@fluentui/react-toast 9.0.6 → 9.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.
Files changed (27) hide show
  1. package/CHANGELOG.json +58 -1
  2. package/CHANGELOG.md +18 -2
  3. package/lib/components/ToastContainer/useToastContainer.js +28 -11
  4. package/lib/components/ToastContainer/useToastContainer.js.map +1 -1
  5. package/lib/components/ToastContainer/useToastContainerStyles.styles.js +2 -2
  6. package/lib/components/ToastContainer/useToastContainerStyles.styles.js.map +1 -1
  7. package/lib/components/Toaster/useToastAnnounce.js +47 -0
  8. package/lib/components/Toaster/useToastAnnounce.js.map +1 -0
  9. package/lib/components/Toaster/useToaster.js +32 -30
  10. package/lib/components/Toaster/useToaster.js.map +1 -1
  11. package/lib/components/Toaster/useToasterFocusManagement.js +85 -0
  12. package/lib/components/Toaster/useToasterFocusManagement.js.map +1 -0
  13. package/lib/state/useToaster.js +24 -6
  14. package/lib/state/useToaster.js.map +1 -1
  15. package/lib-commonjs/components/ToastContainer/useToastContainer.js +28 -11
  16. package/lib-commonjs/components/ToastContainer/useToastContainer.js.map +1 -1
  17. package/lib-commonjs/components/ToastContainer/useToastContainerStyles.styles.js +3 -3
  18. package/lib-commonjs/components/ToastContainer/useToastContainerStyles.styles.js.map +1 -1
  19. package/lib-commonjs/components/Toaster/useToastAnnounce.js +50 -0
  20. package/lib-commonjs/components/Toaster/useToastAnnounce.js.map +1 -0
  21. package/lib-commonjs/components/Toaster/useToaster.js +31 -29
  22. package/lib-commonjs/components/Toaster/useToaster.js.map +1 -1
  23. package/lib-commonjs/components/Toaster/useToasterFocusManagement.js +92 -0
  24. package/lib-commonjs/components/Toaster/useToasterFocusManagement.js.map +1 -0
  25. package/lib-commonjs/state/useToaster.js +24 -6
  26. package/lib-commonjs/state/useToaster.js.map +1 -1
  27. package/package.json +9 -8
package/CHANGELOG.json CHANGED
@@ -2,7 +2,64 @@
2
2
  "name": "@fluentui/react-toast",
3
3
  "entries": [
4
4
  {
5
- "date": "Tue, 01 Aug 2023 10:14:29 GMT",
5
+ "date": "Fri, 04 Aug 2023 08:48:23 GMT",
6
+ "tag": "@fluentui/react-toast_v9.1.0",
7
+ "version": "9.1.0",
8
+ "comments": {
9
+ "minor": [
10
+ {
11
+ "author": "lingfangao@hotmail.com",
12
+ "package": "@fluentui/react-toast",
13
+ "commit": "495a08579f2d16f082f2b18c299f1a647906b236",
14
+ "comment": "feat: Add extra keyboard behaviour for multi toast scenario"
15
+ },
16
+ {
17
+ "author": "beachball",
18
+ "package": "@fluentui/react-toast",
19
+ "comment": "Bump @fluentui/react-aria to v9.3.28",
20
+ "commit": "0bf7d9438c1d0ff90cd2b28bc4cceb4f807afbca"
21
+ },
22
+ {
23
+ "author": "beachball",
24
+ "package": "@fluentui/react-toast",
25
+ "comment": "Bump @fluentui/react-jsx-runtime to v9.0.0-alpha.13",
26
+ "commit": "0bf7d9438c1d0ff90cd2b28bc4cceb4f807afbca"
27
+ },
28
+ {
29
+ "author": "beachball",
30
+ "package": "@fluentui/react-toast",
31
+ "comment": "Bump @fluentui/react-portal to v9.3.5",
32
+ "commit": "0bf7d9438c1d0ff90cd2b28bc4cceb4f807afbca"
33
+ },
34
+ {
35
+ "author": "beachball",
36
+ "package": "@fluentui/react-toast",
37
+ "comment": "Bump @fluentui/react-shared-contexts to v9.7.1",
38
+ "commit": "0bf7d9438c1d0ff90cd2b28bc4cceb4f807afbca"
39
+ },
40
+ {
41
+ "author": "beachball",
42
+ "package": "@fluentui/react-toast",
43
+ "comment": "Bump @fluentui/react-tabster to v9.12.0",
44
+ "commit": "0bf7d9438c1d0ff90cd2b28bc4cceb4f807afbca"
45
+ },
46
+ {
47
+ "author": "beachball",
48
+ "package": "@fluentui/react-toast",
49
+ "comment": "Bump @fluentui/react-theme to v9.1.10",
50
+ "commit": "0bf7d9438c1d0ff90cd2b28bc4cceb4f807afbca"
51
+ },
52
+ {
53
+ "author": "beachball",
54
+ "package": "@fluentui/react-toast",
55
+ "comment": "Bump @fluentui/react-utilities to v9.11.0",
56
+ "commit": "0bf7d9438c1d0ff90cd2b28bc4cceb4f807afbca"
57
+ }
58
+ ]
59
+ }
60
+ },
61
+ {
62
+ "date": "Tue, 01 Aug 2023 10:17:21 GMT",
6
63
  "tag": "@fluentui/react-toast_v9.0.6",
7
64
  "version": "9.0.6",
8
65
  "comments": {
package/CHANGELOG.md CHANGED
@@ -1,12 +1,28 @@
1
1
  # Change Log - @fluentui/react-toast
2
2
 
3
- This log was last generated on Tue, 01 Aug 2023 10:14:29 GMT and should not be manually modified.
3
+ This log was last generated on Fri, 04 Aug 2023 08:48:23 GMT and should not be manually modified.
4
4
 
5
5
  <!-- Start content -->
6
6
 
7
+ ## [9.1.0](https://github.com/microsoft/fluentui/tree/@fluentui/react-toast_v9.1.0)
8
+
9
+ Fri, 04 Aug 2023 08:48:23 GMT
10
+ [Compare changes](https://github.com/microsoft/fluentui/compare/@fluentui/react-toast_v9.0.6..@fluentui/react-toast_v9.1.0)
11
+
12
+ ### Minor changes
13
+
14
+ - feat: Add extra keyboard behaviour for multi toast scenario ([PR #28660](https://github.com/microsoft/fluentui/pull/28660) by lingfangao@hotmail.com)
15
+ - Bump @fluentui/react-aria to v9.3.28 ([commit](https://github.com/microsoft/fluentui/commit/0bf7d9438c1d0ff90cd2b28bc4cceb4f807afbca) by beachball)
16
+ - Bump @fluentui/react-jsx-runtime to v9.0.0-alpha.13 ([commit](https://github.com/microsoft/fluentui/commit/0bf7d9438c1d0ff90cd2b28bc4cceb4f807afbca) by beachball)
17
+ - Bump @fluentui/react-portal to v9.3.5 ([commit](https://github.com/microsoft/fluentui/commit/0bf7d9438c1d0ff90cd2b28bc4cceb4f807afbca) by beachball)
18
+ - Bump @fluentui/react-shared-contexts to v9.7.1 ([commit](https://github.com/microsoft/fluentui/commit/0bf7d9438c1d0ff90cd2b28bc4cceb4f807afbca) by beachball)
19
+ - Bump @fluentui/react-tabster to v9.12.0 ([commit](https://github.com/microsoft/fluentui/commit/0bf7d9438c1d0ff90cd2b28bc4cceb4f807afbca) by beachball)
20
+ - Bump @fluentui/react-theme to v9.1.10 ([commit](https://github.com/microsoft/fluentui/commit/0bf7d9438c1d0ff90cd2b28bc4cceb4f807afbca) by beachball)
21
+ - Bump @fluentui/react-utilities to v9.11.0 ([commit](https://github.com/microsoft/fluentui/commit/0bf7d9438c1d0ff90cd2b28bc4cceb4f807afbca) by beachball)
22
+
7
23
  ## [9.0.6](https://github.com/microsoft/fluentui/tree/@fluentui/react-toast_v9.0.6)
8
24
 
9
- Tue, 01 Aug 2023 10:14:29 GMT
25
+ Tue, 01 Aug 2023 10:17:21 GMT
10
26
  [Compare changes](https://github.com/microsoft/fluentui/compare/@fluentui/react-toast_v9.0.5..@fluentui/react-toast_v9.0.6)
11
27
 
12
28
  ### Patches
@@ -1,8 +1,9 @@
1
1
  import * as React from 'react';
2
2
  import { getNativeElementProps, useMergedRefs, useEventCallback, resolveShorthand, useId } from '@fluentui/react-utilities';
3
3
  import { useFluent_unstable } from '@fluentui/react-shared-contexts';
4
+ import { Delete, Tab } from '@fluentui/keyboard-keys';
5
+ import { useFocusableGroup, useFocusFinders } from '@fluentui/react-tabster';
4
6
  import { Timer } from '../Timer/Timer';
5
- import { useFocusFinders } from '@fluentui/react-tabster';
6
7
  const intentPolitenessMap = {
7
8
  success: 'assertive',
8
9
  warning: 'assertive',
@@ -26,6 +27,16 @@ const intentPolitenessMap = {
26
27
  const [running, setRunning] = React.useState(false);
27
28
  const imperativePauseRef = React.useRef(false);
28
29
  const focusedToastBeforeClose = React.useRef(false);
30
+ const focusableGroupAttribute = useFocusableGroup({
31
+ tabBehavior: 'limited-trap-focus',
32
+ // Users should only use Tab to focus into the toast
33
+ // Escape is already reserved to dismiss all toasts
34
+ ignoreDefaultKeydown: {
35
+ Tab: true,
36
+ Escape: true,
37
+ Enter: true
38
+ }
39
+ });
29
40
  const close = useEventCallback(()=>{
30
41
  var _toastRef_current;
31
42
  const activeElement = targetDocument === null || targetDocument === void 0 ? void 0 : targetDocument.activeElement;
@@ -57,18 +68,12 @@ const intentPolitenessMap = {
57
68
  setRunning(true);
58
69
  }
59
70
  });
60
- const { findFirstFocusable } = useFocusFinders();
61
71
  React.useImperativeHandle(imperativeRef, ()=>({
62
72
  focus: ()=>{
63
73
  if (!toastRef.current) {
64
74
  return;
65
75
  }
66
- const firstFocusable = findFirstFocusable(toastRef.current);
67
- if (firstFocusable) {
68
- firstFocusable.focus();
69
- } else {
70
- toastRef.current.focus();
71
- }
76
+ toastRef.current.focus();
72
77
  },
73
78
  play: ()=>{
74
79
  imperativePauseRef.current = false;
@@ -141,12 +146,23 @@ const intentPolitenessMap = {
141
146
  play();
142
147
  userRootSlot === null || userRootSlot === void 0 ? void 0 : (_userRootSlot_onMouseEnter = userRootSlot.onMouseEnter) === null || _userRootSlot_onMouseEnter === void 0 ? void 0 : _userRootSlot_onMouseEnter.call(userRootSlot, e);
143
148
  });
149
+ const { findFirstFocusable , findLastFocusable } = useFocusFinders();
144
150
  const onKeyDown = useEventCallback((e)=>{
145
151
  var _userRootSlot_onKeyDown;
146
- if (e.key === 'Escape') {
152
+ if (e.key === Delete) {
147
153
  e.preventDefault();
148
154
  close();
149
155
  }
156
+ if (e.key === Tab && e.currentTarget === e.target) {
157
+ e.preventDefault();
158
+ if (e.shiftKey) {
159
+ var _findLastFocusable;
160
+ (_findLastFocusable = findLastFocusable(e.currentTarget)) === null || _findLastFocusable === void 0 ? void 0 : _findLastFocusable.focus();
161
+ } else {
162
+ var _findFirstFocusable;
163
+ (_findFirstFocusable = findFirstFocusable(e.currentTarget)) === null || _findFirstFocusable === void 0 ? void 0 : _findFirstFocusable.focus();
164
+ }
165
+ }
150
166
  userRootSlot === null || userRootSlot === void 0 ? void 0 : (_userRootSlot_onKeyDown = userRootSlot.onKeyDown) === null || _userRootSlot_onKeyDown === void 0 ? void 0 : _userRootSlot_onKeyDown.call(userRootSlot, e);
151
167
  });
152
168
  React.useEffect(()=>{
@@ -193,12 +209,13 @@ const intentPolitenessMap = {
193
209
  root: getNativeElementProps('div', {
194
210
  ref: useMergedRefs(ref, toastRef, toastAnimationRef),
195
211
  children,
196
- tabIndex: -1,
197
- role: 'group',
212
+ tabIndex: 0,
213
+ role: 'listitem',
198
214
  'aria-labelledby': titleId,
199
215
  'aria-describedby': bodyId,
200
216
  ...rest,
201
217
  ...userRootSlot,
218
+ ...focusableGroupAttribute,
202
219
  onMouseEnter,
203
220
  onMouseLeave,
204
221
  onKeyDown
@@ -1 +1 @@
1
- {"version":3,"sources":["useToastContainer.ts"],"sourcesContent":["import * as React from 'react';\nimport {\n getNativeElementProps,\n useMergedRefs,\n ExtractSlotProps,\n Slot,\n useEventCallback,\n resolveShorthand,\n useId,\n} from '@fluentui/react-utilities';\nimport { useFluent_unstable } from '@fluentui/react-shared-contexts';\nimport { ToastStatus } from '../../state';\nimport type { ToastContainerProps, ToastContainerState } from './ToastContainer.types';\nimport { Timer, TimerProps } from '../Timer/Timer';\nimport { useFocusFinders } from '@fluentui/react-tabster';\n\nconst intentPolitenessMap = {\n success: 'assertive',\n warning: 'assertive',\n error: 'assertive',\n info: 'polite',\n} as const;\n\n/**\n * Create the state required to render ToastContainer.\n *\n * The returned state can be modified with hooks such as useToastContainerStyles_unstable,\n * before being passed to renderToastContainer_unstable.\n *\n * @param props - props from this instance of ToastContainer\n * @param ref - reference to root HTMLElement of ToastContainer\n */\nexport const useToastContainer_unstable = (\n props: ToastContainerProps,\n ref: React.Ref<HTMLElement>,\n): ToastContainerState => {\n const {\n visible,\n children,\n close: closeProp,\n remove,\n updateId,\n announce,\n data,\n timeout: timerTimeout,\n politeness: desiredPoliteness,\n intent = 'info',\n pauseOnHover,\n pauseOnWindowBlur,\n imperativeRef,\n tryRestoreFocus,\n ...rest\n } = props;\n const titleId = useId('toast-title');\n const bodyId = useId('toast-body');\n const toastRef = React.useRef<HTMLDivElement | null>(null);\n const { targetDocument } = useFluent_unstable();\n const [running, setRunning] = React.useState(false);\n const imperativePauseRef = React.useRef(false);\n const focusedToastBeforeClose = React.useRef(false);\n\n const close = useEventCallback(() => {\n const activeElement = targetDocument?.activeElement;\n if (activeElement && toastRef.current?.contains(activeElement)) {\n focusedToastBeforeClose.current = true;\n }\n\n closeProp();\n });\n const onStatusChange = useEventCallback((status: ToastStatus) => props.onStatusChange?.(null, { status, ...props }));\n const pause = useEventCallback(() => setRunning(false));\n const play = useEventCallback(() => {\n if (imperativePauseRef.current) {\n return;\n }\n const containsActive = !!toastRef.current?.contains(targetDocument?.activeElement ?? null);\n if (timerTimeout < 0) {\n setRunning(true);\n return;\n }\n\n if (!containsActive) {\n setRunning(true);\n }\n });\n\n const { findFirstFocusable } = useFocusFinders();\n\n React.useImperativeHandle(imperativeRef, () => ({\n focus: () => {\n if (!toastRef.current) {\n return;\n }\n\n const firstFocusable = findFirstFocusable(toastRef.current);\n if (firstFocusable) {\n firstFocusable.focus();\n } else {\n toastRef.current.focus();\n }\n },\n\n play: () => {\n imperativePauseRef.current = false;\n play();\n },\n pause: () => {\n imperativePauseRef.current = true;\n pause();\n },\n }));\n\n React.useEffect(() => {\n return () => onStatusChange('unmounted');\n }, [onStatusChange]);\n\n React.useEffect(() => {\n if (!targetDocument) {\n return;\n }\n\n if (pauseOnWindowBlur) {\n targetDocument.defaultView?.addEventListener('focus', play);\n targetDocument.defaultView?.addEventListener('blur', pause);\n return () => {\n targetDocument.defaultView?.removeEventListener('focus', play);\n targetDocument.defaultView?.removeEventListener('blur', pause);\n };\n }\n }, [targetDocument, pause, play, pauseOnWindowBlur]);\n\n // It's impossible to animate to height: auto in CSS, the actual pixel value must be known\n // Get the height of the toast before animation styles have been applied and set a CSS\n // variable with its height. The CSS variable will be used by the styles\n const onTransitionEntering = () => {\n if (!toastRef.current) {\n return;\n }\n\n const element = toastRef.current;\n element.style.setProperty('--fui-toast-height', `${element.scrollHeight}px`);\n };\n\n // Users never actually use ToastContainer as a JSX but imperatively through useToastContainerController\n const userRootSlot = (data as { root?: ExtractSlotProps<Slot<'div'>> }).root;\n\n // Using a ref callback here because addEventListener supports `once`\n const toastAnimationRef = React.useCallback(\n (el: HTMLDivElement | null) => {\n if (el && toastRef.current) {\n toastRef.current.addEventListener(\n 'animationend',\n () => {\n // start toast once it's fully animated in\n play();\n onStatusChange('visible');\n },\n { once: true },\n );\n }\n },\n [play, onStatusChange],\n );\n\n const onMouseEnter = useEventCallback((e: React.MouseEvent<HTMLDivElement>) => {\n pause();\n userRootSlot?.onMouseEnter?.(e);\n });\n\n const onMouseLeave = useEventCallback((e: React.MouseEvent<HTMLDivElement>) => {\n play();\n userRootSlot?.onMouseEnter?.(e);\n });\n\n const onKeyDown = useEventCallback((e: React.KeyboardEvent<HTMLDivElement>) => {\n if (e.key === 'Escape') {\n e.preventDefault();\n close();\n }\n\n userRootSlot?.onKeyDown?.(e);\n });\n\n React.useEffect(() => {\n if (!visible) {\n return;\n }\n\n const politeness = desiredPoliteness ?? intentPolitenessMap[intent];\n announce(toastRef.current?.textContent ?? '', { politeness });\n }, [announce, desiredPoliteness, toastRef, visible, updateId, intent]);\n\n React.useEffect(() => {\n return () => {\n if (focusedToastBeforeClose.current) {\n focusedToastBeforeClose.current = false;\n tryRestoreFocus();\n }\n };\n }, [tryRestoreFocus]);\n\n return {\n components: {\n timer: Timer,\n root: 'div',\n },\n timer: resolveShorthand<TimerProps>(\n { key: updateId, onTimeout: close, running, timeout: timerTimeout ?? -1 },\n { required: true },\n ),\n root: getNativeElementProps('div', {\n ref: useMergedRefs(ref, toastRef, toastAnimationRef),\n children,\n tabIndex: -1,\n role: 'group',\n 'aria-labelledby': titleId,\n 'aria-describedby': bodyId,\n ...rest,\n ...userRootSlot,\n onMouseEnter,\n onMouseLeave,\n onKeyDown,\n }),\n timerTimeout,\n transitionTimeout: 500,\n running,\n visible,\n remove,\n close,\n onTransitionEntering,\n updateId,\n nodeRef: toastRef,\n intent,\n titleId,\n bodyId,\n };\n};\n"],"names":["React","getNativeElementProps","useMergedRefs","useEventCallback","resolveShorthand","useId","useFluent_unstable","Timer","useFocusFinders","intentPolitenessMap","success","warning","error","info","useToastContainer_unstable","props","ref","visible","children","close","closeProp","remove","updateId","announce","data","timeout","timerTimeout","politeness","desiredPoliteness","intent","pauseOnHover","pauseOnWindowBlur","imperativeRef","tryRestoreFocus","rest","titleId","bodyId","toastRef","useRef","targetDocument","running","setRunning","useState","imperativePauseRef","focusedToastBeforeClose","activeElement","current","contains","onStatusChange","status","pause","play","containsActive","findFirstFocusable","useImperativeHandle","focus","firstFocusable","useEffect","defaultView","addEventListener","removeEventListener","onTransitionEntering","element","style","setProperty","scrollHeight","userRootSlot","root","toastAnimationRef","useCallback","el","once","onMouseEnter","e","onMouseLeave","onKeyDown","key","preventDefault","textContent","components","timer","onTimeout","required","tabIndex","role","transitionTimeout","nodeRef"],"mappings":"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"}
1
+ {"version":3,"sources":["useToastContainer.ts"],"sourcesContent":["import * as React from 'react';\nimport {\n getNativeElementProps,\n useMergedRefs,\n ExtractSlotProps,\n Slot,\n useEventCallback,\n resolveShorthand,\n useId,\n} from '@fluentui/react-utilities';\nimport { useFluent_unstable } from '@fluentui/react-shared-contexts';\nimport { Delete, Tab } from '@fluentui/keyboard-keys';\nimport { useFocusableGroup, useFocusFinders } from '@fluentui/react-tabster';\nimport { ToastStatus } from '../../state';\nimport type { ToastContainerProps, ToastContainerState } from './ToastContainer.types';\nimport { Timer, TimerProps } from '../Timer/Timer';\n\nconst intentPolitenessMap = {\n success: 'assertive',\n warning: 'assertive',\n error: 'assertive',\n info: 'polite',\n} as const;\n\n/**\n * Create the state required to render ToastContainer.\n *\n * The returned state can be modified with hooks such as useToastContainerStyles_unstable,\n * before being passed to renderToastContainer_unstable.\n *\n * @param props - props from this instance of ToastContainer\n * @param ref - reference to root HTMLElement of ToastContainer\n */\nexport const useToastContainer_unstable = (\n props: ToastContainerProps,\n ref: React.Ref<HTMLElement>,\n): ToastContainerState => {\n const {\n visible,\n children,\n close: closeProp,\n remove,\n updateId,\n announce,\n data,\n timeout: timerTimeout,\n politeness: desiredPoliteness,\n intent = 'info',\n pauseOnHover,\n pauseOnWindowBlur,\n imperativeRef,\n tryRestoreFocus,\n ...rest\n } = props;\n const titleId = useId('toast-title');\n const bodyId = useId('toast-body');\n const toastRef = React.useRef<HTMLDivElement | null>(null);\n const { targetDocument } = useFluent_unstable();\n const [running, setRunning] = React.useState(false);\n const imperativePauseRef = React.useRef(false);\n const focusedToastBeforeClose = React.useRef(false);\n const focusableGroupAttribute = useFocusableGroup({\n tabBehavior: 'limited-trap-focus',\n // Users should only use Tab to focus into the toast\n // Escape is already reserved to dismiss all toasts\n ignoreDefaultKeydown: { Tab: true, Escape: true, Enter: true },\n });\n\n const close = useEventCallback(() => {\n const activeElement = targetDocument?.activeElement;\n if (activeElement && toastRef.current?.contains(activeElement)) {\n focusedToastBeforeClose.current = true;\n }\n\n closeProp();\n });\n const onStatusChange = useEventCallback((status: ToastStatus) => props.onStatusChange?.(null, { status, ...props }));\n const pause = useEventCallback(() => setRunning(false));\n const play = useEventCallback(() => {\n if (imperativePauseRef.current) {\n return;\n }\n const containsActive = !!toastRef.current?.contains(targetDocument?.activeElement ?? null);\n if (timerTimeout < 0) {\n setRunning(true);\n return;\n }\n\n if (!containsActive) {\n setRunning(true);\n }\n });\n\n React.useImperativeHandle(imperativeRef, () => ({\n focus: () => {\n if (!toastRef.current) {\n return;\n }\n\n toastRef.current.focus();\n },\n\n play: () => {\n imperativePauseRef.current = false;\n play();\n },\n pause: () => {\n imperativePauseRef.current = true;\n pause();\n },\n }));\n\n React.useEffect(() => {\n return () => onStatusChange('unmounted');\n }, [onStatusChange]);\n\n React.useEffect(() => {\n if (!targetDocument) {\n return;\n }\n\n if (pauseOnWindowBlur) {\n targetDocument.defaultView?.addEventListener('focus', play);\n targetDocument.defaultView?.addEventListener('blur', pause);\n return () => {\n targetDocument.defaultView?.removeEventListener('focus', play);\n targetDocument.defaultView?.removeEventListener('blur', pause);\n };\n }\n }, [targetDocument, pause, play, pauseOnWindowBlur]);\n\n // It's impossible to animate to height: auto in CSS, the actual pixel value must be known\n // Get the height of the toast before animation styles have been applied and set a CSS\n // variable with its height. The CSS variable will be used by the styles\n const onTransitionEntering = () => {\n if (!toastRef.current) {\n return;\n }\n\n const element = toastRef.current;\n element.style.setProperty('--fui-toast-height', `${element.scrollHeight}px`);\n };\n\n // Users never actually use ToastContainer as a JSX but imperatively through useToastContainerController\n const userRootSlot = (data as { root?: ExtractSlotProps<Slot<'div'>> }).root;\n\n // Using a ref callback here because addEventListener supports `once`\n const toastAnimationRef = React.useCallback(\n (el: HTMLDivElement | null) => {\n if (el && toastRef.current) {\n toastRef.current.addEventListener(\n 'animationend',\n () => {\n // start toast once it's fully animated in\n play();\n onStatusChange('visible');\n },\n { once: true },\n );\n }\n },\n [play, onStatusChange],\n );\n\n const onMouseEnter = useEventCallback((e: React.MouseEvent<HTMLDivElement>) => {\n pause();\n userRootSlot?.onMouseEnter?.(e);\n });\n\n const onMouseLeave = useEventCallback((e: React.MouseEvent<HTMLDivElement>) => {\n play();\n userRootSlot?.onMouseEnter?.(e);\n });\n\n const { findFirstFocusable, findLastFocusable } = useFocusFinders();\n const onKeyDown = useEventCallback((e: React.KeyboardEvent<HTMLDivElement>) => {\n if (e.key === Delete) {\n e.preventDefault();\n close();\n }\n\n if (e.key === Tab && e.currentTarget === e.target) {\n e.preventDefault();\n if (e.shiftKey) {\n findLastFocusable(e.currentTarget)?.focus();\n } else {\n findFirstFocusable(e.currentTarget)?.focus();\n }\n }\n\n userRootSlot?.onKeyDown?.(e);\n });\n\n React.useEffect(() => {\n if (!visible) {\n return;\n }\n\n const politeness = desiredPoliteness ?? intentPolitenessMap[intent];\n announce(toastRef.current?.textContent ?? '', { politeness });\n }, [announce, desiredPoliteness, toastRef, visible, updateId, intent]);\n\n React.useEffect(() => {\n return () => {\n if (focusedToastBeforeClose.current) {\n focusedToastBeforeClose.current = false;\n tryRestoreFocus();\n }\n };\n }, [tryRestoreFocus]);\n\n return {\n components: {\n timer: Timer,\n root: 'div',\n },\n timer: resolveShorthand<TimerProps>(\n { key: updateId, onTimeout: close, running, timeout: timerTimeout ?? -1 },\n { required: true },\n ),\n root: getNativeElementProps('div', {\n ref: useMergedRefs(ref, toastRef, toastAnimationRef),\n children,\n tabIndex: 0,\n role: 'listitem',\n 'aria-labelledby': titleId,\n 'aria-describedby': bodyId,\n ...rest,\n ...userRootSlot,\n ...focusableGroupAttribute,\n onMouseEnter,\n onMouseLeave,\n onKeyDown,\n }),\n timerTimeout,\n transitionTimeout: 500,\n running,\n visible,\n remove,\n close,\n onTransitionEntering,\n updateId,\n nodeRef: toastRef,\n intent,\n titleId,\n bodyId,\n };\n};\n"],"names":["React","getNativeElementProps","useMergedRefs","useEventCallback","resolveShorthand","useId","useFluent_unstable","Delete","Tab","useFocusableGroup","useFocusFinders","Timer","intentPolitenessMap","success","warning","error","info","useToastContainer_unstable","props","ref","visible","children","close","closeProp","remove","updateId","announce","data","timeout","timerTimeout","politeness","desiredPoliteness","intent","pauseOnHover","pauseOnWindowBlur","imperativeRef","tryRestoreFocus","rest","titleId","bodyId","toastRef","useRef","targetDocument","running","setRunning","useState","imperativePauseRef","focusedToastBeforeClose","focusableGroupAttribute","tabBehavior","ignoreDefaultKeydown","Escape","Enter","activeElement","current","contains","onStatusChange","status","pause","play","containsActive","useImperativeHandle","focus","useEffect","defaultView","addEventListener","removeEventListener","onTransitionEntering","element","style","setProperty","scrollHeight","userRootSlot","root","toastAnimationRef","useCallback","el","once","onMouseEnter","e","onMouseLeave","findFirstFocusable","findLastFocusable","onKeyDown","key","preventDefault","currentTarget","target","shiftKey","textContent","components","timer","onTimeout","required","tabIndex","role","transitionTimeout","nodeRef"],"mappings":"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"}
@@ -1,7 +1,7 @@
1
1
  import { __resetStyles, __styles, mergeClasses, shorthands } from '@griffel/react';
2
2
  import { tokens } from '@fluentui/react-theme';
3
3
  import { createCustomFocusIndicatorStyle } from '@fluentui/react-tabster';
4
- export const toastClassNames = {
4
+ export const toastContainerClassNames = {
5
5
  root: 'fui-ToastContainer',
6
6
  timer: 'fui-ToastContainer__timer'
7
7
  };
@@ -30,7 +30,7 @@ const useStyles = /*#__PURE__*/__styles({
30
30
  export const useToastContainerStyles_unstable = state => {
31
31
  const rootBaseClassName = useRootBaseClassName();
32
32
  const styles = useStyles();
33
- state.root.className = mergeClasses(toastClassNames.root, rootBaseClassName, state.visible ? styles.enter : styles.exit, state.root.className);
33
+ state.root.className = mergeClasses(toastContainerClassNames.root, rootBaseClassName, state.visible ? styles.enter : styles.exit, state.root.className);
34
34
  return state;
35
35
  };
36
36
  //# sourceMappingURL=useToastContainerStyles.styles.js.map
@@ -1 +1 @@
1
- {"version":3,"names":["__resetStyles","__styles","mergeClasses","shorthands","tokens","createCustomFocusIndicatorStyle","toastClassNames","root","timer","useRootBaseClassName","useStyles","enter","vin17d","m1gqa9","Bv12yb3","exit","d","k","useToastContainerStyles_unstable","state","rootBaseClassName","styles","className","visible"],"sources":["useToastContainerStyles.styles.js"],"sourcesContent":["import { makeResetStyles, makeStyles, mergeClasses, shorthands } from '@griffel/react';\nimport { tokens } from '@fluentui/react-theme';\nimport { createCustomFocusIndicatorStyle } from '@fluentui/react-tabster';\nexport const toastClassNames = {\n root: 'fui-ToastContainer',\n timer: 'fui-ToastContainer__timer'\n};\nconst useRootBaseClassName = makeResetStyles({\n boxSizing: 'border-box',\n marginTop: '16px',\n minHeight: '44px',\n pointerEvents: 'all',\n ...shorthands.borderRadius(tokens.borderRadiusMedium),\n '--fui-toast-height': '44px',\n ...createCustomFocusIndicatorStyle({\n ...shorthands.outline(tokens.strokeWidthThick, 'solid', tokens.colorStrokeFocus2)\n })\n});\n/**\n * Styles for the root slot\n */ const useStyles = makeStyles({\n enter: {\n animationDuration: '200ms, 400ms',\n animationDelay: '0ms, 200ms',\n animationName: [\n {\n from: {\n maxHeight: 0,\n opacity: 0,\n marginTop: 0\n },\n to: {\n marginTop: '16px',\n opacity: 0,\n maxHeight: 'var(--fui-toast-height)'\n }\n },\n {\n from: {\n opacity: 0\n },\n to: {\n opacity: 1\n }\n }\n ]\n },\n exit: {\n animationDuration: '400ms, 200ms',\n animationDelay: '0ms, 400ms',\n animationName: [\n {\n from: {\n opacity: 1\n },\n to: {\n opacity: 0\n }\n },\n {\n from: {\n opacity: 0\n },\n to: {\n opacity: 0,\n marginTop: 0,\n maxHeight: 0\n }\n }\n ]\n }\n});\n/**\n * Apply styling to the ToastContainer slots based on the state\n */ export const useToastContainerStyles_unstable = (state)=>{\n const rootBaseClassName = useRootBaseClassName();\n const styles = useStyles();\n state.root.className = mergeClasses(toastClassNames.root, rootBaseClassName, state.visible ? styles.enter : styles.exit, state.root.className);\n return state;\n};\n"],"mappings":"AAAA,SAAAA,aAAA,EAAAC,QAAA,EAAsCC,YAAY,EAAEC,UAAU,QAAQ,gBAAgB;AACtF,SAASC,MAAM,QAAQ,uBAAuB;AAC9C,SAASC,+BAA+B,QAAQ,yBAAyB;AACzE,OAAO,MAAMC,eAAe,GAAG;EAC3BC,IAAI,EAAE,oBAAoB;EAC1BC,KAAK,EAAE;AACX,CAAC;AACD,MAAMC,oBAAoB,gBAAGT,aAAA,i6BAU5B,CAAC;AACF;AACA;AACA;AAAI,MAAMU,SAAS,gBAAGT,QAAA;EAAAU,KAAA;IAAAC,MAAA;IAAAC,MAAA;IAAAC,OAAA;EAAA;EAAAC,IAAA;IAAAH,MAAA;IAAAC,MAAA;IAAAC,OAAA;EAAA;AAAA;EAAAE,CAAA;EAAAC,CAAA;AAAA,CAmDrB,CAAC;AACF;AACA;AACA;AAAI,OAAO,MAAMC,gCAAgC,GAAIC,KAAK,IAAG;EACzD,MAAMC,iBAAiB,GAAGX,oBAAoB,CAAC,CAAC;EAChD,MAAMY,MAAM,GAAGX,SAAS,CAAC,CAAC;EAC1BS,KAAK,CAACZ,IAAI,CAACe,SAAS,GAAGpB,YAAY,CAACI,eAAe,CAACC,IAAI,EAAEa,iBAAiB,EAAED,KAAK,CAACI,OAAO,GAAGF,MAAM,CAACV,KAAK,GAAGU,MAAM,CAACN,IAAI,EAAEI,KAAK,CAACZ,IAAI,CAACe,SAAS,CAAC;EAC9I,OAAOH,KAAK;AAChB,CAAC"}
1
+ {"version":3,"names":["__resetStyles","__styles","mergeClasses","shorthands","tokens","createCustomFocusIndicatorStyle","toastContainerClassNames","root","timer","useRootBaseClassName","useStyles","enter","vin17d","m1gqa9","Bv12yb3","exit","d","k","useToastContainerStyles_unstable","state","rootBaseClassName","styles","className","visible"],"sources":["useToastContainerStyles.styles.js"],"sourcesContent":["import { makeResetStyles, makeStyles, mergeClasses, shorthands } from '@griffel/react';\nimport { tokens } from '@fluentui/react-theme';\nimport { createCustomFocusIndicatorStyle } from '@fluentui/react-tabster';\nexport const toastContainerClassNames = {\n root: 'fui-ToastContainer',\n timer: 'fui-ToastContainer__timer'\n};\nconst useRootBaseClassName = makeResetStyles({\n boxSizing: 'border-box',\n marginTop: '16px',\n minHeight: '44px',\n pointerEvents: 'all',\n ...shorthands.borderRadius(tokens.borderRadiusMedium),\n '--fui-toast-height': '44px',\n ...createCustomFocusIndicatorStyle({\n ...shorthands.outline(tokens.strokeWidthThick, 'solid', tokens.colorStrokeFocus2)\n })\n});\n/**\n * Styles for the root slot\n */ const useStyles = makeStyles({\n enter: {\n animationDuration: '200ms, 400ms',\n animationDelay: '0ms, 200ms',\n animationName: [\n {\n from: {\n maxHeight: 0,\n opacity: 0,\n marginTop: 0\n },\n to: {\n marginTop: '16px',\n opacity: 0,\n maxHeight: 'var(--fui-toast-height)'\n }\n },\n {\n from: {\n opacity: 0\n },\n to: {\n opacity: 1\n }\n }\n ]\n },\n exit: {\n animationDuration: '400ms, 200ms',\n animationDelay: '0ms, 400ms',\n animationName: [\n {\n from: {\n opacity: 1\n },\n to: {\n opacity: 0\n }\n },\n {\n from: {\n opacity: 0\n },\n to: {\n opacity: 0,\n marginTop: 0,\n maxHeight: 0\n }\n }\n ]\n }\n});\n/**\n * Apply styling to the ToastContainer slots based on the state\n */ export const useToastContainerStyles_unstable = (state)=>{\n const rootBaseClassName = useRootBaseClassName();\n const styles = useStyles();\n state.root.className = mergeClasses(toastContainerClassNames.root, rootBaseClassName, state.visible ? styles.enter : styles.exit, state.root.className);\n return state;\n};\n"],"mappings":"AAAA,SAAAA,aAAA,EAAAC,QAAA,EAAsCC,YAAY,EAAEC,UAAU,QAAQ,gBAAgB;AACtF,SAASC,MAAM,QAAQ,uBAAuB;AAC9C,SAASC,+BAA+B,QAAQ,yBAAyB;AACzE,OAAO,MAAMC,wBAAwB,GAAG;EACpCC,IAAI,EAAE,oBAAoB;EAC1BC,KAAK,EAAE;AACX,CAAC;AACD,MAAMC,oBAAoB,gBAAGT,aAAA,i6BAU5B,CAAC;AACF;AACA;AACA;AAAI,MAAMU,SAAS,gBAAGT,QAAA;EAAAU,KAAA;IAAAC,MAAA;IAAAC,MAAA;IAAAC,OAAA;EAAA;EAAAC,IAAA;IAAAH,MAAA;IAAAC,MAAA;IAAAC,OAAA;EAAA;AAAA;EAAAE,CAAA;EAAAC,CAAA;AAAA,CAmDrB,CAAC;AACF;AACA;AACA;AAAI,OAAO,MAAMC,gCAAgC,GAAIC,KAAK,IAAG;EACzD,MAAMC,iBAAiB,GAAGX,oBAAoB,CAAC,CAAC;EAChD,MAAMY,MAAM,GAAGX,SAAS,CAAC,CAAC;EAC1BS,KAAK,CAACZ,IAAI,CAACe,SAAS,GAAGpB,YAAY,CAACI,wBAAwB,CAACC,IAAI,EAAEa,iBAAiB,EAAED,KAAK,CAACI,OAAO,GAAGF,MAAM,CAACV,KAAK,GAAGU,MAAM,CAACN,IAAI,EAAEI,KAAK,CAACZ,IAAI,CAACe,SAAS,CAAC;EACvJ,OAAOH,KAAK;AAChB,CAAC"}
@@ -0,0 +1,47 @@
1
+ import * as React from 'react';
2
+ import { isHTMLElement } from '@fluentui/react-utilities';
3
+ /**
4
+ * Wraps an aria live announcement function.
5
+ * Aria live announcements can be detrimental once the user is already navigating
6
+ * multiple toasts. Once the user is focused inside the toaster, the announecments should be disabled.
7
+ * @param announce
8
+ * @returns A function to announce a toast and a ref to attach to the toaster element
9
+ */ export function useToastAnnounce(announce) {
10
+ const activeRef = React.useRef(true);
11
+ const cleanupRef = React.useRef(()=>undefined);
12
+ const announceToast = React.useCallback((message, options)=>{
13
+ if (activeRef.current) {
14
+ announce(message, options);
15
+ }
16
+ }, [
17
+ announce
18
+ ]);
19
+ const toasterRef = React.useCallback((el)=>{
20
+ if (!el) {
21
+ cleanupRef.current();
22
+ return;
23
+ }
24
+ const onFocusIn = (e)=>{
25
+ if (isHTMLElement(e.currentTarget) && e.currentTarget.contains(isHTMLElement(e.relatedTarget) ? e.relatedTarget : null)) {
26
+ return;
27
+ }
28
+ activeRef.current = false;
29
+ };
30
+ const onFocusOut = (e)=>{
31
+ if (isHTMLElement(e.currentTarget) && e.currentTarget.contains(isHTMLElement(e.relatedTarget) ? e.relatedTarget : null)) {
32
+ return;
33
+ }
34
+ activeRef.current = true;
35
+ };
36
+ el.addEventListener('focusin', onFocusIn);
37
+ el.addEventListener('focusout', onFocusOut);
38
+ cleanupRef.current = ()=>{
39
+ el.removeEventListener('focusin', onFocusIn);
40
+ el.removeEventListener('focusout', onFocusOut);
41
+ };
42
+ }, []);
43
+ return {
44
+ announceToast,
45
+ toasterRef
46
+ };
47
+ }
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["useToastAnnounce.ts"],"sourcesContent":["import * as React from 'react';\nimport { Announce } from '../AriaLive';\nimport { isHTMLElement } from '@fluentui/react-utilities';\n\n/**\n * Wraps an aria live announcement function.\n * Aria live announcements can be detrimental once the user is already navigating\n * multiple toasts. Once the user is focused inside the toaster, the announecments should be disabled.\n * @param announce\n * @returns A function to announce a toast and a ref to attach to the toaster element\n */\nexport function useToastAnnounce(announce: Announce) {\n const activeRef = React.useRef(true);\n const cleanupRef = React.useRef<() => void>(() => undefined);\n const announceToast = React.useCallback<Announce>(\n (message, options) => {\n if (activeRef.current) {\n announce(message, options);\n }\n },\n [announce],\n );\n\n const toasterRef = React.useCallback((el: HTMLDivElement | null) => {\n if (!el) {\n cleanupRef.current();\n return;\n }\n\n const onFocusIn = (e: FocusEvent) => {\n if (\n isHTMLElement(e.currentTarget) &&\n e.currentTarget.contains(isHTMLElement(e.relatedTarget) ? e.relatedTarget : null)\n ) {\n return;\n }\n\n activeRef.current = false;\n };\n\n const onFocusOut = (e: FocusEvent) => {\n if (\n isHTMLElement(e.currentTarget) &&\n e.currentTarget.contains(isHTMLElement(e.relatedTarget) ? e.relatedTarget : null)\n ) {\n return;\n }\n\n activeRef.current = true;\n };\n\n el.addEventListener('focusin', onFocusIn);\n el.addEventListener('focusout', onFocusOut);\n\n cleanupRef.current = () => {\n el.removeEventListener('focusin', onFocusIn);\n el.removeEventListener('focusout', onFocusOut);\n };\n }, []);\n\n return {\n announceToast,\n toasterRef,\n };\n}\n"],"names":["React","isHTMLElement","useToastAnnounce","announce","activeRef","useRef","cleanupRef","undefined","announceToast","useCallback","message","options","current","toasterRef","el","onFocusIn","e","currentTarget","contains","relatedTarget","onFocusOut","addEventListener","removeEventListener"],"mappings":"AAAA,YAAYA,WAAW,QAAQ;AAE/B,SAASC,aAAa,QAAQ,4BAA4B;AAE1D;;;;;;CAMC,GACD,OAAO,SAASC,iBAAiBC,QAAkB,EAAE;IACnD,MAAMC,YAAYJ,MAAMK,MAAM,CAAC,IAAI;IACnC,MAAMC,aAAaN,MAAMK,MAAM,CAAa,IAAME;IAClD,MAAMC,gBAAgBR,MAAMS,WAAW,CACrC,CAACC,SAASC,UAAY;QACpB,IAAIP,UAAUQ,OAAO,EAAE;YACrBT,SAASO,SAASC;QACpB,CAAC;IACH,GACA;QAACR;KAAS;IAGZ,MAAMU,aAAab,MAAMS,WAAW,CAAC,CAACK,KAA8B;QAClE,IAAI,CAACA,IAAI;YACPR,WAAWM,OAAO;YAClB;QACF,CAAC;QAED,MAAMG,YAAY,CAACC,IAAkB;YACnC,IACEf,cAAce,EAAEC,aAAa,KAC7BD,EAAEC,aAAa,CAACC,QAAQ,CAACjB,cAAce,EAAEG,aAAa,IAAIH,EAAEG,aAAa,GAAG,IAAI,GAChF;gBACA;YACF,CAAC;YAEDf,UAAUQ,OAAO,GAAG,KAAK;QAC3B;QAEA,MAAMQ,aAAa,CAACJ,IAAkB;YACpC,IACEf,cAAce,EAAEC,aAAa,KAC7BD,EAAEC,aAAa,CAACC,QAAQ,CAACjB,cAAce,EAAEG,aAAa,IAAIH,EAAEG,aAAa,GAAG,IAAI,GAChF;gBACA;YACF,CAAC;YAEDf,UAAUQ,OAAO,GAAG,IAAI;QAC1B;QAEAE,GAAGO,gBAAgB,CAAC,WAAWN;QAC/BD,GAAGO,gBAAgB,CAAC,YAAYD;QAEhCd,WAAWM,OAAO,GAAG,IAAM;YACzBE,GAAGQ,mBAAmB,CAAC,WAAWP;YAClCD,GAAGQ,mBAAmB,CAAC,YAAYF;QACrC;IACF,GAAG,EAAE;IAEL,OAAO;QACLZ;QACAK;IACF;AACF,CAAC"}
@@ -1,8 +1,12 @@
1
1
  import * as React from 'react';
2
- import { getNativeElementProps, isHTMLElement, resolveShorthand } from '@fluentui/react-utilities';
2
+ import { getNativeElementProps, resolveShorthand, useEventCallback, useMergedRefs } from '@fluentui/react-utilities';
3
3
  import { useFluent_unstable as useFluent } from '@fluentui/react-shared-contexts';
4
+ import { useFocusableGroup } from '@fluentui/react-tabster';
5
+ import { Escape } from '@fluentui/keyboard-keys';
4
6
  import { TOAST_POSITIONS, useToaster } from '../../state';
5
7
  import { ToastContainer } from '../ToastContainer';
8
+ import { useToasterFocusManagement_unstable } from './useToasterFocusManagement';
9
+ import { useToastAnnounce } from './useToastAnnounce';
6
10
  /**
7
11
  * Create the state required to render Toaster.
8
12
  *
@@ -10,45 +14,43 @@ import { ToastContainer } from '../ToastContainer';
10
14
  */ export const useToaster_unstable = (props)=>{
11
15
  const { offset , announce: announceProp , ...rest } = props;
12
16
  const announceRef = React.useRef(()=>null);
13
- const { toastsToRender , isToastVisible , pauseAllToasts , playAllToasts , tryRestoreFocus } = useToaster(rest);
17
+ const { toastsToRender , isToastVisible , pauseAllToasts , playAllToasts , tryRestoreFocus , closeAllToasts } = useToaster(rest);
14
18
  const announce = React.useCallback((message, options)=>announceRef.current(message, options), []);
15
19
  const { dir } = useFluent();
16
20
  const rootProps = getNativeElementProps('div', rest);
17
- // Adds native HTML focusin/focusout listeners
18
- // https://github.com/facebook/react/issues/25194
19
- const focusListenerRef = React.useCallback((el)=>{
20
- if (el) {
21
- el.addEventListener('focusin', (e)=>{
22
- if (isHTMLElement(e.currentTarget) && !e.currentTarget.contains(isHTMLElement(e.relatedTarget) ? e.relatedTarget : null)) {
23
- pauseAllToasts();
24
- }
25
- });
26
- el.addEventListener('focusout', (e)=>{
27
- if (isHTMLElement(e.currentTarget) && !e.currentTarget.contains(isHTMLElement(e.relatedTarget) ? e.relatedTarget : null)) {
28
- playAllToasts();
29
- tryRestoreFocus();
30
- }
31
- });
21
+ const focusableGroupAttr = useFocusableGroup({
22
+ tabBehavior: 'limited-trap-focus',
23
+ ignoreDefaultKeydown: {
24
+ Escape: true
32
25
  }
33
- }, [
34
- playAllToasts,
35
- pauseAllToasts,
36
- tryRestoreFocus
37
- ]);
38
- const createPositionSlot = (toastPosition)=>{
26
+ });
27
+ const onKeyDown = useEventCallback((e)=>{
28
+ var _props_onKeyDown;
29
+ if (e.key === Escape) {
30
+ e.preventDefault();
31
+ closeAllToasts();
32
+ }
33
+ (_props_onKeyDown = props.onKeyDown) === null || _props_onKeyDown === void 0 ? void 0 : _props_onKeyDown.call(props, e);
34
+ });
35
+ const usePositionSlot = (toastPosition)=>{
39
36
  var _toastsToRender_get;
37
+ const focusManagementRef = useToasterFocusManagement_unstable(pauseAllToasts, playAllToasts);
38
+ const { announceToast , toasterRef } = useToastAnnounce(announceProp !== null && announceProp !== void 0 ? announceProp : announce);
40
39
  return resolveShorthand(toastsToRender.has(toastPosition) ? rootProps : null, {
41
40
  defaultProps: {
42
- ref: focusListenerRef,
41
+ ref: useMergedRefs(focusManagementRef, toasterRef),
43
42
  children: (_toastsToRender_get = toastsToRender.get(toastPosition)) === null || _toastsToRender_get === void 0 ? void 0 : _toastsToRender_get.map((toast)=>/*#__PURE__*/ React.createElement(ToastContainer, {
44
43
  ...toast,
45
44
  tryRestoreFocus: tryRestoreFocus,
46
45
  intent: toast.intent,
47
- announce: announce,
46
+ announce: announceToast,
48
47
  key: toast.toastId,
49
48
  visible: isToastVisible(toast.toastId)
50
49
  }, toast.content)),
51
- 'data-toaster-position': toastPosition
50
+ onKeyDown,
51
+ ...focusableGroupAttr,
52
+ 'data-toaster-position': toastPosition,
53
+ role: 'list'
52
54
  }
53
55
  });
54
56
  };
@@ -64,10 +66,10 @@ import { ToastContainer } from '../ToastContainer';
64
66
  root: resolveShorthand(rootProps, {
65
67
  required: true
66
68
  }),
67
- bottomStart: createPositionSlot(TOAST_POSITIONS.bottomStart),
68
- bottomEnd: createPositionSlot(TOAST_POSITIONS.bottomEnd),
69
- topStart: createPositionSlot(TOAST_POSITIONS.topStart),
70
- topEnd: createPositionSlot(TOAST_POSITIONS.topEnd),
69
+ bottomStart: usePositionSlot(TOAST_POSITIONS.bottomStart),
70
+ bottomEnd: usePositionSlot(TOAST_POSITIONS.bottomEnd),
71
+ topStart: usePositionSlot(TOAST_POSITIONS.topStart),
72
+ topEnd: usePositionSlot(TOAST_POSITIONS.topEnd),
71
73
  announceRef,
72
74
  offset,
73
75
  announce: announceProp !== null && announceProp !== void 0 ? announceProp : announce,
@@ -1 +1 @@
1
- {"version":3,"sources":["useToaster.tsx"],"sourcesContent":["import * as React from 'react';\nimport {\n ExtractSlotProps,\n Slot,\n getNativeElementProps,\n isHTMLElement,\n resolveShorthand,\n} from '@fluentui/react-utilities';\nimport { useFluent_unstable as useFluent } from '@fluentui/react-shared-contexts';\nimport type { ToasterProps, ToasterState } from './Toaster.types';\nimport { TOAST_POSITIONS, ToastPosition, useToaster } from '../../state';\nimport { Announce } from '../AriaLive';\nimport { ToastContainer } from '../ToastContainer';\n\n/**\n * Create the state required to render Toaster.\n *\n * @param props - props from this instance of Toaster\n */\nexport const useToaster_unstable = (props: ToasterProps): ToasterState => {\n const { offset, announce: announceProp, ...rest } = props;\n const announceRef = React.useRef<Announce>(() => null);\n const { toastsToRender, isToastVisible, pauseAllToasts, playAllToasts, tryRestoreFocus } =\n useToaster<HTMLDivElement>(rest);\n const announce = React.useCallback<Announce>((message, options) => announceRef.current(message, options), []);\n const { dir } = useFluent();\n\n const rootProps = getNativeElementProps('div', rest);\n\n // Adds native HTML focusin/focusout listeners\n // https://github.com/facebook/react/issues/25194\n const focusListenerRef = React.useCallback(\n (el: HTMLDivElement | null) => {\n if (el) {\n el.addEventListener('focusin', e => {\n if (\n isHTMLElement(e.currentTarget) &&\n !e.currentTarget.contains(isHTMLElement(e.relatedTarget) ? e.relatedTarget : null)\n ) {\n pauseAllToasts();\n }\n });\n\n el.addEventListener('focusout', e => {\n if (\n isHTMLElement(e.currentTarget) &&\n !e.currentTarget.contains(isHTMLElement(e.relatedTarget) ? e.relatedTarget : null)\n ) {\n playAllToasts();\n tryRestoreFocus();\n }\n });\n }\n },\n [playAllToasts, pauseAllToasts, tryRestoreFocus],\n );\n\n const createPositionSlot = (toastPosition: ToastPosition) =>\n resolveShorthand(toastsToRender.has(toastPosition) ? rootProps : null, {\n defaultProps: {\n ref: focusListenerRef,\n children: toastsToRender.get(toastPosition)?.map(toast => (\n <ToastContainer\n {...toast}\n tryRestoreFocus={tryRestoreFocus}\n intent={toast.intent}\n announce={announce}\n key={toast.toastId}\n visible={isToastVisible(toast.toastId)}\n >\n {toast.content as React.ReactNode}\n </ToastContainer>\n )),\n 'data-toaster-position': toastPosition,\n // Explicitly casting because our slot types can't handle data attributes\n } as ExtractSlotProps<Slot<'div'>>,\n });\n\n return {\n dir,\n components: {\n root: 'div',\n bottomStart: 'div',\n bottomEnd: 'div',\n topStart: 'div',\n topEnd: 'div',\n },\n root: resolveShorthand(rootProps, { required: true }),\n bottomStart: createPositionSlot(TOAST_POSITIONS.bottomStart),\n bottomEnd: createPositionSlot(TOAST_POSITIONS.bottomEnd),\n topStart: createPositionSlot(TOAST_POSITIONS.topStart),\n topEnd: createPositionSlot(TOAST_POSITIONS.topEnd),\n announceRef,\n offset,\n announce: announceProp ?? announce,\n renderAriaLive: !announceProp,\n };\n};\n"],"names":["React","getNativeElementProps","isHTMLElement","resolveShorthand","useFluent_unstable","useFluent","TOAST_POSITIONS","useToaster","ToastContainer","useToaster_unstable","props","offset","announce","announceProp","rest","announceRef","useRef","toastsToRender","isToastVisible","pauseAllToasts","playAllToasts","tryRestoreFocus","useCallback","message","options","current","dir","rootProps","focusListenerRef","el","addEventListener","e","currentTarget","contains","relatedTarget","createPositionSlot","toastPosition","has","defaultProps","ref","children","get","map","toast","intent","key","toastId","visible","content","components","root","bottomStart","bottomEnd","topStart","topEnd","required","renderAriaLive"],"mappings":"AAAA,YAAYA,WAAW,QAAQ;AAC/B,SAGEC,qBAAqB,EACrBC,aAAa,EACbC,gBAAgB,QACX,4BAA4B;AACnC,SAASC,sBAAsBC,SAAS,QAAQ,kCAAkC;AAElF,SAASC,eAAe,EAAiBC,UAAU,QAAQ,cAAc;AAEzE,SAASC,cAAc,QAAQ,oBAAoB;AAEnD;;;;CAIC,GACD,OAAO,MAAMC,sBAAsB,CAACC,QAAsC;IACxE,MAAM,EAAEC,OAAM,EAAEC,UAAUC,aAAY,EAAE,GAAGC,MAAM,GAAGJ;IACpD,MAAMK,cAAcf,MAAMgB,MAAM,CAAW,IAAM,IAAI;IACrD,MAAM,EAAEC,eAAc,EAAEC,eAAc,EAAEC,eAAc,EAAEC,cAAa,EAAEC,gBAAe,EAAE,GACtFd,WAA2BO;IAC7B,MAAMF,WAAWZ,MAAMsB,WAAW,CAAW,CAACC,SAASC,UAAYT,YAAYU,OAAO,CAACF,SAASC,UAAU,EAAE;IAC5G,MAAM,EAAEE,IAAG,EAAE,GAAGrB;IAEhB,MAAMsB,YAAY1B,sBAAsB,OAAOa;IAE/C,8CAA8C;IAC9C,iDAAiD;IACjD,MAAMc,mBAAmB5B,MAAMsB,WAAW,CACxC,CAACO,KAA8B;QAC7B,IAAIA,IAAI;YACNA,GAAGC,gBAAgB,CAAC,WAAWC,CAAAA,IAAK;gBAClC,IACE7B,cAAc6B,EAAEC,aAAa,KAC7B,CAACD,EAAEC,aAAa,CAACC,QAAQ,CAAC/B,cAAc6B,EAAEG,aAAa,IAAIH,EAAEG,aAAa,GAAG,IAAI,GACjF;oBACAf;gBACF,CAAC;YACH;YAEAU,GAAGC,gBAAgB,CAAC,YAAYC,CAAAA,IAAK;gBACnC,IACE7B,cAAc6B,EAAEC,aAAa,KAC7B,CAACD,EAAEC,aAAa,CAACC,QAAQ,CAAC/B,cAAc6B,EAAEG,aAAa,IAAIH,EAAEG,aAAa,GAAG,IAAI,GACjF;oBACAd;oBACAC;gBACF,CAAC;YACH;QACF,CAAC;IACH,GACA;QAACD;QAAeD;QAAgBE;KAAgB;IAGlD,MAAMc,qBAAqB,CAACC;YAIZnB;QAHdd,OAAAA,iBAAiBc,eAAeoB,GAAG,CAACD,iBAAiBT,YAAY,IAAI,EAAE;YACrEW,cAAc;gBACZC,KAAKX;gBACLY,QAAQ,EAAEvB,CAAAA,sBAAAA,eAAewB,GAAG,CAACL,4BAAnBnB,iCAAAA,KAAAA,IAAAA,oBAAmCyB,IAAIC,CAAAA,sBAC/C,oBAACnC;wBACE,GAAGmC,KAAK;wBACTtB,iBAAiBA;wBACjBuB,QAAQD,MAAMC,MAAM;wBACpBhC,UAAUA;wBACViC,KAAKF,MAAMG,OAAO;wBAClBC,SAAS7B,eAAeyB,MAAMG,OAAO;uBAEpCH,MAAMK,OAAO;gBAGlB,yBAAyBZ;YAE3B;QACF;;IAEF,OAAO;QACLV;QACAuB,YAAY;YACVC,MAAM;YACNC,aAAa;YACbC,WAAW;YACXC,UAAU;YACVC,QAAQ;QACV;QACAJ,MAAM/C,iBAAiBwB,WAAW;YAAE4B,UAAU,IAAI;QAAC;QACnDJ,aAAahB,mBAAmB7B,gBAAgB6C,WAAW;QAC3DC,WAAWjB,mBAAmB7B,gBAAgB8C,SAAS;QACvDC,UAAUlB,mBAAmB7B,gBAAgB+C,QAAQ;QACrDC,QAAQnB,mBAAmB7B,gBAAgBgD,MAAM;QACjDvC;QACAJ;QACAC,UAAUC,yBAAAA,0BAAAA,eAAgBD,QAAQ;QAClC4C,gBAAgB,CAAC3C;IACnB;AACF,EAAE"}
1
+ {"version":3,"sources":["useToaster.tsx"],"sourcesContent":["import * as React from 'react';\nimport {\n ExtractSlotProps,\n Slot,\n getNativeElementProps,\n resolveShorthand,\n useEventCallback,\n useMergedRefs,\n} from '@fluentui/react-utilities';\nimport { useFluent_unstable as useFluent } from '@fluentui/react-shared-contexts';\nimport { useFocusableGroup } from '@fluentui/react-tabster';\nimport { Escape } from '@fluentui/keyboard-keys';\nimport type { ToasterProps, ToasterState } from './Toaster.types';\nimport { TOAST_POSITIONS, ToastPosition, useToaster } from '../../state';\nimport { Announce } from '../AriaLive';\nimport { ToastContainer } from '../ToastContainer';\nimport { useToasterFocusManagement_unstable } from './useToasterFocusManagement';\nimport { useToastAnnounce } from './useToastAnnounce';\n\n/**\n * Create the state required to render Toaster.\n *\n * @param props - props from this instance of Toaster\n */\nexport const useToaster_unstable = (props: ToasterProps): ToasterState => {\n const { offset, announce: announceProp, ...rest } = props;\n const announceRef = React.useRef<Announce>(() => null);\n const { toastsToRender, isToastVisible, pauseAllToasts, playAllToasts, tryRestoreFocus, closeAllToasts } =\n useToaster<HTMLDivElement>(rest);\n const announce = React.useCallback<Announce>((message, options) => announceRef.current(message, options), []);\n const { dir } = useFluent();\n\n const rootProps = getNativeElementProps('div', rest);\n const focusableGroupAttr = useFocusableGroup({\n tabBehavior: 'limited-trap-focus',\n ignoreDefaultKeydown: { Escape: true },\n });\n\n const onKeyDown = useEventCallback((e: React.KeyboardEvent<HTMLDivElement>) => {\n if (e.key === Escape) {\n e.preventDefault();\n closeAllToasts();\n }\n\n props.onKeyDown?.(e);\n });\n\n const usePositionSlot = (toastPosition: ToastPosition) => {\n const focusManagementRef = useToasterFocusManagement_unstable(pauseAllToasts, playAllToasts);\n const { announceToast, toasterRef } = useToastAnnounce(announceProp ?? announce);\n return resolveShorthand(toastsToRender.has(toastPosition) ? rootProps : null, {\n defaultProps: {\n ref: useMergedRefs(focusManagementRef, toasterRef),\n children: toastsToRender.get(toastPosition)?.map(toast => (\n <ToastContainer\n {...toast}\n tryRestoreFocus={tryRestoreFocus}\n intent={toast.intent}\n announce={announceToast}\n key={toast.toastId}\n visible={isToastVisible(toast.toastId)}\n >\n {toast.content as React.ReactNode}\n </ToastContainer>\n )),\n onKeyDown,\n ...focusableGroupAttr,\n 'data-toaster-position': toastPosition,\n role: 'list',\n // Explicitly casting because our slot types can't handle data attributes\n } as ExtractSlotProps<Slot<'div'>>,\n });\n };\n\n return {\n dir,\n components: {\n root: 'div',\n bottomStart: 'div',\n bottomEnd: 'div',\n topStart: 'div',\n topEnd: 'div',\n },\n root: resolveShorthand(rootProps, { required: true }),\n bottomStart: usePositionSlot(TOAST_POSITIONS.bottomStart),\n bottomEnd: usePositionSlot(TOAST_POSITIONS.bottomEnd),\n topStart: usePositionSlot(TOAST_POSITIONS.topStart),\n topEnd: usePositionSlot(TOAST_POSITIONS.topEnd),\n announceRef,\n offset,\n announce: announceProp ?? announce,\n renderAriaLive: !announceProp,\n };\n};\n"],"names":["React","getNativeElementProps","resolveShorthand","useEventCallback","useMergedRefs","useFluent_unstable","useFluent","useFocusableGroup","Escape","TOAST_POSITIONS","useToaster","ToastContainer","useToasterFocusManagement_unstable","useToastAnnounce","useToaster_unstable","props","offset","announce","announceProp","rest","announceRef","useRef","toastsToRender","isToastVisible","pauseAllToasts","playAllToasts","tryRestoreFocus","closeAllToasts","useCallback","message","options","current","dir","rootProps","focusableGroupAttr","tabBehavior","ignoreDefaultKeydown","onKeyDown","e","key","preventDefault","usePositionSlot","toastPosition","focusManagementRef","announceToast","toasterRef","has","defaultProps","ref","children","get","map","toast","intent","toastId","visible","content","role","components","root","bottomStart","bottomEnd","topStart","topEnd","required","renderAriaLive"],"mappings":"AAAA,YAAYA,WAAW,QAAQ;AAC/B,SAGEC,qBAAqB,EACrBC,gBAAgB,EAChBC,gBAAgB,EAChBC,aAAa,QACR,4BAA4B;AACnC,SAASC,sBAAsBC,SAAS,QAAQ,kCAAkC;AAClF,SAASC,iBAAiB,QAAQ,0BAA0B;AAC5D,SAASC,MAAM,QAAQ,0BAA0B;AAEjD,SAASC,eAAe,EAAiBC,UAAU,QAAQ,cAAc;AAEzE,SAASC,cAAc,QAAQ,oBAAoB;AACnD,SAASC,kCAAkC,QAAQ,8BAA8B;AACjF,SAASC,gBAAgB,QAAQ,qBAAqB;AAEtD;;;;CAIC,GACD,OAAO,MAAMC,sBAAsB,CAACC,QAAsC;IACxE,MAAM,EAAEC,OAAM,EAAEC,UAAUC,aAAY,EAAE,GAAGC,MAAM,GAAGJ;IACpD,MAAMK,cAAcpB,MAAMqB,MAAM,CAAW,IAAM,IAAI;IACrD,MAAM,EAAEC,eAAc,EAAEC,eAAc,EAAEC,eAAc,EAAEC,cAAa,EAAEC,gBAAe,EAAEC,eAAc,EAAE,GACtGjB,WAA2BS;IAC7B,MAAMF,WAAWjB,MAAM4B,WAAW,CAAW,CAACC,SAASC,UAAYV,YAAYW,OAAO,CAACF,SAASC,UAAU,EAAE;IAC5G,MAAM,EAAEE,IAAG,EAAE,GAAG1B;IAEhB,MAAM2B,YAAYhC,sBAAsB,OAAOkB;IAC/C,MAAMe,qBAAqB3B,kBAAkB;QAC3C4B,aAAa;QACbC,sBAAsB;YAAE5B,QAAQ,IAAI;QAAC;IACvC;IAEA,MAAM6B,YAAYlC,iBAAiB,CAACmC,IAA2C;YAM7EvB;QALA,IAAIuB,EAAEC,GAAG,KAAK/B,QAAQ;YACpB8B,EAAEE,cAAc;YAChBb;QACF,CAAC;QAEDZ,CAAAA,mBAAAA,MAAMsB,SAAS,cAAftB,8BAAAA,KAAAA,IAAAA,iBAAAA,KAAAA,OAAkBuB;IACpB;IAEA,MAAMG,kBAAkB,CAACC,gBAAiC;YAM1CpB;QALd,MAAMqB,qBAAqB/B,mCAAmCY,gBAAgBC;QAC9E,MAAM,EAAEmB,cAAa,EAAEC,WAAU,EAAE,GAAGhC,iBAAiBK,yBAAAA,0BAAAA,eAAgBD,QAAQ;QAC/E,OAAOf,iBAAiBoB,eAAewB,GAAG,CAACJ,iBAAiBT,YAAY,IAAI,EAAE;YAC5Ec,cAAc;gBACZC,KAAK5C,cAAcuC,oBAAoBE;gBACvCI,QAAQ,EAAE3B,CAAAA,sBAAAA,eAAe4B,GAAG,CAACR,4BAAnBpB,iCAAAA,KAAAA,IAAAA,oBAAmC6B,IAAIC,CAAAA,sBAC/C,oBAACzC;wBACE,GAAGyC,KAAK;wBACT1B,iBAAiBA;wBACjB2B,QAAQD,MAAMC,MAAM;wBACpBpC,UAAU2B;wBACVL,KAAKa,MAAME,OAAO;wBAClBC,SAAShC,eAAe6B,MAAME,OAAO;uBAEpCF,MAAMI,OAAO;gBAGlBnB;gBACA,GAAGH,kBAAkB;gBACrB,yBAAyBQ;gBACzBe,MAAM;YAER;QACF;IACF;IAEA,OAAO;QACLzB;QACA0B,YAAY;YACVC,MAAM;YACNC,aAAa;YACbC,WAAW;YACXC,UAAU;YACVC,QAAQ;QACV;QACAJ,MAAMzD,iBAAiB+B,WAAW;YAAE+B,UAAU,IAAI;QAAC;QACnDJ,aAAanB,gBAAgBhC,gBAAgBmD,WAAW;QACxDC,WAAWpB,gBAAgBhC,gBAAgBoD,SAAS;QACpDC,UAAUrB,gBAAgBhC,gBAAgBqD,QAAQ;QAClDC,QAAQtB,gBAAgBhC,gBAAgBsD,MAAM;QAC9C3C;QACAJ;QACAC,UAAUC,yBAAAA,0BAAAA,eAAgBD,QAAQ;QAClCgD,gBAAgB,CAAC/C;IACnB;AACF,EAAE"}
@@ -0,0 +1,85 @@
1
+ import { isHTMLElement } from '@fluentui/react-utilities';
2
+ import * as React from 'react';
3
+ import { useFluent_unstable as useFluent } from '@fluentui/react-shared-contexts';
4
+ import { ArrowDown, ArrowUp } from '@fluentui/keyboard-keys';
5
+ import { toastContainerClassNames } from '../ToastContainer';
6
+ const noop = ()=>undefined;
7
+ /**
8
+ * @internal
9
+ */ export function useToasterFocusManagement_unstable(pauseAllToasts, playAllToasts) {
10
+ const { targetDocument } = useFluent();
11
+ const cleanupListenersRef = React.useRef(noop);
12
+ return React.useCallback((el)=>{
13
+ if (!el || !targetDocument) {
14
+ cleanupListenersRef.current();
15
+ cleanupListenersRef.current = noop;
16
+ return;
17
+ }
18
+ const toastContainerWalker = targetDocument.createTreeWalker(el, NodeFilter.SHOW_ELEMENT, {
19
+ acceptNode (node) {
20
+ if (isHTMLElement(node) && node.classList.contains(toastContainerClassNames.root)) {
21
+ return NodeFilter.FILTER_ACCEPT;
22
+ }
23
+ return NodeFilter.FILTER_SKIP;
24
+ }
25
+ });
26
+ /**
27
+ * FIXME: https://github.com/microsoft/tabster/issues/299
28
+ * Toasts should be arrow navigable and focus should be trapped in a stack of tasts
29
+ * This is a temporary measure, Tabster does not have an API yet to enable mover arrow keys from within grouppers
30
+ * Once tabster fully supports this use case, remove this hook
31
+ */ const keydownListener = (e)=>{
32
+ const { target , key } = e;
33
+ if (!isHTMLElement(target)) {
34
+ return;
35
+ }
36
+ if (key === ArrowDown) {
37
+ toastContainerWalker.currentNode = target;
38
+ let nextToastContainer = toastContainerWalker.nextNode();
39
+ if (!nextToastContainer) {
40
+ toastContainerWalker.currentNode = el;
41
+ nextToastContainer = toastContainerWalker.nextNode();
42
+ }
43
+ if (isHTMLElement(nextToastContainer)) {
44
+ nextToastContainer.focus();
45
+ }
46
+ }
47
+ if (key === ArrowUp) {
48
+ toastContainerWalker.currentNode = target;
49
+ let prevToastContainer = toastContainerWalker.previousNode();
50
+ if (prevToastContainer && prevToastContainer.contains(target)) {
51
+ prevToastContainer = toastContainerWalker.previousNode();
52
+ }
53
+ if (!prevToastContainer) {
54
+ toastContainerWalker.currentNode = el;
55
+ prevToastContainer = toastContainerWalker.lastChild();
56
+ }
57
+ if (isHTMLElement(prevToastContainer)) {
58
+ prevToastContainer.focus();
59
+ }
60
+ }
61
+ };
62
+ const focusInListener = (e)=>{
63
+ if (isHTMLElement(e.currentTarget) && !e.currentTarget.contains(isHTMLElement(e.relatedTarget) ? e.relatedTarget : null)) {
64
+ pauseAllToasts();
65
+ }
66
+ };
67
+ const focusOutListener = (e)=>{
68
+ if (isHTMLElement(e.currentTarget) && !e.currentTarget.contains(isHTMLElement(e.relatedTarget) ? e.relatedTarget : null)) {
69
+ playAllToasts();
70
+ }
71
+ };
72
+ el.addEventListener('keydown', keydownListener);
73
+ el.addEventListener('focusin', focusInListener);
74
+ el.addEventListener('focusout', focusOutListener);
75
+ cleanupListenersRef.current = ()=>{
76
+ el.removeEventListener('keydown', keydownListener);
77
+ el.removeEventListener('focusin', focusInListener);
78
+ el.removeEventListener('focusout', focusOutListener);
79
+ };
80
+ }, [
81
+ targetDocument,
82
+ pauseAllToasts,
83
+ playAllToasts
84
+ ]);
85
+ }
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["useToasterFocusManagement.ts"],"sourcesContent":["import { isHTMLElement } from '@fluentui/react-utilities';\nimport * as React from 'react';\nimport { useFluent_unstable as useFluent } from '@fluentui/react-shared-contexts';\nimport { ArrowDown, ArrowUp } from '@fluentui/keyboard-keys';\nimport { toastContainerClassNames } from '../ToastContainer';\n\nconst noop = () => undefined;\n\n/**\n * @internal\n */\nexport function useToasterFocusManagement_unstable(pauseAllToasts: () => void, playAllToasts: () => void) {\n const { targetDocument } = useFluent();\n const cleanupListenersRef = React.useRef<() => void>(noop);\n\n return React.useCallback(\n (el: HTMLDivElement) => {\n if (!el || !targetDocument) {\n cleanupListenersRef.current();\n cleanupListenersRef.current = noop;\n return;\n }\n\n const toastContainerWalker = targetDocument.createTreeWalker(el, NodeFilter.SHOW_ELEMENT, {\n acceptNode(node: Node) {\n if (isHTMLElement(node) && node.classList.contains(toastContainerClassNames.root)) {\n return NodeFilter.FILTER_ACCEPT;\n }\n\n return NodeFilter.FILTER_SKIP;\n },\n });\n\n /**\n * FIXME: https://github.com/microsoft/tabster/issues/299\n * Toasts should be arrow navigable and focus should be trapped in a stack of tasts\n * This is a temporary measure, Tabster does not have an API yet to enable mover arrow keys from within grouppers\n * Once tabster fully supports this use case, remove this hook\n */\n const keydownListener = (e: KeyboardEvent) => {\n const { target, key } = e;\n if (!isHTMLElement(target)) {\n return;\n }\n\n if (key === ArrowDown) {\n toastContainerWalker.currentNode = target;\n let nextToastContainer = toastContainerWalker.nextNode();\n if (!nextToastContainer) {\n toastContainerWalker.currentNode = el;\n nextToastContainer = toastContainerWalker.nextNode();\n }\n\n if (isHTMLElement(nextToastContainer)) {\n nextToastContainer.focus();\n }\n }\n\n if (key === ArrowUp) {\n toastContainerWalker.currentNode = target;\n let prevToastContainer = toastContainerWalker.previousNode();\n if (prevToastContainer && prevToastContainer.contains(target)) {\n prevToastContainer = toastContainerWalker.previousNode();\n }\n\n if (!prevToastContainer) {\n toastContainerWalker.currentNode = el;\n prevToastContainer = toastContainerWalker.lastChild();\n }\n\n if (isHTMLElement(prevToastContainer)) {\n prevToastContainer.focus();\n }\n }\n };\n\n const focusInListener = (e: FocusEvent) => {\n if (\n isHTMLElement(e.currentTarget) &&\n !e.currentTarget.contains(isHTMLElement(e.relatedTarget) ? e.relatedTarget : null)\n ) {\n pauseAllToasts();\n }\n };\n\n const focusOutListener = (e: FocusEvent) => {\n if (\n isHTMLElement(e.currentTarget) &&\n !e.currentTarget.contains(isHTMLElement(e.relatedTarget) ? e.relatedTarget : null)\n ) {\n playAllToasts();\n }\n };\n\n el.addEventListener('keydown', keydownListener);\n el.addEventListener('focusin', focusInListener);\n el.addEventListener('focusout', focusOutListener);\n\n cleanupListenersRef.current = () => {\n el.removeEventListener('keydown', keydownListener);\n el.removeEventListener('focusin', focusInListener);\n el.removeEventListener('focusout', focusOutListener);\n };\n },\n [targetDocument, pauseAllToasts, playAllToasts],\n );\n}\n"],"names":["isHTMLElement","React","useFluent_unstable","useFluent","ArrowDown","ArrowUp","toastContainerClassNames","noop","undefined","useToasterFocusManagement_unstable","pauseAllToasts","playAllToasts","targetDocument","cleanupListenersRef","useRef","useCallback","el","current","toastContainerWalker","createTreeWalker","NodeFilter","SHOW_ELEMENT","acceptNode","node","classList","contains","root","FILTER_ACCEPT","FILTER_SKIP","keydownListener","e","target","key","currentNode","nextToastContainer","nextNode","focus","prevToastContainer","previousNode","lastChild","focusInListener","currentTarget","relatedTarget","focusOutListener","addEventListener","removeEventListener"],"mappings":"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"}