mirror of
https://github.com/mathuo/dockview
synced 2025-02-01 22:15:44 +00:00
code
This commit is contained in:
parent
9e26f3d47c
commit
9e34faafea
22
packages/splitview/src/api/panePanelApi.ts
Normal file
22
packages/splitview/src/api/panePanelApi.ts
Normal file
@ -0,0 +1,22 @@
|
||||
import { Emitter, Event } from '../events';
|
||||
import { IPanelApi, PanelApi } from './panelApi';
|
||||
|
||||
interface ExpansionEvent {
|
||||
isExpanded: boolean;
|
||||
}
|
||||
|
||||
export interface IPanePanelApi extends IPanelApi {
|
||||
onDidExpansionChange: Event<ExpansionEvent>;
|
||||
}
|
||||
|
||||
export class PanePanelApi extends PanelApi implements IPanePanelApi {
|
||||
readonly _onDidExpansionChange = new Emitter<ExpansionEvent>({
|
||||
emitLastValue: true,
|
||||
});
|
||||
readonly onDidExpansionChange: Event<ExpansionEvent> = this
|
||||
._onDidExpansionChange.event;
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
}
|
||||
}
|
@ -76,6 +76,17 @@ export class ComponentPaneView implements IComponentPaneView {
|
||||
this.paneview.layout(size, orthogonalSize);
|
||||
}
|
||||
|
||||
/**
|
||||
* Resize the layout to fit the parent container
|
||||
*/
|
||||
public resizeToFit(): void {
|
||||
const {
|
||||
width,
|
||||
height,
|
||||
} = this.element.parentElement.getBoundingClientRect();
|
||||
this.layout(width, height);
|
||||
}
|
||||
|
||||
public dispose() {
|
||||
this.paneview.dispose();
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { SplitView, IView, Orientation } from '../splitview/splitview';
|
||||
import { IDisposable } from '../lifecycle';
|
||||
import { CompositeDisposable, IDisposable } from '../lifecycle';
|
||||
import { Emitter, Event } from '../events';
|
||||
import { addClasses, removeClasses } from '../dom';
|
||||
|
||||
@ -13,7 +13,7 @@ export interface IPaneview extends IView {
|
||||
onDidChangeExpansionState: Event<boolean>;
|
||||
}
|
||||
|
||||
export abstract class Pane implements IPaneview {
|
||||
export abstract class Pane extends CompositeDisposable implements IPaneview {
|
||||
private _element: HTMLElement;
|
||||
private _minimumBodySize: number;
|
||||
private _maximumBodySize: number;
|
||||
@ -81,6 +81,10 @@ export abstract class Pane implements IPaneview {
|
||||
}
|
||||
|
||||
constructor(options: IPaneOptions) {
|
||||
super();
|
||||
|
||||
this.addDisposables(this._onDidChange, this._onDidChangeExpansionState);
|
||||
|
||||
this._element = document.createElement('div');
|
||||
this._element.className = 'pane';
|
||||
|
||||
|
@ -9,6 +9,7 @@ import {
|
||||
TabContextMenuEvent,
|
||||
} from '../../dockview/options';
|
||||
import { IGroupPanelApi } from '../../api/groupPanelApi';
|
||||
import { usePortalsLifecycle } from '../react';
|
||||
|
||||
export interface IGroupPanelProps {
|
||||
api: IGroupPanelApi;
|
||||
@ -51,23 +52,12 @@ export interface IDockviewComponentProps {
|
||||
export const DockviewComponent: React.FunctionComponent<IDockviewComponentProps> = (
|
||||
props: IDockviewComponentProps
|
||||
) => {
|
||||
const domReference = React.useRef<HTMLDivElement>();
|
||||
const layoutReference = React.useRef<ComponentDockview>();
|
||||
const domRef = React.useRef<HTMLDivElement>();
|
||||
const dockviewRef = React.useRef<ComponentDockview>();
|
||||
|
||||
const [portals, setPortals] = React.useState<React.ReactPortal[]>([]);
|
||||
const [portals, addPortal] = usePortalsLifecycle();
|
||||
|
||||
React.useEffect(() => {
|
||||
const addPortal = (p: React.ReactPortal) => {
|
||||
setPortals((portals) => [...portals, p]);
|
||||
return {
|
||||
dispose: () => {
|
||||
setPortals((portals) =>
|
||||
portals.filter((portal) => portal !== p)
|
||||
);
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
const factory: GroupPanelFrameworkComponentFactory = {
|
||||
content: {
|
||||
createComponent: (
|
||||
@ -95,7 +85,7 @@ export const DockviewComponent: React.FunctionComponent<IDockviewComponentProps>
|
||||
|
||||
const element = document.createElement('div');
|
||||
|
||||
const layout = new ComponentDockview(element, {
|
||||
const dockview = new ComponentDockview(element, {
|
||||
frameworkComponentFactory: factory,
|
||||
frameworkComponents: props.components,
|
||||
frameworkTabComponents: props.tabComponents,
|
||||
@ -105,28 +95,28 @@ export const DockviewComponent: React.FunctionComponent<IDockviewComponentProps>
|
||||
// orientation: props.orientation,
|
||||
});
|
||||
|
||||
layoutReference.current = layout;
|
||||
domReference.current.appendChild(layoutReference.current.element);
|
||||
|
||||
layout.deserializer = new ReactPanelDeserialzier(layout);
|
||||
|
||||
layout.resizeToFit();
|
||||
domRef.current.appendChild(dockview.element);
|
||||
dockview.deserializer = new ReactPanelDeserialzier(dockview);
|
||||
|
||||
if (props.serializedLayout) {
|
||||
layout.deserialize(props.serializedLayout);
|
||||
dockview.deserialize(props.serializedLayout);
|
||||
}
|
||||
|
||||
dockview.resizeToFit();
|
||||
|
||||
if (props.onReady) {
|
||||
props.onReady({ api: layout });
|
||||
props.onReady({ api: dockview });
|
||||
}
|
||||
|
||||
dockviewRef.current = dockview;
|
||||
|
||||
return () => {
|
||||
layout.dispose();
|
||||
dockview.dispose();
|
||||
};
|
||||
}, []);
|
||||
|
||||
React.useEffect(() => {
|
||||
const disposable = layoutReference.current.onTabContextMenu((event) => {
|
||||
const disposable = dockviewRef.current.onTabContextMenu((event) => {
|
||||
props.onTabContextMenu(event);
|
||||
});
|
||||
|
||||
@ -136,9 +126,7 @@ export const DockviewComponent: React.FunctionComponent<IDockviewComponentProps>
|
||||
}, [props.onTabContextMenu]);
|
||||
|
||||
React.useEffect(() => {
|
||||
layoutReference.current.setAutoResizeToFit(
|
||||
props.autoSizeToFitContainer
|
||||
);
|
||||
dockviewRef.current.setAutoResizeToFit(props.autoSizeToFitContainer);
|
||||
}, [props.autoSizeToFitContainer]);
|
||||
|
||||
return (
|
||||
@ -147,7 +135,7 @@ export const DockviewComponent: React.FunctionComponent<IDockviewComponentProps>
|
||||
// height: '100%',
|
||||
width: '100%',
|
||||
}}
|
||||
ref={domReference}
|
||||
ref={domRef}
|
||||
>
|
||||
{portals}
|
||||
</div>
|
||||
|
@ -54,9 +54,6 @@ export class ReactPanelContentPart implements PanelContentPart {
|
||||
return Promise.resolve(ClosePanelResult.CLOSE);
|
||||
}
|
||||
|
||||
public focus(): void {}
|
||||
public onHide(): void {}
|
||||
|
||||
public dispose() {
|
||||
this.part?.dispose();
|
||||
}
|
||||
|
@ -1,5 +1,4 @@
|
||||
import * as React from 'react';
|
||||
import { IGroupPanelApi } from '../../api/groupPanelApi';
|
||||
import {
|
||||
PanelHeaderPart,
|
||||
GroupPanelPartInitParameters,
|
||||
|
@ -6,6 +6,7 @@ import {
|
||||
import { IGridPanelApi } from '../../api/gridPanelApi';
|
||||
import { Orientation } from '../../splitview/splitview';
|
||||
import { ReactComponentGridView } from './reactComponentGridView';
|
||||
import { usePortalsLifecycle } from '../react';
|
||||
|
||||
export interface GridviewReadyEvent {
|
||||
api: IComponentGridview;
|
||||
@ -26,23 +27,12 @@ export interface IGridviewComponentProps {
|
||||
export const GridviewComponent: React.FunctionComponent<IGridviewComponentProps> = (
|
||||
props: IGridviewComponentProps
|
||||
) => {
|
||||
const domReference = React.useRef<HTMLDivElement>();
|
||||
const gridview = React.useRef<IComponentGridview>();
|
||||
const [portals, setPortals] = React.useState<React.ReactPortal[]>([]);
|
||||
|
||||
const addPortal = React.useCallback((p: React.ReactPortal) => {
|
||||
setPortals((portals) => [...portals, p]);
|
||||
return {
|
||||
dispose: () => {
|
||||
setPortals((portals) =>
|
||||
portals.filter((portal) => portal !== p)
|
||||
);
|
||||
},
|
||||
};
|
||||
}, []);
|
||||
const domRef = React.useRef<HTMLDivElement>();
|
||||
const gridviewRef = React.useRef<IComponentGridview>();
|
||||
const [portals, addPortal] = usePortalsLifecycle();
|
||||
|
||||
React.useEffect(() => {
|
||||
gridview.current = new ComponentGridview(domReference.current, {
|
||||
const gridview = new ComponentGridview(domRef.current, {
|
||||
orientation: props.orientation,
|
||||
frameworkComponents: props.components,
|
||||
frameworkComponentFactory: {
|
||||
@ -59,9 +49,17 @@ export const GridviewComponent: React.FunctionComponent<IGridviewComponentProps>
|
||||
},
|
||||
});
|
||||
|
||||
// gridview.resizeToFit();
|
||||
|
||||
if (props.onReady) {
|
||||
props.onReady({ api: gridview.current });
|
||||
props.onReady({ api: gridview });
|
||||
}
|
||||
|
||||
gridviewRef.current = gridview;
|
||||
|
||||
return () => {
|
||||
gridview.dispose();
|
||||
};
|
||||
}, []);
|
||||
|
||||
return (
|
||||
@ -70,7 +68,7 @@ export const GridviewComponent: React.FunctionComponent<IGridviewComponentProps>
|
||||
height: '100%',
|
||||
width: '100%',
|
||||
}}
|
||||
ref={domReference}
|
||||
ref={domRef}
|
||||
>
|
||||
{portals}
|
||||
</div>
|
||||
|
@ -1,17 +1,18 @@
|
||||
import * as React from 'react';
|
||||
import { IPanelApi } from '../../api/panelApi';
|
||||
import { IPanePanelApi } from '../../api/panePanelApi';
|
||||
import {
|
||||
ComponentPaneView,
|
||||
IComponentPaneView,
|
||||
} from '../../paneview/componentPaneView';
|
||||
import { PaneReact } from './reactPane';
|
||||
import { usePortalsLifecycle } from '../react';
|
||||
|
||||
export interface PaneviewReadyEvent {
|
||||
api: IComponentPaneView;
|
||||
}
|
||||
|
||||
export interface IPaneviewPanelProps {
|
||||
api: IPanelApi;
|
||||
api: IPanePanelApi;
|
||||
}
|
||||
|
||||
export interface IPaneviewComponentProps {
|
||||
@ -24,23 +25,12 @@ export interface IPaneviewComponentProps {
|
||||
export const PaneViewComponent: React.FunctionComponent<IPaneviewComponentProps> = (
|
||||
props: IPaneviewComponentProps
|
||||
) => {
|
||||
const domReference = React.useRef<HTMLDivElement>();
|
||||
const splitpanel = React.useRef<IComponentPaneView>();
|
||||
const [portals, setPortals] = React.useState<React.ReactPortal[]>([]);
|
||||
|
||||
const addPortal = React.useCallback((p: React.ReactPortal) => {
|
||||
setPortals((portals) => [...portals, p]);
|
||||
return {
|
||||
dispose: () => {
|
||||
setPortals((portals) =>
|
||||
portals.filter((portal) => portal !== p)
|
||||
);
|
||||
},
|
||||
};
|
||||
}, []);
|
||||
const domRef = React.useRef<HTMLDivElement>();
|
||||
const paneviewRef = React.useRef<IComponentPaneView>();
|
||||
const [portals, addPortal] = usePortalsLifecycle();
|
||||
|
||||
React.useEffect(() => {
|
||||
splitpanel.current = new ComponentPaneView(domReference.current, {
|
||||
const paneview = new ComponentPaneView(domRef.current, {
|
||||
frameworkComponents: props.components,
|
||||
components: {},
|
||||
frameworkWrapper: {
|
||||
@ -56,16 +46,20 @@ export const PaneViewComponent: React.FunctionComponent<IPaneviewComponentProps>
|
||||
},
|
||||
});
|
||||
|
||||
const { width, height } = domReference.current.getBoundingClientRect();
|
||||
const { width, height } = domRef.current.getBoundingClientRect();
|
||||
const [size, orthogonalSize] = [height, width];
|
||||
splitpanel.current.layout(size, orthogonalSize);
|
||||
paneview.layout(size, orthogonalSize);
|
||||
|
||||
if (props.onReady) {
|
||||
props.onReady({ api: splitpanel.current });
|
||||
props.onReady({ api: paneview });
|
||||
}
|
||||
|
||||
paneview.resizeToFit();
|
||||
|
||||
paneviewRef.current = paneview;
|
||||
|
||||
return () => {
|
||||
splitpanel.current.dispose();
|
||||
paneview.dispose();
|
||||
};
|
||||
}, []);
|
||||
|
||||
@ -75,7 +69,7 @@ export const PaneViewComponent: React.FunctionComponent<IPaneviewComponentProps>
|
||||
height: '100%',
|
||||
width: '100%',
|
||||
}}
|
||||
ref={domReference}
|
||||
ref={domRef}
|
||||
>
|
||||
{portals}
|
||||
</div>
|
||||
|
@ -1,12 +1,12 @@
|
||||
import * as React from 'react';
|
||||
import { BaseViewApi, IBaseViewApi } from '../../api/api';
|
||||
import { IPanePanelApi, PanePanelApi } from '../../api/panePanelApi';
|
||||
import { Pane } from '../../paneview/paneview';
|
||||
import { ReactLayout } from '../dockview/dockview';
|
||||
import { ReactPart } from '../react';
|
||||
|
||||
export class PaneReact extends Pane {
|
||||
private params: {};
|
||||
private api: IBaseViewApi;
|
||||
private api: PanePanelApi;
|
||||
|
||||
private contentPart: ReactPart;
|
||||
private headerPart: ReactPart;
|
||||
@ -27,7 +27,14 @@ export class PaneReact extends Pane {
|
||||
// options.isExpanded
|
||||
});
|
||||
|
||||
this.api = new BaseViewApi();
|
||||
this.api = new PanePanelApi();
|
||||
|
||||
this.addDisposables(
|
||||
this.onDidChangeExpansionState((isExpanded) => {
|
||||
this.api._onDidExpansionChange.fire({ isExpanded });
|
||||
})
|
||||
);
|
||||
|
||||
this.render();
|
||||
}
|
||||
|
||||
@ -62,6 +69,7 @@ export class PaneReact extends Pane {
|
||||
}
|
||||
|
||||
public dispose() {
|
||||
super.dispose();
|
||||
this.headerPart.dispose();
|
||||
this.contentPart.dispose();
|
||||
this.api.dispose();
|
||||
|
@ -118,3 +118,28 @@ export class ReactPart implements IDisposable {
|
||||
this.disposed = true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A React Hook that returns an array of portals to be rendered by the user of this hook
|
||||
* and a disposable function to add a portal. Calling dispose remove this portal from the
|
||||
* portal array
|
||||
*/
|
||||
export const usePortalsLifecycle = () => {
|
||||
const [portals, setPortals] = React.useState<React.ReactPortal[]>([]);
|
||||
|
||||
const addPortal = React.useCallback((p: React.ReactPortal) => {
|
||||
setPortals((portals) => [...portals, p]);
|
||||
return {
|
||||
dispose: () => {
|
||||
setPortals((portals) =>
|
||||
portals.filter((portal) => portal !== p)
|
||||
);
|
||||
},
|
||||
};
|
||||
}, []);
|
||||
|
||||
return [portals, addPortal] as [
|
||||
React.ReactPortal[],
|
||||
(portal: React.ReactPortal) => IDisposable
|
||||
];
|
||||
};
|
||||
|
@ -5,6 +5,7 @@ import {
|
||||
ComponentSplitview,
|
||||
} from '../../splitview/componentSplitview';
|
||||
import { Orientation } from '../../splitview/splitview';
|
||||
import { usePortalsLifecycle } from '../react';
|
||||
import { ReactComponentView } from './reactComponentView';
|
||||
|
||||
export interface SplitviewReadyEvent {
|
||||
@ -26,23 +27,12 @@ export interface ISplitviewComponentProps {
|
||||
export const SplitviewComponent: React.FunctionComponent<ISplitviewComponentProps> = (
|
||||
props: ISplitviewComponentProps
|
||||
) => {
|
||||
const domReference = React.useRef<HTMLDivElement>();
|
||||
const splitpanel = React.useRef<IComponentSplitview>();
|
||||
const [portals, setPortals] = React.useState<React.ReactPortal[]>([]);
|
||||
|
||||
const addPortal = React.useCallback((p: React.ReactPortal) => {
|
||||
setPortals((portals) => [...portals, p]);
|
||||
return {
|
||||
dispose: () => {
|
||||
setPortals((portals) =>
|
||||
portals.filter((portal) => portal !== p)
|
||||
);
|
||||
},
|
||||
};
|
||||
}, []);
|
||||
const domRef = React.useRef<HTMLDivElement>();
|
||||
const splitviewRef = React.useRef<IComponentSplitview>();
|
||||
const [portals, addPortal] = usePortalsLifecycle();
|
||||
|
||||
React.useEffect(() => {
|
||||
splitpanel.current = new ComponentSplitview(domReference.current, {
|
||||
const splitview = new ComponentSplitview(domRef.current, {
|
||||
orientation: props.orientation,
|
||||
frameworkComponents: props.components,
|
||||
frameworkWrapper: {
|
||||
@ -55,19 +45,16 @@ export const SplitviewComponent: React.FunctionComponent<ISplitviewComponentProp
|
||||
proportionalLayout: false,
|
||||
});
|
||||
|
||||
const { width, height } = domReference.current.getBoundingClientRect();
|
||||
const [size, orthogonalSize] =
|
||||
props.orientation === Orientation.HORIZONTAL
|
||||
? [width, height]
|
||||
: [height, width];
|
||||
splitpanel.current.layout(size, orthogonalSize);
|
||||
splitview.resizeToFit();
|
||||
|
||||
if (props.onReady) {
|
||||
props.onReady({ api: splitpanel.current });
|
||||
props.onReady({ api: splitview });
|
||||
}
|
||||
|
||||
splitviewRef.current = splitview;
|
||||
|
||||
return () => {
|
||||
splitpanel.current.dispose();
|
||||
splitview.dispose();
|
||||
};
|
||||
}, []);
|
||||
|
||||
@ -77,7 +64,7 @@ export const SplitviewComponent: React.FunctionComponent<ISplitviewComponentProp
|
||||
height: '100%',
|
||||
width: '100%',
|
||||
}}
|
||||
ref={domReference}
|
||||
ref={domRef}
|
||||
>
|
||||
{portals}
|
||||
</div>
|
||||
|
@ -79,6 +79,17 @@ export class ComponentSplitview implements IComponentSplitview {
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Resize the layout to fit the parent container
|
||||
*/
|
||||
public resizeToFit(): void {
|
||||
const {
|
||||
width,
|
||||
height,
|
||||
} = this.element.parentElement.getBoundingClientRect();
|
||||
this.layout(width, height);
|
||||
}
|
||||
|
||||
private registerView(view: ISerializableView) {
|
||||
//
|
||||
}
|
||||
|
@ -4,5 +4,7 @@
|
||||
"path": "."
|
||||
}
|
||||
],
|
||||
"settings": {}
|
||||
"settings": {
|
||||
"editor.formatOnSave": true
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user