/** * Shared task-modal pieces: the overlay shell (backdrop, form, title, error, * footer) and the title/description/prompt field trio used by both the * NewTaskModal and the EditTaskModal. State stays in the owning modal; these * are controlled components. */ import type { ReactNode } from 'react' import { TAG_NAME_MAX_LENGTH, TAG_PROMPT_MAX_LENGTH, TASK_TAG_LIMIT, normalizeTags, type TaskTag } from '../../core/tasks.ts' import { t } from '../locales.ts' import css from '../board.module.css' /** DOM id shared by the tag-name inputs and their datalist (one board at a time). */ const TAG_NAME_LIST_ID = 'dsh-task-board-tag-names' /** Modal overlay: closes on backdrop press, submits through the form. */ export function ModalShell({ ariaLabel, title, error, pending, submitLabel, onSubmit, onClose, secondaryAction, children, }: { ariaLabel: string title: string error: string | undefined pending: boolean submitLabel: string onSubmit: () => void onClose: () => void /** Optional second action beside the primary submit (e.g. create and run). */ secondaryAction?: { label: string; onSubmit: () => void } children: ReactNode }) { return (
{ if (event.target === event.currentTarget) onClose() }}>
{ event.preventDefault(); onSubmit() }} >

{title}

{children} {error !== undefined &&

{error}

}
) } /** Title + description + prompt fields shared by the new and edit task forms. */ export function TaskContentFields({ title, description, prompt, onTitleChange, onDescriptionChange, onPromptChange, }: { title: string description: string prompt: string /** Receives the new title; the owner also clears its error state. */ onTitleChange: (value: string) => void onDescriptionChange: (value: string) => void onPromptChange: (value: string) => void }) { return ( <>