mirror of
https://github.com/Memo-2023/mana-monorepo.git
synced 2026-05-22 01:26:41 +02:00
fix(shared-ui): TagChip nested button + Pill svelte:element ARIA role
Some checks are pending
CD Mac Mini / Detect Changes (push) Waiting to run
CD Mac Mini / Deploy (push) Blocked by required conditions
CI / Detect Changes (push) Waiting to run
CI / Validate (push) Waiting to run
CI / Build mana-search (push) Blocked by required conditions
CI / Build mana-sync (push) Blocked by required conditions
CI / Build mana-api-gateway (push) Blocked by required conditions
CI / Build mana-crawler (push) Blocked by required conditions
Docker Validate / Validate Dockerfiles (push) Waiting to run
Docker Validate / Build calendar-web (push) Blocked by required conditions
Docker Validate / Build quotes-web (push) Blocked by required conditions
Docker Validate / Build todo-backend (push) Blocked by required conditions
Docker Validate / Build todo-web (push) Blocked by required conditions
Docker Validate / Build mana-auth (push) Blocked by required conditions
Docker Validate / Build mana-sync (push) Blocked by required conditions
Docker Validate / Build mana-media (push) Blocked by required conditions
Mirror to Forgejo / Push to Forgejo (push) Waiting to run
Some checks are pending
CD Mac Mini / Detect Changes (push) Waiting to run
CD Mac Mini / Deploy (push) Blocked by required conditions
CI / Detect Changes (push) Waiting to run
CI / Validate (push) Waiting to run
CI / Build mana-search (push) Blocked by required conditions
CI / Build mana-sync (push) Blocked by required conditions
CI / Build mana-api-gateway (push) Blocked by required conditions
CI / Build mana-crawler (push) Blocked by required conditions
Docker Validate / Validate Dockerfiles (push) Waiting to run
Docker Validate / Build calendar-web (push) Blocked by required conditions
Docker Validate / Build quotes-web (push) Blocked by required conditions
Docker Validate / Build todo-backend (push) Blocked by required conditions
Docker Validate / Build todo-web (push) Blocked by required conditions
Docker Validate / Build mana-auth (push) Blocked by required conditions
Docker Validate / Build mana-sync (push) Blocked by required conditions
Docker Validate / Build mana-media (push) Blocked by required conditions
Mirror to Forgejo / Push to Forgejo (push) Waiting to run
Beide standen seit dem letzten shared-ui-Sync (ce923bbdc) als
svelte-check --fail-on-warnings Treffer im Pre-Push-Hook drin.
Aufgeräumt für die Cutover-PRs.
TagChip: outer war `<button>` mit innerem Remove-`<button>` —
verschachtelte interaktive Elemente sind invalid HTML und brechen
SSR-Hydration. Outer ist jetzt `<span role="button" tabindex="0">`
mit Enter/Space-Keyboard-Handler. CSS-Selektor `button.chip` →
`.chip-interactive` Klasse.
Pill: `<svelte:element this={tag}>` mit onclick/oncontextmenu
braucht explizite ARIA-Rolle (button bzw. link), weil der
statische Analyser den dynamischen Tag nicht aufdröselt.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
db1dc9a738
commit
abafdfbeb3
2 changed files with 30 additions and 8 deletions
|
|
@ -34,16 +34,31 @@
|
|||
e.stopPropagation();
|
||||
onRemove?.();
|
||||
}
|
||||
|
||||
// Outer kann nicht `<button>` sein wenn innen ein Remove-`<button>`
|
||||
// liegt — verschachtelte interaktive Elemente sind invalid HTML
|
||||
// (svelte-check fail-on-warnings). Lösung: outer als `<span
|
||||
// role="button">` mit Keyboard-Handler, damit der ganze Chip
|
||||
// klickbar bleibt und der Remove-Button sein eigener interaktiver
|
||||
// Bereich ist.
|
||||
function handleChipKey(e: KeyboardEvent) {
|
||||
if (e.key === 'Enter' || e.key === ' ') {
|
||||
e.preventDefault();
|
||||
onclick?.(e as unknown as MouseEvent);
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
{#if onclick}
|
||||
<button
|
||||
type="button"
|
||||
class="chip size-{size}"
|
||||
<span
|
||||
role="button"
|
||||
tabindex="0"
|
||||
class="chip chip-interactive size-{size}"
|
||||
class:active
|
||||
class:has-color={!!color}
|
||||
style:--tag-color={color || null}
|
||||
{onclick}
|
||||
onkeydown={handleChipKey}
|
||||
>
|
||||
{#if color}
|
||||
<span class="dot" aria-hidden="true"></span>
|
||||
|
|
@ -54,7 +69,7 @@
|
|||
<DynamicIcon name="x" size="xs" />
|
||||
</button>
|
||||
{/if}
|
||||
</button>
|
||||
</span>
|
||||
{:else}
|
||||
<span
|
||||
class="chip size-{size}"
|
||||
|
|
@ -91,19 +106,19 @@
|
|||
cursor: default;
|
||||
}
|
||||
|
||||
button.chip {
|
||||
.chip-interactive {
|
||||
cursor: pointer;
|
||||
transition:
|
||||
background-color 0.15s ease,
|
||||
border-color 0.15s ease;
|
||||
}
|
||||
|
||||
button.chip:hover {
|
||||
.chip-interactive:hover {
|
||||
background: hsl(var(--color-surface-hover));
|
||||
border-color: hsl(var(--color-primary) / 0.4);
|
||||
}
|
||||
|
||||
button.chip:focus-visible {
|
||||
.chip-interactive:focus-visible {
|
||||
outline: 2px solid hsl(var(--color-primary));
|
||||
outline-offset: 2px;
|
||||
}
|
||||
|
|
@ -162,7 +177,7 @@
|
|||
}
|
||||
|
||||
@media (prefers-reduced-motion: reduce) {
|
||||
button.chip {
|
||||
.chip-interactive {
|
||||
transition: none;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -55,11 +55,18 @@
|
|||
}: Props = $props();
|
||||
|
||||
const tag = $derived(href ? 'a' : 'button');
|
||||
// svelte-check `--fail-on-warnings` will an Dynamic-Elementen mit
|
||||
// click/context-handler explizit eine ARIA-Rolle sehen, weil der
|
||||
// statische Analyser nicht weiß, dass `<button>`/`<a>` schon
|
||||
// inhärent interaktiv sind. Für button reicht `button`, für a
|
||||
// (Link) ist `link` die korrekte Rolle.
|
||||
const explicitRole = $derived(tag === 'a' ? 'link' : 'button');
|
||||
</script>
|
||||
|
||||
<svelte:element
|
||||
this={tag}
|
||||
bind:this={element}
|
||||
role={explicitRole}
|
||||
class="pill size-{size} {className}"
|
||||
class:active
|
||||
class:disabled
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue