feat: dont moove slider cursor if tcp command fails
This commit is contained in:
@@ -13,8 +13,8 @@ type VerticalSliderProps = {
|
||||
switchStepValue?: number;
|
||||
switchStep?: number;
|
||||
|
||||
value?: number;
|
||||
onChange?: (value: number) => void;
|
||||
value: number;
|
||||
onChange?: (value: number) => Promise<boolean>;
|
||||
|
||||
unit?: string;
|
||||
|
||||
@@ -34,23 +34,18 @@ export default function VerticalSlider({
|
||||
step,
|
||||
switchStepValue,
|
||||
switchStep,
|
||||
value: controlledValue,
|
||||
value,
|
||||
onChange,
|
||||
unit = '',
|
||||
className,
|
||||
style,
|
||||
}: VerticalSliderProps) {
|
||||
const [internalValue, setInternalValue] = useState(min);
|
||||
const value = controlledValue ?? internalValue;
|
||||
|
||||
const [editingText, setEditingText] = useState<string | null>(null);
|
||||
const inputRef = useRef<HTMLInputElement>(null);
|
||||
const sliderRef = useRef<HTMLDivElement>(null);
|
||||
const lastValue = useRef(value);
|
||||
const keyboardValue = useRef<number | null>(null);
|
||||
const [displayValue, setDisplayValue] = useState(value);
|
||||
const dragValue = useRef(value);
|
||||
const rafRef = useRef<number | null>(null);
|
||||
const dragging = useRef(false);
|
||||
const thumbRef = useRef<HTMLDivElement>(null);
|
||||
const keyboardEditing = useRef(false);
|
||||
@@ -74,16 +69,20 @@ export default function VerticalSlider({
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
if (dragging.current) return;
|
||||
if (keyboardEditing.current) return;
|
||||
|
||||
setDisplayValue(value);
|
||||
dragValue.current = value;
|
||||
}, [value]);
|
||||
|
||||
const currentStep =
|
||||
switchStepValue !== undefined && switchStep !== undefined && value >= switchStepValue
|
||||
? switchStep
|
||||
: step;
|
||||
function getStep(value: number) {
|
||||
if (switchStepValue !== undefined && switchStep !== undefined && value >= switchStepValue) {
|
||||
return switchStep;
|
||||
}
|
||||
|
||||
return step;
|
||||
}
|
||||
|
||||
const decimals = useMemo(
|
||||
() => Math.max(getDecimals(step), switchStep !== undefined ? getDecimals(switchStep) : 0),
|
||||
@@ -92,30 +91,25 @@ export default function VerticalSlider({
|
||||
|
||||
function normalizeValue(input: number) {
|
||||
const clamped = Math.min(max, Math.max(min, input));
|
||||
const snapped = Math.round(clamped / currentStep) * currentStep;
|
||||
return Number(snapped.toFixed(6));
|
||||
|
||||
const currentStep = getStep(clamped);
|
||||
|
||||
const snapped = min + Math.round((clamped - min) / currentStep) * currentStep;
|
||||
|
||||
return Number(Math.min(max, Math.max(min, snapped)).toFixed(6));
|
||||
}
|
||||
|
||||
function updateValue(v: number) {
|
||||
const next = normalizeValue(v);
|
||||
function updateValue(input: number) {
|
||||
const next = normalizeValue(input);
|
||||
|
||||
dragValue.current = next;
|
||||
lastValue.current = next;
|
||||
|
||||
if (thumbRef.current) {
|
||||
const percent = (next - min) / (max - min);
|
||||
thumbRef.current.style.bottom = `${percent * 100}%`;
|
||||
}
|
||||
|
||||
if (rafRef.current === null) {
|
||||
rafRef.current = requestAnimationFrame(() => {
|
||||
setDisplayValue(dragValue.current);
|
||||
rafRef.current = null;
|
||||
});
|
||||
}
|
||||
setDisplayValue(next);
|
||||
}
|
||||
|
||||
function handleKeyDown(e: React.KeyboardEvent<HTMLDivElement>) {
|
||||
if (!['ArrowUp', 'ArrowDown', 'ArrowLeft', 'ArrowRight'].includes(e.key)) return;
|
||||
if (!['ArrowUp', 'ArrowDown', 'ArrowLeft', 'ArrowRight'].includes(e.key)) {
|
||||
return;
|
||||
}
|
||||
|
||||
keyboardEditing.current = true;
|
||||
|
||||
@@ -123,33 +117,39 @@ export default function VerticalSlider({
|
||||
|
||||
const base = keyboardValue.current ?? value;
|
||||
|
||||
const currentStep = getStep(base);
|
||||
|
||||
let next = base;
|
||||
|
||||
if (e.key === 'ArrowUp' || e.key === 'ArrowRight') next += currentStep;
|
||||
if (e.key === 'ArrowUp' || e.key === 'ArrowRight') {
|
||||
next += currentStep;
|
||||
}
|
||||
|
||||
if (e.key === 'ArrowDown' || e.key === 'ArrowLeft') next -= currentStep;
|
||||
if (e.key === 'ArrowDown' || e.key === 'ArrowLeft') {
|
||||
next -= currentStep;
|
||||
}
|
||||
|
||||
next = normalizeValue(next);
|
||||
|
||||
keyboardValue.current = next;
|
||||
|
||||
updateValue(next); // updates displayValue only
|
||||
updateValue(next);
|
||||
}
|
||||
|
||||
function handleKeyUp() {
|
||||
async function handleKeyUp() {
|
||||
if (keyboardValue.current == null) return;
|
||||
|
||||
keyboardEditing.current = false;
|
||||
|
||||
const next = keyboardValue.current;
|
||||
|
||||
if (controlledValue === undefined) {
|
||||
setInternalValue(next);
|
||||
}
|
||||
|
||||
onChange?.(next);
|
||||
const success = await onChange?.(next);
|
||||
|
||||
keyboardEditing.current = false;
|
||||
keyboardValue.current = null;
|
||||
|
||||
if (success === false) {
|
||||
setDisplayValue(value);
|
||||
dragValue.current = value;
|
||||
}
|
||||
}
|
||||
|
||||
function valueFromPointer(clientY: number) {
|
||||
@@ -172,28 +172,47 @@ export default function VerticalSlider({
|
||||
valueFromPointer(e.clientY);
|
||||
}
|
||||
|
||||
function endDrag(e: React.PointerEvent<HTMLDivElement>) {
|
||||
dragging.current = false;
|
||||
async function endDrag(e: React.PointerEvent<HTMLDivElement>) {
|
||||
if (!dragging.current) return;
|
||||
|
||||
const finalValue = dragValue.current;
|
||||
|
||||
if (controlledValue === undefined) setInternalValue(finalValue);
|
||||
setDisplayValue(finalValue);
|
||||
onChange?.(finalValue);
|
||||
const success = await onChange?.(finalValue);
|
||||
|
||||
dragging.current = false;
|
||||
|
||||
if (success === false) {
|
||||
setDisplayValue(value);
|
||||
dragValue.current = value;
|
||||
}
|
||||
|
||||
if (e.currentTarget.hasPointerCapture(e.pointerId)) {
|
||||
e.currentTarget.releasePointerCapture(e.pointerId);
|
||||
}
|
||||
}
|
||||
|
||||
function commitEditing() {
|
||||
async function commitEditing() {
|
||||
if (editingText !== null && editingText !== '' && editingText !== '-') {
|
||||
const parsed = Number(editingText);
|
||||
if (!Number.isNaN(parsed)) updateValue(parsed);
|
||||
|
||||
if (!Number.isNaN(parsed)) {
|
||||
const next = normalizeValue(parsed);
|
||||
|
||||
setDisplayValue(next);
|
||||
|
||||
const success = await onChange?.(next);
|
||||
|
||||
if (success === false) {
|
||||
setDisplayValue(value);
|
||||
dragValue.current = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
setEditingText(null);
|
||||
}
|
||||
|
||||
const percent = (value - min) / (max - min);
|
||||
const percent = (displayValue - min) / (max - min);
|
||||
|
||||
return (
|
||||
<div
|
||||
|
||||
Reference in New Issue
Block a user