Compare commits

...

2 Commits

Author SHA1 Message Date
Henry
281fbc7b4c fix: submit forms on enter key submission 2025-06-03 14:56:01 +01:00
Krisztiaan
eb49bab675 fix: add type="button" to modal close buttons to fix Enter key form submission
Previously, pressing Enter in modal form inputs would dismiss the modal instead
of submitting the form because close buttons defaulted to type="submit". This
adds explicit type="button" to all modal close buttons to ensure Enter key
properly submits forms.

Fixes:
- New board creation via Enter key
- New workspace creation via Enter key
- New card creation via Enter key
- New list creation via Enter key
- Member invitation via Enter key
- Label creation/editing via Enter key
- Board URL updates via Enter key
- Import boards forms via Enter key
2025-06-03 03:14:37 +02:00
11 changed files with 110 additions and 11 deletions

View File

@@ -98,12 +98,16 @@ const FeedbackButton: React.FC = () => {
onChange={(e) => {
setValue("feedback", e.target.value);
}}
onKeyDown={(e) => {
e.stopPropagation();
}}
value={watch("feedback")}
contentEditable
className="max-h-[300px] min-h-[100px]"
onKeyDown={async (e) => {
e.stopPropagation();
if (e.key === "Enter" && e.shiftKey) {
e.preventDefault();
await handleSubmit(onSubmit)();
}
}}
/>
<div className="flex flex-row items-center justify-between pt-2">
<div>

View File

@@ -69,6 +69,7 @@ const Input = forwardRef<HTMLInputElement, InputProps>(
prefix && "rounded-l-none",
className && className,
)}
onKeyDown={onKeyDown}
{...props}
/>
{type === "password" && (

View File

@@ -1,5 +1,5 @@
import { Listbox, Transition } from "@headlessui/react";
import { Fragment } from "react";
import { Fragment, useEffect } from "react";
import { Controller, useForm } from "react-hook-form";
import { HiChevronUpDown, HiXMark } from "react-icons/hi2";
@@ -103,6 +103,12 @@ export function LabelForm({
}
};
useEffect(() => {
const nameElement: HTMLElement | null =
document.querySelector<HTMLElement>("#label-name");
if (nameElement) nameElement.focus();
}, []);
return (
<form onSubmit={handleSubmit(onSubmit)}>
<div className="px-5 pt-5">
@@ -111,6 +117,7 @@ export function LabelForm({
{isEdit ? "Edit label" : "New label"}
</h2>
<button
type="button"
className="rounded p-1 hover:bg-light-300 focus:outline-none dark:hover:bg-dark-300"
onClick={(e) => {
e.preventDefault();
@@ -121,7 +128,17 @@ export function LabelForm({
</button>
</div>
<Input id="label-name" placeholder="Name" {...register("name")} />
<Input
id="label-name"
placeholder="Name"
{...register("name")}
onKeyDown={async (e) => {
if (e.key === "Enter") {
e.preventDefault();
await handleSubmit(onSubmit)();
}
}}
/>
<Controller
name="colour"
control={control}

View File

@@ -61,6 +61,7 @@ export function NewWorkspaceForm() {
New workspace
</h2>
<button
type="button"
className="rounded p-1 hover:bg-light-200 focus:outline-none dark:hover:bg-dark-300"
onClick={(e) => {
e.preventDefault();
@@ -75,6 +76,12 @@ export function NewWorkspaceForm() {
id="workspace-name"
placeholder="Workspace name"
{...register("name")}
onKeyDown={async (e) => {
if (e.key === "Enter") {
e.preventDefault();
await handleSubmit(onSubmit)();
}
}}
/>
</div>
<div className="mt-12 flex items-center justify-end border-t border-light-600 px-5 pb-5 pt-5 dark:border-dark-600">

View File

@@ -226,6 +226,7 @@ export function NewCardForm({
New card
</h2>
<button
type="button"
className="rounded p-1 hover:bg-light-200 focus:outline-none dark:hover:bg-dark-300"
onClick={(e) => {
closeModal();
@@ -237,7 +238,17 @@ export function NewCardForm({
</div>
<div>
<Input id="title" placeholder="Card title" {...register("title")} />
<Input
id="title"
placeholder="Card title"
{...register("title")}
onKeyDown={async (e) => {
if (e.key === "Enter") {
e.preventDefault();
await handleSubmit(onSubmit)();
}
}}
/>
</div>
<div className="mt-2">
<Input
@@ -245,6 +256,12 @@ export function NewCardForm({
onChange={(e) => setValue("description", e.target.value)}
value={watch("description")}
contentEditable
onKeyDown={async (e) => {
if (e.key === "Enter" && e.shiftKey) {
e.preventDefault();
await handleSubmit(onSubmit)();
}
}}
/>
</div>
<div className="mt-2 flex space-x-1">

View File

@@ -111,6 +111,7 @@ export function NewListForm({
New list
</h2>
<button
type="button"
className="rounded p-1 hover:bg-light-200 focus:outline-none dark:hover:bg-dark-300"
onClick={(e) => {
e.preventDefault();
@@ -121,7 +122,17 @@ export function NewListForm({
</button>
</div>
<Input id="list-name" placeholder="List name" {...register("name")} />
<Input
id="list-name"
placeholder="List name"
{...register("name")}
onKeyDown={async (e) => {
if (e.key === "Enter") {
e.preventDefault();
await handleSubmit(onSubmit)();
}
}}
/>
</div>
<div className="mt-12 flex items-center justify-end border-t border-light-600 px-5 pb-5 pt-5 dark:border-dark-600">
<Toggle

View File

@@ -92,6 +92,7 @@ export function UpdateBoardSlugForm({
Edit board URL
</h2>
<button
type="button"
className="rounded p-1 hover:bg-light-200 focus:outline-none dark:hover:bg-dark-300"
onClick={(e) => {
e.preventDefault();
@@ -107,6 +108,12 @@ export function UpdateBoardSlugForm({
{...register("slug")}
errorMessage={errors.slug?.message}
prefix={`kan.bn/${workspaceSlug}/`}
onKeyDown={async (e) => {
if (e.key === "Enter") {
e.preventDefault();
await handleSubmit(onSubmit)();
}
}}
/>
</div>
<div className="mt-12 flex items-center justify-end border-t border-light-600 px-5 pb-5 pt-5 dark:border-dark-600">

View File

@@ -251,6 +251,7 @@ export function ImportBoardsForm() {
</div>
<button
type="button"
className="rounded p-1 hover:bg-light-200 dark:hover:bg-dark-300"
onClick={() => closeModal()}
>

View File

@@ -1,9 +1,11 @@
import { useEffect } from "react";
import { useForm } from "react-hook-form";
import { HiXMark } from "react-icons/hi2";
import type { NewBoardInput } from "@kan/api/types";
import Button from "~/components/Button";
import Input from "~/components/Input";
import { useModal } from "~/providers/modal";
import { useWorkspace } from "~/providers/workspace";
import { api } from "~/utils/api";
@@ -33,12 +35,19 @@ export function NewBoardForm() {
createBoard.mutate(data);
};
useEffect(() => {
const titleElement: HTMLElement | null =
document.querySelector<HTMLElement>("#name");
if (titleElement) titleElement.focus();
}, []);
return (
<form onSubmit={handleSubmit(onSubmit)}>
<div className="px-5 pt-5">
<div className="text-neutral-9000 flex w-full items-center justify-between pb-4 dark:text-dark-1000">
<h2 className="text-sm font-bold">New board</h2>
<button
type="button"
className="hover:bg-li ght-300 rounded p-1 focus:outline-none dark:hover:bg-dark-300"
onClick={(e) => {
e.preventDefault();
@@ -48,11 +57,16 @@ export function NewBoardForm() {
<HiXMark size={18} className="dark:text-dark-9000 text-light-900" />
</button>
</div>
<input
<Input
id="name"
placeholder="Name"
{...register("name", { required: true })}
className="block w-full rounded-md border-0 bg-white/5 py-1.5 text-neutral-900 placeholder-dark-800 shadow-sm ring-1 ring-inset ring-light-600 focus:ring-2 focus:ring-inset focus:ring-light-600 dark:bg-dark-300 dark:text-dark-1000 dark:ring-dark-700 dark:focus:ring-dark-700 sm:text-sm sm:leading-6"
onKeyDown={async (e) => {
if (e.key === "Enter") {
e.preventDefault();
await handleSubmit(onSubmit)();
}
}}
/>
</div>

View File

@@ -58,6 +58,12 @@ const NewCommentForm = ({ cardPublicId }: { cardPublicId: string }) => {
disabled={false}
onChange={(e) => setValue("comment", e.target.value)}
className="block w-full border-0 bg-transparent py-1.5 text-light-900 focus-visible:outline-none dark:text-dark-1000 sm:text-sm sm:leading-6"
onKeyDown={async (e) => {
if (e.key === "Enter" && e.shiftKey) {
e.preventDefault();
await handleSubmit(onSubmit)();
}
}}
/>
<div className="flex justify-end">
<button

View File

@@ -1,9 +1,11 @@
import { useEffect } from "react";
import { useForm } from "react-hook-form";
import { HiXMark } from "react-icons/hi2";
import type { InviteMemberInput } from "@kan/api/types";
import Button from "~/components/Button";
import Input from "~/components/Input";
import { useModal } from "~/providers/modal";
import { useWorkspace } from "~/providers/workspace";
import { api } from "~/utils/api";
@@ -34,12 +36,19 @@ export function InviteMemberForm() {
createBoard.mutate(data);
};
useEffect(() => {
const emailElement: HTMLElement | null =
document.querySelector<HTMLElement>("#email");
if (emailElement) emailElement.focus();
}, []);
return (
<form onSubmit={handleSubmit(onSubmit)}>
<div className="px-5 pt-5">
<div className="text-neutral-9000 flex w-full items-center justify-between pb-4 dark:text-dark-1000">
<h2 className="text-sm font-bold">Add member</h2>
<button
type="button"
className="hover:bg-li ght-300 rounded p-1 focus:outline-none dark:hover:bg-dark-300"
onClick={(e) => {
e.preventDefault();
@@ -49,11 +58,16 @@ export function InviteMemberForm() {
<HiXMark size={18} className="dark:text-dark-9000 text-light-900" />
</button>
</div>
<input
<Input
id="email"
placeholder="Email"
{...register("email", { required: true })}
className="block w-full rounded-md border-0 bg-white/5 py-1.5 text-neutral-900 placeholder-dark-800 shadow-sm ring-1 ring-inset ring-light-600 focus:ring-2 focus:ring-inset focus:ring-light-600 dark:bg-dark-300 dark:text-dark-1000 dark:ring-dark-700 dark:focus:ring-dark-700 sm:text-sm sm:leading-6"
onKeyDown={async (e) => {
if (e.key === "Enter") {
e.preventDefault();
await handleSubmit(onSubmit)();
}
}}
/>
</div>