From 7fc072ad08d0f17243edef6e8ac2e48145f18fd5 Mon Sep 17 00:00:00 2001 From: THOLOT DECHENE Matthieu Date: Mon, 4 May 2026 18:03:40 +0000 Subject: [PATCH] =?UTF-8?q?release=20:=20couleurs=20et=20surlignage=20dans?= =?UTF-8?q?=20l'=C3=A9diteur=20rich=20text=20(#40)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Résumé Ajoute deux boutons à la toolbar de \`\` pour appliquer une couleur de texte ou un surlignage sur la sélection, façon Jira. ## Changements - Extensions TipTap : \`@tiptap/extension-text-style\`, \`@tiptap/extension-color\`, \`@tiptap/extension-highlight\` (multicolor) - Palette de 8 couleurs texte + 8 pastels surlignage + reset - Indicateur de couleur active sous l'icône - Fermeture popover sur clic extérieur, Échap, ou clic dans l'éditeur - Tests : 4 nouveaux cas (15/15 OK) - Story et \`COMPONENTS.md\` à jour ## Limite à connaître Les couleurs ne sont **pas sérialisables en markdown** (\`tiptap-markdown\` ne les sérialise pas). Pour les conserver au save/reload, utiliser \`output-format="html"\`. ## Release attendu Commit type \`fix:\` → semantic-release publie **1.4.8** (patch). Co-authored-by: kevin Co-authored-by: tristan Co-authored-by: Kevin Boudet Reviewed-on: https://gitea.malio.fr/MALIO-DEV/malio-layer-ui/pulls/40 --- COMPONENTS.md | 8 +- .../malio/input/InputRichText.test.ts | 32 +++ app/components/malio/input/InputRichText.vue | 264 +++++++++++++++++- app/story/input/inputRichText.story.vue | 25 +- package-lock.json | 43 +++ package.json | 3 + 6 files changed, 361 insertions(+), 14 deletions(-) diff --git a/COMPONENTS.md b/COMPONENTS.md index ecf1e1c..0794f58 100644 --- a/COMPONENTS.md +++ b/COMPONENTS.md @@ -134,7 +134,9 @@ Zone de texte multiligne avec compteur et redimensionnement. ## MalioInputRichText -Éditeur de texte riche basé sur **TipTap v3** + **StarterKit** + **tiptap-markdown**. Toolbar avec gras, italique, barré, titres H2/H3, listes, citation, code, code-block, lien, undo/redo. Sortie en markdown (par défaut) ou HTML. +Éditeur de texte riche basé sur **TipTap v3** + **StarterKit** + **tiptap-markdown** + **TextStyle/Color/Highlight**. Toolbar avec gras, italique, barré, titres H2/H3, listes, citation, code, code-block, lien, **couleur du texte**, **surlignage**, undo/redo. Sortie en HTML (par défaut) ou markdown. + +> Couleurs et surlignages ne sont **pas persistés en markdown**. Pour les conserver au save/reload, utiliser `output-format="html"`. | Prop | Type | Défaut | Description | |------|------|--------|-------------| @@ -149,7 +151,7 @@ Zone de texte multiligne avec compteur et redimensionnement. | `hint` | `string` | `''` | Message d'aide | | `error` | `string` | `''` | Message d'erreur | | `success` | `string` | `''` | Message de succès | -| `outputFormat` | `'markdown' \| 'html'` | `'markdown'` | Format émis dans `update:modelValue` | +| `outputFormat` | `'markdown' \| 'html'` | `'html'` | Format émis dans `update:modelValue` | | `groupClass` | `string` | `''` | Classes CSS conteneur (twMerge) | | `labelClass` | `string` | `''` | Classes CSS label (twMerge) | | `editorClass` | `string` | `''` | Classes CSS wrapper éditeur (twMerge) | @@ -159,7 +161,7 @@ Zone de texte multiligne avec compteur et redimensionnement. ```vue - + ``` diff --git a/app/components/malio/input/InputRichText.test.ts b/app/components/malio/input/InputRichText.test.ts index f193f20..15ee4ca 100644 --- a/app/components/malio/input/InputRichText.test.ts +++ b/app/components/malio/input/InputRichText.test.ts @@ -61,10 +61,42 @@ describe('MalioInputRichText', () => { expect(wrapper.find('button[title="Gras"]').exists()).toBe(true) expect(wrapper.find('button[title="Italique"]').exists()).toBe(true) expect(wrapper.find('button[title="Lien"]').exists()).toBe(true) + expect(wrapper.find('button[title="Couleur du texte"]').exists()).toBe(true) + expect(wrapper.find('button[title="Surlignage"]').exists()).toBe(true) expect(wrapper.find('button[title="Annuler"]').exists()).toBe(true) expect(wrapper.find('button[title="Rétablir"]').exists()).toBe(true) }) + it('opens and closes the text color palette', async () => { + const wrapper = await mountComponent({modelValue: ''}) + + expect(wrapper.find('[aria-label="Palette couleur du texte"]').exists()).toBe(false) + + await wrapper.get('button[title="Couleur du texte"]').trigger('click') + expect(wrapper.find('[aria-label="Palette couleur du texte"]').exists()).toBe(true) + + await wrapper.get('button[title="Couleur du texte"]').trigger('click') + expect(wrapper.find('[aria-label="Palette couleur du texte"]').exists()).toBe(false) + }) + + it('opens the highlight palette and closes the color palette', async () => { + const wrapper = await mountComponent({modelValue: ''}) + + await wrapper.get('button[title="Couleur du texte"]').trigger('click') + expect(wrapper.find('[aria-label="Palette couleur du texte"]').exists()).toBe(true) + + await wrapper.get('button[title="Surlignage"]').trigger('click') + expect(wrapper.find('[aria-label="Palette de surlignage"]').exists()).toBe(true) + expect(wrapper.find('[aria-label="Palette couleur du texte"]').exists()).toBe(false) + }) + + it('disables color and highlight buttons when readonly', async () => { + const wrapper = await mountComponent({readonly: true, modelValue: ''}) + + expect(wrapper.get('button[title="Couleur du texte"]').attributes('disabled')).toBeDefined() + expect(wrapper.get('button[title="Surlignage"]').attributes('disabled')).toBeDefined() + }) + it('does not render the toolbar in readonly display mode (editable=false)', async () => { const wrapper = await mountComponent({editable: false, modelValue: '**hi**'}) diff --git a/app/components/malio/input/InputRichText.vue b/app/components/malio/input/InputRichText.vue index 7f1a402..e07ae1b 100644 --- a/app/components/malio/input/InputRichText.vue +++ b/app/components/malio/input/InputRichText.vue @@ -46,6 +46,110 @@