diff --git a/.github/workflows/deploy-docs.yml b/.github/workflows/deploy-docs.yml index 015f2f37e..68f98f050 100644 --- a/.github/workflows/deploy-docs.yml +++ b/.github/workflows/deploy-docs.yml @@ -1,10 +1,10 @@ name: Deploy Docs -on: - schedule: - - cron: '0 3 * * *' # every day at 3 am UTC +# on: +# schedule: +# - cron: '0 3 * * *' # every day at 3 am UTC -# on: [push] +on: [push] jobs: deploy-nightly-demo-app: diff --git a/README.md b/README.md index 554188d93..6d529b68a 100644 --- a/README.md +++ b/README.md @@ -124,31 +124,6 @@ const Component = () => { }; ``` -Specifically for `DockviewReact` there exists higher-order components to encapsulate both the tab and contents into one logical component for the user making state sharing between the two simple, which is an optional feature. - -```tsx -const components: PanelCollection = { - default: (props: IDockviewPanelProps<{ someProps: string }>) => { - return
{props.params.someProps}
; - }, - fancy: (props: IDockviewPanelProps) => { - return ( - - -
- {props.api.title} - props.api.close()}>{'Close'} -
-
- -
{'Hello world'}
-
-
- ); - }, -}; -``` - ## Sandbox examples - [Dockview](https://codesandbox.io/s/simple-dockview-t6491) diff --git a/packages/dockview-demo/src/layout-grid/activitybar.tsx b/packages/dockview-demo/src/layout-grid/activitybar.tsx index 925d3d680..ba68ef956 100644 --- a/packages/dockview-demo/src/layout-grid/activitybar.tsx +++ b/packages/dockview-demo/src/layout-grid/activitybar.tsx @@ -23,10 +23,10 @@ export const Activitybar = (props: IGridviewPanelProps) => { const sidebarPanel = api.getPanel('sidebar'); if (sidebarPanel.api.isVisible) { - api.setVisible(sidebarPanel, false); + sidebarPanel.api.setVisible(false); } else { event.preventDefault(); // prevent focus - api.setVisible(sidebarPanel, true); + sidebarPanel.api.setVisible(true); sidebarPanel.focus(); } }; diff --git a/packages/dockview-demo/src/layout-grid/layoutGrid.tsx b/packages/dockview-demo/src/layout-grid/layoutGrid.tsx index 6c660d91f..d8889ec72 100644 --- a/packages/dockview-demo/src/layout-grid/layoutGrid.tsx +++ b/packages/dockview-demo/src/layout-grid/layoutGrid.tsx @@ -10,7 +10,6 @@ import { IWatermarkPanelProps, IDockviewPanel, PanelCollection, - DockviewComponents, } from 'dockview'; import { CustomTab } from './customTab'; import { Settings } from './settingsPanel'; @@ -47,22 +46,10 @@ const Test = (props: IDockviewPanelProps) => { }, []); return ( - - {counter % 4 === 0 && ( - -
{`custom tab ${counter}`}
-
- )} - -
-
{`custom body ${counter}`}
- -
-
- -
{`custom action ${counter}`}
-
-
+
+
{`custom body ${counter}`}
+ +
); }; diff --git a/packages/dockview-demo/src/layout-grid/panels/exampleFunctions.tsx b/packages/dockview-demo/src/layout-grid/panels/exampleFunctions.tsx index e0384ac30..b0832f0cf 100644 --- a/packages/dockview-demo/src/layout-grid/panels/exampleFunctions.tsx +++ b/packages/dockview-demo/src/layout-grid/panels/exampleFunctions.tsx @@ -1,4 +1,4 @@ -import { DockviewComponents, IDockviewPanelProps } from 'dockview'; +import { IDockviewPanelProps } from 'dockview'; import * as React from 'react'; import { CompositeDisposable } from '../../lifecycle'; import './exampleFunctions.scss'; @@ -30,8 +30,10 @@ export const ExampleFunctions = ( isPanelVisible: x.isVisible, })); }), - props.api.onFocusEvent(() => { - input.current.focus(); + props.api.onDidFocusChange(({ isFocused }) => { + if (isFocused) { + input.current.focus(); + } }) ); @@ -49,80 +51,52 @@ export const ExampleFunctions = ( }; return ( - - -
+
+
+ + {'isGroupActive: '} - menu + {`${panelState.isGroupActive}`} -
- - -
-
- - {'isGroupActive: '} - - {`${panelState.isGroupActive}`} - - - - {'isPanelVisible: '} - - {`${panelState.isPanelVisible}`} - - -
-
- - setPanelName(event.target.value) - } - /> - -
+ + + {'isPanelVisible: '} + + {`${panelState.isPanelVisible}`} + + +
+
+ setPanelName(event.target.value)} + /> + +
- - -
- - + + +
); }; diff --git a/packages/dockview-demo/src/layout-grid/sidebar.tsx b/packages/dockview-demo/src/layout-grid/sidebar.tsx index 864043275..bdb69f55d 100644 --- a/packages/dockview-demo/src/layout-grid/sidebar.tsx +++ b/packages/dockview-demo/src/layout-grid/sidebar.tsx @@ -64,8 +64,10 @@ export const Sidebar = (props: IGridviewPanelProps) => { props.api.onDidVisibilityChange((event) => { console.log(event); }), - props.api.onFocusEvent(() => { - api.current.focus(); + props.api.onDidFocusChange(({ isFocused }) => { + if (isFocused) { + api.current.focus(); + } }) ); diff --git a/packages/dockview-demo/src/layout-grid/splitPanel.tsx b/packages/dockview-demo/src/layout-grid/splitPanel.tsx index 177954997..c5b812383 100644 --- a/packages/dockview-demo/src/layout-grid/splitPanel.tsx +++ b/packages/dockview-demo/src/layout-grid/splitPanel.tsx @@ -29,8 +29,10 @@ const components = { props.api.onDidActiveChange((event) => { setActive(event.isActive); }), - props.api.onFocusEvent(() => { - ref.current.focus(); + props.api.onDidFocusChange(({ isFocused }) => { + if (isFocused) { + ref.current.focus(); + } }) ); @@ -65,8 +67,10 @@ export const SplitPanel = (props: IDockviewPanelProps) => { props.api.onDidDimensionsChange((event) => { api.current?.layout(event.width, event.height - 25); }), - props.api.onFocusEvent(() => { - api.current.focus(); + props.api.onDidFocusChange(({ isFocused }) => { + if (isFocused) { + api.current.focus(); + } }) ); diff --git a/packages/dockview-demo/src/panels/splitview/splitview.tsx b/packages/dockview-demo/src/panels/splitview/splitview.tsx index c74fe45b4..17012f142 100644 --- a/packages/dockview-demo/src/panels/splitview/splitview.tsx +++ b/packages/dockview-demo/src/panels/splitview/splitview.tsx @@ -227,7 +227,7 @@ export const Common = ( const toggleVisibility = (i: number) => () => { const panel = api.current.panels[i]; - api.current.setVisible(panel, !panel.api.isVisible); + panel.api.setVisible(panel.api.isVisible); setDimensions((dimensions) => ({ ...dimensions, visibility: api.current.panels.map((_) => _.api.isVisible), diff --git a/packages/dockview-demo/src/services/widgets.tsx b/packages/dockview-demo/src/services/widgets.tsx index af1174277..555d0cb64 100644 --- a/packages/dockview-demo/src/services/widgets.tsx +++ b/packages/dockview-demo/src/services/widgets.tsx @@ -161,11 +161,11 @@ export const Activitybar = (props: IGridviewPanelProps) => { const sidebarPanel = api.getPanel('sidebar'); if (sidebarPanel.api.isVisible) { if (!alwaysOpen && selectedActive) { - api.setVisible(sidebarPanel, false); + sidebarPanel.api.setVisible(false); } } else { event.preventDefault(); // prevent focus - api.setVisible(sidebarPanel, true); + sidebarPanel.api.setVisible(true); sidebarPanel.focus(); } @@ -234,7 +234,7 @@ export const Activitybar = (props: IGridviewPanelProps) => { const sidebarPanel = api.getPanel('sidebar'); if (!sidebarPanel.api.isVisible) { - api.setVisible(sidebarPanel, true); + sidebarPanel.api.setVisible(true); sidebarPanel.focus(); } diff --git a/packages/dockview-demo/src/stories/dockview/dockview.params.stories.tsx b/packages/dockview-demo/src/stories/dockview/dockview.params.stories.tsx index eaed448c2..888f76bd5 100644 --- a/packages/dockview-demo/src/stories/dockview/dockview.params.stories.tsx +++ b/packages/dockview-demo/src/stories/dockview/dockview.params.stories.tsx @@ -1,6 +1,5 @@ import { DockviewApi, - DockviewComponents, DockviewReact, DockviewReadyEvent, IDockviewPanelProps, @@ -18,35 +17,9 @@ const components: PanelCollection> = { ticker: (props: IDockviewPanelProps<{ ticker: number }>) => { const close = () => props.api.close(); return ( - - -
- {props.api.title} - {`(${props.params.ticker})`} - {!props.api.suppressClosable && ( - X - )} -
-
- -
- {`The current ticker value is ${props.params.ticker}`} -
-
-
+
+ {`The current ticker value is ${props.params.ticker}`} +
); }, iframe: (props) => { diff --git a/packages/dockview-demo/src/stories/dockview/dockview.tab.stories.tsx b/packages/dockview-demo/src/stories/dockview/dockview.tab.stories.tsx index 60bffe701..9f5edfc5e 100644 --- a/packages/dockview-demo/src/stories/dockview/dockview.tab.stories.tsx +++ b/packages/dockview-demo/src/stories/dockview/dockview.tab.stories.tsx @@ -1,6 +1,5 @@ import { DockviewApi, - DockviewComponents, DockviewReact, DockviewReadyEvent, IDockviewPanelProps, @@ -13,35 +12,7 @@ const components: PanelCollection = { default: (props) => { const close = () => props.api.close(); return ( - - -
- {props.api.title} - - {'(Custom tab component)'} - - {!props.api.suppressClosable && ( - X - )} -
-
- -
- hello world -
-
-
+
hello world
); }, }; diff --git a/packages/dockview-docs/src/components/container.tsx b/packages/dockview-docs/src/components/container.tsx index f33d46ae4..56cb9407a 100644 --- a/packages/dockview-docs/src/components/container.tsx +++ b/packages/dockview-docs/src/components/container.tsx @@ -14,7 +14,7 @@ export const Container = (props: { children: React.ReactNode }) => {
{props.children} diff --git a/packages/dockview-docs/src/components/dockview/customCss.tsx b/packages/dockview-docs/src/components/dockview/customCss.tsx new file mode 100644 index 000000000..22f30834a --- /dev/null +++ b/packages/dockview-docs/src/components/dockview/customCss.tsx @@ -0,0 +1,57 @@ +import { + DockviewReact, + DockviewReadyEvent, + IDockviewPanelProps, +} from 'dockview'; + +// +const components = { + default: (props: IDockviewPanelProps<{ title: string }>) => { + return
{props.params.title}
; + }, +}; + +export const CustomCSSDockview = () => { + const onReady = (event: DockviewReadyEvent) => { + event.api.addPanel({ + id: 'panel_1', + component: 'default', + params: { + title: 'Panel 1', + }, + }); + + event.api.addPanel({ + id: 'panel_2', + component: 'default', + params: { + title: 'Panel 2', + }, + }); + + event.api.addPanel({ + id: 'panel_3', + component: 'default', + params: { + title: 'Panel 3', + }, + }); + + event.api.addPanel({ + id: 'panel_4', + component: 'default', + params: { + title: 'Panel 4', + }, + position: { referencePanel: 'panel_1', direction: 'right' }, + }); + }; + + return ( + + ); +}; diff --git a/packages/dockview-docs/src/components/simplePaneview.tsx b/packages/dockview-docs/src/components/simplePaneview.tsx index 98603f027..d1094fe99 100644 --- a/packages/dockview-docs/src/components/simplePaneview.tsx +++ b/packages/dockview-docs/src/components/simplePaneview.tsx @@ -18,6 +18,7 @@ const components = { {props.params.title}
); +<<<<<<< HEAD }, }; @@ -56,9 +57,51 @@ const headerComponents = { {props.params.title} ); +======= +>>>>>>> 10317206e04a4f043398ef500e0212b34620d804 }, }; +const MyHeaderComponent = (props: IPaneviewPanelProps<{ title: string }>) => { + const [expanded, setExpanded] = React.useState( + props.api.isExpanded + ); + + React.useEffect(() => { + const disposable = props.api.onDidExpansionChange((event) => { + setExpanded(event.isExpanded); + }); + + return () => { + disposable.dispose(); + }; + }, []); + + const onClick = () => { + props.api.setExpanded(!expanded); + }; + + return ( + + ); +}; + +const headerComponents = { + myHeaderComponent: MyHeaderComponent, +}; + export const SimplePaneview = () => { const onReady = (event: PaneviewReadyEvent) => { event.api.addPanel({ diff --git a/packages/dockview-docs/src/components/splitview/active.tsx b/packages/dockview-docs/src/components/splitview/active.tsx new file mode 100644 index 000000000..93ecad8b1 --- /dev/null +++ b/packages/dockview-docs/src/components/splitview/active.tsx @@ -0,0 +1,53 @@ +import { + ISplitviewPanelProps, + Orientation, + SplitviewReact, + SplitviewReadyEvent, +} from 'dockview'; + +const components = { + default: (props: ISplitviewPanelProps<{ title: string }>) => { + return
{props.params.title}
; + }, +}; + +export const SimpleSplitview = (props: { proportional?: boolean }) => { + const onReady = (event: SplitviewReadyEvent) => { + event.api.addPanel({ + id: 'panel_1', + component: 'default', + params: { + title: 'Panel 1', + }, + minimumSize: 100, + }); + + event.api.addPanel({ + id: 'panel_2', + component: 'default', + params: { + title: 'Panel 2', + }, + minimumSize: 100, + }); + + event.api.addPanel({ + id: 'panel_3', + component: 'default', + params: { + title: 'Panel 3', + }, + minimumSize: 100, + }); + }; + + return ( + + ); +}; diff --git a/packages/dockview-docs/src/pages/basics.mdx b/packages/dockview-docs/src/pages/basics.mdx index 59872d4ac..b953f64c2 100644 --- a/packages/dockview-docs/src/pages/basics.mdx +++ b/packages/dockview-docs/src/pages/basics.mdx @@ -8,6 +8,7 @@ This section will take you through a number of concepts that can be applied to a ## Panels The below examples use `ReactSplitview` but the logic holds for `ReactPaneview`, `ReactGridview` and `ReactDockview` using their respective implementations and interfaces. +sAll components require you to provide an `onReady` prop which you can use to build and control your component. ### Adding a panel with parameters @@ -38,7 +39,7 @@ const MyComponent = (props: ISplitviewPanelProps<{ title: string }>) => { There are two types of API you will interact with using `dockview`. - The `panel API` is accessible via `props.api` in user defined panels and via the `.api` variable found on panel instances. This API contains actions and variable related to the the individual panel. -- The `component API` is accessible via `event.api` in the `onReady` events and `props.containerApi` in user defined panels. This API contains actions and variable related to the component as a whole. +- The `container API` is accessible via `event.api` in the `onReady` events and `props.containerApi` in user defined panels. This API contains actions and variable related to the component as a whole. ```tsx const MyComponent = (props: ISplitviewPanelProps<{ title: string }>) => { @@ -75,10 +76,28 @@ All components support `toJSON(): T` which returns a Typed object representation ## Auto resizing `SplitviewReact`, `GridviewReact`, `PaneviewReact` and `DockviewReact` will all automatically resize to fill the size of their parent element. -Internally this is achieved using a [ResizeObserver](https://developer.mozilla.org/en-US/docs/Web/API/ResizeObserver). +Internally this is achieved using a [ResizeObserver](https://developer.mozilla.org/en-US/docs/Web/API/ResizeObserver) which some users may need to polyfill. You can disable this by settings the `disableAutoResizing` prop to be `true`. You can manually resize a component using the API method `layout(width: number, height: number): void`. +An advanced case may use this in conjunction with `disableAutoResizing=true` to allow a parent component to have ultimate control over the dimensions of the component. + +## Events + +Many API properties can be listened on using the `Event` pattern. For example `api.onDidFocusChange(() => {...})`. +You should dispose of any event listeners you create cleaning up any listeners you would have created. + +```tsx +React.useEffect(() => { + const disposable = api.onDidFocusChange(() => { + // write some code + }); + + return () => { + disposable.dispose(); + }; +}, []); +``` ## Proportional layout @@ -88,3 +107,7 @@ Although not configurable on `DockviewReact` and `PaneviewReact` these both beha + +## Browser support + +dockview is intended to support all major browsers. Some users may require a polyfill for [ResizeObserver](https://developer.mozilla.org/en-US/docs/Web/API/ResizeObserver). diff --git a/packages/dockview-docs/src/pages/dockview.mdx b/packages/dockview-docs/src/pages/dockview.mdx index f6e391e35..d48386c7d 100644 --- a/packages/dockview-docs/src/pages/dockview.mdx +++ b/packages/dockview-docs/src/pages/dockview.mdx @@ -1,4 +1,7 @@ import { SimpleDockview } from '../components/simpleDockview'; +import Link from 'next/link'; + +# Dockview Dockview is an abstraction built on top of [Gridviews](/gridview) where each view is a tabbed container. @@ -44,18 +47,18 @@ panel.group.header.hidden = true; import { ReactDockview } from 'dockview'; ``` -| Property | Type | Optional | Default | Description | -| ------------------- | ------------------------------------ | -------- | ------- | ------------------------------------------- | -| onReady | (event: SplitviewReadyEvent) => void | No | | | -| components | object | No | | | -| tabComponents | object | Yes | | | -| watermarkComponent | object | Yes | | | -| hideBorders | boolean | Yes | false | | -| className | string | Yes | '' | | -| disableAutoResizing | boolean | Yes | false | See [Auto resizing](/basics/#auto-resizing) | -| onTabContextMenu | Event | Yes | false | | -| onDidDrop | Event | Yes | false | | -| showDndOverlay | Event | Yes | false | | +| Property | Type | Optional | Default | Description | +| ------------------- | ------------------------------------ | -------- | ------- | ------------------------------------------------------------ | +| onReady | (event: SplitviewReadyEvent) => void | No | | | +| components | object | No | | | +| tabComponents | object | Yes | | | +| watermarkComponent | object | Yes | | | +| hideBorders | boolean | Yes | false | | +| className | string | Yes | '' | | +| disableAutoResizing | boolean | Yes | false | See Auto Resizing | +| onTabContextMenu | Event | Yes | false | | +| onDidDrop | Event | Yes | false | | +| showDndOverlay | Event | Yes | false | | ## Dockview API @@ -73,45 +76,45 @@ const onReady = (event: DockviewReadyEvent) => { }; ``` -| Property | Type | Description | -| ---------------------- | ---------------------------------------------------- | ------------------------------------------- | -| height | `number` | Component pixel height | -| width | `number` | Component pixel width | -| minimumHeight | `number` | | -| maximumHeight | `number` | | -| maximumWidth | `number` | | -| maximumWidth | `number` | | -| length | `number` | Number of panels | -| size | `number` | Number of Groups | -| panels | `IDockviewPanel[]` | | -| groups | `GroupPanel[]` | | -| activePanel | `IDockviewPanel \| undefined` | | -| activeGroup | `IDockviewPanel \| undefined` | | -| | | | -| onDidLayoutChange | `Event` | | -| onDidLayoutFromJSON | `Event` | | -| onDidAddGroup | `Event` | | -| onDidRemoveGroup | `Event` | | -| onDidActiveGroupChange | `Event` | | -| onDidAddPanel | `Event` | | -| onDidRemovePanel | `Event` | | -| onDidActivePanelChange | `Event` | | -| onDidDrop | `Event` | | +| onDidLayoutFromJSON | `Event` | | +| onDidAddGroup | `Event` | | +| onDidRemoveGroup | `Event` | | +| onDidActiveGroupChange | `Event` | | +| onDidAddPanel | `Event` | | +| onDidRemovePanel | `Event` | | +| onDidActivePanelChange | `Event` | | +| onDidDrop | `EventAuto Resizing | +| fromJSON | `(data: SerializedDockview): void` | Serialization | +| toJSON | `(): SerializedDockview` | Serialization | ## Dockview Panel API @@ -134,7 +137,6 @@ const MyComponent = (props: IDockviewPanelProps<{ title: string }>) => { | onDidFocusChange | `Event` | | | onDidVisibilityChange | `Event` | | | onDidActiveChange | `Event` | | -| onFocusEvent | `Event` | | | setActive | `(): void` | | | | | | | onDidConstraintsChange | `onDidConstraintsChange: Event` | | diff --git a/packages/dockview-docs/src/pages/gridview.mdx b/packages/dockview-docs/src/pages/gridview.mdx index bbf5f2c12..b022853ce 100644 --- a/packages/dockview-docs/src/pages/gridview.mdx +++ b/packages/dockview-docs/src/pages/gridview.mdx @@ -1,4 +1,7 @@ import { SimpleGridview } from '../components/simpleGridview'; +import Link from 'next/link'; + +# Gridview
void | No | | | -| components | object | No | | | -| orientation | Orientation | Yes | Orientation.HORIZONTAL | | -| proportionalLayout | boolean | Yes | true | | -| hideBorders | boolean | Yes | false | | -| className | string | Yes | '' | | -| disableAutoResizing | boolean | Yes | false | See [Auto resizing](/basics/#auto-resizing) | +| Property | Type | Optional | Default | Description | +| ------------------- | ------------------------------------ | -------- | ---------------------- | ------------------------------------------------------------------------ | +| onReady | (event: SplitviewReadyEvent) => void | No | | | +| components | object | No | | | +| orientation | Orientation | Yes | Orientation.HORIZONTAL | | +| proportionalLayout | boolean | Yes | true | See Proportional layout | +| hideBorders | boolean | Yes | false | | +| className | string | Yes | '' | | +| disableAutoResizing | boolean | Yes | false | See Auto Resizing | ## Gridview API @@ -43,37 +46,34 @@ const onReady = (event: GridviewReadyEvent) => { }; ``` -| Property | Type | Description | -| ---------------------- | ------------------------------------------------------------------------------------------------- | ------------------------------------------- | -| height | `number` | Component pixel height | -| width | `number` | Component pixel width | -| minimumHeight | `number` | | -| maximumHeight | `number` | | -| maximumWidth | `number` | | -| maximumWidth | `number` | | -| length | `number` | Number of panels | -| panels | `ISplitviewPanel[]` | | -| orientation | `Orientation` | | -| | | | -| onDidLayoutChange | `Event` | | -| onDidLayoutFromJSON | `Event` | | -| onDidAddGroup | `Event` | | -| onDidRemoveGroup | `Event` | | -| onDidActiveGroupChange | `Event` | | -| | | | -| addPanel | `addPanel(options: AddComponentOptions): IGridviewPanel` | | -| removePanel | `(panel: IGridviewPanel, sizing?: Sizing): void` | | -| movePanel | `(panel: IGridviewPanel, options: {direction: Direction, refernece:string, size?: number}): void` | | -| getPanel | `(id: string) \| IGridviewPanel \| undefined` | | -| | | | -| updateOptions | `(options:SplitviewComponentUpdateOptions): void` | | -| setVisible | `(panel: IGridviewPanel, isVisible: boolean): void` | | -| focus | `(): void` | | -| setActive | `(panel: IGridviewPanel): void` | | -| toggleVisiblity | `(panel: IGridviewPanel): void` | | -| layout | `(width: number, height:number): void` | See [Auto resizing](/basics/#auto-resizing) | -| fromJSON | `(data: SerializedGridview): void` | See [Serialization](/basics/#serialization) | -| toJSON | `(): SerializedGridview` | See [Serialization](/basics/#serialization) | +| Property | Type | Description | +| ---------------------- | ------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------- | +| height | `number` | Component pixel height | +| width | `number` | Component pixel width | +| minimumHeight | `number` | | +| maximumHeight | `number` | | +| maximumWidth | `number` | | +| maximumWidth | `number` | | +| length | `number` | Number of panels | +| panels | `ISplitviewPanel[]` | all panels | +| orientation | `Orientation` | | +| | | | +| onDidLayoutChange | `Event` | Fires on layout change | +| onDidLayoutFromJSON | `Event` | Fires of layout change caused by a fromJSON deserialization call | +| onDidAddPanel | `Event` | Fires when a view is added | +| onDidRemovePanel | `Event` | Fires when a view is removed | +| onDidActivePanelChange | `Event` | Fires when the active group changes | +| | | | +| addPanel | `addPanel(options: AddComponentOptions): IGridviewPanel` | | +| removePanel | `(panel: IGridviewPanel, sizing?: Sizing): void` | | +| movePanel | `(panel: IGridviewPanel, options: {direction: Direction, refernece:string, size?: number}): void` | | +| getPanel | `(id: string) \| IGridviewPanel \| undefined` | | +| | | | +| updateOptions | `(options:SplitviewComponentUpdateOptions): void` | | +| focus | `(): void` | Focus the active panel, if exists | +| layout | `(width: number, height:number): void` | Auto Resizing | +| fromJSON | `(data: SerializedGridview): void` | Serialization | +| toJSON | `(): SerializedGridview` | Serialization | ## Gridview Panel API @@ -98,7 +98,6 @@ const MyComponent = (props: IGridviewPanelProps<{ title: string }>) => { | onDidFocusChange | `Event` | | | onDidVisibilityChange | `Event` | | | onDidActiveChange | `Event` | | -| onFocusEvent | `Event` | | | onDidConstraintsChange | `onDidConstraintsChange: Event` | | | | | | | setVisible | `(isVisible: boolean): void` | | diff --git a/packages/dockview-docs/src/pages/paneview.mdx b/packages/dockview-docs/src/pages/paneview.mdx index 6505a840b..bc854d7ee 100644 --- a/packages/dockview-docs/src/pages/paneview.mdx +++ b/packages/dockview-docs/src/pages/paneview.mdx @@ -1,4 +1,7 @@ import { SimplePaneview } from '../components/simplePaneview'; +import Link from 'next/link'; + +# Paneview
void | No | | | -| components | object | No | | | -| headerComponents | object | Yes | | | -| className | string | Yes | '' | | -| disableAutoResizing | boolean | Yes | false | See [Auto resizing](/basics/#auto-resizing) | -| disableDnd | boolean | Yes | false | | -| onDidDrop | Event | Yes | | | +| Property | Type | Optional | Default | Description | +| ------------------- | ------------------------------------ | -------- | ------- | -------------------------------------------------------- | +| onReady | (event: SplitviewReadyEvent) => void | No | | | +| components | object | No | | | +| headerComponents | object | Yes | | | +| className | string | Yes | '' | | +| disableAutoResizing | boolean | Yes | false | Auto Resizing | +| disableDnd | boolean | Yes | false | | +| onDidDrop | Event | Yes | | | + +## Custom Header + +The above example shows the default header and will render the `title` along with a small icon to indicate a collapsed or expanded state. +You can provide a custom header: + +```tsx +const onReady = (event: PaneviewReadyEvent) => { + event.api.addPanel({ + id: 'panel_1', + component: 'default', + headerComponent: 'myHeaderComponent', + params: { + valueA: 'A', + }, + title: 'Panel 1', + }); +}; +``` ## Custom Header @@ -102,30 +124,30 @@ const onReady = (event: GridviewReadyEvent) => { }; ``` -| Property | Type | Description | -| ------------------- | ---------------------------------------------------------------- | ------------------------------------------- | -| height | `number` | Component pixel height | -| width | `number` | Component pixel width | -| minimumSize | `number` | | -| maximumSize | `number` | | -| length | `number` | Number of panels | -| panels | `IPaneviewPanel[]` | | -| | | | -| onDidLayoutChange | `Event` | | -| onDidLayoutFromJSON | `Event` | | -| onDidAddView | `Event` | | -| onDidRemoveView | `Event` | | -| onDidDrop | `Event` | Fires on layout change | +| onDidLayoutFromJSON | `Event` | Fires of layout change caused by a fromJSON deserialization call | +| onDidAddView | `Event` | Fires when a view is added | +| onDidRemoveView | `Event` | Fires when a view is removed | +| onDidDrop | `EventDrag and Drop) | +| | | | +| addPanel | `addPanel(options: AddPaneviewComponentOptions): IPaneviewPanel` | | +| removePanel | `(panel: IPaneviewPanel): void` | | +| movePanel | `(from: number, to: number): void` | | +| getPanel | `(id:string): IPaneviewPanel \| undefined` | | +| | | | +| focus | `(): void` | Focus the active panel, if exists | +| layout | `(width: number, height:number): void` | See Auto Resizing | +| fromJSON | `(data: SerializedPaneview): void` | Serialization | +| toJSON | `(): SerializedPaneview` | Serialization | ## Gridview Panel API @@ -150,10 +172,11 @@ const MyComponent = (props: IGridviewPanelProps<{ title: string }>) => { | onDidFocusChange | `Event` | | | onDidVisibilityChange | `Event` | | | onDidActiveChange | `Event` | | -| onFocusEvent | `Event` | | | onDidConstraintsChange | `onDidConstraintsChange: Event` | | | | | | setVisible | `(isVisible: boolean): void` | | | setActive | `(): void` | | | setConstraints | `(value: PanelConstraintChangeEvent2): void;` | | | setSize | `(event: SizeEvent): void` | | + +# Drag And Drop diff --git a/packages/dockview-docs/src/pages/splitview.mdx b/packages/dockview-docs/src/pages/splitview.mdx index 96bd5dfeb..de241e9fd 100644 --- a/packages/dockview-docs/src/pages/splitview.mdx +++ b/packages/dockview-docs/src/pages/splitview.mdx @@ -1,4 +1,5 @@ import { SimpleSplitview } from '../components/simpleSplitview'; +import Link from 'next/link'; # Splitview @@ -73,15 +74,15 @@ import { ReactSplitview } from 'dockview'; The `onReady` prop you will you access to the component `api`. -| Property | Type | Optional | Default | Description | -| ------------------- | -------------------------------------- | -------- | ------------------------ | ------------------------------------------------------- | -| onReady | `(event: SplitviewReadyEvent) => void` | No | | | -| components | `Record` | No | | Panel renderers | -| orientation | `Orientation` | Yes | `Orientation.HORIZONTAL` | Orientation of the Splitview | -| proportionalLayout | `boolean` | Yes | `true` | See [Proportional layout](/basics/#proportional-layout) | -| hideBorders | `boolean` | Yes | `false` | Hide the borders between panels | -| className | `string` | Yes | `''` | Attaches a classname | -| disableAutoResizing | `boolean` | Yes | `false` | See [Auto resizing](/basics/#auto-resizing) | +| Property | Type | Optional | Default | Description | +| ------------------- | -------------------------------------- | -------- | ------------------------ | ------------------------------------------------------------------------ | +| onReady | `(event: SplitviewReadyEvent) => void` | No | | | +| components | `Record` | No | | Panel renderers | +| orientation | `Orientation` | Yes | `Orientation.HORIZONTAL` | Orientation of the Splitview | +| proportionalLayout | `boolean` | Yes | `true` | See Proportional layout | +| hideBorders | `boolean` | Yes | `false` | Hide the borders between panels | +| className | `string` | Yes | `''` | Attaches a classname | +| disableAutoResizing | `boolean` | Yes | `false` | See Auto Resizing | ## Splitview API @@ -99,32 +100,30 @@ const onReady = (event: SplitviewReadyEvent) => { }; ``` -| Property | Type | Description | -| ------------------- | ------------------------------------------------------------------ | ------------------------------------------- | -| height | `number` | Component pixel height | -| width | `number` | Component pixel width | -| minimumSize | `number` | | -| maximumSize | `number` | | -| length | `number` | Number of panels | -| panels | `ISplitviewPanel[]` | | -| | | | -| onDidLayoutChange | `Event` | | -| onDidLayoutFromJSON | `Event` | | -| onDidAddView | `Event` | | -| onDidRemoveView | `Event` | | -| | | | -| addPanel | `addPanel(options: AddSplitviewComponentOptions): ISplitviewPanel` | | -| removePanel | `(panel: ISplitviewPanel, sizing?: Sizing): void` | | -| getPanel | `(id:string): ISplitviewPanel \| undefined` | | -| movePanel | `(from: number, to: number): void` | | +| Property | Type | Description | +| ------------------- | ------------------------------------------------------------------ | ---------------------------------------------------------------- | +| height | `number` | Component pixel height | +| width | `number` | Component pixel width | +| minimumSize | `number` | The sum of the `minimumSize` property for each panel | +| maximumSize | `number` | The sum of the `maximumSize` property for each panel | +| length | `number` | Number of panels | +| panels | `ISplitviewPanel[]` | All panels | +| | | | +| onDidLayoutChange | `Event` | Fires on layout change | +| onDidLayoutFromJSON | `Event` | Fires of layout change caused by a fromJSON deserialization call | +| onDidAddView | `Event` | Fires when a view is added | +| onDidRemoveView | `Event` | Fires when a view is removed | +| | | | +| addPanel | `addPanel(options: AddSplitviewComponentOptions): ISplitviewPanel` | | +| removePanel | `(panel: ISplitviewPanel, sizing?: Sizing): void` | | +| getPanel | `(id:string): ISplitviewPanel \| undefined` | | +| movePanel | `(from: number, to: number): void` | | | | | -| setVisible | `(panel: ISplitviewPanel, isVisible: boolean): void` | | -| setActive | `(panel: ISplitviewPanel): void` | | -| updateOptions | `(options:SplitviewComponentUpdateOptions): void` | | -| focus | `(): void` | | -| layout | `(width: number, height:number): void` | See [Auto resizing](/basics/#auto-resizing) | -| fromJSON | `(data: SerializedSplitview): void` | See [Serialization](/basics/#serialization) | -| toJSON | `(): SerializedSplitview` | See [Serialization](/basics/#serialization) | +| updateOptions | `(options:SplitviewComponentUpdateOptions): void` | | +| focus | `(): void` | Focus the active panel, if exists | +| layout | `(width: number, height:number): void` | See Auto Resizing | +| fromJSON | `(data: SerializedSplitview): void` | Serialization | +| toJSON | `(): SerializedSplitview` | Serialization | ## Splitview Panel API @@ -136,24 +135,79 @@ const MyComponent = (props: ISplitviewPanelProps<{ title: string }>) => { }; ``` -| Property | Type | Description | -| ---------------------- | ----------------------------------------------------------- | ---------------- | -| id | `string` | Panel id | -| isFocused | `boolean` | Is panel focsed | -| isActive | `boolean` | Is panel active | -| isVisible | `boolean` | Is panel visible | -| width | `number` | Panel width | -| height | `number` | Panel height | -| | | -| onDidDimensionsChange | `Event` | | -| onDidFocusChange | `Event` | | -| onDidVisibilityChange | `Event` | | -| onDidActiveChange | `Event` | | -| onFocusEvent | `Event` | | -| onDidConstraintsChange | `onDidConstraintsChange: Event` | | -| | | | -| setVisible | `(isVisible: boolean): void` | | -| setActive | `(): void` | | -| | | | -| setConstraints | `(value: PanelConstraintChangeEvent2): void;` | | -| setSize | `(event: PanelSizeEvent): void` | | +| Property | Type | Description | +| ---------------------- | ----------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------- | +| id | `string` | Panel id | +| isFocused | `boolean` | Is panel focsed | +| isActive | `boolean` | Is panel active | +| isVisible | `boolean` | Is panel visible | +| width | `number` | Panel width | +| height | `number` | Panel height | +| | | | +| onDidDimensionsChange | `Event` | Fires when panel dimensions change | +| onDidFocusChange | `Event` | Fire when panel is focused and blurred | +| onDidVisibilityChange | `Event` | Fires when the panels visiblity property is changed (see Panel Visibility) | +| onDidActiveChange | `Event` | Fires when the panels active property is changed (see Active Panel) | +| onDidConstraintsChange | `onDidConstraintsChange: Event` | Fires when the panels size contrainsts change (see Panel Constraints) | +| | | | +| setVisible | `(isVisible: boolean): void` | | +| setActive | `(): void` | | +| | | | +| setConstraints | `(value: PanelConstraintChangeEvent2): void;` | | +| setSize | `(event: PanelSizeEvent): void` | | + +# Visibility + +```tsx +const disposable = props.api.onDidVisibilityChange(({ isVisible }) => { + // +}); +``` + +```tsx +api.setVisible(true); +``` + +# Active + +Only one panel in the `splitview` can be the active panel at any one time. +Setting a panel as active will set all the others as inactive. +A focused panel is always the active panel but an active panel is not always focused. + +```tsx +const disposable = props.api.onDidActiveChange(({ isActive }) => { + // +}); +``` + +```tsx +api.setActive(); +``` + +# Contraints + +When adding a panel you can specify pixel size contraints + +```tsx +event.api.addPanel({ + id: 'panel_3', + component: 'default', + minimumSize: 100, + maximumSize: 1000, +}); +``` + +These contraints can be updated throughout the lifecycle of the `splitview` using the panel API + +```tsx +props.api.onDidConstraintsChange(({ maximumSize, minimumSize }) => { + // +}); +``` + +```tsx +api.setConstraints({ + maximumSize: 200, + minimumSize: 400, +}); +``` diff --git a/packages/dockview-docs/src/pages/theme.mdx b/packages/dockview-docs/src/pages/theme.mdx new file mode 100644 index 000000000..7f5a1479a --- /dev/null +++ b/packages/dockview-docs/src/pages/theme.mdx @@ -0,0 +1,72 @@ +import { CustomCSSDockview } from '../components/dockview/customCss'; + +# Theme + +`dockview` requires some css to work correctly. +The css is exported as one file under [`dockview/dict/styles/dockview.css`](https://unpkg.com/browse/dockview@latest/dist/styles/dockview.css) +and depending can be imported + +```css +@import './node_modules/dockview/dist/styles/dockview.css'; +``` + +`dockview` supports theming through the use of css properties. +You can view the built-in themes at [`dockview/src/theme.scss`](https://github.com/mathuo/dockview/blob/master/packages/dockview/src/theme.scss) +and are free to build your own themes based on these css properties. + +| CSS Property | Description | +| ---------------------------------------------------- | ----------- | +| --dv-paneview-active-outline-color | | +| --dv-tabs-and-actions-container-font-size | | +| --dv-tabs-and-actions-container-height | | +| --dv-tab-close-icon | | +| --dv-drag-over-background-color | | +| --dv-drag-over-border-color | | +| --dv-tabs-container-scrollbar-color | | +| | | +| --dv-group-view-background-color | | +| | | +| --dv-tabs-and-actions-container-background-color | | +| | | +| --dv-activegroup-visiblepanel-tab-background-color | | +| --dv-activegroup-hiddenpanel-tab-background-color | | +| --dv-inactivegroup-visiblepanel-tab-background-color | | +| --dv-inactivegroup-hiddenpanel-tab-background-color | | +| --dv-tab-divider-color | | +| | | +| --dv-activegroup-visiblepanel-tab-color | | +| --dv-activegroup-hiddenpanel-tab-color | | +| --dv-inactivegroup-visiblepanel-tab-color | | +| --dv-inactivegroup-hiddenpanel-tab-color | | +| | | +| --dv-separator-border | | +| --dv-paneview-header-border-color | | + +You can further customise the theme through adjusting class properties but this is up you. +As an example if you wanted to add a bottom border to the tab container for an active group in the `DockviewReact` component you could write: + +```css +.groupview { + &.active-group { + > .tabs-and-actions-container { + border-bottom: 2px solid var(--dv-activegroup-visiblepanel-tab-background-color); + } + } + &.inactive-group { + > .tabs-and-actions-container { + border-bottom: 2px solid var(--dv-inactivegroup-visiblepanel-tab-background-color); + } + } +} +``` + +
+ +
diff --git a/packages/dockview-docs/src/references/pages.ts b/packages/dockview-docs/src/references/pages.ts index ff4ddefee..6503f875a 100644 --- a/packages/dockview-docs/src/references/pages.ts +++ b/packages/dockview-docs/src/references/pages.ts @@ -7,6 +7,7 @@ export interface Page { export const PAGES: Page[] = [ { title: 'Introduction', url: '/#introduction' }, { title: 'Basics', url: '/basics/#basics' }, + { title: 'Theme', url: '/theme/#theme' }, { title: 'API', url: '#api', diff --git a/packages/dockview/README.md b/packages/dockview/README.md index 554188d93..6d529b68a 100644 --- a/packages/dockview/README.md +++ b/packages/dockview/README.md @@ -124,31 +124,6 @@ const Component = () => { }; ``` -Specifically for `DockviewReact` there exists higher-order components to encapsulate both the tab and contents into one logical component for the user making state sharing between the two simple, which is an optional feature. - -```tsx -const components: PanelCollection = { - default: (props: IDockviewPanelProps<{ someProps: string }>) => { - return
{props.params.someProps}
; - }, - fancy: (props: IDockviewPanelProps) => { - return ( - - -
- {props.api.title} - props.api.close()}>{'Close'} -
-
- -
{'Hello world'}
-
-
- ); - }, -}; -``` - ## Sandbox examples - [Dockview](https://codesandbox.io/s/simple-dockview-t6491) diff --git a/packages/dockview/src/__tests__/api/api.spec.ts b/packages/dockview/src/__tests__/api/api.spec.ts index 647ff98c4..10f9bc657 100644 --- a/packages/dockview/src/__tests__/api/api.spec.ts +++ b/packages/dockview/src/__tests__/api/api.spec.ts @@ -41,11 +41,11 @@ describe('api', () => { expect(api.height).toBe(0); expect(api.width).toBe(0); - api._onDidPanelDimensionChange.fire({ height: 10, width: 20 }); + api._onDidDimensionChange.fire({ height: 10, width: 20 }); expect(api.height).toBe(10); expect(api.width).toBe(20); - api._onDidPanelDimensionChange.fire({ height: 20, width: 10 }); + api._onDidDimensionChange.fire({ height: 20, width: 10 }); expect(api.height).toBe(20); expect(api.width).toBe(10); }); diff --git a/packages/dockview/src/api/component.api.ts b/packages/dockview/src/api/component.api.ts index 034b3b946..00adb0c7f 100644 --- a/packages/dockview/src/api/component.api.ts +++ b/packages/dockview/src/api/component.api.ts @@ -100,10 +100,6 @@ export class SplitviewApi implements CommonApi { this.component.removePanel(panel, sizing); } - setVisible(panel: ISplitviewPanel, isVisible: boolean): void { - this.component.setVisible(panel, isVisible); - } - focus(): void { this.component.focus(); } @@ -112,10 +108,6 @@ export class SplitviewApi implements CommonApi { return this.component.getPanel(id); } - setActive(panel: ISplitviewPanel): void { - this.component.setActive(panel); - } - layout(width: number, height: number): void { return this.component.layout(width, height); } @@ -310,18 +302,6 @@ export class GridviewApi implements CommonApi { return this.component.getPanel(id); } - toggleVisibility(panel: IGridviewPanel): void { - this.component.toggleVisibility(panel); - } - - setVisible(panel: IGridviewPanel, visible: boolean): void { - this.component.setVisible(panel, visible); - } - - setActive(panel: IGridviewPanel): void { - this.component.setActive(panel); - } - fromJSON(data: SerializedGridview): void { return this.component.fromJSON(data); } diff --git a/packages/dockview/src/api/panelApi.ts b/packages/dockview/src/api/panelApi.ts index 88e657531..1b16d9195 100644 --- a/packages/dockview/src/api/panelApi.ts +++ b/packages/dockview/src/api/panelApi.ts @@ -23,8 +23,6 @@ export interface PanelApi { readonly onDidFocusChange: Event; readonly onDidVisibilityChange: Event; readonly onDidActiveChange: Event; - readonly onFocusEvent: Event; - // setVisible(isVisible: boolean): void; setActive(): void; /** @@ -63,11 +61,10 @@ export class PanelApiImpl extends CompositeDisposable implements PanelApi { private _width = 0; private _height = 0; - readonly _onDidPanelDimensionChange = - new Emitter({ - replay: true, - }); - readonly onDidDimensionsChange = this._onDidPanelDimensionChange.event; + readonly _onDidDimensionChange = new Emitter({ + replay: true, + }); + readonly onDidDimensionsChange = this._onDidDimensionChange.event; // readonly _onDidChangeFocus = new Emitter({ replay: true, @@ -121,7 +118,7 @@ export class PanelApiImpl extends CompositeDisposable implements PanelApi { super(); this.addDisposables( - this._onDidPanelDimensionChange, + this._onDidDimensionChange, this._onDidChangeFocus, this._onDidVisibilityChange, this._onDidActiveChange, diff --git a/packages/dockview/src/dockview/components/tab/defaultTab.ts b/packages/dockview/src/dockview/components/tab/defaultTab.ts index 89888da2a..19d0b06be 100644 --- a/packages/dockview/src/dockview/components/tab/defaultTab.ts +++ b/packages/dockview/src/dockview/components/tab/defaultTab.ts @@ -7,67 +7,6 @@ import { addDisposableListener } from '../../../events'; import { PanelUpdateEvent } from '../../../panel/types'; import { GroupPanel } from '../../../groupview/groupviewPanel'; -export class WrappedTab implements ITabRenderer { - private readonly _element: HTMLElement; - - constructor(private readonly renderer: ITabRenderer) { - this._element = document.createElement('element'); - this.show(); - } - - get innerRenderer() { - return this.renderer; - } - - get element() { - return this._element; - } - - get id() { - return this.renderer.id; - } - - show() { - if (!this.renderer.element.parentElement) { - this._element.appendChild(this.renderer.element); - } - } - - hide() { - if (this.renderer.element.parentElement) { - this.renderer.element.remove(); - } - } - - layout(width: number, height: number): void { - this.renderer.layout(width, height); - } - - update(event: PanelUpdateEvent): void { - this.renderer.update(event); - } - - toJSON(): object { - return this.renderer.toJSON(); - } - - focus(): void { - this.renderer.focus(); - } - - init(parameters: GroupPanelPartInitParameters): void { - this.renderer.init(parameters); - } - - updateParentGroup(group: GroupPanel, isPanelVisible: boolean): void { - this.renderer.updateParentGroup(group, isPanelVisible); - } - - dispose() { - this.renderer.dispose(); - } -} - export class DefaultTab extends CompositeDisposable implements ITabRenderer { private _element: HTMLElement; @@ -148,10 +87,16 @@ export class DefaultTab extends CompositeDisposable implements ITabRenderer { } public updateParentGroup(group: GroupPanel, isPanelVisible: boolean) { + const changed = + this._isPanelVisible !== isPanelVisible || + this._isGroupActive !== group.isActive; + this._isPanelVisible = isPanelVisible; this._isGroupActive = group.isActive; - this.render(); + if (changed) { + this.render(); + } } public layout(_width: number, _height: number) { @@ -159,6 +104,8 @@ export class DefaultTab extends CompositeDisposable implements ITabRenderer { } private render() { - this._content.textContent = this.params.title; + if (this._content.textContent !== this.params.title) { + this._content.textContent = this.params.title; + } } } diff --git a/packages/dockview/src/dockview/defaultGroupPanelView.ts b/packages/dockview/src/dockview/defaultGroupPanelView.ts index dac5eec02..c59190758 100644 --- a/packages/dockview/src/dockview/defaultGroupPanelView.ts +++ b/packages/dockview/src/dockview/defaultGroupPanelView.ts @@ -1,4 +1,4 @@ -import { DefaultTab, WrappedTab } from './components/tab/defaultTab'; +import { DefaultTab } from './components/tab/defaultTab'; import { GroupPanelPartInitParameters, IActionsRenderer, @@ -22,7 +22,7 @@ export interface IGroupPanelView extends IDisposable { export class DefaultGroupPanelView implements IGroupPanelView { private readonly _content: IContentRenderer; - private readonly _tab: WrappedTab; + private readonly _tab: ITabRenderer; private readonly _actions: IActionsRenderer | undefined; get content() { @@ -43,7 +43,7 @@ export class DefaultGroupPanelView implements IGroupPanelView { actions?: IActionsRenderer; }) { this._content = renderers.content; - this._tab = new WrappedTab(renderers.tab ?? new DefaultTab()); + this._tab = renderers.tab ?? new DefaultTab(); this._actions = renderers.actions || (this.content.actions @@ -78,10 +78,7 @@ export class DefaultGroupPanelView implements IGroupPanelView { toJSON(): {} { return { content: this.content.toJSON(), - tab: - this.tab.innerRenderer instanceof DefaultTab - ? undefined - : this.tab.toJSON(), + tab: this.tab instanceof DefaultTab ? undefined : this.tab.toJSON(), }; } diff --git a/packages/dockview/src/dockview/dockviewComponent.ts b/packages/dockview/src/dockview/dockviewComponent.ts index 48efdad29..91f5dc6d5 100644 --- a/packages/dockview/src/dockview/dockviewComponent.ts +++ b/packages/dockview/src/dockview/dockviewComponent.ts @@ -669,7 +669,7 @@ export class DockviewComponent } const view = new GroupPanel(this, id, options); - view.init({ params: {}, containerApi: null }); // required to initialized .part and allow for correct disposal of group + view.init({ params: {}, accessor: null }); // required to initialized .part and allow for correct disposal of group if (!this._groups.has(view.id)) { const disposable = new CompositeDisposable( diff --git a/packages/dockview/src/dockview/dockviewGroupPanel.ts b/packages/dockview/src/dockview/dockviewGroupPanel.ts index 5150cd736..b7d44229e 100644 --- a/packages/dockview/src/dockview/dockviewGroupPanel.ts +++ b/packages/dockview/src/dockview/dockviewGroupPanel.ts @@ -169,7 +169,7 @@ export class DockviewGroupPanel public layout(width: number, height: number) { // the obtain the correct dimensions of the content panel we must deduct the tab height - this.api._onDidPanelDimensionChange.fire({ + this.api._onDidDimensionChange.fire({ width, height: height - (this.group.model.header.height || 0), }); diff --git a/packages/dockview/src/gridview/basePanelView.ts b/packages/dockview/src/gridview/basePanelView.ts index f6e5f7567..61445fa21 100644 --- a/packages/dockview/src/gridview/basePanelView.ts +++ b/packages/dockview/src/gridview/basePanelView.ts @@ -90,7 +90,7 @@ export abstract class BasePanelView layout(width: number, height: number) { this._width = width; this._height = height; - this.api._onDidPanelDimensionChange.fire({ width, height }); + this.api._onDidDimensionChange.fire({ width, height }); if (this.part) { if (this._params) { diff --git a/packages/dockview/src/gridview/gridviewComponent.ts b/packages/dockview/src/gridview/gridviewComponent.ts index e7413925c..7738f6158 100644 --- a/packages/dockview/src/gridview/gridviewComponent.ts +++ b/packages/dockview/src/gridview/gridviewComponent.ts @@ -22,7 +22,6 @@ import { IGridviewPanel, } from './gridviewPanel'; import { BaseComponentOptions } from '../panel/types'; -import { GridviewApi } from '../api/component.api'; import { Orientation, Sizing } from '../splitview/core/splitview'; import { createComponent } from '../panel/componentFactory'; import { Emitter, Event } from '../events'; @@ -64,7 +63,6 @@ export interface IGridviewComponent extends IBaseGrid { updateOptions(options: Partial): void; addPanel(options: AddComponentOptions): IGridviewPanel; removePanel(panel: IGridviewPanel, sizing?: Sizing): void; - toggleVisibility(panel: IGridviewPanel): void; focus(): void; fromJSON(serializedGridview: SerializedGridview): void; toJSON(): SerializedGridview; @@ -170,10 +168,6 @@ export class GridviewComponent }); } - toggleVisibility(panel: GridviewPanel) { - this.setVisible(panel, !this.isVisible(panel)); - } - focus() { this.activeGroup?.focus(); } @@ -217,7 +211,7 @@ export class GridviewComponent maximumHeight: data.maximumHeight, priority: data.priority, snap: !!data.snap, - containerApi: new GridviewApi(this), + accessor: this, isVisible: node.visible, }) ); @@ -322,7 +316,7 @@ export class GridviewComponent maximumHeight: options.maximumHeight, priority: options.priority, snap: !!options.snap, - containerApi: new GridviewApi(this), + accessor: this, isVisible: true, }); diff --git a/packages/dockview/src/gridview/gridviewPanel.ts b/packages/dockview/src/gridview/gridviewPanel.ts index 8d49c8cd9..fbdfc6575 100644 --- a/packages/dockview/src/gridview/gridviewPanel.ts +++ b/packages/dockview/src/gridview/gridviewPanel.ts @@ -1,5 +1,8 @@ import { PanelInitParameters } from '../panel/types'; -import { IGridPanelComponentView } from './gridviewComponent'; +import { + GridviewComponent, + IGridPanelComponentView, +} from './gridviewComponent'; import { FunctionOrValue } from '../types'; import { BasePanelView, @@ -10,7 +13,6 @@ import { GridviewPanelApiImpl } from '../api/gridviewPanelApi'; import { LayoutPriority } from '../splitview/core/splitview'; import { Emitter, Event } from '../events'; import { IViewSize } from './gridview'; -import { GridviewApi } from '../api/component.api'; export interface GridviewInitParameters extends PanelInitParameters { minimumWidth?: number; @@ -19,7 +21,7 @@ export interface GridviewInitParameters extends PanelInitParameters { maximumHeight?: number; priority?: LayoutPriority; snap?: boolean; - containerApi: GridviewApi; + accessor: GridviewComponent; isVisible?: boolean; } @@ -132,12 +134,12 @@ export abstract class GridviewPanel this._onDidChange, this.api.onVisibilityChange((event) => { const { isVisible } = event; - const { containerApi } = this._params as GridviewInitParameters; - containerApi.setVisible(this, isVisible); + const { accessor } = this._params as GridviewInitParameters; + accessor.setVisible(this, isVisible); }), this.api.onActiveChange(() => { - const { containerApi } = this._params as GridviewInitParameters; - containerApi.setActive(this); + const { accessor } = this._params as GridviewInitParameters; + accessor.setActive(this); }), this.api.onDidConstraintsChangeInternal((event) => { if ( diff --git a/packages/dockview/src/groupview/types.ts b/packages/dockview/src/groupview/types.ts index 32e6917c7..4c50bfc72 100644 --- a/packages/dockview/src/groupview/types.ts +++ b/packages/dockview/src/groupview/types.ts @@ -5,7 +5,6 @@ import { PanelInitParameters, IPanel } from '../panel/types'; import { DockviewApi } from '../api/component.api'; import { GroupPanel } from './groupviewPanel'; import { Event } from '../events'; -import { WrappedTab } from '../dockview/components/tab/defaultTab'; export interface IRenderable { id: string; @@ -28,7 +27,7 @@ export interface GroupPanelPartInitParameters export interface GroupPanelContentPartInitParameters extends GroupPanelPartInitParameters { - tab: WrappedTab; + tab: ITabRenderer; } export interface IWatermarkRenderer extends IPanel { @@ -54,7 +53,6 @@ export interface IContentRenderer extends IPanel { readonly onDidBlur?: Event; updateParentGroup(group: GroupPanel, isPanelVisible: boolean): void; init(parameters: GroupPanelContentPartInitParameters): void; - close?(): Promise; } // watermark component diff --git a/packages/dockview/src/react/dockview/components.tsx b/packages/dockview/src/react/dockview/components.tsx deleted file mode 100644 index 8f382ab58..000000000 --- a/packages/dockview/src/react/dockview/components.tsx +++ /dev/null @@ -1,89 +0,0 @@ -import * as React from 'react'; -import * as ReactDOM from 'react-dom'; -import { isReactElement, ReactPartContext } from '../react'; -import { ReactContentPartContext } from './reactContentPart'; - -interface WithChildren { - children: React.ReactNode; -} - -const Tab: React.FunctionComponent = (props: WithChildren) => { - return <>{props.children}; -}; - -const Content: React.FunctionComponent = ( - props: WithChildren -) => { - return <>{props.children}; -}; -const Actions: React.FunctionComponent = ( - props: WithChildren -) => { - return <>{props.children}; -}; - -function isValidComponent(element: React.ReactElement) { - return [Content, Actions, Tab].find((comp) => element.type === comp); -} - -const Panel: React.FunctionComponent = (props: WithChildren) => { - const context = React.useContext( - ReactPartContext - ) as ReactContentPartContext; - - const sections = React.useMemo(() => { - const childs = - React.Children.map(props.children, (_) => _)?.filter( - isReactElement - ) || []; - - const isInvalid = !!childs.find((_) => !isValidComponent(_)); - - if (isInvalid) { - throw new Error( - 'Children of DockviewComponents.Panel must be one of the following: DockviewComponents.Content, DockviewComponents.Actions, DockviewComponents.Tab' - ); - } - - const body = childs.find((_) => _.type === Content); - const actions = childs.find((_) => _.type === Actions); - const tab = childs.find((_) => _.type === Tab); - - return { body, actions, tab }; - }, [props.children]); - - React.useEffect(() => { - /** - * hide or show the default tab behavior based on whether we want to override - * with our own React tab. - */ - if (sections.tab) { - context.tabPortalElement.hide(); - } else { - context.tabPortalElement.show(); - } - }, [sections.tab]); - - return ( - <> - {sections.actions && - ReactDOM.createPortal( - sections.actions, - context.actionsPortalElement - )} - {sections.tab && - ReactDOM.createPortal( - sections.tab, - context.tabPortalElement.element - )} - {sections.body || props.children} - - ); -}; - -export const DockviewComponents = { - Tab, - Content, - Actions, - Panel, -}; diff --git a/packages/dockview/src/react/dockview/reactContentPart.ts b/packages/dockview/src/react/dockview/reactContentPart.ts index 319000fe7..07d4036cb 100644 --- a/packages/dockview/src/react/dockview/reactContentPart.ts +++ b/packages/dockview/src/react/dockview/reactContentPart.ts @@ -2,6 +2,7 @@ import * as React from 'react'; import { IContentRenderer, GroupPanelContentPartInitParameters, + ITabRenderer, } from '../../groupview/types'; import { ReactPart, ReactPortalStore } from '../react'; import { IDockviewPanelProps } from '../dockview/dockview'; @@ -10,7 +11,6 @@ import { DockviewPanelApi } from '../../api/groupPanelApi'; import { DockviewApi } from '../../api/component.api'; import { GroupPanel } from '../../groupview/groupviewPanel'; import { Emitter, Event } from '../../events'; -import { WrappedTab } from '../../dockview/components/tab/defaultTab'; export interface IGroupPanelActionbarProps { api: DockviewPanelApi; @@ -21,7 +21,7 @@ export interface ReactContentPartContext { api: DockviewPanelApi; containerApi: DockviewApi; actionsPortalElement: HTMLElement; - tabPortalElement: WrappedTab; + tabPortalElement: ITabRenderer; } export class ReactPanelContentPart implements IContentRenderer { @@ -104,10 +104,6 @@ export class ReactPanelContentPart implements IContentRenderer { // noop } - public close(): Promise { - return Promise.resolve(true); - } - public dispose() { this._onDidFocus.dispose(); this._onDidBlur.dispose(); diff --git a/packages/dockview/src/react/dockview/v2/reactContentRenderer.ts b/packages/dockview/src/react/dockview/v2/reactContentRenderer.ts index 90fbd2af2..83f693b80 100644 --- a/packages/dockview/src/react/dockview/v2/reactContentRenderer.ts +++ b/packages/dockview/src/react/dockview/v2/reactContentRenderer.ts @@ -99,10 +99,6 @@ export class ReactContentRenderer implements IContentRenderer { this._hostedContainer.layout(this.element); } - public close(): Promise { - return Promise.resolve(true); - } - public dispose() { this.part?.dispose(); } diff --git a/packages/dockview/src/react/gridview/view.ts b/packages/dockview/src/react/gridview/view.ts index 9fa0f2446..417734f33 100644 --- a/packages/dockview/src/react/gridview/view.ts +++ b/packages/dockview/src/react/gridview/view.ts @@ -1,3 +1,4 @@ +import { GridviewApi } from '../../api/component.api'; import { GridviewPanel, GridviewInitParameters, @@ -24,8 +25,9 @@ export class ReactGridPanelView extends GridviewPanel { { params: this._params?.params || {}, api: this.api, - containerApi: (this._params as GridviewInitParameters) - .containerApi, + containerApi: new GridviewApi( + (this._params as GridviewInitParameters).accessor + ), } ); } diff --git a/packages/dockview/src/react/index.ts b/packages/dockview/src/react/index.ts index 05705fbdd..023167a96 100644 --- a/packages/dockview/src/react/index.ts +++ b/packages/dockview/src/react/index.ts @@ -1,5 +1,4 @@ export * from './dockview/dockview'; -export * from './dockview/components'; export * from './splitview/splitview'; export * from './gridview/gridview'; export * from './dockview/reactContentPart'; diff --git a/packages/dockview/src/react/splitview/view.ts b/packages/dockview/src/react/splitview/view.ts index 3f427da2d..9c7c66450 100644 --- a/packages/dockview/src/react/splitview/view.ts +++ b/packages/dockview/src/react/splitview/view.ts @@ -1,3 +1,4 @@ +import { SplitviewApi } from '../../api/component.api'; import { PanelViewInitParameters } from '../../splitview/core/options'; import { SplitviewPanel } from '../../splitview/splitviewPanel'; import { ReactPart, ReactPortalStore } from '../react'; @@ -21,8 +22,9 @@ export class ReactPanelView extends SplitviewPanel { { params: this._params?.params || {}, api: this.api, - containerApi: (this._params as PanelViewInitParameters) - .containerApi, + containerApi: new SplitviewApi( + (this._params as PanelViewInitParameters).accessor + ), } ); } diff --git a/packages/dockview/src/splitview/core/options.ts b/packages/dockview/src/splitview/core/options.ts index 24cf5de5a..05d01864f 100644 --- a/packages/dockview/src/splitview/core/options.ts +++ b/packages/dockview/src/splitview/core/options.ts @@ -2,14 +2,14 @@ import { IPanel, PanelInitParameters } from '../../panel/types'; import { IView, SplitViewOptions, LayoutPriority } from './splitview'; import { FrameworkFactory } from '../../types'; import { SplitviewPanel } from '../splitviewPanel'; -import { SplitviewApi } from '../../api/component.api'; +import { SplitviewComponent } from '../splitviewComponent'; export interface PanelViewInitParameters extends PanelInitParameters { minimumSize?: number; maximumSize?: number; snap?: boolean; priority?: LayoutPriority; - containerApi: SplitviewApi; + accessor: SplitviewComponent; } export interface ISerializableView extends IView, IPanel { diff --git a/packages/dockview/src/splitview/splitviewComponent.ts b/packages/dockview/src/splitview/splitviewComponent.ts index 486bfd43f..d802ca4e0 100644 --- a/packages/dockview/src/splitview/splitviewComponent.ts +++ b/packages/dockview/src/splitview/splitviewComponent.ts @@ -14,7 +14,6 @@ import { import { SplitviewComponentOptions } from './core/options'; import { BaseComponentOptions } from '../panel/types'; import { Emitter, Event } from '../events'; -import { SplitviewApi } from '../api/component.api'; import { SplitviewPanel, ISplitviewPanel } from './splitviewPanel'; import { createComponent } from '../panel/componentFactory'; @@ -70,7 +69,6 @@ export interface ISplitviewComponent extends IDisposable { fromJSON(serializedSplitview: SerializedSplitview): void; focus(): void; getPanel(id: string): ISplitviewPanel | undefined; - setActive(view: ISplitviewPanel, skipFocus?: boolean): void; removePanel(panel: ISplitviewPanel, sizing?: Sizing): void; setVisible(panel: ISplitviewPanel, visible: boolean): void; movePanel(from: number, to: number): void; @@ -279,7 +277,7 @@ export class SplitviewComponent maximumSize: options.maximumSize, snap: options.snap, priority: options.priority, - containerApi: new SplitviewApi(this), + accessor: this, }); const size: Sizing | number = @@ -380,7 +378,7 @@ export class SplitviewComponent maximumSize: data.maximumSize, snap: view.snap, priority: view.priority, - containerApi: new SplitviewApi(this), + accessor: this, }); }); diff --git a/packages/dockview/src/splitview/splitviewPanel.ts b/packages/dockview/src/splitview/splitviewPanel.ts index 3b2a21886..459cea825 100644 --- a/packages/dockview/src/splitview/splitviewPanel.ts +++ b/packages/dockview/src/splitview/splitviewPanel.ts @@ -85,14 +85,12 @@ export abstract class SplitviewPanel this._onDidChange, this.api.onVisibilityChange((event) => { const { isVisible } = event; - const { containerApi } = this - ._params as PanelViewInitParameters; - containerApi.setVisible(this, isVisible); + const { accessor } = this._params as PanelViewInitParameters; + accessor.setVisible(this, isVisible); }), this.api.onActiveChange(() => { - const { containerApi } = this - ._params as PanelViewInitParameters; - containerApi.setActive(this); + const { accessor } = this._params as PanelViewInitParameters; + accessor.setActive(this); }), this.api.onDidConstraintsChangeInternal((event) => { if (