enhancement
major
defect
major
minor
The React WYSIWYG editor (com.top_logic.layout.react.wysiwyg) uses Tiptap 2 (@tiptap/core 2.27.x). The Jenkins job CheckDependencies reports GHSA-cp6q-959q-f8rh for it:
Tiptap: mergeAttributes() turns an own __proto__ key into inherited executable DOM attributes.
Affected are all versions >=2.0.0-alpha.0 <3.30.4; there is no fixed 2.x release. The fix requires the upgrade of all @tiptap/* packages to Tiptap 3 (3.30.4 or later), a major release with API changes (e.g. packaging of the table and text-style extensions), so the editor component has to be migrated and re-tested.
Beim Test fiel außerdem auf: In einem Dialog (z.B. Bearbeiten-Dialog mit einem Rich-Text-Feld) ließ sich das Link-Popup der Editor-Werkzeugleiste nicht öffnen, und die Auswahl einer Überschriftenebene bzw. Liste erzeugte eine Flut von RangeError: Maximum call stack size exceeded. Die Popups werden an document.body gerendert; die Fokusfalle des Dialogs holte den Fokus zurück, das Popup holte ihn wieder an sich. Nach dem Schließen eines Popups lag der Fokus zudem auf dem Werkzeugleisten-Button statt im Text, sodass sofortiges Weiterschreiben ins Leere ging.
Lösung
- Alle @tiptap/*-Pakete auf Tiptap 3 (ab 3.31.4), @tiptap/pm als direkte Abhängigkeit. Die in Tiptap 3 zusammengelegten Pakete entfallen: Unterstreichen und Link sind Teil des StarterKit, Tabellenzeile/-zelle/-kopf Teil von @tiptap/extension-table, Farbe Teil von @tiptap/extension-text-style.
- Der Editor konfiguriert Link (ohne Öffnen per Klick) über das StarterKit. Die mit Tiptap 3 neue Standard-Erweiterung TrailingNode (leerer Absatz hinter einer abschließenden Tabelle bzw. einem Codeblock) ist abgeschaltet, damit das Öffnen eines bestehenden Texts im Editor dessen HTML nicht verändert.
- Tiptap 3 rendert die Editor-Komponente nicht mehr bei jeder Transaktion neu. Die Werkzeugleiste liest ihre Zustände (aktive Formatierung, Überschriftenebene, Liste, Link, Rückgängig/Wiederholen) daher über useEditorState und wird nur neu gerendert, wenn sich einer davon ändert.
- Angepasste API: setContent(html, { emitUpdate: false }).
- Die Popups der Werkzeugleiste (Überschrift, Listen, Link) tragen die Markierung anchoredOverlayProps der Bridge, sodass die Fokusfalle eines Dialogs sie als Teil des Dialogs behandelt. Beim Schließen eines Popups (Auswahl, Übernehmen, Escape, Klick daneben) kehrt der Fokus an die vorherige Stelle im Text zurück.