From 7b0e16f0aee714f374f8f0cf0d4d7a2c6a19fa77 Mon Sep 17 00:00:00 2001 From: lubej <9722540+lubej@users.noreply.github.com> Date: Wed, 5 Jul 2023 14:34:28 +0200 Subject: [PATCH] Replace network select --- src/app/components/Select/index.tsx | 85 +++++++-- .../HomePage/Graph/NetworkSelector/index.tsx | 177 +++++++++++------- .../HomePage/Graph/ParaTimeSelector/index.tsx | 2 +- src/stories/ButtonsShowroom.stories.tsx | 8 - 4 files changed, 172 insertions(+), 100 deletions(-) diff --git a/src/app/components/Select/index.tsx b/src/app/components/Select/index.tsx index 083baf43f4..e292f0c5ad 100644 --- a/src/app/components/Select/index.tsx +++ b/src/app/components/Select/index.tsx @@ -1,6 +1,6 @@ import SelectUnstyled, { SelectProps, selectClasses, SelectRootSlotProps } from '@mui/base/Select' import Option, { optionClasses } from '@mui/base/Option' -import Popper from '@mui/base/Popper' +import Popper, { PopperPlacementType } from '@mui/base/Popper' import { styled } from '@mui/material/styles' import Box from '@mui/material/Box' import { @@ -21,8 +21,11 @@ import ExpandLessIcon from '@mui/icons-material/ExpandLess' import ExpandMoreIcon from '@mui/icons-material/ExpandMore' import { COLORS } from '../../../styles/theme/colors' import { useTranslation } from 'react-i18next' +import { WithOptionalOwnerState } from '@mui/base/utils' +import { SelectPopperSlotProps, SelectSlots } from '@mui/base/Select/Select.types' +import * as React from 'react' -const StyledButton = styled(Button)(({ theme }) => ({ +export const StyledSelectButton = styled(Button)(({ theme }) => ({ height: '36px', minWidth: '135px', padding: `0 ${theme.spacing(4)}`, @@ -35,7 +38,7 @@ const StyledButton = styled(Button)(({ theme }) => ({ }, })) -const StyledListbox = styled('ul')(({ theme }) => ({ +export const StyledSelectListbox = styled('ul')(({ theme }) => ({ boxSizing: 'border-box', padding: theme.spacing(0), margin: `${theme.spacing(3)} ${theme.spacing(0)}`, @@ -47,7 +50,7 @@ const StyledListbox = styled('ul')(({ theme }) => ({ filter: 'drop-shadow(0px 4px 4px rgba(0, 0, 0, 0.25))', })) -const StyledOption = styled(Option)(({ theme }) => ({ +export const StyledSelectOption = styled(Option)(({ theme }) => ({ display: 'flex', alignItems: 'center', boxSizing: 'border-box', @@ -85,28 +88,48 @@ const TertiaryButton = forwardRef( const { t } = useTranslation() return ( - + {children ? children : t('select.placeholder')} {ownerState.open ? : } - + ) }, ) const CustomSelect = forwardRef(function CustomSelect( - props: SelectProps, + { + root, + listbox, + popper, + placement, + ...restProps + }: SelectProps & SelectSlots & Partial>, ref: ForwardedRef, ) { const slots: SelectProps['slots'] = { - root: TertiaryButton, - listbox: StyledListbox, - popper: StyledPopper, - ...props.slots, + root, + listbox, + popper, + ...restProps.slots, } - return + return ( + + ) }) as ( - props: SelectProps & RefAttributes, + props: SelectProps & + SelectSlots & + Partial> & + RefAttributes, ) => JSX.Element export interface SelectOptionBase { @@ -114,11 +137,23 @@ export interface SelectOptionBase { value: string | number } +const SelectOption = ({ value, label }: T): ReactElement => ( + + {label} + +) + interface SelectCmpProps { label?: string options: T[] defaultValue?: T['value'] handleChange?: (selectedOption: T['value'] | null) => void + placement?: PopperPlacementType + className?: string + root?: React.ElementType + Option?: typeof SelectOption | undefined + listbox?: React.ElementType + popper?: React.ComponentType>> } const SelectCmp = ({ @@ -126,6 +161,12 @@ const SelectCmp = ({ options, defaultValue, handleChange, + placement = 'bottom-start', + className, + root = TertiaryButton, + listbox = StyledSelectListbox, + popper = StyledPopper, + Option = SelectOption, }: SelectCmpProps): ReactElement => { const selectId = useId() @@ -137,17 +178,23 @@ const SelectCmp = ({ ) return ( - + {label && ( )} - id={selectId} defaultValue={defaultValue} onChange={onChange}> - {options.map(({ label, value }) => ( - - {label} - + + id={selectId} + defaultValue={defaultValue} + onChange={onChange} + root={root} + listbox={listbox} + popper={popper} + placement={placement} + > + {options.map((props: T) => ( + diff --git a/src/app/pages/HomePage/Graph/NetworkSelector/index.tsx b/src/app/pages/HomePage/Graph/NetworkSelector/index.tsx index 48b0b3a130..dbf5e23be3 100644 --- a/src/app/pages/HomePage/Graph/NetworkSelector/index.tsx +++ b/src/app/pages/HomePage/Graph/NetworkSelector/index.tsx @@ -1,100 +1,133 @@ -import { FC, useState } from 'react' +import { FC, ForwardedRef, forwardRef, ReactElement } from 'react' import { useTranslation } from 'react-i18next' -import { useTheme } from '@mui/material/styles' -import { useScreenSize } from '../../../../hooks/useScreensize' -import AddIcon from '@mui/icons-material/Add' import Box from '@mui/material/Box' -import Button from '@mui/material/Button' -import IconButton from '@mui/material/IconButton' -import RemoveIcon from '@mui/icons-material/Remove' import Typography from '@mui/material/Typography' import { styled } from '@mui/material/styles' import { COLORS } from '../../../../../styles/theme/colors' import { getNetworkNames, Network } from '../../../../../types/network' -import Collapse from '@mui/material/Collapse' import { RouteUtils } from '../../../../utils/route-utils' +import { + Select, + SelectOptionBase, + StyledSelectButton, + StyledSelectListbox, + StyledSelectOption, +} from '../../../../components/Select' +import { SelectRootSlotProps } from '@mui/base/Select' +import ExpandLessIcon from '@mui/icons-material/ExpandLess' +import ExpandMoreIcon from '@mui/icons-material/ExpandMore' +import { getNetworkIcons } from '../../../../utils/content' +import { optionClasses } from '@mui/base/Option' -const StyledNetworkSelector = styled(Box)(() => ({ +interface NetworkOption extends SelectOptionBase { + label: Network + value: Network +} + +const StyledNetworkSelector = styled(Select)(({ theme }) => ({ position: 'absolute', - bottom: 0, + bottom: theme.spacing(5), display: 'flex', width: '100%', justifyContent: 'center', })) -const StyledBox = styled(Box)(({ theme }) => ({ +const StyledButton = styled(StyledSelectButton)(({ theme }) => ({ + height: '44px', + minWidth: '200px', backgroundColor: theme.palette.layout.primaryBackground, - border: `solid 3px ${theme.palette.layout.lightBorder}`, - borderRadius: '45px', - padding: `${theme.spacing(3)} ${theme.spacing(4)}`, - display: 'inline-flex', - alignItems: 'center', + border: `2px solid ${theme.palette.layout.lightBorder}`, + color: theme.palette.layout.main, + '&:hover': { + backgroundColor: theme.palette.layout.primaryBackground, + }, })) -export const SelectNetworkButton = styled(Button, { - shouldForwardProp: prop => prop !== 'isSelectedNetwork', -})<{ isSelectedNetwork: boolean }>(({ isSelectedNetwork, theme }) => ({ - height: '30px', - padding: `${theme.spacing(2)} ${theme.spacing(3)}`, - textTransform: 'capitalize', - fontSize: '16px', - borderRadius: '9px', - backgroundColor: isSelectedNetwork - ? theme.palette.layout.primaryBackground - : theme.palette.layout.secondary, - borderColor: isSelectedNetwork ? theme.palette.layout.hoverBorder : theme.palette.layout.secondary, - borderWidth: theme.spacing(1), - color: theme.palette.layout.main, - '&:hover, &:focus-visible': { - backgroundColor: theme.palette.layout.secondary, - borderWidth: theme.spacing(1), - borderColor: COLORS.white, +const StyledListbox = styled(StyledSelectListbox)(() => ({ + minWidth: '200px', + background: COLORS.white, + color: COLORS.grayDark, +})) + +const StyledOption = styled(StyledSelectOption)(() => ({ + height: '44px', + color: COLORS.grayDark, + svg: { + color: COLORS.grayExtraDark, + }, + [`&:hover:not(.${optionClasses.disabled}), + &.${optionClasses.highlighted}`]: { + backgroundColor: 'transparent', }, })) -SelectNetworkButton.defaultProps = { - size: 'small', - variant: 'outlined', - sx: { ml: 4 }, + +const SelectOption = ({ value }: NetworkOption): ReactElement => { + const { t } = useTranslation() + + const labels = getNetworkNames(t) + const icons = getNetworkIcons() + + return ( + + ({ display: 'flex', gap: theme.spacing(3), pl: theme.spacing(3), alignItems: 'center' })} + > + {icons[value]} + {labels[value]} + + + ) } -type NetworkSelectorProps = { +const NetworkSelectorButton = forwardRef( + (props: SelectRootSlotProps, ref: ForwardedRef) => { + const { ownerState, ...restProps } = props + const { open, value } = ownerState + // Expecting value as Network + const networkValue = value as Network + const { t } = useTranslation() + const label = getNetworkNames(t) + const icons = getNetworkIcons() + + return ( + + ({ + display: 'flex', + gap: theme.spacing(3), + pl: theme.spacing(3), + alignItems: 'center', + })} + > + {icons[networkValue]} + {label[networkValue]} + + {open ? : } + + ) + }, +) + +interface NetworkSelectProps { network: Network - setNetwork: (network: Network) => void + setNetwork: (network: Network | null) => void } -export const NetworkSelector: FC = ({ network, setNetwork }) => { - const { t } = useTranslation() - const theme = useTheme() - const { isMobile } = useScreenSize() - const [open, setOpen] = useState(false) - const options: Network[] = RouteUtils.getEnabledNetworks() - const labels = getNetworkNames(t) +export const NetworkSelector: FC = ({ network, setNetwork }) => { + const options = RouteUtils.getEnabledNetworks().map(network => ({ + label: network, + value: network, + })) return ( - - - {!isMobile && ( - - {t('home.selectNetwork')} - - )} - - {options.map(option => ( - - setNetwork(option)} isSelectedNetwork={option === network}> - {labels[option]} - - - ))} - - setOpen(!open)}> - {open ? ( - - ) : ( - - )} - - - + ) } diff --git a/src/app/pages/HomePage/Graph/ParaTimeSelector/index.tsx b/src/app/pages/HomePage/Graph/ParaTimeSelector/index.tsx index bc4768922f..29db46d6f4 100644 --- a/src/app/pages/HomePage/Graph/ParaTimeSelector/index.tsx +++ b/src/app/pages/HomePage/Graph/ParaTimeSelector/index.tsx @@ -260,7 +260,7 @@ const ParaTimeSelectorCmp: FC = ({ )} {step === ParaTimeSelectorStep.Explore && ( - + setNetwork(network ?? Network.mainnet)} /> )} {activeMobileGraphTooltip.current && ( diff --git a/src/stories/ButtonsShowroom.stories.tsx b/src/stories/ButtonsShowroom.stories.tsx index 2beb629e1b..72e86cad86 100644 --- a/src/stories/ButtonsShowroom.stories.tsx +++ b/src/stories/ButtonsShowroom.stories.tsx @@ -7,8 +7,6 @@ import { GetStartedBtn } from '../app/pages/HomePage/Graph/HelpScreen' import { ViewResultButton } from '../app/pages/SearchResultsPage/ResultsGroupByType' import { LoadMoreButton } from '../app/components/LoadMoreButton' import { withRouter } from 'storybook-addon-react-router-v6' -import { SelectNetworkButton } from '../app/pages/HomePage/Graph/NetworkSelector' -import { NetworkButton } from '../app/components/PageLayout/NetworkButton' import WidgetsIcon from '@mui/icons-material/Widgets' export default { @@ -37,12 +35,6 @@ const Template: StoryFn = () => {

- SelectNetworkButton - {}} /> - -
-
- '', selectedPage: 1 }} /> )