@tamagui/toast 1.7.11 → 1.8.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/Toast.js +95 -543
- package/dist/cjs/Toast.js.map +3 -3
- package/dist/cjs/ToastAnnounce.js +93 -0
- package/dist/cjs/ToastAnnounce.js.map +7 -0
- package/dist/cjs/ToastImpl.js +354 -0
- package/dist/cjs/ToastImpl.js.map +7 -0
- package/dist/cjs/ToastProvider.js +109 -0
- package/dist/cjs/ToastProvider.js.map +7 -0
- package/dist/cjs/ToastViewport.js +307 -0
- package/dist/cjs/ToastViewport.js.map +7 -0
- package/dist/cjs/constants.js +29 -0
- package/dist/cjs/constants.js.map +7 -0
- package/dist/cjs/createNativeToast.js +49 -0
- package/dist/cjs/createNativeToast.js.map +7 -0
- package/dist/cjs/createNativeToast.native.js +37 -0
- package/dist/cjs/createNativeToast.native.js.map +7 -0
- package/dist/cjs/createToast.js +88 -0
- package/dist/cjs/createToast.js.map +7 -0
- package/dist/cjs/types.js +17 -0
- package/dist/cjs/types.js.map +7 -0
- package/dist/esm/Toast.js +101 -531
- package/dist/esm/Toast.js.map +3 -3
- package/dist/esm/Toast.mjs +101 -531
- package/dist/esm/Toast.mjs.map +3 -3
- package/dist/esm/ToastAnnounce.js +64 -0
- package/dist/esm/ToastAnnounce.js.map +7 -0
- package/dist/esm/ToastAnnounce.mjs +64 -0
- package/dist/esm/ToastAnnounce.mjs.map +7 -0
- package/dist/esm/ToastImpl.js +330 -0
- package/dist/esm/ToastImpl.js.map +7 -0
- package/dist/esm/ToastImpl.mjs +330 -0
- package/dist/esm/ToastImpl.mjs.map +7 -0
- package/dist/esm/ToastProvider.js +70 -0
- package/dist/esm/ToastProvider.js.map +7 -0
- package/dist/esm/ToastProvider.mjs +70 -0
- package/dist/esm/ToastProvider.mjs.map +7 -0
- package/dist/esm/ToastViewport.js +274 -0
- package/dist/esm/ToastViewport.js.map +7 -0
- package/dist/esm/ToastViewport.mjs +274 -0
- package/dist/esm/ToastViewport.mjs.map +7 -0
- package/dist/esm/constants.js +5 -0
- package/dist/esm/constants.js.map +7 -0
- package/dist/esm/constants.mjs +5 -0
- package/dist/esm/constants.mjs.map +7 -0
- package/dist/esm/createNativeToast.js +25 -0
- package/dist/esm/createNativeToast.js.map +7 -0
- package/dist/esm/createNativeToast.mjs +25 -0
- package/dist/esm/createNativeToast.mjs.map +7 -0
- package/dist/esm/createNativeToast.native.js +13 -0
- package/dist/esm/createNativeToast.native.js.map +7 -0
- package/dist/esm/createNativeToast.native.mjs +13 -0
- package/dist/esm/createNativeToast.native.mjs.map +7 -0
- package/dist/esm/createToast.js +54 -0
- package/dist/esm/createToast.js.map +7 -0
- package/dist/esm/createToast.mjs +54 -0
- package/dist/esm/createToast.mjs.map +7 -0
- package/dist/esm/types.js +1 -0
- package/dist/esm/types.js.map +7 -0
- package/dist/esm/types.mjs +1 -0
- package/dist/esm/types.mjs.map +7 -0
- package/dist/jsx/Toast.js +97 -509
- package/dist/jsx/Toast.js.map +3 -3
- package/dist/jsx/Toast.mjs +97 -509
- package/dist/jsx/Toast.mjs.map +3 -3
- package/dist/jsx/ToastAnnounce.js +60 -0
- package/dist/jsx/ToastAnnounce.js.map +7 -0
- package/dist/jsx/ToastAnnounce.mjs +60 -0
- package/dist/jsx/ToastAnnounce.mjs.map +7 -0
- package/dist/jsx/ToastImpl.js +309 -0
- package/dist/jsx/ToastImpl.js.map +7 -0
- package/dist/jsx/ToastImpl.mjs +309 -0
- package/dist/jsx/ToastImpl.mjs.map +7 -0
- package/dist/jsx/ToastProvider.js +65 -0
- package/dist/jsx/ToastProvider.js.map +7 -0
- package/dist/jsx/ToastProvider.mjs +65 -0
- package/dist/jsx/ToastProvider.mjs.map +7 -0
- package/dist/jsx/ToastViewport.js +254 -0
- package/dist/jsx/ToastViewport.js.map +7 -0
- package/dist/jsx/ToastViewport.mjs +254 -0
- package/dist/jsx/ToastViewport.mjs.map +7 -0
- package/dist/jsx/constants.js +5 -0
- package/dist/jsx/constants.js.map +7 -0
- package/dist/jsx/constants.mjs +5 -0
- package/dist/jsx/constants.mjs.map +7 -0
- package/dist/jsx/createNativeToast.js +25 -0
- package/dist/jsx/createNativeToast.js.map +7 -0
- package/dist/jsx/createNativeToast.mjs +25 -0
- package/dist/jsx/createNativeToast.mjs.map +7 -0
- package/dist/jsx/createNativeToast.native.js +13 -0
- package/dist/jsx/createNativeToast.native.js.map +7 -0
- package/dist/jsx/createNativeToast.native.mjs +13 -0
- package/dist/jsx/createNativeToast.native.mjs.map +7 -0
- package/dist/jsx/createToast.js +49 -0
- package/dist/jsx/createToast.js.map +7 -0
- package/dist/jsx/createToast.mjs +49 -0
- package/dist/jsx/createToast.mjs.map +7 -0
- package/dist/jsx/types.js +1 -0
- package/dist/jsx/types.js.map +7 -0
- package/dist/jsx/types.mjs +1 -0
- package/dist/jsx/types.mjs.map +7 -0
- package/package.json +14 -13
- package/src/Toast.tsx +139 -908
- package/src/ToastAnnounce.tsx +97 -0
- package/src/ToastImpl.tsx +439 -0
- package/src/ToastProvider.tsx +134 -0
- package/src/ToastViewport.tsx +354 -0
- package/src/constants.ts +1 -0
- package/src/createNativeToast.native.tsx +16 -0
- package/src/createNativeToast.tsx +25 -0
- package/src/createToast.tsx +93 -0
- package/src/types.ts +21 -0
- package/types/Toast.d.ts +429 -106
- package/types/Toast.d.ts.map +1 -1
- package/types/ToastAnnounce.d.ts +35 -0
- package/types/ToastAnnounce.d.ts.map +1 -0
- package/types/ToastImpl.d.ts +267 -0
- package/types/ToastImpl.d.ts.map +1 -0
- package/types/ToastProvider.d.ts +80 -0
- package/types/ToastProvider.d.ts.map +1 -0
- package/types/ToastViewport.d.ts +115 -0
- package/types/ToastViewport.d.ts.map +1 -0
- package/types/constants.d.ts +2 -0
- package/types/constants.d.ts.map +1 -0
- package/types/createNativeToast.d.ts +3 -0
- package/types/createNativeToast.d.ts.map +1 -0
- package/types/createNativeToast.native.d.ts +3 -0
- package/types/createNativeToast.native.d.ts.map +1 -0
- package/types/createToast.d.ts +42 -0
- package/types/createToast.d.ts.map +1 -0
- package/types/types.d.ts +17 -0
- package/types/types.d.ts.map +1 -0
package/dist/jsx/Toast.mjs
CHANGED
|
@@ -1,441 +1,79 @@
|
|
|
1
|
-
import { useComposedRefs } from "@tamagui/compose-refs";
|
|
2
1
|
import {
|
|
3
2
|
composeEventHandlers,
|
|
4
|
-
|
|
3
|
+
styled,
|
|
4
|
+
themeable,
|
|
5
5
|
useEvent,
|
|
6
|
-
|
|
6
|
+
useId,
|
|
7
|
+
withStaticProperties
|
|
7
8
|
} from "@tamagui/core";
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
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
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
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
|
-
|
|
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 <
|
|
44
|
+
return <ToastTitleFrame {...titleProps} ref={forwardedRef} />;
|
|
422
45
|
}
|
|
423
46
|
);
|
|
424
47
|
ToastTitle.displayName = TITLE_NAME;
|
|
425
48
|
const DESCRIPTION_NAME = "ToastDescription";
|
|
426
|
-
const
|
|
427
|
-
|
|
428
|
-
|
|
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
|
|
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
|
|
456
|
-
|
|
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
|
-
|
|
102
|
+
/></ToastAnnounceExclude>;
|
|
461
103
|
}
|
|
462
104
|
);
|
|
463
105
|
ToastClose.displayName = CLOSE_NAME;
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
const
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
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
|
-
|
|
147
|
+
createToast,
|
|
148
|
+
createToastScope
|
|
561
149
|
};
|
|
562
150
|
//# sourceMappingURL=Toast.mjs.map
|