From b2caa84f0ec48815eec57d6579b49492fac67854 Mon Sep 17 00:00:00 2001 From: paulrpg Date: Sat, 3 Feb 2024 18:06:44 +0000 Subject: [PATCH 1/2] fix input number issue, migrated from tg and fixed upstream issue --- .../tgui/components/RestrictedInput.jsx | 63 +++++++++++++------ .../tgui/interfaces/NumberInputModal.tsx | 2 +- 2 files changed, 44 insertions(+), 21 deletions(-) diff --git a/tgui/packages/tgui/components/RestrictedInput.jsx b/tgui/packages/tgui/components/RestrictedInput.jsx index 082fc606d998..f61025039f34 100644 --- a/tgui/packages/tgui/components/RestrictedInput.jsx +++ b/tgui/packages/tgui/components/RestrictedInput.jsx @@ -1,48 +1,56 @@ -import { classes } from 'common/react'; +import { KEY_ENTER, KEY_ESCAPE } from 'common/keycodes'; import { clamp } from 'common/math'; +import { classes } from 'common/react'; import { Component, createRef } from 'react'; + import { Box } from './Box'; -import { KEY_ESCAPE, KEY_ENTER } from 'common/keycodes'; -const DEFAULT_MIN = -16777216; -const DEFAULT_MAX = 16777216; +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; - const defaultValue = maximum < 0 ? minimum : minimum > 0 ? minimum : 0; if (!value || !value.length) { - return String(defaultValue); + return String(minimum); } - let parsedValue = parseFloat(value.replace(/[^\-.\d]/g, ''), 10); + let parsedValue = allowFloats + ? parseFloat(value.replace(/[^\-\d.]/g, '')) + : parseInt(value.replace(/[^\-\d]/g, ''), 10); if (isNaN(parsedValue)) { - return String(defaultValue); + return String(minimum); } else { return String(clamp(parsedValue, minimum, maximum)); } }; export class RestrictedInput extends Component { - constructor() { - super(); + constructor(props) { + super(props); this.inputRef = createRef(); this.state = { editing: false, }; this.handleBlur = (e) => { + const { maxValue, minValue, allowFloats } = this.props; const { editing } = this.state; if (editing) { + e.target.value = getClampedNumber( + e.target.value, + minValue, + maxValue, + allowFloats + ); this.setEditing(false); } }; this.handleChange = (e) => { - const { maxValue, minValue, onChange } = this.props; - e.target.value = getClampedNumber(e.target.value, minValue, maxValue); + const { onChange } = this.props; if (onChange) { onChange(e, +e.target.value); } @@ -64,9 +72,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); @@ -91,11 +104,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(() => { @@ -109,14 +127,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 eff7acb62a1b..64895a1a2738 100644 --- a/tgui/packages/tgui/interfaces/NumberInputModal.tsx +++ b/tgui/packages/tgui/interfaces/NumberInputModal.tsx @@ -15,7 +15,7 @@ type NumberInputData = { title: string; }; -export const NumberInputModal = (props) => { +export const NumberInputModal = () => { const { act, data } = useBackend(); const { init_value, large_buttons, message = '', timeout, title } = data; const [input, setInput] = useLocalState('input', init_value); From 73cd7734fc7ca9f9d032cc441e5457b58d96b58e Mon Sep 17 00:00:00 2001 From: paulrpg Date: Mon, 5 Feb 2024 18:02:34 +0000 Subject: [PATCH 2/2] resolve decimal place issue --- code/modules/tgui/tgui_number_input.dm | 1 + .../tgui/interfaces/NumberInputModal.tsx | 20 ++++++++++++++++--- 2 files changed, 18 insertions(+), 3 deletions(-) diff --git a/code/modules/tgui/tgui_number_input.dm b/code/modules/tgui/tgui_number_input.dm index aa189b1d2039..81be13f48730 100644 --- a/code/modules/tgui/tgui_number_input.dm +++ b/code/modules/tgui/tgui_number_input.dm @@ -145,6 +145,7 @@ "min_value" = min_value, "preferences" = list(), "title" = title, + "integer_only" = integer_only ) /datum/tgui_input_number/ui_data(mob/user) diff --git a/tgui/packages/tgui/interfaces/NumberInputModal.tsx b/tgui/packages/tgui/interfaces/NumberInputModal.tsx index 64895a1a2738..32d7161d8faf 100644 --- a/tgui/packages/tgui/interfaces/NumberInputModal.tsx +++ b/tgui/packages/tgui/interfaces/NumberInputModal.tsx @@ -13,11 +13,19 @@ type NumberInputData = { min_value: number | null; timeout: number; title: string; + integer_only: 0 | 1; }; export const NumberInputModal = () => { const { act, data } = useBackend(); - const { init_value, large_buttons, message = '', timeout, title } = data; + const { + init_value, + large_buttons, + message = '', + timeout, + title, + integer_only, + } = data; const [input, setInput] = useLocalState('input', init_value); const onChange = (value: number) => { if (value === input) { @@ -56,7 +64,12 @@ export const NumberInputModal = () => { {message} - + @@ -72,7 +85,7 @@ export const NumberInputModal = () => { const InputArea = (props) => { const { act, data } = useBackend(); const { min_value, max_value, init_value } = data; - const { input, onClick, onChange } = props; + const { input, onClick, onChange, integer_only } = props; return ( @@ -94,6 +107,7 @@ const InputArea = (props) => { onChange={(_, value) => onChange(value)} onEnter={(_, value) => act('submit', { entry: value })} value={input} + allowFloats={integer_only === 1 ? false : true} />