stream-chat-react 14.7.0 → 14.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.
Files changed (150) hide show
  1. package/dist/cjs/{ReactPlayerWrapper.c340ab05.js → ReactPlayerWrapper.60a93742.js} +2 -2
  2. package/dist/cjs/{ReactPlayerWrapper.c340ab05.js.map → ReactPlayerWrapper.60a93742.js.map} +1 -1
  3. package/dist/cjs/channel-detail.js +2 -2
  4. package/dist/cjs/emojis.js +2 -2
  5. package/dist/cjs/index.js +2888 -730
  6. package/dist/cjs/index.js.map +1 -1
  7. package/dist/cjs/{useChannelHeaderOnlineStatus.d39ede24.js → useChannelHeaderOnlineStatus.72753090.js} +373 -63
  8. package/dist/cjs/useChannelHeaderOnlineStatus.72753090.js.map +1 -0
  9. package/dist/cjs/{useMessageComposerController.f1a3d182.js → useMessageComposerController.f8f20e3d.js} +2 -2
  10. package/dist/cjs/{useMessageComposerController.f1a3d182.js.map → useMessageComposerController.f8f20e3d.js.map} +1 -1
  11. package/dist/cjs/{useNotificationApi.87ba0b39.js → useNotificationApi.bf76a16b.js} +294 -42
  12. package/dist/cjs/useNotificationApi.bf76a16b.js.map +1 -0
  13. package/dist/css/index.css +34 -7
  14. package/dist/css/index.css.map +1 -1
  15. package/dist/es/channel-detail.mjs +2 -2
  16. package/dist/es/emojis.mjs +2 -2
  17. package/dist/es/index.mjs +2868 -728
  18. package/dist/es/index.mjs.map +1 -1
  19. package/dist/es/{useChannelHeaderOnlineStatus.b3a51ca7.mjs → useChannelHeaderOnlineStatus.c86db868.mjs} +337 -64
  20. package/dist/es/useChannelHeaderOnlineStatus.c86db868.mjs.map +1 -0
  21. package/dist/es/{useMessageComposerController.2309f433.mjs → useMessageComposerController.d50f6168.mjs} +2 -2
  22. package/dist/es/{useMessageComposerController.2309f433.mjs.map → useMessageComposerController.d50f6168.mjs.map} +1 -1
  23. package/dist/es/{useNotificationApi.eff88f29.mjs → useNotificationApi.ed6bff88.mjs} +271 -43
  24. package/dist/es/useNotificationApi.ed6bff88.mjs.map +1 -0
  25. package/dist/types/a11y/accessibleLabel.d.ts +38 -0
  26. package/dist/types/a11y/accessibleLabel.d.ts.map +1 -0
  27. package/dist/types/a11y/hooks/useListboxKeyboardNavigation.d.ts +73 -0
  28. package/dist/types/a11y/hooks/useListboxKeyboardNavigation.d.ts.map +1 -0
  29. package/dist/types/a11y/hooks/useVirtualizedListboxKeyboardNavigation.d.ts +41 -0
  30. package/dist/types/a11y/hooks/useVirtualizedListboxKeyboardNavigation.d.ts.map +1 -0
  31. package/dist/types/components/Accessibility/AriaLiveAnnouncerProvider.d.ts +13 -0
  32. package/dist/types/components/Accessibility/AriaLiveAnnouncerProvider.d.ts.map +1 -0
  33. package/dist/types/components/Accessibility/AriaLiveOutlet.d.ts +24 -0
  34. package/dist/types/components/Accessibility/AriaLiveOutlet.d.ts.map +1 -0
  35. package/dist/types/components/Accessibility/AriaLiveOutletContext.d.ts +25 -0
  36. package/dist/types/components/Accessibility/AriaLiveOutletContext.d.ts.map +1 -0
  37. package/dist/types/components/Accessibility/NotificationAnnouncer.d.ts +21 -1
  38. package/dist/types/components/Accessibility/NotificationAnnouncer.d.ts.map +1 -1
  39. package/dist/types/components/Accessibility/hooks/useAudioPlaybackChangeAnnouncements.d.ts +3 -0
  40. package/dist/types/components/Accessibility/hooks/useAudioPlaybackChangeAnnouncements.d.ts.map +1 -0
  41. package/dist/types/components/Accessibility/hooks/useFocusReturn.d.ts +44 -0
  42. package/dist/types/components/Accessibility/hooks/useFocusReturn.d.ts.map +1 -0
  43. package/dist/types/components/Accessibility/hooks/useInertWhenHidden.d.ts +88 -0
  44. package/dist/types/components/Accessibility/hooks/useInertWhenHidden.d.ts.map +1 -0
  45. package/dist/types/components/Accessibility/hooks/useInteractionAnnouncements.d.ts +114 -0
  46. package/dist/types/components/Accessibility/hooks/useInteractionAnnouncements.d.ts.map +1 -0
  47. package/dist/types/components/Accessibility/index.d.ts +7 -1
  48. package/dist/types/components/Accessibility/index.d.ts.map +1 -1
  49. package/dist/types/components/Accessibility/scheduling/index.d.ts +4 -0
  50. package/dist/types/components/Accessibility/scheduling/index.d.ts.map +1 -0
  51. package/dist/types/components/Accessibility/scheduling/useAnnouncementQueue.d.ts +25 -0
  52. package/dist/types/components/Accessibility/scheduling/useAnnouncementQueue.d.ts.map +1 -0
  53. package/dist/types/components/Accessibility/scheduling/useDebouncedAnnounce.d.ts +54 -0
  54. package/dist/types/components/Accessibility/scheduling/useDebouncedAnnounce.d.ts.map +1 -0
  55. package/dist/types/components/Accessibility/scheduling/useSettledAnnouncement.d.ts +74 -0
  56. package/dist/types/components/Accessibility/scheduling/useSettledAnnouncement.d.ts.map +1 -0
  57. package/dist/types/components/Accessibility/useAriaLiveAnnouncer.d.ts +24 -1
  58. package/dist/types/components/Accessibility/useAriaLiveAnnouncer.d.ts.map +1 -1
  59. package/dist/types/components/Attachment/AttachmentActions.d.ts.map +1 -1
  60. package/dist/types/components/Attachment/Giphy.d.ts.map +1 -1
  61. package/dist/types/components/Attachment/giphyAccessibility.d.ts +11 -0
  62. package/dist/types/components/Attachment/giphyAccessibility.d.ts.map +1 -0
  63. package/dist/types/components/AudioPlayback/WithAudioPlayback.d.ts.map +1 -1
  64. package/dist/types/components/ChannelList/ChannelListUI.d.ts.map +1 -1
  65. package/dist/types/components/ChannelList/hooks/index.d.ts +1 -0
  66. package/dist/types/components/ChannelList/hooks/index.d.ts.map +1 -1
  67. package/dist/types/components/ChannelList/hooks/useChannelListKeyboardNavigation.d.ts +17 -0
  68. package/dist/types/components/ChannelList/hooks/useChannelListKeyboardNavigation.d.ts.map +1 -0
  69. package/dist/types/components/ChannelListItem/ChannelListItem.d.ts +7 -0
  70. package/dist/types/components/ChannelListItem/ChannelListItem.d.ts.map +1 -1
  71. package/dist/types/components/ChannelListItem/ChannelListItemActionButtons.defaults.d.ts.map +1 -1
  72. package/dist/types/components/ChannelListItem/ChannelListItemUI.d.ts.map +1 -1
  73. package/dist/types/components/ChannelListItem/index.d.ts +1 -0
  74. package/dist/types/components/ChannelListItem/index.d.ts.map +1 -1
  75. package/dist/types/components/ChannelListItem/utils.a11y.d.ts +112 -0
  76. package/dist/types/components/ChannelListItem/utils.a11y.d.ts.map +1 -0
  77. package/dist/types/components/ChannelListItem/utils.d.ts +10 -2
  78. package/dist/types/components/ChannelListItem/utils.d.ts.map +1 -1
  79. package/dist/types/components/Chat/Chat.d.ts.map +1 -1
  80. package/dist/types/components/ChatView/ChatView.a11y.utility.d.ts +9 -17
  81. package/dist/types/components/ChatView/ChatView.a11y.utility.d.ts.map +1 -1
  82. package/dist/types/components/ChatView/ChatView.d.ts +7 -7
  83. package/dist/types/components/ChatView/ChatView.d.ts.map +1 -1
  84. package/dist/types/components/Dialog/components/ContextMenu.d.ts +17 -2
  85. package/dist/types/components/Dialog/components/ContextMenu.d.ts.map +1 -1
  86. package/dist/types/components/Dialog/components/Prompt.d.ts.map +1 -1
  87. package/dist/types/components/Dialog/service/DialogAnchor.d.ts.map +1 -1
  88. package/dist/types/components/Form/SwitchField.d.ts.map +1 -1
  89. package/dist/types/components/Form/TextInput.d.ts.map +1 -1
  90. package/dist/types/components/InfiniteScrollPaginator/InfiniteScrollPaginator.d.ts +7 -0
  91. package/dist/types/components/InfiniteScrollPaginator/InfiniteScrollPaginator.d.ts.map +1 -1
  92. package/dist/types/components/MediaRecorder/hooks/useMediaRecorder.d.ts +2 -2
  93. package/dist/types/components/MediaRecorder/hooks/useMediaRecorder.d.ts.map +1 -1
  94. package/dist/types/components/MessageActions/DownloadSubmenu.d.ts.map +1 -1
  95. package/dist/types/components/MessageActions/RemindMeSubmenu.d.ts.map +1 -1
  96. package/dist/types/components/MessageComposer/AttachmentSelector/AttachmentSelector.d.ts +8 -2
  97. package/dist/types/components/MessageComposer/AttachmentSelector/AttachmentSelector.d.ts.map +1 -1
  98. package/dist/types/components/MessageComposer/AttachmentSelector/CommandsMenu.d.ts.map +1 -1
  99. package/dist/types/components/MessageComposer/CommandChip.d.ts.map +1 -1
  100. package/dist/types/components/MessageComposer/MessageComposerActions.d.ts.map +1 -1
  101. package/dist/types/components/MessageList/MessageList.d.ts.map +1 -1
  102. package/dist/types/components/MessageList/VirtualizedMessageList.d.ts.map +1 -1
  103. package/dist/types/components/Modal/GlobalModal.d.ts +6 -1
  104. package/dist/types/components/Modal/GlobalModal.d.ts.map +1 -1
  105. package/dist/types/components/Notifications/Notification.d.ts.map +1 -1
  106. package/dist/types/components/Notifications/hooks/useNotificationApi.d.ts +7 -0
  107. package/dist/types/components/Notifications/hooks/useNotificationApi.d.ts.map +1 -1
  108. package/dist/types/components/Poll/PollCreationDialog/NameField.d.ts.map +1 -1
  109. package/dist/types/components/Poll/PollCreationDialog/OptionFieldSet.d.ts.map +1 -1
  110. package/dist/types/components/Poll/PollCreationDialog/PollCreationDialog.d.ts.map +1 -1
  111. package/dist/types/components/Poll/PollCreationDialog/PollCreationDialogControls.d.ts.map +1 -1
  112. package/dist/types/components/Poll/PollCreationDialog/PollOptionReorderHandle.d.ts +17 -0
  113. package/dist/types/components/Poll/PollCreationDialog/PollOptionReorderHandle.d.ts.map +1 -0
  114. package/dist/types/components/Search/Search.d.ts +9 -1
  115. package/dist/types/components/Search/Search.d.ts.map +1 -1
  116. package/dist/types/components/Search/SearchBar/SearchBar.d.ts.map +1 -1
  117. package/dist/types/components/Search/SearchContext.d.ts +1 -1
  118. package/dist/types/components/Search/SearchContext.d.ts.map +1 -1
  119. package/dist/types/components/Search/SearchResults/SearchResults.d.ts.map +1 -1
  120. package/dist/types/components/Search/SearchResults/SearchSourceResultListFooter.d.ts.map +1 -1
  121. package/dist/types/components/Search/hooks/index.d.ts +2 -0
  122. package/dist/types/components/Search/hooks/index.d.ts.map +1 -1
  123. package/dist/types/components/Search/hooks/useAnnounceSearchResultCount.d.ts +27 -0
  124. package/dist/types/components/Search/hooks/useAnnounceSearchResultCount.d.ts.map +1 -0
  125. package/dist/types/components/Search/hooks/useSearchResultsKeyboardNavigation.d.ts +13 -0
  126. package/dist/types/components/Search/hooks/useSearchResultsKeyboardNavigation.d.ts.map +1 -0
  127. package/dist/types/components/TextareaComposer/SuggestionList/MentionItem/UserItem.d.ts.map +1 -1
  128. package/dist/types/components/TextareaComposer/SuggestionList/SuggestionList.d.ts +21 -1
  129. package/dist/types/components/TextareaComposer/SuggestionList/SuggestionList.d.ts.map +1 -1
  130. package/dist/types/components/TextareaComposer/TextareaComposer.d.ts +9 -1
  131. package/dist/types/components/TextareaComposer/TextareaComposer.d.ts.map +1 -1
  132. package/dist/types/components/Threads/ThreadList/ThreadList.d.ts.map +1 -1
  133. package/dist/types/components/Threads/ThreadList/ThreadListItemUI.d.ts +7 -1
  134. package/dist/types/components/Threads/ThreadList/ThreadListItemUI.d.ts.map +1 -1
  135. package/dist/types/components/Threads/ThreadList/index.d.ts +1 -0
  136. package/dist/types/components/Threads/ThreadList/index.d.ts.map +1 -1
  137. package/dist/types/components/Threads/ThreadList/utils.a11y.d.ts +111 -0
  138. package/dist/types/components/Threads/ThreadList/utils.a11y.d.ts.map +1 -0
  139. package/dist/types/components/Threads/UnreadCountBadge.d.ts.map +1 -1
  140. package/dist/types/components/UtilityComponents/hooks/useMutationObserver.d.ts +23 -0
  141. package/dist/types/components/UtilityComponents/hooks/useMutationObserver.d.ts.map +1 -0
  142. package/dist/types/i18n/Streami18n.d.ts +79 -13
  143. package/dist/types/i18n/Streami18n.d.ts.map +1 -1
  144. package/package.json +4 -1
  145. package/dist/cjs/useChannelHeaderOnlineStatus.d39ede24.js.map +0 -1
  146. package/dist/cjs/useNotificationApi.87ba0b39.js.map +0 -1
  147. package/dist/es/useChannelHeaderOnlineStatus.b3a51ca7.mjs.map +0 -1
  148. package/dist/es/useNotificationApi.eff88f29.mjs.map +0 -1
  149. package/dist/types/components/Accessibility/AriaLiveRegion.d.ts +0 -3
  150. package/dist/types/components/Accessibility/AriaLiveRegion.d.ts.map +0 -1
@@ -0,0 +1,38 @@
1
+ import type { TranslationContextValue } from '../context/TranslationContext';
2
+ /** Produces one segment of a composed accessible name; return `undefined`/empty to omit it. */
3
+ export type AccessibleLabelPart<TData> = (data: TData) => string | undefined;
4
+ /** Customization for a part-composed accessible name (the channel/thread list-row labels). */
5
+ export type AccessibleLabelConfig<TData> = {
6
+ /** Full override — return the entire label; ignores `order`/`parts`/`separator`. */
7
+ build?: (data: TData) => string;
8
+ /** Which parts to include, in what order. A part not listed here is never rendered. */
9
+ order?: ReadonlyArray<string>;
10
+ /** Override or add individual part generators; merged over the defaults. */
11
+ parts?: Record<string, AccessibleLabelPart<TData>>;
12
+ /** Joiner between non-empty parts. Defaults to ". ". */
13
+ separator?: string;
14
+ };
15
+ /**
16
+ * Composes a single accessible name from named parts: applies `config.build` if present, otherwise
17
+ * merges `config.parts` over `defaultParts`, walks `config.order ?? defaultOrder`, and joins the
18
+ * non-empty segments with `config.separator ?? '. '`. Shared by the channel and thread list-row
19
+ * labels so the assembly logic lives in one place.
20
+ */
21
+ export declare const composeAccessibleLabel: <TData>(data: TData, defaultParts: Record<string, AccessibleLabelPart<TData>>, defaultOrder: ReadonlyArray<string>, config?: AccessibleLabelConfig<TData>) => string;
22
+ type WithT = {
23
+ t: TranslationContextValue['t'];
24
+ };
25
+ /**
26
+ * Announces the active (currently open) row. The active state is announced here (not left to the
27
+ * row's `aria-selected` alone, which is not reliably spoken across screen readers for an option with
28
+ * a custom name); `aria-selected` is kept on the active row for listbox semantics.
29
+ */
30
+ export declare const activeLabelPart: AccessibleLabelPart<WithT & {
31
+ active?: boolean;
32
+ }>;
33
+ /** Announces the unread count when there is one. */
34
+ export declare const unreadCountLabelPart: AccessibleLabelPart<WithT & {
35
+ unreadCount?: number;
36
+ }>;
37
+ export {};
38
+ //# sourceMappingURL=accessibleLabel.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"accessibleLabel.d.ts","sourceRoot":"","sources":["../../../src/a11y/accessibleLabel.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,+BAA+B,CAAC;AAE7E,+FAA+F;AAC/F,MAAM,MAAM,mBAAmB,CAAC,KAAK,IAAI,CAAC,IAAI,EAAE,KAAK,KAAK,MAAM,GAAG,SAAS,CAAC;AAE7E,8FAA8F;AAC9F,MAAM,MAAM,qBAAqB,CAAC,KAAK,IAAI;IACzC,oFAAoF;IACpF,KAAK,CAAC,EAAE,CAAC,IAAI,EAAE,KAAK,KAAK,MAAM,CAAC;IAChC,uFAAuF;IACvF,KAAK,CAAC,EAAE,aAAa,CAAC,MAAM,CAAC,CAAC;IAC9B,4EAA4E;IAC5E,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,mBAAmB,CAAC,KAAK,CAAC,CAAC,CAAC;IACnD,wDAAwD;IACxD,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,CAAC;AAEF;;;;;GAKG;AACH,eAAO,MAAM,sBAAsB,GAAI,KAAK,EAC1C,MAAM,KAAK,EACX,cAAc,MAAM,CAAC,MAAM,EAAE,mBAAmB,CAAC,KAAK,CAAC,CAAC,EACxD,cAAc,aAAa,CAAC,MAAM,CAAC,EACnC,SAAQ,qBAAqB,CAAC,KAAK,CAAM,KACxC,MAWF,CAAC;AAIF,KAAK,KAAK,GAAG;IAAE,CAAC,EAAE,uBAAuB,CAAC,GAAG,CAAC,CAAA;CAAE,CAAC;AAEjD;;;;GAIG;AACH,eAAO,MAAM,eAAe,EAAE,mBAAmB,CAAC,KAAK,GAAG;IAAE,MAAM,CAAC,EAAE,OAAO,CAAA;CAAE,CAGjC,CAAC;AAE9C,oDAAoD;AACpD,eAAO,MAAM,oBAAoB,EAAE,mBAAmB,CACpD,KAAK,GAAG;IAAE,WAAW,CAAC,EAAE,MAAM,CAAA;CAAE,CAInB,CAAC"}
@@ -0,0 +1,73 @@
1
+ import type { KeyboardEvent as ReactKeyboardEvent, RefObject } from 'react';
2
+ /** State handed to a {@link ListboxKeyHandler} when its key is pressed inside the container. */
3
+ export type ListboxNavigationContext = {
4
+ /** The focused element — guaranteed to be inside the container. */
5
+ active: HTMLElement;
6
+ /** The listbox container element. */
7
+ container: HTMLElement;
8
+ /** The current option elements (live). */
9
+ getOptions: () => HTMLElement[];
10
+ /** Whether {@link ListboxNavigationContext.active} is itself an option. */
11
+ onOption: boolean;
12
+ };
13
+ /**
14
+ * Handler for a non-roving key. Return `true` if it handled the key — the hook then
15
+ * `preventDefault()`s and `stopPropagation()`s so nothing else acts on it. Return nothing to let the
16
+ * key fall through (default behaviour preserved).
17
+ */
18
+ export type ListboxKeyHandler = (context: ListboxNavigationContext) => boolean | void;
19
+ export type ListboxKeyboardNavigationConfig = {
20
+ /**
21
+ * Where the roving (vertical) keys are active:
22
+ * - `'option'` (default): only when focus is already on an option — a plain listbox.
23
+ * - `'container'`: anywhere inside the container, so focus can enter the list from a preceding
24
+ * control (e.g. a filter tag); when not on an option, Down/Home land on the first, Up/End on the
25
+ * last.
26
+ */
27
+ enterScope?: 'container' | 'option';
28
+ /**
29
+ * Extra keys to handle, beyond the built-in roving. Mapped by `event.key` to a handler that
30
+ * receives the current {@link ListboxNavigationContext} and decides what to do. The hook does not
31
+ * prescribe any particular keys (e.g. ArrowRight to reach a row's actions) — compose what you need,
32
+ * optionally with {@link createRowActionKeyHandlers}. Roving keys (Up/Down/Home/End) are reserved.
33
+ */
34
+ keyHandlers?: Record<string, ListboxKeyHandler>;
35
+ /** Selector for the navigable options. Default `[role="option"]`. */
36
+ optionSelector?: string;
37
+ /**
38
+ * Maps the focused element to the option that vertical roving (Up/Down/Home/End) should move
39
+ * relative to. Use with `enterScope: 'container'` so those keys work while focus is on something
40
+ * inside an option's row (e.g. its action buttons) and step to the next/previous option from that
41
+ * row, rather than jumping to the first/last. Return `null` to fall back to that default.
42
+ */
43
+ resolveActiveOption?: (active: HTMLElement) => HTMLElement | null;
44
+ };
45
+ /**
46
+ * Keyboard navigation for a list of options (the channel list, the search results, …). Returns an
47
+ * `onKeyDown` to spread onto the container plus `getOptions` for callers that need the current
48
+ * options (e.g. load-more focus management):
49
+ * - **ArrowUp/ArrowDown/Home/End** rove the options (scope set by `enterScope`).
50
+ * - any other key listed in `keyHandlers` is delegated to its handler.
51
+ *
52
+ * For keys, it handles it `stopPropagation()`s, so it stays authoritative — nothing downstream (a
53
+ * parent handler, or the browser/AT "jump to first/last focusable" fallback) can move focus to a
54
+ * non-option. Stateless — safe to call on every render; the handlers read the DOM live.
55
+ */
56
+ export declare const useListboxKeyboardNavigation: (containerRef: RefObject<HTMLElement | null>, { enterScope, keyHandlers, optionSelector, resolveActiveOption, }?: ListboxKeyboardNavigationConfig) => {
57
+ getOptions: () => HTMLElement[];
58
+ onKeyDown: (event: ReactKeyboardEvent<HTMLElement>) => void;
59
+ };
60
+ /**
61
+ * Composable {@link ListboxKeyHandler}s for the "each option sits in a row alongside one or more
62
+ * action targets" pattern (e.g. a channel row + its actions/menu buttons). The option and its
63
+ * actions form one **horizontal cyclic group** in DOM order: from the option **ArrowRight** enters
64
+ * the actions; **ArrowLeft/ArrowRight** move between the actions; stepping off either end returns to
65
+ * the option (so the actions need not be in the Tab order). Rows with no actions (a lone option)
66
+ * leave the keys unhandled. Pass the result as (part of) `keyHandlers`.
67
+ */
68
+ export declare const createRowActionKeyHandlers: ({ actionSelector, optionSelector, rowSelector, }: {
69
+ actionSelector: string;
70
+ optionSelector?: string;
71
+ rowSelector: string;
72
+ }) => Record<string, ListboxKeyHandler>;
73
+ //# sourceMappingURL=useListboxKeyboardNavigation.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useListboxKeyboardNavigation.d.ts","sourceRoot":"","sources":["../../../../src/a11y/hooks/useListboxKeyboardNavigation.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,IAAI,kBAAkB,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAO5E,gGAAgG;AAChG,MAAM,MAAM,wBAAwB,GAAG;IACrC,mEAAmE;IACnE,MAAM,EAAE,WAAW,CAAC;IACpB,qCAAqC;IACrC,SAAS,EAAE,WAAW,CAAC;IACvB,0CAA0C;IAC1C,UAAU,EAAE,MAAM,WAAW,EAAE,CAAC;IAChC,2EAA2E;IAC3E,QAAQ,EAAE,OAAO,CAAC;CACnB,CAAC;AAEF;;;;GAIG;AACH,MAAM,MAAM,iBAAiB,GAAG,CAAC,OAAO,EAAE,wBAAwB,KAAK,OAAO,GAAG,IAAI,CAAC;AAEtF,MAAM,MAAM,+BAA+B,GAAG;IAC5C;;;;;;OAMG;IACH,UAAU,CAAC,EAAE,WAAW,GAAG,QAAQ,CAAC;IACpC;;;;;OAKG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,iBAAiB,CAAC,CAAC;IAChD,qEAAqE;IACrE,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB;;;;;OAKG;IACH,mBAAmB,CAAC,EAAE,CAAC,MAAM,EAAE,WAAW,KAAK,WAAW,GAAG,IAAI,CAAC;CACnE,CAAC;AAEF;;;;;;;;;;GAUG;AACH,eAAO,MAAM,4BAA4B,GACvC,cAAc,SAAS,CAAC,WAAW,GAAG,IAAI,CAAC,EAC3C,oEAKG,+BAAoC;;uBAKb,kBAAkB,CAAC,WAAW,CAAC;CAwC1D,CAAC;AAEF;;;;;;;GAOG;AACH,eAAO,MAAM,0BAA0B,GAAI,kDAIxC;IACD,cAAc,EAAE,MAAM,CAAC;IACvB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,WAAW,EAAE,MAAM,CAAC;CACrB,KAAG,MAAM,CAAC,MAAM,EAAE,iBAAiB,CAkBnC,CAAC"}
@@ -0,0 +1,41 @@
1
+ import type { KeyboardEvent as ReactKeyboardEvent, RefObject } from 'react';
2
+ export type VirtualizedListboxKeyboardNavigationParams<T> = {
3
+ /** Stable id for an item; must equal the value the item's option carries in `itemIdAttribute`. */
4
+ getItemId: (item: T) => string;
5
+ /**
6
+ * The attribute every option carries its id in (e.g. `'data-thread-id'`). Used both to read the id
7
+ * off the focused element and to locate the target option in the DOM.
8
+ */
9
+ itemIdAttribute: string;
10
+ /** The full, unvirtualized list — NOT just the rendered window. Roving indexes into this. */
11
+ items: T[];
12
+ /** Selector for the focusable option elements. Default `[role="option"]`. */
13
+ optionSelector?: string;
14
+ /**
15
+ * Bring the item at `index` into the rendered window, then invoke `onRendered` once it should be in
16
+ * the DOM. For a virtualized list wrap the list's imperative scroll (e.g. Virtuoso's
17
+ * `scrollIntoView({ index, done: onRendered })`); for a non-virtualized list just call
18
+ * `onRendered()`.
19
+ */
20
+ scrollIndexIntoView: (index: number, onRendered: () => void) => void;
21
+ /** Ref to the scrollable listbox container whose subtree holds the rendered options. */
22
+ scrollerRef: RefObject<HTMLElement | null>;
23
+ };
24
+ /**
25
+ * Vertical roving-focus keyboard navigation (ArrowUp/Down/Home/End) for a **virtualized** listbox,
26
+ * where only a window of `role="option"` rows exists in the DOM at a time.
27
+ *
28
+ * A DOM-query-and-`.focus()` approach (see {@link useListboxKeyboardNavigation}) can't work here: it
29
+ * would only ever see the rendered window, so it would cycle within those rows and never scroll the
30
+ * rest of the list into view. This hook instead indexes into the **full** `items` array, focuses the
31
+ * target row if it is already rendered, and otherwise asks the list to scroll it into existence
32
+ * (`scrollIndexIntoView`) and focuses it once painted (retrying across a few frames).
33
+ *
34
+ * Returns an `onKeyDown` to spread onto the scroll container (the `role="listbox"` element). The
35
+ * caller wires `scrollerRef` to that same element and provides `scrollIndexIntoView`. Stateless — the
36
+ * active row is read live from `document.activeElement` on each key.
37
+ */
38
+ export declare const useVirtualizedListboxKeyboardNavigation: <T>({ getItemId, itemIdAttribute, items, optionSelector, scrollerRef, scrollIndexIntoView, }: VirtualizedListboxKeyboardNavigationParams<T>) => {
39
+ onKeyDown: (event: ReactKeyboardEvent<HTMLElement>) => void;
40
+ };
41
+ //# sourceMappingURL=useVirtualizedListboxKeyboardNavigation.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useVirtualizedListboxKeyboardNavigation.d.ts","sourceRoot":"","sources":["../../../../src/a11y/hooks/useVirtualizedListboxKeyboardNavigation.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,IAAI,kBAAkB,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAc5E,MAAM,MAAM,0CAA0C,CAAC,CAAC,IAAI;IAC1D,kGAAkG;IAClG,SAAS,EAAE,CAAC,IAAI,EAAE,CAAC,KAAK,MAAM,CAAC;IAC/B;;;OAGG;IACH,eAAe,EAAE,MAAM,CAAC;IACxB,6FAA6F;IAC7F,KAAK,EAAE,CAAC,EAAE,CAAC;IACX,6EAA6E;IAC7E,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB;;;;;OAKG;IACH,mBAAmB,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,IAAI,KAAK,IAAI,CAAC;IACrE,wFAAwF;IACxF,WAAW,EAAE,SAAS,CAAC,WAAW,GAAG,IAAI,CAAC,CAAC;CAC5C,CAAC;AAEF;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,uCAAuC,GAAI,CAAC,EAAE,0FAOxD,0CAA0C,CAAC,CAAC,CAAC;uBAsCpC,kBAAkB,CAAC,WAAW,CAAC;CAsC1C,CAAC"}
@@ -0,0 +1,13 @@
1
+ import type { PropsWithChildren } from 'react';
2
+ /**
3
+ * Owns the aria-live announcement state and the announce() API for one logical announcer
4
+ * (mount ONE per `Chat`). It renders no DOM region itself — the messages are painted by the
5
+ * single active {@link AriaLiveOutlet} chosen from the registered outlet stack (innermost /
6
+ * highest-layer wins). This is the L1 sink of the unified announcer model; see
7
+ * `specs/a11y-react-web/decisions.md` → "Unify the aria-live announcer implementations".
8
+ *
9
+ * All state lives here (per provider instance), never in module scope, so multiple `Chat`
10
+ * instances on one page never share announcements.
11
+ */
12
+ export declare const AriaLiveAnnouncerProvider: ({ children }: PropsWithChildren) => import("react/jsx-runtime").JSX.Element;
13
+ //# sourceMappingURL=AriaLiveAnnouncerProvider.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"AriaLiveAnnouncerProvider.d.ts","sourceRoot":"","sources":["../../../../src/components/Accessibility/AriaLiveAnnouncerProvider.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,OAAO,CAAC;AA0B/C;;;;;;;;;GASG;AACH,eAAO,MAAM,yBAAyB,GAAI,cAAc,iBAAiB,4CAgMxE,CAAC"}
@@ -0,0 +1,24 @@
1
+ export type AriaLiveOutletProps = {
2
+ /**
3
+ * Stacking layer. The {@link AriaLiveAnnouncerProvider} renders into the highest-layer
4
+ * outlet (ties resolve to the most recently registered). Outlets inside an `aria-modal`
5
+ * subtree must use a layer above the root outlet so announcements land inside the modal
6
+ * (assistive technologies suppress live regions outside the active modal). Defaults to `0`.
7
+ */
8
+ layer?: number;
9
+ /**
10
+ * When true, render the live region into a `document.body` portal instead of in place.
11
+ * Use for the root outlet; modal outlets must render in place (omit) so they stay inside
12
+ * the `aria-modal` subtree.
13
+ */
14
+ portal?: boolean;
15
+ };
16
+ /**
17
+ * Dumb render target for the unified announcer. Registers itself with the nearest
18
+ * {@link AriaLiveAnnouncerProvider} and renders the polite/assertive live regions ONLY when
19
+ * it is the active (innermost) outlet, so exactly one region is live at a time — always in
20
+ * the active accessibility-tree scope. Mount one at the `Chat` root and one inside each
21
+ * `aria-modal` dialog (with a higher `layer`).
22
+ */
23
+ export declare const AriaLiveOutlet: ({ layer, portal }: AriaLiveOutletProps) => import("react/jsx-runtime").JSX.Element | null;
24
+ //# sourceMappingURL=AriaLiveOutlet.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"AriaLiveOutlet.d.ts","sourceRoot":"","sources":["../../../../src/components/Accessibility/AriaLiveOutlet.tsx"],"names":[],"mappings":"AAMA,MAAM,MAAM,mBAAmB,GAAG;IAChC;;;;;OAKG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IACf;;;;OAIG;IACH,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB,CAAC;AAEF;;;;;;GAMG;AACH,eAAO,MAAM,cAAc,GAAI,mBAA+B,mBAAmB,mDA2DhF,CAAC"}
@@ -0,0 +1,25 @@
1
+ import type { AriaLivePriority } from './useAriaLiveAnnouncer';
2
+ export type LiveAnnouncement = {
3
+ id: number;
4
+ message: string;
5
+ };
6
+ export type AnnouncementsByPriority = {
7
+ [key in AriaLivePriority]: LiveAnnouncement[];
8
+ };
9
+ /**
10
+ * Internal coordination context between {@link AriaLiveAnnouncerProvider} (which owns the
11
+ * announcement state and the outlet stack) and the {@link AriaLiveOutlet}s that render the
12
+ * live regions. Not part of the public API — consumers announce via `useAriaLiveAnnouncer`.
13
+ */
14
+ export type AriaLiveOutletContextValue = {
15
+ /** The id of the single outlet that should currently render the live regions. */
16
+ activeOutletId: symbol | null;
17
+ /** Current announcements grouped by aria-live priority. */
18
+ announcementsByPriority: AnnouncementsByPriority;
19
+ /** Register an outlet. Higher `layer` wins; ties resolve to the most recently registered. */
20
+ registerOutlet: (id: symbol, layer: number) => void;
21
+ unregisterOutlet: (id: symbol) => void;
22
+ };
23
+ export declare const AriaLiveOutletContext: import("react").Context<AriaLiveOutletContextValue | undefined>;
24
+ export declare const useAriaLiveOutletContext: () => AriaLiveOutletContextValue | undefined;
25
+ //# sourceMappingURL=AriaLiveOutletContext.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"AriaLiveOutletContext.d.ts","sourceRoot":"","sources":["../../../../src/components/Accessibility/AriaLiveOutletContext.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAE/D,MAAM,MAAM,gBAAgB,GAAG;IAC7B,EAAE,EAAE,MAAM,CAAC;IACX,OAAO,EAAE,MAAM,CAAC;CACjB,CAAC;AAEF,MAAM,MAAM,uBAAuB,GAAG;KACnC,GAAG,IAAI,gBAAgB,GAAG,gBAAgB,EAAE;CAC9C,CAAC;AAEF;;;;GAIG;AACH,MAAM,MAAM,0BAA0B,GAAG;IACvC,iFAAiF;IACjF,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,2DAA2D;IAC3D,uBAAuB,EAAE,uBAAuB,CAAC;IACjD,6FAA6F;IAC7F,cAAc,EAAE,CAAC,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACpD,gBAAgB,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAC;CACxC,CAAC;AAEF,eAAO,MAAM,qBAAqB,iEAEtB,CAAC;AAEb,eAAO,MAAM,wBAAwB,8CAA0C,CAAC"}
@@ -10,5 +10,25 @@ export type NotificationAnnouncerProps = {
10
10
  buildNotificationAnnouncement?: NotificationAnnouncementBuilder;
11
11
  notificationFilter?: NotificationAnnouncementFilter;
12
12
  };
13
- export declare const NotificationAnnouncer: ({ buildNotificationAnnouncement, notificationFilter, }: NotificationAnnouncerProps) => import("react/jsx-runtime").JSX.Element;
13
+ /**
14
+ * Announces app notifications to assistive technology.
15
+ *
16
+ * As of the announcer unification this renders **no live region of its own** — it routes new
17
+ * notifications through the shared {@link useAriaLiveAnnouncer} sink (so they land in the active
18
+ * {@link AriaLiveOutlet}, including inside an open modal) and paces them with
19
+ * {@link useAnnouncementQueue}.
20
+ *
21
+ * ## Required context (contract)
22
+ * `NotificationAnnouncer` **must** be rendered inside an `AriaLiveAnnouncerProvider`. `Chat` mounts
23
+ * that provider (with a root, portalled `AriaLiveOutlet`), so the default component tree already
24
+ * satisfies this and no extra setup is needed.
25
+ *
26
+ * Rendered **without** a provider ancestor it mounts successfully but **announces nothing** —
27
+ * `useAriaLiveAnnouncer()` returns a no-op and logs a `console.warn` ("… called outside of an
28
+ * AriaLiveAnnouncerProvider"). This is intentional post-F4: the component no longer carries a
29
+ * fallback live region, so a single announcer owns all output and there are no duplicate/competing
30
+ * regions. If you render it outside `Chat`, wrap it in `AriaLiveAnnouncerProvider` + `AriaLiveOutlet`
31
+ * yourself.
32
+ */
33
+ export declare const NotificationAnnouncer: ({ buildNotificationAnnouncement, notificationFilter, }: NotificationAnnouncerProps) => null;
14
34
  //# sourceMappingURL=NotificationAnnouncer.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"NotificationAnnouncer.d.ts","sourceRoot":"","sources":["../../../../src/components/Accessibility/NotificationAnnouncer.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAchD,MAAM,MAAM,qCAAqC,GAAG;IAClD,cAAc,EAAE,MAAM,CAAC;IACvB,YAAY,EAAE,YAAY,CAAC;IAC3B,iBAAiB,EAAE,MAAM,CAAC;CAC3B,CAAC;AAEF,MAAM,MAAM,+BAA+B,GAAG,CAC5C,MAAM,EAAE,qCAAqC,KAC1C,MAAM,CAAC;AACZ,MAAM,MAAM,8BAA8B,GAAG,CAAC,YAAY,EAAE,YAAY,KAAK,OAAO,CAAC;AAuBrF,MAAM,MAAM,0BAA0B,GAAG;IACvC,6BAA6B,CAAC,EAAE,+BAA+B,CAAC;IAChE,kBAAkB,CAAC,EAAE,8BAA8B,CAAC;CACrD,CAAC;AAOF,eAAO,MAAM,qBAAqB,GAAI,wDAGnC,0BAA0B,4CA4H5B,CAAC"}
1
+ {"version":3,"file":"NotificationAnnouncer.d.ts","sourceRoot":"","sources":["../../../../src/components/Accessibility/NotificationAnnouncer.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAQhD,MAAM,MAAM,qCAAqC,GAAG;IAClD,cAAc,EAAE,MAAM,CAAC;IACvB,YAAY,EAAE,YAAY,CAAC;IAC3B,iBAAiB,EAAE,MAAM,CAAC;CAC3B,CAAC;AAEF,MAAM,MAAM,+BAA+B,GAAG,CAC5C,MAAM,EAAE,qCAAqC,KAC1C,MAAM,CAAC;AACZ,MAAM,MAAM,8BAA8B,GAAG,CAAC,YAAY,EAAE,YAAY,KAAK,OAAO,CAAC;AAoBrF,MAAM,MAAM,0BAA0B,GAAG;IACvC,6BAA6B,CAAC,EAAE,+BAA+B,CAAC;IAChE,kBAAkB,CAAC,EAAE,8BAA8B,CAAC;CACrD,CAAC;AAOF;;;;;;;;;;;;;;;;;;;GAmBG;AACH,eAAO,MAAM,qBAAqB,GAAI,wDAGnC,0BAA0B,SAuD5B,CAAC"}
@@ -0,0 +1,3 @@
1
+ import type { AudioPlayer } from '../../AudioPlayback';
2
+ export declare const useAudioPlaybackChangeAnnouncements: (audioPlayer: AudioPlayer | undefined) => void;
3
+ //# sourceMappingURL=useAudioPlaybackChangeAnnouncements.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useAudioPlaybackChangeAnnouncements.d.ts","sourceRoot":"","sources":["../../../../../src/components/Accessibility/hooks/useAudioPlaybackChangeAnnouncements.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAoB,MAAM,qBAAqB,CAAC;AASzE,eAAO,MAAM,mCAAmC,GAC9C,aAAa,WAAW,GAAG,SAAS,SAsBrC,CAAC"}
@@ -0,0 +1,44 @@
1
+ export type ReserveFocusReturnOptions = {
2
+ /**
3
+ * Explicit element focus should return to. Defaults to the current
4
+ * `document.activeElement` (the natural "origin" — e.g. the composer when a
5
+ * transient surface steals focus). Provide this when the desired return target
6
+ * is NOT where focus currently is. A non-focusable value (or `document.body`)
7
+ * reserves nothing.
8
+ */
9
+ target?: HTMLElement | null;
10
+ };
11
+ export type UseFocusReturnResult = {
12
+ /**
13
+ * Capture the element focus should return to. Called with no argument it
14
+ * captures the current `document.activeElement`; pass `{ target }` to override.
15
+ * Options is an object for forward-compatibility (future flags add fields here
16
+ * without changing the call signature).
17
+ */
18
+ reserve: (options?: ReserveFocusReturnOptions) => void;
19
+ /**
20
+ * Move focus back to the reserved element (if it is still connected) and clear
21
+ * the reservation. No-op when nothing was reserved or the element is gone.
22
+ * Focuses synchronously — defer announcements yourself if you need the focus
23
+ * announcement to be spoken first.
24
+ */
25
+ restore: () => void;
26
+ };
27
+ /**
28
+ * Generic focus-restoration primitive: capture-before-steal, restore-on-finish —
29
+ * the pattern dialogs/popovers use. A transient surface (e.g. the Giphy preview)
30
+ * `reserve()`s before it moves focus into itself, then `restore()`s when it
31
+ * completes, returning focus to wherever it was — WITHOUT the surface knowing or
32
+ * naming that element (no coupling to "the composer").
33
+ *
34
+ * Single-candidate by design: each consumer holds its own reservation in a ref,
35
+ * so concurrent/nested transient surfaces never clobber each other (each restores
36
+ * its own origin). There is one `document.activeElement` at a time, and these
37
+ * flows are mutually exclusive, so no shared slot/stack/key registry is needed.
38
+ * If a cross-component rendezvous or deep nesting ever appears, a stack (nesting)
39
+ * or coarse typed keys (rendezvous) can be added without changing this API.
40
+ *
41
+ * React 17/18/19 compatible — `useRef`/`useCallback` only.
42
+ */
43
+ export declare const useFocusReturn: () => UseFocusReturnResult;
44
+ //# sourceMappingURL=useFocusReturn.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useFocusReturn.d.ts","sourceRoot":"","sources":["../../../../../src/components/Accessibility/hooks/useFocusReturn.ts"],"names":[],"mappings":"AAEA,MAAM,MAAM,yBAAyB,GAAG;IACtC;;;;;;OAMG;IACH,MAAM,CAAC,EAAE,WAAW,GAAG,IAAI,CAAC;CAC7B,CAAC;AAEF,MAAM,MAAM,oBAAoB,GAAG;IACjC;;;;;OAKG;IACH,OAAO,EAAE,CAAC,OAAO,CAAC,EAAE,yBAAyB,KAAK,IAAI,CAAC;IACvD;;;;;OAKG;IACH,OAAO,EAAE,MAAM,IAAI,CAAC;CACrB,CAAC;AAKF;;;;;;;;;;;;;;;GAeG;AACH,eAAO,MAAM,cAAc,QAAO,oBAgBjC,CAAC"}
@@ -0,0 +1,88 @@
1
+ /**
2
+ * The set of props returned by {@link useInertWhenHidden}, to be spread onto the
3
+ * element that must remain mounted while visually hidden.
4
+ *
5
+ * `inert` is typed as `boolean | undefined` so the object spreads cleanly onto a
6
+ * JSX host element (React 19 types `inert?: boolean`; React 17/18 don't declare
7
+ * it at all, so an extra prop via spread is accepted). The RUNTIME value differs
8
+ * by React major version (string `'true'` on 17/18) — see the implementation
9
+ * note on {@link useInertWhenHidden} — and is cast to `boolean` at the source so
10
+ * the public type stays spread-safe. Consumers spread it; they never read it.
11
+ */
12
+ export type InertWhenHiddenProps = {
13
+ 'aria-hidden': true | undefined;
14
+ hidden: boolean | undefined;
15
+ inert: boolean | undefined;
16
+ tabIndex: number | undefined;
17
+ };
18
+ /**
19
+ * Options for {@link useInertWhenHidden}.
20
+ */
21
+ export type UseInertWhenHiddenOptions = {
22
+ /**
23
+ * Whether to set the HTML `hidden` attribute (which applies `display: none`)
24
+ * when `hidden` is `true`. Defaults to `true`.
25
+ *
26
+ * Set to `false` for elements whose visual hiding is already handled by CSS
27
+ * (e.g. an opacity/scale/`max-width` transition) — the `hidden` attribute
28
+ * would force `display: none` and kill the transition. With `false`, the hook
29
+ * still applies `aria-hidden`, `inert`, and `tabIndex={-1}` so the element is
30
+ * removed from the accessibility tree and tab order while staying laid out.
31
+ */
32
+ setHiddenAttribute?: boolean;
33
+ };
34
+ /**
35
+ * Canonical way to fully hide a control from assistive technology AND the tab
36
+ * order while it must stay mounted.
37
+ *
38
+ * @remarks
39
+ * **Prefer not rendering.** The simplest and most robust fix for a control that
40
+ * should be unavailable is to *not render it at all* when it is hidden. Reach
41
+ * for this hook only when the element MUST stay mounted — e.g. to preserve
42
+ * internal state, layout measurements, or enter/exit transitions.
43
+ *
44
+ * @example
45
+ * ```tsx
46
+ * const Toolbar = ({ collapsed }: { collapsed: boolean }) => {
47
+ * const inertProps = useInertWhenHidden(collapsed);
48
+ * return <button {...inertProps}>Add attachment</button>;
49
+ * };
50
+ * ```
51
+ *
52
+ * When `hidden === true`, the returned props make the element:
53
+ * - absent from the accessibility tree (`aria-hidden`, `hidden`),
54
+ * - unreachable via Tab (`tabIndex={-1}`, `inert`),
55
+ * - non-interactive (`inert`).
56
+ *
57
+ * When `hidden === false`, every returned attribute is `undefined`, so spreading
58
+ * the object is a no-op and the element behaves exactly as normal. In
59
+ * particular, `aria-hidden` is omitted entirely (never emitted as
60
+ * `aria-hidden="false"`).
61
+ *
62
+ * Exact attribute values rendered to the DOM:
63
+ * - hidden: `aria-hidden=""(true)`, `hidden`, `tabindex="-1"`, `inert`
64
+ * - shown: none of the above attributes present
65
+ *
66
+ * **Cross-React-version handling of `inert`:** React 19 supports `inert` as a
67
+ * native boolean prop (`inert={true}` → DOM `inert=""`). React 17/18 do not
68
+ * recognize it and only forward it as a string (`inert="true"` → DOM
69
+ * `inert="true"`). Either of the *other* forms (a boolean on React 17/18, or an
70
+ * empty string on React 19) emits a console warning and/or drops the attribute.
71
+ * We therefore pick the correct form per major version via `React.version`. The
72
+ * resulting DOM attribute is present and falls back to `tabIndex={-1}` +
73
+ * `aria-hidden` on the rare engines lacking `inert` support.
74
+ *
75
+ * **Styling is out of scope.** The HTML `hidden` attribute applies
76
+ * `display: none`. If a consumer needs the element to remain *visible in the
77
+ * layout* (e.g. hidden purely via CSS or kept for transitions), pass
78
+ * `{ setHiddenAttribute: false }` so the `hidden` attribute is omitted while the
79
+ * a11y/focus semantics (`aria-hidden`, `inert`, `tabIndex={-1}`) still apply.
80
+ * The remaining styling is then the consumer's concern.
81
+ *
82
+ * @param hidden Whether the control is currently hidden.
83
+ * @param options Behavior options — see {@link UseInertWhenHiddenOptions}. Use
84
+ * `{ setHiddenAttribute: false }` for elements hidden via CSS/transition.
85
+ * @returns A stable, memoized props object to spread onto the element.
86
+ */
87
+ export declare const useInertWhenHidden: (hidden: boolean, options?: UseInertWhenHiddenOptions) => InertWhenHiddenProps;
88
+ //# sourceMappingURL=useInertWhenHidden.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useInertWhenHidden.d.ts","sourceRoot":"","sources":["../../../../../src/components/Accessibility/hooks/useInertWhenHidden.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;GAUG;AACH,MAAM,MAAM,oBAAoB,GAAG;IACjC,aAAa,EAAE,IAAI,GAAG,SAAS,CAAC;IAChC,MAAM,EAAE,OAAO,GAAG,SAAS,CAAC;IAC5B,KAAK,EAAE,OAAO,GAAG,SAAS,CAAC;IAC3B,QAAQ,EAAE,MAAM,GAAG,SAAS,CAAC;CAC9B,CAAC;AAqCF;;GAEG;AACH,MAAM,MAAM,yBAAyB,GAAG;IACtC;;;;;;;;;OASG;IACH,kBAAkB,CAAC,EAAE,OAAO,CAAC;CAC9B,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoDG;AACH,eAAO,MAAM,kBAAkB,GAC7B,QAAQ,OAAO,EACf,UAAU,yBAAyB,KAClC,oBAMF,CAAC"}
@@ -0,0 +1,114 @@
1
+ /**
2
+ * Optional delivery overrides a call site may pass ALONGSIDE an interaction's message params.
3
+ * These are not consumed by the message resolver — they only affect how the announcement is
4
+ * delivered. `debounceMs` overrides that interaction's default debounce ({@link
5
+ * INTERACTION_DEBOUNCE_MS}) for THIS call, and enables debouncing for an interaction that has no
6
+ * default. `delayMs` overrides the default delay ({@link INTERACTION_DELAY_MS}) for the
7
+ * (non-debounced) immediate path. Param-less (discrete) interactions are always immediate and do
8
+ * not accept overrides.
9
+ *
10
+ * `debounceMs` vs `delayMs`: a debounce collapses rapid repeats on a per-call-site timer and is
11
+ * **cancelled if that call site unmounts** — right for a value that keeps changing in place (a
12
+ * result count). `delayMs` schedules a single deferred emit in the shared announcer PROVIDER, so it
13
+ * **survives the caller unmounting** — right for a one-shot confirmation whose origin (e.g. a list
14
+ * row) disappears on the very action being confirmed (opening a channel/thread hides the list on
15
+ * mobile). Both let the message land after a competing focus/typing read-out. `debounceMs` wins if
16
+ * both are given.
17
+ */
18
+ export type InteractionDeliveryOptions = {
19
+ debounceMs?: number;
20
+ delayMs?: number;
21
+ };
22
+ /**
23
+ * Parameters accepted by each parameterized interaction announcement.
24
+ * Interactions that take no parameters map to `undefined`. Param-ful interactions additionally
25
+ * accept {@link InteractionDeliveryOptions} (e.g. a per-call `debounceMs`).
26
+ */
27
+ export type InteractionAnnouncementParams = {
28
+ /** Audio playback speed was changed via the playback-rate button. `rate` is the new multiplier. */
29
+ 'audioPlayer.playbackRateChanged': InteractionDeliveryOptions & {
30
+ rate: number;
31
+ };
32
+ /** A channel was opened from the channel list. `name` is its display title. */
33
+ 'channel.opened': InteractionDeliveryOptions & {
34
+ name: string;
35
+ };
36
+ /** A slash command was activated from the Instant Commands menu. `command` is its name. */
37
+ 'command.selected': InteractionDeliveryOptions & {
38
+ command: string;
39
+ };
40
+ 'giphy.canceled': undefined;
41
+ 'giphy.sent': undefined;
42
+ 'giphy.shuffled': InteractionDeliveryOptions & {
43
+ title?: string;
44
+ };
45
+ 'poll.dialogOpened': undefined;
46
+ /** A poll option was dropped at a new position during keyboard reorder. */
47
+ 'poll.optionDropped': InteractionDeliveryOptions & {
48
+ option: string;
49
+ position: number;
50
+ };
51
+ /** A poll option was picked up to start a keyboard reorder. `option` is its text (or a fallback). */
52
+ 'poll.optionPickedUp': InteractionDeliveryOptions & {
53
+ option: string;
54
+ };
55
+ 'poll.optionRemoved': InteractionDeliveryOptions & {
56
+ option: string;
57
+ };
58
+ 'poll.sent': undefined;
59
+ 'search.cleared': undefined;
60
+ 'search.resultCount': InteractionDeliveryOptions & {
61
+ /** Whether every active source is fully loaded — appends an "all results loaded" clause. */
62
+ allResultsLoaded?: boolean;
63
+ count: number;
64
+ };
65
+ 'suggestions.count': InteractionDeliveryOptions & {
66
+ count: number;
67
+ suggestionsLabel?: string;
68
+ };
69
+ /** A thread was opened from the thread list. `name` is its channel's display title. */
70
+ 'thread.opened': InteractionDeliveryOptions & {
71
+ name: string;
72
+ };
73
+ 'user.selected': InteractionDeliveryOptions & {
74
+ user: string;
75
+ };
76
+ /** A finished voice recording was added to the composer (async multi-send: not sent yet). */
77
+ 'voiceRecording.attached': undefined;
78
+ 'voiceRecording.paused': undefined;
79
+ 'voiceRecording.resumed': undefined;
80
+ /** A finished voice recording was sent immediately as a message. */
81
+ 'voiceRecording.sent': undefined;
82
+ 'voiceRecording.started': undefined;
83
+ };
84
+ export type InteractionAnnouncementType = keyof InteractionAnnouncementParams;
85
+ type AnnounceInteraction = {
86
+ <T extends InteractionAnnouncementType>(interaction: InteractionAnnouncementParams[T] extends undefined ? T : never): void;
87
+ <T extends InteractionAnnouncementType>(interaction: InteractionAnnouncementParams[T] extends undefined ? never : T, params: InteractionAnnouncementParams[T]): void;
88
+ };
89
+ export type UseInteractionAnnouncementsValue = {
90
+ /**
91
+ * Announce a predefined interaction event to assistive technology. The
92
+ * interaction name maps to a localized message and a baked-in aria-live
93
+ * priority.
94
+ */
95
+ announceInteraction: AnnounceInteraction;
96
+ /**
97
+ * Cancel pending (debounced, not-yet-spoken) announcements: a single `interaction`, or all when
98
+ * omitted. Call this when the source of a debounced announcement is torn down (e.g. search exited)
99
+ * so a queued message is not spoken after its context is gone. An announcement already emitted into
100
+ * the live region cannot be recalled.
101
+ */
102
+ cancelInteraction: (interaction?: InteractionAnnouncementType) => void;
103
+ };
104
+ /**
105
+ * Thin, typed wrapper over the aria-live announcer exposing intention-revealing
106
+ * helpers for transient, user-initiated UI interactions (e.g. a Giphy being
107
+ * sent, a poll being created, a mention being picked). They map to i18n keys with
108
+ * baked-in priorities and reuse the existing live region via
109
+ * {@link useAriaLiveAnnouncer}. New interactions are registered as a single entry
110
+ * in {@link INTERACTION_MESSAGES}.
111
+ */
112
+ export declare const useInteractionAnnouncements: () => UseInteractionAnnouncementsValue;
113
+ export {};
114
+ //# sourceMappingURL=useInteractionAnnouncements.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useInteractionAnnouncements.d.ts","sourceRoot":"","sources":["../../../../../src/components/Accessibility/hooks/useInteractionAnnouncements.ts"],"names":[],"mappings":"AASA;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,MAAM,0BAA0B,GAAG;IAAE,UAAU,CAAC,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC;AAEnF;;;;GAIG;AACH,MAAM,MAAM,6BAA6B,GAAG;IAC1C,mGAAmG;IACnG,iCAAiC,EAAE,0BAA0B,GAAG;QAAE,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC;IACjF,+EAA+E;IAC/E,gBAAgB,EAAE,0BAA0B,GAAG;QAAE,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC;IAChE,2FAA2F;IAC3F,kBAAkB,EAAE,0BAA0B,GAAG;QAAE,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC;IACrE,gBAAgB,EAAE,SAAS,CAAC;IAC5B,YAAY,EAAE,SAAS,CAAC;IACxB,gBAAgB,EAAE,0BAA0B,GAAG;QAAE,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IAClE,mBAAmB,EAAE,SAAS,CAAC;IAC/B,2EAA2E;IAC3E,oBAAoB,EAAE,0BAA0B,GAAG;QACjD,MAAM,EAAE,MAAM,CAAC;QACf,QAAQ,EAAE,MAAM,CAAC;KAClB,CAAC;IACF,qGAAqG;IACrG,qBAAqB,EAAE,0BAA0B,GAAG;QAAE,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC;IACvE,oBAAoB,EAAE,0BAA0B,GAAG;QAAE,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC;IACtE,WAAW,EAAE,SAAS,CAAC;IACvB,gBAAgB,EAAE,SAAS,CAAC;IAC5B,oBAAoB,EAAE,0BAA0B,GAAG;QACjD,4FAA4F;QAC5F,gBAAgB,CAAC,EAAE,OAAO,CAAC;QAC3B,KAAK,EAAE,MAAM,CAAC;KACf,CAAC;IACF,mBAAmB,EAAE,0BAA0B,GAAG;QAChD,KAAK,EAAE,MAAM,CAAC;QACd,gBAAgB,CAAC,EAAE,MAAM,CAAC;KAC3B,CAAC;IACF,uFAAuF;IACvF,eAAe,EAAE,0BAA0B,GAAG;QAAE,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC;IAC/D,eAAe,EAAE,0BAA0B,GAAG;QAAE,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC;IAC/D,6FAA6F;IAC7F,yBAAyB,EAAE,SAAS,CAAC;IACrC,uBAAuB,EAAE,SAAS,CAAC;IACnC,wBAAwB,EAAE,SAAS,CAAC;IACpC,oEAAoE;IACpE,qBAAqB,EAAE,SAAS,CAAC;IACjC,wBAAwB,EAAE,SAAS,CAAC;CACrC,CAAC;AAEF,MAAM,MAAM,2BAA2B,GAAG,MAAM,6BAA6B,CAAC;AAgL9E,KAAK,mBAAmB,GAAG;IACzB,CAAC,CAAC,SAAS,2BAA2B,EACpC,WAAW,EAAE,6BAA6B,CAAC,CAAC,CAAC,SAAS,SAAS,GAAG,CAAC,GAAG,KAAK,GAC1E,IAAI,CAAC;IACR,CAAC,CAAC,SAAS,2BAA2B,EACpC,WAAW,EAAE,6BAA6B,CAAC,CAAC,CAAC,SAAS,SAAS,GAAG,KAAK,GAAG,CAAC,EAC3E,MAAM,EAAE,6BAA6B,CAAC,CAAC,CAAC,GACvC,IAAI,CAAC;CACT,CAAC;AAEF,MAAM,MAAM,gCAAgC,GAAG;IAC7C;;;;OAIG;IACH,mBAAmB,EAAE,mBAAmB,CAAC;IACzC;;;;;OAKG;IACH,iBAAiB,EAAE,CAAC,WAAW,CAAC,EAAE,2BAA2B,KAAK,IAAI,CAAC;CACxE,CAAC;AAEF;;;;;;;GAOG;AACH,eAAO,MAAM,2BAA2B,QAAO,gCA6E9C,CAAC"}
@@ -1,5 +1,11 @@
1
- export * from './AriaLiveRegion';
1
+ export * from './AriaLiveAnnouncerProvider';
2
+ export * from './AriaLiveOutlet';
3
+ export * from './AriaLiveOutletContext';
2
4
  export * from './NotificationAnnouncer';
5
+ export * from './scheduling';
6
+ export * from './hooks/useFocusReturn';
3
7
  export * from './hooks/useIncomingMessageAnnouncements';
8
+ export * from './hooks/useInertWhenHidden';
9
+ export * from './hooks/useInteractionAnnouncements';
4
10
  export * from './useAriaLiveAnnouncer';
5
11
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/components/Accessibility/index.ts"],"names":[],"mappings":"AAAA,cAAc,kBAAkB,CAAC;AACjC,cAAc,yBAAyB,CAAC;AACxC,cAAc,yCAAyC,CAAC;AACxD,cAAc,wBAAwB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/components/Accessibility/index.ts"],"names":[],"mappings":"AAAA,cAAc,6BAA6B,CAAC;AAC5C,cAAc,kBAAkB,CAAC;AACjC,cAAc,yBAAyB,CAAC;AACxC,cAAc,yBAAyB,CAAC;AACxC,cAAc,cAAc,CAAC;AAC7B,cAAc,wBAAwB,CAAC;AACvC,cAAc,yCAAyC,CAAC;AACxD,cAAc,4BAA4B,CAAC;AAC3C,cAAc,qCAAqC,CAAC;AACpD,cAAc,wBAAwB,CAAC"}
@@ -0,0 +1,4 @@
1
+ export * from './useAnnouncementQueue';
2
+ export * from './useDebouncedAnnounce';
3
+ export * from './useSettledAnnouncement';
4
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/components/Accessibility/scheduling/index.ts"],"names":[],"mappings":"AAAA,cAAc,wBAAwB,CAAC;AACvC,cAAc,wBAAwB,CAAC;AACvC,cAAc,0BAA0B,CAAC"}
@@ -0,0 +1,25 @@
1
+ import type { AriaLiveAnnounce, AriaLivePriority } from '../useAriaLiveAnnouncer';
2
+ export type QueuedAnnouncement = {
3
+ message: string;
4
+ priority?: AriaLivePriority;
5
+ };
6
+ export type UseAnnouncementQueueOptions = {
7
+ /** Minimum delay between successive announcements, in ms. Defaults to 150. */
8
+ gapMs?: number;
9
+ };
10
+ export type UseAnnouncementQueueResult = {
11
+ /** Enqueue an announcement. The first drains immediately; the rest are paced by `gapMs`. */
12
+ enqueue: (announcement: QueuedAnnouncement) => void;
13
+ };
14
+ /**
15
+ * L2 scheduling policy: announce queued messages one at a time, spaced by `gapMs`, through the
16
+ * provided `announce` (from `useAriaLiveAnnouncer`). Replaces per-consumer queue/timer
17
+ * bookkeeping (e.g. the old `NotificationAnnouncer` state machine). The unified announcer already
18
+ * appends a fresh node per call, so no "clear region first" trick is needed — the gap simply
19
+ * prevents successive messages from clobbering each other in the screen-reader buffer.
20
+ *
21
+ * React 17/18/19 compatible — `useCallback`/`useRef`/`useEffect` only. Pending timers and the
22
+ * queue are cleared on unmount.
23
+ */
24
+ export declare const useAnnouncementQueue: (announce: AriaLiveAnnounce, { gapMs }?: UseAnnouncementQueueOptions) => UseAnnouncementQueueResult;
25
+ //# sourceMappingURL=useAnnouncementQueue.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useAnnouncementQueue.d.ts","sourceRoot":"","sources":["../../../../../src/components/Accessibility/scheduling/useAnnouncementQueue.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAElF,MAAM,MAAM,kBAAkB,GAAG;IAC/B,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,gBAAgB,CAAC;CAC7B,CAAC;AAEF,MAAM,MAAM,2BAA2B,GAAG;IACxC,8EAA8E;IAC9E,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,CAAC;AAEF,MAAM,MAAM,0BAA0B,GAAG;IACvC,4FAA4F;IAC5F,OAAO,EAAE,CAAC,YAAY,EAAE,kBAAkB,KAAK,IAAI,CAAC;CACrD,CAAC;AAIF;;;;;;;;;GASG;AACH,eAAO,MAAM,oBAAoB,GAC/B,UAAU,gBAAgB,EAC1B,YAA4B,2BAAgC,KAC3D,0BAwCF,CAAC"}