Skip to content

feat(ui): replace MDXEditor with TipTap v3 markdown editor - #2449

Merged
n0umen0n merged 7 commits into
mainfrom
feat/cards/markdown-editor
Aug 12, 2026
Merged

feat(ui): replace MDXEditor with TipTap v3 markdown editor#2449
n0umen0n merged 7 commits into
mainfrom
feat/cards/markdown-editor

Conversation

@n0umen0n

@n0umen0n n0umen0n commented Aug 5, 2026

Copy link
Copy Markdown
Contributor

Summary

Replaces the MDXEditor-based RichTextEditor with a TipTap v3 implementation, keeping markdown as the value format in and out so nothing downstream changes. The motivation is better cross-block selection behaviour and a simpler editing stack.

  • Swaps @mdxeditor/editor and tiptap-markdown for the official @tiptap/* v3 packages (starter-kit, react, pm, extensions, markdown), and upgrades the existing TipTap deps from v2 to v3.
  • Rewrites packages/ui/src/organisms/editor.tsx with a custom toolbar (paragraph, H1–H4, bold/italic/underline, bullet/numbered list, undo/redo), placeholder support, and external-value syncing that avoids stomping in-progress typing on form reset.
  • Rewrites packages/ui/src/organisms/editor.css against Hypha design tokens (--accent-*, --neutral-*, --font-family-text) instead of shipping MDXEditor's stylesheet. Net ~1,400 lines of CSS removed.

Compatibility

RichTextEditorProps keeps the shape the two existing call sites already use, so neither was touched:

  • packages/epics/src/agreements/components/create-agreement-base-fields.tsx
  • packages/epics/src/coherence/components/create-signal-form.tsx

editorRef now points at a TipTap Editor (both call sites pass null), and translation is accepted as a no-op shim — TipTap uses aria-labels on the toolbar instead. Both are migration affordances and can be dropped in a follow-up.

Rebase notes

Rebased onto main (was 136 commits behind). Two things came out of it:

  • Font token rename. main moved to --font-family-text / --font-family-code in refactor(ui): consolidate app type to IBM Plex Sans. The conflict in editor.css was main editing MDXEditor rules this branch deletes — the deletions win, but the rename is carried forward into the new TipTap rules so the editor picks up IBM Plex Sans.
  • Lockfile. pnpm-lock.yaml recorded specifier: ^3 for the TipTap packages while package.json pinned ^3.29.2, which would have failed CI's frozen-lockfile check. Regenerated; pnpm install --frozen-lockfile now passes.

Test plan

Preview: https://hypha-7oosg14il-hypha-dao.vercel.app

  • Agreement create form: type a description, verify bold/italic/underline, H1–H4, and both list types apply and round-trip to markdown on submit.
  • Signal create form (Coherence): same checks, plus placeholder shows when empty.
  • Edit an existing agreement/signal and confirm stored markdown loads back into the editor correctly.
  • Select across multiple blocks (paragraph into list) and confirm formatting applies — the regression this change targets.
  • Undo/redo enable and disable correctly; toolbar clicks do not steal focus from the editor.
  • Check the editor frame in both light and dark themes for double borders inside form wrappers.

The failing Vercel check is the regen-sydney project, whose root directory apps/regen-sydney does not exist on this branch. Unrelated to this change.

Summary by CodeRabbit

  • New Features

    • Replaced the rich-text editor with enhanced support for headings, lists, inline formatting, links, undo/redo, placeholders, and read-only mode.
    • Markdown-like plain-text pastes are automatically converted into formatted content.
    • Chat messages now support headings, ordered and unordered lists, italics, underline, links, and other rich-text markup.
  • Bug Fixes

    • Improved formatted-message handling and list parsing across chat views.
    • Improved editor focus, selection, placeholder, keyboard navigation, and accessibility styling.

@vercel

vercel Bot commented Aug 5, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
regen-sydney Error Error Aug 6, 2026 7:10am

Request Review

@coderabbitai

coderabbitai Bot commented Aug 5, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

Walkthrough

The PR replaces MDXEditor with TipTap v3, adds controlled Markdown editing, toolbar commands, paste conversion, and new styles. Markdown and Matrix chat markup now support headings, lists, italic, and underline formatting. Chat bubbles render derived rich text with expanded test coverage.

Changes

Rich-text editor and markup migration

Layer / File(s) Summary
Markdown and Matrix markup contracts
packages/ui-utils/src/looks-like-markdown.ts, packages/ui-utils/src/markdown-inline.ts, packages/core/src/matrix/chat-markup.ts
Markdown detection and inline tokenization support headings, lists, italic text, and underline formatting. Matrix markup nodes support the same structures.
Markup parsing and message rendering
packages/core/src/matrix/..., packages/epics/src/common/human-chat-panel/..., packages/epics/src/common/ai-panel/...
Matrix markup converts to HTML. Human and AI chat bubbles render headings, lists, italic text, and underlined text.
TipTap editor integration
package.json, packages/ui/src/organisms/editor.tsx, packages/ui/src/organisms/paste-markdown.ts
RichTextEditor now uses TipTap v3 with controlled Markdown, formatting commands, editor refs, paste parsing, and external content synchronization.
Editor presentation and validation
packages/ui/src/organisms/editor.css, packages/ui-utils/src/__tests__/*, packages/core/src/matrix/__tests__/*, packages/epics/src/common/human-chat-panel/__tests__/*
Styles target the TipTap editor. Tests cover Markdown detection, inline tokenization, Matrix markup, and HTML parsing and rendering.

Estimated code review effort: 4 (Complex) | ~45 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Parent
  participant RichTextEditor
  participant TipTapEditor
  participant PasteMarkdown
  Parent->>RichTextEditor: provide Markdown and editor options
  RichTextEditor->>TipTapEditor: initialize content and extensions
  PasteMarkdown->>TipTapEditor: insert parsed Markdown on paste
  TipTapEditor-->>RichTextEditor: emit serialized Markdown changes
  Parent->>RichTextEditor: provide external Markdown
  RichTextEditor->>TipTapEditor: replace editor content
Loading

Possibly related PRs

Suggested reviewers: dsanich

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 23.08% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title follows conventional commit format, uses the valid feat type and ui scope, and clearly describes the main editor replacement.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches 💡 1
📝 Generate docstrings 💡
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/cards/markdown-editor

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 6

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@packages/ui/src/organisms/editor.css`:
- Around line 27-34: Update the editor CSS rules anchored by
.richtext-editor-content-host .tiptap and .richtext-editor-content, including
the referenced ranges, to replace all hardcoded spacing, sizing, and layout
values such as 12px, 120px, 0.5em, 1.5em, and 0.35em with the appropriate design
tokens from ui-utils. Preserve the existing layout behavior while ensuring theme
and density settings control these values consistently.

In `@packages/ui/src/organisms/editor.tsx`:
- Around line 328-329: In packages/ui/src/organisms/editor.tsx#L328-L329, render
EditorToolbar only when editable is true; in
packages/ui/src/organisms/editor.css#L151-L154, remove the pointer-events: none
rule so read-only content remains selectable and editor.setEditable(false)
controls its state.
- Around line 45-57: Define and export named interfaces for the props of both
ToolbarButton and RichTextEditor, replacing ToolbarButton’s anonymous props type
and the existing RichTextEditorProps type alias. Update each component signature
to use its corresponding exported interface while preserving all existing prop
fields and optionality.
- Around line 191-206: Add a link control alongside the list buttons in the
editor toolbar, using an accessible dialog or popover to create and edit links
for the current selection. Wire the control to the editor chain’s setLink,
toggleLink, and unsetLink commands as appropriate, including removal for an
existing link, and preserve the existing ToolbarButton patterns and editor focus
behavior.
- Around line 124-128: Update the toolbar container in the editor component to
implement composite focus management: make only the active ToolbarButton
tabbable, move focus between buttons with Left/Right Arrow keys, and update the
active index as focus changes while preserving normal activation behavior. Use
the existing ToolbarButton elements and toolbar state rather than removing the
role.
- Around line 239-247: The editor currently declares translation as a no-op;
update the toolbar label/title generation to call the provided translation
function for each user-facing value, using the existing English text as the
defaultValue and preserving interpolation arguments where applicable. Apply this
in the toolbar configuration near the translation prop so consumers’
translations replace hardcoded labels while retaining the current fallback when
translation is absent.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 46deb894-7a70-48e6-9a43-34b0ad93021e

📥 Commits

Reviewing files that changed from the base of the PR and between 825858c and 8d665ac.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml, !pnpm-lock.yaml
📒 Files selected for processing (3)
  • package.json
  • packages/ui/src/organisms/editor.css
  • packages/ui/src/organisms/editor.tsx

Comment thread packages/ui/src/organisms/editor.css
Comment thread packages/ui/src/organisms/editor.tsx Outdated
Comment thread packages/ui/src/organisms/editor.tsx
Comment thread packages/ui/src/organisms/editor.tsx
Comment thread packages/ui/src/organisms/editor.tsx Outdated
Comment thread packages/ui/src/organisms/editor.tsx Outdated
@github-actions

github-actions Bot commented Aug 5, 2026

Copy link
Copy Markdown

🔗 Custom preview URL: https://pr-2449.preview-app.hypha.earth

@coderabbitai

coderabbitai Bot commented Aug 5, 2026

Copy link
Copy Markdown
Contributor

Note

GitHub couldn't provide a complete incremental comparison for this pull request, so CodeRabbit is performing a full review instead. This review may take a little longer.

Comment thread packages/ui-utils/src/looks-like-markdown.ts Fixed

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 5

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@packages/core/src/matrix/chat-markup.ts`:
- Around line 53-59: Use one consistent heading-level maximum across all
affected sites, preferably extending support to levels 5 and 6: update
MarkupNode, chatMarkupLooksFormatted, parseHeadingLine, and HTML rendering in
packages/core/src/matrix/chat-markup.ts (lines 53-59); update heading detection
in packages/ui-utils/src/looks-like-markdown.ts (line 21); and update parsing
plus rendering classes for every supported level in
packages/epics/src/common/human-chat-panel/parse-simple-matrix-html.tsx (lines
69-74).

In `@packages/epics/src/common/human-chat-panel/parse-simple-matrix-html.tsx`:
- Around line 210-215: Update the heading branch in renderSimpleHtmlNodes so it
renders a semantic heading element matching n.level (h1–h4), or applies
role="heading" with aria-level={n.level}, while preserving the existing classes,
key, children, and text transformation.

In `@packages/ui-utils/src/looks-like-markdown.test.ts`:
- Around line 1-35: Move packages/ui-utils/src/looks-like-markdown.test.ts
(lines 1-35) to packages/ui-utils/src/__tests__/looks-like-markdown.test.ts and
update its looksLikeMarkdown relative import; also move
packages/ui-utils/src/markdown-inline.test.ts (lines 1-20) to
packages/ui-utils/src/__tests__/markdown-inline.test.ts and update its relative
import.

In `@packages/ui-utils/src/looks-like-markdown.ts`:
- Around line 47-50: Update looksLikeMarkdown by adding an italic-pair inline
Markdown check alongside the existing bold, underline, link, and code checks, so
inputs such as *italic* are detected before the paste handler bypasses
editor.markdown.parse().

In `@packages/ui/src/organisms/editor.tsx`:
- Around line 269-283: Register a custom underline Markdown handler in the
editor extensions near StarterKit, Placeholder, Markdown, and PasteMarkdown so
__text__ maps to underline rather than bold; update
packages/ui/src/organisms/paste-markdown.ts lines 23-35 to route pasted __text__
through that same handler, ensuring the underline semantics are preserved before
persistence.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: a0dbf38a-7c2b-46a5-aa63-8832a1e00703

📥 Commits

Reviewing files that changed from the base of the PR and between 825858c and 580a56f.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml, !pnpm-lock.yaml
📒 Files selected for processing (15)
  • package.json
  • packages/core/src/matrix/__tests__/chat-markup.test.ts
  • packages/core/src/matrix/chat-markup.ts
  • packages/epics/src/common/ai-panel/ai-panel-message-bubble.tsx
  • packages/epics/src/common/human-chat-panel/__tests__/parse-simple-matrix-html.test.ts
  • packages/epics/src/common/human-chat-panel/human-chat-panel-message-bubble.tsx
  • packages/epics/src/common/human-chat-panel/parse-simple-matrix-html.tsx
  • packages/ui-utils/src/index.ts
  • packages/ui-utils/src/looks-like-markdown.test.ts
  • packages/ui-utils/src/looks-like-markdown.ts
  • packages/ui-utils/src/markdown-inline.test.ts
  • packages/ui-utils/src/markdown-inline.ts
  • packages/ui/src/organisms/editor.css
  • packages/ui/src/organisms/editor.tsx
  • packages/ui/src/organisms/paste-markdown.ts

Comment thread packages/core/src/matrix/chat-markup.ts
Comment thread packages/epics/src/common/human-chat-panel/parse-simple-matrix-html.tsx Outdated
Comment thread packages/ui-utils/src/__tests__/looks-like-markdown.test.ts
Comment thread packages/ui-utils/src/looks-like-markdown.ts Outdated
Comment thread packages/ui/src/organisms/editor.tsx
@coderabbitai

coderabbitai Bot commented Aug 6, 2026

Copy link
Copy Markdown
Contributor

Note

GitHub couldn't provide a complete incremental comparison for this pull request, so CodeRabbit is performing a full review instead. This review may take a little longer.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@packages/ui/src/organisms/editor.tsx`:
- Around line 306-320: Add component tests for RichTextEditor covering external
markdown changes and form-reset/resubmit synchronization, verifying the editor
content updates correctly without overwriting local typing. Assert that
controlled synchronization uses the editor update path with emitUpdate: false
and does not invoke onChange.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 23bbeb2c-fe6e-4151-8a5b-aa67386d950a

📥 Commits

Reviewing files that changed from the base of the PR and between 1d8fb5b and e7040b5.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml, !pnpm-lock.yaml
📒 Files selected for processing (15)
  • package.json
  • packages/core/src/matrix/__tests__/chat-markup.test.ts
  • packages/core/src/matrix/chat-markup.ts
  • packages/epics/src/common/ai-panel/ai-panel-message-bubble.tsx
  • packages/epics/src/common/human-chat-panel/__tests__/parse-simple-matrix-html.test.ts
  • packages/epics/src/common/human-chat-panel/human-chat-panel-message-bubble.tsx
  • packages/epics/src/common/human-chat-panel/parse-simple-matrix-html.tsx
  • packages/ui-utils/src/index.ts
  • packages/ui-utils/src/looks-like-markdown.test.ts
  • packages/ui-utils/src/looks-like-markdown.ts
  • packages/ui-utils/src/markdown-inline.test.ts
  • packages/ui-utils/src/markdown-inline.ts
  • packages/ui/src/organisms/editor.css
  • packages/ui/src/organisms/editor.tsx
  • packages/ui/src/organisms/paste-markdown.ts

Comment thread packages/ui/src/organisms/editor.tsx

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@packages/ui-utils/src/looks-like-markdown.ts`:
- Around line 129-170: Make hasMarkdownLink linear by advancing the outer cursor
to labelEnd after each label scan, including when no closing bracket is found,
while preserving detection of valid links and image-marker skipping. Add a
regression test covering many repeated opening brackets without a closing
bracket and verify it completes without quadratic behavior.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 0b74d568-340f-48ec-b3ce-d391d59eefda

📥 Commits

Reviewing files that changed from the base of the PR and between e7040b5 and a72ba1b.

📒 Files selected for processing (6)
  • packages/epics/src/common/human-chat-panel/parse-simple-matrix-html.tsx
  • packages/ui-utils/src/__tests__/looks-like-markdown.test.ts
  • packages/ui-utils/src/__tests__/markdown-inline.test.ts
  • packages/ui-utils/src/looks-like-markdown.ts
  • packages/ui/src/organisms/editor.css
  • packages/ui/src/organisms/editor.tsx
💤 Files with no reviewable changes (1)
  • packages/ui/src/organisms/editor.css

Comment thread packages/ui-utils/src/looks-like-markdown.ts Outdated
@sceenius
sceenius enabled auto-merge August 10, 2026 16:32
sceenius and others added 5 commits August 10, 2026 12:37
Use TipTap for rich-text agreement/signal descriptions with markdown in/out, for better cross-block selection and a simpler editing stack.

Co-authored-by: Cursor <cursoragent@cursor.com>
Add TipTap paste heuristics so markdown clipboard content becomes structured editor nodes, and extend Matrix chat markup/HTML rendering for headings, lists, and underline on send and in bubbles.

Co-authored-by: Cursor <cursoragent@cursor.com>
Use TipTap for rich-text agreement/signal descriptions with markdown in/out, for better cross-block selection and a simpler editing stack.

Co-authored-by: Cursor <cursoragent@cursor.com>
Add TipTap paste heuristics so markdown clipboard content becomes structured editor nodes, and extend Matrix chat markup/HTML rendering for headings, lists, and underline on send and in bubbles.

Co-authored-by: Cursor <cursoragent@cursor.com>
Replace polynomial clipboard heuristics with linear scanners for CodeQL, and harden read-only editor toolbar plus semantic chat headings.

Co-authored-by: Cursor <cursoragent@cursor.com>
@sceenius
sceenius force-pushed the feat/cards/markdown-editor branch from a72ba1b to 0a45db6 Compare August 10, 2026 16:40
Wire toolbar i18n, link popover, roving tabindex, and design tokens.

Co-authored-by: Cursor <cursoragent@cursor.com>
@sceenius

Copy link
Copy Markdown
Collaborator

Review-fix commit landed

Pushed fix(ui): address TipTap editor review findings (0bf34dc44) to this branch.

Included

  • Design-token CSS for editor spacing/typography
  • Exported ToolbarButtonProps / RichTextEditorProps interfaces
  • Toolbar i18n via the existing translation prop
  • Link control (popover + setLink/unsetLink)
  • Roving tabindex / arrow-key toolbar focus

Skipped (already fixed)

  • Toolbar only when editable
  • pointer-events: none on read-only content

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 10

♻️ Duplicate comments (2)
packages/ui/src/organisms/editor.tsx (2)

594-608: 📐 Maintainability & Code Quality | 🔵 Trivial | 🏗️ Heavy lift

Controlled-sync tests are still missing.

No test file covers RichTextEditor. This effect carries the highest correctness risk in the component: it compares markdown against lastEmittedMarkdown.current, then against editor.getMarkdown(), and calls setContent with emitUpdate: false. A serializer normalization difference makes current !== markdown even when the documents match, which resets the cursor mid-edit.

Add tests for external markdown updates, form reset, and the assertion that onChange is not invoked during controlled sync.

This repeats an earlier finding that is not yet resolved.

Do you want me to generate the test file, or open an issue to track it?

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/ui/src/organisms/editor.tsx` around lines 594 - 608, Add tests
covering RichTextEditor controlled synchronization: verify external markdown
updates and form resets update the editor content, and verify controlled sync
calls setContent with emitUpdate false without invoking onChange. Include a case
where editor.getMarkdown() differs only through serializer normalization,
ensuring local typing and cursor state are not unnecessarily reset.

557-571: 🗄️ Data Integrity & Integration | 🟠 Major | 🏗️ Heavy lift

__text__ still resolves to bold, not underline.

The extension list adds Markdown with no custom underline tokenizer or serializer. packages/core/src/matrix/chat-markup.ts treats __text__ as underline, while Marked-based Markdown treats it as strong emphasis. Round-tripping existing content through this editor converts underline to bold before persistence. The toolbar toggleUnderline command at Line 449 has the same asymmetry on serialization.

This repeats an earlier finding that is not yet resolved.

#!/bin/bash
# Confirm the underline markup contract is still divergent across the editor and the chat markup layer.
set -euo pipefail

echo "== underline handling in chat markup =="
rg -nP -C 4 'underline|__|\+\+' packages/core/src/matrix/chat-markup.ts

echo "== any custom markdown tokenizer registered for underline =="
rg -nP -C 4 'markdownTokenizer|renderMarkdown|parseMarkdown|Underline' packages/ui/src/organisms

echo "== paste path =="
cat -n packages/ui/src/organisms/paste-markdown.ts
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/ui/src/organisms/editor.tsx` around lines 557 - 571, Align the
editor’s Markdown extension and the toolbar toggleUnderline serialization with
the underline contract in chat-markup.ts, so __text__ parses and serializes as
underline rather than bold. Add or reuse the appropriate custom underline
tokenizer/serializer in the editor Markdown flow, including pasted Markdown
handled by PasteMarkdown, while preserving normal strong-emphasis behavior.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@packages/ui/src/organisms/editor.css`:
- Around line 147-154: Remove the contrast-reducing color override from the
rich-text underline rule so underlined content inherits the body text color, and
remove opacity from the read-only .richtext-editor container. Preserve the
read-only state using an appropriate background or border change without
reducing text contrast.
- Around line 15-21: Replace the Tailwind utility selector in the rich text
editor styling with the proposed data-attribute hook, and expose that state
through the RichTextEditorProps API in RichTextEditor. Update call sites that
currently depend on the implicit wrapper-class match to pass bordered={false},
preserving border removal only when explicitly requested.
- Around line 163-164: Update the prefers-contrast media query wrapping
.richtext-editor to use the valid more value instead of high, preserving the
existing 2px border styling.
- Around line 42-49: In the rich-text editor placeholder CSS, remove the
unscoped `.tiptap .is-empty::before` selector from the rule and retain only
`.tiptap p.is-editor-empty:first-child::before`, preserving the existing
placeholder declarations.

In `@packages/ui/src/organisms/editor.tsx`:
- Around line 305-329: Update handleToolbarKeyDown and the related itemTabIndex
logic so tabbableIndex is clamped or advanced to an enabled toolbar item
whenever its current button becomes disabled, preserving a reachable Tab stop.
Remove the ineffective ?? tabbableIndex fallback from items.findIndex and
replace the arbitrary items.length * 10 bias with a single items.length offset;
retain existing arrow-key wrapping and focus behavior.
- Around line 572-576: Update RichTextEditorProps and the editorProps.attributes
configuration in the editor setup to accept and apply an accessible name via
aria-label or aria-labelledby, along with role="textbox" and
aria-multiline="true". Because editorProps is captured by useEditor, synchronize
changing ARIA name values with editor.setOptions in an effect, while preserving
the existing class attributes.
- Around line 229-248: Update the applyLink flow in editor.tsx to handle a
collapsed selection with no existing link: insert the URL text and apply the
link mark in the same editor chain, or disable the Apply button for that state.
Preserve the existing behavior for non-empty selections and selections inside
links, and ensure the popover does not close after an ineffective apply.
- Around line 331-340: Inside the component, compute the platform detection once
as an isApple value using the existing navigator guard and regex, then reuse it
for both undoShortcut and redoShortcut ternaries. Remove the duplicated platform
checks while preserving the current shortcut labels and server-safe navigator
handling.
- Around line 566-568: Update the editor synchronization effects near the
existing setEditable effect so changes to the placeholder prop update the
mounted editor’s placeholder extension. Do not rely solely on the one-time
Placeholder.configure call inside useEditor; add the corresponding
editor/placeholder-dependent update using the editor’s existing extension or
command API, while preserving the initial fallback to an empty string.
- Around line 90-136: Update ToolbarButtonProps and ToolbarButton to extend
Button props, forward remaining props to Button, and invoke the optional click
handler with the event while preserving the existing onClick behavior and
onMouseDown guard. Remove the link popover trigger’s no-op click handler so
Radix can receive and compose the forwarded props and event correctly.

---

Duplicate comments:
In `@packages/ui/src/organisms/editor.tsx`:
- Around line 594-608: Add tests covering RichTextEditor controlled
synchronization: verify external markdown updates and form resets update the
editor content, and verify controlled sync calls setContent with emitUpdate
false without invoking onChange. Include a case where editor.getMarkdown()
differs only through serializer normalization, ensuring local typing and cursor
state are not unnecessarily reset.
- Around line 557-571: Align the editor’s Markdown extension and the toolbar
toggleUnderline serialization with the underline contract in chat-markup.ts, so
__text__ parses and serializes as underline rather than bold. Add or reuse the
appropriate custom underline tokenizer/serializer in the editor Markdown flow,
including pasted Markdown handled by PasteMarkdown, while preserving normal
strong-emphasis behavior.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: aec7b5d9-5282-4a65-9481-66977049aeb6

📥 Commits

Reviewing files that changed from the base of the PR and between a72ba1b and 0bf34dc.

📒 Files selected for processing (2)
  • packages/ui/src/organisms/editor.css
  • packages/ui/src/organisms/editor.tsx

Comment thread packages/ui/src/organisms/editor.css
Comment thread packages/ui/src/organisms/editor.css Outdated
Comment thread packages/ui/src/organisms/editor.css
Comment thread packages/ui/src/organisms/editor.css Outdated
Comment thread packages/ui/src/organisms/editor.tsx Outdated
Comment thread packages/ui/src/organisms/editor.tsx
Comment thread packages/ui/src/organisms/editor.tsx
Comment thread packages/ui/src/organisms/editor.tsx Outdated
Comment thread packages/ui/src/organisms/editor.tsx
Comment thread packages/ui/src/organisms/editor.tsx
Align __underline__/ **bold** with chat markup, harden paste detection and
toolbar a11y, and expose an explicit bordered prop instead of Tailwind coupling.

Co-authored-by: Cursor <cursoragent@cursor.com>
@n0umen0n

Copy link
Copy Markdown
Contributor Author

Autofix Review Completed

Fixed 8 file(s) based on 12 unresolved CodeRabbit review comment(s) (1 skipped as already consistent).

Files modified:

  • packages/ui/src/organisms/editor.tsx
  • packages/ui/src/organisms/editor.css
  • packages/ui/src/organisms/chat-markdown-marks.ts (new)
  • packages/ui/src/organisms/paste-markdown.ts
  • packages/ui-utils/src/looks-like-markdown.ts
  • packages/ui-utils/src/__tests__/looks-like-markdown.test.ts
  • packages/epics/src/agreements/components/create-agreement-base-fields.tsx
  • packages/epics/src/coherence/components/create-signal-form.tsx
  • package.json / pnpm-lock.yaml

Commit: 0d014d9f40

Skipped: heading-level max already consistent at 4 across paste detection, Matrix markup, TipTap (levels: [1,2,3,4]), and chat HTML rendering.

The latest autofix changes are on the feat/cards/markdown-editor branch.

@sceenius
sceenius added this pull request to the merge queue Aug 12, 2026
@n0umen0n
n0umen0n removed this pull request from the merge queue due to a manual request Aug 12, 2026
@n0umen0n
n0umen0n added this pull request to the merge queue Aug 12, 2026
Merged via the queue into main with commit d263354 Aug 12, 2026
10 checks passed
@n0umen0n
n0umen0n deleted the feat/cards/markdown-editor branch August 12, 2026 16:20
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants