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/groupcontol-dockview",
"/packages/docs/sandboxes/iframe-dockview", "/packages/docs/sandboxes/iframe-dockview",
"/packages/docs/sandboxes/layout-dockview", "/packages/docs/sandboxes/layout-dockview",
"/packages/docs/sandboxes/lockedgroup-dockview",
"/packages/docs/sandboxes/nativeapp-dockview", "/packages/docs/sandboxes/nativeapp-dockview",
"/packages/docs/sandboxes/nested-dockview", "/packages/docs/sandboxes/nested-dockview",
"/packages/docs/sandboxes/rendering-dockview", "/packages/docs/sandboxes/rendering-dockview",

View File

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

View File

@ -48,7 +48,7 @@ interface GroupMoveEvent {
} }
interface CoreGroupOptions { interface CoreGroupOptions {
locked?: boolean; locked?: DockviewGroupPanelLocked;
hideHeader?: boolean; hideHeader?: boolean;
} }
@ -79,6 +79,8 @@ export interface IHeader {
hidden: boolean; hidden: boolean;
} }
export type DockviewGroupPanelLocked = boolean | 'no-drop-target';
export interface IDockviewGroupPanelModel extends IPanel { export interface IDockviewGroupPanelModel extends IPanel {
readonly isActive: boolean; readonly isActive: boolean;
readonly size: number; readonly size: number;
@ -91,7 +93,7 @@ export interface IDockviewGroupPanelModel extends IPanel {
readonly onDidRemovePanel: Event<GroupviewChangeEvent>; readonly onDidRemovePanel: Event<GroupviewChangeEvent>;
readonly onDidActivePanelChange: Event<GroupviewChangeEvent>; readonly onDidActivePanelChange: Event<GroupviewChangeEvent>;
readonly onMove: Event<GroupMoveEvent>; readonly onMove: Event<GroupMoveEvent>;
locked: boolean; locked: DockviewGroupPanelLocked;
setActive(isActive: boolean): void; setActive(isActive: boolean): void;
initialize(): void; initialize(): void;
// state // state
@ -136,7 +138,7 @@ export class DockviewGroupPanelModel
private _activePanel: IDockviewPanel | undefined; private _activePanel: IDockviewPanel | undefined;
private watermark?: IWatermarkRenderer; private watermark?: IWatermarkRenderer;
private _isGroupActive = false; private _isGroupActive = false;
private _locked = false; private _locked: DockviewGroupPanelLocked = false;
private _isFloating = false; private _isFloating = false;
private _rightHeaderActions: IHeaderActionsRenderer | undefined; private _rightHeaderActions: IHeaderActionsRenderer | undefined;
private _leftHeaderActions: IHeaderActionsRenderer | undefined; private _leftHeaderActions: IHeaderActionsRenderer | undefined;
@ -179,14 +181,18 @@ export class DockviewGroupPanelModel
return this._activePanel; return this._activePanel;
} }
get locked(): boolean { get locked(): DockviewGroupPanelLocked {
return this._locked; return this._locked;
} }
set locked(value: boolean) { set locked(value: DockviewGroupPanelLocked) {
this._locked = value; this._locked = value;
toggleClass(this.container, 'locked-groupview', value); toggleClass(
this.container,
'locked-groupview',
value === 'no-drop-target' || value
);
} }
get isActive(): boolean { get isActive(): boolean {
@ -261,7 +267,10 @@ export class DockviewGroupPanelModel
this.dropTarget = new Droptarget(this.contentContainer.element, { this.dropTarget = new Droptarget(this.contentContainer.element, {
acceptedTargetZones: ['top', 'bottom', 'left', 'right', 'center'], acceptedTargetZones: ['top', 'bottom', 'left', 'right', 'center'],
canDisplayOverlay: (event, position) => { canDisplayOverlay: (event, position) => {
if (this.locked && position === 'center') { if (
this.locked === 'no-drop-target' ||
(this.locked && position === 'center')
) {
return false; return false;
} }
@ -303,7 +312,7 @@ export class DockviewGroupPanelModel
); );
this.header.hidden = !!options.hideHeader; this.header.hidden = !!options.hideHeader;
this.locked = !!options.locked; this.locked = options.locked || false;
this.addDisposables( this.addDisposables(
this.tabsContainer.onDrop((event) => { this.tabsContainer.onDrop((event) => {
@ -385,8 +394,8 @@ export class DockviewGroupPanelModel
id: this.id, id: this.id,
}; };
if (this.locked) { if (this.locked !== false) {
result.locked = true; result.locked = this.locked;
} }
if (this.header.hidden) { if (this.header.hidden) {
@ -746,6 +755,10 @@ export class DockviewGroupPanelModel
position: Position, position: Position,
index?: number index?: number
): void { ): void {
if (this.locked === 'no-drop-target') {
return;
}
const data = getPanelData(); const data = getPanelData();
if (data && data.viewId === this.accessor.id) { 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 DockviewTabheight from '@site/sandboxes/tabheight-dockview/src/app';
import DockviewWithIFrames from '@site/sandboxes/iframe-dockview/src/app'; import DockviewWithIFrames from '@site/sandboxes/iframe-dockview/src/app';
import DockviewFloating from '@site/sandboxes/floatinggroup-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 attachDockviewVanilla } from '@site/sandboxes/javascript/vanilla-dockview/src/app';
import { attach as attachSimpleDockview } from '@site/sandboxes/javascript/simple-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 ```tsx
panel.group.locked = true; 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 ### Group Controls Panel
`DockviewReact` accepts `leftHeaderActionsComponent` and `rightHeaderActionsComponent` which expect a React component with props `IDockviewHeaderActionsProps`. `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
}
}