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.
- package/dist/cjs/dockview/defaultTab.d.ts +7 -0
- package/dist/cjs/dockview/defaultTab.js +99 -0
- package/dist/cjs/dockview/dockview.d.ts +33 -0
- package/dist/cjs/dockview/dockview.js +285 -0
- package/dist/cjs/dockview/headerActionsRenderer.d.ts +24 -0
- package/dist/cjs/dockview/headerActionsRenderer.js +86 -0
- package/dist/cjs/dockview/reactContentPart.d.ts +21 -0
- package/dist/cjs/dockview/reactContentPart.js +52 -0
- package/dist/cjs/dockview/reactContextMenuItemPart.d.ts +14 -0
- package/dist/cjs/dockview/reactContextMenuItemPart.js +31 -0
- package/dist/cjs/dockview/reactGroupDragGhostPart.d.ts +20 -0
- package/dist/cjs/dockview/reactGroupDragGhostPart.js +32 -0
- package/dist/cjs/dockview/reactHeaderPart.d.ts +17 -0
- package/dist/cjs/dockview/reactHeaderPart.js +46 -0
- package/dist/cjs/dockview/reactTabGroupChipPart.d.ts +23 -0
- package/dist/cjs/dockview/reactTabGroupChipPart.js +36 -0
- package/dist/cjs/dockview/reactWatermarkPart.d.ts +18 -0
- package/dist/cjs/dockview/reactWatermarkPart.js +47 -0
- package/dist/cjs/gridview/gridview.d.ts +17 -0
- package/dist/cjs/gridview/gridview.js +105 -0
- package/dist/cjs/gridview/view.d.ts +9 -0
- package/dist/cjs/gridview/view.js +41 -0
- package/dist/cjs/index.d.ts +9 -0
- package/dist/cjs/index.js +7 -0
- package/dist/cjs/paneview/paneview.d.ts +20 -0
- package/dist/cjs/paneview/paneview.js +137 -0
- package/dist/cjs/paneview/view.d.ts +19 -0
- package/dist/cjs/paneview/view.js +44 -0
- package/dist/cjs/react.d.ts +35 -0
- package/dist/cjs/react.js +183 -0
- package/dist/cjs/splitview/splitview.d.ts +17 -0
- package/dist/cjs/splitview/splitview.js +105 -0
- package/dist/cjs/splitview/view.d.ts +9 -0
- package/dist/cjs/splitview/view.js +39 -0
- package/dist/cjs/svg.d.ts +3 -0
- package/dist/cjs/svg.js +15 -0
- package/dist/cjs/types.d.ts +4 -0
- package/dist/cjs/types.js +2 -0
- package/dist/dockview-react.js +21650 -11
- package/dist/dockview-react.min.js +21 -2
- package/dist/dockview-react.min.js.map +1 -1
- package/dist/esm/dockview/defaultTab.d.ts +7 -0
- package/dist/esm/dockview/defaultTab.js +65 -0
- package/dist/esm/dockview/dockview.d.ts +33 -0
- package/dist/esm/dockview/dockview.js +252 -0
- package/dist/esm/dockview/headerActionsRenderer.d.ts +24 -0
- package/dist/esm/dockview/headerActionsRenderer.js +72 -0
- package/dist/esm/dockview/reactContentPart.d.ts +21 -0
- package/dist/esm/dockview/reactContentPart.js +43 -0
- package/dist/esm/dockview/reactContextMenuItemPart.d.ts +14 -0
- package/dist/esm/dockview/reactContextMenuItemPart.js +22 -0
- package/dist/esm/dockview/reactGroupDragGhostPart.d.ts +20 -0
- package/dist/esm/dockview/reactGroupDragGhostPart.js +23 -0
- package/dist/esm/dockview/reactHeaderPart.d.ts +17 -0
- package/dist/esm/dockview/reactHeaderPart.js +37 -0
- package/dist/esm/dockview/reactTabGroupChipPart.d.ts +23 -0
- package/dist/esm/dockview/reactTabGroupChipPart.js +27 -0
- package/dist/esm/dockview/reactWatermarkPart.d.ts +18 -0
- package/dist/esm/dockview/reactWatermarkPart.js +38 -0
- package/dist/esm/gridview/gridview.d.ts +17 -0
- package/dist/esm/gridview/gridview.js +72 -0
- package/dist/esm/gridview/view.d.ts +9 -0
- package/dist/esm/gridview/view.js +19 -0
- package/dist/esm/index.d.ts +9 -0
- package/dist/esm/index.js +7 -0
- package/dist/esm/paneview/paneview.d.ts +20 -0
- package/dist/esm/paneview/paneview.js +104 -0
- package/dist/esm/paneview/view.d.ts +19 -0
- package/dist/esm/paneview/view.js +35 -0
- package/dist/esm/react.d.ts +35 -0
- package/dist/esm/react.js +134 -0
- package/dist/esm/splitview/splitview.d.ts +17 -0
- package/dist/esm/splitview/splitview.js +72 -0
- package/dist/esm/splitview/view.d.ts +9 -0
- package/dist/esm/splitview/view.js +17 -0
- package/dist/esm/svg.d.ts +3 -0
- package/dist/esm/svg.js +7 -0
- package/dist/esm/types.d.ts +4 -0
- package/dist/esm/types.js +1 -0
- package/dist/package/main.cjs.js +1037 -5
- package/dist/package/main.cjs.min.js +2 -2
- package/dist/package/main.esm.min.mjs +2 -8
- package/dist/package/main.esm.mjs +1027 -1
- package/dist/styles/dockview.css +275 -13
- 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
|
+
}
|
package/dist/esm/index.d.ts
CHANGED
|
@@ -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>>;
|