feat(editor-input): replace Lexical with TipTap + v1.7 backward-compat shim#456
feat(editor-input): replace Lexical with TipTap + v1.7 backward-compat shim#456jaieds wants to merge 9 commits into
Conversation
…ble support
Swaps the four Lexical packages for a minimal TipTap stack to eliminate
Shadow DOM bugs (broken outside-click via document.addEventListener,
selectionchange sync workarounds) and reduce overall complexity.
- Remove: lexical, @lexical/react, @lexical/selection, @lexical/utils
- Add: @tiptap/core, @tiptap/react, @tiptap/pm, @tiptap/extension-{document,
paragraph,text,hard-break,placeholder,mention}, @tiptap/suggestion
- Rewrite editor-input.tsx around useEditor; mention chip rendered via
ReactNodeViewRenderer (ProseMirror atom node — no custom arrow-key shims)
- Add utils/markup.ts: parseMarkup / serializeToMarkup for @[Label](id) format
- onChange now emits (markup: string, editor: Editor) instead of EditorState
- defaultValue now accepts plain @[Label](id) markup instead of Lexical JSON
- New multiline prop (default true); false swallows Enter without breaking @
- Shadow DOM: works without selectionchange hack or separate createRoot magic;
suggestion dropdown outside-click uses getRootNode() instead of document
- Delete: mention-node, mention-plugin, mention-hooks, mention-option-item,
editor-theme, character-limit-plugin, override-editor-style-plugin
…-key navigation When the dropdown list is taller than its max-height, keyboard navigation with ArrowUp/ArrowDown now scrolls the highlighted item into view so it is always visible without manual scrolling.
… output Without the regex patterns, @tiptap/pm sub-path imports (e.g. @tiptap/pm/state) and transitive prosemirror-* packages were being bundled into dist/node_modules instead of being treated as peer deps — adding ~600 KB to the output. Mirrors the existing /^@lexical\// pattern used for the previous Lexical deps.
…mpat Reintroduces a compatibility shim for consumers stuck on the pre-TipTap Lexical IO contract. Adds an opt-in `valueFormat: 'markup' | 'lexical'` prop (default `markup`). With `valueFormat="lexical"`: - `defaultValue` accepts the old Lexical `EditorState` JSON string and is converted to a TipTap doc on mount. - `onChange`'s first argument is a synthetic `LegacyEditorState` exposing `.toJSON()` (Lexical-shaped) and `.read()`, so existing call sites that do `editorState.toJSON()` keep working unchanged. - `ref.current.legacy` exposes `getEditorState`, `focus`, and `update`. Each deprecated surface logs one dev-only `console.warn` per session. Adds `utils/lexical-compat.ts` with `lexicalJSONToTipTapDoc`, `tipTapDocToLexicalJSON`, `lexicalToMarkup`, and `markupToLexical`, re-exported from the package root for one-time data migrations. Slated for removal in 2.0; see readme migration section.
The v1.7 Lexical lookup excluded object options whose `[by]` field was
empty, null, undefined, or missing — those entries never appeared in
the suggestion dropdown. The TipTap rewrite dropped that guard, so
empty-labeled options now render as blank rows when the query is empty
(`''.includes('')` is `true`).
Add the `if ( ! val ) return false` check back in `filterOptions`.
The placeholder used `absolute inset-0 flex items-center`, which kept it vertically centered over the whole editor area. As soon as the editor grew (auto-height, additional paragraphs before the user re-emptied it, or a tall wrapper), the placeholder drifted to the middle while the caret stayed on the first line. Pin the placeholder to the top (`top-0 left-0 right-0`), tag it with an `editor-placeholder` marker class, and give it the same per-size `min-h-5/6/7` as the empty `<p>` — combined with `items-center` it now mirrors the `<p>`'s `content-center` so the placeholder text sits at the same vertical position as the caret regardless of the editor's overall height.
… page Adds a one-line changelog entry summarising the Lexical-to-TipTap swap and the `valueFormat="lexical"` compat shim, matching the terse style of existing entries. Also adds a Storybook docs page at "Atoms / EditorInput / Migration & Changelog" with the full migration guide (breaking changes, both migration paths, ref usage, removal timeline). Uses a stories file with a JSDoc-comment description rather than MDX to avoid the SB10 + Vite absolute-file-URL import-analysis bug with `mdx-react-shim`.
| @@ -11,14 +11,20 @@ | |||
| "dependencies": { | |||
There was a problem hiding this comment.
What: Consider verifying the security of dependencies, especially since numerous new packages have been added. For example, ensure that @tiptap packages and other newly introduced packages do not have known vulnerabilities.
Why: Using packages with vulnerabilities can expose the application to attacks, like XSS or injection flaws, especially in a text editor where user content is involved.
How: Check the security audits for the new packages using npm audit, and make sure there are no critical or high severity vulnerabilities. If there are, consider looking for alternative packages or updating to a patched version if available.
| @@ -11,14 +11,20 @@ | |||
| "dependencies": { | |||
There was a problem hiding this comment.
What: The new dependencies have been included without version locking, which can lead to unpredictable behavior based on which version gets installed in production.
Why: Not specifying exact versions can lead to issues when different environments (like production vs development) install different versions of packages, which may cause bugs or errors that are hard to trace.
How: Specify exact versions instead of using caret (^) when adding major changes to production-level packages in the package.json file, ensuring consistent builds across environments.
| "version": "1.8.0", | ||
| "description": "Library of components for the BSF project", | ||
| "main": "./dist/force-ui.cjs.js", | ||
| "module": "./dist/force-ui.es.js", |
There was a problem hiding this comment.
What: The package versions should be reviewed and locked to specific minor versions if stability is a concern.
Why: Using caret (^) with versions can lead to potential breaking changes when updating dependencies to newer versions, potentially causing issues in production.
How: Consider changing the dependencies to specific minor versions (e.g. "@tiptap/core": "3.23.2" instead of "^3.23.2") or ensure that the package is tested well with the latest versions before releasing.
36676d7 to
9e52359
Compare
Summary
EditorInput(commitfa2dca64) to fix Shadow DOM bugs and shrink the bundle. Adds dropdown polish, build fix for@tiptap/*externalisation.valueFormat="lexical"keeps the old LexicalEditorStateJSON contract working fordefaultValue,onChange, andref.current.legacy. Deprecated; removed in 2.0.lexicalToMarkup,markupToLexical,lexicalJSONToTipTapDoc,tipTapDocToLexicalJSON) for one-time data migrations.multilineprop, restores the v1.7 empty-label guard in the mention filter, and fixes the placeholder alignment so it stays on the first line as the editor grows.1.8.0, updateschangelog.txt, and adds a Storybook Migration & Changelog docs page plus aWithLexicalCompatstory.Commits
fa2dca64refactor(editor-input): replace Lexical with TipTap for mention/variable support28e7e99efix(editor-input): scroll selected suggestion item into view on arrow-key navigation25345e1bfix(editor-input): add 8px gap between input and suggestion dropdownc80952d9fix(editor-input): align suggestion dropdown width with input borderf2df720efix(build): externalise @tiptap/* and prosemirror* packages in rollup output55255142feat(editor-input): add valueFormat prop for v1.7 Lexical backward compat672ec606fix(editor-input): restore empty-label guard in mention filterea65d6e8fix(editor-input): align placeholder with caret on first line9e52359bdocs(editor-input): add 1.8.0 changelog entry and Storybook migration pageBreaking changes
defaultValueEditorStateJSON string@[Label](id)markuponChangearg 1EditorState— call sites do.toJSON()markup: stringref.currentLexicalEditorEditorv1.7 consumers opt back into the old contract with a single prop:
Each deprecated surface fires a one-time dev-only
console.warn. Full migration guide on the Storybook Atoms / EditorInput / Migration & Changelog page.Surerank and surerank-pro call sites have been audited (14
<EditorInput>tags); thevalueFormat="lexical"edits are staged in those repos but not yet committed there.Test plan
npm run buildsucceeds and emitseditor-input/utils/lexical-compat.{cjs,es}.js.Atoms/EditorInputall render:Default,Small,Medium,Large,WithDefaultValue(markup),WithLexicalCompat(Lexical JSON via shim),InShadowRoot.WithLexicalCompat: typing into the editor logs a Lexical-shaped JSON object viaeditorState.toJSON()and fires the deprecation warning exactly once.onChangewith no warning.[by]field do not render; dropdown stays inside the input border with an 8px gap; arrow-key selection scrolls into view.ref.currentexposes the TipTapEditorAPI in default mode;ref.current.legacy.{getEditorState,focus,update}exposed only whenvalueFormat="lexical"is set.