From ea92acff3a3b25f6b8e72b0aa5795c5d1c7abe62 Mon Sep 17 00:00:00 2001 From: matthieu Date: Mon, 4 May 2026 19:54:34 +0200 Subject: [PATCH] =?UTF-8?q?fix(input-rich-text)=20:=20couleurs=20de=20text?= =?UTF-8?q?e=20et=20surlignage=20fa=C3=A7on=20Jira?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Ajoute deux boutons à la toolbar avec popover en palette pour appliquer une couleur de texte ou un surlignage sur la sélection. - 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 du popover sur clic extérieur, Echap, ou clic dans l'éditeur. - Inclut les améliorations rendu/markdown du commit précédent (default outputFormat html, normalizeEditorInput, styles deep pour h2/h3/p/ul/ol/blockquote). - Tests : 4 nouveaux cas (15 au total). - Story et COMPONENTS.md à jour. Note : les couleurs ne sont pas sérialisables en markdown ; pour les conserver au save/reload utiliser output-format=\"html\". Co-Authored-By: RuFlo --- 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 @@