soma: P3 cleanup — LinkPreview a11y section + TagGroup key API consistency

- LinkPreview README: elevate the "intentionally hidden from AT" note to
  its own `## Accessibility` section with the three reasons (duplicate
  content, hover-only activation, focus stays on trigger). Consumers
  reaching for an AT-visible preview are pointed at Popover / Tooltip.
- TagGroup `handleItemKeydown`: vertical nav now calls
  `getDirectionalKeys(dir, 'vertical')` (returns UP/DOWN absolute) instead
  of hardcoded `KEYS.ARROW_DOWN/UP`. Functionally identical — vertical
  keys don't flip under RTL — but keeps the shape symmetric with the
  horizontal branch and matches the convention used across the library.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
semantuix
dev 6 months ago
parent 8d4f53a73f
commit 50821aae44

@ -30,7 +30,28 @@ A floating preview card that appears on hover over a link. Supports configurable
| ------- | ------------- | ------ |
| Content | `aria-hidden` | `true` |
The preview content is intentionally hidden from assistive technology — it is a visual convenience only. The underlying link remains fully accessible.
## Accessibility
**LinkPreview is invisible to assistive technology by design.** The floating
preview card exists for sighted-hover discovery only — it adds no
information a screen-reader user could not already reach through the
underlying `<a>` element. Emitting `aria-hidden="true"` on `Content` is a
deliberate choice:
- **Duplicate content:** the preview typically mirrors the destination page
summary that a screen reader would announce after following the link.
Re-reading it as a tooltip is noise, not help.
- **Hover-only activation:** APG explicitly recommends against exposing
pure-hover widgets to assistive tech because keyboard / touch users never
see them anyway — making them invisible everyone except mouse hover is
the consistent experience.
- **Focus stays on the trigger:** the preview never steals focus, never
traps Tab, and closes automatically on blur. There is nothing for a
keyboard / AT user to miss.
If your LinkPreview contains content that is NOT in the destination page
(a custom CTA, a badge, a pricing hint), consider using `Popover` or
`Tooltip` instead — both are AT-visible.
## Data Attributes

@ -156,7 +156,11 @@ export class TagGroupProvider extends Provider<TagGroupOpts> {
handleItemKeydown(e: SomaKeyboardEvent<HTMLElement>, value: string) {
if (this.opts.disabled.current) return;
const dir = this.resolvedDir.current;
// Horizontal flips under RTL; vertical doesn't (UP / DOWN are absolute
// per APG). Using `getDirectionalKeys` for both axes keeps the shape
// symmetric — consistent with other components that navigate grids.
const { nextKey, prevKey } = getDirectionalKeys(dir, 'horizontal');
const { nextKey: downKey, prevKey: upKey } = getDirectionalKeys(dir, 'vertical');
const items = this.getItems();
if (items.length === 0) return;
const currentIndex = items.indexOf(e.currentTarget);
@ -171,9 +175,9 @@ export class TagGroupProvider extends Provider<TagGroupOpts> {
this.focusAt(currentIndex - 1);
return;
}
if (e.key === KEYS.ARROW_DOWN || e.key === KEYS.ARROW_UP) {
if (e.key === downKey || e.key === upKey) {
e.preventDefault();
const delta = e.key === KEYS.ARROW_DOWN ? 1 : -1;
const delta = e.key === downKey ? 1 : -1;
this.focusAt(currentIndex + delta);
return;
}

Loading…
Cancel
Save

Powered by TurnKey Linux.