@retray-dev/ui-kit 1.7.0 → 1.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.mjs CHANGED
@@ -1,5 +1,5 @@
1
1
  import React23, { createContext, useMemo, useContext, useRef, useState, useEffect, useCallback } from 'react';
2
- import { StyleSheet, useColorScheme, Animated, TouchableOpacity, ActivityIndicator, Text, View, TextInput, Image, Easing, PanResponder } from 'react-native';
2
+ import { Platform, StyleSheet, useColorScheme, Animated, TouchableOpacity, ActivityIndicator, Text, View, TextInput, Image, Easing, PanResponder, Modal } from 'react-native';
3
3
  import * as Haptics11 from 'expo-haptics';
4
4
  import { LinearGradient } from 'expo-linear-gradient';
5
5
  import ReanimatedAnimated, { useSharedValue, useAnimatedStyle, withTiming, Easing as Easing$1, withSpring } from 'react-native-reanimated';
@@ -73,6 +73,7 @@ function ThemeProvider({ children, theme, colorScheme = "system" }) {
73
73
  function useTheme() {
74
74
  return useContext(ThemeContext);
75
75
  }
76
+ var nativeDriver = Platform.OS !== "web";
76
77
  var containerSizeStyles = {
77
78
  sm: { paddingHorizontal: 20, paddingVertical: 12 },
78
79
  md: { paddingHorizontal: 24, paddingVertical: 16 },
@@ -103,13 +104,13 @@ function Button({
103
104
  if (isDisabled) return;
104
105
  Animated.spring(scale, {
105
106
  toValue: 0.95,
106
- useNativeDriver: true,
107
+ useNativeDriver: nativeDriver,
107
108
  speed: 40,
108
109
  bounciness: 0
109
110
  }).start();
110
111
  };
111
112
  const handlePressOut = () => {
112
- Animated.spring(scale, { toValue: 1, useNativeDriver: true, speed: 40, bounciness: 4 }).start();
113
+ Animated.spring(scale, { toValue: 1, useNativeDriver: nativeDriver, speed: 40, bounciness: 4 }).start();
113
114
  };
114
115
  const handlePress = (e) => {
115
116
  Haptics11.impactAsync(Haptics11.ImpactFeedbackStyle.Light);
@@ -119,15 +120,17 @@ function Button({
119
120
  primary: { backgroundColor: colors.primary },
120
121
  secondary: { backgroundColor: colors.secondary },
121
122
  outline: { backgroundColor: "transparent", borderWidth: 1.5, borderColor: colors.border },
122
- ghost: { backgroundColor: "transparent" }
123
+ ghost: { backgroundColor: "transparent" },
124
+ destructive: { backgroundColor: colors.destructive }
123
125
  }[variant];
124
126
  const labelVariantStyle = {
125
127
  primary: { color: colors.primaryForeground },
126
128
  secondary: { color: colors.secondaryForeground },
127
129
  outline: { color: colors.foreground },
128
- ghost: { color: colors.foreground }
130
+ ghost: { color: colors.foreground },
131
+ destructive: { color: colors.destructiveForeground }
129
132
  }[variant];
130
- const spinnerColor = variant === "primary" || variant === "secondary" ? colors.primaryForeground : colors.foreground;
133
+ const spinnerColor = variant === "destructive" ? colors.destructiveForeground : variant === "primary" || variant === "secondary" ? colors.primaryForeground : colors.foreground;
131
134
  return /* @__PURE__ */ React23.createElement(Animated.View, { style: [fullWidth && styles.fullWidth, { transform: [{ scale }] }] }, /* @__PURE__ */ React23.createElement(
132
135
  TouchableOpacity,
133
136
  {
@@ -455,12 +458,13 @@ var styles7 = StyleSheet.create({
455
458
  fontWeight: "500"
456
459
  }
457
460
  });
458
- function Alert({ title, description, variant = "default", icon, style }) {
461
+ function AlertBanner({ title, description, variant = "default", icon, style }) {
459
462
  const { colors } = useTheme();
460
- const borderColor = variant === "destructive" ? colors.destructive : colors.border;
461
- const titleColor = variant === "destructive" ? colors.destructive : colors.foreground;
462
- const descColor = variant === "destructive" ? colors.destructive : colors.mutedForeground;
463
- return /* @__PURE__ */ React23.createElement(View, { style: [styles8.container, { backgroundColor: colors.card, borderColor }, style] }, icon ? /* @__PURE__ */ React23.createElement(View, { style: styles8.icon }, icon) : /* @__PURE__ */ React23.createElement(View, { style: styles8.icon }, /* @__PURE__ */ React23.createElement(Text, { style: [styles8.defaultIcon, { color: titleColor }] }, variant === "destructive" ? "\u26A0" : "\u2139")), /* @__PURE__ */ React23.createElement(View, { style: styles8.content }, title ? /* @__PURE__ */ React23.createElement(Text, { style: [styles8.title, { color: titleColor }] }, title) : null, description ? /* @__PURE__ */ React23.createElement(Text, { style: [styles8.description, { color: descColor }] }, description) : null));
463
+ const borderColor = variant === "destructive" ? colors.destructive : variant === "success" ? colors.success : colors.border;
464
+ const titleColor = variant === "destructive" ? colors.destructive : variant === "success" ? colors.success : colors.foreground;
465
+ const descColor = variant === "destructive" ? colors.destructive : variant === "success" ? colors.success : colors.mutedForeground;
466
+ const defaultIcon = variant === "destructive" ? "\u26A0" : variant === "success" ? "\u2713" : "\u2139";
467
+ return /* @__PURE__ */ React23.createElement(View, { style: [styles8.container, { backgroundColor: colors.card, borderColor }, style] }, icon ? /* @__PURE__ */ React23.createElement(View, { style: styles8.icon }, icon) : /* @__PURE__ */ React23.createElement(View, { style: styles8.icon }, /* @__PURE__ */ React23.createElement(Text, { style: [styles8.defaultIcon, { color: titleColor }] }, defaultIcon)), /* @__PURE__ */ React23.createElement(View, { style: styles8.content }, title ? /* @__PURE__ */ React23.createElement(Text, { style: [styles8.title, { color: titleColor }] }, title) : null, description ? /* @__PURE__ */ React23.createElement(Text, { style: [styles8.description, { color: descColor }] }, description) : null));
464
468
  }
465
469
  var styles8 = StyleSheet.create({
466
470
  container: {
@@ -531,9 +535,39 @@ var styles9 = StyleSheet.create({
531
535
  borderRadius: 999
532
536
  }
533
537
  });
534
- function EmptyState({ icon, title, description, action, style }) {
538
+ function EmptyState({ icon, title, description, action, size = "default", style }) {
535
539
  const { colors } = useTheme();
536
- return /* @__PURE__ */ React23.createElement(View, { style: [styles10.container, { borderColor: colors.border }, style] }, icon ? /* @__PURE__ */ React23.createElement(View, { style: [styles10.iconWrapper, { backgroundColor: colors.muted }] }, icon) : null, /* @__PURE__ */ React23.createElement(View, { style: styles10.textWrapper }, /* @__PURE__ */ React23.createElement(Text, { style: [styles10.title, { color: colors.foreground }] }, title), description ? /* @__PURE__ */ React23.createElement(Text, { style: [styles10.description, { color: colors.mutedForeground }] }, description) : null), action ? /* @__PURE__ */ React23.createElement(View, { style: styles10.action }, action) : null);
540
+ const isCompact = size === "compact";
541
+ return /* @__PURE__ */ React23.createElement(
542
+ View,
543
+ {
544
+ style: [
545
+ styles10.container,
546
+ isCompact && styles10.containerCompact,
547
+ { borderColor: colors.border },
548
+ style
549
+ ]
550
+ },
551
+ icon ? /* @__PURE__ */ React23.createElement(
552
+ View,
553
+ {
554
+ style: [
555
+ styles10.iconWrapper,
556
+ isCompact && styles10.iconWrapperCompact,
557
+ { backgroundColor: colors.muted }
558
+ ]
559
+ },
560
+ icon
561
+ ) : null,
562
+ /* @__PURE__ */ React23.createElement(View, { style: styles10.textWrapper }, /* @__PURE__ */ React23.createElement(
563
+ Text,
564
+ {
565
+ style: [styles10.title, isCompact && styles10.titleCompact, { color: colors.foreground }]
566
+ },
567
+ title
568
+ ), description && !isCompact ? /* @__PURE__ */ React23.createElement(Text, { style: [styles10.description, { color: colors.mutedForeground }] }, description) : null),
569
+ action && !isCompact ? /* @__PURE__ */ React23.createElement(View, { style: styles10.action }, action) : null
570
+ );
537
571
  }
538
572
  var styles10 = StyleSheet.create({
539
573
  container: {
@@ -545,6 +579,10 @@ var styles10 = StyleSheet.create({
545
579
  padding: 32,
546
580
  gap: 16
547
581
  },
582
+ containerCompact: {
583
+ padding: 20,
584
+ gap: 10
585
+ },
548
586
  iconWrapper: {
549
587
  width: 48,
550
588
  height: 48,
@@ -552,6 +590,11 @@ var styles10 = StyleSheet.create({
552
590
  alignItems: "center",
553
591
  justifyContent: "center"
554
592
  },
593
+ iconWrapperCompact: {
594
+ width: 36,
595
+ height: 36,
596
+ borderRadius: 8
597
+ },
555
598
  textWrapper: {
556
599
  alignItems: "center",
557
600
  gap: 8,
@@ -562,6 +605,9 @@ var styles10 = StyleSheet.create({
562
605
  fontWeight: "500",
563
606
  textAlign: "center"
564
607
  },
608
+ titleCompact: {
609
+ fontSize: 15
610
+ },
565
611
  description: {
566
612
  fontSize: 14,
567
613
  lineHeight: 20,
@@ -713,6 +759,7 @@ var styles12 = StyleSheet.create({
713
759
  lineHeight: 22
714
760
  }
715
761
  });
762
+ var nativeDriver2 = Platform.OS !== "web";
716
763
  var TRACK_WIDTH = 60;
717
764
  var TRACK_HEIGHT = 36;
718
765
  var THUMB_SIZE = 28;
@@ -726,7 +773,7 @@ function Switch({ checked = false, onCheckedChange, disabled, style }) {
726
773
  Animated.parallel([
727
774
  Animated.spring(translateX, {
728
775
  toValue: checked ? THUMB_TRAVEL : 0,
729
- useNativeDriver: true,
776
+ useNativeDriver: nativeDriver2,
730
777
  bounciness: 4
731
778
  }),
732
779
  Animated.timing(trackOpacity, {
@@ -1828,10 +1875,10 @@ function formatValue(value, prefix, showDecimals) {
1828
1875
  }
1829
1876
  return `${sign}${prefix}${intPart}`;
1830
1877
  }
1831
- function CurrencyDisplay({ value, prefix = "$", showDecimals = false, style }) {
1878
+ function CurrencyDisplay({ value, prefix = "$", showDecimals = false, textColor, style }) {
1832
1879
  const { colors } = useTheme();
1833
1880
  const formatted = formatValue(value, prefix, showDecimals);
1834
- return /* @__PURE__ */ React23.createElement(View, { style: [styles22.container, style] }, /* @__PURE__ */ React23.createElement(Text, { style: [styles22.amount, { color: colors.foreground }], allowFontScaling: true }, formatted));
1881
+ return /* @__PURE__ */ React23.createElement(View, { style: [styles22.container, style] }, /* @__PURE__ */ React23.createElement(Text, { style: [styles22.amount, { color: textColor ?? colors.foreground }], allowFontScaling: true }, formatted));
1835
1882
  }
1836
1883
  var styles22 = StyleSheet.create({
1837
1884
  container: {},
@@ -1883,5 +1930,321 @@ function CurrencyInputLarge({
1883
1930
  }
1884
1931
  );
1885
1932
  }
1933
+ var nativeDriver3 = Platform.OS !== "web";
1934
+ function ListItem({ icon, title, subtitle, trailing, onPress, disabled, style }) {
1935
+ const { colors } = useTheme();
1936
+ const scale = useRef(new Animated.Value(1)).current;
1937
+ const handlePressIn = () => {
1938
+ if (!onPress || disabled) return;
1939
+ Animated.spring(scale, {
1940
+ toValue: 0.97,
1941
+ useNativeDriver: nativeDriver3,
1942
+ speed: 40,
1943
+ bounciness: 0
1944
+ }).start();
1945
+ };
1946
+ const handlePressOut = () => {
1947
+ Animated.spring(scale, {
1948
+ toValue: 1,
1949
+ useNativeDriver: nativeDriver3,
1950
+ speed: 40,
1951
+ bounciness: 4
1952
+ }).start();
1953
+ };
1954
+ const handlePress = () => {
1955
+ Haptics11.selectionAsync();
1956
+ onPress?.();
1957
+ };
1958
+ return /* @__PURE__ */ React23.createElement(Animated.View, { style: [{ transform: [{ scale }] }, disabled && styles23.disabled] }, /* @__PURE__ */ React23.createElement(
1959
+ TouchableOpacity,
1960
+ {
1961
+ style: [styles23.container, style],
1962
+ onPress: onPress ? handlePress : void 0,
1963
+ onPressIn: handlePressIn,
1964
+ onPressOut: handlePressOut,
1965
+ disabled,
1966
+ activeOpacity: 1,
1967
+ touchSoundDisabled: true
1968
+ },
1969
+ icon ? /* @__PURE__ */ React23.createElement(View, { style: styles23.iconWrapper }, icon) : null,
1970
+ /* @__PURE__ */ React23.createElement(View, { style: styles23.content }, /* @__PURE__ */ React23.createElement(Text, { style: [styles23.title, { color: colors.foreground }], allowFontScaling: true }, title), subtitle ? /* @__PURE__ */ React23.createElement(Text, { style: [styles23.subtitle, { color: colors.mutedForeground }], allowFontScaling: true }, subtitle) : null),
1971
+ trailing !== void 0 ? typeof trailing === "string" ? /* @__PURE__ */ React23.createElement(Text, { style: [styles23.trailing, { color: colors.mutedForeground }], allowFontScaling: true }, trailing) : trailing : null
1972
+ ));
1973
+ }
1974
+ var styles23 = StyleSheet.create({
1975
+ container: {
1976
+ flexDirection: "row",
1977
+ alignItems: "center",
1978
+ paddingHorizontal: 16,
1979
+ paddingVertical: 14,
1980
+ gap: 12
1981
+ },
1982
+ iconWrapper: {
1983
+ alignItems: "center",
1984
+ justifyContent: "center"
1985
+ },
1986
+ content: {
1987
+ flex: 1,
1988
+ gap: 3
1989
+ },
1990
+ title: {
1991
+ fontSize: 16,
1992
+ fontWeight: "500",
1993
+ lineHeight: 22
1994
+ },
1995
+ subtitle: {
1996
+ fontSize: 13,
1997
+ lineHeight: 18
1998
+ },
1999
+ trailing: {
2000
+ fontSize: 15
2001
+ },
2002
+ disabled: {
2003
+ opacity: 0.45
2004
+ }
2005
+ });
2006
+ var nativeDriver4 = Platform.OS !== "web";
2007
+ function Chip({ label, selected = false, onPress, style }) {
2008
+ const { colors } = useTheme();
2009
+ const scale = useRef(new Animated.Value(1)).current;
2010
+ const pressAnim = useRef(new Animated.Value(selected ? 1 : 0)).current;
2011
+ useEffect(() => {
2012
+ Animated.timing(pressAnim, {
2013
+ toValue: selected ? 1 : 0,
2014
+ duration: 150,
2015
+ easing: Easing.out(Easing.ease),
2016
+ useNativeDriver: false
2017
+ }).start();
2018
+ }, [selected, pressAnim]);
2019
+ const handlePressIn = () => {
2020
+ Animated.spring(scale, {
2021
+ toValue: 0.95,
2022
+ useNativeDriver: nativeDriver4,
2023
+ speed: 40,
2024
+ bounciness: 0
2025
+ }).start();
2026
+ };
2027
+ const handlePressOut = () => {
2028
+ Animated.spring(scale, {
2029
+ toValue: 1,
2030
+ useNativeDriver: nativeDriver4,
2031
+ speed: 40,
2032
+ bounciness: 4
2033
+ }).start();
2034
+ };
2035
+ const handlePress = () => {
2036
+ Haptics11.selectionAsync();
2037
+ onPress?.();
2038
+ };
2039
+ const backgroundColor = pressAnim.interpolate({
2040
+ inputRange: [0, 1],
2041
+ outputRange: [colors.secondary, colors.primary]
2042
+ });
2043
+ const textColor = pressAnim.interpolate({
2044
+ inputRange: [0, 1],
2045
+ outputRange: [colors.foreground, colors.primaryForeground]
2046
+ });
2047
+ const borderColor = pressAnim.interpolate({
2048
+ inputRange: [0, 1],
2049
+ outputRange: [colors.border, colors.primary]
2050
+ });
2051
+ return /* @__PURE__ */ React23.createElement(Animated.View, { style: [styles24.wrapper, { transform: [{ scale }] }, style] }, /* @__PURE__ */ React23.createElement(
2052
+ TouchableOpacity,
2053
+ {
2054
+ onPress: handlePress,
2055
+ onPressIn: handlePressIn,
2056
+ onPressOut: handlePressOut,
2057
+ activeOpacity: 1,
2058
+ touchSoundDisabled: true
2059
+ },
2060
+ /* @__PURE__ */ React23.createElement(Animated.View, { style: [styles24.chip, { backgroundColor, borderColor }] }, /* @__PURE__ */ React23.createElement(Animated.Text, { style: [styles24.label, { color: textColor }], allowFontScaling: true }, label))
2061
+ ));
2062
+ }
2063
+ function ChipGroup({ options, value, onValueChange, style }) {
2064
+ return /* @__PURE__ */ React23.createElement(View, { style: [styles24.group, style] }, options.map((opt) => /* @__PURE__ */ React23.createElement(
2065
+ Chip,
2066
+ {
2067
+ key: opt.value,
2068
+ label: opt.label,
2069
+ selected: opt.value === value,
2070
+ onPress: () => onValueChange?.(opt.value)
2071
+ }
2072
+ )));
2073
+ }
2074
+ var styles24 = StyleSheet.create({
2075
+ wrapper: {},
2076
+ chip: {
2077
+ borderRadius: 999,
2078
+ paddingHorizontal: 14,
2079
+ paddingVertical: 8,
2080
+ borderWidth: 1.5,
2081
+ alignItems: "center",
2082
+ justifyContent: "center"
2083
+ },
2084
+ label: {
2085
+ fontSize: 14,
2086
+ fontWeight: "500",
2087
+ lineHeight: 20
2088
+ },
2089
+ group: {
2090
+ flexDirection: "row",
2091
+ flexWrap: "wrap",
2092
+ gap: 8
2093
+ }
2094
+ });
2095
+ function ConfirmDialog({
2096
+ visible,
2097
+ title,
2098
+ description,
2099
+ confirmLabel = "Confirm",
2100
+ cancelLabel = "Cancel",
2101
+ confirmVariant = "primary",
2102
+ onConfirm,
2103
+ onCancel
2104
+ }) {
2105
+ const { colors } = useTheme();
2106
+ return /* @__PURE__ */ React23.createElement(Modal, { visible, transparent: true, animationType: "fade", onRequestClose: onCancel }, /* @__PURE__ */ React23.createElement(TouchableOpacity, { style: styles25.overlay, activeOpacity: 1, onPress: onCancel }, /* @__PURE__ */ React23.createElement(
2107
+ View,
2108
+ {
2109
+ style: [styles25.dialog, { backgroundColor: colors.card }],
2110
+ onStartShouldSetResponder: () => true
2111
+ },
2112
+ /* @__PURE__ */ React23.createElement(Text, { style: [styles25.title, { color: colors.cardForeground }], allowFontScaling: true }, title),
2113
+ description ? /* @__PURE__ */ React23.createElement(Text, { style: [styles25.description, { color: colors.mutedForeground }], allowFontScaling: true }, description) : null,
2114
+ /* @__PURE__ */ React23.createElement(View, { style: styles25.actions }, /* @__PURE__ */ React23.createElement(Button, { label: cancelLabel, variant: "outline", fullWidth: true, onPress: onCancel }), /* @__PURE__ */ React23.createElement(Button, { label: confirmLabel, variant: confirmVariant, fullWidth: true, onPress: onConfirm }))
2115
+ )));
2116
+ }
2117
+ var styles25 = StyleSheet.create({
2118
+ overlay: {
2119
+ flex: 1,
2120
+ backgroundColor: "rgba(0,0,0,0.5)",
2121
+ justifyContent: "center",
2122
+ alignItems: "center",
2123
+ padding: 24
2124
+ },
2125
+ dialog: {
2126
+ width: "100%",
2127
+ maxWidth: 400,
2128
+ borderRadius: 16,
2129
+ padding: 24,
2130
+ gap: 12,
2131
+ shadowColor: "#000",
2132
+ shadowOffset: { width: 0, height: 8 },
2133
+ shadowOpacity: 0.15,
2134
+ shadowRadius: 16,
2135
+ elevation: 8
2136
+ },
2137
+ title: {
2138
+ fontSize: 18,
2139
+ fontWeight: "600",
2140
+ lineHeight: 26
2141
+ },
2142
+ description: {
2143
+ fontSize: 15,
2144
+ lineHeight: 22
2145
+ },
2146
+ actions: {
2147
+ gap: 10,
2148
+ marginTop: 8
2149
+ }
2150
+ });
2151
+ function LabelValue({ label, value, style }) {
2152
+ const { colors } = useTheme();
2153
+ return /* @__PURE__ */ React23.createElement(View, { style: [styles26.container, style] }, /* @__PURE__ */ React23.createElement(Text, { style: [styles26.label, { color: colors.mutedForeground }], allowFontScaling: true }, label), typeof value === "string" ? /* @__PURE__ */ React23.createElement(Text, { style: [styles26.value, { color: colors.foreground }], allowFontScaling: true }, value) : value);
2154
+ }
2155
+ var styles26 = StyleSheet.create({
2156
+ container: {
2157
+ flexDirection: "row",
2158
+ justifyContent: "space-between",
2159
+ alignItems: "center",
2160
+ gap: 12
2161
+ },
2162
+ label: {
2163
+ fontSize: 13,
2164
+ lineHeight: 18
2165
+ },
2166
+ value: {
2167
+ fontSize: 15,
2168
+ fontWeight: "500",
2169
+ lineHeight: 22,
2170
+ textAlign: "right"
2171
+ }
2172
+ });
2173
+ var MONTH_NAMES = [
2174
+ "January",
2175
+ "February",
2176
+ "March",
2177
+ "April",
2178
+ "May",
2179
+ "June",
2180
+ "July",
2181
+ "August",
2182
+ "September",
2183
+ "October",
2184
+ "November",
2185
+ "December"
2186
+ ];
2187
+ function MonthPicker({ value, onChange, style }) {
2188
+ const { colors } = useTheme();
2189
+ const handlePrev = () => {
2190
+ Haptics11.selectionAsync();
2191
+ if (value.month === 1) {
2192
+ onChange({ month: 12, year: value.year - 1 });
2193
+ } else {
2194
+ onChange({ month: value.month - 1, year: value.year });
2195
+ }
2196
+ };
2197
+ const handleNext = () => {
2198
+ Haptics11.selectionAsync();
2199
+ if (value.month === 12) {
2200
+ onChange({ month: 1, year: value.year + 1 });
2201
+ } else {
2202
+ onChange({ month: value.month + 1, year: value.year });
2203
+ }
2204
+ };
2205
+ return /* @__PURE__ */ React23.createElement(View, { style: [styles27.container, style] }, /* @__PURE__ */ React23.createElement(
2206
+ TouchableOpacity,
2207
+ {
2208
+ style: styles27.arrow,
2209
+ onPress: handlePrev,
2210
+ activeOpacity: 0.6,
2211
+ touchSoundDisabled: true
2212
+ },
2213
+ /* @__PURE__ */ React23.createElement(Text, { style: [styles27.arrowText, { color: colors.foreground }] }, "\u2039")
2214
+ ), /* @__PURE__ */ React23.createElement(Text, { style: [styles27.label, { color: colors.foreground }], allowFontScaling: true }, MONTH_NAMES[value.month - 1], " ", value.year), /* @__PURE__ */ React23.createElement(
2215
+ TouchableOpacity,
2216
+ {
2217
+ style: styles27.arrow,
2218
+ onPress: handleNext,
2219
+ activeOpacity: 0.6,
2220
+ touchSoundDisabled: true
2221
+ },
2222
+ /* @__PURE__ */ React23.createElement(Text, { style: [styles27.arrowText, { color: colors.foreground }] }, "\u203A")
2223
+ ));
2224
+ }
2225
+ var styles27 = StyleSheet.create({
2226
+ container: {
2227
+ flexDirection: "row",
2228
+ alignItems: "center",
2229
+ justifyContent: "space-between"
2230
+ },
2231
+ arrow: {
2232
+ width: 44,
2233
+ height: 44,
2234
+ alignItems: "center",
2235
+ justifyContent: "center"
2236
+ },
2237
+ arrowText: {
2238
+ fontSize: 24,
2239
+ lineHeight: 30
2240
+ },
2241
+ label: {
2242
+ fontSize: 17,
2243
+ fontWeight: "500",
2244
+ lineHeight: 24,
2245
+ textAlign: "center",
2246
+ minWidth: 160
2247
+ }
2248
+ });
1886
2249
 
1887
- export { Accordion, Alert, Avatar, Badge, Button, Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle, Checkbox, CurrencyDisplay, CurrencyInput, CurrencyInputLarge, EmptyState, Input, Progress, RadioGroup, Select, Separator, Sheet, Skeleton, Slider, Spinner, Switch, Tabs, TabsContent, Text2 as Text, Textarea, ThemeProvider, ToastProvider, Toggle, defaultDark, defaultLight, useTheme, useToast };
2250
+ export { Accordion, AlertBanner, Avatar, Badge, Button, Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle, Checkbox, Chip, ChipGroup, ConfirmDialog, CurrencyDisplay, CurrencyInput, CurrencyInputLarge, EmptyState, Input, LabelValue, ListItem, MonthPicker, Progress, RadioGroup, Select, Separator, Sheet, Skeleton, Slider, Spinner, Switch, Tabs, TabsContent, Text2 as Text, Textarea, ThemeProvider, ToastProvider, Toggle, defaultDark, defaultLight, useTheme, useToast };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@retray-dev/ui-kit",
3
- "version": "1.7.0",
3
+ "version": "1.8.0",
4
4
  "description": "Personal UI Kit for React Native / Expo",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/index.mjs",
@@ -2,22 +2,36 @@ import React from 'react'
2
2
  import { View, Text, StyleSheet, ViewStyle } from 'react-native'
3
3
  import { useTheme } from '../../theme'
4
4
 
5
- export type AlertVariant = 'default' | 'destructive'
5
+ export type AlertBannerVariant = 'default' | 'destructive' | 'success'
6
6
 
7
- export interface AlertProps {
7
+ export interface AlertBannerProps {
8
8
  title?: string
9
9
  description?: string
10
- variant?: AlertVariant
10
+ variant?: AlertBannerVariant
11
11
  icon?: React.ReactNode
12
12
  style?: ViewStyle
13
13
  }
14
14
 
15
- export function Alert({ title, description, variant = 'default', icon, style }: AlertProps) {
15
+ export function AlertBanner({ title, description, variant = 'default', icon, style }: AlertBannerProps) {
16
16
  const { colors } = useTheme()
17
17
 
18
- const borderColor = variant === 'destructive' ? colors.destructive : colors.border
19
- const titleColor = variant === 'destructive' ? colors.destructive : colors.foreground
20
- const descColor = variant === 'destructive' ? colors.destructive : colors.mutedForeground
18
+ const borderColor =
19
+ variant === 'destructive' ? colors.destructive
20
+ : variant === 'success' ? colors.success
21
+ : colors.border
22
+
23
+ const titleColor =
24
+ variant === 'destructive' ? colors.destructive
25
+ : variant === 'success' ? colors.success
26
+ : colors.foreground
27
+
28
+ const descColor =
29
+ variant === 'destructive' ? colors.destructive
30
+ : variant === 'success' ? colors.success
31
+ : colors.mutedForeground
32
+
33
+ const defaultIcon =
34
+ variant === 'destructive' ? '⚠' : variant === 'success' ? '✓' : 'ℹ'
21
35
 
22
36
  return (
23
37
  <View style={[styles.container, { backgroundColor: colors.card, borderColor }, style]}>
@@ -25,9 +39,7 @@ export function Alert({ title, description, variant = 'default', icon, style }:
25
39
  <View style={styles.icon}>{icon}</View>
26
40
  ) : (
27
41
  <View style={styles.icon}>
28
- <Text style={[styles.defaultIcon, { color: titleColor }]}>
29
- {variant === 'destructive' ? '⚠' : 'ℹ'}
30
- </Text>
42
+ <Text style={[styles.defaultIcon, { color: titleColor }]}>{defaultIcon}</Text>
31
43
  </View>
32
44
  )}
33
45
  <View style={styles.content}>
@@ -1,2 +1,2 @@
1
- export { Alert } from './Alert'
2
- export type { AlertProps, AlertVariant } from './Alert'
1
+ export { AlertBanner } from './Alert'
2
+ export type { AlertBannerProps, AlertBannerVariant } from './Alert'
@@ -8,11 +8,14 @@ import {
8
8
  TouchableOpacityProps,
9
9
  ViewStyle,
10
10
  TextStyle,
11
+ Platform,
11
12
  } from 'react-native'
13
+
14
+ const nativeDriver = Platform.OS !== 'web'
12
15
  import * as Haptics from 'expo-haptics'
13
16
  import { useTheme } from '../../theme'
14
17
 
15
- export type ButtonVariant = 'primary' | 'secondary' | 'outline' | 'ghost'
18
+ export type ButtonVariant = 'primary' | 'secondary' | 'outline' | 'ghost' | 'destructive'
16
19
  export type ButtonSize = 'sm' | 'md' | 'lg'
17
20
 
18
21
  export interface ButtonProps extends TouchableOpacityProps {
@@ -67,14 +70,14 @@ export function Button({
67
70
  if (isDisabled) return
68
71
  Animated.spring(scale, {
69
72
  toValue: 0.95,
70
- useNativeDriver: true,
73
+ useNativeDriver: nativeDriver,
71
74
  speed: 40,
72
75
  bounciness: 0,
73
76
  }).start()
74
77
  }
75
78
 
76
79
  const handlePressOut = () => {
77
- Animated.spring(scale, { toValue: 1, useNativeDriver: true, speed: 40, bounciness: 4 }).start()
80
+ Animated.spring(scale, { toValue: 1, useNativeDriver: nativeDriver, speed: 40, bounciness: 4 }).start()
78
81
  }
79
82
 
80
83
  const handlePress: TouchableOpacityProps['onPress'] = (e) => {
@@ -87,6 +90,7 @@ export function Button({
87
90
  secondary: { backgroundColor: colors.secondary },
88
91
  outline: { backgroundColor: 'transparent', borderWidth: 1.5, borderColor: colors.border },
89
92
  ghost: { backgroundColor: 'transparent' },
93
+ destructive: { backgroundColor: colors.destructive },
90
94
  }[variant]
91
95
 
92
96
  const labelVariantStyle: TextStyle = {
@@ -94,10 +98,13 @@ export function Button({
94
98
  secondary: { color: colors.secondaryForeground },
95
99
  outline: { color: colors.foreground },
96
100
  ghost: { color: colors.foreground },
101
+ destructive: { color: colors.destructiveForeground },
97
102
  }[variant]
98
103
 
99
104
  const spinnerColor =
100
- variant === 'primary' || variant === 'secondary' ? colors.primaryForeground : colors.foreground
105
+ variant === 'destructive' ? colors.destructiveForeground
106
+ : variant === 'primary' || variant === 'secondary' ? colors.primaryForeground
107
+ : colors.foreground
101
108
 
102
109
  return (
103
110
  <Animated.View style={[fullWidth && styles.fullWidth, { transform: [{ scale }] }]}>