This commit is contained in:
mathuo 2024-03-10 20:20:53 +00:00
parent b25264e190
commit f93e5b613e
No known key found for this signature in database
GPG Key ID: C6EEDEFD6CA07281
11 changed files with 373 additions and 228 deletions

View File

@ -7,7 +7,8 @@
"esbenp.prettier-vscode", "esbenp.prettier-vscode",
"redhat.vscode-yaml", "redhat.vscode-yaml",
"dbaeumer.vscode-eslint", "dbaeumer.vscode-eslint",
"editorconfig.editorconfig" "editorconfig.editorconfig",
"vue.volar"
], ],
// List of extensions recommended by VS Code that should not be recommended for users of this workspace. // List of extensions recommended by VS Code that should not be recommended for users of this workspace.
"unwantedRecommendations": [] "unwantedRecommendations": []

View File

@ -18,6 +18,7 @@ import {
} from '../../dockview/components/titlebar/tabsContainer'; } from '../../dockview/components/titlebar/tabsContainer';
import { fromPartial } from '@total-typescript/shoehorn'; import { fromPartial } from '@total-typescript/shoehorn';
import { DockviewApi } from '../../api/component.api'; import { DockviewApi } from '../../api/component.api';
import { DockviewDndOverlayEvent } from '../../dockview/options';
class PanelContentPartTest implements IContentRenderer { class PanelContentPartTest implements IContentRenderer {
element: HTMLElement = document.createElement('div'); element: HTMLElement = document.createElement('div');
@ -2039,7 +2040,7 @@ describe('dockviewComponent', () => {
}, },
tabComponents: { tabComponents: {
test_tab_id: PanelTabPartTest, test_tab_id: PanelTabPartTest,
} },
}); });
dockview.layout(1000, 1000); dockview.layout(1000, 1000);
@ -2145,7 +2146,7 @@ describe('dockviewComponent', () => {
}, },
tabComponents: { tabComponents: {
test_tab_id: PanelTabPartTest, test_tab_id: PanelTabPartTest,
} },
}); });
dockview.layout(1000, 1000); dockview.layout(1000, 1000);
@ -2286,7 +2287,7 @@ describe('dockviewComponent', () => {
}, },
tabComponents: { tabComponents: {
test_tab_id: PanelTabPartTest, test_tab_id: PanelTabPartTest,
} },
}); });
dockview.layout(1000, 1000); dockview.layout(1000, 1000);
@ -2414,7 +2415,7 @@ describe('dockviewComponent', () => {
}, },
tabComponents: { tabComponents: {
test_tab_id: PanelTabPartTest, test_tab_id: PanelTabPartTest,
} },
}); });
dockview.layout(1000, 1000); dockview.layout(1000, 1000);
@ -2850,8 +2851,6 @@ describe('dockviewComponent', () => {
test('that external dnd events do not trigger the top-level center dnd target unless empty', () => { test('that external dnd events do not trigger the top-level center dnd target unless empty', () => {
const container = document.createElement('div'); const container = document.createElement('div');
const showDndOverlay = jest.fn().mockReturnValue(true);
const dockview = new DockviewComponent({ const dockview = new DockviewComponent({
parentElement: container, parentElement: container,
components: { components: {
@ -2860,7 +2859,13 @@ describe('dockviewComponent', () => {
tabComponents: { tabComponents: {
test_tab_id: PanelTabPartTest, test_tab_id: PanelTabPartTest,
}, },
showDndOverlay: showDndOverlay, });
let events: DockviewDndOverlayEvent[] = [];
dockview.onUnhandledDragOverEvent((e) => {
events.push(e);
e.accept();
}); });
dockview.layout(1000, 500); dockview.layout(1000, 500);
@ -2900,13 +2905,11 @@ describe('dockviewComponent', () => {
}); });
fireEvent(dockview.element, eventLeft); fireEvent(dockview.element, eventLeft);
expect(showDndOverlay).toHaveBeenCalledWith({ expect(events[0].nativeEvent).toBe(eventLeft);
nativeEvent: eventLeft, expect(events[0].position).toBe('left');
position: 'left', expect(events[0].target).toBe('edge');
target: 'edge', expect(events[0].getData).toBe(getPanelData);
getData: getPanelData, expect(events.length).toBe(1);
});
expect(showDndOverlay).toBeCalledTimes(1);
// right // right
@ -2919,13 +2922,11 @@ describe('dockviewComponent', () => {
}); });
fireEvent(dockview.element, eventRight); fireEvent(dockview.element, eventRight);
expect(showDndOverlay).toHaveBeenCalledWith({ expect(events[1].nativeEvent).toBe(eventRight);
nativeEvent: eventRight, expect(events[1].position).toBe('right');
position: 'right', expect(events[1].target).toBe('edge');
target: 'edge', expect(events[1].getData).toBe(getPanelData);
getData: getPanelData, expect(events.length).toBe(2);
});
expect(showDndOverlay).toBeCalledTimes(2);
// top // top
@ -2938,13 +2939,11 @@ describe('dockviewComponent', () => {
}); });
fireEvent(dockview.element, eventTop); fireEvent(dockview.element, eventTop);
expect(showDndOverlay).toHaveBeenCalledWith({ expect(events[2].nativeEvent).toBe(eventTop);
nativeEvent: eventTop, expect(events[2].position).toBe('top');
position: 'top', expect(events[2].target).toBe('edge');
target: 'edge', expect(events[2].getData).toBe(getPanelData);
getData: getPanelData, expect(events.length).toBe(3);
});
expect(showDndOverlay).toBeCalledTimes(3);
// top // top
@ -2957,13 +2956,11 @@ describe('dockviewComponent', () => {
}); });
fireEvent(dockview.element, eventBottom); fireEvent(dockview.element, eventBottom);
expect(showDndOverlay).toHaveBeenCalledWith({ expect(events[3].nativeEvent).toBe(eventBottom);
nativeEvent: eventBottom, expect(events[3].position).toBe('bottom');
position: 'bottom', expect(events[3].target).toBe('edge');
target: 'edge', expect(events[3].getData).toBe(getPanelData);
getData: getPanelData, expect(events.length).toBe(4);
});
expect(showDndOverlay).toBeCalledTimes(4);
// center // center
@ -2977,7 +2974,7 @@ describe('dockviewComponent', () => {
fireEvent(dockview.element, eventCenter); fireEvent(dockview.element, eventCenter);
// expect not to be called for center // expect not to be called for center
expect(showDndOverlay).toBeCalledTimes(4); expect(events.length).toBe(4);
dockview.removePanel(panel1); dockview.removePanel(panel1);
dockview.removePanel(panel2); dockview.removePanel(panel2);
@ -2993,13 +2990,11 @@ describe('dockviewComponent', () => {
}); });
fireEvent(dockview.element, eventCenter2); fireEvent(dockview.element, eventCenter2);
expect(showDndOverlay).toHaveBeenCalledWith({ expect(events[4].nativeEvent).toBe(eventCenter2);
nativeEvent: eventTop, expect(events[4].position).toBe('center');
position: 'center', expect(events[4].target).toBe('edge');
target: 'edge', expect(events[4].getData).toBe(getPanelData);
getData: getPanelData, expect(events.length).toBe(5);
});
expect(showDndOverlay).toBeCalledTimes(5);
}); });
test('that dragging a tab triggers onWillDragPanel', () => { test('that dragging a tab triggers onWillDragPanel', () => {
@ -4047,7 +4042,7 @@ describe('dockviewComponent', () => {
}, },
tabComponents: { tabComponents: {
test_tab_id: PanelTabPartTest, test_tab_id: PanelTabPartTest,
} },
}); });
dockview.layout(1000, 500); dockview.layout(1000, 500);
@ -4097,7 +4092,7 @@ describe('dockviewComponent', () => {
}, },
tabComponents: { tabComponents: {
test_tab_id: PanelTabPartTest, test_tab_id: PanelTabPartTest,
} },
}); });
dockview.layout(1000, 500); dockview.layout(1000, 500);
@ -4146,7 +4141,7 @@ describe('dockviewComponent', () => {
}, },
tabComponents: { tabComponents: {
test_tab_id: PanelTabPartTest, test_tab_id: PanelTabPartTest,
} },
}); });
dockview.layout(1000, 500); dockview.layout(1000, 500);
@ -4185,7 +4180,7 @@ describe('dockviewComponent', () => {
}, },
tabComponents: { tabComponents: {
test_tab_id: PanelTabPartTest, test_tab_id: PanelTabPartTest,
} },
}); });
dockview.layout(1000, 500); dockview.layout(1000, 500);
@ -4223,7 +4218,7 @@ describe('dockviewComponent', () => {
}, },
tabComponents: { tabComponents: {
test_tab_id: PanelTabPartTest, test_tab_id: PanelTabPartTest,
} },
}); });
dockview.layout(1000, 500); dockview.layout(1000, 500);
@ -4262,7 +4257,7 @@ describe('dockviewComponent', () => {
}, },
tabComponents: { tabComponents: {
test_tab_id: PanelTabPartTest, test_tab_id: PanelTabPartTest,
} },
}); });
dockview.layout(1000, 500); dockview.layout(1000, 500);
@ -4322,7 +4317,7 @@ describe('dockviewComponent', () => {
}, },
tabComponents: { tabComponents: {
test_tab_id: PanelTabPartTest, test_tab_id: PanelTabPartTest,
} },
}); });
dockview.layout(1000, 500); dockview.layout(1000, 500);
@ -4360,7 +4355,7 @@ describe('dockviewComponent', () => {
}, },
tabComponents: { tabComponents: {
test_tab_id: PanelTabPartTest, test_tab_id: PanelTabPartTest,
} },
}); });
dockview.layout(1000, 500); dockview.layout(1000, 500);
@ -4392,7 +4387,7 @@ describe('dockviewComponent', () => {
}, },
tabComponents: { tabComponents: {
test_tab_id: PanelTabPartTest, test_tab_id: PanelTabPartTest,
} },
}); });
dockview.layout(1000, 500); dockview.layout(1000, 500);
@ -4464,7 +4459,7 @@ describe('dockviewComponent', () => {
}, },
tabComponents: { tabComponents: {
test_tab_id: PanelTabPartTest, test_tab_id: PanelTabPartTest,
} },
}); });
dockview.layout(1000, 500); dockview.layout(1000, 500);
@ -4504,7 +4499,7 @@ describe('dockviewComponent', () => {
}, },
tabComponents: { tabComponents: {
test_tab_id: PanelTabPartTest, test_tab_id: PanelTabPartTest,
} },
}); });
const api = new DockviewApi(dockview); const api = new DockviewApi(dockview);

View File

@ -642,7 +642,6 @@ describe('dockviewGroupPanelModel', () => {
return { return {
id: 'testcomponentid', id: 'testcomponentid',
options: { options: {
showDndOverlay: jest.fn(),
parentElement: document.createElement('div'), parentElement: document.createElement('div'),
}, },
getPanel: jest.fn(), getPanel: jest.fn(),
@ -650,6 +649,7 @@ describe('dockviewGroupPanelModel', () => {
onDidRemovePanel: jest.fn(), onDidRemovePanel: jest.fn(),
}; };
}); });
const accessor = new accessorMock() as DockviewComponent; const accessor = new accessorMock() as DockviewComponent;
const groupviewMock = jest.fn<Partial<DockviewGroupPanelModel>, []>( const groupviewMock = jest.fn<Partial<DockviewGroupPanelModel>, []>(
() => { () => {
@ -679,6 +679,12 @@ describe('dockviewGroupPanelModel', () => {
new groupPanelMock() as DockviewGroupPanel new groupPanelMock() as DockviewGroupPanel
); );
let counter = 0;
cut.onUnhandledDragOverEvent(() => {
counter++;
});
const element = container const element = container
.getElementsByClassName('content-container') .getElementsByClassName('content-container')
.item(0)!; .item(0)!;
@ -691,7 +697,7 @@ describe('dockviewGroupPanelModel', () => {
fireEvent.dragEnter(element); fireEvent.dragEnter(element);
fireEvent.dragOver(element); fireEvent.dragOver(element);
expect(accessor.options.showDndOverlay).toBeCalledTimes(1); expect(counter).toBe(1);
expect( expect(
element.getElementsByClassName('drop-target-dropzone').length element.getElementsByClassName('drop-target-dropzone').length
@ -703,7 +709,6 @@ describe('dockviewGroupPanelModel', () => {
return { return {
id: 'testcomponentid', id: 'testcomponentid',
options: { options: {
showDndOverlay: () => true,
parentElement: document.createElement('div'), parentElement: document.createElement('div'),
}, },
getPanel: jest.fn(), getPanel: jest.fn(),
@ -740,6 +745,10 @@ describe('dockviewGroupPanelModel', () => {
new groupPanelMock() as DockviewGroupPanel new groupPanelMock() as DockviewGroupPanel
); );
cut.onUnhandledDragOverEvent((e) => {
e.accept();
});
const element = container const element = container
.getElementsByClassName('content-container') .getElementsByClassName('content-container')
.item(0)!; .item(0)!;
@ -795,7 +804,6 @@ describe('dockviewGroupPanelModel', () => {
return { return {
id: 'testcomponentid', id: 'testcomponentid',
options: { options: {
showDndOverlay: jest.fn(),
parentElement: document.createElement('div'), parentElement: document.createElement('div'),
}, },
getPanel: jest.fn(), getPanel: jest.fn(),
@ -834,6 +842,12 @@ describe('dockviewGroupPanelModel', () => {
new groupPanelMock() as DockviewGroupPanel new groupPanelMock() as DockviewGroupPanel
); );
let counter = 0;
cut.onUnhandledDragOverEvent(() => {
counter++;
});
cut.openPanel( cut.openPanel(
new TestPanel('panel1', { new TestPanel('panel1', {
renderer: 'onlyWhenVisibile', renderer: 'onlyWhenVisibile',
@ -857,7 +871,7 @@ describe('dockviewGroupPanelModel', () => {
fireEvent.dragEnter(element); fireEvent.dragEnter(element);
fireEvent.dragOver(element); fireEvent.dragOver(element);
expect(accessor.options.showDndOverlay).toBeCalledTimes(0); expect(counter).toBe(0);
expect( expect(
element.getElementsByClassName('drop-target-dropzone').length element.getElementsByClassName('drop-target-dropzone').length
@ -869,7 +883,6 @@ describe('dockviewGroupPanelModel', () => {
return { return {
id: 'testcomponentid', id: 'testcomponentid',
options: { options: {
showDndOverlay: jest.fn(),
parentElement: document.createElement('div'), parentElement: document.createElement('div'),
}, },
getPanel: jest.fn(), getPanel: jest.fn(),
@ -908,6 +921,12 @@ describe('dockviewGroupPanelModel', () => {
new groupPanelMock() as DockviewGroupPanel new groupPanelMock() as DockviewGroupPanel
); );
let counter = 0;
cut.onUnhandledDragOverEvent(() => {
counter++;
});
cut.openPanel( cut.openPanel(
new TestPanel('panel1', { new TestPanel('panel1', {
renderer: 'onlyWhenVisibile', renderer: 'onlyWhenVisibile',
@ -936,7 +955,7 @@ describe('dockviewGroupPanelModel', () => {
fireEvent.dragEnter(element); fireEvent.dragEnter(element);
fireEvent.dragOver(element); fireEvent.dragOver(element);
expect(accessor.options.showDndOverlay).toBeCalledTimes(0); expect(counter).toBe(0);
expect( expect(
element.getElementsByClassName('drop-target-dropzone').length element.getElementsByClassName('drop-target-dropzone').length
@ -948,7 +967,6 @@ describe('dockviewGroupPanelModel', () => {
return { return {
id: 'testcomponentid', id: 'testcomponentid',
options: { options: {
showDndOverlay: jest.fn(),
parentElement: document.createElement('div'), parentElement: document.createElement('div'),
}, },
getPanel: jest.fn(), getPanel: jest.fn(),
@ -987,6 +1005,12 @@ describe('dockviewGroupPanelModel', () => {
new groupPanelMock() as DockviewGroupPanel new groupPanelMock() as DockviewGroupPanel
); );
let counter = 0;
cut.onUnhandledDragOverEvent(() => {
counter++;
});
cut.openPanel( cut.openPanel(
new TestPanel('panel1', { new TestPanel('panel1', {
renderer: 'onlyWhenVisibile', renderer: 'onlyWhenVisibile',
@ -1015,7 +1039,7 @@ describe('dockviewGroupPanelModel', () => {
fireEvent.dragEnter(element); fireEvent.dragEnter(element);
fireEvent.dragOver(element); fireEvent.dragOver(element);
expect(accessor.options.showDndOverlay).toBeCalledTimes(1); expect(counter).toBe(1);
expect( expect(
element.getElementsByClassName('drop-target-dropzone').length element.getElementsByClassName('drop-target-dropzone').length

View File

@ -36,3 +36,7 @@ export interface IWatermarkPanelProps {
containerApi: DockviewApi; containerApi: DockviewApi;
group?: IDockviewGroupPanel; group?: IDockviewGroupPanel;
} }
export interface DockviewReadyEvent {
api: DockviewApi;
}

View File

@ -43,6 +43,7 @@ export {
IDockviewHeaderActionsProps, IDockviewHeaderActionsProps,
IGroupHeaderProps, IGroupHeaderProps,
IWatermarkPanelProps, IWatermarkPanelProps,
DockviewReadyEvent,
} from './dockview/framework'; } from './dockview/framework';
export * from './dockview/options'; export * from './dockview/options';

View File

@ -11,40 +11,61 @@ import {
type IWatermarkPanelProps, type IWatermarkPanelProps,
type DockviewOptions, type DockviewOptions,
PROPERTY_KEYS, PROPERTY_KEYS,
type DockviewEvents,
type DockviewFrameworkOptions, type DockviewFrameworkOptions,
} from 'dockview-core' type DockviewReadyEvent,
import { ref, onMounted, defineProps, defineEmits, watch, onBeforeUnmount } from 'vue' } from 'dockview-core';
import {
ref,
onMounted,
defineProps,
defineEmits,
watch,
onBeforeUnmount,
} from 'vue';
import { import {
VueContentRenderer, VueContentRenderer,
VueHeaderActionsRenderer, VueHeaderActionsRenderer,
VueTabRenderer, VueTabRenderer,
VueWatermarkRenderer, VueWatermarkRenderer,
type VueComponent type VueComponent,
} from '../utils' } from '../utils';
interface VueProps { interface VueProps {
// onReady: (event: DockviewReadyEvent) => void; components: Record<string, VueComponent<IDockviewPanelProps>>;
components: Record<string, VueComponent<IDockviewPanelProps>> tabComponents?: Record<string, VueComponent<IDockviewPanelHeaderProps>>;
tabComponents?: Record<string, VueComponent<IDockviewPanelHeaderProps>>
watermarkComponent?: VueComponent<IWatermarkPanelProps>; watermarkComponent?: VueComponent<IWatermarkPanelProps>;
// onDidDrop?: (event: DockviewDidDropEvent) => void; defaultTabComponent?: VueComponent<IDockviewPanelHeaderProps>;
// onWillDrop?: (event: DockviewWillDropEvent) => void; rightHeaderActionsComponent?: VueComponent<IGroupPanelBaseProps>;
// showDndOverlay?: (event: DockviewDndOverlayEvent) => boolean; leftHeaderActionsComponent?: VueComponent<IGroupPanelBaseProps>;
className?: string; prefixHeaderActionsComponent?: VueComponent<IGroupPanelBaseProps>;
defaultTabComponent?: VueComponent<IDockviewPanelHeaderProps>
rightHeaderActionsComponent?: VueComponent<IGroupPanelBaseProps>
leftHeaderActionsComponent?: VueComponent<IGroupPanelBaseProps>
prefixHeaderActionsComponent?: VueComponent<IGroupPanelBaseProps>
} }
type IDockviewVueProps = DockviewOptions & VueProps; const VUE_PROPERTIES = (() => {
const _value: Record<keyof VueProps, undefined> = {
components: undefined,
tabComponents: undefined,
watermarkComponent: undefined,
defaultTabComponent: undefined,
rightHeaderActionsComponent: undefined,
leftHeaderActionsComponent: undefined,
prefixHeaderActionsComponent: undefined,
};
return Object.keys(_value) as (keyof VueProps)[];
})();
type VueEvents = {
ready: [event: DockviewReadyEvent];
};
const DEFAULT_REACT_TAB = 'props.defaultTabComponent';
export type IDockviewVueProps = DockviewOptions & VueProps;
function extractCoreOptions(props: IDockviewVueProps): DockviewOptions { function extractCoreOptions(props: IDockviewVueProps): DockviewOptions {
const coreOptions = (PROPERTY_KEYS as (keyof DockviewOptions)[]).reduce( const coreOptions = (PROPERTY_KEYS as (keyof DockviewOptions)[]).reduce(
(obj, key) => { (obj, key) => {
(obj as any)[key] = props[key] (obj as any)[key] = props[key];
return obj; return obj;
}, },
{} as Partial<DockviewOptions> {} as Partial<DockviewOptions>
@ -53,67 +74,158 @@ function extractCoreOptions(props: IDockviewVueProps): DockviewOptions {
return coreOptions as DockviewOptions; return coreOptions as DockviewOptions;
} }
type VueEvents = { const emit = defineEmits<VueEvents>();
onReady: (event: {api: DockviewApi}) => void; const props = defineProps<IDockviewVueProps>();
}
type DockviewVueEvents = DockviewEvents & VueEvents; const el = ref<HTMLElement | null>(null);
const instance = ref<DockviewComponent | null>(null);
interface TestEvents { PROPERTY_KEYS.forEach((coreOptionKey) => {
onDidChange: (event: string, a: number) => void; watch(
onDidChange2?: (event: string, a: number) => void; () => props[coreOptionKey],
} (newValue, oldValue) => {
type StripEventSyntax<T> = T extends `on${infer E}` ? Uncapitalize<E> : T;
type FunctionValue<T extends (...args: any[]) => void> =
T extends (...args: infer G) => void ? G : never;
type Emitter<T extends Record<string, any>> = { [P in keyof T as StripEventSyntax<P>]-?:
FunctionValue<T[P]>
}
type VueEmits = Emitter<DockviewVueEvents>
const emit = defineEmits<VueEmits>();
const props = defineProps<IDockviewVueProps>()
const el = ref<HTMLElement | null>(null)
const instance = ref<DockviewComponent | null>(null)
PROPERTY_KEYS.forEach(coreOptionKey => {
watch(() => props[coreOptionKey], (newValue, oldValue) => {
if (instance.value) { if (instance.value) {
instance.value.updateOptions({ [coreOptionKey]: newValue }) instance.value.updateOptions({ [coreOptionKey]: newValue });
} }
}) }
}) );
});
watch(
() => props.components,
(newValue, oldValue) => {
if (instance.value) {
instance.value.updateOptions({ frameworkComponents: newValue });
}
}
);
watch(
() => [props.tabComponents, props.defaultTabComponent],
([newTabComponents, newDefaultTabComponent], oldValue) => {
if (instance.value) {
const frameworkTabComponents = newTabComponents ?? {};
if (newDefaultTabComponent) {
frameworkTabComponents[DEFAULT_REACT_TAB] =
newDefaultTabComponent;
}
instance.value.updateOptions({
defaultTabComponent: newDefaultTabComponent
? DEFAULT_REACT_TAB
: undefined,
frameworkTabComponents,
});
}
}
);
watch(
() => props.watermarkComponent,
(newValue, oldValue) => {
if (instance.value) {
instance.value.updateOptions({
watermarkFrameworkComponent: newValue,
});
}
}
);
watch(
() => props.leftHeaderActionsComponent,
(newValue, oldValue) => {
if (instance.value) {
instance.value.updateOptions({
headerLeftActionComponent: newValue
? (group) => {
return new VueHeaderActionsRenderer(
newValue as VueComponent,
group
);
}
: undefined,
});
}
}
);
watch(
() => props.rightHeaderActionsComponent,
(newValue, oldValue) => {
if (instance.value) {
instance.value.updateOptions({
headerRightActionComponent: newValue
? (group) => {
return new VueHeaderActionsRenderer(
newValue as VueComponent,
group
);
}
: undefined,
});
}
}
);
watch(
() => props.prefixHeaderActionsComponent,
(newValue, oldValue) => {
if (instance.value) {
instance.value.updateOptions({
headerPrefixActionComponent: newValue
? (group) => {
return new VueHeaderActionsRenderer(
newValue as VueComponent,
group
);
}
: undefined,
});
}
}
);
onMounted(() => { onMounted(() => {
if (!el.value) { if (!el.value) {
throw new Error('element is not mounted') throw new Error('element is not mounted');
}
const frameworkTabComponents = props.tabComponents ?? {};
if (props.defaultTabComponent) {
frameworkTabComponents[DEFAULT_REACT_TAB] = props.defaultTabComponent;
} }
const frameworkOptions: DockviewFrameworkOptions = { const frameworkOptions: DockviewFrameworkOptions = {
parentElement: el.value, parentElement: el.value,
frameworkComponentFactory: { frameworkComponentFactory: {
content: { content: {
createComponent: (id: string, componentId: string, component: any): IContentRenderer => { createComponent: (
return new VueContentRenderer(component) id: string,
} componentId: string,
component: any
): IContentRenderer => {
return new VueContentRenderer(component);
},
}, },
tab: { tab: {
createComponent: (id: string, componentId: string, component: any): ITabRenderer => { createComponent: (
return new VueTabRenderer(component) id: string,
} componentId: string,
component: any
): ITabRenderer => {
return new VueTabRenderer(component);
},
}, },
watermark: { watermark: {
createComponent: (id: string, componentId: string, component: any): IWatermarkRenderer => { createComponent: (
return new VueWatermarkRenderer(component) id: string,
} componentId: string,
component: any
): IWatermarkRenderer => {
return new VueWatermarkRenderer(component);
},
}, },
// action: { // action: {
// createComponent: (id: string, componentId: string, component: any): IWatermarkRenderer => { // createComponent: (id: string, componentId: string, component: any): IWatermarkRenderer => {
@ -122,39 +234,50 @@ onMounted(() => {
// } // }
}, },
frameworkComponents: props.components, frameworkComponents: props.components,
frameworkTabComponents: props.tabComponents, frameworkTabComponents,
headerLeftActionComponent: props.leftHeaderActionsComponent ? ((group) => { headerLeftActionComponent: props.leftHeaderActionsComponent
? (group) => {
return new VueHeaderActionsRenderer( return new VueHeaderActionsRenderer(
props.leftHeaderActionsComponent as VueComponent, props.leftHeaderActionsComponent as VueComponent,
group); group
}) : undefined, );
headerPrefixActionComponent: props.prefixHeaderActionsComponent ? (group) => { }
: undefined,
headerPrefixActionComponent: props.prefixHeaderActionsComponent
? (group) => {
return new VueHeaderActionsRenderer( return new VueHeaderActionsRenderer(
props.prefixHeaderActionsComponent as VueComponent, props.prefixHeaderActionsComponent as VueComponent,
group); group
} : undefined, );
headerRightActionComponent: props.rightHeaderActionsComponent ? (group) => { }
: undefined,
headerRightActionComponent: props.rightHeaderActionsComponent
? (group) => {
return new VueHeaderActionsRenderer( return new VueHeaderActionsRenderer(
props.rightHeaderActionsComponent as VueComponent, props.rightHeaderActionsComponent as VueComponent,
group); group
} : undefined, );
} }
: undefined,
defaultTabComponent: props.defaultTabComponent
? DEFAULT_REACT_TAB
: undefined,
};
const dockview = new DockviewComponent({ const dockview = new DockviewComponent({
...extractCoreOptions(props), ...extractCoreOptions(props),
...frameworkOptions ...frameworkOptions,
}) });
instance.value = dockview instance.value = dockview;
emit("ready", { api: new DockviewApi(dockview) }) emit('ready', { api: new DockviewApi(dockview) });
}) });
onBeforeUnmount(() => { onBeforeUnmount(() => {
if (instance.value) { if (instance.value) {
instance.value.dispose() instance.value.dispose();
} }
}) });
</script> </script>
<template> <template>

View File

@ -2,15 +2,18 @@ import * as React from 'react';
import { act, render, waitFor } from '@testing-library/react'; import { act, render, waitFor } from '@testing-library/react';
import { import {
DockviewApi, DockviewApi,
DockviewReadyEvent,
IDockviewPanel, IDockviewPanel,
IDockviewPanelProps, IDockviewPanelProps,
} from 'dockview-core'; } from 'dockview-core';
import { DockviewReact, DockviewReadyEvent } from '../../dockview/dockview'; import { DockviewReact } from '../../dockview/dockview';
import { PanelCollection } from '../../types';
import { setMockRefElement } from '../__test_utils__/utils'; import { setMockRefElement } from '../__test_utils__/utils';
describe('gridview react', () => { describe('gridview react', () => {
let components: PanelCollection<IDockviewPanelProps>; let components: Record<
string,
React.FunctionComponent<IDockviewPanelProps>
>;
beforeEach(() => { beforeEach(() => {
components = { components = {

View File

@ -6,11 +6,13 @@ import {
GridviewReact, GridviewReact,
GridviewReadyEvent, GridviewReadyEvent,
} from '../../gridview/gridview'; } from '../../gridview/gridview';
import { PanelCollection } from '../../types';
import { setMockRefElement } from '../__test_utils__/utils'; import { setMockRefElement } from '../__test_utils__/utils';
describe('gridview react', () => { describe('gridview react', () => {
let components: PanelCollection<IGridviewPanelProps>; let components: Record<
string,
React.FunctionComponent<IGridviewPanelProps>
>
beforeEach(() => { beforeEach(() => {
components = { components = {

View File

@ -6,11 +6,13 @@ import {
PaneviewReact, PaneviewReact,
PaneviewReadyEvent, PaneviewReadyEvent,
} from '../../paneview/paneview'; } from '../../paneview/paneview';
import { PanelCollection } from '../../types';
import { setMockRefElement } from '../__test_utils__/utils'; import { setMockRefElement } from '../__test_utils__/utils';
describe('gridview react', () => { describe('gridview react', () => {
let components: PanelCollection<IPaneviewPanelProps>; let components: Record<
string,
React.FunctionComponent<IPaneviewPanelProps>
>;
beforeEach(() => { beforeEach(() => {
components = { components = {

View File

@ -6,11 +6,13 @@ import {
SplitviewReact, SplitviewReact,
SplitviewReadyEvent, SplitviewReadyEvent,
} from '../../splitview/splitview'; } from '../../splitview/splitview';
import { PanelCollection } from '../../types';
import { setMockRefElement } from '../__test_utils__/utils'; import { setMockRefElement } from '../__test_utils__/utils';
describe('splitview react', () => { describe('splitview react', () => {
let components: PanelCollection<ISplitviewPanelProps>; let components: Record<
string,
React.FunctionComponent<ISplitviewPanelProps>
>;
beforeEach(() => { beforeEach(() => {
components = { components = {

View File

@ -19,6 +19,7 @@ import {
DockviewFrameworkOptions, DockviewFrameworkOptions,
IDockviewDisposable, IDockviewDisposable,
DockviewDndOverlayEvent, DockviewDndOverlayEvent,
DockviewReadyEvent,
} from 'dockview-core'; } from 'dockview-core';
import { ReactPanelContentPart } from './reactContentPart'; import { ReactPanelContentPart } from './reactContentPart';
import { ReactPanelHeaderPart } from './reactHeaderPart'; import { ReactPanelHeaderPart } from './reactHeaderPart';
@ -44,27 +45,23 @@ function createGroupControlElement(
const DEFAULT_REACT_TAB = 'props.defaultTabComponent'; const DEFAULT_REACT_TAB = 'props.defaultTabComponent';
export interface DockviewReadyEvent {
api: DockviewApi;
}
export interface IDockviewReactProps extends DockviewOptions { export interface IDockviewReactProps extends DockviewOptions {
className?: string; className?: string;
onReady: (event: DockviewReadyEvent) => void;
onDidDrop?: (event: DockviewDidDropEvent) => void;
onWillDrop?: (event: DockviewWillDropEvent) => void;
components: Record<string, React.FunctionComponent<IDockviewPanelProps>>;
tabComponents?: Record< tabComponents?: Record<
string, string,
React.FunctionComponent<IDockviewPanelHeaderProps> React.FunctionComponent<IDockviewPanelHeaderProps>
>; >;
components: Record<string, React.FunctionComponent<IDockviewPanelProps>>;
watermarkComponent?: React.FunctionComponent<IWatermarkPanelProps>; watermarkComponent?: React.FunctionComponent<IWatermarkPanelProps>;
defaultTabComponent?: React.FunctionComponent<IDockviewPanelHeaderProps>; defaultTabComponent?: React.FunctionComponent<IDockviewPanelHeaderProps>;
rightHeaderActionsComponent?: React.FunctionComponent<IDockviewHeaderActionsProps>; rightHeaderActionsComponent?: React.FunctionComponent<IDockviewHeaderActionsProps>;
leftHeaderActionsComponent?: React.FunctionComponent<IDockviewHeaderActionsProps>; leftHeaderActionsComponent?: React.FunctionComponent<IDockviewHeaderActionsProps>;
prefixHeaderActionsComponent?: React.FunctionComponent<IDockviewHeaderActionsProps>; prefixHeaderActionsComponent?: React.FunctionComponent<IDockviewHeaderActionsProps>;
// //
showDndOverlay: (event: DockviewDndOverlayEvent) => boolean; onReady: (event: DockviewReadyEvent) => void;
onDidDrop?: (event: DockviewDidDropEvent) => void;
onWillDrop?: (event: DockviewWillDropEvent) => void;
showDndOverlay?: (event: DockviewDndOverlayEvent) => boolean;
} }
function extractCoreOptions(props: IDockviewReactProps): DockviewOptions { function extractCoreOptions(props: IDockviewReactProps): DockviewOptions {
@ -229,7 +226,7 @@ export const DockviewReact = React.forwardRef(
const disposable = dockviewRef.current.onUnhandledDragOverEvent( const disposable = dockviewRef.current.onUnhandledDragOverEvent(
(event) => { (event) => {
if (props.showDndOverlay(event)) { if (props.showDndOverlay?.(event)) {
event.accept(); event.accept();
} }
} }
@ -276,15 +273,6 @@ export const DockviewReact = React.forwardRef(
}); });
}, [props.watermarkComponent]); }, [props.watermarkComponent]);
React.useEffect(() => {
if (!dockviewRef.current) {
return;
}
dockviewRef.current.updateOptions({
frameworkTabComponents: props.tabComponents,
});
}, [props.tabComponents]);
React.useEffect(() => { React.useEffect(() => {
if (!dockviewRef.current) { if (!dockviewRef.current) {
return; return;
@ -303,7 +291,7 @@ export const DockviewReact = React.forwardRef(
: undefined, : undefined,
frameworkTabComponents, frameworkTabComponents,
}); });
}, [props.defaultTabComponent]); }, [props.tabComponents, props.defaultTabComponent]);
React.useEffect(() => { React.useEffect(() => {
if (!dockviewRef.current) { if (!dockviewRef.current) {