@astryxdesign/core 0.1.2 → 0.1.3

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 (567) hide show
  1. package/CHANGELOG.md +165 -0
  2. package/README.md +12 -12
  3. package/dist/Avatar/Avatar.d.ts.map +1 -1
  4. package/dist/Avatar/Avatar.js +11 -5
  5. package/dist/Breadcrumbs/BreadcrumbItem.d.ts +1 -1
  6. package/dist/Breadcrumbs/BreadcrumbItem.d.ts.map +1 -1
  7. package/dist/Breadcrumbs/BreadcrumbItem.js +24 -5
  8. package/dist/Button/Button.d.ts.map +1 -1
  9. package/dist/Button/Button.js +2 -4
  10. package/dist/ButtonGroup/ButtonGroup.d.ts.map +1 -1
  11. package/dist/ButtonGroup/ButtonGroup.js +0 -1
  12. package/dist/Calendar/Calendar.d.ts +5 -4
  13. package/dist/Calendar/Calendar.d.ts.map +1 -1
  14. package/dist/Calendar/Calendar.js +82 -43
  15. package/dist/Calendar/hooks/index.d.ts +0 -2
  16. package/dist/Calendar/hooks/index.d.ts.map +1 -1
  17. package/dist/Calendar/hooks/index.js +1 -2
  18. package/dist/Calendar/index.d.ts +3 -3
  19. package/dist/Calendar/index.d.ts.map +1 -1
  20. package/dist/Calendar/index.js +1 -1
  21. package/dist/Calendar/styles.d.ts +3 -9
  22. package/dist/Calendar/styles.d.ts.map +1 -1
  23. package/dist/Calendar/styles.js +3 -11
  24. package/dist/Carousel/Carousel.d.ts.map +1 -1
  25. package/dist/Carousel/Carousel.js +17 -3
  26. package/dist/Center/Center.d.ts +11 -1
  27. package/dist/Center/Center.d.ts.map +1 -1
  28. package/dist/Center/Center.js +9 -3
  29. package/dist/Chat/ChatComposerInput.d.ts.map +1 -1
  30. package/dist/Chat/ChatComposerInput.js +0 -1
  31. package/dist/Chat/ChatMessageList.d.ts +14 -1
  32. package/dist/Chat/ChatMessageList.d.ts.map +1 -1
  33. package/dist/Chat/ChatMessageList.js +2 -0
  34. package/dist/Chat/useTriggerMenu.d.ts +8 -1
  35. package/dist/Chat/useTriggerMenu.d.ts.map +1 -1
  36. package/dist/Chat/useTriggerMenu.js +15 -3
  37. package/dist/CheckboxInput/CheckboxInput.d.ts +23 -2
  38. package/dist/CheckboxInput/CheckboxInput.d.ts.map +1 -1
  39. package/dist/CheckboxInput/CheckboxInput.js +51 -9
  40. package/dist/CheckboxList/CheckboxList.d.ts +13 -1
  41. package/dist/CheckboxList/CheckboxList.d.ts.map +1 -1
  42. package/dist/CheckboxList/CheckboxList.js +39 -9
  43. package/dist/CheckboxList/CheckboxListContext.d.ts +7 -0
  44. package/dist/CheckboxList/CheckboxListContext.d.ts.map +1 -1
  45. package/dist/CheckboxList/CheckboxListItem.d.ts.map +1 -1
  46. package/dist/CheckboxList/CheckboxListItem.js +0 -1
  47. package/dist/Citation/Citation.d.ts.map +1 -1
  48. package/dist/Citation/Citation.js +9 -5
  49. package/dist/CodeBlock/CodeBlock.d.ts.map +1 -1
  50. package/dist/CodeBlock/CodeBlock.js +51 -37
  51. package/dist/CommandPalette/CommandPalette.d.ts.map +1 -1
  52. package/dist/CommandPalette/CommandPalette.js +5 -5
  53. package/dist/ContextMenu/ContextMenu.d.ts +4 -5
  54. package/dist/ContextMenu/ContextMenu.d.ts.map +1 -1
  55. package/dist/ContextMenu/ContextMenu.js +93 -11
  56. package/dist/DateInput/DateInput.d.ts +23 -1
  57. package/dist/DateInput/DateInput.d.ts.map +1 -1
  58. package/dist/DateInput/DateInput.js +167 -99
  59. package/dist/DateRangeInput/DateRangeInput.d.ts +23 -1
  60. package/dist/DateRangeInput/DateRangeInput.d.ts.map +1 -1
  61. package/dist/DateRangeInput/DateRangeInput.js +42 -9
  62. package/dist/DateTimeInput/DateTimeInput.d.ts +35 -2
  63. package/dist/DateTimeInput/DateTimeInput.d.ts.map +1 -1
  64. package/dist/DateTimeInput/DateTimeInput.js +78 -15
  65. package/dist/Dialog/Dialog.d.ts.map +1 -1
  66. package/dist/Dialog/Dialog.js +12 -0
  67. package/dist/DropdownMenu/DropdownMenu.d.ts +1 -8
  68. package/dist/DropdownMenu/DropdownMenu.d.ts.map +1 -1
  69. package/dist/DropdownMenu/DropdownMenu.js +42 -14
  70. package/dist/Field/Field.d.ts +19 -2
  71. package/dist/Field/Field.d.ts.map +1 -1
  72. package/dist/Field/Field.js +4 -0
  73. package/dist/Field/FieldLabel.d.ts +21 -2
  74. package/dist/Field/FieldLabel.d.ts.map +1 -1
  75. package/dist/Field/FieldLabel.js +41 -26
  76. package/dist/FileInput/FileInput.d.ts +22 -1
  77. package/dist/FileInput/FileInput.d.ts.map +1 -1
  78. package/dist/FileInput/FileInput.js +56 -10
  79. package/dist/Grid/Grid.d.ts +11 -1
  80. package/dist/Grid/Grid.d.ts.map +1 -1
  81. package/dist/Grid/Grid.js +32 -6
  82. package/dist/InputGroup/InputGroup.d.ts +4 -3
  83. package/dist/InputGroup/InputGroup.d.ts.map +1 -1
  84. package/dist/InputGroup/InputGroup.js +16 -6
  85. package/dist/InputGroup/InputGroupContext.d.ts +4 -0
  86. package/dist/InputGroup/InputGroupContext.d.ts.map +1 -1
  87. package/dist/InputGroup/InputGroupContext.js +2 -2
  88. package/dist/InputGroup/groupStyles.d.ts +1 -1
  89. package/dist/InputGroup/groupStyles.d.ts.map +1 -1
  90. package/dist/InputGroup/groupStyles.js +3 -3
  91. package/dist/InputGroup/index.d.ts +1 -0
  92. package/dist/InputGroup/index.d.ts.map +1 -1
  93. package/dist/Kbd/Kbd.d.ts.map +1 -1
  94. package/dist/Kbd/Kbd.js +33 -1
  95. package/dist/Layer/layerAnimations.stylex.d.ts +4 -0
  96. package/dist/Layer/layerAnimations.stylex.d.ts.map +1 -1
  97. package/dist/Layer/layerAnimations.stylex.js +8 -4
  98. package/dist/Layer/useLayer.d.ts +10 -0
  99. package/dist/Layer/useLayer.d.ts.map +1 -1
  100. package/dist/Layer/useLayer.js +64 -9
  101. package/dist/Layout/Layout.d.ts +4 -11
  102. package/dist/Layout/Layout.d.ts.map +1 -1
  103. package/dist/Layout/Layout.js +10 -11
  104. package/dist/Layout/LayoutFooter.d.ts +2 -2
  105. package/dist/Layout/LayoutFooter.d.ts.map +1 -1
  106. package/dist/Layout/LayoutHeader.d.ts +2 -2
  107. package/dist/Layout/LayoutHeader.d.ts.map +1 -1
  108. package/dist/Layout/LayoutPanel.d.ts +2 -2
  109. package/dist/Layout/LayoutPanel.d.ts.map +1 -1
  110. package/dist/Layout/padding.stylex.d.ts +51 -0
  111. package/dist/Layout/padding.stylex.d.ts.map +1 -1
  112. package/dist/Layout/padding.stylex.js +63 -0
  113. package/dist/Lightbox/Lightbox.d.ts.map +1 -1
  114. package/dist/Lightbox/Lightbox.js +4 -2
  115. package/dist/Link/Link.d.ts +16 -1
  116. package/dist/Link/Link.d.ts.map +1 -1
  117. package/dist/Link/Link.js +18 -7
  118. package/dist/Markdown/Markdown.d.ts.map +1 -1
  119. package/dist/Markdown/Markdown.js +7 -0
  120. package/dist/MoreMenu/MoreMenu.d.ts +1 -7
  121. package/dist/MoreMenu/MoreMenu.d.ts.map +1 -1
  122. package/dist/MoreMenu/MoreMenu.js +0 -2
  123. package/dist/MultiSelector/MultiSelector.d.ts +27 -2
  124. package/dist/MultiSelector/MultiSelector.d.ts.map +1 -1
  125. package/dist/MultiSelector/MultiSelector.js +141 -42
  126. package/dist/MultiSelector/hooks.d.ts +12 -1
  127. package/dist/MultiSelector/hooks.d.ts.map +1 -1
  128. package/dist/MultiSelector/hooks.js +14 -1
  129. package/dist/NavMenu/NavHeadingMenu.d.ts.map +1 -1
  130. package/dist/NavMenu/NavHeadingMenu.js +34 -3
  131. package/dist/NumberInput/NumberInput.d.ts +23 -2
  132. package/dist/NumberInput/NumberInput.d.ts.map +1 -1
  133. package/dist/NumberInput/NumberInput.js +62 -12
  134. package/dist/Pagination/Pagination.d.ts +1 -1
  135. package/dist/Pagination/Pagination.d.ts.map +1 -1
  136. package/dist/Pagination/Pagination.js +15 -1
  137. package/dist/Popover/Popover.d.ts +18 -2
  138. package/dist/Popover/Popover.d.ts.map +1 -1
  139. package/dist/Popover/Popover.js +5 -2
  140. package/dist/Popover/usePopover.d.ts +38 -3
  141. package/dist/Popover/usePopover.d.ts.map +1 -1
  142. package/dist/Popover/usePopover.js +24 -9
  143. package/dist/PowerSearch/PowerSearch.d.ts +11 -1
  144. package/dist/PowerSearch/PowerSearch.d.ts.map +1 -1
  145. package/dist/PowerSearch/PowerSearch.js +6 -1
  146. package/dist/ProgressBar/ProgressBar.d.ts.map +1 -1
  147. package/dist/ProgressBar/ProgressBar.js +3 -5
  148. package/dist/RadioList/RadioList.d.ts +20 -2
  149. package/dist/RadioList/RadioList.d.ts.map +1 -1
  150. package/dist/RadioList/RadioList.js +105 -9
  151. package/dist/RadioList/RadioListItem.d.ts.map +1 -1
  152. package/dist/RadioList/RadioListItem.js +13 -2
  153. package/dist/SegmentedControl/SegmentedControl.d.ts +13 -2
  154. package/dist/SegmentedControl/SegmentedControl.d.ts.map +1 -1
  155. package/dist/SegmentedControl/SegmentedControl.js +78 -44
  156. package/dist/SegmentedControl/SegmentedControlContext.d.ts +7 -0
  157. package/dist/SegmentedControl/SegmentedControlContext.d.ts.map +1 -1
  158. package/dist/SegmentedControl/SegmentedControlItem.d.ts.map +1 -1
  159. package/dist/SegmentedControl/SegmentedControlItem.js +13 -2
  160. package/dist/Selector/Selector.d.ts +24 -1
  161. package/dist/Selector/Selector.d.ts.map +1 -1
  162. package/dist/Selector/Selector.js +122 -43
  163. package/dist/Selector/hooks.d.ts +8 -1
  164. package/dist/Selector/hooks.d.ts.map +1 -1
  165. package/dist/Selector/hooks.js +14 -1
  166. package/dist/SideNav/SideNavHeading.d.ts.map +1 -1
  167. package/dist/SideNav/SideNavHeading.js +2 -0
  168. package/dist/SideNav/SideNavItem.d.ts.map +1 -1
  169. package/dist/SideNav/SideNavItem.js +1 -1
  170. package/dist/Skeleton/Skeleton.d.ts.map +1 -1
  171. package/dist/Skeleton/Skeleton.js +8 -2
  172. package/dist/Slider/Slider.d.ts +21 -0
  173. package/dist/Slider/Slider.d.ts.map +1 -1
  174. package/dist/Slider/Slider.js +36 -9
  175. package/dist/Spinner/Spinner.d.ts.map +1 -1
  176. package/dist/Spinner/Spinner.js +1 -1
  177. package/dist/Stack/Stack.d.ts +38 -23
  178. package/dist/Stack/Stack.d.ts.map +1 -1
  179. package/dist/Stack/Stack.js +25 -1
  180. package/dist/Stack/StackItem.d.ts +12 -23
  181. package/dist/Stack/StackItem.d.ts.map +1 -1
  182. package/dist/Stack/StackItem.js +8 -1
  183. package/dist/Switch/Switch.d.ts +23 -2
  184. package/dist/Switch/Switch.d.ts.map +1 -1
  185. package/dist/Switch/Switch.js +41 -11
  186. package/dist/TabList/Tab.d.ts.map +1 -1
  187. package/dist/TabList/Tab.js +6 -0
  188. package/dist/TabList/TabList.d.ts +16 -4
  189. package/dist/TabList/TabList.d.ts.map +1 -1
  190. package/dist/TabList/TabList.js +87 -10
  191. package/dist/TabList/TabListContext.d.ts +5 -0
  192. package/dist/TabList/TabListContext.d.ts.map +1 -1
  193. package/dist/TabList/TabListContext.js +5 -0
  194. package/dist/TabList/TabMenu.d.ts.map +1 -1
  195. package/dist/TabList/TabMenu.js +6 -1
  196. package/dist/Table/BaseTable.d.ts.map +1 -1
  197. package/dist/Table/BaseTable.js +11 -8
  198. package/dist/Table/Table.d.ts.map +1 -1
  199. package/dist/Table/Table.js +10 -1
  200. package/dist/Table/TableCell.d.ts +8 -1
  201. package/dist/Table/TableCell.d.ts.map +1 -1
  202. package/dist/Table/TableCell.js +10 -10
  203. package/dist/Table/TableHeaderCell.d.ts +8 -1
  204. package/dist/Table/TableHeaderCell.d.ts.map +1 -1
  205. package/dist/Table/TableHeaderCell.js +16 -16
  206. package/dist/Table/index.d.ts +2 -1
  207. package/dist/Table/index.d.ts.map +1 -1
  208. package/dist/Table/index.js +2 -2
  209. package/dist/Table/plugins/pagination/paginateData.d.ts +2 -1
  210. package/dist/Table/plugins/pagination/paginateData.d.ts.map +1 -1
  211. package/dist/Table/plugins/pagination/paginateData.js +8 -3
  212. package/dist/Table/plugins/pagination/useTablePagination.d.ts.map +1 -1
  213. package/dist/Table/plugins/pagination/useTablePagination.js +6 -1
  214. package/dist/Table/plugins/sortable/useTableSortable.d.ts.map +1 -1
  215. package/dist/Table/plugins/sortable/useTableSortable.js +59 -3
  216. package/dist/Table/tableContextMenu.d.ts +33 -0
  217. package/dist/Table/tableContextMenu.d.ts.map +1 -0
  218. package/dist/Table/tableContextMenu.js +133 -0
  219. package/dist/Table/types.d.ts +66 -0
  220. package/dist/Table/types.d.ts.map +1 -1
  221. package/dist/TextArea/TextArea.d.ts +22 -1
  222. package/dist/TextArea/TextArea.d.ts.map +1 -1
  223. package/dist/TextArea/TextArea.js +41 -9
  224. package/dist/TextInput/TextInput.d.ts +23 -2
  225. package/dist/TextInput/TextInput.d.ts.map +1 -1
  226. package/dist/TextInput/TextInput.js +55 -10
  227. package/dist/TimeInput/TimeInput.d.ts +23 -1
  228. package/dist/TimeInput/TimeInput.d.ts.map +1 -1
  229. package/dist/TimeInput/TimeInput.js +147 -76
  230. package/dist/Toast/Toast.d.ts.map +1 -1
  231. package/dist/Toast/Toast.js +14 -0
  232. package/dist/Toast/ToastViewport.d.ts.map +1 -1
  233. package/dist/Toast/ToastViewport.js +131 -3
  234. package/dist/Tokenizer/Tokenizer.d.ts +12 -1
  235. package/dist/Tokenizer/Tokenizer.d.ts.map +1 -1
  236. package/dist/Tokenizer/Tokenizer.js +26 -4
  237. package/dist/Toolbar/Toolbar.d.ts +3 -3
  238. package/dist/Toolbar/Toolbar.d.ts.map +1 -1
  239. package/dist/Toolbar/Toolbar.js +51 -7
  240. package/dist/Tooltip/useTooltip.d.ts.map +1 -1
  241. package/dist/Tooltip/useTooltip.js +56 -9
  242. package/dist/TopNav/TopNavHeading.d.ts +7 -1
  243. package/dist/TopNav/TopNavHeading.d.ts.map +1 -1
  244. package/dist/TopNav/TopNavHeading.js +8 -0
  245. package/dist/TreeList/TreeList.d.ts +1 -1
  246. package/dist/TreeList/TreeList.d.ts.map +1 -1
  247. package/dist/TreeList/TreeList.js +72 -2
  248. package/dist/TreeList/TreeListItem.d.ts +11 -1
  249. package/dist/TreeList/TreeListItem.d.ts.map +1 -1
  250. package/dist/TreeList/TreeListItem.js +51 -12
  251. package/dist/TreeList/treeListItem.markers.stylex.d.ts +16 -0
  252. package/dist/TreeList/treeListItem.markers.stylex.d.ts.map +1 -0
  253. package/dist/TreeList/treeListItem.markers.stylex.js +22 -0
  254. package/dist/Typeahead/BaseTypeahead.d.ts +13 -0
  255. package/dist/Typeahead/BaseTypeahead.d.ts.map +1 -1
  256. package/dist/Typeahead/BaseTypeahead.js +69 -6
  257. package/dist/Typeahead/Typeahead.d.ts +26 -3
  258. package/dist/Typeahead/Typeahead.d.ts.map +1 -1
  259. package/dist/Typeahead/Typeahead.js +65 -29
  260. package/dist/VisuallyHidden/VisuallyHidden.d.ts +61 -0
  261. package/dist/VisuallyHidden/VisuallyHidden.d.ts.map +1 -0
  262. package/dist/VisuallyHidden/VisuallyHidden.js +65 -0
  263. package/dist/VisuallyHidden/index.d.ts +11 -0
  264. package/dist/VisuallyHidden/index.d.ts.map +1 -0
  265. package/dist/VisuallyHidden/index.js +13 -0
  266. package/dist/astryx.css +18 -0
  267. package/dist/astryx.umd.js +55 -55
  268. package/dist/astryx.umd.js.map +4 -4
  269. package/dist/hooks/focusableSelector.d.ts +22 -0
  270. package/dist/hooks/focusableSelector.d.ts.map +1 -0
  271. package/dist/hooks/focusableSelector.js +24 -0
  272. package/dist/hooks/index.d.ts +12 -2
  273. package/dist/hooks/index.d.ts.map +1 -1
  274. package/dist/hooks/index.js +7 -2
  275. package/dist/hooks/useAnnounce.d.ts +40 -0
  276. package/dist/hooks/useAnnounce.d.ts.map +1 -0
  277. package/dist/hooks/useAnnounce.js +142 -0
  278. package/dist/hooks/useClickableContainer.d.ts +16 -1
  279. package/dist/hooks/useClickableContainer.d.ts.map +1 -1
  280. package/dist/hooks/useClickableContainer.js +16 -4
  281. package/dist/hooks/useEntryAnimation.d.ts.map +1 -1
  282. package/dist/hooks/useEntryAnimation.js +4 -4
  283. package/dist/hooks/useFocusTrap.d.ts +18 -0
  284. package/dist/hooks/useFocusTrap.d.ts.map +1 -1
  285. package/dist/hooks/useFocusTrap.js +87 -3
  286. package/dist/hooks/useGridFocus.d.ts +88 -1
  287. package/dist/hooks/useGridFocus.d.ts.map +1 -1
  288. package/dist/hooks/useGridFocus.js +261 -62
  289. package/dist/hooks/useKeyboardHint.d.ts +82 -0
  290. package/dist/hooks/useKeyboardHint.d.ts.map +1 -0
  291. package/dist/hooks/useKeyboardHint.js +220 -0
  292. package/dist/hooks/useListFocus.d.ts +78 -7
  293. package/dist/hooks/useListFocus.d.ts.map +1 -1
  294. package/dist/hooks/useListFocus.js +305 -52
  295. package/dist/hooks/useLongPress.d.ts +21 -0
  296. package/dist/hooks/useLongPress.d.ts.map +1 -0
  297. package/dist/hooks/useLongPress.js +89 -0
  298. package/dist/hooks/useTreeFocus.d.ts +157 -0
  299. package/dist/hooks/useTreeFocus.d.ts.map +1 -0
  300. package/dist/hooks/useTreeFocus.js +337 -0
  301. package/dist/hooks/useTypeahead.d.ts +63 -0
  302. package/dist/hooks/useTypeahead.d.ts.map +1 -0
  303. package/dist/hooks/useTypeahead.js +117 -0
  304. package/dist/index.d.ts +1 -0
  305. package/dist/index.d.ts.map +1 -1
  306. package/dist/index.js +1 -0
  307. package/dist/utils/dateTypes.d.ts +12 -0
  308. package/dist/utils/dateTypes.d.ts.map +1 -1
  309. package/dist/utils/dateTypes.js +41 -1
  310. package/dist/utils/index.d.ts +4 -0
  311. package/dist/utils/index.d.ts.map +1 -1
  312. package/dist/utils/index.js +3 -1
  313. package/dist/utils/inputAria.d.ts +29 -0
  314. package/dist/utils/inputAria.d.ts.map +1 -0
  315. package/dist/utils/inputAria.js +30 -0
  316. package/dist/utils/timeParser.d.ts.map +1 -1
  317. package/dist/utils/timeParser.js +5 -2
  318. package/docs.mjs +2 -2
  319. package/package.json +12 -8
  320. package/src/Avatar/Avatar.test.tsx +37 -0
  321. package/src/Avatar/Avatar.tsx +10 -5
  322. package/src/Breadcrumbs/BreadcrumbItem.tsx +25 -7
  323. package/src/Breadcrumbs/Breadcrumbs.test.tsx +31 -10
  324. package/src/Button/Button.tsx +3 -16
  325. package/src/ButtonGroup/ButtonGroup.test.tsx +9 -9
  326. package/src/ButtonGroup/ButtonGroup.tsx +0 -1
  327. package/src/Calendar/Calendar.doc.mjs +4 -4
  328. package/src/Calendar/Calendar.test.tsx +168 -30
  329. package/src/Calendar/Calendar.tsx +121 -66
  330. package/src/Calendar/hooks/index.ts +0 -6
  331. package/src/Calendar/index.ts +1 -3
  332. package/src/Calendar/styles.ts +4 -9
  333. package/src/Carousel/Carousel.doc.mjs +7 -1
  334. package/src/Carousel/Carousel.test.tsx +20 -0
  335. package/src/Carousel/Carousel.tsx +16 -1
  336. package/src/Center/Center.doc.mjs +12 -2
  337. package/src/Center/Center.tsx +28 -3
  338. package/src/Chat/ChatComposerInput.test.tsx +26 -7
  339. package/src/Chat/ChatComposerInput.tsx +0 -1
  340. package/src/Chat/ChatDictationButton.doc.mjs +1 -1
  341. package/src/Chat/ChatMessageList.doc.mjs +8 -0
  342. package/src/Chat/ChatMessageList.test.tsx +18 -0
  343. package/src/Chat/ChatMessageList.tsx +16 -0
  344. package/src/Chat/useTriggerMenu.tsx +22 -4
  345. package/src/CheckboxInput/CheckboxInput.doc.mjs +10 -0
  346. package/src/CheckboxInput/CheckboxInput.test.tsx +172 -27
  347. package/src/CheckboxInput/CheckboxInput.tsx +78 -6
  348. package/src/CheckboxList/CheckboxList.doc.mjs +9 -0
  349. package/src/CheckboxList/CheckboxList.test.tsx +192 -26
  350. package/src/CheckboxList/CheckboxList.tsx +56 -3
  351. package/src/CheckboxList/CheckboxListContext.tsx +7 -0
  352. package/src/CheckboxList/CheckboxListItem.tsx +0 -3
  353. package/src/Citation/Citation.doc.mjs +10 -0
  354. package/src/Citation/Citation.test.tsx +121 -0
  355. package/src/Citation/Citation.tsx +15 -3
  356. package/src/CodeBlock/CodeBlock.test.tsx +115 -0
  357. package/src/CodeBlock/CodeBlock.tsx +63 -33
  358. package/src/CommandPalette/CommandPalette.test.tsx +47 -1
  359. package/src/CommandPalette/CommandPalette.tsx +9 -21
  360. package/src/ContextMenu/ContextMenu.doc.mjs +4 -4
  361. package/src/ContextMenu/ContextMenu.test.tsx +155 -1
  362. package/src/ContextMenu/ContextMenu.tsx +113 -16
  363. package/src/DateInput/DateInput.doc.mjs +286 -56
  364. package/src/DateInput/DateInput.test.tsx +248 -2
  365. package/src/DateInput/DateInput.tsx +196 -100
  366. package/src/DateRangeInput/DateRangeInput.doc.mjs +251 -46
  367. package/src/DateRangeInput/DateRangeInput.test.tsx +182 -20
  368. package/src/DateRangeInput/DateRangeInput.tsx +63 -5
  369. package/src/DateTimeInput/DateTimeInput.doc.mjs +368 -67
  370. package/src/DateTimeInput/DateTimeInput.test.tsx +279 -11
  371. package/src/DateTimeInput/DateTimeInput.tsx +125 -17
  372. package/src/Dialog/Dialog.doc.mjs +2 -2
  373. package/src/Dialog/Dialog.tsx +12 -0
  374. package/src/DropdownMenu/DropdownMenu.doc.mjs +1 -8
  375. package/src/DropdownMenu/DropdownMenu.test.tsx +56 -42
  376. package/src/DropdownMenu/DropdownMenu.tsx +52 -18
  377. package/src/Field/Field.doc.mjs +59 -18
  378. package/src/Field/Field.test.tsx +32 -0
  379. package/src/Field/Field.tsx +23 -5
  380. package/src/Field/FieldLabel.tsx +55 -17
  381. package/src/FileInput/FileInput.doc.mjs +17 -0
  382. package/src/FileInput/FileInput.test.tsx +283 -49
  383. package/src/FileInput/FileInput.tsx +76 -4
  384. package/src/Grid/Grid.doc.mjs +17 -4
  385. package/src/Grid/Grid.test.tsx +43 -30
  386. package/src/Grid/Grid.tsx +38 -3
  387. package/src/Icon/Icon.doc.mjs +3 -3
  388. package/src/InputGroup/InputGroup.doc.mjs +111 -23
  389. package/src/InputGroup/InputGroup.test.tsx +257 -60
  390. package/src/InputGroup/InputGroup.tsx +23 -5
  391. package/src/InputGroup/InputGroupContext.ts +9 -4
  392. package/src/InputGroup/groupStyles.ts +7 -1
  393. package/src/InputGroup/index.ts +1 -0
  394. package/src/Kbd/Kbd.test.tsx +22 -4
  395. package/src/Kbd/Kbd.tsx +35 -3
  396. package/src/Layer/layerAnimations.stylex.ts +20 -4
  397. package/src/Layer/useLayer.doc.mjs +5 -0
  398. package/src/Layer/useLayer.test.tsx +111 -0
  399. package/src/Layer/useLayer.tsx +90 -9
  400. package/src/Layout/Layout.tsx +8 -16
  401. package/src/Layout/LayoutFooter.doc.mjs +4 -4
  402. package/src/Layout/LayoutFooter.tsx +3 -3
  403. package/src/Layout/LayoutHeader.doc.mjs +4 -4
  404. package/src/Layout/LayoutHeader.tsx +3 -3
  405. package/src/Layout/LayoutPanel.tsx +3 -3
  406. package/src/Layout/padding.stylex.ts +52 -0
  407. package/src/Lightbox/Lightbox.doc.mjs +9 -0
  408. package/src/Lightbox/Lightbox.test.tsx +53 -5
  409. package/src/Lightbox/Lightbox.tsx +9 -4
  410. package/src/Link/Link.doc.mjs +14 -0
  411. package/src/Link/Link.test.tsx +50 -0
  412. package/src/Link/Link.tsx +39 -4
  413. package/src/Markdown/Markdown.test.tsx +11 -0
  414. package/src/Markdown/Markdown.tsx +7 -0
  415. package/src/MetadataList/MetadataListItem.doc.mjs +4 -0
  416. package/src/MoreMenu/MoreMenu.doc.mjs +2 -17
  417. package/src/MoreMenu/MoreMenu.tsx +0 -9
  418. package/src/MultiSelector/MultiSelector.doc.mjs +30 -0
  419. package/src/MultiSelector/MultiSelector.test.tsx +375 -8
  420. package/src/MultiSelector/MultiSelector.tsx +194 -48
  421. package/src/MultiSelector/hooks.ts +27 -0
  422. package/src/NavMenu/NavHeadingMenu.test.tsx +77 -1
  423. package/src/NavMenu/NavHeadingMenu.tsx +50 -3
  424. package/src/NumberInput/NumberInput.doc.mjs +17 -0
  425. package/src/NumberInput/NumberInput.test.tsx +242 -40
  426. package/src/NumberInput/NumberInput.tsx +89 -11
  427. package/src/Pagination/Pagination.doc.mjs +3 -3
  428. package/src/Pagination/Pagination.test.tsx +117 -5
  429. package/src/Pagination/Pagination.tsx +21 -1
  430. package/src/Popover/Popover.doc.mjs +26 -0
  431. package/src/Popover/Popover.test.tsx +121 -0
  432. package/src/Popover/Popover.tsx +23 -2
  433. package/src/Popover/usePopover.doc.mjs +9 -3
  434. package/src/Popover/usePopover.tsx +70 -12
  435. package/src/PowerSearch/PowerSearch.doc.mjs +15 -0
  436. package/src/PowerSearch/PowerSearch.test.tsx +97 -1
  437. package/src/PowerSearch/PowerSearch.tsx +16 -3
  438. package/src/ProgressBar/ProgressBar.test.tsx +34 -26
  439. package/src/ProgressBar/ProgressBar.tsx +3 -4
  440. package/src/RadioList/RadioList.doc.mjs +9 -0
  441. package/src/RadioList/RadioList.test.tsx +252 -16
  442. package/src/RadioList/RadioList.tsx +166 -10
  443. package/src/RadioList/RadioListItem.tsx +14 -2
  444. package/src/SegmentedControl/SegmentedControl.doc.mjs +9 -0
  445. package/src/SegmentedControl/SegmentedControl.test.tsx +214 -42
  446. package/src/SegmentedControl/SegmentedControl.tsx +102 -54
  447. package/src/SegmentedControl/SegmentedControlContext.ts +7 -0
  448. package/src/SegmentedControl/SegmentedControlItem.tsx +14 -1
  449. package/src/SelectableCard/SelectableCard.doc.mjs +1 -1
  450. package/src/Selector/Selector.doc.mjs +26 -0
  451. package/src/Selector/Selector.test.tsx +387 -15
  452. package/src/Selector/Selector.tsx +175 -67
  453. package/src/Selector/hooks.ts +23 -0
  454. package/src/SideNav/SideNav.test.tsx +48 -0
  455. package/src/SideNav/SideNavHeading.tsx +8 -2
  456. package/src/SideNav/SideNavItem.tsx +2 -4
  457. package/src/Skeleton/Skeleton.test.tsx +25 -0
  458. package/src/Skeleton/Skeleton.tsx +11 -1
  459. package/src/Slider/Slider.doc.mjs +15 -0
  460. package/src/Slider/Slider.test.tsx +155 -2
  461. package/src/Slider/Slider.tsx +53 -5
  462. package/src/Spinner/Spinner.tsx +7 -1
  463. package/src/Stack/Stack.doc.mjs +77 -0
  464. package/src/Stack/Stack.test.tsx +55 -5
  465. package/src/Stack/Stack.tsx +73 -24
  466. package/src/Stack/StackItem.test.tsx +23 -0
  467. package/src/Stack/StackItem.tsx +20 -23
  468. package/src/Switch/Switch.doc.mjs +15 -0
  469. package/src/Switch/Switch.test.tsx +162 -27
  470. package/src/Switch/Switch.tsx +61 -21
  471. package/src/TabList/Tab.tsx +6 -0
  472. package/src/TabList/TabList.doc.mjs +6 -0
  473. package/src/TabList/TabList.test.tsx +251 -0
  474. package/src/TabList/TabList.tsx +103 -12
  475. package/src/TabList/TabListContext.ts +7 -3
  476. package/src/TabList/TabMenu.tsx +6 -3
  477. package/src/Table/BaseTable.tsx +21 -17
  478. package/src/Table/Table.doc.mjs +2 -0
  479. package/src/Table/Table.test.tsx +10 -0
  480. package/src/Table/Table.tsx +8 -0
  481. package/src/Table/TableCell.tsx +25 -23
  482. package/src/Table/TableHeaderCell.tsx +28 -29
  483. package/src/Table/index.ts +3 -2
  484. package/src/Table/plugins/pagination/paginateData.ts +10 -3
  485. package/src/Table/plugins/pagination/useTablePagination.test.tsx +16 -0
  486. package/src/Table/plugins/pagination/useTablePagination.tsx +8 -1
  487. package/src/Table/plugins/sortable/useTableSortable.test.tsx +91 -2
  488. package/src/Table/plugins/sortable/useTableSortable.tsx +53 -1
  489. package/src/Table/tableContextMenu.test.tsx +157 -0
  490. package/src/Table/tableContextMenu.tsx +142 -0
  491. package/src/Table/types.ts +74 -0
  492. package/src/Table/useTableColumnResize.doc.mjs +3 -3
  493. package/src/Table/useTableStickyColumns.doc.mjs +2 -2
  494. package/src/Text/Text.doc.mjs +18 -18
  495. package/src/TextArea/TextArea.doc.mjs +17 -0
  496. package/src/TextArea/TextArea.test.tsx +167 -35
  497. package/src/TextArea/TextArea.tsx +62 -15
  498. package/src/TextInput/TextInput.doc.mjs +17 -0
  499. package/src/TextInput/TextInput.test.tsx +168 -34
  500. package/src/TextInput/TextInput.tsx +77 -9
  501. package/src/Thumbnail/Thumbnail.doc.mjs +4 -4
  502. package/src/TimeInput/TimeInput.doc.mjs +340 -60
  503. package/src/TimeInput/TimeInput.test.tsx +255 -7
  504. package/src/TimeInput/TimeInput.tsx +176 -70
  505. package/src/Timestamp/Timestamp.doc.mjs +19 -19
  506. package/src/Toast/Toast.tsx +14 -0
  507. package/src/Toast/ToastViewport.test.tsx +214 -0
  508. package/src/Toast/ToastViewport.tsx +167 -21
  509. package/src/Tokenizer/Tokenizer.doc.mjs +29 -14
  510. package/src/Tokenizer/Tokenizer.test.tsx +105 -1
  511. package/src/Tokenizer/Tokenizer.tsx +37 -1
  512. package/src/Toolbar/Toolbar.test.tsx +109 -6
  513. package/src/Toolbar/Toolbar.tsx +59 -5
  514. package/src/Tooltip/Tooltip.test.tsx +68 -0
  515. package/src/Tooltip/useTooltip.tsx +55 -8
  516. package/src/TopNav/TopNav.test.tsx +50 -0
  517. package/src/TopNav/TopNavHeading.tsx +17 -1
  518. package/src/TreeList/TreeList.test.tsx +295 -6
  519. package/src/TreeList/TreeList.tsx +73 -1
  520. package/src/TreeList/TreeListItem.tsx +51 -5
  521. package/src/TreeList/treeListItem.markers.stylex.ts +20 -0
  522. package/src/Typeahead/BaseTypeahead.tsx +93 -9
  523. package/src/Typeahead/Typeahead.doc.mjs +141 -30
  524. package/src/Typeahead/Typeahead.test.tsx +331 -1
  525. package/src/Typeahead/Typeahead.tsx +105 -33
  526. package/src/VisuallyHidden/VisuallyHidden.doc.mjs +80 -0
  527. package/src/VisuallyHidden/VisuallyHidden.test.tsx +76 -0
  528. package/src/VisuallyHidden/VisuallyHidden.tsx +113 -0
  529. package/src/VisuallyHidden/index.ts +15 -0
  530. package/src/docs-script.test.mjs +50 -0
  531. package/src/hooks/focusableSelector.ts +25 -0
  532. package/src/hooks/index.ts +28 -2
  533. package/src/hooks/useAnnounce.test.tsx +101 -0
  534. package/src/hooks/useAnnounce.ts +168 -0
  535. package/src/hooks/useClickableContainer.ts +16 -4
  536. package/src/hooks/useEntryAnimation.ts +16 -4
  537. package/src/hooks/useFocusTrap.test.tsx +132 -0
  538. package/src/hooks/useFocusTrap.ts +98 -4
  539. package/src/hooks/useGridFocus.doc.mjs +40 -2
  540. package/src/hooks/useGridFocus.test.tsx +132 -0
  541. package/src/hooks/useGridFocus.ts +343 -67
  542. package/src/hooks/useKeyboardHint.doc.mjs +101 -0
  543. package/src/hooks/useKeyboardHint.test.tsx +70 -0
  544. package/src/hooks/useKeyboardHint.tsx +332 -0
  545. package/src/hooks/useListFocus.doc.mjs +50 -10
  546. package/src/hooks/useListFocus.test.tsx +375 -0
  547. package/src/hooks/useListFocus.ts +395 -57
  548. package/src/hooks/useLongPress.test.tsx +134 -0
  549. package/src/hooks/useLongPress.ts +119 -0
  550. package/src/hooks/useTreeFocus.doc.mjs +140 -0
  551. package/src/hooks/useTreeFocus.test.tsx +214 -0
  552. package/src/hooks/useTreeFocus.ts +559 -0
  553. package/src/hooks/useTypeahead.test.tsx +109 -0
  554. package/src/hooks/useTypeahead.ts +183 -0
  555. package/src/index.ts +1 -0
  556. package/src/theme/derivedVarRegistry.test.ts +10 -5
  557. package/src/utils/dateTypes.test.ts +40 -0
  558. package/src/utils/dateTypes.ts +40 -0
  559. package/src/utils/index.ts +9 -0
  560. package/src/utils/inputAria.test.ts +39 -0
  561. package/src/utils/inputAria.ts +58 -0
  562. package/src/utils/timeParser.test.ts +10 -0
  563. package/src/utils/timeParser.ts +5 -2
  564. package/dist/Calendar/hooks/useCalendarRovingTabindex.d.ts +0 -57
  565. package/dist/Calendar/hooks/useCalendarRovingTabindex.d.ts.map +0 -1
  566. package/dist/Calendar/hooks/useCalendarRovingTabindex.js +0 -96
  567. package/src/Calendar/hooks/useCalendarRovingTabindex.ts +0 -118
@@ -0,0 +1,111 @@
1
+ // Copyright (c) Meta Platforms, Inc. and affiliates.
2
+
3
+ /**
4
+ * @file useLayer.test.tsx
5
+ * @input Uses vitest, @testing-library/react, useLayer hook
6
+ * @output Unit tests for useLayer show/hide behavior and feature-detection guards
7
+ * @position Testing; validates useLayer.tsx implementation
8
+ *
9
+ * SYNC: When useLayer.tsx changes, update tests to match new behavior
10
+ */
11
+
12
+ import {describe, it, expect, vi, afterEach} from 'vitest';
13
+ import {render, act} from '@testing-library/react';
14
+ import {useLayer} from './useLayer';
15
+
16
+ /**
17
+ * Minimal harness that exposes the imperative show/hide callbacks and renders
18
+ * the layer element so tests can assert on visibility.
19
+ */
20
+ function LayerHarness({
21
+ onReady,
22
+ }: {
23
+ onReady: (api: {show: () => void; hide: () => void}) => void;
24
+ }) {
25
+ const layer = useLayer({mode: 'fixed'});
26
+ onReady({show: layer.show, hide: layer.hide});
27
+ return <>{layer.render(<span>Layer content</span>, {x: 0, y: 0})}</>;
28
+ }
29
+
30
+ describe('useLayer', () => {
31
+ const originalShowPopover = HTMLElement.prototype.showPopover;
32
+ const originalHidePopover = HTMLElement.prototype.hidePopover;
33
+
34
+ afterEach(() => {
35
+ // Restore whatever the environment originally provided.
36
+ if (originalShowPopover === undefined) {
37
+ // @ts-expect-error - deleting to simulate original absence
38
+ delete HTMLElement.prototype.showPopover;
39
+ } else {
40
+ HTMLElement.prototype.showPopover = originalShowPopover;
41
+ }
42
+ if (originalHidePopover === undefined) {
43
+ // @ts-expect-error - deleting to simulate original absence
44
+ delete HTMLElement.prototype.hidePopover;
45
+ } else {
46
+ HTMLElement.prototype.hidePopover = originalHidePopover;
47
+ }
48
+ });
49
+
50
+ describe('when the Popover API is supported', () => {
51
+ it('calls showPopover/hidePopover on show/hide', () => {
52
+ const showSpy = vi.fn();
53
+ const hideSpy = vi.fn();
54
+ HTMLElement.prototype.showPopover = showSpy;
55
+ HTMLElement.prototype.hidePopover = hideSpy;
56
+
57
+ let api: {show: () => void; hide: () => void} = {
58
+ show: () => {},
59
+ hide: () => {},
60
+ };
61
+ render(<LayerHarness onReady={a => (api = a)} />);
62
+
63
+ act(() => api.show());
64
+ expect(showSpy).toHaveBeenCalledTimes(1);
65
+
66
+ act(() => api.hide());
67
+ expect(hideSpy).toHaveBeenCalledTimes(1);
68
+ });
69
+ });
70
+
71
+ describe('when the Popover API is unsupported (Safari <17 / Firefox <125)', () => {
72
+ it('show() does not throw when showPopover is undefined and the layer becomes visible', () => {
73
+ // Simulate a browser without the Popover API (finding infra-4).
74
+ // @ts-expect-error - simulate missing API
75
+ delete HTMLElement.prototype.showPopover;
76
+ // @ts-expect-error - simulate missing API
77
+ delete HTMLElement.prototype.hidePopover;
78
+
79
+ let api: {show: () => void; hide: () => void} = {
80
+ show: () => {},
81
+ hide: () => {},
82
+ };
83
+ const {container} = render(<LayerHarness onReady={a => (api = a)} />);
84
+
85
+ const layerEl = container.querySelector('[popover]') as HTMLElement;
86
+ expect(layerEl).not.toBeNull();
87
+
88
+ expect(() => act(() => api.show())).not.toThrow();
89
+ // Falls back to plain visibility so the layer is still usable.
90
+ expect(layerEl.style.display).toBe('block');
91
+ });
92
+
93
+ it('hide() does not throw when hidePopover is undefined and the layer is hidden', () => {
94
+ // @ts-expect-error - simulate missing API
95
+ delete HTMLElement.prototype.showPopover;
96
+ // @ts-expect-error - simulate missing API
97
+ delete HTMLElement.prototype.hidePopover;
98
+
99
+ let api: {show: () => void; hide: () => void} = {
100
+ show: () => {},
101
+ hide: () => {},
102
+ };
103
+ const {container} = render(<LayerHarness onReady={a => (api = a)} />);
104
+ const layerEl = container.querySelector('[popover]') as HTMLElement;
105
+
106
+ act(() => api.show());
107
+ expect(() => act(() => api.hide())).not.toThrow();
108
+ expect(layerEl.style.display).toBe('none');
109
+ });
110
+ });
111
+ });
@@ -15,6 +15,7 @@
15
15
 
16
16
  import React, {
17
17
  useCallback,
18
+ useEffect,
18
19
  useId,
19
20
  useRef,
20
21
  useState,
@@ -99,6 +100,16 @@ export interface ContextRenderProps {
99
100
  * @default 'div'
100
101
  */
101
102
  as?: 'div' | 'span';
103
+ /**
104
+ * Pointer-enter handler attached to the popover container itself. Lets a
105
+ * consumer keep a hover-driven layer open while the pointer is over the
106
+ * surface (e.g. Tooltip/HoverCard "hoverable" behavior — WCAG 1.4.13).
107
+ */
108
+ onMouseEnter?: React.MouseEventHandler<HTMLElement>;
109
+ /**
110
+ * Pointer-leave handler attached to the popover container itself.
111
+ */
112
+ onMouseLeave?: React.MouseEventHandler<HTMLElement>;
102
113
  }
103
114
 
104
115
  /**
@@ -310,8 +321,19 @@ export function useLayer(
310
321
  const isOpenRef = useRef(false);
311
322
 
312
323
  const show = useCallback(() => {
313
- if (popoverRef.current && !isOpenRef.current) {
314
- popoverRef.current.showPopover();
324
+ const el = popoverRef.current;
325
+ if (el && !isOpenRef.current) {
326
+ // Finding infra-4: the Popover API is unsupported on Safari <17 and
327
+ // Firefox <125. On those browsers `showPopover` does not exist, so
328
+ // calling it unconditionally throws a TypeError and the layer never
329
+ // opens. Guard behind a feature check; when the API is missing, fall
330
+ // back to plain visibility (the [popover] attribute is inert there, so
331
+ // the element sits in normal flow) so the layer still becomes visible.
332
+ if (typeof el.showPopover === 'function') {
333
+ el.showPopover();
334
+ } else {
335
+ el.style.display = 'block';
336
+ }
315
337
  isOpenRef.current = true;
316
338
  setIsOpen(true);
317
339
  onShow?.();
@@ -320,7 +342,16 @@ export function useLayer(
320
342
 
321
343
  const hide = useCallback(() => {
322
344
  if (isOpenRef.current) {
323
- popoverRef.current?.hidePopover();
345
+ const el = popoverRef.current;
346
+ // See finding infra-4 note in `show`: mirror the same guard on hide so
347
+ // unsupported browsers degrade gracefully instead of throwing.
348
+ if (el) {
349
+ if (typeof el.hidePopover === 'function') {
350
+ el.hidePopover();
351
+ } else {
352
+ el.style.display = 'none';
353
+ }
354
+ }
324
355
  isOpenRef.current = false;
325
356
  setIsOpen(false);
326
357
  onHide?.();
@@ -367,17 +398,63 @@ export function useLayer(
367
398
  [onHide],
368
399
  );
369
400
 
370
- // Ref callback for popover element — sets up toggle listener
401
+ // Ref callback for popover element — sets up the `toggle` listener.
402
+ // Tracks the element + handler currently bound so the listener is removed
403
+ // when the element detaches or when `handleToggle`'s identity changes (a new
404
+ // `onHide` prop), preventing stale-closure listeners from accumulating on the
405
+ // same element (infra-10).
406
+ const listenedElRef = useRef<HTMLElement | null>(null);
407
+ const listenedHandlerRef = useRef<((e: Event) => void) | null>(null);
408
+
409
+ const bindToggleListener = useCallback(
410
+ (el: HTMLElement | null, handler: (e: Event) => void) => {
411
+ if (
412
+ listenedElRef.current &&
413
+ listenedHandlerRef.current &&
414
+ (listenedElRef.current !== el || listenedHandlerRef.current !== handler)
415
+ ) {
416
+ listenedElRef.current.removeEventListener(
417
+ 'toggle',
418
+ listenedHandlerRef.current,
419
+ );
420
+ listenedElRef.current = null;
421
+ listenedHandlerRef.current = null;
422
+ }
423
+ if (el && listenedElRef.current !== el) {
424
+ el.addEventListener('toggle', handler);
425
+ listenedElRef.current = el;
426
+ listenedHandlerRef.current = handler;
427
+ }
428
+ },
429
+ [],
430
+ );
431
+
371
432
  const popoverRefCallback = useCallback(
372
433
  (el: HTMLElement | null) => {
373
434
  popoverRef.current = el;
374
- if (el) {
375
- el.addEventListener('toggle', handleToggle);
376
- }
435
+ bindToggleListener(el, handleToggle);
377
436
  },
378
- [handleToggle],
437
+ [handleToggle, bindToggleListener],
379
438
  );
380
439
 
440
+ // Re-bind when the handler identity changes while the element stays mounted,
441
+ // and detach on unmount.
442
+ useEffect(() => {
443
+ if (popoverRef.current) {
444
+ bindToggleListener(popoverRef.current, handleToggle);
445
+ }
446
+ return () => {
447
+ if (listenedElRef.current && listenedHandlerRef.current) {
448
+ listenedElRef.current.removeEventListener(
449
+ 'toggle',
450
+ listenedHandlerRef.current,
451
+ );
452
+ listenedElRef.current = null;
453
+ listenedHandlerRef.current = null;
454
+ }
455
+ };
456
+ }, [handleToggle, bindToggleListener]);
457
+
381
458
  // Render function for context mode
382
459
  const renderContext = useCallback(
383
460
  (children: ReactNode, props?: ContextRenderProps) => {
@@ -389,6 +466,8 @@ export function useLayer(
389
466
  className: extraClassName,
390
467
  style: extraStyle,
391
468
  as: Container = 'div',
469
+ onMouseEnter,
470
+ onMouseLeave,
392
471
  } = props || {};
393
472
 
394
473
  // CSS anchor positioning (dynamic, not in StyleX)
@@ -413,7 +492,9 @@ export function useLayer(
413
492
  role={role}
414
493
  popover={lightDismiss ? 'auto' : 'manual'}
415
494
  className={combinedClassName}
416
- style={{...stylexResult.style, ...anchorStyle, ...extraStyle}}>
495
+ style={{...stylexResult.style, ...anchorStyle, ...extraStyle}}
496
+ onMouseEnter={onMouseEnter}
497
+ onMouseLeave={onMouseLeave}>
417
498
  {children}
418
499
  </Container>
419
500
  );
@@ -26,7 +26,7 @@ import {stack} from '../Stack/stack.stylex';
26
26
  import {stackItem} from '../Stack/stackItem.stylex';
27
27
  import {mergeProps} from '../utils';
28
28
  import type {BaseProps} from '../BaseProps';
29
- import type {SpacingStep} from '../utils/types';
29
+ import type {SizeValue, SpacingStep} from '../utils/types';
30
30
  import {themeProps} from '../utils/themeProps';
31
31
  import {
32
32
  layoutPaddingOuterXVarStyles,
@@ -76,12 +76,12 @@ const styles = stylex.create({
76
76
  });
77
77
 
78
78
  const dynamicStyles = stylex.create({
79
- contentWidthVar: (width: number) => ({
80
- '--layout-content-width': `${width}px`,
79
+ contentWidthVar: (width: SizeValue) => ({
80
+ '--layout-content-width': typeof width === 'number' ? `${width}px` : width,
81
81
  }),
82
- contentWidth: (width: number) => ({
82
+ contentWidth: (width: SizeValue) => ({
83
83
  width: '100%',
84
- maxWidth: width,
84
+ maxWidth: typeof width === 'number' ? `${width}px` : width,
85
85
  marginInline: 'auto',
86
86
  }),
87
87
  });
@@ -102,11 +102,12 @@ export interface LayoutProps extends Omit<BaseProps, 'content'> {
102
102
  * panels). Dividers remain full-bleed. Content is centered with
103
103
  * `margin-inline: auto` when narrower than the available space.
104
104
  *
105
- * Accepts any pixel value. Common page widths from internal patterns:
105
+ * Numbers are treated as pixels, strings are used as-is (e.g., '60ch').
106
+ * Common page widths:
106
107
  * - `640` — forms, settings, text-focused pages
107
108
  * - `960` — content pages, component demos, wider layouts
108
109
  */
109
- contentWidth?: number;
110
+ contentWidth?: SizeValue;
110
111
 
111
112
  /**
112
113
  * End panel slot (right in LTR, left in RTL).
@@ -149,15 +150,6 @@ export interface LayoutProps extends Omit<BaseProps, 'content'> {
149
150
  */
150
151
  defaultHasDividers?: boolean;
151
152
 
152
- /**
153
- * CSS class name(s) appended to the root element.
154
- */
155
- className?: string;
156
- /**
157
- * Inline styles to apply to the root element.
158
- */
159
- style?: React.CSSProperties;
160
-
161
153
  /**
162
154
  * Children are a shorthand for the `content` slot:
163
155
  * `<Layout>{main}</Layout>` is equivalent to `<Layout content={main} />`.
@@ -22,8 +22,8 @@ export const docs = {
22
22
  },
23
23
  {
24
24
  name: 'height',
25
- type: 'number | string',
26
- description: 'Footer height.',
25
+ type: 'SizeValue',
26
+ description: 'Footer height. Numbers are treated as pixels, strings are used as-is.',
27
27
  },
28
28
  {
29
29
  name: 'label',
@@ -57,8 +57,8 @@ export const docsZh = {
57
57
  },
58
58
  {
59
59
  name: 'height',
60
- type: 'number | string',
61
- description: '页脚高度。',
60
+ type: 'SizeValue',
61
+ description: '页脚高度。数字类型会被解释为像素值,字符串类型按原样使用。',
62
62
  },
63
63
  {
64
64
  name: 'label',
@@ -22,7 +22,7 @@ import * as stylex from '@stylexjs/stylex';
22
22
  import {LayoutDividerContext} from './LayoutDividerContext';
23
23
  import {colorVars, spacingVars} from '../theme/tokens.stylex';
24
24
  import {mergeProps} from '../utils';
25
- import type {SpacingStep} from '../utils/types';
25
+ import type {SizeValue, SpacingStep} from '../utils/types';
26
26
  import {themeProps} from '../utils/themeProps';
27
27
  import {
28
28
  paddingStyles,
@@ -71,7 +71,7 @@ const styles = stylex.create({
71
71
 
72
72
  // Dynamic styles for sizing props
73
73
  const dynamicStyles = stylex.create({
74
- sizing: (height: number | string | null) => ({
74
+ sizing: (height: SizeValue | null) => ({
75
75
  height,
76
76
  }),
77
77
  });
@@ -95,7 +95,7 @@ export interface LayoutFooterProps extends BaseProps<HTMLDivElement> {
95
95
  * Height of the footer.
96
96
  * Numbers are treated as pixels, strings are used as-is.
97
97
  */
98
- height?: number | string;
98
+ height?: SizeValue;
99
99
 
100
100
  /**
101
101
  * Internal padding of the footer using the spacing scale.
@@ -22,8 +22,8 @@ export const docs = {
22
22
  },
23
23
  {
24
24
  name: 'height',
25
- type: 'number | string',
26
- description: 'Header height.',
25
+ type: 'SizeValue',
26
+ description: 'Header height. Numbers are treated as pixels, strings are used as-is.',
27
27
  },
28
28
  {
29
29
  name: 'label',
@@ -57,8 +57,8 @@ export const docsZh = {
57
57
  },
58
58
  {
59
59
  name: 'height',
60
- type: 'number | string',
61
- description: '页眉高度。',
60
+ type: 'SizeValue',
61
+ description: '页眉高度。数字类型会被解释为像素值,字符串类型按原样使用。',
62
62
  },
63
63
  {
64
64
  name: 'label',
@@ -22,7 +22,7 @@ import * as stylex from '@stylexjs/stylex';
22
22
  import {LayoutDividerContext} from './LayoutDividerContext';
23
23
  import {colorVars, spacingVars} from '../theme/tokens.stylex';
24
24
  import {mergeProps} from '../utils';
25
- import type {SpacingStep} from '../utils/types';
25
+ import type {SizeValue, SpacingStep} from '../utils/types';
26
26
  import {themeProps} from '../utils/themeProps';
27
27
  import {
28
28
  paddingStyles,
@@ -71,7 +71,7 @@ const styles = stylex.create({
71
71
 
72
72
  // Dynamic styles for sizing props
73
73
  const dynamicStyles = stylex.create({
74
- sizing: (height: number | string | null) => ({
74
+ sizing: (height: SizeValue | null) => ({
75
75
  height,
76
76
  }),
77
77
  });
@@ -95,7 +95,7 @@ export interface LayoutHeaderProps extends BaseProps<HTMLDivElement> {
95
95
  * Height of the header.
96
96
  * Numbers are treated as pixels, strings are used as-is.
97
97
  */
98
- height?: number | string;
98
+ height?: SizeValue;
99
99
 
100
100
  /**
101
101
  * Internal padding of the header using the spacing scale.
@@ -23,7 +23,7 @@ import {colorVars, spacingVars} from '../theme/tokens.stylex';
23
23
  import {LayoutAreaContext} from './LayoutAreaContext';
24
24
  import {LayoutSlotsContext} from './LayoutSlotsContext';
25
25
  import {mergeProps} from '../utils';
26
- import type {SpacingStep} from '../utils/types';
26
+ import type {SizeValue, SpacingStep} from '../utils/types';
27
27
  import type {ResizableProps} from '../Resizable/useResizable';
28
28
  import {themeProps} from '../utils/themeProps';
29
29
  import {
@@ -102,7 +102,7 @@ const styles = stylex.create({
102
102
 
103
103
  // Dynamic styles for sizing props
104
104
  const dynamicStyles = stylex.create({
105
- sizing: (width: number | string | null) => ({
105
+ sizing: (width: SizeValue | null) => ({
106
106
  width,
107
107
  }),
108
108
  });
@@ -158,7 +158,7 @@ export interface LayoutPanelProps extends BaseProps<HTMLDivElement> {
158
158
  * Numbers are treated as pixels, strings are used as-is.
159
159
  * When `resizable` is provided, this is ignored — the hook controls width.
160
160
  */
161
- width?: number | string;
161
+ width?: SizeValue;
162
162
 
163
163
  /**
164
164
  * Resize props from `useResizable()`. When provided, the panel width
@@ -220,6 +220,58 @@ export const layoutPaddingOuterYVarStyles = stylex.create({
220
220
  10: {'--layout-padding-outer-y': spacingVars['--spacing-10']},
221
221
  });
222
222
 
223
+ /**
224
+ * Inline-only padding styles.
225
+ * Use when a component needs to set inline (horizontal) padding independently
226
+ * of block padding — e.g. the `paddingX` prop on Stack.
227
+ */
228
+ export const paddingInlineStyles = stylex.create({
229
+ 0: {
230
+ paddingInlineStart: spacingVars['--spacing-0'],
231
+ paddingInlineEnd: spacingVars['--spacing-0'],
232
+ },
233
+ 0.5: {
234
+ paddingInlineStart: spacingVars['--spacing-0-5'],
235
+ paddingInlineEnd: spacingVars['--spacing-0-5'],
236
+ },
237
+ 1: {
238
+ paddingInlineStart: spacingVars['--spacing-1'],
239
+ paddingInlineEnd: spacingVars['--spacing-1'],
240
+ },
241
+ 1.5: {
242
+ paddingInlineStart: spacingVars['--spacing-1-5'],
243
+ paddingInlineEnd: spacingVars['--spacing-1-5'],
244
+ },
245
+ 2: {
246
+ paddingInlineStart: spacingVars['--spacing-2'],
247
+ paddingInlineEnd: spacingVars['--spacing-2'],
248
+ },
249
+ 3: {
250
+ paddingInlineStart: spacingVars['--spacing-3'],
251
+ paddingInlineEnd: spacingVars['--spacing-3'],
252
+ },
253
+ 4: {
254
+ paddingInlineStart: spacingVars['--spacing-4'],
255
+ paddingInlineEnd: spacingVars['--spacing-4'],
256
+ },
257
+ 5: {
258
+ paddingInlineStart: spacingVars['--spacing-5'],
259
+ paddingInlineEnd: spacingVars['--spacing-5'],
260
+ },
261
+ 6: {
262
+ paddingInlineStart: spacingVars['--spacing-6'],
263
+ paddingInlineEnd: spacingVars['--spacing-6'],
264
+ },
265
+ 8: {
266
+ paddingInlineStart: spacingVars['--spacing-8'],
267
+ paddingInlineEnd: spacingVars['--spacing-8'],
268
+ },
269
+ 10: {
270
+ paddingInlineStart: spacingVars['--spacing-10'],
271
+ paddingInlineEnd: spacingVars['--spacing-10'],
272
+ },
273
+ });
274
+
223
275
  /**
224
276
  * Block-only padding override styles.
225
277
  * Use when a component needs to override block padding independently
@@ -64,6 +64,15 @@ export const docs = {
64
64
  { guidance: false, description: 'Nest interactive content inside captions; keep them plain text.' },
65
65
  ],
66
66
  },
67
+ playground: {
68
+ defaults: {
69
+ media: {
70
+ src: 'https://lookaside.facebook.com/assets/astryx/light-scene-horizontal-1.png',
71
+ alt: 'Coastal shoreline with ocean waves',
72
+ caption: 'A scenic coastline with waves rolling onto a sandy beach beneath a clear sky.',
73
+ },
74
+ },
75
+ },
67
76
  };
68
77
 
69
78
  /** @type {import('../docs-types').ComponentDoc} */
@@ -177,7 +177,7 @@ describe('Lightbox', () => {
177
177
  expect(screen.getByLabelText('Next')).toBeInTheDocument();
178
178
  });
179
179
 
180
- it('hides prev button on first item', () => {
180
+ it('keeps prev mounted and disabled on first item', () => {
181
181
  render(
182
182
  <Lightbox
183
183
  isOpen={true}
@@ -186,11 +186,16 @@ describe('Lightbox', () => {
186
186
  index={0}
187
187
  />,
188
188
  );
189
- expect(screen.queryByLabelText('Previous')).not.toBeInTheDocument();
190
- expect(screen.getByLabelText('Next')).toBeInTheDocument();
189
+ // The Prev button stays mounted at the range boundary (disabled) rather
190
+ // than unmounting, so navigating to the first item never removes the
191
+ // focused control and drops focus to <body>.
192
+ const prev = screen.getByLabelText('Previous');
193
+ expect(prev).toBeInTheDocument();
194
+ expect(prev).toBeDisabled();
195
+ expect(screen.getByLabelText('Next')).not.toBeDisabled();
191
196
  });
192
197
 
193
- it('hides next button on last item', () => {
198
+ it('keeps next mounted and disabled on last item', () => {
194
199
  render(
195
200
  <Lightbox
196
201
  isOpen={true}
@@ -199,8 +204,51 @@ describe('Lightbox', () => {
199
204
  index={2}
200
205
  />,
201
206
  );
207
+ const next = screen.getByLabelText('Next');
208
+ expect(next).toBeInTheDocument();
209
+ expect(next).toBeDisabled();
210
+ expect(screen.getByLabelText('Previous')).not.toBeDisabled();
211
+ });
212
+
213
+ it('does not drop focus to <body> when navigating to the last item', () => {
214
+ const {rerender} = render(
215
+ <Lightbox
216
+ isOpen={true}
217
+ onOpenChange={() => {}}
218
+ media={media}
219
+ index={1}
220
+ />,
221
+ );
222
+ // Simulate arriving at the final item (Next becomes disabled).
223
+ rerender(
224
+ <Lightbox
225
+ isOpen={true}
226
+ onOpenChange={() => {}}
227
+ media={media}
228
+ index={2}
229
+ />,
230
+ );
231
+ // Both nav buttons remain in the DOM; the dialog stays available so
232
+ // keyboard gallery navigation isn't dead-ended.
202
233
  expect(screen.getByLabelText('Previous')).toBeInTheDocument();
203
- expect(screen.queryByLabelText('Next')).not.toBeInTheDocument();
234
+ expect(screen.getByLabelText('Next')).toBeInTheDocument();
235
+ const dialog = document.querySelector('dialog');
236
+ expect(dialog).toBeInTheDocument();
237
+ // Arrow handling is on the dialog, so navigation still works at the edge.
238
+ const onIndexChange = vi.fn();
239
+ rerender(
240
+ <Lightbox
241
+ isOpen={true}
242
+ onOpenChange={() => {}}
243
+ media={media}
244
+ index={2}
245
+ onIndexChange={onIndexChange}
246
+ />,
247
+ );
248
+ if (dialog instanceof HTMLElement) {
249
+ fireEvent.keyDown(dialog, {key: 'ArrowLeft'});
250
+ }
251
+ expect(onIndexChange).toHaveBeenCalledWith(1);
204
252
  });
205
253
 
206
254
  it('calls onIndexChange when next is clicked', () => {
@@ -496,13 +496,16 @@ export function Lightbox({
496
496
  />
497
497
  </div>
498
498
 
499
- {/* Gallery nav: prev */}
500
- {isGallery && canPrev && (
499
+ {/* Gallery nav: prev — stays mounted and is disabled at the start of
500
+ the range so pressing/arrowing to the boundary doesn't unmount the
501
+ focused control and drop focus to <body>. */}
502
+ {isGallery && (
501
503
  <div {...stylex.props(styles.navButton, styles.navPrev)}>
502
504
  <IconButton
503
505
  icon={<Icon icon="chevronLeft" size="sm" color="inherit" />}
504
506
  label="Previous"
505
507
  variant="ghost"
508
+ isDisabled={!canPrev}
506
509
  onClick={goToPrev}
507
510
  xstyle={styles.controlButton}
508
511
  />
@@ -549,13 +552,15 @@ export function Lightbox({
549
552
  )}
550
553
  </div>
551
554
 
552
- {/* Gallery nav: next */}
553
- {isGallery && canNext && (
555
+ {/* Gallery nav: next — see "prev" above; stays mounted and disabled at
556
+ the end of the range instead of unmounting. */}
557
+ {isGallery && (
554
558
  <div {...stylex.props(styles.navButton, styles.navNext)}>
555
559
  <IconButton
556
560
  icon={<Icon icon="chevronRight" size="sm" color="inherit" />}
557
561
  label="Next"
558
562
  variant="ghost"
563
+ isDisabled={!canNext}
559
564
  onClick={goToNext}
560
565
  xstyle={styles.controlButton}
561
566
  />
@@ -59,6 +59,13 @@ export const docs = {
59
59
  'Opens in new tab with external icon and safe rel tokens',
60
60
  default: 'false',
61
61
  },
62
+ {
63
+ name: 'newTabLabel',
64
+ type: 'string',
65
+ description:
66
+ 'Screen-reader text announcing that an external link opens in a new tab. Override for localization.',
67
+ default: "'(opens in new tab)'",
68
+ },
62
69
  {
63
70
  name: 'target',
64
71
  type: 'string',
@@ -185,6 +192,12 @@ export const docsZh = {
185
192
  description: '在新标签页中打开,带外部图标和安全 rel 标记',
186
193
  default: 'false',
187
194
  },
195
+ {
196
+ name: 'newTabLabel',
197
+ type: 'string',
198
+ description: '向屏幕阅读器announce外部链接将在新标签页打开的文本。可覆盖以本地化。',
199
+ default: "'(opens in new tab)'",
200
+ },
188
201
  {
189
202
  name: 'target',
190
203
  type: 'string',
@@ -296,6 +309,7 @@ export const docsDense = {
296
309
  hasUnderline: 'Always show underline',
297
310
  isDisabled: 'Disables link',
298
311
  isExternalLink: 'Opens new tab w/ external icon and safe rel tokens',
312
+ newTabLabel: 'SR text announcing an external link opens in a new tab',
299
313
  target:
300
314
  'Where to open linked document. target="_blank" auto-adds noopener noreferrer.',
301
315
  rel: 'Link relationship tokens. noopener noreferrer are merged for target="_blank".',