feat(ui) : required cohérent + astérisque label + sanitisation email (MUI-41) (#60)
## Résumé (MUI-41) Harmonise l'état « obligatoire » des composants de formulaire et normalise le champ email. ### `required` + astérisque - Nouveau composant partagé `MalioRequiredMark` : astérisque rouge (`text-m-danger`, **16px**), `aria-hidden`. - Prop `required` désormais cohérente sur toute la famille formulaire ; quand vraie, l'astérisque s'affiche **dans le label**. - Prop ajoutée à `Select`, `SelectCheckbox`, `InputUpload`, `InputRichText` (les autres l'avaient déjà). - Accessibilité : `required` natif là où l'élément le supporte, sinon `aria-required` (Select/SelectCheckbox sur le `<button>`, RichText sur le wrapper éditeur, Upload sur le champ visible). - `MalioSiteSelector` **exclu** volontairement (segmented control, pas de label de champ). ### Sanitisation email (`MalioInputEmail`) - Suppression de **tous les espaces** à la saisie (pas de masque). - Nouvelle prop opt-in `lowercase` (défaut `false`) : normalise en minuscules à la frappe (cohérent RG-1.21 Starseed). - Garde défensive curseur : l'API de sélection est interdite sur `type="email"` → repositionnement best-effort sans jamais lever. - La validation de format reste à la couche `error`. ### Docs & playground - `COMPONENTS.md` (doc `required` cohérente + note famille + `lowercase`) et `CHANGELOG.md` mis à jour. - Exemples playground `required` et email `lowercase` ajoutés. ## Test plan - [x] Suite complète : 42 fichiers / 771 tests verts - [x] Lint : 0 erreur - [x] Tests `aria-required` sur Select/SelectCheckbox/RichText - [ ] Vérif visuelle playground : astérisque 16px dans le label, email qui retire les espaces / minuscule Spec & plan : `docs/superpowers/specs/` et `docs/superpowers/plans/`. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Reviewed-on: #60 Co-authored-by: tristan <tristan@yuno.malio.fr> Co-committed-by: tristan <tristan@yuno.malio.fr>
This commit was merged in pull request #60.
This commit is contained in:
@@ -5,7 +5,7 @@
|
||||
:for="editorId"
|
||||
:class="mergedLabelClass"
|
||||
>
|
||||
{{ label }}
|
||||
{{ label }}<MalioRequiredMark v-if="required" />
|
||||
</label>
|
||||
|
||||
<!-- Mode lecture seule (rendu uniquement) -->
|
||||
@@ -22,6 +22,7 @@
|
||||
v-else
|
||||
:id="editorId"
|
||||
:class="mergedEditorWrapperClass"
|
||||
:aria-required="required || undefined"
|
||||
@click="focusEditor"
|
||||
>
|
||||
<div
|
||||
@@ -184,6 +185,7 @@
|
||||
</div>
|
||||
|
||||
<p
|
||||
v-if="reserveMessageSpace || hint || error || success"
|
||||
:id="`${editorId}-describedby`"
|
||||
:class="[
|
||||
hasError
|
||||
@@ -191,7 +193,8 @@
|
||||
: hasSuccess
|
||||
? 'text-m-success'
|
||||
: 'text-m-muted',
|
||||
'mt-1 text-xs ml-[2px] min-h-[1rem]',
|
||||
'mt-1 text-xs ml-[2px]',
|
||||
reserveMessageSpace ? 'min-h-[1rem]' : '',
|
||||
]"
|
||||
>
|
||||
{{ error || success || hint }}
|
||||
@@ -210,6 +213,7 @@ import Color from '@tiptap/extension-color'
|
||||
import Highlight from '@tiptap/extension-highlight'
|
||||
import { Markdown } from 'tiptap-markdown'
|
||||
import { twMerge } from 'tailwind-merge'
|
||||
import MalioRequiredMark from '../shared/RequiredMark.vue'
|
||||
|
||||
defineOptions({ name: 'MalioInputRichText', inheritAttrs: false })
|
||||
|
||||
@@ -232,6 +236,8 @@ const props = withDefaults(
|
||||
groupClass?: string
|
||||
labelClass?: string
|
||||
editorClass?: string
|
||||
required?: boolean
|
||||
reserveMessageSpace?: boolean
|
||||
}>(),
|
||||
{
|
||||
id: '',
|
||||
@@ -249,6 +255,8 @@ const props = withDefaults(
|
||||
groupClass: '',
|
||||
labelClass: '',
|
||||
editorClass: '',
|
||||
required: false,
|
||||
reserveMessageSpace: true,
|
||||
},
|
||||
)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user