feat: make sure panel vue component be child of DockViewVue component

This commit is contained in:
chuyuan.du 2024-07-31 18:05:32 +08:00
parent 5b9dbdf57e
commit 73e5dc3571
6 changed files with 72 additions and 15 deletions

View File

@ -1857,11 +1857,6 @@ export class DockviewComponent
throw new Error(`No panel with id ${sourceItemId}`); throw new Error(`No panel with id ${sourceItemId}`);
} }
if (sourceGroup.model.size === 0) {
// remove the group and do not set a new group as active
this.doRemoveGroup(sourceGroup, { skipActive: true });
}
this.movingLock(() => this.movingLock(() =>
destinationGroup.model.openPanel(removedPanel, { destinationGroup.model.openPanel(removedPanel, {
index: destinationIndex, index: destinationIndex,
@ -1870,6 +1865,11 @@ export class DockviewComponent
); );
this.doSetGroupAndPanelActive(destinationGroup); this.doSetGroupAndPanelActive(destinationGroup);
if (sourceGroup.model.size === 0) {
// remove the group and do not set a new group as active
this.doRemoveGroup(sourceGroup, { skipActive: true });
}
this._onDidMovePanel.fire({ this._onDidMovePanel.fire({
panel: removedPanel, panel: removedPanel,
from: sourceGroup, from: sourceGroup,

View File

@ -15,6 +15,8 @@ import {
onBeforeUnmount, onBeforeUnmount,
markRaw, markRaw,
getCurrentInstance, getCurrentInstance,
reactive,
mergeProps,
} from 'vue'; } from 'vue';
import { import {
VueHeaderActionsRenderer, VueHeaderActionsRenderer,
@ -22,7 +24,8 @@ import {
VueWatermarkRenderer, VueWatermarkRenderer,
findComponent, findComponent,
} from '../utils'; } from '../utils';
import type { IDockviewVueProps, VueEvents } from './types'; import type { IDockviewVueProps, VNodeType, VueEvents } from './types';
import Tele from './teleport.vue'
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(
@ -174,8 +177,29 @@ onBeforeUnmount(() => {
instance.value.dispose(); instance.value.dispose();
} }
}); });
const vnodes = reactive<VNodeType[]>([]);
defineExpose({
add(item: VNodeType) {
vnodes.push(item)
},
remove(key: symbol) {
const index = vnodes.findIndex(item => item.key === key);
if(index > -1) {
vnodes.splice(index, 1);
}
},
update(key: symbol, props: Record<string, any>) {
const item = vnodes.find(item => item.key === key);
if(item) {
item.props = mergeProps(item.props, props);
}
}
})
</script> </script>
<template> <template>
<div ref="el" /> <div ref="el" :="$attrs" />
<Tele :items="vnodes"/>
</template> </template>

View File

@ -0,0 +1,13 @@
<script setup lang="ts">
import type { VNodeType } from './types';
const props = defineProps<{
items: VNodeType[]
}>();
</script>
<template>
<Teleport v-for="item in props.items" :key="item.key" :to="item.target">
<component :is="item.component" :=item.props></component>
</Teleport>
</template>

View File

@ -1,4 +1,5 @@
import { type DockviewOptions, type DockviewReadyEvent } from 'dockview-core'; import { type DockviewOptions, type DockviewReadyEvent } from 'dockview-core';
import type { Component } from 'vue';
export interface VueProps { export interface VueProps {
watermarkComponent?: string; watermarkComponent?: string;
@ -13,3 +14,10 @@ export type VueEvents = {
}; };
export type IDockviewVueProps = DockviewOptions & VueProps; export type IDockviewVueProps = DockviewOptions & VueProps;
export type VNodeType = {
key: symbol;
component: Component;
props: any;
target: HTMLElement;
}

View File

@ -21,6 +21,7 @@ import {
cloneVNode, cloneVNode,
type DefineComponent, type DefineComponent,
type ComponentInternalInstance, type ComponentInternalInstance,
markRaw,
} from 'vue'; } from 'vue';
export type ComponentInterface = ComponentOptionsBase< export type ComponentInterface = ComponentOptionsBase<
@ -69,22 +70,32 @@ export function mountVueComponent<T extends Record<string, any>>(
props: T, props: T,
element: HTMLElement element: HTMLElement
) { ) {
let vNode = createVNode(component, Object.freeze(props)); // let vNode = createVNode(component, Object.freeze(props));
vNode.appContext = parent.appContext; // vNode.appContext = parent.appContext;
render(vNode, element); // render(vNode, element);
let runningProps = props; // let runningProps = props;
const key = Symbol();
parent.exposed!.add({
key,
component: markRaw(component),
target: markRaw(element),
props,
});
return { return {
update: (newProps: any) => { update: (newProps: any) => {
runningProps = { ...props, ...newProps }; // runningProps = { ...props, ...newProps };
vNode = cloneVNode(vNode, runningProps); // vNode = cloneVNode(vNode, runningProps);
render(vNode, element); // render(vNode, element);
parent.exposed!.update(key, newProps);
}, },
dispose: () => { dispose: () => {
render(null, element); // render(null, element);
parent.exposed!.remove(key);
}, },
}; };
} }

View File

@ -4,6 +4,7 @@
"include": ["env.d.ts", "src/**/*", "src/**/*.vue"], "include": ["env.d.ts", "src/**/*", "src/**/*.vue"],
"exclude": ["src/**/__tests__/*", "src/**/*.cy.ts"], "exclude": ["src/**/__tests__/*", "src/**/*.cy.ts"],
"compilerOptions": { "compilerOptions": {
"jsxImportSource": "vue",
"composite": true, "composite": true,
"baseUrl": "." "baseUrl": "."
} }