react-native-ai-animations 0.0.0-stage → 0.8.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 (125) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +174 -2
  3. package/lib/module/brand/index.js +4 -0
  4. package/lib/module/brand/index.js.map +1 -0
  5. package/lib/module/brand/spinning-mark.js +96 -0
  6. package/lib/module/brand/spinning-mark.js.map +1 -0
  7. package/lib/module/chat/effort-bar.js +853 -0
  8. package/lib/module/chat/effort-bar.js.map +1 -0
  9. package/lib/module/chat/index.js +8 -0
  10. package/lib/module/chat/index.js.map +1 -0
  11. package/lib/module/chat/question-card.js +720 -0
  12. package/lib/module/chat/question-card.js.map +1 -0
  13. package/lib/module/chat/reasoning.js +38 -0
  14. package/lib/module/chat/reasoning.js.map +1 -0
  15. package/lib/module/chat/status-row.js +140 -0
  16. package/lib/module/chat/status-row.js.map +1 -0
  17. package/lib/module/chat/thinking-block.js +255 -0
  18. package/lib/module/chat/thinking-block.js.map +1 -0
  19. package/lib/module/index.js +5 -0
  20. package/lib/module/index.js.map +1 -0
  21. package/lib/module/internal/color.js +15 -0
  22. package/lib/module/internal/color.js.map +1 -0
  23. package/lib/module/internal/use-elapsed.js +20 -0
  24. package/lib/module/internal/use-elapsed.js.map +1 -0
  25. package/lib/module/package.json +1 -0
  26. package/lib/module/skia/dot-orb.js +256 -0
  27. package/lib/module/skia/dot-orb.js.map +1 -0
  28. package/lib/module/skia/index.js +8 -0
  29. package/lib/module/skia/index.js.map +1 -0
  30. package/lib/module/skia/liquid-orb.js +303 -0
  31. package/lib/module/skia/liquid-orb.js.map +1 -0
  32. package/lib/module/skia/matrix-orb.js +272 -0
  33. package/lib/module/skia/matrix-orb.js.map +1 -0
  34. package/lib/module/skia/media-generating.js +524 -0
  35. package/lib/module/skia/media-generating.js.map +1 -0
  36. package/lib/module/skia/voice-wave.js +278 -0
  37. package/lib/module/skia/voice-wave.js.map +1 -0
  38. package/lib/module/text/index.js +6 -0
  39. package/lib/module/text/index.js.map +1 -0
  40. package/lib/module/text/shimmer-text.js +122 -0
  41. package/lib/module/text/shimmer-text.js.map +1 -0
  42. package/lib/module/text/spoken-text.js +85 -0
  43. package/lib/module/text/spoken-text.js.map +1 -0
  44. package/lib/module/text/streaming-text.js +135 -0
  45. package/lib/module/text/streaming-text.js.map +1 -0
  46. package/lib/module/theme/index.js +5 -0
  47. package/lib/module/theme/index.js.map +1 -0
  48. package/lib/module/theme/palette.js +45 -0
  49. package/lib/module/theme/palette.js.map +1 -0
  50. package/lib/module/theme/provider.js +65 -0
  51. package/lib/module/theme/provider.js.map +1 -0
  52. package/lib/typescript/package.json +1 -0
  53. package/lib/typescript/src/brand/index.d.ts +2 -0
  54. package/lib/typescript/src/brand/index.d.ts.map +1 -0
  55. package/lib/typescript/src/brand/spinning-mark.d.ts +21 -0
  56. package/lib/typescript/src/brand/spinning-mark.d.ts.map +1 -0
  57. package/lib/typescript/src/chat/effort-bar.d.ts +42 -0
  58. package/lib/typescript/src/chat/effort-bar.d.ts.map +1 -0
  59. package/lib/typescript/src/chat/index.d.ts +6 -0
  60. package/lib/typescript/src/chat/index.d.ts.map +1 -0
  61. package/lib/typescript/src/chat/question-card.d.ts +73 -0
  62. package/lib/typescript/src/chat/question-card.d.ts.map +1 -0
  63. package/lib/typescript/src/chat/reasoning.d.ts +20 -0
  64. package/lib/typescript/src/chat/reasoning.d.ts.map +1 -0
  65. package/lib/typescript/src/chat/status-row.d.ts +20 -0
  66. package/lib/typescript/src/chat/status-row.d.ts.map +1 -0
  67. package/lib/typescript/src/chat/thinking-block.d.ts +35 -0
  68. package/lib/typescript/src/chat/thinking-block.d.ts.map +1 -0
  69. package/lib/typescript/src/index.d.ts +3 -0
  70. package/lib/typescript/src/index.d.ts.map +1 -0
  71. package/lib/typescript/src/internal/color.d.ts +2 -0
  72. package/lib/typescript/src/internal/color.d.ts.map +1 -0
  73. package/lib/typescript/src/internal/use-elapsed.d.ts +3 -0
  74. package/lib/typescript/src/internal/use-elapsed.d.ts.map +1 -0
  75. package/lib/typescript/src/skia/dot-orb.d.ts +16 -0
  76. package/lib/typescript/src/skia/dot-orb.d.ts.map +1 -0
  77. package/lib/typescript/src/skia/index.d.ts +6 -0
  78. package/lib/typescript/src/skia/index.d.ts.map +1 -0
  79. package/lib/typescript/src/skia/liquid-orb.d.ts +20 -0
  80. package/lib/typescript/src/skia/liquid-orb.d.ts.map +1 -0
  81. package/lib/typescript/src/skia/matrix-orb.d.ts +12 -0
  82. package/lib/typescript/src/skia/matrix-orb.d.ts.map +1 -0
  83. package/lib/typescript/src/skia/media-generating.d.ts +59 -0
  84. package/lib/typescript/src/skia/media-generating.d.ts.map +1 -0
  85. package/lib/typescript/src/skia/voice-wave.d.ts +17 -0
  86. package/lib/typescript/src/skia/voice-wave.d.ts.map +1 -0
  87. package/lib/typescript/src/text/index.d.ts +4 -0
  88. package/lib/typescript/src/text/index.d.ts.map +1 -0
  89. package/lib/typescript/src/text/shimmer-text.d.ts +13 -0
  90. package/lib/typescript/src/text/shimmer-text.d.ts.map +1 -0
  91. package/lib/typescript/src/text/spoken-text.d.ts +15 -0
  92. package/lib/typescript/src/text/spoken-text.d.ts.map +1 -0
  93. package/lib/typescript/src/text/streaming-text.d.ts +16 -0
  94. package/lib/typescript/src/text/streaming-text.d.ts.map +1 -0
  95. package/lib/typescript/src/theme/index.d.ts +3 -0
  96. package/lib/typescript/src/theme/index.d.ts.map +1 -0
  97. package/lib/typescript/src/theme/palette.d.ts +33 -0
  98. package/lib/typescript/src/theme/palette.d.ts.map +1 -0
  99. package/lib/typescript/src/theme/provider.d.ts +13 -0
  100. package/lib/typescript/src/theme/provider.d.ts.map +1 -0
  101. package/package.json +133 -4
  102. package/src/brand/index.ts +5 -0
  103. package/src/brand/spinning-mark.tsx +118 -0
  104. package/src/chat/effort-bar.tsx +748 -0
  105. package/src/chat/index.ts +45 -0
  106. package/src/chat/question-card.tsx +649 -0
  107. package/src/chat/reasoning.ts +30 -0
  108. package/src/chat/status-row.tsx +127 -0
  109. package/src/chat/thinking-block.tsx +250 -0
  110. package/src/index.ts +2 -0
  111. package/src/internal/color.ts +18 -0
  112. package/src/internal/use-elapsed.ts +21 -0
  113. package/src/skia/dot-orb.tsx +248 -0
  114. package/src/skia/index.ts +34 -0
  115. package/src/skia/liquid-orb.tsx +274 -0
  116. package/src/skia/matrix-orb.tsx +337 -0
  117. package/src/skia/media-generating.tsx +389 -0
  118. package/src/skia/voice-wave.tsx +215 -0
  119. package/src/text/index.ts +3 -0
  120. package/src/text/shimmer-text.tsx +140 -0
  121. package/src/text/spoken-text.tsx +82 -0
  122. package/src/text/streaming-text.tsx +144 -0
  123. package/src/theme/index.ts +11 -0
  124. package/src/theme/palette.ts +62 -0
  125. package/src/theme/provider.tsx +54 -0
@@ -0,0 +1,853 @@
1
+ "use strict";
2
+
3
+ import { useEffect, useMemo, useRef, useState } from "react";
4
+ import { PanResponder, Text, View } from "react-native";
5
+ import Animated, { Easing, FadeIn, interpolateColor, useAnimatedStyle, useDerivedValue, useReducedMotion, useSharedValue, withSpring } from "react-native-reanimated";
6
+ import { withAlpha } from "../internal/color.js";
7
+ import { useMotionPalette } from "../theme/provider.js";
8
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
9
+ const LEVEL_SPRING = {
10
+ damping: 20,
11
+ stiffness: 190,
12
+ mass: 0.9
13
+ };
14
+ const GRAB_SPRING = {
15
+ damping: 22,
16
+ stiffness: 320,
17
+ mass: 0.7
18
+ };
19
+ const EASE_OUT = Easing.bezier(0.22, 1, 0.36, 1);
20
+ const DEFAULT_SEGMENT_STYLE = {
21
+ fontSize: 13,
22
+ lineHeight: 18,
23
+ fontWeight: "600"
24
+ };
25
+ const DEFAULT_GRADIENT = ["#53C26B", "#9BCB4A", "#F0C64A", "#F19A3E", "#EC6A4F", "#E5486F"];
26
+ const SLIDER_TRACK = 40;
27
+ const SLIDER_RIM = 3;
28
+ const SLIDER_STRETCH = 1.4;
29
+ const SLIDER_TAB = 28;
30
+ const SLIDER_TAB_RADIUS = 10;
31
+ const SLIDER_SHOULDER = 8;
32
+ const COMPACT_SLIDER_KNOB = 10;
33
+ function normalize(level) {
34
+ return typeof level === "string" ? {
35
+ label: level
36
+ } : level;
37
+ }
38
+ function mix(a, b, t) {
39
+ const parse = hex => {
40
+ const clean = hex.replace("#", "");
41
+ return [0, 2, 4].map(offset => parseInt(clean.slice(offset, offset + 2), 16));
42
+ };
43
+ const from = parse(a);
44
+ const to = parse(b);
45
+ const channel = index => Math.round(from[index] + (to[index] - from[index]) * t).toString(16).padStart(2, "0");
46
+ return `#${channel(0)}${channel(1)}${channel(2)}`;
47
+ }
48
+ function spread(stops, count) {
49
+ if (count <= 1) return [stops[stops.length - 1]];
50
+ if (stops.length === 1) return new Array(count).fill(stops[0]);
51
+ return Array.from({
52
+ length: count
53
+ }, (_, index) => {
54
+ const position = index / (count - 1) * (stops.length - 1);
55
+ const low = Math.floor(position);
56
+ const high = Math.min(stops.length - 1, low + 1);
57
+ const a = stops[low];
58
+ const b = stops[high];
59
+ return a.startsWith("#") && b.startsWith("#") ? mix(a, b, position - low) : position - low < 0.5 ? a : b;
60
+ });
61
+ }
62
+ function filledFor(index, count, steps) {
63
+ return Math.max(1, Math.round((index + 1) / count * steps));
64
+ }
65
+ export function EffortBar({
66
+ levels,
67
+ value,
68
+ onChange,
69
+ variant = "bars",
70
+ size = "regular",
71
+ steps: stepsProp,
72
+ tabLabel,
73
+ levelIcon,
74
+ disabled = false,
75
+ fillColors,
76
+ barHeight,
77
+ onHaptic,
78
+ accessibilityLabel,
79
+ segmentStyle = DEFAULT_SEGMENT_STYLE,
80
+ colors,
81
+ style
82
+ }) {
83
+ const palette = useMotionPalette(colors);
84
+ const reduceMotion = useReducedMotion();
85
+ const items = useMemo(() => levels.map(normalize), [levels]);
86
+ const count = Math.max(1, items.length);
87
+ const index = Math.min(count - 1, Math.max(0, value));
88
+ const current = items[index];
89
+ const compact = size === "compact";
90
+ const stops = fillColors && fillColors.length > 0 ? fillColors : undefined;
91
+ const custom = !!stops;
92
+ const steps = variant === "bars" ? Math.max(count, stepsProp ?? (compact ? count : Math.max(count, 10))) : count;
93
+ const filled = filledFor(index, count, steps);
94
+ const ratio = count > 1 ? index / (count - 1) : 0;
95
+ const fill = useSharedValue(filled);
96
+ const level = useSharedValue(index);
97
+ const knob = useSharedValue(ratio);
98
+ const pressed = useSharedValue(0);
99
+ const [width, setWidth] = useState(0);
100
+ const lastIndex = useRef(index);
101
+ const indexRef = useRef(index);
102
+ const dragging = useRef(false);
103
+ const interactive = !!onChange && !disabled;
104
+ indexRef.current = index;
105
+ useEffect(() => {
106
+ fill.value = reduceMotion ? filled : withSpring(filled, LEVEL_SPRING);
107
+ level.value = reduceMotion ? index : withSpring(index, LEVEL_SPRING);
108
+ }, [fill, filled, index, level, reduceMotion]);
109
+ useEffect(() => {
110
+ if (dragging.current) return;
111
+ knob.value = reduceMotion ? ratio : withSpring(ratio, LEVEL_SPRING);
112
+ }, [knob, ratio, reduceMotion]);
113
+ const barColors = useMemo(() => spread(stops ?? DEFAULT_GRADIENT, steps), [steps, stops]);
114
+ const trackFills = useMemo(() => stops ? spread(stops, count) : items.map(() => palette.text), [count, items, palette.text, stops]);
115
+ const sliderTrack = barHeight ?? SLIDER_TRACK;
116
+ const knobSize = compact ? COMPACT_SLIDER_KNOB : sliderTrack;
117
+ const knobInset = compact ? 0 : SLIDER_RIM;
118
+ const select = next => {
119
+ const item = items[next];
120
+ onHaptic?.(next);
121
+ onChange?.(next, {
122
+ index: next,
123
+ label: item.label,
124
+ value: item.value,
125
+ budget: item.budget
126
+ });
127
+ };
128
+ const pick = (x, grant) => {
129
+ if (!interactive || width === 0) return;
130
+ let next;
131
+ if (variant === "slider") {
132
+ const position = Math.min(1, Math.max(0, (x - knobInset - knobSize / 2) / Math.max(1, width - knobInset * 2 - knobSize)));
133
+ dragging.current = true;
134
+ knob.value = reduceMotion || !grant ? position : withSpring(position, GRAB_SPRING);
135
+ if (grant && !reduceMotion) pressed.value = withSpring(1, GRAB_SPRING);
136
+ next = Math.round(position * (count - 1));
137
+ } else {
138
+ next = Math.min(count - 1, Math.max(0, Math.floor(x / width * count)));
139
+ }
140
+ if (next === lastIndex.current) return;
141
+ lastIndex.current = next;
142
+ select(next);
143
+ };
144
+ const pickRef = useRef(pick);
145
+ pickRef.current = pick;
146
+ const release = () => {
147
+ if (!dragging.current) return;
148
+ dragging.current = false;
149
+ const target = count > 1 ? indexRef.current / (count - 1) : 0;
150
+ knob.value = reduceMotion ? target : withSpring(target, LEVEL_SPRING);
151
+ pressed.value = reduceMotion ? 0 : withSpring(0, LEVEL_SPRING);
152
+ };
153
+ const releaseRef = useRef(release);
154
+ releaseRef.current = release;
155
+ useEffect(() => {
156
+ lastIndex.current = index;
157
+ }, [index]);
158
+ const responder = useMemo(() => PanResponder.create({
159
+ onStartShouldSetPanResponder: () => true,
160
+ onMoveShouldSetPanResponder: (_, gesture) => Math.abs(gesture.dx) > 4,
161
+ onPanResponderTerminationRequest: () => false,
162
+ onPanResponderGrant: event => pickRef.current(event.nativeEvent.locationX, true),
163
+ onPanResponderMove: event => pickRef.current(event.nativeEvent.locationX, false),
164
+ onPanResponderRelease: () => releaseRef.current(),
165
+ onPanResponderTerminate: () => releaseRef.current()
166
+ }), []);
167
+ const handleLayout = event => setWidth(event.nativeEvent.layout.width);
168
+ const handleAction = event => {
169
+ if (!interactive) return;
170
+ const delta = event.nativeEvent.actionName === "increment" ? 1 : event.nativeEvent.actionName === "decrement" ? -1 : 0;
171
+ const next = Math.min(count - 1, Math.max(0, index + delta));
172
+ if (next !== index) select(next);
173
+ };
174
+ const height = variant === "slider" ? compact ? knobSize : SLIDER_TAB + sliderTrack : barHeight ?? (compact ? 14 : variant === "track" ? 44 : variant === "segmented" ? 40 : 56);
175
+ const compactWidth = variant === "segmented" ? count * 12 + 4 : variant === "slider" ? 40 : steps * 5 + (steps - 1) * 2.5;
176
+ const visual = variant === "track" ? /*#__PURE__*/_jsx(Track, {
177
+ items: items,
178
+ level: level,
179
+ width: width,
180
+ height: height,
181
+ fills: trackFills,
182
+ palette: palette,
183
+ compact: compact,
184
+ segmentStyle: segmentStyle,
185
+ levelIcon: levelIcon
186
+ }) : variant === "segmented" ? /*#__PURE__*/_jsx(Segmented, {
187
+ items: items,
188
+ level: level,
189
+ width: width,
190
+ height: height,
191
+ fills: trackFills,
192
+ custom: custom,
193
+ palette: palette,
194
+ compact: compact,
195
+ segmentStyle: segmentStyle,
196
+ levelIcon: levelIcon
197
+ }) : variant === "slider" ? compact ? /*#__PURE__*/_jsx(CompactSlider, {
198
+ count: count,
199
+ knob: knob,
200
+ width: width,
201
+ knobSize: knobSize,
202
+ fills: trackFills,
203
+ palette: palette
204
+ }) : /*#__PURE__*/_jsx(Slider, {
205
+ count: count,
206
+ label: current?.label ?? "",
207
+ index: index,
208
+ tabLabel: tabLabel,
209
+ levelIcon: levelIcon,
210
+ knob: knob,
211
+ pressed: pressed,
212
+ width: width,
213
+ track: sliderTrack,
214
+ fills: trackFills,
215
+ palette: palette,
216
+ reduceMotion: reduceMotion,
217
+ segmentStyle: segmentStyle
218
+ }) : /*#__PURE__*/_jsx(Bars, {
219
+ steps: steps,
220
+ fill: fill,
221
+ height: height,
222
+ colors: barColors,
223
+ palette: palette,
224
+ compact: compact
225
+ });
226
+ const control = /*#__PURE__*/_jsx(View, {
227
+ onLayout: handleLayout,
228
+ ...(interactive ? responder.panHandlers : {}),
229
+ style: {
230
+ height,
231
+ justifyContent: "flex-end"
232
+ },
233
+ children: /*#__PURE__*/_jsx(View, {
234
+ pointerEvents: "none",
235
+ children: visual
236
+ })
237
+ });
238
+ return /*#__PURE__*/_jsx(View, {
239
+ accessible: true,
240
+ accessibilityRole: "adjustable",
241
+ accessibilityLabel: accessibilityLabel ?? "Effort",
242
+ accessibilityValue: {
243
+ text: current?.label
244
+ },
245
+ accessibilityState: {
246
+ disabled
247
+ },
248
+ accessibilityActions: interactive ? [{
249
+ name: "increment"
250
+ }, {
251
+ name: "decrement"
252
+ }] : undefined,
253
+ onAccessibilityAction: handleAction,
254
+ style: [{
255
+ opacity: disabled ? 0.45 : 1
256
+ }, compact && {
257
+ width: compactWidth
258
+ }, style],
259
+ children: control
260
+ });
261
+ }
262
+ function Bars({
263
+ steps,
264
+ fill,
265
+ height,
266
+ colors,
267
+ palette,
268
+ compact
269
+ }) {
270
+ const gap = compact ? 2.5 : 6;
271
+ const track = compact ? withAlpha(palette.text, 0.14) : withAlpha(palette.text, 0.08);
272
+ return /*#__PURE__*/_jsx(View, {
273
+ style: {
274
+ flexDirection: "row",
275
+ alignItems: "flex-end",
276
+ gap,
277
+ height
278
+ },
279
+ children: Array.from({
280
+ length: steps
281
+ }, (_, position) => /*#__PURE__*/_jsx(Bar, {
282
+ position: position,
283
+ steps: steps,
284
+ fill: fill,
285
+ height: height,
286
+ color: colors[position],
287
+ track: track,
288
+ compact: compact
289
+ }, position))
290
+ });
291
+ }
292
+ function Bar({
293
+ position,
294
+ steps,
295
+ fill,
296
+ height,
297
+ color,
298
+ track,
299
+ compact
300
+ }) {
301
+ const minimum = compact ? 0.4 : 0.42;
302
+ const ratio = steps > 1 ? minimum + (1 - minimum) * position / (steps - 1) : 1;
303
+ const barHeight = Math.round(height * ratio);
304
+ const amount = useDerivedValue(() => Math.min(1, Math.max(0, fill.value - position)));
305
+ const colorStyle = useAnimatedStyle(() => ({
306
+ opacity: amount.value
307
+ }));
308
+ const popStyle = useAnimatedStyle(() => {
309
+ const near = Math.max(0, 1 - Math.abs(fill.value - (position + 1)));
310
+ return {
311
+ transform: [{
312
+ scale: 1 + near * (compact ? 0 : 0.08)
313
+ }]
314
+ };
315
+ });
316
+ return /*#__PURE__*/_jsx(Animated.View, {
317
+ style: [{
318
+ flex: compact ? undefined : 1,
319
+ width: compact ? 5 : undefined,
320
+ height: barHeight,
321
+ borderRadius: 999,
322
+ backgroundColor: track,
323
+ overflow: "hidden"
324
+ }, popStyle],
325
+ children: /*#__PURE__*/_jsx(Animated.View, {
326
+ style: [{
327
+ position: "absolute",
328
+ top: 0,
329
+ left: 0,
330
+ right: 0,
331
+ bottom: 0,
332
+ backgroundColor: color
333
+ }, colorStyle]
334
+ })
335
+ });
336
+ }
337
+ function Track({
338
+ items,
339
+ level,
340
+ width,
341
+ height,
342
+ fills,
343
+ palette,
344
+ compact,
345
+ segmentStyle,
346
+ levelIcon
347
+ }) {
348
+ const count = items.length;
349
+ const segment = width / Math.max(1, count);
350
+ const radius = height / 2;
351
+ const inputs = items.map((_, position) => position);
352
+ const fillStyle = useAnimatedStyle(() => ({
353
+ width: Math.max(height, segment * (level.value + 1)),
354
+ backgroundColor: count > 1 ? interpolateColor(level.value, inputs, fills) : fills[0]
355
+ }));
356
+ const clipStyle = useAnimatedStyle(() => ({
357
+ width: Math.max(height, segment * (level.value + 1))
358
+ }));
359
+ const labels = color => items.map((item, position) => /*#__PURE__*/_jsx(View, {
360
+ style: {
361
+ width: segment,
362
+ alignItems: "center",
363
+ justifyContent: "center"
364
+ },
365
+ children: levelIcon ? levelIcon(position, color) : /*#__PURE__*/_jsx(Text, {
366
+ numberOfLines: 1,
367
+ style: [segmentStyle, {
368
+ color
369
+ }],
370
+ children: item.label
371
+ })
372
+ }, `${position}-${item.label}`));
373
+ return /*#__PURE__*/_jsxs(View, {
374
+ style: {
375
+ height,
376
+ borderRadius: radius,
377
+ borderCurve: "continuous",
378
+ backgroundColor: palette.surface,
379
+ overflow: "hidden"
380
+ },
381
+ children: [!compact ? items.slice(1).map((_, position) => /*#__PURE__*/_jsx(View, {
382
+ style: {
383
+ position: "absolute",
384
+ top: height * 0.3,
385
+ bottom: height * 0.3,
386
+ left: segment * (position + 1),
387
+ width: 1,
388
+ backgroundColor: withAlpha(palette.text, 0.1)
389
+ }
390
+ }, position)) : null, !compact && width > 0 ? /*#__PURE__*/_jsx(View, {
391
+ style: {
392
+ position: "absolute",
393
+ top: 0,
394
+ left: 0,
395
+ bottom: 0,
396
+ flexDirection: "row"
397
+ },
398
+ children: labels(palette.textSecondary)
399
+ }) : null, /*#__PURE__*/_jsx(Animated.View, {
400
+ style: [{
401
+ position: "absolute",
402
+ top: 0,
403
+ left: 0,
404
+ bottom: 0,
405
+ borderRadius: radius,
406
+ borderCurve: "continuous"
407
+ }, fillStyle]
408
+ }), !compact && width > 0 ? /*#__PURE__*/_jsx(Animated.View, {
409
+ style: [{
410
+ position: "absolute",
411
+ top: 0,
412
+ left: 0,
413
+ bottom: 0,
414
+ overflow: "hidden"
415
+ }, clipStyle],
416
+ children: /*#__PURE__*/_jsx(View, {
417
+ style: {
418
+ flexDirection: "row",
419
+ height,
420
+ width
421
+ },
422
+ children: labels(palette.background)
423
+ })
424
+ }) : null]
425
+ });
426
+ }
427
+ function LevelLabel({
428
+ label,
429
+ position,
430
+ level,
431
+ on,
432
+ off,
433
+ segmentStyle,
434
+ align = "center",
435
+ style
436
+ }) {
437
+ const colorStyle = useAnimatedStyle(() => ({
438
+ color: interpolateColor(Math.min(1, Math.abs(level.value - position)), [0, 1], [on, off])
439
+ }));
440
+ return /*#__PURE__*/_jsx(View, {
441
+ style: style,
442
+ children: /*#__PURE__*/_jsx(Animated.Text, {
443
+ numberOfLines: 1,
444
+ style: [segmentStyle, {
445
+ textAlign: align
446
+ }, colorStyle],
447
+ children: label
448
+ })
449
+ });
450
+ }
451
+ function LevelGlyph({
452
+ position,
453
+ level,
454
+ render,
455
+ on,
456
+ off
457
+ }) {
458
+ const onStyle = useAnimatedStyle(() => ({
459
+ opacity: 1 - Math.min(1, Math.abs(level.value - position))
460
+ }));
461
+ return /*#__PURE__*/_jsxs(View, {
462
+ style: {
463
+ alignItems: "center",
464
+ justifyContent: "center"
465
+ },
466
+ children: [render(position, off), /*#__PURE__*/_jsx(Animated.View, {
467
+ style: [{
468
+ position: "absolute"
469
+ }, onStyle],
470
+ children: render(position, on)
471
+ })]
472
+ });
473
+ }
474
+ function Segmented({
475
+ items,
476
+ level,
477
+ width,
478
+ height,
479
+ fills,
480
+ custom,
481
+ palette,
482
+ compact,
483
+ segmentStyle,
484
+ levelIcon
485
+ }) {
486
+ const count = items.length;
487
+ const inset = compact ? 2 : 3;
488
+ const radius = height / 2;
489
+ const segment = Math.max(0, (width - inset * 2) / Math.max(1, count));
490
+ const inputs = items.map((_, position) => position);
491
+ const thumbStyle = useAnimatedStyle(() => ({
492
+ transform: [{
493
+ translateX: segment * level.value
494
+ }],
495
+ backgroundColor: custom ? count > 1 ? interpolateColor(level.value, inputs, fills) : fills[0] : compact ? palette.text : palette.card
496
+ }));
497
+ return /*#__PURE__*/_jsxs(View, {
498
+ style: {
499
+ height,
500
+ flexDirection: "row",
501
+ padding: inset,
502
+ borderRadius: radius,
503
+ borderCurve: "continuous",
504
+ backgroundColor: palette.surface
505
+ },
506
+ children: [width > 0 ? /*#__PURE__*/_jsx(Animated.View, {
507
+ style: [{
508
+ position: "absolute",
509
+ top: inset,
510
+ left: inset,
511
+ bottom: inset,
512
+ width: segment,
513
+ borderRadius: radius - inset,
514
+ borderCurve: "continuous"
515
+ }, !custom && !compact ? {
516
+ shadowColor: "#000000",
517
+ shadowOpacity: 0.1,
518
+ shadowRadius: 6,
519
+ shadowOffset: {
520
+ width: 0,
521
+ height: 2
522
+ }
523
+ } : null, thumbStyle]
524
+ }) : null, !compact && levelIcon ? items.map((item, position) => /*#__PURE__*/_jsx(View, {
525
+ style: {
526
+ flex: 1,
527
+ alignItems: "center",
528
+ justifyContent: "center"
529
+ },
530
+ children: /*#__PURE__*/_jsx(LevelGlyph, {
531
+ position: position,
532
+ level: level,
533
+ render: levelIcon,
534
+ on: custom ? palette.background : palette.text,
535
+ off: palette.textSecondary
536
+ })
537
+ }, `${position}-${item.label}`)) : null, !compact && !levelIcon ? items.map((item, position) => /*#__PURE__*/_jsx(LevelLabel, {
538
+ label: item.label,
539
+ position: position,
540
+ level: level,
541
+ on: custom ? palette.background : palette.text,
542
+ off: palette.textSecondary,
543
+ segmentStyle: segmentStyle,
544
+ style: {
545
+ flex: 1,
546
+ alignItems: "center",
547
+ justifyContent: "center"
548
+ }
549
+ }, `${position}-${item.label}`)) : null]
550
+ });
551
+ }
552
+ function Slider({
553
+ count,
554
+ label,
555
+ index,
556
+ tabLabel,
557
+ levelIcon,
558
+ knob,
559
+ pressed,
560
+ width,
561
+ track,
562
+ fills,
563
+ palette,
564
+ reduceMotion,
565
+ segmentStyle
566
+ }) {
567
+ const span = Math.max(0, width - SLIDER_RIM * 2 - track);
568
+ const radius = track / 2;
569
+ const edge = radius;
570
+ const tabWidth = useSharedValue(0);
571
+ const inputs = Array.from({
572
+ length: count
573
+ }, (_, position) => position);
574
+ const knobFrame = useDerivedValue(() => {
575
+ const size = track * (1 + pressed.value * (SLIDER_STRETCH - 1));
576
+ const center = SLIDER_RIM + track / 2 + knob.value * span;
577
+ const left = Math.min(Math.max(center - size / 2, SLIDER_RIM), Math.max(SLIDER_RIM, width - SLIDER_RIM - size));
578
+ return {
579
+ left,
580
+ size,
581
+ center
582
+ };
583
+ });
584
+ const fillStyle = useAnimatedStyle(() => ({
585
+ width: knobFrame.value.left + knobFrame.value.size + SLIDER_RIM,
586
+ backgroundColor: count > 1 ? interpolateColor(knob.value * (count - 1), inputs, fills) : fills[0]
587
+ }));
588
+ const knobStyle = useAnimatedStyle(() => ({
589
+ width: knobFrame.value.size,
590
+ transform: [{
591
+ translateX: knobFrame.value.left
592
+ }]
593
+ }));
594
+ const tabStyle = useAnimatedStyle(() => {
595
+ const wanted = knobFrame.value.center - tabWidth.value / 2;
596
+ const left = Math.min(Math.max(wanted, edge), Math.max(edge, width - edge - tabWidth.value));
597
+ return {
598
+ opacity: tabWidth.value > 0 ? 1 : 0,
599
+ transform: [{
600
+ translateX: left
601
+ }]
602
+ };
603
+ });
604
+ if (width === 0) return /*#__PURE__*/_jsx(View, {
605
+ style: {
606
+ height: SLIDER_TAB + track
607
+ }
608
+ });
609
+ return /*#__PURE__*/_jsxs(View, {
610
+ style: {
611
+ height: SLIDER_TAB + track
612
+ },
613
+ children: [/*#__PURE__*/_jsxs(Animated.View, {
614
+ onLayout: event => {
615
+ tabWidth.value = event.nativeEvent.layout.width;
616
+ },
617
+ style: [{
618
+ position: "absolute",
619
+ top: 0,
620
+ left: 0
621
+ }, tabStyle],
622
+ children: [/*#__PURE__*/_jsxs(View, {
623
+ style: {
624
+ height: SLIDER_TAB + 1,
625
+ paddingHorizontal: 12,
626
+ paddingBottom: 1,
627
+ flexDirection: "row",
628
+ alignItems: "center",
629
+ gap: 5,
630
+ borderTopLeftRadius: SLIDER_TAB_RADIUS,
631
+ borderTopRightRadius: SLIDER_TAB_RADIUS,
632
+ borderCurve: "continuous",
633
+ backgroundColor: palette.surface
634
+ },
635
+ children: [tabLabel ? /*#__PURE__*/_jsx(Text, {
636
+ style: [segmentStyle, {
637
+ color: palette.text,
638
+ fontWeight: "700"
639
+ }],
640
+ children: tabLabel
641
+ }) : null, levelIcon ? /*#__PURE__*/_jsx(Animated.View, {
642
+ entering: reduceMotion ? undefined : FadeIn.duration(200).easing(EASE_OUT),
643
+ children: levelIcon(index, palette.textSecondary)
644
+ }, index) : /*#__PURE__*/_jsx(Animated.Text, {
645
+ entering: reduceMotion ? undefined : FadeIn.duration(200).easing(EASE_OUT),
646
+ style: [segmentStyle, {
647
+ color: palette.textSecondary,
648
+ fontWeight: "500"
649
+ }],
650
+ children: label
651
+ }, index)]
652
+ }), /*#__PURE__*/_jsx(Shoulder, {
653
+ side: "left",
654
+ color: palette.surface
655
+ }), /*#__PURE__*/_jsx(Shoulder, {
656
+ side: "right",
657
+ color: palette.surface
658
+ })]
659
+ }), /*#__PURE__*/_jsxs(View, {
660
+ style: {
661
+ position: "absolute",
662
+ top: SLIDER_TAB,
663
+ left: 0,
664
+ right: 0,
665
+ height: track,
666
+ borderRadius: radius,
667
+ borderCurve: "continuous",
668
+ backgroundColor: palette.surface,
669
+ overflow: "hidden"
670
+ },
671
+ children: [/*#__PURE__*/_jsx(Animated.View, {
672
+ style: [{
673
+ position: "absolute",
674
+ top: 0,
675
+ left: 0,
676
+ bottom: 0,
677
+ borderRadius: radius,
678
+ borderCurve: "continuous"
679
+ }, fillStyle]
680
+ }), inputs.map(position => /*#__PURE__*/_jsx(Stop, {
681
+ position: position,
682
+ count: count,
683
+ knob: knob,
684
+ left: SLIDER_RIM + track / 2 + (count > 1 ? span * position / (count - 1) : 0),
685
+ size: Math.round(track * 0.3),
686
+ on: withAlpha(palette.card, 0.55),
687
+ off: withAlpha(palette.text, 0.18)
688
+ }, position)), /*#__PURE__*/_jsx(Animated.View, {
689
+ style: [{
690
+ position: "absolute",
691
+ top: SLIDER_RIM,
692
+ left: 0,
693
+ height: track - SLIDER_RIM * 2,
694
+ borderRadius: radius - SLIDER_RIM,
695
+ borderCurve: "continuous",
696
+ backgroundColor: palette.card,
697
+ shadowColor: "#000000",
698
+ shadowOpacity: 0.12,
699
+ shadowRadius: 4,
700
+ shadowOffset: {
701
+ width: 0,
702
+ height: 1
703
+ }
704
+ }, knobStyle]
705
+ })]
706
+ })]
707
+ });
708
+ }
709
+ function Shoulder({
710
+ side,
711
+ color
712
+ }) {
713
+ const size = SLIDER_SHOULDER;
714
+ return /*#__PURE__*/_jsx(View, {
715
+ style: [{
716
+ position: "absolute",
717
+ bottom: 0,
718
+ width: size,
719
+ height: size,
720
+ overflow: "hidden"
721
+ }, side === "left" ? {
722
+ left: -size
723
+ } : {
724
+ right: -size
725
+ }],
726
+ children: /*#__PURE__*/_jsx(View, {
727
+ style: {
728
+ position: "absolute",
729
+ top: -size * 2,
730
+ left: side === "left" ? -size * 2 : -size,
731
+ width: size * 4,
732
+ height: size * 4,
733
+ borderRadius: size * 2,
734
+ borderWidth: size,
735
+ borderColor: color
736
+ }
737
+ })
738
+ });
739
+ }
740
+ function CompactSlider({
741
+ count,
742
+ knob,
743
+ width,
744
+ knobSize,
745
+ fills,
746
+ palette
747
+ }) {
748
+ const inset = knobSize / 2;
749
+ const span = Math.max(0, width - knobSize);
750
+ const inputs = Array.from({
751
+ length: count
752
+ }, (_, position) => position);
753
+ const fillStyle = useAnimatedStyle(() => ({
754
+ width: inset + span * knob.value,
755
+ backgroundColor: count > 1 ? interpolateColor(knob.value * (count - 1), inputs, fills) : fills[0]
756
+ }));
757
+ const knobStyle = useAnimatedStyle(() => ({
758
+ transform: [{
759
+ translateX: span * knob.value
760
+ }]
761
+ }));
762
+ return /*#__PURE__*/_jsxs(View, {
763
+ style: {
764
+ height: knobSize,
765
+ justifyContent: "center"
766
+ },
767
+ children: [/*#__PURE__*/_jsx(View, {
768
+ style: {
769
+ height: 4,
770
+ borderRadius: 2,
771
+ backgroundColor: palette.surface,
772
+ overflow: "hidden"
773
+ },
774
+ children: width > 0 ? /*#__PURE__*/_jsx(Animated.View, {
775
+ style: [{
776
+ position: "absolute",
777
+ top: 0,
778
+ left: 0,
779
+ bottom: 0,
780
+ borderRadius: 2
781
+ }, fillStyle]
782
+ }) : null
783
+ }), width > 0 ? /*#__PURE__*/_jsx(Animated.View, {
784
+ style: [{
785
+ position: "absolute",
786
+ top: 0,
787
+ left: 0,
788
+ width: knobSize,
789
+ height: knobSize,
790
+ borderRadius: knobSize / 2,
791
+ backgroundColor: palette.card,
792
+ borderWidth: 1,
793
+ borderColor: withAlpha(palette.text, 0.08),
794
+ shadowColor: "#000000",
795
+ shadowOpacity: 0.08,
796
+ shadowRadius: 2,
797
+ shadowOffset: {
798
+ width: 0,
799
+ height: 1
800
+ }
801
+ }, knobStyle]
802
+ }) : null]
803
+ });
804
+ }
805
+ function Stop({
806
+ position,
807
+ count,
808
+ knob,
809
+ left,
810
+ size,
811
+ on,
812
+ off
813
+ }) {
814
+ const colorStyle = useAnimatedStyle(() => ({
815
+ backgroundColor: interpolateColor(Math.min(1, Math.max(0, knob.value * (count - 1) - position + 0.5)), [0, 1], [off, on])
816
+ }));
817
+ return /*#__PURE__*/_jsx(Animated.View, {
818
+ style: [{
819
+ position: "absolute",
820
+ left: left - 1,
821
+ top: "50%",
822
+ marginTop: -size / 2,
823
+ width: 2,
824
+ height: size,
825
+ borderRadius: 1
826
+ }, colorStyle]
827
+ });
828
+ }
829
+ export function EffortBars(props) {
830
+ return /*#__PURE__*/_jsx(EffortBar, {
831
+ ...props,
832
+ variant: "bars"
833
+ });
834
+ }
835
+ export function EffortTrack(props) {
836
+ return /*#__PURE__*/_jsx(EffortBar, {
837
+ ...props,
838
+ variant: "track"
839
+ });
840
+ }
841
+ export function EffortSegmented(props) {
842
+ return /*#__PURE__*/_jsx(EffortBar, {
843
+ ...props,
844
+ variant: "segmented"
845
+ });
846
+ }
847
+ export function EffortSlider(props) {
848
+ return /*#__PURE__*/_jsx(EffortBar, {
849
+ ...props,
850
+ variant: "slider"
851
+ });
852
+ }
853
+ //# sourceMappingURL=effort-bar.js.map