mirror of
https://github.com/tiqi-group/pydase.git
synced 2025-06-05 13:10:41 +02:00
feat: selection range in NumberComponent can be changed using Shift and arrows
When pressing shift, the arrow keys can be used to change the selection range. This was done by using a cursor position reference instead of a state and adapting the default behaviour of the arrow keys instead of writing them from scratch.
This commit is contained in:
parent
04a3b225f8
commit
c327215b5f
@ -1,4 +1,4 @@
|
|||||||
import React, { useEffect, useState } from "react";
|
import React, { useEffect, useRef, useState } from "react";
|
||||||
import { Form, InputGroup } from "react-bootstrap";
|
import { Form, InputGroup } from "react-bootstrap";
|
||||||
import { DocStringComponent } from "./DocStringComponent";
|
import { DocStringComponent } from "./DocStringComponent";
|
||||||
import "../App.css";
|
import "../App.css";
|
||||||
@ -175,6 +175,33 @@ const handleNumericKey = (
|
|||||||
return { value: newValue, selectionStart: selectionStart + 1 };
|
return { value: newValue, selectionStart: selectionStart + 1 };
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calculates the new cursor position after moving left by a specified step size.
|
||||||
|
*
|
||||||
|
* @param cursorPosition - The current position of the cursor.
|
||||||
|
* @param step - The number of positions to move left.
|
||||||
|
* @returns The new cursor position, clamped to a minimum of 0.
|
||||||
|
*/
|
||||||
|
const getCursorLeftPosition = (cursorPosition: number, step: number): number => {
|
||||||
|
return Math.max(0, cursorPosition - step);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calculates the new cursor position after moving right by a specified step size.
|
||||||
|
*
|
||||||
|
* @param cursorPosition - The current position of the cursor.
|
||||||
|
* @param step - The number of positions to move right.
|
||||||
|
* @param maxPosition - The maximum allowed cursor position (e.g., value.length).
|
||||||
|
* @returns The new cursor position, clamped to a maximum of maxPosition.
|
||||||
|
*/
|
||||||
|
const getCursorRightPosition = (
|
||||||
|
cursorPosition: number,
|
||||||
|
step: number,
|
||||||
|
maxPosition: number,
|
||||||
|
): number => {
|
||||||
|
return Math.min(maxPosition, cursorPosition + step);
|
||||||
|
};
|
||||||
|
|
||||||
export const NumberComponent = React.memo((props: NumberComponentProps) => {
|
export const NumberComponent = React.memo((props: NumberComponentProps) => {
|
||||||
const {
|
const {
|
||||||
fullAccessPath,
|
fullAccessPath,
|
||||||
@ -191,7 +218,8 @@ export const NumberComponent = React.memo((props: NumberComponentProps) => {
|
|||||||
} = props;
|
} = props;
|
||||||
|
|
||||||
// Create a state for the cursor position
|
// Create a state for the cursor position
|
||||||
const [cursorPosition, setCursorPosition] = useState<number | null>(null);
|
const cursorPositionRef = useRef<number | null>(null);
|
||||||
|
|
||||||
// Create a state for the input string
|
// Create a state for the input string
|
||||||
const [inputString, setInputString] = useState(value.toString());
|
const [inputString, setInputString] = useState(value.toString());
|
||||||
const renderCount = useRenderCount();
|
const renderCount = useRenderCount();
|
||||||
@ -200,26 +228,40 @@ export const NumberComponent = React.memo((props: NumberComponentProps) => {
|
|||||||
const { key, target } = event;
|
const { key, target } = event;
|
||||||
|
|
||||||
const inputTarget = target as HTMLInputElement;
|
const inputTarget = target as HTMLInputElement;
|
||||||
if (key === "F1" || key === "F5" || key === "F12" || key === "Tab") {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
event.preventDefault();
|
|
||||||
|
|
||||||
// Get the current input value and cursor position
|
// Get the current input value and cursor position
|
||||||
const { value } = inputTarget;
|
const { value } = inputTarget;
|
||||||
|
const valueLength = value.length;
|
||||||
const selectionEnd = inputTarget.selectionEnd ?? 0;
|
const selectionEnd = inputTarget.selectionEnd ?? 0;
|
||||||
let selectionStart = inputTarget.selectionStart ?? 0;
|
let selectionStart = inputTarget.selectionStart ?? 0;
|
||||||
|
|
||||||
|
if (key === "F1" || key === "F5" || key === "F12" || key === "Tab") {
|
||||||
|
return;
|
||||||
|
} else if (key === "ArrowLeft" || key === "ArrowRight") {
|
||||||
|
const hasSelection = selectionEnd > selectionStart;
|
||||||
|
|
||||||
|
if (hasSelection && !event.shiftKey) {
|
||||||
|
// Collapse selection: ArrowLeft -> start, ArrowRight -> end
|
||||||
|
const collapseTo = key === "ArrowLeft" ? selectionStart : selectionEnd;
|
||||||
|
cursorPositionRef.current = collapseTo;
|
||||||
|
} else {
|
||||||
|
// No selection or shift key is pressed, just move cursor by one
|
||||||
|
const newSelectionStart =
|
||||||
|
key === "ArrowLeft"
|
||||||
|
? getCursorLeftPosition(selectionStart, 1)
|
||||||
|
: getCursorRightPosition(selectionEnd, 1, valueLength);
|
||||||
|
|
||||||
|
cursorPositionRef.current = newSelectionStart;
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
event.preventDefault();
|
||||||
|
|
||||||
let newValue: string = value;
|
let newValue: string = value;
|
||||||
if (event.ctrlKey && key === "a") {
|
if (event.ctrlKey && key === "a") {
|
||||||
// Select everything when pressing Ctrl + a
|
// Select everything when pressing Ctrl + a
|
||||||
inputTarget.setSelectionRange(0, value.length);
|
inputTarget.setSelectionRange(0, value.length);
|
||||||
return;
|
return;
|
||||||
} else if (key === "ArrowRight" || key === "ArrowLeft") {
|
|
||||||
// Move the cursor with the arrow keys and store its position
|
|
||||||
selectionStart = key === "ArrowRight" ? selectionStart + 1 : selectionStart - 1;
|
|
||||||
setCursorPosition(selectionStart);
|
|
||||||
return;
|
|
||||||
} else if ((key >= "0" && key <= "9") || key === "-") {
|
} else if ((key >= "0" && key <= "9") || key === "-") {
|
||||||
// Check if a number key or a decimal point key is pressed
|
// Check if a number key or a decimal point key is pressed
|
||||||
({ value: newValue, selectionStart } = handleNumericKey(
|
({ value: newValue, selectionStart } = handleNumericKey(
|
||||||
@ -314,7 +356,7 @@ export const NumberComponent = React.memo((props: NumberComponentProps) => {
|
|||||||
setInputString(newValue);
|
setInputString(newValue);
|
||||||
|
|
||||||
// Save the current cursor position before the component re-renders
|
// Save the current cursor position before the component re-renders
|
||||||
setCursorPosition(selectionStart);
|
cursorPositionRef.current = selectionStart;
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleBlur = () => {
|
const handleBlur = () => {
|
||||||
@ -367,8 +409,11 @@ export const NumberComponent = React.memo((props: NumberComponentProps) => {
|
|||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
// Set the cursor position after the component re-renders
|
// Set the cursor position after the component re-renders
|
||||||
const inputElement = document.getElementsByName(id)[0] as HTMLInputElement;
|
const inputElement = document.getElementsByName(id)[0] as HTMLInputElement;
|
||||||
if (inputElement && cursorPosition !== null) {
|
if (inputElement && cursorPositionRef.current !== null) {
|
||||||
inputElement.setSelectionRange(cursorPosition, cursorPosition);
|
inputElement.setSelectionRange(
|
||||||
|
cursorPositionRef.current,
|
||||||
|
cursorPositionRef.current,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user