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

224 lines 7.94 kB
import React from 'react'; import { View, Text, StyleSheet, Pressable, } from 'react-native'; import { FontAwesome5 } from '@expo/vector-icons'; /** * ControlButtonsAltComponent - Absolutely positioned overlay control buttons * * ControlButtonsAltComponent is a React Native component that renders control buttons * in an absolute positioned overlay (typically for video controls, settings, etc.). * It supports flexible positioning (9 positions: corners, edges, center) and can be * shown/hidden dynamically. * * **Key Features:** * - Absolute positioning with 9 screen positions * - Horizontal or vertical button arrangement * - Active/inactive state visual feedback * - Show/hide visibility control * - Custom icon support * - Overlay z-index management * - Press feedback animations * * **UI Customization:** * This component can be replaced via `uiOverrides.controlButtonsAltComponent` to * provide a completely custom positioned control overlay. * * @component * @param {ControlButtonsAltComponentOptions} props - Configuration options for the overlay buttons * * @returns {React.ReactNode} Rendered positioned control button overlay * * @example * // Basic usage - Top-right overlay buttons * import React from 'react'; * import { ControlButtonsAltComponent, AltButton } from 'mediasfu-reactnative-expo'; * * function VideoOverlayControls() { * const [showSettings, setShowSettings] = React.useState(false); * * const overlayButtons: AltButton[] = [ * { * name: 'Settings', * icon: 'cog', * onPress: () => setShowSettings(!showSettings), * active: showSettings, * color: '#FFFFFF', * show: true, * }, * { * name: 'Fullscreen', * icon: 'expand', * onPress: () => console.log('Toggle fullscreen'), * color: '#FFFFFF', * show: true, * }, * ]; * * return ( * <ControlButtonsAltComponent * buttons={overlayButtons} * position="right" * location="top" * direction="vertical" * showAspect={true} * /> * ); * } * * @example * // Bottom-center horizontal buttons * <ControlButtonsAltComponent * buttons={bottomControls} * position="middle" * location="bottom" * direction="horizontal" * showAspect={true} * buttonsContainerStyle={{ * backgroundColor: 'rgba(0,0,0,0.7)', * padding: 8, * borderRadius: 8, * }} * /> * * @example * // Conditional visibility with custom styling * <ControlButtonsAltComponent * buttons={menuButtons} * position="right" * location="center" * direction="vertical" * showAspect={isMenuVisible} * buttonsContainerStyle={{ * gap: 12, * padding: 10, * backgroundColor: 'rgba(0,0,0,0.8)', * borderRadius: 12, * }} * /> * * @example * // Using uiOverrides for complete overlay replacement * import { MyCustomOverlayButtons } from './MyCustomOverlayButtons'; * * const sessionConfig = { * credentials: { apiKey: 'your-api-key' }, * uiOverrides: { * controlButtonsAltComponent: { * component: MyCustomOverlayButtons, * injectedProps: { * fadeInOut: true, * autoHideDelay: 3000, * }, * }, * }, * }; * * // MyCustomOverlayButtons.tsx * export const MyCustomOverlayButtons = (props: ControlButtonsAltComponentOptions & { fadeInOut: boolean; autoHideDelay: number }) => { * const [opacity, setOpacity] = React.useState(props.showAspect ? 1 : 0); * * React.useEffect(() => { * if (props.fadeInOut) { * setOpacity(props.showAspect ? 1 : 0); * } * }, [props.showAspect]); * * const positionStyle = { * position: 'absolute' as const, * [props.location === 'top' ? 'top' : props.location === 'bottom' ? 'bottom' : 'top']: props.location === 'center' ? '50%' : 10, * [props.position === 'left' ? 'left' : props.position === 'right' ? 'right' : 'left']: props.position === 'middle' ? '50%' : 10, * }; * * return ( * <View style={{ ...positionStyle, opacity, flexDirection: props.direction === 'vertical' ? 'column' : 'row' }}> * {props.buttons.filter(btn => btn.show !== false).map((button, index) => ( * <Pressable key={index} onPress={button.onPress}> * <FontAwesome5 name={button.active ? button.alternateIcon : button.icon} size={24} color={button.color} /> * </Pressable> * ))} * </View> * ); * }; */ const ControlButtonsAltComponent = ({ buttons, position = 'left', location = 'top', direction = 'horizontal', buttonsContainerStyle, showAspect = false, style, renderContent, renderContainer, }) => { /** * getAlignmentStyle - Computes alignment styles based on position, location, and direction. * @returns {StyleProp<ViewStyle>} - The computed alignment styles. */ const getAlignmentStyle = () => { const alignmentStyle = {}; // Horizontal alignment if (position === 'left' || position === 'right' || position === 'middle') { alignmentStyle.justifyContent = position === 'left' ? 'flex-start' : position === 'right' ? 'flex-end' : 'center'; } // Vertical alignment if (location === 'top' || location === 'bottom' || location === 'center') { alignmentStyle.alignItems = location === 'top' ? 'flex-start' : location === 'bottom' ? 'flex-end' : 'center'; } // Direction of layout if (direction === 'vertical') { alignmentStyle.flexDirection = 'column'; } else { alignmentStyle.flexDirection = 'row'; } return alignmentStyle; }; const dimensions = { width: 0, height: 0 }; const defaultContent = buttons.filter((button) => button.show !== false).map((button, index) => (<Pressable key={index} style={({ pressed }) => [ styles.buttonContainer, { backgroundColor: pressed ? button.backgroundColor?.pressed || '#444' : button.backgroundColor?.default || 'transparent', }, direction === 'vertical' && styles.verticalButton, ]} onPress={button.onPress}> {button.icon ? (button.active ? (button.alternateIconComponent ? (button.alternateIconComponent) : button.alternateIcon ? (<FontAwesome5 name={button.alternateIcon} size={14} color={button.inActiveColor || '#ffffff'}/>) : null) : button.iconComponent ? (button.iconComponent) : button.icon ? (<FontAwesome5 name={button.icon} size={14} color={button.inActiveColor || '#ffffff'}/>) : null) : (button.customComponent)} {button.name && (<Text style={[styles.buttonText, { color: button.color || '#ffffff' }]}> {button.name} </Text>)} </Pressable>)); const content = renderContent ? renderContent({ defaultContent, dimensions }) : defaultContent; const defaultContainer = (<View style={[ styles.container, getAlignmentStyle(), buttonsContainerStyle, { display: showAspect ? 'flex' : 'none' }, style, ]}> {content} </View>); return renderContainer ? renderContainer({ defaultContainer, dimensions }) : defaultContainer; }; const styles = StyleSheet.create({ container: { marginVertical: 4, width: '100%', maxWidth: '100%', alignItems: 'center', elevation: 9, zIndex: 9, }, buttonContainer: { alignItems: 'center', justifyContent: 'center', padding: 6, borderRadius: 5, marginHorizontal: 2, minWidth: 32, flexShrink: 1, }, verticalButton: { flexDirection: 'column', }, buttonText: { fontSize: 12, marginTop: 5, }, }); export default ControlButtonsAltComponent; //# sourceMappingURL=ControlButtonsAltComponent.js.map