Merge pull request #825 from mathuo/818-container-with-theme-class-is-created-twice-1

bug: duplicate container HTML Element
This commit is contained in:
mathuo 2025-01-11 14:57:56 +00:00 committed by GitHub
commit 6678ae24e0
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
16 changed files with 179 additions and 180 deletions

View File

@ -105,6 +105,21 @@ class ClassUnderTest extends BaseGrid<TestPanel> {
}
describe('baseComponentGridview', () => {
test('that the container is not removed when grid is disposed', () => {
const root = document.createElement('div');
const container = document.createElement('div');
root.appendChild(container);
const cut = new ClassUnderTest(container, {
orientation: Orientation.HORIZONTAL,
proportionalLayout: true,
});
cut.dispose();
expect(container.parentElement).toBe(root);
});
test('that .layout(...) force flag works', () => {
const cut = new ClassUnderTest(document.createElement('div'), {
orientation: Orientation.HORIZONTAL,

View File

@ -67,6 +67,27 @@ describe('componentPaneview', () => {
container.className = 'container';
});
test('that the container is not removed when grid is disposed', () => {
const root = document.createElement('div');
const container = document.createElement('div');
root.appendChild(container);
const paneview = new PaneviewComponent(container, {
createComponent: (options) => {
switch (options.name) {
case 'default':
return new TestPanel(options.id, options.name);
default:
throw new Error('unsupported');
}
},
});
paneview.dispose();
expect(container.parentElement).toBe(root);
});
test('vertical panels', () => {
const disposables = new CompositeDisposable();
@ -293,40 +314,6 @@ describe('componentPaneview', () => {
disposable.dispose();
});
test('dispose of paneviewComponent', () => {
expect(container.childNodes.length).toBe(0);
const paneview = new PaneviewComponent(container, {
createComponent: (options) => {
switch (options.name) {
case 'default':
return new TestPanel(options.id, options.name);
default:
throw new Error('unsupported');
}
},
});
paneview.layout(1000, 1000);
paneview.addPanel({
id: 'panel1',
component: 'default',
title: 'Panel 1',
});
paneview.addPanel({
id: 'panel2',
component: 'default',
title: 'Panel 2',
});
expect(container.childNodes.length).toBeGreaterThan(0);
paneview.dispose();
expect(container.childNodes.length).toBe(0);
});
test('panel is disposed of when component is disposed', () => {
const paneview = new PaneviewComponent(container, {
createComponent: (options) => {
@ -606,10 +593,10 @@ describe('componentPaneview', () => {
className: 'test-a test-b',
});
expect(paneview.element.className).toBe('container test-a test-b');
expect(paneview.element.className).toBe('test-a test-b');
paneview.updateOptions({ className: 'test-b test-c' });
expect(paneview.element.className).toBe('container test-b test-c');
expect(paneview.element.className).toBe('test-b test-c');
});
});

View File

@ -26,6 +26,28 @@ describe('componentSplitview', () => {
container.className = 'container';
});
test('that the container is not removed when grid is disposed', () => {
const root = document.createElement('div');
const container = document.createElement('div');
root.appendChild(container);
const splitview = new SplitviewComponent(container, {
orientation: Orientation.VERTICAL,
createComponent: (options) => {
switch (options.name) {
case 'default':
return new TestPanel(options.id, options.name);
default:
throw new Error('unsupported');
}
},
});
splitview.dispose();
expect(container.parentElement).toBe(root);
});
test('event leakage', () => {
Emitter.setLeakageMonitorEnabled(true);
@ -451,39 +473,6 @@ describe('componentSplitview', () => {
disposable.dispose();
});
test('dispose of splitviewComponent', () => {
expect(container.childNodes.length).toBe(0);
const splitview = new SplitviewComponent(container, {
orientation: Orientation.HORIZONTAL,
createComponent: (options) => {
switch (options.name) {
case 'default':
return new TestPanel(options.id, options.name);
default:
throw new Error('unsupported');
}
},
});
splitview.layout(1000, 1000);
splitview.addPanel({
id: 'panel1',
component: 'default',
});
splitview.addPanel({
id: 'panel2',
component: 'default',
});
expect(container.childNodes.length).toBeGreaterThan(0);
splitview.dispose();
expect(container.childNodes.length).toBe(0);
});
test('panel is disposed of when component is disposed', () => {
const splitview = new SplitviewComponent(container, {
orientation: Orientation.HORIZONTAL,
@ -736,10 +725,10 @@ describe('componentSplitview', () => {
className: 'test-a test-b',
});
expect(splitview.element.className).toBe('container test-a test-b');
expect(splitview.element.className).toBe('test-a test-b');
splitview.updateOptions({ className: 'test-b test-c' });
expect(splitview.element.className).toBe('container test-b test-c');
expect(splitview.element.className).toBe('test-b test-c');
});
});

View File

@ -368,8 +368,8 @@ export class DockviewComponent
return this._floatingGroups;
}
constructor(parentElement: HTMLElement, options: DockviewComponentOptions) {
super(parentElement, {
constructor(container: HTMLElement, options: DockviewComponentOptions) {
super(container, {
proportionalLayout: true,
orientation: Orientation.HORIZONTAL,
styles: options.hideBorders

View File

@ -155,14 +155,17 @@ export abstract class BaseGrid<T extends IGridPanelView>
this.gridview.locked = value;
}
constructor(parentElement: HTMLElement, options: BaseGridOptions) {
super(parentElement, options.disableAutoResizing);
constructor(container: HTMLElement, options: BaseGridOptions) {
super(document.createElement('div'), options.disableAutoResizing);
this.element.style.height = '100%';
this.element.style.width = '100%';
this._classNames = new Classnames(this.element);
this._classNames.setClassNames(options.className ?? '');
// the container is owned by the third-party, do not modify/delete it
container.appendChild(this.element);
this.gridview = new Gridview(
!!options.proportionalLayout,
options.styles,

View File

@ -113,8 +113,8 @@ export class GridviewComponent
this._deserializer = value;
}
constructor(parentElement: HTMLElement, options: GridviewComponentOptions) {
super(parentElement, {
constructor(container: HTMLElement, options: GridviewComponentOptions) {
super(container, {
proportionalLayout: options.proportionalLayout ?? true,
orientation: options.orientation,
styles: options.hideBorders

View File

@ -195,8 +195,10 @@ export class PaneviewComponent extends Resizable implements IPaneviewComponent {
return this._options;
}
constructor(parentElement: HTMLElement, options: PaneviewComponentOptions) {
super(parentElement, options.disableAutoResizing);
constructor(container: HTMLElement, options: PaneviewComponentOptions) {
super(document.createElement('div'), options.disableAutoResizing);
this.element.style.height = '100%';
this.element.style.width = '100%';
this.addDisposables(
this._onDidLayoutChange,
@ -210,6 +212,9 @@ export class PaneviewComponent extends Resizable implements IPaneviewComponent {
this._classNames = new Classnames(this.element);
this._classNames.setClassNames(options.className ?? '');
// the container is owned by the third-party, do not modify/delete it
container.appendChild(this.element);
this._options = options;
this.paneview = new Paneview(this.element, {

View File

@ -32,7 +32,7 @@ export interface ISplitviewStyles {
}
export interface SplitViewOptions {
orientation: Orientation;
orientation?: Orientation;
descriptor?: ISplitViewDescriptor;
proportionalLayout?: boolean;
styles?: ISplitviewStyles;
@ -225,7 +225,7 @@ export class Splitview {
private readonly container: HTMLElement,
options: SplitViewOptions
) {
this._orientation = options.orientation;
this._orientation = options.orientation ?? Orientation.VERTICAL;
this.element = this.createContainer();
this.margin = options.margin ?? 0;

View File

@ -155,15 +155,17 @@ export class SplitviewComponent
: this.splitview.orthogonalSize;
}
constructor(
parentElement: HTMLElement,
options: SplitviewComponentOptions
) {
super(parentElement, options.disableAutoResizing);
constructor(container: HTMLElement, options: SplitviewComponentOptions) {
super(document.createElement('div'), options.disableAutoResizing);
this.element.style.height = '100%';
this.element.style.width = '100%';
this._classNames = new Classnames(this.element);
this._classNames.setClassNames(options.className ?? '');
// the container is owned by the third-party, do not modify/delete it
container.appendChild(this.element);
this._options = options;
this.splitview = new Splitview(this.element, options);

View File

@ -318,11 +318,7 @@ export const DockviewReact = React.forwardRef(
}, [props.prefixHeaderActionsComponent]);
return (
<div
className={props.className}
style={{ height: '100%', width: '100%' }}
ref={domRef}
>
<div style={{ height: '100%', width: '100%' }} ref={domRef}>
{portals}
</div>
);

View File

@ -126,11 +126,7 @@ export const GridviewReact = React.forwardRef(
}, [props.components]);
return (
<div
className={props.className}
style={{ height: '100%', width: '100%' }}
ref={domRef}
>
<div style={{ height: '100%', width: '100%' }} ref={domRef}>
{portals}
</div>
);

View File

@ -176,11 +176,7 @@ export const PaneviewReact = React.forwardRef(
}, [props.onDidDrop]);
return (
<div
className={props.className}
style={{ height: '100%', width: '100%' }}
ref={domRef}
>
<div style={{ height: '100%', width: '100%' }} ref={domRef}>
{portals}
</div>
);

View File

@ -126,11 +126,7 @@ export const SplitviewReact = React.forwardRef(
}, [props.components]);
return (
<div
className={props.className}
style={{ height: '100%', width: '100%' }}
ref={domRef}
>
<div style={{ height: '100%', width: '100%' }} ref={domRef}>
{portals}
</div>
);

View File

@ -176,80 +176,92 @@ const DockviewDemo = (props: { theme?: string }) => {
setPending([]);
}, [pending]);
const onReady = (event: DockviewReadyEvent) => {
setApi(event.api);
setPanels([]);
setGroups([]);
setActivePanel(undefined);
setActiveGroup(undefined);
addLogLine(`Dockview Is Ready`);
event.api.onDidAddPanel((event) => {
setPanels((_) => [..._, event.id]);
addLogLine(`Panel Added ${event.id}`);
});
event.api.onDidActivePanelChange((event) => {
setActivePanel(event?.id);
addLogLine(`Panel Activated ${event?.id}`);
});
event.api.onDidRemovePanel((event) => {
setPanels((_) => {
const next = [..._];
next.splice(
next.findIndex((x) => x === event.id),
1
);
return next;
});
addLogLine(`Panel Removed ${event.id}`);
});
event.api.onDidAddGroup((event) => {
setGroups((_) => [..._, event.id]);
addLogLine(`Group Added ${event.id}`);
});
event.api.onDidMovePanel((event) => {
addLogLine(`Panel Moved ${event.panel.id}`);
});
event.api.onDidMaximizedGroupChange((event) => {
addLogLine(
`Group Maximized Changed ${event.group.api.id} [${event.isMaximized}]`
);
});
event.api.onDidRemoveGroup((event) => {
setGroups((_) => {
const next = [..._];
next.splice(
next.findIndex((x) => x === event.id),
1
);
return next;
});
addLogLine(`Group Removed ${event.id}`);
});
event.api.onDidActiveGroupChange((event) => {
setActiveGroup(event?.id);
addLogLine(`Group Activated ${event?.id}`);
});
const state = localStorage.getItem('dv-demo-state');
if (state) {
try {
event.api.fromJSON(JSON.parse(state));
return;
} catch {
localStorage.removeItem('dv-demo-state');
}
React.useEffect(() => {
if (!api) {
return;
}
defaultConfig(event.api);
const disposables = [
api.onDidAddPanel((event) => {
setPanels((_) => [..._, event.id]);
addLogLine(`Panel Added ${event.id}`);
}),
api.onDidActivePanelChange((event) => {
setActivePanel(event?.id);
addLogLine(`Panel Activated ${event?.id}`);
}),
api.onDidRemovePanel((event) => {
setPanels((_) => {
const next = [..._];
next.splice(
next.findIndex((x) => x === event.id),
1
);
return next;
});
addLogLine(`Panel Removed ${event.id}`);
}),
api.onDidAddGroup((event) => {
setGroups((_) => [..._, event.id]);
addLogLine(`Group Added ${event.id}`);
}),
api.onDidMovePanel((event) => {
addLogLine(`Panel Moved ${event.panel.id}`);
}),
api.onDidMaximizedGroupChange((event) => {
addLogLine(
`Group Maximized Changed ${event.group.api.id} [${event.isMaximized}]`
);
}),
api.onDidRemoveGroup((event) => {
setGroups((_) => {
const next = [..._];
next.splice(
next.findIndex((x) => x === event.id),
1
);
return next;
});
addLogLine(`Group Removed ${event.id}`);
}),
api.onDidActiveGroupChange((event) => {
setActiveGroup(event?.id);
addLogLine(`Group Activated ${event?.id}`);
}),
];
const loadLayout = () => {
const state = localStorage.getItem('dv-demo-state');
if (state) {
try {
api.fromJSON(JSON.parse(state));
return;
} catch {
localStorage.removeItem('dv-demo-state');
}
return;
}
defaultConfig(api);
};
loadLayout();
return () => {
disposables.forEach((disposable) => disposable.dispose());
};
}, [api]);
const onReady = (event: DockviewReadyEvent) => {
setApi(event.api);
};
const [watermark, setWatermark] = React.useState<boolean>(false);

View File

@ -88,7 +88,6 @@ const GroupAction = (props: {
}
onClick={() => {
if (group) {
props.api.addFloatingGroup(group, {
width: 400,
height: 300,
@ -99,7 +98,6 @@ const GroupAction = (props: {
right: 50,
},
});
}
}}
>

View File

@ -3,5 +3,9 @@ import { RecoilRoot } from 'recoil';
// Default implementation, that you can customize
export default function Root({ children }) {
return <RecoilRoot>{children}</RecoilRoot>;
return (
<React.StrictMode>
<RecoilRoot>{children}</RecoilRoot>
</React.StrictMode>
);
}