diff --git a/packages/dockview-core/src/__tests__/gridview/gridviewComponent.spec.ts b/packages/dockview-core/src/__tests__/gridview/gridviewComponent.spec.ts index ec5f306f8..7f48c3584 100644 --- a/packages/dockview-core/src/__tests__/gridview/gridviewComponent.spec.ts +++ b/packages/dockview-core/src/__tests__/gridview/gridviewComponent.spec.ts @@ -36,7 +36,9 @@ describe('gridview', () => { const gridview = new GridviewComponent(container, { proportionalLayout: false, orientation: Orientation.VERTICAL, - components: { default: TestGridview }, + createComponent: (options) => { + return new TestGridview(options.id, options.name); + }, className: 'test-a test-b', }); @@ -51,7 +53,9 @@ describe('gridview', () => { const gridview = new GridviewComponent(container, { proportionalLayout: false, orientation: Orientation.VERTICAL, - components: { default: TestGridview }, + createComponent: (options) => { + return new TestGridview(options.id, options.name); + }, }); gridview.layout(800, 400); @@ -70,7 +74,9 @@ describe('gridview', () => { const gridview = new GridviewComponent(container, { proportionalLayout: false, orientation: Orientation.VERTICAL, - components: { default: TestGridview }, + createComponent: (options) => { + return new TestGridview(options.id, options.name); + }, }); gridview.layout(800, 400); @@ -100,7 +106,9 @@ describe('gridview', () => { const gridview = new GridviewComponent(container, { proportionalLayout: false, orientation: Orientation.VERTICAL, - components: { default: TestGridview }, + createComponent: (options) => { + return new TestGridview(options.id, options.name); + }, }); gridview.layout(800, 400); @@ -160,7 +168,9 @@ describe('gridview', () => { const gridview = new GridviewComponent(container, { proportionalLayout: false, orientation: Orientation.VERTICAL, - components: { default: TestGridview }, + createComponent: (options) => { + return new TestGridview(options.id, options.name); + }, }); gridview.layout(800, 400); @@ -287,7 +297,9 @@ describe('gridview', () => { const gridview = new GridviewComponent(container, { proportionalLayout: false, orientation: Orientation.VERTICAL, - components: { default: TestGridview }, + createComponent: (options) => { + return new TestGridview(options.id, options.name); + }, }); gridview.layout(1000, 1000); @@ -323,7 +335,9 @@ describe('gridview', () => { const gridview = new GridviewComponent(container, { proportionalLayout: false, orientation: Orientation.VERTICAL, - components: { default: TestGridview }, + createComponent: (options) => { + return new TestGridview(options.id, options.name); + }, }); gridview.layout(800, 400); @@ -446,7 +460,9 @@ describe('gridview', () => { const gridview = new GridviewComponent(container, { proportionalLayout: false, orientation: Orientation.VERTICAL, - components: { default: TestGridview }, + createComponent: (options) => { + return new TestGridview(options.id, options.name); + }, }); gridview.layout(800, 400); @@ -475,7 +491,9 @@ describe('gridview', () => { const gridview = new GridviewComponent(container, { proportionalLayout: true, orientation: Orientation.VERTICAL, - components: { default: TestGridview }, + createComponent: (options) => { + return new TestGridview(options.id, options.name); + }, }); gridview.layout(800, 400); @@ -533,7 +551,9 @@ describe('gridview', () => { const gridview = new GridviewComponent(container, { proportionalLayout: true, orientation: Orientation.HORIZONTAL, - components: { default: TestGridview }, + createComponent: (options) => { + return new TestGridview(options.id, options.name); + }, }); gridview.layout(800, 400); @@ -591,7 +611,9 @@ describe('gridview', () => { const gridview = new GridviewComponent(container, { proportionalLayout: true, orientation: Orientation.HORIZONTAL, - components: { default: TestGridview }, + createComponent: (options) => { + return new TestGridview(options.id, options.name); + }, }); gridview.layout(800, 400); @@ -667,7 +689,9 @@ describe('gridview', () => { const gridview = new GridviewComponent(container, { proportionalLayout: true, orientation: Orientation.HORIZONTAL, - components: { default: TestGridview }, + createComponent: (options) => { + return new TestGridview(options.id, options.name); + }, }); gridview.layout(800, 400); @@ -761,7 +785,9 @@ describe('gridview', () => { const gridview = new GridviewComponent(container, { proportionalLayout: true, orientation: Orientation.VERTICAL, - components: { default: TestGridview }, + createComponent: (options) => { + return new TestGridview(options.id, options.name); + }, }); gridview.layout(800, 400); @@ -855,7 +881,9 @@ describe('gridview', () => { const gridview = new GridviewComponent(container, { proportionalLayout: false, orientation: Orientation.VERTICAL, - components: { default: TestGridview }, + createComponent: (options) => { + return new TestGridview(options.id, options.name); + }, }); gridview.layout(800, 400); @@ -949,7 +977,9 @@ describe('gridview', () => { const gridview = new GridviewComponent(container, { proportionalLayout: true, orientation: Orientation.VERTICAL, - components: { default: TestGridview }, + createComponent: (options) => { + return new TestGridview(options.id, options.name); + }, }); gridview.layout(800, 400); @@ -1073,7 +1103,9 @@ describe('gridview', () => { const gridview = new GridviewComponent(container, { proportionalLayout: true, orientation: Orientation.VERTICAL, - components: { default: TestGridview }, + createComponent: (options) => { + return new TestGridview(options.id, options.name); + }, }); gridview.layout(800, 400); @@ -1197,7 +1229,9 @@ describe('gridview', () => { const gridview = new GridviewComponent(container, { proportionalLayout: true, orientation: Orientation.VERTICAL, - components: { default: TestGridview }, + createComponent: (options) => { + return new TestGridview(options.id, options.name); + }, }); gridview.layout(800, 400); @@ -1323,7 +1357,9 @@ describe('gridview', () => { const gridview = new GridviewComponent(container, { proportionalLayout: true, orientation: Orientation.HORIZONTAL, - components: { default: TestGridview }, + createComponent: (options) => { + return new TestGridview(options.id, options.name); + }, }); gridview.layout(800, 400); @@ -1447,7 +1483,9 @@ describe('gridview', () => { const gridview = new GridviewComponent(container, { proportionalLayout: false, orientation: Orientation.HORIZONTAL, - components: { default: TestGridview }, + createComponent: (options) => { + return new TestGridview(options.id, options.name); + }, }); gridview.layout(800, 400); @@ -1571,7 +1609,9 @@ describe('gridview', () => { const gridview = new GridviewComponent(container, { proportionalLayout: true, orientation: Orientation.HORIZONTAL, - components: { default: TestGridview }, + createComponent: (options) => { + return new TestGridview(options.id, options.name); + }, }); gridview.fromJSON({ @@ -1698,7 +1738,9 @@ describe('gridview', () => { const gridview = new GridviewComponent(container, { proportionalLayout: false, orientation: Orientation.VERTICAL, - components: { default: TestGridview }, + createComponent: (options) => { + return new TestGridview(options.id, options.name); + }, }); gridview.layout(1000, 1000); @@ -1728,7 +1770,9 @@ describe('gridview', () => { const gridview = new GridviewComponent(container, { proportionalLayout: false, orientation: Orientation.VERTICAL, - components: { default: TestGridview }, + createComponent: (options) => { + return new TestGridview(options.id, options.name); + }, }); gridview.layout(1000, 1000); @@ -1757,7 +1801,9 @@ describe('gridview', () => { const gridview = new GridviewComponent(container, { proportionalLayout: false, orientation: Orientation.VERTICAL, - components: { default: TestGridview }, + createComponent: (options) => { + return new TestGridview(options.id, options.name); + }, }); gridview.layout(1000, 1000); @@ -1795,7 +1841,9 @@ describe('gridview', () => { const gridview = new GridviewComponent(container, { proportionalLayout: true, orientation: Orientation.HORIZONTAL, - components: { default: TestGridview }, + createComponent: (options) => { + return new TestGridview(options.id, options.name); + }, }); let addGroup: GridviewPanel[] = []; @@ -1917,7 +1965,9 @@ describe('gridview', () => { const gridview = new GridviewComponent(container, { proportionalLayout: true, orientation: Orientation.VERTICAL, - components: { default: TestGridview }, + createComponent: (options) => { + return new TestGridview(options.id, options.name); + }, }); gridview.layout(1600, 800); @@ -2043,7 +2093,9 @@ describe('gridview', () => { const gridview = new GridviewComponent(container, { proportionalLayout: true, orientation: Orientation.VERTICAL, - components: { default: TestGridview }, + createComponent: (options) => { + return new TestGridview(options.id, options.name); + }, }); gridview.layout(6000, 5000); @@ -2318,7 +2370,9 @@ describe('gridview', () => { const gridview = new GridviewComponent(container, { proportionalLayout: true, orientation: Orientation.VERTICAL, - components: { default: TestGridview }, + createComponent: (options) => { + return new TestGridview(options.id, options.name); + }, }); gridview.layout(5000, 6000); @@ -2591,7 +2645,14 @@ describe('gridview', () => { const gridview = new GridviewComponent(container, { proportionalLayout: true, orientation: Orientation.HORIZONTAL, - components: { default: TestGridview }, + createComponent: (options) => { + switch (options.name) { + case 'default': + return new TestGridview(options.id, options.name); + default: + throw new Error(`unsupported panel '${options.name}'`); + } + }, }); let el = gridview.element.querySelector('.dv-view-container'); @@ -2655,9 +2716,7 @@ describe('gridview', () => { }, activePanel: 'panel_1', }); - }).toThrow( - "Cannot create 'panel_1', no component 'somethingBad' provided" - ); + }).toThrow("unsupported panel 'somethingBad'"); expect(gridview.groups.length).toBe(0); @@ -2670,7 +2729,9 @@ describe('gridview', () => { const gridview = new GridviewComponent(container, { proportionalLayout: true, orientation: Orientation.HORIZONTAL, - components: { default: TestGridview }, + createComponent: (options) => { + return new TestGridview(options.id, options.name); + }, }); expect(gridview.disableResizing).toBeFalsy(); @@ -2680,7 +2741,9 @@ describe('gridview', () => { const gridview = new GridviewComponent(container, { proportionalLayout: true, orientation: Orientation.HORIZONTAL, - components: { default: TestGridview }, + createComponent: (options) => { + return new TestGridview(options.id, options.name); + }, disableAutoResizing: true, }); @@ -2691,7 +2754,9 @@ describe('gridview', () => { const gridview = new GridviewComponent(container, { proportionalLayout: true, orientation: Orientation.HORIZONTAL, - components: { default: TestGridview }, + createComponent: (options) => { + return new TestGridview(options.id, options.name); + }, disableAutoResizing: true, }); gridview.layout(1000, 1000); diff --git a/packages/dockview-core/src/__tests__/panel/componentFactory.spec.ts b/packages/dockview-core/src/__tests__/panel/componentFactory.spec.ts deleted file mode 100644 index 4e330056a..000000000 --- a/packages/dockview-core/src/__tests__/panel/componentFactory.spec.ts +++ /dev/null @@ -1,102 +0,0 @@ -import { createComponent } from '../../panel/componentFactory'; - -describe('componentFactory', () => { - describe('createComponent', () => { - test('valid component and framework component', () => { - const mock = jest.fn(); - const mock2 = jest.fn(); - - expect(() => - createComponent( - 'id-1', - 'component-1', - { 'component-1': mock }, - { 'component-1': mock2 } - ) - ).toThrow( - "Cannot create 'id-1'. component 'component-1' registered as both a component and frameworkComponent" - ); - }); - - test('valid framework component but no factory', () => { - const mock = jest.fn(); - - expect(() => - createComponent( - 'id-1', - 'component-1', - {}, - { 'component-1': mock } - ) - ).toThrow( - "Cannot create 'id-1' for framework component 'component-1'. you must register a frameworkPanelWrapper to use framework components" - ); - }); - - test('valid framework component', () => { - const component = jest.fn(); - const createComponentFn = jest - .fn() - .mockImplementation(() => component); - const frameworkComponent = jest.fn(); - - expect( - createComponent( - 'id-1', - 'component-1', - {}, - { 'component-1': frameworkComponent }, - { - createComponent: createComponentFn, - } - ) - ).toBe(component); - - expect(createComponentFn).toHaveBeenCalledWith( - 'id-1', - 'component-1', - frameworkComponent - ); - }); - - test('no valid component with fallback', () => { - const mock = jest.fn(); - - expect( - createComponent( - 'id-1', - 'component-1', - {}, - {}, - { - createComponent: () => null, - }, - () => mock - ) - ).toBe(mock); - }); - - test('no valid component', () => { - expect(() => - createComponent('id-1', 'component-1', {}, {}) - ).toThrow( - "Cannot create 'id-1', no component 'component-1' provided" - ); - }); - - test('valid component', () => { - const component = jest.fn(); - - const componentResult = createComponent( - 'id-1', - 'component-1', - { 'component-1': component }, - {} - ); - - expect(component).toHaveBeenCalled(); - - expect(componentResult instanceof component).toBeTruthy(); - }); - }); -}); diff --git a/packages/dockview-core/src/__tests__/paneview/paneview.spec.ts b/packages/dockview-core/src/__tests__/paneview/paneview.spec.ts index b74c81e2b..5bc8720d8 100644 --- a/packages/dockview-core/src/__tests__/paneview/paneview.spec.ts +++ b/packages/dockview-core/src/__tests__/paneview/paneview.spec.ts @@ -1,14 +1,10 @@ import { CompositeDisposable } from '../../lifecycle'; import { Paneview } from '../../paneview/paneview'; -import { - IPaneBodyPart, - IPaneHeaderPart, - PaneviewPanel, -} from '../../paneview/paneviewPanel'; +import { IPanePart, PaneviewPanel } from '../../paneview/paneviewPanel'; import { Orientation } from '../../splitview/splitview'; class TestPanel extends PaneviewPanel { - protected getBodyComponent(): IPaneBodyPart { + protected getBodyComponent(): IPanePart { return { element: document.createElement('div'), update: () => { @@ -23,7 +19,7 @@ class TestPanel extends PaneviewPanel { }; } - protected getHeaderComponent(): IPaneHeaderPart { + protected getHeaderComponent(): IPanePart { return { element: document.createElement('div'), update: () => { diff --git a/packages/dockview-core/src/__tests__/paneview/paneviewComponent.spec.ts b/packages/dockview-core/src/__tests__/paneview/paneviewComponent.spec.ts index 1c5a77da7..1a0575bc0 100644 --- a/packages/dockview-core/src/__tests__/paneview/paneviewComponent.spec.ts +++ b/packages/dockview-core/src/__tests__/paneview/paneviewComponent.spec.ts @@ -4,8 +4,7 @@ import { PanelUpdateEvent } from '../../panel/types'; import { PaneviewComponent } from '../../paneview/paneviewComponent'; import { PaneviewPanel, - IPaneBodyPart, - IPaneHeaderPart, + IPanePart, PanePanelComponentInitParameter, } from '../../paneview/paneviewPanel'; import { Orientation } from '../../splitview/splitview'; @@ -16,7 +15,7 @@ class TestPanel extends PaneviewPanel { } getHeaderComponent() { - return new (class Header implements IPaneHeaderPart { + return new (class Header implements IPanePart { private _element: HTMLElement = document.createElement('div'); get element() { @@ -38,7 +37,7 @@ class TestPanel extends PaneviewPanel { } getBodyComponent() { - return new (class Header implements IPaneBodyPart { + return new (class Header implements IPanePart { private _element: HTMLElement = document.createElement('div'); get element() { @@ -72,8 +71,8 @@ describe('componentPaneview', () => { const disposables = new CompositeDisposable(); const paneview = new PaneviewComponent(container, { - components: { - testPanel: TestPanel, + createComponent: (options) => { + return new TestPanel(options.id, options.name); }, }); @@ -144,8 +143,8 @@ describe('componentPaneview', () => { test('serialization', () => { const paneview = new PaneviewComponent(container, { - components: { - testPanel: TestPanel, + createComponent: (options) => { + return new TestPanel(options.id, options.name); }, }); @@ -252,8 +251,8 @@ describe('componentPaneview', () => { test('toJSON shouldnt fire any layout events', () => { const paneview = new PaneviewComponent(container, { - components: { - testPanel: TestPanel, + createComponent: (options) => { + return new TestPanel(options.id, options.name); }, }); paneview.layout(1000, 1000); @@ -283,8 +282,8 @@ describe('componentPaneview', () => { expect(container.childNodes.length).toBe(0); const paneview = new PaneviewComponent(container, { - components: { - testPanel: TestPanel, + createComponent: (options) => { + return new TestPanel(options.id, options.name); }, }); @@ -310,8 +309,8 @@ describe('componentPaneview', () => { test('panel is disposed of when component is disposed', () => { const paneview = new PaneviewComponent(container, { - components: { - testPanel: TestPanel, + createComponent: (options) => { + return new TestPanel(options.id, options.name); }, }); @@ -342,8 +341,8 @@ describe('componentPaneview', () => { test('panel is disposed of when removed', () => { const paneview = new PaneviewComponent(container, { - components: { - testPanel: TestPanel, + createComponent: (options) => { + return new TestPanel(options.id, options.name); }, }); @@ -374,8 +373,8 @@ describe('componentPaneview', () => { test('panel is disposed of when fromJSON is called', () => { const paneview = new PaneviewComponent(container, { - components: { - testPanel: TestPanel, + createComponent: (options) => { + return new TestPanel(options.id, options.name); }, }); @@ -406,8 +405,8 @@ describe('componentPaneview', () => { test('that fromJSON layouts are resized to the current dimensions', async () => { const paneview = new PaneviewComponent(container, { - components: { - testPanel: TestPanel, + createComponent: (options) => { + return new TestPanel(options.id, options.name); }, }); @@ -486,8 +485,8 @@ describe('componentPaneview', () => { test('that disableAutoResizing is false by default', () => { const paneview = new PaneviewComponent(container, { - components: { - testPanel: TestPanel, + createComponent: (options) => { + return new TestPanel(options.id, options.name); }, }); @@ -496,8 +495,8 @@ describe('componentPaneview', () => { test('that disableAutoResizing can be enabled', () => { const paneview = new PaneviewComponent(container, { - components: { - testPanel: TestPanel, + createComponent: (options) => { + return new TestPanel(options.id, options.name); }, disableAutoResizing: true, }); @@ -507,8 +506,8 @@ describe('componentPaneview', () => { test('that setVisible toggles visiblity', () => { const paneview = new PaneviewComponent(container, { - components: { - default: TestPanel, + createComponent: (options) => { + return new TestPanel(options.id, options.name); }, disableAutoResizing: true, }); @@ -540,8 +539,8 @@ describe('componentPaneview', () => { test('update className', () => { const paneview = new PaneviewComponent(container, { - components: { - default: TestPanel, + createComponent: (options) => { + return new TestPanel(options.id, options.name); }, disableAutoResizing: true, className: 'test-a test-b', diff --git a/packages/dockview-core/src/__tests__/splitview/splitviewComponent.spec.ts b/packages/dockview-core/src/__tests__/splitview/splitviewComponent.spec.ts index 4c7ed46f3..91c54763b 100644 --- a/packages/dockview-core/src/__tests__/splitview/splitviewComponent.spec.ts +++ b/packages/dockview-core/src/__tests__/splitview/splitviewComponent.spec.ts @@ -31,8 +31,8 @@ describe('componentSplitview', () => { const splitview = new SplitviewComponent(container, { orientation: Orientation.VERTICAL, - components: { - testPanel: TestPanel, + createComponent: (options) => { + return new TestPanel(options.id, options.name); }, }); splitview.layout(600, 400); @@ -67,8 +67,8 @@ describe('componentSplitview', () => { test('remove panel', () => { const splitview = new SplitviewComponent(container, { orientation: Orientation.VERTICAL, - components: { - testPanel: TestPanel, + createComponent: (options) => { + return new TestPanel(options.id, options.name); }, }); splitview.layout(600, 400); @@ -102,8 +102,8 @@ describe('componentSplitview', () => { test('horizontal dimensions', () => { const splitview = new SplitviewComponent(container, { orientation: Orientation.HORIZONTAL, - components: { - testPanel: TestPanel, + createComponent: (options) => { + return new TestPanel(options.id, options.name); }, }); splitview.layout(600, 400); @@ -115,8 +115,8 @@ describe('componentSplitview', () => { test('vertical dimensions', () => { const splitview = new SplitviewComponent(container, { orientation: Orientation.VERTICAL, - components: { - testPanel: TestPanel, + createComponent: (options) => { + return new TestPanel(options.id, options.name); }, }); splitview.layout(600, 400); @@ -128,8 +128,8 @@ describe('componentSplitview', () => { test('api resize', () => { const splitview = new SplitviewComponent(container, { orientation: Orientation.VERTICAL, - components: { - testPanel: TestPanel, + createComponent: (options) => { + return new TestPanel(options.id, options.name); }, }); @@ -180,8 +180,8 @@ describe('componentSplitview', () => { test('api', () => { const splitview = new SplitviewComponent(container, { orientation: Orientation.HORIZONTAL, - components: { - testPanel: TestPanel, + createComponent: (options) => { + return new TestPanel(options.id, options.name); }, }); @@ -221,8 +221,8 @@ describe('componentSplitview', () => { const splitview = new SplitviewComponent(container, { orientation: Orientation.VERTICAL, - components: { - testPanel: TestPanel, + createComponent: (options) => { + return new TestPanel(options.id, options.name); }, }); @@ -272,8 +272,8 @@ describe('componentSplitview', () => { const splitview = new SplitviewComponent(container, { orientation: Orientation.HORIZONTAL, - components: { - testPanel: TestPanel, + createComponent: (options) => { + return new TestPanel(options.id, options.name); }, }); @@ -321,8 +321,8 @@ describe('componentSplitview', () => { test('serialization', () => { const splitview = new SplitviewComponent(container, { orientation: Orientation.VERTICAL, - components: { - testPanel: TestPanel, + createComponent: (options) => { + return new TestPanel(options.id, options.name); }, }); splitview.layout(400, 6); @@ -375,8 +375,8 @@ describe('componentSplitview', () => { test('toJSON shouldnt fire any layout events', () => { const splitview = new SplitviewComponent(container, { orientation: Orientation.HORIZONTAL, - components: { - testPanel: TestPanel, + createComponent: (options) => { + return new TestPanel(options.id, options.name); }, }); @@ -406,8 +406,8 @@ describe('componentSplitview', () => { const splitview = new SplitviewComponent(container, { orientation: Orientation.HORIZONTAL, - components: { - testPanel: TestPanel, + createComponent: (options) => { + return new TestPanel(options.id, options.name); }, }); @@ -432,8 +432,8 @@ describe('componentSplitview', () => { test('panel is disposed of when component is disposed', () => { const splitview = new SplitviewComponent(container, { orientation: Orientation.HORIZONTAL, - components: { - default: TestPanel, + createComponent: (options) => { + return new TestPanel(options.id, options.name); }, }); @@ -463,8 +463,8 @@ describe('componentSplitview', () => { test('panel is disposed of when removed', () => { const splitview = new SplitviewComponent(container, { orientation: Orientation.HORIZONTAL, - components: { - default: TestPanel, + createComponent: (options) => { + return new TestPanel(options.id, options.name); }, }); @@ -494,8 +494,8 @@ describe('componentSplitview', () => { test('panel is disposed of when fromJSON is called', () => { const splitview = new SplitviewComponent(container, { orientation: Orientation.HORIZONTAL, - components: { - default: TestPanel, + createComponent: (options) => { + return new TestPanel(options.id, options.name); }, }); @@ -529,8 +529,8 @@ describe('componentSplitview', () => { test('that fromJSON layouts are resized to the current dimensions', async () => { const splitview = new SplitviewComponent(container, { orientation: Orientation.VERTICAL, - components: { - testPanel: TestPanel, + createComponent: (options) => { + return new TestPanel(options.id, options.name); }, }); splitview.layout(400, 600); @@ -581,8 +581,8 @@ describe('componentSplitview', () => { test('that disableAutoResizing is false by default', () => { const splitview = new SplitviewComponent(container, { orientation: Orientation.VERTICAL, - components: { - testPanel: TestPanel, + createComponent: (options) => { + return new TestPanel(options.id, options.name); }, }); @@ -592,8 +592,8 @@ describe('componentSplitview', () => { test('that disableAutoResizing can be enabled', () => { const splitview = new SplitviewComponent(container, { orientation: Orientation.VERTICAL, - components: { - testPanel: TestPanel, + createComponent: (options) => { + return new TestPanel(options.id, options.name); }, disableAutoResizing: true, }); @@ -604,8 +604,8 @@ describe('componentSplitview', () => { test('that setVisible toggles visiblity', () => { const splitview = new SplitviewComponent(container, { orientation: Orientation.HORIZONTAL, - components: { - default: TestPanel, + createComponent: (options) => { + return new TestPanel(options.id, options.name); }, }); @@ -635,8 +635,8 @@ describe('componentSplitview', () => { test('update className', () => { const splitview = new SplitviewComponent(container, { orientation: Orientation.HORIZONTAL, - components: { - default: TestPanel, + createComponent: (options) => { + return new TestPanel(options.id, options.name); }, className: 'test-a test-b', }); diff --git a/packages/dockview-core/src/dockview/options.ts b/packages/dockview-core/src/dockview/options.ts index 3e87923a2..05175190a 100644 --- a/packages/dockview-core/src/dockview/options.ts +++ b/packages/dockview-core/src/dockview/options.ts @@ -96,7 +96,7 @@ export class DockviewUnhandledDragOverEvent implements DockviewDndOverlayEvent { } } -export const PROPERTY_KEYS: (keyof DockviewOptions)[] = (() => { +export const PROPERTY_KEYS_DOCKVIEW: (keyof DockviewOptions)[] = (() => { /** * by readong the keys from an empty value object TypeScript will error * when we add or remove new properties to `DockviewOptions` diff --git a/packages/dockview-core/src/gridview/gridviewComponent.ts b/packages/dockview-core/src/gridview/gridviewComponent.ts index a0ea22288..00084ce44 100644 --- a/packages/dockview-core/src/gridview/gridviewComponent.ts +++ b/packages/dockview-core/src/gridview/gridviewComponent.ts @@ -23,7 +23,6 @@ import { } from './gridviewPanel'; import { BaseComponentOptions, Parameters } from '../panel/types'; import { Orientation, Sizing } from '../splitview/splitview'; -import { createComponent } from '../panel/componentFactory'; import { Emitter, Event } from '../events'; import { Position } from '../dnd/droptarget'; @@ -116,9 +115,11 @@ export class GridviewComponent constructor(parentElement: HTMLElement, options: GridviewComponentOptions) { super(parentElement, { - proportionalLayout: options.proportionalLayout, + proportionalLayout: options.proportionalLayout ?? true, orientation: options.orientation, - styles: options.styles, + styles: options.hideBorders + ? { separatorBorder: 'transparent' } + : undefined, disableAutoResizing: options.disableAutoResizing, className: options.className, }); @@ -139,13 +140,6 @@ export class GridviewComponent this._onDidActiveGroupChange.fire(event); }) ); - - if (!this.options.components) { - this.options.components = {}; - } - if (!this.options.frameworkComponents) { - this.options.frameworkComponents = {}; - } } override updateOptions(options: Partial): void { @@ -216,19 +210,11 @@ export class GridviewComponent this.gridview.deserialize(grid, { fromJSON: (node) => { const { data } = node; - const view = createComponent( - data.id, - data.component, - this.options.components ?? {}, - this.options.frameworkComponents ?? {}, - this.options.frameworkComponentFactory - ? { - createComponent: - this.options.frameworkComponentFactory - .createComponent, - } - : undefined - ); + + const view = this.options.createComponent({ + id: data.id, + name: data.component, + }); queue.push(() => view.init({ @@ -363,19 +349,10 @@ export class GridviewComponent } } - const view = createComponent( - options.id, - options.component, - this.options.components ?? {}, - this.options.frameworkComponents ?? {}, - this.options.frameworkComponentFactory - ? { - createComponent: - this.options.frameworkComponentFactory - .createComponent, - } - : undefined - ); + const view = this.options.createComponent({ + id: options.id, + name: options.component, + }); view.init({ params: options.params ?? {}, diff --git a/packages/dockview-core/src/gridview/options.ts b/packages/dockview-core/src/gridview/options.ts index 8a5025846..ba96378bc 100644 --- a/packages/dockview-core/src/gridview/options.ts +++ b/packages/dockview-core/src/gridview/options.ts @@ -1,21 +1,34 @@ import { GridviewPanel } from './gridviewPanel'; -import { ISplitviewStyles, Orientation } from '../splitview/splitview'; -import { - ComponentConstructor, - FrameworkFactory, -} from '../panel/componentFactory'; +import { Orientation } from '../splitview/splitview'; +import { CreateComponentOptions } from '../dockview/options'; -export interface GridviewComponentOptions { +export interface GridviewOptions { disableAutoResizing?: boolean; - proportionalLayout: boolean; + proportionalLayout?: boolean; orientation: Orientation; - components?: { - [componentName: string]: ComponentConstructor; - }; - frameworkComponents?: { - [componentName: string]: any; - }; - frameworkComponentFactory?: FrameworkFactory; - styles?: ISplitviewStyles; className?: string; + hideBorders?: boolean; +} + +export interface GridviewFrameworkOptions { + createComponent: (options: CreateComponentOptions) => GridviewPanel; } + +export type GridviewComponentOptions = GridviewOptions & + GridviewFrameworkOptions; + +export const PROPERTY_KEYS_GRIDVIEW: (keyof GridviewOptions)[] = (() => { + /** + * by readong the keys from an empty value object TypeScript will error + * when we add or remove new properties to `DockviewOptions` + */ + const properties: Record = { + disableAutoResizing: undefined, + proportionalLayout: undefined, + orientation: undefined, + hideBorders: undefined, + className: undefined, + }; + + return Object.keys(properties) as (keyof GridviewOptions)[]; +})(); diff --git a/packages/dockview-core/src/index.ts b/packages/dockview-core/src/index.ts index 59d4a19e6..dfaec589f 100644 --- a/packages/dockview-core/src/index.ts +++ b/packages/dockview-core/src/index.ts @@ -24,11 +24,19 @@ export * from './splitview/splitview'; export { SplitviewComponentOptions, PanelViewInitParameters, + SplitviewOptions, + SplitviewFrameworkOptions, + PROPERTY_KEYS_SPLITVIEW, } from './splitview/options'; export * from './paneview/paneview'; export * from './gridview/gridview'; -export { GridviewComponentOptions } from './gridview/options'; +export { + GridviewComponentOptions, + GridviewOptions, + GridviewFrameworkOptions, + PROPERTY_KEYS_GRIDVIEW, +} from './gridview/options'; export * from './gridview/baseComponentGridview'; export { @@ -67,7 +75,12 @@ export * from './dockview/dockviewComponent'; export * from './gridview/gridviewComponent'; export * from './splitview/splitviewComponent'; export * from './paneview/paneviewComponent'; -export { PaneviewComponentOptions } from './paneview/options'; +export { + PaneviewComponentOptions, + PaneviewOptions, + PaneviewFrameworkOptions, + PROPERTY_KEYS_PANEVIEW, +} from './paneview/options'; export * from './gridview/gridviewPanel'; export { SplitviewPanel, ISplitviewPanel } from './splitview/splitviewPanel'; diff --git a/packages/dockview-core/src/panel/componentFactory.ts b/packages/dockview-core/src/panel/componentFactory.ts deleted file mode 100644 index fb77f9944..000000000 --- a/packages/dockview-core/src/panel/componentFactory.ts +++ /dev/null @@ -1,58 +0,0 @@ -export interface FrameworkFactory { - createComponent: (id: string, componentId: string, component: any) => T; -} - -export type ComponentConstructor = { - new (id: string, component: string): T; -}; - -export function createComponent( - id: string, - componentName?: string, - components: { - [componentName: string]: ComponentConstructor; - } = {}, - frameworkComponents: { - [componentName: string]: any; - } = {}, - createFrameworkComponent?: FrameworkFactory, - fallback?: () => T -): T { - const Component = - typeof componentName === 'string' - ? components[componentName] - : undefined; - const FrameworkComponent = - typeof componentName === 'string' - ? frameworkComponents[componentName] - : undefined; - - if (Component && FrameworkComponent) { - throw new Error( - `Cannot create '${id}'. component '${componentName}' registered as both a component and frameworkComponent` - ); - } - if (FrameworkComponent) { - if (!createFrameworkComponent) { - throw new Error( - `Cannot create '${id}' for framework component '${componentName}'. you must register a frameworkPanelWrapper to use framework components` - ); - } - return createFrameworkComponent.createComponent( - id, - componentName!, - FrameworkComponent - ); - } - - if (!Component) { - if (fallback) { - return fallback(); - } - throw new Error( - `Cannot create '${id}', no component '${componentName}' provided` - ); - } - - return new Component(id, componentName!); -} diff --git a/packages/dockview-core/src/paneview/defaultPaneviewHeader.ts b/packages/dockview-core/src/paneview/defaultPaneviewHeader.ts index ee37cc597..c53121154 100644 --- a/packages/dockview-core/src/paneview/defaultPaneviewHeader.ts +++ b/packages/dockview-core/src/paneview/defaultPaneviewHeader.ts @@ -2,14 +2,11 @@ import { addDisposableListener } from '../events'; import { PaneviewPanelApiImpl } from '../api/paneviewPanelApi'; import { CompositeDisposable, MutableDisposable } from '../lifecycle'; import { PanelUpdateEvent } from '../panel/types'; -import { IPaneHeaderPart, PanePanelInitParameter } from './paneviewPanel'; +import { IPanePart, PanePanelInitParameter } from './paneviewPanel'; import { toggleClass } from '../dom'; import { createChevronRightButton, createExpandMoreButton } from '../svg'; -export class DefaultHeader - extends CompositeDisposable - implements IPaneHeaderPart -{ +export class DefaultHeader extends CompositeDisposable implements IPanePart { private readonly _expandedIcon = createExpandMoreButton(); private readonly _collapsedIcon = createChevronRightButton(); private readonly disposable = new MutableDisposable(); diff --git a/packages/dockview-core/src/paneview/options.ts b/packages/dockview-core/src/paneview/options.ts index 8aef3e649..f7702638a 100644 --- a/packages/dockview-core/src/paneview/options.ts +++ b/packages/dockview-core/src/paneview/options.ts @@ -1,29 +1,35 @@ -import { - ComponentConstructor, - FrameworkFactory, -} from '../panel/componentFactory'; +import { CreateComponentOptions } from '../dockview/options'; import { PaneviewDndOverlayEvent } from './paneviewComponent'; -import { IPaneBodyPart, IPaneHeaderPart, PaneviewPanel } from './paneviewPanel'; +import { IPanePart } from './paneviewPanel'; -export interface PaneviewComponentOptions { +export interface PaneviewOptions { disableAutoResizing?: boolean; - components?: { - [componentName: string]: ComponentConstructor; - }; - frameworkComponents?: { - [componentName: string]: any; - }; - headerComponents?: { - [componentName: string]: ComponentConstructor; - }; - headerframeworkComponents?: { - [componentName: string]: any; - }; - frameworkWrapper?: { - header: FrameworkFactory; - body: FrameworkFactory; - }; disableDnd?: boolean; showDndOverlay?: (event: PaneviewDndOverlayEvent) => boolean; className?: string; } + +export interface PaneviewFrameworkOptions { + createComponent: (options: CreateComponentOptions) => IPanePart; + createHeaderComponent?: ( + options: CreateComponentOptions + ) => IPanePart | undefined; +} + +export type PaneviewComponentOptions = PaneviewOptions & + PaneviewFrameworkOptions; + +export const PROPERTY_KEYS_PANEVIEW: (keyof PaneviewOptions)[] = (() => { + /** + * by readong the keys from an empty value object TypeScript will error + * when we add or remove new properties to `DockviewOptions` + */ + const properties: Record = { + disableAutoResizing: undefined, + disableDnd: undefined, + showDndOverlay: undefined, + className: undefined, + }; + + return Object.keys(properties) as (keyof PaneviewOptions)[]; +})(); diff --git a/packages/dockview-core/src/paneview/paneviewComponent.ts b/packages/dockview-core/src/paneview/paneviewComponent.ts index 171f4a703..651f5f406 100644 --- a/packages/dockview-core/src/paneview/paneviewComponent.ts +++ b/packages/dockview-core/src/paneview/paneviewComponent.ts @@ -1,5 +1,4 @@ import { PaneviewApi } from '../api/component.api'; -import { createComponent } from '../panel/componentFactory'; import { Emitter, Event } from '../events'; import { CompositeDisposable, @@ -9,12 +8,7 @@ import { import { LayoutPriority, Orientation, Sizing } from '../splitview/splitview'; import { PaneviewComponentOptions } from './options'; import { Paneview } from './paneview'; -import { - IPaneBodyPart, - IPaneHeaderPart, - PaneviewPanel, - IPaneviewPanel, -} from './paneviewPanel'; +import { IPanePart, PaneviewPanel, IPaneviewPanel } from './paneviewPanel'; import { DraggablePaneviewPanel, PaneviewDropEvent, @@ -61,8 +55,8 @@ export class PaneFramework extends DraggablePaneviewPanel { id: string; component: string; headerComponent: string | undefined; - body: IPaneBodyPart; - header: IPaneHeaderPart; + body: IPanePart; + header: IPanePart; orientation: Orientation; isExpanded: boolean; disableDnd: boolean; @@ -218,13 +212,6 @@ export class PaneviewComponent extends Resizable implements IPaneviewComponent { this._options = options; - if (!options.components) { - options.components = {}; - } - if (!options.frameworkComponents) { - options.frameworkComponents = {}; - } - this.paneview = new Paneview(this.element, { // only allow paneview in the vertical orientation for now orientation: Orientation.VERTICAL, @@ -257,36 +244,21 @@ export class PaneviewComponent extends Resizable implements IPaneviewComponent { addPanel( options: AddPaneviewComponentOptions ): IPaneviewPanel { - const body = createComponent( - options.id, - options.component, - this.options.components ?? {}, - this.options.frameworkComponents ?? {}, - this.options.frameworkWrapper - ? { - createComponent: - this.options.frameworkWrapper.body.createComponent, - } - : undefined - ); + const body = this.options.createComponent({ + id: options.id, + name: options.component, + }); + + let header: IPanePart | undefined; - let header: IPaneHeaderPart; - - if (options.headerComponent) { - header = createComponent( - options.id, - options.headerComponent, - this.options.headerComponents ?? {}, - this.options.headerframeworkComponents, - this.options.frameworkWrapper - ? { - createComponent: - this.options.frameworkWrapper.header - .createComponent, - } - : undefined - ); - } else { + if (options.headerComponent && this.options.createHeaderComponent) { + header = this.options.createHeaderComponent({ + id: options.id, + name: options.headerComponent, + }); + } + + if (!header) { header = new DefaultHeader(); } @@ -395,37 +367,24 @@ export class PaneviewComponent extends Resizable implements IPaneviewComponent { views: views.map((view) => { const data = view.data; - const body = createComponent( - data.id, - data.component, - this.options.components ?? {}, - this.options.frameworkComponents ?? {}, - this.options.frameworkWrapper - ? { - createComponent: - this.options.frameworkWrapper.body - .createComponent, - } - : undefined - ); - - let header: IPaneHeaderPart; - - if (data.headerComponent) { - header = createComponent( - data.id, - data.headerComponent, - this.options.headerComponents ?? {}, - this.options.headerframeworkComponents ?? {}, - this.options.frameworkWrapper - ? { - createComponent: - this.options.frameworkWrapper.header - .createComponent, - } - : undefined - ); - } else { + const body = this.options.createComponent({ + id: data.id, + name: data.component, + }); + + let header: IPanePart | undefined; + + if ( + data.headerComponent && + this.options.createHeaderComponent + ) { + header = this.options.createHeaderComponent({ + id: data.id, + name: data.headerComponent, + }); + } + + if (!header) { header = new DefaultHeader(); } diff --git a/packages/dockview-core/src/paneview/paneviewPanel.ts b/packages/dockview-core/src/paneview/paneviewPanel.ts index 38b4586f6..02710da90 100644 --- a/packages/dockview-core/src/paneview/paneviewPanel.ts +++ b/packages/dockview-core/src/paneview/paneviewPanel.ts @@ -36,13 +36,7 @@ export interface PanePanelComponentInitParameter api: PaneviewPanelApiImpl; } -export interface IPaneBodyPart extends IDisposable { - readonly element: HTMLElement; - update(params: PanelUpdateEvent): void; - init(parameters: PanePanelComponentInitParameter): void; -} - -export interface IPaneHeaderPart extends IDisposable { +export interface IPanePart extends IDisposable { readonly element: HTMLElement; update(params: PanelUpdateEvent): void; init(parameters: PanePanelComponentInitParameter): void; @@ -85,8 +79,8 @@ export abstract class PaneviewPanel private _isExpanded = false; protected header?: HTMLElement; protected body?: HTMLElement; - private bodyPart?: IPaneHeaderPart; - private headerPart?: IPaneBodyPart; + private bodyPart?: IPanePart; + private headerPart?: IPanePart; private expandedSize = 0; private animationTimer: any; private _orientation: Orientation; @@ -338,6 +332,6 @@ export abstract class PaneviewPanel }; } - protected abstract getBodyComponent(): IPaneBodyPart; - protected abstract getHeaderComponent(): IPaneHeaderPart; + protected abstract getBodyComponent(): IPanePart; + protected abstract getHeaderComponent(): IPanePart; } diff --git a/packages/dockview-core/src/splitview/options.ts b/packages/dockview-core/src/splitview/options.ts index 01c32a040..05955f279 100644 --- a/packages/dockview-core/src/splitview/options.ts +++ b/packages/dockview-core/src/splitview/options.ts @@ -2,10 +2,7 @@ import { PanelInitParameters } from '../panel/types'; import { SplitViewOptions, LayoutPriority } from './splitview'; import { SplitviewPanel } from './splitviewPanel'; import { SplitviewComponent } from './splitviewComponent'; -import { - ComponentConstructor, - FrameworkFactory, -} from '../panel/componentFactory'; +import { CreateComponentOptions } from '../dockview/options'; export interface PanelViewInitParameters extends PanelInitParameters { minimumSize?: number; @@ -15,14 +12,32 @@ export interface PanelViewInitParameters extends PanelInitParameters { accessor: SplitviewComponent; } -export interface SplitviewComponentOptions extends SplitViewOptions { +export interface SplitviewOptions extends SplitViewOptions { disableAutoResizing?: boolean; - components?: { - [componentName: string]: ComponentConstructor; - }; - frameworkComponents?: { - [componentName: string]: any; - }; - frameworkWrapper?: FrameworkFactory; className?: string; } + +export interface SplitviewFrameworkOptions { + createComponent: (options: CreateComponentOptions) => SplitviewPanel; +} + +export type SplitviewComponentOptions = SplitviewOptions & + SplitviewFrameworkOptions; + +export const PROPERTY_KEYS_SPLITVIEW: (keyof SplitviewOptions)[] = (() => { + /** + * by readong the keys from an empty value object TypeScript will error + * when we add or remove new properties to `DockviewOptions` + */ + const properties: Record = { + orientation: undefined, + descriptor: undefined, + proportionalLayout: undefined, + styles: undefined, + margin: undefined, + disableAutoResizing: undefined, + className: undefined, + }; + + return Object.keys(properties) as (keyof SplitviewOptions)[]; +})(); diff --git a/packages/dockview-core/src/splitview/splitview.ts b/packages/dockview-core/src/splitview/splitview.ts index c4ceeb3d0..fc5857d08 100644 --- a/packages/dockview-core/src/splitview/splitview.ts +++ b/packages/dockview-core/src/splitview/splitview.ts @@ -32,11 +32,11 @@ export interface ISplitviewStyles { } export interface SplitViewOptions { - readonly orientation: Orientation; - readonly descriptor?: ISplitViewDescriptor; - readonly proportionalLayout?: boolean; - readonly styles?: ISplitviewStyles; - readonly margin?: number; + orientation: Orientation; + descriptor?: ISplitViewDescriptor; + proportionalLayout?: boolean; + styles?: ISplitviewStyles; + margin?: number; } export enum LayoutPriority { diff --git a/packages/dockview-core/src/splitview/splitviewComponent.ts b/packages/dockview-core/src/splitview/splitviewComponent.ts index ab8bb6cf5..5e988c422 100644 --- a/packages/dockview-core/src/splitview/splitviewComponent.ts +++ b/packages/dockview-core/src/splitview/splitviewComponent.ts @@ -15,7 +15,6 @@ import { SplitviewComponentOptions } from './options'; import { BaseComponentOptions, Parameters } from '../panel/types'; import { Emitter, Event } from '../events'; import { SplitviewPanel, ISplitviewPanel } from './splitviewPanel'; -import { createComponent } from '../panel/componentFactory'; import { Resizable } from '../resizable'; import { Classnames } from '../dom'; @@ -167,13 +166,6 @@ export class SplitviewComponent this._options = options; - if (!options.components) { - options.components = {}; - } - if (!options.frameworkComponents) { - options.frameworkComponents = {}; - } - this.splitview = new Splitview(this.element, options); this.addDisposables( @@ -267,18 +259,10 @@ export class SplitviewComponent throw new Error(`panel ${options.id} already exists`); } - const view = createComponent( - options.id, - options.component, - this.options.components ?? {}, - this.options.frameworkComponents ?? {}, - this.options.frameworkWrapper - ? { - createComponent: - this.options.frameworkWrapper.createComponent, - } - : undefined - ); + const view = this.options.createComponent({ + id: options.id, + name: options.component, + }); view.orientation = this.splitview.orientation; @@ -367,19 +351,10 @@ export class SplitviewComponent throw new Error(`panel ${data.id} already exists`); } - const panel = createComponent( - data.id, - data.component, - this.options.components ?? {}, - this.options.frameworkComponents ?? {}, - this.options.frameworkWrapper - ? { - createComponent: - this.options.frameworkWrapper - .createComponent, - } - : undefined - ); + const panel = this.options.createComponent({ + id: data.id, + name: data.component, + }); queue.push(() => { panel.init({ diff --git a/packages/dockview-vue/src/dockview/dockview.vue b/packages/dockview-vue/src/dockview/dockview.vue index 6442ad5eb..35508d49a 100644 --- a/packages/dockview-vue/src/dockview/dockview.vue +++ b/packages/dockview-vue/src/dockview/dockview.vue @@ -2,7 +2,7 @@ import { DockviewApi, type DockviewOptions, - PROPERTY_KEYS, + PROPERTY_KEYS_DOCKVIEW, type DockviewFrameworkOptions, createDockview, } from 'dockview-core'; @@ -25,7 +25,7 @@ import { import type { IDockviewVueProps, VueEvents } from './types'; function extractCoreOptions(props: IDockviewVueProps): DockviewOptions { - const coreOptions = (PROPERTY_KEYS as (keyof DockviewOptions)[]).reduce( + const coreOptions = (PROPERTY_KEYS_DOCKVIEW as (keyof DockviewOptions)[]).reduce( (obj, key) => { (obj as any)[key] = props[key]; return obj; @@ -43,7 +43,7 @@ const props = defineProps(); const el = ref(null); const instance = ref(null); -PROPERTY_KEYS.forEach((coreOptionKey) => { +PROPERTY_KEYS_DOCKVIEW.forEach((coreOptionKey) => { watch( () => props[coreOptionKey], (newValue, oldValue) => { diff --git a/packages/dockview/src/dockview/dockview.tsx b/packages/dockview/src/dockview/dockview.tsx index 550c632b9..fefc605f1 100644 --- a/packages/dockview/src/dockview/dockview.tsx +++ b/packages/dockview/src/dockview/dockview.tsx @@ -10,7 +10,7 @@ import { IDockviewPanelHeaderProps, IDockviewPanelProps, DockviewOptions, - PROPERTY_KEYS, + PROPERTY_KEYS_DOCKVIEW, DockviewComponentOptions, DockviewFrameworkOptions, DockviewReadyEvent, @@ -40,7 +40,6 @@ function createGroupControlElement( const DEFAULT_REACT_TAB = 'props.defaultTabComponent'; export interface IDockviewReactProps extends DockviewOptions { - className?: string; tabComponents?: Record< string, React.FunctionComponent @@ -58,7 +57,7 @@ export interface IDockviewReactProps extends DockviewOptions { } function extractCoreOptions(props: IDockviewReactProps): DockviewOptions { - const coreOptions = PROPERTY_KEYS.reduce((obj, key) => { + const coreOptions = PROPERTY_KEYS_DOCKVIEW.reduce((obj, key) => { if (key in props) { obj[key] = props[key] as any; } @@ -82,7 +81,7 @@ export const DockviewReact = React.forwardRef( () => { const changes: Partial = {}; - PROPERTY_KEYS.forEach((propKey) => { + PROPERTY_KEYS_DOCKVIEW.forEach((propKey) => { const key = propKey; const propValue = props[key]; @@ -99,7 +98,7 @@ export const DockviewReact = React.forwardRef( prevProps.current = props; }, - PROPERTY_KEYS.map((key) => props[key]) + PROPERTY_KEYS_DOCKVIEW.map((key) => props[key]) ); React.useEffect(() => { diff --git a/packages/dockview/src/gridview/gridview.tsx b/packages/dockview/src/gridview/gridview.tsx index c63307593..60b172651 100644 --- a/packages/dockview/src/gridview/gridview.tsx +++ b/packages/dockview/src/gridview/gridview.tsx @@ -1,13 +1,17 @@ import React from 'react'; import { GridviewPanelApi, - Orientation, GridviewApi, createGridview, + GridviewOptions, + PROPERTY_KEYS_GRIDVIEW, + GridviewComponentOptions, + GridviewFrameworkOptions, } from 'dockview-core'; import { ReactGridPanelView } from './view'; import { usePortalsLifecycle } from '../react'; import { PanelParameters } from '../types'; + export interface GridviewReadyEvent { api: GridviewApi; } @@ -18,14 +22,20 @@ export interface IGridviewPanelProps containerApi: GridviewApi; } -export interface IGridviewReactProps { - orientation?: Orientation; +export interface IGridviewReactProps extends GridviewOptions { onReady: (event: GridviewReadyEvent) => void; components: Record>; - hideBorders?: boolean; - className?: string; - proportionalLayout?: boolean; - disableAutoResizing?: boolean; +} + +function extractCoreOptions(props: IGridviewReactProps): GridviewOptions { + const coreOptions = PROPERTY_KEYS_GRIDVIEW.reduce((obj, key) => { + if (key in props) { + obj[key] = props[key] as any; + } + return obj; + }, {} as Partial); + + return coreOptions as GridviewOptions; } export const GridviewReact = React.forwardRef( @@ -36,6 +46,32 @@ export const GridviewReact = React.forwardRef( React.useImperativeHandle(ref, () => domRef.current!, []); + const prevProps = React.useRef>({}); + + React.useEffect( + () => { + const changes: Partial = {}; + + PROPERTY_KEYS_GRIDVIEW.forEach((propKey) => { + const key = propKey; + const propValue = props[key]; + + if (key in props && propValue !== prevProps.current[key]) { + changes[key] = propValue as any; + } + }); + + if (gridviewRef.current) { + gridviewRef.current.updateOptions(changes); + } else { + // not yet fully initialized + } + + prevProps.current = props; + }, + PROPERTY_KEYS_GRIDVIEW.map((key) => props[key]) + ); + React.useEffect(() => { if (!domRef.current) { return () => { @@ -43,29 +79,20 @@ export const GridviewReact = React.forwardRef( }; } - const api = createGridview(domRef.current, { - disableAutoResizing: props.disableAutoResizing, - proportionalLayout: - typeof props.proportionalLayout === 'boolean' - ? props.proportionalLayout - : true, - orientation: props.orientation ?? Orientation.HORIZONTAL, - frameworkComponents: props.components, - frameworkComponentFactory: { - createComponent: (id: string, componentId, component) => { - return new ReactGridPanelView( - id, - componentId, - component, - { - addPortal, - } - ); - }, + const frameworkOptions: GridviewFrameworkOptions = { + createComponent: (options) => { + return new ReactGridPanelView( + options.id, + options.name, + props.components[options.name], + { addPortal } + ); }, - styles: props.hideBorders - ? { separatorBorder: 'transparent' } - : undefined, + }; + + const api = createGridview(domRef.current, { + ...extractCoreOptions(props), + ...frameworkOptions, }); const { clientWidth, clientHeight } = domRef.current; @@ -87,7 +114,14 @@ export const GridviewReact = React.forwardRef( return; } gridviewRef.current.updateOptions({ - frameworkComponents: props.components, + createComponent: (options) => { + return new ReactGridPanelView( + options.id, + options.name, + props.components[options.name], + { addPortal } + ); + }, }); }, [props.components]); diff --git a/packages/dockview/src/paneview/paneview.tsx b/packages/dockview/src/paneview/paneview.tsx index b5db59540..2dc623638 100644 --- a/packages/dockview/src/paneview/paneview.tsx +++ b/packages/dockview/src/paneview/paneview.tsx @@ -5,6 +5,10 @@ import { PaneviewApi, PaneviewDropEvent, createPaneview, + PaneviewOptions, + PROPERTY_KEYS_PANEVIEW, + PaneviewComponentOptions, + PaneviewFrameworkOptions, } from 'dockview-core'; import { usePortalsLifecycle } from '../react'; import { PanePanelSection } from './view'; @@ -21,20 +25,28 @@ export interface IPaneviewPanelProps title: string; } -export interface IPaneviewReactProps { +export interface IPaneviewReactProps extends PaneviewOptions { onReady: (event: PaneviewReadyEvent) => void; components: Record>; headerComponents?: Record< string, React.FunctionComponent >; - className?: string; - disableAutoResizing?: boolean; - disableDnd?: boolean; showDndOverlay?: (event: PaneviewDndOverlayEvent) => boolean; onDidDrop?(event: PaneviewDropEvent): void; } +function extractCoreOptions(props: IPaneviewReactProps): PaneviewOptions { + const coreOptions = PROPERTY_KEYS_PANEVIEW.reduce((obj, key) => { + if (key in props) { + obj[key] = props[key] as any; + } + return obj; + }, {} as Partial); + + return coreOptions as PaneviewOptions; +} + export const PaneviewReact = React.forwardRef( (props: IPaneviewReactProps, ref: React.ForwardedRef) => { const domRef = React.useRef(null); @@ -43,35 +55,64 @@ export const PaneviewReact = React.forwardRef( React.useImperativeHandle(ref, () => domRef.current!, []); - React.useEffect(() => { - const createComponent = ( - id: string, - _componentId: string, - component: any - ) => - new PanePanelSection(id, component, { - addPortal, + const prevProps = React.useRef>({}); + + React.useEffect( + () => { + const changes: Partial = {}; + + PROPERTY_KEYS_PANEVIEW.forEach((propKey) => { + const key = propKey; + const propValue = props[key]; + + if (key in props && propValue !== prevProps.current[key]) { + changes[key] = propValue as any; + } }); - const api = createPaneview(domRef.current!, { - disableAutoResizing: props.disableAutoResizing, - frameworkComponents: props.components, - components: {}, - headerComponents: {}, - disableDnd: props.disableDnd, - headerframeworkComponents: props.headerComponents, - frameworkWrapper: { - header: { - createComponent, - }, - body: { - createComponent, - }, + if (paneviewRef.current) { + paneviewRef.current.updateOptions(changes); + } else { + // not yet fully initialized + } + + prevProps.current = props; + }, + PROPERTY_KEYS_PANEVIEW.map((key) => props[key]) + ); + + React.useEffect(() => { + if (!domRef.current) { + return () => { + // noop + }; + } + + const headerComponents = props.headerComponents ?? {}; + + const frameworkOptions: PaneviewFrameworkOptions = { + createComponent: (options) => { + return new PanePanelSection( + options.id, + props.components[options.name], + { addPortal } + ); }, - showDndOverlay: props.showDndOverlay, + createHeaderComponent: (options) => { + return new PanePanelSection( + options.id, + headerComponents[options.name], + { addPortal } + ); + }, + }; + + const api = createPaneview(domRef.current, { + ...extractCoreOptions(props), + ...frameworkOptions, }); - const { clientWidth, clientHeight } = domRef.current!; + const { clientWidth, clientHeight } = domRef.current; api.layout(clientWidth, clientHeight); if (props.onReady) { @@ -90,7 +131,13 @@ export const PaneviewReact = React.forwardRef( return; } paneviewRef.current.updateOptions({ - frameworkComponents: props.components, + createComponent: (options) => { + return new PanePanelSection( + options.id, + props.components[options.name], + { addPortal } + ); + }, }); }, [props.components]); @@ -98,26 +145,30 @@ export const PaneviewReact = React.forwardRef( if (!paneviewRef.current) { return; } + + const headerComponents = props.headerComponents ?? {}; + paneviewRef.current.updateOptions({ - headerframeworkComponents: props.headerComponents, + createHeaderComponent: (options) => { + return new PanePanelSection( + options.id, + headerComponents[options.name], + { addPortal } + ); + }, }); }, [props.headerComponents]); React.useEffect(() => { if (!paneviewRef.current) { return () => { - // + // noop }; } - const api = paneviewRef.current; - - const disposable = api.onDidDrop((event) => { + const disposable = paneviewRef.current.onDidDrop((event) => { if (props.onDidDrop) { - props.onDidDrop({ - ...event, - api, - }); + props.onDidDrop(event); } }); diff --git a/packages/dockview/src/paneview/view.ts b/packages/dockview/src/paneview/view.ts index 3d3a5d8f6..6840e49d4 100644 --- a/packages/dockview/src/paneview/view.ts +++ b/packages/dockview/src/paneview/view.ts @@ -1,13 +1,13 @@ import React from 'react'; import { PanelUpdateEvent, - IPaneBodyPart, + IPanePart, PanePanelComponentInitParameter, } from 'dockview-core'; import { ReactPart, ReactPortalStore } from '../react'; import { IPaneviewPanelProps } from './paneview'; -export class PanePanelSection implements IPaneBodyPart { +export class PanePanelSection implements IPanePart { private readonly _element: HTMLElement; private part?: ReactPart; diff --git a/packages/dockview/src/splitview/splitview.tsx b/packages/dockview/src/splitview/splitview.tsx index 6c516ce8c..63d2cf5d9 100644 --- a/packages/dockview/src/splitview/splitview.tsx +++ b/packages/dockview/src/splitview/splitview.tsx @@ -2,8 +2,11 @@ import React from 'react'; import { SplitviewApi, SplitviewPanelApi, - Orientation, createSplitview, + SplitviewOptions, + PROPERTY_KEYS_SPLITVIEW, + SplitviewFrameworkOptions, + SplitviewComponentOptions, } from 'dockview-core'; import { usePortalsLifecycle } from '../react'; import { PanelParameters } from '../types'; @@ -19,14 +22,20 @@ export interface ISplitviewPanelProps containerApi: SplitviewApi; } -export interface ISplitviewReactProps { - orientation?: Orientation; +export interface ISplitviewReactProps extends SplitviewOptions { onReady: (event: SplitviewReadyEvent) => void; components: Record>; - proportionalLayout?: boolean; - hideBorders?: boolean; - className?: string; - disableAutoResizing?: boolean; +} + +function extractCoreOptions(props: ISplitviewReactProps): SplitviewOptions { + const coreOptions = PROPERTY_KEYS_SPLITVIEW.reduce((obj, key) => { + if (key in props) { + obj[key] = props[key] as any; + } + return obj; + }, {} as Partial); + + return coreOptions as SplitviewOptions; } export const SplitviewReact = React.forwardRef( @@ -37,32 +46,56 @@ export const SplitviewReact = React.forwardRef( React.useImperativeHandle(ref, () => domRef.current!, []); + const prevProps = React.useRef>({}); + + React.useEffect( + () => { + const changes: Partial = {}; + + PROPERTY_KEYS_SPLITVIEW.forEach((propKey) => { + const key = propKey; + const propValue = props[key]; + + if (key in props && propValue !== prevProps.current[key]) { + changes[key] = propValue as any; + } + }); + + if (splitviewRef.current) { + splitviewRef.current.updateOptions(changes); + } else { + // not yet fully initialized + } + + prevProps.current = props; + }, + PROPERTY_KEYS_SPLITVIEW.map((key) => props[key]) + ); + React.useEffect(() => { - const api = createSplitview(domRef.current!, { - disableAutoResizing: props.disableAutoResizing, - orientation: props.orientation ?? Orientation.HORIZONTAL, - frameworkComponents: props.components, - frameworkWrapper: { - createComponent: ( - id: string, - componentId, - component: any - ) => { - return new ReactPanelView(id, componentId, component, { - addPortal, - }); - }, + if (!domRef.current) { + return () => { + // noop + }; + } + + const frameworkOptions: SplitviewFrameworkOptions = { + createComponent: (options) => { + return new ReactPanelView( + options.id, + options.name, + props.components[options.name], + { addPortal } + ); }, - proportionalLayout: - typeof props.proportionalLayout === 'boolean' - ? props.proportionalLayout - : true, - styles: props.hideBorders - ? { separatorBorder: 'transparent' } - : undefined, + }; + + const api = createSplitview(domRef.current, { + ...extractCoreOptions(props), + ...frameworkOptions, }); - const { clientWidth, clientHeight } = domRef.current!; + const { clientWidth, clientHeight } = domRef.current; api.layout(clientWidth, clientHeight); if (props.onReady) { @@ -81,7 +114,14 @@ export const SplitviewReact = React.forwardRef( return; } splitviewRef.current.updateOptions({ - frameworkComponents: props.components, + createComponent: (options) => { + return new ReactPanelView( + options.id, + options.name, + props.components[options.name], + { addPortal } + ); + }, }); }, [props.components]);