@streamplace/components 0.0.1 → 0.7.0

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 (169) hide show
  1. package/LICENSE +18 -0
  2. package/README.md +35 -0
  3. package/dist/components/chat/chat-box.js +109 -0
  4. package/dist/components/chat/chat-message.js +76 -0
  5. package/dist/components/chat/chat.js +56 -0
  6. package/dist/components/chat/mention-suggestions.js +39 -0
  7. package/dist/components/chat/mod-view.js +33 -0
  8. package/dist/components/mobile-player/fullscreen.js +69 -0
  9. package/dist/components/mobile-player/fullscreen.native.js +151 -0
  10. package/dist/components/mobile-player/player.js +103 -0
  11. package/dist/components/mobile-player/props.js +1 -0
  12. package/dist/components/mobile-player/shared.js +51 -0
  13. package/dist/components/mobile-player/ui/countdown.js +79 -0
  14. package/dist/components/mobile-player/ui/index.js +5 -0
  15. package/dist/components/mobile-player/ui/input.js +38 -0
  16. package/dist/components/mobile-player/ui/metrics.js +40 -0
  17. package/dist/components/mobile-player/ui/streamer-context-menu.js +4 -0
  18. package/dist/components/mobile-player/ui/viewer-context-menu.js +20 -0
  19. package/dist/components/mobile-player/use-webrtc.js +232 -0
  20. package/dist/components/mobile-player/video.js +375 -0
  21. package/dist/components/mobile-player/video.native.js +238 -0
  22. package/dist/components/mobile-player/webrtc-diagnostics.js +106 -0
  23. package/dist/components/mobile-player/webrtc-primitives.js +25 -0
  24. package/dist/components/mobile-player/webrtc-primitives.native.js +1 -0
  25. package/dist/components/ui/button.js +220 -0
  26. package/dist/components/ui/dialog.js +203 -0
  27. package/dist/components/ui/dropdown.js +148 -0
  28. package/dist/components/ui/icons.js +22 -0
  29. package/dist/components/ui/index.js +22 -0
  30. package/dist/components/ui/input.js +202 -0
  31. package/dist/components/ui/loader.js +7 -0
  32. package/dist/components/ui/primitives/button.js +121 -0
  33. package/dist/components/ui/primitives/input.js +202 -0
  34. package/dist/components/ui/primitives/modal.js +203 -0
  35. package/dist/components/ui/primitives/text.js +286 -0
  36. package/dist/components/ui/resizeable.js +101 -0
  37. package/dist/components/ui/text.js +175 -0
  38. package/dist/components/ui/textarea.js +17 -0
  39. package/dist/components/ui/toast.js +129 -0
  40. package/dist/components/ui/view.js +250 -0
  41. package/dist/hooks/index.js +9 -0
  42. package/dist/hooks/useAvatars.js +32 -0
  43. package/dist/hooks/useCameraToggle.js +9 -0
  44. package/dist/hooks/useKeyboard.js +33 -0
  45. package/dist/hooks/useKeyboardSlide.js +11 -0
  46. package/dist/hooks/useLivestreamInfo.js +62 -0
  47. package/dist/hooks/useOuterAndInnerDimensions.js +27 -0
  48. package/dist/hooks/usePlayerDimensions.js +19 -0
  49. package/dist/hooks/useSegmentTiming.js +62 -0
  50. package/dist/index.js +16 -0
  51. package/dist/lib/facet.js +88 -0
  52. package/dist/lib/theme/atoms.js +620 -0
  53. package/dist/lib/theme/atoms.types.js +5 -0
  54. package/dist/lib/theme/index.js +9 -0
  55. package/dist/lib/theme/theme.js +248 -0
  56. package/dist/lib/theme/tokens.js +383 -0
  57. package/dist/lib/utils.js +94 -0
  58. package/dist/livestream-provider/index.js +25 -0
  59. package/dist/livestream-provider/websocket.js +41 -0
  60. package/dist/livestream-store/chat.js +186 -0
  61. package/dist/livestream-store/context.js +2 -0
  62. package/dist/livestream-store/index.js +4 -0
  63. package/dist/livestream-store/livestream-state.js +1 -0
  64. package/dist/livestream-store/livestream-store.js +42 -0
  65. package/dist/livestream-store/stream-key.js +115 -0
  66. package/dist/livestream-store/websocket-consumer.js +55 -0
  67. package/dist/player-store/context.js +2 -0
  68. package/dist/player-store/index.js +6 -0
  69. package/dist/player-store/player-provider.js +52 -0
  70. package/dist/player-store/player-state.js +22 -0
  71. package/dist/player-store/player-store.js +159 -0
  72. package/dist/player-store/single-player-provider.js +109 -0
  73. package/dist/streamplace-provider/context.js +2 -0
  74. package/dist/streamplace-provider/index.js +16 -0
  75. package/dist/streamplace-provider/poller.js +46 -0
  76. package/dist/streamplace-provider/xrpc.js +0 -0
  77. package/dist/streamplace-store/block.js +23 -0
  78. package/dist/streamplace-store/index.js +3 -0
  79. package/dist/streamplace-store/stream.js +193 -0
  80. package/dist/streamplace-store/streamplace-store.js +37 -0
  81. package/dist/streamplace-store/user.js +47 -0
  82. package/dist/streamplace-store/xrpc.js +12 -0
  83. package/node-compile-cache/v22.15.0-x64-efe9a9df-0/37be0eec +0 -0
  84. package/node-compile-cache/v22.15.0-x64-efe9a9df-0/56540125 +0 -0
  85. package/node-compile-cache/v22.15.0-x64-efe9a9df-0/67b1eb60 +0 -0
  86. package/node-compile-cache/v22.15.0-x64-efe9a9df-0/7c275f90 +0 -0
  87. package/package.json +50 -8
  88. package/src/components/chat/chat-box.tsx +195 -0
  89. package/src/components/chat/chat-message.tsx +192 -0
  90. package/src/components/chat/chat.tsx +128 -0
  91. package/src/components/chat/mention-suggestions.tsx +71 -0
  92. package/src/components/chat/mod-view.tsx +118 -0
  93. package/src/components/mobile-player/fullscreen.native.tsx +193 -0
  94. package/src/components/mobile-player/fullscreen.tsx +79 -0
  95. package/src/components/mobile-player/player.tsx +134 -0
  96. package/src/components/mobile-player/props.tsx +11 -0
  97. package/src/components/mobile-player/shared.tsx +56 -0
  98. package/src/components/mobile-player/ui/countdown.tsx +119 -0
  99. package/src/components/mobile-player/ui/index.ts +5 -0
  100. package/src/components/mobile-player/ui/input.tsx +85 -0
  101. package/src/components/mobile-player/ui/metrics.tsx +69 -0
  102. package/src/components/mobile-player/ui/streamer-context-menu.tsx +3 -0
  103. package/src/components/mobile-player/ui/viewer-context-menu.tsx +70 -0
  104. package/src/components/mobile-player/use-webrtc.tsx +282 -0
  105. package/src/components/mobile-player/video.native.tsx +360 -0
  106. package/src/components/mobile-player/video.tsx +557 -0
  107. package/src/components/mobile-player/webrtc-diagnostics.tsx +149 -0
  108. package/src/components/mobile-player/webrtc-primitives.native.tsx +6 -0
  109. package/src/components/mobile-player/webrtc-primitives.tsx +33 -0
  110. package/src/components/ui/button.tsx +309 -0
  111. package/src/components/ui/dialog.tsx +376 -0
  112. package/src/components/ui/dropdown.tsx +399 -0
  113. package/src/components/ui/icons.tsx +50 -0
  114. package/src/components/ui/index.ts +33 -0
  115. package/src/components/ui/input.tsx +350 -0
  116. package/src/components/ui/loader.tsx +9 -0
  117. package/src/components/ui/primitives/button.tsx +292 -0
  118. package/src/components/ui/primitives/input.tsx +422 -0
  119. package/src/components/ui/primitives/modal.tsx +421 -0
  120. package/src/components/ui/primitives/text.tsx +499 -0
  121. package/src/components/ui/resizeable.tsx +169 -0
  122. package/src/components/ui/text.tsx +330 -0
  123. package/src/components/ui/textarea.tsx +34 -0
  124. package/src/components/ui/toast.tsx +203 -0
  125. package/src/components/ui/view.tsx +344 -0
  126. package/src/hooks/index.ts +9 -0
  127. package/src/hooks/useAvatars.tsx +44 -0
  128. package/src/hooks/useCameraToggle.ts +12 -0
  129. package/src/hooks/useKeyboard.tsx +41 -0
  130. package/src/hooks/useKeyboardSlide.ts +12 -0
  131. package/src/hooks/useLivestreamInfo.ts +67 -0
  132. package/src/hooks/useOuterAndInnerDimensions.tsx +32 -0
  133. package/src/hooks/usePlayerDimensions.ts +23 -0
  134. package/src/hooks/useSegmentTiming.tsx +88 -0
  135. package/src/index.tsx +27 -0
  136. package/src/lib/facet.ts +131 -0
  137. package/src/lib/theme/atoms.ts +760 -0
  138. package/src/lib/theme/atoms.types.ts +258 -0
  139. package/src/lib/theme/index.ts +48 -0
  140. package/src/lib/theme/theme.tsx +436 -0
  141. package/src/lib/theme/tokens.ts +409 -0
  142. package/src/lib/utils.ts +132 -0
  143. package/src/livestream-provider/index.tsx +48 -0
  144. package/src/livestream-provider/websocket.tsx +47 -0
  145. package/src/livestream-store/chat.tsx +261 -0
  146. package/src/livestream-store/context.tsx +10 -0
  147. package/src/livestream-store/index.tsx +4 -0
  148. package/src/livestream-store/livestream-state.tsx +21 -0
  149. package/src/livestream-store/livestream-store.tsx +59 -0
  150. package/src/livestream-store/stream-key.tsx +124 -0
  151. package/src/livestream-store/websocket-consumer.tsx +62 -0
  152. package/src/player-store/context.tsx +11 -0
  153. package/src/player-store/index.tsx +6 -0
  154. package/src/player-store/player-provider.tsx +89 -0
  155. package/src/player-store/player-state.tsx +187 -0
  156. package/src/player-store/player-store.tsx +239 -0
  157. package/src/player-store/single-player-provider.tsx +181 -0
  158. package/src/streamplace-provider/context.tsx +10 -0
  159. package/src/streamplace-provider/index.tsx +32 -0
  160. package/src/streamplace-provider/poller.tsx +55 -0
  161. package/src/streamplace-provider/xrpc.tsx +0 -0
  162. package/src/streamplace-store/block.tsx +29 -0
  163. package/src/streamplace-store/index.tsx +3 -0
  164. package/src/streamplace-store/stream.tsx +262 -0
  165. package/src/streamplace-store/streamplace-store.tsx +89 -0
  166. package/src/streamplace-store/user.tsx +57 -0
  167. package/src/streamplace-store/xrpc.tsx +15 -0
  168. package/tsconfig.json +9 -0
  169. package/tsconfig.tsbuildinfo +1 -0
@@ -0,0 +1,106 @@
1
+ import { useEffect, useState } from "react";
2
+ export function useWebRTCDiagnostics() {
3
+ const [diagnostics, setDiagnostics] = useState({
4
+ done: false,
5
+ browserSupport: false,
6
+ rtcPeerConnection: false,
7
+ rtcSessionDescription: false,
8
+ getUserMedia: false,
9
+ getDisplayMedia: false,
10
+ errors: [],
11
+ warnings: [],
12
+ });
13
+ useEffect(() => {
14
+ const errors = [];
15
+ const warnings = [];
16
+ // Check if we're in a browser environment
17
+ if (typeof window === "undefined") {
18
+ errors.push("Running in non-browser environment");
19
+ setDiagnostics({
20
+ done: false,
21
+ browserSupport: false,
22
+ rtcPeerConnection: false,
23
+ rtcSessionDescription: false,
24
+ getUserMedia: false,
25
+ getDisplayMedia: false,
26
+ errors,
27
+ warnings,
28
+ });
29
+ return;
30
+ }
31
+ // Check RTCPeerConnection support
32
+ const rtcPeerConnection = !!(window.RTCPeerConnection ||
33
+ window.webkitRTCPeerConnection ||
34
+ window.mozRTCPeerConnection);
35
+ if (!rtcPeerConnection) {
36
+ errors.push("RTCPeerConnection is not supported");
37
+ }
38
+ // Check RTCSessionDescription support
39
+ const rtcSessionDescription = !!(window.RTCSessionDescription ||
40
+ window.webkitRTCSessionDescription ||
41
+ window.mozRTCSessionDescription);
42
+ if (!rtcSessionDescription) {
43
+ errors.push("RTCSessionDescription is not supported");
44
+ }
45
+ // Check getUserMedia support
46
+ const getUserMedia = !!(navigator.mediaDevices?.getUserMedia ||
47
+ navigator.getUserMedia ||
48
+ navigator.webkitGetUserMedia ||
49
+ navigator.mozGetUserMedia);
50
+ if (!getUserMedia) {
51
+ warnings.push("getUserMedia is not supported - webcam features unavailable");
52
+ }
53
+ // Check getDisplayMedia support
54
+ const getDisplayMedia = !!navigator.mediaDevices?.getDisplayMedia;
55
+ if (!getDisplayMedia) {
56
+ warnings.push("getDisplayMedia is not supported - screen sharing unavailable");
57
+ }
58
+ // Check if running over HTTPS (required for some WebRTC features)
59
+ if (location.protocol !== "https:" &&
60
+ location.hostname !== "localhost" &&
61
+ location.hostname !== "127.0.0.1") {
62
+ warnings.push("WebRTC features may be limited over HTTP connections");
63
+ }
64
+ // Check browser-specific issues
65
+ const userAgent = navigator.userAgent.toLowerCase();
66
+ if (userAgent.includes("safari") && !userAgent.includes("chrome")) {
67
+ warnings.push("Safari may have limited WebRTC codec support");
68
+ }
69
+ const browserSupport = rtcPeerConnection && rtcSessionDescription;
70
+ setDiagnostics({
71
+ done: true,
72
+ browserSupport,
73
+ rtcPeerConnection,
74
+ rtcSessionDescription,
75
+ getUserMedia,
76
+ getDisplayMedia,
77
+ errors,
78
+ warnings,
79
+ });
80
+ }, []);
81
+ return diagnostics;
82
+ }
83
+ export function logWebRTCDiagnostics() {
84
+ console.group("WebRTC Diagnostics");
85
+ // Log browser support
86
+ console.log("RTCPeerConnection:", !!window.RTCPeerConnection);
87
+ console.log("RTCSessionDescription:", !!window.RTCSessionDescription);
88
+ console.log("getUserMedia:", !!navigator.mediaDevices?.getUserMedia);
89
+ console.log("getDisplayMedia:", !!navigator.mediaDevices?.getDisplayMedia);
90
+ // Log browser info
91
+ console.log("User Agent:", navigator.userAgent);
92
+ console.log("Protocol:", location.protocol);
93
+ console.log("Host:", location.hostname);
94
+ // Test basic WebRTC functionality
95
+ if (window.RTCPeerConnection) {
96
+ try {
97
+ const pc = new RTCPeerConnection();
98
+ console.log("RTCPeerConnection creation: ✓ Success");
99
+ pc.close();
100
+ }
101
+ catch (error) {
102
+ console.error("RTCPeerConnection creation: ✗ Failed", error);
103
+ }
104
+ }
105
+ console.groupEnd();
106
+ }
@@ -0,0 +1,25 @@
1
+ // Browser compatibility checks for WebRTC
2
+ const checkWebRTCSupport = () => {
3
+ if (typeof window === "undefined") {
4
+ throw new Error("WebRTC is not available in non-browser environments");
5
+ }
6
+ if (!window.RTCPeerConnection) {
7
+ throw new Error("RTCPeerConnection is not supported in this browser. Please use a modern browser that supports WebRTC.");
8
+ }
9
+ if (!window.RTCSessionDescription) {
10
+ throw new Error("RTCSessionDescription is not supported in this browser. Please use a modern browser that supports WebRTC.");
11
+ }
12
+ };
13
+ // Check support immediately
14
+ try {
15
+ checkWebRTCSupport();
16
+ }
17
+ catch (error) {
18
+ console.error("WebRTC Compatibility Error:", error.message);
19
+ }
20
+ export const RTCPeerConnection = window.RTCPeerConnection;
21
+ export const RTCSessionDescription = window.RTCSessionDescription;
22
+ export const WebRTCMediaStream = window.MediaStream;
23
+ export const mediaDevices = navigator.mediaDevices;
24
+ // Export the compatibility checker for use in other components
25
+ export { checkWebRTCSupport };
@@ -0,0 +1 @@
1
+ export { RTCPeerConnection, RTCSessionDescription, MediaStream as WebRTCMediaStream, mediaDevices, } from "react-native-webrtc";
@@ -0,0 +1,220 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { cva } from "class-variance-authority";
3
+ import React, { forwardRef, useMemo } from "react";
4
+ import { ActivityIndicator, StyleSheet } from "react-native";
5
+ import { useTheme } from "../../lib/theme/theme";
6
+ import * as tokens from "../../lib/theme/tokens";
7
+ import { ButtonPrimitive } from "./primitives/button";
8
+ import { TextPrimitive } from "./primitives/text";
9
+ // Button variants using class-variance-authority pattern
10
+ const buttonVariants = cva("", {
11
+ variants: {
12
+ variant: {
13
+ primary: "primary",
14
+ secondary: "secondary",
15
+ outline: "outline",
16
+ ghost: "ghost",
17
+ destructive: "destructive",
18
+ success: "success",
19
+ },
20
+ size: {
21
+ sm: "sm",
22
+ md: "md",
23
+ lg: "lg",
24
+ xl: "xl",
25
+ pill: "pill",
26
+ },
27
+ },
28
+ defaultVariants: {
29
+ variant: "primary",
30
+ size: "md",
31
+ },
32
+ });
33
+ export const Button = forwardRef(({ variant = "primary", size = "md", children, leftIcon, rightIcon, loading = false, loadingText, disabled, style, ...props }, ref) => {
34
+ const { theme } = useTheme();
35
+ // Create dynamic styles based on theme
36
+ const styles = useMemo(() => createStyles(theme), [theme]);
37
+ // Get variant styles
38
+ const buttonStyle = useMemo(() => {
39
+ const variantStyle = styles[`${variant}Button`];
40
+ const sizeStyle = styles[`${size}Button`];
41
+ return [variantStyle, sizeStyle];
42
+ }, [variant, size, styles]);
43
+ // Get inner styles for button content
44
+ const buttonInnerStyle = useMemo(() => {
45
+ const sizeInnerStyle = styles[`${size}ButtonInner`];
46
+ return sizeInnerStyle;
47
+ }, [size, styles]);
48
+ const textStyle = React.useMemo(() => {
49
+ const variantTextStyle = styles[`${variant}Text`];
50
+ const sizeTextStyle = styles[`${size}Text`];
51
+ return [variantTextStyle, sizeTextStyle];
52
+ }, [variant, size, styles]);
53
+ const iconSize = React.useMemo(() => {
54
+ switch (size) {
55
+ case "sm":
56
+ return 16;
57
+ case "lg":
58
+ return 20;
59
+ case "xl":
60
+ return 24;
61
+ case "md":
62
+ default:
63
+ return 18;
64
+ }
65
+ }, [size]);
66
+ const spinnerSize = useMemo(() => {
67
+ switch (size) {
68
+ case "sm":
69
+ return "small";
70
+ case "lg":
71
+ case "xl":
72
+ return "large";
73
+ case "md":
74
+ default:
75
+ return "small";
76
+ }
77
+ }, [size]);
78
+ const spinnerColor = useMemo(() => {
79
+ switch (variant) {
80
+ case "outline":
81
+ case "ghost":
82
+ return theme.colors.primary;
83
+ case "secondary":
84
+ return theme.colors.secondaryForeground;
85
+ case "destructive":
86
+ return theme.colors.destructiveForeground;
87
+ default:
88
+ return theme.colors.primaryForeground;
89
+ }
90
+ }, [variant, theme.colors]);
91
+ return (_jsx(ButtonPrimitive.Root, { ref: ref, disabled: disabled || loading, style: [buttonStyle, style], ...props, children: _jsxs(ButtonPrimitive.Content, { style: buttonInnerStyle, children: [loading && !leftIcon ? (_jsx(ButtonPrimitive.Icon, { position: "left", children: _jsx(ActivityIndicator, { size: spinnerSize, color: spinnerColor }) })) : leftIcon ? (_jsx(ButtonPrimitive.Icon, { position: "left", style: { width: iconSize, height: iconSize }, children: leftIcon })) : null, _jsx(TextPrimitive.Root, { style: textStyle, children: loading && loadingText ? loadingText : children }), loading && rightIcon ? (_jsx(ButtonPrimitive.Icon, { position: "right", children: _jsx(ActivityIndicator, { size: spinnerSize, color: spinnerColor }) })) : rightIcon ? (_jsx(ButtonPrimitive.Icon, { position: "right", style: { width: iconSize, height: iconSize }, children: rightIcon })) : null] }) }));
92
+ });
93
+ Button.displayName = "Button";
94
+ // Create theme-based styles
95
+ function createStyles(theme) {
96
+ return StyleSheet.create({
97
+ // Variant styles
98
+ primaryButton: {
99
+ backgroundColor: theme.colors.primary,
100
+ borderWidth: 0,
101
+ ...theme.shadows.sm,
102
+ },
103
+ primaryText: {
104
+ color: theme.colors.primaryForeground,
105
+ fontWeight: "600",
106
+ },
107
+ secondaryButton: {
108
+ backgroundColor: theme.colors.secondary,
109
+ borderWidth: 0,
110
+ },
111
+ secondaryText: {
112
+ color: theme.colors.secondaryForeground,
113
+ fontWeight: "500",
114
+ },
115
+ outlineButton: {
116
+ backgroundColor: "transparent",
117
+ borderWidth: 1,
118
+ borderColor: theme.colors.border,
119
+ },
120
+ outlineText: {
121
+ color: theme.colors.foreground,
122
+ fontWeight: "500",
123
+ },
124
+ ghostButton: {
125
+ backgroundColor: "transparent",
126
+ borderWidth: 0,
127
+ },
128
+ ghostText: {
129
+ color: theme.colors.foreground,
130
+ fontWeight: "500",
131
+ },
132
+ destructiveButton: {
133
+ backgroundColor: theme.colors.destructive,
134
+ borderWidth: 0,
135
+ ...theme.shadows.sm,
136
+ },
137
+ destructiveText: {
138
+ color: theme.colors.destructiveForeground,
139
+ fontWeight: "600",
140
+ },
141
+ successButton: {
142
+ backgroundColor: theme.colors.success,
143
+ borderWidth: 0,
144
+ ...theme.shadows.sm,
145
+ },
146
+ successText: {
147
+ color: theme.colors.successForeground,
148
+ fontWeight: "600",
149
+ },
150
+ pillButton: {
151
+ paddingHorizontal: theme.spacing[3],
152
+ paddingVertical: theme.spacing[2],
153
+ borderRadius: tokens.borderRadius.full,
154
+ minHeight: tokens.touchTargets.minimum / 2,
155
+ },
156
+ pillText: {
157
+ color: theme.colors.primaryForeground,
158
+ fontWeight: "400",
159
+ },
160
+ // Size styles
161
+ smButton: {
162
+ paddingHorizontal: theme.spacing[3],
163
+ paddingVertical: theme.spacing[2],
164
+ borderRadius: tokens.borderRadius.md,
165
+ minHeight: tokens.touchTargets.minimum,
166
+ gap: theme.spacing[1],
167
+ },
168
+ smButtonInner: {
169
+ gap: theme.spacing[1],
170
+ },
171
+ smText: {
172
+ fontSize: 14,
173
+ lineHeight: 16,
174
+ },
175
+ mdButton: {
176
+ paddingHorizontal: theme.spacing[4],
177
+ paddingVertical: theme.spacing[3],
178
+ borderRadius: tokens.borderRadius.md,
179
+ minHeight: tokens.touchTargets.minimum,
180
+ gap: theme.spacing[2],
181
+ },
182
+ mdButtonInner: {
183
+ gap: theme.spacing[2],
184
+ },
185
+ mdText: {
186
+ fontSize: 16,
187
+ lineHeight: 18,
188
+ },
189
+ lgButton: {
190
+ paddingHorizontal: theme.spacing[6],
191
+ paddingVertical: theme.spacing[4],
192
+ borderRadius: tokens.borderRadius.md,
193
+ minHeight: tokens.touchTargets.comfortable,
194
+ gap: theme.spacing[3],
195
+ },
196
+ lgButtonInner: {
197
+ gap: theme.spacing[3],
198
+ },
199
+ lgText: {
200
+ fontSize: 18,
201
+ lineHeight: 20,
202
+ },
203
+ xlButton: {
204
+ paddingHorizontal: theme.spacing[8],
205
+ paddingVertical: theme.spacing[5],
206
+ borderRadius: tokens.borderRadius.lg,
207
+ minHeight: tokens.touchTargets.large,
208
+ gap: theme.spacing[4],
209
+ },
210
+ xlButtonInner: {
211
+ gap: theme.spacing[4],
212
+ },
213
+ xlText: {
214
+ fontSize: 20,
215
+ lineHeight: 24,
216
+ },
217
+ });
218
+ }
219
+ // Export button variants for external use
220
+ export { buttonVariants };
@@ -0,0 +1,203 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { cva } from "class-variance-authority";
3
+ import { X } from "lucide-react-native";
4
+ import React, { forwardRef } from "react";
5
+ import { Platform, StyleSheet, Text } from "react-native";
6
+ import { useTheme } from "../../lib/theme/theme";
7
+ import { createThemedIcon } from "./icons";
8
+ import { ModalPrimitive } from "./primitives/modal";
9
+ const ThemedX = createThemedIcon(X);
10
+ // Dialog variants using class-variance-authority pattern
11
+ const dialogVariants = cva("", {
12
+ variants: {
13
+ variant: {
14
+ default: "default",
15
+ sheet: "sheet",
16
+ fullscreen: "fullscreen",
17
+ },
18
+ size: {
19
+ sm: "sm",
20
+ md: "md",
21
+ lg: "lg",
22
+ xl: "xl",
23
+ full: "full",
24
+ },
25
+ position: {
26
+ center: "center",
27
+ top: "top",
28
+ bottom: "bottom",
29
+ left: "left",
30
+ right: "right",
31
+ },
32
+ },
33
+ defaultVariants: {
34
+ variant: "default",
35
+ size: "md",
36
+ position: "center",
37
+ },
38
+ });
39
+ export const Dialog = forwardRef(({ variant = "left", size = "md", position = "center", children, title, description, dismissible = true, showCloseButton = true, onClose, open = false, onOpenChange, ...props }, ref) => {
40
+ const { theme } = useTheme();
41
+ // Create dynamic styles based on theme
42
+ const styles = React.useMemo(() => createStyles(theme), [theme]);
43
+ const handleClose = React.useCallback(() => {
44
+ if (onClose) {
45
+ onClose();
46
+ }
47
+ if (onOpenChange) {
48
+ onOpenChange(false);
49
+ }
50
+ }, [onClose, onOpenChange]);
51
+ const presentationStyle = React.useMemo(() => {
52
+ if (variant === "sheet" && Platform.OS === "ios") {
53
+ return "pageSheet";
54
+ }
55
+ if (variant === "fullscreen") {
56
+ return "fullScreen";
57
+ }
58
+ return Platform.OS === "ios"
59
+ ? "pageSheet"
60
+ : "fullScreen";
61
+ }, [variant]);
62
+ const animationType = React.useMemo(() => {
63
+ if (variant === "sheet") {
64
+ return "slide";
65
+ }
66
+ return "fade";
67
+ }, [variant]);
68
+ return (_jsx(ModalPrimitive.Root, { ref: ref, open: open, onOpenChange: onOpenChange, presentationStyle: presentationStyle, animationType: animationType, ...props, children: _jsx(ModalPrimitive.Overlay, { dismissible: dismissible, onDismiss: handleClose, style: styles.overlay, children: _jsxs(ModalPrimitive.Content, { position: position || "left", size: size || "md", style: [
69
+ styles.content,
70
+ styles[`${variant}Content`],
71
+ styles[`${size}Content`],
72
+ ], children: [(title || showCloseButton) && (_jsxs(ModalPrimitive.Header, { withBorder: variant !== "sheet", style: styles.header, children: [_jsx(DialogTitle, { children: title }), showCloseButton && (_jsx(ModalPrimitive.Close, { onClose: handleClose, style: styles.closeButton, children: _jsx(DialogCloseIcon, {}) }))] })), _jsxs(ModalPrimitive.Body, { scrollable: variant !== "fullscreen", style: styles.body, children: [description && (_jsx(DialogDescription, { children: description })), children] })] }) }) }));
73
+ });
74
+ Dialog.displayName = "Dialog";
75
+ export const DialogTitle = forwardRef(({ children, style, ...props }, ref) => {
76
+ const { theme } = useTheme();
77
+ const styles = React.useMemo(() => createStyles(theme), [theme]);
78
+ if (!children)
79
+ return null;
80
+ return (_jsx(Text, { ref: ref, style: [styles.title, style], ...props, children: children }));
81
+ });
82
+ DialogTitle.displayName = "DialogTitle";
83
+ export const DialogDescription = forwardRef(({ children, style, ...props }, ref) => {
84
+ const { theme } = useTheme();
85
+ const styles = React.useMemo(() => createStyles(theme), [theme]);
86
+ if (!children)
87
+ return null;
88
+ return (_jsx(Text, { ref: ref, style: [styles.description, style], ...props, children: children }));
89
+ });
90
+ DialogDescription.displayName = "DialogDescription";
91
+ export const DialogFooter = forwardRef(({ children, direction = "row", justify = "flex-end", withBorder = true, style, ...props }, ref) => {
92
+ const { theme } = useTheme();
93
+ const styles = React.useMemo(() => createStyles(theme), [theme]);
94
+ if (!children)
95
+ return null;
96
+ return (_jsx(ModalPrimitive.Footer, { ref: ref, withBorder: withBorder, direction: direction, justify: justify, style: [styles.footer, style], ...props, children: children }));
97
+ });
98
+ DialogFooter.displayName = "DialogFooter";
99
+ // Dialog Close Icon component (Lucide X)
100
+ const DialogCloseIcon = () => {
101
+ return _jsx(ThemedX, { size: "md", variant: "muted" });
102
+ };
103
+ // Create theme-aware styles
104
+ function createStyles(theme) {
105
+ return StyleSheet.create({
106
+ overlay: {
107
+ backgroundColor: "rgba(0, 0, 0, 0.5)",
108
+ },
109
+ content: {
110
+ backgroundColor: theme.colors.card,
111
+ borderRadius: theme.borderRadius.lg,
112
+ ...theme.shadows.lg,
113
+ maxHeight: "90%",
114
+ maxWidth: "90%",
115
+ },
116
+ // Variant styles
117
+ defaultContent: {
118
+ // Default styles already applied in content
119
+ },
120
+ sheetContent: {
121
+ borderTopLeftRadius: theme.borderRadius.xl,
122
+ borderTopRightRadius: theme.borderRadius.xl,
123
+ borderBottomLeftRadius: 0,
124
+ borderBottomRightRadius: 0,
125
+ marginTop: "auto",
126
+ marginBottom: 0,
127
+ maxHeight: "80%",
128
+ width: "100%",
129
+ maxWidth: "100%",
130
+ },
131
+ fullscreenContent: {
132
+ width: "100%",
133
+ height: "100%",
134
+ maxWidth: "100%",
135
+ maxHeight: "100%",
136
+ borderRadius: 0,
137
+ margin: 0,
138
+ },
139
+ // Size styles
140
+ smContent: {
141
+ minWidth: 300,
142
+ minHeight: 200,
143
+ },
144
+ mdContent: {
145
+ minWidth: 400,
146
+ minHeight: 300,
147
+ },
148
+ lgContent: {
149
+ minWidth: 500,
150
+ minHeight: 400,
151
+ },
152
+ xlContent: {
153
+ minWidth: 600,
154
+ minHeight: 500,
155
+ },
156
+ fullContent: {
157
+ width: "95%",
158
+ height: "95%",
159
+ maxWidth: "95%",
160
+ maxHeight: "95%",
161
+ },
162
+ header: {
163
+ paddingHorizontal: theme.spacing[6],
164
+ paddingVertical: theme.spacing[4],
165
+ flexDirection: "row",
166
+ alignItems: "center",
167
+ justifyContent: "space-between",
168
+ },
169
+ body: {
170
+ paddingHorizontal: theme.spacing[6],
171
+ paddingBottom: theme.spacing[6],
172
+ flex: 1,
173
+ },
174
+ footer: {
175
+ paddingHorizontal: theme.spacing[6],
176
+ paddingVertical: theme.spacing[4],
177
+ gap: theme.spacing[2],
178
+ },
179
+ title: {
180
+ fontSize: 20,
181
+ fontWeight: "600",
182
+ color: theme.colors.text,
183
+ flex: 1,
184
+ lineHeight: 24,
185
+ },
186
+ description: {
187
+ fontSize: 16,
188
+ color: theme.colors.textMuted,
189
+ lineHeight: 22,
190
+ marginBottom: theme.spacing[4],
191
+ },
192
+ closeButton: {
193
+ width: theme.touchTargets.minimum,
194
+ height: theme.touchTargets.minimum,
195
+ alignItems: "center",
196
+ justifyContent: "center",
197
+ borderRadius: theme.borderRadius.sm,
198
+ marginLeft: theme.spacing[2],
199
+ },
200
+ });
201
+ }
202
+ // Export dialog variants for external use
203
+ export { dialogVariants };