@streamplace/components 0.9.12 → 0.10.6
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/badge.d.ts.map +1 -1
- package/dist/components/chat/badge.js +4 -2
- package/dist/components/chat/badge.js.map +1 -1
- package/dist/components/chat/chat-box.d.ts +2 -1
- package/dist/components/chat/chat-box.d.ts.map +1 -1
- package/dist/components/chat/chat-box.js +1 -1
- package/dist/components/chat/chat-box.js.map +1 -1
- package/dist/components/chat/chat-message.d.ts.map +1 -1
- package/dist/components/chat/chat-message.js +3 -3
- package/dist/components/chat/chat-message.js.map +1 -1
- package/dist/components/chat/chat.d.ts +4 -2
- package/dist/components/chat/chat.d.ts.map +1 -1
- package/dist/components/chat/chat.js +18 -4
- package/dist/components/chat/chat.js.map +1 -1
- package/dist/components/chat/teleport-modal.d.ts.map +1 -1
- package/dist/components/chat/teleport-modal.js +5 -4
- package/dist/components/chat/teleport-modal.js.map +1 -1
- package/dist/components/chat/user-profile-card.d.ts.map +1 -1
- package/dist/components/chat/user-profile-card.js +11 -8
- package/dist/components/chat/user-profile-card.js.map +1 -1
- package/dist/components/error-boundary.d.ts +15 -0
- package/dist/components/error-boundary.d.ts.map +1 -0
- package/dist/components/error-boundary.js +29 -0
- package/dist/components/error-boundary.js.map +1 -0
- package/dist/components/mobile-player/ui/viewer-context-menu.d.ts.map +1 -1
- package/dist/components/mobile-player/ui/viewer-context-menu.js +3 -2
- package/dist/components/mobile-player/ui/viewer-context-menu.js.map +1 -1
- package/dist/components/mobile-player/ui/viewer-loading-overlay.d.ts.map +1 -1
- package/dist/components/mobile-player/ui/viewer-loading-overlay.js +1 -0
- package/dist/components/mobile-player/ui/viewer-loading-overlay.js.map +1 -1
- package/dist/components/mobile-player/video-async.native.d.ts.map +1 -1
- package/dist/components/mobile-player/video-async.native.js +4 -1
- package/dist/components/mobile-player/video-async.native.js.map +1 -1
- package/dist/components/mobile-player/video.d.ts +3 -3
- package/dist/components/mobile-player/video.d.ts.map +1 -1
- package/dist/components/mobile-player/video.js.map +1 -1
- package/dist/components/ui/dropdown.native.d.ts.map +1 -1
- package/dist/components/ui/dropdown.native.js +3 -1
- package/dist/components/ui/dropdown.native.js.map +1 -1
- package/dist/components/ui/icons.js +1 -1
- package/dist/components/ui/icons.js.map +1 -1
- package/dist/components/ui/menu.d.ts +0 -8
- package/dist/components/ui/menu.d.ts.map +1 -1
- package/dist/components/ui/menu.js +1 -35
- package/dist/components/ui/menu.js.map +1 -1
- package/dist/components/ui/primitives/input.d.ts +4 -4
- package/dist/components/ui/primitives/input.d.ts.map +1 -1
- package/dist/components/ui/primitives/input.js +10 -3
- package/dist/components/ui/primitives/input.js.map +1 -1
- package/dist/components/ui/resizeable.d.ts +1 -1
- package/dist/components/ui/resizeable.d.ts.map +1 -1
- package/dist/components/ui/resizeable.js +8 -5
- package/dist/components/ui/resizeable.js.map +1 -1
- package/dist/components/ui/text.d.ts +1 -1
- package/dist/components/ui/toast.js +4 -4
- package/dist/components/ui/toast.js.map +1 -1
- package/dist/context/profile-cache.d.ts.map +1 -1
- package/dist/context/profile-cache.js +2 -1
- package/dist/context/profile-cache.js.map +1 -1
- package/dist/hooks/useSegmentTiming.js +1 -1
- package/dist/hooks/useSegmentTiming.js.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -1
- package/dist/index.js.map +1 -1
- package/dist/lib/facet.js +1 -1
- package/dist/lib/facet.js.map +1 -1
- package/dist/lib/theme/atoms.d.ts +252 -252
- package/dist/lib/theme/theme.js +2 -2
- package/dist/lib/theme/theme.js.map +1 -1
- package/dist/livestream-store/livestream-store.d.ts +2 -2
- package/dist/livestream-store/livestream-store.d.ts.map +1 -1
- package/dist/streamplace-store/index.d.ts +1 -0
- package/dist/streamplace-store/index.d.ts.map +1 -1
- package/dist/streamplace-store/index.js +1 -0
- package/dist/streamplace-store/index.js.map +1 -1
- package/dist/streamplace-store/ingest.d.ts +2 -0
- package/dist/streamplace-store/ingest.d.ts.map +1 -0
- package/dist/streamplace-store/ingest.js +31 -0
- package/dist/streamplace-store/ingest.js.map +1 -0
- package/dist/streamplace-store/stream.d.ts +1 -1
- package/dist/streamplace-store/stream.d.ts.map +1 -1
- package/dist/streamplace-store/streamplace-store.d.ts +3 -2
- package/dist/streamplace-store/streamplace-store.d.ts.map +1 -1
- package/dist/streamplace-store/streamplace-store.js +3 -4
- package/dist/streamplace-store/streamplace-store.js.map +1 -1
- package/dist/streamplace-store/user.d.ts +1 -1
- package/dist/streamplace-store/user.d.ts.map +1 -1
- package/dist/streamplace-store/xrpc.js +4 -4
- package/dist/streamplace-store/xrpc.js.map +1 -1
- package/node-compile-cache/v22.15.0-x64-efe9a9df-0/37be0eec +0 -0
- package/package.json +19 -18
- package/src/components/chat/badge.tsx +4 -2
- package/src/components/chat/chat-box.tsx +2 -0
- package/src/components/chat/chat-message.tsx +4 -5
- package/src/components/chat/chat.tsx +31 -4
- package/src/components/chat/teleport-modal.tsx +4 -3
- package/src/components/chat/user-profile-card.tsx +20 -8
- package/src/components/error-boundary.tsx +42 -0
- package/src/components/mobile-player/ui/viewer-context-menu.tsx +3 -2
- package/src/components/mobile-player/ui/viewer-loading-overlay.tsx +1 -0
- package/src/components/mobile-player/video-async.native.tsx +3 -1
- package/src/components/mobile-player/video.tsx +7 -5
- package/src/components/ui/dropdown.native.tsx +5 -1
- package/src/components/ui/icons.tsx +1 -1
- package/src/components/ui/menu.tsx +56 -62
- package/src/components/ui/primitives/input.tsx +18 -9
- package/src/components/ui/resizeable.tsx +11 -6
- package/src/components/ui/toast.tsx +1 -1
- package/src/context/profile-cache.tsx +7 -1
- package/src/hooks/useSegmentTiming.tsx +1 -1
- package/src/index.tsx +2 -0
- package/src/lib/facet.ts +1 -1
- package/src/lib/theme/theme.tsx +1 -1
- package/src/streamplace-store/index.tsx +1 -0
- package/src/streamplace-store/ingest.tsx +32 -0
- package/src/streamplace-store/streamplace-store.tsx +11 -4
- package/src/streamplace-store/xrpc.tsx +1 -1
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { ProfileViewBasic } from "@atproto/api/dist/client/types/app/bsky/actor/defs";
|
|
2
2
|
import { TriggerRef } from "@rn-primitives/dropdown-menu";
|
|
3
|
+
import { Image } from "expo-image";
|
|
3
4
|
import {
|
|
4
5
|
createContext,
|
|
5
6
|
useCallback,
|
|
@@ -9,7 +10,7 @@ import {
|
|
|
9
10
|
useRef,
|
|
10
11
|
useState,
|
|
11
12
|
} from "react";
|
|
12
|
-
import {
|
|
13
|
+
import { Platform, Pressable, View } from "react-native";
|
|
13
14
|
import { ChatMessageViewHydrated } from "streamplace";
|
|
14
15
|
import { useAvatars } from "../../hooks/useAvatars";
|
|
15
16
|
import { useLivestreamStore } from "../../livestream-store";
|
|
@@ -62,8 +63,9 @@ export const ProfileCardProvider = ({
|
|
|
62
63
|
children: React.ReactNode;
|
|
63
64
|
}) => {
|
|
64
65
|
const [openUri, setOpenUri] = useState<string | null>(null);
|
|
66
|
+
const value = useMemo(() => ({ openUri, setOpenUri }), [openUri]);
|
|
65
67
|
return (
|
|
66
|
-
<OpenCardContext.Provider value={
|
|
68
|
+
<OpenCardContext.Provider value={value}>
|
|
67
69
|
{children}
|
|
68
70
|
</OpenCardContext.Provider>
|
|
69
71
|
);
|
|
@@ -73,17 +75,14 @@ const BadgeRow = ({
|
|
|
73
75
|
streamer,
|
|
74
76
|
badge,
|
|
75
77
|
serviceDid,
|
|
78
|
+
issuerProfiles,
|
|
76
79
|
}: {
|
|
77
80
|
badge: NonNullable<ChatMessageViewHydrated["badges"]>[number];
|
|
78
81
|
serviceDid: string;
|
|
79
82
|
streamer?: ProfileViewBasic;
|
|
83
|
+
issuerProfiles: ReturnType<typeof useAvatars>;
|
|
80
84
|
}) => {
|
|
81
85
|
const isServiceIssued = badge.issuer === serviceDid;
|
|
82
|
-
const issuerDids = useMemo(
|
|
83
|
-
() => (isServiceIssued ? [] : [badge.issuer]),
|
|
84
|
-
[isServiceIssued, badge.issuer],
|
|
85
|
-
);
|
|
86
|
-
const issuerProfiles = useAvatars(issuerDids);
|
|
87
86
|
const meta = BADGE_META[badge.badgeType];
|
|
88
87
|
|
|
89
88
|
if (!meta) return null;
|
|
@@ -149,7 +148,19 @@ export const UserProfileCard = ({
|
|
|
149
148
|
const thisRef = useRef<TriggerRef>(null);
|
|
150
149
|
const [hovered, setHovered] = useState(false);
|
|
151
150
|
|
|
152
|
-
const
|
|
151
|
+
const issuerDids = useMemo(
|
|
152
|
+
() =>
|
|
153
|
+
badges?.map((b) => b.issuer).filter((did) => did && did !== serviceDid) ??
|
|
154
|
+
[],
|
|
155
|
+
[badges, serviceDid],
|
|
156
|
+
);
|
|
157
|
+
|
|
158
|
+
const allDids = useMemo(
|
|
159
|
+
() => (author.did ? [author.did, ...issuerDids] : issuerDids),
|
|
160
|
+
[author.did, issuerDids],
|
|
161
|
+
);
|
|
162
|
+
|
|
163
|
+
const profiles = useAvatars(allDids);
|
|
153
164
|
const profile = profiles[author.did];
|
|
154
165
|
|
|
155
166
|
useEffect(() => {
|
|
@@ -273,6 +284,7 @@ export const UserProfileCard = ({
|
|
|
273
284
|
badge={badge}
|
|
274
285
|
serviceDid={serviceDid}
|
|
275
286
|
streamer={streamer}
|
|
287
|
+
issuerProfiles={profiles}
|
|
276
288
|
/>
|
|
277
289
|
))}
|
|
278
290
|
</View>
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
import { Text, View } from "react-native";
|
|
3
|
+
|
|
4
|
+
type ErrorBoundaryProps = {
|
|
5
|
+
children: React.ReactNode;
|
|
6
|
+
};
|
|
7
|
+
|
|
8
|
+
type ErrorBoundaryState = {
|
|
9
|
+
hasError: boolean;
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
export class ErrorBoundary extends React.Component<
|
|
13
|
+
ErrorBoundaryProps,
|
|
14
|
+
ErrorBoundaryState
|
|
15
|
+
> {
|
|
16
|
+
constructor(props: ErrorBoundaryProps) {
|
|
17
|
+
super(props);
|
|
18
|
+
this.state = { hasError: false };
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
static getDerivedStateFromError(error: any): ErrorBoundaryState {
|
|
22
|
+
// Update state so the next render will show the fallback UI.
|
|
23
|
+
return { hasError: true };
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
componentDidCatch(error: any, info: any) {
|
|
27
|
+
console.error("<ErrorBoundary> caught:", error);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
render() {
|
|
31
|
+
if (this.state.hasError) {
|
|
32
|
+
// You can render any custom fallback UI
|
|
33
|
+
return (
|
|
34
|
+
<View>
|
|
35
|
+
<Text>Error</Text>
|
|
36
|
+
</View>
|
|
37
|
+
);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
return this.props.children;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { useRootContext } from "@rn-primitives/dropdown-menu";
|
|
2
|
+
import { Image } from "expo-image";
|
|
2
3
|
import { Cog } from "lucide-react-native";
|
|
3
4
|
import { useState } from "react";
|
|
4
|
-
import {
|
|
5
|
+
import { Linking, Platform, Pressable, View } from "react-native";
|
|
5
6
|
import Animated, {
|
|
6
7
|
Easing,
|
|
7
8
|
useAnimatedStyle,
|
|
@@ -161,7 +162,7 @@ export function ContextMenu({
|
|
|
161
162
|
uri: avatars[profile?.did]?.avatar,
|
|
162
163
|
}}
|
|
163
164
|
style={{ width: 42, height: 42, borderRadius: 999 }}
|
|
164
|
-
|
|
165
|
+
contentFit="cover"
|
|
165
166
|
/>
|
|
166
167
|
)}
|
|
167
168
|
<View style={{ flex: 1, minWidth: 0 }}>
|
|
@@ -91,6 +91,9 @@ export function NativeVideo(props?: {
|
|
|
91
91
|
|
|
92
92
|
const handleLayout = useCallback((event: LayoutChangeEvent) => {
|
|
93
93
|
const { width, height } = event.nativeEvent.layout;
|
|
94
|
+
if (dimensions.width === width && dimensions.height === height) {
|
|
95
|
+
return;
|
|
96
|
+
}
|
|
94
97
|
setDimensions({ width, height });
|
|
95
98
|
setPlayerWidth(width);
|
|
96
99
|
setPlayerHeight(height);
|
|
@@ -165,7 +168,6 @@ export function NativeVideo(props?: {
|
|
|
165
168
|
<VideoView
|
|
166
169
|
ref={videoRef}
|
|
167
170
|
player={player}
|
|
168
|
-
allowsFullscreen
|
|
169
171
|
nativeControls={fullscreen}
|
|
170
172
|
onFullscreenEnter={() => {
|
|
171
173
|
setFullscreen(true);
|
|
@@ -36,12 +36,14 @@ function assignVideoRef(
|
|
|
36
36
|
|
|
37
37
|
type VideoProps = {
|
|
38
38
|
url: string;
|
|
39
|
-
videoRef?: React.RefObject<HTMLVideoElement>;
|
|
39
|
+
videoRef?: React.RefObject<HTMLVideoElement | null>;
|
|
40
40
|
objectFit?: "contain" | "cover";
|
|
41
41
|
pictureInPictureEnabled?: boolean;
|
|
42
42
|
};
|
|
43
43
|
|
|
44
|
-
function useVideoDimensions(
|
|
44
|
+
function useVideoDimensions(
|
|
45
|
+
videoRef: React.RefObject<HTMLVideoElement | null>,
|
|
46
|
+
) {
|
|
45
47
|
const [dimensions, setDimensions] = useState({ width: 0, height: 0 });
|
|
46
48
|
|
|
47
49
|
useEffect(() => {
|
|
@@ -133,7 +135,7 @@ const updateEvents = {
|
|
|
133
135
|
|
|
134
136
|
const VideoElement = forwardRef<
|
|
135
137
|
HTMLVideoElement,
|
|
136
|
-
VideoProps & { videoRef?: React.RefObject<HTMLVideoElement> }
|
|
138
|
+
VideoProps & { videoRef?: React.RefObject<HTMLVideoElement | null> }
|
|
137
139
|
>((props, ref) => {
|
|
138
140
|
const x = usePlayerStore((x) => x);
|
|
139
141
|
const url = useStreamplaceStore((x) => x.url);
|
|
@@ -359,7 +361,7 @@ export function HLSPlayer(props: VideoProps) {
|
|
|
359
361
|
}
|
|
360
362
|
|
|
361
363
|
export function WebRTCPlayer(
|
|
362
|
-
props: VideoProps & { videoRef?: React.RefObject<HTMLVideoElement> },
|
|
364
|
+
props: VideoProps & { videoRef?: React.RefObject<HTMLVideoElement | null> },
|
|
363
365
|
) {
|
|
364
366
|
const [webrtcError, setWebrtcError] = useState<string | null>(null);
|
|
365
367
|
const setStatus = usePlayerStore((x) => x.setStatus);
|
|
@@ -432,7 +434,7 @@ export function WebRTCPlayerInner({
|
|
|
432
434
|
width,
|
|
433
435
|
height,
|
|
434
436
|
}: {
|
|
435
|
-
videoRef?: React.RefObject<HTMLVideoElement>;
|
|
437
|
+
videoRef?: React.RefObject<HTMLVideoElement | null>;
|
|
436
438
|
url: string;
|
|
437
439
|
width?: string | number;
|
|
438
440
|
height?: string | number;
|
|
@@ -358,7 +358,11 @@ export const DropdownMenuSubTrigger = forwardRef<
|
|
|
358
358
|
const { icons } = useTheme();
|
|
359
359
|
|
|
360
360
|
React.useEffect(() => {
|
|
361
|
-
if (
|
|
361
|
+
if (
|
|
362
|
+
subMenuContext &&
|
|
363
|
+
subMenuTitle &&
|
|
364
|
+
subMenuContext.title !== subMenuTitle
|
|
365
|
+
) {
|
|
362
366
|
subMenuContext.setTitle(subMenuTitle);
|
|
363
367
|
}
|
|
364
368
|
}, [subMenuContext, subMenuTitle]);
|
|
@@ -1,10 +1,4 @@
|
|
|
1
|
-
import {
|
|
2
|
-
Children,
|
|
3
|
-
cloneElement,
|
|
4
|
-
forwardRef,
|
|
5
|
-
isValidElement,
|
|
6
|
-
ReactNode,
|
|
7
|
-
} from "react";
|
|
1
|
+
import { forwardRef, ReactNode } from "react";
|
|
8
2
|
import { Animated, Platform, View, ViewStyle } from "react-native";
|
|
9
3
|
import { Gesture, GestureDetector } from "react-native-gesture-handler";
|
|
10
4
|
import {
|
|
@@ -285,63 +279,63 @@ export const MenuInfo = forwardRef<View, MenuInfoProps>(
|
|
|
285
279
|
},
|
|
286
280
|
);
|
|
287
281
|
|
|
288
|
-
export interface MenuDraggableGroupProps {
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
}
|
|
282
|
+
// export interface MenuDraggableGroupProps {
|
|
283
|
+
// children: ReactNode;
|
|
284
|
+
// onMove: (fromIndex: number, toIndex: number) => void;
|
|
285
|
+
// onDragEnd: (fromIndex: number, toIndex: number) => void;
|
|
286
|
+
// dragHandle?: ReactNode;
|
|
287
|
+
// style?: ViewStyle;
|
|
288
|
+
// }
|
|
295
289
|
|
|
296
|
-
export const MenuDraggableGroup = forwardRef<View, MenuDraggableGroupProps>(
|
|
297
|
-
|
|
298
|
-
|
|
290
|
+
// export const MenuDraggableGroup = forwardRef<View, MenuDraggableGroupProps>(
|
|
291
|
+
// ({ children, onMove, onDragEnd, dragHandle, style }, ref) => {
|
|
292
|
+
// const { theme } = useTheme();
|
|
299
293
|
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
294
|
+
// const childrenArray = Children.toArray(children);
|
|
295
|
+
// const draggableItems = childrenArray.filter(
|
|
296
|
+
// (child) =>
|
|
297
|
+
// isValidElement(child) &&
|
|
298
|
+
// (child.type === MenuItem || child.type === MenuSeparator),
|
|
299
|
+
// );
|
|
306
300
|
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
301
|
+
// let itemIndex = 0;
|
|
302
|
+
// const enhancedChildren = Children.map(children, (child) => {
|
|
303
|
+
// if (isValidElement(child)) {
|
|
304
|
+
// if (child.type === MenuItem) {
|
|
305
|
+
// const currentIndex = itemIndex;
|
|
306
|
+
// itemIndex++;
|
|
313
307
|
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
308
|
+
// return cloneElement(child, {
|
|
309
|
+
// draggable: true,
|
|
310
|
+
// dragHandle: dragHandle || (child && child.props.dragHandle),
|
|
311
|
+
// _dragIndex: currentIndex,
|
|
312
|
+
// _dragTotalItems: draggableItems.filter(
|
|
313
|
+
// (c) => isValidElement(c) && c.type === MenuItem,
|
|
314
|
+
// ).length,
|
|
315
|
+
// _onDragMove: onMove,
|
|
316
|
+
// _onDragEnd: onDragEnd,
|
|
317
|
+
// } as any);
|
|
318
|
+
// }
|
|
319
|
+
// if (child.type === MenuSeparator) {
|
|
320
|
+
// return child;
|
|
321
|
+
// }
|
|
322
|
+
// }
|
|
323
|
+
// return child;
|
|
324
|
+
// });
|
|
331
325
|
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
);
|
|
326
|
+
// return (
|
|
327
|
+
// <View
|
|
328
|
+
// ref={ref}
|
|
329
|
+
// style={[
|
|
330
|
+
// { backgroundColor: theme.colors.muted + "c0" },
|
|
331
|
+
// Platform.OS === "web" ? [px[1], py[1]] : p[1],
|
|
332
|
+
// gap.all[1],
|
|
333
|
+
// { borderRadius: borderRadius.lg },
|
|
334
|
+
// style,
|
|
335
|
+
// ]}
|
|
336
|
+
// >
|
|
337
|
+
// {enhancedChildren}
|
|
338
|
+
// </View>
|
|
339
|
+
// );
|
|
340
|
+
// },
|
|
341
|
+
// );
|
|
@@ -4,28 +4,29 @@ import {
|
|
|
4
4
|
} from "@gorhom/bottom-sheet";
|
|
5
5
|
import React, { forwardRef } from "react";
|
|
6
6
|
import {
|
|
7
|
-
|
|
7
|
+
BlurEvent,
|
|
8
|
+
FocusEvent,
|
|
8
9
|
Platform,
|
|
9
10
|
StyleSheet,
|
|
10
11
|
Text,
|
|
11
12
|
TextInput,
|
|
12
|
-
TextInputFocusEventData,
|
|
13
13
|
TextInputProps,
|
|
14
14
|
TextProps,
|
|
15
15
|
TouchableOpacity,
|
|
16
16
|
View,
|
|
17
17
|
ViewProps,
|
|
18
18
|
} from "react-native";
|
|
19
|
-
import
|
|
19
|
+
import * as tokens from "../../../lib/theme/tokens";
|
|
20
20
|
|
|
21
21
|
// Base input primitive interface
|
|
22
|
-
export interface InputPrimitiveProps
|
|
22
|
+
export interface InputPrimitiveProps
|
|
23
|
+
extends Omit<TextInputProps, "onChange" | "onFocus" | "onBlur"> {
|
|
23
24
|
error?: boolean;
|
|
24
25
|
disabled?: boolean;
|
|
25
26
|
loading?: boolean;
|
|
26
27
|
onChange?: (text: string) => void;
|
|
27
|
-
onFocus?: (event:
|
|
28
|
-
onBlur?: (event:
|
|
28
|
+
onFocus?: (event: FocusEvent) => void;
|
|
29
|
+
onBlur?: (event: BlurEvent) => void;
|
|
29
30
|
}
|
|
30
31
|
|
|
31
32
|
// Input root primitive - the main TextInput component
|
|
@@ -75,7 +76,7 @@ export const InputRoot = forwardRef<any, InputPrimitiveProps>(
|
|
|
75
76
|
);
|
|
76
77
|
|
|
77
78
|
const handleFocus = React.useCallback(
|
|
78
|
-
(event:
|
|
79
|
+
(event: FocusEvent) => {
|
|
79
80
|
setIsFocused(true);
|
|
80
81
|
if (onFocus) {
|
|
81
82
|
onFocus(event);
|
|
@@ -85,7 +86,7 @@ export const InputRoot = forwardRef<any, InputPrimitiveProps>(
|
|
|
85
86
|
);
|
|
86
87
|
|
|
87
88
|
const handleBlur = React.useCallback(
|
|
88
|
-
(event:
|
|
89
|
+
(event: BlurEvent) => {
|
|
89
90
|
setIsFocused(false);
|
|
90
91
|
if (onBlur) {
|
|
91
92
|
onBlur(event);
|
|
@@ -272,13 +273,21 @@ export const InputAddon = forwardRef<
|
|
|
272
273
|
style,
|
|
273
274
|
];
|
|
274
275
|
|
|
276
|
+
// Filter out null event handlers for TouchableOpacity compatibility
|
|
277
|
+
const { onBlur, onFocus, ...restProps } = props;
|
|
278
|
+
const touchableProps = {
|
|
279
|
+
...restProps,
|
|
280
|
+
...(onBlur !== null && onBlur !== undefined && { onBlur }),
|
|
281
|
+
...(onFocus !== null && onFocus !== undefined && { onFocus }),
|
|
282
|
+
};
|
|
283
|
+
|
|
275
284
|
if (touchable && onPress) {
|
|
276
285
|
return (
|
|
277
286
|
<TouchableOpacity
|
|
278
287
|
ref={ref as React.Ref<React.ComponentRef<typeof TouchableOpacity>>}
|
|
279
288
|
style={addonStyle as any}
|
|
280
289
|
onPress={onPress}
|
|
281
|
-
{...
|
|
290
|
+
{...touchableProps}
|
|
282
291
|
>
|
|
283
292
|
{children}
|
|
284
293
|
</TouchableOpacity>
|
|
@@ -7,12 +7,14 @@ import {
|
|
|
7
7
|
Pressable,
|
|
8
8
|
} from "react-native-gesture-handler";
|
|
9
9
|
import Animated, {
|
|
10
|
+
Easing,
|
|
10
11
|
Extrapolation,
|
|
11
12
|
interpolate,
|
|
12
13
|
runOnJS,
|
|
13
14
|
useAnimatedStyle,
|
|
14
15
|
useSharedValue,
|
|
15
16
|
withSpring,
|
|
17
|
+
withTiming,
|
|
16
18
|
} from "react-native-reanimated";
|
|
17
19
|
import { useSafeAreaInsets } from "react-native-safe-area-context";
|
|
18
20
|
import { useKeyboardSlide } from "../../hooks";
|
|
@@ -23,6 +25,11 @@ const AnimatedView = Animated.createAnimatedComponent(View);
|
|
|
23
25
|
|
|
24
26
|
const { height: SCREEN_HEIGHT } = Dimensions.get("window");
|
|
25
27
|
|
|
28
|
+
const TIMING_CONFIG = {
|
|
29
|
+
duration: 300,
|
|
30
|
+
easing: Easing.inOut(Easing.quad),
|
|
31
|
+
};
|
|
32
|
+
|
|
26
33
|
type ResizableChatSheetProps = {
|
|
27
34
|
startingPercentage?: number;
|
|
28
35
|
isPlayerRatioGreater: boolean;
|
|
@@ -31,8 +38,6 @@ type ResizableChatSheetProps = {
|
|
|
31
38
|
renderAbove?: (isCollapsed: boolean) => React.ReactNode;
|
|
32
39
|
};
|
|
33
40
|
|
|
34
|
-
const SPRING_CONFIG = { damping: 20, stiffness: 100 };
|
|
35
|
-
|
|
36
41
|
export function Resizable({
|
|
37
42
|
startingPercentage,
|
|
38
43
|
isPlayerRatioGreater,
|
|
@@ -56,7 +61,7 @@ export function Resizable({
|
|
|
56
61
|
const targetHeight = startingPercentage
|
|
57
62
|
? startingPercentage * SCREEN_HEIGHT
|
|
58
63
|
: MIN_HEIGHT;
|
|
59
|
-
sheetHeight.value =
|
|
64
|
+
sheetHeight.value = withTiming(targetHeight, TIMING_CONFIG);
|
|
60
65
|
setIsCollapsed(targetHeight < COLLAPSE_HEIGHT);
|
|
61
66
|
}, 1000);
|
|
62
67
|
}, []);
|
|
@@ -73,7 +78,7 @@ export function Resizable({
|
|
|
73
78
|
|
|
74
79
|
const nowCollapsed = newHeight < COLLAPSE_HEIGHT;
|
|
75
80
|
if (nowCollapsed && !wasCollapsed.value) {
|
|
76
|
-
sheetHeight.value =
|
|
81
|
+
sheetHeight.value = withTiming(MIN_HEIGHT, TIMING_CONFIG);
|
|
77
82
|
wasCollapsed.value = true;
|
|
78
83
|
runOnJS(setIsCollapsed)(true);
|
|
79
84
|
} else if (!nowCollapsed && wasCollapsed.value) {
|
|
@@ -139,8 +144,8 @@ export function Resizable({
|
|
|
139
144
|
onPress={() => {
|
|
140
145
|
const isCurrentlyCollapsed = sheetHeight.value === MIN_HEIGHT;
|
|
141
146
|
sheetHeight.value = isCurrentlyCollapsed
|
|
142
|
-
?
|
|
143
|
-
:
|
|
147
|
+
? withTiming(MAX_HEIGHT, TIMING_CONFIG)
|
|
148
|
+
: withTiming(MIN_HEIGHT, TIMING_CONFIG);
|
|
144
149
|
setIsCollapsed(!isCurrentlyCollapsed);
|
|
145
150
|
}}
|
|
146
151
|
>
|
|
@@ -21,7 +21,7 @@ import Animated, {
|
|
|
21
21
|
} from "react-native-reanimated";
|
|
22
22
|
import { useSafeAreaInsets } from "react-native-safe-area-context";
|
|
23
23
|
import { Circle, Svg } from "react-native-svg";
|
|
24
|
-
import { useTheme } from "../../
|
|
24
|
+
import { useTheme } from "../../lib/theme/theme";
|
|
25
25
|
import { Button } from "./button";
|
|
26
26
|
import { Text } from "./text";
|
|
27
27
|
|
|
@@ -3,6 +3,7 @@ import {
|
|
|
3
3
|
createContext,
|
|
4
4
|
useCallback,
|
|
5
5
|
useContext,
|
|
6
|
+
useMemo,
|
|
6
7
|
useRef,
|
|
7
8
|
useState,
|
|
8
9
|
} from "react";
|
|
@@ -85,8 +86,13 @@ export function ProfileCacheProvider({
|
|
|
85
86
|
[flush],
|
|
86
87
|
);
|
|
87
88
|
|
|
89
|
+
const value = useMemo(
|
|
90
|
+
() => ({ profiles, requestProfiles }),
|
|
91
|
+
[profiles, requestProfiles],
|
|
92
|
+
);
|
|
93
|
+
|
|
88
94
|
return (
|
|
89
|
-
<ProfileCacheContext.Provider value={
|
|
95
|
+
<ProfileCacheContext.Provider value={value}>
|
|
90
96
|
{children}
|
|
91
97
|
</ProfileCacheContext.Provider>
|
|
92
98
|
);
|
|
@@ -22,7 +22,7 @@ function getLiveConnectionQuality(
|
|
|
22
22
|
export function useSegmentTiming() {
|
|
23
23
|
const latestSegment = useLivestreamStore((x) => x.segment);
|
|
24
24
|
const [segmentDeltas, setSegmentDeltas] = useState<number[]>([]);
|
|
25
|
-
const prevSegmentRef = useRef
|
|
25
|
+
const prevSegmentRef = useRef(latestSegment);
|
|
26
26
|
const prevTimestampRef = useRef<number | null>(null);
|
|
27
27
|
const ls = useLivestream();
|
|
28
28
|
|
package/src/index.tsx
CHANGED
package/src/lib/facet.ts
CHANGED
|
@@ -95,7 +95,7 @@ export const segmentize = (
|
|
|
95
95
|
const { byteStart, byteEnd } = facet.index;
|
|
96
96
|
const features = facet.features;
|
|
97
97
|
|
|
98
|
-
if (byteStart > byteEnd || features.length === 0) {
|
|
98
|
+
if (byteStart > byteEnd || !features || features.length === 0) {
|
|
99
99
|
continue;
|
|
100
100
|
}
|
|
101
101
|
|
package/src/lib/theme/theme.tsx
CHANGED
|
@@ -18,7 +18,7 @@ import {
|
|
|
18
18
|
} from "./tokens";
|
|
19
19
|
|
|
20
20
|
import { GestureHandlerRootView } from "react-native-gesture-handler";
|
|
21
|
-
import { ToastProvider } from "../../components/ui";
|
|
21
|
+
import { ToastProvider } from "../../components/ui/toast";
|
|
22
22
|
|
|
23
23
|
// Import pairify function for generating theme tokens
|
|
24
24
|
function pairify<T extends Record<string, any>>(
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { PlaceStreamIngestDefs } from "streamplace";
|
|
2
|
+
import { useDID, useStreamplaceStore } from "./streamplace-store";
|
|
3
|
+
import { usePDSAgent } from "./xrpc";
|
|
4
|
+
|
|
5
|
+
export default function useGetIngests() {
|
|
6
|
+
const pdsAgent = usePDSAgent();
|
|
7
|
+
const did = useDID();
|
|
8
|
+
const setIngests = useStreamplaceStore((state) => state.setIngests);
|
|
9
|
+
|
|
10
|
+
return async () => {
|
|
11
|
+
if (!pdsAgent || !did) {
|
|
12
|
+
throw new Error("No PDS agent or DID available");
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
const result = await pdsAgent.place.stream.ingest.getIngestUrls();
|
|
16
|
+
if (!result.success) {
|
|
17
|
+
throw new Error("Failed to get ingests");
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
const ingests = result.data.ingests
|
|
21
|
+
.map((ingest) => {
|
|
22
|
+
if (PlaceStreamIngestDefs.isIngest(ingest)) {
|
|
23
|
+
return ingest;
|
|
24
|
+
}
|
|
25
|
+
console.error("Invalid ingest", ingest);
|
|
26
|
+
return null;
|
|
27
|
+
})
|
|
28
|
+
.filter((ingest) => ingest !== null);
|
|
29
|
+
|
|
30
|
+
setIngests(ingests);
|
|
31
|
+
};
|
|
32
|
+
}
|
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
import { SessionManager } from "@atproto/api/dist/session-manager";
|
|
2
2
|
import { useContext } from "react";
|
|
3
|
-
import {
|
|
3
|
+
import {
|
|
4
|
+
PlaceStreamChatProfile,
|
|
5
|
+
PlaceStreamIngestDefs,
|
|
6
|
+
PlaceStreamLivestream,
|
|
7
|
+
} from "streamplace";
|
|
4
8
|
import { createStore, StoreApi, useStore } from "zustand";
|
|
5
9
|
import storage from "../storage";
|
|
6
10
|
import { StreamplaceContext } from "../streamplace-provider/context";
|
|
@@ -41,6 +45,9 @@ export interface StreamplaceState {
|
|
|
41
45
|
handle: string | null;
|
|
42
46
|
chatProfile: PlaceStreamChatProfile.Record | null;
|
|
43
47
|
|
|
48
|
+
ingests: PlaceStreamIngestDefs.Ingest[] | null;
|
|
49
|
+
setIngests: (ingests: PlaceStreamIngestDefs.Ingest[] | null) => void;
|
|
50
|
+
|
|
44
51
|
// Content metadata state
|
|
45
52
|
contentMetadata: ContentMetadataResult | null;
|
|
46
53
|
setContentMetadata: (metadata: ContentMetadataResult | null) => void;
|
|
@@ -113,7 +120,9 @@ export const makeStreamplaceStore = ({
|
|
|
113
120
|
oauthSession: null,
|
|
114
121
|
handle: null,
|
|
115
122
|
chatProfile: null,
|
|
116
|
-
|
|
123
|
+
ingests: null,
|
|
124
|
+
setIngests: (ingests: PlaceStreamIngestDefs.Ingest[] | null) =>
|
|
125
|
+
set({ ingests: ingests }),
|
|
117
126
|
broadcasterDID: null,
|
|
118
127
|
setBroadcasterDID: (broadcasterDID: string | null) =>
|
|
119
128
|
set({ broadcasterDID }),
|
|
@@ -409,5 +418,3 @@ export const useDanmuSettings = () => {
|
|
|
409
418
|
setDanmuMaxMessages,
|
|
410
419
|
};
|
|
411
420
|
};
|
|
412
|
-
|
|
413
|
-
export { useCreateStreamRecord, useUpdateStreamRecord } from "./stream";
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { useMemo } from "react";
|
|
2
2
|
import { StreamplaceAgent } from "streamplace";
|
|
3
|
-
import { useStreamplaceStore, useUrl } from "
|
|
3
|
+
import { useStreamplaceStore, useUrl } from "./streamplace-store";
|
|
4
4
|
|
|
5
5
|
export function usePDSAgent(): StreamplaceAgent | null {
|
|
6
6
|
const oauthSession = useStreamplaceStore((state) => state.oauthSession);
|