mirror of
https://github.com/mathuo/dockview
synced 2025-02-22 16:15:45 +00:00
feat: persistance and rendering
This commit is contained in:
parent
37b0a062a4
commit
f26a1cd404
@ -1,8 +1,9 @@
|
||||
import { DefaultGroupPanelView } from '../../dockview/defaultGroupPanelView';
|
||||
import { GroupPanel } from '../../groupview/groupviewPanel';
|
||||
import { IContentRenderer, ITabRenderer } from '../../groupview/types';
|
||||
|
||||
describe('defaultGroupPanelView', () => {
|
||||
test('dispose cleanup', () => {
|
||||
test('that dispose is called on content and tab renderers when present', () => {
|
||||
const contentMock = jest.fn<IContentRenderer, []>(() => {
|
||||
const partial: Partial<IContentRenderer> = {
|
||||
element: document.createElement('div'),
|
||||
@ -22,11 +23,109 @@ describe('defaultGroupPanelView', () => {
|
||||
const content = new contentMock();
|
||||
const tab = new tabMock();
|
||||
|
||||
const cut = new DefaultGroupPanelView({ content, tab });
|
||||
const cut = new DefaultGroupPanelView({
|
||||
content,
|
||||
tab,
|
||||
contentComponent: 'contentComponent',
|
||||
});
|
||||
|
||||
cut.dispose();
|
||||
|
||||
expect(content.dispose).toHaveBeenCalled();
|
||||
expect(tab.dispose).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
test('that update is called on content and tab renderers when present', () => {
|
||||
const contentMock = jest.fn<IContentRenderer, []>(() => {
|
||||
const partial: Partial<IContentRenderer> = {
|
||||
element: document.createElement('div'),
|
||||
update: jest.fn(),
|
||||
};
|
||||
return partial as IContentRenderer;
|
||||
});
|
||||
|
||||
const tabMock = jest.fn<ITabRenderer, []>(() => {
|
||||
const partial: Partial<IContentRenderer> = {
|
||||
element: document.createElement('div'),
|
||||
update: jest.fn(),
|
||||
};
|
||||
return partial as IContentRenderer;
|
||||
});
|
||||
|
||||
const content = new contentMock();
|
||||
const tab = new tabMock();
|
||||
|
||||
const cut = new DefaultGroupPanelView({
|
||||
content,
|
||||
tab,
|
||||
contentComponent: 'contentComponent',
|
||||
});
|
||||
|
||||
cut.update({
|
||||
params: {},
|
||||
});
|
||||
|
||||
expect(content.update).toHaveBeenCalled();
|
||||
expect(tab.update).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
test('test1', () => {
|
||||
const contentMock = jest.fn<IContentRenderer, []>(() => {
|
||||
const partial: Partial<IContentRenderer> = {
|
||||
element: document.createElement('div'),
|
||||
onGroupChange: jest.fn(),
|
||||
onPanelVisibleChange: jest.fn(),
|
||||
};
|
||||
return partial as IContentRenderer;
|
||||
});
|
||||
|
||||
const tabMock = jest.fn<ITabRenderer, []>(() => {
|
||||
const partial: Partial<IContentRenderer> = {
|
||||
element: document.createElement('div'),
|
||||
onGroupChange: jest.fn(),
|
||||
onPanelVisibleChange: jest.fn(),
|
||||
};
|
||||
return partial as IContentRenderer;
|
||||
});
|
||||
|
||||
const content = new contentMock();
|
||||
const tab = new tabMock();
|
||||
|
||||
let cut = new DefaultGroupPanelView({
|
||||
content,
|
||||
tab,
|
||||
contentComponent: 'contentComponent',
|
||||
});
|
||||
|
||||
const group1 = jest.fn() as any;
|
||||
const group2 = jest.fn() as any;
|
||||
cut.updateParentGroup(group1 as GroupPanel, false);
|
||||
|
||||
expect(content.onGroupChange).toHaveBeenNthCalledWith(1, group1);
|
||||
expect(tab.onGroupChange).toHaveBeenNthCalledWith(1, group1);
|
||||
expect(content.onPanelVisibleChange).toHaveBeenNthCalledWith(1, false);
|
||||
expect(tab.onPanelVisibleChange).toHaveBeenNthCalledWith(1, false);
|
||||
expect(content.onGroupChange).toHaveBeenCalledTimes(1);
|
||||
expect(tab.onGroupChange).toHaveBeenCalledTimes(1);
|
||||
expect(content.onPanelVisibleChange).toHaveBeenCalledTimes(1);
|
||||
expect(tab.onPanelVisibleChange).toHaveBeenCalledTimes(1);
|
||||
|
||||
cut.updateParentGroup(group1 as GroupPanel, true);
|
||||
|
||||
expect(content.onPanelVisibleChange).toHaveBeenNthCalledWith(2, true);
|
||||
expect(tab.onPanelVisibleChange).toHaveBeenNthCalledWith(2, true);
|
||||
expect(content.onGroupChange).toHaveBeenCalledTimes(1);
|
||||
expect(tab.onGroupChange).toHaveBeenCalledTimes(1);
|
||||
expect(content.onPanelVisibleChange).toHaveBeenCalledTimes(2);
|
||||
expect(tab.onPanelVisibleChange).toHaveBeenCalledTimes(2);
|
||||
|
||||
cut.updateParentGroup(group2 as GroupPanel, true);
|
||||
|
||||
expect(content.onGroupChange).toHaveBeenNthCalledWith(2, group2);
|
||||
expect(tab.onGroupChange).toHaveBeenNthCalledWith(2, group2);
|
||||
expect(content.onGroupChange).toHaveBeenCalledTimes(2);
|
||||
expect(tab.onGroupChange).toHaveBeenCalledTimes(2);
|
||||
expect(content.onPanelVisibleChange).toHaveBeenCalledTimes(2);
|
||||
expect(tab.onPanelVisibleChange).toHaveBeenCalledTimes(2);
|
||||
});
|
||||
});
|
||||
|
@ -8,8 +8,6 @@ import { PanelUpdateEvent } from '../../../panel/types';
|
||||
import { GroupPanel } from '../../../groupview/groupviewPanel';
|
||||
import { createCloseButton } from '../../../svg';
|
||||
|
||||
export const DEFAULT_TAB_IDENTIFIER = '__default__tab__';
|
||||
|
||||
export class DefaultTab extends CompositeDisposable implements ITabRenderer {
|
||||
private _element: HTMLElement;
|
||||
|
||||
@ -26,10 +24,6 @@ export class DefaultTab extends CompositeDisposable implements ITabRenderer {
|
||||
return this._element;
|
||||
}
|
||||
|
||||
get id() {
|
||||
return DEFAULT_TAB_IDENTIFIER;
|
||||
}
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
@ -69,18 +63,13 @@ export class DefaultTab extends CompositeDisposable implements ITabRenderer {
|
||||
this.render();
|
||||
}
|
||||
|
||||
public toJSON() {
|
||||
return { id: this.id };
|
||||
}
|
||||
|
||||
focus() {
|
||||
//noop
|
||||
}
|
||||
|
||||
public init(params: GroupPanelPartInitParameters) {
|
||||
this.params = params;
|
||||
this._content.textContent =
|
||||
typeof params.title === 'string' ? params.title : this.id;
|
||||
this._content.textContent = params.title;
|
||||
|
||||
addDisposableListener(this.action, 'click', (ev) => {
|
||||
ev.preventDefault(); //
|
||||
@ -107,10 +96,7 @@ export class DefaultTab extends CompositeDisposable implements ITabRenderer {
|
||||
|
||||
private render() {
|
||||
if (this._content.textContent !== this.params.title) {
|
||||
this._content.textContent =
|
||||
typeof this.params.title === 'string'
|
||||
? this.params.title
|
||||
: this.id;
|
||||
this._content.textContent = this.params.title;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -7,21 +7,32 @@ import {
|
||||
} from '../groupview/types';
|
||||
import { GroupPanel } from '../groupview/groupviewPanel';
|
||||
import { IDisposable } from '../lifecycle';
|
||||
import { createComponent } from '../panel/componentFactory';
|
||||
import { IDockviewComponent } from './dockviewComponent';
|
||||
|
||||
export interface SerializedGroupPanelView {
|
||||
tab?: { id: string };
|
||||
content: { id: string };
|
||||
}
|
||||
|
||||
export interface IGroupPanelView extends IDisposable {
|
||||
readonly contentComponent: string;
|
||||
readonly tabComponent?: string;
|
||||
readonly content: IContentRenderer;
|
||||
readonly tab?: ITabRenderer;
|
||||
update(event: GroupPanelUpdateEvent): void;
|
||||
layout(width: number, height: number): void;
|
||||
init(params: GroupPanelPartInitParameters): void;
|
||||
updateParentGroup(group: GroupPanel, isPanelVisible: boolean): void;
|
||||
toJSON(): {};
|
||||
}
|
||||
|
||||
export class DefaultGroupPanelView implements IGroupPanelView {
|
||||
private readonly _content: IContentRenderer;
|
||||
private readonly _tab: ITabRenderer;
|
||||
|
||||
private _group: GroupPanel | null = null;
|
||||
private _isPanelVisible: boolean | null = null;
|
||||
|
||||
get content(): IContentRenderer {
|
||||
return this._content;
|
||||
}
|
||||
@ -30,9 +41,15 @@ export class DefaultGroupPanelView implements IGroupPanelView {
|
||||
return this._tab;
|
||||
}
|
||||
|
||||
constructor(renderers: { content: IContentRenderer; tab?: ITabRenderer }) {
|
||||
this._content = renderers.content;
|
||||
this._tab = renderers.tab ?? new DefaultTab();
|
||||
constructor(
|
||||
private readonly accessor: IDockviewComponent,
|
||||
private readonly id: string,
|
||||
readonly contentComponent: string,
|
||||
readonly tabComponent?: string
|
||||
) {
|
||||
this._content = this.createContentComponent(this.id, contentComponent);
|
||||
this._tab =
|
||||
this.createTabComponent(this.id, tabComponent) ?? new DefaultTab();
|
||||
}
|
||||
|
||||
init(params: GroupPanelPartInitParameters): void {
|
||||
@ -41,35 +58,65 @@ export class DefaultGroupPanelView implements IGroupPanelView {
|
||||
}
|
||||
|
||||
updateParentGroup(group: GroupPanel, isPanelVisible: boolean): void {
|
||||
this._content.updateParentGroup(group, isPanelVisible);
|
||||
this._tab?.updateParentGroup(group, isPanelVisible);
|
||||
if (group !== this._group) {
|
||||
this._group = group;
|
||||
if (this._content.onGroupChange) {
|
||||
this._content.onGroupChange(group);
|
||||
}
|
||||
if (this._tab.onGroupChange) {
|
||||
this._tab.onGroupChange(group);
|
||||
}
|
||||
}
|
||||
|
||||
if (isPanelVisible !== this._isPanelVisible) {
|
||||
this._isPanelVisible = isPanelVisible;
|
||||
if (this._content.onPanelVisibleChange) {
|
||||
this._content.onPanelVisibleChange(isPanelVisible);
|
||||
}
|
||||
if (this._tab.onPanelVisibleChange) {
|
||||
this._tab.onPanelVisibleChange(isPanelVisible);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
layout(width: number, height: number): void {
|
||||
this.content.layout(width, height);
|
||||
this.content.layout?.(width, height);
|
||||
}
|
||||
|
||||
update(event: GroupPanelUpdateEvent): void {
|
||||
this.content.update(event);
|
||||
this.tab.update(event);
|
||||
}
|
||||
|
||||
toJSON(): {} {
|
||||
let tab =
|
||||
this.tab instanceof DefaultTab ? undefined : this.tab.toJSON();
|
||||
|
||||
if (tab && Object.keys(tab).length === 0) {
|
||||
tab = undefined;
|
||||
}
|
||||
|
||||
return {
|
||||
content: this.content.toJSON(),
|
||||
tab,
|
||||
};
|
||||
this.content.update?.(event);
|
||||
this.tab.update?.(event);
|
||||
}
|
||||
|
||||
dispose(): void {
|
||||
this.content.dispose();
|
||||
this.tab.dispose();
|
||||
this.content.dispose?.();
|
||||
this.tab.dispose?.();
|
||||
}
|
||||
|
||||
private createContentComponent(
|
||||
id: string,
|
||||
componentName: string
|
||||
): IContentRenderer {
|
||||
return createComponent(
|
||||
id,
|
||||
componentName,
|
||||
this.accessor.options.components || {},
|
||||
this.accessor.options.frameworkComponents,
|
||||
this.accessor.options.frameworkComponentFactory?.content
|
||||
);
|
||||
}
|
||||
|
||||
private createTabComponent(
|
||||
id: string,
|
||||
componentName?: string
|
||||
): ITabRenderer {
|
||||
return createComponent(
|
||||
id,
|
||||
componentName,
|
||||
this.accessor.options.tabComponents || {},
|
||||
this.accessor.options.frameworkTabComponents,
|
||||
this.accessor.options.frameworkComponentFactory?.tab,
|
||||
() => new DefaultTab()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
import { GroupviewPanelState, ITabRenderer } from '../groupview/types';
|
||||
import { GroupPanel } from '../groupview/groupviewPanel';
|
||||
import { DockviewPanel, IDockviewPanel } from './dockviewPanel';
|
||||
import { DockviewComponent } from './dockviewComponent';
|
||||
import { IDockviewComponent } from './dockviewComponent';
|
||||
import { createComponent } from '../panel/componentFactory';
|
||||
import { DefaultTab } from './components/tab/defaultTab';
|
||||
import { DefaultGroupPanelView } from './defaultGroupPanelView';
|
||||
@ -12,7 +12,7 @@ export interface IPanelDeserializer {
|
||||
}
|
||||
|
||||
export class DefaultDockviewDeserialzier implements IPanelDeserializer {
|
||||
constructor(private readonly layout: DockviewComponent) {}
|
||||
constructor(private readonly layout: IDockviewComponent) {}
|
||||
|
||||
public fromJSON(
|
||||
panelData: GroupviewPanelState,
|
||||
@ -21,14 +21,21 @@ export class DefaultDockviewDeserialzier implements IPanelDeserializer {
|
||||
const panelId = panelData.id;
|
||||
const params = panelData.params;
|
||||
const title = panelData.title;
|
||||
const viewData = panelData.view;
|
||||
const viewData = panelData.view!;
|
||||
|
||||
let tab: ITabRenderer;
|
||||
|
||||
if (viewData.tab?.id) {
|
||||
const contentComponent = viewData
|
||||
? viewData.content.id
|
||||
: panelData.contentComponent || 'unknown';
|
||||
const tabComponent = viewData
|
||||
? viewData.tab?.id
|
||||
: panelData.tabComponent;
|
||||
|
||||
if (tabComponent) {
|
||||
tab = createComponent(
|
||||
viewData.tab.id,
|
||||
viewData.tab.id,
|
||||
panelId,
|
||||
tabComponent,
|
||||
this.layout.options.tabComponents,
|
||||
this.layout.options.frameworkTabComponents,
|
||||
this.layout.options.frameworkComponentFactory?.tab,
|
||||
@ -36,7 +43,7 @@ export class DefaultDockviewDeserialzier implements IPanelDeserializer {
|
||||
);
|
||||
} else if (this.layout.options.defaultTabComponent) {
|
||||
tab = createComponent(
|
||||
this.layout.options.defaultTabComponent,
|
||||
panelId,
|
||||
this.layout.options.defaultTabComponent,
|
||||
this.layout.options.tabComponents,
|
||||
this.layout.options.frameworkTabComponents,
|
||||
@ -47,16 +54,12 @@ export class DefaultDockviewDeserialzier implements IPanelDeserializer {
|
||||
tab = new DefaultTab();
|
||||
}
|
||||
|
||||
const view = new DefaultGroupPanelView({
|
||||
content: createComponent(
|
||||
viewData.content.id,
|
||||
viewData.content.id,
|
||||
this.layout.options.components,
|
||||
this.layout.options.frameworkComponents,
|
||||
this.layout.options.frameworkComponentFactory?.content
|
||||
),
|
||||
tab,
|
||||
});
|
||||
const view = new DefaultGroupPanelView(
|
||||
this.layout,
|
||||
panelId,
|
||||
contentComponent,
|
||||
tabComponent
|
||||
);
|
||||
|
||||
const panel = new DockviewPanel(
|
||||
panelId,
|
||||
@ -67,7 +70,7 @@ export class DefaultDockviewDeserialzier implements IPanelDeserializer {
|
||||
|
||||
panel.init({
|
||||
view,
|
||||
title,
|
||||
title: title || panelId,
|
||||
params: params || {},
|
||||
});
|
||||
|
||||
|
@ -950,13 +950,16 @@ export class DockviewComponent
|
||||
options: AddPanelOptions,
|
||||
group: GroupPanel
|
||||
): IDockviewPanel {
|
||||
const view = new DefaultGroupPanelView({
|
||||
content: this.createContentComponent(options.id, options.component),
|
||||
tab: this.createTabComponent(
|
||||
const contentComponent = options.component;
|
||||
const tabComponent =
|
||||
options.tabComponent || this.options.defaultTabComponent;
|
||||
|
||||
const view = new DefaultGroupPanelView(
|
||||
this,
|
||||
options.id,
|
||||
options.tabComponent || this.options.defaultTabComponent
|
||||
),
|
||||
});
|
||||
contentComponent,
|
||||
tabComponent
|
||||
);
|
||||
|
||||
const panel = new DockviewPanel(options.id, this, this._api, group);
|
||||
panel.init({
|
||||
@ -968,33 +971,6 @@ export class DockviewComponent
|
||||
return panel;
|
||||
}
|
||||
|
||||
private createContentComponent(
|
||||
id: string,
|
||||
componentName: string
|
||||
): IContentRenderer {
|
||||
return createComponent(
|
||||
id,
|
||||
componentName,
|
||||
this.options.components || {},
|
||||
this.options.frameworkComponents,
|
||||
this.options.frameworkComponentFactory?.content
|
||||
);
|
||||
}
|
||||
|
||||
private createTabComponent(
|
||||
id: string,
|
||||
componentName?: string
|
||||
): ITabRenderer {
|
||||
return createComponent(
|
||||
id,
|
||||
componentName,
|
||||
this.options.tabComponents || {},
|
||||
this.options.frameworkTabComponents,
|
||||
this.options.frameworkComponentFactory?.tab,
|
||||
() => new DefaultTab()
|
||||
);
|
||||
}
|
||||
|
||||
private createGroupAtLocation(location: number[] = [0]): GroupPanel {
|
||||
const group = this.createGroup();
|
||||
this.doAddGroup(group, location);
|
||||
|
@ -12,7 +12,7 @@ import { GroupPanel } from '../groupview/groupviewPanel';
|
||||
import { CompositeDisposable, IDisposable } from '../lifecycle';
|
||||
import { IPanel, Parameters } from '../panel/types';
|
||||
import { IGroupPanelView } from './defaultGroupPanelView';
|
||||
import { DockviewComponent } from './dockviewComponent';
|
||||
import { IDockviewComponent } from './dockviewComponent';
|
||||
|
||||
export interface IDockviewPanel extends IDisposable, IPanel {
|
||||
readonly view?: IGroupPanelView;
|
||||
@ -56,7 +56,7 @@ export class DockviewPanel
|
||||
|
||||
constructor(
|
||||
public readonly id: string,
|
||||
accessor: DockviewComponent,
|
||||
accessor: IDockviewComponent,
|
||||
private readonly containerApi: DockviewApi,
|
||||
group: GroupPanel
|
||||
) {
|
||||
@ -82,9 +82,7 @@ export class DockviewPanel
|
||||
this._params = params.params;
|
||||
this._view = params.view;
|
||||
|
||||
if (typeof params.title === 'string') {
|
||||
this.setTitle(params.title);
|
||||
}
|
||||
|
||||
this.view?.init({
|
||||
...params,
|
||||
@ -100,7 +98,8 @@ export class DockviewPanel
|
||||
public toJSON(): GroupviewPanelState {
|
||||
return <GroupviewPanelState>{
|
||||
id: this.id,
|
||||
view: this.view!.toJSON(),
|
||||
contentComponent: this.view?.contentComponent,
|
||||
tabComponent: this.view?.tabComponent,
|
||||
params:
|
||||
Object.keys(this._params || {}).length > 0
|
||||
? this._params
|
||||
@ -133,12 +132,10 @@ export class DockviewPanel
|
||||
...event.params.params,
|
||||
};
|
||||
|
||||
if (typeof params.title === 'string') {
|
||||
if (params.title !== this.title) {
|
||||
this._title = params.title;
|
||||
this.api._onDidTitleChange.fire({ title: this.title });
|
||||
}
|
||||
}
|
||||
|
||||
this.view?.update({
|
||||
params: {
|
||||
|
@ -235,14 +235,14 @@ export abstract class BaseGrid<T extends IGridPanelView>
|
||||
if (this._activeGroup) {
|
||||
this._activeGroup.setActive(false);
|
||||
if (!skipFocus) {
|
||||
this._activeGroup.focus();
|
||||
this._activeGroup.focus?.();
|
||||
}
|
||||
}
|
||||
|
||||
if (group) {
|
||||
group.setActive(true);
|
||||
if (!skipFocus) {
|
||||
group.focus();
|
||||
group.focus?.();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -40,15 +40,15 @@ export abstract class BasePanelView<T extends PanelApiImpl>
|
||||
*/
|
||||
protected abstract getComponent(): IFrameworkPart;
|
||||
|
||||
get element() {
|
||||
get element(): HTMLElement {
|
||||
return this._element;
|
||||
}
|
||||
|
||||
get width() {
|
||||
get width(): number {
|
||||
return this._width;
|
||||
}
|
||||
|
||||
get height() {
|
||||
get height(): number {
|
||||
return this._height;
|
||||
}
|
||||
|
||||
@ -83,11 +83,11 @@ export abstract class BasePanelView<T extends PanelApiImpl>
|
||||
);
|
||||
}
|
||||
|
||||
focus() {
|
||||
focus(): void {
|
||||
this.api._onFocusEvent.fire();
|
||||
}
|
||||
|
||||
layout(width: number, height: number) {
|
||||
layout(width: number, height: number): void {
|
||||
this._width = width;
|
||||
this._height = height;
|
||||
this.api._onDidDimensionChange.fire({ width, height });
|
||||
@ -104,7 +104,7 @@ export abstract class BasePanelView<T extends PanelApiImpl>
|
||||
this.part = this.getComponent();
|
||||
}
|
||||
|
||||
update(event: PanelUpdateEvent) {
|
||||
update(event: PanelUpdateEvent): void {
|
||||
this._params = {
|
||||
...this._params,
|
||||
params: {
|
||||
@ -125,7 +125,7 @@ export abstract class BasePanelView<T extends PanelApiImpl>
|
||||
};
|
||||
}
|
||||
|
||||
dispose() {
|
||||
dispose(): void {
|
||||
super.dispose();
|
||||
|
||||
this.api.dispose();
|
||||
|
@ -77,7 +77,7 @@ export interface IHeader {
|
||||
height: number | undefined;
|
||||
}
|
||||
|
||||
export interface IGroupview extends IDisposable, IGridPanelView {
|
||||
export interface IGroupview extends IGridPanelView {
|
||||
readonly isActive: boolean;
|
||||
readonly size: number;
|
||||
readonly panels: IDockviewPanel[];
|
||||
@ -427,7 +427,7 @@ export class Groupview extends CompositeDisposable implements IGroupview {
|
||||
}
|
||||
|
||||
focus(): void {
|
||||
this._activePanel?.focus();
|
||||
this._activePanel?.focus?.();
|
||||
}
|
||||
|
||||
public openPanel(
|
||||
@ -525,7 +525,7 @@ export class Groupview extends CompositeDisposable implements IGroupview {
|
||||
): void {
|
||||
if (!force && this.isActive === isGroupActive) {
|
||||
if (!skipFocus) {
|
||||
this._activePanel?.focus();
|
||||
this._activePanel?.focus?.();
|
||||
}
|
||||
return;
|
||||
}
|
||||
@ -545,7 +545,7 @@ export class Groupview extends CompositeDisposable implements IGroupview {
|
||||
|
||||
if (isGroupActive) {
|
||||
if (!skipFocus) {
|
||||
this._activePanel?.focus();
|
||||
this._activePanel?.focus?.();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -74,9 +74,8 @@ export class ContentContainer
|
||||
const disposable = new CompositeDisposable();
|
||||
|
||||
if (this.panel.view) {
|
||||
const _onDidFocus: Event<void> =
|
||||
this.panel.view.content.onDidFocus!;
|
||||
const _onDidBlur: Event<void> = this.panel.view.content.onDidBlur!;
|
||||
const _onDidFocus = this.panel.view.content.onDidFocus;
|
||||
const _onDidBlur = this.panel.view.content.onDidBlur;
|
||||
|
||||
const { onDidFocus, onDidBlur } = trackFocus(this._element);
|
||||
|
||||
|
@ -9,7 +9,11 @@ import {
|
||||
import { DockviewApi } from '../api/component.api';
|
||||
import { GroupPanel } from './groupviewPanel';
|
||||
import { Event } from '../events';
|
||||
import { IGroupPanelView } from '../dockview/defaultGroupPanelView';
|
||||
import {
|
||||
IGroupPanelView,
|
||||
SerializedGroupPanelView,
|
||||
} from '../dockview/defaultGroupPanelView';
|
||||
import { Optional } from '../types';
|
||||
|
||||
export interface IRenderable {
|
||||
id: string;
|
||||
@ -19,7 +23,7 @@ export interface IRenderable {
|
||||
}
|
||||
|
||||
export interface HeaderPartInitParameters {
|
||||
title?: string;
|
||||
title: string;
|
||||
}
|
||||
|
||||
export interface GroupPanelPartInitParameters
|
||||
@ -40,20 +44,28 @@ export interface IWatermarkRenderer extends IPanel {
|
||||
updateParentGroup(group: GroupPanel, visible: boolean): void;
|
||||
}
|
||||
|
||||
export interface ITabRenderer extends IPanel {
|
||||
export interface ITabRenderer
|
||||
extends Optional<
|
||||
Omit<IPanel, 'id'>,
|
||||
'dispose' | 'update' | 'layout' | 'toJSON'
|
||||
> {
|
||||
readonly element: HTMLElement;
|
||||
init(parameters: GroupPanelPartInitParameters): void;
|
||||
updateParentGroup(group: GroupPanel, isPanelVisible: boolean): void;
|
||||
onGroupChange?(group: GroupPanel): void;
|
||||
onPanelVisibleChange?(isPanelVisible: boolean): void;
|
||||
}
|
||||
|
||||
export interface IContentRenderer extends IPanel {
|
||||
export interface IContentRenderer
|
||||
extends Optional<
|
||||
Omit<IPanel, 'id'>,
|
||||
'dispose' | 'update' | 'layout' | 'toJSON'
|
||||
> {
|
||||
readonly element: HTMLElement;
|
||||
readonly actions?: HTMLElement;
|
||||
readonly onDidFocus?: Event<void>;
|
||||
readonly onDidBlur?: Event<void>;
|
||||
updateParentGroup(group: GroupPanel, isPanelVisible: boolean): void;
|
||||
init(parameters: GroupPanelContentPartInitParameters): void;
|
||||
layout(width: number, height: number): void;
|
||||
onGroupChange?(group: GroupPanel): void;
|
||||
onPanelVisibleChange?(isPanelVisible: boolean): void;
|
||||
}
|
||||
|
||||
// watermark component
|
||||
@ -88,7 +100,9 @@ export type GroupPanelUpdateEvent = PanelUpdateEvent<{
|
||||
|
||||
export interface GroupviewPanelState {
|
||||
id: string;
|
||||
view?: any;
|
||||
contentComponent?: string;
|
||||
tabComponent?: string;
|
||||
title?: string;
|
||||
params?: { [key: string]: any };
|
||||
view?: SerializedGroupPanelView; // depreciated
|
||||
}
|
||||
|
@ -22,7 +22,7 @@ export interface IPanel extends IDisposable {
|
||||
layout(width: number, height: number): void;
|
||||
update(event: PanelUpdateEvent<Parameters>): void;
|
||||
toJSON(): object;
|
||||
focus(): void;
|
||||
focus?(): void;
|
||||
}
|
||||
|
||||
export interface IFrameworkPart extends IDisposable {
|
||||
|
@ -11,3 +11,5 @@ export type FunctionOrValue<T> = (() => T) | T;
|
||||
export function isBooleanValue(value: any): value is boolean {
|
||||
return typeof value === 'boolean';
|
||||
}
|
||||
|
||||
export type Optional<T, K extends keyof T> = Pick<Partial<T>, K> & Omit<T, K>;
|
||||
|
@ -11,7 +11,6 @@ import {
|
||||
ITabRenderer,
|
||||
watchElementResize,
|
||||
GroupPanel,
|
||||
DEFAULT_TAB_IDENTIFIER,
|
||||
DefaultDockviewDeserialzier,
|
||||
} from 'dockview-core';
|
||||
import { ReactPanelContentPart } from './reactContentPart';
|
||||
@ -72,6 +71,8 @@ export interface IDockviewReactProps {
|
||||
singleTabMode?: 'fullwidth' | 'default';
|
||||
}
|
||||
|
||||
const DEFAULT_REACT_TAB = 'props.defaultTabComponent';
|
||||
|
||||
export const DockviewReact = React.forwardRef(
|
||||
(props: IDockviewReactProps, ref: React.ForwardedRef<HTMLDivElement>) => {
|
||||
const domRef = React.useRef<HTMLDivElement>(null);
|
||||
@ -144,16 +145,22 @@ export const DockviewReact = React.forwardRef(
|
||||
|
||||
const element = document.createElement('div');
|
||||
|
||||
const frameworkTabComponents = props.tabComponents || {};
|
||||
|
||||
if (props.defaultTabComponent) {
|
||||
frameworkTabComponents[DEFAULT_REACT_TAB] =
|
||||
props.defaultTabComponent;
|
||||
}
|
||||
|
||||
const dockview = new DockviewComponent(element, {
|
||||
frameworkComponentFactory: factory,
|
||||
frameworkComponents: props.components,
|
||||
frameworkTabComponents: {
|
||||
...(props.tabComponents || {}),
|
||||
[DEFAULT_TAB_IDENTIFIER]: props.defaultTabComponent,
|
||||
},
|
||||
frameworkTabComponents,
|
||||
tabHeight: props.tabHeight,
|
||||
watermarkFrameworkComponent: props.watermarkComponent,
|
||||
defaultTabComponent: DEFAULT_TAB_IDENTIFIER,
|
||||
defaultTabComponent: props.defaultTabComponent
|
||||
? DEFAULT_REACT_TAB
|
||||
: undefined,
|
||||
styles: props.hideBorders
|
||||
? { separatorBorder: 'transparent' }
|
||||
: undefined,
|
||||
@ -241,12 +248,19 @@ export const DockviewReact = React.forwardRef(
|
||||
if (!dockviewRef.current) {
|
||||
return;
|
||||
}
|
||||
|
||||
const frameworkTabComponents = props.tabComponents || {};
|
||||
|
||||
if (props.defaultTabComponent) {
|
||||
frameworkTabComponents[DEFAULT_REACT_TAB] =
|
||||
props.defaultTabComponent;
|
||||
}
|
||||
|
||||
dockviewRef.current.updateOptions({
|
||||
defaultTabComponent: DEFAULT_TAB_IDENTIFIER,
|
||||
frameworkTabComponents: {
|
||||
...(props.tabComponents || {}),
|
||||
[DEFAULT_TAB_IDENTIFIER]: props.defaultTabComponent,
|
||||
},
|
||||
defaultTabComponent: props.defaultTabComponent
|
||||
? DEFAULT_REACT_TAB
|
||||
: undefined,
|
||||
frameworkTabComponents,
|
||||
});
|
||||
}, [props.defaultTabComponent]);
|
||||
|
||||
|
@ -52,12 +52,6 @@ export class ReactPanelContentPart implements IContentRenderer {
|
||||
);
|
||||
}
|
||||
|
||||
public toJSON() {
|
||||
return {
|
||||
id: this.id,
|
||||
};
|
||||
}
|
||||
|
||||
public update(event: PanelUpdateEvent) {
|
||||
this.part?.update(event.params);
|
||||
}
|
||||
|
@ -2,7 +2,6 @@ import * as React from 'react';
|
||||
import { ReactPart, ReactPortalStore } from '../react';
|
||||
import { IGroupPanelBaseProps } from './dockview';
|
||||
import {
|
||||
DEFAULT_TAB_IDENTIFIER,
|
||||
PanelUpdateEvent,
|
||||
GroupPanel,
|
||||
ITabRenderer,
|
||||
@ -47,16 +46,6 @@ export class ReactPanelHeaderPart implements ITabRenderer {
|
||||
this.part?.update(event.params);
|
||||
}
|
||||
|
||||
public toJSON() {
|
||||
if (this.id === DEFAULT_TAB_IDENTIFIER) {
|
||||
return {};
|
||||
}
|
||||
|
||||
return {
|
||||
id: this.id,
|
||||
};
|
||||
}
|
||||
|
||||
public layout(_width: number, _height: number) {
|
||||
// noop - retrieval from api
|
||||
}
|
||||
|
@ -32,10 +32,6 @@ export class WebviewContentRenderer implements IContentRenderer {
|
||||
this.parameters = parameters;
|
||||
}
|
||||
|
||||
public toJSON() {
|
||||
return {};
|
||||
}
|
||||
|
||||
public update(params: PanelUpdateEvent) {
|
||||
if (this.parameters) {
|
||||
this.parameters.params = params.params;
|
||||
|
Loading…
Reference in New Issue
Block a user