@blinkdotnew/mobile-ui 2.0.0-alpha.11 → 2.0.0-alpha.13

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
@@ -8,16 +8,16 @@ var blinkConfig = createTamagui({
8
8
  // src/index.ts
9
9
  import { defaultConfig as defaultConfig2 } from "@tamagui/config/v5";
10
10
  import {
11
- View as View6,
11
+ View as View7,
12
12
  Stack,
13
13
  SizableStack,
14
14
  ThemeableStack,
15
15
  Frame,
16
- XStack as XStack27,
17
- YStack as YStack32,
16
+ XStack as XStack41,
17
+ YStack as YStack45,
18
18
  ZStack,
19
- ScrollView as ScrollView5,
20
- Circle as Circle8,
19
+ ScrollView as ScrollView7,
20
+ Circle as Circle9,
21
21
  Square,
22
22
  Spacer,
23
23
  EnsureFlexed,
@@ -38,30 +38,30 @@ import {
38
38
  H6 as H62,
39
39
  Heading,
40
40
  Paragraph,
41
- SizableText as SizableText34,
41
+ SizableText as SizableText48,
42
42
  Text,
43
43
  Label,
44
- Button as Button8,
45
- Input as Input3,
44
+ Button as Button11,
45
+ Input as Input5,
46
46
  TextArea,
47
- Switch as Switch2,
47
+ Switch as Switch3,
48
48
  Checkbox,
49
- Slider,
49
+ Slider as Slider2,
50
50
  RadioGroup,
51
51
  Select,
52
52
  Fieldset,
53
53
  Form,
54
54
  Card as Card2,
55
55
  Avatar as Avatar2,
56
- Separator as Separator5,
57
- Image as Image6,
56
+ Separator as Separator7,
57
+ Image as Image9,
58
58
  Progress,
59
59
  Spinner as Spinner2,
60
60
  ListItem as ListItem2,
61
61
  Anchor,
62
62
  Sheet as Sheet3,
63
63
  Dialog,
64
- AlertDialog as AlertDialog2,
64
+ AlertDialog as AlertDialog3,
65
65
  Popover as Popover2,
66
66
  Tooltip,
67
67
  TooltipSimple,
@@ -76,7 +76,7 @@ import {
76
76
  Adapt,
77
77
  VisuallyHidden,
78
78
  Unspaced,
79
- Theme,
79
+ Theme as Theme2,
80
80
  TamaguiProvider,
81
81
  TamaguiProvider as TamaguiProvider2,
82
82
  createTamagui as createTamagui2,
@@ -89,7 +89,7 @@ import {
89
89
  addTheme,
90
90
  updateTheme,
91
91
  replaceTheme,
92
- styled as styled12,
92
+ styled as styled14,
93
93
  withStaticProperties as withStaticProperties2,
94
94
  isWeb,
95
95
  isClient,
@@ -100,7 +100,7 @@ import {
100
100
  composeRefs,
101
101
  composeEventHandlers,
102
102
  useTheme,
103
- useMedia,
103
+ useMedia as useMedia2,
104
104
  useThemeName,
105
105
  useControllableState,
106
106
  useEvent,
@@ -1035,78 +1035,137 @@ function Container({ children, maxWidth = 500, centered = true, padding = "$4" }
1035
1035
  }
1036
1036
 
1037
1037
  // src/patterns/PaywallScreen.tsx
1038
- import { Button as Button3, SizableText as SizableText17, XStack as XStack10, YStack as YStack14, Circle as Circle2 } from "tamagui";
1038
+ import { useState as useState5, useEffect as useEffect3 } from "react";
1039
+ import { Button as Button3, SizableText as SizableText17, XStack as XStack10, YStack as YStack14, ScrollView as ScrollView2 } from "tamagui";
1039
1040
  import { jsx as jsx20, jsxs as jsxs13 } from "react/jsx-runtime";
1041
+ function useCountdown(minutes) {
1042
+ const [seconds, setSeconds] = useState5((minutes ?? 0) * 60);
1043
+ useEffect3(() => {
1044
+ if (!minutes) return;
1045
+ setSeconds(minutes * 60);
1046
+ const id = setInterval(() => setSeconds((s) => s > 0 ? s - 1 : 0), 1e3);
1047
+ return () => clearInterval(id);
1048
+ }, [minutes]);
1049
+ const mm = String(Math.floor(seconds / 60)).padStart(2, "0");
1050
+ const ss = String(seconds % 60).padStart(2, "0");
1051
+ return { display: `${mm}:${ss}`, expired: seconds <= 0 };
1052
+ }
1053
+ function PlanCard({ plan, selected, onPress }) {
1054
+ return /* @__PURE__ */ jsxs13(
1055
+ YStack14,
1056
+ {
1057
+ flex: 1,
1058
+ padding: "$3",
1059
+ borderRadius: "$5",
1060
+ borderWidth: 2,
1061
+ borderColor: selected ? "$color9" : "$color5",
1062
+ backgroundColor: selected ? "$color3" : "$color1",
1063
+ pressStyle: { scale: 0.97, opacity: 0.9 },
1064
+ animation: "quick",
1065
+ onPress,
1066
+ cursor: "pointer",
1067
+ position: "relative",
1068
+ gap: "$1.5",
1069
+ alignItems: "center",
1070
+ children: [
1071
+ plan.popular && /* @__PURE__ */ jsx20(YStack14, { position: "absolute", top: -10, backgroundColor: "$color9", paddingHorizontal: "$2", paddingVertical: 2, borderRadius: "$10", children: /* @__PURE__ */ jsx20(SizableText17, { size: "$1", color: "white", fontWeight: "700", children: "BEST VALUE" }) }),
1072
+ plan.savings && /* @__PURE__ */ jsx20(YStack14, { position: "absolute", top: plan.popular ? -24 : -10, right: 6, backgroundColor: "$green9", paddingHorizontal: "$1.5", paddingVertical: 2, borderRadius: "$10", children: /* @__PURE__ */ jsx20(SizableText17, { size: "$1", color: "white", fontWeight: "700", children: plan.savings }) }),
1073
+ /* @__PURE__ */ jsx20(SizableText17, { size: "$2", fontWeight: "600", color: "$color11", paddingTop: plan.popular ? "$1" : 0, children: plan.name }),
1074
+ /* @__PURE__ */ jsx20(SizableText17, { size: "$7", fontWeight: "800", children: plan.price }),
1075
+ /* @__PURE__ */ jsxs13(SizableText17, { size: "$2", color: "$color9", children: [
1076
+ "/",
1077
+ plan.period
1078
+ ] }),
1079
+ plan.pricePerWeek && /* @__PURE__ */ jsx20(SizableText17, { size: "$1", color: "$color10", children: plan.pricePerWeek }),
1080
+ plan.trial && /* @__PURE__ */ jsx20(YStack14, { backgroundColor: "$green3", paddingHorizontal: "$2", paddingVertical: 2, borderRadius: "$10", marginTop: "$1", children: /* @__PURE__ */ jsx20(SizableText17, { size: "$1", color: "$green9", fontWeight: "700", children: plan.trial }) })
1081
+ ]
1082
+ }
1083
+ );
1084
+ }
1040
1085
  function PaywallScreen({
1041
- title = "Upgrade Your Experience",
1042
- subtitle = "Choose the plan that works for you",
1086
+ title = "Unlock Premium",
1087
+ subtitle,
1088
+ features = [],
1043
1089
  plans,
1044
1090
  selectedPlan,
1045
1091
  onSelectPlan,
1046
1092
  onContinue,
1093
+ onClose,
1047
1094
  onRestore,
1048
- continueLabel = "Continue"
1095
+ onTerms,
1096
+ onPrivacy,
1097
+ continueLabel = "Continue",
1098
+ reassurance = "Cancel anytime",
1099
+ hero,
1100
+ socialProof,
1101
+ countdownMinutes,
1102
+ badge
1049
1103
  }) {
1050
- return /* @__PURE__ */ jsxs13(YStack14, { flex: 1, padding: "$4", gap: "$5", backgroundColor: "$background", children: [
1051
- /* @__PURE__ */ jsxs13(YStack14, { gap: "$2", paddingTop: "$6", children: [
1052
- /* @__PURE__ */ jsx20(SizableText17, { size: "$9", fontWeight: "700", textAlign: "center", children: title }),
1053
- /* @__PURE__ */ jsx20(SizableText17, { size: "$4", color: "$color10", textAlign: "center", children: subtitle })
1054
- ] }),
1055
- /* @__PURE__ */ jsx20(YStack14, { gap: "$3", flex: 1, children: plans.map((plan) => /* @__PURE__ */ jsxs13(
1104
+ const selected = selectedPlan ?? plans.find((p) => p.popular)?.id ?? plans[0]?.id;
1105
+ const countdown = useCountdown(countdownMinutes);
1106
+ return /* @__PURE__ */ jsxs13(YStack14, { flex: 1, backgroundColor: "$background", children: [
1107
+ onClose && /* @__PURE__ */ jsx20(XStack10, { position: "absolute", top: "$4", right: "$4", zIndex: 10, children: /* @__PURE__ */ jsx20(Button3, { size: "$3", circular: true, chromeless: true, onPress: onClose, pressStyle: { opacity: 0.6 }, children: /* @__PURE__ */ jsx20(SizableText17, { size: "$5", color: "$color9", children: "\u2715" }) }) }),
1108
+ /* @__PURE__ */ jsx20(ScrollView2, { flex: 1, contentContainerStyle: { paddingBottom: 220 }, children: /* @__PURE__ */ jsxs13(YStack14, { padding: "$4", gap: "$4", paddingTop: "$8", children: [
1109
+ hero && /* @__PURE__ */ jsx20(YStack14, { alignItems: "center", paddingVertical: "$3", children: hero }),
1110
+ badge && /* @__PURE__ */ jsx20(XStack10, { justifyContent: "center", children: /* @__PURE__ */ jsx20(YStack14, { backgroundColor: "$color9", paddingHorizontal: "$3", paddingVertical: "$1", borderRadius: "$10", children: /* @__PURE__ */ jsx20(SizableText17, { size: "$2", color: "white", fontWeight: "700", children: badge }) }) }),
1111
+ /* @__PURE__ */ jsxs13(YStack14, { gap: "$1.5", alignItems: "center", children: [
1112
+ /* @__PURE__ */ jsx20(SizableText17, { size: "$9", fontWeight: "800", textAlign: "center", children: title }),
1113
+ subtitle && /* @__PURE__ */ jsx20(SizableText17, { size: "$4", color: "$color10", textAlign: "center", children: subtitle }),
1114
+ socialProof && /* @__PURE__ */ jsx20(SizableText17, { size: "$3", color: "$color9", fontWeight: "600", textAlign: "center", children: socialProof })
1115
+ ] }),
1116
+ countdownMinutes && !countdown.expired && /* @__PURE__ */ jsxs13(XStack10, { justifyContent: "center", padding: "$2", backgroundColor: "$red3", borderRadius: "$4", alignSelf: "center", paddingHorizontal: "$4", gap: "$2", alignItems: "center", children: [
1117
+ /* @__PURE__ */ jsx20(SizableText17, { size: "$2", color: "$red9", fontWeight: "600", children: "Offer ends in" }),
1118
+ /* @__PURE__ */ jsx20(SizableText17, { size: "$5", color: "$red9", fontWeight: "800", fontFamily: "$mono", children: countdown.display })
1119
+ ] }),
1120
+ features.length > 0 && /* @__PURE__ */ jsx20(YStack14, { gap: "$2.5", paddingHorizontal: "$2", children: features.map((f, i) => /* @__PURE__ */ jsxs13(XStack10, { gap: "$2.5", alignItems: "center", children: [
1121
+ /* @__PURE__ */ jsx20(SizableText17, { size: "$4", color: "$green9", children: "\u2713" }),
1122
+ /* @__PURE__ */ jsx20(SizableText17, { size: "$4", color: "$color11", flex: 1, children: f })
1123
+ ] }, i)) }),
1124
+ /* @__PURE__ */ jsx20(XStack10, { gap: "$3", paddingTop: "$1", children: plans.map((plan) => /* @__PURE__ */ jsx20(PlanCard, { plan, selected: selected === plan.id, onPress: () => onSelectPlan?.(plan.id) }, plan.id)) })
1125
+ ] }) }),
1126
+ /* @__PURE__ */ jsxs13(
1056
1127
  YStack14,
1057
1128
  {
1129
+ position: "absolute",
1130
+ bottom: 0,
1131
+ left: 0,
1132
+ right: 0,
1058
1133
  padding: "$4",
1059
- borderRadius: "$5",
1060
- borderWidth: 2,
1061
- borderColor: selectedPlan === plan.id ? "$color9" : "$color4",
1062
- backgroundColor: selectedPlan === plan.id ? "$color2" : "$color1",
1063
- pressStyle: { scale: 0.98 },
1064
- onPress: () => onSelectPlan?.(plan.id),
1065
- cursor: "pointer",
1134
+ paddingBottom: "$6",
1135
+ backgroundColor: "$background",
1136
+ borderTopWidth: 1,
1137
+ borderTopColor: "$color4",
1138
+ gap: "$2.5",
1066
1139
  children: [
1067
- /* @__PURE__ */ jsxs13(XStack10, { justifyContent: "space-between", alignItems: "center", children: [
1068
- /* @__PURE__ */ jsxs13(YStack14, { children: [
1069
- /* @__PURE__ */ jsx20(SizableText17, { size: "$5", fontWeight: "600", children: plan.name }),
1070
- /* @__PURE__ */ jsxs13(XStack10, { alignItems: "baseline", gap: "$1", children: [
1071
- /* @__PURE__ */ jsx20(SizableText17, { size: "$8", fontWeight: "700", children: plan.price }),
1072
- /* @__PURE__ */ jsxs13(SizableText17, { size: "$3", color: "$color9", children: [
1073
- "/",
1074
- plan.period
1075
- ] })
1076
- ] })
1077
- ] }),
1078
- plan.popular && /* @__PURE__ */ jsx20(YStack14, { backgroundColor: "$color9", paddingHorizontal: "$2", paddingVertical: "$1", borderRadius: "$10", children: /* @__PURE__ */ jsx20(SizableText17, { size: "$1", color: "$color1", fontWeight: "600", children: "POPULAR" }) })
1079
- ] }),
1080
- /* @__PURE__ */ jsx20(YStack14, { gap: "$2", paddingTop: "$3", children: plan.features.map((feature, i) => /* @__PURE__ */ jsxs13(XStack10, { gap: "$2", alignItems: "center", children: [
1081
- /* @__PURE__ */ jsx20(Circle2, { size: 6, backgroundColor: "$green9" }),
1082
- /* @__PURE__ */ jsx20(SizableText17, { size: "$3", color: "$color11", children: feature })
1083
- ] }, i)) })
1140
+ /* @__PURE__ */ jsx20(
1141
+ Button3,
1142
+ {
1143
+ size: "$5",
1144
+ backgroundColor: "$color9",
1145
+ color: "$color1",
1146
+ onPress: onContinue,
1147
+ pressStyle: { backgroundColor: "$color8", scale: 0.98 },
1148
+ animation: "quick",
1149
+ borderRadius: "$10",
1150
+ fontWeight: "700",
1151
+ children: continueLabel
1152
+ }
1153
+ ),
1154
+ reassurance && /* @__PURE__ */ jsx20(SizableText17, { size: "$2", color: "$color9", textAlign: "center", children: reassurance }),
1155
+ /* @__PURE__ */ jsxs13(XStack10, { justifyContent: "center", gap: "$3", children: [
1156
+ onRestore && /* @__PURE__ */ jsx20(SizableText17, { size: "$2", color: "$color8", onPress: onRestore, pressStyle: { opacity: 0.6 }, children: "Restore" }),
1157
+ onTerms && /* @__PURE__ */ jsx20(SizableText17, { size: "$2", color: "$color8", onPress: onTerms, pressStyle: { opacity: 0.6 }, children: "Terms" }),
1158
+ onPrivacy && /* @__PURE__ */ jsx20(SizableText17, { size: "$2", color: "$color8", onPress: onPrivacy, pressStyle: { opacity: 0.6 }, children: "Privacy" })
1159
+ ] })
1084
1160
  ]
1085
- },
1086
- plan.id
1087
- )) }),
1088
- /* @__PURE__ */ jsxs13(YStack14, { gap: "$3", paddingBottom: "$4", children: [
1089
- /* @__PURE__ */ jsx20(
1090
- Button3,
1091
- {
1092
- size: "$5",
1093
- backgroundColor: "$color9",
1094
- color: "$color1",
1095
- onPress: onContinue,
1096
- hoverStyle: { backgroundColor: "$color10" },
1097
- pressStyle: { backgroundColor: "$color8" },
1098
- borderRadius: "$5",
1099
- children: continueLabel
1100
- }
1101
- ),
1102
- onRestore && /* @__PURE__ */ jsx20(Button3, { size: "$3", chromeless: true, onPress: onRestore, children: /* @__PURE__ */ jsx20(SizableText17, { size: "$3", color: "$color9", children: "Restore Purchases" }) })
1103
- ] })
1161
+ }
1162
+ )
1104
1163
  ] });
1105
1164
  }
1106
1165
 
1107
1166
  // src/patterns/OnboardingCarousel.tsx
1108
- import { useState as useState5 } from "react";
1109
- import { Button as Button4, SizableText as SizableText18, XStack as XStack11, YStack as YStack15, Circle as Circle3 } from "tamagui";
1167
+ import { useState as useState6 } from "react";
1168
+ import { Button as Button4, SizableText as SizableText18, XStack as XStack11, YStack as YStack15, Circle as Circle2 } from "tamagui";
1110
1169
  import { jsx as jsx21, jsxs as jsxs14 } from "react/jsx-runtime";
1111
1170
  function OnboardingCarousel({
1112
1171
  steps,
@@ -1116,13 +1175,13 @@ function OnboardingCarousel({
1116
1175
  skipLabel = "Skip",
1117
1176
  nextLabel = "Next"
1118
1177
  }) {
1119
- const [current, setCurrent] = useState5(0);
1178
+ const [current, setCurrent] = useState6(0);
1120
1179
  const isLast = current === steps.length - 1;
1121
1180
  const step = steps[current];
1122
1181
  return /* @__PURE__ */ jsxs14(YStack15, { flex: 1, backgroundColor: "$background", padding: "$4", justifyContent: "space-between", children: [
1123
1182
  /* @__PURE__ */ jsx21(XStack11, { justifyContent: "flex-end", paddingTop: "$4", children: !isLast && onSkip && /* @__PURE__ */ jsx21(Button4, { chromeless: true, onPress: onSkip, children: /* @__PURE__ */ jsx21(SizableText18, { size: "$4", color: "$color9", children: skipLabel }) }) }),
1124
1183
  /* @__PURE__ */ jsxs14(YStack15, { flex: 1, alignItems: "center", justifyContent: "center", gap: "$5", paddingHorizontal: "$4", children: [
1125
- step?.icon && /* @__PURE__ */ jsx21(Circle3, { size: 120, backgroundColor: "$color2", alignItems: "center", justifyContent: "center", children: step.icon }),
1184
+ step?.icon && /* @__PURE__ */ jsx21(Circle2, { size: 120, backgroundColor: "$color2", alignItems: "center", justifyContent: "center", children: step.icon }),
1126
1185
  /* @__PURE__ */ jsxs14(YStack15, { gap: "$3", alignItems: "center", children: [
1127
1186
  /* @__PURE__ */ jsx21(SizableText18, { size: "$9", fontWeight: "700", textAlign: "center", children: step?.title }),
1128
1187
  /* @__PURE__ */ jsx21(SizableText18, { size: "$4", color: "$color10", textAlign: "center", maxWidth: 300, children: step?.description })
@@ -1130,7 +1189,7 @@ function OnboardingCarousel({
1130
1189
  ] }),
1131
1190
  /* @__PURE__ */ jsxs14(YStack15, { gap: "$3", paddingBottom: "$2", children: [
1132
1191
  /* @__PURE__ */ jsx21(XStack11, { justifyContent: "center", gap: "$2", children: steps.map((_, i) => /* @__PURE__ */ jsx21(
1133
- Circle3,
1192
+ Circle2,
1134
1193
  {
1135
1194
  size: 8,
1136
1195
  backgroundColor: i === current ? "$color9" : "$color4",
@@ -1156,7 +1215,7 @@ function OnboardingCarousel({
1156
1215
  }
1157
1216
 
1158
1217
  // src/patterns/ChatBubble.tsx
1159
- import { SizableText as SizableText19, XStack as XStack12, YStack as YStack16, Circle as Circle4, Image as Image3 } from "tamagui";
1218
+ import { SizableText as SizableText19, XStack as XStack12, YStack as YStack16, Circle as Circle3, Image as Image3 } from "tamagui";
1160
1219
  import { jsx as jsx22, jsxs as jsxs15 } from "react/jsx-runtime";
1161
1220
  function ChatBubble({ message, showAvatar = true }) {
1162
1221
  const isUser = message.sender === "user";
@@ -1168,7 +1227,7 @@ function ChatBubble({ message, showAvatar = true }) {
1168
1227
  gap: "$2",
1169
1228
  flexDirection: isUser ? "row-reverse" : "row",
1170
1229
  children: [
1171
- showAvatar && !isUser && /* @__PURE__ */ jsx22(Circle4, { size: 32, backgroundColor: "$color4", overflow: "hidden", children: message.avatar ? /* @__PURE__ */ jsx22(Image3, { source: { uri: message.avatar }, width: 32, height: 32, objectFit: "cover" }) : /* @__PURE__ */ jsx22(SizableText19, { size: "$2", fontWeight: "600", color: "$color11", children: message.senderName?.[0]?.toUpperCase() ?? "?" }) }),
1230
+ showAvatar && !isUser && /* @__PURE__ */ jsx22(Circle3, { size: 32, backgroundColor: "$color4", overflow: "hidden", children: message.avatar ? /* @__PURE__ */ jsx22(Image3, { source: { uri: message.avatar }, width: 32, height: 32, objectFit: "cover" }) : /* @__PURE__ */ jsx22(SizableText19, { size: "$2", fontWeight: "600", color: "$color11", children: message.senderName?.[0]?.toUpperCase() ?? "?" }) }),
1172
1231
  /* @__PURE__ */ jsxs15(
1173
1232
  YStack16,
1174
1233
  {
@@ -1267,11 +1326,11 @@ function EmptyState({ icon, title, description, actionLabel, onAction }) {
1267
1326
  }
1268
1327
 
1269
1328
  // src/patterns/ProfileHeader.tsx
1270
- import { Circle as Circle5, Image as Image4, SizableText as SizableText22, XStack as XStack14, YStack as YStack19 } from "tamagui";
1329
+ import { Circle as Circle4, Image as Image4, SizableText as SizableText22, XStack as XStack14, YStack as YStack19 } from "tamagui";
1271
1330
  import { jsx as jsx25, jsxs as jsxs18 } from "react/jsx-runtime";
1272
1331
  function ProfileHeader({ name, subtitle, avatar, stats, actions }) {
1273
1332
  return /* @__PURE__ */ jsxs18(YStack19, { alignItems: "center", gap: "$4", paddingVertical: "$6", paddingHorizontal: "$4", children: [
1274
- /* @__PURE__ */ jsx25(Circle5, { size: 80, backgroundColor: "$color4", overflow: "hidden", children: avatar ? /* @__PURE__ */ jsx25(Image4, { source: { uri: avatar }, width: 80, height: 80, objectFit: "cover" }) : /* @__PURE__ */ jsx25(SizableText22, { size: "$9", fontWeight: "700", color: "$color11", children: name[0]?.toUpperCase() ?? "?" }) }),
1333
+ /* @__PURE__ */ jsx25(Circle4, { size: 80, backgroundColor: "$color4", overflow: "hidden", children: avatar ? /* @__PURE__ */ jsx25(Image4, { source: { uri: avatar }, width: 80, height: 80, objectFit: "cover" }) : /* @__PURE__ */ jsx25(SizableText22, { size: "$9", fontWeight: "700", color: "$color11", children: name[0]?.toUpperCase() ?? "?" }) }),
1275
1334
  /* @__PURE__ */ jsxs18(YStack19, { alignItems: "center", gap: "$1", children: [
1276
1335
  /* @__PURE__ */ jsx25(SizableText22, { size: "$7", fontWeight: "700", children: name }),
1277
1336
  subtitle && /* @__PURE__ */ jsx25(SizableText22, { size: "$4", color: "$color10", children: subtitle })
@@ -1316,7 +1375,7 @@ function AppHeader({ title, subtitle, variant = "simple", onBack, avatar, left,
1316
1375
 
1317
1376
  // src/patterns/BottomSheet.tsx
1318
1377
  import { Sheet, SizableText as SizableText24, XStack as XStack16, YStack as YStack21 } from "tamagui";
1319
- import { ScrollView as ScrollView2 } from "react-native";
1378
+ import { ScrollView as ScrollView3 } from "react-native";
1320
1379
  import { jsx as jsx27, jsxs as jsxs20 } from "react/jsx-runtime";
1321
1380
  function BottomSheet({ open, onOpenChange, title, children, snapPoints = [85], dismissOnSnapToBottom = true, showHandle = true, showClose = false, zIndex = 1e5 }) {
1322
1381
  return /* @__PURE__ */ jsxs20(
@@ -1351,7 +1410,7 @@ function BottomSheet({ open, onOpenChange, title, children, snapPoints = [85], d
1351
1410
  }
1352
1411
  )
1353
1412
  ] }),
1354
- /* @__PURE__ */ jsx27(ScrollView2, { contentContainerStyle: { paddingBottom: 40 }, children: /* @__PURE__ */ jsx27(YStack21, { padding: "$4", children }) })
1413
+ /* @__PURE__ */ jsx27(ScrollView3, { contentContainerStyle: { paddingBottom: 40 }, children: /* @__PURE__ */ jsx27(YStack21, { padding: "$4", children }) })
1355
1414
  ] })
1356
1415
  ]
1357
1416
  }
@@ -1359,12 +1418,12 @@ function BottomSheet({ open, onOpenChange, title, children, snapPoints = [85], d
1359
1418
  }
1360
1419
 
1361
1420
  // src/patterns/LoginScreen.tsx
1362
- import { useState as useState6 } from "react";
1421
+ import { useState as useState7 } from "react";
1363
1422
  import { Button as Button6, SizableText as SizableText25, Spinner, XStack as XStack17, YStack as YStack22 } from "tamagui";
1364
1423
  import { jsx as jsx28, jsxs as jsxs21 } from "react/jsx-runtime";
1365
1424
  function LoginScreen({ title = "Welcome", subtitle = "Sign in to continue", logo, providers = [], onProviderPress, showEmailForm, onEmailSubmit, onForgotPassword, onCreateAccount, onTerms, onPrivacy, loading }) {
1366
- const [email, setEmail] = useState6("");
1367
- const [password, setPassword] = useState6("");
1425
+ const [email, setEmail] = useState7("");
1426
+ const [password, setPassword] = useState7("");
1368
1427
  return /* @__PURE__ */ jsxs21(YStack22, { flex: 1, padding: "$4", gap: "$5", backgroundColor: "$background", justifyContent: "center", children: [
1369
1428
  /* @__PURE__ */ jsxs21(YStack22, { alignItems: "center", gap: "$2", children: [
1370
1429
  logo && /* @__PURE__ */ jsx28(YStack22, { paddingBottom: "$3", children: logo }),
@@ -1620,7 +1679,7 @@ function NotificationBanner({ title, message, variant = "info", onPress, onDismi
1620
1679
  }
1621
1680
 
1622
1681
  // src/patterns/ProgressSteps.tsx
1623
- import { Circle as Circle6, SizableText as SizableText31, XStack as XStack23, YStack as YStack27 } from "tamagui";
1682
+ import { Circle as Circle5, SizableText as SizableText31, XStack as XStack23, YStack as YStack27 } from "tamagui";
1624
1683
  import { jsx as jsx35, jsxs as jsxs27 } from "react/jsx-runtime";
1625
1684
  function ProgressSteps({ steps, currentStep, variant = "dots" }) {
1626
1685
  if (variant === "bar") {
@@ -1632,7 +1691,7 @@ function ProgressSteps({ steps, currentStep, variant = "dots" }) {
1632
1691
  }
1633
1692
  return /* @__PURE__ */ jsx35(XStack23, { alignItems: "center", justifyContent: "center", gap: "$0", children: steps.map((label, i) => /* @__PURE__ */ jsxs27(XStack23, { alignItems: "center", gap: "$0", children: [
1634
1693
  /* @__PURE__ */ jsxs27(YStack27, { alignItems: "center", gap: "$1.5", children: [
1635
- /* @__PURE__ */ jsx35(Circle6, { size: variant === "numbered" ? 28 : 10, backgroundColor: i <= currentStep ? "$color9" : "$color4", animation: "quick", children: variant === "numbered" && /* @__PURE__ */ jsx35(SizableText31, { size: "$2", fontWeight: "600", color: i <= currentStep ? "$color1" : "$color8", children: i + 1 }) }),
1694
+ /* @__PURE__ */ jsx35(Circle5, { size: variant === "numbered" ? 28 : 10, backgroundColor: i <= currentStep ? "$color9" : "$color4", animation: "quick", children: variant === "numbered" && /* @__PURE__ */ jsx35(SizableText31, { size: "$2", fontWeight: "600", color: i <= currentStep ? "$color1" : "$color8", children: i + 1 }) }),
1636
1695
  /* @__PURE__ */ jsx35(SizableText31, { size: "$1", color: i <= currentStep ? "$color11" : "$color8", numberOfLines: 1, children: label })
1637
1696
  ] }),
1638
1697
  i < steps.length - 1 && /* @__PURE__ */ jsx35(YStack27, { height: 2, width: 32, backgroundColor: i < currentStep ? "$color9" : "$color4", marginBottom: "$4" })
@@ -1640,11 +1699,11 @@ function ProgressSteps({ steps, currentStep, variant = "dots" }) {
1640
1699
  }
1641
1700
 
1642
1701
  // src/patterns/SwipeableRow.tsx
1643
- import { useState as useState7 } from "react";
1702
+ import { useState as useState8 } from "react";
1644
1703
  import { Button as Button7, SizableText as SizableText32, XStack as XStack24, YStack as YStack28 } from "tamagui";
1645
1704
  import { Fragment as Fragment2, jsx as jsx36, jsxs as jsxs28 } from "react/jsx-runtime";
1646
1705
  function SwipeableRow({ children, leftActions, rightActions }) {
1647
- const [showActions, setShowActions] = useState7(false);
1706
+ const [showActions, setShowActions] = useState8(false);
1648
1707
  const actions = [...leftActions ?? [], ...rightActions ?? []];
1649
1708
  if (actions.length === 0) return /* @__PURE__ */ jsx36(Fragment2, { children });
1650
1709
  return /* @__PURE__ */ jsxs28(YStack28, { children: [
@@ -1719,17 +1778,17 @@ function MediaCard({ image, title, subtitle, overlay = "gradient", aspectRatio =
1719
1778
  }
1720
1779
 
1721
1780
  // src/patterns/Carousel.tsx
1722
- import { Children as Children2, useState as useState8 } from "react";
1723
- import { Circle as Circle7, XStack as XStack26, YStack as YStack30 } from "tamagui";
1724
- import { ScrollView as ScrollView3 } from "react-native";
1781
+ import { Children as Children2, useState as useState9 } from "react";
1782
+ import { Circle as Circle6, XStack as XStack26, YStack as YStack30 } from "tamagui";
1783
+ import { ScrollView as ScrollView4 } from "react-native";
1725
1784
  import { jsx as jsx38, jsxs as jsxs30 } from "react/jsx-runtime";
1726
1785
  function Carousel({ children, gap = "$3", snapToInterval, showIndicators = false }) {
1727
- const [activeIndex, setActiveIndex] = useState8(0);
1786
+ const [activeIndex, setActiveIndex] = useState9(0);
1728
1787
  const count = Children2.count(children);
1729
1788
  const gapPx = gap === "$2" ? 8 : gap === "$3" ? 12 : 16;
1730
1789
  return /* @__PURE__ */ jsxs30(YStack30, { gap: "$3", children: [
1731
1790
  /* @__PURE__ */ jsx38(
1732
- ScrollView3,
1791
+ ScrollView4,
1733
1792
  {
1734
1793
  horizontal: true,
1735
1794
  showsHorizontalScrollIndicator: false,
@@ -1742,17 +1801,17 @@ function Carousel({ children, gap = "$3", snapToInterval, showIndicators = false
1742
1801
  children
1743
1802
  }
1744
1803
  ),
1745
- showIndicators && count > 1 && /* @__PURE__ */ jsx38(XStack26, { justifyContent: "center", gap: "$1.5", children: Array.from({ length: count }, (_, i) => /* @__PURE__ */ jsx38(Circle7, { size: 6, backgroundColor: i === activeIndex ? "$color9" : "$color4", animation: "quick" }, i)) })
1804
+ showIndicators && count > 1 && /* @__PURE__ */ jsx38(XStack26, { justifyContent: "center", gap: "$1.5", children: Array.from({ length: count }, (_, i) => /* @__PURE__ */ jsx38(Circle6, { size: 6, backgroundColor: i === activeIndex ? "$color9" : "$color4", animation: "quick" }, i)) })
1746
1805
  ] });
1747
1806
  }
1748
1807
 
1749
1808
  // src/patterns/PullToRefresh.tsx
1750
1809
  import { YStack as YStack31 } from "tamagui";
1751
- import { RefreshControl, ScrollView as ScrollView4 } from "react-native";
1810
+ import { RefreshControl, ScrollView as ScrollView5 } from "react-native";
1752
1811
  import { jsx as jsx39 } from "react/jsx-runtime";
1753
1812
  function PullToRefresh({ children, onRefresh, refreshing = false }) {
1754
1813
  return /* @__PURE__ */ jsx39(
1755
- ScrollView4,
1814
+ ScrollView5,
1756
1815
  {
1757
1816
  contentContainerStyle: { flexGrow: 1 },
1758
1817
  refreshControl: /* @__PURE__ */ jsx39(RefreshControl, { refreshing, onRefresh }),
@@ -1760,17 +1819,1334 @@ function PullToRefresh({ children, onRefresh, refreshing = false }) {
1760
1819
  }
1761
1820
  );
1762
1821
  }
1822
+
1823
+ // src/patterns/ProductCard.tsx
1824
+ import { Button as Button8, Image as Image6, SizableText as SizableText34, XStack as XStack27, YStack as YStack32 } from "tamagui";
1825
+ import { jsx as jsx40, jsxs as jsxs31 } from "react/jsx-runtime";
1826
+ function Stars({ rating = 0 }) {
1827
+ return /* @__PURE__ */ jsx40(XStack27, { gap: "$0.5", children: Array.from({ length: 5 }, (_, i) => /* @__PURE__ */ jsx40(SizableText34, { size: "$2", color: i < Math.round(rating) ? "$yellow9" : "$color5", children: "\u2605" }, i)) });
1828
+ }
1829
+ function CardContent2({ title, price, originalPrice, rating, reviewCount, onAddToCart }) {
1830
+ return /* @__PURE__ */ jsxs31(YStack32, { flex: 1, gap: "$1.5", justifyContent: "space-between", children: [
1831
+ /* @__PURE__ */ jsxs31(YStack32, { gap: "$1", children: [
1832
+ /* @__PURE__ */ jsx40(SizableText34, { size: "$4", fontWeight: "600", numberOfLines: 2, children: title }),
1833
+ rating !== void 0 && /* @__PURE__ */ jsxs31(XStack27, { gap: "$1.5", alignItems: "center", children: [
1834
+ /* @__PURE__ */ jsx40(Stars, { rating }),
1835
+ reviewCount !== void 0 && /* @__PURE__ */ jsxs31(SizableText34, { size: "$2", color: "$color9", children: [
1836
+ "(",
1837
+ reviewCount,
1838
+ ")"
1839
+ ] })
1840
+ ] })
1841
+ ] }),
1842
+ /* @__PURE__ */ jsxs31(XStack27, { alignItems: "center", justifyContent: "space-between", children: [
1843
+ /* @__PURE__ */ jsxs31(XStack27, { gap: "$2", alignItems: "baseline", children: [
1844
+ /* @__PURE__ */ jsx40(SizableText34, { size: "$6", fontWeight: "700", children: price }),
1845
+ originalPrice && /* @__PURE__ */ jsx40(SizableText34, { size: "$3", color: "$color8", textDecorationLine: "line-through", children: originalPrice })
1846
+ ] }),
1847
+ onAddToCart && /* @__PURE__ */ jsx40(
1848
+ Button8,
1849
+ {
1850
+ size: "$3",
1851
+ backgroundColor: "$color9",
1852
+ color: "$color1",
1853
+ borderRadius: "$10",
1854
+ onPress: (e) => {
1855
+ e.stopPropagation?.();
1856
+ onAddToCart();
1857
+ },
1858
+ pressStyle: { backgroundColor: "$color8", scale: 0.95 },
1859
+ animation: "quick",
1860
+ children: "+ Cart"
1861
+ }
1862
+ )
1863
+ ] })
1864
+ ] });
1865
+ }
1866
+ function ProductCard({ image, title, price, originalPrice, rating, reviewCount, badge, onPress, onAddToCart, variant = "vertical" }) {
1867
+ const isHorizontal = variant === "horizontal";
1868
+ const Wrapper = isHorizontal ? XStack27 : YStack32;
1869
+ return /* @__PURE__ */ jsxs31(
1870
+ Wrapper,
1871
+ {
1872
+ backgroundColor: "$color1",
1873
+ borderRadius: "$5",
1874
+ overflow: "hidden",
1875
+ borderWidth: 1,
1876
+ borderColor: "$color4",
1877
+ onPress,
1878
+ animation: "quick",
1879
+ pressStyle: onPress ? { scale: 0.98, opacity: 0.9 } : void 0,
1880
+ ...isHorizontal ? { height: 140 } : {},
1881
+ children: [
1882
+ /* @__PURE__ */ jsxs31(YStack32, { ...isHorizontal ? { width: 140 } : { aspectRatio: 4 / 3 }, position: "relative", children: [
1883
+ /* @__PURE__ */ jsx40(Image6, { source: { uri: image }, width: "100%", height: "100%", objectFit: "cover" }),
1884
+ badge && /* @__PURE__ */ jsx40(
1885
+ XStack27,
1886
+ {
1887
+ position: "absolute",
1888
+ top: "$2",
1889
+ left: "$2",
1890
+ backgroundColor: "$red9",
1891
+ paddingHorizontal: "$2",
1892
+ paddingVertical: "$1",
1893
+ borderRadius: "$10",
1894
+ children: /* @__PURE__ */ jsx40(SizableText34, { size: "$1", fontWeight: "700", color: "white", children: badge })
1895
+ }
1896
+ )
1897
+ ] }),
1898
+ /* @__PURE__ */ jsx40(YStack32, { flex: 1, padding: "$3", children: /* @__PURE__ */ jsx40(CardContent2, { ...{ title, price, originalPrice, rating, reviewCount, onAddToCart } }) })
1899
+ ]
1900
+ }
1901
+ );
1902
+ }
1903
+
1904
+ // src/patterns/PricingTable.tsx
1905
+ import { Button as Button9, ScrollView as ScrollView6, SizableText as SizableText35, XStack as XStack28, YStack as YStack33 } from "tamagui";
1906
+ import { jsx as jsx41, jsxs as jsxs32 } from "react/jsx-runtime";
1907
+ function BillingToggle({ annual, onToggle }) {
1908
+ return /* @__PURE__ */ jsx41(XStack28, { alignSelf: "center", backgroundColor: "$color3", borderRadius: "$10", padding: "$1", gap: "$0.5", children: ["Monthly", "Annual"].map((label, i) => {
1909
+ const active = i === 1 ? annual : !annual;
1910
+ return /* @__PURE__ */ jsx41(
1911
+ XStack28,
1912
+ {
1913
+ paddingHorizontal: "$4",
1914
+ paddingVertical: "$2",
1915
+ borderRadius: "$10",
1916
+ backgroundColor: active ? "$color9" : "transparent",
1917
+ onPress: () => onToggle(i === 1),
1918
+ pressStyle: { opacity: 0.8 },
1919
+ animation: "quick",
1920
+ children: /* @__PURE__ */ jsx41(SizableText35, { size: "$3", fontWeight: "600", color: active ? "$color1" : "$color10", children: label })
1921
+ },
1922
+ label
1923
+ );
1924
+ }) });
1925
+ }
1926
+ function PlanCard2({ plan, selected, onSelect }) {
1927
+ return /* @__PURE__ */ jsxs32(
1928
+ YStack33,
1929
+ {
1930
+ flex: 1,
1931
+ minWidth: 260,
1932
+ padding: "$4",
1933
+ borderRadius: "$5",
1934
+ gap: "$3",
1935
+ borderWidth: 2,
1936
+ borderColor: selected ? "$color9" : plan.popular ? "$color9" : "$color4",
1937
+ backgroundColor: plan.popular ? "$color2" : "$color1",
1938
+ position: "relative",
1939
+ pressStyle: { scale: 0.98 },
1940
+ animation: "quick",
1941
+ onPress: onSelect,
1942
+ children: [
1943
+ plan.popular && /* @__PURE__ */ jsx41(
1944
+ XStack28,
1945
+ {
1946
+ position: "absolute",
1947
+ top: -12,
1948
+ alignSelf: "center",
1949
+ backgroundColor: "$color9",
1950
+ paddingHorizontal: "$3",
1951
+ paddingVertical: "$1",
1952
+ borderRadius: "$10",
1953
+ children: /* @__PURE__ */ jsx41(SizableText35, { size: "$1", fontWeight: "700", color: "$color1", children: "POPULAR" })
1954
+ }
1955
+ ),
1956
+ /* @__PURE__ */ jsxs32(YStack33, { gap: "$1", alignItems: "center", paddingTop: plan.popular ? "$2" : 0, children: [
1957
+ /* @__PURE__ */ jsx41(SizableText35, { size: "$4", fontWeight: "600", color: "$color11", children: plan.name }),
1958
+ plan.description && /* @__PURE__ */ jsx41(SizableText35, { size: "$2", color: "$color9", textAlign: "center", children: plan.description }),
1959
+ /* @__PURE__ */ jsxs32(XStack28, { alignItems: "baseline", gap: "$1", children: [
1960
+ /* @__PURE__ */ jsx41(SizableText35, { size: "$9", fontWeight: "800", children: plan.price }),
1961
+ plan.period && /* @__PURE__ */ jsxs32(SizableText35, { size: "$3", color: "$color9", children: [
1962
+ "/",
1963
+ plan.period
1964
+ ] })
1965
+ ] })
1966
+ ] }),
1967
+ /* @__PURE__ */ jsx41(YStack33, { gap: "$2", flex: 1, children: plan.features.map((f, i) => /* @__PURE__ */ jsxs32(XStack28, { gap: "$2", alignItems: "center", children: [
1968
+ /* @__PURE__ */ jsx41(SizableText35, { size: "$3", color: f.included ? "$green9" : "$color6", children: f.included ? "\u2713" : "\u2717" }),
1969
+ /* @__PURE__ */ jsx41(SizableText35, { size: "$3", color: f.included ? "$color11" : "$color8", flex: 1, children: f.label })
1970
+ ] }, i)) }),
1971
+ /* @__PURE__ */ jsx41(
1972
+ Button9,
1973
+ {
1974
+ size: "$4",
1975
+ borderRadius: "$10",
1976
+ fontWeight: "700",
1977
+ animation: "quick",
1978
+ backgroundColor: selected || plan.popular ? "$color9" : "transparent",
1979
+ color: selected || plan.popular ? "$color1" : "$color11",
1980
+ borderWidth: selected || plan.popular ? 0 : 1,
1981
+ borderColor: "$color7",
1982
+ onPress: onSelect,
1983
+ pressStyle: { scale: 0.97, opacity: 0.9 },
1984
+ children: plan.cta ?? "Get Started"
1985
+ }
1986
+ )
1987
+ ]
1988
+ }
1989
+ );
1990
+ }
1991
+ function PricingTable({ plans, selectedPlan, onSelectPlan, annual = false, onToggleBilling }) {
1992
+ const selected = selectedPlan ?? plans.find((p) => p.popular)?.id;
1993
+ return /* @__PURE__ */ jsxs32(YStack33, { gap: "$4", children: [
1994
+ onToggleBilling && /* @__PURE__ */ jsx41(BillingToggle, { annual, onToggle: onToggleBilling }),
1995
+ /* @__PURE__ */ jsx41(
1996
+ ScrollView6,
1997
+ {
1998
+ horizontal: true,
1999
+ showsHorizontalScrollIndicator: false,
2000
+ contentContainerStyle: { gap: 12, paddingHorizontal: 4 },
2001
+ children: plans.map((plan) => /* @__PURE__ */ jsx41(
2002
+ PlanCard2,
2003
+ {
2004
+ plan,
2005
+ selected: selected === plan.id,
2006
+ onSelect: () => onSelectPlan?.(plan.id)
2007
+ },
2008
+ plan.id
2009
+ ))
2010
+ }
2011
+ )
2012
+ ] });
2013
+ }
2014
+
2015
+ // src/patterns/CountdownBanner.tsx
2016
+ import { useState as useState10, useEffect as useEffect4, useRef, useCallback as useCallback2 } from "react";
2017
+ import { SizableText as SizableText36, XStack as XStack29, YStack as YStack34 } from "tamagui";
2018
+ import { jsx as jsx42, jsxs as jsxs33 } from "react/jsx-runtime";
2019
+ function useCountdown2(endTime, minutes, onExpire) {
2020
+ const getRemaining = useCallback2(() => {
2021
+ if (endTime) return Math.max(0, Math.floor((endTime.getTime() - Date.now()) / 1e3));
2022
+ return 0;
2023
+ }, [endTime]);
2024
+ const [seconds, setSeconds] = useState10(() => endTime ? getRemaining() : (minutes ?? 0) * 60);
2025
+ const firedRef = useRef(false);
2026
+ useEffect4(() => {
2027
+ if (endTime) setSeconds(getRemaining());
2028
+ else setSeconds((minutes ?? 0) * 60);
2029
+ firedRef.current = false;
2030
+ }, [endTime, minutes, getRemaining]);
2031
+ useEffect4(() => {
2032
+ if (seconds <= 0) return;
2033
+ const id = setInterval(() => {
2034
+ setSeconds((s) => {
2035
+ const next = endTime ? Math.max(0, Math.floor((endTime.getTime() - Date.now()) / 1e3)) : s - 1;
2036
+ if (next <= 0 && !firedRef.current) {
2037
+ firedRef.current = true;
2038
+ onExpire?.();
2039
+ }
2040
+ return Math.max(0, next);
2041
+ });
2042
+ }, 1e3);
2043
+ return () => clearInterval(id);
2044
+ }, [seconds > 0, endTime, onExpire]);
2045
+ const hh = String(Math.floor(seconds / 3600)).padStart(2, "0");
2046
+ const mm = String(Math.floor(seconds % 3600 / 60)).padStart(2, "0");
2047
+ const ss = String(seconds % 60).padStart(2, "0");
2048
+ const display = seconds >= 3600 ? `${hh}:${mm}:${ss}` : `${mm}:${ss}`;
2049
+ return { display, expired: seconds <= 0 };
2050
+ }
2051
+ function TimeBox({ value }) {
2052
+ return /* @__PURE__ */ jsx42(XStack29, { backgroundColor: "rgba(0,0,0,0.15)", paddingHorizontal: "$2", paddingVertical: "$1", borderRadius: "$3", children: /* @__PURE__ */ jsx42(SizableText36, { size: "$6", fontWeight: "800", color: "white", fontFamily: "$mono", children: value }) });
2053
+ }
2054
+ function CountdownBanner({ endTime, minutes, label = "Offer ends in", onExpire, variant = "banner" }) {
2055
+ const { display, expired } = useCountdown2(endTime, minutes, onExpire);
2056
+ if (expired) return null;
2057
+ const parts = display.split(":");
2058
+ if (variant === "badge") {
2059
+ return /* @__PURE__ */ jsxs33(XStack29, { backgroundColor: "$red9", paddingHorizontal: "$2.5", paddingVertical: "$1", borderRadius: "$10", gap: "$1.5", alignItems: "center", children: [
2060
+ /* @__PURE__ */ jsx42(SizableText36, { size: "$1", fontWeight: "600", color: "white", children: label }),
2061
+ /* @__PURE__ */ jsx42(SizableText36, { size: "$2", fontWeight: "800", color: "white", fontFamily: "$mono", children: display })
2062
+ ] });
2063
+ }
2064
+ if (variant === "compact") {
2065
+ return /* @__PURE__ */ jsxs33(XStack29, { backgroundColor: "$red3", paddingHorizontal: "$3", paddingVertical: "$2", borderRadius: "$4", gap: "$2", alignItems: "center", alignSelf: "center", children: [
2066
+ /* @__PURE__ */ jsx42(SizableText36, { size: "$3", fontWeight: "600", color: "$red9", children: label }),
2067
+ /* @__PURE__ */ jsx42(SizableText36, { size: "$5", fontWeight: "800", color: "$red9", fontFamily: "$mono", children: display })
2068
+ ] });
2069
+ }
2070
+ return /* @__PURE__ */ jsxs33(YStack34, { backgroundColor: "$red9", paddingVertical: "$3", paddingHorizontal: "$4", gap: "$1.5", alignItems: "center", children: [
2071
+ /* @__PURE__ */ jsx42(SizableText36, { size: "$3", fontWeight: "600", color: "white", opacity: 0.9, children: label }),
2072
+ /* @__PURE__ */ jsx42(XStack29, { gap: "$1.5", alignItems: "center", children: parts.map((p, i) => /* @__PURE__ */ jsxs33(XStack29, { gap: "$1.5", alignItems: "center", children: [
2073
+ i > 0 && /* @__PURE__ */ jsx42(SizableText36, { size: "$6", fontWeight: "800", color: "white", children: ":" }),
2074
+ /* @__PURE__ */ jsx42(TimeBox, { value: p })
2075
+ ] }, i)) })
2076
+ ] });
2077
+ }
2078
+
2079
+ // src/patterns/TestimonialCard.tsx
2080
+ import { Image as Image7, SizableText as SizableText37, XStack as XStack30, YStack as YStack35 } from "tamagui";
2081
+ import { jsx as jsx43, jsxs as jsxs34 } from "react/jsx-runtime";
2082
+ function Stars2({ count = 0 }) {
2083
+ if (!count) return null;
2084
+ return /* @__PURE__ */ jsx43(XStack30, { gap: "$0.5", children: Array.from({ length: 5 }, (_, i) => /* @__PURE__ */ jsx43(SizableText37, { size: "$3", color: i < Math.round(count) ? "$yellow9" : "$color5", children: "\u2605" }, i)) });
2085
+ }
2086
+ function AuthorRow({ author, role, avatar }) {
2087
+ return /* @__PURE__ */ jsxs34(XStack30, { gap: "$2.5", alignItems: "center", children: [
2088
+ avatar && /* @__PURE__ */ jsx43(Image7, { source: { uri: avatar }, width: 36, height: 36, borderRadius: 18, objectFit: "cover" }),
2089
+ /* @__PURE__ */ jsxs34(YStack35, { children: [
2090
+ /* @__PURE__ */ jsx43(SizableText37, { size: "$3", fontWeight: "600", children: author }),
2091
+ role && /* @__PURE__ */ jsx43(SizableText37, { size: "$2", color: "$color9", children: role })
2092
+ ] })
2093
+ ] });
2094
+ }
2095
+ function TestimonialCard({ quote, author, role, avatar, rating, variant = "card" }) {
2096
+ if (variant === "minimal") {
2097
+ return /* @__PURE__ */ jsxs34(YStack35, { gap: "$3", paddingVertical: "$2", children: [
2098
+ /* @__PURE__ */ jsx43(Stars2, { count: rating }),
2099
+ /* @__PURE__ */ jsxs34(SizableText37, { size: "$4", color: "$color11", fontStyle: "italic", lineHeight: 24, children: [
2100
+ '"',
2101
+ quote,
2102
+ '"'
2103
+ ] }),
2104
+ /* @__PURE__ */ jsx43(AuthorRow, { author, role, avatar })
2105
+ ] });
2106
+ }
2107
+ if (variant === "featured") {
2108
+ return /* @__PURE__ */ jsxs34(YStack35, { backgroundColor: "$color3", padding: "$5", borderRadius: "$6", gap: "$4", alignItems: "center", children: [
2109
+ /* @__PURE__ */ jsx43(SizableText37, { size: "$8", color: "$color9", opacity: 0.3, fontWeight: "800", children: '"' }),
2110
+ /* @__PURE__ */ jsx43(Stars2, { count: rating }),
2111
+ /* @__PURE__ */ jsxs34(SizableText37, { size: "$5", color: "$color12", fontStyle: "italic", textAlign: "center", lineHeight: 28, children: [
2112
+ '"',
2113
+ quote,
2114
+ '"'
2115
+ ] }),
2116
+ /* @__PURE__ */ jsx43(AuthorRow, { author, role, avatar })
2117
+ ] });
2118
+ }
2119
+ return /* @__PURE__ */ jsxs34(
2120
+ YStack35,
2121
+ {
2122
+ backgroundColor: "$color1",
2123
+ padding: "$4",
2124
+ borderRadius: "$5",
2125
+ borderWidth: 1,
2126
+ borderColor: "$color4",
2127
+ gap: "$3",
2128
+ children: [
2129
+ /* @__PURE__ */ jsx43(Stars2, { count: rating }),
2130
+ /* @__PURE__ */ jsxs34(SizableText37, { size: "$4", color: "$color11", fontStyle: "italic", lineHeight: 24, children: [
2131
+ '"',
2132
+ quote,
2133
+ '"'
2134
+ ] }),
2135
+ /* @__PURE__ */ jsx43(AuthorRow, { author, role, avatar })
2136
+ ]
2137
+ }
2138
+ );
2139
+ }
2140
+
2141
+ // src/patterns/ConfirmDialog.tsx
2142
+ import { AlertDialog as AlertDialog2, Button as Button10, SizableText as SizableText38, XStack as XStack31, YStack as YStack36 } from "tamagui";
2143
+ import { jsx as jsx44, jsxs as jsxs35 } from "react/jsx-runtime";
2144
+ function ConfirmDialog({
2145
+ open,
2146
+ onOpenChange,
2147
+ title,
2148
+ description,
2149
+ confirmLabel = "Confirm",
2150
+ cancelLabel = "Cancel",
2151
+ onConfirm,
2152
+ onCancel,
2153
+ destructive = false,
2154
+ icon
2155
+ }) {
2156
+ const handleCancel = () => {
2157
+ onCancel?.();
2158
+ onOpenChange(false);
2159
+ };
2160
+ const handleConfirm = () => {
2161
+ onConfirm?.();
2162
+ onOpenChange(false);
2163
+ };
2164
+ return /* @__PURE__ */ jsx44(AlertDialog2, { open, onOpenChange, children: /* @__PURE__ */ jsxs35(AlertDialog2.Portal, { children: [
2165
+ /* @__PURE__ */ jsx44(
2166
+ AlertDialog2.Overlay,
2167
+ {
2168
+ opacity: 0.5,
2169
+ enterStyle: { opacity: 0 },
2170
+ exitStyle: { opacity: 0 },
2171
+ animation: "quick"
2172
+ },
2173
+ "overlay"
2174
+ ),
2175
+ /* @__PURE__ */ jsx44(
2176
+ AlertDialog2.Content,
2177
+ {
2178
+ bordered: true,
2179
+ elevate: true,
2180
+ width: "90%",
2181
+ maxWidth: 400,
2182
+ enterStyle: { y: -20, opacity: 0, scale: 0.9 },
2183
+ exitStyle: { y: 10, opacity: 0, scale: 0.95 },
2184
+ x: 0,
2185
+ y: 0,
2186
+ scale: 1,
2187
+ opacity: 1,
2188
+ animation: "quick",
2189
+ children: /* @__PURE__ */ jsxs35(YStack36, { gap: "$4", padding: "$4", children: [
2190
+ icon && /* @__PURE__ */ jsx44(YStack36, { alignItems: "center", children: icon }),
2191
+ /* @__PURE__ */ jsxs35(YStack36, { gap: "$2", alignItems: icon ? "center" : "flex-start", children: [
2192
+ /* @__PURE__ */ jsx44(AlertDialog2.Title, { size: "$6", fontWeight: "700", children: title }),
2193
+ description && /* @__PURE__ */ jsx44(
2194
+ AlertDialog2.Description,
2195
+ {
2196
+ size: "$3",
2197
+ color: "$color10",
2198
+ textAlign: icon ? "center" : "left",
2199
+ children: description
2200
+ }
2201
+ )
2202
+ ] }),
2203
+ /* @__PURE__ */ jsxs35(XStack31, { gap: "$3", justifyContent: "flex-end", children: [
2204
+ /* @__PURE__ */ jsx44(
2205
+ Button10,
2206
+ {
2207
+ flex: 1,
2208
+ size: "$4",
2209
+ borderRadius: "$4",
2210
+ variant: "outlined",
2211
+ borderColor: "$color7",
2212
+ onPress: handleCancel,
2213
+ pressStyle: { opacity: 0.7 },
2214
+ animation: "quick",
2215
+ children: /* @__PURE__ */ jsx44(SizableText38, { fontWeight: "600", children: cancelLabel })
2216
+ }
2217
+ ),
2218
+ /* @__PURE__ */ jsx44(
2219
+ Button10,
2220
+ {
2221
+ flex: 1,
2222
+ size: "$4",
2223
+ borderRadius: "$4",
2224
+ backgroundColor: destructive ? "$red9" : "$color9",
2225
+ onPress: handleConfirm,
2226
+ pressStyle: { backgroundColor: destructive ? "$red8" : "$color8", scale: 0.97 },
2227
+ animation: "quick",
2228
+ children: /* @__PURE__ */ jsx44(SizableText38, { fontWeight: "600", color: "white", children: confirmLabel })
2229
+ }
2230
+ )
2231
+ ] })
2232
+ ] })
2233
+ },
2234
+ "content"
2235
+ )
2236
+ ] }) });
2237
+ }
2238
+
2239
+ // src/patterns/Chip.tsx
2240
+ import { useCallback as useCallback3 } from "react";
2241
+ import { SizableText as SizableText39, XStack as XStack32 } from "tamagui";
2242
+ import { jsx as jsx45, jsxs as jsxs36 } from "react/jsx-runtime";
2243
+ var sizes2 = { sm: { h: 28, px: "$2", text: "$2" }, md: { h: 34, px: "$3", text: "$3" }, lg: { h: 42, px: "$4", text: "$4" } };
2244
+ function Chip({ label, selected, onPress, onRemove, variant = "filled", size = "md", icon, color }) {
2245
+ const s = sizes2[size];
2246
+ const filled = variant === "filled";
2247
+ const active = selected ?? false;
2248
+ const bg = active ? color ?? "$color9" : filled ? "$color3" : "transparent";
2249
+ const border = active ? color ?? "$color9" : "$color6";
2250
+ const fg = active ? "$color1" : "$color11";
2251
+ return /* @__PURE__ */ jsxs36(
2252
+ XStack32,
2253
+ {
2254
+ height: s.h,
2255
+ borderRadius: "$10",
2256
+ paddingHorizontal: s.px,
2257
+ backgroundColor: bg,
2258
+ borderWidth: filled ? 0 : 1,
2259
+ borderColor: border,
2260
+ alignItems: "center",
2261
+ gap: "$1.5",
2262
+ pressStyle: { scale: 0.96, opacity: 0.85 },
2263
+ animation: "quick",
2264
+ onPress,
2265
+ cursor: "pointer",
2266
+ children: [
2267
+ active && /* @__PURE__ */ jsx45(SizableText39, { size: s.text, color: fg, children: "\u2713" }),
2268
+ icon && /* @__PURE__ */ jsx45(SizableText39, { color: fg, children: icon }),
2269
+ /* @__PURE__ */ jsx45(SizableText39, { size: s.text, color: fg, fontWeight: "500", children: label }),
2270
+ onRemove && /* @__PURE__ */ jsx45(
2271
+ SizableText39,
2272
+ {
2273
+ size: "$2",
2274
+ color: fg,
2275
+ opacity: 0.7,
2276
+ pressStyle: { opacity: 1 },
2277
+ onPress: (e) => {
2278
+ e.stopPropagation?.();
2279
+ onRemove();
2280
+ },
2281
+ marginLeft: "$1",
2282
+ children: "\u2715"
2283
+ }
2284
+ )
2285
+ ]
2286
+ }
2287
+ );
2288
+ }
2289
+ function ChipGroup({ chips, selected = [], onSelectionChange, multiSelect = true, variant, size }) {
2290
+ const toggle = useCallback3((id) => {
2291
+ if (!onSelectionChange) return;
2292
+ const isSelected = selected.includes(id);
2293
+ if (multiSelect) {
2294
+ onSelectionChange(isSelected ? selected.filter((s) => s !== id) : [...selected, id]);
2295
+ } else {
2296
+ onSelectionChange(isSelected ? [] : [id]);
2297
+ }
2298
+ }, [selected, onSelectionChange, multiSelect]);
2299
+ return /* @__PURE__ */ jsx45(XStack32, { flexWrap: "wrap", gap: "$2", children: chips.map((chip) => /* @__PURE__ */ jsx45(
2300
+ Chip,
2301
+ {
2302
+ label: chip.label,
2303
+ icon: chip.icon,
2304
+ selected: selected.includes(chip.id),
2305
+ onPress: () => toggle(chip.id),
2306
+ variant,
2307
+ size
2308
+ },
2309
+ chip.id
2310
+ )) });
2311
+ }
2312
+
2313
+ // src/patterns/OTPInput.tsx
2314
+ import { useCallback as useCallback4, useRef as useRef2, useState as useState11 } from "react";
2315
+ import { Platform } from "react-native";
2316
+ import { Input as Input3, SizableText as SizableText40, XStack as XStack33, YStack as YStack37 } from "tamagui";
2317
+ import { jsx as jsx46, jsxs as jsxs37 } from "react/jsx-runtime";
2318
+ function OTPInput({ length = 6, value = "", onChange, onComplete, error, autoFocus, secureEntry }) {
2319
+ const inputRef = useRef2(null);
2320
+ const [focused, setFocused] = useState11(false);
2321
+ const digits = value.padEnd(length, " ").slice(0, length);
2322
+ const handleChange = useCallback4((text) => {
2323
+ const cleaned = text.replace(/\D/g, "").slice(0, length);
2324
+ onChange?.(cleaned);
2325
+ if (cleaned.length === length) onComplete?.(cleaned);
2326
+ }, [length, onChange, onComplete]);
2327
+ const focusInput = useCallback4(() => {
2328
+ inputRef.current?.focus();
2329
+ }, []);
2330
+ return /* @__PURE__ */ jsxs37(YStack37, { position: "relative", children: [
2331
+ /* @__PURE__ */ jsx46(XStack33, { gap: "$2", justifyContent: "center", children: Array.from({ length }, (_, i) => {
2332
+ const char = digits[i]?.trim();
2333
+ const isCursor = focused && value.length === i;
2334
+ return /* @__PURE__ */ jsxs37(
2335
+ YStack37,
2336
+ {
2337
+ width: 48,
2338
+ height: 56,
2339
+ borderRadius: "$3",
2340
+ borderWidth: 2,
2341
+ borderColor: error ? "$red9" : isCursor ? "$color9" : char ? "$color7" : "$color5",
2342
+ backgroundColor: error ? "$red2" : isCursor ? "$color2" : "$color1",
2343
+ alignItems: "center",
2344
+ justifyContent: "center",
2345
+ animation: "quick",
2346
+ pointerEvents: "none",
2347
+ children: [
2348
+ /* @__PURE__ */ jsx46(SizableText40, { size: "$7", fontWeight: "600", color: "$color12", children: char ? secureEntry ? "\u25CF" : char : "" }),
2349
+ isCursor && /* @__PURE__ */ jsx46(
2350
+ YStack37,
2351
+ {
2352
+ position: "absolute",
2353
+ bottom: 10,
2354
+ width: 20,
2355
+ height: 2,
2356
+ backgroundColor: "$color9",
2357
+ animation: "quick"
2358
+ }
2359
+ )
2360
+ ]
2361
+ },
2362
+ i
2363
+ );
2364
+ }) }),
2365
+ Platform.OS === "web" ? /* @__PURE__ */ jsx46(
2366
+ "input",
2367
+ {
2368
+ ref: inputRef,
2369
+ type: "text",
2370
+ inputMode: "numeric",
2371
+ pattern: "[0-9]*",
2372
+ autoComplete: "one-time-code",
2373
+ maxLength: length,
2374
+ value,
2375
+ autoFocus,
2376
+ onChange: (e) => handleChange(e.target.value),
2377
+ onFocus: () => setFocused(true),
2378
+ onBlur: () => setFocused(false),
2379
+ style: {
2380
+ position: "absolute",
2381
+ top: 0,
2382
+ left: 0,
2383
+ right: 0,
2384
+ bottom: 0,
2385
+ width: "100%",
2386
+ height: "100%",
2387
+ opacity: 0,
2388
+ fontSize: 16,
2389
+ caretColor: "transparent",
2390
+ cursor: "pointer"
2391
+ }
2392
+ }
2393
+ ) : /* @__PURE__ */ jsx46(
2394
+ Input3,
2395
+ {
2396
+ ref: inputRef,
2397
+ value,
2398
+ onChangeText: handleChange,
2399
+ keyboardType: "number-pad",
2400
+ maxLength: length,
2401
+ autoFocus,
2402
+ onFocus: () => setFocused(true),
2403
+ onBlur: () => setFocused(false),
2404
+ position: "absolute",
2405
+ top: 0,
2406
+ left: 0,
2407
+ right: 0,
2408
+ bottom: 0,
2409
+ opacity: 0,
2410
+ fontSize: 16
2411
+ }
2412
+ )
2413
+ ] });
2414
+ }
2415
+
2416
+ // src/patterns/PasswordInput.tsx
2417
+ import { useState as useState12, useCallback as useCallback5 } from "react";
2418
+ import { Input as Input4, SizableText as SizableText41, XStack as XStack34, YStack as YStack38 } from "tamagui";
2419
+ import { jsx as jsx47, jsxs as jsxs38 } from "react/jsx-runtime";
2420
+ function getStrength(pw) {
2421
+ if (!pw) return { label: "", color: "$color6", width: "0%" };
2422
+ const score = [pw.length >= 8, /[A-Z]/.test(pw), /[0-9]/.test(pw), /[^A-Za-z0-9]/.test(pw)].filter(Boolean).length;
2423
+ if (score <= 1) return { label: "Weak", color: "$red9", width: "33%" };
2424
+ if (score <= 2) return { label: "Medium", color: "$yellow9", width: "66%" };
2425
+ return { label: "Strong", color: "$green9", width: "100%" };
2426
+ }
2427
+ function PasswordInput({ value = "", onChangeText, placeholder = "Password", label, error, size = "$4", strengthIndicator }) {
2428
+ const [visible, setVisible] = useState12(false);
2429
+ const toggle = useCallback5(() => setVisible((v) => !v), []);
2430
+ const strength = getStrength(value);
2431
+ return /* @__PURE__ */ jsxs38(YStack38, { gap: "$1.5", children: [
2432
+ label && /* @__PURE__ */ jsx47(SizableText41, { size: "$3", color: "$color11", fontWeight: "500", children: label }),
2433
+ /* @__PURE__ */ jsxs38(
2434
+ XStack34,
2435
+ {
2436
+ borderWidth: 1,
2437
+ borderColor: error ? "$red9" : "$color6",
2438
+ borderRadius: "$3",
2439
+ backgroundColor: "$color2",
2440
+ alignItems: "center",
2441
+ paddingRight: "$2",
2442
+ focusStyle: { borderColor: "$color9" },
2443
+ children: [
2444
+ /* @__PURE__ */ jsx47(
2445
+ Input4,
2446
+ {
2447
+ flex: 1,
2448
+ size,
2449
+ value,
2450
+ onChangeText,
2451
+ placeholder,
2452
+ placeholderTextColor: "$color8",
2453
+ secureTextEntry: !visible,
2454
+ backgroundColor: "transparent",
2455
+ borderWidth: 0
2456
+ }
2457
+ ),
2458
+ /* @__PURE__ */ jsx47(
2459
+ SizableText41,
2460
+ {
2461
+ size: "$4",
2462
+ color: "$color8",
2463
+ paddingHorizontal: "$2",
2464
+ pressStyle: { opacity: 0.6 },
2465
+ onPress: toggle,
2466
+ cursor: "pointer",
2467
+ children: visible ? "\u25C9" : "\u25CE"
2468
+ }
2469
+ )
2470
+ ]
2471
+ }
2472
+ ),
2473
+ strengthIndicator && value.length > 0 && /* @__PURE__ */ jsxs38(YStack38, { gap: "$1", children: [
2474
+ /* @__PURE__ */ jsx47(YStack38, { height: 3, backgroundColor: "$color4", borderRadius: 2, overflow: "hidden", children: /* @__PURE__ */ jsx47(YStack38, { height: 3, width: strength.width, backgroundColor: strength.color, borderRadius: 2, animation: "quick" }) }),
2475
+ /* @__PURE__ */ jsx47(SizableText41, { size: "$1", color: strength.color, children: strength.label })
2476
+ ] }),
2477
+ error && /* @__PURE__ */ jsx47(SizableText41, { size: "$2", color: "$red9", children: error })
2478
+ ] });
2479
+ }
2480
+
2481
+ // src/patterns/AvatarGroup.tsx
2482
+ import { Circle as Circle7, Image as Image8, SizableText as SizableText42, XStack as XStack35 } from "tamagui";
2483
+ import { jsx as jsx48, jsxs as jsxs39 } from "react/jsx-runtime";
2484
+ function getInitials(name) {
2485
+ if (!name) return "?";
2486
+ return name.split(" ").map((p) => p[0]).join("").toUpperCase().slice(0, 2);
2487
+ }
2488
+ function AvatarItem({ uri, name, color, size }) {
2489
+ return /* @__PURE__ */ jsx48(
2490
+ Circle7,
2491
+ {
2492
+ size,
2493
+ backgroundColor: color ?? "$color4",
2494
+ borderWidth: 2,
2495
+ borderColor: "$background",
2496
+ overflow: "hidden",
2497
+ alignItems: "center",
2498
+ justifyContent: "center",
2499
+ children: uri ? /* @__PURE__ */ jsx48(Image8, { source: { uri }, width: size, height: size, objectFit: "cover" }) : /* @__PURE__ */ jsx48(SizableText42, { size: "$2", fontWeight: "600", color: color ? "$color1" : "$color11", children: getInitials(name) })
2500
+ }
2501
+ );
2502
+ }
2503
+ function AvatarGroup({ avatars, max = 4, size = 36, overlap = 10 }) {
2504
+ const visible = avatars.slice(0, max);
2505
+ const remaining = avatars.length - max;
2506
+ return /* @__PURE__ */ jsxs39(XStack35, { alignItems: "center", children: [
2507
+ visible.map((avatar, i) => /* @__PURE__ */ jsx48(XStack35, { marginLeft: i === 0 ? 0 : -overlap, zIndex: visible.length - i, children: /* @__PURE__ */ jsx48(AvatarItem, { ...avatar, size }) }, i)),
2508
+ remaining > 0 && /* @__PURE__ */ jsx48(XStack35, { marginLeft: -overlap, zIndex: 0, children: /* @__PURE__ */ jsx48(
2509
+ Circle7,
2510
+ {
2511
+ size,
2512
+ backgroundColor: "$color6",
2513
+ borderWidth: 2,
2514
+ borderColor: "$background",
2515
+ alignItems: "center",
2516
+ justifyContent: "center",
2517
+ children: /* @__PURE__ */ jsxs39(SizableText42, { size: "$2", fontWeight: "600", color: "$color11", children: [
2518
+ "+",
2519
+ remaining
2520
+ ] })
2521
+ }
2522
+ ) })
2523
+ ] });
2524
+ }
2525
+
2526
+ // src/patterns/SwipeCards.tsx
2527
+ import { useState as useState13, useCallback as useCallback6 } from "react";
2528
+ import { Circle as Circle8, SizableText as SizableText43, XStack as XStack36, YStack as YStack39 } from "tamagui";
2529
+ import { jsx as jsx49, jsxs as jsxs40 } from "react/jsx-runtime";
2530
+ var STACK_SIZE = 3;
2531
+ var CARD_OFFSETS = [
2532
+ { scale: 1, y: 0, opacity: 1 },
2533
+ { scale: 0.95, y: 8, opacity: 0.9 },
2534
+ { scale: 0.9, y: 16, opacity: 0.8 }
2535
+ ];
2536
+ function SwipeCards({
2537
+ items,
2538
+ renderCard,
2539
+ onSwipeLeft,
2540
+ onSwipeRight,
2541
+ onEmpty,
2542
+ leftLabel = "Nope",
2543
+ rightLabel = "Like",
2544
+ emptyMessage = "No more cards"
2545
+ }) {
2546
+ const [index, setIndex] = useState13(0);
2547
+ const [exitDir, setExitDir] = useState13(null);
2548
+ const remaining = items.slice(index);
2549
+ const isEmpty = remaining.length === 0;
2550
+ const handleSwipe = useCallback6((dir) => {
2551
+ if (isEmpty) return;
2552
+ const current = items[index];
2553
+ setExitDir(dir);
2554
+ const timer = setTimeout(() => {
2555
+ setExitDir(null);
2556
+ setIndex((i) => {
2557
+ const next = i + 1;
2558
+ if (next >= items.length) onEmpty?.();
2559
+ return next;
2560
+ });
2561
+ dir === "left" ? onSwipeLeft?.(current) : onSwipeRight?.(current);
2562
+ }, 250);
2563
+ return () => clearTimeout(timer);
2564
+ }, [isEmpty, index, items, onEmpty, onSwipeLeft, onSwipeRight]);
2565
+ if (isEmpty) {
2566
+ return /* @__PURE__ */ jsx49(YStack39, { flex: 1, alignItems: "center", justifyContent: "center", gap: "$3", padding: "$4", children: /* @__PURE__ */ jsx49(SizableText43, { size: "$5", color: "$color8", children: emptyMessage }) });
2567
+ }
2568
+ return /* @__PURE__ */ jsxs40(YStack39, { flex: 1, gap: "$4", children: [
2569
+ /* @__PURE__ */ jsx49(YStack39, { flex: 1, alignItems: "center", justifyContent: "center", children: /* @__PURE__ */ jsx49(YStack39, { width: "100%", maxWidth: 340, aspectRatio: 3 / 4, position: "relative", children: remaining.slice(0, STACK_SIZE).reverse().map((item, reverseIdx) => {
2570
+ const stackIdx = Math.min(remaining.length, STACK_SIZE) - 1 - reverseIdx;
2571
+ const isTop = stackIdx === 0;
2572
+ const offset = CARD_OFFSETS[stackIdx] ?? CARD_OFFSETS[2];
2573
+ const exitX = exitDir === "left" ? -400 : exitDir === "right" ? 400 : 0;
2574
+ const exitRotate = exitDir === "left" ? "-15deg" : exitDir === "right" ? "15deg" : "0deg";
2575
+ return /* @__PURE__ */ jsxs40(
2576
+ YStack39,
2577
+ {
2578
+ position: "absolute",
2579
+ top: 0,
2580
+ left: 0,
2581
+ right: 0,
2582
+ bottom: 0,
2583
+ animation: "quick",
2584
+ borderRadius: "$5",
2585
+ overflow: "hidden",
2586
+ backgroundColor: "$background",
2587
+ elevate: isTop,
2588
+ shadowColor: "$shadowColor",
2589
+ shadowRadius: isTop ? 16 : 4,
2590
+ scale: isTop && exitDir ? 1 : offset.scale,
2591
+ opacity: isTop && exitDir ? 0 : offset.opacity,
2592
+ y: isTop && exitDir ? 0 : offset.y,
2593
+ x: isTop ? exitX : 0,
2594
+ rotate: isTop ? exitRotate : "0deg",
2595
+ children: [
2596
+ renderCard(item),
2597
+ isTop && exitDir === "left" && /* @__PURE__ */ jsx49(
2598
+ YStack39,
2599
+ {
2600
+ position: "absolute",
2601
+ top: "$4",
2602
+ right: "$4",
2603
+ borderWidth: 3,
2604
+ borderColor: "$red10",
2605
+ borderRadius: "$3",
2606
+ padding: "$2",
2607
+ rotate: "15deg",
2608
+ children: /* @__PURE__ */ jsx49(SizableText43, { size: "$7", fontWeight: "800", color: "$red10", children: leftLabel.toUpperCase() })
2609
+ }
2610
+ ),
2611
+ isTop && exitDir === "right" && /* @__PURE__ */ jsx49(
2612
+ YStack39,
2613
+ {
2614
+ position: "absolute",
2615
+ top: "$4",
2616
+ left: "$4",
2617
+ borderWidth: 3,
2618
+ borderColor: "$green10",
2619
+ borderRadius: "$3",
2620
+ padding: "$2",
2621
+ rotate: "-15deg",
2622
+ children: /* @__PURE__ */ jsx49(SizableText43, { size: "$7", fontWeight: "800", color: "$green10", children: rightLabel.toUpperCase() })
2623
+ }
2624
+ )
2625
+ ]
2626
+ },
2627
+ item.id
2628
+ );
2629
+ }) }) }),
2630
+ /* @__PURE__ */ jsxs40(XStack36, { justifyContent: "center", gap: "$6", paddingBottom: "$4", children: [
2631
+ /* @__PURE__ */ jsx49(
2632
+ Circle8,
2633
+ {
2634
+ size: 60,
2635
+ backgroundColor: "$red3",
2636
+ borderWidth: 2,
2637
+ borderColor: "$red7",
2638
+ pressStyle: { scale: 0.9, backgroundColor: "$red5" },
2639
+ animation: "quick",
2640
+ onPress: () => handleSwipe("left"),
2641
+ alignItems: "center",
2642
+ justifyContent: "center",
2643
+ children: /* @__PURE__ */ jsx49(SizableText43, { size: "$6", color: "$red10", fontWeight: "700", children: "\u2715" })
2644
+ }
2645
+ ),
2646
+ /* @__PURE__ */ jsx49(
2647
+ Circle8,
2648
+ {
2649
+ size: 60,
2650
+ backgroundColor: "$green3",
2651
+ borderWidth: 2,
2652
+ borderColor: "$green7",
2653
+ pressStyle: { scale: 0.9, backgroundColor: "$green5" },
2654
+ animation: "quick",
2655
+ onPress: () => handleSwipe("right"),
2656
+ alignItems: "center",
2657
+ justifyContent: "center",
2658
+ children: /* @__PURE__ */ jsx49(SizableText43, { size: "$6", color: "$green10", fontWeight: "700", children: "\u2665" })
2659
+ }
2660
+ )
2661
+ ] })
2662
+ ] });
2663
+ }
2664
+
2665
+ // src/patterns/GlassCard.tsx
2666
+ import { styled as styled12, YStack as YStack40 } from "tamagui";
2667
+ import { jsx as jsx50 } from "react/jsx-runtime";
2668
+ var BLUR = { light: 8, medium: 16, heavy: 24 };
2669
+ var TINT_BG = {
2670
+ light: "rgba(255,255,255,0.15)",
2671
+ dark: "rgba(0,0,0,0.25)"
2672
+ };
2673
+ var GlassFrame = styled12(YStack40, {
2674
+ borderWidth: 1,
2675
+ borderColor: "rgba(255,255,255,0.2)",
2676
+ overflow: "hidden"
2677
+ });
2678
+ function GlassCard({
2679
+ children,
2680
+ intensity = "medium",
2681
+ tint = "light",
2682
+ borderRadius = "$4",
2683
+ padding = "$4",
2684
+ elevated = false
2685
+ }) {
2686
+ const blur = BLUR[intensity];
2687
+ return /* @__PURE__ */ jsx50(
2688
+ GlassFrame,
2689
+ {
2690
+ borderRadius,
2691
+ padding,
2692
+ backgroundColor: TINT_BG[tint],
2693
+ elevate: elevated,
2694
+ shadowColor: elevated ? "$shadowColor" : void 0,
2695
+ shadowRadius: elevated ? 20 : void 0,
2696
+ shadowOpacity: elevated ? 0.3 : void 0,
2697
+ style: { backdropFilter: `blur(${blur}px)`, WebkitBackdropFilter: `blur(${blur}px)` },
2698
+ children
2699
+ }
2700
+ );
2701
+ }
2702
+
2703
+ // src/patterns/DataTable.tsx
2704
+ import { useMemo, useState as useState14 } from "react";
2705
+ import { SizableText as SizableText44, Separator as Separator5, XStack as XStack37, YStack as YStack41, useMedia, styled as styled13, View as View6 } from "tamagui";
2706
+ import { jsx as jsx51, jsxs as jsxs41 } from "react/jsx-runtime";
2707
+ var TH = styled13(View6, { padding: "$3", justifyContent: "center" });
2708
+ var TD = styled13(View6, { padding: "$3", justifyContent: "center" });
2709
+ function StatusBadge({ status }) {
2710
+ const isActive = status.toLowerCase() === "active";
2711
+ return /* @__PURE__ */ jsxs41(XStack37, { gap: "$2", alignItems: "center", children: [
2712
+ /* @__PURE__ */ jsx51(
2713
+ View6,
2714
+ {
2715
+ width: 8,
2716
+ height: 8,
2717
+ borderRadius: 4,
2718
+ backgroundColor: isActive ? "$green9" : "$orange9"
2719
+ }
2720
+ ),
2721
+ /* @__PURE__ */ jsx51(SizableText44, { size: "$3", color: "$color11", children: status })
2722
+ ] });
2723
+ }
2724
+ function HeaderCell({ col, sort, onSort }) {
2725
+ const active = sort?.key === col.key;
2726
+ const indicator = active ? sort.dir === "asc" ? " \u25B2" : " \u25BC" : "";
2727
+ return /* @__PURE__ */ jsx51(
2728
+ TH,
2729
+ {
2730
+ width: col.width,
2731
+ flexDirection: "row",
2732
+ alignItems: "center",
2733
+ cursor: col.sortable ? "pointer" : void 0,
2734
+ onPress: col.sortable ? onSort : void 0,
2735
+ pressStyle: col.sortable ? { opacity: 0.7 } : void 0,
2736
+ children: /* @__PURE__ */ jsxs41(
2737
+ SizableText44,
2738
+ {
2739
+ size: "$2",
2740
+ fontWeight: "700",
2741
+ color: active ? "$color12" : "$color9",
2742
+ textTransform: "uppercase",
2743
+ letterSpacing: 0.5,
2744
+ children: [
2745
+ col.header,
2746
+ indicator
2747
+ ]
2748
+ }
2749
+ )
2750
+ },
2751
+ col.key
2752
+ );
2753
+ }
2754
+ function TableRow({ row, columns, onPress, odd }) {
2755
+ return /* @__PURE__ */ jsx51(
2756
+ XStack37,
2757
+ {
2758
+ backgroundColor: odd ? "$color2" : "transparent",
2759
+ borderBottomWidth: 0.5,
2760
+ borderColor: "$color4",
2761
+ hoverStyle: { backgroundColor: "$color3" },
2762
+ cursor: onPress ? "pointer" : void 0,
2763
+ onPress: onPress ? () => onPress(row) : void 0,
2764
+ pressStyle: onPress ? { opacity: 0.85 } : void 0,
2765
+ animation: "quick",
2766
+ children: columns.map((col) => /* @__PURE__ */ jsx51(TD, { width: col.width, flex: col.width ? void 0 : 1, children: col.render ? col.render(row[col.key], row) : /* @__PURE__ */ jsx51(SizableText44, { size: "$3", color: "$color11", children: String(row[col.key] ?? "") }) }, col.key))
2767
+ }
2768
+ );
2769
+ }
2770
+ function CardRow({ row, columns, onPress }) {
2771
+ return /* @__PURE__ */ jsx51(
2772
+ YStack41,
2773
+ {
2774
+ backgroundColor: "$color1",
2775
+ borderRadius: "$4",
2776
+ borderWidth: 1,
2777
+ borderColor: "$color4",
2778
+ padding: "$3",
2779
+ gap: "$2",
2780
+ onPress: onPress ? () => onPress(row) : void 0,
2781
+ pressStyle: onPress ? { scale: 0.98, opacity: 0.9 } : void 0,
2782
+ animation: "quick",
2783
+ children: columns.map((col, i) => /* @__PURE__ */ jsxs41(YStack41, { children: [
2784
+ i > 0 && /* @__PURE__ */ jsx51(Separator5, { marginVertical: "$1.5", borderColor: "$color4" }),
2785
+ /* @__PURE__ */ jsxs41(XStack37, { justifyContent: "space-between", alignItems: "center", children: [
2786
+ /* @__PURE__ */ jsx51(SizableText44, { size: "$2", color: "$color9", fontWeight: "600", children: col.header }),
2787
+ col.render ? col.render(row[col.key], row) : /* @__PURE__ */ jsx51(SizableText44, { size: "$3", color: "$color11", children: String(row[col.key] ?? "") })
2788
+ ] })
2789
+ ] }, col.key))
2790
+ }
2791
+ );
2792
+ }
2793
+ function DataTable({ columns, data, onRowPress, emptyMessage = "No data" }) {
2794
+ const [sort, setSort] = useState14(null);
2795
+ const media = useMedia();
2796
+ const isSmall = media.sm;
2797
+ const sorted = useMemo(() => {
2798
+ if (!sort) return data;
2799
+ return [...data].sort((a, b) => {
2800
+ const av = a[sort.key], bv = b[sort.key];
2801
+ const cmp = typeof av === "number" && typeof bv === "number" ? av - bv : String(av ?? "").localeCompare(String(bv ?? ""));
2802
+ return sort.dir === "asc" ? cmp : -cmp;
2803
+ });
2804
+ }, [data, sort]);
2805
+ const toggleSort = (key) => setSort((s) => s?.key === key ? { key, dir: s.dir === "asc" ? "desc" : "asc" } : { key, dir: "asc" });
2806
+ if (!data.length) {
2807
+ return /* @__PURE__ */ jsx51(YStack41, { padding: "$6", alignItems: "center", children: /* @__PURE__ */ jsx51(SizableText44, { size: "$4", color: "$color9", children: emptyMessage }) });
2808
+ }
2809
+ if (isSmall) {
2810
+ return /* @__PURE__ */ jsx51(YStack41, { gap: "$3", children: sorted.map((row, i) => /* @__PURE__ */ jsx51(CardRow, { row, columns, onPress: onRowPress }, i)) });
2811
+ }
2812
+ return /* @__PURE__ */ jsxs41(YStack41, { borderWidth: 1, borderColor: "$color4", borderRadius: "$4", overflow: "hidden", children: [
2813
+ /* @__PURE__ */ jsx51(XStack37, { backgroundColor: "$color1", borderBottomWidth: 1, borderColor: "$color4", children: columns.map((col) => /* @__PURE__ */ jsx51(HeaderCell, { col, sort, onSort: () => toggleSort(col.key) }, col.key)) }),
2814
+ sorted.map((row, i) => /* @__PURE__ */ jsx51(TableRow, { row, columns, onPress: onRowPress, odd: i % 2 === 1 }, i))
2815
+ ] });
2816
+ }
2817
+
2818
+ // src/patterns/DatePicker.tsx
2819
+ import { useCallback as useCallback7, useMemo as useMemo2, useState as useState15 } from "react";
2820
+ import { SizableText as SizableText45, XStack as XStack38, YStack as YStack42 } from "tamagui";
2821
+ import { jsx as jsx52, jsxs as jsxs42 } from "react/jsx-runtime";
2822
+ var MONTH_NAMES = ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"];
2823
+ var DAY_LABELS_SUN = ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa"];
2824
+ var DAY_LABELS_MON = ["Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"];
2825
+ function daysInMonth(year, month) {
2826
+ return new Date(year, month + 1, 0).getDate();
2827
+ }
2828
+ function sameDay(a, b) {
2829
+ return a ? a.getFullYear() === b.getFullYear() && a.getMonth() === b.getMonth() && a.getDate() === b.getDate() : false;
2830
+ }
2831
+ function buildGrid(year, month, startDay) {
2832
+ const total = daysInMonth(year, month);
2833
+ const firstWeekday = new Date(year, month, 1).getDay();
2834
+ const offset = (firstWeekday - startDay + 7) % 7;
2835
+ const prevTotal = daysInMonth(year, month - 1);
2836
+ const cells = [];
2837
+ for (let i = offset - 1; i >= 0; i--)
2838
+ cells.push({ day: prevTotal - i, month: month - 1, year: month === 0 ? year - 1 : year, outside: true });
2839
+ for (let d = 1; d <= total; d++)
2840
+ cells.push({ day: d, month, year, outside: false });
2841
+ while (cells.length < 42)
2842
+ cells.push({ day: cells.length - offset - total + 1, month: month + 1, year: month === 11 ? year + 1 : year, outside: true });
2843
+ return cells;
2844
+ }
2845
+ function NavButton({ label, onPress }) {
2846
+ return /* @__PURE__ */ jsx52(
2847
+ XStack38,
2848
+ {
2849
+ width: 36,
2850
+ height: 36,
2851
+ borderRadius: "$10",
2852
+ alignItems: "center",
2853
+ justifyContent: "center",
2854
+ backgroundColor: "$color3",
2855
+ pressStyle: { scale: 0.92, backgroundColor: "$color5" },
2856
+ animation: "quick",
2857
+ onPress,
2858
+ cursor: "pointer",
2859
+ children: /* @__PURE__ */ jsx52(SizableText45, { size: "$5", color: "$color11", fontWeight: "600", children: label })
2860
+ }
2861
+ );
2862
+ }
2863
+ function DatePicker({ value, onDateChange, minDate, maxDate, startDay = 1 }) {
2864
+ const today = useMemo2(() => /* @__PURE__ */ new Date(), []);
2865
+ const [viewMonth, setViewMonth] = useState15(value?.getMonth() ?? today.getMonth());
2866
+ const [viewYear, setViewYear] = useState15(value?.getFullYear() ?? today.getFullYear());
2867
+ const headers = startDay === 1 ? DAY_LABELS_MON : DAY_LABELS_SUN;
2868
+ const grid = useMemo2(() => buildGrid(viewYear, viewMonth, startDay), [viewYear, viewMonth, startDay]);
2869
+ const navigate = useCallback7((dir) => {
2870
+ setViewMonth((m) => {
2871
+ const next = m + dir;
2872
+ if (next < 0) {
2873
+ setViewYear((y) => y - 1);
2874
+ return 11;
2875
+ }
2876
+ if (next > 11) {
2877
+ setViewYear((y) => y + 1);
2878
+ return 0;
2879
+ }
2880
+ return next;
2881
+ });
2882
+ }, []);
2883
+ const isDisabled = useCallback7((d) => {
2884
+ if (minDate && d < new Date(minDate.getFullYear(), minDate.getMonth(), minDate.getDate())) return true;
2885
+ if (maxDate && d > new Date(maxDate.getFullYear(), maxDate.getMonth(), maxDate.getDate())) return true;
2886
+ return false;
2887
+ }, [minDate, maxDate]);
2888
+ return /* @__PURE__ */ jsxs42(YStack42, { backgroundColor: "$color2", borderRadius: "$4", padding: "$3", gap: "$2", animation: "quick", children: [
2889
+ /* @__PURE__ */ jsxs42(XStack38, { alignItems: "center", justifyContent: "space-between", children: [
2890
+ /* @__PURE__ */ jsx52(NavButton, { label: "\u2039", onPress: () => navigate(-1) }),
2891
+ /* @__PURE__ */ jsxs42(SizableText45, { size: "$4", fontWeight: "700", color: "$color12", children: [
2892
+ MONTH_NAMES[viewMonth],
2893
+ " ",
2894
+ viewYear
2895
+ ] }),
2896
+ /* @__PURE__ */ jsx52(NavButton, { label: "\u203A", onPress: () => navigate(1) })
2897
+ ] }),
2898
+ /* @__PURE__ */ jsx52(XStack38, { children: headers.map((h) => /* @__PURE__ */ jsx52(SizableText45, { size: "$2", color: "$color8", fontWeight: "600", textAlign: "center", flex: 1, children: h }, h)) }),
2899
+ Array.from({ length: Math.ceil(grid.length / 7) }, (_, row) => /* @__PURE__ */ jsx52(XStack38, { children: grid.slice(row * 7, row * 7 + 7).map((cell, i) => {
2900
+ const date = new Date(cell.year, cell.month, cell.day);
2901
+ const selected = sameDay(value, date);
2902
+ const isToday = sameDay(today, date);
2903
+ const disabled = cell.outside || isDisabled(date);
2904
+ return /* @__PURE__ */ jsx52(YStack42, { flex: 1, alignItems: "center", paddingVertical: "$0.5", children: /* @__PURE__ */ jsx52(
2905
+ XStack38,
2906
+ {
2907
+ width: 40,
2908
+ height: 40,
2909
+ borderRadius: "$10",
2910
+ alignItems: "center",
2911
+ justifyContent: "center",
2912
+ backgroundColor: selected ? "$color9" : "transparent",
2913
+ borderWidth: isToday && !selected ? 1.5 : 0,
2914
+ borderColor: "$color9",
2915
+ pressStyle: disabled ? void 0 : { scale: 0.9, backgroundColor: selected ? "$color10" : "$color4" },
2916
+ animation: "quick",
2917
+ opacity: disabled ? 0.35 : 1,
2918
+ cursor: disabled ? "default" : "pointer",
2919
+ onPress: disabled ? void 0 : () => onDateChange?.(date),
2920
+ children: /* @__PURE__ */ jsx52(
2921
+ SizableText45,
2922
+ {
2923
+ size: "$3",
2924
+ fontWeight: selected || isToday ? "700" : "400",
2925
+ color: selected ? "white" : cell.outside ? "$color5" : "$color12",
2926
+ children: cell.day
2927
+ }
2928
+ )
2929
+ }
2930
+ ) }, `${row}-${i}`);
2931
+ }) }, row))
2932
+ ] });
2933
+ }
2934
+
2935
+ // src/patterns/EventCard.tsx
2936
+ import { SizableText as SizableText46, Theme, XStack as XStack39, YStack as YStack43 } from "tamagui";
2937
+ import { jsx as jsx53, jsxs as jsxs43 } from "react/jsx-runtime";
2938
+ var THEME_MAP = {
2939
+ purple: "purple",
2940
+ green: "green",
2941
+ blue: "blue",
2942
+ orange: "orange",
2943
+ red: "red",
2944
+ pink: "pink"
2945
+ };
2946
+ function ParticipantDots({ count, max }) {
2947
+ const dots = Math.min(count, 5);
2948
+ return /* @__PURE__ */ jsxs43(XStack39, { alignItems: "center", gap: "$1.5", children: [
2949
+ /* @__PURE__ */ jsx53(XStack39, { children: Array.from({ length: dots }, (_, i) => /* @__PURE__ */ jsx53(
2950
+ YStack43,
2951
+ {
2952
+ width: 22,
2953
+ height: 22,
2954
+ borderRadius: 11,
2955
+ backgroundColor: "$color7",
2956
+ borderWidth: 2,
2957
+ borderColor: "$color4",
2958
+ marginLeft: i > 0 ? -8 : 0,
2959
+ alignItems: "center",
2960
+ justifyContent: "center",
2961
+ children: /* @__PURE__ */ jsx53(SizableText46, { size: "$1", color: "$color1", fontWeight: "700", children: String.fromCharCode(65 + i) })
2962
+ },
2963
+ i
2964
+ )) }),
2965
+ /* @__PURE__ */ jsxs43(SizableText46, { size: "$2", color: "$color11", fontWeight: "500", children: [
2966
+ count,
2967
+ max ? `/${max}` : ""
2968
+ ] })
2969
+ ] });
2970
+ }
2971
+ function CardInner({ title, subtitle, time, location, label, participants, maxParticipants, onPress, actions }) {
2972
+ return /* @__PURE__ */ jsxs43(
2973
+ YStack43,
2974
+ {
2975
+ backgroundColor: "$color4",
2976
+ borderRadius: "$5",
2977
+ padding: "$4",
2978
+ gap: "$3",
2979
+ borderWidth: 1,
2980
+ borderColor: "$color7",
2981
+ onPress,
2982
+ animation: "quick",
2983
+ pressStyle: onPress ? { scale: 0.97, opacity: 0.9 } : void 0,
2984
+ cursor: onPress ? "pointer" : void 0,
2985
+ children: [
2986
+ /* @__PURE__ */ jsxs43(XStack39, { justifyContent: "space-between", alignItems: "flex-start", children: [
2987
+ /* @__PURE__ */ jsxs43(YStack43, { flex: 1, gap: "$1", children: [
2988
+ /* @__PURE__ */ jsx53(SizableText46, { size: "$6", fontWeight: "700", color: "$color12", children: title }),
2989
+ subtitle && /* @__PURE__ */ jsx53(SizableText46, { size: "$3", color: "$color11", opacity: 0.8, children: subtitle })
2990
+ ] }),
2991
+ time && /* @__PURE__ */ jsx53(YStack43, { backgroundColor: "$color6", paddingHorizontal: "$2.5", paddingVertical: "$1.5", borderRadius: "$3", children: /* @__PURE__ */ jsx53(SizableText46, { size: "$2", fontWeight: "600", color: "$color12", children: time }) })
2992
+ ] }),
2993
+ /* @__PURE__ */ jsxs43(XStack39, { gap: "$4", alignItems: "center", flexWrap: "wrap", children: [
2994
+ location && /* @__PURE__ */ jsxs43(XStack39, { gap: "$1.5", alignItems: "center", children: [
2995
+ /* @__PURE__ */ jsx53(SizableText46, { size: "$3", children: "\u{1F4CD}" }),
2996
+ /* @__PURE__ */ jsx53(SizableText46, { size: "$3", color: "$color11", children: location })
2997
+ ] }),
2998
+ participants !== void 0 && /* @__PURE__ */ jsx53(ParticipantDots, { count: participants, max: maxParticipants })
2999
+ ] }),
3000
+ (label || actions) && /* @__PURE__ */ jsxs43(XStack39, { justifyContent: "space-between", alignItems: "center", children: [
3001
+ label ? /* @__PURE__ */ jsx53(XStack39, { backgroundColor: "$color6", paddingHorizontal: "$2.5", paddingVertical: "$1", borderRadius: "$10", children: /* @__PURE__ */ jsx53(SizableText46, { size: "$2", fontWeight: "600", color: "$color11", children: label }) }) : /* @__PURE__ */ jsx53(YStack43, {}),
3002
+ actions
3003
+ ] })
3004
+ ]
3005
+ }
3006
+ );
3007
+ }
3008
+ function EventCard({ theme = "purple", ...props }) {
3009
+ return /* @__PURE__ */ jsx53(Theme, { name: THEME_MAP[theme], children: /* @__PURE__ */ jsx53(CardInner, { ...props }) });
3010
+ }
3011
+
3012
+ // src/patterns/UserPreferences.tsx
3013
+ import { Separator as Separator6, SizableText as SizableText47, Slider, Switch as Switch2, XStack as XStack40, YStack as YStack44 } from "tamagui";
3014
+ import { jsx as jsx54, jsxs as jsxs44 } from "react/jsx-runtime";
3015
+ function ItemLabel({ title, description, color }) {
3016
+ return /* @__PURE__ */ jsxs44(YStack44, { flex: 1, gap: "$1", children: [
3017
+ /* @__PURE__ */ jsx54(SizableText47, { size: "$4", fontWeight: "500", color: color ?? "$color12", children: title }),
3018
+ description && /* @__PURE__ */ jsx54(SizableText47, { size: "$2", color: "$color9", children: description })
3019
+ ] });
3020
+ }
3021
+ function ToggleRow({ item }) {
3022
+ return /* @__PURE__ */ jsxs44(XStack40, { alignItems: "center", gap: "$3", paddingVertical: "$3", paddingHorizontal: "$4", children: [
3023
+ /* @__PURE__ */ jsx54(ItemLabel, { title: item.title, description: item.description }),
3024
+ /* @__PURE__ */ jsx54(Switch2, { size: "$3", checked: item.value, onCheckedChange: item.onValueChange, children: /* @__PURE__ */ jsx54(Switch2.Thumb, { animation: "quick" }) })
3025
+ ] });
3026
+ }
3027
+ function SelectRow({ item }) {
3028
+ const current = item.options.find((o) => o.value === item.value);
3029
+ return /* @__PURE__ */ jsxs44(
3030
+ XStack40,
3031
+ {
3032
+ alignItems: "center",
3033
+ gap: "$3",
3034
+ paddingVertical: "$3",
3035
+ paddingHorizontal: "$4",
3036
+ pressStyle: { backgroundColor: "$color3" },
3037
+ animation: "quick",
3038
+ cursor: "pointer",
3039
+ onPress: () => {
3040
+ const idx = item.options.findIndex((o) => o.value === item.value);
3041
+ const next = item.options[(idx + 1) % item.options.length];
3042
+ if (next) item.onValueChange(next.value);
3043
+ },
3044
+ children: [
3045
+ /* @__PURE__ */ jsx54(ItemLabel, { title: item.title, description: item.description }),
3046
+ /* @__PURE__ */ jsx54(SizableText47, { size: "$3", color: "$color9", fontWeight: "500", children: current?.label ?? item.value }),
3047
+ /* @__PURE__ */ jsx54(SizableText47, { size: "$4", color: "$color8", children: "\u203A" })
3048
+ ]
3049
+ }
3050
+ );
3051
+ }
3052
+ function SliderRow({ item }) {
3053
+ const min = item.min ?? 0;
3054
+ const max = item.max ?? 100;
3055
+ return /* @__PURE__ */ jsxs44(YStack44, { gap: "$2", paddingVertical: "$3", paddingHorizontal: "$4", children: [
3056
+ /* @__PURE__ */ jsxs44(XStack40, { justifyContent: "space-between", alignItems: "center", children: [
3057
+ /* @__PURE__ */ jsx54(ItemLabel, { title: item.title, description: item.description }),
3058
+ /* @__PURE__ */ jsx54(SizableText47, { size: "$3", fontWeight: "600", color: "$color11", children: item.value })
3059
+ ] }),
3060
+ /* @__PURE__ */ jsxs44(
3061
+ Slider,
3062
+ {
3063
+ value: [item.value],
3064
+ min,
3065
+ max,
3066
+ step: 1,
3067
+ onValueChange: ([v]) => {
3068
+ if (v !== void 0) item.onValueChange(v);
3069
+ },
3070
+ children: [
3071
+ /* @__PURE__ */ jsx54(Slider.Track, { backgroundColor: "$color4", height: 4, children: /* @__PURE__ */ jsx54(Slider.TrackActive, { backgroundColor: "$color9" }) }),
3072
+ /* @__PURE__ */ jsx54(Slider.Thumb, { index: 0, size: "$1.5", backgroundColor: "$color9", borderWidth: 0, circular: true })
3073
+ ]
3074
+ }
3075
+ )
3076
+ ] });
3077
+ }
3078
+ function ActionRow({ item }) {
3079
+ return /* @__PURE__ */ jsxs44(
3080
+ XStack40,
3081
+ {
3082
+ alignItems: "center",
3083
+ gap: "$3",
3084
+ paddingVertical: "$3",
3085
+ paddingHorizontal: "$4",
3086
+ pressStyle: { backgroundColor: "$color3" },
3087
+ animation: "quick",
3088
+ cursor: "pointer",
3089
+ onPress: item.onPress,
3090
+ children: [
3091
+ /* @__PURE__ */ jsx54(
3092
+ ItemLabel,
3093
+ {
3094
+ title: item.title,
3095
+ description: item.description,
3096
+ color: item.destructive ? "$red10" : void 0
3097
+ }
3098
+ ),
3099
+ /* @__PURE__ */ jsx54(SizableText47, { size: "$4", color: "$color8", children: "\u203A" })
3100
+ ]
3101
+ }
3102
+ );
3103
+ }
3104
+ function PreferenceRow({ item }) {
3105
+ switch (item.type) {
3106
+ case "toggle":
3107
+ return /* @__PURE__ */ jsx54(ToggleRow, { item });
3108
+ case "select":
3109
+ return /* @__PURE__ */ jsx54(SelectRow, { item });
3110
+ case "slider":
3111
+ return /* @__PURE__ */ jsx54(SliderRow, { item });
3112
+ case "action":
3113
+ return /* @__PURE__ */ jsx54(ActionRow, { item });
3114
+ }
3115
+ }
3116
+ function UserPreferences({ sections }) {
3117
+ return /* @__PURE__ */ jsx54(YStack44, { gap: "$5", children: sections.map((section, si) => /* @__PURE__ */ jsxs44(YStack44, { gap: "$2", children: [
3118
+ /* @__PURE__ */ jsxs44(YStack44, { paddingHorizontal: "$1", gap: "$0.5", children: [
3119
+ /* @__PURE__ */ jsx54(SizableText47, { size: "$2", fontWeight: "600", color: "$color9", textTransform: "uppercase", children: section.title }),
3120
+ section.description && /* @__PURE__ */ jsx54(SizableText47, { size: "$2", color: "$color8", children: section.description })
3121
+ ] }),
3122
+ /* @__PURE__ */ jsx54(
3123
+ YStack44,
3124
+ {
3125
+ backgroundColor: "$color2",
3126
+ borderRadius: "$4",
3127
+ overflow: "hidden",
3128
+ borderWidth: 1,
3129
+ borderColor: "$color4",
3130
+ children: section.items.map((item, ii) => /* @__PURE__ */ jsxs44(YStack44, { children: [
3131
+ /* @__PURE__ */ jsx54(PreferenceRow, { item }),
3132
+ ii < section.items.length - 1 && /* @__PURE__ */ jsx54(Separator6, { borderColor: "$color4" })
3133
+ ] }, item.id))
3134
+ }
3135
+ )
3136
+ ] }, si)) });
3137
+ }
1763
3138
  export {
1764
3139
  Accordion,
1765
3140
  ActionSheet,
1766
3141
  Adapt,
1767
- AlertDialog2 as AlertDialog,
3142
+ AlertDialog3 as AlertDialog,
1768
3143
  Anchor,
1769
3144
  AnimatePresence,
1770
3145
  AppHeader,
1771
3146
  Article,
1772
3147
  Aside,
1773
3148
  Avatar2 as Avatar,
3149
+ AvatarGroup,
1774
3150
  Badge,
1775
3151
  BlinkAccordion,
1776
3152
  Avatar as BlinkAvatar,
@@ -1784,24 +3160,32 @@ export {
1784
3160
  BlinkToggleGroup,
1785
3161
  BlinkTooltip,
1786
3162
  BottomSheet,
1787
- Button8 as Button,
3163
+ Button11 as Button,
1788
3164
  Card2 as Card,
1789
3165
  Carousel,
1790
3166
  ChatBubble,
1791
3167
  Checkbox,
1792
- Circle8 as Circle,
3168
+ Chip,
3169
+ ChipGroup,
3170
+ Circle9 as Circle,
3171
+ ConfirmDialog,
1793
3172
  Container,
3173
+ CountdownBanner,
3174
+ DataTable,
3175
+ DatePicker,
1794
3176
  Dialog,
1795
3177
  DialogProvider,
1796
3178
  Divider,
1797
3179
  EmptyState,
1798
3180
  EnsureFlexed,
3181
+ EventCard,
1799
3182
  Fieldset,
1800
3183
  FloatingActionButton,
1801
3184
  Footer,
1802
3185
  Form,
1803
3186
  FormField,
1804
3187
  Frame,
3188
+ GlassCard,
1805
3189
  Grid,
1806
3190
  Group,
1807
3191
  H12 as H1,
@@ -1815,7 +3199,7 @@ export {
1815
3199
  ICONS,
1816
3200
  Icon,
1817
3201
  Image2 as Image,
1818
- Input3 as Input,
3202
+ Input5 as Input,
1819
3203
  KeyboardStickyFooter,
1820
3204
  Label,
1821
3205
  ListItem,
@@ -1824,10 +3208,12 @@ export {
1824
3208
  MediaCard,
1825
3209
  Nav,
1826
3210
  NotificationBanner,
3211
+ OTPInput,
1827
3212
  OnboardingCarousel,
1828
3213
  PageContainer,
1829
3214
  PageMainContainer,
1830
3215
  Paragraph,
3216
+ PasswordInput,
1831
3217
  PaywallScreen,
1832
3218
  Popover2 as Popover,
1833
3219
  Portal,
@@ -1835,6 +3221,8 @@ export {
1835
3221
  PortalItem,
1836
3222
  PortalProvider,
1837
3223
  Pressable,
3224
+ PricingTable,
3225
+ ProductCard,
1838
3226
  ProfileHeader,
1839
3227
  Progress,
1840
3228
  ProgressSteps,
@@ -1842,45 +3230,49 @@ export {
1842
3230
  RadioGroup,
1843
3231
  SafeArea,
1844
3232
  ScreenLayout,
1845
- ScrollView5 as ScrollView,
3233
+ ScrollView7 as ScrollView,
1846
3234
  SearchBar,
1847
3235
  Section,
1848
3236
  Select,
1849
3237
  SepHeading,
1850
- Separator5 as Separator,
3238
+ Separator7 as Separator,
1851
3239
  SettingsScreen,
1852
3240
  Sheet3 as Sheet,
1853
3241
  SizableStack,
1854
- SizableText34 as SizableText,
3242
+ SizableText48 as SizableText,
1855
3243
  Skeleton,
1856
- Slider,
3244
+ Slider2 as Slider,
1857
3245
  Spacer,
1858
3246
  Spinner2 as Spinner,
1859
3247
  Square,
1860
3248
  Stack,
3249
+ StatusBadge,
1861
3250
  StepPageLayout,
1862
3251
  SubHeading,
3252
+ SwipeCards,
1863
3253
  SwipeableRow,
1864
- Switch2 as Switch,
3254
+ Switch3 as Switch,
1865
3255
  TabBar,
1866
3256
  Tabs,
1867
- Image6 as TamaguiImage,
3257
+ Image9 as TamaguiImage,
1868
3258
  ListItem2 as TamaguiListItem,
1869
3259
  TamaguiProvider,
3260
+ TestimonialCard,
1870
3261
  Text,
1871
3262
  TextArea,
1872
- Theme,
3263
+ Theme2 as Theme,
1873
3264
  ThemeableStack,
1874
3265
  ToggleGroup,
1875
3266
  Tooltip,
1876
3267
  TooltipSimple,
1877
3268
  Unspaced,
1878
- View6 as View,
3269
+ UserPreferences,
3270
+ View7 as View,
1879
3271
  VisuallyHidden,
1880
3272
  XGroup,
1881
- XStack27 as XStack,
3273
+ XStack41 as XStack,
1882
3274
  YGroup,
1883
- YStack32 as YStack,
3275
+ YStack45 as YStack,
1884
3276
  ZStack,
1885
3277
  addTheme,
1886
3278
  blinkConfig,
@@ -1902,7 +3294,7 @@ export {
1902
3294
  isWeb,
1903
3295
  replaceTheme,
1904
3296
  showError,
1905
- styled12 as styled,
3297
+ styled14 as styled,
1906
3298
  defaultConfig2 as tamaguiDefaultConfig,
1907
3299
  toast,
1908
3300
  updateTheme,
@@ -1916,7 +3308,7 @@ export {
1916
3308
  useForceUpdate,
1917
3309
  useIsPresent,
1918
3310
  useIsomorphicLayoutEffect,
1919
- useMedia,
3311
+ useMedia2 as useMedia,
1920
3312
  usePresence,
1921
3313
  useTheme,
1922
3314
  useThemeName,