@tamagui/toast 1.7.11 → 1.8.1

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.
Files changed (131) hide show
  1. package/dist/cjs/Toast.js +95 -543
  2. package/dist/cjs/Toast.js.map +3 -3
  3. package/dist/cjs/ToastAnnounce.js +93 -0
  4. package/dist/cjs/ToastAnnounce.js.map +7 -0
  5. package/dist/cjs/ToastImpl.js +354 -0
  6. package/dist/cjs/ToastImpl.js.map +7 -0
  7. package/dist/cjs/ToastProvider.js +109 -0
  8. package/dist/cjs/ToastProvider.js.map +7 -0
  9. package/dist/cjs/ToastViewport.js +307 -0
  10. package/dist/cjs/ToastViewport.js.map +7 -0
  11. package/dist/cjs/constants.js +29 -0
  12. package/dist/cjs/constants.js.map +7 -0
  13. package/dist/cjs/createNativeToast.js +49 -0
  14. package/dist/cjs/createNativeToast.js.map +7 -0
  15. package/dist/cjs/createNativeToast.native.js +37 -0
  16. package/dist/cjs/createNativeToast.native.js.map +7 -0
  17. package/dist/cjs/createToast.js +88 -0
  18. package/dist/cjs/createToast.js.map +7 -0
  19. package/dist/cjs/types.js +17 -0
  20. package/dist/cjs/types.js.map +7 -0
  21. package/dist/esm/Toast.js +101 -531
  22. package/dist/esm/Toast.js.map +3 -3
  23. package/dist/esm/Toast.mjs +101 -531
  24. package/dist/esm/Toast.mjs.map +3 -3
  25. package/dist/esm/ToastAnnounce.js +64 -0
  26. package/dist/esm/ToastAnnounce.js.map +7 -0
  27. package/dist/esm/ToastAnnounce.mjs +64 -0
  28. package/dist/esm/ToastAnnounce.mjs.map +7 -0
  29. package/dist/esm/ToastImpl.js +330 -0
  30. package/dist/esm/ToastImpl.js.map +7 -0
  31. package/dist/esm/ToastImpl.mjs +330 -0
  32. package/dist/esm/ToastImpl.mjs.map +7 -0
  33. package/dist/esm/ToastProvider.js +70 -0
  34. package/dist/esm/ToastProvider.js.map +7 -0
  35. package/dist/esm/ToastProvider.mjs +70 -0
  36. package/dist/esm/ToastProvider.mjs.map +7 -0
  37. package/dist/esm/ToastViewport.js +274 -0
  38. package/dist/esm/ToastViewport.js.map +7 -0
  39. package/dist/esm/ToastViewport.mjs +274 -0
  40. package/dist/esm/ToastViewport.mjs.map +7 -0
  41. package/dist/esm/constants.js +5 -0
  42. package/dist/esm/constants.js.map +7 -0
  43. package/dist/esm/constants.mjs +5 -0
  44. package/dist/esm/constants.mjs.map +7 -0
  45. package/dist/esm/createNativeToast.js +25 -0
  46. package/dist/esm/createNativeToast.js.map +7 -0
  47. package/dist/esm/createNativeToast.mjs +25 -0
  48. package/dist/esm/createNativeToast.mjs.map +7 -0
  49. package/dist/esm/createNativeToast.native.js +13 -0
  50. package/dist/esm/createNativeToast.native.js.map +7 -0
  51. package/dist/esm/createNativeToast.native.mjs +13 -0
  52. package/dist/esm/createNativeToast.native.mjs.map +7 -0
  53. package/dist/esm/createToast.js +54 -0
  54. package/dist/esm/createToast.js.map +7 -0
  55. package/dist/esm/createToast.mjs +54 -0
  56. package/dist/esm/createToast.mjs.map +7 -0
  57. package/dist/esm/types.js +1 -0
  58. package/dist/esm/types.js.map +7 -0
  59. package/dist/esm/types.mjs +1 -0
  60. package/dist/esm/types.mjs.map +7 -0
  61. package/dist/jsx/Toast.js +97 -509
  62. package/dist/jsx/Toast.js.map +3 -3
  63. package/dist/jsx/Toast.mjs +97 -509
  64. package/dist/jsx/Toast.mjs.map +3 -3
  65. package/dist/jsx/ToastAnnounce.js +60 -0
  66. package/dist/jsx/ToastAnnounce.js.map +7 -0
  67. package/dist/jsx/ToastAnnounce.mjs +60 -0
  68. package/dist/jsx/ToastAnnounce.mjs.map +7 -0
  69. package/dist/jsx/ToastImpl.js +309 -0
  70. package/dist/jsx/ToastImpl.js.map +7 -0
  71. package/dist/jsx/ToastImpl.mjs +309 -0
  72. package/dist/jsx/ToastImpl.mjs.map +7 -0
  73. package/dist/jsx/ToastProvider.js +65 -0
  74. package/dist/jsx/ToastProvider.js.map +7 -0
  75. package/dist/jsx/ToastProvider.mjs +65 -0
  76. package/dist/jsx/ToastProvider.mjs.map +7 -0
  77. package/dist/jsx/ToastViewport.js +254 -0
  78. package/dist/jsx/ToastViewport.js.map +7 -0
  79. package/dist/jsx/ToastViewport.mjs +254 -0
  80. package/dist/jsx/ToastViewport.mjs.map +7 -0
  81. package/dist/jsx/constants.js +5 -0
  82. package/dist/jsx/constants.js.map +7 -0
  83. package/dist/jsx/constants.mjs +5 -0
  84. package/dist/jsx/constants.mjs.map +7 -0
  85. package/dist/jsx/createNativeToast.js +25 -0
  86. package/dist/jsx/createNativeToast.js.map +7 -0
  87. package/dist/jsx/createNativeToast.mjs +25 -0
  88. package/dist/jsx/createNativeToast.mjs.map +7 -0
  89. package/dist/jsx/createNativeToast.native.js +13 -0
  90. package/dist/jsx/createNativeToast.native.js.map +7 -0
  91. package/dist/jsx/createNativeToast.native.mjs +13 -0
  92. package/dist/jsx/createNativeToast.native.mjs.map +7 -0
  93. package/dist/jsx/createToast.js +49 -0
  94. package/dist/jsx/createToast.js.map +7 -0
  95. package/dist/jsx/createToast.mjs +49 -0
  96. package/dist/jsx/createToast.mjs.map +7 -0
  97. package/dist/jsx/types.js +1 -0
  98. package/dist/jsx/types.js.map +7 -0
  99. package/dist/jsx/types.mjs +1 -0
  100. package/dist/jsx/types.mjs.map +7 -0
  101. package/package.json +14 -13
  102. package/src/Toast.tsx +139 -908
  103. package/src/ToastAnnounce.tsx +97 -0
  104. package/src/ToastImpl.tsx +439 -0
  105. package/src/ToastProvider.tsx +134 -0
  106. package/src/ToastViewport.tsx +354 -0
  107. package/src/constants.ts +1 -0
  108. package/src/createNativeToast.native.tsx +16 -0
  109. package/src/createNativeToast.tsx +25 -0
  110. package/src/createToast.tsx +93 -0
  111. package/src/types.ts +21 -0
  112. package/types/Toast.d.ts +429 -106
  113. package/types/Toast.d.ts.map +1 -1
  114. package/types/ToastAnnounce.d.ts +35 -0
  115. package/types/ToastAnnounce.d.ts.map +1 -0
  116. package/types/ToastImpl.d.ts +267 -0
  117. package/types/ToastImpl.d.ts.map +1 -0
  118. package/types/ToastProvider.d.ts +80 -0
  119. package/types/ToastProvider.d.ts.map +1 -0
  120. package/types/ToastViewport.d.ts +115 -0
  121. package/types/ToastViewport.d.ts.map +1 -0
  122. package/types/constants.d.ts +2 -0
  123. package/types/constants.d.ts.map +1 -0
  124. package/types/createNativeToast.d.ts +3 -0
  125. package/types/createNativeToast.d.ts.map +1 -0
  126. package/types/createNativeToast.native.d.ts +3 -0
  127. package/types/createNativeToast.native.d.ts.map +1 -0
  128. package/types/createToast.d.ts +42 -0
  129. package/types/createToast.d.ts.map +1 -0
  130. package/types/types.d.ts +17 -0
  131. package/types/types.d.ts.map +1 -0
@@ -1,441 +1,79 @@
1
- import { useComposedRefs } from "@tamagui/compose-refs";
2
1
  import {
3
2
  composeEventHandlers,
4
- isWeb,
3
+ styled,
4
+ themeable,
5
5
  useEvent,
6
- useIsomorphicLayoutEffect
6
+ useId,
7
+ withStaticProperties
7
8
  } from "@tamagui/core";
8
- import { Portal } from "@tamagui/portal";
9
- import { YStack } from "@tamagui/stacks";
9
+ import { ThemeableStack } from "@tamagui/stacks";
10
+ import { SizableText } from "@tamagui/text";
10
11
  import { useControllableState } from "@tamagui/use-controllable-state";
11
- import { VisuallyHidden } from "@tamagui/visually-hidden";
12
12
  import * as React from "react";
13
- import * as ReactDOM from "react-dom";
14
- const PROVIDER_NAME = "ToastProvider";
15
- const [ToastProviderProvider, useToastProviderContext] = [];
16
- const ToastProvider = (props) => {
17
- const {
18
- __scopeToast,
19
- label = "Notification",
20
- duration = 5e3,
21
- swipeDirection = "right",
22
- swipeThreshold = 50,
23
- children
24
- } = props;
25
- const [viewport, setViewport] = React.useState(null);
26
- const [toastCount, setToastCount] = React.useState(0);
27
- const isFocusedToastEscapeKeyDownRef = React.useRef(false);
28
- const isClosePausedRef = React.useRef(false);
29
- return (
30
- // <Collection.Provider scope={__scopeToast}>
31
- <ToastProviderProvider
32
- scope={__scopeToast}
33
- label={label}
34
- duration={duration}
35
- swipeDirection={swipeDirection}
36
- swipeThreshold={swipeThreshold}
37
- toastCount={toastCount}
38
- viewport={viewport}
39
- onViewportChange={setViewport}
40
- onToastAdd={React.useCallback(
41
- () => setToastCount((prevCount) => prevCount + 1),
42
- []
43
- )}
44
- onToastRemove={React.useCallback(
45
- () => setToastCount((prevCount) => prevCount - 1),
46
- []
47
- )}
48
- isFocusedToastEscapeKeyDownRef={isFocusedToastEscapeKeyDownRef}
49
- isClosePausedRef={isClosePausedRef}
50
- >{children}</ToastProviderProvider>
51
- );
52
- };
53
- ToastProvider.propTypes = {
54
- label(props) {
55
- if (props.label && typeof props.label === "string" && !props.label.trim()) {
56
- const error = `Invalid prop \`label\` supplied to \`${PROVIDER_NAME}\`. Expected non-empty \`string\`.`;
57
- return new Error(error);
58
- }
59
- return null;
60
- }
61
- };
62
- ToastProvider.displayName = PROVIDER_NAME;
63
- const VIEWPORT_NAME = "ToastViewport";
64
- const VIEWPORT_DEFAULT_HOTKEY = ["F8"];
65
- const VIEWPORT_PAUSE = "toast.viewportPause";
66
- const VIEWPORT_RESUME = "toast.viewportResume";
67
- const ToastViewport = React.forwardRef(
68
- (props, forwardedRef) => {
69
- const {
70
- __scopeToast,
71
- hotkey = VIEWPORT_DEFAULT_HOTKEY,
72
- label = "Notifications ({hotkey})",
73
- ...viewportProps
74
- } = props;
75
- const context = useToastProviderContext(VIEWPORT_NAME, __scopeToast);
76
- const wrapperRef = React.useRef(null);
77
- const headFocusProxyRef = React.useRef(null);
78
- const tailFocusProxyRef = React.useRef(null);
79
- const ref = React.useRef(null);
80
- const composedRefs = useComposedRefs(forwardedRef, ref, context.onViewportChange);
81
- const hotkeyLabel = hotkey.join("+").replace(/Key/g, "").replace(/Digit/g, "");
82
- const hasToasts = context.toastCount > 0;
83
- React.useEffect(() => {
84
- const handleKeyDown = (event) => {
85
- const isHotkeyPressed = hotkey.every(
86
- (key) => event[key] || event.code === key
87
- );
88
- if (isHotkeyPressed)
89
- ref.current?.focus();
90
- };
91
- document.addEventListener("keydown", handleKeyDown);
92
- return () => document.removeEventListener("keydown", handleKeyDown);
93
- }, [hotkey]);
94
- React.useEffect(() => {
95
- const wrapper = wrapperRef.current;
96
- const viewport = ref.current;
97
- if (wrapper && viewport) {
98
- const handlePause = () => {
99
- const pauseEvent = new CustomEvent(VIEWPORT_PAUSE);
100
- context.isClosePausedRef.current = true;
101
- };
102
- const handleResume = () => {
103
- const resumeEvent = new CustomEvent(VIEWPORT_RESUME);
104
- context.isClosePausedRef.current = false;
105
- };
106
- wrapper.addEventListener("focusin", handlePause);
107
- wrapper.addEventListener("focusout", handleResume);
108
- wrapper.addEventListener("pointerenter", handlePause);
109
- wrapper.addEventListener("pointerleave", handleResume);
110
- window.addEventListener("blur", handlePause);
111
- window.addEventListener("focus", handleResume);
112
- return () => {
113
- wrapper.removeEventListener("focusin", handlePause);
114
- wrapper.removeEventListener("focusout", handleResume);
115
- wrapper.removeEventListener("pointerenter", handlePause);
116
- wrapper.removeEventListener("pointerleave", handleResume);
117
- window.removeEventListener("blur", handlePause);
118
- window.removeEventListener("focus", handleResume);
119
- };
120
- }
121
- }, [context.isClosePausedRef]);
122
- React.useEffect(
123
- () => {
124
- const viewport = ref.current;
125
- if (viewport) {
126
- const handleKeyDown = (event) => {
127
- const isMetaKey = event.altKey || event.ctrlKey || event.metaKey;
128
- const isTabKey = event.key === "Tab" && !isMetaKey;
129
- if (isTabKey) {
130
- const focusedElement = document.activeElement;
131
- const isTabbingBackwards = event.shiftKey;
132
- const targetIsViewport = event.target === viewport;
133
- if (targetIsViewport && isTabbingBackwards) {
134
- headFocusProxyRef.current?.focus();
135
- return;
136
- }
137
- const tabbingDirection = isTabbingBackwards ? "backwards" : "forwards";
138
- }
139
- };
140
- return () => {
141
- };
142
- }
143
- },
144
- [
145
- // getItems, getSortedTabbableCandidates
146
- ]
147
- );
148
- return null;
149
- }
150
- );
151
- ToastViewport.displayName = VIEWPORT_NAME;
152
- const FOCUS_PROXY_NAME = "ToastFocusProxy";
153
- const FocusProxy = React.forwardRef(
154
- (props, forwardedRef) => {
155
- const { __scopeToast, onFocusFromOutsideViewport, ...proxyProps } = props;
156
- const context = useToastProviderContext(FOCUS_PROXY_NAME, __scopeToast);
157
- return <VisuallyHidden
158
- aria-hidden
159
- tabIndex={0}
160
- {...proxyProps}
161
- ref={forwardedRef}
162
- position={isWeb ? "fixed" : "absolute"}
163
- onFocus={(event) => {
164
- const prevFocusedElement = event.relatedTarget;
165
- const isFocusFromOutsideViewport = !context.viewport?.contains(prevFocusedElement);
166
- if (isFocusFromOutsideViewport)
167
- onFocusFromOutsideViewport();
168
- }}
169
- />;
170
- }
171
- );
172
- FocusProxy.displayName = FOCUS_PROXY_NAME;
173
- const TOAST_NAME = "Toast";
174
- const TOAST_SWIPE_START = "toast.swipeStart";
175
- const TOAST_SWIPE_MOVE = "toast.swipeMove";
176
- const TOAST_SWIPE_CANCEL = "toast.swipeCancel";
177
- const TOAST_SWIPE_END = "toast.swipeEnd";
178
- const Toast = React.forwardRef(
179
- (props, forwardedRef) => {
180
- const {
181
- forceMount,
182
- open: openProp,
183
- defaultOpen,
184
- onOpenChange,
185
- ...toastProps
186
- } = props;
187
- const [open, setOpen] = useControllableState({
188
- prop: openProp,
189
- defaultProp: true,
190
- onChange: onOpenChange,
191
- transition: true
192
- });
193
- return (
194
- // <Presence present={forceMount || open}>
195
- <ToastImpl
196
- open={open}
197
- {...toastProps}
198
- ref={forwardedRef}
199
- onClose={() => setOpen(false)}
200
- />
201
- );
202
- }
203
- );
204
- Toast.displayName = TOAST_NAME;
205
- const [ToastInteractiveProvider, useToastInteractiveContext] = {};
206
- const ToastImpl = React.forwardRef(
207
- (props, forwardedRef) => {
208
- const {
209
- __scopeToast,
210
- type = "foreground",
211
- duration: durationProp,
212
- open,
213
- onClose,
214
- onEscapeKeyDown,
215
- onSwipeStart,
216
- onSwipeMove,
217
- onSwipeCancel,
218
- onSwipeEnd,
219
- ...toastProps
220
- } = props;
221
- const context = useToastProviderContext(TOAST_NAME, __scopeToast);
222
- const ref = React.useRef(null);
223
- const composedRefs = useComposedRefs(forwardedRef, ref);
224
- const pointerStartRef = React.useRef(null);
225
- const swipeDeltaRef = React.useRef(null);
226
- const duration = durationProp || context.duration;
227
- const closeTimerStartTimeRef = React.useRef(0);
228
- const closeTimerRemainingTimeRef = React.useRef(duration);
229
- const closeTimerRef = React.useRef(0);
230
- const { onToastAdd, onToastRemove } = context;
231
- const handleClose = useEvent(() => {
232
- onClose();
233
- });
234
- const startTimer = React.useCallback(
235
- (duration2) => {
236
- if (!duration2 || duration2 === Infinity)
237
- return;
238
- window.clearTimeout(closeTimerRef.current);
239
- closeTimerStartTimeRef.current = (/* @__PURE__ */ new Date()).getTime();
240
- closeTimerRef.current = window.setTimeout(handleClose, duration2);
241
- },
242
- [handleClose]
243
- );
244
- React.useEffect(() => {
245
- const viewport = context.viewport;
246
- if (viewport) {
247
- const handleResume = () => {
248
- startTimer(closeTimerRemainingTimeRef.current);
249
- };
250
- const handlePause = () => {
251
- const elapsedTime = (/* @__PURE__ */ new Date()).getTime() - closeTimerStartTimeRef.current;
252
- closeTimerRemainingTimeRef.current = closeTimerRemainingTimeRef.current - elapsedTime;
253
- window.clearTimeout(closeTimerRef.current);
254
- };
255
- viewport.addEventListener(VIEWPORT_PAUSE, handlePause);
256
- viewport.addEventListener(VIEWPORT_RESUME, handleResume);
257
- return () => {
258
- viewport.removeEventListener(VIEWPORT_PAUSE, handlePause);
259
- viewport.removeEventListener(VIEWPORT_RESUME, handleResume);
260
- };
13
+ import { TOAST_NAME } from "./constants";
14
+ import { createToast } from "./createToast";
15
+ import { ToastAnnounceExclude } from "./ToastAnnounce";
16
+ import {
17
+ ToastImpl,
18
+ ToastImplFrame,
19
+ useToastInteractiveContext
20
+ } from "./ToastImpl";
21
+ import {
22
+ ToastProvider,
23
+ createToastScope
24
+ } from "./ToastProvider";
25
+ import { ToastViewport } from "./ToastViewport";
26
+ const TITLE_NAME = "ToastTitle";
27
+ const ToastTitleFrame = styled(SizableText, {
28
+ name: TITLE_NAME,
29
+ color: "$color",
30
+ variants: {
31
+ unstyled: {
32
+ false: {
33
+ size: "$4"
261
34
  }
262
- }, [context.viewport, duration, startTimer]);
263
- React.useEffect(() => {
264
- if (open && !context.isClosePausedRef.current)
265
- startTimer(duration);
266
- }, [open, duration, context.isClosePausedRef, startTimer]);
267
- React.useEffect(() => {
268
- onToastAdd();
269
- return () => onToastRemove();
270
- }, [onToastAdd, onToastRemove]);
271
- if (!context.viewport)
272
- return null;
273
- return <>
274
- <ToastAnnounce
275
- __scopeToast={__scopeToast}
276
- role="status"
277
- aria-live={type === "foreground" ? "assertive" : "polite"}
278
- aria-atomic
279
- >{props.children}</ToastAnnounce>
280
- <ToastInteractiveProvider
281
- scope={__scopeToast}
282
- isInteractive
283
- onClose={handleClose}
284
- >{ReactDOM.createPortal(
285
- <div />,
286
- // <Collection.ItemSlot scope={__scopeToast}>
287
- // <DismissableLayer.Root
288
- // asChild
289
- // onEscapeKeyDown={composeEventHandlers(onEscapeKeyDown, () => {
290
- // if (!context.isFocusedToastEscapeKeyDownRef.current) handleClose()
291
- // context.isFocusedToastEscapeKeyDownRef.current = false
292
- // })}
293
- // >
294
- // <Primitive.li
295
- // // Ensure toasts are announced as status list or status when focused
296
- // role="status"
297
- // aria-live="off"
298
- // aria-atomic
299
- // tabIndex={0}
300
- // data-state={open ? 'open' : 'closed'}
301
- // data-swipe-direction={context.swipeDirection}
302
- // {...toastProps}
303
- // ref={composedRefs}
304
- // style={{ userSelect: 'none', touchAction: 'none', ...props.style }}
305
- // onKeyDown={composeEventHandlers(props.onKeyDown, (event) => {
306
- // if (event.key !== 'Escape') return
307
- // onEscapeKeyDown?.(event.nativeEvent)
308
- // if (!event.nativeEvent.defaultPrevented) {
309
- // context.isFocusedToastEscapeKeyDownRef.current = true
310
- // handleClose()
311
- // }
312
- // })}
313
- // onPointerDown={composeEventHandlers(props.onPointerDown, (event) => {
314
- // if (event.button !== 0) return
315
- // pointerStartRef.current = { x: event.clientX, y: event.clientY }
316
- // })}
317
- // onPointerMove={composeEventHandlers(props.onPointerMove, (event) => {
318
- // if (!pointerStartRef.current) return
319
- // const x = event.clientX - pointerStartRef.current.x
320
- // const y = event.clientY - pointerStartRef.current.y
321
- // const hasSwipeMoveStarted = Boolean(swipeDeltaRef.current)
322
- // const isHorizontalSwipe = ['left', 'right'].includes(context.swipeDirection)
323
- // const clamp = ['left', 'up'].includes(context.swipeDirection)
324
- // ? Math.min
325
- // : Math.max
326
- // const clampedX = isHorizontalSwipe ? clamp(0, x) : 0
327
- // const clampedY = !isHorizontalSwipe ? clamp(0, y) : 0
328
- // const moveStartBuffer = event.pointerType === 'touch' ? 10 : 2
329
- // const delta = { x: clampedX, y: clampedY }
330
- // const eventDetail = { originalEvent: event, delta }
331
- // if (hasSwipeMoveStarted) {
332
- // swipeDeltaRef.current = delta
333
- // handleAndDispatchCustomEvent(TOAST_SWIPE_MOVE, onSwipeMove, eventDetail, {
334
- // discrete: false,
335
- // })
336
- // } else if (isDeltaInDirection(delta, context.swipeDirection, moveStartBuffer)) {
337
- // swipeDeltaRef.current = delta
338
- // handleAndDispatchCustomEvent(TOAST_SWIPE_START, onSwipeStart, eventDetail, {
339
- // discrete: false,
340
- // })
341
- // ;(event.target as HTMLElement).setPointerCapture(event.pointerId)
342
- // } else if (Math.abs(x) > moveStartBuffer || Math.abs(y) > moveStartBuffer) {
343
- // // User is swiping in wrong direction so we disable swipe gesture
344
- // // for the current pointer down interaction
345
- // pointerStartRef.current = null
346
- // }
347
- // })}
348
- // onPointerUp={composeEventHandlers(props.onPointerUp, (event) => {
349
- // const delta = swipeDeltaRef.current
350
- // ;(event.target as HTMLElement).releasePointerCapture(event.pointerId)
351
- // swipeDeltaRef.current = null
352
- // pointerStartRef.current = null
353
- // if (delta) {
354
- // const toast = event.currentTarget
355
- // const eventDetail = { originalEvent: event, delta }
356
- // if (isDeltaInDirection(delta, context.swipeDirection, context.swipeThreshold)) {
357
- // handleAndDispatchCustomEvent(TOAST_SWIPE_END, onSwipeEnd, eventDetail, {
358
- // discrete: true,
359
- // })
360
- // } else {
361
- // handleAndDispatchCustomEvent(TOAST_SWIPE_CANCEL, onSwipeCancel, eventDetail, {
362
- // discrete: true,
363
- // })
364
- // }
365
- // // Prevent click event from triggering on items within the toast when
366
- // // pointer up is part of a swipe gesture
367
- // toast.addEventListener('click', (event) => event.preventDefault(), {
368
- // once: true,
369
- // })
370
- // }
371
- // })}
372
- // />
373
- // </DismissableLayer.Root>,
374
- // </Collection.ItemSlot>,
375
- context.viewport
376
- )}</ToastInteractiveProvider>
377
- </>;
378
- }
379
- );
380
- ToastImpl.propTypes = {
381
- type(props) {
382
- if (props.type && !["foreground", "background"].includes(props.type)) {
383
- const error = `Invalid prop \`type\` supplied to \`${TOAST_NAME}\`. Expected \`foreground | background\`.`;
384
- return new Error(error);
385
35
  }
386
- return null;
36
+ },
37
+ defaultVariants: {
38
+ unstyled: false
387
39
  }
388
- };
389
- const ToastAnnounce = (props) => {
390
- const { __scopeToast, children, ...announceProps } = props;
391
- const context = useToastProviderContext(TOAST_NAME, __scopeToast);
392
- const [renderAnnounceText, setRenderAnnounceText] = React.useState(false);
393
- const [isAnnounced, setIsAnnounced] = React.useState(false);
394
- const [fragment, setFragment] = React.useState();
395
- const [rootFragmentNode, setRootFragmentNode] = React.useState(null);
396
- const announceTextContent = React.useMemo(() => {
397
- return rootFragmentNode ? getAnnounceTextContent(rootFragmentNode) : null;
398
- }, [rootFragmentNode]);
399
- useIsomorphicLayoutEffect(() => {
400
- setFragment(new DocumentFragment());
401
- }, []);
402
- useNextFrame(() => setRenderAnnounceText(true));
403
- React.useEffect(() => {
404
- const timer = window.setTimeout(() => setIsAnnounced(true), 1e3);
405
- return () => window.clearTimeout(timer);
406
- }, []);
407
- return isAnnounced ? null : <>
408
- {fragment && // @ts-ignore
409
- <Portal container={fragment} ref={setRootFragmentNode}>
410
- {context.label}
411
- {" "}
412
- {children}
413
- </Portal>}
414
- <Portal asChild><VisuallyHidden {...announceProps}>{renderAnnounceText && announceTextContent}</VisuallyHidden></Portal>
415
- </>;
416
- };
417
- const TITLE_NAME = "ToastTitle";
40
+ });
418
41
  const ToastTitle = React.forwardRef(
419
42
  (props, forwardedRef) => {
420
43
  const { __scopeToast, ...titleProps } = props;
421
- return <YStack {...titleProps} ref={forwardedRef} />;
44
+ return <ToastTitleFrame {...titleProps} ref={forwardedRef} />;
422
45
  }
423
46
  );
424
47
  ToastTitle.displayName = TITLE_NAME;
425
48
  const DESCRIPTION_NAME = "ToastDescription";
426
- const ToastDescription = React.forwardRef((props, forwardedRef) => {
427
- const { __scopeToast, ...descriptionProps } = props;
428
- return <YStack {...descriptionProps} ref={forwardedRef} />;
49
+ const ToastDescriptionFrame = styled(SizableText, {
50
+ name: DESCRIPTION_NAME,
51
+ color: "$color11",
52
+ variants: {
53
+ unstyled: {
54
+ false: {
55
+ size: "$1"
56
+ }
57
+ }
58
+ },
59
+ defaultVariants: {
60
+ unstyled: false
61
+ }
429
62
  });
63
+ const ToastDescription = React.forwardRef(
64
+ (props, forwardedRef) => {
65
+ const { __scopeToast, ...descriptionProps } = props;
66
+ return <ToastDescriptionFrame {...descriptionProps} ref={forwardedRef} />;
67
+ }
68
+ );
430
69
  ToastDescription.displayName = DESCRIPTION_NAME;
431
70
  const ACTION_NAME = "ToastAction";
432
71
  const ToastAction = React.forwardRef(
433
72
  (props, forwardedRef) => {
434
73
  const { altText, ...actionProps } = props;
435
- const context = useToastInteractiveContext(ACTION_NAME, props.__scopeToast);
436
74
  if (!altText)
437
75
  return null;
438
- return context.isInteractive ? <ToastClose {...actionProps} ref={forwardedRef} /> : <span>{altText}</span>;
76
+ return <ToastAnnounceExclude altText={altText} asChild><ToastClose {...actionProps} ref={forwardedRef} /></ToastAnnounceExclude>;
439
77
  }
440
78
  );
441
79
  ToastAction.propTypes = {
@@ -448,115 +86,65 @@ ToastAction.propTypes = {
448
86
  };
449
87
  ToastAction.displayName = ACTION_NAME;
450
88
  const CLOSE_NAME = "ToastClose";
89
+ const ToastCloseFrame = styled(ThemeableStack, {
90
+ name: CLOSE_NAME,
91
+ tag: "button"
92
+ });
451
93
  const ToastClose = React.forwardRef(
452
94
  (props, forwardedRef) => {
453
95
  const { __scopeToast, ...closeProps } = props;
454
96
  const interactiveContext = useToastInteractiveContext(CLOSE_NAME, __scopeToast);
455
- return interactiveContext.isInteractive ? <YStack
456
- tag="button"
97
+ return <ToastAnnounceExclude asChild><ToastCloseFrame
98
+ accessibilityLabel="Dialog Close"
457
99
  {...closeProps}
458
100
  ref={forwardedRef}
459
101
  onPress={composeEventHandlers(props.onPress, interactiveContext.onClose)}
460
- /> : null;
102
+ /></ToastAnnounceExclude>;
461
103
  }
462
104
  );
463
105
  ToastClose.displayName = CLOSE_NAME;
464
- function handleAndDispatchCustomEvent(name, handler, detail, { discrete }) {
465
- const currentTarget = detail.originalEvent.currentTarget;
466
- const event = new CustomEvent(name, { bubbles: true, cancelable: true, detail });
467
- if (handler)
468
- currentTarget.addEventListener(name, handler, { once: true });
469
- if (discrete) {
470
- } else {
471
- currentTarget.dispatchEvent(event);
472
- }
473
- }
474
- const isDeltaInDirection = (delta, direction, threshold = 0) => {
475
- const deltaX = Math.abs(delta.x);
476
- const deltaY = Math.abs(delta.y);
477
- const isDeltaX = deltaX > deltaY;
478
- if (direction === "left" || direction === "right") {
479
- return isDeltaX && deltaX > threshold;
480
- } else {
481
- return !isDeltaX && deltaY > threshold;
106
+ const ToastComponent = React.forwardRef(
107
+ ToastImplFrame.extractable((props, forwardedRef) => {
108
+ const { forceMount, open: openProp, defaultOpen, onOpenChange, ...toastProps } = props;
109
+ const [open, setOpen] = useControllableState({
110
+ prop: openProp,
111
+ defaultProp: defaultOpen ?? true,
112
+ onChange: onOpenChange
113
+ });
114
+ const id = useId();
115
+ const onPause = useEvent(props.onPause);
116
+ const onResume = useEvent(props.onResume);
117
+ if (!forceMount && !open)
118
+ return null;
119
+ return <ToastImpl
120
+ id={id}
121
+ open={open}
122
+ {...toastProps}
123
+ ref={forwardedRef}
124
+ onClose={() => setOpen(false)}
125
+ onPause={onPause}
126
+ onResume={onResume}
127
+ onSwipeEnd={composeEventHandlers(props.onSwipeEnd, (event) => {
128
+ setOpen(false);
129
+ })}
130
+ />;
131
+ })
132
+ );
133
+ ToastComponent.displayName = TOAST_NAME;
134
+ const Toast = withStaticProperties(
135
+ themeable(ToastComponent, ToastImplFrame.staticConfig),
136
+ {
137
+ Title: ToastTitle,
138
+ Description: ToastDescription,
139
+ Action: ToastAction,
140
+ Close: ToastClose
482
141
  }
483
- };
484
- function useNextFrame(callback = () => {
485
- }) {
486
- const fn = useEvent(callback);
487
- useIsomorphicLayoutEffect(() => {
488
- let raf1 = 0;
489
- let raf2 = 0;
490
- raf1 = window.requestAnimationFrame(
491
- () => raf2 = window.requestAnimationFrame(fn)
492
- );
493
- return () => {
494
- window.cancelAnimationFrame(raf1);
495
- window.cancelAnimationFrame(raf2);
496
- };
497
- }, [fn]);
498
- }
499
- function getAnnounceTextContent(container) {
500
- const textContent = [];
501
- const childNodes = Array.from(container.childNodes);
502
- childNodes.forEach((node) => {
503
- if (node.nodeType === node.TEXT_NODE && node.textContent)
504
- textContent.push(node.textContent);
505
- if (isHTMLElement(node)) {
506
- const isHidden = node.ariaHidden || node.hidden || node.style.display === "none";
507
- if (!isHidden)
508
- textContent.push(...getAnnounceTextContent(node));
509
- }
510
- });
511
- return textContent;
512
- }
513
- function isHTMLElement(node) {
514
- return node.nodeType === node.ELEMENT_NODE;
515
- }
516
- function getTabbableCandidates(container) {
517
- const nodes = [];
518
- const walker = document.createTreeWalker(container, NodeFilter.SHOW_ELEMENT, {
519
- acceptNode: (node) => {
520
- const isHiddenInput = node.tagName === "INPUT" && node.type === "hidden";
521
- if (node.disabled || node.hidden || isHiddenInput)
522
- return NodeFilter.FILTER_SKIP;
523
- return node.tabIndex >= 0 ? NodeFilter.FILTER_ACCEPT : NodeFilter.FILTER_SKIP;
524
- }
525
- });
526
- while (walker.nextNode())
527
- nodes.push(walker.currentNode);
528
- return nodes;
529
- }
530
- function focusFirst(candidates) {
531
- const previouslyFocusedElement = document.activeElement;
532
- return candidates.some((candidate) => {
533
- if (candidate === previouslyFocusedElement)
534
- return true;
535
- candidate.focus();
536
- return document.activeElement !== previouslyFocusedElement;
537
- });
538
- }
539
- const Provider = ToastProvider;
540
- const Viewport = ToastViewport;
541
- const Root = Toast;
542
- const Title = ToastTitle;
543
- const Description = ToastDescription;
544
- const Action = ToastAction;
545
- const Close = ToastClose;
142
+ );
546
143
  export {
547
- Action,
548
- Close,
549
- Description,
550
- Provider,
551
- Root,
552
- Title,
553
144
  Toast,
554
- ToastAction,
555
- ToastClose,
556
- ToastDescription,
557
145
  ToastProvider,
558
- ToastTitle,
559
146
  ToastViewport,
560
- Viewport
147
+ createToast,
148
+ createToastScope
561
149
  };
562
150
  //# sourceMappingURL=Toast.mjs.map