diff options
| author | Oskar Nyberg <oskar@mullvad.net> | 2022-02-09 12:09:09 +0100 |
|---|---|---|
| committer | Oskar Nyberg <oskar@mullvad.net> | 2022-02-09 12:09:09 +0100 |
| commit | f371ebe164a397b42aa4c1f5076e390820e774d6 (patch) | |
| tree | 8749a291404ee1751b7aed70d5ad9228b4f0e07c /gui/src | |
| parent | 00d8d25f997cb6d1c7d1fc68e941d94dbca48dce (diff) | |
| download | mullvadvpn-f371ebe164a397b42aa4c1f5076e390820e774d6.tar.xz mullvadvpn-f371ebe164a397b42aa4c1f5076e390820e774d6.zip | |
Make mssfix and mtu input white when focused
Diffstat (limited to 'gui/src')
| -rw-r--r-- | gui/src/renderer/components/AdvancedSettingsStyles.tsx | 4 | ||||
| -rw-r--r-- | gui/src/renderer/components/OpenVPNSettings.tsx | 30 | ||||
| -rw-r--r-- | gui/src/renderer/components/WireguardSettings.tsx | 30 | ||||
| -rw-r--r-- | gui/src/renderer/components/cell/Input.tsx | 108 |
4 files changed, 94 insertions, 78 deletions
diff --git a/gui/src/renderer/components/AdvancedSettingsStyles.tsx b/gui/src/renderer/components/AdvancedSettingsStyles.tsx index c3b9a140d4..9e6ac73160 100644 --- a/gui/src/renderer/components/AdvancedSettingsStyles.tsx +++ b/gui/src/renderer/components/AdvancedSettingsStyles.tsx @@ -4,10 +4,6 @@ import * as Cell from './cell'; import { NavigationScrollbars } from './NavigationBar'; import Selector from './cell/Selector'; -export const StyledInputFrame = styled(Cell.InputFrame)({ - flex: 0, -}); - export const StyledSelectorContainer = styled.div({ flex: 0, }); diff --git a/gui/src/renderer/components/OpenVPNSettings.tsx b/gui/src/renderer/components/OpenVPNSettings.tsx index ce2cbe264b..480180eb67 100644 --- a/gui/src/renderer/components/OpenVPNSettings.tsx +++ b/gui/src/renderer/components/OpenVPNSettings.tsx @@ -47,10 +47,6 @@ export const StyledSelectorContainer = styled.div({ flex: 0, }); -export const StyledInputFrame = styled(Cell.InputFrame)({ - flex: 0, -}); - interface IProps { bridgeModeAvailablity: BridgeModeAvailability; openvpn: { @@ -195,20 +191,18 @@ export default class OpenVpnSettings extends React.Component<IProps, IState> { {messages.pgettext('openvpn-settings-view', 'Mssfix')} </Cell.InputLabel> </AriaLabel> - <StyledInputFrame> - <AriaInput> - <Cell.AutoSizingTextInput - value={this.props.mssfix ? this.props.mssfix.toString() : ''} - inputMode={'numeric'} - maxLength={4} - placeholder={messages.gettext('Default')} - onSubmitValue={this.onMssfixSubmit} - validateValue={OpenVpnSettings.mssfixIsValid} - submitOnBlur={true} - modifyValue={OpenVpnSettings.removeNonNumericCharacters} - /> - </AriaInput> - </StyledInputFrame> + <AriaInput> + <Cell.AutoSizingTextInput + value={this.props.mssfix ? this.props.mssfix.toString() : ''} + inputMode={'numeric'} + maxLength={4} + placeholder={messages.gettext('Default')} + onSubmitValue={this.onMssfixSubmit} + validateValue={OpenVpnSettings.mssfixIsValid} + submitOnBlur={true} + modifyValue={OpenVpnSettings.removeNonNumericCharacters} + /> + </AriaInput> </Cell.Container> <Cell.Footer> <AriaDescription> diff --git a/gui/src/renderer/components/WireguardSettings.tsx b/gui/src/renderer/components/WireguardSettings.tsx index 8d5d47f38c..2159194a74 100644 --- a/gui/src/renderer/components/WireguardSettings.tsx +++ b/gui/src/renderer/components/WireguardSettings.tsx @@ -43,10 +43,6 @@ export const StyledSelectorForFooter = (styled(Selector)({ marginBottom: 0, }) as unknown) as new <T>() => Selector<T>; -export const StyledInputFrame = styled(Cell.InputFrame)({ - flex: 0, -}); - interface IProps { wireguard: { port?: number; ipVersion?: IpVersion }; wireguardMtu?: number; @@ -227,20 +223,18 @@ export default class WireguardSettings extends React.Component<IProps, IState> { {messages.pgettext('wireguard-settings-view', 'MTU')} </Cell.InputLabel> </AriaLabel> - <StyledInputFrame> - <AriaInput> - <Cell.AutoSizingTextInput - value={this.props.wireguardMtu ? this.props.wireguardMtu.toString() : ''} - inputMode={'numeric'} - maxLength={4} - placeholder={messages.gettext('Default')} - onSubmitValue={this.onWireguardMtuSubmit} - validateValue={WireguardSettings.wireguarMtuIsValid} - submitOnBlur={true} - modifyValue={WireguardSettings.removeNonNumericCharacters} - /> - </AriaInput> - </StyledInputFrame> + <AriaInput> + <Cell.AutoSizingTextInput + value={this.props.wireguardMtu ? this.props.wireguardMtu.toString() : ''} + inputMode={'numeric'} + maxLength={4} + placeholder={messages.gettext('Default')} + onSubmitValue={this.onWireguardMtuSubmit} + validateValue={WireguardSettings.wireguarMtuIsValid} + submitOnBlur={true} + modifyValue={WireguardSettings.removeNonNumericCharacters} + /> + </AriaInput> </Cell.Container> <Cell.Footer> <AriaDescription> diff --git a/gui/src/renderer/components/cell/Input.tsx b/gui/src/renderer/components/cell/Input.tsx index fbc6849de3..4215f6e96e 100644 --- a/gui/src/renderer/components/cell/Input.tsx +++ b/gui/src/renderer/components/cell/Input.tsx @@ -5,6 +5,7 @@ import { mediumText } from '../common-styles'; import { CellDisabledContext, Container } from './Container'; import StandaloneSwitch from '../Switch'; import ImageView from '../ImageView'; +import { useBoolean } from '../../lib/utilityHooks'; export const Switch = React.forwardRef(function SwitchT( props: StandaloneSwitch['props'], @@ -14,13 +15,6 @@ export const Switch = React.forwardRef(function SwitchT( return <StandaloneSwitch ref={ref} disabled={disabled} {...props} />; }); -export const InputFrame = styled.div({ - flexGrow: 0, - backgroundColor: 'rgba(255,255,255,0.1)', - borderRadius: '4px', - padding: '4px 8px', -}); - const inputTextStyles: React.CSSProperties = { ...mediumText, fontWeight: 600, @@ -29,36 +23,18 @@ const inputTextStyles: React.CSSProperties = { padding: '0px', }; -const StyledInput = styled.input({}, (props: { valid?: boolean }) => ({ +const StyledInput = styled.input({}, (props: { focused: boolean; valid?: boolean }) => ({ ...inputTextStyles, backgroundColor: 'transparent', border: 'none', width: '100%', height: '100%', - color: props.valid !== false ? colors.white : colors.red, + color: props.valid === false ? colors.red : props.focused ? colors.blue : colors.white, '::placeholder': { - color: colors.white60, + color: props.focused ? colors.blue60 : colors.white60, }, })); -const StyledAutoSizingTextInputContainer = styled.div({ - position: 'relative', -}); - -const StyledAutoSizingTextInputFiller = styled.pre({ - ...inputTextStyles, - minWidth: '80px', - color: 'transparent', -}); - -const StyledAutoSizingTextInputWrapper = styled.div({ - position: 'absolute', - top: '0px', - left: '0px', - width: '100%', - height: '100%', -}); - interface IInputProps extends React.InputHTMLAttributes<HTMLInputElement> { value?: string; validateValue?: (value: string) => boolean; @@ -123,6 +99,7 @@ export class Input extends React.Component<IInputProps, IInputState> { ref={this.inputRef} type="text" valid={valid} + focused={this.state.focused} aria-invalid={!valid} onChange={this.onChange} onFocus={this.onFocus} @@ -151,9 +128,12 @@ export class Input extends React.Component<IInputProps, IInputState> { private onBlur = (event: React.FocusEvent<HTMLInputElement>) => { this.setState({ focused: false }); + this.props.onBlur?.(event); - if (this.props.submitOnBlur) { + if (this.props.validateValue?.(this.state.value) !== false && this.props.submitOnBlur) { this.props.onSubmitValue?.(this.state.value); + } else { + this.setState({ value: this.props.value }); } }; @@ -166,8 +146,37 @@ export class Input extends React.Component<IInputProps, IInputState> { }; } -export function AutoSizingTextInput({ onChangeValue, ...otherProps }: IInputProps) { +const InputFrame = styled.div((props: { focused: boolean }) => ({ + display: 'flex', + flexGrow: 0, + backgroundColor: props.focused ? colors.white : 'rgba(255,255,255,0.1)', + borderRadius: '4px', + padding: '4px 8px', +})); + +const StyledAutoSizingTextInputContainer = styled.div({ + position: 'relative', +}); + +const StyledAutoSizingTextInputFiller = styled.pre({ + ...inputTextStyles, + minWidth: '80px', + color: 'transparent', +}); + +const StyledAutoSizingTextInputWrapper = styled.div({ + position: 'absolute', + top: '0px', + left: '0px', + width: '100%', + height: '100%', +}); + +export function AutoSizingTextInput(props: IInputProps) { + const { onChangeValue, onFocus, onBlur, ...otherProps } = props; + const [value, setValue] = useState(otherProps.value ?? ''); + const [focused, setFocused, setBlurred] = useBoolean(false); const onChangeValueWrapper = useCallback( (value: string) => { @@ -177,15 +186,38 @@ export function AutoSizingTextInput({ onChangeValue, ...otherProps }: IInputProp [onChangeValue], ); + const onBlurWrapper = useCallback( + (event: React.FocusEvent<HTMLInputElement>) => { + setBlurred(); + onBlur?.(event); + }, + [onBlur], + ); + + const onFocusWrapper = useCallback( + (event: React.FocusEvent<HTMLInputElement>) => { + setFocused(); + onFocus?.(event); + }, + [onFocus], + ); + return ( - <StyledAutoSizingTextInputContainer> - <StyledAutoSizingTextInputWrapper> - <Input onChangeValue={onChangeValueWrapper} {...otherProps} /> - </StyledAutoSizingTextInputWrapper> - <StyledAutoSizingTextInputFiller className={otherProps.className} aria-hidden={true}> - {value === '' ? otherProps.placeholder : value} - </StyledAutoSizingTextInputFiller> - </StyledAutoSizingTextInputContainer> + <InputFrame focused={focused}> + <StyledAutoSizingTextInputContainer> + <StyledAutoSizingTextInputWrapper> + <Input + onChangeValue={onChangeValueWrapper} + onBlur={onBlurWrapper} + onFocus={onFocusWrapper} + {...otherProps} + /> + </StyledAutoSizingTextInputWrapper> + <StyledAutoSizingTextInputFiller className={otherProps.className} aria-hidden={true}> + {value === '' ? otherProps.placeholder : value} + </StyledAutoSizingTextInputFiller> + </StyledAutoSizingTextInputContainer> + </InputFrame> ); } |
