Prevent Default on Ctrl + Backspace in ReactFlow (#706)
This commit is contained in:
commit
9df5e94195
10 changed files with 77 additions and 8 deletions
|
|
@ -1,5 +1,5 @@
|
||||||
import _ from "lodash";
|
import _ from "lodash";
|
||||||
import { useContext, useEffect, useState } from "react";
|
import { useContext, useEffect, useRef, useState } from "react";
|
||||||
import { useLocation } from "react-router-dom";
|
import { useLocation } from "react-router-dom";
|
||||||
import "reactflow/dist/style.css";
|
import "reactflow/dist/style.css";
|
||||||
import "./App.css";
|
import "./App.css";
|
||||||
|
|
@ -121,6 +121,7 @@ export default function App() {
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
//need parent component with width and height
|
//need parent component with width and height
|
||||||
<div className="flex h-full flex-col">
|
<div className="flex h-full flex-col">
|
||||||
|
|
|
||||||
|
|
@ -32,6 +32,13 @@ export default function AccordionComponent({
|
||||||
value === "" ? setValue(keyValue) : setValue("");
|
value === "" ? setValue(keyValue) : setValue("");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const handleKeyDown = (event) => {
|
||||||
|
if (event.key === "Backspace") {
|
||||||
|
event.preventDefault();
|
||||||
|
event.stopPropagation();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Accordion
|
<Accordion
|
||||||
|
|
@ -39,6 +46,7 @@ export default function AccordionComponent({
|
||||||
className="w-full"
|
className="w-full"
|
||||||
value={value}
|
value={value}
|
||||||
onValueChange={setValue}
|
onValueChange={setValue}
|
||||||
|
onKeyDown={handleKeyDown}
|
||||||
>
|
>
|
||||||
<AccordionItem value={keyValue} className="border-b">
|
<AccordionItem value={keyValue} className="border-b">
|
||||||
<AccordionTrigger
|
<AccordionTrigger
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
import { useEffect } from "react";
|
import { useEffect } from "react";
|
||||||
import { FloatComponentType } from "../../types/components";
|
import { FloatComponentType } from "../../types/components";
|
||||||
import { Input } from "../ui/input";
|
import { Input } from "../ui/input";
|
||||||
|
import { handleKeyDown } from "../../utils/reactflowUtils";
|
||||||
|
|
||||||
export default function FloatComponent({
|
export default function FloatComponent({
|
||||||
value,
|
value,
|
||||||
|
|
@ -43,6 +44,9 @@ export default function FloatComponent({
|
||||||
onChange={(e) => {
|
onChange={(e) => {
|
||||||
onChange(e.target.value);
|
onChange(e.target.value);
|
||||||
}}
|
}}
|
||||||
|
onKeyDown={(e) => {
|
||||||
|
handleKeyDown(e, value, '0');
|
||||||
|
}}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@ import { useEffect, useState } from "react";
|
||||||
import { InputComponentType } from "../../types/components";
|
import { InputComponentType } from "../../types/components";
|
||||||
import { classNames } from "../../utils/utils";
|
import { classNames } from "../../utils/utils";
|
||||||
import { Input } from "../ui/input";
|
import { Input } from "../ui/input";
|
||||||
|
import { handleKeyDown } from "../../utils/reactflowUtils";
|
||||||
|
|
||||||
export default function InputComponent({
|
export default function InputComponent({
|
||||||
value,
|
value,
|
||||||
|
|
@ -19,6 +20,7 @@ export default function InputComponent({
|
||||||
}
|
}
|
||||||
}, [disabled, onChange]);
|
}, [disabled, onChange]);
|
||||||
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="relative w-full">
|
<div className="relative w-full">
|
||||||
<Input
|
<Input
|
||||||
|
|
@ -34,6 +36,9 @@ export default function InputComponent({
|
||||||
onChange={(e) => {
|
onChange={(e) => {
|
||||||
onChange(e.target.value);
|
onChange(e.target.value);
|
||||||
}}
|
}}
|
||||||
|
onKeyDown={(e) => {
|
||||||
|
handleKeyDown(e, value, '');
|
||||||
|
}}
|
||||||
/>
|
/>
|
||||||
{password && (
|
{password && (
|
||||||
<button
|
<button
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@ import _ from "lodash";
|
||||||
import { classNames } from "../../utils/utils";
|
import { classNames } from "../../utils/utils";
|
||||||
import IconComponent from "../genericIconComponent";
|
import IconComponent from "../genericIconComponent";
|
||||||
import { Input } from "../ui/input";
|
import { Input } from "../ui/input";
|
||||||
|
import { handleKeyDown } from "../../utils/reactflowUtils";
|
||||||
|
|
||||||
export default function InputListComponent({
|
export default function InputListComponent({
|
||||||
value,
|
value,
|
||||||
|
|
@ -39,6 +40,12 @@ export default function InputListComponent({
|
||||||
newInputList[idx] = e.target.value;
|
newInputList[idx] = e.target.value;
|
||||||
onChange(newInputList);
|
onChange(newInputList);
|
||||||
}}
|
}}
|
||||||
|
onKeyDown={(e) => {
|
||||||
|
if (e.ctrlKey && e.key === "Backspace") {
|
||||||
|
e.preventDefault();
|
||||||
|
e.stopPropagation();
|
||||||
|
}
|
||||||
|
}}
|
||||||
/>
|
/>
|
||||||
{idx === value.length - 1 ? (
|
{idx === value.length - 1 ? (
|
||||||
<button
|
<button
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
import { useEffect } from "react";
|
import { useEffect } from "react";
|
||||||
import { FloatComponentType } from "../../types/components";
|
import { FloatComponentType } from "../../types/components";
|
||||||
import { Input } from "../ui/input";
|
import { Input } from "../ui/input";
|
||||||
|
import { handleKeyDown } from "../../utils/reactflowUtils";
|
||||||
|
|
||||||
export default function IntComponent({
|
export default function IntComponent({
|
||||||
value,
|
value,
|
||||||
|
|
@ -17,6 +18,8 @@ export default function IntComponent({
|
||||||
}
|
}
|
||||||
}, [disabled, onChange]);
|
}, [disabled, onChange]);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="w-full">
|
<div className="w-full">
|
||||||
<Input
|
<Input
|
||||||
|
|
@ -37,6 +40,7 @@ export default function IntComponent({
|
||||||
) {
|
) {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
}
|
}
|
||||||
|
handleKeyDown(event, value, '0');
|
||||||
}}
|
}}
|
||||||
type="number"
|
type="number"
|
||||||
step="1"
|
step="1"
|
||||||
|
|
|
||||||
|
|
@ -29,6 +29,7 @@ export const INVALID_CHARACTERS = [
|
||||||
*/
|
*/
|
||||||
|
|
||||||
export const regexHighlight = /\{([^}]+)\}/g;
|
export const regexHighlight = /\{([^}]+)\}/g;
|
||||||
|
export const specialCharsRegex = /[!@#$%^&*()\-_=+[\]{}|;:'",.<>/?\\`´]/;
|
||||||
|
|
||||||
export const programmingLanguages: languageMap = {
|
export const programmingLanguages: languageMap = {
|
||||||
javascript: ".js",
|
javascript: ".js",
|
||||||
|
|
|
||||||
|
|
@ -22,6 +22,7 @@ import {
|
||||||
varHighlightHTML,
|
varHighlightHTML,
|
||||||
} from "../../utils/utils";
|
} from "../../utils/utils";
|
||||||
import BaseModal from "../baseModal";
|
import BaseModal from "../baseModal";
|
||||||
|
import { handleKeyDown } from "../../utils/reactflowUtils";
|
||||||
|
|
||||||
export default function GenericModal({
|
export default function GenericModal({
|
||||||
field_name = "",
|
field_name = "",
|
||||||
|
|
@ -213,6 +214,9 @@ export default function GenericModal({
|
||||||
checkVariables(e.target.value);
|
checkVariables(e.target.value);
|
||||||
}}
|
}}
|
||||||
placeholder="Type message here."
|
placeholder="Type message here."
|
||||||
|
onKeyDown={(e) => {
|
||||||
|
handleKeyDown(e, inputValue, '');
|
||||||
|
}}
|
||||||
/>
|
/>
|
||||||
) : type === TypeModal.PROMPT && !isEdit ? (
|
) : type === TypeModal.PROMPT && !isEdit ? (
|
||||||
<TextAreaContentView />
|
<TextAreaContentView />
|
||||||
|
|
@ -225,6 +229,9 @@ export default function GenericModal({
|
||||||
setInputValue(e.target.value);
|
setInputValue(e.target.value);
|
||||||
}}
|
}}
|
||||||
placeholder="Type message here."
|
placeholder="Type message here."
|
||||||
|
onKeyDown={(e) => {
|
||||||
|
handleKeyDown(e, value, '');
|
||||||
|
}}
|
||||||
/>
|
/>
|
||||||
) : (
|
) : (
|
||||||
<></>
|
<></>
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,10 @@
|
||||||
import _ from "lodash";
|
import _ from "lodash";
|
||||||
import { Connection, ReactFlowInstance } from "reactflow";
|
import { Connection, Edge, ReactFlowInstance } from "reactflow";
|
||||||
import { APITemplateType } from "../types/api";
|
import { APITemplateType } from "../types/api";
|
||||||
import { FlowType, NodeType } from "../types/flow";
|
import { FlowType, NodeType } from "../types/flow";
|
||||||
import { cleanEdgesType } from "../types/utils/reactflowUtils";
|
import { cleanEdgesType } from "../types/utils/reactflowUtils";
|
||||||
import { toNormalCase } from "./utils";
|
import { toNormalCase } from "./utils";
|
||||||
|
import { specialCharsRegex } from "../constants/constants";
|
||||||
|
|
||||||
export function cleanEdges({
|
export function cleanEdges({
|
||||||
flow: { edges, nodes },
|
flow: { edges, nodes },
|
||||||
|
|
@ -232,3 +233,40 @@ export function addVersionToDuplicates(flow: FlowType, flows: FlowType[]) {
|
||||||
|
|
||||||
return newName;
|
return newName;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function handleKeyDown(e: React.KeyboardEvent<HTMLInputElement>, inputValue: string | string[] | null, block: string)
|
||||||
|
{
|
||||||
|
|
||||||
|
//condition to fix bug control+backspace on Windows/Linux
|
||||||
|
if (typeof inputValue === "string" && e.ctrlKey === true && e.key === "Backspace" &&
|
||||||
|
(inputValue === block || inputValue?.charAt(inputValue?.length - 1) === ' '
|
||||||
|
|| specialCharsRegex.test(inputValue?.charAt(inputValue?.length - 1))
|
||||||
|
)) {
|
||||||
|
e.preventDefault();
|
||||||
|
e.stopPropagation();
|
||||||
|
}
|
||||||
|
|
||||||
|
//condition to fix bug control+backspace on Mac
|
||||||
|
if (typeof inputValue === "string" && e.metaKey === true && e.key === "Backspace" &&
|
||||||
|
(inputValue === block || inputValue?.charAt(inputValue?.length - 1) === ' '
|
||||||
|
|| specialCharsRegex.test(inputValue?.charAt(inputValue?.length - 1))
|
||||||
|
)) {
|
||||||
|
e.preventDefault();
|
||||||
|
e.stopPropagation();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (e.ctrlKey === true && e.key === "Backspace" && inputValue === block) {
|
||||||
|
e.preventDefault();
|
||||||
|
e.stopPropagation();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export function getConnectedNodes(
|
||||||
|
edge: Edge,
|
||||||
|
nodes: Array<NodeType>
|
||||||
|
): Array<NodeType> {
|
||||||
|
const sourceId = edge.source;
|
||||||
|
const targetId = edge.target;
|
||||||
|
return nodes.filter((node) => node.id === targetId || node.id === sourceId);
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -65,7 +65,6 @@ import {
|
||||||
XCircle,
|
XCircle,
|
||||||
Zap,
|
Zap,
|
||||||
} from "lucide-react";
|
} from "lucide-react";
|
||||||
import { Edge, Node } from "reactflow";
|
|
||||||
import { AirbyteIcon } from "../icons/Airbyte";
|
import { AirbyteIcon } from "../icons/Airbyte";
|
||||||
import { AnthropicIcon } from "../icons/Anthropic";
|
import { AnthropicIcon } from "../icons/Anthropic";
|
||||||
import { BingIcon } from "../icons/Bing";
|
import { BingIcon } from "../icons/Bing";
|
||||||
|
|
@ -277,8 +276,3 @@ export const nodeIconsLucide = {
|
||||||
MessageSquare,
|
MessageSquare,
|
||||||
MoreHorizontal,
|
MoreHorizontal,
|
||||||
};
|
};
|
||||||
export function getConnectedNodes(edge: Edge, nodes: Array<Node>): Array<Node> {
|
|
||||||
const sourceId = edge.source;
|
|
||||||
const targetId = edge.target;
|
|
||||||
return nodes.filter((node) => node.id === targetId || node.id === sourceId);
|
|
||||||
}
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue