From 9fba7ba7efb4e18bced86a113faec708769add36 Mon Sep 17 00:00:00 2001 From: Dayle David <274897977+mindcraft-research@users.noreply.github.com> Date: Thu, 14 May 2026 12:19:51 +0200 Subject: [PATCH] fix: clean Word inline styles when pasting into rich editor MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Quand l'utilisateur·rice colle du contenu depuis Word (ou Google Docs, Excel...), les balises inline reçoivent des inline-styles parasites (color, font-family, font-size...) qui écrasent ensuite les couleurs définies au niveau des titres via le bouton « couleur » de l'éditeur. Exemple typique signalé : on colle un titre depuis Word, puis on tente de le passer en bleu via la toolbar. Visuellement le titre reste noir parce que le hérité de Word gagne sur le ajouté par l'éditeur. Fix : intercepter le coller via editorProps.transformPastedHTML, parser le contenu, retirer les inline-styles color / background / font-family / font-size / font-weight des balises inline (strong, b, em, i, u, span). On nettoie aussi les classes Word « MsoXxx » et les balises Office (, ). Le formatage utile (gras, italique, souligné, listes, alignement, titres) reste préservé. Bug signalé par MaximeVIALA dans le feedback #cmp2cj1ok (qui avait identifié la cause lui-même). --- .../src/components/builder/RichEditor.jsx | 47 +++++++++++++++++++ 1 file changed, 47 insertions(+) diff --git a/frontend/src/components/builder/RichEditor.jsx b/frontend/src/components/builder/RichEditor.jsx index 0bc85bd..0b1e283 100644 --- a/frontend/src/components/builder/RichEditor.jsx +++ b/frontend/src/components/builder/RichEditor.jsx @@ -61,6 +61,53 @@ export default function RichEditor({ value, onChange, compact = false }) { onUpdate: ({ editor }) => { onChange(editor.getHTML()) }, + editorProps: { + // Nettoyage du HTML collé depuis Word/Excel/Google Docs/etc. + // Word colle systématiquement des inline-styles (color, font-family, + // font-size) sur les balises inline (, , ...) qui + // écrasent les couleurs et tailles définies au niveau du

/

+ // une fois sauvegardées. On les retire au coller pour que les styles + // de l'éditeur (couleur de titre, etc.) restent maîtres. + transformPastedHTML(html) { + if (typeof window === 'undefined') return html + try { + const doc = new DOMParser().parseFromString(html, 'text/html') + + // Retirer les styles parasites sur les balises inline. + doc.querySelectorAll('strong, b, em, i, u, span').forEach((el) => { + // On retire systématiquement color, font-family, font-size : + // ces propriétés cumulent depuis Word et écrasent les choix + // faits dans l'éditeur via les boutons « couleur », « taille »… + el.style.removeProperty('color') + el.style.removeProperty('background-color') + el.style.removeProperty('background') + el.style.removeProperty('font-family') + el.style.removeProperty('font-size') + el.style.removeProperty('font-weight') + // Si plus aucun style restant, on enlève l'attribut style entier. + if (!el.getAttribute('style')) el.removeAttribute('style') + }) + + // Retirer les classes Word « MsoXxx » (purement décoratives, sans + // CSS associé chez nous, mais peuvent gêner via certains thèmes). + doc.querySelectorAll('[class*="Mso"]').forEach((el) => { + const cls = (el.getAttribute('class') || '') + .split(/\s+/).filter((c) => !c.startsWith('Mso')).join(' ') + if (cls) el.setAttribute('class', cls) + else el.removeAttribute('class') + }) + + // Retirer les balises Office spécifiques (, ...) + // que TipTap rejette parfois bizarrement. + doc.querySelectorAll('o\\:p, w\\:WordDocument').forEach((el) => el.remove()) + + return doc.body.innerHTML + } catch { + // Si le parser plante, on laisse le HTML brut — TipTap fera de son mieux. + return html + } + }, + }, }) useEffect(() => {