@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,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 };