@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.
Files changed (138) hide show
  1. package/dist/components/chat/chat-box.js +109 -0
  2. package/dist/components/chat/chat-message.js +76 -0
  3. package/dist/components/chat/chat.js +56 -0
  4. package/dist/components/chat/mention-suggestions.js +39 -0
  5. package/dist/components/chat/mod-view.js +33 -0
  6. package/dist/components/mobile-player/fullscreen.js +69 -0
  7. package/dist/components/mobile-player/fullscreen.native.js +151 -0
  8. package/dist/components/mobile-player/player.js +103 -0
  9. package/dist/components/mobile-player/props.js +1 -0
  10. package/dist/components/mobile-player/shared.js +51 -0
  11. package/dist/components/mobile-player/ui/countdown.js +79 -0
  12. package/dist/components/mobile-player/ui/index.js +5 -0
  13. package/dist/components/mobile-player/ui/input.js +38 -0
  14. package/dist/components/mobile-player/ui/metrics.js +40 -0
  15. package/dist/components/mobile-player/ui/streamer-context-menu.js +4 -0
  16. package/dist/components/mobile-player/ui/viewer-context-menu.js +20 -0
  17. package/dist/components/mobile-player/use-webrtc.js +232 -0
  18. package/dist/components/mobile-player/video.js +375 -0
  19. package/dist/components/mobile-player/video.native.js +238 -0
  20. package/dist/components/mobile-player/webrtc-diagnostics.js +106 -0
  21. package/dist/components/mobile-player/webrtc-primitives.js +25 -0
  22. package/dist/components/mobile-player/webrtc-primitives.native.js +1 -0
  23. package/dist/components/ui/button.js +220 -0
  24. package/dist/components/ui/dialog.js +203 -0
  25. package/dist/components/ui/dropdown.js +148 -0
  26. package/dist/components/ui/icons.js +22 -0
  27. package/dist/components/ui/index.js +22 -0
  28. package/dist/components/ui/input.js +202 -0
  29. package/dist/components/ui/loader.js +7 -0
  30. package/dist/components/ui/primitives/button.js +121 -0
  31. package/dist/components/ui/primitives/input.js +202 -0
  32. package/dist/components/ui/primitives/modal.js +203 -0
  33. package/dist/components/ui/primitives/text.js +286 -0
  34. package/dist/components/ui/resizeable.js +101 -0
  35. package/dist/components/ui/text.js +175 -0
  36. package/dist/components/ui/textarea.js +17 -0
  37. package/dist/components/ui/toast.js +129 -0
  38. package/dist/components/ui/view.js +250 -0
  39. package/dist/hooks/index.js +9 -0
  40. package/dist/hooks/useAvatars.js +32 -0
  41. package/dist/hooks/useCameraToggle.js +9 -0
  42. package/dist/hooks/useKeyboard.js +33 -0
  43. package/dist/hooks/useKeyboardSlide.js +11 -0
  44. package/dist/hooks/useLivestreamInfo.js +62 -0
  45. package/dist/hooks/useOuterAndInnerDimensions.js +27 -0
  46. package/dist/hooks/usePlayerDimensions.js +19 -0
  47. package/dist/hooks/useSegmentTiming.js +62 -0
  48. package/dist/index.js +10 -0
  49. package/dist/lib/facet.js +88 -0
  50. package/dist/lib/theme/atoms.js +620 -0
  51. package/dist/lib/theme/atoms.types.js +5 -0
  52. package/dist/lib/theme/index.js +9 -0
  53. package/dist/lib/theme/theme.js +248 -0
  54. package/dist/lib/theme/tokens.js +383 -0
  55. package/dist/lib/utils.js +94 -0
  56. package/dist/livestream-provider/index.js +8 -3
  57. package/dist/livestream-store/chat.js +89 -65
  58. package/dist/livestream-store/index.js +1 -0
  59. package/dist/livestream-store/livestream-store.js +3 -0
  60. package/dist/livestream-store/stream-key.js +115 -0
  61. package/dist/player-store/player-provider.js +0 -1
  62. package/dist/player-store/player-store.js +13 -0
  63. package/dist/streamplace-store/block.js +23 -0
  64. package/dist/streamplace-store/index.js +1 -0
  65. package/dist/streamplace-store/stream.js +193 -0
  66. package/node-compile-cache/v22.15.0-x64-efe9a9df-0/37be0eec +0 -0
  67. package/node-compile-cache/v22.15.0-x64-efe9a9df-0/56540125 +0 -0
  68. package/node-compile-cache/v22.15.0-x64-efe9a9df-0/67b1eb60 +0 -0
  69. package/node-compile-cache/v22.15.0-x64-efe9a9df-0/7c275f90 +0 -0
  70. package/package.json +20 -4
  71. package/src/components/chat/chat-box.tsx +195 -0
  72. package/src/components/chat/chat-message.tsx +192 -0
  73. package/src/components/chat/chat.tsx +128 -0
  74. package/src/components/chat/mention-suggestions.tsx +71 -0
  75. package/src/components/chat/mod-view.tsx +118 -0
  76. package/src/components/mobile-player/fullscreen.native.tsx +193 -0
  77. package/src/components/mobile-player/fullscreen.tsx +79 -0
  78. package/src/components/mobile-player/player.tsx +134 -0
  79. package/src/components/mobile-player/props.tsx +11 -0
  80. package/src/components/mobile-player/shared.tsx +56 -0
  81. package/src/components/mobile-player/ui/countdown.tsx +119 -0
  82. package/src/components/mobile-player/ui/index.ts +5 -0
  83. package/src/components/mobile-player/ui/input.tsx +85 -0
  84. package/src/components/mobile-player/ui/metrics.tsx +69 -0
  85. package/src/components/mobile-player/ui/streamer-context-menu.tsx +3 -0
  86. package/src/components/mobile-player/ui/viewer-context-menu.tsx +70 -0
  87. package/src/components/mobile-player/use-webrtc.tsx +282 -0
  88. package/src/components/mobile-player/video.native.tsx +360 -0
  89. package/src/components/mobile-player/video.tsx +557 -0
  90. package/src/components/mobile-player/webrtc-diagnostics.tsx +149 -0
  91. package/src/components/mobile-player/webrtc-primitives.native.tsx +6 -0
  92. package/src/components/mobile-player/webrtc-primitives.tsx +33 -0
  93. package/src/components/ui/button.tsx +309 -0
  94. package/src/components/ui/dialog.tsx +376 -0
  95. package/src/components/ui/dropdown.tsx +399 -0
  96. package/src/components/ui/icons.tsx +50 -0
  97. package/src/components/ui/index.ts +33 -0
  98. package/src/components/ui/input.tsx +350 -0
  99. package/src/components/ui/loader.tsx +9 -0
  100. package/src/components/ui/primitives/button.tsx +292 -0
  101. package/src/components/ui/primitives/input.tsx +422 -0
  102. package/src/components/ui/primitives/modal.tsx +421 -0
  103. package/src/components/ui/primitives/text.tsx +499 -0
  104. package/src/components/ui/resizeable.tsx +169 -0
  105. package/src/components/ui/text.tsx +330 -0
  106. package/src/components/ui/textarea.tsx +34 -0
  107. package/src/components/ui/toast.tsx +203 -0
  108. package/src/components/ui/view.tsx +344 -0
  109. package/src/hooks/index.ts +9 -0
  110. package/src/hooks/useAvatars.tsx +44 -0
  111. package/src/hooks/useCameraToggle.ts +12 -0
  112. package/src/hooks/useKeyboard.tsx +41 -0
  113. package/src/hooks/useKeyboardSlide.ts +12 -0
  114. package/src/hooks/useLivestreamInfo.ts +67 -0
  115. package/src/hooks/useOuterAndInnerDimensions.tsx +32 -0
  116. package/src/hooks/usePlayerDimensions.ts +23 -0
  117. package/src/hooks/useSegmentTiming.tsx +88 -0
  118. package/src/index.tsx +21 -0
  119. package/src/lib/facet.ts +131 -0
  120. package/src/lib/theme/atoms.ts +760 -0
  121. package/src/lib/theme/atoms.types.ts +258 -0
  122. package/src/lib/theme/index.ts +48 -0
  123. package/src/lib/theme/theme.tsx +436 -0
  124. package/src/lib/theme/tokens.ts +409 -0
  125. package/src/lib/utils.ts +132 -0
  126. package/src/livestream-provider/index.tsx +13 -2
  127. package/src/livestream-store/chat.tsx +115 -78
  128. package/src/livestream-store/index.tsx +1 -0
  129. package/src/livestream-store/livestream-state.tsx +3 -0
  130. package/src/livestream-store/livestream-store.tsx +3 -0
  131. package/src/livestream-store/stream-key.tsx +124 -0
  132. package/src/player-store/player-provider.tsx +0 -1
  133. package/src/player-store/player-state.tsx +28 -0
  134. package/src/player-store/player-store.tsx +22 -0
  135. package/src/streamplace-store/block.tsx +29 -0
  136. package/src/streamplace-store/index.tsx +1 -0
  137. package/src/streamplace-store/stream.tsx +262 -0
  138. package/tsconfig.tsbuildinfo +1 -1
@@ -0,0 +1,499 @@
1
+ import { createContext, forwardRef, useContext } from "react";
2
+ import type { ColorValue as RNColorValue } from "react-native";
3
+ import {
4
+ AnimatableNumericValue,
5
+ ColorValue,
6
+ OpaqueColorValue,
7
+ Platform,
8
+ Text as RNText,
9
+ TextProps as RNTextProps,
10
+ TextStyle,
11
+ } from "react-native";
12
+ import { useTheme } from "../../../lib/theme/theme";
13
+ import { typography, type Typography } from "../../../lib/theme/tokens";
14
+
15
+ // Text inheritance context
16
+ interface TextContextValue {
17
+ fontSize?: number;
18
+ fontWeight?: TextStyle["fontWeight"];
19
+ color?: string | RNColorValue | OpaqueColorValue;
20
+ fontFamily?: string;
21
+ lineHeight?: number;
22
+ textAlign?: TextStyle["textAlign"];
23
+ letterSpacing?: number;
24
+ textTransform?: TextStyle["textTransform"];
25
+ textDecorationLine?: TextStyle["textDecorationLine"];
26
+ fontStyle?: TextStyle["fontStyle"];
27
+ opacity?: number | AnimatableNumericValue;
28
+ }
29
+
30
+ export const TextContext = createContext<Partial<TextContextValue> | null>(
31
+ null,
32
+ );
33
+
34
+ export function objectFromObjects(
35
+ arr: Record<string, any>[],
36
+ ): Record<string, any> {
37
+ return Object.assign({}, ...arr);
38
+ }
39
+
40
+ // Text primitive props
41
+ export interface TextPrimitiveProps extends Omit<RNTextProps, "style"> {
42
+ // Typography variants
43
+ variant?:
44
+ | "h1"
45
+ | "h2"
46
+ | "h3"
47
+ | "h4"
48
+ | "h5"
49
+ | "h6"
50
+ | "body1"
51
+ | "body2"
52
+ | "caption"
53
+ | "overline"
54
+ | "subtitle1"
55
+ | "subtitle2";
56
+
57
+ // Size system
58
+ size?: "xs" | "sm" | "base" | "lg" | "xl" | "2xl" | "3xl" | "4xl" | number;
59
+
60
+ // Weight system
61
+ weight?:
62
+ | "thin"
63
+ | "light"
64
+ | "normal"
65
+ | "medium"
66
+ | "semibold"
67
+ | "bold"
68
+ | "extrabold"
69
+ | "black";
70
+
71
+ // Color variants
72
+ color?:
73
+ | "default"
74
+ | "muted"
75
+ | "primary"
76
+ | "secondary"
77
+ | "destructive"
78
+ | "success"
79
+ | "warning"
80
+ | (string & {});
81
+
82
+ // Text alignment
83
+ align?: "left" | "center" | "right" | "justify";
84
+
85
+ // Line height
86
+ leading?: "none" | "tight" | "snug" | "normal" | "relaxed" | "loose" | number;
87
+
88
+ // Letter spacing
89
+ tracking?:
90
+ | "tighter"
91
+ | "tight"
92
+ | "normal"
93
+ | "wide"
94
+ | "wider"
95
+ | "widest"
96
+ | number;
97
+
98
+ // Text transform
99
+ transform?: "none" | "capitalize" | "uppercase" | "lowercase";
100
+
101
+ // Text decoration
102
+ decoration?: "none" | "underline" | "line-through";
103
+
104
+ // Font style
105
+ italic?: boolean;
106
+
107
+ // Opacity
108
+ opacity?: number;
109
+
110
+ // Custom style
111
+ style?: TextStyle | TextStyle[];
112
+
113
+ // Inheritance - whether this component should inherit from parent context
114
+ inherit?: boolean;
115
+
116
+ // Reset inheritance - start fresh context
117
+ reset?: boolean;
118
+ }
119
+
120
+ // Size mapping
121
+ const sizeMap = {
122
+ xs: 12,
123
+ sm: 14,
124
+ base: 16,
125
+ lg: 18,
126
+ xl: 20,
127
+ "2xl": 24,
128
+ "3xl": 30,
129
+ "4xl": 36,
130
+ } as const;
131
+
132
+ // Weight mapping
133
+ const weightMap = {
134
+ thin: "100",
135
+ light: "300",
136
+ normal: "400",
137
+ medium: "500",
138
+ semibold: "600",
139
+ bold: "700",
140
+ extrabold: "800",
141
+ black: "900",
142
+ } as const;
143
+
144
+ // Line height mapping
145
+ const leadingMap = {
146
+ none: 1,
147
+ tight: 1.2,
148
+ snug: 1.3,
149
+ normal: 1.5,
150
+ relaxed: 1.7,
151
+ loose: 2,
152
+ } as const;
153
+
154
+ // Letter spacing mapping
155
+ const trackingMap = {
156
+ tighter: -0.8,
157
+ tight: -0.4,
158
+ normal: 0,
159
+ wide: 0.4,
160
+ wider: 0.8,
161
+ widest: 1.6,
162
+ } as const;
163
+
164
+ // Variant definitions (platform-aware)
165
+ const getVariantStyles = () => {
166
+ // get platform-specific typography
167
+ // iOS, Android, Web (Universal)
168
+ const typographicPlatform = (
169
+ Platform.OS === "ios"
170
+ ? "ios"
171
+ : Platform.OS === "android"
172
+ ? "android"
173
+ : "universal"
174
+ ) as keyof Typography;
175
+ const platformTypography = typography[typographicPlatform] as Record<
176
+ string,
177
+ TextStyle
178
+ >;
179
+
180
+ if (!platformTypography) {
181
+ throw new Error("Platform typography not defined");
182
+ }
183
+
184
+ // Define mapping based on platform
185
+ if (typographicPlatform === "ios") {
186
+ return {
187
+ h1: platformTypography.largeTitle,
188
+ h2: platformTypography.title1,
189
+ h3: platformTypography.title2,
190
+ h4: platformTypography.title3,
191
+ h5: platformTypography.headline,
192
+ h6: platformTypography.headline,
193
+ subtitle1: platformTypography.subhead,
194
+ subtitle2: platformTypography.footnote,
195
+ body1: platformTypography.body,
196
+ body2: platformTypography.callout,
197
+ caption: platformTypography.caption1,
198
+ overline: platformTypography.caption2,
199
+ };
200
+ } else if (typographicPlatform === "android") {
201
+ return {
202
+ h1: platformTypography.headline1,
203
+ h2: platformTypography.headline2,
204
+ h3: platformTypography.headline3,
205
+ h4: platformTypography.headline4,
206
+ h5: platformTypography.headline5,
207
+ h6: platformTypography.headline6,
208
+ subtitle1: platformTypography.subtitle1,
209
+ subtitle2: platformTypography.subtitle2,
210
+ body1: platformTypography.body1,
211
+ body2: platformTypography.body2,
212
+ caption: platformTypography.caption,
213
+ overline: platformTypography.overline,
214
+ };
215
+ } else {
216
+ // universal
217
+ // Map variants to universal sizes
218
+ return {
219
+ h1: platformTypography["4xl"],
220
+ h2: platformTypography["3xl"],
221
+ h3: platformTypography["2xl"],
222
+ h4: platformTypography["xl"],
223
+ h5: platformTypography["lg"],
224
+ h6: platformTypography["base"],
225
+ subtitle1: platformTypography.base,
226
+ subtitle2: platformTypography.sm,
227
+ body1: platformTypography.base,
228
+ body2: platformTypography.sm,
229
+ caption: platformTypography.xs,
230
+ overline: platformTypography.xs,
231
+ };
232
+ }
233
+ };
234
+
235
+ // Text root primitive
236
+ export const TextRoot = forwardRef<RNText, TextPrimitiveProps>(
237
+ (
238
+ {
239
+ variant,
240
+ size,
241
+ weight,
242
+ color,
243
+ align,
244
+ leading,
245
+ tracking,
246
+ transform,
247
+ decoration,
248
+ italic = false,
249
+ opacity,
250
+ style,
251
+ inherit = true,
252
+ reset = false,
253
+ children,
254
+ ...props
255
+ },
256
+ ref,
257
+ ) => {
258
+ const { theme } = useTheme();
259
+ const parentContext = useContext(TextContext);
260
+
261
+ // Get variant styles
262
+ const variantStyles = getVariantStyles() as Record<string, TextStyle>;
263
+
264
+ // Calculate inherited values
265
+ const inheritedContext =
266
+ inherit && !reset && parentContext ? parentContext : {};
267
+
268
+ // Calculate final styles
269
+ const finalStyles: TextStyle = {
270
+ // Start with inherited values
271
+ fontSize: inheritedContext.fontSize,
272
+ fontWeight: inheritedContext.fontWeight,
273
+ //color: inheritedContext.color,
274
+ fontFamily: inheritedContext.fontFamily,
275
+ lineHeight: inheritedContext.lineHeight,
276
+ textAlign: inheritedContext.textAlign,
277
+ letterSpacing: inheritedContext.letterSpacing,
278
+ textTransform: inheritedContext.textTransform,
279
+ textDecorationLine:
280
+ inheritedContext.textDecorationLine as TextStyle["textDecorationLine"],
281
+ fontStyle: inheritedContext.fontStyle,
282
+ opacity: inheritedContext.opacity,
283
+
284
+ // Apply variant styles (these may override inherited)
285
+ ...(variant && variantStyles[variant]),
286
+
287
+ // Apply explicit prop styles (these should override inherited and variant)
288
+
289
+ // Apply size
290
+ ...(size && {
291
+ fontSize: typeof size === "number" ? size : sizeMap[size],
292
+ }),
293
+
294
+ // Apply weight
295
+ ...(weight && {
296
+ fontWeight: weightMap[weight] as TextStyle["fontWeight"],
297
+ }),
298
+
299
+ // Apply color
300
+ ...(color
301
+ ? {
302
+ color:
303
+ color === "default"
304
+ ? theme.colors.text
305
+ : color === "muted"
306
+ ? theme.colors.textMuted
307
+ : color === "primary"
308
+ ? theme.colors.primary
309
+ : color === "secondary"
310
+ ? theme.colors.secondary
311
+ : color === "destructive"
312
+ ? theme.colors.destructive
313
+ : color === "success"
314
+ ? theme.colors.success
315
+ : color === "warning"
316
+ ? theme.colors.warning
317
+ : color || inheritedContext.color, // Custom color string
318
+ }
319
+ : { color: inheritedContext.color || theme.colors.text }),
320
+
321
+ // Apply alignment
322
+ ...(align && {
323
+ textAlign: align,
324
+ }),
325
+
326
+ // Apply line height
327
+ ...(leading && {
328
+ lineHeight: typeof leading === "number" ? leading : leadingMap[leading],
329
+ }),
330
+
331
+ // Apply letter spacing
332
+ ...(tracking && {
333
+ letterSpacing:
334
+ typeof tracking === "number" ? tracking : trackingMap[tracking],
335
+ }),
336
+
337
+ // Apply text transform
338
+ ...(transform &&
339
+ transform !== "none" && {
340
+ textTransform: transform,
341
+ }),
342
+
343
+ // Apply text decoration
344
+ ...(decoration &&
345
+ decoration !== "none" && {
346
+ textDecorationLine: decoration,
347
+ }),
348
+
349
+ // Apply italic
350
+ ...(italic && {
351
+ fontStyle: "italic",
352
+ }),
353
+
354
+ // Apply opacity
355
+ ...(opacity !== undefined && {
356
+ opacity,
357
+ }),
358
+ };
359
+
360
+ finalStyles.color = finalStyles.color as ColorValue;
361
+
362
+ // Create context value for children
363
+ const contextValue: TextContextValue = {
364
+ fontSize:
365
+ typeof finalStyles.fontSize === "number"
366
+ ? finalStyles.fontSize
367
+ : undefined,
368
+ fontWeight: finalStyles.fontWeight,
369
+ color: finalStyles.color || undefined,
370
+ fontFamily:
371
+ typeof finalStyles.fontFamily === "string"
372
+ ? finalStyles.fontFamily
373
+ : undefined,
374
+ lineHeight:
375
+ typeof finalStyles.lineHeight === "number"
376
+ ? finalStyles.lineHeight
377
+ : undefined,
378
+ textAlign: finalStyles.textAlign,
379
+ letterSpacing: finalStyles.letterSpacing as number | undefined,
380
+ textTransform: finalStyles.textTransform,
381
+ textDecorationLine:
382
+ finalStyles.textDecorationLine as TextStyle["textDecorationLine"],
383
+ fontStyle: finalStyles.fontStyle,
384
+ opacity: finalStyles.opacity as number | undefined,
385
+ };
386
+
387
+ return (
388
+ <TextContext.Provider value={contextValue}>
389
+ <RNText ref={ref} style={[finalStyles, style]} {...props}>
390
+ {children}
391
+ </RNText>
392
+ </TextContext.Provider>
393
+ );
394
+ },
395
+ );
396
+
397
+ TextRoot.displayName = "TextRoot";
398
+
399
+ // Text span primitive (inherits from parent but doesn't create new context)
400
+ export const TextSpan = forwardRef<RNText, Omit<TextPrimitiveProps, "reset">>(
401
+ ({ children, ...props }, ref) => {
402
+ return (
403
+ <TextRoot ref={ref as any} inherit={true} {...props}>
404
+ {children}
405
+ </TextRoot>
406
+ );
407
+ },
408
+ );
409
+
410
+ TextSpan.displayName = "TextSpan";
411
+
412
+ // Text block primitive (always creates new context)
413
+ export const TextBlock = forwardRef<RNText, TextPrimitiveProps>(
414
+ ({ children, reset = true, ...props }, ref) => {
415
+ return (
416
+ <TextRoot ref={ref as any} reset={reset} {...props}>
417
+ {children}
418
+ </TextRoot>
419
+ );
420
+ },
421
+ );
422
+
423
+ TextBlock.displayName = "TextBlock";
424
+
425
+ // Hook to access current text context
426
+ export function useTextContext(): TextContextValue | null {
427
+ return useContext(TextContext);
428
+ }
429
+
430
+ // Utility function to create text styles
431
+ export function createTextStyle(
432
+ props: Omit<TextPrimitiveProps, "children" | "style" | "ref">,
433
+ ): TextStyle {
434
+ // This is a utility function that can be used to generate styles
435
+ // without rendering a component
436
+ const style: TextStyle = {};
437
+
438
+ if (props.size) {
439
+ style.fontSize =
440
+ typeof props.size === "number" ? props.size : sizeMap[props.size];
441
+ }
442
+
443
+ if (props.weight) {
444
+ style.fontWeight = weightMap[props.weight] as TextStyle["fontWeight"];
445
+ }
446
+
447
+ if (props.align) {
448
+ style.textAlign = props.align;
449
+ }
450
+
451
+ if (props.leading) {
452
+ style.lineHeight =
453
+ typeof props.leading === "number"
454
+ ? props.leading
455
+ : leadingMap[props.leading];
456
+ }
457
+
458
+ if (props.tracking) {
459
+ style.letterSpacing =
460
+ typeof props.tracking === "number"
461
+ ? props.tracking
462
+ : trackingMap[props.tracking];
463
+ }
464
+
465
+ if (props.transform && props.transform !== "none") {
466
+ style.textTransform = props.transform;
467
+ }
468
+
469
+ if (props.decoration && props.decoration !== "none") {
470
+ style.textDecorationLine = props.decoration;
471
+ }
472
+
473
+ if (props.italic) {
474
+ style.fontStyle = "italic";
475
+ }
476
+
477
+ if (props.opacity !== undefined) {
478
+ style.opacity = props.opacity;
479
+ }
480
+
481
+ return style;
482
+ }
483
+
484
+ // Export primitive collection
485
+ export const TextPrimitive: {
486
+ Root: typeof TextRoot;
487
+ Span: typeof TextSpan;
488
+ Block: typeof TextBlock;
489
+ Context: typeof TextContext;
490
+ useContext: typeof useTextContext;
491
+ createStyle: typeof createTextStyle;
492
+ } = {
493
+ Root: TextRoot,
494
+ Span: TextSpan,
495
+ Block: TextBlock,
496
+ Context: TextContext,
497
+ useContext: useTextContext,
498
+ createStyle: createTextStyle,
499
+ };
@@ -0,0 +1,169 @@
1
+ import { ChevronUp } from "lucide-react-native";
2
+ import { ComponentProps } from "react";
3
+ import { Dimensions } from "react-native";
4
+ import {
5
+ Gesture,
6
+ GestureDetector,
7
+ Pressable,
8
+ } from "react-native-gesture-handler";
9
+ import Animated, {
10
+ Extrapolation,
11
+ interpolate,
12
+ useAnimatedStyle,
13
+ useSharedValue,
14
+ withSpring,
15
+ } from "react-native-reanimated";
16
+ import { useSafeAreaInsets } from "react-native-safe-area-context";
17
+ import { useKeyboardSlide } from "../../hooks";
18
+ import { bottom, layout, p, w, zIndex } from "../../lib/theme/atoms";
19
+ import { View } from "./view";
20
+
21
+ const AnimatedView = Animated.createAnimatedComponent(View);
22
+
23
+ const { height: SCREEN_HEIGHT } = Dimensions.get("window");
24
+
25
+ type ResizableChatSheetProps = {
26
+ isPlayerRatioGreater: boolean;
27
+ style?: ComponentProps<typeof AnimatedView>["style"];
28
+ children?: React.ReactNode;
29
+ };
30
+
31
+ const SPRING_CONFIG = { damping: 20, stiffness: 100 };
32
+
33
+ export function Resizable({
34
+ isPlayerRatioGreater,
35
+ style = {},
36
+ children,
37
+ }: ResizableChatSheetProps) {
38
+ const { slideKeyboard } = useKeyboardSlide();
39
+ const { bottom: safeBottom } = useSafeAreaInsets();
40
+ const MAX_HEIGHT = (SCREEN_HEIGHT - safeBottom) * 0.5;
41
+ const MIN_HEIGHT = -(SCREEN_HEIGHT - safeBottom) * 0.2;
42
+ const COLLAPSE_HEIGHT = (SCREEN_HEIGHT - safeBottom) * 0.1;
43
+
44
+ const sheetHeight = useSharedValue(MIN_HEIGHT);
45
+ const startHeight = useSharedValue(MIN_HEIGHT);
46
+
47
+ const panGesture = Gesture.Pan()
48
+ .onStart(() => {
49
+ startHeight.value = sheetHeight.value;
50
+ })
51
+ .onUpdate((event) => {
52
+ let newHeight = startHeight.value - event.translationY;
53
+ if (newHeight > MAX_HEIGHT) newHeight = MAX_HEIGHT;
54
+ if (newHeight < MIN_HEIGHT) newHeight = MIN_HEIGHT;
55
+ sheetHeight.value = newHeight;
56
+
57
+ if (newHeight < COLLAPSE_HEIGHT) {
58
+ sheetHeight.value = withSpring(MIN_HEIGHT, SPRING_CONFIG);
59
+ }
60
+ });
61
+
62
+ const animatedStyle = useAnimatedStyle(() => ({
63
+ height: sheetHeight.value < COLLAPSE_HEIGHT ? 0 : sheetHeight.value,
64
+ opacity: interpolate(
65
+ sheetHeight.value,
66
+ [MIN_HEIGHT, COLLAPSE_HEIGHT],
67
+ [0, 1],
68
+ Extrapolation.CLAMP,
69
+ ),
70
+ transform: [
71
+ {
72
+ translateY:
73
+ slideKeyboard - safeBottom + Math.max(0, -sheetHeight.value),
74
+ },
75
+ ],
76
+ }));
77
+
78
+ const handleAnimatedStyle = useAnimatedStyle(() => ({
79
+ opacity: sheetHeight.value < COLLAPSE_HEIGHT ? 1 : 0,
80
+ transform: [
81
+ {
82
+ translateY: sheetHeight.value < COLLAPSE_HEIGHT ? 0 : withSpring(20),
83
+ },
84
+ ],
85
+ }));
86
+
87
+ return (
88
+ <>
89
+ <Animated.View
90
+ style={[
91
+ handleAnimatedStyle,
92
+ layout.position.absolute,
93
+ bottom[4],
94
+ w.percent[100],
95
+ layout.flex.center,
96
+ zIndex[1],
97
+ { marginBottom: safeBottom },
98
+ ]}
99
+ >
100
+ <Pressable
101
+ onPress={() => {
102
+ sheetHeight.value =
103
+ sheetHeight.value === MIN_HEIGHT
104
+ ? withSpring(MAX_HEIGHT, SPRING_CONFIG)
105
+ : withSpring(MIN_HEIGHT, SPRING_CONFIG);
106
+ }}
107
+ >
108
+ <View
109
+ style={[
110
+ p[1],
111
+ {
112
+ borderRadius: 999,
113
+ backgroundColor: "rgba(0, 0, 0, 0.5)",
114
+ overflow: "hidden",
115
+ },
116
+ ]}
117
+ >
118
+ <ChevronUp
119
+ size={32}
120
+ color="white"
121
+ style={{ marginBottom: 1, marginTop: -1 }}
122
+ />
123
+ </View>
124
+ </Pressable>
125
+ </Animated.View>
126
+ <AnimatedView
127
+ style={[
128
+ animatedStyle,
129
+ isPlayerRatioGreater
130
+ ? layout.position.relative
131
+ : layout.position.absolute,
132
+ bottom[0],
133
+ zIndex[1],
134
+ w.percent[100],
135
+ {
136
+ backgroundColor: "rgba(0, 0, 0, 0.5)",
137
+ overflow: "visible",
138
+ borderTopLeftRadius: 16,
139
+ borderTopRightRadius: 16,
140
+ minWidth: "100%",
141
+ },
142
+ style,
143
+ ]}
144
+ >
145
+ <View style={[layout.flex.row, layout.flex.justifyCenter]}>
146
+ <GestureDetector gesture={panGesture}>
147
+ <View
148
+ hitSlop={{ top: 20, bottom: 20, left: 20, right: 20 }}
149
+ style={[
150
+ w[32],
151
+ {
152
+ height: 6,
153
+ transform: [{ translateY: -10 }],
154
+ backgroundColor: "#eeeeee66",
155
+ alignItems: "center",
156
+ justifyContent: "center",
157
+ borderRadius: 999,
158
+ },
159
+ ]}
160
+ />
161
+ </GestureDetector>
162
+ </View>
163
+ {children}
164
+ </AnimatedView>
165
+ </>
166
+ );
167
+ }
168
+
169
+ Resizable.displayName = "ResizableChatSheet";