import type {
|
DrawerApiOptions,
|
DrawerProps,
|
ExtendedDrawerApi,
|
} from './drawer';
|
|
import {
|
defineComponent,
|
h,
|
inject,
|
nextTick,
|
provide,
|
reactive,
|
ref,
|
} from 'vue';
|
|
import { useStore } from '@vben-core/shared/store';
|
|
import { DrawerApi } from './drawer-api';
|
import VbenDrawer from './drawer.vue';
|
|
const USER_DRAWER_INJECT_KEY = Symbol('VBEN_DRAWER_INJECT');
|
|
const DEFAULT_DRAWER_PROPS: Partial<DrawerProps> = {};
|
|
export function setDefaultDrawerProps(props: Partial<DrawerProps>) {
|
Object.assign(DEFAULT_DRAWER_PROPS, props);
|
}
|
|
export function useVbenDrawer<
|
TParentDrawerProps extends DrawerProps = DrawerProps,
|
>(options: DrawerApiOptions = {}) {
|
// Drawer一般会抽离出来,所以如果有传入 connectedComponent,则表示为外部调用,与内部组件进行连接
|
// 外部的Drawer通过provide/inject传递api
|
|
const { connectedComponent } = options;
|
if (connectedComponent) {
|
const extendedApi = reactive({});
|
const isDrawerReady = ref(true);
|
const Drawer = defineComponent(
|
(props: TParentDrawerProps, { attrs, slots }) => {
|
provide(USER_DRAWER_INJECT_KEY, {
|
extendApi(api: ExtendedDrawerApi) {
|
// 不能直接给 reactive 赋值,会丢失响应
|
// 不能用 Object.assign,会丢失 api 的原型函数
|
Object.setPrototypeOf(extendedApi, api);
|
},
|
options,
|
async reCreateDrawer() {
|
isDrawerReady.value = false;
|
await nextTick();
|
isDrawerReady.value = true;
|
},
|
});
|
checkProps(extendedApi as ExtendedDrawerApi, {
|
...props,
|
...attrs,
|
...slots,
|
});
|
return () =>
|
h(
|
isDrawerReady.value ? connectedComponent : 'div',
|
{ ...props, ...attrs },
|
slots,
|
);
|
},
|
{
|
inheritAttrs: false,
|
name: 'VbenParentDrawer',
|
},
|
);
|
return [Drawer, extendedApi as ExtendedDrawerApi] as const;
|
}
|
|
const injectData = inject<any>(USER_DRAWER_INJECT_KEY, {});
|
|
const mergedOptions = {
|
...DEFAULT_DRAWER_PROPS,
|
...injectData.options,
|
...options,
|
} as DrawerApiOptions;
|
|
mergedOptions.onOpenChange = (isOpen: boolean) => {
|
options.onOpenChange?.(isOpen);
|
injectData.options?.onOpenChange?.(isOpen);
|
};
|
|
const onClosed = mergedOptions.onClosed;
|
mergedOptions.onClosed = () => {
|
onClosed?.();
|
if (mergedOptions.destroyOnClose) {
|
injectData.reCreateDrawer?.();
|
}
|
};
|
const api = new DrawerApi(mergedOptions);
|
|
const extendedApi: ExtendedDrawerApi = api as never;
|
|
extendedApi.useStore = (selector) => {
|
return useStore(api.store, selector);
|
};
|
|
const Drawer = defineComponent(
|
(props: DrawerProps, { attrs, slots }) => {
|
return () =>
|
h(VbenDrawer, { ...props, ...attrs, drawerApi: extendedApi }, slots);
|
},
|
{
|
inheritAttrs: false,
|
name: 'VbenDrawer',
|
},
|
);
|
injectData.extendApi?.(extendedApi);
|
return [Drawer, extendedApi] as const;
|
}
|
|
async function checkProps(api: ExtendedDrawerApi, attrs: Record<string, any>) {
|
if (!attrs || Object.keys(attrs).length === 0) {
|
return;
|
}
|
await nextTick();
|
|
const state = api?.store?.state;
|
|
if (!state) {
|
return;
|
}
|
|
const stateKeys = new Set(Object.keys(state));
|
|
for (const attr of Object.keys(attrs)) {
|
if (stateKeys.has(attr) && !['class'].includes(attr)) {
|
// connectedComponent存在时,不要传入Drawer的props,会造成复杂度提升,如果你需要修改Drawer的props,请使用 useVbenDrawer 或者api
|
console.warn(
|
`[Vben Drawer]: When 'connectedComponent' exists, do not set props or slots '${attr}', which will increase complexity. If you need to modify the props of Drawer, please use useVbenDrawer or api.`,
|
);
|
}
|
}
|
}
|