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

This commit is contained in:
mathuo 2022-05-10 21:59:28 +01:00
commit f5b90725f4
No known key found for this signature in database
GPG Key ID: C6EEDEFD6CA07281
29 changed files with 126 additions and 398 deletions

View File

@ -23,10 +23,10 @@ export const Activitybar = (props: IGridviewPanelProps) => {
const sidebarPanel = api.getPanel('sidebar'); const sidebarPanel = api.getPanel('sidebar');
if (sidebarPanel.api.isVisible) { if (sidebarPanel.api.isVisible) {
api.setVisible(sidebarPanel, false); sidebarPanel.api.setVisible(false);
} else { } else {
event.preventDefault(); // prevent focus event.preventDefault(); // prevent focus
api.setVisible(sidebarPanel, true); sidebarPanel.api.setVisible(true);
sidebarPanel.focus(); sidebarPanel.focus();
} }
}; };

View File

@ -10,7 +10,6 @@ import {
IWatermarkPanelProps, IWatermarkPanelProps,
IDockviewPanel, IDockviewPanel,
PanelCollection, PanelCollection,
DockviewComponents,
} from 'dockview'; } from 'dockview';
import { CustomTab } from './customTab'; import { CustomTab } from './customTab';
import { Settings } from './settingsPanel'; import { Settings } from './settingsPanel';
@ -47,22 +46,10 @@ const Test = (props: IDockviewPanelProps) => {
}, []); }, []);
return ( return (
<DockviewComponents.Panel> <div>
{counter % 4 === 0 && ( <div>{`custom body ${counter}`}</div>
<DockviewComponents.Tab> <button>Toggle</button>
<div>{`custom tab ${counter}`}</div> </div>
</DockviewComponents.Tab>
)}
<DockviewComponents.Content>
<div>
<div>{`custom body ${counter}`}</div>
<button>Toggle</button>
</div>
</DockviewComponents.Content>
<DockviewComponents.Actions>
<div>{`custom action ${counter}`}</div>
</DockviewComponents.Actions>
</DockviewComponents.Panel>
); );
}; };

View File

@ -1,4 +1,4 @@
import { DockviewComponents, IDockviewPanelProps } from 'dockview'; import { IDockviewPanelProps } from 'dockview';
import * as React from 'react'; import * as React from 'react';
import { CompositeDisposable } from '../../lifecycle'; import { CompositeDisposable } from '../../lifecycle';
import './exampleFunctions.scss'; import './exampleFunctions.scss';
@ -30,8 +30,10 @@ export const ExampleFunctions = (
isPanelVisible: x.isVisible, isPanelVisible: x.isVisible,
})); }));
}), }),
props.api.onFocusEvent(() => { props.api.onDidFocusChange(({ isFocused }) => {
input.current.focus(); if (isFocused) {
input.current.focus();
}
}) })
); );
@ -49,80 +51,52 @@ export const ExampleFunctions = (
}; };
return ( return (
<DockviewComponents.Panel> <div className="example-functions-panel">
<DockviewComponents.Actions> <div className="example-functions-panel-header-bar">
<div <span style={{ padding: '0px 8px' }}>
style={{ <span>{'isGroupActive: '}</span>
height: '100%',
display: 'flex',
backgroundColor: 'rgba(255,255,255,0.1)',
padding: '0px 4px',
}}
>
<span <span
onClick={onClose}
style={{ style={{
height: '100%', color: panelState.isGroupActive
width: '25px', ? '#23d16f'
display: 'flex', : '#cd312b',
alignItems: 'center',
}} }}
> >
<a className="material-icons">menu</a> {`${panelState.isGroupActive}`}
</span> </span>
</div> </span>
</DockviewComponents.Actions> <span style={{ padding: '0px 8px' }}>
<DockviewComponents.Content> <span>{'isPanelVisible: '}</span>
<div className="example-functions-panel"> <span
<div className="example-functions-panel-header-bar"> style={{
<span style={{ padding: '0px 8px' }}> color: panelState.isPanelVisible
<span>{'isGroupActive: '}</span> ? '#23d16f'
<span : '#cd312b',
style={{ }}
color: panelState.isGroupActive >
? '#23d16f' {`${panelState.isPanelVisible}`}
: '#cd312b', </span>
}} </span>
> </div>
{`${panelState.isGroupActive}`} <div className="example-functions-panel-section">
</span> <input
</span> value={panelName}
<span style={{ padding: '0px 8px' }}> placeholder="New Panel Name"
<span>{'isPanelVisible: '}</span> type="text"
<span onChange={(event) => setPanelName(event.target.value)}
style={{ />
color: panelState.isPanelVisible <button onClick={onRename}>Rename</button>
? '#23d16f' </div>
: '#cd312b',
}}
>
{`${panelState.isPanelVisible}`}
</span>
</span>
</div>
<div className="example-functions-panel-section">
<input
value={panelName}
placeholder="New Panel Name"
type="text"
onChange={(event) =>
setPanelName(event.target.value)
}
/>
<button onClick={onRename}>Rename</button>
</div>
<input <input
style={{ width: '175px' }} style={{ width: '175px' }}
ref={input} ref={input}
placeholder="This is focused by the panel" placeholder="This is focused by the panel"
/> />
<input <input
style={{ width: '175px' }} style={{ width: '175px' }}
placeholder="This is also focusable" placeholder="This is also focusable"
/> />
</div> </div>
</DockviewComponents.Content>
</DockviewComponents.Panel>
); );
}; };

View File

@ -64,8 +64,10 @@ export const Sidebar = (props: IGridviewPanelProps) => {
props.api.onDidVisibilityChange((event) => { props.api.onDidVisibilityChange((event) => {
console.log(event); console.log(event);
}), }),
props.api.onFocusEvent(() => { props.api.onDidFocusChange(({ isFocused }) => {
api.current.focus(); if (isFocused) {
api.current.focus();
}
}) })
); );

View File

@ -29,8 +29,10 @@ const components = {
props.api.onDidActiveChange((event) => { props.api.onDidActiveChange((event) => {
setActive(event.isActive); setActive(event.isActive);
}), }),
props.api.onFocusEvent(() => { props.api.onDidFocusChange(({ isFocused }) => {
ref.current.focus(); if (isFocused) {
ref.current.focus();
}
}) })
); );
@ -65,8 +67,10 @@ export const SplitPanel = (props: IDockviewPanelProps) => {
props.api.onDidDimensionsChange((event) => { props.api.onDidDimensionsChange((event) => {
api.current?.layout(event.width, event.height - 25); api.current?.layout(event.width, event.height - 25);
}), }),
props.api.onFocusEvent(() => { props.api.onDidFocusChange(({ isFocused }) => {
api.current.focus(); if (isFocused) {
api.current.focus();
}
}) })
); );

View File

@ -227,7 +227,7 @@ export const Common = (
const toggleVisibility = (i: number) => () => { const toggleVisibility = (i: number) => () => {
const panel = api.current.panels[i]; const panel = api.current.panels[i];
api.current.setVisible(panel, !panel.api.isVisible); panel.api.setVisible(panel.api.isVisible);
setDimensions((dimensions) => ({ setDimensions((dimensions) => ({
...dimensions, ...dimensions,
visibility: api.current.panels.map((_) => _.api.isVisible), visibility: api.current.panels.map((_) => _.api.isVisible),

View File

@ -161,11 +161,11 @@ export const Activitybar = (props: IGridviewPanelProps) => {
const sidebarPanel = api.getPanel('sidebar'); const sidebarPanel = api.getPanel('sidebar');
if (sidebarPanel.api.isVisible) { if (sidebarPanel.api.isVisible) {
if (!alwaysOpen && selectedActive) { if (!alwaysOpen && selectedActive) {
api.setVisible(sidebarPanel, false); sidebarPanel.api.setVisible(false);
} }
} else { } else {
event.preventDefault(); // prevent focus event.preventDefault(); // prevent focus
api.setVisible(sidebarPanel, true); sidebarPanel.api.setVisible(true);
sidebarPanel.focus(); sidebarPanel.focus();
} }
@ -234,7 +234,7 @@ export const Activitybar = (props: IGridviewPanelProps) => {
const sidebarPanel = api.getPanel('sidebar'); const sidebarPanel = api.getPanel('sidebar');
if (!sidebarPanel.api.isVisible) { if (!sidebarPanel.api.isVisible) {
api.setVisible(sidebarPanel, true); sidebarPanel.api.setVisible(true);
sidebarPanel.focus(); sidebarPanel.focus();
} }

View File

@ -1,6 +1,5 @@
import { import {
DockviewApi, DockviewApi,
DockviewComponents,
DockviewReact, DockviewReact,
DockviewReadyEvent, DockviewReadyEvent,
IDockviewPanelProps, IDockviewPanelProps,
@ -18,35 +17,9 @@ const components: PanelCollection<IDockviewPanelProps<any>> = {
ticker: (props: IDockviewPanelProps<{ ticker: number }>) => { ticker: (props: IDockviewPanelProps<{ ticker: number }>) => {
const close = () => props.api.close(); const close = () => props.api.close();
return ( return (
<DockviewComponents.Panel> <div style={{ padding: '10px', height: '100%' }}>
<DockviewComponents.Tab> {`The current ticker value is ${props.params.ticker}`}
<div </div>
style={{
border: '1px solid pink',
height: '100%',
boxSizing: 'border-box',
display: 'flex',
alignItems: 'center',
justifyContent: 'space-between',
padding: '0px 8px',
width: '200px',
}}
>
<span>{props.api.title}</span>
<span
style={{ fontSize: '9px' }}
>{`(${props.params.ticker})`}</span>
{!props.api.suppressClosable && (
<span onClick={close}>X</span>
)}
</div>
</DockviewComponents.Tab>
<DockviewComponents.Content>
<div style={{ padding: '10px', height: '100%' }}>
{`The current ticker value is ${props.params.ticker}`}
</div>
</DockviewComponents.Content>
</DockviewComponents.Panel>
); );
}, },
iframe: (props) => { iframe: (props) => {

View File

@ -1,6 +1,5 @@
import { import {
DockviewApi, DockviewApi,
DockviewComponents,
DockviewReact, DockviewReact,
DockviewReadyEvent, DockviewReadyEvent,
IDockviewPanelProps, IDockviewPanelProps,
@ -13,35 +12,7 @@ const components: PanelCollection<IDockviewPanelProps> = {
default: (props) => { default: (props) => {
const close = () => props.api.close(); const close = () => props.api.close();
return ( return (
<DockviewComponents.Panel> <div style={{ padding: '10px', height: '100%' }}>hello world</div>
<DockviewComponents.Tab>
<div
style={{
border: '1px solid pink',
height: '100%',
boxSizing: 'border-box',
display: 'flex',
alignItems: 'center',
justifyContent: 'space-between',
padding: '0px 8px',
width: '200px',
}}
>
<span>{props.api.title}</span>
<span style={{ fontSize: '9px' }}>
{'(Custom tab component)'}
</span>
{!props.api.suppressClosable && (
<span onClick={close}>X</span>
)}
</div>
</DockviewComponents.Tab>
<DockviewComponents.Content>
<div style={{ padding: '10px', height: '100%' }}>
hello world
</div>
</DockviewComponents.Content>
</DockviewComponents.Panel>
); );
}, },
}; };

View File

@ -41,11 +41,11 @@ describe('api', () => {
expect(api.height).toBe(0); expect(api.height).toBe(0);
expect(api.width).toBe(0); expect(api.width).toBe(0);
api._onDidPanelDimensionChange.fire({ height: 10, width: 20 }); api._onDidDimensionChange.fire({ height: 10, width: 20 });
expect(api.height).toBe(10); expect(api.height).toBe(10);
expect(api.width).toBe(20); expect(api.width).toBe(20);
api._onDidPanelDimensionChange.fire({ height: 20, width: 10 }); api._onDidDimensionChange.fire({ height: 20, width: 10 });
expect(api.height).toBe(20); expect(api.height).toBe(20);
expect(api.width).toBe(10); expect(api.width).toBe(10);
}); });

View File

@ -100,10 +100,6 @@ export class SplitviewApi implements CommonApi<SerializedSplitview> {
this.component.removePanel(panel, sizing); this.component.removePanel(panel, sizing);
} }
setVisible(panel: ISplitviewPanel, isVisible: boolean): void {
this.component.setVisible(panel, isVisible);
}
focus(): void { focus(): void {
this.component.focus(); this.component.focus();
} }
@ -112,10 +108,6 @@ export class SplitviewApi implements CommonApi<SerializedSplitview> {
return this.component.getPanel(id); return this.component.getPanel(id);
} }
setActive(panel: ISplitviewPanel): void {
this.component.setActive(panel);
}
layout(width: number, height: number): void { layout(width: number, height: number): void {
return this.component.layout(width, height); return this.component.layout(width, height);
} }
@ -310,18 +302,6 @@ export class GridviewApi implements CommonApi<SerializedGridview> {
return this.component.getPanel(id); return this.component.getPanel(id);
} }
toggleVisibility(panel: IGridviewPanel): void {
this.component.toggleVisibility(panel);
}
setVisible(panel: IGridviewPanel, visible: boolean): void {
this.component.setVisible(panel, visible);
}
setActive(panel: IGridviewPanel): void {
this.component.setActive(panel);
}
fromJSON(data: SerializedGridview): void { fromJSON(data: SerializedGridview): void {
return this.component.fromJSON(data); return this.component.fromJSON(data);
} }

View File

@ -23,8 +23,6 @@ export interface PanelApi {
readonly onDidFocusChange: Event<FocusEvent>; readonly onDidFocusChange: Event<FocusEvent>;
readonly onDidVisibilityChange: Event<VisibilityEvent>; readonly onDidVisibilityChange: Event<VisibilityEvent>;
readonly onDidActiveChange: Event<ActiveEvent>; readonly onDidActiveChange: Event<ActiveEvent>;
readonly onFocusEvent: Event<void>;
//
setVisible(isVisible: boolean): void; setVisible(isVisible: boolean): void;
setActive(): void; setActive(): void;
/** /**
@ -63,11 +61,10 @@ export class PanelApiImpl extends CompositeDisposable implements PanelApi {
private _width = 0; private _width = 0;
private _height = 0; private _height = 0;
readonly _onDidPanelDimensionChange = readonly _onDidDimensionChange = new Emitter<PanelDimensionChangeEvent>({
new Emitter<PanelDimensionChangeEvent>({ replay: true,
replay: true, });
}); readonly onDidDimensionsChange = this._onDidDimensionChange.event;
readonly onDidDimensionsChange = this._onDidPanelDimensionChange.event;
// //
readonly _onDidChangeFocus = new Emitter<FocusEvent>({ readonly _onDidChangeFocus = new Emitter<FocusEvent>({
replay: true, replay: true,
@ -121,7 +118,7 @@ export class PanelApiImpl extends CompositeDisposable implements PanelApi {
super(); super();
this.addDisposables( this.addDisposables(
this._onDidPanelDimensionChange, this._onDidDimensionChange,
this._onDidChangeFocus, this._onDidChangeFocus,
this._onDidVisibilityChange, this._onDidVisibilityChange,
this._onDidActiveChange, this._onDidActiveChange,

View File

@ -7,67 +7,6 @@ import { addDisposableListener } from '../../../events';
import { PanelUpdateEvent } from '../../../panel/types'; import { PanelUpdateEvent } from '../../../panel/types';
import { GroupPanel } from '../../../groupview/groupviewPanel'; import { GroupPanel } from '../../../groupview/groupviewPanel';
export class WrappedTab implements ITabRenderer {
private readonly _element: HTMLElement;
constructor(private readonly renderer: ITabRenderer) {
this._element = document.createElement('element');
this.show();
}
get innerRenderer() {
return this.renderer;
}
get element() {
return this._element;
}
get id() {
return this.renderer.id;
}
show() {
if (!this.renderer.element.parentElement) {
this._element.appendChild(this.renderer.element);
}
}
hide() {
if (this.renderer.element.parentElement) {
this.renderer.element.remove();
}
}
layout(width: number, height: number): void {
this.renderer.layout(width, height);
}
update(event: PanelUpdateEvent): void {
this.renderer.update(event);
}
toJSON(): object {
return this.renderer.toJSON();
}
focus(): void {
this.renderer.focus();
}
init(parameters: GroupPanelPartInitParameters): void {
this.renderer.init(parameters);
}
updateParentGroup(group: GroupPanel, isPanelVisible: boolean): void {
this.renderer.updateParentGroup(group, isPanelVisible);
}
dispose() {
this.renderer.dispose();
}
}
export class DefaultTab extends CompositeDisposable implements ITabRenderer { export class DefaultTab extends CompositeDisposable implements ITabRenderer {
private _element: HTMLElement; private _element: HTMLElement;
@ -148,10 +87,16 @@ export class DefaultTab extends CompositeDisposable implements ITabRenderer {
} }
public updateParentGroup(group: GroupPanel, isPanelVisible: boolean) { public updateParentGroup(group: GroupPanel, isPanelVisible: boolean) {
const changed =
this._isPanelVisible !== isPanelVisible ||
this._isGroupActive !== group.isActive;
this._isPanelVisible = isPanelVisible; this._isPanelVisible = isPanelVisible;
this._isGroupActive = group.isActive; this._isGroupActive = group.isActive;
this.render(); if (changed) {
this.render();
}
} }
public layout(_width: number, _height: number) { public layout(_width: number, _height: number) {
@ -159,6 +104,8 @@ export class DefaultTab extends CompositeDisposable implements ITabRenderer {
} }
private render() { private render() {
this._content.textContent = this.params.title; if (this._content.textContent !== this.params.title) {
this._content.textContent = this.params.title;
}
} }
} }

View File

@ -1,4 +1,4 @@
import { DefaultTab, WrappedTab } from './components/tab/defaultTab'; import { DefaultTab } from './components/tab/defaultTab';
import { import {
GroupPanelPartInitParameters, GroupPanelPartInitParameters,
IActionsRenderer, IActionsRenderer,
@ -22,7 +22,7 @@ export interface IGroupPanelView extends IDisposable {
export class DefaultGroupPanelView implements IGroupPanelView { export class DefaultGroupPanelView implements IGroupPanelView {
private readonly _content: IContentRenderer; private readonly _content: IContentRenderer;
private readonly _tab: WrappedTab; private readonly _tab: ITabRenderer;
private readonly _actions: IActionsRenderer | undefined; private readonly _actions: IActionsRenderer | undefined;
get content() { get content() {
@ -43,7 +43,7 @@ export class DefaultGroupPanelView implements IGroupPanelView {
actions?: IActionsRenderer; actions?: IActionsRenderer;
}) { }) {
this._content = renderers.content; this._content = renderers.content;
this._tab = new WrappedTab(renderers.tab ?? new DefaultTab()); this._tab = renderers.tab ?? new DefaultTab();
this._actions = this._actions =
renderers.actions || renderers.actions ||
(this.content.actions (this.content.actions
@ -78,10 +78,7 @@ export class DefaultGroupPanelView implements IGroupPanelView {
toJSON(): {} { toJSON(): {} {
return { return {
content: this.content.toJSON(), content: this.content.toJSON(),
tab: tab: this.tab instanceof DefaultTab ? undefined : this.tab.toJSON(),
this.tab.innerRenderer instanceof DefaultTab
? undefined
: this.tab.toJSON(),
}; };
} }

View File

@ -669,7 +669,7 @@ export class DockviewComponent
} }
const view = new GroupPanel(this, id, options); const view = new GroupPanel(this, id, options);
view.init({ params: {}, containerApi: <any>null }); // required to initialized .part and allow for correct disposal of group view.init({ params: {}, accessor: <any>null }); // required to initialized .part and allow for correct disposal of group
if (!this._groups.has(view.id)) { if (!this._groups.has(view.id)) {
const disposable = new CompositeDisposable( const disposable = new CompositeDisposable(

View File

@ -169,7 +169,7 @@ export class DockviewGroupPanel
public layout(width: number, height: number) { public layout(width: number, height: number) {
// the obtain the correct dimensions of the content panel we must deduct the tab height // the obtain the correct dimensions of the content panel we must deduct the tab height
this.api._onDidPanelDimensionChange.fire({ this.api._onDidDimensionChange.fire({
width, width,
height: height - (this.group.model.header.height || 0), height: height - (this.group.model.header.height || 0),
}); });

View File

@ -90,7 +90,7 @@ export abstract class BasePanelView<T extends PanelApiImpl>
layout(width: number, height: number) { layout(width: number, height: number) {
this._width = width; this._width = width;
this._height = height; this._height = height;
this.api._onDidPanelDimensionChange.fire({ width, height }); this.api._onDidDimensionChange.fire({ width, height });
if (this.part) { if (this.part) {
if (this._params) { if (this._params) {

View File

@ -22,7 +22,6 @@ import {
IGridviewPanel, IGridviewPanel,
} from './gridviewPanel'; } from './gridviewPanel';
import { BaseComponentOptions } from '../panel/types'; import { BaseComponentOptions } from '../panel/types';
import { GridviewApi } from '../api/component.api';
import { Orientation, Sizing } from '../splitview/core/splitview'; import { Orientation, Sizing } from '../splitview/core/splitview';
import { createComponent } from '../panel/componentFactory'; import { createComponent } from '../panel/componentFactory';
import { Emitter, Event } from '../events'; import { Emitter, Event } from '../events';
@ -64,7 +63,6 @@ export interface IGridviewComponent extends IBaseGrid<GridviewPanel> {
updateOptions(options: Partial<GridviewComponentUpdateOptions>): void; updateOptions(options: Partial<GridviewComponentUpdateOptions>): void;
addPanel(options: AddComponentOptions): IGridviewPanel; addPanel(options: AddComponentOptions): IGridviewPanel;
removePanel(panel: IGridviewPanel, sizing?: Sizing): void; removePanel(panel: IGridviewPanel, sizing?: Sizing): void;
toggleVisibility(panel: IGridviewPanel): void;
focus(): void; focus(): void;
fromJSON(serializedGridview: SerializedGridview): void; fromJSON(serializedGridview: SerializedGridview): void;
toJSON(): SerializedGridview; toJSON(): SerializedGridview;
@ -170,10 +168,6 @@ export class GridviewComponent
}); });
} }
toggleVisibility(panel: GridviewPanel) {
this.setVisible(panel, !this.isVisible(panel));
}
focus() { focus() {
this.activeGroup?.focus(); this.activeGroup?.focus();
} }
@ -217,7 +211,7 @@ export class GridviewComponent
maximumHeight: data.maximumHeight, maximumHeight: data.maximumHeight,
priority: data.priority, priority: data.priority,
snap: !!data.snap, snap: !!data.snap,
containerApi: new GridviewApi(this), accessor: this,
isVisible: node.visible, isVisible: node.visible,
}) })
); );
@ -322,7 +316,7 @@ export class GridviewComponent
maximumHeight: options.maximumHeight, maximumHeight: options.maximumHeight,
priority: options.priority, priority: options.priority,
snap: !!options.snap, snap: !!options.snap,
containerApi: new GridviewApi(this), accessor: this,
isVisible: true, isVisible: true,
}); });

View File

@ -1,5 +1,8 @@
import { PanelInitParameters } from '../panel/types'; import { PanelInitParameters } from '../panel/types';
import { IGridPanelComponentView } from './gridviewComponent'; import {
GridviewComponent,
IGridPanelComponentView,
} from './gridviewComponent';
import { FunctionOrValue } from '../types'; import { FunctionOrValue } from '../types';
import { import {
BasePanelView, BasePanelView,
@ -10,7 +13,6 @@ import { GridviewPanelApiImpl } from '../api/gridviewPanelApi';
import { LayoutPriority } from '../splitview/core/splitview'; import { LayoutPriority } from '../splitview/core/splitview';
import { Emitter, Event } from '../events'; import { Emitter, Event } from '../events';
import { IViewSize } from './gridview'; import { IViewSize } from './gridview';
import { GridviewApi } from '../api/component.api';
export interface GridviewInitParameters extends PanelInitParameters { export interface GridviewInitParameters extends PanelInitParameters {
minimumWidth?: number; minimumWidth?: number;
@ -19,7 +21,7 @@ export interface GridviewInitParameters extends PanelInitParameters {
maximumHeight?: number; maximumHeight?: number;
priority?: LayoutPriority; priority?: LayoutPriority;
snap?: boolean; snap?: boolean;
containerApi: GridviewApi; accessor: GridviewComponent;
isVisible?: boolean; isVisible?: boolean;
} }
@ -132,12 +134,12 @@ export abstract class GridviewPanel
this._onDidChange, this._onDidChange,
this.api.onVisibilityChange((event) => { this.api.onVisibilityChange((event) => {
const { isVisible } = event; const { isVisible } = event;
const { containerApi } = this._params as GridviewInitParameters; const { accessor } = this._params as GridviewInitParameters;
containerApi.setVisible(this, isVisible); accessor.setVisible(this, isVisible);
}), }),
this.api.onActiveChange(() => { this.api.onActiveChange(() => {
const { containerApi } = this._params as GridviewInitParameters; const { accessor } = this._params as GridviewInitParameters;
containerApi.setActive(this); accessor.setActive(this);
}), }),
this.api.onDidConstraintsChangeInternal((event) => { this.api.onDidConstraintsChangeInternal((event) => {
if ( if (

View File

@ -5,7 +5,6 @@ import { PanelInitParameters, IPanel } from '../panel/types';
import { DockviewApi } from '../api/component.api'; import { DockviewApi } from '../api/component.api';
import { GroupPanel } from './groupviewPanel'; import { GroupPanel } from './groupviewPanel';
import { Event } from '../events'; import { Event } from '../events';
import { WrappedTab } from '../dockview/components/tab/defaultTab';
export interface IRenderable { export interface IRenderable {
id: string; id: string;
@ -28,7 +27,7 @@ export interface GroupPanelPartInitParameters
export interface GroupPanelContentPartInitParameters export interface GroupPanelContentPartInitParameters
extends GroupPanelPartInitParameters { extends GroupPanelPartInitParameters {
tab: WrappedTab; tab: ITabRenderer;
} }
export interface IWatermarkRenderer extends IPanel { export interface IWatermarkRenderer extends IPanel {
@ -54,7 +53,6 @@ export interface IContentRenderer extends IPanel {
readonly onDidBlur?: Event<void>; readonly onDidBlur?: Event<void>;
updateParentGroup(group: GroupPanel, isPanelVisible: boolean): void; updateParentGroup(group: GroupPanel, isPanelVisible: boolean): void;
init(parameters: GroupPanelContentPartInitParameters): void; init(parameters: GroupPanelContentPartInitParameters): void;
close?(): Promise<boolean>;
} }
// watermark component // watermark component

View File

@ -1,89 +0,0 @@
import * as React from 'react';
import * as ReactDOM from 'react-dom';
import { isReactElement, ReactPartContext } from '../react';
import { ReactContentPartContext } from './reactContentPart';
interface WithChildren {
children: React.ReactNode;
}
const Tab: React.FunctionComponent<WithChildren> = (props: WithChildren) => {
return <>{props.children}</>;
};
const Content: React.FunctionComponent<WithChildren> = (
props: WithChildren
) => {
return <>{props.children}</>;
};
const Actions: React.FunctionComponent<WithChildren> = (
props: WithChildren
) => {
return <>{props.children}</>;
};
function isValidComponent(element: React.ReactElement) {
return [Content, Actions, Tab].find((comp) => element.type === comp);
}
const Panel: React.FunctionComponent<WithChildren> = (props: WithChildren) => {
const context = React.useContext(
ReactPartContext
) as ReactContentPartContext;
const sections = React.useMemo(() => {
const childs =
React.Children.map(props.children, (_) => _)?.filter(
isReactElement
) || [];
const isInvalid = !!childs.find((_) => !isValidComponent(_));
if (isInvalid) {
throw new Error(
'Children of DockviewComponents.Panel must be one of the following: DockviewComponents.Content, DockviewComponents.Actions, DockviewComponents.Tab'
);
}
const body = childs.find((_) => _.type === Content);
const actions = childs.find((_) => _.type === Actions);
const tab = childs.find((_) => _.type === Tab);
return { body, actions, tab };
}, [props.children]);
React.useEffect(() => {
/**
* hide or show the default tab behavior based on whether we want to override
* with our own React tab.
*/
if (sections.tab) {
context.tabPortalElement.hide();
} else {
context.tabPortalElement.show();
}
}, [sections.tab]);
return (
<>
{sections.actions &&
ReactDOM.createPortal(
sections.actions,
context.actionsPortalElement
)}
{sections.tab &&
ReactDOM.createPortal(
sections.tab,
context.tabPortalElement.element
)}
{sections.body || props.children}
</>
);
};
export const DockviewComponents = {
Tab,
Content,
Actions,
Panel,
};

View File

@ -2,6 +2,7 @@ import * as React from 'react';
import { import {
IContentRenderer, IContentRenderer,
GroupPanelContentPartInitParameters, GroupPanelContentPartInitParameters,
ITabRenderer,
} from '../../groupview/types'; } from '../../groupview/types';
import { ReactPart, ReactPortalStore } from '../react'; import { ReactPart, ReactPortalStore } from '../react';
import { IDockviewPanelProps } from '../dockview/dockview'; import { IDockviewPanelProps } from '../dockview/dockview';
@ -10,7 +11,6 @@ import { DockviewPanelApi } from '../../api/groupPanelApi';
import { DockviewApi } from '../../api/component.api'; import { DockviewApi } from '../../api/component.api';
import { GroupPanel } from '../../groupview/groupviewPanel'; import { GroupPanel } from '../../groupview/groupviewPanel';
import { Emitter, Event } from '../../events'; import { Emitter, Event } from '../../events';
import { WrappedTab } from '../../dockview/components/tab/defaultTab';
export interface IGroupPanelActionbarProps { export interface IGroupPanelActionbarProps {
api: DockviewPanelApi; api: DockviewPanelApi;
@ -21,7 +21,7 @@ export interface ReactContentPartContext {
api: DockviewPanelApi; api: DockviewPanelApi;
containerApi: DockviewApi; containerApi: DockviewApi;
actionsPortalElement: HTMLElement; actionsPortalElement: HTMLElement;
tabPortalElement: WrappedTab; tabPortalElement: ITabRenderer;
} }
export class ReactPanelContentPart implements IContentRenderer { export class ReactPanelContentPart implements IContentRenderer {
@ -104,10 +104,6 @@ export class ReactPanelContentPart implements IContentRenderer {
// noop // noop
} }
public close(): Promise<boolean> {
return Promise.resolve(true);
}
public dispose() { public dispose() {
this._onDidFocus.dispose(); this._onDidFocus.dispose();
this._onDidBlur.dispose(); this._onDidBlur.dispose();

View File

@ -99,10 +99,6 @@ export class ReactContentRenderer implements IContentRenderer {
this._hostedContainer.layout(this.element); this._hostedContainer.layout(this.element);
} }
public close(): Promise<boolean> {
return Promise.resolve(true);
}
public dispose() { public dispose() {
this.part?.dispose(); this.part?.dispose();
} }

View File

@ -1,3 +1,4 @@
import { GridviewApi } from '../../api/component.api';
import { import {
GridviewPanel, GridviewPanel,
GridviewInitParameters, GridviewInitParameters,
@ -24,8 +25,9 @@ export class ReactGridPanelView extends GridviewPanel {
{ {
params: this._params?.params || {}, params: this._params?.params || {},
api: this.api, api: this.api,
containerApi: (this._params as GridviewInitParameters) containerApi: new GridviewApi(
.containerApi, (this._params as GridviewInitParameters).accessor
),
} }
); );
} }

View File

@ -1,5 +1,4 @@
export * from './dockview/dockview'; export * from './dockview/dockview';
export * from './dockview/components';
export * from './splitview/splitview'; export * from './splitview/splitview';
export * from './gridview/gridview'; export * from './gridview/gridview';
export * from './dockview/reactContentPart'; export * from './dockview/reactContentPart';

View File

@ -1,3 +1,4 @@
import { SplitviewApi } from '../../api/component.api';
import { PanelViewInitParameters } from '../../splitview/core/options'; import { PanelViewInitParameters } from '../../splitview/core/options';
import { SplitviewPanel } from '../../splitview/splitviewPanel'; import { SplitviewPanel } from '../../splitview/splitviewPanel';
import { ReactPart, ReactPortalStore } from '../react'; import { ReactPart, ReactPortalStore } from '../react';
@ -21,8 +22,9 @@ export class ReactPanelView extends SplitviewPanel {
{ {
params: this._params?.params || {}, params: this._params?.params || {},
api: this.api, api: this.api,
containerApi: (this._params as PanelViewInitParameters) containerApi: new SplitviewApi(
.containerApi, (this._params as PanelViewInitParameters).accessor
),
} }
); );
} }

View File

@ -2,14 +2,14 @@ import { IPanel, PanelInitParameters } from '../../panel/types';
import { IView, SplitViewOptions, LayoutPriority } from './splitview'; import { IView, SplitViewOptions, LayoutPriority } from './splitview';
import { FrameworkFactory } from '../../types'; import { FrameworkFactory } from '../../types';
import { SplitviewPanel } from '../splitviewPanel'; import { SplitviewPanel } from '../splitviewPanel';
import { SplitviewApi } from '../../api/component.api'; import { SplitviewComponent } from '../splitviewComponent';
export interface PanelViewInitParameters extends PanelInitParameters { export interface PanelViewInitParameters extends PanelInitParameters {
minimumSize?: number; minimumSize?: number;
maximumSize?: number; maximumSize?: number;
snap?: boolean; snap?: boolean;
priority?: LayoutPriority; priority?: LayoutPriority;
containerApi: SplitviewApi; accessor: SplitviewComponent;
} }
export interface ISerializableView extends IView, IPanel { export interface ISerializableView extends IView, IPanel {

View File

@ -14,7 +14,6 @@ import {
import { SplitviewComponentOptions } from './core/options'; import { SplitviewComponentOptions } from './core/options';
import { BaseComponentOptions } from '../panel/types'; import { BaseComponentOptions } from '../panel/types';
import { Emitter, Event } from '../events'; import { Emitter, Event } from '../events';
import { SplitviewApi } from '../api/component.api';
import { SplitviewPanel, ISplitviewPanel } from './splitviewPanel'; import { SplitviewPanel, ISplitviewPanel } from './splitviewPanel';
import { createComponent } from '../panel/componentFactory'; import { createComponent } from '../panel/componentFactory';
@ -70,7 +69,6 @@ export interface ISplitviewComponent extends IDisposable {
fromJSON(serializedSplitview: SerializedSplitview): void; fromJSON(serializedSplitview: SerializedSplitview): void;
focus(): void; focus(): void;
getPanel(id: string): ISplitviewPanel | undefined; getPanel(id: string): ISplitviewPanel | undefined;
setActive(view: ISplitviewPanel, skipFocus?: boolean): void;
removePanel(panel: ISplitviewPanel, sizing?: Sizing): void; removePanel(panel: ISplitviewPanel, sizing?: Sizing): void;
setVisible(panel: ISplitviewPanel, visible: boolean): void; setVisible(panel: ISplitviewPanel, visible: boolean): void;
movePanel(from: number, to: number): void; movePanel(from: number, to: number): void;
@ -279,7 +277,7 @@ export class SplitviewComponent
maximumSize: options.maximumSize, maximumSize: options.maximumSize,
snap: options.snap, snap: options.snap,
priority: options.priority, priority: options.priority,
containerApi: new SplitviewApi(this), accessor: this,
}); });
const size: Sizing | number = const size: Sizing | number =
@ -380,7 +378,7 @@ export class SplitviewComponent
maximumSize: data.maximumSize, maximumSize: data.maximumSize,
snap: view.snap, snap: view.snap,
priority: view.priority, priority: view.priority,
containerApi: new SplitviewApi(this), accessor: this,
}); });
}); });

View File

@ -85,14 +85,12 @@ export abstract class SplitviewPanel
this._onDidChange, this._onDidChange,
this.api.onVisibilityChange((event) => { this.api.onVisibilityChange((event) => {
const { isVisible } = event; const { isVisible } = event;
const { containerApi } = this const { accessor } = this._params as PanelViewInitParameters;
._params as PanelViewInitParameters; accessor.setVisible(this, isVisible);
containerApi.setVisible(this, isVisible);
}), }),
this.api.onActiveChange(() => { this.api.onActiveChange(() => {
const { containerApi } = this const { accessor } = this._params as PanelViewInitParameters;
._params as PanelViewInitParameters; accessor.setActive(this);
containerApi.setActive(this);
}), }),
this.api.onDidConstraintsChangeInternal((event) => { this.api.onDidConstraintsChangeInternal((event) => {
if ( if (