diff --git a/packages/dockview-core/src/__tests__/dockview/dockviewComponent.spec.ts b/packages/dockview-core/src/__tests__/dockview/dockviewComponent.spec.ts index d5627375c..d8d887de5 100644 --- a/packages/dockview-core/src/__tests__/dockview/dockviewComponent.spec.ts +++ b/packages/dockview-core/src/__tests__/dockview/dockviewComponent.spec.ts @@ -118,6 +118,28 @@ describe('dockviewComponent', () => { window.open = jest.fn(); // not implemented by jest }); + test('update className', () => { + dockview = new DockviewComponent(container, { + createComponent(options) { + switch (options.name) { + case 'default': + return new PanelContentPartTest( + options.id, + options.name + ); + default: + throw new Error(`unsupported`); + } + }, + className: 'test-a test-b', + }); + expect(dockview.element.className).toBe('test-a test-b'); + + dockview.updateOptions({ className: 'test-b test-c' }); + + expect(dockview.element.className).toBe('test-b test-c'); + }); + // describe('memory leakage', () => { // beforeEach(() => { // window.open = () => fromPartial({ diff --git a/packages/dockview-core/src/__tests__/gridview/gridviewComponent.spec.ts b/packages/dockview-core/src/__tests__/gridview/gridviewComponent.spec.ts index 7e5f4e03c..905c6d6e9 100644 --- a/packages/dockview-core/src/__tests__/gridview/gridviewComponent.spec.ts +++ b/packages/dockview-core/src/__tests__/gridview/gridviewComponent.spec.ts @@ -32,6 +32,21 @@ describe('gridview', () => { container = document.createElement('div'); }); + test('update className', () => { + const gridview = new GridviewComponent(container, { + proportionalLayout: false, + orientation: Orientation.VERTICAL, + components: { default: TestGridview }, + className: 'test-a test-b', + }); + + expect(gridview.element.className).toBe('test-a test-b'); + + gridview.updateOptions({ className: 'test-b test-c' }); + + expect(gridview.element.className).toBe('test-b test-c'); + }); + test('added views are visible by default', () => { const gridview = new GridviewComponent(container, { proportionalLayout: false, diff --git a/packages/dockview-core/src/__tests__/paneview/paneviewComponent.spec.ts b/packages/dockview-core/src/__tests__/paneview/paneviewComponent.spec.ts index 246e30f8a..1c5a77da7 100644 --- a/packages/dockview-core/src/__tests__/paneview/paneviewComponent.spec.ts +++ b/packages/dockview-core/src/__tests__/paneview/paneviewComponent.spec.ts @@ -537,4 +537,20 @@ describe('componentPaneview', () => { expect(panel1.api.isVisible).toBeTruthy(); expect(panel2.api.isVisible).toBeTruthy(); }); + + test('update className', () => { + const paneview = new PaneviewComponent(container, { + components: { + default: TestPanel, + }, + disableAutoResizing: true, + className: 'test-a test-b', + }); + + expect(paneview.element.className).toBe('container test-a test-b'); + + paneview.updateOptions({ className: 'test-b test-c' }); + + expect(paneview.element.className).toBe('container test-b test-c'); + }); }); diff --git a/packages/dockview-core/src/__tests__/splitview/splitviewComponent.spec.ts b/packages/dockview-core/src/__tests__/splitview/splitviewComponent.spec.ts index 838f0c4cc..4c7ed46f3 100644 --- a/packages/dockview-core/src/__tests__/splitview/splitviewComponent.spec.ts +++ b/packages/dockview-core/src/__tests__/splitview/splitviewComponent.spec.ts @@ -631,4 +631,20 @@ describe('componentSplitview', () => { expect(panel1.api.isVisible).toBeTruthy(); expect(panel2.api.isVisible).toBeTruthy(); }); + + test('update className', () => { + const splitview = new SplitviewComponent(container, { + orientation: Orientation.HORIZONTAL, + components: { + default: TestPanel, + }, + className: 'test-a test-b', + }); + + expect(splitview.element.className).toBe('container test-a test-b'); + + splitview.updateOptions({ className: 'test-b test-c' }); + + expect(splitview.element.className).toBe('container test-b test-c'); + }); }); diff --git a/packages/dockview-core/src/api/component.api.ts b/packages/dockview-core/src/api/component.api.ts index e6e003169..6978df401 100644 --- a/packages/dockview-core/src/api/component.api.ts +++ b/packages/dockview-core/src/api/component.api.ts @@ -15,7 +15,6 @@ import { Parameters } from '../panel/types'; import { Direction } from '../gridview/baseComponentGridview'; import { AddComponentOptions, - GridviewComponentUpdateOptions, IGridviewComponent, SerializedGridviewComponent, } from '../gridview/gridviewComponent'; @@ -31,7 +30,6 @@ import { AddSplitviewComponentOptions, ISplitviewComponent, SerializedSplitview, - SplitviewComponentUpdateOptions, } from '../splitview/splitviewComponent'; import { IView, Orientation, Sizing } from '../splitview/splitview'; import { ISplitviewPanel } from '../splitview/splitviewPanel'; @@ -46,13 +44,15 @@ import { GroupDragEvent, TabDragEvent, } from '../dockview/components/titlebar/tabsContainer'; -import { AnchoredBox, Box } from '../types'; +import { Box } from '../types'; import { DockviewDidDropEvent, DockviewWillDropEvent, WillShowOverlayLocationEvent, } from '../dockview/dockviewGroupPanelModel'; import { PaneviewComponentOptions } from '../paneview/options'; +import { SplitviewComponentOptions } from '../splitview/options'; +import { GridviewComponentOptions } from '../gridview/options'; export interface CommonApi { readonly height: number; @@ -214,7 +214,7 @@ export class SplitviewApi implements CommonApi { /** * Update configuratable options. */ - updateOptions(options: Partial): void { + updateOptions(options: Partial): void { this.component.updateOptions(options); } @@ -556,7 +556,7 @@ export class GridviewApi implements CommonApi { this.component.clear(); } - updateOptions(options: Partial) { + updateOptions(options: Partial) { this.component.updateOptions(options); } diff --git a/packages/dockview-core/src/dockview/dockviewComponent.ts b/packages/dockview-core/src/dockview/dockviewComponent.ts index c86e05d17..cf1c267ee 100644 --- a/packages/dockview-core/src/dockview/dockviewComponent.ts +++ b/packages/dockview-core/src/dockview/dockviewComponent.ts @@ -1019,7 +1019,9 @@ export class DockviewComponent } } - updateOptions(options: Partial): void { + override updateOptions(options: Partial): void { + super.updateOptions(options); + const changed_floatingGroupBounds = 'floatingGroupBounds' in options && options.floatingGroupBounds !== this.options.floatingGroupBounds; @@ -1106,7 +1108,7 @@ export class DockviewComponent if (!this.activeGroup) { return; } - options.group = this.activeGroup; + options.group = this.activeGroup; } if (options.includePanel && options.group) { diff --git a/packages/dockview-core/src/gridview/baseComponentGridview.ts b/packages/dockview-core/src/gridview/baseComponentGridview.ts index 9e13f6ad0..6bed2c62c 100644 --- a/packages/dockview-core/src/gridview/baseComponentGridview.ts +++ b/packages/dockview-core/src/gridview/baseComponentGridview.ts @@ -7,6 +7,7 @@ import { ISplitviewStyles, Orientation, Sizing } from '../splitview/splitview'; import { IPanel } from '../panel/types'; import { MovementOptions2 } from '../dockview/options'; import { Resizable } from '../resizable'; +import { toggleClass } from '../dom'; const nextLayoutId = sequentialNumberGenerator(); @@ -99,6 +100,8 @@ export abstract class BaseGrid readonly onDidViewVisibilityChangeMicroTaskQueue = this._onDidViewVisibilityChangeMicroTaskQueue.onEvent; + private classNames: string[] = []; + get id(): string { return this._id; } @@ -149,8 +152,10 @@ export abstract class BaseGrid this.element.style.height = '100%'; this.element.style.width = '100%'; - if (typeof options.className === 'string') { - this.element.classList.add(options.className); + this.classNames = options.className?.split(' ') ?? []; + + for (const className of this.classNames) { + toggleClass(this.element, className, true); } options.parentElement.appendChild(this.element); @@ -208,6 +213,18 @@ export abstract class BaseGrid return this.gridview.isViewVisible(getGridLocation(panel.element)); } + updateOptions(options: Partial) { + if ('className' in options) { + for (const className of this.classNames) { + toggleClass(this.element, className, false); + } + this.classNames = options.className?.split(' ') ?? []; + for (const className of this.classNames) { + toggleClass(this.element, className, true); + } + } + } + maximizeGroup(panel: T): void { this.gridview.maximizeView(panel); this.doSetGroupActive(panel); diff --git a/packages/dockview-core/src/gridview/gridviewComponent.ts b/packages/dockview-core/src/gridview/gridviewComponent.ts index f73e4f710..c342d3a50 100644 --- a/packages/dockview-core/src/gridview/gridviewComponent.ts +++ b/packages/dockview-core/src/gridview/gridviewComponent.ts @@ -49,15 +49,10 @@ export interface IGridPanelComponentView extends IGridPanelView { init: (params: GridviewInitParameters) => void; } -export type GridviewComponentUpdateOptions = Pick< - GridviewComponentOptions, - 'orientation' | 'components' | 'frameworkComponents' ->; - export interface IGridviewComponent extends IBaseGrid { readonly orientation: Orientation; readonly onDidLayoutFromJSON: Event; - updateOptions(options: Partial): void; + updateOptions(options: Partial): void; addPanel( options: AddComponentOptions ): IGridviewPanel; @@ -154,7 +149,9 @@ export class GridviewComponent } } - updateOptions(options: Partial): void { + override updateOptions(options: Partial): void { + super.updateOptions(options); + const hasOrientationChanged = typeof options.orientation === 'string' && this.gridview.orientation !== options.orientation; diff --git a/packages/dockview-core/src/paneview/paneviewComponent.ts b/packages/dockview-core/src/paneview/paneviewComponent.ts index 46c2c25a5..944378c31 100644 --- a/packages/dockview-core/src/paneview/paneviewComponent.ts +++ b/packages/dockview-core/src/paneview/paneviewComponent.ts @@ -24,6 +24,7 @@ import { sequentialNumberGenerator } from '../math'; import { PaneTransfer } from '../dnd/dataTransfer'; import { Resizable } from '../resizable'; import { Parameters } from '../panel/types'; +import { toggleClass } from '../dom'; const nextLayoutId = sequentialNumberGenerator(); @@ -151,6 +152,8 @@ export class PaneviewComponent extends Resizable implements IPaneviewComponent { private readonly _onDidRemoveView = new Emitter(); readonly onDidRemoveView = this._onDidRemoveView.event; + private classNames: string[] = []; + get id(): string { return this._id; } @@ -202,10 +205,6 @@ export class PaneviewComponent extends Resizable implements IPaneviewComponent { constructor(parentElement: HTMLElement, options: PaneviewComponentOptions) { super(parentElement, options.disableAutoResizing); - if (typeof options.className === 'string') { - this.element.classList.add(options.className); - } - this.addDisposables( this._onDidLayoutChange, this._onDidLayoutfromJSON, @@ -214,6 +213,12 @@ export class PaneviewComponent extends Resizable implements IPaneviewComponent { this._onDidRemoveView ); + this.classNames = options.className?.split(' ') ?? []; + + for (const className of this.classNames) { + toggleClass(this.element, className, true); + } + this._options = options; if (!options.components) { @@ -241,6 +246,16 @@ export class PaneviewComponent extends Resizable implements IPaneviewComponent { } updateOptions(options: Partial): void { + if ('className' in options) { + for (const className of this.classNames) { + toggleClass(this.element, className, false); + } + this.classNames = options.className?.split(' ') ?? []; + for (const className of this.classNames) { + toggleClass(this.element, className, true); + } + } + this._options = { ...this.options, ...options }; } diff --git a/packages/dockview-core/src/splitview/splitviewComponent.ts b/packages/dockview-core/src/splitview/splitviewComponent.ts index 00a6c8e00..dc770d9a9 100644 --- a/packages/dockview-core/src/splitview/splitviewComponent.ts +++ b/packages/dockview-core/src/splitview/splitviewComponent.ts @@ -9,6 +9,7 @@ import { Orientation, Sizing, Splitview, + SplitViewOptions, } from './splitview'; import { SplitviewComponentOptions } from './options'; import { BaseComponentOptions, Parameters } from '../panel/types'; @@ -16,6 +17,7 @@ import { Emitter, Event } from '../events'; import { SplitviewPanel, ISplitviewPanel } from './splitviewPanel'; import { createComponent } from '../panel/componentFactory'; import { Resizable } from '../resizable'; +import { toggleClass } from '../dom'; export interface SerializedSplitviewPanelData { id: string; @@ -46,11 +48,6 @@ export interface AddSplitviewComponentOptions maximumSize?: number; } -export type SplitviewComponentUpdateOptions = Pick< - SplitviewComponentOptions, - 'orientation' | 'components' | 'frameworkComponents' ->; - export interface ISplitviewComponent extends IDisposable { readonly minimumSize: number; readonly maximumSize: number; @@ -62,7 +59,7 @@ export interface ISplitviewComponent extends IDisposable { readonly onDidRemoveView: Event; readonly onDidLayoutFromJSON: Event; readonly panels: SplitviewPanel[]; - updateOptions(options: Partial): void; + updateOptions(options: Partial): void; addPanel( options: AddSplitviewComponentOptions ): ISplitviewPanel; @@ -103,6 +100,8 @@ export class SplitviewComponent private readonly _onDidLayoutChange = new Emitter(); readonly onDidLayoutChange: Event = this._onDidLayoutChange.event; + private classNames: string[] = []; + get panels(): SplitviewPanel[] { return this.splitview.getViews(); } @@ -163,8 +162,10 @@ export class SplitviewComponent ) { super(parentElement, options.disableAutoResizing); - if (typeof options.className === 'string') { - this.element.classList.add(options.className); + this.classNames = options.className?.split(' ') ?? []; + + for (const className of this.classNames) { + toggleClass(this.element, className, true); } this._options = options; @@ -186,7 +187,17 @@ export class SplitviewComponent ); } - updateOptions(options: Partial): void { + updateOptions(options: Partial): void { + if ('className' in options) { + for (const className of this.classNames) { + toggleClass(this.element, className, false); + } + this.classNames = options.className?.split(' ') ?? []; + for (const className of this.classNames) { + toggleClass(this.element, className, true); + } + } + const hasOrientationChanged = typeof options.orientation === 'string' && this.options.orientation !== options.orientation;