diff --git a/module-build/tsconfig.esm.json b/module-build/tsconfig.esm.json index c04d21274..1520dd78c 100644 --- a/module-build/tsconfig.esm.json +++ b/module-build/tsconfig.esm.json @@ -12,6 +12,7 @@ "allowUnreachableCode": false, "forceConsistentCasingInFileNames": true, "strict": true, + "declarationMap": true, "lib": [ "ES2015", "ES2016.Array.Include", diff --git a/module-build/tsconfig.json b/module-build/tsconfig.json index f8fa378c7..e89bd96f9 100644 --- a/module-build/tsconfig.json +++ b/module-build/tsconfig.json @@ -12,6 +12,7 @@ "allowUnreachableCode": false, "forceConsistentCasingInFileNames": true, "strict": true, + "declarationMap": true, "lib": [ "ES2015", "ES2016.Array.Include", diff --git a/packages/dockview-core/package.json b/packages/dockview-core/package.json index e8a895a95..e2a05b339 100644 --- a/packages/dockview-core/package.json +++ b/packages/dockview-core/package.json @@ -56,13 +56,13 @@ "author": "https://github.com/mathuo", "license": "MIT", "devDependencies": { + "@rollup/plugin-terser": "^0.4.0", "@rollup/plugin-typescript": "^11.0.0", "cross-env": "^7.0.3", "postcss": "^8.4.21", "rimraf": "^4.1.2", "rollup": "^3.15.0", "rollup-plugin-postcss": "^4.0.2", - "rollup-plugin-terser": "^7.0.2", "typedoc": "^0.23.25" } } diff --git a/packages/dockview-core/rollup.config.js b/packages/dockview-core/rollup.config.js index db87a8a18..ad925e4ff 100644 --- a/packages/dockview-core/rollup.config.js +++ b/packages/dockview-core/rollup.config.js @@ -2,7 +2,7 @@ const { join } = require('path'); const typescript = require('@rollup/plugin-typescript'); -const { terser } = require('rollup-plugin-terser'); +const terser = require('@rollup/plugin-terser'); const postcss = require('rollup-plugin-postcss'); const { name, version, homepage, license } = require('./package.json'); @@ -60,10 +60,6 @@ function createBundle(format, options) { const plugins = [ typescript({ tsconfig: 'tsconfig.esm.json', - incremental: false, - tsBuildInfoFile: undefined, - outDir: undefined, - declaration: false, }), ]; 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 new file mode 100644 index 000000000..662f73198 --- /dev/null +++ b/packages/dockview-core/src/__tests__/dockview/components/watermark/watermark.spec.ts @@ -0,0 +1,27 @@ +import { DockviewApi } from '../../../../api/component.api'; +import { Watermark } from '../../../../dockview/components/watermark/watermark'; + +describe('watermark', () => { + test('that the group is closed when the close button is clicked', () => { + const cut = new Watermark(); + + const mockApi = jest.fn, any[]>(() => { + return { + removeGroup: jest.fn(), + }; + }); + const api = new mockApi(); + const group = jest.fn() as any; + + cut.init({ containerApi: api }); + cut.updateParentGroup(group, true); + + const closeEl = cut.element.querySelector('.close-action')!; + + expect(closeEl).toBeTruthy(); + + closeEl.dispatchEvent(new Event('click')); + + expect(api.removeGroup).toHaveBeenCalledWith(group); + }); +}); diff --git a/packages/dockview-core/src/__tests__/dockview/dockviewComponent.spec.ts b/packages/dockview-core/src/__tests__/dockview/dockviewComponent.spec.ts index 5003460f5..25206344b 100644 --- a/packages/dockview-core/src/__tests__/dockview/dockviewComponent.spec.ts +++ b/packages/dockview-core/src/__tests__/dockview/dockviewComponent.spec.ts @@ -3,22 +3,12 @@ import { GroupPanelPartInitParameters, IContentRenderer, ITabRenderer, - GroupPanelUpdateEvent, - GroupviewPanelState, - IGroupPanelInitParameters, } from '../../dockview/types'; import { PanelUpdateEvent } from '../../panel/types'; import { Orientation } from '../../splitview/splitview'; import { CompositeDisposable } from '../../lifecycle'; import { Emitter } from '../../events'; import { IDockviewPanel } from '../../dockview/dockviewPanel'; -import { - DockviewPanelApi, - DockviewPanelApiImpl, -} from '../../api/dockviewPanelApi'; -import { IDockviewPanelModel } from '../../dockview/dockviewPanelModel'; -import { DockviewPanelModelMock } from '../__mocks__/mockDockviewPanelMode'; -import { DefaultTab } from '../../dockview/components/tab/defaultTab'; import { DockviewGroupPanel } from '../../dockview/dockviewGroupPanel'; class PanelContentPartTest implements IContentRenderer { @@ -100,7 +90,8 @@ describe('dockviewComponent', () => { beforeEach(() => { container = document.createElement('div'); - dockview = new DockviewComponent(container, { + dockview = new DockviewComponent({ + parentElement: container, components: { default: PanelContentPartTest, }, @@ -1037,7 +1028,8 @@ describe('dockviewComponent', () => { test('panel is disposed of when closed', () => { const container = document.createElement('div'); - const dockview = new DockviewComponent(container, { + const dockview = new DockviewComponent({ + parentElement: container, components: { default: PanelContentPartTest }, }); @@ -1061,7 +1053,8 @@ describe('dockviewComponent', () => { test('can add panel of same id if already removed', () => { const container = document.createElement('div'); - const dockview = new DockviewComponent(container, { + const dockview = new DockviewComponent({ + parentElement: container, components: { default: PanelContentPartTest }, }); @@ -1095,7 +1088,8 @@ describe('dockviewComponent', () => { test('panel is disposed of when removed', () => { const container = document.createElement('div'); - const dockview = new DockviewComponent(container, { + const dockview = new DockviewComponent({ + parentElement: container, components: { default: PanelContentPartTest }, }); @@ -1119,7 +1113,8 @@ describe('dockviewComponent', () => { test('panel is not disposed of when moved to a new group', () => { const container = document.createElement('div'); - const dockview = new DockviewComponent(container, { + const dockview = new DockviewComponent({ + parentElement: container, components: { default: PanelContentPartTest, }, @@ -1160,7 +1155,8 @@ describe('dockviewComponent', () => { test('panel is not disposed of when moved within another group', () => { const container = document.createElement('div'); - const dockview = new DockviewComponent(container, { + const dockview = new DockviewComponent({ + parentElement: container, components: { default: PanelContentPartTest, }, @@ -1201,7 +1197,8 @@ describe('dockviewComponent', () => { test('panel is not disposed of when moved within another group', () => { const container = document.createElement('div'); - const dockview = new DockviewComponent(container, { + const dockview = new DockviewComponent({ + parentElement: container, components: { default: PanelContentPartTest, }, @@ -1241,7 +1238,8 @@ describe('dockviewComponent', () => { test('panel is disposed of when group is disposed', () => { const container = document.createElement('div'); - const dockview = new DockviewComponent(container, { + const dockview = new DockviewComponent({ + parentElement: container, components: { default: PanelContentPartTest, }, @@ -1275,7 +1273,8 @@ describe('dockviewComponent', () => { test('panel is disposed of when component is disposed', () => { const container = document.createElement('div'); - const dockview = new DockviewComponent(container, { + const dockview = new DockviewComponent({ + parentElement: container, components: { default: PanelContentPartTest, }, @@ -1309,7 +1308,8 @@ describe('dockviewComponent', () => { test('panel is disposed of when from JSON is called', () => { const container = document.createElement('div'); - const dockview = new DockviewComponent(container, { + const dockview = new DockviewComponent({ + parentElement: container, components: { default: PanelContentPartTest, }, @@ -1353,7 +1353,8 @@ describe('dockviewComponent', () => { test('move entire group into another group', () => { const container = document.createElement('div'); - const dockview = new DockviewComponent(container, { + const dockview = new DockviewComponent({ + parentElement: container, components: { default: PanelContentPartTest }, }); @@ -1566,7 +1567,8 @@ describe('dockviewComponent', () => { test('load a layout with a non-existant tab id', () => { const container = document.createElement('div'); - const dockview = new DockviewComponent(container, { + const dockview = new DockviewComponent({ + parentElement: container, components: { default: PanelContentPartTest, }, @@ -1652,7 +1654,8 @@ describe('dockviewComponent', () => { test('load and persist layout with custom tab header', () => { const container = document.createElement('div'); - const dockview = new DockviewComponent(container, { + const dockview = new DockviewComponent({ + parentElement: container, components: { default: PanelContentPartTest, }, @@ -1760,7 +1763,8 @@ describe('dockviewComponent', () => { test('#2', () => { const container = document.createElement('div'); - const dockview = new DockviewComponent(container, { + const dockview = new DockviewComponent({ + parentElement: container, components: { default: PanelContentPartTest, }, @@ -1846,7 +1850,8 @@ describe('dockviewComponent', () => { test('orthogonal realigment #1', () => { const container = document.createElement('div'); - const dockview = new DockviewComponent(container, { + const dockview = new DockviewComponent({ + parentElement: container, components: { default: PanelContentPartTest, }, @@ -1951,7 +1956,8 @@ describe('dockviewComponent', () => { test('orthogonal realigment #2', () => { const container = document.createElement('div'); - const dockview = new DockviewComponent(container, { + const dockview = new DockviewComponent({ + parentElement: container, components: { default: PanelContentPartTest, }, @@ -2091,7 +2097,8 @@ describe('dockviewComponent', () => { test('orthogonal realigment #3', () => { const container = document.createElement('div'); - const dockview = new DockviewComponent(container, { + const dockview = new DockviewComponent({ + parentElement: container, components: { default: PanelContentPartTest, }, @@ -2218,7 +2225,8 @@ describe('dockviewComponent', () => { test('that a empty component has no groups', () => { const container = document.createElement('div'); - const dockview = new DockviewComponent(container, { + const dockview = new DockviewComponent({ + parentElement: container, components: { default: PanelContentPartTest, }, @@ -2234,7 +2242,8 @@ describe('dockviewComponent', () => { test('that deserializing an empty layout has zero groups and a watermark', () => { const container = document.createElement('div'); - const dockview = new DockviewComponent(container, { + const dockview = new DockviewComponent({ + parentElement: container, components: { default: PanelContentPartTest, }, @@ -2273,7 +2282,8 @@ describe('dockviewComponent', () => { test('empty', () => { const container = document.createElement('div'); - const dockview = new DockviewComponent(container, { + const dockview = new DockviewComponent({ + parentElement: container, components: { default: PanelContentPartTest, }, diff --git a/packages/dockview-core/src/__tests__/gridview/baseComponentGridview.spec.ts b/packages/dockview-core/src/__tests__/gridview/baseComponentGridview.spec.ts index 74a1df1d1..592598807 100644 --- a/packages/dockview-core/src/__tests__/gridview/baseComponentGridview.spec.ts +++ b/packages/dockview-core/src/__tests__/gridview/baseComponentGridview.spec.ts @@ -70,8 +70,8 @@ class TestPanel implements IGridPanelView { } class ClassUnderTest extends BaseGrid { - constructor(element: HTMLElement, options: BaseGridOptions) { - super(element, options); + constructor(options: BaseGridOptions) { + super(options); } doRemoveGroup( @@ -108,7 +108,8 @@ class ClassUnderTest extends BaseGrid { describe('baseComponentGridview', () => { test('can add group', () => { - const cut = new ClassUnderTest(document.createElement('div'), { + const cut = new ClassUnderTest({ + parentElement: document.createElement('div'), orientation: Orientation.HORIZONTAL, proportionalLayout: true, }); diff --git a/packages/dockview-core/src/__tests__/gridview/gridviewComponent.spec.ts b/packages/dockview-core/src/__tests__/gridview/gridviewComponent.spec.ts index f28c2f828..083526119 100644 --- a/packages/dockview-core/src/__tests__/gridview/gridviewComponent.spec.ts +++ b/packages/dockview-core/src/__tests__/gridview/gridviewComponent.spec.ts @@ -33,7 +33,8 @@ describe('gridview', () => { }); test('added views are visible by default', () => { - const gridview = new GridviewComponent(container, { + const gridview = new GridviewComponent({ + parentElement: container, proportionalLayout: false, orientation: Orientation.VERTICAL, components: { default: TestGridview }, @@ -52,7 +53,8 @@ describe('gridview', () => { }); test('remove panel', () => { - const gridview = new GridviewComponent(container, { + const gridview = new GridviewComponent({ + parentElement: container, proportionalLayout: false, orientation: Orientation.VERTICAL, components: { default: TestGridview }, @@ -82,7 +84,8 @@ describe('gridview', () => { }); test('active panel', () => { - const gridview = new GridviewComponent(container, { + const gridview = new GridviewComponent({ + parentElement: container, proportionalLayout: false, orientation: Orientation.VERTICAL, components: { default: TestGridview }, @@ -142,7 +145,8 @@ describe('gridview', () => { }); test('deserialize and serialize a layout', () => { - const gridview = new GridviewComponent(container, { + const gridview = new GridviewComponent({ + parentElement: container, proportionalLayout: false, orientation: Orientation.VERTICAL, components: { default: TestGridview }, @@ -269,7 +273,8 @@ describe('gridview', () => { }); test('toJSON shouldnt fire any layout events', () => { - const gridview = new GridviewComponent(container, { + const gridview = new GridviewComponent({ + parentElement: container, proportionalLayout: false, orientation: Orientation.VERTICAL, components: { default: TestGridview }, @@ -305,7 +310,8 @@ describe('gridview', () => { }); test('gridview events', () => { - const gridview = new GridviewComponent(container, { + const gridview = new GridviewComponent({ + parentElement: container, proportionalLayout: false, orientation: Orientation.VERTICAL, components: { default: TestGridview }, @@ -428,7 +434,8 @@ describe('gridview', () => { test('dispose of gridviewComponent', () => { expect(container.childNodes.length).toBe(0); - const gridview = new GridviewComponent(container, { + const gridview = new GridviewComponent({ + parentElement: container, proportionalLayout: false, orientation: Orientation.VERTICAL, components: { default: TestGridview }, @@ -457,7 +464,8 @@ describe('gridview', () => { }); test('#1/VERTICAL', () => { - const gridview = new GridviewComponent(container, { + const gridview = new GridviewComponent({ + parentElement: container, proportionalLayout: true, orientation: Orientation.VERTICAL, components: { default: TestGridview }, @@ -513,7 +521,8 @@ describe('gridview', () => { }); test('#2/HORIZONTAL', () => { - const gridview = new GridviewComponent(container, { + const gridview = new GridviewComponent({ + parentElement: container, proportionalLayout: true, orientation: Orientation.HORIZONTAL, components: { default: TestGridview }, @@ -571,7 +580,8 @@ describe('gridview', () => { }); test('#3/HORIZONTAL', () => { - const gridview = new GridviewComponent(container, { + const gridview = new GridviewComponent({ + parentElement: container, proportionalLayout: true, orientation: Orientation.HORIZONTAL, components: { default: TestGridview }, @@ -647,7 +657,8 @@ describe('gridview', () => { }); test('#4/HORIZONTAL', () => { - const gridview = new GridviewComponent(container, { + const gridview = new GridviewComponent({ + parentElement: container, proportionalLayout: true, orientation: Orientation.HORIZONTAL, components: { default: TestGridview }, @@ -741,7 +752,8 @@ describe('gridview', () => { }); test('#5/VERTICAL', () => { - const gridview = new GridviewComponent(container, { + const gridview = new GridviewComponent({ + parentElement: container, proportionalLayout: true, orientation: Orientation.VERTICAL, components: { default: TestGridview }, @@ -835,7 +847,8 @@ describe('gridview', () => { }); test('#5/VERTICAL/proportional/false', () => { - const gridview = new GridviewComponent(container, { + const gridview = new GridviewComponent({ + parentElement: container, proportionalLayout: false, orientation: Orientation.VERTICAL, components: { default: TestGridview }, @@ -928,7 +941,8 @@ describe('gridview', () => { }); test('#6/VERTICAL', () => { - const gridview = new GridviewComponent(container, { + const gridview = new GridviewComponent({ + parentElement: container, proportionalLayout: true, orientation: Orientation.VERTICAL, components: { default: TestGridview }, @@ -1052,7 +1066,8 @@ describe('gridview', () => { }); test('#7/VERTICAL layout first', () => { - const gridview = new GridviewComponent(container, { + const gridview = new GridviewComponent({ + parentElement: container, proportionalLayout: true, orientation: Orientation.VERTICAL, components: { default: TestGridview }, @@ -1176,7 +1191,8 @@ describe('gridview', () => { }); test('#8/VERTICAL layout after', () => { - const gridview = new GridviewComponent(container, { + const gridview = new GridviewComponent({ + parentElement: container, proportionalLayout: true, orientation: Orientation.VERTICAL, components: { default: TestGridview }, @@ -1299,7 +1315,8 @@ describe('gridview', () => { }); test('#9/HORIZONTAL', () => { - const gridview = new GridviewComponent(container, { + const gridview = new GridviewComponent({ + parentElement: container, proportionalLayout: true, orientation: Orientation.HORIZONTAL, components: { default: TestGridview }, @@ -1421,7 +1438,8 @@ describe('gridview', () => { }); test('#9/HORIZONTAL/proportional/false', () => { - const gridview = new GridviewComponent(container, { + const gridview = new GridviewComponent({ + parentElement: container, proportionalLayout: false, orientation: Orientation.HORIZONTAL, components: { default: TestGridview }, @@ -1543,7 +1561,8 @@ describe('gridview', () => { }); test('#10/HORIZONTAL scale x:1.5 y:2', () => { - const gridview = new GridviewComponent(container, { + const gridview = new GridviewComponent({ + parentElement: container, proportionalLayout: true, orientation: Orientation.HORIZONTAL, components: { default: TestGridview }, @@ -1670,7 +1689,8 @@ describe('gridview', () => { }); test('panel is disposed of when component is disposed', () => { - const gridview = new GridviewComponent(container, { + const gridview = new GridviewComponent({ + parentElement: container, proportionalLayout: false, orientation: Orientation.VERTICAL, components: { default: TestGridview }, @@ -1700,7 +1720,8 @@ describe('gridview', () => { }); test('panel is disposed of when removed', () => { - const gridview = new GridviewComponent(container, { + const gridview = new GridviewComponent({ + parentElement: container, proportionalLayout: false, orientation: Orientation.VERTICAL, components: { default: TestGridview }, @@ -1729,7 +1750,8 @@ describe('gridview', () => { }); test('panel is disposed of when fromJSON is called', () => { - const gridview = new GridviewComponent(container, { + const gridview = new GridviewComponent({ + parentElement: container, proportionalLayout: false, orientation: Orientation.VERTICAL, components: { default: TestGridview }, @@ -1767,7 +1789,8 @@ describe('gridview', () => { test('fromJSON events should still fire', () => { jest.useFakeTimers(); - const gridview = new GridviewComponent(container, { + const gridview = new GridviewComponent({ + parentElement: container, proportionalLayout: true, orientation: Orientation.HORIZONTAL, components: { default: TestGridview }, diff --git a/packages/dockview-core/src/__tests__/groupview/dockviewGroupPanelModel.spec.ts b/packages/dockview-core/src/__tests__/groupview/dockviewGroupPanelModel.spec.ts index 64ba6c717..4bbc0237f 100644 --- a/packages/dockview-core/src/__tests__/groupview/dockviewGroupPanelModel.spec.ts +++ b/packages/dockview-core/src/__tests__/groupview/dockviewGroupPanelModel.spec.ts @@ -490,7 +490,8 @@ describe('groupview', () => { }); test('that group is set on panel during onDidAddPanel event', () => { - const cut = new DockviewComponent(document.createElement('div'), { + const cut = new DockviewComponent({ + parentElement: document.createElement('div'), components: { component: TestContentPart, }, @@ -505,14 +506,12 @@ describe('groupview', () => { }); test('toJSON() default', () => { - const dockviewComponent = new DockviewComponent( - document.createElement('div'), - { - components: { - component: TestContentPart, - }, - } - ); + const dockviewComponent = new DockviewComponent({ + parentElement: document.createElement('div'), + components: { + component: TestContentPart, + }, + }); const cut = new DockviewGroupPanelModel( document.createElement('div'), @@ -530,14 +529,12 @@ describe('groupview', () => { }); test('toJSON() locked and hideHeader', () => { - const dockviewComponent = new DockviewComponent( - document.createElement('div'), - { - components: { - component: TestContentPart, - }, - } - ); + const dockviewComponent = new DockviewComponent({ + parentElement: document.createElement('div'), + components: { + component: TestContentPart, + }, + }); const cut = new DockviewGroupPanelModel( document.createElement('div'), @@ -560,14 +557,12 @@ describe('groupview', () => { }); test("that openPanel with skipSetActive doesn't set panel to active", () => { - const dockviewComponent = new DockviewComponent( - document.createElement('div'), - { - components: { - component: TestContentPart, - }, - } - ); + const dockviewComponent = new DockviewComponent({ + parentElement: document.createElement('div'), + components: { + component: TestContentPart, + }, + }); const groupviewContainer = document.createElement('div'); const cut = new DockviewGroupPanelModel( diff --git a/packages/dockview-core/src/__tests__/lifecycle.spec.ts b/packages/dockview-core/src/__tests__/lifecycle.spec.ts index 100b04f5b..db67c750c 100644 --- a/packages/dockview-core/src/__tests__/lifecycle.spec.ts +++ b/packages/dockview-core/src/__tests__/lifecycle.spec.ts @@ -48,4 +48,20 @@ describe('lifecycle', () => { expect(d3.dispose).toHaveBeenCalledTimes(1); expect(d4.dispose).toHaveBeenCalledTimes(1); }); + + test('that isDisposed=true once CompositeDisposable is disposed', () => { + class Test extends CompositeDisposable { + checkIsDisposed(): boolean { + return this.isDisposed; + } + } + + const cut = new Test(); + + expect(cut.checkIsDisposed()).toBeFalsy(); + + cut.dispose(); + + expect(cut.checkIsDisposed()).toBeTruthy(); + }); }); diff --git a/packages/dockview-core/src/__tests__/paneview/paneviewComponent.spec.ts b/packages/dockview-core/src/__tests__/paneview/paneviewComponent.spec.ts index 859095735..cb5763046 100644 --- a/packages/dockview-core/src/__tests__/paneview/paneviewComponent.spec.ts +++ b/packages/dockview-core/src/__tests__/paneview/paneviewComponent.spec.ts @@ -71,7 +71,8 @@ describe('componentPaneview', () => { test('vertical panels', () => { const disposables = new CompositeDisposable(); - const paneview = new PaneviewComponent(container, { + const paneview = new PaneviewComponent({ + parentElement: container, components: { testPanel: TestPanel, }, @@ -141,7 +142,8 @@ describe('componentPaneview', () => { }); test('serialization', () => { - const paneview = new PaneviewComponent(container, { + const paneview = new PaneviewComponent({ + parentElement: container, components: { testPanel: TestPanel, }, @@ -249,7 +251,8 @@ describe('componentPaneview', () => { }); test('toJSON shouldnt fire any layout events', () => { - const paneview = new PaneviewComponent(container, { + const paneview = new PaneviewComponent({ + parentElement: container, components: { testPanel: TestPanel, }, @@ -280,7 +283,8 @@ describe('componentPaneview', () => { test('dispose of paneviewComponent', () => { expect(container.childNodes.length).toBe(0); - const paneview = new PaneviewComponent(container, { + const paneview = new PaneviewComponent({ + parentElement: container, components: { testPanel: TestPanel, }, @@ -307,7 +311,8 @@ describe('componentPaneview', () => { }); test('panel is disposed of when component is disposed', () => { - const paneview = new PaneviewComponent(container, { + const paneview = new PaneviewComponent({ + parentElement: container, components: { testPanel: TestPanel, }, @@ -326,8 +331,8 @@ describe('componentPaneview', () => { title: 'Panel 2', }); - const panel1 = paneview.getPanel('panel1'); - const panel2 = paneview.getPanel('panel2'); + const panel1 = paneview.getPanel('panel1')!; + const panel2 = paneview.getPanel('panel2')!; const panel1Spy = jest.spyOn(panel1, 'dispose'); const panel2Spy = jest.spyOn(panel2, 'dispose'); @@ -339,7 +344,8 @@ describe('componentPaneview', () => { }); test('panel is disposed of when removed', () => { - const paneview = new PaneviewComponent(container, { + const paneview = new PaneviewComponent({ + parentElement: container, components: { testPanel: TestPanel, }, @@ -358,8 +364,8 @@ describe('componentPaneview', () => { title: 'Panel 2', }); - const panel1 = paneview.getPanel('panel1'); - const panel2 = paneview.getPanel('panel2'); + const panel1 = paneview.getPanel('panel1')!; + const panel2 = paneview.getPanel('panel2')!; const panel1Spy = jest.spyOn(panel1, 'dispose'); const panel2Spy = jest.spyOn(panel2, 'dispose'); @@ -371,7 +377,8 @@ describe('componentPaneview', () => { }); test('panel is disposed of when fromJSON is called', () => { - const paneview = new PaneviewComponent(container, { + const paneview = new PaneviewComponent({ + parentElement: container, components: { testPanel: TestPanel, }, @@ -390,8 +397,8 @@ describe('componentPaneview', () => { title: 'Panel 2', }); - const panel1 = paneview.getPanel('panel1'); - const panel2 = paneview.getPanel('panel2'); + const panel1 = paneview.getPanel('panel1')!; + const panel2 = paneview.getPanel('panel2')!; const panel1Spy = jest.spyOn(panel1, 'dispose'); const panel2Spy = jest.spyOn(panel2, 'dispose'); diff --git a/packages/dockview-core/src/__tests__/splitview/splitviewComponent.spec.ts b/packages/dockview-core/src/__tests__/splitview/splitviewComponent.spec.ts index 03450f1f1..e3c16e751 100644 --- a/packages/dockview-core/src/__tests__/splitview/splitviewComponent.spec.ts +++ b/packages/dockview-core/src/__tests__/splitview/splitviewComponent.spec.ts @@ -26,7 +26,8 @@ describe('componentSplitview', () => { }); test('remove panel', () => { - const splitview = new SplitviewComponent(container, { + const splitview = new SplitviewComponent({ + parentElement: container, orientation: Orientation.VERTICAL, components: { testPanel: TestPanel, @@ -38,9 +39,9 @@ describe('componentSplitview', () => { splitview.addPanel({ id: 'panel2', component: 'testPanel' }); splitview.addPanel({ id: 'panel3', component: 'testPanel' }); - const panel1 = splitview.getPanel('panel1'); - const panel2 = splitview.getPanel('panel2'); - const panel3 = splitview.getPanel('panel3'); + const panel1 = splitview.getPanel('panel1')!; + const panel2 = splitview.getPanel('panel2')!; + const panel3 = splitview.getPanel('panel3')!; expect(panel1.api.isActive).toBeFalsy(); expect(panel2.api.isActive).toBeFalsy(); @@ -61,7 +62,8 @@ describe('componentSplitview', () => { }); test('horizontal dimensions', () => { - const splitview = new SplitviewComponent(container, { + const splitview = new SplitviewComponent({ + parentElement: container, orientation: Orientation.HORIZONTAL, components: { testPanel: TestPanel, @@ -74,7 +76,8 @@ describe('componentSplitview', () => { }); test('vertical dimensions', () => { - const splitview = new SplitviewComponent(container, { + const splitview = new SplitviewComponent({ + parentElement: container, orientation: Orientation.VERTICAL, components: { testPanel: TestPanel, @@ -87,7 +90,8 @@ describe('componentSplitview', () => { }); test('api resize', () => { - const splitview = new SplitviewComponent(container, { + const splitview = new SplitviewComponent({ + parentElement: container, orientation: Orientation.VERTICAL, components: { testPanel: TestPanel, @@ -99,9 +103,9 @@ describe('componentSplitview', () => { splitview.addPanel({ id: 'panel2', component: 'testPanel' }); splitview.addPanel({ id: 'panel3', component: 'testPanel' }); - const panel1 = splitview.getPanel('panel1'); - const panel2 = splitview.getPanel('panel2'); - const panel3 = splitview.getPanel('panel3'); + const panel1 = splitview.getPanel('panel1')!; + const panel2 = splitview.getPanel('panel2')!; + const panel3 = splitview.getPanel('panel3')!; expect(panel1.width).toBe(400); expect(panel1.height).toBe(200); @@ -139,7 +143,8 @@ describe('componentSplitview', () => { }); test('api', () => { - const splitview = new SplitviewComponent(container, { + const splitview = new SplitviewComponent({ + parentElement: container, orientation: Orientation.HORIZONTAL, components: { testPanel: TestPanel, @@ -180,7 +185,8 @@ describe('componentSplitview', () => { test('vertical panels', () => { const disposables = new CompositeDisposable(); - const splitview = new SplitviewComponent(container, { + const splitview = new SplitviewComponent({ + parentElement: container, orientation: Orientation.VERTICAL, components: { testPanel: TestPanel, @@ -229,7 +235,8 @@ describe('componentSplitview', () => { test('horizontal panels', () => { const disposables = new CompositeDisposable(); - const splitview = new SplitviewComponent(container, { + const splitview = new SplitviewComponent({ + parentElement: container, orientation: Orientation.HORIZONTAL, components: { testPanel: TestPanel, @@ -276,7 +283,8 @@ describe('componentSplitview', () => { }); test('serialization', () => { - const splitview = new SplitviewComponent(container, { + const splitview = new SplitviewComponent({ + parentElement: container, orientation: Orientation.VERTICAL, components: { testPanel: TestPanel, @@ -330,7 +338,8 @@ describe('componentSplitview', () => { }); test('toJSON shouldnt fire any layout events', () => { - const splitview = new SplitviewComponent(container, { + const splitview = new SplitviewComponent({ + parentElement: container, orientation: Orientation.HORIZONTAL, components: { testPanel: TestPanel, @@ -361,7 +370,8 @@ describe('componentSplitview', () => { test('dispose of splitviewComponent', () => { expect(container.childNodes.length).toBe(0); - const splitview = new SplitviewComponent(container, { + const splitview = new SplitviewComponent({ + parentElement: container, orientation: Orientation.HORIZONTAL, components: { testPanel: TestPanel, @@ -387,7 +397,8 @@ describe('componentSplitview', () => { }); test('panel is disposed of when component is disposed', () => { - const splitview = new SplitviewComponent(container, { + const splitview = new SplitviewComponent({ + parentElement: container, orientation: Orientation.HORIZONTAL, components: { default: TestPanel, @@ -405,8 +416,8 @@ describe('componentSplitview', () => { component: 'default', }); - const panel1 = splitview.getPanel('panel1'); - const panel2 = splitview.getPanel('panel2'); + const panel1 = splitview.getPanel('panel1')!; + const panel2 = splitview.getPanel('panel2')!; const panel1Spy = jest.spyOn(panel1, 'dispose'); const panel2Spy = jest.spyOn(panel2, 'dispose'); @@ -418,7 +429,8 @@ describe('componentSplitview', () => { }); test('panel is disposed of when removed', () => { - const splitview = new SplitviewComponent(container, { + const splitview = new SplitviewComponent({ + parentElement: container, orientation: Orientation.HORIZONTAL, components: { default: TestPanel, @@ -436,8 +448,8 @@ describe('componentSplitview', () => { component: 'default', }); - const panel1 = splitview.getPanel('panel1'); - const panel2 = splitview.getPanel('panel2'); + const panel1 = splitview.getPanel('panel1')!; + const panel2 = splitview.getPanel('panel2')!; const panel1Spy = jest.spyOn(panel1, 'dispose'); const panel2Spy = jest.spyOn(panel2, 'dispose'); @@ -449,7 +461,8 @@ describe('componentSplitview', () => { }); test('panel is disposed of when fromJSON is called', () => { - const splitview = new SplitviewComponent(container, { + const splitview = new SplitviewComponent({ + parentElement: container, orientation: Orientation.HORIZONTAL, components: { default: TestPanel, @@ -467,8 +480,8 @@ describe('componentSplitview', () => { component: 'default', }); - const panel1 = splitview.getPanel('panel1'); - const panel2 = splitview.getPanel('panel2'); + const panel1 = splitview.getPanel('panel1')!; + const panel2 = splitview.getPanel('panel2')!; const panel1Spy = jest.spyOn(panel1, 'dispose'); const panel2Spy = jest.spyOn(panel2, 'dispose'); diff --git a/packages/dockview-core/src/dockview/components/watermark/watermark.ts b/packages/dockview-core/src/dockview/components/watermark/watermark.ts index adeed029a..28ecf9c7c 100644 --- a/packages/dockview-core/src/dockview/components/watermark/watermark.ts +++ b/packages/dockview-core/src/dockview/components/watermark/watermark.ts @@ -1,5 +1,4 @@ import { - GroupPanelPartInitParameters, IWatermarkRenderer, WatermarkRendererInitParameters, } from '../../types'; @@ -9,14 +8,15 @@ import { CompositeDisposable } from '../../../lifecycle'; import { DockviewGroupPanel } from '../../dockviewGroupPanel'; import { PanelUpdateEvent } from '../../../panel/types'; import { createCloseButton } from '../../../svg'; +import { DockviewApi } from '../../../api/component.api'; export class Watermark extends CompositeDisposable implements IWatermarkRenderer { private _element: HTMLElement; - private group: DockviewGroupPanel | undefined; - private params: GroupPanelPartInitParameters | undefined; + private _group: DockviewGroupPanel | undefined; + private _api: DockviewApi | undefined; get element(): HTMLElement { return this._element; @@ -54,8 +54,8 @@ export class Watermark this.addDisposables( addDisposableListener(closeAnchor, 'click', (ev) => { ev.preventDefault(); - if (this.group) { - this.params?.containerApi.removeGroup(this.group); + if (this._group) { + this._api?.removeGroup(this._group); } }) ); @@ -74,11 +74,12 @@ export class Watermark } init(_params: WatermarkRendererInitParameters): void { + this._api = _params.containerApi; this.render(); } updateParentGroup(group: DockviewGroupPanel, _visible: boolean): void { - this.group = group; + this._group = group; this.render(); } @@ -87,9 +88,7 @@ export class Watermark } private render(): void { - const isOneGroup = !!( - this.params && this.params.containerApi.size <= 1 - ); + const isOneGroup = !!(this._api && this._api.size <= 1); toggleClass(this.element, 'has-actions', isOneGroup); } } diff --git a/packages/dockview-core/src/dockview/dockviewComponent.ts b/packages/dockview-core/src/dockview/dockviewComponent.ts index 5ffbf99c2..13eb455aa 100644 --- a/packages/dockview-core/src/dockview/dockviewComponent.ts +++ b/packages/dockview-core/src/dockview/dockviewComponent.ts @@ -185,11 +185,12 @@ export class DockviewComponent return this.options.tabHeight; } - constructor(element: HTMLElement, options: DockviewComponentOptions) { - super(element, { + constructor(options: DockviewComponentOptions) { + super({ proportionalLayout: true, orientation: options.orientation || Orientation.HORIZONTAL, styles: options.styles, + parentElement: options.parentElement, }); this.element.classList.add('dv-dockview'); diff --git a/packages/dockview-core/src/dockview/options.ts b/packages/dockview-core/src/dockview/options.ts index 6e83797d7..f1751c7fb 100644 --- a/packages/dockview-core/src/dockview/options.ts +++ b/packages/dockview-core/src/dockview/options.ts @@ -84,6 +84,7 @@ export interface DockviewComponentOptions extends DockviewRenderFunctions { group: DockviewGroupPanel ) => IGroupControlRenderer; singleTabMode?: 'fullwidth' | 'default'; + parentElement?: HTMLElement; } export interface PanelOptions { diff --git a/packages/dockview-core/src/dom.ts b/packages/dockview-core/src/dom.ts index 3d08bb8b2..eb1a37c05 100644 --- a/packages/dockview-core/src/dom.ts +++ b/packages/dockview-core/src/dom.ts @@ -11,8 +11,15 @@ export function watchElementResize( cb: (entry: ResizeObserverEntry) => void ): IDisposable { const observer = new ResizeObserver((entires) => { - const firstEntry = entires[0]; - cb(firstEntry); + /** + * Fast browser window resize produces Error: ResizeObserver loop limit exceeded. + * The error isn't visible in browser console, doesn't affect functionality, but degrades performance. + * See https://stackoverflow.com/questions/49384120/resizeobserver-loop-limit-exceeded/58701523#58701523 + */ + requestAnimationFrame(() => { + const firstEntry = entires[0]; + cb(firstEntry); + }); }); observer.observe(element); diff --git a/packages/dockview-core/src/gridview/baseComponentGridview.ts b/packages/dockview-core/src/gridview/baseComponentGridview.ts index 9c6e6b4de..7f2c281df 100644 --- a/packages/dockview-core/src/gridview/baseComponentGridview.ts +++ b/packages/dockview-core/src/gridview/baseComponentGridview.ts @@ -1,11 +1,12 @@ import { Emitter, Event, TickDelayedEvent } from '../events'; import { getGridLocation, Gridview, IGridView } from './gridview'; import { Position } from '../dnd/droptarget'; -import { CompositeDisposable, IValueDisposable } from '../lifecycle'; +import { IValueDisposable } from '../lifecycle'; import { sequentialNumberGenerator } from '../math'; import { ISplitviewStyles, Orientation, Sizing } from '../splitview/splitview'; import { IPanel } from '../panel/types'; import { MovementOptions2 } from '../dockview/options'; +import { Resizable } from '../resizable'; const nextLayoutId = sequentialNumberGenerator(); @@ -31,6 +32,7 @@ export interface BaseGridOptions { readonly proportionalLayout: boolean; readonly orientation: Orientation; readonly styles?: ISplitviewStyles; + readonly parentElement?: HTMLElement; } export interface IGridPanelView extends IGridView, IPanel { @@ -64,7 +66,7 @@ export interface IBaseGrid { } export abstract class BaseGrid - extends CompositeDisposable + extends Resizable implements IBaseGrid { private readonly _id = nextLayoutId.next(); @@ -92,10 +94,6 @@ export abstract class BaseGrid return this._id; } - get element(): HTMLElement { - return this._element; - } - get size(): number { return this._groups.size; } @@ -129,11 +127,8 @@ export abstract class BaseGrid return this._activeGroup; } - constructor( - private readonly _element: HTMLElement, - options: BaseGridOptions - ) { - super(); + constructor(options: BaseGridOptions) { + super(options.parentElement); this.gridview = new Gridview( !!options.proportionalLayout, @@ -295,8 +290,8 @@ export abstract class BaseGrid return; } - this.element.style.height = `${height}px`; - this.element.style.width = `${width}px`; + this.gridview.element.style.height = `${height}px`; + this.gridview.element.style.width = `${width}px`; this.gridview.layout(width, height); } diff --git a/packages/dockview-core/src/gridview/gridviewComponent.ts b/packages/dockview-core/src/gridview/gridviewComponent.ts index 13651be30..b216cd8a9 100644 --- a/packages/dockview-core/src/gridview/gridviewComponent.ts +++ b/packages/dockview-core/src/gridview/gridviewComponent.ts @@ -100,8 +100,9 @@ export class GridviewComponent this._deserializer = value; } - constructor(element: HTMLElement, options: GridviewComponentOptions) { - super(element, { + constructor(options: GridviewComponentOptions) { + super({ + parentElement: options.parentElement, proportionalLayout: options.proportionalLayout, orientation: options.orientation, styles: options.styles, diff --git a/packages/dockview-core/src/gridview/options.ts b/packages/dockview-core/src/gridview/options.ts index 8125f9127..7596bb0b2 100644 --- a/packages/dockview-core/src/gridview/options.ts +++ b/packages/dockview-core/src/gridview/options.ts @@ -16,4 +16,5 @@ export interface GridviewComponentOptions { frameworkComponentFactory?: FrameworkFactory; tabHeight?: number; styles?: ISplitviewStyles; + parentElement?: HTMLElement; } diff --git a/packages/dockview-core/src/lifecycle.ts b/packages/dockview-core/src/lifecycle.ts index d71947174..e756bc803 100644 --- a/packages/dockview-core/src/lifecycle.ts +++ b/packages/dockview-core/src/lifecycle.ts @@ -17,6 +17,11 @@ export namespace Disposable { export class CompositeDisposable { private readonly disposables: IDisposable[]; + private _isDisposed = false; + + protected get isDisposed(): boolean { + return this._isDisposed; + } public static from(...args: IDisposable[]): CompositeDisposable { return new CompositeDisposable(...args); @@ -32,6 +37,8 @@ export class CompositeDisposable { public dispose(): void { this.disposables.forEach((arg) => arg.dispose()); + + this._isDisposed = true; } } diff --git a/packages/dockview-core/src/paneview/options.ts b/packages/dockview-core/src/paneview/options.ts index 91fd9c6fe..00763e652 100644 --- a/packages/dockview-core/src/paneview/options.ts +++ b/packages/dockview-core/src/paneview/options.ts @@ -25,4 +25,5 @@ export interface PaneviewComponentOptions { }; disableDnd?: boolean; showDndOverlay?: (event: PaneviewDndOverlayEvent) => boolean; + parentElement?: HTMLElement; } diff --git a/packages/dockview-core/src/paneview/paneviewComponent.ts b/packages/dockview-core/src/paneview/paneviewComponent.ts index 50d8ae307..290316eb0 100644 --- a/packages/dockview-core/src/paneview/paneviewComponent.ts +++ b/packages/dockview-core/src/paneview/paneviewComponent.ts @@ -22,6 +22,7 @@ import { import { DefaultHeader } from './defaultPaneviewHeader'; import { sequentialNumberGenerator } from '../math'; import { PaneTransfer } from '../dnd/dataTransfer'; +import { Resizable } from '../resizable'; const nextLayoutId = sequentialNumberGenerator(); @@ -126,10 +127,7 @@ export interface IPaneviewComponent extends IDisposable { clear(): void; } -export class PaneviewComponent - extends CompositeDisposable - implements IPaneviewComponent -{ +export class PaneviewComponent extends Resizable implements IPaneviewComponent { private readonly _id = nextLayoutId.next(); private _options: PaneviewComponentOptions; private _disposable = new MutableDisposable(); @@ -199,11 +197,8 @@ export class PaneviewComponent return this._options; } - constructor( - private element: HTMLElement, - options: PaneviewComponentOptions - ) { - super(); + constructor(options: PaneviewComponentOptions) { + super(options.parentElement); this.addDisposables( this._onDidLayoutChange, diff --git a/packages/dockview-core/src/resizable.ts b/packages/dockview-core/src/resizable.ts new file mode 100644 index 000000000..499ce6615 --- /dev/null +++ b/packages/dockview-core/src/resizable.ts @@ -0,0 +1,39 @@ +import { watchElementResize } from './dom'; +import { CompositeDisposable } from './lifecycle'; + +export abstract class Resizable extends CompositeDisposable { + private readonly _element: HTMLElement; + + get element(): HTMLElement { + return this._element; + } + + constructor(parentElement?: HTMLElement) { + super(); + + if (parentElement) { + this._element = parentElement; + } else { + this._element = document.createElement('div'); + this._element.style.height = '100%'; + this._element.style.width = '100%'; + this._element.className = 'dv-resizable-container'; + } + + this.addDisposables( + watchElementResize(this._element, (entry) => { + if (this.isDisposed) { + /** + * resize is delayed through requestAnimationFrame so there is a small chance + * the component has already been disposed of + */ + return; + } + const { width, height } = entry.contentRect; + this.layout(width, height); + }) + ); + } + + abstract layout(width: number, height: number): void; +} diff --git a/packages/dockview-core/src/splitview/options.ts b/packages/dockview-core/src/splitview/options.ts index e79eb0b0a..7f180cd0a 100644 --- a/packages/dockview-core/src/splitview/options.ts +++ b/packages/dockview-core/src/splitview/options.ts @@ -26,4 +26,5 @@ export interface SplitviewComponentOptions extends SplitViewOptions { [componentName: string]: any; }; frameworkWrapper?: FrameworkFactory; + parentElement?: HTMLElement; } diff --git a/packages/dockview-core/src/splitview/splitviewComponent.ts b/packages/dockview-core/src/splitview/splitviewComponent.ts index e5ebf74b9..f4f0bee7c 100644 --- a/packages/dockview-core/src/splitview/splitviewComponent.ts +++ b/packages/dockview-core/src/splitview/splitviewComponent.ts @@ -16,6 +16,7 @@ import { BaseComponentOptions } from '../panel/types'; import { Emitter, Event } from '../events'; import { SplitviewPanel, ISplitviewPanel } from './splitviewPanel'; import { createComponent } from '../panel/componentFactory'; +import { Resizable } from '../resizable'; export interface SerializedSplitviewPanelData { id: string; @@ -79,7 +80,7 @@ export interface ISplitviewComponent extends IDisposable { * A high-level implementation of splitview that works using 'panels' */ export class SplitviewComponent - extends CompositeDisposable + extends Resizable implements ISplitviewComponent { private _disposable = new MutableDisposable(); @@ -154,11 +155,8 @@ export class SplitviewComponent : this.splitview.orthogonalSize; } - constructor( - private readonly element: HTMLElement, - options: SplitviewComponentOptions - ) { - super(); + constructor(options: SplitviewComponentOptions) { + super(options.parentElement); this._options = options; diff --git a/packages/dockview/package.json b/packages/dockview/package.json index 9b3f65c46..dce0840c5 100644 --- a/packages/dockview/package.json +++ b/packages/dockview/package.json @@ -60,6 +60,7 @@ }, "devDependencies": { "@rollup/plugin-node-resolve": "^15.0.1", + "@rollup/plugin-terser": "^0.4.0", "@rollup/plugin-typescript": "^11.0.0", "@testing-library/react": "^13.4.0", "@types/react": "^18.0.28", @@ -71,7 +72,6 @@ "rimraf": "^4.1.2", "rollup": "^3.15.0", "rollup-plugin-postcss": "^4.0.2", - "rollup-plugin-terser": "^7.0.2", "typedoc": "^0.23.25" } } diff --git a/packages/dockview/rollup.config.js b/packages/dockview/rollup.config.js index 42b354279..ba0fb90fd 100644 --- a/packages/dockview/rollup.config.js +++ b/packages/dockview/rollup.config.js @@ -2,7 +2,7 @@ const { join } = require('path'); const typescript = require('@rollup/plugin-typescript'); -const { terser } = require('rollup-plugin-terser'); +const terser = require('@rollup/plugin-terser'); const postcss = require('rollup-plugin-postcss'); const nodeResolve = require('@rollup/plugin-node-resolve'); @@ -64,10 +64,6 @@ function createBundle(format, options) { }), typescript({ tsconfig: 'tsconfig.esm.json', - incremental: false, - tsBuildInfoFile: undefined, - outDir: undefined, - declaration: false, }), ]; diff --git a/packages/dockview/src/__tests__/dockview/dockview.spec.tsx b/packages/dockview/src/__tests__/dockview/dockview.spec.tsx index 0a9887e7b..2c55b29b7 100644 --- a/packages/dockview/src/__tests__/dockview/dockview.spec.tsx +++ b/packages/dockview/src/__tests__/dockview/dockview.spec.tsx @@ -33,11 +33,13 @@ describe('gridview react', () => { }); test('is sized to container', () => { - setMockRefElement({ - clientHeight: 450, - clientWidth: 650, - appendChild: jest.fn(), - }); + const el = document.createElement('div'); + + jest.spyOn(el, 'clientHeight', 'get').mockReturnValue(450); + jest.spyOn(el, 'clientWidth', 'get').mockReturnValue(650); + + setMockRefElement(el); + let api: DockviewApi | undefined; const onReady = (event: DockviewReadyEvent) => { diff --git a/packages/dockview/src/__tests__/gridview/gridview.spec.tsx b/packages/dockview/src/__tests__/gridview/gridview.spec.tsx index ac4c5c24e..92f81f4c3 100644 --- a/packages/dockview/src/__tests__/gridview/gridview.spec.tsx +++ b/packages/dockview/src/__tests__/gridview/gridview.spec.tsx @@ -39,11 +39,12 @@ describe('gridview react', () => { }); test('is sized to container', () => { - setMockRefElement({ - clientHeight: 450, - clientWidth: 650, - appendChild: jest.fn(), - }); + const el = document.createElement('div') as any; + + jest.spyOn(el, 'clientHeight', 'get').mockReturnValue(450); + jest.spyOn(el, 'clientWidth', 'get').mockReturnValue(650); + + setMockRefElement(el); let api: GridviewApi | undefined; const onReady = (event: GridviewReadyEvent) => { diff --git a/packages/dockview/src/__tests__/react/dockview/dockview.spec.tsx b/packages/dockview/src/__tests__/react/dockview/dockview.spec.tsx index 817e1ed46..b8e9f1bcb 100644 --- a/packages/dockview/src/__tests__/react/dockview/dockview.spec.tsx +++ b/packages/dockview/src/__tests__/react/dockview/dockview.spec.tsx @@ -9,7 +9,7 @@ import { import { PanelCollection } from '../../../types'; import { setMockRefElement } from '../../__test_utils__/utils'; -describe('gridview react', () => { +describe('dockview', () => { let components: PanelCollection; beforeEach(() => { @@ -33,11 +33,12 @@ describe('gridview react', () => { }); test('is sized to container', () => { - setMockRefElement({ - clientHeight: 450, - clientWidth: 650, - appendChild: jest.fn(), - }); + const el = document.createElement('div') as any; + jest.spyOn(el, 'clientHeight', 'get').mockReturnValue(450); + jest.spyOn(el, 'clientWidth', 'get').mockReturnValue(650); + + setMockRefElement(el); + let api: DockviewApi | undefined; const onReady = (event: DockviewReadyEvent) => { diff --git a/packages/dockview/src/dockview/dockview.tsx b/packages/dockview/src/dockview/dockview.tsx index 534a1cca6..f9d97ba03 100644 --- a/packages/dockview/src/dockview/dockview.tsx +++ b/packages/dockview/src/dockview/dockview.tsx @@ -9,7 +9,6 @@ import { DockviewApi, IContentRenderer, ITabRenderer, - watchElementResize, DockviewGroupPanel, } from 'dockview-core'; import { ReactPanelContentPart } from './reactContentPart'; @@ -81,23 +80,12 @@ export const DockviewReact = React.forwardRef( React.useImperativeHandle(ref, () => domRef.current!, []); React.useEffect(() => { - if (props.disableAutoResizing) { + if (!domRef.current) { return () => { - // + // noop }; } - const watcher = watchElementResize(domRef.current!, (entry) => { - const { width, height } = entry.contentRect; - dockviewRef.current?.layout(width, height); - }); - - return () => { - watcher.dispose(); - }; - }, [props.disableAutoResizing]); - - React.useEffect(() => { const factory: GroupPanelFrameworkComponentFactory = { content: { createComponent: ( @@ -142,8 +130,6 @@ export const DockviewReact = React.forwardRef( }, }; - const element = document.createElement('div'); - const frameworkTabComponents = props.tabComponents || {}; if (props.defaultTabComponent) { @@ -151,7 +137,8 @@ export const DockviewReact = React.forwardRef( props.defaultTabComponent; } - const dockview = new DockviewComponent(element, { + const dockview = new DockviewComponent({ + parentElement: domRef.current, frameworkComponentFactory: factory, frameworkComponents: props.components, frameworkTabComponents, @@ -171,9 +158,7 @@ export const DockviewReact = React.forwardRef( singleTabMode: props.singleTabMode, }); - domRef.current?.appendChild(dockview.element); - - const { clientWidth, clientHeight } = domRef.current!; + const { clientWidth, clientHeight } = domRef.current; dockview.layout(clientWidth, clientHeight); if (props.onReady) { @@ -184,7 +169,6 @@ export const DockviewReact = React.forwardRef( return () => { dockview.dispose(); - element.remove(); }; }, []); diff --git a/packages/dockview/src/gridview/gridview.tsx b/packages/dockview/src/gridview/gridview.tsx index bd330e65d..1cb71f427 100644 --- a/packages/dockview/src/gridview/gridview.tsx +++ b/packages/dockview/src/gridview/gridview.tsx @@ -5,7 +5,6 @@ import { GridviewPanelApi, Orientation, GridviewApi, - watchElementResize, } from 'dockview-core'; import { ReactGridPanelView } from './view'; import { usePortalsLifecycle } from '../react'; @@ -40,26 +39,14 @@ export const GridviewReact = React.forwardRef( React.useImperativeHandle(ref, () => domRef.current!, []); React.useEffect(() => { - if (props.disableAutoResizing) { + if (!domRef.current) { return () => { - // + // noop }; } - const watcher = watchElementResize(domRef.current!, (entry) => { - const { width, height } = entry.contentRect; - gridviewRef.current?.layout(width, height); - }); - - return () => { - watcher.dispose(); - }; - }, [props.disableAutoResizing]); - - React.useEffect(() => { - const element = document.createElement('div'); - - const gridview = new GridviewComponent(element, { + const gridview = new GridviewComponent({ + parentElement: domRef.current, proportionalLayout: typeof props.proportionalLayout === 'boolean' ? props.proportionalLayout @@ -83,9 +70,7 @@ export const GridviewReact = React.forwardRef( : undefined, }); - domRef.current?.appendChild(gridview.element); - - const { clientWidth, clientHeight } = domRef.current!; + const { clientWidth, clientHeight } = domRef.current; gridview.layout(clientWidth, clientHeight); if (props.onReady) { @@ -96,7 +81,6 @@ export const GridviewReact = React.forwardRef( return () => { gridview.dispose(); - element.remove(); }; }, []); diff --git a/packages/dockview/src/paneview/paneview.tsx b/packages/dockview/src/paneview/paneview.tsx index ed27f9893..358c15b8a 100644 --- a/packages/dockview/src/paneview/paneview.tsx +++ b/packages/dockview/src/paneview/paneview.tsx @@ -5,7 +5,6 @@ import { IPaneviewComponent, PaneviewDndOverlayEvent, PaneviewApi, - watchElementResize, PaneviewDropEvent, } from 'dockview-core'; import { usePortalsLifecycle } from '../react'; @@ -42,23 +41,6 @@ export const PaneviewReact = React.forwardRef( React.useImperativeHandle(ref, () => domRef.current!, []); - React.useEffect(() => { - if (props.disableAutoResizing) { - return () => { - // - }; - } - - const watcher = watchElementResize(domRef.current!, (entry) => { - const { width, height } = entry.contentRect; - paneviewRef.current?.layout(width, height); - }); - - return () => { - watcher.dispose(); - }; - }, [props.disableAutoResizing]); - React.useEffect(() => { const createComponent = ( id: string, @@ -69,7 +51,8 @@ export const PaneviewReact = React.forwardRef( addPortal, }); - const paneview = new PaneviewComponent(domRef.current!, { + const paneview = new PaneviewComponent({ + parentElement: domRef.current!, frameworkComponents: props.components, components: {}, headerComponents: {}, diff --git a/packages/dockview/src/splitview/splitview.tsx b/packages/dockview/src/splitview/splitview.tsx index d6382a29f..c6536b256 100644 --- a/packages/dockview/src/splitview/splitview.tsx +++ b/packages/dockview/src/splitview/splitview.tsx @@ -5,7 +5,6 @@ import { ISplitviewComponent, SplitviewComponent, Orientation, - watchElementResize, } from 'dockview-core'; import { usePortalsLifecycle } from '../react'; import { PanelCollection, PanelParameters } from '../types'; @@ -40,24 +39,8 @@ export const SplitviewReact = React.forwardRef( React.useImperativeHandle(ref, () => domRef.current!, []); React.useEffect(() => { - if (props.disableAutoResizing) { - return () => { - // - }; - } - - const watcher = watchElementResize(domRef.current!, (entry) => { - const { width, height } = entry.contentRect; - splitviewRef.current?.layout(width, height); - }); - - return () => { - watcher.dispose(); - }; - }, [props.disableAutoResizing]); - - React.useEffect(() => { - const splitview = new SplitviewComponent(domRef.current!, { + const splitview = new SplitviewComponent({ + parentElement: domRef.current!, orientation: props.orientation || Orientation.HORIZONTAL, frameworkComponents: props.components, frameworkWrapper: { diff --git a/packages/docs/docs/components/dockview.mdx b/packages/docs/docs/components/dockview.mdx index 149d9df5c..8d69a0543 100644 --- a/packages/docs/docs/components/dockview.mdx +++ b/packages/docs/docs/components/dockview.mdx @@ -22,8 +22,8 @@ import DockviewNative2 from '@site/sandboxes/nativeapp-dockview/src/app'; import DockviewSetTitle from '@site/sandboxes/updatetitle-dockview/src/app'; import RenderingDockview from '@site/sandboxes/rendering-dockview/src/app'; import DockviewExternalDnd from '@site/sandboxes/externaldnd-dockview/src/app'; -// import { attach as attachDockviewVanilla } from '@site/sandboxes/vanilla-dockview/src/app'; import DockviewResizeContainer from '@site/sandboxes/resizeContainer-dockview/src/app'; +import { attach as attachDockviewVanilla } from '@site/sandboxes/vanilla-dockview/src/app'; # Dockview @@ -713,7 +713,7 @@ hello 2 - + diff --git a/packages/docs/sandboxes/vanilla-dockview/src/app.ts b/packages/docs/sandboxes/vanilla-dockview/src/app.ts index b7ffbe53d..79479e1ae 100644 --- a/packages/docs/sandboxes/vanilla-dockview/src/app.ts +++ b/packages/docs/sandboxes/vanilla-dockview/src/app.ts @@ -25,22 +25,17 @@ export function attach(parent: HTMLElement): { } { const element = document.createElement('div'); element.className = 'dockview-theme-abyss'; - parent.appendChild(element); + element.style.height = '100%'; + element.style.width = '100%'; - const dockview = new DockviewComponent(element, { + const dockview = new DockviewComponent({ components: { default: DefaultPanel, }, + parentElement: element, }); - const observer = new ResizeObserver((entires) => { - const firstEntry = entires[0]; - - const { width, height } = firstEntry.contentRect; - dockview.layout(width, height); - }); - - observer.observe(parent); + parent.appendChild(element); const panel1 = dockview.addPanel({ id: 'panel_1', @@ -78,9 +73,6 @@ export function attach(parent: HTMLElement): { return { dispose: () => { - observer.unobserve(element); - observer.disconnect(); - dockview.dispose(); element.remove(); }, diff --git a/yarn.lock b/yarn.lock index 1d2ba8663..f28480a93 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2680,6 +2680,15 @@ is-module "^1.0.0" resolve "^1.22.1" +"@rollup/plugin-terser@^0.4.0": + version "0.4.0" + resolved "https://registry.yarnpkg.com/@rollup/plugin-terser/-/plugin-terser-0.4.0.tgz#4c76249ad337f3eb04ab409332f23717af2c1fbf" + integrity sha512-Ipcf3LPNerey1q9ZMjiaWHlNPEHNU/B5/uh9zXLltfEQ1lVSLLeZSgAtTPWGyw8Ip1guOeq+mDtdOlEj/wNxQw== + dependencies: + serialize-javascript "^6.0.0" + smob "^0.0.6" + terser "^5.15.1" + "@rollup/plugin-typescript@^11.0.0": version "11.0.0" resolved "https://registry.yarnpkg.com/@rollup/plugin-typescript/-/plugin-typescript-11.0.0.tgz#f136272d1df5209daca0cb6f171c574b1d505545" @@ -9153,15 +9162,6 @@ jest-watcher@^29.5.0: jest-util "^29.5.0" string-length "^4.0.1" -jest-worker@^26.2.1: - version "26.6.2" - resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-26.6.2.tgz#7f72cbc4d643c365e27b9fd775f9d0eaa9c7a8ed" - integrity sha512-KWYVV1c4i+jbMpaBC+U++4Va0cp8OisU185o73T1vo99hqi7w8tSJfUXYswwqqrjzwxa6KpRK54WhPvwf5w6PQ== - dependencies: - "@types/node" "*" - merge-stream "^2.0.0" - supports-color "^7.0.0" - jest-worker@^27.4.5: version "27.5.1" resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-27.5.1.tgz#8d146f0900e8973b106b6f73cc1e9a8cb86f8db0" @@ -12826,16 +12826,6 @@ rollup-plugin-postcss@^4.0.2: safe-identifier "^0.4.2" style-inject "^0.3.0" -rollup-plugin-terser@^7.0.2: - version "7.0.2" - resolved "https://registry.yarnpkg.com/rollup-plugin-terser/-/rollup-plugin-terser-7.0.2.tgz#e8fbba4869981b2dc35ae7e8a502d5c6c04d324d" - integrity sha512-w3iIaU4OxcF52UUXiZNsNeuXIMDvFrr+ZXK6bFZ0Q60qyVfq4uLptoS4bbq3paG3x216eQllFZX7zt6TIImguQ== - dependencies: - "@babel/code-frame" "^7.10.4" - jest-worker "^26.2.1" - serialize-javascript "^4.0.0" - terser "^5.0.0" - rollup-pluginutils@^2.8.2: version "2.8.2" resolved "https://registry.yarnpkg.com/rollup-pluginutils/-/rollup-pluginutils-2.8.2.tgz#72f2af0748b592364dbd3389e600e5a9444a351e" @@ -13077,13 +13067,6 @@ send@0.18.0: range-parser "~1.2.1" statuses "2.0.1" -serialize-javascript@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-4.0.0.tgz#b525e1238489a5ecfc42afacc3fe99e666f4b1aa" - integrity sha512-GaNA54380uFefWghODBWEGisLZFj00nS5ACs6yHa9nLqlLpVLO8ChDGeKRjZnV4Nh4n0Qi7nhYZD/9fCPzEqkw== - dependencies: - randombytes "^2.1.0" - serialize-javascript@^6.0.0, serialize-javascript@^6.0.1: version "6.0.1" resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-6.0.1.tgz#b206efb27c3da0b0ab6b52f48d170b7996458e5c" @@ -13268,6 +13251,11 @@ smart-buffer@^4.2.0: resolved "https://registry.yarnpkg.com/smart-buffer/-/smart-buffer-4.2.0.tgz#6e1d71fa4f18c05f7d0ff216dd16a481d0e8d9ae" integrity sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg== +smob@^0.0.6: + version "0.0.6" + resolved "https://registry.yarnpkg.com/smob/-/smob-0.0.6.tgz#09b268fea916158a2781c152044c6155adbb8aa1" + integrity sha512-V21+XeNni+tTyiST1MHsa84AQhT1aFZipzPpOFAVB8DkHzwJyjjAmt9bgwnuZiZWnIbMo2duE29wybxv/7HWUw== + snapdragon-node@^2.0.1: version "2.1.1" resolved "https://registry.yarnpkg.com/snapdragon-node/-/snapdragon-node-2.1.1.tgz#6c175f86ff14bdb0724563e8f3c1b021a286853b" @@ -13740,7 +13728,7 @@ supports-color@^5.3.0: dependencies: has-flag "^3.0.0" -supports-color@^7.0.0, supports-color@^7.1.0: +supports-color@^7.1.0: version "7.2.0" resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.2.0.tgz#1b7dcdcb32b8138801b3e478ba6a51caa89648da" integrity sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw== @@ -13878,7 +13866,7 @@ terser-webpack-plugin@^5.1.3, terser-webpack-plugin@^5.3.3: serialize-javascript "^6.0.1" terser "^5.16.5" -terser@^5.0.0, terser@^5.10.0, terser@^5.16.5: +terser@^5.10.0, terser@^5.15.1, terser@^5.16.5: version "5.16.8" resolved "https://registry.yarnpkg.com/terser/-/terser-5.16.8.tgz#ccde583dabe71df3f4ed02b65eb6532e0fae15d5" integrity sha512-QI5g1E/ef7d+PsDifb+a6nnVgC4F22Bg6T0xrBrz6iloVB4PUkkunp6V8nzoOOZJIzjWVdAGqCdlKlhLq/TbIA==