implement edit dialog mnemonics

This commit is contained in:
2025-05-27 16:47:46 +01:00
parent 7bddab0619
commit 347451dbbc
2 changed files with 65 additions and 4 deletions

View File

@@ -33,6 +33,9 @@ function AddBookmarkDialog() {
{ ignore: () => false },
)
// when using autoFocus, it also captures the "a" mnemonic
// which appends the "a" to the input
// this is to prevent the "a" mnemonic to be captured as input to the text box
useEffect(() => {
setTimeout(() => {
if (linkInputRef.current) {

View File

@@ -1,5 +1,5 @@
import type { Bookmark, Tag } from "@markone/core"
import { useId, useRef } from "react"
import { useEffect, useId, useImperativeHandle, useRef } from "react"
import { useBookmarkTags, useUpdateBookmark } from "~/bookmark/api"
import { Button } from "~/components/button"
import { Dialog, DialogActionRow, DialogBody, DialogTitle } from "~/components/dialog"
@@ -7,12 +7,47 @@ import { FormField } from "~/components/form-field"
import { LoadingSpinner } from "~/components/loading-spinner"
import { Message, MessageVariant } from "~/components/message.tsx"
import { TagsInput, type TagsInputRef } from "~/components/tags-input"
import { useMnemonics } from "~/hooks/use-mnemonics.ts"
import { useBookmarkPageStore } from "../-store"
interface EditFormRef {
form: HTMLFormElement | null
titleInput: HTMLInputElement | null
tagsInput: TagsInputRef | null
}
function EditBookmarkDialog({ bookmark }: { bookmark: Bookmark }) {
const closeDialog = useBookmarkPageStore((state) => state.closeDialog)
const { data: tags, status } = useBookmarkTags(bookmark)
const editFormId = useId()
const editFormRef = useRef<EditFormRef | null>(null)
useMnemonics(
{
s: () => {
if (
editFormRef.current &&
editFormRef.current.titleInput !== document.activeElement &&
editFormRef.current.tagsInput?.input !== document.activeElement
) {
editFormRef.current.form?.requestSubmit()
}
},
c: () => {
if (
editFormRef.current?.titleInput !== document.activeElement &&
editFormRef.current?.tagsInput?.input !== document.activeElement
) {
closeDialog()
}
},
Escape: () => {
editFormRef.current?.titleInput?.blur()
editFormRef.current?.tagsInput?.input?.blur()
},
},
{ ignore: () => false },
)
function content() {
switch (status) {
@@ -23,7 +58,7 @@ function EditBookmarkDialog({ bookmark }: { bookmark: Bookmark }) {
</p>
)
case "success":
return <EditForm formId={editFormId} bookmark={bookmark} tags={tags} />
return <EditForm ref={editFormRef} formId={editFormId} bookmark={bookmark} tags={tags} />
case "error":
return null
}
@@ -45,11 +80,33 @@ function EditBookmarkDialog({ bookmark }: { bookmark: Bookmark }) {
)
}
function EditForm({ formId, bookmark, tags }: { formId: string; bookmark: Bookmark; tags: Tag[] }) {
function EditForm({
ref,
formId,
bookmark,
tags,
}: { ref: React.Ref<EditFormRef>; formId: string; bookmark: Bookmark; tags: Tag[] }) {
const formRef = useRef<HTMLFormElement | null>(null)
const titleInputRef = useRef<HTMLInputElement | null>(null)
const tagsInputRef = useRef<TagsInputRef>(null)
const updateBookmarkMutation = useUpdateBookmark(bookmark)
const closeDialog = useBookmarkPageStore((state) => state.closeDialog)
useImperativeHandle(ref, () => ({
form: formRef.current,
titleInput: titleInputRef.current,
tagsInput: tagsInputRef.current,
}))
// when using autoFocus, it also captures the "e" mnemonic
// which appends the "e" to the input
// this is to prevent the "e" mnemonic to be captured as input to the text box
useEffect(() => {
setTimeout(() => {
titleInputRef.current?.focus()
}, 0)
}, [])
async function onSubmit(event: React.FormEvent<HTMLFormElement>) {
if (tagsInputRef.current) {
event.preventDefault()
@@ -86,8 +143,9 @@ function EditForm({ formId, bookmark, tags }: { formId: string; bookmark: Bookma
return (
<>
{message()}
<form id={formId} onSubmit={onSubmit}>
<form ref={formRef} id={formId} onSubmit={onSubmit}>
<FormField
ref={titleInputRef}
type="text"
name="title"
label="TITLE"