diff --git a/packages/dockview/src/__tests__/splitview/core/splitview.spec.ts b/packages/dockview/src/__tests__/splitview/core/splitview.spec.ts index ef4f607d2..a2357bf02 100644 --- a/packages/dockview/src/__tests__/splitview/core/splitview.spec.ts +++ b/packages/dockview/src/__tests__/splitview/core/splitview.spec.ts @@ -14,7 +14,10 @@ class Testview implements IView { private _orthogonalSize = 0; private _priority: LayoutPriority | undefined; - private readonly _onDidChange = new Emitter(); + private readonly _onDidChange = new Emitter<{ + size?: number; + orthogonalSize?: number; + }>(); readonly onDidChange = this._onDidChange.event; private readonly _onLayoutCalled = new Emitter(); @@ -62,7 +65,7 @@ class Testview implements IView { this._onLayoutCalled.fire(); } - fireChangeEvent(value: number | undefined) { + fireChangeEvent(value: { size?: number; orthogonalSize?: number }) { this._onDidChange.fire(value); } @@ -288,17 +291,17 @@ describe('splitview', () => { expect(view1.size).toBe(100); expect(view2.size).toBe(100); - view1.fireChangeEvent(65); + view1.fireChangeEvent({ size: 65 }); expect(view1.size).toBe(65); expect(view2.size).toBe(135); - view2.fireChangeEvent(75); + view2.fireChangeEvent({ size: 75 }); expect(view1.size).toBe(125); expect(view2.size).toBe(75); - view2.fireChangeEvent(undefined); + view2.fireChangeEvent({}); expect(view1.size).toBe(125); expect(view2.size).toBe(75); diff --git a/packages/dockview/src/dockview/dockviewComponent.ts b/packages/dockview/src/dockview/dockviewComponent.ts index 1ddfa193a..4e7bea1b4 100644 --- a/packages/dockview/src/dockview/dockviewComponent.ts +++ b/packages/dockview/src/dockview/dockviewComponent.ts @@ -697,6 +697,8 @@ export class DockviewComponent this._onDidDrop.fire({ ...event, api: this._api, group: view }); }), view.model.onDidAddPanel((event) => { + + this._onDidAddPanel.fire(event.panel); }), view.model.onDidRemovePanel((event) => { diff --git a/packages/dockview/src/gridview/branchNode.ts b/packages/dockview/src/gridview/branchNode.ts index 0126fab48..bc8f591a9 100644 --- a/packages/dockview/src/gridview/branchNode.ts +++ b/packages/dockview/src/gridview/branchNode.ts @@ -24,8 +24,12 @@ export class BranchNode extends CompositeDisposable implements IView { private _size: number; public readonly children: Node[] = []; - private readonly _onDidChange = new Emitter(); - readonly onDidChange: Event = this._onDidChange.event; + private readonly _onDidChange = new Emitter<{ + size?: number; + orthogonalSize?: number; + }>(); + readonly onDidChange: Event<{ size?: number; orthogonalSize?: number }> = + this._onDidChange.event; get width(): number { return this.orientation === Orientation.HORIZONTAL @@ -157,7 +161,7 @@ export class BranchNode extends CompositeDisposable implements IView { this.addDisposables( this._onDidChange, this.splitview.onDidSashEnd(() => { - this._onDidChange.fire(undefined); + this._onDidChange.fire({}); }) ); @@ -282,12 +286,12 @@ export class BranchNode extends CompositeDisposable implements IView { this._childrenDisposable = Event.any( ...this.children.map((c) => c.onDidChange) - )(() => { + )((e) => { /** * indicate a change has occured to allows any re-rendering but don't bubble * event because that was specific to this branch */ - this._onDidChange.fire(undefined); + this._onDidChange.fire({ size: e.orthogonalSize }); }); } diff --git a/packages/dockview/src/gridview/gridview.ts b/packages/dockview/src/gridview/gridview.ts index 8f7bfb5a3..386deba9e 100644 --- a/packages/dockview/src/gridview/gridview.ts +++ b/packages/dockview/src/gridview/gridview.ts @@ -269,8 +269,12 @@ export class Gridview implements IDisposable { public readonly element: HTMLElement; private disposable: MutableDisposable = new MutableDisposable(); - private readonly _onDidChange = new Emitter(); - readonly onDidChange: Event = this._onDidChange.event; + private readonly _onDidChange = new Emitter<{ + size?: number; + orthogonalSize?: number; + }>(); + readonly onDidChange: Event<{ size?: number; orthogonalSize?: number }> = + this._onDidChange.event; public serialize() { const root = serializeBranchNode(this.getView(), this.orientation); diff --git a/packages/dockview/src/gridview/leafNode.ts b/packages/dockview/src/gridview/leafNode.ts index 5da71ad7f..eed4a55bf 100644 --- a/packages/dockview/src/gridview/leafNode.ts +++ b/packages/dockview/src/gridview/leafNode.ts @@ -13,8 +13,12 @@ import { IGridView } from './gridview'; import { IDisposable } from '../lifecycle'; export class LeafNode implements IView { - private readonly _onDidChange = new Emitter(); - readonly onDidChange: Event = this._onDidChange.event; + private readonly _onDidChange = new Emitter<{ + size?: number; + orthogonalSize?: number; + }>(); + readonly onDidChange: Event<{ size?: number; orthogonalSize?: number }> = + this._onDidChange.event; private _size: number; private _orthogonalSize: number; private _disposable: IDisposable; @@ -102,13 +106,18 @@ export class LeafNode implements IView { this._disposable = this.view.onDidChange((event) => { if (event) { - this._onDidChange.fire( - this.orientation === Orientation.VERTICAL - ? event.width - : event.height - ); + this._onDidChange.fire({ + size: + this.orientation === Orientation.VERTICAL + ? event.width + : event.height, + orthogonalSize: + this.orientation === Orientation.VERTICAL + ? event.height + : event.width, + }); } else { - this._onDidChange.fire(undefined); + this._onDidChange.fire({}); } }); } @@ -116,7 +125,7 @@ export class LeafNode implements IView { public setVisible(visible: boolean) { if (this.view.setVisible) { this.view.setVisible(visible); - this._onDidChange.fire(undefined); + this._onDidChange.fire({}); } } diff --git a/packages/dockview/src/paneview/paneviewPanel.ts b/packages/dockview/src/paneview/paneviewPanel.ts index 84039b5d4..c1b3bd823 100644 --- a/packages/dockview/src/paneview/paneviewPanel.ts +++ b/packages/dockview/src/paneview/paneviewPanel.ts @@ -69,8 +69,12 @@ export abstract class PaneviewPanel { replay: true } ); onDidChangeExpansionState = this._onDidChangeExpansionState.event; - private readonly _onDidChange = new Emitter(); - readonly onDidChange: Event = this._onDidChange.event; + private readonly _onDidChange = new Emitter<{ + size?: number; + orthogonalSize?: number; + }>(); + readonly onDidChange: Event<{ size?: number; orthogonalSize?: number }> = + this._onDidChange.event; private headerSize = 22; private _orthogonalSize = 0; @@ -171,7 +175,7 @@ export abstract class PaneviewPanel this.addDisposables( this.api.onDidSizeChange((event) => { - this._onDidChange.fire(event.size); + this._onDidChange.fire({ size: event.size }); }), addDisposableListener( this.element, @@ -243,7 +247,7 @@ export abstract class PaneviewPanel }, 200); } - this._onDidChange.fire(expanded ? this.width : undefined); + this._onDidChange.fire(expanded ? { size: this.width } : {}); this._onDidChangeExpansionState.fire(expanded); } diff --git a/packages/dockview/src/splitview/core/splitview.ts b/packages/dockview/src/splitview/core/splitview.ts index 47fcfe0ff..6b9d3a013 100644 --- a/packages/dockview/src/splitview/core/splitview.ts +++ b/packages/dockview/src/splitview/core/splitview.ts @@ -51,7 +51,7 @@ export interface IBaseView { export interface IView extends IBaseView { readonly element: HTMLElement | DocumentFragment; - readonly onDidChange: Event; + readonly onDidChange: Event<{ size?: number; orthogonalSize?: number }>; layout(size: number, orthogonalSize: number): void; setVisible(visible: boolean): void; } @@ -364,7 +364,7 @@ export class Splitview { } const disposable = view.onDidChange((newSize) => - this.onDidChange(viewItem, newSize) + this.onDidChange(viewItem, newSize.size) ); const dispose = () => { diff --git a/packages/dockview/src/splitview/splitviewPanel.ts b/packages/dockview/src/splitview/splitviewPanel.ts index 459cea825..051452751 100644 --- a/packages/dockview/src/splitview/splitviewPanel.ts +++ b/packages/dockview/src/splitview/splitviewPanel.ts @@ -31,8 +31,12 @@ export abstract class SplitviewPanel private _orientation?: Orientation; - private readonly _onDidChange = new Emitter(); - readonly onDidChange: Event = this._onDidChange.event; + private readonly _onDidChange = new Emitter<{ + size?: number; + orthogonalSize?: number; + }>(); + readonly onDidChange: Event<{ size?: number; orthogonalSize?: number }> = + this._onDidChange.event; get priority(): LayoutPriority | undefined { return this._priority; @@ -108,7 +112,7 @@ export abstract class SplitviewPanel this.updateConstraints(); }), this.api.onDidSizeChange((event) => { - this._onDidChange.fire(event.size); + this._onDidChange.fire({ size: event.size }); }) ); } diff --git a/packages/docs/docs/components/dockview.mdx b/packages/docs/docs/components/dockview.mdx index 3b57de0a8..0faa319cf 100644 --- a/packages/docs/docs/components/dockview.mdx +++ b/packages/docs/docs/components/dockview.mdx @@ -12,6 +12,7 @@ import { EventsDockview } from '@site/src/components/dockview/events'; import { ContextMenuDockview } from '@site/src/components/dockview/contextMenu'; import { NestedDockview } from '@site/src/components/dockview/nested'; import { CustomHeadersDockview } from '@site/src/components/dockview/customHeaders'; +import { ResizeDockview } from '@site/src/components/dockview/resize'; import Link from '@docusaurus/Link'; # Dockview @@ -150,6 +151,36 @@ const MyComponent = (props: IDockviewPanelProps<{ title: string }>) => { ## Advanced Features +### Resizing via API + +Each Dockview is comprised of a number of groups, each of which have a number of panels. +Logically most people would want to resize a panel but practically this really translates to resizing the group to which the panel belongs. + +From the api you can access the panels group object (`props.group`) which exposes it's own api object (`props.groups.api`). +This api is largly similar to the Gridview API. + +To resize an individual panel you could create a snippet similar to below. + +```tsx +const onResizePanel = () => { + props.api.group.api.setSize({ + height: 100, + }); +}; +``` + +```tsx +const onResizePanel = () => { + props.api.group.api.setSize({ + width: 100, + }); +}; +``` + +Here is a working example of resizing panels via these API methods. + + + ### Locked group Locking a group will disable all drop events for this group ensuring a user can not add additional panels to the group. diff --git a/packages/docs/docusaurus.config.js b/packages/docs/docusaurus.config.js index ad57ab55d..fc5450b1b 100644 --- a/packages/docs/docusaurus.config.js +++ b/packages/docs/docusaurus.config.js @@ -208,6 +208,10 @@ const config = { }, ], }, + announcementBar: { + id: 'announcementBar', // Increment on change + content: `⭐️ If you like Dockview, give it a star on GitHub`, + }, }), }; diff --git a/packages/docs/src/components/dockview/demo.tsx b/packages/docs/src/components/dockview/demo.tsx index ceb1aad74..88410fc6d 100644 --- a/packages/docs/src/components/dockview/demo.tsx +++ b/packages/docs/src/components/dockview/demo.tsx @@ -209,8 +209,9 @@ const Icon = (props: { }; const Button = () => { - const [position, setPosition] = - React.useState<{ x: number; y: number } | undefined>(undefined); + const [position, setPosition] = React.useState< + { x: number; y: number } | undefined + >(undefined); const close = () => setPosition(undefined); @@ -318,6 +319,16 @@ export const DockviewDemo = () => { event.api.addEmptyGroup(); event.api.getPanel('panel_1').api.setActive(); + + setInterval(() => { + event.api.getPanel('panel_1').update({ + params: { + params: { + title: Date.now().toString(), + }, + }, + }); + }, 1000); }; return ( diff --git a/packages/docs/src/components/dockview/resize.scss b/packages/docs/src/components/dockview/resize.scss new file mode 100644 index 000000000..25b49d5cb --- /dev/null +++ b/packages/docs/src/components/dockview/resize.scss @@ -0,0 +1,23 @@ +.resize-panel { + padding: 10px; + color: white; + + .resize-control { + display: flex; + height: 18px; + line-height: 18px; + font-size: 13px; + + span { + width: 60px; + } + + input { + width: 75px; + } + + button { + width: 50px; + } + } +} diff --git a/packages/docs/src/components/dockview/resize.tsx b/packages/docs/src/components/dockview/resize.tsx new file mode 100644 index 000000000..eaff93af3 --- /dev/null +++ b/packages/docs/src/components/dockview/resize.tsx @@ -0,0 +1,111 @@ +import { + DockviewReact, + DockviewReadyEvent, + IDockviewPanelProps, +} from 'dockview'; +import * as React from 'react'; +import './resize.scss'; + +const Default = (props: IDockviewPanelProps) => { + const [width, setWidth] = React.useState(100); + const [height, setHeight] = React.useState(100); + + return ( +
+
{props.api.title}
+
+ Width: + setWidth(Number(e.target.value))} + type="number" + min={50} + step={1} + /> + +
+
+ Height: + setHeight(Number(e.target.value))} + type="number" + min={50} + step={1} + /> + +
+
+ ); +}; + +const components = { + default: Default, +}; + +export const ResizeDockview = () => { + const onReady = (event: DockviewReadyEvent) => { + 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 ( +
+ +
+ ); +}; diff --git a/packages/docs/src/pages/index.tsx b/packages/docs/src/pages/index.tsx index 9911bd008..95e2dd4f5 100644 --- a/packages/docs/src/pages/index.tsx +++ b/packages/docs/src/pages/index.tsx @@ -67,8 +67,8 @@ export default function Home(): JSX.Element { const { siteConfig } = useDocusaurusContext(); return (
diff --git a/packages/docs/versioned_docs/version-1.5.1/components/dockview.mdx b/packages/docs/versioned_docs/version-1.5.1/components/dockview.mdx index 3b57de0a8..4af21aca7 100644 --- a/packages/docs/versioned_docs/version-1.5.1/components/dockview.mdx +++ b/packages/docs/versioned_docs/version-1.5.1/components/dockview.mdx @@ -150,6 +150,32 @@ const MyComponent = (props: IDockviewPanelProps<{ title: string }>) => { ## Advanced Features +### Resizing via API + +Each Dockview is comprised of a number of groups, each of which have a number of panels. +Logically most people would want to resize a panel but practically this really translates to resizing the group to which the panel belongs. + +From the api you can access the panels group object (`props.group`) which exposes it's own api object (`props.groups.api`). +This api is largly similar to the Gridview API. + +To resize an individual panel you could create a snippet similar to below. + +```tsx +const onResizePanel = () => { + props.api.group.api.setSize({ + height: 100, + }); +}; +``` + +```tsx +const onResizePanel = () => { + props.api.group.api.setSize({ + width: 100, + }); +}; +``` + ### Locked group Locking a group will disable all drop events for this group ensuring a user can not add additional panels to the group.