chore: update docs (#429)

* chore: 1.9.0 docs
This commit is contained in:
mathuo 2024-01-15 20:03:20 +00:00 committed by GitHub
parent 5ca1cc5e62
commit ffddc95602
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
40 changed files with 1778 additions and 1391 deletions

View File

@ -20,8 +20,10 @@
"/packages/docs/sandboxes/keyboard-dockview", "/packages/docs/sandboxes/keyboard-dockview",
"/packages/docs/sandboxes/layout-dockview", "/packages/docs/sandboxes/layout-dockview",
"/packages/docs/sandboxes/lockedgroup-dockview", "/packages/docs/sandboxes/lockedgroup-dockview",
"/packages/docs/sandboxes/maximizegroup-dockview",
"/packages/docs/sandboxes/nativeapp-dockview", "/packages/docs/sandboxes/nativeapp-dockview",
"/packages/docs/sandboxes/nested-dockview", "/packages/docs/sandboxes/nested-dockview",
"/packages/docs/sandboxes/popoutgroup-dockview",
"/packages/docs/sandboxes/rendering-dockview", "/packages/docs/sandboxes/rendering-dockview",
"/packages/docs/sandboxes/rendermode-dockview", "/packages/docs/sandboxes/rendermode-dockview",
"/packages/docs/sandboxes/resize-dockview", "/packages/docs/sandboxes/resize-dockview",

View File

@ -1,13 +1,14 @@
<div align="center"> <div align="center">
<h1>dockview</h1> <h1>dockview</h1>
<p>Zero dependency layout manager supporting tabs, grids and splitviews with ReactJS support written in TypeScript</p> <p>Zero dependency layout manager supporting tabs, groups, grids and splitviews with ReactJS support written in TypeScript</p>
</div> </div>
--- ---
[![npm version](https://badge.fury.io/js/dockview.svg)](https://www.npmjs.com/package/dockview) [![npm version](https://badge.fury.io/js/dockview.svg)](https://www.npmjs.com/package/dockview)
[![npm](https://img.shields.io/npm/dm/dockview)](https://www.npmjs.com/package/dockview)
[![CI Build](https://github.com/mathuo/dockview/workflows/CI/badge.svg)](https://github.com/mathuo/dockview/actions?query=workflow%3ACI) [![CI Build](https://github.com/mathuo/dockview/workflows/CI/badge.svg)](https://github.com/mathuo/dockview/actions?query=workflow%3ACI)
[![Coverage](https://sonarcloud.io/api/project_badges/measure?project=mathuo_dockview&metric=coverage)](https://sonarcloud.io/summary/overall?id=mathuo_dockview) [![Coverage](https://sonarcloud.io/api/project_badges/measure?project=mathuo_dockview&metric=coverage)](https://sonarcloud.io/summary/overall?id=mathuo_dockview)
[![Quality Gate Status](https://sonarcloud.io/api/project_badges/measure?project=mathuo_dockview&metric=alert_status)](https://sonarcloud.io/summary/overall?id=mathuo_dockview) [![Quality Gate Status](https://sonarcloud.io/api/project_badges/measure?project=mathuo_dockview&metric=alert_status)](https://sonarcloud.io/summary/overall?id=mathuo_dockview)
@ -21,16 +22,20 @@ Please see the website: https://dockview.dev
## Features ## Features
- Simple splitviews, nested splitviews (i.e. gridviews) supporting full layout managment with - Serialization / deserialization with full layout management
dockable and tabular views - Support for split-views, grid-views and 'dockable' views
- Extensive API support at the component level and view level - Themeable and customizable
- Themable and customizable - Tab and Group docking / Drag n' Drop
- Serialization / deserialization support - Popout Windows
- Tabular docking and Drag and Drop support - Floating Groups
- Floating groups, customized header bars and tab - Extensive API
- Documentation and examples - Supports Shadow DOMs
- High test coverage
- Documentation website with live examples
- Transparent builds and Code Analysis
- Security at mind - verifed publishing and builds through GitHub Actions
Want to inspect the latest deployment? Go to https://unpkg.com/browse/dockview@latest/ Want to verify our builds? Go [here](https://www.npmjs.com/package/dockview#Provenance).
## Quick start ## Quick start

View File

@ -8,6 +8,7 @@
--- ---
[![npm version](https://badge.fury.io/js/dockview.svg)](https://www.npmjs.com/package/dockview) [![npm version](https://badge.fury.io/js/dockview.svg)](https://www.npmjs.com/package/dockview)
[![npm](https://img.shields.io/npm/dm/dockview)](https://www.npmjs.com/package/dockview)
[![CI Build](https://github.com/mathuo/dockview/workflows/CI/badge.svg)](https://github.com/mathuo/dockview/actions?query=workflow%3ACI) [![CI Build](https://github.com/mathuo/dockview/workflows/CI/badge.svg)](https://github.com/mathuo/dockview/actions?query=workflow%3ACI)
[![Coverage](https://sonarcloud.io/api/project_badges/measure?project=mathuo_dockview&metric=coverage)](https://sonarcloud.io/summary/overall?id=mathuo_dockview) [![Coverage](https://sonarcloud.io/api/project_badges/measure?project=mathuo_dockview&metric=coverage)](https://sonarcloud.io/summary/overall?id=mathuo_dockview)
[![Quality Gate Status](https://sonarcloud.io/api/project_badges/measure?project=mathuo_dockview&metric=alert_status)](https://sonarcloud.io/summary/overall?id=mathuo_dockview) [![Quality Gate Status](https://sonarcloud.io/api/project_badges/measure?project=mathuo_dockview&metric=alert_status)](https://sonarcloud.io/summary/overall?id=mathuo_dockview)
@ -15,24 +16,30 @@
## ##
![](packages/docs/static/img/splashscreen.gif)
Please see the website: https://dockview.dev Please see the website: https://dockview.dev
## Features ## Features
- Simple splitviews, nested splitviews (i.e. gridviews) supporting full layout managment with - Serialization / deserialization with full layout management
dockable and tabular views - Support for split-views, grid-views and 'dockable' views
- Extensive API support at the component level and view level - Themeable and customizable
- Themable and customizable - Tab and Group docking / Drag n' Drop
- Serialization / deserialization support - Popout Windows
- Tabular docking and Drag and Drop support - Floating Groups
- Floating groups, customized header bars and tab - Extensive API
- Documentation and examples - Supports Shadow DOMs
- High test coverage
- Documentation website with live examples
- Transparent builds and Code Analysis
- Security at mind - verifed publishing and builds through GitHub Actions
Want to inspect the latest deployment? Go to https://unpkg.com/browse/dockview-core@latest/ Want to verify our builds? Go [here](https://www.npmjs.com/package/dockview#Provenance).
## Quick start ## Quick start
You can install dockview-core from [npm](https://www.npmjs.com/package/dockview-core). Dockview has a peer dependency on `react >= 16.8.0` and `react-dom >= 16.8.0`. You can install dockview from [npm](https://www.npmjs.com/package/dockview-core).
``` ```
npm install --save dockview-core npm install --save dockview-core

View File

@ -240,7 +240,7 @@ export function getDomNodePagePosition(domNode: Element): {
export function isInDocument(element: Element): boolean { export function isInDocument(element: Element): boolean {
let currentElement: Element | ParentNode = element; let currentElement: Element | ParentNode = element;
while (currentElement && currentElement.parentNode) { while (currentElement?.parentNode) {
if (currentElement.parentNode === document) { if (currentElement.parentNode === document) {
return true; return true;
} else if (currentElement.parentNode instanceof DocumentFragment) { } else if (currentElement.parentNode instanceof DocumentFragment) {

View File

@ -8,6 +8,7 @@
--- ---
[![npm version](https://badge.fury.io/js/dockview.svg)](https://www.npmjs.com/package/dockview) [![npm version](https://badge.fury.io/js/dockview.svg)](https://www.npmjs.com/package/dockview)
[![npm](https://img.shields.io/npm/dm/dockview)](https://www.npmjs.com/package/dockview)
[![CI Build](https://github.com/mathuo/dockview/workflows/CI/badge.svg)](https://github.com/mathuo/dockview/actions?query=workflow%3ACI) [![CI Build](https://github.com/mathuo/dockview/workflows/CI/badge.svg)](https://github.com/mathuo/dockview/actions?query=workflow%3ACI)
[![Coverage](https://sonarcloud.io/api/project_badges/measure?project=mathuo_dockview&metric=coverage)](https://sonarcloud.io/summary/overall?id=mathuo_dockview) [![Coverage](https://sonarcloud.io/api/project_badges/measure?project=mathuo_dockview&metric=coverage)](https://sonarcloud.io/summary/overall?id=mathuo_dockview)
[![Quality Gate Status](https://sonarcloud.io/api/project_badges/measure?project=mathuo_dockview&metric=alert_status)](https://sonarcloud.io/summary/overall?id=mathuo_dockview) [![Quality Gate Status](https://sonarcloud.io/api/project_badges/measure?project=mathuo_dockview&metric=alert_status)](https://sonarcloud.io/summary/overall?id=mathuo_dockview)
@ -19,16 +20,20 @@ Please see the website: https://dockview.dev
## Features ## Features
- Simple splitviews, nested splitviews (i.e. gridviews) supporting full layout managment with - Serialization / deserialization with full layout management
dockable and tabular views - Support for split-views, grid-views and 'dockable' views
- Extensive API support at the component level and view level - Themeable and customizable
- Themable and customizable - Tab and Group docking / Drag n' Drop
- Serialization / deserialization support - Popout Windows
- Tabular docking and Drag and Drop support - Floating Groups
- Floating groups, customized header bars and tab - Extensive API
- Documentation and examples - Supports Shadow DOMs
- High test coverage
- Documentation website with live examples
- Transparent builds and Code Analysis
- Security at mind - verifed publishing and builds through GitHub Actions
Want to inspect the latest deployment? Go to https://unpkg.com/browse/dockview@latest/ Want to verify our builds? Go [here](https://www.npmjs.com/package/dockview#Provenance).
## Quick start ## Quick start

View File

@ -16,6 +16,8 @@ Please reference to docs @ [dockview.dev](https://dockview.dev).
- Advanced panel rendering configurations [#397](https://github.com/mathuo/dockview/issues/397) - Advanced panel rendering configurations [#397](https://github.com/mathuo/dockview/issues/397)
- Support for rendering within Shadow DOM elements [#425](https://github.com/mathuo/dockview/issues/425)
## 🛠 Miscs ## 🛠 Miscs
- Remove hover effect on inactive drag handles [#392](https://github.com/mathuo/dockview/pull/392) - Remove hover effect on inactive drag handles [#392](https://github.com/mathuo/dockview/pull/392)

View File

@ -29,6 +29,7 @@ import DockviewFloating from '@site/sandboxes/floatinggroup-dockview/src/app';
import DockviewLockedGroup from '@site/sandboxes/lockedgroup-dockview/src/app'; import DockviewLockedGroup from '@site/sandboxes/lockedgroup-dockview/src/app';
import DockviewKeyboard from '@site/sandboxes/keyboard-dockview/src/app'; import DockviewKeyboard from '@site/sandboxes/keyboard-dockview/src/app';
import DockviewPopoutGroup from '@site/sandboxes/popoutgroup-dockview/src/app'; import DockviewPopoutGroup from '@site/sandboxes/popoutgroup-dockview/src/app';
import DockviewMaximizeGroup from '@site/sandboxes/maximizegroup-dockview/src/app';
import DockviewRenderMode from '@site/sandboxes/rendermode-dockview/src/app'; import DockviewRenderMode from '@site/sandboxes/rendermode-dockview/src/app';
import { DocRef } from '@site/src/components/ui/reference/docRef'; import { DocRef } from '@site/src/components/ui/reference/docRef';
@ -403,7 +404,7 @@ To programatically move the popout group back into the main grid you can use the
```tsx ```tsx
// option 1: add absolutely to the right-side of the grid // option 1: add absolutely to the right-side of the grid
props.group.api.moveTo({position: 'right'}); props.group.api.moveTo({ position: 'right' });
// option 2: create a new group and move the contents of the popout group to it // option 2: create a new group and move the contents of the popout group to it
const group = props.containerApi.addGroup(); const group = props.containerApi.addGroup();
@ -418,12 +419,44 @@ props.group.api.moveTo({ group });
## Maximized Groups ## Maximized Groups
To maximize a group you can all To maximize a group from the component `api`:
```tsx ```tsx
// maximize a specified group
api.maxmimizeGroup(group); api.maxmimizeGroup(group);
// check whether a specific group is maximized
const result: boolean = api.isMaximizedGroup(group);
// if there is any maximized group exit the maximized state
exitMaximizedGroup();
// is there a maximized group
const result: boolean = hasMaximizedGroup();
``` ```
The following methods are available on both the panel and group `api` objects:
> `api.<method>` is equivalent to `api.group.api.<method>` for all of these methods. The methods exist on the panel `api` object for convenience.
```ts
// maximize the group
api.maximize();
// is this group maximized (if another group is maximized this method will still return false)
const result: boolean = api.isMaxmized();
// exit only if this group is maximzied (if another group is maxmized this has no affect)
api.exitMaximized();
```
<MultiFrameworkContainer
height={600}
sandboxId="maximizegroup-dockview"
react={DockviewMaximizeGroup}
/>
## Panels ## Panels
### Add Panel ### Add Panel
@ -667,9 +700,9 @@ Toggling the checkbox you can see that when you only render those panels which a
You can provide custom renderers for your tab headers for maximum customization. You can provide custom renderers for your tab headers for maximum customization.
A default implementation of `DockviewDefaultTab` is provided should you only wish to attach minor A default implementation of `DockviewDefaultTab` is provided should you only wish to attach minor
changes and events that do not alter the default behaviour, for example to add a custom context menu event changes and events that do not alter the default behaviour, for example to add a custom context menu event
handler. handler or to hide the close button.
The `DockviewDefaulTab` component accepts a `hideClose` prop if you wish only to hide the close button. The `DockviewDefaultTab` component accepts a `hideClose` prop if you wish only to hide the close button.
```tsx title="Attaching a custom context menu event handlers to a custom header" ```tsx title="Attaching a custom context menu event handlers to a custom header"
import { IDockviewPanelHeaderProps, DockviewDefaultTab } from 'dockview'; import { IDockviewPanelHeaderProps, DockviewDefaultTab } from 'dockview';
@ -679,7 +712,7 @@ const MyCustomheader = (props: IDockviewPanelHeaderProps) => {
event.preventDefault(); event.preventDefault();
alert('context menu'); alert('context menu');
}; };
return <DockviewDefaultTab onContextMenu={onContextMenu} {...props} />; return <DockviewDefaultTab onContextMenu={onContextMenu} hideClose={true} {...props} />;
}; };
``` ```
@ -900,16 +933,17 @@ iFrames required special attention because of a particular behaviour in how iFra
You can find many examples of discussions on this. Two reputable forums for example are linked [here](https://bugzilla.mozilla.org/show_bug.cgi?id=254144) and [here](https://github.com/whatwg/html/issues/5484). You can find many examples of discussions on this. Two reputable forums for example are linked [here](https://bugzilla.mozilla.org/show_bug.cgi?id=254144) and [here](https://github.com/whatwg/html/issues/5484).
The problem with iFrames and `dockview` is that when you hide or move a panel that panels DOM element may be moved within the DOM or removed from the DOM completely. To ensure iFrames work as expected you should render them in panels with `renderer: 'always'` to ensure they are never removed from the DOM, alternatively set the defaultRenderer to `always`.
If your panel contains an iFrame then that iFrame will reload after being re-positioned within the DOM tree and all state in that iFrame will most likely be lost.
`dockview` does not provide a built-in solution to this because it's too specific of a problem to include in the library. > See the **Panel Rendering** section for more information of render modes.
However the below example does show an implementation of a higher-order component `HoistedDockviewPanel`that you could use to work around this problems and make iFrames behave in `dockview`.
What the higher-order component is doing is to hoist the panels contents into a DOM element that is always present and then `position: absolute` that element to match the dimensions of it's linked panel. ```tsx title="Example of a panel using an alternative renderer"
The visibility of these hoisted elements is then controlled through some exposed api methods to hide elements that shouldn't be currently shown. api.addPanel({
id: 'my_panel_id',
You should open this example in CodeSandbox using the provided link to understand the code and make use of this implemention if required. component: 'my_component',
renderer: 'always',
});
```
<MultiFrameworkContainer <MultiFrameworkContainer
sandboxId="iframe-dockview" sandboxId="iframe-dockview"

View File

@ -7,6 +7,8 @@ description: Contributing
# Project description # Project description
Pre-requisites: Node >=18, Yarn
Dockview is a layout manager library designed to provide a complete layouting solution. Dockview is a layout manager library designed to provide a complete layouting solution.
It is written in plain TypeScript and can be used without any framework although It is written in plain TypeScript and can be used without any framework although
an extensive React wrapper has always and will always be provided for those using the React framework. an extensive React wrapper has always and will always be provided for those using the React framework.

View File

@ -3,10 +3,12 @@ sidebar_position: 0
description: A zero dependency layout manager supporting ReactJS and Vanilla TypeScript description: A zero dependency layout manager supporting ReactJS and Vanilla TypeScript
--- ---
import { MultiFrameworkContainer } from '@site/src/components/ui/container';
import { SimpleSplitview } from '@site/src/components/simpleSplitview'; import { SimpleSplitview } from '@site/src/components/simpleSplitview';
import { SimpleGridview } from '@site/src/components/simpleGridview'; import { SimpleGridview } from '@site/src/components/simpleGridview';
import { SimplePaneview } from '@site/src/components/simplePaneview'; import { SimplePaneview } from '@site/src/components/simplePaneview';
import SimpleDockview from '@site/sandboxes/simple-dockview/src/app'; import DockviewDemo from '@site/sandboxes/demo-dockview/src/app';
import Link from '@docusaurus/Link'; import Link from '@docusaurus/Link';
# Introduction # Introduction
@ -34,16 +36,11 @@ There are 4 components you may want to use:
<h2>Dockview</h2> <h2>Dockview</h2>
</Link> </Link>
<div <MultiFrameworkContainer
style={{ height={500}
height: '300px', sandboxId="demo-dockview"
backgroundColor: 'rgb(30,30,30)', react={DockviewDemo}
color: 'white', />
margin: '20px 0px',
}}
>
<SimpleDockview />
</div>
<Link to="./components/splitview"> <Link to="./components/splitview">
<h2>Splitview</h2> <h2>Splitview</h2>

View File

@ -31,74 +31,13 @@ const headerComponents = {
}, },
}; };
const Popover = (props: {
children: React.ReactNode;
position?: { x: number; y: number };
close: () => void;
}) => {
const uuid = React.useMemo(() => v4(), []);
React.useEffect(() => {
const listener = (event: KeyboardEvent) => {
if (event.key === 'Escape') {
props.close();
}
};
const listener2 = (event: MouseEvent) => {
let target = event.target;
while (target) {
if (target instanceof HTMLElement) {
if (target.classList.contains(uuid)) {
return;
} else {
target = target.parentElement;
}
} else {
target = null;
}
}
props.close();
};
window.addEventListener('keypress', listener);
window.addEventListener('mousedown', listener2);
return () => {
window.removeEventListener('keypress', listener);
window.removeEventListener('mousedown', listener2);
};
}, [props.close, uuid]);
if (!props.position) {
return null;
}
return ReactDOM.createPortal(
<div
className={uuid}
style={{
position: 'absolute',
top: props.position.y,
left: props.position.x,
background: 'white',
border: '1px solid black',
zIndex: 99,
padding: '10px',
}}
>
{props.children}
</div>,
document.body
);
};
const Icon = (props: { const Icon = (props: {
icon: string; icon: string;
title?: string;
onClick?: (event: React.MouseEvent) => void; onClick?: (event: React.MouseEvent) => void;
}) => { }) => {
return ( return (
<div className="action" onClick={props.onClick}> <div title={props.title} className="action" onClick={props.onClick}>
<span <span
style={{ fontSize: 'inherit' }} style={{ fontSize: 'inherit' }}
className="material-symbols-outlined" className="material-symbols-outlined"
@ -124,54 +63,44 @@ const RightControls = (props: IDockviewHeaderActionsProps) => {
return groupControlsComponents[props.activePanel.id]; return groupControlsComponents[props.activePanel.id];
}, [props.isGroupActive, props.activePanel]); }, [props.isGroupActive, props.activePanel]);
// const [icon, setIcon] = React.useState<string>( const [isMaximized, setIsMaximized] = React.useState<boolean>(
// props.containerApi.hasMaximizedGroup() props.containerApi.hasMaximizedGroup()
// ? 'collapse_content' );
// : 'expand_content'
// );
// const [popoutIcon, setPopoutIcon] = React.useState<string>( const [isPopout, setIsPopout] = React.useState<boolean>(
// props.api.location === 'popout' ? 'close_fullscreen' : 'open_in_new' props.api.location === 'popout'
// ); );
// React.useEffect(() => { React.useEffect(() => {
// const disposable = props.containerApi.onDidMaxmizedGroupChange(() => { const disposable = props.containerApi.onDidMaxmizedGroupChange(() => {
// setIcon( setIsMaximized(props.containerApi.hasMaximizedGroup());
// props.containerApi.hasMaximizedGroup() });
// ? 'collapse_content'
// : 'expand_content'
// );
// });
// const disposable2 = props.api.onDidLocationChange(() => { const disposable2 = props.api.onDidLocationChange(() => {
// setPopoutIcon( setIsPopout(props.api.location === 'popout');
// props.api.location === 'popout' });
// ? 'close_fullscreen'
// : 'open_in_new'
// );
// });
// return () => { return () => {
// disposable.dispose(); disposable.dispose();
// disposable2.dispose(); disposable2.dispose();
// }; };
// }, [props.containerApi]); }, [props.containerApi]);
// const onClick = () => { const onClick = () => {
// if (props.containerApi.hasMaximizedGroup()) { if (props.containerApi.hasMaximizedGroup()) {
// props.containerApi.exitMaxmizedGroup(); props.containerApi.exitMaxmizedGroup();
// } else { } else {
// props.activePanel?.api.maximize(); props.activePanel?.api.maximize();
// } }
// }; };
// const onClick2 = () => { const onClick2 = () => {
// if (props.api.location !== 'popout') { if (props.api.location !== 'popout') {
// props.containerApi.addPopoutGroup(props.group); props.containerApi.addPopoutGroup(props.group);
// } else { } else {
// props.api.moveTo({ position: 'right' }); props.api.moveTo({ position: 'right' });
// } }
// }; };
return ( return (
<div <div
@ -186,8 +115,18 @@ const RightControls = (props: IDockviewHeaderActionsProps) => {
> >
{props.isGroupActive && <Icon icon="star" />} {props.isGroupActive && <Icon icon="star" />}
{Component && <Component />} {Component && <Component />}
{/* <Icon icon={popoutIcon} onClick={onClick2} /> <Icon
<Icon icon={icon} onClick={onClick} /> */} title={isPopout ? 'Close Window' : 'Open In New Window'}
icon={isPopout ? 'close_fullscreen' : 'open_in_new'}
onClick={onClick2}
/>
{!isPopout && (
<Icon
title={isMaximized ? 'Minimize View' : 'Maximize View'}
icon={isMaximized ? 'collapse_content' : 'expand_content'}
onClick={onClick}
/>
)}
</div> </div>
); );
}; };
@ -241,45 +180,62 @@ const PrefixHeaderControls = (props: IDockviewHeaderActionsProps) => {
const DockviewDemo = (props: { theme?: string }) => { const DockviewDemo = (props: { theme?: string }) => {
const onReady = (event: DockviewReadyEvent) => { const onReady = (event: DockviewReadyEvent) => {
event.api.addPanel({ const panel1 = event.api.addPanel({
id: 'panel_1', id: 'panel_1',
component: 'default', component: 'default',
title: 'Panel 1', title: 'Panel 1',
}); });
event.api.addPanel({ event.api.addPanel({
id: 'panel_2', id: 'panel_2',
component: 'default', component: 'default',
title: 'Panel 2', title: 'Panel 2',
position: { referencePanel: 'panel_1', direction: 'right' }, position: { referencePanel: panel1 },
}); });
event.api.addPanel({ event.api.addPanel({
id: 'panel_3', id: 'panel_3',
component: 'default', component: 'default',
title: 'Panel 3', title: 'Panel 3',
position: { referencePanel: 'panel_2', direction: 'below' }, position: { referencePanel: panel1 },
}); });
event.api.addPanel({
const panel4 = event.api.addPanel({
id: 'panel_4', id: 'panel_4',
component: 'default', component: 'default',
title: 'Panel 4', title: 'Panel 4',
position: { referencePanel: 'panel_3', direction: 'right' }, position: { referencePanel: panel1, direction: 'right' },
}); });
event.api.addPanel({
const panel5 = event.api.addPanel({
id: 'panel_5', id: 'panel_5',
component: 'default', component: 'default',
title: 'Panel 5', title: 'Panel 5',
position: { referencePanel: 'panel_3', direction: 'below' }, position: { referencePanel: panel4 },
}); });
event.api.addPanel({
const panel6 = event.api.addPanel({
id: 'panel_6', id: 'panel_6',
component: 'default', component: 'default',
title: 'Panel 6', title: 'Panel 6',
position: { referencePanel: 'panel_3', direction: 'right' }, position: { referencePanel: panel5, direction: 'below' },
}); });
event.api.getPanel('panel_1')!.api.setActive(); const panel7 = event.api.addPanel({
id: 'panel_7',
component: 'default',
title: 'Panel 7',
position: { referencePanel: panel6, direction: 'left' },
});
console.log(event.api.toJSON()); event.api.addPanel({
id: 'panel8',
component: 'default',
title: 'Panel 8',
position: { referencePanel: panel7, direction: 'below' },
});
panel1.api.setActive();
}; };
return ( return (

View File

@ -1,25 +1,11 @@
import { import { DockviewReact, DockviewReadyEvent } from 'dockview';
DockviewReact,
DockviewReadyEvent,
IDockviewPanelProps,
} from 'dockview';
import * as React from 'react'; import * as React from 'react';
import { HoistedDockviewPanel } from './hoistedDockviewPanel';
const components = { const components = {
iframeComponent: (props: IDockviewPanelProps<{ color: string }>) => { iframeComponent: () => {
return (
<div style={{ height: '100%', overflow: 'auto' }}>
<div style={{ height: '1000px', color: 'white' }}>
{props.api.title}
</div>
</div>
);
return ( return (
<iframe <iframe
style={{ style={{
// pointerEvents: 'none',
// border: 'none',
width: '100%', width: '100%',
height: '100%', height: '100%',
}} }}

View File

@ -1,92 +0,0 @@
import { IDockviewPanelProps } from 'dockview';
import * as React from 'react';
import * as ReactDOM from 'react-dom';
// get absolute position of element allowing for scroll position
function getDomNodePagePosition(domNode: HTMLElement): {
left: number;
top: number;
width: number;
height: number;
} {
const { left, top, width, height } = domNode.getBoundingClientRect();
return {
left: left + window.scrollX,
top: top + window.scrollY,
width: width,
height: height,
};
}
function toggleVisibility(element: HTMLElement, isVisible: boolean) {
element.style.visibility = isVisible ? 'visible' : 'hidden';
}
export const HoistedDockviewPanel = <T extends object>(
DockviewPanelComponent: React.FC<IDockviewPanelProps<T>>
) => {
return (props: IDockviewPanelProps<T>) => {
const ref = React.useRef<HTMLDivElement>(null);
const innerRef = React.useRef<HTMLDivElement>(null);
const positionHoistedPanel = () => {
if (!ref.current || !innerRef.current) {
return;
}
const { left, top, height, width } = getDomNodePagePosition(
ref.current.parentElement! // use the parent element to determine our size
);
innerRef.current.style.left = `${left}px`;
innerRef.current.style.top = `${top}px`;
innerRef.current.style.height = `${height}px`;
innerRef.current.style.width = `${width}px`;
};
React.useEffect(() => {
if (!innerRef.current) {
return;
}
const disposable1 = props.api.onDidVisibilityChange((event) => {
if (!innerRef.current) {
return;
}
toggleVisibility(innerRef.current, event.isVisible); // subsequent checks of visibility
});
const disposable2 = props.api.onDidDimensionsChange(() => {
positionHoistedPanel();
});
positionHoistedPanel();
return () => {
disposable1.dispose(); // cleanup
disposable2.dispose();
};
}, [props.api]);
return (
<div ref={ref}>
{ReactDOM.createPortal(
<div
/** you may want to mark these elements with some kind of attribute id */
ref={innerRef}
style={{
position: 'absolute',
overflow: 'hidden',
zIndex: 999,
pointerEvents: 'none', // prevent this wrapper contain stealing events
}}
>
<DockviewPanelComponent {...props} />
</div>,
document.body // <-- you may choose to mount these 'global' elements to anywhere you see suitable
)}
</div>
);
};
};

View File

@ -0,0 +1,32 @@
{
"name": "maximizegroup-dockview",
"description": "",
"keywords": [
"dockview"
],
"version": "1.0.0",
"main": "src/index.tsx",
"dependencies": {
"dockview": "*",
"react": "^18.2.0",
"react-dom": "^18.2.0"
},
"devDependencies": {
"@types/react": "^18.0.28",
"@types/react-dom": "^18.0.11",
"typescript": "^4.9.5",
"react-scripts": "*"
},
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test --env=jsdom",
"eject": "react-scripts eject"
},
"browserslist": [
">0.2%",
"not dead",
"not ie <= 11",
"not op_mini all"
]
}

View File

@ -0,0 +1,44 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<meta name="theme-color" content="#000000">
<!--
manifest.json provides metadata used when your web app is added to the
homescreen on Android. See https://developers.google.com/web/fundamentals/engage-and-retain/web-app-manifest/
-->
<link rel="manifest" href="%PUBLIC_URL%/manifest.json">
<link rel="shortcut icon" href="%PUBLIC_URL%/favicon.ico">
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:opsz,wght,FILL,GRAD@20..48,100..700,0..1,-50..200" />
<!--
Notice the use of %PUBLIC_URL% in the tags above.
It will be replaced with the URL of the `public` folder during the build.
Only files inside the `public` folder can be referenced from the HTML.
Unlike "/favicon.ico" or "favicon.ico", "%PUBLIC_URL%/favicon.ico" will
work correctly both with client-side routing and a non-root public URL.
Learn how to configure a non-root public URL by running `npm run build`.
-->
<title>React App</title>
</head>
<body>
<noscript>
You need to enable JavaScript to run this app.
</noscript>
<div id="root"></div>
<!--
This HTML file is a template.
If you open it directly in the browser, you will see an empty page.
You can add webfonts, meta tags, or analytics to this file.
The build step will place the bundled scripts into the <body> tag.
To begin the development, run `npm start` or `yarn start`.
To create a production bundle, use `npm run build` or `yarn build`.
-->
</body>
</html>

View File

@ -0,0 +1,252 @@
import {
DockviewApi,
DockviewGroupPanel,
DockviewReact,
DockviewReadyEvent,
IDockviewHeaderActionsProps,
IDockviewPanelProps,
SerializedDockview,
} from 'dockview';
import * as React from 'react';
import { Icon } from './utils';
const components = {
default: (props: IDockviewPanelProps<{ title: string }>) => {
return (
<div
style={{
height: '100%',
padding: '20px',
background: 'var(--dv-group-view-background-color)',
}}
>
{props.params.title}
</div>
);
},
};
const counter = (() => {
let i = 0;
return {
next: () => ++i,
};
})();
function loadDefaultLayout(api: DockviewApi) {
api.addPanel({
id: 'panel_1',
component: 'default',
});
api.addPanel({
id: 'panel_2',
component: 'default',
});
api.addPanel({
id: 'panel_3',
component: 'default',
});
api.addPanel({
id: 'panel_4',
component: 'default',
});
api.addPanel({
id: 'panel_5',
component: 'default',
position: { direction: 'right' },
});
api.addPanel({
id: 'panel_6',
component: 'default',
});
}
let panelCount = 0;
function safeParse<T>(value: any): T | null {
try {
return JSON.parse(value) as T;
} catch (err) {
return null;
}
}
const useLocalStorage = <T,>(
key: string
): [T | null, (setter: T | null) => void] => {
const [state, setState] = React.useState<T | null>(
safeParse(localStorage.getItem(key))
);
React.useEffect(() => {
const _state = localStorage.getItem('key');
try {
if (_state !== null) {
setState(JSON.parse(_state));
}
} catch (err) {
//
}
}, [key]);
return [
state,
(_state: T | null) => {
if (_state === null) {
localStorage.removeItem(key);
} else {
localStorage.setItem(key, JSON.stringify(_state));
setState(_state);
}
},
];
};
export const App = (props: { theme?: string }) => {
const [api, setApi] = React.useState<DockviewApi>();
const [layout, setLayout] =
useLocalStorage<SerializedDockview>('floating.layout');
const [disableFloatingGroups, setDisableFloatingGroups] =
React.useState<boolean>(false);
const load = (api: DockviewApi) => {
api.clear();
if (layout) {
try {
api.fromJSON(layout);
} catch (err) {
console.error(err);
api.clear();
loadDefaultLayout(api);
}
} else {
loadDefaultLayout(api);
}
};
const onReady = (event: DockviewReadyEvent) => {
load(event.api);
setApi(event.api);
};
const [options, setOptions] = React.useState<
'boundedWithinViewport' | undefined
>(undefined);
return (
<div
style={{
display: 'flex',
flexDirection: 'column',
height: '100%',
}}
>
<div style={{ height: '25px' }}>
<button
onClick={() => {
if (api) {
setLayout(api.toJSON());
}
}}
>
Save
</button>
<button
onClick={() => {
if (api) {
load(api);
}
}}
>
Load
</button>
<button
onClick={() => {
api!.clear();
setLayout(null);
}}
>
Clear
</button>
</div>
<div
style={{
flexGrow: 1,
}}
>
<DockviewReact
onReady={onReady}
components={components}
watermarkComponent={Watermark}
leftHeaderActionsComponent={LeftComponent}
rightHeaderActionsComponent={RightComponent}
disableFloatingGroups={disableFloatingGroups}
floatingGroupBounds={options}
className={`${props.theme || 'dockview-theme-abyss'}`}
/>
</div>
</div>
);
};
const LeftComponent = (props: IDockviewHeaderActionsProps) => {
const onClick = () => {
props.containerApi.addPanel({
id: (++panelCount).toString(),
title: `Tab ${panelCount}`,
component: 'default',
position: { referenceGroup: props.group },
});
};
return (
<div style={{ height: '100%', color: 'white', padding: '0px 4px' }}>
<Icon onClick={onClick} icon={'add'} />
</div>
);
};
const RightComponent = (props: IDockviewHeaderActionsProps) => {
const [maximized, setMaximized] = React.useState<boolean>(
props.api.isMaximized()
);
React.useEffect(() => {
const disposable = props.containerApi.onDidMaxmizedGroupChange(() => {
setMaximized(props.api.isMaximized());
});
return () => {
disposable.dispose();
};
}, [props.containerApi]);
const onClick = () => {
if (maximized) {
props.api.exitMaximized();
} else {
props.api.maximize();
}
};
return (
<div style={{ height: '100%', color: 'white', padding: '0px 4px' }}>
<Icon
onClick={onClick}
icon={maximized ? 'jump_to_element' : 'back_to_tab'}
/>
</div>
);
};
export default App;
const Watermark = () => {
return <div style={{ color: 'white', padding: '8px' }}>watermark</div>;
};

View File

@ -0,0 +1,20 @@
import { StrictMode } from 'react';
import * as ReactDOMClient from 'react-dom/client';
import './styles.css';
import 'dockview/dist/styles/dockview.css';
import App from './app';
const rootElement = document.getElementById('root');
if (rootElement) {
const root = ReactDOMClient.createRoot(rootElement);
root.render(
<StrictMode>
<div className="app">
<App />
</div>
</StrictMode>
);
}

View File

@ -0,0 +1,16 @@
body {
margin: 0px;
color: white;
font-family: sans-serif;
text-align: center;
}
#root {
height: 100vh;
width: 100vw;
}
.app {
height: 100%;
}

View File

@ -0,0 +1,30 @@
import * as React from 'react';
export const Icon = (props: {
icon: string;
title?: string;
onClick?: (event: React.MouseEvent) => void;
}) => {
return (
<div
title={props.title}
style={{
display: 'flex',
justifyContent: 'center',
alignItems: 'center',
width: '30px',
height: '100%',
fontSize: '18px',
}}
onClick={props.onClick}
>
<span
style={{ fontSize: 'inherit', cursor: 'pointer' }}
className="material-symbols-outlined"
>
{props.icon}
</span>
</div>
);
};

View File

@ -0,0 +1,18 @@
{
"compilerOptions": {
"outDir": "build/dist",
"module": "esnext",
"target": "es5",
"lib": ["es6", "dom"],
"sourceMap": true,
"allowJs": true,
"jsx": "react-jsx",
"moduleResolution": "node",
"rootDir": "src",
"forceConsistentCasingInFileNames": true,
"noImplicitReturns": true,
"noImplicitThis": true,
"noImplicitAny": true,
"strictNullChecks": true
}
}

View File

@ -1,6 +1,6 @@
.nested-dockview { .nested-dockview {
position: relative; position: relative;
::after { &::after {
content: ''; content: '';
position: absolute; position: absolute;
top: 0px; top: 0px;

View File

@ -108,7 +108,7 @@ const useLocalStorage = <T,>(
]; ];
}; };
export const DockviewPersistance = (props: { theme?: string }) => { export const App = (props: { theme?: string }) => {
const [api, setApi] = React.useState<DockviewApi>(); const [api, setApi] = React.useState<DockviewApi>();
const [layout, setLayout] = const [layout, setLayout] =
useLocalStorage<SerializedDockview>('floating.layout'); useLocalStorage<SerializedDockview>('floating.layout');
@ -218,9 +218,9 @@ const RightComponent = (props: IDockviewHeaderActionsProps) => {
); );
React.useEffect(() => { React.useEffect(() => {
const disposable = props.group.api.onDidLocationChange( const disposable = props.group.api.onDidLocationChange((event) => [
(event) => [setPopout(event.location === 'popout')] setPopout(event.location === 'popout'),
); ]);
return () => { return () => {
disposable.dispose(); disposable.dispose();
@ -232,7 +232,9 @@ const RightComponent = (props: IDockviewHeaderActionsProps) => {
const group = props.containerApi.addGroup(); const group = props.containerApi.addGroup();
props.group.api.moveTo({ group }); props.group.api.moveTo({ group });
} else { } else {
props.containerApi.addPopoutGroup(props.group); props.containerApi.addPopoutGroup(props.group, {
popoutUrl: '/popout/index.html',
});
} }
}; };
@ -246,7 +248,7 @@ const RightComponent = (props: IDockviewHeaderActionsProps) => {
); );
}; };
export default DockviewPersistance; export default App;
const Watermark = () => { const Watermark = () => {
return <div style={{ color: 'white', padding: '8px' }}>watermark</div>; return <div style={{ color: 'white', padding: '8px' }}>watermark</div>;

View File

@ -62,11 +62,11 @@ const FeatureList: FeatureItem[] = [
</div> </div>
<div className="feature-banner"> <div className="feature-banner">
<h3 className="feature-banner-header"> <h3 className="feature-banner-header">
Floating Group Support Floating and Popout Groups
</h3> </h3>
<p className="feature-banner-content"> <p className="feature-banner-content">
Built-in support for floating groups with a supporting Built-in support for floating groups and groups in new
api for progmatic control. windows with a supporting api for progmatic control.
</p> </p>
</div> </div>
<div className="feature-banner"> <div className="feature-banner">

View File

@ -26,7 +26,7 @@ export const Introduction = () => {
<div style={{ padding: '20px' }}> <div style={{ padding: '20px' }}>
<BrowserHeader /> <BrowserHeader />
<MultiFrameworkContainer <MultiFrameworkContainer
height={500} height={750}
sandboxId="demo-dockview" sandboxId="demo-dockview"
react={DockviewDemo} react={DockviewDemo}
/> />

View File

@ -54,6 +54,7 @@ export const CodeSandboxButton = (props: {
<a <a
href={url} href={url}
target={'_blank'} target={'_blank'}
rel='noopener'
className="codesandbox-button-content" className="codesandbox-button-content"
> >
<span <span

Binary file not shown.

Before

Width:  |  Height:  |  Size: 455 KiB

After

Width:  |  Height:  |  Size: 655 KiB

View File

@ -1,114 +0,0 @@
---
sidebar_position: 1
description: How to get started with Dockview
---
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

@ -1,120 +0,0 @@
---
description: Gridview Documentation
---
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

@ -1,285 +0,0 @@
---
description: Paneview Documentation
---
import { SimplePaneview } from '@site/src/components/simplePaneview';
import { CustomHeaderPaneview } from '@site/src/components/paneview/customHeader';
import { DragAndDropPaneview } from '@site/src/components/paneview/dragAndDrop';
import { SideBySidePaneview } from '@site/src/components/paneview/sideBySide';
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-abyss"
/>
);
};
```
## 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 />
### Interactions
You can safely create multiple paneview instances within one page. They will not interact with each other by default.
If you wish to interact with the drop event from one paneview instance in another paneview instance you can implement the `showDndOverlay` and `onDidDrop` props on `PaneviewReact`.
As an example see how dragging a header from one control to another will only trigger an interactable event for the developer if the checkbox is enabled.
<SideBySidePaneview />

View File

@ -1,246 +0,0 @@
---
description: Splitview Documentation
---
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-abyss"
/>
);
};
```
## 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

@ -1,149 +0,0 @@
---
sidebar_position: 0
description: A zero dependency layout manager built for React
---
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/sandboxes/simple-dockview/src/app';
# 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-abyss">
...
</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

@ -2,6 +2,7 @@
"label": "Components", "label": "Components",
"collapsible": true, "collapsible": true,
"collapsed": false, "collapsed": false,
"position": 2,
"link": { "link": {
"type": "generated-index", "type": "generated-index",
"title": "Components" "title": "Components"

View File

@ -2,10 +2,7 @@
description: Dockview Documentation description: Dockview Documentation
--- ---
import { import { MultiFrameworkContainer } from '@site/src/components/ui/container';
Container,
MultiFrameworkContainer,
} from '@site/src/components/ui/container';
import Link from '@docusaurus/Link'; import Link from '@docusaurus/Link';
import useBaseUrl from '@docusaurus/useBaseUrl'; import useBaseUrl from '@docusaurus/useBaseUrl';
@ -28,6 +25,14 @@ import DockviewExternalDnd from '@site/sandboxes/externaldnd-dockview/src/app';
import DockviewResizeContainer from '@site/sandboxes/resizecontainer-dockview/src/app'; import DockviewResizeContainer from '@site/sandboxes/resizecontainer-dockview/src/app';
import DockviewTabheight from '@site/sandboxes/tabheight-dockview/src/app'; import DockviewTabheight from '@site/sandboxes/tabheight-dockview/src/app';
import DockviewWithIFrames from '@site/sandboxes/iframe-dockview/src/app'; import DockviewWithIFrames from '@site/sandboxes/iframe-dockview/src/app';
import DockviewFloating from '@site/sandboxes/floatinggroup-dockview/src/app';
import DockviewLockedGroup from '@site/sandboxes/lockedgroup-dockview/src/app';
import DockviewKeyboard from '@site/sandboxes/keyboard-dockview/src/app';
import DockviewPopoutGroup from '@site/sandboxes/popoutgroup-dockview/src/app';
import DockviewMaximizeGroup from '@site/sandboxes/maximizegroup-dockview/src/app';
import DockviewRenderMode from '@site/sandboxes/rendermode-dockview/src/app';
import { DocRef } from '@site/src/components/ui/reference/docRef';
import { attach as attachDockviewVanilla } from '@site/sandboxes/javascript/vanilla-dockview/src/app'; import { attach as attachDockviewVanilla } from '@site/sandboxes/javascript/vanilla-dockview/src/app';
import { attach as attachSimpleDockview } from '@site/sandboxes/javascript/simple-dockview/src/app'; import { attach as attachSimpleDockview } from '@site/sandboxes/javascript/simple-dockview/src/app';
@ -55,24 +60,12 @@ Dockview is an abstraction built on top of [Gridviews](./gridview) where each vi
You can create a Dockview through the use of the `DockviewReact` component. You can create a Dockview through the use of the `DockviewReact` component.
```tsx <p style={{ fontSize: '1.3em' }}>
import { DockviewReact } from 'dockview'; <span>{'All of these are React props available through the '}</span>
``` <code>DockviewReact</code>
<span>{' component.'}</span>
| Property | Type | Optional | Default | Description | </p>
| --------------------- | ------------------------------------ | -------- | --------- | ------------------------------------------------------------ | <DocRef declaration="IDockviewReactProps" />
| 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> |
| onDidDrop | Event | Yes | false | |
| showDndOverlay | Event | Yes | false | |
| defaultTabComponent | object | Yes | | |
| groupControlComponent | object | Yes | | |
| singleTabMode | 'fullwidth' \| 'default' | Yes | 'default' | |
## Dockview API ## Dockview API
@ -93,44 +86,19 @@ const onReady = (event: DockviewReadyEvent) => {
}; };
``` ```
| Property | Type | Description | <p style={{ fontSize: '1.3em' }}>
| ---------------------- | ---------------------------------------------------- | -------------------------------------------------------- | <span>{'All of these methods are available through the '}</span>
| height | `number` | Component pixel height | <code>api</code>
| width | `number` | Component pixel width | <span>{' property of '}</span>
| minimumHeight | `number` | | <code>DockviewComponent</code>
| maximumHeight | `number` | | <span>{' and the '}</span>
| maximumWidth | `number` | | <code>containerApi</code>
| maximumWidth | `number` | | <span>{' property of '}</span>
| length | `number` | Number of panels | <code>IDockviewPanel</code>
| size | `number` | Number of Groups | <span>.</span>
| panels | `IDockviewPanel[]` | | </p>
| groups | `GroupPanel[]` | |
| activePanel | `IDockviewPanel \| undefined` | | <DocRef declaration="DockviewApi" />
| 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` | |
| addGroup | `(options? AddGroupOptions): void` | |
| closeAllGroups | `(): void` | |
| removeGroup | `(group: GroupPanel): void` | |
| getGroup | `(id: string): GroupPanel \| undefined` | |
| | | |
| 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 ## Dockview Panel API
@ -142,29 +110,34 @@ const MyComponent = (props: IDockviewPanelProps<{ title: string }>) => {
}; };
``` ```
| Property | Type | Description | <p style={{ fontSize: '1.3em' }}>
| ---------------------- | ----------------------------------------------------------- | ---------------- | <span>{'All of these are methods are available through the '}</span>
| id | `string` | Panel id | <code>api</code>
| isFocused | `boolean` | Is panel focused | <span>{' property of '}</span>
| isActive | `boolean` | Is panel active | <code>IDockviewPanel</code>
| width | `number` | Panel width | <span>.</span>
| height | `number` | Panel height | </p>
| onDidDimensionsChange | `Event<PanelDimensionChangeEvent>` | |
| onDidFocusChange | `Event<FocusEvent>` | | <DocRef declaration="DockviewPanelApi" />
| onDidVisibilityChange | `Event<VisibilityEvent>` | |
| onDidActiveChange | `Event<ActiveEvent>` | | ## Theme
| setActive | `(): void` | |
| | | | As well as importing the `dockview` stylesheet you must provide a class-based theme somewhere in your application. For example.
| onDidConstraintsChange | `onDidConstraintsChange: Event<PanelConstraintChangeEvent>` | |
| setConstraints | `(value: PanelConstraintChangeEvent2): void;` | | ```tsx
| setSize | `(event: SizeEvent): void` | | // Providing a theme directly through the DockviewReact component props
| | | | <DockviewReact className="dockview-theme-dark" />
| group | `GroupPanel | undefined` |
| isGroupActive | `boolean` | | // Providing a theme somewhere in the DOM tree
| title | `string` | | <div className="dockview-theme-dark">
| suppressClosable | `boolean` | | <div>
| close | `(): void` | | {/**... */}
| setTitle | `(title: string): void` | | <DockviewReact />
</div>
</div>
```
You can find more details on theming <Link to="../theme">here</Link>.
## Layout Persistance ## Layout Persistance
@ -218,9 +191,10 @@ const onReady = (event: DockviewReadyEvent) => {
Here is an example using the above code loading from and saving to localStorage. Here is an example using the above code loading from and saving to localStorage.
If you refresh the page you should notice your layout is loaded as you left it. If you refresh the page you should notice your layout is loaded as you left it.
<Container sandboxId="layout-dockview"> <MultiFrameworkContainer
<DockviewPersistance /> sandboxId="layout-dockview"
</Container> react={DockviewPersistance}
/>
## Resizing ## Resizing
@ -249,17 +223,16 @@ props.api.group.api.setSize({
You can see an example invoking both approaches below. You can see an example invoking both approaches below.
<Container sandboxId="resize-dockview"> <MultiFrameworkContainer sandboxId="resize-dockview" react={ResizeDockview} />
<ResizeDockview />
</Container>
### Container Resizing ### Container Resizing
The component will automatically resize to it's container. The component will automatically resize to it's container.
<Container sandboxId="resizecontainer-dockview"> <MultiFrameworkContainer
<DockviewResizeContainer /> sandboxId="resizecontainer-dockview"
</Container> react={DockviewResizeContainer}
/>
## Watermark ## Watermark
@ -267,9 +240,10 @@ When the dockview is empty you may want to display some fallback content, this i
By default there the watermark has no content but you can provide as a prop to `DockviewReact` a `watermarkComponent` By default there the watermark has no content but you can provide as a prop to `DockviewReact` a `watermarkComponent`
which will be rendered when there are no panels or groups. which will be rendered when there are no panels or groups.
<Container sandboxId="watermark-dockview"> <MultiFrameworkContainer
<DockviewWatermark /> sandboxId="watermark-dockview"
</Container> react={DockviewWatermark}
/>
## Drag And Drop ## Drag And Drop
@ -346,9 +320,11 @@ return (
); );
``` ```
<Container sandboxId="dnd-dockview"> ### Intercepting Drag Events
<DndDockview />
</Container> You can intercept drag events to attach your own metadata using the `onWillDragPanel` and `onWillDragGroup` api methods.
<MultiFrameworkContainer sandboxId="dnd-dockview" react={DndDockview} />
### Third Party Dnd Libraries ### Third Party Dnd Libraries
@ -356,9 +332,130 @@ This shows a simple example of a third-party library used inside a panel that re
and drop functionalities. This examples serves to show that `dockview` doesn't interfer with and drop functionalities. This examples serves to show that `dockview` doesn't interfer with
any drag and drop logic for other controls. any drag and drop logic for other controls.
<Container> <MultiFrameworkContainer
<DockviewExternalDnd /> sandboxId="externaldnd-dockview"
</Container> react={DockviewExternalDnd}
/>
## Floating Groups
Dockview has built-in support for floating groups. Each floating container can contain a single group with many panels
and you can have as many floating containers as needed. You cannot dock multiple groups together in the same floating container.
Floating groups can be interacted with whilst holding the `shift` key activating the `event.shiftKey` boolean property on `KeyboardEvent` events.
> Float an existing tab by holding `shift` whilst interacting with the tab
<img style={{ width: '60%' }} src={useBaseUrl('/img/float_add.svg')} />
> Move a floating tab by holding `shift` whilst moving the cursor or dragging the empty
> header space
<img style={{ width: '60%' }} src={useBaseUrl('/img/float_move.svg')} />
> Move an entire floating group by holding `shift` whilst dragging the empty header space
<img style={{ width: '60%' }} src={useBaseUrl('/img/float_group.svg')} />
Floating groups can be programatically added through the dockview `api` method `api.addFloatingGroup(...)` and you can check whether
a group is floating via the `group.api.location` property. See examples for full code.
You can control the bounding box of floating groups through the optional `floatingGroupBounds` options:
- `boundedWithinViewport` will force the entire floating group to be bounded within the docks viewport.
- `{minimumHeightWithinViewport?: number, minimumWidthWithinViewport?: number}` sets the respective dimension minimums that must appears within the docks viewport
- If no options are provided the defaults of `100px` minimum height and width within the viewport are set.
<MultiFrameworkContainer
height={600}
sandboxId="floatinggroup-dockview"
react={DockviewFloating}
/>
## Popout Groups
Dockview has built-in support for opening groups in new Windows.
Each popout window can contain a single group with many panels and you can have as many popout
windows as needed. You cannot dock multiple groups together in the same window.
Popout windows require your website to have a blank `.html` page that can be used, by default this is set to `/popout.html` but
can be configured to match requirements.
```tsx title="Open new popout group from the component api"
api.addPopoutGroup(
group,
// the second arguments (options) is optional
{
popoutUrl:"/popout.html",
box: { left: 0, top: 0, height: 200, width: 300 }
});
```
> If you do not provide `options.popoutUrl` a default of `/popout.html` is used and if `options.box` is not provided
the view will be places according to it's currently position.
From within a panel you may say
```tsx
props.containerApi.addPopoutGroup(props.api.group);
```
To programatically move the popout group back into the main grid you can use the `moveTo` method in many ways, one of the following would suffice
```tsx
// option 1: add absolutely to the right-side of the grid
props.group.api.moveTo({ position: 'right' });
// option 2: create a new group and move the contents of the popout group to it
const group = props.containerApi.addGroup();
props.group.api.moveTo({ group });
```
<MultiFrameworkContainer
height={600}
sandboxId="popoutgroup-dockview"
react={DockviewPopoutGroup}
/>
## Maximized Groups
To maximize a group from the component `api`:
```tsx
// maximize a specified group
api.maxmimizeGroup(group);
// check whether a specific group is maximized
const result: boolean = api.isMaximizedGroup(group);
// if there is any maximized group exit the maximized state
exitMaximizedGroup();
// is there a maximized group
const result: boolean = hasMaximizedGroup();
```
The following methods are available on both the panel and group `api` objects:
> `api.<method>` is equivalent to `api.group.api.<method>` for all of these methods. The methods exist on the panel `api` object for convenience.
```ts
// maximize the group
api.maximize();
// is this group maximized (if another group is maximized this method will still return false)
const result: boolean = api.isMaxmized();
// exit only if this group is maximzied (if another group is maxmized this has no affect)
api.exitMaximized();
```
<MultiFrameworkContainer
height={600}
sandboxId="maximizegroup-dockview"
react={DockviewMaximizeGroup}
/>
## Panels ## Panels
@ -416,7 +513,7 @@ Finally `addPanel` accepts a `position` object which tells dockview where to pla
- This object accepts a `direction` property which dictates where, - This object accepts a `direction` property which dictates where,
relative to the provided reference the new panel will be placed. relative to the provided reference the new panel will be placed.
> If neither a `referencePanel` or `referenceGroup` then the provided `direction` will be treated as absolute. > If neither a `referencePanel` or `referenceGroup` is provided then the `direction` will be treated as absolute.
> If no `direction` is provided the library will place the new panel in a pre-determined position. > If no `direction` is provided the library will place the new panel in a pre-determined position.
@ -436,6 +533,23 @@ const panel2 = api.addPanel({
}); });
``` ```
To add a floating panel you should include the `floating` variable which can be either a `boolean` or an object defining it's bounds.
These bounds are relative to the dockview component.
```ts
const panel1 = api.addPanel({
id: 'panel_2',
component: 'default',
floating: true,
});
const panel2 = api.addPanel({
id: 'panel_2',
component: 'default',
floating: { x: 10, y: 10, width: 300, height: 300 },
});
```
### Update Panel ### Update Panel
You can programatically update the `params` passed through to the panel through the panal api using `api.updateParameters`. You can programatically update the `params` passed through to the panel through the panal api using `api.updateParameters`.
@ -470,20 +584,69 @@ panel.api.updateParameters({
}); });
``` ```
### Move panel
You can programatically move a panel using the panel `api`.
```ts
panel.api.moveTo({ group, position, index });
```
An equivalent method for moving groups is avaliable on the group `api`.
```ts
const group = panel.api.group;
group.api.moveTo({ group, position });
```
### Remove panel
You can programatically remove a panel using the panel `api`.
```ts
panel.api.close();
```
Given a reference to the panel you can also use the component `api` to remove it.
```ts
const panel = api.getPanel('myPanel');
api.removePanel(panel);
```
### Panel Rendering ### Panel Rendering
#### Render Mode
Dockview has two rendering modes `onlyWhenVisible` (default) and `always`. A rendering mode can be defined through the `renderer` prop to `DockviewReact` or at an individual panel level when added where
the panel declaration takes precedence if both are defined. Rendering modes defined at the panel level are persisted, those defined at the `DockviewReact` level are not persisted.
- `onlyWhenVisible` mode is the default mode. In this mode when a panel is no longer visible through either it's visiblity being hidden or it not being the active panel within a group the panels HTMLElement is removed
from the DOM and any DOM state such as scrollbar positions will be lost. If you are using any ResizeObservers to measure size this will result both zero height and width as the HTMLElement no longer belongs to the DOM.
This design allows for maximum performance at some cost.
- `always` mode. In this mode when panels become hidden the HTMLElement is not destroyed so all DOM state such as scrollbar positions will be maintained. This is implemented by rendering each panel as an absolutely positioned
HTMLElement and hidden the HTMLElement with `display: none` when it should be hidden.
<MultiFrameworkContainer
height={500}
sandboxId="rendermode-dockview"
react={DockviewRenderMode}
/>
####
By default `DockviewReact` only adds to the DOM those panels that are visible, By default `DockviewReact` only adds to the DOM those panels that are visible,
if a panel is not the active tab and not shown the contents of the hidden panel will be removed from the DOM. if a panel is not the active tab and not shown the contents of the hidden panel will be removed from the DOM.
However the React Components associated with each panel are only created once and will always exist for as long as the panel exists, hidden or not. When a panel is in `onlyWhenVisible` render mode this only affects the contents within the DOM. The lifecycle of that panel instance is still maintained.
The React Components associated with each panel are only created once and will always exist for as long as the panel exists, hidden or not.
> For example this means that any hooks in those components will run whether the panel is visible or not which may lead to excessive background work depending > e.g. This means that any hooks in those components will run whether the panel is visible or not which may lead to excessive background work depending
> on the panels implementation. > on the panels implementation.
This is the default behaviour to ensure the greatest flexibility for the user but through the panels `props.api` you can listen to the visiblity state of the panel You can listen to the visiblity state of the panel and write additional logic to optimize your application if required, although this is an advanced case.
and write additional logic to optimize your application.
For example if you wanted to unmount the React Components when the panel is not visible you could create a Higher-Order-Component that listens to the panels If you wanted to unmount the React Components when the panel is not visible you could create a Higher-Order-Component that listens to the panels
visiblity state and only renders the panel when visible. visiblity state and only renders the panel when visible.
```tsx title="Only rendering the React Component when the panel is visible, otherwise rendering a null React Component" ```tsx title="Only rendering the React Component when the panel is visible, otherwise rendering a null React Component"
@ -524,9 +687,11 @@ const components = { default: RenderWhenVisible(MyComponent) };
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. 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.
<Container sandboxId="rendering-dockview">
<RenderingDockview renderVisibleOnly={false} /> <MultiFrameworkContainer
</Container> sandboxId="rendering-dockview"
react={RenderingDockview}
/>
## Headers ## Headers
@ -535,7 +700,9 @@ Toggling the checkbox you can see that when you only render those panels which a
You can provide custom renderers for your tab headers for maximum customization. You can provide custom renderers for your tab headers for maximum customization.
A default implementation of `DockviewDefaultTab` is provided should you only wish to attach minor A default implementation of `DockviewDefaultTab` is provided should you only wish to attach minor
changes and events that do not alter the default behaviour, for example to add a custom context menu event changes and events that do not alter the default behaviour, for example to add a custom context menu event
handler. handler or to hide the close button.
The `DockviewDefaultTab` component accepts a `hideClose` prop if you wish only to hide the close button.
```tsx title="Attaching a custom context menu event handlers to a custom header" ```tsx title="Attaching a custom context menu event handlers to a custom header"
import { IDockviewPanelHeaderProps, DockviewDefaultTab } from 'dockview'; import { IDockviewPanelHeaderProps, DockviewDefaultTab } from 'dockview';
@ -545,7 +712,7 @@ const MyCustomheader = (props: IDockviewPanelHeaderProps) => {
event.preventDefault(); event.preventDefault();
alert('context menu'); alert('context menu');
}; };
return <DockviewDefaultTab onContextMenu={onContextMenu} {...props} />; return <DockviewDefaultTab onContextMenu={onContextMenu} hideClose={true} {...props} />;
}; };
``` ```
@ -580,9 +747,10 @@ As a simple example the below attaches a custom event handler for the context me
The below example uses a custom tab renderer to reigster a popover when the user right clicked on a tab. The below example uses a custom tab renderer to reigster a popover when the user right clicked on a tab.
This still makes use of the `DockviewDefaultTab` since it's only a minor change. This still makes use of the `DockviewDefaultTab` since it's only a minor change.
<Container sandboxId="customheader-dockview"> <MultiFrameworkContainer
<CustomHeadersDockview /> sandboxId="customheader-dockview"
</Container> react={CustomHeadersDockview}
/>
### Default Tab Title ### Default Tab Title
@ -605,9 +773,10 @@ api.setTitle('my_new_custom_title');
> Note this only works when using the default tab implementation. > Note this only works when using the default tab implementation.
<Container sandboxId="updatetitle-dockview"> <MultiFrameworkContainer
<DockviewSetTitle /> sandboxId="updatetitle-dockview"
</Container> react={DockviewSetTitle}
/>
### Custom Tab Title ### Custom Tab Title
@ -679,26 +848,38 @@ You can still add groups to a locked panel programatically using the API though.
```tsx ```tsx
panel.group.locked = true; panel.group.locked = true;
// Or
panel.group.locked = 'no-drop-target';
``` ```
Use `true` to keep drop zones top, right, bottom, left for the group. Use `no-drop-target` to disable all drop zones. For you to get a
better understanding of what this means, try and drag the panels in the example below to the locked groups.
<MultiFrameworkContainer
sandboxId="lockedgroup-dockview"
react={DockviewLockedGroup}
/>
### Group Controls Panel ### Group Controls Panel
`DockviewReact` accepts a prop `groupControlComponent` which expects a React component whos props are `IDockviewGroupControlProps`. `DockviewReact` accepts `leftHeaderActionsComponent`, `rightHeaderActionsComponent` and `prefixHeaderActionsComponent` which expect a React component with props `IDockviewHeaderActionsProps`.
This control will be rendered inside the header bar on the right hand side for each group of tabs. These controls are rendered to left and right side of the space to the right of the tabs in the header bar as well as before the first tab in the case of the prefix header prop.
```tsx ```tsx
const Component: React.FunctionComponent<IDockviewGroupControlProps> = () => { const Component: React.FunctionComponent<IDockviewHeaderActionsProps> = () => {
return <div>{'...'}</div>; return <div>{'...'}</div>;
}; };
return <DockviewReact {...props} groupControlComponent={Component} />; return <DockviewReact {...props} leftHeaderActionsComponent={Component} rightHeaderActionsComponent={...} />;
``` ```
As a simple example the below uses the `groupControlComponent` to render a small control that indicates whether the group As a simple example the below uses the `groupControlComponent` to render a small control that indicates whether the group
is active and which panel is active in that group. is active and which panel is active in that group.
```tsx ```tsx
const GroupControlComponent = (props: IDockviewGroupControlProps) => { const RightHeaderActionsComponent = (props: IDockviewHeaderActionsProps) => {
const isGroupActive = props.isGroupActive; const isGroupActive = props.isGroupActive;
const activePanel = props.activePanel; const activePanel = props.activePanel;
@ -720,9 +901,10 @@ const GroupControlComponent = (props: IDockviewGroupControlProps) => {
}; };
``` ```
<Container sandboxId="groupcontrol-dockview"> <MultiFrameworkContainer
<DockviewGroupControl /> sandboxId="groupcontrol-dockview"
</Container> react={DockviewGroupControl}
/>
### Constraints ### Constraints
@ -736,9 +918,12 @@ api.group.api.setConstraints(...)
> If you specific a constraint on a group and move a panel within that group to another group it will no > If you specific a constraint on a group and move a panel within that group to another group it will no
> longer be subject to those constraints since those constraints were on the group and not on the individual panel. > longer be subject to those constraints since those constraints were on the group and not on the individual panel.
<Container height={500} sandboxId="constraints-dockview"> <MultiFrameworkContainer
<DockviewConstraints /> height={500}
</Container> sandboxId="constraints-dockview"
react={DockviewConstraints}
/>
## iFrames ## iFrames
@ -748,55 +933,54 @@ iFrames required special attention because of a particular behaviour in how iFra
You can find many examples of discussions on this. Two reputable forums for example are linked [here](https://bugzilla.mozilla.org/show_bug.cgi?id=254144) and [here](https://github.com/whatwg/html/issues/5484). You can find many examples of discussions on this. Two reputable forums for example are linked [here](https://bugzilla.mozilla.org/show_bug.cgi?id=254144) and [here](https://github.com/whatwg/html/issues/5484).
The problem with iFrames and `dockview` is that when you hide or move a panel that panels DOM element may be moved within the DOM or removed from the DOM completely. To ensure iFrames work as expected you should render them in panels with `renderer: 'always'` to ensure they are never removed from the DOM, alternatively set the defaultRenderer to `always`.
If your panel contains an iFrame then that iFrame will reload after being re-positioned within the DOM tree and all state in that iFrame will most likely be lost.
`dockview` does not provide a built-in solution to this because it's too specific of a problem to include in the library. > See the **Panel Rendering** section for more information of render modes.
However the below example does show an implementation of a higher-order component `HoistedDockviewPanel`that you could use to work around this problems and make iFrames behave in `dockview`.
What the higher-order component is doing is to hoist the panels contents into a DOM element that is always present and then `position: absolute` that element to match the dimensions of it's linked panel. ```tsx title="Example of a panel using an alternative renderer"
The visibility of these hoisted elements is then controlled through some exposed api methods to hide elements that shouldn't be currently shown. api.addPanel({
id: 'my_panel_id',
component: 'my_component',
renderer: 'always',
});
```
You should open this example in CodeSandbox using the provided link to understand the code and make use of this implemention if required. <MultiFrameworkContainer
sandboxId="iframe-dockview"
<Container sandboxId="iframe-dockview" height={600}> height={600}
<DockviewWithIFrames /> react={DockviewWithIFrames}
</Container> />
## Events ## Events
A simple example showing events fired by `dockviewz that can be interacted with. A simple example showing events fired by `dockviewz that can be interacted with.
<Container height={600} sandboxId="events-dockview"> <MultiFrameworkContainer
<EventsDockview /> height={600}
</Container> sandboxId="events-dockview"
react={EventsDockview}
/>
## Advanced Examples ## Keyboard Navigation
Keyboard shortcuts
<MultiFrameworkContainer
height={600}
sandboxId="keyboard-dockview"
react={DockviewKeyboard}
/>
### Nested Dockviews ### Nested Dockviews
You can safely create multiple dockview instances within one page and nest dockviews within other dockviews. You can safely create multiple dockview instances within one page and nest dockviews within other dockviews.
If you wish to interact with the drop event from one dockview instance in another dockview instance you can implement the `showDndOverlay` and `onDidDrop` props on `DockviewReact`. If you wish to interact with the drop event from one dockview instance in another dockview instance you can implement the `showDndOverlay` and `onDidDrop` props on `DockviewReact`.
<Container sandboxId="nested-dockview"> <MultiFrameworkContainer sandboxId="nested-dockview" react={NestedDockview} />
<NestedDockview />
</Container>
### Window-like mananger with tabs ### Window-like mananger with tabs
<DockviewNative2 />
## Vanilla JS <MultiFrameworkContainer sandboxId="nativeapp-dockview" react={DockviewNative2} />
> Note: This section is experimental and support for Vanilla JS is a work in progress.
The `dockview` package contains `ReactJS` wrappers for the core library.
The core library is published as an independant package under the name `dockview-core` which you can install standalone.
> When using `dockview` there is no need to also install `dockview-core`.
> `dockview-core` is a dependency of `dockview` and automatically installed during the installation process of `dockview` via `npm install dockview`.
<Container
sandboxId="typescript/vanilla-dockview"
injectVanillaJS={attachDockviewVanilla}
/>

View File

@ -0,0 +1,235 @@
---
description: Gridview Documentation
---
import { MultiFrameworkContainer } from '@site/src/components/ui/container';
import SimpleGridview from '@site/sandboxes/simple-gridview/src/app';
import EditorGridview from '@site/sandboxes/editor-gridview/src/app';
// import SimpleGridview from '@site/sandboxes/simple-gridview/src/app';
import { EventsGridview } from '@site/src/components/gridview/events';
// import IDEExample from '@site/sandboxes/ide-example/src/app';
import Link from '@docusaurus/Link';
import { DocRef } from '@site/src/components/ui/reference/docRef';
# Gridview
Gridview is a collection of nested splitviews and is the foundation for the [Dockview](./dockview) component.
Gridview serves a purpose when you want only the nested splitviews with no tabs and no headers.
## Introduction
<MultiFrameworkContainer
height={600}
sandboxId="simple-gridview"
react={SimpleGridview}
/>
## GridviewReact Component
```tsx
import { ReactGridview } from 'dockview';
```
<DocRef declaration="IGridviewReactProps" />
## 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...
};
```
<DocRef declaration="GridviewApi" />
## Gridview Panel API
```tsx
const MyComponent = (props: IGridviewPanelProps<{ title: string }>) => {
// props.api...
return <div>{`My first panel has the title: ${props.params.title}`}</div>;
};
```
<DocRef declaration="GridviewPanelApi" />
## Resizing
### Panel Resizing
You can set the size of a panel using `props.api.setSize(...)`.
```tsx
// it's mandatory to provide either a height or a width, providing both is optional
props.api.setSize({
height: 100,
width: 200,
});
```
You can update any constraints on the panel. All parameters are optional.
```tsx
props.api.setConstraints({
minimumHeight: 100,
maximumHeight: 1000
minimumWidth: 100,
maximumWidth: 1000
});
```
You can hide a panel by setting it's visibility to `false`. Hidden panels retain their size
at the point of being hidden, if made visible again they will try to resize to the remembered size.
```tsx
props.api.setVisible(false);
```
## Panels
### Add Panel
Using the gridview API you can access the `addPanel` method which returns an instance of the created panel.
The minimum method signature is:
```ts
const panel = api.addPanel({
id: 'my_unique_panel_id',
component: 'my_component',
});
```
where `id` is the unique id of the panel and `component` is the implenentation which
will be used to render the panel. You will have registered this using the `components` prop of the `GridviewReactComponent` component.
You can pass bounding constraints to limit the size of the panel.
```ts
const panel = api.addPanel({
id: 'my_unique_panel_id',
component: 'my_component',
minimumHeight: 100,
maximumHeight: 1000,
minimumWidth: 100,
maximumWidth: 1000,
});
```
You can pass a `snap` parameter which will hide the panel when an attempt is made to move it beyond a minimum width or height if one exists.
```ts
const panel = api.addPanel({
id: 'my_unique_panel_id',
component: 'my_component',
minimumHeight: 100,
snap: true,
});
```
You can pass a `priority` parameter which will keep the panel a certain priority when being resized. This is useful when you know you want this
panel to always take the first available or last available space. The default is `LayoutPriority.Normal` which defers space allocations to the libraries discression.
```ts
const panel = api.addPanel({
id: 'my_unique_panel_id',
component: 'my_component',
minimumHeight: 100,
priority: LayoutPriority.High,
});
```
You can pass properties to the panel using the `params` key.
You can update these properties through the panels `api` object and its `updateParameters` method.
```ts
const panel = api.addPanel({
id: 'my_unique_panel_id',
component: 'my_component',
params: {
myCustomKey: 'my_custom_value',
},
});
```
```tsx
panel.api.updateParameters({
myCustomKey: 'my_custom_value',
myOtherCustomKey: 'my_other_custom_key',
});
```
> Note `updateParameters` does not accept partial parameter updates, you should call it with the entire set of parameters
> you want the panel to receive.
Finally `addPanel` accepts a `position` object which tells dockview where to place the panel.
- This object accepts a `referencePanel` which can be the associated id as a string
or the panel object reference.
- This object accepts a `direction` property which dictates where,
relative to the provided reference the new panel will be placed.
> If a `referencePanel` is not passed then the `direction` will be treated as absolute.
> If no `direction` is provided the library will place the new panel in a pre-determined position.
```ts
const panel = api.addPanel({
id: 'panel_1',
component: 'default',
});
const panel2 = api.addPanel({
id: 'panel_2',
component: 'default',
position: {
referencePanel: panel1,
direction: 'right',
},
});
```
> Note `updateParameters` does not accept partial parameter updates, you should call it with the entire set of parameters
> you want the panel to receive.
## Theme
As well as importing the `dockview` stylesheet you must provide a class-based theme somewhere in your application. For example.
```tsx
// Providing a theme directly through the DockviewReact component props
<GridviewReact className="dockview-theme-dark" />
// Providing a theme somewhere in the DOM tree
<div className="dockview-theme-dark">
<div>
{/**... */}
<GridviewReact />
</div>
</div>
```
You can find more details on theming <Link to="../theme">here</Link>.
## 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 />
## Complex Example
<MultiFrameworkContainer
height={600}
sandboxId="editor-gridview"
react={EditorGridview}
hideThemePicker={true}
/>

View File

@ -0,0 +1,228 @@
---
description: Paneview Documentation
---
import { MultiFrameworkContainer } from '@site/src/components/ui/container';
import SimplePaneview from '@site/sandboxes/simple-paneview/src/app';
import { CustomHeaderPaneview } from '@site/src/components/paneview/customHeader';
import { DragAndDropPaneview } from '@site/src/components/paneview/dragAndDrop';
import { SideBySidePaneview } from '@site/src/components/paneview/sideBySide';
import Link from '@docusaurus/Link';
import { DocRef } from '@site/src/components/ui/reference/docRef';
# 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
<MultiFrameworkContainer sandboxId="simple-paneview" react={SimplePaneview} />
```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-abyss"
/>
);
};
```
## PaneviewReact Component
You can create a Paneview through the use of the `ReactPaneview` component.
```tsx
import { ReactPaneview } from 'dockview';
```
<DocRef declaration="IPaneviewReactProps" />
## 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...
};
```
<DocRef declaration="PaneviewApi" />
## Paneview Panel API
```tsx
const MyComponent = (props: IGridviewPanelProps<{ title: string }>) => {
// props.api...
return <div>{`My first panel has the title: ${props.params.title}`}</div>;
};
```
<DocRef declaration="PaneviewPanelApi" />
## 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 />
### Interactions
You can safely create multiple paneview instances within one page. They will not interact with each other by default.
If you wish to interact with the drop event from one paneview instance in another paneview instance you can implement the `showDndOverlay` and `onDidDrop` props on `PaneviewReact`.
As an example see how dragging a header from one control to another will only trigger an interactable event for the developer if the checkbox is enabled.
<SideBySidePaneview />

View File

@ -0,0 +1,196 @@
---
description: Splitview Documentation
---
import { SimpleSplitview } from '@site/src/components/simpleSplitview';
import { SplitviewExample1 } from '@site/src/components/splitview/active';
import Link from '@docusaurus/Link';
import { DocRef } from '@site/src/components/ui/reference/docRef';
# 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-abyss"
/>
);
};
```
## 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.
<DocRef declaration="ISplitviewReactProps" />
## 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...
};
```
<DocRef declaration="SplitviewApi" />
## 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>;
};
```
<DocRef declaration="SplitviewPanelApi" />
## 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,54 @@
---
sidebar_position: 3
description: Contributing
---
# Contributing
# Project description
Pre-requisites: Node >=18, Yarn
Dockview is a layout manager library designed to provide a complete layouting solution.
It is written in plain TypeScript and can be used without any framework although
an extensive React wrapper has always and will always be provided for those using the React framework.
The project is hosted on GitHub and developed within a Monorepo powered by [Lerna](https://github.com/lerna/lerna).
It is developed using the `yarn` package manager since at the time of creation `yarn` was far superior when it came to managing monorepos.
The Monorepo contains three packages:
#### packages/dockview-core
The core project is entirely written in plain TypeScript without any frameworks or dependencies and it's source-code can be found
within the `dockview-core` package which is also published to npm.
#### packages/dockview
A complete collection of React components for use through the React framework to use dockview seamlessly
and is published to npm. It depends explicitly on `dockview-core` so there is no need to additionally install `dockview-core`.
> Dockview was originally a React-only library which is why the React version maintains the name `dockview` after
> splitting the core logic into a seperate package named `dockview-core`.
#### packages/docs
This package contains the code for this documentation website and examples hosted through **CodeSandbox**. It is **not** a published package on npm.
# Run the project locally
1. After you have cloned the project from GitHub run `yarn` at the root of the project which will install all project dependencies.
2. In order build `packages/dockview-core` then `packages/dockview`.
3. Run the docs website through `npm run start` in the `packages/docs` directory and go to _http://localhost:3000_ which
will now be running the local copy of `dockview` that you have just built.
### Examples
All examples can be found under [**packages/docs/sandboxes**](https://github.com/mathuo/dockview/tree/master/packages/docs/sandboxes).
Each example is an independently runnable example through **CodeSandbox**.
Through the documentation you will see links to runnable **CodeSandbox** examples.
## FAQ
#### Are there any plans to publish wrapper libraries for other frameworks such as Angular and Vue?
Currently no but this is open for contributors to try.

View File

@ -0,0 +1,88 @@
---
sidebar_position: 0
description: A zero dependency layout manager supporting ReactJS and Vanilla TypeScript
---
import { MultiFrameworkContainer } from '@site/src/components/ui/container';
import { SimpleSplitview } from '@site/src/components/simpleSplitview';
import { SimpleGridview } from '@site/src/components/simpleGridview';
import { SimplePaneview } from '@site/src/components/simplePaneview';
import DockviewDemo from '@site/sandboxes/demo-dockview/src/app';
import Link from '@docusaurus/Link';
# Introduction
**dockview** is a zero dependency layout manager that supports tab, grids and splitviews.
## 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';
```
There are 4 components you may want to use:
<Link to="./components/dockview">
<h2>Dockview</h2>
</Link>
<MultiFrameworkContainer
height={500}
sandboxId="demo-dockview"
react={DockviewDemo}
/>
<Link to="./components/splitview">
<h2>Splitview</h2>
</Link>
<div
style={{
height: '100px',
backgroundColor: 'rgb(30,30,30)',
color: 'white',
margin: '20px 0px',
}}
>
<SimpleSplitview />
</div>
<Link to="./components/gridview">
<h2>Gridview</h2>
</Link>
<div
style={{
height: '300px',
backgroundColor: 'rgb(30,30,30)',
color: 'white',
margin: '20px 0px',
}}
>
<SimpleGridview />
</div>
<Link to="./components/paneview">
<h2>Paneview</h2>
</Link>
<div
style={{
height: '300px',
backgroundColor: 'rgb(30,30,30)',
color: 'white',
margin: '20px 0px',
}}
>
<SimplePaneview />
</div>

View File

@ -1,29 +1,31 @@
--- ---
sidebar_position: 3 sidebar_position: 1
description: Theming Dockview Components description: Theming Dockview Components
--- ---
import { CustomCSSDockview } from '@site/src/components/dockview/customCss';
# Theme # Theme
## Introduction ## Introduction
`dockview` requires some css to work correctly. `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) 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 and should be imported at some point in your application
```css ```css title="Example import with .css file"
@import './node_modules/dockview/dist/styles/dockview.css'; @import './node_modules/dockview/dist/styles/dockview.css';
``` ```
## Provided themes ## Provided themes
The following are provided as classes that you can attached to your components for themeing `dockview` comes with a number of themes which are all CSS classes and can be found [here](https://github.com/mathuo/dockview/blob/master/packages/dockview-core/src/theme.scss).
To use a `dockview` theme the CSS must encapsulate the component. The current list of themes is:
- `.dockview-theme-light` - `dockview-theme-dark`
- `.dockview-theme-dark` - `dockview-theme-light`
- `.dockview-theme-abyss` - `dockview-theme-vs`
- `dockview-theme-abyss`
- `dockview-theme-dracula`
- `dockview-theme-replit`
## Customizing Theme ## Customizing Theme
@ -58,11 +60,16 @@ and are free to build your own themes based on these css properties.
| | | | | |
| --dv-separator-border | | | --dv-separator-border | |
| --dv-paneview-header-border-color | | | --dv-paneview-header-border-color | |
| | |
| --dv-icon-hover-background-color | |
| --dv-floating-box-shadow | |
| --dv-active-sash-color | |
| --dv-background-color | |
You can further customise the theme through adjusting class properties but this is up you. 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: For 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 ```css title="Additional CSS to show a bottom border on active groups"
.groupview { .groupview {
&.active-group { &.active-group {
> .tabs-and-actions-container { > .tabs-and-actions-container {
@ -76,14 +83,3 @@ As an example if you wanted to add a bottom border to the tab container for an a
} }
} }
``` ```
<div
style={{
height: '300px',
backgroundColor: 'rgb(30,30,30)',
color: 'white',
margin: '20px 0px',
}}
>
<CustomCSSDockview />
</div>

View File

@ -1,4 +1,4 @@
[ [
"1.8.4", "1.9.0",
"1.7.6" "1.8.4"
] ]