diff --git a/.claude/skills/creating-malio-component/SKILL.md b/.claude/skills/creating-malio-component/SKILL.md index ea139f1..1e6695d 100644 --- a/.claude/skills/creating-malio-component/SKILL.md +++ b/.claude/skills/creating-malio-component/SKILL.md @@ -7,7 +7,7 @@ description: Use when creating a new UI component in the @malio/layer-ui Nuxt la ## 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. +Step-by-step process for creating a component in `@malio/layer-ui`. Each component requires 6 deliverables : le `.vue`, les tests, la page playground, la story Histoire, la mise à jour du CHANGELOG, et la mise à jour du `COMPONENTS.md`. ## When to Use @@ -27,6 +27,7 @@ digraph create_component { "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"; + "7. Mettre à jour CHANGELOG.md" -> "8. Mettre à jour COMPONENTS.md"; } ``` @@ -176,6 +177,37 @@ Pour extraire le numéro de ticket depuis la branche courante : git branch --show-current | grep -oP '(MUI-\d+|\d{3,})' | head -1 ``` +### 8. Mettre à jour COMPONENTS.md + +**Fichier :** `COMPONENTS.md` à la racine du projet. + +Ce fichier sert de documentation de référence pour les projets qui consomment `@malio/layer-ui`. Il est lu par Claude dans les projets consommateurs pour connaître les composants disponibles et leurs props. + +**Ajouter une section pour le nouveau composant** en suivant le format existant : + +```markdown +## MalioNomComposant + +Description courte du composant. + +| Prop | Type | Défaut | Description | +|------|------|--------|-------------| +| ... | ... | ... | ... | + +**Events :** `update:modelValue(value: string)` + +\`\`\`vue + +\`\`\` +``` + +**Checklist :** +- Toutes les props documentées avec type, défaut et description +- Events listés +- Slots listés si applicable +- 2-5 exemples d'utilisation couvrant les cas courants (simple, avec options, disabled, erreur) +- Section placée par ordre logique (inputs ensemble, boutons ensemble, etc.) + ## 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.** @@ -188,3 +220,4 @@ Cette section est alimentée au fur et à mesure des retours utilisateur et des | 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 | +| COMPONENTS.md pas mis à jour | Ajouter la doc du composant dans `COMPONENTS.md` — c'est la référence pour les projets consommateurs | diff --git a/CHANGELOG.md b/CHANGELOG.md index 309707e..c5b539c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -22,6 +22,7 @@ Liste des évolutions de la librairie Malio layer UI * [#MUI-20] Création d'un composant sidebar * [#MUI-23] Revoir la config couleur tailwind * [#MUI-10] Création d'un composant bouton +* [#MUI-2] Faire un MCP pour la librairie de composant ### Changed diff --git a/COMPONENTS.md b/COMPONENTS.md new file mode 100644 index 0000000..c103142 --- /dev/null +++ b/COMPONENTS.md @@ -0,0 +1,357 @@ +# @malio/layer-ui — Composants + +Tous les composants sont auto-importés avec le préfixe `Malio`. Utiliser `v-model` pour le binding bidirectionnel sur les composants de formulaire. + +--- + +## MalioInputText + +Champ texte avec label, icône optionnelle et support de masque de saisie. + +| Prop | Type | Défaut | Description | +|------|------|--------|-------------| +| `id` | `string` | auto | Identifiant HTML | +| `label` | `string` | `''` | Label du champ | +| `modelValue` | `string \| null` | `undefined` | Valeur (v-model) | +| `disabled` | `boolean` | `false` | Désactive le champ | +| `readonly` | `boolean` | `false` | Lecture seule | +| `required` | `boolean` | `false` | Champ requis | +| `hint` | `string` | `''` | Message d'aide | +| `error` | `string` | `''` | Message d'erreur | +| `success` | `string` | `''` | Message de succès | +| `iconName` | `string` | `''` | Icône Iconify (ex: `mdi:magnify`) | +| `iconPosition` | `'left' \| 'right'` | `'right'` | Position de l'icône | +| `iconSize` | `string \| number` | `24` | Taille icône | +| `iconColor` | `string` | `'text-m-muted'` | Classe couleur icône | +| `mask` | `string \| MaskInputOptions` | — | Masque de saisie (maska) | +| `maxLength` | `number \| string` | — | Longueur max | +| `minLength` | `number \| string` | — | Longueur min | +| `inputClass` | `string` | `''` | Classes CSS input | +| `labelClass` | `string` | `''` | Classes CSS label | +| `groupClass` | `string` | `''` | Classes CSS conteneur | + +**Events :** `update:modelValue(value: string)` + +```vue + + + + + +``` + +--- + +## MalioInputPassword + +Champ mot de passe avec toggle visibilité. + +| Prop | Type | Défaut | Description | +|------|------|--------|-------------| +| `modelValue` | `string \| null` | `undefined` | Valeur (v-model) | +| `label` | `string` | `''` | Label | +| `displayIcon` | `boolean` | `true` | Afficher l'icône toggle | +| `disabled` | `boolean` | `false` | Désactivé | +| `readonly` | `boolean` | `false` | Lecture seule | +| `hint` | `string` | `''` | Message d'aide | +| `error` | `string` | `''` | Message d'erreur | +| `success` | `string` | `''` | Message de succès | + +**Events :** `update:modelValue(value: string)` + +```vue + + +``` + +--- + +## MalioInputAmount + +Champ montant avec icône devise (euro par défaut). + +| Prop | Type | Défaut | Description | +|------|------|--------|-------------| +| `modelValue` | `string \| null` | `undefined` | Valeur (v-model) | +| `label` | `string` | `''` | Label | +| `iconName` | `string` | `'mdi:currency-eur'` | Icône devise | +| `disabled` | `boolean` | `false` | Désactivé | +| `error` | `string` | `''` | Message d'erreur | + +**Events :** `update:modelValue(value: string)` + +```vue + + +``` + +--- + +## MalioInputNumber + +Champ numérique avec boutons +/-. + +| Prop | Type | Défaut | Description | +|------|------|--------|-------------| +| `modelValue` | `string \| null` | `undefined` | Valeur (v-model) | +| `label` | `string` | `''` | Label | +| `min` | `number \| string` | — | Valeur minimum | +| `max` | `number \| string` | — | Valeur maximum | +| `disabled` | `boolean` | `false` | Désactivé | +| `error` | `string` | `''` | Message d'erreur | + +**Events :** `update:modelValue(value: string)` + +```vue + +``` + +--- + +## MalioInputTextArea + +Zone de texte multiligne avec compteur et redimensionnement. + +| Prop | Type | Défaut | Description | +|------|------|--------|-------------| +| `modelValue` | `string \| null` | `undefined` | Valeur (v-model) | +| `label` | `string` | `''` | Label | +| `size` | `number \| string` | `2` | Nombre de lignes | +| `resize` | `'none' \| 'both' \| 'horizontal' \| 'vertical'` | `'both'` | Mode redimensionnement | +| `maxLength` | `number` | `800` | Longueur max | +| `showCounter` | `boolean` | `false` | Afficher le compteur | +| `disabled` | `boolean` | `false` | Désactivé | +| `error` | `string` | `''` | Message d'erreur | + +**Events :** `update:modelValue(value: string)` + +```vue + + +``` + +--- + +## MalioInputUpload + +Champ d'upload de fichier. + +| Prop | Type | Défaut | Description | +|------|------|--------|-------------| +| `modelValue` | `string \| null` | `undefined` | Nom du fichier (v-model) | +| `label` | `string` | `''` | Label | +| `accept` | `string` | `''` | Types de fichiers acceptés | +| `displayIcon` | `boolean` | `true` | Afficher l'icône | +| `disabled` | `boolean` | `false` | Désactivé | +| `error` | `string` | `''` | Message d'erreur | + +**Events :** `update:modelValue(value: string)`, `file-selected(file: File)` + +```vue + +``` + +--- + +## MalioSelect + +Liste déroulante. + +| Prop | Type | Défaut | Description | +|------|------|--------|-------------| +| `modelValue` | `string \| number \| null` | **requis** | Valeur sélectionnée (v-model) | +| `options` | `{ value: string \| number, text: string }[]` | `[]` | Options disponibles | +| `emptyOptionLabel` | `string` | `''` | Placeholder option vide | +| `label` | `string` | `''` | Label | +| `disabled` | `boolean` | `false` | Désactivé | +| `error` | `string` | `''` | Message d'erreur | + +**Events :** `update:modelValue(value: string | number | null)` +**Slots :** `icon` (icône dropdown custom) + +```vue + + +``` + +--- + +## MalioSelectCheckbox + +Liste déroulante multi-sélection avec checkboxes. + +| Prop | Type | Défaut | Description | +|------|------|--------|-------------| +| `modelValue` | `(string \| number)[]` | **requis** | Valeurs sélectionnées (v-model) | +| `options` | `{ value: string \| number, text: string }[]` | `[]` | Options | +| `displayTag` | `boolean` | `false` | Afficher les tags sélectionnés | +| `displaySelectAll` | `boolean` | `false` | Afficher "Tout sélectionner" | +| `selectAllLabel` | `string` | `'Tout sélectionner'` | Texte du sélecteur global | +| `label` | `string` | `''` | Label | +| `disabled` | `boolean` | `false` | Désactivé | + +**Events :** `update:modelValue(value: (string | number)[])` + +```vue + + +``` + +--- + +## MalioCheckbox + +Case à cocher. + +| Prop | Type | Défaut | Description | +|------|------|--------|-------------| +| `modelValue` | `boolean \| null` | `undefined` | Valeur (v-model) | +| `label` | `string` | `''` | Label | +| `disabled` | `boolean` | `false` | Désactivé | +| `readonly` | `boolean` | `false` | Lecture seule | +| `error` | `string` | `''` | Message d'erreur | + +**Events :** `update:modelValue(value: boolean)` + +```vue + + +``` + +--- + +## MalioRadioButton + +Bouton radio (à utiliser en groupe avec le même `name`). + +| Prop | Type | Défaut | Description | +|------|------|--------|-------------| +| `modelValue` | `string \| number \| boolean \| null` | `undefined` | Valeur du groupe (v-model) | +| `value` | `string \| number \| boolean \| null` | `undefined` | Valeur de cette option | +| `label` | `string` | `''` | Label | +| `name` | `string` | `''` | Nom du groupe radio | +| `disabled` | `boolean` | `false` | Désactivé | +| `readonly` | `boolean` | `false` | Lecture seule | + +**Events :** `update:modelValue(value: string | number | boolean | null)` + +```vue + + +``` + +--- + +## MalioTime + +Sélecteur d'heure. + +| Prop | Type | Défaut | Description | +|------|------|--------|-------------| +| `modelValue` | `string \| null` | `undefined` | Heure au format HH:mm (v-model) | +| `label` | `string` | `''` | Label | +| `disabled` | `boolean` | `false` | Désactivé | +| `readonly` | `boolean` | `false` | Lecture seule | +| `error` | `string` | `''` | Message d'erreur | + +**Events :** `update:modelValue(value: string)` + +```vue + + +``` + +--- + +## MalioButton + +Bouton d'action avec 4 variantes visuelles et icône optionnelle. + +| Prop | Type | Défaut | Description | +|------|------|--------|-------------| +| `label` | `string` | `''` | Texte du bouton (ou slot par défaut) | +| `variant` | `'primary' \| 'secondary' \| 'tertiary' \| 'danger'` | `'primary'` | Variante visuelle | +| `disabled` | `boolean` | `false` | Désactivé | +| `buttonClass` | `string` | `''` | Classes CSS additionnelles (twMerge) | +| `iconName` | `string` | `''` | Icône Iconify | +| `iconPosition` | `'left' \| 'right'` | `'right'` | Position icône | +| `iconSize` | `string \| number` | `16` | Taille icône | + +**Events :** `click(e: MouseEvent)` +**Slots :** `default` (contenu du bouton, remplace `label`) + +```vue + + + + + +``` + +--- + +## MalioButtonIcon + +Bouton icône seul (sans texte). + +| Prop | Type | Défaut | Description | +|------|------|--------|-------------| +| `icon` | `string` | **requis** | Icône Iconify | +| `ariaLabel` | `string` | **requis** | Label accessible | +| `variant` | `'filled' \| 'ghost'` | `'filled'` | Variante visuelle | +| `disabled` | `boolean` | `false` | Désactivé | +| `buttonClass` | `string` | `''` | Classes CSS additionnelles | +| `iconSize` | `string \| number` | `24` | Taille icône | + +**Events :** `click(e: MouseEvent)` + +```vue + + +``` + +--- + +## MalioTabList + +Navigation par onglets avec contenu dynamique. + +| Prop | Type | Défaut | Description | +|------|------|--------|-------------| +| `modelValue` | `string` | `undefined` | Onglet actif (v-model) | +| `tabs` | `{ key: string, label: string, icon?: string }[]` | **requis** | Liste des onglets | + +**Events :** `update:modelValue(value: string)` +**Slots :** Un slot nommé par `tab.key` pour le contenu de chaque onglet + +```vue + + + + +``` + +--- + +## MalioSidebar + +Barre latérale de navigation rétractable. + +| Prop | Type | Défaut | Description | +|------|------|--------|-------------| +| `modelValue` | `boolean` | `undefined` | État ouvert/fermé (v-model) | +| `sections` | `SidebarSection[]` | **requis** | Sections de navigation | +| `sidebarClass` | `string` | `''` | Classes CSS sidebar | +| `toggleClass` | `string` | `''` | Classes CSS bouton toggle | + +**Type SidebarSection :** `{ title?: string, items: { label: string, icon?: string, to?: string, href?: string, active?: boolean }[] }` + +**Events :** `update:modelValue(value: boolean)` +**Slots :** `logo` (sidebar ouverte), `logo-collapsed` (sidebar fermée) + +```vue + + + + +```