-
-
Notifications
You must be signed in to change notification settings - Fork 135
Rich and Markdown Text Editor #2501
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Conversation
… SN theme, formik bridge touchups, a better toolbar style
…gic, image markdown transformer, testing on more scenarios
…ty; re-instate SN markdown renderer
…cussions create/edit
…s for markdown mode
…t, re-introduce usage of Lexical in read mode
…ustomAutoLink plugin
…ia component rendering
…fore lexical loads
…s, remove more parts of experimental migration strategy
…that many worker instances can pick up, idempotently
…eProtocol on embed recognition
…up: remove unused code, improve lexical structure; fix: move embed dimensions to the parent rather than the iframe
combine mdHas and mdGetTypes to avoid double markdown parsing reduce $isMarkdownMode calls reduce $getSelection calls
…priate extensions directory
…ables and toolbar buttons; fix: client-side shortcuts to avoid hydration mismatches
| const text = markdownNode?.getTextContent() || '' | ||
| const percent = total ? Math.floor((loaded / total) * 100) : 0 | ||
| const regex = new RegExp(`!\\[Uploading ${file.name}… \\d+%\\]\\(${key}\\)`) | ||
| const newText = text.replace(regex, ``) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Bug: Filenames Corrupt Regex Patterns
In markdown mode, file.name is directly interpolated into a regex pattern without escaping special characters. If the filename contains regex metacharacters like ., [, ], (, ), *, +, ?, etc., the regex will either fail to match or match unintended strings, breaking upload progress updates. The same issue exists in onSuccess at line 172 where the regex is constructed identically.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actually during cleanup I was debating the utility of a progress percentage. If we drop it then we don't have to do regexes.
|
Woot! The bug hunt begins! I found a couple just now. Transforms appear to be unreliable: buggy.transforms.movSometimes the editor will get into a state where the cursor isn't in a paragraph block and new blocks will be weird (eg code block). I seemed to trigger this behavior after transforming back and forth to markdown mode: buggy.block.mov |
wow you spotted a very recent bug haha lexical/7974 note: transformations need serious QA because covering a lot of scenarios can be really messy.
Ah, might've reduced selection placement calls too much... |
…tion after emptying the editor
fix: pass item.text to truncateString as a fallback for missing HTML
| toaster.danger(`upload of '${file.name}' failed: ` + e.message || e.toString?.()) | ||
| } | ||
| continue | ||
| toaster.danger(`upload of '${file.name}' failed: ` + e.message || e.toString?.()) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Bug: Error Message Precedence Drops Context
Operator precedence bug in error message construction. The expression evaluates as (fullString + e.message) || e.toString?.(), so if e.message is an empty string, the entire upload context message is discarded and only e.toString() is shown. The fallback should be e.message || e.toString?.() with the string concatenation wrapping the entire result.
|
|
||
| console.log('resolve id', id) | ||
| resolve(id) | ||
| xhr.send(form) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Bug: Stale Callbacks: Incomplete Dependency Array
The s3Upload callback's dependency array on line 94 only includes toaster and getSignedPOST, but the callback also uses avatar, onUpload, onError, onProgress, and onSuccess props. If these props change after the component mounts, the callback will continue using stale values, potentially calling outdated handlers or using incorrect avatar settings.
Description
Introduces Lexical as a Markdown/Rich Text editor and renderer
This PR is ready for review as-is. While structure and cleanup are an on-going work, the editor has been QA'd extensively and logic has been refined across these two months.
Screenshots
Comment editor view:

Toplevel editor view:

Toolbar
Toolbar with shortcuts

Toolbar with dropdowns

Floating Toolbar

Media
Media captions, resize and DnD
Screen.Recording.2025-11-02.at.18.32.34.mp4
Decorators
Table of contentstable-of-contents.mp4
Features
core
formatting
lists
1))content
media
links
mentions
markdown
server
UX
New things
4kBof size in the bundle (this has to be re-verified later)MediaOrLinkpreserves scroll on load, supports captions and resizeAdditional Context
TBD, a lot has changed from the last update
Progress
TBD, a lot has changed from the last update
Checklist
Are your changes backward compatible? Please answer below:
For example, a change is not backward compatible if you removed a GraphQL field or dropped a database column.
Yes! Everything has backwards compatibility. But it also does not depend on existing features that are going to be replaced.
On a scale of 1-10 how well and how have you QA'd this change and any features it might affect? Please answer below:
tbd
For frontend changes: Tested on mobile, light and dark mode? Please answer below:
UI is tested on both mobile and desktop.
Did you introduce any new environment variables? If so, call them out explicitly here:
n/a
Did you use AI for this? If so, how much did it assist you?
It's a big PR with Lexical being a novel paradigm.
Ask: better lexical understanding, things that weren't clear in documentation or in code, best practices
Agent: massive restructuring, autocomplete, lexical overrides with lint
Note
Introduce a Lexical-based rich/markdown editor and renderer, add schema/API fields for
lexicalState/html, server HTML generation, and a worker-driven migration for legacy content, with broad UI integration and media/mention tooling.Item.lexicalState(JSONB) andItem.html; createLexicalMigrationLog/LexicalBatchMigrationLog.lexicalState/htmltoItem; acceptlexicalStatein item/sub/user mutations; newexecuteConversionmutation.MarkdownInputwithLexicalInputacross forms (posts, comments, jobs, polls, bounties, bio, sub descriptions).MediaOrLinkscroll-preserving and resizing/captions./u/:idredirect.Written by Cursor Bugbot for commit bc69de5. This will update automatically on new commits. Configure here.