@astryxdesign/core 0.5.0 → 0.5.1-canary.f64186a

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 (597) hide show
  1. package/CHANGELOG.md +222 -0
  2. package/dist/AlertDialog/AlertDialog.d.ts +1 -1
  3. package/dist/AlertDialog/AlertDialog.d.ts.map +1 -1
  4. package/dist/AlertDialog/AlertDialog.js +45 -20
  5. package/dist/AspectRatio/AspectRatio.d.ts +6 -6
  6. package/dist/Avatar/Avatar.d.ts +25 -1
  7. package/dist/Avatar/Avatar.d.ts.map +1 -1
  8. package/dist/Avatar/Avatar.js +43 -9
  9. package/dist/Avatar/index.d.ts +2 -2
  10. package/dist/Avatar/index.d.ts.map +1 -1
  11. package/dist/Avatar/index.js +1 -1
  12. package/dist/AvatarGroup/AvatarGroup.d.ts +9 -2
  13. package/dist/AvatarGroup/AvatarGroup.d.ts.map +1 -1
  14. package/dist/AvatarGroup/AvatarGroup.js +5 -2
  15. package/dist/AvatarGroup/AvatarGroupContext.d.ts +2 -1
  16. package/dist/AvatarGroup/AvatarGroupContext.d.ts.map +1 -1
  17. package/dist/AvatarGroup/AvatarGroupOverflow.d.ts.map +1 -1
  18. package/dist/AvatarGroup/AvatarGroupOverflow.js +11 -7
  19. package/dist/Badge/Badge.d.ts.map +1 -1
  20. package/dist/Badge/Badge.js +26 -2
  21. package/dist/Banner/Banner.d.ts +10 -1
  22. package/dist/Banner/Banner.d.ts.map +1 -1
  23. package/dist/Banner/Banner.js +11 -2
  24. package/dist/Button/Button.d.ts.map +1 -1
  25. package/dist/Button/Button.js +8 -7
  26. package/dist/Calendar/Calendar.d.ts +4 -2
  27. package/dist/Calendar/Calendar.d.ts.map +1 -1
  28. package/dist/Calendar/Calendar.js +15 -21
  29. package/dist/Calendar/hooks/useCalendarDays.js +4 -6
  30. package/dist/Calendar/hooks/useCalendarNavigation.js +4 -6
  31. package/dist/Calendar/styles.d.ts +5 -20
  32. package/dist/Calendar/styles.d.ts.map +1 -1
  33. package/dist/Calendar/styles.js +15 -17
  34. package/dist/Card/Card.d.ts +12 -12
  35. package/dist/Card/Card.d.ts.map +1 -1
  36. package/dist/Card/Card.js +17 -9
  37. package/dist/Card/index.d.ts +35 -1
  38. package/dist/Card/index.d.ts.map +1 -1
  39. package/dist/Card/index.js +21 -1
  40. package/dist/Carousel/Carousel.d.ts.map +1 -1
  41. package/dist/Carousel/Carousel.js +108 -7
  42. package/dist/CheckboxInput/CheckboxInput.d.ts.map +1 -1
  43. package/dist/CheckboxInput/CheckboxInput.js +7 -1
  44. package/dist/CodeBlock/CodeBlock.d.ts.map +1 -1
  45. package/dist/CodeBlock/CodeBlock.js +15 -4
  46. package/dist/CodeBlock/highlightRanges.js +1 -1
  47. package/dist/CodeBlock/highlightStyles.js +13 -13
  48. package/dist/CommandPalette/CommandPaletteItem.d.ts.map +1 -1
  49. package/dist/CommandPalette/CommandPaletteItem.js +2 -7
  50. package/dist/ComplexSelector/ComplexSelector.d.ts +10 -2
  51. package/dist/ComplexSelector/ComplexSelector.d.ts.map +1 -1
  52. package/dist/ComplexSelector/ComplexSelector.js +14 -7
  53. package/dist/DateInput/DateInput.d.ts +43 -0
  54. package/dist/DateInput/DateInput.d.ts.map +1 -1
  55. package/dist/DateInput/DateInput.js +22 -5
  56. package/dist/DateInput/MonthScroller.d.ts.map +1 -1
  57. package/dist/DateInput/MonthScroller.js +5 -3
  58. package/dist/DateInput/MonthYearWheels.d.ts.map +1 -1
  59. package/dist/DateInput/MonthYearWheels.js +6 -4
  60. package/dist/DateInput/NativeDateField.d.ts +10 -0
  61. package/dist/DateInput/NativeDateField.d.ts.map +1 -0
  62. package/dist/DateInput/NativeDateField.js +494 -0
  63. package/dist/DateInput/TouchDateField.d.ts.map +1 -1
  64. package/dist/DateInput/TouchDateField.js +52 -25
  65. package/dist/DateInput/Wheel.d.ts.map +1 -1
  66. package/dist/DateInput/Wheel.js +1 -0
  67. package/dist/DateInput/index.d.ts +1 -1
  68. package/dist/DateInput/index.d.ts.map +1 -1
  69. package/dist/DateInput/nativeDateSegments.d.ts +22 -0
  70. package/dist/DateInput/nativeDateSegments.d.ts.map +1 -0
  71. package/dist/DateInput/nativeDateSegments.js +111 -0
  72. package/dist/DateRangeInput/DateRangeInput.d.ts +4 -2
  73. package/dist/DateRangeInput/DateRangeInput.d.ts.map +1 -1
  74. package/dist/DateRangeInput/DateRangeInput.js +3 -5
  75. package/dist/DateTimeInput/DateTimeInput.d.ts +23 -24
  76. package/dist/DateTimeInput/DateTimeInput.d.ts.map +1 -1
  77. package/dist/DateTimeInput/DateTimeInput.js +35 -10
  78. package/dist/DateTimeInput/TouchDateTimeField.d.ts +6 -0
  79. package/dist/DateTimeInput/TouchDateTimeField.d.ts.map +1 -0
  80. package/dist/DateTimeInput/TouchDateTimeField.js +1021 -0
  81. package/dist/Dialog/Dialog.d.ts +16 -2
  82. package/dist/Dialog/Dialog.d.ts.map +1 -1
  83. package/dist/Dialog/Dialog.js +28 -7
  84. package/dist/DropdownMenu/DropdownMenu.d.ts.map +1 -1
  85. package/dist/DropdownMenu/DropdownMenu.js +4 -13
  86. package/dist/Field/FieldLabel.d.ts.map +1 -1
  87. package/dist/Field/FieldLabel.js +9 -1
  88. package/dist/Field/InputClearButton.d.ts +9 -3
  89. package/dist/Field/InputClearButton.d.ts.map +1 -1
  90. package/dist/Field/InputClearButton.js +14 -3
  91. package/dist/Heading/Heading.d.ts.map +1 -1
  92. package/dist/Heading/Heading.js +0 -1
  93. package/dist/HoverCard/HoverCard.d.ts.map +1 -1
  94. package/dist/HoverCard/HoverCard.js +104 -3
  95. package/dist/HoverCard/useHoverCard.d.ts +14 -2
  96. package/dist/HoverCard/useHoverCard.d.ts.map +1 -1
  97. package/dist/HoverCard/useHoverCard.js +7 -1
  98. package/dist/Icon/Icon.d.ts +4 -2
  99. package/dist/Icon/Icon.d.ts.map +1 -1
  100. package/dist/Icon/defaultIcons.d.ts +3 -2
  101. package/dist/Icon/defaultIcons.d.ts.map +1 -1
  102. package/dist/Icon/defaultIcons.js +7 -0
  103. package/dist/Icon/globalIconRegistry.d.ts +13 -0
  104. package/dist/Icon/globalIconRegistry.d.ts.map +1 -1
  105. package/dist/Icon/globalIconRegistry.js +34 -6
  106. package/dist/Icon/index.d.ts +1 -1
  107. package/dist/Icon/index.d.ts.map +1 -1
  108. package/dist/Icon/useIcon.d.ts +5 -2
  109. package/dist/Icon/useIcon.d.ts.map +1 -1
  110. package/dist/Icon/useIcon.js +3 -0
  111. package/dist/Indicator/CheckboxIndicator.d.ts.map +1 -1
  112. package/dist/Indicator/CheckboxIndicator.js +6 -2
  113. package/dist/Item/Item.d.ts.map +1 -1
  114. package/dist/Item/Item.js +2 -2
  115. package/dist/Kbd/Kbd.d.ts.map +1 -1
  116. package/dist/Kbd/Kbd.js +2 -26
  117. package/dist/Layer/gestureCounter.d.ts +8 -0
  118. package/dist/Layer/gestureCounter.d.ts.map +1 -0
  119. package/dist/Layer/gestureCounter.js +53 -0
  120. package/dist/Layer/useLayer.d.ts +23 -13
  121. package/dist/Layer/useLayer.d.ts.map +1 -1
  122. package/dist/Layer/useLayer.js +146 -24
  123. package/dist/List/List.d.ts +1 -1
  124. package/dist/List/List.d.ts.map +1 -1
  125. package/dist/List/List.js +15 -4
  126. package/dist/Markdown/Markdown.d.ts +1 -1
  127. package/dist/Markdown/Markdown.d.ts.map +1 -1
  128. package/dist/Markdown/Markdown.js +20 -7
  129. package/dist/Markdown/parser.d.ts.map +1 -1
  130. package/dist/Markdown/parser.js +5 -3
  131. package/dist/MetadataList/MetadataListItem.d.ts +1 -1
  132. package/dist/MetadataList/MetadataListItem.d.ts.map +1 -1
  133. package/dist/MetadataList/MetadataListItem.js +4 -1
  134. package/dist/MultiSelector/MultiSelector.d.ts +18 -1
  135. package/dist/MultiSelector/MultiSelector.d.ts.map +1 -1
  136. package/dist/MultiSelector/MultiSelector.js +58 -11
  137. package/dist/MultiSelector/hooks.d.ts +7 -1
  138. package/dist/MultiSelector/hooks.d.ts.map +1 -1
  139. package/dist/MultiSelector/hooks.js +3 -2
  140. package/dist/NavIcon/NavIcon.d.ts.map +1 -1
  141. package/dist/NavIcon/NavIcon.js +5 -1
  142. package/dist/NavItem/navItemStyles.stylex.d.ts +0 -8
  143. package/dist/NavItem/navItemStyles.stylex.d.ts.map +1 -1
  144. package/dist/NavItem/navItemStyles.stylex.js +0 -2
  145. package/dist/NavMenu/NavHeadingMenu.d.ts +1 -1
  146. package/dist/NavMenu/NavHeadingMenu.d.ts.map +1 -1
  147. package/dist/NavMenu/NavHeadingMenu.js +7 -4
  148. package/dist/NumberInput/NumberInput.d.ts +6 -1
  149. package/dist/NumberInput/NumberInput.d.ts.map +1 -1
  150. package/dist/NumberInput/NumberInput.js +95 -126
  151. package/dist/NumberInput/numberInputCommit.d.ts +34 -0
  152. package/dist/NumberInput/numberInputCommit.d.ts.map +1 -0
  153. package/dist/NumberInput/numberInputCommit.js +71 -0
  154. package/dist/NumberInput/numberParser.d.ts +64 -0
  155. package/dist/NumberInput/numberParser.d.ts.map +1 -0
  156. package/dist/NumberInput/numberParser.js +350 -0
  157. package/dist/Outline/Outline.d.ts.map +1 -1
  158. package/dist/Outline/Outline.js +2 -3
  159. package/dist/OverflowList/OverflowList.d.ts +41 -1
  160. package/dist/OverflowList/OverflowList.d.ts.map +1 -1
  161. package/dist/OverflowList/OverflowList.js +43 -2
  162. package/dist/Popover/Popover.d.ts.map +1 -1
  163. package/dist/Popover/Popover.js +8 -14
  164. package/dist/Popover/usePopover.d.ts +15 -41
  165. package/dist/Popover/usePopover.d.ts.map +1 -1
  166. package/dist/Popover/usePopover.js +26 -7
  167. package/dist/PowerSearch/PowerSearchValueEditor.d.ts.map +1 -1
  168. package/dist/PowerSearch/PowerSearchValueEditor.js +91 -18
  169. package/dist/PowerSearch/formatFilterValue.d.ts.map +1 -1
  170. package/dist/PowerSearch/formatFilterValue.js +4 -2
  171. package/dist/ProgressBar/ProgressBar.d.ts.map +1 -1
  172. package/dist/ProgressBar/ProgressBar.js +18 -5
  173. package/dist/Resizable/useResizable.d.ts +19 -1
  174. package/dist/Resizable/useResizable.d.ts.map +1 -1
  175. package/dist/Resizable/useResizable.js +104 -38
  176. package/dist/SelectableCard/SelectableCard.d.ts.map +1 -1
  177. package/dist/SelectableCard/SelectableCard.js +9 -0
  178. package/dist/Selector/Selector.d.ts +18 -1
  179. package/dist/Selector/Selector.d.ts.map +1 -1
  180. package/dist/Selector/Selector.js +92 -21
  181. package/dist/Selector/hooks.d.ts +7 -1
  182. package/dist/Selector/hooks.d.ts.map +1 -1
  183. package/dist/Selector/hooks.js +3 -2
  184. package/dist/SideNav/SideNav.d.ts +6 -1
  185. package/dist/SideNav/SideNav.d.ts.map +1 -1
  186. package/dist/SideNav/SideNav.js +57 -27
  187. package/dist/SideNav/SideNavHeading.d.ts.map +1 -1
  188. package/dist/SideNav/SideNavHeading.js +5 -4
  189. package/dist/SideNav/SideNavItem.d.ts +29 -4
  190. package/dist/SideNav/SideNavItem.d.ts.map +1 -1
  191. package/dist/SideNav/SideNavItem.js +75 -20
  192. package/dist/Slider/Slider.d.ts.map +1 -1
  193. package/dist/Slider/Slider.js +34 -2
  194. package/dist/Spinner/Spinner.d.ts +3 -1
  195. package/dist/Spinner/Spinner.d.ts.map +1 -1
  196. package/dist/Spinner/Spinner.js +199 -20
  197. package/dist/StatusDot/StatusDot.d.ts.map +1 -1
  198. package/dist/StatusDot/StatusDot.js +6 -1
  199. package/dist/Stepper/Step.d.ts.map +1 -1
  200. package/dist/Stepper/Step.js +7 -6
  201. package/dist/Switch/Switch.d.ts.map +1 -1
  202. package/dist/Switch/Switch.js +5 -1
  203. package/dist/Table/BaseTable.d.ts.map +1 -1
  204. package/dist/Table/BaseTable.js +6 -1
  205. package/dist/Table/Table.d.ts.map +1 -1
  206. package/dist/Table/Table.js +3 -6
  207. package/dist/Table/plugins/filtering/useTableFiltering.d.ts.map +1 -1
  208. package/dist/Table/plugins/filtering/useTableFiltering.js +73 -4
  209. package/dist/Table/plugins/groupedRows/useTableGroupedRows.d.ts +26 -0
  210. package/dist/Table/plugins/groupedRows/useTableGroupedRows.d.ts.map +1 -1
  211. package/dist/Table/plugins/groupedRows/useTableGroupedRows.js +34 -3
  212. package/dist/Table/plugins/selection/useTableSelection.d.ts.map +1 -1
  213. package/dist/Table/plugins/selection/useTableSelection.js +25 -1
  214. package/dist/Table/plugins/stickyColumns/useTableStickyColumns.d.ts.map +1 -1
  215. package/dist/Table/plugins/stickyColumns/useTableStickyColumns.js +3 -4
  216. package/dist/Text/Text.d.ts.map +1 -1
  217. package/dist/Text/Text.js +0 -1
  218. package/dist/TextArea/TextArea.d.ts.map +1 -1
  219. package/dist/TextArea/TextArea.js +13 -8
  220. package/dist/Timestamp/Timestamp.d.ts +1 -1
  221. package/dist/Timestamp/Timestamp.d.ts.map +1 -1
  222. package/dist/Timestamp/Timestamp.js +10 -18
  223. package/dist/Timestamp/formatInstant.d.ts.map +1 -1
  224. package/dist/Timestamp/formatInstant.js +10 -5
  225. package/dist/Toast/Toast.d.ts +17 -2
  226. package/dist/Toast/Toast.d.ts.map +1 -1
  227. package/dist/Toast/Toast.js +77 -11
  228. package/dist/Toast/ToastViewport.d.ts +1 -0
  229. package/dist/Toast/ToastViewport.d.ts.map +1 -1
  230. package/dist/Toast/ToastViewport.js +76 -21
  231. package/dist/Toast/index.d.ts +1 -1
  232. package/dist/Toast/index.d.ts.map +1 -1
  233. package/dist/Toast/types.d.ts +38 -0
  234. package/dist/Toast/types.d.ts.map +1 -1
  235. package/dist/Toast/useToastGesture.d.ts +26 -0
  236. package/dist/Toast/useToastGesture.d.ts.map +1 -0
  237. package/dist/Toast/useToastGesture.js +223 -0
  238. package/dist/Token/Token.d.ts +1 -1
  239. package/dist/Token/Token.d.ts.map +1 -1
  240. package/dist/Token/Token.js +23 -12
  241. package/dist/Token/TokenLink.d.ts +1 -1
  242. package/dist/Token/TokenLink.d.ts.map +1 -1
  243. package/dist/Token/TokenLink.js +5 -2
  244. package/dist/Tokenizer/Tokenizer.d.ts +12 -1
  245. package/dist/Tokenizer/Tokenizer.d.ts.map +1 -1
  246. package/dist/Tokenizer/Tokenizer.js +31 -21
  247. package/dist/TopNav/TopNavHeading.js +2 -2
  248. package/dist/TopNav/TopNavItem.d.ts.map +1 -1
  249. package/dist/TopNav/TopNavItem.js +3 -3
  250. package/dist/TopNav/TopNavMegaMenu.d.ts +1 -1
  251. package/dist/TopNav/TopNavMegaMenu.d.ts.map +1 -1
  252. package/dist/TopNav/TopNavMegaMenu.js +30 -9
  253. package/dist/TopNav/TopNavMegaMenuItem.d.ts.map +1 -1
  254. package/dist/TopNav/TopNavMegaMenuItem.js +3 -3
  255. package/dist/TopNav/TopNavMenu.d.ts +1 -1
  256. package/dist/TopNav/TopNavMenu.d.ts.map +1 -1
  257. package/dist/TopNav/TopNavMenu.js +21 -6
  258. package/dist/TreeList/TreeList.d.ts +1 -1
  259. package/dist/TreeList/TreeList.d.ts.map +1 -1
  260. package/dist/TreeList/TreeList.js +7 -2
  261. package/dist/TreeList/TreeListItem.d.ts.map +1 -1
  262. package/dist/TreeList/TreeListItem.js +2 -2
  263. package/dist/Typeahead/BaseTypeahead.d.ts +33 -0
  264. package/dist/Typeahead/BaseTypeahead.d.ts.map +1 -1
  265. package/dist/Typeahead/BaseTypeahead.js +51 -8
  266. package/dist/Typeahead/Typeahead.d.ts +8 -1
  267. package/dist/Typeahead/Typeahead.d.ts.map +1 -1
  268. package/dist/Typeahead/Typeahead.js +2 -0
  269. package/dist/Typeahead/TypeaheadItem.d.ts +1 -1
  270. package/dist/Typeahead/TypeaheadItem.d.ts.map +1 -1
  271. package/dist/Typeahead/TypeaheadItem.js +7 -2
  272. package/dist/astryx.css +87 -22
  273. package/dist/hooks/useHotkeys.d.ts.map +1 -1
  274. package/dist/hooks/useHotkeys.js +3 -25
  275. package/dist/hooks/useOverflow.d.ts.map +1 -1
  276. package/dist/hooks/useOverflow.js +14 -4
  277. package/dist/index.d.ts +1 -1
  278. package/dist/index.d.ts.map +1 -1
  279. package/dist/theme/Theme.d.ts.map +1 -1
  280. package/dist/theme/Theme.js +46 -10
  281. package/dist/theme/defineTheme.d.ts +9 -3
  282. package/dist/theme/defineTheme.d.ts.map +1 -1
  283. package/dist/theme/defineTheme.js +5 -0
  284. package/dist/theme/derivedVarRegistry.d.ts.map +1 -1
  285. package/dist/theme/derivedVarRegistry.js +24 -4
  286. package/dist/theme/generateThemeRules.d.ts +21 -0
  287. package/dist/theme/generateThemeRules.d.ts.map +1 -1
  288. package/dist/theme/generateThemeRules.js +26 -0
  289. package/dist/theme/syntax/tokens.d.ts +1 -1
  290. package/dist/theme/syntax/tokens.d.ts.map +1 -1
  291. package/dist/theme/syntax/tokens.js +5 -2
  292. package/dist/theme/useTheme.d.ts.map +1 -1
  293. package/dist/theme/useTheme.js +6 -7
  294. package/dist/utils/dateParser.d.ts +5 -8
  295. package/dist/utils/dateParser.d.ts.map +1 -1
  296. package/dist/utils/dateParser.js +10 -11
  297. package/dist/utils/focusOutline.stylex.d.ts +25 -0
  298. package/dist/utils/focusOutline.stylex.d.ts.map +1 -1
  299. package/dist/utils/focusOutline.stylex.js +15 -0
  300. package/dist/utils/interactionOverlay.stylex.d.ts +26 -0
  301. package/dist/utils/interactionOverlay.stylex.d.ts.map +1 -0
  302. package/dist/utils/interactionOverlay.stylex.js +42 -0
  303. package/dist/utils/isApplePlatform.d.ts +18 -0
  304. package/dist/utils/isApplePlatform.d.ts.map +1 -0
  305. package/dist/utils/isApplePlatform.js +37 -0
  306. package/dist/utils/plainDate.d.ts +11 -0
  307. package/dist/utils/plainDate.d.ts.map +1 -1
  308. package/dist/utils/plainDate.js +20 -4
  309. package/locales/af-ZA.json +7 -7
  310. package/locales/ar-SA.json +7 -7
  311. package/locales/ca-ES.json +6 -6
  312. package/locales/cs-CZ.json +7 -7
  313. package/locales/da-DK.json +7 -7
  314. package/locales/de-DE.json +7 -7
  315. package/locales/el-GR.json +7 -7
  316. package/locales/en.json +178 -6
  317. package/locales/es-ES.json +6 -6
  318. package/locales/fi-FI.json +7 -7
  319. package/locales/fr-FR.json +7 -7
  320. package/locales/he-IL.json +7 -7
  321. package/locales/hu-HU.json +7 -7
  322. package/locales/it-IT.json +7 -7
  323. package/locales/ja-JP.json +7 -7
  324. package/locales/ko-KR.json +7 -7
  325. package/locales/nl-NL.json +7 -7
  326. package/locales/no-NO.json +7 -7
  327. package/locales/pl-PL.json +7 -7
  328. package/locales/pseudo.json +130 -1
  329. package/locales/pt-BR.json +7 -7
  330. package/locales/pt-PT.json +7 -7
  331. package/locales/ro-RO.json +7 -7
  332. package/locales/ru-RU.json +7 -7
  333. package/locales/sr-SP.json +7 -7
  334. package/locales/sv-SE.json +7 -7
  335. package/locales/tr-TR.json +7 -7
  336. package/locales/uk-UA.json +7 -7
  337. package/locales/vi-VN.json +7 -7
  338. package/locales/zh-CN.json +7 -7
  339. package/locales/zh-TW.json +7 -7
  340. package/package.json +4 -5
  341. package/src/AlertDialog/AlertDialog.doc.mjs +114 -30
  342. package/src/AlertDialog/AlertDialog.test.tsx +211 -2
  343. package/src/AlertDialog/AlertDialog.tsx +62 -20
  344. package/src/AspectRatio/AspectRatio.doc.mjs +3 -3
  345. package/src/AspectRatio/AspectRatio.tsx +6 -6
  346. package/src/Avatar/Avatar.doc.mjs +12 -2
  347. package/src/Avatar/Avatar.test.tsx +80 -0
  348. package/src/Avatar/Avatar.tsx +64 -14
  349. package/src/Avatar/index.ts +2 -2
  350. package/src/AvatarGroup/AvatarGroup.doc.mjs +8 -2
  351. package/src/AvatarGroup/AvatarGroup.test.tsx +24 -0
  352. package/src/AvatarGroup/AvatarGroup.tsx +12 -4
  353. package/src/AvatarGroup/AvatarGroupContext.ts +5 -3
  354. package/src/AvatarGroup/AvatarGroupOverflow.tsx +12 -12
  355. package/src/Badge/Badge.doc.mjs +3 -2
  356. package/src/Badge/Badge.test.tsx +32 -3
  357. package/src/Badge/Badge.tsx +42 -1
  358. package/src/Banner/Banner.doc.mjs +9 -0
  359. package/src/Banner/Banner.test.tsx +76 -11
  360. package/src/Banner/Banner.tsx +21 -2
  361. package/src/Button/Button.doc.mjs +2 -1
  362. package/src/Button/Button.test.tsx +19 -4
  363. package/src/Button/Button.tsx +9 -29
  364. package/src/ButtonGroup/ButtonGroup.doc.mjs +2 -2
  365. package/src/ButtonGroup/ButtonGroup.test.tsx +13 -0
  366. package/src/Calendar/Calendar.doc.mjs +3 -3
  367. package/src/Calendar/Calendar.test.tsx +112 -0
  368. package/src/Calendar/Calendar.tsx +18 -16
  369. package/src/Calendar/hooks/useCalendarDays.ts +4 -4
  370. package/src/Calendar/hooks/useCalendarNavigation.ts +4 -4
  371. package/src/Calendar/styles.ts +48 -42
  372. package/src/Card/Card.doc.mjs +10 -7
  373. package/src/Card/Card.test.tsx +113 -19
  374. package/src/Card/Card.tsx +67 -89
  375. package/src/Card/index.ts +36 -1
  376. package/src/Carousel/Carousel.doc.mjs +3 -0
  377. package/src/Carousel/Carousel.test.tsx +360 -0
  378. package/src/Carousel/Carousel.tsx +116 -15
  379. package/src/CheckboxInput/CheckboxInput.doc.mjs +2 -0
  380. package/src/CheckboxInput/CheckboxInput.test.tsx +15 -0
  381. package/src/CheckboxInput/CheckboxInput.tsx +5 -0
  382. package/src/CodeBlock/CodeBlock.doc.mjs +10 -4
  383. package/src/CodeBlock/CodeBlock.test.tsx +37 -0
  384. package/src/CodeBlock/CodeBlock.tsx +20 -4
  385. package/src/CodeBlock/highlightRanges.ts +1 -1
  386. package/src/CodeBlock/highlightStyles.ts +13 -13
  387. package/src/CommandPalette/CommandPaletteItem.tsx +2 -12
  388. package/src/ComplexSelector/ComplexSelector.doc.mjs +7 -0
  389. package/src/ComplexSelector/ComplexSelector.test.tsx +183 -0
  390. package/src/ComplexSelector/ComplexSelector.tsx +22 -12
  391. package/src/DateInput/DateInput.doc.mjs +16 -0
  392. package/src/DateInput/DateInput.test.tsx +9 -4
  393. package/src/DateInput/DateInput.tsx +54 -3
  394. package/src/DateInput/DateInputTouch.test.tsx +146 -32
  395. package/src/DateInput/MonthScroller.tsx +5 -1
  396. package/src/DateInput/MonthYearWheels.tsx +7 -4
  397. package/src/DateInput/NativeDateField.test.tsx +635 -0
  398. package/src/DateInput/NativeDateField.tsx +641 -0
  399. package/src/DateInput/TouchDateField.tsx +83 -33
  400. package/src/DateInput/Wheel.tsx +1 -0
  401. package/src/DateInput/index.ts +1 -0
  402. package/src/DateInput/nativeDateSegments.ts +127 -0
  403. package/src/DateRangeInput/DateRangeInput.doc.mjs +2 -2
  404. package/src/DateRangeInput/DateRangeInput.test.tsx +46 -0
  405. package/src/DateRangeInput/DateRangeInput.tsx +8 -13
  406. package/src/DateTimeInput/DateTimeInput.doc.mjs +38 -21
  407. package/src/DateTimeInput/DateTimeInput.test.tsx +76 -0
  408. package/src/DateTimeInput/DateTimeInput.tsx +54 -20
  409. package/src/DateTimeInput/DateTimeInputTouch.test.tsx +980 -0
  410. package/src/DateTimeInput/TouchDateTimeField.tsx +1437 -0
  411. package/src/Dialog/Dialog.test.tsx +185 -18
  412. package/src/Dialog/Dialog.tsx +35 -11
  413. package/src/DropdownMenu/DropdownMenu.test.tsx +44 -10
  414. package/src/DropdownMenu/DropdownMenu.tsx +4 -13
  415. package/src/Field/FieldLabel.test.tsx +29 -0
  416. package/src/Field/FieldLabel.tsx +7 -0
  417. package/src/Field/InputClearButton.test.tsx +15 -1
  418. package/src/Field/InputClearButton.tsx +28 -4
  419. package/src/Heading/Heading.tsx +0 -1
  420. package/src/HoverCard/HoverCard.doc.mjs +8 -2
  421. package/src/HoverCard/HoverCard.test.tsx +154 -4
  422. package/src/HoverCard/HoverCard.tsx +137 -3
  423. package/src/HoverCard/useHoverCard.tsx +23 -3
  424. package/src/Icon/Icon.test.tsx +55 -1
  425. package/src/Icon/Icon.tsx +5 -3
  426. package/src/Icon/defaultIcons.tsx +11 -2
  427. package/src/Icon/globalIconRegistry.test.tsx +16 -3
  428. package/src/Icon/globalIconRegistry.tsx +37 -6
  429. package/src/Icon/index.ts +1 -0
  430. package/src/Icon/useIcon.ts +9 -2
  431. package/src/Indicator/CheckboxIndicator.tsx +14 -8
  432. package/src/Indicator/Indicator.doc.mjs +2 -0
  433. package/src/Item/Item.tsx +2 -7
  434. package/src/Kbd/Kbd.test.tsx +0 -17
  435. package/src/Kbd/Kbd.tsx +2 -26
  436. package/src/Layer/gestureCounter.ts +57 -0
  437. package/src/Layer/useLayer.test.tsx +368 -16
  438. package/src/Layer/useLayer.tsx +208 -35
  439. package/src/Layout/__tests__/edgeCompensation.test.tsx +1 -1
  440. package/src/List/List.test.tsx +38 -0
  441. package/src/List/List.tsx +8 -1
  442. package/src/Markdown/Markdown.test.tsx +37 -0
  443. package/src/Markdown/Markdown.tsx +16 -5
  444. package/src/Markdown/parser.test.ts +33 -0
  445. package/src/Markdown/parser.ts +9 -3
  446. package/src/MetadataList/MetadataList.test.tsx +75 -2
  447. package/src/MetadataList/MetadataListItem.tsx +5 -2
  448. package/src/MultiSelector/MultiSelector.doc.mjs +22 -1
  449. package/src/MultiSelector/MultiSelector.test.tsx +205 -0
  450. package/src/MultiSelector/MultiSelector.tsx +103 -16
  451. package/src/MultiSelector/hooks.ts +9 -2
  452. package/src/NavIcon/NavIcon.doc.mjs +8 -2
  453. package/src/NavIcon/NavIcon.test.tsx +9 -0
  454. package/src/NavIcon/NavIcon.tsx +5 -1
  455. package/src/NavItem/navItemStyles.stylex.ts +0 -8
  456. package/src/NavMenu/NavHeadingMenu.test.tsx +30 -0
  457. package/src/NavMenu/NavHeadingMenu.tsx +7 -4
  458. package/src/NumberInput/NumberInput.doc.mjs +26 -7
  459. package/src/NumberInput/NumberInput.test.tsx +563 -8
  460. package/src/NumberInput/NumberInput.tsx +77 -131
  461. package/src/NumberInput/numberInputCommit.test.ts +72 -0
  462. package/src/NumberInput/numberInputCommit.ts +103 -0
  463. package/src/NumberInput/numberParser.docblock.test.ts +234 -0
  464. package/src/NumberInput/numberParser.test.ts +222 -0
  465. package/src/NumberInput/numberParser.ts +403 -0
  466. package/src/Outline/Outline.tsx +2 -4
  467. package/src/OverflowList/OverflowList.doc.mjs +102 -21
  468. package/src/OverflowList/OverflowList.test.tsx +550 -4
  469. package/src/OverflowList/OverflowList.tsx +100 -2
  470. package/src/Pagination/Pagination.test.tsx +3 -2
  471. package/src/Popover/Popover.doc.mjs +2 -2
  472. package/src/Popover/Popover.test.tsx +38 -0
  473. package/src/Popover/Popover.tsx +28 -66
  474. package/src/Popover/usePopover.tsx +44 -5
  475. package/src/PowerSearch/PowerSearchEditPopover.test.tsx +87 -0
  476. package/src/PowerSearch/PowerSearchValueEditor.test.tsx +64 -0
  477. package/src/PowerSearch/PowerSearchValueEditor.tsx +109 -10
  478. package/src/PowerSearch/formatFilterValue.test.ts +16 -1
  479. package/src/PowerSearch/formatFilterValue.ts +2 -0
  480. package/src/ProgressBar/ProgressBar.doc.mjs +42 -6
  481. package/src/ProgressBar/ProgressBar.test.tsx +24 -0
  482. package/src/ProgressBar/ProgressBar.tsx +28 -8
  483. package/src/Resizable/Resizable.doc.mjs +2 -2
  484. package/src/Resizable/useResizable.doc.mjs +21 -2
  485. package/src/Resizable/useResizable.test.ts +421 -0
  486. package/src/Resizable/useResizable.ts +133 -48
  487. package/src/SelectableCard/SelectableCard.doc.mjs +3 -0
  488. package/src/SelectableCard/SelectableCard.tsx +16 -0
  489. package/src/Selector/Selector.doc.mjs +14 -0
  490. package/src/Selector/Selector.source-build.test.mjs +65 -0
  491. package/src/Selector/Selector.test.tsx +301 -0
  492. package/src/Selector/Selector.tsx +145 -32
  493. package/src/Selector/hooks.ts +17 -2
  494. package/src/SideNav/SideNav.doc.mjs +2 -2
  495. package/src/SideNav/SideNav.test.tsx +1069 -6
  496. package/src/SideNav/SideNav.tsx +109 -38
  497. package/src/SideNav/SideNavHeading.tsx +5 -2
  498. package/src/SideNav/SideNavItem.doc.mjs +24 -3
  499. package/src/SideNav/SideNavItem.tsx +134 -44
  500. package/src/Slider/Slider.test.tsx +106 -1
  501. package/src/Slider/Slider.tsx +52 -1
  502. package/src/Spinner/Spinner.doc.mjs +17 -5
  503. package/src/Spinner/Spinner.test.tsx +164 -0
  504. package/src/Spinner/Spinner.tsx +252 -22
  505. package/src/StatusDot/StatusDot.doc.mjs +8 -2
  506. package/src/StatusDot/StatusDot.test.tsx +9 -0
  507. package/src/StatusDot/StatusDot.tsx +7 -1
  508. package/src/Stepper/Step.doc.mjs +1 -1
  509. package/src/Stepper/Step.tsx +7 -14
  510. package/src/Switch/Switch.doc.mjs +2 -0
  511. package/src/Switch/Switch.test.tsx +10 -0
  512. package/src/Switch/Switch.tsx +3 -0
  513. package/src/Table/BaseTable.tsx +6 -1
  514. package/src/Table/Table.doc.mjs +5 -3
  515. package/src/Table/Table.tsx +3 -8
  516. package/src/Table/TableBody.doc.mjs +2 -2
  517. package/src/Table/TableFooter.doc.mjs +1 -1
  518. package/src/Table/TableHeader.doc.mjs +1 -1
  519. package/src/Table/plugins/filtering/useTableFiltering.test.tsx +44 -6
  520. package/src/Table/plugins/filtering/useTableFiltering.tsx +100 -4
  521. package/src/Table/plugins/groupedRows/useTableGroupedRows.tsx +50 -4
  522. package/src/Table/plugins/selection/useTableSelection.test.tsx +62 -0
  523. package/src/Table/plugins/selection/useTableSelection.tsx +25 -2
  524. package/src/Table/plugins/stickyColumns/useTableStickyColumns.tsx +1 -2
  525. package/src/Table/useTableGroupedRows.doc.mjs +3 -3
  526. package/src/Table/useTablePagination.doc.mjs +1 -1
  527. package/src/Table/useTableSelection.doc.mjs +1 -1
  528. package/src/Text/Text.test.tsx +44 -0
  529. package/src/Text/Text.tsx +0 -1
  530. package/src/TextArea/TextArea.doc.mjs +12 -2
  531. package/src/TextArea/TextArea.test.tsx +11 -0
  532. package/src/TextArea/TextArea.tsx +34 -22
  533. package/src/Timestamp/Timestamp.test.tsx +89 -0
  534. package/src/Timestamp/Timestamp.tsx +8 -8
  535. package/src/Timestamp/formatInstant.ts +5 -0
  536. package/src/Toast/Toast.doc.mjs +213 -44
  537. package/src/Toast/Toast.tsx +118 -23
  538. package/src/Toast/ToastViewport.test.tsx +1434 -8
  539. package/src/Toast/ToastViewport.tsx +85 -14
  540. package/src/Toast/index.ts +2 -0
  541. package/src/Toast/types.ts +43 -5
  542. package/src/Toast/useToastGesture.ts +361 -0
  543. package/src/Token/Token.test.tsx +95 -0
  544. package/src/Token/Token.tsx +19 -17
  545. package/src/Token/TokenLink.tsx +12 -3
  546. package/src/Tokenizer/Tokenizer.doc.mjs +16 -3
  547. package/src/Tokenizer/Tokenizer.test.tsx +161 -0
  548. package/src/Tokenizer/Tokenizer.tsx +49 -24
  549. package/src/TopNav/TopNavHeading.tsx +2 -2
  550. package/src/TopNav/TopNavItem.tsx +3 -7
  551. package/src/TopNav/TopNavMegaMenu.test.tsx +104 -0
  552. package/src/TopNav/TopNavMegaMenu.tsx +47 -4
  553. package/src/TopNav/TopNavMegaMenuItem.tsx +10 -9
  554. package/src/TopNav/TopNavMenu.test.tsx +133 -1
  555. package/src/TopNav/TopNavMenu.tsx +38 -5
  556. package/src/TreeList/TreeList.test.tsx +49 -0
  557. package/src/TreeList/TreeList.tsx +7 -2
  558. package/src/TreeList/TreeListItem.tsx +2 -7
  559. package/src/Typeahead/BaseTypeahead.doc.mjs +13 -0
  560. package/src/Typeahead/BaseTypeahead.tsx +96 -6
  561. package/src/Typeahead/Typeahead.doc.mjs +6 -0
  562. package/src/Typeahead/Typeahead.test.tsx +154 -0
  563. package/src/Typeahead/Typeahead.tsx +9 -0
  564. package/src/Typeahead/TypeaheadItem.test.tsx +43 -0
  565. package/src/Typeahead/TypeaheadItem.tsx +8 -1
  566. package/src/hooks/useAnnounce.doc.mjs +96 -0
  567. package/src/hooks/useDevWarning.doc.mjs +96 -0
  568. package/src/hooks/useHotkeys.test.ts +0 -18
  569. package/src/hooks/useHotkeys.ts +3 -25
  570. package/src/hooks/useIndicatorFocusRing.doc.mjs +104 -0
  571. package/src/hooks/useInputStatusIcon.doc.mjs +142 -0
  572. package/src/hooks/useInteractiveRole.doc.mjs +119 -0
  573. package/src/hooks/useLongPress.doc.mjs +123 -0
  574. package/src/hooks/useOverflow.doc.mjs +58 -17
  575. package/src/hooks/useOverflow.ts +16 -4
  576. package/src/hooks/useTypeahead.doc.mjs +153 -0
  577. package/src/index.ts +2 -0
  578. package/src/raw-import.d.ts +14 -0
  579. package/src/theme/Theme.test.tsx +104 -2
  580. package/src/theme/Theme.tsx +49 -14
  581. package/src/theme/defineTheme.test.ts +23 -0
  582. package/src/theme/defineTheme.ts +12 -3
  583. package/src/theme/derivedVarRegistry.test.ts +87 -3
  584. package/src/theme/derivedVarRegistry.ts +23 -4
  585. package/src/theme/generateThemeRules.test.ts +99 -1
  586. package/src/theme/generateThemeRules.ts +28 -0
  587. package/src/theme/syntax/tokens.ts +5 -2
  588. package/src/theme/useTheme.test.tsx +10 -0
  589. package/src/theme/useTheme.ts +16 -10
  590. package/src/utils/dateParser.test.ts +34 -2
  591. package/src/utils/dateParser.ts +11 -14
  592. package/src/utils/focusOutline.stylex.ts +50 -0
  593. package/src/utils/interactionOverlay.stylex.ts +74 -0
  594. package/src/utils/isApplePlatform.test.ts +61 -0
  595. package/src/utils/isApplePlatform.ts +37 -0
  596. package/src/utils/plainDate.test.ts +46 -0
  597. package/src/utils/plainDate.ts +18 -3
@@ -97,6 +97,19 @@ export interface BaseTypeaheadProps<T extends SearchableItem> extends Omit<
97
97
  /** Fixed dropdown width in pixels. Never shrinks below the anchor width. */
98
98
  menuWidth?: number;
99
99
 
100
+ /**
101
+ * Minimum query length before the search source is queried. Below it no
102
+ * search runs and the menu stays closed, so a remote source is not asked
103
+ * for a result set that cannot be meaningful yet — and the user does not
104
+ * see "no results" for a query that was never searched.
105
+ *
106
+ * Measured with `String.length` (UTF-16 code units), like every other
107
+ * length check in the library.
108
+ *
109
+ * @default 1 — every non-empty query is searched.
110
+ */
111
+ minQueryLength?: number;
112
+
100
113
  /**
101
114
  * Text shown when no results found.
102
115
  * @default 'No results found'
@@ -135,6 +148,28 @@ export interface BaseTypeaheadProps<T extends SearchableItem> extends Omit<
135
148
  */
136
149
  onOpenChange?: (isOpen: boolean) => void;
137
150
 
151
+ /**
152
+ * Entries derived from the query text rather than fetched for it — today,
153
+ * Tokenizer's "Create ...".
154
+ *
155
+ * They are appended to whatever the search returned, and they are offered
156
+ * whatever `minQueryLength` says: that threshold exists to avoid a fetch
157
+ * that is too broad to be worth making, and these cost no fetch. A field
158
+ * that can create `QA` should not stop being able to just because a search
159
+ * for `QA` would match too much.
160
+ *
161
+ * Receives the results they will be appended to, so a caller can decline to
162
+ * offer an entry that duplicates one.
163
+ *
164
+ * Underscored and `@internal`: `BaseTypeaheadProps` is re-exported from the
165
+ * package entry point, so anything named on it ships as public API at the
166
+ * next cut. This is a wiring detail between Tokenizer and the base — the
167
+ * same reason `DefinedTheme.__inputTokens` carries its prefix.
168
+ *
169
+ * @internal
170
+ */
171
+ __queryEntries?: (query: string, results: T[]) => T[];
172
+
138
173
  /**
139
174
  * Debounce delay in ms before triggering search after typing.
140
175
  * Set to 0 for synchronous/local search sources that don't need debouncing.
@@ -301,6 +336,19 @@ const itemSizeStyles = stylex.create({
301
336
  },
302
337
  });
303
338
 
339
+ // =============================================================================
340
+ // Helpers
341
+ // =============================================================================
342
+
343
+ /**
344
+ * A query that has been typed but is still shorter than the caller's
345
+ * threshold. An empty query is not "below the minimum" — it is the
346
+ * untouched state, and `hasEntriesOnFocus` owns what happens there.
347
+ */
348
+ function isBelowMinQueryLength(query: string, minQueryLength: number): boolean {
349
+ return query.length > 0 && query.length < minQueryLength;
350
+ }
351
+
304
352
  // =============================================================================
305
353
  // Component
306
354
  // =============================================================================
@@ -333,12 +381,14 @@ export const BaseTypeahead = function BaseTypeahead<T extends SearchableItem>({
333
381
  hasEntriesOnFocus = false,
334
382
  maxMenuItems = 10,
335
383
  menuWidth,
384
+ minQueryLength = 1,
336
385
  emptySearchResultsText: emptySearchResultsTextFromProps,
337
386
  isDisabled = false,
338
387
  isFocusableDisabled = false,
339
388
  hasAutoFocus = false,
340
389
  onChangeQuery,
341
390
  onOpenChange,
391
+ __queryEntries,
342
392
  inputId: externalInputId,
343
393
  ariaDescribedBy,
344
394
  ariaLabelledBy,
@@ -457,7 +507,11 @@ export const BaseTypeahead = function BaseTypeahead<T extends SearchableItem>({
457
507
  return;
458
508
  }
459
509
  resultsGenRef.current = gen;
460
- const shown = searchResults.slice(0, maxMenuItems);
510
+ const fetched = searchResults.slice(0, maxMenuItems);
511
+ const shown = [
512
+ ...fetched,
513
+ ...(__queryEntries?.(searchQuery, fetched) ?? []),
514
+ ];
461
515
  setResults(shown);
462
516
  setHighlightedIndex(shown.length > 0 ? 0 : -1);
463
517
  if (searchResults.length > 0 || searchQuery.length > 0) {
@@ -490,6 +544,7 @@ export const BaseTypeahead = function BaseTypeahead<T extends SearchableItem>({
490
544
  showLayer,
491
545
  announce,
492
546
  emptySearchResultsText,
547
+ __queryEntries,
493
548
  t,
494
549
  ],
495
550
  );
@@ -532,14 +587,35 @@ export const BaseTypeahead = function BaseTypeahead<T extends SearchableItem>({
532
587
  clearTimeout(searchTimeoutRef.current);
533
588
  }
534
589
 
535
- if (newQuery.length === 0 && !hasEntriesOnFocus) {
590
+ // Nothing to search: either the field was emptied, or the query is
591
+ // still shorter than `minQueryLength`. Both drop stale results and
592
+ // close the menu — showing the empty state for a query that was never
593
+ // searched would report "no results" that nobody looked for.
594
+ if (
595
+ (newQuery.length === 0 && !hasEntriesOnFocus) ||
596
+ isBelowMinQueryLength(newQuery, minQueryLength)
597
+ ) {
536
598
  searchGenRef.current++;
537
599
  searchSource.cancel?.();
538
- setResults([]);
600
+ // A query too short to search can still carry entries derived from
601
+ // the text itself. `hasSearched` stays false either way, so the menu
602
+ // never reports "no results" for a query nobody looked for.
603
+ const derived = __queryEntries?.(newQuery, []) ?? [];
604
+ setResults(derived);
605
+ setHighlightedIndex(derived.length > 0 ? 0 : -1);
539
606
  setHasSearched(false);
607
+ // Bumping the generation abandons any in-flight search, which means
608
+ // its own `finally` will decline to clear this — so clear it here or
609
+ // the field spins forever. Backspacing below the threshold on a remote
610
+ // source is the everyday way to hit that.
611
+ setIsLoading(false);
540
612
  // Clear any lingering result-count / no-results announcement.
541
613
  announce('');
542
- popover.hide();
614
+ if (derived.length > 0) {
615
+ showLayer();
616
+ } else {
617
+ popover.hide();
618
+ }
543
619
  return;
544
620
  }
545
621
 
@@ -560,6 +636,9 @@ export const BaseTypeahead = function BaseTypeahead<T extends SearchableItem>({
560
636
  [
561
637
  onChangeQuery,
562
638
  hasEntriesOnFocus,
639
+ minQueryLength,
640
+ __queryEntries,
641
+ showLayer,
563
642
  performSearch,
564
643
  performBootstrap,
565
644
  popover,
@@ -591,6 +670,10 @@ export const BaseTypeahead = function BaseTypeahead<T extends SearchableItem>({
591
670
  setQuery('');
592
671
  setResults([]);
593
672
  setHasSearched(false);
673
+ // Same reason as in handleQueryChange: the invalidated search will not
674
+ // clear this itself. Selecting a stale result while the next search is
675
+ // still in flight would otherwise leave the field spinning.
676
+ setIsLoading(false);
594
677
  popover.hide();
595
678
  inputRef.current?.focus();
596
679
  },
@@ -674,7 +757,13 @@ export const BaseTypeahead = function BaseTypeahead<T extends SearchableItem>({
674
757
  if (results.length > 0) {
675
758
  popover.show();
676
759
  setHighlightedIndex(0);
677
- } else if (hasEntriesOnFocus) {
760
+ } else if (
761
+ hasEntriesOnFocus &&
762
+ // A below-threshold query was never searched; falling back to the
763
+ // bootstrap entries here would open a menu of suggestions that
764
+ // ignore what the user has already typed.
765
+ !isBelowMinQueryLength(query, minQueryLength)
766
+ ) {
678
767
  void performBootstrap();
679
768
  }
680
769
  }
@@ -740,7 +829,8 @@ export const BaseTypeahead = function BaseTypeahead<T extends SearchableItem>({
740
829
  highlightedIndex,
741
830
  handleSelect,
742
831
  hasEntriesOnFocus,
743
- query.length,
832
+ query,
833
+ minQueryLength,
744
834
  performBootstrap,
745
835
  externalOnKeyDown,
746
836
  ],
@@ -83,6 +83,12 @@ export const docs = {
83
83
  description: 'Maximum number of dropdown items to display.',
84
84
  default: '10',
85
85
  },
86
+ {
87
+ name: 'minQueryLength',
88
+ type: 'number',
89
+ description: 'Minimum query length before the search source is queried. Below it no search runs and the menu stays closed.',
90
+ default: '1',
91
+ },
86
92
  {
87
93
  name: 'status',
88
94
  type: "{type: 'warning' | 'error' | 'success', message?: string}",
@@ -778,6 +778,160 @@ describe('BaseTypeahead hasEntriesOnFocus', () => {
778
778
  });
779
779
  });
780
780
 
781
+ describe('BaseTypeahead minQueryLength', () => {
782
+ it('does not search or open the menu below the threshold', async () => {
783
+ const search = vi.fn((query: string) =>
784
+ fruits.filter(f => f.label.toLowerCase().includes(query.toLowerCase())),
785
+ );
786
+ render(
787
+ <BaseTypeahead
788
+ searchSource={{search, bootstrap: () => []}}
789
+ value={null}
790
+ onChange={() => {}}
791
+ minQueryLength={3}
792
+ debounceMs={0}
793
+ />,
794
+ );
795
+ const input = screen.getByRole('combobox');
796
+
797
+ fireEvent.change(input, {target: {value: 'Ap'}});
798
+ await act(async () => {
799
+ await Promise.resolve();
800
+ });
801
+
802
+ expect(search).not.toHaveBeenCalled();
803
+ expect(input).toHaveAttribute('aria-expanded', 'false');
804
+
805
+ // Positive control: the third character crosses the threshold, so the
806
+ // same harness does see the search and the open menu.
807
+ fireEvent.change(input, {target: {value: 'App'}});
808
+ await waitFor(() => {
809
+ expect(input).toHaveAttribute('aria-expanded', 'true');
810
+ });
811
+ expect(search).toHaveBeenCalledExactlyOnceWith('App');
812
+ });
813
+
814
+ it('closes the menu again when the query falls back below the threshold', async () => {
815
+ render(
816
+ <BaseTypeahead
817
+ searchSource={fruitSource}
818
+ value={null}
819
+ onChange={() => {}}
820
+ minQueryLength={3}
821
+ debounceMs={0}
822
+ />,
823
+ );
824
+ const input = screen.getByRole('combobox');
825
+
826
+ fireEvent.change(input, {target: {value: 'App'}});
827
+ await waitFor(() => {
828
+ expect(input).toHaveAttribute('aria-expanded', 'true');
829
+ });
830
+
831
+ fireEvent.change(input, {target: {value: 'Ap'}});
832
+ await waitFor(() => {
833
+ expect(input).toHaveAttribute('aria-expanded', 'false');
834
+ });
835
+ });
836
+
837
+ it('does not fall back to bootstrap entries on ArrowDown below the threshold', async () => {
838
+ const bootstrap = vi.fn(() => fruits.slice(0, 3));
839
+ render(
840
+ <BaseTypeahead
841
+ searchSource={{search: () => [], bootstrap}}
842
+ value={null}
843
+ onChange={() => {}}
844
+ hasEntriesOnFocus
845
+ minQueryLength={3}
846
+ debounceMs={0}
847
+ />,
848
+ );
849
+ const input = screen.getByRole('combobox');
850
+
851
+ fireEvent.focus(input);
852
+ await waitFor(() => {
853
+ expect(input).toHaveAttribute('aria-expanded', 'true');
854
+ });
855
+ bootstrap.mockClear();
856
+
857
+ // Typing below the threshold closes the bootstrap menu...
858
+ fireEvent.change(input, {target: {value: 'Ap'}});
859
+ await waitFor(() => {
860
+ expect(input).toHaveAttribute('aria-expanded', 'false');
861
+ });
862
+
863
+ // ...and ArrowDown must not re-open it with entries that ignore the
864
+ // two characters already typed.
865
+ fireEvent.keyDown(input, {key: 'ArrowDown'});
866
+ await act(async () => {
867
+ await Promise.resolve();
868
+ });
869
+ expect(bootstrap).not.toHaveBeenCalled();
870
+ expect(input).toHaveAttribute('aria-expanded', 'false');
871
+ });
872
+
873
+ it('searches on the first character when minQueryLength is not set', async () => {
874
+ const search = vi.fn(() => fruits.slice(0, 1));
875
+ render(
876
+ <BaseTypeahead
877
+ searchSource={{search, bootstrap: () => []}}
878
+ value={null}
879
+ onChange={() => {}}
880
+ debounceMs={0}
881
+ />,
882
+ );
883
+ const input = screen.getByRole('combobox');
884
+
885
+ fireEvent.change(input, {target: {value: 'A'}});
886
+ await waitFor(() => {
887
+ expect(input).toHaveAttribute('aria-expanded', 'true');
888
+ });
889
+ expect(search).toHaveBeenCalledExactlyOnceWith('A');
890
+ });
891
+
892
+ it('stops reporting "Loading" when the query falls below the threshold mid-search', async () => {
893
+ // Falling below the threshold abandons the in-flight search by bumping the
894
+ // search generation, which also makes that search decline to clear the
895
+ // loading flag on its way out. Backspacing from three characters to two on
896
+ // a remote source is the everyday way to hit it, and the field would
897
+ // otherwise report "Loading" to a screen reader until the third character
898
+ // went back in.
899
+ let settle: (items: SearchableItem[]) => void = () => {};
900
+ const search = vi.fn(
901
+ async () =>
902
+ new Promise<SearchableItem[]>(resolve => {
903
+ settle = resolve;
904
+ }),
905
+ );
906
+ render(
907
+ <BaseTypeahead
908
+ searchSource={{search, bootstrap: () => []}}
909
+ value={null}
910
+ onChange={() => {}}
911
+ minQueryLength={3}
912
+ debounceMs={0}
913
+ />,
914
+ );
915
+ const input = screen.getByRole('combobox');
916
+
917
+ fireEvent.change(input, {target: {value: 'App'}});
918
+ await waitFor(() => {
919
+ expect(screen.getByRole('status', {name: 'Loading'})).toBeInTheDocument();
920
+ });
921
+
922
+ fireEvent.change(input, {target: {value: 'Ap'}});
923
+ await act(async () => {
924
+ settle(fruits.slice(0, 1));
925
+ await Promise.resolve();
926
+ });
927
+
928
+ expect(
929
+ screen.queryByRole('status', {name: 'Loading'}),
930
+ ).not.toBeInTheDocument();
931
+ expect(input).toHaveAttribute('aria-expanded', 'false');
932
+ });
933
+ });
934
+
781
935
  describe('BaseTypeahead hasSearched reset', () => {
782
936
  it('does not show "No results found" after selecting an item and re-entering', async () => {
783
937
  const onChange = vi.fn();
@@ -111,6 +111,13 @@ export interface TypeaheadProps<T extends SearchableItem> extends Omit<
111
111
  hasEntriesOnFocus?: boolean;
112
112
  /** Max dropdown items. @default 10 */
113
113
  maxMenuItems?: number;
114
+ /**
115
+ * Minimum query length before the search source is queried. Below it no
116
+ * search runs and the menu stays closed — useful for remote sources where
117
+ * one or two characters match too much to be worth fetching.
118
+ * @default 1
119
+ */
120
+ minQueryLength?: number;
114
121
  /** Text shown when no results found. @default 'No results found' */
115
122
  emptySearchResultsText?: string;
116
123
  /** Whether the input is disabled. @default false */
@@ -248,6 +255,7 @@ export function Typeahead<T extends SearchableItem>({
248
255
  placeholder,
249
256
  hasEntriesOnFocus,
250
257
  maxMenuItems,
258
+ minQueryLength,
251
259
  emptySearchResultsText,
252
260
  isDisabled = false,
253
261
  disabledMessage,
@@ -467,6 +475,7 @@ export function Typeahead<T extends SearchableItem>({
467
475
  placeholder={showToken ? undefined : placeholder}
468
476
  hasEntriesOnFocus={hasEntriesOnFocus}
469
477
  maxMenuItems={maxMenuItems}
478
+ minQueryLength={minQueryLength}
470
479
  emptySearchResultsText={emptySearchResultsText}
471
480
  isDisabled={isDisabled}
472
481
  hasAutoFocus={hasAutoFocus}
@@ -0,0 +1,43 @@
1
+ // Copyright (c) Meta Platforms, Inc. and affiliates.
2
+
3
+ /**
4
+ * @file TypeaheadItem.test.tsx
5
+ * @input Uses vitest, @testing-library/react, TypeaheadItem
6
+ * @output Unit tests for TypeaheadItem
7
+ * @position Testing; validates TypeaheadItem.tsx implementation
8
+ */
9
+
10
+ import {describe, it, expect} from 'vitest';
11
+ import {render, screen} from '@testing-library/react';
12
+ import {TypeaheadItem} from './TypeaheadItem';
13
+
14
+ describe('TypeaheadItem', () => {
15
+ it('forwards pass-through props to the item element', () => {
16
+ render(
17
+ <TypeaheadItem
18
+ item={{id: '1', label: 'Alice'}}
19
+ aria-label="Alice, engineer"
20
+ id="result-1"
21
+ data-source="directory"
22
+ data-testid="item"
23
+ />,
24
+ );
25
+ const item = screen.getByTestId('item');
26
+ expect(item).toHaveAttribute('aria-label', 'Alice, engineer');
27
+ expect(item).toHaveAttribute('id', 'result-1');
28
+ expect(item).toHaveAttribute('data-source', 'directory');
29
+ });
30
+
31
+ it('merges a caller className with its own classes', () => {
32
+ render(
33
+ <TypeaheadItem
34
+ item={{id: '1', label: 'Alice'}}
35
+ className="caller-class"
36
+ data-testid="item"
37
+ />,
38
+ );
39
+ const item = screen.getByTestId('item');
40
+ expect(item.className).toContain('caller-class');
41
+ expect(item.className).toContain('astryx-typeahead-item');
42
+ });
43
+ });
@@ -132,7 +132,11 @@ export function TypeaheadItem<T extends SearchableItem>({
132
132
  icon,
133
133
  description,
134
134
  isDisabled = false,
135
+ group: _group,
135
136
  xstyle,
137
+ className,
138
+ style,
139
+ ...rest
136
140
  }: TypeaheadItemProps<T>) {
137
141
  // If item has a pre-rendered element, use it
138
142
  if (item.element) {
@@ -145,7 +149,10 @@ export function TypeaheadItem<T extends SearchableItem>({
145
149
  {...mergeProps(
146
150
  themeProps('typeahead-item'),
147
151
  stylex.props(styles.container, isDisabled && styles.disabled, xstyle),
148
- )}>
152
+ className,
153
+ style,
154
+ )}
155
+ {...rest}>
149
156
  {icon}
150
157
  <div {...stylex.props(styles.content)}>
151
158
  <span {...stylex.props(styles.label)}>{item.label}</span>
@@ -0,0 +1,96 @@
1
+ // Copyright (c) Meta Platforms, Inc. and affiliates.
2
+
3
+ /** @type {import('@astryxdesign/cli/authoring').HookDoc} */
4
+ export const docs = {
5
+ name: 'useAnnounce',
6
+ displayName: 'useAnnounce',
7
+ keywords: [
8
+ 'announce',
9
+ 'live region',
10
+ 'aria-live',
11
+ 'screen reader',
12
+ 'accessibility',
13
+ 'a11y',
14
+ 'status',
15
+ 'alert',
16
+ 'polite',
17
+ 'assertive',
18
+ 'visually hidden',
19
+ 'wcag',
20
+ ],
21
+ params: [],
22
+ returns: [
23
+ {
24
+ name: 'announce',
25
+ type: '(message: string, politeness?: "polite" | "assertive") => void',
26
+ description:
27
+ 'Speaks a message through the shared live region. Politeness defaults to "polite"; an empty message clears any lingering status instead of announcing.',
28
+ },
29
+ ],
30
+ usage: {
31
+ description:
32
+ 'Imperatively announces a message to screen readers through a visually-hidden live region. Use it for state that is only conveyed visually; search result counts, "no results", loading and saved confirmations, validation errors (WCAG 4.1.3 Status Messages). The polite and assertive regions are created empty on first use and stay mounted, which is what makes announcements reliable: most screen readers ignore a live region that is inserted together with its content. Each message is cleared a couple of seconds after it is announced so stale status does not linger in the accessibility tree.',
33
+ bestPractices: [
34
+ {
35
+ guidance: true,
36
+ description:
37
+ 'Reach for this instead of hand-rolling an aria-live div; a region rendered with its content usually does not announce at all.',
38
+ },
39
+ {
40
+ guidance: true,
41
+ description:
42
+ 'Keep "polite" for status and result counts; reserve "assertive" for errors and time-sensitive alerts, since it interrupts whatever the screen reader is saying.',
43
+ },
44
+ {
45
+ guidance: true,
46
+ description:
47
+ 'Announce the outcome, not the interaction; "12 results" rather than "search ran".',
48
+ },
49
+ {
50
+ guidance: false,
51
+ description:
52
+ 'Announce content that is already visible and correctly labeled in the DOM; that doubles up for screen reader users.',
53
+ },
54
+ ],
55
+ },
56
+ relatedComponents: ['VisuallyHidden', 'Toast'],
57
+ relatedHooks: ['useClipboard'],
58
+ importPath: '@astryxdesign/core/hooks',
59
+ category: 'accessibility',
60
+ };
61
+
62
+ /** @type {import('@astryxdesign/cli/authoring').HookTranslationDoc} */
63
+ export const docsDense = {
64
+ description:
65
+ 'Imperative screen-reader announcements via a visually-hidden live region. Polite + assertive regions created empty on first use + kept mounted, so announcements are reliable (most AT ignore a live region inserted together w/ its content). Messages auto-clear after ~2s.',
66
+ returnDescriptions: {
67
+ announce:
68
+ 'speaks message through shared live region. politeness defaults "polite"; empty message clears lingering status.',
69
+ },
70
+ usage: {
71
+ description:
72
+ 'Announces visual-only state to screen readers: result counts, "no results", loading / saved confirmations, validation errors (WCAG 4.1.3). Regions mounted empty up front, so updates announce; text auto-clears so stale status does not linger in a11y tree.',
73
+ bestPractices: [
74
+ {
75
+ guidance: true,
76
+ description:
77
+ 'Use instead of hand-rolled aria-live div; region rendered w/ its content usually does not announce.',
78
+ },
79
+ {
80
+ guidance: true,
81
+ description:
82
+ '"polite" for status / counts; "assertive" only for errors + time-sensitive alerts (it interrupts).',
83
+ },
84
+ {
85
+ guidance: true,
86
+ description:
87
+ 'Announce outcome, not interaction; "12 results", not "search ran".',
88
+ },
89
+ {
90
+ guidance: false,
91
+ description:
92
+ 'Announce content already visible + labeled in DOM; doubles up for AT users.',
93
+ },
94
+ ],
95
+ },
96
+ };
@@ -0,0 +1,96 @@
1
+ // Copyright (c) Meta Platforms, Inc. and affiliates.
2
+
3
+ /** @type {import('@astryxdesign/cli/authoring').HookDoc} */
4
+ export const docs = {
5
+ name: 'useDevWarning',
6
+ displayName: 'useDevWarning',
7
+ keywords: [
8
+ 'warning',
9
+ 'dev',
10
+ 'development',
11
+ 'console',
12
+ 'guardrail',
13
+ 'misuse',
14
+ 'invariant',
15
+ 'debug',
16
+ 'devWarn',
17
+ ],
18
+ params: [
19
+ {
20
+ name: 'component',
21
+ type: 'string',
22
+ description: 'Component or hook name, used as the message prefix.',
23
+ required: true,
24
+ },
25
+ {
26
+ name: 'message',
27
+ type: 'string',
28
+ description: 'What went wrong and how to fix it.',
29
+ required: true,
30
+ },
31
+ {
32
+ name: 'condition',
33
+ type: 'boolean',
34
+ description: 'Whether to warn.',
35
+ default: 'true',
36
+ },
37
+ ],
38
+ returns: [],
39
+ usage: {
40
+ description:
41
+ 'Fires a dev-only "Component: message" console warning once per mount while the condition holds. It is the render-safe way for a component to flag misuse: warning straight from the render body repeats on every render, and gating it with state adds a re-render, so this uses a ref and an effect instead. For a warning outside a component, use the imperative devWarn utility.',
42
+ bestPractices: [
43
+ {
44
+ guidance: true,
45
+ description:
46
+ 'Say what is wrong and what the builder should do instead; the message is the whole value of the warning.',
47
+ },
48
+ {
49
+ guidance: true,
50
+ description:
51
+ 'Warn about combinations the types cannot express, such as two mutually exclusive props being set together.',
52
+ },
53
+ {
54
+ guidance: false,
55
+ description:
56
+ 'Use it for anything a user could see or for runtime error handling; it is stripped from production builds.',
57
+ },
58
+ ],
59
+ },
60
+ relatedComponents: [],
61
+ relatedHooks: [],
62
+ importPath: '@astryxdesign/core/hooks',
63
+ category: 'utility',
64
+ };
65
+
66
+ /** @type {import('@astryxdesign/cli/authoring').HookTranslationDoc} */
67
+ export const docsDense = {
68
+ description:
69
+ 'Dev-only "Component: message" console warning, once per mount while condition holds. Ref + effect, so it never repeats per render nor causes a re-render. Outside a component, use the imperative devWarn utility.',
70
+ paramDescriptions: {
71
+ component: 'component / hook name, used as message prefix.',
72
+ message: 'what went wrong + how to fix it.',
73
+ condition: 'whether to warn.',
74
+ },
75
+ usage: {
76
+ description:
77
+ 'Render-safe guardrail warning from inside a component. Stripped from production builds.',
78
+ bestPractices: [
79
+ {
80
+ guidance: true,
81
+ description:
82
+ 'Say what is wrong + what to do instead; the message is the value.',
83
+ },
84
+ {
85
+ guidance: true,
86
+ description:
87
+ 'Warn about combinations types cannot express (mutually exclusive props set together).',
88
+ },
89
+ {
90
+ guidance: false,
91
+ description:
92
+ 'Use for user-visible problems / runtime error handling; it is dev-only.',
93
+ },
94
+ ],
95
+ },
96
+ };
@@ -67,24 +67,6 @@ describe('useHotkeys', () => {
67
67
  expect(onPress).toHaveBeenCalledTimes(1);
68
68
  });
69
69
 
70
- it('reads a blank userAgentData.platform as unknown, not as non-Apple', () => {
71
- // Builds that rewrite their client-hints identity expose the key with an
72
- // empty value; navigator.platform is the only surface left that answers.
73
- vi.stubGlobal('navigator', {
74
- userAgentData: {platform: ''},
75
- platform: 'MacIntel',
76
- });
77
- const onPress = vi.fn();
78
- renderHook(() => useHotkeys([{keys: 'mod+k', onPress}]));
79
-
80
- press('k', {ctrlKey: true});
81
- expect(onPress).not.toHaveBeenCalled();
82
-
83
- const event = press('k', {metaKey: true});
84
- expect(onPress).toHaveBeenCalledTimes(1);
85
- expect(onPress).toHaveBeenCalledWith(event);
86
- });
87
-
88
70
  it('does not fire a bare key when modifiers are held', () => {
89
71
  stubApplePlatform();
90
72
  const onPress = vi.fn();