mirror of
https://github.com/we-promise/sure.git
synced 2026-05-24 21:14:56 +00:00
* fix(design-system): DS::Link a11y — distinguishable default, icon-only label, external-link hardening Closes #1739. DS::Link extends Buttonish, so the styled variants (`:primary`, `:secondary`, `:icon`, `:ghost`, etc.) inherit the Buttonish styling pipeline. The `default` variant is the bare inline link, which had multiple a11y gaps: 1. **WCAG 1.4.1 — color is not the only difference.** The default variant had `container_classes: ""`, so a link rendered as plain text-color text with no underline, no weight change, nothing. Color-only differentiation fails WCAG 1.4.1 for low-vision and colorblind users. Now: `text-link underline underline-offset-2 hover:no-underline` — underlined at rest, underline removed on hover for a polish hint, plus the `text-link` token (blue-600 light / blue-500 dark) for color. 2. **Focus ring.** `<a>` doesn't pick up the `button` focus rule from base.css (#1738). Add `focus-visible:outline-2 outline-offset-2 outline-gray-900 theme-dark:outline-white` directly on the default variant. The Buttonish-derived variants render as buttons visually but as `<a>` in markup — out of scope here; covered by their own callsites styling. 3. **Icon-only accessible name.** Mirror the DS::Button fix from #1738: derive a humanized `aria-label` from the icon key when the caller doesn't provide one, so AT users hear "More horizontal" instead of just the URL. 4. **External-link hardening.** `target="_blank"` without `rel="noopener"` exposes `window.opener` to the new tab (reverse-tabnabbing). Always set `noopener noreferrer` when the target is `_blank`. Authors can override by passing `rel:` explicitly. 5. **sr-only "(opens in new tab)" hint.** Append an `sr-only` span after the link text when `target="_blank"` so AT users hear the navigation behavior. Visual indication (e.g. an external-link icon) stays at the caller's discretion. Locale key: `ds.link.opens_in_new_tab` (en only — other locales in a separate translation pass per repo norm). API unchanged. No existing callsites use `target="_blank"` or icon-only links, so no migration needed. * fix(review): fold new-tab cue into icon-only aria-label When an icon-only DS::Link also targets `_blank`, the generated `aria-label` was overriding the descendant accessible name, masking the sr-only "(opens in new tab)" span. Include the cue directly in the generated label so AT users hear the warning. Also switch `capitalize` to `humanize` so multi-word icon keys like `external-link` read as "External link" rather than "External link" already worked but `humanize` is the more idiomatic Rails choice and keeps us aligned with the suggested patch. Flagged by Codex P2 + CodeRabbit on PR #1844. * fix(review): swap raw outline palette to alpha-ring tokens Codex P1 follow-up after the ready-for-review transition: the default \`DS::Link\` focus ring used raw \`outline-gray-900\` + \`theme-dark:focus-visible:outline-white\`, which violates the DS-hygiene rule that bans raw Tailwind palette utilities in component styling. Swap to the established alpha-ring pattern already used by DS::Toggle (#1843), DS::Tooltip (#1845), provider_card, and form-field — \`focus-visible:ring-2 focus-visible:ring-alpha-black-300\` + \`theme-dark:focus-visible:ring-alpha-white-300\`. Same visual contract (WCAG 1.4.11), theme tokens centralized.
18 lines
483 B
Plaintext
18 lines
483 B
Plaintext
<%= link_to href, **merged_opts do %>
|
|
<% if icon && (icon_position != "right") %>
|
|
<%= helpers.icon(icon, size: size, color: icon_color) %>
|
|
<% end %>
|
|
|
|
<% unless icon_only? %>
|
|
<%= text %>
|
|
<% end %>
|
|
|
|
<% if icon && icon_position == "right" %>
|
|
<%= helpers.icon(icon, size: size, color: icon_color) %>
|
|
<% end %>
|
|
|
|
<% if opens_in_new_tab? %>
|
|
<span class="sr-only"><%= t("ds.link.opens_in_new_tab", default: "(opens in new tab)") %></span>
|
|
<% end %>
|
|
<% end %>
|