Make nodes editable: norms, goals and keyword triggers
This commit is contained in:
committed by
Gerla, J. (Justin)
parent
f534f0cefa
commit
aeaf526797
27
src/components/TextField.module.css
Normal file
27
src/components/TextField.module.css
Normal file
@@ -0,0 +1,27 @@
|
||||
.text-field {
|
||||
border: 1px solid transparent;
|
||||
border-radius: 5pt;
|
||||
padding: 4px 8px;
|
||||
outline: none;
|
||||
background-color: canvas;
|
||||
transition: border-color 0.2s, box-shadow 0.2s;
|
||||
cursor: text;
|
||||
}
|
||||
|
||||
.text-field.invalid {
|
||||
border-color: red;
|
||||
color: red;
|
||||
}
|
||||
|
||||
.text-field:focus:not(.invalid) {
|
||||
border-color: color-mix(in srgb, canvas, #777 10%);
|
||||
}
|
||||
|
||||
.text-field:read-only {
|
||||
cursor: pointer;
|
||||
background-color: color-mix(in srgb, canvas, #777 5%);
|
||||
}
|
||||
|
||||
.text-field:read-only:hover:not(.invalid) {
|
||||
border-color: color-mix(in srgb, canvas, #777 10%);
|
||||
}
|
||||
101
src/components/TextField.tsx
Normal file
101
src/components/TextField.tsx
Normal file
@@ -0,0 +1,101 @@
|
||||
import {useState} from "react";
|
||||
import styles from "./TextField.module.css";
|
||||
|
||||
/**
|
||||
* A text input element in our own style that calls `setValue` at every keystroke.
|
||||
*
|
||||
* @param {Object} props - The component props.
|
||||
* @param {string} props.value - The value of the text input.
|
||||
* @param {(value: string) => void} props.setValue - A function that sets the value of the text input.
|
||||
* @param {string} [props.placeholder] - The placeholder text for the text input.
|
||||
* @param {string} [props.className] - Additional CSS classes for the text input.
|
||||
* @param {string} [props.id] - The ID of the text input.
|
||||
* @param {string} [props.ariaLabel] - The ARIA label for the text input.
|
||||
*/
|
||||
export function RealtimeTextField({
|
||||
value = "",
|
||||
setValue,
|
||||
onCommit,
|
||||
placeholder,
|
||||
className,
|
||||
id,
|
||||
ariaLabel,
|
||||
invalid = false,
|
||||
} : {
|
||||
value: string,
|
||||
setValue: (value: string) => void,
|
||||
onCommit: () => void,
|
||||
placeholder?: string,
|
||||
className?: string,
|
||||
id?: string,
|
||||
ariaLabel?: string,
|
||||
invalid?: boolean,
|
||||
}) {
|
||||
const [readOnly, setReadOnly] = useState(true);
|
||||
|
||||
const updateData = () => {
|
||||
setReadOnly(true);
|
||||
onCommit();
|
||||
};
|
||||
|
||||
const updateOnEnter = (event: React.KeyboardEvent<HTMLInputElement>) => { if (event.key === "Enter") (event.target as HTMLInputElement).blur(); };
|
||||
|
||||
return <input
|
||||
type={"text"}
|
||||
placeholder={placeholder}
|
||||
value={value}
|
||||
onChange={(e) => setValue(e.target.value)}
|
||||
onFocus={() => setReadOnly(false)}
|
||||
onBlur={updateData}
|
||||
onKeyDown={updateOnEnter}
|
||||
readOnly={readOnly}
|
||||
id={id}
|
||||
// ReactFlow uses the "drag" / "nodrag" classes to enable / disable dragging of nodes
|
||||
className={`${readOnly ? "drag" : "nodrag"} ${styles.textField} ${invalid ? styles.invalid : ""} ${className}`}
|
||||
aria-label={ariaLabel}
|
||||
/>;
|
||||
}
|
||||
|
||||
/**
|
||||
* A text input element in our own style that calls `setValue` once the user presses the enter key or clicks outside the input.
|
||||
*
|
||||
* @param {Object} props - The component props.
|
||||
* @param {string} props.value - The value of the text input.
|
||||
* @param {(value: string) => void} props.setValue - A function that sets the value of the text input.
|
||||
* @param {string} [props.placeholder] - The placeholder text for the text input.
|
||||
* @param {string} [props.className] - Additional CSS classes for the text input.
|
||||
* @param {string} [props.id] - The ID of the text input.
|
||||
* @param {string} [props.ariaLabel] - The ARIA label for the text input.
|
||||
*/
|
||||
export function TextField({
|
||||
value = "",
|
||||
setValue,
|
||||
placeholder,
|
||||
className,
|
||||
id,
|
||||
ariaLabel,
|
||||
invalid = false,
|
||||
} : {
|
||||
value: string,
|
||||
setValue: (value: string) => void,
|
||||
placeholder?: string,
|
||||
className?: string,
|
||||
id?: string,
|
||||
ariaLabel?: string,
|
||||
invalid?: boolean,
|
||||
}) {
|
||||
const [inputValue, setInputValue] = useState(value);
|
||||
|
||||
const onCommit = () => setValue(inputValue);
|
||||
|
||||
return <RealtimeTextField
|
||||
placeholder={placeholder}
|
||||
value={inputValue}
|
||||
setValue={setInputValue}
|
||||
onCommit={onCommit}
|
||||
id={id}
|
||||
className={className}
|
||||
ariaLabel={ariaLabel}
|
||||
invalid={invalid}
|
||||
/>;
|
||||
}
|
||||
Reference in New Issue
Block a user