fix: add missing emits event

This commit is contained in:
zernonia 2023-08-23 18:43:51 +08:00
parent 81197d1e02
commit fd0eb2f5e8
4 changed files with 42 additions and 11 deletions

View File

@ -20,7 +20,7 @@ import { Label } from '@/registry/default/ui/label'
Edit Profile Edit Profile
</Button> </Button>
</DialogTrigger> </DialogTrigger>
<DialogContent class="sm:max-w-[425px]"> <DialogContent class="sm:max-w-[425px]" @escape-key-down.prevent>
<DialogHeader> <DialogHeader>
<DialogTitle>Edit profile</DialogTitle> <DialogTitle>Edit profile</DialogTitle>
<DialogDescription> <DialogDescription>

View File

@ -2,14 +2,16 @@ import { defineComponent, h } from 'vue'
import { import {
AlertDialogAction as AlertDialogActionPrimitive, type AlertDialogActionProps, AlertDialogAction as AlertDialogActionPrimitive, type AlertDialogActionProps,
AlertDialogCancel as AlertDialogCancelPrimitive, type AlertDialogCancelProps, AlertDialogCancel as AlertDialogCancelPrimitive, type AlertDialogCancelProps,
AlertDialogContent as AlertDialogContentPrimitive, type AlertDialogContentProps, type AlertDialogContentEmits, AlertDialogContent as AlertDialogContentPrimitive, type AlertDialogContentProps,
AlertDialogDescription as AlertDialogDescriptionPrimitive, type AlertDialogDescriptionProps, AlertDialogDescription as AlertDialogDescriptionPrimitive, type AlertDialogDescriptionProps,
AlertDialogOverlay as AlertDialogOverlayPrimitive, type AlertDialogOverlayProps, AlertDialogOverlay as AlertDialogOverlayPrimitive, type AlertDialogOverlayProps,
AlertDialogPortal as AlertDialogPortalPrimitive, AlertDialogPortal as AlertDialogPortalPrimitive,
AlertDialogRoot, AlertDialogTitle as AlertDialogTitlePrimitive, AlertDialogRoot, AlertDialogTitle as AlertDialogTitlePrimitive,
type AlertDialogTitleProps, AlertDialogTrigger as AlertDialogTriggerPrimitive, type AlertDialogTitleProps, AlertDialogTrigger as AlertDialogTriggerPrimitive,
} from 'radix-vue' } from 'radix-vue'
import { cn } from '@/utils' import type { ParseEmits } from '@/utils'
import { cn, useEmitAsProps } from '@/utils'
import { buttonVariants } from '@/registry/default/ui/button' import { buttonVariants } from '@/registry/default/ui/button'
export const AlertDialog = AlertDialogRoot export const AlertDialog = AlertDialogRoot
@ -25,16 +27,19 @@ export const AlertDialogOverlay = defineComponent<AlertDialogOverlayProps>(
}, { name: 'AlertDialogOverlay' }, }, { name: 'AlertDialogOverlay' },
) )
export const AlertDialogContent = defineComponent<AlertDialogContentProps>( export const AlertDialogContent = defineComponent<AlertDialogContentProps, ParseEmits<AlertDialogContentEmits>>(
(props, { attrs, slots }) => { (props, { emit, attrs, slots }) => {
const emitsAsProps = useEmitAsProps(emit)
return () => h(AlertDialogPortal, () => [ return () => h(AlertDialogPortal, () => [
h(AlertDialogOverlay), h(AlertDialogOverlay),
h(AlertDialogContentPrimitive, { h(AlertDialogContentPrimitive, {
class: cn('fixed left-[50%] top-[50%] z-50 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 border bg-background p-6 shadow-lg duration-200 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%] sm:rounded-lg md:w-full', attrs.class ?? ''), class: cn('fixed left-[50%] top-[50%] z-50 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 border bg-background p-6 shadow-lg duration-200 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%] sm:rounded-lg md:w-full', attrs.class ?? ''),
...props, ...props,
...emitsAsProps,
}, slots), }, slots),
]) ])
}, { name: 'AlertDialogContent' }, }, { name: 'AlertDialogContent', emits: AlertDialogContentPrimitive.emits },
) )
export const AlertDialogHeader = defineComponent( export const AlertDialogHeader = defineComponent(

View File

@ -1,6 +1,6 @@
import { defineComponent, h } from 'vue' import { defineComponent, h } from 'vue'
import { import {
DialogClose, DialogContent as DialogContentPrimitive, type DialogContentProps, DialogClose, type DialogContentEmits, DialogContent as DialogContentPrimitive, type DialogContentProps,
DialogDescription as DialogDescriptionPrimitive, type DialogDescriptionProps, DialogDescription as DialogDescriptionPrimitive, type DialogDescriptionProps,
DialogOverlay as DialogOverlayPrimitive, type DialogOverlayProps, DialogOverlay as DialogOverlayPrimitive, type DialogOverlayProps,
DialogPortal as DialogPortalPrimitive, DialogRoot, DialogPortal as DialogPortalPrimitive, DialogRoot,
@ -8,7 +8,8 @@ import {
DialogTrigger as DialogTriggerPrimitive, DialogTrigger as DialogTriggerPrimitive,
} from 'radix-vue' } from 'radix-vue'
import { X } from 'lucide-vue-next' import { X } from 'lucide-vue-next'
import { cn } from '@/utils' import type { ParseEmits } from '@/utils'
import { cn, useEmitAsProps } from '@/utils'
export const Dialog = DialogRoot export const Dialog = DialogRoot
export const DialogTrigger = DialogTriggerPrimitive export const DialogTrigger = DialogTriggerPrimitive
@ -23,13 +24,16 @@ export const DialogOverlay = defineComponent<DialogOverlayProps>(
}, { name: 'DialogOverlay' }, }, { name: 'DialogOverlay' },
) )
export const DialogContent = defineComponent<DialogContentProps>( export const DialogContent = defineComponent<DialogContentProps, ParseEmits<DialogContentEmits>>(
(props, { attrs, slots }) => { (props, { emit, attrs, slots }) => {
const emitsAsProps = useEmitAsProps(emit)
return () => h(DialogPortal, () => [ return () => h(DialogPortal, () => [
h(DialogOverlay), h(DialogOverlay),
h(DialogContentPrimitive, { h(DialogContentPrimitive, {
class: cn('fixed left-[50%] top-[50%] z-50 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 border bg-background p-6 shadow-lg duration-200 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%] sm:rounded-lg md:w-full', attrs.class ?? ''), class: cn('fixed left-[50%] top-[50%] z-50 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 border bg-background p-6 shadow-lg duration-200 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%] sm:rounded-lg md:w-full', attrs.class ?? ''),
...props, ...props,
...emitsAsProps,
}, () => [ }, () => [
slots.default(), slots.default(),
h(DialogClose, h(DialogClose,
@ -38,7 +42,7 @@ export const DialogContent = defineComponent<DialogContentProps>(
), ),
]), ]),
]) ])
}, { name: 'DialogContent' }, }, { name: 'DialogContent', emits: DialogContentPrimitive.emits },
) )
export const DialogHeader = defineComponent( export const DialogHeader = defineComponent(

View File

@ -1,6 +1,7 @@
import type { ClassValue } from 'clsx' import type { ClassValue } from 'clsx'
import { clsx } from 'clsx' import { clsx } from 'clsx'
import { twMerge } from 'tailwind-merge' import { twMerge } from 'tailwind-merge'
import { camelize, getCurrentInstance, toHandlerKey } from 'vue'
export type ParseEmits<T extends Record<string, any>> = { export type ParseEmits<T extends Record<string, any>> = {
[K in keyof T]: (...args: T[K]) => void; [K in keyof T]: (...args: T[K]) => void;
@ -9,3 +10,24 @@ export type ParseEmits<T extends Record<string, any>> = {
export function cn(...inputs: ClassValue[]) { export function cn(...inputs: ClassValue[]) {
return twMerge(clsx(inputs)) return twMerge(clsx(inputs))
} }
// Vue doesn't have emits forwarding, in order to bind the emits we have to convert events into `onXXX` handlers
// issue: https://github.com/vuejs/core/issues/5917
export function useEmitAsProps<Name extends string>(
emit: (name: Name, ...args: any[]) => void,
) {
const vm = getCurrentInstance()
const events = vm?.type.emits as Name[]
const result: Record<string, any> = {}
if (!events?.length) {
console.warn(
`No emitted event found. Please check component: ${vm?.type.__name}`,
)
}
events?.forEach((ev) => {
result[toHandlerKey(camelize(ev))] = (...arg: any) => emit(ev, ...arg)
})
return result
}