feat: standardize FieldShell accessibility boundary (AEG-V16-017)

Centralize label, error, help, required, and ARIA relationships across core field wrappers. Preserve WBS evidence and keep the item IN_PROGRESS pending predecessor acceptance evidence.

Evidence: frontend pnpm typecheck; pnpm test (42/42); pnpm build.
This commit is contained in:
2026-08-08 12:51:51 +09:00
parent 8c777df66b
commit 7304aafc83
16 changed files with 458 additions and 352 deletions
@@ -1,18 +1,13 @@
<script setup lang="ts">
import { computed, useId } from 'vue'
import type { UiSelectOption } from '../adapter/contracts'
import { useUiAdapter } from '../adapter/useUiAdapter'
import FieldShell from './FieldShell.vue'
const props = defineProps<{ modelValue: unknown; label: string; options: UiSelectOption[]; inputId?: string; disabled?: boolean; required?: boolean; error?: string; help?: string; placeholder?: string }>()
const emit = defineEmits<{ 'update:modelValue': [value: unknown]; blur: [event: FocusEvent] }>()
const adapter = useUiAdapter()
const generatedId = useId()
const resolvedId = computed(() => props.inputId ?? `ks-select-${generatedId}`)
</script>
<template>
<div class="ks-field">
<label :for="resolvedId">{{ label }} <span v-if="required" aria-hidden="true">*</span></label>
<component :is="adapter.components.Select" :input-id="resolvedId" :model-value="modelValue" :options="options" :disabled="disabled" :invalid="Boolean(error)" :placeholder="placeholder" @update:model-value="emit('update:modelValue', $event)" @blur="emit('blur', $event)" />
<small v-if="error || help" :class="{ 'ks-danger-text': error }">{{ error ?? help }}</small>
</div>
<FieldShell :label="label" :input-id="inputId" :required="required" :error="error" :help="help" v-slot="field">
<component :is="adapter.components.Select" :input-id="field.inputId" :model-value="modelValue" :options="options" :disabled="disabled" :invalid="field.invalid" :placeholder="placeholder" :aria-describedby="field.describedBy" :aria-required="field.required || undefined" @update:model-value="emit('update:modelValue', $event)" @blur="emit('blur', $event)" />
</FieldShell>
</template>
<style scoped>.ks-field { display: grid; gap: var(--ks-space-1); } label { font-weight: 650; } small { color: var(--ks-color-neutral-600); }</style>