FormField.vue 1.76 KB
<script setup>
/**
 * FormField —— 表单控件的外壳:标签、必填星号、提示、错误。控件本身经默认插槽注入
 * (Input / Textarea / Select 都行)。外层是 <label>,与内部控件天然关联,点标签即聚焦。
 *
 * `error` 非空时只显示 error,不显示 hint —— 出错时读者要看的是错在哪。
 */

defineProps({
  /** 标签文案。 */
  label: { type: String, default: '' },
  /** 辅助说明(无错误时显示)。 */
  hint: { type: String, default: '' },
  /** 错误文案(非空时替代 hint,并显示为 danger 色)。 */
  error: { type: String, default: '' },
  /** 必填:标签后加星号。 */
  required: { type: Boolean, default: false },
})
</script>

<template>
  <label class="drama-field">
    <span
      v-if="label"
      class="drama-field__label"
    >
      {{ label }}
      <span
        v-if="required"
        class="drama-field__required"
        aria-hidden="true"
      >*</span>
    </span>
    <slot />
    <span
      v-if="error"
      class="drama-field__error"
      role="alert"
    >{{ error }}</span>
    <span
      v-else-if="hint"
      class="drama-field__hint"
    >{{ hint }}</span>
  </label>
</template>

<style scoped>
.drama-field {
  display: grid;
  gap: var(--drama-space-sm);
  min-width: 0;
  font-family: var(--drama-font-family-body);
}

.drama-field__label {
  color: var(--drama-color-text);
  font-size: var(--drama-font-size-sm);
  font-weight: var(--drama-font-weight-medium);
}

.drama-field__required {
  color: var(--drama-color-danger);
}

.drama-field__hint {
  color: var(--drama-color-text-muted);
  font-size: var(--drama-font-size-xs);
}

.drama-field__error {
  color: var(--drama-color-danger);
  font-size: var(--drama-font-size-xs);
}
</style>