Skip to content

fix(ui): keep the alert type word in the accessible name on every engine (ui 0.38.2) - #1511

Merged
backnotprop merged 1 commit into
mainfrom
fix/ui-0.38.2-alert-title-a11y
Sep 11, 2026
Merged

backnotprop merged 1 commit into
mainfrom
fix/ui-0.38.2-alert-title-a11y

Conversation

@backnotprop

Copy link
Copy Markdown
Owner

What

@plannotator/ui 0.38.2 on core 0.25.2 (core unchanged, not republished).

  1. Accessibility (Safari regression from 0.38.1). The titled alert row carried aria-label="<Type>: <title>" on a plain div. ARIA prohibits naming a generic element; Chrome exposes it, WebKit drops it, so VoiceOver on Safari read only the bold title. The type word now rides a visually hidden sr-only span before the title. Reported by the Workspaces design review of 0.38.1 (finding MEDIUM 2).
  2. Seam contract. alertIconRenderer was consulted even when the title line carried an emoji (result discarded). Now consulted only for a title line with an icon comment and no emoji, as documented.
  3. React peer back to ^19.2.3 (0.38.1 declared ^19.2.8 from the dependency batch; nothing in the package needs it; consumers pinning 19.2.7 got an unmet-peer warning).
  4. CI. The two alert DOM test files from feat(ui): render a GitHub alert's bold-only first line as its title, with an icon seam #1509 were never in test.yml's explicit DOM list, so they had been silently skipping. Registered; the seam-contract bug in (2) is what they caught once run.

Verification

  • DOM_TESTS=1 bun test --isolate on both alert test files: 14/14 (13/14 before fix 2).
  • tsc --noEmit -p packages/ui/tsconfig.json clean.
  • bun run --cwd packages/ui smoke:package against the published core 0.25.2: passes (the registry check now runs for real).
  • Full bun test packages/ui: unchanged, 0 fail.

Do not publish from this PR; the owner publishes.

…ine (ui 0.38.2)

ui 0.38.1 named a titled alert's row with aria-label="<Type>: <title>" on
a plain div. ARIA prohibits naming a generic element: Chrome exposes it,
WebKit drops it, so VoiceOver on Safari read only the bold title and lost
the type word that 0.37.0 showed as text. The type word now rides a
visually hidden sr-only span before the title, which every engine reads.

Also: the alertIconRenderer seam was consulted even when the title line
carried an emoji (its result was discarded, so rendering was right, but
the contract says it is not called); it is now called only for a title
line with an icon comment and no emoji. Caught by the seam test, which,
like the title test, had been silently skipped: both are DOM-gated and
were missing from the CI DOM list in test.yml. Registered now.

React peer loosened back to ^19.2.3 (0.38.1 declared ^19.2.8 only because
the dependency batch moved it; nothing in the package needs a newer API).

Verified: DOM_TESTS=1 bun test --isolate on both alert test files 14/14,
tsc clean, smoke:package against the published core 0.25.2, full ui suite
unchanged.
@backnotprop
backnotprop merged commit 0f2bd60 into main Sep 11, 2026
28 checks passed
@backnotprop
backnotprop deleted the fix/ui-0.38.2-alert-title-a11y branch September 11, 2026 20:24
backnotprop added a commit that referenced this pull request Sep 15, 2026
…d quotes

#1509 hoisted an alert's bold-only first line onto the icon row and #1511 put
a visually hidden "<Type>: " span there. Both changed the DOM text of an
annotatable block, which the annotation layer reads.

- Viewer turns on the hook's content-verifying restore. web-highlighter's
  stored metas are positional (`parentIndex` is the index among all elements
  of that tag), so a titled alert that stopped contributing its own `<p>`
  renumbers every later anchor: a pre-upgrade draft resolved silently onto the
  wrong text with nothing to reject it. Verification drops the bad resolve and
  falls through to the text-search rescue. Cost measured at ~5% of a
  300-annotation restore (no extra DOM query; `getDoms` was already called).

- The sr-only type word is marked `annotation-exclude`, and a new annotation's
  quote drops excluded chrome. The class alone was not enough: the highlighter
  skips excluded nodes when painting and searching, but the quote comes from
  the browser's selection string, so a drag starting over the icon still
  produced `originalText: "Tip:Browser quirks"` — a word the reviewer never
  selected, exported to the agent, and unfindable on a share-link restore. The
  painted highlight is now the authority on content and the selection string on
  formatting: excluded runs are removed and the result kept only when it
  matches what was painted, so any unrecognized shape leaves the quote as is.

- An emoji-only first line becoming the alert's icon is intended (the
  documented grammar admits an emoji without a title precisely so it can be the
  icon); the existing case now records that decision and pins that the line is
  relocated, not duplicated.
backnotprop added a commit that referenced this pull request Sep 15, 2026
…d quotes (#1535)

#1509 hoisted an alert's bold-only first line onto the icon row and #1511 put
a visually hidden "<Type>: " span there. Both changed the DOM text of an
annotatable block, which the annotation layer reads.

- Viewer turns on the hook's content-verifying restore. web-highlighter's
  stored metas are positional (`parentIndex` is the index among all elements
  of that tag), so a titled alert that stopped contributing its own `<p>`
  renumbers every later anchor: a pre-upgrade draft resolved silently onto the
  wrong text with nothing to reject it. Verification drops the bad resolve and
  falls through to the text-search rescue. Cost measured at ~5% of a
  300-annotation restore (no extra DOM query; `getDoms` was already called).

- The sr-only type word is marked `annotation-exclude`, and a new annotation's
  quote drops excluded chrome. The class alone was not enough: the highlighter
  skips excluded nodes when painting and searching, but the quote comes from
  the browser's selection string, so a drag starting over the icon still
  produced `originalText: "Tip:Browser quirks"` — a word the reviewer never
  selected, exported to the agent, and unfindable on a share-link restore. The
  painted highlight is now the authority on content and the selection string on
  formatting: excluded runs are removed and the result kept only when it
  matches what was painted, so any unrecognized shape leaves the quote as is.

- An emoji-only first line becoming the alert's icon is intended (the
  documented grammar admits an emoji without a title precisely so it can be the
  icon); the existing case now records that decision and pins that the line is
  relocated, not duplicated.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant