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
226 lines • 7.78 kB
JavaScript
// SubAspectComponent.tsx
import React, { useState, useEffect } from 'react';
import { View, StyleSheet, Dimensions, } from 'react-native';
/**
* SubAspectComponent - Secondary responsive container for auxiliary content
*
* SubAspectComponent is a React Native component that provides a responsive
* sub-container typically used for secondary content areas (e.g., chat panels,
* participant lists, control bars). It calculates dimensions based on window size
* and control visibility, automatically adjusting on resize/rotation.
*
* **Key Features:**
* - Responsive dimension calculation with fractional sizing
* - Control visibility-based height adjustment
* - Automatic window resize/rotation handling
* - Custom background color support
* - Flexible positioning for auxiliary content
* - Advanced render override hooks
*
* **UI Customization:**
* This component can be replaced via `uiOverrides.subAspectComponent` to
* provide a completely custom secondary container.
*
* @component
* @param {SubAspectComponentOptions} props - Configuration options for the sub-aspect container
*
* @returns {JSX.Element} Rendered responsive sub-aspect container
*
* @example
* // Basic usage - Bottom control bar area
* import React from 'react';
* import { SubAspectComponent } from 'mediasfu-reactnative-expo';
*
* function ControlBarArea() {
* return (
* <SubAspectComponent
* backgroundColor="#2c2c2c"
* showControls={true}
* containerWidthFraction={1.0}
* containerHeightFraction={0.1}
* defaultFractionSub={0}
* >
* <ControlButtons />
* </SubAspectComponent>
* );
* }
*
* @example
* // Side panel with custom sizing
* <SubAspectComponent
* backgroundColor="#f5f5f5"
* showControls={true}
* containerWidthFraction={0.25}
* containerHeightFraction={0.8}
* defaultFractionSub={0.05}
* >
* <ParticipantsSidebar />
* </SubAspectComponent>
*
* @example
* // With custom content renderer (add header)
* <SubAspectComponent
* backgroundColor="white"
* containerWidthFraction={0.3}
* containerHeightFraction={0.7}
* renderContent={({ defaultContent, dimensions }) => (
* <>
* <View style={{ padding: 10, borderBottomWidth: 1, borderColor: '#ccc' }}>
* <Text style={{ fontWeight: 'bold' }}>Chat Panel</Text>
* </View>
* {defaultContent}
* </>
* )}
* >
* <ChatMessages />
* </SubAspectComponent>
*
* @example
* // Using uiOverrides for complete sub-aspect replacement
* import { MyCustomSubAspect } from './MyCustomSubAspect';
*
* const sessionConfig = {
* credentials: { apiKey: 'your-api-key' },
* uiOverrides: {
* subAspectComponent: {
* component: MyCustomSubAspect,
* injectedProps: {
* collapsible: true,
* minHeight: 50,
* },
* },
* },
* };
*
* // MyCustomSubAspect.tsx
* export const MyCustomSubAspect = (props: SubAspectComponentOptions & { collapsible: boolean; minHeight: number }) => {
* const [collapsed, setCollapsed] = React.useState(false);
* const [dimensions, setDimensions] = React.useState({ width: 0, height: 0 });
*
* React.useEffect(() => {
* const updateDimensions = () => {
* const { width, height } = Dimensions.get('window');
* const containerHeight = collapsed ? props.minHeight : height * (props.containerHeightFraction || 1);
* setDimensions({
* width: width * (props.containerWidthFraction || 1),
* height: containerHeight,
* });
* };
* const subscription = Dimensions.addEventListener('change', updateDimensions);
* updateDimensions();
* return () => subscription?.remove();
* }, [collapsed, props.containerWidthFraction, props.containerHeightFraction]);
*
* return (
* <View style={{
* width: dimensions.width,
* height: dimensions.height,
* backgroundColor: props.backgroundColor,
* }}>
* {props.collapsible && (
* <TouchableOpacity onPress={() => setCollapsed(!collapsed)}>
* <Text>{collapsed ? '▲ Expand' : '▼ Collapse'}</Text>
* </TouchableOpacity>
* )}
* {!collapsed && props.children}
* </View>
* );
* };
*/
const SubAspectComponent = ({ backgroundColor, children, showControls = true, containerWidthFraction = 1.0, // Default to full width if not provided
containerHeightFraction = 1.0, // Default to full height if not provided
defaultFractionSub = 0.0, style, renderContent, renderContainer, }) => {
// Calculate sub-aspect fraction based on showControls
const subAspectFraction = showControls ? defaultFractionSub : 0.0;
// State to store calculated aspect styles
const [aspectStyles, setAspectStyles] = useState({
height: showControls
? containerHeightFraction * Dimensions.get('window').height * subAspectFraction
: 0,
width: containerWidthFraction
? containerWidthFraction * Dimensions.get('window').width
: Dimensions.get('window').width,
display: showControls ? 'flex' : 'none',
});
/**
* Updates the aspect styles based on current window dimensions and props.
*
* @param {ScaledSize} window - The new window dimensions.
*/
const updateAspectStyles = (window) => {
setAspectStyles({
height: showControls
? containerHeightFraction * window.height * subAspectFraction
: 0,
width: containerWidthFraction
? containerWidthFraction * window.width
: window.width,
display: showControls ? 'flex' : 'none',
});
};
// Effect to handle dimension changes
useEffect(() => {
// Handler for dimension changes
const handleChange = ({ window }) => {
updateAspectStyles(window);
};
// Initial setup
const initialWindow = Dimensions.get('window');
updateAspectStyles(initialWindow);
// Add event listener for dimension changes
const subscription = Dimensions.addEventListener('change', handleChange);
// Cleanup listener on component unmount
return () => {
if (subscription?.remove) {
subscription.remove();
}
else {
// For React Native versions < 0.65
subscription.remove();
}
};
// Dependencies include all props that affect aspect styles
}, [
showControls,
containerWidthFraction,
containerHeightFraction,
defaultFractionSub,
subAspectFraction,
]);
// Extract dimensions from aspectStyles
const styleObj = aspectStyles;
const dimensions = {
width: typeof styleObj.width === 'number' ? styleObj.width : 0,
height: typeof styleObj.height === 'number' ? styleObj.height : 0,
};
const defaultContent = children;
const content = renderContent
? renderContent({ defaultContent, dimensions })
: defaultContent;
const defaultContainer = (<View style={[
styles.subAspectContainer,
{ backgroundColor },
aspectStyles,
style,
]}>
{content}
</View>);
return renderContainer
? renderContainer({ defaultContainer, dimensions })
: defaultContainer;
};
export default SubAspectComponent;
/**
* Stylesheet for the SubAspectComponent.
*/
const styles = StyleSheet.create({
subAspectContainer: {
position: 'absolute',
bottom: 0,
margin: 0,
backgroundColor: 'blue',
overflow: 'hidden',
flex: 1,
},
});
//# sourceMappingURL=SubAspectComponent.js.map