Merge pull request #315 from techbech/locked-groups

feat: added the option for 'no-drop-target' for locked on dockview groups
This commit is contained in:
mathuo 2023-07-30 16:48:37 +01:00 committed by GitHub
commit 3fb2800db4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 242 additions and 13 deletions

View File

@ -15,6 +15,7 @@
"/packages/docs/sandboxes/groupcontol-dockview",
"/packages/docs/sandboxes/iframe-dockview",
"/packages/docs/sandboxes/layout-dockview",
"/packages/docs/sandboxes/lockedgroup-dockview",
"/packages/docs/sandboxes/nativeapp-dockview",
"/packages/docs/sandboxes/nested-dockview",
"/packages/docs/sandboxes/rendering-dockview",

View File

@ -5,6 +5,7 @@ import {
GroupOptions,
IDockviewGroupPanelModel,
IHeader,
DockviewGroupPanelLocked,
} from './dockviewGroupPanelModel';
import { GridviewPanel, IGridviewPanel } from '../gridview/gridviewPanel';
import { IDockviewPanel } from '../dockview/dockviewPanel';
@ -16,7 +17,7 @@ import {
export interface IDockviewGroupPanel
extends IGridviewPanel<DockviewGroupPanelApi> {
model: IDockviewGroupPanelModel;
locked: boolean;
locked: DockviewGroupPanelLocked;
readonly size: number;
readonly panels: IDockviewPanel[];
readonly activePanel: IDockviewPanel | undefined;
@ -46,11 +47,11 @@ export class DockviewGroupPanel
return this._model;
}
get locked(): boolean {
get locked(): DockviewGroupPanelLocked {
return this._model.locked;
}
set locked(value: boolean) {
set locked(value: DockviewGroupPanelLocked) {
this._model.locked = value;
}

View File

@ -48,7 +48,7 @@ interface GroupMoveEvent {
}
interface CoreGroupOptions {
locked?: boolean;
locked?: DockviewGroupPanelLocked;
hideHeader?: boolean;
}
@ -79,6 +79,8 @@ export interface IHeader {
hidden: boolean;
}
export type DockviewGroupPanelLocked = boolean | 'no-drop-target';
export interface IDockviewGroupPanelModel extends IPanel {
readonly isActive: boolean;
readonly size: number;
@ -91,7 +93,7 @@ export interface IDockviewGroupPanelModel extends IPanel {
readonly onDidRemovePanel: Event<GroupviewChangeEvent>;
readonly onDidActivePanelChange: Event<GroupviewChangeEvent>;
readonly onMove: Event<GroupMoveEvent>;
locked: boolean;
locked: DockviewGroupPanelLocked;
setActive(isActive: boolean): void;
initialize(): void;
// state
@ -136,7 +138,7 @@ export class DockviewGroupPanelModel
private _activePanel: IDockviewPanel | undefined;
private watermark?: IWatermarkRenderer;
private _isGroupActive = false;
private _locked = false;
private _locked: DockviewGroupPanelLocked = false;
private _isFloating = false;
private _rightHeaderActions: IHeaderActionsRenderer | undefined;
private _leftHeaderActions: IHeaderActionsRenderer | undefined;
@ -179,14 +181,18 @@ export class DockviewGroupPanelModel
return this._activePanel;
}
get locked(): boolean {
get locked(): DockviewGroupPanelLocked {
return this._locked;
}
set locked(value: boolean) {
set locked(value: DockviewGroupPanelLocked) {
this._locked = value;
toggleClass(this.container, 'locked-groupview', value);
toggleClass(
this.container,
'locked-groupview',
value === 'no-drop-target' || value
);
}
get isActive(): boolean {
@ -261,7 +267,10 @@ export class DockviewGroupPanelModel
this.dropTarget = new Droptarget(this.contentContainer.element, {
acceptedTargetZones: ['top', 'bottom', 'left', 'right', 'center'],
canDisplayOverlay: (event, position) => {
if (this.locked && position === 'center') {
if (
this.locked === 'no-drop-target' ||
(this.locked && position === 'center')
) {
return false;
}
@ -303,7 +312,7 @@ export class DockviewGroupPanelModel
);
this.header.hidden = !!options.hideHeader;
this.locked = !!options.locked;
this.locked = options.locked || false;
this.addDisposables(
this.tabsContainer.onDrop((event) => {
@ -385,8 +394,8 @@ export class DockviewGroupPanelModel
id: this.id,
};
if (this.locked) {
result.locked = true;
if (this.locked !== false) {
result.locked = this.locked;
}
if (this.header.hidden) {
@ -746,6 +755,10 @@ export class DockviewGroupPanelModel
position: Position,
index?: number
): void {
if (this.locked === 'no-drop-target') {
return;
}
const data = getPanelData();
if (data && data.viewId === this.accessor.id) {

View File

@ -26,6 +26,7 @@ import DockviewResizeContainer from '@site/sandboxes/resizecontainer-dockview/sr
import DockviewTabheight from '@site/sandboxes/tabheight-dockview/src/app';
import DockviewWithIFrames from '@site/sandboxes/iframe-dockview/src/app';
import DockviewFloating from '@site/sandboxes/floatinggroup-dockview/src/app';
import DockviewLockedGroup from '@site/sandboxes/lockedgroup-dockview/src/app';
import { attach as attachDockviewVanilla } from '@site/sandboxes/javascript/vanilla-dockview/src/app';
import { attach as attachSimpleDockview } from '@site/sandboxes/javascript/simple-dockview/src/app';
@ -776,8 +777,20 @@ You can still add groups to a locked panel programatically using the API though.
```tsx
panel.group.locked = true;
// Or
panel.group.locked = 'no-drop-target';
```
Use `true` to keep drop zones top, right, bottom, left for the group. Use `no-drop-target` to disable all drop zones. For you to get a
better understanding of what this means, try and drag the panels in the example below to the locked groups.
<MultiFrameworkContainer
sandboxId="lockedgroup-dockview"
react={DockviewLockedGroup}
/>
### Group Controls Panel
`DockviewReact` accepts `leftHeaderActionsComponent` and `rightHeaderActionsComponent` which expect a React component with props `IDockviewHeaderActionsProps`.

View File

@ -0,0 +1,32 @@
{
"name": "lockedgroup-dockview",
"description": "",
"keywords": [
"dockview"
],
"version": "1.0.0",
"main": "src/index.tsx",
"dependencies": {
"dockview": "*",
"react": "^18.2.0",
"react-dom": "^18.2.0"
},
"devDependencies": {
"@types/react": "^18.0.28",
"@types/react-dom": "^18.0.11",
"typescript": "^4.9.5",
"react-scripts": "*"
},
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test --env=jsdom",
"eject": "react-scripts eject"
},
"browserslist": [
">0.2%",
"not dead",
"not ie <= 11",
"not op_mini all"
]
}

View File

@ -0,0 +1,44 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<meta name="theme-color" content="#000000">
<!--
manifest.json provides metadata used when your web app is added to the
homescreen on Android. See https://developers.google.com/web/fundamentals/engage-and-retain/web-app-manifest/
-->
<link rel="manifest" href="%PUBLIC_URL%/manifest.json">
<link rel="shortcut icon" href="%PUBLIC_URL%/favicon.ico">
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:opsz,wght,FILL,GRAD@20..48,100..700,0..1,-50..200" />
<!--
Notice the use of %PUBLIC_URL% in the tags above.
It will be replaced with the URL of the `public` folder during the build.
Only files inside the `public` folder can be referenced from the HTML.
Unlike "/favicon.ico" or "favicon.ico", "%PUBLIC_URL%/favicon.ico" will
work correctly both with client-side routing and a non-root public URL.
Learn how to configure a non-root public URL by running `npm run build`.
-->
<title>React App</title>
</head>
<body>
<noscript>
You need to enable JavaScript to run this app.
</noscript>
<div id="root"></div>
<!--
This HTML file is a template.
If you open it directly in the browser, you will see an empty page.
You can add webfonts, meta tags, or analytics to this file.
The build step will place the bundled scripts into the <body> tag.
To begin the development, run `npm start` or `yarn start`.
To create a production bundle, use `npm run build` or `yarn build`.
-->
</body>
</html>

View File

@ -0,0 +1,71 @@
import {
DockviewReact,
DockviewReadyEvent,
IDockviewPanelProps,
} from 'dockview';
import * as React from 'react';
const components = {
default: (props: IDockviewPanelProps<{ title: string }>) => {
return (
<div style={{ padding: '20px', color: 'white' }}>
{props.params.title}
</div>
);
},
};
export const App: React.FC = (props: { theme?: string }) => {
const onReady = (event: DockviewReadyEvent) => {
const panel1 = event.api.addPanel({
id: 'locked1',
component: 'default',
params: {
title: 'Locked',
},
});
panel1.group.locked = true;
panel1.group.header.hidden = true;
event.api.addPanel({
id: 'Drag me',
component: 'default',
params: {
title: '',
},
position: { referencePanel: 'locked1', direction: 'right' },
});
event.api.addPanel({
id: 'Drag me too',
component: 'default',
params: {
title: '',
},
position: { referencePanel: 'Drag me', direction: 'right' },
});
const panel3 = event.api.addPanel({
id: 'locked2',
component: 'default',
params: {
title: 'Locked with no drop target',
},
position: { referencePanel: 'Drag me too', direction: 'right' },
});
panel3.group.locked = 'no-drop-target';
panel3.group.header.hidden = true;
};
return (
<DockviewReact
components={components}
onReady={onReady}
className={props.theme || 'dockview-theme-abyss'}
/>
);
};
export default App;

View File

@ -0,0 +1,20 @@
import { StrictMode } from 'react';
import * as ReactDOMClient from 'react-dom/client';
import './styles.css';
import 'dockview/dist/styles/dockview.css';
import App from './app';
const rootElement = document.getElementById('root');
if (rootElement) {
const root = ReactDOMClient.createRoot(rootElement);
root.render(
<StrictMode>
<div className="app">
<App />
</div>
</StrictMode>
);
}

View File

@ -0,0 +1,16 @@
body {
margin: 0px;
color: white;
font-family: sans-serif;
text-align: center;
}
#root {
height: 100vh;
width: 100vw;
}
.app {
height: 100%;
}

View File

@ -0,0 +1,18 @@
{
"compilerOptions": {
"outDir": "build/dist",
"module": "esnext",
"target": "es5",
"lib": ["es6", "dom"],
"sourceMap": true,
"allowJs": true,
"jsx": "react-jsx",
"moduleResolution": "node",
"rootDir": "src",
"forceConsistentCasingInFileNames": true,
"noImplicitReturns": true,
"noImplicitThis": true,
"noImplicitAny": true,
"strictNullChecks": true
}
}