UNPKG

mediasfu-reactnative-expo

Version:

mediasfu-reactnative-expo – Expo-managed React Native WebRTC SDK for video conferencing, webinars, live streaming, broadcast, screen sharing, whiteboard, chat, recording, live subtitles, translation, and AI agent rooms on iOS, Android, and web. Prebuilt r

248 lines 8.01 kB
// FlexibleVideo.tsx import React, { useEffect, useState } from 'react'; import { View, StyleSheet } from 'react-native'; /** * FlexibleVideo - Video grid layout with screen sharing and annotation support * * FlexibleVideo is a specialized React Native component for displaying video streams * in a flexible grid layout. It extends FlexibleGrid with additional support for * screen sharing overlays and real-time annotation capabilities. * * **Key Features:** * - Dynamic video grid with custom rows/columns * - Aspect ratio preservation for video streams * - Screen sharing overlay (Screenboard) support * - Real-time screen annotation capabilities * - Custom cell dimensions and background colors * - Efficient video stream rendering * * **UI Customization:** * This component can be replaced via `uiOverrides.flexibleVideoComponent` to * provide a completely custom video grid implementation. * * @component * @param {FlexibleVideoOptions} props - Configuration options for the FlexibleVideo component * * @returns {JSX.Element} Rendered video grid with optional screen sharing overlay * * @example * // Basic usage - 2x2 video grid * import React from 'react'; * import { FlexibleVideo, VideoCard } from 'mediasfu-reactnative-expo'; * * function VideoGrid() { * const participants = [p1, p2, p3, p4]; * * const videoComponents = participants.map((p, idx) => ( * <VideoCard * key={idx} * name={p.name} * participant={p} * videoStream={p.stream} * parameters={sessionParams} * /> * )); * * return ( * <FlexibleVideo * customWidth={400} * customHeight={300} * rows={2} * columns={2} * componentsToRender={videoComponents} * showAspect={true} * backgroundColor="#000" * /> * ); * } * * @example * // With screen sharing annotation * <FlexibleVideo * customWidth={800} * customHeight={600} * rows={1} * columns={1} * componentsToRender={[screenShareVideo]} * showAspect={true} * backgroundColor="#1a1a2e" * Screenboard={<ScreenboardComponent />} * annotateScreenStream={true} * localStreamScreen={localScreenStream} * /> * * @example * // Using uiOverrides for complete video grid replacement * import { MyCustomVideoGrid } from './MyCustomVideoGrid'; * * const sessionConfig = { * credentials: { apiKey: 'your-api-key' }, * uiOverrides: { * flexibleVideoComponent: { * component: MyCustomVideoGrid, * injectedProps: { * layout: 'spotlight', * transition: 'smooth', * }, * }, * }, * }; * * // MyCustomVideoGrid.tsx * export const MyCustomVideoGrid = (props: FlexibleVideoOptions & { layout: string; transition: string }) => { * return ( * <View style={{ flex: 1 }}> * {props.layout === 'spotlight' ? ( * <View style={{ flex: 1 }}>{props.componentsToRender[0]}</View> * ) : ( * props.componentsToRender.map((component, idx) => ( * <View key={idx} style={{ width: props.customWidth, height: props.customHeight }}> * {component} * </View> * )) * )} * {props.Screenboard} * </View> * ); * }; */ const FlexibleVideo = ({ customWidth, customHeight, rows, columns, componentsToRender, showAspect = false, backgroundColor = 'transparent', Screenboard, annotateScreenStream = false, localStreamScreen, style, renderContent, renderContainer, }) => { const [key, setKey] = useState(0); const [cardWidth, setCardWidth] = useState(customWidth); const [cardHeight, setCardHeight] = useState(customHeight); const [, setCardTop] = useState(0); const [cardLeft, setCardLeft] = useState(0); const [canvasLeft, setCanvasLeft] = useState(0); useEffect(() => { setKey((prevKey) => prevKey + 1); }, [columns]); useEffect(() => { if (annotateScreenStream && localStreamScreen) { const videoTrack = localStreamScreen.getVideoTracks()[0]; const videoSettings = videoTrack.getSettings(); const videoHeight = videoSettings.height || customHeight; const videoWidth = videoSettings.width || customWidth; setCardWidth(videoWidth); setCardHeight(videoHeight); setCardTop(Math.floor((customHeight - videoHeight) / 2)); setCardLeft(Math.floor((customWidth - videoWidth) / 2)); setCanvasLeft(cardLeft < 0 ? cardLeft : 0); } else { setCardWidth(customWidth); setCardHeight(customHeight); setCardTop(0); setCardLeft(0); setCanvasLeft(0); } }, [ customWidth, customHeight, localStreamScreen, annotateScreenStream, cardLeft, ]); /** * Renders the grid layout based on the number of rows and columns. * * @returns {React.ReactNode[]} Array of React elements representing the grid. */ const renderGrid = () => { const grid = []; for (let row = 0; row < rows; row++) { const rowComponents = []; for (let col = 0; col < columns; col++) { const index = row * columns + col; const component = componentsToRender[index]; rowComponents.push(<View key={col} style={[ styles.gridItem, { width: cardWidth, height: cardHeight, backgroundColor, margin: 1, padding: 0, borderRadius: 0, left: cardLeft, }, ]}> {component} </View>); } grid.push(<View key={row} style={styles.rowContainer}> {rowComponents} </View>); } return grid; }; const dimensions = { width: cardWidth * columns, height: cardHeight * rows, }; const defaultContent = (<> {renderGrid()} {Screenboard && (<View style={[ styles.screenboardOverlay, { top: 0, left: canvasLeft, width: cardWidth, height: cardHeight, backgroundColor: 'rgba(0, 0, 0, 0.005)', zIndex: 2, }, ]}> {Screenboard} </View>)} </>); const content = renderContent ? renderContent({ defaultContent, dimensions }) : defaultContent; const defaultContainer = (<View key={key} style={[ styles.gridContainer, { padding: 0, flex: 1, margin: 0, position: 'relative', display: showAspect ? 'flex' : 'none', maxWidth: customWidth, overflow: 'hidden', left: cardLeft > 0 ? cardLeft : 0, }, style, ]}> {content} </View>); return renderContainer ? renderContainer({ defaultContainer, dimensions }) : defaultContainer; }; export default FlexibleVideo; /** * Stylesheet for the FlexibleVideo component. */ const styles = StyleSheet.create({ gridContainer: { // Additional container styles can be added here if needed }, rowContainer: { flexDirection: 'row', }, gridItem: { flex: 1, margin: 1, padding: 0, borderRadius: 0, }, screenboardOverlay: { position: 'absolute', top: 0, left: 0, // width and height are set dynamically via inline styles backgroundColor: 'rgba(0, 0, 0, 0.005)', zIndex: 2, // Additional overlay styles can be added here }, }); //# sourceMappingURL=FlexibleVideo.js.map