@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,101 @@
1
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
+ import { ChevronUp } from "lucide-react-native";
3
+ import { Dimensions } from "react-native";
4
+ import { Gesture, GestureDetector, Pressable, } from "react-native-gesture-handler";
5
+ import Animated, { Extrapolation, interpolate, useAnimatedStyle, useSharedValue, withSpring, } from "react-native-reanimated";
6
+ import { useSafeAreaInsets } from "react-native-safe-area-context";
7
+ import { useKeyboardSlide } from "../../hooks";
8
+ import { bottom, layout, p, w, zIndex } from "../../lib/theme/atoms";
9
+ import { View } from "./view";
10
+ const AnimatedView = Animated.createAnimatedComponent(View);
11
+ const { height: SCREEN_HEIGHT } = Dimensions.get("window");
12
+ const SPRING_CONFIG = { damping: 20, stiffness: 100 };
13
+ export function Resizable({ isPlayerRatioGreater, style = {}, children, }) {
14
+ const { slideKeyboard } = useKeyboardSlide();
15
+ const { bottom: safeBottom } = useSafeAreaInsets();
16
+ const MAX_HEIGHT = (SCREEN_HEIGHT - safeBottom) * 0.5;
17
+ const MIN_HEIGHT = -(SCREEN_HEIGHT - safeBottom) * 0.2;
18
+ const COLLAPSE_HEIGHT = (SCREEN_HEIGHT - safeBottom) * 0.1;
19
+ const sheetHeight = useSharedValue(MIN_HEIGHT);
20
+ const startHeight = useSharedValue(MIN_HEIGHT);
21
+ const panGesture = Gesture.Pan()
22
+ .onStart(() => {
23
+ startHeight.value = sheetHeight.value;
24
+ })
25
+ .onUpdate((event) => {
26
+ let newHeight = startHeight.value - event.translationY;
27
+ if (newHeight > MAX_HEIGHT)
28
+ newHeight = MAX_HEIGHT;
29
+ if (newHeight < MIN_HEIGHT)
30
+ newHeight = MIN_HEIGHT;
31
+ sheetHeight.value = newHeight;
32
+ if (newHeight < COLLAPSE_HEIGHT) {
33
+ sheetHeight.value = withSpring(MIN_HEIGHT, SPRING_CONFIG);
34
+ }
35
+ });
36
+ const animatedStyle = useAnimatedStyle(() => ({
37
+ height: sheetHeight.value < COLLAPSE_HEIGHT ? 0 : sheetHeight.value,
38
+ opacity: interpolate(sheetHeight.value, [MIN_HEIGHT, COLLAPSE_HEIGHT], [0, 1], Extrapolation.CLAMP),
39
+ transform: [
40
+ {
41
+ translateY: slideKeyboard - safeBottom + Math.max(0, -sheetHeight.value),
42
+ },
43
+ ],
44
+ }));
45
+ const handleAnimatedStyle = useAnimatedStyle(() => ({
46
+ opacity: sheetHeight.value < COLLAPSE_HEIGHT ? 1 : 0,
47
+ transform: [
48
+ {
49
+ translateY: sheetHeight.value < COLLAPSE_HEIGHT ? 0 : withSpring(20),
50
+ },
51
+ ],
52
+ }));
53
+ return (_jsxs(_Fragment, { children: [_jsx(Animated.View, { style: [
54
+ handleAnimatedStyle,
55
+ layout.position.absolute,
56
+ bottom[4],
57
+ w.percent[100],
58
+ layout.flex.center,
59
+ zIndex[1],
60
+ { marginBottom: safeBottom },
61
+ ], children: _jsx(Pressable, { onPress: () => {
62
+ sheetHeight.value =
63
+ sheetHeight.value === MIN_HEIGHT
64
+ ? withSpring(MAX_HEIGHT, SPRING_CONFIG)
65
+ : withSpring(MIN_HEIGHT, SPRING_CONFIG);
66
+ }, children: _jsx(View, { style: [
67
+ p[1],
68
+ {
69
+ borderRadius: 999,
70
+ backgroundColor: "rgba(0, 0, 0, 0.5)",
71
+ overflow: "hidden",
72
+ },
73
+ ], children: _jsx(ChevronUp, { size: 32, color: "white", style: { marginBottom: 1, marginTop: -1 } }) }) }) }), _jsxs(AnimatedView, { style: [
74
+ animatedStyle,
75
+ isPlayerRatioGreater
76
+ ? layout.position.relative
77
+ : layout.position.absolute,
78
+ bottom[0],
79
+ zIndex[1],
80
+ w.percent[100],
81
+ {
82
+ backgroundColor: "rgba(0, 0, 0, 0.5)",
83
+ overflow: "visible",
84
+ borderTopLeftRadius: 16,
85
+ borderTopRightRadius: 16,
86
+ minWidth: "100%",
87
+ },
88
+ style,
89
+ ], children: [_jsx(View, { style: [layout.flex.row, layout.flex.justifyCenter], children: _jsx(GestureDetector, { gesture: panGesture, children: _jsx(View, { hitSlop: { top: 20, bottom: 20, left: 20, right: 20 }, style: [
90
+ w[32],
91
+ {
92
+ height: 6,
93
+ transform: [{ translateY: -10 }],
94
+ backgroundColor: "#eeeeee66",
95
+ alignItems: "center",
96
+ justifyContent: "center",
97
+ borderRadius: 999,
98
+ },
99
+ ] }) }) }), children] })] }));
100
+ }
101
+ Resizable.displayName = "ResizableChatSheet";
@@ -0,0 +1,175 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { cva } from "class-variance-authority";
3
+ import React, { forwardRef } from "react";
4
+ import { StyleSheet } from "react-native";
5
+ import { colors, borderRadius as radius, spacing } from "../../lib/theme/atoms";
6
+ import { TextPrimitive } from "./primitives/text";
7
+ // Text variants using class-variance-authority pattern
8
+ const textVariants = cva("", {
9
+ variants: {
10
+ variant: {
11
+ h1: "h1",
12
+ h2: "h2",
13
+ h3: "h3",
14
+ h4: "h4",
15
+ h5: "h5",
16
+ h6: "h6",
17
+ subtitle1: "subtitle1",
18
+ subtitle2: "subtitle2",
19
+ body1: "body1",
20
+ body2: "body2",
21
+ caption: "caption",
22
+ overline: "overline",
23
+ },
24
+ size: {
25
+ xs: "xs",
26
+ sm: "sm",
27
+ base: "base",
28
+ lg: "lg",
29
+ xl: "xl",
30
+ "2xl": "2xl",
31
+ "3xl": "3xl",
32
+ "4xl": "4xl",
33
+ },
34
+ weight: {
35
+ thin: "thin",
36
+ light: "light",
37
+ normal: "normal",
38
+ medium: "medium",
39
+ semibold: "semibold",
40
+ bold: "bold",
41
+ extrabold: "extrabold",
42
+ black: "black",
43
+ },
44
+ color: {
45
+ default: "default",
46
+ muted: "muted",
47
+ primary: "primary",
48
+ secondary: "secondary",
49
+ destructive: "destructive",
50
+ success: "success",
51
+ warning: "warning",
52
+ },
53
+ },
54
+ defaultVariants: {
55
+ variant: "body1",
56
+ size: "base",
57
+ weight: "normal",
58
+ color: "default",
59
+ },
60
+ });
61
+ export const Text = forwardRef(({ variant = undefined, size = undefined, weight = undefined, color = undefined, muted = false, bold = false, italic = false, underline = false, strikethrough = false, uppercase = false, lowercase = false, capitalize = false, center = false, right = false, justify = false, customColor, style, children, ...props }, ref) => {
62
+ // Create dynamic styles based on atoms
63
+ const styles = React.useMemo(() => createStyles(), []);
64
+ // Override props based on convenience props
65
+ const finalColor = customColor ? customColor : muted ? "muted" : color;
66
+ const finalTransform = uppercase
67
+ ? "uppercase"
68
+ : lowercase
69
+ ? "lowercase"
70
+ : capitalize
71
+ ? "capitalize"
72
+ : "none";
73
+ const finalDecoration = underline && strikethrough
74
+ ? "underline line-through"
75
+ : underline
76
+ ? "underline"
77
+ : strikethrough
78
+ ? "line-through"
79
+ : "none";
80
+ const finalAlign = center
81
+ ? "center"
82
+ : right
83
+ ? "right"
84
+ : justify
85
+ ? "justify"
86
+ : "left";
87
+ // Get variant-specific styles
88
+ const variantStyle = styles[`${variant}Style`] || {};
89
+ const styleArr = (Array.isArray(style) ? style : [style || undefined]).filter((s) => s !== undefined);
90
+ return (_jsx(TextPrimitive.Root, { ref: ref, variant: variant || "body1", size: size || "base", color: finalColor || "default", align: finalAlign, transform: finalTransform, decoration: finalDecoration, italic: italic, style: [variantStyle, ...styleArr], ...props, children: children }));
91
+ });
92
+ Text.displayName = "Text";
93
+ // Convenience components for common text elements
94
+ export const Heading = forwardRef(({ level = 1, ...props }, ref) => (_jsx(Text, { ref: ref, variant: `h${level}`, ...props })));
95
+ Heading.displayName = "Heading";
96
+ export const Subtitle = forwardRef(({ level = 1, ...props }, ref) => (_jsx(Text, { ref: ref, variant: level === 1 ? "subtitle1" : "subtitle2", ...props })));
97
+ Subtitle.displayName = "Subtitle";
98
+ export const Body = forwardRef(({ level = 1, ...props }, ref) => (_jsx(Text, { ref: ref, variant: level === 1 ? "body1" : "body2", ...props })));
99
+ Body.displayName = "Body";
100
+ export const Caption = forwardRef((props, ref) => _jsx(Text, { ref: ref, variant: "caption", ...props }));
101
+ Caption.displayName = "Caption";
102
+ export const Label = forwardRef((props, ref) => (_jsx(Text, { ref: ref, variant: "subtitle1", weight: "medium", ...props })));
103
+ Label.displayName = "Label";
104
+ export const Code = forwardRef(({ style, ...props }, ref) => {
105
+ const styles = React.useMemo(() => createStyles(), []);
106
+ // if style is not an array, convert it to an array
107
+ const styleArr = (Array.isArray(style) ? style : [style || undefined]).filter((s) => s !== undefined);
108
+ return _jsx(Text, { ref: ref, style: [styles.codeStyle, ...styleArr], ...props });
109
+ });
110
+ Code.displayName = "Code";
111
+ // Span component for inline text styling (inherits from parent)
112
+ export const Span = forwardRef(({ children, ...props }, ref) => (_jsx(TextPrimitive.Span, { ref: ref, ...props, children: children })));
113
+ Span.displayName = "Span";
114
+ // Create atom-based styles
115
+ function createStyles() {
116
+ return StyleSheet.create({
117
+ // Variant-specific styles
118
+ h1Style: {
119
+ marginBottom: spacing[4],
120
+ },
121
+ h2Style: {
122
+ marginBottom: spacing[3],
123
+ },
124
+ h3Style: {
125
+ marginBottom: spacing[3],
126
+ },
127
+ h4Style: {
128
+ marginBottom: spacing[2],
129
+ },
130
+ h5Style: {
131
+ marginBottom: spacing[2],
132
+ },
133
+ h6Style: {
134
+ marginBottom: spacing[2],
135
+ },
136
+ subtitle1Style: {
137
+ marginBottom: spacing[2],
138
+ },
139
+ subtitle2Style: {
140
+ marginBottom: spacing[1],
141
+ },
142
+ body1Style: {
143
+ marginBottom: spacing[3],
144
+ },
145
+ body2Style: {
146
+ marginBottom: spacing[2],
147
+ },
148
+ captionStyle: {
149
+ marginBottom: spacing[1],
150
+ },
151
+ overlineStyle: {
152
+ marginBottom: spacing[1],
153
+ textTransform: "uppercase",
154
+ letterSpacing: 1,
155
+ },
156
+ labelStyle: {
157
+ marginBottom: spacing[1],
158
+ },
159
+ buttonStyle: {
160
+ textAlign: "center",
161
+ },
162
+ codeStyle: {
163
+ fontFamily: "monospace",
164
+ backgroundColor: colors["muted"],
165
+ paddingHorizontal: spacing[1],
166
+ paddingVertical: 2,
167
+ borderRadius: radius.sm,
168
+ fontSize: 14,
169
+ },
170
+ });
171
+ }
172
+ // Export text variants for external use
173
+ export { textVariants };
174
+ // Re-export primitive components for advanced usage
175
+ export { TextPrimitive };
@@ -0,0 +1,17 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { TextInput } from "react-native";
3
+ import { bg, borders, flex, p, text } from "../../lib/theme/atoms";
4
+ function Textarea({ style, multiline = true, numberOfLines = 4, ...props }) {
5
+ return (_jsx(TextInput, { style: [
6
+ flex.values[1],
7
+ borders.width.thin,
8
+ borders.color.gray[400],
9
+ bg.gray[900],
10
+ p[3],
11
+ text.gray[200],
12
+ props.editable === false && { opacity: 0.5 },
13
+ { borderRadius: 10 },
14
+ style,
15
+ ], multiline: multiline, numberOfLines: numberOfLines, textAlignVertical: "top", ...props }));
16
+ }
17
+ export { Textarea };
@@ -0,0 +1,129 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { Portal } from "@rn-primitives/portal";
3
+ import { useEffect, useState } from "react";
4
+ import { Animated, Platform, Pressable, StyleSheet, Text, useWindowDimensions, View, } from "react-native";
5
+ import { useSafeAreaInsets } from "react-native-safe-area-context";
6
+ import { useTheme } from "../../lib/theme/theme";
7
+ export function Toast({ open, onOpenChange, title, description, actionLabel = "Action", onAction, duration = 3, }) {
8
+ const [seconds, setSeconds] = useState(duration);
9
+ const insets = useSafeAreaInsets();
10
+ const { theme } = useTheme();
11
+ const [fadeAnim] = useState(new Animated.Value(0));
12
+ const { width } = useWindowDimensions();
13
+ const isWeb = Platform.OS === "web";
14
+ const isDesktop = isWeb && width >= 768;
15
+ const containerPosition = isDesktop
16
+ ? {
17
+ top: undefined,
18
+ bottom: theme.spacing[4],
19
+ right: theme.spacing[4], // <-- use spacing, not 1
20
+ alignItems: "flex-end",
21
+ minWidth: 400,
22
+ width: 400,
23
+ // Do NOT set left at all
24
+ }
25
+ : {
26
+ bottom: insets.bottom + theme.spacing[1],
27
+ left: 0,
28
+ right: 0,
29
+ alignItems: "center",
30
+ width: "100%",
31
+ maxWidth: undefined,
32
+ };
33
+ useEffect(() => {
34
+ let interval = null;
35
+ if (open) {
36
+ setSeconds(duration);
37
+ Animated.timing(fadeAnim, {
38
+ toValue: 1,
39
+ duration: 200,
40
+ useNativeDriver: true,
41
+ }).start();
42
+ interval = setInterval(() => {
43
+ setSeconds((prev) => {
44
+ if (prev <= 1) {
45
+ onOpenChange(false);
46
+ if (interval)
47
+ clearInterval(interval);
48
+ return duration;
49
+ }
50
+ return prev - 1;
51
+ });
52
+ }, 1000);
53
+ }
54
+ else {
55
+ if (interval)
56
+ clearInterval(interval);
57
+ Animated.timing(fadeAnim, {
58
+ toValue: 0,
59
+ duration: 150,
60
+ useNativeDriver: true,
61
+ }).start();
62
+ setSeconds(duration);
63
+ }
64
+ return () => {
65
+ if (interval)
66
+ clearInterval(interval);
67
+ };
68
+ // eslint-disable-next-line
69
+ }, [open, duration]);
70
+ if (!open)
71
+ return null;
72
+ return (_jsx(Portal, { name: "toast", children: _jsx(Animated.View, { style: [styles.container, containerPosition, { opacity: fadeAnim }], pointerEvents: "box-none", children: _jsxs(View, { style: [
73
+ styles.toast,
74
+ {
75
+ backgroundColor: theme.colors.secondary,
76
+ borderColor: theme.colors.border,
77
+ borderRadius: theme.borderRadius.xl,
78
+ flexDirection: "column",
79
+ justifyContent: "space-between",
80
+ alignItems: "center",
81
+ padding: theme.spacing[4],
82
+ width: isDesktop ? "100%" : "95%",
83
+ },
84
+ ], children: [_jsxs(View, { style: { gap: theme.spacing[1], width: "100%" }, children: [_jsx(Text, { style: [
85
+ {
86
+ color: theme.colors.foreground,
87
+ fontSize: 16,
88
+ fontWeight: "500",
89
+ },
90
+ ], children: title }), description ? (_jsx(Text, { style: [{ color: theme.colors.foreground, fontSize: 14 }], children: description })) : null] }), _jsxs(View, { style: {
91
+ gap: theme.spacing[1],
92
+ flexDirection: "row",
93
+ justifyContent: "flex-end",
94
+ width: "100%",
95
+ }, children: [onAction && (_jsx(Pressable, { style: [
96
+ styles.button,
97
+ {
98
+ borderColor: theme.colors.primary,
99
+ paddingHorizontal: theme.spacing[4],
100
+ paddingVertical: theme.spacing[2],
101
+ },
102
+ ], onPress: onAction, children: _jsx(Text, { style: { color: theme.colors.foreground }, children: actionLabel }) })), _jsx(Pressable, { style: [
103
+ styles.button,
104
+ {
105
+ borderColor: theme.colors.primary,
106
+ paddingHorizontal: theme.spacing[4],
107
+ paddingVertical: theme.spacing[2],
108
+ },
109
+ ], onPress: () => onOpenChange(false), children: _jsx(Text, { style: { color: theme.colors.foreground }, children: "Close" }) })] })] }) }) }));
110
+ }
111
+ const styles = StyleSheet.create({
112
+ container: {
113
+ position: "absolute",
114
+ zIndex: 1000,
115
+ paddingHorizontal: 16,
116
+ },
117
+ toast: {
118
+ opacity: 0.95,
119
+ borderWidth: 1,
120
+ gap: 8,
121
+ },
122
+ button: {
123
+ borderWidth: 1,
124
+ borderRadius: 8,
125
+ alignItems: "center",
126
+ justifyContent: "center",
127
+ backgroundColor: "transparent",
128
+ },
129
+ });
@@ -0,0 +1,250 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { cva } from "class-variance-authority";
3
+ import { forwardRef } from "react";
4
+ import { View as RNView, } from "react-native";
5
+ import { borderRadius as radius, spacing } from "../../lib/theme/atoms";
6
+ import { useTheme } from "../../lib/theme/theme";
7
+ // View variants using class-variance-authority pattern
8
+ const viewVariants = cva("", {
9
+ variants: {
10
+ variant: {
11
+ default: "default",
12
+ card: "card",
13
+ overlay: "overlay",
14
+ surface: "surface",
15
+ container: "container",
16
+ },
17
+ padding: {
18
+ none: "none",
19
+ xs: "xs",
20
+ sm: "sm",
21
+ md: "md",
22
+ lg: "lg",
23
+ xl: "xl",
24
+ },
25
+ margin: {
26
+ none: "none",
27
+ xs: "xs",
28
+ sm: "sm",
29
+ md: "md",
30
+ lg: "lg",
31
+ xl: "xl",
32
+ },
33
+ direction: {
34
+ row: "row",
35
+ column: "column",
36
+ "row-reverse": "row-reverse",
37
+ "column-reverse": "column-reverse",
38
+ },
39
+ align: {
40
+ start: "start",
41
+ center: "center",
42
+ end: "end",
43
+ stretch: "stretch",
44
+ baseline: "baseline",
45
+ },
46
+ justify: {
47
+ start: "start",
48
+ center: "center",
49
+ end: "end",
50
+ between: "between",
51
+ around: "around",
52
+ evenly: "evenly",
53
+ },
54
+ flex: {
55
+ none: "none",
56
+ auto: "auto",
57
+ initial: "initial",
58
+ },
59
+ },
60
+ defaultVariants: {
61
+ variant: "default",
62
+ padding: "none",
63
+ margin: "none",
64
+ direction: "column",
65
+ align: "stretch",
66
+ justify: "start",
67
+ flex: "none",
68
+ },
69
+ });
70
+ export const View = forwardRef(({ variant = "default", padding = "none", margin = "none", direction = "column", align = "stretch", justify = "start", flex = "none", fullWidth = false, fullHeight = false, centered = false, backgroundColor, borderColor, borderWidth, borderRadius, shadow = false, style, ...props }, ref) => {
71
+ const { theme } = useTheme();
72
+ // Map variant to styles
73
+ const variantStyles = (() => {
74
+ switch (variant) {
75
+ case "card":
76
+ return {
77
+ backgroundColor: theme.colors.card,
78
+ borderRadius: radius.lg,
79
+ shadowColor: "#000",
80
+ shadowOffset: { width: 0, height: 2 },
81
+ shadowOpacity: 0.1,
82
+ shadowRadius: 4,
83
+ elevation: 3,
84
+ };
85
+ case "overlay":
86
+ return {
87
+ backgroundColor: "rgba(0, 0, 0, 0.5)",
88
+ };
89
+ case "surface":
90
+ return {
91
+ backgroundColor: theme.colors.background,
92
+ };
93
+ case "container":
94
+ return {
95
+ backgroundColor: theme.colors.background,
96
+ padding: spacing[4],
97
+ };
98
+ default:
99
+ return {};
100
+ }
101
+ })();
102
+ // Map padding to numeric values
103
+ const paddingValue = (() => {
104
+ switch (padding) {
105
+ case "xs":
106
+ return spacing[1];
107
+ case "sm":
108
+ return spacing[2];
109
+ case "md":
110
+ return spacing[3];
111
+ case "lg":
112
+ return spacing[4];
113
+ case "xl":
114
+ return spacing[5];
115
+ default:
116
+ return undefined;
117
+ }
118
+ })();
119
+ // Map margin to numeric values
120
+ const marginValue = (() => {
121
+ switch (margin) {
122
+ case "xs":
123
+ return spacing[1];
124
+ case "sm":
125
+ return spacing[2];
126
+ case "md":
127
+ return spacing[3];
128
+ case "lg":
129
+ return spacing[4];
130
+ case "xl":
131
+ return spacing[5];
132
+ default:
133
+ return undefined;
134
+ }
135
+ })();
136
+ // Map flex direction
137
+ const flexDirection = (() => {
138
+ switch (direction) {
139
+ case "row":
140
+ return "row";
141
+ case "column":
142
+ return "column";
143
+ case "row-reverse":
144
+ return "row-reverse";
145
+ case "column-reverse":
146
+ return "column-reverse";
147
+ default:
148
+ return "column";
149
+ }
150
+ })();
151
+ // Map align items
152
+ const alignItems = (() => {
153
+ switch (align) {
154
+ case "start":
155
+ return "flex-start";
156
+ case "center":
157
+ return "center";
158
+ case "end":
159
+ return "flex-end";
160
+ case "stretch":
161
+ return "stretch";
162
+ case "baseline":
163
+ return "baseline";
164
+ default:
165
+ return "stretch";
166
+ }
167
+ })();
168
+ // Map justify content
169
+ const justifyContent = (() => {
170
+ switch (justify) {
171
+ case "start":
172
+ return "flex-start";
173
+ case "center":
174
+ return "center";
175
+ case "end":
176
+ return "flex-end";
177
+ case "between":
178
+ return "space-between";
179
+ case "around":
180
+ return "space-around";
181
+ case "evenly":
182
+ return "space-evenly";
183
+ default:
184
+ return "flex-start";
185
+ }
186
+ })();
187
+ // Map flex value
188
+ const flexValue = (() => {
189
+ if (typeof flex === "number") {
190
+ return flex;
191
+ }
192
+ switch (flex) {
193
+ case "auto":
194
+ return undefined; // auto is default
195
+ case "initial":
196
+ return 0;
197
+ case "none":
198
+ default:
199
+ return undefined;
200
+ }
201
+ })();
202
+ const computedStyle = {
203
+ ...variantStyles,
204
+ ...(paddingValue !== undefined && { padding: paddingValue }),
205
+ ...(marginValue !== undefined && { margin: marginValue }),
206
+ flexDirection,
207
+ alignItems,
208
+ justifyContent,
209
+ ...(flexValue !== undefined && { flex: flexValue }),
210
+ ...(fullWidth && { width: "100%" }),
211
+ ...(fullHeight && { height: "100%" }),
212
+ ...(centered && {
213
+ alignItems: "center",
214
+ justifyContent: "center",
215
+ }),
216
+ ...(backgroundColor && { backgroundColor }),
217
+ ...(borderColor && { borderColor }),
218
+ ...(borderWidth !== undefined && { borderWidth }),
219
+ ...(borderRadius !== undefined && { borderRadius }),
220
+ ...(shadow && {
221
+ shadowColor: "#000",
222
+ shadowOffset: { width: 0, height: 2 },
223
+ shadowOpacity: 0.1,
224
+ shadowRadius: 4,
225
+ elevation: 3,
226
+ }),
227
+ };
228
+ const finalStyle = Array.isArray(style)
229
+ ? [computedStyle, ...style]
230
+ : [computedStyle, style];
231
+ return _jsx(RNView, { ref: ref, style: finalStyle, ...props });
232
+ });
233
+ View.displayName = "View";
234
+ // Convenience components
235
+ export const Card = forwardRef((props, ref) => _jsx(View, { ref: ref, variant: "card", ...props }));
236
+ Card.displayName = "Card";
237
+ export const Container = forwardRef((props, ref) => _jsx(View, { ref: ref, variant: "container", ...props }));
238
+ Container.displayName = "Container";
239
+ export const Surface = forwardRef((props, ref) => _jsx(View, { ref: ref, variant: "surface", ...props }));
240
+ Surface.displayName = "Surface";
241
+ export const Overlay = forwardRef((props, ref) => _jsx(View, { ref: ref, variant: "overlay", ...props }));
242
+ Overlay.displayName = "Overlay";
243
+ export const Row = forwardRef((props, ref) => _jsx(View, { ref: ref, direction: "row", ...props }));
244
+ Row.displayName = "Row";
245
+ export const Column = forwardRef((props, ref) => _jsx(View, { ref: ref, direction: "column", ...props }));
246
+ Column.displayName = "Column";
247
+ export const Center = forwardRef((props, ref) => (_jsx(View, { ref: ref, centered: true, ...props })));
248
+ Center.displayName = "Center";
249
+ // Export view variants for external use
250
+ export { viewVariants };
@@ -0,0 +1,9 @@
1
+ // barrel file :)
2
+ export * from "./useAvatars";
3
+ export * from "./useCameraToggle";
4
+ export * from "./useKeyboard";
5
+ export * from "./useKeyboardSlide";
6
+ export * from "./useLivestreamInfo";
7
+ export * from "./useOuterAndInnerDimensions";
8
+ export * from "./usePlayerDimensions";
9
+ export * from "./useSegmentTiming";