@astryxdesign/core 0.7.7-canary.fc68123 → 0.7.7

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 (240) hide show
  1. package/CHANGELOG.md +104 -0
  2. package/dist/AlertDialog/AlertDialog.d.ts +1 -4
  3. package/dist/AlertDialog/AlertDialog.d.ts.map +1 -1
  4. package/dist/AlertDialog/AlertDialog.js +6 -36
  5. package/dist/BottomSheet/BottomSheetPanel.d.ts.map +1 -1
  6. package/dist/BottomSheet/BottomSheetPanel.js +4 -23
  7. package/dist/BottomSheet/useSheetGestures.d.ts.map +1 -1
  8. package/dist/BottomSheet/useSheetGestures.js +1 -3
  9. package/dist/Button/Button.d.ts.map +1 -1
  10. package/dist/Button/Button.js +1 -17
  11. package/dist/CheckboxInput/CheckboxInput.d.ts.map +1 -1
  12. package/dist/CheckboxInput/CheckboxInput.js +2 -13
  13. package/dist/ComplexSelector/ComplexSelector.d.ts +1 -4
  14. package/dist/ComplexSelector/ComplexSelector.d.ts.map +1 -1
  15. package/dist/ComplexSelector/ComplexSelector.js +4 -14
  16. package/dist/ContextMenu/ContextMenu.js +2 -2
  17. package/dist/Dialog/Dialog.d.ts.map +1 -1
  18. package/dist/Dialog/Dialog.js +31 -7
  19. package/dist/Field/Field.js +2 -2
  20. package/dist/HoverCard/HoverCard.d.ts +3 -4
  21. package/dist/HoverCard/HoverCard.d.ts.map +1 -1
  22. package/dist/HoverCard/HoverCard.js +2 -27
  23. package/dist/HoverCard/useHoverCard.d.ts +4 -5
  24. package/dist/HoverCard/useHoverCard.d.ts.map +1 -1
  25. package/dist/HoverCard/useHoverCard.js +31 -17
  26. package/dist/Icon/Icon.d.ts +1 -5
  27. package/dist/Icon/Icon.d.ts.map +1 -1
  28. package/dist/Icon/Icon.js +2 -5
  29. package/dist/Layer/usePressPin.d.ts +5 -17
  30. package/dist/Layer/usePressPin.d.ts.map +1 -1
  31. package/dist/Layer/usePressPin.js +12 -62
  32. package/dist/Lightbox/Lightbox.d.ts.map +1 -1
  33. package/dist/Lightbox/Lightbox.js +0 -18
  34. package/dist/PowerSearch/PowerSearch.d.ts +3 -36
  35. package/dist/PowerSearch/PowerSearch.d.ts.map +1 -1
  36. package/dist/PowerSearch/PowerSearch.js +127 -433
  37. package/dist/PowerSearch/PowerSearchEditPopover.d.ts +1 -32
  38. package/dist/PowerSearch/PowerSearchEditPopover.d.ts.map +1 -1
  39. package/dist/PowerSearch/PowerSearchEditPopover.js +6 -17
  40. package/dist/PowerSearch/PowerSearchValueEditor.d.ts +3 -38
  41. package/dist/PowerSearch/PowerSearchValueEditor.d.ts.map +1 -1
  42. package/dist/PowerSearch/PowerSearchValueEditor.js +61 -170
  43. package/dist/PowerSearch/formatFilterValue.d.ts +0 -7
  44. package/dist/PowerSearch/formatFilterValue.d.ts.map +1 -1
  45. package/dist/PowerSearch/formatFilterValue.js +1 -11
  46. package/dist/RadioList/RadioList.d.ts.map +1 -1
  47. package/dist/RadioList/RadioList.js +2 -3
  48. package/dist/RadioList/RadioListItem.d.ts +1 -1
  49. package/dist/RadioList/RadioListItem.d.ts.map +1 -1
  50. package/dist/RadioList/RadioListItem.js +3 -5
  51. package/dist/Resizable/ResizeHandle.d.ts +1 -2
  52. package/dist/Resizable/ResizeHandle.d.ts.map +1 -1
  53. package/dist/Resizable/ResizeHandle.js +77 -99
  54. package/dist/SegmentedControl/useSegmentedSelectionMotion.d.ts.map +1 -1
  55. package/dist/SegmentedControl/useSegmentedSelectionMotion.js +3 -3
  56. package/dist/Slider/sliderTouchController.js +2 -2
  57. package/dist/Spinner/Spinner.d.ts +1 -1
  58. package/dist/Spinner/Spinner.d.ts.map +1 -1
  59. package/dist/Spinner/Spinner.js +58 -60
  60. package/dist/Switch/useSwitchTouch.js +4 -4
  61. package/dist/Table/BaseTable.d.ts.map +1 -1
  62. package/dist/Table/BaseTable.js +8 -29
  63. package/dist/TextInput/TextInput.d.ts +2 -2
  64. package/dist/TextInput/TextInput.d.ts.map +1 -1
  65. package/dist/TextInput/TextInput.js +7 -10
  66. package/dist/Toast/Toast.d.ts +1 -11
  67. package/dist/Toast/Toast.d.ts.map +1 -1
  68. package/dist/Toast/Toast.js +15 -25
  69. package/dist/Toast/ToastViewport.d.ts.map +1 -1
  70. package/dist/Toast/ToastViewport.js +34 -94
  71. package/dist/Toast/types.d.ts +3 -9
  72. package/dist/Toast/types.d.ts.map +1 -1
  73. package/dist/Tooltip/useTooltip.d.ts +1 -19
  74. package/dist/Tooltip/useTooltip.d.ts.map +1 -1
  75. package/dist/Tooltip/useTooltip.js +53 -34
  76. package/dist/Typeahead/TypeaheadItem.d.ts +1 -2
  77. package/dist/Typeahead/TypeaheadItem.d.ts.map +1 -1
  78. package/dist/astryx.css +6 -35
  79. package/dist/gestures/PressTracker.d.ts.map +1 -1
  80. package/dist/gestures/PressTracker.js +3 -4
  81. package/dist/hooks/actionGroupTracker.d.ts +1 -4
  82. package/dist/hooks/actionGroupTracker.d.ts.map +1 -1
  83. package/dist/hooks/actionGroupTracker.js +3 -13
  84. package/dist/hooks/index.d.ts +0 -1
  85. package/dist/hooks/index.d.ts.map +1 -1
  86. package/dist/hooks/index.js +0 -1
  87. package/dist/hooks/useAttachment.d.ts +1 -1
  88. package/dist/hooks/useAttachment.js +1 -1
  89. package/dist/hooks/useInputStatusIcon.d.ts +1 -1
  90. package/dist/hooks/useInputStatusIcon.d.ts.map +1 -1
  91. package/dist/hooks/useInputStatusIcon.js +2 -2
  92. package/dist/hooks/useLongPress.d.ts +2 -6
  93. package/dist/hooks/useLongPress.d.ts.map +1 -1
  94. package/dist/hooks/useLongPress.js +15 -95
  95. package/dist/i18n/generated-english/PowerSearch/PowerSearchValueEditor.generated.d.ts.map +1 -1
  96. package/dist/i18n/generated-english/PowerSearch/PowerSearchValueEditor.generated.js +0 -6
  97. package/dist/i18n/generated-locales/en.generated.d.ts.map +1 -1
  98. package/dist/i18n/generated-locales/en.generated.js +0 -30
  99. package/dist/i18n/generated-locales/pseudo.generated.d.ts.map +1 -1
  100. package/dist/i18n/generated-locales/pseudo.generated.js +0 -30
  101. package/dist/index.d.ts +0 -1
  102. package/dist/index.d.ts.map +1 -1
  103. package/dist/index.js +0 -4
  104. package/dist/motion/animatedLayout.d.ts.map +1 -1
  105. package/dist/motion/animatedLayout.js +6 -5
  106. package/dist/motion/animator.d.ts +14 -14
  107. package/dist/motion/animator.d.ts.map +1 -1
  108. package/dist/motion/animator.js +18 -41
  109. package/dist/utils/dateParser.d.ts.map +1 -1
  110. package/dist/utils/dateParser.js +0 -12
  111. package/dist/utils/focusReturn.d.ts +0 -15
  112. package/dist/utils/focusReturn.d.ts.map +1 -1
  113. package/dist/utils/focusReturn.js +0 -28
  114. package/dist/utils/interactionOverlay.stylex.d.ts +2 -3
  115. package/dist/utils/interactionOverlay.stylex.d.ts.map +1 -1
  116. package/dist/utils/interactionOverlay.stylex.js +2 -3
  117. package/dist/utils/pressFeedback.d.ts.map +1 -1
  118. package/dist/utils/pressFeedback.js +6 -19
  119. package/locales/en.json +0 -120
  120. package/locales/pseudo.json +0 -90
  121. package/package.json +5 -10
  122. package/src/AlertDialog/AlertDialog.doc.mjs +2 -2
  123. package/src/AlertDialog/AlertDialog.tsx +5 -37
  124. package/src/BottomSheet/BottomSheetPanel.tsx +3 -37
  125. package/src/BottomSheet/useSheetGestures.ts +1 -3
  126. package/src/Button/Button.tsx +4 -26
  127. package/src/CheckboxInput/CheckboxInput.doc.mjs +0 -18
  128. package/src/CheckboxInput/CheckboxInput.tsx +9 -36
  129. package/src/ComplexSelector/ComplexSelector.tsx +5 -20
  130. package/src/ContextMenu/ContextMenu.tsx +2 -2
  131. package/src/Dialog/Dialog.tsx +31 -10
  132. package/src/Field/Field.tsx +2 -2
  133. package/src/HoverCard/HoverCard.doc.mjs +2 -4
  134. package/src/HoverCard/HoverCard.tsx +4 -35
  135. package/src/HoverCard/useHoverCard.doc.mjs +36 -178
  136. package/src/HoverCard/useHoverCard.tsx +52 -46
  137. package/src/Icon/Icon.doc.mjs +8 -49
  138. package/src/Icon/Icon.tsx +7 -15
  139. package/src/Layer/usePressPin.ts +15 -81
  140. package/src/Lightbox/Lightbox.tsx +0 -18
  141. package/src/PowerSearch/PowerSearch.doc.mjs +5 -54
  142. package/src/PowerSearch/PowerSearch.tsx +155 -609
  143. package/src/PowerSearch/PowerSearchEditPopover.tsx +6 -28
  144. package/src/PowerSearch/PowerSearchValueEditor.tsx +38 -203
  145. package/src/PowerSearch/formatFilterValue.ts +1 -18
  146. package/src/RadioList/RadioList.tsx +2 -3
  147. package/src/RadioList/RadioListItem.tsx +3 -5
  148. package/src/Resizable/Resizable.doc.mjs +4 -5
  149. package/src/Resizable/ResizeHandle.tsx +109 -167
  150. package/src/SegmentedControl/useSegmentedSelectionMotion.ts +3 -6
  151. package/src/Slider/sliderTouchController.ts +2 -2
  152. package/src/Spinner/Spinner.tsx +63 -77
  153. package/src/Switch/useSwitchTouch.ts +4 -4
  154. package/src/Table/BaseTable.tsx +12 -46
  155. package/src/TextInput/TextInput.tsx +10 -11
  156. package/src/Toast/Toast.doc.mjs +3 -4
  157. package/src/Toast/Toast.tsx +32 -52
  158. package/src/Toast/ToastViewport.tsx +35 -121
  159. package/src/Toast/types.ts +3 -9
  160. package/src/Tooltip/useTooltip.doc.mjs +0 -24
  161. package/src/Tooltip/useTooltip.tsx +56 -61
  162. package/src/Typeahead/TypeaheadItem.doc.mjs +3 -6
  163. package/src/Typeahead/TypeaheadItem.tsx +1 -2
  164. package/src/gestures/PressTracker.ts +3 -4
  165. package/src/gestures/README.md +1 -7
  166. package/src/hooks/actionGroupTracker.ts +5 -20
  167. package/src/hooks/index.ts +0 -2
  168. package/src/hooks/useAttachment.ts +1 -1
  169. package/src/hooks/useInputStatusIcon.tsx +2 -3
  170. package/src/hooks/useLongPress.doc.mjs +2 -2
  171. package/src/hooks/useLongPress.ts +15 -136
  172. package/src/i18n/generated-english/PowerSearch/PowerSearchValueEditor.generated.ts +0 -6
  173. package/src/i18n/generated-locales/en.generated.ts +0 -41
  174. package/src/i18n/generated-locales/pseudo.generated.ts +0 -42
  175. package/src/index.ts +0 -13
  176. package/src/motion/README.md +5 -9
  177. package/src/motion/animatedLayout.ts +4 -5
  178. package/src/motion/animator.ts +29 -61
  179. package/src/utils/dateParser.ts +0 -16
  180. package/src/utils/focusReturn.ts +0 -30
  181. package/src/utils/interactionOverlay.stylex.ts +2 -3
  182. package/src/utils/pressFeedback.ts +6 -19
  183. package/dist/PowerSearch/PowerSearchBottomSheet.d.ts +0 -100
  184. package/dist/PowerSearch/PowerSearchBottomSheet.d.ts.map +0 -1
  185. package/dist/PowerSearch/PowerSearchBottomSheet.js +0 -1913
  186. package/dist/PowerSearch/formatTokenValue.d.ts +0 -28
  187. package/dist/PowerSearch/formatTokenValue.d.ts.map +0 -1
  188. package/dist/PowerSearch/formatTokenValue.js +0 -160
  189. package/dist/PowerSearch/powerSearchSheetUtils.d.ts +0 -65
  190. package/dist/PowerSearch/powerSearchSheetUtils.d.ts.map +0 -1
  191. package/dist/PowerSearch/powerSearchSheetUtils.js +0 -168
  192. package/dist/animator/createAnimator.d.ts +0 -98
  193. package/dist/animator/createAnimator.d.ts.map +0 -1
  194. package/dist/animator/createAnimator.js +0 -259
  195. package/dist/hooks/pressGroupContext.d.ts +0 -6
  196. package/dist/hooks/pressGroupContext.d.ts.map +0 -1
  197. package/dist/hooks/pressGroupContext.js +0 -20
  198. package/dist/hooks/useActionGroupTracking.d.ts +0 -53
  199. package/dist/hooks/useActionGroupTracking.d.ts.map +0 -1
  200. package/dist/hooks/useActionGroupTracking.js +0 -174
  201. package/dist/hooks/useAnimator.d.ts +0 -41
  202. package/dist/hooks/useAnimator.d.ts.map +0 -1
  203. package/dist/hooks/useAnimator.js +0 -70
  204. package/dist/i18n/generated-english/PowerSearch/PowerSearchBottomSheet.generated.d.ts +0 -8
  205. package/dist/i18n/generated-english/PowerSearch/PowerSearchBottomSheet.generated.d.ts.map +0 -1
  206. package/dist/i18n/generated-english/PowerSearch/PowerSearchBottomSheet.generated.js +0 -42
  207. package/dist/i18n/generated-english/PowerSearch/formatTokenValue.generated.d.ts +0 -8
  208. package/dist/i18n/generated-english/PowerSearch/formatTokenValue.generated.d.ts.map +0 -1
  209. package/dist/i18n/generated-english/PowerSearch/formatTokenValue.generated.js +0 -14
  210. package/dist/internal/indicatorPress.stylex.d.ts +0 -20
  211. package/dist/internal/indicatorPress.stylex.d.ts.map +0 -1
  212. package/dist/internal/indicatorPress.stylex.js +0 -26
  213. package/dist/motion/progress.d.ts +0 -88
  214. package/dist/motion/progress.d.ts.map +0 -1
  215. package/dist/motion/progress.js +0 -128
  216. package/dist/motion/uikit/alert.d.ts +0 -41
  217. package/dist/motion/uikit/alert.d.ts.map +0 -1
  218. package/dist/motion/uikit/alert.js +0 -43
  219. package/dist/privateAttributes/pressGroupItem.stylex.d.ts +0 -15
  220. package/dist/privateAttributes/pressGroupItem.stylex.d.ts.map +0 -1
  221. package/dist/privateAttributes/pressGroupItem.stylex.js +0 -23
  222. package/dist/utils/triggerFocus.d.ts +0 -36
  223. package/dist/utils/triggerFocus.d.ts.map +0 -1
  224. package/dist/utils/triggerFocus.js +0 -65
  225. package/src/PowerSearch/PowerSearchBottomSheet.tsx +0 -2515
  226. package/src/PowerSearch/formatTokenValue.ts +0 -215
  227. package/src/PowerSearch/powerSearchSheetUtils.ts +0 -224
  228. package/src/animator/createAnimator.doc.mjs +0 -153
  229. package/src/animator/createAnimator.ts +0 -324
  230. package/src/hooks/pressGroupContext.ts +0 -21
  231. package/src/hooks/useActionGroupTracking.ts +0 -224
  232. package/src/hooks/useAnimator.doc.mjs +0 -109
  233. package/src/hooks/useAnimator.ts +0 -67
  234. package/src/i18n/generated-english/PowerSearch/PowerSearchBottomSheet.generated.ts +0 -43
  235. package/src/i18n/generated-english/PowerSearch/formatTokenValue.generated.ts +0 -15
  236. package/src/internal/indicatorPress.stylex.ts +0 -24
  237. package/src/motion/progress.ts +0 -155
  238. package/src/motion/uikit/alert.ts +0 -43
  239. package/src/privateAttributes/pressGroupItem.stylex.ts +0 -23
  240. package/src/utils/triggerFocus.ts +0 -80
@@ -57,8 +57,7 @@ export interface ActionGroupTrackerOptions {
57
57
  * target past the group's ends commits the lift there wherever the finger
58
58
  * lifts.
59
59
  * @default the target whose rect, grown by `highlightExpansion`, holds the
60
- * point, the one the press landed on where several do; none between or
61
- * outside them
60
+ * point; none between or outside them
62
61
  */
63
62
  resolveTarget?: (
64
63
  x: number,
@@ -84,13 +83,8 @@ export interface ActionGroupTracker {
84
83
  /**
85
84
  * A press began at viewport (x, y): read the actions' rects once and
86
85
  * highlight the one under it. An inert press is taken but tracks nothing.
87
- * `landed` is the node the press landed on.
88
86
  */
89
- begin(
90
- x: number,
91
- y: number,
92
- options?: {inert?: boolean; landed?: Node | null},
93
- ): void;
87
+ begin(x: number, y: number, options?: {inert?: boolean}): void;
94
88
  /** The finger moved to viewport (x, y). */
95
89
  move(x: number, y: number): void;
96
90
  /**
@@ -156,7 +150,6 @@ export function createActionGroupTracker(
156
150
  let actions: TrackedAction[] = [];
157
151
  let highlighted: HTMLElement | null = null;
158
152
  let beganOn: HTMLElement | null = null;
159
- let landedOn: Node | null = null;
160
153
  let isTracking = false;
161
154
  let isInert = false;
162
155
  // The finger's last position: `remeasure` resolves it again.
@@ -248,9 +241,6 @@ export function createActionGroupTracker(
248
241
  if (resolveTarget != null) {
249
242
  return actions.length === 0 ? null : resolveTarget(x, y, actions);
250
243
  }
251
- // Rects that share an edge, or that have no layout (a test renderer), can
252
- // both hold the point: the one the press landed on wins.
253
- let first: HTMLElement | null = null;
254
244
  for (const action of actions) {
255
245
  if (
256
246
  x >= action.left - margin &&
@@ -258,26 +248,22 @@ export function createActionGroupTracker(
258
248
  y >= action.top - margin &&
259
249
  y <= action.bottom + margin
260
250
  ) {
261
- if (landedOn != null && action.element.contains(landedOn)) {
262
- return action.element;
263
- }
264
- first ??= action.element;
251
+ return action.element;
265
252
  }
266
253
  }
267
- return first;
254
+ return null;
268
255
  };
269
256
 
270
257
  const reset = () => {
271
258
  actions = [];
272
259
  highlighted = null;
273
260
  beganOn = null;
274
- landedOn = null;
275
261
  isTracking = false;
276
262
  isInert = false;
277
263
  };
278
264
 
279
265
  return {
280
- begin(x, y, {inert = false, landed = null} = {}) {
266
+ begin(x, y, {inert = false} = {}) {
281
267
  // A press can begin while another is tracked, when a second recognizer
282
268
  // takes over the finger (a trigger's held press, then the menu's): the
283
269
  // action the first one lit loses its paint.
@@ -290,7 +276,6 @@ export function createActionGroupTracker(
290
276
  highlighted = null;
291
277
  isTracking = true;
292
278
  isInert = inert;
293
- landedOn = landed;
294
279
  lastX = x;
295
280
  lastY = y;
296
281
  getOptions().onMove?.(x, y);
@@ -133,8 +133,6 @@ export type {
133
133
  UseInteractiveRoleOptions,
134
134
  } from './useInteractiveRole';
135
135
 
136
- export {useAnimator} from './useAnimator';
137
-
138
136
  export {useLongPress} from './useLongPress';
139
137
  export type {UseLongPressOptions, UseLongPressHandlers} from './useLongPress';
140
138
 
@@ -9,7 +9,7 @@
9
9
  * @output Exports useAttachment and useAttachmentPair (two elements): they keep
10
10
  * the attach function bound to the nodes the refs hold across commits
11
11
  * @position Internal React helper, not in hooks/index.ts: the one attach and
12
- * release lifecycle of the gesture hooks, the pager and useAnimator
12
+ * release lifecycle of the gesture hooks and the pager
13
13
  *
14
14
  * SYNC: When modified, update gestures/__tests__/useGestureRecognizer.test.tsx,
15
15
  * gestures/__tests__/useFingerScroll.test.tsx and
@@ -15,10 +15,9 @@
15
15
  import {useCallback, useEffect, useState} from 'react';
16
16
  import type {ReactNode} from 'react';
17
17
  import * as stylex from '@stylexjs/stylex';
18
- import {Icon, type IconSize} from '../Icon/Icon';
19
- import type {IconName} from '../Icon/globalIconRegistry';
18
+ import {Icon, type IconName, type IconSize} from '../Icon';
20
19
  import type {InputStatus, InputStatusType} from '../Field/types';
21
- import {useTooltip} from '../Tooltip/useTooltip';
20
+ import {useTooltip} from '../Tooltip';
22
21
  import {radiusVars} from '../theme/tokens.stylex';
23
22
  import {themeProps} from '../utils/themeProps';
24
23
  import {focusOutlineStyles} from '../utils/focusOutline.stylex';
@@ -59,7 +59,7 @@ export const docs = {
59
59
  ],
60
60
  usage: {
61
61
  description:
62
- 'Detects a single-finger press-and-hold and reports where it happened, so touch users can reach affordances that a pointer gets from right-click. iOS Safari never synthesizes a contextmenu event on long-press, which makes this the only touch route into a cursor-positioned surface such as ContextMenu. The press cancels on movement, lift, multi-touch or unmount. The hold is timed on the touch events\u2019 own timestamps: when a busy page handles the lift late, a finger held for the full delay still reports its long press, before the lift acts.',
62
+ 'Detects a single-finger press-and-hold and reports where it happened, so touch users can reach affordances that a pointer gets from right-click. iOS Safari never synthesizes a contextmenu event on long-press, which makes this the only touch route into a cursor-positioned surface such as ContextMenu. The press cancels on movement, lift, multi-touch or unmount.',
63
63
  bestPractices: [
64
64
  {
65
65
  guidance: true,
@@ -102,7 +102,7 @@ export const docsDense = {
102
102
  },
103
103
  usage: {
104
104
  description:
105
- "Touch press-and-hold for affordances a pointer reaches by right-click (e.g. ContextMenu). Reports the point so the surface opens under the finger. Timed on the touch events' timestamps: a busy page delays the report, never drops it.",
105
+ 'Touch press-and-hold for affordances a pointer reaches by right-click (e.g. ContextMenu). Reports the point so the surface opens under the finger.',
106
106
  bestPractices: [
107
107
  {
108
108
  guidance: true,
@@ -25,11 +25,6 @@
25
25
  // its tolerance as a distance, as UIKit does. This hook measures it on each
26
26
  // axis. The context menu's own movement allowance is a guess and is not
27
27
  // measured yet (AST-094).
28
- //
29
- // The hold is a deadline on the touch events' timestamps, on the clock of the
30
- // touch's own window. A busy main thread can delay the timer past the
31
- // deadline. A touch stamped after the deadline then reports the press before
32
- // it acts.
33
28
 
34
29
  import {useCallback, useEffect, useRef} from 'react';
35
30
  import {
@@ -42,41 +37,6 @@ import {
42
37
  const DEFAULT_DELAY_MS = LONG_PRESS_DURATION_MS;
43
38
  const DEFAULT_MOVE_CANCEL_PX = LONG_PRESS_ALLOWABLE_MOVEMENT_PX;
44
39
 
45
- /** The part of a window's performance timeline a press reads. */
46
- type EventClock = Pick<Performance, 'now'>;
47
-
48
- function clockOf(e: React.TouchEvent): EventClock | null {
49
- const view = e.view as unknown as {performance?: EventClock} | null;
50
- return (
51
- view?.performance ??
52
- (typeof performance === 'undefined' ? null : performance)
53
- );
54
- }
55
-
56
- /**
57
- * An event's time on its window's clock. jsdom stamps events with
58
- * `Date.now()`. The hook reads the age of such a stamp on that clock, so a
59
- * frozen system time keeps the hold's length. A stamp nearer `Date.now()` than
60
- * the window's clock is that kind of stamp.
61
- */
62
- function timeOn(
63
- clock: EventClock | null,
64
- timeStamp: number | undefined,
65
- ): number | undefined {
66
- // A stamp of 0 means the event carries no time, so the hold falls back to
67
- // the full delay on the page's timer.
68
- if (timeStamp == null || !Number.isFinite(timeStamp) || timeStamp <= 0) {
69
- return undefined;
70
- }
71
- if (
72
- clock != null &&
73
- Math.abs(Date.now() - timeStamp) < Math.abs(clock.now() - timeStamp)
74
- ) {
75
- return clock.now() - (Date.now() - timeStamp);
76
- }
77
- return timeStamp;
78
- }
79
-
80
40
  export interface UseLongPressOptions {
81
41
  /** Fired with the touch start point once the press is held for `delayMs`. */
82
42
  onLongPress: (point: {x: number; y: number}) => void;
@@ -99,12 +59,8 @@ export interface LongPressTolerance {
99
59
  export interface UseLongPressHandlers {
100
60
  onTouchStart: (e: React.TouchEvent) => void;
101
61
  onTouchMove: (e: React.TouchEvent) => void;
102
- /**
103
- * The lift. Pass the event, so a press it is stamped past (its timer held
104
- * back by a busy page) still reports first. Spreading the handlers does.
105
- */
106
- onTouchEnd: (e?: React.TouchEvent) => void;
107
- onTouchCancel: (e?: React.TouchEvent) => void;
62
+ onTouchEnd: () => void;
63
+ onTouchCancel: () => void;
108
64
  /**
109
65
  * Begin detection at a point, for a caller driving this from its own
110
66
  * pointer events rather than the touch handlers above.
@@ -162,9 +118,6 @@ export function useLongPressDetector(
162
118
 
163
119
  const timerRef = useRef<ReturnType<typeof setTimeout> | null>(null);
164
120
  const startRef = useRef<{x: number; y: number} | null>(null);
165
- // The pending press's deadline and clock, when it started from a touch.
166
- const deadlineRef = useRef<number | null>(null);
167
- const clockRef = useRef<EventClock | null>(null);
168
121
  // The press in progress's tolerance, when its caller chose one at start.
169
122
  const pressToleranceRef = useRef<LongPressTolerance | null>(null);
170
123
  // Keep the latest callback without re-creating handlers on every render.
@@ -177,39 +130,10 @@ export function useLongPressDetector(
177
130
  timerRef.current = null;
178
131
  }
179
132
  startRef.current = null;
180
- deadlineRef.current = null;
181
- clockRef.current = null;
182
133
  }, []);
183
134
 
184
- const fire = useCallback(() => {
185
- const from = startRef.current;
186
- if (from == null) {
187
- return;
188
- }
189
- clear();
190
- onLongPressRef.current({x: from.x, y: from.y});
191
- }, [clear]);
192
-
193
- // A touch stamped at or past the deadline: the finger was down for the
194
- // whole delay, so the press reports before the touch acts.
195
- const fireIfDue = useCallback(
196
- (e: React.TouchEvent | undefined) => {
197
- const deadline = deadlineRef.current;
198
- const eventTime =
199
- e == null ? undefined : timeOn(clockRef.current, e.timeStamp);
200
- if (deadline != null && eventTime != null && eventTime >= deadline) {
201
- fire();
202
- }
203
- },
204
- [fire],
205
- );
206
-
207
- const begin = useCallback(
208
- (
209
- point: {x: number; y: number},
210
- tolerance: LongPressTolerance | undefined,
211
- started: {at: number; clock: EventClock} | undefined,
212
- ) => {
135
+ const start = useCallback(
136
+ (point: {x: number; y: number}, tolerance?: LongPressTolerance) => {
213
137
  if (disabled) {
214
138
  return;
215
139
  }
@@ -218,40 +142,15 @@ export function useLongPressDetector(
218
142
  clear();
219
143
  startRef.current = {x: point.x, y: point.y};
220
144
  pressToleranceRef.current = tolerance ?? null;
221
- const clock = started?.clock ?? null;
222
- const deadline = started == null ? null : started.at + delayMs;
223
- clockRef.current = clock;
224
- deadlineRef.current = deadline;
225
- // Wait only for the rest of the hold, so a touch handled late does not
226
- // lengthen it, and never past the delay.
227
- const remaining =
228
- clock == null || deadline == null
229
- ? delayMs
230
- : Math.min(delayMs, Math.max(0, deadline - clock.now()));
231
- // A late timer yields to queued input once, so a lift stamped before
232
- // the deadline still cancels the press. The gesture arena does the same.
233
- const run = (mayYield: boolean) => {
234
- timerRef.current = null;
235
- if (
236
- mayYield &&
237
- clock != null &&
238
- deadline != null &&
239
- clock.now() > deadline
240
- ) {
241
- timerRef.current = setTimeout(() => run(false), 0);
145
+ timerRef.current = setTimeout(() => {
146
+ const from = startRef.current;
147
+ if (from == null) {
242
148
  return;
243
149
  }
244
- fire();
245
- };
246
- timerRef.current = setTimeout(() => run(true), remaining);
150
+ onLongPressRef.current({x: from.x, y: from.y});
151
+ }, delayMs);
247
152
  },
248
- [disabled, delayMs, clear, fire],
249
- );
250
-
251
- const start = useCallback(
252
- (point: {x: number; y: number}, tolerance?: LongPressTolerance) =>
253
- begin(point, tolerance, undefined),
254
- [begin],
153
+ [disabled, delayMs, clear],
255
154
  );
256
155
 
257
156
  const moveTo = useCallback(
@@ -280,29 +179,17 @@ export function useLongPressDetector(
280
179
  return;
281
180
  }
282
181
  if (e.touches.length !== 1) {
283
- // A second finger ends the press, unless the press was already due.
284
- fireIfDue(e);
285
182
  clear();
286
183
  return;
287
184
  }
288
185
  const touch = e.touches[0];
289
- const clock = clockOf(e);
290
- const at = timeOn(clock, e.timeStamp);
291
- begin(
292
- {x: touch.clientX, y: touch.clientY},
293
- undefined,
294
- clock == null || at == null ? undefined : {at, clock},
295
- );
186
+ start({x: touch.clientX, y: touch.clientY});
296
187
  },
297
- [disabled, clear, begin, fireIfDue],
188
+ [disabled, clear, start],
298
189
  );
299
190
 
300
191
  const onTouchMove = useCallback(
301
192
  (e: React.TouchEvent) => {
302
- if (startRef.current == null) {
303
- return;
304
- }
305
- fireIfDue(e);
306
193
  if (startRef.current == null) {
307
194
  return;
308
195
  }
@@ -313,15 +200,7 @@ export function useLongPressDetector(
313
200
  const touch = e.touches[0];
314
201
  moveTo({x: touch.clientX, y: touch.clientY});
315
202
  },
316
- [clear, moveTo, fireIfDue],
317
- );
318
-
319
- const onTouchEnd = useCallback(
320
- (e?: React.TouchEvent) => {
321
- fireIfDue(e);
322
- clear();
323
- },
324
- [clear, fireIfDue],
203
+ [clear, moveTo],
325
204
  );
326
205
 
327
206
  useEffect(() => clear, [clear]);
@@ -329,8 +208,8 @@ export function useLongPressDetector(
329
208
  return {
330
209
  onTouchStart,
331
210
  onTouchMove,
332
- onTouchEnd,
333
- onTouchCancel: onTouchEnd,
211
+ onTouchEnd: clear,
212
+ onTouchCancel: clear,
334
213
  start,
335
214
  moveTo,
336
215
  cancel: clear,
@@ -7,12 +7,6 @@
7
7
  */
8
8
 
9
9
  const english: Readonly<Record<string, string>> = {
10
- "@astryx.powersearch.sheet.relativeDaysAgo": "{count, number} {count, plural, one {day} other {days}} ago",
11
- "@astryx.powersearch.sheet.relativeDaysFromNow": "{count, number} {count, plural, one {day} other {days}} from now",
12
- "@astryx.powersearch.sheet.relativeMonthsAgo": "{count, number} {count, plural, one {month} other {months}} ago",
13
- "@astryx.powersearch.sheet.relativeMonthsFromNow": "{count, number} {count, plural, one {month} other {months}} from now",
14
- "@astryx.powersearch.sheet.relativeWeeksAgo": "{count, number} {count, plural, one {week} other {weeks}} ago",
15
- "@astryx.powersearch.sheet.relativeWeeksFromNow": "{count, number} {count, plural, one {week} other {weeks}} from now",
16
10
  "@astryx.powersearch.valueEditor.addValuesPlaceholder": "Add values…",
17
11
  "@astryx.powersearch.valueEditor.date": "Date",
18
12
  "@astryx.powersearch.valueEditor.dateRange": "date range",
@@ -78,47 +78,6 @@ const runtimeCatalog: Readonly<Record<string, string>> = {
78
78
  '{count, number} {count, plural, one {filter} other {filters}}',
79
79
  '@astryx.powersearch.resultCount':
80
80
  '{count, number} {count, plural, one {result} other {results}}',
81
- '@astryx.powersearch.sheet.filtersTitle': 'Filters',
82
- '@astryx.powersearch.sheet.addFilter': 'Add filter',
83
- '@astryx.powersearch.sheet.noFilters': 'No filters applied',
84
- '@astryx.powersearch.sheet.noFiltersDescription':
85
- 'Add a filter to narrow your results and find what you need faster.',
86
- '@astryx.powersearch.sheet.clearAll': 'Clear all',
87
- '@astryx.powersearch.sheet.clearAllTitle': 'Clear all filters?',
88
- '@astryx.powersearch.sheet.clearAllDescription':
89
- 'This removes all editable filters from this search.',
90
- '@astryx.powersearch.sheet.clearAllConfirm': 'Clear filters',
91
- '@astryx.powersearch.sheet.clearAllCancel': 'Keep filters',
92
- '@astryx.powersearch.sheet.done': 'Done',
93
- '@astryx.powersearch.sheet.search': 'Search',
94
- '@astryx.powersearch.sheet.searchResults': 'Search results',
95
- '@astryx.powersearch.sheet.searchFields': 'Search filters',
96
- '@astryx.powersearch.sheet.searchFieldsPlaceholder': 'Search filters…',
97
- '@astryx.powersearch.sheet.ungroupedFields': 'General',
98
- '@astryx.powersearch.sheet.noMatchingFields': 'No filters match your search',
99
- '@astryx.powersearch.sheet.tryDifferentSearch': 'Try a different search.',
100
- '@astryx.powersearch.sheet.noResults': 'No results found',
101
- '@astryx.powersearch.sheet.filterUnavailable':
102
- 'This filter is no longer available',
103
- '@astryx.powersearch.sheet.removeFilter': 'Remove {field} filter',
104
- '@astryx.powersearch.sheet.relativeDaysAgo':
105
- '{count, number} {count, plural, one {day} other {days}} ago',
106
- '@astryx.powersearch.sheet.relativeDaysFromNow':
107
- '{count, number} {count, plural, one {day} other {days}} from now',
108
- '@astryx.powersearch.sheet.relativeWeeksAgo':
109
- '{count, number} {count, plural, one {week} other {weeks}} ago',
110
- '@astryx.powersearch.sheet.relativeWeeksFromNow':
111
- '{count, number} {count, plural, one {week} other {weeks}} from now',
112
- '@astryx.powersearch.sheet.relativeMonthsAgo':
113
- '{count, number} {count, plural, one {month} other {months}} ago',
114
- '@astryx.powersearch.sheet.relativeMonthsFromNow':
115
- '{count, number} {count, plural, one {month} other {months}} from now',
116
- '@astryx.powersearch.sheet.fieldOperator': '{field} {operator}',
117
- '@astryx.powersearch.sheet.labelValue': '{label} {value}',
118
- '@astryx.powersearch.sheet.filtersClearedWithCount':
119
- 'All filters removed. {resultCount}',
120
- '@astryx.powersearch.sheet.editableFiltersClearedWithCount':
121
- 'Editable filters removed. {resultCount}',
122
81
  '@astryx.alertDialog.cancel': 'Cancel',
123
82
  '@astryx.appShell.mobileNavigation': 'Mobile navigation',
124
83
  '@astryx.appShell.skipToContent': 'Skip to content',
@@ -80,48 +80,6 @@ const runtimeCatalog: Readonly<Record<string, string>> = {
80
80
  '⟦{count, number} {count, plural, one {filter} other {filters}}⟧',
81
81
  '@astryx.powersearch.resultCount':
82
82
  '⟦{count, number} {count, plural, one {result} other {results}}⟧',
83
- '@astryx.powersearch.sheet.filtersTitle': '⟦Ƒíłţéřš⟧',
84
- '@astryx.powersearch.sheet.addFilter': '⟦Àðð ƒíłţéř⟧',
85
- '@astryx.powersearch.sheet.noFilters': '⟦Ñó ƒíłţéřš àþþłíéð⟧',
86
- '@astryx.powersearch.sheet.noFiltersDescription':
87
- '⟦Àðð à ƒíłţéř ţó ñàřřóŵ ýóúř řéšúłţš àñð ƒíñð ŵĥàţ ýóú ñééð ƒàšţéř.⟧',
88
- '@astryx.powersearch.sheet.clearAll': '⟦Çłéàř àłł⟧',
89
- '@astryx.powersearch.sheet.clearAllTitle': '⟦Çłéàř àłł ƒíłţéřš?⟧',
90
- '@astryx.powersearch.sheet.clearAllDescription':
91
- '⟦Ţĥíš řéɱóṽéš àłł éðíţàƀłé ƒíłţéřš ƒřóɱ ţĥíš šéàřçĥ.⟧',
92
- '@astryx.powersearch.sheet.clearAllConfirm': '⟦Çłéàř ƒíłţéřš⟧',
93
- '@astryx.powersearch.sheet.clearAllCancel': '⟦Ķééþ ƒíłţéřš⟧',
94
- '@astryx.powersearch.sheet.done': '⟦Ðóñé⟧',
95
- '@astryx.powersearch.sheet.search': '⟦Šéàřçĥ⟧',
96
- '@astryx.powersearch.sheet.searchResults': '⟦Šéàřçĥ řéšúłţš⟧',
97
- '@astryx.powersearch.sheet.searchFields': '⟦Šéàřçĥ ƒíłţéřš⟧',
98
- '@astryx.powersearch.sheet.searchFieldsPlaceholder': '⟦Šéàřçĥ ƒíłţéřš…⟧',
99
- '@astryx.powersearch.sheet.ungroupedFields': '⟦Ĝéñéřàł⟧',
100
- '@astryx.powersearch.sheet.noMatchingFields':
101
- '⟦Ñó ƒíłţéřš ɱàţçĥ ýóúř šéàřçĥ⟧',
102
- '@astryx.powersearch.sheet.tryDifferentSearch': '⟦Ţřý à ð탃éřéñţ šéàřçĥ.⟧',
103
- '@astryx.powersearch.sheet.noResults': '⟦Ñó řéšúłţš ƒóúñð⟧',
104
- '@astryx.powersearch.sheet.filterUnavailable':
105
- '⟦Ţĥíš ƒíłţéř íš ñó łóñĝéř àṽàíłàƀłé⟧',
106
- '@astryx.powersearch.sheet.removeFilter': '⟦Řéɱóṽé {field} ƒíłţéř⟧',
107
- '@astryx.powersearch.sheet.relativeDaysAgo':
108
- '⟦{count, number} {count, plural, one {day} other {days}} àĝó⟧',
109
- '@astryx.powersearch.sheet.relativeDaysFromNow':
110
- '⟦{count, number} {count, plural, one {day} other {days}} ƒřóɱ ñóŵ⟧',
111
- '@astryx.powersearch.sheet.relativeWeeksAgo':
112
- '⟦{count, number} {count, plural, one {week} other {weeks}} àĝó⟧',
113
- '@astryx.powersearch.sheet.relativeWeeksFromNow':
114
- '⟦{count, number} {count, plural, one {week} other {weeks}} ƒřóɱ ñóŵ⟧',
115
- '@astryx.powersearch.sheet.relativeMonthsAgo':
116
- '⟦{count, number} {count, plural, one {month} other {months}} àĝó⟧',
117
- '@astryx.powersearch.sheet.relativeMonthsFromNow':
118
- '⟦{count, number} {count, plural, one {month} other {months}} ƒřóɱ ñóŵ⟧',
119
- '@astryx.powersearch.sheet.fieldOperator': '⟦{field} {operator}⟧',
120
- '@astryx.powersearch.sheet.labelValue': '⟦{label} {value}⟧',
121
- '@astryx.powersearch.sheet.filtersClearedWithCount':
122
- '⟦Àłł ƒíłţéřš řéɱóṽéð. {resultCount}⟧',
123
- '@astryx.powersearch.sheet.editableFiltersClearedWithCount':
124
- '⟦Éðíţàƀłé ƒíłţéřš řéɱóṽéð. {resultCount}⟧',
125
83
  '@astryx.alertDialog.cancel': '⟦Çàñçéł⟧',
126
84
  '@astryx.appShell.mobileNavigation': '⟦Ṁóƀíłé ñàṽíĝàţíóñ⟧',
127
85
  '@astryx.appShell.skipToContent': '⟦Šķíþ ţó çóñţéñţ⟧',
package/src/index.ts CHANGED
@@ -173,19 +173,6 @@ export * from './Outline';
173
173
  // Overflow list
174
174
  export * from './OverflowList';
175
175
 
176
- // Animating one element: from the package root only, since one API has one
177
- // entry. Its hook ships from './hooks'.
178
- export {
179
- createAnimator,
180
- type Animator,
181
- type AnimatorAnimateOptions,
182
- type AnimatorChannel,
183
- type AnimatorDecayVelocity,
184
- type AnimatorHandle,
185
- type AnimatorSnapshot,
186
- type AnimatorValues,
187
- } from './animator/createAnimator';
188
-
189
176
  // Hooks
190
177
  export * from './hooks';
191
178
 
@@ -19,7 +19,6 @@ roles through `resolveMotion`.
19
19
  | `uikit/scroll.ts` | UIScrollView: deceleration rates, rubber band, bounce-back spring, `delaysContentTouches`, scroll to top. |
20
20
  | `uikit/timing.ts` | Non-spring clocks and curves: press highlight, Core Animation's named curves, keyboard, Reduced Motion cross-fade. |
21
21
  | `uikit/paging.ts` | A paging UIScrollView: the integrator that settles a release on its page, the page rule, the catch, `setContentOffset(animated:)`. |
22
- | `uikit/alert.ts` | UIAlertController: how a finger is tracked across the actions (highlight onset and bounds). |
23
22
  | `uikit/navigation.ts` | UINavigationController: push velocity, parallax, dimming, transition clock, interactive pop finish rule. |
24
23
  | `uikit/progressBar.ts` | UIProgressView's fill: the whole-track duration and curve, its minimum length and empty alpha; the reduced-motion pulse (three roles). |
25
24
  | `uikit/gestures.ts` | Gesture recognizer thresholds, the velocity filter and haptic stand-ins, as `{value, unit}` entries (sources in JSDoc). |
@@ -38,7 +37,6 @@ roles through `resolveMotion`.
38
37
  | `resolveSnapPoint.ts` | Release policy: the snap point a release lands on (flick, back-out cancel, step limit), on `selectSnapPoint`. Internal. |
39
38
  | `bezier.ts` | Cubic-bézier timing functions (Core Animation's named curves). |
40
39
  | `animator.ts` | Compositor animator: springs, coasts and any closed-form curve compiled to Web Animations, read back analytically. |
41
- | `progress.ts` | A spring's progress, one curve mapped from another (companions, clamped ranges), the velocity that continues a motion. |
42
40
  | `presentation.ts` | Where each moving element is drawn relative to where the engine hit-tests it, reported by the animator while translate runs; read by the gesture host at touch-down. |
43
41
  | `reducedMotionPlan.ts` | The animator's Reduce Motion planner: what one call becomes, a cross-fade whose travel lands while transparent or at once. |
44
42
  | `__tests__/animator.interaction.browser.spec.ts` | Browser proofs on the interaction harness (Chromium and WebKit): busy main thread, end state through a block, no Layout / Paint, seeked curves, a dialog's backdrop. |
@@ -66,7 +64,7 @@ the timings that decide who gets a touch are not roles.
66
64
  ## Animator
67
65
 
68
66
  ```
69
- import {createMotionAnimator} from '../motion/animator';
67
+ import {createAnimator} from '../motion/animator';
70
68
  import {coast} from '../motion/coast';
71
69
  import {solveSpringTowardRamp, toSpring} from '../motion/spring';
72
70
  import {resolveMotion} from '../motion/resolveMotion';
@@ -75,7 +73,7 @@ import {registerSpringsTable, springs} from '../motion/uikit';
75
73
  // Once, so the springs are registered as their roles:
76
74
  registerSpringsTable();
77
75
 
78
- const animator = createMotionAnimator(sheet);
76
+ const animator = createAnimator(sheet);
79
77
  // The animator plays a motion role (spec:AST-094 FR4), its table value, as the
80
78
  // per-role tables stay internal (DEC-15); math on a spring reads the role with
81
79
  // resolveMotion.
@@ -140,10 +138,8 @@ await handle.finished; // true if it ran to the end, false if interrupted
140
138
  presented call's second frame) runs on over two frames, the start moves to
141
139
  the call's first read after it, with every call of that task. Everything
142
140
  the call starts shares that start
143
- (`handle.started`); a retarget of a curve that still moves keeps an
144
- explicit one, while one on a tail that already shows as at rest (within two
145
- sample tolerances of its target, and slower than one a frame) counts as a
146
- call from rest. `{at}` puts several animators on one clock. `{start: 'commit'}` lets the browser date
141
+ (`handle.started`); a retarget keeps an explicit one, and `{at}` puts
142
+ several animators on one clock. `{start: 'commit'}` lets the browser date
147
143
  a retarget too; `{start: 'presented'}` waits two frames, until the
148
144
  element at rest has been presented. `handle.curve(property)` is the curve
149
145
  a call plays, for a companion to follow. `{additive: true}` retargets the
@@ -172,7 +168,7 @@ await handle.finished; // true if it ran to the end, false if interrupted
172
168
  - `animatorFor(element)` returns the one animator for an element, so code
173
169
  that animates it from several places (a swipe on x, a removal on y)
174
170
  composes in one `translate` track.
175
- - `createMotionAnimator(dialog, {pseudoElement: '::backdrop'})` drives a
171
+ - `createAnimator(dialog, {pseudoElement: '::backdrop'})` drives a
176
172
  pseudo-element; with no inline style to hold it, a static filling animation
177
173
  holds its end value until the next animation replaces it, while the
178
174
  pseudo-element exists. A dialog's `::backdrop` is made again each time the
@@ -89,8 +89,7 @@ import {
89
89
  wrapText,
90
90
  } from './transientCopy';
91
91
  import {isSpring} from './roleValue';
92
- import {progressCurve} from './progress';
93
- import type {SpringDescription} from './spring';
92
+ import {solveSpring, toSpring, type SpringDescription} from './spring';
94
93
  import {registerSpringsTable, SETTLE_SPRING} from './uikit/springs';
95
94
  import {reducedMotionCrossFade} from './uikit/timing';
96
95
 
@@ -143,11 +142,11 @@ function settleSpring(): SpringDescription {
143
142
  }
144
143
 
145
144
  function springProgress(description: SpringDescription): SpringProgress {
146
- const curve = progressCurve(description, {epsilon: 0.001});
147
- const durationMs = Math.max(1, curve.duration * 1000);
145
+ const curve = solveSpring(toSpring(description), {from: 1, to: 0});
146
+ const durationMs = Math.max(1, curve.settleTime(0.001) * 1000);
148
147
  return {
149
148
  durationMs,
150
- remaining: t => (t >= durationMs ? 0 : 1 - curve.at(t / 1000)),
149
+ remaining: t => (t >= durationMs ? 0 : curve.value(t / 1000)),
151
150
  };
152
151
  }
153
152