feat: add VNode type to toast description

This commit is contained in:
Sadegh Barati 2023-10-30 22:36:00 +03:30
parent 247a57c9d7
commit 849596e870
12 changed files with 72 additions and 26 deletions

View File

@ -3,6 +3,7 @@ import { useForm } from 'vee-validate'
import { toTypedSchema } from '@vee-validate/zod' import { toTypedSchema } from '@vee-validate/zod'
import * as z from 'zod' import * as z from 'zod'
import { h } from 'vue'
import { Button } from '@/lib/registry/default/ui/button' import { Button } from '@/lib/registry/default/ui/button'
import { import {
FormControl, FormControl,
@ -13,6 +14,7 @@ import {
FormMessage, FormMessage,
} from '@/lib/registry/default/ui/form' } from '@/lib/registry/default/ui/form'
import { Input } from '@/lib/registry/default/ui/input' import { Input } from '@/lib/registry/default/ui/input'
import { toast } from '@/lib/registry/default/ui/toast/use-toast'
const formSchema = toTypedSchema(z.object({ const formSchema = toTypedSchema(z.object({
username: z.string().min(2).max(50), username: z.string().min(2).max(50),
@ -23,7 +25,10 @@ const { handleSubmit } = useForm({
}) })
const onSubmit = handleSubmit((values) => { const onSubmit = handleSubmit((values) => {
console.log('Form submitted!', values) toast({
title: 'You submitted the following values:',
description: h('pre', { class: 'mt-2 w-[340px] rounded-md bg-slate-950 p-4' }, h('code', { class: 'text-white' }, JSON.stringify(values, null, 2))),
})
}) })
</script> </script>

View File

@ -1,18 +1,24 @@
<script setup lang="ts"> <script lang="ts">
import { ToastRoot, type ToastRootEmits, type ToastRootProps, useEmitAsProps } from 'radix-vue' import type { ToastRootEmits, ToastRootProps } from 'radix-vue'
import type { VariantProps } from 'class-variance-authority'
import { toastVariants } from '.'
import { cn } from '@/lib/utils'
interface ToastVariantProps extends VariantProps<typeof toastVariants> {} interface ToastVariantProps extends VariantProps<typeof toastVariants> {}
export interface ToastProps extends ToastRootProps { export interface ToastProps extends ToastRootProps {
class?: string class?: string
variant?: ToastVariantProps['variant'] variant?: ToastVariantProps['variant']
'onUpdate:open'?: ((value: boolean) => void) | undefined
}; };
</script>
<script setup lang="ts">
import { ToastRoot, useEmitAsProps } from 'radix-vue'
import { toastVariants } from '.'
import { cn } from '@/lib/utils'
const props = defineProps<ToastProps>() const props = defineProps<ToastProps>()
const emits = defineEmits<ToastRootEmits>() const emits = defineEmits<Omit<ToastRootEmits, 'update:open'>>()
</script> </script>
<template> <template>

View File

@ -1,6 +1,6 @@
<script setup lang="ts"> <script setup lang="ts">
import { ToastDescription, type ToastDescriptionProps } from 'radix-vue' import { ToastDescription, type ToastDescriptionProps } from 'radix-vue'
import { cn } from '@/lib/utils.ts' import { cn } from '@/lib/utils'
const props = defineProps<ToastDescriptionProps & { class?: string }>() const props = defineProps<ToastDescriptionProps & { class?: string }>()
</script> </script>

View File

@ -1,4 +1,5 @@
<script setup lang="ts"> <script setup lang="ts">
import { isVNode } from 'vue'
import { useToast } from './use-toast' import { useToast } from './use-toast'
import { Toast, ToastClose, ToastDescription, ToastProvider, ToastTitle, ToastViewport } from '.' import { Toast, ToastClose, ToastDescription, ToastProvider, ToastTitle, ToastViewport } from '.'
@ -12,9 +13,14 @@ const { toasts } = useToast()
<ToastTitle v-if="toast.title"> <ToastTitle v-if="toast.title">
{{ toast.title }} {{ toast.title }}
</ToastTitle> </ToastTitle>
<ToastDescription v-if="toast.description"> <template v-if="toast.description">
{{ toast.description }} <ToastDescription v-if="isVNode(toast.description)">
</ToastDescription> <component :is="toast.description" />
</ToastDescription>
<ToastDescription v-else>
{{ toast.description }}
</ToastDescription>
</template>
<ToastClose /> <ToastClose />
</div> </div>
<component :is="toast.action" /> <component :is="toast.action" />

View File

@ -6,6 +6,7 @@ export { default as ToastClose } from './ToastClose.vue'
export { default as ToastTitle } from './ToastTitle.vue' export { default as ToastTitle } from './ToastTitle.vue'
export { default as ToastDescription } from './ToastDescription.vue' export { default as ToastDescription } from './ToastDescription.vue'
export { default as ToastProvider } from './ToastProvider.vue' export { default as ToastProvider } from './ToastProvider.vue'
export { useToast } from './use-toast'
import { cva } from 'class-variance-authority' import { cva } from 'class-variance-authority'

View File

@ -1,14 +1,19 @@
import { computed, ref } from 'vue' import { computed, ref } from 'vue'
import type { Component } from 'vue' import type { Component, VNode } from 'vue'
import type { ToastProps } from './Toast.vue' import type { ToastProps } from './Toast.vue'
const TOAST_LIMIT = 1 const TOAST_LIMIT = 1
const TOAST_REMOVE_DELAY = 1000000 const TOAST_REMOVE_DELAY = 1000000
export type StringOrVNode =
| string
| VNode
| (() => VNode)
type ToasterToast = ToastProps & { type ToasterToast = ToastProps & {
id: string id: string
title?: string title?: string
description?: string description?: StringOrVNode
action?: Component action?: Component
} }

View File

@ -1,4 +1,5 @@
<script setup lang="ts"> <script setup lang="ts">
import { h } from 'vue'
import { useForm } from 'vee-validate' import { useForm } from 'vee-validate'
import { toTypedSchema } from '@vee-validate/zod' import { toTypedSchema } from '@vee-validate/zod'
import * as z from 'zod' import * as z from 'zod'
@ -13,6 +14,7 @@ import {
FormMessage, FormMessage,
} from '@/lib/registry/new-york/ui/form' } from '@/lib/registry/new-york/ui/form'
import { Input } from '@/lib/registry/new-york/ui/input' import { Input } from '@/lib/registry/new-york/ui/input'
import { toast } from '@/lib/registry/new-york/ui/toast/use-toast'
const formSchema = toTypedSchema(z.object({ const formSchema = toTypedSchema(z.object({
username: z.string().min(2).max(50), username: z.string().min(2).max(50),
@ -23,7 +25,10 @@ const { isFieldDirty, handleSubmit } = useForm({
}) })
const onSubmit = handleSubmit((values) => { const onSubmit = handleSubmit((values) => {
console.log('Form submitted!', values) toast({
title: 'You submitted the following values:',
description: h('pre', { class: 'mt-2 w-[340px] rounded-md bg-slate-950 p-4' }, h('code', { class: 'text-white' }, JSON.stringify(values, null, 2))),
})
}) })
</script> </script>

View File

@ -1,18 +1,24 @@
<script setup lang="ts"> <script lang="ts">
import { ToastRoot, type ToastRootEmits, type ToastRootProps, useEmitAsProps } from 'radix-vue' import type { ToastRootEmits, ToastRootProps } from 'radix-vue'
import type { VariantProps } from 'class-variance-authority'
import { toastVariants } from '.'
import { cn } from '@/lib/utils'
interface ToastVariantProps extends VariantProps<typeof toastVariants> {} interface ToastVariantProps extends VariantProps<typeof toastVariants> {}
export interface ToastProps extends ToastRootProps { export interface ToastProps extends ToastRootProps {
class?: string class?: string
variant?: ToastVariantProps['variant'] variant?: ToastVariantProps['variant']
'onUpdate:open'?: ((value: boolean) => void) | undefined
}; };
</script>
<script setup lang="ts">
import { ToastRoot, useEmitAsProps } from 'radix-vue'
import { toastVariants } from '.'
import { cn } from '@/lib/utils'
const props = defineProps<ToastProps>() const props = defineProps<ToastProps>()
const emits = defineEmits<ToastRootEmits>() const emits = defineEmits<Omit<ToastRootEmits, 'update:open'>>()
</script> </script>
<template> <template>

View File

@ -1,6 +1,6 @@
<script setup lang="ts"> <script setup lang="ts">
import { ToastDescription, type ToastDescriptionProps } from 'radix-vue' import { ToastDescription, type ToastDescriptionProps } from 'radix-vue'
import { cn } from '@/lib/utils.ts' import { cn } from '@/lib/utils'
const props = defineProps<ToastDescriptionProps & { class?: string }>() const props = defineProps<ToastDescriptionProps & { class?: string }>()
</script> </script>

View File

@ -1,4 +1,5 @@
<script setup lang="ts"> <script setup lang="ts">
import { isVNode } from 'vue'
import { useToast } from './use-toast' import { useToast } from './use-toast'
import { Toast, ToastClose, ToastDescription, ToastProvider, ToastTitle, ToastViewport } from '.' import { Toast, ToastClose, ToastDescription, ToastProvider, ToastTitle, ToastViewport } from '.'
@ -12,9 +13,14 @@ const { toasts } = useToast()
<ToastTitle v-if="toast.title"> <ToastTitle v-if="toast.title">
{{ toast.title }} {{ toast.title }}
</ToastTitle> </ToastTitle>
<ToastDescription v-if="toast.description"> <template v-if="toast.description">
{{ toast.description }} <ToastDescription v-if="isVNode(toast.description)">
</ToastDescription> <component :is="toast.description" />
</ToastDescription>
<ToastDescription v-else>
{{ toast.description }}
</ToastDescription>
</template>
<ToastClose /> <ToastClose />
</div> </div>
<component :is="toast.action" /> <component :is="toast.action" />

View File

@ -6,6 +6,7 @@ export { default as ToastClose } from './ToastClose.vue'
export { default as ToastTitle } from './ToastTitle.vue' export { default as ToastTitle } from './ToastTitle.vue'
export { default as ToastDescription } from './ToastDescription.vue' export { default as ToastDescription } from './ToastDescription.vue'
export { default as ToastProvider } from './ToastProvider.vue' export { default as ToastProvider } from './ToastProvider.vue'
export { useToast } from './use-toast'
import { cva } from 'class-variance-authority' import { cva } from 'class-variance-authority'

View File

@ -1,14 +1,19 @@
import { computed, ref } from 'vue' import { computed, ref } from 'vue'
import type { Component } from 'vue' import type { Component, VNode } from 'vue'
import type { ToastProps } from './Toast.vue' import type { ToastProps } from './Toast.vue'
const TOAST_LIMIT = 1 const TOAST_LIMIT = 1
const TOAST_REMOVE_DELAY = 1000000 const TOAST_REMOVE_DELAY = 1000000
export type StringOrVNode =
| string
| VNode
| (() => VNode)
type ToasterToast = ToastProps & { type ToasterToast = ToastProps & {
id: string id: string
title?: string title?: string
description?: string description?: StringOrVNode
action?: Component action?: Component
} }