@retray-dev/ui-kit 3.1.0 → 5.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (50) hide show
  1. package/COMPONENTS.md +1792 -659
  2. package/README.md +8 -7
  3. package/dist/index.d.mts +269 -89
  4. package/dist/index.d.ts +269 -89
  5. package/dist/index.js +1034 -312
  6. package/dist/index.mjs +1031 -314
  7. package/package.json +3 -2
  8. package/src/components/Accordion/Accordion.tsx +1 -1
  9. package/src/components/AlertBanner/AlertBanner.tsx +50 -45
  10. package/src/components/Avatar/Avatar.tsx +61 -17
  11. package/src/components/Badge/Badge.tsx +17 -15
  12. package/src/components/Button/Button.tsx +31 -42
  13. package/src/components/Card/Card.tsx +4 -4
  14. package/src/components/CategoryStrip/CategoryStrip.tsx +185 -0
  15. package/src/components/CategoryStrip/index.ts +2 -0
  16. package/src/components/Checkbox/Checkbox.tsx +44 -16
  17. package/src/components/Chip/Chip.tsx +1 -1
  18. package/src/components/ConfirmDialog/ConfirmDialog.tsx +4 -4
  19. package/src/components/CurrencyDisplay/CurrencyDisplay.tsx +1 -0
  20. package/src/components/CurrencyInput/CurrencyInput.tsx +6 -4
  21. package/src/components/EmptyState/EmptyState.tsx +9 -9
  22. package/src/components/IconButton/IconButton.tsx +74 -34
  23. package/src/components/Input/Input.tsx +15 -13
  24. package/src/components/LabelValue/LabelValue.tsx +1 -1
  25. package/src/components/ListItem/ListItem.tsx +5 -5
  26. package/src/components/MediaCard/MediaCard.tsx +249 -0
  27. package/src/components/MediaCard/index.ts +2 -0
  28. package/src/components/Pressable/Pressable.tsx +100 -0
  29. package/src/components/Pressable/index.ts +1 -0
  30. package/src/components/Progress/Progress.tsx +14 -7
  31. package/src/components/RadioGroup/RadioGroup.tsx +1 -1
  32. package/src/components/Select/Select.tsx +5 -5
  33. package/src/components/Sheet/Sheet.tsx +3 -9
  34. package/src/components/Skeleton/Skeleton.tsx +34 -7
  35. package/src/components/Slider/Slider.tsx +2 -2
  36. package/src/components/Spinner/Spinner.tsx +1 -1
  37. package/src/components/Switch/Switch.tsx +31 -4
  38. package/src/components/Tabs/Tabs.tsx +63 -45
  39. package/src/components/Text/Text.tsx +59 -10
  40. package/src/components/Textarea/Textarea.tsx +4 -3
  41. package/src/components/Toast/Toast.tsx +77 -36
  42. package/src/components/Toggle/Toggle.tsx +3 -3
  43. package/src/index.ts +8 -2
  44. package/src/theme/ThemeProvider.tsx +11 -10
  45. package/src/theme/colorUtils.ts +80 -0
  46. package/src/theme/colors.ts +76 -35
  47. package/src/theme/index.ts +2 -2
  48. package/src/theme/types.ts +27 -13
  49. package/src/tokens.ts +150 -13
  50. package/src/utils/hover.ts +25 -0
package/dist/index.mjs CHANGED
@@ -1,5 +1,5 @@
1
1
  import React25, { createContext, useMemo, useContext, useRef, useState, useEffect, useCallback } from 'react';
2
- import { Platform, StyleSheet, useColorScheme, Animated, TouchableOpacity, ActivityIndicator, Text, View, TextInput, Image, Easing, Modal, Pressable } from 'react-native';
2
+ import { Platform, StyleSheet, useColorScheme, Animated, TouchableOpacity, ActivityIndicator, Text, View, TextInput, Image, Easing, Modal, ScrollView, Pressable } from 'react-native';
3
3
  import { verticalScale, scale, moderateScale, moderateVerticalScale } from 'react-native-size-matters';
4
4
  import AntDesign from '@expo/vector-icons/AntDesign';
5
5
  import Entypo from '@expo/vector-icons/Entypo';
@@ -7,7 +7,7 @@ import Feather from '@expo/vector-icons/Feather';
7
7
  import FontAwesome5 from '@expo/vector-icons/FontAwesome5';
8
8
  import MaterialIcons from '@expo/vector-icons/MaterialIcons';
9
9
  import Ionicons from '@expo/vector-icons/Ionicons';
10
- import { AntDesign as AntDesign$1, Entypo as Entypo$1, Feather as Feather$1, FontAwesome5 as FontAwesome5$1, MaterialIcons as MaterialIcons$1 } from '@expo/vector-icons';
10
+ import { AntDesign as AntDesign$1, Feather as Feather$1, Entypo as Entypo$1, FontAwesome5 as FontAwesome5$1, MaterialIcons as MaterialIcons$1 } from '@expo/vector-icons';
11
11
  import { LinearGradient } from 'expo-linear-gradient';
12
12
  import Animated11, { useSharedValue, useDerivedValue, withTiming, Easing as Easing$1, useAnimatedStyle, withSpring } from 'react-native-reanimated';
13
13
  import RNSlider from '@react-native-community/slider';
@@ -20,61 +20,125 @@ import { useSafeAreaInsets } from 'react-native-safe-area-context';
20
20
 
21
21
  // src/theme/ThemeProvider.tsx
22
22
 
23
+ // src/theme/colorUtils.ts
24
+ function hexToRgb(hex) {
25
+ const clean = hex.replace("#", "");
26
+ const full = clean.length === 3 ? clean.split("").map((c) => c + c).join("") : clean;
27
+ if (full.length !== 6) return null;
28
+ return {
29
+ r: parseInt(full.slice(0, 2), 16),
30
+ g: parseInt(full.slice(2, 4), 16),
31
+ b: parseInt(full.slice(4, 6), 16)
32
+ };
33
+ }
34
+ function componentToHex(c) {
35
+ return Math.round(Math.max(0, Math.min(255, c))).toString(16).padStart(2, "0");
36
+ }
37
+ function rgbToHex(r, g, b) {
38
+ return `#${componentToHex(r)}${componentToHex(g)}${componentToHex(b)}`;
39
+ }
40
+ function withAlphaOnWhite(hex, alpha) {
41
+ const rgb = hexToRgb(hex);
42
+ if (!rgb) return hex;
43
+ const r = rgb.r * alpha + 255 * (1 - alpha);
44
+ const g = rgb.g * alpha + 255 * (1 - alpha);
45
+ const b = rgb.b * alpha + 255 * (1 - alpha);
46
+ return rgbToHex(r, g, b);
47
+ }
48
+ function withAlphaOnDark(hex, alpha, bgHex = "#0f0f0f") {
49
+ const rgb = hexToRgb(hex);
50
+ const bg = hexToRgb(bgHex);
51
+ if (!rgb || !bg) return hex;
52
+ const r = rgb.r * alpha + bg.r * (1 - alpha);
53
+ const g = rgb.g * alpha + bg.g * (1 - alpha);
54
+ const b = rgb.b * alpha + bg.b * (1 - alpha);
55
+ return rgbToHex(r, g, b);
56
+ }
57
+ function mixWithBackground(fgHex, bgHex, opacity) {
58
+ const fg = hexToRgb(fgHex);
59
+ const bg = hexToRgb(bgHex);
60
+ if (!fg || !bg) return fgHex;
61
+ const r = fg.r * opacity + bg.r * (1 - opacity);
62
+ const g = fg.g * opacity + bg.g * (1 - opacity);
63
+ const b = fg.b * opacity + bg.b * (1 - opacity);
64
+ return rgbToHex(r, g, b);
65
+ }
66
+ function lighten(hex, amount) {
67
+ return withAlphaOnWhite(hex, 1 - amount);
68
+ }
69
+ function darken(hex, amount) {
70
+ const rgb = hexToRgb(hex);
71
+ if (!rgb) return hex;
72
+ return rgbToHex(rgb.r * (1 - amount), rgb.g * (1 - amount), rgb.b * (1 - amount));
73
+ }
74
+
23
75
  // src/theme/colors.ts
24
76
  var defaultLight = {
25
77
  background: "#ffffff",
26
- foreground: "#171717",
78
+ foreground: "#222222",
79
+ // Airbnb ink — deep near-black, never pure black
27
80
  card: "#ffffff",
28
- cardForeground: "#171717",
29
81
  primary: "#1a1a1a",
82
+ // Near-black primary — clean, premium default
30
83
  primaryForeground: "#ffffff",
31
- secondary: "#f1f1f1",
32
- secondaryForeground: "#171717",
33
- muted: "#f1f1f1",
34
- mutedForeground: "#a2a2a2",
35
- accent: "#e4e4e4",
36
- accentForeground: "#171717",
37
- destructive: "#ef4444",
84
+ border: "#dddddd",
85
+ // Airbnb hairline — light, airy
86
+ destructive: "#e53935",
38
87
  destructiveForeground: "#ffffff",
39
- border: "#e5e5e5",
40
- input: "#e5e5e5",
41
- ring: "#1a1a1a",
42
88
  success: "#1a7a45",
43
89
  successForeground: "#ffffff",
44
- destructiveTint: "#fff5f5",
45
- destructiveBorder: "#fecaca",
46
- successTint: "#f0fdf4",
47
- successBorder: "#bbf7d0"
90
+ warning: "#e67e00",
91
+ warningForeground: "#ffffff"
48
92
  };
49
93
  var defaultDark = {
50
94
  background: "#0f0f0f",
51
95
  foreground: "#fafafa",
52
96
  card: "#1c1c1c",
53
- cardForeground: "#fafafa",
54
97
  primary: "#fafafa",
55
98
  primaryForeground: "#0f0f0f",
56
- secondary: "#272727",
57
- secondaryForeground: "#fafafa",
58
- muted: "#272727",
59
- mutedForeground: "#9a9a9a",
60
- accent: "#2e2e2e",
61
- accentForeground: "#fafafa",
62
- destructive: "#dc2626",
63
- destructiveForeground: "#ffffff",
64
99
  border: "#303030",
65
- input: "#2a2a2a",
66
- ring: "#fafafa",
67
- success: "#166534",
100
+ destructive: "#ef5350",
101
+ destructiveForeground: "#ffffff",
102
+ success: "#2e7d52",
68
103
  successForeground: "#ffffff",
69
- destructiveTint: "#3b0a0a",
70
- destructiveBorder: "#7f1d1d",
71
- successTint: "#052e16",
72
- successBorder: "#166534"
104
+ warning: "#f57c00",
105
+ warningForeground: "#ffffff"
73
106
  };
107
+ function deriveColors(t, scheme) {
108
+ const dark = scheme === "dark";
109
+ const bg = t.background;
110
+ const foregroundSubtle = mixWithBackground(t.foreground, bg, 0.55);
111
+ const foregroundMuted = mixWithBackground(t.foreground, bg, 0.38);
112
+ const surface = dark ? lighten(bg, -0.06) : darken(bg, 0.04);
113
+ const surfaceStrong = dark ? lighten(bg, -0.12) : darken(bg, 0.08);
114
+ const destructiveTint = dark ? withAlphaOnDark(t.destructive, 0.15, bg) : withAlphaOnWhite(t.destructive, 0.08);
115
+ const destructiveBorder = dark ? withAlphaOnDark(t.destructive, 0.45, bg) : withAlphaOnWhite(t.destructive, 0.3);
116
+ const successTint = dark ? withAlphaOnDark(t.success, 0.15, bg) : withAlphaOnWhite(t.success, 0.08);
117
+ const successBorder = dark ? withAlphaOnDark(t.success, 0.45, bg) : withAlphaOnWhite(t.success, 0.3);
118
+ const warningTint = dark ? withAlphaOnDark(t.warning, 0.15, bg) : withAlphaOnWhite(t.warning, 0.08);
119
+ const warningBorder = dark ? withAlphaOnDark(t.warning, 0.45, bg) : withAlphaOnWhite(t.warning, 0.3);
120
+ return {
121
+ ...t,
122
+ foregroundSubtle,
123
+ foregroundMuted,
124
+ surface,
125
+ surfaceStrong,
126
+ destructiveTint,
127
+ destructiveBorder,
128
+ successTint,
129
+ successBorder,
130
+ warningTint,
131
+ warningBorder,
132
+ ring: t.primary,
133
+ // focus ring always = primary
134
+ input: t.border
135
+ // input border always = border
136
+ };
137
+ }
74
138
 
75
139
  // src/theme/ThemeProvider.tsx
76
140
  var ThemeContext = createContext({
77
- colors: defaultLight,
141
+ colors: deriveColors(defaultLight, "light"),
78
142
  colorScheme: "light"
79
143
  });
80
144
  function ThemeProvider({ children, theme, colorScheme = "system" }) {
@@ -83,7 +147,8 @@ function ThemeProvider({ children, theme, colorScheme = "system" }) {
83
147
  const colors = useMemo(() => {
84
148
  const base = resolvedScheme === "dark" ? defaultDark : defaultLight;
85
149
  const override = resolvedScheme === "dark" ? theme?.dark : theme?.light;
86
- return override ? { ...base, ...override } : base;
150
+ const merged = override ? { ...base, ...override } : base;
151
+ return deriveColors(merged, resolvedScheme);
87
152
  }, [resolvedScheme, theme]);
88
153
  return /* @__PURE__ */ React25.createElement(ThemeContext.Provider, { value: { colors, colorScheme: resolvedScheme } }, children);
89
154
  }
@@ -163,17 +228,194 @@ function renderIcon(name, size, color) {
163
228
  return React25.createElement(Icon, { name, size, color });
164
229
  }
165
230
 
231
+ // src/tokens.ts
232
+ var SPACING = {
233
+ xxs: 2,
234
+ xs: 4,
235
+ sm: 8,
236
+ md: 12,
237
+ base: 16,
238
+ lg: 24,
239
+ xl: 32,
240
+ xxl: 48,
241
+ section: 64
242
+ };
243
+ var ICON_SIZES = {
244
+ sm: 14,
245
+ md: 18,
246
+ lg: 22,
247
+ xl: 28,
248
+ "2xl": 32
249
+ };
250
+ var RADIUS = {
251
+ none: 0,
252
+ xs: 4,
253
+ sm: 8,
254
+ md: 14,
255
+ lg: 20,
256
+ xl: 32,
257
+ full: 9999
258
+ };
259
+ var SHADOWS = {
260
+ sm: {
261
+ shadowColor: "#000",
262
+ shadowOffset: { width: 0, height: 1 },
263
+ shadowOpacity: 0.06,
264
+ shadowRadius: 4,
265
+ elevation: 2
266
+ },
267
+ md: {
268
+ shadowColor: "#000",
269
+ shadowOffset: { width: 0, height: 2 },
270
+ shadowOpacity: 0.1,
271
+ shadowRadius: 8,
272
+ elevation: 5
273
+ },
274
+ lg: {
275
+ shadowColor: "#000",
276
+ shadowOffset: { width: 0, height: 6 },
277
+ shadowOpacity: 0.16,
278
+ shadowRadius: 16,
279
+ elevation: 10
280
+ },
281
+ xl: {
282
+ shadowColor: "#000",
283
+ shadowOffset: { width: 0, height: 12 },
284
+ shadowOpacity: 0.24,
285
+ shadowRadius: 24,
286
+ elevation: 18
287
+ }
288
+ };
289
+ var BREAKPOINTS = {
290
+ wide: 700
291
+ };
292
+ var TYPOGRAPHY = {
293
+ "display-hero": {
294
+ fontFamily: "Poppins-Bold",
295
+ fontSize: 64,
296
+ fontWeight: "700",
297
+ lineHeight: 70,
298
+ letterSpacing: -1
299
+ },
300
+ "display-xl": {
301
+ fontFamily: "Poppins-Bold",
302
+ fontSize: 28,
303
+ fontWeight: "700",
304
+ lineHeight: 40,
305
+ letterSpacing: 0
306
+ },
307
+ "display-lg": {
308
+ fontFamily: "Poppins-Medium",
309
+ fontSize: 22,
310
+ fontWeight: "500",
311
+ lineHeight: 26,
312
+ letterSpacing: -0.44
313
+ },
314
+ "display-md": {
315
+ fontFamily: "Poppins-Bold",
316
+ fontSize: 21,
317
+ fontWeight: "700",
318
+ lineHeight: 30,
319
+ letterSpacing: 0
320
+ },
321
+ "display-sm": {
322
+ fontFamily: "Poppins-SemiBold",
323
+ fontSize: 20,
324
+ fontWeight: "600",
325
+ lineHeight: 24,
326
+ letterSpacing: -0.18
327
+ },
328
+ "title-md": {
329
+ fontFamily: "Poppins-SemiBold",
330
+ fontSize: 16,
331
+ fontWeight: "600",
332
+ lineHeight: 20,
333
+ letterSpacing: 0
334
+ },
335
+ "title-sm": {
336
+ fontFamily: "Poppins-Medium",
337
+ fontSize: 16,
338
+ fontWeight: "500",
339
+ lineHeight: 20,
340
+ letterSpacing: 0
341
+ },
342
+ "body-md": {
343
+ fontFamily: "Poppins-Regular",
344
+ fontSize: 16,
345
+ fontWeight: "400",
346
+ lineHeight: 24,
347
+ letterSpacing: 0
348
+ },
349
+ "body-sm": {
350
+ fontFamily: "Poppins-Regular",
351
+ fontSize: 14,
352
+ fontWeight: "400",
353
+ lineHeight: 20,
354
+ letterSpacing: 0
355
+ },
356
+ caption: {
357
+ fontFamily: "Poppins-Medium",
358
+ fontSize: 14,
359
+ fontWeight: "500",
360
+ lineHeight: 18,
361
+ letterSpacing: 0
362
+ },
363
+ "caption-sm": {
364
+ fontFamily: "Poppins-Regular",
365
+ fontSize: 13,
366
+ fontWeight: "400",
367
+ lineHeight: 16,
368
+ letterSpacing: 0
369
+ },
370
+ "badge-text": {
371
+ fontFamily: "Poppins-SemiBold",
372
+ fontSize: 11,
373
+ fontWeight: "600",
374
+ lineHeight: 13,
375
+ letterSpacing: 0
376
+ },
377
+ "micro-label": {
378
+ fontFamily: "Poppins-Bold",
379
+ fontSize: 12,
380
+ fontWeight: "700",
381
+ lineHeight: 16,
382
+ letterSpacing: 0
383
+ },
384
+ "uppercase-tag": {
385
+ fontFamily: "Poppins-Bold",
386
+ fontSize: 8,
387
+ fontWeight: "700",
388
+ lineHeight: 10,
389
+ letterSpacing: 0.32,
390
+ textTransform: "uppercase"
391
+ },
392
+ "button-lg": {
393
+ fontFamily: "Poppins-Medium",
394
+ fontSize: 16,
395
+ fontWeight: "500",
396
+ lineHeight: 20,
397
+ letterSpacing: 0
398
+ },
399
+ "button-sm": {
400
+ fontFamily: "Poppins-Medium",
401
+ fontSize: 14,
402
+ fontWeight: "500",
403
+ lineHeight: 18,
404
+ letterSpacing: 0
405
+ }
406
+ };
407
+
166
408
  // src/components/Button/Button.tsx
167
409
  var nativeDriver = Platform.OS !== "web";
168
410
  var containerSizeStyles = {
169
- sm: { paddingHorizontal: s(12), paddingVertical: vs(10), minHeight: 44 },
170
- md: { paddingHorizontal: s(16), paddingVertical: vs(10), minHeight: 44 },
171
- lg: { paddingHorizontal: s(20), paddingVertical: vs(12), minHeight: 48 }
411
+ sm: { paddingHorizontal: s(16), paddingVertical: vs(10), minHeight: 40 },
412
+ md: { paddingHorizontal: s(24), paddingVertical: vs(14), minHeight: 48 },
413
+ lg: { paddingHorizontal: s(28), paddingVertical: vs(16), minHeight: 56 }
172
414
  };
173
415
  var labelSizeStyles = {
174
- sm: { fontSize: ms(13) },
175
- md: { fontSize: ms(15) },
176
- lg: { fontSize: ms(16) }
416
+ sm: { ...TYPOGRAPHY["button-sm"], fontSize: ms(TYPOGRAPHY["button-sm"].fontSize) },
417
+ md: { ...TYPOGRAPHY["button-lg"], fontSize: ms(TYPOGRAPHY["button-lg"].fontSize) },
418
+ lg: { ...TYPOGRAPHY["button-lg"], fontSize: ms(TYPOGRAPHY["button-lg"].fontSize + 1) }
177
419
  };
178
420
  var iconSizeMap = { sm: 16, md: 18, lg: 20 };
179
421
  function Button({
@@ -196,12 +438,7 @@ function Button({
196
438
  const scale2 = useRef(new Animated.Value(1)).current;
197
439
  const handlePressIn = () => {
198
440
  if (isDisabled) return;
199
- Animated.spring(scale2, {
200
- toValue: 0.95,
201
- useNativeDriver: nativeDriver,
202
- speed: 40,
203
- bounciness: 0
204
- }).start();
441
+ Animated.spring(scale2, { toValue: 0.95, useNativeDriver: nativeDriver, speed: 40, bounciness: 0 }).start();
205
442
  };
206
443
  const handlePressOut = () => {
207
444
  Animated.spring(scale2, { toValue: 1, useNativeDriver: nativeDriver, speed: 40, bounciness: 4 }).start();
@@ -212,20 +449,18 @@ function Button({
212
449
  };
213
450
  const containerVariantStyle = {
214
451
  primary: { backgroundColor: colors.primary },
215
- secondary: { backgroundColor: colors.secondary },
216
- outline: { backgroundColor: "transparent", borderWidth: 1.5, borderColor: colors.border },
217
- ghost: { backgroundColor: "transparent" },
452
+ secondary: { backgroundColor: "transparent", borderWidth: 1.5, borderColor: colors.primary },
453
+ text: { backgroundColor: "transparent" },
218
454
  destructive: { backgroundColor: colors.destructive }
219
455
  }[variant];
220
456
  const labelVariantStyle = {
221
457
  primary: { color: colors.primaryForeground },
222
- secondary: { color: colors.secondaryForeground },
223
- outline: { color: colors.foreground },
224
- ghost: { color: colors.foreground },
458
+ secondary: { color: colors.primary },
459
+ text: { color: colors.foreground },
225
460
  destructive: { color: colors.destructiveForeground }
226
461
  }[variant];
227
462
  const effectiveIcon = iconName ? renderIcon(iconName, iconSizeMap[size], iconColor ?? labelVariantStyle.color) : typeof icon === "function" ? icon({ label, size, variant }) : icon;
228
- const spinnerColor = variant === "destructive" ? colors.destructiveForeground : variant === "primary" || variant === "secondary" ? colors.primaryForeground : colors.foreground;
463
+ const spinnerColor = variant === "destructive" ? colors.destructiveForeground : variant === "primary" ? colors.primaryForeground : colors.foreground;
229
464
  return /* @__PURE__ */ React25.createElement(Animated.View, { style: [fullWidth && styles.fullWidth, { transform: [{ scale: scale2 }] }] }, /* @__PURE__ */ React25.createElement(
230
465
  TouchableOpacity,
231
466
  {
@@ -245,12 +480,20 @@ function Button({
245
480
  onPressOut: handlePressOut,
246
481
  ...props
247
482
  },
248
- loading ? /* @__PURE__ */ React25.createElement(ActivityIndicator, { size: "small", color: spinnerColor }) : /* @__PURE__ */ React25.createElement(React25.Fragment, null, effectiveIcon && iconPosition === "left" && /* @__PURE__ */ React25.createElement(React25.Fragment, null, effectiveIcon), /* @__PURE__ */ React25.createElement(Text, { style: [styles.label, labelVariantStyle, labelSizeStyles[size], effectiveIcon ? styles.labelWithIcon : void 0], allowFontScaling: true }, label), effectiveIcon && iconPosition === "right" && /* @__PURE__ */ React25.createElement(React25.Fragment, null, effectiveIcon))
483
+ loading ? /* @__PURE__ */ React25.createElement(ActivityIndicator, { size: "small", color: spinnerColor }) : /* @__PURE__ */ React25.createElement(React25.Fragment, null, effectiveIcon && iconPosition === "left" && /* @__PURE__ */ React25.createElement(React25.Fragment, null, effectiveIcon), /* @__PURE__ */ React25.createElement(
484
+ Text,
485
+ {
486
+ style: [styles.label, labelVariantStyle, labelSizeStyles[size], effectiveIcon ? styles.labelWithIcon : void 0],
487
+ allowFontScaling: true
488
+ },
489
+ label
490
+ ), effectiveIcon && iconPosition === "right" && /* @__PURE__ */ React25.createElement(React25.Fragment, null, effectiveIcon))
249
491
  ));
250
492
  }
251
493
  var styles = StyleSheet.create({
252
494
  base: {
253
- borderRadius: 8,
495
+ borderRadius: RADIUS.xl,
496
+ // 32px — pill-shaped primary CTA (Airbnb spec)
254
497
  alignItems: "center",
255
498
  justifyContent: "center",
256
499
  flexDirection: "row"
@@ -259,18 +502,18 @@ var styles = StyleSheet.create({
259
502
  width: "100%"
260
503
  },
261
504
  disabled: {
262
- opacity: 0.5
505
+ opacity: 0.45
263
506
  },
264
507
  label: {
265
- fontFamily: "Poppins-SemiBold"
508
+ fontFamily: "Poppins-Medium"
266
509
  },
267
510
  labelWithIcon: {
268
- marginHorizontal: s(8)
511
+ marginHorizontal: s(6)
269
512
  }
270
513
  });
271
514
  var nativeDriver2 = Platform.OS !== "web";
272
515
  var sizeMap = {
273
- sm: { container: s(40), icon: 18 },
516
+ sm: { container: s(32), icon: 16 },
274
517
  md: { container: s(44), icon: 20 },
275
518
  lg: { container: s(52), icon: 24 }
276
519
  };
@@ -281,6 +524,7 @@ function IconButton({
281
524
  variant = "primary",
282
525
  size = "md",
283
526
  loading = false,
527
+ badge,
284
528
  disabled,
285
529
  style,
286
530
  onPress,
@@ -291,20 +535,10 @@ function IconButton({
291
535
  const scale2 = useRef(new Animated.Value(1)).current;
292
536
  const handlePressIn = () => {
293
537
  if (isDisabled) return;
294
- Animated.spring(scale2, {
295
- toValue: 0.95,
296
- useNativeDriver: nativeDriver2,
297
- speed: 40,
298
- bounciness: 0
299
- }).start();
538
+ Animated.spring(scale2, { toValue: 0.95, useNativeDriver: nativeDriver2, speed: 40, bounciness: 0 }).start();
300
539
  };
301
540
  const handlePressOut = () => {
302
- Animated.spring(scale2, {
303
- toValue: 1,
304
- useNativeDriver: nativeDriver2,
305
- speed: 40,
306
- bounciness: 4
307
- }).start();
541
+ Animated.spring(scale2, { toValue: 1, useNativeDriver: nativeDriver2, speed: 40, bounciness: 4 }).start();
308
542
  };
309
543
  const handlePress = (e) => {
310
544
  impactLight();
@@ -312,22 +546,25 @@ function IconButton({
312
546
  };
313
547
  const containerVariantStyle = {
314
548
  primary: { backgroundColor: colors.primary },
315
- secondary: { backgroundColor: colors.secondary },
549
+ secondary: { backgroundColor: colors.surface },
316
550
  outline: { backgroundColor: "transparent", borderWidth: 1.5, borderColor: colors.border },
317
- ghost: { backgroundColor: "transparent" },
551
+ text: { backgroundColor: "transparent" },
318
552
  destructive: { backgroundColor: colors.destructive }
319
553
  }[variant];
320
554
  const defaultIconColor = {
321
555
  primary: colors.primaryForeground,
322
- secondary: colors.secondaryForeground,
556
+ secondary: colors.foreground,
323
557
  outline: colors.foreground,
324
- ghost: colors.foreground,
558
+ text: colors.foreground,
325
559
  destructive: colors.destructiveForeground
326
560
  }[variant];
327
- const spinnerColor = variant === "destructive" ? colors.destructiveForeground : variant === "primary" || variant === "secondary" ? colors.primaryForeground : colors.foreground;
561
+ const spinnerColor = variant === "destructive" ? colors.destructiveForeground : variant === "primary" ? colors.primaryForeground : colors.foreground;
328
562
  const { container: containerSize, icon: iconSize } = sizeMap[size];
329
563
  const resolvedIcon = iconName ? renderIcon(iconName, iconSize, iconColor ?? defaultIconColor) : icon;
330
- return /* @__PURE__ */ React25.createElement(Animated.View, { style: { transform: [{ scale: scale2 }] } }, /* @__PURE__ */ React25.createElement(
564
+ const showBadge = badge !== void 0 && badge !== false && badge !== 0;
565
+ const badgeCount = typeof badge === "number" ? Math.min(badge, 99) : null;
566
+ const showCount = typeof badge === "number" && badge > 0;
567
+ return /* @__PURE__ */ React25.createElement(Animated.View, { style: [styles2.wrapper, { transform: [{ scale: scale2 }] }] }, /* @__PURE__ */ React25.createElement(
331
568
  TouchableOpacity,
332
569
  {
333
570
  style: [
@@ -346,33 +583,93 @@ function IconButton({
346
583
  ...props
347
584
  },
348
585
  loading ? /* @__PURE__ */ React25.createElement(ActivityIndicator, { size: "small", color: spinnerColor }) : resolvedIcon
349
- ));
586
+ ), showBadge && /* @__PURE__ */ React25.createElement(View, { style: [
587
+ styles2.badge,
588
+ { backgroundColor: colors.primary },
589
+ showCount ? styles2.badgeCount : styles2.badgeDot
590
+ ] }, showCount && /* @__PURE__ */ React25.createElement(Text, { style: [styles2.badgeText, { color: colors.primaryForeground }] }, badgeCount)));
350
591
  }
351
592
  var styles2 = StyleSheet.create({
593
+ wrapper: {
594
+ alignSelf: "flex-start"
595
+ },
352
596
  base: {
353
- borderRadius: 999,
597
+ borderRadius: 9999,
354
598
  alignItems: "center",
355
599
  justifyContent: "center"
356
600
  },
357
601
  disabled: {
358
- opacity: 0.5
602
+ opacity: 0.45
603
+ },
604
+ badge: {
605
+ position: "absolute",
606
+ top: -2,
607
+ right: -2,
608
+ alignItems: "center",
609
+ justifyContent: "center"
610
+ },
611
+ badgeDot: {
612
+ width: 8,
613
+ height: 8,
614
+ borderRadius: 9999
615
+ },
616
+ badgeCount: {
617
+ minWidth: 16,
618
+ height: 16,
619
+ borderRadius: 9999,
620
+ paddingHorizontal: 3
621
+ },
622
+ badgeText: {
623
+ fontFamily: "Poppins-Bold",
624
+ fontSize: ms(9),
625
+ lineHeight: 14
359
626
  }
360
627
  });
361
628
  var variantStyles = {
362
- h1: { fontFamily: "Poppins-Bold", fontSize: ms(40), lineHeight: mvs(52) },
363
- h2: { fontFamily: "Poppins-Bold", fontSize: ms(28), lineHeight: mvs(36) },
364
- h3: { fontFamily: "Poppins-SemiBold", fontSize: ms(22), lineHeight: mvs(30) },
365
- body: { fontFamily: "Poppins-Regular", fontSize: ms(17), lineHeight: mvs(26) },
366
- caption: { fontFamily: "Poppins-Regular", fontSize: ms(13), lineHeight: mvs(20) },
367
- label: { fontFamily: "Poppins-Medium", fontSize: ms(15), lineHeight: mvs(22) }
629
+ "display-hero": { ...TYPOGRAPHY["display-hero"], fontSize: ms(TYPOGRAPHY["display-hero"].fontSize), lineHeight: mvs(TYPOGRAPHY["display-hero"].lineHeight) },
630
+ "display-xl": { ...TYPOGRAPHY["display-xl"], fontSize: ms(TYPOGRAPHY["display-xl"].fontSize), lineHeight: mvs(TYPOGRAPHY["display-xl"].lineHeight) },
631
+ "display-lg": { ...TYPOGRAPHY["display-lg"], fontSize: ms(TYPOGRAPHY["display-lg"].fontSize), lineHeight: mvs(TYPOGRAPHY["display-lg"].lineHeight) },
632
+ "display-md": { ...TYPOGRAPHY["display-md"], fontSize: ms(TYPOGRAPHY["display-md"].fontSize), lineHeight: mvs(TYPOGRAPHY["display-md"].lineHeight) },
633
+ "display-sm": { ...TYPOGRAPHY["display-sm"], fontSize: ms(TYPOGRAPHY["display-sm"].fontSize), lineHeight: mvs(TYPOGRAPHY["display-sm"].lineHeight) },
634
+ "title-md": { ...TYPOGRAPHY["title-md"], fontSize: ms(TYPOGRAPHY["title-md"].fontSize), lineHeight: mvs(TYPOGRAPHY["title-md"].lineHeight) },
635
+ "title-sm": { ...TYPOGRAPHY["title-sm"], fontSize: ms(TYPOGRAPHY["title-sm"].fontSize), lineHeight: mvs(TYPOGRAPHY["title-sm"].lineHeight) },
636
+ "body-md": { ...TYPOGRAPHY["body-md"], fontSize: ms(TYPOGRAPHY["body-md"].fontSize), lineHeight: mvs(TYPOGRAPHY["body-md"].lineHeight) },
637
+ "body-sm": { ...TYPOGRAPHY["body-sm"], fontSize: ms(TYPOGRAPHY["body-sm"].fontSize), lineHeight: mvs(TYPOGRAPHY["body-sm"].lineHeight) },
638
+ caption: { ...TYPOGRAPHY["caption"], fontSize: ms(TYPOGRAPHY["caption"].fontSize), lineHeight: mvs(TYPOGRAPHY["caption"].lineHeight) },
639
+ "caption-sm": { ...TYPOGRAPHY["caption-sm"], fontSize: ms(TYPOGRAPHY["caption-sm"].fontSize), lineHeight: mvs(TYPOGRAPHY["caption-sm"].lineHeight) },
640
+ "badge-text": { ...TYPOGRAPHY["badge-text"], fontSize: ms(TYPOGRAPHY["badge-text"].fontSize), lineHeight: mvs(TYPOGRAPHY["badge-text"].lineHeight) },
641
+ "micro-label": { ...TYPOGRAPHY["micro-label"], fontSize: ms(TYPOGRAPHY["micro-label"].fontSize), lineHeight: mvs(TYPOGRAPHY["micro-label"].lineHeight) },
642
+ "uppercase-tag": { ...TYPOGRAPHY["uppercase-tag"], fontSize: ms(TYPOGRAPHY["uppercase-tag"].fontSize), lineHeight: mvs(TYPOGRAPHY["uppercase-tag"].lineHeight) },
643
+ "button-lg": { ...TYPOGRAPHY["button-lg"], fontSize: ms(TYPOGRAPHY["button-lg"].fontSize), lineHeight: mvs(TYPOGRAPHY["button-lg"].lineHeight) },
644
+ "button-sm": { ...TYPOGRAPHY["button-sm"], fontSize: ms(TYPOGRAPHY["button-sm"].fontSize), lineHeight: mvs(TYPOGRAPHY["button-sm"].lineHeight) }
368
645
  };
369
- function Text2({ variant = "body", color, style, children, ...props }) {
646
+ var defaultColorVariant = {
647
+ "display-hero": "foreground",
648
+ "display-xl": "foreground",
649
+ "display-lg": "foreground",
650
+ "display-md": "foreground",
651
+ "display-sm": "foreground",
652
+ "title-md": "foreground",
653
+ "title-sm": "foreground",
654
+ "body-md": "foregroundSubtle",
655
+ // running text — slightly softer
656
+ "body-sm": "foregroundSubtle",
657
+ caption: "foregroundMuted",
658
+ "caption-sm": "foregroundMuted",
659
+ "badge-text": "foreground",
660
+ "micro-label": "foreground",
661
+ "uppercase-tag": "foregroundMuted",
662
+ "button-lg": "foreground",
663
+ "button-sm": "foreground"
664
+ };
665
+ function Text3({ variant = "body-md", color, style, children, ...props }) {
370
666
  const { colors } = useTheme();
371
- const defaultColor = variant === "caption" ? colors.mutedForeground : colors.foreground;
667
+ const colorKey = defaultColorVariant[variant] ?? "foreground";
668
+ const resolvedColor = color ?? colors[colorKey];
372
669
  return /* @__PURE__ */ React25.createElement(
373
670
  Text,
374
671
  {
375
- style: [variantStyles[variant], { color: color ?? defaultColor }, style],
672
+ style: [variantStyles[variant], { color: resolvedColor }, style],
376
673
  allowFontScaling: true,
377
674
  ...props
378
675
  },
@@ -386,21 +683,21 @@ function Input({ label, error, hint, prefix, suffix, prefixStyle, suffixStyle, p
386
683
  const [showPassword, setShowPassword] = useState(false);
387
684
  const isPassword = type === "password";
388
685
  const effectiveSecure = isPassword ? !showPassword : secureTextEntry;
389
- const effectivePrefix = prefixIcon ? renderIcon(prefixIcon, 20, prefixIconColor ?? colors.mutedForeground) : prefix;
390
- const effectiveSuffix = isPassword && !suffix && !suffixIcon ? /* @__PURE__ */ React25.createElement(TouchableOpacity, { onPress: () => setShowPassword(!showPassword), style: styles3.passwordToggle, activeOpacity: 0.6 }, /* @__PURE__ */ React25.createElement(AntDesign$1, { name: showPassword ? "eye" : "eye-invisible", size: 20, color: colors.mutedForeground })) : suffixIcon ? renderIcon(suffixIcon, 20, suffixIconColor ?? colors.mutedForeground) : suffix;
686
+ const effectivePrefix = prefixIcon ? renderIcon(prefixIcon, 20, prefixIconColor ?? colors.foregroundMuted) : prefix;
687
+ const effectiveSuffix = isPassword && !suffix && !suffixIcon ? /* @__PURE__ */ React25.createElement(TouchableOpacity, { onPress: () => setShowPassword(!showPassword), style: styles3.passwordToggle, activeOpacity: 0.6 }, /* @__PURE__ */ React25.createElement(AntDesign$1, { name: showPassword ? "eye" : "eye-invisible", size: 20, color: colors.foregroundMuted })) : suffixIcon ? renderIcon(suffixIcon, 20, suffixIconColor ?? colors.foregroundMuted) : suffix;
391
688
  return /* @__PURE__ */ React25.createElement(View, { style: [styles3.container, containerStyle] }, label ? /* @__PURE__ */ React25.createElement(Text, { style: [styles3.label, { color: colors.foreground }], allowFontScaling: true }, label) : null, /* @__PURE__ */ React25.createElement(
392
689
  View,
393
690
  {
394
691
  style: [
395
692
  styles3.inputWrapper,
396
693
  {
397
- borderColor: error ? colors.destructive : focused ? colors.ring ?? colors.primary : colors.border,
694
+ borderColor: error ? colors.destructive : focused ? colors.primary : colors.border,
398
695
  backgroundColor: colors.background
399
696
  },
400
697
  inputWrapperStyle
401
698
  ]
402
699
  },
403
- effectivePrefix ? typeof effectivePrefix === "string" ? /* @__PURE__ */ React25.createElement(Text, { style: [styles3.prefixText, { color: colors.mutedForeground }, prefixStyle], allowFontScaling: true }, effectivePrefix) : /* @__PURE__ */ React25.createElement(View, { style: styles3.prefixContainer }, effectivePrefix) : null,
700
+ effectivePrefix ? typeof effectivePrefix === "string" ? /* @__PURE__ */ React25.createElement(Text, { style: [styles3.prefixText, { color: colors.foregroundMuted }, prefixStyle], allowFontScaling: true }, effectivePrefix) : /* @__PURE__ */ React25.createElement(View, { style: styles3.prefixContainer }, effectivePrefix) : null,
404
701
  /* @__PURE__ */ React25.createElement(
405
702
  TextInput,
406
703
  {
@@ -420,14 +717,14 @@ function Input({ label, error, hint, prefix, suffix, prefixStyle, suffixStyle, p
420
717
  setFocused(false);
421
718
  onBlur?.(e);
422
719
  },
423
- placeholderTextColor: colors.mutedForeground,
720
+ placeholderTextColor: colors.foregroundMuted,
424
721
  allowFontScaling: true,
425
722
  secureTextEntry: effectiveSecure,
426
723
  ...props
427
724
  }
428
725
  ),
429
- effectiveSuffix ? typeof effectiveSuffix === "string" ? /* @__PURE__ */ React25.createElement(Text, { style: [styles3.suffixText, { color: colors.mutedForeground }, suffixStyle], allowFontScaling: true }, effectiveSuffix) : /* @__PURE__ */ React25.createElement(View, { style: styles3.suffixContainer }, effectiveSuffix) : null
430
- ), error ? /* @__PURE__ */ React25.createElement(Text, { style: [styles3.helperText, { color: colors.destructive }], allowFontScaling: true }, error) : null, !error && hint ? /* @__PURE__ */ React25.createElement(Text, { style: [styles3.helperText, { color: colors.mutedForeground }], allowFontScaling: true }, hint) : null);
726
+ effectiveSuffix ? typeof effectiveSuffix === "string" ? /* @__PURE__ */ React25.createElement(Text, { style: [styles3.suffixText, { color: colors.foregroundMuted }, suffixStyle], allowFontScaling: true }, effectiveSuffix) : /* @__PURE__ */ React25.createElement(View, { style: styles3.suffixContainer }, effectiveSuffix) : null
727
+ ), error ? /* @__PURE__ */ React25.createElement(Text, { style: [styles3.helperText, { color: colors.destructive }], allowFontScaling: true }, error) : null, !error && hint ? /* @__PURE__ */ React25.createElement(Text, { style: [styles3.helperText, { color: colors.foregroundMuted }], allowFontScaling: true }, hint) : null);
431
728
  }
432
729
  var styles3 = StyleSheet.create({
433
730
  container: {
@@ -435,21 +732,24 @@ var styles3 = StyleSheet.create({
435
732
  },
436
733
  label: {
437
734
  fontFamily: "Poppins-Medium",
438
- fontSize: ms(13)
735
+ fontSize: ms(14)
736
+ // caption size for input labels
439
737
  },
440
738
  inputWrapper: {
441
739
  flexDirection: "row",
442
740
  alignItems: "center",
443
- borderWidth: 1,
444
- borderRadius: ms(8),
741
+ borderWidth: 2,
742
+ borderRadius: 8,
445
743
  paddingHorizontal: s(14),
446
- paddingVertical: vs(11)
744
+ paddingVertical: vs(11),
745
+ minHeight: 48
447
746
  },
448
747
  input: {
449
748
  fontFamily: "Poppins-Regular",
450
749
  flex: 1,
451
- fontSize: ms(15),
452
- paddingVertical: 0
750
+ fontSize: ms(16),
751
+ paddingVertical: vs(2),
752
+ includeFontPadding: false
453
753
  },
454
754
  prefixContainer: {
455
755
  marginRight: s(8)
@@ -495,23 +795,25 @@ function Badge({ label, children, variant = "default", size = "md", icon, iconNa
495
795
  const { colors } = useTheme();
496
796
  const containerStyle = {
497
797
  default: { backgroundColor: colors.primary },
498
- secondary: { backgroundColor: colors.secondary },
798
+ secondary: { backgroundColor: colors.surface },
499
799
  destructive: { backgroundColor: colors.destructive },
500
800
  outline: { backgroundColor: "transparent", borderWidth: 1, borderColor: colors.border },
501
801
  success: { backgroundColor: colors.success },
502
- warning: { backgroundColor: "#f59e0b" },
802
+ warning: { backgroundColor: colors.warning },
503
803
  successOutline: { backgroundColor: colors.successTint, borderWidth: 1, borderColor: colors.successBorder },
504
- destructiveOutline: { backgroundColor: colors.destructiveTint, borderWidth: 1, borderColor: colors.destructiveBorder }
804
+ destructiveOutline: { backgroundColor: colors.destructiveTint, borderWidth: 1, borderColor: colors.destructiveBorder },
805
+ warningOutline: { backgroundColor: colors.warningTint, borderWidth: 1, borderColor: colors.warningBorder }
505
806
  }[variant];
506
807
  const textColor = {
507
808
  default: colors.primaryForeground,
508
- secondary: colors.secondaryForeground,
809
+ secondary: colors.foreground,
509
810
  destructive: colors.destructiveForeground,
510
811
  outline: colors.foreground,
511
812
  success: colors.successForeground,
512
- warning: "#ffffff",
813
+ warning: colors.warningForeground,
513
814
  successOutline: colors.success,
514
- destructiveOutline: colors.destructive
815
+ destructiveOutline: colors.destructive,
816
+ warningOutline: colors.warning
515
817
  }[variant];
516
818
  const effectiveIcon = iconName ? renderIcon(iconName, sizeIconSize[size], iconColor ?? textColor) : icon;
517
819
  const content = children ?? label;
@@ -572,7 +874,7 @@ function Card({ children, variant = "elevated", onPress, style }) {
572
874
  elevation: 0
573
875
  },
574
876
  filled: {
575
- backgroundColor: colors.accent,
877
+ backgroundColor: colors.surfaceStrong,
576
878
  borderColor: colors.border,
577
879
  shadowOpacity: 0,
578
880
  elevation: 0
@@ -599,11 +901,11 @@ function CardHeader({ children, style }) {
599
901
  }
600
902
  function CardTitle({ children, style }) {
601
903
  const { colors } = useTheme();
602
- return /* @__PURE__ */ React25.createElement(Text, { style: [styles5.title, { color: colors.cardForeground }, style], allowFontScaling: true }, children);
904
+ return /* @__PURE__ */ React25.createElement(Text, { style: [styles5.title, { color: colors.foreground }, style], allowFontScaling: true }, children);
603
905
  }
604
906
  function CardDescription({ children, style }) {
605
907
  const { colors } = useTheme();
606
- return /* @__PURE__ */ React25.createElement(Text, { style: [styles5.description, { color: colors.mutedForeground }, style], allowFontScaling: true }, children);
908
+ return /* @__PURE__ */ React25.createElement(Text, { style: [styles5.description, { color: colors.foregroundMuted }, style], allowFontScaling: true }, children);
607
909
  }
608
910
  function CardContent({ children, style }) {
609
911
  return /* @__PURE__ */ React25.createElement(View, { style: [styles5.content, style] }, children);
@@ -613,7 +915,8 @@ function CardFooter({ children, style }) {
613
915
  }
614
916
  var styles5 = StyleSheet.create({
615
917
  card: {
616
- borderRadius: ms(12),
918
+ borderRadius: 14,
919
+ // RADIUS.md — Airbnb property card spec
617
920
  borderWidth: 1
618
921
  },
619
922
  header: {
@@ -682,7 +985,7 @@ function Spinner({ size = "md", color, label, ...props }) {
682
985
  return /* @__PURE__ */ React25.createElement(View, { style: styles7.wrapper }, /* @__PURE__ */ React25.createElement(ActivityIndicator, { size: sizeMap2[size], color: color ?? colors.primary, ...props }), /* @__PURE__ */ React25.createElement(
683
986
  Text,
684
987
  {
685
- style: [styles7.label, { color: colors.mutedForeground, fontSize: labelFontSize[size] }],
988
+ style: [styles7.label, { color: colors.foregroundMuted, fontSize: labelFontSize[size] }],
686
989
  allowFontScaling: true
687
990
  },
688
991
  label
@@ -700,18 +1003,21 @@ var styles7 = StyleSheet.create({
700
1003
  lineHeight: mvs(18)
701
1004
  }
702
1005
  });
703
- function Skeleton({ width = "100%", height = 16, borderRadius = 6, style }) {
1006
+ function Skeleton({
1007
+ width = "100%",
1008
+ height = 16,
1009
+ borderRadius = 6,
1010
+ preset = "base",
1011
+ diameter = 40,
1012
+ style
1013
+ }) {
704
1014
  const { colors, colorScheme } = useTheme();
705
1015
  const shimmerAnim = useRef(new Animated.Value(0)).current;
706
1016
  const [containerWidth, setContainerWidth] = useState(300);
707
1017
  const shimmerHighlight = colorScheme === "dark" ? "rgba(255,255,255,0.08)" : "rgba(255,255,255,0.7)";
708
1018
  useEffect(() => {
709
1019
  const animation = Animated.loop(
710
- Animated.timing(shimmerAnim, {
711
- toValue: 1,
712
- duration: 1200,
713
- useNativeDriver: true
714
- })
1020
+ Animated.timing(shimmerAnim, { toValue: 1, duration: 1200, useNativeDriver: true })
715
1021
  );
716
1022
  animation.start();
717
1023
  return () => animation.stop();
@@ -720,12 +1026,15 @@ function Skeleton({ width = "100%", height = 16, borderRadius = 6, style }) {
720
1026
  inputRange: [0, 1],
721
1027
  outputRange: [-containerWidth, containerWidth]
722
1028
  });
1029
+ const resolvedWidth = preset === "circle" ? s(diameter) : preset === "text" ? "60%" : width;
1030
+ const resolvedHeight = preset === "circle" ? s(diameter) : preset === "text" ? 14 : height;
1031
+ const resolvedRadius = preset === "circle" ? 9999 : preset === "text" ? 4 : borderRadius;
723
1032
  return /* @__PURE__ */ React25.createElement(
724
1033
  View,
725
1034
  {
726
1035
  style: [
727
1036
  styles8.base,
728
- { width, height, borderRadius, backgroundColor: colors.muted },
1037
+ { width: resolvedWidth, height: resolvedHeight, borderRadius: resolvedRadius, backgroundColor: colors.surface },
729
1038
  style
730
1039
  ],
731
1040
  onLayout: (e) => setContainerWidth(e.nativeEvent.layout.width)
@@ -758,19 +1067,32 @@ var fontSizeMap = {
758
1067
  lg: ms(22),
759
1068
  xl: ms(28)
760
1069
  };
761
- function Avatar({ src, fallback, size = "md", style }) {
1070
+ var statusSizeMap = {
1071
+ sm: 8,
1072
+ md: 10,
1073
+ lg: 13,
1074
+ xl: 16
1075
+ };
1076
+ function Avatar({ src, fallback, size = "md", status, style }) {
762
1077
  const { colors } = useTheme();
763
1078
  const [imageError, setImageError] = useState(false);
764
1079
  const dimension = sizeMap3[size];
765
1080
  const showFallback = !src || imageError;
1081
+ const statusSize = statusSizeMap[size];
1082
+ const statusColor = {
1083
+ online: "#22c55e",
1084
+ offline: "transparent",
1085
+ busy: colors.destructive,
1086
+ away: colors.warning
1087
+ };
766
1088
  const containerStyle = {
767
1089
  width: dimension,
768
1090
  height: dimension,
769
1091
  borderRadius: dimension / 2,
770
- backgroundColor: colors.muted,
1092
+ backgroundColor: colors.surface,
771
1093
  overflow: "hidden"
772
1094
  };
773
- return /* @__PURE__ */ React25.createElement(View, { style: [styles9.base, containerStyle, style] }, !showFallback ? /* @__PURE__ */ React25.createElement(
1095
+ return /* @__PURE__ */ React25.createElement(View, { style: [styles9.wrapper, style] }, /* @__PURE__ */ React25.createElement(View, { style: [styles9.base, containerStyle] }, !showFallback ? /* @__PURE__ */ React25.createElement(
774
1096
  Image,
775
1097
  {
776
1098
  source: { uri: src },
@@ -780,64 +1102,86 @@ function Avatar({ src, fallback, size = "md", style }) {
780
1102
  ) : /* @__PURE__ */ React25.createElement(
781
1103
  Text,
782
1104
  {
783
- style: [styles9.fallback, { color: colors.mutedForeground, fontSize: fontSizeMap[size] }],
1105
+ style: [styles9.fallback, { color: colors.foregroundMuted, fontSize: fontSizeMap[size] }],
784
1106
  allowFontScaling: true
785
1107
  },
786
1108
  fallback?.slice(0, 2).toUpperCase() ?? "?"
1109
+ )), status && /* @__PURE__ */ React25.createElement(
1110
+ View,
1111
+ {
1112
+ style: [
1113
+ styles9.statusDot,
1114
+ {
1115
+ width: statusSize,
1116
+ height: statusSize,
1117
+ borderRadius: statusSize / 2,
1118
+ backgroundColor: statusColor[status],
1119
+ borderWidth: status === "offline" ? 2 : 1.5,
1120
+ borderColor: status === "offline" ? colors.border : colors.background
1121
+ }
1122
+ ]
1123
+ }
787
1124
  ));
788
1125
  }
789
1126
  var styles9 = StyleSheet.create({
1127
+ wrapper: {
1128
+ alignSelf: "flex-start",
1129
+ position: "relative"
1130
+ },
790
1131
  base: {
791
1132
  alignItems: "center",
792
1133
  justifyContent: "center"
793
1134
  },
794
1135
  fallback: {
795
1136
  fontFamily: "Poppins-Medium"
1137
+ },
1138
+ statusDot: {
1139
+ position: "absolute",
1140
+ bottom: 0,
1141
+ right: 0
796
1142
  }
797
1143
  });
798
1144
  function AlertBanner({ title, description, variant = "default", icon, iconName, iconColor, style }) {
799
1145
  const { colors } = useTheme();
800
- const bgColor = variant === "destructive" ? colors.destructiveBorder : variant === "success" ? colors.successBorder : colors.card;
801
- const textColor = variant === "destructive" ? "#991b1b" : variant === "success" ? "#166534" : colors.foreground;
802
- const borderColor = textColor;
803
- const defaultIcon = variant === "success" ? /* @__PURE__ */ React25.createElement(FontAwesome5$1, { name: "check-circle", size: 18, color: textColor }) : variant === "destructive" ? /* @__PURE__ */ React25.createElement(MaterialIcons$1, { name: "error-outline", size: 20, color: textColor }) : /* @__PURE__ */ React25.createElement(Entypo$1, { name: "info-with-circle", size: 18, color: textColor });
804
- const effectiveIcon = iconName ? renderIcon(iconName, 18, iconColor ?? textColor) : icon ?? defaultIcon;
805
- return /* @__PURE__ */ React25.createElement(View, { style: [styles10.container, { backgroundColor: bgColor, borderColor }, style] }, /* @__PURE__ */ React25.createElement(View, { style: styles10.header }, /* @__PURE__ */ React25.createElement(View, { style: styles10.icon }, effectiveIcon), title ? /* @__PURE__ */ React25.createElement(Text, { style: [styles10.title, { color: textColor }], allowFontScaling: true }, title) : null), description ? /* @__PURE__ */ React25.createElement(Text, { style: [styles10.description, { color: textColor, opacity: 0.85 }], allowFontScaling: true }, description) : null);
1146
+ const bgColor = variant === "destructive" ? colors.destructiveTint : variant === "success" ? colors.successTint : variant === "warning" ? colors.warningTint : colors.card;
1147
+ const borderColor = variant === "destructive" ? colors.destructiveBorder : variant === "success" ? colors.successBorder : variant === "warning" ? colors.warningBorder : colors.border;
1148
+ const accentColor = variant === "destructive" ? colors.destructive : variant === "success" ? colors.success : variant === "warning" ? colors.warning : colors.primary;
1149
+ const titleColor = variant === "default" ? colors.foreground : accentColor;
1150
+ const descColor = variant === "default" ? colors.foregroundMuted : accentColor;
1151
+ const defaultIcon = variant === "success" ? /* @__PURE__ */ React25.createElement(FontAwesome5$1, { name: "check-circle", size: 16, color: accentColor }) : variant === "destructive" ? /* @__PURE__ */ React25.createElement(MaterialIcons$1, { name: "error-outline", size: 17, color: accentColor }) : variant === "warning" ? /* @__PURE__ */ React25.createElement(MaterialIcons$1, { name: "warning-amber", size: 17, color: accentColor }) : /* @__PURE__ */ React25.createElement(Entypo$1, { name: "info-with-circle", size: 16, color: accentColor });
1152
+ const effectiveIcon = iconName ? renderIcon(iconName, 16, iconColor ?? accentColor) : icon ?? defaultIcon;
1153
+ return /* @__PURE__ */ React25.createElement(View, { style: [styles10.container, { backgroundColor: bgColor, borderColor }, style] }, /* @__PURE__ */ React25.createElement(View, { style: styles10.iconSlot }, effectiveIcon), /* @__PURE__ */ React25.createElement(View, { style: styles10.content }, /* @__PURE__ */ React25.createElement(Text, { style: [styles10.title, { color: titleColor }], allowFontScaling: true }, title), description ? /* @__PURE__ */ React25.createElement(Text, { style: [styles10.description, { color: descColor }], allowFontScaling: true }, description) : null));
806
1154
  }
807
1155
  var styles10 = StyleSheet.create({
808
1156
  container: {
809
- borderWidth: 1,
810
- borderRadius: ms(12),
811
- paddingHorizontal: s(14),
812
- paddingVertical: vs(12),
813
- gap: vs(8),
814
- shadowColor: "#000",
815
- shadowOffset: { width: 0, height: 3 },
816
- shadowOpacity: 0.1,
817
- shadowRadius: 8,
818
- elevation: 5
819
- },
820
- header: {
821
1157
  flexDirection: "row",
822
- alignItems: "center",
1158
+ alignItems: "flex-start",
1159
+ borderWidth: 0.5,
1160
+ borderRadius: 10,
1161
+ paddingHorizontal: s(12),
1162
+ paddingVertical: vs(10),
823
1163
  gap: s(10)
824
1164
  },
825
- icon: {
826
- marginTop: 0
1165
+ iconSlot: {
1166
+ marginTop: vs(1)
1167
+ },
1168
+ content: {
1169
+ flex: 1,
1170
+ gap: vs(2)
827
1171
  },
828
1172
  title: {
829
- fontFamily: "Poppins-Bold",
830
- fontSize: ms(15),
831
- lineHeight: mvs(20),
832
- flex: 1
1173
+ fontFamily: "Poppins-Medium",
1174
+ fontSize: ms(13),
1175
+ lineHeight: ms(18)
833
1176
  },
834
1177
  description: {
835
1178
  fontFamily: "Poppins-Regular",
836
- fontSize: ms(14),
837
- lineHeight: mvs(20)
1179
+ fontSize: ms(12),
1180
+ lineHeight: ms(17),
1181
+ opacity: 0.85
838
1182
  }
839
1183
  });
840
- function Progress({ value = 0, max = 100, style }) {
1184
+ function Progress({ value = 0, max = 100, variant = "default", style }) {
841
1185
  const { colors } = useTheme();
842
1186
  const percent = Math.min(Math.max(value / max * 100, 0), 100);
843
1187
  const [trackWidth, setTrackWidth] = useState(0);
@@ -851,16 +1195,17 @@ function Progress({ value = 0, max = 100, style }) {
851
1195
  bounciness: 0
852
1196
  }).start();
853
1197
  }, [percent, trackWidth]);
1198
+ const indicatorColor = variant === "success" ? colors.success : variant === "warning" ? colors.warning : variant === "destructive" ? colors.destructive : colors.primary;
854
1199
  return /* @__PURE__ */ React25.createElement(
855
1200
  View,
856
1201
  {
857
- style: [styles11.track, { backgroundColor: colors.muted }, style],
1202
+ style: [styles11.track, { backgroundColor: colors.surface }, style],
858
1203
  onLayout: (e) => setTrackWidth(e.nativeEvent.layout.width)
859
1204
  },
860
1205
  /* @__PURE__ */ React25.createElement(
861
1206
  Animated.View,
862
1207
  {
863
- style: [styles11.indicator, { width: animatedWidth, backgroundColor: colors.primary }]
1208
+ style: [styles11.indicator, { width: animatedWidth, backgroundColor: indicatorColor }]
864
1209
  }
865
1210
  )
866
1211
  );
@@ -868,19 +1213,19 @@ function Progress({ value = 0, max = 100, style }) {
868
1213
  var styles11 = StyleSheet.create({
869
1214
  track: {
870
1215
  height: vs(8),
871
- borderRadius: 999,
1216
+ borderRadius: 9999,
872
1217
  overflow: "hidden",
873
1218
  width: "100%"
874
1219
  },
875
1220
  indicator: {
876
1221
  height: "100%",
877
- borderRadius: 999
1222
+ borderRadius: 9999
878
1223
  }
879
1224
  });
880
1225
  function EmptyState({ icon, iconName, iconColor, title, description, action, size = "default", style }) {
881
1226
  const { colors } = useTheme();
882
1227
  const isCompact = size === "compact";
883
- const effectiveIcon = iconName ? renderIcon(iconName, isCompact ? 32 : 48, iconColor ?? colors.mutedForeground) : icon;
1228
+ const effectiveIcon = iconName ? renderIcon(iconName, isCompact ? 32 : 48, iconColor ?? colors.foregroundMuted) : icon;
884
1229
  return /* @__PURE__ */ React25.createElement(
885
1230
  View,
886
1231
  {
@@ -897,7 +1242,7 @@ function EmptyState({ icon, iconName, iconColor, title, description, action, siz
897
1242
  style: [
898
1243
  styles12.iconWrapper,
899
1244
  isCompact && styles12.iconWrapperCompact,
900
- { backgroundColor: colors.muted }
1245
+ { backgroundColor: colors.surface }
901
1246
  ]
902
1247
  },
903
1248
  effectiveIcon
@@ -909,7 +1254,7 @@ function EmptyState({ icon, iconName, iconColor, title, description, action, siz
909
1254
  allowFontScaling: true
910
1255
  },
911
1256
  title
912
- ), description && !isCompact ? /* @__PURE__ */ React25.createElement(Text, { style: [styles12.description, { color: colors.mutedForeground }], allowFontScaling: true }, description) : null),
1257
+ ), description && !isCompact ? /* @__PURE__ */ React25.createElement(Text, { style: [styles12.description, { color: colors.foregroundMuted }], allowFontScaling: true }, description) : null),
913
1258
  action && !isCompact ? /* @__PURE__ */ React25.createElement(View, { style: styles12.action }, action) : null
914
1259
  );
915
1260
  }
@@ -928,16 +1273,16 @@ var styles12 = StyleSheet.create({
928
1273
  gap: vs(10)
929
1274
  },
930
1275
  iconWrapper: {
931
- width: s(48),
932
- height: s(48),
933
- borderRadius: ms(12),
1276
+ width: s(80),
1277
+ height: s(80),
1278
+ borderRadius: ms(20),
934
1279
  alignItems: "center",
935
1280
  justifyContent: "center"
936
1281
  },
937
1282
  iconWrapperCompact: {
938
- width: s(36),
939
- height: s(36),
940
- borderRadius: ms(8)
1283
+ width: s(56),
1284
+ height: s(56),
1285
+ borderRadius: ms(14)
941
1286
  },
942
1287
  textWrapper: {
943
1288
  alignItems: "center",
@@ -1001,11 +1346,11 @@ function Textarea({
1001
1346
  setFocused(false);
1002
1347
  onBlur?.(e);
1003
1348
  },
1004
- placeholderTextColor: colors.mutedForeground,
1349
+ placeholderTextColor: colors.foregroundMuted,
1005
1350
  allowFontScaling: true,
1006
1351
  ...props
1007
1352
  }
1008
- ), error ? /* @__PURE__ */ React25.createElement(Text, { style: [styles13.helperText, { color: colors.destructive }], allowFontScaling: true }, error) : null, !error && hint ? /* @__PURE__ */ React25.createElement(Text, { style: [styles13.helperText, { color: colors.mutedForeground }], allowFontScaling: true }, hint) : null);
1353
+ ), error ? /* @__PURE__ */ React25.createElement(Text, { style: [styles13.helperText, { color: colors.destructive }], allowFontScaling: true }, error) : null, !error && hint ? /* @__PURE__ */ React25.createElement(Text, { style: [styles13.helperText, { color: colors.foregroundMuted }], allowFontScaling: true }, hint) : null);
1009
1354
  }
1010
1355
  var styles13 = StyleSheet.create({
1011
1356
  container: {
@@ -1017,11 +1362,12 @@ var styles13 = StyleSheet.create({
1017
1362
  },
1018
1363
  input: {
1019
1364
  fontFamily: "Poppins-Regular",
1020
- borderWidth: 1,
1365
+ borderWidth: 2,
1021
1366
  borderRadius: ms(8),
1022
1367
  paddingHorizontal: s(14),
1023
1368
  paddingVertical: vs(11),
1024
- fontSize: ms(15)
1369
+ fontSize: ms(15),
1370
+ includeFontPadding: false
1025
1371
  },
1026
1372
  helperText: {
1027
1373
  fontFamily: "Poppins-Regular",
@@ -1038,6 +1384,30 @@ function Checkbox({
1038
1384
  }) {
1039
1385
  const { colors } = useTheme();
1040
1386
  const scale2 = useRef(new Animated.Value(1)).current;
1387
+ const bgOpacity = useRef(new Animated.Value(checked ? 1 : 0)).current;
1388
+ const checkOpacity = useRef(new Animated.Value(checked ? 1 : 0)).current;
1389
+ useEffect(() => {
1390
+ Animated.parallel([
1391
+ Animated.timing(bgOpacity, {
1392
+ toValue: checked ? 1 : 0,
1393
+ duration: 150,
1394
+ useNativeDriver: false
1395
+ }),
1396
+ Animated.timing(checkOpacity, {
1397
+ toValue: checked ? 1 : 0,
1398
+ duration: 120,
1399
+ useNativeDriver: false
1400
+ })
1401
+ ]).start();
1402
+ }, [checked, bgOpacity, checkOpacity]);
1403
+ const borderColor = bgOpacity.interpolate({
1404
+ inputRange: [0, 1],
1405
+ outputRange: [colors.border, colors.primary]
1406
+ });
1407
+ const backgroundColor = bgOpacity.interpolate({
1408
+ inputRange: [0, 1],
1409
+ outputRange: ["transparent", colors.primary]
1410
+ });
1041
1411
  const handlePressIn = () => {
1042
1412
  if (disabled) return;
1043
1413
  Animated.spring(scale2, { toValue: 0.95, useNativeDriver: nativeDriver4, speed: 40, bounciness: 0 }).start();
@@ -1059,25 +1429,24 @@ function Checkbox({
1059
1429
  activeOpacity: 1,
1060
1430
  touchSoundDisabled: true
1061
1431
  },
1062
- /* @__PURE__ */ React25.createElement(
1432
+ /* @__PURE__ */ React25.createElement(Animated.View, { style: { transform: [{ scale: scale2 }] } }, /* @__PURE__ */ React25.createElement(
1063
1433
  Animated.View,
1064
1434
  {
1065
1435
  style: [
1066
1436
  styles14.box,
1067
1437
  {
1068
- borderColor: checked ? colors.primary : colors.border,
1069
- backgroundColor: checked ? colors.primary : "transparent",
1070
- opacity: disabled ? 0.45 : 1,
1071
- transform: [{ scale: scale2 }]
1438
+ borderColor,
1439
+ backgroundColor,
1440
+ opacity: disabled ? 0.45 : 1
1072
1441
  }
1073
1442
  ]
1074
1443
  },
1075
- checked ? /* @__PURE__ */ React25.createElement(View, { style: [styles14.checkmark, { borderColor: colors.primaryForeground }] }) : null
1076
- ),
1444
+ /* @__PURE__ */ React25.createElement(Animated.View, { style: { opacity: checkOpacity } }, /* @__PURE__ */ React25.createElement(View, { style: [styles14.checkmark, { borderColor: colors.primaryForeground }] }))
1445
+ )),
1077
1446
  label ? /* @__PURE__ */ React25.createElement(
1078
1447
  Text,
1079
1448
  {
1080
- style: [styles14.label, { color: disabled ? colors.mutedForeground : colors.foreground }],
1449
+ style: [styles14.label, { color: disabled ? colors.foregroundMuted : colors.foreground }],
1081
1450
  allowFontScaling: true
1082
1451
  },
1083
1452
  label
@@ -1117,10 +1486,13 @@ var TRACK_HEIGHT = s(30);
1117
1486
  var THUMB_SIZE = s(24);
1118
1487
  var THUMB_OFFSET = s(3);
1119
1488
  var THUMB_TRAVEL = TRACK_WIDTH - THUMB_SIZE - THUMB_OFFSET * 2;
1489
+ var ICON_SIZE = s(13);
1120
1490
  function Switch({ checked = false, onCheckedChange, disabled, style }) {
1121
1491
  const { colors } = useTheme();
1122
1492
  const translateX = useRef(new Animated.Value(checked ? THUMB_TRAVEL : 0)).current;
1123
1493
  const trackOpacity = useRef(new Animated.Value(checked ? 1 : 0)).current;
1494
+ const checkOpacity = useRef(new Animated.Value(checked ? 1 : 0)).current;
1495
+ const crossOpacity = useRef(new Animated.Value(checked ? 0 : 1)).current;
1124
1496
  useEffect(() => {
1125
1497
  Animated.parallel([
1126
1498
  Animated.spring(translateX, {
@@ -1132,12 +1504,22 @@ function Switch({ checked = false, onCheckedChange, disabled, style }) {
1132
1504
  toValue: checked ? 1 : 0,
1133
1505
  duration: 150,
1134
1506
  useNativeDriver: false
1507
+ }),
1508
+ Animated.timing(checkOpacity, {
1509
+ toValue: checked ? 1 : 0,
1510
+ duration: 120,
1511
+ useNativeDriver: true
1512
+ }),
1513
+ Animated.timing(crossOpacity, {
1514
+ toValue: checked ? 0 : 1,
1515
+ duration: 120,
1516
+ useNativeDriver: true
1135
1517
  })
1136
1518
  ]).start();
1137
- }, [checked, translateX, trackOpacity]);
1519
+ }, [checked, translateX, trackOpacity, checkOpacity, crossOpacity]);
1138
1520
  const trackColor = trackOpacity.interpolate({
1139
1521
  inputRange: [0, 1],
1140
- outputRange: [colors.muted, colors.primary]
1522
+ outputRange: [colors.surface, colors.primary]
1141
1523
  });
1142
1524
  return /* @__PURE__ */ React25.createElement(View, { style: [{ opacity: disabled ? 0.45 : 1 }, style] }, /* @__PURE__ */ React25.createElement(
1143
1525
  TouchableOpacity,
@@ -1158,7 +1540,9 @@ function Switch({ checked = false, onCheckedChange, disabled, style }) {
1158
1540
  styles15.thumb,
1159
1541
  { backgroundColor: colors.primaryForeground, transform: [{ translateX }] }
1160
1542
  ]
1161
- }
1543
+ },
1544
+ /* @__PURE__ */ React25.createElement(Animated.View, { style: [styles15.iconWrapper, { opacity: checkOpacity }] }, /* @__PURE__ */ React25.createElement(Feather$1, { name: "check", size: ICON_SIZE, color: colors.primary })),
1545
+ /* @__PURE__ */ React25.createElement(Animated.View, { style: [styles15.iconWrapper, { opacity: crossOpacity }] }, /* @__PURE__ */ React25.createElement(Feather$1, { name: "x", size: ICON_SIZE, color: colors.foregroundMuted }))
1162
1546
  ))
1163
1547
  ));
1164
1548
  }
@@ -1182,7 +1566,12 @@ var styles15 = StyleSheet.create({
1182
1566
  shadowOffset: { width: 0, height: 1 },
1183
1567
  shadowOpacity: 0.15,
1184
1568
  shadowRadius: 2,
1185
- elevation: 2
1569
+ elevation: 2,
1570
+ alignItems: "center",
1571
+ justifyContent: "center"
1572
+ },
1573
+ iconWrapper: {
1574
+ position: "absolute"
1186
1575
  }
1187
1576
  });
1188
1577
  var nativeDriver6 = Platform.OS !== "web";
@@ -1232,7 +1621,7 @@ function Toggle({
1232
1621
  });
1233
1622
  const backgroundColor = pressAnim.interpolate({
1234
1623
  inputRange: [0, 1],
1235
- outputRange: ["transparent", colors.accent]
1624
+ outputRange: ["transparent", colors.surfaceStrong]
1236
1625
  });
1237
1626
  const textColor = pressAnim.interpolate({
1238
1627
  inputRange: [0, 1],
@@ -1251,10 +1640,10 @@ function Toggle({
1251
1640
  if (active) return /* @__PURE__ */ React25.createElement(React25.Fragment, null, active);
1252
1641
  return /* @__PURE__ */ React25.createElement(FontAwesome5$1, { name: "check-circle", size: iconSize, color: colors.primary });
1253
1642
  }
1254
- if (iconName) return /* @__PURE__ */ React25.createElement(React25.Fragment, null, renderIcon(iconName, iconSize, iconColor ?? colors.mutedForeground));
1643
+ if (iconName) return /* @__PURE__ */ React25.createElement(React25.Fragment, null, renderIcon(iconName, iconSize, iconColor ?? colors.foregroundMuted));
1255
1644
  const custom = renderProp(icon);
1256
1645
  if (custom) return /* @__PURE__ */ React25.createElement(React25.Fragment, null, custom);
1257
- return /* @__PURE__ */ React25.createElement(FontAwesome5$1, { name: "circle", size: iconSize, color: colors.mutedForeground });
1646
+ return /* @__PURE__ */ React25.createElement(FontAwesome5$1, { name: "circle", size: iconSize, color: colors.foregroundMuted });
1258
1647
  };
1259
1648
  return /* @__PURE__ */ React25.createElement(Animated.View, { style: [{ transform: [{ scale: scale2 }] }, disabled && styles16.disabled, style] }, /* @__PURE__ */ React25.createElement(
1260
1649
  TouchableOpacity,
@@ -1351,7 +1740,7 @@ function RadioItem({
1351
1740
  {
1352
1741
  style: [
1353
1742
  styles17.label,
1354
- { color: option.disabled ? colors.mutedForeground : colors.foreground }
1743
+ { color: option.disabled ? colors.foregroundMuted : colors.foreground }
1355
1744
  ],
1356
1745
  allowFontScaling: true
1357
1746
  },
@@ -1413,7 +1802,8 @@ function TabTrigger({
1413
1802
  tab,
1414
1803
  isActive,
1415
1804
  onPress,
1416
- onLayout
1805
+ onLayout,
1806
+ variant
1417
1807
  }) {
1418
1808
  const { colors } = useTheme();
1419
1809
  const scale2 = useRef(new Animated.Value(1)).current;
@@ -1423,10 +1813,15 @@ function TabTrigger({
1423
1813
  const handlePressOut = () => {
1424
1814
  Animated.spring(scale2, { toValue: 1, useNativeDriver: nativeDriver8, speed: 40, bounciness: 4 }).start();
1425
1815
  };
1816
+ const isUnderline = variant === "underline";
1426
1817
  return /* @__PURE__ */ React25.createElement(
1427
1818
  TouchableOpacity,
1428
1819
  {
1429
- style: styles18.trigger,
1820
+ style: [
1821
+ styles18.trigger,
1822
+ isUnderline && styles18.triggerUnderline,
1823
+ isUnderline && isActive && { borderBottomColor: colors.primary }
1824
+ ],
1430
1825
  onPress,
1431
1826
  onPressIn: handlePressIn,
1432
1827
  onPressOut: handlePressOut,
@@ -1439,8 +1834,8 @@ function TabTrigger({
1439
1834
  {
1440
1835
  style: [
1441
1836
  styles18.triggerLabel,
1442
- { color: isActive ? colors.foreground : colors.mutedForeground },
1443
- isActive && styles18.activeTriggerLabel
1837
+ { color: isActive ? colors.foreground : colors.foregroundMuted },
1838
+ isActive && (isUnderline ? styles18.activeTriggerLabelUnderline : styles18.activeTriggerLabel)
1444
1839
  ],
1445
1840
  allowFontScaling: true
1446
1841
  },
@@ -1448,7 +1843,7 @@ function TabTrigger({
1448
1843
  )))
1449
1844
  );
1450
1845
  }
1451
- function Tabs({ tabs, value, onValueChange, children, style }) {
1846
+ function Tabs({ tabs, variant = "pill", value, onValueChange, children, style }) {
1452
1847
  const [internal, setInternal] = useState(tabs[0]?.value ?? "");
1453
1848
  const { colors } = useTheme();
1454
1849
  const active = value ?? internal;
@@ -1461,18 +1856,8 @@ function Tabs({ tabs, value, onValueChange, children, style }) {
1461
1856
  if (!layout) return;
1462
1857
  if (animate) {
1463
1858
  Animated.parallel([
1464
- Animated.spring(pillX, {
1465
- toValue: layout.x,
1466
- useNativeDriver: false,
1467
- speed: 20,
1468
- bounciness: 0
1469
- }),
1470
- Animated.spring(pillWidth, {
1471
- toValue: layout.width,
1472
- useNativeDriver: false,
1473
- speed: 20,
1474
- bounciness: 0
1475
- })
1859
+ Animated.spring(pillX, { toValue: layout.x, useNativeDriver: false, speed: 20, bounciness: 0 }),
1860
+ Animated.spring(pillWidth, { toValue: layout.width, useNativeDriver: false, speed: 20, bounciness: 0 })
1476
1861
  ]).start();
1477
1862
  } else {
1478
1863
  pillX.setValue(layout.x);
@@ -1480,16 +1865,16 @@ function Tabs({ tabs, value, onValueChange, children, style }) {
1480
1865
  }
1481
1866
  };
1482
1867
  useEffect(() => {
1483
- if (initialised.current) {
1484
- animatePill(active, true);
1485
- }
1868
+ if (initialised.current) animatePill(active, true);
1486
1869
  }, [active]);
1487
1870
  const handlePress = (v) => {
1488
1871
  selectionAsync();
1489
1872
  if (!value) setInternal(v);
1490
1873
  onValueChange?.(v);
1491
1874
  };
1492
- return /* @__PURE__ */ React25.createElement(View, { style }, /* @__PURE__ */ React25.createElement(View, { style: [styles18.list, { backgroundColor: colors.muted }] }, /* @__PURE__ */ React25.createElement(
1875
+ return /* @__PURE__ */ React25.createElement(View, { style }, /* @__PURE__ */ React25.createElement(View, { style: [
1876
+ variant === "pill" ? [styles18.list, { backgroundColor: colors.surface }] : styles18.listUnderline
1877
+ ] }, variant === "pill" && /* @__PURE__ */ React25.createElement(
1493
1878
  Animated.View,
1494
1879
  {
1495
1880
  style: [
@@ -1504,7 +1889,7 @@ function Tabs({ tabs, value, onValueChange, children, style }) {
1504
1889
  borderRadius: 8,
1505
1890
  shadowColor: "#000",
1506
1891
  shadowOffset: { width: 0, height: 1 },
1507
- shadowOpacity: 0.1,
1892
+ shadowOpacity: 0.08,
1508
1893
  shadowRadius: 2,
1509
1894
  elevation: 2
1510
1895
  }
@@ -1517,6 +1902,7 @@ function Tabs({ tabs, value, onValueChange, children, style }) {
1517
1902
  tab,
1518
1903
  isActive: tab.value === active,
1519
1904
  onPress: () => handlePress(tab.value),
1905
+ variant,
1520
1906
  onLayout: (e) => {
1521
1907
  const { x, width } = e.nativeEvent.layout;
1522
1908
  tabLayouts.current[tab.value] = { x, width };
@@ -1535,20 +1921,32 @@ function TabsContent({ value, activeValue, children, style }) {
1535
1921
  var styles18 = StyleSheet.create({
1536
1922
  list: {
1537
1923
  flexDirection: "row",
1538
- borderRadius: ms(12),
1924
+ borderRadius: 12,
1539
1925
  padding: s(4),
1540
1926
  gap: s(4)
1541
1927
  },
1928
+ listUnderline: {
1929
+ flexDirection: "row",
1930
+ borderBottomWidth: 1
1931
+ },
1542
1932
  pill: {},
1543
1933
  trigger: {
1544
1934
  flex: 1,
1545
1935
  paddingVertical: vs(7),
1546
1936
  paddingHorizontal: s(10),
1547
- borderRadius: ms(6),
1937
+ borderRadius: 8,
1548
1938
  alignItems: "center",
1549
1939
  justifyContent: "center",
1550
1940
  zIndex: 1
1551
1941
  },
1942
+ triggerUnderline: {
1943
+ flex: 0,
1944
+ paddingVertical: vs(12),
1945
+ paddingHorizontal: s(16),
1946
+ borderRadius: 0,
1947
+ borderBottomWidth: 2,
1948
+ borderBottomColor: "transparent"
1949
+ },
1552
1950
  triggerInner: {
1553
1951
  flexDirection: "row",
1554
1952
  alignItems: "center",
@@ -1561,6 +1959,10 @@ var styles18 = StyleSheet.create({
1561
1959
  },
1562
1960
  activeTriggerLabel: {
1563
1961
  fontFamily: "Poppins-Medium"
1962
+ },
1963
+ activeTriggerLabelUnderline: {
1964
+ fontFamily: "Poppins-SemiBold",
1965
+ fontSize: ms(14)
1564
1966
  }
1565
1967
  });
1566
1968
  function AccordionItemComponent({
@@ -1603,7 +2005,7 @@ function AccordionItemComponent({
1603
2005
  }
1604
2006
  },
1605
2007
  /* @__PURE__ */ React25.createElement(Text, { style: [styles19.triggerText, { color: colors.foreground }], allowFontScaling: true }, item.trigger),
1606
- /* @__PURE__ */ React25.createElement(Animated11.View, { style: [styles19.chevron, rotationStyle] }, /* @__PURE__ */ React25.createElement(Entypo$1, { name: "chevron-down", size: 18, color: colors.mutedForeground }))
2008
+ /* @__PURE__ */ React25.createElement(Animated11.View, { style: [styles19.chevron, rotationStyle] }, /* @__PURE__ */ React25.createElement(Entypo$1, { name: "chevron-down", size: 18, color: colors.foregroundMuted }))
1607
2009
  ), /* @__PURE__ */ React25.createElement(Animated11.View, { style: bodyStyle }, /* @__PURE__ */ React25.createElement(
1608
2010
  View,
1609
2011
  {
@@ -1695,7 +2097,7 @@ function Slider({
1695
2097
  }
1696
2098
  onValueChange?.(v);
1697
2099
  };
1698
- return /* @__PURE__ */ React25.createElement(View, { style: [styles20.wrapper, style], accessibilityLabel }, label || showValue ? /* @__PURE__ */ React25.createElement(View, { style: styles20.header }, label ? /* @__PURE__ */ React25.createElement(Text, { style: [styles20.label, { color: colors.foreground }], allowFontScaling: true }, label) : null, showValue ? /* @__PURE__ */ React25.createElement(Text, { style: [styles20.valueText, { color: colors.mutedForeground }], allowFontScaling: true }, formatValue2(value)) : null) : null, /* @__PURE__ */ React25.createElement(View, { style: disabled ? styles20.disabled : void 0 }, /* @__PURE__ */ React25.createElement(
2100
+ return /* @__PURE__ */ React25.createElement(View, { style: [styles20.wrapper, style], accessibilityLabel }, label || showValue ? /* @__PURE__ */ React25.createElement(View, { style: styles20.header }, label ? /* @__PURE__ */ React25.createElement(Text, { style: [styles20.label, { color: colors.foreground }], allowFontScaling: true }, label) : null, showValue ? /* @__PURE__ */ React25.createElement(Text, { style: [styles20.valueText, { color: colors.foregroundMuted }], allowFontScaling: true }, formatValue2(value)) : null) : null, /* @__PURE__ */ React25.createElement(View, { style: disabled ? styles20.disabled : void 0 }, /* @__PURE__ */ React25.createElement(
1699
2101
  RNSlider,
1700
2102
  {
1701
2103
  value,
@@ -1706,7 +2108,7 @@ function Slider({
1706
2108
  onValueChange: handleValueChange,
1707
2109
  onSlidingComplete,
1708
2110
  minimumTrackTintColor: colors.primary,
1709
- maximumTrackTintColor: colors.muted,
2111
+ maximumTrackTintColor: colors.surface,
1710
2112
  thumbTintColor: colors.primary,
1711
2113
  style: styles20.slider,
1712
2114
  accessibilityLabel
@@ -1744,7 +2146,6 @@ function Sheet({
1744
2146
  title,
1745
2147
  description,
1746
2148
  children,
1747
- snapPoints = ["50%"],
1748
2149
  style
1749
2150
  }) {
1750
2151
  const { colors } = useTheme();
@@ -1770,14 +2171,14 @@ function Sheet({
1770
2171
  BottomSheetModal,
1771
2172
  {
1772
2173
  ref,
1773
- snapPoints,
2174
+ enableDynamicSizing: true,
1774
2175
  onDismiss: onClose,
1775
2176
  backdropComponent: renderBackdrop,
1776
2177
  backgroundStyle: [styles21.background, { backgroundColor: colors.card }],
1777
2178
  handleIndicatorStyle: [styles21.handle, { backgroundColor: colors.border }],
1778
2179
  enablePanDownToClose: true
1779
2180
  },
1780
- /* @__PURE__ */ React25.createElement(BottomSheetView, { style: [styles21.content, style] }, title || description ? /* @__PURE__ */ React25.createElement(View, { style: styles21.header }, title ? /* @__PURE__ */ React25.createElement(Text, { style: [styles21.title, { color: colors.cardForeground }], allowFontScaling: true }, title) : null, description ? /* @__PURE__ */ React25.createElement(Text, { style: [styles21.description, { color: colors.mutedForeground }], allowFontScaling: true }, description) : null) : null, children)
2181
+ /* @__PURE__ */ React25.createElement(BottomSheetView, { style: [styles21.content, style] }, title || description ? /* @__PURE__ */ React25.createElement(View, { style: styles21.header }, title ? /* @__PURE__ */ React25.createElement(Text, { style: [styles21.title, { color: colors.foreground }], allowFontScaling: true }, title) : null, description ? /* @__PURE__ */ React25.createElement(Text, { style: [styles21.description, { color: colors.foregroundMuted }], allowFontScaling: true }, description) : null) : null, children)
1781
2182
  );
1782
2183
  }
1783
2184
  var styles21 = StyleSheet.create({
@@ -1876,14 +2277,14 @@ function Select({
1876
2277
  {
1877
2278
  style: [
1878
2279
  styles22.triggerText,
1879
- { color: selected ? colors.foreground : colors.mutedForeground }
2280
+ { color: selected ? colors.foreground : colors.foregroundMuted }
1880
2281
  ],
1881
2282
  numberOfLines: 1,
1882
2283
  allowFontScaling: true
1883
2284
  },
1884
2285
  selected?.label ?? placeholder
1885
2286
  ),
1886
- /* @__PURE__ */ React25.createElement(Entypo$1, { name: "chevron-with-circle-down", size: 20, color: colors.mutedForeground })
2287
+ /* @__PURE__ */ React25.createElement(Entypo$1, { name: "chevron-with-circle-down", size: 20, color: colors.foregroundMuted })
1887
2288
  )) : null, isIOS ? /* @__PURE__ */ React25.createElement(
1888
2289
  Modal,
1889
2290
  {
@@ -1900,7 +2301,7 @@ function Select({
1900
2301
  onValueChange: (val) => setPendingValue(val),
1901
2302
  itemStyle: { color: colors.foreground }
1902
2303
  },
1903
- !value ? /* @__PURE__ */ React25.createElement(Picker.Item, { label: placeholder, value: "", color: colors.mutedForeground, enabled: false }) : null,
2304
+ !value ? /* @__PURE__ */ React25.createElement(Picker.Item, { label: placeholder, value: "", color: colors.foregroundMuted, enabled: false }) : null,
1904
2305
  options.map((o) => /* @__PURE__ */ React25.createElement(
1905
2306
  Picker.Item,
1906
2307
  {
@@ -1908,7 +2309,7 @@ function Select({
1908
2309
  label: o.label,
1909
2310
  value: o.value,
1910
2311
  enabled: !o.disabled,
1911
- color: o.disabled ? colors.mutedForeground : colors.foreground
2312
+ color: o.disabled ? colors.foregroundMuted : colors.foreground
1912
2313
  }
1913
2314
  ))
1914
2315
  ))
@@ -1952,7 +2353,7 @@ function Select({
1952
2353
  styles22.webPicker,
1953
2354
  {
1954
2355
  borderColor: error ? colors.destructive : colors.border,
1955
- color: selected ? colors.foreground : colors.mutedForeground,
2356
+ color: selected ? colors.foreground : colors.foregroundMuted,
1956
2357
  backgroundColor: colors.background,
1957
2358
  opacity: disabled ? 0.45 : 1
1958
2359
  }
@@ -2087,19 +2488,39 @@ function ToastNotification({ item, onDismiss }) {
2087
2488
  }));
2088
2489
  const variant = item.variant ?? "default";
2089
2490
  const bgColor = {
2090
- default: colors.foreground,
2491
+ default: colors.card,
2492
+ destructive: colors.destructiveTint,
2493
+ success: colors.successTint,
2494
+ warning: colors.warningTint
2495
+ }[variant];
2496
+ const borderColor = {
2497
+ default: colors.border,
2091
2498
  destructive: colors.destructiveBorder,
2092
- success: colors.successBorder
2499
+ success: colors.successBorder,
2500
+ warning: colors.warningBorder
2093
2501
  }[variant];
2094
- const textColor = {
2095
- default: colors.background,
2096
- destructive: "#991b1b",
2097
- success: "#166534"
2502
+ const accentColor = {
2503
+ default: colors.primary,
2504
+ destructive: colors.destructive,
2505
+ success: colors.success,
2506
+ warning: colors.warning
2098
2507
  }[variant];
2099
- const borderColor = textColor;
2100
- const defaultIcon = variant === "success" ? /* @__PURE__ */ React25.createElement(FontAwesome5$1, { name: "check-circle", size: 18, color: textColor }) : variant === "destructive" ? /* @__PURE__ */ React25.createElement(AntDesign$1, { name: "exclamation-circle", size: 18, color: textColor }) : /* @__PURE__ */ React25.createElement(Entypo$1, { name: "info-with-circle", size: 18, color: textColor });
2101
- const leftIcon = item.iconName ? renderIcon(item.iconName, 22, item.iconColor ?? textColor) : item.icon ?? defaultIcon;
2102
- return /* @__PURE__ */ React25.createElement(GestureDetector, { gesture: panGesture }, /* @__PURE__ */ React25.createElement(Animated11.View, { style: [styles23.toast, { backgroundColor: bgColor, borderColor }, animatedStyle] }, /* @__PURE__ */ React25.createElement(View, { style: styles23.leftIconContainer }, leftIcon), /* @__PURE__ */ React25.createElement(View, { style: styles23.toastContent }, item.title ? /* @__PURE__ */ React25.createElement(Text, { style: [styles23.toastTitle, { color: textColor }], allowFontScaling: true }, item.title) : null, item.description ? /* @__PURE__ */ React25.createElement(Text, { style: [styles23.toastDescription, { color: textColor, opacity: 0.85 }], allowFontScaling: true }, item.description) : null), /* @__PURE__ */ React25.createElement(TouchableOpacity, { onPress: onDismiss, style: styles23.dismissButton, touchSoundDisabled: true }, /* @__PURE__ */ React25.createElement(AntDesign$1, { name: "close-circle", size: 18, color: textColor }))));
2508
+ const titleColor = variant === "default" ? colors.foreground : accentColor;
2509
+ const descColor = variant === "default" ? colors.foregroundMuted : accentColor;
2510
+ const defaultIcon = variant === "success" ? /* @__PURE__ */ React25.createElement(FontAwesome5$1, { name: "check-circle", size: 16, color: accentColor }) : variant === "destructive" ? /* @__PURE__ */ React25.createElement(AntDesign$1, { name: "exclamation-circle", size: 16, color: accentColor }) : variant === "warning" ? /* @__PURE__ */ React25.createElement(MaterialIcons$1, { name: "warning-amber", size: 17, color: accentColor }) : /* @__PURE__ */ React25.createElement(Entypo$1, { name: "info-with-circle", size: 16, color: accentColor });
2511
+ const leftIcon = item.iconName ? renderIcon(item.iconName, 16, item.iconColor ?? accentColor) : item.icon ?? defaultIcon;
2512
+ return /* @__PURE__ */ React25.createElement(GestureDetector, { gesture: panGesture }, /* @__PURE__ */ React25.createElement(Animated11.View, { style: [styles23.toast, { backgroundColor: bgColor, borderColor }, animatedStyle] }, /* @__PURE__ */ React25.createElement(View, { style: styles23.leftIconContainer }, leftIcon), /* @__PURE__ */ React25.createElement(View, { style: styles23.toastContent }, item.title ? /* @__PURE__ */ React25.createElement(Text, { style: [styles23.toastTitle, { color: titleColor }], allowFontScaling: true }, item.title) : null, item.description ? /* @__PURE__ */ React25.createElement(Text, { style: [styles23.toastDescription, { color: descColor }], allowFontScaling: true }, item.description) : null), item.action && /* @__PURE__ */ React25.createElement(
2513
+ TouchableOpacity,
2514
+ {
2515
+ onPress: () => {
2516
+ item.action.onPress();
2517
+ onDismiss();
2518
+ },
2519
+ style: styles23.actionButton,
2520
+ touchSoundDisabled: true
2521
+ },
2522
+ /* @__PURE__ */ React25.createElement(Text, { style: [styles23.actionLabel, { color: accentColor }], allowFontScaling: true }, item.action.label)
2523
+ ), /* @__PURE__ */ React25.createElement(TouchableOpacity, { onPress: onDismiss, style: styles23.dismissButton, touchSoundDisabled: true }, /* @__PURE__ */ React25.createElement(AntDesign$1, { name: "close-circle", size: 16, color: descColor }))));
2103
2524
  }
2104
2525
  function ToastProvider({ children }) {
2105
2526
  const [toasts, setToasts] = useState([]);
@@ -2110,6 +2531,8 @@ function ToastProvider({ children }) {
2110
2531
  notificationSuccess();
2111
2532
  } else if (item.variant === "destructive") {
2112
2533
  notificationError();
2534
+ } else if (item.variant === "warning") {
2535
+ notificationError();
2113
2536
  } else {
2114
2537
  impactLight();
2115
2538
  }
@@ -2136,38 +2559,52 @@ var styles23 = StyleSheet.create({
2136
2559
  },
2137
2560
  toast: {
2138
2561
  flexDirection: "row",
2139
- alignItems: "center",
2140
- borderRadius: ms(12),
2141
- borderWidth: 1,
2142
- paddingHorizontal: s(14),
2143
- paddingVertical: vs(12),
2562
+ alignItems: "flex-start",
2563
+ borderRadius: ms(10),
2564
+ borderWidth: 0.5,
2565
+ paddingHorizontal: s(12),
2566
+ paddingVertical: vs(10),
2144
2567
  shadowColor: "#000",
2145
- shadowOffset: { width: 0, height: 3 },
2146
- shadowOpacity: 0.1,
2147
- shadowRadius: 8,
2148
- elevation: 5
2568
+ shadowOffset: { width: 0, height: 2 },
2569
+ shadowOpacity: 0.06,
2570
+ shadowRadius: 4,
2571
+ elevation: 3
2149
2572
  },
2150
2573
  toastContent: {
2151
2574
  flex: 1,
2152
- gap: vs(4)
2575
+ gap: vs(2)
2153
2576
  },
2154
2577
  leftIconContainer: {
2155
- width: s(28),
2578
+ marginTop: vs(1),
2156
2579
  alignItems: "center",
2157
2580
  justifyContent: "center",
2158
2581
  marginRight: s(10)
2159
2582
  },
2160
2583
  toastTitle: {
2161
- fontFamily: "Poppins-SemiBold",
2162
- fontSize: ms(15)
2584
+ fontFamily: "Poppins-Medium",
2585
+ fontSize: ms(13),
2586
+ lineHeight: ms(18)
2163
2587
  },
2164
2588
  toastDescription: {
2165
2589
  fontFamily: "Poppins-Regular",
2166
- fontSize: ms(14)
2590
+ fontSize: ms(12),
2591
+ lineHeight: ms(17),
2592
+ opacity: 0.85
2167
2593
  },
2168
- dismissButton: {
2169
- padding: s(8),
2594
+ actionButton: {
2595
+ paddingHorizontal: s(8),
2596
+ paddingVertical: vs(4),
2170
2597
  marginLeft: s(4)
2598
+ },
2599
+ actionLabel: {
2600
+ fontFamily: "Poppins-Medium",
2601
+ fontSize: ms(12),
2602
+ textDecorationLine: "underline"
2603
+ },
2604
+ dismissButton: {
2605
+ padding: s(6),
2606
+ marginLeft: s(2),
2607
+ marginTop: vs(0)
2171
2608
  }
2172
2609
  });
2173
2610
  function formatCurrency(raw, separator) {
@@ -2201,7 +2638,7 @@ function CurrencyInput({
2201
2638
  onChangeValue?.(isNaN(raw) ? 0 : raw);
2202
2639
  };
2203
2640
  const inputStyle = size === "large" ? { fontFamily: "Poppins-Regular", fontSize: ms(36) } : { fontFamily: "Poppins-Regular" };
2204
- const dollarIcon = renderIcon("dollar-sign", size === "large" ? 24 : 16, colors.mutedForeground);
2641
+ const dollarIcon = renderIcon("dollar-sign", size === "large" ? 24 : 16, colors.foregroundMuted);
2205
2642
  const displayValue = value && prefix && value.startsWith(prefix) ? value.slice(prefix.length) : value;
2206
2643
  return /* @__PURE__ */ React25.createElement(
2207
2644
  Input,
@@ -2216,7 +2653,7 @@ function CurrencyInput({
2216
2653
  editable,
2217
2654
  prefix: dollarIcon,
2218
2655
  containerStyle,
2219
- inputWrapperStyle: size === "large" ? { paddingVertical: 10 } : void 0,
2656
+ inputWrapperStyle: size === "large" ? { paddingVertical: vs(16), minHeight: 72 } : void 0,
2220
2657
  style: [inputStyle, style]
2221
2658
  }
2222
2659
  );
@@ -2242,7 +2679,8 @@ var styles24 = StyleSheet.create({
2242
2679
  container: {},
2243
2680
  amount: {
2244
2681
  fontFamily: "Poppins-Bold",
2245
- fontSize: ms(56)
2682
+ fontSize: ms(56),
2683
+ letterSpacing: -2
2246
2684
  }
2247
2685
  });
2248
2686
  var nativeDriver10 = Platform.OS !== "web";
@@ -2292,7 +2730,7 @@ function ListItem({
2292
2730
  onPress?.();
2293
2731
  };
2294
2732
  const effectiveLeft = leftIcon ? renderIcon(leftIcon, 24, leftIconColor ?? colors.foreground) : leftRender ?? icon;
2295
- const effectiveRight = rightIcon ? renderIcon(rightIcon, 24, rightIconColor ?? colors.mutedForeground) : rightRender ?? trailing;
2733
+ const effectiveRight = rightIcon ? renderIcon(rightIcon, 24, rightIconColor ?? colors.foregroundMuted) : rightRender ?? trailing;
2296
2734
  const cardStyle = variant === "card" ? {
2297
2735
  backgroundColor: colors.card,
2298
2736
  borderRadius: 12,
@@ -2327,7 +2765,7 @@ function ListItem({
2327
2765
  ), subtitle ? /* @__PURE__ */ React25.createElement(
2328
2766
  Text,
2329
2767
  {
2330
- style: [styles25.subtitle, { color: colors.mutedForeground }, subtitleStyle],
2768
+ style: [styles25.subtitle, { color: colors.foregroundMuted }, subtitleStyle],
2331
2769
  numberOfLines: 2,
2332
2770
  allowFontScaling: true
2333
2771
  },
@@ -2335,7 +2773,7 @@ function ListItem({
2335
2773
  ) : null, caption ? /* @__PURE__ */ React25.createElement(
2336
2774
  Text,
2337
2775
  {
2338
- style: [styles25.caption, { color: colors.mutedForeground }, captionStyle],
2776
+ style: [styles25.caption, { color: colors.foregroundMuted }, captionStyle],
2339
2777
  numberOfLines: 1,
2340
2778
  allowFontScaling: true
2341
2779
  },
@@ -2344,11 +2782,11 @@ function ListItem({
2344
2782
  effectiveRight !== void 0 ? /* @__PURE__ */ React25.createElement(View, { style: styles25.rightContainer }, typeof effectiveRight === "string" ? /* @__PURE__ */ React25.createElement(
2345
2783
  Text,
2346
2784
  {
2347
- style: [styles25.rightText, { color: colors.mutedForeground }],
2785
+ style: [styles25.rightText, { color: colors.foregroundMuted }],
2348
2786
  allowFontScaling: true
2349
2787
  },
2350
2788
  effectiveRight
2351
- ) : effectiveRight) : showChevron ? /* @__PURE__ */ React25.createElement(Entypo$1, { name: "chevron-with-circle-right", size: 20, color: colors.mutedForeground }) : null
2789
+ ) : effectiveRight) : showChevron ? /* @__PURE__ */ React25.createElement(Entypo$1, { name: "chevron-with-circle-right", size: 20, color: colors.foregroundMuted }) : null
2352
2790
  ), showSeparator ? /* @__PURE__ */ React25.createElement(
2353
2791
  View,
2354
2792
  {
@@ -2450,7 +2888,7 @@ function Chip({ label, selected = false, onPress, icon, iconName, style }) {
2450
2888
  };
2451
2889
  const backgroundColor = pressAnim.interpolate({
2452
2890
  inputRange: [0, 1],
2453
- outputRange: [colors.secondary, colors.primary]
2891
+ outputRange: [colors.surface, colors.primary]
2454
2892
  });
2455
2893
  const textColor = pressAnim.interpolate({
2456
2894
  inputRange: [0, 1],
@@ -2565,18 +3003,18 @@ function ConfirmDialog({
2565
3003
  BottomSheetModal,
2566
3004
  {
2567
3005
  ref,
2568
- snapPoints: ["35%"],
3006
+ enableDynamicSizing: true,
2569
3007
  onDismiss: onCancel,
2570
3008
  backdropComponent: renderBackdrop,
2571
3009
  backgroundStyle: [styles27.background, { backgroundColor: colors.card }],
2572
3010
  handleIndicatorStyle: [styles27.handle, { backgroundColor: colors.border }],
2573
3011
  enablePanDownToClose: true
2574
3012
  },
2575
- /* @__PURE__ */ React25.createElement(BottomSheetView, { style: styles27.content }, /* @__PURE__ */ React25.createElement(Text, { style: [styles27.title, { color: colors.cardForeground }], allowFontScaling: true }, title), description ? /* @__PURE__ */ React25.createElement(Text, { style: [styles27.description, { color: colors.mutedForeground }], allowFontScaling: true }, description) : null, /* @__PURE__ */ React25.createElement(View, { style: styles27.actions }, /* @__PURE__ */ React25.createElement(
3013
+ /* @__PURE__ */ React25.createElement(BottomSheetView, { style: styles27.content }, /* @__PURE__ */ React25.createElement(Text, { style: [styles27.title, { color: colors.foreground }], allowFontScaling: true }, title), description ? /* @__PURE__ */ React25.createElement(Text, { style: [styles27.description, { color: colors.foregroundMuted }], allowFontScaling: true }, description) : null, /* @__PURE__ */ React25.createElement(View, { style: styles27.actions }, /* @__PURE__ */ React25.createElement(
2576
3014
  Button,
2577
3015
  {
2578
3016
  label: cancelLabel,
2579
- variant: "outline",
3017
+ variant: "secondary",
2580
3018
  fullWidth: true,
2581
3019
  onPress: onCancel,
2582
3020
  icon: /* @__PURE__ */ React25.createElement(Feather$1, { name: "x", size: 15, color: colors.foreground })
@@ -2632,7 +3070,7 @@ var styles27 = StyleSheet.create({
2632
3070
  });
2633
3071
  function LabelValue({ label, value, style }) {
2634
3072
  const { colors } = useTheme();
2635
- return /* @__PURE__ */ React25.createElement(View, { style: [styles28.container, style] }, /* @__PURE__ */ React25.createElement(Text, { style: [styles28.label, { color: colors.mutedForeground }], allowFontScaling: true }, label), typeof value === "string" ? /* @__PURE__ */ React25.createElement(Text, { style: [styles28.value, { color: colors.foreground }], allowFontScaling: true }, value) : value);
3073
+ return /* @__PURE__ */ React25.createElement(View, { style: [styles28.container, style] }, /* @__PURE__ */ React25.createElement(Text, { style: [styles28.label, { color: colors.foregroundMuted }], allowFontScaling: true }, label), typeof value === "string" ? /* @__PURE__ */ React25.createElement(Text, { style: [styles28.value, { color: colors.foreground }], allowFontScaling: true }, value) : value);
2636
3074
  }
2637
3075
  var styles28 = StyleSheet.create({
2638
3076
  container: {
@@ -2725,63 +3163,342 @@ var styles29 = StyleSheet.create({
2725
3163
  minWidth: s(160)
2726
3164
  }
2727
3165
  });
3166
+ function useHover() {
3167
+ const [hovered, setHovered] = useState(false);
3168
+ const onMouseEnter = useCallback(() => setHovered(true), []);
3169
+ const onMouseLeave = useCallback(() => setHovered(false), []);
3170
+ if (Platform.OS !== "web") {
3171
+ return { hovered: false, hoverHandlers: {} };
3172
+ }
3173
+ return { hovered, hoverHandlers: { onMouseEnter, onMouseLeave } };
3174
+ }
2728
3175
 
2729
- // src/tokens.ts
2730
- var SPACING = {
2731
- xs: 4,
2732
- sm: 8,
2733
- md: 12,
2734
- lg: 16,
2735
- xl: 24,
2736
- "2xl": 32,
2737
- "3xl": 48
2738
- };
2739
- var ICON_SIZES = {
2740
- sm: 14,
2741
- md: 18,
2742
- lg: 22,
2743
- xl: 28,
2744
- "2xl": 32
2745
- };
2746
- var RADIUS = {
2747
- sm: 4,
2748
- md: 8,
2749
- lg: 12,
2750
- xl: 16,
2751
- full: 9999
3176
+ // src/components/MediaCard/MediaCard.tsx
3177
+ var nativeDriver12 = Platform.OS !== "web";
3178
+ var aspectRatioMap = {
3179
+ "1:1": 1,
3180
+ "4:3": 3 / 4,
3181
+ "16:9": 9 / 16,
3182
+ "4:5": 5 / 4,
3183
+ "3:2": 2 / 3
2752
3184
  };
2753
- var SHADOWS = {
2754
- sm: {
2755
- shadowColor: "#000",
2756
- shadowOffset: { width: 0, height: 1 },
2757
- shadowOpacity: 0.08,
2758
- shadowRadius: 4,
2759
- elevation: 2
3185
+ function MediaCard({
3186
+ imageSource,
3187
+ aspectRatio = "4:3",
3188
+ badge,
3189
+ actionIcon,
3190
+ actionIconName,
3191
+ actionActive = false,
3192
+ onActionPress,
3193
+ title,
3194
+ subtitle,
3195
+ caption,
3196
+ onPress,
3197
+ style,
3198
+ imageStyle,
3199
+ footer
3200
+ }) {
3201
+ const { colors } = useTheme();
3202
+ const scale2 = useRef(new Animated.Value(1)).current;
3203
+ const { hovered, hoverHandlers } = useHover();
3204
+ const handlePressIn = () => {
3205
+ if (!onPress) return;
3206
+ Animated.spring(scale2, { toValue: 0.98, useNativeDriver: nativeDriver12, speed: 40, bounciness: 0 }).start();
3207
+ };
3208
+ const handlePressOut = () => {
3209
+ if (!onPress) return;
3210
+ Animated.spring(scale2, { toValue: 1, useNativeDriver: nativeDriver12, speed: 40, bounciness: 4 }).start();
3211
+ };
3212
+ const handlePress = () => {
3213
+ if (!onPress) return;
3214
+ impactLight();
3215
+ onPress();
3216
+ };
3217
+ const ratio = aspectRatioMap[aspectRatio];
3218
+ const resolvedActionIcon = actionIconName ? renderIcon(actionIconName, 18, actionActive ? colors.primary : colors.background) : actionIcon ?? renderIcon("heart", 18, actionActive ? colors.primary : colors.background);
3219
+ const cardContent = /* @__PURE__ */ React25.createElement(
3220
+ View,
3221
+ {
3222
+ style: [
3223
+ styles30.card,
3224
+ hovered && styles30.cardHovered,
3225
+ style
3226
+ ],
3227
+ ...Platform.OS === "web" ? hoverHandlers : {}
3228
+ },
3229
+ /* @__PURE__ */ React25.createElement(View, { style: [styles30.imageContainer, imageStyle] }, /* @__PURE__ */ React25.createElement(View, { style: { paddingTop: `${ratio * 100}%` } }, /* @__PURE__ */ React25.createElement(View, { style: StyleSheet.absoluteFill }, imageSource ? /* @__PURE__ */ React25.createElement(
3230
+ Image,
3231
+ {
3232
+ source: imageSource,
3233
+ style: styles30.image,
3234
+ resizeMode: "cover"
3235
+ }
3236
+ ) : /* @__PURE__ */ React25.createElement(View, { style: [styles30.imagePlaceholder, { backgroundColor: colors.surface }] }))), badge && /* @__PURE__ */ React25.createElement(View, { style: styles30.badgeContainer }, badge), (onActionPress || actionIcon || actionIconName) && /* @__PURE__ */ React25.createElement(
3237
+ TouchableOpacity,
3238
+ {
3239
+ style: [styles30.actionButton, { backgroundColor: "rgba(0,0,0,0.24)" }],
3240
+ onPress: () => {
3241
+ impactLight();
3242
+ onActionPress?.();
3243
+ },
3244
+ activeOpacity: 0.8,
3245
+ touchSoundDisabled: true
3246
+ },
3247
+ resolvedActionIcon
3248
+ )),
3249
+ (title || subtitle || caption || footer) && /* @__PURE__ */ React25.createElement(View, { style: styles30.meta }, title ? /* @__PURE__ */ React25.createElement(Text, { style: [styles30.title, { color: colors.foreground }], numberOfLines: 2, allowFontScaling: true }, title) : null, subtitle ? /* @__PURE__ */ React25.createElement(Text, { style: [styles30.subtitle, { color: colors.foregroundSubtle }], numberOfLines: 1, allowFontScaling: true }, subtitle) : null, caption ? /* @__PURE__ */ React25.createElement(Text, { style: [styles30.caption, { color: colors.foregroundMuted }], numberOfLines: 1, allowFontScaling: true }, caption) : null, footer)
3250
+ );
3251
+ if (onPress) {
3252
+ return /* @__PURE__ */ React25.createElement(Animated.View, { style: { transform: [{ scale: scale2 }] } }, /* @__PURE__ */ React25.createElement(
3253
+ TouchableOpacity,
3254
+ {
3255
+ onPress: handlePress,
3256
+ onPressIn: handlePressIn,
3257
+ onPressOut: handlePressOut,
3258
+ activeOpacity: 1,
3259
+ touchSoundDisabled: true
3260
+ },
3261
+ cardContent
3262
+ ));
3263
+ }
3264
+ return cardContent;
3265
+ }
3266
+ var styles30 = StyleSheet.create({
3267
+ card: {
3268
+ borderRadius: RADIUS.md,
3269
+ // 14px — Airbnb property card spec
3270
+ overflow: "hidden",
3271
+ backgroundColor: "transparent"
2760
3272
  },
2761
- md: {
2762
- shadowColor: "#000",
2763
- shadowOffset: { width: 0, height: 3 },
2764
- shadowOpacity: 0.12,
2765
- shadowRadius: 8,
2766
- elevation: 5
3273
+ cardHovered: {
3274
+ // Web hover: lift shadow
3275
+ ...SHADOWS.md
2767
3276
  },
2768
- lg: {
2769
- shadowColor: "#000",
2770
- shadowOffset: { width: 0, height: 6 },
2771
- shadowOpacity: 0.2,
2772
- shadowRadius: 16,
2773
- elevation: 10
3277
+ imageContainer: {
3278
+ borderRadius: RADIUS.md,
3279
+ overflow: "hidden"
2774
3280
  },
2775
- xl: {
2776
- shadowColor: "#000",
2777
- shadowOffset: { width: 0, height: 12 },
2778
- shadowOpacity: 0.28,
2779
- shadowRadius: 24,
2780
- elevation: 18
3281
+ image: {
3282
+ width: "100%",
3283
+ height: "100%"
3284
+ },
3285
+ imagePlaceholder: {
3286
+ width: "100%",
3287
+ height: "100%"
3288
+ },
3289
+ badgeContainer: {
3290
+ position: "absolute",
3291
+ top: s(8),
3292
+ left: s(8)
3293
+ },
3294
+ actionButton: {
3295
+ position: "absolute",
3296
+ top: s(8),
3297
+ right: s(8),
3298
+ width: s(32),
3299
+ height: s(32),
3300
+ borderRadius: 9999,
3301
+ alignItems: "center",
3302
+ justifyContent: "center"
3303
+ },
3304
+ meta: {
3305
+ paddingTop: vs(8),
3306
+ gap: vs(2)
3307
+ },
3308
+ title: {
3309
+ fontFamily: "Poppins-SemiBold",
3310
+ fontSize: ms(14),
3311
+ lineHeight: mvs(20)
3312
+ },
3313
+ subtitle: {
3314
+ fontFamily: "Poppins-Regular",
3315
+ fontSize: ms(13),
3316
+ lineHeight: mvs(18)
3317
+ },
3318
+ caption: {
3319
+ fontFamily: "Poppins-Regular",
3320
+ fontSize: ms(12),
3321
+ lineHeight: mvs(16)
2781
3322
  }
2782
- };
2783
- var BREAKPOINTS = {
2784
- wide: 700
2785
- };
3323
+ });
3324
+ var nativeDriver13 = Platform.OS !== "web";
3325
+ function CategoryChip({
3326
+ item,
3327
+ selected,
3328
+ onPress
3329
+ }) {
3330
+ const { colors } = useTheme();
3331
+ const scale2 = useRef(new Animated.Value(1)).current;
3332
+ const handlePressIn = () => {
3333
+ Animated.spring(scale2, { toValue: 0.95, useNativeDriver: nativeDriver13, speed: 40, bounciness: 0 }).start();
3334
+ };
3335
+ const handlePressOut = () => {
3336
+ Animated.spring(scale2, { toValue: 1, useNativeDriver: nativeDriver13, speed: 40, bounciness: 4 }).start();
3337
+ };
3338
+ const bgColor = selected ? colors.primary : colors.surface;
3339
+ const textColor = selected ? colors.primaryForeground : colors.foregroundSubtle;
3340
+ const borderColor = selected ? colors.primary : colors.border;
3341
+ const resolvedIcon = typeof item.icon === "string" ? renderIcon(item.icon, 16, textColor) : item.icon ?? null;
3342
+ return /* @__PURE__ */ React25.createElement(Animated.View, { style: { transform: [{ scale: scale2 }] } }, /* @__PURE__ */ React25.createElement(
3343
+ TouchableOpacity,
3344
+ {
3345
+ style: [
3346
+ styles31.chip,
3347
+ {
3348
+ backgroundColor: bgColor,
3349
+ borderColor
3350
+ }
3351
+ ],
3352
+ onPress,
3353
+ onPressIn: handlePressIn,
3354
+ onPressOut: handlePressOut,
3355
+ activeOpacity: 1,
3356
+ touchSoundDisabled: true
3357
+ },
3358
+ resolvedIcon && /* @__PURE__ */ React25.createElement(View, { style: styles31.chipIcon }, resolvedIcon),
3359
+ /* @__PURE__ */ React25.createElement(Text, { style: [styles31.chipLabel, { color: textColor }], allowFontScaling: true }, item.label),
3360
+ item.badge !== void 0 && item.badge > 0 && /* @__PURE__ */ React25.createElement(View, { style: [styles31.chipBadge, { backgroundColor: colors.primary }] }, /* @__PURE__ */ React25.createElement(Text, { style: [styles31.chipBadgeText, { color: colors.primaryForeground }] }, Math.min(item.badge, 99)))
3361
+ ));
3362
+ }
3363
+ function CategoryStrip({
3364
+ categories,
3365
+ value,
3366
+ onValueChange,
3367
+ multiSelect = false,
3368
+ style,
3369
+ itemStyle
3370
+ }) {
3371
+ const selected = Array.isArray(value) ? value : value ? [value] : [];
3372
+ const handlePress = (v) => {
3373
+ selectionAsync();
3374
+ if (multiSelect) {
3375
+ const current = Array.isArray(value) ? value : value ? [value] : [];
3376
+ const next = current.includes(v) ? current.filter((x) => x !== v) : [...current, v];
3377
+ onValueChange?.(next);
3378
+ } else {
3379
+ onValueChange?.(v === value ? "" : v);
3380
+ }
3381
+ };
3382
+ return /* @__PURE__ */ React25.createElement(
3383
+ ScrollView,
3384
+ {
3385
+ horizontal: true,
3386
+ showsHorizontalScrollIndicator: false,
3387
+ contentContainerStyle: [styles31.container, style],
3388
+ style: styles31.scroll
3389
+ },
3390
+ categories.map((cat) => /* @__PURE__ */ React25.createElement(View, { key: cat.value, style: itemStyle }, /* @__PURE__ */ React25.createElement(
3391
+ CategoryChip,
3392
+ {
3393
+ item: cat,
3394
+ selected: selected.includes(cat.value),
3395
+ onPress: () => handlePress(cat.value)
3396
+ }
3397
+ )))
3398
+ );
3399
+ }
3400
+ var styles31 = StyleSheet.create({
3401
+ scroll: {
3402
+ flexGrow: 0
3403
+ },
3404
+ container: {
3405
+ flexDirection: "row",
3406
+ gap: s(8),
3407
+ paddingHorizontal: s(4),
3408
+ paddingVertical: vs(4)
3409
+ },
3410
+ chip: {
3411
+ flexDirection: "row",
3412
+ alignItems: "center",
3413
+ borderRadius: RADIUS.full,
3414
+ borderWidth: 1,
3415
+ paddingHorizontal: s(14),
3416
+ paddingVertical: vs(8),
3417
+ gap: s(6)
3418
+ },
3419
+ chipIcon: {
3420
+ alignItems: "center",
3421
+ justifyContent: "center"
3422
+ },
3423
+ chipLabel: {
3424
+ fontFamily: "Poppins-Medium",
3425
+ fontSize: ms(13)
3426
+ },
3427
+ chipBadge: {
3428
+ minWidth: 16,
3429
+ height: 16,
3430
+ borderRadius: 9999,
3431
+ paddingHorizontal: 3,
3432
+ alignItems: "center",
3433
+ justifyContent: "center"
3434
+ },
3435
+ chipBadgeText: {
3436
+ fontFamily: "Poppins-Bold",
3437
+ fontSize: ms(9),
3438
+ lineHeight: 14
3439
+ }
3440
+ });
3441
+ var nativeDriver14 = Platform.OS !== "web";
3442
+ function Pressable2({
3443
+ children,
3444
+ onPress,
3445
+ pressScale = 0.98,
3446
+ bounciness = 4,
3447
+ haptics = true,
3448
+ style,
3449
+ disabled,
3450
+ hoverScale = 1.02,
3451
+ ...touchableProps
3452
+ }) {
3453
+ const scale2 = useRef(new Animated.Value(1)).current;
3454
+ const { hovered, hoverHandlers } = useHover();
3455
+ const handlePressIn = () => {
3456
+ if (disabled) return;
3457
+ Animated.spring(scale2, {
3458
+ toValue: pressScale,
3459
+ useNativeDriver: nativeDriver14,
3460
+ speed: 40,
3461
+ bounciness: 0
3462
+ }).start();
3463
+ };
3464
+ const handlePressOut = () => {
3465
+ if (disabled) return;
3466
+ Animated.spring(scale2, {
3467
+ toValue: 1,
3468
+ useNativeDriver: nativeDriver14,
3469
+ speed: 40,
3470
+ bounciness
3471
+ }).start();
3472
+ };
3473
+ const handlePress = () => {
3474
+ if (disabled || !onPress) return;
3475
+ if (haptics) impactLight();
3476
+ onPress();
3477
+ };
3478
+ const hoverScaleValue = hovered && hoverScale !== 1 ? hoverScale : 1;
3479
+ return /* @__PURE__ */ React25.createElement(
3480
+ Animated.View,
3481
+ {
3482
+ style: [
3483
+ { transform: [{ scale: Animated.multiply(scale2, hoverScaleValue) }] },
3484
+ style
3485
+ ],
3486
+ ...Platform.OS === "web" ? hoverHandlers : {}
3487
+ },
3488
+ /* @__PURE__ */ React25.createElement(
3489
+ TouchableOpacity,
3490
+ {
3491
+ onPress: handlePress,
3492
+ onPressIn: handlePressIn,
3493
+ onPressOut: handlePressOut,
3494
+ activeOpacity: 1,
3495
+ disabled,
3496
+ touchSoundDisabled: true,
3497
+ ...touchableProps
3498
+ },
3499
+ children
3500
+ )
3501
+ );
3502
+ }
2786
3503
 
2787
- export { Accordion, AlertBanner, Avatar, BREAKPOINTS, Badge, Button, Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle, Checkbox, Chip, ChipGroup, ConfirmDialog, CurrencyDisplay, CurrencyInput, CurrencyInput as CurrencyInputLarge, EmptyState, ICON_SIZES, Icon, IconButton, Input, LabelValue, ListItem, MonthPicker, Progress, RADIUS, RadioGroup, SHADOWS, SPACING, Select, Separator, Sheet, Skeleton, Slider, Spinner, Switch, Tabs, TabsContent, Text2 as Text, Textarea, ThemeProvider, ToastProvider, Toggle, defaultDark, defaultLight, renderIcon, useTheme, useToast };
3504
+ export { Accordion, AlertBanner, Avatar, BREAKPOINTS, Badge, Button, Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle, CategoryStrip, Checkbox, Chip, ChipGroup, ConfirmDialog, CurrencyDisplay, CurrencyInput, CurrencyInput as CurrencyInputLarge, EmptyState, ICON_SIZES, Icon, IconButton, Input, LabelValue, ListItem, MediaCard, MonthPicker, Pressable2 as Pressable, Progress, RADIUS, RadioGroup, SHADOWS, SPACING, Select, Separator, Sheet, Skeleton, Slider, Spinner, Switch, TYPOGRAPHY, Tabs, TabsContent, Text3 as Text, Textarea, ThemeProvider, ToastProvider, Toggle, defaultDark, defaultLight, deriveColors, renderIcon, useTheme, useToast };