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.
- package/LICENSE +21 -0
- package/README.md +44 -0
- package/lib/module/core/constants.js +21 -0
- package/lib/module/core/constants.js.map +1 -0
- package/lib/module/core/intlHelpers.js +310 -0
- package/lib/module/core/intlHelpers.js.map +1 -0
- package/lib/module/core/layout.js +71 -0
- package/lib/module/core/layout.js.map +1 -0
- package/lib/module/core/mask.js +50 -0
- package/lib/module/core/mask.js.map +1 -0
- package/lib/module/core/numerals/detection.js +105 -0
- package/lib/module/core/numerals/detection.js.map +1 -0
- package/lib/module/core/numerals/digits.js +128 -0
- package/lib/module/core/numerals/digits.js.map +1 -0
- package/lib/module/core/numerals/index.js +5 -0
- package/lib/module/core/numerals/index.js.map +1 -0
- package/lib/module/core/numerals/tables.js +114 -0
- package/lib/module/core/numerals/tables.js.map +1 -0
- package/lib/module/core/superscript.js +31 -0
- package/lib/module/core/superscript.js.map +1 -0
- package/lib/module/core/timeLayout.js +98 -0
- package/lib/module/core/timeLayout.js.map +1 -0
- package/lib/module/core/timeTypes.js +4 -0
- package/lib/module/core/timeTypes.js.map +1 -0
- package/lib/module/core/timing.js +45 -0
- package/lib/module/core/timing.js.map +1 -0
- package/lib/module/core/types.js +58 -0
- package/lib/module/core/types.js.map +1 -0
- package/lib/module/core/useAccessibilityAnnouncement.js +27 -0
- package/lib/module/core/useAccessibilityAnnouncement.js.map +1 -0
- package/lib/module/core/useAnimatedX.js +25 -0
- package/lib/module/core/useAnimatedX.js.map +1 -0
- package/lib/module/core/useAnimationLifecycle.js +37 -0
- package/lib/module/core/useAnimationLifecycle.js.map +1 -0
- package/lib/module/core/useCanAnimate.js +22 -0
- package/lib/module/core/useCanAnimate.js.map +1 -0
- package/lib/module/core/useContinuousSpin.js +89 -0
- package/lib/module/core/useContinuousSpin.js.map +1 -0
- package/lib/module/core/useDebouncedWidths.js +74 -0
- package/lib/module/core/useDebouncedWidths.js.map +1 -0
- package/lib/module/core/useDigitAnimation.js +138 -0
- package/lib/module/core/useDigitAnimation.js.map +1 -0
- package/lib/module/core/useFlowPipeline.js +85 -0
- package/lib/module/core/useFlowPipeline.js.map +1 -0
- package/lib/module/core/useFormattedValue.js +28 -0
- package/lib/module/core/useFormattedValue.js.map +1 -0
- package/lib/module/core/useLayoutDiff.js +59 -0
- package/lib/module/core/useLayoutDiff.js.map +1 -0
- package/lib/module/core/useNumberFormatting.js +158 -0
- package/lib/module/core/useNumberFormatting.js.map +1 -0
- package/lib/module/core/useSlotOpacity.js +53 -0
- package/lib/module/core/useSlotOpacity.js.map +1 -0
- package/lib/module/core/useTimeFormatting.js +74 -0
- package/lib/module/core/useTimeFormatting.js.map +1 -0
- package/lib/module/core/useTimingResolution.js +21 -0
- package/lib/module/core/useTimingResolution.js.map +1 -0
- package/lib/module/core/useWorkletFormatting.js +49 -0
- package/lib/module/core/useWorkletFormatting.js.map +1 -0
- package/lib/module/core/utils.js +132 -0
- package/lib/module/core/utils.js.map +1 -0
- package/lib/module/core/warnings.js +10 -0
- package/lib/module/core/warnings.js.map +1 -0
- package/lib/module/index.js +7 -0
- package/lib/module/index.js.map +1 -0
- package/lib/module/native/DigitSlot.js +163 -0
- package/lib/module/native/DigitSlot.js.map +1 -0
- package/lib/module/native/NumberFlow.js +244 -0
- package/lib/module/native/NumberFlow.js.map +1 -0
- package/lib/module/native/SymbolSlot.js +52 -0
- package/lib/module/native/SymbolSlot.js.map +1 -0
- package/lib/module/native/TimeFlow.js +270 -0
- package/lib/module/native/TimeFlow.js.map +1 -0
- package/lib/module/native/index.js +5 -0
- package/lib/module/native/index.js.map +1 -0
- package/lib/module/native/renderSlots.js +108 -0
- package/lib/module/native/renderSlots.js.map +1 -0
- package/lib/module/native/types.js +4 -0
- package/lib/module/native/types.js.map +1 -0
- package/lib/module/native/useMeasuredGlyphMetrics.js +156 -0
- package/lib/module/native/useMeasuredGlyphMetrics.js.map +1 -0
- package/lib/module/package.json +1 -0
- package/lib/module/skia/DigitSlot.js +171 -0
- package/lib/module/skia/DigitSlot.js.map +1 -0
- package/lib/module/skia/SkiaNumberFlow.js +430 -0
- package/lib/module/skia/SkiaNumberFlow.js.map +1 -0
- package/lib/module/skia/SkiaTimeFlow.js +226 -0
- package/lib/module/skia/SkiaTimeFlow.js.map +1 -0
- package/lib/module/skia/SymbolSlot.js +92 -0
- package/lib/module/skia/SymbolSlot.js.map +1 -0
- package/lib/module/skia/index.js +6 -0
- package/lib/module/skia/index.js.map +1 -0
- package/lib/module/skia/renderSlots.js +131 -0
- package/lib/module/skia/renderSlots.js.map +1 -0
- package/lib/module/skia/useGlyphMetrics.js +72 -0
- package/lib/module/skia/useGlyphMetrics.js.map +1 -0
- package/lib/module/skia/useScrubbing.js +165 -0
- package/lib/module/skia/useScrubbing.js.map +1 -0
- package/lib/module/skia/useSkiaFont.js +23 -0
- package/lib/module/skia/useSkiaFont.js.map +1 -0
- package/lib/typescript/core/constants.d.ts +15 -0
- package/lib/typescript/core/constants.d.ts.map +1 -0
- package/lib/typescript/core/intlHelpers.d.ts +10 -0
- package/lib/typescript/core/intlHelpers.d.ts.map +1 -0
- package/lib/typescript/core/layout.d.ts +22 -0
- package/lib/typescript/core/layout.d.ts.map +1 -0
- package/lib/typescript/core/mask.d.ts +18 -0
- package/lib/typescript/core/mask.d.ts.map +1 -0
- package/lib/typescript/core/numerals/detection.d.ts +17 -0
- package/lib/typescript/core/numerals/detection.d.ts.map +1 -0
- package/lib/typescript/core/numerals/digits.d.ts +43 -0
- package/lib/typescript/core/numerals/digits.d.ts.map +1 -0
- package/lib/typescript/core/numerals/index.d.ts +3 -0
- package/lib/typescript/core/numerals/index.d.ts.map +1 -0
- package/lib/typescript/core/numerals/tables.d.ts +32 -0
- package/lib/typescript/core/numerals/tables.d.ts.map +1 -0
- package/lib/typescript/core/superscript.d.ts +16 -0
- package/lib/typescript/core/superscript.d.ts.map +1 -0
- package/lib/typescript/core/timeLayout.d.ts +19 -0
- package/lib/typescript/core/timeLayout.d.ts.map +1 -0
- package/lib/typescript/core/timeTypes.d.ts +80 -0
- package/lib/typescript/core/timeTypes.d.ts.map +1 -0
- package/lib/typescript/core/timing.d.ts +6 -0
- package/lib/typescript/core/timing.d.ts.map +1 -0
- package/lib/typescript/core/types.d.ts +165 -0
- package/lib/typescript/core/types.d.ts.map +1 -0
- package/lib/typescript/core/useAccessibilityAnnouncement.d.ts +10 -0
- package/lib/typescript/core/useAccessibilityAnnouncement.d.ts.map +1 -0
- package/lib/typescript/core/useAnimatedX.d.ts +9 -0
- package/lib/typescript/core/useAnimatedX.d.ts.map +1 -0
- package/lib/typescript/core/useAnimationLifecycle.d.ts +14 -0
- package/lib/typescript/core/useAnimationLifecycle.d.ts.map +1 -0
- package/lib/typescript/core/useCanAnimate.d.ts +14 -0
- package/lib/typescript/core/useCanAnimate.d.ts.map +1 -0
- package/lib/typescript/core/useContinuousSpin.d.ts +23 -0
- package/lib/typescript/core/useContinuousSpin.d.ts.map +1 -0
- package/lib/typescript/core/useDebouncedWidths.d.ts +17 -0
- package/lib/typescript/core/useDebouncedWidths.d.ts.map +1 -0
- package/lib/typescript/core/useDigitAnimation.d.ts +38 -0
- package/lib/typescript/core/useDigitAnimation.d.ts.map +1 -0
- package/lib/typescript/core/useFlowPipeline.d.ts +46 -0
- package/lib/typescript/core/useFlowPipeline.d.ts.map +1 -0
- package/lib/typescript/core/useFormattedValue.d.ts +14 -0
- package/lib/typescript/core/useFormattedValue.d.ts.map +1 -0
- package/lib/typescript/core/useLayoutDiff.d.ts +18 -0
- package/lib/typescript/core/useLayoutDiff.d.ts.map +1 -0
- package/lib/typescript/core/useNumberFormatting.d.ts +18 -0
- package/lib/typescript/core/useNumberFormatting.d.ts.map +1 -0
- package/lib/typescript/core/useSlotOpacity.d.ts +18 -0
- package/lib/typescript/core/useSlotOpacity.d.ts.map +1 -0
- package/lib/typescript/core/useTimeFormatting.d.ts +22 -0
- package/lib/typescript/core/useTimeFormatting.d.ts.map +1 -0
- package/lib/typescript/core/useTimingResolution.d.ts +13 -0
- package/lib/typescript/core/useTimingResolution.d.ts.map +1 -0
- package/lib/typescript/core/useWorkletFormatting.d.ts +14 -0
- package/lib/typescript/core/useWorkletFormatting.d.ts.map +1 -0
- package/lib/typescript/core/utils.d.ts +44 -0
- package/lib/typescript/core/utils.d.ts.map +1 -0
- package/lib/typescript/core/warnings.d.ts +2 -0
- package/lib/typescript/core/warnings.d.ts.map +1 -0
- package/lib/typescript/index.d.ts +8 -0
- package/lib/typescript/index.d.ts.map +1 -0
- package/lib/typescript/native/DigitSlot.d.ts +27 -0
- package/lib/typescript/native/DigitSlot.d.ts.map +1 -0
- package/lib/typescript/native/NumberFlow.d.ts +3 -0
- package/lib/typescript/native/NumberFlow.d.ts.map +1 -0
- package/lib/typescript/native/SymbolSlot.d.ts +19 -0
- package/lib/typescript/native/SymbolSlot.d.ts.map +1 -0
- package/lib/typescript/native/TimeFlow.d.ts +3 -0
- package/lib/typescript/native/TimeFlow.d.ts.map +1 -0
- package/lib/typescript/native/index.d.ts +3 -0
- package/lib/typescript/native/index.d.ts.map +1 -0
- package/lib/typescript/native/renderSlots.d.ts +31 -0
- package/lib/typescript/native/renderSlots.d.ts.map +1 -0
- package/lib/typescript/native/types.d.ts +36 -0
- package/lib/typescript/native/types.d.ts.map +1 -0
- package/lib/typescript/native/useMeasuredGlyphMetrics.d.ts +8 -0
- package/lib/typescript/native/useMeasuredGlyphMetrics.d.ts.map +1 -0
- package/lib/typescript/package.json +1 -0
- package/lib/typescript/skia/DigitSlot.d.ts +35 -0
- package/lib/typescript/skia/DigitSlot.d.ts.map +1 -0
- package/lib/typescript/skia/SkiaNumberFlow.d.ts +3 -0
- package/lib/typescript/skia/SkiaNumberFlow.d.ts.map +1 -0
- package/lib/typescript/skia/SkiaTimeFlow.d.ts +3 -0
- package/lib/typescript/skia/SkiaTimeFlow.d.ts.map +1 -0
- package/lib/typescript/skia/SymbolSlot.d.ts +26 -0
- package/lib/typescript/skia/SymbolSlot.d.ts.map +1 -0
- package/lib/typescript/skia/index.d.ts +6 -0
- package/lib/typescript/skia/index.d.ts.map +1 -0
- package/lib/typescript/skia/renderSlots.d.ts +40 -0
- package/lib/typescript/skia/renderSlots.d.ts.map +1 -0
- package/lib/typescript/skia/useGlyphMetrics.d.ts +16 -0
- package/lib/typescript/skia/useGlyphMetrics.d.ts.map +1 -0
- package/lib/typescript/skia/useScrubbing.d.ts +59 -0
- package/lib/typescript/skia/useScrubbing.d.ts.map +1 -0
- package/lib/typescript/skia/useSkiaFont.d.ts +13 -0
- package/lib/typescript/skia/useSkiaFont.d.ts.map +1 -0
- package/package.json +104 -0
- package/src/core/constants.ts +20 -0
- package/src/core/intlHelpers.ts +351 -0
- package/src/core/layout.ts +108 -0
- package/src/core/mask.ts +72 -0
- package/src/core/numerals/detection.ts +112 -0
- package/src/core/numerals/digits.ts +102 -0
- package/src/core/numerals/index.ts +9 -0
- package/src/core/numerals/tables.ts +112 -0
- package/src/core/superscript.ts +27 -0
- package/src/core/timeLayout.ts +119 -0
- package/src/core/timeTypes.ts +88 -0
- package/src/core/timing.ts +60 -0
- package/src/core/types.ts +189 -0
- package/src/core/useAccessibilityAnnouncement.ts +27 -0
- package/src/core/useAnimatedX.ts +30 -0
- package/src/core/useAnimationLifecycle.ts +54 -0
- package/src/core/useCanAnimate.ts +21 -0
- package/src/core/useContinuousSpin.ts +112 -0
- package/src/core/useDebouncedWidths.ts +93 -0
- package/src/core/useDigitAnimation.ts +192 -0
- package/src/core/useFlowPipeline.ts +126 -0
- package/src/core/useFormattedValue.ts +32 -0
- package/src/core/useLayoutDiff.ts +71 -0
- package/src/core/useNumberFormatting.ts +164 -0
- package/src/core/useSlotOpacity.ts +66 -0
- package/src/core/useTimeFormatting.ts +95 -0
- package/src/core/useTimingResolution.ts +47 -0
- package/src/core/useWorkletFormatting.ts +59 -0
- package/src/core/utils.ts +149 -0
- package/src/core/warnings.ts +8 -0
- package/src/index.ts +15 -0
- package/src/native/DigitSlot.tsx +203 -0
- package/src/native/NumberFlow.tsx +287 -0
- package/src/native/SymbolSlot.tsx +68 -0
- package/src/native/TimeFlow.tsx +287 -0
- package/src/native/index.ts +2 -0
- package/src/native/renderSlots.tsx +150 -0
- package/src/native/types.ts +40 -0
- package/src/native/useMeasuredGlyphMetrics.tsx +205 -0
- package/src/skia/DigitSlot.tsx +221 -0
- package/src/skia/SkiaNumberFlow.tsx +506 -0
- package/src/skia/SkiaTimeFlow.tsx +257 -0
- package/src/skia/SymbolSlot.tsx +120 -0
- package/src/skia/index.ts +5 -0
- package/src/skia/renderSlots.tsx +180 -0
- package/src/skia/useGlyphMetrics.ts +79 -0
- package/src/skia/useScrubbing.ts +223 -0
- package/src/skia/useSkiaFont.ts +25 -0
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
import { HANIDEC_DIGITS, LATIN_ZERO, ZERO_CODEPOINTS } from "./tables";
|
|
2
|
+
|
|
3
|
+
const digitStringsCache = new Map<string, string[]>();
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Returns the numeric value (0-9) of a hanidec character code,
|
|
7
|
+
* or -1 if the code is not a hanidec digit.
|
|
8
|
+
*
|
|
9
|
+
* Uses a switch with literal hex values (not the HANIDEC_CODEPOINTS array)
|
|
10
|
+
* to guarantee safe serialization in Reanimated worklets.
|
|
11
|
+
*/
|
|
12
|
+
export function hanidecDigitValue(charCode: number): number {
|
|
13
|
+
"worklet";
|
|
14
|
+
switch (charCode) {
|
|
15
|
+
case 0x3007: return 0; // 〇
|
|
16
|
+
case 0x4e00: return 1; // 一
|
|
17
|
+
case 0x4e8c: return 2; // 二
|
|
18
|
+
case 0x4e09: return 3; // 三
|
|
19
|
+
case 0x56db: return 4; // 四
|
|
20
|
+
case 0x4e94: return 5; // 五
|
|
21
|
+
case 0x516d: return 6; // 六
|
|
22
|
+
case 0x4e03: return 7; // 七
|
|
23
|
+
case 0x516b: return 8; // 八
|
|
24
|
+
case 0x4e5d: return 9; // 九
|
|
25
|
+
default: return -1;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Returns the Unicode codepoint of digit zero for a numbering system.
|
|
31
|
+
* Falls back to Latin (48) for unknown or supplementary-plane systems.
|
|
32
|
+
* For hanidec, returns 0x3007 as a sentinel (digits are non-contiguous).
|
|
33
|
+
*/
|
|
34
|
+
export function getZeroCodePoint(numberingSystem: string): number {
|
|
35
|
+
return ZERO_CODEPOINTS[numberingSystem] ?? LATIN_ZERO;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Builds an array of 10 digit strings for a numbering system.
|
|
40
|
+
* digitStrings[0] = zero character, digitStrings[9] = nine character.
|
|
41
|
+
*/
|
|
42
|
+
export function getDigitStrings(numberingSystem: string): string[] {
|
|
43
|
+
const cached = digitStringsCache.get(numberingSystem);
|
|
44
|
+
if (cached) return cached;
|
|
45
|
+
|
|
46
|
+
if (numberingSystem === "hanidec") {
|
|
47
|
+
digitStringsCache.set("hanidec", HANIDEC_DIGITS);
|
|
48
|
+
return HANIDEC_DIGITS;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
const zeroCP = getZeroCodePoint(numberingSystem);
|
|
52
|
+
const strings = Array.from({ length: 10 }, (_, i) => String.fromCharCode(zeroCP + i));
|
|
53
|
+
|
|
54
|
+
digitStringsCache.set(numberingSystem, strings);
|
|
55
|
+
return strings;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Returns the numeric value (0-9) of a character code in the given system,
|
|
60
|
+
* or -1 if the code is not a digit in that system.
|
|
61
|
+
*
|
|
62
|
+
* Worklet-safe. Handles hanidec (non-contiguous) via sentinel zeroCodePoint = 0x3007.
|
|
63
|
+
*/
|
|
64
|
+
export function localeDigitValue(charCode: number, zeroCodePoint: number): number {
|
|
65
|
+
"worklet";
|
|
66
|
+
if (zeroCodePoint === 0x3007) return hanidecDigitValue(charCode);
|
|
67
|
+
|
|
68
|
+
const value = charCode - zeroCodePoint;
|
|
69
|
+
return value >= 0 && value <= 9 ? value : -1;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Checks if a character code is a digit in the given numbering system.
|
|
74
|
+
* Worklet-safe. Handles hanidec via sentinel zeroCodePoint = 0x3007.
|
|
75
|
+
*/
|
|
76
|
+
export function isLocaleDigit(charCode: number, zeroCodePoint: number): boolean {
|
|
77
|
+
"worklet";
|
|
78
|
+
return localeDigitValue(charCode, zeroCodePoint) >= 0;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Checks if a single character is a digit in the given numbering system.
|
|
83
|
+
* Convenience wrapper over localeDigitValue for string-based callers.
|
|
84
|
+
* Worklet-safe.
|
|
85
|
+
*/
|
|
86
|
+
export function isDigitChar(char: string, zeroCodePoint = 48): boolean {
|
|
87
|
+
"worklet";
|
|
88
|
+
return localeDigitValue(char.charCodeAt(0), zeroCodePoint) >= 0;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Counts the number of digit characters in a string for a given numbering system.
|
|
93
|
+
* Worklet-safe.
|
|
94
|
+
*/
|
|
95
|
+
export function countDigits(text: string, zeroCodePoint: number): number {
|
|
96
|
+
"worklet";
|
|
97
|
+
let count = 0;
|
|
98
|
+
for (let i = 0; i < text.length; i++) {
|
|
99
|
+
if (localeDigitValue(text.charCodeAt(i), zeroCodePoint) >= 0) count++;
|
|
100
|
+
}
|
|
101
|
+
return count;
|
|
102
|
+
}
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Lookup tables for numeral system support.
|
|
3
|
+
*
|
|
4
|
+
* Most Unicode decimal digit systems use 10 contiguous codepoints (0-9),
|
|
5
|
+
* enabling digit detection via: digitValue = charCode - zeroCodePoint.
|
|
6
|
+
*
|
|
7
|
+
* Exception: hanidec (〇一二三四五六七八九) uses non-contiguous ideographs.
|
|
8
|
+
* Functions that accept a zeroCodePoint use 0x3007 as a sentinel to trigger
|
|
9
|
+
* the hanidec lookup path.
|
|
10
|
+
*
|
|
11
|
+
* Only BMP (Basic Multilingual Plane, U+0000-U+FFFF) systems are supported
|
|
12
|
+
* because the codebase uses charCodeAt-based indexing in worklets.
|
|
13
|
+
* Supplementary plane systems (adlm) fall back to Latin digits.
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
export const LATIN_ZERO = 0x0030; // 48
|
|
17
|
+
export const HANIDEC_ZERO = 0x3007;
|
|
18
|
+
|
|
19
|
+
export const HANIDEC_DIGITS = ["〇", "一", "二", "三", "四", "五", "六", "七", "八", "九"];
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Map of CLDR numbering system name → Unicode codepoint of digit zero.
|
|
23
|
+
* Only includes BMP systems (codepoint <= 0xFFFF).
|
|
24
|
+
* hanidec uses 0x3007 as a sentinel — the remaining digits are non-contiguous.
|
|
25
|
+
*/
|
|
26
|
+
export const ZERO_CODEPOINTS: Record<string, number> = {
|
|
27
|
+
latn: 0x0030,
|
|
28
|
+
arab: 0x0660,
|
|
29
|
+
arabext: 0x06f0,
|
|
30
|
+
bali: 0x1b50,
|
|
31
|
+
beng: 0x09e6,
|
|
32
|
+
cham: 0xaa50,
|
|
33
|
+
deva: 0x0966,
|
|
34
|
+
fullwide: 0xff10,
|
|
35
|
+
gujr: 0x0ae6,
|
|
36
|
+
guru: 0x0a66,
|
|
37
|
+
hanidec: 0x3007,
|
|
38
|
+
java: 0xa9d0,
|
|
39
|
+
kali: 0xa900,
|
|
40
|
+
khmr: 0x17e0,
|
|
41
|
+
knda: 0x0ce6,
|
|
42
|
+
lana: 0x1a80,
|
|
43
|
+
lanatham: 0x1a90,
|
|
44
|
+
laoo: 0x0ed0,
|
|
45
|
+
lepc: 0x1c40,
|
|
46
|
+
limb: 0x1946,
|
|
47
|
+
mlym: 0x0d66,
|
|
48
|
+
mong: 0x1810,
|
|
49
|
+
mtei: 0xabf0,
|
|
50
|
+
mymr: 0x1040,
|
|
51
|
+
mymrshan: 0x1090,
|
|
52
|
+
nkoo: 0x07c0,
|
|
53
|
+
olck: 0x1c50,
|
|
54
|
+
orya: 0x0b66,
|
|
55
|
+
saur: 0xa8d0,
|
|
56
|
+
sinh: 0x0de6,
|
|
57
|
+
sund: 0x1bb0,
|
|
58
|
+
talu: 0x19d0,
|
|
59
|
+
tamldec: 0x0be6,
|
|
60
|
+
telu: 0x0c66,
|
|
61
|
+
thai: 0x0e50,
|
|
62
|
+
tibt: 0x0f20,
|
|
63
|
+
vaii: 0xa620,
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* CLDR default numbering systems for locales where the platform (Hermes)
|
|
68
|
+
* may fall back to "latn" despite the locale specifying a different system.
|
|
69
|
+
*
|
|
70
|
+
* Only includes locales whose CLDR default differs from "latn".
|
|
71
|
+
* Key format: language subtag or language-region (e.g. "ar", "ar-EG").
|
|
72
|
+
*/
|
|
73
|
+
export const CLDR_DEFAULT_NUMBERING: Record<string, string> = {
|
|
74
|
+
ar: "arab",
|
|
75
|
+
"ar-AE": "arab",
|
|
76
|
+
"ar-BH": "arab",
|
|
77
|
+
"ar-EG": "arab",
|
|
78
|
+
"ar-IQ": "arab",
|
|
79
|
+
"ar-JO": "arab",
|
|
80
|
+
"ar-KW": "arab",
|
|
81
|
+
"ar-LB": "arab",
|
|
82
|
+
"ar-OM": "arab",
|
|
83
|
+
"ar-QA": "arab",
|
|
84
|
+
"ar-SA": "arab",
|
|
85
|
+
"ar-SD": "arab",
|
|
86
|
+
"ar-SY": "arab",
|
|
87
|
+
"ar-YE": "arab",
|
|
88
|
+
as: "beng",
|
|
89
|
+
"as-IN": "beng",
|
|
90
|
+
bn: "beng",
|
|
91
|
+
"bn-BD": "beng",
|
|
92
|
+
"bn-IN": "beng",
|
|
93
|
+
ckb: "arab",
|
|
94
|
+
"ckb-IQ": "arab",
|
|
95
|
+
dz: "tibt",
|
|
96
|
+
"dz-BT": "tibt",
|
|
97
|
+
fa: "arabext",
|
|
98
|
+
"fa-IR": "arabext",
|
|
99
|
+
ks: "arabext",
|
|
100
|
+
"ks-IN": "arabext",
|
|
101
|
+
mr: "deva",
|
|
102
|
+
"mr-IN": "deva",
|
|
103
|
+
my: "mymr",
|
|
104
|
+
"my-MM": "mymr",
|
|
105
|
+
ne: "deva",
|
|
106
|
+
"ne-NP": "deva",
|
|
107
|
+
ps: "arabext",
|
|
108
|
+
"ps-AF": "arabext",
|
|
109
|
+
sat: "olck",
|
|
110
|
+
"sat-IN": "olck",
|
|
111
|
+
"ur-IN": "arabext",
|
|
112
|
+
};
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import type { TextStyle } from "react-native";
|
|
2
|
+
import { SUPERSCRIPT_SCALE } from "./constants";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Returns the scaled TextStyle for superscript rendering in native slots.
|
|
6
|
+
* Reduces fontSize and lineHeight by SUPERSCRIPT_SCALE.
|
|
7
|
+
*/
|
|
8
|
+
export function getSuperscriptTextStyle(textStyle: TextStyle, lineHeight: number): TextStyle {
|
|
9
|
+
return {
|
|
10
|
+
...textStyle,
|
|
11
|
+
fontSize: (textStyle.fontSize ?? 16) * SUPERSCRIPT_SCALE,
|
|
12
|
+
lineHeight,
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Returns the pivot-scale transform array for superscript rendering in Skia slots.
|
|
18
|
+
* Pivots around the text top so the digit shrinks downward within the mask region.
|
|
19
|
+
*/
|
|
20
|
+
export function getSuperscriptTransform(
|
|
21
|
+
baseY: number,
|
|
22
|
+
ascent: number,
|
|
23
|
+
): ({ translateY: number } | { scale: number })[] {
|
|
24
|
+
const textTop = baseY + ascent;
|
|
25
|
+
|
|
26
|
+
return [{ translateY: textTop }, { scale: SUPERSCRIPT_SCALE }, { translateY: -textTop }];
|
|
27
|
+
}
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
import { assignXPositions, type CharLayout } from "./layout";
|
|
2
|
+
import type { GlyphMetrics, TextAlign } from "./types";
|
|
3
|
+
import { isDigitChar, localeDigitValue } from "./numerals";
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Keys for each digit position within a time segment.
|
|
7
|
+
* Index 0 = tens digit, index 1 = ones digit.
|
|
8
|
+
*/
|
|
9
|
+
const HOUR_KEYS = ["h10", "h1"] as const;
|
|
10
|
+
const MINUTE_KEYS = ["m10", "m1"] as const;
|
|
11
|
+
const SECOND_KEYS = ["s10", "s1"] as const;
|
|
12
|
+
|
|
13
|
+
function pushChar(
|
|
14
|
+
chars: CharLayout[],
|
|
15
|
+
key: string,
|
|
16
|
+
char: string,
|
|
17
|
+
metrics: GlyphMetrics,
|
|
18
|
+
zeroCodePoint = 48,
|
|
19
|
+
): void {
|
|
20
|
+
const isDigit = isDigitChar(char, zeroCodePoint);
|
|
21
|
+
const width = metrics.charWidths[char] ?? metrics.maxDigitWidth;
|
|
22
|
+
chars.push({
|
|
23
|
+
key,
|
|
24
|
+
char,
|
|
25
|
+
isDigit,
|
|
26
|
+
digitValue: isDigit ? localeDigitValue(char.charCodeAt(0), zeroCodePoint) : -1,
|
|
27
|
+
x: 0,
|
|
28
|
+
width,
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Pushes a group of digit characters with the given key array.
|
|
34
|
+
* If the digit string is shorter than the keys array (e.g. single-digit hour),
|
|
35
|
+
* only the last N keys are used (matching the useTimeFormatting behavior where
|
|
36
|
+
* h10 is omitted for single-digit hours).
|
|
37
|
+
*/
|
|
38
|
+
function pushDigitGroup(
|
|
39
|
+
chars: CharLayout[],
|
|
40
|
+
digits: string,
|
|
41
|
+
keys: readonly string[],
|
|
42
|
+
metrics: GlyphMetrics,
|
|
43
|
+
): void {
|
|
44
|
+
const offset = keys.length - digits.length;
|
|
45
|
+
for (let i = 0; i < digits.length; i++) {
|
|
46
|
+
pushChar(chars, keys[offset + i], digits[i], metrics);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Computes time-aware string layout with fixed semantic keys.
|
|
52
|
+
*
|
|
53
|
+
* Unlike `computeStringLayout` which uses positional keys (`pos:0`, `pos:1`),
|
|
54
|
+
* this function assigns the same fixed keys (h10, h1, sep, m10, m1, etc.)
|
|
55
|
+
* that `useTimeFormatting` produces. This ensures worklet-driven updates
|
|
56
|
+
* produce stable keys that match prop-driven updates.
|
|
57
|
+
*
|
|
58
|
+
* @param timeString - Formatted time string like "14:30", "9:30", "2:30 PM", "05:30"
|
|
59
|
+
* @param metrics - Glyph measurement data
|
|
60
|
+
* @param totalWidth - Available width for alignment
|
|
61
|
+
* @param textAlign - Text alignment within totalWidth
|
|
62
|
+
* @param hasHours - Whether the hours segment is shown (determines how to interpret segments)
|
|
63
|
+
* @param hasSeconds - Whether the seconds segment is shown
|
|
64
|
+
*/
|
|
65
|
+
export function computeTimeStringLayout(
|
|
66
|
+
timeString: string,
|
|
67
|
+
metrics: GlyphMetrics,
|
|
68
|
+
totalWidth: number,
|
|
69
|
+
textAlign: TextAlign,
|
|
70
|
+
hasHours: boolean,
|
|
71
|
+
hasSeconds: boolean,
|
|
72
|
+
): CharLayout[] {
|
|
73
|
+
const chars: CharLayout[] = [];
|
|
74
|
+
|
|
75
|
+
let ampmLabel: string | null = null;
|
|
76
|
+
let timePart = timeString;
|
|
77
|
+
if (timePart.endsWith(" AM")) {
|
|
78
|
+
ampmLabel = "AM";
|
|
79
|
+
timePart = timePart.slice(0, -3);
|
|
80
|
+
} else if (timePart.endsWith(" PM")) {
|
|
81
|
+
ampmLabel = "PM";
|
|
82
|
+
timePart = timePart.slice(0, -3);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
const segments = timePart.split(":");
|
|
86
|
+
|
|
87
|
+
if (hasHours && hasSeconds && segments.length === 3) {
|
|
88
|
+
// HH:MM:SS
|
|
89
|
+
pushDigitGroup(chars, segments[0], HOUR_KEYS, metrics);
|
|
90
|
+
pushChar(chars, "sep", ":", metrics);
|
|
91
|
+
pushDigitGroup(chars, segments[1], MINUTE_KEYS, metrics);
|
|
92
|
+
pushChar(chars, "sep2", ":", metrics);
|
|
93
|
+
pushDigitGroup(chars, segments[2], SECOND_KEYS, metrics);
|
|
94
|
+
} else if (hasHours && !hasSeconds && segments.length >= 2) {
|
|
95
|
+
// HH:MM
|
|
96
|
+
pushDigitGroup(chars, segments[0], HOUR_KEYS, metrics);
|
|
97
|
+
pushChar(chars, "sep", ":", metrics);
|
|
98
|
+
pushDigitGroup(chars, segments[1], MINUTE_KEYS, metrics);
|
|
99
|
+
} else if (!hasHours && hasSeconds && segments.length >= 2) {
|
|
100
|
+
// MM:SS (countdown mode)
|
|
101
|
+
pushDigitGroup(chars, segments[0], MINUTE_KEYS, metrics);
|
|
102
|
+
pushChar(chars, "sep2", ":", metrics);
|
|
103
|
+
pushDigitGroup(chars, segments[1], SECOND_KEYS, metrics);
|
|
104
|
+
} else {
|
|
105
|
+
// Fallback: just minutes (shouldn't normally happen)
|
|
106
|
+
pushDigitGroup(chars, segments[0], MINUTE_KEYS, metrics);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
// AM/PM suffix — individual characters with value-dependent keys
|
|
110
|
+
if (ampmLabel) {
|
|
111
|
+
pushChar(chars, "ampm-sp", " ", metrics);
|
|
112
|
+
for (let i = 0; i < ampmLabel.length; i++) {
|
|
113
|
+
pushChar(chars, `ampm:${ampmLabel}:${i}`, ampmLabel[i], metrics);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
assignXPositions(chars, totalWidth, textAlign);
|
|
118
|
+
return chars;
|
|
119
|
+
}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import type { SkFont } from "@shopify/react-native-skia";
|
|
2
|
+
import type { ViewStyle } from "react-native";
|
|
3
|
+
import type { SharedValue } from "react-native-reanimated";
|
|
4
|
+
import type { NumberFlowStyle } from "../native/types";
|
|
5
|
+
import type { AnimationBehaviorProps, TextAlign } from "./types";
|
|
6
|
+
|
|
7
|
+
interface TimeFlowBaseProps extends AnimationBehaviorProps {
|
|
8
|
+
/** Use 24-hour format. Default: true. Only applies when hours are shown. */
|
|
9
|
+
is24Hour?: boolean;
|
|
10
|
+
/** Pad hours with leading zero. Default: true. "09:30" vs "9:30". */
|
|
11
|
+
padHours?: boolean;
|
|
12
|
+
|
|
13
|
+
/** Text styling. fontSize is required; fontFamily defaults to the platform system font. */
|
|
14
|
+
style: NumberFlowStyle;
|
|
15
|
+
/** Text alignment. Defaults to "left". */
|
|
16
|
+
textAlign?: TextAlign;
|
|
17
|
+
/** Style applied to the outer container View */
|
|
18
|
+
containerStyle?: ViewStyle;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
interface TimeFlowValueProps {
|
|
22
|
+
/** Hours value (0-23). Omit to hide the hours segment (countdown MM:SS mode). */
|
|
23
|
+
hours?: number;
|
|
24
|
+
/** Minutes value (0-59). Required. */
|
|
25
|
+
minutes: number;
|
|
26
|
+
/** Seconds value (0-59). Omit to hide the seconds segment. */
|
|
27
|
+
seconds?: number;
|
|
28
|
+
/** Unix timestamp in ms. Extracts hours/minutes/seconds automatically. Takes priority over direct values. */
|
|
29
|
+
timestamp?: number;
|
|
30
|
+
/** Timezone offset in ms for timestamp mode. */
|
|
31
|
+
timezoneOffset?: number;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/** Props for TimeFlow. Accessibility is built-in: accessibilityRole="text" and accessibilityLabel are set automatically. */
|
|
35
|
+
export type TimeFlowProps = TimeFlowBaseProps & TimeFlowValueProps;
|
|
36
|
+
|
|
37
|
+
interface SkiaTimeFlowBaseProps extends AnimationBehaviorProps {
|
|
38
|
+
/** Use 24-hour format. Default: true. Only applies when hours are shown. */
|
|
39
|
+
is24Hour?: boolean;
|
|
40
|
+
/** Pad hours with leading zero. Default: true. "09:30" vs "9:30". */
|
|
41
|
+
padHours?: boolean;
|
|
42
|
+
|
|
43
|
+
/** SkFont instance from useFont(). Required — renders empty until font loads. */
|
|
44
|
+
font: SkFont | null;
|
|
45
|
+
/** Text color (Skia color string). Defaults to "#000000". */
|
|
46
|
+
color?: string;
|
|
47
|
+
/** X position within the Canvas. Defaults to 0. */
|
|
48
|
+
x?: number;
|
|
49
|
+
/** Y position within the Canvas (baseline). Defaults to 0. */
|
|
50
|
+
y?: number;
|
|
51
|
+
/** Available width for alignment calculations. Defaults to 0. */
|
|
52
|
+
width?: number;
|
|
53
|
+
/** Text alignment within the available width. Defaults to "left". */
|
|
54
|
+
textAlign?: TextAlign;
|
|
55
|
+
/** Parent opacity (SharedValue for animation coordination) */
|
|
56
|
+
opacity?: SharedValue<number>;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
type SkiaTimeFlowValueProps =
|
|
60
|
+
| {
|
|
61
|
+
/** Hours value (0-23). Omit to hide the hours segment. */
|
|
62
|
+
hours?: number;
|
|
63
|
+
/** Minutes value (0-59). Required when using direct time values. */
|
|
64
|
+
minutes: number;
|
|
65
|
+
/** Seconds value (0-59). Omit to hide the seconds segment. */
|
|
66
|
+
seconds?: number;
|
|
67
|
+
/** Unix timestamp in ms. Extracts hours/minutes/seconds automatically. */
|
|
68
|
+
timestamp?: number;
|
|
69
|
+
/** Timezone offset in ms for timestamp mode. */
|
|
70
|
+
timezoneOffset?: number;
|
|
71
|
+
sharedValue?: never;
|
|
72
|
+
}
|
|
73
|
+
| {
|
|
74
|
+
hours?: never;
|
|
75
|
+
minutes?: never;
|
|
76
|
+
seconds?: never;
|
|
77
|
+
timestamp?: never;
|
|
78
|
+
timezoneOffset?: never;
|
|
79
|
+
/** Worklet-driven pre-formatted time string (e.g. "14:30", "2:30 PM"). */
|
|
80
|
+
sharedValue: SharedValue<string>;
|
|
81
|
+
};
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Props for SkiaTimeFlow.
|
|
85
|
+
* Value changes are auto-announced for screen reader users.
|
|
86
|
+
* For VoiceOver/TalkBack focus-based reading, set `accessibilityLabel` on the parent Canvas.
|
|
87
|
+
*/
|
|
88
|
+
export type SkiaTimeFlowProps = SkiaTimeFlowBaseProps & SkiaTimeFlowValueProps;
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { Easing } from "react-native-reanimated";
|
|
2
|
+
import type { TimingConfig } from "./types";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* NumberFlow's CSS linear() easing function — exact reproduction.
|
|
6
|
+
* A smooth deceleration curve defined by 90 evenly-spaced control points.
|
|
7
|
+
*/
|
|
8
|
+
const NUMBER_FLOW_EASING_POINTS = [
|
|
9
|
+
0, 0.005, 0.019, 0.039, 0.066, 0.096, 0.129, 0.165, 0.202, 0.24, 0.278, 0.316, 0.354, 0.39, 0.426,
|
|
10
|
+
0.461, 0.494, 0.526, 0.557, 0.586, 0.614, 0.64, 0.665, 0.689, 0.711, 0.731, 0.751, 0.769, 0.786,
|
|
11
|
+
0.802, 0.817, 0.831, 0.844, 0.856, 0.867, 0.877, 0.887, 0.896, 0.904, 0.912, 0.919, 0.925, 0.931,
|
|
12
|
+
0.937, 0.942, 0.947, 0.951, 0.955, 0.959, 0.962, 0.965, 0.968, 0.971, 0.973, 0.976, 0.978, 0.98,
|
|
13
|
+
0.981, 0.983, 0.984, 0.986, 0.987, 0.988, 0.989, 0.99, 0.991, 0.992, 0.992, 0.993, 0.994, 0.994,
|
|
14
|
+
0.995, 0.995, 0.996, 0.996, 0.9963, 0.9967, 0.9969, 0.9972, 0.9975, 0.9977, 0.9979, 0.9981,
|
|
15
|
+
0.9982, 0.9984, 0.9985, 0.9987, 0.9988, 0.9989, 1,
|
|
16
|
+
] as const;
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* NumberFlow's default transform easing — smooth deceleration curve.
|
|
20
|
+
* Piecewise linear interpolation over the control points above,
|
|
21
|
+
* recreating CSS linear() easing from the Web Animations API.
|
|
22
|
+
*/
|
|
23
|
+
const numberFlowEasing = (t: number) => {
|
|
24
|
+
"worklet";
|
|
25
|
+
|
|
26
|
+
const lastIndex = NUMBER_FLOW_EASING_POINTS.length - 1;
|
|
27
|
+
|
|
28
|
+
if (t <= 0) return NUMBER_FLOW_EASING_POINTS[0];
|
|
29
|
+
if (t >= 1) return NUMBER_FLOW_EASING_POINTS[lastIndex];
|
|
30
|
+
|
|
31
|
+
const scaledT = t * lastIndex;
|
|
32
|
+
const index = Math.floor(scaledT);
|
|
33
|
+
const fraction = scaledT - index;
|
|
34
|
+
|
|
35
|
+
return (
|
|
36
|
+
NUMBER_FLOW_EASING_POINTS[index] +
|
|
37
|
+
(NUMBER_FLOW_EASING_POINTS[index + 1] - NUMBER_FLOW_EASING_POINTS[index]) * fraction
|
|
38
|
+
);
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
export const DEFAULT_TRANSFORM_TIMING: TimingConfig = {
|
|
42
|
+
duration: 900,
|
|
43
|
+
easing: numberFlowEasing,
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
// How long a digit spins before settling into its final position
|
|
47
|
+
export const DEFAULT_SPIN_TIMING: TimingConfig = DEFAULT_TRANSFORM_TIMING;
|
|
48
|
+
|
|
49
|
+
export const DEFAULT_OPACITY_TIMING: TimingConfig = {
|
|
50
|
+
duration: 450,
|
|
51
|
+
easing: Easing.out(Easing.ease),
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
export const ZERO_TIMING: TimingConfig = {
|
|
55
|
+
duration: 0,
|
|
56
|
+
easing: (t: number) => {
|
|
57
|
+
"worklet";
|
|
58
|
+
return t;
|
|
59
|
+
},
|
|
60
|
+
};
|