Skip to content

feat: multiple actions support and api improvements #2

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 7 commits into from
May 30, 2024
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions components.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ export {}

declare module 'vue' {
export interface GlobalComponents {
'Carbon:cafe': typeof import('~icons/carbon/cafe')['default']
'Carbon:logoTwitter': typeof import('~icons/carbon/logo-twitter')['default']
CheckIcon: typeof import('./src/components/icons/CheckIcon.vue')['default']
CopyIcon: typeof import('./src/components/icons/CopyIcon.vue')['default']
Expand: typeof import('./src/components/Expand.vue')['default']
Expand All @@ -15,6 +17,8 @@ declare module 'vue' {
HeadlessToastWithProps: typeof import('./src/components/HeadlessToastWithProps.vue')['default']
Hero: typeof import('./src/components/Hero.vue')['default']
Installation: typeof import('./src/components/Installation.vue')['default']
'Mdi:heart': typeof import('~icons/mdi/heart')['default']
New: typeof import('./src/components/examples/New.vue')['default']
Others: typeof import('./src/components/Others.vue')['default']
Position: typeof import('./src/components/Position.vue')['default']
Styling: typeof import('./src/components/Styling.vue')['default']
Expand Down
98 changes: 56 additions & 42 deletions packages/Toast.vue
Original file line number Diff line number Diff line change
Expand Up @@ -109,38 +109,50 @@
</div>
</template>
</div>
<template v-if="toast.cancel">
<button
:class="cn(classes?.cancelButton, toast.classes?.cancelButton)"
data-button
data-cancel
@click="
() => {
deleteToast()
if (toast.cancel?.onClick) {
toast.cancel.onClick()

<div data-buttons="">
<template v-if="toast.cancel">
<button
:class="cn(classes?.cancelButton, toast.classes?.cancelButton)"
data-button
data-cancel
@click="
() => {
deleteToast()
if (toast.cancel?.onClick) {
toast.cancel.onClick()
}
}
}
"
>
{{ toast.cancel.label }}
</button>
</template>
<template v-if="toast.action">
<button
:class="cn(classes?.actionButton, toast.classes?.actionButton)"
data-button
@click="
(event) => {
toast.action?.onClick(event)
if (event.defaultPrevented) return
deleteToast()
}
"
>
{{ toast.action.label }}
</button>
</template>
"
>
{{ toast.cancel.label }}
</button>
</template>

<template v-if="toast.action">
<template
v-for="(action, index) in Array.isArray(toast.action)
? toast.action
: [toast.action]"
:key="index"
>
<button
:class="cn(classes?.actionButton, action?.classes)"
data-button
@click="
(event) => {
action.onClick(event, {
deleteToast
})
if (event.defaultPrevented) return
}
"
>
{{ action.label }}
</button>
</template>
</template>
</div>
</template>
</li>
</template>
Expand Down Expand Up @@ -265,18 +277,20 @@ onMounted(() => {
emit('update:heights', newHeightArr as HeightT[])
})

const deleteToast = () => {
// Save the offset for the exit swipe animation
removed.value = true
offsetBeforeRemove.value = offset.value
const newHeights = props.heights.filter(
(height) => height.toastId !== props.toast.id
)
emit('update:heights', newHeights)

const deleteToast = (delay = 0) => {
setTimeout(() => {
emit('removeToast', props.toast)
}, TIME_BEFORE_UNMOUNT)
// Save the offset for the exit swipe animation
removed.value = true
offsetBeforeRemove.value = offset.value
const newHeights = props.heights.filter(
(height) => height.toastId !== props.toast.id
)
emit('update:heights', newHeights)

setTimeout(() => {
emit('removeToast', props.toast)
}, TIME_BEFORE_UNMOUNT)
Comment on lines +294 to +296
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It'll be good to obtain a reference to the timeout ID returned by the inner setTimeout call and clear it during the unmount phase.

}, delay)
}

const handleCloseToast = () => {
Expand Down
7 changes: 7 additions & 0 deletions packages/styles.css
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,13 @@ html[dir='rtl'],
box-shadow: 0px 4px 12px rgba(0, 0, 0, 0.1), 0 0 0 2px rgba(0, 0, 0, 0.2);
}

[data-sonner-toast] [data-buttons] {
display: flex;
gap: 8px;
margin-left: var(--toast-button-margin-start);
margin-right: var(--toast-button-margin-end);
}

[data-sonner-toast][data-y-position='top'] {
top: 0;
--y: translateY(-100%);
Expand Down
16 changes: 12 additions & 4 deletions packages/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,17 @@ export interface ToastIcons {
loading?: Component
}

export type ToastAction = {
label: string | Component
onClick: (
event: MouseEvent,
toast: {
deleteToast: (delay?: number) => void
}
) => void
classes?: string
}

export type ToastT<T extends Component = Component> = {
id: number | string
title?: string | Component
Expand All @@ -62,10 +73,7 @@ export type ToastT<T extends Component = Component> = {
duration?: number
delete?: boolean
important?: boolean
action?: {
label: string | Component
onClick: (event: MouseEvent) => void
}
action?: ToastAction | ToastAction[]
cancel?: {
label: string | Component
onClick?: () => void
Expand Down
Loading