@astryxdesign/core 0.7.6 → 0.7.7-canary.0eb44a2

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 (272) hide show
  1. package/dist/AppShell/AppShell.d.ts.map +1 -1
  2. package/dist/AppShell/AppShell.js +23 -3
  3. package/dist/Avatar/Avatar.d.ts.map +1 -1
  4. package/dist/Avatar/Avatar.js +1 -1
  5. package/dist/BottomSheet/BottomSheetPanel.d.ts.map +1 -1
  6. package/dist/BottomSheet/BottomSheetPanel.js +16 -9
  7. package/dist/Breadcrumbs/BreadcrumbItem.d.ts.map +1 -1
  8. package/dist/Breadcrumbs/BreadcrumbItem.js +2 -1
  9. package/dist/Button/Button.d.ts.map +1 -1
  10. package/dist/Button/Button.js +3 -2
  11. package/dist/Chat/ChatComposerInput.d.ts +9 -0
  12. package/dist/Chat/ChatComposerInput.d.ts.map +1 -1
  13. package/dist/Chat/ChatComposerInput.js +2 -0
  14. package/dist/Chat/ChatMessage.js +2 -2
  15. package/dist/Chat/chatMessage.vars.stylex.d.ts +8 -8
  16. package/dist/Chat/chatMessage.vars.stylex.js +8 -8
  17. package/dist/CommandPalette/CommandPaletteInput.d.ts.map +1 -1
  18. package/dist/CommandPalette/CommandPaletteInput.js +8 -1
  19. package/dist/DateInput/MonthScroller.d.ts.map +1 -1
  20. package/dist/DateInput/MonthScroller.js +72 -2
  21. package/dist/DateInput/Wheel.d.ts +17 -1
  22. package/dist/DateInput/Wheel.d.ts.map +1 -1
  23. package/dist/DateInput/Wheel.js +179 -19
  24. package/dist/DateRangeInput/DateRangeInput.d.ts.map +1 -1
  25. package/dist/DateRangeInput/DateRangeInput.js +63 -49
  26. package/dist/Dialog/Dialog.d.ts.map +1 -1
  27. package/dist/Dialog/Dialog.js +37 -1
  28. package/dist/Drawer/Drawer.d.ts.map +1 -1
  29. package/dist/Drawer/Drawer.js +6 -0
  30. package/dist/Drawer/useDrawerDialogPresence.d.ts.map +1 -1
  31. package/dist/Drawer/useDrawerDialogPresence.js +4 -0
  32. package/dist/DropdownMenu/DropdownMenu.d.ts.map +1 -1
  33. package/dist/DropdownMenu/DropdownMenu.js +20 -4
  34. package/dist/DropdownMenu/useMenuOverflow.d.ts +13 -3
  35. package/dist/DropdownMenu/useMenuOverflow.d.ts.map +1 -1
  36. package/dist/DropdownMenu/useMenuOverflow.js +31 -8
  37. package/dist/Field/PanelSearchInput.d.ts.map +1 -1
  38. package/dist/Field/PanelSearchInput.js +8 -1
  39. package/dist/Field/textEntryTraits.d.ts +6 -6
  40. package/dist/Field/textEntryTraits.js +6 -6
  41. package/dist/Layer/layerClickBoundary.d.ts +7 -1
  42. package/dist/Layer/layerClickBoundary.d.ts.map +1 -1
  43. package/dist/Layer/layerClickBoundary.js +2 -2
  44. package/dist/Layer/usePressPin.d.ts +95 -0
  45. package/dist/Layer/usePressPin.d.ts.map +1 -0
  46. package/dist/Layer/usePressPin.js +365 -0
  47. package/dist/Layer/useTouchTrigger.d.ts +23 -1
  48. package/dist/Layer/useTouchTrigger.d.ts.map +1 -1
  49. package/dist/Layer/useTouchTrigger.js +45 -7
  50. package/dist/Lightbox/Lightbox.d.ts.map +1 -1
  51. package/dist/Lightbox/Lightbox.js +2 -1
  52. package/dist/Link/Link.d.ts.map +1 -1
  53. package/dist/Link/Link.js +1 -0
  54. package/dist/Popover/usePopover.d.ts.map +1 -1
  55. package/dist/Popover/usePopover.js +56 -7
  56. package/dist/PowerSearch/PowerSearch.d.ts.map +1 -1
  57. package/dist/PowerSearch/PowerSearch.js +38 -30
  58. package/dist/ProgressBar/ProgressBar.d.ts +1 -1
  59. package/dist/ProgressBar/ProgressBar.d.ts.map +1 -1
  60. package/dist/ProgressBar/ProgressBar.js +52 -14
  61. package/dist/ProgressBar/ProgressBarTouch.d.ts +29 -0
  62. package/dist/ProgressBar/ProgressBarTouch.d.ts.map +1 -0
  63. package/dist/ProgressBar/ProgressBarTouch.js +91 -0
  64. package/dist/SegmentedControl/SegmentedControlItem.d.ts.map +1 -1
  65. package/dist/SegmentedControl/SegmentedControlItem.js +2 -1
  66. package/dist/Selector/Selector.d.ts.map +1 -1
  67. package/dist/Selector/Selector.js +25 -13
  68. package/dist/Slider/Slider.d.ts.map +1 -1
  69. package/dist/Slider/Slider.js +404 -131
  70. package/dist/Slider/sliderTouchController.d.ts +189 -0
  71. package/dist/Slider/sliderTouchController.d.ts.map +1 -0
  72. package/dist/Slider/sliderTouchController.js +1017 -0
  73. package/dist/Slider/useSliderTouch.d.ts +22 -0
  74. package/dist/Slider/useSliderTouch.d.ts.map +1 -0
  75. package/dist/Slider/useSliderTouch.js +56 -0
  76. package/dist/Switch/Switch.d.ts +1 -1
  77. package/dist/Switch/Switch.d.ts.map +1 -1
  78. package/dist/Switch/Switch.js +200 -46
  79. package/dist/Switch/switchFill.d.ts +31 -0
  80. package/dist/Switch/switchFill.d.ts.map +1 -0
  81. package/dist/Switch/switchFill.js +88 -0
  82. package/dist/Switch/switchTouch.d.ts +81 -0
  83. package/dist/Switch/switchTouch.d.ts.map +1 -0
  84. package/dist/Switch/switchTouch.js +133 -0
  85. package/dist/Switch/useSwitchTouch.d.ts +285 -0
  86. package/dist/Switch/useSwitchTouch.d.ts.map +1 -0
  87. package/dist/Switch/useSwitchTouch.js +998 -0
  88. package/dist/TabList/Tab.d.ts.map +1 -1
  89. package/dist/TabList/Tab.js +4 -3
  90. package/dist/Tokenizer/Tokenizer.d.ts.map +1 -1
  91. package/dist/Tokenizer/Tokenizer.js +12 -5
  92. package/dist/Tokenizer/TokenizerItemRemovableContext.d.ts +3 -0
  93. package/dist/Tokenizer/TokenizerItemRemovableContext.d.ts.map +1 -0
  94. package/dist/Tokenizer/TokenizerItemRemovableContext.js +17 -0
  95. package/dist/Tooltip/Tooltip.d.ts +30 -6
  96. package/dist/Tooltip/Tooltip.d.ts.map +1 -1
  97. package/dist/Tooltip/Tooltip.js +5 -0
  98. package/dist/Tooltip/index.d.ts +1 -1
  99. package/dist/Tooltip/index.d.ts.map +1 -1
  100. package/dist/Tooltip/useTooltip.d.ts +31 -5
  101. package/dist/Tooltip/useTooltip.d.ts.map +1 -1
  102. package/dist/Tooltip/useTooltip.js +59 -18
  103. package/dist/Typeahead/BaseTypeahead.d.ts.map +1 -1
  104. package/dist/Typeahead/BaseTypeahead.js +19 -9
  105. package/dist/Typeahead/Typeahead.d.ts.map +1 -1
  106. package/dist/Typeahead/Typeahead.js +26 -15
  107. package/dist/astryx.css +91 -8
  108. package/dist/gestures/GestureArena.d.ts +21 -2
  109. package/dist/gestures/GestureArena.d.ts.map +1 -1
  110. package/dist/gestures/GestureArena.js +23 -3
  111. package/dist/gestures/GestureHost.d.ts +123 -3
  112. package/dist/gestures/GestureHost.d.ts.map +1 -1
  113. package/dist/gestures/GestureHost.js +797 -15
  114. package/dist/gestures/GestureRecognizer.d.ts +15 -1
  115. package/dist/gestures/GestureRecognizer.d.ts.map +1 -1
  116. package/dist/gestures/GestureRecognizer.js +12 -0
  117. package/dist/gestures/PanGestureRecognizer.d.ts +8 -0
  118. package/dist/gestures/PanGestureRecognizer.d.ts.map +1 -1
  119. package/dist/gestures/PinchGestureRecognizer.d.ts +5 -1
  120. package/dist/gestures/PinchGestureRecognizer.d.ts.map +1 -1
  121. package/dist/gestures/PinchGestureRecognizer.js +10 -0
  122. package/dist/gestures/PressTracker.d.ts +6 -0
  123. package/dist/gestures/PressTracker.d.ts.map +1 -1
  124. package/dist/gestures/PressTracker.js +3 -0
  125. package/dist/gestures/ScreenEdgePanGestureRecognizer.d.ts +3 -3
  126. package/dist/gestures/ScreenEdgePanGestureRecognizer.d.ts.map +1 -1
  127. package/dist/gestures/ScreenEdgePanGestureRecognizer.js +7 -5
  128. package/dist/gestures/nativeScroll.d.ts +16 -2
  129. package/dist/gestures/nativeScroll.d.ts.map +1 -1
  130. package/dist/gestures/nativeScroll.js +39 -8
  131. package/dist/gestures/recognizerInternals.d.ts +4 -2
  132. package/dist/gestures/recognizerInternals.d.ts.map +1 -1
  133. package/dist/gestures/types.d.ts +17 -0
  134. package/dist/gestures/types.d.ts.map +1 -1
  135. package/dist/gestures/types.js +7 -0
  136. package/dist/gestures/usePressTracker.d.ts.map +1 -1
  137. package/dist/gestures/usePressTracker.js +1 -0
  138. package/dist/gestures/wheelSegmenter.d.ts +56 -0
  139. package/dist/gestures/wheelSegmenter.d.ts.map +1 -0
  140. package/dist/gestures/wheelSegmenter.js +122 -0
  141. package/dist/hooks/useAttachment.d.ts +16 -8
  142. package/dist/hooks/useAttachment.d.ts.map +1 -1
  143. package/dist/hooks/useAttachment.js +35 -15
  144. package/dist/hooks/useFocusTrap.d.ts +15 -0
  145. package/dist/hooks/useFocusTrap.d.ts.map +1 -1
  146. package/dist/hooks/useFocusTrap.js +13 -2
  147. package/dist/hooks/usePager.d.ts +261 -0
  148. package/dist/hooks/usePager.d.ts.map +1 -0
  149. package/dist/hooks/usePager.js +1169 -0
  150. package/dist/motion/animator.d.ts.map +1 -1
  151. package/dist/motion/animator.js +140 -19
  152. package/dist/motion/paging.d.ts +69 -0
  153. package/dist/motion/paging.d.ts.map +1 -0
  154. package/dist/motion/paging.js +148 -0
  155. package/dist/motion/uikit/index.d.ts +8 -4
  156. package/dist/motion/uikit/index.d.ts.map +1 -1
  157. package/dist/motion/uikit/index.js +8 -4
  158. package/dist/motion/uikit/paging.d.ts +171 -0
  159. package/dist/motion/uikit/paging.d.ts.map +1 -0
  160. package/dist/motion/uikit/paging.js +192 -0
  161. package/dist/motion/uikit/progressBar.d.ts +79 -0
  162. package/dist/motion/uikit/progressBar.d.ts.map +1 -0
  163. package/dist/motion/uikit/progressBar.js +102 -0
  164. package/dist/motion/uikit/scroll.d.ts +0 -19
  165. package/dist/motion/uikit/scroll.d.ts.map +1 -1
  166. package/dist/motion/uikit/scroll.js +2 -21
  167. package/dist/motion/uikit/slider.d.ts +97 -0
  168. package/dist/motion/uikit/slider.d.ts.map +1 -0
  169. package/dist/motion/uikit/slider.js +111 -0
  170. package/dist/motion/uikit/springs.d.ts +59 -30
  171. package/dist/motion/uikit/springs.d.ts.map +1 -1
  172. package/dist/motion/uikit/springs.js +64 -34
  173. package/dist/motion/uikit/switch.d.ts +166 -0
  174. package/dist/motion/uikit/switch.d.ts.map +1 -0
  175. package/dist/motion/uikit/switch.js +186 -0
  176. package/dist/privateAttributes/pressHoldsDrag.stylex.d.ts +18 -0
  177. package/dist/privateAttributes/pressHoldsDrag.stylex.d.ts.map +1 -0
  178. package/dist/privateAttributes/pressHoldsDrag.stylex.js +28 -0
  179. package/dist/utils/pressFeedback.d.ts.map +1 -1
  180. package/dist/utils/pressFeedback.js +5 -0
  181. package/dist/utils/selectionLock.d.ts +43 -0
  182. package/dist/utils/selectionLock.d.ts.map +1 -1
  183. package/dist/utils/selectionLock.js +394 -6
  184. package/package.json +5 -5
  185. package/src/AppShell/AppShell.doc.mjs +10 -0
  186. package/src/AppShell/AppShell.tsx +48 -2
  187. package/src/Avatar/Avatar.tsx +3 -1
  188. package/src/BottomSheet/BottomSheetPanel.tsx +16 -9
  189. package/src/Breadcrumbs/BreadcrumbItem.tsx +4 -1
  190. package/src/Button/Button.tsx +3 -2
  191. package/src/Chat/Chat.doc.mjs +1 -0
  192. package/src/Chat/ChatComposerInput.doc.mjs +11 -0
  193. package/src/Chat/ChatComposerInput.tsx +11 -0
  194. package/src/Chat/ChatMessage.tsx +2 -2
  195. package/src/Chat/chatMessage.vars.stylex.ts +8 -8
  196. package/src/CommandPalette/CommandPaletteInput.tsx +6 -0
  197. package/src/DateInput/MonthScroller.tsx +63 -5
  198. package/src/DateInput/Wheel.tsx +174 -14
  199. package/src/DateRangeInput/DateRangeInput.doc.mjs +3 -2
  200. package/src/DateRangeInput/DateRangeInput.tsx +117 -71
  201. package/src/Dialog/Dialog.tsx +37 -1
  202. package/src/Drawer/Drawer.tsx +6 -0
  203. package/src/Drawer/useDrawerDialogPresence.ts +4 -0
  204. package/src/DropdownMenu/DropdownMenu.tsx +28 -6
  205. package/src/DropdownMenu/useMenuOverflow.ts +44 -8
  206. package/src/Field/PanelSearchInput.tsx +6 -0
  207. package/src/Field/textEntryTraits.ts +6 -6
  208. package/src/Layer/layerClickBoundary.ts +2 -2
  209. package/src/Layer/usePressPin.ts +516 -0
  210. package/src/Layer/useTouchTrigger.ts +56 -6
  211. package/src/Lightbox/Lightbox.tsx +2 -1
  212. package/src/Link/Link.tsx +3 -0
  213. package/src/Popover/usePopover.tsx +71 -9
  214. package/src/PowerSearch/PowerSearch.tsx +38 -31
  215. package/src/ProgressBar/ProgressBar.doc.mjs +7 -5
  216. package/src/ProgressBar/ProgressBar.tsx +147 -16
  217. package/src/ProgressBar/ProgressBarTouch.ts +109 -0
  218. package/src/SegmentedControl/SegmentedControlItem.tsx +2 -1
  219. package/src/Selector/Selector.tsx +29 -2
  220. package/src/Slider/Slider.doc.mjs +11 -7
  221. package/src/Slider/Slider.tsx +539 -132
  222. package/src/Slider/sliderTouchController.ts +1209 -0
  223. package/src/Slider/useSliderTouch.ts +78 -0
  224. package/src/Switch/Switch.doc.mjs +3 -3
  225. package/src/Switch/Switch.tsx +412 -86
  226. package/src/Switch/switchFill.ts +106 -0
  227. package/src/Switch/switchTouch.ts +194 -0
  228. package/src/Switch/useSwitchTouch.ts +1121 -0
  229. package/src/TabList/Tab.tsx +5 -3
  230. package/src/Tokenizer/Tokenizer.tsx +15 -5
  231. package/src/Tokenizer/TokenizerItemRemovableContext.ts +22 -0
  232. package/src/Tooltip/Tooltip.doc.mjs +21 -6
  233. package/src/Tooltip/Tooltip.tsx +42 -5
  234. package/src/Tooltip/index.ts +1 -0
  235. package/src/Tooltip/useTooltip.doc.mjs +4 -2
  236. package/src/Tooltip/useTooltip.tsx +84 -21
  237. package/src/Typeahead/BaseTypeahead.tsx +16 -8
  238. package/src/Typeahead/Typeahead.tsx +29 -15
  239. package/src/gestures/GestureArena.ts +45 -4
  240. package/src/gestures/GestureHost.ts +958 -15
  241. package/src/gestures/GestureRecognizer.ts +28 -0
  242. package/src/gestures/PanGestureRecognizer.ts +8 -0
  243. package/src/gestures/PinchGestureRecognizer.ts +16 -1
  244. package/src/gestures/PressTracker.ts +10 -0
  245. package/src/gestures/README.md +82 -3
  246. package/src/gestures/ScreenEdgePanGestureRecognizer.ts +7 -5
  247. package/src/gestures/nativeScroll.ts +49 -9
  248. package/src/gestures/recognizerInternals.ts +9 -2
  249. package/src/gestures/types.ts +18 -0
  250. package/src/gestures/usePressTracker.ts +2 -0
  251. package/src/gestures/wheelSegmenter.ts +143 -0
  252. package/src/hooks/useAttachment.ts +56 -14
  253. package/src/hooks/useFocusTrap.ts +26 -2
  254. package/src/hooks/usePager.ts +1446 -0
  255. package/src/motion/MEASUREMENTS.md +36 -27
  256. package/src/motion/README.md +7 -3
  257. package/src/motion/animator.ts +193 -25
  258. package/src/motion/paging.ts +161 -0
  259. package/src/motion/uikit/index.ts +7 -4
  260. package/src/motion/uikit/paging.ts +193 -0
  261. package/src/motion/uikit/progressBar.ts +102 -0
  262. package/src/motion/uikit/scroll.ts +2 -18
  263. package/src/motion/uikit/slider.ts +105 -0
  264. package/src/motion/uikit/springs.ts +53 -32
  265. package/src/motion/uikit/switch.ts +174 -0
  266. package/src/privateAttributes/pressHoldsDrag.stylex.ts +28 -0
  267. package/src/utils/pressFeedback.ts +5 -0
  268. package/src/utils/selectionLock.ts +501 -6
  269. package/dist/motion/selectPage.d.ts +0 -26
  270. package/dist/motion/selectPage.d.ts.map +0 -1
  271. package/dist/motion/selectPage.js +0 -55
  272. package/src/motion/selectPage.ts +0 -55
@@ -0,0 +1,106 @@
1
+ // Copyright (c) Meta Platforms, Inc. and affiliates.
2
+
3
+ /**
4
+ * @file switchFill.ts
5
+ * @input Switch's track element and the props its other state renders with
6
+ * @output Exports TrackState, sameTrackState, trackStateOf, readInState and
7
+ * readFillOf: an element read in its other state, in place
8
+ * @position Shared by Switch.tsx and useSwitchTouch.ts for the colour fade
9
+ * under a finger
10
+ *
11
+ * The colour fade needs the track's fill in its other state, as the theme
12
+ * paints it. readFillOf swaps the track's class and attributes, reads the
13
+ * colour and swaps back in the same task, so nothing paints in between.
14
+ *
15
+ * SYNC: When modified, update Switch.tsx and useSwitchTouch.ts.
16
+ */
17
+
18
+ /** A track state: its class name and its data attributes. */
19
+ export interface TrackState {
20
+ readonly className: string;
21
+ readonly attributes: Readonly<Record<string, string>>;
22
+ }
23
+
24
+ /** Whether two track states render alike: the same class and attributes. */
25
+ export function sameTrackState(
26
+ a: TrackState | null,
27
+ b: TrackState | null,
28
+ ): boolean {
29
+ if (a === b) {
30
+ return true;
31
+ }
32
+ if (a == null || b == null || a.className !== b.className) {
33
+ return false;
34
+ }
35
+ const names = Object.keys(a.attributes);
36
+ return (
37
+ names.length === Object.keys(b.attributes).length &&
38
+ names.every(name => a.attributes[name] === b.attributes[name])
39
+ );
40
+ }
41
+
42
+ /** The track state of rendered props (`className` and `data-*` props). */
43
+ export function trackStateOf(props: object): TrackState {
44
+ const attributes: Record<string, string> = {};
45
+ let className = '';
46
+ for (const [name, value] of Object.entries(props)) {
47
+ if (name === 'className' && typeof value === 'string') {
48
+ className = value;
49
+ } else if (name.startsWith('data-') && value != null) {
50
+ // As React writes a data attribute: every value but null or undefined.
51
+ attributes[name] = String(value);
52
+ }
53
+ }
54
+ return {className, attributes};
55
+ }
56
+
57
+ /**
58
+ * Reads `element` as it renders in `state` (its class and data attributes),
59
+ * swapping them in and back in the same task, so nothing paints between.
60
+ */
61
+ export function readInState<T>(
62
+ element: HTMLElement,
63
+ state: TrackState,
64
+ read: (element: HTMLElement) => T,
65
+ ): T {
66
+ const names = new Set(Object.keys(state.attributes));
67
+ for (const attribute of Array.from(element.attributes)) {
68
+ if (attribute.name.startsWith('data-')) {
69
+ names.add(attribute.name);
70
+ }
71
+ }
72
+ const savedClass = element.className;
73
+ const saved = new Map<string, string | null>();
74
+ for (const name of names) {
75
+ saved.set(name, element.getAttribute(name));
76
+ }
77
+ const apply = (
78
+ className: string,
79
+ valueOf: (name: string) => string | null,
80
+ ) => {
81
+ element.className = className;
82
+ for (const name of names) {
83
+ const value = valueOf(name);
84
+ if (value == null) {
85
+ element.removeAttribute(name);
86
+ } else {
87
+ element.setAttribute(name, value);
88
+ }
89
+ }
90
+ };
91
+ apply(state.className, name => state.attributes[name] ?? null);
92
+ try {
93
+ return read(element);
94
+ } finally {
95
+ apply(savedClass, name => saved.get(name) ?? null);
96
+ }
97
+ }
98
+
99
+ /** The track's computed fill in `state`, read without a paint. */
100
+ export function readFillOf(track: HTMLElement, state: TrackState): string {
101
+ return readInState(
102
+ track,
103
+ state,
104
+ element => getComputedStyle(element).backgroundColor,
105
+ );
106
+ }
@@ -0,0 +1,194 @@
1
+ // Copyright (c) Meta Platforms, Inc. and affiliates.
2
+
3
+ /**
4
+ * @file switchTouch.ts
5
+ * @input The UIKit switch constants (motion/uikit/switch.ts) and a track size
6
+ * @output The pure model of Switch's touch presentation: thumb geometry, the
7
+ * drag's target, the flip rule, the commit on release and its click wait,
8
+ * and when the lifted thumb may settle
9
+ * @position Pure half of Switch's touch presentation; driven by
10
+ * useSwitchTouch.ts, tested by switchTouch.test.ts without a browser
11
+ *
12
+ * Positions are thumb offsets from the off end, 0 … `travel`, in the writing
13
+ * direction; the caller mirrors them for right-to-left.
14
+ * SYNC: When modified, update useSwitchTouch.ts and switchTouch.test.ts.
15
+ */
16
+
17
+ import {rubberBandClamp, rubberBandUnclamp} from '../motion/rubberBand';
18
+ import {switchControl} from '../motion/uikit/switch';
19
+
20
+ export interface SwitchTouchGeometry {
21
+ readonly trackWidth: number;
22
+ readonly trackHeight: number;
23
+ /** The thumb at rest, px. */
24
+ readonly thumbWidth: number;
25
+ readonly thumbHeight: number;
26
+ /** Gap between the thumb and the track's top, bottom and nearer end, px. */
27
+ readonly inset: number;
28
+ /** Offset of the thumb at the on end, px. */
29
+ readonly travel: number;
30
+ /**
31
+ * Scale of the lifted thumb, one value on both axes. It is UIKit's lift,
32
+ * capped so the thumb grows into at most half the gap on each side.
33
+ */
34
+ readonly liftScaleX: number;
35
+ readonly liftScaleY: number;
36
+ /**
37
+ * The drag's rubber-band dimension, px: UIKit's, scaled to the track. It
38
+ * never exceeds the gap the lift leaves (`inset` less the lifted growth).
39
+ * The band approaches its dimension and never reaches it, so a banded thumb
40
+ * stays inside the track.
41
+ */
42
+ readonly rubberBandDimension: number;
43
+ /** How far the finger goes toward the other end before a flip, px. */
44
+ readonly flipDistance: number;
45
+ }
46
+
47
+ const [UIKIT_TRACK_WIDTH, UIKIT_TRACK_HEIGHT] = switchControl.trackSize;
48
+ const [UIKIT_THUMB_WIDTH, UIKIT_THUMB_HEIGHT] = switchControl.thumbSize;
49
+ const [LIFTED_WIDTH, LIFTED_HEIGHT] = switchControl.liftedThumbSize;
50
+
51
+ /**
52
+ * The thumb geometry in a track of this size: the thumb's measured box when
53
+ * given, UIKit's proportions otherwise.
54
+ */
55
+ export function switchTouchGeometry(
56
+ trackWidth: number,
57
+ trackHeight: number,
58
+ thumb?: {readonly width: number; readonly height: number},
59
+ ): SwitchTouchGeometry {
60
+ const thumbHeight =
61
+ thumb?.height ?? (trackHeight * UIKIT_THUMB_HEIGHT) / UIKIT_TRACK_HEIGHT;
62
+ const thumbWidth =
63
+ thumb?.width ?? (trackWidth * UIKIT_THUMB_WIDTH) / UIKIT_TRACK_WIDTH;
64
+ const inset = Math.max(0, (trackHeight - thumbHeight) / 2);
65
+ // UIKit lifts to 58 × 38.3 from 37 × 24; here the lift fills at most half
66
+ // the gap on each side, on both axes alike.
67
+ const liftScale = Math.max(
68
+ 1,
69
+ Math.min(
70
+ LIFTED_WIDTH / UIKIT_THUMB_WIDTH,
71
+ LIFTED_HEIGHT / UIKIT_THUMB_HEIGHT,
72
+ thumbWidth > 0 ? 1 + inset / thumbWidth : 1,
73
+ thumbHeight > 0 ? 1 + inset / thumbHeight : 1,
74
+ ),
75
+ );
76
+ const liftGrowth = (thumbWidth * (liftScale - 1)) / 2;
77
+ return {
78
+ trackWidth,
79
+ trackHeight,
80
+ thumbWidth,
81
+ thumbHeight,
82
+ inset,
83
+ travel: Math.max(0, trackWidth - thumbWidth - 2 * inset),
84
+ liftScaleX: liftScale,
85
+ liftScaleY: liftScale,
86
+ rubberBandDimension: Math.max(
87
+ 0,
88
+ Math.min(
89
+ (switchControl.rubberBand.dimension * trackHeight) / UIKIT_TRACK_HEIGHT,
90
+ inset - liftGrowth,
91
+ ),
92
+ ),
93
+ flipDistance: Math.max(0, trackWidth - thumbWidth),
94
+ };
95
+ }
96
+
97
+ /**
98
+ * Where the drag puts the thumb's target. It is the offset at the landing,
99
+ * moved by the finger's translation and rubber-banded past either end.
100
+ *
101
+ * `start` is the thumb's offset on screen when the finger landed, mid-flight
102
+ * or banded. It is unbanded first, so a finger that grabs a moving thumb
103
+ * continues without a jump.
104
+ */
105
+ export function dragTarget(
106
+ start: number,
107
+ translation: number,
108
+ geometry: SwitchTouchGeometry,
109
+ ): number {
110
+ const {travel, rubberBandDimension} = geometry;
111
+ const coefficient = switchControl.rubberBand.coefficient;
112
+ const raw =
113
+ rubberBandUnclamp(start, 0, travel, rubberBandDimension, coefficient) +
114
+ translation;
115
+ return rubberBandClamp(raw, 0, travel, rubberBandDimension, coefficient);
116
+ }
117
+
118
+ /** A drag's flip state: the side it shows and how it got there. */
119
+ export interface SwitchFlip {
120
+ /** The value when the finger landed. */
121
+ readonly startedOn: boolean;
122
+ readonly isVisuallyOn: boolean;
123
+ /** The finger passed `flipDistance` on the last event: the next one flips. */
124
+ readonly isArmed: boolean;
125
+ /** The drag has flipped at least once. */
126
+ readonly didFlip: boolean;
127
+ }
128
+
129
+ export function startFlip(isOn: boolean): SwitchFlip {
130
+ return {startedOn: isOn, isVisuallyOn: isOn, isArmed: false, didFlip: false};
131
+ }
132
+
133
+ /**
134
+ * One touch event of the drag. `translation` is the finger's travel since it
135
+ * landed along the writing direction (positive toward the on end).
136
+ */
137
+ export function stepFlip(
138
+ flip: SwitchFlip,
139
+ translation: number,
140
+ geometry: SwitchTouchGeometry,
141
+ ): SwitchFlip {
142
+ // Travel toward the other end: right from off, left from on.
143
+ const toward = flip.startedOn ? -translation : translation;
144
+ if (flip.isVisuallyOn !== flip.startedOn) {
145
+ return toward < 0
146
+ ? {...flip, isVisuallyOn: flip.startedOn, isArmed: false}
147
+ : flip;
148
+ }
149
+ const isPast = toward >= geometry.flipDistance;
150
+ if (flip.isArmed && isPast) {
151
+ return {
152
+ ...flip,
153
+ isVisuallyOn: !flip.startedOn,
154
+ isArmed: false,
155
+ didFlip: true,
156
+ };
157
+ }
158
+ return isPast === flip.isArmed ? flip : {...flip, isArmed: isPast};
159
+ }
160
+
161
+ /**
162
+ * Passive: how long a lift waits for the browser's own click before the
163
+ * switch clicks its input itself, ms. The browser sends that click with the
164
+ * lift's `touchend`. The surface's `touch-action` leaves no double-tap delay.
165
+ * So this only runs out for a lift the browser does not count as a click.
166
+ */
167
+ export const BROWSER_CLICK_WAIT_MS = 300;
168
+
169
+ /**
170
+ * What a release commits: the side a drag flipped to; when nothing flipped,
171
+ * the other side of the value, wherever the finger lifts. A press slid off
172
+ * and lifted outside toggles too, as UISwitch's does. A toggle is
173
+ * reversible, so a stray release costs one more tap.
174
+ */
175
+ export function commitOnRelease(
176
+ flip: SwitchFlip | null,
177
+ isOn: boolean,
178
+ ): boolean {
179
+ return flip?.didFlip === true ? flip.isVisuallyOn : !isOn;
180
+ }
181
+
182
+ /**
183
+ * When the lifted thumb may settle, on the document timeline (ms). It is the
184
+ * release, but never sooner than the minimum lift time after the lift.
185
+ * A caller may pass the minimum it plays; the table's measured one by
186
+ * default.
187
+ */
188
+ export function settleTime(
189
+ releaseTime: number,
190
+ liftTime: number,
191
+ minimumLiftMs: number = switchControl.minimumLiftMs,
192
+ ): number {
193
+ return Math.max(releaseTime, liftTime + minimumLiftMs);
194
+ }