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,720 @@
1
+ "use strict";
2
+
3
+ import { forwardRef, useEffect, useImperativeHandle, useMemo, useRef, useState } from "react";
4
+ import { Pressable, Text, TextInput, View } from "react-native";
5
+ import Animated, { Easing, FadeIn, FadeOut, interpolateColor, useAnimatedStyle, useReducedMotion, useSharedValue, withSequence, withSpring, withTiming, ZoomIn, ZoomOut } from "react-native-reanimated";
6
+ import { scheduleOnRN } from "react-native-worklets";
7
+ import { withAlpha } from "../internal/color.js";
8
+ import { useMotionPalette } from "../theme/provider.js";
9
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
10
+ const EASE_OUT = Easing.bezier(0.22, 1, 0.36, 1);
11
+ const ENTER_SPRING = {
12
+ damping: 24,
13
+ stiffness: 220,
14
+ mass: 0.9
15
+ };
16
+ const HEIGHT_SPRING = {
17
+ damping: 28,
18
+ stiffness: 260,
19
+ mass: 0.9
20
+ };
21
+ const CHIP_SPRING = {
22
+ damping: 14,
23
+ stiffness: 420,
24
+ mass: 0.6
25
+ };
26
+ const PAGE_OUT = 110;
27
+ const PAGE_IN = 240;
28
+ const PAGE_SHIFT = 12;
29
+ const ADVANCE_DELAY = 260;
30
+ const CHIP = 26;
31
+ const DEFAULT_TITLE_STYLE = {
32
+ fontSize: 19,
33
+ lineHeight: 25,
34
+ fontWeight: "500"
35
+ };
36
+ const DEFAULT_OPTION_STYLE = {
37
+ fontSize: 16,
38
+ lineHeight: 22
39
+ };
40
+ const DEFAULT_META_STYLE = {
41
+ fontSize: 13,
42
+ lineHeight: 18,
43
+ fontWeight: "500"
44
+ };
45
+ const DEFAULT_LABELS = {
46
+ progress: (current, total) => `${current} of ${total}`,
47
+ next: "Continue",
48
+ submit: "Send",
49
+ customPlaceholder: "Type your answer...",
50
+ sent: "Answers sent"
51
+ };
52
+ const emptyDraft = () => ({
53
+ selected: [],
54
+ custom: ""
55
+ });
56
+ function normalize(option) {
57
+ return typeof option === "string" ? {
58
+ label: option
59
+ } : option;
60
+ }
61
+ function isAnswered(draft) {
62
+ return !!draft && (draft.selected.length > 0 || draft.custom.trim().length > 0);
63
+ }
64
+ function buildAnswers(questions, drafts) {
65
+ return questions.map((question, index) => {
66
+ const draft = drafts[index] ?? emptyDraft();
67
+ const options = question.options.map(normalize);
68
+ const custom = draft.custom.trim();
69
+ return {
70
+ question: question.title,
71
+ selected: draft.selected,
72
+ labels: draft.selected.map(position => options[position]?.label ?? ""),
73
+ ...(custom ? {
74
+ custom
75
+ } : {})
76
+ };
77
+ });
78
+ }
79
+ export const QuestionCard = /*#__PURE__*/forwardRef(function QuestionCard({
80
+ questions,
81
+ variant = "card",
82
+ labels,
83
+ icons,
84
+ numbered = true,
85
+ autoAdvance = true,
86
+ autoSubmit = true,
87
+ showSentState = true,
88
+ onSubmit,
89
+ onClose,
90
+ onAnswerChange,
91
+ onHaptic,
92
+ renderOption,
93
+ fontFamily,
94
+ titleStyle: titleStyleProp = DEFAULT_TITLE_STYLE,
95
+ optionStyle: optionStyleProp = DEFAULT_OPTION_STYLE,
96
+ metaStyle: metaStyleProp = DEFAULT_META_STYLE,
97
+ colors,
98
+ style
99
+ }, ref) {
100
+ const font = fontFamily ? {
101
+ fontFamily
102
+ } : null;
103
+ const titleStyle = [titleStyleProp, font];
104
+ const optionStyle = [optionStyleProp, font];
105
+ const metaStyle = [metaStyleProp, font];
106
+ const palette = useMotionPalette(colors);
107
+ const reduceMotion = useReducedMotion();
108
+ const copy = {
109
+ ...DEFAULT_LABELS,
110
+ ...labels
111
+ };
112
+ const [page, setPage] = useState(0);
113
+ const [shown, setShown] = useState(0);
114
+ const [drafts, setDrafts] = useState(() => questions.map(emptyDraft));
115
+ const [sent, setSent] = useState(false);
116
+ const draftsRef = useRef(drafts);
117
+ draftsRef.current = drafts;
118
+ const timer = useRef(null);
119
+ const enter = useSharedValue(reduceMotion ? 1 : 0);
120
+ const contentOpacity = useSharedValue(1);
121
+ const contentShift = useSharedValue(0);
122
+ const height = useSharedValue(0);
123
+ const measured = useRef(0);
124
+ useEffect(() => {
125
+ enter.value = reduceMotion ? 1 : withSpring(1, ENTER_SPRING);
126
+ }, [enter, reduceMotion]);
127
+ useEffect(() => () => {
128
+ if (timer.current) clearTimeout(timer.current);
129
+ }, []);
130
+ const signature = questions.map(item => `${item.title}:${item.options.length}`).join("|");
131
+ const lastSignature = useRef(signature);
132
+ useEffect(() => {
133
+ if (lastSignature.current === signature) return;
134
+ lastSignature.current = signature;
135
+ setPage(0);
136
+ setShown(0);
137
+ setSent(false);
138
+ setDrafts(questions.map(emptyDraft));
139
+ }, [questions, signature]);
140
+ useEffect(() => {
141
+ if (page === shown) return;
142
+ const direction = page > shown ? 1 : -1;
143
+ if (reduceMotion) {
144
+ setShown(page);
145
+ return;
146
+ }
147
+ contentShift.value = withTiming(-direction * PAGE_SHIFT, {
148
+ duration: PAGE_OUT,
149
+ easing: Easing.in(Easing.quad)
150
+ });
151
+ contentOpacity.value = withTiming(0, {
152
+ duration: PAGE_OUT,
153
+ easing: Easing.in(Easing.quad)
154
+ }, finished => {
155
+ if (finished) scheduleOnRN(setShown, page);
156
+ });
157
+ }, [contentOpacity, contentShift, page, reduceMotion, shown]);
158
+ const firstShown = useRef(true);
159
+ useEffect(() => {
160
+ if (firstShown.current) {
161
+ firstShown.current = false;
162
+ return;
163
+ }
164
+ if (reduceMotion) return;
165
+ contentShift.value = contentShift.value < 0 ? PAGE_SHIFT : -PAGE_SHIFT;
166
+ contentShift.value = withTiming(0, {
167
+ duration: PAGE_IN,
168
+ easing: EASE_OUT
169
+ });
170
+ contentOpacity.value = withTiming(1, {
171
+ duration: PAGE_IN,
172
+ easing: EASE_OUT
173
+ });
174
+ }, [contentOpacity, contentShift, reduceMotion, shown]);
175
+ const question = questions[shown];
176
+ const kind = question?.kind ?? "single";
177
+ const draft = drafts[shown] ?? emptyDraft();
178
+ const options = useMemo(() => question?.options.map(normalize) ?? [], [question]);
179
+ const last = shown === questions.length - 1;
180
+ const hairline = withAlpha(palette.text, 0.08);
181
+ const commit = next => {
182
+ draftsRef.current = next;
183
+ setDrafts(next);
184
+ onAnswerChange?.(buildAnswers(questions, next));
185
+ };
186
+ const goTo = target => {
187
+ if (target < 0 || target >= questions.length || target === page) return;
188
+ if (timer.current) clearTimeout(timer.current);
189
+ onHaptic?.("page");
190
+ setPage(target);
191
+ };
192
+ const submit = () => {
193
+ const current = draftsRef.current;
194
+ if (!current.every(isAnswered)) return;
195
+ onHaptic?.("submit");
196
+ onSubmit(buildAnswers(questions, current));
197
+ if (showSentState) setSent(true);
198
+ };
199
+ const select = index => {
200
+ onHaptic?.("select");
201
+ const selected = kind === "single" ? [index] : draft.selected.includes(index) ? draft.selected.filter(value => value !== index) : [...draft.selected, index].sort((a, b) => a - b);
202
+ commit(drafts.map((item, position) => position === shown ? {
203
+ selected,
204
+ custom: kind === "single" ? "" : item.custom
205
+ } : item));
206
+ if (kind !== "single") return;
207
+ if (timer.current) clearTimeout(timer.current);
208
+ if (!last && autoAdvance) {
209
+ timer.current = setTimeout(() => goTo(shown + 1), ADVANCE_DELAY);
210
+ } else if (last && autoSubmit) {
211
+ timer.current = setTimeout(submit, ADVANCE_DELAY);
212
+ }
213
+ };
214
+ const setCustom = value => {
215
+ commit(drafts.map((item, position) => position === shown ? {
216
+ selected: kind === "single" && value ? [] : item.selected,
217
+ custom: value
218
+ } : item));
219
+ };
220
+ const sendCustom = () => {
221
+ if (!draft.custom.trim()) return;
222
+ if (last) submit();else goTo(shown + 1);
223
+ };
224
+ useImperativeHandle(ref, () => ({
225
+ select,
226
+ goTo,
227
+ submit
228
+ }));
229
+ const handleLayout = event => {
230
+ const next = Math.ceil(event.nativeEvent.layout.height);
231
+ if (next === measured.current) return;
232
+ const initial = measured.current === 0;
233
+ measured.current = next;
234
+ height.value = initial || reduceMotion ? next : withSpring(next, HEIGHT_SPRING);
235
+ };
236
+ const shellStyle = useAnimatedStyle(() => ({
237
+ opacity: Math.min(1, enter.value * 1.6),
238
+ transform: [{
239
+ translateY: (1 - enter.value) * 22
240
+ }, {
241
+ scale: 0.985 + enter.value * 0.015
242
+ }]
243
+ }));
244
+ const clipStyle = useAnimatedStyle(() => height.value > 0 ? {
245
+ height: height.value
246
+ } : {});
247
+ const contentStyle = useAnimatedStyle(() => ({
248
+ opacity: contentOpacity.value,
249
+ transform: [{
250
+ translateX: contentShift.value
251
+ }]
252
+ }));
253
+ const radius = variant === "card" ? 26 : 0;
254
+ const container = variant === "card" ? {
255
+ borderRadius: radius,
256
+ borderCurve: "continuous",
257
+ backgroundColor: palette.card,
258
+ borderWidth: 1,
259
+ borderColor: withAlpha(palette.text, 0.06),
260
+ shadowColor: "#000000",
261
+ shadowOpacity: 0.08,
262
+ shadowRadius: 22,
263
+ shadowOffset: {
264
+ width: 0,
265
+ height: 8
266
+ }
267
+ } : {};
268
+ const sheet = variant === "sheet";
269
+ const padding = sheet ? {
270
+ paddingHorizontal: 20,
271
+ paddingTop: 12,
272
+ paddingBottom: 16
273
+ } : {
274
+ paddingHorizontal: 16,
275
+ paddingTop: 12,
276
+ paddingBottom: 12
277
+ };
278
+ const showFooter = kind === "multiple" && draft.selected.length > 0;
279
+ return /*#__PURE__*/_jsx(Animated.View, {
280
+ style: [container, shellStyle, style],
281
+ children: /*#__PURE__*/_jsx(Animated.View, {
282
+ style: [{
283
+ overflow: "hidden",
284
+ borderRadius: radius
285
+ }, sheet ? null : clipStyle],
286
+ children: /*#__PURE__*/_jsx(View, {
287
+ onLayout: sheet ? undefined : handleLayout,
288
+ style: [padding, sheet ? null : {
289
+ position: "absolute",
290
+ top: 0,
291
+ left: 0,
292
+ right: 0
293
+ }],
294
+ children: sent ? /*#__PURE__*/_jsxs(Animated.View, {
295
+ entering: reduceMotion ? undefined : FadeIn.duration(260).easing(EASE_OUT),
296
+ style: {
297
+ flexDirection: "row",
298
+ alignItems: "center",
299
+ gap: 10,
300
+ paddingVertical: 10
301
+ },
302
+ children: [/*#__PURE__*/_jsx(Animated.View, {
303
+ entering: reduceMotion ? undefined : ZoomIn.springify().damping(14).stiffness(320),
304
+ style: {
305
+ width: CHIP,
306
+ height: CHIP,
307
+ borderRadius: CHIP / 2,
308
+ alignItems: "center",
309
+ justifyContent: "center",
310
+ backgroundColor: palette.success
311
+ },
312
+ children: icons?.sent ?? /*#__PURE__*/_jsx(Text, {
313
+ style: {
314
+ color: palette.accentContrast,
315
+ fontSize: 13,
316
+ fontWeight: "700"
317
+ },
318
+ children: "\u2713"
319
+ })
320
+ }), /*#__PURE__*/_jsx(Text, {
321
+ style: [optionStyle, {
322
+ color: palette.text,
323
+ fontWeight: "500"
324
+ }],
325
+ children: copy.sent
326
+ })]
327
+ }) : question ? /*#__PURE__*/_jsxs(_Fragment, {
328
+ children: [/*#__PURE__*/_jsxs(View, {
329
+ style: {
330
+ flexDirection: "row",
331
+ alignItems: "center",
332
+ minHeight: 32
333
+ },
334
+ children: [questions.length > 1 ? /*#__PURE__*/_jsxs(View, {
335
+ style: {
336
+ flexDirection: "row",
337
+ alignItems: "center",
338
+ marginLeft: -8
339
+ },
340
+ children: [/*#__PURE__*/_jsx(IconButton, {
341
+ label: "Previous question",
342
+ disabled: page === 0,
343
+ onPress: () => goTo(page - 1),
344
+ children: icons?.previous ?? /*#__PURE__*/_jsx(Text, {
345
+ style: [metaStyle, {
346
+ color: palette.textSecondary,
347
+ fontSize: 18,
348
+ fontWeight: "400"
349
+ }],
350
+ children: "\u2039"
351
+ })
352
+ }), /*#__PURE__*/_jsx(Text, {
353
+ style: [metaStyle, {
354
+ color: palette.textSecondary,
355
+ fontVariant: ["tabular-nums"]
356
+ }],
357
+ children: copy.progress(page + 1, questions.length)
358
+ }), /*#__PURE__*/_jsx(IconButton, {
359
+ label: "Next question",
360
+ disabled: page === questions.length - 1 || !isAnswered(drafts[page]),
361
+ onPress: () => goTo(page + 1),
362
+ children: icons?.next ?? /*#__PURE__*/_jsx(Text, {
363
+ style: [metaStyle, {
364
+ color: palette.textSecondary,
365
+ fontSize: 18,
366
+ fontWeight: "400"
367
+ }],
368
+ children: "\u203A"
369
+ })
370
+ })]
371
+ }) : null, /*#__PURE__*/_jsx(View, {
372
+ style: {
373
+ flex: 1
374
+ }
375
+ }), onClose ? /*#__PURE__*/_jsx(View, {
376
+ style: {
377
+ marginRight: -8
378
+ },
379
+ children: /*#__PURE__*/_jsx(IconButton, {
380
+ label: "Close",
381
+ onPress: onClose,
382
+ children: icons?.close ?? /*#__PURE__*/_jsx(Text, {
383
+ style: [metaStyle, {
384
+ color: palette.textSecondary,
385
+ fontSize: 18,
386
+ fontWeight: "400"
387
+ }],
388
+ children: "\xD7"
389
+ })
390
+ })
391
+ }) : null]
392
+ }), /*#__PURE__*/_jsxs(Animated.View, {
393
+ style: contentStyle,
394
+ children: [/*#__PURE__*/_jsx(Text, {
395
+ accessibilityRole: "header",
396
+ style: [titleStyle, {
397
+ color: palette.text,
398
+ marginTop: 4,
399
+ marginBottom: 8
400
+ }],
401
+ children: question.title
402
+ }), /*#__PURE__*/_jsxs(View, {
403
+ accessibilityRole: kind === "single" ? "radiogroup" : undefined,
404
+ children: [options.map((option, index) => /*#__PURE__*/_jsx(OptionRow, {
405
+ label: option.label,
406
+ description: option.description,
407
+ index: index,
408
+ kind: kind,
409
+ selected: draft.selected.includes(index),
410
+ divider: index > 0,
411
+ numbered: numbered,
412
+ palette: palette,
413
+ hairline: hairline,
414
+ optionStyle: optionStyle,
415
+ metaStyle: metaStyle,
416
+ checkIcon: icons?.check,
417
+ animate: !reduceMotion,
418
+ renderOption: renderOption,
419
+ onPress: () => select(index)
420
+ }, `${shown}-${index}`)), question.allowCustom !== false ? /*#__PURE__*/_jsxs(View, {
421
+ style: {
422
+ flexDirection: "row",
423
+ alignItems: "center",
424
+ gap: 12,
425
+ minHeight: 50,
426
+ marginHorizontal: -8,
427
+ paddingHorizontal: 8
428
+ },
429
+ children: [options.length ? /*#__PURE__*/_jsx(View, {
430
+ style: {
431
+ position: "absolute",
432
+ top: 0,
433
+ left: numbered ? CHIP + 20 : 8,
434
+ right: 8,
435
+ height: 1,
436
+ backgroundColor: hairline
437
+ }
438
+ }) : null, numbered ? /*#__PURE__*/_jsx(View, {
439
+ style: {
440
+ width: CHIP,
441
+ height: CHIP,
442
+ borderRadius: 8,
443
+ alignItems: "center",
444
+ justifyContent: "center",
445
+ backgroundColor: palette.surface
446
+ },
447
+ children: icons?.custom ?? /*#__PURE__*/_jsx(Text, {
448
+ style: [metaStyle, {
449
+ color: palette.textSecondary
450
+ }],
451
+ children: "\u270E"
452
+ })
453
+ }) : null, /*#__PURE__*/_jsx(TextInput, {
454
+ value: draft.custom,
455
+ onChangeText: setCustom,
456
+ placeholder: copy.customPlaceholder,
457
+ placeholderTextColor: palette.textTertiary,
458
+ returnKeyType: last ? "send" : "next",
459
+ onSubmitEditing: sendCustom,
460
+ style: [optionStyle, {
461
+ flex: 1,
462
+ color: palette.text,
463
+ paddingVertical: 12
464
+ }]
465
+ }), draft.custom.trim() ? /*#__PURE__*/_jsx(Animated.View, {
466
+ entering: reduceMotion ? undefined : ZoomIn.springify().damping(15).stiffness(340),
467
+ exiting: reduceMotion ? undefined : ZoomOut.duration(140),
468
+ children: /*#__PURE__*/_jsx(Pressable, {
469
+ onPress: sendCustom,
470
+ accessibilityRole: "button",
471
+ accessibilityLabel: last ? copy.submit : copy.next,
472
+ hitSlop: 6,
473
+ style: ({
474
+ pressed
475
+ }) => ({
476
+ width: 32,
477
+ height: 32,
478
+ borderRadius: 16,
479
+ alignItems: "center",
480
+ justifyContent: "center",
481
+ backgroundColor: palette.accent,
482
+ opacity: pressed ? 0.8 : 1
483
+ }),
484
+ children: icons?.send ?? /*#__PURE__*/_jsx(Text, {
485
+ style: {
486
+ color: palette.accentContrast,
487
+ fontSize: 16,
488
+ fontWeight: "700"
489
+ },
490
+ children: "\u2191"
491
+ })
492
+ })
493
+ }) : null]
494
+ }) : null]
495
+ }), showFooter ? /*#__PURE__*/_jsx(Animated.View, {
496
+ entering: reduceMotion ? undefined : FadeIn.duration(200).easing(EASE_OUT),
497
+ exiting: reduceMotion ? undefined : FadeOut.duration(120),
498
+ style: {
499
+ alignItems: "flex-end",
500
+ paddingTop: 8
501
+ },
502
+ children: /*#__PURE__*/_jsx(Pressable, {
503
+ onPress: () => last ? submit() : goTo(shown + 1),
504
+ accessibilityRole: "button",
505
+ style: ({
506
+ pressed
507
+ }) => ({
508
+ paddingHorizontal: 18,
509
+ height: 38,
510
+ borderRadius: 19,
511
+ justifyContent: "center",
512
+ backgroundColor: palette.text,
513
+ opacity: pressed ? 0.85 : 1
514
+ }),
515
+ children: /*#__PURE__*/_jsx(Text, {
516
+ style: [metaStyle, {
517
+ color: palette.background,
518
+ fontSize: 15,
519
+ fontWeight: "600"
520
+ }],
521
+ children: last ? copy.submit : copy.next
522
+ })
523
+ })
524
+ }) : null]
525
+ })]
526
+ }) : null
527
+ })
528
+ })
529
+ });
530
+ });
531
+ function IconButton({
532
+ label,
533
+ disabled,
534
+ onPress,
535
+ children
536
+ }) {
537
+ return /*#__PURE__*/_jsx(Pressable, {
538
+ onPress: onPress,
539
+ disabled: disabled,
540
+ hitSlop: 6,
541
+ accessibilityRole: "button",
542
+ accessibilityLabel: label,
543
+ accessibilityState: {
544
+ disabled: !!disabled
545
+ },
546
+ style: {
547
+ width: 30,
548
+ height: 30,
549
+ alignItems: "center",
550
+ justifyContent: "center",
551
+ opacity: disabled ? 0.28 : 1
552
+ },
553
+ children: children
554
+ });
555
+ }
556
+ function OptionRow({
557
+ label,
558
+ description,
559
+ index,
560
+ kind,
561
+ selected,
562
+ divider,
563
+ numbered,
564
+ palette,
565
+ hairline,
566
+ optionStyle,
567
+ metaStyle,
568
+ checkIcon,
569
+ animate,
570
+ renderOption,
571
+ onPress
572
+ }) {
573
+ const pop = useSharedValue(1);
574
+ const fill = useSharedValue(selected ? 1 : 0);
575
+ const pressed = useSharedValue(0);
576
+ const rest = withAlpha(palette.text, 0);
577
+ const press = withAlpha(palette.text, 0.05);
578
+ useEffect(() => {
579
+ fill.value = animate ? withTiming(selected ? 1 : 0, {
580
+ duration: 180,
581
+ easing: EASE_OUT
582
+ }) : selected ? 1 : 0;
583
+ if (selected && animate) pop.value = withSequence(withTiming(0.86, {
584
+ duration: 70
585
+ }), withSpring(1, CHIP_SPRING));
586
+ }, [animate, fill, pop, selected]);
587
+ const chipStyle = useAnimatedStyle(() => ({
588
+ transform: [{
589
+ scale: pop.value
590
+ }]
591
+ }));
592
+ const chipFill = useAnimatedStyle(() => ({
593
+ opacity: fill.value
594
+ }));
595
+ const rowStyle = useAnimatedStyle(() => ({
596
+ backgroundColor: interpolateColor(pressed.value, [0, 1], [rest, press])
597
+ }));
598
+ return /*#__PURE__*/_jsx(Pressable, {
599
+ onPress: onPress,
600
+ onPressIn: () => {
601
+ pressed.value = withTiming(1, {
602
+ duration: 80
603
+ });
604
+ },
605
+ onPressOut: () => {
606
+ pressed.value = withTiming(0, {
607
+ duration: 220
608
+ });
609
+ },
610
+ accessibilityRole: kind === "single" ? "radio" : "checkbox",
611
+ accessibilityState: {
612
+ checked: selected
613
+ },
614
+ accessibilityLabel: label,
615
+ children: /*#__PURE__*/_jsxs(Animated.View, {
616
+ style: [{
617
+ flexDirection: "row",
618
+ alignItems: "center",
619
+ gap: 12,
620
+ minHeight: 50,
621
+ paddingVertical: 10,
622
+ marginHorizontal: -8,
623
+ paddingHorizontal: 8,
624
+ borderRadius: 12
625
+ }, rowStyle],
626
+ children: [divider ? /*#__PURE__*/_jsx(View, {
627
+ style: {
628
+ position: "absolute",
629
+ top: 0,
630
+ left: numbered ? CHIP + 20 : 8,
631
+ right: 8,
632
+ height: 1,
633
+ backgroundColor: hairline
634
+ }
635
+ }) : null, renderOption ? renderOption({
636
+ label,
637
+ description
638
+ }, {
639
+ index,
640
+ selected,
641
+ kind
642
+ }) : /*#__PURE__*/_jsxs(_Fragment, {
643
+ children: [numbered ? /*#__PURE__*/_jsxs(Animated.View, {
644
+ style: [{
645
+ width: CHIP,
646
+ height: CHIP,
647
+ borderRadius: 8,
648
+ alignItems: "center",
649
+ justifyContent: "center",
650
+ backgroundColor: palette.surface
651
+ }, chipStyle],
652
+ children: [/*#__PURE__*/_jsx(Animated.View, {
653
+ style: [{
654
+ position: "absolute",
655
+ top: 0,
656
+ left: 0,
657
+ right: 0,
658
+ bottom: 0,
659
+ borderRadius: 8,
660
+ backgroundColor: palette.text
661
+ }, chipFill]
662
+ }), /*#__PURE__*/_jsx(Text, {
663
+ style: [metaStyle, {
664
+ color: selected ? palette.background : palette.textSecondary,
665
+ fontVariant: ["tabular-nums"]
666
+ }],
667
+ children: index + 1
668
+ })]
669
+ }) : null, /*#__PURE__*/_jsxs(View, {
670
+ style: {
671
+ flex: 1
672
+ },
673
+ children: [/*#__PURE__*/_jsx(Text, {
674
+ style: [optionStyle, {
675
+ color: palette.text
676
+ }],
677
+ children: label
678
+ }), description ? /*#__PURE__*/_jsx(Text, {
679
+ style: [metaStyle, {
680
+ color: palette.textSecondary,
681
+ marginTop: 1,
682
+ fontWeight: "400"
683
+ }],
684
+ children: description
685
+ }) : null]
686
+ }), kind === "multiple" ? /*#__PURE__*/_jsx(View, {
687
+ style: {
688
+ width: 22,
689
+ height: 22,
690
+ borderRadius: 11,
691
+ borderWidth: selected ? 0 : 1.5,
692
+ borderColor: withAlpha(palette.text, 0.22),
693
+ backgroundColor: selected ? palette.text : "transparent",
694
+ alignItems: "center",
695
+ justifyContent: "center"
696
+ },
697
+ children: selected ? /*#__PURE__*/_jsx(Animated.View, {
698
+ entering: animate ? ZoomIn.springify().damping(14).stiffness(380) : undefined,
699
+ children: checkIcon ?? /*#__PURE__*/_jsx(Text, {
700
+ style: {
701
+ color: palette.background,
702
+ fontSize: 12,
703
+ fontWeight: "700"
704
+ },
705
+ children: "\u2713"
706
+ })
707
+ }) : null
708
+ }) : null]
709
+ })]
710
+ })
711
+ });
712
+ }
713
+ export const QuestionSheet = /*#__PURE__*/forwardRef(function QuestionSheet(props, ref) {
714
+ return /*#__PURE__*/_jsx(QuestionCard, {
715
+ ...props,
716
+ ref: ref,
717
+ variant: "sheet"
718
+ });
719
+ });
720
+ //# sourceMappingURL=question-card.js.map