Skip to content

Conversation

@SonyLeo
Copy link
Collaborator

@SonyLeo SonyLeo commented Nov 25, 2025

Component

  • Refactor useKeyboardHandler to extract insertNewLine logic into separate function
  • Implement handleNewLine function to centralize newline handling for submitType="enter"
  • Support Ctrl+Enter and Shift+Enter for newline insertion in single-line mode
  • Auto-switch from single-line to multi-line mode when using newline shortcuts

Docs

  • Update documentation to explain submitType behavior with Ctrl+Enter and Shift+Enter
  • Add detailed info box explaining submit vs newline shortcuts for each submitType
  • Expand keyboard shortcuts reference table with dual-function keys

Preview

https://sonyleo.github.io/tiny-robot/alpha/components/sender.html#%E8%BE%93%E5%85%A5%E6%A8%A1%E5%BC%8F

Summary by CodeRabbit

  • New Features

    • Ctrl+Enter and Shift+Enter now insert a newline at the cursor when submitType="enter" and will auto-switch to multi-line as needed; single-line also auto-switches when content exceeds width.
  • Documentation

    • Expanded guidance on submitType options and newline behavior, updated keyboard-shortcut references, and added dedicated info/tip blocks clarifying submission vs. newline rules.

✏️ Tip: You can customize this high-level summary in your review settings.

@coderabbitai
Copy link

coderabbitai bot commented Nov 25, 2025

Walkthrough

Docs clarify Sender single-line→multi-line switching and newline/submit shortcut rules. Keyboard handler refactor centralizes newline insertion (Ctrl+Enter/Shift+Enter support), moves newline processing before other key logic, and streamlines submit checks.

Changes

Cohort / File(s) Summary
Documentation Updates
docs/src/components/sender.md
Clarified auto-switch condition (now triggered by content width). Added "提交与换行说明" describing the three submitType modes and newline behaviors. Updated 快捷键参考 table, added "换行快捷键说明" tip, and moved the multi-line switch note into the interaction section.
Keyboard handling refactor
packages/components/src/sender/composables/useKeyboardHandler.ts
Added insertNewLine(target) to insert newline at cursor and adjust scroll. Introduced handleNewLine(event) to handle Ctrl+Enter/Shift+Enter and conditional newline only when submitType === 'enter', using setMultipleMode when switching from single-line. Refactored handleKeyPress to delegate newline handling first and consolidated submit-checks (checkSubmitShortcut && canSubmit); retained navigation, suggestion, and escape logic after newline processing. Comments updated.

Sequence Diagram

sequenceDiagram
    participant User
    participant HandleKeyPress as HandleKeyPress
    participant HandleNewLine as HandleNewLine
    participant SetMultipleMode as SetMultipleMode
    participant InsertNewLine as InsertNewLine
    participant InputState as InputState

    User->>HandleKeyPress: keydown (Enter / Ctrl+Enter / Shift+Enter / other)
    Activate HandleKeyPress

    HandleKeyPress->>HandleNewLine: delegate newline handling
    Activate HandleNewLine

    alt submitType == "enter"
        alt Ctrl+Enter or Shift+Enter
            HandleNewLine->>SetMultipleMode: ensure multi-line mode if needed
            Activate SetMultipleMode
            SetMultipleMode->>InputState: update mode
            Deactivate SetMultipleMode

            HandleNewLine->>InsertNewLine: insert "\n" at cursor & adjust scroll
            Activate InsertNewLine
            InsertNewLine->>InputState: update value & cursor position
            Deactivate InsertNewLine

            HandleNewLine->>HandleKeyPress: preventDefault / stop propagation
        else if plain Enter (submit shortcut allowed)
            HandleNewLine->>HandleKeyPress: defer to submission path
        end
    end

    Deactivate HandleNewLine

    HandleKeyPress->>HandleKeyPress: run navigation, suggestion, escape, and submit checks
    alt submit conditions met
        HandleKeyPress->>InputState: triggerSubmit()
    end
    Deactivate HandleKeyPress
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

  • Verify cursor insertion and scroll behavior in insertNewLine.
  • Confirm setMultipleMode safely transitions UI state.
  • Ensure handleNewLine conditionals don't interfere with existing submit/navigation logic.
  • Check docs text matches implemented behavior.

Poem

🐰 I tap the keys and split the line,
Ctrl or Shift and newlines shine,
I hop to multi when space grows wide,
Cursor comfy, text inside,
Docs and code — a tidy sign.

Pre-merge checks and finishing touches

✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The PR title clearly summarizes the main feature: supporting Ctrl+Enter and Shift+Enter for newline insertion in the sender input component, which aligns with the primary changes in both the documentation and code.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

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 and usage tips.

@SonyLeo SonyLeo marked this pull request as ready for review November 25, 2025 02:44
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (2)
packages/components/src/sender/composables/useKeyboardHandler.ts (2)

87-100: Scroll behavior may be incorrect when inserting newline mid-content.

Line 98 sets scrollTop = scrollHeight, which scrolls to the bottom of the textarea. However, when the user inserts a newline in the middle of existing text, they likely want the view to remain at the cursor position, not jump to the bottom.

Consider using scrollIntoView behavior or calculating the proper scroll position based on cursor location:

   setTimeout(() => {
     target.selectionStart = target.selectionEnd = cursorPosition + 1
-    // 滚动到光标所在位置,确保光标可见
-    target.scrollTop = target.scrollHeight
+    // 确保光标可见(浏览器通常会自动处理光标可见性)
   }, 0)

Alternatively, if explicit scroll control is needed, consider a more precise calculation based on line height and cursor position.


107-138: Missing metaKey support for Cmd+Enter on macOS.

Line 111 checks event.ctrlKey && !event.shiftKey but doesn't account for metaKey. On macOS, users typically use Cmd instead of Ctrl. The checkSubmitShortcut function (line 75) handles metaKey for submissions, but handleNewLine doesn't, creating inconsistent behavior.

Additionally, the Ctrl+Enter and Shift+Enter branches (lines 119-126 and 128-135) contain duplicated logic.

  const handleNewLine = (event: KeyboardEvent): boolean => {
    // 只在 submitType='enter' 时支持 Ctrl+Enter 和 Shift+Enter 换行
    if (props.submitType !== 'enter' || event.key !== 'Enter') return false

-   const isCtrlEnter = event.ctrlKey && !event.shiftKey
+   const isCtrlEnter = (event.ctrlKey || event.metaKey) && !event.shiftKey
    const isShiftEnter = event.shiftKey && !event.ctrlKey

    if (!isCtrlEnter && !isShiftEnter) return false

    event.preventDefault()
    const target = event.target as HTMLTextAreaElement

-   // Ctrl+Enter: 单行模式切换到多行,多行模式直接换行
-   if (isCtrlEnter) {
-     if (currentMode?.value === 'single' && setMultipleMode) {
-       setMultipleMode()
-     }
-     insertNewLine(target)
-     return true
+   // 单行模式切换到多行,然后插入换行
+   if (currentMode?.value === 'single' && setMultipleMode) {
+     setMultipleMode()
    }
-
-   // Shift+Enter: 单行模式切换到多行,多行模式直接换行
-   if (isShiftEnter) {
-     if (currentMode?.value === 'single' && setMultipleMode) {
-       setMultipleMode()
-     }
-     insertNewLine(target)
-     return true
-   }
-
-   return false
+   insertNewLine(target)
+   return true
  }
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between b775495 and f55d7f0.

📒 Files selected for processing (2)
  • docs/src/components/sender.md (2 hunks)
  • packages/components/src/sender/composables/useKeyboardHandler.ts (1 hunks)
🔇 Additional comments (5)
packages/components/src/sender/composables/useKeyboardHandler.ts (1)

143-149: LGTM!

The integration of handleNewLine at the beginning of handleKeyPress with early return is correct. This ensures newline shortcuts are processed before other handlers (suggestions, escape, submit) when submitType='enter'.

docs/src/components/sender.md (4)

20-24: LGTM!

The documentation clearly explains the auto-switch behavior in single-line mode, including both the content overflow trigger and the new Ctrl+Enter/Shift+Enter shortcuts when submitType="enter".


149-155: LGTM!

The info block provides a clear and accurate summary of the submit vs newline behavior for each submitType option, along with the auto-switch behavior in single-line mode.


162-163: Consider adding macOS keyboard shortcut clarification.

The shortcut table is accurate. If the suggested metaKey support is added in the code, consider clarifying that Cmd+Enter works as Ctrl+Enter on macOS for better cross-platform documentation.


168-174: LGTM!

The tip block provides helpful details about newline shortcuts, including the auto-switch behavior in single-line mode. This complements the info block well and gives users a complete understanding of keyboard interactions.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (1)
packages/components/src/sender/composables/useKeyboardHandler.ts (1)

132-185: Keyboard flow refactor looks good; consider simplifying canSubmit checks

The new handleKeyPress flow (IME guard → newline handling → suggestions → escape → submit shortcut) is clear and matches the documented shortcut rules. Delegating newline logic to handleNewLine and submit logic to checkSubmitShortcut/triggerSubmit is a nice cleanup.

Minor duplication: triggerSubmit already checks canSubmit.value, and Line 181 also guards on canSubmit.value. You can remove one of these guards so there’s a single source of truth for the “can submit” condition, e.g.:

-    if (checkSubmitShortcut(event, props.submitType as SubmitTrigger) && canSubmit.value) {
-      event.preventDefault()
-      triggerSubmit()
-    }
+    if (checkSubmitShortcut(event, props.submitType as SubmitTrigger)) {
+      event.preventDefault()
+      triggerSubmit()
+    }

(or drop the check inside triggerSubmit instead).

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between f55d7f0 and 1f97957.

📒 Files selected for processing (1)
  • packages/components/src/sender/composables/useKeyboardHandler.ts (2 hunks)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: e2e-tests
🔇 Additional comments (1)
packages/components/src/sender/composables/useKeyboardHandler.ts (1)

107-127: I'm unable to access the repository due to persistent cloning errors. However, I can analyze the review comment based on the information provided:

Verification inconclusive—repository access unavailable; concern remains theoretical without template inspection

The review comment raises a valid concern about potential DOM element stale references if mode switching replaces the underlying element. However, the concern is explicitly conditional ("If switching modes replaces the underlying DOM element") and the reviewer acknowledges that "If single/multiple modes always share the same textarea instance, this is fine as-is."

Without access to:

  • The Sender component template to verify if v-if conditionals swap elements between single/multiple modes
  • The setMultipleMode() implementation
  • The insertNewLine() function's interaction with setTimeout

I cannot definitively confirm or refute whether this is an actual issue or a theoretical edge case that does not occur in practice.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (1)
packages/components/src/sender/composables/useKeyboardHandler.ts (1)

109-129: Clarify modifier handling for newline shortcuts (Ctrl/Shift vs Meta/Alt)

handleNewLine treats only ctrlKey and shiftKey as meaningful, while metaKey/altKey are ignored here (and altKey is also ignored in checkSubmitShortcut). For consistency and to avoid surprises on different platforms, consider making the modifier intent explicit, e.g. by:

  • Explicitly ruling out metaKey/altKey in isCtrlEnter/isShiftEnter, and/or
  • Documenting that Alt/Command + Enter are intentionally not treated as newline shortcuts when submitType='enter'.

This is small, but it helps keep behavior predictable across OSes.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 1f97957 and ab501bd.

📒 Files selected for processing (1)
  • packages/components/src/sender/composables/useKeyboardHandler.ts (2 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
packages/components/src/sender/composables/useKeyboardHandler.ts (1)
packages/components/src/sender/index.type.ts (1)
  • SubmitTrigger (15-15)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: e2e-tests
🔇 Additional comments (2)
packages/components/src/sender/composables/useKeyboardHandler.ts (2)

84-102: insertNewLine now correctly respects selection range

Using selectionStart/selectionEnd and replacing the selected text with '\n' matches native textarea behavior; caret repositioning and scroll handling via setTimeout also look solid.


131-139: Verify Ctrl+Enter behavior when suggestions are visible

With newline handling moved ahead of suggestion logic, when submitType='enter' and suggestions are shown:

  • Plain Enter still accepts the active suggestion (default activeSuggestionKeys=['Enter','Tab']).
  • Ctrl+Enter/Shift+Enter now insert a newline via handleNewLine instead of accepting the suggestion (previously, modifiers were ignored and Enter typically accepted the suggestion).

If the intended UX is "only unmodified Enter accepts suggestions; Ctrl/Shift+Enter always mean newline in this mode", this is fine; otherwise, you may want to gate handleNewLine behind !showSuggestions.value or refine the suggestion key handling.

Also applies to: 183-186

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.

2 participants