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

275 lines 9.21 kB
import React from "react"; import { View, Text, StyleSheet, Pressable, } from "react-native"; import { FontAwesome5 } from "@expo/vector-icons"; /** * ControlButtonsComponentTouch - Touch-optimized positioned overlay buttons * * ControlButtonsComponentTouch is a React Native component specifically optimized * for touch interfaces. It renders control buttons in an absolute positioned overlay * with enhanced touch targets and press feedback for mobile/tablet devices. * * **Key Features:** * - Touch-optimized button sizing and spacing * - Absolute positioning with 9 screen positions * - Horizontal or vertical button arrangement * - Active/inactive state visual feedback * - Disabled button support * - Enhanced press feedback for mobile * - Show/hide visibility control * - TypeScript-validated icon names * * **UI Customization:** * This component can be replaced via `uiOverrides.controlButtonsComponentTouch` to * provide a completely custom touch-optimized control overlay. * * @component * @param {ControlButtonsComponentTouchOptions} props - Configuration options for touch-optimized buttons * * @returns {JSX.Element} Rendered touch-optimized control button overlay * * @example * // Basic usage - Touch-optimized video controls * import React from 'react'; * import { ControlButtonsComponentTouch, ButtonTouch } from 'mediasfu-reactnative-expo'; * * function TouchVideoControls() { * const [isPlaying, setIsPlaying] = React.useState(false); * const [isMuted, setIsMuted] = React.useState(false); * * const touchButtons: ButtonTouch[] = [ * { * name: 'PlayPause', * icon: 'play', * alternateIcon: 'pause', * active: isPlaying, * onPress: () => setIsPlaying(!isPlaying), * activeColor: '#007bff', * inActiveColor: '#FFFFFF', * show: true, * }, * { * name: 'Mute', * icon: 'volume-up', * alternateIcon: 'volume-mute', * active: isMuted, * onPress: () => setIsMuted(!isMuted), * activeColor: '#FF0000', * inActiveColor: '#FFFFFF', * show: true, * }, * ]; * * return ( * <ControlButtonsComponentTouch * buttons={touchButtons} * position="middle" * location="bottom" * direction="horizontal" * showAspect={true} * buttonsContainerStyle={{ * backgroundColor: 'rgba(0,0,0,0.6)', * padding: 12, * borderRadius: 24, * gap: 16, * }} * /> * ); * } * * @example * // Side panel touch buttons * <ControlButtonsComponentTouch * buttons={sideButtons} * position="right" * location="center" * direction="vertical" * showAspect={true} * buttonsContainerStyle={{ * gap: 16, * padding: 12, * backgroundColor: 'rgba(0,0,0,0.7)', * }} * /> * * @example * // With disabled and conditional buttons * const buttons: ButtonTouch[] = [ * { * name: 'Record', * icon: 'circle', * onPress: startRecording, * disabled: isRecording, * color: '#FF0000', * show: canRecord, * }, * { * name: 'Stop', * icon: 'stop', * onPress: stopRecording, * disabled: !isRecording, * color: '#FFFFFF', * show: canRecord, * }, * ]; * * <ControlButtonsComponentTouch * buttons={buttons} * position="left" * location="top" * direction="horizontal" * showAspect={true} * /> * * @example * // Using uiOverrides for complete touch overlay replacement * import { MyCustomTouchButtons } from './MyCustomTouchButtons'; * * const sessionConfig = { * credentials: { apiKey: 'your-api-key' }, * uiOverrides: { * controlButtonsComponentTouch: { * component: MyCustomTouchButtons, * injectedProps: { * hapticFeedback: true, * minimumTouchSize: 48, * }, * }, * }, * }; * * // MyCustomTouchButtons.tsx * export const MyCustomTouchButtons = (props: ControlButtonsComponentTouchOptions & { hapticFeedback: boolean; minimumTouchSize: number }) => { * const handlePress = (button: ButtonTouch) => { * if (props.hapticFeedback && Platform.OS !== 'web') { * Haptics.impactAsync(Haptics.ImpactFeedbackStyle.Light); * } * button.onPress?.(); * }; * * return ( * <View style={{ flexDirection: props.direction === 'vertical' ? 'column' : 'row' }}> * {props.buttons.filter(btn => btn.show !== false).map((button, index) => ( * <Pressable * key={index} * onPress={() => handlePress(button)} * disabled={button.disabled} * style={{ * minWidth: props.minimumTouchSize, * minHeight: props.minimumTouchSize, * justifyContent: 'center', * alignItems: 'center', * opacity: button.disabled ? 0.5 : 1, * }} * > * <FontAwesome5 * name={button.active ? button.alternateIcon : button.icon} * size={28} * color={button.active ? button.activeColor : button.inActiveColor || button.color} * /> * </Pressable> * ))} * </View> * ); * }; */ const ControlButtonsComponentTouch = ({ 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.map((button, index) => (<Pressable key={index} style={({ pressed }) => [ styles.buttonContainer, { backgroundColor: pressed ? button.backgroundColor?.pressed || button.backgroundColor?.default || "rgba(255, 255, 255, 0.25)" : button.backgroundColor?.default || button.backgroundColor?.pressed || "rgba(255, 255, 255, 0.25)", display: button.show ? "flex" : "none", }, direction === "vertical" && styles.verticalButton, ]} onPress={button.onPress} disabled={button.disabled}> {button.icon ? (button.active ? (button.alternateIconComponent ? (button.alternateIconComponent) : button.alternateIcon ? (<FontAwesome5 name={button.alternateIcon} size={20} color={button.activeColor || "transparent"}/>) : null) : button.iconComponent ? (button.iconComponent) : button.icon ? (<FontAwesome5 name={button.icon} size={20} color={button.inActiveColor || "transparent"}/>) : null) : (button.customComponent)} {button.name && (<Text style={[ styles.buttonText, { color: button.color || "transparent" }, ]}> {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: { position: "absolute", bottom: 0, left: 0, right: 0, marginVertical: 5, zIndex: 9, backgroundColor: "transparent", }, buttonContainer: { alignItems: "center", padding: 10, borderRadius: 5, marginHorizontal: 5, marginVertical: 5, backgroundColor: "transparent", }, verticalButton: { flexDirection: "column", }, buttonText: { fontSize: 14, marginTop: 5, }, }); export default ControlButtonsComponentTouch; //# sourceMappingURL=ControlButtonsComponentTouch.js.map