Skip to content

Conversation

@yyhhyyyyyy
Copy link
Collaborator

@yyhhyyyyyy yyhhyyyyyy commented Sep 17, 2025

close #905
Currently, both Enter and Shift+Enter create a new line, while Command+Enter or Ctrl+Enter saves and sends.

Summary by CodeRabbit

  • New Features
    • Editing a message now uses an auto-resizing text box that grows with content up to a sensible maximum and then scrolls.
    • Save shortcut updated to Ctrl/Cmd + Enter (Enter inserts a new line); Esc still cancels.
    • Edit area adapts to window size changes for better responsiveness.
    • Editing starts with correctly sized input across all message types.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Sep 17, 2025

Walkthrough

Implements dynamic, auto-resizing edit textarea in MessageItemUser.vue with computed max height, window-resize handling, and refs for textarea. Adjusts keyboard shortcuts to save on Ctrl/Cmd+Enter and cancel on Esc. Initializes and updates sizing on edit start, input, text changes, and window resize; cleans up listeners on unmount.

Changes

Cohort / File(s) Change Summary
Message edit UX and sizing logic
src/renderer/src/components/message/MessageItemUser.vue
Added auto-resizing textarea with rows=1, editTextarea ref, editMaxHeight computed via container/window; autoResize adjusts height and overflow; computeEditMaxHeight derives bounds; listen to window resize with cleanup; nextTick-based sizing on edit start; watch editedText for resizing; changed save to Ctrl/Cmd+Enter, Esc cancels.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  actor User
  participant MessageItemUser as Component
  participant DOM as Textarea & Window

  User->>MessageItemUser: Click "Edit"
  activate MessageItemUser
  MessageItemUser->>DOM: computeEditMaxHeight()
  MessageItemUser->>DOM: autoResize(textarea)
  MessageItemUser-->>User: Edit mode shown

  User->>DOM: Input typing
  DOM-->>MessageItemUser: input event
  MessageItemUser->>DOM: autoResize(textarea)

  User->>MessageItemUser: Ctrl/Cmd+Enter
  MessageItemUser-->>User: Save and exit edit

  User->>MessageItemUser: Esc
  MessageItemUser-->>User: Cancel and exit edit

  DOM->>MessageItemUser: window resize
  MessageItemUser->>DOM: computeEditMaxHeight() + autoResize()

  deactivate MessageItemUser
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

  • Fixed: the edit mode not work good #596: Also adjusts MessageItemUser.vue edit-mode behavior (structured content handling, textarea sizing, and keypress save/cancel), overlapping with this PR’s textarea resize and shortcut logic.

Suggested reviewers

  • zerob13

Poem

A nibble of keys, a hop of height,
The textbox grows to fit just right.
Cmd+Enter—thump!—it’s saved with cheer,
Esc to vanish edits here.
Windows sigh, the bounds align—
A bunny’s UX, crisp and fine. 🐇✍️

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Description Check ⚠️ Warning The PR description is minimal and does not follow the repository's required template; it only includes "close #905" and a brief sentence about current keybindings. It lacks a clear problem statement, a description of the implemented solution, UI/UX details or screenshots, platform compatibility notes, and explicit testing or verification steps, and it may be ambiguous relative to the linked issue. As written, the description is insufficient for reviewers to fully validate the change. Please update the PR description to follow the repository template by adding a concise problem statement, a clear description of the implemented solution (including the new keybindings: Enter inserts newline, Ctrl/Cmd+Enter saves, Esc cancels), UI/UX notes and screenshots/GIFs if applicable, platform compatibility and test steps used to verify the fix, and explicitly state that this closes issue #905. Also note which platforms (macOS, Windows, Linux) were tested and include short manual test instructions or automated test references to help reviewers validate the change. These details will make review faster and reduce back-and-forth.
✅ Passed checks (4 passed)
Check name Status Explanation
Title Check ✅ Passed The title "fix: Enter inserts newline in edit mode" is concise and directly describes the primary user-facing change implemented by the patch, namely changing Enter behavior in message edit mode. It focuses on the core fix without extraneous detail and is clear enough for a teammate scanning commit history to understand the intent. Therefore the title accurately reflects the main change in MessageItemUser.vue.
Linked Issues Check ✅ Passed Based on the provided change summary, the patch implements an auto-resizing edit textarea, switches save to Ctrl/Cmd+Enter while keeping Esc to cancel, removes the early-return that prevented proper newline display, and adds resizing and height constraints tied to the message list container and window. Those code-level changes directly address the linked issue's objectives by allowing newline input during edit, preventing Enter/Shift+Enter from exiting edit state, and using an explicit save shortcut. Thus the changes satisfy the coding requirements of issue #905 pending verification on actual platforms and test coverage.
Out of Scope Changes Check ✅ Passed The provided diff summary shows changes confined to src/renderer/src/components/message/MessageItemUser.vue and focuses on edit-mode textarea behavior, autosizing, and keyboard handling; no other files or public API signatures were altered. All modifications appear directly related to the edit UX and the objectives of the linked issue. There is no evidence in the summary of unrelated or out-of-scope changes.
Docstring Coverage ✅ Passed No functions found in the changes. Docstring coverage check skipped.
✨ Finishing touches
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch fix/message-edit-enter-autosize

Tip

👮 Agentic pre-merge checks are now available in preview!

Pro plan users can now enable pre-merge checks in their settings to enforce checklists before merging PRs.

  • Built-in checks – Quickly apply ready-made checks to enforce title conventions, require pull request descriptions that follow templates, validate linked issues for compliance, and more.
  • Custom agentic checks – Define your own rules using CodeRabbit’s advanced agentic capabilities to enforce organization-specific policies and workflows. For example, you can instruct CodeRabbit’s agent to verify that API documentation is updated whenever API schema files are modified in a PR. Note: Upto 5 custom checks are currently allowed during the preview period. Pricing for this feature will be announced in a few weeks.

Please see the documentation for more information.

Example:

reviews:
  pre_merge_checks:
    custom_checks:
      - name: "Undocumented Breaking Changes"
        mode: "warning"
        instructions: |
          Pass/fail criteria: All breaking changes to public APIs, CLI flags, environment variables, configuration keys, database schemas, or HTTP/GraphQL endpoints must be documented in the "Breaking Change" section of the PR description and in CHANGELOG.md. Exclude purely internal or private changes (e.g., code not exported from package entry points or explicitly marked as internal).

Please share your feedback with us on this Discord post.


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.

Copy link
Contributor

@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 (7)
src/renderer/src/components/message/MessageItemUser.vue (7)

36-47: Avoid fixed inline width; it becomes stale on resize and conflicts with w-full

Pinning width to originalContentWidth + 20px can overflow after window resizes and fights Tailwind’s w-full. Prefer responsive width only; keep maxHeight logic.

Apply:

-            class="text-sm bg-[#EFF6FF] dark:bg-muted rounded-lg p-2 border flex flex-col gap-1.5 resize-none overflow-y-auto overscroll-contain min-w-[40vw] w-full"
+            class="text-sm bg-[#EFF6FF] dark:bg-muted rounded-lg p-2 border flex flex-col gap-1.5 resize-none overflow-y-auto overscroll-contain min-w-[40vw] w-full box-border"
             :style="{
-              width: originalContentWidth + 20 + 'px',
               maxHeight: editMaxHeight ? editMaxHeight + 'px' : undefined
             }"

Also, please verify no parent-level key handlers still react to Enter. If they do, stop propagation on plain Enter/Shift+Enter for the textarea.


153-158: Preserve paragraph boundaries when merging text blocks

Joining with '' can collapse paragraphs. Use a newline to keep intent.

Apply:

-    editedText.value = textBlocks.map((block) => block.content).join('')
+    editedText.value = textBlocks.map((block) => block.content).join('\n')

Please verify this matches how MessageContent renders multi-block text.


204-218: autoResize is solid; consider rAF to reduce layout thrash

Minor polish: schedule height calc in requestAnimationFrame to avoid sync reflow on fast input.

Apply:

-const autoResize = () => {
-  const el = editTextarea.value
-  if (!el) return
-  el.style.height = 'auto'
-  const computed = window.getComputedStyle(el)
-  const maxH = parseFloat(computed.maxHeight || '')
-  const scrollH = el.scrollHeight
-  const target = Number.isFinite(maxH) && maxH > 0 ? Math.min(scrollH, maxH) : scrollH
-  el.style.height = target + 'px'
-  if (scrollH > target) {
-    el.style.overflowY = 'auto'
-  } else {
-    el.style.overflowY = 'hidden'
-  }
-}
+const autoResize = () => {
+  const el = editTextarea.value
+  if (!el) return
+  requestAnimationFrame(() => {
+    el.style.height = 'auto'
+    const computed = window.getComputedStyle(el)
+    const maxH = parseFloat(computed.maxHeight || '')
+    const scrollH = el.scrollHeight
+    const target = Number.isFinite(maxH) && maxH > 0 ? Math.min(scrollH, maxH) : scrollH
+    el.style.height = target + 'px'
+    el.style.overflowY = scrollH > target ? 'auto' : 'hidden'
+  })
+}

224-228: Decouple from global selector if possible

Querying .message-list-container couples layout across components. Prefer measuring the textarea’s scroll parent (e.g., el.closest()) or accept an optional container element/height via prop/inject.


230-235: Register resize listener on mount for SSR-safety and symmetry

Move addEventListener into onMounted (you already remove it in onBeforeUnmount).

Apply:

 onMounted(() => {
   if (originalContent.value) {
     // eslint-disable-next-line @typescript-eslint/no-explicit-any
     originalContentHeight.value = (originalContent.value as any).offsetHeight
     // eslint-disable-next-line @typescript-eslint/no-explicit-any
     originalContentWidth.value = (originalContent.value as any).offsetWidth
   }
+  window.addEventListener('resize', handleWindowResize)
 })
 
- window.addEventListener('resize', handleWindowResize)
 onBeforeUnmount(() => {
   window.removeEventListener('resize', handleWindowResize)
 })

Also applies to: 237-240, 119-126


16-18: i18n: replace hardcoded 'user' fallback with a translation key

Renderer must use vue-i18n for user-visible strings.

Apply:

-        :name="message.name ?? 'user'"
+        :name="message.name ?? t('common.user')"

And in script:

+import { useI18n } from 'vue-i18n'
 ...
+const { t } = useI18n()

Please adjust the key path to match your i18n schema.


7-12: Comments should be in English per repo guidelines

Translate Chinese comments to English for consistency.

Also applies to: 60-72

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between d1416f6 and 99fe754.

📒 Files selected for processing (1)
  • src/renderer/src/components/message/MessageItemUser.vue (6 hunks)
🧰 Additional context used
📓 Path-based instructions (15)
src/renderer/src/**/*

📄 CodeRabbit inference engine (.cursor/rules/i18n.mdc)

src/renderer/src/**/*: All user-facing strings must use i18n keys (avoid hardcoded user-visible text in code)
Use the 'vue-i18n' framework for all internationalization in the renderer
Ensure all user-visible text in the renderer uses the translation system

Files:

  • src/renderer/src/components/message/MessageItemUser.vue
src/renderer/**/*.{vue,ts,js,tsx,jsx}

📄 CodeRabbit inference engine (.cursor/rules/project-structure.mdc)

渲染进程代码放在 src/renderer

Files:

  • src/renderer/src/components/message/MessageItemUser.vue
src/renderer/src/**/*.{vue,ts,tsx,js,jsx}

📄 CodeRabbit inference engine (.cursor/rules/vue-best-practices.mdc)

src/renderer/src/**/*.{vue,ts,tsx,js,jsx}: Use the Composition API for better code organization and reusability
Implement proper state management with Pinia
Utilize Vue Router for navigation and route management
Leverage Vue's built-in reactivity system for efficient data handling

Files:

  • src/renderer/src/components/message/MessageItemUser.vue
src/renderer/src/**/*.vue

📄 CodeRabbit inference engine (.cursor/rules/vue-best-practices.mdc)

Use scoped styles to prevent CSS conflicts between components

Files:

  • src/renderer/src/components/message/MessageItemUser.vue
src/renderer/**/*.{ts,tsx,vue}

📄 CodeRabbit inference engine (.cursor/rules/vue-shadcn.mdc)

src/renderer/**/*.{ts,tsx,vue}: Use descriptive variable names with auxiliary verbs (e.g., isLoading, hasError).
Use TypeScript for all code; prefer types over interfaces.
Avoid enums; use const objects instead.
Use arrow functions for methods and computed properties.
Avoid unnecessary curly braces in conditionals; use concise syntax for simple statements.

Files:

  • src/renderer/src/components/message/MessageItemUser.vue
src/renderer/**/*.{vue,ts}

📄 CodeRabbit inference engine (.cursor/rules/vue-shadcn.mdc)

Implement lazy loading for routes and components.

Files:

  • src/renderer/src/components/message/MessageItemUser.vue
src/renderer/**/*.{ts,vue}

📄 CodeRabbit inference engine (.cursor/rules/vue-shadcn.mdc)

src/renderer/**/*.{ts,vue}: Use useFetch and useAsyncData for data fetching.
Implement SEO best practices using Nuxt's useHead and useSeoMeta.

Use Pinia for frontend state management (do not introduce alternative state libraries)

Files:

  • src/renderer/src/components/message/MessageItemUser.vue
**/*.{ts,tsx,js,vue}

📄 CodeRabbit inference engine (CLAUDE.md)

Use English for all logs and comments

Files:

  • src/renderer/src/components/message/MessageItemUser.vue
**/*.{ts,tsx,vue}

📄 CodeRabbit inference engine (CLAUDE.md)

Enable and adhere to strict TypeScript typing (avoid implicit any, prefer precise types)

Files:

  • src/renderer/src/components/message/MessageItemUser.vue
src/renderer/{src,shell,floating}/**/*.vue

📄 CodeRabbit inference engine (CLAUDE.md)

src/renderer/{src,shell,floating}/**/*.vue: Use Vue 3 Composition API for all components
All user-facing strings must use i18n keys via vue-i18n (no hard-coded UI strings)
Use Tailwind CSS utilities and ensure styles are scoped in Vue components

Files:

  • src/renderer/src/components/message/MessageItemUser.vue
src/renderer/src/components/**/*

📄 CodeRabbit inference engine (CLAUDE.md)

Organize UI components by feature within src/renderer/src/

Files:

  • src/renderer/src/components/message/MessageItemUser.vue
src/renderer/src/**

📄 CodeRabbit inference engine (AGENTS.md)

Put application code for the Vue app under src/renderer/src (components, stores, views, i18n, lib)

Files:

  • src/renderer/src/components/message/MessageItemUser.vue
src/renderer/src/**/*.{vue,ts}

📄 CodeRabbit inference engine (AGENTS.md)

All user-facing strings in the renderer must use vue-i18n keys defined in src/renderer/src/i18n

Files:

  • src/renderer/src/components/message/MessageItemUser.vue
**/*.{js,jsx,ts,tsx,vue}

📄 CodeRabbit inference engine (AGENTS.md)

Apply Prettier formatting: single quotes, no semicolons, max width 100

Files:

  • src/renderer/src/components/message/MessageItemUser.vue
src/renderer/**/*.vue

📄 CodeRabbit inference engine (AGENTS.md)

Name Vue components in PascalCase (e.g., ChatInput.vue)

Files:

  • src/renderer/src/components/message/MessageItemUser.vue
⏰ 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: build-check (x64)
🔇 Additional comments (2)
src/renderer/src/components/message/MessageItemUser.vue (2)

114-116: Good: strongly typed refs for textarea and its constraints

These additions are correct and align with strict TS.


134-135: Correct: initialize sizing when entering edit mode

Computing max height and resizing on enter is appropriate.

@zerob13 zerob13 merged commit 0fbd881 into dev Sep 17, 2025
2 checks passed
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.

[bug] macOS: Can’t insert newline when editing message

3 participants