diff options
| author | Oskar Nyberg <oskar@mullvad.net> | 2022-09-20 17:13:20 +0200 |
|---|---|---|
| committer | Oskar Nyberg <oskar@mullvad.net> | 2022-09-27 10:30:53 +0200 |
| commit | 7d05e6624ac4fcde6964422241b0b5a9aeb8f840 (patch) | |
| tree | 73cbf2f77859ba7d67d1428a045c14db1228b34d /gui/src | |
| parent | de9bf32918295037d1616d256afedf52ab7d4b6d (diff) | |
| download | mullvadvpn-7d05e6624ac4fcde6964422241b0b5a9aeb8f840.tar.xz mullvadvpn-7d05e6624ac4fcde6964422241b0b5a9aeb8f840.zip | |
Update selector to handle automatic values
Diffstat (limited to 'gui/src')
| -rw-r--r-- | gui/src/renderer/components/cell/Selector.tsx | 103 |
1 files changed, 61 insertions, 42 deletions
diff --git a/gui/src/renderer/components/cell/Selector.tsx b/gui/src/renderer/components/cell/Selector.tsx index e815519552..f5024989e3 100644 --- a/gui/src/renderer/components/cell/Selector.tsx +++ b/gui/src/renderer/components/cell/Selector.tsx @@ -1,7 +1,8 @@ -import * as React from 'react'; +import { useCallback } from 'react'; import styled from 'styled-components'; import { colors } from '../../../config.json'; +import { messages } from '../../../shared/gettext'; import { useBoolean } from '../../lib/utilityHooks'; import Accordion from '../Accordion'; import { AriaDetails, AriaInput, AriaLabel } from '../AriaGroup'; @@ -24,44 +25,64 @@ const StyledChevronButton = styled(ChevronButton)({ marginRight: '16px', }); -export interface ISelectorItem<T> { +export interface SelectorItem<T> { label: string; value: T; disabled?: boolean; } -interface ISelectorProps<T> { +interface SelectorProps<T, U> { title?: string; - values: Array<ISelectorItem<T>>; - value: T; - onSelect: (value: T) => void; - selectedCellRef?: React.Ref<HTMLButtonElement>; + items: Array<SelectorItem<T>>; + value: T | U; + onSelect: (value: T | U) => void; + selectedCellRef?: React.Ref<HTMLElement>; className?: string; details?: React.ReactElement; expandable?: boolean; disabled?: boolean; thinTitle?: boolean; + automaticLabel?: string; + automaticValue?: U; } -export default function Selector<T>(props: ISelectorProps<T>) { +export default function Selector<T, U>(props: SelectorProps<T, U>) { const [expanded, , , toggleExpanded] = useBoolean(!props.expandable); - const items = props.values.map((item, i) => { - const selected = item.value === props.value; + const items = props.items.map((item) => { + const selected = props.value === item.value; + const ref = selected ? (props.selectedCellRef as React.Ref<HTMLButtonElement>) : undefined; return ( <SelectorCell - key={i} + key={`value-${item.value}`} value={item.value} - selected={selected} + isSelected={selected} disabled={props.disabled || item.disabled} - forwardedRef={selected ? props.selectedCellRef : undefined} + forwardedRef={ref} onSelect={props.onSelect}> {item.label} </SelectorCell> ); }); + if (props.automaticValue !== undefined) { + const selected = props.value === props.automaticValue; + const ref = selected ? (props.selectedCellRef as React.Ref<HTMLButtonElement>) : undefined; + + items.unshift( + <SelectorCell + key={'automatic'} + value={props.automaticValue} + isSelected={selected} + disabled={props.disabled} + forwardedRef={ref} + onSelect={props.onSelect}> + {props.automaticLabel ?? messages.gettext('Automatic')} + </SelectorCell>, + ); + } + const title = props.title && ( <StyledTitle> <AriaLabel> @@ -97,40 +118,38 @@ const StyledLabel = styled(Cell.Label)(normalText, { fontWeight: 400, }); -interface ISelectorCellProps<T> { +interface SelectorCellProps<T> { value: T; - selected: boolean; + isSelected: boolean; disabled?: boolean; onSelect: (value: T) => void; - children?: React.ReactText; + children: React.ReactNode | Array<React.ReactNode>; forwardedRef?: React.Ref<HTMLButtonElement>; } -class SelectorCell<T> extends React.Component<ISelectorCellProps<T>> { - public render() { - return ( - <Cell.CellButton - ref={this.props.forwardedRef} - onClick={this.onClick} - selected={this.props.selected} - disabled={this.props.disabled} - role="option" - aria-selected={this.props.selected} - aria-disabled={this.props.disabled}> - <StyledCellIcon - visible={this.props.selected} - source="icon-tick" - width={18} - tintColor={colors.white} - /> - <StyledLabel>{this.props.children}</StyledLabel> - </Cell.CellButton> - ); - } - - private onClick = () => { - if (!this.props.selected) { - this.props.onSelect(this.props.value); +function SelectorCell<T>(props: SelectorCellProps<T>) { + const handleClick = useCallback(() => { + if (!props.isSelected) { + props.onSelect(props.value); } - }; + }, [props.isSelected, props.onSelect, props.value]); + + return ( + <Cell.CellButton + ref={props.forwardedRef} + onClick={handleClick} + selected={props.isSelected} + disabled={props.disabled} + role="option" + aria-selected={props.isSelected} + aria-disabled={props.disabled}> + <StyledCellIcon + visible={props.isSelected} + source="icon-tick" + width={18} + tintColor={colors.white} + /> + <StyledLabel>{props.children}</StyledLabel> + </Cell.CellButton> + ); } |
