@retray-dev/ui-kit 0.1.0 → 1.5.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 (56) hide show
  1. package/COMPONENTS.md +710 -0
  2. package/LICENSE +21 -0
  3. package/README.md +150 -0
  4. package/dist/index.d.mts +345 -4
  5. package/dist/index.d.ts +345 -4
  6. package/dist/index.js +1644 -58
  7. package/dist/index.mjs +1590 -58
  8. package/package.json +44 -5
  9. package/src/components/Accordion/Accordion.tsx +173 -0
  10. package/src/components/Accordion/index.ts +2 -0
  11. package/src/components/Alert/Alert.tsx +59 -0
  12. package/src/components/Alert/index.ts +2 -0
  13. package/src/components/Avatar/Avatar.tsx +71 -0
  14. package/src/components/Avatar/index.ts +2 -0
  15. package/src/components/Badge/Badge.tsx +48 -0
  16. package/src/components/Badge/index.ts +2 -0
  17. package/src/components/Button/Button.tsx +94 -45
  18. package/src/components/Card/Card.tsx +103 -0
  19. package/src/components/Card/index.ts +9 -0
  20. package/src/components/Checkbox/Checkbox.tsx +98 -0
  21. package/src/components/Checkbox/index.ts +2 -0
  22. package/src/components/EmptyState/EmptyState.tsx +67 -0
  23. package/src/components/EmptyState/index.ts +2 -0
  24. package/src/components/Input/Input.tsx +28 -35
  25. package/src/components/Progress/Progress.tsx +52 -0
  26. package/src/components/Progress/index.ts +2 -0
  27. package/src/components/RadioGroup/RadioGroup.tsx +132 -0
  28. package/src/components/RadioGroup/index.ts +2 -0
  29. package/src/components/Select/Select.tsx +232 -0
  30. package/src/components/Select/index.ts +2 -0
  31. package/src/components/Separator/Separator.tsx +33 -0
  32. package/src/components/Separator/index.ts +2 -0
  33. package/src/components/Sheet/Sheet.tsx +115 -0
  34. package/src/components/Sheet/index.ts +2 -0
  35. package/src/components/Skeleton/Skeleton.tsx +63 -0
  36. package/src/components/Skeleton/index.ts +2 -0
  37. package/src/components/Slider/Slider.tsx +143 -0
  38. package/src/components/Slider/index.ts +2 -0
  39. package/src/components/Spinner/Spinner.tsx +21 -0
  40. package/src/components/Spinner/index.ts +2 -0
  41. package/src/components/Switch/Switch.tsx +86 -0
  42. package/src/components/Switch/index.ts +2 -0
  43. package/src/components/Tabs/Tabs.tsx +196 -0
  44. package/src/components/Tabs/index.ts +2 -0
  45. package/src/components/Text/Text.tsx +10 -4
  46. package/src/components/Textarea/Textarea.tsx +89 -0
  47. package/src/components/Textarea/index.ts +2 -0
  48. package/src/components/Toast/Toast.tsx +200 -0
  49. package/src/components/Toast/index.ts +2 -0
  50. package/src/components/Toggle/Toggle.tsx +92 -0
  51. package/src/components/Toggle/index.ts +2 -0
  52. package/src/index.ts +26 -0
  53. package/src/theme/ThemeProvider.tsx +47 -0
  54. package/src/theme/colors.ts +45 -0
  55. package/src/theme/index.ts +4 -0
  56. package/src/theme/types.ts +33 -0
package/dist/index.js CHANGED
@@ -1,34 +1,111 @@
1
1
  'use strict';
2
2
 
3
- var React3 = require('react');
3
+ var React23 = require('react');
4
4
  var reactNative = require('react-native');
5
+ var Haptics11 = require('expo-haptics');
6
+ var expoLinearGradient = require('expo-linear-gradient');
7
+ var ReanimatedAnimated = require('react-native-reanimated');
8
+ var bottomSheet = require('@gorhom/bottom-sheet');
9
+ var reactNativeGestureHandler = require('react-native-gesture-handler');
10
+ var reactNativeSafeAreaContext = require('react-native-safe-area-context');
5
11
 
6
12
  function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
7
13
 
8
- var React3__default = /*#__PURE__*/_interopDefault(React3);
14
+ function _interopNamespace(e) {
15
+ if (e && e.__esModule) return e;
16
+ var n = Object.create(null);
17
+ if (e) {
18
+ Object.keys(e).forEach(function (k) {
19
+ if (k !== 'default') {
20
+ var d = Object.getOwnPropertyDescriptor(e, k);
21
+ Object.defineProperty(n, k, d.get ? d : {
22
+ enumerable: true,
23
+ get: function () { return e[k]; }
24
+ });
25
+ }
26
+ });
27
+ }
28
+ n.default = e;
29
+ return Object.freeze(n);
30
+ }
31
+
32
+ var React23__default = /*#__PURE__*/_interopDefault(React23);
33
+ var Haptics11__namespace = /*#__PURE__*/_interopNamespace(Haptics11);
34
+ var ReanimatedAnimated__default = /*#__PURE__*/_interopDefault(ReanimatedAnimated);
9
35
 
10
- // src/components/Button/Button.tsx
11
- var containerVariantStyles = {
12
- primary: { backgroundColor: "#000" },
13
- secondary: { backgroundColor: "#6B7280" },
14
- outline: { backgroundColor: "transparent", borderWidth: 1.5, borderColor: "#000" },
15
- ghost: { backgroundColor: "transparent" }
36
+ // src/theme/ThemeProvider.tsx
37
+
38
+ // src/theme/colors.ts
39
+ var defaultLight = {
40
+ background: "#ffffff",
41
+ foreground: "#171717",
42
+ card: "#ffffff",
43
+ cardForeground: "#171717",
44
+ primary: "#1a1a1a",
45
+ primaryForeground: "#fafafa",
46
+ secondary: "#f5f5f5",
47
+ secondaryForeground: "#1a1a1a",
48
+ muted: "#f5f5f5",
49
+ mutedForeground: "#646464",
50
+ accent: "#f5f5f5",
51
+ accentForeground: "#1a1a1a",
52
+ destructive: "#ef4444",
53
+ destructiveForeground: "#fafafa",
54
+ border: "#e5e5e5",
55
+ input: "#e5e5e5",
56
+ ring: "#a3a3a3",
57
+ success: "#16a34a",
58
+ successForeground: "#ffffff"
16
59
  };
17
- var containerSizeStyles = {
18
- sm: { paddingHorizontal: 12, paddingVertical: 6 },
19
- md: { paddingHorizontal: 16, paddingVertical: 10 },
20
- lg: { paddingHorizontal: 24, paddingVertical: 14 }
60
+ var defaultDark = {
61
+ background: "#171717",
62
+ foreground: "#fafafa",
63
+ card: "#1f1f1f",
64
+ cardForeground: "#fafafa",
65
+ primary: "#fafafa",
66
+ primaryForeground: "#1a1a1a",
67
+ secondary: "#2a2a2a",
68
+ secondaryForeground: "#fafafa",
69
+ muted: "#2a2a2a",
70
+ mutedForeground: "#a3a3a3",
71
+ accent: "#2a2a2a",
72
+ accentForeground: "#fafafa",
73
+ destructive: "#dc2626",
74
+ destructiveForeground: "#fafafa",
75
+ border: "#2a2a2a",
76
+ input: "#2a2a2a",
77
+ ring: "#d4d4d4",
78
+ success: "#22c55e",
79
+ successForeground: "#ffffff"
21
80
  };
22
- var labelVariantStyles = {
23
- primary: { color: "#fff" },
24
- secondary: { color: "#fff" },
25
- outline: { color: "#000" },
26
- ghost: { color: "#000" }
81
+
82
+ // src/theme/ThemeProvider.tsx
83
+ var ThemeContext = React23.createContext({
84
+ colors: defaultLight,
85
+ colorScheme: "light"
86
+ });
87
+ function ThemeProvider({ children, theme, colorScheme = "system" }) {
88
+ const systemScheme = reactNative.useColorScheme() ?? "light";
89
+ const resolvedScheme = colorScheme === "system" ? systemScheme : colorScheme;
90
+ const colors = React23.useMemo(() => {
91
+ const base = resolvedScheme === "dark" ? defaultDark : defaultLight;
92
+ const overrides = resolvedScheme === "dark" ? theme?.dark : theme?.light;
93
+ return { ...base, ...overrides };
94
+ }, [resolvedScheme, theme]);
95
+ return /* @__PURE__ */ React23__default.default.createElement(ThemeContext.Provider, { value: { colors, colorScheme: resolvedScheme } }, children);
96
+ }
97
+ function useTheme() {
98
+ return React23.useContext(ThemeContext);
99
+ }
100
+ var containerSizeStyles = {
101
+ sm: { paddingHorizontal: 16, paddingVertical: 10 },
102
+ md: { paddingHorizontal: 20, paddingVertical: 14 },
103
+ lg: { paddingHorizontal: 28, paddingVertical: 18 }
27
104
  };
28
105
  var labelSizeStyles = {
29
- sm: { fontSize: 13 },
30
- md: { fontSize: 15 },
31
- lg: { fontSize: 17 }
106
+ sm: { fontSize: 14 },
107
+ md: { fontSize: 16 },
108
+ lg: { fontSize: 18 }
32
109
  };
33
110
  function Button({
34
111
  label,
@@ -36,34 +113,66 @@ function Button({
36
113
  size = "md",
37
114
  loading = false,
38
115
  fullWidth = false,
116
+ icon,
117
+ iconPosition = "left",
39
118
  disabled,
40
119
  style,
120
+ onPress,
41
121
  ...props
42
122
  }) {
123
+ const { colors } = useTheme();
43
124
  const isDisabled = disabled || loading;
44
- return /* @__PURE__ */ React3__default.default.createElement(
125
+ const scale = React23.useRef(new reactNative.Animated.Value(1)).current;
126
+ const handlePressIn = () => {
127
+ if (isDisabled) return;
128
+ reactNative.Animated.spring(scale, {
129
+ toValue: 0.95,
130
+ useNativeDriver: true,
131
+ speed: 40,
132
+ bounciness: 0
133
+ }).start();
134
+ };
135
+ const handlePressOut = () => {
136
+ reactNative.Animated.spring(scale, { toValue: 1, useNativeDriver: true, speed: 40, bounciness: 4 }).start();
137
+ };
138
+ const handlePress = (e) => {
139
+ Haptics11__namespace.impactAsync(Haptics11__namespace.ImpactFeedbackStyle.Light);
140
+ onPress?.(e);
141
+ };
142
+ const containerVariantStyle = {
143
+ primary: { backgroundColor: colors.primary },
144
+ secondary: { backgroundColor: colors.secondary },
145
+ outline: { backgroundColor: "transparent", borderWidth: 1.5, borderColor: colors.border },
146
+ ghost: { backgroundColor: "transparent" }
147
+ }[variant];
148
+ const labelVariantStyle = {
149
+ primary: { color: colors.primaryForeground },
150
+ secondary: { color: colors.secondaryForeground },
151
+ outline: { color: colors.foreground },
152
+ ghost: { color: colors.foreground }
153
+ }[variant];
154
+ const spinnerColor = variant === "primary" || variant === "secondary" ? colors.primaryForeground : colors.foreground;
155
+ return /* @__PURE__ */ React23__default.default.createElement(reactNative.Animated.View, { style: [fullWidth && styles.fullWidth, { transform: [{ scale }] }] }, /* @__PURE__ */ React23__default.default.createElement(
45
156
  reactNative.TouchableOpacity,
46
157
  {
47
158
  style: [
48
159
  styles.base,
49
- containerVariantStyles[variant],
160
+ containerVariantStyle,
50
161
  containerSizeStyles[size],
51
162
  fullWidth && styles.fullWidth,
52
163
  isDisabled && styles.disabled,
53
164
  style
54
165
  ],
55
166
  disabled: isDisabled,
56
- activeOpacity: 0.75,
167
+ activeOpacity: 1,
168
+ touchSoundDisabled: true,
169
+ onPress: handlePress,
170
+ onPressIn: handlePressIn,
171
+ onPressOut: handlePressOut,
57
172
  ...props
58
173
  },
59
- loading ? /* @__PURE__ */ React3__default.default.createElement(
60
- reactNative.ActivityIndicator,
61
- {
62
- size: "small",
63
- color: variant === "outline" || variant === "ghost" ? "#000" : "#fff"
64
- }
65
- ) : /* @__PURE__ */ React3__default.default.createElement(reactNative.Text, { style: [styles.label, labelVariantStyles[variant], labelSizeStyles[size]] }, label)
66
- );
174
+ loading ? /* @__PURE__ */ React23__default.default.createElement(reactNative.ActivityIndicator, { size: "small", color: spinnerColor }) : /* @__PURE__ */ React23__default.default.createElement(React23__default.default.Fragment, null, icon && iconPosition === "left" && /* @__PURE__ */ React23__default.default.createElement(React23__default.default.Fragment, null, icon), /* @__PURE__ */ React23__default.default.createElement(reactNative.Text, { style: [styles.label, labelVariantStyle, labelSizeStyles[size], icon ? styles.labelWithIcon : void 0] }, label), icon && iconPosition === "right" && /* @__PURE__ */ React23__default.default.createElement(React23__default.default.Fragment, null, icon))
175
+ ));
67
176
  }
68
177
  var styles = reactNative.StyleSheet.create({
69
178
  base: {
@@ -80,35 +189,45 @@ var styles = reactNative.StyleSheet.create({
80
189
  },
81
190
  label: {
82
191
  fontWeight: "600"
192
+ },
193
+ labelWithIcon: {
194
+ marginHorizontal: 6
83
195
  }
84
196
  });
85
197
  var variantStyles = {
86
- h1: { fontSize: 32, fontWeight: "700", lineHeight: 40 },
198
+ h1: { fontSize: 32, fontWeight: "700", lineHeight: 44 },
87
199
  h2: { fontSize: 24, fontWeight: "700", lineHeight: 32 },
88
200
  h3: { fontSize: 20, fontWeight: "600", lineHeight: 28 },
89
201
  body: { fontSize: 16, fontWeight: "400", lineHeight: 24 },
90
- caption: { fontSize: 12, fontWeight: "400", lineHeight: 18, color: "#6B7280" },
202
+ caption: { fontSize: 12, fontWeight: "400", lineHeight: 18 },
91
203
  label: { fontSize: 14, fontWeight: "500", lineHeight: 20 }
92
204
  };
93
205
  function Text2({ variant = "body", color, style, children, ...props }) {
94
- return /* @__PURE__ */ React3__default.default.createElement(
206
+ const { colors } = useTheme();
207
+ const defaultColor = variant === "caption" ? colors.mutedForeground : colors.foreground;
208
+ return /* @__PURE__ */ React23__default.default.createElement(
95
209
  reactNative.Text,
96
210
  {
97
- style: [variantStyles[variant], color ? { color } : void 0, style],
211
+ style: [variantStyles[variant], { color: color ?? defaultColor }, style],
212
+ allowFontScaling: true,
98
213
  ...props
99
214
  },
100
215
  children
101
216
  );
102
217
  }
103
- function Input({ label, error, hint, style, onFocus, onBlur, ...props }) {
104
- const [focused, setFocused] = React3.useState(false);
105
- return /* @__PURE__ */ React3__default.default.createElement(reactNative.View, { style: styles2.container }, label ? /* @__PURE__ */ React3__default.default.createElement(reactNative.Text, { style: styles2.label }, label) : null, /* @__PURE__ */ React3__default.default.createElement(
218
+ function Input({ label, error, hint, containerStyle, style, onFocus, onBlur, ...props }) {
219
+ const { colors } = useTheme();
220
+ const [focused, setFocused] = React23.useState(false);
221
+ return /* @__PURE__ */ React23__default.default.createElement(reactNative.View, { style: [styles2.container, containerStyle] }, label ? /* @__PURE__ */ React23__default.default.createElement(reactNative.Text, { style: [styles2.label, { color: colors.foreground }], allowFontScaling: true }, label) : null, /* @__PURE__ */ React23__default.default.createElement(
106
222
  reactNative.TextInput,
107
223
  {
108
224
  style: [
109
225
  styles2.input,
110
- focused && styles2.inputFocused,
111
- error ? styles2.inputError : void 0,
226
+ {
227
+ borderColor: error ? colors.destructive : focused ? colors.ring : colors.border,
228
+ color: colors.foreground,
229
+ backgroundColor: colors.background
230
+ },
112
231
  style
113
232
  ],
114
233
  onFocus: (e) => {
@@ -119,10 +238,11 @@ function Input({ label, error, hint, style, onFocus, onBlur, ...props }) {
119
238
  setFocused(false);
120
239
  onBlur?.(e);
121
240
  },
122
- placeholderTextColor: "#9CA3AF",
241
+ placeholderTextColor: colors.mutedForeground,
242
+ allowFontScaling: true,
123
243
  ...props
124
244
  }
125
- ), error ? /* @__PURE__ */ React3__default.default.createElement(reactNative.Text, { style: styles2.errorText }, error) : null, !error && hint ? /* @__PURE__ */ React3__default.default.createElement(reactNative.Text, { style: styles2.hintText }, hint) : null);
245
+ ), error ? /* @__PURE__ */ React23__default.default.createElement(reactNative.Text, { style: [styles2.helperText, { color: colors.destructive }], allowFontScaling: true }, error) : null, !error && hint ? /* @__PURE__ */ React23__default.default.createElement(reactNative.Text, { style: [styles2.helperText, { color: colors.mutedForeground }], allowFontScaling: true }, hint) : null);
126
246
  }
127
247
  var styles2 = reactNative.StyleSheet.create({
128
248
  container: {
@@ -131,35 +251,1501 @@ var styles2 = reactNative.StyleSheet.create({
131
251
  label: {
132
252
  fontSize: 14,
133
253
  fontWeight: "500",
134
- color: "#111827",
135
- marginBottom: 2
254
+ marginBottom: 4
255
+ },
256
+ input: {
257
+ borderWidth: 1.5,
258
+ borderRadius: 8,
259
+ paddingHorizontal: 16,
260
+ paddingVertical: 14,
261
+ fontSize: 16
262
+ },
263
+ helperText: {
264
+ fontSize: 12
265
+ }
266
+ });
267
+ function Badge({ label, variant = "default", style }) {
268
+ const { colors } = useTheme();
269
+ const containerStyle = {
270
+ default: { backgroundColor: colors.primary },
271
+ secondary: { backgroundColor: colors.secondary },
272
+ destructive: { backgroundColor: colors.destructive },
273
+ outline: { backgroundColor: "transparent", borderWidth: 1, borderColor: colors.border }
274
+ }[variant];
275
+ const textColor = {
276
+ default: colors.primaryForeground,
277
+ secondary: colors.secondaryForeground,
278
+ destructive: colors.destructiveForeground,
279
+ outline: colors.foreground
280
+ }[variant];
281
+ return /* @__PURE__ */ React23__default.default.createElement(reactNative.View, { style: [styles3.container, containerStyle, style] }, /* @__PURE__ */ React23__default.default.createElement(reactNative.Text, { style: [styles3.label, { color: textColor }], allowFontScaling: true }, label));
282
+ }
283
+ var styles3 = reactNative.StyleSheet.create({
284
+ container: {
285
+ borderRadius: 6,
286
+ paddingHorizontal: 8,
287
+ paddingVertical: 2,
288
+ alignSelf: "flex-start"
289
+ },
290
+ label: {
291
+ fontSize: 12,
292
+ fontWeight: "500"
293
+ }
294
+ });
295
+ function Card({ children, style }) {
296
+ const { colors } = useTheme();
297
+ return /* @__PURE__ */ React23__default.default.createElement(
298
+ reactNative.View,
299
+ {
300
+ style: [styles4.card, { backgroundColor: colors.card, borderColor: colors.border }, style]
301
+ },
302
+ children
303
+ );
304
+ }
305
+ function CardHeader({ children, style }) {
306
+ return /* @__PURE__ */ React23__default.default.createElement(reactNative.View, { style: [styles4.header, style] }, children);
307
+ }
308
+ function CardTitle({ children, style }) {
309
+ const { colors } = useTheme();
310
+ return /* @__PURE__ */ React23__default.default.createElement(reactNative.Text, { style: [styles4.title, { color: colors.cardForeground }, style] }, children);
311
+ }
312
+ function CardDescription({ children, style }) {
313
+ const { colors } = useTheme();
314
+ return /* @__PURE__ */ React23__default.default.createElement(reactNative.Text, { style: [styles4.description, { color: colors.mutedForeground }, style] }, children);
315
+ }
316
+ function CardContent({ children, style }) {
317
+ return /* @__PURE__ */ React23__default.default.createElement(reactNative.View, { style: [styles4.content, style] }, children);
318
+ }
319
+ function CardFooter({ children, style }) {
320
+ return /* @__PURE__ */ React23__default.default.createElement(reactNative.View, { style: [styles4.footer, style] }, children);
321
+ }
322
+ var styles4 = reactNative.StyleSheet.create({
323
+ card: {
324
+ borderRadius: 12,
325
+ borderWidth: 1,
326
+ shadowColor: "#000",
327
+ shadowOffset: { width: 0, height: 1 },
328
+ shadowOpacity: 0.05,
329
+ shadowRadius: 2,
330
+ elevation: 1
331
+ },
332
+ header: {
333
+ padding: 24,
334
+ paddingBottom: 0,
335
+ gap: 6
336
+ },
337
+ title: {
338
+ fontSize: 18,
339
+ fontWeight: "600",
340
+ lineHeight: 24
341
+ },
342
+ description: {
343
+ fontSize: 14,
344
+ lineHeight: 20
345
+ },
346
+ content: {
347
+ padding: 24
348
+ },
349
+ footer: {
350
+ padding: 24,
351
+ paddingTop: 0,
352
+ flexDirection: "row",
353
+ alignItems: "center"
354
+ }
355
+ });
356
+ function Separator({ orientation = "horizontal", style }) {
357
+ const { colors } = useTheme();
358
+ return /* @__PURE__ */ React23__default.default.createElement(
359
+ reactNative.View,
360
+ {
361
+ style: [
362
+ orientation === "horizontal" ? styles5.horizontal : styles5.vertical,
363
+ { backgroundColor: colors.border },
364
+ style
365
+ ]
366
+ }
367
+ );
368
+ }
369
+ var styles5 = reactNative.StyleSheet.create({
370
+ horizontal: {
371
+ height: 1,
372
+ width: "100%"
373
+ },
374
+ vertical: {
375
+ width: 1,
376
+ height: "100%"
377
+ }
378
+ });
379
+ var sizeMap = {
380
+ sm: "small",
381
+ md: "small",
382
+ lg: "large"
383
+ };
384
+ function Spinner({ size = "md", color, ...props }) {
385
+ const { colors } = useTheme();
386
+ return /* @__PURE__ */ React23__default.default.createElement(reactNative.ActivityIndicator, { size: sizeMap[size], color: color ?? colors.primary, ...props });
387
+ }
388
+ function Skeleton({ width = "100%", height = 16, borderRadius = 6, style }) {
389
+ const { colors, colorScheme } = useTheme();
390
+ const shimmerAnim = React23.useRef(new reactNative.Animated.Value(0)).current;
391
+ const [containerWidth, setContainerWidth] = React23.useState(300);
392
+ const shimmerHighlight = colorScheme === "dark" ? "rgba(255,255,255,0.08)" : "rgba(255,255,255,0.7)";
393
+ React23.useEffect(() => {
394
+ const animation = reactNative.Animated.loop(
395
+ reactNative.Animated.timing(shimmerAnim, {
396
+ toValue: 1,
397
+ duration: 1200,
398
+ useNativeDriver: true
399
+ })
400
+ );
401
+ animation.start();
402
+ return () => animation.stop();
403
+ }, [shimmerAnim]);
404
+ const translateX = shimmerAnim.interpolate({
405
+ inputRange: [0, 1],
406
+ outputRange: [-containerWidth, containerWidth]
407
+ });
408
+ return /* @__PURE__ */ React23__default.default.createElement(
409
+ reactNative.View,
410
+ {
411
+ style: [
412
+ styles6.base,
413
+ { width, height, borderRadius, backgroundColor: colors.muted },
414
+ style
415
+ ],
416
+ onLayout: (e) => setContainerWidth(e.nativeEvent.layout.width)
417
+ },
418
+ /* @__PURE__ */ React23__default.default.createElement(reactNative.Animated.View, { style: [reactNative.StyleSheet.absoluteFill, { transform: [{ translateX }] }] }, /* @__PURE__ */ React23__default.default.createElement(
419
+ expoLinearGradient.LinearGradient,
420
+ {
421
+ colors: ["transparent", shimmerHighlight, "transparent"],
422
+ start: { x: 0, y: 0 },
423
+ end: { x: 1, y: 0 },
424
+ style: reactNative.StyleSheet.absoluteFill
425
+ }
426
+ ))
427
+ );
428
+ }
429
+ var styles6 = reactNative.StyleSheet.create({
430
+ base: {
431
+ overflow: "hidden"
432
+ }
433
+ });
434
+ var sizeMap2 = {
435
+ sm: 24,
436
+ md: 32,
437
+ lg: 48,
438
+ xl: 64
439
+ };
440
+ var fontSizeMap = {
441
+ sm: 10,
442
+ md: 13,
443
+ lg: 18,
444
+ xl: 24
445
+ };
446
+ function Avatar({ src, fallback, size = "md", style }) {
447
+ const { colors } = useTheme();
448
+ const [imageError, setImageError] = React23.useState(false);
449
+ const dimension = sizeMap2[size];
450
+ const showFallback = !src || imageError;
451
+ const containerStyle = {
452
+ width: dimension,
453
+ height: dimension,
454
+ borderRadius: dimension / 2,
455
+ backgroundColor: colors.muted,
456
+ overflow: "hidden"
457
+ };
458
+ return /* @__PURE__ */ React23__default.default.createElement(reactNative.View, { style: [styles7.base, containerStyle, style] }, !showFallback ? /* @__PURE__ */ React23__default.default.createElement(
459
+ reactNative.Image,
460
+ {
461
+ source: { uri: src },
462
+ style: { width: dimension, height: dimension },
463
+ onError: () => setImageError(true)
464
+ }
465
+ ) : /* @__PURE__ */ React23__default.default.createElement(
466
+ reactNative.Text,
467
+ {
468
+ style: [styles7.fallback, { color: colors.mutedForeground, fontSize: fontSizeMap[size] }]
469
+ },
470
+ fallback?.slice(0, 2).toUpperCase() ?? "?"
471
+ ));
472
+ }
473
+ var styles7 = reactNative.StyleSheet.create({
474
+ base: {
475
+ alignItems: "center",
476
+ justifyContent: "center"
477
+ },
478
+ fallback: {
479
+ fontWeight: "500"
480
+ }
481
+ });
482
+ function Alert({ title, description, variant = "default", icon, style }) {
483
+ const { colors } = useTheme();
484
+ const borderColor = variant === "destructive" ? colors.destructive : colors.border;
485
+ const titleColor = variant === "destructive" ? colors.destructive : colors.foreground;
486
+ const descColor = variant === "destructive" ? colors.destructive : colors.mutedForeground;
487
+ return /* @__PURE__ */ React23__default.default.createElement(reactNative.View, { style: [styles8.container, { backgroundColor: colors.card, borderColor }, style] }, icon ? /* @__PURE__ */ React23__default.default.createElement(reactNative.View, { style: styles8.icon }, icon) : null, /* @__PURE__ */ React23__default.default.createElement(reactNative.View, { style: styles8.content }, title ? /* @__PURE__ */ React23__default.default.createElement(reactNative.Text, { style: [styles8.title, { color: titleColor }] }, title) : null, description ? /* @__PURE__ */ React23__default.default.createElement(reactNative.Text, { style: [styles8.description, { color: descColor }] }, description) : null));
488
+ }
489
+ var styles8 = reactNative.StyleSheet.create({
490
+ container: {
491
+ flexDirection: "row",
492
+ borderWidth: 1,
493
+ borderRadius: 8,
494
+ padding: 16,
495
+ gap: 12
496
+ },
497
+ icon: {
498
+ marginTop: 2
499
+ },
500
+ content: {
501
+ flex: 1,
502
+ gap: 4
503
+ },
504
+ title: {
505
+ fontSize: 14,
506
+ fontWeight: "500",
507
+ lineHeight: 20
508
+ },
509
+ description: {
510
+ fontSize: 14,
511
+ lineHeight: 20
512
+ }
513
+ });
514
+ function Progress({ value = 0, max = 100, style }) {
515
+ const { colors } = useTheme();
516
+ const percent = Math.min(Math.max(value / max * 100, 0), 100);
517
+ const [trackWidth, setTrackWidth] = React23.useState(0);
518
+ const animatedWidth = React23.useRef(new reactNative.Animated.Value(0)).current;
519
+ React23.useEffect(() => {
520
+ if (trackWidth === 0) return;
521
+ reactNative.Animated.spring(animatedWidth, {
522
+ toValue: percent / 100 * trackWidth,
523
+ useNativeDriver: false,
524
+ speed: 20,
525
+ bounciness: 0
526
+ }).start();
527
+ }, [percent, trackWidth]);
528
+ return /* @__PURE__ */ React23__default.default.createElement(
529
+ reactNative.View,
530
+ {
531
+ style: [styles9.track, { backgroundColor: colors.muted }, style],
532
+ onLayout: (e) => setTrackWidth(e.nativeEvent.layout.width)
533
+ },
534
+ /* @__PURE__ */ React23__default.default.createElement(
535
+ reactNative.Animated.View,
536
+ {
537
+ style: [styles9.indicator, { width: animatedWidth, backgroundColor: colors.primary }]
538
+ }
539
+ )
540
+ );
541
+ }
542
+ var styles9 = reactNative.StyleSheet.create({
543
+ track: {
544
+ height: 8,
545
+ borderRadius: 999,
546
+ overflow: "hidden",
547
+ width: "100%"
548
+ },
549
+ indicator: {
550
+ height: "100%",
551
+ borderRadius: 999
552
+ }
553
+ });
554
+ function EmptyState({ icon, title, description, action, style }) {
555
+ const { colors } = useTheme();
556
+ return /* @__PURE__ */ React23__default.default.createElement(reactNative.View, { style: [styles10.container, { borderColor: colors.border }, style] }, icon ? /* @__PURE__ */ React23__default.default.createElement(reactNative.View, { style: [styles10.iconWrapper, { backgroundColor: colors.muted }] }, icon) : null, /* @__PURE__ */ React23__default.default.createElement(reactNative.View, { style: styles10.textWrapper }, /* @__PURE__ */ React23__default.default.createElement(reactNative.Text, { style: [styles10.title, { color: colors.foreground }] }, title), description ? /* @__PURE__ */ React23__default.default.createElement(reactNative.Text, { style: [styles10.description, { color: colors.mutedForeground }] }, description) : null), action ? /* @__PURE__ */ React23__default.default.createElement(reactNative.View, { style: styles10.action }, action) : null);
557
+ }
558
+ var styles10 = reactNative.StyleSheet.create({
559
+ container: {
560
+ alignItems: "center",
561
+ justifyContent: "center",
562
+ borderWidth: 1,
563
+ borderStyle: "dashed",
564
+ borderRadius: 12,
565
+ padding: 32,
566
+ gap: 16
567
+ },
568
+ iconWrapper: {
569
+ width: 48,
570
+ height: 48,
571
+ borderRadius: 12,
572
+ alignItems: "center",
573
+ justifyContent: "center"
574
+ },
575
+ textWrapper: {
576
+ alignItems: "center",
577
+ gap: 8,
578
+ maxWidth: 320
579
+ },
580
+ title: {
581
+ fontSize: 18,
582
+ fontWeight: "500",
583
+ textAlign: "center"
584
+ },
585
+ description: {
586
+ fontSize: 14,
587
+ lineHeight: 20,
588
+ textAlign: "center"
589
+ },
590
+ action: {
591
+ marginTop: 8
592
+ }
593
+ });
594
+ function Textarea({
595
+ label,
596
+ error,
597
+ hint,
598
+ rows = 4,
599
+ containerStyle,
600
+ style,
601
+ onFocus,
602
+ onBlur,
603
+ ...props
604
+ }) {
605
+ const { colors } = useTheme();
606
+ const [focused, setFocused] = React23.useState(false);
607
+ return /* @__PURE__ */ React23__default.default.createElement(reactNative.View, { style: [styles11.container, containerStyle] }, label ? /* @__PURE__ */ React23__default.default.createElement(reactNative.Text, { style: [styles11.label, { color: colors.foreground }], allowFontScaling: true }, label) : null, /* @__PURE__ */ React23__default.default.createElement(
608
+ reactNative.TextInput,
609
+ {
610
+ multiline: true,
611
+ numberOfLines: rows,
612
+ textAlignVertical: "top",
613
+ style: [
614
+ styles11.input,
615
+ {
616
+ borderColor: error ? colors.destructive : focused ? colors.ring : colors.border,
617
+ color: colors.foreground,
618
+ backgroundColor: colors.background,
619
+ minHeight: rows * 28
620
+ },
621
+ style
622
+ ],
623
+ onFocus: (e) => {
624
+ setFocused(true);
625
+ onFocus?.(e);
626
+ },
627
+ onBlur: (e) => {
628
+ setFocused(false);
629
+ onBlur?.(e);
630
+ },
631
+ placeholderTextColor: colors.mutedForeground,
632
+ allowFontScaling: true,
633
+ ...props
634
+ }
635
+ ), error ? /* @__PURE__ */ React23__default.default.createElement(reactNative.Text, { style: [styles11.helperText, { color: colors.destructive }], allowFontScaling: true }, error) : null, !error && hint ? /* @__PURE__ */ React23__default.default.createElement(reactNative.Text, { style: [styles11.helperText, { color: colors.mutedForeground }], allowFontScaling: true }, hint) : null);
636
+ }
637
+ var styles11 = reactNative.StyleSheet.create({
638
+ container: {
639
+ gap: 4
640
+ },
641
+ label: {
642
+ fontSize: 14,
643
+ fontWeight: "500",
644
+ marginBottom: 4
136
645
  },
137
646
  input: {
138
647
  borderWidth: 1.5,
139
- borderColor: "#D1D5DB",
140
648
  borderRadius: 8,
649
+ paddingHorizontal: 16,
650
+ paddingVertical: 14,
651
+ fontSize: 16
652
+ },
653
+ helperText: {
654
+ fontSize: 12
655
+ }
656
+ });
657
+ function Checkbox({
658
+ checked = false,
659
+ onCheckedChange,
660
+ label,
661
+ disabled,
662
+ style
663
+ }) {
664
+ const { colors } = useTheme();
665
+ const scale = React23.useRef(new reactNative.Animated.Value(1)).current;
666
+ const handlePressIn = () => {
667
+ if (disabled) return;
668
+ reactNative.Animated.spring(scale, { toValue: 0.95, useNativeDriver: true, speed: 40, bounciness: 0 }).start();
669
+ };
670
+ const handlePressOut = () => {
671
+ reactNative.Animated.spring(scale, { toValue: 1, useNativeDriver: true, speed: 40, bounciness: 4 }).start();
672
+ };
673
+ return /* @__PURE__ */ React23__default.default.createElement(reactNative.Animated.View, { style: { transform: [{ scale }] } }, /* @__PURE__ */ React23__default.default.createElement(
674
+ reactNative.TouchableOpacity,
675
+ {
676
+ style: [styles12.row, style],
677
+ onPress: () => {
678
+ Haptics11__namespace.selectionAsync();
679
+ onCheckedChange?.(!checked);
680
+ },
681
+ onPressIn: handlePressIn,
682
+ onPressOut: handlePressOut,
683
+ disabled,
684
+ activeOpacity: 1,
685
+ touchSoundDisabled: true
686
+ },
687
+ /* @__PURE__ */ React23__default.default.createElement(
688
+ reactNative.View,
689
+ {
690
+ style: [
691
+ styles12.box,
692
+ {
693
+ borderColor: checked ? colors.primary : colors.border,
694
+ backgroundColor: checked ? colors.primary : "transparent",
695
+ opacity: disabled ? 0.45 : 1
696
+ }
697
+ ]
698
+ },
699
+ checked ? /* @__PURE__ */ React23__default.default.createElement(reactNative.View, { style: [styles12.checkmark, { borderColor: colors.primaryForeground }] }) : null
700
+ ),
701
+ label ? /* @__PURE__ */ React23__default.default.createElement(
702
+ reactNative.Text,
703
+ {
704
+ style: [styles12.label, { color: disabled ? colors.mutedForeground : colors.foreground }]
705
+ },
706
+ label
707
+ ) : null
708
+ ));
709
+ }
710
+ var styles12 = reactNative.StyleSheet.create({
711
+ row: {
712
+ flexDirection: "row",
713
+ alignItems: "center",
714
+ gap: 10
715
+ },
716
+ box: {
717
+ width: 24,
718
+ height: 24,
719
+ borderRadius: 6,
720
+ borderWidth: 1.5,
721
+ alignItems: "center",
722
+ justifyContent: "center"
723
+ },
724
+ checkmark: {
725
+ width: 13,
726
+ height: 8,
727
+ borderLeftWidth: 2,
728
+ borderBottomWidth: 2,
729
+ transform: [{ rotate: "-45deg" }, { translateY: -1 }]
730
+ },
731
+ label: {
732
+ fontSize: 14,
733
+ lineHeight: 20
734
+ }
735
+ });
736
+ var TRACK_WIDTH = 56;
737
+ var TRACK_HEIGHT = 32;
738
+ var THUMB_SIZE = 24;
739
+ var THUMB_OFFSET = 4;
740
+ var THUMB_TRAVEL = TRACK_WIDTH - THUMB_SIZE - THUMB_OFFSET * 2;
741
+ function Switch({ checked = false, onCheckedChange, disabled, style }) {
742
+ const { colors } = useTheme();
743
+ const translateX = React23.useRef(new reactNative.Animated.Value(checked ? THUMB_TRAVEL : 0)).current;
744
+ const trackOpacity = React23.useRef(new reactNative.Animated.Value(checked ? 1 : 0)).current;
745
+ React23.useEffect(() => {
746
+ reactNative.Animated.parallel([
747
+ reactNative.Animated.spring(translateX, {
748
+ toValue: checked ? THUMB_TRAVEL : 0,
749
+ useNativeDriver: true,
750
+ bounciness: 4
751
+ }),
752
+ reactNative.Animated.timing(trackOpacity, {
753
+ toValue: checked ? 1 : 0,
754
+ duration: 150,
755
+ useNativeDriver: false
756
+ })
757
+ ]).start();
758
+ }, [checked, translateX, trackOpacity]);
759
+ const trackColor = trackOpacity.interpolate({
760
+ inputRange: [0, 1],
761
+ outputRange: [colors.muted, colors.primary]
762
+ });
763
+ return /* @__PURE__ */ React23__default.default.createElement(
764
+ reactNative.TouchableOpacity,
765
+ {
766
+ onPress: () => {
767
+ Haptics11__namespace.selectionAsync();
768
+ onCheckedChange?.(!checked);
769
+ },
770
+ disabled,
771
+ activeOpacity: 0.8,
772
+ touchSoundDisabled: true,
773
+ style: [styles13.wrapper, { opacity: disabled ? 0.45 : 1 }, style]
774
+ },
775
+ /* @__PURE__ */ React23__default.default.createElement(reactNative.Animated.View, { style: [styles13.track, { backgroundColor: trackColor }] }, /* @__PURE__ */ React23__default.default.createElement(
776
+ reactNative.Animated.View,
777
+ {
778
+ style: [
779
+ styles13.thumb,
780
+ { backgroundColor: colors.primaryForeground, transform: [{ translateX }] }
781
+ ]
782
+ }
783
+ ))
784
+ );
785
+ }
786
+ var styles13 = reactNative.StyleSheet.create({
787
+ wrapper: {},
788
+ track: {
789
+ width: TRACK_WIDTH,
790
+ height: TRACK_HEIGHT,
791
+ borderRadius: TRACK_HEIGHT / 2,
792
+ justifyContent: "center",
793
+ paddingHorizontal: THUMB_OFFSET
794
+ },
795
+ thumb: {
796
+ width: THUMB_SIZE,
797
+ height: THUMB_SIZE,
798
+ borderRadius: THUMB_SIZE / 2,
799
+ shadowColor: "#000",
800
+ shadowOffset: { width: 0, height: 1 },
801
+ shadowOpacity: 0.15,
802
+ shadowRadius: 2,
803
+ elevation: 2
804
+ }
805
+ });
806
+ var sizeStyles = {
807
+ sm: { paddingHorizontal: 12, paddingVertical: 8, minWidth: 40, minHeight: 40 },
808
+ md: { paddingHorizontal: 16, paddingVertical: 12, minWidth: 44, minHeight: 44 },
809
+ lg: { paddingHorizontal: 20, paddingVertical: 14, minWidth: 48, minHeight: 48 }
810
+ };
811
+ function Toggle({
812
+ pressed = false,
813
+ onPressedChange,
814
+ variant = "default",
815
+ size = "md",
816
+ label,
817
+ icon,
818
+ disabled,
819
+ style,
820
+ ...props
821
+ }) {
822
+ const { colors } = useTheme();
823
+ const scale = React23.useRef(new reactNative.Animated.Value(1)).current;
824
+ const handlePressIn = () => {
825
+ if (disabled) return;
826
+ reactNative.Animated.spring(scale, { toValue: 0.95, useNativeDriver: true, speed: 40, bounciness: 0 }).start();
827
+ };
828
+ const handlePressOut = () => {
829
+ reactNative.Animated.spring(scale, { toValue: 1, useNativeDriver: true, speed: 40, bounciness: 4 }).start();
830
+ };
831
+ const containerStyle = pressed ? { backgroundColor: colors.accent } : variant === "outline" ? { backgroundColor: "transparent", borderWidth: 1, borderColor: colors.border } : { backgroundColor: "transparent" };
832
+ const textColor = pressed ? colors.accentForeground : colors.foreground;
833
+ return /* @__PURE__ */ React23__default.default.createElement(reactNative.Animated.View, { style: { transform: [{ scale }] } }, /* @__PURE__ */ React23__default.default.createElement(
834
+ reactNative.TouchableOpacity,
835
+ {
836
+ style: [styles14.base, containerStyle, sizeStyles[size], disabled && styles14.disabled, style],
837
+ onPress: () => {
838
+ Haptics11__namespace.selectionAsync();
839
+ onPressedChange?.(!pressed);
840
+ },
841
+ onPressIn: handlePressIn,
842
+ onPressOut: handlePressOut,
843
+ disabled,
844
+ activeOpacity: 1,
845
+ touchSoundDisabled: true,
846
+ ...props
847
+ },
848
+ icon,
849
+ label ? /* @__PURE__ */ React23__default.default.createElement(reactNative.Text, { style: [styles14.label, { color: textColor }] }, label) : null
850
+ ));
851
+ }
852
+ var styles14 = reactNative.StyleSheet.create({
853
+ base: {
854
+ borderRadius: 8,
855
+ flexDirection: "row",
856
+ alignItems: "center",
857
+ justifyContent: "center",
858
+ gap: 8
859
+ },
860
+ disabled: {
861
+ opacity: 0.45
862
+ },
863
+ label: {
864
+ fontSize: 14,
865
+ fontWeight: "500"
866
+ }
867
+ });
868
+ function RadioItem({
869
+ option,
870
+ selected,
871
+ onSelect
872
+ }) {
873
+ const { colors } = useTheme();
874
+ const scale = React23.useRef(new reactNative.Animated.Value(1)).current;
875
+ const handlePressIn = () => {
876
+ if (option.disabled) return;
877
+ reactNative.Animated.spring(scale, { toValue: 0.95, useNativeDriver: true, speed: 40, bounciness: 0 }).start();
878
+ };
879
+ const handlePressOut = () => {
880
+ reactNative.Animated.spring(scale, { toValue: 1, useNativeDriver: true, speed: 40, bounciness: 4 }).start();
881
+ };
882
+ return /* @__PURE__ */ React23__default.default.createElement(reactNative.Animated.View, { style: { transform: [{ scale }] } }, /* @__PURE__ */ React23__default.default.createElement(
883
+ reactNative.TouchableOpacity,
884
+ {
885
+ style: styles15.row,
886
+ onPress: () => {
887
+ if (!option.disabled) {
888
+ Haptics11__namespace.selectionAsync();
889
+ onSelect();
890
+ }
891
+ },
892
+ onPressIn: handlePressIn,
893
+ onPressOut: handlePressOut,
894
+ activeOpacity: 1,
895
+ touchSoundDisabled: true,
896
+ disabled: option.disabled
897
+ },
898
+ /* @__PURE__ */ React23__default.default.createElement(
899
+ reactNative.View,
900
+ {
901
+ style: [
902
+ styles15.radio,
903
+ {
904
+ borderColor: selected ? colors.primary : colors.border,
905
+ opacity: option.disabled ? 0.45 : 1
906
+ }
907
+ ]
908
+ },
909
+ selected ? /* @__PURE__ */ React23__default.default.createElement(reactNative.View, { style: [styles15.dot, { backgroundColor: colors.primary }] }) : null
910
+ ),
911
+ /* @__PURE__ */ React23__default.default.createElement(
912
+ reactNative.Text,
913
+ {
914
+ style: [
915
+ styles15.label,
916
+ { color: option.disabled ? colors.mutedForeground : colors.foreground }
917
+ ]
918
+ },
919
+ option.label
920
+ )
921
+ ));
922
+ }
923
+ function RadioGroup({
924
+ options,
925
+ value,
926
+ onValueChange,
927
+ orientation = "vertical",
928
+ style
929
+ }) {
930
+ return /* @__PURE__ */ React23__default.default.createElement(reactNative.View, { style: [styles15.container, orientation === "horizontal" && styles15.horizontal, style] }, options.map((option) => /* @__PURE__ */ React23__default.default.createElement(
931
+ RadioItem,
932
+ {
933
+ key: option.value,
934
+ option,
935
+ selected: option.value === value,
936
+ onSelect: () => onValueChange?.(option.value)
937
+ }
938
+ )));
939
+ }
940
+ var styles15 = reactNative.StyleSheet.create({
941
+ container: {
942
+ gap: 10
943
+ },
944
+ horizontal: {
945
+ flexDirection: "row",
946
+ flexWrap: "wrap"
947
+ },
948
+ row: {
949
+ flexDirection: "row",
950
+ alignItems: "center",
951
+ gap: 10
952
+ },
953
+ radio: {
954
+ width: 24,
955
+ height: 24,
956
+ borderRadius: 12,
957
+ borderWidth: 1.5,
958
+ alignItems: "center",
959
+ justifyContent: "center"
960
+ },
961
+ dot: {
962
+ width: 10,
963
+ height: 10,
964
+ borderRadius: 5
965
+ },
966
+ label: {
967
+ fontSize: 14,
968
+ lineHeight: 20
969
+ }
970
+ });
971
+ function TabTrigger({
972
+ tab,
973
+ isActive,
974
+ onPress,
975
+ onLayout
976
+ }) {
977
+ const { colors } = useTheme();
978
+ const scale = React23.useRef(new reactNative.Animated.Value(1)).current;
979
+ const handlePressIn = () => {
980
+ reactNative.Animated.spring(scale, { toValue: 0.95, useNativeDriver: true, speed: 40, bounciness: 0 }).start();
981
+ };
982
+ const handlePressOut = () => {
983
+ reactNative.Animated.spring(scale, { toValue: 1, useNativeDriver: true, speed: 40, bounciness: 4 }).start();
984
+ };
985
+ return /* @__PURE__ */ React23__default.default.createElement(
986
+ reactNative.TouchableOpacity,
987
+ {
988
+ style: styles16.trigger,
989
+ onPress,
990
+ onPressIn: handlePressIn,
991
+ onPressOut: handlePressOut,
992
+ onLayout,
993
+ activeOpacity: 1,
994
+ touchSoundDisabled: true
995
+ },
996
+ /* @__PURE__ */ React23__default.default.createElement(reactNative.Animated.View, { style: { transform: [{ scale }] } }, /* @__PURE__ */ React23__default.default.createElement(
997
+ reactNative.Text,
998
+ {
999
+ style: [
1000
+ styles16.triggerLabel,
1001
+ { color: isActive ? colors.foreground : colors.mutedForeground },
1002
+ isActive && styles16.activeTriggerLabel
1003
+ ]
1004
+ },
1005
+ tab.label
1006
+ ))
1007
+ );
1008
+ }
1009
+ function Tabs({ tabs, value, onValueChange, children, style }) {
1010
+ const [internal, setInternal] = React23.useState(tabs[0]?.value ?? "");
1011
+ const { colors } = useTheme();
1012
+ const active = value ?? internal;
1013
+ const tabLayouts = React23.useRef({});
1014
+ const pillX = React23.useRef(new reactNative.Animated.Value(0)).current;
1015
+ const pillWidth = React23.useRef(new reactNative.Animated.Value(0)).current;
1016
+ const initialised = React23.useRef(false);
1017
+ const animatePill = (tabValue, animate) => {
1018
+ const layout = tabLayouts.current[tabValue];
1019
+ if (!layout) return;
1020
+ if (animate) {
1021
+ reactNative.Animated.parallel([
1022
+ reactNative.Animated.spring(pillX, {
1023
+ toValue: layout.x,
1024
+ useNativeDriver: false,
1025
+ speed: 20,
1026
+ bounciness: 0
1027
+ }),
1028
+ reactNative.Animated.spring(pillWidth, {
1029
+ toValue: layout.width,
1030
+ useNativeDriver: false,
1031
+ speed: 20,
1032
+ bounciness: 0
1033
+ })
1034
+ ]).start();
1035
+ } else {
1036
+ pillX.setValue(layout.x);
1037
+ pillWidth.setValue(layout.width);
1038
+ }
1039
+ };
1040
+ React23.useEffect(() => {
1041
+ if (initialised.current) {
1042
+ animatePill(active, true);
1043
+ }
1044
+ }, [active]);
1045
+ const handlePress = (v) => {
1046
+ Haptics11__namespace.selectionAsync();
1047
+ if (!value) setInternal(v);
1048
+ onValueChange?.(v);
1049
+ };
1050
+ return /* @__PURE__ */ React23__default.default.createElement(reactNative.View, { style }, /* @__PURE__ */ React23__default.default.createElement(reactNative.View, { style: [styles16.list, { backgroundColor: colors.muted }] }, /* @__PURE__ */ React23__default.default.createElement(
1051
+ reactNative.Animated.View,
1052
+ {
1053
+ style: [
1054
+ styles16.pill,
1055
+ {
1056
+ backgroundColor: colors.background,
1057
+ position: "absolute",
1058
+ top: 4,
1059
+ bottom: 4,
1060
+ left: pillX,
1061
+ width: pillWidth,
1062
+ borderRadius: 6,
1063
+ shadowColor: "#000",
1064
+ shadowOffset: { width: 0, height: 1 },
1065
+ shadowOpacity: 0.1,
1066
+ shadowRadius: 2,
1067
+ elevation: 2
1068
+ }
1069
+ ]
1070
+ }
1071
+ ), tabs.map((tab) => /* @__PURE__ */ React23__default.default.createElement(
1072
+ TabTrigger,
1073
+ {
1074
+ key: tab.value,
1075
+ tab,
1076
+ isActive: tab.value === active,
1077
+ onPress: () => handlePress(tab.value),
1078
+ onLayout: (e) => {
1079
+ const { x, width } = e.nativeEvent.layout;
1080
+ tabLayouts.current[tab.value] = { x, width };
1081
+ if (tab.value === active) {
1082
+ animatePill(tab.value, false);
1083
+ initialised.current = true;
1084
+ }
1085
+ }
1086
+ }
1087
+ ))), children);
1088
+ }
1089
+ function TabsContent({ value, activeValue, children, style }) {
1090
+ if (value !== activeValue) return null;
1091
+ return /* @__PURE__ */ React23__default.default.createElement(reactNative.View, { style }, children);
1092
+ }
1093
+ var styles16 = reactNative.StyleSheet.create({
1094
+ list: {
1095
+ flexDirection: "row",
1096
+ borderRadius: 8,
1097
+ padding: 4,
1098
+ gap: 4
1099
+ },
1100
+ pill: {},
1101
+ trigger: {
1102
+ flex: 1,
1103
+ paddingVertical: 8,
141
1104
  paddingHorizontal: 12,
142
- paddingVertical: 10,
1105
+ borderRadius: 6,
1106
+ alignItems: "center",
1107
+ justifyContent: "center",
1108
+ zIndex: 1
1109
+ },
1110
+ triggerLabel: {
1111
+ fontSize: 14,
1112
+ fontWeight: "400"
1113
+ },
1114
+ activeTriggerLabel: {
1115
+ fontWeight: "500"
1116
+ }
1117
+ });
1118
+ function AccordionItemComponent({
1119
+ item,
1120
+ isOpen,
1121
+ onToggle
1122
+ }) {
1123
+ const { colors } = useTheme();
1124
+ const animatedHeight = ReanimatedAnimated.useSharedValue(0);
1125
+ const animatedRotation = ReanimatedAnimated.useSharedValue(0);
1126
+ const contentHeight = React23.useRef(0);
1127
+ const scale = React23.useRef(new reactNative.Animated.Value(1)).current;
1128
+ const toggle = (open) => {
1129
+ const easing = open ? ReanimatedAnimated.Easing.out(ReanimatedAnimated.Easing.ease) : ReanimatedAnimated.Easing.in(ReanimatedAnimated.Easing.ease);
1130
+ animatedHeight.value = ReanimatedAnimated.withTiming(open ? contentHeight.current : 0, { duration: 220, easing });
1131
+ animatedRotation.value = ReanimatedAnimated.withTiming(open ? 1 : 0, { duration: 220, easing });
1132
+ };
1133
+ React23__default.default.useEffect(() => {
1134
+ toggle(isOpen);
1135
+ }, [isOpen]);
1136
+ const onLayout = (e) => {
1137
+ if (contentHeight.current === 0) {
1138
+ contentHeight.current = e.nativeEvent.layout.height;
1139
+ if (isOpen) animatedHeight.value = contentHeight.current;
1140
+ }
1141
+ };
1142
+ const heightStyle = ReanimatedAnimated.useAnimatedStyle(() => ({
1143
+ height: animatedHeight.value,
1144
+ overflow: "hidden"
1145
+ }));
1146
+ const rotationStyle = ReanimatedAnimated.useAnimatedStyle(() => ({
1147
+ transform: [{ rotate: `${animatedRotation.value * 180}deg` }]
1148
+ }));
1149
+ const handlePressIn = () => {
1150
+ reactNative.Animated.spring(scale, { toValue: 0.95, useNativeDriver: true, speed: 40, bounciness: 0 }).start();
1151
+ };
1152
+ const handlePressOut = () => {
1153
+ reactNative.Animated.spring(scale, { toValue: 1, useNativeDriver: true, speed: 40, bounciness: 4 }).start();
1154
+ };
1155
+ return /* @__PURE__ */ React23__default.default.createElement(reactNative.View, { style: [styles17.item, { borderBottomColor: colors.border }] }, /* @__PURE__ */ React23__default.default.createElement(reactNative.Animated.View, { style: { transform: [{ scale }] } }, /* @__PURE__ */ React23__default.default.createElement(
1156
+ reactNative.TouchableOpacity,
1157
+ {
1158
+ style: styles17.trigger,
1159
+ onPress: () => {
1160
+ Haptics11__namespace.selectionAsync();
1161
+ onToggle();
1162
+ },
1163
+ onPressIn: handlePressIn,
1164
+ onPressOut: handlePressOut,
1165
+ activeOpacity: 1,
1166
+ touchSoundDisabled: true
1167
+ },
1168
+ /* @__PURE__ */ React23__default.default.createElement(reactNative.Text, { style: [styles17.triggerText, { color: colors.foreground }] }, item.trigger),
1169
+ /* @__PURE__ */ React23__default.default.createElement(
1170
+ ReanimatedAnimated__default.default.Text,
1171
+ {
1172
+ style: [styles17.chevron, { color: colors.foreground }, rotationStyle]
1173
+ },
1174
+ "\u25BE"
1175
+ )
1176
+ )), /* @__PURE__ */ React23__default.default.createElement(ReanimatedAnimated__default.default.View, { style: heightStyle }, /* @__PURE__ */ React23__default.default.createElement(reactNative.View, { style: styles17.content, onLayout }, item.content)));
1177
+ }
1178
+ function Accordion({ items, type = "single", defaultValue, style }) {
1179
+ const [openValues, setOpenValues] = React23.useState(() => {
1180
+ if (!defaultValue) return [];
1181
+ return Array.isArray(defaultValue) ? defaultValue : [defaultValue];
1182
+ });
1183
+ const toggle = (value) => {
1184
+ if (type === "single") {
1185
+ setOpenValues((prev) => prev.includes(value) ? [] : [value]);
1186
+ } else {
1187
+ setOpenValues(
1188
+ (prev) => prev.includes(value) ? prev.filter((v) => v !== value) : [...prev, value]
1189
+ );
1190
+ }
1191
+ };
1192
+ return /* @__PURE__ */ React23__default.default.createElement(reactNative.View, { style }, items.map((item) => /* @__PURE__ */ React23__default.default.createElement(
1193
+ AccordionItemComponent,
1194
+ {
1195
+ key: item.value,
1196
+ item,
1197
+ isOpen: openValues.includes(item.value),
1198
+ onToggle: () => toggle(item.value)
1199
+ }
1200
+ )));
1201
+ }
1202
+ var styles17 = reactNative.StyleSheet.create({
1203
+ item: {
1204
+ borderBottomWidth: 1
1205
+ },
1206
+ trigger: {
1207
+ flexDirection: "row",
1208
+ justifyContent: "space-between",
1209
+ alignItems: "center",
1210
+ paddingVertical: 16
1211
+ },
1212
+ triggerText: {
143
1213
  fontSize: 15,
144
- color: "#111827",
145
- backgroundColor: "#fff"
1214
+ fontWeight: "500",
1215
+ flex: 1
146
1216
  },
147
- inputFocused: {
148
- borderColor: "#000"
1217
+ chevron: {
1218
+ fontSize: 16,
1219
+ marginLeft: 8
149
1220
  },
150
- inputError: {
151
- borderColor: "#EF4444"
1221
+ content: {
1222
+ paddingBottom: 16,
1223
+ position: "absolute",
1224
+ width: "100%"
1225
+ }
1226
+ });
1227
+ function Slider({
1228
+ value = 0,
1229
+ minimumValue = 0,
1230
+ maximumValue = 1,
1231
+ step = 0,
1232
+ onValueChange,
1233
+ onSlidingComplete,
1234
+ disabled,
1235
+ style
1236
+ }) {
1237
+ const { colors } = useTheme();
1238
+ const trackWidth = React23.useRef(0);
1239
+ const lastSteppedValue = React23.useRef(value);
1240
+ const [internalValue, setInternalValue] = React23.useState(value);
1241
+ const currentValue = value ?? internalValue;
1242
+ const clamp = (v) => Math.min(Math.max(v, minimumValue), maximumValue);
1243
+ const snapToStep = (v) => {
1244
+ if (!step) return v;
1245
+ return Math.round((v - minimumValue) / step) * step + minimumValue;
1246
+ };
1247
+ const xToValue = (x) => {
1248
+ const ratio = Math.min(Math.max(x / trackWidth.current, 0), 1);
1249
+ const raw = ratio * (maximumValue - minimumValue) + minimumValue;
1250
+ return clamp(snapToStep(raw));
1251
+ };
1252
+ const panResponder = React23.useRef(
1253
+ reactNative.PanResponder.create({
1254
+ onStartShouldSetPanResponder: () => !disabled,
1255
+ onMoveShouldSetPanResponder: () => !disabled,
1256
+ onPanResponderGrant: (e) => {
1257
+ const x = e.nativeEvent.locationX;
1258
+ const newValue = xToValue(x);
1259
+ setInternalValue(newValue);
1260
+ onValueChange?.(newValue);
1261
+ },
1262
+ onPanResponderMove: (e) => {
1263
+ const x = e.nativeEvent.locationX;
1264
+ const newValue = xToValue(x);
1265
+ if (newValue !== lastSteppedValue.current) {
1266
+ lastSteppedValue.current = newValue;
1267
+ Haptics11__namespace.selectionAsync();
1268
+ }
1269
+ setInternalValue(newValue);
1270
+ onValueChange?.(newValue);
1271
+ },
1272
+ onPanResponderRelease: (e) => {
1273
+ const x = e.nativeEvent.locationX;
1274
+ const newValue = xToValue(x);
1275
+ setInternalValue(newValue);
1276
+ onSlidingComplete?.(newValue);
1277
+ }
1278
+ })
1279
+ ).current;
1280
+ const onLayout = (e) => {
1281
+ trackWidth.current = e.nativeEvent.layout.width;
1282
+ };
1283
+ const percent = (currentValue - minimumValue) / (maximumValue - minimumValue) * 100;
1284
+ return /* @__PURE__ */ React23__default.default.createElement(
1285
+ reactNative.View,
1286
+ {
1287
+ style: [styles18.container, disabled && styles18.disabled, style],
1288
+ ...panResponder.panHandlers,
1289
+ onLayout
1290
+ },
1291
+ /* @__PURE__ */ React23__default.default.createElement(reactNative.View, { style: [styles18.track, { backgroundColor: colors.muted }] }, /* @__PURE__ */ React23__default.default.createElement(
1292
+ reactNative.View,
1293
+ {
1294
+ style: [styles18.range, { width: `${percent}%`, backgroundColor: colors.primary }]
1295
+ }
1296
+ )),
1297
+ /* @__PURE__ */ React23__default.default.createElement(
1298
+ reactNative.View,
1299
+ {
1300
+ style: [
1301
+ styles18.thumb,
1302
+ {
1303
+ left: `${percent}%`,
1304
+ backgroundColor: colors.primary,
1305
+ borderColor: colors.background,
1306
+ transform: [{ translateX: -14 }]
1307
+ }
1308
+ ],
1309
+ pointerEvents: "none"
1310
+ }
1311
+ )
1312
+ );
1313
+ }
1314
+ var styles18 = reactNative.StyleSheet.create({
1315
+ container: {
1316
+ height: 32,
1317
+ justifyContent: "center",
1318
+ position: "relative"
152
1319
  },
153
- errorText: {
154
- fontSize: 12,
155
- color: "#EF4444"
1320
+ disabled: {
1321
+ opacity: 0.45
156
1322
  },
157
- hintText: {
158
- fontSize: 12,
159
- color: "#6B7280"
1323
+ track: {
1324
+ height: 6,
1325
+ borderRadius: 3,
1326
+ overflow: "hidden",
1327
+ width: "100%"
1328
+ },
1329
+ range: {
1330
+ height: "100%",
1331
+ borderRadius: 3
1332
+ },
1333
+ thumb: {
1334
+ position: "absolute",
1335
+ width: 28,
1336
+ height: 28,
1337
+ borderRadius: 14,
1338
+ borderWidth: 2,
1339
+ shadowColor: "#000",
1340
+ shadowOffset: { width: 0, height: 1 },
1341
+ shadowOpacity: 0.2,
1342
+ shadowRadius: 2,
1343
+ elevation: 2
1344
+ }
1345
+ });
1346
+ function Sheet({
1347
+ open,
1348
+ onClose,
1349
+ title,
1350
+ description,
1351
+ children,
1352
+ snapPoints = ["50%"],
1353
+ style
1354
+ }) {
1355
+ const { colors } = useTheme();
1356
+ const ref = React23.useRef(null);
1357
+ React23.useEffect(() => {
1358
+ if (open) {
1359
+ Haptics11__namespace.impactAsync(Haptics11__namespace.ImpactFeedbackStyle.Light);
1360
+ ref.current?.present();
1361
+ } else {
1362
+ ref.current?.dismiss();
1363
+ }
1364
+ }, [open]);
1365
+ const renderBackdrop = (props) => /* @__PURE__ */ React23__default.default.createElement(
1366
+ bottomSheet.BottomSheetBackdrop,
1367
+ {
1368
+ ...props,
1369
+ disappearsOnIndex: -1,
1370
+ appearsOnIndex: 0,
1371
+ pressBehavior: "close"
1372
+ }
1373
+ );
1374
+ return /* @__PURE__ */ React23__default.default.createElement(
1375
+ bottomSheet.BottomSheetModal,
1376
+ {
1377
+ ref,
1378
+ snapPoints,
1379
+ onDismiss: onClose,
1380
+ backdropComponent: renderBackdrop,
1381
+ backgroundStyle: [styles19.background, { backgroundColor: colors.card }],
1382
+ handleIndicatorStyle: [styles19.handle, { backgroundColor: colors.border }],
1383
+ enablePanDownToClose: true
1384
+ },
1385
+ /* @__PURE__ */ React23__default.default.createElement(bottomSheet.BottomSheetView, { style: [styles19.content, style] }, title || description ? /* @__PURE__ */ React23__default.default.createElement(reactNative.View, { style: styles19.header }, title ? /* @__PURE__ */ React23__default.default.createElement(reactNative.Text, { style: [styles19.title, { color: colors.cardForeground }] }, title) : null, description ? /* @__PURE__ */ React23__default.default.createElement(reactNative.Text, { style: [styles19.description, { color: colors.mutedForeground }] }, description) : null) : null, children)
1386
+ );
1387
+ }
1388
+ var styles19 = reactNative.StyleSheet.create({
1389
+ background: {
1390
+ borderTopLeftRadius: 16,
1391
+ borderTopRightRadius: 16
1392
+ },
1393
+ handle: {
1394
+ width: 36,
1395
+ height: 4,
1396
+ borderRadius: 2
1397
+ },
1398
+ content: {
1399
+ paddingHorizontal: 24,
1400
+ paddingBottom: 32
1401
+ },
1402
+ header: {
1403
+ gap: 8,
1404
+ marginBottom: 16
1405
+ },
1406
+ title: {
1407
+ fontSize: 18,
1408
+ fontWeight: "600"
1409
+ },
1410
+ description: {
1411
+ fontSize: 14,
1412
+ lineHeight: 20
1413
+ }
1414
+ });
1415
+ function Select({
1416
+ options,
1417
+ value,
1418
+ onValueChange,
1419
+ placeholder = "Select an option",
1420
+ label,
1421
+ error,
1422
+ disabled,
1423
+ style
1424
+ }) {
1425
+ const { colors } = useTheme();
1426
+ const bottomSheetRef = React23.useRef(null);
1427
+ const scale = React23.useRef(new reactNative.Animated.Value(1)).current;
1428
+ const selected = options.find((o) => o.value === value);
1429
+ const handlePressIn = () => {
1430
+ if (disabled) return;
1431
+ reactNative.Animated.spring(scale, { toValue: 0.95, useNativeDriver: true, speed: 40, bounciness: 0 }).start();
1432
+ };
1433
+ const handlePressOut = () => {
1434
+ reactNative.Animated.spring(scale, { toValue: 1, useNativeDriver: true, speed: 40, bounciness: 4 }).start();
1435
+ };
1436
+ const handleOpen = () => {
1437
+ if (!disabled) {
1438
+ Haptics11__namespace.selectionAsync();
1439
+ bottomSheetRef.current?.present();
1440
+ }
1441
+ };
1442
+ const renderBackdrop = React23.useCallback(
1443
+ (props) => /* @__PURE__ */ React23__default.default.createElement(
1444
+ bottomSheet.BottomSheetBackdrop,
1445
+ {
1446
+ ...props,
1447
+ disappearsOnIndex: -1,
1448
+ appearsOnIndex: 0,
1449
+ pressBehavior: "close"
1450
+ }
1451
+ ),
1452
+ []
1453
+ );
1454
+ return /* @__PURE__ */ React23__default.default.createElement(reactNative.View, { style: [styles20.container, style] }, label ? /* @__PURE__ */ React23__default.default.createElement(reactNative.Text, { style: [styles20.label, { color: colors.foreground }] }, label) : null, /* @__PURE__ */ React23__default.default.createElement(reactNative.Animated.View, { style: { transform: [{ scale }], opacity: disabled ? 0.45 : 1 } }, /* @__PURE__ */ React23__default.default.createElement(
1455
+ reactNative.TouchableOpacity,
1456
+ {
1457
+ style: [
1458
+ styles20.trigger,
1459
+ {
1460
+ borderColor: error ? colors.destructive : colors.border,
1461
+ backgroundColor: colors.background
1462
+ }
1463
+ ],
1464
+ onPress: handleOpen,
1465
+ onPressIn: handlePressIn,
1466
+ onPressOut: handlePressOut,
1467
+ activeOpacity: 1,
1468
+ touchSoundDisabled: true
1469
+ },
1470
+ /* @__PURE__ */ React23__default.default.createElement(
1471
+ reactNative.Text,
1472
+ {
1473
+ style: [
1474
+ styles20.triggerText,
1475
+ { color: selected ? colors.foreground : colors.mutedForeground }
1476
+ ],
1477
+ numberOfLines: 1
1478
+ },
1479
+ selected?.label ?? placeholder
1480
+ ),
1481
+ /* @__PURE__ */ React23__default.default.createElement(reactNative.Text, { style: [styles20.chevron, { color: colors.mutedForeground }] }, "\u25BE")
1482
+ )), error ? /* @__PURE__ */ React23__default.default.createElement(reactNative.Text, { style: [styles20.helperText, { color: colors.destructive }] }, error) : null, /* @__PURE__ */ React23__default.default.createElement(
1483
+ bottomSheet.BottomSheetModal,
1484
+ {
1485
+ ref: bottomSheetRef,
1486
+ enableDynamicSizing: true,
1487
+ enablePanDownToClose: true,
1488
+ backdropComponent: renderBackdrop,
1489
+ backgroundStyle: [styles20.sheetBackground, { backgroundColor: colors.card }],
1490
+ handleIndicatorStyle: [styles20.sheetHandle, { backgroundColor: colors.border }]
1491
+ },
1492
+ /* @__PURE__ */ React23__default.default.createElement(bottomSheet.BottomSheetView, { style: styles20.sheetContent }, label ? /* @__PURE__ */ React23__default.default.createElement(reactNative.Text, { style: [styles20.sheetTitle, { color: colors.foreground }] }, label) : null, options.map((item) => {
1493
+ const isSelected = item.value === value;
1494
+ return /* @__PURE__ */ React23__default.default.createElement(
1495
+ reactNative.TouchableOpacity,
1496
+ {
1497
+ key: item.value,
1498
+ style: [
1499
+ styles20.option,
1500
+ isSelected && { backgroundColor: colors.accent },
1501
+ item.disabled && styles20.disabledOption
1502
+ ],
1503
+ onPress: () => {
1504
+ if (!item.disabled) {
1505
+ Haptics11__namespace.selectionAsync();
1506
+ onValueChange?.(item.value);
1507
+ bottomSheetRef.current?.dismiss();
1508
+ }
1509
+ },
1510
+ activeOpacity: 0.7,
1511
+ touchSoundDisabled: true
1512
+ },
1513
+ /* @__PURE__ */ React23__default.default.createElement(
1514
+ reactNative.Text,
1515
+ {
1516
+ style: [
1517
+ styles20.optionText,
1518
+ { color: item.disabled ? colors.mutedForeground : colors.foreground },
1519
+ isSelected && { fontWeight: "500" }
1520
+ ]
1521
+ },
1522
+ item.label
1523
+ ),
1524
+ isSelected ? /* @__PURE__ */ React23__default.default.createElement(reactNative.Text, { style: [styles20.checkmark, { color: colors.primary }] }, "\u2713") : null
1525
+ );
1526
+ }))
1527
+ ));
1528
+ }
1529
+ var styles20 = reactNative.StyleSheet.create({
1530
+ container: {
1531
+ gap: 4
1532
+ },
1533
+ label: {
1534
+ fontSize: 14,
1535
+ fontWeight: "500",
1536
+ marginBottom: 2
1537
+ },
1538
+ trigger: {
1539
+ flexDirection: "row",
1540
+ alignItems: "center",
1541
+ justifyContent: "space-between",
1542
+ borderWidth: 1.5,
1543
+ borderRadius: 8,
1544
+ paddingHorizontal: 16,
1545
+ paddingVertical: 14
1546
+ },
1547
+ triggerText: {
1548
+ fontSize: 16,
1549
+ flex: 1
1550
+ },
1551
+ chevron: {
1552
+ fontSize: 14,
1553
+ marginLeft: 8
1554
+ },
1555
+ helperText: {
1556
+ fontSize: 12
1557
+ },
1558
+ sheetBackground: {
1559
+ borderTopLeftRadius: 16,
1560
+ borderTopRightRadius: 16
1561
+ },
1562
+ sheetHandle: {
1563
+ width: 36,
1564
+ height: 4,
1565
+ borderRadius: 2
1566
+ },
1567
+ sheetContent: {
1568
+ paddingHorizontal: 16,
1569
+ paddingBottom: 32
1570
+ },
1571
+ sheetTitle: {
1572
+ fontSize: 16,
1573
+ fontWeight: "600",
1574
+ paddingVertical: 12,
1575
+ paddingHorizontal: 4
1576
+ },
1577
+ option: {
1578
+ flexDirection: "row",
1579
+ alignItems: "center",
1580
+ justifyContent: "space-between",
1581
+ paddingHorizontal: 12,
1582
+ paddingVertical: 14,
1583
+ borderRadius: 8
1584
+ },
1585
+ optionText: {
1586
+ fontSize: 15,
1587
+ flex: 1
1588
+ },
1589
+ disabledOption: {
1590
+ opacity: 0.45
1591
+ },
1592
+ checkmark: {
1593
+ fontSize: 14,
1594
+ fontWeight: "600",
1595
+ marginLeft: 8
1596
+ }
1597
+ });
1598
+ var ToastContext = React23.createContext({
1599
+ toast: () => {
1600
+ },
1601
+ dismiss: () => {
1602
+ }
1603
+ });
1604
+ function useToast() {
1605
+ return React23.useContext(ToastContext);
1606
+ }
1607
+ var SWIPE_THRESHOLD = 80;
1608
+ var VELOCITY_THRESHOLD = 800;
1609
+ function ToastNotification({ item, onDismiss }) {
1610
+ const { colors } = useTheme();
1611
+ const translateY = ReanimatedAnimated.useSharedValue(-80);
1612
+ const translateX = ReanimatedAnimated.useSharedValue(0);
1613
+ const opacity = ReanimatedAnimated.useSharedValue(0);
1614
+ React23.useEffect(() => {
1615
+ translateY.value = ReanimatedAnimated.withTiming(0, { duration: 120, easing: ReanimatedAnimated.Easing.out(ReanimatedAnimated.Easing.exp) });
1616
+ opacity.value = ReanimatedAnimated.withTiming(1, { duration: 100 });
1617
+ const timer = setTimeout(() => {
1618
+ translateY.value = ReanimatedAnimated.withTiming(-80, { duration: 200 });
1619
+ opacity.value = ReanimatedAnimated.withTiming(0, { duration: 200 }, (done) => {
1620
+ if (done) ReanimatedAnimated.runOnJS(onDismiss)();
1621
+ });
1622
+ }, item.duration ?? 3e3);
1623
+ return () => clearTimeout(timer);
1624
+ }, []);
1625
+ const panGesture = reactNativeGestureHandler.Gesture.Pan().onUpdate((e) => {
1626
+ translateX.value = e.translationX;
1627
+ }).onEnd((e) => {
1628
+ const shouldDismiss = Math.abs(translateX.value) > SWIPE_THRESHOLD || Math.abs(e.velocityX) > VELOCITY_THRESHOLD;
1629
+ if (shouldDismiss) {
1630
+ const direction = translateX.value > 0 ? 1 : -1;
1631
+ translateX.value = ReanimatedAnimated.withTiming(direction * 500, { duration: 200 }, (done) => {
1632
+ if (done) ReanimatedAnimated.runOnJS(onDismiss)();
1633
+ });
1634
+ opacity.value = ReanimatedAnimated.withTiming(0, { duration: 150 });
1635
+ } else {
1636
+ translateX.value = ReanimatedAnimated.withSpring(0, { damping: 20, stiffness: 300 });
1637
+ }
1638
+ });
1639
+ const animatedStyle = ReanimatedAnimated.useAnimatedStyle(() => ({
1640
+ opacity: opacity.value,
1641
+ transform: [{ translateY: translateY.value }, { translateX: translateX.value }]
1642
+ }));
1643
+ const bgColor = {
1644
+ default: colors.foreground,
1645
+ destructive: colors.destructive,
1646
+ success: colors.success
1647
+ }[item.variant ?? "default"];
1648
+ const textColor = {
1649
+ default: colors.background,
1650
+ destructive: colors.destructiveForeground,
1651
+ success: colors.successForeground
1652
+ }[item.variant ?? "default"];
1653
+ return /* @__PURE__ */ React23__default.default.createElement(reactNativeGestureHandler.GestureDetector, { gesture: panGesture }, /* @__PURE__ */ React23__default.default.createElement(ReanimatedAnimated__default.default.View, { style: [styles21.toast, { backgroundColor: bgColor }, animatedStyle] }, /* @__PURE__ */ React23__default.default.createElement(reactNative.View, { style: styles21.toastContent }, item.title ? /* @__PURE__ */ React23__default.default.createElement(reactNative.Text, { style: [styles21.toastTitle, { color: textColor }] }, item.title) : null, item.description ? /* @__PURE__ */ React23__default.default.createElement(reactNative.Text, { style: [styles21.toastDescription, { color: textColor, opacity: 0.85 }] }, item.description) : null), /* @__PURE__ */ React23__default.default.createElement(reactNative.TouchableOpacity, { onPress: onDismiss, style: styles21.dismissButton, touchSoundDisabled: true }, /* @__PURE__ */ React23__default.default.createElement(reactNative.Text, { style: [styles21.dismissIcon, { color: textColor }] }, "\u2715"))));
1654
+ }
1655
+ function ToastProvider({ children }) {
1656
+ const [toasts, setToasts] = React23.useState([]);
1657
+ const insets = reactNativeSafeAreaContext.useSafeAreaInsets();
1658
+ const toast = React23.useCallback((item) => {
1659
+ const id = Math.random().toString(36).slice(2);
1660
+ if (item.variant === "success") {
1661
+ Haptics11__namespace.notificationAsync(Haptics11__namespace.NotificationFeedbackType.Success);
1662
+ } else if (item.variant === "destructive") {
1663
+ Haptics11__namespace.notificationAsync(Haptics11__namespace.NotificationFeedbackType.Error);
1664
+ } else {
1665
+ Haptics11__namespace.impactAsync(Haptics11__namespace.ImpactFeedbackStyle.Light);
1666
+ }
1667
+ setToasts((prev) => [{ ...item, id }, ...prev].slice(0, 3));
1668
+ }, []);
1669
+ const dismiss = React23.useCallback((id) => {
1670
+ setToasts((prev) => prev.filter((t) => t.id !== id));
1671
+ }, []);
1672
+ return /* @__PURE__ */ React23__default.default.createElement(ToastContext.Provider, { value: { toast, dismiss } }, children, /* @__PURE__ */ React23__default.default.createElement(reactNative.View, { style: [styles21.container, { top: insets.top + 8 }], pointerEvents: "box-none" }, toasts.map((item) => /* @__PURE__ */ React23__default.default.createElement(ToastNotification, { key: item.id, item, onDismiss: () => dismiss(item.id) }))));
1673
+ }
1674
+ var styles21 = reactNative.StyleSheet.create({
1675
+ container: {
1676
+ position: "absolute",
1677
+ left: 16,
1678
+ right: 16,
1679
+ gap: 8,
1680
+ zIndex: 9999
1681
+ },
1682
+ toast: {
1683
+ flexDirection: "row",
1684
+ alignItems: "center",
1685
+ borderRadius: 12,
1686
+ paddingHorizontal: 16,
1687
+ paddingVertical: 12,
1688
+ shadowColor: "#000",
1689
+ shadowOffset: { width: 0, height: 4 },
1690
+ shadowOpacity: 0.15,
1691
+ shadowRadius: 8,
1692
+ elevation: 6
1693
+ },
1694
+ toastContent: {
1695
+ flex: 1,
1696
+ gap: 4
1697
+ },
1698
+ toastTitle: {
1699
+ fontSize: 14,
1700
+ fontWeight: "600"
1701
+ },
1702
+ toastDescription: {
1703
+ fontSize: 13
1704
+ },
1705
+ dismissButton: {
1706
+ padding: 12,
1707
+ marginLeft: 4
1708
+ },
1709
+ dismissIcon: {
1710
+ fontSize: 12
160
1711
  }
161
1712
  });
162
1713
 
1714
+ Object.defineProperty(exports, "BottomSheetModalProvider", {
1715
+ enumerable: true,
1716
+ get: function () { return bottomSheet.BottomSheetModalProvider; }
1717
+ });
1718
+ exports.Accordion = Accordion;
1719
+ exports.Alert = Alert;
1720
+ exports.Avatar = Avatar;
1721
+ exports.Badge = Badge;
163
1722
  exports.Button = Button;
1723
+ exports.Card = Card;
1724
+ exports.CardContent = CardContent;
1725
+ exports.CardDescription = CardDescription;
1726
+ exports.CardFooter = CardFooter;
1727
+ exports.CardHeader = CardHeader;
1728
+ exports.CardTitle = CardTitle;
1729
+ exports.Checkbox = Checkbox;
1730
+ exports.EmptyState = EmptyState;
164
1731
  exports.Input = Input;
1732
+ exports.Progress = Progress;
1733
+ exports.RadioGroup = RadioGroup;
1734
+ exports.Select = Select;
1735
+ exports.Separator = Separator;
1736
+ exports.Sheet = Sheet;
1737
+ exports.Skeleton = Skeleton;
1738
+ exports.Slider = Slider;
1739
+ exports.Spinner = Spinner;
1740
+ exports.Switch = Switch;
1741
+ exports.Tabs = Tabs;
1742
+ exports.TabsContent = TabsContent;
165
1743
  exports.Text = Text2;
1744
+ exports.Textarea = Textarea;
1745
+ exports.ThemeProvider = ThemeProvider;
1746
+ exports.ToastProvider = ToastProvider;
1747
+ exports.Toggle = Toggle;
1748
+ exports.defaultDark = defaultDark;
1749
+ exports.defaultLight = defaultLight;
1750
+ exports.useTheme = useTheme;
1751
+ exports.useToast = useToast;