UNPKG

@100mslive/roomkit-react

Version:

![Banner](https://github.com/100mslive/web-sdks/blob/06c65259912db6ccd8617f2ecb6fef51429251ec/prebuilt-banner.png)

302 lines (291 loc) 9.45 kB
import React, { useCallback, useEffect, useState } from 'react'; import { useMedia } from 'react-use'; import { ChevronLeftIcon, CrossIcon, GridFourIcon, NotificationsIcon, SettingsIcon } from '@100mslive/react-icons'; import { HorizontalDivider } from '../../../Divider'; import { IconButton } from '../../../IconButton'; import { Box, Flex } from '../../../Layout'; import { Dialog } from '../../../Modal'; import { Sheet } from '../../../Sheet'; import { Tabs } from '../../../Tabs'; import { Text } from '../../../Text'; import { config as cssConfig } from '../../../Theme'; import DeviceSettings from './DeviceSettings'; import { LayoutSettings } from './LayoutSettings'; import { NotificationSettings } from './NotificationSettings'; import { settingContent } from './common'; const settingsList = [ { tabName: 'devices', title: 'Device Settings', icon: SettingsIcon, content: DeviceSettings, }, { tabName: 'notifications', title: 'Notifications', icon: NotificationsIcon, content: NotificationSettings, }, { tabName: 'layout', title: 'Layout', icon: GridFourIcon, content: LayoutSettings, }, ]; const SettingsModal = ({ open, onOpenChange, screenType, children = <></> }) => { const mediaQueryLg = cssConfig.media.md; const isMobile = useMedia(mediaQueryLg); const [showSetting, setShowSetting] = useState(() => settingsList.reduce((obj, { tabName }) => ({ ...obj, [tabName]: true }), {}), ); const hideSettingByTabName = useCallback( key => hide => setShowSetting(prev => ({ ...prev, [key]: !hide })), [setShowSetting], ); useEffect(() => { if (screenType === 'hls_live_streaming') { hideSettingByTabName('layout')(true); } }, [screenType, hideSettingByTabName]); const [selection, setSelection] = useState(() => Object.keys(showSetting).find(key => showSetting[key]) ?? ''); const resetSelection = useCallback(() => { setSelection(''); }, []); useEffect(() => { if (isMobile) { setSelection(''); } else { const firstNotHiddenTabName = Object.keys(showSetting).find(key => showSetting[key]) ?? ''; setSelection(firstNotHiddenTabName); } }, [isMobile, showSetting]); return isMobile ? ( <MobileSettingModal open={open} onOpenChange={onOpenChange} selection={selection} setSelection={setSelection} showSetting={showSetting} hideSettingByTabName={hideSettingByTabName} resetSelection={resetSelection} > {children} </MobileSettingModal> ) : ( <DesktopSettingModal open={open} onOpenChange={onOpenChange} selection={selection} setSelection={setSelection} showSetting={showSetting} hideSettingByTabName={hideSettingByTabName} resetSelection={resetSelection} > {children} </DesktopSettingModal> ); }; const MobileSettingModal = ({ open, onOpenChange, selection, setSelection, showSetting, hideSettingByTabName, resetSelection, children = <></>, }) => { return ( <Sheet.Root open={open} onOpenChange={onOpenChange}> <Sheet.Trigger asChild>{children}</Sheet.Trigger> <Sheet.Content css={{ bg: '$surface_dim', overflowY: 'auto', }} > <Sheet.Title css={{ py: '$10', px: '$8', alignItems: 'center' }}> <Flex direction="row" justify="between" css={{ w: '100%' }}> {!selection ? ( <Text variant="h6" css={{ display: 'flex' }}> Settings </Text> ) : ( <Text variant="h6" css={{ display: 'flex' }}> <Box as="span" css={{ r: '$round', mr: '$2' }} onClick={resetSelection}> <ChevronLeftIcon /> </Box> {selection?.charAt(0).toUpperCase() + selection.slice(1)} </Text> )} <Sheet.Close> <IconButton as="div" data-testid="dialog_cross_icon"> <CrossIcon /> </IconButton> </Sheet.Close> </Flex> </Sheet.Title> <HorizontalDivider /> {!selection ? ( <Flex direction="column" css={{ pb: '$8', overflowY: 'auto', }} > {settingsList .filter(({ tabName }) => showSetting[tabName]) .map(({ icon: Icon, tabName, title }) => { return ( <Box key={tabName} value={tabName} onClick={() => { setSelection(tabName); }} as="div" css={{ all: 'unset', fontFamily: '$sans', p: '$10 $8', display: 'flex', alignItems: 'center', fontSize: '$sm', lineHeight: '$sm', color: '$on_surface_high', userSelect: 'none', gap: '$8', cursor: 'pointer', '&:hover': { bg: '$surface_brighter', r: '$1', gap: '$8', border: 'none', }, borderBottom: '1px solid $border_default', }} > <Icon /> {title} </Box> ); })} </Flex> ) : ( <Box direction="column" css={{ overflowY: 'scroll', px: '$8', py: '$10', maxHeight: '70vh', overflowX: 'hidden' }} > {settingsList .filter(({ tabName }) => showSetting[tabName] && selection === tabName) .map(({ content: Content, title, tabName }) => { return <Content key={title} setHide={hideSettingByTabName(tabName)} />; })} </Box> )} </Sheet.Content> </Sheet.Root> ); }; const DesktopSettingModal = ({ open, onOpenChange, selection, setSelection, showSetting, hideSettingByTabName, resetSelection, children = <></>, }) => { return ( <Dialog.Root open={open} onOpenChange={onOpenChange}> <Dialog.Trigger asChild>{children}</Dialog.Trigger> <Dialog.Portal> <Dialog.Overlay /> <Dialog.Content css={{ w: 'min(800px, 90%)', height: 'min(656px, 90%)', p: 0, r: '$4', }} > <Tabs.Root value={selection} activationMode="automatic" onValueChange={setSelection} css={{ size: '100%', position: 'relative' }} > <Tabs.List css={{ w: '18.625rem', flexDirection: 'column', bg: '$background_default', p: '$14 $10', borderTopLeftRadius: '$4', borderBottomLeftRadius: '$4', }} > <Text variant="h5">Settings </Text> <Flex direction="column" css={{ mx: 0, overflowY: 'auto', pt: '$10' }}> {settingsList .filter(({ tabName }) => showSetting[tabName]) .map(({ icon: Icon, tabName, title }) => { return ( <Tabs.Trigger key={tabName} value={tabName} css={{ gap: '$8' }}> <Icon /> {title} </Tabs.Trigger> ); })} </Flex> </Tabs.List> {selection && ( <Flex direction="column" css={{ flex: '1 1 0', minWidth: 0, mr: '$4', }} > {settingsList .filter(({ tabName }) => showSetting[tabName]) .map(({ content: Content, title, tabName }) => { return ( <Tabs.Content key={tabName} value={tabName} className={settingContent()}> <SettingsContentHeader onBack={resetSelection} isMobile={false}> {title} </SettingsContentHeader> <Content setHide={hideSettingByTabName(tabName)} /> </Tabs.Content> ); })} </Flex> )} </Tabs.Root> <Dialog.Close css={{ position: 'absolute', right: '$10', top: '$10' }}> <IconButton as="div" data-testid="dialog_cross_icon"> <CrossIcon /> </IconButton> </Dialog.Close> </Dialog.Content> </Dialog.Portal> </Dialog.Root> ); }; const SettingsContentHeader = ({ children, isMobile, onBack }) => { return ( <Text variant="h6" css={{ mb: '$12', display: 'flex', alignItems: 'center' }}> {isMobile && ( <Box as="span" css={{ bg: '$surface_bright', mr: '$4', r: '$round', p: '$2' }} onClick={onBack}> <ChevronLeftIcon /> </Box> )} {children} </Text> ); }; export default SettingsModal;