1
0
Fork 0
mirror of https://git.sr.ht/~ashkeel/strimertul synced 2024-09-20 02:00:49 +00:00

fix: keep cursor in the correct position when cleaning up IDs

fixes #29
This commit is contained in:
Ash Keel 2022-12-01 16:53:48 +01:00
parent fd9dbedfdb
commit 8f5f38a377
No known key found for this signature in database
GPG key ID: BAD8D93E7314ED3E
3 changed files with 50 additions and 4 deletions

View file

@ -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>,
HTMLInputElement
>,
) => {
const { value, onChange, ...rest } = props;
const [cursor, setCursor] = useState<number>(null);
const ref = useRef<HTMLInputElement>(null);
useEffect(() => {
const input = ref.current;
if (input) input.setSelectionRange(cursor, cursor);
}, [ref, cursor, value]);
return (
<input
ref={ref}
value={value}
onChange={(e) => {
setCursor(e.target.selectionStart);
if (onChange) onChange(e);
}}
{...rest}
/>
);
};
export default ControlledInput;

View file

@ -12,6 +12,7 @@ import {
Button, Button,
Checkbox, Checkbox,
CheckboxIndicator, CheckboxIndicator,
ControlledInputBox,
Dialog, Dialog,
DialogActions, DialogActions,
Field, Field,
@ -268,6 +269,7 @@ function GoalItem({
function RewardsPage() { function RewardsPage() {
const { t } = useTranslation(); const { t } = useTranslation();
const dispatch = useAppDispatch(); const dispatch = useAppDispatch();
const [cursorPosition, setCursorPosition] = useState(0);
const [config] = useModule(modules.loyaltyConfig); const [config] = useModule(modules.loyaltyConfig);
const [rewards, setRewards] = useModule(modules.loyaltyRewards); const [rewards, setRewards] = useModule(modules.loyaltyRewards);
const [filter, setFilter] = useState(''); const [filter, setFilter] = useState('');
@ -343,13 +345,17 @@ function RewardsPage() {
<Label htmlFor="reward-id"> <Label htmlFor="reward-id">
{t('pages.loyalty-rewards.reward-id')} {t('pages.loyalty-rewards.reward-id')}
</Label> </Label>
<InputBox <ControlledInputBox
id="reward-id" id="reward-id"
type="text" type="text"
required required
disabled={!dialogReward.new} disabled={!dialogReward.new}
value={dialogReward?.reward?.id} value={dialogReward?.reward?.id}
onFocus={(e) => {
e.target.selectionStart = cursorPosition;
}}
onChange={(e) => { onChange={(e) => {
setCursorPosition(e.target.selectionStart);
setDialogReward({ setDialogReward({
...dialogReward, ...dialogReward,
reward: { reward: {
@ -671,7 +677,7 @@ function GoalsPage() {
<Label htmlFor="goal-id"> <Label htmlFor="goal-id">
{t('pages.loyalty-rewards.goal-id')} {t('pages.loyalty-rewards.goal-id')}
</Label> </Label>
<InputBox <ControlledInputBox
id="goal-id" id="goal-id"
type="text" type="text"
required required

View file

@ -1,8 +1,10 @@
import * as UnstyledLabel from '@radix-ui/react-label'; import * as UnstyledLabel from '@radix-ui/react-label';
import * as CheckboxPrimitive from '@radix-ui/react-checkbox'; import * as CheckboxPrimitive from '@radix-ui/react-checkbox';
import * as ToggleGroup from '@radix-ui/react-toggle-group'; import * as ToggleGroup from '@radix-ui/react-toggle-group';
import { CSS } from '@stitches/react';
import { styled } from './theme'; import { styled } from './theme';
import { theme } from '.'; import { theme } from '.';
import ControlledInput from '../components/utils/ControlledInput';
export const Field = styled('fieldset', { export const Field = styled('fieldset', {
all: 'unset', all: 'unset',
@ -45,7 +47,7 @@ export const Label = styled(UnstyledLabel.Root, {
fontWeight: 'bold', fontWeight: 'bold',
}); });
export const InputBox = styled('input', { const inputStyles: CSS = {
all: 'unset', all: 'unset',
fontWeight: '300', fontWeight: '300',
border: '1px solid $gray6', border: '1px solid $gray6',
@ -74,7 +76,10 @@ export const InputBox = styled('input', {
}, },
}, },
}, },
}); };
export const InputBox = styled('input', inputStyles);
export const ControlledInputBox = styled(ControlledInput, inputStyles);
export const Textarea = styled('textarea', { export const Textarea = styled('textarea', {
all: 'unset', all: 'unset',