@streamplace/components 0.6.37 → 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.
- package/dist/components/chat/chat-box.js +109 -0
- package/dist/components/chat/chat-message.js +76 -0
- package/dist/components/chat/chat.js +56 -0
- package/dist/components/chat/mention-suggestions.js +39 -0
- package/dist/components/chat/mod-view.js +33 -0
- package/dist/components/mobile-player/fullscreen.js +69 -0
- package/dist/components/mobile-player/fullscreen.native.js +151 -0
- package/dist/components/mobile-player/player.js +103 -0
- package/dist/components/mobile-player/props.js +1 -0
- package/dist/components/mobile-player/shared.js +51 -0
- package/dist/components/mobile-player/ui/countdown.js +79 -0
- package/dist/components/mobile-player/ui/index.js +5 -0
- package/dist/components/mobile-player/ui/input.js +38 -0
- package/dist/components/mobile-player/ui/metrics.js +40 -0
- package/dist/components/mobile-player/ui/streamer-context-menu.js +4 -0
- package/dist/components/mobile-player/ui/viewer-context-menu.js +20 -0
- package/dist/components/mobile-player/use-webrtc.js +232 -0
- package/dist/components/mobile-player/video.js +375 -0
- package/dist/components/mobile-player/video.native.js +238 -0
- package/dist/components/mobile-player/webrtc-diagnostics.js +106 -0
- package/dist/components/mobile-player/webrtc-primitives.js +25 -0
- package/dist/components/mobile-player/webrtc-primitives.native.js +1 -0
- package/dist/components/ui/button.js +220 -0
- package/dist/components/ui/dialog.js +203 -0
- package/dist/components/ui/dropdown.js +148 -0
- package/dist/components/ui/icons.js +22 -0
- package/dist/components/ui/index.js +22 -0
- package/dist/components/ui/input.js +202 -0
- package/dist/components/ui/loader.js +7 -0
- package/dist/components/ui/primitives/button.js +121 -0
- package/dist/components/ui/primitives/input.js +202 -0
- package/dist/components/ui/primitives/modal.js +203 -0
- package/dist/components/ui/primitives/text.js +286 -0
- package/dist/components/ui/resizeable.js +101 -0
- package/dist/components/ui/text.js +175 -0
- package/dist/components/ui/textarea.js +17 -0
- package/dist/components/ui/toast.js +129 -0
- package/dist/components/ui/view.js +250 -0
- package/dist/hooks/index.js +9 -0
- package/dist/hooks/useAvatars.js +32 -0
- package/dist/hooks/useCameraToggle.js +9 -0
- package/dist/hooks/useKeyboard.js +33 -0
- package/dist/hooks/useKeyboardSlide.js +11 -0
- package/dist/hooks/useLivestreamInfo.js +62 -0
- package/dist/hooks/useOuterAndInnerDimensions.js +27 -0
- package/dist/hooks/usePlayerDimensions.js +19 -0
- package/dist/hooks/useSegmentTiming.js +62 -0
- package/dist/index.js +10 -0
- package/dist/lib/facet.js +88 -0
- package/dist/lib/theme/atoms.js +620 -0
- package/dist/lib/theme/atoms.types.js +5 -0
- package/dist/lib/theme/index.js +9 -0
- package/dist/lib/theme/theme.js +248 -0
- package/dist/lib/theme/tokens.js +383 -0
- package/dist/lib/utils.js +94 -0
- package/dist/livestream-provider/index.js +8 -3
- package/dist/livestream-store/chat.js +89 -65
- package/dist/livestream-store/index.js +1 -0
- package/dist/livestream-store/livestream-store.js +3 -0
- package/dist/livestream-store/stream-key.js +115 -0
- package/dist/player-store/player-provider.js +0 -1
- package/dist/player-store/player-store.js +13 -0
- package/dist/streamplace-store/block.js +23 -0
- package/dist/streamplace-store/index.js +1 -0
- package/dist/streamplace-store/stream.js +193 -0
- package/node-compile-cache/v22.15.0-x64-efe9a9df-0/37be0eec +0 -0
- package/node-compile-cache/v22.15.0-x64-efe9a9df-0/56540125 +0 -0
- package/node-compile-cache/v22.15.0-x64-efe9a9df-0/67b1eb60 +0 -0
- package/node-compile-cache/v22.15.0-x64-efe9a9df-0/7c275f90 +0 -0
- package/package.json +20 -4
- package/src/components/chat/chat-box.tsx +195 -0
- package/src/components/chat/chat-message.tsx +192 -0
- package/src/components/chat/chat.tsx +128 -0
- package/src/components/chat/mention-suggestions.tsx +71 -0
- package/src/components/chat/mod-view.tsx +118 -0
- package/src/components/mobile-player/fullscreen.native.tsx +193 -0
- package/src/components/mobile-player/fullscreen.tsx +79 -0
- package/src/components/mobile-player/player.tsx +134 -0
- package/src/components/mobile-player/props.tsx +11 -0
- package/src/components/mobile-player/shared.tsx +56 -0
- package/src/components/mobile-player/ui/countdown.tsx +119 -0
- package/src/components/mobile-player/ui/index.ts +5 -0
- package/src/components/mobile-player/ui/input.tsx +85 -0
- package/src/components/mobile-player/ui/metrics.tsx +69 -0
- package/src/components/mobile-player/ui/streamer-context-menu.tsx +3 -0
- package/src/components/mobile-player/ui/viewer-context-menu.tsx +70 -0
- package/src/components/mobile-player/use-webrtc.tsx +282 -0
- package/src/components/mobile-player/video.native.tsx +360 -0
- package/src/components/mobile-player/video.tsx +557 -0
- package/src/components/mobile-player/webrtc-diagnostics.tsx +149 -0
- package/src/components/mobile-player/webrtc-primitives.native.tsx +6 -0
- package/src/components/mobile-player/webrtc-primitives.tsx +33 -0
- package/src/components/ui/button.tsx +309 -0
- package/src/components/ui/dialog.tsx +376 -0
- package/src/components/ui/dropdown.tsx +399 -0
- package/src/components/ui/icons.tsx +50 -0
- package/src/components/ui/index.ts +33 -0
- package/src/components/ui/input.tsx +350 -0
- package/src/components/ui/loader.tsx +9 -0
- package/src/components/ui/primitives/button.tsx +292 -0
- package/src/components/ui/primitives/input.tsx +422 -0
- package/src/components/ui/primitives/modal.tsx +421 -0
- package/src/components/ui/primitives/text.tsx +499 -0
- package/src/components/ui/resizeable.tsx +169 -0
- package/src/components/ui/text.tsx +330 -0
- package/src/components/ui/textarea.tsx +34 -0
- package/src/components/ui/toast.tsx +203 -0
- package/src/components/ui/view.tsx +344 -0
- package/src/hooks/index.ts +9 -0
- package/src/hooks/useAvatars.tsx +44 -0
- package/src/hooks/useCameraToggle.ts +12 -0
- package/src/hooks/useKeyboard.tsx +41 -0
- package/src/hooks/useKeyboardSlide.ts +12 -0
- package/src/hooks/useLivestreamInfo.ts +67 -0
- package/src/hooks/useOuterAndInnerDimensions.tsx +32 -0
- package/src/hooks/usePlayerDimensions.ts +23 -0
- package/src/hooks/useSegmentTiming.tsx +88 -0
- package/src/index.tsx +21 -0
- package/src/lib/facet.ts +131 -0
- package/src/lib/theme/atoms.ts +760 -0
- package/src/lib/theme/atoms.types.ts +258 -0
- package/src/lib/theme/index.ts +48 -0
- package/src/lib/theme/theme.tsx +436 -0
- package/src/lib/theme/tokens.ts +409 -0
- package/src/lib/utils.ts +132 -0
- package/src/livestream-provider/index.tsx +13 -2
- package/src/livestream-store/chat.tsx +115 -78
- package/src/livestream-store/index.tsx +1 -0
- package/src/livestream-store/livestream-state.tsx +3 -0
- package/src/livestream-store/livestream-store.tsx +3 -0
- package/src/livestream-store/stream-key.tsx +124 -0
- package/src/player-store/player-provider.tsx +0 -1
- package/src/player-store/player-state.tsx +28 -0
- package/src/player-store/player-store.tsx +22 -0
- package/src/streamplace-store/block.tsx +29 -0
- package/src/streamplace-store/index.tsx +1 -0
- package/src/streamplace-store/stream.tsx +262 -0
- package/tsconfig.tsbuildinfo +1 -1
|
@@ -0,0 +1,436 @@
|
|
|
1
|
+
import { PortalHost } from "@rn-primitives/portal";
|
|
2
|
+
import {
|
|
3
|
+
createContext,
|
|
4
|
+
useContext,
|
|
5
|
+
useMemo,
|
|
6
|
+
useState,
|
|
7
|
+
type ReactNode,
|
|
8
|
+
} from "react";
|
|
9
|
+
import { Platform, useColorScheme } from "react-native";
|
|
10
|
+
import {
|
|
11
|
+
animations,
|
|
12
|
+
borderRadius,
|
|
13
|
+
colors,
|
|
14
|
+
shadows,
|
|
15
|
+
spacing,
|
|
16
|
+
touchTargets,
|
|
17
|
+
typography,
|
|
18
|
+
} from "./tokens";
|
|
19
|
+
|
|
20
|
+
import { GestureHandlerRootView } from "react-native-gesture-handler";
|
|
21
|
+
|
|
22
|
+
// Theme interfaces
|
|
23
|
+
export interface Theme {
|
|
24
|
+
colors: {
|
|
25
|
+
// Core semantic colors
|
|
26
|
+
background: string;
|
|
27
|
+
foreground: string;
|
|
28
|
+
|
|
29
|
+
// Card/surface colors
|
|
30
|
+
card: string;
|
|
31
|
+
cardForeground: string;
|
|
32
|
+
|
|
33
|
+
// Popover colors
|
|
34
|
+
popover: string;
|
|
35
|
+
popoverForeground: string;
|
|
36
|
+
|
|
37
|
+
// Primary colors
|
|
38
|
+
primary: string;
|
|
39
|
+
primaryForeground: string;
|
|
40
|
+
|
|
41
|
+
// Secondary colors
|
|
42
|
+
secondary: string;
|
|
43
|
+
secondaryForeground: string;
|
|
44
|
+
|
|
45
|
+
// Muted colors
|
|
46
|
+
muted: string;
|
|
47
|
+
mutedForeground: string;
|
|
48
|
+
|
|
49
|
+
// Accent colors
|
|
50
|
+
accent: string;
|
|
51
|
+
accentForeground: string;
|
|
52
|
+
|
|
53
|
+
// Destructive colors
|
|
54
|
+
destructive: string;
|
|
55
|
+
destructiveForeground: string;
|
|
56
|
+
|
|
57
|
+
// Success colors
|
|
58
|
+
success: string;
|
|
59
|
+
successForeground: string;
|
|
60
|
+
|
|
61
|
+
// Warning colors
|
|
62
|
+
warning: string;
|
|
63
|
+
warningForeground: string;
|
|
64
|
+
|
|
65
|
+
// Border and input colors
|
|
66
|
+
border: string;
|
|
67
|
+
input: string;
|
|
68
|
+
ring: string;
|
|
69
|
+
|
|
70
|
+
// Text colors
|
|
71
|
+
text: string;
|
|
72
|
+
textMuted: string;
|
|
73
|
+
textDisabled: string;
|
|
74
|
+
};
|
|
75
|
+
spacing: typeof spacing;
|
|
76
|
+
borderRadius: typeof borderRadius;
|
|
77
|
+
typography: typeof typography;
|
|
78
|
+
shadows: typeof shadows;
|
|
79
|
+
touchTargets: typeof touchTargets;
|
|
80
|
+
animations: typeof animations;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// Utility styles interface
|
|
84
|
+
export interface ThemeStyles {
|
|
85
|
+
shadow: {
|
|
86
|
+
sm: typeof shadows.sm;
|
|
87
|
+
md: typeof shadows.md;
|
|
88
|
+
lg: typeof shadows.lg;
|
|
89
|
+
xl: typeof shadows.xl;
|
|
90
|
+
};
|
|
91
|
+
button: {
|
|
92
|
+
primary: object;
|
|
93
|
+
secondary: object;
|
|
94
|
+
outline: object;
|
|
95
|
+
ghost: object;
|
|
96
|
+
};
|
|
97
|
+
text: {
|
|
98
|
+
primary: object;
|
|
99
|
+
muted: object;
|
|
100
|
+
disabled: object;
|
|
101
|
+
};
|
|
102
|
+
input: {
|
|
103
|
+
base: object;
|
|
104
|
+
focused: object;
|
|
105
|
+
error: object;
|
|
106
|
+
};
|
|
107
|
+
card: {
|
|
108
|
+
base: object;
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
// Icon utilities interface
|
|
113
|
+
export interface ThemeIcons {
|
|
114
|
+
color: {
|
|
115
|
+
default: string;
|
|
116
|
+
muted: string;
|
|
117
|
+
primary: string;
|
|
118
|
+
secondary: string;
|
|
119
|
+
destructive: string;
|
|
120
|
+
success: string;
|
|
121
|
+
warning: string;
|
|
122
|
+
};
|
|
123
|
+
size: {
|
|
124
|
+
sm: number;
|
|
125
|
+
md: number;
|
|
126
|
+
lg: number;
|
|
127
|
+
xl: number;
|
|
128
|
+
};
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
// Create theme colors based on dark mode
|
|
132
|
+
const createThemeColors = (isDark: boolean): Theme["colors"] => ({
|
|
133
|
+
background: isDark ? colors.gray[950] : colors.white,
|
|
134
|
+
foreground: isDark ? colors.gray[50] : colors.gray[950],
|
|
135
|
+
|
|
136
|
+
card: isDark ? colors.gray[900] : colors.white,
|
|
137
|
+
cardForeground: isDark ? colors.gray[50] : colors.gray[950],
|
|
138
|
+
|
|
139
|
+
popover: isDark ? colors.gray[900] : colors.white,
|
|
140
|
+
popoverForeground: isDark ? colors.gray[50] : colors.gray[950],
|
|
141
|
+
|
|
142
|
+
primary: Platform.OS === "ios" ? colors.ios.systemBlue : colors.primary[500],
|
|
143
|
+
primaryForeground: colors.white,
|
|
144
|
+
|
|
145
|
+
secondary: isDark ? colors.gray[800] : colors.gray[100],
|
|
146
|
+
secondaryForeground: isDark ? colors.gray[50] : colors.gray[900],
|
|
147
|
+
|
|
148
|
+
muted: isDark ? colors.gray[800] : colors.gray[100],
|
|
149
|
+
mutedForeground: isDark ? colors.gray[400] : colors.gray[500],
|
|
150
|
+
|
|
151
|
+
accent: isDark ? colors.gray[800] : colors.gray[100],
|
|
152
|
+
accentForeground: isDark ? colors.gray[50] : colors.gray[900],
|
|
153
|
+
|
|
154
|
+
destructive:
|
|
155
|
+
Platform.OS === "ios" ? colors.ios.systemRed : colors.destructive[500],
|
|
156
|
+
destructiveForeground: colors.white,
|
|
157
|
+
|
|
158
|
+
success: Platform.OS === "ios" ? colors.ios.systemGreen : colors.success[500],
|
|
159
|
+
successForeground: colors.white,
|
|
160
|
+
|
|
161
|
+
warning:
|
|
162
|
+
Platform.OS === "ios" ? colors.ios.systemOrange : colors.warning[500],
|
|
163
|
+
warningForeground: colors.white,
|
|
164
|
+
|
|
165
|
+
border: isDark ? colors.gray[500] + "30" : colors.gray[200] + "30",
|
|
166
|
+
input: isDark ? colors.gray[800] : colors.gray[200],
|
|
167
|
+
ring: Platform.OS === "ios" ? colors.ios.systemBlue : colors.primary[500],
|
|
168
|
+
|
|
169
|
+
text: isDark ? colors.gray[50] : colors.gray[950],
|
|
170
|
+
textMuted: isDark ? colors.gray[400] : colors.gray[500],
|
|
171
|
+
textDisabled: isDark ? colors.gray[600] : colors.gray[400],
|
|
172
|
+
});
|
|
173
|
+
|
|
174
|
+
// Create theme styles based on colors
|
|
175
|
+
const createThemeStyles = (themeColors: Theme["colors"]): ThemeStyles => ({
|
|
176
|
+
shadow: {
|
|
177
|
+
sm: shadows.sm,
|
|
178
|
+
md: shadows.md,
|
|
179
|
+
lg: shadows.lg,
|
|
180
|
+
xl: shadows.xl,
|
|
181
|
+
},
|
|
182
|
+
button: {
|
|
183
|
+
primary: {
|
|
184
|
+
backgroundColor: themeColors.primary,
|
|
185
|
+
borderWidth: 0,
|
|
186
|
+
...shadows.sm,
|
|
187
|
+
},
|
|
188
|
+
secondary: {
|
|
189
|
+
backgroundColor: themeColors.secondary,
|
|
190
|
+
borderWidth: 0,
|
|
191
|
+
},
|
|
192
|
+
outline: {
|
|
193
|
+
backgroundColor: "transparent",
|
|
194
|
+
borderWidth: 1,
|
|
195
|
+
borderColor: themeColors.border,
|
|
196
|
+
},
|
|
197
|
+
ghost: {
|
|
198
|
+
backgroundColor: "transparent",
|
|
199
|
+
borderWidth: 0,
|
|
200
|
+
},
|
|
201
|
+
},
|
|
202
|
+
text: {
|
|
203
|
+
primary: {
|
|
204
|
+
color: themeColors.text,
|
|
205
|
+
},
|
|
206
|
+
muted: {
|
|
207
|
+
color: themeColors.textMuted,
|
|
208
|
+
},
|
|
209
|
+
disabled: {
|
|
210
|
+
color: themeColors.textDisabled,
|
|
211
|
+
},
|
|
212
|
+
},
|
|
213
|
+
input: {
|
|
214
|
+
base: {
|
|
215
|
+
backgroundColor: themeColors.background,
|
|
216
|
+
borderWidth: 1,
|
|
217
|
+
borderColor: themeColors.border,
|
|
218
|
+
borderRadius: borderRadius.md,
|
|
219
|
+
paddingHorizontal: spacing[3],
|
|
220
|
+
paddingVertical: spacing[3],
|
|
221
|
+
minHeight: touchTargets.minimum,
|
|
222
|
+
},
|
|
223
|
+
focused: {
|
|
224
|
+
borderColor: themeColors.ring,
|
|
225
|
+
borderWidth: 2,
|
|
226
|
+
},
|
|
227
|
+
error: {
|
|
228
|
+
borderColor: themeColors.destructive,
|
|
229
|
+
borderWidth: 2,
|
|
230
|
+
},
|
|
231
|
+
},
|
|
232
|
+
card: {
|
|
233
|
+
base: {
|
|
234
|
+
backgroundColor: themeColors.card,
|
|
235
|
+
borderRadius: borderRadius.lg,
|
|
236
|
+
...shadows.sm,
|
|
237
|
+
},
|
|
238
|
+
},
|
|
239
|
+
});
|
|
240
|
+
|
|
241
|
+
// Create theme icons based on colors
|
|
242
|
+
const createThemeIcons = (themeColors: Theme["colors"]): ThemeIcons => ({
|
|
243
|
+
color: {
|
|
244
|
+
default: themeColors.text,
|
|
245
|
+
muted: themeColors.textMuted,
|
|
246
|
+
primary: themeColors.primary,
|
|
247
|
+
secondary: themeColors.secondary,
|
|
248
|
+
destructive: themeColors.destructive,
|
|
249
|
+
success: themeColors.success,
|
|
250
|
+
warning: themeColors.warning,
|
|
251
|
+
},
|
|
252
|
+
size: {
|
|
253
|
+
sm: 16,
|
|
254
|
+
md: 20,
|
|
255
|
+
lg: 24,
|
|
256
|
+
xl: 32,
|
|
257
|
+
},
|
|
258
|
+
});
|
|
259
|
+
|
|
260
|
+
// Theme context interface
|
|
261
|
+
interface ThemeContextType {
|
|
262
|
+
theme: Theme;
|
|
263
|
+
styles: ThemeStyles;
|
|
264
|
+
icons: ThemeIcons;
|
|
265
|
+
isDark: boolean;
|
|
266
|
+
currentTheme: "light" | "dark" | "system";
|
|
267
|
+
systemTheme: "light" | "dark";
|
|
268
|
+
setTheme: (theme: "light" | "dark" | "system") => void;
|
|
269
|
+
toggleTheme: () => void;
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
// Create the theme context
|
|
273
|
+
const ThemeContext = createContext<ThemeContextType | null>(null);
|
|
274
|
+
|
|
275
|
+
// Theme provider props
|
|
276
|
+
interface ThemeProviderProps {
|
|
277
|
+
children: ReactNode;
|
|
278
|
+
defaultTheme?: "light" | "dark" | "system";
|
|
279
|
+
forcedTheme?: "light" | "dark";
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
// Theme provider component
|
|
283
|
+
export function ThemeProvider({
|
|
284
|
+
children,
|
|
285
|
+
defaultTheme = "system",
|
|
286
|
+
forcedTheme,
|
|
287
|
+
}: ThemeProviderProps) {
|
|
288
|
+
const systemColorScheme = useColorScheme();
|
|
289
|
+
const [currentTheme, setCurrentTheme] = useState<"light" | "dark" | "system">(
|
|
290
|
+
defaultTheme,
|
|
291
|
+
);
|
|
292
|
+
|
|
293
|
+
// Determine if dark mode should be active
|
|
294
|
+
const isDark = useMemo(() => {
|
|
295
|
+
if (forcedTheme === "light") return false;
|
|
296
|
+
if (forcedTheme === "dark") return true;
|
|
297
|
+
if (currentTheme === "light") return false;
|
|
298
|
+
if (currentTheme === "dark") return true;
|
|
299
|
+
if (currentTheme === "system") return systemColorScheme === "dark";
|
|
300
|
+
return systemColorScheme === "dark";
|
|
301
|
+
}, [forcedTheme, currentTheme, systemColorScheme]);
|
|
302
|
+
|
|
303
|
+
// Create theme based on dark mode
|
|
304
|
+
const theme = useMemo<Theme>(() => {
|
|
305
|
+
const themeColors = createThemeColors(isDark);
|
|
306
|
+
return {
|
|
307
|
+
colors: themeColors,
|
|
308
|
+
spacing,
|
|
309
|
+
borderRadius,
|
|
310
|
+
typography,
|
|
311
|
+
shadows,
|
|
312
|
+
touchTargets,
|
|
313
|
+
animations,
|
|
314
|
+
};
|
|
315
|
+
}, [isDark]);
|
|
316
|
+
|
|
317
|
+
// Create utility styles
|
|
318
|
+
const styles = useMemo<ThemeStyles>(() => {
|
|
319
|
+
return createThemeStyles(theme.colors);
|
|
320
|
+
}, [theme.colors]);
|
|
321
|
+
|
|
322
|
+
// Create icon utilities
|
|
323
|
+
const icons = useMemo<ThemeIcons>(() => {
|
|
324
|
+
return createThemeIcons(theme.colors);
|
|
325
|
+
}, [theme.colors]);
|
|
326
|
+
|
|
327
|
+
// Theme controls
|
|
328
|
+
const setTheme = (newTheme: "light" | "dark" | "system") => {
|
|
329
|
+
if (!forcedTheme) {
|
|
330
|
+
setCurrentTheme(newTheme);
|
|
331
|
+
}
|
|
332
|
+
};
|
|
333
|
+
|
|
334
|
+
const toggleTheme = () => {
|
|
335
|
+
if (!forcedTheme) {
|
|
336
|
+
setCurrentTheme((prev) => {
|
|
337
|
+
if (prev === "light") return "dark";
|
|
338
|
+
if (prev === "dark") return "system";
|
|
339
|
+
return "light";
|
|
340
|
+
});
|
|
341
|
+
}
|
|
342
|
+
};
|
|
343
|
+
|
|
344
|
+
const value = useMemo<ThemeContextType>(
|
|
345
|
+
() => ({
|
|
346
|
+
theme,
|
|
347
|
+
styles,
|
|
348
|
+
icons,
|
|
349
|
+
isDark,
|
|
350
|
+
currentTheme: forcedTheme || currentTheme,
|
|
351
|
+
systemTheme: (systemColorScheme as "light" | "dark") || "light",
|
|
352
|
+
setTheme,
|
|
353
|
+
toggleTheme,
|
|
354
|
+
}),
|
|
355
|
+
[
|
|
356
|
+
theme,
|
|
357
|
+
styles,
|
|
358
|
+
icons,
|
|
359
|
+
isDark,
|
|
360
|
+
forcedTheme,
|
|
361
|
+
currentTheme,
|
|
362
|
+
systemColorScheme,
|
|
363
|
+
setTheme,
|
|
364
|
+
toggleTheme,
|
|
365
|
+
],
|
|
366
|
+
);
|
|
367
|
+
|
|
368
|
+
return (
|
|
369
|
+
<ThemeContext.Provider value={value}>
|
|
370
|
+
<GestureHandlerRootView>
|
|
371
|
+
{children}
|
|
372
|
+
<PortalHost />
|
|
373
|
+
</GestureHandlerRootView>
|
|
374
|
+
</ThemeContext.Provider>
|
|
375
|
+
);
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
// Hook to use theme
|
|
379
|
+
export function useTheme(): ThemeContextType {
|
|
380
|
+
const context = useContext(ThemeContext);
|
|
381
|
+
if (!context) {
|
|
382
|
+
throw new Error("useTheme must be used within a ThemeProvider");
|
|
383
|
+
}
|
|
384
|
+
return context;
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
// Hook to get current platform's typography
|
|
388
|
+
export function usePlatformTypography() {
|
|
389
|
+
const { theme } = useTheme();
|
|
390
|
+
|
|
391
|
+
return useMemo(() => {
|
|
392
|
+
if (Platform.OS === "ios") {
|
|
393
|
+
return theme.typography.ios;
|
|
394
|
+
} else if (Platform.OS === "android") {
|
|
395
|
+
return theme.typography.android;
|
|
396
|
+
}
|
|
397
|
+
return theme.typography.universal;
|
|
398
|
+
}, [theme.typography]);
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
// Utility function to create theme-aware styles
|
|
402
|
+
export function createThemedStyles<T extends Record<string, any>>(
|
|
403
|
+
styleCreator: (theme: Theme, styles: ThemeStyles, icons: ThemeIcons) => T,
|
|
404
|
+
) {
|
|
405
|
+
return function useThemedStyles() {
|
|
406
|
+
const { theme, styles, icons } = useTheme();
|
|
407
|
+
return useMemo(
|
|
408
|
+
() => styleCreator(theme, styles, icons),
|
|
409
|
+
[theme, styles, icons],
|
|
410
|
+
);
|
|
411
|
+
};
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
// Create light and dark theme instances for external use
|
|
415
|
+
export const lightTheme: Theme = {
|
|
416
|
+
colors: createThemeColors(false),
|
|
417
|
+
spacing,
|
|
418
|
+
borderRadius,
|
|
419
|
+
typography,
|
|
420
|
+
shadows,
|
|
421
|
+
touchTargets,
|
|
422
|
+
animations,
|
|
423
|
+
};
|
|
424
|
+
|
|
425
|
+
export const darkTheme: Theme = {
|
|
426
|
+
colors: createThemeColors(true),
|
|
427
|
+
spacing,
|
|
428
|
+
borderRadius,
|
|
429
|
+
typography,
|
|
430
|
+
shadows,
|
|
431
|
+
touchTargets,
|
|
432
|
+
animations,
|
|
433
|
+
};
|
|
434
|
+
|
|
435
|
+
// Export individual theme utilities for convenience
|
|
436
|
+
export { createThemeColors, createThemeIcons, createThemeStyles };
|