mirror of
https://github.com/mathuo/dockview
synced 2025-03-10 07:52:07 +00:00
parent
cc50199cff
commit
e85863b65f
@ -43,23 +43,23 @@ describe('tabsContainer', () => {
|
|||||||
|
|
||||||
const emptySpace = cut.element
|
const emptySpace = cut.element
|
||||||
.getElementsByClassName('void-container')
|
.getElementsByClassName('void-container')
|
||||||
.item(0);
|
.item(0)
|
||||||
|
|
||||||
if (!emptySpace) {
|
if (!emptySpace!) {
|
||||||
fail('element not found');
|
fail('element not found');
|
||||||
}
|
}
|
||||||
|
|
||||||
jest.spyOn(emptySpace, 'clientHeight', 'get').mockImplementation(
|
jest.spyOn(emptySpace!, 'clientHeight', 'get').mockImplementation(
|
||||||
() => 100
|
() => 100
|
||||||
);
|
);
|
||||||
jest.spyOn(emptySpace, 'clientWidth', 'get').mockImplementation(
|
jest.spyOn(emptySpace!, 'clientWidth', 'get').mockImplementation(
|
||||||
() => 100
|
() => 100
|
||||||
);
|
);
|
||||||
|
|
||||||
fireEvent.dragEnter(emptySpace);
|
fireEvent.dragEnter(emptySpace!);
|
||||||
fireEvent.dragOver(emptySpace);
|
fireEvent.dragOver(emptySpace!);
|
||||||
|
|
||||||
expect(groupView.canDisplayOverlay).toBeCalled();
|
expect(groupView.canDisplayOverlay).toHaveBeenCalled();
|
||||||
|
|
||||||
expect(
|
expect(
|
||||||
cut.element.getElementsByClassName('drop-target-dropzone').length
|
cut.element.getElementsByClassName('drop-target-dropzone').length
|
||||||
@ -102,14 +102,14 @@ describe('tabsContainer', () => {
|
|||||||
.getElementsByClassName('void-container')
|
.getElementsByClassName('void-container')
|
||||||
.item(0);
|
.item(0);
|
||||||
|
|
||||||
if (!emptySpace) {
|
if (!emptySpace!) {
|
||||||
fail('element not found');
|
fail('element not found');
|
||||||
}
|
}
|
||||||
|
|
||||||
jest.spyOn(emptySpace, 'clientHeight', 'get').mockImplementation(
|
jest.spyOn(emptySpace!, 'clientHeight', 'get').mockImplementation(
|
||||||
() => 100
|
() => 100
|
||||||
);
|
);
|
||||||
jest.spyOn(emptySpace, 'clientWidth', 'get').mockImplementation(
|
jest.spyOn(emptySpace!, 'clientWidth', 'get').mockImplementation(
|
||||||
() => 100
|
() => 100
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -124,10 +124,10 @@ describe('tabsContainer', () => {
|
|||||||
PanelTransfer.prototype
|
PanelTransfer.prototype
|
||||||
);
|
);
|
||||||
|
|
||||||
fireEvent.dragEnter(emptySpace);
|
fireEvent.dragEnter(emptySpace!);
|
||||||
fireEvent.dragOver(emptySpace);
|
fireEvent.dragOver(emptySpace!);
|
||||||
|
|
||||||
expect(groupView.canDisplayOverlay).toBeCalledTimes(0);
|
expect(groupView.canDisplayOverlay).toHaveBeenCalledTimes(0);
|
||||||
|
|
||||||
expect(
|
expect(
|
||||||
cut.element.getElementsByClassName('drop-target-dropzone').length
|
cut.element.getElementsByClassName('drop-target-dropzone').length
|
||||||
@ -173,14 +173,14 @@ describe('tabsContainer', () => {
|
|||||||
.getElementsByClassName('void-container')
|
.getElementsByClassName('void-container')
|
||||||
.item(0);
|
.item(0);
|
||||||
|
|
||||||
if (!emptySpace) {
|
if (!emptySpace!) {
|
||||||
fail('element not found');
|
fail('element not found');
|
||||||
}
|
}
|
||||||
|
|
||||||
jest.spyOn(emptySpace, 'clientHeight', 'get').mockImplementation(
|
jest.spyOn(emptySpace!, 'clientHeight', 'get').mockImplementation(
|
||||||
() => 100
|
() => 100
|
||||||
);
|
);
|
||||||
jest.spyOn(emptySpace, 'clientWidth', 'get').mockImplementation(
|
jest.spyOn(emptySpace!, 'clientWidth', 'get').mockImplementation(
|
||||||
() => 100
|
() => 100
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -189,10 +189,10 @@ describe('tabsContainer', () => {
|
|||||||
PanelTransfer.prototype
|
PanelTransfer.prototype
|
||||||
);
|
);
|
||||||
|
|
||||||
fireEvent.dragEnter(emptySpace);
|
fireEvent.dragEnter(emptySpace!);
|
||||||
fireEvent.dragOver(emptySpace);
|
fireEvent.dragOver(emptySpace!);
|
||||||
|
|
||||||
expect(groupView.canDisplayOverlay).toBeCalledTimes(0);
|
expect(groupView.canDisplayOverlay).toHaveBeenCalledTimes(0);
|
||||||
|
|
||||||
expect(
|
expect(
|
||||||
cut.element.getElementsByClassName('drop-target-dropzone').length
|
cut.element.getElementsByClassName('drop-target-dropzone').length
|
||||||
@ -238,14 +238,14 @@ describe('tabsContainer', () => {
|
|||||||
.getElementsByClassName('void-container')
|
.getElementsByClassName('void-container')
|
||||||
.item(0);
|
.item(0);
|
||||||
|
|
||||||
if (!emptySpace) {
|
if (!emptySpace!) {
|
||||||
fail('element not found');
|
fail('element not found');
|
||||||
}
|
}
|
||||||
|
|
||||||
jest.spyOn(emptySpace, 'clientHeight', 'get').mockImplementation(
|
jest.spyOn(emptySpace!, 'clientHeight', 'get').mockImplementation(
|
||||||
() => 100
|
() => 100
|
||||||
);
|
);
|
||||||
jest.spyOn(emptySpace, 'clientWidth', 'get').mockImplementation(
|
jest.spyOn(emptySpace!, 'clientWidth', 'get').mockImplementation(
|
||||||
() => 100
|
() => 100
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -254,10 +254,10 @@ describe('tabsContainer', () => {
|
|||||||
PanelTransfer.prototype
|
PanelTransfer.prototype
|
||||||
);
|
);
|
||||||
|
|
||||||
fireEvent.dragEnter(emptySpace);
|
fireEvent.dragEnter(emptySpace!);
|
||||||
fireEvent.dragOver(emptySpace);
|
fireEvent.dragOver(emptySpace!);
|
||||||
|
|
||||||
expect(groupView.canDisplayOverlay).toBeCalledTimes(0);
|
expect(groupView.canDisplayOverlay).toHaveBeenCalledTimes(0);
|
||||||
|
|
||||||
expect(
|
expect(
|
||||||
cut.element.getElementsByClassName('drop-target-dropzone').length
|
cut.element.getElementsByClassName('drop-target-dropzone').length
|
||||||
@ -302,14 +302,14 @@ describe('tabsContainer', () => {
|
|||||||
.getElementsByClassName('void-container')
|
.getElementsByClassName('void-container')
|
||||||
.item(0);
|
.item(0);
|
||||||
|
|
||||||
if (!emptySpace) {
|
if (!emptySpace!) {
|
||||||
fail('element not found');
|
fail('element not found');
|
||||||
}
|
}
|
||||||
|
|
||||||
jest.spyOn(emptySpace, 'clientHeight', 'get').mockImplementation(
|
jest.spyOn(emptySpace!, 'clientHeight', 'get').mockImplementation(
|
||||||
() => 100
|
() => 100
|
||||||
);
|
);
|
||||||
jest.spyOn(emptySpace, 'clientWidth', 'get').mockImplementation(
|
jest.spyOn(emptySpace!, 'clientWidth', 'get').mockImplementation(
|
||||||
() => 100
|
() => 100
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -324,10 +324,10 @@ describe('tabsContainer', () => {
|
|||||||
PanelTransfer.prototype
|
PanelTransfer.prototype
|
||||||
);
|
);
|
||||||
|
|
||||||
fireEvent.dragEnter(emptySpace);
|
fireEvent.dragEnter(emptySpace!);
|
||||||
fireEvent.dragOver(emptySpace);
|
fireEvent.dragOver(emptySpace!);
|
||||||
|
|
||||||
expect(groupView.canDisplayOverlay).toBeCalledTimes(1);
|
expect(groupView.canDisplayOverlay).toHaveBeenCalledTimes(1);
|
||||||
|
|
||||||
expect(
|
expect(
|
||||||
cut.element.getElementsByClassName('drop-target-dropzone').length
|
cut.element.getElementsByClassName('drop-target-dropzone').length
|
||||||
@ -507,7 +507,7 @@ describe('tabsContainer', () => {
|
|||||||
const eventPreventDefaultSpy = jest.spyOn(event, 'preventDefault');
|
const eventPreventDefaultSpy = jest.spyOn(event, 'preventDefault');
|
||||||
fireEvent(container, event);
|
fireEvent(container, event);
|
||||||
|
|
||||||
expect(accessor.addFloatingGroup).toBeCalledWith(
|
expect(accessor.addFloatingGroup).toHaveBeenCalledWith(
|
||||||
groupPanel,
|
groupPanel,
|
||||||
{
|
{
|
||||||
x: 100,
|
x: 100,
|
||||||
@ -567,15 +567,15 @@ describe('tabsContainer', () => {
|
|||||||
const eventPreventDefaultSpy = jest.spyOn(event, 'preventDefault');
|
const eventPreventDefaultSpy = jest.spyOn(event, 'preventDefault');
|
||||||
fireEvent(container, event);
|
fireEvent(container, event);
|
||||||
|
|
||||||
expect(accessor.addFloatingGroup).toBeCalledTimes(0);
|
expect(accessor.addFloatingGroup).toHaveBeenCalledTimes(0);
|
||||||
expect(eventPreventDefaultSpy).toBeCalledTimes(0);
|
expect(eventPreventDefaultSpy).toHaveBeenCalledTimes(0);
|
||||||
|
|
||||||
const event2 = new KeyboardEvent('mousedown', { shiftKey: false });
|
const event2 = new KeyboardEvent('mousedown', { shiftKey: false });
|
||||||
const eventPreventDefaultSpy2 = jest.spyOn(event2, 'preventDefault');
|
const eventPreventDefaultSpy2 = jest.spyOn(event2, 'preventDefault');
|
||||||
fireEvent(container, event2);
|
fireEvent(container, event2);
|
||||||
|
|
||||||
expect(accessor.addFloatingGroup).toBeCalledTimes(0);
|
expect(accessor.addFloatingGroup).toHaveBeenCalledTimes(0);
|
||||||
expect(eventPreventDefaultSpy2).toBeCalledTimes(0);
|
expect(eventPreventDefaultSpy2).toHaveBeenCalledTimes(0);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('that selecting a tab with shift down will move that tab into a new floating group', () => {
|
test('that selecting a tab with shift down will move that tab into a new floating group', () => {
|
||||||
|
@ -170,10 +170,10 @@ type AddPanelPositionUnion = {
|
|||||||
|
|
||||||
type AddPanelOptionsUnion = AddPanelFloatingGroupUnion | AddPanelPositionUnion;
|
type AddPanelOptionsUnion = AddPanelFloatingGroupUnion | AddPanelPositionUnion;
|
||||||
|
|
||||||
export type AddPanelOptions<P extends object = Parameters> = Omit<
|
export type AddPanelOptions<P extends object = Parameters> = {
|
||||||
PanelOptions<P>,
|
params?: P;
|
||||||
'component' | 'tabComponent'
|
id: string;
|
||||||
> & {
|
title?: string;
|
||||||
component: string;
|
component: string;
|
||||||
tabComponent?: string;
|
tabComponent?: string;
|
||||||
renderer?: DockviewPanelRenderer;
|
renderer?: DockviewPanelRenderer;
|
||||||
|
41
packages/docs/blog/2024-02-28-dockview-1.10.0.md
Normal file
41
packages/docs/blog/2024-02-28-dockview-1.10.0.md
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
---
|
||||||
|
slug: dockview-1.10.0-release
|
||||||
|
title: Dockview 1.10.0
|
||||||
|
tags: [release]
|
||||||
|
---
|
||||||
|
|
||||||
|
# Release Notes
|
||||||
|
|
||||||
|
Please reference to docs @ [dockview.dev](https://dockview.dev).
|
||||||
|
|
||||||
|
## 🚀 Features
|
||||||
|
|
||||||
|
- New Documentation Website [#475](https://github.com/mathuo/dockview/issues/475)
|
||||||
|
- Documentation website improved to cater for growing libary
|
||||||
|
- Panel Gaps [#447](https://github.com/mathuo/dockview/issues/447)
|
||||||
|
- CSS Variable `--dv-group-gap-size` exposed.
|
||||||
|
- Locked Dock [#460](https://github.com/mathuo/dockview/issues/460)
|
||||||
|
- `locked` option prevents all user resizing of dock.
|
||||||
|
- Enhance Window Popout [#469](https://github.com/mathuo/dockview/issues/469)
|
||||||
|
- Numerous improved to Window popouts including replacement of window to original location
|
||||||
|
when popout is closed.
|
||||||
|
- Enhance Events [#479](https://github.com/mathuo/dockview/issues/479)
|
||||||
|
- Drag and Drop Events [#395](https://github.com/mathuo/dockview/issues/395)
|
||||||
|
|
||||||
|
## 🛠 Miscs
|
||||||
|
|
||||||
|
- Bug: Drop Target Scaling [#448](https://github.com/mathuo/dockview/issues/448)
|
||||||
|
- Drop target overlays are no longer scaled with `transform` which allows for better CSS customization.
|
||||||
|
- Bug: Popout `always` rendeing mode [#486](https://github.com/mathuo/dockview/issues/486)
|
||||||
|
- `always` render mode now works in Popout Windows too.
|
||||||
|
- Bug: React Component Support [#498](https://github.com/mathuo/dockview/issues/498)
|
||||||
|
- Support components wrapped with `React.memo(...)` passed in `components` option.
|
||||||
|
- Bug: Remove Source Maps [#509](https://github.com/mathuo/dockview/issues/509)
|
||||||
|
- Source maps do not currently work. They have been removed and will be re-evaluated for a later release.
|
||||||
|
|
||||||
|
## 🔥 Breaking changes
|
||||||
|
|
||||||
|
- Bug: Typo [#495](https://github.com/mathuo/dockview/issues/495)
|
||||||
|
- Rename `onDidMaxmizedNodeChange` to `onDidMaximizedNodeChange`
|
||||||
|
- Rename `exitMaxmizedGroup` to `exitMaximizedGroup`
|
||||||
|
- Rename `onDidMaxmizedGroupChange` to `onDidMaximizedGroupChange`
|
5
packages/docs/docs/advanced/_category_.json
Normal file
5
packages/docs/docs/advanced/_category_.json
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
{
|
||||||
|
"label": "Advanced",
|
||||||
|
"collapsible": false,
|
||||||
|
"collapsed": false
|
||||||
|
}
|
8
packages/docs/docs/advanced/advanced.mdx
Normal file
8
packages/docs/docs/advanced/advanced.mdx
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
import { MultiFrameworkContainer } from '@site/src/components/ui/container';
|
||||||
|
import DockviewNative2 from '@site/sandboxes/nativeapp-dockview/src/app';
|
||||||
|
|
||||||
|
# Window-like mananger with tabs
|
||||||
|
|
||||||
|
<MultiFrameworkContainer sandboxId="nativeapp-dockview" react={DockviewNative2} />
|
||||||
|
|
||||||
|
|
12
packages/docs/docs/advanced/events.mdx
Normal file
12
packages/docs/docs/advanced/events.mdx
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
import { MultiFrameworkContainer } from '@site/src/components/ui/container';
|
||||||
|
import EventsDockview from '@site/sandboxes/events-dockview/src/app';
|
||||||
|
|
||||||
|
# Events
|
||||||
|
|
||||||
|
A simple example showing events fired by `dockviewz that can be interacted with.
|
||||||
|
|
||||||
|
<MultiFrameworkContainer
|
||||||
|
height={600}
|
||||||
|
sandboxId="events-dockview"
|
||||||
|
react={EventsDockview}
|
||||||
|
/>
|
30
packages/docs/docs/advanced/iframe.mdx
Normal file
30
packages/docs/docs/advanced/iframe.mdx
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
import { MultiFrameworkContainer } from '@site/src/components/ui/container';
|
||||||
|
import DockviewWithIFrames from '@site/sandboxes/iframe-dockview/src/app';
|
||||||
|
|
||||||
|
# iframes
|
||||||
|
|
||||||
|
iframes reload when repositioned within the DOM which can cause issues.
|
||||||
|
|
||||||
|
iFrames required special attention because of a particular behaviour in how iFrames render:
|
||||||
|
|
||||||
|
> Re-parenting an iFrame will reload the contents of the iFrame or the rephrase this, moving an iFrame within the DOM will cause a reload of its contents.
|
||||||
|
|
||||||
|
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).
|
||||||
|
|
||||||
|
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`.
|
||||||
|
|
||||||
|
> See the [Panel Rendering](/core/panels/rendering.mdx) section for more information of render modes.
|
||||||
|
|
||||||
|
```tsx title="Example of a panel using an alternative renderer"
|
||||||
|
api.addPanel({
|
||||||
|
id: 'my_panel_id',
|
||||||
|
component: 'my_component',
|
||||||
|
renderer: 'always',
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
<MultiFrameworkContainer
|
||||||
|
sandboxId="iframe-dockview"
|
||||||
|
height={600}
|
||||||
|
react={DockviewWithIFrames}
|
||||||
|
/>
|
16
packages/docs/docs/advanced/keyboard.mdx
Normal file
16
packages/docs/docs/advanced/keyboard.mdx
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
---
|
||||||
|
title: Keyboard
|
||||||
|
---
|
||||||
|
|
||||||
|
import { MultiFrameworkContainer } from '@site/src/components/ui/container';
|
||||||
|
import DockviewKeyboard from '@site/sandboxes/keyboard-dockview/src/app';
|
||||||
|
|
||||||
|
# Keyboard Navigation
|
||||||
|
|
||||||
|
Keyboard shortcuts
|
||||||
|
|
||||||
|
<MultiFrameworkContainer
|
||||||
|
height={600}
|
||||||
|
sandboxId="keyboard-dockview"
|
||||||
|
react={DockviewKeyboard}
|
||||||
|
/>
|
14
packages/docs/docs/advanced/nested.mdx
Normal file
14
packages/docs/docs/advanced/nested.mdx
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
---
|
||||||
|
title: Nested Instances
|
||||||
|
---
|
||||||
|
|
||||||
|
|
||||||
|
import { MultiFrameworkContainer } from '@site/src/components/ui/container';
|
||||||
|
import NestedDockview from '@site/sandboxes/nested-dockview/src/app';
|
||||||
|
|
||||||
|
# Nested 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`.
|
||||||
|
|
||||||
|
<MultiFrameworkContainer sandboxId="nested-dockview" react={NestedDockview} />
|
14
packages/docs/docs/api/dockview/groupApi.mdx
Normal file
14
packages/docs/docs/api/dockview/groupApi.mdx
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
---
|
||||||
|
title: Group API
|
||||||
|
sidebar_position: 3
|
||||||
|
---
|
||||||
|
|
||||||
|
:::info
|
||||||
|
Use the group API sparingly. As you move panels, groups change and if you don't track this correctly you may encounter unexpected
|
||||||
|
behaviours. You should be able to achieve most things directly through the panel API.
|
||||||
|
:::
|
||||||
|
|
||||||
|
import { DocRef } from '@site/src/components/ui/reference/docRef';
|
||||||
|
|
||||||
|
|
||||||
|
<DocRef declaration="DockviewGroupPanelApi" />
|
18
packages/docs/docs/api/dockview/options.mdx
Normal file
18
packages/docs/docs/api/dockview/options.mdx
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
---
|
||||||
|
title: Options
|
||||||
|
sidebar_position: 0
|
||||||
|
---
|
||||||
|
|
||||||
|
import { DocRef } from '@site/src/components/ui/reference/docRef';
|
||||||
|
|
||||||
|
|
||||||
|
<FrameworkSpecific framework="JavaScript">
|
||||||
|
<DocRef declaration="DockviewComponentOptions" />
|
||||||
|
</FrameworkSpecific>
|
||||||
|
|
||||||
|
<FrameworkSpecific framework="React">
|
||||||
|
<DocRef declaration="IDockviewReactProps" />
|
||||||
|
</FrameworkSpecific>
|
||||||
|
|
||||||
|
|
||||||
|
|
10
packages/docs/docs/api/dockview/overview.mdx
Normal file
10
packages/docs/docs/api/dockview/overview.mdx
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
---
|
||||||
|
title: API
|
||||||
|
sidebar_position: 1
|
||||||
|
---
|
||||||
|
|
||||||
|
import { DocRef } from '@site/src/components/ui/reference/docRef';
|
||||||
|
|
||||||
|
This section describes the api object.
|
||||||
|
|
||||||
|
<DocRef declaration="DockviewApi" />
|
10
packages/docs/docs/api/dockview/panelApi.mdx
Normal file
10
packages/docs/docs/api/dockview/panelApi.mdx
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
---
|
||||||
|
description: API
|
||||||
|
title: Panel API
|
||||||
|
sidebar_position: 2
|
||||||
|
---
|
||||||
|
|
||||||
|
import { DocRef } from '@site/src/components/ui/reference/docRef';
|
||||||
|
|
||||||
|
|
||||||
|
<DocRef declaration="DockviewPanelApi" />
|
9
packages/docs/docs/api/gridview/api.mdx
Normal file
9
packages/docs/docs/api/gridview/api.mdx
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
---
|
||||||
|
description: API
|
||||||
|
title: "API"
|
||||||
|
sidebar_position: 1
|
||||||
|
---
|
||||||
|
|
||||||
|
import { DocRef } from '@site/src/components/ui/reference/docRef';
|
||||||
|
|
||||||
|
<DocRef declaration="GridviewApi" />
|
18
packages/docs/docs/api/gridview/options.mdx
Normal file
18
packages/docs/docs/api/gridview/options.mdx
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
---
|
||||||
|
title: Options
|
||||||
|
sidebar_position: 0
|
||||||
|
---
|
||||||
|
|
||||||
|
import { DocRef } from '@site/src/components/ui/reference/docRef';
|
||||||
|
|
||||||
|
|
||||||
|
<FrameworkSpecific framework="JavaScript">
|
||||||
|
<DocRef declaration="GridviewComponentOptions" />
|
||||||
|
</FrameworkSpecific>
|
||||||
|
|
||||||
|
<FrameworkSpecific framework="React">
|
||||||
|
<DocRef declaration="IGridviewReactProps" />
|
||||||
|
</FrameworkSpecific>
|
||||||
|
|
||||||
|
|
||||||
|
|
10
packages/docs/docs/api/gridview/panelApi.mdx
Normal file
10
packages/docs/docs/api/gridview/panelApi.mdx
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
---
|
||||||
|
description: API
|
||||||
|
title: Panel API
|
||||||
|
sidebar_position: 2
|
||||||
|
---
|
||||||
|
|
||||||
|
import { DocRef } from '@site/src/components/ui/reference/docRef';
|
||||||
|
|
||||||
|
|
||||||
|
<DocRef declaration="GridviewPanelApi" />
|
9
packages/docs/docs/api/paneview/api.mdx
Normal file
9
packages/docs/docs/api/paneview/api.mdx
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
---
|
||||||
|
description: API
|
||||||
|
title: "API"
|
||||||
|
sidebar_position: 1
|
||||||
|
---
|
||||||
|
|
||||||
|
import { DocRef } from '@site/src/components/ui/reference/docRef';
|
||||||
|
|
||||||
|
<DocRef declaration="PaneviewApi" />
|
18
packages/docs/docs/api/paneview/options.mdx
Normal file
18
packages/docs/docs/api/paneview/options.mdx
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
---
|
||||||
|
title: Options
|
||||||
|
sidebar_position: 0
|
||||||
|
---
|
||||||
|
|
||||||
|
import { DocRef } from '@site/src/components/ui/reference/docRef';
|
||||||
|
|
||||||
|
|
||||||
|
<FrameworkSpecific framework="JavaScript">
|
||||||
|
<DocRef declaration="PaneviewComponentOptions" />
|
||||||
|
</FrameworkSpecific>
|
||||||
|
|
||||||
|
<FrameworkSpecific framework="React">
|
||||||
|
<DocRef declaration="IPaneviewReactProps" />
|
||||||
|
</FrameworkSpecific>
|
||||||
|
|
||||||
|
|
||||||
|
|
10
packages/docs/docs/api/paneview/panelApi.mdx
Normal file
10
packages/docs/docs/api/paneview/panelApi.mdx
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
---
|
||||||
|
description: API
|
||||||
|
title: Panel API
|
||||||
|
sidebar_position: 2
|
||||||
|
---
|
||||||
|
|
||||||
|
import { DocRef } from '@site/src/components/ui/reference/docRef';
|
||||||
|
|
||||||
|
|
||||||
|
<DocRef declaration="PaneviewPanelApi" />
|
9
packages/docs/docs/api/splitview/api.mdx
Normal file
9
packages/docs/docs/api/splitview/api.mdx
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
---
|
||||||
|
description: API
|
||||||
|
title: "API"
|
||||||
|
sidebar_position: 1
|
||||||
|
---
|
||||||
|
|
||||||
|
import { DocRef } from '@site/src/components/ui/reference/docRef';
|
||||||
|
|
||||||
|
<DocRef declaration="SplitviewApi" />
|
18
packages/docs/docs/api/splitview/options.mdx
Normal file
18
packages/docs/docs/api/splitview/options.mdx
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
---
|
||||||
|
title: Options
|
||||||
|
sidebar_position: 0
|
||||||
|
---
|
||||||
|
|
||||||
|
import { DocRef } from '@site/src/components/ui/reference/docRef';
|
||||||
|
|
||||||
|
|
||||||
|
<FrameworkSpecific framework="JavaScript">
|
||||||
|
<DocRef declaration="SplitviewComponentOptions" />
|
||||||
|
</FrameworkSpecific>
|
||||||
|
|
||||||
|
<FrameworkSpecific framework="React">
|
||||||
|
<DocRef declaration="ISplitviewReactProps" />
|
||||||
|
</FrameworkSpecific>
|
||||||
|
|
||||||
|
|
||||||
|
|
10
packages/docs/docs/api/splitview/panelApi.mdx
Normal file
10
packages/docs/docs/api/splitview/panelApi.mdx
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
---
|
||||||
|
description: API
|
||||||
|
title: Panel API
|
||||||
|
sidebar_position: 2
|
||||||
|
---
|
||||||
|
|
||||||
|
import { DocRef } from '@site/src/components/ui/reference/docRef';
|
||||||
|
|
||||||
|
|
||||||
|
<DocRef declaration="SplitviewPanelApi" />
|
@ -1,10 +1,6 @@
|
|||||||
{
|
{
|
||||||
"label": "Components",
|
"position": 5,
|
||||||
|
"label": "Tabs",
|
||||||
"collapsible": true,
|
"collapsible": true,
|
||||||
"collapsed": false,
|
"collapsed": false
|
||||||
"position": 2,
|
|
||||||
"link": {
|
|
||||||
"type": "generated-index",
|
|
||||||
"title": "Components"
|
|
||||||
}
|
|
||||||
}
|
}
|
@ -7,15 +7,15 @@ import { 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';
|
||||||
|
|
||||||
import DockviewPersistence from '@site/sandboxes/layout-dockview/src/app';
|
// import DockviewPersistence from '@site/sandboxes/layout-dockview/src/app';
|
||||||
import SimpleDockview from '@site/sandboxes/simple-dockview/src/app';
|
import SimpleDockview from '@site/sandboxes/simple-dockview/src/app';
|
||||||
import ResizeDockview from '@site/sandboxes/resize-dockview/src/app';
|
import ResizeDockview from '@site/sandboxes/resize-dockview/src/app';
|
||||||
import DockviewWatermark from '@site/sandboxes/watermark-dockview/src/app';
|
// import DockviewWatermark from '@site/sandboxes/watermark-dockview/src/app';
|
||||||
import DockviewConstraints from '@site/sandboxes/constraints-dockview/src/app';
|
// import DockviewConstraints from '@site/sandboxes/constraints-dockview/src/app';
|
||||||
import DndDockview from '@site/sandboxes/dnd-dockview/src/app';
|
import DndDockview from '@site/sandboxes/dnd-dockview/src/app';
|
||||||
import NestedDockview from '@site/sandboxes/nested-dockview/src/app';
|
import NestedDockview from '@site/sandboxes/nested-dockview/src/app';
|
||||||
import EventsDockview from '@site/sandboxes/events-dockview/src/app';
|
import EventsDockview from '@site/sandboxes/events-dockview/src/app';
|
||||||
import DockviewGroupControl from '@site/sandboxes/headeractions-dockview/src/app';
|
// import DockviewGroupControl from '@site/sandboxes/headeractions-dockview/src/app';
|
||||||
import CustomHeadersDockview from '@site/sandboxes/customheader-dockview/src/app';
|
import CustomHeadersDockview from '@site/sandboxes/customheader-dockview/src/app';
|
||||||
import DockviewNative from '@site/sandboxes/fullwidthtab-dockview/src/app';
|
import DockviewNative from '@site/sandboxes/fullwidthtab-dockview/src/app';
|
||||||
import DockviewNative2 from '@site/sandboxes/nativeapp-dockview/src/app';
|
import DockviewNative2 from '@site/sandboxes/nativeapp-dockview/src/app';
|
||||||
@ -25,13 +25,13 @@ 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 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 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 DockviewScrollbars from '@site/sandboxes/scrollbars-dockview/src/app';
|
// import DockviewScrollbars from '@site/sandboxes/scrollbars-dockview/src/app';
|
||||||
|
|
||||||
import DockviewFocus from '@site/sandboxes/focus-dockview/src/app';
|
import DockviewFocus from '@site/sandboxes/focus-dockview/src/app';
|
||||||
|
|
||||||
@ -199,10 +199,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.
|
||||||
|
|
||||||
<MultiFrameworkContainer
|
{/* <MultiFrameworkContainer
|
||||||
sandboxId="layout-dockview"
|
sandboxId="layout-dockview"
|
||||||
react={DockviewPersistence}
|
react={DockviewPersistence}
|
||||||
/>
|
/> */}
|
||||||
|
|
||||||
## Scrollbars
|
## Scrollbars
|
||||||
|
|
||||||
@ -215,10 +215,10 @@ The following container three views:
|
|||||||
- **Panel 3**: Sets `height: 100%` and defines an inner component with `overflow: auto` to enable the scrollbars.
|
- **Panel 3**: Sets `height: 100%` and defines an inner component with `overflow: auto` to enable the scrollbars.
|
||||||
|
|
||||||
|
|
||||||
<MultiFrameworkContainer
|
{/* <MultiFrameworkContainer
|
||||||
sandboxId="scrollbars-dockview"
|
sandboxId="scrollbars-dockview"
|
||||||
react={DockviewScrollbars}
|
react={DockviewScrollbars}
|
||||||
/>
|
/> */}
|
||||||
|
|
||||||
## Resizing
|
## Resizing
|
||||||
|
|
||||||
@ -264,10 +264,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.
|
||||||
|
|
||||||
<MultiFrameworkContainer
|
{/* <MultiFrameworkContainer
|
||||||
sandboxId="watermark-dockview"
|
sandboxId="watermark-dockview"
|
||||||
react={DockviewWatermark}
|
react={DockviewWatermark}
|
||||||
/>
|
/> */}
|
||||||
|
|
||||||
## Drag And Drop
|
## Drag And Drop
|
||||||
|
|
||||||
@ -402,11 +402,11 @@ You can control the bounding box of floating groups through the optional `floati
|
|||||||
- `{minimumHeightWithinViewport?: number, minimumWidthWithinViewport?: number}` sets the respective dimension minimums that must appears 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.
|
- If no options are provided the defaults of `100px` minimum height and width within the viewport are set.
|
||||||
|
|
||||||
<MultiFrameworkContainer
|
{/* <MultiFrameworkContainer
|
||||||
height={600}
|
height={600}
|
||||||
sandboxId="floatinggroup-dockview"
|
sandboxId="floatinggroup-dockview"
|
||||||
react={DockviewFloating}
|
react={DockviewFloating}
|
||||||
/>
|
/> */}
|
||||||
|
|
||||||
## Popout Groups
|
## Popout Groups
|
||||||
|
|
||||||
@ -447,11 +447,11 @@ const group = props.containerApi.addGroup();
|
|||||||
props.group.api.moveTo({ group });
|
props.group.api.moveTo({ group });
|
||||||
```
|
```
|
||||||
|
|
||||||
<MultiFrameworkContainer
|
{/* <MultiFrameworkContainer
|
||||||
height={600}
|
height={600}
|
||||||
sandboxId="popoutgroup-dockview"
|
sandboxId="popoutgroup-dockview"
|
||||||
react={DockviewPopoutGroup}
|
react={DockviewPopoutGroup}
|
||||||
/>
|
/> */}
|
||||||
|
|
||||||
## Maximized Groups
|
## Maximized Groups
|
||||||
|
|
||||||
@ -486,11 +486,11 @@ const result: boolean = api.isMaxmized();
|
|||||||
api.exitMaximized();
|
api.exitMaximized();
|
||||||
```
|
```
|
||||||
|
|
||||||
<MultiFrameworkContainer
|
{/* <MultiFrameworkContainer
|
||||||
height={600}
|
height={600}
|
||||||
sandboxId="maximizegroup-dockview"
|
sandboxId="maximizegroup-dockview"
|
||||||
react={DockviewMaximizeGroup}
|
react={DockviewMaximizeGroup}
|
||||||
/>
|
/> */}
|
||||||
|
|
||||||
|
|
||||||
## Panels
|
## Panels
|
||||||
@ -663,11 +663,11 @@ 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
|
- `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.
|
HTMLElement and hidden the HTMLElement with `display: none` when it should be hidden.
|
||||||
|
|
||||||
<MultiFrameworkContainer
|
{/* <MultiFrameworkContainer
|
||||||
height={500}
|
height={500}
|
||||||
sandboxId="rendermode-dockview"
|
sandboxId="rendermode-dockview"
|
||||||
react={DockviewRenderMode}
|
react={DockviewRenderMode}
|
||||||
/>
|
/> */}
|
||||||
|
|
||||||
####
|
####
|
||||||
|
|
||||||
@ -937,10 +937,10 @@ const RightHeaderActionsComponent = (props: IDockviewHeaderActionsProps) => {
|
|||||||
};
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
<MultiFrameworkContainer
|
{/* <MultiFrameworkContainer
|
||||||
sandboxId="groupcontrol-dockview"
|
sandboxId="groupcontrol-dockview"
|
||||||
react={DockviewGroupControl}
|
react={DockviewGroupControl}
|
||||||
/>
|
/> */}
|
||||||
|
|
||||||
### Constraints
|
### Constraints
|
||||||
|
|
||||||
@ -954,11 +954,11 @@ 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.
|
||||||
|
|
||||||
<MultiFrameworkContainer
|
{/* <MultiFrameworkContainer
|
||||||
height={500}
|
height={500}
|
||||||
sandboxId="constraints-dockview"
|
sandboxId="constraints-dockview"
|
||||||
react={DockviewConstraints}
|
react={DockviewConstraints}
|
||||||
/>
|
/> */}
|
||||||
|
|
||||||
|
|
||||||
## iFrames
|
## iFrames
|
||||||
|
78
packages/docs/docs/components/intro.mdx
Normal file
78
packages/docs/docs/components/intro.mdx
Normal file
@ -0,0 +1,78 @@
|
|||||||
|
---
|
||||||
|
title: Get Started
|
||||||
|
sidebar_position: 0
|
||||||
|
---
|
||||||
|
|
||||||
|
import { MultiFrameworkContainer } from '@site/src/components/ui/container';
|
||||||
|
|
||||||
|
import SimpleDockview from '@site/sandboxes/simple-dockview/src/app';
|
||||||
|
import DockviewExampleApp from '@site/sandboxes/example-app-dockview/src/app';
|
||||||
|
import { attach as attachSimpleDockview } from '@site/sandboxes/javascript/simple-dockview/src/app';
|
||||||
|
|
||||||
|
|
||||||
|
<MultiFrameworkContainer
|
||||||
|
sandboxId="example-app-dockview"
|
||||||
|
react={DockviewExampleApp}
|
||||||
|
/>
|
||||||
|
|
||||||
|
|
||||||
|
## Introduction
|
||||||
|
|
||||||
|
Dockview is an abstraction built on top of [Gridviews](./gridview) where each view is a container of many tabbed panels.
|
||||||
|
|
||||||
|
<MultiFrameworkContainer
|
||||||
|
sandboxId="simple-dockview"
|
||||||
|
react={SimpleDockview}
|
||||||
|
typescript={attachSimpleDockview}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<br />
|
||||||
|
|
||||||
|
> You can access the panels associated group through the `panel.group` variable.
|
||||||
|
> The group will always be defined and will change if a panel is moved into another group.
|
||||||
|
|
||||||
|
|
||||||
|
## Dockview API
|
||||||
|
|
||||||
|
The Dockview API is exposed both at the `onReady` event and on each panel through `props.containerApi`.
|
||||||
|
Through this API you can control general features of the component and access all added panels.
|
||||||
|
|
||||||
|
```tsx title="Dockview API via Panel component"
|
||||||
|
const MyComponent = (props: IDockviewPanelProps<{ title: string }>) => {
|
||||||
|
// props.containerApi...
|
||||||
|
|
||||||
|
return <div>{`My first panel has the title: ${props.params.title}`}</div>;
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
```tsx title="Dockview API via the onReady callback"
|
||||||
|
const onReady = (event: DockviewReadyEvent) => {
|
||||||
|
// event.api...
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
## Dockview Panel API
|
||||||
|
|
||||||
|
```tsx
|
||||||
|
const MyComponent = (props: IDockviewPanelProps<{ title: string }>) => {
|
||||||
|
// props.api...
|
||||||
|
|
||||||
|
return <div>{`My first panel has the title: ${props.params.title}`}</div>;
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
6
packages/docs/docs/core/dnd/_category_.json
Normal file
6
packages/docs/docs/core/dnd/_category_.json
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
{
|
||||||
|
"position": 3,
|
||||||
|
"label": "Drag & Drop",
|
||||||
|
"collapsible": true,
|
||||||
|
"collapsed": true
|
||||||
|
}
|
20
packages/docs/docs/core/dnd/disable.mdx
Normal file
20
packages/docs/docs/core/dnd/disable.mdx
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
---
|
||||||
|
title: 'Disable Dnd'
|
||||||
|
sidebar_position: 3
|
||||||
|
---
|
||||||
|
|
||||||
|
import { DocRef } from '@site/src/components/ui/reference/docRef';
|
||||||
|
|
||||||
|
|
||||||
|
<FrameworkSpecific framework="JavaScript">
|
||||||
|
<DocRef declaration="DockviewComponentOptions" methods={["disableDnd"]} />
|
||||||
|
</FrameworkSpecific>
|
||||||
|
|
||||||
|
<FrameworkSpecific framework="React">
|
||||||
|
<DocRef declaration="IDockviewReactProps" methods={["disableDnd"]} />
|
||||||
|
</FrameworkSpecific>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
97
packages/docs/docs/core/dnd/dragAndDrop.mdx
Normal file
97
packages/docs/docs/core/dnd/dragAndDrop.mdx
Normal file
@ -0,0 +1,97 @@
|
|||||||
|
---
|
||||||
|
title: 'Dnd'
|
||||||
|
sidebar_position: 1
|
||||||
|
---
|
||||||
|
|
||||||
|
import useBaseUrl from '@docusaurus/useBaseUrl';
|
||||||
|
import { MultiFrameworkContainer } from '@site/src/components/ui/container';
|
||||||
|
import DndDockview from '@site/sandboxes/dnd-dockview/src/app';
|
||||||
|
import DockviewExternalDnd from '@site/sandboxes/externaldnd-dockview/src/app';
|
||||||
|
import LiveExample from '@site/src/components/ui/exampleFrame';
|
||||||
|
|
||||||
|
import { DocRef } from '@site/src/components/ui/reference/docRef';
|
||||||
|
|
||||||
|
The dock makes heavy use of drag and drop functionalities.
|
||||||
|
|
||||||
|
<DocRef declaration="DockviewApi"
|
||||||
|
methods={[
|
||||||
|
'onWillDragPanel', 'onWillDragGroup',
|
||||||
|
'onWillDrop', 'onDidDrop', 'onWillShowOverlay'
|
||||||
|
]}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<LiveExample framework='react' id='dockview/dnd-events' />
|
||||||
|
|
||||||
|
|
||||||
|
# Drag And Drop
|
||||||
|
|
||||||
|
You can override the conditions of the far edge overlays through the `rootOverlayModel` prop.
|
||||||
|
|
||||||
|
```tsx
|
||||||
|
<DockviewReact
|
||||||
|
{...props}
|
||||||
|
rootOverlayModel={{
|
||||||
|
size: { value: 100, type: 'pixels' },
|
||||||
|
activationSize: { value: 5, type: 'percentage' },
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
```
|
||||||
|
|
||||||
|
## Extended behaviours
|
||||||
|
|
||||||
|
For interaction with the Drag events directly the component exposes some method to help determine whether external drag events should be interacted with or not.
|
||||||
|
|
||||||
|
```tsx
|
||||||
|
/**
|
||||||
|
* called when an ondrop event which does not originate from the dockview libray and
|
||||||
|
* passes the showDndOverlay condition occurs
|
||||||
|
**/
|
||||||
|
const onDidDrop = (event: DockviewDropEvent) => {
|
||||||
|
const { group } = event;
|
||||||
|
|
||||||
|
event.api.addPanel({
|
||||||
|
id: 'test',
|
||||||
|
component: 'default',
|
||||||
|
position: {
|
||||||
|
referencePanel: group.activePanel.id,
|
||||||
|
direction: 'within',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* called for drag over events which do not originate from the dockview library
|
||||||
|
* allowing the developer to decide where the overlay should be shown for a
|
||||||
|
* particular drag event
|
||||||
|
**/
|
||||||
|
const showDndOverlay = (event: DockviewDndOverlayEvent) => {
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<DockviewReact
|
||||||
|
components={components}
|
||||||
|
onReady={onReady}
|
||||||
|
className="dockview-theme-abyss"
|
||||||
|
onDidDrop={onDidDrop}
|
||||||
|
showDndOverlay={showDndOverlay}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
## Intercepting Drag Events
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
This shows a simple example of a third-party library used inside a panel that relies on drag
|
||||||
|
and drop functionalities. This examples serves to show that `dockview` doesn't interfer with
|
||||||
|
any drag and drop logic for other controls.
|
||||||
|
|
||||||
|
<MultiFrameworkContainer
|
||||||
|
sandboxId="externaldnd-dockview"
|
||||||
|
react={DockviewExternalDnd}
|
||||||
|
/>
|
44
packages/docs/docs/core/dnd/overview.mdx
Normal file
44
packages/docs/docs/core/dnd/overview.mdx
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
---
|
||||||
|
title: 'Overview'
|
||||||
|
sidebar_position: 0
|
||||||
|
---
|
||||||
|
|
||||||
|
import useBaseUrl from '@docusaurus/useBaseUrl';
|
||||||
|
import { MultiFrameworkContainer } from '@site/src/components/ui/container';
|
||||||
|
import DndDockview from '@site/sandboxes/dnd-dockview/src/app';
|
||||||
|
import DockviewExternalDnd from '@site/sandboxes/externaldnd-dockview/src/app';
|
||||||
|
|
||||||
|
import { DocRef } from '@site/src/components/ui/reference/docRef';
|
||||||
|
|
||||||
|
Dockview supports a wide variety of built-in Drag and Drop possibilities.
|
||||||
|
|
||||||
|
<h4>Position a tab between two other tabs</h4>
|
||||||
|
|
||||||
|
<div style={{display:' flex', justifyContent: 'center'}}>
|
||||||
|
<img style={{ height: '50px' }} src={useBaseUrl('/img/add_to_tab.svg')} />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<h4>Position a tab at the end of a list of tabs</h4>
|
||||||
|
|
||||||
|
<div style={{display:' flex', justifyContent: 'center'}}>
|
||||||
|
<img style={{ height: '50px' }} src={useBaseUrl('/img/add_to_empty_space.svg')} />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<h4>Merge one group with another group</h4>
|
||||||
|
|
||||||
|
<div style={{display:' flex', justifyContent: 'center'}}>
|
||||||
|
<img style={{ height: '50px' }} src={useBaseUrl('/img/add_to_group.svg')} />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<h4>Move both Tabs and Groups in relation to another group</h4>
|
||||||
|
|
||||||
|
|
||||||
|
<div style={{display:' flex', justifyContent: 'center'}}>
|
||||||
|
<img style={{ height: '300px' }} src={useBaseUrl('/img/drop_positions.svg')} />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<h4>Move both Tabs and Groups in relation to the container</h4>
|
||||||
|
|
||||||
|
<div style={{display:' flex', justifyContent: 'center'}}>
|
||||||
|
<img style={{ height: '300px' }} src={useBaseUrl('/img/magnet_drop_positions.svg')} />
|
||||||
|
</div>
|
13
packages/docs/docs/core/dnd/thirdParty.mdx
Normal file
13
packages/docs/docs/core/dnd/thirdParty.mdx
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
---
|
||||||
|
title: 'Third Party Libraries'
|
||||||
|
sidebar_position: 2
|
||||||
|
---
|
||||||
|
|
||||||
|
All third party Drag & Drop libraries should work as expected.
|
||||||
|
|
||||||
|
Dockview fire and intercepts Drag & Drop events extensively however it is indended that the user has ultimate
|
||||||
|
control over all events.
|
||||||
|
|
||||||
|
Dockview should not change the behaviours of any third party Drag & Drop libraries.
|
||||||
|
If you feel that Dockview is cause the behaviour of any third party Drag & Drop libraries to change please
|
||||||
|
raise an Issue.
|
6
packages/docs/docs/core/groups/_category_.json
Normal file
6
packages/docs/docs/core/groups/_category_.json
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
{
|
||||||
|
"position": 3,
|
||||||
|
"label": "Groups",
|
||||||
|
"collapsible": true,
|
||||||
|
"collapsed": true
|
||||||
|
}
|
17
packages/docs/docs/core/groups/constraints.mdx
Normal file
17
packages/docs/docs/core/groups/constraints.mdx
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
---
|
||||||
|
title: Constraints
|
||||||
|
---
|
||||||
|
|
||||||
|
import LiveExample from '@site/src/components/ui/exampleFrame';
|
||||||
|
import { DocRef } from '@site/src/components/ui/reference/docRef'
|
||||||
|
|
||||||
|
:::warning
|
||||||
|
Constraints come with several caveats. They are not serialized with layouts and can only be applied to groups.
|
||||||
|
:::
|
||||||
|
|
||||||
|
<DocRef declaration="DockviewGroupPanelApi" methods={['setConstraints', 'onDidConstraintsChange']} />
|
||||||
|
|
||||||
|
## Live Example
|
||||||
|
|
||||||
|
<LiveExample framework="react" id="dockview/constraints"/>
|
||||||
|
|
43
packages/docs/docs/core/groups/controls.mdx
Normal file
43
packages/docs/docs/core/groups/controls.mdx
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
---
|
||||||
|
title: Group Controls
|
||||||
|
---
|
||||||
|
|
||||||
|
import LiveExample from '@site/src/components/ui/exampleFrame';
|
||||||
|
import { DocRef } from '@site/src/components/ui/reference/docRef';
|
||||||
|
|
||||||
|
This section describes how you can customize the header component of each group.
|
||||||
|
|
||||||
|
<FrameworkSpecific framework='React'>
|
||||||
|
<DocRef declaration="IDockviewReactProps" methods={['leftHeaderActionsComponent', 'rightHeaderActionsComponent', 'prefixHeaderActionsComponent']} />
|
||||||
|
</FrameworkSpecific>
|
||||||
|
|
||||||
|
<FrameworkSpecific framework='JavaScript'>
|
||||||
|
<DocRef declaration="DockviewComponentOptions"
|
||||||
|
methods={['createLeftHeaderActionsElement', 'createRightHeaderActionsElement', 'createPrefixHeaderActionsElement']} />
|
||||||
|
</FrameworkSpecific>
|
||||||
|
|
||||||
|
|
||||||
|
```tsx
|
||||||
|
const LeftComponent = (props: IDockviewHeaderActionsProps) => {
|
||||||
|
return <div>{/** content */}</div>;
|
||||||
|
};
|
||||||
|
|
||||||
|
const RightComponent = (props: IDockviewHeaderActionsProps) => {
|
||||||
|
return <div>{/** content */}</div>;
|
||||||
|
};
|
||||||
|
|
||||||
|
const PrefixComponent = (props: IDockviewHeaderActionsProps) => {
|
||||||
|
return <div>{/** content */}</div>;
|
||||||
|
};
|
||||||
|
|
||||||
|
return <DockviewReact
|
||||||
|
leftHeaderActionsComponent={LeftComponent}
|
||||||
|
rightHeaderActionsComponent={RightComponent}
|
||||||
|
prefixHeaderActionsComponent={PrefixComponent}
|
||||||
|
/>;
|
||||||
|
```
|
||||||
|
|
||||||
|
## Live Example
|
||||||
|
|
||||||
|
<LiveExample framework="react" id="dockview/group-actions"/>
|
||||||
|
|
79
packages/docs/docs/core/groups/floatingGroups.mdx
Normal file
79
packages/docs/docs/core/groups/floatingGroups.mdx
Normal file
@ -0,0 +1,79 @@
|
|||||||
|
---
|
||||||
|
title: Floating Groups
|
||||||
|
---
|
||||||
|
|
||||||
|
import useBaseUrl from '@docusaurus/useBaseUrl';
|
||||||
|
import LiveExample from '@site/src/components/ui/exampleFrame';
|
||||||
|
import { DocRef } from '@site/src/components/ui/reference/docRef';
|
||||||
|
|
||||||
|
This section describes floating groups.
|
||||||
|
|
||||||
|
:::info
|
||||||
|
Floating groups **cannot** be maximized. Calling maximize function on groups in these states will have no effect.
|
||||||
|
:::
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
|
## Options
|
||||||
|
|
||||||
|
The following properties can be set to configure the behaviours of floating groups.
|
||||||
|
|
||||||
|
<FrameworkSpecific framework='React'>
|
||||||
|
<DocRef declaration="IDockviewReactProps" methods={['floatingGroupBounds', 'disableFloatingGroups']} />
|
||||||
|
</FrameworkSpecific>
|
||||||
|
|
||||||
|
<FrameworkSpecific framework='JavaScript'>
|
||||||
|
<DocRef declaration="DockviewComponentOptions" methods={['floatingGroupBounds', 'disableFloatingGroups']} />
|
||||||
|
</FrameworkSpecific>
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
|
|
||||||
|
## API
|
||||||
|
|
||||||
|
The following properties can be used to create floating groups
|
||||||
|
|
||||||
|
<DocRef declaration="DockviewApi" methods={['addFloatingGroup']} />
|
||||||
|
|
||||||
|
:::info
|
||||||
|
`addFloatingGroup` only accepts existing panels and groups. See [Addding Panels](/docs/core/panels/add) on how to firstly add panels.
|
||||||
|
:::
|
||||||
|
|
||||||
|
|
||||||
|
Floating groups can be programatically added through the dockview `api` method `api.addFloatingGroup(...)`.
|
||||||
|
|
||||||
|
## Panel and Group API
|
||||||
|
|
||||||
|
<DocRef declaration="DockviewPanelApi" methods={['location', 'onDidLocationChange']} />
|
||||||
|
|
||||||
|
You can check whether a group is floating via the `group.api.location` property. See examples for full code.
|
||||||
|
|
||||||
|
|
||||||
|
## Working with Floating Groups
|
||||||
|
|
||||||
|
<h4>Float an existing tab by holding `shift` whilst interacting with the tab</h4>
|
||||||
|
|
||||||
|
<div style={{display:' flex', justifyContent: 'center'}}>
|
||||||
|
<img style={{ height: '200px' }} src={useBaseUrl('/img/float_add.svg')} />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<h4>Move a floating tab by holding `shift` whilst moving the cursor or dragging the empty header space</h4>
|
||||||
|
|
||||||
|
<div style={{display:' flex', justifyContent: 'center'}}>
|
||||||
|
<img style={{ height: '200px' }} src={useBaseUrl('/img/float_move.svg')} />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<h4>Move an entire floating group by holding `shift` whilst dragging the empty header space</h4>
|
||||||
|
|
||||||
|
<div style={{display:' flex', justifyContent: 'center'}}>
|
||||||
|
<img style={{ height: '200px' }} src={useBaseUrl('/img/float_group.svg')} />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
## Live Example
|
||||||
|
|
||||||
|
<LiveExample framework="react" id="dockview/floating-groups"/>
|
13
packages/docs/docs/core/groups/hiddenHeader.mdx
Normal file
13
packages/docs/docs/core/groups/hiddenHeader.mdx
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
---
|
||||||
|
title: Hidden Header
|
||||||
|
---
|
||||||
|
|
||||||
|
import useBaseUrl from '@docusaurus/useBaseUrl';
|
||||||
|
import LiveExample from '@site/src/components/ui/exampleFrame';
|
||||||
|
import { DocRef } from '@site/src/components/ui/reference/docRef';
|
||||||
|
|
||||||
|
You may wish to hide the header section of a group. This can achieved through the `hidden` variable on `panel.group.header`.
|
||||||
|
|
||||||
|
```tsx
|
||||||
|
panel.group.header.hidden = true;
|
||||||
|
```
|
27
packages/docs/docs/core/groups/locked.mdx
Normal file
27
packages/docs/docs/core/groups/locked.mdx
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
---
|
||||||
|
title: Locked Groups
|
||||||
|
---
|
||||||
|
|
||||||
|
import { MultiFrameworkContainer } from '@site/src/components/ui/container';
|
||||||
|
import DockviewLockedGroup from '@site/sandboxes/lockedgroup-dockview/src/app';
|
||||||
|
|
||||||
|
## Locked group
|
||||||
|
|
||||||
|
Locking a group will disable all drop events for this group ensuring no additional panels can be added to the group through drop events.
|
||||||
|
You can still add groups to a locked panel programatically using the API though.
|
||||||
|
|
||||||
|
```tsx
|
||||||
|
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}
|
||||||
|
/>
|
58
packages/docs/docs/core/groups/maxmizedGroups.mdx
Normal file
58
packages/docs/docs/core/groups/maxmizedGroups.mdx
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
---
|
||||||
|
title: Maximized Groups
|
||||||
|
---
|
||||||
|
|
||||||
|
import { DocRef } from '@site/src/components/ui/reference/docRef';
|
||||||
|
import LiveExample from '@site/src/components/ui/exampleFrame';
|
||||||
|
|
||||||
|
This section described how to maxmimize groups.
|
||||||
|
|
||||||
|
## Options
|
||||||
|
|
||||||
|
<DocRef declaration="DockviewApi" methods={['maximizeGroup', 'hasMaximizedGroup', 'exitMaximizedGroup', 'onDidMaxmizedGroupChange']} />
|
||||||
|
|
||||||
|
```tsx
|
||||||
|
const api: DockviewApi;
|
||||||
|
|
||||||
|
// 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();
|
||||||
|
```
|
||||||
|
|
||||||
|
## Panel API
|
||||||
|
|
||||||
|
<DocRef declaration="DockviewPanelApi" methods={['maximize', 'isMaximized', 'exitMaximized']} />
|
||||||
|
|
||||||
|
```tsx
|
||||||
|
const api: DockviewPanelApi;
|
||||||
|
|
||||||
|
// 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();
|
||||||
|
```
|
||||||
|
|
||||||
|
:::tip
|
||||||
|
`api.<maximize|isMaximized|exitMaximized>` is equivalent to `api.group.api.<maximize|isMaximized|exitMaximized>`.
|
||||||
|
The methods exist on the panel `api` object for convenience.
|
||||||
|
:::
|
||||||
|
|
||||||
|
## Live Examples
|
||||||
|
|
||||||
|
<LiveExample framework="react" id="dockview/maximize-group"/>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
21
packages/docs/docs/core/groups/move.mdx
Normal file
21
packages/docs/docs/core/groups/move.mdx
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
---
|
||||||
|
title: Move Group
|
||||||
|
sidebar_position: 5
|
||||||
|
---
|
||||||
|
|
||||||
|
import { DocRef } from '@site/src/components/ui/reference/docRef';
|
||||||
|
|
||||||
|
This section describes how you can move a group.
|
||||||
|
|
||||||
|
## Methods
|
||||||
|
|
||||||
|
<DocRef declaration="DockviewGroupPanelApi" methods={["moveTo"]}/>
|
||||||
|
|
||||||
|
## Move a Group
|
||||||
|
|
||||||
|
You can move a group through the [Group API](/docs/api/dockview/groupApi) and you can find out how to move a Panel [here](/docs/core/panels/move).
|
||||||
|
|
||||||
|
```ts
|
||||||
|
panel.group.api.moveTo({ group, position, index });
|
||||||
|
```
|
||||||
|
|
60
packages/docs/docs/core/groups/popoutGroups.mdx
Normal file
60
packages/docs/docs/core/groups/popoutGroups.mdx
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
---
|
||||||
|
title: Popout Windows
|
||||||
|
---
|
||||||
|
|
||||||
|
import LiveExample from '@site/src/components/ui/exampleFrame';
|
||||||
|
import { DocRef } from '@site/src/components/ui/reference/docRef';
|
||||||
|
|
||||||
|
This section describes have to create popout windows.
|
||||||
|
|
||||||
|
:::info
|
||||||
|
Popout groups **cannot** be maximized. Calling maximize function on groups in these states will have no effect.
|
||||||
|
:::
|
||||||
|
|
||||||
|
<DocRef declaration="DockviewApi" methods={['addPopoutGroup']} />
|
||||||
|
|
||||||
|
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
|
||||||
|
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);
|
||||||
|
```
|
||||||
|
|
||||||
|
## Closing the Popout 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 });
|
||||||
|
```
|
||||||
|
|
||||||
|
Alternatively, if the user closes the Window the group the dock will make a best attempt to place it back
|
||||||
|
in it's original location within the grid. If the dock cannot determine the original location it will
|
||||||
|
choose a new location.
|
||||||
|
|
||||||
|
|
||||||
|
<LiveExample framework="react" id="dockview/popout-group"/>
|
37
packages/docs/docs/core/groups/resizing.mdx
Normal file
37
packages/docs/docs/core/groups/resizing.mdx
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
---
|
||||||
|
title: Resizing
|
||||||
|
---
|
||||||
|
|
||||||
|
import LiveExample from '@site/src/components/ui/exampleFrame';
|
||||||
|
import { DocRef } from '@site/src/components/ui/reference/docRef';
|
||||||
|
|
||||||
|
<DocRef declaration="DockviewGroupPanelApi" methods={['height', 'width', 'setSize', 'onDidDimensionsChange']} />
|
||||||
|
|
||||||
|
|
||||||
|
## Panel Resizing
|
||||||
|
|
||||||
|
Each Dockview contains of a number of groups and each group has a number of panels.
|
||||||
|
Logically a user may want to resize a panel, but this translates to resizing the group which contains that panel.
|
||||||
|
|
||||||
|
You can set the size of a panel using `props.api.setSize(...)`.
|
||||||
|
You can also set the size of the group associated with the panel using `props.api.group.api.setSize(...)` although this isn't recommended
|
||||||
|
due to the clunky syntax.
|
||||||
|
|
||||||
|
```tsx
|
||||||
|
// it's mandatory to provide either a height or a width, providing both is optional
|
||||||
|
props.api.setSize({
|
||||||
|
height: 100,
|
||||||
|
width: 200,
|
||||||
|
});
|
||||||
|
|
||||||
|
// you could also resize the panels group, although not recommended it achieved the same result
|
||||||
|
props.api.group.api.setSize({
|
||||||
|
height: 100,
|
||||||
|
width: 200,
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
You can see an example invoking both approaches below.
|
||||||
|
|
||||||
|
|
||||||
|
<LiveExample framework="react" id="dockview/resize"/>
|
12
packages/docs/docs/core/locked.mdx
Normal file
12
packages/docs/docs/core/locked.mdx
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
---
|
||||||
|
title: Locked
|
||||||
|
---
|
||||||
|
|
||||||
|
import useBaseUrl from '@docusaurus/useBaseUrl';
|
||||||
|
|
||||||
|
import { DocRef } from '@site/src/components/ui/reference/docRef';
|
||||||
|
import LiveExample from '@site/src/components/ui/exampleFrame';
|
||||||
|
|
||||||
|
This section describes how to lock the dock to prevent movement.
|
||||||
|
|
||||||
|
<LiveExample framework='react' id='dockview/locked'/>
|
42
packages/docs/docs/core/overview.mdx
Normal file
42
packages/docs/docs/core/overview.mdx
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
---
|
||||||
|
title: Overview
|
||||||
|
sidebar_position: 0
|
||||||
|
---
|
||||||
|
|
||||||
|
import LiveExample from '@site/src/components/ui/exampleFrame';
|
||||||
|
|
||||||
|
This section provided a core overview.
|
||||||
|
|
||||||
|
The component takes a collection of [Options](/docs/api/dockview/options) as inputs and
|
||||||
|
once you have created a dock you can store a reference to the [API](/docs/api/dockview/overview) that is created.
|
||||||
|
|
||||||
|
<FrameworkSpecific framework='React'>
|
||||||
|
```tsx
|
||||||
|
function onReady(event: DockviewReadyEvent) {
|
||||||
|
/**
|
||||||
|
* You should store a reference to `api` in a Ref or State
|
||||||
|
* for later interactions
|
||||||
|
*/
|
||||||
|
const api: DockviewApi = event.api;
|
||||||
|
}
|
||||||
|
|
||||||
|
<DockviewReact onReady={onReady}/>
|
||||||
|
```
|
||||||
|
</FrameworkSpecific>
|
||||||
|
|
||||||
|
|
||||||
|
<FrameworkSpecific framework='JavaScript'>
|
||||||
|
```tsx
|
||||||
|
const component = new DockviewComponent({
|
||||||
|
/** options */
|
||||||
|
});
|
||||||
|
```
|
||||||
|
</FrameworkSpecific>
|
||||||
|
|
||||||
|
## Container Resizing
|
||||||
|
|
||||||
|
The component will automatically resize to it's container.
|
||||||
|
|
||||||
|
<LiveExample framework="react" id="dockview/resize-container"/>
|
||||||
|
|
||||||
|
# Disposal Pattern
|
6
packages/docs/docs/core/panels/_category_.json
Normal file
6
packages/docs/docs/core/panels/_category_.json
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
{
|
||||||
|
"position": 1,
|
||||||
|
"label": "Panels",
|
||||||
|
"collapsible": true,
|
||||||
|
"collapsed": true
|
||||||
|
}
|
167
packages/docs/docs/core/panels/add.mdx
Normal file
167
packages/docs/docs/core/panels/add.mdx
Normal file
@ -0,0 +1,167 @@
|
|||||||
|
---
|
||||||
|
title: Adding Panels
|
||||||
|
sidebar_position: 1
|
||||||
|
---
|
||||||
|
|
||||||
|
import { DocRef } from '@site/src/components/ui/reference/docRef';
|
||||||
|
import LiveExample from '@site/src/components/ui/exampleFrame';
|
||||||
|
|
||||||
|
This section describes how to add a new panel and the options you can provide.
|
||||||
|
|
||||||
|
|
||||||
|
Panels can be added through the dock api.
|
||||||
|
|
||||||
|
<DocRef declaration="DockviewApi" methods={['addPanel']} />
|
||||||
|
|
||||||
|
## Opening a Basic Panel
|
||||||
|
|
||||||
|
To open a panel requires a unique `id` and the name of the `component` to render.
|
||||||
|
|
||||||
|
```ts
|
||||||
|
const panel: IDockviewPanel = api.addPanel({
|
||||||
|
id: 'my_unique_panel_id',
|
||||||
|
component: 'my_component',
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
> See [Overview](/docs/core/overview) to register components.
|
||||||
|
|
||||||
|
## Providing a Panel Title
|
||||||
|
|
||||||
|
:::warning
|
||||||
|
Registering and updating the title using these built-in variables only works for the default tab renderer.
|
||||||
|
If you use a custom tab render you can optionally access these variables to render the title, or you can take
|
||||||
|
your own approach to rendering a tab title.
|
||||||
|
:::
|
||||||
|
|
||||||
|
Use `title` to provide a custom title for the panel. If no `title` is provided then the dock will render `id` in the tab.
|
||||||
|
|
||||||
|
```tsx
|
||||||
|
api.addPanel({
|
||||||
|
id: 'panel_1',
|
||||||
|
component: 'my_component',
|
||||||
|
title: 'my_custom_title',
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
```tsx
|
||||||
|
api.setTitle('my_new_custom_title');
|
||||||
|
```
|
||||||
|
|
||||||
|
<LiveExample framework="react" id="dockview/update-title" height={250}/>
|
||||||
|
|
||||||
|
## Provide a custom Tab renderer
|
||||||
|
|
||||||
|
:::info
|
||||||
|
You can override the default tab renderer through the [Options](/docs/api/dockview/options).
|
||||||
|
:::
|
||||||
|
|
||||||
|
To render a custom tab component you should specify the `tabComponent`.
|
||||||
|
|
||||||
|
```ts
|
||||||
|
const panel: IDockviewPanel = api.addPanel({
|
||||||
|
id: 'my_unique_panel_id',
|
||||||
|
component: 'my_component',
|
||||||
|
tabComponent: 'my_tab_component',
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
> See [Tabs](/docs/core/panels/tabs) to learn how to register tab components.
|
||||||
|
|
||||||
|
## Provide custom Parameters
|
||||||
|
|
||||||
|
Using the `params` option you can specific a simple object that is accessible in both the panel and tab renderer.
|
||||||
|
To update these parameters after the panel has been created see [Update Panel](/docs/core/panels/update).
|
||||||
|
|
||||||
|
```ts
|
||||||
|
const panel: IDockviewPanel = api.addPanel({
|
||||||
|
id: 'my_unique_panel_id',
|
||||||
|
component: 'my_component',
|
||||||
|
params: {
|
||||||
|
myCustomKey: 'my_custom_value',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
## Rendering
|
||||||
|
|
||||||
|
See [Panel Rendering](/docs/core/panels/rendering).
|
||||||
|
|
||||||
|
## Positioning the Panel
|
||||||
|
|
||||||
|
You can position a panel relative to an existing panel, group using `direction`. If you do not provide a reference panel
|
||||||
|
or group then the panel will be positioned to the edge of the dock in the specified direction.
|
||||||
|
|
||||||
|
#### Relative to another Panel
|
||||||
|
|
||||||
|
```ts
|
||||||
|
const panel2: IDockviewPanel = api.addPanel({
|
||||||
|
id: 'panel_2',
|
||||||
|
component: 'default',
|
||||||
|
position: {
|
||||||
|
referencePanel: 'panel_1',
|
||||||
|
direction: 'above'
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
api.addPanel({
|
||||||
|
id: 'panel_3',
|
||||||
|
component: 'default',
|
||||||
|
position: {
|
||||||
|
referencePanel: panel2,
|
||||||
|
direction: 'above'
|
||||||
|
}
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Relative to another Group
|
||||||
|
|
||||||
|
```ts
|
||||||
|
const panel2: IDockviewPanel = api.addPanel({
|
||||||
|
id: 'panel_2',
|
||||||
|
component: 'default',
|
||||||
|
position: {
|
||||||
|
referenceGroup: 'panel_1',
|
||||||
|
direction: 'left'
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const panel = api.addPanel({
|
||||||
|
id: 'panel_2',
|
||||||
|
component: 'default',
|
||||||
|
position: {
|
||||||
|
referenceGroup: panel2.group,
|
||||||
|
direction: 'left'
|
||||||
|
}
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Relative to the container
|
||||||
|
|
||||||
|
```ts
|
||||||
|
const panel = api.addPanel({
|
||||||
|
id: 'panel_2',
|
||||||
|
component: 'default',
|
||||||
|
position: {
|
||||||
|
direction: 'right'
|
||||||
|
}
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
### Floating
|
||||||
|
|
||||||
|
You should specific the `floating` option which can be either `true` or an object describing the position of the floating group.
|
||||||
|
|
||||||
|
```ts
|
||||||
|
api.addPanel({
|
||||||
|
id: 'panel_1',
|
||||||
|
component: 'default',
|
||||||
|
floating: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
api.addPanel({
|
||||||
|
id: 'panel_2',
|
||||||
|
component: 'default',
|
||||||
|
floating: { x: 10, y: 10, width: 300, height: 300 },
|
||||||
|
});
|
||||||
|
```
|
28
packages/docs/docs/core/panels/move.mdx
Normal file
28
packages/docs/docs/core/panels/move.mdx
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
---
|
||||||
|
title: Move Panel
|
||||||
|
sidebar_position: 3
|
||||||
|
---
|
||||||
|
|
||||||
|
import { DocRef } from '@site/src/components/ui/reference/docRef';
|
||||||
|
|
||||||
|
This section describes how you can move a panel to another panel or group.
|
||||||
|
|
||||||
|
## Methods
|
||||||
|
|
||||||
|
<DocRef declaration="DockviewPanelApi" methods={["moveTo"]}/>
|
||||||
|
|
||||||
|
## Move a Panel
|
||||||
|
|
||||||
|
You can move a panel through the [Panel API](/docs/api/dockview/panelApi) and you can find out how to move a Group [here](/docs/core/groups/move).
|
||||||
|
|
||||||
|
```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 });
|
||||||
|
```
|
||||||
|
|
45
packages/docs/docs/core/panels/register.mdx
Normal file
45
packages/docs/docs/core/panels/register.mdx
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
---
|
||||||
|
title: Registering Panels
|
||||||
|
sidebar_position: 0
|
||||||
|
---
|
||||||
|
|
||||||
|
import { DocRef } from '@site/src/components/ui/reference/docRef';
|
||||||
|
|
||||||
|
|
||||||
|
This section describes how to register a panel.
|
||||||
|
|
||||||
|
You can register panels through the dock [option](/docs/api/dockview/options) `components`.
|
||||||
|
|
||||||
|
<FrameworkSpecific framework='React'>
|
||||||
|
<DocRef declaration="IDockviewReactProps" methods={['components']} />
|
||||||
|
</FrameworkSpecific>
|
||||||
|
|
||||||
|
<FrameworkSpecific framework='JavaScript'>
|
||||||
|
<DocRef declaration="DockviewComponentOptions" methods={['components']} />
|
||||||
|
</FrameworkSpecific>
|
||||||
|
|
||||||
|
|
||||||
|
<FrameworkSpecific framework='React'>
|
||||||
|
```tsx
|
||||||
|
const components = {
|
||||||
|
component_1: (props: IDockviewPanelProps) => {
|
||||||
|
const api: DockviewPanelApi = props.api;
|
||||||
|
const groupApi: DockviewGroupPanelApi = props.group.api;
|
||||||
|
const containerApi: DockviewApi = props.containerApi;
|
||||||
|
|
||||||
|
return <div>{/** logic */}</div>
|
||||||
|
},
|
||||||
|
component_2: (props: IDockviewPanelProps) => {
|
||||||
|
return <div>{/** logic */}</div>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return <DockviewReact components={components}/>
|
||||||
|
```
|
||||||
|
</FrameworkSpecific>
|
||||||
|
|
||||||
|
|
||||||
|
Each panel has an [api](/docs/api/dockview/panelApi) which is used to control specific
|
||||||
|
features on that individual panel.
|
||||||
|
The panel also has access the [group api](/docs/api/dockview/groupApi) and the container
|
||||||
|
[api](/docs/api/dockview/overview).
|
29
packages/docs/docs/core/panels/remove.mdx
Normal file
29
packages/docs/docs/core/panels/remove.mdx
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
---
|
||||||
|
title: Remove Panel
|
||||||
|
sidebar_position: 4
|
||||||
|
---
|
||||||
|
|
||||||
|
import { DocRef } from '@site/src/components/ui/reference/docRef';
|
||||||
|
|
||||||
|
This section describes multiple ways to remove a panel.
|
||||||
|
|
||||||
|
## Remove a Panel using the Panel API
|
||||||
|
|
||||||
|
<DocRef declaration="DockviewPanelApi" methods={["close"]}/>
|
||||||
|
|
||||||
|
Calling `close` on the panel API is the easiest way to close a panel through code.
|
||||||
|
|
||||||
|
```ts
|
||||||
|
panel.api.close();
|
||||||
|
```
|
||||||
|
|
||||||
|
## Remove a Panel using the API
|
||||||
|
<DocRef declaration="DockviewApi" methods={["removePanel"]}/>
|
||||||
|
|
||||||
|
Firstly, you can retrieve a reference to the panel given it's id and then you can
|
||||||
|
pass that reference into `removePanel` to remove the panel.
|
||||||
|
|
||||||
|
```ts
|
||||||
|
const panel: IDockviewPanel = api.getPanel('myPanel');
|
||||||
|
api.removePanel(panel);
|
||||||
|
```
|
132
packages/docs/docs/core/panels/rendering.mdx
Normal file
132
packages/docs/docs/core/panels/rendering.mdx
Normal file
@ -0,0 +1,132 @@
|
|||||||
|
---
|
||||||
|
title: Rendering Panels
|
||||||
|
sidebar_postiion: 5
|
||||||
|
---
|
||||||
|
|
||||||
|
import { MultiFrameworkContainer } from '@site/src/components/ui/container';
|
||||||
|
import RenderingDockview from '@site/sandboxes/rendering-dockview/src/app';
|
||||||
|
|
||||||
|
import LiveExample from '@site/src/components/ui/exampleFrame';
|
||||||
|
|
||||||
|
|
||||||
|
Rendering type is an important consideration when creating your application and whether your panels should be destroyed when hidden.
|
||||||
|
|
||||||
|
:::info
|
||||||
|
If you are looking for information on how to render **iframes** in Dockview please go the the [iframes](/docs/advanced/iframe) section.
|
||||||
|
:::
|
||||||
|
|
||||||
|
When a panel is selected all other panels in that group are not visible. The API does expose methods to determine whether your panel is visible or not
|
||||||
|
and the panel instance only ever destroyed when removed however the question still remains, what to do with the partial DOM tree that makes up your panel and there are two options the dock can take:
|
||||||
|
|
||||||
|
1. (*onlyWhenVisible*) Remove the element from the DOM tree to make space for the new panel.
|
||||||
|
|
||||||
|
This will cause the element to loss any DOM-specific state such as scrollbar position and if you measure the size of any elements during this time you will mostly like see both a width and height of 0px,
|
||||||
|
this is also true for any active ResizeObservers.
|
||||||
|
|
||||||
|
```ts
|
||||||
|
api.addPanel({
|
||||||
|
id: 'my_unique_panel_id',
|
||||||
|
component: 'my_component',
|
||||||
|
renderer: 'always'
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
2. (*always*) Keep the DOM tree alive but hide it in order to allow the select panels content to show.
|
||||||
|
|
||||||
|
This approach will maintain any DOM-sepcific state you had and is essential if you require the native scrollbar position to be preserved.
|
||||||
|
|
||||||
|
```ts
|
||||||
|
api.addPanel({
|
||||||
|
id: 'my_unique_panel_id',
|
||||||
|
component: 'my_component',
|
||||||
|
renderer: 'onlyWhenVisible'
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
Both are valid use-cases therefore the dock allows you to choose your rendering mode, the default however is the first option since this is the most memory efficient solution.
|
||||||
|
|
||||||
|
> You can change the `defaultRenderer` in the Dock [Options](/docs/api/dockview/options).
|
||||||
|
|
||||||
|
:::info
|
||||||
|
The panel instance is only ever destroyed when it is removed from the dock allowing you to still run code associated with the panel when it is not visible.
|
||||||
|
The renderer only affects what happens to the DOM element.
|
||||||
|
:::
|
||||||
|
|
||||||
|
## Choose a Render Mode
|
||||||
|
|
||||||
|
```ts
|
||||||
|
api.addPanel({
|
||||||
|
id: 'my_unique_panel_id',
|
||||||
|
component: 'my_component',
|
||||||
|
renderer: 'always'
|
||||||
|
});
|
||||||
|
|
||||||
|
api.addPanel({
|
||||||
|
id: 'my_unique_panel_id',
|
||||||
|
component: 'my_component',
|
||||||
|
renderer: 'onlyWhenVisible'
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
## Live Example
|
||||||
|
|
||||||
|
<LiveExample framework="react" id="dockview/render-mode"/>
|
||||||
|
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
|
> 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.
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
|
```tsx title="Only rendering the React Component when the panel is visible, otherwise rendering a null React Component"
|
||||||
|
import { IDockviewPanelProps } from 'dockview';
|
||||||
|
import * as React from 'react';
|
||||||
|
|
||||||
|
function RenderWhenVisible(
|
||||||
|
component: React.FunctionComponent<IDockviewPanelProps>
|
||||||
|
) {
|
||||||
|
const HigherOrderComponent = (props: IDockviewPanelProps) => {
|
||||||
|
const [visible, setVisible] = React.useState<boolean>(
|
||||||
|
props.api.isVisible
|
||||||
|
);
|
||||||
|
|
||||||
|
React.useEffect(() => {
|
||||||
|
const disposable = props.api.onDidVisibilityChange((event) =>
|
||||||
|
setVisible(event.isVisible)
|
||||||
|
);
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
disposable.dispose();
|
||||||
|
};
|
||||||
|
}, [props.api]);
|
||||||
|
|
||||||
|
if (!visible) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return React.createElement(component, props);
|
||||||
|
};
|
||||||
|
return HigherOrderComponent;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
```tsx
|
||||||
|
const 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.
|
||||||
|
|
||||||
|
|
||||||
|
<MultiFrameworkContainer
|
||||||
|
sandboxId="rendering-dockview"
|
||||||
|
react={RenderingDockview}
|
||||||
|
/>
|
40
packages/docs/docs/core/panels/resizing.mdx
Normal file
40
packages/docs/docs/core/panels/resizing.mdx
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
---
|
||||||
|
title: Resizing
|
||||||
|
---
|
||||||
|
|
||||||
|
This section describes how to programatically resize a panel.
|
||||||
|
|
||||||
|
import LiveExample from '@site/src/components/ui/exampleFrame';
|
||||||
|
import { DocRef } from '@site/src/components/ui/reference/docRef';
|
||||||
|
|
||||||
|
<DocRef declaration="DockviewPanelApi" methods={['height', 'width', 'setSize', 'onDidDimensionsChange']} />
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## Panel Resizing
|
||||||
|
|
||||||
|
Each dock contains groups and each group contains panels.
|
||||||
|
Logically a user may want to resize a panel but this really translates to resizing the group which contains that panel.
|
||||||
|
|
||||||
|
The panel resize methods are repeats of the same resize methods found on the group.
|
||||||
|
|
||||||
|
```tsx
|
||||||
|
// it's mandatory to provide either a height or a width, providing both is optional
|
||||||
|
props.api.setSize({
|
||||||
|
height: 100,
|
||||||
|
width: 200,
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* you could also resize the panels group, although not recommended due to the
|
||||||
|
* clunky syntax it does achieve the same result
|
||||||
|
*/
|
||||||
|
props.api.group.api.setSize({
|
||||||
|
height: 100,
|
||||||
|
width: 200,
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
You can see an example invoking both approaches below.
|
||||||
|
|
||||||
|
<LiveExample framework="react" id="dockview/resize"/>
|
140
packages/docs/docs/core/panels/tabs.mdx
Normal file
140
packages/docs/docs/core/panels/tabs.mdx
Normal file
@ -0,0 +1,140 @@
|
|||||||
|
---
|
||||||
|
title: Tabs
|
||||||
|
sidebar_position: 2
|
||||||
|
---
|
||||||
|
|
||||||
|
import { MultiFrameworkContainer } from '@site/src/components/ui/container';
|
||||||
|
import CustomHeadersDockview from '@site/sandboxes/customheader-dockview/src/app';
|
||||||
|
import DockviewNative from '@site/sandboxes/fullwidthtab-dockview/src/app';
|
||||||
|
import { attach as attachNativeDockview } from '@site/sandboxes/javascript/fullwidthtab-dockview/src/app';
|
||||||
|
import { DocRef } from '@site/src/components/ui/reference/docRef';
|
||||||
|
|
||||||
|
This section describes how to implement custom tab renderers
|
||||||
|
|
||||||
|
## Register a Tab Component
|
||||||
|
|
||||||
|
<FrameworkSpecific framework='React'>
|
||||||
|
```tsx
|
||||||
|
const components = {
|
||||||
|
tab_1: (props: IDockviewPanelHeaderProps) => {
|
||||||
|
const api: DockviewPanelApi = props.api;
|
||||||
|
const containerApi: DockviewApi = props.containerApi;
|
||||||
|
|
||||||
|
return <div>{/** logic */}</div>
|
||||||
|
},
|
||||||
|
tab_2: (props: IDockviewPanelHeaderProps) => {
|
||||||
|
return <div>{/** logic */}</div>
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return <DockviewReact tabComponents={tabComponents}/>
|
||||||
|
```
|
||||||
|
</FrameworkSpecific>
|
||||||
|
|
||||||
|
<FrameworkSpecific framework='JavaScript'>
|
||||||
|
not implemented
|
||||||
|
</FrameworkSpecific>
|
||||||
|
|
||||||
|
|
||||||
|
## Default Tab Renderer
|
||||||
|
|
||||||
|
<FrameworkSpecific framework='React'>
|
||||||
|
```jsx
|
||||||
|
const CustomTabRenderer = (props: IDockviewPanelHeaderProps) => {
|
||||||
|
const api: DockviewPanelApi = props.api;
|
||||||
|
const containerApi: DockviewApi = props.containerApi;
|
||||||
|
|
||||||
|
return <div>{/** logic */}</div>
|
||||||
|
}
|
||||||
|
|
||||||
|
return <DockviewReact defaultTabRenderer={CustomTabRenderer}/>
|
||||||
|
```
|
||||||
|
</FrameworkSpecific>
|
||||||
|
|
||||||
|
<FrameworkSpecific framework='JavaScript'>
|
||||||
|
not implemented
|
||||||
|
</FrameworkSpecific>
|
||||||
|
|
||||||
|
## Accessing Custom Panel Parameters
|
||||||
|
|
||||||
|
You can provide a generic type that matches the structure of the epxected custom panels parameters
|
||||||
|
to provide type-hints for the panel parameters which can be accessed via the `params` option.
|
||||||
|
|
||||||
|
<FrameworkSpecific framework='React'>
|
||||||
|
```jsx
|
||||||
|
type MyParameters = { my_value: number };
|
||||||
|
|
||||||
|
const MyTab = (props: IDockviewPanelHeaderProps<MyParameters>) => {
|
||||||
|
const value: number = props.params.my_value;
|
||||||
|
return <div>{/** logic */}</div>
|
||||||
|
}
|
||||||
|
```
|
||||||
|
</FrameworkSpecific>
|
||||||
|
|
||||||
|
|
||||||
|
## Extend the Default Tab Implementation
|
||||||
|
|
||||||
|
If you only want to make minor changes to the tab rendering you may be able to use the
|
||||||
|
default implementation as a base. This could include:
|
||||||
|
- Hiding the close button
|
||||||
|
- Attaching additional event listeners
|
||||||
|
|
||||||
|
|
||||||
|
<FrameworkSpecific framework='React'>
|
||||||
|
```tsx
|
||||||
|
import { IDockviewPanelHeaderProps, DockviewDefaultTab } from 'dockview';
|
||||||
|
|
||||||
|
const MyCustomTab = (props: IDockviewPanelHeaderProps) => {
|
||||||
|
const onContextMenu = (event: React.MouseEvent) => {
|
||||||
|
event.preventDefault();
|
||||||
|
alert('context menu');
|
||||||
|
};
|
||||||
|
return <DockviewDefaultTab onContextMenu={onContextMenu} hideClose={true} {...props} />;
|
||||||
|
};
|
||||||
|
```
|
||||||
|
</FrameworkSpecific>
|
||||||
|
|
||||||
|
As a simple example the below attaches a custom event handler for the context menu on all tabs as a default tab renderer
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
|
<MultiFrameworkContainer
|
||||||
|
sandboxId="customheader-dockview"
|
||||||
|
react={CustomHeadersDockview}
|
||||||
|
/>
|
||||||
|
|
||||||
|
## Full Width Tab
|
||||||
|
|
||||||
|
When a group has only one single tab you may want that tab to take the full width.
|
||||||
|
|
||||||
|
<FrameworkSpecific framework='React'>
|
||||||
|
<DocRef declaration="IDockviewReactProps" methods={['singleTabMode']} />
|
||||||
|
</FrameworkSpecific>
|
||||||
|
|
||||||
|
<FrameworkSpecific framework='JavaScript'>
|
||||||
|
<DocRef declaration="DockviewComponentOptions" methods={['singleTabMode']} />
|
||||||
|
</FrameworkSpecific>
|
||||||
|
|
||||||
|
```tsx
|
||||||
|
return <DockviewReactComponent singleTabMode="fullwidth" />
|
||||||
|
```
|
||||||
|
|
||||||
|
<MultiFrameworkContainer
|
||||||
|
sandboxId="fullwidthtab-dockview"
|
||||||
|
react={DockviewNative}
|
||||||
|
typescript={attachNativeDockview}
|
||||||
|
/>
|
||||||
|
|
||||||
|
import DockviewTabheight from '@site/sandboxes/tabheight-dockview/src/app';
|
||||||
|
import { attach as attachTabHeightDockview } from '@site/sandboxes/javascript/tabheight-dockview/src/app';
|
||||||
|
|
||||||
|
## Tab Height
|
||||||
|
|
||||||
|
Tab height can be controlled through CSS.
|
||||||
|
|
||||||
|
<MultiFrameworkContainer
|
||||||
|
sandboxId="tabheight-dockview"
|
||||||
|
react={DockviewTabheight}
|
||||||
|
typescript={attachTabHeightDockview}
|
||||||
|
/>
|
46
packages/docs/docs/core/panels/update.mdx
Normal file
46
packages/docs/docs/core/panels/update.mdx
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
---
|
||||||
|
title: Update Panel
|
||||||
|
sidebar_position: 2
|
||||||
|
---
|
||||||
|
|
||||||
|
import { DocRef } from '@site/src/components/ui/reference/docRef';
|
||||||
|
import LiveExample from '@site/src/components/ui/exampleFrame';
|
||||||
|
|
||||||
|
This section describes how to update the parameters of a panel.
|
||||||
|
|
||||||
|
:::warning
|
||||||
|
**Use this feature sparingly**: Anything you assign to the `params` options of a panel will be saved when calling `api.toJSON()`.
|
||||||
|
Only use this to store small amounts of static view data.
|
||||||
|
**Do not** use this to store application state or dynamic panel state.
|
||||||
|
:::
|
||||||
|
|
||||||
|
## Methods
|
||||||
|
|
||||||
|
<DocRef declaration="DockviewPanelApi" methods={['updateParameters']} />
|
||||||
|
|
||||||
|
## Updating parameters
|
||||||
|
|
||||||
|
:::info
|
||||||
|
If you want to set initial parameters when adding a panel see the [Add Panel](/docs/core/panels/add) section.
|
||||||
|
:::
|
||||||
|
|
||||||
|
You can update a panel through the [Panel API](/docs/api/dockview/panelApi).
|
||||||
|
|
||||||
|
```ts
|
||||||
|
panel.api.updateParameters({
|
||||||
|
keyA: 'anotherValueA',
|
||||||
|
keyB: 'valueB',
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
To delete a parameter you should pass a value of `undefined`.
|
||||||
|
|
||||||
|
```ts
|
||||||
|
panel.api.updateParameters({
|
||||||
|
keyA: undefined,
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
## Live Example
|
||||||
|
|
||||||
|
<LiveExample framework="react" id="dockview/update-parameters"/>
|
20
packages/docs/docs/core/scrollbars.mdx
Normal file
20
packages/docs/docs/core/scrollbars.mdx
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
---
|
||||||
|
title: Scrolling
|
||||||
|
---
|
||||||
|
|
||||||
|
import LiveExample from '@site/src/components/ui/exampleFrame';
|
||||||
|
|
||||||
|
It's important to understand how to configure the scrollbar within a panel.
|
||||||
|
|
||||||
|
A panel will appear with a scrollbar if the the contents of your view has a fixed height.
|
||||||
|
If you are using a relative height such as `100%` you will need a child container
|
||||||
|
with the appropiate `overflow` value to allow for scrollbars.
|
||||||
|
|
||||||
|
## Live Examples
|
||||||
|
|
||||||
|
The following example contains three views:
|
||||||
|
- **Panel 1** (`height: 100%`): No scrollbar appears and the content is clipped.
|
||||||
|
- **Panel 2** (`height: 2000px`): A scrollbar does appear since a fixed height has been used.
|
||||||
|
- **Panel 3**: `height: 100%` and a child component with `overflow: auto` which will enable scrollbars.
|
||||||
|
|
||||||
|
<LiveExample framework="react" id="dockview/scrollbars"/>
|
6
packages/docs/docs/core/state/_category_.json
Normal file
6
packages/docs/docs/core/state/_category_.json
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
{
|
||||||
|
"position": 3,
|
||||||
|
"label": "State",
|
||||||
|
"collapsible": true,
|
||||||
|
"collapsed": true
|
||||||
|
}
|
47
packages/docs/docs/core/state/load.mdx
Normal file
47
packages/docs/docs/core/state/load.mdx
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
---
|
||||||
|
title: Loading State
|
||||||
|
---
|
||||||
|
|
||||||
|
import { MultiFrameworkContainer } from '@site/src/components/ui/container';
|
||||||
|
import LiveExample from '@site/src/components/ui/exampleFrame';
|
||||||
|
import { DocRef } from '@site/src/components/ui/reference/docRef';
|
||||||
|
|
||||||
|
This section described loading a dock layout.
|
||||||
|
|
||||||
|
<DocRef declaration="DockviewApi" methods={['fromJSON', 'onDidLayoutFromJSON']} />
|
||||||
|
|
||||||
|
## Load A Layout
|
||||||
|
|
||||||
|
To load a layout you should a pass a valid object to `fromJSON`. If you try to load an invalid or corrupted layout the dock will throw an Error and the dock will reset gracefully ready
|
||||||
|
for another attempt with a valid object.
|
||||||
|
|
||||||
|
You could load a previously saved layout from local storage for example.
|
||||||
|
|
||||||
|
```tsx
|
||||||
|
const onReady = (event: DockviewReadyEvent) => {
|
||||||
|
let success = false;
|
||||||
|
|
||||||
|
const mySerializedLayout = localStorage.getItem('my_layout');
|
||||||
|
|
||||||
|
if (mySerializedLayout) {
|
||||||
|
try {
|
||||||
|
const layout = JSON.parse(mySerializedLayout);
|
||||||
|
event.api.fromJSON(layout);
|
||||||
|
success = true;
|
||||||
|
} catch (err) {
|
||||||
|
// log the error
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!success) {
|
||||||
|
// perhap load a default layout?
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return <DockviewComponent onReady={onReady}/>;
|
||||||
|
```
|
||||||
|
|
||||||
|
# Live Example
|
||||||
|
|
||||||
|
<LiveExample framework="react" id="dockview/layout"/>
|
||||||
|
|
43
packages/docs/docs/core/state/save.mdx
Normal file
43
packages/docs/docs/core/state/save.mdx
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
---
|
||||||
|
title: Saving State
|
||||||
|
---
|
||||||
|
|
||||||
|
|
||||||
|
import { MultiFrameworkContainer } from '@site/src/components/ui/container';
|
||||||
|
import LiveExample from '@site/src/components/ui/exampleFrame';
|
||||||
|
import { DocRef } from '@site/src/components/ui/reference/docRef';
|
||||||
|
|
||||||
|
This section describes how to serialize a dockview instance.
|
||||||
|
|
||||||
|
<DocRef declaration="DockviewApi" methods={['toJSON', 'onDidLayoutChange']} />
|
||||||
|
|
||||||
|
To retrieve the current state of the dock call `toJSON()`.
|
||||||
|
You can listen to the event `onDidlayoutChange` to determine when the layout has changed.
|
||||||
|
|
||||||
|
```tsx
|
||||||
|
const [api, setApi] = React.useState<DockviewApi>();
|
||||||
|
|
||||||
|
React.useEffect(() => {
|
||||||
|
if(!api) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const disposable = api.onDidLayoutChange(() => {
|
||||||
|
const layout: SerializedDockview = api.toJSON();
|
||||||
|
localStorage.setItem('my_layout', JSON.stringify(layout));
|
||||||
|
});
|
||||||
|
|
||||||
|
return () => disposable.dispose();
|
||||||
|
}, [api]);
|
||||||
|
|
||||||
|
const onReady = (event: DockviewReadyEvent) => {
|
||||||
|
setApi(event.api);
|
||||||
|
}
|
||||||
|
|
||||||
|
return <DockviewComponent onReady={onReady}/>
|
||||||
|
```
|
||||||
|
|
||||||
|
# Live Example
|
||||||
|
|
||||||
|
<LiveExample framework="react" id="dockview/layout"/>
|
||||||
|
|
31
packages/docs/docs/core/watermark.mdx
Normal file
31
packages/docs/docs/core/watermark.mdx
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
---
|
||||||
|
title: Watermark
|
||||||
|
---
|
||||||
|
|
||||||
|
import useBaseUrl from '@docusaurus/useBaseUrl';
|
||||||
|
|
||||||
|
import { DocRef } from '@site/src/components/ui/reference/docRef';
|
||||||
|
import LiveExample from '@site/src/components/ui/exampleFrame';
|
||||||
|
|
||||||
|
When there is nothing else to display.
|
||||||
|
|
||||||
|
When the dock is empty or a group has no panels (an empty group) you can render some fallback
|
||||||
|
content which is refered to as a `watermark`. Both are controlled through the same provided component.
|
||||||
|
|
||||||
|
## Options
|
||||||
|
|
||||||
|
The following properties can be set to configure the behaviours of floating groups.
|
||||||
|
|
||||||
|
<FrameworkSpecific framework='React'>
|
||||||
|
<DocRef declaration="IDockviewReactProps" methods={['watermarkComponent']} />
|
||||||
|
</FrameworkSpecific>
|
||||||
|
|
||||||
|
<FrameworkSpecific framework='JavaScript'>
|
||||||
|
<DocRef declaration="DockviewComponentOptions"
|
||||||
|
methods={['watermarkComponent', 'watermarkFrameworkComponent', 'frameworkComponentFactory']}
|
||||||
|
/>
|
||||||
|
</FrameworkSpecific>
|
||||||
|
|
||||||
|
## Live Examples
|
||||||
|
|
||||||
|
<LiveExample framework="react" id="dockview/watermark"/>
|
@ -1,6 +1,7 @@
|
|||||||
---
|
---
|
||||||
sidebar_position: 0
|
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
|
||||||
|
title: Introduction
|
||||||
---
|
---
|
||||||
|
|
||||||
import { MultiFrameworkContainer } from '@site/src/components/ui/container';
|
import { MultiFrameworkContainer } from '@site/src/components/ui/container';
|
||||||
@ -8,11 +9,9 @@ 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 DockviewDemo from '@site/sandboxes/demo-dockview/src/app';
|
// import DockviewDemo from '@site/sandboxes/demo-dockview/src/app';
|
||||||
import Link from '@docusaurus/Link';
|
import Link from '@docusaurus/Link';
|
||||||
|
|
||||||
# Introduction
|
|
||||||
|
|
||||||
**dockview** is a zero dependency layout manager that supports tab, grids and splitviews.
|
**dockview** is a zero dependency layout manager that supports tab, grids and splitviews.
|
||||||
|
|
||||||
## Quick start
|
## Quick start
|
||||||
@ -36,11 +35,11 @@ There are 4 components you may want to use:
|
|||||||
<h2>Dockview</h2>
|
<h2>Dockview</h2>
|
||||||
</Link>
|
</Link>
|
||||||
|
|
||||||
<MultiFrameworkContainer
|
{/* <MultiFrameworkContainer
|
||||||
height={500}
|
height={500}
|
||||||
sandboxId="demo-dockview"
|
sandboxId="demo-dockview"
|
||||||
react={DockviewDemo}
|
react={DockviewDemo}
|
||||||
/>
|
/> */}
|
||||||
|
|
||||||
<Link to="./components/splitview">
|
<Link to="./components/splitview">
|
||||||
<h2>Splitview</h2>
|
<h2>Splitview</h2>
|
||||||
|
6
packages/docs/docs/overview/getStarted/_category_.json
Normal file
6
packages/docs/docs/overview/getStarted/_category_.json
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
{
|
||||||
|
"position": 0,
|
||||||
|
"label": "Get Started",
|
||||||
|
"collapsible": true,
|
||||||
|
"collapsed": true
|
||||||
|
}
|
@ -1,11 +1,10 @@
|
|||||||
---
|
---
|
||||||
sidebar_position: 3
|
sidebar_position: 2
|
||||||
description: Contributing
|
description: Contributing
|
||||||
|
title: Contributing
|
||||||
---
|
---
|
||||||
|
|
||||||
# Contributing
|
## Project description
|
||||||
|
|
||||||
# Project description
|
|
||||||
|
|
||||||
Pre-requisites: Node >=18, Yarn
|
Pre-requisites: Node >=18, Yarn
|
||||||
|
|
23
packages/docs/docs/overview/getStarted/installation.mdx
Normal file
23
packages/docs/docs/overview/getStarted/installation.mdx
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
---
|
||||||
|
id: installation
|
||||||
|
title: Installation
|
||||||
|
sidebar_position: 0
|
||||||
|
---
|
||||||
|
|
||||||
|
Learn how to install Dockview for a selection of frameworks.
|
||||||
|
|
||||||
|
<FrameworkSpecific framework='JavaScript'>
|
||||||
|
Firstly, install the `dockvire-core` library:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
npm install dockview-core
|
||||||
|
```
|
||||||
|
</FrameworkSpecific>
|
||||||
|
|
||||||
|
<FrameworkSpecific framework='React'>
|
||||||
|
Firstly, install the `dockview` library:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
npm install dockview
|
||||||
|
```
|
||||||
|
</FrameworkSpecific>
|
69
packages/docs/docs/overview/getStarted/theme.mdx
Normal file
69
packages/docs/docs/overview/getStarted/theme.mdx
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
---
|
||||||
|
sidebar_position: 1
|
||||||
|
description: Theming Dockview Components
|
||||||
|
title: Theme
|
||||||
|
---
|
||||||
|
|
||||||
|
|
||||||
|
import { CSSVariablesTable, ThemeTable } from '@site/src/components/cssVariables';
|
||||||
|
|
||||||
|
Theming is controlled through CSS and is highly customizable.
|
||||||
|
|
||||||
|
Firstly, you should import `dockview.css`:
|
||||||
|
|
||||||
|
<FrameworkSpecific framework='JavaScript'>
|
||||||
|
```css
|
||||||
|
@import './node_modules/dockview-core/dist/styles/dockview.css';
|
||||||
|
```
|
||||||
|
</FrameworkSpecific>
|
||||||
|
|
||||||
|
<FrameworkSpecific framework='React'>
|
||||||
|
```css
|
||||||
|
@import './node_modules/dockview/dist/styles/dockview.css';
|
||||||
|
```
|
||||||
|
</FrameworkSpecific>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## Provided themes
|
||||||
|
|
||||||
|
`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:
|
||||||
|
|
||||||
|
<ThemeTable/>
|
||||||
|
|
||||||
|
:::info
|
||||||
|
The source code for all themes can be found [here](https://github.com/mathuo/dockview/blob/master/packages/dockview-core/src/theme.scss).
|
||||||
|
:::
|
||||||
|
|
||||||
|
## Customizing Theme
|
||||||
|
|
||||||
|
The provided themes are controlled primarily through a long list of CSS variables which can be modified by the user either entirely for a new theme
|
||||||
|
or partial for a modification to an existing theme.
|
||||||
|
|
||||||
|
<CSSVariablesTable />
|
||||||
|
|
||||||
|
## Extending Theme
|
||||||
|
|
||||||
|
You can extends existing themes or create new themes.
|
||||||
|
|
||||||
|
As an example if you wanted to extend the **dockview-theme-abyss** theme to dislay a within the tabs container you
|
||||||
|
may try:
|
||||||
|
|
||||||
|
|
||||||
|
```css
|
||||||
|
.dockview-theme-abyss {
|
||||||
|
.groupview {
|
||||||
|
&.active-group {
|
||||||
|
> .tabs-and-actions-container {
|
||||||
|
border-bottom: 2px solid var(--dv-activegroup-visiblepanel-tab-background-color);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
&.inactive-group {
|
||||||
|
> .tabs-and-actions-container {
|
||||||
|
border-bottom: 2px solid var(--dv-inactivegroup-visiblepanel-tab-background-color);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
@ -1,85 +0,0 @@
|
|||||||
---
|
|
||||||
sidebar_position: 1
|
|
||||||
description: Theming Dockview Components
|
|
||||||
---
|
|
||||||
|
|
||||||
# Theme
|
|
||||||
|
|
||||||
## Introduction
|
|
||||||
|
|
||||||
`dockview` requires some CSS to work correctly.
|
|
||||||
The CSS is exported as one file under [`dockview/dict/styles/dockview.css`](https://unpkg.com/browse/dockview@latest/dist/styles/dockview.css)
|
|
||||||
and should be imported at some point in your application
|
|
||||||
|
|
||||||
```css title="Example import with .css file"
|
|
||||||
@import './node_modules/dockview/dist/styles/dockview.css';
|
|
||||||
```
|
|
||||||
|
|
||||||
## Provided themes
|
|
||||||
|
|
||||||
`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-dark`
|
|
||||||
- `dockview-theme-light`
|
|
||||||
- `dockview-theme-vs`
|
|
||||||
- `dockview-theme-abyss`
|
|
||||||
- `dockview-theme-dracula`
|
|
||||||
- `dockview-theme-replit`
|
|
||||||
|
|
||||||
## Customizing Theme
|
|
||||||
|
|
||||||
`dockview` supports theming through the use of css properties.
|
|
||||||
You can view the built-in themes at [`dockview/src/theme.scss`](https://github.com/mathuo/dockview/blob/master/packages/dockview/src/theme.scss)
|
|
||||||
and are free to build your own themes based on these css properties.
|
|
||||||
|
|
||||||
| CSS Property | Description |
|
|
||||||
| ---------------------------------------------------- | ----------- |
|
|
||||||
| --dv-paneview-active-outline-color | |
|
|
||||||
| --dv-tabs-and-actions-container-font-size | |
|
|
||||||
| --dv-tabs-and-actions-container-height | |
|
|
||||||
| --dv-tab-close-icon | |
|
|
||||||
| --dv-drag-over-background-color | |
|
|
||||||
| --dv-drag-over-border-color | |
|
|
||||||
| --dv-tabs-container-scrollbar-color | |
|
|
||||||
| | |
|
|
||||||
| --dv-group-view-background-color | |
|
|
||||||
| | |
|
|
||||||
| --dv-tabs-and-actions-container-background-color | |
|
|
||||||
| | |
|
|
||||||
| --dv-activegroup-visiblepanel-tab-background-color | |
|
|
||||||
| --dv-activegroup-hiddenpanel-tab-background-color | |
|
|
||||||
| --dv-inactivegroup-visiblepanel-tab-background-color | |
|
|
||||||
| --dv-inactivegroup-hiddenpanel-tab-background-color | |
|
|
||||||
| --dv-tab-divider-color | |
|
|
||||||
| | |
|
|
||||||
| --dv-activegroup-visiblepanel-tab-color | |
|
|
||||||
| --dv-activegroup-hiddenpanel-tab-color | |
|
|
||||||
| --dv-inactivegroup-visiblepanel-tab-color | |
|
|
||||||
| --dv-inactivegroup-hiddenpanel-tab-color | |
|
|
||||||
| | |
|
|
||||||
| --dv-separator-border | |
|
|
||||||
| --dv-paneview-header-border-color | |
|
|
||||||
| | |
|
|
||||||
| --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.
|
|
||||||
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 title="Additional CSS to show a bottom border on active groups"
|
|
||||||
.groupview {
|
|
||||||
&.active-group {
|
|
||||||
> .tabs-and-actions-container {
|
|
||||||
border-bottom: 2px solid var(--dv-activegroup-visiblepanel-tab-background-color);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
&.inactive-group {
|
|
||||||
> .tabs-and-actions-container {
|
|
||||||
border-bottom: 2px solid var(--dv-inactivegroup-visiblepanel-tab-background-color);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
@ -3,7 +3,26 @@
|
|||||||
|
|
||||||
const { themes } = require('prism-react-renderer');
|
const { themes } = require('prism-react-renderer');
|
||||||
const lightCodeTheme = themes.nightOwlLight;
|
const lightCodeTheme = themes.nightOwlLight;
|
||||||
const darkCodeTheme = themes.vsDark;
|
const darkCodeTheme = themes.palenight;
|
||||||
|
|
||||||
|
// dracula
|
||||||
|
// duotoneDark
|
||||||
|
// duotoneLight
|
||||||
|
// github
|
||||||
|
// jettwaveDark
|
||||||
|
// jettwaveLight
|
||||||
|
// nightOwl
|
||||||
|
// nightOwlLight
|
||||||
|
// oceanicNext
|
||||||
|
// okaidia
|
||||||
|
// oneDark
|
||||||
|
// oneLight
|
||||||
|
// palenight
|
||||||
|
// shadesOfPurple
|
||||||
|
// synthwave84
|
||||||
|
// ultramin
|
||||||
|
// vsDark
|
||||||
|
// vsLight
|
||||||
|
|
||||||
const path = require('path');
|
const path = require('path');
|
||||||
|
|
||||||
@ -101,7 +120,7 @@ const config = {
|
|||||||
'https://github.com/facebook/docusaurus/tree/main/packages/create-docusaurus/templates/shared/',
|
'https://github.com/facebook/docusaurus/tree/main/packages/create-docusaurus/templates/shared/',
|
||||||
},
|
},
|
||||||
theme: {
|
theme: {
|
||||||
customCss: require.resolve('./src/css/custom.css'),
|
customCss: require.resolve('./src/css/custom.scss'),
|
||||||
},
|
},
|
||||||
gtag: process.env.CI
|
gtag: process.env.CI
|
||||||
? {
|
? {
|
||||||
@ -137,6 +156,11 @@ const config = {
|
|||||||
].join(' ,'),
|
].join(' ,'),
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
docs: {
|
||||||
|
sidebar: {
|
||||||
|
autoCollapseCategories: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
navbar: {
|
navbar: {
|
||||||
title: 'Dockview',
|
title: 'Dockview',
|
||||||
logo: {
|
logo: {
|
||||||
@ -146,24 +170,33 @@ const config = {
|
|||||||
items: [
|
items: [
|
||||||
{
|
{
|
||||||
type: 'doc',
|
type: 'doc',
|
||||||
docId: 'index',
|
docId: 'overview/getStarted/installation',
|
||||||
position: 'left',
|
position: 'left',
|
||||||
label: 'Docs',
|
label: 'Docs',
|
||||||
},
|
},
|
||||||
{ to: '/blog', label: 'Blog', position: 'left' },
|
|
||||||
{
|
{
|
||||||
to: 'https://dockview.dev/typedocs',
|
type: 'docSidebar',
|
||||||
label: 'TSDoc',
|
|
||||||
position: 'left',
|
position: 'left',
|
||||||
|
sidebarId: 'api',
|
||||||
|
label: 'API',
|
||||||
},
|
},
|
||||||
|
{ to: '/blog', label: 'Blog', position: 'left' },
|
||||||
|
{ to: '/demo', label: 'Demo', position: 'left' },
|
||||||
|
// {
|
||||||
|
// to: 'https://dockview.dev/typedocs',
|
||||||
|
// label: 'TSDoc',
|
||||||
|
// position: 'left',
|
||||||
|
// },
|
||||||
|
|
||||||
{
|
{
|
||||||
type: 'docsVersionDropdown',
|
type: 'docsVersionDropdown',
|
||||||
position: 'right',
|
position: 'right',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
href: 'https://github.com/mathuo/dockview',
|
href: 'https://github.com/mathuo/dockview',
|
||||||
label: 'GitHub',
|
|
||||||
position: 'right',
|
position: 'right',
|
||||||
|
className: 'header-github-link',
|
||||||
|
'aria-label': 'GitHub repository',
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
@ -227,6 +260,9 @@ const config = {
|
|||||||
id: 'announcementBar', // Increment on change
|
id: 'announcementBar', // Increment on change
|
||||||
content: `⭐️ If you like Dockview, give it a star on <a target="_blank" rel="noopener noreferrer" href="https://github.com/mathuo/dockview">GitHub</a>`,
|
content: `⭐️ If you like Dockview, give it a star on <a target="_blank" rel="noopener noreferrer" href="https://github.com/mathuo/dockview">GitHub</a>`,
|
||||||
},
|
},
|
||||||
|
tableOfContents: {
|
||||||
|
maxHeadingLevel: 5,
|
||||||
|
},
|
||||||
}),
|
}),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
20
packages/docs/locate.js
Normal file
20
packages/docs/locate.js
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
const fs = require('fs');
|
||||||
|
const path = require('path');
|
||||||
|
|
||||||
|
function* readAllFiles(dir) {
|
||||||
|
const files = fs.readdirSync(dir, { withFileTypes: true });
|
||||||
|
|
||||||
|
for (const file of files) {
|
||||||
|
if (file.isDirectory()) {
|
||||||
|
yield* readAllFiles(path.join(dir, file.name));
|
||||||
|
} else {
|
||||||
|
yield path.join(dir, file.name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log(
|
||||||
|
Array.from(
|
||||||
|
readAllFiles(path.join(__dirname, '..', 'dockview-core', 'src'))
|
||||||
|
).filter((file) => file.endsWith('.scss'))
|
||||||
|
);
|
@ -6,6 +6,7 @@
|
|||||||
"build": "docusaurus build",
|
"build": "docusaurus build",
|
||||||
"clear": "docusaurus clear",
|
"clear": "docusaurus clear",
|
||||||
"start": "docusaurus start",
|
"start": "docusaurus start",
|
||||||
|
"swizzle": "docusaurus swizzle @docusaurus/theme-classic",
|
||||||
"docs:version": "docusaurus docs:version",
|
"docs:version": "docusaurus docs:version",
|
||||||
"typecheck": "tsc"
|
"typecheck": "tsc"
|
||||||
},
|
},
|
||||||
@ -22,13 +23,15 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@docusaurus/core": "^3.0.1",
|
"@docusaurus/core": "^3.1.1",
|
||||||
"@docusaurus/module-type-aliases": "^3.0.1",
|
"@docusaurus/module-type-aliases": "^3.1.1",
|
||||||
"@docusaurus/preset-classic": "^3.0.1",
|
"@docusaurus/preset-classic": "^3.1.1",
|
||||||
"@mdx-js/react": "^3.0.0",
|
"@mdx-js/react": "^3.0.0",
|
||||||
"@minoru/react-dnd-treeview": "^3.4.4",
|
"@minoru/react-dnd-treeview": "^3.4.4",
|
||||||
"@radix-ui/react-icons": "^1.3.0",
|
"@radix-ui/react-icons": "^1.3.0",
|
||||||
"@radix-ui/react-popover": "^1.0.7",
|
"@radix-ui/react-popover": "^1.0.7",
|
||||||
|
"ag-grid-community": "^31.0.2",
|
||||||
|
"ag-grid-react": "^31.0.2",
|
||||||
"axios": "^1.6.3",
|
"axios": "^1.6.3",
|
||||||
"clsx": "^2.1.0",
|
"clsx": "^2.1.0",
|
||||||
"dockview": "^1.9.2",
|
"dockview": "^1.9.2",
|
||||||
|
@ -1,649 +0,0 @@
|
|||||||
import {
|
|
||||||
DockviewDefaultTab,
|
|
||||||
DockviewReact,
|
|
||||||
DockviewReadyEvent,
|
|
||||||
IDockviewPanelHeaderProps,
|
|
||||||
IDockviewPanelProps,
|
|
||||||
IDockviewHeaderActionsProps,
|
|
||||||
DockviewPanelApi,
|
|
||||||
DockviewPanelRenderer,
|
|
||||||
DockviewGroupLocation,
|
|
||||||
DockviewApi,
|
|
||||||
} from 'dockview';
|
|
||||||
import * as React from 'react';
|
|
||||||
import * as ReactDOM from 'react-dom';
|
|
||||||
import { v4 } from 'uuid';
|
|
||||||
import './app.scss';
|
|
||||||
|
|
||||||
interface PanelApiMetadata {
|
|
||||||
isActive: {
|
|
||||||
value: boolean;
|
|
||||||
count: number;
|
|
||||||
};
|
|
||||||
isVisible: {
|
|
||||||
value: boolean;
|
|
||||||
count: number;
|
|
||||||
};
|
|
||||||
isHidden: {
|
|
||||||
value: boolean;
|
|
||||||
count: number;
|
|
||||||
};
|
|
||||||
renderer: {
|
|
||||||
value: DockviewPanelRenderer;
|
|
||||||
count: number;
|
|
||||||
};
|
|
||||||
isGroupActive: {
|
|
||||||
value: boolean;
|
|
||||||
count: number;
|
|
||||||
};
|
|
||||||
groupChanged: {
|
|
||||||
count: number;
|
|
||||||
};
|
|
||||||
location: {
|
|
||||||
value: DockviewGroupLocation;
|
|
||||||
count: number;
|
|
||||||
};
|
|
||||||
didFocus: {
|
|
||||||
count: number;
|
|
||||||
};
|
|
||||||
dimensions: {
|
|
||||||
count: number;
|
|
||||||
height: number;
|
|
||||||
width: number;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
function usePanelApiMetadata(api: DockviewPanelApi): PanelApiMetadata {
|
|
||||||
const [state, setState] = React.useState<PanelApiMetadata>({
|
|
||||||
isActive: { value: api.isActive, count: 0 },
|
|
||||||
isVisible: { value: api.isVisible, count: 0 },
|
|
||||||
isHidden: { value: api.isHidden, count: 0 },
|
|
||||||
renderer: { value: api.renderer, count: 0 },
|
|
||||||
isGroupActive: { value: api.isGroupActive, count: 0 },
|
|
||||||
groupChanged: { count: 0 },
|
|
||||||
location: { value: api.location, count: 0 },
|
|
||||||
didFocus: { count: 0 },
|
|
||||||
dimensions: { count: 0, height: api.height, width: api.width },
|
|
||||||
});
|
|
||||||
|
|
||||||
React.useEffect(() => {
|
|
||||||
const d1 = api.onDidActiveChange((event) => {
|
|
||||||
setState((_) => ({
|
|
||||||
..._,
|
|
||||||
isActive: {
|
|
||||||
value: event.isActive,
|
|
||||||
count: _.isActive.count + 1,
|
|
||||||
},
|
|
||||||
}));
|
|
||||||
});
|
|
||||||
const d2 = api.onDidActiveGroupChange((event) => {
|
|
||||||
setState((_) => ({
|
|
||||||
..._,
|
|
||||||
isGroupActive: {
|
|
||||||
value: event.isActive,
|
|
||||||
count: _.isGroupActive.count + 1,
|
|
||||||
},
|
|
||||||
}));
|
|
||||||
});
|
|
||||||
const d3 = api.onDidDimensionsChange((event) => {
|
|
||||||
setState((_) => ({
|
|
||||||
..._,
|
|
||||||
dimensions: {
|
|
||||||
count: _.dimensions.count + 1,
|
|
||||||
height: event.height,
|
|
||||||
width: event.width,
|
|
||||||
},
|
|
||||||
}));
|
|
||||||
});
|
|
||||||
const d4 = api.onDidFocusChange((event) => {
|
|
||||||
setState((_) => ({
|
|
||||||
..._,
|
|
||||||
didFocus: {
|
|
||||||
count: _.didFocus.count + 1,
|
|
||||||
},
|
|
||||||
}));
|
|
||||||
});
|
|
||||||
const d5 = api.onDidGroupChange((event) => {
|
|
||||||
setState((_) => ({
|
|
||||||
..._,
|
|
||||||
groupChanged: {
|
|
||||||
count: _.groupChanged.count + 1,
|
|
||||||
},
|
|
||||||
}));
|
|
||||||
});
|
|
||||||
const d6 = api.onDidHiddenChange((event) => {
|
|
||||||
setState((_) => ({
|
|
||||||
..._,
|
|
||||||
isHidden: {
|
|
||||||
value: event.isHidden,
|
|
||||||
count: _.isHidden.count + 1,
|
|
||||||
},
|
|
||||||
}));
|
|
||||||
});
|
|
||||||
const d7 = api.onDidLocationChange((event) => {
|
|
||||||
setState((_) => ({
|
|
||||||
..._,
|
|
||||||
location: {
|
|
||||||
value: event.location,
|
|
||||||
count: _.location.count + 1,
|
|
||||||
},
|
|
||||||
}));
|
|
||||||
});
|
|
||||||
const d8 = api.onDidRendererChange((event) => {
|
|
||||||
setState((_) => ({
|
|
||||||
..._,
|
|
||||||
renderer: {
|
|
||||||
value: event.renderer,
|
|
||||||
count: _.renderer.count + 1,
|
|
||||||
},
|
|
||||||
}));
|
|
||||||
});
|
|
||||||
const d9 = api.onDidVisibilityChange((event) => {
|
|
||||||
setState((_) => ({
|
|
||||||
..._,
|
|
||||||
isVisible: {
|
|
||||||
value: event.isVisible,
|
|
||||||
count: _.isVisible.count + 1,
|
|
||||||
},
|
|
||||||
}));
|
|
||||||
});
|
|
||||||
|
|
||||||
return () => {
|
|
||||||
d1.dispose();
|
|
||||||
d2.dispose();
|
|
||||||
d3.dispose();
|
|
||||||
d4.dispose();
|
|
||||||
d5.dispose();
|
|
||||||
d6.dispose();
|
|
||||||
d7.dispose();
|
|
||||||
d8.dispose();
|
|
||||||
d9.dispose();
|
|
||||||
};
|
|
||||||
}, [api]);
|
|
||||||
|
|
||||||
return state;
|
|
||||||
}
|
|
||||||
|
|
||||||
const components = {
|
|
||||||
default: (props: IDockviewPanelProps) => {
|
|
||||||
const metadata = usePanelApiMetadata(props.api);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div
|
|
||||||
style={{
|
|
||||||
height: '100%',
|
|
||||||
overflow: 'auto',
|
|
||||||
color: 'white',
|
|
||||||
position: 'relative',
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<pre style={{ fontSize: '11px' }}>
|
|
||||||
{JSON.stringify(metadata, null, 4)}
|
|
||||||
</pre>
|
|
||||||
<span
|
|
||||||
style={{
|
|
||||||
position: 'absolute',
|
|
||||||
top: '50%',
|
|
||||||
left: '50%',
|
|
||||||
transform: 'translate(-50%,-50%)',
|
|
||||||
pointerEvents: 'none',
|
|
||||||
fontSize: '42px',
|
|
||||||
opacity: 0.5,
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{props.api.title}
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
const headerComponents = {
|
|
||||||
default: (props: IDockviewPanelHeaderProps) => {
|
|
||||||
const onContextMenu = (event: React.MouseEvent) => {
|
|
||||||
event.preventDefault();
|
|
||||||
alert('context menu');
|
|
||||||
};
|
|
||||||
return <DockviewDefaultTab onContextMenu={onContextMenu} {...props} />;
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
const Icon = (props: {
|
|
||||||
icon: string;
|
|
||||||
title?: string;
|
|
||||||
onClick?: (event: React.MouseEvent) => void;
|
|
||||||
}) => {
|
|
||||||
return (
|
|
||||||
<div title={props.title} className="action" onClick={props.onClick}>
|
|
||||||
<span
|
|
||||||
style={{ fontSize: 'inherit' }}
|
|
||||||
className="material-symbols-outlined"
|
|
||||||
>
|
|
||||||
{props.icon}
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
const groupControlsComponents: Record<string, React.FC> = {
|
|
||||||
panel_1: () => {
|
|
||||||
return <Icon icon="file_download" />;
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
const RightControls = (props: IDockviewHeaderActionsProps) => {
|
|
||||||
const Component = React.useMemo(() => {
|
|
||||||
if (!props.isGroupActive || !props.activePanel) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
return groupControlsComponents[props.activePanel.id];
|
|
||||||
}, [props.isGroupActive, props.activePanel]);
|
|
||||||
|
|
||||||
const [isMaximized, setIsMaximized] = React.useState<boolean>(
|
|
||||||
props.containerApi.hasMaximizedGroup()
|
|
||||||
);
|
|
||||||
|
|
||||||
const [isPopout, setIsPopout] = React.useState<boolean>(
|
|
||||||
props.api.location.type === 'popout'
|
|
||||||
);
|
|
||||||
|
|
||||||
React.useEffect(() => {
|
|
||||||
const disposable = props.containerApi.onDidMaximizedGroupChange(() => {
|
|
||||||
setIsMaximized(props.containerApi.hasMaximizedGroup());
|
|
||||||
});
|
|
||||||
|
|
||||||
const disposable2 = props.api.onDidLocationChange(() => {
|
|
||||||
setIsPopout(props.api.location.type === 'popout');
|
|
||||||
});
|
|
||||||
|
|
||||||
return () => {
|
|
||||||
disposable.dispose();
|
|
||||||
disposable2.dispose();
|
|
||||||
};
|
|
||||||
}, [props.containerApi]);
|
|
||||||
|
|
||||||
const onClick = () => {
|
|
||||||
if (props.containerApi.hasMaximizedGroup()) {
|
|
||||||
props.containerApi.exitMaximizedGroup();
|
|
||||||
} else {
|
|
||||||
props.activePanel?.api.maximize();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const onClick2 = () => {
|
|
||||||
if (props.api.location !== 'popout') {
|
|
||||||
props.containerApi.addPopoutGroup(props.group);
|
|
||||||
} else {
|
|
||||||
props.api.moveTo({ position: 'right' });
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div
|
|
||||||
className="group-control"
|
|
||||||
style={{
|
|
||||||
display: 'flex',
|
|
||||||
alignItems: 'center',
|
|
||||||
padding: '0px 8px',
|
|
||||||
height: '100%',
|
|
||||||
color: 'var(--dv-activegroup-visiblepanel-tab-color)',
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{props.isGroupActive && <Icon icon="star" />}
|
|
||||||
{Component && <Component />}
|
|
||||||
<Icon
|
|
||||||
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>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
let counter = 0;
|
|
||||||
|
|
||||||
const LeftControls = (props: IDockviewHeaderActionsProps) => {
|
|
||||||
const onClick = () => {
|
|
||||||
props.containerApi.addPanel({
|
|
||||||
id: `id_${Date.now().toString()}`,
|
|
||||||
component: 'default',
|
|
||||||
title: `Tab ${counter++}`,
|
|
||||||
position: {
|
|
||||||
referenceGroup: props.group,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div
|
|
||||||
className="group-control"
|
|
||||||
style={{
|
|
||||||
display: 'flex',
|
|
||||||
alignItems: 'center',
|
|
||||||
padding: '0px 8px',
|
|
||||||
height: '100%',
|
|
||||||
color: 'var(--dv-activegroup-visiblepanel-tab-color)',
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<Icon onClick={onClick} icon="add" />
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
const PrefixHeaderControls = (props: IDockviewHeaderActionsProps) => {
|
|
||||||
return (
|
|
||||||
<div
|
|
||||||
className="group-control"
|
|
||||||
style={{
|
|
||||||
display: 'flex',
|
|
||||||
alignItems: 'center',
|
|
||||||
padding: '0px 8px',
|
|
||||||
height: '100%',
|
|
||||||
color: 'var(--dv-activegroup-visiblepanel-tab-color)',
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<Icon icon="Menu" />
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
const DockviewDemo = (props: { theme?: string }) => {
|
|
||||||
const [logLines, setLogLines] = React.useState<any[]>([]);
|
|
||||||
|
|
||||||
const [panels, setPanels] = React.useState<string[]>([]);
|
|
||||||
const [groups, setGroups] = React.useState<string[]>([]);
|
|
||||||
const [api, setApi] = React.useState<DockviewApi>();
|
|
||||||
|
|
||||||
const [activePanel, setActivePanel] = React.useState<string>();
|
|
||||||
const [activeGroup, setActiveGroup] = React.useState<string>();
|
|
||||||
|
|
||||||
const onReady = (event: DockviewReadyEvent) => {
|
|
||||||
setApi(event.api);
|
|
||||||
|
|
||||||
event.api.onDidAddPanel((event) => {
|
|
||||||
setPanels((_) => [..._, event.id]);
|
|
||||||
setLogLines((line) => [`Panel Added ${event.id}`, ...line]);
|
|
||||||
});
|
|
||||||
event.api.onDidActivePanelChange((event) => {
|
|
||||||
setActivePanel(event?.id);
|
|
||||||
setLogLines((line) => [`Panel Activated ${event?.id}`, ...line]);
|
|
||||||
});
|
|
||||||
event.api.onDidRemovePanel((event) => {
|
|
||||||
setPanels((_) => {
|
|
||||||
const next = [..._];
|
|
||||||
next.splice(
|
|
||||||
next.findIndex((x) => x === event.id),
|
|
||||||
1
|
|
||||||
);
|
|
||||||
|
|
||||||
return next;
|
|
||||||
});
|
|
||||||
setLogLines((line) => [`Panel Removed ${event.id}`, ...line]);
|
|
||||||
});
|
|
||||||
|
|
||||||
event.api.onDidAddGroup((event) => {
|
|
||||||
setGroups((_) => [..._, event.id]);
|
|
||||||
setLogLines((line) => [`Group Added ${event.id}`, ...line]);
|
|
||||||
});
|
|
||||||
|
|
||||||
event.api.onDidRemoveGroup((event) => {
|
|
||||||
setGroups((_) => {
|
|
||||||
const next = [..._];
|
|
||||||
next.splice(
|
|
||||||
next.findIndex((x) => x === event.id),
|
|
||||||
1
|
|
||||||
);
|
|
||||||
|
|
||||||
return next;
|
|
||||||
});
|
|
||||||
setLogLines((line) => [`Group Removed ${event.id}`, ...line]);
|
|
||||||
});
|
|
||||||
|
|
||||||
event.api.onDidActiveGroupChange((event) => {
|
|
||||||
setActiveGroup(event?.id);
|
|
||||||
setLogLines((line) => [`Group Activated ${event?.id}`, ...line]);
|
|
||||||
});
|
|
||||||
|
|
||||||
const panel1 = event.api.addPanel({
|
|
||||||
id: 'panel_1',
|
|
||||||
component: 'default',
|
|
||||||
title: 'Panel 1',
|
|
||||||
});
|
|
||||||
|
|
||||||
event.api.addPanel({
|
|
||||||
id: 'panel_2',
|
|
||||||
component: 'default',
|
|
||||||
title: 'Panel 2',
|
|
||||||
position: { referencePanel: panel1 },
|
|
||||||
});
|
|
||||||
|
|
||||||
event.api.addPanel({
|
|
||||||
id: 'panel_3',
|
|
||||||
component: 'default',
|
|
||||||
title: 'Panel 3',
|
|
||||||
position: { referencePanel: panel1 },
|
|
||||||
});
|
|
||||||
|
|
||||||
const panel4 = event.api.addPanel({
|
|
||||||
id: 'panel_4',
|
|
||||||
component: 'default',
|
|
||||||
title: 'Panel 4',
|
|
||||||
position: { referencePanel: panel1, direction: 'right' },
|
|
||||||
});
|
|
||||||
|
|
||||||
const panel5 = event.api.addPanel({
|
|
||||||
id: 'panel_5',
|
|
||||||
component: 'default',
|
|
||||||
title: 'Panel 5',
|
|
||||||
position: { referencePanel: panel4 },
|
|
||||||
});
|
|
||||||
|
|
||||||
const panel6 = event.api.addPanel({
|
|
||||||
id: 'panel_6',
|
|
||||||
component: 'default',
|
|
||||||
title: 'Panel 6',
|
|
||||||
position: { referencePanel: panel5, direction: 'below' },
|
|
||||||
});
|
|
||||||
|
|
||||||
const panel7 = event.api.addPanel({
|
|
||||||
id: 'panel_7',
|
|
||||||
component: 'default',
|
|
||||||
title: 'Panel 7',
|
|
||||||
position: { referencePanel: panel6, direction: 'left' },
|
|
||||||
});
|
|
||||||
|
|
||||||
event.api.addPanel({
|
|
||||||
id: 'panel8',
|
|
||||||
component: 'default',
|
|
||||||
title: 'Panel 8',
|
|
||||||
position: { referencePanel: panel7, direction: 'below' },
|
|
||||||
});
|
|
||||||
|
|
||||||
panel1.api.setActive();
|
|
||||||
};
|
|
||||||
|
|
||||||
const onAddPanel = () => {
|
|
||||||
api?.addPanel({
|
|
||||||
id: `id_${Date.now().toString()}`,
|
|
||||||
component: 'default',
|
|
||||||
title: `Tab ${counter++}`,
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
const onAddGroup = () => {
|
|
||||||
api?.addGroup();
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div
|
|
||||||
style={{ height: '100%', display: 'flex', flexDirection: 'column' }}
|
|
||||||
>
|
|
||||||
<div>
|
|
||||||
<div
|
|
||||||
style={{
|
|
||||||
display: 'flex',
|
|
||||||
height: '25px',
|
|
||||||
padding: '2px 0px',
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<button onClick={onAddPanel}>Add Panel</button>
|
|
||||||
<button onClick={onAddGroup}>Add Group</button>
|
|
||||||
</div>
|
|
||||||
<div
|
|
||||||
style={{
|
|
||||||
display: 'flex',
|
|
||||||
height: '25px',
|
|
||||||
padding: '2px 0px',
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{panels.map((x) => {
|
|
||||||
const onClick = () => {
|
|
||||||
api?.getPanel(x)?.focus();
|
|
||||||
};
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
<button
|
|
||||||
onClick={onClick}
|
|
||||||
style={{
|
|
||||||
minWidth: '50px',
|
|
||||||
border: 'none',
|
|
||||||
margin: '0px 2px',
|
|
||||||
padding: '0px 2px',
|
|
||||||
backgroundColor:
|
|
||||||
activePanel === x
|
|
||||||
? 'blueviolet'
|
|
||||||
: 'dodgerblue',
|
|
||||||
borderRadius: '2px',
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{x}
|
|
||||||
</button>
|
|
||||||
<button
|
|
||||||
onClick={() => {
|
|
||||||
const panel = api?.getPanel(x);
|
|
||||||
if (panel) {
|
|
||||||
api?.addFloatingGroup(panel);
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
float
|
|
||||||
</button>
|
|
||||||
<button
|
|
||||||
onClick={() => {
|
|
||||||
const panel = api?.getPanel(x);
|
|
||||||
if (panel) {
|
|
||||||
api?.addPopoutGroup(panel);
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
pop
|
|
||||||
</button>
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
</div>
|
|
||||||
<div
|
|
||||||
style={{
|
|
||||||
display: 'flex',
|
|
||||||
height: '25px',
|
|
||||||
padding: '2px 0px',
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{groups.map((x) => {
|
|
||||||
const onClick = () => {
|
|
||||||
api?.getGroup(x)?.focus();
|
|
||||||
};
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
<button
|
|
||||||
onClick={onClick}
|
|
||||||
style={{
|
|
||||||
minWidth: '50px',
|
|
||||||
border: 'none',
|
|
||||||
margin: '0px 2px',
|
|
||||||
padding: '0px 2px',
|
|
||||||
backgroundColor:
|
|
||||||
activeGroup === x
|
|
||||||
? 'blueviolet'
|
|
||||||
: 'dodgerblue',
|
|
||||||
borderRadius: '2px',
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{x}
|
|
||||||
</button>
|
|
||||||
<button
|
|
||||||
onClick={() => {
|
|
||||||
const panel = api?.getGroup(x);
|
|
||||||
if (panel) {
|
|
||||||
api?.addFloatingGroup(panel);
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
float
|
|
||||||
</button>
|
|
||||||
<button
|
|
||||||
onClick={() => {
|
|
||||||
const panel = api?.getGroup(x);
|
|
||||||
if (panel) {
|
|
||||||
api?.addPopoutGroup(panel);
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
pop
|
|
||||||
</button>
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div style={{ flexGrow: 1 }}>
|
|
||||||
<DockviewReact
|
|
||||||
components={components}
|
|
||||||
defaultTabComponent={headerComponents.default}
|
|
||||||
rightHeaderActionsComponent={RightControls}
|
|
||||||
leftHeaderActionsComponent={LeftControls}
|
|
||||||
prefixHeaderActionsComponent={PrefixHeaderControls}
|
|
||||||
onReady={onReady}
|
|
||||||
className={props.theme || 'dockview-theme-abyss'}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div
|
|
||||||
style={{
|
|
||||||
height: '200px',
|
|
||||||
backgroundColor: 'black',
|
|
||||||
color: 'white',
|
|
||||||
overflow: 'auto',
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{logLines.map((line, i) => {
|
|
||||||
return (
|
|
||||||
<div key={i}>
|
|
||||||
<span
|
|
||||||
style={{
|
|
||||||
display: 'inline-block',
|
|
||||||
width: '30px',
|
|
||||||
color: 'gray',
|
|
||||||
borderRight: '1px solid gray',
|
|
||||||
marginRight: '4px',
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{logLines.length - i}
|
|
||||||
</span>
|
|
||||||
<span>{line}</span>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default DockviewDemo;
|
|
34
packages/docs/sandboxes/example-app-dockview/package.json
Normal file
34
packages/docs/sandboxes/example-app-dockview/package.json
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
{
|
||||||
|
"name": "example-app-dockview",
|
||||||
|
"description": "",
|
||||||
|
"keywords": [
|
||||||
|
"dockview"
|
||||||
|
],
|
||||||
|
"version": "1.0.0",
|
||||||
|
"main": "src/index.tsx",
|
||||||
|
"dependencies": {
|
||||||
|
"ag-grid-community": "^31.0.2",
|
||||||
|
"ag-grid-react": "^31.0.2",
|
||||||
|
"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"
|
||||||
|
]
|
||||||
|
}
|
17
packages/docs/sandboxes/example-app-dockview/src/app.scss
Normal file
17
packages/docs/sandboxes/example-app-dockview/src/app.scss
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
.my-custom-tab {
|
||||||
|
padding: 0px 8px;
|
||||||
|
width: 100%;
|
||||||
|
display: flex;
|
||||||
|
height: 100%;
|
||||||
|
align-items: center;
|
||||||
|
background-color: var(--dv-tabs-and-actions-container-background-color);
|
||||||
|
|
||||||
|
.my-custom-tab-icon {
|
||||||
|
font-size: 16px;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
border-radius: 2px;
|
||||||
|
background-color: var(--dv-icon-hover-background-color);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
90
packages/docs/sandboxes/example-app-dockview/src/app.tsx
Normal file
90
packages/docs/sandboxes/example-app-dockview/src/app.tsx
Normal file
@ -0,0 +1,90 @@
|
|||||||
|
import {
|
||||||
|
DockviewReact,
|
||||||
|
DockviewReadyEvent,
|
||||||
|
IDockviewPanelProps,
|
||||||
|
IDockviewPanelHeaderProps,
|
||||||
|
} from 'dockview';
|
||||||
|
import * as React from 'react';
|
||||||
|
import './app.scss';
|
||||||
|
|
||||||
|
import { AgGridReact } from 'ag-grid-react';
|
||||||
|
import { ColDef } from 'ag-grid-community';
|
||||||
|
|
||||||
|
import 'ag-grid-community/styles/ag-grid.css';
|
||||||
|
import 'ag-grid-community/styles/ag-theme-balham.css';
|
||||||
|
|
||||||
|
const data = new Array(1000).fill(0).map((_, i) => {
|
||||||
|
return {
|
||||||
|
index: i,
|
||||||
|
a: Math.random() * 100,
|
||||||
|
b: Math.random() * 100,
|
||||||
|
c: Math.random() * 100,
|
||||||
|
d: Math.random() * 100,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
const columnDefs: ColDef[] = [
|
||||||
|
{
|
||||||
|
field: 'a',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: 'b',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: 'c',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: 'd',
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
const components = {
|
||||||
|
default: (props: IDockviewPanelProps<{ title: string; x?: number }>) => {
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
display: 'flex',
|
||||||
|
justifyContent: 'center',
|
||||||
|
alignItems: 'center',
|
||||||
|
color: 'white',
|
||||||
|
height: '100%',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<span>{`${props.params.title}`}</span>
|
||||||
|
{props.params.x && <span>{` ${props.params.x}`}</span>}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
},
|
||||||
|
grid: () => {
|
||||||
|
return (
|
||||||
|
<div className="ag-theme-balham-dark" style={{ height: '100%' }}>
|
||||||
|
<AgGridReact rowData={data} columnDefs={columnDefs} />
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const DockviewComponent = (props: { theme?: string }) => {
|
||||||
|
const onReady = (event: DockviewReadyEvent) => {
|
||||||
|
const panel1 = event.api.addPanel({
|
||||||
|
id: 'panel_1',
|
||||||
|
component: 'default',
|
||||||
|
});
|
||||||
|
|
||||||
|
event.api.addPanel({
|
||||||
|
id: 'panel_2',
|
||||||
|
component: 'grid',
|
||||||
|
renderer: 'always',
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<DockviewReact
|
||||||
|
onReady={onReady}
|
||||||
|
components={components}
|
||||||
|
className={`${props.theme || 'dockview-theme-abyss'}`}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default DockviewComponent;
|
@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"name": "floatinggroup-dockview",
|
"name": "dockview.constraints",
|
||||||
"description": "",
|
"description": "",
|
||||||
"keywords": [
|
"keywords": [
|
||||||
"dockview"
|
"dockview"
|
@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"name": "demo-dockview",
|
"name": "dockview.demo",
|
||||||
"description": "",
|
"description": "",
|
||||||
"keywords": [
|
"keywords": [
|
||||||
"dockview"
|
"dockview"
|
@ -0,0 +1,84 @@
|
|||||||
|
.group-control {
|
||||||
|
.action {
|
||||||
|
padding: 4px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
box-sizing: border-box;
|
||||||
|
font-size: 18px;
|
||||||
|
cursor: pointer;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
border-radius: 2px;
|
||||||
|
background-color: var(--dv-icon-hover-background-color);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.data-table {
|
||||||
|
table {
|
||||||
|
font-size: 11px;
|
||||||
|
th {
|
||||||
|
padding: 0px 8px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.action-container {
|
||||||
|
display: flex;
|
||||||
|
padding: 4px 0px;
|
||||||
|
overflow: auto;
|
||||||
|
|
||||||
|
button {
|
||||||
|
height: 25px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
background-color: #1c254a;
|
||||||
|
border: none;
|
||||||
|
cursor: pointer;
|
||||||
|
outline: 1px solid #4c65d4;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background-color: #222e62;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.text-button {
|
||||||
|
margin: 0px 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.button-action {
|
||||||
|
margin: 0px 4px;
|
||||||
|
// display: flex;
|
||||||
|
|
||||||
|
.selected {
|
||||||
|
background-color: #4864dc;
|
||||||
|
}
|
||||||
|
|
||||||
|
.demo-button {
|
||||||
|
min-width: 50px;
|
||||||
|
padding: 0px 2px;
|
||||||
|
border-radius: 0px;
|
||||||
|
display: flex;
|
||||||
|
flex-grow: 1;
|
||||||
|
align-items: center;
|
||||||
|
outline: 1px solid #4c65d4;
|
||||||
|
}
|
||||||
|
|
||||||
|
.demo-icon-button {
|
||||||
|
outline: 1px solid #4c65d4;
|
||||||
|
flex-grow: 1;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
border-radius: 0px;
|
||||||
|
padding: 0px 4px;
|
||||||
|
border: none;
|
||||||
|
cursor: pointer;
|
||||||
|
|
||||||
|
span {
|
||||||
|
font-size: 16px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
213
packages/docs/sandboxes/react/dockview/demo-dockview/src/app.tsx
Normal file
213
packages/docs/sandboxes/react/dockview/demo-dockview/src/app.tsx
Normal file
@ -0,0 +1,213 @@
|
|||||||
|
import {
|
||||||
|
DockviewDefaultTab,
|
||||||
|
DockviewReact,
|
||||||
|
DockviewReadyEvent,
|
||||||
|
IDockviewPanelHeaderProps,
|
||||||
|
IDockviewPanelProps,
|
||||||
|
DockviewApi,
|
||||||
|
} from 'dockview';
|
||||||
|
import * as React from 'react';
|
||||||
|
import './app.scss';
|
||||||
|
import { defaultConfig } from './defaultLayout';
|
||||||
|
import { GridActions } from './gridActions';
|
||||||
|
import { PanelActions } from './panelActions';
|
||||||
|
import { GroupActions } from './groupActions';
|
||||||
|
import { LeftControls, PrefixHeaderControls, RightControls } from './controls';
|
||||||
|
import { Table, usePanelApiMetadata } from './debugPanel';
|
||||||
|
|
||||||
|
const components = {
|
||||||
|
default: (props: IDockviewPanelProps) => {
|
||||||
|
const metadata = usePanelApiMetadata(props.api);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
height: '100%',
|
||||||
|
overflow: 'auto',
|
||||||
|
color: 'white',
|
||||||
|
position: 'relative',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Table data={metadata} />
|
||||||
|
<span
|
||||||
|
style={{
|
||||||
|
position: 'absolute',
|
||||||
|
top: '50%',
|
||||||
|
left: '50%',
|
||||||
|
transform: 'translate(-50%,-50%)',
|
||||||
|
pointerEvents: 'none',
|
||||||
|
fontSize: '42px',
|
||||||
|
opacity: 0.5,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{props.api.title}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
},
|
||||||
|
iframe: () => {
|
||||||
|
return (
|
||||||
|
<iframe
|
||||||
|
style={{
|
||||||
|
width: '100%',
|
||||||
|
height: '100%',
|
||||||
|
}}
|
||||||
|
src="https://dockview.dev"
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const headerComponents = {
|
||||||
|
default: (props: IDockviewPanelHeaderProps) => {
|
||||||
|
const onContextMenu = (event: React.MouseEvent) => {
|
||||||
|
event.preventDefault();
|
||||||
|
alert('context menu');
|
||||||
|
};
|
||||||
|
return <DockviewDefaultTab onContextMenu={onContextMenu} {...props} />;
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const DockviewDemo = (props: { theme?: string }) => {
|
||||||
|
const [logLines, setLogLines] = React.useState<any[]>([]);
|
||||||
|
|
||||||
|
const [panels, setPanels] = React.useState<string[]>([]);
|
||||||
|
const [groups, setGroups] = React.useState<string[]>([]);
|
||||||
|
const [api, setApi] = React.useState<DockviewApi>();
|
||||||
|
|
||||||
|
const [activePanel, setActivePanel] = React.useState<string>();
|
||||||
|
const [activeGroup, setActiveGroup] = React.useState<string>();
|
||||||
|
|
||||||
|
const onReady = (event: DockviewReadyEvent) => {
|
||||||
|
setApi(event.api);
|
||||||
|
|
||||||
|
event.api.onDidAddPanel((event) => {
|
||||||
|
setPanels((_) => [..._, event.id]);
|
||||||
|
setLogLines((line) => [`Panel Added ${event.id}`, ...line]);
|
||||||
|
});
|
||||||
|
event.api.onDidActivePanelChange((event) => {
|
||||||
|
setActivePanel(event?.id);
|
||||||
|
setLogLines((line) => [`Panel Activated ${event?.id}`, ...line]);
|
||||||
|
});
|
||||||
|
event.api.onDidRemovePanel((event) => {
|
||||||
|
setPanels((_) => {
|
||||||
|
const next = [..._];
|
||||||
|
next.splice(
|
||||||
|
next.findIndex((x) => x === event.id),
|
||||||
|
1
|
||||||
|
);
|
||||||
|
|
||||||
|
return next;
|
||||||
|
});
|
||||||
|
setLogLines((line) => [`Panel Removed ${event.id}`, ...line]);
|
||||||
|
});
|
||||||
|
|
||||||
|
event.api.onDidAddGroup((event) => {
|
||||||
|
setGroups((_) => [..._, event.id]);
|
||||||
|
setLogLines((line) => [`Group Added ${event.id}`, ...line]);
|
||||||
|
});
|
||||||
|
|
||||||
|
event.api.onDidRemoveGroup((event) => {
|
||||||
|
setGroups((_) => {
|
||||||
|
const next = [..._];
|
||||||
|
next.splice(
|
||||||
|
next.findIndex((x) => x === event.id),
|
||||||
|
1
|
||||||
|
);
|
||||||
|
|
||||||
|
return next;
|
||||||
|
});
|
||||||
|
setLogLines((line) => [`Group Removed ${event.id}`, ...line]);
|
||||||
|
});
|
||||||
|
|
||||||
|
event.api.onDidActiveGroupChange((event) => {
|
||||||
|
setActiveGroup(event?.id);
|
||||||
|
setLogLines((line) => [`Group Activated ${event?.id}`, ...line]);
|
||||||
|
});
|
||||||
|
|
||||||
|
const state = localStorage.getItem('dv-demo-state');
|
||||||
|
if (state) {
|
||||||
|
try {
|
||||||
|
event.api.fromJSON(JSON.parse(state));
|
||||||
|
return;
|
||||||
|
} catch {
|
||||||
|
localStorage.removeItem('dv-demo-state');
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
defaultConfig(event.api);
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
height: '100%',
|
||||||
|
display: 'flex',
|
||||||
|
flexDirection: 'column',
|
||||||
|
flexGrow: 1,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<div>
|
||||||
|
<GridActions api={api} />
|
||||||
|
<PanelActions
|
||||||
|
api={api}
|
||||||
|
panels={panels}
|
||||||
|
activePanel={activePanel}
|
||||||
|
/>
|
||||||
|
<GroupActions
|
||||||
|
api={api}
|
||||||
|
groups={groups}
|
||||||
|
activeGroup={activeGroup}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
flexGrow: 1,
|
||||||
|
overflow: 'hidden',
|
||||||
|
// flexBasis: 0
|
||||||
|
height: 0,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<DockviewReact
|
||||||
|
components={components}
|
||||||
|
defaultTabComponent={headerComponents.default}
|
||||||
|
rightHeaderActionsComponent={RightControls}
|
||||||
|
leftHeaderActionsComponent={LeftControls}
|
||||||
|
prefixHeaderActionsComponent={PrefixHeaderControls}
|
||||||
|
onReady={onReady}
|
||||||
|
className={props.theme || 'dockview-theme-abyss'}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
height: '200px',
|
||||||
|
backgroundColor: 'black',
|
||||||
|
color: 'white',
|
||||||
|
overflow: 'auto',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{logLines.map((line, i) => {
|
||||||
|
return (
|
||||||
|
<div key={i}>
|
||||||
|
<span
|
||||||
|
style={{
|
||||||
|
display: 'inline-block',
|
||||||
|
width: '30px',
|
||||||
|
color: 'gray',
|
||||||
|
borderRight: '1px solid gray',
|
||||||
|
marginRight: '4px',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{logLines.length - i}
|
||||||
|
</span>
|
||||||
|
<span>{line}</span>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default DockviewDemo;
|
@ -0,0 +1,148 @@
|
|||||||
|
import { IDockviewHeaderActionsProps } from 'dockview';
|
||||||
|
import * as React from 'react';
|
||||||
|
import { nextId } from './defaultLayout';
|
||||||
|
|
||||||
|
const Icon = (props: {
|
||||||
|
icon: string;
|
||||||
|
title?: string;
|
||||||
|
onClick?: (event: React.MouseEvent) => void;
|
||||||
|
}) => {
|
||||||
|
return (
|
||||||
|
<div title={props.title} className="action" onClick={props.onClick}>
|
||||||
|
<span
|
||||||
|
style={{ fontSize: 'inherit' }}
|
||||||
|
className="material-symbols-outlined"
|
||||||
|
>
|
||||||
|
{props.icon}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const groupControlsComponents: Record<string, React.FC> = {
|
||||||
|
panel_1: () => {
|
||||||
|
return <Icon icon="file_download" />;
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export const RightControls = (props: IDockviewHeaderActionsProps) => {
|
||||||
|
const Component = React.useMemo(() => {
|
||||||
|
if (!props.isGroupActive || !props.activePanel) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return groupControlsComponents[props.activePanel.id];
|
||||||
|
}, [props.isGroupActive, props.activePanel]);
|
||||||
|
|
||||||
|
const [isMaximized, setIsMaximized] = React.useState<boolean>(
|
||||||
|
props.containerApi.hasMaximizedGroup()
|
||||||
|
);
|
||||||
|
|
||||||
|
const [isPopout, setIsPopout] = React.useState<boolean>(
|
||||||
|
props.api.location.type === 'popout'
|
||||||
|
);
|
||||||
|
|
||||||
|
React.useEffect(() => {
|
||||||
|
const disposable = props.containerApi.onDidMaximizedGroupChange(() => {
|
||||||
|
setIsMaximized(props.containerApi.hasMaximizedGroup());
|
||||||
|
});
|
||||||
|
|
||||||
|
const disposable2 = props.api.onDidLocationChange(() => {
|
||||||
|
setIsPopout(props.api.location.type === 'popout');
|
||||||
|
});
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
disposable.dispose();
|
||||||
|
disposable2.dispose();
|
||||||
|
};
|
||||||
|
}, [props.containerApi]);
|
||||||
|
|
||||||
|
const onClick = () => {
|
||||||
|
if (props.containerApi.hasMaximizedGroup()) {
|
||||||
|
props.containerApi.exitMaximizedGroup();
|
||||||
|
} else {
|
||||||
|
props.activePanel?.api.maximize();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const onClick2 = () => {
|
||||||
|
if (props.api.location.type !== 'popout') {
|
||||||
|
props.containerApi.addPopoutGroup(props.group);
|
||||||
|
} else {
|
||||||
|
props.api.moveTo({ position: 'right' });
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
className="group-control"
|
||||||
|
style={{
|
||||||
|
display: 'flex',
|
||||||
|
alignItems: 'center',
|
||||||
|
padding: '0px 8px',
|
||||||
|
height: '100%',
|
||||||
|
color: 'var(--dv-activegroup-visiblepanel-tab-color)',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{props.isGroupActive && <Icon icon="star" />}
|
||||||
|
{Component && <Component />}
|
||||||
|
<Icon
|
||||||
|
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>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export const LeftControls = (props: IDockviewHeaderActionsProps) => {
|
||||||
|
const onClick = () => {
|
||||||
|
props.containerApi.addPanel({
|
||||||
|
id: `id_${Date.now().toString()}`,
|
||||||
|
component: 'default',
|
||||||
|
title: `Tab ${nextId()}`,
|
||||||
|
position: {
|
||||||
|
referenceGroup: props.group,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
className="group-control"
|
||||||
|
style={{
|
||||||
|
display: 'flex',
|
||||||
|
alignItems: 'center',
|
||||||
|
padding: '0px 8px',
|
||||||
|
height: '100%',
|
||||||
|
color: 'var(--dv-activegroup-visiblepanel-tab-color)',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Icon onClick={onClick} icon="add" />
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export const PrefixHeaderControls = (props: IDockviewHeaderActionsProps) => {
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
className="group-control"
|
||||||
|
style={{
|
||||||
|
display: 'flex',
|
||||||
|
alignItems: 'center',
|
||||||
|
padding: '0px 8px',
|
||||||
|
height: '100%',
|
||||||
|
color: 'var(--dv-activegroup-visiblepanel-tab-color)',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Icon icon="Menu" />
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
@ -0,0 +1,179 @@
|
|||||||
|
import {
|
||||||
|
DockviewGroupLocation,
|
||||||
|
DockviewPanelApi,
|
||||||
|
DockviewPanelRenderer,
|
||||||
|
} from 'dockview';
|
||||||
|
import * as React from 'react';
|
||||||
|
|
||||||
|
export interface PanelApiMetadata {
|
||||||
|
isActive: {
|
||||||
|
value: boolean;
|
||||||
|
count: number;
|
||||||
|
};
|
||||||
|
isVisible: {
|
||||||
|
value: boolean;
|
||||||
|
count: number;
|
||||||
|
};
|
||||||
|
isHidden: {
|
||||||
|
value: boolean;
|
||||||
|
count: number;
|
||||||
|
};
|
||||||
|
renderer: {
|
||||||
|
value: DockviewPanelRenderer;
|
||||||
|
count: number;
|
||||||
|
};
|
||||||
|
isGroupActive: {
|
||||||
|
value: boolean;
|
||||||
|
count: number;
|
||||||
|
};
|
||||||
|
groupChanged: {
|
||||||
|
count: number;
|
||||||
|
};
|
||||||
|
location: {
|
||||||
|
value: DockviewGroupLocation;
|
||||||
|
count: number;
|
||||||
|
};
|
||||||
|
didFocus: {
|
||||||
|
count: number;
|
||||||
|
};
|
||||||
|
dimensions: {
|
||||||
|
count: number;
|
||||||
|
value: { height: number; width: number };
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export const Table = (props: { data: PanelApiMetadata }) => {
|
||||||
|
return (
|
||||||
|
<div className="data-table">
|
||||||
|
<table>
|
||||||
|
<tr>
|
||||||
|
<th>{'Key'}</th>
|
||||||
|
<th>{'Count'}</th>
|
||||||
|
<th>{'Value'}</th>
|
||||||
|
</tr>
|
||||||
|
{Object.entries(props.data).map(([key, value]) => {
|
||||||
|
return (
|
||||||
|
<tr key={key}>
|
||||||
|
<th>{key}</th>
|
||||||
|
<th>{value.count}</th>
|
||||||
|
<th>{JSON.stringify(value.value, null, 4)}</th>
|
||||||
|
</tr>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export function usePanelApiMetadata(api: DockviewPanelApi): PanelApiMetadata {
|
||||||
|
const [state, setState] = React.useState<PanelApiMetadata>({
|
||||||
|
isActive: { value: api.isActive, count: 0 },
|
||||||
|
isVisible: { value: api.isVisible, count: 0 },
|
||||||
|
isHidden: { value: api.isHidden, count: 0 },
|
||||||
|
renderer: { value: api.renderer, count: 0 },
|
||||||
|
isGroupActive: { value: api.isGroupActive, count: 0 },
|
||||||
|
groupChanged: { count: 0 },
|
||||||
|
location: { value: api.location, count: 0 },
|
||||||
|
didFocus: { count: 0 },
|
||||||
|
dimensions: {
|
||||||
|
count: 0,
|
||||||
|
value: { height: api.height, width: api.width },
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
React.useEffect(() => {
|
||||||
|
const d1 = api.onDidActiveChange((event) => {
|
||||||
|
setState((_) => ({
|
||||||
|
..._,
|
||||||
|
isActive: {
|
||||||
|
value: event.isActive,
|
||||||
|
count: _.isActive.count + 1,
|
||||||
|
},
|
||||||
|
}));
|
||||||
|
});
|
||||||
|
const d2 = api.onDidActiveGroupChange((event) => {
|
||||||
|
setState((_) => ({
|
||||||
|
..._,
|
||||||
|
isGroupActive: {
|
||||||
|
value: event.isActive,
|
||||||
|
count: _.isGroupActive.count + 1,
|
||||||
|
},
|
||||||
|
}));
|
||||||
|
});
|
||||||
|
const d3 = api.onDidDimensionsChange((event) => {
|
||||||
|
setState((_) => ({
|
||||||
|
..._,
|
||||||
|
dimensions: {
|
||||||
|
count: _.dimensions.count + 1,
|
||||||
|
value: { height: event.height, width: event.width },
|
||||||
|
},
|
||||||
|
}));
|
||||||
|
});
|
||||||
|
const d4 = api.onDidFocusChange((event) => {
|
||||||
|
setState((_) => ({
|
||||||
|
..._,
|
||||||
|
didFocus: {
|
||||||
|
count: _.didFocus.count + 1,
|
||||||
|
},
|
||||||
|
}));
|
||||||
|
});
|
||||||
|
const d5 = api.onDidGroupChange((event) => {
|
||||||
|
setState((_) => ({
|
||||||
|
..._,
|
||||||
|
groupChanged: {
|
||||||
|
count: _.groupChanged.count + 1,
|
||||||
|
},
|
||||||
|
}));
|
||||||
|
});
|
||||||
|
const d6 = api.onDidHiddenChange((event) => {
|
||||||
|
setState((_) => ({
|
||||||
|
..._,
|
||||||
|
isHidden: {
|
||||||
|
value: event.isHidden,
|
||||||
|
count: _.isHidden.count + 1,
|
||||||
|
},
|
||||||
|
}));
|
||||||
|
});
|
||||||
|
const d7 = api.onDidLocationChange((event) => {
|
||||||
|
setState((_) => ({
|
||||||
|
..._,
|
||||||
|
location: {
|
||||||
|
value: event.location,
|
||||||
|
count: _.location.count + 1,
|
||||||
|
},
|
||||||
|
}));
|
||||||
|
});
|
||||||
|
const d8 = api.onDidRendererChange((event) => {
|
||||||
|
setState((_) => ({
|
||||||
|
..._,
|
||||||
|
renderer: {
|
||||||
|
value: event.renderer,
|
||||||
|
count: _.renderer.count + 1,
|
||||||
|
},
|
||||||
|
}));
|
||||||
|
});
|
||||||
|
const d9 = api.onDidVisibilityChange((event) => {
|
||||||
|
setState((_) => ({
|
||||||
|
..._,
|
||||||
|
isVisible: {
|
||||||
|
value: event.isVisible,
|
||||||
|
count: _.isVisible.count + 1,
|
||||||
|
},
|
||||||
|
}));
|
||||||
|
});
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
d1.dispose();
|
||||||
|
d2.dispose();
|
||||||
|
d3.dispose();
|
||||||
|
d4.dispose();
|
||||||
|
d5.dispose();
|
||||||
|
d6.dispose();
|
||||||
|
d7.dispose();
|
||||||
|
d8.dispose();
|
||||||
|
d9.dispose();
|
||||||
|
};
|
||||||
|
}, [api]);
|
||||||
|
|
||||||
|
return state;
|
||||||
|
}
|
@ -0,0 +1,69 @@
|
|||||||
|
import { DockviewApi } from 'dockview';
|
||||||
|
|
||||||
|
export const nextId = (() => {
|
||||||
|
let counter = 0;
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
counter++;
|
||||||
|
};
|
||||||
|
})();
|
||||||
|
|
||||||
|
export function defaultConfig(api: DockviewApi) {
|
||||||
|
const panel1 = api.addPanel({
|
||||||
|
id: 'panel_1',
|
||||||
|
component: 'iframe',
|
||||||
|
renderer: 'always',
|
||||||
|
title: 'Panel 1',
|
||||||
|
});
|
||||||
|
|
||||||
|
api.addPanel({
|
||||||
|
id: 'panel_2',
|
||||||
|
component: 'default',
|
||||||
|
title: 'Panel 2',
|
||||||
|
position: { referencePanel: panel1 },
|
||||||
|
});
|
||||||
|
|
||||||
|
api.addPanel({
|
||||||
|
id: 'panel_3',
|
||||||
|
component: 'default',
|
||||||
|
title: 'Panel 3',
|
||||||
|
position: { referencePanel: panel1 },
|
||||||
|
});
|
||||||
|
|
||||||
|
const panel4 = api.addPanel({
|
||||||
|
id: 'panel_4',
|
||||||
|
component: 'default',
|
||||||
|
title: 'Panel 4',
|
||||||
|
position: { referencePanel: panel1, direction: 'right' },
|
||||||
|
});
|
||||||
|
|
||||||
|
const panel5 = api.addPanel({
|
||||||
|
id: 'panel_5',
|
||||||
|
component: 'default',
|
||||||
|
title: 'Panel 5',
|
||||||
|
position: { referencePanel: panel4 },
|
||||||
|
});
|
||||||
|
|
||||||
|
const panel6 = api.addPanel({
|
||||||
|
id: 'panel_6',
|
||||||
|
component: 'default',
|
||||||
|
title: 'Panel 6',
|
||||||
|
position: { referencePanel: panel5, direction: 'below' },
|
||||||
|
});
|
||||||
|
|
||||||
|
const panel7 = api.addPanel({
|
||||||
|
id: 'panel_7',
|
||||||
|
component: 'default',
|
||||||
|
title: 'Panel 7',
|
||||||
|
position: { referencePanel: panel6, direction: 'left' },
|
||||||
|
});
|
||||||
|
|
||||||
|
api.addPanel({
|
||||||
|
id: 'panel8',
|
||||||
|
component: 'default',
|
||||||
|
title: 'Panel 8',
|
||||||
|
position: { referencePanel: panel7, direction: 'below' },
|
||||||
|
});
|
||||||
|
|
||||||
|
panel1.api.setActive();
|
||||||
|
}
|
@ -0,0 +1,71 @@
|
|||||||
|
import { DockviewApi } from 'dockview';
|
||||||
|
import * as React from 'react';
|
||||||
|
import { defaultConfig, nextId } from './defaultLayout';
|
||||||
|
|
||||||
|
export const GridActions = (props: { api?: DockviewApi }) => {
|
||||||
|
const onClear = () => {
|
||||||
|
props.api?.clear();
|
||||||
|
};
|
||||||
|
|
||||||
|
const onLoad = () => {
|
||||||
|
const state = localStorage.getItem('dv-demo-state');
|
||||||
|
if (state) {
|
||||||
|
try {
|
||||||
|
props.api?.fromJSON(JSON.parse(state));
|
||||||
|
} catch {
|
||||||
|
localStorage.removeItem('dv-demo-state');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const onSave = () => {
|
||||||
|
if (props.api) {
|
||||||
|
localStorage.setItem(
|
||||||
|
'dv-demo-state',
|
||||||
|
JSON.stringify(props.api.toJSON())
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const onReset = () => {
|
||||||
|
if (props.api) {
|
||||||
|
props.api.clear();
|
||||||
|
defaultConfig(props.api);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const onAddPanel = () => {
|
||||||
|
props.api?.addPanel({
|
||||||
|
id: `id_${Date.now().toString()}`,
|
||||||
|
component: 'default',
|
||||||
|
title: `Tab ${nextId()}`,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const onAddGroup = () => {
|
||||||
|
props.api?.addGroup();
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="action-container">
|
||||||
|
<button className="text-button" onClick={onAddPanel}>
|
||||||
|
Add Panel
|
||||||
|
</button>
|
||||||
|
<button className="text-button" onClick={onAddGroup}>
|
||||||
|
Add Group
|
||||||
|
</button>
|
||||||
|
<button className="text-button" onClick={onClear}>
|
||||||
|
Clear
|
||||||
|
</button>
|
||||||
|
<button className="text-button" onClick={onLoad}>
|
||||||
|
Load
|
||||||
|
</button>
|
||||||
|
<button className="text-button" onClick={onSave}>
|
||||||
|
Save
|
||||||
|
</button>
|
||||||
|
<button className="text-button" onClick={onReset}>
|
||||||
|
Reset
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
@ -0,0 +1,87 @@
|
|||||||
|
import { DockviewApi } from 'dockview';
|
||||||
|
|
||||||
|
export const GroupActions = (props: {
|
||||||
|
groups: string[];
|
||||||
|
api?: DockviewApi;
|
||||||
|
activeGroup?: string;
|
||||||
|
}) => {
|
||||||
|
return (
|
||||||
|
<div className="action-container">
|
||||||
|
{props.groups.map((x) => {
|
||||||
|
const onClick = () => {
|
||||||
|
props.api?.getGroup(x)?.focus();
|
||||||
|
};
|
||||||
|
return (
|
||||||
|
<div className="button-action">
|
||||||
|
<div style={{ display: 'flex' }}>
|
||||||
|
<button
|
||||||
|
onClick={onClick}
|
||||||
|
className={
|
||||||
|
props.activeGroup === x
|
||||||
|
? 'demo-button selected'
|
||||||
|
: 'demo-button'
|
||||||
|
}
|
||||||
|
>
|
||||||
|
{x}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div style={{ display: 'flex' }}>
|
||||||
|
<button
|
||||||
|
className="demo-icon-button"
|
||||||
|
onClick={() => {
|
||||||
|
const panel = props.api?.getGroup(x);
|
||||||
|
if (panel) {
|
||||||
|
props.api?.addFloatingGroup(panel);
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<span className="material-symbols-outlined">
|
||||||
|
ad_group
|
||||||
|
</span>
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
className="demo-icon-button"
|
||||||
|
onClick={() => {
|
||||||
|
const panel = props.api?.getGroup(x);
|
||||||
|
if (panel) {
|
||||||
|
props.api?.addPopoutGroup(panel);
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<span className="material-symbols-outlined">
|
||||||
|
open_in_new
|
||||||
|
</span>
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
className="demo-icon-button"
|
||||||
|
onClick={() => {
|
||||||
|
const panel = props.api?.getGroup(x);
|
||||||
|
if (panel?.api.isMaximized()) {
|
||||||
|
panel.api.exitMaximized();
|
||||||
|
} else {
|
||||||
|
panel?.api.maximize();
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<span className="material-symbols-outlined">
|
||||||
|
fullscreen
|
||||||
|
</span>
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
className="demo-icon-button"
|
||||||
|
onClick={() => {
|
||||||
|
const panel = props.api?.getGroup(x);
|
||||||
|
panel?.api.close();
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<span className="material-symbols-outlined">
|
||||||
|
close
|
||||||
|
</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
@ -0,0 +1,72 @@
|
|||||||
|
import { DockviewApi } from 'dockview';
|
||||||
|
|
||||||
|
export const PanelActions = (props: {
|
||||||
|
panels: string[];
|
||||||
|
api?: DockviewApi;
|
||||||
|
activePanel?: string;
|
||||||
|
}) => {
|
||||||
|
return (
|
||||||
|
<div className="action-container">
|
||||||
|
{props.panels.map((x) => {
|
||||||
|
const onClick = () => {
|
||||||
|
props.api?.getPanel(x)?.focus();
|
||||||
|
};
|
||||||
|
return (
|
||||||
|
<div className="button-action">
|
||||||
|
<div style={{ display: 'flex' }}>
|
||||||
|
<button
|
||||||
|
className={
|
||||||
|
props.activePanel === x
|
||||||
|
? 'demo-button selected'
|
||||||
|
: 'demo-button'
|
||||||
|
}
|
||||||
|
onClick={onClick}
|
||||||
|
>
|
||||||
|
{x}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div style={{ display: 'flex' }}>
|
||||||
|
<button
|
||||||
|
className="demo-icon-button"
|
||||||
|
onClick={() => {
|
||||||
|
const panel = props.api?.getPanel(x);
|
||||||
|
if (panel) {
|
||||||
|
props.api?.addFloatingGroup(panel);
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<span className="material-symbols-outlined">
|
||||||
|
ad_group
|
||||||
|
</span>
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
className="demo-icon-button"
|
||||||
|
onClick={() => {
|
||||||
|
const panel = props.api?.getPanel(x);
|
||||||
|
if (panel) {
|
||||||
|
props.api?.addPopoutGroup(panel);
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<span className="material-symbols-outlined">
|
||||||
|
open_in_new
|
||||||
|
</span>
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
className="demo-icon-button"
|
||||||
|
onClick={() => {
|
||||||
|
const panel = props.api?.getPanel(x);
|
||||||
|
panel?.api.close();
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<span className="material-symbols-outlined">
|
||||||
|
close
|
||||||
|
</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"name": "updatetitle-dockview",
|
"name": "dockview.dnd-events",
|
||||||
"description": "",
|
"description": "",
|
||||||
"keywords": [
|
"keywords": [
|
||||||
"dockview"
|
"dockview"
|
139
packages/docs/sandboxes/react/dockview/dnd-events/src/app.tsx
Normal file
139
packages/docs/sandboxes/react/dockview/dnd-events/src/app.tsx
Normal file
@ -0,0 +1,139 @@
|
|||||||
|
import {
|
||||||
|
DockviewApi,
|
||||||
|
DockviewReact,
|
||||||
|
DockviewReadyEvent,
|
||||||
|
IDockviewPanelProps,
|
||||||
|
} from 'dockview';
|
||||||
|
import * as React from 'react';
|
||||||
|
|
||||||
|
const Default = (props: IDockviewPanelProps) => {
|
||||||
|
return (
|
||||||
|
<div style={{ height: '100%' }}>
|
||||||
|
<div>{props.api.title}</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const components = {
|
||||||
|
default: Default,
|
||||||
|
};
|
||||||
|
|
||||||
|
const Component = (props: { theme?: string }) => {
|
||||||
|
const [disablePanelDrag, setDisablePanelDrag] =
|
||||||
|
React.useState<boolean>(false);
|
||||||
|
const [disableGroupDrag, setDisableGroupDrag] =
|
||||||
|
React.useState<boolean>(false);
|
||||||
|
const [disableOverlay, setDisableOverlay] = React.useState<boolean>(false);
|
||||||
|
|
||||||
|
const [api, setApi] = React.useState<DockviewApi>();
|
||||||
|
|
||||||
|
React.useEffect(() => {
|
||||||
|
if (!api) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const disposables = [
|
||||||
|
api.onWillDragPanel((e) => {
|
||||||
|
if (!disablePanelDrag) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
e.nativeEvent.preventDefault();
|
||||||
|
}),
|
||||||
|
|
||||||
|
api.onWillDragGroup((e) => {
|
||||||
|
if (!disableGroupDrag) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
e.nativeEvent.preventDefault();
|
||||||
|
}),
|
||||||
|
api.onWillShowOverlay((e) => {
|
||||||
|
if (!disableOverlay) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
e.preventDefault();
|
||||||
|
}),
|
||||||
|
|
||||||
|
api.onWillDrop((e) => {
|
||||||
|
//
|
||||||
|
}),
|
||||||
|
|
||||||
|
api.onDidDrop((e) => {
|
||||||
|
//
|
||||||
|
}),
|
||||||
|
];
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
disposables.forEach((disposable) => {
|
||||||
|
disposable.dispose();
|
||||||
|
});
|
||||||
|
};
|
||||||
|
}, [api, disablePanelDrag, disableGroupDrag]);
|
||||||
|
|
||||||
|
const onReady = (event: DockviewReadyEvent) => {
|
||||||
|
setApi(event.api);
|
||||||
|
|
||||||
|
event.api.addPanel({
|
||||||
|
id: 'panel_1',
|
||||||
|
component: 'default',
|
||||||
|
});
|
||||||
|
|
||||||
|
event.api.addPanel({
|
||||||
|
id: 'panel_2',
|
||||||
|
component: 'default',
|
||||||
|
position: {
|
||||||
|
direction: 'right',
|
||||||
|
referencePanel: 'panel_1',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
event.api.addPanel({
|
||||||
|
id: 'panel_3',
|
||||||
|
component: 'default',
|
||||||
|
position: {
|
||||||
|
direction: 'below',
|
||||||
|
referencePanel: 'panel_1',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
event.api.addPanel({
|
||||||
|
id: 'panel_4',
|
||||||
|
component: 'default',
|
||||||
|
});
|
||||||
|
event.api.addPanel({
|
||||||
|
id: 'panel_5',
|
||||||
|
component: 'default',
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
style={{ display: 'flex', flexDirection: 'column', height: '100%' }}
|
||||||
|
>
|
||||||
|
<div>
|
||||||
|
<button
|
||||||
|
onClick={() => setDisablePanelDrag(!disablePanelDrag)}
|
||||||
|
>{`Panel Drag: ${
|
||||||
|
disablePanelDrag ? 'disabled' : 'enabled'
|
||||||
|
}`}</button>
|
||||||
|
<button
|
||||||
|
onClick={() => setDisableGroupDrag(!disableGroupDrag)}
|
||||||
|
>{`Group Drag: ${
|
||||||
|
disableGroupDrag ? 'disabled' : 'enabled'
|
||||||
|
}`}</button>
|
||||||
|
<button
|
||||||
|
onClick={() => setDisableOverlay(!disableOverlay)}
|
||||||
|
>{`Overlay: ${
|
||||||
|
disableOverlay ? 'disabled' : 'enabled'
|
||||||
|
}`}</button>
|
||||||
|
</div>
|
||||||
|
<div style={{ flexGrow: 1 }}>
|
||||||
|
<DockviewReact
|
||||||
|
className={`${props.theme || 'dockview-theme-abyss'}`}
|
||||||
|
onReady={onReady}
|
||||||
|
components={components}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Component;
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user