Fix a11y label associations across components

- Add for/id attributes to associate labels with form controls in PipelinePanel
- Add for/id for pipeline select in +page.svelte
- Change Device label to span since DeviceSelector has its own internal label

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
2026-05-14 08:38:47 -04:00
parent d9d10cd6fb
commit ea6a0bd9ca
2 changed files with 20 additions and 11 deletions

View File

@@ -92,11 +92,12 @@
<div class="flex flex-col h-full"> <div class="flex flex-col h-full">
<!-- Preset selector --> <!-- Preset selector -->
<div class="p-4 border-b border-grey-200"> <div class="p-4 border-b border-grey-200">
<label class="block text-xs font-medium text-grey-500 uppercase tracking-wide mb-2"> <label for="preset-select" class="block text-xs font-medium text-grey-500 uppercase tracking-wide mb-2">
Preset Preset
</label> </label>
<div class="flex gap-2"> <div class="flex gap-2">
<select <select
id="preset-select"
class=" class="
flex-1 px-3 py-2 flex-1 px-3 py-2
bg-white text-ink text-sm bg-white text-ink text-sm
@@ -174,8 +175,9 @@
defaultExpanded defaultExpanded
> >
{#snippet children()} {#snippet children()}
<label class="block text-xs text-grey-500 mb-1">Mode</label> <label for="crop-mode" class="block text-xs text-grey-500 mb-1">Mode</label>
<select <select
id="crop-mode"
class="w-full px-2 py-1.5 text-sm border border-grey-200 rounded-md" class="w-full px-2 py-1.5 text-sm border border-grey-200 rounded-md"
value={config.crop.mode} value={config.crop.mode}
onchange={(e) => updateStep('crop', { mode: (e.target as HTMLSelectElement).value as CropMode })} onchange={(e) => updateStep('crop', { mode: (e.target as HTMLSelectElement).value as CropMode })}
@@ -195,8 +197,9 @@
defaultExpanded defaultExpanded
> >
{#snippet children()} {#snippet children()}
<label class="block text-xs text-grey-500 mb-1">Mode</label> <label for="resize-mode" class="block text-xs text-grey-500 mb-1">Mode</label>
<select <select
id="resize-mode"
class="w-full px-2 py-1.5 text-sm border border-grey-200 rounded-md" class="w-full px-2 py-1.5 text-sm border border-grey-200 rounded-md"
value={config.resize.mode} value={config.resize.mode}
onchange={(e) => updateStep('resize', { mode: (e.target as HTMLSelectElement).value as ResizeMode })} onchange={(e) => updateStep('resize', { mode: (e.target as HTMLSelectElement).value as ResizeMode })}
@@ -281,9 +284,10 @@
onToggle={(enabled) => updateStep('autoLevels', { enabled })} onToggle={(enabled) => updateStep('autoLevels', { enabled })}
> >
{#snippet children()} {#snippet children()}
<label class="block text-xs text-grey-500 mb-1">Clip %</label> <label for="autolevels-clip" class="block text-xs text-grey-500 mb-1">Clip %</label>
<div class="flex items-center gap-2"> <div class="flex items-center gap-2">
<input <input
id="autolevels-clip"
type="range" type="range"
min="0" min="0"
max="5" max="5"
@@ -305,8 +309,9 @@
defaultExpanded defaultExpanded
> >
{#snippet children()} {#snippet children()}
<label class="block text-xs text-grey-500 mb-1">Method</label> <label for="greyscale-method" class="block text-xs text-grey-500 mb-1">Method</label>
<select <select
id="greyscale-method"
class="w-full px-2 py-1.5 text-sm border border-grey-200 rounded-md" class="w-full px-2 py-1.5 text-sm border border-grey-200 rounded-md"
value={config.greyscale.method} value={config.greyscale.method}
onchange={(e) => updateStep('greyscale', { method: (e.target as HTMLSelectElement).value as GreyscaleMethod })} onchange={(e) => updateStep('greyscale', { method: (e.target as HTMLSelectElement).value as GreyscaleMethod })}
@@ -325,9 +330,10 @@
onToggle={(enabled) => updateStep('sharpen', { enabled })} onToggle={(enabled) => updateStep('sharpen', { enabled })}
> >
{#snippet children()} {#snippet children()}
<label class="block text-xs text-grey-500 mb-1">Amount</label> <label for="sharpen-amount" class="block text-xs text-grey-500 mb-1">Amount</label>
<div class="flex items-center gap-2"> <div class="flex items-center gap-2">
<input <input
id="sharpen-amount"
type="range" type="range"
min="0" min="0"
max="100" max="100"
@@ -348,8 +354,9 @@
onToggle={(enabled) => updateStep('quantize', { enabled })} onToggle={(enabled) => updateStep('quantize', { enabled })}
> >
{#snippet children()} {#snippet children()}
<label class="block text-xs text-grey-500 mb-1">Levels</label> <label for="quantize-levels" class="block text-xs text-grey-500 mb-1">Levels</label>
<select <select
id="quantize-levels"
class="w-full px-2 py-1.5 text-sm border border-grey-200 rounded-md" class="w-full px-2 py-1.5 text-sm border border-grey-200 rounded-md"
value={config.quantize.levels} value={config.quantize.levels}
onchange={(e) => updateStep('quantize', { levels: parseInt((e.target as HTMLSelectElement).value) })} onchange={(e) => updateStep('quantize', { levels: parseInt((e.target as HTMLSelectElement).value) })}
@@ -373,8 +380,9 @@
onToggle={(enabled) => updateStep('dither', { enabled })} onToggle={(enabled) => updateStep('dither', { enabled })}
> >
{#snippet children()} {#snippet children()}
<label class="block text-xs text-grey-500 mb-1">Algorithm</label> <label for="dither-algorithm" class="block text-xs text-grey-500 mb-1">Algorithm</label>
<select <select
id="dither-algorithm"
class="w-full px-2 py-1.5 text-sm border border-grey-200 rounded-md" class="w-full px-2 py-1.5 text-sm border border-grey-200 rounded-md"
value={config.dither.algorithm} value={config.dither.algorithm}
onchange={(e) => updateStep('dither', { algorithm: (e.target as HTMLSelectElement).value as DitherAlgorithm })} onchange={(e) => updateStep('dither', { algorithm: (e.target as HTMLSelectElement).value as DitherAlgorithm })}

View File

@@ -399,18 +399,19 @@
<!-- Controls bar --> <!-- Controls bar -->
<div class="flex flex-col sm:flex-row sm:items-end justify-between gap-4 mb-6"> <div class="flex flex-col sm:flex-row sm:items-end justify-between gap-4 mb-6">
<div class="flex-1 max-w-xs"> <div class="flex-1 max-w-xs">
<label class="block text-xs font-medium text-grey-500 uppercase tracking-wide mb-1.5"> <span class="block text-xs font-medium text-grey-500 uppercase tracking-wide mb-1.5">
Device Device
</label> </span>
<DeviceSelector onCustomClick={openCustomModal} /> <DeviceSelector onCustomClick={openCustomModal} />
</div> </div>
<div class="w-full sm:w-auto sm:max-w-xs"> <div class="w-full sm:w-auto sm:max-w-xs">
<label class="block text-xs font-medium text-grey-500 uppercase tracking-wide mb-1.5"> <label for="pipeline-select" class="block text-xs font-medium text-grey-500 uppercase tracking-wide mb-1.5">
Pipeline Pipeline
</label> </label>
<div class="flex items-center gap-2"> <div class="flex items-center gap-2">
<select <select
id="pipeline-select"
class=" class="
flex-1 px-3 py-2 flex-1 px-3 py-2
bg-white text-ink text-sm bg-white text-ink text-sm