diff options
| author | Oliver <oliver@mohlin.dev> | 2025-09-02 08:19:25 +0200 |
|---|---|---|
| committer | Tobias Järvelöv <tobias.jarvelov@mullvad.net> | 2025-09-22 12:35:43 +0200 |
| commit | 4b230dc4d1b5df0987c077bf9a00ee7dea3763b4 (patch) | |
| tree | 4ec2088f111432e831780b561e46139aad8b85b6 | |
| parent | c492fcf1b6063235a37f6441992044970f2742fa (diff) | |
| download | mullvadvpn-4b230dc4d1b5df0987c077bf9a00ee7dea3763b4.tar.xz mullvadvpn-4b230dc4d1b5df0987c077bf9a00ee7dea3763b4.zip | |
Use Listbox in shadow socks settings view
| -rw-r--r-- | desktop/packages/mullvad-vpn/src/renderer/components/views/shadowsocks-settings/components/shadowsocks-port-setting/ShadowSocksPortSetting.tsx | 111 |
1 files changed, 61 insertions, 50 deletions
diff --git a/desktop/packages/mullvad-vpn/src/renderer/components/views/shadowsocks-settings/components/shadowsocks-port-setting/ShadowSocksPortSetting.tsx b/desktop/packages/mullvad-vpn/src/renderer/components/views/shadowsocks-settings/components/shadowsocks-port-setting/ShadowSocksPortSetting.tsx index 1b7246d070..284f333915 100644 --- a/desktop/packages/mullvad-vpn/src/renderer/components/views/shadowsocks-settings/components/shadowsocks-port-setting/ShadowSocksPortSetting.tsx +++ b/desktop/packages/mullvad-vpn/src/renderer/components/views/shadowsocks-settings/components/shadowsocks-port-setting/ShadowSocksPortSetting.tsx @@ -1,80 +1,91 @@ -import { useCallback } from 'react'; +import React, { useCallback } from 'react'; import { sprintf } from 'sprintf-js'; -import styled from 'styled-components'; import { wrapConstraint } from '../../../../../../shared/daemon-rpc-types'; import { messages } from '../../../../../../shared/gettext'; import { removeNonNumericCharacters } from '../../../../../../shared/string-helpers'; import { useAppContext } from '../../../../../context'; +import { Listbox } from '../../../../../lib/components/listbox/Listbox'; import { useSelector } from '../../../../../redux/store'; -import { AriaDescription, AriaInputGroup } from '../../../../AriaGroup'; -import * as Cell from '../../../../cell'; -import { SelectorItem, SelectorWithCustomItem } from '../../../../cell/Selector'; +import { DefaultListboxOption } from '../../../../default-listbox-option'; +import { InputListboxOption } from '../../../../input-listbox-option'; -const PORTS: Array<SelectorItem<number>> = []; const ALLOWED_RANGE = [1, 65535]; -const StyledSelectorContainer = styled.div({ - flex: 0, -}); - export function ShadowsocksPortSetting() { const { setObfuscationSettings } = useAppContext(); const obfuscationSettings = useSelector((state) => state.settings.obfuscationSettings); + const descriptionId = React.useId(); - const port = - obfuscationSettings.shadowsocksSettings.port === 'any' - ? null - : obfuscationSettings.shadowsocksSettings.port.only; + const selectedOption = React.useMemo(() => { + const port = obfuscationSettings.shadowsocksSettings.port; + if (port === 'any') + return { + port: 'any', + value: null, + }; + return { + port: port.only, + value: 'custom', + }; + }, [obfuscationSettings]); const setShadowsocksPort = useCallback( - async (port: number | null) => { + async (port: string | null) => { await setObfuscationSettings({ ...obfuscationSettings, shadowsocksSettings: { ...obfuscationSettings.shadowsocksSettings, - port: wrapConstraint(port), + port: wrapConstraint(typeof port === 'string' ? parseInt(port) : port), }, }); }, [setObfuscationSettings, obfuscationSettings], ); - const parseValue = useCallback((port: string) => parseInt(port), []); - - const validateValue = useCallback( - (value: number) => value >= ALLOWED_RANGE[0] && value <= ALLOWED_RANGE[1], - [], - ); + const validateValue = useCallback((value: string) => { + const port = parseInt(value); + return port >= ALLOWED_RANGE[0] && port <= ALLOWED_RANGE[1]; + }, []); return ( - <AriaInputGroup> - <StyledSelectorContainer> - <SelectorWithCustomItem - // TRANSLATORS: The title for the WireGuard port selector. - title={messages.pgettext('wireguard-settings-view', 'Port')} - items={PORTS} - value={port} - onSelect={setShadowsocksPort} - inputPlaceholder={messages.pgettext('wireguard-settings-view', 'Port')} - automaticValue={null} - parseValue={parseValue} - modifyValue={removeNonNumericCharacters} - validateValue={validateValue} - maxLength={`${ALLOWED_RANGE[1]}`.length} - /> - </StyledSelectorContainer> - <Cell.CellFooter> - <AriaDescription> - <Cell.CellFooterText> - {sprintf( - // TRANSLATORS: Text describing the valid port range for a port selector. - messages.pgettext('wireguard-settings-view', 'Valid range: %(min)s - %(max)s'), - { min: ALLOWED_RANGE[0], max: ALLOWED_RANGE[1] }, - )} - </Cell.CellFooterText> - </AriaDescription> - </Cell.CellFooter> - </AriaInputGroup> + <Listbox value={selectedOption.value} onValueChange={setShadowsocksPort}> + <Listbox.Item> + <Listbox.Content> + <Listbox.Label> + { + // TRANSLATORS: The title for the WireGuard port selector. + messages.pgettext('wireguard-settings-view', 'Port') + } + </Listbox.Label> + </Listbox.Content> + </Listbox.Item> + <Listbox.Options> + <DefaultListboxOption value={null}>{messages.gettext('Automatic')}</DefaultListboxOption> + <InputListboxOption value="custom"> + <InputListboxOption.Label>{messages.gettext('Custom')}</InputListboxOption.Label> + <InputListboxOption.Input + aria-describedby={descriptionId} + type="text" + placeholder={messages.pgettext('wireguard-settings-view', 'Port')} + initialValue={ + selectedOption.value === 'custom' ? selectedOption.port?.toString() : undefined + } + validate={validateValue} + format={removeNonNumericCharacters} + maxLength={`${ALLOWED_RANGE[1]}`.length} + /> + </InputListboxOption> + </Listbox.Options> + <Listbox.Footer> + <Listbox.Text id={descriptionId}> + {sprintf( + // TRANSLATORS: Text describing the valid port range for a port selector. + messages.pgettext('wireguard-settings-view', 'Valid range: %(min)s - %(max)s'), + { min: ALLOWED_RANGE[0], max: ALLOWED_RANGE[1] }, + )} + </Listbox.Text> + </Listbox.Footer> + </Listbox> ); } |
