@astryxdesign/core 0.7.3 → 0.7.4-canary.1a552f2

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 (143) hide show
  1. package/dist/BottomSheet/BottomSheet.d.ts +18 -6
  2. package/dist/BottomSheet/BottomSheet.d.ts.map +1 -1
  3. package/dist/BottomSheet/BottomSheet.js +268 -58
  4. package/dist/BottomSheet/BottomSheetSwitcher.d.ts +41 -12
  5. package/dist/BottomSheet/BottomSheetSwitcher.d.ts.map +1 -1
  6. package/dist/BottomSheet/BottomSheetSwitcher.js +294 -165
  7. package/dist/BottomSheet/BottomSheetSwitcherContext.d.ts +51 -1
  8. package/dist/BottomSheet/BottomSheetSwitcherContext.d.ts.map +1 -1
  9. package/dist/BottomSheet/BottomSheetSwitcherContext.js +13 -1
  10. package/dist/Carousel/Carousel.d.ts.map +1 -1
  11. package/dist/Carousel/Carousel.js +7 -11
  12. package/dist/Chat/ChatMessageList.d.ts.map +1 -1
  13. package/dist/Chat/ChatMessageList.js +8 -1
  14. package/dist/Chat/useTriggerMenu.d.ts.map +1 -1
  15. package/dist/Chat/useTriggerMenu.js +46 -7
  16. package/dist/CheckboxInput/CheckboxInput.d.ts.map +1 -1
  17. package/dist/CheckboxInput/CheckboxInput.js +6 -0
  18. package/dist/CommandPalette/CommandPalette.d.ts.map +1 -1
  19. package/dist/CommandPalette/CommandPalette.js +6 -11
  20. package/dist/CommandPalette/CommandPaletteInput.d.ts.map +1 -1
  21. package/dist/CommandPalette/CommandPaletteInput.js +7 -1
  22. package/dist/ComplexSelector/ComplexSelector.d.ts.map +1 -1
  23. package/dist/ComplexSelector/ComplexSelector.js +6 -1
  24. package/dist/ContextMenu/ContextMenu.d.ts.map +1 -1
  25. package/dist/ContextMenu/ContextMenu.js +12 -0
  26. package/dist/DateInput/DateInput.d.ts.map +1 -1
  27. package/dist/DateInput/DateInput.js +6 -1
  28. package/dist/DateInput/NativeDateField.d.ts.map +1 -1
  29. package/dist/DateInput/NativeDateField.js +6 -1
  30. package/dist/DateInput/TouchDateField.d.ts.map +1 -1
  31. package/dist/DateInput/TouchDateField.js +9 -1
  32. package/dist/DateRangeInput/DateRangeInput.d.ts.map +1 -1
  33. package/dist/DateRangeInput/DateRangeInput.js +6 -1
  34. package/dist/DateTimeInput/DateTimeInput.d.ts.map +1 -1
  35. package/dist/DateTimeInput/DateTimeInput.js +6 -1
  36. package/dist/DateTimeInput/TouchDateTimeField.d.ts.map +1 -1
  37. package/dist/DateTimeInput/TouchDateTimeField.js +9 -1
  38. package/dist/DropdownMenu/DropdownMenuSubMenu.d.ts.map +1 -1
  39. package/dist/DropdownMenu/DropdownMenuSubMenu.js +7 -1
  40. package/dist/FileInput/FileInput.d.ts.map +1 -1
  41. package/dist/FileInput/FileInput.js +16 -2
  42. package/dist/MultiSelector/MultiSelector.d.ts.map +1 -1
  43. package/dist/MultiSelector/MultiSelector.js +6 -1
  44. package/dist/Selector/Selector.d.ts.map +1 -1
  45. package/dist/Selector/Selector.js +6 -1
  46. package/dist/TextArea/TextArea.d.ts.map +1 -1
  47. package/dist/TextArea/TextArea.js +6 -1
  48. package/dist/TextInput/TextInput.d.ts.map +1 -1
  49. package/dist/TextInput/TextInput.js +6 -1
  50. package/dist/Thumbnail/Thumbnail.d.ts.map +1 -1
  51. package/dist/Thumbnail/Thumbnail.js +9 -2
  52. package/dist/TimeInput/TimeInput.d.ts.map +1 -1
  53. package/dist/TimeInput/TimeInput.js +6 -1
  54. package/dist/TimeInput/TouchTimeField.d.ts.map +1 -1
  55. package/dist/TimeInput/TouchTimeField.js +9 -1
  56. package/dist/Tokenizer/Tokenizer.d.ts.map +1 -1
  57. package/dist/Tokenizer/Tokenizer.js +9 -1
  58. package/dist/Typeahead/BaseTypeahead.d.ts.map +1 -1
  59. package/dist/Typeahead/BaseTypeahead.js +7 -1
  60. package/dist/Typeahead/Typeahead.d.ts.map +1 -1
  61. package/dist/Typeahead/Typeahead.js +9 -1
  62. package/dist/astryx.css +2 -0
  63. package/dist/hooks/useBusyAnnouncement.d.ts +22 -0
  64. package/dist/hooks/useBusyAnnouncement.d.ts.map +1 -0
  65. package/dist/hooks/useBusyAnnouncement.js +87 -0
  66. package/dist/hooks/useMenuPress.d.ts +2 -2
  67. package/dist/hooks/useMenuPress.d.ts.map +1 -1
  68. package/dist/hooks/useMenuPress.js +5 -1
  69. package/dist/hooks/useTypeahead.d.ts.map +1 -1
  70. package/dist/hooks/useTypeahead.js +7 -2
  71. package/dist/i18n/generated-locales/en.generated.d.ts.map +1 -1
  72. package/dist/i18n/generated-locales/en.generated.js +1 -0
  73. package/dist/i18n/generated-locales/pseudo.generated.d.ts.map +1 -1
  74. package/dist/i18n/generated-locales/pseudo.generated.js +1 -0
  75. package/locales/en.json +6 -2
  76. package/locales/pseudo.json +3 -0
  77. package/package.json +4 -4
  78. package/src/BottomSheet/BottomSheet.doc.mjs +2 -2
  79. package/src/BottomSheet/BottomSheet.spec.md +3 -5
  80. package/src/BottomSheet/BottomSheet.tsx +260 -47
  81. package/src/BottomSheet/BottomSheetEdgeTint.test.tsx +29 -4
  82. package/src/BottomSheet/BottomSheetSwitcher.doc.mjs +11 -10
  83. package/src/BottomSheet/BottomSheetSwitcher.spec.md +35 -41
  84. package/src/BottomSheet/BottomSheetSwitcher.test.tsx +1051 -49
  85. package/src/BottomSheet/BottomSheetSwitcher.tsx +396 -215
  86. package/src/BottomSheet/BottomSheetSwitcherContext.ts +57 -2
  87. package/src/BottomSheet/__tests__/BottomSheetNativeModal.a11y.browser.spec.ts +461 -0
  88. package/src/Carousel/Carousel.test.tsx +8 -12
  89. package/src/Carousel/Carousel.tsx +6 -13
  90. package/src/Chat/ChatComposerInput.test.tsx +167 -1
  91. package/src/Chat/ChatMessageList.test.tsx +6 -2
  92. package/src/Chat/ChatMessageList.tsx +7 -1
  93. package/src/Chat/__tests__/ChatMessageList.a11y.chromium.spec.ts +20 -12
  94. package/src/Chat/useTriggerMenu.tsx +55 -6
  95. package/src/CheckboxInput/CheckboxInput.tsx +6 -0
  96. package/src/CommandPalette/CommandPalette.test.tsx +4 -2
  97. package/src/CommandPalette/CommandPalette.tsx +6 -11
  98. package/src/CommandPalette/CommandPaletteInput.test.tsx +3 -1
  99. package/src/CommandPalette/CommandPaletteInput.tsx +10 -1
  100. package/src/ComplexSelector/ComplexSelector.tsx +5 -1
  101. package/src/ContextMenu/ContextMenu.test.tsx +34 -0
  102. package/src/ContextMenu/ContextMenu.tsx +13 -1
  103. package/src/DateInput/DateInput.tsx +5 -1
  104. package/src/DateInput/DateInputTouch.test.tsx +45 -0
  105. package/src/DateInput/NativeDateField.test.tsx +10 -2
  106. package/src/DateInput/NativeDateField.tsx +5 -1
  107. package/src/DateInput/TouchDateField.tsx +14 -2
  108. package/src/DateRangeInput/DateRangeInput.tsx +5 -1
  109. package/src/DateTimeInput/DateTimeInput.tsx +5 -1
  110. package/src/DateTimeInput/TouchDateTimeField.tsx +14 -2
  111. package/src/DropdownMenu/DropdownMenuSubMenu.tsx +10 -1
  112. package/src/FileInput/FileInput.tsx +18 -2
  113. package/src/MultiSelector/MultiSelector.test.tsx +18 -4
  114. package/src/MultiSelector/MultiSelector.tsx +5 -1
  115. package/src/ProgressBar/ProgressBar.test.tsx +4 -21
  116. package/src/ProgressBar/__tests__/ProgressBar.a11y.chromium.spec.ts +114 -0
  117. package/src/ProgressBar/__tests__/ProgressBar.a11y.known-failures.ts +12 -0
  118. package/src/ProgressBar/__tests__/ProgressBar.a11y.renders.tsx +38 -0
  119. package/src/ProgressBar/__tests__/ProgressBar.a11y.states.ts +123 -0
  120. package/src/ProgressBar/__tests__/ProgressBar.a11y.test.tsx +107 -0
  121. package/src/Selector/Selector.test.tsx +22 -5
  122. package/src/Selector/Selector.tsx +5 -1
  123. package/src/TextArea/TextArea.test.tsx +9 -1
  124. package/src/TextArea/TextArea.tsx +5 -1
  125. package/src/TextInput/TextInput.tsx +5 -1
  126. package/src/Thumbnail/Thumbnail.test.tsx +6 -1
  127. package/src/Thumbnail/Thumbnail.tsx +12 -3
  128. package/src/TimeInput/TimeInput.tsx +5 -1
  129. package/src/TimeInput/TouchTimeField.tsx +12 -2
  130. package/src/Tokenizer/Tokenizer.test.tsx +17 -12
  131. package/src/Tokenizer/Tokenizer.tsx +10 -1
  132. package/src/Typeahead/BaseTypeahead.tsx +14 -1
  133. package/src/Typeahead/Typeahead.test.tsx +32 -41
  134. package/src/Typeahead/Typeahead.tsx +10 -1
  135. package/src/__tests__/BusyOwnerAnnouncement.test.tsx +792 -0
  136. package/src/hooks/__tests__/MenuPressShadowRoot.a11y.chromium.spec.ts +50 -0
  137. package/src/hooks/useBusyAnnouncement.ts +100 -0
  138. package/src/hooks/useMenuPress.test.tsx +27 -1
  139. package/src/hooks/useMenuPress.ts +12 -3
  140. package/src/hooks/useTypeahead.test.tsx +42 -1
  141. package/src/hooks/useTypeahead.ts +7 -2
  142. package/src/i18n/generated-locales/en.generated.ts +1 -0
  143. package/src/i18n/generated-locales/pseudo.generated.ts +1 -0
@@ -36,6 +36,7 @@ import { warnOnce } from "../utils/devWarning.js";
36
36
  import { themeProps } from "../utils/themeProps.js";
37
37
  import { useTranslator } from "../i18n/index.js";
38
38
  import { useMergedRefs } from "../hooks/useMergedRefs.js";
39
+ import { useBusyAnnouncement } from "../hooks/useBusyAnnouncement.js";
39
40
  import "../Layer/layerViewportInset.stylex.js";
40
41
  import { layerViewportInset } from "../Layer/layerViewportInset.stylex.js";
41
42
  import { clampInlineSize } from "../Layer/clampInlineSize.js";
@@ -277,6 +278,10 @@ export const BaseTypeahead = function BaseTypeahead({
277
278
  // A wrapper that owns the inline-end lane subscribes through context; see
278
279
  // busyIndicatorLane.tsx for why this is not a prop.
279
280
  const busyLane = useBusyIndicatorLane();
281
+ // Without a wrapper that took the indicator over, this input announces each
282
+ // search's busy start (spec:AST-086 FR8); its Spinner stays named but is not
283
+ // a live region (family:input-fields FR7).
284
+ useBusyAnnouncement(isLoading && busyLane == null, t('@astryx.typeahead.loading'), inputRef);
280
285
  const onLoadingChangeRef = useRef(busyLane?.onBusyChange);
281
286
  useIsomorphicLayoutEffect(() => {
282
287
  onLoadingChangeRef.current = busyLane?.onBusyChange;
@@ -805,7 +810,8 @@ export const BaseTypeahead = function BaseTypeahead({
805
810
  },
806
811
  children: /*#__PURE__*/_jsx(Spinner, {
807
812
  size: "sm",
808
- "aria-label": t('@astryx.typeahead.loading')
813
+ "aria-label": t('@astryx.typeahead.loading'),
814
+ role: "img"
809
815
  })
810
816
  }), popover.render(/*#__PURE__*/_jsx("div", {
811
817
  id: listboxId,
@@ -1 +1 @@
1
- {"version":3,"file":"Typeahead.d.ts","sourceRoot":"","sources":["../../src/Typeahead/Typeahead.tsx"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"Typeahead.d.ts","sourceRoot":"","sources":["../../src/Typeahead/Typeahead.tsx"],"names":[],"mappings":"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"}
@@ -38,6 +38,7 @@ import { useFieldInputStyling } from "../Field/fieldParts.js";
38
38
  import { themeProps } from "../utils/themeProps.js";
39
39
  import { useTranslator } from "../i18n/index.js";
40
40
  import { useMergedRefs } from "../hooks/useMergedRefs.js";
41
+ import { useBusyAnnouncement } from "../hooks/useBusyAnnouncement.js";
41
42
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
42
43
  // =============================================================================
43
44
  // Styles
@@ -123,9 +124,14 @@ const wrapperSizeStyles = {
123
124
  function EndLane({
124
125
  lane,
125
126
  loadingLabel,
127
+ anchorRef,
126
128
  clear
127
129
  }) {
128
130
  const isBusy = useIsBusy(lane);
131
+ // The search Spinner stays named (family:input-fields FR7) but is not a
132
+ // live region; the field announces each search's busy start instead
133
+ // (spec:AST-086 FR8).
134
+ useBusyAnnouncement(isBusy, loadingLabel, anchorRef);
129
135
  if (!isBusy && clear == null) {
130
136
  return null;
131
137
  }
@@ -135,7 +141,8 @@ function EndLane({
135
141
  },
136
142
  children: [isBusy && /*#__PURE__*/_jsx(Spinner, {
137
143
  size: "sm",
138
- "aria-label": loadingLabel
144
+ "aria-label": loadingLabel,
145
+ role: "img"
139
146
  }), clear]
140
147
  });
141
148
  }
@@ -417,6 +424,7 @@ export function Typeahead({
417
424
  }), /*#__PURE__*/_jsx(EndLane, {
418
425
  lane: busyLane,
419
426
  loadingLabel: t('@astryx.typeahead.loading'),
427
+ anchorRef: wrapperRef,
420
428
  clear: hasClear && value && !isDisabled ? /*#__PURE__*/_jsx(InputClearButton, {
421
429
  label: t('@astryx.typeahead.clearSelection'),
422
430
  onClick: e => {
package/dist/astryx.css CHANGED
@@ -2185,6 +2185,7 @@
2185
2185
  .x142juwg:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#):not(#\#):not(#\#)::backdrop{transition-behavior:allow-discrete}
2186
2186
  .xizoc3:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#):not(#\#):not(#\#)::before{transition-delay:var(--x-owu7oy)}
2187
2187
  .x18w5vxb:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#):not(#\#):not(#\#)::after{transition-duration:var(--_press-overlay-transition)}
2188
+ .x10buo38:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#):not(#\#):not(#\#)::backdrop{transition-duration:var(--_sheet-scrim-duration,var(--duration-medium))}
2188
2189
  .x1y1nw7a:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#):not(#\#):not(#\#)::before{transition-duration:var(--duration-fast)}
2189
2190
  .xft5bk6:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#):not(#\#):not(#\#)::backdrop{transition-duration:var(--duration-medium)}
2190
2191
  .xuhr57t:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#):not(#\#):not(#\#)::before{transition-duration:var(--duration-medium)}
@@ -2211,6 +2212,7 @@
2211
2212
  @media (prefers-reduced-motion: reduce){.xhhm9v0.xhhm9v0:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#):not(#\#):not(#\#)::before{transition-delay:0s}}
2212
2213
  @media (prefers-reduced-motion: reduce){.x1viac0w.x1viac0w:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#):not(#\#):not(#\#)::backdrop{transition-duration:.01s}}
2213
2214
  @media (prefers-reduced-motion: reduce){.x13sdc92.x13sdc92:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#):not(#\#):not(#\#)::before{transition-duration:0s}}
2215
+ @media (prefers-reduced-motion: reduce){.x15l12jy.x15l12jy:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#):not(#\#):not(#\#)::backdrop{transition-duration:var(--_sheet-scrim-duration,.01s)}}
2214
2216
  @media (pointer: coarse){.x1gybruy.x1gybruy.x1gybruy:where(.x1odsvnm:active *):not(#\#):not(#\#):not(#\#):not(#\#):not(#\#):not(#\#):not(#\#)::after{background-color:transparent}}
2215
2217
  @media (pointer: coarse){.xapkq76.xapkq76.xapkq76:where(.x1odsvnm:active:not(:has(a:active,button:active,[role="button"]:active,[role="link"]:active)) *):not(#\#):not(#\#):not(#\#):not(#\#):not(#\#):not(#\#):not(#\#)::after{background-color:transparent}}
2216
2218
  @media (pointer: coarse){.x1ikgzpo.x1ikgzpo.x1ikgzpo:where(.x1odsvnm[data-astryx-press="on"] *):not(#\#):not(#\#):not(#\#):not(#\#):not(#\#):not(#\#):not(#\#)::after{background-image:var(--_press-paint-image)}}
@@ -0,0 +1,22 @@
1
+ /**
2
+ * @file useBusyAnnouncement.ts
3
+ * @input Whether the owning control is busy, the words to announce, and a ref
4
+ * to an element inside the control
5
+ * @output Announces each busy start once, through the shared polite channel
6
+ * or a persistent region inside the open modal dialog holding the control
7
+ * @position Core a11y hook for controls that show a decorative busy Spinner
8
+ *
9
+ * The busy Spinner inside a control is decorative (hidden, no live role); the
10
+ * control announces its busy state instead (`spec:AST-086` FR8), once per busy
11
+ * start (FR6): rerenders and StrictMode replay do not repeat it, and settling
12
+ * re-arms it. While a native modal is open, the body-level channel is not
13
+ * exposed, so a control inside it announces through one persistent polite
14
+ * region in that dialog, inserted empty and filled a frame later (Platform
15
+ * support, FR3).
16
+ *
17
+ * SYNC: deliberately NOT exported from /packages/core/src/hooks/index.ts —
18
+ * this is a shared implementation detail of Astryx's busy controls.
19
+ */
20
+ import { type RefObject } from 'react';
21
+ export declare function useBusyAnnouncement(isBusy: boolean, message: string, elementRef: RefObject<Element | null>): void;
22
+ //# sourceMappingURL=useBusyAnnouncement.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useBusyAnnouncement.d.ts","sourceRoot":"","sources":["../../src/hooks/useBusyAnnouncement.ts"],"names":[],"mappings":"AAIA;;;;;;;;;;;;;;;;;;GAkBG;AAEH,OAAO,EAAoB,KAAK,SAAS,EAAC,MAAM,OAAO,CAAC;AA+CxD,wBAAgB,mBAAmB,CACjC,MAAM,EAAE,OAAO,EACf,OAAO,EAAE,MAAM,EACf,UAAU,EAAE,SAAS,CAAC,OAAO,GAAG,IAAI,CAAC,GACpC,IAAI,CAwBN"}
@@ -0,0 +1,87 @@
1
+ // Copyright (c) Meta Platforms, Inc. and affiliates.
2
+
3
+ 'use client';
4
+
5
+ /**
6
+ * @file useBusyAnnouncement.ts
7
+ * @input Whether the owning control is busy, the words to announce, and a ref
8
+ * to an element inside the control
9
+ * @output Announces each busy start once, through the shared polite channel
10
+ * or a persistent region inside the open modal dialog holding the control
11
+ * @position Core a11y hook for controls that show a decorative busy Spinner
12
+ *
13
+ * The busy Spinner inside a control is decorative (hidden, no live role); the
14
+ * control announces its busy state instead (`spec:AST-086` FR8), once per busy
15
+ * start (FR6): rerenders and StrictMode replay do not repeat it, and settling
16
+ * re-arms it. While a native modal is open, the body-level channel is not
17
+ * exposed, so a control inside it announces through one persistent polite
18
+ * region in that dialog, inserted empty and filled a frame later (Platform
19
+ * support, FR3).
20
+ *
21
+ * SYNC: deliberately NOT exported from /packages/core/src/hooks/index.ts —
22
+ * this is a shared implementation detail of Astryx's busy controls.
23
+ */
24
+ import { useEffect, useRef } from 'react';
25
+ import { useAnnounce } from "./useAnnounce.js";
26
+ const REGION_ATTR = 'data-astryx-modal-busy-region';
27
+ const VISUALLY_HIDDEN_CSS = 'position:absolute;width:1px;height:1px;margin:-1px;padding:0;' + 'overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0;';
28
+ const CLEAR_DELAY_MS = 2000; // Matches useAnnounce.
29
+
30
+ // The pending write and clear of each in-dialog region; a new write cancels
31
+ // them so an earlier message can neither land late nor clear a later one.
32
+ const pendingByRegion = new WeakMap();
33
+ function announceInModal(dialog, message) {
34
+ let region = dialog.querySelector(`:scope > [${REGION_ATTR}]`);
35
+ if (region == null) {
36
+ region = document.createElement('div');
37
+ region.setAttribute(REGION_ATTR, '');
38
+ region.setAttribute('role', 'status');
39
+ region.setAttribute('aria-live', 'polite');
40
+ region.setAttribute('aria-atomic', 'true');
41
+ region.style.cssText = VISUALLY_HIDDEN_CSS;
42
+ dialog.appendChild(region);
43
+ }
44
+ const target = region;
45
+ const previous = pendingByRegion.get(target);
46
+ if (previous != null) {
47
+ cancelAnimationFrame(previous.frame);
48
+ clearTimeout(previous.timer);
49
+ }
50
+ target.textContent = '';
51
+ const pending = {
52
+ frame: 0
53
+ };
54
+ pending.frame = requestAnimationFrame(() => {
55
+ target.textContent = message;
56
+ pending.timer = setTimeout(() => {
57
+ target.textContent = '';
58
+ pendingByRegion.delete(target);
59
+ }, CLEAR_DELAY_MS);
60
+ });
61
+ pendingByRegion.set(target, pending);
62
+ }
63
+ export function useBusyAnnouncement(isBusy, message, elementRef) {
64
+ const announce = useAnnounce();
65
+ const hasAnnouncedRef = useRef(false);
66
+ useEffect(() => {
67
+ if (!isBusy) {
68
+ hasAnnouncedRef.current = false;
69
+ return;
70
+ }
71
+ if (hasAnnouncedRef.current) {
72
+ return;
73
+ }
74
+ // Choose the route a frame later: a Dialog opening in the same commit
75
+ // calls showModal() in its own Effect, which runs after this one.
76
+ const frame = requestAnimationFrame(() => {
77
+ hasAnnouncedRef.current = true;
78
+ const dialog = elementRef.current?.closest('dialog');
79
+ if (dialog?.open && dialog.matches(':modal')) {
80
+ announceInModal(dialog, message);
81
+ } else {
82
+ announce(message, 'polite');
83
+ }
84
+ });
85
+ return () => cancelAnimationFrame(frame);
86
+ }, [announce, elementRef, isBusy, message]);
87
+ }
@@ -110,8 +110,8 @@ export interface UseMenuPressOptions {
110
110
  getScroller?: () => HTMLElement | null;
111
111
  /**
112
112
  * Resolve the element under a viewport point. Defaults to
113
- * `document.elementFromPoint`, falling back to the event target where the
114
- * document lacks it (jsdom). A test seam.
113
+ * `elementFromPoint` on the menu's own document or shadow root, falling back
114
+ * to the event target where the document lacks it (jsdom). A test seam.
115
115
  */
116
116
  hitTest?: (x: number, y: number) => Element | null;
117
117
  /** @default 500 */
@@ -1 +1 @@
1
- {"version":3,"file":"useMenuPress.d.ts","sourceRoot":"","sources":["../../src/hooks/useMenuPress.ts"],"names":[],"mappings":"AAIA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2CG;AAEH,OAAO,EAA0C,KAAK,SAAS,EAAC,MAAM,OAAO,CAAC;AAE9E,OAAO,EAML,KAAK,oBAAoB,EAC1B,MAAM,oBAAoB,CAAC;AAG5B,uDAAuD;AACvD,eAAO,MAAM,iBAAiB,2BAA2B,CAAC;AAE1D;;;;;;GAMG;AACH,eAAO,MAAM,uBAAuB,mCAAmC,CAAC;AAExE,+EAA+E;AAC/E,eAAO,MAAM,yBAAyB,MAAM,CAAC;AAC7C,iFAAiF;AACjF,eAAO,MAAM,wBAAwB,MAAM,CAAC;AAC5C,oFAAoF;AACpF,eAAO,MAAM,6BAA6B,KAAK,CAAC;AAchD;;;;;GAKG;AACH,wBAAgB,qBAAqB,IAAI,OAAO,CAE/C;AA6DD,0DAA0D;AAC1D,wBAAgB,uBAAuB,IAAI,IAAI,CAE9C;AAMD,MAAM,WAAW,mBAAmB;IAClC,+EAA+E;IAC/E,OAAO,EAAE,SAAS,CAAC,WAAW,GAAG,IAAI,CAAC,CAAC;IACvC,uEAAuE;IACvE,UAAU,CAAC,EAAE,SAAS,CAAC,WAAW,GAAG,IAAI,CAAC,CAAC;IAC3C;;;OAGG;IACH,YAAY,EAAE,MAAM,CAAC;IACrB;;;;;;;OAOG;IACH,cAAc,CAAC,EAAE,CAAC,WAAW,EAAE,oBAAoB,KAAK,OAAO,CAAC;IAChE;;;;;OAKG;IACH,WAAW,CAAC,EAAE,CAAC,GAAG,EAAE,WAAW,GAAG,IAAI,KAAK,IAAI,CAAC;IAChD;;;;OAIG;IACH,UAAU,CAAC,EAAE,CAAC,GAAG,EAAE,WAAW,EAAE,OAAO,EAAE,YAAY,KAAK,IAAI,CAAC;IAC/D,2EAA2E;IAC3E,SAAS,CAAC,EAAE,MAAM,IAAI,CAAC;IACvB;;;OAGG;IACH,WAAW,CAAC,EAAE,MAAM,WAAW,GAAG,IAAI,CAAC;IACvC;;;;OAIG;IACH,OAAO,CAAC,EAAE,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,KAAK,OAAO,GAAG,IAAI,CAAC;IACnD,mBAAmB;IACnB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,+CAA+C;IAC/C,SAAS,CAAC,EAAE,OAAO,CAAC;CACrB;AAED,MAAM,WAAW,kBAAkB;IACjC,sEAAsE;IACtE,SAAS,EAAE;QACT,aAAa,EAAE,CAAC,KAAK,EAAE,KAAK,CAAC,YAAY,CAAC,WAAW,CAAC,KAAK,IAAI,CAAC;QAChE,CAAC,iBAAiB,CAAC,EAAE,EAAE,CAAC;KACzB,CAAC;IACF,yEAAyE;IACzE,YAAY,EAAE;QACZ,aAAa,EAAE,CAAC,KAAK,EAAE,KAAK,CAAC,YAAY,CAAC,WAAW,CAAC,KAAK,IAAI,CAAC;QAChE,aAAa,EAAE,CAAC,KAAK,EAAE,KAAK,CAAC,UAAU,CAAC,WAAW,CAAC,KAAK,IAAI,CAAC;KAC/D,CAAC;IACF;;;;OAIG;IACH,uBAAuB,EAAE,MAAM,OAAO,CAAC;IACvC,uEAAuE;IACvE,MAAM,EAAE,MAAM,IAAI,CAAC;CACpB;AAkED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,YAAY,CAAC,OAAO,EAAE,mBAAmB,GAAG,kBAAkB,CA2iB7E"}
1
+ {"version":3,"file":"useMenuPress.d.ts","sourceRoot":"","sources":["../../src/hooks/useMenuPress.ts"],"names":[],"mappings":"AAIA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2CG;AAEH,OAAO,EAA0C,KAAK,SAAS,EAAC,MAAM,OAAO,CAAC;AAE9E,OAAO,EAML,KAAK,oBAAoB,EAC1B,MAAM,oBAAoB,CAAC;AAG5B,uDAAuD;AACvD,eAAO,MAAM,iBAAiB,2BAA2B,CAAC;AAE1D;;;;;;GAMG;AACH,eAAO,MAAM,uBAAuB,mCAAmC,CAAC;AAExE,+EAA+E;AAC/E,eAAO,MAAM,yBAAyB,MAAM,CAAC;AAC7C,iFAAiF;AACjF,eAAO,MAAM,wBAAwB,MAAM,CAAC;AAC5C,oFAAoF;AACpF,eAAO,MAAM,6BAA6B,KAAK,CAAC;AAchD;;;;;GAKG;AACH,wBAAgB,qBAAqB,IAAI,OAAO,CAE/C;AA6DD,0DAA0D;AAC1D,wBAAgB,uBAAuB,IAAI,IAAI,CAE9C;AAMD,MAAM,WAAW,mBAAmB;IAClC,+EAA+E;IAC/E,OAAO,EAAE,SAAS,CAAC,WAAW,GAAG,IAAI,CAAC,CAAC;IACvC,uEAAuE;IACvE,UAAU,CAAC,EAAE,SAAS,CAAC,WAAW,GAAG,IAAI,CAAC,CAAC;IAC3C;;;OAGG;IACH,YAAY,EAAE,MAAM,CAAC;IACrB;;;;;;;OAOG;IACH,cAAc,CAAC,EAAE,CAAC,WAAW,EAAE,oBAAoB,KAAK,OAAO,CAAC;IAChE;;;;;OAKG;IACH,WAAW,CAAC,EAAE,CAAC,GAAG,EAAE,WAAW,GAAG,IAAI,KAAK,IAAI,CAAC;IAChD;;;;OAIG;IACH,UAAU,CAAC,EAAE,CAAC,GAAG,EAAE,WAAW,EAAE,OAAO,EAAE,YAAY,KAAK,IAAI,CAAC;IAC/D,2EAA2E;IAC3E,SAAS,CAAC,EAAE,MAAM,IAAI,CAAC;IACvB;;;OAGG;IACH,WAAW,CAAC,EAAE,MAAM,WAAW,GAAG,IAAI,CAAC;IACvC;;;;OAIG;IACH,OAAO,CAAC,EAAE,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,KAAK,OAAO,GAAG,IAAI,CAAC;IACnD,mBAAmB;IACnB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,+CAA+C;IAC/C,SAAS,CAAC,EAAE,OAAO,CAAC;CACrB;AAED,MAAM,WAAW,kBAAkB;IACjC,sEAAsE;IACtE,SAAS,EAAE;QACT,aAAa,EAAE,CAAC,KAAK,EAAE,KAAK,CAAC,YAAY,CAAC,WAAW,CAAC,KAAK,IAAI,CAAC;QAChE,CAAC,iBAAiB,CAAC,EAAE,EAAE,CAAC;KACzB,CAAC;IACF,yEAAyE;IACzE,YAAY,EAAE;QACZ,aAAa,EAAE,CAAC,KAAK,EAAE,KAAK,CAAC,YAAY,CAAC,WAAW,CAAC,KAAK,IAAI,CAAC;QAChE,aAAa,EAAE,CAAC,KAAK,EAAE,KAAK,CAAC,UAAU,CAAC,WAAW,CAAC,KAAK,IAAI,CAAC;KAC/D,CAAC;IACF;;;;OAIG;IACH,uBAAuB,EAAE,MAAM,OAAO,CAAC;IACvC,uEAAuE;IACvE,MAAM,EAAE,MAAM,IAAI,CAAC;CACpB;AAkED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,YAAY,CAAC,OAAO,EAAE,mBAAmB,GAAG,kBAAkB,CAojB7E"}
@@ -256,7 +256,11 @@ export function useMenuPress(options) {
256
256
  if (hitTest != null) {
257
257
  element = hitTest(event.clientX, event.clientY);
258
258
  } else if (typeof doc.elementFromPoint === 'function') {
259
- element = doc.elementFromPoint(event.clientX, event.clientY);
259
+ // Hit-test in the menu's own tree: inside a shadow root the document
260
+ // answers with the shadow host, never the row under the pointer.
261
+ const tree = menu?.getRootNode();
262
+ const scope = tree != null && tree !== doc && typeof tree.elementFromPoint === 'function' ? tree : doc;
263
+ element = scope.elementFromPoint(event.clientX, event.clientY);
260
264
  } else {
261
265
  element = event.target instanceof Element ? event.target : null;
262
266
  }
@@ -1 +1 @@
1
- {"version":3,"file":"useTypeahead.d.ts","sourceRoot":"","sources":["../../src/hooks/useTypeahead.ts"],"names":[],"mappings":"AAkBA,MAAM,WAAW,mBAAmB;IAClC;;;;OAIG;IACH,aAAa,EAAE,MAAM,aAAa,CAAC,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC,CAAC;IAE9D;;;OAGG;IACH,OAAO,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAEjC;;;;;OAKG;IACH,eAAe,CAAC,EAAE,MAAM,MAAM,CAAC;IAE/B;;;OAGG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;IAEjB;;OAEG;IACH,UAAU,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,OAAO,CAAC;CACzC;AAED,MAAM,WAAW,kBAAkB;IACjC;;;;OAIG;IACH,SAAS,EAAE,CAAC,CAAC,EAAE,KAAK,CAAC,aAAa,GAAG,aAAa,KAAK,OAAO,CAAC;IAC/D,gDAAgD;IAChD,KAAK,EAAE,MAAM,IAAI,CAAC;CACnB;AA+BD;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,wBAAgB,YAAY,CAAC,OAAO,EAAE,mBAAmB,GAAG,kBAAkB,CA8F7E"}
1
+ {"version":3,"file":"useTypeahead.d.ts","sourceRoot":"","sources":["../../src/hooks/useTypeahead.ts"],"names":[],"mappings":"AAkBA,MAAM,WAAW,mBAAmB;IAClC;;;;OAIG;IACH,aAAa,EAAE,MAAM,aAAa,CAAC,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC,CAAC;IAE9D;;;OAGG;IACH,OAAO,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAEjC;;;;;OAKG;IACH,eAAe,CAAC,EAAE,MAAM,MAAM,CAAC;IAE/B;;;OAGG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;IAEjB;;OAEG;IACH,UAAU,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,OAAO,CAAC;CACzC;AAED,MAAM,WAAW,kBAAkB;IACjC;;;;OAIG;IACH,SAAS,EAAE,CAAC,CAAC,EAAE,KAAK,CAAC,aAAa,GAAG,aAAa,KAAK,OAAO,CAAC;IAC/D,gDAAgD;IAChD,KAAK,EAAE,MAAM,IAAI,CAAC;CACnB;AA+BD;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,wBAAgB,YAAY,CAAC,OAAO,EAAE,mBAAmB,GAAG,kBAAkB,CAmG7E"}
@@ -4,7 +4,7 @@
4
4
 
5
5
  /**
6
6
  * @file useTypeahead.ts
7
- * @input Uses React useCallback/useRef
7
+ * @input Uses React useCallback/useEffect/useRef
8
8
  * @output Exports useTypeahead hook for first-character (type-to-focus) search
9
9
  * @position Core hook; adds APG typeahead to menus, listboxes, and other
10
10
  * collections. Composes with useListFocus/useGridFocus (or any collection)
@@ -13,7 +13,7 @@
13
13
  * SYNC: When modified, update:
14
14
  * - /packages/core/src/hooks/index.ts
15
15
  */
16
- import { useCallback, useRef } from 'react';
16
+ import { useCallback, useEffect, useRef } from 'react';
17
17
  /**
18
18
  * Whether a key event represents a single printable character (a type-to-focus
19
19
  * candidate) rather than a control/navigation key or a shortcut chord.
@@ -79,6 +79,11 @@ export function useTypeahead(options) {
79
79
  timeoutRef.current = undefined;
80
80
  }
81
81
  }, []);
82
+
83
+ // A collection that unmounts, or that an `<Activity>` boundary hides,
84
+ // mid-typing leaves no reset timer running and comes back with an empty
85
+ // buffer, as the reset would have left it.
86
+ useEffect(() => reset, [reset]);
82
87
  const scheduleReset = useCallback(() => {
83
88
  if (timeoutRef.current) {
84
89
  clearTimeout(timeoutRef.current);
@@ -1 +1 @@
1
- {"version":3,"file":"en.generated.d.ts","sourceRoot":"","sources":["../../../src/i18n/generated-locales/en.generated.ts"],"names":[],"mappings":"AAEA;;;;GAIG;AAEH,QAAA,MAAM,cAAc,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CA8jBpD,CAAC;AAEF,eAAe,cAAc,CAAC"}
1
+ {"version":3,"file":"en.generated.d.ts","sourceRoot":"","sources":["../../../src/i18n/generated-locales/en.generated.ts"],"names":[],"mappings":"AAEA;;;;GAIG;AAEH,QAAA,MAAM,cAAc,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CA+jBpD,CAAC;AAEF,eAAe,cAAc,CAAC"}
@@ -315,6 +315,7 @@ const runtimeCatalog = {
315
315
  '@astryx.chatToolCalls.status.complete': 'Complete',
316
316
  '@astryx.chatToolCalls.status.error': 'Failed',
317
317
  '@astryx.chatToolCalls.groupLabel': '{count} tool calls',
318
+ '@astryx.chatTriggerMenu.searching': 'Searching…',
318
319
  '@astryx.chatTriggerMenu.suggestions': 'Suggestions',
319
320
  '@astryx.citation.label': 'Citation {number}: {title}',
320
321
  '@astryx.codeBlock.copied': 'Copied',
@@ -1 +1 @@
1
- {"version":3,"file":"pseudo.generated.d.ts","sourceRoot":"","sources":["../../../src/i18n/generated-locales/pseudo.generated.ts"],"names":[],"mappings":"AAEA;;;;GAIG;AAEH,QAAA,MAAM,cAAc,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAukBpD,CAAC;AAEF,eAAe,cAAc,CAAC"}
1
+ {"version":3,"file":"pseudo.generated.d.ts","sourceRoot":"","sources":["../../../src/i18n/generated-locales/pseudo.generated.ts"],"names":[],"mappings":"AAEA;;;;GAIG;AAEH,QAAA,MAAM,cAAc,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAwkBpD,CAAC;AAEF,eAAe,cAAc,CAAC"}
@@ -315,6 +315,7 @@ const runtimeCatalog = {
315
315
  '@astryx.chatToolCalls.status.complete': '⟦Çóɱþłéţé⟧',
316
316
  '@astryx.chatToolCalls.status.error': '⟦Ƒàíłéð⟧',
317
317
  '@astryx.chatToolCalls.groupLabel': '⟦{count} ţóół çàłłš⟧',
318
+ '@astryx.chatTriggerMenu.searching': '⟦Šéàřçĥíñĝ…⟧',
318
319
  '@astryx.chatTriggerMenu.suggestions': '⟦Šúĝĝéšţíóñš⟧',
319
320
  '@astryx.citation.label': '⟦Çíţàţíóñ {number}: {title}⟧',
320
321
  '@astryx.codeBlock.copied': '⟦Çóþíéð⟧',
package/locales/en.json CHANGED
@@ -901,7 +901,7 @@
901
901
  },
902
902
  "@astryx.typeahead.loading": {
903
903
  "defaultMessage": "Loading",
904
- "description": "Screen-reader-only name for a spinner shown inside a Typeahead dropdown while suggestions are being fetched. Present-progressive form."
904
+ "description": "Screen-reader-only name for the spinner a Typeahead, Tokenizer or directly used BaseTypeahead shows while suggestions are being fetched; also announced once through the shared announcement channel when each search starts. Present-progressive form."
905
905
  },
906
906
  "@astryx.typeahead.searchResults": {
907
907
  "defaultMessage": "Search results",
@@ -1169,7 +1169,7 @@
1169
1169
  },
1170
1170
  "@astryx.spinner.loading": {
1171
1171
  "defaultMessage": "Loading",
1172
- "description": "Screen-reader-only default name for a standalone Spinner's role=\"status\" element, used when the consumer supplies neither `aria-label` nor a visible string label. Present-progressive form. Kept separate from `button.loading` and `typeahead.loading` — translations may diverge."
1172
+ "description": "Screen-reader-only default name for a standalone Spinner's role=\"status\" element, used when the consumer supplies neither `aria-label` nor a visible string label; also announced once when a busy input or selector starts loading, in place of its decorative Spinner. Present-progressive form. Kept separate from `button.loading` and `typeahead.loading` — translations may diverge."
1173
1173
  },
1174
1174
  "@astryx.chatComposerDrawer.expand": {
1175
1175
  "defaultMessage": "Expand {label}",
@@ -1231,6 +1231,10 @@
1231
1231
  "defaultMessage": "{count} tool calls",
1232
1232
  "description": "Summary label shown in the group header when multiple tool calls are expanded. {count} is the number of calls."
1233
1233
  },
1234
+ "@astryx.chatTriggerMenu.searching": {
1235
+ "defaultMessage": "Searching…",
1236
+ "description": "Shown, and announced politely to screen readers, while a chat composer's @-mention or slash-command menu waits for async search results. Present participle; trailing `…` is one character."
1237
+ },
1234
1238
  "@astryx.chatTriggerMenu.suggestions": {
1235
1239
  "defaultMessage": "Suggestions",
1236
1240
  "description": "Screen-reader-only fallback label for the popover listbox opened by a trigger character (`@`, `/`) in the chat composer when the trigger provides no specific label."
@@ -923,6 +923,9 @@
923
923
  "@astryx.chatToolCalls.groupLabel": {
924
924
  "defaultMessage": "⟦{count} ţóół çàłłš⟧"
925
925
  },
926
+ "@astryx.chatTriggerMenu.searching": {
927
+ "defaultMessage": "⟦Šéàřçĥíñĝ…⟧"
928
+ },
926
929
  "@astryx.chatTriggerMenu.suggestions": {
927
930
  "defaultMessage": "⟦Šúĝĝéšţíóñš⟧"
928
931
  },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@astryxdesign/core",
3
- "version": "0.7.3",
3
+ "version": "0.7.4-canary.1a552f2",
4
4
  "displayName": "Astryx Core",
5
5
  "description": "The component library. Accessible, themeable React components with built-in spacing, dark mode, and StyleX styling.",
6
6
  "author": "Meta Open Source",
@@ -792,6 +792,8 @@
792
792
  "react-dom": ">=19.0.0"
793
793
  },
794
794
  "devDependencies": {
795
+ "@astryxdesign/a11y-spec": "0.7.4-canary.1a552f2",
796
+ "@astryxdesign/cli": "0.7.4-canary.1a552f2",
795
797
  "@babel/cli": "^7.29.7",
796
798
  "@babel/core": "^7.29.7",
797
799
  "@babel/preset-react": "^7.29.7",
@@ -802,9 +804,7 @@
802
804
  "@testing-library/jest-dom": "^6.6.0",
803
805
  "@testing-library/react": "^16.3.2",
804
806
  "@types/babel__core": "^7.20.5",
805
- "tailwindcss": "^4.3.2",
806
- "@astryxdesign/a11y-spec": "0.0.0",
807
- "@astryxdesign/cli": "0.7.3"
807
+ "tailwindcss": "^4.3.2"
808
808
  },
809
809
  "dependencies": {
810
810
  "intl-messageformat": "^11.2.9"
@@ -95,7 +95,7 @@ export const docs = {
95
95
  derived: [{property: 'padding', expand: 'container'}],
96
96
  },
97
97
  description:
98
- "A mobile touch sheet that rises from the bottom edge, with animated entrance and exit, a grab handle, optional drag-to-resize snap points, and purpose-controlled dismissal. Like Dialog, it is a padded container: content starts at the theme's bottom-sheet padding (--spacing-4 by default), and a lone Section child or bleed children such as Table and Divider align against it. A standalone sheet owns a native <dialog>; inside BottomSheetSwitcher it renders a panel in the switcher's shared dialog. In both modes, ref and shared DOM props target the visual panel <div>.",
98
+ "A mobile touch sheet that rises from the bottom edge, with animated entrance and exit, a grab handle, optional drag-to-resize snap points, and purpose-controlled dismissal. Like Dialog, it is a padded container: content starts at the theme's bottom-sheet padding (--spacing-4 by default), and a lone Section child or bleed children such as Table and Divider align against it. A sheet always owns a native <dialog>; inside BottomSheetSwitcher the switcher presents and closes that dialog as the flow moves between steps. In both modes, ref and shared DOM props target the visual panel <div>.",
99
99
  props: [
100
100
  {
101
101
  name: 'isOpen',
@@ -165,7 +165,7 @@ export const docs = {
165
165
  name: 'hasScrim',
166
166
  type: 'boolean',
167
167
  description:
168
- "For a standalone BottomSheet, whether to render a scrim, the semi-transparent overlay that covers and blocks the background. true (default) uses showModal(): top layer, focus trap, ::backdrop scrim, body scroll lock, and tap-scrim-to-dismiss when purpose='info', with the background inert. false uses show() with no scrim, leaving the page behind interactive and scrollable. For a multi-step flow, configure hasScrim on BottomSheetSwitcher instead; it owns one shared dialog across every child.",
168
+ "For a standalone BottomSheet, whether to render a scrim, the semi-transparent overlay that covers and blocks the background. true (default) uses showModal(): top layer, native focus containment, ::backdrop scrim, body scroll lock, and tap-scrim-to-dismiss when purpose='info', with the background inert. false uses show() with no scrim, leaving the page behind interactive and scrollable. For a multi-step flow, configure hasScrim on BottomSheetSwitcher instead; it applies to every child's dialog.",
169
169
  default: 'true',
170
170
  },
171
171
  ],
@@ -15,6 +15,7 @@ verified_by:
15
15
  packages/core/src/BottomSheet/BottomSheet.test.tsx,
16
16
  packages/core/src/BottomSheet/BottomSheetPanel.test.tsx,
17
17
  packages/core/src/BottomSheet/BottomSheetKeyboard.test.tsx,
18
+ packages/core/src/BottomSheet/__tests__/BottomSheetNativeModal.a11y.browser.spec.ts,
18
19
  packages/core/src/BottomSheet/__tests__/BottomSheetKeyboard.a11y.browser.spec.ts,
19
20
  apps/storybook/stories/BottomSheet.stories.tsx,
20
21
  scripts/check-knowledge.mjs,
@@ -66,9 +67,7 @@ Consumer migration instructions belong in consumer docs and release notes.
66
67
  `architecture:container-padding`.
67
68
  - Standalone sheet presentation, including its optional native-dialog Scrim.
68
69
  - The native dialog every sheet renders, standalone or switcher-managed
69
- (`component:BottomSheetSwitcher` DEC-1). Implementation gap: a
70
- switcher-managed sheet renders a panel inside the switcher's one shared
71
- dialog and owns no dialog of its own.
70
+ (`component:BottomSheetSwitcher` DEC-1).
72
71
 
73
72
  **Does not own / non-goals**
74
73
 
@@ -107,8 +106,7 @@ in `BottomSheet.doc.mjs`.
107
106
  without a Scrim.
108
107
  - A switcher-managed sheet renders the same panel anatomy in its own dialog while
109
108
  BottomSheetSwitcher coordinates that dialog's lifecycle and the flow's one Scrim
110
- (`component:BottomSheetSwitcher` DEC-1). Implementation gap: the panel
111
- renders inside the switcher's one shared dialog.
109
+ (`component:BottomSheetSwitcher` DEC-1).
112
110
 
113
111
  ### Transformation and precedence order
114
112