dockview-react 6.6.0 → 7.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (85) hide show
  1. package/dist/cjs/dockview/defaultTab.d.ts +7 -0
  2. package/dist/cjs/dockview/defaultTab.js +99 -0
  3. package/dist/cjs/dockview/dockview.d.ts +33 -0
  4. package/dist/cjs/dockview/dockview.js +285 -0
  5. package/dist/cjs/dockview/headerActionsRenderer.d.ts +24 -0
  6. package/dist/cjs/dockview/headerActionsRenderer.js +86 -0
  7. package/dist/cjs/dockview/reactContentPart.d.ts +21 -0
  8. package/dist/cjs/dockview/reactContentPart.js +52 -0
  9. package/dist/cjs/dockview/reactContextMenuItemPart.d.ts +14 -0
  10. package/dist/cjs/dockview/reactContextMenuItemPart.js +31 -0
  11. package/dist/cjs/dockview/reactGroupDragGhostPart.d.ts +20 -0
  12. package/dist/cjs/dockview/reactGroupDragGhostPart.js +32 -0
  13. package/dist/cjs/dockview/reactHeaderPart.d.ts +17 -0
  14. package/dist/cjs/dockview/reactHeaderPart.js +46 -0
  15. package/dist/cjs/dockview/reactTabGroupChipPart.d.ts +23 -0
  16. package/dist/cjs/dockview/reactTabGroupChipPart.js +36 -0
  17. package/dist/cjs/dockview/reactWatermarkPart.d.ts +18 -0
  18. package/dist/cjs/dockview/reactWatermarkPart.js +47 -0
  19. package/dist/cjs/gridview/gridview.d.ts +17 -0
  20. package/dist/cjs/gridview/gridview.js +105 -0
  21. package/dist/cjs/gridview/view.d.ts +9 -0
  22. package/dist/cjs/gridview/view.js +41 -0
  23. package/dist/cjs/index.d.ts +9 -0
  24. package/dist/cjs/index.js +7 -0
  25. package/dist/cjs/paneview/paneview.d.ts +20 -0
  26. package/dist/cjs/paneview/paneview.js +137 -0
  27. package/dist/cjs/paneview/view.d.ts +19 -0
  28. package/dist/cjs/paneview/view.js +44 -0
  29. package/dist/cjs/react.d.ts +35 -0
  30. package/dist/cjs/react.js +183 -0
  31. package/dist/cjs/splitview/splitview.d.ts +17 -0
  32. package/dist/cjs/splitview/splitview.js +105 -0
  33. package/dist/cjs/splitview/view.d.ts +9 -0
  34. package/dist/cjs/splitview/view.js +39 -0
  35. package/dist/cjs/svg.d.ts +3 -0
  36. package/dist/cjs/svg.js +15 -0
  37. package/dist/cjs/types.d.ts +4 -0
  38. package/dist/cjs/types.js +2 -0
  39. package/dist/dockview-react.js +21650 -11
  40. package/dist/dockview-react.min.js +21 -2
  41. package/dist/dockview-react.min.js.map +1 -1
  42. package/dist/esm/dockview/defaultTab.d.ts +7 -0
  43. package/dist/esm/dockview/defaultTab.js +65 -0
  44. package/dist/esm/dockview/dockview.d.ts +33 -0
  45. package/dist/esm/dockview/dockview.js +252 -0
  46. package/dist/esm/dockview/headerActionsRenderer.d.ts +24 -0
  47. package/dist/esm/dockview/headerActionsRenderer.js +72 -0
  48. package/dist/esm/dockview/reactContentPart.d.ts +21 -0
  49. package/dist/esm/dockview/reactContentPart.js +43 -0
  50. package/dist/esm/dockview/reactContextMenuItemPart.d.ts +14 -0
  51. package/dist/esm/dockview/reactContextMenuItemPart.js +22 -0
  52. package/dist/esm/dockview/reactGroupDragGhostPart.d.ts +20 -0
  53. package/dist/esm/dockview/reactGroupDragGhostPart.js +23 -0
  54. package/dist/esm/dockview/reactHeaderPart.d.ts +17 -0
  55. package/dist/esm/dockview/reactHeaderPart.js +37 -0
  56. package/dist/esm/dockview/reactTabGroupChipPart.d.ts +23 -0
  57. package/dist/esm/dockview/reactTabGroupChipPart.js +27 -0
  58. package/dist/esm/dockview/reactWatermarkPart.d.ts +18 -0
  59. package/dist/esm/dockview/reactWatermarkPart.js +38 -0
  60. package/dist/esm/gridview/gridview.d.ts +17 -0
  61. package/dist/esm/gridview/gridview.js +72 -0
  62. package/dist/esm/gridview/view.d.ts +9 -0
  63. package/dist/esm/gridview/view.js +19 -0
  64. package/dist/esm/index.d.ts +9 -0
  65. package/dist/esm/index.js +7 -0
  66. package/dist/esm/paneview/paneview.d.ts +20 -0
  67. package/dist/esm/paneview/paneview.js +104 -0
  68. package/dist/esm/paneview/view.d.ts +19 -0
  69. package/dist/esm/paneview/view.js +35 -0
  70. package/dist/esm/react.d.ts +35 -0
  71. package/dist/esm/react.js +134 -0
  72. package/dist/esm/splitview/splitview.d.ts +17 -0
  73. package/dist/esm/splitview/splitview.js +72 -0
  74. package/dist/esm/splitview/view.d.ts +9 -0
  75. package/dist/esm/splitview/view.js +17 -0
  76. package/dist/esm/svg.d.ts +3 -0
  77. package/dist/esm/svg.js +7 -0
  78. package/dist/esm/types.d.ts +4 -0
  79. package/dist/esm/types.js +1 -0
  80. package/dist/package/main.cjs.js +1037 -5
  81. package/dist/package/main.cjs.min.js +2 -2
  82. package/dist/package/main.esm.min.mjs +2 -8
  83. package/dist/package/main.esm.mjs +1027 -1
  84. package/dist/styles/dockview.css +275 -13
  85. package/package.json +15 -2
@@ -0,0 +1,23 @@
1
+ import React from 'react';
2
+ import { ReactPortalStore } from '../react';
3
+ import { ITabGroupChipRenderer, ITabGroup, DockviewApi } from 'dockview';
4
+ export interface IDockviewTabGroupChipProps {
5
+ tabGroup: ITabGroup;
6
+ api: DockviewApi;
7
+ }
8
+ export declare class ReactTabGroupChipPart implements ITabGroupChipRenderer {
9
+ private readonly component;
10
+ private readonly reactPortalStore;
11
+ private readonly _element;
12
+ private part?;
13
+ get element(): HTMLElement;
14
+ constructor(component: React.FunctionComponent<IDockviewTabGroupChipProps>, reactPortalStore: ReactPortalStore);
15
+ init(params: {
16
+ tabGroup: ITabGroup;
17
+ api: DockviewApi;
18
+ }): void;
19
+ update(params: {
20
+ tabGroup: ITabGroup;
21
+ }): void;
22
+ dispose(): void;
23
+ }
@@ -0,0 +1,27 @@
1
+ import { ReactPart } from '../react';
2
+ export class ReactTabGroupChipPart {
3
+ get element() {
4
+ return this._element;
5
+ }
6
+ constructor(component, reactPortalStore) {
7
+ this.component = component;
8
+ this.reactPortalStore = reactPortalStore;
9
+ this._element = document.createElement('div');
10
+ this._element.className = 'dv-react-part';
11
+ this._element.style.display = 'inline-flex';
12
+ }
13
+ init(params) {
14
+ this.part = new ReactPart(this._element, this.reactPortalStore, this.component, {
15
+ tabGroup: params.tabGroup,
16
+ api: params.api,
17
+ });
18
+ }
19
+ update(params) {
20
+ var _a;
21
+ (_a = this.part) === null || _a === void 0 ? void 0 : _a.update({ tabGroup: params.tabGroup });
22
+ }
23
+ dispose() {
24
+ var _a;
25
+ (_a = this.part) === null || _a === void 0 ? void 0 : _a.dispose();
26
+ }
27
+ }
@@ -0,0 +1,18 @@
1
+ import React from 'react';
2
+ import { ReactPortalStore } from '../react';
3
+ import { PanelUpdateEvent, IWatermarkRenderer, WatermarkRendererInitParameters, IWatermarkPanelProps } from 'dockview';
4
+ export declare class ReactWatermarkPart implements IWatermarkRenderer {
5
+ readonly id: string;
6
+ private readonly component;
7
+ private readonly reactPortalStore;
8
+ private readonly _element;
9
+ private part?;
10
+ private readonly parameters;
11
+ get element(): HTMLElement;
12
+ constructor(id: string, component: React.FunctionComponent<IWatermarkPanelProps>, reactPortalStore: ReactPortalStore);
13
+ init(parameters: WatermarkRendererInitParameters): void;
14
+ focus(): void;
15
+ update(params: PanelUpdateEvent): void;
16
+ layout(_width: number, _height: number): void;
17
+ dispose(): void;
18
+ }
@@ -0,0 +1,38 @@
1
+ import { ReactPart } from '../react';
2
+ export class ReactWatermarkPart {
3
+ get element() {
4
+ return this._element;
5
+ }
6
+ constructor(id, component, reactPortalStore) {
7
+ this.id = id;
8
+ this.component = component;
9
+ this.reactPortalStore = reactPortalStore;
10
+ this._element = document.createElement('div');
11
+ this._element.className = 'dv-react-part';
12
+ this._element.style.height = '100%';
13
+ this._element.style.width = '100%';
14
+ }
15
+ init(parameters) {
16
+ this.part = new ReactPart(this.element, this.reactPortalStore, this.component, {
17
+ group: parameters.group,
18
+ containerApi: parameters.containerApi,
19
+ });
20
+ }
21
+ focus() {
22
+ // noop
23
+ }
24
+ update(params) {
25
+ var _a, _b, _c;
26
+ if (this.parameters) {
27
+ this.parameters.params = params.params;
28
+ }
29
+ (_a = this.part) === null || _a === void 0 ? void 0 : _a.update({ params: (_c = (_b = this.parameters) === null || _b === void 0 ? void 0 : _b.params) !== null && _c !== void 0 ? _c : {} });
30
+ }
31
+ layout(_width, _height) {
32
+ // noop - retrieval from api
33
+ }
34
+ dispose() {
35
+ var _a;
36
+ (_a = this.part) === null || _a === void 0 ? void 0 : _a.dispose();
37
+ }
38
+ }
@@ -0,0 +1,17 @@
1
+ import React from 'react';
2
+ import { GridviewPanelApi, GridviewApi, GridviewOptions } from 'dockview';
3
+ import { PanelParameters } from '../types';
4
+ export interface GridviewReadyEvent {
5
+ api: GridviewApi;
6
+ }
7
+ export interface IGridviewPanelProps<T extends {
8
+ [index: string]: any;
9
+ } = any> extends PanelParameters<T> {
10
+ api: GridviewPanelApi;
11
+ containerApi: GridviewApi;
12
+ }
13
+ export interface IGridviewReactProps extends GridviewOptions {
14
+ onReady: (event: GridviewReadyEvent) => void;
15
+ components: Record<string, React.FunctionComponent<IGridviewPanelProps>>;
16
+ }
17
+ export declare const GridviewReact: React.ForwardRefExoticComponent<IGridviewReactProps & React.RefAttributes<HTMLDivElement>>;
@@ -0,0 +1,72 @@
1
+ import React from 'react';
2
+ import { createGridview, PROPERTY_KEYS_GRIDVIEW, } from 'dockview';
3
+ import { ReactGridPanelView } from './view';
4
+ import { usePortalsLifecycle } from '../react';
5
+ function extractCoreOptions(props) {
6
+ const coreOptions = PROPERTY_KEYS_GRIDVIEW.reduce((obj, key) => {
7
+ if (key in props) {
8
+ obj[key] = props[key];
9
+ }
10
+ return obj;
11
+ }, {});
12
+ return coreOptions;
13
+ }
14
+ export const GridviewReact = React.forwardRef((props, ref) => {
15
+ const domRef = React.useRef(null);
16
+ const gridviewRef = React.useRef(undefined);
17
+ const [portals, addPortal] = usePortalsLifecycle();
18
+ React.useImperativeHandle(ref, () => domRef.current, []);
19
+ const prevProps = React.useRef({});
20
+ React.useEffect(() => {
21
+ const changes = {};
22
+ PROPERTY_KEYS_GRIDVIEW.forEach((propKey) => {
23
+ const key = propKey;
24
+ const propValue = props[key];
25
+ if (key in props && propValue !== prevProps.current[key]) {
26
+ changes[key] = propValue;
27
+ }
28
+ });
29
+ if (gridviewRef.current) {
30
+ gridviewRef.current.updateOptions(changes);
31
+ }
32
+ else {
33
+ // not yet fully initialized
34
+ }
35
+ prevProps.current = props;
36
+ }, PROPERTY_KEYS_GRIDVIEW.map((key) => props[key]));
37
+ React.useEffect(() => {
38
+ if (!domRef.current) {
39
+ return () => {
40
+ // noop
41
+ };
42
+ }
43
+ const frameworkOptions = {
44
+ createComponent: (options) => {
45
+ return new ReactGridPanelView(options.id, options.name, props.components[options.name], { addPortal });
46
+ },
47
+ };
48
+ const api = createGridview(domRef.current, Object.assign(Object.assign({}, extractCoreOptions(props)), frameworkOptions));
49
+ const { clientWidth, clientHeight } = domRef.current;
50
+ api.layout(clientWidth, clientHeight);
51
+ if (props.onReady) {
52
+ props.onReady({ api });
53
+ }
54
+ gridviewRef.current = api;
55
+ return () => {
56
+ gridviewRef.current = undefined;
57
+ api.dispose();
58
+ };
59
+ }, []);
60
+ React.useEffect(() => {
61
+ if (!gridviewRef.current) {
62
+ return;
63
+ }
64
+ gridviewRef.current.updateOptions({
65
+ createComponent: (options) => {
66
+ return new ReactGridPanelView(options.id, options.name, props.components[options.name], { addPortal });
67
+ },
68
+ });
69
+ }, [props.components]);
70
+ return (React.createElement("div", { style: { height: '100%', width: '100%' }, ref: domRef }, portals));
71
+ });
72
+ GridviewReact.displayName = 'GridviewComponent';
@@ -0,0 +1,9 @@
1
+ import { GridviewPanel, IFrameworkPart } from 'dockview';
2
+ import { ReactPortalStore } from '../react';
3
+ import { IGridviewPanelProps } from './gridview';
4
+ export declare class ReactGridPanelView extends GridviewPanel {
5
+ private readonly reactComponent;
6
+ private readonly reactPortalStore;
7
+ constructor(id: string, component: string, reactComponent: React.FunctionComponent<IGridviewPanelProps>, reactPortalStore: ReactPortalStore);
8
+ getComponent(): IFrameworkPart;
9
+ }
@@ -0,0 +1,19 @@
1
+ import { GridviewApi, GridviewPanel, } from 'dockview';
2
+ import { ReactPart } from '../react';
3
+ export class ReactGridPanelView extends GridviewPanel {
4
+ constructor(id, component, reactComponent, reactPortalStore) {
5
+ super(id, component);
6
+ this.reactComponent = reactComponent;
7
+ this.reactPortalStore = reactPortalStore;
8
+ }
9
+ getComponent() {
10
+ var _a, _b;
11
+ return new ReactPart(this.element, this.reactPortalStore, this.reactComponent, {
12
+ params: (_b = (_a = this._params) === null || _a === void 0 ? void 0 : _a.params) !== null && _b !== void 0 ? _b : {},
13
+ api: this.api,
14
+ // TODO: fix casting hack
15
+ containerApi: new GridviewApi(this._params
16
+ .accessor),
17
+ });
18
+ }
19
+ }
@@ -1 +1,10 @@
1
1
  export * from 'dockview';
2
+ export * from './dockview/dockview';
3
+ export * from './dockview/defaultTab';
4
+ export { IDockviewTabGroupChipProps } from './dockview/reactTabGroupChipPart';
5
+ export { IDockviewGroupDragGhostProps } from './dockview/reactGroupDragGhostPart';
6
+ export * from './splitview/splitview';
7
+ export * from './gridview/gridview';
8
+ export * from './paneview/paneview';
9
+ export * from './types';
10
+ export * from './react';
package/dist/esm/index.js CHANGED
@@ -1 +1,8 @@
1
1
  export * from 'dockview';
2
+ export * from './dockview/dockview';
3
+ export * from './dockview/defaultTab';
4
+ export * from './splitview/splitview';
5
+ export * from './gridview/gridview';
6
+ export * from './paneview/paneview';
7
+ export * from './types';
8
+ export * from './react';
@@ -0,0 +1,20 @@
1
+ import React from 'react';
2
+ import { PaneviewPanelApi, PaneviewApi, PaneviewDidDropEvent, PaneviewOptions } from 'dockview';
3
+ import { PanelParameters } from '../types';
4
+ export interface PaneviewReadyEvent {
5
+ api: PaneviewApi;
6
+ }
7
+ export interface IPaneviewPanelProps<T extends {
8
+ [index: string]: any;
9
+ } = any> extends PanelParameters<T> {
10
+ api: PaneviewPanelApi;
11
+ containerApi: PaneviewApi;
12
+ title: string;
13
+ }
14
+ export interface IPaneviewReactProps extends PaneviewOptions {
15
+ onReady: (event: PaneviewReadyEvent) => void;
16
+ components: Record<string, React.FunctionComponent<IPaneviewPanelProps>>;
17
+ headerComponents?: Record<string, React.FunctionComponent<IPaneviewPanelProps>>;
18
+ onDidDrop?(event: PaneviewDidDropEvent): void;
19
+ }
20
+ export declare const PaneviewReact: React.ForwardRefExoticComponent<IPaneviewReactProps & React.RefAttributes<HTMLDivElement>>;
@@ -0,0 +1,104 @@
1
+ import React from 'react';
2
+ import { createPaneview, PROPERTY_KEYS_PANEVIEW, } from 'dockview';
3
+ import { usePortalsLifecycle } from '../react';
4
+ import { PanePanelSection } from './view';
5
+ function extractCoreOptions(props) {
6
+ const coreOptions = PROPERTY_KEYS_PANEVIEW.reduce((obj, key) => {
7
+ if (key in props) {
8
+ obj[key] = props[key];
9
+ }
10
+ return obj;
11
+ }, {});
12
+ return coreOptions;
13
+ }
14
+ export const PaneviewReact = React.forwardRef((props, ref) => {
15
+ const domRef = React.useRef(null);
16
+ const paneviewRef = React.useRef(undefined);
17
+ const [portals, addPortal] = usePortalsLifecycle();
18
+ React.useImperativeHandle(ref, () => domRef.current, []);
19
+ const prevProps = React.useRef({});
20
+ React.useEffect(() => {
21
+ const changes = {};
22
+ PROPERTY_KEYS_PANEVIEW.forEach((propKey) => {
23
+ const key = propKey;
24
+ const propValue = props[key];
25
+ if (key in props && propValue !== prevProps.current[key]) {
26
+ changes[key] = propValue;
27
+ }
28
+ });
29
+ if (paneviewRef.current) {
30
+ paneviewRef.current.updateOptions(changes);
31
+ }
32
+ else {
33
+ // not yet fully initialized
34
+ }
35
+ prevProps.current = props;
36
+ }, PROPERTY_KEYS_PANEVIEW.map((key) => props[key]));
37
+ React.useEffect(() => {
38
+ var _a;
39
+ if (!domRef.current) {
40
+ return () => {
41
+ // noop
42
+ };
43
+ }
44
+ const headerComponents = (_a = props.headerComponents) !== null && _a !== void 0 ? _a : {};
45
+ const frameworkOptions = {
46
+ createComponent: (options) => {
47
+ return new PanePanelSection(options.id, props.components[options.name], { addPortal });
48
+ },
49
+ createHeaderComponent: (options) => {
50
+ return new PanePanelSection(options.id, headerComponents[options.name], { addPortal });
51
+ },
52
+ };
53
+ const api = createPaneview(domRef.current, Object.assign(Object.assign({}, extractCoreOptions(props)), frameworkOptions));
54
+ const { clientWidth, clientHeight } = domRef.current;
55
+ api.layout(clientWidth, clientHeight);
56
+ if (props.onReady) {
57
+ props.onReady({ api });
58
+ }
59
+ paneviewRef.current = api;
60
+ return () => {
61
+ paneviewRef.current = undefined;
62
+ api.dispose();
63
+ };
64
+ }, []);
65
+ React.useEffect(() => {
66
+ if (!paneviewRef.current) {
67
+ return;
68
+ }
69
+ paneviewRef.current.updateOptions({
70
+ createComponent: (options) => {
71
+ return new PanePanelSection(options.id, props.components[options.name], { addPortal });
72
+ },
73
+ });
74
+ }, [props.components]);
75
+ React.useEffect(() => {
76
+ var _a;
77
+ if (!paneviewRef.current) {
78
+ return;
79
+ }
80
+ const headerComponents = (_a = props.headerComponents) !== null && _a !== void 0 ? _a : {};
81
+ paneviewRef.current.updateOptions({
82
+ createHeaderComponent: (options) => {
83
+ return new PanePanelSection(options.id, headerComponents[options.name], { addPortal });
84
+ },
85
+ });
86
+ }, [props.headerComponents]);
87
+ React.useEffect(() => {
88
+ if (!paneviewRef.current) {
89
+ return () => {
90
+ // noop
91
+ };
92
+ }
93
+ const disposable = paneviewRef.current.onDidDrop((event) => {
94
+ if (props.onDidDrop) {
95
+ props.onDidDrop(event);
96
+ }
97
+ });
98
+ return () => {
99
+ disposable.dispose();
100
+ };
101
+ }, [props.onDidDrop]);
102
+ return (React.createElement("div", { style: { height: '100%', width: '100%' }, ref: domRef }, portals));
103
+ });
104
+ PaneviewReact.displayName = 'PaneviewComponent';
@@ -0,0 +1,19 @@
1
+ import React from 'react';
2
+ import { PanelUpdateEvent, IPanePart, PanePanelComponentInitParameter } from 'dockview';
3
+ import { ReactPortalStore } from '../react';
4
+ import { IPaneviewPanelProps } from './paneview';
5
+ export declare class PanePanelSection implements IPanePart {
6
+ readonly id: string;
7
+ private readonly component;
8
+ private readonly reactPortalStore;
9
+ private readonly _element;
10
+ private part?;
11
+ get element(): HTMLElement;
12
+ constructor(id: string, component: React.FunctionComponent<IPaneviewPanelProps>, reactPortalStore: ReactPortalStore);
13
+ init(parameters: PanePanelComponentInitParameter): void;
14
+ toJSON(): {
15
+ id: string;
16
+ };
17
+ update(params: PanelUpdateEvent): void;
18
+ dispose(): void;
19
+ }
@@ -0,0 +1,35 @@
1
+ import { ReactPart } from '../react';
2
+ export class PanePanelSection {
3
+ get element() {
4
+ return this._element;
5
+ }
6
+ constructor(id, component, reactPortalStore) {
7
+ this.id = id;
8
+ this.component = component;
9
+ this.reactPortalStore = reactPortalStore;
10
+ this._element = document.createElement('div');
11
+ this._element.style.height = '100%';
12
+ this._element.style.width = '100%';
13
+ }
14
+ init(parameters) {
15
+ this.part = new ReactPart(this.element, this.reactPortalStore, this.component, {
16
+ params: parameters.params,
17
+ api: parameters.api,
18
+ title: parameters.title,
19
+ containerApi: parameters.containerApi,
20
+ });
21
+ }
22
+ toJSON() {
23
+ return {
24
+ id: this.id,
25
+ };
26
+ }
27
+ update(params) {
28
+ var _a;
29
+ (_a = this.part) === null || _a === void 0 ? void 0 : _a.update(params.params);
30
+ }
31
+ dispose() {
32
+ var _a;
33
+ (_a = this.part) === null || _a === void 0 ? void 0 : _a.dispose();
34
+ }
35
+ }
@@ -0,0 +1,35 @@
1
+ import React from 'react';
2
+ import { IFrameworkPart, DockviewIDisposable } from 'dockview';
3
+ export interface ReactPortalStore {
4
+ addPortal: (portal: React.ReactPortal) => DockviewIDisposable;
5
+ }
6
+ export declare const ReactPartContext: React.Context<{}>;
7
+ export declare class ReactPart<P extends object, C extends object = {}> implements IFrameworkPart {
8
+ private readonly parent;
9
+ private readonly portalStore;
10
+ private readonly component;
11
+ private readonly parameters;
12
+ private readonly context?;
13
+ private _initialProps;
14
+ private componentInstance?;
15
+ private ref?;
16
+ private disposed;
17
+ constructor(parent: HTMLElement, portalStore: ReactPortalStore, component: React.FunctionComponent<P>, parameters: P, context?: C | undefined);
18
+ update(props: {
19
+ [index: string]: any;
20
+ }): void;
21
+ private createPortal;
22
+ dispose(): void;
23
+ }
24
+ type PortalLifecycleHook = () => [
25
+ React.ReactPortal[],
26
+ (portal: React.ReactPortal) => DockviewIDisposable
27
+ ];
28
+ /**
29
+ * A React Hook that returns an array of portals to be rendered by the user of this hook
30
+ * and a disposable function to add a portal. Calling dispose removes this portal from the
31
+ * portal array
32
+ */
33
+ export declare const usePortalsLifecycle: PortalLifecycleHook;
34
+ export declare function isReactComponent(component: any): boolean;
35
+ export {};
@@ -0,0 +1,134 @@
1
+ import React from 'react';
2
+ import ReactDOM from 'react-dom';
3
+ import { DockviewDisposable, } from 'dockview';
4
+ /**
5
+ * This component is intended to interface between vanilla-js and React hence we need to be
6
+ * creative in how we update props.
7
+ * A ref of the component is exposed with an update method; which when called stores the props
8
+ * as a ref within this component and forcefully triggers a re-render of the component using
9
+ * the ref of props we just set on the renderered component as the props passed to the inner
10
+ * component
11
+ */
12
+ const ReactComponentBridge = (props, ref) => {
13
+ const [, triggerRender] = React.useState(0);
14
+ const _props = React.useRef(props.componentProps);
15
+ React.useImperativeHandle(ref, () => ({
16
+ update: (componentProps) => {
17
+ _props.current = Object.assign(Object.assign({}, _props.current), componentProps);
18
+ /**
19
+ * setting a arbitrary piece of state within this component will
20
+ * trigger a re-render.
21
+ * we use this rather than updating through a prop since we can
22
+ * pass a ref into the vanilla-js world.
23
+ *
24
+ * Use a monotonic counter rather than `Date.now()` so two
25
+ * updates within the same millisecond still produce distinct
26
+ * state values and avoid React's bailout.
27
+ */
28
+ triggerRender((n) => n + 1);
29
+ },
30
+ }), []);
31
+ return React.createElement(props.component, _props.current);
32
+ };
33
+ ReactComponentBridge.displayName = 'DockviewReactJsBridge';
34
+ /**
35
+ * Since we are storing the React.Portal references in a rendered array they
36
+ * require a key property like any other React element rendered in an array
37
+ * to prevent excessive re-rendering
38
+ */
39
+ const uniquePortalKeyGenerator = (() => {
40
+ let value = 1;
41
+ return { next: () => `dockview_react_portal_key_${(value++).toString()}` };
42
+ })();
43
+ export const ReactPartContext = React.createContext({});
44
+ export class ReactPart {
45
+ constructor(parent, portalStore, component, parameters, context) {
46
+ this.parent = parent;
47
+ this.portalStore = portalStore;
48
+ this.component = component;
49
+ this.parameters = parameters;
50
+ this.context = context;
51
+ this._initialProps = {};
52
+ this.disposed = false;
53
+ this.createPortal();
54
+ }
55
+ update(props) {
56
+ if (this.disposed) {
57
+ throw new Error('invalid operation: resource is already disposed');
58
+ }
59
+ if (!this.componentInstance) {
60
+ // if the component is yet to be mounted store the props
61
+ this._initialProps = Object.assign(Object.assign({}, this._initialProps), props);
62
+ }
63
+ else {
64
+ this.componentInstance.update(props);
65
+ }
66
+ }
67
+ createPortal() {
68
+ if (this.disposed) {
69
+ throw new Error('invalid operation: resource is already disposed');
70
+ }
71
+ if (!isReactComponent(this.component)) {
72
+ /**
73
+ * we know this isn't a React.FunctionComponent so throw an error here.
74
+ * if we do not intercept then React library will throw a very obsure error
75
+ * for the same reason... at least at this point we will emit a sensible stacktrace.
76
+ */
77
+ throw new Error('Dockview: Only React.memo(...), React.ForwardRef(...) and functional components are accepted as components');
78
+ }
79
+ const bridgeComponent = React.createElement(React.forwardRef(ReactComponentBridge), {
80
+ component: this
81
+ .component,
82
+ componentProps: this.parameters,
83
+ ref: (element) => {
84
+ this.componentInstance = element;
85
+ if (Object.keys(this._initialProps).length > 0) {
86
+ this.componentInstance.update(this._initialProps);
87
+ this._initialProps = {}; // don't keep a reference to the users object once no longer required
88
+ }
89
+ },
90
+ });
91
+ const node = this.context
92
+ ? React.createElement(ReactPartContext.Provider, { value: this.context }, bridgeComponent)
93
+ : bridgeComponent;
94
+ const portal = ReactDOM.createPortal(node, this.parent, uniquePortalKeyGenerator.next());
95
+ this.ref = {
96
+ portal,
97
+ disposable: this.portalStore.addPortal(portal),
98
+ };
99
+ }
100
+ dispose() {
101
+ var _a;
102
+ (_a = this.ref) === null || _a === void 0 ? void 0 : _a.disposable.dispose();
103
+ this.disposed = true;
104
+ }
105
+ }
106
+ /**
107
+ * A React Hook that returns an array of portals to be rendered by the user of this hook
108
+ * and a disposable function to add a portal. Calling dispose removes this portal from the
109
+ * portal array
110
+ */
111
+ export const usePortalsLifecycle = () => {
112
+ const [portals, setPortals] = React.useState([]);
113
+ React.useDebugValue(`Portal count: ${portals.length}`);
114
+ const addPortal = React.useCallback((portal) => {
115
+ setPortals((existingPortals) => [...existingPortals, portal]);
116
+ let disposed = false;
117
+ return DockviewDisposable.from(() => {
118
+ if (disposed) {
119
+ throw new Error('invalid operation: resource already disposed');
120
+ }
121
+ disposed = true;
122
+ setPortals((existingPortals) => existingPortals.filter((p) => p !== portal));
123
+ });
124
+ }, []);
125
+ return [portals, addPortal];
126
+ };
127
+ export function isReactComponent(component) {
128
+ /**
129
+ * Yes, we could use "react-is" but that would introduce an unwanted peer dependency
130
+ * so for now we will check in a rather crude fashion...
131
+ */
132
+ return (typeof component === 'function' /** Functional Componnts */ ||
133
+ !!(component === null || component === void 0 ? void 0 : component.$$typeof) /** React.memo(...) Components */);
134
+ }
@@ -0,0 +1,17 @@
1
+ import React from 'react';
2
+ import { SplitviewApi, SplitviewPanelApi, SplitviewOptions } from 'dockview';
3
+ import { PanelParameters } from '../types';
4
+ export interface SplitviewReadyEvent {
5
+ api: SplitviewApi;
6
+ }
7
+ export interface ISplitviewPanelProps<T extends {
8
+ [index: string]: any;
9
+ } = any> extends PanelParameters<T> {
10
+ api: SplitviewPanelApi;
11
+ containerApi: SplitviewApi;
12
+ }
13
+ export interface ISplitviewReactProps extends SplitviewOptions {
14
+ onReady: (event: SplitviewReadyEvent) => void;
15
+ components: Record<string, React.FunctionComponent<ISplitviewPanelProps>>;
16
+ }
17
+ export declare const SplitviewReact: React.ForwardRefExoticComponent<ISplitviewReactProps & React.RefAttributes<HTMLDivElement>>;