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