diff --git a/arduino-ide-extension/src/browser/dialogs/settings/settings-component.tsx b/arduino-ide-extension/src/browser/dialogs/settings/settings-component.tsx
index bbc73b8c3..3138c7242 100644
--- a/arduino-ide-extension/src/browser/dialogs/settings/settings-component.tsx
+++ b/arduino-ide-extension/src/browser/dialogs/settings/settings-component.tsx
@@ -180,7 +180,8 @@ export class SettingsComponent extends React.Component<
diff --git a/arduino-ide-extension/src/browser/dialogs/settings/settings-step-input.tsx b/arduino-ide-extension/src/browser/dialogs/settings/settings-step-input.tsx
index e6eef4b9c..1470ec192 100644
--- a/arduino-ide-extension/src/browser/dialogs/settings/settings-step-input.tsx
+++ b/arduino-ide-extension/src/browser/dialogs/settings/settings-step-input.tsx
@@ -2,7 +2,7 @@ import * as React from '@theia/core/shared/react';
import classnames from 'classnames';
interface SettingsStepInputProps {
- value: number;
+ initialValue: number;
setSettingsStateValue: (value: number) => void;
step: number;
maxValue: number;
@@ -15,7 +15,7 @@ const SettingsStepInput: React.FC
= (
props: SettingsStepInputProps
) => {
const {
- value,
+ initialValue,
setSettingsStateValue,
step,
maxValue,
@@ -24,18 +24,35 @@ const SettingsStepInput: React.FC = (
classNames,
} = props;
+ const [valueState, setValueState] = React.useState<{
+ currentValue: number;
+ isEmptyString: boolean;
+ }>({
+ currentValue: initialValue,
+ isEmptyString: false,
+ });
+ const { currentValue, isEmptyString } = valueState;
+
const clamp = (value: number, min: number, max: number): number => {
return Math.min(Math.max(value, min), max);
};
+ const resetToInitialState = (): void => {
+ setValueState({
+ currentValue: initialValue,
+ isEmptyString: false,
+ });
+ };
+
const onStep = (
roundingOperation: 'ceil' | 'floor',
stepOperation: (a: number, b: number) => number
): void => {
- const valueRoundedToScale = Math[roundingOperation](value / step) * step;
+ const valueRoundedToScale =
+ Math[roundingOperation](currentValue / step) * step;
const calculatedValue =
- valueRoundedToScale === value
- ? stepOperation(value, step)
+ valueRoundedToScale === currentValue
+ ? stepOperation(currentValue, step)
: valueRoundedToScale;
const newValue = clamp(calculatedValue, minValue, maxValue);
@@ -52,33 +69,53 @@ const SettingsStepInput: React.FC = (
const onUserInput = (event: React.ChangeEvent): void => {
const { value: eventValue } = event.target;
+ setValueState({
+ currentValue: Number(eventValue),
+ isEmptyString: eventValue === '',
+ });
+ };
- if (eventValue === '') {
- setSettingsStateValue(0);
+ /* Prevent the user from entering invalid values */
+ const onBlur = (event: React.FocusEvent): void => {
+ if (
+ (currentValue === initialValue && !isEmptyString) ||
+ event.currentTarget.contains(event.relatedTarget as Node)
+ ) {
+ return;
}
- const number = Number(eventValue);
-
- if (!isNaN(number) && number !== value) {
- const newValue = clamp(number, minValue, maxValue);
-
- setSettingsStateValue(newValue);
+ const clampedValue = clamp(currentValue, minValue, maxValue);
+ if (clampedValue === initialValue || isNaN(currentValue) || isEmptyString) {
+ resetToInitialState();
+ return;
}
+
+ setSettingsStateValue(clampedValue);
};
- const upDisabled = value >= maxValue;
- const downDisabled = value <= minValue;
+ const valueIsNotWithinRange =
+ currentValue < minValue || currentValue > maxValue;
+ const isDisabledException =
+ valueIsNotWithinRange || isEmptyString || isNaN(currentValue);
+
+ const upDisabled = isDisabledException || currentValue >= maxValue;
+ const downDisabled = isDisabledException || currentValue <= minValue;
return (
-
+
-
+