Skip to content

Commit 2a54869

Browse files
committedNov 13, 2024·
feat: add sonner 1.7.0 features
1 parent 01435c8 commit 2a54869

File tree

5 files changed

+105
-100
lines changed

5 files changed

+105
-100
lines changed
 

‎src/packages/Toast.vue

+31-28
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@
7272

7373
<template v-else>
7474
<template v-if="toastType !== 'default' || toast.icon || toast.promise">
75-
<div data-icon="">
75+
<div data-icon="" :class="cn(classes?.icon, toast?.classes?.icon)">
7676
<template
7777
v-if="(toast.promise || toastType === 'loading') && !toast.icon"
7878
>
@@ -153,6 +153,7 @@
153153
if (!isAction(toast.action!)) return;
154154
if (event.defaultPrevented) return;
155155
toast.action.onClick?.(event);
156+
if (event.defaultPrevented) return;
156157
deleteToast();
157158
}
158159
"
@@ -167,7 +168,7 @@
167168
<script lang="ts" setup>
168169
import './styles.css'
169170
170-
import { computed, onMounted, onUnmounted, ref, watch, watchEffect } from 'vue'
171+
import { computed, onBeforeUnmount, onMounted, onUnmounted, ref, watch, watchEffect } from 'vue'
171172
import { type HeightT, type ToastProps, type ToastT, isAction } from './types'
172173
import { useIsDocumentHidden } from './hooks'
173174
@@ -189,8 +190,10 @@ const mounted = ref(false)
189190
const removed = ref(false)
190191
const swiping = ref(false)
191192
const swipeOut = ref(false)
193+
const swiped = ref(false)
192194
const offsetBeforeRemove = ref(0)
193195
const initialHeight = ref(0)
196+
const remainingTime = ref(props.toast.duration || props.duration || TOAST_LIFETIME)
194197
const dragStartTime = ref<Date | null>(null)
195198
const toastRef = ref<HTMLLIElement | null>(null)
196199
const isFront = computed(() => props.index === 0)
@@ -213,7 +216,6 @@ const duration = computed(
213216
)
214217
215218
const closeTimerStartTimeRef = ref(0)
216-
const offset = ref(0)
217219
const lastCloseTimerStartTimeRef = ref(0)
218220
const pointerStartRef = ref<{ x: number; y: number } | null>(null)
219221
const coords = computed(() => props.position.split('-'))
@@ -238,6 +240,10 @@ const isDocumentHidden = useIsDocumentHidden()
238240
const invert = computed(() => props.toast.invert || props.invert)
239241
const disabled = computed(() => toastType.value === 'loading')
240242
243+
const offset = computed(() => {
244+
return heightIndex.value * props.gap! + toastsHeightBefore.value || 0
245+
})
246+
241247
onMounted(() => {
242248
if (!mounted.value) return
243249
@@ -250,6 +256,7 @@ onMounted(() => {
250256
initialHeight.value = newHeight
251257
252258
let newHeightArr
259+
253260
const alreadyExists = props.heights.find(
254261
(height) => height.toastId === props.toast.id
255262
)
@@ -290,7 +297,7 @@ function deleteToast() {
290297
291298
function handleCloseToast() {
292299
if (disabled.value || !dismissible.value) {
293-
return
300+
return {}
294301
}
295302
296303
deleteToast()
@@ -309,7 +316,7 @@ function onPointerDown(event: PointerEvent) {
309316
}
310317
311318
function onPointerUp() {
312-
if (swipeOut.value) return
319+
if (swipeOut.value || !dismissible) return;
313320
pointerStartRef.value = null
314321
315322
const swipeAmount = Number(
@@ -327,6 +334,7 @@ function onPointerUp() {
327334
props.toast.onDismiss?.(props.toast)
328335
deleteToast()
329336
swipeOut.value = true
337+
swiped.value = false
330338
return
331339
}
332340
@@ -338,25 +346,20 @@ function onPointerMove(event: PointerEvent) {
338346
if (!pointerStartRef.value || !dismissible.value) return
339347
340348
const yPosition = event.clientY - pointerStartRef.value.y
341-
const xPosition = event.clientX - pointerStartRef.value.x
342-
343-
const clamp = coords.value[0] === 'top' ? Math.min : Math.max
344-
const clampedY = clamp(0, yPosition)
345-
const swipeStartThreshold = event.pointerType === 'touch' ? 10 : 2
346-
const isAllowedToSwipe = Math.abs(clampedY) > swipeStartThreshold
347-
348-
if (isAllowedToSwipe) {
349-
toastRef.value?.style.setProperty('--swipe-amount', `${yPosition}px`)
350-
} else if (Math.abs(xPosition) > swipeStartThreshold) {
351-
// User is swiping in wrong direction so we disable swipe gesture
352-
// for the current pointer down interaction
353-
pointerStartRef.value = null
349+
350+
// @ts-expect-error
351+
const isHighlighted = window.getSelection()?.toString().length > 0;
352+
353+
const swipeAmount = y.value === 'top' ? Math.min(0, yPosition) : Math.max(0, yPosition);
354+
355+
if (Math.abs(swipeAmount) > 0) {
356+
swiped.value = true;
354357
}
355-
}
356358
357-
watchEffect(() => {
358-
offset.value = heightIndex.value * props?.gap! + toastsHeightBefore.value
359-
})
359+
if (isHighlighted) return;
360+
361+
toastRef.value?.style.setProperty('--swipe-amount', `${swipeAmount}px`);
362+
}
360363
361364
watchEffect((onInvalidate) => {
362365
if (
@@ -367,29 +370,28 @@ watchEffect((onInvalidate) => {
367370
return
368371
}
369372
let timeoutId: ReturnType<typeof setTimeout>
370-
let remainingTime = duration.value
371373
372374
// Pause the timer on each hover
373375
const pauseTimer = () => {
374376
if (lastCloseTimerStartTimeRef.value < closeTimerStartTimeRef.value) {
375377
// Get the elapsed time since the timer started
376378
const elapsedTime = new Date().getTime() - closeTimerStartTimeRef.value
377379
378-
remainingTime = remainingTime - elapsedTime
380+
remainingTime.value = remainingTime.value - elapsedTime
379381
}
380382
381383
lastCloseTimerStartTimeRef.value = new Date().getTime()
382384
}
383385
384386
const startTimer = () => {
385-
if (remainingTime === Infinity) return
387+
if (remainingTime.value === Infinity) return
386388
closeTimerStartTimeRef.value = new Date().getTime()
387389
388390
// Let the toast know it has started
389391
timeoutId = setTimeout(() => {
390392
props.toast.onAutoClose?.(props.toast)
391393
deleteToast()
392-
}, remainingTime)
394+
}, remainingTime.value)
393395
}
394396
395397
if (
@@ -417,6 +419,8 @@ watch(
417419
)
418420
419421
onMounted(() => {
422+
mounted.value = true
423+
420424
if (toastRef.value) {
421425
const height = toastRef.value.getBoundingClientRect().height
422426
// Add toast height tot heights array after the toast is mounted
@@ -428,10 +432,9 @@ onMounted(() => {
428432
]
429433
emit('update:heights', newHeights)
430434
}
431-
mounted.value = true
432435
})
433436
434-
onUnmounted(() => {
437+
onBeforeUnmount(() => {
435438
if (toastRef.value) {
436439
const newHeights = props.heights.filter(
437440
(height) => height.toastId !== props.toast.id

‎src/packages/Toaster.vue

+21-5
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
<template>
22
<!-- Remove item from normal navigation flow, only available via hotkey -->
3-
<section :aria-label="`${containerAriaLabel} ${hotkeyLabel}`" :tabIndex="-1">
3+
<section :aria-label="`${containerAriaLabel} ${hotkeyLabel}`" :tabIndex="-1" aria-live="polite" aria-relevant="additions text" aria-atomic="false">
44
<template v-for="(pos, index) in possiblePositions" :key="pos">
55
<ol
66
ref="listRef"
@@ -12,6 +12,7 @@
1212
:data-rich-colors="richColors"
1313
:data-y-position="pos.split('-')[0]"
1414
:data-x-position="pos.split('-')[1]"
15+
:data-lifted="expanded && toasts.length > 1 && !expand"
1516
:style="
1617
{
1718
'--front-toast-height': `${heights[0]?.height}px`,
@@ -272,7 +273,7 @@ function onPointerDown(event: PointerEvent) {
272273
273274
if (isNotDismissible) return
274275
}
275-
interacting.value = false
276+
interacting.value = true
276277
}
277278
278279
watchEffect((onInvalidate) => {
@@ -331,15 +332,30 @@ watch(
331332
332333
if (typeof window === 'undefined') return
333334
334-
window
335-
.matchMedia('(prefers-color-scheme: dark)')
336-
.addEventListener('change', ({ matches }) => {
335+
const darkMediaQuery = window.matchMedia('(prefers-color-scheme: dark)');
336+
337+
try {
338+
// Chrome & Firefox
339+
darkMediaQuery.addEventListener('change', ({ matches }) => {
337340
if (matches) {
338341
actualTheme.value = 'dark'
339342
} else {
340343
actualTheme.value = 'light'
341344
}
342345
})
346+
} catch(error) {
347+
darkMediaQuery.addListener(({ matches }) => {
348+
try {
349+
if (matches) {
350+
actualTheme.value = 'dark'
351+
} else {
352+
actualTheme.value = 'light'
353+
}
354+
} catch (e) {
355+
console.error(e);
356+
}
357+
});
358+
}
343359
}
344360
)
345361

‎src/packages/state.ts

+10-8
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ import type {
1010

1111
let toastsCounter = 0
1212

13+
type titleT = (() => string | Component) | string | Component;
14+
1315
class Observer {
1416
subscribers: Array<(toast: ExternalToast | ToastToDismiss) => void>
1517
toasts: Array<ToastT | ToastToDismiss>
@@ -40,7 +42,7 @@ class Observer {
4042

4143
create = (
4244
data: ExternalToast & {
43-
message?: string | Component
45+
message?: titleT
4446
type?: ToastTypes
4547
promise?: PromiseT
4648
}
@@ -90,27 +92,27 @@ class Observer {
9092
return id
9193
}
9294

93-
message = (message: string | Component, data?: ExternalToast) => {
95+
message = (message: titleT, data?: ExternalToast) => {
9496
return this.create({ ...data, message, type: 'default' })
9597
}
9698

97-
error = (message: string | Component, data?: ExternalToast) => {
99+
error = (message: titleT, data?: ExternalToast) => {
98100
return this.create({ ...data, type: 'error', message })
99101
}
100102

101-
success = (message: string | Component, data?: ExternalToast) => {
103+
success = (message: titleT, data?: ExternalToast) => {
102104
return this.create({ ...data, type: 'success', message })
103105
}
104106

105-
info = (message: string | Component, data?: ExternalToast) => {
107+
info = (message: titleT, data?: ExternalToast) => {
106108
return this.create({ ...data, type: 'info', message })
107109
}
108110

109-
warning = (message: string | Component, data?: ExternalToast) => {
111+
warning = (message: titleT, data?: ExternalToast) => {
110112
return this.create({ ...data, type: 'warning', message })
111113
}
112114

113-
loading = (message: string | Component, data?: ExternalToast) => {
115+
loading = (message: titleT, data?: ExternalToast) => {
114116
return this.create({ ...data, type: 'loading', message })
115117
}
116118

@@ -229,7 +231,7 @@ class Observer {
229231
export const ToastState = new Observer()
230232

231233
// bind this to the toast function
232-
function toastFunction(message: string | Component, data?: ExternalToast) {
234+
function toastFunction(message: titleT, data?: ExternalToast) {
233235
const id = data?.id || toastsCounter++
234236

235237
ToastState.create({

0 commit comments

Comments
 (0)
Please sign in to comment.