@hanzogui/toast 8.0.0 → 8.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/ToastComposable.cjs +1 -0
- package/dist/cjs/ToastComposable.native.js +17 -0
- package/dist/cjs/ToastComposable.native.js.map +1 -1
- package/dist/cjs/ToastImpl.native.js.map +1 -1
- package/dist/esm/ToastComposable.mjs +1 -0
- package/dist/esm/ToastComposable.mjs.map +1 -1
- package/dist/esm/ToastComposable.native.js +17 -0
- package/dist/esm/ToastComposable.native.js.map +1 -1
- package/dist/jsx/ToastComposable.mjs +1 -0
- package/dist/jsx/ToastComposable.mjs.map +1 -1
- package/dist/jsx/ToastComposable.native.js +17 -0
- package/dist/jsx/ToastComposable.native.js.map +1 -1
- package/dist/jsx/ToastImpl.native.js.map +1 -1
- package/package.json +24 -18
- package/src/ToastComposable.tsx +17 -0
- package/src/ToastImpl.tsx +231 -234
- package/types/Toast.d.ts +33 -33
- package/types/Toast.d.ts.map +1 -1
- package/types/ToastAnnounce.d.ts +2 -2
- package/types/ToastAnnounce.d.ts.map +1 -1
- package/types/ToastComposable.d.ts +26 -26
- package/types/ToastComposable.d.ts.map +1 -1
- package/types/ToastImpl.d.ts +9 -9
- package/types/ToastImpl.d.ts.map +1 -1
- package/types/ToastItemFrame.d.ts +12 -12
- package/types/ToastItemFrame.d.ts.map +1 -1
- package/types/ToastViewport.d.ts +9 -9
- package/types/ToastViewport.d.ts.map +1 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hanzogui/toast",
|
|
3
|
-
"version": "8.
|
|
3
|
+
"version": "8.1.0",
|
|
4
4
|
"source": "src/index.ts",
|
|
5
5
|
"files": [
|
|
6
6
|
"src",
|
|
@@ -44,25 +44,26 @@
|
|
|
44
44
|
"clean:build": "hanzogui-build clean:build"
|
|
45
45
|
},
|
|
46
46
|
"dependencies": {
|
|
47
|
-
"@hanzogui/animate-presence": "8.
|
|
48
|
-
"@hanzogui/collection": "8.
|
|
49
|
-
"@hanzogui/compose-refs": "8.
|
|
50
|
-
"@hanzogui/constants": "8.
|
|
51
|
-
"@hanzogui/core": "8.
|
|
52
|
-
"@hanzogui/create-context": "8.
|
|
53
|
-
"@hanzogui/dismissable": "8.
|
|
54
|
-
"@hanzogui/helpers": "8.
|
|
55
|
-
"@hanzogui/native": "8.
|
|
56
|
-
"@hanzogui/polyfill-dev": "8.
|
|
57
|
-
"@hanzogui/portal": "8.
|
|
58
|
-
"@hanzogui/stacks": "8.
|
|
59
|
-
"@hanzogui/start-transition": "8.
|
|
60
|
-
"@hanzogui/text": "8.
|
|
61
|
-
"@hanzogui/use-controllable-state": "8.
|
|
62
|
-
"@hanzogui/visually-hidden": "8.
|
|
47
|
+
"@hanzogui/animate-presence": "8.1.0",
|
|
48
|
+
"@hanzogui/collection": "8.1.0",
|
|
49
|
+
"@hanzogui/compose-refs": "8.1.0",
|
|
50
|
+
"@hanzogui/constants": "8.1.0",
|
|
51
|
+
"@hanzogui/core": "8.1.0",
|
|
52
|
+
"@hanzogui/create-context": "8.1.0",
|
|
53
|
+
"@hanzogui/dismissable": "8.1.0",
|
|
54
|
+
"@hanzogui/helpers": "8.1.0",
|
|
55
|
+
"@hanzogui/native": "8.1.0",
|
|
56
|
+
"@hanzogui/polyfill-dev": "8.1.0",
|
|
57
|
+
"@hanzogui/portal": "8.1.0",
|
|
58
|
+
"@hanzogui/stacks": "8.1.0",
|
|
59
|
+
"@hanzogui/start-transition": "8.1.0",
|
|
60
|
+
"@hanzogui/text": "8.1.0",
|
|
61
|
+
"@hanzogui/use-controllable-state": "8.1.0",
|
|
62
|
+
"@hanzogui/visually-hidden": "8.1.0",
|
|
63
|
+
"@hanzogui/web": "8.1.0"
|
|
63
64
|
},
|
|
64
65
|
"devDependencies": {
|
|
65
|
-
"@hanzogui/build": "8.
|
|
66
|
+
"@hanzogui/build": "8.1.0",
|
|
66
67
|
"react": ">=19",
|
|
67
68
|
"react-native": "0.83.2"
|
|
68
69
|
},
|
|
@@ -76,5 +77,10 @@
|
|
|
76
77
|
"./types/v2.d.ts"
|
|
77
78
|
]
|
|
78
79
|
}
|
|
80
|
+
},
|
|
81
|
+
"repository": {
|
|
82
|
+
"type": "git",
|
|
83
|
+
"url": "git+https://github.com/hanzoai/gui.git",
|
|
84
|
+
"directory": "pkgs/ui/toast"
|
|
79
85
|
}
|
|
80
86
|
}
|
package/src/ToastComposable.tsx
CHANGED
|
@@ -1203,6 +1203,23 @@ const ToastItemInner = ToastItemFrame.styleable<ToastItemProps>(
|
|
|
1203
1203
|
dragRef={dragRef}
|
|
1204
1204
|
>
|
|
1205
1205
|
<ToastItemFrame
|
|
1206
|
+
// The one hook a stylesheet can reach a toast by.
|
|
1207
|
+
//
|
|
1208
|
+
// A toast is floating chrome — it is over the page or it is nothing
|
|
1209
|
+
// — so a design system wants to give it the same material every
|
|
1210
|
+
// other floating surface wears. It had no handle at all: `Toaster`
|
|
1211
|
+
// accepts sonner's `className`/`style`/`classNames` and documents
|
|
1212
|
+
// them as INERT, and nothing else here reaches the DOM node. So the
|
|
1213
|
+
// one surface that is unambiguously floating was the one surface a
|
|
1214
|
+
// sheet could not select, and it kept a hand-rolled
|
|
1215
|
+
// `rgba(0,0,0,0.15)` drop that is very nearly invisible on a dark
|
|
1216
|
+
// ground — the exact defect an elevation ladder exists to end.
|
|
1217
|
+
//
|
|
1218
|
+
// `data-slot` rather than a class or a prop because it needs no
|
|
1219
|
+
// decision from a call site: a toast is glass because it IS a toast.
|
|
1220
|
+
// gui forwards unrecognised props to the DOM node and native drops
|
|
1221
|
+
// them, which is what makes this cross-platform safe.
|
|
1222
|
+
data-slot="toast"
|
|
1206
1223
|
role="status"
|
|
1207
1224
|
aria-live="polite"
|
|
1208
1225
|
aria-atomic
|
package/src/ToastImpl.tsx
CHANGED
|
@@ -161,254 +161,251 @@ type ToastImplProps = ScopedProps<
|
|
|
161
161
|
ToastImplPrivateProps & ToastImplFrameProps & ToastExtraProps
|
|
162
162
|
>
|
|
163
163
|
|
|
164
|
-
const ToastImpl = React.forwardRef<GuiElement, ToastImplProps>(
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
})
|
|
164
|
+
const ToastImpl = React.forwardRef<GuiElement, ToastImplProps>((props, forwardedRef) => {
|
|
165
|
+
const {
|
|
166
|
+
scope,
|
|
167
|
+
type = 'foreground',
|
|
168
|
+
duration: durationProp,
|
|
169
|
+
open,
|
|
170
|
+
onClose,
|
|
171
|
+
onEscapeKeyDown,
|
|
172
|
+
onPause,
|
|
173
|
+
onResume,
|
|
174
|
+
onSwipeStart,
|
|
175
|
+
onSwipeMove,
|
|
176
|
+
onSwipeCancel,
|
|
177
|
+
onSwipeEnd,
|
|
178
|
+
viewportName = 'default',
|
|
179
|
+
...toastProps
|
|
180
|
+
} = props
|
|
181
|
+
const isPresent = useIsPresent()
|
|
182
|
+
const context = useToastProviderContext(scope)
|
|
183
|
+
const [node, setNode] = React.useState<GuiElement | null>(null)
|
|
184
|
+
const composedRefs = useComposedRefs(forwardedRef, setNode)
|
|
185
|
+
const duration = durationProp || context.duration
|
|
186
|
+
const closeTimerStartTimeRef = React.useRef(0)
|
|
187
|
+
const closeTimerRemainingTimeRef = React.useRef(duration)
|
|
188
|
+
const closeTimerRef = React.useRef(0)
|
|
189
|
+
const { onToastAdd, onToastRemove } = context
|
|
190
|
+
|
|
191
|
+
const viewport = React.useMemo(() => {
|
|
192
|
+
return context.viewports[viewportName] as HTMLElement | null | undefined
|
|
193
|
+
}, [context.viewports, viewportName])
|
|
194
|
+
|
|
195
|
+
const handleClose = useEvent(() => {
|
|
196
|
+
if (!isPresent) {
|
|
197
|
+
// already removed from the react tree
|
|
198
|
+
return
|
|
199
|
+
}
|
|
200
|
+
// focus viewport if focus is within toast to read the remaining toast
|
|
201
|
+
// count to SR users and ensure focus isn't lost
|
|
202
|
+
if (isWeb) {
|
|
203
|
+
const isFocusInToast = (node as unknown as HTMLDivElement)?.contains(
|
|
204
|
+
document.activeElement
|
|
205
|
+
)
|
|
206
|
+
if (isFocusInToast) viewport?.focus()
|
|
207
|
+
}
|
|
208
|
+
onClose()
|
|
209
|
+
})
|
|
211
210
|
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
viewport.removeEventListener(VIEWPORT_RESUME, handleResume)
|
|
244
|
-
}
|
|
245
|
-
}
|
|
246
|
-
}, [viewport, duration, onPause, onResume, startTimer])
|
|
247
|
-
|
|
248
|
-
// start timer when toast opens or duration changes.
|
|
249
|
-
// we include `open` in deps because closed !== unmounted when animating
|
|
250
|
-
// so it could reopen before being completely unmounted
|
|
251
|
-
React.useEffect(() => {
|
|
252
|
-
if (open && !context.isClosePausedRef.current) {
|
|
253
|
-
startTimer(duration)
|
|
211
|
+
const startTimer = React.useCallback(
|
|
212
|
+
(duration: number) => {
|
|
213
|
+
if (!duration || duration === Number.POSITIVE_INFINITY) return
|
|
214
|
+
clearTimeout(closeTimerRef.current)
|
|
215
|
+
closeTimerStartTimeRef.current = new Date().getTime()
|
|
216
|
+
closeTimerRef.current = setTimeout(handleClose, duration) as unknown as number
|
|
217
|
+
},
|
|
218
|
+
[handleClose]
|
|
219
|
+
)
|
|
220
|
+
|
|
221
|
+
const handleResume = React.useCallback(() => {
|
|
222
|
+
startTimer(closeTimerRemainingTimeRef.current)
|
|
223
|
+
onResume?.()
|
|
224
|
+
}, [onResume, startTimer])
|
|
225
|
+
|
|
226
|
+
const handlePause = React.useCallback(() => {
|
|
227
|
+
const elapsedTime = new Date().getTime() - closeTimerStartTimeRef.current
|
|
228
|
+
closeTimerRemainingTimeRef.current = closeTimerRemainingTimeRef.current - elapsedTime
|
|
229
|
+
window.clearTimeout(closeTimerRef.current)
|
|
230
|
+
onPause?.()
|
|
231
|
+
}, [onPause])
|
|
232
|
+
|
|
233
|
+
React.useEffect(() => {
|
|
234
|
+
if (!isWeb) return
|
|
235
|
+
|
|
236
|
+
if (viewport) {
|
|
237
|
+
viewport.addEventListener(VIEWPORT_PAUSE, handlePause)
|
|
238
|
+
viewport.addEventListener(VIEWPORT_RESUME, handleResume)
|
|
239
|
+
return () => {
|
|
240
|
+
viewport.removeEventListener(VIEWPORT_PAUSE, handlePause)
|
|
241
|
+
viewport.removeEventListener(VIEWPORT_RESUME, handleResume)
|
|
254
242
|
}
|
|
255
|
-
}
|
|
243
|
+
}
|
|
244
|
+
}, [viewport, duration, onPause, onResume, startTimer])
|
|
245
|
+
|
|
246
|
+
// start timer when toast opens or duration changes.
|
|
247
|
+
// we include `open` in deps because closed !== unmounted when animating
|
|
248
|
+
// so it could reopen before being completely unmounted
|
|
249
|
+
React.useEffect(() => {
|
|
250
|
+
if (open && !context.isClosePausedRef.current) {
|
|
251
|
+
startTimer(duration)
|
|
252
|
+
}
|
|
253
|
+
}, [open, duration, context.isClosePausedRef, startTimer])
|
|
256
254
|
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
255
|
+
React.useEffect(() => {
|
|
256
|
+
onToastAdd()
|
|
257
|
+
return () => onToastRemove()
|
|
258
|
+
}, [onToastAdd, onToastRemove])
|
|
261
259
|
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
260
|
+
const announceTextContent = React.useMemo(() => {
|
|
261
|
+
if (!isWeb) return null
|
|
262
|
+
return node ? getAnnounceTextContent(node as unknown as HTMLDivElement) : null
|
|
263
|
+
}, [node])
|
|
266
264
|
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
265
|
+
const isHorizontalSwipe = ['left', 'right', 'horizontal'].includes(
|
|
266
|
+
context.swipeDirection
|
|
267
|
+
)
|
|
270
268
|
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
269
|
+
const { animationDriver } = useConfiguration()
|
|
270
|
+
if (!animationDriver) {
|
|
271
|
+
throw new Error('Must set animations in hanzogui.config.ts')
|
|
272
|
+
}
|
|
275
273
|
|
|
276
|
-
|
|
274
|
+
const { useAnimatedNumber, useAnimatedNumberStyle } = animationDriver
|
|
277
275
|
|
|
278
|
-
|
|
276
|
+
const animatedNumber = useAnimatedNumber(0)
|
|
279
277
|
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
278
|
+
// temp until reanimated useAnimatedNumber fix
|
|
279
|
+
const AnimatedView = (animationDriver['NumberView'] ??
|
|
280
|
+
animationDriver.View ??
|
|
281
|
+
View) as typeof Animated.View
|
|
284
282
|
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
283
|
+
const animatedStyles = useAnimatedNumberStyle(animatedNumber, (val) => {
|
|
284
|
+
'worklet'
|
|
285
|
+
return {
|
|
286
|
+
transform: [isHorizontalSwipe ? { translateX: val } : { translateY: val }],
|
|
287
|
+
}
|
|
288
|
+
})
|
|
291
289
|
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
290
|
+
const panResponder = React.useMemo(() => {
|
|
291
|
+
const PanResponder = getPanResponder()
|
|
292
|
+
if (!PanResponder) return null
|
|
293
|
+
return PanResponder.create({
|
|
294
|
+
onMoveShouldSetPanResponder: (e, gesture) => {
|
|
295
|
+
const shouldMove = shouldGrantGestureMove(context.swipeDirection, gesture)
|
|
296
|
+
if (shouldMove) {
|
|
297
|
+
onSwipeStart?.(e)
|
|
298
|
+
return true
|
|
299
|
+
}
|
|
300
|
+
return false
|
|
301
|
+
},
|
|
302
|
+
onPanResponderGrant: (e) => {
|
|
303
|
+
if (!isWeb) {
|
|
304
|
+
handlePause?.()
|
|
305
|
+
}
|
|
306
|
+
},
|
|
307
|
+
onPanResponderMove: (e, gesture) => {
|
|
308
|
+
const { x, y } = getGestureDistance(context.swipeDirection, gesture)
|
|
309
|
+
const delta = { x, y }
|
|
310
|
+
animatedNumber.setValue(isHorizontalSwipe ? x : y, { type: 'direct' })
|
|
311
|
+
if (isDeltaInDirection(delta, context.swipeDirection, context.swipeThreshold)) {
|
|
312
|
+
onSwipeEnd?.(e)
|
|
313
|
+
}
|
|
314
|
+
onSwipeMove?.(e)
|
|
315
|
+
},
|
|
316
|
+
onPanResponderEnd: (e, { dx, dy }) => {
|
|
317
|
+
if (
|
|
318
|
+
!isDeltaInDirection(
|
|
319
|
+
{ x: dx, y: dy },
|
|
320
|
+
context.swipeDirection,
|
|
321
|
+
context.swipeThreshold
|
|
322
|
+
)
|
|
323
|
+
) {
|
|
305
324
|
if (!isWeb) {
|
|
306
|
-
|
|
307
|
-
}
|
|
308
|
-
},
|
|
309
|
-
onPanResponderMove: (e, gesture) => {
|
|
310
|
-
const { x, y } = getGestureDistance(context.swipeDirection, gesture)
|
|
311
|
-
const delta = { x, y }
|
|
312
|
-
animatedNumber.setValue(isHorizontalSwipe ? x : y, { type: 'direct' })
|
|
313
|
-
if (isDeltaInDirection(delta, context.swipeDirection, context.swipeThreshold)) {
|
|
314
|
-
onSwipeEnd?.(e)
|
|
325
|
+
handleResume?.()
|
|
315
326
|
}
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
scope={scope}
|
|
358
|
-
onClose={() => {
|
|
359
|
-
handleClose()
|
|
360
|
-
}}
|
|
327
|
+
onSwipeCancel?.(e)
|
|
328
|
+
animatedNumber.setValue(0, { type: 'spring' })
|
|
329
|
+
}
|
|
330
|
+
},
|
|
331
|
+
})
|
|
332
|
+
}, [handlePause, handleResume])
|
|
333
|
+
|
|
334
|
+
// need to get the theme name from context and apply it again since portals don't retain the theme
|
|
335
|
+
const themeName = useThemeName()
|
|
336
|
+
|
|
337
|
+
return (
|
|
338
|
+
<>
|
|
339
|
+
{announceTextContent && (
|
|
340
|
+
<ToastAnnounce
|
|
341
|
+
scope={scope}
|
|
342
|
+
// Toasts are always role=status to avoid stuttering issues with role=alert in SRs.
|
|
343
|
+
// biome-ignore lint/a11y/useSemanticElements: <explanation>
|
|
344
|
+
role="status"
|
|
345
|
+
aria-live={type === 'foreground' ? 'assertive' : 'polite'}
|
|
346
|
+
aria-atomic
|
|
347
|
+
>
|
|
348
|
+
{announceTextContent}
|
|
349
|
+
</ToastAnnounce>
|
|
350
|
+
)}
|
|
351
|
+
|
|
352
|
+
<PortalItem hostName={viewportName ?? 'default'}>
|
|
353
|
+
<ToastInteractiveProvider
|
|
354
|
+
key={props.id}
|
|
355
|
+
scope={scope}
|
|
356
|
+
onClose={() => {
|
|
357
|
+
handleClose()
|
|
358
|
+
}}
|
|
359
|
+
>
|
|
360
|
+
<Dismissable
|
|
361
|
+
// asChild
|
|
362
|
+
onEscapeKeyDown={composeEventHandlers(onEscapeKeyDown, () => {
|
|
363
|
+
if (!context.isFocusedToastEscapeKeyDownRef.current) {
|
|
364
|
+
handleClose()
|
|
365
|
+
}
|
|
366
|
+
context.isFocusedToastEscapeKeyDownRef.current = false
|
|
367
|
+
})}
|
|
361
368
|
>
|
|
362
|
-
<
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
}
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
</Collection.ItemSlot>
|
|
403
|
-
</AnimatedView>
|
|
404
|
-
</Theme>
|
|
405
|
-
</Dismissable>
|
|
406
|
-
</ToastInteractiveProvider>
|
|
407
|
-
</PortalItem>
|
|
408
|
-
</>
|
|
409
|
-
)
|
|
410
|
-
}
|
|
411
|
-
)
|
|
369
|
+
<Theme contain forceClassName name={themeName}>
|
|
370
|
+
<AnimatedView
|
|
371
|
+
{...panResponder?.panHandlers}
|
|
372
|
+
style={[{ margin: 'auto' }, animatedStyles]}
|
|
373
|
+
>
|
|
374
|
+
<Collection.ItemSlot scope={context.toastScope}>
|
|
375
|
+
<ToastImplFrame
|
|
376
|
+
// Ensure toasts are announced as status list or status when focused
|
|
377
|
+
role="status"
|
|
378
|
+
aria-live="off"
|
|
379
|
+
aria-atomic
|
|
380
|
+
data-state={open ? 'open' : 'closed'}
|
|
381
|
+
data-swipe-direction={context.swipeDirection}
|
|
382
|
+
pointerEvents="auto"
|
|
383
|
+
$platform-web={{
|
|
384
|
+
touchAction: 'none',
|
|
385
|
+
userSelect: 'none',
|
|
386
|
+
}}
|
|
387
|
+
{...toastProps}
|
|
388
|
+
ref={composedRefs}
|
|
389
|
+
{...(isWeb && {
|
|
390
|
+
onKeyDown: composeEventHandlers(props.onKeyDown, (event) => {
|
|
391
|
+
if (event.key !== 'Escape') return
|
|
392
|
+
onEscapeKeyDown?.(event)
|
|
393
|
+
if (!event.defaultPrevented) {
|
|
394
|
+
context.isFocusedToastEscapeKeyDownRef.current = true
|
|
395
|
+
handleClose()
|
|
396
|
+
}
|
|
397
|
+
}),
|
|
398
|
+
})}
|
|
399
|
+
/>
|
|
400
|
+
</Collection.ItemSlot>
|
|
401
|
+
</AnimatedView>
|
|
402
|
+
</Theme>
|
|
403
|
+
</Dismissable>
|
|
404
|
+
</ToastInteractiveProvider>
|
|
405
|
+
</PortalItem>
|
|
406
|
+
</>
|
|
407
|
+
)
|
|
408
|
+
})
|
|
412
409
|
|
|
413
410
|
ToastImpl.propTypes = {
|
|
414
411
|
type(props) {
|