feat: forwardRef the React views

This commit is contained in:
mathuo 2021-03-25 21:42:54 +00:00
parent 9c547f90b6
commit 62e568265e
4 changed files with 313 additions and 288 deletions

View File

@ -49,122 +49,132 @@ export interface IDockviewReactProps {
disableAutoResizing?: boolean; disableAutoResizing?: boolean;
} }
export const DockviewReact: React.FunctionComponent<IDockviewReactProps> = ( export const DockviewReact = React.forwardRef(
props: IDockviewReactProps (props: IDockviewReactProps, ref: React.ForwardedRef<HTMLDivElement>) => {
) => { const domRef = React.useRef<HTMLDivElement>(null);
const domRef = React.useRef<HTMLDivElement>(null); const dockviewRef = React.useRef<DockviewComponent>();
const dockviewRef = React.useRef<DockviewComponent>(); const [portals, addPortal] = usePortalsLifecycle();
const [portals, addPortal] = usePortalsLifecycle();
React.useEffect(() => { React.useImperativeHandle(ref, () => domRef.current!, []);
if (props.disableAutoResizing) {
return () => {
//
};
}
const watcher = watchElementResize(domRef.current!, (entry) => { React.useEffect(() => {
const { width, height } = entry.contentRect; if (props.disableAutoResizing) {
dockviewRef.current?.layout(width, height); return () => {
}); //
};
return () => {
watcher.dispose();
};
}, [props.disableAutoResizing]);
React.useEffect(() => {
const factory: GroupPanelFrameworkComponentFactory = {
content: {
createComponent: (
id: string,
componentId: string,
component: React.FunctionComponent<IGroupPanelBaseProps>
): IContentRenderer => {
return new ReactPanelContentPart(componentId, component, {
addPortal,
});
},
},
tab: {
createComponent: (
id: string,
componentId: string,
component: React.FunctionComponent<IGroupPanelBaseProps>
): ITabRenderer => {
return new ReactPanelHeaderPart(componentId, component, {
addPortal,
});
},
},
watermark: {
createComponent: (
id: string,
componentId: string,
component: React.FunctionComponent<{}>
) => {
return new ReactWatermarkPart(componentId, component, {
addPortal,
});
},
},
};
const element = document.createElement('div');
const dockview = new DockviewComponent(element, {
frameworkComponentFactory: factory,
frameworkComponents: props.components,
frameworkTabComponents: props.tabComponents,
tabHeight: props.tabHeight,
debug: props.debug,
enableExternalDragEvents: props.enableExternalDragEvents,
watermarkFrameworkComponent: props.watermarkComponent,
styles: props.hideBorders
? { separatorBorder: 'transparent' }
: undefined,
});
domRef.current?.appendChild(dockview.element);
dockview.deserializer = new ReactPanelDeserialzier(dockview);
if (props.onReady) {
props.onReady({ api: new DockviewApi(dockview) });
}
dockviewRef.current = dockview;
return () => {
dockview.dispose();
};
}, []);
React.useEffect(() => {
if (!props.onTabContextMenu || !dockviewRef.current) {
return () => {
//noop
};
}
const disposable = dockviewRef.current.onTabContextMenu((event) => {
if (props.onTabContextMenu) {
props.onTabContextMenu(event);
} }
});
return () => { const watcher = watchElementResize(domRef.current!, (entry) => {
disposable.dispose(); const { width, height } = entry.contentRect;
}; dockviewRef.current?.layout(width, height);
}, [props.onTabContextMenu]); });
return ( return () => {
<div watcher.dispose();
className={props.className} };
style={{ height: '100%', width: '100%' }} }, [props.disableAutoResizing]);
ref={domRef}
> React.useEffect(() => {
{portals} const factory: GroupPanelFrameworkComponentFactory = {
</div> content: {
); createComponent: (
}; id: string,
componentId: string,
component: React.FunctionComponent<IGroupPanelBaseProps>
): IContentRenderer => {
return new ReactPanelContentPart(
componentId,
component,
{
addPortal,
}
);
},
},
tab: {
createComponent: (
id: string,
componentId: string,
component: React.FunctionComponent<IGroupPanelBaseProps>
): ITabRenderer => {
return new ReactPanelHeaderPart(
componentId,
component,
{
addPortal,
}
);
},
},
watermark: {
createComponent: (
id: string,
componentId: string,
component: React.FunctionComponent<{}>
) => {
return new ReactWatermarkPart(componentId, component, {
addPortal,
});
},
},
};
const element = document.createElement('div');
const dockview = new DockviewComponent(element, {
frameworkComponentFactory: factory,
frameworkComponents: props.components,
frameworkTabComponents: props.tabComponents,
tabHeight: props.tabHeight,
debug: props.debug,
enableExternalDragEvents: props.enableExternalDragEvents,
watermarkFrameworkComponent: props.watermarkComponent,
styles: props.hideBorders
? { separatorBorder: 'transparent' }
: undefined,
});
domRef.current?.appendChild(dockview.element);
dockview.deserializer = new ReactPanelDeserialzier(dockview);
if (props.onReady) {
props.onReady({ api: new DockviewApi(dockview) });
}
dockviewRef.current = dockview;
return () => {
dockview.dispose();
};
}, []);
React.useEffect(() => {
if (!props.onTabContextMenu || !dockviewRef.current) {
return () => {
//noop
};
}
const disposable = dockviewRef.current.onTabContextMenu((event) => {
if (props.onTabContextMenu) {
props.onTabContextMenu(event);
}
});
return () => {
disposable.dispose();
};
}, [props.onTabContextMenu]);
return (
<div
className={props.className}
style={{ height: '100%', width: '100%' }}
ref={domRef}
>
{portals}
</div>
);
}
);
DockviewReact.displayName = 'DockviewComponent'; DockviewReact.displayName = 'DockviewComponent';

View File

@ -31,70 +31,77 @@ export interface IGridviewReactProps {
disableAutoResizing?: boolean; disableAutoResizing?: boolean;
} }
export const GridviewReact: React.FunctionComponent<IGridviewReactProps> = ( export const GridviewReact = React.forwardRef(
props: IGridviewReactProps (props: IGridviewReactProps, ref: React.ForwardedRef<HTMLDivElement>) => {
) => { const domRef = React.useRef<HTMLDivElement>(null);
const domRef = React.useRef<HTMLDivElement>(null); const gridviewRef = React.useRef<IGridviewComponent>();
const gridviewRef = React.useRef<IGridviewComponent>(); const [portals, addPortal] = usePortalsLifecycle();
const [portals, addPortal] = usePortalsLifecycle();
React.useImperativeHandle(ref, () => domRef.current!, []);
React.useEffect(() => {
if (props.disableAutoResizing) {
return () => {
//
};
}
const watcher = watchElementResize(domRef.current!, (entry) => {
const { width, height } = entry.contentRect;
gridviewRef.current?.layout(width, height);
});
React.useEffect(() => {
if (props.disableAutoResizing) {
return () => { return () => {
// watcher.dispose();
}; };
} }, [props.disableAutoResizing]);
const watcher = watchElementResize(domRef.current!, (entry) => { React.useEffect(() => {
const { width, height } = entry.contentRect; const element = document.createElement('div');
gridviewRef.current?.layout(width, height);
});
return () => { const gridview = new GridviewComponent(element, {
watcher.dispose(); proportionalLayout: !!props.proportionalLayout,
}; orientation: props.orientation,
}, [props.disableAutoResizing]); frameworkComponents: props.components,
frameworkComponentFactory: {
React.useEffect(() => { createComponent: (id: string, componentId, component) => {
const element = document.createElement('div'); return new ReactGridPanelView(
id,
const gridview = new GridviewComponent(element, { componentId,
proportionalLayout: !!props.proportionalLayout, component,
orientation: props.orientation, {
frameworkComponents: props.components, addPortal,
frameworkComponentFactory: { }
createComponent: (id: string, componentId, component) => { );
return new ReactGridPanelView(id, componentId, component, { },
addPortal,
});
}, },
}, styles: props.hideBorders
styles: props.hideBorders ? { separatorBorder: 'transparent' }
? { separatorBorder: 'transparent' } : undefined,
: undefined, });
});
domRef.current?.appendChild(gridview.element); domRef.current?.appendChild(gridview.element);
if (props.onReady) { if (props.onReady) {
props.onReady({ api: new GridviewApi(gridview) }); props.onReady({ api: new GridviewApi(gridview) });
} }
gridviewRef.current = gridview; gridviewRef.current = gridview;
return () => { return () => {
gridview.dispose(); gridview.dispose();
}; };
}, []); }, []);
return ( return (
<div <div
className={props.className} className={props.className}
style={{ height: '100%', width: '100%' }} style={{ height: '100%', width: '100%' }}
ref={domRef} ref={domRef}
> >
{portals} {portals}
</div> </div>
); );
}; }
);
GridviewReact.displayName = 'GridviewComponent'; GridviewReact.displayName = 'GridviewComponent';

View File

@ -29,81 +29,83 @@ export interface IPaneviewReactProps {
disableAutoResizing?: boolean; disableAutoResizing?: boolean;
} }
export const PaneviewReact: React.FunctionComponent<IPaneviewReactProps> = ( export const PaneviewReact = React.forwardRef(
props: IPaneviewReactProps (props: IPaneviewReactProps, ref: React.ForwardedRef<HTMLDivElement>) => {
) => { const domRef = React.useRef<HTMLDivElement>(null);
const domRef = React.useRef<HTMLDivElement>(null); const paneviewRef = React.useRef<IPaneviewComponent>();
const paneviewRef = React.useRef<IPaneviewComponent>(); const [portals, addPortal] = usePortalsLifecycle();
const [portals, addPortal] = usePortalsLifecycle();
React.useImperativeHandle(ref, () => domRef.current!, []);
React.useEffect(() => {
if (props.disableAutoResizing) {
return () => {
//
};
}
const watcher = watchElementResize(domRef.current!, (entry) => {
const { width, height } = entry.contentRect;
paneviewRef.current?.layout(width, height);
});
React.useEffect(() => {
if (props.disableAutoResizing) {
return () => { return () => {
// watcher.dispose();
}; };
} }, [props.disableAutoResizing]);
const watcher = watchElementResize(domRef.current!, (entry) => { React.useEffect(() => {
const { width, height } = entry.contentRect; const paneview = new PaneviewComponent(domRef.current!, {
paneviewRef.current?.layout(width, height); frameworkComponents: props.components,
}); components: {},
headerComponents: {},
return () => { headerframeworkComponents: props.headerComponents,
watcher.dispose(); frameworkWrapper: {
}; header: {
}, [props.disableAutoResizing]); createComponent: (
id: string,
React.useEffect(() => { componentId,
const paneview = new PaneviewComponent(domRef.current!, { component: any
frameworkComponents: props.components, ) => {
components: {}, return new PanePanelSection(id, component, {
headerComponents: {}, addPortal,
headerframeworkComponents: props.headerComponents, });
frameworkWrapper: { },
header: { },
createComponent: ( body: {
id: string, createComponent: (
componentId, id: string,
component: any componentId,
) => { component: any
return new PanePanelSection(id, component, { ) => {
addPortal, return new PanePanelSection(id, component, {
}); addPortal,
});
},
}, },
}, },
body: { });
createComponent: (
id: string,
componentId,
component: any
) => {
return new PanePanelSection(id, component, {
addPortal,
});
},
},
},
});
if (props.onReady) { if (props.onReady) {
props.onReady({ api: new PaneviewApi(paneview) }); props.onReady({ api: new PaneviewApi(paneview) });
} }
paneviewRef.current = paneview; paneviewRef.current = paneview;
return () => { return () => {
paneview.dispose(); paneview.dispose();
}; };
}, []); }, []);
return ( return (
<div <div
className={props.className} className={props.className}
style={{ height: '100%', width: '100%' }} style={{ height: '100%', width: '100%' }}
ref={domRef} ref={domRef}
> >
{portals} {portals}
</div> </div>
); );
}; }
);
PaneviewReact.displayName = 'PaneviewComponent'; PaneviewReact.displayName = 'PaneviewComponent';

View File

@ -31,66 +31,72 @@ export interface ISplitviewReactProps {
disableAutoResizing?: boolean; disableAutoResizing?: boolean;
} }
export const SplitviewReact: React.FunctionComponent<ISplitviewReactProps> = ( export const SplitviewReact = React.forwardRef(
props: ISplitviewReactProps (props: ISplitviewReactProps, ref: React.ForwardedRef<HTMLDivElement>) => {
) => { const domRef = React.useRef<HTMLDivElement>(null);
const domRef = React.useRef<HTMLDivElement>(null); const splitviewRef = React.useRef<ISplitviewComponent>();
const splitviewRef = React.useRef<ISplitviewComponent>(); const [portals, addPortal] = usePortalsLifecycle();
const [portals, addPortal] = usePortalsLifecycle();
React.useImperativeHandle(ref, () => domRef.current!, []);
React.useEffect(() => {
if (props.disableAutoResizing) {
return () => {
//
};
}
const watcher = watchElementResize(domRef.current!, (entry) => {
const { width, height } = entry.contentRect;
splitviewRef.current?.layout(width, height);
});
React.useEffect(() => {
if (props.disableAutoResizing) {
return () => { return () => {
// watcher.dispose();
}; };
} }, [props.disableAutoResizing]);
const watcher = watchElementResize(domRef.current!, (entry) => { React.useEffect(() => {
const { width, height } = entry.contentRect; const splitview = new SplitviewComponent(domRef.current!, {
splitviewRef.current?.layout(width, height); orientation: props.orientation,
}); frameworkComponents: props.components,
frameworkWrapper: {
return () => { createComponent: (
watcher.dispose(); id: string,
}; componentId,
}, [props.disableAutoResizing]); component: any
) => {
React.useEffect(() => { return new ReactPanelView(id, componentId, component, {
const splitview = new SplitviewComponent(domRef.current!, { addPortal,
orientation: props.orientation, });
frameworkComponents: props.components, },
frameworkWrapper: {
createComponent: (id: string, componentId, component: any) => {
return new ReactPanelView(id, componentId, component, {
addPortal,
});
}, },
}, proportionalLayout: props.proportionalLayout,
proportionalLayout: props.proportionalLayout, styles: props.hideBorders
styles: props.hideBorders ? { separatorBorder: 'transparent' }
? { separatorBorder: 'transparent' } : undefined,
: undefined, });
});
if (props.onReady) { if (props.onReady) {
props.onReady({ api: new SplitviewApi(splitview) }); props.onReady({ api: new SplitviewApi(splitview) });
} }
splitviewRef.current = splitview; splitviewRef.current = splitview;
return () => { return () => {
splitview.dispose(); splitview.dispose();
}; };
}, []); }, []);
return ( return (
<div <div
className={props.className} className={props.className}
style={{ height: '100%', width: '100%' }} style={{ height: '100%', width: '100%' }}
ref={domRef} ref={domRef}
> >
{portals} {portals}
</div> </div>
); );
}; }
);
SplitviewReact.displayName = 'SplitviewComponent'; SplitviewReact.displayName = 'SplitviewComponent';