Merge branch 'master' of https://github.com/mathuo/dockview into master

This commit is contained in:
mathuo 2022-05-31 19:55:52 +01:00
commit f82f2c8636
No known key found for this signature in database
GPG Key ID: C6EEDEFD6CA07281
41 changed files with 2559 additions and 321 deletions

View File

@ -4,8 +4,6 @@ on:
schedule:
- cron: '0 3 * * *' # every day at 3 am UTC
# on: [push]
jobs:
deploy-nightly-demo-app:
runs-on: ubuntu-latest
@ -28,11 +26,13 @@ jobs:
${{ runner.os }}-node-
- run: yarn install
working-directory: docs
- run: lerna bootstrap
- run: yarn build
working-directory: docs
working-directory: packages/dockview
- run: yarn build
working-directory: packages/docs
- run: npm run deploy-docs
working-directory: docs
working-directory: packages/docs
- name: Deploy 🚀
uses: JamesIves/github-pages-deploy-action@3.7.1
with:

View File

@ -15,7 +15,7 @@
##
Please see the website: https://mathuo.github.io/dockview/docs
Please see the website: https://dockview.dev
Want to inspect the latest deployment? Go to https://unpkg.com/browse/dockview@latest/

View File

@ -15,7 +15,7 @@
##
Please see the website: https://mathuo.github.io/dockview/docs
Please see the website: https://dockview.dev
Want to inspect the latest deployment? Go to https://unpkg.com/browse/dockview@latest/

View File

@ -1,7 +0,0 @@
{
"label": "API",
"position": 2,
"link": {
"type": "generated-index"
}
}

View File

@ -2,8 +2,8 @@
sidebar_position: 1
---
import { SimpleSplitview } from '../src/components/simpleSplitview';
import { SimpleSplitview2 } from '../src/components/simpleSplitview2';
import { SimpleSplitview } from '@site/src/components/simpleSplitview';
import { SimpleSplitview2 } from '@site/src/components/simpleSplitview2';
# Basics

View File

@ -0,0 +1,9 @@
{
"label": "Components",
"collapsible": true,
"collapsed": false,
"link": {
"type": "generated-index",
"title": "Components"
},
}

View File

@ -1,17 +1,18 @@
import { SimpleDockview } from '../../src/components/simpleDockview';
import { SimpleDockview } from '@site/src/components/simpleDockview';
import {
RenderingDockview,
Checkbox,
} from '../../src/components/dockview/rendering';
import { DndDockview } from '../../src/components/dockview/dnd';
import { EventsDockview } from '../../src/components/dockview/events';
} from '@site/src/components/dockview/rendering';
import { DndDockview } from '@site/src/components/dockview/dnd';
import { EventsDockview } from '@site/src/components/dockview/events';
import { ContextMenuDockview } from '@site/src/components/dockview/contextMenu';
import Link from '@docusaurus/Link';
# Dockview
## Introduction
Dockview is an abstraction built on top of [Gridviews](/docs/api/gridview) where each view is a tabbed container.
Dockview is an abstraction built on top of [Gridviews](./gridview) where each view is a container of many tabbed panels.
<div
style={{
@ -24,36 +25,36 @@ Dockview is an abstraction built on top of [Gridviews](/docs/api/gridview) where
<SimpleDockview />
</div>
```tsx
const panel = event.api.addPanel(...);
const anotherPanel = event.api.getPanel('somePanelid');
```
You can access the panels associated group through the `panel.group` variable.
The group will always be defined and will change if a panel is moved into another group.
## DockviewReact Component
You can create a Dockview through the use of the `ReactDockview` component.
```tsx
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 <Link to="/docs/basics/#auto-resizing">Auto Resizing</Link> |
| 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 <Link to="../basics/#auto-resizing">Auto Resizing</Link> |
| onTabContextMenu | Event | Yes | false | |
| onDidDrop | Event | Yes | false | |
| showDndOverlay | Event | Yes | false | |
## Dockview API
```tsx
The Dockview API is exposed both at the `onReady` event and on each panel through `props.containerApi`.
Through this API you can control general features of the component and access all added panels.
```tsx title="Dockview API via Panel component"
const MyComponent = (props: IDockviewPanelProps<{ title: string }>) => {
// props.containerApi...
@ -61,52 +62,52 @@ const MyComponent = (props: IDockviewPanelProps<{ title: string }>) => {
};
```
```tsx
```tsx title="Dockview API via the onReady callback"
const onReady = (event: DockviewReadyEvent) => {
// event.api...
};
```
| 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<void>` | |
| onDidLayoutFromJSON | `Event<void>` | |
| onDidAddGroup | `Event<GroupPanel>` | |
| onDidRemoveGroup | `Event<GroupPanel>` | |
| onDidActiveGroupChange | `Event<GroupPanel \| undefined>` | |
| onDidAddPanel | `Event<IDockviewPanel>` | |
| onDidRemovePanel | `Event<IDockviewPanel>` | |
| onDidActivePanelChange | `Event<IDockviewPanel \| undefined>` | |
| onDidDrop | `Event<DockviewDropEvent` | |
| | | |
| addPanel | `addPanel(options: AddPanelOptions): IDockviewPanel` | |
| getPanel | `(id: string) \| IDockviewPanel \| undefined` | |
| addEmptyGroup | `(options? AddGroupOptions): void` | |
| closeAllGroups | `(): void` | |
| removeGroup | `(group: GroupPanel): void` | |
| getGroup | `(id: string): GroupPanel \| undefined` | |
| | | |
| getTabHeight | `(): number \| undefined` | |
| setTabHeight | `(hegiht: number \| undefined): void` | |
| updateOptions | `(options:SplitviewComponentUpdateOptions): void` | |
| focus | `(): void` | |
| layout | `(width: number, height:number): void` | <Link to="/docs/basics/#auto-resizing">Auto Resizing</Link> |
| fromJSON | `(data: SerializedDockview): void` | <Link to="/docs/basics/#serialization">Serialization</Link> |
| toJSON | `(): SerializedDockview` | <Link to="/docs/basics/#serialization">Serialization</Link> |
| clear | `(): void` | Clears the current layout |
| 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<void>` | |
| onDidLayoutFromJSON | `Event<void>` | |
| onDidAddGroup | `Event<GroupPanel>` | |
| onDidRemoveGroup | `Event<GroupPanel>` | |
| onDidActiveGroupChange | `Event<GroupPanel \| undefined>` | |
| onDidAddPanel | `Event<IDockviewPanel>` | |
| onDidRemovePanel | `Event<IDockviewPanel>` | |
| onDidActivePanelChange | `Event<IDockviewPanel \| undefined>` | |
| onDidDrop | `Event<DockviewDropEvent` | |
| | | |
| addPanel | `addPanel(options: AddPanelOptions): IDockviewPanel` | |
| getPanel | `(id: string) \| IDockviewPanel \| undefined` | |
| addEmptyGroup | `(options? AddGroupOptions): void` | |
| closeAllGroups | `(): void` | |
| removeGroup | `(group: GroupPanel): void` | |
| getGroup | `(id: string): GroupPanel \| undefined` | |
| | | |
| getTabHeight | `(): number \| undefined` | |
| setTabHeight | `(hegiht: number \| undefined): void` | |
| updateOptions | `(options:SplitviewComponentUpdateOptions): void` | |
| focus | `(): void` | |
| layout | `(width: number, height:number): void` | <Link to="../basics/#auto-resizing">Auto Resizing</Link> |
| fromJSON | `(data: SerializedDockview): void` | <Link to="../basics/#serialization">Serialization</Link> |
| toJSON | `(): SerializedDockview` | <Link to="../basics/#serialization">Serialization</Link> |
| clear | `(): void` | Clears the current layout |
## Dockview Panel API
@ -147,7 +148,7 @@ const MyComponent = (props: IDockviewPanelProps<{ title: string }>) => {
### Locked group
Locking a group will disable all drop events for this group ensuring a user can not add additional panels to the group.
You can still add groups to a locked panel programatically using the api.
You can still add groups to a locked panel programatically using the API.
```tsx
panel.group.locked = true;
@ -163,7 +164,15 @@ panel.group.header.hidden = true;
### Context Menu
import { ContextMenuDockview } from '../../src/components/dockview/contextMenu';
Since overriding the context menu is a such a common feature rather than defining a custom tab the `ReactDockview` component exposes the prop `onTabContextMenu`.
You can alternatively define a custom tab component for more granular control.
:::caution
The `onTabContextMenu` is intended to be removed in a future release to further simplify the library.
In the future you will be required to define a custom tab component to intercept the context menu events.
:::
<div
style={{

View File

@ -1,5 +1,5 @@
import { SimpleGridview } from '../../src/components/simpleGridview';
import { EventsGridview } from '../../src/components/gridview/events';
import { SimpleGridview } from '@site/src/components/simpleGridview';
import { EventsGridview } from '@site/src/components/gridview/events';
import Link from '@docusaurus/Link';
# Gridview
@ -23,15 +23,15 @@ import Link from '@docusaurus/Link';
import { ReactGridview } from 'dockview';
```
| Property | Type | Optional | Default | Description |
| ------------------- | ------------------------------------ | -------- | ---------------------- | --------------------------------------------------------------------------- |
| onReady | (event: SplitviewReadyEvent) => void | No | | |
| components | object | No | | |
| orientation | Orientation | Yes | Orientation.HORIZONTAL | |
| proportionalLayout | boolean | Yes | true | See <Link to="/docs/basics/#proportional-layout">Proportional layout</Link> |
| hideBorders | boolean | Yes | false | |
| className | string | Yes | '' | |
| disableAutoResizing | boolean | Yes | false | See <Link to="/docs/basics/#auto-resizing">Auto Resizing</Link> |
| Property | Type | Optional | Default | Description |
| ------------------- | ------------------------------------ | -------- | ---------------------- | ------------------------------------------------------------------------ |
| onReady | (event: SplitviewReadyEvent) => void | No | | |
| components | object | No | | |
| orientation | Orientation | Yes | Orientation.HORIZONTAL | |
| proportionalLayout | boolean | Yes | true | See <Link to="../basics/#proportional-layout">Proportional layout</Link> |
| hideBorders | boolean | Yes | false | |
| className | string | Yes | '' | |
| disableAutoResizing | boolean | Yes | false | See <Link to="../basics/#auto-resizing">Auto Resizing</Link> |
## Gridview API
@ -74,9 +74,9 @@ const onReady = (event: GridviewReadyEvent) => {
| | | |
| updateOptions | `(options:SplitviewComponentUpdateOptions): void` | |
| focus | `(): void` | Focus the active panel, if exists |
| layout | `(width: number, height:number): void` | <Link to="/docs/basics/#auto-resizing">Auto Resizing</Link> |
| fromJSON | `(data: SerializedGridview): void` | <Link to="/docs/basics/#serialization">Serialization</Link> |
| toJSON | `(): SerializedGridview` | <Link to="/docs/basics/#serialization">Serialization</Link> |
| layout | `(width: number, height:number): void` | <Link to="../basics/#auto-resizing">Auto Resizing</Link> |
| fromJSON | `(data: SerializedGridview): void` | <Link to="../basics/#serialization">Serialization</Link> |
| toJSON | `(): SerializedGridview` | <Link to="../basics/#serialization">Serialization</Link> |
| clear | `(): void` | Clears the current layout |
## Gridview Panel API

View File

@ -1,8 +1,21 @@
import { SimplePaneview } from '../../src/components/simplePaneview';
import { SimplePaneview } from '@site/src/components/simplePaneview';
import { CustomHeaderPaneview } from '@site/src/components/paneview/customHeader';
import { DragAndDropPaneview } from '@site/src/components/paneview/dragAndDrop';
import Link from '@docusaurus/Link';
# Paneview
A paneview is a collapsed collection of vertically stacked panels and panel headers.
The panel header will always remain visible however the panel will only be visible when the panel is expanded.
:::info
Paneview panels can be re-ordered by dragging and dropping the panel headers.
:::
---
# Introduction
<div
@ -16,25 +29,94 @@ import Link from '@docusaurus/Link';
<SimplePaneview />
</div>
```tsx title="Simple Paneview example"
import {
IPaneviewPanelProps,
PaneviewReact,
PaneviewReadyEvent,
} from 'dockview';
const components = {
default: (props: IPaneviewPanelProps<{ title: string }>) => {
return (
<div
style={{
padding: '10px',
height: '100%',
backgroundColor: 'rgb(60,60,60)',
}}
>
{props.params.title}
</div>
);
},
};
SimplePaneview = () => {
const onReady = (event: PaneviewReadyEvent) => {
event.api.addPanel({
id: 'panel_1',
component: 'default',
params: {
title: 'Panel 1',
},
title: 'Panel 1',
});
event.api.addPanel({
id: 'panel_2',
component: 'default',
params: {
title: 'Panel 2',
},
title: 'Panel 2',
});
event.api.addPanel({
id: 'panel_3',
component: 'default',
params: {
title: 'Panel 3',
},
title: 'Panel 3',
});
};
return (
<PaneviewReact
components={components}
headerComponents={headerComponents}
onReady={onReady}
className="dockview-theme-dark"
/>
);
};
```
## PaneviewReact Component
You can create a Paneview through the use of the `ReactPaneview` component.
```tsx
import { ReactPaneview } from 'dockview';
```
| Property | Type | Optional | Default | Description |
| ------------------- | ------------------------------------ | -------- | ------- | ----------------------------------------------------------- |
| onReady | (event: SplitviewReadyEvent) => void | No | | |
| components | object | No | | |
| headerComponents | object | Yes | | |
| className | string | Yes | '' | |
| disableAutoResizing | boolean | Yes | false | <Link to="/docs/basics/#auto-resizing">Auto Resizing</Link> |
| 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 | <Link to="../basics/#auto-resizing">Auto Resizing</Link> |
| disableDnd | boolean | Yes | false | |
| onDidDrop | Event | Yes | | |
## Paneview API
```tsx
The Paneview API is exposed both at the `onReady` event and on each panel through `props.containerApi`.
Through this API you can control general features of the component and access all added panels.
```tsx title="Paneview API via Panel component"
const MyComponent = (props: IGridviewPanelProps<{ title: string }>) => {
// props.containerApi...
@ -42,39 +124,39 @@ const MyComponent = (props: IGridviewPanelProps<{ title: string }>) => {
};
```
```tsx
```tsx title="Paneview API via the onReady callback"
const onReady = (event: GridviewReadyEvent) => {
// event.api...
};
```
| 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 | `IPaneviewPanel[]` | All panels |
| | | |
| onDidLayoutChange | `Event<void>` | Fires on layout change |
| onDidLayoutFromJSON | `Event<void>` | Fires of layout change caused by a fromJSON deserialization call |
| onDidAddView | `Event<IPaneviewPanel>` | Fires when a view is added |
| onDidRemoveView | `Event<IPaneviewPanel>` | Fires when a view is removed |
| onDidDrop | `Event<PaneviewDropEvent` | Fires on an external drop event (See <Link to="/docs/api/paneview/#drag-and-drop">Drag and Drop</Link>) |
| | | |
| 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 <Link to="/docs/basics/#auto-resizing">Auto Resizing</Link> |
| fromJSON | `(data: SerializedPaneview): void` | <Link to="/docs/basics/#serialization">Serialization</Link> |
| toJSON | `(): SerializedPaneview` | <Link to="/docs/basics/#serialization">Serialization</Link> |
| clear | `(): void` | Clears the current layout |
| 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 | `IPaneviewPanel[]` | All panels |
| | | |
| onDidLayoutChange | `Event<void>` | Fires on layout change |
| onDidLayoutFromJSON | `Event<void>` | Fires of layout change caused by a fromJSON deserialization call |
| onDidAddView | `Event<IPaneviewPanel>` | Fires when a view is added |
| onDidRemoveView | `Event<IPaneviewPanel>` | Fires when a view is removed |
| onDidDrop | `Event<PaneviewDropEvent` | Fires on an external drop event (See <Link to="./paneview/#drag-and-drop">Drag and Drop</Link>) |
| | | |
| 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 <Link to="../basics/#auto-resizing">Auto Resizing</Link> |
| fromJSON | `(data: SerializedPaneview): void` | <Link to="../basics/#serialization">Serialization</Link> |
| toJSON | `(): SerializedPaneview` | <Link to="../basics/#serialization">Serialization</Link> |
| clear | `(): void` | Clears the current layout |
## Gridview Panel API
## Paneview Panel API
```tsx
const MyComponent = (props: IGridviewPanelProps<{ title: string }>) => {
@ -108,8 +190,20 @@ const MyComponent = (props: IGridviewPanelProps<{ title: string }>) => {
### 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:
You can provide a custom component to render an alternative header.
<div
style={{
height: '400px',
backgroundColor: 'rgb(30,30,30)',
color: 'white',
margin: '20px 0px',
}}
>
<CustomHeaderPaneview />
</div>
You can provide a `headerComponent` option when creating a panel to tell the library to use a custom header component.
```tsx
const onReady = (event: PaneviewReadyEvent) => {
@ -125,27 +219,12 @@ const onReady = (event: PaneviewReadyEvent) => {
};
```
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:
This header must be defined in the collection of components provided to the `headerComponents` props for `ReactPaneivew`
```tsx
const onReady = (event: PaneviewReadyEvent) => {
event.api.addPanel({
id: 'panel_1',
component: 'default',
headerComponent: 'myHeaderComponent',
params: {
valueA: 'A',
},
title: 'Panel 1',
});
};
```
import { IPaneviewPanelProps } from 'dockview';
You can define a header component and listen to the expanded state to update the component accordingly.
```tsx
const CustomHeader = (props: IPaneviewPanelProps) => {
const MyHeaderComponent = (props: IPaneviewPanelProps<{ title: string }>) => {
const [expanded, setExpanded] = React.useState<boolean>(
props.api.isExpanded
);
@ -165,7 +244,13 @@ const CustomHeader = (props: IPaneviewPanelProps) => {
};
return (
<div>
<div
style={{
padding: '10px',
height: '100%',
backgroundColor: 'rgb(60,60,60)',
}}
>
<a
onClick={onClick}
className={expanded ? 'expanded' : 'collapsed'}
@ -174,12 +259,12 @@ const CustomHeader = (props: IPaneviewPanelProps) => {
</div>
);
};
```
You should provide a value for the `headerComponents` React prop.
```tsx
const headerComponents = { myHeaderComponent: CustomHeader };
const headerComponents = { myHeaderComponent: MyHeaderComponent };
```
### Drag And Drop
If you provide the `PaneviewReact` component with the prop `onDidDrop` you will be able to interact with custom drop events.
<DragAndDropPaneview />

View File

@ -1,14 +1,12 @@
import { SimpleSplitview } from '../../src/components/simpleSplitview';
import { SplitviewExample1 } from '../../src/components/splitview/active';
import { SimpleSplitview } from '@site/src/components/simpleSplitview';
import { SplitviewExample1 } from '@site/src/components/splitview/active';
import Link from '@docusaurus/Link';
# Splitview
## Introduction
A Splitview is a collection resizable horizontally or vertically stacked panels.
The Splitview exposes a component level API through the `onReady` event and through the `props.containerApi` variable on the panel props.
A panel level API is exposed on each panel through it's props as `props.api`.
A Splitview is a collection of resizable horizontally or vertically stacked panels.
<div
style={{
@ -81,21 +79,22 @@ You can create a Splitview through the use of the `ReactSplitview` component.
import { ReactSplitview } from 'dockview';
```
Using the `onReady` prop you can access to the component `api` and add panels either through deserialization or indivial addition of panels.
Using the `onReady` prop you can access to the component `api` and add panels either through deserialization or the individual addition of panels.
| Property | Type | Optional | Default | Description |
| ------------------- | -------------------------------------- | -------- | ------------------------ | --------------------------------------------------------------------------- |
| onReady | `(event: SplitviewReadyEvent) => void` | No | | Function |
| components | `Record<string, ISplitviewPanelProps>` | No | | Panel renderers |
| orientation | `Orientation` | Yes | `Orientation.HORIZONTAL` | Orientation of the Splitview |
| proportionalLayout | `boolean` | Yes | `true` | See <Link to="/docs/basics/#proportional-layout">Proportional layout</Link> |
| hideBorders | `boolean` | Yes | `false` | Hide the borders between panels |
| className | `string` | Yes | `''` | Attaches a classname |
| disableAutoResizing | `boolean` | Yes | `false` | See <Link to="/docs/basics/#auto-resizing">Auto Resizing</Link> |
| Property | Type | Optional | Default | Description |
| ------------------- | -------------------------------------- | -------- | ------------------------ | ------------------------------------------------------------------------ |
| onReady | `(event: SplitviewReadyEvent) => void` | No | | Function |
| components | `Record<string, ISplitviewPanelProps>` | No | | Panel renderers |
| orientation | `Orientation` | Yes | `Orientation.HORIZONTAL` | Orientation of the Splitview |
| proportionalLayout | `boolean` | Yes | `true` | See <Link to="../basics/#proportional-layout">Proportional layout</Link> |
| hideBorders | `boolean` | Yes | `false` | Hide the borders between panels |
| className | `string` | Yes | `''` | Attaches a classname |
| disableAutoResizing | `boolean` | Yes | `false` | See <Link to="../basics/#auto-resizing">Auto Resizing</Link> |
## Splitview API
The Splitview API is exposed both at the `onReady` event and on each panel through `props.containerApi`.
Through this API you can control general features of the component and access all added panels.
```tsx title="Splitview API via Panel component"
const MyComponent = (props: ISplitviewPanelProps<{ title: string }>) => {
@ -132,14 +131,14 @@ const onReady = (event: SplitviewReadyEvent) => {
| | |
| updateOptions | `(options: SplitviewComponentUpdateOptions): void` | |
| focus | `(): void` | Focus the active panel, if exists |
| layout | `(width: number, height:number): void` | See <Link to="/docs/basics/#auto-resizing">Auto Resizing</Link> |
| fromJSON | `(data: SerializedSplitview): void` | <Link to="/docs/basics/#serialization">Serialization</Link> |
| toJSON | `(): SerializedSplitview` | <Link to="/docs/basics/#serialization">Serialization</Link> |
| layout | `(width: number, height:number): void` | See <Link to="../basics/#auto-resizing">Auto Resizing</Link> |
| fromJSON | `(data: SerializedSplitview): void` | <Link to="../basics/#serialization">Serialization</Link> |
| toJSON | `(): SerializedSplitview` | <Link to="../basics/#serialization">Serialization</Link> |
| clear | `(): void` | Clears the current layout |
## Splitview Panel API
The Splitview panel API is exposed on each panel and contains actions and variables specific to that panel.
The Splitview panel API is exposed on each panel containing actions and variables specific to that panel.
```tsx title="Splitview panel API via Panel component"
const MyComponent = (props: ISplitviewPanelProps<{ title: string }>) => {
@ -149,30 +148,30 @@ 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<PanelDimensionChangeEvent>` | Fires when panel dimensions change |
| onDidFocusChange | `Event<FocusEvent>` | Fire when panel is focused and blurred |
| onDidVisibilityChange | `Event<VisibilityEvent>` | Fires when the panels visiblity property is changed (see <Link to="/docs/api/splitview/#visibility">Panel Visibility</Link>) |
| onDidActiveChange | `Event<ActiveEvent>` | Fires when the panels active property is changed (see <Link to="/docs/api/splitview/#active">Active Panel</Link>) |
| onDidConstraintsChange | `onDidConstraintsChange: Event<PanelConstraintChangeEvent>` | Fires when the panels size contrainsts change (see <Link to="/docs/api/splitview/#contraints">Panel Constraints</Link>) |
| | | |
| 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<PanelDimensionChangeEvent>` | Fires when panel dimensions change |
| onDidFocusChange | `Event<FocusEvent>` | Fire when panel is focused and blurred |
| onDidVisibilityChange | `Event<VisibilityEvent>` | Fires when the panels visiblity property is changed (see <Link to="./splitview/#visibility">Panel Visibility</Link>) |
| onDidActiveChange | `Event<ActiveEvent>` | Fires when the panels active property is changed (see <Link to="./splitview/#active">Active Panel</Link>) |
| onDidConstraintsChange | `onDidConstraintsChange: Event<PanelConstraintChangeEvent>` | Fires when the panels size contrainsts change (see <Link to="./splitview/#contraints">Panel Constraints</Link>) |
| | | |
| setVisible | `(isVisible: boolean): void` | |
| setActive | `(): void` | |
| | | |
| setConstraints | `(value: PanelConstraintChangeEvent2): void;` | |
| setSize | `(event: PanelSizeEvent): void` | |
## Advanced Features
Listed below are some functionality avalaible to you through both the panel and component APIs. The live demo shows examples of these in real-time.
Listed below are some functionalities avalaible through both the panel and component APIs. The live demo shows examples of these in real-time.
<div
style={{
@ -185,7 +184,7 @@ Listed below are some functionality avalaible to you through both the panel and
### Visibility
A panels visibility can be controlled and monitoring through the following code.
A panels visibility can be controlled and monitored through the following code.
A panel with visibility set to `false` will remain as a part of the components list of panels but will not be rendered.
```tsx

View File

@ -2,10 +2,10 @@
sidebar_position: 0
---
import { SimpleSplitview } from '../src/components/simpleSplitview';
import { SimpleGridview } from '../src/components/simpleGridview';
import { SimplePaneview } from '../src/components/simplePaneview';
import { SimpleDockview } from '../src/components/simpleDockview';
import { SimpleSplitview } from '@site/src/components/simpleSplitview';
import { SimpleGridview } from '@site/src/components/simpleGridview';
import { SimplePaneview } from '@site/src/components/simplePaneview';
import { SimpleDockview } from '@site/src/components/simpleDockview';
# Dockview

View File

@ -2,7 +2,7 @@
sidebar_position: 3
---
import { CustomCSSDockview } from '../src/components/dockview/customCss';
import { CustomCSSDockview } from '@site/src/components/dockview/customCss';
# Theme

View File

@ -11,12 +11,12 @@ console.log(`isCI: ${process.env.CI}`);
/** @type {import('@docusaurus/types').Config} */
const config = {
title: 'Dockview',
tagline: 'Zero dependency layout manager for React',
url: 'https://your-docusaurus-test-site.com',
tagline: 'A zero dependency layout manager built for React',
url: 'https://dockview.dev',
baseUrl: process.env.CI ? `/` : '/',
onBrokenLinks: 'throw',
onBrokenMarkdownLinks: 'warn',
favicon: 'img/favicon.ico',
favicon: 'img/dockview_logo.ico',
// GitHub pages deployment config.
// If you aren't using GitHub pages, you don't need these.
@ -52,6 +52,9 @@ const config = {
'react-dom'
),
},
fallback: {
timers: false,
},
},
};
},
@ -69,6 +72,11 @@ const config = {
// Remove this to remove the "edit this page" links.
editUrl:
'https://github.com/facebook/docusaurus/tree/main/packages/create-docusaurus/templates/shared/',
versions: {
current: {
label: `Development 🚧`,
},
},
},
blog: {
showReadingTime: true,
@ -80,6 +88,11 @@ const config = {
theme: {
customCss: require.resolve('./src/css/custom.css'),
},
gtag: process.env.CI
? {
trackingID: 'G-KXGC1C9ZHC',
}
: undefined,
}),
],
],
@ -87,11 +100,33 @@ const config = {
themeConfig:
/** @type {import('@docusaurus/preset-classic').ThemeConfig} */
({
metadata: [
{
name: 'keywords',
content: [
'react',
'components',
'typescript',
'drag-and-drop',
'reactjs',
'layout',
'drag',
'drop',
'tabs',
'dock',
'docking',
'splitter',
'docking-library',
'layout-manager',
'docking-layout',
].join(' ,'),
},
],
navbar: {
title: 'Dockview',
logo: {
alt: 'My Site Logo',
src: 'img/logo.svg',
src: 'img/dockview_logo.svg',
},
items: [
{
@ -101,6 +136,10 @@ const config = {
label: 'Docs',
},
{ to: '/blog', label: 'Blog', position: 'left' },
{
type: 'docsVersionDropdown',
position: 'right',
},
{
href: 'https://github.com/mathuo/dockview',
label: 'GitHub',

View File

@ -19,12 +19,14 @@
"@docusaurus/core": "2.0.0-beta.20",
"@docusaurus/preset-classic": "2.0.0-beta.20",
"@mdx-js/react": "^1.6.22",
"axios": "^0.27.2",
"clsx": "^1.1.1",
"dockview": "^1.4.3",
"prism-react-renderer": "^1.3.1",
"react": "^17.0.2",
"react-dom": "^17.0.2",
"recoil": "^0.7.3-alpha.2"
"recoil": "^0.7.3-alpha.2",
"xml2js": "^0.4.23"
},
"devDependencies": {
"@docusaurus/module-type-aliases": "2.0.0-beta.20",

View File

@ -3,68 +3,112 @@ import clsx from 'clsx';
import styles from './styles.module.css';
type FeatureItem = {
title: string;
Svg: React.ComponentType<React.ComponentProps<'svg'>>;
description: JSX.Element;
title: string;
Svg: React.ComponentType<React.ComponentProps<'svg'>>;
description: JSX.Element;
};
const FeatureList: FeatureItem[] = [
{
title: 'Easy to Use',
Svg: require('@site/static/img/undraw_docusaurus_mountain.svg').default,
description: (
<>
Docusaurus was designed from the ground up to be easily installed and
used to get your website up and running quickly.
</>
),
},
{
title: 'Focus on What Matters',
Svg: require('@site/static/img/undraw_docusaurus_tree.svg').default,
description: (
<>
Docusaurus lets you focus on your docs, and we&apos;ll do the chores. Go
ahead and move your docs into the <code>docs</code> directory.
</>
),
},
{
title: 'Powered by React',
Svg: require('@site/static/img/undraw_docusaurus_react.svg').default,
description: (
<>
Extend or customize your website layout by reusing React. Docusaurus can
be extended while reusing the same header and footer.
</>
),
},
{
title: '',
Svg: require('@site/static/img/dockview_grid_2.svg').default,
description: (
<>
<div className="feature-banner">
<h3 className="feature-banner-header">
Serialziable Layouts
</h3>
<p className="feature-banner-content">
Add and remove panels using the provided api or use the
serialization method to persist layouts.
</p>
</div>
<div className="feature-banner">
<h3 className="feature-banner-header">
Customizable Theme
</h3>
<p className="feature-banner-content">
Adjust a numbero of provided CSS Properties for a simple
change or target specific classes for a more customized
approach.
</p>
</div>
<div className="feature-banner">
<h3 className="feature-banner-header">
Choose Your Control
</h3>
<p className="feature-banner-content">
Choose from a simple splitview, a gridview, collapsable
panes or a full docking solution. Combine multiple for
more complex layouts.
</p>
</div>
</>
),
},
{
title: '',
Svg: require('@site/static/img/dockview_splash_2.svg').default,
description: (
<>
<div className="feature-banner">
<h3 className="feature-banner-header">Drag And Drop</h3>
<p className="feature-banner-content">
Drag and Drop to position your layout and interact with
external drag events too.
</p>
</div>
<div className="feature-banner">
<h3 className="feature-banner-header">Zero Dependencies</h3>
<p className="feature-banner-content">
Zero dependencies, that's all.
</p>
</div>
<div className="feature-banner">
<h3 className="feature-banner-header">
Code Quality and Transparency
</h3>
<p className="feature-banner-content">
All of the code is run through Sonarcloud Code Analyis
which along with the source code and high test coverage
can be viewed from the Github page.
</p>
</div>
</>
),
},
];
function Feature({title, Svg, description}: FeatureItem) {
return (
<div className={clsx('col col--4')}>
<div className="text--center">
<Svg className={styles.featureSvg} role="img" />
</div>
<div className="text--center padding-horiz--md">
<h3>{title}</h3>
<p>{description}</p>
</div>
</div>
);
function Feature({ title, Svg, description }: FeatureItem) {
return (
<div
style={{
display: 'flex',
flexWrap: 'wrap',
margin: 'auto',
justifyContent: 'center',
}}
className="dockview-feature"
>
<Svg className={styles.featureSvg} role="img" />
<div style={{ maxWidth: '400px', padding: '0px 20px' }}>
<h3>{title}</h3>
<p>{description}</p>
</div>
</div>
);
}
export default function HomepageFeatures(): JSX.Element {
return (
<section className={styles.features}>
<div className="container">
<div className="row">
{FeatureList.map((props, idx) => (
<Feature key={idx} {...props} />
))}
</div>
</div>
</section>
);
return (
<section className={styles.features}>
<div className="container">
<div className="row">
{FeatureList.map((props, idx) => (
<Feature key={idx} {...props} />
))}
</div>
</div>
</section>
);
}

View File

@ -6,6 +6,6 @@
}
.featureSvg {
height: 200px;
width: 200px;
height: 400px;
width: 400px;
}

View File

@ -0,0 +1,72 @@
import axios from 'axios';
const EXCHANGE_URL = 'https://api.exchange.coinbase.com';
const URL = 'https://api.coinbase.com/v2';
export interface Currency {
id: string;
name: string;
min_size: string;
max_precision: string;
status: string;
details: {
type: string;
symbol: string;
sort_order: number;
push_payment_methods: string[];
display_name: string;
group_types: string[];
};
}
export interface Price {
data: { base: string; currency: string; amount: string };
}
export async function allCurrencies(): Promise<Currency[]> {
try {
const response = await axios.get<Currency[]>(
`${EXCHANGE_URL}/currencies`,
{
headers: { Accept: 'application/json' },
}
);
return response.data;
} catch (err) {
return [];
}
}
export async function getCurrencies(id: string): Promise<Currency | null> {
try {
const response = await axios.get<Currency>(
`${EXCHANGE_URL}/currencies/${id}`,
{
headers: { Accept: 'application/json' },
}
);
return response.data;
} catch (err) {
return null;
}
}
export async function getPrice(base: string, quote: string) {
try {
const response = await axios.get<Price>(
`${URL}/prices/${base}-${quote}/buy`,
{
headers: { Accept: 'application/json' },
}
);
return response.data;
} catch (err) {
return null;
}
}
export const CURRENCIES = ['BTC', 'ETH', 'LTC'];

View File

@ -0,0 +1,28 @@
.tab {
.dockview-react-tab {
display: flex;
padding: 0px 8px;
align-items: center;
height: 100%;
.dockview-react-tab-title {
padding: 0px 8px;
flex-grow: 1;
}
.dockview-react-tab-action {
padding: 0px 4px;
&:hover {
border-radius: 2px;
background-color: rgba(90, 93, 94, 0.31);
}
}
}
&.dockview-inactive-tab:not(:hover) {
.dockview-react-tab-action {
visibility: hidden;
}
}
}

View File

@ -3,65 +3,59 @@ import {
DockviewReadyEvent,
IDockviewPanelHeaderProps,
IDockviewPanelProps,
TabContextMenuEvent,
} from 'dockview';
import * as React from 'react';
import './contextMenu.scss';
//
const components = {
default: (props: IDockviewPanelProps<{ title: string }>) => {
return <div style={{ padding: '20px' }}>{props.params.title}</div>;
},
};
const DefaultTab = (props: IDockviewPanelHeaderProps) => {
const [active, setActive] = React.useState<boolean>(props.api.isActive);
const [groupActive, setGroupActive] = React.useState<boolean>(
props.api.isGroupActive
const CustomTab = (
props: IDockviewPanelHeaderProps & React.DOMAttributes<HTMLDivElement>
) => {
const onClose = React.useCallback(
(event: React.MouseEvent<HTMLSpanElement>) => {
event.stopPropagation();
props.api.close();
},
[props.api]
);
React.useEffect(() => {
const disposable1 = props.api.onDidActiveChange((e) => {
setActive(e.isActive);
});
const disposable2 = props.containerApi.onDidActiveGroupChange((e) => {
setGroupActive(props.api.isGroupActive);
});
const onClick = React.useCallback(
(event: React.MouseEvent<HTMLDivElement>) => {
props.api.setActive();
return () => {
disposable1.dispose();
disposable2.dispose();
};
}, [props.api]);
if (props.onClick) {
props.onClick(event);
}
},
[props.api, props.onClick]
);
return (
<div
style={{
display: 'flex',
padding: '0px 8px',
alignItems: 'center',
height: '100%',
}}
>
<span style={{ padding: '0px 8px', flexGrow: 1 }}>
{props.api.title}
</span>
<span
className=""
onClick={() => props.api.setActive()}
style={{
display: 'flex',
alignItems: 'center',
paddingRight: '8px',
}}
>
<div {...props} onClick={onClick} className="dockview-react-tab">
<span className="dockview-react-tab-title">{props.api.title}</span>
<span onClick={onClose} className="dockview-react-tab-action">
{'✕'}
</span>
</div>
);
};
const Test = (props: IDockviewPanelHeaderProps) => {
const onContextMenu = (event: React.MouseEvent) => {
event.preventDefault();
alert('hiya');
};
return <CustomTab onContextMenu={onContextMenu} {...props} />;
};
const tabComponents = {
default: DefaultTab,
default: Test,
};
export const ContextMenuDockview = () => {
@ -104,12 +98,18 @@ export const ContextMenuDockview = () => {
});
};
const onContextMenu = (event: TabContextMenuEvent) => {
event.event.preventDefault();
alert(`Content appear event fired for panel ${event.panel.id}`);
};
return (
<DockviewReact
components={components}
tabComponents={tabComponents}
onReady={onReady}
className="dockview-theme-dark"
onTabContextMenu={onContextMenu}
/>
);
};

View File

@ -0,0 +1,15 @@
.news-panel {
height: 100%;
overflow: auto;
.story {
display: flex;
flex-direction: column;
justify-content: start;
.link {
color: white !important;
font-size: 11px;
}
}
}

View File

@ -0,0 +1,186 @@
import {
DockviewReact,
DockviewReadyEvent,
IDockviewPanelProps,
} from 'dockview';
import * as React from 'react';
import { CURRENCIES, Currency, getCurrencies, getPrice } from './api';
import './demo.scss';
const CurrencyRow = (props: { currency: Currency }) => {
const [price, setPrice] = React.useState<number>();
React.useEffect(() => {
getPrice(props.currency.id, 'USD').then((result) => {
setPrice(Number(result.data.amount));
});
}, [props.currency]);
return (
<>
<div>{props.currency.id}</div>
<div>{`${typeof price === 'number' ? `$${price}` : '-'}`}</div>
</>
);
};
const Currencies = () => {
const [currencies, setCurrencies] = React.useState<Currency[]>([]);
React.useEffect(() => {
Promise.all(CURRENCIES.map(getCurrencies)).then((results) => {
setCurrencies(results.filter(Boolean));
});
}, []);
return (
<div
style={{
height: '100%',
overflow: 'auto',
margin: '10px',
}}
>
<div
style={{
display: 'grid',
gridTemplateColumns: '50px 100px',
justifyItems: 'start',
}}
>
{currencies.map((currency) => (
<CurrencyRow key={currency.id} currency={currency} />
))}
</div>
</div>
);
};
import axios from 'axios';
type Article = {
id: 15255;
title: string;
url: string;
imageUrl: string;
newsSite: string;
summary: string;
publishedAt: string;
updatedAt: string;
featured: boolean;
launches: any[];
events: any[];
};
async function getStories(): Promise<Article[]> {
const response = await axios.get<Article[]>(
'https://api.spaceflightnewsapi.net/v3/articles'
);
return response.data;
}
const News = () => {
const [stories, setStories] = React.useState<Article[]>([]);
React.useEffect(() => {
getStories().then(setStories);
}, []);
return (
<div className="news-panel">
{stories.map((story) => {
return (
<div className="story">
<div className="metadata">
<span>{story.title}</span>
</div>
<div className="link">
<a href={story.url}>{story.url.substring(0, 10)}</a>
</div>
</div>
);
})}
</div>
);
};
const components = {
default: (props: IDockviewPanelProps<{ title: string }>) => {
return <div style={{ padding: '20px' }}>{props.params.title}</div>;
},
currencies: Currencies,
news: News,
};
export const DockviewDemo = () => {
const onReady = (event: DockviewReadyEvent) => {
// event.api.addPanel({
// id: 'currencies',
// component: 'currencies',
// title: 'Prices',
// });
// event.api.addPanel({
// id: 'news',
// component: 'news',
// title: 'News',
// });
event.api.addPanel({
id: 'panel_1',
component: 'default',
title: 'Panel 1',
});
event.api.addPanel({
id: 'panel_2',
component: 'default',
title: 'Panel 2',
});
event.api.addPanel({
id: 'panel_3',
component: 'default',
title: 'Panel 3',
});
event.api.addPanel({
id: 'panel_4',
component: 'default',
title: 'Panel 4',
position: { referencePanel: 'panel_3', direction: 'right' },
});
event.api.addPanel({
id: 'panel_5',
component: 'default',
title: 'Panel 5',
position: { referencePanel: 'panel_4', direction: 'within' },
});
const panel6 = event.api.addPanel({
id: 'panel_6',
component: 'default',
title: 'Panel 6',
position: { referencePanel: 'panel_4', direction: 'below' },
});
panel6.group.locked = true;
panel6.group.header.hidden = true;
event.api.addPanel({
id: 'panel_7',
component: 'default',
title: 'Panel 7',
position: { referencePanel: 'panel_6', direction: 'right' },
});
event.api.addPanel({
id: 'panel_8',
component: 'default',
title: 'Panel 8',
position: { referencePanel: 'panel_7', direction: 'within' },
});
};
return (
<DockviewReact
components={components}
onReady={onReady}
className="dockview-theme-dark"
/>
);
};

View File

@ -0,0 +1,104 @@
import {
IPaneviewPanelProps,
PaneviewReact,
PaneviewReadyEvent,
} from 'dockview';
import * as React from 'react';
const components = {
default: (props: IPaneviewPanelProps<{ title: string }>) => {
return (
<div
style={{
padding: '10px',
height: '100%',
backgroundColor: 'rgb(60,60,60)',
}}
>
{props.params.title}
</div>
);
},
};
const MyHeaderComponent = (props: IPaneviewPanelProps<{ title: string }>) => {
const [expanded, setExpanded] = React.useState<boolean>(
props.api.isExpanded
);
React.useEffect(() => {
const disposable = props.api.onDidExpansionChange((event) => {
setExpanded(event.isExpanded);
});
return () => {
disposable.dispose();
};
}, []);
const onClick = () => {
props.api.setExpanded(!expanded);
};
return (
<div
style={{
padding: '0px 8px',
height: '100%',
backgroundColor: 'rgb(60,60,60)',
}}
>
<span>{`Custom header for ${props.title}`}</span>
<button onClick={onClick}>
{expanded ? 'Collapse' : 'Expand'}
</button>
</div>
);
};
const headerComponents = {
myHeaderComponent: MyHeaderComponent,
};
export const CustomHeaderPaneview = () => {
const onReady = (event: PaneviewReadyEvent) => {
event.api.addPanel({
id: 'panel_1',
component: 'default',
headerComponent: 'myHeaderComponent',
params: {
title: 'Panel 1',
},
title: 'Panel 1',
});
event.api.addPanel({
id: 'panel_2',
component: 'default',
headerComponent: 'myHeaderComponent',
params: {
title: 'Panel 2',
},
title: 'Panel 2',
});
event.api.addPanel({
id: 'panel_3',
component: 'default',
headerComponent: 'myHeaderComponent',
params: {
title: 'Panel 3',
},
title: 'Panel 3',
});
};
return (
<PaneviewReact
components={components}
headerComponents={headerComponents}
onReady={onReady}
className="dockview-theme-dark"
/>
);
};

View File

@ -0,0 +1,102 @@
import {
IPaneviewPanelProps,
PaneviewDropEvent,
PaneviewReact,
PaneviewReadyEvent,
} from 'dockview';
import * as React from 'react';
const components = {
default: (props: IPaneviewPanelProps<{ title: string }>) => {
return (
<div
style={{
padding: '10px',
height: '100%',
backgroundColor: 'rgb(60,60,60)',
}}
>
{props.params.title}
</div>
);
},
};
export const DragAndDropPaneview = () => {
const onReady = (event: PaneviewReadyEvent) => {
event.api.addPanel({
id: 'panel_1',
component: 'default',
params: {
title: 'Panel 1',
},
title: 'Panel 1',
});
event.api.addPanel({
id: 'panel_2',
component: 'default',
params: {
title: 'Panel 2',
},
title: 'Panel 2',
});
event.api.addPanel({
id: 'panel_3',
component: 'default',
params: {
title: 'Panel 3',
},
title: 'Panel 3',
});
};
const onDidDrop = (event: PaneviewDropEvent) => {
const index = event.api.panels.indexOf(event.panel);
event.api.addPanel({
id: 'panel_4',
component: 'default',
params: {
title: 'Panel 4',
},
title: 'Panel 4',
index,
});
};
return (
<div>
<div>
<div
style={{
backgroundColor: 'orange',
padding: '0px 8px',
borderRadius: '4px',
width: '100px',
cursor: 'pointer',
}}
draggable={true}
>
Drag me
</div>
</div>
<div
style={{
height: '300px',
backgroundColor: 'rgb(30,30,30)',
color: 'white',
margin: '20px 0px',
}}
>
<PaneviewReact
components={components}
onReady={onReady}
onDidDrop={onDidDrop}
className="dockview-theme-dark"
/>
</div>
</div>
);
};

View File

@ -6,13 +6,13 @@
/* You can override the default Infima variables here. */
:root {
--ifm-color-primary: #2e8555;
--ifm-color-primary-dark: #29784c;
--ifm-color-primary-darker: #277148;
--ifm-color-primary-darkest: #205d3b;
--ifm-color-primary-light: #33925d;
--ifm-color-primary-lighter: #359962;
--ifm-color-primary-lightest: #3cad6e;
--ifm-color-primary: #21222c;
--ifm-color-primary-dark: #1e1f28;
--ifm-color-primary-darker: #1c1d25;
--ifm-color-primary-darkest: #17181f;
--ifm-color-primary-light: #242530;
--ifm-color-primary-lighter: #262733;
--ifm-color-primary-lightest: #2b2c39;
--ifm-code-font-size: 95%;
--docusaurus-highlighted-code-line-bg: rgba(0, 0, 0, 0.1);
}
@ -29,4 +29,9 @@
--docusaurus-highlighted-code-line-bg: rgba(0, 0, 0, 0.3);
}
body {
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Ubuntu, Cantarell, Helvetica, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Android Emoji", EmojiSymbols, "EmojiOne Mozilla", "Twemoji Mozilla", "Segoe UI Symbol", "Noto Color Emoji"
html
}
@import "~dockview/dist/styles/dockview.css"

View File

@ -0,0 +1,27 @@
.badge-container {
img:not(:first-child) {
padding-left: 10px;
}
}
.dockview-feature-panel {
max-width: 1000px;
display: flex;
padding: 20px;
justify-content: space-around;
.feature-banner {
.feature-banner-header {
// font-size: 1.25em;
}
.feature-banner-content {
}
}
}
.dockview-feature {
&:nth-child(2n) {
flex-direction: row-reverse;
}
}

View File

@ -5,7 +5,9 @@ import Link from '@docusaurus/Link';
import useDocusaurusContext from '@docusaurus/useDocusaurusContext';
import styles from './index.module.css';
import HomepageFeatures from '@site/src/components/HomepageFeatures';
import { SimpleDockview } from '../components/simpleDockview';
import { DockviewDemo } from '../components/dockview/demo';
import useBaseUrl from '@docusaurus/useBaseUrl';
import './index.scss';
function HomepageHeader() {
const { siteConfig } = useDocusaurusContext();
@ -27,19 +29,46 @@ function HomepageHeader() {
);
}
function HomepageHeader2() {
const { siteConfig } = useDocusaurusContext();
return (
<header className={clsx('hero hero--primary', styles.heroBanner)}>
<div className="container">
<img src={useBaseUrl('/img/dockview_logo.svg')} />
<h1 className="hero__title">{siteConfig.title}</h1>
{/* <div className="badge-container">
<img src="https://badge.fury.io/js/dockview.svg" />
<img src="https://github.com/mathuo/dockview/workflows/CI/badge.svg" />
<img src="https://sonarcloud.io/api/project_badges/measure?project=mathuo_dockview&metric=coverage" />
<img src="https://sonarcloud.io/api/project_badges/measure?project=mathuo_dockview&metric=alert_status" />
</div> */}
<p className="hero__subtitle">{siteConfig.tagline}</p>
<div className={styles.buttons}>
<Link
className="button button--secondary button--lg"
to="/docs"
>
Get Started
</Link>
</div>
</div>
</header>
);
}
export default function Home(): JSX.Element {
const { siteConfig } = useDocusaurusContext();
return (
<Layout
title={`Hello from ${siteConfig.title}`}
description="Description will go into a meta tag in <head />"
title={`${siteConfig.title}`}
description="A zero dependency layout mananger for React."
>
<HomepageHeader />
<HomepageHeader2 />
<main className="container">
<div style={{ height: '500px', padding: '20px 0px' }}>
<SimpleDockview />
<HomepageFeatures />
<div style={{ height: '500px', margin: '20px 0px' }}>
<DockviewDemo />
</div>
{/* <HomepageFeatures /> */}
</main>
</Layout>
);

View File

@ -0,0 +1,45 @@
<svg width="312" height="200" viewBox="0 0 312 200" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect width="311.504" height="200" rx="5" fill="white"/>
<path d="M0 5C0 2.23858 2.23858 0 5 0H307C309.761 0 312 2.23858 312 5V11H0V5Z" fill="#DCDCDC"/>
<rect y="10" width="312" height="1" fill="#BABABA"/>
<rect y="11" width="156" height="189" fill="#A8A8A8"/>
<rect x="156" y="11" width="156" height="91" fill="#000C18"/>
<rect x="234" y="102" width="78" height="98" fill="#000C18"/>
<rect x="156" y="102" width="78" height="98" fill="#000C18"/>
<rect y="24" width="156" height="176" fill="#000C18"/>
<rect x="157" y="102" width="155" height="1" fill="#2B2B4A"/>
<rect width="1" height="189" transform="matrix(-1 0 0 1 157 11)" fill="#2B2B4A"/>
<path d="M234 103H233V200H234V103Z" fill="#2B2B4A"/>
<rect y="11" width="156" height="14" fill="#1C1C2A"/>
<rect y="11" width="30" height="14" fill="#10192C"/>
<rect x="31" y="11" width="30" height="14" fill="#10192C"/>
<rect x="62" y="11" width="30" height="14" fill="#000C18"/>
<rect x="30" y="11" width="1" height="14" fill="#2B2B4A"/>
<rect x="61" y="11" width="1" height="14" fill="#2B2B4A"/>
<rect x="92" y="11" width="1" height="14" fill="#2B2B4A"/>
<rect x="157" y="11" width="155" height="14" fill="#1C1C2A"/>
<rect x="157" y="11" width="30" height="14" fill="#10192C"/>
<rect x="188" y="11" width="30" height="14" fill="#000C18"/>
<rect x="187" y="11" width="1" height="14" fill="#2B2B4A"/>
<rect x="218" y="11" width="1" height="14" fill="#2B2B4A"/>
<rect x="234" y="103" width="78" height="14" fill="#1C1C2A"/>
<rect x="234" y="103" width="24" height="14" fill="#10192C"/>
<rect x="258" y="103" width="24" height="14" fill="#000C18"/>
<rect x="258" y="103" width="0.503226" height="14" fill="#2B2B4A"/>
<rect x="282" y="103" width="0.503226" height="14" fill="#2B2B4A"/>
<rect x="66" y="16" width="7" height="4" rx="2" fill="white"/>
<rect x="76" y="16" width="12" height="4" rx="2" fill="white"/>
<rect x="191" y="16" width="12" height="4" rx="2" fill="#777777"/>
<rect x="260" y="108" width="7" height="4" rx="2" fill="#777777"/>
<rect x="268" y="108" width="11" height="4" rx="2" fill="#777777"/>
<rect x="206" y="16" width="4" height="4" rx="2" fill="#777777"/>
<rect x="160" y="16" width="5" height="4" rx="2" fill="#282828"/>
<rect x="166" y="16" width="16" height="4" rx="2" fill="#282828"/>
<rect x="237" y="108" width="16" height="4" rx="2" fill="#282828"/>
<rect x="33" y="16" width="15" height="4" rx="2" fill="#777777"/>
<rect x="4" y="3" width="4" height="4" rx="2" fill="#FD605E"/>
<rect x="10" y="3" width="4" height="4" rx="2" fill="#FBBC3F"/>
<rect x="16" y="3" width="4" height="4" rx="2" fill="#34C942"/>
<rect x="2" y="16" width="6" height="4" rx="2" fill="#777777"/>
<rect x="10" y="16" width="18" height="4" rx="2" fill="#777777"/>
</svg>

After

Width:  |  Height:  |  Size: 2.8 KiB

View File

@ -0,0 +1,51 @@
<svg width="312" height="200" viewBox="0 0 312 200" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect width="311.504" height="200" rx="5" fill="white"/>
<path d="M0 5C0 2.23858 2.23858 0 5 0H307C309.761 0 312 2.23858 312 5V11H0V5Z" fill="#DCDCDC"/>
<rect y="10" width="312" height="1" fill="#BABABA"/>
<rect y="11" width="156" height="189" fill="#A8A8A8"/>
<rect x="156" y="11" width="156" height="91" fill="#000C18"/>
<rect x="234" y="102" width="78" height="98" fill="#000C18"/>
<rect x="156" y="102" width="78" height="98" fill="#000C18"/>
<rect y="24" width="156" height="176" fill="#000C18"/>
<rect x="157" y="102" width="155" height="1" fill="#2B2B4A"/>
<rect width="1" height="189" transform="matrix(-1 0 0 1 157 11)" fill="#2B2B4A"/>
<path d="M234 103H233V200H234V103Z" fill="#2B2B4A"/>
<rect y="11" width="156" height="14" fill="#1C1C2A"/>
<rect y="11" width="30" height="14" fill="#10192C"/>
<rect x="31" y="11" width="30" height="14" fill="#10192C"/>
<rect x="62" y="11" width="30" height="14" fill="#000C18"/>
<rect x="30" y="11" width="1" height="14" fill="#2B2B4A"/>
<rect x="61" y="11" width="1" height="14" fill="#2B2B4A"/>
<rect x="92" y="11" width="1" height="14" fill="#2B2B4A"/>
<rect x="157" y="11" width="155" height="14" fill="#1C1C2A"/>
<rect x="157" y="11" width="30" height="14" fill="#10192C"/>
<rect x="188" y="11" width="30" height="14" fill="#000C18"/>
<rect x="187" y="11" width="1" height="14" fill="#2B2B4A"/>
<rect x="218" y="11" width="1" height="14" fill="#2B2B4A"/>
<rect x="234" y="103" width="78" height="14" fill="#1C1C2A"/>
<rect x="234" y="103" width="24" height="14" fill="#10192C"/>
<rect x="258" y="103" width="24" height="14" fill="#000C18"/>
<rect x="258" y="103" width="0.503226" height="14" fill="#2B2B4A"/>
<rect x="282" y="103" width="0.503226" height="14" fill="#2B2B4A"/>
<rect x="66" y="16" width="7" height="4" rx="2" fill="white"/>
<rect x="76" y="16" width="12" height="4" rx="2" fill="white"/>
<rect x="191" y="16" width="12" height="4" rx="2" fill="#777777"/>
<rect x="260" y="108" width="7" height="4" rx="2" fill="#777777"/>
<rect x="268" y="108" width="11" height="4" rx="2" fill="#777777"/>
<rect x="206" y="16" width="4" height="4" rx="2" fill="#777777"/>
<rect x="160" y="16" width="5" height="4" rx="2" fill="#282828"/>
<rect x="166" y="16" width="16" height="4" rx="2" fill="#282828"/>
<rect x="237" y="108" width="16" height="4" rx="2" fill="#282828"/>
<rect x="33" y="16" width="15" height="4" rx="2" fill="#777777"/>
<rect x="4" y="3" width="4" height="4" rx="2" fill="#FD605E"/>
<rect x="10" y="3" width="4" height="4" rx="2" fill="#FBBC3F"/>
<rect x="16" y="3" width="4" height="4" rx="2" fill="#34C942"/>
<rect x="2" y="16" width="6" height="4" rx="2" fill="#777777"/>
<rect x="10" y="16" width="18" height="4" rx="2" fill="#777777"/>
<rect x="157" y="61" width="155" height="41" fill="#E1E1E1" fill-opacity="0.25"/>
<rect x="172.5" y="68.5" width="29" height="13" fill="#000C18" stroke="#2B2B4A"/>
<rect x="176" y="73" width="7" height="4" rx="2" fill="white"/>
<rect x="187" y="73" width="12" height="4" rx="2" fill="white"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M201.344 83.2654C201.52 83.1426 201.51 82.8799 201.327 82.77L197.18 80.2905C196.961 80.1595 196.691 80.3492 196.739 80.5997L197.651 85.344C197.691 85.5542 197.935 85.653 198.11 85.5302L198.772 85.067C198.867 85.0002 198.914 84.8836 198.892 84.7693L198.602 83.2612C198.554 83.0106 198.825 82.821 199.044 82.952L200.362 83.7401C200.462 83.7999 200.588 83.7954 200.683 83.7286L201.344 83.2654Z" fill="white"/>
<rect x="200.5" y="84.5" width="4" height="2" stroke="white" stroke-dasharray="0.25 0.25"/>
</svg>

After

Width:  |  Height:  |  Size: 3.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 279 KiB

View File

@ -0,0 +1,60 @@
<svg width="232" height="232" viewBox="0 0 232 232" fill="none" xmlns="http://www.w3.org/2000/svg">
<g filter="url(#filter0_i_9_129)">
<path d="M186.777 80.7107L151.421 116.066L84.2462 48.8909C82.2936 46.9383 82.2936 43.7724 84.2462 41.8198L98.3883 27.6777C108.151 17.9146 123.981 17.9146 133.744 27.6777L186.777 80.7107Z" fill="url(#paint0_linear_9_129)"/>
</g>
<g filter="url(#filter1_i_9_129)">
<path d="M186.777 151.421L151.421 116.066L84.2462 183.241C82.2936 185.194 82.2936 188.36 84.2462 190.312L98.3883 204.454C108.151 214.218 123.981 214.218 133.744 204.454L186.777 151.421Z" fill="url(#paint1_linear_9_129)"/>
</g>
<g filter="url(#filter2_i_9_129)">
<path fill-rule="evenodd" clip-rule="evenodd" d="M204.454 133.744L186.777 151.421L169.099 133.744L151.421 116.066L169.099 98.3884C178.862 88.6253 178.862 72.7961 169.099 63.033L186.777 80.7107L204.454 98.3884C214.217 108.151 214.217 123.981 204.454 133.744Z" fill="url(#paint2_linear_9_129)"/>
</g>
<rect x="20" y="20" width="50" height="192" rx="15" fill="url(#paint3_linear_9_129)"/>
<defs>
<filter id="filter0_i_9_129" x="82.7817" y="20.3553" width="103.995" height="99.7107" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
<feBlend mode="normal" in="SourceGraphic" in2="BackgroundImageFix" result="shape"/>
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
<feOffset dy="4"/>
<feGaussianBlur stdDeviation="2"/>
<feComposite in2="hardAlpha" operator="arithmetic" k2="-1" k3="1"/>
<feColorMatrix type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.25 0"/>
<feBlend mode="normal" in2="shape" result="effect1_innerShadow_9_129"/>
</filter>
<filter id="filter1_i_9_129" x="82.7817" y="116.066" width="103.995" height="99.7107" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
<feBlend mode="normal" in="SourceGraphic" in2="BackgroundImageFix" result="shape"/>
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
<feOffset dy="4"/>
<feGaussianBlur stdDeviation="2"/>
<feComposite in2="hardAlpha" operator="arithmetic" k2="-1" k3="1"/>
<feColorMatrix type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.25 0"/>
<feBlend mode="normal" in2="shape" result="effect1_innerShadow_9_129"/>
</filter>
<filter id="filter2_i_9_129" x="151.421" y="63.0331" width="60.3553" height="92.3883" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
<feBlend mode="normal" in="SourceGraphic" in2="BackgroundImageFix" result="shape"/>
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
<feOffset dy="4"/>
<feGaussianBlur stdDeviation="2"/>
<feComposite in2="hardAlpha" operator="arithmetic" k2="-1" k3="1"/>
<feColorMatrix type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.25 0"/>
<feBlend mode="normal" in2="shape" result="effect1_innerShadow_9_129"/>
</filter>
<linearGradient id="paint0_linear_9_129" x1="186.777" y1="80.7107" x2="80.7107" y2="45.3554" gradientUnits="userSpaceOnUse">
<stop stop-color="#0469C2"/>
<stop offset="1" stop-color="#034DC3"/>
</linearGradient>
<linearGradient id="paint1_linear_9_129" x1="186.777" y1="151.421" x2="80.7107" y2="186.777" gradientUnits="userSpaceOnUse">
<stop offset="0.00126552" stop-color="#38AFF5"/>
<stop offset="1" stop-color="#069CEF"/>
</linearGradient>
<linearGradient id="paint2_linear_9_129" x1="222.132" y1="116.066" x2="151.421" y2="116.066" gradientUnits="userSpaceOnUse">
<stop stop-color="#10B1EE"/>
<stop offset="1" stop-color="#0B8CE7"/>
</linearGradient>
<linearGradient id="paint3_linear_9_129" x1="45" y1="20" x2="69.8621" y2="211.48" gradientUnits="userSpaceOnUse">
<stop stop-color="#18A3F2"/>
<stop offset="1" stop-color="#0349AB"/>
</linearGradient>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 3.9 KiB

View File

@ -0,0 +1,45 @@
<svg width="312" height="200" viewBox="0 0 312 200" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M0 5C0 2.23858 2.23858 0 5 0H307C309.761 0 312 2.23858 312 5V11H0V5Z" fill="#DCDCDC"/>
<rect y="10" width="312" height="1" fill="#BABABA"/>
<rect x="4" y="3" width="4" height="4" rx="2" fill="#FD605E"/>
<rect x="10" y="3" width="4" height="4" rx="2" fill="#FBBC3F"/>
<rect x="16" y="3" width="4" height="4" rx="2" fill="#34C942"/>
<rect y="11" width="312" height="189" fill="#D9D9D9"/>
<rect y="11" width="166" height="189" fill="#000C18"/>
<rect x="167" y="11" width="145" height="189" fill="#000C18"/>
<rect x="166" y="11" width="1" height="189" fill="#2B2B4A"/>
<rect x="167" y="56" width="145" height="1" fill="#2B2B4A"/>
<rect x="167" y="112" width="145" height="1" fill="#2B2B4A"/>
<rect y="11" width="166" height="10" fill="#1C1C2A"/>
<rect y="22" width="166" height="10" fill="#1C1C2A"/>
<rect y="94" width="166" height="10" fill="#1C1C2A"/>
<rect y="190" width="166" height="10" fill="#1C1C2A"/>
<rect y="21" width="166" height="1" fill="#2B2B4A"/>
<rect x="11" y="14" width="21" height="4" rx="2" fill="white"/>
<rect x="34" y="14" width="11" height="4" rx="2" fill="white"/>
<rect x="11" y="25" width="6" height="4" rx="2" fill="white"/>
<rect x="19" y="25" width="11" height="4" rx="2" fill="white"/>
<rect x="11" y="97" width="16" height="4" rx="2" fill="white"/>
<rect x="29" y="97" width="5" height="4" rx="2" fill="white"/>
<rect x="11" y="193" width="14" height="4" rx="2" fill="white"/>
<path d="M5 29L2 25.6078L2.5375 25L5 27.7986L7.4625 25.0141L8 25.6219L5 29Z" fill="white"/>
<path d="M5 101L2 97.6078L2.5375 97L5 99.7986L7.4625 97.0141L8 97.6219L5 101Z" fill="white"/>
<path d="M6 16L2.60777 19L2 18.4625L4.79859 16L2.01413 13.5375L2.62191 13L6 16Z" fill="white"/>
<path d="M6 195L2.60777 198L2 197.463L4.79859 195L2.01413 192.538L2.62191 192L6 195Z" fill="white"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M212.674 111C212.91 111 213.068 110.779 212.971 110.584L210.797 106.175C210.682 105.942 210.318 105.942 210.203 106.175L208.029 110.584C207.932 110.779 208.09 111 208.326 111H209.215C209.343 111 209.46 110.932 209.512 110.825L210.203 109.424C210.318 109.191 210.682 109.191 210.797 109.424L211.488 110.825C211.54 110.932 211.657 111 211.785 111H212.674Z" fill="white"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M208.326 114C208.09 114 207.932 114.221 208.029 114.416L210.203 118.825C210.318 119.058 210.682 119.058 210.797 118.825L212.971 114.416C213.068 114.221 212.91 114 212.674 114H211.785C211.657 114 211.54 114.068 211.488 114.175L210.797 115.576C210.682 115.809 210.318 115.809 210.203 115.576L209.512 114.175C209.46 114.068 209.343 114 209.215 114H208.326Z" fill="white"/>
<line x1="210.5" y1="116" x2="210.5" y2="109" stroke="white"/>
<rect x="175" y="18" width="20" height="19" rx="2" fill="#777777"/>
<rect x="198" y="18" width="5" height="5" rx="2" fill="#777777"/>
<rect x="206" y="18" width="26" height="5" rx="2" fill="#777777"/>
<rect x="203" y="71" width="44" height="5" rx="2" fill="#777777"/>
<rect x="228" y="78" width="44" height="14" rx="2" fill="#777777"/>
<rect x="250" y="71" width="22" height="5" rx="2" fill="#777777"/>
<rect x="239" y="95" width="33" height="5" rx="2" fill="#777777"/>
<rect x="272" y="117" width="33" height="5" rx="2" fill="#777777"/>
<rect x="259" y="117" width="7" height="5" rx="2" fill="#777777"/>
<rect x="213" y="95" width="23" height="5" rx="2" fill="#777777"/>
<rect x="203" y="95" width="8" height="5" rx="2" fill="#777777"/>
<rect x="198" y="25" width="15" height="5" rx="2" fill="#777777"/>
<rect x="215" y="25" width="18" height="5" rx="2" fill="#777777"/>
</svg>

After

Width:  |  Height:  |  Size: 3.6 KiB

View File

@ -0,0 +1,117 @@
---
sidebar_position: 1
---
import { SimpleSplitview } from '@site/src/components/simpleSplitview';
import { SimpleSplitview2 } from '@site/src/components/simpleSplitview2';
# Basics
This section will take you through a number of concepts that can be applied to all dockview components.
## Panels
The below examples use `ReactSplitview` but the logic holds for `ReactPaneview`, `ReactGridview` and `ReactDockview` using their respective implementations and interfaces.
All components require you to provide an `onReady` prop which you can use to build and control your component.
### Adding a panel with parameters
You can pass parameters to a panel through the `params` object
```tsx
const onReady = (event: SplitviewReadyEvent) => {
event.api.addPanel({
id: 'panel_1',
component: 'myComponent',
params: {
title: 'My Title',
},
});
};
```
and you can access those properties through the `props.params` object. The TypeScript interface accepts an optional generic type `T` that corresponds to the params objects type.
```tsx
const MyComponent = (props: ISplitviewPanelProps<{ title: string }>) => {
return <div>{`My first panel has the title: ${props.params.title}`}</div>;
};
```
## API
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 `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 }>) => {
React.useEffect(() => {
const disposable = props.api.onDidActiveChange((event) => {
console.log(`is panel active: ${event.isActive}`);
});
return () => {
disposable.dispose(); // remember to dispose of any subscriptions
};
}, [props.api]);
const addAnotherPanel = React.useCallback(() => {
props.containerApi.addPanel({
id: 'another_id',
component: 'anotherComponent',
});
}, [props.containerApi]);
return (
<div>
<span>{`My first panel has the title: ${props.params.title}`}</span>
<button onClick={addAnotherPanel}>Add Panel</button>
</div>
);
};
```
### Serialization
All components support `toJSON(): T` which returns a Typed object representation of the components state. This same Typed object can be used to deserialize a view using `fromJSON(object: T): void`.
## 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) 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
The `proportionalLayout` property indicates the expected behaviour of the component as it's container resizes, should all views resize equally or should just one view expand to fill the new space. `proportionalLayout` can be set as a property on `SplitviewReact` and `GridviewReact` components.
Although not configurable on `DockviewReact` and `PaneviewReact` these both behave as if `proportionalLayout=true` was set for them.
<SimpleSplitview2 proportional={false} />
<SimpleSplitview2 proportional={true} />
## 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).

View File

@ -0,0 +1,9 @@
{
"label": "Components",
"collapsible": true,
"collapsed": false,
"link": {
"type": "generated-index",
"title": "Components"
},
}

View File

@ -0,0 +1,294 @@
import { SimpleDockview } from '@site/src/components/simpleDockview';
import {
RenderingDockview,
Checkbox,
} from '@site/src/components/dockview/rendering';
import { DndDockview } from '@site/src/components/dockview/dnd';
import { EventsDockview } from '@site/src/components/dockview/events';
import { ContextMenuDockview } from '@site/src/components/dockview/contextMenu';
import Link from '@docusaurus/Link';
# Dockview
## Introduction
Dockview is an abstraction built on top of [Gridviews](./gridview) where each view is a container of many tabbed panels.
<div
style={{
height: '300px',
backgroundColor: 'rgb(30,30,30)',
color: 'white',
margin: '20px 0px',
}}
>
<SimpleDockview />
</div>
You can access the panels associated group through the `panel.group` variable.
The group will always be defined and will change if a panel is moved into another group.
## DockviewReact Component
You can create a Dockview through the use of the `ReactDockview` component.
```tsx
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 <Link to="../basics/#auto-resizing">Auto Resizing</Link> |
| onTabContextMenu | Event | Yes | false | |
| onDidDrop | Event | Yes | false | |
| showDndOverlay | Event | Yes | false | |
## Dockview API
The Dockview API is exposed both at the `onReady` event and on each panel through `props.containerApi`.
Through this API you can control general features of the component and access all added panels.
```tsx title="Dockview API via Panel component"
const MyComponent = (props: IDockviewPanelProps<{ title: string }>) => {
// props.containerApi...
return <div>{`My first panel has the title: ${props.params.title}`}</div>;
};
```
```tsx title="Dockview API via the onReady callback"
const onReady = (event: DockviewReadyEvent) => {
// event.api...
};
```
| 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<void>` | |
| onDidLayoutFromJSON | `Event<void>` | |
| onDidAddGroup | `Event<GroupPanel>` | |
| onDidRemoveGroup | `Event<GroupPanel>` | |
| onDidActiveGroupChange | `Event<GroupPanel \| undefined>` | |
| onDidAddPanel | `Event<IDockviewPanel>` | |
| onDidRemovePanel | `Event<IDockviewPanel>` | |
| onDidActivePanelChange | `Event<IDockviewPanel \| undefined>` | |
| onDidDrop | `Event<DockviewDropEvent` | |
| | | |
| addPanel | `addPanel(options: AddPanelOptions): IDockviewPanel` | |
| getPanel | `(id: string) \| IDockviewPanel \| undefined` | |
| addEmptyGroup | `(options? AddGroupOptions): void` | |
| closeAllGroups | `(): void` | |
| removeGroup | `(group: GroupPanel): void` | |
| getGroup | `(id: string): GroupPanel \| undefined` | |
| | | |
| getTabHeight | `(): number \| undefined` | |
| setTabHeight | `(hegiht: number \| undefined): void` | |
| updateOptions | `(options:SplitviewComponentUpdateOptions): void` | |
| focus | `(): void` | |
| layout | `(width: number, height:number): void` | <Link to="../basics/#auto-resizing">Auto Resizing</Link> |
| fromJSON | `(data: SerializedDockview): void` | <Link to="../basics/#serialization">Serialization</Link> |
| toJSON | `(): SerializedDockview` | <Link to="../basics/#serialization">Serialization</Link> |
| clear | `(): void` | Clears the current layout |
## Dockview Panel API
```tsx
const MyComponent = (props: IDockviewPanelProps<{ title: string }>) => {
// props.api...
return <div>{`My first panel has the title: ${props.params.title}`}</div>;
};
```
| Property | Type | Description |
| ---------------------- | ----------------------------------------------------------- | --------------- |
| id | `string` | Panel id |
| isFocused | `boolean` | Is panel focsed |
| isActive | `boolean` | Is panel active |
| width | `number` | Panel width |
| height | `number` | Panel height |
| onDidDimensionsChange | `Event<PanelDimensionChangeEvent>` | |
| onDidFocusChange | `Event<FocusEvent>` | |
| onDidVisibilityChange | `Event<VisibilityEvent>` | |
| onDidActiveChange | `Event<ActiveEvent>` | |
| setActive | `(): void` | |
| | | |
| onDidConstraintsChange | `onDidConstraintsChange: Event<PanelConstraintChangeEvent>` | |
| setConstraints | `(value: PanelConstraintChangeEvent2): void;` | |
| setSize | `(event: SizeEvent): void` | |
| | | |
| group | `GroupPanel | undefined` |
| isGroupActive | `boolean` | |
| title | `string` | |
| suppressClosable | `boolean` | |
| close | `(): void` | |
| setTitle | `(title: string): void` | |
## Advanced Features
### Locked group
Locking a group will disable all drop events for this group ensuring a user can not add additional panels to the group.
You can still add groups to a locked panel programatically using the API.
```tsx
panel.group.locked = true;
```
### Group header
You may wish to hide the header section of a group. This can achieved through setting the `hidden` variable on `panel.group.header`.
```tsx
panel.group.header.hidden = true;
```
### Context Menu
Since overriding the context menu is a such a common feature rather than defining a custom tab the `ReactDockview` component exposes the prop `onTabContextMenu`.
You can alternatively define a custom tab component for more granular control.
:::caution
The `onTabContextMenu` is intended to be removed in a future release to further simplify the library.
In the future you will be required to define a custom tab component to intercept the context menu events.
:::
<div
style={{
height: '300px',
backgroundColor: 'rgb(30,30,30)',
color: 'white',
margin: '20px 0px',
}}
>
<ContextMenuDockview />
</div>
### Rendering
Although `DockviewReact` will only add those tabs that are visible to the DOM all associated React Components for each tab including those that
are not initially visible will be created.
This will mean that any hooks in those components will run and if you running expensive operations in the tabs you may end up doing a lot of initial
work for what are hidden tabs.
This is the default behaviour to ensure the greatest flexibility for the user but you can create a Higher-Order component wrapping your components that
will ensure the component is only created if the tab is visible as below:
```tsx
import { PanelApi } from 'dockview';
import * as React from 'react';
function RenderWhenVisible<
T extends { api: Pick<PanelApi, 'isVisible' | 'onDidVisibilityChange'> }
>(component: React.FunctionComponent<T>) {
const HigherOrderComponent = (props: T) => {
const [visible, setVisible] = React.useState<boolean>(
props.api.isVisible
);
React.useEffect(() => {
const disposable = props.api.onDidVisibilityChange((event) =>
setVisible(event.isVisible)
);
return () => {
disposable.dispose();
};
}, [props.api]);
if (!visible) {
return null;
}
return React.createElement(component, props);
};
return HigherOrderComponent;
}
```
```tsx
const component = RenderWhenVisible(MyComponent);
```
Through toggling the checkbox you can see that when you only render those panels which are visible the underling React component is destroyed when it becomes hidden and re-created when it becomes visible.
<Checkbox />
<div
style={{
height: '300px',
backgroundColor: 'rgb(30,30,30)',
color: 'white',
margin: '20px 0px',
}}
>
<RenderingDockview renderVisibleOnly={false} />
</div>
### Drag And Drop
The component exposes some method to help determine whether external drag events should be interacted with or not.
```tsx
/**
* called when an ondrop event which does not originate from the dockview libray and
* passes the showDndOverlay condition occurs
**/
const onDidDrop = (event: DockviewDropEvent) => {
const { group } = event;
event.api.addPanel({
id: 'test',
component: 'default',
position: {
referencePanel: group.activePanel.id,
direction: 'within',
},
});
};
/**
* called for drag over events which do not originate from the dockview library
* allowing the developer to decide where the overlay should be shown for a
* particular drag event
**/
const showDndOverlay = (event: DockviewDndOverlayEvent) => {
return true;
};
return (
<DockviewReact
components={components}
onReady={onReady}
className="dockview-theme-dark"
onDidDrop={onDidDrop}
showDndOverlay={showDndOverlay}
/>
);
```
<DndDockview />
### Events
<EventsDockview />

View File

@ -0,0 +1,116 @@
import { SimpleGridview } from '@site/src/components/simpleGridview';
import { EventsGridview } from '@site/src/components/gridview/events';
import Link from '@docusaurus/Link';
# Gridview
## Introduction
<div
style={{
height: '300px',
backgroundColor: 'rgb(30,30,30)',
color: 'white',
margin: '20px 0px',
}}
>
<SimpleGridview />
</div>
## GridviewReact Component
```tsx
import { ReactGridview } from 'dockview';
```
| Property | Type | Optional | Default | Description |
| ------------------- | ------------------------------------ | -------- | ---------------------- | ------------------------------------------------------------------------ |
| onReady | (event: SplitviewReadyEvent) => void | No | | |
| components | object | No | | |
| orientation | Orientation | Yes | Orientation.HORIZONTAL | |
| proportionalLayout | boolean | Yes | true | See <Link to="../basics/#proportional-layout">Proportional layout</Link> |
| hideBorders | boolean | Yes | false | |
| className | string | Yes | '' | |
| disableAutoResizing | boolean | Yes | false | See <Link to="../basics/#auto-resizing">Auto Resizing</Link> |
## Gridview API
```tsx
const MyComponent = (props: IGridviewPanelProps<{ title: string }>) => {
// props.containerApi...
return <div>{`My first panel has the title: ${props.params.title}`}</div>;
};
```
```tsx
const onReady = (event: GridviewReadyEvent) => {
// event.api...
};
```
| 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<void>` | Fires on layout change |
| onDidLayoutFromJSON | `Event<void>` | Fires of layout change caused by a fromJSON deserialization call |
| onDidAddPanel | `Event<IGridviewPanel>` | Fires when a view is added |
| onDidRemovePanel | `Event<IGridviewPanel>` | Fires when a view is removed |
| onDidActivePanelChange | `Event<IGridviewPanel \| undefined>` | 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` | <Link to="../basics/#auto-resizing">Auto Resizing</Link> |
| fromJSON | `(data: SerializedGridview): void` | <Link to="../basics/#serialization">Serialization</Link> |
| toJSON | `(): SerializedGridview` | <Link to="../basics/#serialization">Serialization</Link> |
| clear | `(): void` | Clears the current layout |
## Gridview Panel API
```tsx
const MyComponent = (props: IGridviewPanelProps<{ title: string }>) => {
// props.api...
return <div>{`My first panel has the title: ${props.params.title}`}</div>;
};
```
| 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<PanelDimensionChangeEvent>` | |
| onDidFocusChange | `Event<FocusEvent>` | |
| onDidVisibilityChange | `Event<VisibilityEvent>` | |
| onDidActiveChange | `Event<ActiveEvent>` | |
| onDidConstraintsChange | `onDidConstraintsChange: Event<PanelConstraintChangeEvent>` | |
| | | |
| setVisible | `(isVisible: boolean): void` | |
| setActive | `(): void` | |
| setConstraints | `(value: PanelConstraintChangeEvent2): void;` | |
| setSize | `(event: SizeEvent): void` | |
## Events
`GridviewReact` exposes a number of events that the developer can listen to and below is a simple example with a log panel showing those events that occur.
<EventsGridview />

View File

@ -0,0 +1,270 @@
import { SimplePaneview } from '@site/src/components/simplePaneview';
import { CustomHeaderPaneview } from '@site/src/components/paneview/customHeader';
import { DragAndDropPaneview } from '@site/src/components/paneview/dragAndDrop';
import Link from '@docusaurus/Link';
# Paneview
A paneview is a collapsed collection of vertically stacked panels and panel headers.
The panel header will always remain visible however the panel will only be visible when the panel is expanded.
:::info
Paneview panels can be re-ordered by dragging and dropping the panel headers.
:::
---
# Introduction
<div
style={{
height: '400px',
backgroundColor: 'rgb(30,30,30)',
color: 'white',
margin: '20px 0px',
}}
>
<SimplePaneview />
</div>
```tsx title="Simple Paneview example"
import {
IPaneviewPanelProps,
PaneviewReact,
PaneviewReadyEvent,
} from 'dockview';
const components = {
default: (props: IPaneviewPanelProps<{ title: string }>) => {
return (
<div
style={{
padding: '10px',
height: '100%',
backgroundColor: 'rgb(60,60,60)',
}}
>
{props.params.title}
</div>
);
},
};
SimplePaneview = () => {
const onReady = (event: PaneviewReadyEvent) => {
event.api.addPanel({
id: 'panel_1',
component: 'default',
params: {
title: 'Panel 1',
},
title: 'Panel 1',
});
event.api.addPanel({
id: 'panel_2',
component: 'default',
params: {
title: 'Panel 2',
},
title: 'Panel 2',
});
event.api.addPanel({
id: 'panel_3',
component: 'default',
params: {
title: 'Panel 3',
},
title: 'Panel 3',
});
};
return (
<PaneviewReact
components={components}
headerComponents={headerComponents}
onReady={onReady}
className="dockview-theme-dark"
/>
);
};
```
## PaneviewReact Component
You can create a Paneview through the use of the `ReactPaneview` component.
```tsx
import { ReactPaneview } from 'dockview';
```
| Property | Type | Optional | Default | Description |
| ------------------- | ------------------------------------ | -------- | ------- | -------------------------------------------------------- |
| onReady | (event: SplitviewReadyEvent) => void | No | | |
| components | object | No | | |
| headerComponents | object | Yes | | |
| className | string | Yes | '' | |
| disableAutoResizing | boolean | Yes | false | <Link to="../basics/#auto-resizing">Auto Resizing</Link> |
| disableDnd | boolean | Yes | false | |
| onDidDrop | Event | Yes | | |
## Paneview API
The Paneview API is exposed both at the `onReady` event and on each panel through `props.containerApi`.
Through this API you can control general features of the component and access all added panels.
```tsx title="Paneview API via Panel component"
const MyComponent = (props: IGridviewPanelProps<{ title: string }>) => {
// props.containerApi...
return <div>{`My first panel has the title: ${props.params.title}`}</div>;
};
```
```tsx title="Paneview API via the onReady callback"
const onReady = (event: GridviewReadyEvent) => {
// event.api...
};
```
| 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 | `IPaneviewPanel[]` | All panels |
| | | |
| onDidLayoutChange | `Event<void>` | Fires on layout change |
| onDidLayoutFromJSON | `Event<void>` | Fires of layout change caused by a fromJSON deserialization call |
| onDidAddView | `Event<IPaneviewPanel>` | Fires when a view is added |
| onDidRemoveView | `Event<IPaneviewPanel>` | Fires when a view is removed |
| onDidDrop | `Event<PaneviewDropEvent` | Fires on an external drop event (See <Link to="./paneview/#drag-and-drop">Drag and Drop</Link>) |
| | | |
| 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 <Link to="../basics/#auto-resizing">Auto Resizing</Link> |
| fromJSON | `(data: SerializedPaneview): void` | <Link to="../basics/#serialization">Serialization</Link> |
| toJSON | `(): SerializedPaneview` | <Link to="../basics/#serialization">Serialization</Link> |
| clear | `(): void` | Clears the current layout |
## Paneview Panel API
```tsx
const MyComponent = (props: IGridviewPanelProps<{ title: string }>) => {
// props.api...
return <div>{`My first panel has the title: ${props.params.title}`}</div>;
};
```
| 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<PanelDimensionChangeEvent>` | |
| onDidFocusChange | `Event<FocusEvent>` | |
| onDidVisibilityChange | `Event<VisibilityEvent>` | |
| onDidActiveChange | `Event<ActiveEvent>` | |
| onDidConstraintsChange | `onDidConstraintsChange: Event<PanelConstraintChangeEvent>` | |
| | |
| setVisible | `(isVisible: boolean): void` | |
| setActive | `(): void` | |
| setConstraints | `(value: PanelConstraintChangeEvent2): void;` | |
| setSize | `(event: SizeEvent): void` | |
## Advanced Features
### Custom Header
You can provide a custom component to render an alternative header.
<div
style={{
height: '400px',
backgroundColor: 'rgb(30,30,30)',
color: 'white',
margin: '20px 0px',
}}
>
<CustomHeaderPaneview />
</div>
You can provide a `headerComponent` option when creating a panel to tell the library to use a custom header component.
```tsx
const onReady = (event: PaneviewReadyEvent) => {
event.api.addPanel({
id: 'panel_1',
component: 'default',
headerComponent: 'myHeaderComponent',
params: {
valueA: 'A',
},
title: 'Panel 1',
});
};
```
This header must be defined in the collection of components provided to the `headerComponents` props for `ReactPaneivew`
```tsx
import { IPaneviewPanelProps } from 'dockview';
const MyHeaderComponent = (props: IPaneviewPanelProps<{ title: string }>) => {
const [expanded, setExpanded] = React.useState<boolean>(
props.api.isExpanded
);
React.useEffect(() => {
const disposable = props.api.onDidExpansionChange((event) => {
setExpanded(event.isExpanded);
});
return () => {
disposable.dispose();
};
}, []);
const onClick = () => {
props.api.setExpanded(!expanded);
};
return (
<div
style={{
padding: '10px',
height: '100%',
backgroundColor: 'rgb(60,60,60)',
}}
>
<a
onClick={onClick}
className={expanded ? 'expanded' : 'collapsed'}
/>
<span>{props.params.title}</span>
</div>
);
};
const headerComponents = { myHeaderComponent: MyHeaderComponent };
```
### Drag And Drop
If you provide the `PaneviewReact` component with the prop `onDidDrop` you will be able to interact with custom drop events.
<DragAndDropPaneview />

View File

@ -0,0 +1,242 @@
import { SimpleSplitview } from '@site/src/components/simpleSplitview';
import { SplitviewExample1 } from '@site/src/components/splitview/active';
import Link from '@docusaurus/Link';
# Splitview
## Introduction
A Splitview is a collection of resizable horizontally or vertically stacked panels.
<div
style={{
height: '100px',
backgroundColor: 'rgb(30,30,30)',
color: 'white',
margin: '20px 0px',
}}
>
<SimpleSplitview />
</div>
```tsx title="Simple Splitview example"
import {
ISplitviewPanelProps,
Orientation,
SplitviewReact,
SplitviewReadyEvent,
} from 'dockview';
const components = {
default: (props: ISplitviewPanelProps<{ title: string }>) => {
return <div style={{ padding: '20px' }}>{props.params.title}</div>;
},
};
export const SimpleSplitview = () => {
const onReady = (event: SplitviewReadyEvent) => {
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',
},
});
};
return (
<SplitviewReact
components={components}
onReady={onReady}
orientation={Orientation.HORIZONTAL}
className="dockview-theme-dark"
/>
);
};
```
## SplitviewReact Component
You can create a Splitview through the use of the `ReactSplitview` component.
```tsx
import { ReactSplitview } from 'dockview';
```
Using the `onReady` prop you can access to the component `api` and add panels either through deserialization or the individual addition of panels.
| Property | Type | Optional | Default | Description |
| ------------------- | -------------------------------------- | -------- | ------------------------ | ------------------------------------------------------------------------ |
| onReady | `(event: SplitviewReadyEvent) => void` | No | | Function |
| components | `Record<string, ISplitviewPanelProps>` | No | | Panel renderers |
| orientation | `Orientation` | Yes | `Orientation.HORIZONTAL` | Orientation of the Splitview |
| proportionalLayout | `boolean` | Yes | `true` | See <Link to="../basics/#proportional-layout">Proportional layout</Link> |
| hideBorders | `boolean` | Yes | `false` | Hide the borders between panels |
| className | `string` | Yes | `''` | Attaches a classname |
| disableAutoResizing | `boolean` | Yes | `false` | See <Link to="../basics/#auto-resizing">Auto Resizing</Link> |
## Splitview API
The Splitview API is exposed both at the `onReady` event and on each panel through `props.containerApi`.
Through this API you can control general features of the component and access all added panels.
```tsx title="Splitview API via Panel component"
const MyComponent = (props: ISplitviewPanelProps<{ title: string }>) => {
// props.containerApi...
return <div>{`My first panel has the title: ${props.params.title}`}</div>;
};
```
```tsx title="Splitview API via the onReady callback"
const onReady = (event: SplitviewReadyEvent) => {
// event.api...
};
```
| 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<void>` | Fires on layout change |
| onDidLayoutFromJSON | `Event<void>` | Fires of layout change caused by a fromJSON deserialization call |
| onDidAddView | `Event<IView>` | Fires when a view is added |
| onDidRemoveView | `Event<IView>` | 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` | |
| | |
| updateOptions | `(options: SplitviewComponentUpdateOptions): void` | |
| focus | `(): void` | Focus the active panel, if exists |
| layout | `(width: number, height:number): void` | See <Link to="../basics/#auto-resizing">Auto Resizing</Link> |
| fromJSON | `(data: SerializedSplitview): void` | <Link to="../basics/#serialization">Serialization</Link> |
| toJSON | `(): SerializedSplitview` | <Link to="../basics/#serialization">Serialization</Link> |
| clear | `(): void` | Clears the current layout |
## Splitview Panel API
The Splitview panel API is exposed on each panel containing actions and variables specific to that panel.
```tsx title="Splitview panel API via Panel component"
const MyComponent = (props: ISplitviewPanelProps<{ title: string }>) => {
// props.api...
return <div>{`My first panel has the title: ${props.params.title}`}</div>;
};
```
| 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<PanelDimensionChangeEvent>` | Fires when panel dimensions change |
| onDidFocusChange | `Event<FocusEvent>` | Fire when panel is focused and blurred |
| onDidVisibilityChange | `Event<VisibilityEvent>` | Fires when the panels visiblity property is changed (see <Link to="./splitview/#visibility">Panel Visibility</Link>) |
| onDidActiveChange | `Event<ActiveEvent>` | Fires when the panels active property is changed (see <Link to="./splitview/#active">Active Panel</Link>) |
| onDidConstraintsChange | `onDidConstraintsChange: Event<PanelConstraintChangeEvent>` | Fires when the panels size contrainsts change (see <Link to="./splitview/#contraints">Panel Constraints</Link>) |
| | | |
| setVisible | `(isVisible: boolean): void` | |
| setActive | `(): void` | |
| | | |
| setConstraints | `(value: PanelConstraintChangeEvent2): void;` | |
| setSize | `(event: PanelSizeEvent): void` | |
## Advanced Features
Listed below are some functionalities avalaible through both the panel and component APIs. The live demo shows examples of these in real-time.
<div
style={{
height: '200px',
margin: '20px 0px',
}}
>
<SplitviewExample1 />
</div>
### Visibility
A panels visibility can be controlled and monitored through the following code.
A panel with visibility set to `false` will remain as a part of the components list of panels but will not be rendered.
```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,
});
```

View File

@ -0,0 +1,150 @@
---
sidebar_position: 0
---
import { SimpleSplitview } from '@site/src/components/simpleSplitview';
import { SimpleGridview } from '@site/src/components/simpleGridview';
import { SimplePaneview } from '@site/src/components/simplePaneview';
import { SimpleDockview } from '@site/src/components/simpleDockview';
# Dockview
## Introduction
**dockview** is a zero dependency layout manager that supports tab, grids and splitviews.
## Features
- Themable and customizable
- Support for the serialization and deserialization of layouts
- Drag and drop support
## Quick start
`dockview` has a peer dependency on `react >= 16.8.0` and `react-dom >= 16.8.0`. To install `dockview` you can run:
```shell
npm install dockview
```
You must also import the dockview stylesheet found under [`dockview/dict/styles/dockview.css`](https://unpkg.com/browse/dockview@latest/dist/styles/dockview.css),
depending on your solution this might be:
```css
@import './node_modules/dockview/dist/styles/dockview.css';
```
A dark and light theme are provided, one of these classes (or a custom theme) must be attached at any point above your components in the HTML tree. To cover the entire web page you might attach the class to the `body` component:
```html
<body classname="dockview-theme-dark">
...
</body>
<body classname="dockview-theme-light">
...
</body>
```
There are 4 components you may want to use:
Splitview
<div
style={{
height: '100px',
backgroundColor: 'rgb(30,30,30)',
color: 'white',
margin: '20px 0px',
}}
>
<SimpleSplitview />
</div>
<div
style={{
height: '300px',
backgroundColor: 'rgb(30,30,30)',
color: 'white',
margin: '20px 0px',
}}
>
<SimpleGridview />
</div>
<div
style={{
height: '300px',
backgroundColor: 'rgb(30,30,30)',
color: 'white',
margin: '20px 0px',
}}
>
<SimplePaneview />
</div>
<div
style={{
height: '300px',
backgroundColor: 'rgb(30,30,30)',
color: 'white',
margin: '20px 0px',
}}
>
<SimpleDockview />
</div>
```tsx
import {
DockviewReact,
DockviewReadyEvent,
PanelCollection,
IDockviewPanelProps,
IDockviewPanelHeaderProps,
} from 'dockview';
const components: PanelCollection<IDockviewPanelProps> = {
default: (props: IDockviewPanelProps<{ someProps: string }>) => {
return <div>{props.params.someProps}</div>;
},
};
const headers: PanelCollection<IDockviewPanelHeaderProps> = {
customTab: (props: IDockviewPanelHeaderProps) => {
return (
<div>
<span>{props.api.title}</span>
<span onClick={() => props.api.close()}>{'[x]'}</span>
</div>
);
},
};
const Component = () => {
const onReady = (event: DockviewReadyEvent) => {
event.api.addPanel({
id: 'panel1',
component: 'default',
tabComponent: 'customTab', // optional custom header
params: {
someProps: 'Hello',
},
});
event.api.addPanel({
id: 'panel2',
component: 'default',
params: {
someProps: 'World',
},
position: { referencePanel: 'panel1', direction: 'below' },
});
};
return (
<DockviewReact
components={components}
tabComponents={headers} // optional headers renderer
onReady={onReady}
/>
);
};
```

View File

@ -0,0 +1,80 @@
---
sidebar_position: 3
---
import { CustomCSSDockview } from '@site/src/components/dockview/customCss';
# Theme
## Introduction
`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';
```
## Customizing Theme
`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);
}
}
}
```
<div
style={{
height: '300px',
backgroundColor: 'rgb(30,30,30)',
color: 'white',
margin: '20px 0px',
}}
>
<CustomCSSDockview />
</div>

View File

@ -0,0 +1,8 @@
{
"tutorialSidebar": [
{
"type": "autogenerated",
"dirName": "."
}
]
}

View File

@ -0,0 +1,3 @@
[
"1.4.3"
]