@astryxdesign/core 0.7.8 → 0.7.9-canary.0a64fdb

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 (276) 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/Calendar/styles.d.ts +1 -1
  6. package/dist/CheckboxInput/CheckboxInput.d.ts.map +1 -1
  7. package/dist/CheckboxInput/CheckboxInput.js +54 -11
  8. package/dist/ClickableCard/ClickableCard.d.ts +1 -1
  9. package/dist/ClickableCard/ClickableCard.d.ts.map +1 -1
  10. package/dist/ClickableCard/ClickableCard.js +5 -1
  11. package/dist/DateInput/PickerWheel.d.ts.map +1 -1
  12. package/dist/DateInput/PickerWheel.js +7 -1
  13. package/dist/DateRangeInput/DateRangeInput.js +1 -1
  14. package/dist/Dialog/Dialog.d.ts +2 -1
  15. package/dist/Dialog/Dialog.d.ts.map +1 -1
  16. package/dist/Dialog/Dialog.js +12 -1
  17. package/dist/Drawer/useDrawerDialogPresence.d.ts +2 -1
  18. package/dist/Drawer/useDrawerDialogPresence.d.ts.map +1 -1
  19. package/dist/Drawer/useDrawerDialogPresence.js +11 -2
  20. package/dist/DropdownMenu/DropdownMenu.d.ts +9 -1
  21. package/dist/DropdownMenu/DropdownMenu.d.ts.map +1 -1
  22. package/dist/DropdownMenu/DropdownMenu.js +9 -4
  23. package/dist/DropdownMenu/DropdownMenuCheckboxItem.d.ts.map +1 -1
  24. package/dist/DropdownMenu/DropdownMenuCheckboxItem.js +3 -2
  25. package/dist/DropdownMenu/DropdownMenuItem.d.ts.map +1 -1
  26. package/dist/DropdownMenu/DropdownMenuItem.js +3 -2
  27. package/dist/DropdownMenu/DropdownMenuRadioItem.d.ts.map +1 -1
  28. package/dist/DropdownMenu/DropdownMenuRadioItem.js +3 -2
  29. package/dist/DropdownMenu/DropdownMenuSubMenu.d.ts.map +1 -1
  30. package/dist/DropdownMenu/DropdownMenuSubMenu.js +3 -2
  31. package/dist/Field/inputDisabledFocus.d.ts +4 -4
  32. package/dist/Field/inputStyles.stylex.d.ts +1 -1
  33. package/dist/FileInput/FileInput.d.ts.map +1 -1
  34. package/dist/FileInput/FileInput.js +16 -2
  35. package/dist/Icon/Icon.d.ts +1 -1
  36. package/dist/InfoTip/InfoTip.d.ts +1 -0
  37. package/dist/InfoTip/InfoTip.d.ts.map +1 -1
  38. package/dist/InfoTip/InfoTip.js +1 -0
  39. package/dist/InputGroup/InputGroup.d.ts +4 -3
  40. package/dist/InputGroup/InputGroup.d.ts.map +1 -1
  41. package/dist/InputGroup/InputGroup.js +2 -2
  42. package/dist/InputGroup/groupStyles.d.ts +1 -1
  43. package/dist/InputGroup/groupStyles.d.ts.map +1 -1
  44. package/dist/InputGroup/groupStyles.js +1 -1
  45. package/dist/Item/Item.d.ts +2 -1
  46. package/dist/Item/Item.d.ts.map +1 -1
  47. package/dist/Item/Item.js +29 -6
  48. package/dist/Layer/holdEntranceInput.d.ts +24 -0
  49. package/dist/Layer/holdEntranceInput.d.ts.map +1 -0
  50. package/dist/Layer/holdEntranceInput.js +65 -0
  51. package/dist/Layer/inputHold.d.ts +49 -0
  52. package/dist/Layer/inputHold.d.ts.map +1 -0
  53. package/dist/Layer/inputHold.js +636 -0
  54. package/dist/Layer/preserveAnimations.d.ts +1 -5
  55. package/dist/Layer/preserveAnimations.d.ts.map +1 -1
  56. package/dist/Layer/preserveAnimations.js +12 -214
  57. package/dist/Layout/LayoutContent.d.ts +3 -1
  58. package/dist/Layout/LayoutContent.d.ts.map +1 -1
  59. package/dist/Layout/LayoutContent.js +12 -4
  60. package/dist/Layout/LayoutPanel.d.ts +4 -1
  61. package/dist/Layout/LayoutPanel.d.ts.map +1 -1
  62. package/dist/Layout/LayoutPanel.js +13 -4
  63. package/dist/Lightbox/Lightbox.d.ts.map +1 -1
  64. package/dist/Lightbox/Lightbox.js +4 -0
  65. package/dist/MetadataList/MetadataList.js +1 -1
  66. package/dist/MobileNav/MobileNav.d.ts +11 -1
  67. package/dist/MobileNav/MobileNav.d.ts.map +1 -1
  68. package/dist/MobileNav/MobileNav.js +39 -1
  69. package/dist/MoreMenu/MoreMenu.d.ts +5 -3
  70. package/dist/MoreMenu/MoreMenu.d.ts.map +1 -1
  71. package/dist/RadioList/RadioListItem.d.ts.map +1 -1
  72. package/dist/RadioList/RadioListItem.js +22 -4
  73. package/dist/SelectableCard/SelectableCard.d.ts +1 -1
  74. package/dist/SelectableCard/SelectableCard.d.ts.map +1 -1
  75. package/dist/SelectableCard/SelectableCard.js +5 -1
  76. package/dist/Spinner/Spinner.d.ts.map +1 -1
  77. package/dist/Spinner/Spinner.js +12 -2
  78. package/dist/Stack/StackItem.d.ts +8 -4
  79. package/dist/Stack/StackItem.d.ts.map +1 -1
  80. package/dist/Stack/StackItem.js +17 -4
  81. package/dist/Table/plugins/sortable/useTableSortable.js +1 -1
  82. package/dist/Token/Token.d.ts.map +1 -1
  83. package/dist/Token/Token.js +9 -0
  84. package/dist/Token/TokenLink.d.ts +1 -1
  85. package/dist/Token/TokenLink.d.ts.map +1 -1
  86. package/dist/Token/TokenLink.js +4 -1
  87. package/dist/Tooltip/useTooltip.d.ts.map +1 -1
  88. package/dist/Tooltip/useTooltip.js +162 -59
  89. package/dist/TreeList/TreeListItem.d.ts +2 -1
  90. package/dist/TreeList/TreeListItem.d.ts.map +1 -1
  91. package/dist/TreeList/TreeListItem.js +27 -3
  92. package/dist/astryx.css +35 -8
  93. package/dist/gestures/GestureHost.d.ts +2 -2
  94. package/dist/gestures/GestureHost.d.ts.map +1 -1
  95. package/dist/gestures/GestureHost.js +21 -6
  96. package/dist/gestures/PanGestureRecognizer.d.ts +11 -1
  97. package/dist/gestures/PanGestureRecognizer.d.ts.map +1 -1
  98. package/dist/gestures/PanGestureRecognizer.js +15 -1
  99. package/dist/gestures/ScreenEdgePanGestureRecognizer.d.ts +6 -1
  100. package/dist/gestures/ScreenEdgePanGestureRecognizer.d.ts.map +1 -1
  101. package/dist/gestures/nativeScroll.d.ts +3 -6
  102. package/dist/gestures/nativeScroll.d.ts.map +1 -1
  103. package/dist/gestures/nativeScroll.js +7 -52
  104. package/dist/gestures/wheelSegmenter.d.ts +68 -1
  105. package/dist/gestures/wheelSegmenter.d.ts.map +1 -1
  106. package/dist/gestures/wheelSegmenter.js +199 -10
  107. package/dist/hooks/StackItemScrollRegion.d.ts +31 -0
  108. package/dist/hooks/StackItemScrollRegion.d.ts.map +1 -0
  109. package/dist/hooks/StackItemScrollRegion.js +40 -0
  110. package/dist/hooks/menuPressGesture.d.ts +133 -21
  111. package/dist/hooks/menuPressGesture.d.ts.map +1 -1
  112. package/dist/hooks/menuPressGesture.js +155 -30
  113. package/dist/hooks/menuPressValues.d.ts +16 -0
  114. package/dist/hooks/menuPressValues.d.ts.map +1 -0
  115. package/dist/hooks/menuPressValues.js +18 -0
  116. package/dist/hooks/useClickableContainer.d.ts +27 -5
  117. package/dist/hooks/useClickableContainer.d.ts.map +1 -1
  118. package/dist/hooks/useClickableContainer.js +41 -5
  119. package/dist/hooks/useFocusTrap.d.ts +10 -0
  120. package/dist/hooks/useFocusTrap.d.ts.map +1 -1
  121. package/dist/hooks/useFocusTrap.js +225 -132
  122. package/dist/hooks/useMenuPress.d.ts +34 -1
  123. package/dist/hooks/useMenuPress.d.ts.map +1 -1
  124. package/dist/hooks/useMenuPress.js +93 -5
  125. package/dist/hooks/usePressFeedback.d.ts +6 -6
  126. package/dist/hooks/usePressFeedback.js +6 -6
  127. package/dist/hooks/useScrollRegionProps.d.ts +35 -0
  128. package/dist/hooks/useScrollRegionProps.d.ts.map +1 -0
  129. package/dist/hooks/useScrollRegionProps.js +51 -0
  130. package/dist/i18n/generated-english/hooks/useScrollRegionProps.generated.d.ts +8 -0
  131. package/dist/i18n/generated-english/hooks/useScrollRegionProps.generated.d.ts.map +1 -0
  132. package/dist/i18n/generated-english/hooks/useScrollRegionProps.generated.js +12 -0
  133. package/dist/i18n/generated-locales/en.generated.d.ts.map +1 -1
  134. package/dist/i18n/generated-locales/en.generated.js +1 -0
  135. package/dist/i18n/generated-locales/pseudo.generated.d.ts.map +1 -1
  136. package/dist/i18n/generated-locales/pseudo.generated.js +1 -0
  137. package/dist/motion/carryAnimations.d.ts +58 -0
  138. package/dist/motion/carryAnimations.d.ts.map +1 -0
  139. package/dist/motion/carryAnimations.js +305 -0
  140. package/dist/motion/transientCopy.d.ts +4 -2
  141. package/dist/motion/transientCopy.d.ts.map +1 -1
  142. package/dist/motion/transientCopy.js +34 -5
  143. package/dist/motion/uikit/gestures.d.ts +41 -0
  144. package/dist/motion/uikit/gestures.d.ts.map +1 -1
  145. package/dist/motion/uikit/gestures.js +25 -0
  146. package/dist/motion/uikit/index.d.ts +1 -1
  147. package/dist/motion/uikit/index.d.ts.map +1 -1
  148. package/dist/motion/uikit/index.js +1 -1
  149. package/dist/privateAttributes/menuPressLit.stylex.d.ts +52 -0
  150. package/dist/privateAttributes/menuPressLit.stylex.d.ts.map +1 -0
  151. package/dist/privateAttributes/menuPressLit.stylex.js +99 -0
  152. package/dist/privateAttributes/press.stylex.d.ts +139 -0
  153. package/dist/privateAttributes/press.stylex.d.ts.map +1 -0
  154. package/dist/privateAttributes/press.stylex.js +98 -0
  155. package/dist/theme/tokens.stylex.d.ts +2 -2
  156. package/dist/theme/tokens.stylex.js +1 -1
  157. package/dist/utils/flatTree.d.ts +6 -3
  158. package/dist/utils/flatTree.d.ts.map +1 -1
  159. package/dist/utils/flatTree.js +13 -3
  160. package/dist/utils/hitArea.d.ts.map +1 -1
  161. package/dist/utils/hitArea.js +82 -5
  162. package/dist/utils/inputStream.d.ts +14 -1
  163. package/dist/utils/inputStream.d.ts.map +1 -1
  164. package/dist/utils/inputStream.js +40 -9
  165. package/dist/utils/interactionOverlay.stylex.d.ts +2 -1
  166. package/dist/utils/interactionOverlay.stylex.d.ts.map +1 -1
  167. package/dist/utils/interactionOverlay.stylex.js +7 -2
  168. package/dist/utils/pressFeedback.d.ts +7 -0
  169. package/dist/utils/pressFeedback.d.ts.map +1 -1
  170. package/dist/utils/pressFeedback.js +32 -7
  171. package/dist/utils/pressGesture.d.ts +6 -0
  172. package/dist/utils/pressGesture.d.ts.map +1 -1
  173. package/dist/utils/pressGesture.js +17 -0
  174. package/dist/utils/rowPressLayer.stylex.d.ts +14 -0
  175. package/dist/utils/rowPressLayer.stylex.d.ts.map +1 -0
  176. package/dist/utils/rowPressLayer.stylex.js +25 -0
  177. package/dist/utils/scrollView.d.ts +25 -0
  178. package/dist/utils/scrollView.d.ts.map +1 -0
  179. package/dist/utils/scrollView.js +108 -0
  180. package/dist/utils/selectionLock.d.ts.map +1 -1
  181. package/dist/utils/selectionLock.js +1 -10
  182. package/dist/utils/touchHitArea.stylex.d.ts +35 -0
  183. package/dist/utils/touchHitArea.stylex.d.ts.map +1 -0
  184. package/dist/utils/touchHitArea.stylex.js +32 -0
  185. package/dist/utils/triggerFocus.d.ts +5 -0
  186. package/dist/utils/triggerFocus.d.ts.map +1 -1
  187. package/dist/utils/triggerFocus.js +9 -2
  188. package/locales/en.json +4 -0
  189. package/locales/pseudo.json +3 -0
  190. package/package.json +5 -5
  191. package/src/AppShell/observeMainOverflow.ts +9 -6
  192. package/src/BottomSheet/BottomSheet.tsx +5 -0
  193. package/src/CheckboxInput/CheckboxInput.doc.mjs +3 -2
  194. package/src/CheckboxInput/CheckboxInput.tsx +71 -9
  195. package/src/ClickableCard/ClickableCard.tsx +8 -1
  196. package/src/DateInput/PickerWheel.tsx +7 -2
  197. package/src/DateRangeInput/DateRangeInput.tsx +1 -1
  198. package/src/Dialog/Dialog.doc.mjs +1 -1
  199. package/src/Dialog/Dialog.tsx +12 -1
  200. package/src/Drawer/Drawer.doc.mjs +1 -1
  201. package/src/Drawer/useDrawerDialogPresence.ts +9 -2
  202. package/src/DropdownMenu/DropdownMenu.doc.mjs +1 -2
  203. package/src/DropdownMenu/DropdownMenu.tsx +29 -5
  204. package/src/DropdownMenu/DropdownMenuCheckboxItem.tsx +5 -1
  205. package/src/DropdownMenu/DropdownMenuItem.tsx +8 -4
  206. package/src/DropdownMenu/DropdownMenuRadioItem.tsx +5 -1
  207. package/src/DropdownMenu/DropdownMenuSubMenu.tsx +5 -1
  208. package/src/FileInput/FileInput.tsx +16 -2
  209. package/src/InfoTip/InfoTip.doc.mjs +26 -2
  210. package/src/InfoTip/InfoTip.tsx +1 -0
  211. package/src/InputGroup/InputGroup.doc.mjs +4 -3
  212. package/src/InputGroup/InputGroup.tsx +4 -3
  213. package/src/InputGroup/groupStyles.ts +3 -1
  214. package/src/Item/Item.tsx +51 -9
  215. package/src/Layer/holdEntranceInput.ts +84 -0
  216. package/src/Layer/inputHold.ts +734 -0
  217. package/src/Layer/preserveAnimations.ts +12 -275
  218. package/src/Layout/LayoutContent.doc.mjs +6 -3
  219. package/src/Layout/LayoutContent.tsx +10 -4
  220. package/src/Layout/LayoutPanel.doc.mjs +6 -3
  221. package/src/Layout/LayoutPanel.tsx +11 -4
  222. package/src/Lightbox/Lightbox.tsx +4 -0
  223. package/src/MetadataList/MetadataList.tsx +1 -1
  224. package/src/MobileNav/MobileNav.doc.mjs +3 -3
  225. package/src/MobileNav/MobileNav.tsx +39 -1
  226. package/src/MoreMenu/MoreMenu.doc.mjs +2 -4
  227. package/src/MoreMenu/MoreMenu.tsx +5 -3
  228. package/src/RadioList/RadioListItem.doc.mjs +3 -2
  229. package/src/RadioList/RadioListItem.tsx +25 -7
  230. package/src/SelectableCard/SelectableCard.tsx +8 -1
  231. package/src/Spinner/Spinner.tsx +13 -3
  232. package/src/Stack/Stack.doc.mjs +1 -1
  233. package/src/Stack/StackItem.tsx +27 -13
  234. package/src/Table/plugins/sortable/useTableSortable.tsx +1 -1
  235. package/src/Token/Token.tsx +18 -1
  236. package/src/Token/TokenLink.tsx +7 -1
  237. package/src/Tooltip/useTooltip.tsx +175 -79
  238. package/src/TreeList/TreeListItem.tsx +36 -2
  239. package/src/gestures/GestureHost.ts +21 -5
  240. package/src/gestures/PanGestureRecognizer.ts +19 -2
  241. package/src/gestures/README.md +14 -5
  242. package/src/gestures/ScreenEdgePanGestureRecognizer.ts +6 -1
  243. package/src/gestures/nativeScroll.ts +12 -68
  244. package/src/gestures/wheelSegmenter.ts +243 -10
  245. package/src/hooks/StackItemScrollRegion.tsx +57 -0
  246. package/src/hooks/menuPressGesture.ts +244 -38
  247. package/src/hooks/menuPressValues.ts +18 -0
  248. package/src/hooks/useClickableContainer.doc.mjs +8 -2
  249. package/src/hooks/useClickableContainer.ts +72 -6
  250. package/src/hooks/useFocusTrap.ts +268 -151
  251. package/src/hooks/useMenuPress.ts +118 -11
  252. package/src/hooks/usePressFeedback.doc.mjs +3 -3
  253. package/src/hooks/usePressFeedback.ts +6 -6
  254. package/src/hooks/useScrollRegionProps.ts +76 -0
  255. package/src/i18n/generated-english/hooks/useScrollRegionProps.generated.ts +13 -0
  256. package/src/i18n/generated-locales/en.generated.ts +1 -0
  257. package/src/i18n/generated-locales/pseudo.generated.ts +1 -0
  258. package/src/motion/MEASUREMENTS.md +11 -0
  259. package/src/motion/carryAnimations.ts +389 -0
  260. package/src/motion/transientCopy.ts +45 -5
  261. package/src/motion/uikit/gestures.ts +22 -0
  262. package/src/motion/uikit/index.ts +1 -0
  263. package/src/privateAttributes/menuPressLit.stylex.ts +104 -0
  264. package/src/privateAttributes/press.stylex.ts +244 -0
  265. package/src/theme/tokens.stylex.ts +1 -1
  266. package/src/utils/flatTree.ts +15 -3
  267. package/src/utils/hitArea.ts +107 -5
  268. package/src/utils/inputStream.ts +47 -10
  269. package/src/utils/interactionOverlay.stylex.ts +7 -2
  270. package/src/utils/pressFeedback.ts +31 -6
  271. package/src/utils/pressGesture.ts +24 -1
  272. package/src/utils/rowPressLayer.stylex.ts +27 -0
  273. package/src/utils/scrollView.ts +135 -0
  274. package/src/utils/selectionLock.ts +5 -10
  275. package/src/utils/touchHitArea.stylex.ts +41 -0
  276. package/src/utils/triggerFocus.ts +17 -4
@@ -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
  },
@@ -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,
@@ -0,0 +1,84 @@
1
+ // Copyright (c) Meta Platforms, Inc. and affiliates.
2
+
3
+ 'use client';
4
+
5
+ /**
6
+ * @file holdEntranceInput.ts
7
+ * @input A layer root whose CSS entrance has just started
8
+ * @output holdEntranceInput: under a coarse primary pointer, a finger's or a
9
+ * pen's input held away from the layer until its entrance ends
10
+ * @position The entrance hold for layers that enter through CSS (Dialog,
11
+ * Drawer, MobileNav), on the Layer module's input hold (inputHold.ts)
12
+ *
13
+ * SYNC: When modified, update holdEntranceInput.test.ts and its callers
14
+ * (Dialog.tsx, Drawer/useDrawerDialogPresence.ts, MobileNav/MobileNav.tsx).
15
+ */
16
+
17
+ import {isCoarsePointer} from '../utils/coarsePointer';
18
+ import {holdInput} from './inputHold';
19
+
20
+ /** Options for {@link holdEntranceInput}. */
21
+ export interface EntranceHoldOptions {
22
+ /**
23
+ * Holds input anywhere while true. While false, only what lands on the layer
24
+ * is held, and the page stays live.
25
+ * @default true
26
+ */
27
+ isModal?: boolean;
28
+ /**
29
+ * The element whose animations are the entrance, when it is not the layer
30
+ * itself (a drawer inside its dialog).
31
+ * @default the layer
32
+ */
33
+ entrance?: Element | null;
34
+ /** The longest the hold lasts, ms. An entrance that runs longer ends it. */
35
+ capMs?: number;
36
+ }
37
+
38
+ /**
39
+ * Holds a finger's and a pen's input away from `layer` until its entrance
40
+ * ends, or at most `capMs`. Returns the release, or `null` when nothing is
41
+ * held: no entrance runs, or the primary pointer is fine.
42
+ */
43
+ export function holdEntranceInput(
44
+ layer: Element,
45
+ {isModal = true, entrance: animated = layer, capMs}: EntranceHoldOptions = {},
46
+ ): (() => void) | null {
47
+ if (animated == null || typeof animated.getAnimations !== 'function') {
48
+ return null;
49
+ }
50
+ // getAnimations() flushes styles, so it lists an entrance the open has just
51
+ // started. A theme's duration, a shorter reduced-motion entrance and a
52
+ // canceled entrance all end the hold when they end.
53
+ const entrance = animated.getAnimations().filter(isEntrance);
54
+ if (entrance.length === 0) {
55
+ return null;
56
+ }
57
+ // A touch presentation only, read as the layer opens. A finger on a device
58
+ // whose primary pointer is fine, such as a touchscreen laptop, is not held.
59
+ if (!isCoarsePointer(layer.ownerDocument.defaultView)) {
60
+ return null;
61
+ }
62
+ const ended = Promise.all(
63
+ entrance.map(async animation => animation.finished),
64
+ );
65
+ return holdInput(layer, {
66
+ until: capMs == null ? ended : Promise.race([ended, after(capMs)]),
67
+ scope: isModal ? 'viewport' : 'surface',
68
+ });
69
+ }
70
+
71
+ async function after(ms: number): Promise<void> {
72
+ await new Promise(resolve => {
73
+ setTimeout(resolve, ms);
74
+ });
75
+ }
76
+
77
+ /** A running animation that ends on its own: an entrance, not a spin. */
78
+ function isEntrance(animation: Animation): boolean {
79
+ if (animation.playState !== 'running') {
80
+ return false;
81
+ }
82
+ const end = animation.effect?.getComputedTiming().endTime;
83
+ return typeof end === 'number' && Number.isFinite(end);
84
+ }