This commit is contained in:
dap
2025-11-30 01:57:18 +08:00
152 changed files with 632 additions and 273 deletions

View File

@@ -144,24 +144,26 @@ export async function vbenPrompt<T = any>(
const modelValue = ref<T | undefined>(defaultValue);
const inputComponentRef = ref<null | VNode>(null);
const staticContents: Component[] = [];
staticContents.push(h(VbenRenderContent, { content, renderBr: true }));
const staticContents: Component[] = [
h(VbenRenderContent, { content, renderBr: true }),
];
const modelPropName = _modelPropName || 'modelValue';
const componentProps = { ..._componentProps };
// 每次渲染时都会重新计算的内容函数
const contentRenderer = () => {
const currentProps = { ...componentProps };
const currentProps = {
...componentProps,
[modelPropName]: modelValue.value,
[`onUpdate:${modelPropName}`]: (val: T) => {
modelValue.value = val;
},
};
// 设置当前值
currentProps[modelPropName] = modelValue.value;
// 设置更新处理函数
currentProps[`onUpdate:${modelPropName}`] = (val: T) => {
modelValue.value = val;
};
// 创建输入组件
inputComponentRef.value = h(

View File

@@ -149,7 +149,7 @@ async function handleOpenChange(val: boolean) {
containerClass,
'left-0 right-0 mx-auto flex max-h-[80%] flex-col p-0 duration-300 sm:w-[520px] sm:max-w-[80%] sm:rounded-[var(--radius)]',
{
'border-border border': bordered,
'border border-border': bordered,
'shadow-3xl': !bordered,
},
)
@@ -168,7 +168,7 @@ async function handleOpenChange(val: boolean) {
:disabled="loading"
@click="handleCancel"
>
<X class="text-muted-foreground size-4" />
<X class="size-4 text-muted-foreground" />
</VbenButton>
</AlertDialogCancel>
</div>

View File

@@ -223,7 +223,7 @@ const getForceMount = computed(() => {
v-if="closable && closeIconPlacement === 'left'"
as-child
:disabled="submitting"
class="data-[state=open]:bg-secondary ml-[2px] cursor-pointer rounded-full opacity-80 transition-opacity hover:opacity-100 focus:outline-none disabled:pointer-events-none"
class="ml-[2px] cursor-pointer rounded-full opacity-80 transition-opacity hover:opacity-100 focus:outline-none disabled:pointer-events-none data-[state=open]:bg-secondary"
>
<slot name="close-icon">
<VbenIconButton>
@@ -264,7 +264,7 @@ const getForceMount = computed(() => {
v-if="closable && closeIconPlacement === 'right'"
as-child
:disabled="submitting"
class="data-[state=open]:bg-secondary ml-[2px] cursor-pointer rounded-full opacity-80 transition-opacity hover:opacity-100 focus:outline-none disabled:pointer-events-none"
class="ml-[2px] cursor-pointer rounded-full opacity-80 transition-opacity hover:opacity-100 focus:outline-none disabled:pointer-events-none data-[state=open]:bg-secondary"
>
<slot name="close-icon">
<VbenIconButton>

View File

@@ -104,6 +104,10 @@ const shouldDraggable = computed(
() => draggable.value && !shouldFullscreen.value && header.value,
);
const shouldCentered = computed(
() => centered.value && !shouldFullscreen.value,
);
const getAppendTo = computed(() => {
return appendToMain.value
? `#${ELEMENT_ID_MAIN_CONTENT}>div:not(.absolute)>div`
@@ -115,6 +119,7 @@ const { dragging, transform } = useModalDraggable(
headerRef,
shouldDraggable,
getAppendTo,
shouldCentered,
);
const firstOpened = ref(false);
@@ -132,7 +137,9 @@ watch(
dialogRef.value = innerContentRef.$el;
// reopen modal reassign value
const { offsetX, offsetY } = transform;
dialogRef.value.style.transform = `translate(${offsetX}px, ${offsetY}px)`;
dialogRef.value.style.transform = shouldCentered.value
? `translate(${offsetX}px, calc(-50% + ${offsetY}px))`
: `translate(${offsetX}px, ${offsetY}px)`;
}
},
{ immediate: true },
@@ -235,11 +242,11 @@ function handleClosed() {
shouldFullscreen ? 'sm:rounded-none' : 'sm:rounded-[var(--radius)]',
modalClass,
{
'border-border border': bordered,
'border border-border': bordered,
'shadow-3xl': !bordered,
'left-0 top-0 size-full max-h-full !translate-x-0 !translate-y-0':
shouldFullscreen,
'top-1/2 !-translate-y-1/2': centered && !shouldFullscreen,
'top-1/2': centered && !shouldFullscreen,
'duration-300': !dragging,
hidden: isClosed,
},
@@ -311,7 +318,7 @@ function handleClosed() {
<VbenLoading v-if="showLoading || submitting" spinning />
<VbenIconButton
v-if="fullscreenButton"
class="hover:bg-accent hover:text-accent-foreground text-foreground/80 flex-center absolute right-10 top-3 hidden size-6 rounded-full px-1 text-lg opacity-70 transition-opacity hover:opacity-100 focus:outline-none disabled:pointer-events-none sm:block"
class="flex-center absolute right-10 top-3 hidden size-6 rounded-full px-1 text-lg text-foreground/80 opacity-70 transition-opacity hover:bg-accent hover:text-accent-foreground hover:opacity-100 focus:outline-none disabled:pointer-events-none sm:block"
@click="handleFullscreen"
>
<Shrink v-if="fullscreen" class="size-3.5" />

View File

@@ -5,14 +5,17 @@
import type { ComputedRef, Ref } from 'vue';
import { unrefElement } from '@vueuse/core';
import { onBeforeUnmount, onMounted, reactive, ref, watchEffect } from 'vue';
import { unrefElement } from '@vueuse/core';
export function useModalDraggable(
targetRef: Ref<HTMLElement | undefined>,
dragRef: Ref<HTMLElement | undefined>,
draggable: ComputedRef<boolean>,
containerSelector?: ComputedRef<string | undefined>,
centered?: ComputedRef<boolean>,
) {
const transform = reactive({
offsetX: 0,
@@ -72,7 +75,10 @@ export function useModalDraggable(
transform.offsetY = moveY;
if (targetRef.value) {
targetRef.value.style.transform = `translate(${moveX}px, ${moveY}px)`;
const isCentered = centered?.value;
targetRef.value.style.transform = isCentered
? `translate(${moveX}px, calc(-50% + ${moveY}px))`
: `translate(${moveX}px, ${moveY}px)`;
dragging.value = true;
}
};
@@ -107,7 +113,7 @@ export function useModalDraggable(
const target = unrefElement(targetRef);
if (target) {
target.style.transform = 'none';
target.style.transform = '';
}
};