fix(frontend): clear svelte-check a11y and reactivity warnings
- TagBadge: derive color/style so they track a changing tag prop. - FilterBar: seed tokens from the value prop via untrack (the effect keeps it in sync), silencing state_referenced_locally. - FileCard: give the interactive card role="button". - admin user toggles: add aria-labels to the switch buttons. svelte-check is now clean (0 errors, 0 warnings). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -138,6 +138,8 @@
|
|||||||
class:focused
|
class:focused
|
||||||
use:lazyload
|
use:lazyload
|
||||||
data-file-index={index}
|
data-file-index={index}
|
||||||
|
role="button"
|
||||||
|
tabindex="-1"
|
||||||
onpointerdown={onPointerDown}
|
onpointerdown={onPointerDown}
|
||||||
onpointermove={onPointerMoveInternal}
|
onpointermove={onPointerMoveInternal}
|
||||||
onpointerup={() => {
|
onpointerup={() => {
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
|
import { untrack } from 'svelte';
|
||||||
import type { Tag } from '$lib/api/types';
|
import type { Tag } from '$lib/api/types';
|
||||||
import { fetchAllTags } from '$lib/api/tags';
|
import { fetchAllTags } from '$lib/api/tags';
|
||||||
import { buildDslFilter, parseDslFilter, tokenLabel } from '$lib/utils/dsl';
|
import { buildDslFilter, parseDslFilter, tokenLabel } from '$lib/utils/dsl';
|
||||||
@@ -16,7 +17,9 @@
|
|||||||
|
|
||||||
let tags = $state<Tag[]>([]);
|
let tags = $state<Tag[]>([]);
|
||||||
let search = $state('');
|
let search = $state('');
|
||||||
let tokens = $state<string[]>(parseDslFilter(value));
|
// Seed from the prop once; the $effect below keeps it in sync afterwards, so
|
||||||
|
// read it untracked to avoid the state-referenced-locally warning.
|
||||||
|
let tokens = $state<string[]>(untrack(() => parseDslFilter(value)));
|
||||||
let tagNames = $derived(
|
let tagNames = $derived(
|
||||||
new Map(tags.filter((t) => t.id && t.name).map((t) => [t.id as string, t.name as string]))
|
new Map(tags.filter((t) => t.id && t.name).map((t) => [t.id as string, t.name as string]))
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -13,8 +13,8 @@
|
|||||||
|
|
||||||
let { tag, onclick, size = 'md', focused = false, index }: Props = $props();
|
let { tag, onclick, size = 'md', focused = false, index }: Props = $props();
|
||||||
|
|
||||||
const color = tag.color ?? tag.category_color;
|
let color = $derived(tag.color ?? tag.category_color);
|
||||||
const style = color ? `background-color: #${color}` : '';
|
let style = $derived(color ? `background-color: #${color}` : '');
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
{#if onclick}
|
{#if onclick}
|
||||||
|
|||||||
@@ -107,6 +107,7 @@
|
|||||||
class:on={isAdmin}
|
class:on={isAdmin}
|
||||||
role="switch"
|
role="switch"
|
||||||
aria-checked={isAdmin}
|
aria-checked={isAdmin}
|
||||||
|
aria-label="Admin"
|
||||||
onclick={() => (isAdmin = !isAdmin)}><span class="thumb"></span></button
|
onclick={() => (isAdmin = !isAdmin)}><span class="thumb"></span></button
|
||||||
>
|
>
|
||||||
</div>
|
</div>
|
||||||
@@ -121,6 +122,7 @@
|
|||||||
class:on={canCreate}
|
class:on={canCreate}
|
||||||
role="switch"
|
role="switch"
|
||||||
aria-checked={canCreate}
|
aria-checked={canCreate}
|
||||||
|
aria-label="Can create"
|
||||||
onclick={() => (canCreate = !canCreate)}><span class="thumb"></span></button
|
onclick={() => (canCreate = !canCreate)}><span class="thumb"></span></button
|
||||||
>
|
>
|
||||||
</div>
|
</div>
|
||||||
@@ -140,6 +142,7 @@
|
|||||||
class:danger={isBlocked}
|
class:danger={isBlocked}
|
||||||
role="switch"
|
role="switch"
|
||||||
aria-checked={isBlocked}
|
aria-checked={isBlocked}
|
||||||
|
aria-label="Blocked"
|
||||||
onclick={() => (isBlocked = !isBlocked)}><span class="thumb"></span></button
|
onclick={() => (isBlocked = !isBlocked)}><span class="thumb"></span></button
|
||||||
>
|
>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Reference in New Issue
Block a user