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

@ -1,162 +1,285 @@
<script setup lang="ts"> <script setup lang="ts">
import { import {
DockviewApi, DockviewApi,
DockviewComponent, DockviewComponent,
type IContentRenderer, type IContentRenderer,
type ITabRenderer, type ITabRenderer,
type IWatermarkRenderer, type IWatermarkRenderer,
type IDockviewPanelProps, type IDockviewPanelProps,
type IDockviewPanelHeaderProps, type IDockviewPanelHeaderProps,
type IGroupPanelBaseProps, type IGroupPanelBaseProps,
type IWatermarkPanelProps, type IWatermarkPanelProps,
type DockviewOptions, type DockviewOptions,
PROPERTY_KEYS, PROPERTY_KEYS,
type DockviewEvents, type DockviewFrameworkOptions,
type DockviewFrameworkOptions, type DockviewReadyEvent,
} from 'dockview-core' } from 'dockview-core';
import { ref, onMounted, defineProps, defineEmits, watch, onBeforeUnmount } from 'vue'
import { import {
VueContentRenderer, ref,
VueHeaderActionsRenderer, onMounted,
VueTabRenderer, defineProps,
VueWatermarkRenderer, defineEmits,
type VueComponent watch,
} from '../utils' onBeforeUnmount,
} from 'vue';
import {
VueContentRenderer,
VueHeaderActionsRenderer,
VueTabRenderer,
VueWatermarkRenderer,
type VueComponent,
} 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>; defaultTabComponent?: VueComponent<IDockviewPanelHeaderProps>;
// onDidDrop?: (event: DockviewDidDropEvent) => void; rightHeaderActionsComponent?: VueComponent<IGroupPanelBaseProps>;
// onWillDrop?: (event: DockviewWillDropEvent) => void; leftHeaderActionsComponent?: VueComponent<IGroupPanelBaseProps>;
// showDndOverlay?: (event: DockviewDndOverlayEvent) => boolean; prefixHeaderActionsComponent?: VueComponent<IGroupPanelBaseProps>;
className?: string;
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,
};
function extractCoreOptions(props: IDockviewVueProps): DockviewOptions { return Object.keys(_value) as (keyof VueProps)[];
const coreOptions = (PROPERTY_KEYS as (keyof DockviewOptions)[]).reduce( })();
(obj, key) => {
(obj as any)[key] = props[key]
return obj;
},
{} as Partial<DockviewOptions>
);
return coreOptions as DockviewOptions;
}
type VueEvents = { type VueEvents = {
onReady: (event: {api: DockviewApi}) => void; ready: [event: DockviewReadyEvent];
};
const DEFAULT_REACT_TAB = 'props.defaultTabComponent';
export type IDockviewVueProps = DockviewOptions & VueProps;
function extractCoreOptions(props: IDockviewVueProps): DockviewOptions {
const coreOptions = (PROPERTY_KEYS as (keyof DockviewOptions)[]).reduce(
(obj, key) => {
(obj as any)[key] = props[key];
return obj;
},
{} as Partial<DockviewOptions>
);
return coreOptions as DockviewOptions;
} }
type DockviewVueEvents = DockviewEvents & VueEvents; const emit = defineEmits<VueEvents>();
const props = defineProps<IDockviewVueProps>();
interface TestEvents { const el = ref<HTMLElement | null>(null);
onDidChange: (event: string, a: number) => void; const instance = ref<DockviewComponent | null>(null);
onDidChange2?: (event: string, a: number) => void;
}
type StripEventSyntax<T> = T extends `on${infer E}` ? Uncapitalize<E> : T; PROPERTY_KEYS.forEach((coreOptionKey) => {
watch(
() => props[coreOptionKey],
(newValue, oldValue) => {
if (instance.value) {
instance.value.updateOptions({ [coreOptionKey]: newValue });
}
}
);
});
type FunctionValue<T extends (...args: any[]) => void> = watch(
T extends (...args: infer G) => void ? G : never; () => props.components,
(newValue, oldValue) => {
type Emitter<T extends Record<string, any>> = { [P in keyof T as StripEventSyntax<P>]-?: if (instance.value) {
FunctionValue<T[P]> instance.value.updateOptions({ frameworkComponents: newValue });
} }
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) {
instance.value.updateOptions({ [coreOptionKey]: 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 frameworkOptions: DockviewFrameworkOptions = { const frameworkTabComponents = props.tabComponents ?? {};
parentElement: el.value,
frameworkComponentFactory: {
content: {
createComponent: (id: string, componentId: string, component: any): IContentRenderer => {
return new VueContentRenderer(component)
}
},
tab: {
createComponent: (id: string, componentId: string, component: any): ITabRenderer => {
return new VueTabRenderer(component)
}
},
watermark: {
createComponent: (id: string, componentId: string, component: any): IWatermarkRenderer => {
return new VueWatermarkRenderer(component)
}
},
// action: {
// createComponent: (id: string, componentId: string, component: any): IWatermarkRenderer => {
// return new VueHeaderActionRenderer(component)
// }
// }
},
frameworkComponents: props.components,
frameworkTabComponents: props.tabComponents,
headerLeftActionComponent: props.leftHeaderActionsComponent ? ((group) => {
return new VueHeaderActionsRenderer(
props.leftHeaderActionsComponent as VueComponent,
group);
}) : undefined,
headerPrefixActionComponent: props.prefixHeaderActionsComponent ? (group) => {
return new VueHeaderActionsRenderer(
props.prefixHeaderActionsComponent as VueComponent,
group);
} : undefined,
headerRightActionComponent: props.rightHeaderActionsComponent ? (group) => {
return new VueHeaderActionsRenderer(
props.rightHeaderActionsComponent as VueComponent,
group);
} : undefined,
}
const dockview = new DockviewComponent({ if (props.defaultTabComponent) {
...extractCoreOptions(props), frameworkTabComponents[DEFAULT_REACT_TAB] = props.defaultTabComponent;
...frameworkOptions }
})
instance.value = dockview const frameworkOptions: DockviewFrameworkOptions = {
emit("ready", { api: new DockviewApi(dockview) }) parentElement: el.value,
}) frameworkComponentFactory: {
content: {
createComponent: (
id: string,
componentId: string,
component: any
): IContentRenderer => {
return new VueContentRenderer(component);
},
},
tab: {
createComponent: (
id: string,
componentId: string,
component: any
): ITabRenderer => {
return new VueTabRenderer(component);
},
},
watermark: {
createComponent: (
id: string,
componentId: string,
component: any
): IWatermarkRenderer => {
return new VueWatermarkRenderer(component);
},
},
// action: {
// createComponent: (id: string, componentId: string, component: any): IWatermarkRenderer => {
// return new VueHeaderActionRenderer(component)
// }
// }
},
frameworkComponents: props.components,
frameworkTabComponents,
headerLeftActionComponent: props.leftHeaderActionsComponent
? (group) => {
return new VueHeaderActionsRenderer(
props.leftHeaderActionsComponent as VueComponent,
group
);
}
: undefined,
headerPrefixActionComponent: props.prefixHeaderActionsComponent
? (group) => {
return new VueHeaderActionsRenderer(
props.prefixHeaderActionsComponent as VueComponent,
group
);
}
: undefined,
headerRightActionComponent: props.rightHeaderActionsComponent
? (group) => {
return new VueHeaderActionsRenderer(
props.rightHeaderActionsComponent as VueComponent,
group
);
}
: undefined,
defaultTabComponent: props.defaultTabComponent
? DEFAULT_REACT_TAB
: undefined,
};
const dockview = new DockviewComponent({
...extractCoreOptions(props),
...frameworkOptions,
});
instance.value = 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>
<div ref="el" /> <div ref="el" />
</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) {