feat(lab): add link support to RichTextEditor - #4670
Merged
Conversation
potatowagon
requested review from
cixzhang,
ejhammond and
imdreamrunner
as code owners
August 3, 2026 05:28
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
potatowagon
force-pushed
the
navi/feat/richtext-links
branch
from
August 3, 2026 05:47
91a0f25 to
4149440
Compare
Add link creation/editing to the experimental RichTextEditor, matching
the command + node contract of Meta's EPS eps-lexical editor so its
internals can later be backed by this component.
- RichTextEditorToolbar: Link button + Cmd/Ctrl+K toggle a link on the
selection via Lexical TOGGLE_LINK_COMMAND; active state synced with
$isLinkNode(parent) || $isLinkNode(node). URL obtained via an
overridable promptForUrl (window.prompt default), sanitized to
http/https/mailto/tel. Collapsed-caret fallback inserts a link node.
- New-tab is baked into the link node data (target=_blank + rel via the
TOGGLE_LINK_COMMAND {url, target, rel} payload), so it serializes and
round-trips — no DOM-patching plugin. Toggle with linkOpensInNewTab.
- RichTextEditorAutoLinkPlugin: auto-linkify typed/pasted URLs + emails
with new-tab attributes; matchers overridable.
- linkUtils: sanitizeUrl/validateUrl + URL/EMAIL matchers.
- Tests, storybook stories, docs.
potatowagon
force-pushed
the
navi/feat/richtext-links
branch
from
August 3, 2026 06:14
4149440 to
1fda690
Compare
cixzhang
approved these changes
Aug 3, 2026
Contributor
PR Analysis Report📚 Storybook PreviewView Storybook for this PR 🧪 Sandbox PreviewView Sandbox for this PR Modified ComponentsRichTextEditor (@astryxdesign/lab) · View in Storybook
Bundle Size Summary
Accessibility AuditStatus: No accessibility violations detected. Generated by PR Enrichment workflow | Storybook | Sandbox | View full report |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
Adds link support to the experimental
RichTextEditor(@astryxdesign/lab). PreviouslyLinkNode/AutoLinkNode+LinkPluginwere registered, so links rendered — but there was no way to create one. This adds creation, auto-linking, and new-tab behavior.Why this shape — EPS eps-lexical compatibility
The end goal is to back Meta's EPS
EPSRichTextArea(nest/libs/eps-lexical) with this editor. So the design deliberately matches EPS's command + node contract, not its UI chrome:TOGGLE_LINK_COMMAND(same as eps-lexical'sLinkPopoverPlugin.handleSubmit)$isLinkNode(parent) || $isLinkNode(node)(identical to the EPS toolbar)$createLinkNode(matches EPS)createLinkMatcherWithRegExp+attributes) and new-tab defaults — EPS can pass its own richer matchers (e.g.D123/T456/S789intern URLs)target/relvia theTOGGLE_LINK_COMMAND {url, target, rel}payload) so it serializes and round-trips — no DOM-patching pluginEPS keeps its own popover UI / hardened auto-link fork; astryx stays OSS-minimal and exposes the extension points (
promptForUrl,matchers,linkOpensInNewTab) so EPS drops in without changing the contract.Changes
RichTextEditorToolbar: Link button (on by default;hasLink={false}to hide) +Cmd/Ctrl+K(via Lexical'sisExactShortcutMatch, mirroring the playground'sShortcutsPlugin). Prompts for a URL via overridablepromptForUrl(defaultwindow.prompt), sanitizes it, toggles the link. Themeable icon via therichtext:linkregistry key.target="_blank"+rel="noopener noreferrer"by default;linkOpensInNewTab={false}opts out.RichTextEditorAutoLinkPlugin: auto-linkify typed/pasted URLs + emails (new-tab);matchersoverridable.linkUtils:sanitizeUrl/validateUrl(only http/https/mailto/tel; rejectsjavascript:/data:) +URL_MATCHER/EMAIL_MATCHER.WithLinks,WithAutoLink), doc updates.Testing
pnpm -F @astryxdesign/lab typecheck— clean (pre-existing.doc.mjsimplicit-any warnings unrelated)RichTextEditor.test.tsx— passing (incl. new link/sanitizer/autolink/new-tab/shortcut tests)check:sync/check:package-boundaries/check:changesets— clean