@astryxdesign/core 0.7.8 → 0.7.9-canary.7400c1f

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 (203) hide show
  1. package/dist/Calendar/styles.d.ts +1 -1
  2. package/dist/ClickableCard/ClickableCard.d.ts +1 -1
  3. package/dist/ClickableCard/ClickableCard.d.ts.map +1 -1
  4. package/dist/ClickableCard/ClickableCard.js +5 -1
  5. package/dist/DateInput/PickerWheel.d.ts.map +1 -1
  6. package/dist/DateInput/PickerWheel.js +7 -1
  7. package/dist/DateRangeInput/DateRangeInput.js +1 -1
  8. package/dist/Dialog/Dialog.d.ts +2 -1
  9. package/dist/Dialog/Dialog.d.ts.map +1 -1
  10. package/dist/Dialog/Dialog.js +8 -1
  11. package/dist/Drawer/useDrawerDialogPresence.d.ts +2 -1
  12. package/dist/Drawer/useDrawerDialogPresence.d.ts.map +1 -1
  13. package/dist/Drawer/useDrawerDialogPresence.js +11 -2
  14. package/dist/DropdownMenu/DropdownMenu.d.ts +9 -1
  15. package/dist/DropdownMenu/DropdownMenu.d.ts.map +1 -1
  16. package/dist/DropdownMenu/DropdownMenu.js +9 -4
  17. package/dist/DropdownMenu/DropdownMenuCheckboxItem.d.ts.map +1 -1
  18. package/dist/DropdownMenu/DropdownMenuCheckboxItem.js +3 -2
  19. package/dist/DropdownMenu/DropdownMenuItem.d.ts.map +1 -1
  20. package/dist/DropdownMenu/DropdownMenuItem.js +3 -2
  21. package/dist/DropdownMenu/DropdownMenuRadioItem.d.ts.map +1 -1
  22. package/dist/DropdownMenu/DropdownMenuRadioItem.js +3 -2
  23. package/dist/DropdownMenu/DropdownMenuSubMenu.d.ts.map +1 -1
  24. package/dist/DropdownMenu/DropdownMenuSubMenu.js +3 -2
  25. package/dist/Field/inputDisabledFocus.d.ts +4 -4
  26. package/dist/Field/inputStyles.stylex.d.ts +1 -1
  27. package/dist/FileInput/FileInput.d.ts.map +1 -1
  28. package/dist/FileInput/FileInput.js +16 -2
  29. package/dist/Icon/Icon.d.ts +1 -1
  30. package/dist/InfoTip/InfoTip.d.ts +1 -0
  31. package/dist/InfoTip/InfoTip.d.ts.map +1 -1
  32. package/dist/InfoTip/InfoTip.js +1 -0
  33. package/dist/Item/Item.d.ts +2 -1
  34. package/dist/Item/Item.d.ts.map +1 -1
  35. package/dist/Item/Item.js +29 -6
  36. package/dist/Layer/holdEntranceInput.d.ts +24 -0
  37. package/dist/Layer/holdEntranceInput.d.ts.map +1 -0
  38. package/dist/Layer/holdEntranceInput.js +65 -0
  39. package/dist/Layer/inputHold.d.ts +49 -0
  40. package/dist/Layer/inputHold.d.ts.map +1 -0
  41. package/dist/Layer/inputHold.js +636 -0
  42. package/dist/Layer/preserveAnimations.d.ts +1 -5
  43. package/dist/Layer/preserveAnimations.d.ts.map +1 -1
  44. package/dist/Layer/preserveAnimations.js +12 -214
  45. package/dist/MetadataList/MetadataList.js +1 -1
  46. package/dist/MobileNav/MobileNav.d.ts +11 -1
  47. package/dist/MobileNav/MobileNav.d.ts.map +1 -1
  48. package/dist/MobileNav/MobileNav.js +34 -1
  49. package/dist/MoreMenu/MoreMenu.d.ts +5 -3
  50. package/dist/MoreMenu/MoreMenu.d.ts.map +1 -1
  51. package/dist/RadioList/RadioListItem.d.ts.map +1 -1
  52. package/dist/RadioList/RadioListItem.js +4 -1
  53. package/dist/SelectableCard/SelectableCard.d.ts +1 -1
  54. package/dist/SelectableCard/SelectableCard.d.ts.map +1 -1
  55. package/dist/SelectableCard/SelectableCard.js +5 -1
  56. package/dist/Spinner/Spinner.d.ts.map +1 -1
  57. package/dist/Spinner/Spinner.js +12 -2
  58. package/dist/Table/plugins/sortable/useTableSortable.js +1 -1
  59. package/dist/Token/Token.d.ts.map +1 -1
  60. package/dist/Token/Token.js +9 -0
  61. package/dist/Token/TokenLink.d.ts +1 -1
  62. package/dist/Token/TokenLink.d.ts.map +1 -1
  63. package/dist/Token/TokenLink.js +4 -1
  64. package/dist/Tooltip/useTooltip.d.ts.map +1 -1
  65. package/dist/Tooltip/useTooltip.js +162 -59
  66. package/dist/TreeList/TreeListItem.d.ts +2 -1
  67. package/dist/TreeList/TreeListItem.d.ts.map +1 -1
  68. package/dist/TreeList/TreeListItem.js +27 -3
  69. package/dist/astryx.css +30 -7
  70. package/dist/gestures/GestureHost.d.ts +2 -2
  71. package/dist/gestures/GestureHost.d.ts.map +1 -1
  72. package/dist/gestures/GestureHost.js +21 -6
  73. package/dist/gestures/nativeScroll.d.ts +3 -6
  74. package/dist/gestures/nativeScroll.d.ts.map +1 -1
  75. package/dist/gestures/nativeScroll.js +7 -52
  76. package/dist/gestures/wheelSegmenter.d.ts +68 -1
  77. package/dist/gestures/wheelSegmenter.d.ts.map +1 -1
  78. package/dist/gestures/wheelSegmenter.js +199 -10
  79. package/dist/hooks/menuPressGesture.d.ts +133 -21
  80. package/dist/hooks/menuPressGesture.d.ts.map +1 -1
  81. package/dist/hooks/menuPressGesture.js +155 -30
  82. package/dist/hooks/menuPressValues.d.ts +16 -0
  83. package/dist/hooks/menuPressValues.d.ts.map +1 -0
  84. package/dist/hooks/menuPressValues.js +18 -0
  85. package/dist/hooks/useClickableContainer.d.ts +27 -5
  86. package/dist/hooks/useClickableContainer.d.ts.map +1 -1
  87. package/dist/hooks/useClickableContainer.js +41 -5
  88. package/dist/hooks/useMenuPress.d.ts +34 -1
  89. package/dist/hooks/useMenuPress.d.ts.map +1 -1
  90. package/dist/hooks/useMenuPress.js +93 -5
  91. package/dist/hooks/usePressFeedback.d.ts +6 -6
  92. package/dist/hooks/usePressFeedback.js +6 -6
  93. package/dist/motion/carryAnimations.d.ts +58 -0
  94. package/dist/motion/carryAnimations.d.ts.map +1 -0
  95. package/dist/motion/carryAnimations.js +305 -0
  96. package/dist/motion/transientCopy.d.ts +4 -2
  97. package/dist/motion/transientCopy.d.ts.map +1 -1
  98. package/dist/motion/transientCopy.js +34 -5
  99. package/dist/motion/uikit/gestures.d.ts +41 -0
  100. package/dist/motion/uikit/gestures.d.ts.map +1 -1
  101. package/dist/motion/uikit/gestures.js +25 -0
  102. package/dist/motion/uikit/index.d.ts +1 -1
  103. package/dist/motion/uikit/index.d.ts.map +1 -1
  104. package/dist/motion/uikit/index.js +1 -1
  105. package/dist/privateAttributes/menuPressLit.stylex.d.ts +52 -0
  106. package/dist/privateAttributes/menuPressLit.stylex.d.ts.map +1 -0
  107. package/dist/privateAttributes/menuPressLit.stylex.js +99 -0
  108. package/dist/privateAttributes/press.stylex.d.ts +139 -0
  109. package/dist/privateAttributes/press.stylex.d.ts.map +1 -0
  110. package/dist/privateAttributes/press.stylex.js +98 -0
  111. package/dist/theme/tokens.stylex.d.ts +2 -2
  112. package/dist/theme/tokens.stylex.js +1 -1
  113. package/dist/utils/flatTree.d.ts +6 -3
  114. package/dist/utils/flatTree.d.ts.map +1 -1
  115. package/dist/utils/flatTree.js +13 -3
  116. package/dist/utils/hitArea.d.ts.map +1 -1
  117. package/dist/utils/hitArea.js +82 -5
  118. package/dist/utils/inputStream.d.ts +14 -1
  119. package/dist/utils/inputStream.d.ts.map +1 -1
  120. package/dist/utils/inputStream.js +40 -9
  121. package/dist/utils/interactionOverlay.stylex.d.ts +2 -1
  122. package/dist/utils/interactionOverlay.stylex.d.ts.map +1 -1
  123. package/dist/utils/interactionOverlay.stylex.js +7 -2
  124. package/dist/utils/pressFeedback.d.ts +7 -0
  125. package/dist/utils/pressFeedback.d.ts.map +1 -1
  126. package/dist/utils/pressFeedback.js +32 -7
  127. package/dist/utils/pressGesture.d.ts +6 -0
  128. package/dist/utils/pressGesture.d.ts.map +1 -1
  129. package/dist/utils/pressGesture.js +17 -0
  130. package/dist/utils/rowPressLayer.stylex.d.ts +14 -0
  131. package/dist/utils/rowPressLayer.stylex.d.ts.map +1 -0
  132. package/dist/utils/rowPressLayer.stylex.js +25 -0
  133. package/dist/utils/scrollView.d.ts +25 -0
  134. package/dist/utils/scrollView.d.ts.map +1 -0
  135. package/dist/utils/scrollView.js +108 -0
  136. package/dist/utils/selectionLock.d.ts.map +1 -1
  137. package/dist/utils/selectionLock.js +1 -10
  138. package/dist/utils/triggerFocus.d.ts +5 -0
  139. package/dist/utils/triggerFocus.d.ts.map +1 -1
  140. package/dist/utils/triggerFocus.js +9 -2
  141. package/package.json +5 -5
  142. package/src/ClickableCard/ClickableCard.tsx +8 -1
  143. package/src/DateInput/PickerWheel.tsx +7 -2
  144. package/src/DateRangeInput/DateRangeInput.tsx +1 -1
  145. package/src/Dialog/Dialog.doc.mjs +1 -1
  146. package/src/Dialog/Dialog.tsx +8 -1
  147. package/src/Drawer/Drawer.doc.mjs +1 -1
  148. package/src/Drawer/useDrawerDialogPresence.ts +9 -2
  149. package/src/DropdownMenu/DropdownMenu.doc.mjs +1 -2
  150. package/src/DropdownMenu/DropdownMenu.tsx +29 -5
  151. package/src/DropdownMenu/DropdownMenuCheckboxItem.tsx +5 -1
  152. package/src/DropdownMenu/DropdownMenuItem.tsx +8 -4
  153. package/src/DropdownMenu/DropdownMenuRadioItem.tsx +5 -1
  154. package/src/DropdownMenu/DropdownMenuSubMenu.tsx +5 -1
  155. package/src/FileInput/FileInput.tsx +16 -2
  156. package/src/InfoTip/InfoTip.doc.mjs +26 -2
  157. package/src/InfoTip/InfoTip.tsx +1 -0
  158. package/src/Item/Item.tsx +51 -9
  159. package/src/Layer/holdEntranceInput.ts +84 -0
  160. package/src/Layer/inputHold.ts +734 -0
  161. package/src/Layer/preserveAnimations.ts +12 -275
  162. package/src/MetadataList/MetadataList.tsx +1 -1
  163. package/src/MobileNav/MobileNav.doc.mjs +3 -3
  164. package/src/MobileNav/MobileNav.tsx +34 -1
  165. package/src/MoreMenu/MoreMenu.doc.mjs +2 -4
  166. package/src/MoreMenu/MoreMenu.tsx +5 -3
  167. package/src/RadioList/RadioListItem.tsx +4 -5
  168. package/src/SelectableCard/SelectableCard.tsx +8 -1
  169. package/src/Spinner/Spinner.tsx +13 -3
  170. package/src/Table/plugins/sortable/useTableSortable.tsx +1 -1
  171. package/src/Token/Token.tsx +18 -1
  172. package/src/Token/TokenLink.tsx +7 -1
  173. package/src/Tooltip/useTooltip.tsx +175 -79
  174. package/src/TreeList/TreeListItem.tsx +36 -2
  175. package/src/gestures/GestureHost.ts +21 -5
  176. package/src/gestures/README.md +12 -4
  177. package/src/gestures/nativeScroll.ts +12 -68
  178. package/src/gestures/wheelSegmenter.ts +243 -10
  179. package/src/hooks/menuPressGesture.ts +244 -38
  180. package/src/hooks/menuPressValues.ts +18 -0
  181. package/src/hooks/useClickableContainer.doc.mjs +8 -2
  182. package/src/hooks/useClickableContainer.ts +72 -6
  183. package/src/hooks/useMenuPress.ts +118 -11
  184. package/src/hooks/usePressFeedback.doc.mjs +3 -3
  185. package/src/hooks/usePressFeedback.ts +6 -6
  186. package/src/motion/MEASUREMENTS.md +11 -0
  187. package/src/motion/carryAnimations.ts +389 -0
  188. package/src/motion/transientCopy.ts +45 -5
  189. package/src/motion/uikit/gestures.ts +22 -0
  190. package/src/motion/uikit/index.ts +1 -0
  191. package/src/privateAttributes/menuPressLit.stylex.ts +104 -0
  192. package/src/privateAttributes/press.stylex.ts +244 -0
  193. package/src/theme/tokens.stylex.ts +1 -1
  194. package/src/utils/flatTree.ts +15 -3
  195. package/src/utils/hitArea.ts +107 -5
  196. package/src/utils/inputStream.ts +47 -10
  197. package/src/utils/interactionOverlay.stylex.ts +7 -2
  198. package/src/utils/pressFeedback.ts +31 -6
  199. package/src/utils/pressGesture.ts +24 -1
  200. package/src/utils/rowPressLayer.stylex.ts +27 -0
  201. package/src/utils/scrollView.ts +135 -0
  202. package/src/utils/selectionLock.ts +5 -10
  203. package/src/utils/triggerFocus.ts +17 -4
@@ -1,19 +1,16 @@
1
1
  /**
2
- * @file menuPressGesture.ts
3
- * @input A menu press gesture and one pointer event, both as plain data
4
- * @output The pure `menuPressStep` state machine, its state, event and effect
5
- * types, and the settle constant
6
- * @position Pure module under `useMenuPress`. It has no DOM and no React, so
7
- * a unit test can check each transition without a browser.
8
- *
9
- * SYNC: When modified, update:
10
- * - /packages/core/src/hooks/menuPressGesture.test.ts
11
- * - /packages/core/src/hooks/useMenuPress.ts
2
+ * How long the opening press must last before its release may act, unless a
3
+ * finger's handoff applies.
12
4
  */
13
- /** How long the opening press must last before its release may act. */
14
5
  export declare const MENU_PRESS_SETTLE_MS = 300;
6
+ /**
7
+ * How far a finger that opened the menu travels, from the first sample the
8
+ * menu sees, before it starts picking (UIMenu's scrub handoff).
9
+ */
10
+ export declare const MENU_PRESS_HANDOFF_PX: number;
15
11
  export type MenuPressPointerType = 'mouse' | 'touch' | 'pen';
16
- export type MenuPressGesture<T> = {
12
+ /** @internal The machine's own shape, with the finger's handoff; not public contract. */
13
+ export type MenuPressState<T> = {
17
14
  phase: 'idle';
18
15
  } | {
19
16
  phase: 'triggerPress';
@@ -23,6 +20,15 @@ export type MenuPressGesture<T> = {
23
20
  phase: 'open';
24
21
  pointerType: MenuPressPointerType;
25
22
  openedAt: number;
23
+ /**
24
+ * A finger's handoff: the first position the menu saw after it opened,
25
+ * which the scrub distance is counted from. Unset until that sample.
26
+ * @internal Not public contract.
27
+ */
28
+ handoffFrom?: {
29
+ x: number;
30
+ y: number;
31
+ };
26
32
  } | {
27
33
  phase: 'tracking';
28
34
  pointerType: MenuPressPointerType;
@@ -31,7 +37,8 @@ export type MenuPressGesture<T> = {
31
37
  /** The enabled row currently under the pointer, if any. */
32
38
  row: T | null;
33
39
  };
34
- export type MenuPressEvent<T> = {
40
+ /** @internal The machine's own shape, with the finger's handoff; not public contract. */
41
+ export type MenuPressInput<T> = {
35
42
  type: 'down';
36
43
  target: 'trigger' | 'menu';
37
44
  pointerType: MenuPressPointerType;
@@ -48,18 +55,33 @@ export type MenuPressEvent<T> = {
48
55
  row: T | null;
49
56
  isInMenu: boolean;
50
57
  time: number;
58
+ /**
59
+ * Viewport position, for a finger's handoff distance.
60
+ * @internal Not public contract.
61
+ */
62
+ x?: number;
63
+ /** @internal See `x`. */
64
+ y?: number;
51
65
  } | {
52
66
  type: 'up';
53
67
  row: T | null;
54
68
  isInMenu: boolean;
55
69
  isOnTrigger: boolean;
56
70
  time: number;
71
+ /**
72
+ * Viewport position, for a finger's handoff distance.
73
+ * @internal Not public contract.
74
+ */
75
+ x?: number;
76
+ /** @internal See `x`. */
77
+ y?: number;
57
78
  }
58
79
  /** The browser took the gesture: pointercancel, a second pointer, a scroll. */
59
80
  | {
60
81
  type: 'cancel';
61
82
  };
62
- export type MenuPressEffect<T> = {
83
+ /** @internal The machine's own shape, with the finger's handoff; not public contract. */
84
+ export type MenuPressOutcome<T> = {
63
85
  type: 'none';
64
86
  }
65
87
  /** A mouse pressed the trigger: open the menu now, under the held pointer. */
@@ -77,18 +99,19 @@ export type MenuPressEffect<T> = {
77
99
  /**
78
100
  * The gesture ended without a row acting. `stray` says whether the browser
79
101
  * will still report a `click` for this gesture that must not act; `dismiss`
80
- * says the menu should close (a mouse released outside it).
102
+ * says the menu should close: a mouse released outside it.
81
103
  */
82
104
  | {
83
105
  type: 'settle';
84
106
  stray: boolean;
85
107
  dismiss: boolean;
86
108
  };
87
- export interface MenuPressStep<T> {
88
- gesture: MenuPressGesture<T>;
89
- effect: MenuPressEffect<T>;
109
+ /** @internal The machine's own shape, with the finger's handoff; not public contract. */
110
+ export interface MenuPressTransition<T> {
111
+ gesture: MenuPressState<T>;
112
+ effect: MenuPressOutcome<T>;
90
113
  }
91
- export declare const IDLE_MENU_PRESS: MenuPressGesture<never>;
114
+ export declare const IDLE_MENU_PRESS: MenuPressState<never>;
92
115
  /**
93
116
  * Advance the gesture by one event. Pure: same inputs, same output.
94
117
  *
@@ -97,10 +120,15 @@ export declare const IDLE_MENU_PRESS: MenuPressGesture<never>;
97
120
  * - `idle`: no gesture is live.
98
121
  * - `triggerPress`: a finger rests on the trigger, and the menu is not open
99
122
  * yet. A mouse press on the trigger skips this state and opens at once.
100
- * - `open`: the menu opened under a held pointer, and the pointer has not
101
- * entered it yet.
123
+ * - `open`: the menu opened under a held pointer, and the pointer does not
124
+ * pick yet.
102
125
  * - `tracking`: the pointer is held, and the highlight follows it.
103
126
  *
127
+ * A finger or a pen that opened the menu picks only after it travels
128
+ * `MENU_PRESS_HANDOFF_PX` from the first position the menu sees. UIMenu
129
+ * hands off the same way. Until then nothing lights, and its lift acts on
130
+ * nothing. A host that reports no positions keeps the settle rule.
131
+ *
104
132
  * The settle rule: the release of the opening gesture acts only after the
105
133
  * pointer entered the menu or the press lasted `MENU_PRESS_SETTLE_MS`. Else a
106
134
  * menu that opens under the pointer would pick a row that nobody chose.
@@ -108,6 +136,90 @@ export declare const IDLE_MENU_PRESS: MenuPressGesture<never>;
108
136
  * Rows are opaque (`T`). The hook feeds in the enabled row under the
109
137
  * pointer, or `null` over a divider, a heading, a disabled row, or outside
110
138
  * the menu.
139
+ *
140
+ * @internal The machine's own shape, with the finger's handoff; not public
141
+ * contract.
142
+ */
143
+ export declare function menuPressTransition<T>(gesture: MenuPressState<T>, event: MenuPressInput<T>): MenuPressTransition<T>;
144
+ export type MenuPressGesture<T> = {
145
+ phase: 'idle';
146
+ } | {
147
+ phase: 'triggerPress';
148
+ pointerType: MenuPressPointerType;
149
+ startedAt: number;
150
+ } | {
151
+ phase: 'open';
152
+ pointerType: MenuPressPointerType;
153
+ openedAt: number;
154
+ } | {
155
+ phase: 'tracking';
156
+ pointerType: MenuPressPointerType;
157
+ /** Where the press began. */
158
+ origin: 'trigger' | 'menu';
159
+ /** The enabled row currently under the pointer, if any. */
160
+ row: T | null;
161
+ };
162
+ export type MenuPressEvent<T> = {
163
+ type: 'down';
164
+ target: 'trigger' | 'menu';
165
+ pointerType: MenuPressPointerType;
166
+ /** The enabled row under the press when it lands inside the menu. */
167
+ row: T | null;
168
+ time: number;
169
+ }
170
+ /** The menu opened while the trigger press is still held. */
171
+ | {
172
+ type: 'opened';
173
+ time: number;
174
+ } | {
175
+ type: 'move';
176
+ row: T | null;
177
+ isInMenu: boolean;
178
+ time: number;
179
+ } | {
180
+ type: 'up';
181
+ row: T | null;
182
+ isInMenu: boolean;
183
+ isOnTrigger: boolean;
184
+ time: number;
185
+ }
186
+ /** The browser took the gesture: pointercancel, a second pointer, a scroll. */
187
+ | {
188
+ type: 'cancel';
189
+ };
190
+ export type MenuPressEffect<T> = {
191
+ type: 'none';
192
+ }
193
+ /** A mouse pressed the trigger: open the menu now, under the held pointer. */
194
+ | {
195
+ type: 'open';
196
+ } | {
197
+ type: 'highlight';
198
+ row: T;
199
+ } | {
200
+ type: 'clear';
201
+ } | {
202
+ type: 'act';
203
+ row: T;
204
+ }
205
+ /**
206
+ * The gesture ends without a row acting. Its `stray` flag is true when the
207
+ * browser still sends a `click` for this gesture. That click must not act.
208
+ * Its `dismiss` flag is true when the menu must close (a mouse released
209
+ * outside it).
210
+ */
211
+ | {
212
+ type: 'settle';
213
+ stray: boolean;
214
+ dismiss: boolean;
215
+ };
216
+ export interface MenuPressStep<T> {
217
+ gesture: MenuPressGesture<T>;
218
+ effect: MenuPressEffect<T>;
219
+ }
220
+ /**
221
+ * The menu press machine, as released: one step from a gesture and an event
222
+ * to the next gesture and the effect to apply. Pure.
111
223
  */
112
224
  export declare function menuPressStep<T>(gesture: MenuPressGesture<T>, event: MenuPressEvent<T>): MenuPressStep<T>;
113
225
  //# sourceMappingURL=menuPressGesture.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"menuPressGesture.d.ts","sourceRoot":"","sources":["../../src/hooks/menuPressGesture.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;;GAWG;AAEH,uEAAuE;AACvE,eAAO,MAAM,oBAAoB,MAAM,CAAC;AAExC,MAAM,MAAM,oBAAoB,GAAG,OAAO,GAAG,OAAO,GAAG,KAAK,CAAC;AAE7D,MAAM,MAAM,gBAAgB,CAAC,CAAC,IAC1B;IAAC,KAAK,EAAE,MAAM,CAAA;CAAC,GACf;IACE,KAAK,EAAE,cAAc,CAAC;IACtB,WAAW,EAAE,oBAAoB,CAAC;IAClC,SAAS,EAAE,MAAM,CAAC;CACnB,GACD;IACE,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,oBAAoB,CAAC;IAClC,QAAQ,EAAE,MAAM,CAAC;CAClB,GACD;IACE,KAAK,EAAE,UAAU,CAAC;IAClB,WAAW,EAAE,oBAAoB,CAAC;IAClC,6BAA6B;IAC7B,MAAM,EAAE,SAAS,GAAG,MAAM,CAAC;IAC3B,2DAA2D;IAC3D,GAAG,EAAE,CAAC,GAAG,IAAI,CAAC;CACf,CAAC;AAEN,MAAM,MAAM,cAAc,CAAC,CAAC,IACxB;IACE,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,SAAS,GAAG,MAAM,CAAC;IAC3B,WAAW,EAAE,oBAAoB,CAAC;IAClC,qEAAqE;IACrE,GAAG,EAAE,CAAC,GAAG,IAAI,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;CACd;AACH,6DAA6D;GAC3D;IAAC,IAAI,EAAE,QAAQ,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAC,GAC9B;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,CAAC,GAAG,IAAI,CAAC;IAAC,QAAQ,EAAE,OAAO,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAC,GAC9D;IACE,IAAI,EAAE,IAAI,CAAC;IACX,GAAG,EAAE,CAAC,GAAG,IAAI,CAAC;IACd,QAAQ,EAAE,OAAO,CAAC;IAClB,WAAW,EAAE,OAAO,CAAC;IACrB,IAAI,EAAE,MAAM,CAAC;CACd;AACH,+EAA+E;GAC7E;IAAC,IAAI,EAAE,QAAQ,CAAA;CAAC,CAAC;AAErB,MAAM,MAAM,eAAe,CAAC,CAAC,IACzB;IAAC,IAAI,EAAE,MAAM,CAAA;CAAC;AAChB,8EAA8E;GAC5E;IAAC,IAAI,EAAE,MAAM,CAAA;CAAC,GACd;IAAC,IAAI,EAAE,WAAW,CAAC;IAAC,GAAG,EAAE,CAAC,CAAA;CAAC,GAC3B;IAAC,IAAI,EAAE,OAAO,CAAA;CAAC,GACf;IAAC,IAAI,EAAE,KAAK,CAAC;IAAC,GAAG,EAAE,CAAC,CAAA;CAAC;AACvB;;;;GAIG;GACD;IAAC,IAAI,EAAE,QAAQ,CAAC;IAAC,KAAK,EAAE,OAAO,CAAC;IAAC,OAAO,EAAE,OAAO,CAAA;CAAC,CAAC;AAEvD,MAAM,WAAW,aAAa,CAAC,CAAC;IAC9B,OAAO,EAAE,gBAAgB,CAAC,CAAC,CAAC,CAAC;IAC7B,MAAM,EAAE,eAAe,CAAC,CAAC,CAAC,CAAC;CAC5B;AAED,eAAO,MAAM,eAAe,EAAE,gBAAgB,CAAC,KAAK,CAAmB,CAAC;AA+BxE;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,aAAa,CAAC,CAAC,EAC7B,OAAO,EAAE,gBAAgB,CAAC,CAAC,CAAC,EAC5B,KAAK,EAAE,cAAc,CAAC,CAAC,CAAC,GACvB,aAAa,CAAC,CAAC,CAAC,CAWlB"}
1
+ {"version":3,"file":"menuPressGesture.d.ts","sourceRoot":"","sources":["../../src/hooks/menuPressGesture.ts"],"names":[],"mappings":"AAiBA;;;GAGG;AACH,eAAO,MAAM,oBAAoB,MAAM,CAAC;AAExC;;;GAGG;AACH,eAAO,MAAM,qBAAqB,EAAE,MAAoC,CAAC;AAEzE,MAAM,MAAM,oBAAoB,GAAG,OAAO,GAAG,OAAO,GAAG,KAAK,CAAC;AAE7D,yFAAyF;AACzF,MAAM,MAAM,cAAc,CAAC,CAAC,IACxB;IAAC,KAAK,EAAE,MAAM,CAAA;CAAC,GACf;IACE,KAAK,EAAE,cAAc,CAAC;IACtB,WAAW,EAAE,oBAAoB,CAAC;IAClC,SAAS,EAAE,MAAM,CAAC;CACnB,GACD;IACE,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,oBAAoB,CAAC;IAClC,QAAQ,EAAE,MAAM,CAAC;IACjB;;;;OAIG;IACH,WAAW,CAAC,EAAE;QAAC,CAAC,EAAE,MAAM,CAAC;QAAC,CAAC,EAAE,MAAM,CAAA;KAAC,CAAC;CACtC,GACD;IACE,KAAK,EAAE,UAAU,CAAC;IAClB,WAAW,EAAE,oBAAoB,CAAC;IAClC,6BAA6B;IAC7B,MAAM,EAAE,SAAS,GAAG,MAAM,CAAC;IAC3B,2DAA2D;IAC3D,GAAG,EAAE,CAAC,GAAG,IAAI,CAAC;CACf,CAAC;AAEN,yFAAyF;AACzF,MAAM,MAAM,cAAc,CAAC,CAAC,IACxB;IACE,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,SAAS,GAAG,MAAM,CAAC;IAC3B,WAAW,EAAE,oBAAoB,CAAC;IAClC,qEAAqE;IACrE,GAAG,EAAE,CAAC,GAAG,IAAI,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;CACd;AACH,6DAA6D;GAC3D;IAAC,IAAI,EAAE,QAAQ,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAC,GAC9B;IACE,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,CAAC,GAAG,IAAI,CAAC;IACd,QAAQ,EAAE,OAAO,CAAC;IAClB,IAAI,EAAE,MAAM,CAAC;IACb;;;OAGG;IACH,CAAC,CAAC,EAAE,MAAM,CAAC;IACX,yBAAyB;IACzB,CAAC,CAAC,EAAE,MAAM,CAAC;CACZ,GACD;IACE,IAAI,EAAE,IAAI,CAAC;IACX,GAAG,EAAE,CAAC,GAAG,IAAI,CAAC;IACd,QAAQ,EAAE,OAAO,CAAC;IAClB,WAAW,EAAE,OAAO,CAAC;IACrB,IAAI,EAAE,MAAM,CAAC;IACb;;;OAGG;IACH,CAAC,CAAC,EAAE,MAAM,CAAC;IACX,yBAAyB;IACzB,CAAC,CAAC,EAAE,MAAM,CAAC;CACZ;AACH,+EAA+E;GAC7E;IAAC,IAAI,EAAE,QAAQ,CAAA;CAAC,CAAC;AAErB,yFAAyF;AACzF,MAAM,MAAM,gBAAgB,CAAC,CAAC,IAC1B;IAAC,IAAI,EAAE,MAAM,CAAA;CAAC;AAChB,8EAA8E;GAC5E;IAAC,IAAI,EAAE,MAAM,CAAA;CAAC,GACd;IAAC,IAAI,EAAE,WAAW,CAAC;IAAC,GAAG,EAAE,CAAC,CAAA;CAAC,GAC3B;IAAC,IAAI,EAAE,OAAO,CAAA;CAAC,GACf;IAAC,IAAI,EAAE,KAAK,CAAC;IAAC,GAAG,EAAE,CAAC,CAAA;CAAC;AACvB;;;;GAIG;GACD;IAAC,IAAI,EAAE,QAAQ,CAAC;IAAC,KAAK,EAAE,OAAO,CAAC;IAAC,OAAO,EAAE,OAAO,CAAA;CAAC,CAAC;AAEvD,yFAAyF;AACzF,MAAM,WAAW,mBAAmB,CAAC,CAAC;IACpC,OAAO,EAAE,cAAc,CAAC,CAAC,CAAC,CAAC;IAC3B,MAAM,EAAE,gBAAgB,CAAC,CAAC,CAAC,CAAC;CAC7B;AAED,eAAO,MAAM,eAAe,EAAE,cAAc,CAAC,KAAK,CAAmB,CAAC;AAuDtE;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,wBAAgB,mBAAmB,CAAC,CAAC,EACnC,OAAO,EAAE,cAAc,CAAC,CAAC,CAAC,EAC1B,KAAK,EAAE,cAAc,CAAC,CAAC,CAAC,GACvB,mBAAmB,CAAC,CAAC,CAAC,CAWxB;AAyKD,MAAM,MAAM,gBAAgB,CAAC,CAAC,IAC1B;IAAC,KAAK,EAAE,MAAM,CAAA;CAAC,GACf;IACE,KAAK,EAAE,cAAc,CAAC;IACtB,WAAW,EAAE,oBAAoB,CAAC;IAClC,SAAS,EAAE,MAAM,CAAC;CACnB,GACD;IACE,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,oBAAoB,CAAC;IAClC,QAAQ,EAAE,MAAM,CAAC;CAClB,GACD;IACE,KAAK,EAAE,UAAU,CAAC;IAClB,WAAW,EAAE,oBAAoB,CAAC;IAClC,6BAA6B;IAC7B,MAAM,EAAE,SAAS,GAAG,MAAM,CAAC;IAC3B,2DAA2D;IAC3D,GAAG,EAAE,CAAC,GAAG,IAAI,CAAC;CACf,CAAC;AAEN,MAAM,MAAM,cAAc,CAAC,CAAC,IACxB;IACE,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,SAAS,GAAG,MAAM,CAAC;IAC3B,WAAW,EAAE,oBAAoB,CAAC;IAClC,qEAAqE;IACrE,GAAG,EAAE,CAAC,GAAG,IAAI,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;CACd;AACH,6DAA6D;GAC3D;IAAC,IAAI,EAAE,QAAQ,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAC,GAC9B;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,CAAC,GAAG,IAAI,CAAC;IAAC,QAAQ,EAAE,OAAO,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAC,GAC9D;IACE,IAAI,EAAE,IAAI,CAAC;IACX,GAAG,EAAE,CAAC,GAAG,IAAI,CAAC;IACd,QAAQ,EAAE,OAAO,CAAC;IAClB,WAAW,EAAE,OAAO,CAAC;IACrB,IAAI,EAAE,MAAM,CAAC;CACd;AACH,+EAA+E;GAC7E;IAAC,IAAI,EAAE,QAAQ,CAAA;CAAC,CAAC;AAErB,MAAM,MAAM,eAAe,CAAC,CAAC,IACzB;IAAC,IAAI,EAAE,MAAM,CAAA;CAAC;AAChB,8EAA8E;GAC5E;IAAC,IAAI,EAAE,MAAM,CAAA;CAAC,GACd;IAAC,IAAI,EAAE,WAAW,CAAC;IAAC,GAAG,EAAE,CAAC,CAAA;CAAC,GAC3B;IAAC,IAAI,EAAE,OAAO,CAAA;CAAC,GACf;IAAC,IAAI,EAAE,KAAK,CAAC;IAAC,GAAG,EAAE,CAAC,CAAA;CAAC;AACvB;;;;;GAKG;GACD;IAAC,IAAI,EAAE,QAAQ,CAAC;IAAC,KAAK,EAAE,OAAO,CAAC;IAAC,OAAO,EAAE,OAAO,CAAA;CAAC,CAAC;AAEvD,MAAM,WAAW,aAAa,CAAC,CAAC;IAC9B,OAAO,EAAE,gBAAgB,CAAC,CAAC,CAAC,CAAC;IAC7B,MAAM,EAAE,eAAe,CAAC,CAAC,CAAC,CAAC;CAC5B;AAED;;;GAGG;AACH,wBAAgB,aAAa,CAAC,CAAC,EAC7B,OAAO,EAAE,gBAAgB,CAAC,CAAC,CAAC,EAC5B,KAAK,EAAE,cAAc,CAAC,CAAC,CAAC,GACvB,aAAa,CAAC,CAAC,CAAC,CAgBlB"}
@@ -4,7 +4,7 @@
4
4
  * @file menuPressGesture.ts
5
5
  * @input A menu press gesture and one pointer event, both as plain data
6
6
  * @output The pure `menuPressStep` state machine, its state, event and effect
7
- * types, and the settle constant
7
+ * types, the settle constant, and the finger's handoff distance
8
8
  * @position Pure module under `useMenuPress`. It has no DOM and no React, so
9
9
  * a unit test can check each transition without a browser.
10
10
  *
@@ -13,8 +13,28 @@
13
13
  * - /packages/core/src/hooks/useMenuPress.ts
14
14
  */
15
15
 
16
- /** How long the opening press must last before its release may act. */
16
+ import { MENU_PRESS_HANDOFF_PX as UIKIT_MENU_PRESS_HANDOFF_PX } from "./menuPressValues.js";
17
+
18
+ /**
19
+ * How long the opening press must last before its release may act, unless a
20
+ * finger's handoff applies.
21
+ */
17
22
  export const MENU_PRESS_SETTLE_MS = 300;
23
+
24
+ /**
25
+ * How far a finger that opened the menu travels, from the first sample the
26
+ * menu sees, before it starts picking (UIMenu's scrub handoff).
27
+ */
28
+ export const MENU_PRESS_HANDOFF_PX = UIKIT_MENU_PRESS_HANDOFF_PX;
29
+
30
+ /** @internal The machine's own shape, with the finger's handoff; not public contract. */
31
+
32
+ /** @internal The machine's own shape, with the finger's handoff; not public contract. */
33
+
34
+ /** @internal The machine's own shape, with the finger's handoff; not public contract. */
35
+
36
+ /** @internal The machine's own shape, with the finger's handoff; not public contract. */
37
+
18
38
  export const IDLE_MENU_PRESS = {
19
39
  phase: 'idle'
20
40
  };
@@ -38,6 +58,23 @@ function highlightEffect(row) {
38
58
  };
39
59
  }
40
60
 
61
+ /** A finger or a pen: UIKit's touch rules apply. */
62
+ function isFinger(pointerType) {
63
+ return pointerType !== 'mouse';
64
+ }
65
+ function hasPosition(event) {
66
+ return event.x != null && event.y != null;
67
+ }
68
+
69
+ /**
70
+ * Whether a finger has travelled the handoff distance from `from`. The
71
+ * distance is a straight line, as UIMenu measures it: a diagonal 7 pt each
72
+ * way does not hand off, 9 pt each way does.
73
+ */
74
+ function hasPassedHandoff(from, to) {
75
+ return Math.hypot(to.x - from.x, to.y - from.y) >= MENU_PRESS_HANDOFF_PX;
76
+ }
77
+
41
78
  /**
42
79
  * Resolve a release while the highlight is tracking the pointer: over an
43
80
  * enabled row it acts, over the menu's chrome it acts on nothing, outside the
@@ -73,10 +110,15 @@ function release(pointerType, event) {
73
110
  * - `idle`: no gesture is live.
74
111
  * - `triggerPress`: a finger rests on the trigger, and the menu is not open
75
112
  * yet. A mouse press on the trigger skips this state and opens at once.
76
- * - `open`: the menu opened under a held pointer, and the pointer has not
77
- * entered it yet.
113
+ * - `open`: the menu opened under a held pointer, and the pointer does not
114
+ * pick yet.
78
115
  * - `tracking`: the pointer is held, and the highlight follows it.
79
116
  *
117
+ * A finger or a pen that opened the menu picks only after it travels
118
+ * `MENU_PRESS_HANDOFF_PX` from the first position the menu sees. UIMenu
119
+ * hands off the same way. Until then nothing lights, and its lift acts on
120
+ * nothing. A host that reports no positions keeps the settle rule.
121
+ *
80
122
  * The settle rule: the release of the opening gesture acts only after the
81
123
  * pointer entered the menu or the press lasted `MENU_PRESS_SETTLE_MS`. Else a
82
124
  * menu that opens under the pointer would pick a row that nobody chose.
@@ -84,8 +126,11 @@ function release(pointerType, event) {
84
126
  * Rows are opaque (`T`). The hook feeds in the enabled row under the
85
127
  * pointer, or `null` over a divider, a heading, a disabled row, or outside
86
128
  * the menu.
129
+ *
130
+ * @internal The machine's own shape, with the finger's handoff; not public
131
+ * contract.
87
132
  */
88
- export function menuPressStep(gesture, event) {
133
+ export function menuPressTransition(gesture, event) {
89
134
  switch (gesture.phase) {
90
135
  case 'idle':
91
136
  return stepIdle(gesture, event);
@@ -176,23 +221,67 @@ function stepTriggerPress(gesture, event) {
176
221
  function stepOpen(gesture, event) {
177
222
  switch (event.type) {
178
223
  case 'move':
179
- if (!event.isInMenu) {
224
+ {
225
+ if (isFinger(gesture.pointerType) && hasPosition(event)) {
226
+ // UIMenu counts from the first sample after the open, not from the
227
+ // open point.
228
+ const from = gesture.handoffFrom;
229
+ if (from == null) {
230
+ return {
231
+ gesture: {
232
+ ...gesture,
233
+ handoffFrom: {
234
+ x: event.x,
235
+ y: event.y
236
+ }
237
+ },
238
+ effect: NONE
239
+ };
240
+ }
241
+ if (!hasPassedHandoff(from, event)) {
242
+ return {
243
+ gesture,
244
+ effect: NONE
245
+ };
246
+ }
247
+ return {
248
+ gesture: {
249
+ phase: 'tracking',
250
+ pointerType: gesture.pointerType,
251
+ origin: 'trigger',
252
+ row: event.row
253
+ },
254
+ effect: highlightEffect(event.row)
255
+ };
256
+ }
257
+ if (!event.isInMenu) {
258
+ return {
259
+ gesture,
260
+ effect: NONE
261
+ };
262
+ }
180
263
  return {
181
- gesture,
182
- effect: NONE
264
+ gesture: {
265
+ phase: 'tracking',
266
+ pointerType: gesture.pointerType,
267
+ origin: 'trigger',
268
+ row: event.row
269
+ },
270
+ effect: highlightEffect(event.row)
183
271
  };
184
272
  }
185
- return {
186
- gesture: {
187
- phase: 'tracking',
188
- pointerType: gesture.pointerType,
189
- origin: 'trigger',
190
- row: event.row
191
- },
192
- effect: highlightEffect(event.row)
193
- };
194
273
  case 'up':
195
274
  {
275
+ if (isFinger(gesture.pointerType) && hasPosition(event)) {
276
+ // The finger never travelled the handoff distance, so the row under it
277
+ // appeared under a press nobody moved. Nothing acts, the menu stays,
278
+ // and the trigger's click for this press is spent.
279
+ return idle({
280
+ type: 'settle',
281
+ stray: true,
282
+ dismiss: false
283
+ });
284
+ }
196
285
  const hasSettled = event.time - gesture.openedAt >= MENU_PRESS_SETTLE_MS;
197
286
  if (!hasSettled) {
198
287
  // The pointer never entered the menu and the press was short: the
@@ -208,7 +297,7 @@ function stepOpen(gesture, event) {
208
297
  }
209
298
  case 'cancel':
210
299
  // As above: the gesture ends, so its document listeners come off. The
211
- // menu stays open — a cancelled pointer did not ask to close it.
300
+ // menu stays open: a cancelled pointer did not ask to close it.
212
301
  return idle({
213
302
  type: 'settle',
214
303
  stray: false,
@@ -225,21 +314,19 @@ function stepOpen(gesture, event) {
225
314
  function stepTracking(gesture, event) {
226
315
  switch (event.type) {
227
316
  case 'move':
228
- {
229
- if (event.row === gesture.row) {
230
- return {
231
- gesture,
232
- effect: NONE
233
- };
234
- }
317
+ if (event.row === gesture.row) {
235
318
  return {
236
- gesture: {
237
- ...gesture,
238
- row: event.row
239
- },
240
- effect: highlightEffect(event.row)
319
+ gesture,
320
+ effect: NONE
241
321
  };
242
322
  }
323
+ return {
324
+ gesture: {
325
+ ...gesture,
326
+ row: event.row
327
+ },
328
+ effect: highlightEffect(event.row)
329
+ };
243
330
  case 'up':
244
331
  return release(gesture.pointerType, event);
245
332
  case 'cancel':
@@ -257,4 +344,42 @@ function stepTracking(gesture, event) {
257
344
  effect: NONE
258
345
  };
259
346
  }
347
+ }
348
+
349
+ // ---------------------------------------------------------------------------
350
+ // The released public shape (`@astryxdesign/core/hooks`). The handoff
351
+ // positions and `handoffFrom` stay internal: a caller of
352
+ // `menuPressStep` keeps the settle rule, as released.
353
+ // ---------------------------------------------------------------------------
354
+
355
+ /**
356
+ * The menu press machine, as released: one step from a gesture and an event
357
+ * to the next gesture and the effect to apply. Pure.
358
+ */
359
+ export function menuPressStep(gesture, event) {
360
+ // The released machine keeps the settle rule. Positions start the handoff,
361
+ // so a caller's event reaches the transition without them.
362
+ const {
363
+ x: _x,
364
+ y: _y,
365
+ ...released
366
+ } = event;
367
+ const {
368
+ gesture: next,
369
+ effect
370
+ } = menuPressTransition(gesture, released);
371
+ return {
372
+ gesture: publicGesture(next),
373
+ effect
374
+ };
375
+ }
376
+ function publicGesture(gesture) {
377
+ if (gesture.phase !== 'open') {
378
+ return gesture;
379
+ }
380
+ return {
381
+ phase: 'open',
382
+ pointerType: gesture.pointerType,
383
+ openedAt: gesture.openedAt
384
+ };
260
385
  }
@@ -0,0 +1,16 @@
1
+ /**
2
+ * @file menuPressValues.ts
3
+ * @input None
4
+ * @output The UIKit value the menu press model reads
5
+ * @position A copy of one UIKit table entry, motion/uikit gestures.ts
6
+ * `UIKIT_MENU_PRESS.handoff`. A menu then bundles this number, not the
7
+ * table with its measurement records. The table stays the source and
8
+ * documents the measurement. menuPressValues.test.ts fails when the copy
9
+ * drifts.
10
+ *
11
+ * SYNC: When modified, update:
12
+ * - /packages/core/src/motion/uikit/gestures.ts
13
+ */
14
+ /** How far the opening finger travels after the menu opens before it picks. */
15
+ export declare const MENU_PRESS_HANDOFF_PX = 10;
16
+ //# sourceMappingURL=menuPressValues.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"menuPressValues.d.ts","sourceRoot":"","sources":["../../src/hooks/menuPressValues.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;;;GAYG;AAEH,+EAA+E;AAC/E,eAAO,MAAM,qBAAqB,KAAK,CAAC"}
@@ -0,0 +1,18 @@
1
+ // Copyright (c) Meta Platforms, Inc. and affiliates.
2
+
3
+ /**
4
+ * @file menuPressValues.ts
5
+ * @input None
6
+ * @output The UIKit value the menu press model reads
7
+ * @position A copy of one UIKit table entry, motion/uikit gestures.ts
8
+ * `UIKIT_MENU_PRESS.handoff`. A menu then bundles this number, not the
9
+ * table with its measurement records. The table stays the source and
10
+ * documents the measurement. menuPressValues.test.ts fails when the copy
11
+ * drifts.
12
+ *
13
+ * SYNC: When modified, update:
14
+ * - /packages/core/src/motion/uikit/gestures.ts
15
+ */
16
+
17
+ /** How far the opening finger travels after the menu opens before it picks. */
18
+ export const MENU_PRESS_HANDOFF_PX = 10;
@@ -1,16 +1,18 @@
1
1
  /**
2
2
  * @file useClickableContainer.ts
3
3
  * @input Container ref, interactive element ref, click/href handlers
4
- * @output onClick and onMouseUp handlers for the container; INTERACTIVE_SELECTORS list;
4
+ * @output onClick, onMouseUp and onPointerDown handlers for the container;
5
+ * INTERACTIVE_SELECTORS list;
5
6
  * hasInteractiveAncestor and the shared innermostInteractive walk
6
7
  * @position Core hook for clickable containers with nested interactive
7
8
  * elements. A click on a nested button or link does not run the card's
8
- * action. Each navigation passes the rule in utils/safeUrl.ts first.
9
+ * action, and a finger press there shows no press on the card. Each navigation
10
+ * passes the rule in utils/safeUrl.ts first.
9
11
  *
10
12
  * SYNC: When modified, update:
11
13
  * - /packages/core/src/hooks/index.ts (export)
12
14
  */
13
- import { type RefObject, type MouseEvent } from 'react';
15
+ import { type RefObject, type MouseEvent, type PointerEvent } from 'react';
14
16
  /**
15
17
  * The attribute this hook sets on the container it makes clickable. A click
16
18
  * inside a nested marked container belongs to that container (see
@@ -57,6 +59,14 @@ export declare function innermostInteractive(el: Element, rootEl: Element | null
57
59
  * belongs to that surface, not the container around its trigger.
58
60
  */
59
61
  export declare function hasInteractiveAncestor(el: Element, rootEl: Element): boolean;
62
+ /**
63
+ * The touch half of a container's press rule: a finger press that starts on a nested interactive element
64
+ * other than the container's own action does not activate the container, so
65
+ * it ends the press controller's paint on `container`. A mouse or pen press,
66
+ * and a press on the container's surface or on `ownAction`, are left alone.
67
+ * Not part of the package's public API.
68
+ */
69
+ export declare function cancelNestedTouchPress(event: PointerEvent<HTMLElement>, container: HTMLElement | null, ownAction: Element | null): void;
60
70
  /**
61
71
  * Check if there's a text selection inside the node (don't navigate on text select)
62
72
  *
@@ -87,6 +97,14 @@ export interface UseClickableContainerOptions {
87
97
  export interface ClickableContainerResult {
88
98
  onClick: (event: MouseEvent<HTMLElement>) => void;
89
99
  onMouseUp: (event: MouseEvent<HTMLElement>) => void;
100
+ /**
101
+ * Spread on the container with `onClick`. A press that starts on a nested
102
+ * interactive element does not activate the container. On a container that
103
+ * paints its press with `usePressFeedback`, this drops that touch press.
104
+ * A mouse `:active` press paint is unchanged. A container without it keeps
105
+ * its activation rule and shows its pressed state for every press.
106
+ */
107
+ onPointerDown: (event: PointerEvent<HTMLElement>) => void;
90
108
  }
91
109
  /**
92
110
  * Hook that makes a container element clickable while preserving
@@ -103,12 +121,16 @@ export interface ClickableContainerResult {
103
121
  * @example
104
122
  * ```
105
123
  * const containerRef = useRef<HTMLDivElement>(null);
106
- * const { onClick, onMouseUp } = useClickableContainer({
124
+ * const { onClick, onMouseUp, onPointerDown } = useClickableContainer({
107
125
  * containerRef,
108
126
  * onClick: () => console.log('card clicked'),
109
127
  * });
110
128
  * return (
111
- * <div ref={containerRef} onClick={onClick} onMouseUp={onMouseUp}>
129
+ * <div
130
+ * ref={containerRef}
131
+ * onClick={onClick}
132
+ * onMouseUp={onMouseUp}
133
+ * onPointerDown={onPointerDown}>
112
134
  * <p>Click anywhere on this card</p>
113
135
  * <button onClick={() => alert('button')}>Nested button</button>
114
136
  * </div>
@@ -1 +1 @@
1
- {"version":3,"file":"useClickableContainer.d.ts","sourceRoot":"","sources":["../../src/hooks/useClickableContainer.ts"],"names":[],"mappings":"AAIA;;;;;;;;;;;GAWG;AAEH,OAAO,EAAyB,KAAK,SAAS,EAAE,KAAK,UAAU,EAAC,MAAM,OAAO,CAAC;AAI9E;;;;GAIG;AACH,eAAO,MAAM,6BAA6B,6BAA6B,CAAC;AAExE;;;;;;;;;;GAUG;AACH,eAAO,MAAM,qBAAqB,QAmBvB,CAAC;AAIZ;;;GAGG;AACH,wBAAgB,2BAA2B,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAKrE;AAED;;;;;;GAMG;AACH,wBAAgB,oBAAoB,CAClC,EAAE,EAAE,OAAO,EACX,MAAM,EAAE,OAAO,GAAG,IAAI,EACtB,aAAa,GAAE,CAAC,OAAO,EAAE,OAAO,KAAK,OAAqC,GACzE,OAAO,GAAG,IAAI,CAShB;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,sBAAsB,CAAC,EAAE,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,GAAG,OAAO,CAE5E;AASD;;;;;;;GAOG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,OAAO,GAAG,OAAO,CASvD;AAED,MAAM,WAAW,4BAA4B;IAC3C,yCAAyC;IACzC,YAAY,EAAE,SAAS,CAAC,WAAW,GAAG,IAAI,CAAC,CAAC;IAC5C,mEAAmE;IACnE,cAAc,CAAC,EAAE,SAAS,CAAC,WAAW,GAAG,IAAI,CAAC,CAAC;IAC/C,oBAAoB;IACpB,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,UAAU,CAAC,WAAW,CAAC,KAAK,IAAI,CAAC;IACnD;;;;OAIG;IACH,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,kBAAkB;IAClB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,wCAAwC;IACxC,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAED,MAAM,WAAW,wBAAwB;IACvC,OAAO,EAAE,CAAC,KAAK,EAAE,UAAU,CAAC,WAAW,CAAC,KAAK,IAAI,CAAC;IAClD,SAAS,EAAE,CAAC,KAAK,EAAE,UAAU,CAAC,WAAW,CAAC,KAAK,IAAI,CAAC;CACrD;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,wBAAgB,qBAAqB,CAAC,EACpC,YAAY,EACZ,cAAc,EACd,OAAO,EAAE,WAAW,EACpB,IAAI,EACJ,MAAM,EACN,QAAgB,GACjB,EAAE,4BAA4B,GAAG,wBAAwB,CA+GzD"}
1
+ {"version":3,"file":"useClickableContainer.d.ts","sourceRoot":"","sources":["../../src/hooks/useClickableContainer.ts"],"names":[],"mappings":"AAIA;;;;;;;;;;;;;GAaG;AAEH,OAAO,EAGL,KAAK,SAAS,EACd,KAAK,UAAU,EACf,KAAK,YAAY,EAClB,MAAM,OAAO,CAAC;AAKf;;;;GAIG;AACH,eAAO,MAAM,6BAA6B,6BAA6B,CAAC;AAExE;;;;;;;;;;GAUG;AACH,eAAO,MAAM,qBAAqB,QAmBvB,CAAC;AAIZ;;;GAGG;AACH,wBAAgB,2BAA2B,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAKrE;AAED;;;;;;GAMG;AACH,wBAAgB,oBAAoB,CAClC,EAAE,EAAE,OAAO,EACX,MAAM,EAAE,OAAO,GAAG,IAAI,EACtB,aAAa,GAAE,CAAC,OAAO,EAAE,OAAO,KAAK,OAAqC,GACzE,OAAO,GAAG,IAAI,CAShB;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,sBAAsB,CAAC,EAAE,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,GAAG,OAAO,CAE5E;AASD;;;;;;GAMG;AACH,wBAAgB,sBAAsB,CACpC,KAAK,EAAE,YAAY,CAAC,WAAW,CAAC,EAChC,SAAS,EAAE,WAAW,GAAG,IAAI,EAC7B,SAAS,EAAE,OAAO,GAAG,IAAI,GACxB,IAAI,CAeN;AAED;;;;;;;GAOG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,OAAO,GAAG,OAAO,CASvD;AAED,MAAM,WAAW,4BAA4B;IAC3C,yCAAyC;IACzC,YAAY,EAAE,SAAS,CAAC,WAAW,GAAG,IAAI,CAAC,CAAC;IAC5C,mEAAmE;IACnE,cAAc,CAAC,EAAE,SAAS,CAAC,WAAW,GAAG,IAAI,CAAC,CAAC;IAC/C,oBAAoB;IACpB,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,UAAU,CAAC,WAAW,CAAC,KAAK,IAAI,CAAC;IACnD;;;;OAIG;IACH,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,kBAAkB;IAClB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,wCAAwC;IACxC,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAED,MAAM,WAAW,wBAAwB;IACvC,OAAO,EAAE,CAAC,KAAK,EAAE,UAAU,CAAC,WAAW,CAAC,KAAK,IAAI,CAAC;IAClD,SAAS,EAAE,CAAC,KAAK,EAAE,UAAU,CAAC,WAAW,CAAC,KAAK,IAAI,CAAC;IACpD;;;;;;OAMG;IACH,aAAa,EAAE,CAAC,KAAK,EAAE,YAAY,CAAC,WAAW,CAAC,KAAK,IAAI,CAAC;CAC3D;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AACH,wBAAgB,qBAAqB,CAAC,EACpC,YAAY,EACZ,cAAc,EACd,OAAO,EAAE,WAAW,EACpB,IAAI,EACJ,MAAM,EACN,QAAgB,GACjB,EAAE,4BAA4B,GAAG,wBAAwB,CAgIzD"}