@blinkdotnew/mobile-ui 2.0.0-alpha.1 → 2.0.0-alpha.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.mjs CHANGED
@@ -1,347 +1,206 @@
1
1
  // src/config/tamagui.config.ts
2
+ import { defaultConfig } from "@tamagui/config/v5";
2
3
  import { createTamagui } from "tamagui";
3
-
4
- // src/config/tokens.ts
5
- import { createTokens } from "tamagui";
6
- var tokens = createTokens({
7
- color: {
8
- white: "#FFFFFF",
9
- black: "#000000",
10
- transparent: "transparent"
11
- },
12
- space: {
13
- 0: 0,
14
- 0.5: 2,
15
- 1: 4,
16
- 1.5: 6,
17
- 2: 8,
18
- 2.5: 10,
19
- 3: 12,
20
- 3.5: 14,
21
- 4: 16,
22
- 5: 20,
23
- 6: 24,
24
- 7: 28,
25
- 8: 32,
26
- 9: 36,
27
- 10: 40,
28
- 12: 48,
29
- 16: 64,
30
- true: 16,
31
- "-1": -4,
32
- "-2": -8,
33
- "-3": -12,
34
- "-4": -16
35
- },
36
- size: {
37
- 0: 0,
38
- 1: 4,
39
- 2: 8,
40
- 3: 12,
41
- 4: 16,
42
- 5: 20,
43
- 6: 24,
44
- 7: 28,
45
- 8: 32,
46
- 9: 36,
47
- 10: 40,
48
- 11: 44,
49
- 12: 48,
50
- 14: 56,
51
- 16: 64,
52
- 20: 80,
53
- true: 44
54
- },
55
- radius: {
56
- 0: 0,
57
- 1: 2,
58
- 2: 4,
59
- 3: 6,
60
- 4: 8,
61
- 5: 10,
62
- 6: 12,
63
- 7: 16,
64
- 8: 20,
65
- 9: 24,
66
- 10: 9999,
67
- true: 12
68
- },
69
- zIndex: {
70
- 0: 0,
71
- 1: 100,
72
- 2: 200,
73
- 3: 300,
74
- 4: 400,
75
- 5: 500
76
- }
77
- });
78
-
79
- // src/config/themes.ts
80
- var oceanLight = {
81
- background: "#FFFFFF",
82
- backgroundHover: "#F8FAFC",
83
- backgroundPress: "#F1F5F9",
84
- color: "#0F172A",
85
- colorHover: "#1E293B",
86
- colorPress: "#334155",
87
- primary: "#0D9488",
88
- primaryHover: "#0F766E",
89
- primaryPress: "#115E59",
90
- secondary: "#F0F9FF",
91
- secondaryHover: "#E0F2FE",
92
- secondaryPress: "#BAE6FD",
93
- accent: "#2DD4BF",
94
- surface: "#F8FAFC",
95
- surfaceHover: "#F1F5F9",
96
- card: "#FFFFFF",
97
- cardHover: "#F8FAFC",
98
- border: "#E2E8F0",
99
- borderHover: "#CBD5E1",
100
- textPrimary: "#0F172A",
101
- textSecondary: "#475569",
102
- textMuted: "#94A3B8",
103
- textInverse: "#FFFFFF",
104
- error: "#EF4444",
105
- errorHover: "#DC2626",
106
- success: "#10B981",
107
- successHover: "#059669",
108
- warning: "#F59E0B",
109
- warningHover: "#D97706",
110
- highlight: "#0D9488",
111
- overlay: "rgba(0,0,0,0.5)",
112
- shadowColor: "rgba(0,0,0,0.1)"
113
- };
114
- var oceanDark = {
115
- background: "#0F172A",
116
- backgroundHover: "#1E293B",
117
- backgroundPress: "#334155",
118
- color: "#F8FAFC",
119
- colorHover: "#E2E8F0",
120
- colorPress: "#CBD5E1",
121
- primary: "#14B8A6",
122
- primaryHover: "#2DD4BF",
123
- primaryPress: "#0D9488",
124
- secondary: "#1E293B",
125
- secondaryHover: "#334155",
126
- secondaryPress: "#475569",
127
- accent: "#2DD4BF",
128
- surface: "#1E293B",
129
- surfaceHover: "#334155",
130
- card: "#1E293B",
131
- cardHover: "#334155",
132
- border: "#334155",
133
- borderHover: "#475569",
134
- textPrimary: "#F8FAFC",
135
- textSecondary: "#94A3B8",
136
- textMuted: "#64748B",
137
- textInverse: "#0F172A",
138
- error: "#F87171",
139
- errorHover: "#EF4444",
140
- success: "#34D399",
141
- successHover: "#10B981",
142
- warning: "#FBBF24",
143
- warningHover: "#F59E0B",
144
- highlight: "#14B8A6",
145
- overlay: "rgba(0,0,0,0.7)",
146
- shadowColor: "rgba(0,0,0,0.3)"
147
- };
148
- var themes = {
149
- light: oceanLight,
150
- dark: oceanDark
151
- };
152
-
153
- // src/config/fonts.ts
154
- import { createFont } from "tamagui";
155
- var outfitFont = createFont({
156
- family: "Outfit, System",
157
- size: {
158
- 1: 11,
159
- 2: 12,
160
- 3: 13,
161
- 4: 14,
162
- 5: 15,
163
- 6: 16,
164
- 7: 18,
165
- 8: 20,
166
- 9: 22,
167
- 10: 28,
168
- 11: 36,
169
- 12: 48,
170
- true: 15
171
- },
172
- lineHeight: {
173
- 1: 16,
174
- 2: 18,
175
- 3: 20,
176
- 4: 22,
177
- 5: 23,
178
- 6: 24,
179
- 7: 26,
180
- 8: 28,
181
- 9: 30,
182
- 10: 36,
183
- 11: 44,
184
- 12: 56,
185
- true: 23
186
- },
187
- weight: {
188
- 1: "400",
189
- 2: "500",
190
- 3: "600",
191
- 4: "700",
192
- 5: "800",
193
- true: "400"
194
- },
195
- letterSpacing: {
196
- 1: 0,
197
- 2: -0.2,
198
- 3: -0.4,
199
- 4: -0.6,
200
- true: 0
201
- }
202
- });
203
-
204
- // src/config/tamagui.config.ts
205
4
  var blinkConfig = createTamagui({
206
- tokens,
207
- themes,
208
- fonts: {
209
- heading: outfitFont,
210
- body: outfitFont
211
- },
212
- media: {
213
- xs: { maxWidth: 660 },
214
- sm: { maxWidth: 860 },
215
- md: { maxWidth: 980 },
216
- lg: { maxWidth: 1120 },
217
- gtSm: { minWidth: 861 },
218
- short: { maxHeight: 820 }
219
- },
220
- shorthands: {
221
- px: "paddingHorizontal",
222
- py: "paddingVertical",
223
- mx: "marginHorizontal",
224
- my: "marginVertical",
225
- bg: "backgroundColor",
226
- br: "borderRadius",
227
- f: "flex",
228
- w: "width",
229
- h: "height"
230
- }
5
+ ...defaultConfig
231
6
  });
232
7
 
8
+ // src/index.ts
9
+ import { defaultConfig as defaultConfig2 } from "@tamagui/config/v5";
10
+ import {
11
+ View as View6,
12
+ Stack,
13
+ SizableStack,
14
+ ThemeableStack,
15
+ Frame,
16
+ XStack as XStack27,
17
+ YStack as YStack32,
18
+ ZStack,
19
+ ScrollView as ScrollView5,
20
+ Circle as Circle8,
21
+ Square,
22
+ Spacer,
23
+ EnsureFlexed,
24
+ Group,
25
+ XGroup,
26
+ YGroup,
27
+ Header,
28
+ Footer,
29
+ Main,
30
+ Nav,
31
+ Article,
32
+ Aside,
33
+ H1 as H12,
34
+ H2 as H22,
35
+ H3 as H32,
36
+ H4 as H42,
37
+ H5 as H52,
38
+ H6 as H62,
39
+ Heading,
40
+ Paragraph,
41
+ SizableText as SizableText34,
42
+ Text,
43
+ Label,
44
+ Button as Button8,
45
+ Input as Input3,
46
+ TextArea,
47
+ Switch as Switch2,
48
+ Checkbox,
49
+ Slider,
50
+ RadioGroup,
51
+ Select,
52
+ Fieldset,
53
+ Form,
54
+ Card as Card2,
55
+ Avatar as Avatar2,
56
+ Separator as Separator5,
57
+ Image as Image6,
58
+ Progress,
59
+ Spinner as Spinner2,
60
+ ListItem as ListItem2,
61
+ Anchor,
62
+ Sheet as Sheet3,
63
+ Dialog,
64
+ AlertDialog as AlertDialog2,
65
+ Popover as Popover2,
66
+ Tooltip,
67
+ TooltipSimple,
68
+ Portal,
69
+ PortalHost,
70
+ PortalItem,
71
+ PortalProvider,
72
+ Tabs,
73
+ Accordion,
74
+ ToggleGroup,
75
+ AnimatePresence,
76
+ Adapt,
77
+ VisuallyHidden,
78
+ Unspaced,
79
+ Theme,
80
+ TamaguiProvider,
81
+ TamaguiProvider as TamaguiProvider2,
82
+ createTamagui as createTamagui2,
83
+ createFont,
84
+ createMedia,
85
+ createTheme,
86
+ createTokens,
87
+ createVariable,
88
+ createStyledContext,
89
+ addTheme,
90
+ updateTheme,
91
+ replaceTheme,
92
+ styled as styled12,
93
+ withStaticProperties as withStaticProperties2,
94
+ isWeb,
95
+ isClient,
96
+ getConfig,
97
+ getToken,
98
+ getTokens,
99
+ getTokenValue,
100
+ composeRefs,
101
+ composeEventHandlers,
102
+ useTheme,
103
+ useMedia,
104
+ useThemeName,
105
+ useControllableState,
106
+ useEvent,
107
+ useForceUpdate,
108
+ useIsomorphicLayoutEffect,
109
+ useComposedRefs,
110
+ useWindowDimensions,
111
+ useDidFinishSSR,
112
+ useDebounce,
113
+ useDebounceValue,
114
+ usePresence,
115
+ useIsPresent
116
+ } from "tamagui";
117
+
233
118
  // src/primitives/Button.tsx
234
- import { styled, View, Text, withStaticProperties } from "tamagui";
235
- var ButtonFrame = styled(View, {
236
- name: "BlinkButton",
237
- tag: "button",
238
- alignItems: "center",
239
- justifyContent: "center",
240
- flexDirection: "row",
241
- gap: "$2",
119
+ import { Button as TamaguiButton, styled } from "tamagui";
120
+ var Button = styled(TamaguiButton, {
121
+ borderWidth: 0,
242
122
  cursor: "pointer",
243
- pressStyle: { opacity: 0.8, scale: 0.98 },
123
+ focusVisibleStyle: {
124
+ outlineWidth: 2,
125
+ outlineStyle: "solid",
126
+ outlineColor: "$color8"
127
+ },
244
128
  variants: {
245
129
  variant: {
130
+ default: {
131
+ backgroundColor: "$color3",
132
+ hoverStyle: { backgroundColor: "$color4" },
133
+ pressStyle: { backgroundColor: "$color2", opacity: 0.8 }
134
+ },
246
135
  primary: {
247
- backgroundColor: "$primary"
136
+ backgroundColor: "$color9",
137
+ color: "$color1",
138
+ hoverStyle: { backgroundColor: "$color10" },
139
+ pressStyle: { backgroundColor: "$color8", opacity: 0.9 }
248
140
  },
249
- secondary: {
250
- backgroundColor: "$secondary"
141
+ outlined: {
142
+ backgroundColor: "transparent",
143
+ borderWidth: 2,
144
+ borderColor: "$color6",
145
+ hoverStyle: { borderColor: "$color8" },
146
+ pressStyle: { borderColor: "$color4", opacity: 0.8 }
251
147
  },
252
- outline: {
148
+ transparent: {
253
149
  backgroundColor: "transparent",
254
- borderWidth: 1,
255
- borderColor: "$border"
150
+ hoverStyle: { backgroundColor: "$color2" },
151
+ pressStyle: { backgroundColor: "$color1", opacity: 0.8 }
256
152
  },
257
- ghost: {
258
- backgroundColor: "transparent"
153
+ floating: {
154
+ backgroundColor: "$color4",
155
+ shadowColor: "$shadow2",
156
+ shadowRadius: 5,
157
+ shadowOffset: { height: 2, width: 0 },
158
+ hoverStyle: { backgroundColor: "$color5" },
159
+ pressStyle: { backgroundColor: "$color3", opacity: 0.9 }
259
160
  },
260
161
  destructive: {
261
- backgroundColor: "$error"
162
+ backgroundColor: "$red9",
163
+ color: "$color1",
164
+ hoverStyle: { backgroundColor: "$red10" },
165
+ pressStyle: { backgroundColor: "$red8", opacity: 0.9 }
262
166
  }
263
167
  },
264
168
  size: {
265
- sm: {
266
- height: "$8",
267
- paddingHorizontal: "$3",
268
- borderRadius: "$4"
269
- },
270
- md: {
271
- height: "$11",
272
- paddingHorizontal: "$4",
273
- borderRadius: "$6"
274
- },
275
- lg: {
276
- height: "$14",
277
- paddingHorizontal: "$6",
278
- borderRadius: "$7"
279
- }
169
+ sm: { height: "$3", paddingHorizontal: "$3", borderRadius: "$3" },
170
+ md: { height: "$4", paddingHorizontal: "$4", borderRadius: "$4" },
171
+ lg: { height: "$5", paddingHorizontal: "$5", borderRadius: "$5" }
280
172
  },
281
173
  fullWidth: {
282
174
  true: { width: "100%" }
283
- },
284
- disabled: {
285
- true: { opacity: 0.5, pointerEvents: "none" }
286
- }
287
- },
288
- defaultVariants: {
289
- variant: "primary",
290
- size: "md"
291
- }
292
- });
293
- var ButtonText = styled(Text, {
294
- name: "BlinkButtonText",
295
- fontFamily: "$body",
296
- fontWeight: "600",
297
- textAlign: "center",
298
- variants: {
299
- variant: {
300
- primary: { color: "$textInverse" },
301
- secondary: { color: "$textPrimary" },
302
- outline: { color: "$textPrimary" },
303
- ghost: { color: "$textPrimary" },
304
- destructive: { color: "$textInverse" }
305
- },
306
- size: {
307
- sm: { fontSize: "$3" },
308
- md: { fontSize: "$5" },
309
- lg: { fontSize: "$6" }
310
175
  }
311
176
  },
312
177
  defaultVariants: {
313
- variant: "primary",
178
+ variant: "default",
314
179
  size: "md"
315
180
  }
316
181
  });
317
- var Button = withStaticProperties(ButtonFrame, {
318
- Text: ButtonText
319
- });
320
182
 
321
183
  // src/primitives/Text.tsx
322
- import { styled as styled2, Text as Text2 } from "tamagui";
323
- var BlinkText = styled2(Text2, {
184
+ import { SizableText, styled as styled2 } from "tamagui";
185
+ var BlinkText = styled2(SizableText, {
324
186
  name: "BlinkText",
325
- fontFamily: "$body",
326
- color: "$color",
327
187
  variants: {
328
188
  variant: {
329
- display: { fontSize: "$12", fontWeight: "800", letterSpacing: "$4" },
330
- h1: { fontSize: "$10", fontWeight: "700", letterSpacing: "$3" },
331
- h2: { fontSize: "$9", fontWeight: "700", letterSpacing: "$2" },
332
- h3: { fontSize: "$7", fontWeight: "600" },
333
- h4: { fontSize: "$6", fontWeight: "600" },
334
- body: { fontSize: "$5", fontWeight: "400" },
335
- bodySmall: { fontSize: "$4", fontWeight: "400" },
336
- caption: { fontSize: "$3", fontWeight: "400", color: "$textSecondary" },
337
- small: { fontSize: "$2", fontWeight: "400", color: "$textMuted" },
338
- tiny: { fontSize: "$1", fontWeight: "400", color: "$textMuted" }
189
+ display: { size: "$10", fontWeight: "800" },
190
+ h1: { size: "$9", fontWeight: "700" },
191
+ h2: { size: "$8", fontWeight: "700" },
192
+ h3: { size: "$7", fontWeight: "600" },
193
+ h4: { size: "$6", fontWeight: "600" },
194
+ body: { size: "$5", fontWeight: "400" },
195
+ bodySmall: { size: "$4", fontWeight: "400" },
196
+ caption: { size: "$3", fontWeight: "400", color: "$color10" },
197
+ small: { size: "$2", fontWeight: "400", color: "$color9" }
339
198
  },
340
199
  muted: {
341
- true: { color: "$textMuted" }
200
+ true: { color: "$color9" }
342
201
  },
343
202
  secondary: {
344
- true: { color: "$textSecondary" }
203
+ true: { color: "$color10" }
345
204
  },
346
205
  center: {
347
206
  true: { textAlign: "center" }
@@ -356,30 +215,30 @@ var BlinkText = styled2(Text2, {
356
215
  });
357
216
 
358
217
  // src/primitives/Card.tsx
359
- import { styled as styled3, View as View2, withStaticProperties as withStaticProperties2 } from "tamagui";
360
- var CardFrame = styled3(View2, {
218
+ import { styled as styled3, View, withStaticProperties } from "tamagui";
219
+ var CardFrame = styled3(View, {
361
220
  name: "BlinkCard",
362
- backgroundColor: "$card",
221
+ backgroundColor: "$color2",
222
+ borderRadius: "$4",
363
223
  overflow: "hidden",
364
224
  variants: {
365
225
  variant: {
366
226
  flat: {},
367
227
  elevated: {
368
- shadowColor: "$shadowColor",
228
+ shadowColor: "$shadow2",
369
229
  shadowOffset: { width: 0, height: 2 },
370
- shadowOpacity: 0.1,
371
230
  shadowRadius: 8,
372
231
  elevation: 3
373
232
  },
374
233
  outlined: {
375
234
  borderWidth: 1,
376
- borderColor: "$border"
235
+ borderColor: "$color5"
377
236
  }
378
237
  },
379
238
  size: {
380
- sm: { borderRadius: "$4", padding: "$3" },
381
- md: { borderRadius: "$6", padding: "$4" },
382
- lg: { borderRadius: "$7", padding: "$5" }
239
+ sm: { borderRadius: "$3", padding: "$3" },
240
+ md: { borderRadius: "$4", padding: "$4" },
241
+ lg: { borderRadius: "$5", padding: "$5" }
383
242
  },
384
243
  pressable: {
385
244
  true: {
@@ -393,88 +252,71 @@ var CardFrame = styled3(View2, {
393
252
  size: "md"
394
253
  }
395
254
  });
396
- var CardHeader = styled3(View2, {
397
- name: "BlinkCardHeader",
398
- paddingBottom: "$3"
399
- });
400
- var CardContent = styled3(View2, {
401
- name: "BlinkCardContent"
402
- });
403
- var CardFooter = styled3(View2, {
255
+ var CardHeader = styled3(View, { name: "BlinkCardHeader", paddingBottom: "$3" });
256
+ var CardContent = styled3(View, { name: "BlinkCardContent" });
257
+ var CardFooter = styled3(View, {
404
258
  name: "BlinkCardFooter",
405
259
  paddingTop: "$3",
406
260
  flexDirection: "row",
407
261
  alignItems: "center",
408
262
  gap: "$2"
409
263
  });
410
- var Card = withStaticProperties2(CardFrame, {
264
+ var Card = withStaticProperties(CardFrame, {
411
265
  Header: CardHeader,
412
266
  Content: CardContent,
413
267
  Footer: CardFooter
414
268
  });
415
269
 
416
270
  // src/primitives/Input.tsx
417
- import { styled as styled4, View as View3, Text as Text3, Input as TamaguiInput } from "tamagui";
271
+ import { Input as TamaguiInput, styled as styled4, View as View2, SizableText as SizableText2 } from "tamagui";
418
272
  import { jsx, jsxs } from "react/jsx-runtime";
419
- var InputFrame = styled4(View3, {
273
+ var InputFrame = styled4(View2, {
420
274
  name: "BlinkInputFrame",
421
275
  gap: "$1.5"
422
276
  });
423
- var InputLabel = styled4(Text3, {
277
+ var InputLabel = styled4(SizableText2, {
424
278
  name: "BlinkInputLabel",
425
- fontFamily: "$body",
426
- fontSize: "$4",
279
+ size: "$4",
427
280
  fontWeight: "500",
428
- color: "$textSecondary"
281
+ color: "$color11"
429
282
  });
430
283
  var InputField = styled4(TamaguiInput, {
431
284
  name: "BlinkInput",
432
- fontFamily: "$body",
433
- fontSize: "$5",
434
- color: "$color",
435
- backgroundColor: "$background",
436
- borderWidth: 1,
437
- borderColor: "$border",
438
- borderRadius: "$6",
439
- height: "$14",
440
- paddingHorizontal: "$4",
441
- placeholderTextColor: "$textMuted",
442
- focusStyle: {
443
- borderColor: "$primary",
444
- borderWidth: 2
285
+ height: 50,
286
+ size: "$5",
287
+ borderWidth: 0.5,
288
+ borderColor: "$color5",
289
+ borderRadius: "$4",
290
+ backgroundColor: "$color1",
291
+ placeholderTextColor: "$color8",
292
+ focusVisibleStyle: {
293
+ outlineWidth: 3,
294
+ outlineStyle: "solid",
295
+ outlineColor: "$background04",
296
+ outlineOffset: 1,
297
+ borderWidth: 0.5,
298
+ borderColor: "$color7"
445
299
  },
446
300
  variants: {
447
301
  hasError: {
448
302
  true: {
449
- borderColor: "$error",
450
- focusStyle: { borderColor: "$error" }
303
+ borderColor: "$red9",
304
+ focusVisibleStyle: { borderColor: "$red9" }
451
305
  }
452
306
  },
453
307
  variant: {
454
308
  default: {},
455
309
  filled: {
456
- backgroundColor: "$surface",
310
+ backgroundColor: "$color2",
457
311
  borderColor: "transparent",
458
- focusStyle: { borderColor: "$primary" }
312
+ focusVisibleStyle: { borderColor: "$color7" }
459
313
  }
460
314
  }
461
315
  },
462
- defaultVariants: {
463
- variant: "default"
464
- }
465
- });
466
- var InputError = styled4(Text3, {
467
- name: "BlinkInputError",
468
- fontFamily: "$body",
469
- fontSize: "$2",
470
- color: "$error"
471
- });
472
- var InputHint = styled4(Text3, {
473
- name: "BlinkInputHint",
474
- fontFamily: "$body",
475
- fontSize: "$2",
476
- color: "$textMuted"
316
+ defaultVariants: { variant: "default" }
477
317
  });
318
+ var InputError = styled4(SizableText2, { name: "BlinkInputError", size: "$2", color: "$red10" });
319
+ var InputHint = styled4(SizableText2, { name: "BlinkInputHint", size: "$2", color: "$color9" });
478
320
  function Input({ label, error, hint, ...props }) {
479
321
  return /* @__PURE__ */ jsxs(InputFrame, { children: [
480
322
  label && /* @__PURE__ */ jsx(InputLabel, { children: label }),
@@ -485,69 +327,1574 @@ function Input({ label, error, hint, ...props }) {
485
327
  }
486
328
 
487
329
  // src/primitives/Avatar.tsx
488
- import { styled as styled5, View as View4, Text as Text4, Image } from "tamagui";
330
+ import { memo } from "react";
331
+ import { Circle, Image, SizableText as SizableText3 } from "tamagui";
489
332
  import { jsx as jsx2 } from "react/jsx-runtime";
490
- var AvatarFrame = styled5(View4, {
491
- name: "BlinkAvatar",
492
- alignItems: "center",
493
- justifyContent: "center",
494
- overflow: "hidden",
495
- backgroundColor: "$primary",
333
+ var simpleSizes = {
334
+ xs: 24,
335
+ sm: 32,
336
+ md: 40,
337
+ lg: 48,
338
+ xl: 64
339
+ };
340
+ function getSize(size) {
341
+ if (typeof size === "number") return size;
342
+ return simpleSizes[size] ?? 40;
343
+ }
344
+ var Avatar = memo(({ uri, name, size: sizeIn = "md" }) => {
345
+ const size = getSize(sizeIn);
346
+ return /* @__PURE__ */ jsx2(
347
+ Circle,
348
+ {
349
+ size,
350
+ overflow: "hidden",
351
+ backgroundColor: "$color4",
352
+ alignItems: "center",
353
+ justifyContent: "center",
354
+ children: uri ? /* @__PURE__ */ jsx2(
355
+ Image,
356
+ {
357
+ source: { uri },
358
+ width: size,
359
+ height: size,
360
+ objectFit: "cover"
361
+ }
362
+ ) : /* @__PURE__ */ jsx2(
363
+ SizableText3,
364
+ {
365
+ size: "$3",
366
+ fontWeight: "600",
367
+ color: "$color11",
368
+ children: name ? name.split(" ").map((p) => p[0]).join("").toUpperCase().slice(0, 2) : "?"
369
+ }
370
+ )
371
+ }
372
+ );
373
+ });
374
+
375
+ // src/interface/Headings.tsx
376
+ import { Separator, SizableText as SizableText4, XStack, styled as styled5 } from "tamagui";
377
+ import { jsx as jsx3, jsxs as jsxs2 } from "react/jsx-runtime";
378
+ var H1 = styled5(SizableText4, {
379
+ name: "BlinkH1",
380
+ role: "heading",
381
+ fontFamily: "$heading",
382
+ size: "$10",
383
+ fontWeight: "700"
384
+ });
385
+ var H2 = styled5(SizableText4, {
386
+ name: "BlinkH2",
387
+ role: "heading",
388
+ fontFamily: "$heading",
389
+ size: "$9",
390
+ fontWeight: "700"
391
+ });
392
+ var H3 = styled5(SizableText4, {
393
+ name: "BlinkH3",
394
+ role: "heading",
395
+ fontFamily: "$heading",
396
+ size: "$8",
397
+ fontWeight: "600"
398
+ });
399
+ var H4 = styled5(SizableText4, {
400
+ name: "BlinkH4",
401
+ role: "heading",
402
+ fontFamily: "$heading",
403
+ size: "$6",
404
+ fontWeight: "600"
405
+ });
406
+ var H5 = styled5(SizableText4, {
407
+ name: "BlinkH5",
408
+ role: "heading",
409
+ fontFamily: "$heading",
410
+ size: "$5",
411
+ fontWeight: "500"
412
+ });
413
+ var H6 = styled5(SizableText4, {
414
+ name: "BlinkH6",
415
+ role: "heading",
416
+ fontFamily: "$heading",
417
+ size: "$4",
418
+ fontWeight: "500"
419
+ });
420
+ var SubHeading = styled5(SizableText4, {
421
+ name: "BlinkSubHeading",
422
+ size: "$5",
423
+ color: "$color10",
424
+ fontWeight: "300",
425
+ $lg: { size: "$6" }
426
+ });
427
+ function SepHeading({ children }) {
428
+ return /* @__PURE__ */ jsxs2(XStack, { marginTop: "$6", marginBottom: "$4", alignItems: "center", gap: "$6", children: [
429
+ /* @__PURE__ */ jsx3(H3, { size: "$4", color: "$color10", children }),
430
+ /* @__PURE__ */ jsx3(Separator, { opacity: 0.5 })
431
+ ] });
432
+ }
433
+
434
+ // src/interface/PageContainer.tsx
435
+ import { styled as styled6, YStack } from "tamagui";
436
+ var PageContainer = styled6(YStack, {
437
+ name: "BlinkPageContainer",
438
+ position: "relative",
439
+ marginHorizontal: "auto",
440
+ flex: 1,
441
+ flexBasis: "auto",
442
+ paddingHorizontal: "$4",
443
+ width: "100%",
444
+ minWidth: 380,
445
+ $md: { maxWidth: 760 },
446
+ $lg: { maxWidth: 860 },
447
+ $xl: { maxWidth: 1140 }
448
+ });
449
+ var PageMainContainer = styled6(PageContainer, {
450
+ name: "BlinkPageMainContainer",
451
+ role: "main"
452
+ });
453
+
454
+ // src/interface/Dialog.tsx
455
+ import { useState, useEffect } from "react";
456
+ import { AlertDialog, Button as Button2, XStack as XStack2, YStack as YStack2 } from "tamagui";
457
+ import { Fragment, jsx as jsx4, jsxs as jsxs3 } from "react/jsx-runtime";
458
+ var globalShowDialog = null;
459
+ function DialogProvider({ children }) {
460
+ const [state, setState] = useState({
461
+ type: null,
462
+ title: "",
463
+ description: ""
464
+ });
465
+ useEffect(() => {
466
+ globalShowDialog = (newState) => setState({ ...newState, resolve: newState.resolve });
467
+ return () => {
468
+ globalShowDialog = null;
469
+ };
470
+ }, []);
471
+ const handleClose = (confirmed) => {
472
+ if (!state.resolve) return;
473
+ const resolve = state.resolve;
474
+ setState({ type: null, title: "", description: "" });
475
+ resolve(confirmed);
476
+ };
477
+ return /* @__PURE__ */ jsxs3(Fragment, { children: [
478
+ children,
479
+ /* @__PURE__ */ jsx4(
480
+ AlertDialog,
481
+ {
482
+ open: state.type !== null,
483
+ onOpenChange: (open) => {
484
+ if (!open && state.type !== null) handleClose(false);
485
+ },
486
+ children: /* @__PURE__ */ jsxs3(AlertDialog.Portal, { children: [
487
+ /* @__PURE__ */ jsx4(
488
+ AlertDialog.Overlay,
489
+ {
490
+ opacity: 0.5,
491
+ enterStyle: { opacity: 0 },
492
+ exitStyle: { opacity: 0 }
493
+ },
494
+ "overlay"
495
+ ),
496
+ /* @__PURE__ */ jsx4(
497
+ AlertDialog.Content,
498
+ {
499
+ bordered: true,
500
+ elevate: true,
501
+ enterStyle: { x: 0, y: -20, opacity: 0, scale: 0.9 },
502
+ exitStyle: { x: 0, y: 10, opacity: 0, scale: 0.95 },
503
+ x: 0,
504
+ scale: 1,
505
+ opacity: 1,
506
+ y: 0,
507
+ width: "90%",
508
+ maxWidth: 400,
509
+ children: /* @__PURE__ */ jsxs3(YStack2, { gap: "$4", children: [
510
+ /* @__PURE__ */ jsx4(AlertDialog.Title, { size: "$6", children: state.title }),
511
+ /* @__PURE__ */ jsx4(AlertDialog.Description, { size: "$3", color: "$color11", children: state.description }),
512
+ /* @__PURE__ */ jsx4(XStack2, { gap: "$3", justifyContent: "flex-end", children: state.type === "confirm" ? /* @__PURE__ */ jsxs3(Fragment, { children: [
513
+ /* @__PURE__ */ jsx4(Button2, { onPress: () => handleClose(false), children: "Cancel" }),
514
+ /* @__PURE__ */ jsx4(Button2, { theme: "blue", onPress: () => handleClose(true), children: "Confirm" })
515
+ ] }) : /* @__PURE__ */ jsx4(Button2, { theme: "blue", onPress: () => handleClose(false), children: "OK" }) })
516
+ ] })
517
+ },
518
+ "content"
519
+ )
520
+ ] })
521
+ }
522
+ )
523
+ ] });
524
+ }
525
+ var showError = (error, title = "Error") => {
526
+ let description = "An unexpected error occurred";
527
+ if (error instanceof Error) description = error.message;
528
+ else if (typeof error === "string") description = error;
529
+ else if (error && typeof error === "object" && "message" in error)
530
+ description = String(error.message);
531
+ if (globalShowDialog) globalShowDialog({ type: "error", title, description });
532
+ else console.error(`${title}: ${description}`);
533
+ };
534
+ var dialogConfirm = async (props) => {
535
+ const { title = "Confirm", description = "Are you sure?" } = props;
536
+ if (!globalShowDialog) {
537
+ console.error("DialogProvider not mounted");
538
+ return false;
539
+ }
540
+ return new Promise((resolve) => {
541
+ globalShowDialog({ type: "confirm", title, description, resolve });
542
+ });
543
+ };
544
+
545
+ // src/interface/Pressable.tsx
546
+ import { styled as styled7, View as View3 } from "tamagui";
547
+ var Pressable = styled7(View3, {
548
+ name: "BlinkPressable",
549
+ hitSlop: 10,
550
+ pressStyle: { opacity: 0.5 }
551
+ });
552
+
553
+ // src/interface/Image.tsx
554
+ import { styled as styled8, Image as TamaguiImage } from "tamagui";
555
+ var Image2 = styled8(TamaguiImage, {
556
+ name: "BlinkImage"
557
+ });
558
+
559
+ // src/interface/Badge.tsx
560
+ import { styled as styled9, SizableText as SizableText5, View as View4 } from "tamagui";
561
+ import { jsx as jsx5 } from "react/jsx-runtime";
562
+ var BadgeFrame = styled9(View4, {
563
+ name: "BlinkBadge",
564
+ paddingHorizontal: "$2",
565
+ paddingVertical: "$1",
566
+ borderRadius: "$10",
567
+ backgroundColor: "$color3",
568
+ alignSelf: "flex-start",
496
569
  variants: {
497
- size: {
498
- xs: { width: 24, height: 24, borderRadius: 12 },
499
- sm: { width: 32, height: 32, borderRadius: 16 },
500
- md: { width: 40, height: 40, borderRadius: 20 },
501
- lg: { width: 48, height: 48, borderRadius: 24 },
502
- xl: { width: 64, height: 64, borderRadius: 32 },
503
- xxl: { width: 80, height: 80, borderRadius: 40 }
570
+ variant: {
571
+ default: { backgroundColor: "$color3" },
572
+ success: { backgroundColor: "$green3" },
573
+ warning: { backgroundColor: "$yellow3" },
574
+ error: { backgroundColor: "$red3" },
575
+ info: { backgroundColor: "$blue3" }
504
576
  }
505
577
  },
506
- defaultVariants: {
507
- size: "md"
508
- }
578
+ defaultVariants: { variant: "default" }
509
579
  });
510
- var AvatarInitials = styled5(Text4, {
511
- name: "BlinkAvatarInitials",
512
- fontFamily: "$body",
580
+ var BadgeText = styled9(SizableText5, {
581
+ name: "BlinkBadgeText",
582
+ size: "$2",
513
583
  fontWeight: "600",
514
- color: "$textInverse",
584
+ color: "$color11"
585
+ });
586
+ function Badge({ children, variant = "default" }) {
587
+ return /* @__PURE__ */ jsx5(BadgeFrame, { variant, children: /* @__PURE__ */ jsx5(BadgeText, { children }) });
588
+ }
589
+
590
+ // src/interface/Icon.tsx
591
+ import { SizableText as SizableText6 } from "tamagui";
592
+ import { jsx as jsx6 } from "react/jsx-runtime";
593
+ var ICONS = {
594
+ home: "\u2302",
595
+ search: "\u2315",
596
+ back: "\u2039",
597
+ forward: "\u203A",
598
+ close: "\u2715",
599
+ menu: "\u2630",
600
+ more: "\u22EF",
601
+ plus: "+",
602
+ minus: "\u2212",
603
+ check: "\u2713",
604
+ star: "\u2605",
605
+ starOutline: "\u2606",
606
+ heart: "\u2665",
607
+ heartOutline: "\u2661",
608
+ share: "\u2934",
609
+ edit: "\u270E",
610
+ trash: "\u232B",
611
+ copy: "\u2398",
612
+ chat: "\u{1F4AC}",
613
+ mail: "\u2709",
614
+ bell: "\u{1F514}",
615
+ bellOff: "\u{1F515}",
616
+ send: "\u27A4",
617
+ play: "\u25B6",
618
+ pause: "\u23F8",
619
+ camera: "\u{1F4F7}",
620
+ image: "\u{1F5BC}",
621
+ info: "\u2139",
622
+ warning: "\u26A0",
623
+ error: "\u2715",
624
+ success: "\u2713",
625
+ loading: "\u27F3",
626
+ user: "\u{1F464}",
627
+ users: "\u{1F465}",
628
+ settings: "\u2699",
629
+ lock: "\u{1F512}",
630
+ unlock: "\u{1F513}",
631
+ arrowUp: "\u2191",
632
+ arrowDown: "\u2193",
633
+ arrowLeft: "\u2190",
634
+ arrowRight: "\u2192",
635
+ chevronUp: "\u2303",
636
+ chevronDown: "\u2304",
637
+ chevronLeft: "\u2039",
638
+ chevronRight: "\u203A"
639
+ };
640
+ function Icon({ name, size = 20, color = "$color12" }) {
641
+ return /* @__PURE__ */ jsx6(SizableText6, { fontSize: size, lineHeight: size, color, textAlign: "center", width: size, height: size, children: ICONS[name] });
642
+ }
643
+
644
+ // src/interface/BlinkAccordion.tsx
645
+ import { useState as useState2 } from "react";
646
+ import { Separator as Separator2, SizableText as SizableText7, XStack as XStack3, YStack as YStack3 } from "tamagui";
647
+ import { jsx as jsx7, jsxs as jsxs4 } from "react/jsx-runtime";
648
+ function BlinkAccordion({ items, defaultOpen, allowMultiple = false }) {
649
+ const [openIds, setOpenIds] = useState2(defaultOpen ?? []);
650
+ const toggle = (id) => {
651
+ setOpenIds((prev) => {
652
+ if (prev.includes(id)) return prev.filter((i) => i !== id);
653
+ return allowMultiple ? [...prev, id] : [id];
654
+ });
655
+ };
656
+ return /* @__PURE__ */ jsx7(YStack3, { children: items.map((item, index) => {
657
+ const isOpen = openIds.includes(item.id);
658
+ return /* @__PURE__ */ jsxs4(YStack3, { children: [
659
+ index > 0 && /* @__PURE__ */ jsx7(Separator2, { borderColor: "$borderColor" }),
660
+ /* @__PURE__ */ jsxs4(
661
+ XStack3,
662
+ {
663
+ paddingVertical: "$3",
664
+ paddingHorizontal: "$2",
665
+ justifyContent: "space-between",
666
+ alignItems: "center",
667
+ pressStyle: { opacity: 0.7 },
668
+ onPress: () => toggle(item.id),
669
+ cursor: "pointer",
670
+ children: [
671
+ /* @__PURE__ */ jsx7(SizableText7, { size: "$4", fontWeight: "600", children: item.title }),
672
+ /* @__PURE__ */ jsx7(SizableText7, { size: "$3", color: "$color10", children: isOpen ? "\u2303" : "\u2304" })
673
+ ]
674
+ }
675
+ ),
676
+ isOpen && /* @__PURE__ */ jsx7(YStack3, { paddingHorizontal: "$2", paddingBottom: "$3", children: item.content })
677
+ ] }, item.id);
678
+ }) });
679
+ }
680
+
681
+ // src/interface/BlinkTabs.tsx
682
+ import { useState as useState3 } from "react";
683
+ import { ScrollView } from "react-native";
684
+ import { SizableText as SizableText8, XStack as XStack4, YStack as YStack4 } from "tamagui";
685
+ import { jsx as jsx8 } from "react/jsx-runtime";
686
+ function BlinkTabs({ tabs, activeTab, onTabChange, variant = "underline" }) {
687
+ const [internalActive, setInternalActive] = useState3(tabs[0]?.key ?? "");
688
+ const current = activeTab ?? internalActive;
689
+ const handlePress = (key) => {
690
+ if (!activeTab) setInternalActive(key);
691
+ onTabChange?.(key);
692
+ };
693
+ return /* @__PURE__ */ jsx8(YStack4, { children: /* @__PURE__ */ jsx8(ScrollView, { horizontal: true, showsHorizontalScrollIndicator: false, children: /* @__PURE__ */ jsx8(XStack4, { gap: "$2", paddingHorizontal: "$2", paddingBottom: "$2", children: tabs.map((tab) => {
694
+ const isActive = tab.key === current;
695
+ return /* @__PURE__ */ jsx8(
696
+ YStack4,
697
+ {
698
+ paddingVertical: "$2",
699
+ paddingHorizontal: "$3",
700
+ borderRadius: variant === "pill" ? "$4" : "$0",
701
+ backgroundColor: variant === "pill" && isActive ? "$color9" : "transparent",
702
+ borderBottomWidth: variant === "underline" ? 2 : 0,
703
+ borderBottomColor: variant === "underline" && isActive ? "$color9" : "transparent",
704
+ pressStyle: { opacity: 0.7 },
705
+ onPress: () => handlePress(tab.key),
706
+ cursor: "pointer",
707
+ children: /* @__PURE__ */ jsx8(
708
+ SizableText8,
709
+ {
710
+ size: "$3",
711
+ fontWeight: isActive ? "600" : "400",
712
+ color: variant === "pill" && isActive ? "$color1" : isActive ? "$color12" : "$color10",
713
+ children: tab.label
714
+ }
715
+ )
716
+ },
717
+ tab.key
718
+ );
719
+ }) }) }) });
720
+ }
721
+
722
+ // src/interface/BlinkToggleGroup.tsx
723
+ import { SizableText as SizableText9, XStack as XStack5 } from "tamagui";
724
+ import { jsx as jsx9 } from "react/jsx-runtime";
725
+ var sizeMap = { sm: "$2", md: "$3", lg: "$4" };
726
+ function BlinkToggleGroup({ options, value, onValueChange, size = "md" }) {
727
+ const textSize = sizeMap[size];
728
+ return /* @__PURE__ */ jsx9(XStack5, { borderRadius: "$4", overflow: "hidden", backgroundColor: "$color2", children: options.map((option, index) => {
729
+ const isActive = option.value === value;
730
+ return /* @__PURE__ */ jsx9(
731
+ XStack5,
732
+ {
733
+ flex: 1,
734
+ justifyContent: "center",
735
+ alignItems: "center",
736
+ paddingVertical: "$2",
737
+ paddingHorizontal: "$3",
738
+ backgroundColor: isActive ? "$color9" : "$color2",
739
+ borderLeftWidth: index > 0 ? 1 : 0,
740
+ borderLeftColor: isActive ? "$color9" : "$color4",
741
+ pressStyle: { opacity: 0.7 },
742
+ onPress: () => onValueChange(option.value),
743
+ cursor: "pointer",
744
+ children: /* @__PURE__ */ jsx9(SizableText9, { size: textSize, fontWeight: isActive ? "600" : "400", color: isActive ? "$color1" : "$color11", children: option.label })
745
+ },
746
+ option.value
747
+ );
748
+ }) });
749
+ }
750
+
751
+ // src/interface/BlinkToast.tsx
752
+ import { useState as useState4, useCallback, useEffect as useEffect2, createContext, useContext } from "react";
753
+ import { SizableText as SizableText10, XStack as XStack6, YStack as YStack5 } from "tamagui";
754
+ import { jsx as jsx10, jsxs as jsxs5 } from "react/jsx-runtime";
755
+ var ToastContext = createContext(null);
756
+ var variantStyles = {
757
+ default: { bg: "$color3", border: "$color6", icon: "\u2139" },
758
+ success: { bg: "$green2", border: "$green7", icon: "\u2713" },
759
+ error: { bg: "$red2", border: "$red7", icon: "\u2715" },
760
+ warning: { bg: "$yellow2", border: "$yellow7", icon: "!" }
761
+ };
762
+ var globalToastShow = null;
763
+ var toast = (title, options) => {
764
+ const opts = typeof options === "string" ? { variant: options } : options;
765
+ if (globalToastShow) globalToastShow(title, opts);
766
+ else console.warn("BlinkToastProvider not mounted");
767
+ };
768
+ function BlinkToastProvider({ children }) {
769
+ const [toasts, setToasts] = useState4([]);
770
+ const show = useCallback((title, options) => {
771
+ const id = Math.random().toString(36).slice(2, 9);
772
+ const entry = {
773
+ id,
774
+ title,
775
+ message: options?.message,
776
+ variant: options?.variant ?? "default",
777
+ duration: options?.duration ?? 3e3
778
+ };
779
+ setToasts((prev) => [...prev, entry]);
780
+ setTimeout(() => setToasts((prev) => prev.filter((t) => t.id !== id)), entry.duration);
781
+ }, []);
782
+ useEffect2(() => {
783
+ globalToastShow = show;
784
+ return () => {
785
+ globalToastShow = null;
786
+ };
787
+ }, [show]);
788
+ const dismiss = useCallback((id) => {
789
+ setToasts((prev) => prev.filter((t) => t.id !== id));
790
+ }, []);
791
+ return /* @__PURE__ */ jsxs5(ToastContext.Provider, { value: { show }, children: [
792
+ children,
793
+ /* @__PURE__ */ jsx10(
794
+ YStack5,
795
+ {
796
+ position: "absolute",
797
+ top: 50,
798
+ left: 0,
799
+ right: 0,
800
+ alignItems: "center",
801
+ gap: "$2",
802
+ pointerEvents: "box-none",
803
+ zIndex: 1e5,
804
+ paddingHorizontal: "$4",
805
+ children: toasts.map((t) => {
806
+ const style = variantStyles[t.variant ?? "default"];
807
+ return /* @__PURE__ */ jsxs5(
808
+ XStack6,
809
+ {
810
+ width: "100%",
811
+ maxWidth: 400,
812
+ backgroundColor: style.bg,
813
+ borderWidth: 1,
814
+ borderColor: style.border,
815
+ borderRadius: "$4",
816
+ paddingHorizontal: "$4",
817
+ paddingVertical: "$3",
818
+ gap: "$3",
819
+ alignItems: "flex-start",
820
+ enterStyle: { opacity: 0, y: -20, scale: 0.95 },
821
+ exitStyle: { opacity: 0, y: -20, scale: 0.95 },
822
+ opacity: 1,
823
+ y: 0,
824
+ scale: 1,
825
+ animation: "quick",
826
+ pointerEvents: "auto",
827
+ elevation: 4,
828
+ children: [
829
+ /* @__PURE__ */ jsx10(SizableText10, { size: "$4", fontWeight: "700", marginTop: "$0.5", children: style.icon }),
830
+ /* @__PURE__ */ jsxs5(YStack5, { flex: 1, gap: "$1", children: [
831
+ /* @__PURE__ */ jsx10(SizableText10, { size: "$4", fontWeight: "600", color: "$color12", children: t.title }),
832
+ t.message && /* @__PURE__ */ jsx10(SizableText10, { size: "$3", color: "$color10", children: t.message })
833
+ ] }),
834
+ /* @__PURE__ */ jsx10(
835
+ SizableText10,
836
+ {
837
+ size: "$3",
838
+ color: "$color8",
839
+ fontWeight: "600",
840
+ pressStyle: { opacity: 0.5 },
841
+ onPress: () => dismiss(t.id),
842
+ cursor: "pointer",
843
+ marginTop: "$0.5",
844
+ children: "\u2715"
845
+ }
846
+ )
847
+ ]
848
+ },
849
+ t.id
850
+ );
851
+ })
852
+ }
853
+ )
854
+ ] });
855
+ }
856
+ function useBlinkToast() {
857
+ const ctx = useContext(ToastContext);
858
+ if (!ctx) throw new Error("useBlinkToast must be used within BlinkToastProvider");
859
+ return ctx;
860
+ }
861
+
862
+ // src/interface/FormField.tsx
863
+ import { SizableText as SizableText11, YStack as YStack6 } from "tamagui";
864
+ import { jsx as jsx11, jsxs as jsxs6 } from "react/jsx-runtime";
865
+ function FormField({ label, error, helperText, required, children }) {
866
+ return /* @__PURE__ */ jsxs6(YStack6, { gap: "$1.5", children: [
867
+ label && /* @__PURE__ */ jsxs6(SizableText11, { size: "$3", fontWeight: "600", color: "$color11", children: [
868
+ label,
869
+ required && /* @__PURE__ */ jsx11(SizableText11, { color: "$red9", children: " *" })
870
+ ] }),
871
+ children,
872
+ helperText && !error && /* @__PURE__ */ jsx11(SizableText11, { size: "$2", color: "$color9", children: helperText }),
873
+ error && /* @__PURE__ */ jsx11(SizableText11, { size: "$2", color: "$red9", children: error })
874
+ ] });
875
+ }
876
+
877
+ // src/interface/Tooltip.tsx
878
+ import { Popover, SizableText as SizableText12 } from "tamagui";
879
+ import { jsx as jsx12, jsxs as jsxs7 } from "react/jsx-runtime";
880
+ function BlinkTooltip({ content, children, side = "top" }) {
881
+ return /* @__PURE__ */ jsxs7(Popover, { size: "$2", placement: side, children: [
882
+ /* @__PURE__ */ jsx12(Popover.Trigger, { asChild: true, children }),
883
+ /* @__PURE__ */ jsxs7(
884
+ Popover.Content,
885
+ {
886
+ backgroundColor: "$color11",
887
+ borderRadius: "$2",
888
+ paddingHorizontal: "$2.5",
889
+ paddingVertical: "$1.5",
890
+ elevate: true,
891
+ enterStyle: { opacity: 0, y: side === "bottom" ? -4 : 4 },
892
+ exitStyle: { opacity: 0, y: side === "bottom" ? -4 : 4 },
893
+ opacity: 1,
894
+ y: 0,
895
+ animation: "quick",
896
+ children: [
897
+ /* @__PURE__ */ jsx12(Popover.Arrow, { backgroundColor: "$color11", size: "$1" }),
898
+ /* @__PURE__ */ jsx12(SizableText12, { size: "$2", color: "$color1", children: content })
899
+ ]
900
+ }
901
+ )
902
+ ] });
903
+ }
904
+
905
+ // src/layouts/StepPageLayout.tsx
906
+ import { SizableText as SizableText13, YStack as YStack7 } from "tamagui";
907
+ import { jsx as jsx13, jsxs as jsxs8 } from "react/jsx-runtime";
908
+ function StepPageLayout({ title, description, children, bottom }) {
909
+ return /* @__PURE__ */ jsxs8(YStack7, { flex: 1, padding: "$4", maxWidth: 500, marginHorizontal: "auto", width: "100%", children: [
910
+ /* @__PURE__ */ jsx13(YStack7, { gap: "$5", children: /* @__PURE__ */ jsxs8(YStack7, { gap: "$2", children: [
911
+ /* @__PURE__ */ jsx13(SizableText13, { size: "$8", fontWeight: "700", children: title }),
912
+ description && /* @__PURE__ */ jsx13(SizableText13, { size: "$5", fontWeight: "400", color: "$color10", children: description })
913
+ ] }) }),
914
+ /* @__PURE__ */ jsx13(YStack7, { paddingTop: "$5", gap: "$4", children }),
915
+ bottom && /* @__PURE__ */ jsx13(YStack7, { paddingTop: "$4", children: bottom })
916
+ ] });
917
+ }
918
+
919
+ // src/layouts/ScreenLayout.tsx
920
+ import { styled as styled10, YStack as YStack8 } from "tamagui";
921
+ var ScreenLayout = styled10(YStack8, {
922
+ name: "BlinkScreenLayout",
923
+ flex: 1,
924
+ backgroundColor: "$background",
515
925
  variants: {
516
- size: {
517
- xs: { fontSize: 10 },
518
- sm: { fontSize: 12 },
519
- md: { fontSize: 14 },
520
- lg: { fontSize: 18 },
521
- xl: { fontSize: 24 },
522
- xxl: { fontSize: 30 }
926
+ padded: {
927
+ true: { padding: "$4" }
928
+ },
929
+ centered: {
930
+ true: { alignItems: "center", justifyContent: "center" }
931
+ },
932
+ safe: {
933
+ true: { paddingTop: "$6" }
523
934
  }
524
- },
525
- defaultVariants: {
526
- size: "md"
527
935
  }
528
936
  });
529
- function getInitials(name) {
530
- return name.split(" ").map((p) => p[0]).join("").toUpperCase().slice(0, 2);
937
+
938
+ // src/layouts/Section.tsx
939
+ import { SizableText as SizableText14, YStack as YStack9 } from "tamagui";
940
+ import { jsx as jsx14, jsxs as jsxs9 } from "react/jsx-runtime";
941
+ function Section({ title, description, children, gap = "$3" }) {
942
+ return /* @__PURE__ */ jsxs9(YStack9, { gap, children: [
943
+ title && /* @__PURE__ */ jsxs9(YStack9, { gap: "$1", children: [
944
+ /* @__PURE__ */ jsx14(SizableText14, { size: "$5", fontWeight: "600", color: "$color12", children: title }),
945
+ description && /* @__PURE__ */ jsx14(SizableText14, { size: "$3", color: "$color9", children: description })
946
+ ] }),
947
+ children
948
+ ] });
949
+ }
950
+
951
+ // src/layouts/ListItem.tsx
952
+ import { styled as styled11, SizableText as SizableText15, XStack as XStack7, YStack as YStack10, View as View5 } from "tamagui";
953
+ import { jsx as jsx15, jsxs as jsxs10 } from "react/jsx-runtime";
954
+ var ListItemFrame = styled11(XStack7, {
955
+ name: "BlinkListItem",
956
+ alignItems: "center",
957
+ gap: "$3",
958
+ padding: "$3",
959
+ borderRadius: "$3",
960
+ variants: {
961
+ pressable: {
962
+ true: {
963
+ cursor: "pointer",
964
+ hoverStyle: { backgroundColor: "$color2" },
965
+ pressStyle: { backgroundColor: "$color3", opacity: 0.9 }
966
+ }
967
+ }
968
+ }
969
+ });
970
+ function ListItem({ icon, title, subtitle, right, onPress }) {
971
+ return /* @__PURE__ */ jsxs10(ListItemFrame, { pressable: !!onPress, onPress, children: [
972
+ icon && /* @__PURE__ */ jsx15(View5, { children: icon }),
973
+ /* @__PURE__ */ jsxs10(YStack10, { flex: 1, gap: "$1", children: [
974
+ /* @__PURE__ */ jsx15(SizableText15, { size: "$4", fontWeight: "500", color: "$color12", children: title }),
975
+ subtitle && /* @__PURE__ */ jsx15(SizableText15, { size: "$2", color: "$color9", children: subtitle })
976
+ ] }),
977
+ right
978
+ ] });
979
+ }
980
+
981
+ // src/layouts/Divider.tsx
982
+ import { Separator as Separator3, SizableText as SizableText16, XStack as XStack8 } from "tamagui";
983
+ import { jsx as jsx16, jsxs as jsxs11 } from "react/jsx-runtime";
984
+ function Divider({ label }) {
985
+ if (!label) return /* @__PURE__ */ jsx16(Separator3, { borderColor: "$color4" });
986
+ return /* @__PURE__ */ jsxs11(XStack8, { alignItems: "center", gap: "$3", children: [
987
+ /* @__PURE__ */ jsx16(Separator3, { flex: 1, borderColor: "$color4" }),
988
+ /* @__PURE__ */ jsx16(SizableText16, { size: "$2", color: "$color9", children: label }),
989
+ /* @__PURE__ */ jsx16(Separator3, { flex: 1, borderColor: "$color4" })
990
+ ] });
991
+ }
992
+
993
+ // src/layouts/KeyboardStickyFooter.tsx
994
+ import { YStack as YStack11 } from "tamagui";
995
+ import { jsx as jsx17 } from "react/jsx-runtime";
996
+ function KeyboardStickyFooter({ children, offset }) {
997
+ return /* @__PURE__ */ jsx17(YStack11, { maxWidth: 500, alignSelf: "center", paddingTop: "$8", paddingBottom: "$4", style: { paddingBottom: offset }, children });
998
+ }
999
+
1000
+ // src/layouts/SafeArea.tsx
1001
+ import { YStack as YStack12 } from "tamagui";
1002
+ import { jsx as jsx18 } from "react/jsx-runtime";
1003
+ function SafeArea({ children, edges = ["top", "bottom"] }) {
1004
+ return /* @__PURE__ */ jsx18(
1005
+ YStack12,
1006
+ {
1007
+ flex: 1,
1008
+ backgroundColor: "$background",
1009
+ paddingTop: edges.includes("top") ? "$6" : void 0,
1010
+ paddingBottom: edges.includes("bottom") ? "$6" : void 0,
1011
+ paddingLeft: edges.includes("left") ? "$4" : void 0,
1012
+ paddingRight: edges.includes("right") ? "$4" : void 0,
1013
+ children
1014
+ }
1015
+ );
1016
+ }
1017
+
1018
+ // src/layouts/Grid.tsx
1019
+ import { Children } from "react";
1020
+ import { XStack as XStack9, YStack as YStack13 } from "tamagui";
1021
+ import { jsx as jsx19, jsxs as jsxs12 } from "react/jsx-runtime";
1022
+ function Grid({ children, columns = 2, gap = "$3" }) {
1023
+ const items = Children.toArray(children);
1024
+ const rows = [];
1025
+ for (let i = 0; i < items.length; i += columns) {
1026
+ rows.push(items.slice(i, i + columns));
1027
+ }
1028
+ return /* @__PURE__ */ jsx19(YStack13, { gap, children: rows.map((row, ri) => /* @__PURE__ */ jsxs12(XStack9, { gap, children: [
1029
+ row.map((item, ci) => /* @__PURE__ */ jsx19(YStack13, { flex: 1, children: item }, ci)),
1030
+ row.length < columns && Array.from({ length: columns - row.length }).map((_, i) => /* @__PURE__ */ jsx19(YStack13, { flex: 1 }, `pad-${i}`))
1031
+ ] }, ri)) });
1032
+ }
1033
+ function Container({ children, maxWidth = 500, centered = true, padding = "$4" }) {
1034
+ return /* @__PURE__ */ jsx19(YStack13, { width: "100%", maxWidth, alignSelf: centered ? "center" : void 0, padding, children });
1035
+ }
1036
+
1037
+ // src/patterns/PaywallScreen.tsx
1038
+ import { Button as Button3, SizableText as SizableText17, XStack as XStack10, YStack as YStack14, Circle as Circle2 } from "tamagui";
1039
+ import { jsx as jsx20, jsxs as jsxs13 } from "react/jsx-runtime";
1040
+ function PaywallScreen({
1041
+ title = "Upgrade Your Experience",
1042
+ subtitle = "Choose the plan that works for you",
1043
+ plans,
1044
+ selectedPlan,
1045
+ onSelectPlan,
1046
+ onContinue,
1047
+ onRestore,
1048
+ continueLabel = "Continue"
1049
+ }) {
1050
+ return /* @__PURE__ */ jsxs13(YStack14, { flex: 1, padding: "$4", gap: "$5", backgroundColor: "$background", children: [
1051
+ /* @__PURE__ */ jsxs13(YStack14, { gap: "$2", paddingTop: "$6", children: [
1052
+ /* @__PURE__ */ jsx20(SizableText17, { size: "$9", fontWeight: "700", textAlign: "center", children: title }),
1053
+ /* @__PURE__ */ jsx20(SizableText17, { size: "$4", color: "$color10", textAlign: "center", children: subtitle })
1054
+ ] }),
1055
+ /* @__PURE__ */ jsx20(YStack14, { gap: "$3", flex: 1, children: plans.map((plan) => /* @__PURE__ */ jsxs13(
1056
+ YStack14,
1057
+ {
1058
+ padding: "$4",
1059
+ borderRadius: "$5",
1060
+ borderWidth: 2,
1061
+ borderColor: selectedPlan === plan.id ? "$color9" : "$color4",
1062
+ backgroundColor: selectedPlan === plan.id ? "$color2" : "$color1",
1063
+ pressStyle: { scale: 0.98 },
1064
+ onPress: () => onSelectPlan?.(plan.id),
1065
+ cursor: "pointer",
1066
+ children: [
1067
+ /* @__PURE__ */ jsxs13(XStack10, { justifyContent: "space-between", alignItems: "center", children: [
1068
+ /* @__PURE__ */ jsxs13(YStack14, { children: [
1069
+ /* @__PURE__ */ jsx20(SizableText17, { size: "$5", fontWeight: "600", children: plan.name }),
1070
+ /* @__PURE__ */ jsxs13(XStack10, { alignItems: "baseline", gap: "$1", children: [
1071
+ /* @__PURE__ */ jsx20(SizableText17, { size: "$8", fontWeight: "700", children: plan.price }),
1072
+ /* @__PURE__ */ jsxs13(SizableText17, { size: "$3", color: "$color9", children: [
1073
+ "/",
1074
+ plan.period
1075
+ ] })
1076
+ ] })
1077
+ ] }),
1078
+ plan.popular && /* @__PURE__ */ jsx20(YStack14, { backgroundColor: "$color9", paddingHorizontal: "$2", paddingVertical: "$1", borderRadius: "$10", children: /* @__PURE__ */ jsx20(SizableText17, { size: "$1", color: "$color1", fontWeight: "600", children: "POPULAR" }) })
1079
+ ] }),
1080
+ /* @__PURE__ */ jsx20(YStack14, { gap: "$2", paddingTop: "$3", children: plan.features.map((feature, i) => /* @__PURE__ */ jsxs13(XStack10, { gap: "$2", alignItems: "center", children: [
1081
+ /* @__PURE__ */ jsx20(Circle2, { size: 6, backgroundColor: "$green9" }),
1082
+ /* @__PURE__ */ jsx20(SizableText17, { size: "$3", color: "$color11", children: feature })
1083
+ ] }, i)) })
1084
+ ]
1085
+ },
1086
+ plan.id
1087
+ )) }),
1088
+ /* @__PURE__ */ jsxs13(YStack14, { gap: "$3", paddingBottom: "$4", children: [
1089
+ /* @__PURE__ */ jsx20(
1090
+ Button3,
1091
+ {
1092
+ size: "$5",
1093
+ backgroundColor: "$color9",
1094
+ color: "$color1",
1095
+ onPress: onContinue,
1096
+ hoverStyle: { backgroundColor: "$color10" },
1097
+ pressStyle: { backgroundColor: "$color8" },
1098
+ borderRadius: "$5",
1099
+ children: continueLabel
1100
+ }
1101
+ ),
1102
+ onRestore && /* @__PURE__ */ jsx20(Button3, { size: "$3", chromeless: true, onPress: onRestore, children: /* @__PURE__ */ jsx20(SizableText17, { size: "$3", color: "$color9", children: "Restore Purchases" }) })
1103
+ ] })
1104
+ ] });
1105
+ }
1106
+
1107
+ // src/patterns/OnboardingCarousel.tsx
1108
+ import { useState as useState5 } from "react";
1109
+ import { Button as Button4, SizableText as SizableText18, XStack as XStack11, YStack as YStack15, Circle as Circle3 } from "tamagui";
1110
+ import { jsx as jsx21, jsxs as jsxs14 } from "react/jsx-runtime";
1111
+ function OnboardingCarousel({
1112
+ steps,
1113
+ onComplete,
1114
+ onSkip,
1115
+ completeLabel = "Get Started",
1116
+ skipLabel = "Skip",
1117
+ nextLabel = "Next"
1118
+ }) {
1119
+ const [current, setCurrent] = useState5(0);
1120
+ const isLast = current === steps.length - 1;
1121
+ const step = steps[current];
1122
+ return /* @__PURE__ */ jsxs14(YStack15, { flex: 1, backgroundColor: "$background", padding: "$4", justifyContent: "space-between", children: [
1123
+ /* @__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
+ /* @__PURE__ */ jsxs14(YStack15, { flex: 1, alignItems: "center", justifyContent: "center", gap: "$5", paddingHorizontal: "$4", children: [
1125
+ step?.icon && /* @__PURE__ */ jsx21(Circle3, { size: 120, backgroundColor: "$color2", alignItems: "center", justifyContent: "center", children: step.icon }),
1126
+ /* @__PURE__ */ jsxs14(YStack15, { gap: "$3", alignItems: "center", children: [
1127
+ /* @__PURE__ */ jsx21(SizableText18, { size: "$9", fontWeight: "700", textAlign: "center", children: step?.title }),
1128
+ /* @__PURE__ */ jsx21(SizableText18, { size: "$4", color: "$color10", textAlign: "center", maxWidth: 300, children: step?.description })
1129
+ ] })
1130
+ ] }),
1131
+ /* @__PURE__ */ jsxs14(YStack15, { gap: "$3", paddingBottom: "$2", children: [
1132
+ /* @__PURE__ */ jsx21(XStack11, { justifyContent: "center", gap: "$2", children: steps.map((_, i) => /* @__PURE__ */ jsx21(
1133
+ Circle3,
1134
+ {
1135
+ size: 8,
1136
+ backgroundColor: i === current ? "$color9" : "$color4",
1137
+ animation: "quick"
1138
+ },
1139
+ i
1140
+ )) }),
1141
+ /* @__PURE__ */ jsx21(
1142
+ Button4,
1143
+ {
1144
+ size: "$5",
1145
+ backgroundColor: "$color9",
1146
+ color: "$color1",
1147
+ borderRadius: "$5",
1148
+ hoverStyle: { backgroundColor: "$color10" },
1149
+ pressStyle: { backgroundColor: "$color8" },
1150
+ onPress: () => isLast ? onComplete?.() : setCurrent((c) => c + 1),
1151
+ children: isLast ? completeLabel : nextLabel
1152
+ }
1153
+ )
1154
+ ] })
1155
+ ] });
1156
+ }
1157
+
1158
+ // src/patterns/ChatBubble.tsx
1159
+ import { SizableText as SizableText19, XStack as XStack12, YStack as YStack16, Circle as Circle4, Image as Image3 } from "tamagui";
1160
+ import { jsx as jsx22, jsxs as jsxs15 } from "react/jsx-runtime";
1161
+ function ChatBubble({ message, showAvatar = true }) {
1162
+ const isUser = message.sender === "user";
1163
+ return /* @__PURE__ */ jsxs15(
1164
+ XStack12,
1165
+ {
1166
+ alignSelf: isUser ? "flex-end" : "flex-start",
1167
+ maxWidth: "75%",
1168
+ gap: "$2",
1169
+ flexDirection: isUser ? "row-reverse" : "row",
1170
+ children: [
1171
+ showAvatar && !isUser && /* @__PURE__ */ jsx22(Circle4, { size: 32, backgroundColor: "$color4", overflow: "hidden", children: message.avatar ? /* @__PURE__ */ jsx22(Image3, { source: { uri: message.avatar }, width: 32, height: 32, objectFit: "cover" }) : /* @__PURE__ */ jsx22(SizableText19, { size: "$2", fontWeight: "600", color: "$color11", children: message.senderName?.[0]?.toUpperCase() ?? "?" }) }),
1172
+ /* @__PURE__ */ jsxs15(
1173
+ YStack16,
1174
+ {
1175
+ backgroundColor: isUser ? "$color9" : "$color3",
1176
+ paddingHorizontal: "$3",
1177
+ paddingVertical: "$2.5",
1178
+ borderRadius: "$5",
1179
+ borderBottomRightRadius: isUser ? "$2" : "$5",
1180
+ borderBottomLeftRadius: isUser ? "$5" : "$2",
1181
+ gap: "$1",
1182
+ children: [
1183
+ /* @__PURE__ */ jsx22(SizableText19, { size: "$3", color: isUser ? "$color1" : "$color12", children: message.text }),
1184
+ message.timestamp && /* @__PURE__ */ jsx22(SizableText19, { size: "$1", color: isUser ? "$color3" : "$color9", alignSelf: "flex-end", children: message.timestamp })
1185
+ ]
1186
+ }
1187
+ )
1188
+ ]
1189
+ }
1190
+ );
1191
+ }
1192
+
1193
+ // src/patterns/SettingsScreen.tsx
1194
+ import { Separator as Separator4, SizableText as SizableText20, Switch, XStack as XStack13, YStack as YStack17 } from "tamagui";
1195
+ import { jsx as jsx23, jsxs as jsxs16 } from "react/jsx-runtime";
1196
+ function SettingsItemRow({ item }) {
1197
+ return /* @__PURE__ */ jsxs16(
1198
+ XStack13,
1199
+ {
1200
+ alignItems: "center",
1201
+ gap: "$3",
1202
+ paddingVertical: "$3",
1203
+ paddingHorizontal: "$4",
1204
+ hoverStyle: item.onPress ? { backgroundColor: "$color2" } : void 0,
1205
+ pressStyle: item.onPress ? { backgroundColor: "$color3" } : void 0,
1206
+ onPress: item.onPress,
1207
+ cursor: item.onPress ? "pointer" : void 0,
1208
+ children: [
1209
+ item.icon && /* @__PURE__ */ jsx23(YStack17, { width: 24, alignItems: "center", children: item.icon }),
1210
+ /* @__PURE__ */ jsxs16(YStack17, { flex: 1, gap: "$1", children: [
1211
+ /* @__PURE__ */ jsx23(SizableText20, { size: "$4", fontWeight: "500", children: item.title }),
1212
+ item.subtitle && /* @__PURE__ */ jsx23(SizableText20, { size: "$2", color: "$color9", children: item.subtitle })
1213
+ ] }),
1214
+ item.type === "toggle" ? /* @__PURE__ */ jsx23(Switch, { size: "$3", checked: item.value, onCheckedChange: item.onValueChange, children: /* @__PURE__ */ jsx23(Switch.Thumb, { animation: "quick" }) }) : item.right ? item.right : item.onPress && /* @__PURE__ */ jsx23(SizableText20, { size: "$5", color: "$color8", children: "\u203A" })
1215
+ ]
1216
+ }
1217
+ );
531
1218
  }
532
- function Avatar({ uri, name, size = "md", ...props }) {
533
- if (uri) {
534
- return /* @__PURE__ */ jsx2(AvatarFrame, { size, ...props, children: /* @__PURE__ */ jsx2(
535
- Image,
1219
+ function SettingsScreen({ sections, header }) {
1220
+ return /* @__PURE__ */ jsxs16(YStack17, { flex: 1, backgroundColor: "$background", children: [
1221
+ header,
1222
+ /* @__PURE__ */ jsx23(YStack17, { gap: "$4", paddingVertical: "$2", children: sections.map((section, si) => /* @__PURE__ */ jsxs16(YStack17, { children: [
1223
+ section.title && /* @__PURE__ */ jsx23(
1224
+ SizableText20,
1225
+ {
1226
+ size: "$2",
1227
+ fontWeight: "600",
1228
+ color: "$color9",
1229
+ paddingHorizontal: "$4",
1230
+ paddingBottom: "$2",
1231
+ textTransform: "uppercase",
1232
+ children: section.title
1233
+ }
1234
+ ),
1235
+ /* @__PURE__ */ jsx23(YStack17, { backgroundColor: "$color1", borderRadius: "$4", marginHorizontal: "$3", overflow: "hidden", children: section.items.map((item, ii) => /* @__PURE__ */ jsxs16(YStack17, { children: [
1236
+ /* @__PURE__ */ jsx23(SettingsItemRow, { item }),
1237
+ ii < section.items.length - 1 && /* @__PURE__ */ jsx23(Separator4, { borderColor: "$color3", marginLeft: "$12" })
1238
+ ] }, item.id)) })
1239
+ ] }, si)) })
1240
+ ] });
1241
+ }
1242
+
1243
+ // src/patterns/EmptyState.tsx
1244
+ import { Button as Button5, SizableText as SizableText21, YStack as YStack18 } from "tamagui";
1245
+ import { jsx as jsx24, jsxs as jsxs17 } from "react/jsx-runtime";
1246
+ function EmptyState({ icon, title, description, actionLabel, onAction }) {
1247
+ return /* @__PURE__ */ jsxs17(YStack18, { flex: 1, alignItems: "center", justifyContent: "center", gap: "$4", padding: "$6", children: [
1248
+ icon,
1249
+ /* @__PURE__ */ jsxs17(YStack18, { gap: "$2", alignItems: "center", children: [
1250
+ /* @__PURE__ */ jsx24(SizableText21, { size: "$6", fontWeight: "600", textAlign: "center", children: title }),
1251
+ description && /* @__PURE__ */ jsx24(SizableText21, { size: "$4", color: "$color9", textAlign: "center", maxWidth: 280, children: description })
1252
+ ] }),
1253
+ actionLabel && onAction && /* @__PURE__ */ jsx24(
1254
+ Button5,
1255
+ {
1256
+ size: "$4",
1257
+ backgroundColor: "$color9",
1258
+ color: "$color1",
1259
+ borderRadius: "$4",
1260
+ hoverStyle: { backgroundColor: "$color10" },
1261
+ pressStyle: { backgroundColor: "$color8" },
1262
+ onPress: onAction,
1263
+ children: actionLabel
1264
+ }
1265
+ )
1266
+ ] });
1267
+ }
1268
+
1269
+ // src/patterns/ProfileHeader.tsx
1270
+ import { Circle as Circle5, Image as Image4, SizableText as SizableText22, XStack as XStack14, YStack as YStack19 } from "tamagui";
1271
+ import { jsx as jsx25, jsxs as jsxs18 } from "react/jsx-runtime";
1272
+ function ProfileHeader({ name, subtitle, avatar, stats, actions }) {
1273
+ return /* @__PURE__ */ jsxs18(YStack19, { alignItems: "center", gap: "$4", paddingVertical: "$6", paddingHorizontal: "$4", children: [
1274
+ /* @__PURE__ */ jsx25(Circle5, { size: 80, backgroundColor: "$color4", overflow: "hidden", children: avatar ? /* @__PURE__ */ jsx25(Image4, { source: { uri: avatar }, width: 80, height: 80, objectFit: "cover" }) : /* @__PURE__ */ jsx25(SizableText22, { size: "$9", fontWeight: "700", color: "$color11", children: name[0]?.toUpperCase() ?? "?" }) }),
1275
+ /* @__PURE__ */ jsxs18(YStack19, { alignItems: "center", gap: "$1", children: [
1276
+ /* @__PURE__ */ jsx25(SizableText22, { size: "$7", fontWeight: "700", children: name }),
1277
+ subtitle && /* @__PURE__ */ jsx25(SizableText22, { size: "$4", color: "$color10", children: subtitle })
1278
+ ] }),
1279
+ stats && stats.length > 0 && /* @__PURE__ */ jsx25(XStack14, { gap: "$6", children: stats.map((stat, i) => /* @__PURE__ */ jsxs18(YStack19, { alignItems: "center", gap: "$1", children: [
1280
+ /* @__PURE__ */ jsx25(SizableText22, { size: "$6", fontWeight: "700", children: stat.value }),
1281
+ /* @__PURE__ */ jsx25(SizableText22, { size: "$2", color: "$color9", children: stat.label })
1282
+ ] }, i)) }),
1283
+ actions
1284
+ ] });
1285
+ }
1286
+
1287
+ // src/patterns/AppHeader.tsx
1288
+ import { SizableText as SizableText23, XStack as XStack15, YStack as YStack20 } from "tamagui";
1289
+ import { jsx as jsx26, jsxs as jsxs19 } from "react/jsx-runtime";
1290
+ function AppHeader({ title, subtitle, variant = "simple", onBack, avatar, left, right, transparent, borderless }) {
1291
+ const leftContent = (() => {
1292
+ if (variant === "back") return /* @__PURE__ */ jsx26(SizableText23, { size: "$6", paddingRight: "$2", onPress: onBack, pressStyle: { opacity: 0.6 }, cursor: "pointer", children: "\u2039" });
1293
+ if (variant === "profile") return /* @__PURE__ */ jsx26(Avatar, { uri: avatar, name: title, size: "sm" });
1294
+ if (variant === "centered") return left ?? null;
1295
+ return null;
1296
+ })();
1297
+ const rightContent = variant === "profile" || variant === "centered" ? right ?? null : null;
1298
+ return /* @__PURE__ */ jsx26(
1299
+ YStack20,
1300
+ {
1301
+ paddingTop: "$6",
1302
+ backgroundColor: transparent ? "transparent" : "$background",
1303
+ borderBottomWidth: borderless ? 0 : 1,
1304
+ borderBottomColor: "$borderColor",
1305
+ children: /* @__PURE__ */ jsxs19(XStack15, { height: 56, alignItems: "center", paddingHorizontal: "$4", gap: "$3", children: [
1306
+ leftContent,
1307
+ /* @__PURE__ */ jsxs19(YStack20, { flex: 1, alignItems: variant === "centered" ? "center" : "flex-start", children: [
1308
+ /* @__PURE__ */ jsx26(SizableText23, { size: "$6", fontWeight: "700", numberOfLines: 1, children: title }),
1309
+ subtitle && /* @__PURE__ */ jsx26(SizableText23, { size: "$2", color: "$color9", numberOfLines: 1, children: subtitle })
1310
+ ] }),
1311
+ rightContent
1312
+ ] })
1313
+ }
1314
+ );
1315
+ }
1316
+
1317
+ // src/patterns/BottomSheet.tsx
1318
+ import { Sheet, SizableText as SizableText24, XStack as XStack16, YStack as YStack21 } from "tamagui";
1319
+ import { ScrollView as ScrollView2 } from "react-native";
1320
+ import { jsx as jsx27, jsxs as jsxs20 } from "react/jsx-runtime";
1321
+ function BottomSheet({ open, onOpenChange, title, children, snapPoints = [85], dismissOnSnapToBottom = true, showHandle = true, showClose = false }) {
1322
+ return /* @__PURE__ */ jsxs20(Sheet, { modal: true, open, onOpenChange, snapPoints, dismissOnSnapToBottom, animation: "medium", children: [
1323
+ /* @__PURE__ */ jsx27(Sheet.Overlay, { animation: "lazy", enterStyle: { opacity: 0 }, exitStyle: { opacity: 0 } }),
1324
+ showHandle && /* @__PURE__ */ jsx27(Sheet.Handle, {}),
1325
+ /* @__PURE__ */ jsxs20(Sheet.Frame, { borderTopLeftRadius: "$6", borderTopRightRadius: "$6", backgroundColor: "$background", children: [
1326
+ (title || showClose) && /* @__PURE__ */ jsxs20(XStack16, { paddingHorizontal: "$4", paddingTop: "$3", paddingBottom: "$2", alignItems: "center", justifyContent: "space-between", children: [
1327
+ /* @__PURE__ */ jsx27(SizableText24, { size: "$6", fontWeight: "600", flexShrink: 1, children: title }),
1328
+ showClose && /* @__PURE__ */ jsx27(
1329
+ XStack16,
1330
+ {
1331
+ width: 28,
1332
+ height: 28,
1333
+ borderRadius: "$10",
1334
+ backgroundColor: "$color4",
1335
+ alignItems: "center",
1336
+ justifyContent: "center",
1337
+ pressStyle: { opacity: 0.7 },
1338
+ onPress: () => onOpenChange(false),
1339
+ children: /* @__PURE__ */ jsx27(SizableText24, { size: "$3", color: "$color10", fontWeight: "600", children: "\u2715" })
1340
+ }
1341
+ )
1342
+ ] }),
1343
+ /* @__PURE__ */ jsx27(ScrollView2, { contentContainerStyle: { paddingBottom: 40 }, children: /* @__PURE__ */ jsx27(YStack21, { padding: "$4", children }) })
1344
+ ] })
1345
+ ] });
1346
+ }
1347
+
1348
+ // src/patterns/LoginScreen.tsx
1349
+ import { useState as useState6 } from "react";
1350
+ import { Button as Button6, SizableText as SizableText25, Spinner, XStack as XStack17, YStack as YStack22 } from "tamagui";
1351
+ import { jsx as jsx28, jsxs as jsxs21 } from "react/jsx-runtime";
1352
+ function LoginScreen({ title = "Welcome", subtitle = "Sign in to continue", logo, providers = [], onProviderPress, showEmailForm, onEmailSubmit, onForgotPassword, onCreateAccount, onTerms, onPrivacy, loading }) {
1353
+ const [email, setEmail] = useState6("");
1354
+ const [password, setPassword] = useState6("");
1355
+ return /* @__PURE__ */ jsxs21(YStack22, { flex: 1, padding: "$4", gap: "$5", backgroundColor: "$background", justifyContent: "center", children: [
1356
+ /* @__PURE__ */ jsxs21(YStack22, { alignItems: "center", gap: "$2", children: [
1357
+ logo && /* @__PURE__ */ jsx28(YStack22, { paddingBottom: "$3", children: logo }),
1358
+ /* @__PURE__ */ jsx28(SizableText25, { size: "$9", fontWeight: "700", textAlign: "center", children: title }),
1359
+ /* @__PURE__ */ jsx28(SizableText25, { size: "$4", color: "$color10", textAlign: "center", children: subtitle })
1360
+ ] }),
1361
+ providers.length > 0 && /* @__PURE__ */ jsx28(YStack22, { gap: "$2.5", children: providers.map((p) => /* @__PURE__ */ jsx28(
1362
+ Button6,
1363
+ {
1364
+ size: "$5",
1365
+ borderWidth: 1.5,
1366
+ borderColor: "$color5",
1367
+ backgroundColor: "$color1",
1368
+ borderRadius: "$4",
1369
+ disabled: loading,
1370
+ onPress: () => onProviderPress?.(p.id),
1371
+ hoverStyle: { backgroundColor: "$color2" },
1372
+ pressStyle: { backgroundColor: "$color3" },
1373
+ children: /* @__PURE__ */ jsxs21(XStack17, { alignItems: "center", gap: "$2", children: [
1374
+ p.icon,
1375
+ /* @__PURE__ */ jsx28(SizableText25, { size: "$4", fontWeight: "500", children: p.name })
1376
+ ] })
1377
+ },
1378
+ p.id
1379
+ )) }),
1380
+ showEmailForm && providers.length > 0 && /* @__PURE__ */ jsx28(Divider, { label: "or" }),
1381
+ showEmailForm && /* @__PURE__ */ jsxs21(YStack22, { gap: "$3", children: [
1382
+ /* @__PURE__ */ jsx28(Input, { label: "Email", placeholder: "your@email.com", value: email, onChangeText: setEmail, keyboardType: "email-address", autoCapitalize: "none" }),
1383
+ /* @__PURE__ */ jsx28(Input, { label: "Password", placeholder: "\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022", value: password, onChangeText: setPassword, secureTextEntry: true }),
1384
+ onForgotPassword && /* @__PURE__ */ jsx28(XStack17, { justifyContent: "flex-end", children: /* @__PURE__ */ jsx28(SizableText25, { size: "$3", color: "$color9", onPress: onForgotPassword, children: "Forgot password?" }) }),
1385
+ /* @__PURE__ */ jsx28(
1386
+ Button6,
1387
+ {
1388
+ size: "$5",
1389
+ backgroundColor: "$color9",
1390
+ color: "$color1",
1391
+ borderRadius: "$5",
1392
+ disabled: loading,
1393
+ onPress: () => onEmailSubmit?.(email, password),
1394
+ hoverStyle: { backgroundColor: "$color10" },
1395
+ pressStyle: { backgroundColor: "$color8" },
1396
+ icon: loading ? /* @__PURE__ */ jsx28(Spinner, { size: "small", color: "$color1" }) : void 0,
1397
+ children: "Sign In"
1398
+ }
1399
+ ),
1400
+ onCreateAccount && /* @__PURE__ */ jsx28(Button6, { size: "$3", chromeless: true, onPress: onCreateAccount, children: /* @__PURE__ */ jsx28(SizableText25, { size: "$3", color: "$color9", children: "Create Account" }) })
1401
+ ] }),
1402
+ (onTerms || onPrivacy) && /* @__PURE__ */ jsx28(YStack22, { paddingTop: "$2", alignItems: "center", children: /* @__PURE__ */ jsxs21(SizableText25, { size: "$2", color: "$color8", textAlign: "center", children: [
1403
+ "By continuing you agree to our",
1404
+ " ",
1405
+ onTerms && /* @__PURE__ */ jsx28(SizableText25, { size: "$2", color: "$color9", onPress: onTerms, children: "Terms of Service" }),
1406
+ onTerms && onPrivacy && " & ",
1407
+ onPrivacy && /* @__PURE__ */ jsx28(SizableText25, { size: "$2", color: "$color9", onPress: onPrivacy, children: "Privacy Policy" })
1408
+ ] }) })
1409
+ ] });
1410
+ }
1411
+
1412
+ // src/patterns/TabBar.tsx
1413
+ import { SizableText as SizableText26, XStack as XStack18, YStack as YStack23 } from "tamagui";
1414
+ import { jsx as jsx29, jsxs as jsxs22 } from "react/jsx-runtime";
1415
+ function TabBar({ tabs, activeTab, onTabPress, showLabels = true }) {
1416
+ return /* @__PURE__ */ jsx29(XStack18, { height: 56, borderTopWidth: 1, borderTopColor: "$borderColor", backgroundColor: "$background", paddingBottom: "$2", children: tabs.map((tab) => {
1417
+ const active = tab.id === activeTab;
1418
+ return /* @__PURE__ */ jsxs22(
1419
+ YStack23,
536
1420
  {
537
- source: { uri },
538
- style: { width: "100%", height: "100%" },
539
- resizeMode: "cover"
1421
+ flex: 1,
1422
+ alignItems: "center",
1423
+ justifyContent: "center",
1424
+ gap: "$1",
1425
+ pressStyle: { opacity: 0.6 },
1426
+ onPress: () => onTabPress(tab.id),
1427
+ children: [
1428
+ tab.icon && /* @__PURE__ */ jsx29(SizableText26, { size: "$5", color: active ? "$color9" : "$color8", children: tab.icon }),
1429
+ showLabels && /* @__PURE__ */ jsx29(SizableText26, { size: "$1", color: active ? "$color9" : "$color8", fontWeight: active ? "600" : "400", children: tab.label })
1430
+ ]
1431
+ },
1432
+ tab.id
1433
+ );
1434
+ }) });
1435
+ }
1436
+
1437
+ // src/patterns/SearchBar.tsx
1438
+ import { Input as Input2, SizableText as SizableText27, XStack as XStack19 } from "tamagui";
1439
+ import { jsx as jsx30, jsxs as jsxs23 } from "react/jsx-runtime";
1440
+ function SearchBar({ value, onChangeText, placeholder = "Search\u2026", onFilter, onCancel, autoFocus }) {
1441
+ return /* @__PURE__ */ jsxs23(XStack19, { height: 44, borderRadius: "$10", backgroundColor: "$color2", alignItems: "center", paddingHorizontal: "$3", gap: "$2", children: [
1442
+ /* @__PURE__ */ jsx30(SizableText27, { size: "$4", color: "$color8", children: "\u2315" }),
1443
+ /* @__PURE__ */ jsx30(
1444
+ Input2,
1445
+ {
1446
+ flex: 1,
1447
+ size: "$4",
1448
+ value,
1449
+ onChangeText,
1450
+ placeholder,
1451
+ placeholderTextColor: "$color8",
1452
+ backgroundColor: "transparent",
1453
+ borderWidth: 0,
1454
+ autoFocus
540
1455
  }
541
- ) });
1456
+ ),
1457
+ onFilter && /* @__PURE__ */ jsx30(SizableText27, { size: "$4", color: "$color9", pressStyle: { opacity: 0.6 }, onPress: onFilter, children: "\u2ACF" }),
1458
+ onCancel && /* @__PURE__ */ jsx30(SizableText27, { size: "$3", color: "$color9", pressStyle: { opacity: 0.6 }, onPress: onCancel, children: "Cancel" })
1459
+ ] });
1460
+ }
1461
+
1462
+ // src/patterns/FloatingActionButton.tsx
1463
+ import { SizableText as SizableText28, XStack as XStack20 } from "tamagui";
1464
+ import { jsx as jsx31, jsxs as jsxs24 } from "react/jsx-runtime";
1465
+ var sizes = { sm: 44, md: 56, lg: 68 };
1466
+ var positionStyles = {
1467
+ "bottom-right": { right: 20 },
1468
+ "bottom-center": { left: "50%", marginLeft: -28 },
1469
+ "bottom-left": { left: 20 }
1470
+ };
1471
+ function FloatingActionButton({ icon, label, onPress, position = "bottom-right", size = "md" }) {
1472
+ const dim = sizes[size];
1473
+ return /* @__PURE__ */ jsxs24(
1474
+ XStack20,
1475
+ {
1476
+ position: "absolute",
1477
+ bottom: 32,
1478
+ ...positionStyles[position],
1479
+ height: dim,
1480
+ minWidth: dim,
1481
+ borderRadius: label ? "$6" : "$10",
1482
+ backgroundColor: "$color9",
1483
+ alignItems: "center",
1484
+ justifyContent: "center",
1485
+ gap: "$2",
1486
+ paddingHorizontal: label ? "$4" : 0,
1487
+ elevation: 4,
1488
+ pressStyle: { scale: 0.95, opacity: 0.9 },
1489
+ onPress,
1490
+ children: [
1491
+ icon && /* @__PURE__ */ jsx31(SizableText28, { color: "$color1", children: icon }),
1492
+ label && /* @__PURE__ */ jsx31(SizableText28, { color: "$color1", size: "$4", fontWeight: "600", children: label })
1493
+ ]
1494
+ }
1495
+ );
1496
+ }
1497
+
1498
+ // src/patterns/ActionSheet.tsx
1499
+ import { Sheet as Sheet2, SizableText as SizableText29, XStack as XStack21, YStack as YStack24 } from "tamagui";
1500
+ import { jsx as jsx32, jsxs as jsxs25 } from "react/jsx-runtime";
1501
+ function ActionSheet({ open, onOpenChange, title, items, onSelect, cancelLabel = "Cancel" }) {
1502
+ return /* @__PURE__ */ jsxs25(Sheet2, { modal: true, open, onOpenChange, snapPoints: [50], dismissOnSnapToBottom: true, animation: "medium", children: [
1503
+ /* @__PURE__ */ jsx32(Sheet2.Overlay, { animation: "lazy", enterStyle: { opacity: 0 }, exitStyle: { opacity: 0 } }),
1504
+ /* @__PURE__ */ jsx32(Sheet2.Handle, {}),
1505
+ /* @__PURE__ */ jsxs25(Sheet2.Frame, { borderTopLeftRadius: "$6", borderTopRightRadius: "$6", backgroundColor: "$background", children: [
1506
+ title && /* @__PURE__ */ jsx32(SizableText29, { size: "$3", color: "$color8", textAlign: "center", paddingTop: "$3", paddingBottom: "$1", children: title }),
1507
+ /* @__PURE__ */ jsx32(YStack24, { paddingHorizontal: "$3", paddingTop: "$2", children: items.map((item) => /* @__PURE__ */ jsxs25(
1508
+ XStack21,
1509
+ {
1510
+ height: 52,
1511
+ alignItems: "center",
1512
+ gap: "$3",
1513
+ paddingHorizontal: "$3",
1514
+ borderRadius: "$4",
1515
+ pressStyle: { backgroundColor: "$color3" },
1516
+ onPress: () => {
1517
+ onSelect(item.id);
1518
+ onOpenChange(false);
1519
+ },
1520
+ children: [
1521
+ item.icon && /* @__PURE__ */ jsx32(SizableText29, { size: "$5", children: item.icon }),
1522
+ /* @__PURE__ */ jsx32(
1523
+ SizableText29,
1524
+ {
1525
+ size: "$5",
1526
+ flex: 1,
1527
+ color: item.destructive ? "$red9" : "$color12",
1528
+ fontWeight: item.destructive ? "600" : "400",
1529
+ children: item.label
1530
+ }
1531
+ )
1532
+ ]
1533
+ },
1534
+ item.id
1535
+ )) }),
1536
+ /* @__PURE__ */ jsx32(YStack24, { paddingHorizontal: "$3", paddingVertical: "$3", borderTopWidth: 1, borderTopColor: "$borderColor", marginTop: "$2", children: /* @__PURE__ */ jsx32(
1537
+ XStack21,
1538
+ {
1539
+ height: 48,
1540
+ alignItems: "center",
1541
+ justifyContent: "center",
1542
+ borderRadius: "$4",
1543
+ pressStyle: { backgroundColor: "$color3" },
1544
+ onPress: () => onOpenChange(false),
1545
+ children: /* @__PURE__ */ jsx32(SizableText29, { size: "$5", fontWeight: "600", color: "$color9", children: cancelLabel })
1546
+ }
1547
+ ) })
1548
+ ] })
1549
+ ] });
1550
+ }
1551
+
1552
+ // src/patterns/Skeleton.tsx
1553
+ import { YStack as YStack25 } from "tamagui";
1554
+ import { jsx as jsx33 } from "react/jsx-runtime";
1555
+ function Skeleton({ width, height, borderRadius, variant = "rectangular" }) {
1556
+ const size = variant === "circular" ? height ?? 40 : height;
1557
+ const w = variant === "text" ? width ?? "100%" : width;
1558
+ const h = variant === "text" ? height ?? 16 : size;
1559
+ const r = variant === "circular" ? 9999 : borderRadius ?? 8;
1560
+ return /* @__PURE__ */ jsx33(YStack25, { width: w, height: h, borderRadius: r, backgroundColor: "$color3", opacity: 0.6, animation: "slow", enterStyle: { opacity: 0.3 }, exitStyle: { opacity: 0.3 } });
1561
+ }
1562
+
1563
+ // src/patterns/NotificationBanner.tsx
1564
+ import { SizableText as SizableText30, XStack as XStack22, YStack as YStack26 } from "tamagui";
1565
+ import { jsx as jsx34, jsxs as jsxs26 } from "react/jsx-runtime";
1566
+ var variantColors = {
1567
+ info: { bg: "$blue3", text: "$blue11" },
1568
+ success: { bg: "$green3", text: "$green11" },
1569
+ warning: { bg: "$yellow3", text: "$yellow11" },
1570
+ error: { bg: "$red3", text: "$red11" }
1571
+ };
1572
+ function NotificationBanner({ title, message, variant = "info", onPress, onDismiss, icon }) {
1573
+ const colors = variantColors[variant];
1574
+ return /* @__PURE__ */ jsxs26(
1575
+ XStack22,
1576
+ {
1577
+ backgroundColor: colors.bg,
1578
+ padding: "$3",
1579
+ borderRadius: "$4",
1580
+ gap: "$3",
1581
+ alignItems: "flex-start",
1582
+ onPress,
1583
+ pressStyle: onPress ? { opacity: 0.8 } : void 0,
1584
+ children: [
1585
+ icon && /* @__PURE__ */ jsx34(YStack26, { paddingTop: "$0.5", children: icon }),
1586
+ /* @__PURE__ */ jsxs26(YStack26, { flex: 1, gap: "$1", children: [
1587
+ /* @__PURE__ */ jsx34(SizableText30, { size: "$4", fontWeight: "600", color: colors.text, children: title }),
1588
+ message && /* @__PURE__ */ jsx34(SizableText30, { size: "$3", color: colors.text, opacity: 0.8, children: message })
1589
+ ] }),
1590
+ onDismiss && /* @__PURE__ */ jsx34(SizableText30, { size: "$3", color: colors.text, opacity: 0.6, onPress: onDismiss, padding: "$1", children: "\u2715" })
1591
+ ]
1592
+ }
1593
+ );
1594
+ }
1595
+
1596
+ // src/patterns/ProgressSteps.tsx
1597
+ import { Circle as Circle6, SizableText as SizableText31, XStack as XStack23, YStack as YStack27 } from "tamagui";
1598
+ import { jsx as jsx35, jsxs as jsxs27 } from "react/jsx-runtime";
1599
+ function ProgressSteps({ steps, currentStep, variant = "dots" }) {
1600
+ if (variant === "bar") {
1601
+ const progress = steps.length > 1 ? currentStep / (steps.length - 1) * 100 : 100;
1602
+ return /* @__PURE__ */ jsxs27(YStack27, { gap: "$2", children: [
1603
+ /* @__PURE__ */ jsx35(YStack27, { height: 4, backgroundColor: "$color4", borderRadius: 2, overflow: "hidden", children: /* @__PURE__ */ jsx35(YStack27, { height: 4, width: `${progress}%`, backgroundColor: "$color9", borderRadius: 2, animation: "quick" }) }),
1604
+ /* @__PURE__ */ jsx35(XStack23, { justifyContent: "space-between", children: steps.map((label, i) => /* @__PURE__ */ jsx35(SizableText31, { size: "$2", color: i <= currentStep ? "$color9" : "$color8", children: label }, i)) })
1605
+ ] });
542
1606
  }
543
- return /* @__PURE__ */ jsx2(AvatarFrame, { size, ...props, children: /* @__PURE__ */ jsx2(AvatarInitials, { size, children: name ? getInitials(name) : "?" }) });
1607
+ return /* @__PURE__ */ jsx35(XStack23, { alignItems: "center", justifyContent: "center", gap: "$0", children: steps.map((label, i) => /* @__PURE__ */ jsxs27(XStack23, { alignItems: "center", gap: "$0", children: [
1608
+ /* @__PURE__ */ jsxs27(YStack27, { alignItems: "center", gap: "$1.5", children: [
1609
+ /* @__PURE__ */ jsx35(Circle6, { size: variant === "numbered" ? 28 : 10, backgroundColor: i <= currentStep ? "$color9" : "$color4", animation: "quick", children: variant === "numbered" && /* @__PURE__ */ jsx35(SizableText31, { size: "$2", fontWeight: "600", color: i <= currentStep ? "$color1" : "$color8", children: i + 1 }) }),
1610
+ /* @__PURE__ */ jsx35(SizableText31, { size: "$1", color: i <= currentStep ? "$color11" : "$color8", numberOfLines: 1, children: label })
1611
+ ] }),
1612
+ i < steps.length - 1 && /* @__PURE__ */ jsx35(YStack27, { height: 2, width: 32, backgroundColor: i < currentStep ? "$color9" : "$color4", marginBottom: "$4" })
1613
+ ] }, i)) });
1614
+ }
1615
+
1616
+ // src/patterns/SwipeableRow.tsx
1617
+ import { useState as useState7 } from "react";
1618
+ import { Button as Button7, SizableText as SizableText32, XStack as XStack24, YStack as YStack28 } from "tamagui";
1619
+ import { Fragment as Fragment2, jsx as jsx36, jsxs as jsxs28 } from "react/jsx-runtime";
1620
+ function SwipeableRow({ children, leftActions, rightActions }) {
1621
+ const [showActions, setShowActions] = useState7(false);
1622
+ const actions = [...leftActions ?? [], ...rightActions ?? []];
1623
+ if (actions.length === 0) return /* @__PURE__ */ jsx36(Fragment2, { children });
1624
+ return /* @__PURE__ */ jsxs28(YStack28, { children: [
1625
+ /* @__PURE__ */ jsx36(YStack28, { onLongPress: () => setShowActions((v) => !v), pressStyle: { opacity: 0.9 }, children }),
1626
+ showActions && /* @__PURE__ */ jsx36(XStack24, { gap: "$2", padding: "$2", animation: "quick", enterStyle: { opacity: 0, scale: 0.95 }, children: actions.map((action) => /* @__PURE__ */ jsx36(
1627
+ Button7,
1628
+ {
1629
+ flex: 1,
1630
+ size: "$3",
1631
+ backgroundColor: action.color,
1632
+ borderRadius: "$3",
1633
+ onPress: () => {
1634
+ action.onPress();
1635
+ setShowActions(false);
1636
+ },
1637
+ children: /* @__PURE__ */ jsx36(SizableText32, { size: "$2", fontWeight: "600", color: "white", children: action.label })
1638
+ },
1639
+ action.id
1640
+ )) })
1641
+ ] });
1642
+ }
1643
+
1644
+ // src/patterns/MediaCard.tsx
1645
+ import { Image as Image5, SizableText as SizableText33, XStack as XStack25, YStack as YStack29 } from "tamagui";
1646
+ import { LinearGradient } from "tamagui/linear-gradient";
1647
+ import { jsx as jsx37, jsxs as jsxs29 } from "react/jsx-runtime";
1648
+ function MediaCard({ image, title, subtitle, overlay = "gradient", aspectRatio = 16 / 9, onPress, badge }) {
1649
+ return /* @__PURE__ */ jsx37(
1650
+ YStack29,
1651
+ {
1652
+ borderRadius: "$4",
1653
+ overflow: "hidden",
1654
+ onPress,
1655
+ pressStyle: onPress ? { scale: 0.98, opacity: 0.9 } : void 0,
1656
+ animation: "quick",
1657
+ children: /* @__PURE__ */ jsxs29(YStack29, { aspectRatio, children: [
1658
+ /* @__PURE__ */ jsx37(Image5, { source: { uri: image }, width: "100%", height: "100%", objectFit: "cover" }),
1659
+ overlay === "gradient" && /* @__PURE__ */ jsx37(
1660
+ LinearGradient,
1661
+ {
1662
+ colors: ["transparent", "rgba(0,0,0,0.7)"],
1663
+ start: [0, 0],
1664
+ end: [0, 1],
1665
+ position: "absolute",
1666
+ bottom: 0,
1667
+ left: 0,
1668
+ right: 0,
1669
+ height: "60%"
1670
+ }
1671
+ ),
1672
+ overlay === "dark" && /* @__PURE__ */ jsx37(YStack29, { position: "absolute", fullscreen: true, backgroundColor: "rgba(0,0,0,0.4)" }),
1673
+ badge && /* @__PURE__ */ jsx37(
1674
+ XStack25,
1675
+ {
1676
+ position: "absolute",
1677
+ top: "$2",
1678
+ right: "$2",
1679
+ backgroundColor: "$color9",
1680
+ paddingHorizontal: "$2",
1681
+ paddingVertical: "$1",
1682
+ borderRadius: "$2",
1683
+ children: /* @__PURE__ */ jsx37(SizableText33, { size: "$1", fontWeight: "600", color: "$color1", children: badge })
1684
+ }
1685
+ ),
1686
+ /* @__PURE__ */ jsxs29(YStack29, { position: "absolute", bottom: 0, left: 0, right: 0, padding: "$3", gap: "$1", children: [
1687
+ /* @__PURE__ */ jsx37(SizableText33, { size: "$5", fontWeight: "600", color: "white", children: title }),
1688
+ subtitle && /* @__PURE__ */ jsx37(SizableText33, { size: "$3", color: "rgba(255,255,255,0.8)", children: subtitle })
1689
+ ] })
1690
+ ] })
1691
+ }
1692
+ );
1693
+ }
1694
+
1695
+ // src/patterns/Carousel.tsx
1696
+ import { Children as Children2, useState as useState8 } from "react";
1697
+ import { Circle as Circle7, XStack as XStack26, YStack as YStack30 } from "tamagui";
1698
+ import { ScrollView as ScrollView3 } from "react-native";
1699
+ import { jsx as jsx38, jsxs as jsxs30 } from "react/jsx-runtime";
1700
+ function Carousel({ children, gap = "$3", snapToInterval, showIndicators = false }) {
1701
+ const [activeIndex, setActiveIndex] = useState8(0);
1702
+ const count = Children2.count(children);
1703
+ const gapPx = gap === "$2" ? 8 : gap === "$3" ? 12 : 16;
1704
+ return /* @__PURE__ */ jsxs30(YStack30, { gap: "$3", children: [
1705
+ /* @__PURE__ */ jsx38(
1706
+ ScrollView3,
1707
+ {
1708
+ horizontal: true,
1709
+ showsHorizontalScrollIndicator: false,
1710
+ snapToInterval,
1711
+ decelerationRate: "fast",
1712
+ contentContainerStyle: { gap: gapPx, paddingHorizontal: 16 },
1713
+ onMomentumScrollEnd: (e) => {
1714
+ if (snapToInterval) setActiveIndex(Math.round(e.nativeEvent.contentOffset.x / snapToInterval));
1715
+ },
1716
+ children
1717
+ }
1718
+ ),
1719
+ showIndicators && count > 1 && /* @__PURE__ */ jsx38(XStack26, { justifyContent: "center", gap: "$1.5", children: Array.from({ length: count }, (_, i) => /* @__PURE__ */ jsx38(Circle7, { size: 6, backgroundColor: i === activeIndex ? "$color9" : "$color4", animation: "quick" }, i)) })
1720
+ ] });
1721
+ }
1722
+
1723
+ // src/patterns/PullToRefresh.tsx
1724
+ import { YStack as YStack31 } from "tamagui";
1725
+ import { RefreshControl, ScrollView as ScrollView4 } from "react-native";
1726
+ import { jsx as jsx39 } from "react/jsx-runtime";
1727
+ function PullToRefresh({ children, onRefresh, refreshing = false }) {
1728
+ return /* @__PURE__ */ jsx39(
1729
+ ScrollView4,
1730
+ {
1731
+ contentContainerStyle: { flexGrow: 1 },
1732
+ refreshControl: /* @__PURE__ */ jsx39(RefreshControl, { refreshing, onRefresh }),
1733
+ children: /* @__PURE__ */ jsx39(YStack31, { flex: 1, children })
1734
+ }
1735
+ );
544
1736
  }
545
1737
  export {
546
- Avatar,
1738
+ Accordion,
1739
+ ActionSheet,
1740
+ Adapt,
1741
+ AlertDialog2 as AlertDialog,
1742
+ Anchor,
1743
+ AnimatePresence,
1744
+ AppHeader,
1745
+ Article,
1746
+ Aside,
1747
+ Avatar2 as Avatar,
1748
+ Badge,
1749
+ BlinkAccordion,
1750
+ Avatar as BlinkAvatar,
1751
+ Button as BlinkButton,
1752
+ Card as BlinkCard,
1753
+ Input as BlinkInput,
1754
+ TamaguiProvider2 as BlinkProvider,
1755
+ BlinkTabs,
547
1756
  BlinkText,
548
- Button,
549
- Card,
550
- Input,
551
- blinkConfig
1757
+ BlinkToastProvider,
1758
+ BlinkToggleGroup,
1759
+ BlinkTooltip,
1760
+ BottomSheet,
1761
+ Button8 as Button,
1762
+ Card2 as Card,
1763
+ Carousel,
1764
+ ChatBubble,
1765
+ Checkbox,
1766
+ Circle8 as Circle,
1767
+ Container,
1768
+ Dialog,
1769
+ DialogProvider,
1770
+ Divider,
1771
+ EmptyState,
1772
+ EnsureFlexed,
1773
+ Fieldset,
1774
+ FloatingActionButton,
1775
+ Footer,
1776
+ Form,
1777
+ FormField,
1778
+ Frame,
1779
+ Grid,
1780
+ Group,
1781
+ H12 as H1,
1782
+ H22 as H2,
1783
+ H32 as H3,
1784
+ H42 as H4,
1785
+ H52 as H5,
1786
+ H62 as H6,
1787
+ Header,
1788
+ Heading,
1789
+ ICONS,
1790
+ Icon,
1791
+ Image2 as Image,
1792
+ Input3 as Input,
1793
+ KeyboardStickyFooter,
1794
+ Label,
1795
+ ListItem,
1796
+ LoginScreen,
1797
+ Main,
1798
+ MediaCard,
1799
+ Nav,
1800
+ NotificationBanner,
1801
+ OnboardingCarousel,
1802
+ PageContainer,
1803
+ PageMainContainer,
1804
+ Paragraph,
1805
+ PaywallScreen,
1806
+ Popover2 as Popover,
1807
+ Portal,
1808
+ PortalHost,
1809
+ PortalItem,
1810
+ PortalProvider,
1811
+ Pressable,
1812
+ ProfileHeader,
1813
+ Progress,
1814
+ ProgressSteps,
1815
+ PullToRefresh,
1816
+ RadioGroup,
1817
+ SafeArea,
1818
+ ScreenLayout,
1819
+ ScrollView5 as ScrollView,
1820
+ SearchBar,
1821
+ Section,
1822
+ Select,
1823
+ SepHeading,
1824
+ Separator5 as Separator,
1825
+ SettingsScreen,
1826
+ Sheet3 as Sheet,
1827
+ SizableStack,
1828
+ SizableText34 as SizableText,
1829
+ Skeleton,
1830
+ Slider,
1831
+ Spacer,
1832
+ Spinner2 as Spinner,
1833
+ Square,
1834
+ Stack,
1835
+ StepPageLayout,
1836
+ SubHeading,
1837
+ SwipeableRow,
1838
+ Switch2 as Switch,
1839
+ TabBar,
1840
+ Tabs,
1841
+ Image6 as TamaguiImage,
1842
+ ListItem2 as TamaguiListItem,
1843
+ TamaguiProvider,
1844
+ Text,
1845
+ TextArea,
1846
+ Theme,
1847
+ ThemeableStack,
1848
+ ToggleGroup,
1849
+ Tooltip,
1850
+ TooltipSimple,
1851
+ Unspaced,
1852
+ View6 as View,
1853
+ VisuallyHidden,
1854
+ XGroup,
1855
+ XStack27 as XStack,
1856
+ YGroup,
1857
+ YStack32 as YStack,
1858
+ ZStack,
1859
+ addTheme,
1860
+ blinkConfig,
1861
+ composeEventHandlers,
1862
+ composeRefs,
1863
+ createFont,
1864
+ createMedia,
1865
+ createStyledContext,
1866
+ createTamagui2 as createTamagui,
1867
+ createTheme,
1868
+ createTokens,
1869
+ createVariable,
1870
+ dialogConfirm,
1871
+ getConfig,
1872
+ getToken,
1873
+ getTokenValue,
1874
+ getTokens,
1875
+ isClient,
1876
+ isWeb,
1877
+ replaceTheme,
1878
+ showError,
1879
+ styled12 as styled,
1880
+ defaultConfig2 as tamaguiDefaultConfig,
1881
+ toast,
1882
+ updateTheme,
1883
+ useBlinkToast,
1884
+ useComposedRefs,
1885
+ useControllableState,
1886
+ useDebounce,
1887
+ useDebounceValue,
1888
+ useDidFinishSSR,
1889
+ useEvent,
1890
+ useForceUpdate,
1891
+ useIsPresent,
1892
+ useIsomorphicLayoutEffect,
1893
+ useMedia,
1894
+ usePresence,
1895
+ useTheme,
1896
+ useThemeName,
1897
+ useWindowDimensions,
1898
+ withStaticProperties2 as withStaticProperties
552
1899
  };
553
1900
  //# sourceMappingURL=index.mjs.map