@astryxdesign/core 0.7.1 → 0.7.2-canary.020e1fe

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 (377) hide show
  1. package/dist/AppShell/AppShell.d.ts.map +1 -1
  2. package/dist/AppShell/AppShell.js +40 -1
  3. package/dist/AspectRatio/AspectRatio.d.ts +6 -8
  4. package/dist/AspectRatio/AspectRatio.d.ts.map +1 -1
  5. package/dist/AspectRatio/AspectRatio.js +44 -3
  6. package/dist/Breadcrumbs/BreadcrumbItem.d.ts.map +1 -1
  7. package/dist/Breadcrumbs/BreadcrumbItem.js +5 -2
  8. package/dist/Button/Button.d.ts.map +1 -1
  9. package/dist/Button/Button.js +38 -14
  10. package/dist/CheckboxInput/CheckboxInput.d.ts +1 -1
  11. package/dist/CheckboxInput/CheckboxInput.d.ts.map +1 -1
  12. package/dist/CheckboxInput/CheckboxInput.js +3 -1
  13. package/dist/CheckboxList/CheckboxListItem.d.ts +9 -1
  14. package/dist/CheckboxList/CheckboxListItem.d.ts.map +1 -1
  15. package/dist/CheckboxList/CheckboxListItem.js +4 -2
  16. package/dist/CommandPalette/CommandPaletteInput.d.ts +1 -1
  17. package/dist/CommandPalette/CommandPaletteInput.d.ts.map +1 -1
  18. package/dist/CommandPalette/CommandPaletteInput.js +37 -5
  19. package/dist/ContextMenu/ContextMenu.d.ts.map +1 -1
  20. package/dist/ContextMenu/ContextMenu.js +5 -2
  21. package/dist/Dialog/Dialog.d.ts.map +1 -1
  22. package/dist/Dialog/Dialog.js +20 -8
  23. package/dist/Drawer/Drawer.d.ts +191 -0
  24. package/dist/Drawer/Drawer.d.ts.map +1 -0
  25. package/dist/Drawer/Drawer.js +382 -0
  26. package/dist/Drawer/DrawerHeader.d.ts +85 -0
  27. package/dist/Drawer/DrawerHeader.d.ts.map +1 -0
  28. package/dist/Drawer/DrawerHeader.js +134 -0
  29. package/dist/Drawer/index.d.ts +11 -0
  30. package/dist/Drawer/index.d.ts.map +1 -0
  31. package/dist/Drawer/index.js +11 -0
  32. package/dist/Drawer/useDrawerDialogPresence.d.ts +42 -0
  33. package/dist/Drawer/useDrawerDialogPresence.d.ts.map +1 -0
  34. package/dist/Drawer/useDrawerDialogPresence.js +236 -0
  35. package/dist/DropdownMenu/DropdownMenu.d.ts +1 -1
  36. package/dist/DropdownMenu/DropdownMenu.d.ts.map +1 -1
  37. package/dist/DropdownMenu/DropdownMenu.js +83 -11
  38. package/dist/DropdownMenu/DropdownMenuContext.d.ts +17 -0
  39. package/dist/DropdownMenu/DropdownMenuContext.d.ts.map +1 -1
  40. package/dist/DropdownMenu/DropdownMenuContext.js +21 -0
  41. package/dist/DropdownMenu/DropdownMenuDivider.d.ts +5 -3
  42. package/dist/DropdownMenu/DropdownMenuDivider.d.ts.map +1 -1
  43. package/dist/DropdownMenu/DropdownMenuDivider.js +7 -3
  44. package/dist/DropdownMenu/DropdownMenuGroup.d.ts +6 -4
  45. package/dist/DropdownMenu/DropdownMenuGroup.d.ts.map +1 -1
  46. package/dist/DropdownMenu/DropdownMenuGroup.js +4 -3
  47. package/dist/DropdownMenu/DropdownMenuSubMenu.d.ts.map +1 -1
  48. package/dist/DropdownMenu/DropdownMenuSubMenu.js +19 -8
  49. package/dist/DropdownMenu/lazyMenuBottomSheet.d.ts +24 -0
  50. package/dist/DropdownMenu/lazyMenuBottomSheet.d.ts.map +1 -0
  51. package/dist/DropdownMenu/lazyMenuBottomSheet.js +46 -0
  52. package/dist/EmptyState/EmptyState.d.ts.map +1 -1
  53. package/dist/EmptyState/EmptyState.js +4 -10
  54. package/dist/Field/Field.d.ts +1 -1
  55. package/dist/Field/Field.d.ts.map +1 -1
  56. package/dist/Field/Field.js +8 -4
  57. package/dist/Grid/GridSpan.d.ts.map +1 -1
  58. package/dist/Grid/GridSpan.js +1 -0
  59. package/dist/Heading/Heading.d.ts.map +1 -1
  60. package/dist/Heading/Heading.js +4 -2
  61. package/dist/HoverCard/useHoverCard.d.ts.map +1 -1
  62. package/dist/HoverCard/useHoverCard.js +10 -2
  63. package/dist/Item/Item.d.ts +6 -2
  64. package/dist/Item/Item.d.ts.map +1 -1
  65. package/dist/Item/Item.js +19 -4
  66. package/dist/Layer/layerViewportInset.stylex.d.ts +6 -2
  67. package/dist/Layer/layerViewportInset.stylex.d.ts.map +1 -1
  68. package/dist/Layer/layerViewportInset.stylex.js +6 -2
  69. package/dist/Layer/useLayer.d.ts.map +1 -1
  70. package/dist/Layer/useLayer.js +13 -7
  71. package/dist/Layer/useLayerDismissal.d.ts +1 -1
  72. package/dist/Layer/useLayerDismissal.js +1 -1
  73. package/dist/Layout/container.stylex.d.ts +5 -5
  74. package/dist/Layout/container.stylex.js +4 -4
  75. package/dist/List/List.d.ts +46 -19
  76. package/dist/List/List.d.ts.map +1 -1
  77. package/dist/List/List.js +28 -10
  78. package/dist/List/ListContext.d.ts +8 -3
  79. package/dist/List/ListContext.d.ts.map +1 -1
  80. package/dist/List/ListContext.js +7 -2
  81. package/dist/List/ListItem.d.ts +13 -5
  82. package/dist/List/ListItem.d.ts.map +1 -1
  83. package/dist/List/ListItem.js +21 -8
  84. package/dist/List/index.d.ts +1 -1
  85. package/dist/List/index.d.ts.map +1 -1
  86. package/dist/Markdown/Markdown.d.ts.map +1 -1
  87. package/dist/Markdown/Markdown.js +8 -1
  88. package/dist/Markdown/plugins/frontmatter.d.ts.map +1 -1
  89. package/dist/Markdown/plugins/frontmatter.js +7 -3
  90. package/dist/MetadataList/MetadataList.d.ts.map +1 -1
  91. package/dist/MetadataList/MetadataList.js +5 -1
  92. package/dist/MetadataList/MetadataListContext.d.ts +1 -1
  93. package/dist/MetadataList/MetadataListContext.d.ts.map +1 -1
  94. package/dist/MobileNav/MobileNav.d.ts +9 -0
  95. package/dist/MobileNav/MobileNav.d.ts.map +1 -1
  96. package/dist/MobileNav/MobileNav.js +30 -3
  97. package/dist/MultiSelector/MultiSelector.d.ts.map +1 -1
  98. package/dist/MultiSelector/MultiSelector.js +22 -8
  99. package/dist/MultiSelector/OptionActions.a11y.chromium.spec.js +100 -2
  100. package/dist/MultiSelector/hooks.d.ts.map +1 -1
  101. package/dist/MultiSelector/hooks.js +3 -1
  102. package/dist/Pagination/Pagination.d.ts +8 -5
  103. package/dist/Pagination/Pagination.d.ts.map +1 -1
  104. package/dist/Pagination/Pagination.js +21 -8
  105. package/dist/Popover/Popover.js +2 -2
  106. package/dist/PowerSearch/PowerSearch.js +1 -1
  107. package/dist/RadioList/RadioList.d.ts +1 -1
  108. package/dist/RadioList/RadioList.d.ts.map +1 -1
  109. package/dist/RadioList/RadioList.js +6 -2
  110. package/dist/RadioList/RadioListItem.d.ts +9 -1
  111. package/dist/RadioList/RadioListItem.d.ts.map +1 -1
  112. package/dist/RadioList/RadioListItem.js +2 -0
  113. package/dist/Selector/hooks.d.ts.map +1 -1
  114. package/dist/Selector/hooks.js +6 -2
  115. package/dist/SideNav/SideNavItem.d.ts +8 -1
  116. package/dist/SideNav/SideNavItem.d.ts.map +1 -1
  117. package/dist/SideNav/SideNavItem.js +71 -9
  118. package/dist/Switch/Switch.d.ts +1 -1
  119. package/dist/Switch/Switch.d.ts.map +1 -1
  120. package/dist/Switch/Switch.js +13 -1
  121. package/dist/TabList/TabMenu.d.ts +2 -2
  122. package/dist/TabList/TabMenu.d.ts.map +1 -1
  123. package/dist/TabList/TabMenu.js +6 -3
  124. package/dist/Text/Text.d.ts.map +1 -1
  125. package/dist/Text/Text.js +4 -2
  126. package/dist/Text/useTruncation.d.ts +7 -5
  127. package/dist/Text/useTruncation.d.ts.map +1 -1
  128. package/dist/Text/useTruncation.js +16 -5
  129. package/dist/ToggleButton/ToggleButton.d.ts +3 -2
  130. package/dist/ToggleButton/ToggleButton.d.ts.map +1 -1
  131. package/dist/ToggleButton/ToggleButton.js +12 -1
  132. package/dist/Tooltip/useTooltip.d.ts.map +1 -1
  133. package/dist/Tooltip/useTooltip.js +11 -0
  134. package/dist/TopNav/TopNavMegaMenu.d.ts.map +1 -1
  135. package/dist/TopNav/TopNavMegaMenu.js +3 -3
  136. package/dist/TopNav/TopNavMenu.d.ts.map +1 -1
  137. package/dist/TopNav/TopNavMenu.js +3 -3
  138. package/dist/TreeList/TreeList.d.ts.map +1 -1
  139. package/dist/TreeList/TreeList.js +1 -0
  140. package/dist/TreeList/TreeListBranches.d.ts.map +1 -1
  141. package/dist/TreeList/TreeListBranches.js +2 -2
  142. package/dist/TreeList/TreeListItem.d.ts.map +1 -1
  143. package/dist/TreeList/TreeListItem.js +57 -9
  144. package/dist/Typeahead/BaseTypeahead.d.ts.map +1 -1
  145. package/dist/Typeahead/BaseTypeahead.js +26 -0
  146. package/dist/astryx.css +47 -13
  147. package/dist/hooks/useEntryAnimation.d.ts +2 -1
  148. package/dist/hooks/useEntryAnimation.d.ts.map +1 -1
  149. package/dist/hooks/useEntryAnimation.js +14 -12
  150. package/dist/hooks/useIsHydrating.d.ts +6 -0
  151. package/dist/hooks/useIsHydrating.d.ts.map +1 -0
  152. package/dist/hooks/useIsHydrating.js +30 -0
  153. package/dist/hooks/useMenuHover.d.ts.map +1 -1
  154. package/dist/hooks/useMenuHover.js +18 -13
  155. package/dist/i18n/generated-locales/en.generated.d.ts.map +1 -1
  156. package/dist/i18n/generated-locales/en.generated.js +112 -1
  157. package/dist/i18n/generated-locales/pseudo.generated.d.ts.map +1 -1
  158. package/dist/i18n/generated-locales/pseudo.generated.js +112 -1
  159. package/dist/index.d.ts +1 -0
  160. package/dist/index.d.ts.map +1 -1
  161. package/dist/index.js +1 -0
  162. package/dist/theme/derivedVarRegistry.d.ts.map +1 -1
  163. package/dist/theme/derivedVarRegistry.js +0 -3
  164. package/dist/utils/focusOutline.stylex.d.ts +4 -0
  165. package/dist/utils/focusOutline.stylex.d.ts.map +1 -1
  166. package/dist/utils/focusOutline.stylex.js +4 -0
  167. package/dist/utils/plainDate.d.ts.map +1 -1
  168. package/dist/utils/plainDate.js +15 -9
  169. package/dist/utils/sharedMutationObserver.d.ts +21 -0
  170. package/dist/utils/sharedMutationObserver.d.ts.map +1 -0
  171. package/dist/utils/sharedMutationObserver.js +69 -0
  172. package/locales/en.json +444 -0
  173. package/locales/pseudo.json +333 -0
  174. package/package.json +9 -4
  175. package/scripts/agent-doc-state.mjs +38 -0
  176. package/scripts/postinstall.mjs +1 -1
  177. package/src/AppShell/AppShell.tsx +45 -1
  178. package/src/AspectRatio/AspectRatio.test.tsx +44 -43
  179. package/src/AspectRatio/AspectRatio.tsx +38 -18
  180. package/src/AspectRatio/__tests__/AspectRatioFitLayers.a11y.browser.spec.ts +157 -0
  181. package/src/Avatar/Avatar.doc.mjs +5 -3
  182. package/src/AvatarGroup/AvatarGroup.doc.mjs +3 -2
  183. package/src/Breadcrumbs/BreadcrumbItem.tsx +4 -1
  184. package/src/Breadcrumbs/Breadcrumbs.test.tsx +30 -1
  185. package/src/Button/Button.doc.mjs +2 -2
  186. package/src/Button/Button.test.tsx +155 -9
  187. package/src/Button/Button.tsx +39 -16
  188. package/src/Button/__tests__/Button.a11y.known-failures.ts +1 -62
  189. package/src/Button/__tests__/Button.a11y.states.ts +0 -10
  190. package/src/Card/Card.doc.mjs +1 -1
  191. package/src/Chat/__tests__/ChatMessageMetadata.a11y.chromium.spec.ts +3 -1
  192. package/src/CheckboxInput/CheckboxInput.test.tsx +34 -0
  193. package/src/CheckboxInput/CheckboxInput.tsx +3 -1
  194. package/src/CheckboxList/CheckboxList.test.tsx +22 -0
  195. package/src/CheckboxList/CheckboxListItem.doc.mjs +16 -0
  196. package/src/CheckboxList/CheckboxListItem.tsx +10 -0
  197. package/src/Code/Code.doc.mjs +1 -0
  198. package/src/CommandPalette/CommandPalette.doc.mjs +2 -0
  199. package/src/CommandPalette/CommandPaletteInput.test.tsx +53 -4
  200. package/src/CommandPalette/CommandPaletteInput.tsx +33 -3
  201. package/src/CommandPalette/__tests__/CommandPaletteInputAudit.a11y.chromium.spec.ts +335 -0
  202. package/src/CommandPalette/__tests__/CommandPaletteItemAudit.a11y.chromium.spec.ts +292 -0
  203. package/src/ContextMenu/ContextMenu.doc.mjs +2 -3
  204. package/src/ContextMenu/ContextMenu.tsx +4 -1
  205. package/src/ContextMenu/__tests__/ContextMenuAudit.a11y.chromium.spec.ts +438 -0
  206. package/src/Dialog/Dialog.test.tsx +46 -0
  207. package/src/Dialog/Dialog.tsx +20 -7
  208. package/src/Dialog/__tests__/Dialog.a11y.known-failures.ts +0 -14
  209. package/src/Drawer/Drawer.doc.mjs +473 -0
  210. package/src/Drawer/Drawer.spec.md +357 -0
  211. package/src/Drawer/Drawer.test.tsx +1300 -0
  212. package/src/Drawer/Drawer.tsx +613 -0
  213. package/src/Drawer/DrawerDirection.test.tsx +127 -0
  214. package/src/Drawer/DrawerHeader.doc.mjs +293 -0
  215. package/src/Drawer/DrawerHeader.test.tsx +102 -0
  216. package/src/Drawer/DrawerHeader.tsx +235 -0
  217. package/src/Drawer/__tests__/DrawerAudit.a11y.chromium.spec.ts +401 -0
  218. package/src/Drawer/__tests__/DrawerHeaderAudit.a11y.chromium.spec.ts +297 -0
  219. package/src/Drawer/index.ts +13 -0
  220. package/src/Drawer/useDrawerDialogPresence.ts +284 -0
  221. package/src/DropdownMenu/DropdownMenu.ssr.test.tsx +57 -0
  222. package/src/DropdownMenu/DropdownMenu.test.tsx +79 -18
  223. package/src/DropdownMenu/DropdownMenu.tsx +83 -12
  224. package/src/DropdownMenu/DropdownMenuContext.tsx +24 -0
  225. package/src/DropdownMenu/DropdownMenuDivider.doc.mjs +2 -2
  226. package/src/DropdownMenu/DropdownMenuDivider.spec.md +192 -0
  227. package/src/DropdownMenu/DropdownMenuDivider.tsx +9 -5
  228. package/src/DropdownMenu/DropdownMenuGroup.doc.mjs +169 -10
  229. package/src/DropdownMenu/DropdownMenuGroup.tsx +6 -4
  230. package/src/DropdownMenu/DropdownMenuLazySheet.test.tsx +126 -0
  231. package/src/DropdownMenu/DropdownMenuSubMenu.test.tsx +185 -0
  232. package/src/DropdownMenu/DropdownMenuSubMenu.tsx +19 -5
  233. package/src/DropdownMenu/__tests__/DropdownMenuDividerAudit.a11y.chromium.spec.ts +280 -0
  234. package/src/DropdownMenu/__tests__/DropdownMenuGroupAudit.a11y.chromium.spec.ts +334 -0
  235. package/src/DropdownMenu/__tests__/Menu.a11y.chromium.spec.ts +145 -0
  236. package/src/DropdownMenu/__tests__/Menu.a11y.known-failures.ts +26 -0
  237. package/src/DropdownMenu/__tests__/Menu.a11y.renders.tsx +65 -0
  238. package/src/DropdownMenu/__tests__/Menu.a11y.states.ts +138 -0
  239. package/src/DropdownMenu/__tests__/Menu.a11y.test.tsx +136 -0
  240. package/src/DropdownMenu/__tests__/warmMenuBottomSheet.tsx +43 -0
  241. package/src/DropdownMenu/lazyMenuBottomSheet.ts +71 -0
  242. package/src/EmptyState/EmptyState.doc.mjs +3 -2
  243. package/src/EmptyState/EmptyState.spec.md +189 -0
  244. package/src/EmptyState/EmptyState.test.tsx +74 -3
  245. package/src/EmptyState/EmptyState.tsx +4 -8
  246. package/src/Field/Field.doc.mjs +14 -8
  247. package/src/Field/Field.spec.md +217 -0
  248. package/src/Field/Field.test.tsx +60 -2
  249. package/src/Field/Field.tsx +17 -8
  250. package/src/Field/FieldLabel.doc.mjs +133 -26
  251. package/src/Field/FieldLabel.spec.md +172 -0
  252. package/src/Field/__tests__/FieldLabelAudit.a11y.chromium.spec.ts +296 -0
  253. package/src/Grid/GridSpan.tsx +3 -0
  254. package/src/Heading/Heading.test.tsx +57 -0
  255. package/src/Heading/Heading.tsx +6 -2
  256. package/src/HoverCard/HoverCard.test.tsx +58 -0
  257. package/src/HoverCard/useHoverCard.tsx +10 -2
  258. package/src/Icon/Icon.doc.mjs +36 -0
  259. package/src/IconButton/IconButton.doc.mjs +2 -2
  260. package/src/IconButton/IconButton.test.tsx +3 -1
  261. package/src/Item/Item.doc.mjs +12 -8
  262. package/src/Item/Item.spec.md +226 -0
  263. package/src/Item/Item.test.tsx +61 -0
  264. package/src/Item/Item.tsx +40 -4
  265. package/src/Layer/layerViewportInset.source-build.test.mjs +90 -0
  266. package/src/Layer/layerViewportInset.stylex.ts +6 -2
  267. package/src/Layer/layerViewportInset.test.ts +1 -0
  268. package/src/Layer/useLayer.tsx +24 -13
  269. package/src/Layer/useLayerDismissal.ts +1 -1
  270. package/src/Layout/LayoutHeader.doc.mjs +5 -0
  271. package/src/Layout/container.stylex.ts +6 -6
  272. package/src/List/List.doc.mjs +14 -1
  273. package/src/List/List.spec.md +129 -77
  274. package/src/List/List.test.tsx +163 -94
  275. package/src/List/List.tsx +74 -18
  276. package/src/List/ListContext.tsx +9 -3
  277. package/src/List/ListItem.doc.mjs +24 -5
  278. package/src/List/ListItem.tsx +56 -27
  279. package/src/List/index.ts +1 -1
  280. package/src/Markdown/Markdown.tsx +14 -1
  281. package/src/Markdown/plugins/frontmatter.test.tsx +25 -0
  282. package/src/Markdown/plugins/frontmatter.ts +7 -3
  283. package/src/MetadataList/MetadataList.doc.mjs +3 -3
  284. package/src/MetadataList/MetadataList.test.tsx +38 -0
  285. package/src/MetadataList/MetadataList.tsx +8 -1
  286. package/src/MetadataList/MetadataListContext.tsx +1 -1
  287. package/src/MobileNav/MobileNav.tsx +30 -3
  288. package/src/MobileNav/MobileNavCloseEdgeCases.test.tsx +173 -15
  289. package/src/MoreMenu/MoreMenu.test.tsx +5 -1
  290. package/src/MultiSelector/MultiSelector.test.tsx +159 -0
  291. package/src/MultiSelector/MultiSelector.tsx +40 -7
  292. package/src/MultiSelector/OptionActions.a11y.chromium.spec.ts +112 -2
  293. package/src/MultiSelector/hooks.ts +3 -1
  294. package/src/MultiSelector/useMultiCombobox.doc.mjs +267 -0
  295. package/src/Pagination/Pagination.doc.mjs +7 -7
  296. package/src/Pagination/Pagination.spec.md +9 -9
  297. package/src/Pagination/Pagination.test.tsx +242 -0
  298. package/src/Pagination/Pagination.tsx +27 -11
  299. package/src/Popover/Popover.test.tsx +2 -2
  300. package/src/Popover/Popover.tsx +4 -4
  301. package/src/PowerSearch/PowerSearch.test.tsx +85 -0
  302. package/src/PowerSearch/PowerSearch.tsx +2 -2
  303. package/src/ProgressBar/ProgressBar.doc.mjs +1 -0
  304. package/src/RadioList/RadioList.fr10.test.tsx +45 -2
  305. package/src/RadioList/RadioList.test.tsx +22 -0
  306. package/src/RadioList/RadioList.tsx +4 -1
  307. package/src/RadioList/RadioListItem.doc.mjs +16 -0
  308. package/src/RadioList/RadioListItem.tsx +10 -1
  309. package/src/Resizable/useResizable.doc.mjs +2 -0
  310. package/src/ScrollableArea/ScrollableArea.doc.mjs +1 -1
  311. package/src/Selector/hooks.ts +6 -2
  312. package/src/Selector/useCombobox.doc.mjs +237 -0
  313. package/src/SideNav/SideNav.spec.md +227 -0
  314. package/src/SideNav/SideNav.test.tsx +179 -0
  315. package/src/SideNav/SideNavItem.doc.mjs +2 -2
  316. package/src/SideNav/SideNavItem.tsx +96 -17
  317. package/src/Slider/Slider.spec.md +39 -18
  318. package/src/Spinner/Spinner.doc.mjs +1 -1
  319. package/src/Switch/Switch.test.tsx +49 -0
  320. package/src/Switch/Switch.tsx +11 -0
  321. package/src/TabList/TabList.spec.md +57 -44
  322. package/src/TabList/TabList.test.tsx +67 -0
  323. package/src/TabList/TabMenu.doc.mjs +4 -3
  324. package/src/TabList/TabMenu.tsx +7 -4
  325. package/src/Text/Text.test.tsx +57 -0
  326. package/src/Text/Text.tsx +6 -2
  327. package/src/Text/useTruncation.test.tsx +69 -0
  328. package/src/Text/useTruncation.ts +16 -5
  329. package/src/TimeInput/TimeInput.fr10.test.tsx +15 -0
  330. package/src/Timestamp/Timestamp.doc.mjs +1 -1
  331. package/src/ToggleButton/ToggleButton.test.tsx +95 -0
  332. package/src/ToggleButton/ToggleButton.tsx +12 -1
  333. package/src/ToggleButton/ToggleButtonGroup.doc.mjs +4 -0
  334. package/src/Tokenizer/Tokenizer.test.tsx +54 -1
  335. package/src/Toolbar/Toolbar.test.tsx +0 -8
  336. package/src/Toolbar/__tests__/Toolbar.a11y.chromium.spec.ts +163 -0
  337. package/src/Toolbar/__tests__/Toolbar.a11y.renders.tsx +63 -0
  338. package/src/Toolbar/__tests__/Toolbar.a11y.states.ts +142 -0
  339. package/src/Toolbar/__tests__/Toolbar.a11y.test.tsx +126 -0
  340. package/src/Tooltip/Tooltip.test.tsx +31 -0
  341. package/src/Tooltip/useTooltip.test.tsx +13 -0
  342. package/src/Tooltip/useTooltip.tsx +11 -0
  343. package/src/TopNav/TopNavMegaMenu.test.tsx +22 -0
  344. package/src/TopNav/TopNavMegaMenu.tsx +7 -3
  345. package/src/TopNav/TopNavMenu.test.tsx +19 -0
  346. package/src/TopNav/TopNavMenu.tsx +11 -3
  347. package/src/TreeList/TreeList.doc.mjs +1 -0
  348. package/src/TreeList/TreeList.spec.md +29 -17
  349. package/src/TreeList/TreeList.test.tsx +327 -6
  350. package/src/TreeList/TreeList.tsx +5 -1
  351. package/src/TreeList/TreeListBranches.tsx +6 -0
  352. package/src/TreeList/TreeListItem.tsx +88 -13
  353. package/src/Typeahead/BaseTypeahead.tsx +26 -0
  354. package/src/Typeahead/Typeahead.test.tsx +260 -2
  355. package/src/docPropLiterals.test.ts +36 -10
  356. package/src/hooks/useEntryAnimation.doc.mjs +4 -4
  357. package/src/hooks/useEntryAnimation.ssr.test.tsx +143 -0
  358. package/src/hooks/useEntryAnimation.ts +15 -16
  359. package/src/hooks/useIsHydrating.test.tsx +70 -0
  360. package/src/hooks/useIsHydrating.ts +31 -0
  361. package/src/hooks/useMenuHover.ts +18 -13
  362. package/src/i18n/InternationalizationProvider.doc.mjs +8 -0
  363. package/src/i18n/InternationalizationProvider.spec.md +252 -0
  364. package/src/i18n/__tests__/InternationalizationProvider.test.tsx +128 -0
  365. package/src/i18n/generated-locales/en.generated.ts +121 -0
  366. package/src/i18n/generated-locales/pseudo.generated.ts +121 -0
  367. package/src/i18n/useTranslator.test.tsx +37 -0
  368. package/src/index.ts +1 -0
  369. package/src/postinstall.test.mjs +46 -0
  370. package/src/reset.css +0 -29
  371. package/src/theme/derivedVarRegistry.test.ts +7 -3
  372. package/src/theme/derivedVarRegistry.ts +0 -3
  373. package/src/utils/focusOutline.stylex.ts +4 -0
  374. package/src/utils/plainDate.test.ts +37 -1
  375. package/src/utils/plainDate.ts +15 -5
  376. package/src/utils/sharedMutationObserver.test.ts +53 -0
  377. package/src/utils/sharedMutationObserver.ts +78 -0
@@ -0,0 +1,235 @@
1
+ // Copyright (c) Meta Platforms, Inc. and affiliates.
2
+
3
+ 'use client';
4
+
5
+ /**
6
+ * @file DrawerHeader.tsx
7
+ * @input Uses React, StyleX, LayoutHeader, Button, Icon, Heading, Text, i18n, BaseProps, isRenderable, mergeProps, themeProps
8
+ * @output Exports DrawerHeader component and DrawerHeaderProps
9
+ * @position Drawer header; composed in a Layout header slot inside Drawer, tested by DrawerHeader.test.tsx
10
+ *
11
+ * Mirrors DialogHeader's API: a title, an optional subtitle, start/end content
12
+ * slots, and a close button that renders only when `onOpenChange` is passed.
13
+ * Two differences follow from Drawer's contract:
14
+ * - It does not move focus on mount. Drawer owns focus entry through
15
+ * `data-autofocus` once its native host is presented.
16
+ * - It does not name the drawer. Drawer's required `label` does.
17
+ *
18
+ * SYNC: When modified, update these files to stay in sync:
19
+ * - /packages/core/src/Drawer/DrawerHeader.doc.mjs (props, anatomy, theming)
20
+ * - /packages/core/src/Drawer/DrawerHeader.test.tsx (tests for new/changed behavior)
21
+ * - /packages/core/src/Drawer/index.ts (exports if types change)
22
+ * - /packages/cli/assets/templates/blocks/components/Drawer/ (showcase blocks)
23
+ * - /packages/cli/assets/templates/blocks/components/DrawerHeader/ (showcase blocks)
24
+ * - /apps/storybook/stories/Drawer.stories.tsx (examples and visual coverage)
25
+ * - /apps/storybook/stories/DrawerHeader.stories.tsx (component audit fixture)
26
+ */
27
+
28
+ import type {ReactNode} from 'react';
29
+ import * as stylex from '@stylexjs/stylex';
30
+ import type {BaseProps} from '../BaseProps';
31
+ import {sizeVars, spacingVars, typeScaleVars} from '../theme/tokens.stylex';
32
+ import {Button} from '../Button';
33
+ import {Heading} from '../Heading';
34
+ import {Icon} from '../Icon';
35
+ import {LayoutHeader} from '../Layout';
36
+ import {Text} from '../Text';
37
+ import {useTranslator} from '../i18n';
38
+ import {isRenderable, mergeProps, themeProps} from '../utils';
39
+
40
+ const styles = stylex.create({
41
+ container: {
42
+ display: 'flex',
43
+ alignItems: 'flex-start',
44
+ justifyContent: 'space-between',
45
+ gap: spacingVars['--spacing-3'],
46
+ },
47
+ // Compensate for the medium icon button's visual padding on the end slot.
48
+ endBlockEdgeCompensation: {
49
+ marginBlock: `calc(-1 * ${spacingVars['--spacing-2']})`,
50
+ },
51
+ endInlineEdgeCompensation: {
52
+ marginInlineEnd: `calc(-1 * ${spacingVars['--spacing-2']})`,
53
+ },
54
+ titleWrapper: {
55
+ display: 'flex',
56
+ flexDirection: 'column',
57
+ gap: spacingVars['--spacing-0'],
58
+ flex: 1,
59
+ minWidth: 0,
60
+ // Align the title's center with the close button's center, as
61
+ // DialogHeader does.
62
+ marginBlock: `calc(${sizeVars['--size-element-md']} / 2 - ${spacingVars['--spacing-2']} - ${typeScaleVars['--text-heading-2-size']} * ${typeScaleVars['--text-heading-2-leading']} / 2)`,
63
+ },
64
+ actions: {
65
+ display: 'flex',
66
+ alignItems: 'center',
67
+ gap: spacingVars['--spacing-2'],
68
+ flexShrink: 0,
69
+ },
70
+ });
71
+
72
+ export interface DrawerHeaderProps extends BaseProps<HTMLDivElement> {
73
+ /** Ref forwarded to the root element */
74
+ ref?: React.Ref<HTMLDivElement>;
75
+
76
+ /**
77
+ * The title of the drawer, rendered as an h2. Keep it inline and
78
+ * non-interactive. It does not name the drawer; Drawer's `label` does.
79
+ */
80
+ title: ReactNode;
81
+
82
+ /**
83
+ * Optional subtitle displayed below the title in smaller, secondary text.
84
+ * Accepts inline content such as a Link; it renders inside a span, so
85
+ * avoid block elements. Nothing renders for `null`, `undefined`, booleans,
86
+ * or an empty string.
87
+ */
88
+ subtitle?: ReactNode;
89
+
90
+ /**
91
+ * Called with `false` when the close button is clicked. Pass the Drawer's
92
+ * own `onOpenChange`. If not provided, no close button is rendered.
93
+ */
94
+ onOpenChange?: (isOpen: boolean) => unknown;
95
+
96
+ /**
97
+ * Content to render before the title (e.g., a back button).
98
+ */
99
+ startContent?: ReactNode;
100
+
101
+ /**
102
+ * Content to render after the title, before the close button (e.g., action
103
+ * buttons).
104
+ */
105
+ endContent?: ReactNode;
106
+
107
+ /**
108
+ * Overrides automatic end-slot compensation. When omitted, rendering the
109
+ * close action applies block and logical inline-end compensation. Use
110
+ * `inline`, `block`, or `all` to select the axes explicitly.
111
+ */
112
+ endContentEdgeCompensation?: 'inline' | 'block' | 'all';
113
+
114
+ /**
115
+ * Adds a themed border at the bottom edge.
116
+ * When false, spacing collapse is applied automatically for seamless visual flow.
117
+ * Defaults to the parent Layout's `defaultHasDividers` context value.
118
+ */
119
+ hasDivider?: boolean;
120
+ }
121
+
122
+ /**
123
+ * Header for a Drawer: a title, optional subtitle and start/end content, and a
124
+ * close button when `onOpenChange` is passed. Same API as DialogHeader.
125
+ *
126
+ * Uses LayoutHeader internally for consistent styling with other layout headers.
127
+ *
128
+ * @example
129
+ * ```
130
+ * <Drawer isOpen={isOpen} onOpenChange={setIsOpen} label="Details">
131
+ * <DrawerHeader title="Details" onOpenChange={setIsOpen} />
132
+ * <Section padding={4}>Content</Section>
133
+ * </Drawer>
134
+ * ```
135
+ */
136
+ export function DrawerHeader({
137
+ title,
138
+ subtitle,
139
+ onOpenChange,
140
+ startContent,
141
+ endContent,
142
+ endContentEdgeCompensation,
143
+ hasDivider,
144
+ xstyle,
145
+ className,
146
+ style,
147
+ ref,
148
+ ...rest
149
+ }: DrawerHeaderProps) {
150
+ const t = useTranslator();
151
+ const hasSubtitle = isRenderable(subtitle);
152
+ const hasStartContent = isRenderable(startContent);
153
+ const hasEndContent = isRenderable(endContent);
154
+ const shouldCompensateEndBlock =
155
+ endContentEdgeCompensation == null
156
+ ? onOpenChange != null
157
+ : endContentEdgeCompensation === 'block' ||
158
+ endContentEdgeCompensation === 'all';
159
+ const shouldCompensateEndInline =
160
+ endContentEdgeCompensation == null
161
+ ? onOpenChange != null
162
+ : endContentEdgeCompensation === 'inline' ||
163
+ endContentEdgeCompensation === 'all';
164
+
165
+ return (
166
+ <LayoutHeader
167
+ ref={ref}
168
+ hasDivider={hasDivider}
169
+ xstyle={xstyle}
170
+ className={className}
171
+ style={style}
172
+ {...rest}>
173
+ <div
174
+ {...mergeProps(
175
+ themeProps('drawer-header'),
176
+ stylex.props(styles.container),
177
+ )}>
178
+ {hasStartContent && (
179
+ <div
180
+ {...mergeProps(
181
+ themeProps('drawer-header-start-content'),
182
+ stylex.props(styles.actions),
183
+ )}>
184
+ {startContent}
185
+ </div>
186
+ )}
187
+ <div
188
+ {...mergeProps(
189
+ themeProps('drawer-header-title-block'),
190
+ stylex.props(styles.titleWrapper),
191
+ )}>
192
+ <Heading level={2}>{title}</Heading>
193
+ {hasSubtitle && (
194
+ <Text type="body" size="sm" color="secondary">
195
+ {subtitle}
196
+ </Text>
197
+ )}
198
+ </div>
199
+ {(hasEndContent || onOpenChange != null) && (
200
+ <div
201
+ {...mergeProps(
202
+ themeProps('drawer-header-end-content'),
203
+ stylex.props(
204
+ styles.actions,
205
+ shouldCompensateEndBlock && styles.endBlockEdgeCompensation,
206
+ shouldCompensateEndInline && styles.endInlineEdgeCompensation,
207
+ ),
208
+ )}>
209
+ {endContent}
210
+ {onOpenChange && (
211
+ <Button
212
+ variant="ghost"
213
+ label={t('@astryx.dialog.close')}
214
+ tooltip={t('@astryx.dialog.close')}
215
+ icon={
216
+ <Icon
217
+ icon="close"
218
+ color="inherit"
219
+ {...themeProps('drawer-header-close-icon')}
220
+ />
221
+ }
222
+ onClick={() => {
223
+ onOpenChange(false);
224
+ }}
225
+ isIconOnly
226
+ />
227
+ )}
228
+ </div>
229
+ )}
230
+ </div>
231
+ </LayoutHeader>
232
+ );
233
+ }
234
+
235
+ DrawerHeader.displayName = 'DrawerHeader';
@@ -0,0 +1,401 @@
1
+ // Copyright (c) Meta Platforms, Inc. and affiliates.
2
+
3
+ /**
4
+ * @file DrawerAudit.a11y.chromium.spec.ts
5
+ * @input Exact-head Core/Drawer Storybook fixtures in light/dark, neutral/custom themes, LTR/RTL, wide/narrow, modal/non-modal, purpose, padding, and stacked states
6
+ * @output Bounded screenshots and fail-closed sensor receipts for the Drawer whole-component audit
7
+ * @position Component-owned Night Watch browser evidence; CI runs it only for a Drawer component-audit pull request
8
+ */
9
+
10
+ import {createHash} from 'node:crypto';
11
+ import {execFileSync} from 'node:child_process';
12
+ import * as fs from 'node:fs';
13
+ import * as path from 'node:path';
14
+ import {expect, test, type Page} from '@playwright/test';
15
+ import {holdMotionStill} from '@astryxdesign/a11y-spec/chromium';
16
+ import {
17
+ DEFAULT_STORYBOOK_DIR,
18
+ serveStorybook,
19
+ type StaticServer,
20
+ } from '@astryxdesign/a11y-spec/storybook';
21
+
22
+ const OUTPUT = path.resolve('test-results/drawer-audit-evidence');
23
+ const WIDE = {width: 1024, height: 768};
24
+ const NARROW = {width: 320, height: 720};
25
+
26
+ type Mode = 'light' | 'dark';
27
+ type Direction = 'ltr' | 'rtl';
28
+ type Theme = 'neutral' | 'butter';
29
+
30
+ type Case = {
31
+ key: string;
32
+ story: string;
33
+ buttons: string[];
34
+ mode: Mode;
35
+ direction: Direction;
36
+ theme: Theme;
37
+ viewport: {width: number; height: number};
38
+ expected: {
39
+ count?: number;
40
+ side?: 'start' | 'end';
41
+ modal?: boolean;
42
+ role?: 'dialog' | 'alertdialog';
43
+ narrowCoverage?: 'reveal' | 'full';
44
+ motionDirection?: Direction;
45
+ paddingPx?: number;
46
+ };
47
+ };
48
+
49
+ const cases: Case[] = [];
50
+ function addPair(
51
+ key: string,
52
+ story: string,
53
+ buttons: string[],
54
+ expected: Case['expected'],
55
+ options: Partial<Pick<Case, 'direction' | 'theme' | 'viewport'>> = {},
56
+ ) {
57
+ for (const mode of ['light', 'dark'] as const) {
58
+ cases.push({
59
+ key: `${key}-${mode}`,
60
+ story,
61
+ buttons,
62
+ mode,
63
+ direction: options.direction ?? 'ltr',
64
+ theme: options.theme ?? 'neutral',
65
+ viewport: options.viewport ?? WIDE,
66
+ expected,
67
+ });
68
+ }
69
+ }
70
+
71
+ addPair('modal-end', 'showcase', ['Open inspector'], {
72
+ side: 'end',
73
+ modal: true,
74
+ role: 'dialog',
75
+ });
76
+ addPair(
77
+ 'modal-end-custom-theme',
78
+ 'showcase',
79
+ ['Open inspector'],
80
+ {side: 'end', modal: true, role: 'dialog'},
81
+ {theme: 'butter'},
82
+ );
83
+ addPair('nonmodal-end', 'row-inspector', ['Open drawer'], {
84
+ side: 'end',
85
+ modal: false,
86
+ role: 'dialog',
87
+ });
88
+ addPair('start-ltr', 'sides', ['Open from start'], {
89
+ side: 'start',
90
+ modal: true,
91
+ role: 'dialog',
92
+ });
93
+ addPair(
94
+ 'end-ambient-rtl',
95
+ 'sides',
96
+ ['Open from end'],
97
+ {
98
+ side: 'end',
99
+ modal: true,
100
+ role: 'dialog',
101
+ motionDirection: 'rtl',
102
+ },
103
+ {direction: 'rtl'},
104
+ );
105
+ addPair(
106
+ 'start-self-rtl',
107
+ 'self-directed-rtl-start',
108
+ ['Open self-directed RTL start drawer'],
109
+ {side: 'start', modal: true, role: 'dialog', motionDirection: 'rtl'},
110
+ );
111
+ addPair(
112
+ 'end-self-rtl',
113
+ 'self-directed-rtl-end',
114
+ ['Open self-directed RTL end drawer'],
115
+ {side: 'end', modal: true, role: 'dialog', motionDirection: 'rtl'},
116
+ );
117
+ addPair(
118
+ 'nested-ltr-override',
119
+ 'nested-ltr-override',
120
+ ['Open nested LTR drawer'],
121
+ {side: 'end', modal: true, role: 'dialog', motionDirection: 'ltr'},
122
+ {direction: 'rtl'},
123
+ );
124
+ addPair(
125
+ 'mobile-reveal',
126
+ 'mobile-width',
127
+ ['56px reveal on mobile'],
128
+ {
129
+ side: 'end',
130
+ modal: true,
131
+ role: 'dialog',
132
+ narrowCoverage: 'reveal',
133
+ },
134
+ {viewport: NARROW},
135
+ );
136
+ addPair(
137
+ 'mobile-full',
138
+ 'mobile-width',
139
+ ['Full width on mobile'],
140
+ {side: 'end', modal: true, role: 'dialog', narrowCoverage: 'full'},
141
+ {viewport: NARROW},
142
+ );
143
+ addPair('purpose-form', 'purpose', ['form'], {
144
+ side: 'end',
145
+ modal: true,
146
+ role: 'dialog',
147
+ });
148
+ addPair('purpose-required', 'purpose', ['required'], {
149
+ side: 'end',
150
+ modal: true,
151
+ role: 'alertdialog',
152
+ });
153
+ addPair('themed-padding', 'themed-padding', ['Open themed drawer'], {
154
+ side: 'end',
155
+ modal: true,
156
+ role: 'dialog',
157
+ paddingPx: 24,
158
+ });
159
+ addPair('stacked', 'stacked-drawers', ['Open order', 'Open line item'], {
160
+ count: 2,
161
+ modal: false,
162
+ role: 'dialog',
163
+ });
164
+
165
+ test.describe.configure({mode: 'serial', retries: 0});
166
+ let server: StaticServer;
167
+ let checkoutSha: string;
168
+ let storybookSha: string;
169
+
170
+ function storyUrl(item: Case) {
171
+ return `${server.origin}/iframe.html?id=core-drawer--${item.story}&viewMode=story&globals=colorMode:${item.mode};astryxTheme:${item.theme};direction:${item.direction}`;
172
+ }
173
+
174
+ async function settle(page: Page) {
175
+ await holdMotionStill(page);
176
+ await page.evaluate(async () => document.fonts.ready);
177
+ await page.waitForTimeout(40);
178
+ }
179
+
180
+ async function readClosedTranslateX(page: Page): Promise<number | null> {
181
+ return page.locator('dialog.astryx-drawer').evaluate(dialog => {
182
+ const element = dialog as HTMLElement;
183
+ const previous = element.style.display;
184
+ element.style.display = 'flex';
185
+ const transform = getComputedStyle(element).transform;
186
+ element.style.display = previous;
187
+ if (transform === 'none') {
188
+ return null;
189
+ }
190
+ return new DOMMatrixReadOnly(transform).m41;
191
+ });
192
+ }
193
+
194
+ test.beforeAll(async () => {
195
+ fs.rmSync(OUTPUT, {recursive: true, force: true});
196
+ fs.mkdirSync(OUTPUT, {recursive: true});
197
+ checkoutSha = execFileSync('git', ['rev-parse', 'HEAD'], {
198
+ encoding: 'utf8',
199
+ }).trim();
200
+ const expected = process.env.ASTRYX_HEAD_SHA;
201
+ if (expected && expected !== checkoutSha) {
202
+ throw new Error(
203
+ `checkout ${checkoutSha} does not match expected head ${expected}`,
204
+ );
205
+ }
206
+ server = await serveStorybook(
207
+ process.env.ASTRYX_STORYBOOK_DIR ?? DEFAULT_STORYBOOK_DIR,
208
+ );
209
+ const response = await fetch(`${server.origin}/astryx-build-sha.txt`);
210
+ if (!response.ok) {
211
+ throw new Error(`Storybook build has no SHA stamp (${response.status})`);
212
+ }
213
+ storybookSha = (await response.text()).trim();
214
+ if (storybookSha !== checkoutSha) {
215
+ throw new Error(
216
+ `Storybook ${storybookSha} does not match checkout ${checkoutSha}`,
217
+ );
218
+ }
219
+ });
220
+
221
+ test.afterAll(async () => {
222
+ await server?.close();
223
+ });
224
+
225
+ for (const item of cases) {
226
+ test(item.key, async ({browser}) => {
227
+ const context = await browser.newContext({
228
+ viewport: item.viewport,
229
+ colorScheme: item.mode,
230
+ reducedMotion: 'reduce',
231
+ });
232
+ const page = await context.newPage();
233
+ const pageErrors: string[] = [];
234
+ page.on('pageerror', error => pageErrors.push(String(error)));
235
+ await page.goto(storyUrl(item), {waitUntil: 'load'});
236
+ await page.locator('#storybook-root').waitFor();
237
+ await settle(page);
238
+
239
+ const closedTranslateX = item.expected.motionDirection
240
+ ? await readClosedTranslateX(page)
241
+ : null;
242
+ if (item.expected.motionDirection) {
243
+ const ltrSign = item.expected.side === 'start' ? -1 : 1;
244
+ const directionSign = item.expected.motionDirection === 'rtl' ? -1 : 1;
245
+ expect(
246
+ (closedTranslateX ?? 0) * ltrSign * directionSign,
247
+ 'closed drawer moves toward its resolved logical edge',
248
+ ).toBeGreaterThan(0);
249
+ }
250
+
251
+ for (const label of item.buttons) {
252
+ await page.getByRole('button', {name: label, exact: true}).click();
253
+ await settle(page);
254
+ }
255
+
256
+ const drawers = page.locator('dialog.astryx-drawer:visible');
257
+ const expectedCount = item.expected.count ?? 1;
258
+ await expect(drawers).toHaveCount(expectedCount);
259
+ const drawer = drawers.last();
260
+ const box = await drawer.boundingBox();
261
+ if (box == null) {
262
+ throw new Error(`${item.key}: visible drawer has no geometry`);
263
+ }
264
+
265
+ const observed = await drawer.evaluate(element => {
266
+ const style = getComputedStyle(element);
267
+ const backdrop = getComputedStyle(element, '::backdrop');
268
+ const content = element.firstElementChild;
269
+ const contentStyle = content ? getComputedStyle(content) : null;
270
+ return {
271
+ role: element.getAttribute('role') ?? 'dialog',
272
+ name: element.getAttribute('aria-label'),
273
+ modal: element.getAttribute('aria-modal') === 'true',
274
+ side: element.getAttribute('data-side'),
275
+ direction: style.direction,
276
+ backgroundColor: style.backgroundColor,
277
+ color: style.color,
278
+ transform: style.transform,
279
+ backdropColor: backdrop.backgroundColor,
280
+ contentPaddingInlineStart: contentStyle?.paddingInlineStart ?? null,
281
+ contentPaddingInlineEnd: contentStyle?.paddingInlineEnd ?? null,
282
+ contentOverflowY: contentStyle?.overflowY ?? null,
283
+ };
284
+ });
285
+ const environment = await page.evaluate(() => ({
286
+ theme: document
287
+ .querySelector('[data-astryx-theme]')
288
+ ?.getAttribute('data-astryx-theme'),
289
+ mode: document.documentElement.getAttribute('data-theme'),
290
+ viewport: {width: innerWidth, height: innerHeight},
291
+ reducedMotion: matchMedia('(prefers-reduced-motion: reduce)').matches,
292
+ horizontalOverflow: document.documentElement.scrollWidth > innerWidth + 1,
293
+ fonts: document.fonts.status,
294
+ }));
295
+
296
+ expect(pageErrors).toEqual([]);
297
+ expect(environment.theme).toBe(item.theme);
298
+ expect(environment.mode).toBe(item.mode);
299
+ expect(environment.viewport).toEqual(item.viewport);
300
+ expect(environment.reducedMotion).toBe(true);
301
+ expect(environment.horizontalOverflow).toBe(false);
302
+ expect(environment.fonts).toBe('loaded');
303
+ expect(observed.side).toBe(item.expected.side ?? observed.side);
304
+ expect(observed.modal).toBe(item.expected.modal);
305
+ expect(observed.role).toBe(item.expected.role);
306
+ expect(observed.transform).toBe('matrix(1, 0, 0, 1, 0, 0)');
307
+ expect(observed.contentOverflowY).toBe('auto');
308
+
309
+ const expectedDirection = item.expected.motionDirection ?? item.direction;
310
+ expect(observed.direction).toBe(expectedDirection);
311
+ if (item.expected.side === 'start' && observed.direction === 'ltr') {
312
+ expect(box.x).toBeLessThanOrEqual(0.5);
313
+ }
314
+ if (item.expected.side === 'start' && observed.direction === 'rtl') {
315
+ expect(box.x + box.width).toBeGreaterThanOrEqual(
316
+ item.viewport.width - 0.5,
317
+ );
318
+ }
319
+ if (item.expected.side === 'end' && observed.direction === 'ltr') {
320
+ expect(box.x + box.width).toBeGreaterThanOrEqual(
321
+ item.viewport.width - 0.5,
322
+ );
323
+ }
324
+ if (item.expected.side === 'end' && observed.direction === 'rtl') {
325
+ expect(box.x).toBeLessThanOrEqual(0.5);
326
+ }
327
+ if (item.expected.narrowCoverage === 'reveal') {
328
+ expect(box.width).toBeCloseTo(item.viewport.width - 56, 0);
329
+ }
330
+ if (item.expected.narrowCoverage === 'full') {
331
+ expect(box.width).toBeCloseTo(item.viewport.width, 0);
332
+ }
333
+ if (item.expected.paddingPx != null) {
334
+ expect(Number.parseFloat(observed.contentPaddingInlineStart ?? '')).toBe(
335
+ item.expected.paddingPx,
336
+ );
337
+ expect(Number.parseFloat(observed.contentPaddingInlineEnd ?? '')).toBe(
338
+ item.expected.paddingPx,
339
+ );
340
+ }
341
+
342
+ const png = await page.screenshot({animations: 'disabled'});
343
+ expect(png.length).toBeGreaterThan(100);
344
+ const image = `${item.key}.png`;
345
+ const receipt = {
346
+ schemaVersion: 1,
347
+ expected: {
348
+ build: checkoutSha,
349
+ storyId: `core-drawer--${item.story}`,
350
+ mode: item.mode,
351
+ direction: item.direction,
352
+ theme: item.theme,
353
+ viewport: item.viewport,
354
+ ...item.expected,
355
+ },
356
+ observed: {
357
+ build: storybookSha,
358
+ drawerCount: expectedCount,
359
+ closedTranslateX,
360
+ geometry: box,
361
+ ...observed,
362
+ ...environment,
363
+ pageErrors,
364
+ },
365
+ image: {
366
+ file: image,
367
+ sha256: createHash('sha256').update(png).digest('hex'),
368
+ width: png.readUInt32BE(16),
369
+ height: png.readUInt32BE(20),
370
+ },
371
+ passed: true,
372
+ };
373
+ fs.writeFileSync(path.join(OUTPUT, image), png);
374
+ fs.writeFileSync(
375
+ path.join(OUTPUT, `${item.key}.sensors.json`),
376
+ `${JSON.stringify(receipt, null, 2)}\n`,
377
+ );
378
+ await context.close();
379
+ });
380
+ }
381
+
382
+ test('manifest is complete', async () => {
383
+ const receipts = fs
384
+ .readdirSync(OUTPUT)
385
+ .filter(file => file.endsWith('.sensors.json'));
386
+ expect(receipts).toHaveLength(cases.length);
387
+ const manifest = {
388
+ schemaVersion: 1,
389
+ component: 'core/Drawer',
390
+ build: checkoutSha,
391
+ frames: cases.map(item => ({
392
+ key: item.key,
393
+ image: `${item.key}.png`,
394
+ receipt: `${item.key}.sensors.json`,
395
+ })),
396
+ };
397
+ fs.writeFileSync(
398
+ path.join(OUTPUT, 'manifest.json'),
399
+ `${JSON.stringify(manifest, null, 2)}\n`,
400
+ );
401
+ });