@astryxdesign/core 0.7.7 → 0.7.8-canary.30b1896

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 (540) hide show
  1. package/dist/AlertDialog/AlertDialog.d.ts +4 -1
  2. package/dist/AlertDialog/AlertDialog.d.ts.map +1 -1
  3. package/dist/AlertDialog/AlertDialog.js +46 -6
  4. package/dist/AppShell/AppShell.d.ts.map +1 -1
  5. package/dist/AppShell/AppShell.js +5 -0
  6. package/dist/BottomSheet/BottomSheet.d.ts.map +1 -1
  7. package/dist/BottomSheet/BottomSheet.js +1 -0
  8. package/dist/BottomSheet/BottomSheetPanel.d.ts.map +1 -1
  9. package/dist/BottomSheet/BottomSheetPanel.js +25 -4
  10. package/dist/BottomSheet/BottomSheetSwitcher.d.ts.map +1 -1
  11. package/dist/BottomSheet/BottomSheetSwitcher.js +5 -0
  12. package/dist/BottomSheet/useMobileKeyboard.d.ts.map +1 -1
  13. package/dist/BottomSheet/useMobileKeyboard.js +6 -0
  14. package/dist/BottomSheet/useSheetGestures.d.ts.map +1 -1
  15. package/dist/BottomSheet/useSheetGestures.js +12 -1
  16. package/dist/Button/Button.d.ts.map +1 -1
  17. package/dist/Button/Button.js +17 -1
  18. package/dist/Calendar/Calendar.d.ts.map +1 -1
  19. package/dist/Calendar/Calendar.js +15 -16
  20. package/dist/Carousel/Carousel.d.ts.map +1 -1
  21. package/dist/Carousel/Carousel.js +2 -0
  22. package/dist/Chat/ChatComposerInput.d.ts.map +1 -1
  23. package/dist/Chat/ChatComposerInput.js +4 -0
  24. package/dist/Chat/ChatMessageList.d.ts.map +1 -1
  25. package/dist/Chat/ChatMessageList.js +2 -1
  26. package/dist/Chat/useChatDictation.d.ts.map +1 -1
  27. package/dist/Chat/useChatDictation.js +2 -0
  28. package/dist/Chat/useChatNewMessages.js +1 -1
  29. package/dist/Chat/useChatStreamScroll.d.ts.map +1 -1
  30. package/dist/Chat/useChatStreamScroll.js +2 -0
  31. package/dist/Chat/useSpeechRecognition.d.ts.map +1 -1
  32. package/dist/Chat/useSpeechRecognition.js +3 -0
  33. package/dist/Chat/useTriggerMenu.js +1 -1
  34. package/dist/CheckboxInput/CheckboxInput.d.ts.map +1 -1
  35. package/dist/CheckboxInput/CheckboxInput.js +17 -12
  36. package/dist/CodeBlock/CodeBlock.d.ts +10 -1
  37. package/dist/CodeBlock/CodeBlock.d.ts.map +1 -1
  38. package/dist/CodeBlock/CodeBlock.js +28 -11
  39. package/dist/CommandPalette/CommandPalette.d.ts.map +1 -1
  40. package/dist/CommandPalette/CommandPalette.js +2 -0
  41. package/dist/CommandPalette/CommandPaletteItem.d.ts.map +1 -1
  42. package/dist/CommandPalette/CommandPaletteItem.js +2 -0
  43. package/dist/ComplexSelector/ComplexSelector.d.ts +4 -1
  44. package/dist/ComplexSelector/ComplexSelector.d.ts.map +1 -1
  45. package/dist/ComplexSelector/ComplexSelector.js +14 -4
  46. package/dist/ContextMenu/ContextMenu.js +2 -2
  47. package/dist/DateInput/MonthScroller.d.ts.map +1 -1
  48. package/dist/DateInput/MonthScroller.js +5 -2
  49. package/dist/DateInput/TouchDateField.d.ts.map +1 -1
  50. package/dist/DateInput/TouchDateField.js +1 -0
  51. package/dist/DateInput/Wheel.d.ts.map +1 -1
  52. package/dist/DateInput/Wheel.js +4 -0
  53. package/dist/DateInput/useOwnScrollGesture.d.ts.map +1 -1
  54. package/dist/DateInput/useOwnScrollGesture.js +3 -0
  55. package/dist/DateInput/usePointerDragScroll.d.ts.map +1 -1
  56. package/dist/DateInput/usePointerDragScroll.js +2 -0
  57. package/dist/DateInput/useScrollSettle.d.ts.map +1 -1
  58. package/dist/DateInput/useScrollSettle.js +3 -0
  59. package/dist/Dialog/Dialog.d.ts.map +1 -1
  60. package/dist/Dialog/Dialog.js +9 -32
  61. package/dist/Drawer/useDrawerDialogPresence.d.ts.map +1 -1
  62. package/dist/Drawer/useDrawerDialogPresence.js +3 -0
  63. package/dist/DropdownMenu/useMenuOverflow.d.ts.map +1 -1
  64. package/dist/DropdownMenu/useMenuOverflow.js +5 -0
  65. package/dist/Field/Field.js +2 -2
  66. package/dist/FieldStatus/useFieldStatusAnnouncement.d.ts.map +1 -1
  67. package/dist/FieldStatus/useFieldStatusAnnouncement.js +1 -0
  68. package/dist/FormLayout/FormLayout.d.ts +5 -1
  69. package/dist/FormLayout/FormLayout.d.ts.map +1 -1
  70. package/dist/HoverCard/HoverCard.d.ts +6 -4
  71. package/dist/HoverCard/HoverCard.d.ts.map +1 -1
  72. package/dist/HoverCard/HoverCard.js +48 -3
  73. package/dist/HoverCard/useHoverCard.d.ts +5 -4
  74. package/dist/HoverCard/useHoverCard.d.ts.map +1 -1
  75. package/dist/HoverCard/useHoverCard.js +20 -33
  76. package/dist/Icon/Icon.d.ts +5 -1
  77. package/dist/Icon/Icon.d.ts.map +1 -1
  78. package/dist/Icon/Icon.js +5 -2
  79. package/dist/Item/useSwipeAction.d.ts.map +1 -1
  80. package/dist/Item/useSwipeAction.js +3 -0
  81. package/dist/Layer/modalOutlet.d.ts.map +1 -1
  82. package/dist/Layer/modalOutlet.js +2 -0
  83. package/dist/Layer/outsidePress.d.ts.map +1 -1
  84. package/dist/Layer/outsidePress.js +1 -0
  85. package/dist/Layer/useLayer.d.ts.map +1 -1
  86. package/dist/Layer/useLayer.js +3 -0
  87. package/dist/Layer/useLayerDismissal.d.ts.map +1 -1
  88. package/dist/Layer/useLayerDismissal.js +3 -0
  89. package/dist/Layer/usePressPin.d.ts +17 -5
  90. package/dist/Layer/usePressPin.d.ts.map +1 -1
  91. package/dist/Layer/usePressPin.js +62 -12
  92. package/dist/Layer/useTouchTrigger.d.ts.map +1 -1
  93. package/dist/Layer/useTouchTrigger.js +3 -0
  94. package/dist/Lightbox/Lightbox.d.ts.map +1 -1
  95. package/dist/Lightbox/Lightbox.js +19 -0
  96. package/dist/MobileNav/MobileNav.d.ts +3 -2
  97. package/dist/MobileNav/MobileNav.d.ts.map +1 -1
  98. package/dist/MobileNav/MobileNav.js +9 -25
  99. package/dist/Outline/useOutlineFromDOM.d.ts.map +1 -1
  100. package/dist/Outline/useOutlineFromDOM.js +3 -0
  101. package/dist/Outline/useScrollSpy.d.ts.map +1 -1
  102. package/dist/Outline/useScrollSpy.js +3 -0
  103. package/dist/OverflowList/OverflowList.d.ts.map +1 -1
  104. package/dist/OverflowList/OverflowList.js +3 -0
  105. package/dist/Popover/Popover.d.ts.map +1 -1
  106. package/dist/Popover/Popover.js +6 -0
  107. package/dist/PowerSearch/PowerSearch.d.ts +43 -4
  108. package/dist/PowerSearch/PowerSearch.d.ts.map +1 -1
  109. package/dist/PowerSearch/PowerSearch.js +445 -134
  110. package/dist/PowerSearch/PowerSearchBottomSheet.d.ts +102 -0
  111. package/dist/PowerSearch/PowerSearchBottomSheet.d.ts.map +1 -0
  112. package/dist/PowerSearch/PowerSearchBottomSheet.js +1919 -0
  113. package/dist/PowerSearch/PowerSearchEditPopover.d.ts +35 -2
  114. package/dist/PowerSearch/PowerSearchEditPopover.d.ts.map +1 -1
  115. package/dist/PowerSearch/PowerSearchEditPopover.js +25 -6
  116. package/dist/PowerSearch/PowerSearchFilterEditor.d.ts +1 -1
  117. package/dist/PowerSearch/PowerSearchFilterEditor.d.ts.map +1 -1
  118. package/dist/PowerSearch/PowerSearchFilterEditor.js +4 -2
  119. package/dist/PowerSearch/PowerSearchToken.d.ts +1 -1
  120. package/dist/PowerSearch/PowerSearchToken.d.ts.map +1 -1
  121. package/dist/PowerSearch/PowerSearchToken.js +7 -2
  122. package/dist/PowerSearch/PowerSearchValueEditor.d.ts +38 -3
  123. package/dist/PowerSearch/PowerSearchValueEditor.d.ts.map +1 -1
  124. package/dist/PowerSearch/PowerSearchValueEditor.js +193 -83
  125. package/dist/PowerSearch/formatFilterValue.d.ts +18 -6
  126. package/dist/PowerSearch/formatFilterValue.d.ts.map +1 -1
  127. package/dist/PowerSearch/formatFilterValue.js +33 -12
  128. package/dist/PowerSearch/formatTokenValue.d.ts +28 -0
  129. package/dist/PowerSearch/formatTokenValue.d.ts.map +1 -0
  130. package/dist/PowerSearch/formatTokenValue.js +162 -0
  131. package/dist/PowerSearch/powerSearchDateZone.d.ts +21 -0
  132. package/dist/PowerSearch/powerSearchDateZone.d.ts.map +1 -0
  133. package/dist/PowerSearch/powerSearchDateZone.js +37 -0
  134. package/dist/PowerSearch/powerSearchSheetUtils.d.ts +65 -0
  135. package/dist/PowerSearch/powerSearchSheetUtils.d.ts.map +1 -0
  136. package/dist/PowerSearch/powerSearchSheetUtils.js +168 -0
  137. package/dist/PowerSearch/types.d.ts +2 -0
  138. package/dist/PowerSearch/types.d.ts.map +1 -1
  139. package/dist/ProgressBar/ProgressBarTouch.d.ts.map +1 -1
  140. package/dist/ProgressBar/ProgressBarTouch.js +2 -0
  141. package/dist/RadioList/RadioList.d.ts.map +1 -1
  142. package/dist/RadioList/RadioList.js +3 -2
  143. package/dist/RadioList/RadioListItem.d.ts +1 -1
  144. package/dist/RadioList/RadioListItem.d.ts.map +1 -1
  145. package/dist/RadioList/RadioListItem.js +5 -3
  146. package/dist/Resizable/ResizeHandle.d.ts +2 -1
  147. package/dist/Resizable/ResizeHandle.d.ts.map +1 -1
  148. package/dist/Resizable/ResizeHandle.js +101 -77
  149. package/dist/Resizable/createResizable.d.ts +145 -0
  150. package/dist/Resizable/createResizable.d.ts.map +1 -0
  151. package/dist/Resizable/createResizable.js +575 -0
  152. package/dist/Resizable/useResizable.d.ts +3 -3
  153. package/dist/Resizable/useResizable.d.ts.map +1 -1
  154. package/dist/Resizable/useResizable.js +252 -459
  155. package/dist/SegmentedControl/useSegmentedSelectionMotion.d.ts.map +1 -1
  156. package/dist/SegmentedControl/useSegmentedSelectionMotion.js +3 -3
  157. package/dist/SelectableCard/SelectableCard.d.ts +2 -0
  158. package/dist/SelectableCard/SelectableCard.d.ts.map +1 -1
  159. package/dist/SelectableCard/SelectableCard.js +36 -11
  160. package/dist/SelectableCard/selectableCardInput.d.ts +12 -0
  161. package/dist/SelectableCard/selectableCardInput.d.ts.map +1 -0
  162. package/dist/SelectableCard/selectableCardInput.js +20 -0
  163. package/dist/Selector/Selector.d.ts.map +1 -1
  164. package/dist/Selector/Selector.js +5 -8
  165. package/dist/Slider/sliderTouchController.js +2 -2
  166. package/dist/Spinner/Spinner.d.ts +1 -1
  167. package/dist/Spinner/Spinner.d.ts.map +1 -1
  168. package/dist/Spinner/Spinner.js +60 -58
  169. package/dist/Switch/Switch.d.ts.map +1 -1
  170. package/dist/Switch/Switch.js +4 -10
  171. package/dist/Switch/useSwitchTouch.js +4 -4
  172. package/dist/Table/BaseTable.d.ts.map +1 -1
  173. package/dist/Table/BaseTable.js +29 -8
  174. package/dist/Table/plugins/columnResize/useTableColumnResize.d.ts.map +1 -1
  175. package/dist/Table/plugins/columnResize/useTableColumnResize.js +3 -1
  176. package/dist/Table/plugins/filtering/useTableFiltering.d.ts.map +1 -1
  177. package/dist/Table/plugins/filtering/useTableFiltering.js +2 -1
  178. package/dist/Table/plugins/rowExpansion/useTableRowExpansion.d.ts.map +1 -1
  179. package/dist/Table/plugins/rowExpansion/useTableRowExpansion.js +4 -0
  180. package/dist/Table/plugins/stickyColumns/useTableStickyColumns.d.ts.map +1 -1
  181. package/dist/Table/plugins/stickyColumns/useTableStickyColumns.js +2 -0
  182. package/dist/TextInput/TextInput.d.ts +2 -2
  183. package/dist/TextInput/TextInput.d.ts.map +1 -1
  184. package/dist/TextInput/TextInput.js +10 -7
  185. package/dist/TimeInput/TimeInput.d.ts.map +1 -1
  186. package/dist/TimeInput/TimeInput.js +2 -0
  187. package/dist/Timer/Timer.d.ts.map +1 -1
  188. package/dist/Timer/Timer.js +2 -0
  189. package/dist/Timestamp/Timestamp.js +1 -1
  190. package/dist/Toast/Toast.d.ts +11 -1
  191. package/dist/Toast/Toast.d.ts.map +1 -1
  192. package/dist/Toast/Toast.js +25 -15
  193. package/dist/Toast/ToastViewport.d.ts.map +1 -1
  194. package/dist/Toast/ToastViewport.js +97 -34
  195. package/dist/Toast/types.d.ts +9 -3
  196. package/dist/Toast/types.d.ts.map +1 -1
  197. package/dist/Toast/useToast.d.ts.map +1 -1
  198. package/dist/Toast/useToast.js +1 -0
  199. package/dist/Tokenizer/Tokenizer.d.ts +49 -37
  200. package/dist/Tokenizer/Tokenizer.d.ts.map +1 -1
  201. package/dist/Tokenizer/Tokenizer.js +22 -19
  202. package/dist/Tokenizer/TokenizerBottomSheet.d.ts +1 -1
  203. package/dist/Tokenizer/TokenizerBottomSheet.js +1 -1
  204. package/dist/Tokenizer/index.d.ts +1 -1
  205. package/dist/Tokenizer/index.d.ts.map +1 -1
  206. package/dist/Tooltip/useTooltip.d.ts +19 -1
  207. package/dist/Tooltip/useTooltip.d.ts.map +1 -1
  208. package/dist/Tooltip/useTooltip.js +34 -53
  209. package/dist/Typeahead/BaseTypeahead.d.ts.map +1 -1
  210. package/dist/Typeahead/BaseTypeahead.js +27 -18
  211. package/dist/Typeahead/TypeaheadItem.d.ts +2 -1
  212. package/dist/Typeahead/TypeaheadItem.d.ts.map +1 -1
  213. package/dist/animator/createAnimator.d.ts +98 -0
  214. package/dist/animator/createAnimator.d.ts.map +1 -0
  215. package/dist/animator/createAnimator.js +259 -0
  216. package/dist/astryx.css +36 -6
  217. package/dist/gestures/PressTracker.d.ts.map +1 -1
  218. package/dist/gestures/PressTracker.js +4 -3
  219. package/dist/hooks/ModalAnnounceProvider.d.ts.map +1 -1
  220. package/dist/hooks/ModalAnnounceProvider.js +1 -0
  221. package/dist/hooks/actionGroupTracker.d.ts +4 -1
  222. package/dist/hooks/actionGroupTracker.d.ts.map +1 -1
  223. package/dist/hooks/actionGroupTracker.js +13 -3
  224. package/dist/hooks/index.d.ts +1 -0
  225. package/dist/hooks/index.d.ts.map +1 -1
  226. package/dist/hooks/index.js +1 -0
  227. package/dist/hooks/longPressDetector.d.ts +66 -0
  228. package/dist/hooks/longPressDetector.d.ts.map +1 -0
  229. package/dist/hooks/longPressDetector.js +200 -0
  230. package/dist/hooks/pressGroupContext.d.ts +6 -0
  231. package/dist/hooks/pressGroupContext.d.ts.map +1 -0
  232. package/dist/hooks/pressGroupContext.js +20 -0
  233. package/dist/hooks/rootScrollStyles.d.ts +48 -0
  234. package/dist/hooks/rootScrollStyles.d.ts.map +1 -0
  235. package/dist/hooks/rootScrollStyles.js +207 -0
  236. package/dist/hooks/scrollLockTouchGuard.d.ts +13 -0
  237. package/dist/hooks/scrollLockTouchGuard.d.ts.map +1 -0
  238. package/dist/hooks/scrollLockTouchGuard.js +134 -0
  239. package/dist/hooks/scrollbarGutter.d.ts +4 -4
  240. package/dist/hooks/scrollbarGutter.d.ts.map +1 -1
  241. package/dist/hooks/scrollbarGutter.js +36 -23
  242. package/dist/hooks/useActionGroupTracking.d.ts +53 -0
  243. package/dist/hooks/useActionGroupTracking.d.ts.map +1 -0
  244. package/dist/hooks/useActionGroupTracking.js +174 -0
  245. package/dist/hooks/useAnimator.d.ts +41 -0
  246. package/dist/hooks/useAnimator.d.ts.map +1 -0
  247. package/dist/hooks/useAnimator.js +70 -0
  248. package/dist/hooks/useAnnounceRenderedText.d.ts.map +1 -1
  249. package/dist/hooks/useAnnounceRenderedText.js +1 -0
  250. package/dist/hooks/useAttachment.d.ts +1 -1
  251. package/dist/hooks/useAttachment.js +1 -1
  252. package/dist/hooks/useAutoMediaMode.d.ts.map +1 -1
  253. package/dist/hooks/useAutoMediaMode.js +1 -0
  254. package/dist/hooks/useBusyAnnouncement.d.ts.map +1 -1
  255. package/dist/hooks/useBusyAnnouncement.js +2 -0
  256. package/dist/hooks/useDevWarning.d.ts.map +1 -1
  257. package/dist/hooks/useDevWarning.js +2 -0
  258. package/dist/hooks/useFocusTrap.d.ts.map +1 -1
  259. package/dist/hooks/useFocusTrap.js +2 -0
  260. package/dist/hooks/useGridFocus.d.ts +8 -5
  261. package/dist/hooks/useGridFocus.d.ts.map +1 -1
  262. package/dist/hooks/useGridFocus.js +4 -3
  263. package/dist/hooks/useHotkeys.d.ts.map +1 -1
  264. package/dist/hooks/useHotkeys.js +3 -0
  265. package/dist/hooks/useImageMode.d.ts.map +1 -1
  266. package/dist/hooks/useImageMode.js +3 -0
  267. package/dist/hooks/useInputStatusIcon.d.ts +1 -1
  268. package/dist/hooks/useInputStatusIcon.d.ts.map +1 -1
  269. package/dist/hooks/useInputStatusIcon.js +2 -2
  270. package/dist/hooks/useKeyboardHint.js +1 -1
  271. package/dist/hooks/useLongPress.d.ts +8 -9
  272. package/dist/hooks/useLongPress.d.ts.map +1 -1
  273. package/dist/hooks/useLongPress.js +23 -106
  274. package/dist/hooks/useMenuHover.d.ts.map +1 -1
  275. package/dist/hooks/useMenuHover.js +2 -0
  276. package/dist/hooks/useMenuPress.d.ts.map +1 -1
  277. package/dist/hooks/useMenuPress.js +3 -0
  278. package/dist/hooks/useOverflow.d.ts.map +1 -1
  279. package/dist/hooks/useOverflow.js +2 -1
  280. package/dist/hooks/usePressFeedback.d.ts.map +1 -1
  281. package/dist/hooks/usePressFeedback.js +1 -0
  282. package/dist/hooks/useResolvedRequired.d.ts +3 -0
  283. package/dist/hooks/useResolvedRequired.d.ts.map +1 -1
  284. package/dist/hooks/useResolvedRequired.js +3 -0
  285. package/dist/hooks/useScrollLock.d.ts +7 -9
  286. package/dist/hooks/useScrollLock.d.ts.map +1 -1
  287. package/dist/hooks/useScrollLock.js +55 -48
  288. package/dist/hooks/useScrollableArea.d.ts.map +1 -1
  289. package/dist/hooks/useScrollableArea.js +5 -0
  290. package/dist/hooks/useStreamingText.d.ts.map +1 -1
  291. package/dist/hooks/useStreamingText.js +3 -0
  292. package/dist/i18n/generated-english/PowerSearch/PowerSearchBottomSheet.generated.d.ts +8 -0
  293. package/dist/i18n/generated-english/PowerSearch/PowerSearchBottomSheet.generated.d.ts.map +1 -0
  294. package/dist/i18n/generated-english/PowerSearch/PowerSearchBottomSheet.generated.js +42 -0
  295. package/dist/i18n/generated-english/PowerSearch/PowerSearchValueEditor.generated.d.ts.map +1 -1
  296. package/dist/i18n/generated-english/PowerSearch/PowerSearchValueEditor.generated.js +6 -0
  297. package/dist/i18n/generated-english/PowerSearch/formatTokenValue.generated.d.ts +8 -0
  298. package/dist/i18n/generated-english/PowerSearch/formatTokenValue.generated.d.ts.map +1 -0
  299. package/dist/i18n/generated-english/PowerSearch/formatTokenValue.generated.js +14 -0
  300. package/dist/i18n/generated-locales/en.generated.d.ts.map +1 -1
  301. package/dist/i18n/generated-locales/en.generated.js +30 -0
  302. package/dist/i18n/generated-locales/pseudo.generated.d.ts.map +1 -1
  303. package/dist/i18n/generated-locales/pseudo.generated.js +30 -0
  304. package/dist/index.d.ts +1 -0
  305. package/dist/index.d.ts.map +1 -1
  306. package/dist/index.js +4 -0
  307. package/dist/internal/indicatorPress.stylex.d.ts +20 -0
  308. package/dist/internal/indicatorPress.stylex.d.ts.map +1 -0
  309. package/dist/internal/indicatorPress.stylex.js +26 -0
  310. package/dist/internal/selectable-card.d.ts +21 -0
  311. package/dist/internal/selectable-card.d.ts.map +1 -0
  312. package/dist/internal/selectable-card.js +20 -0
  313. package/dist/internal/sheetDraft.d.ts +2 -2
  314. package/dist/internal/sheetDraft.js +2 -2
  315. package/dist/motion/animatedLayout.d.ts.map +1 -1
  316. package/dist/motion/animatedLayout.js +7 -7
  317. package/dist/motion/animator.d.ts +14 -14
  318. package/dist/motion/animator.d.ts.map +1 -1
  319. package/dist/motion/animator.js +45 -20
  320. package/dist/motion/progress.d.ts +88 -0
  321. package/dist/motion/progress.d.ts.map +1 -0
  322. package/dist/motion/progress.js +128 -0
  323. package/dist/motion/reducedMotion.d.ts.map +1 -1
  324. package/dist/motion/reducedMotion.js +3 -1
  325. package/dist/motion/uikit/alert.d.ts +41 -0
  326. package/dist/motion/uikit/alert.d.ts.map +1 -0
  327. package/dist/motion/uikit/alert.js +43 -0
  328. package/dist/privateAttributes/pressGroupItem.stylex.d.ts +22 -0
  329. package/dist/privateAttributes/pressGroupItem.stylex.d.ts.map +1 -0
  330. package/dist/privateAttributes/pressGroupItem.stylex.js +36 -0
  331. package/dist/privateAttributes/reducedMotion.stylex.d.ts +23 -0
  332. package/dist/privateAttributes/reducedMotion.stylex.d.ts.map +1 -0
  333. package/dist/privateAttributes/reducedMotion.stylex.js +40 -0
  334. package/dist/theme/Theme.d.ts.map +1 -1
  335. package/dist/theme/Theme.js +29 -4
  336. package/dist/theme/motionKnobs.d.ts +4 -3
  337. package/dist/theme/motionKnobs.d.ts.map +1 -1
  338. package/dist/theme/motionKnobs.js +3 -2
  339. package/dist/theme/themeMotion.d.ts +6 -0
  340. package/dist/theme/themeMotion.d.ts.map +1 -1
  341. package/dist/theme/themeMotion.js +7 -0
  342. package/dist/utils/dateParser.d.ts.map +1 -1
  343. package/dist/utils/dateParser.js +12 -0
  344. package/dist/utils/focusReturn.d.ts +15 -0
  345. package/dist/utils/focusReturn.d.ts.map +1 -1
  346. package/dist/utils/focusReturn.js +28 -0
  347. package/dist/utils/interactionModality.d.ts.map +1 -1
  348. package/dist/utils/interactionModality.js +4 -0
  349. package/dist/utils/interactionOverlay.stylex.d.ts +3 -2
  350. package/dist/utils/interactionOverlay.stylex.d.ts.map +1 -1
  351. package/dist/utils/interactionOverlay.stylex.js +3 -2
  352. package/dist/utils/plainDate.d.ts +8 -0
  353. package/dist/utils/plainDate.d.ts.map +1 -1
  354. package/dist/utils/plainDate.js +19 -0
  355. package/dist/utils/pressFeedback.d.ts.map +1 -1
  356. package/dist/utils/pressFeedback.js +20 -6
  357. package/dist/utils/triggerFocus.d.ts +36 -0
  358. package/dist/utils/triggerFocus.d.ts.map +1 -0
  359. package/dist/utils/triggerFocus.js +65 -0
  360. package/locales/en.json +120 -0
  361. package/locales/pseudo.json +90 -0
  362. package/package.json +14 -9
  363. package/src/AlertDialog/AlertDialog.doc.mjs +2 -2
  364. package/src/AlertDialog/AlertDialog.tsx +46 -5
  365. package/src/AppShell/AppShell.tsx +4 -0
  366. package/src/BottomSheet/BottomSheet.tsx +1 -0
  367. package/src/BottomSheet/BottomSheetPanel.tsx +39 -3
  368. package/src/BottomSheet/BottomSheetSwitcher.tsx +5 -0
  369. package/src/BottomSheet/useMobileKeyboard.ts +4 -0
  370. package/src/BottomSheet/useSheetGestures.ts +10 -1
  371. package/src/Button/Button.tsx +26 -4
  372. package/src/Calendar/Calendar.tsx +36 -25
  373. package/src/Carousel/Carousel.tsx +1 -0
  374. package/src/Chat/ChatComposerInput.tsx +2 -0
  375. package/src/Chat/ChatMessageList.tsx +2 -1
  376. package/src/Chat/useChatDictation.ts +1 -0
  377. package/src/Chat/useChatNewMessages.ts +1 -1
  378. package/src/Chat/useChatStreamScroll.ts +2 -0
  379. package/src/Chat/useSpeechRecognition.ts +2 -0
  380. package/src/Chat/useTriggerMenu.tsx +1 -1
  381. package/src/CheckboxInput/CheckboxInput.doc.mjs +18 -0
  382. package/src/CheckboxInput/CheckboxInput.tsx +38 -15
  383. package/src/CodeBlock/CodeBlock.doc.mjs +9 -1
  384. package/src/CodeBlock/CodeBlock.tsx +41 -4
  385. package/src/CommandPalette/CommandPalette.tsx +1 -0
  386. package/src/CommandPalette/CommandPaletteItem.tsx +1 -0
  387. package/src/ComplexSelector/ComplexSelector.tsx +20 -5
  388. package/src/ContextMenu/ContextMenu.tsx +2 -2
  389. package/src/DateInput/MonthScroller.tsx +8 -2
  390. package/src/DateInput/TouchDateField.tsx +1 -0
  391. package/src/DateInput/Wheel.tsx +4 -0
  392. package/src/DateInput/useOwnScrollGesture.ts +2 -0
  393. package/src/DateInput/usePointerDragScroll.ts +1 -0
  394. package/src/DateInput/useScrollSettle.ts +2 -0
  395. package/src/Dialog/Dialog.tsx +12 -32
  396. package/src/Drawer/useDrawerDialogPresence.ts +2 -0
  397. package/src/DropdownMenu/useMenuOverflow.ts +3 -0
  398. package/src/Field/Field.tsx +2 -2
  399. package/src/FieldStatus/useFieldStatusAnnouncement.ts +1 -0
  400. package/src/FormLayout/FormLayout.doc.mjs +181 -46
  401. package/src/FormLayout/FormLayout.tsx +5 -1
  402. package/src/HoverCard/HoverCard.doc.mjs +10 -8
  403. package/src/HoverCard/HoverCard.tsx +58 -6
  404. package/src/HoverCard/useHoverCard.doc.mjs +178 -36
  405. package/src/HoverCard/useHoverCard.tsx +49 -54
  406. package/src/Icon/Icon.doc.mjs +49 -8
  407. package/src/Icon/Icon.tsx +15 -7
  408. package/src/IconButton/IconButton.doc.mjs +141 -21
  409. package/src/Item/useSwipeAction.ts +2 -0
  410. package/src/Layer/modalOutlet.ts +2 -0
  411. package/src/Layer/outsidePress.ts +1 -0
  412. package/src/Layer/useLayer.tsx +2 -0
  413. package/src/Layer/useLayerDismissal.ts +2 -0
  414. package/src/Layer/usePressPin.ts +81 -15
  415. package/src/Layer/useTouchTrigger.ts +2 -0
  416. package/src/Lightbox/Lightbox.tsx +19 -0
  417. package/src/MobileNav/MobileNav.tsx +9 -30
  418. package/src/Outline/useOutlineFromDOM.ts +2 -0
  419. package/src/Outline/useScrollSpy.ts +2 -0
  420. package/src/OverflowList/OverflowList.tsx +2 -0
  421. package/src/Popover/Popover.tsx +4 -0
  422. package/src/PowerSearch/PowerSearch.doc.mjs +60 -8
  423. package/src/PowerSearch/PowerSearch.tsx +627 -157
  424. package/src/PowerSearch/PowerSearchBottomSheet.tsx +2525 -0
  425. package/src/PowerSearch/PowerSearchEditPopover.tsx +39 -6
  426. package/src/PowerSearch/PowerSearchFilterEditor.tsx +2 -0
  427. package/src/PowerSearch/PowerSearchToken.tsx +7 -0
  428. package/src/PowerSearch/PowerSearchValueEditor.tsx +244 -58
  429. package/src/PowerSearch/formatFilterValue.ts +55 -17
  430. package/src/PowerSearch/formatTokenValue.ts +222 -0
  431. package/src/PowerSearch/powerSearchDateZone.ts +64 -0
  432. package/src/PowerSearch/powerSearchSheetUtils.ts +224 -0
  433. package/src/PowerSearch/types.ts +2 -0
  434. package/src/ProgressBar/ProgressBarTouch.ts +2 -0
  435. package/src/RadioList/RadioList.tsx +3 -2
  436. package/src/RadioList/RadioListItem.tsx +5 -3
  437. package/src/Resizable/Resizable.doc.mjs +5 -4
  438. package/src/Resizable/ResizeHandle.tsx +169 -109
  439. package/src/Resizable/createResizable.ts +831 -0
  440. package/src/Resizable/useResizable.ts +292 -623
  441. package/src/SegmentedControl/useSegmentedSelectionMotion.ts +6 -3
  442. package/src/SelectableCard/SelectableCard.tsx +39 -10
  443. package/src/SelectableCard/selectableCardInput.ts +30 -0
  444. package/src/Selector/Selector.tsx +5 -12
  445. package/src/Slider/sliderTouchController.ts +2 -2
  446. package/src/Spinner/Spinner.tsx +77 -63
  447. package/src/Switch/Switch.tsx +2 -6
  448. package/src/Switch/useSwitchTouch.ts +4 -4
  449. package/src/Table/BaseTable.tsx +46 -12
  450. package/src/Table/plugins/columnResize/useTableColumnResize.tsx +2 -1
  451. package/src/Table/plugins/filtering/useTableFiltering.tsx +1 -0
  452. package/src/Table/plugins/rowExpansion/useTableRowExpansion.tsx +4 -0
  453. package/src/Table/plugins/stickyColumns/useTableStickyColumns.tsx +2 -0
  454. package/src/TextInput/TextInput.tsx +11 -10
  455. package/src/TimeInput/TimeInput.tsx +2 -0
  456. package/src/Timer/Timer.tsx +1 -0
  457. package/src/Timestamp/Timestamp.tsx +1 -1
  458. package/src/Toast/Toast.doc.mjs +4 -3
  459. package/src/Toast/Toast.tsx +52 -32
  460. package/src/Toast/ToastViewport.tsx +123 -35
  461. package/src/Toast/types.ts +9 -3
  462. package/src/Toast/useToast.tsx +1 -0
  463. package/src/Tokenizer/Tokenizer.doc.mjs +19 -3
  464. package/src/Tokenizer/Tokenizer.tsx +73 -51
  465. package/src/Tokenizer/TokenizerBottomSheet.tsx +1 -1
  466. package/src/Tokenizer/index.ts +1 -0
  467. package/src/Tooltip/useTooltip.doc.mjs +24 -0
  468. package/src/Tooltip/useTooltip.tsx +61 -56
  469. package/src/Typeahead/BaseTypeahead.tsx +27 -17
  470. package/src/Typeahead/TypeaheadItem.doc.mjs +6 -3
  471. package/src/Typeahead/TypeaheadItem.tsx +2 -1
  472. package/src/animator/createAnimator.doc.mjs +153 -0
  473. package/src/animator/createAnimator.ts +324 -0
  474. package/src/gestures/PressTracker.ts +4 -3
  475. package/src/gestures/README.md +10 -4
  476. package/src/hooks/ModalAnnounceProvider.tsx +1 -0
  477. package/src/hooks/actionGroupTracker.ts +20 -5
  478. package/src/hooks/index.ts +2 -0
  479. package/src/hooks/longPressDetector.ts +273 -0
  480. package/src/hooks/pressGroupContext.ts +21 -0
  481. package/src/hooks/rootScrollStyles.ts +247 -0
  482. package/src/hooks/scrollLockTouchGuard.ts +182 -0
  483. package/src/hooks/scrollbarGutter.ts +41 -26
  484. package/src/hooks/useActionGroupTracking.ts +224 -0
  485. package/src/hooks/useAnimator.doc.mjs +109 -0
  486. package/src/hooks/useAnimator.ts +67 -0
  487. package/src/hooks/useAnnounceRenderedText.ts +1 -0
  488. package/src/hooks/useAttachment.ts +1 -1
  489. package/src/hooks/useAutoMediaMode.ts +1 -0
  490. package/src/hooks/useBusyAnnouncement.ts +2 -0
  491. package/src/hooks/useDevWarning.ts +2 -0
  492. package/src/hooks/useFocusTrap.ts +2 -0
  493. package/src/hooks/useGridFocus.doc.mjs +6 -6
  494. package/src/hooks/useGridFocus.ts +10 -7
  495. package/src/hooks/useHotkeys.ts +2 -0
  496. package/src/hooks/useImageMode.ts +2 -0
  497. package/src/hooks/useInputStatusIcon.tsx +3 -2
  498. package/src/hooks/useKeyboardHint.tsx +1 -1
  499. package/src/hooks/useLongPress.doc.mjs +2 -2
  500. package/src/hooks/useLongPress.ts +32 -122
  501. package/src/hooks/useMenuHover.ts +1 -0
  502. package/src/hooks/useMenuPress.ts +2 -0
  503. package/src/hooks/useOverflow.ts +2 -1
  504. package/src/hooks/usePressFeedback.ts +1 -0
  505. package/src/hooks/useResolvedRequired.ts +3 -0
  506. package/src/hooks/useScrollLock.doc.mjs +51 -12
  507. package/src/hooks/useScrollLock.ts +57 -60
  508. package/src/hooks/useScrollableArea.ts +4 -0
  509. package/src/hooks/useStreamingText.ts +2 -0
  510. package/src/i18n/generated-english/PowerSearch/PowerSearchBottomSheet.generated.ts +43 -0
  511. package/src/i18n/generated-english/PowerSearch/PowerSearchValueEditor.generated.ts +6 -0
  512. package/src/i18n/generated-english/PowerSearch/formatTokenValue.generated.ts +15 -0
  513. package/src/i18n/generated-locales/en.generated.ts +41 -0
  514. package/src/i18n/generated-locales/pseudo.generated.ts +42 -0
  515. package/src/index.ts +13 -0
  516. package/src/internal/indicatorPress.stylex.ts +24 -0
  517. package/src/internal/selectable-card.ts +21 -0
  518. package/src/internal/sheetDraft.ts +2 -2
  519. package/src/motion/README.md +9 -5
  520. package/src/motion/animatedLayout.ts +10 -5
  521. package/src/motion/animator.ts +66 -31
  522. package/src/motion/progress.ts +155 -0
  523. package/src/motion/reducedMotion.ts +3 -1
  524. package/src/motion/uikit/alert.ts +43 -0
  525. package/src/privateAttributes/pressGroupItem.stylex.ts +44 -0
  526. package/src/privateAttributes/reducedMotion.stylex.ts +45 -0
  527. package/src/theme/Theme.tsx +37 -3
  528. package/src/theme/motionKnobs.ts +4 -3
  529. package/src/theme/themeMotion.ts +7 -0
  530. package/src/utils/dateParser.ts +16 -0
  531. package/src/utils/focusReturn.ts +30 -0
  532. package/src/utils/interactionModality.ts +4 -0
  533. package/src/utils/interactionOverlay.stylex.ts +3 -2
  534. package/src/utils/plainDate.ts +21 -0
  535. package/src/utils/pressFeedback.ts +24 -6
  536. package/src/utils/triggerFocus.ts +80 -0
  537. package/dist/internal/touch-sheet.d.ts +0 -21
  538. package/dist/internal/touch-sheet.d.ts.map +0 -1
  539. package/dist/internal/touch-sheet.js +0 -19
  540. package/src/internal/touch-sheet.ts +0 -21
@@ -54,7 +54,7 @@ export const docs = {
54
54
  name: 'children',
55
55
  type: 'ReactNode',
56
56
  description:
57
- 'The trigger. A single string or number is wrapped in a focusable inline span. Text that reaches HoverCard in several pieces, such as `Edited {when}`, gets no trigger, so pass one string, such as a template literal, or wrap it in a focusable element. With element children, HoverCard wires the first element, so that element does not need to accept a ref.',
57
+ 'The trigger. Text children, a string or number or text written around an expression such as `Edited {when}`, are wrapped in a focusable inline span; holes such as `false` and `null` are ignored. With element children, HoverCard wires the first element, so that element does not need to accept a ref.',
58
58
  },
59
59
  {
60
60
  name: 'content',
@@ -98,7 +98,8 @@ export const docs = {
98
98
  {
99
99
  name: 'focusTrigger',
100
100
  type: "'auto' | 'always' | 'never'",
101
- description: 'Controls when focus events trigger the hover card.',
101
+ description:
102
+ 'When focus should open the hover card. auto opens when the trigger itself takes focus, or focus lands inside a trigger that is focusable at that moment, so a roving-tabindex member opens when the arrow keys reach it.',
102
103
  default: "'auto'",
103
104
  },
104
105
  {
@@ -130,7 +131,7 @@ export const docs = {
130
131
  name: 'hasHoverIndication',
131
132
  type: "'auto' | boolean",
132
133
  description:
133
- 'Shows a dashed underline on a text trigger. auto shows it when children is a single string or number. It has no effect on an element trigger, which keeps its own styling.',
134
+ 'Shows a dashed underline on a text trigger. auto shows it when children is text: strings and numbers, such as `Edited {when}`, with holes such as `false` and `null` ignored. It has no effect on an element trigger, which keeps its own styling.',
134
135
  default: "'auto'",
135
136
  },
136
137
  {
@@ -266,7 +267,7 @@ export const docsZh = {
266
267
  name: 'children',
267
268
  type: 'ReactNode',
268
269
  description:
269
- '触发元素。单个字符串或数字会被包裹在可聚焦的内联 span 中。分成多段到达的文本(例如 `Edited {when}`)不会得到触发器,请传入单个字符串(例如模板字符串)或用可聚焦元素包裹。传入元素时,HoverCard 连接第一个元素,因此该元素无需接受 ref。',
270
+ '触发元素。文本子元素(字符串或数字,或围绕表达式书写的文本,例如 `Edited {when}`)会被包裹在可聚焦的内联 span 中;`false`、`null` 等空位会被忽略。传入元素时,HoverCard 连接第一个元素,因此该元素无需接受 ref。',
270
271
  },
271
272
  {
272
273
  name: 'content',
@@ -303,7 +304,8 @@ export const docsZh = {
303
304
  {
304
305
  name: 'focusTrigger',
305
306
  type: "'auto' | 'always' | 'never'",
306
- description: '控制焦点事件何时触发悬浮卡片。',
307
+ description:
308
+ '焦点何时打开悬浮卡片。auto 在触发元素自身获得焦点,或焦点落在当时可聚焦的触发元素内部时打开,因此方向键到达漫游 tabindex 成员时也会打开。',
307
309
  default: "'auto'",
308
310
  },
309
311
  {
@@ -335,7 +337,7 @@ export const docsZh = {
335
337
  name: 'hasHoverIndication',
336
338
  type: "'auto' | boolean",
337
339
  description:
338
- '在文本触发元素上显示虚线下划线。auto:当 children 是单个字符串或数字时显示。对元素触发器无效,元素保留自身样式。',
340
+ '在文本触发元素上显示虚线下划线。auto:当 children 是文本(字符串和数字,例如 `Edited {when}`,忽略 `false`、`null` 等空位)时显示。对元素触发器无效,元素保留自身样式。',
339
341
  default: "'auto'",
340
342
  },
341
343
  {
@@ -474,7 +476,7 @@ export const docsDense = {
474
476
  'Component wrapper for hover card overlay; richer overlay triggered on hover/focus.',
475
477
  propDescriptions: {
476
478
  children:
477
- 'Trigger. A single string/number is wrapped in a focusable inline span; text in several pieces (`Edited {when}`) gets no trigger; pass one string or a focusable element. With elements, the first element is wired (no ref needed).',
479
+ 'Trigger. Text children (strings/numbers, incl. `Edited {when}`; holes like false/null ignored) are wrapped in a focusable inline span. With elements, the first element is wired (no ref needed).',
478
480
  content: 'Hover card content.',
479
481
  placement:
480
482
  "Position relative to anchor element. Logical: start/end follow the popover's inherited direction (RTL mirrors).",
@@ -491,7 +493,7 @@ export const docsDense = {
491
493
  onOpenChange:
492
494
  'Callback when visibility changes; true=shown, false=hidden.',
493
495
  hasHoverIndication:
494
- 'Dashed underline on a text trigger. auto = single string/number children; no effect on element triggers.',
496
+ 'Dashed underline on a text trigger. auto = text children (strings/numbers, holes ignored); no effect on element triggers.',
495
497
  isDefaultOpen: 'Show hover card on mount. Still dismissible.',
496
498
  isOpen:
497
499
  'Controlled open state. true holds open; false holds closed against hover, but trigger focus still opens it. Escape calls onOpenChange(false) without closing; setting false returns focus inside the card to the trigger.',
@@ -16,7 +16,15 @@
16
16
  * - /packages/cli/assets/templates/blocks/components/HoverCard/ (showcase blocks)
17
17
  */
18
18
 
19
- import {useCallback, useRef, type ReactElement, type ReactNode} from 'react';
19
+ import {
20
+ useCallback,
21
+ useRef,
22
+ useState,
23
+ type ReactElement,
24
+ type ReactNode,
25
+ } from 'react';
26
+ import {isRenderable} from '../utils/isRenderable';
27
+ import {observeMutations} from '../utils/sharedMutationObserver';
20
28
  import {useIsomorphicLayoutEffect} from '../hooks/useIsomorphicLayoutEffect';
21
29
  import * as stylex from '@stylexjs/stylex';
22
30
  import {
@@ -148,9 +156,10 @@ export interface HoverCardProps extends Pick<
148
156
 
149
157
  /**
150
158
  * When to trigger on focus:
151
- * - `auto`: Only if element is naturally focusable
152
- * - `always`: Always attach focus listeners
153
- * - `never`: Never attach focus listeners (for composite widgets)
159
+ * - `auto`: focus on the trigger itself, or within a trigger that is
160
+ * focusable when focus arrives
161
+ * - `always`: focus on the trigger or anything inside it
162
+ * - `never`: never on focus (for composite widgets)
154
163
  *
155
164
  * @default 'auto'
156
165
  */
@@ -193,7 +202,8 @@ export interface HoverCardProps extends Pick<
193
202
  /**
194
203
  * Whether to show hover indication (dashed underline) on a text trigger.
195
204
  * An element trigger keeps its own styling, so this has no effect on it.
196
- * - `'auto'`: Show when children is a single string or number
205
+ * - `'auto'`: Show when children is text: strings and numbers, such as
206
+ * `Edited {when}`, with holes such as `false` and `null` ignored
197
207
  * - `true`: Show on a text trigger
198
208
  * - `false`: Never show
199
209
  *
@@ -227,7 +237,26 @@ export interface HoverCardProps extends Pick<
227
237
  * Check if children are text-only (no React elements)
228
238
  */
229
239
  function isTextOnly(children: ReactNode): boolean {
230
- return typeof children === 'string' || typeof children === 'number';
240
+ if (typeof children === 'string' || typeof children === 'number') {
241
+ return true;
242
+ }
243
+ // Text written around an expression, such as `Edited {when}`, reaches React
244
+ // as several strings. Holes that render nothing do not change that; one
245
+ // element does.
246
+ if (!Array.isArray(children)) {
247
+ return false;
248
+ }
249
+ let hasText = false;
250
+ for (const child of children.flat(Infinity) as ReactNode[]) {
251
+ if (!isRenderable(child)) {
252
+ continue;
253
+ }
254
+ if (typeof child !== 'string' && typeof child !== 'number') {
255
+ return false;
256
+ }
257
+ hasText = true;
258
+ }
259
+ return hasText;
231
260
  }
232
261
 
233
262
  /**
@@ -303,6 +332,28 @@ export function HoverCard({
303
332
  onHide: handleHide,
304
333
  });
305
334
 
335
+ // The wrapper's first element is the trigger, and it can be replaced after
336
+ // mount: by new children, or by a child component that swaps its own root
337
+ // without a render here. Syncs with the DOM: on a replacement the wiring
338
+ // below re-runs, so the old element is released before the new one is wired.
339
+ const [triggerReplacements, setTriggerReplacements] = useState(0);
340
+ const observedTriggerRef = useRef<Element | null>(null);
341
+ useIsomorphicLayoutEffect(() => {
342
+ const wrapper = wrapperRef.current;
343
+ if (textOnly || wrapper == null) {
344
+ return;
345
+ }
346
+ observedTriggerRef.current = wrapper.firstElementChild;
347
+ return observeMutations(wrapper, {childList: true}, () => {
348
+ const trigger = wrapper.firstElementChild;
349
+ if (trigger === observedTriggerRef.current) {
350
+ return;
351
+ }
352
+ observedTriggerRef.current = trigger;
353
+ setTriggerReplacements(count => count + 1);
354
+ });
355
+ }, [textOnly]);
356
+
306
357
  // For element children with display:contents, attach ref to first child
307
358
  useIsomorphicLayoutEffect(() => {
308
359
  if (textOnly) {
@@ -407,6 +458,7 @@ export function HoverCard({
407
458
  hoverCard.id,
408
459
  hoverCard.isOpen,
409
460
  hoverCard.describedBy,
461
+ triggerReplacements,
410
462
  ]);
411
463
 
412
464
  // While closed, useLayer leaves only an inert <template> marker at this JSX
@@ -5,37 +5,159 @@ export const docs = {
5
5
  name: 'useHoverCard',
6
6
  displayName: 'useHoverCard',
7
7
  group: 'HoverCard',
8
- keywords: ['hovercard', 'hover', 'preview', 'card', 'tooltip', 'popup', 'floating', 'anchor'],
8
+ keywords: [
9
+ 'hovercard',
10
+ 'hover',
11
+ 'preview',
12
+ 'card',
13
+ 'tooltip',
14
+ 'popup',
15
+ 'floating',
16
+ 'anchor',
17
+ ],
9
18
  params: [
10
- {name: 'placement', type: "'above' | 'below' | 'start' | 'end'", description: "Position relative to the trigger. Logical: start/end resolve against the popover\'s own inherited direction (RTL mirrors in pure CSS).", default: "'above'"},
11
- {name: 'alignment', type: "'start' | 'center' | 'end'", description: "Alignment along the placement axis. Logical: start/end resolve against the popover\'s own inherited direction (RTL mirrors in pure CSS).", default: "'center'"},
12
- {name: 'delay', type: 'number', description: 'Delay before showing the hover card on hover, in milliseconds.', default: '300'},
13
- {name: 'hideDelay', type: 'number', description: 'Delay before hiding after mouse or focus leaves, in milliseconds.', default: '200'},
14
- {name: 'focusTrigger', type: "'auto' | 'always' | 'never'", description: 'When focus should open the hover card. auto only attaches focus listeners to naturally focusable elements.', default: "'auto'"},
15
- {name: 'touchTrigger', type: "'auto' | 'tap' | 'none'", description: 'What a tap does where there is no hover. auto opens on tap unless the trigger performs an action of its own (an aria-disabled control performs none); tap always opens; none never opens on touch.', default: "'auto'"},
16
- {name: 'isEnabled', type: 'boolean', description: 'Whether hover and focus triggers are enabled.', default: 'true'},
17
- {name: 'label', type: 'string', description: 'Accessible name for the hover card popup. When provided, the popup is exposed as a named role="dialog"; when omitted, it falls back to role="group" (a group may validly be unnamed).'},
18
- {name: 'isOpen', type: 'boolean', description: 'Controlled open state. true force-shows, false force-hides, undefined lets hover/focus manage visibility.'},
19
- {name: 'isDefaultOpen', type: 'boolean', description: 'Whether the hover card should be shown on mount.', default: 'false'},
20
- {name: 'onShow', type: '() => void', description: 'Callback fired when the hover card becomes visible.'},
21
- {name: 'onHide', type: '() => void', description: 'Callback fired when the hover card is hidden.'},
19
+ {
20
+ name: 'placement',
21
+ type: "'above' | 'below' | 'start' | 'end'",
22
+ description:
23
+ "Position relative to the trigger. Logical: start/end resolve against the popover\'s own inherited direction (RTL mirrors in pure CSS).",
24
+ default: "'above'",
25
+ },
26
+ {
27
+ name: 'alignment',
28
+ type: "'start' | 'center' | 'end'",
29
+ description:
30
+ "Alignment along the placement axis. Logical: start/end resolve against the popover\'s own inherited direction (RTL mirrors in pure CSS).",
31
+ default: "'center'",
32
+ },
33
+ {
34
+ name: 'delay',
35
+ type: 'number',
36
+ description:
37
+ 'Delay before showing the hover card on hover, in milliseconds.',
38
+ default: '300',
39
+ },
40
+ {
41
+ name: 'hideDelay',
42
+ type: 'number',
43
+ description:
44
+ 'Delay before hiding after mouse or focus leaves, in milliseconds.',
45
+ default: '200',
46
+ },
47
+ {
48
+ name: 'focusTrigger',
49
+ type: "'auto' | 'always' | 'never'",
50
+ description:
51
+ 'When focus should open the hover card. auto opens when the trigger itself takes focus, or focus lands inside a trigger that is focusable at that moment, so a roving-tabindex member opens when the arrow keys reach it.',
52
+ default: "'auto'",
53
+ },
54
+ {
55
+ name: 'touchTrigger',
56
+ type: "'auto' | 'tap' | 'none'",
57
+ description:
58
+ 'What a tap does where there is no hover. auto opens on tap unless the trigger performs an action of its own (an aria-disabled control performs none); tap always opens; none never opens on touch.',
59
+ default: "'auto'",
60
+ },
61
+ {
62
+ name: 'isEnabled',
63
+ type: 'boolean',
64
+ description: 'Whether hover and focus triggers are enabled.',
65
+ default: 'true',
66
+ },
67
+ {
68
+ name: 'label',
69
+ type: 'string',
70
+ description:
71
+ 'Accessible name for the hover card popup. When provided, the popup is exposed as a named role="dialog"; when omitted, it falls back to role="group" (a group may validly be unnamed).',
72
+ },
73
+ {
74
+ name: 'isOpen',
75
+ type: 'boolean',
76
+ description:
77
+ 'Controlled open state. true force-shows, false force-hides, undefined lets hover/focus manage visibility.',
78
+ },
79
+ {
80
+ name: 'isDefaultOpen',
81
+ type: 'boolean',
82
+ description: 'Whether the hover card should be shown on mount.',
83
+ default: 'false',
84
+ },
85
+ {
86
+ name: 'onShow',
87
+ type: '() => void',
88
+ description: 'Callback fired when the hover card becomes visible.',
89
+ },
90
+ {
91
+ name: 'onHide',
92
+ type: '() => void',
93
+ description: 'Callback fired when the hover card is hidden.',
94
+ },
22
95
  ],
23
96
  returns: [
24
- {name: 'ref', type: 'RefCallback<HTMLElement>', description: 'Combined ref that sets both position and interaction on the same trigger element.'},
25
- {name: 'positionRef', type: 'RefCallback<HTMLElement>', description: 'Ref for the positioning anchor element. Use when position and interaction live on different elements.'},
26
- {name: 'interactionRef', type: 'RefCallback<HTMLElement>', description: 'Ref for the hover/focus interaction element. Use with positionRef for split trigger patterns.'},
27
- {name: 'anchorId', type: 'string', description: 'CSS anchor name for advanced positioning cases.'},
28
- {name: 'describedBy', type: 'string', description: 'ID to compose into aria-describedby on the trigger.'},
29
- {name: 'renderHoverCard', type: "(children: ReactNode, props?: Omit<ContextRenderProps, 'positioning'>) => ReactNode", description: 'Render function for the anchor-positioned hover card content. The positioning opt-out is excluded: the hover card always derives its position from placement/alignment.'},
30
- {name: 'show', type: '() => void', description: 'Imperatively show the hover card immediately.'},
31
- {name: 'hide', type: '() => void', description: 'Imperatively hide the hover card immediately.'},
97
+ {
98
+ name: 'ref',
99
+ type: 'RefCallback<HTMLElement>',
100
+ description:
101
+ 'Combined ref that sets both position and interaction on the same trigger element.',
102
+ },
103
+ {
104
+ name: 'positionRef',
105
+ type: 'RefCallback<HTMLElement>',
106
+ description:
107
+ 'Ref for the positioning anchor element. Use when position and interaction live on different elements.',
108
+ },
109
+ {
110
+ name: 'interactionRef',
111
+ type: 'RefCallback<HTMLElement>',
112
+ description:
113
+ 'Ref for the hover/focus interaction element. Use with positionRef for split trigger patterns.',
114
+ },
115
+ {
116
+ name: 'anchorId',
117
+ type: 'string',
118
+ description: 'CSS anchor name for advanced positioning cases.',
119
+ },
120
+ {
121
+ name: 'describedBy',
122
+ type: 'string',
123
+ description: 'ID to compose into aria-describedby on the trigger.',
124
+ },
125
+ {
126
+ name: 'renderHoverCard',
127
+ type: "(children: ReactNode, props?: Omit<ContextRenderProps, 'positioning'>) => ReactNode",
128
+ description:
129
+ 'Render function for the anchor-positioned hover card content. The positioning opt-out is excluded: the hover card always derives its position from placement/alignment.',
130
+ },
131
+ {
132
+ name: 'show',
133
+ type: '() => void',
134
+ description: 'Imperatively show the hover card immediately.',
135
+ },
136
+ {
137
+ name: 'hide',
138
+ type: '() => void',
139
+ description: 'Imperatively hide the hover card immediately.',
140
+ },
32
141
  ],
33
142
  usage: {
34
- description: 'Headless hook for hover-triggered floating cards. Builds on useLayer with hover/focus intent detection, configurable delays, safe hover behavior, and accessible aria-describedby linking. Use for rich previews on hover when you need full control over the trigger or rendered content.',
143
+ description:
144
+ 'Headless hook for hover-triggered floating cards. Builds on useLayer with hover/focus intent detection, configurable delays, safe hover behavior, and accessible aria-describedby linking. Use for rich previews on hover when you need full control over the trigger or rendered content.',
35
145
  bestPractices: [
36
- {guidance: true, description: 'Use for rich content previews such as user profiles, entity summaries, and link previews.'},
37
- {guidance: true, description: 'Prefer the HoverCard component for standard trigger-content pairs; use the hook for custom trigger patterns.'},
38
- {guidance: false, description: 'Use for simple text hints: use Tooltip or useTooltip instead.'},
146
+ {
147
+ guidance: true,
148
+ description:
149
+ 'Use for rich content previews such as user profiles, entity summaries, and link previews.',
150
+ },
151
+ {
152
+ guidance: true,
153
+ description:
154
+ 'Prefer the HoverCard component for standard trigger-content pairs; use the hook for custom trigger patterns.',
155
+ },
156
+ {
157
+ guidance: false,
158
+ description:
159
+ 'Use for simple text hints: use Tooltip or useTooltip instead.',
160
+ },
39
161
  ],
40
162
  },
41
163
  relatedComponents: ['HoverCard', 'Tooltip', 'Popover'],
@@ -46,17 +168,24 @@ export const docs = {
46
168
 
47
169
  /** @type {import('@astryxdesign/cli/authoring').HookTranslationDoc} */
48
170
  export const docsDense = {
49
- description: 'Headless hover-triggered floating cards. Builds on useLayer w/ hover/focus intent, delays, safe hover behavior, aria-describedby. Use for rich previews when trigger/content rendering needs full control.',
171
+ description:
172
+ 'Headless hover-triggered floating cards. Builds on useLayer w/ hover/focus intent, delays, safe hover behavior, aria-describedby. Use for rich previews when trigger/content rendering needs full control.',
50
173
  paramDescriptions: {
51
- placement: 'position relative to trigger. logical: start/end follow the popover\'s inherited direction (RTL mirrors).',
52
- alignment: 'alignment along placement axis. logical: start/end follow the popover\'s inherited direction (RTL mirrors).',
174
+ placement:
175
+ "position relative to trigger. logical: start/end follow the popover's inherited direction (RTL mirrors).",
176
+ alignment:
177
+ "alignment along placement axis. logical: start/end follow the popover's inherited direction (RTL mirrors).",
53
178
  delay: 'show delay in ms.',
54
179
  hideDelay: 'hide delay after mouse/focus leave in ms.',
55
- focusTrigger: 'when focus opens hover card; auto = naturally focusable elements only.',
56
- touchTrigger: 'tap behavior with no hover; auto = tap unless trigger acts, tap = always, none = never.',
180
+ focusTrigger:
181
+ 'when focus opens hover card; auto = focus on the trigger, or inside a trigger focusable when focus arrives.',
182
+ touchTrigger:
183
+ 'tap behavior with no hover; auto = tap unless trigger acts, tap = always, none = never.',
57
184
  isEnabled: 'whether hover/focus triggers are enabled.',
58
- label: 'accessible name for popup. with label: named role="dialog"; without: role="group".',
59
- isOpen: 'controlled open state: true force-show, false force-hide, undefined unmanaged.',
185
+ label:
186
+ 'accessible name for popup. with label: named role="dialog"; without: role="group".',
187
+ isOpen:
188
+ 'controlled open state: true force-show, false force-hide, undefined unmanaged.',
60
189
  isDefaultOpen: 'show on mount.',
61
190
  onShow: 'fires when hover card becomes visible.',
62
191
  onHide: 'fires when hover card hides.',
@@ -72,11 +201,24 @@ export const docsDense = {
72
201
  hide: 'hide immediately.',
73
202
  },
74
203
  usage: {
75
- description: 'Headless hover-triggered floating cards. Builds on useLayer w/ hover/focus intent, delays, safe hover behavior, aria-describedby. Use for rich previews when trigger/content rendering needs full control.',
204
+ description:
205
+ 'Headless hover-triggered floating cards. Builds on useLayer w/ hover/focus intent, delays, safe hover behavior, aria-describedby. Use for rich previews when trigger/content rendering needs full control.',
76
206
  bestPractices: [
77
- {guidance: true, description: 'Use for rich previews: profiles, entity summaries, link previews.'},
78
- {guidance: true, description: 'Prefer HoverCard for standard trigger-content pairs; use hook for custom trigger patterns.'},
79
- {guidance: false, description: 'Use for simple text hints: use Tooltip / useTooltip instead.'},
207
+ {
208
+ guidance: true,
209
+ description:
210
+ 'Use for rich previews: profiles, entity summaries, link previews.',
211
+ },
212
+ {
213
+ guidance: true,
214
+ description:
215
+ 'Prefer HoverCard for standard trigger-content pairs; use hook for custom trigger patterns.',
216
+ },
217
+ {
218
+ guidance: false,
219
+ description:
220
+ 'Use for simple text hints: use Tooltip / useTooltip instead.',
221
+ },
80
222
  ],
81
223
  },
82
224
  };
@@ -16,9 +16,11 @@ import {
16
16
  useCallback,
17
17
  useEffect,
18
18
  useRef,
19
+ useState,
19
20
  type ReactNode,
20
21
  type RefCallback,
21
22
  } from 'react';
23
+ import {createTriggerFocusGate} from '../utils/triggerFocus';
22
24
  import * as stylex from '@stylexjs/stylex';
23
25
  import {
24
26
  useLayer,
@@ -60,7 +62,7 @@ const styles = stylex.create({
60
62
  });
61
63
 
62
64
  /**
63
- * Focus trigger behavior for hover cards
65
+ * When focus on the trigger opens the hover card
64
66
  */
65
67
  export type HoverCardFocusTrigger = 'auto' | 'always' | 'never';
66
68
 
@@ -96,9 +98,10 @@ export interface HoverCardOptions {
96
98
 
97
99
  /**
98
100
  * When to trigger on focus:
99
- * - `auto`: Only if element is naturally focusable
100
- * - `always`: Always attach focus listeners
101
- * - `never`: Never attach focus listeners (for composite widgets)
101
+ * - `auto`: focus on the trigger itself, or within a trigger that is
102
+ * focusable when focus arrives
103
+ * - `always`: focus on the trigger or anything inside it
104
+ * - `never`: never on focus (for composite widgets)
102
105
  *
103
106
  * @default 'auto'
104
107
  */
@@ -235,29 +238,6 @@ export interface HoverCardReturn {
235
238
  hide: () => void;
236
239
  }
237
240
 
238
- /**
239
- * Check if an element is naturally focusable
240
- */
241
- function isFocusable(element: HTMLElement): boolean {
242
- // Elements with explicit tabindex
243
- if (element.hasAttribute('tabindex')) {
244
- return element.tabIndex >= 0;
245
- }
246
-
247
- // Naturally focusable elements
248
- const focusableTags = ['A', 'BUTTON', 'INPUT', 'SELECT', 'TEXTAREA'];
249
- if (focusableTags.includes(element.tagName)) {
250
- return !(element as HTMLButtonElement).disabled;
251
- }
252
-
253
- // Elements with contenteditable
254
- if (element.isContentEditable) {
255
- return true;
256
- }
257
-
258
- return false;
259
- }
260
-
261
241
  /**
262
242
  * Hook for hover card behavior with hover/focus triggers.
263
243
  *
@@ -426,27 +406,44 @@ export function useHoverCard(options: HoverCardOptions = {}): HoverCardReturn {
426
406
  [handleTouchPointerDown],
427
407
  );
428
408
 
429
- const handleFocusIn = useCallback(() => {
430
- if (!isEnabled) {
431
- return;
432
- }
433
- // A tap focuses the trigger it activates. Opening on that focus would
434
- // reinstate exactly the behavior the touch path just decided against —
435
- // and on an action trigger it covers the thing the user tapped.
436
- if (isTouchInteraction()) {
437
- return;
438
- }
439
- // Skip showing if we're in the middle of an Escape dismiss
440
- if (isEscapeDismissingRef.current) {
441
- isEscapeDismissingRef.current = false;
442
- return;
443
- }
444
- clearTimeouts();
445
- showLayer();
446
- }, [isEnabled, isTouchInteraction, clearTimeouts, showLayer]);
409
+ // Under `auto`, whether focus counts is decided when it arrives, and a
410
+ // focus that counted still hides on blur (utils/triggerFocus.ts).
411
+ const [focusGate] = useState(createTriggerFocusGate);
412
+
413
+ const handleFocusIn = useCallback(
414
+ (e: Event) => {
415
+ if (!focusGate.focusIn(e, focusTrigger) || !isEnabled) {
416
+ return;
417
+ }
418
+ // A tap focuses the trigger it activates. Opening on that focus would
419
+ // reinstate exactly the behavior the touch path just decided against —
420
+ // and on an action trigger it covers the thing the user tapped.
421
+ if (isTouchInteraction()) {
422
+ return;
423
+ }
424
+ // Skip showing if we're in the middle of an Escape dismiss
425
+ if (isEscapeDismissingRef.current) {
426
+ isEscapeDismissingRef.current = false;
427
+ return;
428
+ }
429
+ clearTimeouts();
430
+ showLayer();
431
+ },
432
+ [
433
+ focusGate,
434
+ focusTrigger,
435
+ isEnabled,
436
+ isTouchInteraction,
437
+ clearTimeouts,
438
+ showLayer,
439
+ ],
440
+ );
447
441
 
448
442
  const handleFocusOut = useCallback(
449
443
  (e: FocusEvent) => {
444
+ if (!focusGate.focusOut(e, focusTrigger)) {
445
+ return;
446
+ }
450
447
  // Check if focus is moving to the hover card content
451
448
  const relatedTarget = e.relatedTarget as HTMLElement | null;
452
449
  const popoverElement = document.getElementById(layerId);
@@ -458,7 +455,7 @@ export function useHoverCard(options: HoverCardOptions = {}): HoverCardReturn {
458
455
 
459
456
  scheduleHide();
460
457
  },
461
- [layerId, scheduleHide],
458
+ [focusGate, focusTrigger, layerId, scheduleHide],
462
459
  );
463
460
 
464
461
  // Escape dismissal (WCAG 1.4.13) goes through the shared layer stack: a
@@ -558,12 +555,9 @@ export function useHoverCard(options: HoverCardOptions = {}): HoverCardReturn {
558
555
  el.addEventListener('mouseleave', handleMouseLeave);
559
556
  el.addEventListener('pointerdown', handlePointerDown);
560
557
 
561
- // Attach focus listeners based on focusTrigger option
562
- const shouldAttachFocus =
563
- focusTrigger === 'always' ||
564
- (focusTrigger === 'auto' && isFocusable(el));
565
-
566
- if (shouldAttachFocus) {
558
+ // Focus listeners unless focus never opens the card; `auto` decides
559
+ // per event (utils/triggerFocus.ts).
560
+ if (focusTrigger !== 'never') {
567
561
  el.addEventListener('focusin', handleFocusIn);
568
562
  el.addEventListener('focusout', handleFocusOut as EventListener);
569
563
  }
@@ -591,7 +585,7 @@ export function useHoverCard(options: HoverCardOptions = {}): HoverCardReturn {
591
585
  [layerRef, interactionRef],
592
586
  );
593
587
 
594
- // Cleanup on unmount
588
+ // Releases the hover-card timers on unmount.
595
589
  useEffect(() => {
596
590
  return () => {
597
591
  clearTimeouts();
@@ -606,7 +600,8 @@ export function useHoverCard(options: HoverCardOptions = {}): HoverCardReturn {
606
600
  // eslint-disable-next-line @eslint-react/exhaustive-deps -- intentionally only on mount
607
601
  }, []);
608
602
 
609
- // Controlled open state — overrides hover/focus triggers
603
+ // Syncs the layer with the controlled `isOpen`. A close moves focus back to
604
+ // the trigger when the card holds it.
610
605
  useEffect(() => {
611
606
  if (isOpen === undefined) {
612
607
  return;