Skip to content

Commit

Permalink
[preferences]: Input field validation
Browse files Browse the repository at this point in the history
Fixes: eclipse-theia#7741

Added an input field validation in the preference widget.
Updated the input field type to be `number` instead of `text` for
numerical fields.

Signed-off-by: Anas Shahid <[email protected]>
  • Loading branch information
Anas Shahid committed Jul 28, 2020
1 parent fd23988 commit 87dfa46
Show file tree
Hide file tree
Showing 2 changed files with 73 additions and 11 deletions.
29 changes: 29 additions & 0 deletions packages/preferences/src/browser/style/index.css
Original file line number Diff line number Diff line change
Expand Up @@ -299,6 +299,35 @@
outline-width: 2px;
}

.theia-settings-container .theia-input[type="number"]:focus {
outline-width: 2px;
}

.theia-settings-container .theia-input[type="number"] {
-webkit-appearance: textfield;
border: 1px solid var(--theia-dropdown-border);
}

.theia-settings-container input::-webkit-outer-spin-button,
.theia-settings-container input::-webkit-inner-spin-button {
-webkit-appearance: none;
margin: 0;
}

.theia-settings-container .pref-content-container .pref-input .pref-input-container .pref-error-notification {
border-style: solid;
border-color: var(--theia-inputValidation-errorBorder);
background-color: var(--theia-inputValidation-errorBackground);
width: 100%;
box-sizing: border-box;
padding: var(--theia-ui-padding);
}

.theia-settings-container .pref-content-container .pref-input .pref-input-container {
display: flex;
flex-direction: column;
}

.theia-settings-container .pref-content-container a.theia-json-input {
text-decoration: underline;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,27 +31,60 @@ export const PreferenceNumberInput: React.FC<PreferenceNumberInputProps> = ({ pr

const [currentTimeout, setCurrentTimetout] = React.useState<number>(0);
const [currentValue, setCurrentValue] = React.useState<string>(externalValue);
const [currentMessage, setCurrentMessage] = React.useState<string>('');
const [isErrorMessageVisible, setErrorMessageVisibility] = React.useState<boolean>(false);

React.useEffect(() => {
setCurrentValue(externalValue);
}, [externalValue]);

const onChange = React.useCallback(e => {
const { value: newValue } = e.target;
clearTimeout(currentTimeout);
const newTimeout = setTimeout(() => setPreference(id, Number(newValue)), 750);
setCurrentTimetout(Number(newTimeout));
const { value: newValue } = e.target;
setCurrentValue(newValue);
const preferenceValue: number = Number(newValue);
const { isValid, message } = getErrorMessage(preferenceValue);
setCurrentMessage(message);
setErrorMessageVisibility(!isValid);
if (isValid) {
const newTimeout = setTimeout(() => setPreference(id, preferenceValue), 750);
setCurrentTimetout(Number(newTimeout));
}
}, [currentTimeout]);

const onBlur = () => setErrorMessageVisibility(false);
const onFocus = () => setErrorMessageVisibility(!!currentMessage.length);

/**
* Validates the input.
* @param input the input value.
*/
const getErrorMessage = (input: number | undefined): { isValid: boolean, message: string } => {
if (!input) {
return { isValid: false, message: 'Value must be a number.' };
} else if (data.minimum && input < data.minimum) {
return { isValid: false, message: `Value must be greater than or equal to ${data.minimum}.` };
} else if (data.maximum && input > data.maximum) {
return { isValid: false, message: `Value must be less than or equal to ${data.maximum}.` };
} else if (data.type === 'integer' && input % 1 !== 0) {
return { isValid: false, message: 'Value must be an integer.' };
}
return { isValid: true, message: '' };
};

return (
<input
type="text"
className="theia-input"
pattern="[0-9]*"
value={currentValue}
onChange={onChange}
data-preference-id={id}
/>
<div className='pref-input-container'>
<input
type="number"
className="theia-input"
pattern="[0-9]*"
value={currentValue}
onChange={onChange}
onBlur={onBlur}
onFocus={onFocus}
data-preference-id={id}
/>
{isErrorMessageVisible ? <div className='pref-error-notification'>{currentMessage}</div> : undefined}
</div>
);
};

0 comments on commit 87dfa46

Please sign in to comment.