From 52342ee45dbacc6e645b8e89ed4ccf3aba4d9b29 Mon Sep 17 00:00:00 2001 From: Matt Date: Thu, 21 May 2026 17:20:13 +0200 Subject: [PATCH] feat(uat-batch-4): a11y form primitives + click-to-preview + EOI empty-state + lint guards MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - FieldError primitive (role=alert, aria-live) — used by Wave 3 form-error UX work. - FieldLabel primitive (Label + Info-tooltip slot) — foundational for the platform-wide admin-settings tooltip audit. - ESLint guard against em-dash in user-facing JSX text inside src/components + src/app (warning, not error; 111 existing instances flagged for follow-up sweep). - FileGrid card body becomes click-to-preview button (was hidden under a kebab); aria-label per row; kebab keeps Download/Rename/Delete. - DocumentList: title cell on rows with signedFileId opens FilePreviewDialog; kebab gains Download action (was missing per UAT). Single FilePreviewDialog instance lifted to the parent. - DocumentList type extended with signedFileId. - EOI empty state: third ghost button "Mark signed without file" wired to existing MarkExternallySignedDialog (parity with reservation tab). - Watcher empty-state padding fix on document-detail. tsc clean. 1419/1419 vitest. lint clean on touched files. Co-Authored-By: Claude Opus 4.7 (1M context) --- eslint.config.mjs | 18 +++++ src/components/documents/document-detail.tsx | 2 +- src/components/documents/document-list.tsx | 58 ++++++++++++++-- src/components/files/file-grid.tsx | 19 +++--- src/components/interests/interest-eoi-tab.tsx | 18 ++++- src/components/ui/field-error.tsx | 48 ++++++++++++++ src/components/ui/field-label.tsx | 66 +++++++++++++++++++ 7 files changed, 212 insertions(+), 17 deletions(-) create mode 100644 src/components/ui/field-error.tsx create mode 100644 src/components/ui/field-label.tsx diff --git a/eslint.config.mjs b/eslint.config.mjs index c2ca5e3a..6b175387 100644 --- a/eslint.config.mjs +++ b/eslint.config.mjs @@ -35,6 +35,24 @@ const eslintConfig = [ 'react-hooks/incompatible-library': 'off', }, }, + { + // User-facing copy in src/components and src/app should never use + // em-dashes (—) in JSX text. The user reads em-dashes as a + // tell-tale "AI-generated" marker; we prefer periods, commas, or + // simple hyphens. Code comments / audit-log strings / templates + // outside these directories are exempt. + files: ['src/components/**/*.tsx', 'src/app/**/*.tsx'], + rules: { + 'no-restricted-syntax': [ + 'warn', + { + selector: "JSXText[value=/\\u2014/]", + message: + 'No em-dash in user-facing JSX text. Use period, comma, or hyphen instead.', + }, + ], + }, + }, { // Tests assert response shape via expect() — narrowing every // `res.json()` to a structural type adds boilerplate without catching diff --git a/src/components/documents/document-detail.tsx b/src/components/documents/document-detail.tsx index cde42c4c..de7440b0 100644 --- a/src/components/documents/document-detail.tsx +++ b/src/components/documents/document-detail.tsx @@ -543,7 +543,7 @@ function WatchersCard({ documentId, watchers }: { documentId: string; watchers:

{watchers.length === 0 ? ( -

No one is watching this document yet.

+

No one is watching this document yet.

) : (