diff --git a/code/modules/tgui_input/number.dm b/code/modules/tgui_input/number.dm index 81964597df7..7f2918d87c7 100644 --- a/code/modules/tgui_input/number.dm +++ b/code/modules/tgui_input/number.dm @@ -119,6 +119,7 @@ data["min_value"] = min_value data["swapped_buttons"] = user.client.prefs.read_preference(/datum/preference/toggle/tgui_input_swapped) data["title"] = title + data["round_value"] = round_value return data /datum/tgui_input_number/ui_data(mob/user) diff --git a/tgui/packages/tgui/components/RestrictedInput.js b/tgui/packages/tgui/components/RestrictedInput.js index ff8cd7b903e..1b082296ca5 100644 --- a/tgui/packages/tgui/components/RestrictedInput.js +++ b/tgui/packages/tgui/components/RestrictedInput.js @@ -8,17 +8,19 @@ const DEFAULT_MIN = 0; const DEFAULT_MAX = 10000; /** - * Takes a string input and parses integers from it. + * Takes a string input and parses integers or floats from it. * If none: Minimum is set. * Else: Clamps it to the given range. */ -const getClampedNumber = (value, minValue, maxValue) => { +const getClampedNumber = (value, minValue, maxValue, allowFloats) => { const minimum = minValue || DEFAULT_MIN; const maximum = maxValue || maxValue === 0 ? maxValue : DEFAULT_MAX; if (!value || !value.length) { return String(minimum); } - let parsedValue = parseInt(value.replace(/[^\-\d]/g, ''), 10); + let parsedValue = allowFloats + ? parseFloat(value.replace(/[^\-\d.]/g, '')) + : parseInt(value.replace(/[^\-\d]/g, ''), 10); if (isNaN(parsedValue)) { return String(minimum); } else { @@ -40,8 +42,13 @@ export class RestrictedInput extends Component { } }; this.handleChange = (e) => { - const { maxValue, minValue, onChange } = this.props; - e.target.value = getClampedNumber(e.target.value, minValue, maxValue); + const { maxValue, minValue, onChange, allowFloats } = this.props; + e.target.value = getClampedNumber( + e.target.value, + minValue, + maxValue, + allowFloats + ); if (onChange) { onChange(e, +e.target.value); } @@ -63,9 +70,14 @@ export class RestrictedInput extends Component { } }; this.handleKeyDown = (e) => { - const { maxValue, minValue, onChange, onEnter } = this.props; + const { maxValue, minValue, onChange, onEnter, allowFloats } = this.props; if (e.keyCode === KEY_ENTER) { - const safeNum = getClampedNumber(e.target.value, minValue, maxValue); + const safeNum = getClampedNumber( + e.target.value, + minValue, + maxValue, + allowFloats + ); this.setEditing(false); if (onChange) { onChange(e, +safeNum); @@ -90,11 +102,16 @@ export class RestrictedInput extends Component { } componentDidMount() { - const { maxValue, minValue } = this.props; + const { maxValue, minValue, allowFloats } = this.props; const nextValue = this.props.value?.toString(); const input = this.inputRef.current; if (input) { - input.value = getClampedNumber(nextValue, minValue, maxValue); + input.value = getClampedNumber( + nextValue, + minValue, + maxValue, + allowFloats + ); } if (this.props.autoFocus || this.props.autoSelect) { setTimeout(() => { @@ -108,14 +125,19 @@ export class RestrictedInput extends Component { } componentDidUpdate(prevProps, _) { - const { maxValue, minValue } = this.props; + const { maxValue, minValue, allowFloats } = this.props; const { editing } = this.state; const prevValue = prevProps.value?.toString(); const nextValue = this.props.value?.toString(); const input = this.inputRef.current; if (input && !editing) { if (nextValue !== prevValue && nextValue !== input.value) { - input.value = getClampedNumber(nextValue, minValue, maxValue); + input.value = getClampedNumber( + nextValue, + minValue, + maxValue, + allowFloats + ); } } } diff --git a/tgui/packages/tgui/interfaces/NumberInputModal.tsx b/tgui/packages/tgui/interfaces/NumberInputModal.tsx index 7b15f4217ed..76f1306d159 100644 --- a/tgui/packages/tgui/interfaces/NumberInputModal.tsx +++ b/tgui/packages/tgui/interfaces/NumberInputModal.tsx @@ -13,6 +13,7 @@ type NumberInputData = { min_value: number | null; timeout: number; title: string; + round_value: boolean; }; export const NumberInputModal = (props, context) => { @@ -71,9 +72,8 @@ export const NumberInputModal = (props, context) => { /** Gets the user input and invalidates if there's a constraint. */ const InputArea = (props, context) => { const { act, data } = useBackend(context); - const { min_value, max_value, init_value } = data; + const { min_value, max_value, init_value, round_value } = data; const { input, onClick, onChange } = props; - return ( @@ -89,6 +89,7 @@ const InputArea = (props, context) => { autoFocus autoSelect fluid + allowFloats={!round_value} minValue={min_value} maxValue={max_value} onChange={(_, value) => onChange(value)}