feat: add opened and closed events for dialog (#4775)

This commit is contained in:
Netfan
2024-10-31 22:05:18 +08:00
committed by GitHub
parent 353e8be289
commit 06ba7cb224
7 changed files with 80 additions and 9 deletions

View File

@@ -110,4 +110,19 @@ describe('modalApi', () => {
expect(modalApi.store.state.title).toBe('Batch Title');
expect(modalApi.store.state.confirmText).toBe('Batch Confirm');
});
it('should call onClosed callback when provided', () => {
const onClosed = vi.fn();
const modalApiWithHook = new ModalApi({ onClosed });
modalApiWithHook.onClosed();
expect(onClosed).toHaveBeenCalled();
});
it('should call onOpened callback when provided', () => {
const onOpened = vi.fn();
const modalApiWithHook = new ModalApi({ onOpened });
modalApiWithHook.open();
modalApiWithHook.onOpened();
expect(onOpened).toHaveBeenCalled();
});
});

View File

@@ -6,7 +6,12 @@ import { bindMethods, isFunction } from '@vben-core/shared/utils';
export class ModalApi {
private api: Pick<
ModalApiOptions,
'onBeforeClose' | 'onCancel' | 'onConfirm' | 'onOpenChange'
| 'onBeforeClose'
| 'onCancel'
| 'onClosed'
| 'onConfirm'
| 'onOpenChange'
| 'onOpened'
>;
// private prevState!: ModalState;
private state!: ModalState;
@@ -23,8 +28,10 @@ export class ModalApi {
connectedComponent: _,
onBeforeClose,
onCancel,
onClosed,
onConfirm,
onOpenChange,
onOpened,
...storeState
} = options;
@@ -77,8 +84,10 @@ export class ModalApi {
this.api = {
onBeforeClose,
onCancel,
onClosed,
onConfirm,
onOpenChange,
onOpened,
};
bindMethods(this);
}
@@ -115,6 +124,15 @@ export class ModalApi {
}
}
/**
* 弹窗关闭动画播放完毕后的回调
*/
onClosed() {
if (!this.state.isOpen) {
this.api.onClosed?.();
}
}
/**
* 确认操作
*/
@@ -122,6 +140,15 @@ export class ModalApi {
this.api.onConfirm?.();
}
/**
* 弹窗打开动画播放完毕后的回调
*/
onOpened() {
if (this.state.isOpen) {
this.api.onOpened?.();
}
}
open() {
this.store.setState((prev) => ({ ...prev, isOpen: true }));
}

View File

@@ -139,6 +139,11 @@ export interface ModalApiOptions extends ModalState {
* 点击取消按钮的回调
*/
onCancel?: () => void;
/**
* 弹窗关闭动画结束的回调
* @returns
*/
onClosed?: () => void;
/**
* 点击确定按钮的回调
*/
@@ -149,4 +154,9 @@ export interface ModalApiOptions extends ModalState {
* @returns
*/
onOpenChange?: (isOpen: boolean) => void;
/**
* 弹窗打开动画结束的回调
* @returns
*/
onOpened?: () => void;
}

View File

@@ -188,10 +188,12 @@ function handleFocusOutside(e: Event) {
:show-close="closable"
close-class="top-3"
@close-auto-focus="handleFocusOutside"
@closed="() => modalApi?.onClosed()"
@escape-key-down="escapeKeyDown"
@focus-outside="handleFocusOutside"
@interact-outside="interactOutside"
@open-auto-focus="handerOpenAutoFocus"
@opened="() => modalApi?.onOpened()"
@pointer-down-outside="pointerDownOutside"
>
<DialogHeader

View File

@@ -27,7 +27,9 @@ const props = withDefaults(
>(),
{ showClose: true },
);
const emits = defineEmits<{ close: [] } & DialogContentEmits>();
const emits = defineEmits<
{ close: []; closed: []; opened: [] } & DialogContentEmits
>();
const delegatedProps = computed(() => {
const {
@@ -44,7 +46,13 @@ const delegatedProps = computed(() => {
const forwarded = useForwardPropsEmits(delegatedProps, emits);
const contentRef = ref<InstanceType<typeof DialogContent> | null>(null);
function onAnimationEnd() {
if (props.open) {
emits('opened');
} else {
emits('closed');
}
}
defineExpose({
getContentRef: () => contentRef.value,
});
@@ -57,6 +65,7 @@ defineExpose({
</Transition>
<DialogContent
ref="contentRef"
@animationend="onAnimationEnd"
v-bind="forwarded"
:class="
cn(