@astryxdesign/core 0.7.7-canary.c0929c8 → 0.7.7-canary.c19ca12

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 (472) 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 +36 -6
  4. package/dist/AppShell/useCloseMobileDrawerOnActivate.d.ts +13 -0
  5. package/dist/AppShell/useCloseMobileDrawerOnActivate.d.ts.map +1 -0
  6. package/dist/AppShell/useCloseMobileDrawerOnActivate.js +45 -0
  7. package/dist/BottomSheet/BottomSheet.d.ts.map +1 -1
  8. package/dist/BottomSheet/BottomSheet.js +79 -9
  9. package/dist/BottomSheet/BottomSheetPanel.d.ts.map +1 -1
  10. package/dist/BottomSheet/BottomSheetPanel.js +23 -4
  11. package/dist/BottomSheet/bottomSheetStack.d.ts.map +1 -1
  12. package/dist/BottomSheet/bottomSheetStack.js +5 -4
  13. package/dist/BottomSheet/useSheetGestures.d.ts.map +1 -1
  14. package/dist/BottomSheet/useSheetGestures.js +3 -1
  15. package/dist/Breadcrumbs/BreadcrumbItem.d.ts +2 -1
  16. package/dist/Breadcrumbs/BreadcrumbItem.d.ts.map +1 -1
  17. package/dist/Breadcrumbs/BreadcrumbItem.js +7 -3
  18. package/dist/Button/Button.d.ts.map +1 -1
  19. package/dist/Button/Button.js +47 -3
  20. package/dist/CheckboxInput/CheckboxInput.d.ts.map +1 -1
  21. package/dist/CheckboxInput/CheckboxInput.js +13 -2
  22. package/dist/CheckboxList/CheckboxList.d.ts.map +1 -1
  23. package/dist/CheckboxList/CheckboxList.js +7 -1
  24. package/dist/CheckboxList/CheckboxListContext.d.ts +6 -0
  25. package/dist/CheckboxList/CheckboxListContext.d.ts.map +1 -1
  26. package/dist/CheckboxList/CheckboxListItem.d.ts.map +1 -1
  27. package/dist/CheckboxList/CheckboxListItem.js +10 -2
  28. package/dist/ComplexSelector/ComplexSelector.d.ts +4 -1
  29. package/dist/ComplexSelector/ComplexSelector.d.ts.map +1 -1
  30. package/dist/ComplexSelector/ComplexSelector.js +14 -4
  31. package/dist/ContextMenu/ContextMenu.js +2 -2
  32. package/dist/DateInput/DateInput.d.ts.map +1 -1
  33. package/dist/DateInput/DateInput.js +5 -2
  34. package/dist/DateInput/MonthScroller.d.ts.map +1 -1
  35. package/dist/DateInput/MonthScroller.js +13 -27
  36. package/dist/DateInput/Wheel.d.ts.map +1 -1
  37. package/dist/DateInput/Wheel.js +22 -41
  38. package/dist/DateTimeInput/DateTimeInput.d.ts.map +1 -1
  39. package/dist/DateTimeInput/DateTimeInput.js +5 -2
  40. package/dist/Dialog/Dialog.d.ts.map +1 -1
  41. package/dist/Dialog/Dialog.js +23 -45
  42. package/dist/Drawer/Drawer.d.ts.map +1 -1
  43. package/dist/Drawer/Drawer.js +15 -11
  44. package/dist/Drawer/useDrawerDialogPresence.d.ts.map +1 -1
  45. package/dist/Drawer/useDrawerDialogPresence.js +5 -1
  46. package/dist/Field/Field.js +2 -2
  47. package/dist/Field/PanelSearchInput.d.ts +9 -1
  48. package/dist/Field/PanelSearchInput.d.ts.map +1 -1
  49. package/dist/Field/PanelSearchInput.js +3 -1
  50. package/dist/HoverCard/HoverCard.d.ts +4 -3
  51. package/dist/HoverCard/HoverCard.d.ts.map +1 -1
  52. package/dist/HoverCard/HoverCard.js +27 -2
  53. package/dist/HoverCard/useHoverCard.d.ts +5 -4
  54. package/dist/HoverCard/useHoverCard.d.ts.map +1 -1
  55. package/dist/HoverCard/useHoverCard.js +17 -31
  56. package/dist/Icon/Icon.d.ts +5 -1
  57. package/dist/Icon/Icon.d.ts.map +1 -1
  58. package/dist/Icon/Icon.js +5 -2
  59. package/dist/InfoTip/InfoTip.d.ts +63 -0
  60. package/dist/InfoTip/InfoTip.d.ts.map +1 -0
  61. package/dist/InfoTip/InfoTip.js +126 -0
  62. package/dist/InfoTip/index.d.ts +10 -0
  63. package/dist/InfoTip/index.d.ts.map +1 -0
  64. package/dist/InfoTip/index.js +12 -0
  65. package/dist/Layer/layerAnimations.stylex.d.ts +7 -8
  66. package/dist/Layer/layerAnimations.stylex.d.ts.map +1 -1
  67. package/dist/Layer/layerAnimations.stylex.js +25 -20
  68. package/dist/Layer/useBackdropPress.d.ts +27 -0
  69. package/dist/Layer/useBackdropPress.d.ts.map +1 -0
  70. package/dist/Layer/useBackdropPress.js +53 -0
  71. package/dist/Layer/usePressPin.d.ts +20 -10
  72. package/dist/Layer/usePressPin.d.ts.map +1 -1
  73. package/dist/Layer/usePressPin.js +66 -18
  74. package/dist/Lightbox/Lightbox.d.ts.map +1 -1
  75. package/dist/Lightbox/Lightbox.js +18 -0
  76. package/dist/MobileNav/MobileNav.js +0 -1
  77. package/dist/MultiSelector/hooks.d.ts.map +1 -1
  78. package/dist/MultiSelector/hooks.js +2 -4
  79. package/dist/Outline/Outline.d.ts +2 -4
  80. package/dist/Outline/Outline.d.ts.map +1 -1
  81. package/dist/Outline/Outline.js +4 -52
  82. package/dist/Outline/useOutlineFromMarkdown.d.ts.map +1 -1
  83. package/dist/Outline/useOutlineFromMarkdown.js +1 -0
  84. package/dist/Outline/useScrollSpy.js +3 -3
  85. package/dist/PowerSearch/PowerSearch.d.ts +36 -3
  86. package/dist/PowerSearch/PowerSearch.d.ts.map +1 -1
  87. package/dist/PowerSearch/PowerSearch.js +571 -302
  88. package/dist/PowerSearch/PowerSearchBottomSheet.d.ts +100 -0
  89. package/dist/PowerSearch/PowerSearchBottomSheet.d.ts.map +1 -0
  90. package/dist/PowerSearch/PowerSearchBottomSheet.js +1913 -0
  91. package/dist/PowerSearch/PowerSearchEditPopover.d.ts +32 -1
  92. package/dist/PowerSearch/PowerSearchEditPopover.d.ts.map +1 -1
  93. package/dist/PowerSearch/PowerSearchEditPopover.js +17 -6
  94. package/dist/PowerSearch/PowerSearchValueEditor.d.ts +38 -3
  95. package/dist/PowerSearch/PowerSearchValueEditor.d.ts.map +1 -1
  96. package/dist/PowerSearch/PowerSearchValueEditor.js +170 -61
  97. package/dist/PowerSearch/formatFilterValue.d.ts +7 -0
  98. package/dist/PowerSearch/formatFilterValue.d.ts.map +1 -1
  99. package/dist/PowerSearch/formatFilterValue.js +11 -1
  100. package/dist/PowerSearch/formatTokenValue.d.ts +28 -0
  101. package/dist/PowerSearch/formatTokenValue.d.ts.map +1 -0
  102. package/dist/PowerSearch/formatTokenValue.js +160 -0
  103. package/dist/PowerSearch/powerSearchSheetUtils.d.ts +65 -0
  104. package/dist/PowerSearch/powerSearchSheetUtils.d.ts.map +1 -0
  105. package/dist/PowerSearch/powerSearchSheetUtils.js +168 -0
  106. package/dist/RadioList/RadioList.d.ts.map +1 -1
  107. package/dist/RadioList/RadioList.js +8 -2
  108. package/dist/RadioList/RadioListItem.d.ts +1 -1
  109. package/dist/RadioList/RadioListItem.d.ts.map +1 -1
  110. package/dist/RadioList/RadioListItem.js +5 -3
  111. package/dist/Resizable/ResizeHandle.d.ts.map +1 -1
  112. package/dist/Resizable/ResizeHandle.js +118 -260
  113. package/dist/Resizable/resizeGesture.d.ts +91 -0
  114. package/dist/Resizable/resizeGesture.d.ts.map +1 -0
  115. package/dist/Resizable/resizeGesture.js +251 -0
  116. package/dist/SegmentedControl/SegmentedControl.d.ts +3 -1
  117. package/dist/SegmentedControl/SegmentedControl.d.ts.map +1 -1
  118. package/dist/SegmentedControl/SegmentedControl.js +115 -8
  119. package/dist/SegmentedControl/SegmentedControlContext.d.ts +6 -0
  120. package/dist/SegmentedControl/SegmentedControlContext.d.ts.map +1 -1
  121. package/dist/SegmentedControl/SegmentedControlItem.d.ts +1 -0
  122. package/dist/SegmentedControl/SegmentedControlItem.d.ts.map +1 -1
  123. package/dist/SegmentedControl/SegmentedControlItem.js +8 -1
  124. package/dist/SegmentedControl/useSegmentedSelectionMotion.d.ts +357 -0
  125. package/dist/SegmentedControl/useSegmentedSelectionMotion.d.ts.map +1 -0
  126. package/dist/SegmentedControl/useSegmentedSelectionMotion.js +1349 -0
  127. package/dist/SegmentedControl/useSegmentedTouchTracking.d.ts +70 -0
  128. package/dist/SegmentedControl/useSegmentedTouchTracking.d.ts.map +1 -0
  129. package/dist/SegmentedControl/useSegmentedTouchTracking.js +264 -0
  130. package/dist/Selector/Selector.d.ts.map +1 -1
  131. package/dist/Selector/Selector.js +96 -67
  132. package/dist/Selector/optionShape.d.ts +24 -0
  133. package/dist/Selector/optionShape.d.ts.map +1 -0
  134. package/dist/Selector/optionShape.js +48 -0
  135. package/dist/Selector/selectableOptionEntries.d.ts +20 -0
  136. package/dist/Selector/selectableOptionEntries.d.ts.map +1 -0
  137. package/dist/Selector/selectableOptionEntries.js +38 -0
  138. package/dist/Selector/utils.d.ts +2 -17
  139. package/dist/Selector/utils.d.ts.map +1 -1
  140. package/dist/Selector/utils.js +3 -51
  141. package/dist/SideNav/SideNavItem.d.ts.map +1 -1
  142. package/dist/SideNav/SideNavItem.js +3 -9
  143. package/dist/Slider/sliderTouchController.js +2 -2
  144. package/dist/Spinner/Spinner.d.ts +1 -1
  145. package/dist/Spinner/Spinner.d.ts.map +1 -1
  146. package/dist/Spinner/Spinner.js +60 -58
  147. package/dist/Switch/switchTouch.d.ts +0 -7
  148. package/dist/Switch/switchTouch.d.ts.map +1 -1
  149. package/dist/Switch/switchTouch.js +2 -10
  150. package/dist/Switch/useSwitchTouch.d.ts +2 -11
  151. package/dist/Switch/useSwitchTouch.d.ts.map +1 -1
  152. package/dist/Switch/useSwitchTouch.js +35 -93
  153. package/dist/Table/BaseTable.d.ts.map +1 -1
  154. package/dist/Table/BaseTable.js +29 -8
  155. package/dist/TextInput/TextInput.d.ts +2 -2
  156. package/dist/TextInput/TextInput.d.ts.map +1 -1
  157. package/dist/TextInput/TextInput.js +10 -7
  158. package/dist/Toast/Toast.d.ts +11 -1
  159. package/dist/Toast/Toast.d.ts.map +1 -1
  160. package/dist/Toast/Toast.js +30 -15
  161. package/dist/Toast/ToastViewport.d.ts.map +1 -1
  162. package/dist/Toast/ToastViewport.js +94 -34
  163. package/dist/Toast/types.d.ts +9 -3
  164. package/dist/Toast/types.d.ts.map +1 -1
  165. package/dist/Token/Token.d.ts +2 -2
  166. package/dist/Token/Token.d.ts.map +1 -1
  167. package/dist/Token/Token.js +13 -4
  168. package/dist/Token/TokenNamingContext.d.ts +14 -0
  169. package/dist/Token/TokenNamingContext.d.ts.map +1 -0
  170. package/dist/Token/TokenNamingContext.js +23 -0
  171. package/dist/Tokenizer/Tokenizer.d.ts +46 -59
  172. package/dist/Tokenizer/Tokenizer.d.ts.map +1 -1
  173. package/dist/Tokenizer/Tokenizer.js +40 -57
  174. package/dist/Tokenizer/TokenizerBottomSheet.d.ts +25 -28
  175. package/dist/Tokenizer/TokenizerBottomSheet.d.ts.map +1 -1
  176. package/dist/Tokenizer/TokenizerBottomSheet.js +157 -54
  177. package/dist/Tokenizer/TokenizerItemRemovableContext.d.ts +3 -0
  178. package/dist/Tokenizer/TokenizerItemRemovableContext.d.ts.map +1 -0
  179. package/dist/Tokenizer/TokenizerItemRemovableContext.js +19 -0
  180. package/dist/Tooltip/Tooltip.d.ts +25 -30
  181. package/dist/Tooltip/Tooltip.d.ts.map +1 -1
  182. package/dist/Tooltip/Tooltip.js +24 -5
  183. package/dist/Tooltip/index.d.ts +1 -1
  184. package/dist/Tooltip/index.d.ts.map +1 -1
  185. package/dist/Tooltip/useTooltip.d.ts +45 -28
  186. package/dist/Tooltip/useTooltip.d.ts.map +1 -1
  187. package/dist/Tooltip/useTooltip.js +52 -59
  188. package/dist/TopNav/TopNavItem.d.ts.map +1 -1
  189. package/dist/TopNav/TopNavItem.js +4 -7
  190. package/dist/TopNav/TopNavMegaMenuItem.d.ts.map +1 -1
  191. package/dist/TopNav/TopNavMegaMenuItem.js +4 -7
  192. package/dist/TopNav/TopNavMenu.d.ts.map +1 -1
  193. package/dist/TopNav/TopNavMenu.js +4 -7
  194. package/dist/Typeahead/TypeaheadItem.d.ts +2 -1
  195. package/dist/Typeahead/TypeaheadItem.d.ts.map +1 -1
  196. package/dist/animator/createAnimator.d.ts +98 -0
  197. package/dist/animator/createAnimator.d.ts.map +1 -0
  198. package/dist/animator/createAnimator.js +259 -0
  199. package/dist/astryx.css +96 -7
  200. package/dist/gestures/GestureHost.d.ts +27 -1
  201. package/dist/gestures/GestureHost.d.ts.map +1 -1
  202. package/dist/gestures/GestureHost.js +157 -21
  203. package/dist/gestures/PressTracker.d.ts.map +1 -1
  204. package/dist/gestures/PressTracker.js +4 -3
  205. package/dist/hooks/actionGroupTracker.d.ts +7 -4
  206. package/dist/hooks/actionGroupTracker.d.ts.map +1 -1
  207. package/dist/hooks/actionGroupTracker.js +19 -56
  208. package/dist/hooks/index.d.ts +1 -0
  209. package/dist/hooks/index.d.ts.map +1 -1
  210. package/dist/hooks/index.js +1 -0
  211. package/dist/hooks/pressGroupContext.d.ts +6 -0
  212. package/dist/hooks/pressGroupContext.d.ts.map +1 -0
  213. package/dist/hooks/pressGroupContext.js +20 -0
  214. package/dist/hooks/useActionGroupTracking.d.ts +53 -0
  215. package/dist/hooks/useActionGroupTracking.d.ts.map +1 -0
  216. package/dist/hooks/useActionGroupTracking.js +174 -0
  217. package/dist/hooks/useAnimator.d.ts +41 -0
  218. package/dist/hooks/useAnimator.d.ts.map +1 -0
  219. package/dist/hooks/useAnimator.js +70 -0
  220. package/dist/hooks/useAttachment.d.ts +1 -1
  221. package/dist/hooks/useAttachment.js +1 -1
  222. package/dist/hooks/useHighlightedOptionScroll.d.ts +11 -1
  223. package/dist/hooks/useHighlightedOptionScroll.d.ts.map +1 -1
  224. package/dist/hooks/useHighlightedOptionScroll.js +112 -11
  225. package/dist/hooks/useInputStatusIcon.d.ts +1 -1
  226. package/dist/hooks/useInputStatusIcon.d.ts.map +1 -1
  227. package/dist/hooks/useInputStatusIcon.js +2 -2
  228. package/dist/hooks/useLongPress.d.ts +6 -2
  229. package/dist/hooks/useLongPress.d.ts.map +1 -1
  230. package/dist/hooks/useLongPress.js +95 -15
  231. package/dist/hooks/useMediaQuery.d.ts +2 -1
  232. package/dist/hooks/useMediaQuery.d.ts.map +1 -1
  233. package/dist/hooks/useMediaQuery.js +7 -4
  234. package/dist/hooks/useMenuPress.d.ts.map +1 -1
  235. package/dist/hooks/useMenuPress.js +4 -2
  236. package/dist/i18n/generated-english/InfoTip/InfoTip.generated.d.ts +8 -0
  237. package/dist/i18n/generated-english/InfoTip/InfoTip.generated.d.ts.map +1 -0
  238. package/dist/i18n/generated-english/InfoTip/InfoTip.generated.js +12 -0
  239. package/dist/i18n/generated-english/PowerSearch/PowerSearch.generated.d.ts.map +1 -1
  240. package/dist/i18n/generated-english/PowerSearch/PowerSearch.generated.js +1 -0
  241. package/dist/i18n/generated-english/PowerSearch/PowerSearchBottomSheet.generated.d.ts +8 -0
  242. package/dist/i18n/generated-english/PowerSearch/PowerSearchBottomSheet.generated.d.ts.map +1 -0
  243. package/dist/i18n/generated-english/PowerSearch/PowerSearchBottomSheet.generated.js +42 -0
  244. package/dist/i18n/generated-english/PowerSearch/PowerSearchValueEditor.generated.d.ts.map +1 -1
  245. package/dist/i18n/generated-english/PowerSearch/PowerSearchValueEditor.generated.js +6 -0
  246. package/dist/i18n/generated-english/PowerSearch/formatTokenValue.generated.d.ts +8 -0
  247. package/dist/i18n/generated-english/PowerSearch/formatTokenValue.generated.d.ts.map +1 -0
  248. package/dist/i18n/generated-english/PowerSearch/formatTokenValue.generated.js +14 -0
  249. package/dist/i18n/generated-english/Tokenizer/TokenizerBottomSheet.generated.d.ts.map +1 -1
  250. package/dist/i18n/generated-english/Tokenizer/TokenizerBottomSheet.generated.js +7 -1
  251. package/dist/i18n/generated-locales/en.generated.d.ts.map +1 -1
  252. package/dist/i18n/generated-locales/en.generated.js +33 -1
  253. package/dist/i18n/generated-locales/pseudo.generated.d.ts.map +1 -1
  254. package/dist/i18n/generated-locales/pseudo.generated.js +33 -1
  255. package/dist/index.d.ts +2 -0
  256. package/dist/index.d.ts.map +1 -1
  257. package/dist/index.js +5 -0
  258. package/dist/internal/SheetConfirmation.d.ts +11 -0
  259. package/dist/internal/SheetConfirmation.d.ts.map +1 -0
  260. package/dist/internal/SheetConfirmation.js +92 -0
  261. package/dist/internal/indicatorPress.stylex.d.ts +20 -0
  262. package/dist/internal/indicatorPress.stylex.d.ts.map +1 -0
  263. package/dist/internal/indicatorPress.stylex.js +26 -0
  264. package/dist/internal/sheetDraft.d.ts +35 -0
  265. package/dist/internal/sheetDraft.d.ts.map +1 -0
  266. package/dist/internal/sheetDraft.js +65 -0
  267. package/dist/internal/touch-sheet.d.ts +21 -0
  268. package/dist/internal/touch-sheet.d.ts.map +1 -0
  269. package/dist/internal/touch-sheet.js +19 -0
  270. package/dist/internal/useDismissSearchOnTouchDrag.d.ts +24 -0
  271. package/dist/internal/useDismissSearchOnTouchDrag.d.ts.map +1 -0
  272. package/dist/internal/useDismissSearchOnTouchDrag.js +56 -0
  273. package/dist/motion/animator.d.ts +14 -14
  274. package/dist/motion/animator.d.ts.map +1 -1
  275. package/dist/motion/animator.js +41 -18
  276. package/dist/motion/reducedMotion.d.ts +24 -0
  277. package/dist/motion/reducedMotion.d.ts.map +1 -1
  278. package/dist/motion/reducedMotion.js +78 -1
  279. package/dist/motion/roles.d.ts +7 -1
  280. package/dist/motion/roles.d.ts.map +1 -1
  281. package/dist/motion/roles.js +20 -1
  282. package/dist/motion/uikit/alert.d.ts +41 -0
  283. package/dist/motion/uikit/alert.d.ts.map +1 -0
  284. package/dist/motion/uikit/alert.js +43 -0
  285. package/dist/motion/uikit/index.d.ts +6 -5
  286. package/dist/motion/uikit/index.d.ts.map +1 -1
  287. package/dist/motion/uikit/index.js +6 -5
  288. package/dist/motion/uikit/segmented.d.ts +55 -0
  289. package/dist/motion/uikit/segmented.d.ts.map +1 -0
  290. package/dist/motion/uikit/segmented.js +77 -0
  291. package/dist/motion/uikit/springs.d.ts +0 -18
  292. package/dist/motion/uikit/springs.d.ts.map +1 -1
  293. package/dist/motion/uikit/springs.js +5 -21
  294. package/dist/privateAttributes/pressGroupItem.stylex.d.ts +15 -0
  295. package/dist/privateAttributes/pressGroupItem.stylex.d.ts.map +1 -0
  296. package/dist/privateAttributes/pressGroupItem.stylex.js +23 -0
  297. package/dist/privateAttributes/segmentTitle.stylex.d.ts +5 -0
  298. package/dist/privateAttributes/segmentTitle.stylex.d.ts.map +1 -0
  299. package/dist/privateAttributes/segmentTitle.stylex.js +22 -0
  300. package/dist/utils/browserClickWait.d.ts +35 -0
  301. package/dist/utils/browserClickWait.d.ts.map +1 -0
  302. package/dist/utils/browserClickWait.js +123 -0
  303. package/dist/utils/clickGuard.d.ts +14 -1
  304. package/dist/utils/clickGuard.d.ts.map +1 -1
  305. package/dist/utils/clickGuard.js +46 -1
  306. package/dist/utils/dateParser.d.ts.map +1 -1
  307. package/dist/utils/dateParser.js +12 -0
  308. package/dist/utils/focusReturn.d.ts +15 -0
  309. package/dist/utils/focusReturn.d.ts.map +1 -1
  310. package/dist/utils/focusReturn.js +28 -0
  311. package/dist/utils/interactionOverlay.stylex.d.ts +3 -2
  312. package/dist/utils/interactionOverlay.stylex.d.ts.map +1 -1
  313. package/dist/utils/interactionOverlay.stylex.js +3 -2
  314. package/dist/utils/pressFeedback.d.ts.map +1 -1
  315. package/dist/utils/pressFeedback.js +19 -6
  316. package/dist/utils/triggerFocus.d.ts +36 -0
  317. package/dist/utils/triggerFocus.d.ts.map +1 -0
  318. package/dist/utils/triggerFocus.js +65 -0
  319. package/locales/en.json +128 -0
  320. package/locales/pseudo.json +96 -0
  321. package/package.json +18 -8
  322. package/src/AlertDialog/AlertDialog.doc.mjs +2 -2
  323. package/src/AlertDialog/AlertDialog.tsx +37 -5
  324. package/src/AppShell/useCloseMobileDrawerOnActivate.ts +52 -0
  325. package/src/BottomSheet/BottomSheet.tsx +95 -10
  326. package/src/BottomSheet/BottomSheetPanel.tsx +40 -5
  327. package/src/BottomSheet/bottomSheetStack.ts +8 -4
  328. package/src/BottomSheet/useSheetGestures.ts +3 -1
  329. package/src/Breadcrumbs/BreadcrumbItem.tsx +13 -3
  330. package/src/Button/Button.tsx +63 -5
  331. package/src/CheckboxInput/CheckboxInput.doc.mjs +18 -0
  332. package/src/CheckboxInput/CheckboxInput.tsx +36 -9
  333. package/src/CheckboxList/CheckboxList.doc.mjs +4 -2
  334. package/src/CheckboxList/CheckboxList.tsx +6 -0
  335. package/src/CheckboxList/CheckboxListContext.tsx +6 -0
  336. package/src/CheckboxList/CheckboxListItem.tsx +11 -2
  337. package/src/ComplexSelector/ComplexSelector.tsx +20 -5
  338. package/src/ContextMenu/ContextMenu.tsx +2 -2
  339. package/src/DateInput/DateInput.tsx +8 -2
  340. package/src/DateInput/MonthScroller.tsx +18 -22
  341. package/src/DateInput/Wheel.tsx +30 -32
  342. package/src/DateTimeInput/DateTimeInput.tsx +8 -2
  343. package/src/Dialog/Dialog.tsx +54 -45
  344. package/src/Drawer/Drawer.tsx +28 -11
  345. package/src/Drawer/useDrawerDialogPresence.ts +5 -1
  346. package/src/Field/Field.tsx +2 -2
  347. package/src/Field/PanelSearchInput.tsx +11 -0
  348. package/src/HoverCard/HoverCard.doc.mjs +4 -2
  349. package/src/HoverCard/HoverCard.tsx +35 -4
  350. package/src/HoverCard/useHoverCard.doc.mjs +178 -36
  351. package/src/HoverCard/useHoverCard.tsx +46 -52
  352. package/src/Icon/Icon.doc.mjs +49 -8
  353. package/src/Icon/Icon.tsx +15 -7
  354. package/src/InfoTip/InfoTip.doc.mjs +192 -0
  355. package/src/InfoTip/InfoTip.tsx +186 -0
  356. package/src/InfoTip/index.ts +14 -0
  357. package/src/Layer/layerAnimations.stylex.ts +24 -16
  358. package/src/Layer/useBackdropPress.ts +81 -0
  359. package/src/Layer/usePressPin.ts +86 -26
  360. package/src/Lightbox/Lightbox.tsx +18 -0
  361. package/src/MobileNav/MobileNav.tsx +1 -1
  362. package/src/MultiSelector/hooks.ts +2 -4
  363. package/src/Outline/Outline.doc.mjs +177 -51
  364. package/src/Outline/Outline.tsx +5 -57
  365. package/src/Outline/useOutlineFromMarkdown.doc.mjs +157 -0
  366. package/src/Outline/useOutlineFromMarkdown.ts +1 -0
  367. package/src/Outline/useScrollSpy.ts +3 -3
  368. package/src/PowerSearch/PowerSearch.doc.mjs +55 -6
  369. package/src/PowerSearch/PowerSearch.tsx +798 -324
  370. package/src/PowerSearch/PowerSearchBottomSheet.tsx +2515 -0
  371. package/src/PowerSearch/PowerSearchEditPopover.tsx +28 -6
  372. package/src/PowerSearch/PowerSearchValueEditor.tsx +203 -38
  373. package/src/PowerSearch/formatFilterValue.ts +18 -1
  374. package/src/PowerSearch/formatTokenValue.ts +215 -0
  375. package/src/PowerSearch/powerSearchSheetUtils.ts +224 -0
  376. package/src/RadioList/RadioList.doc.mjs +4 -2
  377. package/src/RadioList/RadioList.tsx +7 -2
  378. package/src/RadioList/RadioListItem.tsx +5 -3
  379. package/src/Resizable/ResizeHandle.tsx +133 -328
  380. package/src/Resizable/resizeGesture.ts +368 -0
  381. package/src/SegmentedControl/SegmentedControl.doc.mjs +3 -3
  382. package/src/SegmentedControl/SegmentedControl.tsx +179 -5
  383. package/src/SegmentedControl/SegmentedControlContext.ts +6 -0
  384. package/src/SegmentedControl/SegmentedControlItem.tsx +12 -1
  385. package/src/SegmentedControl/useSegmentedSelectionMotion.ts +1640 -0
  386. package/src/SegmentedControl/useSegmentedTouchTracking.ts +308 -0
  387. package/src/Selector/Selector.tsx +136 -89
  388. package/src/Selector/optionShape.ts +64 -0
  389. package/src/Selector/selectableOptionEntries.ts +39 -0
  390. package/src/Selector/utils.ts +9 -68
  391. package/src/SideNav/SideNavItem.tsx +3 -7
  392. package/src/Slider/sliderTouchController.ts +2 -2
  393. package/src/Spinner/Spinner.tsx +77 -63
  394. package/src/Switch/switchTouch.ts +2 -10
  395. package/src/Switch/useSwitchTouch.ts +38 -104
  396. package/src/Table/BaseTable.tsx +46 -12
  397. package/src/TextInput/TextInput.tsx +11 -10
  398. package/src/Toast/Toast.doc.mjs +4 -3
  399. package/src/Toast/Toast.tsx +57 -32
  400. package/src/Toast/ToastViewport.tsx +121 -35
  401. package/src/Toast/types.ts +9 -3
  402. package/src/Token/Token.tsx +15 -4
  403. package/src/Token/TokenNamingContext.ts +28 -0
  404. package/src/Tokenizer/Tokenizer.doc.mjs +16 -0
  405. package/src/Tokenizer/Tokenizer.tsx +89 -85
  406. package/src/Tokenizer/TokenizerBottomSheet.tsx +219 -93
  407. package/src/Tokenizer/TokenizerItemRemovableContext.ts +24 -0
  408. package/src/Tooltip/Tooltip.doc.mjs +123 -54
  409. package/src/Tooltip/Tooltip.tsx +36 -39
  410. package/src/Tooltip/index.ts +0 -1
  411. package/src/Tooltip/useTooltip.doc.mjs +171 -33
  412. package/src/Tooltip/useTooltip.tsx +98 -86
  413. package/src/TopNav/TopNavItem.tsx +6 -5
  414. package/src/TopNav/TopNavMegaMenuItem.tsx +6 -5
  415. package/src/TopNav/TopNavMenu.tsx +6 -5
  416. package/src/Typeahead/TypeaheadItem.doc.mjs +6 -3
  417. package/src/Typeahead/TypeaheadItem.tsx +2 -1
  418. package/src/animator/createAnimator.doc.mjs +153 -0
  419. package/src/animator/createAnimator.ts +324 -0
  420. package/src/gestures/GestureHost.ts +198 -20
  421. package/src/gestures/PressTracker.ts +4 -3
  422. package/src/gestures/README.md +7 -1
  423. package/src/hooks/actionGroupTracker.ts +32 -61
  424. package/src/hooks/index.ts +2 -0
  425. package/src/hooks/pressGroupContext.ts +21 -0
  426. package/src/hooks/useActionGroupTracking.ts +224 -0
  427. package/src/hooks/useAnimator.doc.mjs +109 -0
  428. package/src/hooks/useAnimator.ts +67 -0
  429. package/src/hooks/useAttachment.ts +1 -1
  430. package/src/hooks/useHighlightedOptionScroll.ts +123 -15
  431. package/src/hooks/useInputStatusIcon.tsx +3 -2
  432. package/src/hooks/useLongPress.doc.mjs +2 -2
  433. package/src/hooks/useLongPress.ts +136 -15
  434. package/src/hooks/useMediaQuery.doc.mjs +2 -2
  435. package/src/hooks/useMediaQuery.ts +13 -4
  436. package/src/hooks/useMenuPress.ts +8 -2
  437. package/src/i18n/generated-english/InfoTip/InfoTip.generated.ts +13 -0
  438. package/src/i18n/generated-english/PowerSearch/PowerSearch.generated.ts +1 -0
  439. package/src/i18n/generated-english/PowerSearch/PowerSearchBottomSheet.generated.ts +43 -0
  440. package/src/i18n/generated-english/PowerSearch/PowerSearchValueEditor.generated.ts +6 -0
  441. package/src/i18n/generated-english/PowerSearch/formatTokenValue.generated.ts +15 -0
  442. package/src/i18n/generated-english/Tokenizer/TokenizerBottomSheet.generated.ts +7 -1
  443. package/src/i18n/generated-locales/en.generated.ts +43 -0
  444. package/src/i18n/generated-locales/pseudo.generated.ts +44 -0
  445. package/src/index.ts +14 -0
  446. package/src/internal/SheetConfirmation.tsx +101 -0
  447. package/src/internal/indicatorPress.stylex.ts +24 -0
  448. package/src/internal/sheetDraft.ts +80 -0
  449. package/src/internal/touch-sheet.ts +21 -0
  450. package/src/internal/useDismissSearchOnTouchDrag.ts +69 -0
  451. package/src/motion/MEASUREMENTS.md +7 -0
  452. package/src/motion/README.md +9 -5
  453. package/src/motion/animator.ts +61 -29
  454. package/src/motion/reducedMotion.ts +79 -1
  455. package/src/motion/roles.ts +20 -1
  456. package/src/motion/uikit/alert.ts +43 -0
  457. package/src/motion/uikit/index.ts +5 -5
  458. package/src/motion/uikit/segmented.ts +74 -0
  459. package/src/motion/uikit/springs.ts +5 -21
  460. package/src/privateAttributes/pressGroupItem.stylex.ts +23 -0
  461. package/src/privateAttributes/segmentTitle.stylex.ts +22 -0
  462. package/src/utils/browserClickWait.ts +133 -0
  463. package/src/utils/clickGuard.ts +64 -1
  464. package/src/utils/dateParser.ts +16 -0
  465. package/src/utils/focusReturn.ts +30 -0
  466. package/src/utils/interactionOverlay.stylex.ts +3 -2
  467. package/src/utils/pressFeedback.ts +19 -6
  468. package/src/utils/triggerFocus.ts +80 -0
  469. package/dist/internal/tokenizer-presentation.d.ts +0 -21
  470. package/dist/internal/tokenizer-presentation.d.ts.map +0 -1
  471. package/dist/internal/tokenizer-presentation.js +0 -21
  472. package/src/internal/tokenizer-presentation.ts +0 -25
@@ -0,0 +1,368 @@
1
+ // Copyright (c) Meta Platforms, Inc. and affiliates.
2
+
3
+ /**
4
+ * @file resizeGesture.ts
5
+ * @input A handle element, a resize model (its state, and a gesture's start,
6
+ * move, end and cancel), and the handle's axis, reversal and disabled state
7
+ * @output createResizeGesture: the window splitter's input in one place: a
8
+ * pointer drag that holds its pointer, the arrow keys, Home, End and Enter,
9
+ * and a double-click collapse; and the body's drag cursor
10
+ * @position Internal to the Resizable family. ResizeHandle forwards its React
11
+ * events to it. No React, and no DOM work on import
12
+ */
13
+
14
+ import type {ResizableDirection} from './resizableModel';
15
+
16
+ /** Pixels an arrow key moves the separator; Shift moves it further. */
17
+ export const KEYBOARD_STEP = 10;
18
+ export const KEYBOARD_LARGE_STEP = 50;
19
+
20
+ /** What a gesture reads from its region when an input arrives. */
21
+ export interface ResizeGestureState {
22
+ /** The region's size in px, 0 while collapsed. */
23
+ readonly size: number;
24
+ readonly isCollapsed: boolean;
25
+ readonly minPx: number;
26
+ /** The configured maximum, Infinity when the region has none. */
27
+ readonly maxPx: number;
28
+ readonly snaps: ReadonlyArray<number>;
29
+ readonly collapsedSize: number;
30
+ readonly collapsible: boolean;
31
+ }
32
+
33
+ /** The region a gesture resizes. */
34
+ export interface ResizeGestureModel {
35
+ state(): ResizeGestureState;
36
+ /** A gesture begins: the region holds its basis until it ends. */
37
+ start(): void;
38
+ /** The gesture has moved `delta` px from where it began. */
39
+ move(delta: number): void;
40
+ /** The gesture ends as completed. */
41
+ end(): void;
42
+ /** The gesture ends without completing. */
43
+ cancel(): void;
44
+ /**
45
+ * The region's own collapse and expand. They restore the size it had before
46
+ * it collapsed, as the APG window splitter's Enter does. Without them a
47
+ * toggle is a resize gesture to the minimum.
48
+ */
49
+ collapse?: () => void;
50
+ expand?: () => void;
51
+ }
52
+
53
+ /** The handle's configuration, read at each input. */
54
+ export interface ResizeGestureConfig {
55
+ readonly direction: ResizableDirection;
56
+ readonly isReversed: boolean;
57
+ readonly isDisabled: boolean;
58
+ }
59
+
60
+ /** The fields of a pointer event the gesture reads (native or React). */
61
+ export interface ResizeGesturePointerEvent {
62
+ readonly pointerId: number;
63
+ readonly clientX: number;
64
+ readonly clientY: number;
65
+ readonly currentTarget: EventTarget | null;
66
+ preventDefault(): void;
67
+ stopPropagation(): void;
68
+ }
69
+
70
+ /** The fields of a key event the gesture reads (native or React). */
71
+ export interface ResizeGestureKeyEvent {
72
+ readonly key: string;
73
+ readonly shiftKey: boolean;
74
+ preventDefault(): void;
75
+ }
76
+
77
+ export interface ResizeGesture {
78
+ pointerDown(event: ResizeGesturePointerEvent): void;
79
+ pointerMove(event: ResizeGesturePointerEvent): void;
80
+ pointerUp(event: ResizeGesturePointerEvent): void;
81
+ /** A `pointercancel` or a `lostpointercapture`. */
82
+ pointerCancel(event: ResizeGesturePointerEvent): void;
83
+ keyDown(event: ResizeGestureKeyEvent): void;
84
+ doubleClick(): void;
85
+ /** Whether a pointer drag is in flight. */
86
+ readonly isDragging: boolean;
87
+ /**
88
+ * Ends a drag in flight as cancelled, for a handle that goes away mid-drag.
89
+ * It releases the pointer and the body's drag cursor, and tells the region
90
+ * that the gesture is over.
91
+ */
92
+ interrupt(): void;
93
+ }
94
+
95
+ /**
96
+ * Drag feedback lives on the page's `<body>`, not on the handle. During a
97
+ * drag the pointer moves over whatever the panels contain, and the resize
98
+ * cursor must hold there.
99
+ */
100
+ function applyBodyDragStyles(isHorizontal: boolean): void {
101
+ document.body.style.cursor = isHorizontal ? 'col-resize' : 'row-resize';
102
+ document.body.style.userSelect = 'none';
103
+ }
104
+
105
+ function clearBodyDragStyles(): void {
106
+ document.body.style.cursor = '';
107
+ document.body.style.userSelect = '';
108
+ }
109
+
110
+ /**
111
+ * The snap point `count` points away from the region's current size in
112
+ * `direction` (+1 grows, -1 shrinks). A point beyond the minimum or the
113
+ * maximum counts as that bound. When fewer points remain, the nearest end
114
+ * point serves, or the current size when the region is already there.
115
+ */
116
+ function adjacentSnapPoint(
117
+ state: ResizeGestureState,
118
+ direction: 1 | -1,
119
+ count: number,
120
+ ): number {
121
+ const points = [
122
+ ...new Set(
123
+ state.snaps.map(p => Math.min(state.maxPx, Math.max(state.minPx, p))),
124
+ ),
125
+ ].sort((a, b) => a - b);
126
+ const {size} = state;
127
+ const ahead =
128
+ direction > 0
129
+ ? points.filter(p => p > size)
130
+ : points.filter(p => p < size).reverse();
131
+ if (ahead.length === 0) {
132
+ return size;
133
+ }
134
+ return ahead[Math.min(count, ahead.length) - 1];
135
+ }
136
+
137
+ function step(model: ResizeGestureModel, delta: number): void {
138
+ model.start();
139
+ model.move(delta);
140
+ model.end();
141
+ }
142
+
143
+ /**
144
+ * Collapse an open pane, or restore a collapsed one to the size it had before
145
+ * it collapsed, with the region's own collapse and expand. A region without
146
+ * them falls back to a resize gesture to the minimum. That gesture cannot
147
+ * reopen a pane whose minimum sits below its collapse threshold.
148
+ */
149
+ function toggleCollapse(model: ResizeGestureModel): void {
150
+ const state = model.state();
151
+ if (model.collapse != null && model.expand != null) {
152
+ if (state.isCollapsed) {
153
+ model.expand();
154
+ } else {
155
+ model.collapse();
156
+ }
157
+ return;
158
+ }
159
+ step(model, state.isCollapsed ? state.minPx : -state.size);
160
+ }
161
+
162
+ /**
163
+ * The window splitter's input for one handle. A drag takes pointer capture
164
+ * on the element the press landed on. The rest of the gesture then goes to
165
+ * that element. Without capture, the browser hit-tests each move, and an
166
+ * embedded frame under the pointer takes the drag.
167
+ */
168
+ export function createResizeGesture(
169
+ getHandle: () => Element | null,
170
+ model: ResizeGestureModel,
171
+ getConfig: () => ResizeGestureConfig,
172
+ onDraggingChange?: (isDragging: boolean) => void,
173
+ ): ResizeGesture {
174
+ let drag: {
175
+ pointerId: number;
176
+ startPos: number;
177
+ rtl: number;
178
+ target: Element | null;
179
+ } | null = null;
180
+
181
+ const rtlMultiplier = (): number => {
182
+ const handle = getHandle();
183
+ if (handle == null) {
184
+ return 1;
185
+ }
186
+ const view = handle.ownerDocument.defaultView;
187
+ return view?.getComputedStyle(handle).direction === 'rtl' ? -1 : 1;
188
+ };
189
+
190
+ const clearDrag = () => {
191
+ const ending = drag;
192
+ drag = null;
193
+ const target = ending?.target;
194
+ if (
195
+ ending != null &&
196
+ target != null &&
197
+ target.hasPointerCapture?.(ending.pointerId) === true
198
+ ) {
199
+ target.releasePointerCapture(ending.pointerId);
200
+ }
201
+ if (ending != null) {
202
+ clearBodyDragStyles();
203
+ }
204
+ onDraggingChange?.(false);
205
+ };
206
+
207
+ return {
208
+ get isDragging() {
209
+ return drag != null;
210
+ },
211
+
212
+ pointerDown(event) {
213
+ const config = getConfig();
214
+ if (config.isDisabled || drag != null) {
215
+ return;
216
+ }
217
+ event.preventDefault();
218
+ event.stopPropagation();
219
+ // An element from another document (an iframe, a popup) is not an
220
+ // instance of this page's Element, so test for the capture API itself.
221
+ const current = event.currentTarget as Element | null;
222
+ const target =
223
+ typeof current?.setPointerCapture === 'function' ? current : null;
224
+ target?.setPointerCapture?.(event.pointerId);
225
+ const isHorizontal = config.direction === 'horizontal';
226
+ drag = {
227
+ pointerId: event.pointerId,
228
+ startPos: isHorizontal ? event.clientX : event.clientY,
229
+ rtl: isHorizontal ? rtlMultiplier() : 1,
230
+ target,
231
+ };
232
+ onDraggingChange?.(true);
233
+ model.start();
234
+ applyBodyDragStyles(isHorizontal);
235
+ },
236
+
237
+ pointerMove(event) {
238
+ if (drag == null || drag.pointerId !== event.pointerId) {
239
+ return;
240
+ }
241
+ const config = getConfig();
242
+ const position =
243
+ config.direction === 'horizontal' ? event.clientX : event.clientY;
244
+ const sign = config.isReversed ? -1 : 1;
245
+ model.move((position - drag.startPos) * drag.rtl * sign);
246
+ },
247
+
248
+ pointerUp(event) {
249
+ if (drag?.pointerId !== event.pointerId) {
250
+ return;
251
+ }
252
+ clearDrag();
253
+ model.end();
254
+ },
255
+
256
+ // Serves pointercancel and lostpointercapture alike: an interrupted drag
257
+ // ends without a resize end. The implicit release after every pointerup
258
+ // or pointercancel also fires lostpointercapture. By then the drag is
259
+ // already cleared, and this is a no-op.
260
+ pointerCancel(event) {
261
+ if (drag?.pointerId !== event.pointerId) {
262
+ return;
263
+ }
264
+ clearDrag();
265
+ model.cancel();
266
+ },
267
+
268
+ interrupt() {
269
+ if (drag == null) {
270
+ return;
271
+ }
272
+ clearDrag();
273
+ model.cancel();
274
+ },
275
+
276
+ keyDown(event) {
277
+ const config = getConfig();
278
+ if (config.isDisabled) {
279
+ return;
280
+ }
281
+ const state = model.state();
282
+ const isHorizontal = config.direction === 'horizontal';
283
+ const sign = config.isReversed ? -1 : 1;
284
+ const keyStep = event.shiftKey ? KEYBOARD_LARGE_STEP : KEYBOARD_STEP;
285
+ const rtl = isHorizontal ? rtlMultiplier() : 1;
286
+
287
+ // The pane's grow direction on this key: ArrowRight/Down grow unless the
288
+ // layout is reversed or, on the inline axis, right-to-left.
289
+ const grows = (key: string) =>
290
+ (key === 'ArrowRight' || key === 'ArrowDown'
291
+ ? 1
292
+ : key === 'ArrowLeft' || key === 'ArrowUp'
293
+ ? -1
294
+ : 0) *
295
+ (isHorizontal ? rtl : 1) *
296
+ sign >
297
+ 0;
298
+
299
+ switch (event.key) {
300
+ case 'ArrowRight':
301
+ case 'ArrowDown':
302
+ case 'ArrowLeft':
303
+ case 'ArrowUp': {
304
+ event.preventDefault();
305
+ if (state.isCollapsed) {
306
+ // A collapsed pane answers only the grow arrow. It opens one step
307
+ // above its minimum, the value the separator announces while
308
+ // collapsed. If the collapse threshold is larger, it opens there.
309
+ // A bare step would stay below the threshold and leave the pane
310
+ // closed. The shrink arrow is a no-op.
311
+ if (grows(event.key)) {
312
+ step(model, Math.max(state.minPx + keyStep, state.collapsedSize));
313
+ }
314
+ break;
315
+ }
316
+ if (state.snaps.length > 0) {
317
+ // With snap points the region rests only on a point, so a pixel
318
+ // step would snap straight back. The arrow moves to the adjacent
319
+ // point in its direction instead, two points with Shift, within
320
+ // the bounds.
321
+ step(
322
+ model,
323
+ adjacentSnapPoint(
324
+ state,
325
+ grows(event.key) ? 1 : -1,
326
+ event.shiftKey ? 2 : 1,
327
+ ) - state.size,
328
+ );
329
+ break;
330
+ }
331
+ const direction =
332
+ event.key === 'ArrowRight' || event.key === 'ArrowDown' ? 1 : -1;
333
+ step(model, direction * keyStep * (isHorizontal ? rtl : 1) * sign);
334
+ break;
335
+ }
336
+ case 'Home': {
337
+ event.preventDefault();
338
+ step(model, state.minPx - state.size);
339
+ break;
340
+ }
341
+ case 'End': {
342
+ event.preventDefault();
343
+ // Only a configured maximum is the region's own limit. The reported
344
+ // stand-in for an unbounded region is where the pane could reach,
345
+ // not where End may move it.
346
+ if (state.maxPx !== Infinity) {
347
+ step(model, state.maxPx - state.size);
348
+ }
349
+ break;
350
+ }
351
+ case 'Enter': {
352
+ event.preventDefault();
353
+ if (state.collapsible) {
354
+ toggleCollapse(model);
355
+ }
356
+ break;
357
+ }
358
+ }
359
+ },
360
+
361
+ doubleClick() {
362
+ if (getConfig().isDisabled || !model.state().collapsible) {
363
+ return;
364
+ }
365
+ toggleCollapse(model);
366
+ },
367
+ };
368
+ }
@@ -168,7 +168,7 @@ function WorkspaceCard() {
168
168
  usage: {
169
169
  anatomy,
170
170
  description:
171
- 'A segmented button group that allows users to make a single selection from a small set of mutually exclusive options. Use SegmentedControl when all options should be visible at once and the selection controls a value or mode, not page navigation.',
171
+ 'A segmented button group that allows users to make a single selection from a small set of mutually exclusive options. Use SegmentedControl when all options should be visible at once and the selection controls a value or mode, not page navigation. Under a finger, on a touch device (a coarse primary pointer), the selection slides to the new segment, whether a tap, an arrow key or a new value moved it; with Reduce Motion nothing travels: the old selection fades out as the new one fades in. There, dragging the selected segment carries the selection along with the selected label’s colour following it, and the segment under the finger is chosen when it lets go (letting go outside the control selects nothing); a tap selects through the browser’s click; a pressed segment shows the shared pressed overlay, and nothing lifts or dims. With a mouse or a pen every change, a click included, slides on the theme’s duration and easing, and dragging the selected segment carries it as a finger does.',
172
172
  accessibility: [
173
173
  {
174
174
  name: 'Text label',
@@ -240,7 +240,7 @@ export const docsZh = {
240
240
  usage: {
241
241
  anatomy,
242
242
  description:
243
- 'A segmented button group that allows users to make a single selection from a small set of mutually exclusive options. Use SegmentedControl when all options should be visible at once and the selection controls a value or mode, not page navigation.',
243
+ 'A segmented button group that allows users to make a single selection from a small set of mutually exclusive options. Use SegmentedControl when all options should be visible at once and the selection controls a value or mode, not page navigation. Under a finger, on a touch device (a coarse primary pointer), the selection slides to the new segment, whether a tap, an arrow key or a new value moved it; with Reduce Motion nothing travels: the old selection fades out as the new one fades in. There, dragging the selected segment carries the selection along with the selected label’s colour following it, and the segment under the finger is chosen when it lets go (letting go outside the control selects nothing); a tap selects through the browser’s click; a pressed segment shows the shared pressed overlay, and nothing lifts or dims. With a mouse or a pen every change, a click included, slides on the theme’s duration and easing, and dragging the selected segment carries it as a finger does.',
244
244
  bestPractices: [
245
245
  {guidance: true, description: 'Use for switching between 2–5 mutually exclusive views or modes where all options should be visible.'},
246
246
  {guidance: true, description: 'Provide a descriptive label for the control to ensure the group is accessible to screen readers.'},
@@ -256,7 +256,7 @@ export const docsDense = {
256
256
  usage: {
257
257
  anatomy,
258
258
  description:
259
- 'A segmented button group that allows users to make a single selection from a small set of mutually exclusive options. Use SegmentedControl when all options should be visible at once and the selection controls a value or mode, not page navigation.',
259
+ 'A segmented button group that allows users to make a single selection from a small set of mutually exclusive options. Use SegmentedControl when all options should be visible at once and the selection controls a value or mode, not page navigation. Under a finger, on a touch device (a coarse primary pointer), the selection slides to the new segment, whether a tap, an arrow key or a new value moved it; with Reduce Motion nothing travels: the old selection fades out as the new one fades in. There, dragging the selected segment carries the selection along with the selected label’s colour following it, and the segment under the finger is chosen when it lets go (letting go outside the control selects nothing); a tap selects through the browser’s click; a pressed segment shows the shared pressed overlay, and nothing lifts or dims. With a mouse or a pen every change, a click included, slides on the theme’s duration and easing, and dragging the selected segment carries it as a finger does.',
260
260
  bestPractices: [
261
261
  {guidance: true, description: 'Use for switching between 2–5 mutually exclusive views or modes where all options should be visible.'},
262
262
  {guidance: true, description: 'Provide a descriptive label for the control to ensure the group is accessible to screen readers.'},
@@ -4,7 +4,8 @@
4
4
 
5
5
  /**
6
6
  * @file SegmentedControl.tsx
7
- * @input Uses React, StyleX, SegmentedControlContext, useListFocus, useKeyboardHint
7
+ * @input Uses React, StyleX, SegmentedControlContext, useListFocus,
8
+ * useKeyboardHint, useTouchPresentation, useSegmentedSelectionMotion
8
9
  * @output Exports SegmentedControl component and SegmentedControlProps type
9
10
  * @position Container wrapper; provides context to SegmentedControlItem children
10
11
  *
@@ -12,10 +13,11 @@
12
13
  * - /packages/core/src/SegmentedControl/SegmentedControl.doc.mjs
13
14
  * - /packages/core/src/SegmentedControl/index.ts
14
15
  * - /packages/core/src/SegmentedControl/SegmentedControl.test.tsx
16
+ * - /packages/core/src/SegmentedControl/useSegmentedSelectionMotion.ts
15
17
  * - /packages/cli/assets/templates/blocks/components/SegmentedControl/ (showcase blocks)
16
18
  */
17
19
 
18
- import React, {useMemo, useCallback, type ReactNode} from 'react';
20
+ import React, {useMemo, useCallback, useRef, type ReactNode} from 'react';
19
21
  import * as stylex from '@stylexjs/stylex';
20
22
  import {colorVars, spacingVars, radiusVars} from '../theme/tokens.stylex';
21
23
  import {SegmentedControlContext} from './SegmentedControlContext';
@@ -34,6 +36,9 @@ import type {BaseProps} from '../BaseProps';
34
36
  import {themeProps} from '../utils/themeProps';
35
37
 
36
38
  import {useMergedRefs} from '../hooks/useMergedRefs';
39
+ import {useTouchPresentation} from '../utils/touchPresentation';
40
+ import {useSegmentedSelectionMotion} from './useSegmentedSelectionMotion';
41
+
37
42
  export interface SegmentedControlProps extends Omit<
38
43
  BaseProps<HTMLDivElement>,
39
44
  'onChange'
@@ -94,6 +99,11 @@ export interface SegmentedControlProps extends Omit<
94
99
 
95
100
  const styles = stylex.create({
96
101
  container: {
102
+ // The lens's containing block and stacking context. The lens sits at
103
+ // z-index -1 inside it: above the track's own background, below every
104
+ // segment.
105
+ position: 'relative',
106
+ isolation: 'isolate',
97
107
  display: 'inline-flex',
98
108
  alignItems: 'center',
99
109
  width: 'fit-content',
@@ -127,6 +137,140 @@ const styles = stylex.create({
127
137
  disabled: {
128
138
  opacity: 0.5,
129
139
  },
140
+ // The lens uses the radiogroup's own pseudo-elements, so it adds no
141
+ // element. ::before carries the selected surface. Under Reduced Motion,
142
+ // ::after is the old surface that fades out in place. Both are hidden at
143
+ // rest. A negative z-index keeps them under every segment's content, inside
144
+ // the stacking context the container's isolation makes. Above the segments,
145
+ // a moving lens could paint over their titles. WebKit's overlap test can
146
+ // miss what a moving layer covers.
147
+ lens: {
148
+ '::before': {
149
+ content: '""',
150
+ position: 'absolute',
151
+ zIndex: -1,
152
+ // eslint-disable-next-line @astryx/no-physical-properties -- intentional: laid out on a segment's box measured from client rects (useSegmentedSelectionMotion), in both directions.
153
+ left: 'var(--_segmented-lens-left, 0px)',
154
+ top: 'var(--_segmented-lens-top, 0px)',
155
+ width: 'var(--_segmented-lens-width, 0px)',
156
+ height: 'var(--_segmented-lens-height, 0px)',
157
+ boxSizing: 'border-box',
158
+ // Scales around its center: the lens's position and size are separate.
159
+ transformOrigin: '50% 50%',
160
+ pointerEvents: 'none',
161
+ visibility: 'var(--_segmented-lens-visibility, hidden)',
162
+ willChange: 'var(--astryx-motion-will-change-before, auto)',
163
+ // It carries a copy of an already resolved surface, forced colors
164
+ // included (Highlight), so the UA must not remap it again.
165
+ forcedColorAdjust: 'none',
166
+ backgroundColor: 'var(--_segmented-lens-background-color, transparent)',
167
+ backgroundImage: 'var(--_segmented-lens-background-image, none)',
168
+ backgroundPosition: 'var(--_segmented-lens-background-position, 0% 0%)',
169
+ backgroundSize: 'var(--_segmented-lens-background-size, auto)',
170
+ backgroundRepeat: 'var(--_segmented-lens-background-repeat, repeat)',
171
+ backgroundOrigin: 'var(--_segmented-lens-background-origin, padding-box)',
172
+ backgroundClip: 'var(--_segmented-lens-background-clip, border-box)',
173
+ boxShadow: 'var(--_segmented-lens-box-shadow, none)',
174
+ // eslint-disable-next-line @astryx/no-physical-properties -- intentional: a copy of the segment's computed (physical) surface.
175
+ borderTopLeftRadius: 'var(--_segmented-lens-border-top-left-radius, 0px)',
176
+ // eslint-disable-next-line @astryx/no-physical-properties -- intentional: a copy of the segment's computed (physical) surface.
177
+ borderTopRightRadius:
178
+ 'var(--_segmented-lens-border-top-right-radius, 0px)',
179
+ // eslint-disable-next-line @astryx/no-physical-properties -- intentional: a copy of the segment's computed (physical) surface.
180
+ borderBottomRightRadius:
181
+ 'var(--_segmented-lens-border-bottom-right-radius, 0px)',
182
+ // eslint-disable-next-line @astryx/no-physical-properties -- intentional: a copy of the segment's computed (physical) surface.
183
+ borderBottomLeftRadius:
184
+ 'var(--_segmented-lens-border-bottom-left-radius, 0px)',
185
+ borderTopWidth: 'var(--_segmented-lens-border-top-width, 0px)',
186
+ // eslint-disable-next-line @astryx/no-physical-properties -- intentional: a copy of the segment's computed (physical) surface.
187
+ borderRightWidth: 'var(--_segmented-lens-border-right-width, 0px)',
188
+ borderBottomWidth: 'var(--_segmented-lens-border-bottom-width, 0px)',
189
+ // eslint-disable-next-line @astryx/no-physical-properties -- intentional: a copy of the segment's computed (physical) surface.
190
+ borderLeftWidth: 'var(--_segmented-lens-border-left-width, 0px)',
191
+ borderTopStyle: 'var(--_segmented-lens-border-top-style, none)',
192
+ // eslint-disable-next-line @astryx/no-physical-properties -- intentional: a copy of the segment's computed (physical) surface.
193
+ borderRightStyle: 'var(--_segmented-lens-border-right-style, none)',
194
+ borderBottomStyle: 'var(--_segmented-lens-border-bottom-style, none)',
195
+ // eslint-disable-next-line @astryx/no-physical-properties -- intentional: a copy of the segment's computed (physical) surface.
196
+ borderLeftStyle: 'var(--_segmented-lens-border-left-style, none)',
197
+ borderTopColor: 'var(--_segmented-lens-border-top-color, currentcolor)',
198
+ // eslint-disable-next-line @astryx/no-physical-properties -- intentional: a copy of the segment's computed (physical) surface.
199
+ borderRightColor:
200
+ 'var(--_segmented-lens-border-right-color, currentcolor)',
201
+ borderBottomColor:
202
+ 'var(--_segmented-lens-border-bottom-color, currentcolor)',
203
+ // eslint-disable-next-line @astryx/no-physical-properties -- intentional: a copy of the segment's computed (physical) surface.
204
+ borderLeftColor: 'var(--_segmented-lens-border-left-color, currentcolor)',
205
+ backdropFilter: 'var(--_segmented-lens-backdrop-filter, none)',
206
+ WebkitBackdropFilter:
207
+ 'var(--_segmented-lens-webkit-backdrop-filter, none)',
208
+ },
209
+ '::after': {
210
+ content: '""',
211
+ position: 'absolute',
212
+ zIndex: -1,
213
+ // eslint-disable-next-line @astryx/no-physical-properties -- intentional: laid out on a segment's box measured from client rects (useSegmentedSelectionMotion), in both directions.
214
+ left: 'var(--_segmented-after-left, 0px)',
215
+ top: 'var(--_segmented-after-top, 0px)',
216
+ width: 'var(--_segmented-after-width, 0px)',
217
+ height: 'var(--_segmented-after-height, 0px)',
218
+ boxSizing: 'border-box',
219
+ // Scales around its center: the lens's position and size are separate.
220
+ transformOrigin: '50% 50%',
221
+ pointerEvents: 'none',
222
+ visibility: 'var(--_segmented-after-visibility, hidden)',
223
+ willChange: 'var(--astryx-motion-will-change-after, auto)',
224
+ // It carries a copy of an already resolved surface, forced colors
225
+ // included (Highlight), so the UA must not remap it again.
226
+ forcedColorAdjust: 'none',
227
+ backgroundColor: 'var(--_segmented-after-background-color, transparent)',
228
+ backgroundImage: 'var(--_segmented-after-background-image, none)',
229
+ backgroundPosition: 'var(--_segmented-after-background-position, 0% 0%)',
230
+ backgroundSize: 'var(--_segmented-after-background-size, auto)',
231
+ backgroundRepeat: 'var(--_segmented-after-background-repeat, repeat)',
232
+ backgroundOrigin:
233
+ 'var(--_segmented-after-background-origin, padding-box)',
234
+ backgroundClip: 'var(--_segmented-after-background-clip, border-box)',
235
+ boxShadow: 'var(--_segmented-after-box-shadow, none)',
236
+ // eslint-disable-next-line @astryx/no-physical-properties -- intentional: a copy of the segment's computed (physical) surface.
237
+ borderTopLeftRadius:
238
+ 'var(--_segmented-after-border-top-left-radius, 0px)',
239
+ // eslint-disable-next-line @astryx/no-physical-properties -- intentional: a copy of the segment's computed (physical) surface.
240
+ borderTopRightRadius:
241
+ 'var(--_segmented-after-border-top-right-radius, 0px)',
242
+ // eslint-disable-next-line @astryx/no-physical-properties -- intentional: a copy of the segment's computed (physical) surface.
243
+ borderBottomRightRadius:
244
+ 'var(--_segmented-after-border-bottom-right-radius, 0px)',
245
+ // eslint-disable-next-line @astryx/no-physical-properties -- intentional: a copy of the segment's computed (physical) surface.
246
+ borderBottomLeftRadius:
247
+ 'var(--_segmented-after-border-bottom-left-radius, 0px)',
248
+ borderTopWidth: 'var(--_segmented-after-border-top-width, 0px)',
249
+ // eslint-disable-next-line @astryx/no-physical-properties -- intentional: a copy of the segment's computed (physical) surface.
250
+ borderRightWidth: 'var(--_segmented-after-border-right-width, 0px)',
251
+ borderBottomWidth: 'var(--_segmented-after-border-bottom-width, 0px)',
252
+ // eslint-disable-next-line @astryx/no-physical-properties -- intentional: a copy of the segment's computed (physical) surface.
253
+ borderLeftWidth: 'var(--_segmented-after-border-left-width, 0px)',
254
+ borderTopStyle: 'var(--_segmented-after-border-top-style, none)',
255
+ // eslint-disable-next-line @astryx/no-physical-properties -- intentional: a copy of the segment's computed (physical) surface.
256
+ borderRightStyle: 'var(--_segmented-after-border-right-style, none)',
257
+ borderBottomStyle: 'var(--_segmented-after-border-bottom-style, none)',
258
+ // eslint-disable-next-line @astryx/no-physical-properties -- intentional: a copy of the segment's computed (physical) surface.
259
+ borderLeftStyle: 'var(--_segmented-after-border-left-style, none)',
260
+ borderTopColor: 'var(--_segmented-after-border-top-color, currentcolor)',
261
+ // eslint-disable-next-line @astryx/no-physical-properties -- intentional: a copy of the segment's computed (physical) surface.
262
+ borderRightColor:
263
+ 'var(--_segmented-after-border-right-color, currentcolor)',
264
+ borderBottomColor:
265
+ 'var(--_segmented-after-border-bottom-color, currentcolor)',
266
+ // eslint-disable-next-line @astryx/no-physical-properties -- intentional: a copy of the segment's computed (physical) surface.
267
+ borderLeftColor:
268
+ 'var(--_segmented-after-border-left-color, currentcolor)',
269
+ backdropFilter: 'var(--_segmented-after-backdrop-filter, none)',
270
+ WebkitBackdropFilter:
271
+ 'var(--_segmented-after-webkit-backdrop-filter, none)',
272
+ },
273
+ },
130
274
  });
131
275
 
132
276
  const sizeStyles = stylex.create({
@@ -177,6 +321,20 @@ export function SegmentedControl({
177
321
  ...rest
178
322
  }: SegmentedControlProps) {
179
323
  const size = useSize(sizeProp, 'md');
324
+ // A touch device (a coarse primary pointer) gets UIKit's motion: the
325
+ // selection slides on a spring. Under a mouse it slides on the theme's
326
+ // duration and easing.
327
+ const isTouchPresentation = useTouchPresentation().isTouch;
328
+ const trackRef = useRef<HTMLDivElement | null>(null);
329
+ // Every pointer's press is tracked. A drag from the selected segment
330
+ // carries the lens, and the lift commits the segment nearest the pointer.
331
+ // A lift outside the control commits nothing.
332
+ const {selection, attachTrack} = useSegmentedSelectionMotion(
333
+ trackRef,
334
+ value,
335
+ isTouchPresentation,
336
+ !isDisabled,
337
+ );
180
338
 
181
339
  // Disabled-reason tooltip. Applies to the whole-group disabled state. The
182
340
  // tooltip listeners attach to the radiogroup container, which keeps pointer
@@ -215,6 +373,7 @@ export function SegmentedControl({
215
373
 
216
374
  const handleContainerKeyDown = useCallback(
217
375
  (e: React.KeyboardEvent<HTMLDivElement>) => {
376
+ selection.keyPressed();
218
377
  onKeyDownProp?.(e);
219
378
  if (e.defaultPrevented) {
220
379
  return;
@@ -222,7 +381,7 @@ export function SegmentedControl({
222
381
  hint.onKeyDown(e);
223
382
  handleKeyDown(e);
224
383
  },
225
- [onKeyDownProp, hint, handleKeyDown],
384
+ [selection, onKeyDownProp, hint, handleKeyDown],
226
385
  );
227
386
 
228
387
  // Selection-follows-focus (APG radiogroup): useListFocus only *moves* focus,
@@ -252,6 +411,12 @@ export function SegmentedControl({
252
411
  if (!e.currentTarget.contains(e.relatedTarget)) {
253
412
  return;
254
413
  }
414
+ // A mouse or pen press moves focus at pointerdown. A finger moves it
415
+ // after the lift, before the tap's click. The press commits through
416
+ // that click, so this focus move selects nothing.
417
+ if (selection.isPressing()) {
418
+ return;
419
+ }
255
420
  const focused = (e.target as HTMLElement | null)?.closest<HTMLElement>(
256
421
  '[role="radio"][data-value]',
257
422
  );
@@ -263,7 +428,7 @@ export function SegmentedControl({
263
428
  onChange(nextValue);
264
429
  }
265
430
  },
266
- [onFocusProp, hint, handleFocus, isDisabled, onChange, value],
431
+ [onFocusProp, hint, handleFocus, isDisabled, onChange, selection, value],
267
432
  );
268
433
 
269
434
  const contextValue = useMemo(
@@ -276,6 +441,7 @@ export function SegmentedControl({
276
441
  disabledReasonID: showsDisabledMessage
277
442
  ? disabledMessageTooltip.describedBy
278
443
  : undefined,
444
+ isTouchPresentation,
279
445
  }),
280
446
  [
281
447
  value,
@@ -285,13 +451,20 @@ export function SegmentedControl({
285
451
  isDisabled,
286
452
  showsDisabledMessage,
287
453
  disabledMessageTooltip.describedBy,
454
+ isTouchPresentation,
288
455
  ],
289
456
  );
290
457
 
291
458
  return (
292
459
  <SegmentedControlContext value={contextValue}>
293
460
  <div
294
- ref={useMergedRefs(ref, listRef, disabledMessageTooltip.ref)}
461
+ ref={useMergedRefs(
462
+ ref,
463
+ listRef,
464
+ trackRef,
465
+ attachTrack,
466
+ disabledMessageTooltip.ref,
467
+ )}
295
468
  {...rest}
296
469
  role="radiogroup"
297
470
  aria-label={label}
@@ -310,6 +483,7 @@ export function SegmentedControl({
310
483
  styles.container,
311
484
  sizeStyles[size],
312
485
  layout === 'fill' && styles.fill,
486
+ (isTouchPresentation || !isDisabled) && styles.lens,
313
487
  isDisabled && styles.disabled,
314
488
  xstyle,
315
489
  ),