|
@@ -1,10 +1,10 @@
|
|
|
-import type { Component } from 'vue';
|
|
|
+import type { Component, VNode } from 'vue';
|
|
|
|
|
|
import type { Recordable } from '@vben-core/typings';
|
|
|
|
|
|
-import type { AlertProps, BeforeCloseScope } from './alert';
|
|
|
+import type { AlertProps, BeforeCloseScope, PromptProps } from './alert';
|
|
|
|
|
|
-import { h, ref, render } from 'vue';
|
|
|
+import { h, nextTick, ref, render } from 'vue';
|
|
|
|
|
|
import { useSimpleLocale } from '@vben-core/composables';
|
|
|
import { Input } from '@vben-core/shadcn-ui';
|
|
@@ -130,40 +130,58 @@ export function vbenConfirm(
|
|
|
}
|
|
|
|
|
|
export async function vbenPrompt<T = any>(
|
|
|
- options: Omit<AlertProps, 'beforeClose'> & {
|
|
|
- beforeClose?: (scope: {
|
|
|
- isConfirm: boolean;
|
|
|
- value: T | undefined;
|
|
|
- }) => boolean | Promise<boolean | undefined> | undefined;
|
|
|
- component?: Component;
|
|
|
- componentProps?: Recordable<any>;
|
|
|
- defaultValue?: T;
|
|
|
- modelPropName?: string;
|
|
|
- },
|
|
|
+ options: PromptProps<T>,
|
|
|
): Promise<T | undefined> {
|
|
|
const {
|
|
|
component: _component,
|
|
|
componentProps: _componentProps,
|
|
|
+ componentSlots,
|
|
|
content,
|
|
|
defaultValue,
|
|
|
modelPropName: _modelPropName,
|
|
|
...delegated
|
|
|
} = options;
|
|
|
- const contents: Component[] = [];
|
|
|
+
|
|
|
const modelValue = ref<T | undefined>(defaultValue);
|
|
|
+ const inputComponentRef = ref<null | VNode>(null);
|
|
|
+ const staticContents: Component[] = [];
|
|
|
+
|
|
|
if (isString(content)) {
|
|
|
- contents.push(h('span', content));
|
|
|
- } else {
|
|
|
- contents.push(content);
|
|
|
+ staticContents.push(h('span', content));
|
|
|
+ } else if (content) {
|
|
|
+ staticContents.push(content as Component);
|
|
|
}
|
|
|
- const componentProps = _componentProps || {};
|
|
|
+
|
|
|
const modelPropName = _modelPropName || 'modelValue';
|
|
|
- componentProps[modelPropName] = modelValue.value;
|
|
|
- componentProps[`onUpdate:${modelPropName}`] = (val: any) => {
|
|
|
- modelValue.value = val;
|
|
|
+ const componentProps = { ..._componentProps };
|
|
|
+
|
|
|
+ // 每次渲染时都会重新计算的内容函数
|
|
|
+ const contentRenderer = () => {
|
|
|
+ const currentProps = { ...componentProps };
|
|
|
+
|
|
|
+ // 设置当前值
|
|
|
+ currentProps[modelPropName] = modelValue.value;
|
|
|
+
|
|
|
+ // 设置更新处理函数
|
|
|
+ currentProps[`onUpdate:${modelPropName}`] = (val: T) => {
|
|
|
+ modelValue.value = val;
|
|
|
+ };
|
|
|
+
|
|
|
+ // 创建输入组件
|
|
|
+ inputComponentRef.value = h(
|
|
|
+ _component || Input,
|
|
|
+ currentProps,
|
|
|
+ componentSlots,
|
|
|
+ );
|
|
|
+
|
|
|
+ // 返回包含静态内容和输入组件的数组
|
|
|
+ return h(
|
|
|
+ 'div',
|
|
|
+ { class: 'flex flex-col gap-2' },
|
|
|
+ { default: () => [...staticContents, inputComponentRef.value] },
|
|
|
+ );
|
|
|
};
|
|
|
- const componentRef = h(_component || Input, componentProps);
|
|
|
- contents.push(componentRef);
|
|
|
+
|
|
|
const props: AlertProps & Recordable<any> = {
|
|
|
...delegated,
|
|
|
async beforeClose(scope: BeforeCloseScope) {
|
|
@@ -174,23 +192,46 @@ export async function vbenPrompt<T = any>(
|
|
|
});
|
|
|
}
|
|
|
},
|
|
|
- content: h(
|
|
|
- 'div',
|
|
|
- { class: 'flex flex-col gap-2' },
|
|
|
- { default: () => contents },
|
|
|
- ),
|
|
|
- onOpened() {
|
|
|
- // 组件挂载完成后,自动聚焦到输入组件
|
|
|
- if (
|
|
|
- componentRef.component?.exposed &&
|
|
|
- isFunction(componentRef.component.exposed.focus)
|
|
|
- ) {
|
|
|
- componentRef.component.exposed.focus();
|
|
|
- } else if (componentRef.el && isFunction(componentRef.el.focus)) {
|
|
|
- componentRef.el.focus();
|
|
|
+ // 使用函数形式,每次渲染都会重新计算内容
|
|
|
+ content: contentRenderer,
|
|
|
+ contentMasking: true,
|
|
|
+ async onOpened() {
|
|
|
+ await nextTick();
|
|
|
+ const componentRef: null | VNode = inputComponentRef.value;
|
|
|
+ if (componentRef) {
|
|
|
+ if (
|
|
|
+ componentRef.component?.exposed &&
|
|
|
+ isFunction(componentRef.component.exposed.focus)
|
|
|
+ ) {
|
|
|
+ componentRef.component.exposed.focus();
|
|
|
+ } else {
|
|
|
+ if (componentRef.el) {
|
|
|
+ if (
|
|
|
+ isFunction(componentRef.el.focus) &&
|
|
|
+ ['BUTTON', 'INPUT', 'SELECT', 'TEXTAREA'].includes(
|
|
|
+ componentRef.el.tagName,
|
|
|
+ )
|
|
|
+ ) {
|
|
|
+ componentRef.el.focus();
|
|
|
+ } else if (isFunction(componentRef.el.querySelector)) {
|
|
|
+ const focusableElement = componentRef.el.querySelector(
|
|
|
+ 'input, select, textarea, button',
|
|
|
+ );
|
|
|
+ if (focusableElement && isFunction(focusableElement.focus)) {
|
|
|
+ focusableElement.focus();
|
|
|
+ }
|
|
|
+ } else if (
|
|
|
+ componentRef.el.nextElementSibling &&
|
|
|
+ isFunction(componentRef.el.nextElementSibling.focus)
|
|
|
+ ) {
|
|
|
+ componentRef.el.nextElementSibling.focus();
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
}
|
|
|
},
|
|
|
};
|
|
|
+
|
|
|
await vbenConfirm(props);
|
|
|
return modelValue.value;
|
|
|
}
|