@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.d.mts +256 -3
- package/dist/index.d.ts +256 -3
- package/dist/index.js +1577 -168
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +1503 -111
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
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
|
|
11
|
+
View as View7,
|
|
12
12
|
Stack,
|
|
13
13
|
SizableStack,
|
|
14
14
|
ThemeableStack,
|
|
15
15
|
Frame,
|
|
16
|
-
XStack as
|
|
17
|
-
YStack as
|
|
16
|
+
XStack as XStack41,
|
|
17
|
+
YStack as YStack45,
|
|
18
18
|
ZStack,
|
|
19
|
-
ScrollView as
|
|
20
|
-
Circle as
|
|
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
|
|
41
|
+
SizableText as SizableText48,
|
|
42
42
|
Text,
|
|
43
43
|
Label,
|
|
44
|
-
Button as
|
|
45
|
-
Input as
|
|
44
|
+
Button as Button11,
|
|
45
|
+
Input as Input5,
|
|
46
46
|
TextArea,
|
|
47
|
-
Switch as
|
|
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
|
|
57
|
-
Image as
|
|
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
|
|
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
|
|
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 {
|
|
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 = "
|
|
1042
|
-
subtitle
|
|
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
|
-
|
|
1095
|
+
onTerms,
|
|
1096
|
+
onPrivacy,
|
|
1097
|
+
continueLabel = "Continue",
|
|
1098
|
+
reassurance = "Cancel anytime",
|
|
1099
|
+
hero,
|
|
1100
|
+
socialProof,
|
|
1101
|
+
countdownMinutes,
|
|
1102
|
+
badge
|
|
1049
1103
|
}) {
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
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
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
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__ */
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
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
|
-
|
|
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
|
|
1109
|
-
import { Button as Button4, SizableText as SizableText18, XStack as XStack11, YStack as YStack15, Circle as
|
|
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] =
|
|
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(
|
|
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
|
-
|
|
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
|
|
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(
|
|
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
|
|
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(
|
|
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
|
|
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(
|
|
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
|
|
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] =
|
|
1367
|
-
const [password, setPassword] =
|
|
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
|
|
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(
|
|
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
|
|
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] =
|
|
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
|
|
1723
|
-
import { Circle as
|
|
1724
|
-
import { ScrollView as
|
|
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] =
|
|
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
|
-
|
|
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(
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
3163
|
+
Button11 as Button,
|
|
1788
3164
|
Card2 as Card,
|
|
1789
3165
|
Carousel,
|
|
1790
3166
|
ChatBubble,
|
|
1791
3167
|
Checkbox,
|
|
1792
|
-
|
|
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
|
-
|
|
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
|
-
|
|
3233
|
+
ScrollView7 as ScrollView,
|
|
1846
3234
|
SearchBar,
|
|
1847
3235
|
Section,
|
|
1848
3236
|
Select,
|
|
1849
3237
|
SepHeading,
|
|
1850
|
-
|
|
3238
|
+
Separator7 as Separator,
|
|
1851
3239
|
SettingsScreen,
|
|
1852
3240
|
Sheet3 as Sheet,
|
|
1853
3241
|
SizableStack,
|
|
1854
|
-
|
|
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
|
-
|
|
3254
|
+
Switch3 as Switch,
|
|
1865
3255
|
TabBar,
|
|
1866
3256
|
Tabs,
|
|
1867
|
-
|
|
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
|
-
|
|
3269
|
+
UserPreferences,
|
|
3270
|
+
View7 as View,
|
|
1879
3271
|
VisuallyHidden,
|
|
1880
3272
|
XGroup,
|
|
1881
|
-
|
|
3273
|
+
XStack41 as XStack,
|
|
1882
3274
|
YGroup,
|
|
1883
|
-
|
|
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
|
-
|
|
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,
|