@streamplace/components 0.7.35 → 0.8.3

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.
Files changed (45) hide show
  1. package/dist/components/content-metadata/content-metadata-form.js +467 -0
  2. package/dist/components/content-metadata/content-rights.js +78 -0
  3. package/dist/components/content-metadata/content-warnings.js +68 -0
  4. package/dist/components/content-metadata/index.js +11 -0
  5. package/dist/components/mobile-player/player.js +4 -0
  6. package/dist/components/mobile-player/ui/report-modal.js +3 -2
  7. package/dist/components/ui/checkbox.js +87 -0
  8. package/dist/components/ui/dialog.js +188 -83
  9. package/dist/components/ui/primitives/input.js +13 -1
  10. package/dist/components/ui/primitives/modal.js +2 -2
  11. package/dist/components/ui/select.js +89 -0
  12. package/dist/components/ui/textarea.js +23 -4
  13. package/dist/components/ui/toast.js +464 -114
  14. package/dist/components/ui/tooltip.js +103 -0
  15. package/dist/index.js +2 -0
  16. package/dist/lib/metadata-constants.js +157 -0
  17. package/dist/lib/theme/theme.js +5 -3
  18. package/dist/streamplace-provider/index.js +14 -4
  19. package/dist/streamplace-store/content-metadata-actions.js +124 -0
  20. package/dist/streamplace-store/streamplace-store.js +22 -5
  21. package/dist/streamplace-store/user.js +67 -7
  22. package/node-compile-cache/v22.15.0-x64-efe9a9df-0/37be0eec +0 -0
  23. package/package.json +3 -3
  24. package/src/components/content-metadata/content-metadata-form.tsx +893 -0
  25. package/src/components/content-metadata/content-rights.tsx +104 -0
  26. package/src/components/content-metadata/content-warnings.tsx +100 -0
  27. package/src/components/content-metadata/index.tsx +10 -0
  28. package/src/components/mobile-player/player.tsx +5 -0
  29. package/src/components/mobile-player/ui/report-modal.tsx +13 -7
  30. package/src/components/ui/checkbox.tsx +147 -0
  31. package/src/components/ui/dialog.tsx +319 -99
  32. package/src/components/ui/primitives/input.tsx +19 -2
  33. package/src/components/ui/primitives/modal.tsx +4 -2
  34. package/src/components/ui/select.tsx +175 -0
  35. package/src/components/ui/textarea.tsx +47 -29
  36. package/src/components/ui/toast.tsx +785 -179
  37. package/src/components/ui/tooltip.tsx +131 -0
  38. package/src/index.tsx +3 -0
  39. package/src/lib/metadata-constants.ts +180 -0
  40. package/src/lib/theme/theme.tsx +10 -6
  41. package/src/streamplace-provider/index.tsx +20 -2
  42. package/src/streamplace-store/content-metadata-actions.tsx +145 -0
  43. package/src/streamplace-store/streamplace-store.tsx +41 -4
  44. package/src/streamplace-store/user.tsx +71 -7
  45. package/tsconfig.tsbuildinfo +1 -1
@@ -47,6 +47,7 @@ const ReportModal = ({ open, onOpenChange, onSubmit, subject, title = "Report",
47
47
  const [additionalComments, setAdditionalComments] = (0, react_1.useState)("");
48
48
  const [isSubmitting, setIsSubmitting] = (0, react_1.useState)(false);
49
49
  const [submitError, setSubmitError] = (0, react_1.useState)(null);
50
+ const { theme } = (0, ui_1.useTheme)();
50
51
  const submitReport = (0, livestream_store_1.useSubmitReport)();
51
52
  const handleCancel = () => {
52
53
  setSelectedReason(null);
@@ -74,7 +75,7 @@ const ReportModal = ({ open, onOpenChange, onSubmit, subject, title = "Report",
74
75
  setIsSubmitting(false);
75
76
  }
76
77
  };
77
- return ((0, jsx_runtime_1.jsxs)(ui_1.Dialog, { open: open, onOpenChange: onOpenChange, title: title, description: description, showCloseButton: true, variant: "default", size: "md", dismissible: false, position: "center", children: [(0, jsx_runtime_1.jsxs)(ui_1.ModalContent, { style: [__1.zero.pb[2]], children: [REPORT_REASONS.map((reason) => ((0, jsx_runtime_1.jsxs)(react_native_1.TouchableOpacity, { onPress: () => setSelectedReason(reason.value), style: [
78
+ return ((0, jsx_runtime_1.jsxs)(ui_1.ResponsiveDialog, { open: open, onOpenChange: onOpenChange, title: title, description: description, showCloseButton: true, variant: "default", size: "md", dismissible: false, position: "center", children: [(0, jsx_runtime_1.jsxs)(react_native_1.View, { style: [__1.zero.pb[2]], children: [REPORT_REASONS.map((reason) => ((0, jsx_runtime_1.jsxs)(react_native_1.TouchableOpacity, { onPress: () => setSelectedReason(reason.value), style: [
78
79
  __1.zero.layout.flex.row,
79
80
  __1.zero.gap.all[2],
80
81
  __1.zero.py[3],
@@ -84,7 +85,7 @@ const ReportModal = ({ open, onOpenChange, onSubmit, subject, title = "Report",
84
85
  selectedReason === reason.value && {
85
86
  backgroundColor: "rgba(0, 122, 255, 0.1)",
86
87
  },
87
- ], children: [(0, jsx_runtime_1.jsx)(react_native_1.View, { children: selectedReason === reason.value ? (0, jsx_runtime_1.jsx)(lucide_react_native_1.CheckCircle, {}) : (0, jsx_runtime_1.jsx)(lucide_react_native_1.Circle, {}) }), (0, jsx_runtime_1.jsxs)(react_native_1.View, { style: [__1.zero.layout.flex.column, __1.zero.gap.all[1], __1.zero.flex[1]], children: [(0, jsx_runtime_1.jsx)(ui_1.Text, { style: [{ fontWeight: "600" }], children: reason.label }), (0, jsx_runtime_1.jsx)(ui_1.Text, { style: [{ fontSize: 14, color: "rgba(255,255,255,0.7)" }], children: reason.description })] })] }, reason.value))), (0, jsx_runtime_1.jsxs)(react_native_1.View, { style: [__1.zero.pb[4], __1.zero.mt[4], __1.zero.px[2]], children: [(0, jsx_runtime_1.jsx)(ui_1.Text, { style: [__1.zero.mb[2]], children: "Additional Comments (optional)" }), (0, jsx_runtime_1.jsx)(ui_1.Textarea, { maxLength: 500, numberOfLines: 3, value: additionalComments, onChangeText: setAdditionalComments, placeholder: "Provide additional context for this report..." }), submitError && ((0, jsx_runtime_1.jsx)(ui_1.Text, { style: [__1.zero.mt[2], { color: "red", fontSize: 14 }], children: submitError }))] })] }), (0, jsx_runtime_1.jsxs)(ui_1.DialogFooter, { children: [(0, jsx_runtime_1.jsx)(ui_1.Button, { variant: "secondary", onPress: handleCancel, disabled: isSubmitting, children: (0, jsx_runtime_1.jsx)(ui_1.Text, { children: "Cancel" }) }), (0, jsx_runtime_1.jsx)(ui_1.Button, { variant: "primary", onPress: handleSubmit, disabled: !selectedReason || isSubmitting, children: isSubmitting ? ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsx)(lucide_react_native_1.Loader2, { style: [{ marginRight: 8 }] }), (0, jsx_runtime_1.jsx)(ui_1.Text, { children: "Submitting..." })] })) : ((0, jsx_runtime_1.jsx)(ui_1.Text, { children: "Submit" })) })] })] }));
88
+ ], children: [(0, jsx_runtime_1.jsx)(react_native_1.View, { children: selectedReason === reason.value ? ((0, jsx_runtime_1.jsx)(lucide_react_native_1.CheckCircle, { color: theme.colors.foreground })) : ((0, jsx_runtime_1.jsx)(lucide_react_native_1.Circle, { color: theme.colors.foreground })) }), (0, jsx_runtime_1.jsxs)(react_native_1.View, { style: [__1.zero.layout.flex.column, __1.zero.gap.all[1], __1.zero.flex[1]], children: [(0, jsx_runtime_1.jsx)(ui_1.Text, { style: [{ fontWeight: "600" }], children: reason.label }), (0, jsx_runtime_1.jsx)(ui_1.Text, { style: [{ fontSize: 14, color: "rgba(255,255,255,0.7)" }], children: reason.description })] })] }, reason.value))), (0, jsx_runtime_1.jsxs)(react_native_1.View, { style: [__1.zero.pb[4], __1.zero.mt[4], __1.zero.px[2]], children: [(0, jsx_runtime_1.jsx)(ui_1.Text, { style: [__1.zero.mb[2]], children: "Additional Comments (optional)" }), (0, jsx_runtime_1.jsx)(ui_1.Textarea, { maxLength: 500, numberOfLines: 3, value: additionalComments, onChangeText: setAdditionalComments, placeholder: "Provide additional context for this report..." }), submitError && ((0, jsx_runtime_1.jsx)(ui_1.Text, { style: [__1.zero.mt[2], { color: "red", fontSize: 14 }], children: submitError }))] })] }), (0, jsx_runtime_1.jsxs)(ui_1.DialogFooter, { children: [(0, jsx_runtime_1.jsx)(ui_1.Button, { variant: "secondary", onPress: handleCancel, disabled: isSubmitting, children: (0, jsx_runtime_1.jsx)(ui_1.Text, { children: "Cancel" }) }), (0, jsx_runtime_1.jsx)(ui_1.Button, { variant: "primary", onPress: handleSubmit, disabled: !selectedReason || isSubmitting, children: isSubmitting ? ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsx)(lucide_react_native_1.Loader2, { style: [{ marginRight: 8 }] }), (0, jsx_runtime_1.jsx)(ui_1.Text, { children: "Submitting..." })] })) : ((0, jsx_runtime_1.jsx)(ui_1.Text, { children: "Submit" })) })] })] }));
88
89
  };
89
90
  exports.ReportModal = ReportModal;
90
91
  exports.default = exports.ReportModal;
@@ -0,0 +1,87 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.Checkbox = void 0;
4
+ const jsx_runtime_1 = require("react/jsx-runtime");
5
+ const lucide_react_native_1 = require("lucide-react-native");
6
+ const react_1 = require("react");
7
+ const react_native_1 = require("react-native");
8
+ const theme_1 = require("../../lib/theme/theme");
9
+ const text_1 = require("./text");
10
+ exports.Checkbox = (0, react_1.forwardRef)(({ checked, onCheckedChange, disabled = false, size = "md", label, description, style, ...props }, ref) => {
11
+ const { theme } = (0, theme_1.useTheme)();
12
+ const handlePress = () => {
13
+ if (!disabled) {
14
+ onCheckedChange(!checked);
15
+ }
16
+ };
17
+ const styles = createStyles(theme, size, disabled, checked);
18
+ return ((0, jsx_runtime_1.jsxs)(react_native_1.TouchableOpacity, { ref: ref, style: [styles.container, style], onPress: handlePress, disabled: disabled, ...props, children: [(0, jsx_runtime_1.jsx)(react_native_1.View, { style: styles.checkbox, children: checked && ((0, jsx_runtime_1.jsx)(lucide_react_native_1.Check, { size: size === "sm" ? 12 : size === "lg" ? 18 : 14, color: disabled
19
+ ? theme.colors.textDisabled
20
+ : theme.colors.primaryForeground })) }), (label || description) && ((0, jsx_runtime_1.jsxs)(react_native_1.View, { style: styles.content, children: [label && (0, jsx_runtime_1.jsx)(text_1.Text, { style: styles.label, children: label }), description && ((0, jsx_runtime_1.jsx)(text_1.Text, { style: styles.description, children: description }))] }))] }));
21
+ });
22
+ exports.Checkbox.displayName = "Checkbox";
23
+ function createStyles(theme, size, disabled, checked) {
24
+ const sizeStyles = {
25
+ sm: {
26
+ checkboxSize: 16,
27
+ borderRadius: 2,
28
+ padding: theme.spacing[1],
29
+ gap: theme.spacing[1],
30
+ },
31
+ md: {
32
+ checkboxSize: 20,
33
+ borderRadius: 4,
34
+ padding: theme.spacing[1],
35
+ gap: theme.spacing[2],
36
+ },
37
+ lg: {
38
+ checkboxSize: 24,
39
+ borderRadius: 6,
40
+ padding: theme.spacing[2],
41
+ gap: theme.spacing[3],
42
+ },
43
+ };
44
+ const currentSize = sizeStyles[size];
45
+ return react_native_1.StyleSheet.create({
46
+ container: {
47
+ flexDirection: "row",
48
+ alignItems: "flex-start",
49
+ opacity: disabled ? 0.5 : 1,
50
+ },
51
+ checkbox: {
52
+ width: currentSize.checkboxSize,
53
+ height: currentSize.checkboxSize,
54
+ borderWidth: 1.5,
55
+ borderColor: disabled
56
+ ? theme.colors.border
57
+ : checked
58
+ ? theme.colors.primary
59
+ : theme.colors.border,
60
+ borderRadius: currentSize.borderRadius,
61
+ backgroundColor: disabled
62
+ ? theme.colors.muted
63
+ : checked
64
+ ? theme.colors.primary
65
+ : "transparent",
66
+ alignItems: "center",
67
+ justifyContent: "center",
68
+ },
69
+ content: {
70
+ flex: 1,
71
+ paddingTop: currentSize.padding * 0.5,
72
+ paddingLeft: theme.spacing[2],
73
+ },
74
+ label: {
75
+ fontSize: size === "sm" ? 14 : size === "lg" ? 18 : 16,
76
+ fontWeight: "500",
77
+ color: disabled ? theme.colors.textDisabled : theme.colors.text,
78
+ lineHeight: size === "sm" ? 18 : size === "lg" ? 22 : 20,
79
+ },
80
+ description: {
81
+ fontSize: size === "sm" ? 12 : size === "lg" ? 16 : 14,
82
+ color: disabled ? theme.colors.textDisabled : theme.colors.textMuted,
83
+ marginTop: theme.spacing[1],
84
+ lineHeight: size === "sm" ? 16 : size === "lg" ? 20 : 18,
85
+ },
86
+ });
87
+ }
@@ -1,16 +1,20 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.dialogVariants = exports.DialogFooter = exports.DialogDescription = exports.DialogTitle = exports.Dialog = void 0;
3
+ exports.dialogVariants = exports.DialogFooter = exports.DialogDescription = exports.DialogTitle = exports.ResponsiveDialog = exports.Dialog = void 0;
4
4
  const tslib_1 = require("tslib");
5
5
  const jsx_runtime_1 = require("react/jsx-runtime");
6
+ const bottom_sheet_1 = tslib_1.__importStar(require("@gorhom/bottom-sheet"));
7
+ // to get the portal
8
+ const Portal = tslib_1.__importStar(require("@rn-primitives/portal"));
6
9
  const class_variance_authority_1 = require("class-variance-authority");
7
10
  const lucide_react_native_1 = require("lucide-react-native");
8
11
  const react_1 = tslib_1.__importStar(require("react"));
9
12
  const react_native_1 = require("react-native");
13
+ const react_native_safe_area_context_1 = require("react-native-safe-area-context");
10
14
  const theme_1 = require("../../lib/theme/theme");
11
- const zero = tslib_1.__importStar(require("../../ui"));
12
15
  const icons_1 = require("./icons");
13
16
  const modal_1 = require("./primitives/modal");
17
+ const text_1 = require("./text");
14
18
  const ThemedX = (0, icons_1.createThemedIcon)(lucide_react_native_1.X);
15
19
  // Dialog variants using class-variance-authority pattern
16
20
  const dialogVariants = (0, class_variance_authority_1.cva)("", {
@@ -42,67 +46,59 @@ const dialogVariants = (0, class_variance_authority_1.cva)("", {
42
46
  },
43
47
  });
44
48
  exports.dialogVariants = dialogVariants;
45
- exports.Dialog = (0, react_1.forwardRef)(({ variant = "left", size = "md", position = "center", children, title, description, dismissible = true, showCloseButton = true, onClose, open = false, onOpenChange, ...props }, ref) => {
46
- const { zero: zt, theme } = (0, theme_1.useTheme)();
47
- // Content styles using theme.zero
48
- const contentStyles = react_1.default.useMemo(() => {
49
- const baseStyle = [
50
- zt.bg.card,
51
- zero.r.lg,
52
- zero.shadows.lg,
53
- { maxHeight: "90%", maxWidth: "90%" },
54
- ];
55
- const variantStyle = (() => {
56
- switch (variant) {
57
- case "sheet":
58
- return [
59
- { borderRadius: zero.borderRadius.xl },
60
- {
61
- borderBottomLeftRadius: 0,
62
- borderBottomRightRadius: 0,
63
- marginTop: "auto",
64
- marginBottom: 0,
65
- maxHeight: "80%",
49
+ // Bottom Sheet Dialog Component
50
+ const DialogBottomSheet = (0, react_1.forwardRef)(function DialogBottomSheet({ overlayStyle, portalHost, children, title, description, showCloseButton = true, onClose, open = false, onOpenChange, ...props }, _ref) {
51
+ const { theme } = (0, theme_1.useTheme)();
52
+ const sheetRef = (0, react_1.useRef)(null);
53
+ const { top } = (0, react_native_safe_area_context_1.useSafeAreaInsets)();
54
+ const dims = (0, react_native_1.useWindowDimensions)();
55
+ const handleClose = react_1.default.useCallback(() => {
56
+ if (onClose) {
57
+ onClose();
58
+ }
59
+ if (onOpenChange) {
60
+ onOpenChange(false);
61
+ }
62
+ }, [onClose, onOpenChange]);
63
+ if (!open) {
64
+ return null;
65
+ }
66
+ return ((0, jsx_runtime_1.jsx)(Portal.Portal, { name: "dialog", children: (0, jsx_runtime_1.jsx)(bottom_sheet_1.default, { ref: sheetRef, index: open ? 0 : -1, enablePanDownToClose: true, enableDynamicSizing: true, maxDynamicContentSize: dims.height - top, keyboardBehavior: "interactive", keyboardBlurBehavior: "restore", enableContentPanningGesture: false, backdropComponent: ({ style }) => ((0, jsx_runtime_1.jsx)(react_native_1.Pressable, { style: [style, react_native_1.StyleSheet.absoluteFill], onPress: handleClose })), onClose: handleClose, style: [overlayStyle], backgroundStyle: {
67
+ backgroundColor: theme.colors.card,
68
+ borderRadius: theme.borderRadius.lg,
69
+ ...theme.shadows.lg,
70
+ }, handleIndicatorStyle: {
71
+ width: 48,
72
+ height: 4,
73
+ backgroundColor: theme.colors.textMuted,
74
+ }, children: (0, jsx_runtime_1.jsxs)(bottom_sheet_1.BottomSheetScrollView, { style: {
75
+ flex: 1,
76
+ width: "100%",
77
+ }, contentContainerStyle: { flexGrow: 1 }, children: [(title || showCloseButton) && ((0, jsx_runtime_1.jsxs)(react_native_1.View, { style: {
78
+ paddingHorizontal: theme.spacing[4],
79
+ paddingVertical: theme.spacing[4],
80
+ flexDirection: "row",
81
+ alignItems: "center",
82
+ justifyContent: "space-between",
66
83
  width: "100%",
67
- maxWidth: "100%",
68
- },
69
- ];
70
- case "fullscreen":
71
- return [
72
- {
84
+ }, children: [title && (0, jsx_runtime_1.jsx)(exports.DialogTitle, { children: title }), showCloseButton && ((0, jsx_runtime_1.jsx)(react_native_1.Pressable, { onPress: handleClose, style: {
85
+ width: theme.touchTargets.minimum,
86
+ height: theme.touchTargets.minimum,
87
+ alignItems: "center",
88
+ justifyContent: "center",
89
+ borderRadius: theme.borderRadius.sm,
90
+ marginLeft: theme.spacing[2],
91
+ }, children: (0, jsx_runtime_1.jsx)(DialogCloseIcon, {}) }))] })), (0, jsx_runtime_1.jsxs)(react_native_1.View, { style: {
92
+ paddingHorizontal: theme.spacing[4],
93
+ paddingBottom: theme.spacing[6],
94
+ flex: 1,
73
95
  width: "100%",
74
- height: "100%",
75
- maxWidth: "100%",
76
- maxHeight: "100%",
77
- borderRadius: 0,
78
- margin: 0,
79
- },
80
- ];
81
- default:
82
- return [];
83
- }
84
- })();
85
- const sizeStyle = (() => {
86
- switch (size) {
87
- case "sm":
88
- return { minWidth: 300, minHeight: 200 };
89
- case "lg":
90
- return { minWidth: 500, minHeight: 400 };
91
- case "xl":
92
- return { minWidth: 600, minHeight: 500 };
93
- case "full":
94
- return {
95
- width: "95%",
96
- height: "95%",
97
- maxWidth: "95%",
98
- maxHeight: "95%",
99
- };
100
- default:
101
- return { minWidth: 400, minHeight: 300 };
102
- }
103
- })();
104
- return [baseStyle, variantStyle, sizeStyle].flat();
105
- }, [variant, size, zero]);
96
+ }, children: [description && ((0, jsx_runtime_1.jsx)(exports.DialogDescription, { children: description })), children] })] }) }) }));
97
+ });
98
+ exports.Dialog = (0, react_1.forwardRef)(({ variant = "default", size = "md", position = "center", children, title, description, dismissible = true, showCloseButton = true, onClose, open = false, onOpenChange, ...props }, ref) => {
99
+ const { theme } = (0, theme_1.useTheme)();
100
+ // Create dynamic styles based on theme
101
+ const styles = react_1.default.useMemo(() => createStyles(theme), [theme]);
106
102
  const handleClose = react_1.default.useCallback(() => {
107
103
  if (onClose) {
108
104
  onClose();
@@ -128,46 +124,155 @@ exports.Dialog = (0, react_1.forwardRef)(({ variant = "left", size = "md", posit
128
124
  }
129
125
  return "fade";
130
126
  }, [variant]);
131
- return ((0, jsx_runtime_1.jsx)(modal_1.ModalPrimitive.Root, { ref: ref, open: open, onOpenChange: onOpenChange, presentationStyle: presentationStyle, animationType: animationType, ...props, children: (0, jsx_runtime_1.jsx)(modal_1.ModalPrimitive.Overlay, { dismissible: dismissible, onDismiss: handleClose, style: zt.bg.overlay, children: (0, jsx_runtime_1.jsxs)(modal_1.ModalPrimitive.Content, { position: position || "left", size: size || "md", style: contentStyles, children: [(title || showCloseButton) && ((0, jsx_runtime_1.jsxs)(modal_1.ModalPrimitive.Header, { withBorder: variant !== "sheet", style: [
132
- zero.p[4],
133
- {
134
- flexDirection: "row",
135
- alignItems: "center",
136
- justifyContent: "space-between",
137
- },
138
- ], children: [(0, jsx_runtime_1.jsx)(exports.DialogTitle, { children: title }), showCloseButton && ((0, jsx_runtime_1.jsx)(modal_1.ModalPrimitive.Close, { onClose: handleClose, style: [
139
- zero.p[2],
140
- {
141
- width: 44,
142
- height: 44,
143
- alignItems: "center",
144
- justifyContent: "center",
145
- },
146
- ], children: (0, jsx_runtime_1.jsx)(DialogCloseIcon, {}) }))] })), (0, jsx_runtime_1.jsxs)(modal_1.ModalPrimitive.Body, { scrollable: variant !== "fullscreen", style: [zero.p[6], { paddingTop: 0, flex: 1 }], children: [description && ((0, jsx_runtime_1.jsx)(exports.DialogDescription, { children: description })), children] })] }) }) }));
127
+ return ((0, jsx_runtime_1.jsx)(modal_1.ModalPrimitive.Root, { ref: ref, open: open, onOpenChange: onOpenChange, presentationStyle: presentationStyle, animationType: animationType, ...props, children: (0, jsx_runtime_1.jsx)(modal_1.ModalPrimitive.Overlay, { dismissible: dismissible, onDismiss: handleClose, style: styles.overlay, children: (0, jsx_runtime_1.jsxs)(modal_1.ModalPrimitive.Content, { position: position || "center", size: size || "md", style: [
128
+ styles.content,
129
+ variant === "sheet" && styles.sheetContent,
130
+ variant === "fullscreen" && styles.fullscreenContent,
131
+ size === "sm" && styles.smContent,
132
+ size === "md" && styles.mdContent,
133
+ size === "lg" && styles.lgContent,
134
+ size === "xl" && styles.xlContent,
135
+ size === "full" && styles.fullContent,
136
+ ], children: [(title || showCloseButton) && ((0, jsx_runtime_1.jsxs)(modal_1.ModalPrimitive.Header, { withBorder: variant !== "sheet", style: styles.header, children: [(0, jsx_runtime_1.jsx)(exports.DialogTitle, { children: title }), showCloseButton && ((0, jsx_runtime_1.jsx)(modal_1.ModalPrimitive.Close, { onClose: handleClose, style: styles.closeButton, children: (0, jsx_runtime_1.jsx)(DialogCloseIcon, {}) }))] })), (0, jsx_runtime_1.jsxs)(modal_1.ModalPrimitive.Body, { scrollable: variant !== "fullscreen", style: styles.body, children: [description && ((0, jsx_runtime_1.jsx)(exports.DialogDescription, { children: description })), children] })] }) }) }));
147
137
  });
148
138
  exports.Dialog.displayName = "Dialog";
139
+ /// Responsive Dialog Component. On mobile this will render a *bottom sheet*.
140
+ /// Prefer this over the regular Dialog component for better mobile UX.
141
+ exports.ResponsiveDialog = (0, react_1.forwardRef)(({ children, size, ...props }, ref) => {
142
+ const { width } = (0, react_native_1.useWindowDimensions)();
143
+ // On web, you might want to always use the normal dialog
144
+ // On mobile (width < 800), use the bottom sheet
145
+ const isBottomSheet = react_native_1.Platform.OS !== "web" && width < 800;
146
+ if (isBottomSheet) {
147
+ return ((0, jsx_runtime_1.jsx)(DialogBottomSheet, { ref: ref, ...props, size: "full", showCloseButton: false, variant: "fullscreen", children: children }));
148
+ }
149
+ // Use larger default size for regular dialogs to give more room
150
+ const dialogSize = size || "lg";
151
+ return ((0, jsx_runtime_1.jsx)(exports.Dialog, { ref: ref, size: dialogSize, ...props, children: children }));
152
+ });
153
+ exports.ResponsiveDialog.displayName = "ResponsiveDialog";
149
154
  exports.DialogTitle = (0, react_1.forwardRef)(({ children, style, ...props }, ref) => {
150
- const { zero: zt } = (0, theme_1.useTheme)();
155
+ const { theme } = (0, theme_1.useTheme)();
156
+ const styles = react_1.default.useMemo(() => createStyles(theme), [theme]);
151
157
  if (!children)
152
158
  return null;
153
- return ((0, jsx_runtime_1.jsx)(react_native_1.Text, { ref: ref, style: [zt.text.xl, { fontWeight: "600", flex: 1 }, style], ...props, children: children }));
159
+ return ((0, jsx_runtime_1.jsx)(text_1.Text, { ref: ref, style: [styles.title, style], ...props, children: children }));
154
160
  });
155
161
  exports.DialogTitle.displayName = "DialogTitle";
156
162
  exports.DialogDescription = (0, react_1.forwardRef)(({ children, style, ...props }, ref) => {
157
- const { zero: zt } = (0, theme_1.useTheme)();
163
+ const { theme } = (0, theme_1.useTheme)();
164
+ const styles = react_1.default.useMemo(() => createStyles(theme), [theme]);
158
165
  if (!children)
159
166
  return null;
160
- return ((0, jsx_runtime_1.jsx)(react_native_1.Text, { ref: ref, style: [zt.text.muted, zero.mb[4], style], ...props, children: children }));
167
+ return ((0, jsx_runtime_1.jsx)(text_1.Text, { ref: ref, style: [styles.description, style], ...props, children: children }));
161
168
  });
162
169
  exports.DialogDescription.displayName = "DialogDescription";
163
170
  exports.DialogFooter = (0, react_1.forwardRef)(({ children, direction = "row", justify = "flex-end", withBorder = true, style, ...props }, ref) => {
164
- const { zero: zt } = (0, theme_1.useTheme)();
171
+ const { theme } = (0, theme_1.useTheme)();
172
+ const styles = react_1.default.useMemo(() => createStyles(theme), [theme]);
165
173
  if (!children)
166
174
  return null;
167
- return ((0, jsx_runtime_1.jsx)(modal_1.ModalPrimitive.Footer, { ref: ref, withBorder: withBorder, direction: direction, justify: justify, style: [zero.p[6], { gap: 8 }, style], ...props, children: children }));
175
+ return ((0, jsx_runtime_1.jsx)(modal_1.ModalPrimitive.Footer, { ref: ref, withBorder: withBorder, direction: direction, justify: justify, style: [styles.footer, style], ...props, children: children }));
168
176
  });
169
177
  exports.DialogFooter.displayName = "DialogFooter";
170
178
  // Dialog Close Icon component (Lucide X)
171
179
  const DialogCloseIcon = () => {
172
180
  return (0, jsx_runtime_1.jsx)(ThemedX, { size: "md", variant: "default" });
173
181
  };
182
+ // Create theme-aware styles
183
+ function createStyles(theme) {
184
+ return react_native_1.StyleSheet.create({
185
+ overlay: {
186
+ backgroundColor: "rgba(0, 0, 0, 0.5)",
187
+ },
188
+ content: {
189
+ backgroundColor: theme.colors.card,
190
+ borderRadius: theme.borderRadius.lg,
191
+ ...theme.shadows.lg,
192
+ maxHeight: "90%",
193
+ maxWidth: "90%",
194
+ },
195
+ // Variant styles
196
+ sheetContent: {
197
+ borderTopLeftRadius: theme.borderRadius.xl,
198
+ borderTopRightRadius: theme.borderRadius.xl,
199
+ borderBottomLeftRadius: 0,
200
+ borderBottomRightRadius: 0,
201
+ marginTop: "auto",
202
+ marginBottom: 0,
203
+ maxHeight: "80%",
204
+ width: "100%",
205
+ maxWidth: "100%",
206
+ },
207
+ fullscreenContent: {
208
+ width: "100%",
209
+ height: "100%",
210
+ maxWidth: "100%",
211
+ maxHeight: "100%",
212
+ borderRadius: 0,
213
+ margin: 0,
214
+ },
215
+ // Size styles
216
+ smContent: {
217
+ minWidth: 300,
218
+ minHeight: 200,
219
+ },
220
+ mdContent: {
221
+ minWidth: 400,
222
+ minHeight: 300,
223
+ },
224
+ lgContent: {
225
+ minWidth: 500,
226
+ minHeight: 400,
227
+ },
228
+ xlContent: {
229
+ minWidth: 600,
230
+ minHeight: 500,
231
+ },
232
+ fullContent: {
233
+ width: "95%",
234
+ height: "95%",
235
+ maxWidth: "95%",
236
+ maxHeight: "95%",
237
+ },
238
+ header: {
239
+ paddingHorizontal: theme.spacing[6],
240
+ paddingVertical: theme.spacing[4],
241
+ flexDirection: "row",
242
+ alignItems: "center",
243
+ justifyContent: "space-between",
244
+ },
245
+ body: {
246
+ paddingHorizontal: theme.spacing[6],
247
+ paddingBottom: theme.spacing[6],
248
+ flex: 1,
249
+ },
250
+ footer: {
251
+ paddingHorizontal: theme.spacing[6],
252
+ paddingVertical: theme.spacing[4],
253
+ gap: theme.spacing[2],
254
+ width: "100%",
255
+ },
256
+ title: {
257
+ fontSize: 20,
258
+ fontWeight: "600",
259
+ color: theme.colors.text,
260
+ flex: 1,
261
+ lineHeight: 24,
262
+ },
263
+ description: {
264
+ fontSize: 16,
265
+ color: theme.colors.textMuted,
266
+ lineHeight: 22,
267
+ marginVertical: theme.spacing[4],
268
+ },
269
+ closeButton: {
270
+ width: theme.touchTargets.minimum,
271
+ height: theme.touchTargets.minimum,
272
+ alignItems: "center",
273
+ justifyContent: "center",
274
+ borderRadius: theme.borderRadius.sm,
275
+ marginLeft: theme.spacing[2],
276
+ },
277
+ });
278
+ }
@@ -3,11 +3,23 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.InputPrimitive = exports.InputGroup = exports.InputAddon = exports.InputError = exports.InputDescription = exports.InputLabel = exports.InputContainer = exports.InputRoot = void 0;
4
4
  const tslib_1 = require("tslib");
5
5
  const jsx_runtime_1 = require("react/jsx-runtime");
6
+ const bottom_sheet_1 = require("@gorhom/bottom-sheet");
6
7
  const react_1 = tslib_1.__importStar(require("react"));
7
8
  const react_native_1 = require("react-native");
8
9
  // Input root primitive - the main TextInput component
9
10
  exports.InputRoot = (0, react_1.forwardRef)(({ value, onChangeText, onChange, onFocus, onBlur, error = false, disabled = false, loading = false, editable, style, placeholderTextColor = "#9ca3af", ...props }, ref) => {
10
11
  const [isFocused, setIsFocused] = react_1.default.useState(false);
12
+ let isInBottomSheet = false;
13
+ try {
14
+ (0, bottom_sheet_1.useBottomSheetInternal)();
15
+ isInBottomSheet = true;
16
+ }
17
+ catch {
18
+ isInBottomSheet = false;
19
+ }
20
+ const InputComponent = isInBottomSheet && react_native_1.Platform.OS !== "web"
21
+ ? bottom_sheet_1.BottomSheetTextInput
22
+ : react_native_1.TextInput;
11
23
  const handleChangeText = react_1.default.useCallback((text) => {
12
24
  if (onChangeText) {
13
25
  onChangeText(text);
@@ -28,7 +40,7 @@ exports.InputRoot = (0, react_1.forwardRef)(({ value, onChangeText, onChange, on
28
40
  onBlur(event);
29
41
  }
30
42
  }, [onBlur]);
31
- return ((0, jsx_runtime_1.jsx)(react_native_1.TextInput, { ref: ref, value: value, onChangeText: handleChangeText, onFocus: handleFocus, onBlur: handleBlur, editable: !disabled && !loading && editable, placeholderTextColor: placeholderTextColor, style: [
43
+ return ((0, jsx_runtime_1.jsx)(InputComponent, { ref: ref, value: value, onChangeText: handleChangeText, onFocus: handleFocus, onBlur: handleBlur, editable: !disabled && !loading && editable, placeholderTextColor: placeholderTextColor, style: [
32
44
  primitiveStyles.input,
33
45
  style,
34
46
  error && primitiveStyles.inputError,
@@ -7,7 +7,7 @@ const react_1 = tslib_1.__importStar(require("react"));
7
7
  const react_native_1 = require("react-native");
8
8
  const { width: screenWidth, height: screenHeight } = react_native_1.Dimensions.get("window");
9
9
  // Modal root primitive - handles the native Modal component
10
- exports.ModalRoot = (0, react_1.forwardRef)(({ open = false, onOpenChange, children, onRequestClose, animationType = "fade", presentationStyle = react_native_1.Platform.OS === "ios" ? "pageSheet" : "fullScreen", statusBarTranslucent = react_native_1.Platform.OS === "android", ...props }, ref) => {
10
+ exports.ModalRoot = (0, react_1.forwardRef)(({ open = false, onOpenChange, children, onRequestClose, animationType = "fade", presentationStyle = react_native_1.Platform.OS === "ios" ? "pageSheet" : "formSheet", statusBarTranslucent = react_native_1.Platform.OS !== "ios", transparent = true, ...props }, ref) => {
11
11
  const handleRequestClose = react_1.default.useCallback((e) => {
12
12
  if (onOpenChange) {
13
13
  onOpenChange(false);
@@ -16,7 +16,7 @@ exports.ModalRoot = (0, react_1.forwardRef)(({ open = false, onOpenChange, child
16
16
  onRequestClose(e);
17
17
  }
18
18
  }, [onOpenChange, onRequestClose]);
19
- return ((0, jsx_runtime_1.jsx)(react_native_1.Modal, { visible: open, onRequestClose: handleRequestClose, animationType: animationType, presentationStyle: presentationStyle, statusBarTranslucent: statusBarTranslucent, ...props, children: (0, jsx_runtime_1.jsx)(react_native_1.View, { ref: ref, style: primitiveStyles.container, children: children }) }));
19
+ return ((0, jsx_runtime_1.jsx)(react_native_1.Modal, { visible: open, onRequestClose: handleRequestClose, animationType: animationType, presentationStyle: presentationStyle, statusBarTranslucent: statusBarTranslucent, transparent: transparent, ...props, children: (0, jsx_runtime_1.jsx)(react_native_1.View, { ref: ref, style: primitiveStyles.container, children: children }) }));
20
20
  });
21
21
  exports.ModalRoot.displayName = "ModalRoot";
22
22
  exports.ModalOverlay = (0, react_1.forwardRef)(({ dismissible = true, onDismiss, onPress, style, children, activeOpacity = 1, ...props }, ref) => {
@@ -0,0 +1,89 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.Select = void 0;
4
+ const jsx_runtime_1 = require("react/jsx-runtime");
5
+ const lucide_react_native_1 = require("lucide-react-native");
6
+ const react_1 = require("react");
7
+ const react_native_1 = require("react-native");
8
+ const theme_1 = require("../../lib/theme/theme");
9
+ const text_1 = require("./text");
10
+ exports.Select = (0, react_1.forwardRef)(({ value, onValueChange, placeholder = "Select...", items, disabled = false, style, }, ref) => {
11
+ const { theme } = (0, theme_1.useTheme)();
12
+ const [isOpen, setIsOpen] = (0, react_1.useState)(false);
13
+ const selectedItem = items.find((item) => item.value === value);
14
+ const handleSelect = (itemValue) => {
15
+ onValueChange(itemValue);
16
+ setIsOpen(false);
17
+ };
18
+ const styles = createStyles(theme, disabled);
19
+ return ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsxs)(react_native_1.TouchableOpacity, { ref: ref, style: [styles.container, style], onPress: () => !disabled && setIsOpen(true), disabled: disabled, children: [(0, jsx_runtime_1.jsx)(text_1.Text, { style: styles.value, children: selectedItem?.label || placeholder }), (0, jsx_runtime_1.jsx)(lucide_react_native_1.ChevronDown, { size: 16, color: theme.colors.textMuted })] }), (0, jsx_runtime_1.jsx)(react_native_1.Modal, { visible: isOpen, transparent: true, animationType: "fade", onRequestClose: () => setIsOpen(false), children: (0, jsx_runtime_1.jsx)(react_native_1.TouchableOpacity, { style: styles.overlay, activeOpacity: 1, onPress: () => setIsOpen(false), children: (0, jsx_runtime_1.jsx)(react_native_1.View, { style: styles.dropdown, children: (0, jsx_runtime_1.jsx)(react_native_1.FlatList, { data: items, keyExtractor: (item) => item.value, renderItem: ({ item }) => ((0, jsx_runtime_1.jsxs)(react_native_1.TouchableOpacity, { style: [
20
+ styles.item,
21
+ item.value === value && styles.selectedItem,
22
+ ], onPress: () => handleSelect(item.value), children: [(0, jsx_runtime_1.jsx)(text_1.Text, { style: [
23
+ styles.itemText,
24
+ item.value === value ? styles.selectedItemText : {},
25
+ ], children: item.label }), item.description && ((0, jsx_runtime_1.jsx)(text_1.Text, { style: styles.itemDescription, children: item.description }))] })), style: styles.list }) }) }) })] }));
26
+ });
27
+ exports.Select.displayName = "Select";
28
+ function createStyles(theme, disabled) {
29
+ return react_native_1.StyleSheet.create({
30
+ container: {
31
+ flexDirection: "row",
32
+ alignItems: "center",
33
+ justifyContent: "space-between",
34
+ paddingHorizontal: theme.spacing[3],
35
+ paddingVertical: theme.spacing[3],
36
+ borderWidth: 1,
37
+ borderColor: theme.colors.border,
38
+ borderRadius: theme.borderRadius.md,
39
+ backgroundColor: disabled ? theme.colors.muted : theme.colors.card,
40
+ minHeight: theme.touchTargets.minimum,
41
+ },
42
+ value: {
43
+ fontSize: 16,
44
+ color: disabled ? theme.colors.textDisabled : theme.colors.text,
45
+ flex: 1,
46
+ },
47
+ overlay: {
48
+ flex: 1,
49
+ backgroundColor: "rgba(0, 0, 0, 0.5)",
50
+ justifyContent: "center",
51
+ alignItems: "center",
52
+ },
53
+ dropdown: {
54
+ backgroundColor: theme.colors.background,
55
+ borderRadius: theme.borderRadius.md,
56
+ borderWidth: 1,
57
+ borderColor: theme.colors.border,
58
+ maxHeight: 300,
59
+ width: "90%",
60
+ maxWidth: 400,
61
+ ...theme.shadows.lg,
62
+ },
63
+ list: {
64
+ maxHeight: 300,
65
+ },
66
+ item: {
67
+ paddingHorizontal: theme.spacing[4],
68
+ paddingVertical: theme.spacing[3],
69
+ borderBottomWidth: 1,
70
+ borderBottomColor: theme.colors.border,
71
+ },
72
+ selectedItem: {
73
+ backgroundColor: theme.colors.primary,
74
+ },
75
+ itemText: {
76
+ fontSize: 16,
77
+ color: theme.colors.text,
78
+ },
79
+ selectedItemText: {
80
+ color: theme.colors.primaryForeground,
81
+ fontWeight: "500",
82
+ },
83
+ itemDescription: {
84
+ fontSize: 14,
85
+ color: theme.colors.textMuted,
86
+ marginTop: theme.spacing[1],
87
+ },
88
+ });
89
+ }
@@ -1,11 +1,28 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.Textarea = Textarea;
3
+ exports.Textarea = void 0;
4
+ const tslib_1 = require("tslib");
4
5
  const jsx_runtime_1 = require("react/jsx-runtime");
6
+ const bottom_sheet_1 = require("@gorhom/bottom-sheet");
7
+ const React = tslib_1.__importStar(require("react"));
5
8
  const react_native_1 = require("react-native");
6
9
  const atoms_1 = require("../../lib/theme/atoms");
7
- function Textarea({ style, multiline = true, numberOfLines = 4, ...props }) {
8
- return ((0, jsx_runtime_1.jsx)(react_native_1.TextInput, { style: [
10
+ const Textarea = React.forwardRef(({ style, multiline = true, numberOfLines = 4, ...props }, ref) => {
11
+ // Detect if we're inside a bottom sheet
12
+ let isInBottomSheet = false;
13
+ try {
14
+ (0, bottom_sheet_1.useBottomSheetInternal)();
15
+ isInBottomSheet = true;
16
+ }
17
+ catch {
18
+ // Not in a bottom sheet context
19
+ isInBottomSheet = false;
20
+ }
21
+ // Use BottomSheetTextInput when inside a bottom sheet, regular TextInput otherwise
22
+ const InputComponent = isInBottomSheet && react_native_1.Platform.OS !== "web"
23
+ ? bottom_sheet_1.BottomSheetTextInput
24
+ : react_native_1.TextInput;
25
+ return ((0, jsx_runtime_1.jsx)(InputComponent, { ref: ref, style: [
9
26
  atoms_1.flex.values[1],
10
27
  atoms_1.borders.width.thin,
11
28
  atoms_1.borders.color.gray[400],
@@ -16,4 +33,6 @@ function Textarea({ style, multiline = true, numberOfLines = 4, ...props }) {
16
33
  { borderRadius: 10 },
17
34
  style,
18
35
  ], multiline: multiline, numberOfLines: numberOfLines, textAlignVertical: "top", ...props }));
19
- }
36
+ });
37
+ exports.Textarea = Textarea;
38
+ Textarea.displayName = "Textarea";