From 8f5f38a37713838daa72e64c96e3494bf78b6ea9 Mon Sep 17 00:00:00 2001 From: Ash Keel Date: Thu, 1 Dec 2022 16:53:48 +0100 Subject: [PATCH] fix: keep cursor in the correct position when cleaning up IDs fixes #29 --- .../ui/components/utils/ControlledInput.tsx | 35 +++++++++++++++++++ frontend/src/ui/pages/LoyaltyRewards.tsx | 10 ++++-- frontend/src/ui/theme/forms.ts | 9 +++-- 3 files changed, 50 insertions(+), 4 deletions(-) create mode 100644 frontend/src/ui/components/utils/ControlledInput.tsx diff --git a/frontend/src/ui/components/utils/ControlledInput.tsx b/frontend/src/ui/components/utils/ControlledInput.tsx new file mode 100644 index 0000000..1fd807d --- /dev/null +++ b/frontend/src/ui/components/utils/ControlledInput.tsx @@ -0,0 +1,35 @@ +// From https://stackoverflow.com/a/68928267 +// Allows to have a input with text manipulation (e.g. sanitation) without +// messing with the cursor + +import React, { useState, useRef, useEffect } from 'react'; + +const ControlledInput = ( + props: React.DetailedHTMLProps< + React.InputHTMLAttributes, + HTMLInputElement + >, +) => { + const { value, onChange, ...rest } = props; + const [cursor, setCursor] = useState(null); + const ref = useRef(null); + + useEffect(() => { + const input = ref.current; + if (input) input.setSelectionRange(cursor, cursor); + }, [ref, cursor, value]); + + return ( + { + setCursor(e.target.selectionStart); + if (onChange) onChange(e); + }} + {...rest} + /> + ); +}; + +export default ControlledInput; diff --git a/frontend/src/ui/pages/LoyaltyRewards.tsx b/frontend/src/ui/pages/LoyaltyRewards.tsx index 4c605d2..fd0d36f 100644 --- a/frontend/src/ui/pages/LoyaltyRewards.tsx +++ b/frontend/src/ui/pages/LoyaltyRewards.tsx @@ -12,6 +12,7 @@ import { Button, Checkbox, CheckboxIndicator, + ControlledInputBox, Dialog, DialogActions, Field, @@ -268,6 +269,7 @@ function GoalItem({ function RewardsPage() { const { t } = useTranslation(); const dispatch = useAppDispatch(); + const [cursorPosition, setCursorPosition] = useState(0); const [config] = useModule(modules.loyaltyConfig); const [rewards, setRewards] = useModule(modules.loyaltyRewards); const [filter, setFilter] = useState(''); @@ -343,13 +345,17 @@ function RewardsPage() { - { + e.target.selectionStart = cursorPosition; + }} onChange={(e) => { + setCursorPosition(e.target.selectionStart); setDialogReward({ ...dialogReward, reward: { @@ -671,7 +677,7 @@ function GoalsPage() { -