Merge pull request #686 from mathuo/651-offical-support-for-vanilla-typescript-1

chore: updateOptions logic
This commit is contained in:
mathuo 2024-08-16 19:16:42 +01:00 committed by GitHub
commit 05084030db
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
15 changed files with 128 additions and 173 deletions

View File

@ -1,20 +1,16 @@
import { DockviewApi } from '../../../../api/component.api'; import { DockviewApi } from '../../../../api/component.api';
import { Watermark } from '../../../../dockview/components/watermark/watermark'; import { Watermark } from '../../../../dockview/components/watermark/watermark';
import { fromPartial } from '@total-typescript/shoehorn';
describe('watermark', () => { describe('watermark', () => {
test('that the group is closed when the close button is clicked', () => { test('that the group is closed when the close button is clicked', () => {
const cut = new Watermark(); const cut = new Watermark();
const api = fromPartial<DockviewApi>({
const mockApi = jest.fn<Partial<DockviewApi>, any[]>(() => { removeGroup: jest.fn(),
return {
removeGroup: jest.fn(),
};
}); });
const api = <DockviewApi>new mockApi();
const group = jest.fn() as any; const group = jest.fn() as any;
cut.init({ containerApi: api }); cut.init({ containerApi: api, group });
cut.updateParentGroup(group, true);
const closeEl = cut.element.querySelector('.close-action')!; const closeEl = cut.element.querySelector('.close-action')!;

View File

@ -8,9 +8,9 @@ import { PanelUpdateEvent } from '../../panel/types';
import { Orientation } from '../../splitview/splitview'; import { Orientation } from '../../splitview/splitview';
import { CompositeDisposable } from '../../lifecycle'; import { CompositeDisposable } from '../../lifecycle';
import { Emitter } from '../../events'; import { Emitter } from '../../events';
import { DockviewPanel, IDockviewPanel } from '../../dockview/dockviewPanel'; import { IDockviewPanel } from '../../dockview/dockviewPanel';
import { DockviewGroupPanel } from '../../dockview/dockviewGroupPanel'; import { DockviewGroupPanel } from '../../dockview/dockviewGroupPanel';
import { fireEvent, getByTestId, queryByTestId } from '@testing-library/dom'; import { fireEvent, queryByTestId } from '@testing-library/dom';
import { getPanelData } from '../../dnd/dataTransfer'; import { getPanelData } from '../../dnd/dataTransfer';
import { import {
GroupDragEvent, GroupDragEvent,

View File

@ -116,10 +116,6 @@ class Watermark implements IWatermarkRenderer {
return {}; return {};
} }
updateParentGroup() {
//
}
dispose() { dispose() {
// //
} }

View File

@ -68,8 +68,8 @@ class TestPanel implements IGridPanelView {
class ClassUnderTest extends BaseGrid<TestPanel> { class ClassUnderTest extends BaseGrid<TestPanel> {
readonly gridview = this.gridview; readonly gridview = this.gridview;
constructor(options: BaseGridOptions) { constructor(parentElement: HTMLElement, options: BaseGridOptions) {
super(options); super(parentElement, options);
} }
doRemoveGroup( doRemoveGroup(
@ -106,8 +106,7 @@ class ClassUnderTest extends BaseGrid<TestPanel> {
describe('baseComponentGridview', () => { describe('baseComponentGridview', () => {
test('that .layout(...) force flag works', () => { test('that .layout(...) force flag works', () => {
const cut = new ClassUnderTest({ const cut = new ClassUnderTest(document.createElement('div'), {
parentElement: document.createElement('div'),
orientation: Orientation.HORIZONTAL, orientation: Orientation.HORIZONTAL,
proportionalLayout: true, proportionalLayout: true,
}); });
@ -131,8 +130,7 @@ describe('baseComponentGridview', () => {
}); });
test('can add group', () => { test('can add group', () => {
const cut = new ClassUnderTest({ const cut = new ClassUnderTest(document.createElement('div'), {
parentElement: document.createElement('div'),
orientation: Orientation.HORIZONTAL, orientation: Orientation.HORIZONTAL,
proportionalLayout: true, proportionalLayout: true,
}); });

View File

@ -5,8 +5,7 @@ import {
import { addDisposableListener } from '../../../events'; import { addDisposableListener } from '../../../events';
import { toggleClass } from '../../../dom'; import { toggleClass } from '../../../dom';
import { CompositeDisposable } from '../../../lifecycle'; import { CompositeDisposable } from '../../../lifecycle';
import { DockviewGroupPanel } from '../../dockviewGroupPanel'; import { IDockviewGroupPanel } from '../../dockviewGroupPanel';
import { PanelUpdateEvent } from '../../../panel/types';
import { createCloseButton } from '../../../svg'; import { createCloseButton } from '../../../svg';
import { DockviewApi } from '../../../api/component.api'; import { DockviewApi } from '../../../api/component.api';
@ -15,7 +14,7 @@ export class Watermark
implements IWatermarkRenderer implements IWatermarkRenderer
{ {
private _element: HTMLElement; private _element: HTMLElement;
private _group: DockviewGroupPanel | undefined; private _group: IDockviewGroupPanel | undefined;
private _api: DockviewApi | undefined; private _api: DockviewApi | undefined;
get element(): HTMLElement { get element(): HTMLElement {
@ -52,8 +51,9 @@ export class Watermark
title.appendChild(actionsContainer); title.appendChild(actionsContainer);
this.addDisposables( this.addDisposables(
addDisposableListener(closeAnchor, 'click', (ev) => { addDisposableListener(closeAnchor, 'click', (event: MouseEvent) => {
ev.preventDefault(); event.preventDefault();
if (this._group) { if (this._group) {
this._api?.removeGroup(this._group); this._api?.removeGroup(this._group);
} }
@ -61,32 +61,12 @@ export class Watermark
); );
} }
update(_event: PanelUpdateEvent): void {
// noop
}
focus(): void {
// noop
}
layout(_width: number, _height: number): void {
// noop
}
init(_params: WatermarkRendererInitParameters): void { init(_params: WatermarkRendererInitParameters): void {
this._api = _params.containerApi; this._api = _params.containerApi;
this._group = _params.group;
this.render(); this.render();
} }
updateParentGroup(group: DockviewGroupPanel, _visible: boolean): void {
this._group = group;
this.render();
}
dispose(): void {
super.dispose();
}
private render(): void { private render(): void {
const isOneGroup = !!(this._api && this._api.size <= 1); const isOneGroup = !!(this._api && this._api.size <= 1);
toggleClass(this.element, 'has-actions', isOneGroup); toggleClass(this.element, 'has-actions', isOneGroup);

View File

@ -51,7 +51,12 @@ import { DockviewPanelModel } from './dockviewPanelModel';
import { getPanelData } from '../dnd/dataTransfer'; import { getPanelData } from '../dnd/dataTransfer';
import { Parameters } from '../panel/types'; import { Parameters } from '../panel/types';
import { Overlay } from '../overlay/overlay'; import { Overlay } from '../overlay/overlay';
import { addTestId, toggleClass, watchElementResize } from '../dom'; import {
addTestId,
getDockviewTheme,
toggleClass,
watchElementResize,
} from '../dom';
import { DockviewFloatingGroupPanel } from './dockviewFloatingGroupPanel'; import { DockviewFloatingGroupPanel } from './dockviewFloatingGroupPanel';
import { import {
GroupDragEvent, GroupDragEvent,
@ -92,33 +97,6 @@ function moveGroupWithoutDestroying(options: {
}); });
} }
function getDockviewTheme(element: HTMLElement): string | undefined {
function toClassList(element: HTMLElement) {
const list: string[] = [];
for (let i = 0; i < element.classList.length; i++) {
list.push(element.classList.item(i)!);
}
return list;
}
let theme: string | undefined = undefined;
let parent: HTMLElement | null = element;
while (parent !== null) {
theme = toClassList(parent).find((cls) =>
cls.startsWith('dockview-theme-')
);
if (typeof theme === 'string') {
break;
}
parent = parent.parentElement;
}
return theme;
}
export interface PanelReference { export interface PanelReference {
update: (event: { params: { [key: string]: any } }) => void; update: (event: { params: { [key: string]: any } }) => void;
remove: () => void; remove: () => void;
@ -362,23 +340,18 @@ export class DockviewComponent
} }
constructor(parentElement: HTMLElement, options: DockviewComponentOptions) { constructor(parentElement: HTMLElement, options: DockviewComponentOptions) {
super({ super(parentElement, {
proportionalLayout: true, proportionalLayout: true,
orientation: Orientation.HORIZONTAL, orientation: Orientation.HORIZONTAL,
styles: options.hideBorders styles: options.hideBorders
? { separatorBorder: 'transparent' } ? { separatorBorder: 'transparent' }
: undefined, : undefined,
parentElement: parentElement,
disableAutoResizing: options.disableAutoResizing, disableAutoResizing: options.disableAutoResizing,
locked: options.locked, locked: options.locked,
margin: options.gap, margin: options.gap,
className: options.className, className: options.className,
}); });
// const gready = document.createElement('div');
// gready.className = 'dv-overlay-render-container';
// this.gridview.element.appendChild(gready);
this.overlayRenderContainer = new OverlayRenderContainer( this.overlayRenderContainer = new OverlayRenderContainer(
this.gridview.element, this.gridview.element,
this this
@ -1022,19 +995,9 @@ export class DockviewComponent
override updateOptions(options: Partial<DockviewComponentOptions>): void { override updateOptions(options: Partial<DockviewComponentOptions>): void {
super.updateOptions(options); super.updateOptions(options);
const changed_floatingGroupBounds = if ('floatingGroupBounds' in options) {
'floatingGroupBounds' in options &&
options.floatingGroupBounds !== this.options.floatingGroupBounds;
const changed_rootOverlayOptions =
'rootOverlayModel' in options &&
options.rootOverlayModel !== this.options.rootOverlayModel;
this._options = { ...this.options, ...options };
if (changed_floatingGroupBounds) {
for (const group of this._floatingGroups) { for (const group of this._floatingGroups) {
switch (this.options.floatingGroupBounds) { switch (options.floatingGroupBounds) {
case 'boundedWithinViewport': case 'boundedWithinViewport':
group.overlay.minimumInViewportHeight = undefined; group.overlay.minimumInViewportHeight = undefined;
group.overlay.minimumInViewportWidth = undefined; group.overlay.minimumInViewportWidth = undefined;
@ -1047,30 +1010,26 @@ export class DockviewComponent
break; break;
default: default:
group.overlay.minimumInViewportHeight = group.overlay.minimumInViewportHeight =
this.options.floatingGroupBounds?.minimumHeightWithinViewport; options.floatingGroupBounds?.minimumHeightWithinViewport;
group.overlay.minimumInViewportWidth = group.overlay.minimumInViewportWidth =
this.options.floatingGroupBounds?.minimumWidthWithinViewport; options.floatingGroupBounds?.minimumWidthWithinViewport;
} }
group.overlay.setBounds(); group.overlay.setBounds();
} }
} }
if (changed_rootOverlayOptions) { if ('rootOverlayModel' in options) {
this._rootDropTarget.setOverlayModel(options.rootOverlayModel!); this._rootDropTarget.setOverlayModel(
options.rootOverlayModel ?? DEFAULT_ROOT_OVERLAY_MODEL
);
} }
if ( if ('gap' in options) {
// if explicitly set as `undefined` this.gridview.margin = options.gap ?? 0;
'gap' in options &&
options.gap === undefined
) {
this.gridview.margin = 0;
} }
if (typeof options.gap === 'number') { this._options = { ...this.options, ...options };
this.gridview.margin = options.gap;
}
this.layout(this.gridview.width, this.gridview.height, true); this.layout(this.gridview.width, this.gridview.height, true);
} }
@ -1108,7 +1067,7 @@ export class DockviewComponent
if (!this.activeGroup) { if (!this.activeGroup) {
return; return;
} }
options.group = this.activeGroup; options.group = this.activeGroup;
} }
if (options.includePanel && options.group) { if (options.includePanel && options.group) {

View File

@ -972,8 +972,6 @@ export class DockviewGroupPanelModel
this.tabsContainer.hide(); this.tabsContainer.hide();
this.contentContainer.element.appendChild(this.watermark.element); this.contentContainer.element.appendChild(this.watermark.element);
this.watermark.updateParentGroup(this.groupPanel, true);
} }
if (!this.isEmpty && this.watermark) { if (!this.isEmpty && this.watermark) {
this.watermark.element.remove(); this.watermark.element.remove();

View File

@ -32,7 +32,6 @@ export interface IWatermarkRenderer
extends Optional<Omit<IPanel, 'id' | 'init'>, RendererMethodOptionalList> { extends Optional<Omit<IPanel, 'id' | 'init'>, RendererMethodOptionalList> {
readonly element: HTMLElement; readonly element: HTMLElement;
init: (params: WatermarkRendererInitParameters) => void; init: (params: WatermarkRendererInitParameters) => void;
updateParentGroup(group: DockviewGroupPanel, visible: boolean): void;
} }
export interface ITabRenderer export interface ITabRenderer

View File

@ -280,3 +280,50 @@ export function disableIframePointEvents() {
}, },
}; };
} }
export function getDockviewTheme(element: HTMLElement): string | undefined {
function toClassList(element: HTMLElement) {
const list: string[] = [];
for (let i = 0; i < element.classList.length; i++) {
list.push(element.classList.item(i)!);
}
return list;
}
let theme: string | undefined = undefined;
let parent: HTMLElement | null = element;
while (parent !== null) {
theme = toClassList(parent).find((cls) =>
cls.startsWith('dockview-theme-')
);
if (typeof theme === 'string') {
break;
}
parent = parent.parentElement;
}
return theme;
}
export class Classnames {
private _classNames: string[] = [];
constructor(private readonly element: HTMLElement) {}
setClassNames(classNames: string) {
for (const className of this._classNames) {
toggleClass(this.element, className, false);
}
this._classNames = classNames
.split(' ')
.filter((v) => v.trim().length > 0);
for (const className of this._classNames) {
toggleClass(this.element, className, true);
}
}
}

View File

@ -7,7 +7,7 @@ import { ISplitviewStyles, Orientation, Sizing } from '../splitview/splitview';
import { IPanel } from '../panel/types'; import { IPanel } from '../panel/types';
import { MovementOptions2 } from '../dockview/options'; import { MovementOptions2 } from '../dockview/options';
import { Resizable } from '../resizable'; import { Resizable } from '../resizable';
import { toggleClass } from '../dom'; import { Classnames, toggleClass } from '../dom';
const nextLayoutId = sequentialNumberGenerator(); const nextLayoutId = sequentialNumberGenerator();
@ -33,7 +33,6 @@ export interface BaseGridOptions {
readonly proportionalLayout: boolean; readonly proportionalLayout: boolean;
readonly orientation: Orientation; readonly orientation: Orientation;
readonly styles?: ISplitviewStyles; readonly styles?: ISplitviewStyles;
readonly parentElement: HTMLElement;
readonly disableAutoResizing?: boolean; readonly disableAutoResizing?: boolean;
readonly locked?: boolean; readonly locked?: boolean;
readonly margin?: number; readonly margin?: number;
@ -100,7 +99,7 @@ export abstract class BaseGrid<T extends IGridPanelView>
readonly onDidViewVisibilityChangeMicroTaskQueue = readonly onDidViewVisibilityChangeMicroTaskQueue =
this._onDidViewVisibilityChangeMicroTaskQueue.onEvent; this._onDidViewVisibilityChangeMicroTaskQueue.onEvent;
private classNames: string[] = []; private readonly _classNames: Classnames;
get id(): string { get id(): string {
return this._id; return this._id;
@ -147,18 +146,15 @@ export abstract class BaseGrid<T extends IGridPanelView>
this.gridview.locked = value; this.gridview.locked = value;
} }
constructor(options: BaseGridOptions) { constructor(parentElement: HTMLElement, options: BaseGridOptions) {
super(document.createElement('div'), options.disableAutoResizing); super(document.createElement('div'), options.disableAutoResizing);
this.element.style.height = '100%'; this.element.style.height = '100%';
this.element.style.width = '100%'; this.element.style.width = '100%';
this.classNames = options.className?.split(' ') ?? []; this._classNames = new Classnames(this.element);
this._classNames.setClassNames(options.className ?? '');
for (const className of this.classNames) { parentElement.appendChild(this.element);
toggleClass(this.element, className, true);
}
options.parentElement.appendChild(this.element);
this.gridview = new Gridview( this.gridview = new Gridview(
!!options.proportionalLayout, !!options.proportionalLayout,
@ -214,14 +210,26 @@ export abstract class BaseGrid<T extends IGridPanelView>
} }
updateOptions(options: Partial<BaseGridOptions>) { updateOptions(options: Partial<BaseGridOptions>) {
if (typeof options.proportionalLayout === 'boolean') {
// this.gridview.proportionalLayout = options.proportionalLayout; // not supported
}
if (options.orientation) {
this.gridview.orientation = options.orientation;
}
if ('styles' in options) {
// this.gridview.styles = options.styles; // not supported
}
if ('disableResizing' in options) {
this.disableResizing = options.disableAutoResizing ?? false;
}
if ('locked' in options) {
this.locked = options.locked ?? false;
}
if ('margin' in options) {
this.gridview.margin = options.margin ?? 0;
}
if ('className' in options) { if ('className' in options) {
for (const className of this.classNames) { this._classNames.setClassNames(options.className ?? '');
toggleClass(this.element, className, false);
}
this.classNames = options.className?.split(' ') ?? [];
for (const className of this.classNames) {
toggleClass(this.element, className, true);
}
} }
} }

View File

@ -115,8 +115,7 @@ export class GridviewComponent
} }
constructor(parentElement: HTMLElement, options: GridviewComponentOptions) { constructor(parentElement: HTMLElement, options: GridviewComponentOptions) {
super({ super(parentElement, {
parentElement: parentElement,
proportionalLayout: options.proportionalLayout, proportionalLayout: options.proportionalLayout,
orientation: options.orientation, orientation: options.orientation,
styles: options.styles, styles: options.styles,

View File

@ -24,7 +24,7 @@ import { sequentialNumberGenerator } from '../math';
import { PaneTransfer } from '../dnd/dataTransfer'; import { PaneTransfer } from '../dnd/dataTransfer';
import { Resizable } from '../resizable'; import { Resizable } from '../resizable';
import { Parameters } from '../panel/types'; import { Parameters } from '../panel/types';
import { toggleClass } from '../dom'; import { Classnames, toggleClass } from '../dom';
const nextLayoutId = sequentialNumberGenerator(); const nextLayoutId = sequentialNumberGenerator();
@ -152,7 +152,7 @@ export class PaneviewComponent extends Resizable implements IPaneviewComponent {
private readonly _onDidRemoveView = new Emitter<PaneviewPanel>(); private readonly _onDidRemoveView = new Emitter<PaneviewPanel>();
readonly onDidRemoveView = this._onDidRemoveView.event; readonly onDidRemoveView = this._onDidRemoveView.event;
private classNames: string[] = []; private readonly _classNames: Classnames;
get id(): string { get id(): string {
return this._id; return this._id;
@ -213,11 +213,8 @@ export class PaneviewComponent extends Resizable implements IPaneviewComponent {
this._onDidRemoveView this._onDidRemoveView
); );
this.classNames = options.className?.split(' ') ?? []; this._classNames = new Classnames(this.element);
this._classNames.setClassNames(options.className ?? '');
for (const className of this.classNames) {
toggleClass(this.element, className, true);
}
this._options = options; this._options = options;
@ -247,13 +244,11 @@ export class PaneviewComponent extends Resizable implements IPaneviewComponent {
updateOptions(options: Partial<PaneviewComponentOptions>): void { updateOptions(options: Partial<PaneviewComponentOptions>): void {
if ('className' in options) { if ('className' in options) {
for (const className of this.classNames) { this._classNames.setClassNames(options.className ?? '');
toggleClass(this.element, className, false); }
}
this.classNames = options.className?.split(' ') ?? []; if ('disableResizing' in options) {
for (const className of this.classNames) { this.disableResizing = options.disableAutoResizing ?? false;
toggleClass(this.element, className, true);
}
} }
this._options = { ...this.options, ...options }; this._options = { ...this.options, ...options };

View File

@ -17,7 +17,7 @@ import { Emitter, Event } from '../events';
import { SplitviewPanel, ISplitviewPanel } from './splitviewPanel'; import { SplitviewPanel, ISplitviewPanel } from './splitviewPanel';
import { createComponent } from '../panel/componentFactory'; import { createComponent } from '../panel/componentFactory';
import { Resizable } from '../resizable'; import { Resizable } from '../resizable';
import { toggleClass } from '../dom'; import { Classnames, toggleClass } from '../dom';
export interface SerializedSplitviewPanelData { export interface SerializedSplitviewPanelData {
id: string; id: string;
@ -100,7 +100,7 @@ export class SplitviewComponent
private readonly _onDidLayoutChange = new Emitter<void>(); private readonly _onDidLayoutChange = new Emitter<void>();
readonly onDidLayoutChange: Event<void> = this._onDidLayoutChange.event; readonly onDidLayoutChange: Event<void> = this._onDidLayoutChange.event;
private classNames: string[] = []; private readonly _classNames: Classnames;
get panels(): SplitviewPanel[] { get panels(): SplitviewPanel[] {
return this.splitview.getViews(); return this.splitview.getViews();
@ -162,11 +162,8 @@ export class SplitviewComponent
) { ) {
super(parentElement, options.disableAutoResizing); super(parentElement, options.disableAutoResizing);
this.classNames = options.className?.split(' ') ?? []; this._classNames = new Classnames(this.element);
this._classNames.setClassNames(options.className ?? '');
for (const className of this.classNames) {
toggleClass(this.element, className, true);
}
this._options = options; this._options = options;
@ -189,25 +186,19 @@ export class SplitviewComponent
updateOptions(options: Partial<SplitviewComponentOptions>): void { updateOptions(options: Partial<SplitviewComponentOptions>): void {
if ('className' in options) { if ('className' in options) {
for (const className of this.classNames) { this._classNames.setClassNames(options.className ?? '');
toggleClass(this.element, className, false);
}
this.classNames = options.className?.split(' ') ?? [];
for (const className of this.classNames) {
toggleClass(this.element, className, true);
}
} }
const hasOrientationChanged = if ('disableResizing' in options) {
typeof options.orientation === 'string' && this.disableResizing = options.disableAutoResizing ?? false;
this.options.orientation !== options.orientation; }
this._options = { ...this.options, ...options }; if (typeof options.orientation === 'string') {
if (hasOrientationChanged) {
this.splitview.orientation = options.orientation!; this.splitview.orientation = options.orientation!;
} }
this._options = { ...this.options, ...options };
this.splitview.layout( this.splitview.layout(
this.splitview.size, this.splitview.size,
this.splitview.orthogonalSize this.splitview.orthogonalSize

View File

@ -183,10 +183,6 @@ export class VueWatermarkRenderer
); );
} }
updateParentGroup(group: DockviewGroupPanel, visible: boolean): void {
// TODO: make optional on interface
}
update(event: PanelUpdateEvent<Parameters>): void { update(event: PanelUpdateEvent<Parameters>): void {
// noop // noop
} }

View File

@ -57,13 +57,6 @@ export class ReactWatermarkPart implements IWatermarkRenderer {
// noop - retrieval from api // noop - retrieval from api
} }
updateParentGroup(
_group: DockviewGroupPanel,
_isPanelVisible: boolean
): void {
// noop
}
dispose(): void { dispose(): void {
this.part?.dispose(); this.part?.dispose();
} }