1
0
Fork 0
mirror of https://git.sr.ht/~ashkeel/strimertul synced 2024-09-18 01:50:50 +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,
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() {
<Label htmlFor="reward-id">
{t('pages.loyalty-rewards.reward-id')}
</Label>
<InputBox
<ControlledInputBox
id="reward-id"
type="text"
required
disabled={!dialogReward.new}
value={dialogReward?.reward?.id}
onFocus={(e) => {
e.target.selectionStart = cursorPosition;
}}
onChange={(e) => {
setCursorPosition(e.target.selectionStart);
setDialogReward({
...dialogReward,
reward: {
@ -671,7 +677,7 @@ function GoalsPage() {
<Label htmlFor="goal-id">
{t('pages.loyalty-rewards.goal-id')}
</Label>
<InputBox
<ControlledInputBox
id="goal-id"
type="text"
required

View file

@ -1,8 +1,10 @@
import * as UnstyledLabel from '@radix-ui/react-label';
import * as CheckboxPrimitive from '@radix-ui/react-checkbox';
import * as ToggleGroup from '@radix-ui/react-toggle-group';
import { CSS } from '@stitches/react';
import { styled } from './theme';
import { theme } from '.';
import ControlledInput from '../components/utils/ControlledInput';
export const Field = styled('fieldset', {
all: 'unset',
@ -45,7 +47,7 @@ export const Label = styled(UnstyledLabel.Root, {
fontWeight: 'bold',
});
export const InputBox = styled('input', {
const inputStyles: CSS = {
all: 'unset',
fontWeight: '300',
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', {
all: 'unset',