feat: docs website

This commit is contained in:
mathuo 2022-04-27 18:27:29 +01:00
parent 9a38f039f4
commit 30a42a6fcd
No known key found for this signature in database
GPG Key ID: C6EEDEFD6CA07281
32 changed files with 86178 additions and 34654 deletions

View File

@ -2,6 +2,8 @@
"packages": [ "packages": [
"packages/*" "packages/*"
], ],
"npmClient": "yarn",
"useWorkspaces": true,
"version": "1.3.0", "version": "1.3.0",
"command": { "command": {
"publish": { "publish": {

34501
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -2,6 +2,9 @@
"name": "dockview-monorepo-root", "name": "dockview-monorepo-root",
"private": true, "private": true,
"description": "Monorepo for https://github.com/mathuo/dockview", "description": "Monorepo for https://github.com/mathuo/dockview",
"workspaces": [
"packages/*"
],
"scripts": { "scripts": {
"test": "jest", "test": "jest",
"lint": "eslint packages/**/src/** --ext .ts,.tsx,.js,.jsx", "lint": "eslint packages/**/src/** --ext .ts,.tsx,.js,.jsx",

View File

@ -1,20 +1,23 @@
// const remarkFrontmatter = import('remark-frontmatter');
// const rehypePrismPlus = import('rehype-prism-plus');
// const remarkPrism = import('remark-prism');
// const transpile = require('next-transpile-modules');
// import mdx from '@next/mdx';
import transpile from 'next-transpile-modules'; import transpile from 'next-transpile-modules';
import slugs from 'rehype-slug'; import slugs from 'rehype-slug';
import autoLinkHeadings from 'rehype-autolink-headings'; import autoLinkHeadings from 'rehype-autolink-headings';
import mdx from '@next/mdx'; import mdx from '@next/mdx';
import remarkGfm from 'remark-gfm';
const withTM = transpile(['dockview']); const withTM = transpile(['dockview', 'dockview-demo'], {
resolveSymlinks: true,
});
import path from 'path';
import { URL } from 'url'; // in Browser, the URL in native accessible on window
const __dirname = new URL('.', import.meta.url).pathname;
const withMDX = mdx({ const withMDX = mdx({
extension: /\.mdx$/, extension: /\.mdx$/,
options: { options: {
remarkPlugins: [], remarkPlugins: [remarkGfm],
rehypePlugins: [ rehypePlugins: [
slugs, slugs,
[ [
@ -30,9 +33,33 @@ const withMDX = mdx({
export default withTM( export default withTM(
withMDX({ withMDX({
pageExtensions: ['js', 'jsx', 'ts', 'tsx', 'md', 'mdx'], reactStrictMode: true,
pageExtensions: ['ts', 'tsx', 'js', 'jsx', 'md', 'mdx'],
experimental: { experimental: {
externalDir: true, externalDir: true,
}, },
webpack(config, options) {
if (options.isServer) {
config.externals = ['react', 'react-dom', ...config.externals];
}
config.module.rules.push({
test: /\.tsx?|\.ts?$/,
use: [options.defaultLoaders.babel],
});
// config.resolve.alias['react'] = path.resolve(
// __dirname,
// '.',
// 'node_modules',
// 'react-dom'
// );
// config.resolve.alias['react-dom'] = path.resolve(
// __dirname,
// '.',
// 'node_modules',
// 'react-dom'
// );
return config;
},
}) })
); );

File diff suppressed because it is too large Load Diff

View File

@ -18,18 +18,14 @@
"react": "^18.0.0", "react": "^18.0.0",
"react-dom": "^18.0.0", "react-dom": "^18.0.0",
"rehype-autolink-headings": "^6.1.1", "rehype-autolink-headings": "^6.1.1",
"rehype-prism-plus": "^1.3.2",
"rehype-slug": "^5.0.1", "rehype-slug": "^5.0.1",
"remark-autolink-headings": "^7.0.1", "remark-gfm": "^3.0.1"
"remark-frontmatter": "^4.0.1",
"remark-prism": "^1.3.6",
"remark-slug": "^7.0.1"
}, },
"devDependencies": { "devDependencies": {
"@types/node": "17.0.25", "@types/node": "17.0.28",
"@types/react": "^18.0.6", "@types/react": "^18.0.8",
"@types/react-dom": "^18.0.2", "@types/react-dom": "^18.0.2",
"eslint": "8.13.0", "eslint": "8.14.0",
"eslint-config-next": "12.1.5", "eslint-config-next": "12.1.5",
"next-transpile-modules": "^9.0.0", "next-transpile-modules": "^9.0.0",
"typescript": "4.6.3" "typescript": "4.6.3"

View File

@ -13,7 +13,12 @@ export const Container = (props: { children: React.ReactNode }) => {
<div style={{ padding: '20px' }}> <div style={{ padding: '20px' }}>
<Navigation pages={PAGES} /> <Navigation pages={PAGES} />
</div> </div>
<div style={{ flexGrow: 1, padding: '20px' }}>{props.children}</div> <div
style={{ flexGrow: 1, padding: '20px' }}
className="markdown-body"
>
{props.children}
</div>
</main> </main>
); );
}; };

View File

@ -31,7 +31,7 @@ export const Header = (props: {}) => {
return ( return (
<div <div
style={{ style={{
height: '1000px', height: '0px',
backgroundColor: '#0070f3', backgroundColor: '#0070f3',
padding: '5vw', padding: '5vw',
}} }}

View File

@ -0,0 +1,100 @@
import {
DockviewReact,
DockviewReadyEvent,
IDockviewPanelProps,
} from 'dockview';
const components = {
default: (props: IDockviewPanelProps<{ title: string }>) => {
return <div style={{ padding: '20px' }}>{props.params.title}</div>;
},
};
export const SimpleDockview = () => {
const onReady = (event: DockviewReadyEvent) => {
event.api.onDidLayoutChange(() => {
localStorage.setItem(
'dockview_test',
JSON.stringify(event.api.toJSON())
);
});
const layout = localStorage.getItem('dockview_test');
if (layout) {
event.api.fromJSON(JSON.parse(layout));
return;
}
event.api.addPanel({
id: 'panel_1',
component: 'default',
params: {
title: 'Panel 1',
},
});
event.api.addPanel({
id: 'panel_2',
component: 'default',
params: {
title: 'Panel 2',
},
});
event.api.addPanel({
id: 'panel_3',
component: 'default',
params: {
title: 'Panel 3',
},
});
event.api.addPanel({
id: 'panel_4',
component: 'default',
params: {
title: 'Panel 4',
},
position: { referencePanelId: 'panel_1', direction: 'right' },
});
const panel5 = event.api.addPanel({
id: 'panel_5',
component: 'default',
params: {
title: 'Panel 5',
},
position: { referencePanelId: 'panel_3', direction: 'right' },
});
// panel5.group!.model.header.hidden = true;
// panel5.group!.model.locked = true;
event.api.addPanel({
id: 'panel_6',
component: 'default',
params: {
title: 'Panel 6',
},
position: { referencePanelId: 'panel_5', direction: 'below' },
});
event.api.addPanel({
id: 'panel_7',
component: 'default',
params: {
title: 'Panel 7',
},
position: { referencePanelId: 'panel_6', direction: 'right' },
});
};
return (
<DockviewReact
components={components}
onReady={onReady}
className="dockview-theme-dark"
/>
);
};

View File

@ -0,0 +1,85 @@
import {
IGridviewPanelProps,
Orientation,
GridviewReact,
GridviewReadyEvent,
} from 'dockview';
const components = {
default: (props: IGridviewPanelProps<{ title: string }>) => {
return <div style={{ padding: '20px' }}>{props.params.title}</div>;
},
};
export const SimpleGridview = () => {
const onReady = (event: GridviewReadyEvent) => {
event.api.addPanel({
id: 'panel_1',
component: 'default',
params: {
title: 'Panel 1',
},
});
event.api.addPanel({
id: 'panel_2',
component: 'default',
params: {
title: 'Panel 2',
},
});
event.api.addPanel({
id: 'panel_3',
component: 'default',
params: {
title: 'Panel 3',
},
});
event.api.addPanel({
id: 'panel_4',
component: 'default',
params: {
title: 'Panel 4',
},
position: { reference: 'panel_1', direction: 'right' },
});
event.api.addPanel({
id: 'panel_5',
component: 'default',
params: {
title: 'Panel 5',
},
position: { reference: 'panel_3', direction: 'right' },
});
event.api.addPanel({
id: 'panel_6',
component: 'default',
params: {
title: 'Panel 6',
},
position: { reference: 'panel_5', direction: 'below' },
});
event.api.addPanel({
id: 'panel_7',
component: 'default',
params: {
title: 'Panel 7',
},
position: { reference: 'panel_6', direction: 'right' },
});
};
return (
<GridviewReact
components={components}
onReady={onReady}
orientation={Orientation.VERTICAL}
className="dockview-theme-dark"
/>
);
};

View File

@ -0,0 +1,50 @@
import {
IPaneviewPanelProps,
PaneviewReact,
PaneviewReadyEvent,
} from 'dockview';
const components = {
default: (props: IPaneviewPanelProps<{ title: string }>) => {
return <div style={{ padding: '20px' }}>{props.params.title}</div>;
},
};
export const 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}
onReady={onReady}
className="dockview-theme-dark"
/>
);
};

View File

@ -7,11 +7,11 @@ import {
const components = { const components = {
default: (props: ISplitviewPanelProps<{ title: string }>) => { default: (props: ISplitviewPanelProps<{ title: string }>) => {
return <div style={{ margin: '20px' }}>{props.params.title}</div>; return <div style={{ padding: '20px' }}>{props.params.title}</div>;
}, },
}; };
export const SimpleSplitview = () => { export const SimpleSplitview = (props: { proportional?: boolean }) => {
const onReady = (event: SplitviewReadyEvent) => { const onReady = (event: SplitviewReadyEvent) => {
event.api.addPanel({ event.api.addPanel({
id: 'panel_1', id: 'panel_1',
@ -19,6 +19,7 @@ export const SimpleSplitview = () => {
params: { params: {
title: 'Panel 1', title: 'Panel 1',
}, },
minimumSize: 100,
}); });
event.api.addPanel({ event.api.addPanel({
@ -27,6 +28,7 @@ export const SimpleSplitview = () => {
params: { params: {
title: 'Panel 2', title: 'Panel 2',
}, },
minimumSize: 100,
}); });
event.api.addPanel({ event.api.addPanel({
@ -35,12 +37,14 @@ export const SimpleSplitview = () => {
params: { params: {
title: 'Panel 3', title: 'Panel 3',
}, },
minimumSize: 100,
}); });
}; };
return ( return (
<SplitviewReact <SplitviewReact
components={components} components={components}
proportionalLayout={props.proportional}
onReady={onReady} onReady={onReady}
orientation={Orientation.HORIZONTAL} orientation={Orientation.HORIZONTAL}
className="dockview-theme-dark" className="dockview-theme-dark"

View File

@ -0,0 +1,91 @@
import { SimpleSplitview } from '../components/simpleSplitview';
## 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).
You can disable this by settings the `disableAutoResizing` prop to be `true`.
## Proportional layout
<div
style={{
height: '100px',
backgroundColor: 'rgb(30,30,30)',
color: 'white',
margin: '20px 0px',
}}
>
<SimpleSplitview proportional={false} />
</div>
<div
style={{
height: '100px',
backgroundColor: 'rgb(30,30,30)',
color: 'white',
margin: '20px 0px',
}}
>
<SimpleSplitview proportional={true} />
</div>
## Panels
The below examples use `ReactSplitview` but the logic holds for `ReactPaneview`, `ReactGridview` and `ReactDockview` using their respective implementations and interfaces.
### 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>;
};
```
### Accessing the panel API
You can access an extensive set of functions in the panel via both the panel `api` and `containerApi`. The `api` is specific to that particular panel and the `containerApi` corresponds to that api which you access during the `onReady` event.
```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>
);
};
```

View File

@ -1,9 +0,0 @@
import { NextPage } from 'next';
const Page: NextPage = (props) => {
return (
<div style={{ height: '1000px', backgroundColor: 'red' }}>basics</div>
);
};
export default Page;

View File

@ -0,0 +1,12 @@
| Property | Type | Optional | Default | Description |
| ------------------- | ------------------------------------ | -------- | ------- | ----------- |
| onReady | (event: SplitviewReadyEvent) => void | No | | |
| components | object | No | | |
| tabComponents | object | Yes | | |
| watermarkComponent | object | Yes | | |
| hideBorders | boolean | Yes | false | |
| className | string | Yes | '' | |
| disableAutoResizing | boolean | Yes | false | |
| onTabContextMenu | Event | Yes | false | |
| onDidDrop | Event | Yes | false | |
| showDndOverlay | Event | Yes | false | |

View File

@ -0,0 +1,9 @@
| Property | Type | Optional | Default | Description |
| ------------------- | ------------------------------------ | -------- | ---------------------- | ----------- |
| onReady | (event: SplitviewReadyEvent) => void | No | | |
| components | object | No | | |
| orientation | Orientation | Yes | Orientation.HORIZONTAL | |
| proportionalLayout | boolean | Yes | true | |
| hideBorders | boolean | Yes | false | |
| className | string | Yes | '' | |
| disableAutoResizing | boolean | Yes | false | |

View File

@ -1,4 +1,7 @@
import { SimpleSplitview } from '../components/simpleSplitview'; import { SimpleSplitview } from '../components/simpleSplitview';
import { SimpleGridview } from '../components/simpleGridview';
import { SimplePaneview } from '../components/simplePaneview';
import { SimpleDockview } from '../components/simpleDockview';
# Introduction # Introduction
@ -45,11 +48,45 @@ Splitview
height: '100px', height: '100px',
backgroundColor: 'rgb(30,30,30)', backgroundColor: 'rgb(30,30,30)',
color: 'white', color: 'white',
margin: '20px 0px',
}} }}
> >
<SimpleSplitview /> <SimpleSplitview />
</div> </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 ```tsx
import { import {
DockviewReact, DockviewReact,

View File

@ -0,0 +1,9 @@
| Property | Type | Optional | Default | Description |
| ------------------- | ------------------------------------ | -------- | ------- | ----------- |
| onReady | (event: SplitviewReadyEvent) => void | No | | |
| components | object | No | | |
| headerComponents | object | Yes | | |
| className | string | Yes | '' | |
| disableAutoResizing | boolean | Yes | false | |
| disableDnd | boolean | Yes | false | |
| onDidDrop | Event | Yes | | |

View File

@ -0,0 +1,150 @@
import { SimpleSplitview } from '../components/simpleSplitview';
# Splitview
<div
style={{
height: '100px',
backgroundColor: 'rgb(30,30,30)',
color: 'white',
margin: '20px 0px',
}}
>
<SimpleSplitview />
</div>
```tsx
import {
ISplitviewPanelProps,
Orientation,
SplitviewReact,
SplitviewReadyEvent,
} from 'dockview';
const components = {
default: (props: ISplitviewPanelProps<{ title: string }>) => {
return <div style={{ padding: '20px' }}>{props.params.title}</div>;
},
};
export const SimpleSplitview = () => {
const onReady = (event: SplitviewReadyEvent) => {
event.api.addPanel({
id: 'panel_1',
component: 'default',
params: {
title: 'Panel 1',
},
});
event.api.addPanel({
id: 'panel_2',
component: 'default',
params: {
title: 'Panel 2',
},
});
event.api.addPanel({
id: 'panel_3',
component: 'default',
params: {
title: 'Panel 3',
},
});
};
return (
<SplitviewReact
components={components}
onReady={onReady}
orientation={Orientation.HORIZONTAL}
className="dockview-theme-dark"
/>
);
};
```
## Component Props
The `onReady` prop you will you access to the component `api`.
| Property | Type | Optional | Default | Description |
| ------------------- | -------------------------------------- | -------- | ------------------------ | ------------------------------------------------------- |
| onReady | `(event: SplitviewReadyEvent) => void` | No | | |
| components | `Record<string, ISplitviewPanelProps>` | No | | Panel renderers |
| orientation | `Orientation` | Yes | `Orientation.HORIZONTAL` | Orientation of the Splitview |
| proportionalLayout | `boolean` | Yes | `true` | See [Proportional layout](/basics/#proportional-layout) |
| hideBorders | `boolean` | Yes | `false` | Hide the borders between panels |
| className | `string` | Yes | `''` | Attaches a classname |
| disableAutoResizing | `boolean` | Yes | `false` | See [Auto resizing](/basics/#auto-resizing) |
## Splitview API
```tsx
const MyComponent = (props: ISplitviewPanelProps<{ title: string }>) => {
// props.containerApi...
return <div>{`My first panel has the title: ${props.params.title}`}</div>;
};
```
```tsx
const onReady = (event: SplitviewReadyEvent) => {
// event.api...
};
```
| Property | Type | Description |
| ------------------- | ------------------------------------------------------------------ | -------------------- |
| height | `number` | |
| width | `number` | |
| minimumSize | `number` | |
| maximumSize | `number` | |
| length | `number` | Number of panels |
| panels | `ISplitviewPanel[]` | |
| onDidLayoutChange | `Event<void>` | |
| onDidLayoutFromJSON | `Event<void>` | |
| onDidAddView | `Event<IView>` | |
| onDidRemoveView | `Event<IView>` | |
| addPanel | `addPanel(options: AddSplitviewComponentOptions): ISplitviewPanel` | |
| removePanel | `(panel: ISplitviewPanel, sizing?: Sizing): void` | |
| updateOptions | `(options:SplitviewComponentUpdateOptions): void` | |
| movePanel | `(from: number, to: number): void` | |
| setVisible | `(panel: ISplitviewPanel, isVisible: boolean): void` | |
| focus | `(): void` | |
| getPanel | `(id:string): ISplitviewPanel \| undefined` | |
| setActive | `(panel: ISplitviewPanel): void` | |
| layout | `(width: number, height:number): void` | |
| resizeToFit | `(): void` | |
| fromJSON | `(data: SerializedSplitview): void` | Deserialize a layout |
| toJSON | `(): SerializedSplitview` | Serialized a layout |
## Splitview Panel API
```tsx
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>` | |
| onDidFocusChange | `Event<FocusEvent>` | |
| onDidVisibilityChange | `Event<VisibilityEvent>` | |
| onDidActiveChange | `Event<ActiveEvent>` | |
| onFocusEvent | `Event<void>` | |
| setVisible | `(isVisible: boolean): void` | |
| setActive | `(): void` | |
| onDidConstraintsChange | `onDidConstraintsChange: Event<PanelConstraintChangeEvent>` | |
| setConstraints | `(value: PanelConstraintChangeEvent2): void;` | |
| setSize | `(event: PanelSizeEvent): void` | |

View File

@ -12,37 +12,21 @@ export const PAGES: Page[] = [
url: '#api', url: '#api',
routes: [ routes: [
{ {
title: 'Dockview', title: 'Splitview',
url: '#dockview', url: '/splitview/#splitview',
routes: [ },
{ title: 'Item1', url: '/item1' }, {
{ title: 'Item2', url: '/item2' }, title: 'Gridview',
], url: '/gridview/#gridview',
},
{
title: 'Dockview',
url: '/dockview/#dockview',
},
{
title: 'Paneview',
url: '/paneview/#paneview',
}, },
// {
// title: 'Gridview',
// url: '#gridview',
// routes: [
// { title: 'Item1', url: 'item1' },
// { title: 'Item2', url: 'item2' },
// ],
// },
// {
// title: 'Splitview',
// url: '#splitview',
// routes: [
// { title: 'Item1', url: 'item1' },
// { title: 'Item2', url: 'item2' },
// ],
// },
// {
// title: 'Paneview',
// url: '#paneivew',
// routes: [
// { title: 'Item1', url: 'item1' },
// { title: 'Item2', url: 'item2' },
// ],
// },
], ],
}, },
{ title: 'Guides', url: '#guides' }, { title: 'Guides', url: '#guides' },

View File

@ -41,3 +41,32 @@ a:hover {
background-size: 100%; background-size: 100%;
background-position: center center; background-position: center center;
} }
.markdown-body table {
border-collapse: collapse;
border-spacing: 0;
font-size: 12px;
}
.markdown-body td,
.markdown-body th {
padding: 0;
}
.markdown-body table tr {
background-color: rgb(255, 255, 255);
border-top: 1px solid rgb(198, 203, 209);
}
.markdown-body table th {
border:1px solid rgb(223, 226, 229);
padding: 6px 13px;
}
.markdown-body table td {
border:1px solid rgb(223, 226, 229);
padding: 6px 13px;
}
.markdown-body table tr:nth-child(2n) {
background-color: rgb(246, 248, 250);
}

View File

@ -15,7 +15,7 @@
"jsx": "preserve", "jsx": "preserve",
"incremental": true "incremental": true
}, },
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", "src/pages/index.msx", "src/pages/basic.stsx"], "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx"],
"exclude": ["node_modules"], "exclude": ["node_modules"],
"paths": { "paths": {
"react": ["node_modules/react"], "react": ["node_modules/react"],

View File

@ -121,8 +121,8 @@ export class SplitviewApi implements CommonApi<SerializedSplitview> {
return this.component.layout(width, height); return this.component.layout(width, height);
} }
addPanel(options: AddSplitviewComponentOptions): void { addPanel(options: AddSplitviewComponentOptions): ISplitviewPanel {
this.component.addPanel(options); return this.component.addPanel(options);
} }
resizeToFit(): void { resizeToFit(): void {
@ -216,8 +216,8 @@ export class PaneviewApi implements CommonApi<SerializedPaneview> {
this.component.layout(width, height); this.component.layout(width, height);
} }
addPanel(options: AddPaneviewComponentOptions): void { addPanel(options: AddPaneviewComponentOptions): IPaneviewPanel {
this.component.addPanel(options); return this.component.addPanel(options);
} }
resizeToFit(): void { resizeToFit(): void {
@ -300,8 +300,8 @@ export class GridviewApi implements CommonApi<SerializedGridview> {
this.component.layout(width, height, force); this.component.layout(width, height, force);
} }
addPanel(options: AddComponentOptions): void { addPanel(options: AddComponentOptions): IGridviewPanel {
this.component.addPanel(options); return this.component.addPanel(options);
} }
removePanel(panel: IGridviewPanel, sizing?: Sizing): void { removePanel(panel: IGridviewPanel, sizing?: Sizing): void {

View File

@ -15,26 +15,24 @@
height: 100%; height: 100%;
width: 100%; width: 100%;
background-color: var(--dv-drag-over-background-color); background-color: var(--dv-drag-over-background-color);
transition: top 70ms ease-out,left 70ms ease-out,width 70ms ease-out,height 70ms ease-out,opacity .15s ease-out;
transition-duration: 0.15s;
transition-timing-function: ease-out;
will-change: transform; will-change: transform;
pointer-events: none; pointer-events: none;
&.left { &.left {
transform: translateX(-25%) scaleX(50%) transform: translateX(-25%) scaleX(0.5)
} }
&.right { &.right {
transform: translateX(25%) scaleX(50%) transform: translateX(25%) scaleX(0.5)
} }
&.top { &.top {
transform: translateY(-25%) scaleY(50%); transform: translateY(-25%) scaleY(0.5);
} }
&.bottom { &.bottom {
transform: translateY(25%) scaleY(50%); transform: translateY(25%) scaleY(0.5);
} }
&.small-top { &.small-top {

View File

@ -54,7 +54,6 @@ export interface DockviewOptions extends DockviewRenderFunctions {
watermarkFrameworkComponent?: any; watermarkFrameworkComponent?: any;
frameworkComponentFactory?: GroupPanelFrameworkComponentFactory; frameworkComponentFactory?: GroupPanelFrameworkComponentFactory;
tabHeight?: number; tabHeight?: number;
debug?: boolean;
orientation?: Orientation; orientation?: Orientation;
styles?: ISplitviewStyles; styles?: ISplitviewStyles;
showDndOverlay?: (event: DragEvent, target: DockviewDropTargets) => boolean; showDndOverlay?: (event: DragEvent, target: DockviewDropTargets) => boolean;

View File

@ -44,7 +44,7 @@ export interface AddComponentOptions extends BaseComponentOptions {
maximumHeight?: number; maximumHeight?: number;
position?: { position?: {
direction: Direction; direction: Direction;
reference: string; referencePanel: string;
}; };
location?: number[]; location?: number[];
} }
@ -62,7 +62,7 @@ export interface IGridviewComponent extends IBaseGrid<GridviewPanel> {
readonly orientation: Orientation; readonly orientation: Orientation;
readonly onDidLayoutFromJSON: Event<void>; readonly onDidLayoutFromJSON: Event<void>;
updateOptions(options: Partial<GridviewComponentUpdateOptions>): void; updateOptions(options: Partial<GridviewComponentUpdateOptions>): void;
addPanel(options: AddComponentOptions): void; addPanel(options: AddComponentOptions): IGridviewPanel;
removePanel(panel: IGridviewPanel, sizing?: Sizing): void; removePanel(panel: IGridviewPanel, sizing?: Sizing): void;
toggleVisibility(panel: IGridviewPanel): void; toggleVisibility(panel: IGridviewPanel): void;
focus(): void; focus(): void;
@ -273,17 +273,17 @@ export class GridviewComponent
this.doAddGroup(removedPanel, relativeLocation, options.size); this.doAddGroup(removedPanel, relativeLocation, options.size);
} }
public addPanel(options: AddComponentOptions): void { public addPanel(options: AddComponentOptions): IGridviewPanel {
let relativeLocation: number[] = options.location || [0]; let relativeLocation: number[] = options.location || [0];
if (options.position?.reference) { if (options.position?.referencePanel) {
const referenceGroup = this._groups.get( const referenceGroup = this._groups.get(
options.position.reference options.position.referencePanel
)?.value; )?.value;
if (!referenceGroup) { if (!referenceGroup) {
throw new Error( throw new Error(
`reference group ${options.position.reference} does not exist` `reference group ${options.position.referencePanel} does not exist`
); );
} }
@ -329,6 +329,8 @@ export class GridviewComponent
this.registerPanel(view); this.registerPanel(view);
this.doAddGroup(view, relativeLocation, options.size); this.doAddGroup(view, relativeLocation, options.size);
return view;
} }
private registerPanel(panel: GridviewPanel) { private registerPanel(panel: GridviewPanel) {

View File

@ -36,11 +36,10 @@ export interface DockviewReadyEvent {
} }
export interface IDockviewReactProps { export interface IDockviewReactProps {
components?: PanelCollection<IDockviewPanelProps>; components: PanelCollection<IDockviewPanelProps>;
tabComponents?: PanelCollection<IDockviewPanelHeaderProps>; tabComponents?: PanelCollection<IDockviewPanelHeaderProps>;
watermarkComponent?: React.FunctionComponent<IWatermarkPanelProps>; watermarkComponent?: React.FunctionComponent<IWatermarkPanelProps>;
onReady?: (event: DockviewReadyEvent) => void; onReady: (event: DockviewReadyEvent) => void;
debug?: boolean;
tabHeight?: number; tabHeight?: number;
onTabContextMenu?: (event: TabContextMenuEvent) => void; onTabContextMenu?: (event: TabContextMenuEvent) => void;
onDidDrop?: (event: DockviewDropEvent) => void; onDidDrop?: (event: DockviewDropEvent) => void;
@ -127,7 +126,6 @@ export const DockviewReact = React.forwardRef(
frameworkComponents: props.components, frameworkComponents: props.components,
frameworkTabComponents: props.tabComponents, frameworkTabComponents: props.tabComponents,
tabHeight: props.tabHeight, tabHeight: props.tabHeight,
debug: props.debug,
watermarkFrameworkComponent: props.watermarkComponent, watermarkFrameworkComponent: props.watermarkComponent,
styles: props.hideBorders styles: props.hideBorders
? { separatorBorder: 'transparent' } ? { separatorBorder: 'transparent' }

View File

@ -22,8 +22,8 @@ export interface IGridviewPanelProps<T extends { [index: string]: any } = any>
} }
export interface IGridviewReactProps { export interface IGridviewReactProps {
orientation: Orientation; orientation?: Orientation;
onReady?: (event: GridviewReadyEvent) => void; onReady: (event: GridviewReadyEvent) => void;
components: PanelCollection<IGridviewPanelProps>; components: PanelCollection<IGridviewPanelProps>;
hideBorders?: boolean; hideBorders?: boolean;
className?: string; className?: string;
@ -64,7 +64,7 @@ export const GridviewReact = React.forwardRef(
typeof props.proportionalLayout === 'boolean' typeof props.proportionalLayout === 'boolean'
? props.proportionalLayout ? props.proportionalLayout
: true, : true,
orientation: props.orientation, orientation: props.orientation || Orientation.HORIZONTAL,
frameworkComponents: props.components, frameworkComponents: props.components,
frameworkComponentFactory: { frameworkComponentFactory: {
createComponent: (id: string, componentId, component) => { createComponent: (id: string, componentId, component) => {

View File

@ -27,8 +27,8 @@ export interface PaneviewDropEvent extends PaneviewDropEvent2 {
} }
export interface IPaneviewReactProps { export interface IPaneviewReactProps {
onReady?: (event: PaneviewReadyEvent) => void; onReady: (event: PaneviewReadyEvent) => void;
components?: PanelCollection<IPaneviewPanelProps>; components: PanelCollection<IPaneviewPanelProps>;
headerComponents?: PanelCollection<IPaneviewPanelProps>; headerComponents?: PanelCollection<IPaneviewPanelProps>;
className?: string; className?: string;
disableAutoResizing?: boolean; disableAutoResizing?: boolean;

View File

@ -22,8 +22,8 @@ export interface ISplitviewPanelProps<T extends { [index: string]: any } = any>
} }
export interface ISplitviewReactProps { export interface ISplitviewReactProps {
orientation: Orientation; orientation?: Orientation;
onReady?: (event: SplitviewReadyEvent) => void; onReady: (event: SplitviewReadyEvent) => void;
components: PanelCollection<ISplitviewPanelProps>; components: PanelCollection<ISplitviewPanelProps>;
proportionalLayout?: boolean; proportionalLayout?: boolean;
hideBorders?: boolean; hideBorders?: boolean;
@ -58,7 +58,7 @@ export const SplitviewReact = React.forwardRef(
React.useEffect(() => { React.useEffect(() => {
const splitview = new SplitviewComponent(domRef.current!, { const splitview = new SplitviewComponent(domRef.current!, {
orientation: props.orientation, orientation: props.orientation || Orientation.HORIZONTAL,
frameworkComponents: props.components, frameworkComponents: props.components,
frameworkWrapper: { frameworkWrapper: {
createComponent: ( createComponent: (

View File

@ -61,8 +61,9 @@ export interface ISplitviewComponent extends IDisposable {
readonly onDidAddView: Event<IView>; readonly onDidAddView: Event<IView>;
readonly onDidRemoveView: Event<IView>; readonly onDidRemoveView: Event<IView>;
readonly onDidLayoutFromJSON: Event<void>; readonly onDidLayoutFromJSON: Event<void>;
readonly panels: SplitviewPanel[];
updateOptions(options: Partial<SplitviewComponentUpdateOptions>): void; updateOptions(options: Partial<SplitviewComponentUpdateOptions>): void;
addPanel(options: AddSplitviewComponentOptions): void; addPanel(options: AddSplitviewComponentOptions): ISplitviewPanel;
layout(width: number, height: number): void; layout(width: number, height: number): void;
onDidLayoutChange: Event<void>; onDidLayoutChange: Event<void>;
toJSON(): SerializedSplitview; toJSON(): SerializedSplitview;
@ -72,7 +73,7 @@ export interface ISplitviewComponent extends IDisposable {
getPanel(id: string): ISplitviewPanel | undefined; getPanel(id: string): ISplitviewPanel | undefined;
setActive(view: ISplitviewPanel, skipFocus?: boolean): void; setActive(view: ISplitviewPanel, skipFocus?: boolean): void;
removePanel(panel: ISplitviewPanel, sizing?: Sizing): void; removePanel(panel: ISplitviewPanel, sizing?: Sizing): void;
getPanels(): SplitviewPanel[];
setVisible(panel: ISplitviewPanel, visible: boolean): void; setVisible(panel: ISplitviewPanel, visible: boolean): void;
movePanel(from: number, to: number): void; movePanel(from: number, to: number): void;
} }
@ -87,7 +88,7 @@ export class SplitviewComponent
private _disposable = new MutableDisposable(); private _disposable = new MutableDisposable();
private _splitview!: Splitview; private _splitview!: Splitview;
private _activePanel: SplitviewPanel | undefined; private _activePanel: SplitviewPanel | undefined;
private panels = new Map<string, IValueDisposable<SplitviewPanel>>(); private _panels = new Map<string, IValueDisposable<SplitviewPanel>>();
private _options: SplitviewComponentOptions; private _options: SplitviewComponentOptions;
private readonly _onDidLayoutfromJSON = new Emitter<void>(); private readonly _onDidLayoutfromJSON = new Emitter<void>();
@ -102,15 +103,23 @@ export class SplitviewComponent
private readonly _onDidLayoutChange = new Emitter<void>(); private readonly _onDidLayoutChange = new Emitter<void>();
readonly onDidLayoutChange: Event<void> = this._onDidLayoutChange.event; readonly onDidLayoutChange: Event<void> = this._onDidLayoutChange.event;
get options() { get options(): SplitviewComponentOptions {
return this._options; return this._options;
} }
get orientation() { get panels(): SplitviewPanel[] {
return this.splitview.getViews();
}
get length(): number {
return this._panels.size;
}
get orientation(): Orientation {
return this.splitview.orientation; return this.splitview.orientation;
} }
get splitview() { get splitview(): Splitview {
return this._splitview; return this._splitview;
} }
@ -128,30 +137,26 @@ export class SplitviewComponent
); );
} }
get minimumSize() { get minimumSize(): number {
return this.splitview.minimumSize; return this.splitview.minimumSize;
} }
get maximumSize() { get maximumSize(): number {
return this.splitview.maximumSize; return this.splitview.maximumSize;
} }
get height() { get height(): number {
return this.splitview.orientation === Orientation.HORIZONTAL return this.splitview.orientation === Orientation.HORIZONTAL
? this.splitview.orthogonalSize ? this.splitview.orthogonalSize
: this.splitview.size; : this.splitview.size;
} }
get width() { get width(): number {
return this.splitview.orientation === Orientation.HORIZONTAL return this.splitview.orientation === Orientation.HORIZONTAL
? this.splitview.size ? this.splitview.size
: this.splitview.orthogonalSize; : this.splitview.orthogonalSize;
} }
get length() {
return this.panels.size;
}
constructor( constructor(
private readonly element: HTMLElement, private readonly element: HTMLElement,
options: SplitviewComponentOptions options: SplitviewComponentOptions
@ -195,23 +200,23 @@ export class SplitviewComponent
); );
} }
focus() { focus(): void {
this._activePanel?.focus(); this._activePanel?.focus();
} }
movePanel(from: number, to: number) { movePanel(from: number, to: number): void {
this.splitview.moveView(from, to); this.splitview.moveView(from, to);
} }
setVisible(panel: SplitviewPanel, visible: boolean) { setVisible(panel: SplitviewPanel, visible: boolean): void {
const index = this.getPanels().indexOf(panel); const index = this.panels.indexOf(panel);
this.splitview.setViewVisible(index, visible); this.splitview.setViewVisible(index, visible);
} }
setActive(view: SplitviewPanel, skipFocus?: boolean) { setActive(view: SplitviewPanel, skipFocus?: boolean): void {
this._activePanel = view; this._activePanel = view;
this.getPanels() this.panels
.filter((v) => v !== view) .filter((v) => v !== view)
.forEach((v) => { .forEach((v) => {
v.api._onDidActiveChange.fire({ isActive: false }); v.api._onDidActiveChange.fire({ isActive: false });
@ -225,12 +230,8 @@ export class SplitviewComponent
} }
} }
getPanels(): SplitviewPanel[] { removePanel(panel: SplitviewPanel, sizing?: Sizing): void {
return this.splitview.getViews(); const disposable = this._panels.get(panel.id);
}
removePanel(panel: SplitviewPanel, sizing?: Sizing) {
const disposable = this.panels.get(panel.id);
if (!disposable) { if (!disposable) {
throw new Error(`unknown splitview panel ${panel.id}`); throw new Error(`unknown splitview panel ${panel.id}`);
@ -239,23 +240,23 @@ export class SplitviewComponent
disposable.disposable.dispose(); disposable.disposable.dispose();
disposable.value.dispose(); disposable.value.dispose();
this.panels.delete(panel.id); this._panels.delete(panel.id);
const index = this.getPanels().findIndex((_) => _ === panel); const index = this.panels.findIndex((_) => _ === panel);
this.splitview.removeView(index, sizing); this.splitview.removeView(index, sizing);
const panels = this.getPanels(); const panels = this.panels;
if (panels.length > 0) { if (panels.length > 0) {
this.setActive(panels[panels.length - 1]); this.setActive(panels[panels.length - 1]);
} }
} }
getPanel(id: string): SplitviewPanel | undefined { getPanel(id: string): SplitviewPanel | undefined {
return this.getPanels().find((view) => view.id === id); return this.panels.find((view) => view.id === id);
} }
addPanel(options: AddSplitviewComponentOptions): void { addPanel(options: AddSplitviewComponentOptions): ISplitviewPanel {
if (this.panels.has(options.id)) { if (this._panels.has(options.id)) {
throw new Error(`panel ${options.id} already exists`); throw new Error(`panel ${options.id} already exists`);
} }
@ -292,6 +293,8 @@ export class SplitviewComponent
this.doAddView(view); this.doAddView(view);
this.setActive(view); this.setActive(view);
return view;
} }
/** /**
@ -314,7 +317,7 @@ export class SplitviewComponent
this.splitview.layout(size, orthogonalSize); this.splitview.layout(size, orthogonalSize);
} }
private doAddView(view: SplitviewPanel) { private doAddView(view: SplitviewPanel): void {
const disposable = view.api.onDidFocusChange((event) => { const disposable = view.api.onDidFocusChange((event) => {
if (!event.isFocused) { if (!event.isFocused) {
return; return;
@ -322,7 +325,7 @@ export class SplitviewComponent
this.setActive(view, true); this.setActive(view, true);
}); });
this.panels.set(view.id, { disposable, value: view }); this._panels.set(view.id, { disposable, value: view });
} }
toJSON(): SerializedSplitview { toJSON(): SerializedSplitview {
@ -349,11 +352,11 @@ export class SplitviewComponent
fromJSON(serializedSplitview: SerializedSplitview): void { fromJSON(serializedSplitview: SerializedSplitview): void {
const { views, orientation, size, activeView } = serializedSplitview; const { views, orientation, size, activeView } = serializedSplitview;
for (const [_, value] of this.panels.entries()) { for (const [_, value] of this._panels.entries()) {
value.disposable.dispose(); value.disposable.dispose();
value.value.dispose(); value.value.dispose();
} }
this.panels.clear(); this._panels.clear();
this.splitview.dispose(); this.splitview.dispose();
const queue: Function[] = []; const queue: Function[] = [];
@ -366,7 +369,7 @@ export class SplitviewComponent
views: views.map((view) => { views: views.map((view) => {
const data = view.data; const data = view.data;
if (this.panels.has(data.id)) { if (this._panels.has(data.id)) {
throw new Error(`panel ${data.id} already exists`); throw new Error(`panel ${data.id} already exists`);
} }
@ -422,12 +425,12 @@ export class SplitviewComponent
this._onDidLayoutfromJSON.fire(); this._onDidLayoutfromJSON.fire();
} }
dispose() { dispose(): void {
for (const [_, value] of this.panels.entries()) { for (const [_, value] of this._panels.entries()) {
value.disposable.dispose(); value.disposable.dispose();
value.value.dispose(); value.value.dispose();
} }
this.panels.clear(); this._panels.clear();
this.splitview.dispose(); this.splitview.dispose();

17793
yarn.lock Normal file

File diff suppressed because it is too large Load Diff