@astryxdesign/core 0.7.8 → 0.7.9-canary.07992bb

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 (403) hide show
  1. package/dist/AppShell/observeMainOverflow.d.ts.map +1 -1
  2. package/dist/AppShell/observeMainOverflow.js +9 -6
  3. package/dist/BottomSheet/BottomSheet.d.ts.map +1 -1
  4. package/dist/BottomSheet/BottomSheet.js +5 -0
  5. package/dist/BottomSheet/BottomSheetPanel.d.ts.map +1 -1
  6. package/dist/BottomSheet/BottomSheetPanel.js +40 -8
  7. package/dist/BottomSheet/useSheetGestures.d.ts.map +1 -1
  8. package/dist/BottomSheet/useSheetGestures.js +61 -21
  9. package/dist/Calendar/Calendar.d.ts +14 -2
  10. package/dist/Calendar/Calendar.d.ts.map +1 -1
  11. package/dist/Calendar/Calendar.js +63 -74
  12. package/dist/Calendar/getInitialFocusDate.d.ts +4 -1
  13. package/dist/Calendar/getInitialFocusDate.d.ts.map +1 -1
  14. package/dist/Calendar/getInitialFocusDate.js +7 -5
  15. package/dist/Calendar/hooks/useCalendarDays.d.ts +19 -2
  16. package/dist/Calendar/hooks/useCalendarDays.d.ts.map +1 -1
  17. package/dist/Calendar/hooks/useCalendarDays.js +57 -64
  18. package/dist/Calendar/hooks/useCalendarNavigation.d.ts +28 -3
  19. package/dist/Calendar/hooks/useCalendarNavigation.d.ts.map +1 -1
  20. package/dist/Calendar/hooks/useCalendarNavigation.js +33 -22
  21. package/dist/Calendar/styles.d.ts +1 -1
  22. package/dist/CheckboxInput/CheckboxInput.d.ts.map +1 -1
  23. package/dist/CheckboxInput/CheckboxInput.js +54 -11
  24. package/dist/ClickableCard/ClickableCard.d.ts +1 -1
  25. package/dist/ClickableCard/ClickableCard.d.ts.map +1 -1
  26. package/dist/ClickableCard/ClickableCard.js +5 -1
  27. package/dist/DateInput/DateInput.d.ts.map +1 -1
  28. package/dist/DateInput/DateInput.js +4 -1
  29. package/dist/DateInput/PickerWheel.d.ts.map +1 -1
  30. package/dist/DateInput/PickerWheel.js +7 -1
  31. package/dist/DateRangeInput/DateRangeInput.d.ts.map +1 -1
  32. package/dist/DateRangeInput/DateRangeInput.js +5 -2
  33. package/dist/DateTimeInput/DateTimeInput.d.ts.map +1 -1
  34. package/dist/DateTimeInput/DateTimeInput.js +4 -1
  35. package/dist/Dialog/Dialog.d.ts +2 -1
  36. package/dist/Dialog/Dialog.d.ts.map +1 -1
  37. package/dist/Dialog/Dialog.js +12 -1
  38. package/dist/Drawer/useDrawerDialogPresence.d.ts +2 -1
  39. package/dist/Drawer/useDrawerDialogPresence.d.ts.map +1 -1
  40. package/dist/Drawer/useDrawerDialogPresence.js +11 -2
  41. package/dist/DropdownMenu/DropdownMenu.d.ts +9 -1
  42. package/dist/DropdownMenu/DropdownMenu.d.ts.map +1 -1
  43. package/dist/DropdownMenu/DropdownMenu.js +9 -4
  44. package/dist/DropdownMenu/DropdownMenuCheckboxItem.d.ts.map +1 -1
  45. package/dist/DropdownMenu/DropdownMenuCheckboxItem.js +3 -2
  46. package/dist/DropdownMenu/DropdownMenuItem.d.ts.map +1 -1
  47. package/dist/DropdownMenu/DropdownMenuItem.js +3 -2
  48. package/dist/DropdownMenu/DropdownMenuRadioItem.d.ts.map +1 -1
  49. package/dist/DropdownMenu/DropdownMenuRadioItem.js +3 -2
  50. package/dist/DropdownMenu/DropdownMenuSubMenu.d.ts.map +1 -1
  51. package/dist/DropdownMenu/DropdownMenuSubMenu.js +3 -2
  52. package/dist/Field/inputDisabledFocus.d.ts +4 -4
  53. package/dist/Field/inputStyles.stylex.d.ts +1 -1
  54. package/dist/FileInput/FileInput.d.ts.map +1 -1
  55. package/dist/FileInput/FileInput.js +16 -2
  56. package/dist/HoverCard/useHoverCard.d.ts +3 -1
  57. package/dist/HoverCard/useHoverCard.d.ts.map +1 -1
  58. package/dist/Icon/Icon.d.ts +1 -1
  59. package/dist/InfoTip/InfoTip.d.ts +1 -0
  60. package/dist/InfoTip/InfoTip.d.ts.map +1 -1
  61. package/dist/InfoTip/InfoTip.js +1 -0
  62. package/dist/InputGroup/InputGroup.d.ts +4 -3
  63. package/dist/InputGroup/InputGroup.d.ts.map +1 -1
  64. package/dist/InputGroup/InputGroup.js +2 -2
  65. package/dist/InputGroup/groupStyles.d.ts +1 -1
  66. package/dist/InputGroup/groupStyles.d.ts.map +1 -1
  67. package/dist/InputGroup/groupStyles.js +1 -1
  68. package/dist/Item/Item.d.ts +2 -1
  69. package/dist/Item/Item.d.ts.map +1 -1
  70. package/dist/Item/Item.js +29 -6
  71. package/dist/Layer/holdEntranceInput.d.ts +24 -0
  72. package/dist/Layer/holdEntranceInput.d.ts.map +1 -0
  73. package/dist/Layer/holdEntranceInput.js +65 -0
  74. package/dist/Layer/inputHold.d.ts +49 -0
  75. package/dist/Layer/inputHold.d.ts.map +1 -0
  76. package/dist/Layer/inputHold.js +636 -0
  77. package/dist/Layer/preserveAnimations.d.ts +1 -5
  78. package/dist/Layer/preserveAnimations.d.ts.map +1 -1
  79. package/dist/Layer/preserveAnimations.js +12 -214
  80. package/dist/Layer/useLayer.d.ts +3 -1
  81. package/dist/Layer/useLayer.d.ts.map +1 -1
  82. package/dist/Layer/useLayer.js +64 -4
  83. package/dist/Layout/LayoutContent.d.ts +3 -1
  84. package/dist/Layout/LayoutContent.d.ts.map +1 -1
  85. package/dist/Layout/LayoutContent.js +12 -4
  86. package/dist/Layout/LayoutPanel.d.ts +4 -1
  87. package/dist/Layout/LayoutPanel.d.ts.map +1 -1
  88. package/dist/Layout/LayoutPanel.js +13 -4
  89. package/dist/Lightbox/Lightbox.d.ts.map +1 -1
  90. package/dist/Lightbox/Lightbox.js +4 -0
  91. package/dist/MetadataList/MetadataList.js +1 -1
  92. package/dist/MobileNav/MobileNav.d.ts +11 -1
  93. package/dist/MobileNav/MobileNav.d.ts.map +1 -1
  94. package/dist/MobileNav/MobileNav.js +39 -1
  95. package/dist/MoreMenu/MoreMenu.d.ts +5 -3
  96. package/dist/MoreMenu/MoreMenu.d.ts.map +1 -1
  97. package/dist/NumberInput/NumberInput.d.ts +4 -2
  98. package/dist/NumberInput/NumberInput.d.ts.map +1 -1
  99. package/dist/NumberInput/NumberInput.js +244 -11
  100. package/dist/Popover/usePopover.d.ts +1 -0
  101. package/dist/Popover/usePopover.d.ts.map +1 -1
  102. package/dist/PowerSearch/PowerSearch.d.ts.map +1 -1
  103. package/dist/PowerSearch/PowerSearch.js +12 -5
  104. package/dist/PowerSearch/PowerSearchBottomSheet.d.ts.map +1 -1
  105. package/dist/PowerSearch/PowerSearchBottomSheet.js +4 -2
  106. package/dist/PowerSearch/PowerSearchToken.d.ts.map +1 -1
  107. package/dist/PowerSearch/PowerSearchToken.js +3 -1
  108. package/dist/PowerSearch/formatFilterValue.d.ts +9 -3
  109. package/dist/PowerSearch/formatFilterValue.d.ts.map +1 -1
  110. package/dist/PowerSearch/formatFilterValue.js +14 -11
  111. package/dist/PowerSearch/formatTokenValue.d.ts +6 -2
  112. package/dist/PowerSearch/formatTokenValue.d.ts.map +1 -1
  113. package/dist/PowerSearch/formatTokenValue.js +6 -3
  114. package/dist/RadioList/RadioListItem.d.ts.map +1 -1
  115. package/dist/RadioList/RadioListItem.js +22 -4
  116. package/dist/SelectableCard/SelectableCard.d.ts +1 -1
  117. package/dist/SelectableCard/SelectableCard.d.ts.map +1 -1
  118. package/dist/SelectableCard/SelectableCard.js +5 -1
  119. package/dist/Spinner/Spinner.d.ts.map +1 -1
  120. package/dist/Spinner/Spinner.js +14 -71
  121. package/dist/Spinner/index.d.ts +1 -1
  122. package/dist/Spinner/index.d.ts.map +1 -1
  123. package/dist/Spinner/spinnerRotor.d.ts +28 -0
  124. package/dist/Spinner/spinnerRotor.d.ts.map +1 -0
  125. package/dist/Spinner/spinnerRotor.js +98 -0
  126. package/dist/Stack/StackItem.d.ts +8 -4
  127. package/dist/Stack/StackItem.d.ts.map +1 -1
  128. package/dist/Stack/StackItem.js +17 -4
  129. package/dist/Switch/Switch.d.ts.map +1 -1
  130. package/dist/Switch/Switch.js +13 -10
  131. package/dist/Table/plugins/sortable/useTableSortable.js +1 -1
  132. package/dist/Timestamp/Timestamp.d.ts.map +1 -1
  133. package/dist/Timestamp/Timestamp.js +14 -8
  134. package/dist/Timestamp/formatInstant.d.ts +10 -1
  135. package/dist/Timestamp/formatInstant.d.ts.map +1 -1
  136. package/dist/Timestamp/formatInstant.js +13 -27
  137. package/dist/Timestamp/tooltipEntries.d.ts +5 -3
  138. package/dist/Timestamp/tooltipEntries.d.ts.map +1 -1
  139. package/dist/Timestamp/tooltipEntries.js +6 -4
  140. package/dist/Token/Token.d.ts.map +1 -1
  141. package/dist/Token/Token.js +9 -0
  142. package/dist/Token/TokenLink.d.ts +1 -1
  143. package/dist/Token/TokenLink.d.ts.map +1 -1
  144. package/dist/Token/TokenLink.js +4 -1
  145. package/dist/Tokenizer/Tokenizer.d.ts +14 -10
  146. package/dist/Tokenizer/Tokenizer.d.ts.map +1 -1
  147. package/dist/Tokenizer/Tokenizer.js +189 -89
  148. package/dist/Tooltip/useTooltip.d.ts +3 -1
  149. package/dist/Tooltip/useTooltip.d.ts.map +1 -1
  150. package/dist/Tooltip/useTooltip.js +162 -59
  151. package/dist/TreeList/TreeListItem.d.ts +2 -1
  152. package/dist/TreeList/TreeListItem.d.ts.map +1 -1
  153. package/dist/TreeList/TreeListItem.js +27 -3
  154. package/dist/astryx.css +45 -18
  155. package/dist/gestures/GestureHost.d.ts +2 -2
  156. package/dist/gestures/GestureHost.d.ts.map +1 -1
  157. package/dist/gestures/GestureHost.js +21 -6
  158. package/dist/gestures/PanGestureRecognizer.d.ts +11 -1
  159. package/dist/gestures/PanGestureRecognizer.d.ts.map +1 -1
  160. package/dist/gestures/PanGestureRecognizer.js +15 -1
  161. package/dist/gestures/ScreenEdgePanGestureRecognizer.d.ts +6 -1
  162. package/dist/gestures/ScreenEdgePanGestureRecognizer.d.ts.map +1 -1
  163. package/dist/gestures/nativeScroll.d.ts +3 -6
  164. package/dist/gestures/nativeScroll.d.ts.map +1 -1
  165. package/dist/gestures/nativeScroll.js +7 -52
  166. package/dist/gestures/wheelSegmenter.d.ts +68 -1
  167. package/dist/gestures/wheelSegmenter.d.ts.map +1 -1
  168. package/dist/gestures/wheelSegmenter.js +199 -10
  169. package/dist/hooks/StackItemScrollRegion.d.ts +31 -0
  170. package/dist/hooks/StackItemScrollRegion.d.ts.map +1 -0
  171. package/dist/hooks/StackItemScrollRegion.js +40 -0
  172. package/dist/hooks/menuPressGesture.d.ts +133 -21
  173. package/dist/hooks/menuPressGesture.d.ts.map +1 -1
  174. package/dist/hooks/menuPressGesture.js +155 -30
  175. package/dist/hooks/menuPressValues.d.ts +16 -0
  176. package/dist/hooks/menuPressValues.d.ts.map +1 -0
  177. package/dist/hooks/menuPressValues.js +18 -0
  178. package/dist/hooks/useClickableContainer.d.ts +27 -5
  179. package/dist/hooks/useClickableContainer.d.ts.map +1 -1
  180. package/dist/hooks/useClickableContainer.js +41 -5
  181. package/dist/hooks/useFocusTrap.d.ts +10 -0
  182. package/dist/hooks/useFocusTrap.d.ts.map +1 -1
  183. package/dist/hooks/useFocusTrap.js +225 -132
  184. package/dist/hooks/useMenuPress.d.ts +34 -1
  185. package/dist/hooks/useMenuPress.d.ts.map +1 -1
  186. package/dist/hooks/useMenuPress.js +93 -5
  187. package/dist/hooks/usePressFeedback.d.ts +6 -6
  188. package/dist/hooks/usePressFeedback.js +6 -6
  189. package/dist/hooks/useScrollRegionProps.d.ts +35 -0
  190. package/dist/hooks/useScrollRegionProps.d.ts.map +1 -0
  191. package/dist/hooks/useScrollRegionProps.js +51 -0
  192. package/dist/i18n/InternationalizationContext.d.ts +6 -0
  193. package/dist/i18n/InternationalizationContext.d.ts.map +1 -1
  194. package/dist/i18n/InternationalizationProvider.d.ts +21 -3
  195. package/dist/i18n/InternationalizationProvider.d.ts.map +1 -1
  196. package/dist/i18n/InternationalizationProvider.js +8 -3
  197. package/dist/i18n/generated-english/hooks/useScrollRegionProps.generated.d.ts +8 -0
  198. package/dist/i18n/generated-english/hooks/useScrollRegionProps.generated.d.ts.map +1 -0
  199. package/dist/i18n/generated-english/hooks/useScrollRegionProps.generated.js +12 -0
  200. package/dist/i18n/generated-locales/en.generated.d.ts.map +1 -1
  201. package/dist/i18n/generated-locales/en.generated.js +1 -0
  202. package/dist/i18n/generated-locales/pseudo.generated.d.ts.map +1 -1
  203. package/dist/i18n/generated-locales/pseudo.generated.js +1 -0
  204. package/dist/i18n/index.d.ts +2 -0
  205. package/dist/i18n/index.d.ts.map +1 -1
  206. package/dist/i18n/index.js +1 -0
  207. package/dist/i18n/useCalendarSystem.d.ts +19 -0
  208. package/dist/i18n/useCalendarSystem.d.ts.map +1 -0
  209. package/dist/i18n/useCalendarSystem.js +61 -0
  210. package/dist/internal/spinner-rotor.d.ts +16 -0
  211. package/dist/internal/spinner-rotor.d.ts.map +1 -0
  212. package/dist/internal/spinner-rotor.js +16 -0
  213. package/dist/internal/touch.d.ts +14 -1
  214. package/dist/internal/touch.d.ts.map +1 -1
  215. package/dist/internal/touch.js +20 -2
  216. package/dist/motion/carryAnimations.d.ts +58 -0
  217. package/dist/motion/carryAnimations.d.ts.map +1 -0
  218. package/dist/motion/carryAnimations.js +305 -0
  219. package/dist/motion/transientCopy.d.ts +4 -2
  220. package/dist/motion/transientCopy.d.ts.map +1 -1
  221. package/dist/motion/transientCopy.js +34 -5
  222. package/dist/motion/uikit/gestures.d.ts +41 -0
  223. package/dist/motion/uikit/gestures.d.ts.map +1 -1
  224. package/dist/motion/uikit/gestures.js +25 -0
  225. package/dist/motion/uikit/index.d.ts +1 -1
  226. package/dist/motion/uikit/index.d.ts.map +1 -1
  227. package/dist/motion/uikit/index.js +1 -1
  228. package/dist/motion/uikit/timing.d.ts +14 -10
  229. package/dist/motion/uikit/timing.d.ts.map +1 -1
  230. package/dist/motion/uikit/timing.js +7 -5
  231. package/dist/privateAttributes/menuPressLit.stylex.d.ts +52 -0
  232. package/dist/privateAttributes/menuPressLit.stylex.d.ts.map +1 -0
  233. package/dist/privateAttributes/menuPressLit.stylex.js +99 -0
  234. package/dist/privateAttributes/press.stylex.d.ts +139 -0
  235. package/dist/privateAttributes/press.stylex.d.ts.map +1 -0
  236. package/dist/privateAttributes/press.stylex.js +97 -0
  237. package/dist/theme/themeMotion.d.ts +3 -2
  238. package/dist/theme/themeMotion.d.ts.map +1 -1
  239. package/dist/theme/themeMotion.js +3 -2
  240. package/dist/theme/tokens.stylex.d.ts +2 -2
  241. package/dist/theme/tokens.stylex.js +1 -1
  242. package/dist/utils/calendarSystem.d.ts +114 -0
  243. package/dist/utils/calendarSystem.d.ts.map +1 -0
  244. package/dist/utils/calendarSystem.js +386 -0
  245. package/dist/utils/flatTree.d.ts +6 -3
  246. package/dist/utils/flatTree.d.ts.map +1 -1
  247. package/dist/utils/flatTree.js +13 -3
  248. package/dist/utils/hitArea.d.ts.map +1 -1
  249. package/dist/utils/hitArea.js +82 -5
  250. package/dist/utils/inputStream.d.ts +14 -1
  251. package/dist/utils/inputStream.d.ts.map +1 -1
  252. package/dist/utils/inputStream.js +40 -9
  253. package/dist/utils/interactionOverlay.stylex.d.ts +5 -9
  254. package/dist/utils/interactionOverlay.stylex.d.ts.map +1 -1
  255. package/dist/utils/interactionOverlay.stylex.js +29 -31
  256. package/dist/utils/plainDate.d.ts +23 -7
  257. package/dist/utils/plainDate.d.ts.map +1 -1
  258. package/dist/utils/plainDate.js +57 -18
  259. package/dist/utils/pressFeedback.d.ts +10 -2
  260. package/dist/utils/pressFeedback.d.ts.map +1 -1
  261. package/dist/utils/pressFeedback.js +40 -15
  262. package/dist/utils/pressGesture.d.ts +12 -6
  263. package/dist/utils/pressGesture.d.ts.map +1 -1
  264. package/dist/utils/pressGesture.js +26 -8
  265. package/dist/utils/scrollView.d.ts +25 -0
  266. package/dist/utils/scrollView.d.ts.map +1 -0
  267. package/dist/utils/scrollView.js +108 -0
  268. package/dist/utils/selectionLock.d.ts.map +1 -1
  269. package/dist/utils/selectionLock.js +1 -10
  270. package/dist/utils/touchHitArea.stylex.d.ts +35 -0
  271. package/dist/utils/touchHitArea.stylex.d.ts.map +1 -0
  272. package/dist/utils/touchHitArea.stylex.js +32 -0
  273. package/dist/utils/triggerFocus.d.ts +5 -0
  274. package/dist/utils/triggerFocus.d.ts.map +1 -1
  275. package/dist/utils/triggerFocus.js +9 -2
  276. package/locales/en.json +4 -0
  277. package/locales/pseudo.json +3 -0
  278. package/package.json +10 -4
  279. package/src/AppShell/observeMainOverflow.ts +9 -6
  280. package/src/BottomSheet/BottomSheet.tsx +5 -0
  281. package/src/BottomSheet/BottomSheetPanel.tsx +64 -7
  282. package/src/BottomSheet/useSheetGestures.ts +83 -20
  283. package/src/Calendar/Calendar.doc.mjs +76 -6
  284. package/src/Calendar/Calendar.tsx +123 -104
  285. package/src/Calendar/getInitialFocusDate.ts +22 -8
  286. package/src/Calendar/hooks/useCalendarDays.ts +89 -63
  287. package/src/Calendar/hooks/useCalendarNavigation.ts +68 -26
  288. package/src/CheckboxInput/CheckboxInput.doc.mjs +3 -2
  289. package/src/CheckboxInput/CheckboxInput.tsx +71 -9
  290. package/src/ClickableCard/ClickableCard.tsx +8 -1
  291. package/src/DateInput/DateInput.tsx +2 -0
  292. package/src/DateInput/PickerWheel.tsx +7 -2
  293. package/src/DateRangeInput/DateRangeInput.tsx +3 -1
  294. package/src/DateTimeInput/DateTimeInput.tsx +2 -0
  295. package/src/Dialog/Dialog.doc.mjs +1 -1
  296. package/src/Dialog/Dialog.tsx +12 -1
  297. package/src/Drawer/Drawer.doc.mjs +1 -1
  298. package/src/Drawer/useDrawerDialogPresence.ts +9 -2
  299. package/src/DropdownMenu/DropdownMenu.doc.mjs +1 -2
  300. package/src/DropdownMenu/DropdownMenu.tsx +29 -5
  301. package/src/DropdownMenu/DropdownMenuCheckboxItem.tsx +5 -1
  302. package/src/DropdownMenu/DropdownMenuItem.tsx +8 -4
  303. package/src/DropdownMenu/DropdownMenuRadioItem.tsx +5 -1
  304. package/src/DropdownMenu/DropdownMenuSubMenu.tsx +5 -1
  305. package/src/FileInput/FileInput.tsx +16 -2
  306. package/src/HoverCard/useHoverCard.tsx +3 -1
  307. package/src/InfoTip/InfoTip.doc.mjs +26 -2
  308. package/src/InfoTip/InfoTip.tsx +1 -0
  309. package/src/InputGroup/InputGroup.doc.mjs +4 -3
  310. package/src/InputGroup/InputGroup.tsx +4 -3
  311. package/src/InputGroup/groupStyles.ts +3 -1
  312. package/src/Item/Item.tsx +51 -9
  313. package/src/Layer/holdEntranceInput.ts +84 -0
  314. package/src/Layer/inputHold.ts +734 -0
  315. package/src/Layer/preserveAnimations.ts +12 -275
  316. package/src/Layer/useLayer.tsx +77 -4
  317. package/src/Layout/LayoutContent.doc.mjs +6 -3
  318. package/src/Layout/LayoutContent.tsx +10 -4
  319. package/src/Layout/LayoutPanel.doc.mjs +6 -3
  320. package/src/Layout/LayoutPanel.tsx +11 -4
  321. package/src/Lightbox/Lightbox.tsx +4 -0
  322. package/src/MetadataList/MetadataList.tsx +1 -1
  323. package/src/MobileNav/MobileNav.doc.mjs +3 -3
  324. package/src/MobileNav/MobileNav.tsx +39 -1
  325. package/src/MoreMenu/MoreMenu.doc.mjs +2 -4
  326. package/src/MoreMenu/MoreMenu.tsx +5 -3
  327. package/src/NumberInput/NumberInput.doc.mjs +1 -1
  328. package/src/NumberInput/NumberInput.tsx +259 -11
  329. package/src/Popover/usePopover.tsx +1 -0
  330. package/src/PowerSearch/PowerSearch.doc.mjs +3 -3
  331. package/src/PowerSearch/PowerSearch.tsx +20 -3
  332. package/src/PowerSearch/PowerSearchBottomSheet.tsx +4 -1
  333. package/src/PowerSearch/PowerSearchToken.tsx +3 -0
  334. package/src/PowerSearch/formatFilterValue.ts +21 -11
  335. package/src/PowerSearch/formatTokenValue.ts +7 -1
  336. package/src/RadioList/RadioListItem.doc.mjs +3 -2
  337. package/src/RadioList/RadioListItem.tsx +25 -7
  338. package/src/SelectableCard/SelectableCard.tsx +8 -1
  339. package/src/Spinner/Spinner.tsx +7 -89
  340. package/src/Spinner/index.ts +1 -5
  341. package/src/Spinner/spinnerRotor.ts +113 -0
  342. package/src/Stack/Stack.doc.mjs +1 -1
  343. package/src/Stack/StackItem.tsx +27 -13
  344. package/src/Switch/Switch.tsx +7 -6
  345. package/src/Table/plugins/sortable/useTableSortable.tsx +1 -1
  346. package/src/Timestamp/Timestamp.doc.mjs +3 -3
  347. package/src/Timestamp/Timestamp.tsx +13 -8
  348. package/src/Timestamp/formatInstant.ts +49 -28
  349. package/src/Timestamp/tooltipEntries.ts +7 -3
  350. package/src/Token/Token.tsx +18 -1
  351. package/src/Token/TokenLink.tsx +7 -1
  352. package/src/Tokenizer/Tokenizer.doc.mjs +3 -3
  353. package/src/Tokenizer/Tokenizer.tsx +252 -115
  354. package/src/Tooltip/useTooltip.tsx +178 -80
  355. package/src/TreeList/TreeListItem.tsx +36 -2
  356. package/src/gestures/GestureHost.ts +21 -5
  357. package/src/gestures/PanGestureRecognizer.ts +19 -2
  358. package/src/gestures/README.md +14 -5
  359. package/src/gestures/ScreenEdgePanGestureRecognizer.ts +6 -1
  360. package/src/gestures/nativeScroll.ts +12 -68
  361. package/src/gestures/wheelSegmenter.ts +243 -10
  362. package/src/hooks/StackItemScrollRegion.tsx +57 -0
  363. package/src/hooks/menuPressGesture.ts +244 -38
  364. package/src/hooks/menuPressValues.ts +18 -0
  365. package/src/hooks/useClickableContainer.doc.mjs +8 -2
  366. package/src/hooks/useClickableContainer.ts +72 -6
  367. package/src/hooks/useFocusTrap.ts +268 -151
  368. package/src/hooks/useMenuPress.ts +118 -11
  369. package/src/hooks/usePressFeedback.doc.mjs +3 -3
  370. package/src/hooks/usePressFeedback.ts +6 -6
  371. package/src/hooks/useScrollRegionProps.ts +76 -0
  372. package/src/i18n/InternationalizationContext.ts +6 -0
  373. package/src/i18n/InternationalizationProvider.doc.mjs +29 -1
  374. package/src/i18n/InternationalizationProvider.tsx +33 -3
  375. package/src/i18n/generated-english/hooks/useScrollRegionProps.generated.ts +13 -0
  376. package/src/i18n/generated-locales/en.generated.ts +1 -0
  377. package/src/i18n/generated-locales/pseudo.generated.ts +1 -0
  378. package/src/i18n/index.ts +2 -0
  379. package/src/i18n/useCalendarSystem.ts +95 -0
  380. package/src/internal/spinner-rotor.ts +20 -0
  381. package/src/internal/touch.ts +34 -1
  382. package/src/motion/MEASUREMENTS.md +11 -0
  383. package/src/motion/carryAnimations.ts +389 -0
  384. package/src/motion/transientCopy.ts +45 -5
  385. package/src/motion/uikit/gestures.ts +22 -0
  386. package/src/motion/uikit/index.ts +1 -0
  387. package/src/motion/uikit/timing.ts +7 -5
  388. package/src/privateAttributes/menuPressLit.stylex.ts +104 -0
  389. package/src/privateAttributes/press.stylex.ts +243 -0
  390. package/src/theme/themeMotion.ts +3 -2
  391. package/src/theme/tokens.stylex.ts +1 -1
  392. package/src/utils/calendarSystem.ts +548 -0
  393. package/src/utils/flatTree.ts +15 -3
  394. package/src/utils/hitArea.ts +107 -5
  395. package/src/utils/inputStream.ts +47 -10
  396. package/src/utils/interactionOverlay.stylex.ts +19 -22
  397. package/src/utils/plainDate.ts +84 -19
  398. package/src/utils/pressFeedback.ts +46 -14
  399. package/src/utils/pressGesture.ts +35 -9
  400. package/src/utils/scrollView.ts +135 -0
  401. package/src/utils/selectionLock.ts +5 -10
  402. package/src/utils/touchHitArea.stylex.ts +41 -0
  403. package/src/utils/triggerFocus.ts +17 -4
@@ -5,7 +5,7 @@
5
5
  /**
6
6
  * @file Dialog.tsx
7
7
  * @input Uses React, DialogHTMLAttributes, ReactNode, container (Layout), DialogContext, layerTextReset,
8
- * layerStructureReset, modalOutlet, interactionModality, chainEventHandlers
8
+ * layerStructureReset, modalOutlet, interactionModality, chainEventHandlers, holdEntranceInput
9
9
  * @output Exports Dialog component, DialogProps, DialogVariant, DialogPurpose types
10
10
  * @position Core implementation; consumed by index.ts, tested by Dialog.test.tsx
11
11
  *
@@ -27,6 +27,7 @@
27
27
  * SYNC: When modified, update these files to stay in sync:
28
28
  * - /packages/core/src/Dialog/Dialog.doc.mjs (props table, features, implementation notes)
29
29
  * - /packages/core/src/Dialog/Dialog.test.tsx (tests for new/changed behavior)
30
+ * - /packages/core/src/Dialog/__tests__/DialogTouchEntrance.interaction.browser.spec.ts (the touch entrance hold)
30
31
  * - /packages/core/src/Dialog/index.ts (exports if types change)
31
32
  * - /apps/storybook/stories/Dialog.stories.tsx (storybook stories)
32
33
  * - /packages/cli/assets/templates/blocks/components/Dialog/ (showcase blocks)
@@ -51,8 +52,10 @@ import {layerStructureReset} from '../Layer/layerStructureReset.stylex';
51
52
  import {LayerContentBoundary} from '../Layer/layerScopedContext';
52
53
  import {layerClickBoundary} from '../Layer/layerClickBoundary';
53
54
  import {LayerDepthProvider} from '../Layer/LayerDepthContext';
55
+ import {holdEntranceInput} from '../Layer/holdEntranceInput';
54
56
  import {useLayerDismissal} from '../Layer/useLayerDismissal';
55
57
  import {useBackdropPress} from '../Layer/useBackdropPress';
58
+ import {useFocusRegionContainment} from '../hooks/useFocusTrap';
56
59
  import {useModalOutlet} from '../Layer/modalOutlet';
57
60
  import {
58
61
  colorVars,
@@ -547,6 +550,9 @@ export function Dialog({
547
550
  props['aria-label'] != null || props['aria-labelledby'] != null;
548
551
 
549
552
  const dialogRef = useRef<HTMLDialogElement>(null);
553
+ // Native showModal() lets Tab leave for the browser's own UI, so the shared
554
+ // module wraps it. An inline preview is not modal and contains nothing.
555
+ useFocusRegionContainment(dialogRef, isOpen && !isInline);
550
556
 
551
557
  // Callback ref on the <dialog>: sync the default aria-labelledby from the
552
558
  // DialogHeader title (if one rendered) in the same commit, with no second
@@ -642,6 +648,11 @@ export function Dialog({
642
648
  focusForLastInput(autofocusTarget);
643
649
  }
644
650
  }
651
+ // Under a coarse primary pointer, a tap or a drag during the entrance
652
+ // reaches nothing. Keys and assistive technology stay live. The hold
653
+ // ends with the entrance, or with this effect's cleanup on a close or
654
+ // unmount.
655
+ return holdEntranceInput(dialog) ?? undefined;
645
656
  } else {
646
657
  if (dialog.open) {
647
658
  dialog.close();
@@ -172,7 +172,7 @@ export const docs = {
172
172
  usage: {
173
173
  anatomy,
174
174
  description:
175
- 'A side panel that floats above page content for inspectors and detail views: the "click a table row, see its details" pattern. Unlike a docked panel it overlays the layout instead of reflowing it. Works on desktop and touch: the width budget applies on desktop and the panel preserves a 56px page reveal below 640px without exceeding the width budget. Escape closes the drawer (unless purpose is required) and focus returns to the element that opened it. Entry/exit slide animation respects prefers-reduced-motion. Stacking contract: sibling drawers stack last-opened on top, Escape closes only the topmost, and closing peels innermost-first; render them as siblings, never nested.\n\nLike Dialog, the drawer is a container: its content area is inset by --spacing-4 (16px) by default, by the padding prop, or by a theme\'s padding on drawer. Compose the header, body, and footer the way Dialog does, with a Layout: DrawerHeader in the header slot (it shows a close button when you pass it onOpenChange, like DialogHeader), the body in LayoutContent, and actions in LayoutFooter. The Layout redistributes the inset to those regions so they line up on one content line, and the header is not inset twice. A lone Section child also escapes the inset. Drawer renders no close button of its own, so give every drawer a visible way to close, especially a non-modal one, which has no scrim to click. Put data-autofocus on the control that should receive focus on open.\n\nChoosing a surface: use Dialog for a centered decision or short form, Drawer for full-height side detail that keeps the page in sight, BottomSheet for block-axis sheets on touch, and a docked panel (a layout column) when content should reflow the page instead of floating over it.\n\nTheming: the panel is the single stable target (astryx-drawer, with data-side reflecting side), and the scrim is the panel\'s native ::backdrop. DrawerHeader exposes astryx-drawer-header targets for its row, slots, and close icon.',
175
+ 'A side panel that floats above page content for inspectors and detail views: the "click a table row, see its details" pattern. Unlike a docked panel it overlays the layout instead of reflowing it. Works on desktop and touch: the width budget applies on desktop and the panel preserves a 56px page reveal below 640px without exceeding the width budget. Escape closes the drawer (unless purpose is required) and focus returns to the element that opened it. Entry/exit slide animation respects prefers-reduced-motion. On a phone or tablet (a coarse primary pointer), a tap or a drag that lands while the drawer is still sliding in reaches nothing (for a drawer without a scrim, only one on the panel: the page stays live), and the drawer finishes sliding in; keys and assistive technology stay live, and a mouse or a trackpad still clicks: at once when it was the last pointer used, otherwise once it moves. Stacking contract: sibling drawers stack last-opened on top, Escape closes only the topmost, and closing peels innermost-first; render them as siblings, never nested.\n\nLike Dialog, the drawer is a container: its content area is inset by --spacing-4 (16px) by default, by the padding prop, or by a theme\'s padding on drawer. Compose the header, body, and footer the way Dialog does, with a Layout: DrawerHeader in the header slot (it shows a close button when you pass it onOpenChange, like DialogHeader), the body in LayoutContent, and actions in LayoutFooter. The Layout redistributes the inset to those regions so they line up on one content line, and the header is not inset twice. A lone Section child also escapes the inset. Drawer renders no close button of its own, so give every drawer a visible way to close, especially a non-modal one, which has no scrim to click. Put data-autofocus on the control that should receive focus on open.\n\nChoosing a surface: use Dialog for a centered decision or short form, Drawer for full-height side detail that keeps the page in sight, BottomSheet for block-axis sheets on touch, and a docked panel (a layout column) when content should reflow the page instead of floating over it.\n\nTheming: the panel is the single stable target (astryx-drawer, with data-side reflecting side), and the scrim is the panel\'s native ::backdrop. DrawerHeader exposes astryx-drawer-header targets for its row, slots, and close icon.',
176
176
  bestPractices: [
177
177
  {
178
178
  guidance: true,
@@ -5,7 +5,7 @@
5
5
  /**
6
6
  * @file useDrawerDialogPresence.ts
7
7
  * @input Controlled open state, modal mode, dialog ref, and rendered-state setter
8
- * @output Coordinates native top-layer presence, exit timing, focus restoration, and unmount cleanup
8
+ * @output Coordinates native top-layer presence, the touch entrance's input hold, exit timing, focus restoration, and unmount cleanup
9
9
  * @position Drawer-internal hook; consumed only by Drawer.tsx
10
10
  *
11
11
  * The drawer has two independent notions of presence:
@@ -21,6 +21,7 @@
21
21
  *
22
22
  * SYNC: When modified, update:
23
23
  * - /packages/core/src/Drawer/Drawer.test.tsx
24
+ * - /packages/core/src/Drawer/__tests__/DrawerTouchEntrance.interaction.browser.spec.ts
24
25
  * - /.github/scripts/modal-close-visibility.js
25
26
  */
26
27
 
@@ -32,6 +33,7 @@ import {
32
33
  type SetStateAction,
33
34
  } from 'react';
34
35
  import {flushSync} from 'react-dom';
36
+ import {holdEntranceInput} from '../Layer/holdEntranceInput';
35
37
  import {notifyTopLayerEntry} from '../Layer/modalOutlet';
36
38
  import {runPopoverOperation} from '../Layer/popoverOperations';
37
39
 
@@ -149,7 +151,12 @@ export function useDrawerDialogPresence({
149
151
  // contract as Dialog).
150
152
  dialog.querySelector<HTMLElement>('[data-autofocus]')?.focus();
151
153
  }
152
- return;
154
+ // Under a coarse primary pointer, a tap or a drag during the slide-in
155
+ // reaches nothing. A non-modal drawer holds only its panel, so its page
156
+ // stays live. Keys and assistive technology stay live. The hold ends
157
+ // with the slide-in, or with this effect's cleanup on a close or
158
+ // unmount.
159
+ return holdEntranceInput(dialog, {isModal}) ?? undefined;
153
160
  }
154
161
 
155
162
  if (!isDrawerHostOpen(dialog, isModal)) {
@@ -201,8 +201,7 @@ export const docs = {
201
201
  name: 'presentation',
202
202
  type: "'popover' | 'bottom-sheet' | 'adaptive'",
203
203
  description:
204
- "Presentation surface for data-driven items. 'popover' stays anchored, 'bottom-sheet' always renders the actions in a modal BottomSheet, and 'adaptive' uses a BottomSheet on compact coarse-pointer layouts while remaining anchored elsewhere. Compound children currently support popover only.",
205
- default: "'popover'",
204
+ "Presentation surface for data-driven items. 'popover' stays anchored, 'bottom-sheet' always renders the actions in a modal BottomSheet, and 'adaptive' uses a BottomSheet on compact coarse-pointer layouts while remaining anchored elsewhere. Compound children currently support popover only. Omitted, the menu is anchored, and under a finger, on every device, the finger that opened it picks a row only after moving 10 px. Pass 'popover' to keep the pointer behavior on every device, the settle rule included.",
206
205
  },
207
206
  {
208
207
  name: 'isMenuOpen',
@@ -70,7 +70,7 @@ import {
70
70
  import {useIsomorphicLayoutEffect} from '../hooks/useIsomorphicLayoutEffect';
71
71
  import {useMergedRefs} from '../hooks/useMergedRefs';
72
72
  import {useListFocus} from '../hooks/useListFocus';
73
- import {useMenuPress} from '../hooks/useMenuPress';
73
+ import {useDropdownMenuPress} from '../hooks/useMenuPress';
74
74
  import type {MenuPressPointerType} from '../hooks/menuPressGesture';
75
75
  import {useTypeahead} from '../hooks/useTypeahead';
76
76
  import {useFocusReturnVisibility} from '../hooks/useFocusReturnVisibility';
@@ -460,7 +460,10 @@ interface DropdownMenuDataProps extends DropdownMenuBaseProps {
460
460
  * Surface used to present the actions. Pass a value selected by product
461
461
  * policy (for example, a compact-touch media query) when the presentation
462
462
  * should adapt. Bottom-sheet presentation is intended for short action sets.
463
- * @default 'popover'
463
+ * Omitted, the menu is the anchored popover. Under a finger, on every
464
+ * device, the finger that opened it picks as UIMenu's does, once it has
465
+ * moved. `'popover'` pins the anchored popover with the pointer behavior on
466
+ * every device (the opening press follows the settle rule).
464
467
  */
465
468
  presentation?: DropdownMenuPresentation;
466
469
  items: DropdownMenuOption[];
@@ -468,6 +471,11 @@ interface DropdownMenuDataProps extends DropdownMenuBaseProps {
468
471
  }
469
472
 
470
473
  interface DropdownMenuCompoundProps extends DropdownMenuBaseProps {
474
+ /**
475
+ * `'popover'` pins the pointer behavior on every device (the opening press
476
+ * follows the settle rule). Omitted, on every device, the finger
477
+ * that opened the menu picks as UIMenu's does, once it has moved.
478
+ */
471
479
  presentation?: 'popover';
472
480
  items?: undefined;
473
481
  children: ReactNode;
@@ -881,6 +889,7 @@ function DropdownMenuPopover({
881
889
  placement = 'below',
882
890
  alignment = 'start',
883
891
  presentation: _presentation,
892
+ pressTouchModel = 'uikit',
884
893
  header,
885
894
  footer,
886
895
  className,
@@ -888,7 +897,13 @@ function DropdownMenuPopover({
888
897
  xstyle,
889
898
  'data-testid': testId,
890
899
  ...props
891
- }: DropdownMenuProps) {
900
+ }: DropdownMenuProps & {
901
+ /**
902
+ * How a finger's press runs, on every device: UIMenu's, unless the caller
903
+ * pins `presentation="popover"`.
904
+ */
905
+ pressTouchModel?: 'pointer' | 'uikit';
906
+ }) {
892
907
  const t = useComponentTranslator();
893
908
  const button = buttonFromProps ?? {label: t(DEFAULT_BUTTON_I18N_KEY)};
894
909
 
@@ -1359,12 +1374,15 @@ function DropdownMenuPopover({
1359
1374
  // The press model: the row under a release acts, the highlight follows a
1360
1375
  // held pointer. A mouse released outside the menu dismisses it; a finger
1361
1376
  // released outside leaves it open, so the hook never calls onDismiss then.
1362
- const menuPress = useMenuPress({
1377
+ const menuPress = useDropdownMenuPress({
1363
1378
  menuRef: listRef,
1364
1379
  triggerRef: buttonRef,
1365
1380
  itemSelector: MENU_ITEM_SELECTOR,
1366
1381
  onTriggerPress: handleTriggerPress,
1367
1382
  onDismiss: closeMenu,
1383
+ // Under a finger, on every device, the opening finger picks as UIMenu's
1384
+ // does. `presentation="popover"` pins the pointer model.
1385
+ touchModel: pressTouchModel,
1368
1386
  });
1369
1387
  cancelMenuPressRef.current = menuPress.cancel;
1370
1388
 
@@ -1786,7 +1804,13 @@ export function DropdownMenu(props: DropdownMenuProps) {
1786
1804
  );
1787
1805
  }
1788
1806
 
1789
- return <DropdownMenuPopover {...sharedProps} presentation="popover" />;
1807
+ return (
1808
+ <DropdownMenuPopover
1809
+ {...sharedProps}
1810
+ presentation="popover"
1811
+ pressTouchModel={props.presentation === 'popover' ? 'pointer' : 'uikit'}
1812
+ />
1813
+ );
1790
1814
  }
1791
1815
 
1792
1816
  DropdownMenu.displayName = 'DropdownMenu';
@@ -38,6 +38,7 @@ import {useIndicator} from '../Indicator';
38
38
  import {Item} from '../Item';
39
39
  import {useDropdownMenuContext} from './DropdownMenuContext';
40
40
  import {focusOutlineStyles} from '../utils/focusOutline.stylex';
41
+ import {menuPressLitRowStyle} from '../privateAttributes/menuPressLit.stylex';
41
42
  import {focusMenuItemOnHover} from './menuItemHover';
42
43
  import {colorVars, focusVars, spacingVars} from '../theme/tokens.stylex';
43
44
  import {composeEventHandlers, mergeProps, themeProps} from '../utils';
@@ -50,7 +51,9 @@ const styles = stylex.create({
50
51
  color: colorVars['--color-text-primary'],
51
52
  backgroundColor: {
52
53
  default: 'transparent',
53
- ':focus': colorVars['--color-overlay-hover'],
54
+ // menuPressLitRowStyle sets the variable on the row a held finger or pen
55
+ // lights.
56
+ ':focus': `var(--_menu-row-focus-paint, ${colorVars['--color-overlay-hover']})`,
54
57
  },
55
58
  cursor: {
56
59
  default: 'pointer',
@@ -231,6 +234,7 @@ export function DropdownMenuCheckboxItem({
231
234
  xstyle={[
232
235
  focusOutlineStyles.focusVisible,
233
236
  styles.root,
237
+ menuPressLitRowStyle,
234
238
  isDisabled && styles.disabled,
235
239
  xstyle,
236
240
  ]}
@@ -49,6 +49,7 @@ import {composeEventHandlers, mergeProps} from '../utils';
49
49
  import type {BaseProps} from '../BaseProps';
50
50
  import {useDropdownMenuContext} from './DropdownMenuContext';
51
51
  import {focusOutlineStyles} from '../utils/focusOutline.stylex';
52
+ import {menuPressLitRowStyle} from '../privateAttributes/menuPressLit.stylex';
52
53
  import {focusMenuItemOnHover} from './menuItemHover';
53
54
  import {isModifiedClick} from './menuItemRoles';
54
55
  import {themeProps} from '../utils/themeProps';
@@ -66,14 +67,16 @@ const menuItemStyles = stylex.create({
66
67
  color: colorVars['--color-text-primary'],
67
68
  backgroundColor: {
68
69
  default: 'transparent',
69
- ':focus': colorVars['--color-overlay-hover'],
70
+ // menuPressLitRowStyle sets the variable on the row a held finger or pen
71
+ // lights.
72
+ ':focus': `var(--_menu-row-focus-paint, ${colorVars['--color-overlay-hover']})`,
70
73
  // The pressed look only where hover exists. Under a finger the row a
71
74
  // press BEGAN on would otherwise stay painted while the highlight (focus)
72
- // moves to the row under the finger — two rows lit.
75
+ // moves to the row under the finger — two rows lit. A held finger or pen
76
+ // sets the variable on the menu. Then only the lit row keeps the look.
73
77
  '@media (hover: hover)': {
74
78
  default: null,
75
- ':active:where(:not(:disabled,[aria-disabled="true"]))':
76
- colorVars['--color-overlay-pressed'],
79
+ ':active:where(:not(:disabled,[aria-disabled="true"]))': `var(--_menu-row-active-paint, ${colorVars['--color-overlay-pressed']})`,
77
80
  },
78
81
  },
79
82
  borderWidth: 0,
@@ -303,6 +306,7 @@ export function DropdownMenuItem({
303
306
  xstyle={[
304
307
  focusOutlineStyles.focusVisible,
305
308
  menuItemStyles.root,
309
+ menuPressLitRowStyle,
306
310
  itemSizeStyles[menuSize],
307
311
  isDestructive && menuItemStyles.destructive,
308
312
  isDisabled && menuItemStyles.disabled,
@@ -34,6 +34,7 @@ import {useIndicator} from '../Indicator';
34
34
  import {Item} from '../Item';
35
35
  import {useDropdownMenuContext} from './DropdownMenuContext';
36
36
  import {focusOutlineStyles} from '../utils/focusOutline.stylex';
37
+ import {menuPressLitRowStyle} from '../privateAttributes/menuPressLit.stylex';
37
38
  import {focusMenuItemOnHover} from './menuItemHover';
38
39
  import {colorVars, focusVars, spacingVars} from '../theme/tokens.stylex';
39
40
  import {composeEventHandlers, mergeProps, themeProps} from '../utils';
@@ -47,7 +48,9 @@ const styles = stylex.create({
47
48
  color: colorVars['--color-text-primary'],
48
49
  backgroundColor: {
49
50
  default: 'transparent',
50
- ':focus': colorVars['--color-overlay-hover'],
51
+ // menuPressLitRowStyle sets the variable on the row a held finger or pen
52
+ // lights.
53
+ ':focus': `var(--_menu-row-focus-paint, ${colorVars['--color-overlay-hover']})`,
51
54
  },
52
55
  cursor: {
53
56
  default: 'pointer',
@@ -218,6 +221,7 @@ export function DropdownMenuRadioItem({
218
221
  xstyle={[
219
222
  focusOutlineStyles.focusVisible,
220
223
  styles.root,
224
+ menuPressLitRowStyle,
221
225
  isDisabled && styles.disabled,
222
226
  xstyle,
223
227
  ]}
@@ -99,6 +99,7 @@ import {
99
99
  rtlStyles,
100
100
  } from '../utils';
101
101
  import {focusOutlineStyles} from '../utils/focusOutline.stylex';
102
+ import {menuPressLitRowStyle} from '../privateAttributes/menuPressLit.stylex';
102
103
  import {getInteractionModality} from '../utils/interactionModality';
103
104
  import {useMergedRefs} from '../hooks/useMergedRefs';
104
105
  import {useDevWarning} from '../hooks/useDevWarning';
@@ -146,7 +147,9 @@ const triggerStyles = stylex.create({
146
147
  color: colorVars['--color-text-primary'],
147
148
  backgroundColor: {
148
149
  default: 'transparent',
149
- ':focus': colorVars['--color-overlay-hover'],
150
+ // menuPressLitRowStyle sets the variable on the row a held finger or pen
151
+ // lights.
152
+ ':focus': `var(--_menu-row-focus-paint, ${colorVars['--color-overlay-hover']})`,
150
153
  },
151
154
  borderWidth: 0,
152
155
  borderStyle: 'none',
@@ -1243,6 +1246,7 @@ export function DropdownMenuSubMenu(
1243
1246
  xstyle={[
1244
1247
  focusOutlineStyles.focusVisible,
1245
1248
  triggerStyles.root,
1249
+ menuPressLitRowStyle,
1246
1250
  triggerSizeStyles[menuSize],
1247
1251
  isOpen && triggerStyles.open,
1248
1252
  isDisabled && triggerStyles.disabled,
@@ -754,7 +754,14 @@ export function FileInput({
754
754
  (e: DragEvent) => {
755
755
  e.preventDefault();
756
756
  e.stopPropagation();
757
- if (!isSelectionDisabled && mode === 'dropzone') {
757
+ if (isSelectionDisabled) {
758
+ // A cancelled dragover with the default effect makes the zone a drop
759
+ // target.
760
+ // The 'none' effect shows the no-drop cursor and stops the drop.
761
+ if (e.dataTransfer) {
762
+ e.dataTransfer.dropEffect = 'none';
763
+ }
764
+ } else if (mode === 'dropzone') {
758
765
  setIsDragOver(true);
759
766
  }
760
767
  },
@@ -765,7 +772,14 @@ export function FileInput({
765
772
  (e: DragEvent) => {
766
773
  e.preventDefault();
767
774
  e.stopPropagation();
768
- if (!isSelectionDisabled && mode === 'dropzone') {
775
+ if (isSelectionDisabled) {
776
+ // A cancelled dragover with the default effect makes the zone a drop
777
+ // target.
778
+ // The 'none' effect shows the no-drop cursor and stops the drop.
779
+ if (e.dataTransfer) {
780
+ e.dataTransfer.dropEffect = 'none';
781
+ }
782
+ } else if (mode === 'dropzone') {
769
783
  setIsDragOver(true);
770
784
  }
771
785
  },
@@ -177,7 +177,8 @@ export interface HoverCardReturn {
177
177
 
178
178
  /**
179
179
  * Ref for the positioning anchor element.
180
- * Injects anchorName style for CSS anchor positioning.
180
+ * While the layer is shown, and until its exit animation ends, the trigger
181
+ * carries the layer's CSS anchor name.
181
182
  */
182
183
  positionRef: RefCallback<HTMLElement>;
183
184
 
@@ -191,6 +192,7 @@ export interface HoverCardReturn {
191
192
  /**
192
193
  * The CSS anchor name to use for positioning.
193
194
  * Use this when you need to set anchorName manually (e.g., display:contents wrapper).
195
+ * Set it only while the layer is shown or its exit animation runs.
194
196
  */
195
197
  anchorId: string;
196
198
 
@@ -1,5 +1,27 @@
1
1
  // Copyright (c) Meta Platforms, Inc. and affiliates.
2
2
 
3
+ /** @type {import('@astryxdesign/cli/authoring').ComponentAnatomyElement[]} */
4
+ const anatomy = [
5
+ {
6
+ name: 'Trigger button',
7
+ required: true,
8
+ description:
9
+ 'Small round native button, named by `label`, that previews and pins the help.',
10
+ },
11
+ {
12
+ name: 'Info icon',
13
+ required: true,
14
+ description:
15
+ "The icon registry's `info` artwork at `size`; a theme may replace it.",
16
+ },
17
+ {
18
+ name: 'Help surface',
19
+ required: true,
20
+ description:
21
+ 'Tooltip surface that shows `content` while the help is shown.',
22
+ },
23
+ ];
24
+
3
25
  /** @type {import('@astryxdesign/cli/authoring').ComponentDoc} */
4
26
 
5
27
  export const docs = {
@@ -50,8 +72,9 @@ export const docs = {
50
72
  },
51
73
  ],
52
74
  usage: {
75
+ anatomy,
53
76
  description:
54
- 'An info icon that reveals help: a small "i" button. Hover and keyboard focus preview the help, and a click, tap, Enter, or Space pins it open until Escape, a second press, a press outside, or focus leaving. Use it next to labels, values, and metrics for permission notes, metric definitions, and field help. Its value over hand-composing Icon inside Tooltip is the pre-wired accessible trigger: a real button with an aria-label, Tab-reachable, tooltip on hover AND focus AND tap, and Escape dismissal.',
77
+ 'An info icon that reveals help: a small "i" button. Hover and keyboard focus preview the help, and a click, tap, Enter, or Space pins it open until Escape, a second press, a press outside, or focus leaving. Use it next to labels, values, and metrics for permission notes, metric definitions, and field help. Its value over hand-composing Icon inside Tooltip is the pre-wired accessible trigger: a real button with an aria-label, Tab-reachable, tooltip on hover AND focus AND tap, and Escape dismissal. It follows the toggletip pattern: the button reports `aria-expanded="true"` while the help is pinned, and a screen reader hears the help once when it pins.',
55
78
  bestPractices: [
56
79
  {
57
80
  guidance: true,
@@ -115,6 +138,7 @@ export const docsZh = {
115
138
  },
116
139
  ],
117
140
  usage: {
141
+ anatomy,
118
142
  description:
119
143
  'An info icon that reveals help: a small "i" button. Hover and keyboard focus preview the help, and a click, tap, Enter, or Space pins it open until Escape, a second press, a press outside, or focus leaving. Use it next to labels, values, and metrics for permission notes, metric definitions, and field help.',
120
144
  bestPractices: [
@@ -153,7 +177,7 @@ export const docsDense = {
153
177
  'Inline info-icon help affordance: accessible "i" button trigger pre-wired into a Tooltip.',
154
178
  usage: {
155
179
  description:
156
- 'A small "i" button: hover and keyboard focus preview the help; a click, tap, Enter, or Space pins it open. Use next to labels, values, and metrics for permission notes, metric definitions, and field help. Pre-wired accessible trigger: real button, aria-label, Tab-reachable, tooltip on hover AND focus AND tap, Escape dismissal.',
180
+ 'A small "i" button: hover and keyboard focus preview the help; a click, tap, Enter, or Space pins it open. Use next to labels, values, and metrics for permission notes, metric definitions, and field help. Pre-wired accessible trigger: real button, aria-label, Tab-reachable, tooltip on hover AND focus AND tap, Escape dismissal. Toggletip pattern: aria-expanded="true" while pinned; the help is announced once when it pins.',
157
181
  bestPractices: [
158
182
  {
159
183
  guidance: true,
@@ -15,6 +15,7 @@
15
15
  * - /docs/specs/components/InfoTip/InfoTip.spec.md (contract)
16
16
  * - /packages/core/src/InfoTip/InfoTip.test.tsx (tests for new/changed behavior)
17
17
  * - /packages/core/src/InfoTip/index.ts (exports if types change)
18
+ * - /packages/cli/assets/templates/blocks/components/InfoTip/ (showcase and example blocks)
18
19
  */
19
20
 
20
21
  import {
@@ -24,7 +24,7 @@ export const docs = {
24
24
  ],
25
25
  },
26
26
  description:
27
- 'Groups an input with prefix/suffix addons in a visually connected container with shared border and focus ring.',
27
+ 'Groups an input with prefix and suffix addons in one connected row. A focused member stays above its neighbours, so its focus ring shows in full.',
28
28
  props: [
29
29
  {
30
30
  name: 'children',
@@ -59,7 +59,7 @@ export const docs = {
59
59
  {
60
60
  name: 'isOptional',
61
61
  type: 'boolean',
62
- description: 'Show "(optional)" indicator.',
62
+ description: 'Show the "Optional" indicator after the label.',
63
63
  default: 'false',
64
64
  },
65
65
  {
@@ -77,7 +77,8 @@ export const docs = {
77
77
  {
78
78
  name: 'status',
79
79
  type: "{type: 'warning' | 'error' | 'success', message?: string}",
80
- description: 'Status indicator applied to the group border.',
80
+ description:
81
+ 'Validation status. Its message shows below the group. The group border does not change; a theme can style the row from `data-status`.',
81
82
  },
82
83
  {
83
84
  name: 'labelTooltip',
@@ -109,7 +109,8 @@ export interface InputGroupProps extends Omit<
109
109
  size?: InputGroupSize;
110
110
 
111
111
  /**
112
- * Status indicator applied to the group border.
112
+ * Validation status. Its message shows below the group. The group border
113
+ * does not change; a theme can style the row from `data-status`.
113
114
  */
114
115
  status?: InputStatus;
115
116
 
@@ -125,8 +126,8 @@ export interface InputGroupProps extends Omit<
125
126
  }
126
127
 
127
128
  /**
128
- * Groups an input with prefix/suffix addons in a visually connected
129
- * container with shared border and focus ring.
129
+ * Groups an input with prefix and suffix addons in one connected row. A
130
+ * focused member stays above its neighbours, so its focus ring shows in full.
130
131
  *
131
132
  * @example
132
133
  * ```
@@ -96,8 +96,10 @@ export const groupStyles = stylex.create({
96
96
  default: 0,
97
97
  [IS_LAST_ITEM]: radiusVars['--radius-element'],
98
98
  },
99
+ // Input wrappers already sit at z-index 1. A focused member goes one
100
+ // higher, so an unfocused input beside it cannot cover its focus ring.
99
101
  ':focus-within': {
100
- zIndex: 1,
102
+ zIndex: 2,
101
103
  },
102
104
  },
103
105
  });
package/src/Item/Item.tsx CHANGED
@@ -4,7 +4,8 @@
4
4
 
5
5
  /**
6
6
  * @file Item.tsx
7
- * @input Uses React, ReactNode, StyleXStyles, theme tokens, useClickableContainer
7
+ * @input Uses React, ReactNode, StyleXStyles, theme tokens, useClickableContainer,
8
+ * the shared press overlays and the compositor press layer
8
9
  * @output Exports Item component, ItemProps type; publishes the shared inline inset.
9
10
  * Only numbered composing rows keep their start/label/end slots in one flex
10
11
  * group, through Item's private exact-marker scope; other marked rows keep
@@ -50,17 +51,22 @@ import {
50
51
  import type {BaseProps} from '../BaseProps';
51
52
  import {isRenderable} from '../utils/isRenderable';
52
53
  import {mergeProps} from '../utils/mergeProps';
54
+ import {chainEventHandlers} from '../utils/chainEventHandlers';
53
55
  import {useFocusAcrossSwap} from '../utils/useFocusAcrossSwap';
54
56
  import {ItemDescriptionContext} from './ItemDescriptionContext';
55
57
  import {ItemMarkerColumnsContext} from './ItemMarkerColumnsContext';
56
58
  import {useMergedRefs} from '../hooks/useMergedRefs';
57
59
  import {computeTargetAndRel} from '../Link/computeTargetAndRel';
58
60
  import {useLinkComponent} from '../Link/useLinkComponent';
59
- import {useClickableContainer} from '../hooks/useClickableContainer';
61
+ import {
62
+ cancelNestedTouchPress,
63
+ useClickableContainer,
64
+ } from '../hooks/useClickableContainer';
60
65
  import {useDevWarning} from '../hooks/useDevWarning';
61
66
  import {themeProps} from '../utils/themeProps';
62
67
  import {focusOutlineProps} from '../utils/focusOutline.stylex';
63
68
  import {interactionOverlayStyles} from '../utils/interactionOverlay.stylex';
69
+ import {rowPressLayerStyles} from '../privateAttributes/press.stylex';
64
70
  import {usePressFeedback} from '../hooks/usePressFeedback';
65
71
  import type {ItemSwipeBridge} from './ItemSwipeLayer';
66
72
 
@@ -532,7 +538,6 @@ const styles = stylex.create({
532
538
  // zoomable (WCAG 1.4.4). The hover transition keeps its own clock beside
533
539
  // the transform's.
534
540
  swipeRoot: {
535
- isolation: 'isolate',
536
541
  touchAction: 'pan-y pinch-zoom',
537
542
  transform: `translate3d(${SWIPE_TRAVEL}, 0, 0)`,
538
543
  transitionProperty: 'background-color, transform',
@@ -618,7 +623,11 @@ export function Item({
618
623
  // the router link component, which may require a live href. The element type
619
624
  // then changes with `isDisabled`, so focus follows the swap (FR4).
620
625
  const RowAnchor = isDisabled ? 'a' : LinkComponent;
621
- const anchorRef = useFocusAcrossSwap<HTMLAnchorElement>();
626
+ // The row's own action, its invisible link or button: a press on it
627
+ // activates the row.
628
+ const actionLinkRef = useRef<HTMLAnchorElement | null>(null);
629
+ const actionButtonRef = useRef<HTMLButtonElement | null>(null);
630
+ const anchorRef = useFocusAcrossSwap<HTMLAnchorElement>(actionLinkRef);
622
631
 
623
632
  // Delegation mode: the row is an enlarged click/tap target for a nested
624
633
  // control (e.g. a checkbox) that owns the keyboard access and action. The
@@ -627,11 +636,12 @@ export function Item({
627
636
  const containerRef = useRef<HTMLElement | null>(null);
628
637
  // Only onClick is needed: onMouseUp handles middle-click href navigation,
629
638
  // which delegation mode never has (href is ignored here).
630
- const {onClick: delegatedOnClick} = useClickableContainer({
631
- containerRef,
632
- interactiveRef: interactiveRef ?? undefined,
633
- disabled: isDisabled,
634
- });
639
+ const {onClick: delegatedOnClick, onPointerDown: delegatedOnPointerDown} =
640
+ useClickableContainer({
641
+ containerRef,
642
+ interactiveRef: interactiveRef ?? undefined,
643
+ disabled: isDisabled,
644
+ });
635
645
 
636
646
  useDevWarning(
637
647
  'Item',
@@ -651,6 +661,18 @@ export function Item({
651
661
  // component means the root itself is the anchor, so the address rides it
652
662
  // and the invisible anchor below is not rendered.
653
663
  const isLinkRoot = typeof Component !== 'string' && href != null;
664
+ // A press on a nested control does not run this row's action, so the row
665
+ // shows no touch press. A row with a parent role or a link root runs it, so
666
+ // it keeps the press. Such a row is not a clickable container: an enclosing
667
+ // card still treats it as part of its own surface.
668
+ const hasOwnAction =
669
+ (onClick != null || href != null) && !hasParentRole && !isLinkRoot;
670
+ const pressOnRow = (event: React.PointerEvent<HTMLElement>) =>
671
+ cancelNestedTouchPress(
672
+ event,
673
+ event.currentTarget,
674
+ href != null ? actionLinkRef.current : actionButtonRef.current,
675
+ );
654
676
 
655
677
  // Swipe actions exist where the row's role permits interactive descendants
656
678
  // (a swipe panel's buttons are such descendants): a `listitem`, or no role
@@ -809,6 +831,7 @@ export function Item({
809
831
  </RowAnchor>
810
832
  ) : onClick != null ? (
811
833
  <button
834
+ ref={actionButtonRef}
812
835
  type="button"
813
836
  onClick={onClick}
814
837
  disabled={isDisabled}
@@ -896,6 +919,21 @@ export function Item({
896
919
  {...restProps}
897
920
  {...swipeHandlers}
898
921
  {...linkRootProps}
922
+ {...(isDelegate
923
+ ? {
924
+ onPointerDown: chainEventHandlers(
925
+ restProps.onPointerDown,
926
+ delegatedOnPointerDown,
927
+ ),
928
+ }
929
+ : hasOwnAction && !isDisabled
930
+ ? {
931
+ onPointerDown: chainEventHandlers(
932
+ swipeHandlers?.onPointerDown ?? restProps.onPointerDown,
933
+ pressOnRow,
934
+ ),
935
+ }
936
+ : null)}
899
937
  aria-selected={(allowsAriaSelected && isSelected) || undefined}
900
938
  // aria-selected is invalid on roles that don't permit it (listitem, a
901
939
  // bare div, etc.). For those, convey selection via aria-current — valid
@@ -916,6 +954,10 @@ export function Item({
916
954
  align === 'first-line' && styles.alignFirstLine,
917
955
  isInteractive && styles.interactive,
918
956
  isInteractive && interactionOverlayStyles.backgroundColor,
957
+ // The touch press on a compositor layer (after the overlay, whose
958
+ // own touch paint it turns off): the release keeps fading while
959
+ // script runs.
960
+ isInteractive && rowPressLayerStyles.cell,
919
961
  isLinkRoot && styles.linkRoot,
920
962
  isHighlighted && styles.highlighted,
921
963
  isSelected && styles.selected,