number-flow-react-native 0.1.0

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 (245) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +44 -0
  3. package/lib/module/core/constants.js +21 -0
  4. package/lib/module/core/constants.js.map +1 -0
  5. package/lib/module/core/intlHelpers.js +310 -0
  6. package/lib/module/core/intlHelpers.js.map +1 -0
  7. package/lib/module/core/layout.js +71 -0
  8. package/lib/module/core/layout.js.map +1 -0
  9. package/lib/module/core/mask.js +50 -0
  10. package/lib/module/core/mask.js.map +1 -0
  11. package/lib/module/core/numerals/detection.js +105 -0
  12. package/lib/module/core/numerals/detection.js.map +1 -0
  13. package/lib/module/core/numerals/digits.js +128 -0
  14. package/lib/module/core/numerals/digits.js.map +1 -0
  15. package/lib/module/core/numerals/index.js +5 -0
  16. package/lib/module/core/numerals/index.js.map +1 -0
  17. package/lib/module/core/numerals/tables.js +114 -0
  18. package/lib/module/core/numerals/tables.js.map +1 -0
  19. package/lib/module/core/superscript.js +31 -0
  20. package/lib/module/core/superscript.js.map +1 -0
  21. package/lib/module/core/timeLayout.js +98 -0
  22. package/lib/module/core/timeLayout.js.map +1 -0
  23. package/lib/module/core/timeTypes.js +4 -0
  24. package/lib/module/core/timeTypes.js.map +1 -0
  25. package/lib/module/core/timing.js +45 -0
  26. package/lib/module/core/timing.js.map +1 -0
  27. package/lib/module/core/types.js +58 -0
  28. package/lib/module/core/types.js.map +1 -0
  29. package/lib/module/core/useAccessibilityAnnouncement.js +27 -0
  30. package/lib/module/core/useAccessibilityAnnouncement.js.map +1 -0
  31. package/lib/module/core/useAnimatedX.js +25 -0
  32. package/lib/module/core/useAnimatedX.js.map +1 -0
  33. package/lib/module/core/useAnimationLifecycle.js +37 -0
  34. package/lib/module/core/useAnimationLifecycle.js.map +1 -0
  35. package/lib/module/core/useCanAnimate.js +22 -0
  36. package/lib/module/core/useCanAnimate.js.map +1 -0
  37. package/lib/module/core/useContinuousSpin.js +89 -0
  38. package/lib/module/core/useContinuousSpin.js.map +1 -0
  39. package/lib/module/core/useDebouncedWidths.js +74 -0
  40. package/lib/module/core/useDebouncedWidths.js.map +1 -0
  41. package/lib/module/core/useDigitAnimation.js +138 -0
  42. package/lib/module/core/useDigitAnimation.js.map +1 -0
  43. package/lib/module/core/useFlowPipeline.js +85 -0
  44. package/lib/module/core/useFlowPipeline.js.map +1 -0
  45. package/lib/module/core/useFormattedValue.js +28 -0
  46. package/lib/module/core/useFormattedValue.js.map +1 -0
  47. package/lib/module/core/useLayoutDiff.js +59 -0
  48. package/lib/module/core/useLayoutDiff.js.map +1 -0
  49. package/lib/module/core/useNumberFormatting.js +158 -0
  50. package/lib/module/core/useNumberFormatting.js.map +1 -0
  51. package/lib/module/core/useSlotOpacity.js +53 -0
  52. package/lib/module/core/useSlotOpacity.js.map +1 -0
  53. package/lib/module/core/useTimeFormatting.js +74 -0
  54. package/lib/module/core/useTimeFormatting.js.map +1 -0
  55. package/lib/module/core/useTimingResolution.js +21 -0
  56. package/lib/module/core/useTimingResolution.js.map +1 -0
  57. package/lib/module/core/useWorkletFormatting.js +49 -0
  58. package/lib/module/core/useWorkletFormatting.js.map +1 -0
  59. package/lib/module/core/utils.js +132 -0
  60. package/lib/module/core/utils.js.map +1 -0
  61. package/lib/module/core/warnings.js +10 -0
  62. package/lib/module/core/warnings.js.map +1 -0
  63. package/lib/module/index.js +7 -0
  64. package/lib/module/index.js.map +1 -0
  65. package/lib/module/native/DigitSlot.js +163 -0
  66. package/lib/module/native/DigitSlot.js.map +1 -0
  67. package/lib/module/native/NumberFlow.js +244 -0
  68. package/lib/module/native/NumberFlow.js.map +1 -0
  69. package/lib/module/native/SymbolSlot.js +52 -0
  70. package/lib/module/native/SymbolSlot.js.map +1 -0
  71. package/lib/module/native/TimeFlow.js +270 -0
  72. package/lib/module/native/TimeFlow.js.map +1 -0
  73. package/lib/module/native/index.js +5 -0
  74. package/lib/module/native/index.js.map +1 -0
  75. package/lib/module/native/renderSlots.js +108 -0
  76. package/lib/module/native/renderSlots.js.map +1 -0
  77. package/lib/module/native/types.js +4 -0
  78. package/lib/module/native/types.js.map +1 -0
  79. package/lib/module/native/useMeasuredGlyphMetrics.js +156 -0
  80. package/lib/module/native/useMeasuredGlyphMetrics.js.map +1 -0
  81. package/lib/module/package.json +1 -0
  82. package/lib/module/skia/DigitSlot.js +171 -0
  83. package/lib/module/skia/DigitSlot.js.map +1 -0
  84. package/lib/module/skia/SkiaNumberFlow.js +430 -0
  85. package/lib/module/skia/SkiaNumberFlow.js.map +1 -0
  86. package/lib/module/skia/SkiaTimeFlow.js +226 -0
  87. package/lib/module/skia/SkiaTimeFlow.js.map +1 -0
  88. package/lib/module/skia/SymbolSlot.js +92 -0
  89. package/lib/module/skia/SymbolSlot.js.map +1 -0
  90. package/lib/module/skia/index.js +6 -0
  91. package/lib/module/skia/index.js.map +1 -0
  92. package/lib/module/skia/renderSlots.js +131 -0
  93. package/lib/module/skia/renderSlots.js.map +1 -0
  94. package/lib/module/skia/useGlyphMetrics.js +72 -0
  95. package/lib/module/skia/useGlyphMetrics.js.map +1 -0
  96. package/lib/module/skia/useScrubbing.js +165 -0
  97. package/lib/module/skia/useScrubbing.js.map +1 -0
  98. package/lib/module/skia/useSkiaFont.js +23 -0
  99. package/lib/module/skia/useSkiaFont.js.map +1 -0
  100. package/lib/typescript/core/constants.d.ts +15 -0
  101. package/lib/typescript/core/constants.d.ts.map +1 -0
  102. package/lib/typescript/core/intlHelpers.d.ts +10 -0
  103. package/lib/typescript/core/intlHelpers.d.ts.map +1 -0
  104. package/lib/typescript/core/layout.d.ts +22 -0
  105. package/lib/typescript/core/layout.d.ts.map +1 -0
  106. package/lib/typescript/core/mask.d.ts +18 -0
  107. package/lib/typescript/core/mask.d.ts.map +1 -0
  108. package/lib/typescript/core/numerals/detection.d.ts +17 -0
  109. package/lib/typescript/core/numerals/detection.d.ts.map +1 -0
  110. package/lib/typescript/core/numerals/digits.d.ts +43 -0
  111. package/lib/typescript/core/numerals/digits.d.ts.map +1 -0
  112. package/lib/typescript/core/numerals/index.d.ts +3 -0
  113. package/lib/typescript/core/numerals/index.d.ts.map +1 -0
  114. package/lib/typescript/core/numerals/tables.d.ts +32 -0
  115. package/lib/typescript/core/numerals/tables.d.ts.map +1 -0
  116. package/lib/typescript/core/superscript.d.ts +16 -0
  117. package/lib/typescript/core/superscript.d.ts.map +1 -0
  118. package/lib/typescript/core/timeLayout.d.ts +19 -0
  119. package/lib/typescript/core/timeLayout.d.ts.map +1 -0
  120. package/lib/typescript/core/timeTypes.d.ts +80 -0
  121. package/lib/typescript/core/timeTypes.d.ts.map +1 -0
  122. package/lib/typescript/core/timing.d.ts +6 -0
  123. package/lib/typescript/core/timing.d.ts.map +1 -0
  124. package/lib/typescript/core/types.d.ts +165 -0
  125. package/lib/typescript/core/types.d.ts.map +1 -0
  126. package/lib/typescript/core/useAccessibilityAnnouncement.d.ts +10 -0
  127. package/lib/typescript/core/useAccessibilityAnnouncement.d.ts.map +1 -0
  128. package/lib/typescript/core/useAnimatedX.d.ts +9 -0
  129. package/lib/typescript/core/useAnimatedX.d.ts.map +1 -0
  130. package/lib/typescript/core/useAnimationLifecycle.d.ts +14 -0
  131. package/lib/typescript/core/useAnimationLifecycle.d.ts.map +1 -0
  132. package/lib/typescript/core/useCanAnimate.d.ts +14 -0
  133. package/lib/typescript/core/useCanAnimate.d.ts.map +1 -0
  134. package/lib/typescript/core/useContinuousSpin.d.ts +23 -0
  135. package/lib/typescript/core/useContinuousSpin.d.ts.map +1 -0
  136. package/lib/typescript/core/useDebouncedWidths.d.ts +17 -0
  137. package/lib/typescript/core/useDebouncedWidths.d.ts.map +1 -0
  138. package/lib/typescript/core/useDigitAnimation.d.ts +38 -0
  139. package/lib/typescript/core/useDigitAnimation.d.ts.map +1 -0
  140. package/lib/typescript/core/useFlowPipeline.d.ts +46 -0
  141. package/lib/typescript/core/useFlowPipeline.d.ts.map +1 -0
  142. package/lib/typescript/core/useFormattedValue.d.ts +14 -0
  143. package/lib/typescript/core/useFormattedValue.d.ts.map +1 -0
  144. package/lib/typescript/core/useLayoutDiff.d.ts +18 -0
  145. package/lib/typescript/core/useLayoutDiff.d.ts.map +1 -0
  146. package/lib/typescript/core/useNumberFormatting.d.ts +18 -0
  147. package/lib/typescript/core/useNumberFormatting.d.ts.map +1 -0
  148. package/lib/typescript/core/useSlotOpacity.d.ts +18 -0
  149. package/lib/typescript/core/useSlotOpacity.d.ts.map +1 -0
  150. package/lib/typescript/core/useTimeFormatting.d.ts +22 -0
  151. package/lib/typescript/core/useTimeFormatting.d.ts.map +1 -0
  152. package/lib/typescript/core/useTimingResolution.d.ts +13 -0
  153. package/lib/typescript/core/useTimingResolution.d.ts.map +1 -0
  154. package/lib/typescript/core/useWorkletFormatting.d.ts +14 -0
  155. package/lib/typescript/core/useWorkletFormatting.d.ts.map +1 -0
  156. package/lib/typescript/core/utils.d.ts +44 -0
  157. package/lib/typescript/core/utils.d.ts.map +1 -0
  158. package/lib/typescript/core/warnings.d.ts +2 -0
  159. package/lib/typescript/core/warnings.d.ts.map +1 -0
  160. package/lib/typescript/index.d.ts +8 -0
  161. package/lib/typescript/index.d.ts.map +1 -0
  162. package/lib/typescript/native/DigitSlot.d.ts +27 -0
  163. package/lib/typescript/native/DigitSlot.d.ts.map +1 -0
  164. package/lib/typescript/native/NumberFlow.d.ts +3 -0
  165. package/lib/typescript/native/NumberFlow.d.ts.map +1 -0
  166. package/lib/typescript/native/SymbolSlot.d.ts +19 -0
  167. package/lib/typescript/native/SymbolSlot.d.ts.map +1 -0
  168. package/lib/typescript/native/TimeFlow.d.ts +3 -0
  169. package/lib/typescript/native/TimeFlow.d.ts.map +1 -0
  170. package/lib/typescript/native/index.d.ts +3 -0
  171. package/lib/typescript/native/index.d.ts.map +1 -0
  172. package/lib/typescript/native/renderSlots.d.ts +31 -0
  173. package/lib/typescript/native/renderSlots.d.ts.map +1 -0
  174. package/lib/typescript/native/types.d.ts +36 -0
  175. package/lib/typescript/native/types.d.ts.map +1 -0
  176. package/lib/typescript/native/useMeasuredGlyphMetrics.d.ts +8 -0
  177. package/lib/typescript/native/useMeasuredGlyphMetrics.d.ts.map +1 -0
  178. package/lib/typescript/package.json +1 -0
  179. package/lib/typescript/skia/DigitSlot.d.ts +35 -0
  180. package/lib/typescript/skia/DigitSlot.d.ts.map +1 -0
  181. package/lib/typescript/skia/SkiaNumberFlow.d.ts +3 -0
  182. package/lib/typescript/skia/SkiaNumberFlow.d.ts.map +1 -0
  183. package/lib/typescript/skia/SkiaTimeFlow.d.ts +3 -0
  184. package/lib/typescript/skia/SkiaTimeFlow.d.ts.map +1 -0
  185. package/lib/typescript/skia/SymbolSlot.d.ts +26 -0
  186. package/lib/typescript/skia/SymbolSlot.d.ts.map +1 -0
  187. package/lib/typescript/skia/index.d.ts +6 -0
  188. package/lib/typescript/skia/index.d.ts.map +1 -0
  189. package/lib/typescript/skia/renderSlots.d.ts +40 -0
  190. package/lib/typescript/skia/renderSlots.d.ts.map +1 -0
  191. package/lib/typescript/skia/useGlyphMetrics.d.ts +16 -0
  192. package/lib/typescript/skia/useGlyphMetrics.d.ts.map +1 -0
  193. package/lib/typescript/skia/useScrubbing.d.ts +59 -0
  194. package/lib/typescript/skia/useScrubbing.d.ts.map +1 -0
  195. package/lib/typescript/skia/useSkiaFont.d.ts +13 -0
  196. package/lib/typescript/skia/useSkiaFont.d.ts.map +1 -0
  197. package/package.json +104 -0
  198. package/src/core/constants.ts +20 -0
  199. package/src/core/intlHelpers.ts +351 -0
  200. package/src/core/layout.ts +108 -0
  201. package/src/core/mask.ts +72 -0
  202. package/src/core/numerals/detection.ts +112 -0
  203. package/src/core/numerals/digits.ts +102 -0
  204. package/src/core/numerals/index.ts +9 -0
  205. package/src/core/numerals/tables.ts +112 -0
  206. package/src/core/superscript.ts +27 -0
  207. package/src/core/timeLayout.ts +119 -0
  208. package/src/core/timeTypes.ts +88 -0
  209. package/src/core/timing.ts +60 -0
  210. package/src/core/types.ts +189 -0
  211. package/src/core/useAccessibilityAnnouncement.ts +27 -0
  212. package/src/core/useAnimatedX.ts +30 -0
  213. package/src/core/useAnimationLifecycle.ts +54 -0
  214. package/src/core/useCanAnimate.ts +21 -0
  215. package/src/core/useContinuousSpin.ts +112 -0
  216. package/src/core/useDebouncedWidths.ts +93 -0
  217. package/src/core/useDigitAnimation.ts +192 -0
  218. package/src/core/useFlowPipeline.ts +126 -0
  219. package/src/core/useFormattedValue.ts +32 -0
  220. package/src/core/useLayoutDiff.ts +71 -0
  221. package/src/core/useNumberFormatting.ts +164 -0
  222. package/src/core/useSlotOpacity.ts +66 -0
  223. package/src/core/useTimeFormatting.ts +95 -0
  224. package/src/core/useTimingResolution.ts +47 -0
  225. package/src/core/useWorkletFormatting.ts +59 -0
  226. package/src/core/utils.ts +149 -0
  227. package/src/core/warnings.ts +8 -0
  228. package/src/index.ts +15 -0
  229. package/src/native/DigitSlot.tsx +203 -0
  230. package/src/native/NumberFlow.tsx +287 -0
  231. package/src/native/SymbolSlot.tsx +68 -0
  232. package/src/native/TimeFlow.tsx +287 -0
  233. package/src/native/index.ts +2 -0
  234. package/src/native/renderSlots.tsx +150 -0
  235. package/src/native/types.ts +40 -0
  236. package/src/native/useMeasuredGlyphMetrics.tsx +205 -0
  237. package/src/skia/DigitSlot.tsx +221 -0
  238. package/src/skia/SkiaNumberFlow.tsx +506 -0
  239. package/src/skia/SkiaTimeFlow.tsx +257 -0
  240. package/src/skia/SymbolSlot.tsx +120 -0
  241. package/src/skia/index.ts +5 -0
  242. package/src/skia/renderSlots.tsx +180 -0
  243. package/src/skia/useGlyphMetrics.ts +79 -0
  244. package/src/skia/useScrubbing.ts +223 -0
  245. package/src/skia/useSkiaFont.ts +25 -0
@@ -0,0 +1,22 @@
1
+ "use strict";
2
+
3
+ import { useReducedMotion } from "react-native-reanimated";
4
+
5
+ /**
6
+ * Returns whether NumberFlow animations are currently enabled.
7
+ *
8
+ * Use this to conditionally render UI based on animation support:
9
+ * ```tsx
10
+ * const canAnimate = useCanAnimate();
11
+ * return canAnimate ? <NumberFlow value={42} /> : <Text>42</Text>;
12
+ * ```
13
+ *
14
+ * When `respectMotionPreference` is true (default), returns false
15
+ * if the device's "Reduce Motion" accessibility setting is on.
16
+ */
17
+ export function useCanAnimate(respectMotionPreference = true) {
18
+ const reducedMotion = useReducedMotion();
19
+ if (!respectMotionPreference) return true;
20
+ return !reducedMotion;
21
+ }
22
+ //# sourceMappingURL=useCanAnimate.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":["useReducedMotion","useCanAnimate","respectMotionPreference","reducedMotion"],"sourceRoot":"../../../src","sources":["core/useCanAnimate.ts"],"mappings":";;AAAA,SAASA,gBAAgB,QAAQ,yBAAyB;;AAE1D;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,OAAO,SAASC,aAAaA,CAACC,uBAAuB,GAAG,IAAI,EAAW;EACrE,MAAMC,aAAa,GAAGH,gBAAgB,CAAC,CAAC;EAExC,IAAI,CAACE,uBAAuB,EAAE,OAAO,IAAI;EAEzC,OAAO,CAACC,aAAa;AACvB","ignoreList":[]}
@@ -0,0 +1,89 @@
1
+ "use strict";
2
+
3
+ import { useRef } from "react";
4
+ import { parseDigitPosition } from "./utils.js";
5
+
6
+ /**
7
+ * Pure algorithm: given previous and current keyed parts, determines which
8
+ * unchanged lower-significance digits should do a full-wheel continuous spin.
9
+ *
10
+ * Returns a new Map with incremented generation counters for those digits.
11
+ * The generation counter is what triggers the spin animation in useDigitAnimation.
12
+ */
13
+ export function computeContinuousGenerations(prevParts, currentParts, prevGenerations) {
14
+ // Build lookup of previous digit values by key
15
+ const prevDigits = new Map();
16
+ for (const part of prevParts) {
17
+ if (part.type === "digit") {
18
+ prevDigits.set(part.key, part.digitValue);
19
+ }
20
+ }
21
+
22
+ // Find the highest-significance position where the digit value changed
23
+ let maxChangedPos = -Infinity;
24
+ for (const part of currentParts) {
25
+ if (part.type !== "digit") continue;
26
+ const pos = parseDigitPosition(part.key);
27
+ if (pos === undefined) continue;
28
+ const prevValue = prevDigits.get(part.key);
29
+ const changed = prevValue !== undefined && prevValue !== part.digitValue;
30
+ if (changed && pos > maxChangedPos) {
31
+ maxChangedPos = pos;
32
+ }
33
+ }
34
+
35
+ // No digit changed — nothing to spin
36
+ if (maxChangedPos === -Infinity) return prevGenerations;
37
+
38
+ /**
39
+ * Increment the generation counter for each unchanged digit whose
40
+ * significance is lower than the most-significant changed digit.
41
+ * Only digits that existed in the previous render qualify — entering
42
+ * digits have no previous value and can't be "unchanged".
43
+ */
44
+ const nextGenerations = new Map(prevGenerations);
45
+ for (const part of currentParts) {
46
+ if (part.type !== "digit") continue;
47
+ const pos = parseDigitPosition(part.key);
48
+ if (pos === undefined || pos >= maxChangedPos) continue;
49
+ const prevValue = prevDigits.get(part.key);
50
+ const unchanged = prevValue !== undefined && prevValue === part.digitValue;
51
+ if (unchanged) {
52
+ const prev = nextGenerations.get(part.key) ?? 0;
53
+ nextGenerations.set(part.key, prev + 1);
54
+ }
55
+ }
56
+ return nextGenerations;
57
+ }
58
+
59
+ /**
60
+ * Tracks which digits need a full-wheel continuous spin.
61
+ *
62
+ * When `continuous` is enabled, unchanged lower-significance digits spin
63
+ * through a complete cycle alongside higher-significance digits that changed.
64
+ * For example, 100 -> 200 with trend=1 makes ones and tens both do a
65
+ * full upward rotation even though their values didn't change.
66
+ *
67
+ * Returns a Map<key, generation> where generation increments each time
68
+ * a digit should perform a continuous spin. Returns undefined when
69
+ * continuous is disabled (zero overhead path).
70
+ */
71
+ export function useContinuousSpin(keyedParts, continuous, trend) {
72
+ const prevPartsRef = useRef([]);
73
+ const generationsRef = useRef(new Map());
74
+ if (!continuous) {
75
+ prevPartsRef.current = keyedParts;
76
+ return undefined;
77
+ }
78
+ const prevParts = prevPartsRef.current;
79
+ prevPartsRef.current = keyedParts;
80
+
81
+ // First render — nothing to compare against
82
+ if (prevParts.length === 0) return generationsRef.current;
83
+
84
+ // Shortest-path trend defeats the purpose of continuous spin
85
+ if (trend === 0) return generationsRef.current;
86
+ generationsRef.current = computeContinuousGenerations(prevParts, keyedParts, generationsRef.current);
87
+ return generationsRef.current;
88
+ }
89
+ //# sourceMappingURL=useContinuousSpin.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":["useRef","parseDigitPosition","computeContinuousGenerations","prevParts","currentParts","prevGenerations","prevDigits","Map","part","type","set","key","digitValue","maxChangedPos","Infinity","pos","undefined","prevValue","get","changed","nextGenerations","unchanged","prev","useContinuousSpin","keyedParts","continuous","trend","prevPartsRef","generationsRef","current","length"],"sourceRoot":"../../../src","sources":["core/useContinuousSpin.ts"],"mappings":"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","ignoreList":[]}
@@ -0,0 +1,74 @@
1
+ "use strict";
2
+
3
+ import { useState } from "react";
4
+ import { makeMutable, useAnimatedReaction, withTiming } from "react-native-reanimated";
5
+ import { MAX_SLOTS } from "./constants.js";
6
+ import { localeDigitValue } from "./numerals/index.js";
7
+ const WIDTH_ANIM_MS = 200;
8
+
9
+ /**
10
+ * Creates a pool of SharedValue<number> that hold digit widths for worklet layout.
11
+ *
12
+ * **Tabular mode during scrubbing**: While sharedValue is active (scrubbing),
13
+ * all digits use a fixed width (scrubDigitWidth) — this eliminates jitter entirely
14
+ * because all digits occupy the same width regardless of which digit (0-9) is displayed.
15
+ * Only digits are affected; symbols (like `.`) keep their natural width.
16
+ *
17
+ * **Proportional mode when idle**: When scrubbing ends (sharedValue becomes
18
+ * empty), widths animate to proportional values for natural typography.
19
+ *
20
+ * This approach gives the best of both worlds: stable layout during rapid
21
+ * scrubbing, and beautiful proportional spacing for static display.
22
+ */
23
+ export function useDebouncedWidths(digitWidths, scrubDigitWidth, sharedValue, prefix, suffix, zeroCodePoint = 48) {
24
+ const [debouncedWidths] = useState(() => Array.from({
25
+ length: MAX_SLOTS
26
+ }, () => makeMutable(-1)));
27
+ const [prevDigits] = useState(() => Array.from({
28
+ length: MAX_SLOTS
29
+ }, () => makeMutable(-1)));
30
+ const [wasActive] = useState(() => makeMutable(false));
31
+ useAnimatedReaction(() => sharedValue?.value ?? "", (current, previous) => {
32
+ if (current === previous) return;
33
+ if (!digitWidths) return;
34
+ if (!current) {
35
+ // Scrubbing ended — animate to proportional widths
36
+ if (wasActive.value) {
37
+ wasActive.value = false;
38
+ for (let i = 0; i < MAX_SLOTS; i++) {
39
+ const prevDv = prevDigits[i].value;
40
+ if (prevDv >= 0) {
41
+ const proportionalWidth = digitWidths[prevDv];
42
+ debouncedWidths[i].value = withTiming(proportionalWidth, {
43
+ duration: WIDTH_ANIM_MS
44
+ });
45
+ } else {
46
+ debouncedWidths[i].value = -1;
47
+ }
48
+ prevDigits[i].value = -1;
49
+ }
50
+ }
51
+ return;
52
+ }
53
+ const isFirstActivation = !wasActive.value;
54
+ if (isFirstActivation) wasActive.value = true;
55
+ const fullText = prefix + current + suffix;
56
+ const len = fullText.length;
57
+ let digitIndex = 0;
58
+ for (let i = 0; i < len && digitIndex < MAX_SLOTS; i++) {
59
+ const code = fullText.charCodeAt(i);
60
+ const dv = localeDigitValue(code, zeroCodePoint);
61
+ if (dv >= 0) {
62
+ prevDigits[digitIndex].value = dv;
63
+ debouncedWidths[digitIndex].value = scrubDigitWidth;
64
+ digitIndex++;
65
+ }
66
+ }
67
+ for (let i = digitIndex; i < MAX_SLOTS; i++) {
68
+ if (debouncedWidths[i].value !== -1) debouncedWidths[i].value = -1;
69
+ prevDigits[i].value = -1;
70
+ }
71
+ }, [prefix, suffix, digitWidths, scrubDigitWidth, zeroCodePoint]);
72
+ return debouncedWidths;
73
+ }
74
+ //# sourceMappingURL=useDebouncedWidths.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":["useState","makeMutable","useAnimatedReaction","withTiming","MAX_SLOTS","localeDigitValue","WIDTH_ANIM_MS","useDebouncedWidths","digitWidths","scrubDigitWidth","sharedValue","prefix","suffix","zeroCodePoint","debouncedWidths","Array","from","length","prevDigits","wasActive","value","current","previous","i","prevDv","proportionalWidth","duration","isFirstActivation","fullText","len","digitIndex","code","charCodeAt","dv"],"sourceRoot":"../../../src","sources":["core/useDebouncedWidths.ts"],"mappings":"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","ignoreList":[]}
@@ -0,0 +1,138 @@
1
+ "use strict";
2
+
3
+ import { useCallback, useLayoutEffect, useRef, useState } from "react";
4
+ import { makeMutable, runOnJS, useAnimatedReaction, withTiming } from "react-native-reanimated";
5
+ import { DIGIT_COUNT } from "./constants.js";
6
+ import { useSlotOpacity } from "./useSlotOpacity.js";
7
+ import { computeRollDelta } from "./utils.js";
8
+
9
+ /**
10
+ * We use makeMutable (via useState) instead of useSharedValue because
11
+ * useSharedValue's cleanup calls cancelAnimation, which kills in-flight
12
+ * animations when the component re-renders in StrictMode.
13
+ */
14
+
15
+ /**
16
+ * Manages the digit rolling state machine: delta tracking, exit animations,
17
+ * prop-driven digit changes, and worklet-driven digit updates.
18
+ *
19
+ * Each renderer creates its own format-specific Y transforms and position
20
+ * reaction that reads animDelta + currentDigitSV from this hook.
21
+ */
22
+ export function useDigitAnimation({
23
+ digitValue,
24
+ entering,
25
+ exiting,
26
+ trend,
27
+ spinTiming,
28
+ opacityTiming,
29
+ exitKey,
30
+ onExitComplete,
31
+ workletDigitValue,
32
+ digitCount,
33
+ continuousSpinGeneration
34
+ }) {
35
+ const resolvedDigitCount = digitCount ?? DIGIT_COUNT;
36
+ const initialDigit = entering ? 0 : digitValue;
37
+ const prevDigitRef = useRef(initialDigit);
38
+
39
+ /**
40
+ * animDelta starts at the computed roll distance and animates toward 0.
41
+ * The per-digit position reaction computes c = currentDigit - animDelta
42
+ * and uses mod-10 arithmetic to position each digit individually.
43
+ */
44
+ const [animDelta] = useState(() => makeMutable(0));
45
+ const [currentDigitSV] = useState(() => makeMutable(initialDigit));
46
+ const handleExitingStart = useCallback(() => {
47
+ if (prevDigitRef.current !== 0) {
48
+ const delta = computeRollDelta(prevDigitRef.current, 0, trend, resolvedDigitCount);
49
+ prevDigitRef.current = 0;
50
+ currentDigitSV.value = 0;
51
+ animDelta.value = delta;
52
+ animDelta.value = withTiming(0, {
53
+ duration: spinTiming.duration,
54
+ easing: spinTiming.easing
55
+ });
56
+ }
57
+ }, [trend, spinTiming, animDelta, currentDigitSV, resolvedDigitCount]);
58
+ const slotOpacity = useSlotOpacity({
59
+ entering,
60
+ exiting,
61
+ opacityTiming,
62
+ exitKey,
63
+ onExitComplete,
64
+ onExitingStart: handleExitingStart
65
+ });
66
+ useLayoutEffect(() => {
67
+ const workletActive = workletDigitValue !== undefined && workletDigitValue.value >= 0;
68
+ if (!exiting && !workletActive && prevDigitRef.current !== digitValue) {
69
+ const delta = computeRollDelta(prevDigitRef.current, digitValue, trend, resolvedDigitCount);
70
+ prevDigitRef.current = digitValue;
71
+ currentDigitSV.value = digitValue;
72
+ animDelta.value = delta;
73
+ animDelta.value = withTiming(0, {
74
+ duration: spinTiming.duration,
75
+ easing: spinTiming.easing
76
+ });
77
+ }
78
+ }, [digitValue, exiting, workletDigitValue, trend, spinTiming, animDelta, currentDigitSV, resolvedDigitCount]);
79
+
80
+ /**
81
+ * Continuous spin: when the generation counter increments, this digit's
82
+ * value didn't change but a higher-significance digit did. Perform a
83
+ * full-wheel rotation so the digit appears to "carry" through.
84
+ *
85
+ * Example: 100 → 200 with trend=1 — the ones digit (0→0) spins through
86
+ * all 10 values upward while the hundreds digit rolls 1→2 normally.
87
+ */
88
+ const prevSpinGenRef = useRef(continuousSpinGeneration ?? 0);
89
+ useLayoutEffect(() => {
90
+ const currentGen = continuousSpinGeneration ?? 0;
91
+
92
+ // Generation unchanged — no continuous spin needed
93
+ if (currentGen === prevSpinGenRef.current) return;
94
+ prevSpinGenRef.current = currentGen;
95
+
96
+ // Don't spin digits that are entering or exiting — they animate via opacity
97
+ if (exiting || entering) return;
98
+
99
+ // Full wheel rotation: e.g. 10 * 1 = spin up 10, or 6 * -1 = spin down 6 (for s10)
100
+ const delta = resolvedDigitCount * trend;
101
+ if (delta === 0) return;
102
+
103
+ // Accumulate onto any in-flight animation, then ease back to 0
104
+ animDelta.value = animDelta.value + delta;
105
+ animDelta.value = withTiming(0, {
106
+ duration: spinTiming.duration,
107
+ easing: spinTiming.easing
108
+ });
109
+ }, [continuousSpinGeneration, exiting, entering, trend, spinTiming, resolvedDigitCount, animDelta]);
110
+ const syncFromWorklet = useCallback(digit => {
111
+ prevDigitRef.current = digit;
112
+ }, []);
113
+ useAnimatedReaction(() => workletDigitValue?.value ?? -1, (current, previous) => {
114
+ if (current < 0 || current === previous) return;
115
+ const prev = currentDigitSV.value;
116
+ if (prev === current) return;
117
+ const delta = computeRollDelta(prev, current, trend, resolvedDigitCount);
118
+ currentDigitSV.value = current;
119
+
120
+ /**
121
+ * Accumulate remaining animation delta (composite: 'accumulate').
122
+ * Safe to read animDelta.value here — we're on the UI thread.
123
+ */
124
+ animDelta.value = animDelta.value + delta;
125
+ animDelta.value = withTiming(0, {
126
+ duration: spinTiming.duration,
127
+ easing: spinTiming.easing
128
+ });
129
+ runOnJS(syncFromWorklet)(current);
130
+ }, [workletDigitValue, spinTiming, trend]);
131
+ return {
132
+ initialDigit,
133
+ animDelta,
134
+ currentDigitSV,
135
+ slotOpacity
136
+ };
137
+ }
138
+ //# sourceMappingURL=useDigitAnimation.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":["useCallback","useLayoutEffect","useRef","useState","makeMutable","runOnJS","useAnimatedReaction","withTiming","DIGIT_COUNT","useSlotOpacity","computeRollDelta","useDigitAnimation","digitValue","entering","exiting","trend","spinTiming","opacityTiming","exitKey","onExitComplete","workletDigitValue","digitCount","continuousSpinGeneration","resolvedDigitCount","initialDigit","prevDigitRef","animDelta","currentDigitSV","handleExitingStart","current","delta","value","duration","easing","slotOpacity","onExitingStart","workletActive","undefined","prevSpinGenRef","currentGen","syncFromWorklet","digit","previous","prev"],"sourceRoot":"../../../src","sources":["core/useDigitAnimation.ts"],"mappings":"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","ignoreList":[]}
@@ -0,0 +1,85 @@
1
+ "use strict";
2
+
3
+ import { useMemo, useRef } from "react";
4
+ import { computeAdaptiveMaskHeights } from "./mask.js";
5
+ import { useAnimationLifecycle } from "./useAnimationLifecycle.js";
6
+ import { useContinuousSpin } from "./useContinuousSpin.js";
7
+ import { useLayoutDiff } from "./useLayoutDiff.js";
8
+ import { useTimingResolution } from "./useTimingResolution.js";
9
+ import { resolveTrend } from "./utils.js";
10
+ const ZERO_MASK = {
11
+ top: 0,
12
+ bottom: 0,
13
+ expansionTop: 0,
14
+ expansionBottom: 0
15
+ };
16
+
17
+ /**
18
+ * Shared data pipeline for all Flow components (NumberFlow, TimeFlow,
19
+ * SkiaNumberFlow, SkiaTimeFlow).
20
+ *
21
+ * Handles: timing resolution, trend tracking, continuous spin,
22
+ * animation lifecycle, layout diffing, accessibility label,
23
+ * and adaptive mask computation.
24
+ *
25
+ * Layout computation is left to callers because Skia components
26
+ * have additional sharedValue-driven layout paths.
27
+ */
28
+ export function useFlowPipeline(input) {
29
+ // 1. Timing resolution
30
+ const {
31
+ resolvedSpinTiming,
32
+ resolvedOpacityTiming,
33
+ resolvedTransformTiming
34
+ } = useTimingResolution(input.animated, input.respectMotionPreference, input.spinTiming, input.opacityTiming, input.transformTiming);
35
+
36
+ // 2. Trend tracking
37
+ const prevValueRef = useRef(input.trendValue);
38
+ const resolvedTrend = resolveTrend(input.trend, prevValueRef.current, input.trendValue);
39
+ prevValueRef.current = input.trendValue;
40
+
41
+ // 3. Continuous spin
42
+ const spinGenerations = useContinuousSpin(input.keyedParts, input.continuous, resolvedTrend);
43
+
44
+ // 4. Animation lifecycle
45
+ useAnimationLifecycle(input.layout, {
46
+ spin: resolvedSpinTiming,
47
+ opacity: resolvedOpacityTiming,
48
+ transform: resolvedTransformTiming
49
+ }, input.onAnimationsStart, input.onAnimationsFinish);
50
+
51
+ // 5. Layout diff
52
+ const {
53
+ prevMap,
54
+ isInitialRender,
55
+ exitingEntries,
56
+ onExitComplete
57
+ } = useLayoutDiff(input.layout);
58
+
59
+ // 6. Accessibility label
60
+ const accessibilityLabel = useMemo(() => {
61
+ if (input.keyedParts.length === 0) return undefined;
62
+ return input.keyedParts.map(p => p.char).join("");
63
+ }, [input.keyedParts]);
64
+
65
+ // 7. Adaptive mask
66
+ const resolvedMask = input.mask ?? true;
67
+ const adaptiveMask = useMemo(() => {
68
+ if (!input.metrics || !resolvedMask) return ZERO_MASK;
69
+ return computeAdaptiveMaskHeights(input.layout, exitingEntries, input.metrics);
70
+ }, [input.metrics, resolvedMask, input.layout, exitingEntries]);
71
+ return {
72
+ resolvedSpinTiming,
73
+ resolvedOpacityTiming,
74
+ resolvedTransformTiming,
75
+ resolvedTrend,
76
+ spinGenerations,
77
+ prevMap,
78
+ isInitialRender,
79
+ exitingEntries,
80
+ onExitComplete,
81
+ accessibilityLabel,
82
+ adaptiveMask
83
+ };
84
+ }
85
+ //# sourceMappingURL=useFlowPipeline.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":["useMemo","useRef","computeAdaptiveMaskHeights","useAnimationLifecycle","useContinuousSpin","useLayoutDiff","useTimingResolution","resolveTrend","ZERO_MASK","top","bottom","expansionTop","expansionBottom","useFlowPipeline","input","resolvedSpinTiming","resolvedOpacityTiming","resolvedTransformTiming","animated","respectMotionPreference","spinTiming","opacityTiming","transformTiming","prevValueRef","trendValue","resolvedTrend","trend","current","spinGenerations","keyedParts","continuous","layout","spin","opacity","transform","onAnimationsStart","onAnimationsFinish","prevMap","isInitialRender","exitingEntries","onExitComplete","accessibilityLabel","length","undefined","map","p","char","join","resolvedMask","mask","adaptiveMask","metrics"],"sourceRoot":"../../../src","sources":["core/useFlowPipeline.ts"],"mappings":";;AAAA,SAASA,OAAO,EAAEC,MAAM,QAAQ,OAAO;AAEvC,SAASC,0BAA0B,QAA0B,WAAQ;AAErE,SAASC,qBAAqB,QAAQ,4BAAyB;AAC/D,SAASC,iBAAiB,QAAQ,wBAAqB;AACvD,SAASC,aAAa,QAAQ,oBAAiB;AAC/C,SAASC,mBAAmB,QAAQ,0BAAuB;AAC3D,SAASC,YAAY,QAAQ,YAAS;AA8CtC,MAAMC,SAAsB,GAAG;EAAEC,GAAG,EAAE,CAAC;EAAEC,MAAM,EAAE,CAAC;EAAEC,YAAY,EAAE,CAAC;EAAEC,eAAe,EAAE;AAAE,CAAC;;AAEzF;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,OAAO,SAASC,eAAeA,CAACC,KAAwB,EAAsB;EAC5E;EACA,MAAM;IAAEC,kBAAkB;IAAEC,qBAAqB;IAAEC;EAAwB,CAAC,GAC1EX,mBAAmB,CACjBQ,KAAK,CAACI,QAAQ,EACdJ,KAAK,CAACK,uBAAuB,EAC7BL,KAAK,CAACM,UAAU,EAChBN,KAAK,CAACO,aAAa,EACnBP,KAAK,CAACQ,eACR,CAAC;;EAEH;EACA,MAAMC,YAAY,GAAGtB,MAAM,CAAqBa,KAAK,CAACU,UAAU,CAAC;EACjE,MAAMC,aAAa,GAAGlB,YAAY,CAACO,KAAK,CAACY,KAAK,EAAEH,YAAY,CAACI,OAAO,EAAEb,KAAK,CAACU,UAAU,CAAC;EACvFD,YAAY,CAACI,OAAO,GAAGb,KAAK,CAACU,UAAU;;EAEvC;EACA,MAAMI,eAAe,GAAGxB,iBAAiB,CAACU,KAAK,CAACe,UAAU,EAAEf,KAAK,CAACgB,UAAU,EAAEL,aAAa,CAAC;;EAE5F;EACAtB,qBAAqB,CACnBW,KAAK,CAACiB,MAAM,EACZ;IAAEC,IAAI,EAAEjB,kBAAkB;IAAEkB,OAAO,EAAEjB,qBAAqB;IAAEkB,SAAS,EAAEjB;EAAwB,CAAC,EAChGH,KAAK,CAACqB,iBAAiB,EACvBrB,KAAK,CAACsB,kBACR,CAAC;;EAED;EACA,MAAM;IAAEC,OAAO;IAAEC,eAAe;IAAEC,cAAc;IAAEC;EAAe,CAAC,GAAGnC,aAAa,CAACS,KAAK,CAACiB,MAAM,CAAC;;EAEhG;EACA,MAAMU,kBAAkB,GAAGzC,OAAO,CAAC,MAAM;IACvC,IAAIc,KAAK,CAACe,UAAU,CAACa,MAAM,KAAK,CAAC,EAAE,OAAOC,SAAS;IAEnD,OAAO7B,KAAK,CAACe,UAAU,CAACe,GAAG,CAAEC,CAAC,IAAKA,CAAC,CAACC,IAAI,CAAC,CAACC,IAAI,CAAC,EAAE,CAAC;EACrD,CAAC,EAAE,CAACjC,KAAK,CAACe,UAAU,CAAC,CAAC;;EAEtB;EACA,MAAMmB,YAAY,GAAGlC,KAAK,CAACmC,IAAI,IAAI,IAAI;EACvC,MAAMC,YAAY,GAAGlD,OAAO,CAAC,MAAM;IACjC,IAAI,CAACc,KAAK,CAACqC,OAAO,IAAI,CAACH,YAAY,EAAE,OAAOxC,SAAS;IAErD,OAAON,0BAA0B,CAACY,KAAK,CAACiB,MAAM,EAAEQ,cAAc,EAAEzB,KAAK,CAACqC,OAAO,CAAC;EAChF,CAAC,EAAE,CAACrC,KAAK,CAACqC,OAAO,EAAEH,YAAY,EAAElC,KAAK,CAACiB,MAAM,EAAEQ,cAAc,CAAC,CAAC;EAE/D,OAAO;IACLxB,kBAAkB;IAClBC,qBAAqB;IACrBC,uBAAuB;IACvBQ,aAAa;IACbG,eAAe;IACfS,OAAO;IACPC,eAAe;IACfC,cAAc;IACdC,cAAc;IACdC,kBAAkB;IAClBS;EACF,CAAC;AACH","ignoreList":[]}
@@ -0,0 +1,28 @@
1
+ "use strict";
2
+
3
+ import { useMemo } from "react";
4
+ import { getOrCreateFormatter } from "./intlHelpers.js";
5
+
6
+ /**
7
+ * Formats a numeric value to a display string using Intl.NumberFormat, with optional prefix/suffix.
8
+ * Useful for providing an accessibility label on a parent Canvas for Skia components:
9
+ *
10
+ * ```tsx
11
+ * const label = useFormattedValue(value, { style: "currency", currency: "USD" });
12
+ *
13
+ * <Canvas accessible accessibilityLabel={label}>
14
+ * <SkiaNumberFlow value={value} font={font} format={{ style: "currency", currency: "USD" }} />
15
+ * </Canvas>
16
+ * ```
17
+ */
18
+ export function useFormattedValue(value, format, locales, prefix, suffix) {
19
+ // Serialize format/locales to a stable string — avoids re-runs when callers pass inline objects
20
+ const formatKey = useMemo(() => JSON.stringify([locales, format]), [locales, format]);
21
+ return useMemo(() => {
22
+ if (value === undefined) return undefined;
23
+ const formatter = getOrCreateFormatter(locales, format);
24
+ return `${prefix ?? ""}${formatter.format(value)}${suffix ?? ""}`;
25
+ // eslint-disable-next-line react-hooks/exhaustive-deps
26
+ }, [value, prefix, suffix, formatKey]);
27
+ }
28
+ //# sourceMappingURL=useFormattedValue.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":["useMemo","getOrCreateFormatter","useFormattedValue","value","format","locales","prefix","suffix","formatKey","JSON","stringify","undefined","formatter"],"sourceRoot":"../../../src","sources":["core/useFormattedValue.ts"],"mappings":";;AAAA,SAASA,OAAO,QAAQ,OAAO;AAC/B,SAASC,oBAAoB,QAAQ,kBAAe;;AAEpD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,OAAO,SAASC,iBAAiBA,CAC/BC,KAAyB,EACzBC,MAAiC,EACjCC,OAA8B,EAC9BC,MAAe,EACfC,MAAe,EACK;EACpB;EACA,MAAMC,SAAS,GAAGR,OAAO,CAAC,MAAMS,IAAI,CAACC,SAAS,CAAC,CAACL,OAAO,EAAED,MAAM,CAAC,CAAC,EAAE,CAACC,OAAO,EAAED,MAAM,CAAC,CAAC;EAErF,OAAOJ,OAAO,CAAC,MAAM;IACnB,IAAIG,KAAK,KAAKQ,SAAS,EAAE,OAAOA,SAAS;IACzC,MAAMC,SAAS,GAAGX,oBAAoB,CAACI,OAAO,EAAED,MAAM,CAAC;IACvD,OAAO,GAAGE,MAAM,IAAI,EAAE,GAAGM,SAAS,CAACR,MAAM,CAACD,KAAK,CAAC,GAAGI,MAAM,IAAI,EAAE,EAAE;IACjE;EACF,CAAC,EAAE,CAACJ,KAAK,EAAEG,MAAM,EAAEC,MAAM,EAAEC,SAAS,CAAC,CAAC;AACxC","ignoreList":[]}
@@ -0,0 +1,59 @@
1
+ "use strict";
2
+
3
+ import { useCallback, useReducer, useRef } from "react";
4
+ /**
5
+ * Manages enter/exit tracking for layout transitions. Diffs the current
6
+ * layout against the previous one and tracks exiting entries until their
7
+ * animations complete.
8
+ *
9
+ * The diff logic runs during render (not in useEffect) using a ref-based
10
+ * idempotent pattern for StrictMode safety.
11
+ */
12
+ export function useLayoutDiff(layout) {
13
+ const prevLayoutRef = useRef([]);
14
+ const exitingRef = useRef(new Map());
15
+ const [, forceUpdate] = useReducer(n => n + 1, 0);
16
+ const isFirstLayoutRef = useRef(true);
17
+ const lastDiffIdRef = useRef("");
18
+ const diffResultRef = useRef({
19
+ prevMap: new Map(),
20
+ isInitialRender: true
21
+ });
22
+ const onExitComplete = useCallback(key => {
23
+ exitingRef.current.delete(key);
24
+ forceUpdate();
25
+ }, []);
26
+
27
+ // Stable layout identity — fast string concat instead of map+join
28
+ let layoutId = "";
29
+ for (const s of layout) {
30
+ layoutId += `${s.key}:${s.digitValue}|`;
31
+ }
32
+ if (layoutId !== lastDiffIdRef.current) {
33
+ lastDiffIdRef.current = layoutId;
34
+ const currentKeys = new Set(layout.map(s => s.key));
35
+ const prevMap = new Map(prevLayoutRef.current.map(s => [s.key, s]));
36
+ for (const prev of prevLayoutRef.current) {
37
+ if (!currentKeys.has(prev.key) && !exitingRef.current.has(prev.key)) {
38
+ exitingRef.current.set(prev.key, prev);
39
+ }
40
+ }
41
+ for (const key of currentKeys) {
42
+ exitingRef.current.delete(key);
43
+ }
44
+ const isInitialRender = isFirstLayoutRef.current;
45
+ if (layout.length > 0) isFirstLayoutRef.current = false;
46
+ diffResultRef.current = {
47
+ prevMap,
48
+ isInitialRender
49
+ };
50
+ prevLayoutRef.current = layout;
51
+ }
52
+ return {
53
+ prevMap: diffResultRef.current.prevMap,
54
+ isInitialRender: diffResultRef.current.isInitialRender,
55
+ exitingEntries: exitingRef.current,
56
+ onExitComplete
57
+ };
58
+ }
59
+ //# sourceMappingURL=useLayoutDiff.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":["useCallback","useReducer","useRef","useLayoutDiff","layout","prevLayoutRef","exitingRef","Map","forceUpdate","n","isFirstLayoutRef","lastDiffIdRef","diffResultRef","prevMap","isInitialRender","onExitComplete","key","current","delete","layoutId","s","digitValue","currentKeys","Set","map","prev","has","set","length","exitingEntries"],"sourceRoot":"../../../src","sources":["core/useLayoutDiff.ts"],"mappings":";;AAAA,SAASA,WAAW,EAAEC,UAAU,EAAEC,MAAM,QAAQ,OAAO;AAUvD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,OAAO,SAASC,aAAaA,CAACC,MAAoB,EAAoB;EACpE,MAAMC,aAAa,GAAGH,MAAM,CAAe,EAAE,CAAC;EAC9C,MAAMI,UAAU,GAAGJ,MAAM,CAA0B,IAAIK,GAAG,CAAC,CAAC,CAAC;EAC7D,MAAM,GAAGC,WAAW,CAAC,GAAGP,UAAU,CAAEQ,CAAS,IAAKA,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;EAC3D,MAAMC,gBAAgB,GAAGR,MAAM,CAAC,IAAI,CAAC;EAErC,MAAMS,aAAa,GAAGT,MAAM,CAAC,EAAE,CAAC;EAChC,MAAMU,aAAa,GAAGV,MAAM,CAGzB;IAAEW,OAAO,EAAE,IAAIN,GAAG,CAAC,CAAC;IAAEO,eAAe,EAAE;EAAK,CAAC,CAAC;EAEjD,MAAMC,cAAc,GAAGf,WAAW,CAAEgB,GAAW,IAAK;IAClDV,UAAU,CAACW,OAAO,CAACC,MAAM,CAACF,GAAG,CAAC;IAC9BR,WAAW,CAAC,CAAC;EACf,CAAC,EAAE,EAAE,CAAC;;EAEN;EACA,IAAIW,QAAQ,GAAG,EAAE;EACjB,KAAK,MAAMC,CAAC,IAAIhB,MAAM,EAAE;IACtBe,QAAQ,IAAI,GAAGC,CAAC,CAACJ,GAAG,IAAII,CAAC,CAACC,UAAU,GAAG;EACzC;EAEA,IAAIF,QAAQ,KAAKR,aAAa,CAACM,OAAO,EAAE;IACtCN,aAAa,CAACM,OAAO,GAAGE,QAAQ;IAEhC,MAAMG,WAAW,GAAG,IAAIC,GAAG,CAACnB,MAAM,CAACoB,GAAG,CAAEJ,CAAC,IAAKA,CAAC,CAACJ,GAAG,CAAC,CAAC;IACrD,MAAMH,OAAO,GAAG,IAAIN,GAAG,CAACF,aAAa,CAACY,OAAO,CAACO,GAAG,CAAEJ,CAAC,IAAK,CAACA,CAAC,CAACJ,GAAG,EAAEI,CAAC,CAAC,CAAC,CAAC;IAErE,KAAK,MAAMK,IAAI,IAAIpB,aAAa,CAACY,OAAO,EAAE;MACxC,IAAI,CAACK,WAAW,CAACI,GAAG,CAACD,IAAI,CAACT,GAAG,CAAC,IAAI,CAACV,UAAU,CAACW,OAAO,CAACS,GAAG,CAACD,IAAI,CAACT,GAAG,CAAC,EAAE;QACnEV,UAAU,CAACW,OAAO,CAACU,GAAG,CAACF,IAAI,CAACT,GAAG,EAAES,IAAI,CAAC;MACxC;IACF;IAEA,KAAK,MAAMT,GAAG,IAAIM,WAAW,EAAE;MAC7BhB,UAAU,CAACW,OAAO,CAACC,MAAM,CAACF,GAAG,CAAC;IAChC;IAEA,MAAMF,eAAe,GAAGJ,gBAAgB,CAACO,OAAO;IAChD,IAAIb,MAAM,CAACwB,MAAM,GAAG,CAAC,EAAElB,gBAAgB,CAACO,OAAO,GAAG,KAAK;IAEvDL,aAAa,CAACK,OAAO,GAAG;MAAEJ,OAAO;MAAEC;IAAgB,CAAC;IACpDT,aAAa,CAACY,OAAO,GAAGb,MAAM;EAChC;EAEA,OAAO;IACLS,OAAO,EAAED,aAAa,CAACK,OAAO,CAACJ,OAAO;IACtCC,eAAe,EAAEF,aAAa,CAACK,OAAO,CAACH,eAAe;IACtDe,cAAc,EAAEvB,UAAU,CAACW,OAAO;IAClCF;EACF,CAAC;AACH","ignoreList":[]}