@astryxdesign/core 0.7.5 → 0.7.6-canary.5cd7a15

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 (463) hide show
  1. package/dist/AlertDialog/AlertDialog.d.ts +1 -1
  2. package/dist/AlertDialog/AlertDialog.d.ts.map +1 -1
  3. package/dist/AlertDialog/AlertDialog.js +5 -5
  4. package/dist/Avatar/Avatar.d.ts.map +1 -1
  5. package/dist/Avatar/Avatar.js +12 -3
  6. package/dist/Badge/Badge.d.ts.map +1 -1
  7. package/dist/Badge/Badge.js +7 -1
  8. package/dist/BottomSheet/BottomSheet.js +1 -1
  9. package/dist/BottomSheet/BottomSheetPanel.d.ts.map +1 -1
  10. package/dist/BottomSheet/BottomSheetPanel.js +2 -1
  11. package/dist/BottomSheet/useSheetGestures.d.ts +12 -0
  12. package/dist/BottomSheet/useSheetGestures.d.ts.map +1 -1
  13. package/dist/BottomSheet/useSheetGestures.js +30 -3
  14. package/dist/Button/Button.js +4 -4
  15. package/dist/CheckboxInput/CheckboxInput.d.ts.map +1 -1
  16. package/dist/CheckboxInput/CheckboxInput.js +6 -5
  17. package/dist/DateInput/DateInput.d.ts.map +1 -1
  18. package/dist/DateInput/DateInput.js +12 -4
  19. package/dist/DateInput/MonthScroller.d.ts.map +1 -1
  20. package/dist/DateInput/MonthScroller.js +101 -15
  21. package/dist/DateInput/TouchDateField.d.ts.map +1 -1
  22. package/dist/DateInput/TouchDateField.js +8 -3
  23. package/dist/DateRangeInput/DateRangeInput.d.ts.map +1 -1
  24. package/dist/DateRangeInput/DateRangeInput.js +1 -1
  25. package/dist/DateTimeInput/DateTimeInput.d.ts +5 -2
  26. package/dist/DateTimeInput/DateTimeInput.d.ts.map +1 -1
  27. package/dist/DateTimeInput/DateTimeInput.js +23 -12
  28. package/dist/DateTimeInput/NativeTimeSegment.d.ts.map +1 -1
  29. package/dist/DateTimeInput/NativeTimeSegment.js +5 -4
  30. package/dist/DateTimeInput/TouchDateTimeField.d.ts.map +1 -1
  31. package/dist/DateTimeInput/TouchDateTimeField.js +4 -3
  32. package/dist/Dialog/Dialog.d.ts.map +1 -1
  33. package/dist/Dialog/Dialog.js +34 -9
  34. package/dist/Dialog/DialogHeader.d.ts.map +1 -1
  35. package/dist/Dialog/DialogHeader.js +5 -4
  36. package/dist/Divider/Divider.d.ts.map +1 -1
  37. package/dist/Divider/Divider.js +2 -1
  38. package/dist/Drawer/Drawer.d.ts +1 -0
  39. package/dist/Drawer/Drawer.d.ts.map +1 -1
  40. package/dist/Drawer/Drawer.js +7 -2
  41. package/dist/DropdownMenu/DropdownMenu.d.ts.map +1 -1
  42. package/dist/DropdownMenu/DropdownMenu.js +4 -1
  43. package/dist/DropdownMenu/MenuBottomSheetActionList.d.ts.map +1 -1
  44. package/dist/DropdownMenu/MenuBottomSheetActionList.js +6 -5
  45. package/dist/DropdownMenu/lazyMenuBottomSheet.d.ts +10 -1
  46. package/dist/DropdownMenu/lazyMenuBottomSheet.d.ts.map +1 -1
  47. package/dist/DropdownMenu/lazyMenuBottomSheet.js +16 -2
  48. package/dist/DropdownMenu/renderDropdownItems.d.ts.map +1 -1
  49. package/dist/DropdownMenu/renderDropdownItems.js +21 -16
  50. package/dist/EmptyState/EmptyState.d.ts.map +1 -1
  51. package/dist/EmptyState/EmptyState.js +2 -1
  52. package/dist/Field/FieldLabel.d.ts +1 -1
  53. package/dist/Field/FieldLabel.d.ts.map +1 -1
  54. package/dist/Field/FieldLabel.js +4 -4
  55. package/dist/Field/InputClearButton.js +3 -3
  56. package/dist/Field/PanelSearchInput.js +2 -2
  57. package/dist/FieldStatus/FieldStatus.js +2 -2
  58. package/dist/FileInput/FileInput.d.ts.map +1 -1
  59. package/dist/FileInput/FileInput.js +7 -1
  60. package/dist/Heading/Heading.js +1 -1
  61. package/dist/Icon/Icon.js +1 -1
  62. package/dist/Indicator/CheckIndicator.d.ts.map +1 -1
  63. package/dist/Indicator/CheckIndicator.js +2 -1
  64. package/dist/Indicator/CheckboxIndicator.d.ts.map +1 -1
  65. package/dist/Indicator/CheckboxIndicator.js +3 -1
  66. package/dist/Indicator/RadioIndicator.d.ts.map +1 -1
  67. package/dist/Indicator/RadioIndicator.js +3 -1
  68. package/dist/Item/Item.d.ts.map +1 -1
  69. package/dist/Item/Item.js +2 -1
  70. package/dist/Item/ItemSwipeLayer.js +1 -1
  71. package/dist/Layout/Layout.js +1 -1
  72. package/dist/Layout/LayoutContent.js +1 -1
  73. package/dist/Layout/LayoutFooter.js +1 -1
  74. package/dist/Layout/LayoutHeader.js +1 -1
  75. package/dist/Lightbox/Lightbox.d.ts.map +1 -1
  76. package/dist/Lightbox/Lightbox.js +5 -0
  77. package/dist/Lightbox/LightboxViewport.a11y.browser.spec.js +5 -4
  78. package/dist/List/List.js +1 -1
  79. package/dist/List/ListItem.js +3 -3
  80. package/dist/MobileNav/MobileNav.d.ts.map +1 -1
  81. package/dist/MobileNav/MobileNav.js +7 -2
  82. package/dist/MultiSelector/MultiSelector.d.ts +1 -1
  83. package/dist/MultiSelector/MultiSelector.d.ts.map +1 -1
  84. package/dist/MultiSelector/MultiSelector.js +5 -2
  85. package/dist/NumberInput/NumberInput.d.ts +3 -1
  86. package/dist/NumberInput/NumberInput.d.ts.map +1 -1
  87. package/dist/NumberInput/NumberInput.js +3 -3
  88. package/dist/NumberInput/numberParser.d.ts +3 -0
  89. package/dist/NumberInput/numberParser.d.ts.map +1 -1
  90. package/dist/NumberInput/numberParser.js +7 -44
  91. package/dist/ProgressBar/ProgressBar.d.ts.map +1 -1
  92. package/dist/ProgressBar/ProgressBar.js +16 -12
  93. package/dist/Resizable/useResizable.d.ts.map +1 -1
  94. package/dist/Resizable/useResizable.js +28 -2
  95. package/dist/SegmentedControl/SegmentedControlItem.d.ts.map +1 -1
  96. package/dist/SegmentedControl/SegmentedControlItem.js +4 -1
  97. package/dist/Selector/useSelectorPresentation.d.ts +8 -1
  98. package/dist/Selector/useSelectorPresentation.d.ts.map +1 -1
  99. package/dist/Selector/useSelectorPresentation.js +20 -4
  100. package/dist/Slider/Slider.d.ts.map +1 -1
  101. package/dist/Slider/Slider.js +7 -1
  102. package/dist/Spinner/Spinner.js +2 -2
  103. package/dist/Stack/Stack.js +1 -1
  104. package/dist/Stack/StackItem.js +1 -1
  105. package/dist/TabList/TabList.d.ts.map +1 -1
  106. package/dist/TabList/TabList.js +16 -1
  107. package/dist/Table/plugins/columnResize/useTableColumnResize.d.ts.map +1 -1
  108. package/dist/Table/plugins/columnResize/useTableColumnResize.js +9 -1
  109. package/dist/Text/Text.js +1 -1
  110. package/dist/Text/useTruncation.d.ts.map +1 -1
  111. package/dist/Text/useTruncation.js +23 -5
  112. package/dist/TextArea/TextArea.d.ts +1 -1
  113. package/dist/TextArea/TextArea.d.ts.map +1 -1
  114. package/dist/TextArea/TextArea.js +13 -2
  115. package/dist/TextInput/TextInput.d.ts.map +1 -1
  116. package/dist/TextInput/TextInput.js +3 -3
  117. package/dist/TimeInput/TimeInput.d.ts +6 -2
  118. package/dist/TimeInput/TimeInput.d.ts.map +1 -1
  119. package/dist/TimeInput/TimeInput.js +21 -14
  120. package/dist/TimeInput/TouchTimeField.d.ts.map +1 -1
  121. package/dist/TimeInput/TouchTimeField.js +5 -4
  122. package/dist/Timestamp/Timestamp.d.ts.map +1 -1
  123. package/dist/Timestamp/Timestamp.js +2 -2
  124. package/dist/Timestamp/TimestampHoverCard.js +4 -4
  125. package/dist/Toast/Toast.d.ts.map +1 -1
  126. package/dist/Toast/Toast.js +60 -20
  127. package/dist/Toast/ToastViewport.d.ts.map +1 -1
  128. package/dist/Toast/ToastViewport.js +82 -51
  129. package/dist/Tokenizer/Tokenizer.d.ts.map +1 -1
  130. package/dist/Tokenizer/Tokenizer.js +13 -2
  131. package/dist/Tokenizer/TokenizerBottomSheet.js +3 -3
  132. package/dist/Toolbar/Toolbar.d.ts.map +1 -1
  133. package/dist/Toolbar/Toolbar.js +2 -1
  134. package/dist/Typeahead/Typeahead.d.ts +1 -1
  135. package/dist/Typeahead/Typeahead.d.ts.map +1 -1
  136. package/dist/Typeahead/Typeahead.js +9 -1
  137. package/dist/astryx.css +15 -1
  138. package/dist/gestures/GestureArena.d.ts +6 -0
  139. package/dist/gestures/GestureArena.d.ts.map +1 -1
  140. package/dist/gestures/GestureArena.js +39 -0
  141. package/dist/gestures/GestureHost.d.ts +352 -0
  142. package/dist/gestures/GestureHost.d.ts.map +1 -0
  143. package/dist/gestures/GestureHost.js +1773 -0
  144. package/dist/gestures/GestureRecognizer.d.ts +10 -0
  145. package/dist/gestures/GestureRecognizer.d.ts.map +1 -1
  146. package/dist/gestures/GestureRecognizer.js +16 -0
  147. package/dist/gestures/LongPressGestureRecognizer.d.ts +1 -0
  148. package/dist/gestures/LongPressGestureRecognizer.d.ts.map +1 -1
  149. package/dist/gestures/LongPressGestureRecognizer.js +3 -0
  150. package/dist/gestures/PanGestureRecognizer.d.ts +1 -0
  151. package/dist/gestures/PanGestureRecognizer.d.ts.map +1 -1
  152. package/dist/gestures/PanGestureRecognizer.js +3 -0
  153. package/dist/gestures/PinchGestureRecognizer.d.ts +31 -0
  154. package/dist/gestures/PinchGestureRecognizer.d.ts.map +1 -0
  155. package/dist/gestures/PinchGestureRecognizer.js +128 -0
  156. package/dist/gestures/ScreenEdgePanGestureRecognizer.d.ts +71 -0
  157. package/dist/gestures/ScreenEdgePanGestureRecognizer.d.ts.map +1 -0
  158. package/dist/gestures/ScreenEdgePanGestureRecognizer.js +223 -0
  159. package/dist/gestures/SwipeGestureRecognizer.d.ts +37 -0
  160. package/dist/gestures/SwipeGestureRecognizer.d.ts.map +1 -0
  161. package/dist/gestures/SwipeGestureRecognizer.js +148 -0
  162. package/dist/gestures/TapGestureRecognizer.d.ts +1 -0
  163. package/dist/gestures/TapGestureRecognizer.d.ts.map +1 -1
  164. package/dist/gestures/TapGestureRecognizer.js +3 -0
  165. package/dist/gestures/VelocityTracker.d.ts +6 -2
  166. package/dist/gestures/VelocityTracker.d.ts.map +1 -1
  167. package/dist/gestures/VelocityTracker.js +7 -3
  168. package/dist/gestures/haptics.d.ts +65 -0
  169. package/dist/gestures/haptics.d.ts.map +1 -0
  170. package/dist/gestures/haptics.js +182 -0
  171. package/dist/gestures/nativeScroll.d.ts +42 -0
  172. package/dist/gestures/nativeScroll.d.ts.map +1 -0
  173. package/dist/gestures/nativeScroll.js +228 -0
  174. package/dist/gestures/touchAction.d.ts +60 -0
  175. package/dist/gestures/touchAction.d.ts.map +1 -0
  176. package/dist/gestures/touchAction.js +157 -0
  177. package/dist/gestures/touchActionRule.d.ts +34 -0
  178. package/dist/gestures/touchActionRule.d.ts.map +1 -0
  179. package/dist/gestures/touchActionRule.js +140 -0
  180. package/dist/gestures/types.d.ts +18 -7
  181. package/dist/gestures/types.d.ts.map +1 -1
  182. package/dist/gestures/types.js +22 -2
  183. package/dist/hooks/useAdaptivePresentation.d.ts.map +1 -1
  184. package/dist/hooks/useAdaptivePresentation.js +4 -1
  185. package/dist/hooks/useMenuHover.d.ts.map +1 -1
  186. package/dist/hooks/useMenuHover.js +12 -1
  187. package/dist/i18n/generated-locales/en.generated.d.ts.map +1 -1
  188. package/dist/i18n/generated-locales/en.generated.js +3 -0
  189. package/dist/i18n/generated-locales/pseudo.generated.d.ts.map +1 -1
  190. package/dist/i18n/generated-locales/pseudo.generated.js +3 -0
  191. package/dist/motion/animator.d.ts +7 -1
  192. package/dist/motion/animator.d.ts.map +1 -1
  193. package/dist/motion/animator.js +119 -27
  194. package/dist/theme/defineTheme.js +1 -1
  195. package/dist/theme/domainTokens/domainTokenDefaults.d.ts +3 -0
  196. package/dist/theme/domainTokens/domainTokenDefaults.d.ts.map +1 -0
  197. package/dist/theme/domainTokens/domainTokenDefaults.js +19 -0
  198. package/dist/theme/domainTokens/index.d.ts +5 -4
  199. package/dist/theme/domainTokens/index.d.ts.map +1 -1
  200. package/dist/theme/domainTokens/index.js +5 -9
  201. package/dist/utils/focusReturn.d.ts +17 -1
  202. package/dist/utils/focusReturn.d.ts.map +1 -1
  203. package/dist/utils/focusReturn.js +11 -4
  204. package/dist/utils/getNodeText.d.ts +8 -0
  205. package/dist/utils/getNodeText.d.ts.map +1 -0
  206. package/dist/utils/getNodeText.js +37 -0
  207. package/dist/utils/interactionModality.d.ts +11 -2
  208. package/dist/utils/interactionModality.d.ts.map +1 -1
  209. package/dist/utils/interactionModality.js +58 -5
  210. package/dist/utils/plainDate.d.ts +2 -0
  211. package/dist/utils/plainDate.d.ts.map +1 -1
  212. package/dist/utils/plainDate.js +46 -3
  213. package/dist/utils/presentation.d.ts +50 -0
  214. package/dist/utils/presentation.d.ts.map +1 -0
  215. package/dist/utils/presentation.js +125 -0
  216. package/dist/utils/primaryClick.d.ts +11 -0
  217. package/dist/utils/primaryClick.d.ts.map +1 -0
  218. package/dist/utils/primaryClick.js +25 -0
  219. package/dist/utils/timeFormat.d.ts +47 -0
  220. package/dist/utils/timeFormat.d.ts.map +1 -0
  221. package/dist/utils/timeFormat.js +240 -0
  222. package/dist/utils/touchPresentation.d.ts.map +1 -1
  223. package/dist/utils/touchPresentation.js +5 -3
  224. package/dist/utils/touchPresentation.stylex.d.ts +15 -0
  225. package/dist/utils/touchPresentation.stylex.d.ts.map +1 -0
  226. package/dist/utils/touchPresentation.stylex.js +33 -0
  227. package/dist/utils/unicodeDigits.d.ts +20 -0
  228. package/dist/utils/unicodeDigits.d.ts.map +1 -0
  229. package/dist/utils/unicodeDigits.js +70 -0
  230. package/locales/en.json +15 -3
  231. package/locales/pseudo.json +9 -0
  232. package/package.json +5 -4
  233. package/src/AlertDialog/AlertDialog.tsx +6 -5
  234. package/src/AlertDialog/__tests__/AlertDialog.a11y.chromium.spec.ts +18 -6
  235. package/src/Avatar/Avatar.spec.md +22 -22
  236. package/src/Avatar/Avatar.tsx +18 -1
  237. package/src/Avatar/__tests__/AvatarForcedColors.a11y.chromium.spec.ts +126 -0
  238. package/src/Badge/Badge.doc.mjs +1 -1
  239. package/src/Badge/Badge.tsx +19 -2
  240. package/src/Badge/__tests__/BadgeLargerText.a11y.chromium.spec.ts +260 -0
  241. package/src/BottomSheet/BottomSheet.test.tsx +46 -0
  242. package/src/BottomSheet/BottomSheet.tsx +1 -1
  243. package/src/BottomSheet/BottomSheetPanel.tsx +2 -1
  244. package/src/BottomSheet/useSheetGestures.test.ts +52 -0
  245. package/src/BottomSheet/useSheetGestures.ts +37 -6
  246. package/src/Breadcrumbs/__tests__/Breadcrumbs.a11y.chromium.spec.ts +18 -6
  247. package/src/Button/Button.tsx +4 -4
  248. package/src/Calendar/Calendar.spec.md +87 -48
  249. package/src/Calendar/__tests__/Calendar.a11y.chromium.spec.ts +21 -7
  250. package/src/Carousel/__tests__/Carousel.a11y.chromium.spec.ts +21 -7
  251. package/src/CheckboxInput/CheckboxInput.tsx +6 -5
  252. package/src/Collapsible/Collapsible.spec.md +2 -0
  253. package/src/Collapsible/CollapsibleGroup.spec.md +57 -29
  254. package/src/Collapsible/__tests__/Collapsible.a11y.chromium.spec.ts +18 -7
  255. package/src/Collapsible/__tests__/CollapsibleGroupAccordion.a11y.chromium.spec.ts +18 -6
  256. package/src/ComplexSelector/ComplexSelector.test.tsx +37 -0
  257. package/src/ContextMenu/ContextMenu.test.tsx +35 -0
  258. package/src/DateInput/DateInput.test.tsx +115 -3
  259. package/src/DateInput/DateInput.tsx +29 -14
  260. package/src/DateInput/DateInputTouch.test.tsx +76 -0
  261. package/src/DateInput/MonthScroller.tsx +106 -20
  262. package/src/DateInput/MonthScrollerSettle.test.tsx +165 -0
  263. package/src/DateInput/TouchDateField.tsx +14 -3
  264. package/src/DateInput/__tests__/MonthScrollerSteps.interaction.browser.spec.ts +312 -0
  265. package/src/DateRangeInput/DateRangeInput.test.tsx +46 -3
  266. package/src/DateRangeInput/DateRangeInput.tsx +16 -12
  267. package/src/DateTimeInput/DateTimeInput.doc.mjs +10 -8
  268. package/src/DateTimeInput/DateTimeInput.spec.md +75 -51
  269. package/src/DateTimeInput/DateTimeInput.test.tsx +81 -0
  270. package/src/DateTimeInput/DateTimeInput.tsx +46 -24
  271. package/src/DateTimeInput/NativeTimeSegment.tsx +4 -6
  272. package/src/DateTimeInput/TouchDateTimeField.tsx +3 -7
  273. package/src/Dialog/Dialog.test.tsx +216 -2
  274. package/src/Dialog/Dialog.tsx +42 -9
  275. package/src/Dialog/DialogHeader.tsx +5 -4
  276. package/src/Dialog/__tests__/DialogSecondDocument.a11y.browser.spec.ts +202 -0
  277. package/src/Divider/Divider.tsx +2 -1
  278. package/src/Drawer/Drawer.spec.md +111 -80
  279. package/src/Drawer/Drawer.test.tsx +35 -0
  280. package/src/Drawer/Drawer.tsx +13 -2
  281. package/src/Drawer/DrawerHeader.spec.md +181 -0
  282. package/src/Drawer/__tests__/DrawerNonModalPageScroll.a11y.chromium.spec.ts +267 -0
  283. package/src/DropdownMenu/DropdownMenu.test.tsx +41 -0
  284. package/src/DropdownMenu/DropdownMenu.tsx +7 -1
  285. package/src/DropdownMenu/DropdownMenuSubMenu.test.tsx +34 -0
  286. package/src/DropdownMenu/MenuBottomSheetActionList.tsx +6 -5
  287. package/src/DropdownMenu/__tests__/Menu.a11y.chromium.spec.ts +19 -7
  288. package/src/DropdownMenu/__tests__/MenuButton.a11y.chromium.spec.ts +21 -9
  289. package/src/DropdownMenu/lazyMenuBottomSheet.test.ts +53 -0
  290. package/src/DropdownMenu/lazyMenuBottomSheet.ts +23 -6
  291. package/src/DropdownMenu/renderDropdownItems.tsx +24 -19
  292. package/src/EmptyState/EmptyState.tsx +2 -1
  293. package/src/Field/FieldLabel.tsx +5 -4
  294. package/src/Field/InputClearButton.tsx +3 -3
  295. package/src/Field/PanelSearchInput.tsx +2 -2
  296. package/src/FieldStatus/FieldStatus.tsx +2 -2
  297. package/src/FileInput/FileInput.test.tsx +21 -0
  298. package/src/FileInput/FileInput.tsx +4 -1
  299. package/src/FormLayout/FormLayout.spec.md +7 -8
  300. package/src/Heading/Heading.tsx +1 -1
  301. package/src/Icon/Icon.tsx +1 -1
  302. package/src/Indicator/CheckIndicator.spec.md +47 -42
  303. package/src/Indicator/CheckIndicator.tsx +2 -1
  304. package/src/Indicator/CheckboxIndicator.spec.md +40 -37
  305. package/src/Indicator/CheckboxIndicator.tsx +3 -1
  306. package/src/Indicator/Indicator.spec.md +188 -0
  307. package/src/Indicator/RadioIndicator.tsx +3 -1
  308. package/src/Item/Item.tsx +2 -1
  309. package/src/Item/ItemSwipeLayer.tsx +1 -1
  310. package/src/Layout/Layout.spec.md +127 -131
  311. package/src/Layout/Layout.tsx +1 -1
  312. package/src/Layout/LayoutContent.spec.md +205 -0
  313. package/src/Layout/LayoutContent.tsx +1 -1
  314. package/src/Layout/LayoutFooter.spec.md +190 -0
  315. package/src/Layout/LayoutFooter.tsx +1 -1
  316. package/src/Layout/LayoutHeader.spec.md +193 -0
  317. package/src/Layout/LayoutHeader.tsx +1 -1
  318. package/src/Layout/LayoutPanel.spec.md +194 -0
  319. package/src/Layout/__tests__/Layout.a11y.chromium.spec.ts +18 -6
  320. package/src/Lightbox/Lightbox.test.tsx +18 -0
  321. package/src/Lightbox/Lightbox.tsx +5 -0
  322. package/src/Lightbox/LightboxViewport.a11y.browser.spec.ts +8 -4
  323. package/src/Link/__tests__/Link.a11y.chromium.spec.ts +18 -8
  324. package/src/List/List.tsx +1 -1
  325. package/src/List/ListItem.spec.md +205 -0
  326. package/src/List/ListItem.tsx +3 -3
  327. package/src/MobileNav/MobileNav.test.tsx +15 -0
  328. package/src/MobileNav/MobileNav.tsx +9 -1
  329. package/src/MobileNav/__tests__/MobileNavHeader.a11y.chromium.spec.ts +89 -0
  330. package/src/MoreMenu/MoreMenu.test.tsx +11 -0
  331. package/src/MultiSelector/MultiSelector.spec.md +7 -4
  332. package/src/MultiSelector/MultiSelector.test.tsx +118 -1
  333. package/src/MultiSelector/MultiSelector.tsx +6 -2
  334. package/src/MultiSelector/__tests__/MultiSelector.listbox.a11y.test.tsx +8 -1
  335. package/src/NavMenu/NavHeadingMenu.spec.md +1 -5
  336. package/src/NumberInput/NumberInput.doc.mjs +13 -7
  337. package/src/NumberInput/NumberInput.spec.md +59 -37
  338. package/src/NumberInput/NumberInput.tsx +13 -3
  339. package/src/NumberInput/__tests__/NumberInput.coarse-pointer.a11y.chromium.spec.ts +102 -0
  340. package/src/NumberInput/numberParser.ts +7 -45
  341. package/src/ProgressBar/ProgressBar.test.tsx +108 -32
  342. package/src/ProgressBar/ProgressBar.tsx +58 -10
  343. package/src/ProgressBar/__tests__/ProgressBar.a11y.chromium.spec.ts +21 -9
  344. package/src/ProgressBar/__tests__/ProgressBarMotion.a11y.chromium.spec.ts +831 -0
  345. package/src/Resizable/__tests__/ResizeHandle.a11y.chromium.spec.ts +21 -14
  346. package/src/Resizable/useResizable.test.ts +43 -0
  347. package/src/Resizable/useResizable.ts +32 -9
  348. package/src/SegmentedControl/SegmentedControl.test.tsx +84 -0
  349. package/src/SegmentedControl/SegmentedControlItem.tsx +11 -5
  350. package/src/Selector/Selector.test.tsx +90 -1
  351. package/src/Selector/__tests__/Selector.combobox.a11y.test.tsx +8 -1
  352. package/src/Selector/__tests__/Selector.listbox.a11y.test.tsx +8 -1
  353. package/src/Selector/useSelectorPresentation.ts +31 -3
  354. package/src/SideNav/SideNav.test.tsx +27 -0
  355. package/src/SideNav/__tests__/SideNavRailMotion.interaction.browser.spec.ts +176 -51
  356. package/src/Slider/Slider.test.tsx +12 -0
  357. package/src/Slider/Slider.tsx +4 -1
  358. package/src/Slider/__tests__/Slider.a11y.chromium.spec.ts +19 -7
  359. package/src/Spinner/Spinner.tsx +2 -2
  360. package/src/Stack/Stack.tsx +1 -1
  361. package/src/Stack/StackItem.tsx +1 -1
  362. package/src/TabList/TabList.test.tsx +58 -4
  363. package/src/TabList/TabList.tsx +16 -1
  364. package/src/TabList/__tests__/TabPressPointer.interaction.browser.spec.ts +163 -0
  365. package/src/Table/__tests__/Table.a11y.chromium.spec.ts +18 -6
  366. package/src/Table/plugins/columnResize/useTableColumnResize.test.tsx +22 -0
  367. package/src/Table/plugins/columnResize/useTableColumnResize.tsx +8 -4
  368. package/src/Text/Text.tsx +1 -1
  369. package/src/Text/useTruncation.test.tsx +128 -1
  370. package/src/Text/useTruncation.ts +23 -5
  371. package/src/TextArea/TextArea.spec.md +10 -13
  372. package/src/TextArea/TextArea.test.tsx +60 -0
  373. package/src/TextArea/TextArea.tsx +15 -1
  374. package/src/TextInput/TextInput.test.tsx +21 -0
  375. package/src/TextInput/TextInput.tsx +3 -1
  376. package/src/TimeInput/NativeTimeInput.test.tsx +17 -0
  377. package/src/TimeInput/Presentation.test.tsx +21 -0
  378. package/src/TimeInput/TimeInput.doc.mjs +8 -8
  379. package/src/TimeInput/TimeInput.spec.md +45 -48
  380. package/src/TimeInput/TimeInput.test.tsx +76 -0
  381. package/src/TimeInput/TimeInput.tsx +36 -18
  382. package/src/TimeInput/TouchTimeField.tsx +4 -6
  383. package/src/Timestamp/Timestamp.spec.md +6 -12
  384. package/src/Timestamp/Timestamp.test.tsx +30 -5
  385. package/src/Timestamp/Timestamp.tsx +6 -2
  386. package/src/Timestamp/TimestampHoverCard.tsx +4 -4
  387. package/src/Toast/Toast.spec.md +14 -20
  388. package/src/Toast/Toast.tsx +104 -36
  389. package/src/Toast/ToastViewport.test.tsx +719 -1
  390. package/src/Toast/ToastViewport.tsx +100 -50
  391. package/src/Tokenizer/Tokenizer.spec.md +5 -3
  392. package/src/Tokenizer/Tokenizer.test.tsx +68 -0
  393. package/src/Tokenizer/Tokenizer.tsx +14 -2
  394. package/src/Tokenizer/TokenizerBottomSheet.test.tsx +15 -4
  395. package/src/Tokenizer/TokenizerBottomSheet.tsx +3 -3
  396. package/src/Toolbar/Toolbar.spec.md +5 -6
  397. package/src/Toolbar/Toolbar.test.tsx +30 -0
  398. package/src/Toolbar/Toolbar.tsx +2 -1
  399. package/src/Toolbar/__tests__/Toolbar.a11y.chromium.spec.ts +18 -6
  400. package/src/Tooltip/__tests__/Tooltip.a11y.chromium.spec.ts +18 -7
  401. package/src/TopNav/TopNav.test.tsx +27 -0
  402. package/src/Typeahead/Typeahead.test.tsx +40 -0
  403. package/src/Typeahead/Typeahead.tsx +12 -1
  404. package/src/gestures/GestureArena.ts +35 -0
  405. package/src/gestures/GestureHost.ts +2065 -0
  406. package/src/gestures/GestureRecognizer.ts +18 -0
  407. package/src/gestures/LongPressGestureRecognizer.ts +4 -0
  408. package/src/gestures/PanGestureRecognizer.ts +4 -0
  409. package/src/gestures/PinchGestureRecognizer.ts +148 -0
  410. package/src/gestures/ScreenEdgePanGestureRecognizer.ts +256 -0
  411. package/src/gestures/SwipeGestureRecognizer.ts +197 -0
  412. package/src/gestures/TapGestureRecognizer.ts +4 -0
  413. package/src/gestures/VelocityTracker.ts +10 -3
  414. package/src/gestures/__tests__/GestureHost.test.ts +2087 -0
  415. package/src/gestures/__tests__/PanGestureRecognizer.test.ts +4 -4
  416. package/src/gestures/__tests__/PinchGestureRecognizer.test.ts +74 -0
  417. package/src/gestures/__tests__/ScreenEdgePanGestureRecognizer.test.ts +498 -0
  418. package/src/gestures/__tests__/SwipeGestureRecognizer.test.ts +108 -0
  419. package/src/gestures/__tests__/arena.test.ts +5 -0
  420. package/src/gestures/__tests__/arenaPinchSwipeEdge.test.ts +193 -0
  421. package/src/gestures/__tests__/browser/build-fixture.mjs +46 -0
  422. package/src/gestures/__tests__/browser/fixture.ts +307 -0
  423. package/src/gestures/__tests__/browser/gestures.interaction.browser.spec.ts +1137 -0
  424. package/src/gestures/__tests__/browserNegotiation.test.ts +293 -0
  425. package/src/gestures/__tests__/haptics.test.ts +187 -0
  426. package/src/gestures/__tests__/harness.ts +21 -2
  427. package/src/gestures/__tests__/recognizerKind.test.ts +78 -0
  428. package/src/gestures/__tests__/touchActionRule.test.ts +54 -0
  429. package/src/gestures/haptics.ts +203 -0
  430. package/src/gestures/nativeScroll.ts +277 -0
  431. package/src/gestures/touchAction.ts +191 -0
  432. package/src/gestures/touchActionRule.ts +157 -0
  433. package/src/gestures/types.ts +30 -9
  434. package/src/hooks/useAdaptivePresentation.ts +4 -1
  435. package/src/hooks/useMenuHover.ts +15 -1
  436. package/src/i18n/generated-locales/en.generated.ts +4 -0
  437. package/src/i18n/generated-locales/pseudo.generated.ts +4 -0
  438. package/src/motion/README.md +11 -1
  439. package/src/motion/animator.test.ts +151 -3
  440. package/src/motion/animator.ts +149 -33
  441. package/src/theme/defineTheme.ts +1 -1
  442. package/src/theme/derivedVarRegistry.test.ts +4 -0
  443. package/src/theme/domainTokens/domainTokenDefaults.ts +19 -0
  444. package/src/theme/domainTokens/index.ts +6 -10
  445. package/src/utils/focusReturn.ts +17 -6
  446. package/src/utils/getNodeText.test.ts +24 -0
  447. package/src/utils/getNodeText.ts +37 -0
  448. package/src/utils/interactionModality.test.ts +45 -1
  449. package/src/utils/interactionModality.ts +64 -5
  450. package/src/utils/plainDate.test.ts +90 -0
  451. package/src/utils/plainDate.ts +58 -3
  452. package/src/utils/presentation.test.ts +380 -0
  453. package/src/utils/presentation.ts +180 -0
  454. package/src/utils/pressPaintPriority.test.ts +80 -0
  455. package/src/utils/primaryClick.test.ts +38 -0
  456. package/src/utils/primaryClick.ts +28 -0
  457. package/src/utils/timeFormat.test.ts +204 -0
  458. package/src/utils/timeFormat.ts +314 -0
  459. package/src/utils/touchPresentation.stylex.ts +43 -0
  460. package/src/utils/touchPresentation.test.ts +140 -1
  461. package/src/utils/touchPresentation.ts +5 -3
  462. package/src/utils/unicodeDigits.test.ts +44 -0
  463. package/src/utils/unicodeDigits.ts +71 -0
@@ -0,0 +1,53 @@
1
+ // Copyright (c) Meta Platforms, Inc. and affiliates.
2
+
3
+ /**
4
+ * @file lazyMenuBottomSheet.test.ts
5
+ * @input lazyMenuBottomSheet's action-list preload, with the list's module
6
+ * failing to load once
7
+ * @output A failed preload is no unhandled rejection, and is not kept: the
8
+ * next load asks the module loader again
9
+ * @position Unit test of ./lazyMenuBottomSheet; the hydration case is in
10
+ * DropdownMenu.ssr.test.tsx
11
+ */
12
+
13
+ import {afterEach, describe, expect, it, vi} from 'vitest';
14
+
15
+ afterEach(() => {
16
+ vi.doUnmock('./MenuBottomSheetActionList');
17
+ vi.resetModules();
18
+ });
19
+
20
+ describe('preloadMenuBottomSheetActionList', () => {
21
+ it('drops a failed preload without an unhandled rejection, and asks the module loader again on the next call', async () => {
22
+ vi.resetModules();
23
+ let attempts = 0;
24
+ vi.doMock('./MenuBottomSheetActionList', () => {
25
+ attempts += 1;
26
+ if (attempts === 1) {
27
+ throw new Error('the connection dropped');
28
+ }
29
+ return {MenuBottomSheetActionList: () => null};
30
+ });
31
+ const unhandled: unknown[] = [];
32
+ const onUnhandled = (reason: unknown) => unhandled.push(reason);
33
+ process.on('unhandledRejection', onUnhandled);
34
+ try {
35
+ const {preloadMenuBottomSheetActionList} =
36
+ await import('./lazyMenuBottomSheet');
37
+ preloadMenuBottomSheetActionList();
38
+ await vi.waitFor(() => expect(attempts).toBe(1));
39
+ // An unhandled rejection is reported after the rejecting task's
40
+ // microtasks: give it two macrotasks.
41
+ await new Promise(resolve => setTimeout(resolve, 0));
42
+ await new Promise(resolve => setTimeout(resolve, 0));
43
+ expect(unhandled).toEqual([]);
44
+
45
+ preloadMenuBottomSheetActionList();
46
+ await vi.waitFor(() => expect(attempts).toBe(2));
47
+ const loaded = await import('./MenuBottomSheetActionList');
48
+ expect(typeof loaded.MenuBottomSheetActionList).toBe('function');
49
+ } finally {
50
+ process.off('unhandledRejection', onUnhandled);
51
+ }
52
+ });
53
+ });
@@ -15,6 +15,11 @@
15
15
  * of pages whose dropdowns only open as anchored popovers. Each wrapper keeps
16
16
  * the wrapped component's props and renders nothing until its module loads.
17
17
  *
18
+ * The action list preloads at rest; a failed load is not kept, so the next
19
+ * preload or open asks the module loader again (a loader that retries then
20
+ * loads it; a browser does not fetch a native module again once its import
21
+ * failed).
22
+ *
18
23
  * Neither wrapper renders on the server or in the render that hydrates server
19
24
  * HTML (spec:AST-013 FR9): a lazy component that has not loaded yet would
20
25
  * leave server markup incomplete and abort hydration. The closed sheet has no
@@ -47,16 +52,28 @@ const LazyMenuBottomSheet = lazy(async () =>
47
52
  let actionListModule: typeof ActionListModule | null = null;
48
53
  let actionListLoad: Promise<typeof ActionListModule> | null = null;
49
54
  async function loadActionList(): Promise<typeof ActionListModule> {
50
- actionListLoad ??= import('./MenuBottomSheetActionList').then(module => {
51
- actionListModule = module;
52
- return module;
53
- });
55
+ actionListLoad ??= import('./MenuBottomSheetActionList').then(
56
+ module => {
57
+ actionListModule = module;
58
+ return module;
59
+ },
60
+ (error: unknown) => {
61
+ // A failed load (a dropped connection) is not kept: the next caller
62
+ // asks the module loader again.
63
+ actionListLoad = null;
64
+ throw error;
65
+ },
66
+ );
54
67
  return actionListLoad;
55
68
  }
56
69
 
57
- /** Starts loading the action list; a sheet menu calls it at rest. */
70
+ /**
71
+ * Starts loading the action list; a sheet menu calls it at rest. A preload
72
+ * that fails is dropped, never an unhandled rejection: the first open asks the
73
+ * module loader again.
74
+ */
58
75
  export function preloadMenuBottomSheetActionList(): void {
59
- void loadActionList();
76
+ loadActionList().catch(() => {});
60
77
  }
61
78
 
62
79
  const LazyMenuBottomSheetActionList = lazy(async () =>
@@ -68,6 +68,28 @@ function renderLeafItem(
68
68
  return <DropdownMenuItem key={getItemKey(item, index)} {...itemProps} />;
69
69
  }
70
70
 
71
+ /**
72
+ * A data item that declares nested `items` becomes a submenu (data-mode
73
+ * parity with the compound DropdownMenuSubMenu API), at the top level and
74
+ * inside a section alike; otherwise it's a leaf. renderDropdownItems owns the
75
+ * recursion and hands the rendered children to DropdownMenuSubMenu, so
76
+ * DropdownMenuSubMenu never imports this module back (no import cycle).
77
+ */
78
+ function renderItem(item: DropdownMenuItemData, index: number): ReactElement {
79
+ if (item.items && item.items.length > 0) {
80
+ return (
81
+ <DropdownMenuSubMenu
82
+ key={getItemKey(item, index)}
83
+ icon={item.icon}
84
+ label={item.label}
85
+ isDisabled={item.isDisabled}>
86
+ {renderDropdownItems(item.items)}
87
+ </DropdownMenuSubMenu>
88
+ );
89
+ }
90
+ return renderLeafItem(item, index);
91
+ }
92
+
71
93
  /**
72
94
  * Converts data-driven items into DropdownMenuItem components,
73
95
  * so both modes share the same rendering and keyboard navigation path.
@@ -96,28 +118,11 @@ export function renderDropdownItems(items: DropdownMenuOption[]): ReactNode {
96
118
  {option.title}
97
119
  </div>
98
120
  )}
99
- {option.items.map(renderLeafItem)}
121
+ {option.items.map(renderItem)}
100
122
  </div>,
101
123
  );
102
124
  } else if (!('type' in option)) {
103
- // A plain item that declares nested `items` becomes a submenu (data-mode
104
- // parity with the compound DropdownMenuSubMenu API); otherwise it's a
105
- // leaf. renderDropdownItems owns the recursion and hands the rendered
106
- // children to DropdownMenuSubMenu — so DropdownMenuSubMenu never imports
107
- // this module back (no import cycle).
108
- if (option.items && option.items.length > 0) {
109
- elements.push(
110
- <DropdownMenuSubMenu
111
- key={getItemKey(option, i)}
112
- icon={option.icon}
113
- label={option.label}
114
- isDisabled={option.isDisabled}>
115
- {renderDropdownItems(option.items)}
116
- </DropdownMenuSubMenu>,
117
- );
118
- } else {
119
- elements.push(renderLeafItem(option, i));
120
- }
125
+ elements.push(renderItem(option, i));
121
126
  }
122
127
  }
123
128
 
@@ -24,7 +24,8 @@ import {
24
24
  } from '../theme/tokens.stylex';
25
25
  import type {BaseProps} from '../BaseProps';
26
26
  import {AnnounceRenderedText} from '../hooks/AnnounceRenderedText';
27
- import {isRenderable, mergeProps} from '../utils';
27
+ import {isRenderable} from '../utils/isRenderable';
28
+ import {mergeProps} from '../utils/mergeProps';
28
29
  import {themeProps} from '../utils/themeProps';
29
30
 
30
31
  const styles = stylex.create({
@@ -19,7 +19,7 @@
19
19
  import {use, useMemo, useRef, type ReactNode, type RefObject} from 'react';
20
20
  import * as stylex from '@stylexjs/stylex';
21
21
  import type {BaseProps} from '../BaseProps';
22
- import {mergeProps} from '../utils';
22
+ import {mergeProps} from '../utils/mergeProps';
23
23
 
24
24
  import {
25
25
  colorVars,
@@ -28,9 +28,10 @@ import {
28
28
  typographyVars,
29
29
  typeScaleVars,
30
30
  } from '../theme/tokens.stylex';
31
- import {Icon, renderIconSlot, type IconType} from '../Icon';
32
- import {Tooltip} from '../Tooltip';
33
- import {useTranslator} from '../i18n';
31
+ import {Icon, renderIconSlot} from '../Icon/Icon';
32
+ import type {IconType} from '../Icon';
33
+ import {Tooltip} from '../Tooltip/Tooltip';
34
+ import {useTranslator} from '../i18n/useTranslator';
34
35
  import {themeProps} from '../utils/themeProps';
35
36
  import {useInputContainer} from '../hooks/useInputContainer';
36
37
  import {FormLayoutContext} from '../FormLayout/FormLayoutContext';
@@ -18,9 +18,9 @@
18
18
 
19
19
  import type {ReactNode} from 'react';
20
20
  import * as stylex from '@stylexjs/stylex';
21
- import {Button} from '../Button';
22
- import {Icon} from '../Icon';
23
- import {useTranslator} from '../i18n';
21
+ import {Button} from '../Button/Button';
22
+ import {Icon} from '../Icon/Icon';
23
+ import {useTranslator} from '../i18n/useTranslator';
24
24
  import {themeProps} from '../utils/themeProps';
25
25
 
26
26
  const styles = stylex.create({
@@ -42,9 +42,9 @@
42
42
  import {useCallback, useState, type Ref} from 'react';
43
43
  import * as stylex from '@stylexjs/stylex';
44
44
  import type {StyleXStyles} from '@stylexjs/stylex';
45
- import {Icon} from '../Icon';
45
+ import {Icon} from '../Icon/Icon';
46
46
  import {InputClearButton} from './InputClearButton';
47
- import {mergeProps} from '../utils';
47
+ import {mergeProps} from '../utils/mergeProps';
48
48
  import {
49
49
  getInteractionModality,
50
50
  useInteractionModalityTracking,
@@ -20,7 +20,7 @@
20
20
  import React from 'react';
21
21
  import * as stylex from '@stylexjs/stylex';
22
22
  import type {BaseProps} from '../BaseProps';
23
- import {mergeProps} from '../utils';
23
+ import {mergeProps} from '../utils/mergeProps';
24
24
  import {
25
25
  colorVars,
26
26
  radiusVars,
@@ -31,7 +31,7 @@ import {
31
31
  import type {InputStatusType} from '../Field/types';
32
32
  import {useEntryAnimation} from '../hooks/useEntryAnimation';
33
33
  import {themeProps} from '../utils/themeProps';
34
- import {Icon} from '../Icon';
34
+ import {Icon} from '../Icon/Icon';
35
35
  import type {IconName} from '../Icon';
36
36
  import type {FieldStatusVariantMap} from './index';
37
37
  import {useFieldStatusAnnouncement} from './useFieldStatusAnnouncement';
@@ -20,6 +20,7 @@ import {
20
20
  } from '@testing-library/react';
21
21
  import userEvent from '@testing-library/user-event';
22
22
  import {FileInput} from './FileInput';
23
+ import {FormLayout} from '../FormLayout';
23
24
  import {__resetLiveRegionsForTest} from '../hooks/useAnnounce';
24
25
  import {InternationalizationProvider} from '../i18n';
25
26
  import {Theme} from '../theme/Theme';
@@ -204,6 +205,26 @@ describe('FileInput', () => {
204
205
  expect(trigger).not.toHaveAttribute('aria-required');
205
206
  });
206
207
 
208
+ it('conveys required state under FormLayout defaultOptionality="required" unless isOptional (FormLayout FR5)', () => {
209
+ render(
210
+ <FormLayout defaultOptionality="required">
211
+ <FileInput label="Resume" value={null} onChange={() => {}} />
212
+ <FileInput
213
+ label="Cover letter"
214
+ isOptional
215
+ value={null}
216
+ onChange={() => {}}
217
+ />
218
+ </FormLayout>,
219
+ );
220
+ expect(
221
+ screen.getByRole('button', {name: 'Resume'}),
222
+ ).toHaveAccessibleDescription(/Required/);
223
+ expect(
224
+ screen.getByRole('button', {name: /Cover letter/}),
225
+ ).not.toHaveAccessibleDescription(/Required/);
226
+ });
227
+
207
228
  it('combines required with the description in the accessible description', () => {
208
229
  render(
209
230
  <FileInput
@@ -68,6 +68,7 @@ import {useTranslator} from '../i18n';
68
68
  import type {TranslatorFn} from '../i18n';
69
69
 
70
70
  import {useMergedRefs} from '../hooks/useMergedRefs';
71
+ import {useResolvedRequired} from '../hooks/useResolvedRequired';
71
72
  function formatFileSize(bytes: number, t: TranslatorFn): string {
72
73
  if (bytes < 1024) {
73
74
  return t('@astryx.fileInput.fileSize.bytes', {size: bytes});
@@ -544,7 +545,9 @@ export function FileInput({
544
545
  // at a visually hidden "Required" span — mirroring the Field label's visible
545
546
  // indicator (where isOptional takes precedence) and the pattern Slider uses
546
547
  // for its thumbs.
547
- const conveysRequired = isRequired && !isOptional;
548
+ // A surrounding FormLayout's defaultOptionality="required" makes an unmarked
549
+ // field required too (FormLayout FR5).
550
+ const conveysRequired = useResolvedRequired({isRequired, isOptional});
548
551
 
549
552
  const ariaDescribedBy =
550
553
  [
@@ -63,12 +63,11 @@ This table is a review projection; the body below is authoritative.
63
63
 
64
64
  ## Current-state impact
65
65
 
66
- - **Required state lost for four controls (FR5, AR2).** Under
66
+ - **Required state lost for two controls (FR5, AR2).** Under
67
67
  `defaultOptionality="required"` the visible "Required" marker is hidden,
68
- but Typeahead and Tokenizer set no `aria-required`, and FileInput and
69
- Slider build their required description from `isRequired` alone. Screen
70
- reader users hear those fields as not required, while sighted users see
71
- the form-wide convention.
68
+ but Typeahead and Tokenizer set no `aria-required`. Screen reader users
69
+ hear those fields as not required, while sighted users see the form-wide
70
+ convention.
72
71
 
73
72
  ## Ownership boundary
74
73
 
@@ -101,7 +100,7 @@ This table is a review projection; the body below is authoritative.
101
100
  | FR2 | `horizontal` places every direct child in one `1fr` grid column in the document's logical inline order, with a `--spacing-4` gap and no component-owned wrap rule. | Released source, tests, and stories |
102
101
  | FR3 | `horizontal-labels` is a two-column grid (`auto 1fr`) with a `--spacing-3` row gap and `--spacing-4` column gap, items aligned to the start, so Field labels sit on the inline-start side of their controls; at a viewport width of 480px or below it becomes one flex column with a `--spacing-4` gap. OQ1 holds whether the collapsed label and control need a tighter pair gap. | Released source, Field composition, and tests |
103
102
  | FR4 | FormLayout provides its direction and `defaultOptionality` to descendants in the same layer; a nested FormLayout replaces both for its own descendants, and content in a layer opened inside a FormLayout starts without them (`spec:AST-038` FR7, FR8). | Context source and tests |
104
- | FR5 | `defaultOptionality` suppresses only the visible marker that restates the form default; descendant controls still expose the resolved `aria-required`, while native `required` stays tied to an explicit field `isRequired`. Unset keeps each field's own indicators. Implementation gap: under `defaultOptionality="required"`, Typeahead and Tokenizer set no `aria-required`, and FileInput and Slider describe required state from `isRequired` alone, so those fields are announced as not required while the marker is hidden (Current-state impact). | Tests; `family:input-fields` ownership |
103
+ | FR5 | `defaultOptionality` suppresses only the visible marker that restates the form default; descendant controls still expose the resolved `aria-required`, while native `required` stays tied to an explicit field `isRequired`. Unset keeps each field's own indicators. Implementation gap: under `defaultOptionality="required"`, Typeahead and Tokenizer set no `aria-required`, so those fields are announced as not required while the marker is hidden (Current-state impact). | Tests; `family:input-fields` ownership |
105
104
  | FR6 | The root is a `div`. `ref`, DOM, data, ARIA, and event props, `xstyle`, class name, and inline style reach or compose on the root without replacing `data-direction` or the `form-layout` target. | `architecture:public-component-api/INV5–INV8`; source and tests |
106
105
 
107
106
  ### Allowed variation
@@ -135,7 +134,7 @@ This table is a review projection; the body below is authoritative.
135
134
  ## Accessibility contract
136
135
 
137
136
  - **AR1 — Layout remains nonsemantic.** FormLayout renders a `<div>` and does not imply `<form>`, group, label, or submission semantics; callers provide those when their composition needs them.
138
- - **AR2 — Required state remains perceivable.** A form-wide optionality convention may remove redundant visible markers, but descendant controls preserve the resolved required state for assistive technology. Implementation gap: Typeahead, Tokenizer, FileInput, and Slider do not (FR5).
137
+ - **AR2 — Required state remains perceivable.** A form-wide optionality convention may remove redundant visible markers, but descendant controls preserve the resolved required state for assistive technology. Implementation gap: Typeahead and Tokenizer do not (FR5).
139
138
  - **AR3 — Logical order is preserved.** Every direction retains DOM order and logical inline flow; FormLayout does not create a separate keyboard order.
140
139
 
141
140
  ## Design relationships
@@ -191,7 +190,7 @@ The root target reflects the closed `direction` axis. It owns the outer arrangem
191
190
  | -------------- | ----------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | -------------------------------- |
192
191
  | FR1–FR3 | `FormLayout.test.tsx` direction snapshots; `FormLayout.stories.tsx` play checks; stable visual baseline `core-formlayout--vertical` | Vertical, horizontal, horizontal-labels wide and narrow | A changed style class set fails the snapshots; a narrow horizontal-labels control narrower than the layout, or a wide label not before its control, fails the play checks; a changed vertical layout comes back changed for review. The story play guard also runs the AuditMatrix play right-to-left at 320px and the default width, where mirrored horizontal columns are asserted. Gap: no right-to-left check asserts that a horizontal-labels label sits on the inline-start side of its control. | `audit:FormLayout/behavior` |
193
192
  | FR4, ORD1 | `FormLayout.test.tsx` context and nesting tests; `Layer/layerScopedContext.test.tsx` | Default, explicit, nested; content in a fixed Layer and an inline Dialog | A lost default or value, lost shadowing by an inner layout's explicit values, or content inside a layer that still reads the outer `defaultOptionality` fails. Gap: no test covers an inner layout with unset props (which supplies its own defaults) or `direction` across a layer boundary. | `audit:FormLayout/behavior` |
194
- | FR5, ORD3, AR2 | `FormLayout.test.tsx` optionality and `aria-required` tests | Required, optional, unset defaults; explicit exceptions | A redundant marker, a missing `aria-required`, or a native `required` from the default fails. Gap: no test covers Typeahead, Tokenizer, FileInput, or Slider under a `required` default, which do not expose it. | `audit:FormLayout/accessibility` |
193
+ | FR5, ORD3, AR2 | `FormLayout.test.tsx` optionality and `aria-required` tests | Required, optional, unset defaults; explicit exceptions | A redundant marker, a missing `aria-required`, or a native `required` from the default fails. FileInput and Slider tests cover a `required` default. Gap: no test covers Typeahead or Tokenizer under a `required` default, which do not expose it. | `audit:FormLayout/accessibility` |
195
194
  | FR6, ORD2 | `FormLayout.test.tsx` ref, passthrough, and owned-metadata tests; `themingTargets.test.ts` | Ref, attributes, colliding `data-direction` | A ref on a non-`div`, a dropped `id` or `role`, or a replaced `data-direction` fails. Gap: no test covers event props or the styling-input merge order. | `audit:FormLayout/api` |
196
195
  | AR1, AR3 | `FormLayout.test.tsx` div and passthrough tests; `FormLayout.stories.tsx` play checks | Plain root; caller `role` | A non-`div` root or a dropped caller `role` fails. Horizontal columns that do not mirror right-to-left fail the AuditMatrix play under the story play guard. Gap: no check fails if FormLayout adds a role of its own. | `audit:FormLayout/accessibility` |
197
196
  | PR1 | Source review | Every direction | Gap: no automated check covers context identity or added resources. | `audit:FormLayout/behavior` |
@@ -45,7 +45,7 @@ import {
45
45
  import {useTruncation} from '../Text/useTruncation';
46
46
  import {resolveStyleColor} from '../Text/Text';
47
47
  import type {LayerPlacement} from '../Layer';
48
- import {mergeProps} from '../utils';
48
+ import {mergeProps} from '../utils/mergeProps';
49
49
  import {useMergedRefs} from '../hooks/useMergedRefs';
50
50
  import type {BaseProps} from '../BaseProps';
51
51
  import {themeProps} from '../utils/themeProps';
package/src/Icon/Icon.tsx CHANGED
@@ -38,7 +38,7 @@ import {useThemeName} from '../theme/useTheme';
38
38
  import {resolveIcon} from './globalIconRegistry';
39
39
  import type {IconName, NamespacedIconName} from './globalIconRegistry';
40
40
  import type {IconVariant} from './index';
41
- import {mergeProps} from '../utils';
41
+ import {mergeProps} from '../utils/mergeProps';
42
42
  import {themeProps} from '../utils/themeProps';
43
43
  import {useIconSize} from './IconDefaultSizeContext';
44
44
  import {iconSizeStyles, type IconSize} from './IconSize.stylex';
@@ -1,20 +1,19 @@
1
1
  ---
2
2
  schema_version: 3
3
- template_version: 6
3
+ template_version: 7
4
4
  kind: component
5
5
  id: component:CheckIndicator
6
- authority: draft
6
+ authority: current
7
7
  archive_reason: null
8
8
  superseded_by: null
9
- approved_by: null
10
- approved_at: null
9
+ approved_by: cixzhang
10
+ approved_at: 2026-10-31
11
11
  owners: [cixzhang]
12
12
  review_triggers: [public-api, behavior, theming, accessibility, visual]
13
13
  verified_by:
14
14
  [
15
15
  packages/core/src/Indicator/Indicator.test.tsx,
16
16
  packages/core/src/theme/themingTargets.test.ts,
17
- apps/storybook/stories/Indicator.stories.tsx,
18
17
  ]
19
18
  modules: []
20
19
  families: []
@@ -33,17 +32,17 @@ system_specs: []
33
32
 
34
33
  ## Contract at a glance
35
34
 
36
- | Area | Contract |
37
- | ----------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
38
- | Public contract | `CheckIndicator` is exported from `@astryxdesign/core/Indicator`; `state` is required, `size` defaults to `md`, `isDisabled` defaults to `false`, and `children` may replace the built-in mark. |
39
- | Behavior | The component draws a decorative check glyph only when checked. Shallow-renderable `children` replace that glyph in either state; unchecked without replacement content renders no element. |
40
- | End-user impact | People receive one selection cue from the owning control without a duplicate accessible object or an empty placeholder beside unselected rows. |
41
- | Builder impact | Builders may replace the named `check` indicator or compose host-owned classes and styling without taking over the owning control's semantics. |
42
- | Compatibility/readiness | The released component and default state behavior remain unchanged. The checked glyph path currently drops the declared `ref`; this draft records that current-authority gap without choosing a new DOM or ref contract. |
43
- | Review checks | Reject lost `aria-hidden`, a mark in the unchecked default, a missing checked mark, dropped supported DOM/styling passthrough, changed replacement precedence, a new component-owned theme target, or any claim that the checked-path ref gap is resolved. |
44
- | Governing rules | `architecture:public-component-api/INV1,INV5,INV6,INV8,INV9`; `architecture:component-theming-surface/INV3–INV6`; `architecture:component-test-sufficiency/INV1–INV7,INV10–INV11`. |
35
+ | Area | Contract |
36
+ | ----------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
37
+ | Public contract | `CheckIndicator` is exported from `@astryxdesign/core/Indicator`; `state` is required, `size` defaults to `md`, `isDisabled` defaults to `false`, and `children` may replace the built-in mark. |
38
+ | Behavior | The component draws a decorative check glyph only when checked. Shallow-renderable `children` replace that glyph in either state; unchecked without replacement content renders no element. |
39
+ | End-user impact | People receive one selection cue from the owning control without a duplicate accessible object or an empty placeholder beside unselected rows. |
40
+ | Builder impact | Builders may replace the named `check` indicator or compose host-owned classes and styling without taking over the owning control's semantics. |
41
+ | Compatibility/readiness | Records shipped behavior; no API, default, or DOM change. The checked glyph path drops the declared `ref`; listed under Current-state impact, with the fix open (OQ1). |
42
+ | Review checks | Reject lost `aria-hidden`, a mark in the unchecked default, a missing checked mark, dropped supported DOM/styling passthrough, changed replacement precedence, a new component-owned theme target, or a checked path that still drops the ref once OQ1 is decided. |
43
+ | Governing rules | `architecture:public-component-api/INV1,INV5,INV6,INV8,INV9`; `architecture:component-theming-surface/INV3–INV6`; `architecture:component-test-sufficiency/INV1–INV7,INV10–INV11`. |
45
44
 
46
- This table is a review projection; the body below is authoritative only after owner approval.
45
+ This table is a review projection; the body below is authoritative.
47
46
 
48
47
  ## Intent
49
48
 
@@ -52,7 +51,8 @@ Render the replaceable, decorative checkmark used by a host to show that one opt
52
51
  ## Compatibility and migration
53
52
 
54
53
  - Released default preserved: yes
55
- - Compatibility class: observational only; no runtime or public-type change
54
+ - Compatibility class: records shipped behavior; no public prop, default,
55
+ export, or DOM change
56
56
  - Controlled/uncontrolled behavior: not applicable; `state` is supplied by the owner
57
57
  - Migration decision: none; the public component and `check` registry name remain unchanged
58
58
 
@@ -68,29 +68,29 @@ Consumer migration instructions belong in consumer docs and release notes.
68
68
  **Does not own / non-goals**
69
69
 
70
70
  - Selection role, accessible name, state, focus, keyboard, activation, or busy semantics — owned by the composing control.
71
- - Persistent checkbox or radio chrome — owned by `component:CheckboxIndicator` or `component:RadioIndicator`.
71
+ - Persistent checkbox or radio chrome — owned by `component:CheckboxIndicator` or `component:Indicator`.
72
72
  - Row placement and logical-edge layout — owned by the host component.
73
73
  - The behavior or accessibility of consumer-supplied replacement content.
74
74
 
75
75
  ## Public concepts
76
76
 
77
- | Concept | Closed values or states | Meaning | Availability by variant/orientation/state | Default | Owner | Stability | Invalid-value behavior |
78
- | ------------------- | --------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------- | ------------------ | -------------------------- | ------------------------------------------ | -------------------------------------------------- |
79
- | state | `unchecked`, `checked` | Selects whether the built-in check glyph is absent or present. | Every render path. | required | `component:CheckIndicator` | stable | rejected by the public type |
80
- | size | `sm`, `md` | Selects the shared indicator size; both current values use the `sm` Icon glyph. | Checked and replacement-content roots. | `md` | `component:CheckIndicator` | stable | rejected by the public type |
81
- | disabled appearance | enabled, disabled | Mirrors the owning control's disabled color without creating semantics. | Checked and replacement-content roots. | enabled | `component:CheckIndicator` | stable | boolean only |
82
- | replacement content | shallow renderable or empty | Replaces the built-in mark in either state when `isRenderable(children)` returns true. React elements and containers take this branch even when descendants render nothing. | Every state; replacement content creates a span root. | built-in mark path | `component:CheckIndicator` | observed; empty-container policy unsettled | unsupported values follow React rendering behavior |
77
+ | Concept | Closed values or states | Meaning | Availability by variant/orientation/state | Default | Owner | Stability | Invalid-value behavior |
78
+ | ------------------- | --------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------- | ------------------ | -------------------------- | ----------------------------------------- | -------------------------------------------------- |
79
+ | state | `unchecked`, `checked` | Selects whether the built-in check glyph is absent or present. | Every render path. | required | `component:CheckIndicator` | stable | rejected by the public type |
80
+ | size | `sm`, `md` | Selects the shared indicator size; both current values use the `sm` Icon glyph. | Checked and replacement-content roots. | `md` | `component:CheckIndicator` | stable | rejected by the public type |
81
+ | disabled appearance | enabled, disabled | Mirrors the owning control's disabled color without creating semantics. | Checked and replacement-content roots. | enabled | `component:CheckIndicator` | stable | boolean only |
82
+ | replacement content | shallow renderable or empty | Replaces the built-in mark in either state when `isRenderable(children)` returns true. React elements and containers take this branch even when descendants render nothing. | Every state; replacement content creates a span root. | built-in mark path | `component:CheckIndicator` | stable; empty-container policy open (OQ2) | unsupported values follow React rendering behavior |
83
83
 
84
84
  ## Behavioral and layout contract
85
85
 
86
- | ID | Candidate invariant | Basis | Draft review state |
87
- | --- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------- | ------------------ |
88
- | FR1 | The component MUST render one decorative check glyph when `state="checked"` and no replacement content is present, and MUST set its own `aria-hidden="true"` after caller passthrough. | shipped source; `architecture:public-component-api/INV5` | verify |
89
- | FR2 | The default component MUST render no element when `state="unchecked"` and no replacement content is present. | shipped source, docs, tests, and stories | verify |
90
- | FR3 | The current implementation uses shallow `isRenderable(children)` replacement precedence in both states: nullish values, booleans, and the empty string keep the built-in state behavior; React elements and containers replace it even when descendants render nothing. This draft does not settle whether empty-container behavior should remain public policy. | shipped source and regression tests | verify |
91
- | FR4 | Every rendered root MUST preserve supported DOM props, `className`, `style`, and `xstyle` while keeping component-owned accessibility precedence. Under `architecture:public-component-api/INV8`, the declared ref also MUST reach the promised root; the replacement-content span does, but the checked Icon path currently drops it. | `architecture:public-component-api/INV5,INV6,INV8`; shipped source review | human decision |
92
- | FR5 | The built-in checked mark MUST remain an Icon-owned painter on the same element as host-supplied classes; CheckIndicator MUST NOT add a wrapper or a distinct public target without an approved contract change. | shipped source; `architecture:component-theming-surface/INV3–INV5` | verify |
93
- | FR6 | Disabled color and replacement-content color MUST continue to use semantic tokens rather than raw color values. | shipped source; current token and theming architecture | verify |
86
+ | ID | Invariant | Basis |
87
+ | --- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------ |
88
+ | FR1 | The component MUST render one decorative check glyph when `state="checked"` and no replacement content is present, and MUST set its own `aria-hidden="true"` after caller passthrough. | shipped source; `architecture:public-component-api/INV5` |
89
+ | FR2 | The default component MUST render no element when `state="unchecked"` and no replacement content is present. | shipped source, docs, tests, and stories |
90
+ | FR3 | Replacement uses shallow `isRenderable(children)` precedence in both states: nullish values, booleans, and the empty string keep the built-in state behavior; React elements and containers replace it even when descendants render nothing (OQ2). | shipped source and regression tests |
91
+ | FR4 | Every rendered root MUST preserve supported DOM props, `className`, `style`, and `xstyle` while keeping component-owned accessibility precedence, and the declared ref MUST reach the rendered root (`architecture:public-component-api/INV8`). Implementation gap: the replacement-content span receives the ref, but the checked Icon path drops it (OQ1). | `architecture:public-component-api/INV5,INV6,INV8`; current source |
92
+ | FR5 | The built-in checked mark MUST remain an Icon-owned painter on the same element as host-supplied classes; CheckIndicator MUST NOT add a wrapper or a distinct public target without an approved contract change. | shipped source; `architecture:component-theming-surface/INV3–INV5` |
93
+ | FR6 | Disabled color and replacement-content color MUST continue to use semantic tokens rather than raw color values. | shipped source; current token and theming architecture |
94
94
 
95
95
  ### Allowed variation
96
96
 
@@ -126,7 +126,7 @@ Consumer migration instructions belong in consumer docs and release notes.
126
126
  | Chrome | CheckIndicator intentionally owns no persistent chrome. | observed shipped representation | not applicable | FR2, FR5 |
127
127
  | State mark | Checked state renders the shared decorative check Icon. | Icon-owned current theming architecture | supporting state cue | FR1, FR5–FR6 |
128
128
 
129
- The shared `Indicator.doc.mjs` owns anatomy and targets for CheckboxIndicator, CheckIndicator, and RadioIndicator together. This component draft does not add an `anatomy-theming:v1` block while that shared consumer record remains the canonical cross-component inventory; the block is optional during migration. CheckIndicator owns no persistent chrome and delegates its built-in checked mark to Icon.
129
+ The shared `Indicator.doc.mjs` lists anatomy and targets for CheckboxIndicator, CheckIndicator, and RadioIndicator together, so this record carries no anatomy-theming map. CheckIndicator owns no persistent chrome and delegates its built-in checked mark to Icon.
130
130
 
131
131
  ## Family and system relationships
132
132
 
@@ -136,23 +136,28 @@ The shared `Indicator.doc.mjs` owns anatomy and targets for CheckboxIndicator, C
136
136
 
137
137
  ## Verification map
138
138
 
139
- | Contract | Verification | Representative states | Mutation or failure expectation | Audit section |
140
- | ----------- | ----------------------------------------------------------- | --------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------- | ------------------------------- |
141
- | FR1–FR3 | `Indicator.test.tsx` state and replacement-content cases | checked, unchecked, empty scalar, visible child, numeric 0 | Removing the glyph, adding unchecked chrome, or choosing the wrong children branch fails DOM assertions. | `audit:CheckIndicator/behavior` |
142
- | FR1, AR1 | `Indicator.test.tsx` decorative-contract cases | glyph and replacement roots; hostile `aria-hidden` input | Removing or reordering owned `aria-hidden` exposes duplicate semantics. | `audit:CheckIndicator/a11y` |
143
- | FR4 | `Indicator.test.tsx`, strict lint, and source review | neutral DOM props on both roots; replacement-root class; checked-path style composition | Passthrough stops reaching a rendered root or the checked Icon stops receiving composed `className`, `style`, and `xstyle`. | `audit:CheckIndicator/api` |
144
- | FR4 ref gap | source review | checked Icon root and replacement-content span | The declared ref remains `null` on the checked path while reaching the replacement span. | `audit:CheckIndicator/api` |
145
- | FR5–FR6 | source review, Icon target guards, and rendered evidence | checked, disabled, replacement content; light/dark | A wrapper separates the host target from the painter or semantic color stops reaching the mark. | `audit:CheckIndicator/theming` |
146
- | All | `Indicator.stories.tsx`, component-scoped axe and RTL audit | all states, sizes, disabled, replacement content | A required rendered state is unreachable or gains an accessibility/RTL failure. | `audit:CheckIndicator/testing` |
139
+ | Contract | Verification | Representative states | Mutation or failure expectation | Audit section |
140
+ | ------------- | ------------------------------------------------------------------------------------------------------ | ----------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------ |
141
+ | FR1, FR2, FR3 | `Indicator.test.tsx` CheckIndicator state and replacement cases; falsy-children cases | Checked, unchecked, empty scalar, visible child, `0` | Removing the glyph, adding unchecked chrome, or choosing the wrong children branch fails. | `audit:CheckIndicator/behavior` |
142
+ | FR1, AR1 | `Indicator.test.tsx` decorative-contract cases | Glyph and replacement roots; a caller `aria-hidden={false}` | A root that a caller can expose fails. Evidence gap: no test asserts that replacement content is not the only state expression (AR2). | `audit:CheckIndicator/accessibility` |
143
+ | FR4 | `Indicator.test.tsx` "forwards caller props and styling on both render paths" | Both render paths | A caller DOM prop that stops reaching either root, or a `className` that stops reaching the replacement span, fails. Evidence gap: no test asserts `className`, `style`, or `xstyle` on the checked-glyph path, `style` or `xstyle` on the replacement span, or the ref on either path (the checked-path ref is the FR4 gap). | `audit:CheckIndicator/api` |
144
+ | FR5, FR6 | `themingTargets.test.ts` | Checked glyph | A rendered class absent from the documented targets fails. Evidence gap: no test asserts that no wrapper separates host classes from the Icon painter, or that disabled and replacement colors use semantic tokens. | `audit:CheckIndicator/theming` |
145
+ | ORD1, PR1 | Covered by the FR1–FR4 rows. Evidence gap: no test asserts the absence of state, effects, or listeners | — | — | `audit:CheckIndicator/behavior` |
146
+
147
+ ## Current-state impact
148
+
149
+ - **Checked-path ref (FR4).** The declared ref is `null` when CheckIndicator
150
+ draws its checked glyph, against `architecture:public-component-api` INV8; the
151
+ fix is OQ1.
147
152
 
148
153
  ## Decision log
149
154
 
150
- None. This draft records only verified shipped behavior.
155
+ No component-local decision.
151
156
 
152
157
  ## Open questions
153
158
 
154
159
  - **OQ1 — Should CheckIndicator preserve its declared `HTMLSpanElement` ref by owning a stable span root in the checked path, or should the public ref contract change to match the Icon-owned painter?** (`human-api`) The current checked path returns `null`; either correction changes a released DOM or ref contract.
155
- - **OQ2 — Should empty React containers continue to suppress the built-in state mark?** (`human-api`) This observational draft records the current shallow branch without approving it as future policy.
160
+ - **OQ2 — Should empty React containers continue to suppress the built-in state mark?** (`human-api`) FR3 records that they do today.
156
161
 
157
162
  ## Content boundary
158
163
 
@@ -34,7 +34,8 @@ import * as stylex from '@stylexjs/stylex';
34
34
  import type {SVGProps} from 'react';
35
35
  import {Icon} from '../Icon/Icon';
36
36
  import {colorVars} from '../theme/tokens.stylex';
37
- import {isRenderable, mergeProps} from '../utils';
37
+ import {isRenderable} from '../utils/isRenderable';
38
+ import {mergeProps} from '../utils/mergeProps';
38
39
  import type {IndicatorProps} from './types';
39
40
 
40
41
  /** The check glyph matches the control sizes the indicator families share. */