@blinkdotnew/mobile-ui 2.0.0-alpha.5 → 2.0.0-alpha.7
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 +330 -30
- package/dist/index.d.ts +330 -30
- package/dist/index.js +980 -157
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +932 -136
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -8,11 +8,14 @@ var blinkConfig = createTamagui({
|
|
|
8
8
|
// src/index.ts
|
|
9
9
|
import {
|
|
10
10
|
View as View6,
|
|
11
|
-
XStack as
|
|
12
|
-
YStack as
|
|
11
|
+
XStack as XStack26,
|
|
12
|
+
YStack as YStack32,
|
|
13
13
|
ZStack,
|
|
14
|
-
ScrollView,
|
|
15
|
-
Circle as
|
|
14
|
+
ScrollView as ScrollView5,
|
|
15
|
+
Circle as Circle8,
|
|
16
|
+
Square,
|
|
17
|
+
XGroup,
|
|
18
|
+
YGroup,
|
|
16
19
|
H1 as H12,
|
|
17
20
|
H2 as H22,
|
|
18
21
|
H3 as H32,
|
|
@@ -20,28 +23,40 @@ import {
|
|
|
20
23
|
H5 as H52,
|
|
21
24
|
H6 as H62,
|
|
22
25
|
Paragraph,
|
|
23
|
-
SizableText as
|
|
26
|
+
SizableText as SizableText34,
|
|
24
27
|
Text,
|
|
25
|
-
|
|
26
|
-
|
|
28
|
+
Label,
|
|
29
|
+
Button as Button8,
|
|
30
|
+
Input as Input3,
|
|
27
31
|
TextArea,
|
|
28
32
|
Switch as Switch2,
|
|
29
33
|
Checkbox,
|
|
30
34
|
Slider,
|
|
31
35
|
RadioGroup,
|
|
32
36
|
Select,
|
|
33
|
-
|
|
37
|
+
Fieldset,
|
|
34
38
|
Card as Card2,
|
|
35
39
|
Avatar as Avatar2,
|
|
36
|
-
Separator as
|
|
37
|
-
Image as
|
|
40
|
+
Separator as Separator5,
|
|
41
|
+
Image as Image6,
|
|
38
42
|
Progress,
|
|
39
|
-
Spinner,
|
|
40
|
-
|
|
43
|
+
Spinner as Spinner2,
|
|
44
|
+
ListItem as ListItem2,
|
|
45
|
+
Sheet as Sheet3,
|
|
41
46
|
Dialog,
|
|
42
47
|
AlertDialog as AlertDialog2,
|
|
43
|
-
Popover,
|
|
48
|
+
Popover as Popover2,
|
|
44
49
|
Tooltip,
|
|
50
|
+
TooltipSimple,
|
|
51
|
+
Tabs,
|
|
52
|
+
Accordion,
|
|
53
|
+
ToggleGroup,
|
|
54
|
+
Adapt,
|
|
55
|
+
PortalProvider,
|
|
56
|
+
VisuallyHidden,
|
|
57
|
+
Unspaced,
|
|
58
|
+
Anchor,
|
|
59
|
+
Form,
|
|
45
60
|
Theme,
|
|
46
61
|
TamaguiProvider,
|
|
47
62
|
styled as styled12,
|
|
@@ -523,23 +538,282 @@ function Badge({ children, variant = "default" }) {
|
|
|
523
538
|
return /* @__PURE__ */ jsx5(BadgeFrame, { variant, children: /* @__PURE__ */ jsx5(BadgeText, { children }) });
|
|
524
539
|
}
|
|
525
540
|
|
|
541
|
+
// src/interface/Icon.tsx
|
|
542
|
+
import { SizableText as SizableText6 } from "tamagui";
|
|
543
|
+
import { jsx as jsx6 } from "react/jsx-runtime";
|
|
544
|
+
var ICONS = {
|
|
545
|
+
home: "\u2302",
|
|
546
|
+
search: "\u2315",
|
|
547
|
+
back: "\u2039",
|
|
548
|
+
forward: "\u203A",
|
|
549
|
+
close: "\u2715",
|
|
550
|
+
menu: "\u2630",
|
|
551
|
+
more: "\u22EF",
|
|
552
|
+
plus: "+",
|
|
553
|
+
minus: "\u2212",
|
|
554
|
+
check: "\u2713",
|
|
555
|
+
star: "\u2605",
|
|
556
|
+
starOutline: "\u2606",
|
|
557
|
+
heart: "\u2665",
|
|
558
|
+
heartOutline: "\u2661",
|
|
559
|
+
share: "\u2934",
|
|
560
|
+
edit: "\u270E",
|
|
561
|
+
trash: "\u232B",
|
|
562
|
+
copy: "\u2398",
|
|
563
|
+
chat: "\u{1F4AC}",
|
|
564
|
+
mail: "\u2709",
|
|
565
|
+
bell: "\u{1F514}",
|
|
566
|
+
bellOff: "\u{1F515}",
|
|
567
|
+
send: "\u27A4",
|
|
568
|
+
play: "\u25B6",
|
|
569
|
+
pause: "\u23F8",
|
|
570
|
+
camera: "\u{1F4F7}",
|
|
571
|
+
image: "\u{1F5BC}",
|
|
572
|
+
info: "\u2139",
|
|
573
|
+
warning: "\u26A0",
|
|
574
|
+
error: "\u2715",
|
|
575
|
+
success: "\u2713",
|
|
576
|
+
loading: "\u27F3",
|
|
577
|
+
user: "\u{1F464}",
|
|
578
|
+
users: "\u{1F465}",
|
|
579
|
+
settings: "\u2699",
|
|
580
|
+
lock: "\u{1F512}",
|
|
581
|
+
unlock: "\u{1F513}",
|
|
582
|
+
arrowUp: "\u2191",
|
|
583
|
+
arrowDown: "\u2193",
|
|
584
|
+
arrowLeft: "\u2190",
|
|
585
|
+
arrowRight: "\u2192",
|
|
586
|
+
chevronUp: "\u2303",
|
|
587
|
+
chevronDown: "\u2304",
|
|
588
|
+
chevronLeft: "\u2039",
|
|
589
|
+
chevronRight: "\u203A"
|
|
590
|
+
};
|
|
591
|
+
function Icon({ name, size = 20, color = "$color12" }) {
|
|
592
|
+
return /* @__PURE__ */ jsx6(SizableText6, { fontSize: size, lineHeight: size, color, textAlign: "center", width: size, height: size, children: ICONS[name] });
|
|
593
|
+
}
|
|
594
|
+
|
|
595
|
+
// src/interface/BlinkAccordion.tsx
|
|
596
|
+
import { useState as useState2 } from "react";
|
|
597
|
+
import { Separator as Separator2, SizableText as SizableText7, XStack as XStack3, YStack as YStack3 } from "tamagui";
|
|
598
|
+
import { jsx as jsx7, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
599
|
+
function BlinkAccordion({ items, defaultOpen, allowMultiple = false }) {
|
|
600
|
+
const [openIds, setOpenIds] = useState2(defaultOpen ?? []);
|
|
601
|
+
const toggle = (id) => {
|
|
602
|
+
setOpenIds((prev) => {
|
|
603
|
+
if (prev.includes(id)) return prev.filter((i) => i !== id);
|
|
604
|
+
return allowMultiple ? [...prev, id] : [id];
|
|
605
|
+
});
|
|
606
|
+
};
|
|
607
|
+
return /* @__PURE__ */ jsx7(YStack3, { children: items.map((item, index) => {
|
|
608
|
+
const isOpen = openIds.includes(item.id);
|
|
609
|
+
return /* @__PURE__ */ jsxs4(YStack3, { children: [
|
|
610
|
+
index > 0 && /* @__PURE__ */ jsx7(Separator2, { borderColor: "$borderColor" }),
|
|
611
|
+
/* @__PURE__ */ jsxs4(
|
|
612
|
+
XStack3,
|
|
613
|
+
{
|
|
614
|
+
paddingVertical: "$3",
|
|
615
|
+
paddingHorizontal: "$2",
|
|
616
|
+
justifyContent: "space-between",
|
|
617
|
+
alignItems: "center",
|
|
618
|
+
pressStyle: { opacity: 0.7 },
|
|
619
|
+
onPress: () => toggle(item.id),
|
|
620
|
+
cursor: "pointer",
|
|
621
|
+
children: [
|
|
622
|
+
/* @__PURE__ */ jsx7(SizableText7, { size: "$4", fontWeight: "600", children: item.title }),
|
|
623
|
+
/* @__PURE__ */ jsx7(SizableText7, { size: "$3", color: "$color10", children: isOpen ? "\u2303" : "\u2304" })
|
|
624
|
+
]
|
|
625
|
+
}
|
|
626
|
+
),
|
|
627
|
+
isOpen && /* @__PURE__ */ jsx7(YStack3, { paddingHorizontal: "$2", paddingBottom: "$3", children: item.content })
|
|
628
|
+
] }, item.id);
|
|
629
|
+
}) });
|
|
630
|
+
}
|
|
631
|
+
|
|
632
|
+
// src/interface/BlinkTabs.tsx
|
|
633
|
+
import { useState as useState3 } from "react";
|
|
634
|
+
import { ScrollView } from "react-native";
|
|
635
|
+
import { SizableText as SizableText8, XStack as XStack4, YStack as YStack4 } from "tamagui";
|
|
636
|
+
import { jsx as jsx8 } from "react/jsx-runtime";
|
|
637
|
+
function BlinkTabs({ tabs, activeTab, onTabChange, variant = "underline" }) {
|
|
638
|
+
const [internalActive, setInternalActive] = useState3(tabs[0]?.key ?? "");
|
|
639
|
+
const current = activeTab ?? internalActive;
|
|
640
|
+
const handlePress = (key) => {
|
|
641
|
+
if (!activeTab) setInternalActive(key);
|
|
642
|
+
onTabChange?.(key);
|
|
643
|
+
};
|
|
644
|
+
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) => {
|
|
645
|
+
const isActive = tab.key === current;
|
|
646
|
+
return /* @__PURE__ */ jsx8(
|
|
647
|
+
YStack4,
|
|
648
|
+
{
|
|
649
|
+
paddingVertical: "$2",
|
|
650
|
+
paddingHorizontal: "$3",
|
|
651
|
+
borderRadius: variant === "pill" ? "$4" : "$0",
|
|
652
|
+
backgroundColor: variant === "pill" && isActive ? "$color9" : "transparent",
|
|
653
|
+
borderBottomWidth: variant === "underline" ? 2 : 0,
|
|
654
|
+
borderBottomColor: variant === "underline" && isActive ? "$color9" : "transparent",
|
|
655
|
+
pressStyle: { opacity: 0.7 },
|
|
656
|
+
onPress: () => handlePress(tab.key),
|
|
657
|
+
cursor: "pointer",
|
|
658
|
+
children: /* @__PURE__ */ jsx8(
|
|
659
|
+
SizableText8,
|
|
660
|
+
{
|
|
661
|
+
size: "$3",
|
|
662
|
+
fontWeight: isActive ? "600" : "400",
|
|
663
|
+
color: variant === "pill" && isActive ? "$color1" : isActive ? "$color12" : "$color10",
|
|
664
|
+
children: tab.label
|
|
665
|
+
}
|
|
666
|
+
)
|
|
667
|
+
},
|
|
668
|
+
tab.key
|
|
669
|
+
);
|
|
670
|
+
}) }) }) });
|
|
671
|
+
}
|
|
672
|
+
|
|
673
|
+
// src/interface/BlinkToggleGroup.tsx
|
|
674
|
+
import { SizableText as SizableText9, XStack as XStack5 } from "tamagui";
|
|
675
|
+
import { jsx as jsx9 } from "react/jsx-runtime";
|
|
676
|
+
var sizeMap = { sm: "$2", md: "$3", lg: "$4" };
|
|
677
|
+
function BlinkToggleGroup({ options, value, onValueChange, size = "md" }) {
|
|
678
|
+
const textSize = sizeMap[size];
|
|
679
|
+
return /* @__PURE__ */ jsx9(XStack5, { borderRadius: "$4", overflow: "hidden", backgroundColor: "$color2", children: options.map((option, index) => {
|
|
680
|
+
const isActive = option.value === value;
|
|
681
|
+
return /* @__PURE__ */ jsx9(
|
|
682
|
+
XStack5,
|
|
683
|
+
{
|
|
684
|
+
flex: 1,
|
|
685
|
+
justifyContent: "center",
|
|
686
|
+
alignItems: "center",
|
|
687
|
+
paddingVertical: "$2",
|
|
688
|
+
paddingHorizontal: "$3",
|
|
689
|
+
backgroundColor: isActive ? "$color9" : "$color2",
|
|
690
|
+
borderLeftWidth: index > 0 ? 1 : 0,
|
|
691
|
+
borderLeftColor: isActive ? "$color9" : "$color4",
|
|
692
|
+
pressStyle: { opacity: 0.7 },
|
|
693
|
+
onPress: () => onValueChange(option.value),
|
|
694
|
+
cursor: "pointer",
|
|
695
|
+
children: /* @__PURE__ */ jsx9(SizableText9, { size: textSize, fontWeight: isActive ? "600" : "400", color: isActive ? "$color1" : "$color11", children: option.label })
|
|
696
|
+
},
|
|
697
|
+
option.value
|
|
698
|
+
);
|
|
699
|
+
}) });
|
|
700
|
+
}
|
|
701
|
+
|
|
702
|
+
// src/interface/BlinkToast.tsx
|
|
703
|
+
import { useState as useState4, useCallback, useEffect as useEffect2, createContext, useContext } from "react";
|
|
704
|
+
import { SizableText as SizableText10, YStack as YStack5 } from "tamagui";
|
|
705
|
+
import { jsx as jsx10, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
706
|
+
var ToastContext = createContext(null);
|
|
707
|
+
var variantColors = {
|
|
708
|
+
default: "$color9",
|
|
709
|
+
success: "$green9",
|
|
710
|
+
error: "$red9",
|
|
711
|
+
warning: "$yellow9"
|
|
712
|
+
};
|
|
713
|
+
var globalToastShow = null;
|
|
714
|
+
var toast = (message, variant, duration) => {
|
|
715
|
+
if (globalToastShow) globalToastShow(message, variant, duration);
|
|
716
|
+
else console.warn("BlinkToastProvider not mounted");
|
|
717
|
+
};
|
|
718
|
+
function BlinkToastProvider({ children }) {
|
|
719
|
+
const [toasts, setToasts] = useState4([]);
|
|
720
|
+
const show = useCallback((message, variant = "default", duration = 3e3) => {
|
|
721
|
+
const id = Math.random().toString(36).slice(2, 9);
|
|
722
|
+
setToasts((prev) => [...prev, { id, message, variant, duration }]);
|
|
723
|
+
setTimeout(() => setToasts((prev) => prev.filter((t) => t.id !== id)), duration);
|
|
724
|
+
}, []);
|
|
725
|
+
useEffect2(() => {
|
|
726
|
+
globalToastShow = show;
|
|
727
|
+
return () => {
|
|
728
|
+
globalToastShow = null;
|
|
729
|
+
};
|
|
730
|
+
}, [show]);
|
|
731
|
+
return /* @__PURE__ */ jsxs5(ToastContext.Provider, { value: { show }, children: [
|
|
732
|
+
children,
|
|
733
|
+
/* @__PURE__ */ jsx10(YStack5, { position: "absolute", top: 60, left: 0, right: 0, alignItems: "center", gap: "$2", pointerEvents: "none", zIndex: 1e5, children: toasts.map((t) => /* @__PURE__ */ jsx10(
|
|
734
|
+
YStack5,
|
|
735
|
+
{
|
|
736
|
+
backgroundColor: variantColors[t.variant ?? "default"],
|
|
737
|
+
paddingHorizontal: "$4",
|
|
738
|
+
paddingVertical: "$2.5",
|
|
739
|
+
borderRadius: "$4",
|
|
740
|
+
enterStyle: { opacity: 0, y: -10 },
|
|
741
|
+
exitStyle: { opacity: 0, y: -10 },
|
|
742
|
+
opacity: 1,
|
|
743
|
+
y: 0,
|
|
744
|
+
animation: "quick",
|
|
745
|
+
children: /* @__PURE__ */ jsx10(SizableText10, { size: "$3", color: "white", fontWeight: "600", children: t.message })
|
|
746
|
+
},
|
|
747
|
+
t.id
|
|
748
|
+
)) })
|
|
749
|
+
] });
|
|
750
|
+
}
|
|
751
|
+
function useBlinkToast() {
|
|
752
|
+
const ctx = useContext(ToastContext);
|
|
753
|
+
if (!ctx) throw new Error("useBlinkToast must be used within BlinkToastProvider");
|
|
754
|
+
return ctx;
|
|
755
|
+
}
|
|
756
|
+
|
|
757
|
+
// src/interface/FormField.tsx
|
|
758
|
+
import { SizableText as SizableText11, YStack as YStack6 } from "tamagui";
|
|
759
|
+
import { jsx as jsx11, jsxs as jsxs6 } from "react/jsx-runtime";
|
|
760
|
+
function FormField({ label, error, helperText, required, children }) {
|
|
761
|
+
return /* @__PURE__ */ jsxs6(YStack6, { gap: "$1.5", children: [
|
|
762
|
+
label && /* @__PURE__ */ jsxs6(SizableText11, { size: "$3", fontWeight: "600", color: "$color11", children: [
|
|
763
|
+
label,
|
|
764
|
+
required && /* @__PURE__ */ jsx11(SizableText11, { color: "$red9", children: " *" })
|
|
765
|
+
] }),
|
|
766
|
+
children,
|
|
767
|
+
helperText && !error && /* @__PURE__ */ jsx11(SizableText11, { size: "$2", color: "$color9", children: helperText }),
|
|
768
|
+
error && /* @__PURE__ */ jsx11(SizableText11, { size: "$2", color: "$red9", children: error })
|
|
769
|
+
] });
|
|
770
|
+
}
|
|
771
|
+
|
|
772
|
+
// src/interface/Tooltip.tsx
|
|
773
|
+
import { Popover, SizableText as SizableText12 } from "tamagui";
|
|
774
|
+
import { jsx as jsx12, jsxs as jsxs7 } from "react/jsx-runtime";
|
|
775
|
+
function BlinkTooltip({ content, children, side = "top" }) {
|
|
776
|
+
return /* @__PURE__ */ jsxs7(Popover, { size: "$2", placement: side, children: [
|
|
777
|
+
/* @__PURE__ */ jsx12(Popover.Trigger, { asChild: true, children }),
|
|
778
|
+
/* @__PURE__ */ jsxs7(
|
|
779
|
+
Popover.Content,
|
|
780
|
+
{
|
|
781
|
+
backgroundColor: "$color11",
|
|
782
|
+
borderRadius: "$2",
|
|
783
|
+
paddingHorizontal: "$2.5",
|
|
784
|
+
paddingVertical: "$1.5",
|
|
785
|
+
elevate: true,
|
|
786
|
+
enterStyle: { opacity: 0, y: side === "bottom" ? -4 : 4 },
|
|
787
|
+
exitStyle: { opacity: 0, y: side === "bottom" ? -4 : 4 },
|
|
788
|
+
opacity: 1,
|
|
789
|
+
y: 0,
|
|
790
|
+
animation: "quick",
|
|
791
|
+
children: [
|
|
792
|
+
/* @__PURE__ */ jsx12(Popover.Arrow, { backgroundColor: "$color11", size: "$1" }),
|
|
793
|
+
/* @__PURE__ */ jsx12(SizableText12, { size: "$2", color: "$color1", children: content })
|
|
794
|
+
]
|
|
795
|
+
}
|
|
796
|
+
)
|
|
797
|
+
] });
|
|
798
|
+
}
|
|
799
|
+
|
|
526
800
|
// src/layouts/StepPageLayout.tsx
|
|
527
|
-
import { SizableText as
|
|
528
|
-
import { jsx as
|
|
801
|
+
import { SizableText as SizableText13, YStack as YStack7 } from "tamagui";
|
|
802
|
+
import { jsx as jsx13, jsxs as jsxs8 } from "react/jsx-runtime";
|
|
529
803
|
function StepPageLayout({ title, description, children, bottom }) {
|
|
530
|
-
return /* @__PURE__ */
|
|
531
|
-
/* @__PURE__ */
|
|
532
|
-
/* @__PURE__ */
|
|
533
|
-
description && /* @__PURE__ */
|
|
804
|
+
return /* @__PURE__ */ jsxs8(YStack7, { flex: 1, padding: "$4", maxWidth: 500, marginHorizontal: "auto", width: "100%", children: [
|
|
805
|
+
/* @__PURE__ */ jsx13(YStack7, { gap: "$5", children: /* @__PURE__ */ jsxs8(YStack7, { gap: "$2", children: [
|
|
806
|
+
/* @__PURE__ */ jsx13(SizableText13, { size: "$8", fontWeight: "700", children: title }),
|
|
807
|
+
description && /* @__PURE__ */ jsx13(SizableText13, { size: "$5", fontWeight: "400", color: "$color10", children: description })
|
|
534
808
|
] }) }),
|
|
535
|
-
/* @__PURE__ */
|
|
536
|
-
bottom && /* @__PURE__ */
|
|
809
|
+
/* @__PURE__ */ jsx13(YStack7, { paddingTop: "$5", gap: "$4", children }),
|
|
810
|
+
bottom && /* @__PURE__ */ jsx13(YStack7, { paddingTop: "$4", children: bottom })
|
|
537
811
|
] });
|
|
538
812
|
}
|
|
539
813
|
|
|
540
814
|
// src/layouts/ScreenLayout.tsx
|
|
541
|
-
import { styled as styled10, YStack as
|
|
542
|
-
var ScreenLayout = styled10(
|
|
815
|
+
import { styled as styled10, YStack as YStack8 } from "tamagui";
|
|
816
|
+
var ScreenLayout = styled10(YStack8, {
|
|
543
817
|
name: "BlinkScreenLayout",
|
|
544
818
|
flex: 1,
|
|
545
819
|
backgroundColor: "$background",
|
|
@@ -557,22 +831,22 @@ var ScreenLayout = styled10(YStack4, {
|
|
|
557
831
|
});
|
|
558
832
|
|
|
559
833
|
// src/layouts/Section.tsx
|
|
560
|
-
import { SizableText as
|
|
561
|
-
import { jsx as
|
|
834
|
+
import { SizableText as SizableText14, YStack as YStack9 } from "tamagui";
|
|
835
|
+
import { jsx as jsx14, jsxs as jsxs9 } from "react/jsx-runtime";
|
|
562
836
|
function Section({ title, description, children, gap = "$3" }) {
|
|
563
|
-
return /* @__PURE__ */
|
|
564
|
-
title && /* @__PURE__ */
|
|
565
|
-
/* @__PURE__ */
|
|
566
|
-
description && /* @__PURE__ */
|
|
837
|
+
return /* @__PURE__ */ jsxs9(YStack9, { gap, children: [
|
|
838
|
+
title && /* @__PURE__ */ jsxs9(YStack9, { gap: "$1", children: [
|
|
839
|
+
/* @__PURE__ */ jsx14(SizableText14, { size: "$5", fontWeight: "600", color: "$color12", children: title }),
|
|
840
|
+
description && /* @__PURE__ */ jsx14(SizableText14, { size: "$3", color: "$color9", children: description })
|
|
567
841
|
] }),
|
|
568
842
|
children
|
|
569
843
|
] });
|
|
570
844
|
}
|
|
571
845
|
|
|
572
846
|
// src/layouts/ListItem.tsx
|
|
573
|
-
import { styled as styled11, SizableText as
|
|
574
|
-
import { jsx as
|
|
575
|
-
var ListItemFrame = styled11(
|
|
847
|
+
import { styled as styled11, SizableText as SizableText15, XStack as XStack6, YStack as YStack10, View as View5 } from "tamagui";
|
|
848
|
+
import { jsx as jsx15, jsxs as jsxs10 } from "react/jsx-runtime";
|
|
849
|
+
var ListItemFrame = styled11(XStack6, {
|
|
576
850
|
name: "BlinkListItem",
|
|
577
851
|
alignItems: "center",
|
|
578
852
|
gap: "$3",
|
|
@@ -589,38 +863,67 @@ var ListItemFrame = styled11(XStack3, {
|
|
|
589
863
|
}
|
|
590
864
|
});
|
|
591
865
|
function ListItem({ icon, title, subtitle, right, onPress }) {
|
|
592
|
-
return /* @__PURE__ */
|
|
593
|
-
icon && /* @__PURE__ */
|
|
594
|
-
/* @__PURE__ */
|
|
595
|
-
/* @__PURE__ */
|
|
596
|
-
subtitle && /* @__PURE__ */
|
|
866
|
+
return /* @__PURE__ */ jsxs10(ListItemFrame, { pressable: !!onPress, onPress, children: [
|
|
867
|
+
icon && /* @__PURE__ */ jsx15(View5, { children: icon }),
|
|
868
|
+
/* @__PURE__ */ jsxs10(YStack10, { flex: 1, gap: "$1", children: [
|
|
869
|
+
/* @__PURE__ */ jsx15(SizableText15, { size: "$4", fontWeight: "500", color: "$color12", children: title }),
|
|
870
|
+
subtitle && /* @__PURE__ */ jsx15(SizableText15, { size: "$2", color: "$color9", children: subtitle })
|
|
597
871
|
] }),
|
|
598
872
|
right
|
|
599
873
|
] });
|
|
600
874
|
}
|
|
601
875
|
|
|
602
876
|
// src/layouts/Divider.tsx
|
|
603
|
-
import { Separator as
|
|
604
|
-
import { jsx as
|
|
877
|
+
import { Separator as Separator3, SizableText as SizableText16, XStack as XStack7 } from "tamagui";
|
|
878
|
+
import { jsx as jsx16, jsxs as jsxs11 } from "react/jsx-runtime";
|
|
605
879
|
function Divider({ label }) {
|
|
606
|
-
if (!label) return /* @__PURE__ */
|
|
607
|
-
return /* @__PURE__ */
|
|
608
|
-
/* @__PURE__ */
|
|
609
|
-
/* @__PURE__ */
|
|
610
|
-
/* @__PURE__ */
|
|
880
|
+
if (!label) return /* @__PURE__ */ jsx16(Separator3, { borderColor: "$color4" });
|
|
881
|
+
return /* @__PURE__ */ jsxs11(XStack7, { alignItems: "center", gap: "$3", children: [
|
|
882
|
+
/* @__PURE__ */ jsx16(Separator3, { flex: 1, borderColor: "$color4" }),
|
|
883
|
+
/* @__PURE__ */ jsx16(SizableText16, { size: "$2", color: "$color9", children: label }),
|
|
884
|
+
/* @__PURE__ */ jsx16(Separator3, { flex: 1, borderColor: "$color4" })
|
|
611
885
|
] });
|
|
612
886
|
}
|
|
613
887
|
|
|
614
888
|
// src/layouts/KeyboardStickyFooter.tsx
|
|
615
|
-
import { YStack as
|
|
616
|
-
import { jsx as
|
|
889
|
+
import { YStack as YStack11 } from "tamagui";
|
|
890
|
+
import { jsx as jsx17 } from "react/jsx-runtime";
|
|
617
891
|
function KeyboardStickyFooter({ children, offset }) {
|
|
618
|
-
return /* @__PURE__ */
|
|
892
|
+
return /* @__PURE__ */ jsx17(YStack11, { maxWidth: 500, alignSelf: "center", paddingTop: "$8", paddingBottom: "$4", style: { paddingBottom: offset }, children });
|
|
893
|
+
}
|
|
894
|
+
|
|
895
|
+
// src/layouts/SafeArea.tsx
|
|
896
|
+
import { YStack as YStack12 } from "tamagui";
|
|
897
|
+
import { jsx as jsx18 } from "react/jsx-runtime";
|
|
898
|
+
function SafeArea({ children, edges = ["top", "bottom"] }) {
|
|
899
|
+
return /* @__PURE__ */ jsx18(
|
|
900
|
+
YStack12,
|
|
901
|
+
{
|
|
902
|
+
flex: 1,
|
|
903
|
+
backgroundColor: "$background",
|
|
904
|
+
paddingTop: edges.includes("top") ? "$6" : void 0,
|
|
905
|
+
paddingBottom: edges.includes("bottom") ? "$6" : void 0,
|
|
906
|
+
paddingLeft: edges.includes("left") ? "$4" : void 0,
|
|
907
|
+
paddingRight: edges.includes("right") ? "$4" : void 0,
|
|
908
|
+
children
|
|
909
|
+
}
|
|
910
|
+
);
|
|
911
|
+
}
|
|
912
|
+
|
|
913
|
+
// src/layouts/Grid.tsx
|
|
914
|
+
import { XStack as XStack8, YStack as YStack13 } from "tamagui";
|
|
915
|
+
import { jsx as jsx19 } from "react/jsx-runtime";
|
|
916
|
+
function Grid({ children, columns = 2, gap = "$3" }) {
|
|
917
|
+
const childWidth = `${100 / columns}%`;
|
|
918
|
+
return /* @__PURE__ */ jsx19(XStack8, { flexWrap: "wrap", gap, children: Array.isArray(children) ? children.map((child, i) => /* @__PURE__ */ jsx19(YStack13, { width: childWidth, flexBasis: childWidth, children: child }, i)) : children });
|
|
919
|
+
}
|
|
920
|
+
function Container({ children, maxWidth = 500, centered = true }) {
|
|
921
|
+
return /* @__PURE__ */ jsx19(YStack13, { width: "100%", maxWidth, alignSelf: centered ? "center" : void 0, children });
|
|
619
922
|
}
|
|
620
923
|
|
|
621
924
|
// src/patterns/PaywallScreen.tsx
|
|
622
|
-
import { Button as Button3, SizableText as
|
|
623
|
-
import { jsx as
|
|
925
|
+
import { Button as Button3, SizableText as SizableText17, XStack as XStack9, YStack as YStack14, Circle as Circle2 } from "tamagui";
|
|
926
|
+
import { jsx as jsx20, jsxs as jsxs12 } from "react/jsx-runtime";
|
|
624
927
|
function PaywallScreen({
|
|
625
928
|
title = "Upgrade Your Experience",
|
|
626
929
|
subtitle = "Choose the plan that works for you",
|
|
@@ -631,13 +934,13 @@ function PaywallScreen({
|
|
|
631
934
|
onRestore,
|
|
632
935
|
continueLabel = "Continue"
|
|
633
936
|
}) {
|
|
634
|
-
return /* @__PURE__ */
|
|
635
|
-
/* @__PURE__ */
|
|
636
|
-
/* @__PURE__ */
|
|
637
|
-
/* @__PURE__ */
|
|
937
|
+
return /* @__PURE__ */ jsxs12(YStack14, { flex: 1, padding: "$4", gap: "$5", backgroundColor: "$background", children: [
|
|
938
|
+
/* @__PURE__ */ jsxs12(YStack14, { gap: "$2", paddingTop: "$6", children: [
|
|
939
|
+
/* @__PURE__ */ jsx20(SizableText17, { size: "$9", fontWeight: "700", textAlign: "center", children: title }),
|
|
940
|
+
/* @__PURE__ */ jsx20(SizableText17, { size: "$4", color: "$color10", textAlign: "center", children: subtitle })
|
|
638
941
|
] }),
|
|
639
|
-
/* @__PURE__ */
|
|
640
|
-
|
|
942
|
+
/* @__PURE__ */ jsx20(YStack14, { gap: "$3", flex: 1, children: plans.map((plan) => /* @__PURE__ */ jsxs12(
|
|
943
|
+
YStack14,
|
|
641
944
|
{
|
|
642
945
|
padding: "$4",
|
|
643
946
|
borderRadius: "$5",
|
|
@@ -648,29 +951,29 @@ function PaywallScreen({
|
|
|
648
951
|
onPress: () => onSelectPlan?.(plan.id),
|
|
649
952
|
cursor: "pointer",
|
|
650
953
|
children: [
|
|
651
|
-
/* @__PURE__ */
|
|
652
|
-
/* @__PURE__ */
|
|
653
|
-
/* @__PURE__ */
|
|
654
|
-
/* @__PURE__ */
|
|
655
|
-
/* @__PURE__ */
|
|
656
|
-
/* @__PURE__ */
|
|
954
|
+
/* @__PURE__ */ jsxs12(XStack9, { justifyContent: "space-between", alignItems: "center", children: [
|
|
955
|
+
/* @__PURE__ */ jsxs12(YStack14, { children: [
|
|
956
|
+
/* @__PURE__ */ jsx20(SizableText17, { size: "$5", fontWeight: "600", children: plan.name }),
|
|
957
|
+
/* @__PURE__ */ jsxs12(XStack9, { alignItems: "baseline", gap: "$1", children: [
|
|
958
|
+
/* @__PURE__ */ jsx20(SizableText17, { size: "$8", fontWeight: "700", children: plan.price }),
|
|
959
|
+
/* @__PURE__ */ jsxs12(SizableText17, { size: "$3", color: "$color9", children: [
|
|
657
960
|
"/",
|
|
658
961
|
plan.period
|
|
659
962
|
] })
|
|
660
963
|
] })
|
|
661
964
|
] }),
|
|
662
|
-
plan.popular && /* @__PURE__ */
|
|
965
|
+
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" }) })
|
|
663
966
|
] }),
|
|
664
|
-
/* @__PURE__ */
|
|
665
|
-
/* @__PURE__ */
|
|
666
|
-
/* @__PURE__ */
|
|
967
|
+
/* @__PURE__ */ jsx20(YStack14, { gap: "$2", paddingTop: "$3", children: plan.features.map((feature, i) => /* @__PURE__ */ jsxs12(XStack9, { gap: "$2", alignItems: "center", children: [
|
|
968
|
+
/* @__PURE__ */ jsx20(Circle2, { size: 6, backgroundColor: "$green9" }),
|
|
969
|
+
/* @__PURE__ */ jsx20(SizableText17, { size: "$3", color: "$color11", children: feature })
|
|
667
970
|
] }, i)) })
|
|
668
971
|
]
|
|
669
972
|
},
|
|
670
973
|
plan.id
|
|
671
974
|
)) }),
|
|
672
|
-
/* @__PURE__ */
|
|
673
|
-
/* @__PURE__ */
|
|
975
|
+
/* @__PURE__ */ jsxs12(YStack14, { gap: "$3", paddingBottom: "$4", children: [
|
|
976
|
+
/* @__PURE__ */ jsx20(
|
|
674
977
|
Button3,
|
|
675
978
|
{
|
|
676
979
|
size: "$5",
|
|
@@ -683,15 +986,15 @@ function PaywallScreen({
|
|
|
683
986
|
children: continueLabel
|
|
684
987
|
}
|
|
685
988
|
),
|
|
686
|
-
onRestore && /* @__PURE__ */
|
|
989
|
+
onRestore && /* @__PURE__ */ jsx20(Button3, { size: "$3", chromeless: true, onPress: onRestore, children: /* @__PURE__ */ jsx20(SizableText17, { size: "$3", color: "$color9", children: "Restore Purchases" }) })
|
|
687
990
|
] })
|
|
688
991
|
] });
|
|
689
992
|
}
|
|
690
993
|
|
|
691
994
|
// src/patterns/OnboardingCarousel.tsx
|
|
692
|
-
import { useState as
|
|
693
|
-
import { Button as Button4, SizableText as
|
|
694
|
-
import { jsx as
|
|
995
|
+
import { useState as useState5 } from "react";
|
|
996
|
+
import { Button as Button4, SizableText as SizableText18, XStack as XStack10, YStack as YStack15, Circle as Circle3 } from "tamagui";
|
|
997
|
+
import { jsx as jsx21, jsxs as jsxs13 } from "react/jsx-runtime";
|
|
695
998
|
function OnboardingCarousel({
|
|
696
999
|
steps,
|
|
697
1000
|
onComplete,
|
|
@@ -700,20 +1003,20 @@ function OnboardingCarousel({
|
|
|
700
1003
|
skipLabel = "Skip",
|
|
701
1004
|
nextLabel = "Next"
|
|
702
1005
|
}) {
|
|
703
|
-
const [current, setCurrent] =
|
|
1006
|
+
const [current, setCurrent] = useState5(0);
|
|
704
1007
|
const isLast = current === steps.length - 1;
|
|
705
1008
|
const step = steps[current];
|
|
706
|
-
return /* @__PURE__ */
|
|
707
|
-
/* @__PURE__ */
|
|
708
|
-
/* @__PURE__ */
|
|
709
|
-
step?.icon && /* @__PURE__ */
|
|
710
|
-
/* @__PURE__ */
|
|
711
|
-
/* @__PURE__ */
|
|
712
|
-
/* @__PURE__ */
|
|
1009
|
+
return /* @__PURE__ */ jsxs13(YStack15, { flex: 1, backgroundColor: "$background", padding: "$4", justifyContent: "space-between", children: [
|
|
1010
|
+
/* @__PURE__ */ jsx21(XStack10, { 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 }) }) }),
|
|
1011
|
+
/* @__PURE__ */ jsxs13(YStack15, { flex: 1, alignItems: "center", justifyContent: "center", gap: "$5", paddingHorizontal: "$4", children: [
|
|
1012
|
+
step?.icon && /* @__PURE__ */ jsx21(Circle3, { size: 120, backgroundColor: "$color2", alignItems: "center", justifyContent: "center", children: step.icon }),
|
|
1013
|
+
/* @__PURE__ */ jsxs13(YStack15, { gap: "$3", alignItems: "center", children: [
|
|
1014
|
+
/* @__PURE__ */ jsx21(SizableText18, { size: "$9", fontWeight: "700", textAlign: "center", children: step?.title }),
|
|
1015
|
+
/* @__PURE__ */ jsx21(SizableText18, { size: "$4", color: "$color10", textAlign: "center", maxWidth: 300, children: step?.description })
|
|
713
1016
|
] })
|
|
714
1017
|
] }),
|
|
715
|
-
/* @__PURE__ */
|
|
716
|
-
/* @__PURE__ */
|
|
1018
|
+
/* @__PURE__ */ jsxs13(YStack15, { gap: "$3", paddingBottom: "$2", children: [
|
|
1019
|
+
/* @__PURE__ */ jsx21(XStack10, { justifyContent: "center", gap: "$2", children: steps.map((_, i) => /* @__PURE__ */ jsx21(
|
|
717
1020
|
Circle3,
|
|
718
1021
|
{
|
|
719
1022
|
size: 8,
|
|
@@ -722,7 +1025,7 @@ function OnboardingCarousel({
|
|
|
722
1025
|
},
|
|
723
1026
|
i
|
|
724
1027
|
)) }),
|
|
725
|
-
/* @__PURE__ */
|
|
1028
|
+
/* @__PURE__ */ jsx21(
|
|
726
1029
|
Button4,
|
|
727
1030
|
{
|
|
728
1031
|
size: "$5",
|
|
@@ -740,21 +1043,21 @@ function OnboardingCarousel({
|
|
|
740
1043
|
}
|
|
741
1044
|
|
|
742
1045
|
// src/patterns/ChatBubble.tsx
|
|
743
|
-
import { SizableText as
|
|
744
|
-
import { jsx as
|
|
1046
|
+
import { SizableText as SizableText19, XStack as XStack11, YStack as YStack16, Circle as Circle4, Image as Image3 } from "tamagui";
|
|
1047
|
+
import { jsx as jsx22, jsxs as jsxs14 } from "react/jsx-runtime";
|
|
745
1048
|
function ChatBubble({ message, showAvatar = true }) {
|
|
746
1049
|
const isUser = message.sender === "user";
|
|
747
|
-
return /* @__PURE__ */
|
|
748
|
-
|
|
1050
|
+
return /* @__PURE__ */ jsxs14(
|
|
1051
|
+
XStack11,
|
|
749
1052
|
{
|
|
750
1053
|
alignSelf: isUser ? "flex-end" : "flex-start",
|
|
751
1054
|
maxWidth: "75%",
|
|
752
1055
|
gap: "$2",
|
|
753
1056
|
flexDirection: isUser ? "row-reverse" : "row",
|
|
754
1057
|
children: [
|
|
755
|
-
showAvatar && !isUser && /* @__PURE__ */
|
|
756
|
-
/* @__PURE__ */
|
|
757
|
-
|
|
1058
|
+
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() ?? "?" }) }),
|
|
1059
|
+
/* @__PURE__ */ jsxs14(
|
|
1060
|
+
YStack16,
|
|
758
1061
|
{
|
|
759
1062
|
backgroundColor: isUser ? "$color9" : "$color3",
|
|
760
1063
|
paddingHorizontal: "$3",
|
|
@@ -764,8 +1067,8 @@ function ChatBubble({ message, showAvatar = true }) {
|
|
|
764
1067
|
borderBottomLeftRadius: isUser ? "$5" : "$2",
|
|
765
1068
|
gap: "$1",
|
|
766
1069
|
children: [
|
|
767
|
-
/* @__PURE__ */
|
|
768
|
-
message.timestamp && /* @__PURE__ */
|
|
1070
|
+
/* @__PURE__ */ jsx22(SizableText19, { size: "$3", color: isUser ? "$color1" : "$color12", children: message.text }),
|
|
1071
|
+
message.timestamp && /* @__PURE__ */ jsx22(SizableText19, { size: "$1", color: isUser ? "$color3" : "$color9", alignSelf: "flex-end", children: message.timestamp })
|
|
769
1072
|
]
|
|
770
1073
|
}
|
|
771
1074
|
)
|
|
@@ -775,11 +1078,11 @@ function ChatBubble({ message, showAvatar = true }) {
|
|
|
775
1078
|
}
|
|
776
1079
|
|
|
777
1080
|
// src/patterns/SettingsScreen.tsx
|
|
778
|
-
import { Separator as
|
|
779
|
-
import { jsx as
|
|
1081
|
+
import { Separator as Separator4, SizableText as SizableText20, Switch, XStack as XStack12, YStack as YStack17 } from "tamagui";
|
|
1082
|
+
import { jsx as jsx23, jsxs as jsxs15 } from "react/jsx-runtime";
|
|
780
1083
|
function SettingsItemRow({ item }) {
|
|
781
|
-
return /* @__PURE__ */
|
|
782
|
-
|
|
1084
|
+
return /* @__PURE__ */ jsxs15(
|
|
1085
|
+
XStack12,
|
|
783
1086
|
{
|
|
784
1087
|
alignItems: "center",
|
|
785
1088
|
gap: "$3",
|
|
@@ -790,22 +1093,22 @@ function SettingsItemRow({ item }) {
|
|
|
790
1093
|
onPress: item.onPress,
|
|
791
1094
|
cursor: item.onPress ? "pointer" : void 0,
|
|
792
1095
|
children: [
|
|
793
|
-
item.icon && /* @__PURE__ */
|
|
794
|
-
/* @__PURE__ */
|
|
795
|
-
/* @__PURE__ */
|
|
796
|
-
item.subtitle && /* @__PURE__ */
|
|
1096
|
+
item.icon && /* @__PURE__ */ jsx23(YStack17, { width: 24, alignItems: "center", children: item.icon }),
|
|
1097
|
+
/* @__PURE__ */ jsxs15(YStack17, { flex: 1, gap: "$1", children: [
|
|
1098
|
+
/* @__PURE__ */ jsx23(SizableText20, { size: "$4", fontWeight: "500", children: item.title }),
|
|
1099
|
+
item.subtitle && /* @__PURE__ */ jsx23(SizableText20, { size: "$2", color: "$color9", children: item.subtitle })
|
|
797
1100
|
] }),
|
|
798
|
-
item.type === "toggle" ? /* @__PURE__ */
|
|
1101
|
+
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" })
|
|
799
1102
|
]
|
|
800
1103
|
}
|
|
801
1104
|
);
|
|
802
1105
|
}
|
|
803
1106
|
function SettingsScreen({ sections, header }) {
|
|
804
|
-
return /* @__PURE__ */
|
|
1107
|
+
return /* @__PURE__ */ jsxs15(YStack17, { flex: 1, backgroundColor: "$background", children: [
|
|
805
1108
|
header,
|
|
806
|
-
/* @__PURE__ */
|
|
807
|
-
section.title && /* @__PURE__ */
|
|
808
|
-
|
|
1109
|
+
/* @__PURE__ */ jsx23(YStack17, { gap: "$4", paddingVertical: "$2", children: sections.map((section, si) => /* @__PURE__ */ jsxs15(YStack17, { children: [
|
|
1110
|
+
section.title && /* @__PURE__ */ jsx23(
|
|
1111
|
+
SizableText20,
|
|
809
1112
|
{
|
|
810
1113
|
size: "$2",
|
|
811
1114
|
fontWeight: "600",
|
|
@@ -816,25 +1119,25 @@ function SettingsScreen({ sections, header }) {
|
|
|
816
1119
|
children: section.title
|
|
817
1120
|
}
|
|
818
1121
|
),
|
|
819
|
-
/* @__PURE__ */
|
|
820
|
-
/* @__PURE__ */
|
|
821
|
-
ii < section.items.length - 1 && /* @__PURE__ */
|
|
1122
|
+
/* @__PURE__ */ jsx23(YStack17, { backgroundColor: "$color1", borderRadius: "$4", marginHorizontal: "$3", overflow: "hidden", children: section.items.map((item, ii) => /* @__PURE__ */ jsxs15(YStack17, { children: [
|
|
1123
|
+
/* @__PURE__ */ jsx23(SettingsItemRow, { item }),
|
|
1124
|
+
ii < section.items.length - 1 && /* @__PURE__ */ jsx23(Separator4, { borderColor: "$color3", marginLeft: "$12" })
|
|
822
1125
|
] }, item.id)) })
|
|
823
1126
|
] }, si)) })
|
|
824
1127
|
] });
|
|
825
1128
|
}
|
|
826
1129
|
|
|
827
1130
|
// src/patterns/EmptyState.tsx
|
|
828
|
-
import { Button as Button5, SizableText as
|
|
829
|
-
import { jsx as
|
|
1131
|
+
import { Button as Button5, SizableText as SizableText21, YStack as YStack18 } from "tamagui";
|
|
1132
|
+
import { jsx as jsx24, jsxs as jsxs16 } from "react/jsx-runtime";
|
|
830
1133
|
function EmptyState({ icon, title, description, actionLabel, onAction }) {
|
|
831
|
-
return /* @__PURE__ */
|
|
1134
|
+
return /* @__PURE__ */ jsxs16(YStack18, { flex: 1, alignItems: "center", justifyContent: "center", gap: "$4", padding: "$6", children: [
|
|
832
1135
|
icon,
|
|
833
|
-
/* @__PURE__ */
|
|
834
|
-
/* @__PURE__ */
|
|
835
|
-
description && /* @__PURE__ */
|
|
1136
|
+
/* @__PURE__ */ jsxs16(YStack18, { gap: "$2", alignItems: "center", children: [
|
|
1137
|
+
/* @__PURE__ */ jsx24(SizableText21, { size: "$6", fontWeight: "600", textAlign: "center", children: title }),
|
|
1138
|
+
description && /* @__PURE__ */ jsx24(SizableText21, { size: "$4", color: "$color9", textAlign: "center", maxWidth: 280, children: description })
|
|
836
1139
|
] }),
|
|
837
|
-
actionLabel && onAction && /* @__PURE__ */
|
|
1140
|
+
actionLabel && onAction && /* @__PURE__ */ jsx24(
|
|
838
1141
|
Button5,
|
|
839
1142
|
{
|
|
840
1143
|
size: "$4",
|
|
@@ -851,89 +1154,582 @@ function EmptyState({ icon, title, description, actionLabel, onAction }) {
|
|
|
851
1154
|
}
|
|
852
1155
|
|
|
853
1156
|
// src/patterns/ProfileHeader.tsx
|
|
854
|
-
import { Circle as Circle5, Image as Image4, SizableText as
|
|
855
|
-
import { jsx as
|
|
1157
|
+
import { Circle as Circle5, Image as Image4, SizableText as SizableText22, XStack as XStack13, YStack as YStack19 } from "tamagui";
|
|
1158
|
+
import { jsx as jsx25, jsxs as jsxs17 } from "react/jsx-runtime";
|
|
856
1159
|
function ProfileHeader({ name, subtitle, avatar, stats, actions }) {
|
|
857
|
-
return /* @__PURE__ */
|
|
858
|
-
/* @__PURE__ */
|
|
859
|
-
/* @__PURE__ */
|
|
860
|
-
/* @__PURE__ */
|
|
861
|
-
subtitle && /* @__PURE__ */
|
|
1160
|
+
return /* @__PURE__ */ jsxs17(YStack19, { alignItems: "center", gap: "$4", paddingVertical: "$6", paddingHorizontal: "$4", children: [
|
|
1161
|
+
/* @__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() ?? "?" }) }),
|
|
1162
|
+
/* @__PURE__ */ jsxs17(YStack19, { alignItems: "center", gap: "$1", children: [
|
|
1163
|
+
/* @__PURE__ */ jsx25(SizableText22, { size: "$7", fontWeight: "700", children: name }),
|
|
1164
|
+
subtitle && /* @__PURE__ */ jsx25(SizableText22, { size: "$4", color: "$color10", children: subtitle })
|
|
862
1165
|
] }),
|
|
863
|
-
stats && stats.length > 0 && /* @__PURE__ */
|
|
864
|
-
/* @__PURE__ */
|
|
865
|
-
/* @__PURE__ */
|
|
1166
|
+
stats && stats.length > 0 && /* @__PURE__ */ jsx25(XStack13, { gap: "$6", children: stats.map((stat, i) => /* @__PURE__ */ jsxs17(YStack19, { alignItems: "center", gap: "$1", children: [
|
|
1167
|
+
/* @__PURE__ */ jsx25(SizableText22, { size: "$6", fontWeight: "700", children: stat.value }),
|
|
1168
|
+
/* @__PURE__ */ jsx25(SizableText22, { size: "$2", color: "$color9", children: stat.label })
|
|
866
1169
|
] }, i)) }),
|
|
867
1170
|
actions
|
|
868
1171
|
] });
|
|
869
1172
|
}
|
|
1173
|
+
|
|
1174
|
+
// src/patterns/AppHeader.tsx
|
|
1175
|
+
import { SizableText as SizableText23, XStack as XStack14, YStack as YStack20 } from "tamagui";
|
|
1176
|
+
import { jsx as jsx26, jsxs as jsxs18 } from "react/jsx-runtime";
|
|
1177
|
+
function AppHeader({ title, subtitle, variant = "simple", onBack, avatar, left, right, transparent, borderless }) {
|
|
1178
|
+
const leftContent = (() => {
|
|
1179
|
+
if (variant === "back") return /* @__PURE__ */ jsx26(SizableText23, { size: "$6", paddingRight: "$2", onPress: onBack, pressStyle: { opacity: 0.6 }, cursor: "pointer", children: "\u2039" });
|
|
1180
|
+
if (variant === "profile") return /* @__PURE__ */ jsx26(Avatar, { uri: avatar, name: title, size: "sm" });
|
|
1181
|
+
if (variant === "centered") return left ?? null;
|
|
1182
|
+
return null;
|
|
1183
|
+
})();
|
|
1184
|
+
const rightContent = variant === "profile" || variant === "centered" ? right ?? null : null;
|
|
1185
|
+
return /* @__PURE__ */ jsx26(
|
|
1186
|
+
YStack20,
|
|
1187
|
+
{
|
|
1188
|
+
paddingTop: "$6",
|
|
1189
|
+
backgroundColor: transparent ? "transparent" : "$background",
|
|
1190
|
+
borderBottomWidth: borderless ? 0 : 1,
|
|
1191
|
+
borderBottomColor: "$borderColor",
|
|
1192
|
+
children: /* @__PURE__ */ jsxs18(XStack14, { height: 56, alignItems: "center", paddingHorizontal: "$4", gap: "$3", children: [
|
|
1193
|
+
leftContent,
|
|
1194
|
+
/* @__PURE__ */ jsxs18(YStack20, { flex: 1, alignItems: variant === "centered" ? "center" : "flex-start", children: [
|
|
1195
|
+
/* @__PURE__ */ jsx26(SizableText23, { size: "$6", fontWeight: "700", numberOfLines: 1, children: title }),
|
|
1196
|
+
subtitle && /* @__PURE__ */ jsx26(SizableText23, { size: "$2", color: "$color9", numberOfLines: 1, children: subtitle })
|
|
1197
|
+
] }),
|
|
1198
|
+
rightContent
|
|
1199
|
+
] })
|
|
1200
|
+
}
|
|
1201
|
+
);
|
|
1202
|
+
}
|
|
1203
|
+
|
|
1204
|
+
// src/patterns/BottomSheet.tsx
|
|
1205
|
+
import { Sheet, SizableText as SizableText24, XStack as XStack15, YStack as YStack21 } from "tamagui";
|
|
1206
|
+
import { ScrollView as ScrollView2 } from "react-native";
|
|
1207
|
+
import { jsx as jsx27, jsxs as jsxs19 } from "react/jsx-runtime";
|
|
1208
|
+
function BottomSheet({ open, onOpenChange, title, children, snapPoints = [85], dismissOnSnapToBottom = true, showHandle = true, showClose = false }) {
|
|
1209
|
+
return /* @__PURE__ */ jsxs19(Sheet, { modal: true, open, onOpenChange, snapPoints, dismissOnSnapToBottom, animation: "medium", children: [
|
|
1210
|
+
/* @__PURE__ */ jsx27(Sheet.Overlay, { animation: "lazy", enterStyle: { opacity: 0 }, exitStyle: { opacity: 0 } }),
|
|
1211
|
+
showHandle && /* @__PURE__ */ jsx27(Sheet.Handle, {}),
|
|
1212
|
+
/* @__PURE__ */ jsxs19(Sheet.Frame, { borderTopLeftRadius: "$6", borderTopRightRadius: "$6", backgroundColor: "$background", children: [
|
|
1213
|
+
(title || showClose) && /* @__PURE__ */ jsxs19(XStack15, { paddingHorizontal: "$4", paddingTop: "$3", paddingBottom: "$2", alignItems: "center", justifyContent: "space-between", children: [
|
|
1214
|
+
/* @__PURE__ */ jsx27(SizableText24, { size: "$6", fontWeight: "600", flexShrink: 1, children: title }),
|
|
1215
|
+
showClose && /* @__PURE__ */ jsx27(
|
|
1216
|
+
XStack15,
|
|
1217
|
+
{
|
|
1218
|
+
width: 28,
|
|
1219
|
+
height: 28,
|
|
1220
|
+
borderRadius: "$10",
|
|
1221
|
+
backgroundColor: "$color4",
|
|
1222
|
+
alignItems: "center",
|
|
1223
|
+
justifyContent: "center",
|
|
1224
|
+
pressStyle: { opacity: 0.7 },
|
|
1225
|
+
onPress: () => onOpenChange(false),
|
|
1226
|
+
children: /* @__PURE__ */ jsx27(SizableText24, { size: "$3", color: "$color10", fontWeight: "600", children: "\u2715" })
|
|
1227
|
+
}
|
|
1228
|
+
)
|
|
1229
|
+
] }),
|
|
1230
|
+
/* @__PURE__ */ jsx27(ScrollView2, { contentContainerStyle: { paddingBottom: 40 }, children: /* @__PURE__ */ jsx27(YStack21, { padding: "$4", children }) })
|
|
1231
|
+
] })
|
|
1232
|
+
] });
|
|
1233
|
+
}
|
|
1234
|
+
|
|
1235
|
+
// src/patterns/LoginScreen.tsx
|
|
1236
|
+
import { useState as useState6 } from "react";
|
|
1237
|
+
import { Button as Button6, SizableText as SizableText25, Spinner, XStack as XStack16, YStack as YStack22 } from "tamagui";
|
|
1238
|
+
import { jsx as jsx28, jsxs as jsxs20 } from "react/jsx-runtime";
|
|
1239
|
+
function LoginScreen({ title = "Welcome", subtitle = "Sign in to continue", logo, providers = [], onProviderPress, showEmailForm, onEmailSubmit, onForgotPassword, onCreateAccount, onTerms, onPrivacy, loading }) {
|
|
1240
|
+
const [email, setEmail] = useState6("");
|
|
1241
|
+
const [password, setPassword] = useState6("");
|
|
1242
|
+
return /* @__PURE__ */ jsxs20(YStack22, { flex: 1, padding: "$4", gap: "$5", backgroundColor: "$background", justifyContent: "center", children: [
|
|
1243
|
+
/* @__PURE__ */ jsxs20(YStack22, { alignItems: "center", gap: "$2", children: [
|
|
1244
|
+
logo && /* @__PURE__ */ jsx28(YStack22, { paddingBottom: "$3", children: logo }),
|
|
1245
|
+
/* @__PURE__ */ jsx28(SizableText25, { size: "$9", fontWeight: "700", textAlign: "center", children: title }),
|
|
1246
|
+
/* @__PURE__ */ jsx28(SizableText25, { size: "$4", color: "$color10", textAlign: "center", children: subtitle })
|
|
1247
|
+
] }),
|
|
1248
|
+
providers.length > 0 && /* @__PURE__ */ jsx28(YStack22, { gap: "$2.5", children: providers.map((p) => /* @__PURE__ */ jsx28(
|
|
1249
|
+
Button6,
|
|
1250
|
+
{
|
|
1251
|
+
size: "$5",
|
|
1252
|
+
borderWidth: 1.5,
|
|
1253
|
+
borderColor: "$color5",
|
|
1254
|
+
backgroundColor: "$color1",
|
|
1255
|
+
borderRadius: "$4",
|
|
1256
|
+
disabled: loading,
|
|
1257
|
+
onPress: () => onProviderPress?.(p.id),
|
|
1258
|
+
hoverStyle: { backgroundColor: "$color2" },
|
|
1259
|
+
pressStyle: { backgroundColor: "$color3" },
|
|
1260
|
+
children: /* @__PURE__ */ jsxs20(XStack16, { alignItems: "center", gap: "$2", children: [
|
|
1261
|
+
p.icon,
|
|
1262
|
+
/* @__PURE__ */ jsx28(SizableText25, { size: "$4", fontWeight: "500", children: p.name })
|
|
1263
|
+
] })
|
|
1264
|
+
},
|
|
1265
|
+
p.id
|
|
1266
|
+
)) }),
|
|
1267
|
+
showEmailForm && providers.length > 0 && /* @__PURE__ */ jsx28(Divider, { label: "or" }),
|
|
1268
|
+
showEmailForm && /* @__PURE__ */ jsxs20(YStack22, { gap: "$3", children: [
|
|
1269
|
+
/* @__PURE__ */ jsx28(Input, { label: "Email", placeholder: "your@email.com", value: email, onChangeText: setEmail, keyboardType: "email-address", autoCapitalize: "none" }),
|
|
1270
|
+
/* @__PURE__ */ jsx28(Input, { label: "Password", placeholder: "\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022", value: password, onChangeText: setPassword, secureTextEntry: true }),
|
|
1271
|
+
onForgotPassword && /* @__PURE__ */ jsx28(XStack16, { justifyContent: "flex-end", children: /* @__PURE__ */ jsx28(SizableText25, { size: "$3", color: "$color9", onPress: onForgotPassword, children: "Forgot password?" }) }),
|
|
1272
|
+
/* @__PURE__ */ jsx28(
|
|
1273
|
+
Button6,
|
|
1274
|
+
{
|
|
1275
|
+
size: "$5",
|
|
1276
|
+
backgroundColor: "$color9",
|
|
1277
|
+
color: "$color1",
|
|
1278
|
+
borderRadius: "$5",
|
|
1279
|
+
disabled: loading,
|
|
1280
|
+
onPress: () => onEmailSubmit?.(email, password),
|
|
1281
|
+
hoverStyle: { backgroundColor: "$color10" },
|
|
1282
|
+
pressStyle: { backgroundColor: "$color8" },
|
|
1283
|
+
icon: loading ? /* @__PURE__ */ jsx28(Spinner, { size: "small", color: "$color1" }) : void 0,
|
|
1284
|
+
children: "Sign In"
|
|
1285
|
+
}
|
|
1286
|
+
),
|
|
1287
|
+
onCreateAccount && /* @__PURE__ */ jsx28(Button6, { size: "$3", chromeless: true, onPress: onCreateAccount, children: /* @__PURE__ */ jsx28(SizableText25, { size: "$3", color: "$color9", children: "Create Account" }) })
|
|
1288
|
+
] }),
|
|
1289
|
+
(onTerms || onPrivacy) && /* @__PURE__ */ jsx28(YStack22, { paddingTop: "$2", alignItems: "center", children: /* @__PURE__ */ jsxs20(SizableText25, { size: "$2", color: "$color8", textAlign: "center", children: [
|
|
1290
|
+
"By continuing you agree to our",
|
|
1291
|
+
" ",
|
|
1292
|
+
onTerms && /* @__PURE__ */ jsx28(SizableText25, { size: "$2", color: "$color9", onPress: onTerms, children: "Terms of Service" }),
|
|
1293
|
+
onTerms && onPrivacy && " & ",
|
|
1294
|
+
onPrivacy && /* @__PURE__ */ jsx28(SizableText25, { size: "$2", color: "$color9", onPress: onPrivacy, children: "Privacy Policy" })
|
|
1295
|
+
] }) })
|
|
1296
|
+
] });
|
|
1297
|
+
}
|
|
1298
|
+
|
|
1299
|
+
// src/patterns/TabBar.tsx
|
|
1300
|
+
import { SizableText as SizableText26, XStack as XStack17, YStack as YStack23 } from "tamagui";
|
|
1301
|
+
import { jsx as jsx29, jsxs as jsxs21 } from "react/jsx-runtime";
|
|
1302
|
+
function TabBar({ tabs, activeTab, onTabPress, showLabels = true }) {
|
|
1303
|
+
return /* @__PURE__ */ jsx29(XStack17, { height: 56, borderTopWidth: 1, borderTopColor: "$borderColor", backgroundColor: "$background", paddingBottom: "$2", children: tabs.map((tab) => {
|
|
1304
|
+
const active = tab.id === activeTab;
|
|
1305
|
+
return /* @__PURE__ */ jsxs21(
|
|
1306
|
+
YStack23,
|
|
1307
|
+
{
|
|
1308
|
+
flex: 1,
|
|
1309
|
+
alignItems: "center",
|
|
1310
|
+
justifyContent: "center",
|
|
1311
|
+
gap: "$1",
|
|
1312
|
+
pressStyle: { opacity: 0.6 },
|
|
1313
|
+
onPress: () => onTabPress(tab.id),
|
|
1314
|
+
children: [
|
|
1315
|
+
tab.icon && /* @__PURE__ */ jsx29(SizableText26, { size: "$5", color: active ? "$color9" : "$color8", children: tab.icon }),
|
|
1316
|
+
showLabels && /* @__PURE__ */ jsx29(SizableText26, { size: "$1", color: active ? "$color9" : "$color8", fontWeight: active ? "600" : "400", children: tab.label })
|
|
1317
|
+
]
|
|
1318
|
+
},
|
|
1319
|
+
tab.id
|
|
1320
|
+
);
|
|
1321
|
+
}) });
|
|
1322
|
+
}
|
|
1323
|
+
|
|
1324
|
+
// src/patterns/SearchBar.tsx
|
|
1325
|
+
import { Input as Input2, SizableText as SizableText27, XStack as XStack18 } from "tamagui";
|
|
1326
|
+
import { jsx as jsx30, jsxs as jsxs22 } from "react/jsx-runtime";
|
|
1327
|
+
function SearchBar({ value, onChangeText, placeholder = "Search\u2026", onFilter, onCancel, autoFocus }) {
|
|
1328
|
+
return /* @__PURE__ */ jsxs22(XStack18, { height: 44, borderRadius: "$10", backgroundColor: "$color2", alignItems: "center", paddingHorizontal: "$3", gap: "$2", children: [
|
|
1329
|
+
/* @__PURE__ */ jsx30(SizableText27, { size: "$4", color: "$color8", children: "\u2315" }),
|
|
1330
|
+
/* @__PURE__ */ jsx30(
|
|
1331
|
+
Input2,
|
|
1332
|
+
{
|
|
1333
|
+
flex: 1,
|
|
1334
|
+
size: "$4",
|
|
1335
|
+
value,
|
|
1336
|
+
onChangeText,
|
|
1337
|
+
placeholder,
|
|
1338
|
+
placeholderTextColor: "$color8",
|
|
1339
|
+
backgroundColor: "transparent",
|
|
1340
|
+
borderWidth: 0,
|
|
1341
|
+
autoFocus
|
|
1342
|
+
}
|
|
1343
|
+
),
|
|
1344
|
+
onFilter && /* @__PURE__ */ jsx30(SizableText27, { size: "$4", color: "$color9", pressStyle: { opacity: 0.6 }, onPress: onFilter, children: "\u2ACF" }),
|
|
1345
|
+
onCancel && /* @__PURE__ */ jsx30(SizableText27, { size: "$3", color: "$color9", pressStyle: { opacity: 0.6 }, onPress: onCancel, children: "Cancel" })
|
|
1346
|
+
] });
|
|
1347
|
+
}
|
|
1348
|
+
|
|
1349
|
+
// src/patterns/FloatingActionButton.tsx
|
|
1350
|
+
import { SizableText as SizableText28, XStack as XStack19 } from "tamagui";
|
|
1351
|
+
import { jsx as jsx31, jsxs as jsxs23 } from "react/jsx-runtime";
|
|
1352
|
+
var sizes = { sm: 44, md: 56, lg: 68 };
|
|
1353
|
+
var positionStyles = {
|
|
1354
|
+
"bottom-right": { right: 20 },
|
|
1355
|
+
"bottom-center": { left: "50%", marginLeft: -28 },
|
|
1356
|
+
"bottom-left": { left: 20 }
|
|
1357
|
+
};
|
|
1358
|
+
function FloatingActionButton({ icon, label, onPress, position = "bottom-right", size = "md" }) {
|
|
1359
|
+
const dim = sizes[size];
|
|
1360
|
+
return /* @__PURE__ */ jsxs23(
|
|
1361
|
+
XStack19,
|
|
1362
|
+
{
|
|
1363
|
+
position: "absolute",
|
|
1364
|
+
bottom: 32,
|
|
1365
|
+
...positionStyles[position],
|
|
1366
|
+
height: dim,
|
|
1367
|
+
minWidth: dim,
|
|
1368
|
+
borderRadius: label ? "$6" : "$10",
|
|
1369
|
+
backgroundColor: "$color9",
|
|
1370
|
+
alignItems: "center",
|
|
1371
|
+
justifyContent: "center",
|
|
1372
|
+
gap: "$2",
|
|
1373
|
+
paddingHorizontal: label ? "$4" : 0,
|
|
1374
|
+
elevation: 4,
|
|
1375
|
+
pressStyle: { scale: 0.95, opacity: 0.9 },
|
|
1376
|
+
onPress,
|
|
1377
|
+
children: [
|
|
1378
|
+
icon && /* @__PURE__ */ jsx31(SizableText28, { color: "$color1", children: icon }),
|
|
1379
|
+
label && /* @__PURE__ */ jsx31(SizableText28, { color: "$color1", size: "$4", fontWeight: "600", children: label })
|
|
1380
|
+
]
|
|
1381
|
+
}
|
|
1382
|
+
);
|
|
1383
|
+
}
|
|
1384
|
+
|
|
1385
|
+
// src/patterns/ActionSheet.tsx
|
|
1386
|
+
import { Sheet as Sheet2, SizableText as SizableText29, XStack as XStack20, YStack as YStack24 } from "tamagui";
|
|
1387
|
+
import { jsx as jsx32, jsxs as jsxs24 } from "react/jsx-runtime";
|
|
1388
|
+
function ActionSheet({ open, onOpenChange, title, items, onSelect, cancelLabel = "Cancel" }) {
|
|
1389
|
+
return /* @__PURE__ */ jsxs24(Sheet2, { modal: true, open, onOpenChange, snapPoints: [50], dismissOnSnapToBottom: true, animation: "medium", children: [
|
|
1390
|
+
/* @__PURE__ */ jsx32(Sheet2.Overlay, { animation: "lazy", enterStyle: { opacity: 0 }, exitStyle: { opacity: 0 } }),
|
|
1391
|
+
/* @__PURE__ */ jsx32(Sheet2.Handle, {}),
|
|
1392
|
+
/* @__PURE__ */ jsxs24(Sheet2.Frame, { borderTopLeftRadius: "$6", borderTopRightRadius: "$6", backgroundColor: "$background", children: [
|
|
1393
|
+
title && /* @__PURE__ */ jsx32(SizableText29, { size: "$3", color: "$color8", textAlign: "center", paddingTop: "$3", paddingBottom: "$1", children: title }),
|
|
1394
|
+
/* @__PURE__ */ jsx32(YStack24, { paddingHorizontal: "$3", paddingTop: "$2", children: items.map((item) => /* @__PURE__ */ jsxs24(
|
|
1395
|
+
XStack20,
|
|
1396
|
+
{
|
|
1397
|
+
height: 52,
|
|
1398
|
+
alignItems: "center",
|
|
1399
|
+
gap: "$3",
|
|
1400
|
+
paddingHorizontal: "$3",
|
|
1401
|
+
borderRadius: "$4",
|
|
1402
|
+
pressStyle: { backgroundColor: "$color3" },
|
|
1403
|
+
onPress: () => {
|
|
1404
|
+
onSelect(item.id);
|
|
1405
|
+
onOpenChange(false);
|
|
1406
|
+
},
|
|
1407
|
+
children: [
|
|
1408
|
+
item.icon && /* @__PURE__ */ jsx32(SizableText29, { size: "$5", children: item.icon }),
|
|
1409
|
+
/* @__PURE__ */ jsx32(
|
|
1410
|
+
SizableText29,
|
|
1411
|
+
{
|
|
1412
|
+
size: "$5",
|
|
1413
|
+
flex: 1,
|
|
1414
|
+
color: item.destructive ? "$red9" : "$color12",
|
|
1415
|
+
fontWeight: item.destructive ? "600" : "400",
|
|
1416
|
+
children: item.label
|
|
1417
|
+
}
|
|
1418
|
+
)
|
|
1419
|
+
]
|
|
1420
|
+
},
|
|
1421
|
+
item.id
|
|
1422
|
+
)) }),
|
|
1423
|
+
/* @__PURE__ */ jsx32(YStack24, { paddingHorizontal: "$3", paddingVertical: "$3", borderTopWidth: 1, borderTopColor: "$borderColor", marginTop: "$2", children: /* @__PURE__ */ jsx32(
|
|
1424
|
+
XStack20,
|
|
1425
|
+
{
|
|
1426
|
+
height: 48,
|
|
1427
|
+
alignItems: "center",
|
|
1428
|
+
justifyContent: "center",
|
|
1429
|
+
borderRadius: "$4",
|
|
1430
|
+
pressStyle: { backgroundColor: "$color3" },
|
|
1431
|
+
onPress: () => onOpenChange(false),
|
|
1432
|
+
children: /* @__PURE__ */ jsx32(SizableText29, { size: "$5", fontWeight: "600", color: "$color9", children: cancelLabel })
|
|
1433
|
+
}
|
|
1434
|
+
) })
|
|
1435
|
+
] })
|
|
1436
|
+
] });
|
|
1437
|
+
}
|
|
1438
|
+
|
|
1439
|
+
// src/patterns/Skeleton.tsx
|
|
1440
|
+
import { YStack as YStack25 } from "tamagui";
|
|
1441
|
+
import { jsx as jsx33 } from "react/jsx-runtime";
|
|
1442
|
+
function Skeleton({ width, height, borderRadius, variant = "rectangular" }) {
|
|
1443
|
+
const size = variant === "circular" ? height ?? 40 : height;
|
|
1444
|
+
const w = variant === "text" ? width ?? "100%" : width;
|
|
1445
|
+
const h = variant === "text" ? height ?? 16 : size;
|
|
1446
|
+
const r = variant === "circular" ? 9999 : borderRadius ?? 8;
|
|
1447
|
+
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 } });
|
|
1448
|
+
}
|
|
1449
|
+
|
|
1450
|
+
// src/patterns/NotificationBanner.tsx
|
|
1451
|
+
import { SizableText as SizableText30, XStack as XStack21, YStack as YStack26 } from "tamagui";
|
|
1452
|
+
import { jsx as jsx34, jsxs as jsxs25 } from "react/jsx-runtime";
|
|
1453
|
+
var variantColors2 = {
|
|
1454
|
+
info: { bg: "$blue3", text: "$blue11" },
|
|
1455
|
+
success: { bg: "$green3", text: "$green11" },
|
|
1456
|
+
warning: { bg: "$yellow3", text: "$yellow11" },
|
|
1457
|
+
error: { bg: "$red3", text: "$red11" }
|
|
1458
|
+
};
|
|
1459
|
+
function NotificationBanner({ title, message, variant = "info", onPress, onDismiss, icon }) {
|
|
1460
|
+
const colors = variantColors2[variant];
|
|
1461
|
+
return /* @__PURE__ */ jsxs25(
|
|
1462
|
+
XStack21,
|
|
1463
|
+
{
|
|
1464
|
+
backgroundColor: colors.bg,
|
|
1465
|
+
padding: "$3",
|
|
1466
|
+
borderRadius: "$4",
|
|
1467
|
+
gap: "$3",
|
|
1468
|
+
alignItems: "flex-start",
|
|
1469
|
+
onPress,
|
|
1470
|
+
pressStyle: onPress ? { opacity: 0.8 } : void 0,
|
|
1471
|
+
children: [
|
|
1472
|
+
icon && /* @__PURE__ */ jsx34(YStack26, { paddingTop: "$0.5", children: icon }),
|
|
1473
|
+
/* @__PURE__ */ jsxs25(YStack26, { flex: 1, gap: "$1", children: [
|
|
1474
|
+
/* @__PURE__ */ jsx34(SizableText30, { size: "$4", fontWeight: "600", color: colors.text, children: title }),
|
|
1475
|
+
message && /* @__PURE__ */ jsx34(SizableText30, { size: "$3", color: colors.text, opacity: 0.8, children: message })
|
|
1476
|
+
] }),
|
|
1477
|
+
onDismiss && /* @__PURE__ */ jsx34(SizableText30, { size: "$3", color: colors.text, opacity: 0.6, onPress: onDismiss, padding: "$1", children: "\u2715" })
|
|
1478
|
+
]
|
|
1479
|
+
}
|
|
1480
|
+
);
|
|
1481
|
+
}
|
|
1482
|
+
|
|
1483
|
+
// src/patterns/ProgressSteps.tsx
|
|
1484
|
+
import { Circle as Circle6, SizableText as SizableText31, XStack as XStack22, YStack as YStack27 } from "tamagui";
|
|
1485
|
+
import { jsx as jsx35, jsxs as jsxs26 } from "react/jsx-runtime";
|
|
1486
|
+
function ProgressSteps({ steps, currentStep, variant = "dots" }) {
|
|
1487
|
+
if (variant === "bar") {
|
|
1488
|
+
const progress = steps.length > 1 ? currentStep / (steps.length - 1) * 100 : 100;
|
|
1489
|
+
return /* @__PURE__ */ jsxs26(YStack27, { gap: "$2", children: [
|
|
1490
|
+
/* @__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" }) }),
|
|
1491
|
+
/* @__PURE__ */ jsx35(XStack22, { justifyContent: "space-between", children: steps.map((label, i) => /* @__PURE__ */ jsx35(SizableText31, { size: "$2", color: i <= currentStep ? "$color9" : "$color8", children: label }, i)) })
|
|
1492
|
+
] });
|
|
1493
|
+
}
|
|
1494
|
+
return /* @__PURE__ */ jsx35(XStack22, { alignItems: "center", justifyContent: "center", gap: "$0", children: steps.map((label, i) => /* @__PURE__ */ jsxs26(XStack22, { alignItems: "center", gap: "$0", children: [
|
|
1495
|
+
/* @__PURE__ */ jsxs26(YStack27, { alignItems: "center", gap: "$1.5", children: [
|
|
1496
|
+
/* @__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 }) }),
|
|
1497
|
+
/* @__PURE__ */ jsx35(SizableText31, { size: "$1", color: i <= currentStep ? "$color11" : "$color8", numberOfLines: 1, children: label })
|
|
1498
|
+
] }),
|
|
1499
|
+
i < steps.length - 1 && /* @__PURE__ */ jsx35(YStack27, { height: 2, width: 32, backgroundColor: i < currentStep ? "$color9" : "$color4", marginBottom: "$4" })
|
|
1500
|
+
] }, i)) });
|
|
1501
|
+
}
|
|
1502
|
+
|
|
1503
|
+
// src/patterns/SwipeableRow.tsx
|
|
1504
|
+
import { useState as useState7 } from "react";
|
|
1505
|
+
import { Button as Button7, SizableText as SizableText32, XStack as XStack23, YStack as YStack28 } from "tamagui";
|
|
1506
|
+
import { Fragment as Fragment2, jsx as jsx36, jsxs as jsxs27 } from "react/jsx-runtime";
|
|
1507
|
+
function SwipeableRow({ children, leftActions, rightActions }) {
|
|
1508
|
+
const [showActions, setShowActions] = useState7(false);
|
|
1509
|
+
const actions = [...leftActions ?? [], ...rightActions ?? []];
|
|
1510
|
+
if (actions.length === 0) return /* @__PURE__ */ jsx36(Fragment2, { children });
|
|
1511
|
+
return /* @__PURE__ */ jsxs27(YStack28, { children: [
|
|
1512
|
+
/* @__PURE__ */ jsx36(YStack28, { onLongPress: () => setShowActions((v) => !v), pressStyle: { opacity: 0.9 }, children }),
|
|
1513
|
+
showActions && /* @__PURE__ */ jsx36(XStack23, { gap: "$2", padding: "$2", animation: "quick", enterStyle: { opacity: 0, scale: 0.95 }, children: actions.map((action) => /* @__PURE__ */ jsx36(
|
|
1514
|
+
Button7,
|
|
1515
|
+
{
|
|
1516
|
+
flex: 1,
|
|
1517
|
+
size: "$3",
|
|
1518
|
+
backgroundColor: action.color,
|
|
1519
|
+
borderRadius: "$3",
|
|
1520
|
+
onPress: () => {
|
|
1521
|
+
action.onPress();
|
|
1522
|
+
setShowActions(false);
|
|
1523
|
+
},
|
|
1524
|
+
children: /* @__PURE__ */ jsx36(SizableText32, { size: "$2", fontWeight: "600", color: "white", children: action.label })
|
|
1525
|
+
},
|
|
1526
|
+
action.id
|
|
1527
|
+
)) })
|
|
1528
|
+
] });
|
|
1529
|
+
}
|
|
1530
|
+
|
|
1531
|
+
// src/patterns/MediaCard.tsx
|
|
1532
|
+
import { Image as Image5, SizableText as SizableText33, XStack as XStack24, YStack as YStack29 } from "tamagui";
|
|
1533
|
+
import { LinearGradient } from "tamagui/linear-gradient";
|
|
1534
|
+
import { jsx as jsx37, jsxs as jsxs28 } from "react/jsx-runtime";
|
|
1535
|
+
function MediaCard({ image, title, subtitle, overlay = "gradient", aspectRatio = 16 / 9, onPress, badge }) {
|
|
1536
|
+
return /* @__PURE__ */ jsx37(
|
|
1537
|
+
YStack29,
|
|
1538
|
+
{
|
|
1539
|
+
borderRadius: "$4",
|
|
1540
|
+
overflow: "hidden",
|
|
1541
|
+
onPress,
|
|
1542
|
+
pressStyle: onPress ? { scale: 0.98, opacity: 0.9 } : void 0,
|
|
1543
|
+
animation: "quick",
|
|
1544
|
+
children: /* @__PURE__ */ jsxs28(YStack29, { aspectRatio, children: [
|
|
1545
|
+
/* @__PURE__ */ jsx37(Image5, { source: { uri: image }, width: "100%", height: "100%", objectFit: "cover" }),
|
|
1546
|
+
overlay === "gradient" && /* @__PURE__ */ jsx37(
|
|
1547
|
+
LinearGradient,
|
|
1548
|
+
{
|
|
1549
|
+
colors: ["transparent", "rgba(0,0,0,0.7)"],
|
|
1550
|
+
start: [0, 0],
|
|
1551
|
+
end: [0, 1],
|
|
1552
|
+
position: "absolute",
|
|
1553
|
+
bottom: 0,
|
|
1554
|
+
left: 0,
|
|
1555
|
+
right: 0,
|
|
1556
|
+
height: "60%"
|
|
1557
|
+
}
|
|
1558
|
+
),
|
|
1559
|
+
overlay === "dark" && /* @__PURE__ */ jsx37(YStack29, { position: "absolute", fullscreen: true, backgroundColor: "rgba(0,0,0,0.4)" }),
|
|
1560
|
+
badge && /* @__PURE__ */ jsx37(
|
|
1561
|
+
XStack24,
|
|
1562
|
+
{
|
|
1563
|
+
position: "absolute",
|
|
1564
|
+
top: "$2",
|
|
1565
|
+
right: "$2",
|
|
1566
|
+
backgroundColor: "$color9",
|
|
1567
|
+
paddingHorizontal: "$2",
|
|
1568
|
+
paddingVertical: "$1",
|
|
1569
|
+
borderRadius: "$2",
|
|
1570
|
+
children: /* @__PURE__ */ jsx37(SizableText33, { size: "$1", fontWeight: "600", color: "$color1", children: badge })
|
|
1571
|
+
}
|
|
1572
|
+
),
|
|
1573
|
+
/* @__PURE__ */ jsxs28(YStack29, { position: "absolute", bottom: 0, left: 0, right: 0, padding: "$3", gap: "$1", children: [
|
|
1574
|
+
/* @__PURE__ */ jsx37(SizableText33, { size: "$5", fontWeight: "600", color: "white", children: title }),
|
|
1575
|
+
subtitle && /* @__PURE__ */ jsx37(SizableText33, { size: "$3", color: "rgba(255,255,255,0.8)", children: subtitle })
|
|
1576
|
+
] })
|
|
1577
|
+
] })
|
|
1578
|
+
}
|
|
1579
|
+
);
|
|
1580
|
+
}
|
|
1581
|
+
|
|
1582
|
+
// src/patterns/Carousel.tsx
|
|
1583
|
+
import { Children, useState as useState8 } from "react";
|
|
1584
|
+
import { Circle as Circle7, XStack as XStack25, YStack as YStack30 } from "tamagui";
|
|
1585
|
+
import { ScrollView as ScrollView3 } from "react-native";
|
|
1586
|
+
import { jsx as jsx38, jsxs as jsxs29 } from "react/jsx-runtime";
|
|
1587
|
+
function Carousel({ children, gap = "$3", snapToInterval, showIndicators = false }) {
|
|
1588
|
+
const [activeIndex, setActiveIndex] = useState8(0);
|
|
1589
|
+
const count = Children.count(children);
|
|
1590
|
+
const gapPx = gap === "$2" ? 8 : gap === "$3" ? 12 : 16;
|
|
1591
|
+
return /* @__PURE__ */ jsxs29(YStack30, { gap: "$3", children: [
|
|
1592
|
+
/* @__PURE__ */ jsx38(
|
|
1593
|
+
ScrollView3,
|
|
1594
|
+
{
|
|
1595
|
+
horizontal: true,
|
|
1596
|
+
showsHorizontalScrollIndicator: false,
|
|
1597
|
+
snapToInterval,
|
|
1598
|
+
decelerationRate: "fast",
|
|
1599
|
+
contentContainerStyle: { gap: gapPx, paddingHorizontal: 16 },
|
|
1600
|
+
onMomentumScrollEnd: (e) => {
|
|
1601
|
+
if (snapToInterval) setActiveIndex(Math.round(e.nativeEvent.contentOffset.x / snapToInterval));
|
|
1602
|
+
},
|
|
1603
|
+
children
|
|
1604
|
+
}
|
|
1605
|
+
),
|
|
1606
|
+
showIndicators && count > 1 && /* @__PURE__ */ jsx38(XStack25, { justifyContent: "center", gap: "$1.5", children: Array.from({ length: count }, (_, i) => /* @__PURE__ */ jsx38(Circle7, { size: 6, backgroundColor: i === activeIndex ? "$color9" : "$color4", animation: "quick" }, i)) })
|
|
1607
|
+
] });
|
|
1608
|
+
}
|
|
1609
|
+
|
|
1610
|
+
// src/patterns/PullToRefresh.tsx
|
|
1611
|
+
import { YStack as YStack31 } from "tamagui";
|
|
1612
|
+
import { RefreshControl, ScrollView as ScrollView4 } from "react-native";
|
|
1613
|
+
import { jsx as jsx39 } from "react/jsx-runtime";
|
|
1614
|
+
function PullToRefresh({ children, onRefresh, refreshing = false }) {
|
|
1615
|
+
return /* @__PURE__ */ jsx39(
|
|
1616
|
+
ScrollView4,
|
|
1617
|
+
{
|
|
1618
|
+
contentContainerStyle: { flexGrow: 1 },
|
|
1619
|
+
refreshControl: /* @__PURE__ */ jsx39(RefreshControl, { refreshing, onRefresh }),
|
|
1620
|
+
children: /* @__PURE__ */ jsx39(YStack31, { flex: 1, children })
|
|
1621
|
+
}
|
|
1622
|
+
);
|
|
1623
|
+
}
|
|
870
1624
|
export {
|
|
1625
|
+
Accordion,
|
|
1626
|
+
ActionSheet,
|
|
1627
|
+
Adapt,
|
|
871
1628
|
AlertDialog2 as AlertDialog,
|
|
1629
|
+
Anchor,
|
|
1630
|
+
AppHeader,
|
|
872
1631
|
Avatar2 as Avatar,
|
|
873
1632
|
Badge,
|
|
1633
|
+
BlinkAccordion,
|
|
874
1634
|
Avatar as BlinkAvatar,
|
|
875
1635
|
Button as BlinkButton,
|
|
876
1636
|
Card as BlinkCard,
|
|
877
1637
|
Input as BlinkInput,
|
|
1638
|
+
BlinkTabs,
|
|
878
1639
|
BlinkText,
|
|
879
|
-
|
|
1640
|
+
BlinkToastProvider,
|
|
1641
|
+
BlinkToggleGroup,
|
|
1642
|
+
BlinkTooltip,
|
|
1643
|
+
BottomSheet,
|
|
1644
|
+
Button8 as Button,
|
|
880
1645
|
Card2 as Card,
|
|
1646
|
+
Carousel,
|
|
881
1647
|
ChatBubble,
|
|
882
1648
|
Checkbox,
|
|
883
|
-
|
|
1649
|
+
Circle8 as Circle,
|
|
1650
|
+
Container,
|
|
884
1651
|
Dialog,
|
|
885
1652
|
DialogProvider,
|
|
886
1653
|
Divider,
|
|
887
1654
|
EmptyState,
|
|
1655
|
+
Fieldset,
|
|
1656
|
+
FloatingActionButton,
|
|
1657
|
+
Form,
|
|
1658
|
+
FormField,
|
|
1659
|
+
Grid,
|
|
888
1660
|
H12 as H1,
|
|
889
1661
|
H22 as H2,
|
|
890
1662
|
H32 as H3,
|
|
891
1663
|
H42 as H4,
|
|
892
1664
|
H52 as H5,
|
|
893
1665
|
H62 as H6,
|
|
1666
|
+
ICONS,
|
|
1667
|
+
Icon,
|
|
894
1668
|
Image2 as Image,
|
|
895
|
-
|
|
1669
|
+
Input3 as Input,
|
|
896
1670
|
KeyboardStickyFooter,
|
|
897
1671
|
Label,
|
|
898
1672
|
ListItem,
|
|
1673
|
+
LoginScreen,
|
|
1674
|
+
MediaCard,
|
|
1675
|
+
NotificationBanner,
|
|
899
1676
|
OnboardingCarousel,
|
|
900
1677
|
PageContainer,
|
|
901
1678
|
PageMainContainer,
|
|
902
1679
|
Paragraph,
|
|
903
1680
|
PaywallScreen,
|
|
904
|
-
Popover,
|
|
1681
|
+
Popover2 as Popover,
|
|
1682
|
+
PortalProvider,
|
|
905
1683
|
Pressable,
|
|
906
1684
|
ProfileHeader,
|
|
907
1685
|
Progress,
|
|
1686
|
+
ProgressSteps,
|
|
1687
|
+
PullToRefresh,
|
|
908
1688
|
RadioGroup,
|
|
1689
|
+
SafeArea,
|
|
909
1690
|
ScreenLayout,
|
|
910
|
-
ScrollView,
|
|
1691
|
+
ScrollView5 as ScrollView,
|
|
1692
|
+
SearchBar,
|
|
911
1693
|
Section,
|
|
912
1694
|
Select,
|
|
913
1695
|
SepHeading,
|
|
914
|
-
|
|
1696
|
+
Separator5 as Separator,
|
|
915
1697
|
SettingsScreen,
|
|
916
|
-
Sheet,
|
|
917
|
-
|
|
1698
|
+
Sheet3 as Sheet,
|
|
1699
|
+
SizableText34 as SizableText,
|
|
1700
|
+
Skeleton,
|
|
918
1701
|
Slider,
|
|
919
|
-
Spinner,
|
|
1702
|
+
Spinner2 as Spinner,
|
|
1703
|
+
Square,
|
|
920
1704
|
StepPageLayout,
|
|
921
1705
|
SubHeading,
|
|
1706
|
+
SwipeableRow,
|
|
922
1707
|
Switch2 as Switch,
|
|
923
|
-
|
|
1708
|
+
TabBar,
|
|
1709
|
+
Tabs,
|
|
1710
|
+
Image6 as TamaguiImage,
|
|
1711
|
+
ListItem2 as TamaguiListItem,
|
|
924
1712
|
TamaguiProvider,
|
|
925
1713
|
Text,
|
|
926
1714
|
TextArea,
|
|
927
1715
|
Theme,
|
|
1716
|
+
ToggleGroup,
|
|
928
1717
|
Tooltip,
|
|
1718
|
+
TooltipSimple,
|
|
1719
|
+
Unspaced,
|
|
929
1720
|
View6 as View,
|
|
930
|
-
|
|
931
|
-
|
|
1721
|
+
VisuallyHidden,
|
|
1722
|
+
XGroup,
|
|
1723
|
+
XStack26 as XStack,
|
|
1724
|
+
YGroup,
|
|
1725
|
+
YStack32 as YStack,
|
|
932
1726
|
ZStack,
|
|
933
1727
|
blinkConfig,
|
|
934
1728
|
dialogConfirm,
|
|
935
1729
|
showError,
|
|
936
1730
|
styled12 as styled,
|
|
1731
|
+
toast,
|
|
1732
|
+
useBlinkToast,
|
|
937
1733
|
useMedia,
|
|
938
1734
|
useTheme,
|
|
939
1735
|
useThemeName,
|