mirror of
https://github.com/mathuo/dockview
synced 2025-08-14 13:16:02 +00:00
commit
e41d0ea64a
86
packages/dockview/src/__tests__/react/react.spec.tsx
Normal file
86
packages/dockview/src/__tests__/react/react.spec.tsx
Normal file
@ -0,0 +1,86 @@
|
||||
import { ReactPart } from '../../react/react';
|
||||
import * as React from 'react';
|
||||
import { render, screen } from '@testing-library/react';
|
||||
|
||||
interface TestInterface {
|
||||
valueA: string;
|
||||
valueB: number;
|
||||
}
|
||||
|
||||
describe('react', () => {
|
||||
describe('ReactPart', () => {
|
||||
test('update underlying component via ReactPart class', () => {
|
||||
let api: ReactPart<TestInterface>;
|
||||
|
||||
const onReady = (_api: ReactPart<TestInterface>) => {
|
||||
api = _api;
|
||||
};
|
||||
|
||||
render(<TestWrapper onReady={onReady} component={Component} />);
|
||||
|
||||
expect(api).toBeTruthy();
|
||||
|
||||
expect(screen.getByTestId('valueA').textContent).toBe('stringA');
|
||||
expect(screen.getByTestId('valueB').textContent).toBe('42');
|
||||
|
||||
api.update({ valueB: '32' });
|
||||
|
||||
expect(screen.getByTestId('valueA').textContent).toBe('stringA');
|
||||
expect(screen.getByTestId('valueB').textContent).toBe('32');
|
||||
|
||||
api.update({ valueA: 'anotherStringA', valueB: '22' });
|
||||
|
||||
expect(screen.getByTestId('valueA').textContent).toBe(
|
||||
'anotherStringA'
|
||||
);
|
||||
expect(screen.getByTestId('valueB').textContent).toBe('22');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
const Component = (props: TestInterface) => {
|
||||
return (
|
||||
<div>
|
||||
<div data-testid="valueA">{props.valueA}</div>
|
||||
<div data-testid="valueB">{props.valueB}</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
const TestWrapper = (props: {
|
||||
component: React.FunctionComponent<TestInterface>;
|
||||
onReady: (api: ReactPart<TestInterface>) => void;
|
||||
}) => {
|
||||
const [portal, setPortal] = React.useState<React.ReactPortal[]>([]);
|
||||
const ref = React.useRef<HTMLDivElement>(null);
|
||||
|
||||
React.useEffect(() => {
|
||||
const cut = new ReactPart<TestInterface>(
|
||||
ref.current,
|
||||
{
|
||||
addPortal: (portal: React.ReactPortal) => {
|
||||
setPortal((_) => [..._, portal]);
|
||||
|
||||
return {
|
||||
dispose: () => {
|
||||
setPortal((_) => _.filter((_) => _ !== portal));
|
||||
},
|
||||
};
|
||||
},
|
||||
},
|
||||
props.component,
|
||||
{
|
||||
valueA: 'stringA',
|
||||
valueB: 42,
|
||||
}
|
||||
);
|
||||
|
||||
props.onReady(cut);
|
||||
|
||||
return () => {
|
||||
cut.dispose();
|
||||
};
|
||||
}, []);
|
||||
|
||||
return <div ref={ref}>{portal}</div>;
|
||||
};
|
@ -2,7 +2,6 @@ import { getElementsByTagName } from '../dom';
|
||||
import { addDisposableListener, Emitter } from '../events';
|
||||
import { focusedElement } from '../focusedElement';
|
||||
import { CompositeDisposable, IDisposable } from '../lifecycle';
|
||||
import { DATA_KEY, LocalSelectionTransfer } from './dataTransfer';
|
||||
|
||||
export abstract class DragHandler extends CompositeDisposable {
|
||||
private iframes: HTMLElement[] = [];
|
||||
|
@ -103,17 +103,6 @@ export interface IDockviewComponent extends IBaseGrid<GroupviewPanel> {
|
||||
onTabContextMenu: Event<TabContextMenuEvent>;
|
||||
moveToNext(options?: MovementOptions): void;
|
||||
moveToPrevious(options?: MovementOptions): void;
|
||||
// createDragTarget(
|
||||
// target: {
|
||||
// element: HTMLElement;
|
||||
// content: string;
|
||||
// },
|
||||
// options: (() => PanelOptions) | PanelOptions
|
||||
// ): IDisposable;
|
||||
// addDndHandle(
|
||||
// type: string,
|
||||
// cb: (event: LayoutDropEvent) => PanelOptions
|
||||
// ): void;
|
||||
setActivePanel(panel: IGroupPanel): void;
|
||||
focus(): void;
|
||||
toJSON(): SerializedDockview;
|
||||
@ -138,13 +127,8 @@ export class DockviewComponent
|
||||
readonly onTabContextMenu: Event<TabContextMenuEvent> =
|
||||
this._onTabContextMenu.event;
|
||||
// everything else
|
||||
// private drag = new MutableDisposable();
|
||||
private _deserializer: IPanelDeserializer | undefined;
|
||||
private panelState: State = {};
|
||||
// private registry = new Map<
|
||||
// string,
|
||||
// (event: LayoutDropEvent) => PanelOptions
|
||||
// >();
|
||||
private _api: DockviewApi;
|
||||
private _options: DockviewComponentOptions;
|
||||
|
||||
@ -229,13 +213,6 @@ export class DockviewComponent
|
||||
this.layout(this.gridview.width, this.gridview.height, true);
|
||||
}
|
||||
|
||||
// addDndHandle(
|
||||
// type: string,
|
||||
// cb: (event: LayoutDropEvent) => PanelOptions
|
||||
// ): void {
|
||||
// this.registry.set(type, cb);
|
||||
// }
|
||||
|
||||
focus(): void {
|
||||
this.activeGroup?.focus();
|
||||
}
|
||||
@ -244,58 +221,6 @@ export class DockviewComponent
|
||||
return this._panels.get(id)?.value;
|
||||
}
|
||||
|
||||
// createDragTarget(
|
||||
// target: {
|
||||
// element: HTMLElement;
|
||||
// content: string;
|
||||
// },
|
||||
// options: (() => PanelOptions) | PanelOptions
|
||||
// ): IDisposable {
|
||||
// return new CompositeDisposable(
|
||||
// addDisposableListener(target.element, 'dragstart', (event) => {
|
||||
// if (!event.dataTransfer) {
|
||||
// throw new Error('unsupported');
|
||||
// }
|
||||
|
||||
// const panelOptions =
|
||||
// typeof options === 'function' ? options() : options;
|
||||
|
||||
// const panel = this.panels.get(panelOptions.id)?.value;
|
||||
// if (panel) {
|
||||
// this.drag.value = panel.group!.model.startActiveDrag(panel);
|
||||
// }
|
||||
|
||||
// const data = JSON.stringify({
|
||||
// type: DragType.EXTERNAL,
|
||||
// ...panelOptions,
|
||||
// });
|
||||
|
||||
// LocalSelectionTransfer.getInstance().setData([data], this.id);
|
||||
|
||||
// event.dataTransfer.effectAllowed = 'move';
|
||||
|
||||
// const dragImage = document.createElement('div');
|
||||
// dragImage.textContent = target.content;
|
||||
// dragImage.classList.add('custom-dragging');
|
||||
|
||||
// document.body.appendChild(dragImage);
|
||||
// event.dataTransfer.setDragImage(
|
||||
// dragImage,
|
||||
// event.offsetX,
|
||||
// event.offsetY
|
||||
// );
|
||||
// setTimeout(() => document.body.removeChild(dragImage), 0);
|
||||
|
||||
// event.dataTransfer.setData(DATA_KEY, data);
|
||||
// }),
|
||||
// addDisposableListener(this.element, 'dragend', (ev) => {
|
||||
// // drop events fire before dragend so we can remove this safely
|
||||
// LocalSelectionTransfer.getInstance().clearData(this.id);
|
||||
// this.drag.dispose();
|
||||
// })
|
||||
// );
|
||||
// }
|
||||
|
||||
setActivePanel(panel: IGroupPanel): void {
|
||||
if (!panel.group) {
|
||||
throw new Error(`Panel ${panel.id} has no associated group`);
|
||||
@ -394,8 +319,6 @@ export class DockviewComponent
|
||||
|
||||
const data = this.gridview.serialize();
|
||||
|
||||
// const state = { ...this.panelState };
|
||||
|
||||
const panels = Array.from(this._panels.values()).reduce(
|
||||
(collection, panel) => {
|
||||
if (!this.panelState[panel.value.id]) {
|
||||
@ -736,7 +659,7 @@ export class DockviewComponent
|
||||
const dirtyPanels = Array.from(this.dirtyPanels);
|
||||
|
||||
if (dirtyPanels.length === 0) {
|
||||
// console.debug('[layout#syncConfigs] no dirty panels');
|
||||
//
|
||||
}
|
||||
|
||||
this.dirtyPanels.clear();
|
||||
|
@ -419,13 +419,13 @@ export class Gridview implements IDisposable {
|
||||
|
||||
for (let i = 0; i < node.children.length; i++) {
|
||||
const child = node.children[i];
|
||||
const cachedVisibleSize = node.getChildCachedVisibleSize(i);
|
||||
const nodeCachedVisibleSize = node.getChildCachedVisibleSize(i);
|
||||
|
||||
children.push(
|
||||
this._getViews(
|
||||
child,
|
||||
orthogonal(orientation),
|
||||
cachedVisibleSize
|
||||
nodeCachedVisibleSize
|
||||
)
|
||||
);
|
||||
}
|
||||
@ -643,7 +643,7 @@ export class Gridview implements IDisposable {
|
||||
const isSiblingVisible = parent.isChildVisible(0);
|
||||
parent.removeChild(0, sizing);
|
||||
|
||||
const sizes = grandParent.children.map((_, i) =>
|
||||
const sizes = grandParent.children.map((size, i) =>
|
||||
grandParent.getChildSize(i)
|
||||
);
|
||||
grandParent.removeChild(parentIndex, sizing);
|
||||
|
@ -1,8 +1,7 @@
|
||||
import { DockviewApi } from '../api/component.api';
|
||||
import { timeoutAsPromise } from '../async';
|
||||
import { getPanelData } from '../dnd/dataTransfer';
|
||||
import { Position } from '../dnd/droptarget';
|
||||
import { Droptarget } from '../dnd/droptarget';
|
||||
import { Droptarget, Position } from '../dnd/droptarget';
|
||||
import {
|
||||
DockviewComponent,
|
||||
IDockviewComponent,
|
||||
|
@ -112,9 +112,9 @@ export abstract class DraggablePaneviewPanel extends PaneviewPanel {
|
||||
|
||||
const containerApi = (this.params! as PanePanelInitParameter)
|
||||
.containerApi;
|
||||
const id = data.paneId;
|
||||
const panelId = data.paneId;
|
||||
|
||||
const existingPanel = containerApi.getPanel(id);
|
||||
const existingPanel = containerApi.getPanel(panelId);
|
||||
if (!existingPanel) {
|
||||
this._onDidDrop.fire({
|
||||
...event,
|
||||
|
@ -176,8 +176,10 @@ export abstract class PaneviewPanel
|
||||
|
||||
this.addDisposables(
|
||||
this._onDidChangeExpansionState,
|
||||
this.onDidChangeExpansionState((isExpanded) => {
|
||||
this.api._onDidExpansionChange.fire({ isExpanded });
|
||||
this.onDidChangeExpansionState((isPanelExpanded) => {
|
||||
this.api._onDidExpansionChange.fire({
|
||||
isExpanded: isPanelExpanded,
|
||||
});
|
||||
})
|
||||
);
|
||||
|
||||
|
@ -49,13 +49,6 @@ const ReactComponentBridge: React.ForwardRefRenderFunction<
|
||||
[]
|
||||
);
|
||||
|
||||
React.useEffect(() => {
|
||||
// console.debug('[reactwrapper] component mounted ');
|
||||
return () => {
|
||||
// console.debug('[reactwrapper] component unmounted ');
|
||||
};
|
||||
}, []);
|
||||
|
||||
return React.createElement(props.component, _props.current);
|
||||
};
|
||||
ReactComponentBridge.displayName = 'DockviewReactJsBridge';
|
||||
|
Loading…
x
Reference in New Issue
Block a user