mirror of
https://github.com/cpvalente/ontime.git
synced 2026-08-20 14:39:06 +00:00
refactor: improve synchronisation of external text
This commit is contained in:
committed by
Carlos Valente
parent
dbd535dd6c
commit
4bc271208e
@@ -1,9 +1,7 @@
|
|||||||
import { useEffect, useRef } from 'react';
|
import { PropsWithChildren, useEffect, useRef, useState } from 'react';
|
||||||
import { IoEye, IoEyeOffOutline } from 'react-icons/io5';
|
|
||||||
import { Input } from '@chakra-ui/react';
|
import { Input } from '@chakra-ui/react';
|
||||||
|
|
||||||
import TooltipActionBtn from '../../../common/components/buttons/TooltipActionBtn';
|
import { cx } from '../../../common/utils/styleUtils';
|
||||||
import { tooltipDelayMid } from '../../../ontimeConfig';
|
|
||||||
|
|
||||||
import style from './InputRow.module.scss';
|
import style from './InputRow.module.scss';
|
||||||
|
|
||||||
@@ -12,50 +10,53 @@ interface InputRowProps {
|
|||||||
placeholder: string;
|
placeholder: string;
|
||||||
text: string;
|
text: string;
|
||||||
visible: boolean;
|
visible: boolean;
|
||||||
actionHandler: () => void;
|
|
||||||
changeHandler: (newValue: string) => void;
|
changeHandler: (newValue: string) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function InputRow(props: InputRowProps) {
|
export default function InputRow(props: PropsWithChildren<InputRowProps>) {
|
||||||
const { label, placeholder, text, visible, actionHandler, changeHandler } = props;
|
const { label, placeholder, text, visible, changeHandler, children } = props;
|
||||||
|
|
||||||
|
const [value, setValue] = useState(text);
|
||||||
const inputRef = useRef<HTMLInputElement>(null);
|
const inputRef = useRef<HTMLInputElement>(null);
|
||||||
const cursorPositionRef = useRef(0);
|
const cursorPositionRef = useRef(0);
|
||||||
|
|
||||||
// sync cursor position with text
|
// sync cursor position with text
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (inputRef.current) {
|
if (inputRef.current && inputRef.current !== document.activeElement) {
|
||||||
inputRef.current.selectionStart = cursorPositionRef.current;
|
inputRef.current.selectionStart = cursorPositionRef.current;
|
||||||
inputRef.current.selectionEnd = cursorPositionRef.current;
|
inputRef.current.selectionEnd = cursorPositionRef.current;
|
||||||
}
|
}
|
||||||
}, [text]);
|
}, [text]);
|
||||||
|
|
||||||
|
// synchronise external text
|
||||||
|
useEffect(() => {
|
||||||
|
if (inputRef.current !== document.activeElement) {
|
||||||
|
setValue(text);
|
||||||
|
}
|
||||||
|
}, [text]);
|
||||||
|
|
||||||
const handleInputChange = (event: React.ChangeEvent<HTMLInputElement>) => {
|
const handleInputChange = (event: React.ChangeEvent<HTMLInputElement>) => {
|
||||||
cursorPositionRef.current = event.target.selectionStart ?? 0;
|
cursorPositionRef.current = event.target.selectionStart ?? 0;
|
||||||
|
setValue(event.target.value);
|
||||||
changeHandler(event.target.value);
|
changeHandler(event.target.value);
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={style.inputRow}>
|
<div className={style.inputRow}>
|
||||||
<label className={`${style.label} ${visible ? style.active : ''}`}>{label}</label>
|
<label className={cx([style.label, visible ?? style.active])} htmlFor={label}>
|
||||||
|
{label}
|
||||||
|
</label>
|
||||||
<div className={style.inputItems}>
|
<div className={style.inputItems}>
|
||||||
<Input
|
<Input
|
||||||
|
id={label}
|
||||||
ref={inputRef}
|
ref={inputRef}
|
||||||
size='sm'
|
size='sm'
|
||||||
variant='ontime-filled'
|
variant='ontime-filled'
|
||||||
value={text}
|
value={value}
|
||||||
onChange={handleInputChange}
|
onChange={handleInputChange}
|
||||||
placeholder={placeholder}
|
placeholder={placeholder}
|
||||||
/>
|
/>
|
||||||
<TooltipActionBtn
|
{children}
|
||||||
clickHandler={actionHandler}
|
|
||||||
tooltip={visible ? 'Make invisible' : 'Make visible'}
|
|
||||||
aria-label={`Toggle ${label}`}
|
|
||||||
openDelay={tooltipDelayMid}
|
|
||||||
icon={visible ? <IoEye size='18px' /> : <IoEyeOffOutline size='18px' />}
|
|
||||||
variant={visible ? 'ontime-filled' : 'ontime-subtle'}
|
|
||||||
size='sm'
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1,4 +1,8 @@
|
|||||||
|
import { IoEye, IoEyeOffOutline } from 'react-icons/io5';
|
||||||
|
|
||||||
|
import TooltipActionBtn from '../../../common/components/buttons/TooltipActionBtn';
|
||||||
import { setMessage, useExternalMessageInput, useTimerMessageInput } from '../../../common/hooks/useSocket';
|
import { setMessage, useExternalMessageInput, useTimerMessageInput } from '../../../common/hooks/useSocket';
|
||||||
|
import { tooltipDelayMid } from '../../../ontimeConfig';
|
||||||
|
|
||||||
import InputRow from './InputRow';
|
import InputRow from './InputRow';
|
||||||
import TimerControlsPreview from './TimerViewControl';
|
import TimerControlsPreview from './TimerViewControl';
|
||||||
@@ -23,8 +27,17 @@ function TimerMessageInput() {
|
|||||||
text={text}
|
text={text}
|
||||||
visible={visible}
|
visible={visible}
|
||||||
changeHandler={(newValue) => setMessage.timerText(newValue)}
|
changeHandler={(newValue) => setMessage.timerText(newValue)}
|
||||||
actionHandler={() => setMessage.timerVisible(!visible)}
|
>
|
||||||
/>
|
<TooltipActionBtn
|
||||||
|
clickHandler={() => setMessage.timerVisible(!visible)}
|
||||||
|
tooltip={visible ? 'Make invisible' : 'Make visible'}
|
||||||
|
aria-label='Toggle timer message visibility'
|
||||||
|
openDelay={tooltipDelayMid}
|
||||||
|
icon={visible ? <IoEye size='18px' /> : <IoEyeOffOutline size='18px' />}
|
||||||
|
variant={visible ? 'ontime-filled' : 'ontime-subtle'}
|
||||||
|
size='sm'
|
||||||
|
/>
|
||||||
|
</InputRow>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -46,7 +59,16 @@ function ExternalInput() {
|
|||||||
text={text}
|
text={text}
|
||||||
visible={visible}
|
visible={visible}
|
||||||
changeHandler={(newValue) => setMessage.externalText(newValue)}
|
changeHandler={(newValue) => setMessage.externalText(newValue)}
|
||||||
actionHandler={toggleExternal}
|
>
|
||||||
/>
|
<TooltipActionBtn
|
||||||
|
clickHandler={toggleExternal}
|
||||||
|
tooltip={visible ? 'Make invisible' : 'Make visible'}
|
||||||
|
aria-label='Toggle external message visibility'
|
||||||
|
openDelay={tooltipDelayMid}
|
||||||
|
icon={visible ? <IoEye size='18px' /> : <IoEyeOffOutline size='18px' />}
|
||||||
|
variant={visible ? 'ontime-filled' : 'ontime-subtle'}
|
||||||
|
size='sm'
|
||||||
|
/>
|
||||||
|
</InputRow>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user