这是indexloc提供的服务,不要输入任何密码
Skip to content

Conversation

@balanceiskey
Copy link
Contributor

@balanceiskey balanceiskey commented Aug 26, 2025

What problem(s) was I solving?

Replaced the basic HTML textarea response editor with TipTap, a modern rich-text editor built on ProseMirror. The previous textarea lacked syntax highlighting and had limited keyboard shortcut support, making it difficult to write and review markdown-formatted responses effectively.

Related to improving the overall editing experience in the HumanLayer WUI for AI agent interactions.

What user-facing changes did I ship?

Enhanced Text Editor

  • Real-time markdown syntax highlighting for bold, italic, strikethrough, headings, lists, and inline code
  • Syntax-highlighted code blocks supporting 15+ programming languages (JavaScript, Python, Rust, Go, etc.)
  • Preserved all keyboard shortcuts: Cmd+Enter (submit), Shift+Tab (toggle auto-accept), Alt+Y (toggle skip permissions), Escape (blur)
  • Improved visual feedback: Focus state indicators, syntax marker dimming, accent/error caret colors
  • Better focus management: Consistent behavior across modals and editor states

Visual Improvements

  • Terminal-themed syntax highlighting for code blocks
  • Proper typography with weighted headings and styled lists
  • Left border color changes based on focus state (normal/error modes)
  • Markdown syntax markers visually de-emphasized for cleaner reading

How I implemented it

Core Migration (TipTap Integration)

  • Added TipTap dependencies (@tiptap/react, @tiptap/starter-kit, @tiptap/pm, @tiptap/extension-code-block-lowlight)
  • Created new ResponseEditor.tsx component (579 lines) with custom ProseMirror extensions
  • Implemented markdown syntax highlighting using decoration-based approach for performance
  • Integrated lowlight for code syntax highlighting with 15+ language support

State Management Refactoring

  • Moved editor instance to global Zustand store (AppStore.ts)
  • Added setResponseEditor() and removeResponseEditor() functions
  • Enabled global access for keyboard shortcuts and focus management
  • Changed local storage format from plain text to JSON content structure

Component Updates

  • Replaced Textarea in ResponseInput.tsx with new TipTap editor
  • Updated SessionDetail.tsx to use global editor references
  • Modified useSessionActions.ts hook to extract text from TipTap editor
  • Added comprehensive CSS styling (tiptap-editor.css, 267 lines)

Keyboard Shortcut Preservation

  • Built custom TipTap extension for shortcut handling
  • Used refs to avoid stale closures in event handlers
  • Maintained exact same shortcut behavior as original implementation
  • Proper integration with existing hotkeys system

How to verify it

  • I have ensured make check test passes (Note: pre-existing test failure in claudecode-go unrelated to this PR)

Manual Testing

  1. Markdown Syntax Highlighting:

    • Type **bold**, *italic*, ~~strikethrough~~, # heading, - list item
    • Verify real-time syntax highlighting appears
    • Confirm markdown markers are visually dimmed
  2. Code Block Testing:

    • Create code blocks with triple backticks and language specifiers
    • Test multiple languages (js, python, rust, go, etc.)
    • Verify syntax highlighting matches terminal theme
    • Check that multi-line code blocks maintain proper highlighting
  3. Keyboard Shortcuts:

    • Cmd/Ctrl+Enter: Submit non-empty content
    • Shift+Tab: Toggle auto-accept mode
    • Alt+Y: Toggle dangerous skip permissions
    • Escape: Blur editor
    • Enter (when blurred): Focus editor
  4. Focus Management:

    • Test focus/blur states show correct border colors
    • Verify modal interactions preserve focus properly
    • Check caret color changes between normal (accent) and deny (error) modes
  5. State Persistence:

    • Type content and refresh page
    • Verify content is restored from local storage
    • Check that JSON format is properly saved/loaded

Description for the changelog

Upgraded response editor from textarea to TipTap rich-text editor with real-time markdown syntax highlighting, code block syntax highlighting for 15+ languages, preserved all keyboard shortcuts, and improved visual feedback through terminal-themed styling.

@balanceiskey
Copy link
Contributor Author

This is extremely old, throwing it up as a diff to play with later

@balanceiskey balanceiskey changed the title Add TipTap editor with compose mode toggle Add updated editor with compose mode toggle Aug 26, 2025
balanceiskey and others added 9 commits August 26, 2025 14:48
- Add global keyboard shortcut (Cmd+Shift+C) to toggle compose mode
- Install TipTap dependencies (@tiptap/react, @tiptap/pm, @tiptap/starter-kit)
- Create TiptapEditor component wrapper that maintains plain text compatibility
- Integrate TipTap editor conditionally in ResponseInput when compose mode is active
- Add toast notifications when toggling compose mode on/off
- Maintain existing reply submission functionality (Cmd+Enter)
- Add CodeBlockLowlight extension for syntax highlighting
- Add MarkdownSyntaxHighlight extension to preserve markdown syntax visibility
- Apply visual styling (bold, italic, strike, code) while preserving syntax
- Style markdown syntax characters with muted colors and reduced opacity
- Add terminal color variables for syntax highlighting theme

This is an experimental feature to explore rich text editing capabilities
while maintaining backward compatibility with the existing plain text system.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
- Corrected lowlight v3 API usage from highlight(content, {language}) to highlight(language, text)
- Updated parsing logic to handle lowlight v3's tree structure instead of HTML
- Fixed CSS to display syntax highlight spans inline instead of as blocks
- Code blocks now properly highlight JavaScript and other registered languages

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
Added HTML attributes to prevent OS/browser-level text transformations:
- spellcheck: false - Disables spell checking
- autocorrect: off - Prevents auto-correction including smart quotes
- autocapitalize: off - Disables auto-capitalization

This ensures quotes remain as standard straight quotes for code/markdown editing.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
Fixed character splitting issue in code block syntax highlighting by:
- Correcting position calculation for code block content
- Building non-overlapping decoration segments before applying
- Properly accumulating CSS classes through the lowlight tree
- Ensuring decorations are freshly created on each plugin call

The fix properly traverses the lowlight v3 tree structure and applies
decorations only at text leaf nodes with all accumulated parent classes,
preventing overlapping decorations that caused character splitting.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
Process each line of multi-line code blocks independently to maintain correct
position mapping when ProseMirror splits content into separate paragraph nodes.
This prevents character splitting and DOM corruption that occurred when
decorations spanned across paragraph boundaries.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
- Rename TiptapEditor to ResponseEditor for clarity
- Store editor instance in zustand global store
- Change content persistence from plain text to JSON format
- Remove prop drilling in favor of global editor access
- Simplify editor lifecycle management through store methods
- Extract auto-accept toggle logic into reusable handler
- Extend TipTap KeyboardShortcuts to handle Shift+Tab when editor is focused
- Pass toggle handler through ResponseInput to ResponseEditor
- Fix TypeScript issues with ResponseInput ref types
- Update fork message handling to use global editor state
- Remove unused window.editor debug code and unused variables
… in TipTap editor

- Extract dangerous skip permissions toggle logic into reusable handler
- Move useHotkeysContext before handler definitions to fix hook ordering
- Extend TipTap KeyboardShortcuts to handle Alt-y when editor is focused
- Pass toggle handler through ResponseInput to ResponseEditor
- Update fork message handling to use global editor state
@balanceiskey balanceiskey changed the title Add updated editor with compose mode toggle Upgrade text editor to TipTap Aug 28, 2025
@balanceiskey balanceiskey marked this pull request as ready for review August 28, 2025 16:08
Copy link
Contributor

@ellipsis-dev ellipsis-dev bot left a comment

Choose a reason for hiding this comment

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

Caution

Changes requested ❌

Reviewed everything up to 6b56fcc in 2 minutes and 33 seconds. Click for details.
  • Reviewed 1914 lines of code in 11 files
  • Skipped 0 files when reviewing.
  • Skipped posting 7 draft comments. View those below.
  • Modify your settings and rules to customize what types of comments Ellipsis leaves. And don't forget to react with 👍 or 👎 to teach Ellipsis.
1. humanlayer-wui/src/styles/tiptap-editor.css:13
  • Draft comment:
    Consider unifying CSS variable names for color and background. The editor uses '--background' and '--foreground' (e.g., line 13) while later sections (e.g., pre block at line 159) use '--terminal-background' and '--terminal-foreground'. Using a consistent naming scheme simplifies theming.
  • Reason this comment was not posted:
    Decided after close inspection that this draft comment was likely wrong and/or not actionable: usefulness confidence = 10% vs. threshold = 50% The different variable naming appears intentional as it serves different purposes - general UI vs terminal/code styling. The terminal-prefixed variables are used consistently throughout the syntax highlighting section. Having separate variable sets allows for independent theming of the editor vs code blocks. The comment assumes these should be unified but doesn't consider they may be intentionally separate. I could be wrong about the intention - maybe this is actually an oversight. Without seeing the theme definition file, I can't be 100% certain these are meant to be separate. Even with that uncertainty, the consistent usage patterns strongly suggest this is an intentional separation between general UI and terminal/code theming. The comment should be deleted as it appears to misunderstand the intentional separation between general UI theming and terminal/code block theming variables.
2. humanlayer-wui/src/styles/tiptap-editor.css:57
  • Draft comment:
    Consider grouping related markdown syntax rules (bold, italic, strike, code, headings, lists) to improve maintainability and readability.
  • Reason this comment was not posted:
    Confidence changes required: 50% <= threshold 50% None
3. humanlayer-wui/bun.lock:976
  • Draft comment:
    Typographical error: The dependency key "devlop" appears to be a typo. It should likely be "develop".
  • Reason this comment was not posted:
    Comment looked like it was already resolved.
4. humanlayer-wui/bun.lock:1024
  • Draft comment:
    Typo detected: In the dependency list for 'micromark', the key "devlop" appears to be a misspelling. It likely should be "develop".
  • Reason this comment was not posted:
    Comment was on unchanged code.
5. humanlayer-wui/src/components/internal/SessionDetail/components/ResponseEditor.tsx:536
  • Draft comment:
    Typographical error: The log message on this line reads 'TiptapEditor.useEffect() - destroying editor', which is inconsistent with the component name 'ResponseEditor'. Consider updating it for clarity.
  • Reason this comment was not posted:
    Decided after close inspection that this draft comment was likely wrong and/or not actionable: usefulness confidence = 0% vs. threshold = 50% While the comment is technically correct about the inconsistency, the PR review rules state not to make comments that are purely informative or unimportant. Log messages are primarily for debugging purposes and this inconsistency doesn't affect functionality. The rules emphasize focusing on code changes that require action, and log message wording is a very minor issue. The inconsistent naming could potentially cause confusion during debugging since the log refers to a different component name. It's a small but real issue. While debugging clarity is important, this is still a very minor issue that doesn't impact functionality. The rules specifically say not to make comments that are obvious or unimportant. The comment should be deleted as it addresses a minor logging inconsistency that doesn't require immediate action and falls under the category of unimportant comments that the rules say to avoid.
6. humanlayer-wui/src/components/internal/SessionDetail/components/ResponseInput.tsx:181
  • Draft comment:
    It looks like the commented-out Textarea block is not properly closed. The opening comment with {/* is never terminated (e.g. with */}) which might lead to a syntax issue or unintended rendering. Please review and either fully remove the commented code or add the proper closing comment token.
  • Reason this comment was not posted:
    Comment looked like it was already resolved.
7. humanlayer-wui/src/components/internal/SessionDetail/components/ResponseInput.tsx:193
  • Draft comment:
    It looks like there's a stray closing comment marker (*/) at the end of this line. If it's not intentional, please remove it to avoid confusion.
  • Reason this comment was not posted:
    Comment looked like it was already resolved.

Workflow ID: wflow_xahEHsqojSMATrnD

You can customize Ellipsis by changing your verbosity settings, reacting with 👍 or 👎, replying to comments, or adding code review rules.

}

.tiptap-editor:focus {
/* border-color: var(--ring); */
Copy link
Contributor

Choose a reason for hiding this comment

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

The focus style for .tiptap-editor is commented out. For improved accessibility, ensure a visible focus outline is enabled.

Suggested change
/* border-color: var(--ring); */
border-color: var(--ring);

balanceiskey and others added 4 commits August 28, 2025 13:35
…itor is focused

- Replace shadow-based focus indicators with cleaner border-left approach
- Add --terminal-accent-dim variable to all themes (rgba with 0.3 opacity)
- Dim focus indicators when ResponseEditor has focus to reduce distraction
- No layout shifts: always has 2px left border, just changes color

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
Enables Fork View modal to be opened via Cmd+Y even when the response editor
has focus. Previously, TipTap was capturing keyboard events and preventing
the global hotkey from working.

- Extract handleToggleForkView as reusable callback in SessionDetail
- Pass onToggleForkView handler through ResponseInput to ResponseEditor
- Add Mod-y keyboard shortcut to TipTap's KeyboardShortcuts extension
@balanceiskey balanceiskey merged commit f5debda into humanlayer:main Aug 28, 2025
4 checks passed

"@tauri-apps/plugin-notification": ["@tauri-apps/plugin-notification@2.3.0", "", { "dependencies": { "@tauri-apps/api": "^2.6.0" } }, "sha512-QDwXo9VzAlH97c0veuf19TZI6cRBPfJDl2O6hNEDvI66j60lOO9z+PL6MJrj8A6Y+t55r7mGhe3rQWLmOre2HA=="],

"@tauri-apps/plugin-opener": ["@tauri-apps/plugin-opener@2.3.0", "", { "dependencies": { "@tauri-apps/api": "^2.0.0" } }, "sha512-yAbauwp8BCHIhhA48NN8rEf6OtfZBPCgTOCa10gmtoVCpmic5Bq+1Ba7C+NZOjogedkSiV7hAotjYnnbUVmYrw=="],

Choose a reason for hiding this comment

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

Jc

@ParmsiN9699
Copy link

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