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
JavaScript
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