summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorOliver <oliver@mohlin.dev>2025-09-02 08:19:25 +0200
committerTobias Järvelöv <tobias.jarvelov@mullvad.net>2025-09-22 12:35:43 +0200
commit4b230dc4d1b5df0987c077bf9a00ee7dea3763b4 (patch)
tree4ec2088f111432e831780b561e46139aad8b85b6
parentc492fcf1b6063235a37f6441992044970f2742fa (diff)
downloadmullvadvpn-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.tsx111
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>
);
}