From 0233e8fa4256f5bb79e83e4d375b1c0e589f93e5 Mon Sep 17 00:00:00 2001 From: mathuo <6710312+mathuo@users.noreply.github.com> Date: Sun, 3 Nov 2024 19:21:57 +0000 Subject: [PATCH 1/9] chore(release): publish v2.0.0 --- lerna.json | 2 +- packages/dockview-angular/package.json | 4 ++-- packages/dockview-core/package.json | 2 +- packages/dockview-react/package.json | 4 ++-- packages/dockview-vue/package.json | 4 ++-- packages/dockview/package.json | 4 ++-- packages/docs/package.json | 4 ++-- 7 files changed, 12 insertions(+), 12 deletions(-) diff --git a/lerna.json b/lerna.json index 0db0b74b9..c1fe88e6a 100644 --- a/lerna.json +++ b/lerna.json @@ -2,7 +2,7 @@ "packages": [ "packages/*" ], - "version": "1.17.2", + "version": "2.0.0", "npmClient": "yarn", "command": { "publish": { diff --git a/packages/dockview-angular/package.json b/packages/dockview-angular/package.json index 71411409b..cebda7271 100644 --- a/packages/dockview-angular/package.json +++ b/packages/dockview-angular/package.json @@ -1,6 +1,6 @@ { "name": "dockview-angular", - "version": "1.17.2", + "version": "2.0.0", "description": "Zero dependency layout manager supporting tabs, grids and splitviews", "keywords": [ "splitview", @@ -54,6 +54,6 @@ "test:cov": "cross-env ../../node_modules/.bin/jest --selectProjects dockview --coverage" }, "dependencies": { - "dockview-core": "^1.17.2" + "dockview-core": "^2.0.0" } } diff --git a/packages/dockview-core/package.json b/packages/dockview-core/package.json index b63be23e7..01e63a421 100644 --- a/packages/dockview-core/package.json +++ b/packages/dockview-core/package.json @@ -1,6 +1,6 @@ { "name": "dockview-core", - "version": "1.17.2", + "version": "2.0.0", "description": "Zero dependency layout manager supporting tabs, grids and splitviews", "keywords": [ "splitview", diff --git a/packages/dockview-react/package.json b/packages/dockview-react/package.json index 5a8508a94..c0051e41f 100644 --- a/packages/dockview-react/package.json +++ b/packages/dockview-react/package.json @@ -1,6 +1,6 @@ { "name": "dockview-react", - "version": "1.17.2", + "version": "2.0.0", "description": "Zero dependency layout manager supporting tabs, grids and splitviews", "keywords": [ "splitview", @@ -54,6 +54,6 @@ "test:cov": "cross-env ../../node_modules/.bin/jest --selectProjects dockview-react --coverage" }, "dependencies": { - "dockview": "^1.17.2" + "dockview": "^2.0.0" } } diff --git a/packages/dockview-vue/package.json b/packages/dockview-vue/package.json index 6fbef7925..d5f23fd8a 100644 --- a/packages/dockview-vue/package.json +++ b/packages/dockview-vue/package.json @@ -1,6 +1,6 @@ { "name": "dockview-vue", - "version": "1.17.2", + "version": "2.0.0", "description": "Zero dependency layout manager supporting tabs, grids and splitviews", "keywords": [ "splitview", @@ -52,6 +52,6 @@ "test:cov": "cross-env ../../node_modules/.bin/jest --selectProjects dockview-vue --coverage" }, "dependencies": { - "dockview-core": "^1.17.2" + "dockview-core": "^2.0.0" } } diff --git a/packages/dockview/package.json b/packages/dockview/package.json index 89fd9e985..a7016f392 100644 --- a/packages/dockview/package.json +++ b/packages/dockview/package.json @@ -1,6 +1,6 @@ { "name": "dockview", - "version": "1.17.2", + "version": "2.0.0", "description": "Zero dependency layout manager supporting tabs, grids and splitviews", "keywords": [ "splitview", @@ -54,6 +54,6 @@ "test:cov": "cross-env ../../node_modules/.bin/jest --selectProjects dockview --coverage" }, "dependencies": { - "dockview-core": "^1.17.2" + "dockview-core": "^2.0.0" } } diff --git a/packages/docs/package.json b/packages/docs/package.json index 209c9c0a0..25f23a5df 100644 --- a/packages/docs/package.json +++ b/packages/docs/package.json @@ -1,6 +1,6 @@ { "name": "dockview-docs", - "version": "1.17.2", + "version": "2.0.0", "private": true, "scripts": { "build": "npm run build-templates && docusaurus build", @@ -38,7 +38,7 @@ "ag-grid-react": "^31.0.2", "axios": "^1.6.3", "clsx": "^2.1.0", - "dockview": "^1.17.2", + "dockview": "^2.0.0", "prism-react-renderer": "^2.3.1", "react-dnd": "^16.0.1", "react-laag": "^2.0.5", From df3269d56e30023146947a52d3878da7582daa1d Mon Sep 17 00:00:00 2001 From: mathuo <6710312+mathuo@users.noreply.github.com> Date: Sun, 3 Nov 2024 19:23:16 +0000 Subject: [PATCH 2/9] chore: v2.0.0 docs --- .../docs/blog/2024-11-03-dockview-2.0.0.md | 32 ++ packages/docs/docs/core/panels/add.mdx | 22 +- packages/docs/src/generated/api.output.json | 384 +++++++++++------- 3 files changed, 297 insertions(+), 141 deletions(-) create mode 100644 packages/docs/blog/2024-11-03-dockview-2.0.0.md diff --git a/packages/docs/blog/2024-11-03-dockview-2.0.0.md b/packages/docs/blog/2024-11-03-dockview-2.0.0.md new file mode 100644 index 000000000..3cc856412 --- /dev/null +++ b/packages/docs/blog/2024-11-03-dockview-2.0.0.md @@ -0,0 +1,32 @@ +--- +slug: dockview-2.0.0-release +title: Dockview 2.0.0 +tags: [release] +--- + +# Release Notes + +This major version bump is due to breaking changes related to classnames. + +Please reference docs @ [dockview.dev](https://dockview.dev). + +## 🚀 Features + +- Add panel within group at specific index [#751](https://github.com/mathuo/dockview/pull/751) + +## 🛠 Miscs + +- Set drag event dataTransfer object to empty string [#738](https://github.com/mathuo/dockview/pull/738) +- General code cleanup / housekeeping [#740](https://github.com/mathuo/dockview/pull/740) [#746](https://github.com/mathuo/dockview/pull/746) +- Bug: Popout window initial sizing [#737](https://github.com/mathuo/dockview/pull/737) [#727](https://github.com/mathuo/dockview/pull/727) +- Bug: Close popout window on unload (refresh) [#731](https://github.com/mathuo/dockview/pull/731) +- Bug: Preserve Vue3 inject/provide context [#673](https://github.com/mathuo/dockview/pull/673) +- Bug: Fix Contraints [#744](https://github.com/mathuo/dockview/pull/744) +- Bug: Fix popout window issues [#748](https://github.com/mathuo/dockview/pull/748) + +## 🔥 Breaking changes + +- Prefix all classnames with `-dv-*` [#688](https://github.com/mathuo/dockview/pull/688) +- Remove depreciated methods [#742](https://github.com/mathuo/dockview/pull/742) + + diff --git a/packages/docs/docs/core/panels/add.mdx b/packages/docs/docs/core/panels/add.mdx index b964cdc05..cb151eb6e 100644 --- a/packages/docs/docs/core/panels/add.mdx +++ b/packages/docs/docs/core/panels/add.mdx @@ -115,6 +115,15 @@ api.addPanel({ direction: 'above' } }); + +api.addPanel({ + id: 'panel_4', + component: 'default', + position: { + referencePanel: panel2, + index: 2 // optionally specify which index to add the panel at + } +}); ``` #### Relative to another Group @@ -129,7 +138,9 @@ const panel2: IDockviewPanel = api.addPanel({ } }); -const panel = api.addPanel({ + + +api.addPanel({ id: 'panel_2', component: 'default', position: { @@ -137,6 +148,15 @@ const panel = api.addPanel({ direction: 'left' } }); + +api.addPanel({ + id: 'panel_3', + component: 'default', + position: { + referenceGroup: panel2.group, + index: 2 // optionally specify which index to add the panel at + } +}); ``` #### Relative to the container diff --git a/packages/docs/src/generated/api.output.json b/packages/docs/src/generated/api.output.json index 4f2f51762..d7024baab 100644 --- a/packages/docs/src/generated/api.output.json +++ b/packages/docs/src/generated/api.output.json @@ -5155,7 +5155,7 @@ }, { "name": "addPopoutGroup", - "code": "(itemToPopout: DockviewPanel | DockviewGroupPanel, options?: { onDidOpen?: (event: { id: string, window: Window }): void, onWillClose?: (event: { id: string, window: Window }): void, overridePopoutGroup?: DockviewGroupPanel, popoutUrl?: string, position?: Box, skipRemoveGroup?: boolean }): Promise", + "code": "(itemToPopout: DockviewPanel | DockviewGroupPanel, options?: { onDidOpen?: (event: { id: string, window: Window }): void, onWillClose?: (event: { id: string, window: Window }): void, overridePopoutGroup?: DockviewGroupPanel, popoutUrl?: string, position?: Box }): Promise", "kind": "method", "signature": [ { @@ -5184,12 +5184,12 @@ }, { "name": "options", - "code": "options?: { onDidOpen?: (event: { id: string, window: Window }): void, onWillClose?: (event: { id: string, window: Window }): void, overridePopoutGroup?: DockviewGroupPanel, popoutUrl?: string, position?: Box, skipRemoveGroup?: boolean }", + "code": "options?: { onDidOpen?: (event: { id: string, window: Window }): void, onWillClose?: (event: { id: string, window: Window }): void, overridePopoutGroup?: DockviewGroupPanel, popoutUrl?: string, position?: Box }", "type": { "type": "reflection", "value": { "name": "__type", - "code": "{ onDidOpen?: (event: { id: string, window: Window }): void, onWillClose?: (event: { id: string, window: Window }): void, overridePopoutGroup?: DockviewGroupPanel, popoutUrl?: string, position?: Box, skipRemoveGroup?: boolean }", + "code": "{ onDidOpen?: (event: { id: string, window: Window }): void, onWillClose?: (event: { id: string, window: Window }): void, overridePopoutGroup?: DockviewGroupPanel, popoutUrl?: string, position?: Box }", "kind": "typeLiteral", "properties": [ { @@ -5361,18 +5361,6 @@ "flags": { "isOptional": true } - }, - { - "name": "skipRemoveGroup", - "code": "boolean", - "kind": "property", - "type": { - "type": "intrinsic", - "value": "boolean" - }, - "flags": { - "isOptional": true - } } ] } @@ -5391,7 +5379,7 @@ } ] }, - "code": "(itemToPopout: DockviewPanel | DockviewGroupPanel, options?: { onDidOpen?: (event: { id: string, window: Window }): void, onWillClose?: (event: { id: string, window: Window }): void, overridePopoutGroup?: DockviewGroupPanel, popoutUrl?: string, position?: Box, skipRemoveGroup?: boolean }): Promise", + "code": "(itemToPopout: DockviewPanel | DockviewGroupPanel, options?: { onDidOpen?: (event: { id: string, window: Window }): void, onWillClose?: (event: { id: string, window: Window }): void, overridePopoutGroup?: DockviewGroupPanel, popoutUrl?: string, position?: Box }): Promise", "kind": "callSignature" } ] @@ -7337,6 +7325,78 @@ } } }, + { + "name": "__maximumHeight", + "code": "(): number", + "kind": "method", + "signature": [ + { + "name": "__maximumHeight", + "typeParameters": [], + "parameters": [], + "returnType": { + "type": "intrinsic", + "value": "number" + }, + "code": "(): number", + "kind": "callSignature" + } + ] + }, + { + "name": "__maximumWidth", + "code": "(): number", + "kind": "method", + "signature": [ + { + "name": "__maximumWidth", + "typeParameters": [], + "parameters": [], + "returnType": { + "type": "intrinsic", + "value": "number" + }, + "code": "(): number", + "kind": "callSignature" + } + ] + }, + { + "name": "__minimumHeight", + "code": "(): number", + "kind": "method", + "signature": [ + { + "name": "__minimumHeight", + "typeParameters": [], + "parameters": [], + "returnType": { + "type": "intrinsic", + "value": "number" + }, + "code": "(): number", + "kind": "callSignature" + } + ] + }, + { + "name": "__minimumWidth", + "code": "(): number", + "kind": "method", + "signature": [ + { + "name": "__minimumWidth", + "typeParameters": [], + "parameters": [], + "returnType": { + "type": "intrinsic", + "value": "number" + }, + "code": "(): number", + "kind": "callSignature" + } + ] + }, { "name": "addDisposables", "code": "(args: IDisposable[]): void", @@ -14662,6 +14722,78 @@ } } }, + { + "name": "__maximumHeight", + "code": "(): number", + "kind": "method", + "signature": [ + { + "name": "__maximumHeight", + "typeParameters": [], + "parameters": [], + "returnType": { + "type": "intrinsic", + "value": "number" + }, + "code": "(): number", + "kind": "callSignature" + } + ] + }, + { + "name": "__maximumWidth", + "code": "(): number", + "kind": "method", + "signature": [ + { + "name": "__maximumWidth", + "typeParameters": [], + "parameters": [], + "returnType": { + "type": "intrinsic", + "value": "number" + }, + "code": "(): number", + "kind": "callSignature" + } + ] + }, + { + "name": "__minimumHeight", + "code": "(): number", + "kind": "method", + "signature": [ + { + "name": "__minimumHeight", + "typeParameters": [], + "parameters": [], + "returnType": { + "type": "intrinsic", + "value": "number" + }, + "code": "(): number", + "kind": "callSignature" + } + ] + }, + { + "name": "__minimumWidth", + "code": "(): number", + "kind": "method", + "signature": [ + { + "name": "__minimumWidth", + "typeParameters": [], + "parameters": [], + "returnType": { + "type": "intrinsic", + "value": "number" + }, + "code": "(): number", + "kind": "callSignature" + } + ] + }, { "name": "addDisposables", "code": "(args: IDisposable[]): void", @@ -23422,6 +23554,79 @@ ], "extends": [] }, + "DockviewGroupMoveParams": { + "kind": "interface", + "name": "DockviewGroupMoveParams", + "children": [ + { + "name": "group", + "code": "DockviewGroupPanel", + "kind": "property", + "type": { + "type": "reference", + "value": "DockviewGroupPanel", + "source": "dockview-core" + }, + "flags": { + "isOptional": true + } + }, + { + "name": "index", + "code": "number", + "kind": "property", + "type": { + "type": "intrinsic", + "value": "number" + }, + "flags": { + "isOptional": true + }, + "comment": { + "summary": [ + { + "kind": "text", + "text": "The index to place the panel within a group, only applicable if the placement is within an existing group" + } + ] + } + }, + { + "name": "position", + "code": "'bottom' | 'right' | 'top' | 'left' | 'center'", + "kind": "property", + "type": { + "type": "or", + "values": [ + { + "type": "literal", + "value": "bottom" + }, + { + "type": "literal", + "value": "right" + }, + { + "type": "literal", + "value": "top" + }, + { + "type": "literal", + "value": "left" + }, + { + "type": "literal", + "value": "center" + } + ] + }, + "flags": { + "isOptional": true + } + } + ], + "extends": [] + }, "DockviewGroupPanelApi": { "kind": "interface", "name": "DockviewGroupPanelApi", @@ -23898,7 +24103,7 @@ }, { "name": "moveTo", - "code": "(options: { group?: DockviewGroupPanel, position?: 'right' | 'bottom' | 'top' | 'left' | 'center' }): void", + "code": "(options: DockviewGroupMoveParams): void", "kind": "method", "signature": [ { @@ -23907,62 +24112,11 @@ "parameters": [ { "name": "options", - "code": "options: { group?: DockviewGroupPanel, position?: 'right' | 'bottom' | 'top' | 'left' | 'center' }", + "code": "options: DockviewGroupMoveParams", "type": { - "type": "reflection", - "value": { - "name": "__type", - "code": "{ group?: DockviewGroupPanel, position?: 'right' | 'bottom' | 'top' | 'left' | 'center' }", - "kind": "typeLiteral", - "properties": [ - { - "name": "group", - "code": "DockviewGroupPanel", - "kind": "property", - "type": { - "type": "reference", - "value": "DockviewGroupPanel", - "source": "dockview-core" - }, - "flags": { - "isOptional": true - } - }, - { - "name": "position", - "code": "'right' | 'bottom' | 'top' | 'left' | 'center'", - "kind": "property", - "type": { - "type": "or", - "values": [ - { - "type": "literal", - "value": "right" - }, - { - "type": "literal", - "value": "bottom" - }, - { - "type": "literal", - "value": "top" - }, - { - "type": "literal", - "value": "left" - }, - { - "type": "literal", - "value": "center" - } - ] - }, - "flags": { - "isOptional": true - } - } - ] - } + "type": "reference", + "value": "DockviewGroupMoveParams", + "source": "dockview-core" }, "kind": "parameter" } @@ -23971,7 +24125,7 @@ "type": "intrinsic", "value": "void" }, - "code": "(options: { group?: DockviewGroupPanel, position?: 'right' | 'bottom' | 'top' | 'left' | 'center' }): void", + "code": "(options: DockviewGroupMoveParams): void", "kind": "callSignature" } ] @@ -25016,7 +25170,7 @@ }, { "name": "moveTo", - "code": "(options: { group: DockviewGroupPanel, index?: number, position?: 'right' | 'bottom' | 'top' | 'left' | 'center' }): void", + "code": "(options: DockviewGroupMoveParams): void", "kind": "method", "signature": [ { @@ -25025,72 +25179,11 @@ "parameters": [ { "name": "options", - "code": "options: { group: DockviewGroupPanel, index?: number, position?: 'right' | 'bottom' | 'top' | 'left' | 'center' }", + "code": "options: DockviewGroupMoveParams", "type": { - "type": "reflection", - "value": { - "name": "__type", - "code": "{ group: DockviewGroupPanel, index?: number, position?: 'right' | 'bottom' | 'top' | 'left' | 'center' }", - "kind": "typeLiteral", - "properties": [ - { - "name": "group", - "code": "DockviewGroupPanel", - "kind": "property", - "type": { - "type": "reference", - "value": "DockviewGroupPanel", - "source": "dockview-core" - }, - "flags": {} - }, - { - "name": "index", - "code": "number", - "kind": "property", - "type": { - "type": "intrinsic", - "value": "number" - }, - "flags": { - "isOptional": true - } - }, - { - "name": "position", - "code": "'right' | 'bottom' | 'top' | 'left' | 'center'", - "kind": "property", - "type": { - "type": "or", - "values": [ - { - "type": "literal", - "value": "right" - }, - { - "type": "literal", - "value": "bottom" - }, - { - "type": "literal", - "value": "top" - }, - { - "type": "literal", - "value": "left" - }, - { - "type": "literal", - "value": "center" - } - ] - }, - "flags": { - "isOptional": true - } - } - ] - } + "type": "reference", + "value": "DockviewGroupMoveParams", + "source": "dockview-core" }, "kind": "parameter" } @@ -25099,7 +25192,7 @@ "type": "intrinsic", "value": "void" }, - "code": "(options: { group: DockviewGroupPanel, index?: number, position?: 'right' | 'bottom' | 'top' | 'left' | 'center' }): void", + "code": "(options: DockviewGroupMoveParams): void", "kind": "callSignature" } ] @@ -41519,6 +41612,17 @@ }, "kind": "typeAlias" }, + "DockviewPanelMoveParams": { + "name": "DockviewPanelMoveParams", + "code": "DockviewGroupMoveParams", + "typeParameters": [], + "type": { + "type": "reference", + "value": "DockviewGroupMoveParams", + "source": "dockview-core" + }, + "kind": "typeAlias" + }, "DockviewPanelRenderer": { "name": "DockviewPanelRenderer", "code": "'always' | 'onlyWhenVisible'", From aeb0e382493a919d0fc4ca289670bb47a5c5167d Mon Sep 17 00:00:00 2001 From: mathuo <6710312+mathuo@users.noreply.github.com> Date: Thu, 7 Nov 2024 18:58:25 +0000 Subject: [PATCH 3/9] feat: tab container empty space not focusable --- .../src/dockview/components/titlebar/voidContainer.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/dockview-core/src/dockview/components/titlebar/voidContainer.ts b/packages/dockview-core/src/dockview/components/titlebar/voidContainer.ts index 284b780a4..6e9ea0c47 100644 --- a/packages/dockview-core/src/dockview/components/titlebar/voidContainer.ts +++ b/packages/dockview-core/src/dockview/components/titlebar/voidContainer.ts @@ -36,7 +36,6 @@ export class VoidContainer extends CompositeDisposable { this._element = document.createElement('div'); this._element.className = 'dv-void-container'; - this._element.tabIndex = 0; this._element.draggable = true; this.addDisposables( From 1d61a47e7c4f3ac0155ce665525b4fc6482709ce Mon Sep 17 00:00:00 2001 From: Jafar Akhondali Date: Thu, 7 Nov 2024 17:23:01 +0100 Subject: [PATCH 4/9] Block malicious looking requests to prevent path traversal attacks. --- packages/docs/web-server/index.mjs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/packages/docs/web-server/index.mjs b/packages/docs/web-server/index.mjs index 8cbd23434..7e1abd54f 100644 --- a/packages/docs/web-server/index.mjs +++ b/packages/docs/web-server/index.mjs @@ -35,5 +35,10 @@ function write(res, file) { http.createServer((req, res) => { const route = req.url.split('/').slice(1); + if (route.includes('..')) { + res.writeHead(403); + res.end(''); + return; + } write(res, route); }).listen(PORT, HOST); From d651c2213ea7940ad14f8d2f3712a516d476fdd2 Mon Sep 17 00:00:00 2001 From: mathuo <6710312+mathuo@users.noreply.github.com> Date: Mon, 4 Nov 2024 20:28:27 +0000 Subject: [PATCH 5/9] bug: fix setVisible on floating groups --- .../src/dockview/dockviewComponent.ts | 25 +++++++++++++++++++ .../dockview-core/src/overlay/overlay.scss | 4 +++ packages/dockview-core/src/overlay/overlay.ts | 17 +++++++++++++ 3 files changed, 46 insertions(+) diff --git a/packages/dockview-core/src/dockview/dockviewComponent.ts b/packages/dockview-core/src/dockview/dockviewComponent.ts index 27e95fc52..78eed98c2 100644 --- a/packages/dockview-core/src/dockview/dockviewComponent.ts +++ b/packages/dockview-core/src/dockview/dockviewComponent.ts @@ -538,6 +538,31 @@ export class DockviewComponent this.updateWatermark(); } + override setVisible(panel: DockviewGroupPanel, visible: boolean): void { + switch (panel.api.location.type) { + case 'grid': + super.setVisible(panel, visible); + break; + case 'floating': + const item = this.floatingGroups.find( + (floatingGroup) => floatingGroup.group === panel + ); + + if (item) { + item.overlay.setVisible(visible); + panel.api._onDidVisibilityChange.fire({ + isVisible: visible, + }); + } + break; + case 'popout': + console.warn( + 'dockview: You cannot hide a group that is in a popout window' + ); + break; + } + } + addPopoutGroup( itemToPopout: DockviewPanel | DockviewGroupPanel, options?: { diff --git a/packages/dockview-core/src/overlay/overlay.scss b/packages/dockview-core/src/overlay/overlay.scss index 89788e032..fa88193c7 100644 --- a/packages/dockview-core/src/overlay/overlay.scss +++ b/packages/dockview-core/src/overlay/overlay.scss @@ -34,6 +34,10 @@ border: 1px solid var(--dv-tab-divider-color); box-shadow: var(--dv-floating-box-shadow); + &.dv-hidden { + display: none; + } + &.dv-resize-container-dragging { opacity: 0.5; } diff --git a/packages/dockview-core/src/overlay/overlay.ts b/packages/dockview-core/src/overlay/overlay.ts index b34fb9296..36fd00d96 100644 --- a/packages/dockview-core/src/overlay/overlay.ts +++ b/packages/dockview-core/src/overlay/overlay.ts @@ -59,6 +59,8 @@ export class Overlay extends CompositeDisposable { private verticalAlignment: 'top' | 'bottom' | undefined; private horiziontalAlignment: 'left' | 'right' | undefined; + private _isVisible: boolean; + set minimumInViewportWidth(value: number | undefined) { this.options.minimumInViewportWidth = value; } @@ -71,6 +73,10 @@ export class Overlay extends CompositeDisposable { return this._element; } + get isVisible(): boolean { + return this._isVisible; + } + constructor( private readonly options: AnchoredBox & { container: HTMLElement; @@ -84,6 +90,7 @@ export class Overlay extends CompositeDisposable { this.addDisposables(this._onDidChange, this._onDidChangeEnd); this._element.className = 'dv-resize-container'; + this._isVisible = true; this.setupResize('top'); this.setupResize('bottom'); @@ -110,6 +117,16 @@ export class Overlay extends CompositeDisposable { arialLevelTracker.push(this._element); } + setVisible(isVisible: boolean): void { + if (isVisible === this.isVisible) { + return; + } + + this._isVisible = isVisible; + + toggleClass(this.element, 'dv-hidden', !this.isVisible); + } + bringToFront(): void { arialLevelTracker.push(this._element); } From 1ce96c8ab86231a2623c0fad5a20e6523bb47e62 Mon Sep 17 00:00:00 2001 From: mathuo <6710312+mathuo@users.noreply.github.com> Date: Sun, 10 Nov 2024 10:58:21 +0000 Subject: [PATCH 6/9] test: add tests --- .../dockview/dockviewComponent.spec.ts | 513 ++++++++++++------ 1 file changed, 335 insertions(+), 178 deletions(-) diff --git a/packages/dockview-core/src/__tests__/dockview/dockviewComponent.spec.ts b/packages/dockview-core/src/__tests__/dockview/dockviewComponent.spec.ts index 72faaebe6..66f4f023e 100644 --- a/packages/dockview-core/src/__tests__/dockview/dockviewComponent.spec.ts +++ b/packages/dockview-core/src/__tests__/dockview/dockviewComponent.spec.ts @@ -5354,169 +5354,378 @@ describe('dockviewComponent', () => { }); }); - test('that setVisible toggles visiblity', () => { - const container = document.createElement('div'); + describe('panel visibility', () => { + test('that setVisible toggles visiblity', () => { + const container = document.createElement('div'); - const dockview = new DockviewComponent(container, { - createComponent(options) { - switch (options.name) { - case 'default': - return new PanelContentPartTest( - options.id, - options.name - ); - default: - throw new Error(`unsupported`); - } - }, - }); - const api = new DockviewApi(dockview); + const dockview = new DockviewComponent(container, { + createComponent(options) { + switch (options.name) { + case 'default': + return new PanelContentPartTest( + options.id, + options.name + ); + default: + throw new Error(`unsupported`); + } + }, + }); + const api = new DockviewApi(dockview); - dockview.layout(1000, 1000); + dockview.layout(1000, 1000); - const panel1 = api.addPanel({ - id: 'panel1', - component: 'default', - }); - const panel2 = api.addPanel({ - id: 'panel2', - component: 'default', - position: { referencePanel: panel1, direction: 'within' }, - }); + const panel1 = api.addPanel({ + id: 'panel1', + component: 'default', + }); + const panel2 = api.addPanel({ + id: 'panel2', + component: 'default', + position: { referencePanel: panel1, direction: 'within' }, + }); - const panel3 = api.addPanel({ - id: 'panel3', - component: 'default', - position: { referencePanel: panel1, direction: 'right' }, - }); + const panel3 = api.addPanel({ + id: 'panel3', + component: 'default', + position: { referencePanel: panel1, direction: 'right' }, + }); - const panel4 = api.addPanel({ - id: 'panel4', - component: 'default', - position: { referencePanel: panel3, direction: 'within' }, - }); + const panel4 = api.addPanel({ + id: 'panel4', + component: 'default', + position: { referencePanel: panel3, direction: 'within' }, + }); - expect(api.groups.length).toBe(2); - expect(panel1.group).toBe(panel2.group); - expect(panel3.group).toBe(panel4.group); + expect(api.groups.length).toBe(2); + expect(panel1.group).toBe(panel2.group); + expect(panel3.group).toBe(panel4.group); - expect(panel1.group.api.isVisible).toBeTruthy(); - expect(panel2.group.api.isVisible).toBeTruthy(); - expect(panel3.group.api.isVisible).toBeTruthy(); - expect(panel4.group.api.isVisible).toBeTruthy(); + expect(panel1.group.api.isVisible).toBeTruthy(); + expect(panel2.group.api.isVisible).toBeTruthy(); + expect(panel3.group.api.isVisible).toBeTruthy(); + expect(panel4.group.api.isVisible).toBeTruthy(); - expect(panel1.api.isVisible).toBeFalsy(); - expect(panel2.api.isVisible).toBeTruthy(); - expect(panel3.api.isVisible).toBeFalsy(); - expect(panel4.api.isVisible).toBeTruthy(); + expect(panel1.api.isVisible).toBeFalsy(); + expect(panel2.api.isVisible).toBeTruthy(); + expect(panel3.api.isVisible).toBeFalsy(); + expect(panel4.api.isVisible).toBeTruthy(); - // case #1 - panel1.group.api.setVisible(false); + // case #1 + panel1.group.api.setVisible(false); - expect(panel1.group.api.isVisible).toBeFalsy(); - expect(panel2.group.api.isVisible).toBeFalsy(); - expect(panel3.group.api.isVisible).toBeTruthy(); - expect(panel4.group.api.isVisible).toBeTruthy(); + expect(panel1.group.api.isVisible).toBeFalsy(); + expect(panel2.group.api.isVisible).toBeFalsy(); + expect(panel3.group.api.isVisible).toBeTruthy(); + expect(panel4.group.api.isVisible).toBeTruthy(); - expect(panel1.api.isVisible).toBeFalsy(); - expect(panel2.api.isVisible).toBeFalsy(); - expect(panel3.api.isVisible).toBeFalsy(); - expect(panel4.api.isVisible).toBeTruthy(); + expect(panel1.api.isVisible).toBeFalsy(); + expect(panel2.api.isVisible).toBeFalsy(); + expect(panel3.api.isVisible).toBeFalsy(); + expect(panel4.api.isVisible).toBeTruthy(); - // case #2 + // case #2 - panel3.group.api.setVisible(false); + panel3.group.api.setVisible(false); - expect(panel1.group.api.isVisible).toBeFalsy(); - expect(panel2.group.api.isVisible).toBeFalsy(); - expect(panel3.group.api.isVisible).toBeFalsy(); - expect(panel4.group.api.isVisible).toBeFalsy(); + expect(panel1.group.api.isVisible).toBeFalsy(); + expect(panel2.group.api.isVisible).toBeFalsy(); + expect(panel3.group.api.isVisible).toBeFalsy(); + expect(panel4.group.api.isVisible).toBeFalsy(); - expect(panel1.api.isVisible).toBeFalsy(); - expect(panel2.api.isVisible).toBeFalsy(); - expect(panel3.api.isVisible).toBeFalsy(); - expect(panel4.api.isVisible).toBeFalsy(); + expect(panel1.api.isVisible).toBeFalsy(); + expect(panel2.api.isVisible).toBeFalsy(); + expect(panel3.api.isVisible).toBeFalsy(); + expect(panel4.api.isVisible).toBeFalsy(); - // case #2 + // case #2 - panel3.group.api.setVisible(true); + panel3.group.api.setVisible(true); - expect(panel1.group.api.isVisible).toBeFalsy(); - expect(panel2.group.api.isVisible).toBeFalsy(); - expect(panel3.group.api.isVisible).toBeTruthy(); - expect(panel4.group.api.isVisible).toBeTruthy(); + expect(panel1.group.api.isVisible).toBeFalsy(); + expect(panel2.group.api.isVisible).toBeFalsy(); + expect(panel3.group.api.isVisible).toBeTruthy(); + expect(panel4.group.api.isVisible).toBeTruthy(); - expect(panel1.api.isVisible).toBeFalsy(); - expect(panel2.api.isVisible).toBeFalsy(); - expect(panel3.api.isVisible).toBeFalsy(); - expect(panel4.api.isVisible).toBeTruthy(); + expect(panel1.api.isVisible).toBeFalsy(); + expect(panel2.api.isVisible).toBeFalsy(); + expect(panel3.api.isVisible).toBeFalsy(); + expect(panel4.api.isVisible).toBeTruthy(); - // case #2 + // case #2 - panel1.group.api.setVisible(true); + panel1.group.api.setVisible(true); - expect(panel1.group.api.isVisible).toBeTruthy(); - expect(panel2.group.api.isVisible).toBeTruthy(); - expect(panel3.group.api.isVisible).toBeTruthy(); - expect(panel4.group.api.isVisible).toBeTruthy(); + expect(panel1.group.api.isVisible).toBeTruthy(); + expect(panel2.group.api.isVisible).toBeTruthy(); + expect(panel3.group.api.isVisible).toBeTruthy(); + expect(panel4.group.api.isVisible).toBeTruthy(); - expect(panel1.api.isVisible).toBeFalsy(); - expect(panel2.api.isVisible).toBeTruthy(); - expect(panel3.api.isVisible).toBeFalsy(); - expect(panel4.api.isVisible).toBeTruthy(); - }); + expect(panel1.api.isVisible).toBeFalsy(); + expect(panel2.api.isVisible).toBeTruthy(); + expect(panel3.api.isVisible).toBeFalsy(); + expect(panel4.api.isVisible).toBeTruthy(); + }); - test('setVisible #1', () => { - const container = document.createElement('div'); + test('setVisible #1', () => { + const container = document.createElement('div'); - const dockview = new DockviewComponent(container, { - createComponent(options) { - switch (options.name) { - case 'default': - return new PanelContentPartTest( - options.id, - options.name - ); - default: - throw new Error(`unsupported`); - } - }, + const dockview = new DockviewComponent(container, { + createComponent(options) { + switch (options.name) { + case 'default': + return new PanelContentPartTest( + options.id, + options.name + ); + default: + throw new Error(`unsupported`); + } + }, + }); + const api = new DockviewApi(dockview); + + dockview.layout(1000, 1000); + + const panel1 = api.addPanel({ + id: 'panel1', + component: 'default', + }); + const panel2 = api.addPanel({ + id: 'panel2', + component: 'default', + position: { referencePanel: panel1, direction: 'below' }, + }); + + const panel3 = api.addPanel({ + id: 'panel3', + component: 'default', + position: { referencePanel: panel1, direction: 'below' }, + }); + + expect(api.groups.length).toBe(3); + + panel1.group.api.setVisible(false); + panel2.group.api.setVisible(false); + panel3.group.api.setVisible(false); + + expect(panel1.group.api.isVisible).toBeFalsy(); + expect(panel2.group.api.isVisible).toBeFalsy(); + expect(panel3.group.api.isVisible).toBeFalsy(); + + panel1.group.api.setVisible(true); + + expect(panel1.group.api.isVisible).toBeTruthy(); + expect(panel2.group.api.isVisible).toBeFalsy(); + expect(panel3.group.api.isVisible).toBeFalsy(); }); - const api = new DockviewApi(dockview); - dockview.layout(1000, 1000); + test('that watermark appears when all views are not visible', () => { + jest.useFakeTimers(); + const container = document.createElement('div'); - const panel1 = api.addPanel({ - id: 'panel1', - component: 'default', + const dockview = new DockviewComponent(container, { + createComponent(options) { + switch (options.name) { + case 'default': + return new PanelContentPartTest( + options.id, + options.name + ); + default: + throw new Error(`unsupported`); + } + }, + }); + const api = new DockviewApi(dockview); + + dockview.layout(1000, 1000); + + const panel1 = api.addPanel({ + id: 'panel_1', + component: 'default', + }); + const panel2 = api.addPanel({ + id: 'panel_2', + component: 'default', + position: { + direction: 'right', + }, + }); + + let query = queryByTestId(container, 'watermark-component'); + expect(query).toBeFalsy(); + + panel1.group.api.setVisible(false); + jest.runAllTicks(); // visibility events check fires on microtask-queue + query = queryByTestId(container, 'watermark-component'); + expect(query).toBeFalsy(); + + panel2.group.api.setVisible(false); + jest.runAllTicks(); // visibility events check fires on microtask-queue + query = queryByTestId(container, 'watermark-component'); + expect(query).toBeTruthy(); + + panel1.group.api.setVisible(true); + jest.runAllTicks(); // visibility events check fires on microtask-queue + query = queryByTestId(container, 'watermark-component'); + expect(query).toBeFalsy(); }); - const panel2 = api.addPanel({ - id: 'panel2', - component: 'default', - position: { referencePanel: panel1, direction: 'below' }, + + test('setVisible on floating group', () => { + const container = document.createElement('div'); + + const dockview = new DockviewComponent(container, { + createComponent(options) { + switch (options.name) { + case 'default': + return new PanelContentPartTest( + options.id, + options.name + ); + default: + throw new Error(`unsupported`); + } + }, + }); + const api = new DockviewApi(dockview); + + dockview.layout(1000, 1000); + + const panel1 = api.addPanel({ + id: 'panel1', + component: 'default', + }); + const panel2 = api.addPanel({ + id: 'panel2', + component: 'default', + position: { referencePanel: panel1, direction: 'below' }, + }); + + const panel3 = api.addPanel({ + id: 'panel3', + component: 'default', + position: { referencePanel: panel1, direction: 'below' }, + }); + + api.addFloatingGroup(panel2); + expect(panel2.api.location.type).toBe('floating'); + + panel2.api.group.setVisible(false); + expect(panel2.api.isVisible).toBeFalsy(); + expect(panel2.api.group.api.isVisible).toBeFalsy(); + + panel2.api.group.setVisible(true); + expect(panel2.api.isVisible).toBeTruthy(); + expect(panel2.api.group.api.isVisible).toBeTruthy(); + + panel2.api.group.setVisible(false); + expect(panel2.api.isVisible).toBeFalsy(); + expect(panel2.api.group.api.isVisible).toBeFalsy(); + + panel2.api.group.api.moveTo({ + group: panel1.group, + position: 'left', + }); + expect(api.groups.length).toBe(3); + expect(panel2.api.isVisible).toBeFalsy(); + expect(panel2.api.group.api.isVisible).toBeFalsy(); + + panel2.api.group.setVisible(true); + expect(panel2.api.isVisible).toBeTruthy(); + expect(panel2.api.group.api.isVisible).toBeTruthy(); }); - const panel3 = api.addPanel({ - id: 'panel3', - component: 'default', - position: { referencePanel: panel1, direction: 'below' }, + test('setVisible on popout group should have no effect', async () => { + window.open = () => setupMockWindow(); + + const container = document.createElement('div'); + + const dockview = new DockviewComponent(container, { + createComponent(options) { + switch (options.name) { + case 'default': + return new PanelContentPartTest( + options.id, + options.name + ); + default: + throw new Error(`unsupported`); + } + }, + }); + const api = new DockviewApi(dockview); + + dockview.layout(1000, 1000); + + const panel1 = api.addPanel({ + id: 'panel1', + component: 'default', + }); + const panel2 = api.addPanel({ + id: 'panel2', + component: 'default', + position: { referencePanel: panel1, direction: 'below' }, + }); + + const panel3 = api.addPanel({ + id: 'panel3', + component: 'default', + position: { referencePanel: panel1, direction: 'below' }, + }); + + await api.addPopoutGroup(panel2); + expect(panel2.api.location.type).toBe('popout'); + + expect(panel2.api.group.api.isVisible).toBeTruthy(); + panel2.api.group.api.setVisible(false); + expect(panel2.api.group.api.isVisible).toBeTruthy(); }); - expect(api.groups.length).toBe(3); + test('opening a popout group from a group that is non visible should automatically make it visible', async () => { + window.open = () => setupMockWindow(); + + const container = document.createElement('div'); + + const dockview = new DockviewComponent(container, { + createComponent(options) { + switch (options.name) { + case 'default': + return new PanelContentPartTest( + options.id, + options.name + ); + default: + throw new Error(`unsupported`); + } + }, + }); + const api = new DockviewApi(dockview); - panel1.group.api.setVisible(false); - panel2.group.api.setVisible(false); - panel3.group.api.setVisible(false); + dockview.layout(1000, 1000); - expect(panel1.group.api.isVisible).toBeFalsy(); - expect(panel2.group.api.isVisible).toBeFalsy(); - expect(panel3.group.api.isVisible).toBeFalsy(); + const panel1 = api.addPanel({ + id: 'panel1', + component: 'default', + }); + const panel2 = api.addPanel({ + id: 'panel2', + component: 'default', + position: { referencePanel: panel1, direction: 'below' }, + }); + + const panel3 = api.addPanel({ + id: 'panel3', + component: 'default', + position: { referencePanel: panel1, direction: 'below' }, + }); - panel1.group.api.setVisible(true); + panel2.api.group.api.setVisible(false); - expect(panel1.group.api.isVisible).toBeTruthy(); - expect(panel2.group.api.isVisible).toBeFalsy(); - expect(panel3.group.api.isVisible).toBeFalsy(); + await api.addPopoutGroup(panel2); + expect(panel2.api.location.type).toBe('popout'); + expect(panel2.api.group.api.isVisible).toBeTruthy(); + }); }); describe('addPanel', () => { @@ -5939,58 +6148,6 @@ describe('dockviewComponent', () => { expect(api.groups.length).toBe(3); }); - test('that watermark appears when all views are not visible', () => { - jest.useFakeTimers(); - const container = document.createElement('div'); - - const dockview = new DockviewComponent(container, { - createComponent(options) { - switch (options.name) { - case 'default': - return new PanelContentPartTest( - options.id, - options.name - ); - default: - throw new Error(`unsupported`); - } - }, - }); - const api = new DockviewApi(dockview); - - dockview.layout(1000, 1000); - - const panel1 = api.addPanel({ - id: 'panel_1', - component: 'default', - }); - const panel2 = api.addPanel({ - id: 'panel_2', - component: 'default', - position: { - direction: 'right', - }, - }); - - let query = queryByTestId(container, 'watermark-component'); - expect(query).toBeFalsy(); - - panel1.group.api.setVisible(false); - jest.runAllTicks(); // visibility events check fires on microtask-queue - query = queryByTestId(container, 'watermark-component'); - expect(query).toBeFalsy(); - - panel2.group.api.setVisible(false); - jest.runAllTicks(); // visibility events check fires on microtask-queue - query = queryByTestId(container, 'watermark-component'); - expect(query).toBeTruthy(); - - panel1.group.api.setVisible(true); - jest.runAllTicks(); // visibility events check fires on microtask-queue - query = queryByTestId(container, 'watermark-component'); - expect(query).toBeFalsy(); - }); - describe('updateOptions', () => { test('gap', () => { const container = document.createElement('div'); From 1b921864fc022cd2056f0b71554a12a3eaf83403 Mon Sep 17 00:00:00 2001 From: mathuo <6710312+mathuo@users.noreply.github.com> Date: Sun, 10 Nov 2024 11:12:01 +0000 Subject: [PATCH 7/9] chore: fix sonar issue --- packages/dockview-core/src/dockview/dockviewComponent.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/dockview-core/src/dockview/dockviewComponent.ts b/packages/dockview-core/src/dockview/dockviewComponent.ts index 78eed98c2..5a20f5b84 100644 --- a/packages/dockview-core/src/dockview/dockviewComponent.ts +++ b/packages/dockview-core/src/dockview/dockviewComponent.ts @@ -543,7 +543,7 @@ export class DockviewComponent case 'grid': super.setVisible(panel, visible); break; - case 'floating': + case 'floating': { const item = this.floatingGroups.find( (floatingGroup) => floatingGroup.group === panel ); @@ -555,6 +555,7 @@ export class DockviewComponent }); } break; + } case 'popout': console.warn( 'dockview: You cannot hide a group that is in a popout window' From 615886e666e6ad7f25d38f31f5cd8999722ac52a Mon Sep 17 00:00:00 2001 From: Daniel Goodwin Date: Sat, 30 Nov 2024 23:43:04 -0500 Subject: [PATCH 8/9] Do not close group if it's the only group available --- packages/dockview-core/src/dockview/dockviewComponent.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/packages/dockview-core/src/dockview/dockviewComponent.ts b/packages/dockview-core/src/dockview/dockviewComponent.ts index 5a20f5b84..8424e98f5 100644 --- a/packages/dockview-core/src/dockview/dockviewComponent.ts +++ b/packages/dockview-core/src/dockview/dockviewComponent.ts @@ -1793,6 +1793,10 @@ export class DockviewComponent } | undefined ): DockviewGroupPanel { + if (this.groups.length <= 1) { + return false; + } + const panels = [...group.panels]; // reassign since group panels will mutate if (!options?.skipDispose) { From a02241d1a741788b4d1477d91be27629afb48cfb Mon Sep 17 00:00:00 2001 From: mathuo <6710312+mathuo@users.noreply.github.com> Date: Mon, 2 Dec 2024 20:04:10 +0000 Subject: [PATCH 9/9] feat: ensure group always exists --- .../components/watermark/watermark.spec.ts | 23 --------- .../dockview/dockviewGroupPanelModel.spec.ts | 33 +++--------- .../components/watermark/watermark.scss | 40 +-------------- .../components/watermark/watermark.ts | 50 +------------------ .../src/dockview/dockviewComponent.ts | 7 +-- .../src/dockview/dockviewGroupPanel.scss | 6 --- .../src/dockview/dockviewGroupPanelModel.ts | 14 ++++-- .../dockview-core/src/dockview/options.ts | 5 ++ 8 files changed, 24 insertions(+), 154 deletions(-) delete mode 100644 packages/dockview-core/src/__tests__/dockview/components/watermark/watermark.spec.ts diff --git a/packages/dockview-core/src/__tests__/dockview/components/watermark/watermark.spec.ts b/packages/dockview-core/src/__tests__/dockview/components/watermark/watermark.spec.ts deleted file mode 100644 index 92797f0e9..000000000 --- a/packages/dockview-core/src/__tests__/dockview/components/watermark/watermark.spec.ts +++ /dev/null @@ -1,23 +0,0 @@ -import { DockviewApi } from '../../../../api/component.api'; -import { Watermark } from '../../../../dockview/components/watermark/watermark'; -import { fromPartial } from '@total-typescript/shoehorn'; - -describe('watermark', () => { - test('that the group is closed when the close button is clicked', () => { - const cut = new Watermark(); - const api = fromPartial({ - removeGroup: jest.fn(), - }); - const group = jest.fn() as any; - - cut.init({ containerApi: api, group }); - - const closeEl = cut.element.querySelector('.dv-close-action')!; - - expect(closeEl).toBeTruthy(); - - closeEl.dispatchEvent(new Event('click')); - - expect(api.removeGroup).toHaveBeenCalledWith(group); - }); -}); diff --git a/packages/dockview-core/src/__tests__/dockview/dockviewGroupPanelModel.spec.ts b/packages/dockview-core/src/__tests__/dockview/dockviewGroupPanelModel.spec.ts index d9b6d4bfb..55aed39ec 100644 --- a/packages/dockview-core/src/__tests__/dockview/dockviewGroupPanelModel.spec.ts +++ b/packages/dockview-core/src/__tests__/dockview/dockviewGroupPanelModel.spec.ts @@ -9,39 +9,20 @@ import { } from '../../dockview/types'; import { PanelUpdateEvent, Parameters } from '../../panel/types'; import { - DockviewGroupLocation, DockviewGroupPanelModel, GroupOptions, } from '../../dockview/dockviewGroupPanelModel'; import { fireEvent } from '@testing-library/dom'; import { LocalSelectionTransfer, PanelTransfer } from '../../dnd/dataTransfer'; import { CompositeDisposable } from '../../lifecycle'; -import { - ActiveGroupEvent, - DockviewPanelApi, - GroupChangedEvent, - RendererChangedEvent, -} from '../../api/dockviewPanelApi'; +import { DockviewPanelApi } from '../../api/dockviewPanelApi'; import { IDockviewPanel } from '../../dockview/dockviewPanel'; import { IDockviewPanelModel } from '../../dockview/dockviewPanelModel'; import { DockviewGroupPanel } from '../../dockview/dockviewGroupPanel'; import { WatermarkRendererInitParameters } from '../../dockview/types'; import { createOffsetDragOverEvent } from '../__test_utils__/utils'; -import { - DockviewPanelRenderer, - OverlayRenderContainer, -} from '../../overlay/overlayRenderContainer'; -import { DockviewGroupPanelFloatingChangeEvent } from '../../api/dockviewGroupPanelApi'; -import { SizeEvent } from '../../api/gridviewPanelApi'; -import { - PanelDimensionChangeEvent, - FocusEvent, - VisibilityEvent, - ActiveEvent, - WillFocusEvent, -} from '../../api/panelApi'; -import { Position } from '../../dnd/droptarget'; -import { Emitter, Event } from '../../events'; +import { OverlayRenderContainer } from '../../overlay/overlayRenderContainer'; +import { Emitter } from '../../events'; import { fromPartial } from '@total-typescript/shoehorn'; enum GroupChangeKind2 { @@ -513,14 +494,14 @@ describe('dockviewGroupPanelModel', () => { groupview.model.closeAllPanels(); - expect(removePanelMock).toBeCalledWith(panel1); - expect(removePanelMock).toBeCalledWith(panel2); - expect(removePanelMock).toBeCalledWith(panel3); + expect(removePanelMock).toHaveBeenCalledWith(panel1, undefined); + expect(removePanelMock).toHaveBeenCalledWith(panel2, undefined); + expect(removePanelMock).toHaveBeenCalledWith(panel3, undefined); }); test('closeAllPanels with no panels', () => { groupview.model.closeAllPanels(); - expect(removeGroupMock).toBeCalledWith(groupview); + expect(removeGroupMock).toHaveBeenCalledWith(groupview); }); test('that group is set on panel during onDidAddPanel event', () => { diff --git a/packages/dockview-core/src/dockview/components/watermark/watermark.scss b/packages/dockview-core/src/dockview/components/watermark/watermark.scss index f085a974d..7936cabcc 100644 --- a/packages/dockview-core/src/dockview/components/watermark/watermark.scss +++ b/packages/dockview-core/src/dockview/components/watermark/watermark.scss @@ -1,42 +1,4 @@ .dv-watermark { display: flex; - width: 100%; - - &.dv-has-actions { - .dv-watermark-title { - .dv-actions-container { - display: none; - } - } - } - - .dv-watermark-title { - height: 35px; - width: 100%; - display: flex; - } - .dv-watermark-content { - flex-grow: 1; - } - - .dv-actions-container { - display: flex; - align-items: center; - padding: 0px 8px; - - .dv-close-action { - padding: 4px; - display: flex; - align-items: center; - justify-content: center; - box-sizing: border-box; - cursor: pointer; - color: var(--dv-activegroup-hiddenpanel-tab-color); - - &:hover { - border-radius: 2px; - background-color: var(--dv-icon-hover-background-color); - } - } - } + height: 100%; } diff --git a/packages/dockview-core/src/dockview/components/watermark/watermark.ts b/packages/dockview-core/src/dockview/components/watermark/watermark.ts index f213868b8..3e20dc273 100644 --- a/packages/dockview-core/src/dockview/components/watermark/watermark.ts +++ b/packages/dockview-core/src/dockview/components/watermark/watermark.ts @@ -2,20 +2,13 @@ import { IWatermarkRenderer, WatermarkRendererInitParameters, } from '../../types'; -import { addDisposableListener } from '../../../events'; -import { toggleClass } from '../../../dom'; import { CompositeDisposable } from '../../../lifecycle'; -import { IDockviewGroupPanel } from '../../dockviewGroupPanel'; -import { createCloseButton } from '../../../svg'; -import { DockviewApi } from '../../../api/component.api'; export class Watermark extends CompositeDisposable implements IWatermarkRenderer { private readonly _element: HTMLElement; - private _group: IDockviewGroupPanel | undefined; - private _api: DockviewApi | undefined; get element(): HTMLElement { return this._element; @@ -25,50 +18,9 @@ export class Watermark super(); this._element = document.createElement('div'); this._element.className = 'dv-watermark'; - - const title = document.createElement('div'); - title.className = 'dv-watermark-title'; - - const emptySpace = document.createElement('span'); - emptySpace.style.flexGrow = '1'; - - const content = document.createElement('div'); - content.className = 'dv-watermark-content'; - - this._element.appendChild(title); - this._element.appendChild(content); - - const actionsContainer = document.createElement('div'); - actionsContainer.className = 'dv-actions-container'; - - const closeAnchor = document.createElement('div'); - closeAnchor.className = 'dv-close-action'; - closeAnchor.appendChild(createCloseButton()); - - actionsContainer.appendChild(closeAnchor); - - title.appendChild(emptySpace); - title.appendChild(actionsContainer); - - this.addDisposables( - addDisposableListener(closeAnchor, 'click', (event: MouseEvent) => { - event.preventDefault(); - - if (this._group) { - this._api?.removeGroup(this._group); - } - }) - ); } init(_params: WatermarkRendererInitParameters): void { - this._api = _params.containerApi; - this._group = _params.group; - this.render(); - } - - private render(): void { - const isOneGroup = !!(this._api && this._api.size <= 1); - toggleClass(this.element, 'dv-has-actions', isOneGroup); + // noop } } diff --git a/packages/dockview-core/src/dockview/dockviewComponent.ts b/packages/dockview-core/src/dockview/dockviewComponent.ts index 8424e98f5..4727f305e 100644 --- a/packages/dockview-core/src/dockview/dockviewComponent.ts +++ b/packages/dockview-core/src/dockview/dockviewComponent.ts @@ -1623,11 +1623,10 @@ export class DockviewComponent panel: IDockviewPanel, options: { removeEmptyGroup: boolean; - skipDispose: boolean; + skipDispose?: boolean; skipSetActiveGroup?: boolean; } = { removeEmptyGroup: true, - skipDispose: false, } ): void { const group = panel.group; @@ -1793,10 +1792,6 @@ export class DockviewComponent } | undefined ): DockviewGroupPanel { - if (this.groups.length <= 1) { - return false; - } - const panels = [...group.panels]; // reassign since group panels will mutate if (!options?.skipDispose) { diff --git a/packages/dockview-core/src/dockview/dockviewGroupPanel.scss b/packages/dockview-core/src/dockview/dockviewGroupPanel.scss index 3faff3ce0..d452917f2 100644 --- a/packages/dockview-core/src/dockview/dockviewGroupPanel.scss +++ b/packages/dockview-core/src/dockview/dockviewGroupPanel.scss @@ -9,12 +9,6 @@ outline: none; } - &.dv-empty { - > .dv-tabs-and-actions-container { - display: none; - } - } - > .dv-content-container { flex-grow: 1; min-height: 0; diff --git a/packages/dockview-core/src/dockview/dockviewGroupPanelModel.ts b/packages/dockview-core/src/dockview/dockviewGroupPanelModel.ts index a377ed9ec..cfb47243f 100644 --- a/packages/dockview-core/src/dockview/dockviewGroupPanelModel.ts +++ b/packages/dockview-core/src/dockview/dockviewGroupPanelModel.ts @@ -787,7 +787,15 @@ export class DockviewGroupPanelModel } private doClose(panel: IDockviewPanel): void { - this.accessor.removePanel(panel); + const isLast = + this.panels.length === 1 && this.accessor.groups.length === 1; + + this.accessor.removePanel( + panel, + isLast && this.accessor.options.noPanelsOverlay === 'emptyGroup' + ? { removeEmptyGroup: false } + : undefined + ); } public isPanelActive(panel: IDockviewPanel): boolean { @@ -955,8 +963,6 @@ export class DockviewGroupPanelModel } private updateContainer(): void { - toggleClass(this.container, 'dv-empty', this.isEmpty); - this.panels.forEach((panel) => panel.runEvents()); if (this.isEmpty && !this.watermark) { @@ -973,14 +979,12 @@ export class DockviewGroupPanelModel } }); - this.tabsContainer.hide(); this.contentContainer.element.appendChild(this.watermark.element); } if (!this.isEmpty && this.watermark) { this.watermark.element.remove(); this.watermark.dispose?.(); this.watermark = undefined; - this.tabsContainer.show(); } } diff --git a/packages/dockview-core/src/dockview/options.ts b/packages/dockview-core/src/dockview/options.ts index c1a429a08..3e87923a2 100644 --- a/packages/dockview-core/src/dockview/options.ts +++ b/packages/dockview-core/src/dockview/options.ts @@ -59,6 +59,10 @@ export interface DockviewOptions { * Pixel gap between groups */ gap?: number; + /** + * Define the behaviour of the dock when there are no panels to display. Defaults to `watermark`. + */ + noPanelsOverlay?: 'emptyGroup' | 'watermark'; } export interface DockviewDndOverlayEvent { @@ -111,6 +115,7 @@ export const PROPERTY_KEYS: (keyof DockviewOptions)[] = (() => { disableDnd: undefined, gap: undefined, className: undefined, + noPanelsOverlay: undefined, }; return Object.keys(properties) as (keyof DockviewOptions)[];