diff --git a/src/app/projects/[projectId]/setup/evidence/RequirementsTable.tsx b/src/app/projects/[projectId]/setup/evidence/RequirementsTable.tsx index 31eb5271..8ded6f2c 100644 --- a/src/app/projects/[projectId]/setup/evidence/RequirementsTable.tsx +++ b/src/app/projects/[projectId]/setup/evidence/RequirementsTable.tsx @@ -44,8 +44,11 @@ const EMPTY_DRAFT: Draft = { namingRule: "", }; +// `pr-8` keeps the option text clear of the native chevron, which is drawn +// inside the control's right padding — at `px-2` a long stage name runs +// straight under it. const selectClass = - "w-full rounded-md border border-gray-200 bg-white px-2 py-1.5 text-sm text-gray-700 focus:border-indigo-400 focus:outline-none focus:ring-1 focus:ring-indigo-400 disabled:cursor-not-allowed disabled:bg-gray-50 disabled:text-gray-400"; + "w-full rounded-md border border-gray-200 bg-white px-2 py-1.5 pr-8 text-sm text-gray-700 focus:border-indigo-400 focus:outline-none focus:ring-1 focus:ring-indigo-400 disabled:cursor-not-allowed disabled:bg-gray-50 disabled:text-gray-400"; const inputClass = "w-full rounded-md border border-gray-200 bg-white px-2 py-1.5 font-mono text-xs text-gray-700 placeholder:font-sans placeholder:text-gray-400 focus:border-indigo-400 focus:outline-none focus:ring-1 focus:ring-indigo-400 disabled:cursor-not-allowed disabled:bg-gray-50"; @@ -67,6 +70,13 @@ export function RequirementsTable({ const collectionUrl = `/api/projects/${projectId}/workstreams/${workstream.workstreamId}/evidence-requirements`; + /** + * Ties the composer's controls to the form element below the table. Derived + * from the workstream rather than generated, so it is the same string on the + * server and in the browser — and distinct per workstream. + */ + const addFormId = `evidence-add-${workstream.workstreamId}`; + const refresh = () => queryClient.invalidateQueries({ queryKey: evidenceQueryKey(projectId) }); @@ -197,12 +207,14 @@ export function RequirementsTable({ Document - Stage + {/* Wide enough for "Whole workstream" and a stage name, chevron included. */} + Stage Naming rule Required - + {/* Wide enough for the composer's Add button, not just the bin. */} + @@ -312,22 +324,148 @@ export function RequirementsTable({ ))} + + {/* + The composer lives in the table's own ``, so its fields sit + in the same columns as the rows above by construction — no second + set of column captions to go subtly out of line, and the table's + headings label the composer too. + It stays obviously separate: a heavy rule above it, a tinted band, + and its own "Add a document" caption spanning the width. + The controls are associated with the `
` below by id rather + than being wrapped in one, because a `` cannot sit between a + `` and its rows. Enter still submits. + */} + {canManage && ( + + + {/* + The dividing rule hangs off this cell rather than off + ``: in the collapsed border model a row-group border + is the least reliably drawn of the two, and this one spans + the full width anyway. + */} + + + + + + + + + + + + + + )}
+ + + Add a document + +
+ + + + + + setDraft({ ...draft, namingRule: event.target.value }) + } + /> + + + setDraft({ ...draft, required: event.target.checked }) + } + /> + + +
+ {hasStages + ? "Leave the stage as “Whole workstream” to expect the document at any point." + : "This workstream has no stages yet, so a requirement applies to the workstream as a whole. Tag it with a stage once the ladder exists."} +
{/* - The composer is deliberately *not* a twelfth column-aligned row. - Labelled cells sitting under the table's own headings read as a second - header row — two near-identical sets of words, never quite in line, - which is at its worst when the table is empty. So it announces itself - with its own heading and lays its controls out as a form: the fields - carry placeholders and `aria-label`s rather than column captions, and - they are free to size themselves. + The form the composer's controls belong to. It carries the submit + handler and nothing else — the fields themselves are up in the table's + footer, pointed here by their `form` attribute. */} {canManage && ( { event.preventDefault(); if (!draft.fileType) { @@ -336,101 +474,7 @@ export function RequirementsTable({ } add.mutate(draft); }} - > -

- - Add a document -

- -
- - - - - - setDraft({ ...draft, namingRule: event.target.value }) - } - /> - - - - -
- -

- {hasStages - ? "Leave the stage unset to expect the document at any point in the workstream." - : "This workstream has no stages yet, so a requirement applies to the workstream as a whole. Tag it with a stage once the ladder exists."} -

-
+ /> )}