diff options
| author | Tobias Järvelöv <tobias.jarvelov@mullvad.net> | 2025-11-03 17:23:57 +0100 |
|---|---|---|
| committer | Tobias Järvelöv <tobias.jarvelov@mullvad.net> | 2025-11-03 17:23:57 +0100 |
| commit | b8c29b0ff18bd5d50981914841acdde2d44bf11f (patch) | |
| tree | 16ee6c9054a83b3dabf94513b94fab7d77eb37db | |
| parent | eb9b4fdd8f0ab7031e2f3f21bfbca3cc98f988c1 (diff) | |
| download | mullvadvpn-poc-switch-component-form-label-integration-switches-not-focusable-des-1637.tar.xz mullvadvpn-poc-switch-component-form-label-integration-switches-not-focusable-des-1637.zip | |
Proof of concept showing Switch component <-> form label integrationpoc-switch-component-form-label-integration-switches-not-focusable-des-1637
6 files changed, 34 insertions, 12 deletions
diff --git a/desktop/packages/mullvad-vpn/src/renderer/components/AriaGroup.tsx b/desktop/packages/mullvad-vpn/src/renderer/components/AriaGroup.tsx index 59536e6109..eb91633ac5 100644 --- a/desktop/packages/mullvad-vpn/src/renderer/components/AriaGroup.tsx +++ b/desktop/packages/mullvad-vpn/src/renderer/components/AriaGroup.tsx @@ -56,6 +56,8 @@ const AriaInputContext = React.createContext<IAriaInputContext>({ }, }); +export const useAriaInputContext = () => useContext(AriaInputContext); + export function AriaInputGroup(props: IAriaGroupProps) { const id = useId(); diff --git a/desktop/packages/mullvad-vpn/src/renderer/components/ProxyForm.tsx b/desktop/packages/mullvad-vpn/src/renderer/components/ProxyForm.tsx index 3d36fff9c9..d09c0d7393 100644 --- a/desktop/packages/mullvad-vpn/src/renderer/components/ProxyForm.tsx +++ b/desktop/packages/mullvad-vpn/src/renderer/components/ProxyForm.tsx @@ -14,6 +14,7 @@ import { FlexRow } from '../lib/components/flex-row'; import { Switch } from '../lib/components/switch'; import { IpAddress } from '../lib/ip'; import { useEffectEvent } from '../lib/utility-hooks'; +import { useAriaInputContext } from './AriaGroup'; import { SettingsForm, useSettingsFormSubmittable } from './cell/SettingsForm'; import { SettingsGroup } from './cell/SettingsGroup'; import { SettingsRadioGroup } from './cell/SettingsRadioGroup'; @@ -393,6 +394,18 @@ function EditSocks5Remote(props: EditProxyProps<Socks5RemoteCustomProxy>) { // eslint-disable-next-line react-hooks/exhaustive-deps useEffect(() => onUpdate(ip, port, username, password), [ip, port, username, password]); + const SettingsAuthentication = () => { + const { inputId } = useAriaInputContext(); + + return ( + <Switch id={inputId} checked={authentication} onCheckedChange={setAuthentication}> + <Switch.Trigger> + <Switch.Thumb /> + </Switch.Trigger> + </Switch> + ); + }; + return ( <SettingsGroup title={messages.pgettext('api-access-methods-view', 'Remote Server')}> <SettingsRow @@ -424,11 +437,7 @@ function EditSocks5Remote(props: EditProxyProps<Socks5RemoteCustomProxy>) { </SettingsRow> <SettingsRow label={messages.pgettext('api-access-methods-view', 'Authentication')}> - <Switch checked={authentication} onCheckedChange={setAuthentication}> - <Switch.Trigger> - <Switch.Thumb /> - </Switch.Trigger> - </Switch> + <SettingsAuthentication /> </SettingsRow> {authentication && ( diff --git a/desktop/packages/mullvad-vpn/src/renderer/components/cell/SettingsGroup.tsx b/desktop/packages/mullvad-vpn/src/renderer/components/cell/SettingsGroup.tsx index 777a610ef2..1cf1acd55d 100644 --- a/desktop/packages/mullvad-vpn/src/renderer/components/cell/SettingsGroup.tsx +++ b/desktop/packages/mullvad-vpn/src/renderer/components/cell/SettingsGroup.tsx @@ -27,6 +27,7 @@ const StyledInfoButton = styled(InfoButton)({ export const StyledSettingsGroup = styled.div({}); interface SettingsGroupContext { + key?: string; setError?: (key: string, errorMessage: string) => void; unsetError?: (key: string) => void; } @@ -48,7 +49,7 @@ export function useSettingsGroupContext() { useEffect(() => () => unsetErrorImpl(), [unsetErrorImpl]); - return { reportError, unsetError: unsetErrorImpl }; + return { key, reportError, unsetError: unsetErrorImpl }; } interface SettingsGroupProps { diff --git a/desktop/packages/mullvad-vpn/src/renderer/lib/components/switch/Switch.tsx b/desktop/packages/mullvad-vpn/src/renderer/lib/components/switch/Switch.tsx index 8fe92377c9..7c222d2bb0 100644 --- a/desktop/packages/mullvad-vpn/src/renderer/lib/components/switch/Switch.tsx +++ b/desktop/packages/mullvad-vpn/src/renderer/lib/components/switch/Switch.tsx @@ -4,6 +4,7 @@ import { SwitchLabel, SwitchThumb, SwitchTrigger } from './components'; import { SwitchProvider } from './SwitchContext'; export interface SwitchProps { + id: string; checked?: boolean; onCheckedChange?: (checked: boolean) => void; labelId?: string; @@ -12,6 +13,7 @@ export interface SwitchProps { } function Switch({ + id, labelId: labelIdProp, checked, onCheckedChange, @@ -21,6 +23,7 @@ function Switch({ const labelId = React.useId(); return ( <SwitchProvider + id={id} labelId={labelIdProp ?? labelId} checked={checked} onCheckedChange={onCheckedChange} diff --git a/desktop/packages/mullvad-vpn/src/renderer/lib/components/switch/SwitchContext.tsx b/desktop/packages/mullvad-vpn/src/renderer/lib/components/switch/SwitchContext.tsx index 78520c0e9a..2a210d64d4 100644 --- a/desktop/packages/mullvad-vpn/src/renderer/lib/components/switch/SwitchContext.tsx +++ b/desktop/packages/mullvad-vpn/src/renderer/lib/components/switch/SwitchContext.tsx @@ -3,6 +3,7 @@ import React from 'react'; import { SwitchProps } from './Switch'; interface SwitchContextProps { + id: string; labelId: string; disabled: SwitchProps['disabled']; checked?: SwitchProps['checked']; @@ -20,6 +21,7 @@ export const useSwitchContext = (): SwitchContextProps => { }; interface SwitchProviderProps { + id: string; labelId: string; disabled: SwitchProps['disabled']; checked?: SwitchProps['checked']; diff --git a/desktop/packages/mullvad-vpn/src/renderer/lib/components/switch/components/switch-trigger/SwitchTrigger.tsx b/desktop/packages/mullvad-vpn/src/renderer/lib/components/switch/components/switch-trigger/SwitchTrigger.tsx index a14883e4f6..c369dad4c6 100644 --- a/desktop/packages/mullvad-vpn/src/renderer/lib/components/switch/components/switch-trigger/SwitchTrigger.tsx +++ b/desktop/packages/mullvad-vpn/src/renderer/lib/components/switch/components/switch-trigger/SwitchTrigger.tsx @@ -17,18 +17,23 @@ export const StyledSwitchTrigger = styled.button<{ $checked?: boolean }>` `; export function SwitchTrigger(props: SwitchTriggerProps) { - const { labelId, checked, disabled, onCheckedChange } = useSwitchContext(); - const handleClick = React.useCallback(() => { - if (onCheckedChange) { - onCheckedChange(!checked); - } - }, [checked, onCheckedChange]); + const { id, labelId, checked, disabled, onCheckedChange } = useSwitchContext(); + const handleClick = React.useCallback( + (event: React.MouseEvent) => { + event.preventDefault(); + if (onCheckedChange) { + onCheckedChange(!checked); + } + }, + [checked, onCheckedChange], + ); return ( <StyledSwitchTrigger onClick={handleClick} disabled={disabled} role="switch" + id={id} aria-checked={checked ? 'true' : 'false'} aria-labelledby={labelId} {...props} |
