Skip to content

Commit

Permalink
Merge pull request #52 from sc420/43-disable-dragging-the-node-while-…
Browse files Browse the repository at this point in the history
…editing-the-node-name

make node not draggable when editing the name
  • Loading branch information
sc420 authored Jan 21, 2024
2 parents 3d5bae2 + aae1fdc commit 293a622
Show file tree
Hide file tree
Showing 4 changed files with 89 additions and 12 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,12 @@ jest.mock("../latex/Katex");

test("should render the name only", () => {
const handleNameChange = jest.fn();
const handleEditingChange = jest.fn();
render(
<EditableName
name="abc"
operationData={null}
onEditingChange={handleEditingChange}
onNameChange={handleNameChange}
/>,
);
Expand All @@ -19,11 +21,13 @@ test("should render the name only", () => {

test("should render the name and operation text", () => {
const operationData = getOperationData();
const handleEditingChange = jest.fn();
const handleNameChange = jest.fn();
render(
<EditableName
name="abc"
operationData={operationData}
onEditingChange={handleEditingChange}
onNameChange={handleNameChange}
/>,
);
Expand All @@ -32,57 +36,72 @@ test("should render the name and operation text", () => {
expect(screen.getByText("(Operation 1)")).toBeInTheDocument();
});

test("should trigger event with updated name when blurred", () => {
test("should trigger events when blurred", () => {
const handleEditingChange = jest.fn();
const handleNameChange = jest.fn();
render(
<EditableName
name="abc"
operationData={null}
onEditingChange={handleEditingChange}
onNameChange={handleNameChange}
/>,
);

clickEditIcon();
expect(handleEditingChange).toBeCalledWith(true);

changeName("123");
const input = getEditingTextbox();
fireEvent.blur(input);

expect(handleEditingChange).toBeCalledWith(false);
expect(handleNameChange).toBeCalledWith("123");
});

test("should trigger event with updated name when Enter is pressed", () => {
test("should trigger events when Enter is pressed", () => {
const handleEditingChange = jest.fn();
const handleNameChange = jest.fn();
render(
<EditableName
name="abc"
operationData={null}
onEditingChange={handleEditingChange}
onNameChange={handleNameChange}
/>,
);

clickEditIcon();
expect(handleEditingChange).toBeCalledWith(true);

changeName("123");
const input = getEditingTextbox();
fireEvent.keyDown(input, { key: "Enter" });

expect(handleEditingChange).toBeCalledWith(false);
expect(handleNameChange).toBeCalledWith("123");
});

test("should not trigger event with old name when Escape is pressed", () => {
test("should trigger events when Escape is pressed", () => {
const handleEditingChange = jest.fn();
const handleNameChange = jest.fn();
render(
<EditableName
name="abc"
operationData={null}
onEditingChange={handleEditingChange}
onNameChange={handleNameChange}
/>,
);

clickEditIcon();
expect(handleEditingChange).toBeCalledWith(true);

changeName("123");
const input = getEditingTextbox();
fireEvent.keyDown(input, { key: "Escape" });

expect(handleEditingChange).toBeCalledWith(false);
expect(handleNameChange).not.toBeCalled();
});

Expand Down
25 changes: 19 additions & 6 deletions interactive-computational-graph/src/reactflow/EditableName.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,46 +18,59 @@ import Katex from "../latex/Katex";
interface EditableNameProps {
name: string;
operationData: OperationNodeData | null;
onEditingChange: (isEditing: boolean) => void;
onNameChange: (name: string) => void;
}

const EditableName: FunctionComponent<EditableNameProps> = ({
name,
operationData,
onEditingChange,
onNameChange,
}) => {
const [isEditing, setIsEditing] = useState(false);
const [editingName, setEditingName] = useState(name);

const updateEditing = useCallback(
(isEditing: boolean) => {
setIsEditing(isEditing);
onEditingChange(isEditing);
},
[onEditingChange],
);

const handleChange = useCallback((name: string) => {
setEditingName(name);
}, []);

const handleSaveName = useCallback(
(name: string) => {
onNameChange(name);
setIsEditing(false);
updateEditing(false);
},
[onNameChange],
[onNameChange, updateEditing],
);

const handleKeyDown = useCallback(
(e: KeyboardEvent) => {
if (e.key === "Enter") {
onNameChange(editingName);
setIsEditing(false);
updateEditing(false);
} else if (e.key === "Escape") {
setEditingName(name);
setIsEditing(false);
updateEditing(false);
}
},
[editingName, name, onNameChange],
[editingName, name, onNameChange, updateEditing],
);

return (
<Stack direction="row" alignItems="center" justifyContent="space-between">
{isEditing ? (
<TextField
inputProps={{
"aria-label": "editingName",
}}
size="small"
value={editingName}
onChange={(event) => {
Expand Down Expand Up @@ -93,7 +106,7 @@ const EditableName: FunctionComponent<EditableNameProps> = ({
aria-label="edit"
size="small"
onClick={() => {
setIsEditing(true);
updateEditing(true);
}}
>
<EditIcon fontSize="small" />
Expand Down
32 changes: 31 additions & 1 deletion interactive-computational-graph/src/reactflow/NodeTitle.test.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { render, screen } from "@testing-library/react";
import { fireEvent, render, screen } from "@testing-library/react";
import type OperationNodeData from "../features/OperationNodeData";
import NodeTitle from "./NodeTitle";

Expand All @@ -22,6 +22,36 @@ test("should render the name", () => {
expect(screen.getByText("abc")).toBeInTheDocument();
});

test("should not have draggable class when editing the name", () => {
const operationData = getOperationData();
const handleNameChange = jest.fn();
render(
<NodeTitle
id="1"
name="abc"
operationData={operationData}
backgroundColor="white"
isDarkMode={false}
isHighlighted={false}
onNameChange={handleNameChange}
/>,
);

const nodeTitle = screen.getByTestId("node-title-1");
const editIcon = screen.getByLabelText("edit");

expect(nodeTitle).toHaveClass("drag-handle");

fireEvent.click(editIcon);

expect(nodeTitle).not.toHaveClass("drag-handle");

const editingInput = screen.getByLabelText("editingName");
fireEvent.blur(editingInput);

expect(nodeTitle).toHaveClass("drag-handle");
});

test("should not have striped animation when not highlighted", () => {
const operationData = getOperationData();
const handleNameChange = jest.fn();
Expand Down
19 changes: 17 additions & 2 deletions interactive-computational-graph/src/reactflow/NodeTitle.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import DragIndicatorIcon from "@mui/icons-material/DragIndicator";
import { Box, Stack } from "@mui/material";
import { useMemo, type FunctionComponent } from "react";
import { useCallback, useMemo, useState, type FunctionComponent } from "react";
import type OperationNodeData from "../features/OperationNodeData";
import EditableName from "./EditableName";
import "./NodeTitle.css";
Expand Down Expand Up @@ -31,11 +31,25 @@ const NodeTitle: FunctionComponent<NodeTitleProps> = ({
return isDarkMode ? "striped-animation-dark" : "striped-animation-light";
}, [isDarkMode, isHighlighted]);

const [isEditingName, setIsEditingName] = useState(false);

const getClassName = useCallback(() => {
if (isEditingName) {
return `${animationClassName}`;
} else {
return `drag-handle ${animationClassName}`;
}
}, [animationClassName, isEditingName]);

const handleEditingChange = useCallback((isEditing: boolean) => {
setIsEditingName(isEditing);
}, []);

return (
<Box
data-testid={`node-title-${id}`}
// corresponds to dragHandle when creating new reactflow.Node
className={`drag-handle ${animationClassName}`}
className={getClassName()}
display="flex"
sx={{ backgroundColor }}
p={0.5}
Expand All @@ -48,6 +62,7 @@ const NodeTitle: FunctionComponent<NodeTitleProps> = ({
<EditableName
name={name}
operationData={operationData}
onEditingChange={handleEditingChange}
onNameChange={onNameChange}
/>
</Box>
Expand Down

0 comments on commit 293a622

Please sign in to comment.