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

259 lines 8.84 kB
// ControlButtonsComponent.tsx import React from 'react'; import { View, Text, StyleSheet, Pressable, } from 'react-native'; import { FontAwesome5 } from "@expo/vector-icons"; /** * ControlButtonsComponent - Flexible control button bar for meeting actions * * ControlButtonsComponent is a React Native component that renders a customizable * row or column of control buttons (mute, video, screen share, etc.). Each button * supports active/inactive states, custom icons, disabled states, and press feedback. * * **Key Features:** * - Horizontal or vertical button arrangement * - Active/inactive state visual feedback * - Custom icon support (FontAwesome5 or custom components) * - Pressed state animations * - Disabled button handling * - Flexible alignment options * - Show/hide individual buttons * * **UI Customization:** * This component can be replaced via `uiOverrides.controlButtonsComponent` to * provide a completely custom control button bar. * * @component * @param {ControlButtonsComponentOptions} props - Configuration options for the control buttons * * @returns {JSX.Element} Rendered control button bar * * @example * // Basic usage - Horizontal button bar * import React from 'react'; * import { ControlButtonsComponent, Button } from 'mediasfu-reactnative-expo'; * * function MeetingControls() { * const [isMuted, setIsMuted] = React.useState(false); * const [isVideoOff, setIsVideoOff] = React.useState(false); * * const buttons: Button[] = [ * { * name: 'Mic', * icon: 'microphone', * alternateIcon: 'microphone-slash', * active: isMuted, * onPress: () => setIsMuted(!isMuted), * activeColor: '#FF0000', * inActiveColor: '#FFFFFF', * }, * { * name: 'Video', * icon: 'video', * alternateIcon: 'video-slash', * active: isVideoOff, * onPress: () => setIsVideoOff(!isVideoOff), * activeColor: '#FF0000', * inActiveColor: '#FFFFFF', * }, * { * name: 'Leave', * icon: 'phone', * onPress: () => console.log('Leave meeting'), * backgroundColor: { default: '#FF0000', pressed: '#CC0000' }, * color: '#FFFFFF', * }, * ]; * * return ( * <ControlButtonsComponent * buttons={buttons} * alignment="center" * buttonBackgroundColor={{ default: '#333333', pressed: '#555555' }} * vertical={false} * /> * ); * } * * @example * // Vertical button bar with custom styling * <ControlButtonsComponent * buttons={controlButtons} * alignment="flex-start" * vertical={true} * buttonsContainerStyle={{ * gap: 10, * padding: 8, * backgroundColor: 'rgba(0,0,0,0.7)', * borderRadius: 8, * }} * /> * * @example * // With custom icon components * const customButtons: Button[] = [ * { * name: 'Custom', * customComponent: <MyCustomButtonComponent />, * onPress: () => console.log('Custom pressed'), * }, * { * name: 'Icon', * iconComponent: <CustomIcon name="custom" />, * alternateIconComponent: <CustomIcon name="custom-alt" />, * active: isActive, * onPress: toggleActive, * }, * ]; * * <ControlButtonsComponent * buttons={customButtons} * alignment="space-evenly" * /> * * @example * // Using uiOverrides for complete control bar replacement * import { MyCustomControlButtons } from './MyCustomControlButtons'; * * const sessionConfig = { * credentials: { apiKey: 'your-api-key' }, * uiOverrides: { * controlButtonsComponent: { * component: MyCustomControlButtons, * injectedProps: { * theme: 'modern', * showLabels: true, * }, * }, * }, * }; * * // MyCustomControlButtons.tsx * export const MyCustomControlButtons = (props: ControlButtonsComponentOptions & { theme: string; showLabels: boolean }) => { * return ( * <View style={{ flexDirection: props.vertical ? 'column' : 'row', gap: 12 }}> * {props.buttons.filter(btn => btn.show !== false).map((button, index) => ( * <Pressable * key={index} * onPress={button.onPress} * disabled={button.disabled} * style={{ * padding: 12, * borderRadius: props.theme === 'modern' ? 24 : 8, * backgroundColor: button.active ? '#007bff' : '#e0e0e0', * }} * > * {button.customComponent || ( * <FontAwesome5 * name={button.active ? button.alternateIcon : button.icon} * size={20} * color={button.active ? button.activeColor : button.inActiveColor} * /> * )} * {props.showLabels && <Text>{button.name}</Text>} * </Pressable> * ))} * </View> * ); * }; */ const ControlButtonsComponent = ({ buttons, buttonBackgroundColor, alignment = 'flex-start', vertical = false, buttonsContainerStyle, style, renderContent, renderContainer, }) => { /** * getAlignmentStyle - Computes alignment styles based on alignment prop. * @returns {StyleProp<ViewStyle>} The computed alignment styles. */ const getAlignmentStyle = () => { const alignmentStyle = {}; switch (alignment) { case 'center': alignmentStyle.justifyContent = 'center'; break; case 'flex-end': alignmentStyle.justifyContent = 'flex-end'; break; case 'space-between': alignmentStyle.justifyContent = 'space-between'; break; case 'space-around': alignmentStyle.justifyContent = 'space-around'; break; case 'space-evenly': alignmentStyle.justifyContent = 'space-evenly'; break; case 'flex-start': default: alignmentStyle.justifyContent = 'flex-start'; break; } return alignmentStyle; }; const dimensions = { width: 0, height: 0 }; // Dynamic sizing based on button count const defaultContent = buttons.filter((button) => button.show !== false).map((button, index) => { const iconNode = button.icon ? (button.active ? (button.alternateIconComponent ? (button.alternateIconComponent) : button.alternateIcon ? (<FontAwesome5 name={button.alternateIcon} size={24} color={button.activeColor || '#ffffff'}/>) : null) : button.iconComponent ? (button.iconComponent) : button.icon ? (<FontAwesome5 name={button.icon} size={24} color={button.inActiveColor || '#ffffff'}/>) : null) : (button.customComponent); return (<Pressable key={index} style={({ pressed }) => [ styles.buttonContainer, { backgroundColor: pressed ? buttonBackgroundColor?.pressed || '#444' : buttonBackgroundColor?.default || 'transparent', }, vertical && styles.verticalButton, ]} onPress={button.onPress} disabled={button.disabled} accessibilityRole="button" accessibilityLabel={button.accessibilityLabel || button.name}> <View style={styles.buttonContent}> {iconNode} {button.name && (<Text numberOfLines={1} style={[styles.buttonText, { color: button.color || '#ffffff' }]}> {button.name} </Text>)} </View> </Pressable>); }); const content = renderContent ? renderContent({ defaultContent, dimensions }) : defaultContent; const defaultContainer = (<View style={[ styles.container, getAlignmentStyle(), buttonsContainerStyle, { display: 'flex' }, style, ]}> {content} </View>); return renderContainer ? renderContainer({ defaultContainer, dimensions }) : defaultContainer; }; const styles = StyleSheet.create({ container: { flexDirection: 'row', marginVertical: 6, width: '100%', maxWidth: '100%', alignItems: 'center', }, buttonContainer: { alignItems: 'center', justifyContent: 'center', paddingVertical: 6, paddingHorizontal: 8, borderRadius: 5, marginHorizontal: 2, minWidth: 32, flexShrink: 0, }, buttonContent: { flexDirection: 'row', alignItems: 'center', justifyContent: 'center', maxWidth: '100%', }, verticalButton: { flexDirection: 'column', }, buttonText: { fontSize: 12, marginLeft: 6, lineHeight: 14, }, }); export default ControlButtonsComponent; //# sourceMappingURL=ControlButtonsComponent.js.map