Skip to content

Commit

Permalink
Merge pull request #43 from mayank1513/fix/42-mouse-selection
Browse files Browse the repository at this point in the history
Fix mouse selection and clicking on links in tasks.
  • Loading branch information
mayank1513 authored Jul 3, 2024
2 parents 79ebfed + c53ceba commit 332f1f4
Show file tree
Hide file tree
Showing 9 changed files with 86 additions and 48 deletions.
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
# Trello Kanban Board

## 0.6.1

### Patch Changes

- 093b58c: Fix clicking on link and allow selection without entering editing mode.

## 0.6.0

### Minor Changes
Expand Down
6 changes: 4 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "trello-kanban-task-board",
"private": true,
"version": "0.6.0",
"version": "0.6.1",
"type": "module",
"scripts": {
"dev": "vite --port 3000",
Expand All @@ -22,7 +22,9 @@
"react-dom": "^18.2.0",
"react-markdown": "^9.0.1",
"react-toastify": "^9.1.3",
"rehype-raw": "^7.0.0"
"react-webgl-trails": "^0.0.4",
"rehype-raw": "^7.0.0",
"remark-gfm": "^4.0.0"
},
"devDependencies": {
"@changesets/cli": "^2.27.1",
Expand Down
35 changes: 19 additions & 16 deletions src/App.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,10 @@ describe("Test Board", () => {

test("Create new tasks", ({ expect }) => {
const columnEl = screen.getByTestId("column-3");
act(() => fireEvent.click(columnEl.getElementsByTagName("button")[0]));
act(() => fireEvent.click(columnEl.getElementsByTagName("button")[0]));
// click add task button
act(() => fireEvent.click(columnEl.getElementsByClassName(columnListStyles.addTask)[0]));
// Add another task
act(() => fireEvent.click(columnEl.getElementsByClassName(columnListStyles.addTask)[0]));
expect(columnEl.getElementsByClassName(taskStyles.task).length).toBe(2);
});

Expand All @@ -60,7 +62,7 @@ describe("Test Board", () => {

test("Create a new task", async ({ expect }) => {
const columnEl = screen.getByTestId("column-0");
act(() => fireEvent.click(columnEl.getElementsByTagName("button")[0]));
act(() => fireEvent.click(columnEl.getElementsByClassName(columnListStyles.addTask)[0]));
await new Promise((resolve) => setTimeout(resolve, 400));
expect(columnEl.getElementsByClassName(taskStyles.task).length).toBe(2);
expect(scrollIntoViewMock).toBeCalled();
Expand All @@ -69,12 +71,12 @@ describe("Test Board", () => {
/** Todo: drop on another column or position */
test("Move task", async ({ expect }) => {
const columnEl = screen.getByTestId("column-0");
const taskEl = columnEl.getElementsByClassName(taskStyles.task)[0];
const taskHanleEl = columnEl.getElementsByClassName(taskStyles.task)[0].getElementsByTagName("header")[0];
// simulate dragging -- not very effective
act(() => fireEvent.mouseDown(taskEl, { clientX: 100, clientY: 150 }));
act(() => fireEvent.mouseMove(taskEl, { clientX: 450, clientY: 500 }));
act(() => fireEvent.mouseMove(taskEl, { clientX: 650, clientY: 300 }));
act(() => fireEvent.mouseUp(taskEl, { clientX: 650, clientY: 300 }));
act(() => fireEvent.mouseDown(taskHanleEl, { clientX: 100, clientY: 150 }));
act(() => fireEvent.mouseMove(taskHanleEl, { clientX: 450, clientY: 500 }));
act(() => fireEvent.mouseMove(taskHanleEl, { clientX: 650, clientY: 300 }));
act(() => fireEvent.mouseUp(taskHanleEl, { clientX: 650, clientY: 300 }));
expect(columnEl.getElementsByClassName(taskStyles.task).length).toBe(2);
});

Expand Down Expand Up @@ -132,23 +134,24 @@ describe("Test Board", () => {
expect(setStateFn).toBeCalled();
});

test("Remove task", async ({ expect }) => {
const columnEl = screen.getByTestId("column-0");
const taskEl = columnEl.getElementsByClassName(taskStyles.task)[0];
act(() => fireEvent.click(taskEl.getElementsByClassName(taskStyles.close)[0]));
expect(columnEl.getElementsByClassName(taskStyles.task).length).toBe(1);
});

test("Edit task", async ({ expect }) => {
const columnEl = screen.getByTestId("column-0");
const taskEl = columnEl.getElementsByClassName(taskStyles.task)[0];
act(() => fireEvent.click(taskEl));
const editBtn = taskEl.getElementsByTagName("button")[0];
act(() => fireEvent.click(editBtn));
const inputEl = taskEl.getElementsByTagName("textarea")[0];
act(() => fireEvent.input(inputEl, { target: { value: "Task 1" } }));
act(() => fireEvent.blur(inputEl));
expect(taskEl.textContent).toContain("Task 1");
});

test("Remove task", async ({ expect }) => {
const columnEl = screen.getByTestId("column-0");
const taskEl = columnEl.getElementsByClassName(taskStyles.task)[0];
act(() => fireEvent.click(taskEl.getElementsByClassName(taskStyles.close)[0]));
expect(columnEl.getElementsByClassName(taskStyles.task).length).toBe(1);
});

test("Drawer", ({ expect }) => {
act(() => render(<Drawer open scope="Global" />));
act(() => fireEvent.click(screen.getByText("⚙")));
Expand Down
2 changes: 2 additions & 0 deletions src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { GlobalContext } from "utils/context";
import { ToastContainer } from "react-toastify";
import "react-toastify/dist/ReactToastify.css";
import { ThemeSwitcher } from "nextjs-themes";
import { MouseTrail } from "react-webgl-trails";

function App() {
const [state, _setState] = useState<BoardType>(defaultBoard);
Expand All @@ -24,6 +25,7 @@ function App() {
<ThemeSwitcher storage="localStorage" themeTransition="all .3s" />
<Board />
<ToastContainer position="bottom-right" />
<MouseTrail />
</GlobalContext.Provider>
);
}
Expand Down
3 changes: 2 additions & 1 deletion src/components/column-list/column-list.module.scss
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,8 @@
overflow-x: hidden;
overflow-y: auto;
max-height: calc(100vh - 200px);
padding: 0;
padding: 0 10px;
margin: 0 -10px;
}
.close {
display: none;
Expand Down
2 changes: 1 addition & 1 deletion src/components/column-list/column.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ export default function Column({ column, index }: { column: ColumnType; index: n
// listRef.current?.scrollTo({ top: listRef.current.scrollHeight, behavior: "smooth" });
const newTaskElement = listRef.current?.children[listRef.current.children.length - 1] as HTMLLabelElement;
newTaskElement?.scrollIntoView({ behavior: "smooth", block: "center", inline: "center" });
newTaskElement?.click();
newTaskElement?.getElementsByTagName("button")[0].click();
setTimeout(() => {
newTaskElement?.getElementsByTagName("textarea")[0].focus();
newTaskElement?.getElementsByTagName("textarea")[0].click();
Expand Down
34 changes: 21 additions & 13 deletions src/components/task/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { RefObject, useId, useRef, useState } from "react";
import { Draggable } from "react-beautiful-dnd";
import ReactMarkdown from "react-markdown";
import rehypeRaw from "rehype-raw";
import remarkGfm from "remark-gfm";
import { useGlobalState } from "utils/context";
import styles from "./task.module.scss";
import { vscode } from "utils/vscode";
Expand Down Expand Up @@ -38,19 +39,27 @@ export default function Task({ task, index }: { task: TaskType; index: number })
provided.draggableProps.style.transform += " rotate(5deg)";
return (
<label
onClick={() => {
setIsEditing(true);
resizeTextArea(textareaRef);
if (textareaRef.current?.value) {
textareaRef.current.value = "hk";
textareaRef.current.value = task.description;
}
}}
htmlFor={id}
ref={provided.innerRef}
{...provided.dragHandleProps}
{...provided.draggableProps}
className={[styles.task, isEditing ? styles.active : ""].join(" ")}>
<header {...provided.dragHandleProps}>
<span>∘∘∘</span>
<button
onClick={() => {
setIsEditing(true);
if (textareaRef.current?.value) {
textareaRef.current.value = "hk";
textareaRef.current.value = task.description;
}
setTimeout(() => resizeTextArea(textareaRef), 100);
}}>
🖉
</button>
<button className={styles.close} onClick={removeTask}>
</button>
</header>
<textarea
id={id}
value={task.description}
Expand All @@ -64,12 +73,11 @@ export default function Task({ task, index }: { task: TaskType; index: number })
placeholder="Enter task description in Markdown format"
hidden={!isEditing}
/>
<span className={styles.close} onClick={removeTask}>
</span>
{!isEditing &&
(task.description.trim() ? (
<ReactMarkdown rehypePlugins={[rehypeRaw]}>{task.description.replace(/\n+/g, "\n\n")}</ReactMarkdown>
<ReactMarkdown rehypePlugins={[rehypeRaw]} remarkPlugins={[remarkGfm]}>
{task.description.replace(/\n+/g, "\n\n")}
</ReactMarkdown>
) : (
<p className={styles.placeholder}>Enter task description in Markdown format.</p>
))}
Expand Down
44 changes: 29 additions & 15 deletions src/components/task/task.module.scss
Original file line number Diff line number Diff line change
@@ -1,12 +1,40 @@
.task {
margin: 5px;
margin-bottom: 10px;
padding: 5px;
border-radius: 5px;
border: 1px solid gray;
box-shadow: 0 0 5px #555;
display: block;
position: relative;
background: var(--bg);
header {
text-align: center;
box-shadow: 0 0 2px currentColor;
margin: -5px;
margin-bottom: -5px;
margin-bottom: 0;
border-radius: 5px 5px 0 0;
padding-bottom: 2px;
position: relative;
button {
all: unset;
position: absolute;
right: 24px;
top: 0;
cursor: pointer;
padding: 0 5px;
&:hover {
color: orange;
}
}

.close {
right: 2px;
&:hover {
color: red;
}
}
}
textarea {
width: calc(100% - 10px);
resize: none;
Expand All @@ -18,24 +46,10 @@
ul {
padding-left: 20px;
}
&:hover .close {
display: block;
}
}
.active {
box-shadow: 0 0 5px red;
}
.placeholder {
opacity: 0.5;
}
.close {
position: absolute;
right: 5px;
top: -5px;
display: none;
cursor: pointer;
z-index: 100;
&:hover {
color: red;
}
}
2 changes: 2 additions & 0 deletions vitest.setup.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,5 @@ Object.defineProperty(window, "matchMedia", {
dispatchEvent: vi.fn(),
})),
});

vi.mock("react-webgl-trails", () => ({ MouseTrail: () => null }));

0 comments on commit 332f1f4

Please sign in to comment.