Skip to content

Commit db9221b

Browse files
Merge pull request xiaoluoboding#83 from sadeghbarati/updates
feat: `sonner` updates
2 parents 6dd1510 + b76df7e commit db9221b

File tree

11 files changed

+2397
-2209
lines changed

11 files changed

+2397
-2209
lines changed

components.d.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
/* eslint-disable */
2-
/* prettier-ignore */
32
// @ts-nocheck
43
// Generated by unplugin-vue-components
54
// Read more: https://github.com/vuejs/core/pull/3399
65
export {}
76

7+
/* prettier-ignore */
88
declare module 'vue' {
99
export interface GlobalComponents {
1010
CheckIcon: typeof import('./src/components/icons/CheckIcon.vue')['default']

package.json

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -36,21 +36,21 @@
3636
"license": "MIT",
3737
"devDependencies": {
3838
"@iconify/json": "^2.2.172",
39-
"@microsoft/api-extractor": "^7.42.1",
39+
"@microsoft/api-extractor": "^7.47.9",
4040
"@types/node": "^18.19.8",
41-
"@unocss/reset": "^0.58.5",
42-
"@vitejs/plugin-vue": "^5.0.4",
41+
"@unocss/reset": "^0.62.4",
42+
"@vitejs/plugin-vue": "^5.1.4",
4343
"@vue/tsconfig": "^0.5.1",
44-
"@vueuse/core": "^10.9.0",
44+
"@vueuse/core": "^11.1.0",
4545
"@vueuse/head": "^2.0.0",
4646
"clean-css": "^5.3.3",
47-
"highlight.js": "^11.9.0",
48-
"typescript": "^5.3.3",
49-
"unocss": "^0.58.5",
50-
"unplugin-icons": "^0.18.5",
51-
"unplugin-vue-components": "^0.26.0",
52-
"vite": "^5.1.4",
53-
"vue": "^3.4.21",
54-
"vue-tsc": "^2.0.1"
47+
"highlight.js": "^11.10.0",
48+
"typescript": "^5.6.2",
49+
"unocss": "^0.62.4",
50+
"unplugin-icons": "^0.19.3",
51+
"unplugin-vue-components": "^0.27.4",
52+
"vite": "^5.4.7",
53+
"vue": "^3.5.8",
54+
"vue-tsc": "^2.1.6"
5555
}
5656
}

packages/Toast.vue

Lines changed: 71 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
11
<template>
22
<li
3+
ref="toastRef"
34
:aria-live="toast.important ? 'assertive' : 'polite'"
45
aria-atomic="true"
56
role="status"
67
tabindex="0"
7-
ref="toastRef"
8-
data-sonner-toast=""
8+
data-sonner-toast="true"
99
:class="toastClass"
10+
:data-rich-colors="toast.richColors ?? defaultRichColors"
1011
:data-styled="!Boolean(toast.component || toast?.unstyled || unstyled)"
1112
:data-mounted="mounted"
1213
:data-promise="Boolean(toast.promise)"
@@ -39,11 +40,16 @@
3940
<button
4041
:aria-label="closeButtonAriaLabel || 'Close toast'"
4142
:data-disabled="disabled"
42-
data-close-button
43+
data-close-button="true"
4344
:class="cn(classes?.closeButton, toast?.classes?.closeButton)"
4445
@click="handleCloseToast"
4546
>
46-
<CloseIcon />
47+
<template v-if="icons?.close">
48+
<component :is="icons?.close" />
49+
</template>
50+
<template v-else>
51+
<slot name="close-icon" />
52+
</template>
4753
</button>
4854
</template>
4955

@@ -67,10 +73,10 @@
6773
<component :is="toast.icon" v-if="toast.icon" />
6874

6975
<template v-else>
70-
<slot name="success-icon" v-if="toastType === 'success'" />
71-
<slot name="error-icon" v-else-if="toastType === 'error'" />
72-
<slot name="warning-icon" v-else-if="toastType === 'warning'" />
73-
<slot name="info-icon" v-else-if="toastType === 'info'" />
76+
<slot v-if="toastType === 'success'" name="success-icon" />
77+
<slot v-else-if="toastType === 'error'" name="error-icon" />
78+
<slot v-else-if="toastType === 'warning'" name="warning-icon" />
79+
<slot v-else-if="toastType === 'info'" name="info-icon" />
7480
</template>
7581
</div>
7682
</template>
@@ -91,7 +97,7 @@
9197
:class="
9298
cn(
9399
descriptionClass,
94-
toast.descriptionClass,
100+
toastDescriptionClass,
95101
classes?.description,
96102
toast.classes?.description
97103
)
@@ -111,34 +117,38 @@
111117
</div>
112118
<template v-if="toast.cancel">
113119
<button
120+
:style="toast.cancelButtonStyle || cancelButtonStyle"
114121
:class="cn(classes?.cancelButton, toast.classes?.cancelButton)"
115122
data-button
116123
data-cancel
117124
@click="
118-
() => {
119-
deleteToast()
120-
if (toast.cancel?.onClick) {
121-
toast.cancel.onClick()
122-
}
125+
(event) => {
126+
if (!isAction(toast.cancel!)) return;
127+
if (!dismissible) return;
128+
toast.cancel.onClick?.(event);
129+
deleteToast();
123130
}
124131
"
125132
>
126-
{{ toast.cancel.label }}
133+
{{ isAction(toast.cancel) ? toast.cancel?.label : toast.cancel }}
127134
</button>
128135
</template>
129136
<template v-if="toast.action">
130137
<button
138+
:style="toast.actionButtonStyle || actionButtonStyle"
131139
:class="cn(classes?.actionButton, toast.classes?.actionButton)"
132140
data-button
141+
data-action
133142
@click="
134143
(event) => {
135-
toast.action?.onClick(event)
136-
if (event.defaultPrevented) return
137-
deleteToast()
144+
if (!isAction(toast.action!)) return;
145+
if (event.defaultPrevented) return;
146+
toast.action.onClick?.(event);
147+
deleteToast();
138148
}
139149
"
140150
>
141-
{{ toast.action.label }}
151+
{{ isAction(toast.action) ? toast.action?.label : toast.action }}
142152
</button>
143153
</template>
144154
</template>
@@ -149,48 +159,37 @@
149159
import './styles.css'
150160
151161
import { computed, onMounted, onUnmounted, ref, watchEffect } from 'vue'
152-
import type { ToastProps, HeightT, ToastT } from './types'
153-
import CloseIcon from './assets/CloseIcon.vue'
162+
import { type HeightT, type ToastProps, type ToastT, isAction } from './types'
154163
import { useIsDocumentHidden } from './hooks'
155164
156-
// Default lifetime of a toasts (in ms)
157-
const TOAST_LIFETIME = 4000
158-
159-
// Default gap between toasts
160-
const GAP = 14
161-
162-
const SWIPE_THRESHOLD = 20
163-
164-
const TIME_BEFORE_UNMOUNT = 200
165+
const props = defineProps<ToastProps>()
165166
166167
const emit = defineEmits<{
167168
(e: 'update:heights', heights: HeightT[]): void
168169
(e: 'removeToast', toast: ToastT): void
169170
}>()
170171
171-
const props = defineProps<ToastProps>()
172+
// Default lifetime of a toasts (in ms)
173+
const TOAST_LIFETIME = 4000
174+
175+
const SWIPE_THRESHOLD = 20
176+
177+
const TIME_BEFORE_UNMOUNT = 200
172178
173179
const mounted = ref(false)
174180
const removed = ref(false)
175181
const swiping = ref(false)
176182
const swipeOut = ref(false)
177183
const offsetBeforeRemove = ref(0)
178184
const initialHeight = ref(0)
179-
let dragStartTime: number = 0
185+
const dragStartTime = ref<Date | null>(null)
180186
const toastRef = ref<HTMLLIElement | null>(null)
181187
const isFront = computed(() => props.index === 0)
182188
const isVisible = computed(() => props.index + 1 <= props.visibleToasts)
183189
const toastType = computed(() => props.toast.type)
184190
const dismissible = computed(() => props.toast.dismissible !== false)
185-
const toastClass = computed(() => {
186-
return props.cn(
187-
props.classes?.toast,
188-
props.toast?.classes?.toast,
189-
props.classes?.default,
190-
props.classes?.[props.toast.type || 'default'],
191-
props.toast?.classes?.[props.toast.type || 'default']
192-
)
193-
})
191+
const toastClass = computed(() => props.toast.class || '')
192+
const toastDescriptionClass = computed(() => props.descriptionClass || '')
194193
195194
const toastStyle = props.toast.style || {}
196195
@@ -206,14 +205,15 @@ const duration = computed(
206205
207206
const closeTimerStartTimeRef = ref(0)
208207
const offset = ref(0)
209-
const remainingTime = ref(duration.value)
210208
const lastCloseTimerStartTimeRef = ref(0)
211209
const pointerStartRef = ref<{ x: number; y: number } | null>(null)
212210
const coords = computed(() => props.position.split('-'))
213211
const y = computed(() => coords.value[0])
214212
const x = computed(() => coords.value[1])
215213
const isStringOfTitle = computed(() => typeof props.toast.title !== 'string')
216-
const isStringOfDescription = computed(() => typeof props.toast.description !== 'string')
214+
const isStringOfDescription = computed(
215+
() => typeof props.toast.description !== 'string'
216+
)
217217
218218
const toastsHeightBefore = computed(() => {
219219
return props.heights.reduce((prev, curr, reducerIndex) => {
@@ -265,17 +265,21 @@ onMounted(() => {
265265
emit('update:heights', newHeightArr as HeightT[])
266266
})
267267
268-
const deleteToast = () => {
268+
function deleteToast() {
269269
// Save the offset for the exit swipe animation
270270
removed.value = true
271271
offsetBeforeRemove.value = offset.value
272+
const height = props.heights.filter(
273+
(height) => height.toastId !== props.toast.id
274+
)
275+
emit('update:heights', height)
272276
273277
setTimeout(() => {
274278
emit('removeToast', props.toast)
275279
}, TIME_BEFORE_UNMOUNT)
276280
}
277281
278-
const handleCloseToast = () => {
282+
function handleCloseToast() {
279283
if (disabled.value || !dismissible.value) {
280284
return
281285
}
@@ -284,9 +288,9 @@ const handleCloseToast = () => {
284288
props.toast.onDismiss?.(props.toast)
285289
}
286290
287-
const onPointerDown = (event: PointerEvent) => {
291+
function onPointerDown(event: PointerEvent) {
288292
if (disabled.value || !dismissible.value) return
289-
dragStartTime = Date.now()
293+
dragStartTime.value = new Date()
290294
offsetBeforeRemove.value = offset.value
291295
// Ensure we maintain correct pointer capture even when going outside of the toast (e.g. when swiping)
292296
;(event.target as HTMLElement).setPointerCapture(event.pointerId)
@@ -295,7 +299,7 @@ const onPointerDown = (event: PointerEvent) => {
295299
pointerStartRef.value = { x: event.clientX, y: event.clientY }
296300
}
297301
298-
const onPointerUp = (event: PointerEvent) => {
302+
function onPointerUp() {
299303
if (swipeOut.value) return
300304
pointerStartRef.value = null
301305
@@ -305,7 +309,7 @@ const onPointerUp = (event: PointerEvent) => {
305309
.replace('px', '') || 0
306310
)
307311
308-
const timeTaken = (Date.now() - dragStartTime) || 50
312+
const timeTaken = new Date().getTime() - dragStartTime.value?.getTime()!
309313
const velocity = Math.abs(swipeAmount) / timeTaken
310314
311315
// Remove only if treshold is met
@@ -321,8 +325,8 @@ const onPointerUp = (event: PointerEvent) => {
321325
swiping.value = false
322326
}
323327
324-
const onPointerMove = (event: PointerEvent) => {
325-
if (!pointerStartRef.value) return
328+
function onPointerMove(event: PointerEvent) {
329+
if (!pointerStartRef.value || !dismissible.value) return
326330
327331
const yPosition = event.clientY - pointerStartRef.value.y
328332
const xPosition = event.clientX - pointerStartRef.value.x
@@ -342,37 +346,41 @@ const onPointerMove = (event: PointerEvent) => {
342346
}
343347
344348
watchEffect(() => {
345-
offset.value = heightIndex.value * GAP + toastsHeightBefore.value
349+
offset.value = heightIndex.value * props?.gap! + toastsHeightBefore.value
346350
})
347351
348352
watchEffect((onInvalidate) => {
349353
if (
350354
(props.toast.promise && toastType.value === 'loading') ||
351355
props.toast.duration === Infinity ||
352356
props.toast.type === 'loading'
353-
)
357+
) {
354358
return
359+
}
355360
let timeoutId: ReturnType<typeof setTimeout>
361+
let remainingTime = duration.value
356362
357363
// Pause the timer on each hover
358364
const pauseTimer = () => {
359365
if (lastCloseTimerStartTimeRef.value < closeTimerStartTimeRef.value) {
360366
// Get the elapsed time since the timer started
361-
const elapsedTime = Date.now() - closeTimerStartTimeRef.value
367+
const elapsedTime = new Date().getTime() - closeTimerStartTimeRef.value
362368
363-
remainingTime.value = remainingTime.value - elapsedTime
369+
remainingTime = remainingTime - elapsedTime
364370
}
365371
366-
lastCloseTimerStartTimeRef.value = Date.now()
372+
lastCloseTimerStartTimeRef.value = new Date().getTime()
367373
}
368374
369375
const startTimer = () => {
370-
closeTimerStartTimeRef.value = Date.now()
376+
if (remainingTime === Infinity) return
377+
closeTimerStartTimeRef.value = new Date().getTime()
378+
371379
// Let the toast know it has started
372380
timeoutId = setTimeout(() => {
373381
props.toast.onAutoClose?.(props.toast)
374382
deleteToast()
375-
}, remainingTime.value)
383+
}, remainingTime)
376384
}
377385
378386
if (
@@ -390,11 +398,11 @@ watchEffect((onInvalidate) => {
390398
})
391399
})
392400
393-
watchEffect(() => {
394-
if (props.toast.delete) {
395-
deleteToast()
396-
}
397-
})
401+
// watchEffect(() => {
402+
// if (props.toast.delete) {
403+
// deleteToast()
404+
// }
405+
// })
398406
399407
onMounted(() => {
400408
if (toastRef.value) {

0 commit comments

Comments
 (0)