## Résumé
Nouveau composant `MalioInputRichText` : éditeur WYSIWYG basé sur **TipTap v3** + **StarterKit** + **tiptap-markdown**, aligné sur le thème Malio (couleurs `m-*`, icônes `mdi:*`, états error / success / hint).
## Détails
- **Toolbar** : gras, italique, barré, H2, H3, liste à puces, liste numérotée, citation, code inline, bloc de code, lien (prompt URL), undo / redo
- **Sortie** : `markdown` (par défaut) ou `html` via la prop `outputFormat`
- **Modes** : `editable`, `disabled`, `readonly` ; mode lecture seule (`editable=false`) rend le contenu en `prose` sans toolbar
- **Accessibilité** : label `for/id`, `aria-invalid`, `aria-describedby`, `aria-pressed` sur les boutons toolbar
- **Style** : floating focus border `m-primary`, error `m-danger`, success `m-success`, toolbar `bg-m-bg`
## Dépendances ajoutées (purement additives, aucun bump existant)
- `@tiptap/vue-3` ^3.22.5
- `@tiptap/starter-kit` ^3.22.5
- `@tiptap/extension-placeholder` ^3.22.5
- `@tiptap/pm` ^3.22.5
- `tiptap-markdown` ^0.9.0
> Note : `@tiptap/extension-link` n'est pas installé séparément car StarterKit v3 l'inclut nativement (configuré via `StarterKit.configure({ link: { ... } })`).
## Test plan
- [x] `npm run test` — 315/315 (12 nouveaux tests sur InputRichText)
- [x] `npm run lint` — 0 erreur sur les fichiers ajoutés
- [x] `npm run story:build` — Histoire build OK (story `Input/RichText` listée)
- [x] `npm run dev` — playground `/composant/input/inputRichText` (vérification visuelle des 8 variantes : simple, hint, erreur, succès, readonly, disabled, lecture seule, sortie HTML)
- [x] `npm run story:dev` — story `Input/RichText` avec docs
## Fichiers
- `app/components/malio/input/InputRichText.vue` — composant
- `app/components/malio/input/InputRichText.test.ts` — tests
- `.playground/pages/composant/input/inputRichText.vue` — playground
- `app/story/input/inputRichText.story.vue` — story Histoire
- `histoire.config.ts` — alias ESM + `optimizeDeps` pour `tiptap-markdown` (sinon Histoire choisit la build UMD)
- `CHANGELOG.md`, `COMPONENTS.md` — documentation
Reviewed-on: #37
Co-authored-by: matthieu <matthieu@yuno.malio.fr>
Co-committed-by: matthieu <matthieu@yuno.malio.fr>
203 lines
5.6 KiB
Vue
203 lines
5.6 KiB
Vue
<template>
|
|
<Story title="Input/RichText">
|
|
<div class="grid grid-cols-1 gap-6 lg:grid-cols-2">
|
|
<div class="rounded-lg border p-4">
|
|
<h2 class="mb-4 text-xl font-bold">Simple</h2>
|
|
<MalioInputRichText
|
|
v-model="simpleValue"
|
|
label="Note"
|
|
placeholder="Écrire ici…"
|
|
/>
|
|
</div>
|
|
|
|
<div class="rounded-lg border p-4">
|
|
<h2 class="mb-4 text-xl font-bold">Avec contenu initial + hint</h2>
|
|
<MalioInputRichText
|
|
v-model="hintValue"
|
|
label="Description"
|
|
hint="Mise en forme via la barre d'outils"
|
|
/>
|
|
</div>
|
|
|
|
<div class="rounded-lg border p-4">
|
|
<h2 class="mb-4 text-xl font-bold">Erreur</h2>
|
|
<MalioInputRichText
|
|
v-model="errorValue"
|
|
label="Compte-rendu"
|
|
error="Le compte-rendu doit faire au moins 20 caractères"
|
|
/>
|
|
</div>
|
|
|
|
<div class="rounded-lg border p-4">
|
|
<h2 class="mb-4 text-xl font-bold">Succès</h2>
|
|
<MalioInputRichText
|
|
v-model="successValue"
|
|
label="Compte-rendu"
|
|
success="Compte-rendu validé"
|
|
/>
|
|
</div>
|
|
|
|
<div class="rounded-lg border p-4">
|
|
<h2 class="mb-4 text-xl font-bold">Désactivé</h2>
|
|
<MalioInputRichText
|
|
v-model="disabledValue"
|
|
label="Note"
|
|
disabled
|
|
/>
|
|
</div>
|
|
|
|
<div class="rounded-lg border p-4">
|
|
<h2 class="mb-4 text-xl font-bold">Readonly</h2>
|
|
<MalioInputRichText
|
|
v-model="readonlyValue"
|
|
label="Note"
|
|
readonly
|
|
/>
|
|
</div>
|
|
|
|
<div class="rounded-lg border p-4 lg:col-span-2">
|
|
<h2 class="mb-4 text-xl font-bold">Affichage seul (editable=false)</h2>
|
|
<MalioInputRichText
|
|
:model-value="readonlyValue"
|
|
:editable="false"
|
|
/>
|
|
</div>
|
|
|
|
<div class="rounded-lg border p-4 lg:col-span-2">
|
|
<h2 class="mb-4 text-xl font-bold">Sortie HTML</h2>
|
|
<MalioInputRichText
|
|
v-model="htmlValue"
|
|
label="Article"
|
|
output-format="html"
|
|
min-height="200px"
|
|
/>
|
|
</div>
|
|
</div>
|
|
</Story>
|
|
</template>
|
|
|
|
<docs lang="md">
|
|
# MalioInputRichText
|
|
|
|
Éditeur de texte riche basé sur **TipTap v3** + **StarterKit** + **tiptap-markdown**.
|
|
Sortie en **markdown** (par défaut) ou en **HTML**. Aligné sur le thème Malio
|
|
(couleurs `m-*`, icônes `mdi:*`, états error / success / hint).
|
|
|
|
------------------------------------------------------------------------
|
|
|
|
## Props détaillées
|
|
|
|
### id
|
|
|
|
- Type: `string`
|
|
- Description: Identifiant HTML.
|
|
- Comportement: Généré automatiquement si non fourni (`malio-input-rich-text-…`).
|
|
|
|
### label
|
|
|
|
- Type: `string`
|
|
- Description: Label affiché au-dessus de l'éditeur.
|
|
- Comportement: Change de couleur selon l'état (focus → `m-primary`, error → `m-danger`, success → `m-success`).
|
|
|
|
### modelValue
|
|
|
|
- Type: `string | null | undefined`
|
|
- Description: Contenu de l'éditeur (markdown ou HTML selon `outputFormat`).
|
|
- Comportement: `v-model` ; sync bidirectionnelle.
|
|
|
|
### placeholder
|
|
|
|
- Type: `string`
|
|
- Défaut: `''`
|
|
- Description: Texte affiché quand l'éditeur est vide.
|
|
|
|
### minHeight
|
|
|
|
- Type: `string`
|
|
- Défaut: `160px`
|
|
- Description: Hauteur minimale de la zone d'édition (CSS valid value).
|
|
|
|
### editable
|
|
|
|
- Type: `boolean`
|
|
- Défaut: `true`
|
|
- Description: `false` → mode affichage seul, **toolbar masquée**, contenu rendu en `prose`.
|
|
|
|
### disabled
|
|
|
|
- Type: `boolean`
|
|
- Défaut: `false`
|
|
- Description: Désactive l'édition et la toolbar (opacité réduite).
|
|
|
|
### readonly
|
|
|
|
- Type: `boolean`
|
|
- Défaut: `false`
|
|
- Description: Lecture seule (toolbar visible mais désactivée, pas de saisie).
|
|
|
|
### hint / error / success
|
|
|
|
- Type: `string`
|
|
- Description: Messages contextuels affichés sous l'éditeur.
|
|
- Priorité: `error` > `success` > `hint`.
|
|
|
|
### outputFormat
|
|
|
|
- Type: `'markdown' | 'html'`
|
|
- Défaut: `'markdown'`
|
|
- Description: Format émis dans `update:modelValue`.
|
|
- `markdown` : utilise `tiptap-markdown` (`getMarkdown()`).
|
|
- `html` : utilise `editor.getHTML()`.
|
|
|
|
### groupClass / labelClass / editorClass
|
|
|
|
- Type: `string`
|
|
- Description: Classes Tailwind additionnelles fusionnées via `twMerge` pour override.
|
|
|
|
------------------------------------------------------------------------
|
|
|
|
## Toolbar
|
|
|
|
Boutons (icônes `mdi:*`) :
|
|
|
|
- Gras, Italique, Barré
|
|
- Titre H2, Titre H3
|
|
- Liste à puces, Liste numérotée
|
|
- Citation
|
|
- Code inline, Bloc de code
|
|
- Lien (prompt URL ; vide pour retirer)
|
|
- Annuler / Rétablir
|
|
|
|
------------------------------------------------------------------------
|
|
|
|
## Accessibilité
|
|
|
|
- Le label est lié à la zone d'édition via `for` / `id`.
|
|
- `aria-invalid="true"` sur la zone d'édition en cas d'erreur.
|
|
- `aria-describedby` référence le message d'erreur / succès / hint.
|
|
- Boutons toolbar : `aria-pressed` reflète l'état actif, `aria-label` pour l'usage screen-reader.
|
|
|
|
------------------------------------------------------------------------
|
|
|
|
## Events
|
|
|
|
### update:modelValue
|
|
|
|
- Émis à chaque modification du contenu.
|
|
- Payload : `string` (markdown ou HTML selon `outputFormat`).
|
|
|
|
</docs>
|
|
|
|
<script setup lang="ts">
|
|
import {ref} from 'vue'
|
|
import MalioInputRichText from '../../components/malio/input/InputRichText.vue'
|
|
|
|
const simpleValue = ref('')
|
|
const hintValue = ref('## Titre\n\nUn paragraphe avec du **gras**, de l\'*italique* et un [lien](https://malio.fr).')
|
|
const errorValue = ref('Trop court')
|
|
const successValue = ref('Tout est bon de mon côté.')
|
|
const disabledValue = ref('Contenu indisponible.')
|
|
const readonlyValue = ref('## Compte-rendu\n\n- Point 1\n- Point 2\n\n> Citation importante')
|
|
const htmlValue = ref('<p>Contenu <strong>riche</strong>.</p>')
|
|
</script>
|