Files
malio-layer-ui/.claude/skills/creating-malio-component/SKILL.md
tristan 9925f1ced4 [#MUI-8] Ajout composant mot de passe (#13)
| Numéro du ticket | Titre du ticket |
|------------------|-----------------|
|                  |                 |

## Description de la PR

## Modification du .env

## Check list

- [ ] Pas de régression
- [ ] TU/TI/TF rédigée
- [ ] TU/TI/TF OK
- [ ] CHANGELOG modifié

Reviewed-on: #13
Co-authored-by: tristan <tristan@yuno.malio.fr>
Co-committed-by: tristan <tristan@yuno.malio.fr>
2026-03-19 09:43:55 +00:00

6.9 KiB

name, description
name description
creating-malio-component Use when creating a new UI component in the @malio/layer-ui Nuxt layer — covers component, tests, playground page, and Histoire story

Creating a Malio Component

Overview

Step-by-step process for creating a component in @malio/layer-ui. Each component requires 5 deliverables : le .vue, les tests, la page playground, la story Histoire, et la mise à jour du CHANGELOG.

When to Use

  • Création d'un nouveau composant dans app/components/malio/
  • Ajout d'une variante d'un composant existant (ex: InputPassword basé sur InputText)

Workflow

digraph create_component {
  rankdir=TB;
  "1. Lire les fichiers de référence" -> "2. Créer le composant .vue";
  "2. Créer le composant .vue" -> "3. Créer les tests .test.ts";
  "3. Créer les tests .test.ts" -> "4. npm run test + npm run lint";
  "4. npm run test + npm run lint" -> "Tests OK?" [shape=diamond];
  "Tests OK?" -> "5. Créer la page playground" [label="oui"];
  "Tests OK?" -> "3. Créer les tests .test.ts" [label="non, corriger"];
  "5. Créer la page playground" -> "6. Créer la story Histoire";
  "6. Créer la story Histoire" -> "7. Mettre à jour CHANGELOG.md";
}

Étapes

1. Lire les fichiers de référence

Identifier le composant le plus proche comme base (ex: InputText.vue pour InputPassword.vue). Lire :

  • Le composant de référence : app/components/malio/<Ref>.vue
  • Ses tests : app/components/malio/<Ref>.test.ts

2. Créer le composant .vue

Fichier : app/components/malio/<NomComposant>.vue

Checklist obligatoire :

Élément Pattern
defineOptions { name: 'Malio<Nom>', inheritAttrs: false }
Props defineProps<T>() + withDefaults() — props communes : id, label, modelValue, inputClass, labelClass, groupClass, disabled, readonly, hint, error, success
Contrôlé / non-contrôlé isControlled = computed(() => props.modelValue !== undefined) + localValue en fallback
Classes CSS Fusionnées via twMerge() pour permettre l'override consommateur
Accessibilité aria-invalid, aria-describedby, label[for] lié à input[id]
Icônes Icon as IconifyIcon depuis @iconify/vue (pas @nuxt/icon)
ID généré useId() + prefix unique (ex: malio-input-password-${generatedId})

3. Créer les tests .test.ts

Fichier : app/components/malio/<NomComposant>.test.ts (colocalisé)

Pattern de montage :

import { mount } from '@vue/test-utils'
import type { DefineComponent } from 'vue'
import MonComposant from './MonComposant.vue'

const ComposantForTest = MonComposant as DefineComponent<MonComposantProps>

const mountComponent = (props: MonComposantProps = {}) =>
  mount(ComposantForTest, {
    props,
    global: {
      stubs: {
        IconifyIcon: {
          template: '<span data-test="icon" v-bind="$attrs" />',
        },
      },
    },
  })

Tests minimum à couvrir :

  • Rendu initial avec valeur
  • Rendu du label
  • Emit update:modelValue
  • Props disabled, readonly
  • États error, success, hint (messages + classes CSS)
  • Accessibilité (aria-invalid, label[for] / input[id])
  • Comportements spécifiques au composant

Attention stub IconifyIcon : Le stub basé sur le nom IconifyIcon ne remplace pas toujours le vrai composant @iconify/vue. Pour tester les props du composant Icon (ex: icon), utiliser findComponent avec l'import réel :

import { Icon as IconifyIcon } from '@iconify/vue'
// ...
const iconComponent = wrapper.findComponent(IconifyIcon)
expect(iconComponent.props('icon')).toBe('mdi:eye-outline')

4. Vérification

npm run test    # Tous les tests passent
npm run lint    # Pas d'erreurs

5. Créer la page playground

Fichier : .playground/pages/composant/<nomComposant>.vue (camelCase)

La page est auto-détectée par index.vue via import.meta.glob. Inclure des variantes représentatives dans une grille :

<div class="grid grid-cols-1 items-start gap-6 md:grid-cols-2">
  <div class="rounded-lg border p-4">
    <h2 class="mb-4 text-xl font-bold">Titre variante</h2>
    <MalioMonComposant ... />
  </div>
</div>

Variantes typiques : simple, avec label, désactivé, readonly, hint, erreur, succès, validation dynamique.

6. Créer la story Histoire

Fichier : app/story/<nomComposant>.story.vue (camelCase)

Structure :

<template>
  <Story title="Category/Name">
    <!-- Variantes avec v-model et valeurs initiales -->
  </Story>
</template>

<docs lang="md">
# MalioNomComposant
Description courte.
## Props détaillées
<!-- Documenter chaque prop : type, description, défaut, comportement -->
## Comportement
## Accessibilité
## Events
</docs>

<script setup lang="ts">
import { ref } from 'vue'
import MalioMonComposant from '../components/malio/MonComposant.vue'
// refs pour chaque variante avec valeurs initiales
</script>

Important : initial state avec variantes. La story doit contenir des exemples visuels directement visibles (pas un composant vide). Chaque variante a un v-model avec une ref initialisée. Variantes typiques à inclure :

  • Simple (avec label)
  • Sans icône (display-icon="false") si applicable
  • Avec hint
  • Désactivé (avec valeur pré-remplie)
  • Readonly (avec valeur pré-remplie)
  • Erreur (avec valeur + message d'erreur)
  • Succès (avec valeur + message de succès)

7. Mettre à jour le CHANGELOG

Fichier : CHANGELOG.md à la racine du projet.

Ajouter une ligne dans la section ### Added de la version courante. Le numéro de ticket se trouve dans le nom de la branche Git (ex: branche feat/MUI-8-composant-password → ticket MUI-8).

Format :

  • Avec numéro de ticket : * [#MUI-8] Création d'un composant mot de passe
  • Sans numéro de ticket : * Création d'un composant textarea

Pour extraire le numéro de ticket depuis la branche courante :

git branch --show-current | grep -oP '(MUI-\d+|\d{3,})' | head -1

Common Mistakes

Cette section est alimentée au fur et à mesure des retours utilisateur et des problèmes rencontrés. Si un retour ou un bug est identifié lors de la création d'un composant, ajouter une ligne dans ce tableau.

Erreur Solution
Stub IconifyIcon ne fonctionne pas dans les tests Utiliser findComponent(IconifyIcon) avec l'import réel pour tester les props
Oubli de inheritAttrs: false Toujours dans defineOptions — sinon les attrs se dupliquent
Page playground non détectée Vérifier le nom du fichier en camelCase dans .playground/pages/composant/
Padding input pas ajusté avec icône Ajouter !pr-10 (ou équivalent) quand une icône est présente à droite
Story sans initial state Toujours initialiser les ref avec des valeurs pour que les variantes soient visibles dès le chargement
CHANGELOG oublié Toujours ajouter la ligne dans ### Added avant de commit