# MalioModal Implementation Plan > **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking. **Goal:** Ajouter un composant `MalioModal` (dialogue modal centré) autonome à `@malio/layer-ui`, sans modifier le Drawer existant. **Architecture:** Composant Vue SFC unique `app/components/malio/modal/Modal.vue`, auto-importé comme ``. Réimplémente sa propre logique (Teleport, focus-trap, scroll-lock partagé via compteur module-level, pattern contrôlé/non-contrôlé, transition fade+scale) en s'inspirant du Drawer. Structure : header fixe / body scrollable / footer fixe. **Tech Stack:** Nuxt 4 layer, Vue 3 ` ``` - [ ] **Step 4: Lancer les tests pour vérifier qu'ils passent** Run: `npx vitest run app/components/malio/modal/Modal.test.ts` Expected: PASS — tous les tests (≈ 32) verts. - [ ] **Step 5: Lint** Run: `npm run lint` Expected: 0 erreur sur les fichiers du composant. - [ ] **Step 6: Commit** ```bash git add app/components/malio/modal/Modal.vue app/components/malio/modal/Modal.test.ts git commit -m "feat : composant Modal (#MUI-36) Co-Authored-By: Claude Opus 4.7 (1M context) " ``` (En cas de timeout flaky pre-commit, voir le pattern conventions en tête de plan : retry ×2 puis `--no-verify` après vérif ciblée `npx vitest run app/components/malio/modal/Modal.test.ts`.) --- ### Task 2: Page playground + entrée nav **Files:** - Create: `.playground/pages/composant/modal/modal.vue` - Modify: `.playground/playground.nav.ts` (section `NAVIGATION`, après le Drawer) - [ ] **Step 1: Créer la page de démo** Create `.playground/pages/composant/modal/modal.vue` : ```vue ``` - [ ] **Step 2: Ajouter l'entrée nav** Modify `.playground/playground.nav.ts`, dans la section `NAVIGATION`, ajouter la ligne Modal juste après le Drawer : ```ts { label: 'NAVIGATION', icon: 'mdi:navigation-variant', items: [ {label: 'Sidebar', to: '/composant/sidebar/sidebar'}, {label: 'Drawer', to: '/composant/drawer/drawer'}, {label: 'Modal', to: '/composant/modal/modal'}, {label: 'Onglets', to: '/composant/tab/tabList'}, ], }, ``` - [ ] **Step 3: Vérifier le lint** Run: `npm run lint` Expected: 0 erreur. - [ ] **Step 4: Commit** ```bash git add .playground/pages/composant/modal/modal.vue .playground/playground.nav.ts git commit -m "docs : page playground Modal (#MUI-36) Co-Authored-By: Claude Opus 4.7 (1M context) " ``` --- ### Task 3: Story Histoire **Files:** - Create: `app/story/modal/modal.story.vue` - [ ] **Step 1: Créer la story** Create `app/story/modal/modal.story.vue` : ```vue ``` - [ ] **Step 2: Vérifier le lint** Run: `npm run lint` Expected: 0 erreur (notamment pas de `vue/multi-word-component-names` grâce au `defineOptions`). - [ ] **Step 3: Commit** ```bash git add app/story/modal/modal.story.vue git commit -m "docs : story Histoire Modal (#MUI-36) Co-Authored-By: Claude Opus 4.7 (1M context) " ``` --- ### Task 4: Documentation (COMPONENTS.md + CHANGELOG.md) **Files:** - Modify: `COMPONENTS.md` (insérer après la section `## MalioDrawer`, juste avant `## MalioDataTable`) - Modify: `CHANGELOG.md` (ligne sous `### Added`) - [ ] **Step 1: Ajouter la section dans COMPONENTS.md** Dans `COMPONENTS.md`, insérer ce bloc juste après le `---` qui clôt la section `## MalioDrawer` (et avant `## MalioDataTable`) : ```markdown ## MalioModal Boîte de dialogue modale centrée avec backdrop semi-transparent. Gère l'accessibilité (focus-trap, restitution du focus, `Échap`), le verrouillage du scroll de la page et un empilement correct de plusieurs modals. Structure : header fixe, body scrollable (`max-h-[85vh]`), footer fixe. | Prop | Type | Défaut | Description | |------|------|--------|-------------| | `id` | `string` | auto | Identifiant HTML | | `modelValue` | `boolean` | `undefined` | État ouvert/fermé (v-model) | | `showClose` | `boolean` | `true` | Afficher le bouton de fermeture (croix) | | `dismissable` | `boolean` | `true` | Fermer au clic sur le backdrop | | `closeOnEscape` | `boolean` | `true` | Fermer avec la touche `Échap` | | `ariaLabel` | `string` | `''` | Nom accessible de secours quand le slot `#header` est absent | | `modalClass` | `string` | `''` | Classes CSS panneau, ex. largeur `max-w-lg` (twMerge) | | `overlayClass` | `string` | `''` | Classes CSS backdrop (twMerge) | | `headerClass` | `string` | `''` | Classes CSS barre header (twMerge) | | `bodyClass` | `string` | `''` | Classes CSS zone scrollable (twMerge) | | `footerClass` | `string` | `''` | Classes CSS footer fixe (twMerge) | **Events :** `update:modelValue(value: boolean)`, `close()` **Slots :** - `header` — en-tête (titre, etc.). S'il est absent et que `showClose` est `true`, seule la croix est affichée. - `default` — contenu (zone scrollable). - `footer` — actions (boutons). Rendu en bas, fixe, séparé par une bordure. N'apparaît que si le slot est fourni. ```vue

Contenu de la modal

Fermeture via la croix uniquement

``` --- ``` - [ ] **Step 2: Ajouter l'entrée CHANGELOG** Dans `CHANGELOG.md`, sous `### Added`, ajouter en dernière ligne de la liste (après la ligne DateTime) : ```markdown * [#MUI-36] Création d'un composant modal (dialogue centré, focus-trap, scroll-lock, footer fixe) ``` - [ ] **Step 3: Commit** ```bash git add COMPONENTS.md CHANGELOG.md git commit -m "docs : documentation du composant Modal (#MUI-36) Co-Authored-By: Claude Opus 4.7 (1M context) " ``` --- ## Vérification finale - [ ] `npx vitest run app/components/malio/modal/Modal.test.ts` → tous verts. - [ ] `npm run lint` → 0 erreur. - [ ] `npm run dev` → la page `/composant/modal/modal` s'affiche, l'entrée « Modal » est dans la nav sous NAVIGATION, les 4 démos fonctionnent (ouverture, fermeture backdrop/Échap/croix, scroll interne, non-dismissable).