From 206255b411b22a6ddb3b51a43e31a6b7774a3396 Mon Sep 17 00:00:00 2001
From: mathuo <6710312+mathuo@users.noreply.github.com>
Date: Sat, 30 Sep 2023 10:17:36 +0100
Subject: [PATCH 1/4] chore: provide additional examples
---
.codesandbox/ci.json | 2 +
packages/docs/docs/components/dockview.mdx | 9 +
.../docs/sandboxes/ide-example/package.json | 32 ++++
.../sandboxes/ide-example/public/index.html | 44 +++++
.../docs/sandboxes/ide-example/src/app.tsx | 162 ++++++++++++++++++
.../docs/sandboxes/ide-example/src/index.tsx | 20 +++
.../docs/sandboxes/ide-example/src/styles.css | 15 ++
.../docs/sandboxes/ide-example/tsconfig.json | 18 ++
8 files changed, 302 insertions(+)
create mode 100644 packages/docs/sandboxes/ide-example/package.json
create mode 100644 packages/docs/sandboxes/ide-example/public/index.html
create mode 100644 packages/docs/sandboxes/ide-example/src/app.tsx
create mode 100644 packages/docs/sandboxes/ide-example/src/index.tsx
create mode 100644 packages/docs/sandboxes/ide-example/src/styles.css
create mode 100644 packages/docs/sandboxes/ide-example/tsconfig.json
diff --git a/.codesandbox/ci.json b/.codesandbox/ci.json
index 986267fe3..83de42b89 100644
--- a/.codesandbox/ci.json
+++ b/.codesandbox/ci.json
@@ -13,6 +13,8 @@
"/packages/docs/sandboxes/externaldnd-dockview",
"/packages/docs/sandboxes/floatinggroup-dockview",
"/packages/docs/sandboxes/fullwidthtab-dockview",
+ "/packages/docs/sandboxes/headeractions-dockview",
+ "/packages/docs/sandboxes/ide-example",
"/packages/docs/sandboxes/groupcontol-dockview",
"/packages/docs/sandboxes/iframe-dockview",
"/packages/docs/sandboxes/layout-dockview",
diff --git a/packages/docs/docs/components/dockview.mdx b/packages/docs/docs/components/dockview.mdx
index 25f67edc5..6de717337 100644
--- a/packages/docs/docs/components/dockview.mdx
+++ b/packages/docs/docs/components/dockview.mdx
@@ -27,6 +27,7 @@ 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 IDEExample from '@site/sandboxes/ide-example/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';
@@ -901,6 +902,14 @@ A simple example showing events fired by `dockviewz that can be interacted with.
## Advanced Examples
+## Application with sidebars
+
+
+
### Nested Dockviews
You can safely create multiple dockview instances within one page and nest dockviews within other dockviews.
diff --git a/packages/docs/sandboxes/ide-example/package.json b/packages/docs/sandboxes/ide-example/package.json
new file mode 100644
index 000000000..5de7b1222
--- /dev/null
+++ b/packages/docs/sandboxes/ide-example/package.json
@@ -0,0 +1,32 @@
+{
+ "name": "ide-example",
+ "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"
+ ]
+}
diff --git a/packages/docs/sandboxes/ide-example/public/index.html b/packages/docs/sandboxes/ide-example/public/index.html
new file mode 100644
index 000000000..1f8a52426
--- /dev/null
+++ b/packages/docs/sandboxes/ide-example/public/index.html
@@ -0,0 +1,44 @@
+
+
+
+
+
+
+
+
+
+
+
+
+ React App
+
+
+
+
+ You need to enable JavaScript to run this app.
+
+
+
+
+
+
diff --git a/packages/docs/sandboxes/ide-example/src/app.tsx b/packages/docs/sandboxes/ide-example/src/app.tsx
new file mode 100644
index 000000000..79d5acda6
--- /dev/null
+++ b/packages/docs/sandboxes/ide-example/src/app.tsx
@@ -0,0 +1,162 @@
+import {
+ GridviewReact,
+ GridviewReadyEvent,
+ IGridviewPanelProps,
+ GridviewComponent,
+ Orientation,
+ GridviewApi,
+ LayoutPriority,
+} from 'dockview';
+import * as React from 'react';
+
+const components = {
+ 'left-sidebar': (props: IGridviewPanelProps<{ title: string }>) => {
+ return (
+
+ {props.params.title}
+
+ );
+ },
+ 'middle-content': (props: IGridviewPanelProps<{ title: string }>) => {
+ return (
+
+ {props.params.title}
+
+ );
+ },
+ 'right-sidebar': (props: IGridviewPanelProps<{ title: string }>) => {
+ return (
+
+ {props.params.title}
+
+ );
+ },
+};
+
+const App = (props: { theme?: string }) => {
+ const [api, setApi] = React.useState();
+
+ const onReady = (event: GridviewReadyEvent) => {
+ event.api.fromJSON({
+ grid: {
+ height: 1000,
+ width: 1000,
+ orientation: Orientation.HORIZONTAL,
+ root: {
+ type: 'branch',
+ data: [
+ {
+ type: 'leaf',
+ data: {
+ id: 'left-sidebar-id',
+ component: 'left-sidebar',
+ snap: true,
+ minimumWidth: 100,
+ },
+ size: 200,
+ },
+ {
+ type: 'leaf',
+ data: {
+ id: 'middle-content-id',
+ component: 'middle-content',
+ priority: LayoutPriority.High,
+ minimumWidth: 100,
+ },
+ size: 600,
+ },
+ {
+ type: 'leaf',
+ data: {
+ id: 'right-sidebar-id',
+ component: 'right-sidebar',
+ snap: true,
+ minimumWidth: 100,
+ },
+ size: 200,
+ },
+ ],
+ },
+ },
+ });
+
+ setApi(event.api);
+ };
+
+ const onKeyPress = (event: React.KeyboardEvent) => {
+ if (!api) {
+ return;
+ }
+
+ if (event.ctrlKey) {
+ if (event.code === 'ArrowLeft') {
+ const leftSidebarPanel = api.getPanel('left-sidebar-id');
+ const rightSidebarPanel = api.getPanel('right-sidebar-id');
+
+ // const width = rightSidebarPanel?.api.width;
+
+ if (leftSidebarPanel) {
+ leftSidebarPanel.api.setVisible(false);
+
+ // if (rightSidebarPanel && typeof width === 'number') {
+ // rightSidebarPanel.api.setSize({ width });
+ // }
+ }
+ }
+ }
+
+ if (event.code === 'ArrowRight') {
+ const leftSidebarPanel = api.getPanel('left-sidebar-id');
+
+ if (leftSidebarPanel) {
+ leftSidebarPanel.api.setVisible(true);
+ // leftSidebarPanel.api.setSize({ width: 200 });
+ }
+ }
+ };
+
+ return (
+
+
+ {'Use '}
+ {'Ctrl+ArrowLeft'}
+ {' and '}
+ {'Ctrl+ArrowRight'}
+ {
+ ' to show and hide the left sidebar. The right sidebar can be hidden by dragging it to the right.'
+ }
+
+
+
+
+
+ );
+};
+
+export default App;
diff --git a/packages/docs/sandboxes/ide-example/src/index.tsx b/packages/docs/sandboxes/ide-example/src/index.tsx
new file mode 100644
index 000000000..2fe1be232
--- /dev/null
+++ b/packages/docs/sandboxes/ide-example/src/index.tsx
@@ -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(
+
+
+
+ );
+}
diff --git a/packages/docs/sandboxes/ide-example/src/styles.css b/packages/docs/sandboxes/ide-example/src/styles.css
new file mode 100644
index 000000000..2198f8a37
--- /dev/null
+++ b/packages/docs/sandboxes/ide-example/src/styles.css
@@ -0,0 +1,15 @@
+body {
+ margin: 0px;
+ font-family: sans-serif;
+ text-align: center;
+}
+
+#root {
+ height: 100vh;
+ width: 100vw;
+}
+
+.app {
+ height: 100%;
+
+}
diff --git a/packages/docs/sandboxes/ide-example/tsconfig.json b/packages/docs/sandboxes/ide-example/tsconfig.json
new file mode 100644
index 000000000..cdc4fb5f5
--- /dev/null
+++ b/packages/docs/sandboxes/ide-example/tsconfig.json
@@ -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
+ }
+}
From 08ec3fd3a54af6c58c68e26e353402d8748b2e26 Mon Sep 17 00:00:00 2001
From: mathuo <6710312+mathuo@users.noreply.github.com>
Date: Sat, 30 Sep 2023 11:24:26 +0100
Subject: [PATCH 2/4] feat: ensure view priority used for viewChange events
---
.../dockview-core/src/splitview/splitview.ts | 24 +++++++++++++++----
1 file changed, 20 insertions(+), 4 deletions(-)
diff --git a/packages/dockview-core/src/splitview/splitview.ts b/packages/dockview-core/src/splitview/splitview.ts
index 007a8e60a..0d56cce24 100644
--- a/packages/dockview-core/src/splitview/splitview.ts
+++ b/packages/dockview-core/src/splitview/splitview.ts
@@ -37,10 +37,11 @@ export interface SplitViewOptions {
readonly proportionalLayout?: boolean;
readonly styles?: ISplitviewStyles;
}
+
export enum LayoutPriority {
- Low = 'low',
- High = 'high',
- Normal = 'normal',
+ Low = 'low', // view is offered space last
+ High = 'high', // view is offered space first
+ Normal = 'normal', // view is offered space in view order
}
export interface IBaseView extends IDisposable {
@@ -340,7 +341,22 @@ export class Splitview {
item.size = size;
- this.relayout([index]);
+ const indexes = range(this.viewItems.length).filter((i) => i !== index);
+ const lowPriorityIndexes = [
+ ...indexes.filter(
+ (i) => this.viewItems[i].priority === LayoutPriority.Low
+ ),
+ index,
+ ];
+ const highPriorityIndexes = indexes.filter(
+ (i) => this.viewItems[i].priority === LayoutPriority.High
+ );
+
+ /**
+ * add this view we are changing to the low-index list since we have determined the size
+ * here and don't want it changed
+ */
+ this.relayout([...lowPriorityIndexes, index], highPriorityIndexes);
}
public addView(
From 4c142b9632008728d9726d116a10de8f9811dcfa Mon Sep 17 00:00:00 2001
From: mathuo <6710312+mathuo@users.noreply.github.com>
Date: Sat, 30 Sep 2023 11:31:01 +0100
Subject: [PATCH 3/4] chore: update examples
---
packages/docs/sandboxes/ide-example/src/app.tsx | 8 --------
1 file changed, 8 deletions(-)
diff --git a/packages/docs/sandboxes/ide-example/src/app.tsx b/packages/docs/sandboxes/ide-example/src/app.tsx
index 79d5acda6..d63b035f8 100644
--- a/packages/docs/sandboxes/ide-example/src/app.tsx
+++ b/packages/docs/sandboxes/ide-example/src/app.tsx
@@ -109,16 +109,9 @@ const App = (props: { theme?: string }) => {
if (event.ctrlKey) {
if (event.code === 'ArrowLeft') {
const leftSidebarPanel = api.getPanel('left-sidebar-id');
- const rightSidebarPanel = api.getPanel('right-sidebar-id');
-
- // const width = rightSidebarPanel?.api.width;
if (leftSidebarPanel) {
leftSidebarPanel.api.setVisible(false);
-
- // if (rightSidebarPanel && typeof width === 'number') {
- // rightSidebarPanel.api.setSize({ width });
- // }
}
}
}
@@ -128,7 +121,6 @@ const App = (props: { theme?: string }) => {
if (leftSidebarPanel) {
leftSidebarPanel.api.setVisible(true);
- // leftSidebarPanel.api.setSize({ width: 200 });
}
}
};
From fc1c747bed61ac4f169ed5c04695b4eb940eab14 Mon Sep 17 00:00:00 2001
From: mathuo <6710312+mathuo@users.noreply.github.com>
Date: Sat, 30 Sep 2023 11:47:36 +0100
Subject: [PATCH 4/4] test: add tests
---
.../src/__tests__/splitview/splitview.spec.ts | 96 +++++++++++++++++++
1 file changed, 96 insertions(+)
diff --git a/packages/dockview-core/src/__tests__/splitview/splitview.spec.ts b/packages/dockview-core/src/__tests__/splitview/splitview.spec.ts
index ec7654393..ed02acf4c 100644
--- a/packages/dockview-core/src/__tests__/splitview/splitview.spec.ts
+++ b/packages/dockview-core/src/__tests__/splitview/splitview.spec.ts
@@ -676,4 +676,100 @@ describe('splitview', () => {
expect(addEventListenerSpy).toBeCalledTimes(3);
expect(removeEventListenerSpy).toBeCalledTimes(3);
});
+
+ test('setViewVisible', () => {
+ const splitview = new Splitview(container, {
+ orientation: Orientation.HORIZONTAL,
+ proportionalLayout: false,
+ });
+ splitview.layout(900, 500);
+
+ const view1 = new Testview(0, 1000);
+ const view2 = new Testview(0, 1000);
+ const view3 = new Testview(0, 1000);
+
+ splitview.addView(view1);
+ splitview.addView(view2);
+ splitview.addView(view3);
+
+ expect([view1.size, view2.size, view3.size]).toEqual([300, 300, 300]);
+
+ splitview.setViewVisible(0, false);
+ expect([view1.size, view2.size, view3.size]).toEqual([0, 300, 600]);
+
+ splitview.setViewVisible(0, true);
+ expect([view1.size, view2.size, view3.size]).toEqual([300, 300, 300]);
+ });
+
+ test('setViewVisible with one view having high layout priority', () => {
+ const splitview = new Splitview(container, {
+ orientation: Orientation.HORIZONTAL,
+ proportionalLayout: false,
+ });
+ splitview.layout(900, 500);
+
+ const view1 = new Testview(0, 1000);
+ const view2 = new Testview(0, 1000, LayoutPriority.High);
+ const view3 = new Testview(0, 1000);
+
+ splitview.addView(view1);
+ splitview.addView(view2);
+ splitview.addView(view3);
+
+ expect([view1.size, view2.size, view3.size]).toEqual([300, 300, 300]);
+
+ splitview.setViewVisible(0, false);
+ expect([view1.size, view2.size, view3.size]).toEqual([0, 600, 300]);
+
+ splitview.setViewVisible(0, true);
+ expect([view1.size, view2.size, view3.size]).toEqual([300, 300, 300]);
+ });
+
+ test('set view size', () => {
+ const splitview = new Splitview(container, {
+ orientation: Orientation.HORIZONTAL,
+ proportionalLayout: false,
+ });
+ splitview.layout(900, 500);
+
+ const view1 = new Testview(0, 1000);
+ const view2 = new Testview(0, 1000);
+ const view3 = new Testview(0, 1000);
+
+ splitview.addView(view1);
+ splitview.addView(view2);
+ splitview.addView(view3);
+
+ expect([view1.size, view2.size, view3.size]).toEqual([300, 300, 300]);
+
+ view1.fireChangeEvent({ size: 0 });
+ expect([view1.size, view2.size, view3.size]).toEqual([0, 300, 600]);
+
+ view1.fireChangeEvent({ size: 300 });
+ expect([view1.size, view2.size, view3.size]).toEqual([300, 300, 300]);
+ });
+
+ test('set view size with one view having high layout priority', () => {
+ const splitview = new Splitview(container, {
+ orientation: Orientation.HORIZONTAL,
+ proportionalLayout: false,
+ });
+ splitview.layout(900, 500);
+
+ const view1 = new Testview(0, 1000);
+ const view2 = new Testview(0, 1000, LayoutPriority.High);
+ const view3 = new Testview(0, 1000);
+
+ splitview.addView(view1);
+ splitview.addView(view2);
+ splitview.addView(view3);
+
+ expect([view1.size, view2.size, view3.size]).toEqual([300, 300, 300]);
+
+ view1.fireChangeEvent({ size: 0 });
+ expect([view1.size, view2.size, view3.size]).toEqual([0, 600, 300]);
+
+ view1.fireChangeEvent({ size: 300 });
+ expect([view1.size, view2.size, view3.size]).toEqual([300, 300, 300]);
+ });
});