fix: resolve mobile chat input freeze and multiline attachment button alignment#9202
fix: resolve mobile chat input freeze and multiline attachment button alignment#9202leafliber wants to merge 3 commits into
Conversation
The autoResize() function in ChatInput.vue used minHeight + 8 as the threshold to decide whether to switch from multi-line (textarea) back to single-line (input). On mobile viewports (max-width: 768px), the textarea's 2-line scrollHeight is below minHeight + 8 due to smaller line-height and padding, causing an infinite oscillation loop between <input> and <textarea> that freezes the browser. Fix: compute the actual single-line content height from getComputedStyle (line-height + vertical padding) and use that as the wrapping threshold instead of the hardcoded minHeight + 8 offset. Also temporarily set min-height to 0 during scrollHeight measurement to avoid the CSS min-height: 52px inflating the value.
The mobile multiline grid used a 2-column layout (1fr auto) with 'left right' areas, causing the left actions area to span the full remaining width and centering the + button via justify-content: center. Switch to the same 3-column layout (auto 1fr auto) with 'left . right' areas used on desktop, so the + button sits at the left edge.
There was a problem hiding this comment.
Hey - I've left some high level feedback:
- The
0.5threshold in the multiline detection condition feels like a magic number; consider either documenting why this margin is needed or deriving it from a clearer constant so future maintainers understand the intent. - Temporarily forcing
minHeightto0for measurement could interact unexpectedly if other logic or styles depend onmin-height; it may be safer to cache the previous value and restore it explicitly rather than assigning an empty string. - When
getComputedStylereturns non-numeric values (e.g.,line-height: normal),shouldUseMultilinedefaults totrue; if possible, consider a fallback estimation of single-line height instead of always switching to multiline to avoid unnecessary layout changes on some browsers.
Prompt for AI Agents
Please address the comments from this code review:
## Overall Comments
- The `0.5` threshold in the multiline detection condition feels like a magic number; consider either documenting why this margin is needed or deriving it from a clearer constant so future maintainers understand the intent.
- Temporarily forcing `minHeight` to `0` for measurement could interact unexpectedly if other logic or styles depend on `min-height`; it may be safer to cache the previous value and restore it explicitly rather than assigning an empty string.
- When `getComputedStyle` returns non-numeric values (e.g., `line-height: normal`), `shouldUseMultiline` defaults to `true`; if possible, consider a fallback estimation of single-line height instead of always switching to multiline to avoid unnecessary layout changes on some browsers.Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.
There was a problem hiding this comment.
Code Review
This pull request refactors the auto-resize logic of the chat input component to dynamically measure line height and vertical padding, and adjusts the CSS grid layout for the multiline composer row. The review feedback points out that setting el.style.minHeight = "0" will fail to override CSS rules marked with !important, and that a line-height of normal will resolve to NaN, preventing the input from shrinking back to a single line. A robust fallback calculation and the use of setProperty with important are suggested to resolve these issues.
Important
The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.
| el.style.minHeight = "0"; | ||
| const measuredHeight = el.scrollHeight; | ||
| el.style.minHeight = ""; | ||
| const computed = getComputedStyle(el); | ||
| const lineHeight = parseFloat(computed.lineHeight); | ||
| const paddingVertical = | ||
| parseFloat(computed.paddingTop) + parseFloat(computed.paddingBottom); | ||
| const canMeasure = | ||
| Number.isFinite(lineHeight) && Number.isFinite(paddingVertical); | ||
| const shouldUseMultiline = | ||
| localPrompt.value.includes("\n") || measuredHeight > minHeight + 8; | ||
| localPrompt.value.includes("\n") || | ||
| (canMeasure ? measuredHeight > lineHeight + paddingVertical + 0.5 : true); |
There was a problem hiding this comment.
问题分析
-
el.style.minHeight = "0"无法覆盖!important样式
在 CSS 中,.chat-textarea和.chat-text-input都设置了min-height: 52px !important;。在 JavaScript 中,直接通过el.style.minHeight = "0"设置的是普通优先级的内联样式,无法覆盖带有!important的样式表规则。因此,浏览器在测量scrollHeight时依然会强制应用52px的最小高度,导致测量值不准确。
解决方案:使用el.style.setProperty("min-height", "0", "important")来强制覆盖,并在测量后使用el.style.removeProperty("min-height")恢复。 -
更健壮的
lineHeight和paddingVertical计算
如果line-height计算结果为"normal",parseFloat会返回NaN。虽然代码中处理了canMeasure,但如果canMeasure为false,shouldUseMultiline会一直为true,导致输入框无法缩回单行。
解决方案:在lineHeight为NaN时,通过fontSize * 1.2计算一个合理的兜底值,并对paddingVertical进行兜底(使用|| 0),从而确保shouldUseMultiline始终能被准确计算,避免无法缩回单行的问题。
el.style.setProperty("min-height", "0", "important");
const measuredHeight = el.scrollHeight;
el.style.removeProperty("min-height");
const computed = getComputedStyle(el);
let lineHeight = parseFloat(computed.lineHeight);
if (!Number.isFinite(lineHeight)) {
const fontSize = parseFloat(computed.fontSize);
lineHeight = Number.isFinite(fontSize) ? fontSize * 1.2 : 20;
}
const paddingVertical =
(parseFloat(computed.paddingTop) || 0) + (parseFloat(computed.paddingBottom) || 0);
const shouldUseMultiline =
localPrompt.value.includes("\n") ||
measuredHeight > lineHeight + paddingVertical + 0.5;
…ement
el.style.minHeight = '0' cannot override the CSS min-height: 52px
!important rule, leaving scrollHeight inflated and preventing the
textarea from switching back to single-line for short text.
Use setProperty('min-height', '0', 'important') to force the override,
and removeProperty to restore. Also add a fontSize * 1.2 fallback when
getComputedStyle returns 'normal' for line-height, so the threshold is
always computable.
Modifications / 改动点
Fixes: #9181
文件:dashboard/src/components/chat/ChatInput.vue
将硬编码的 minHeight + 8 阈值替换为通过 getComputedStyle() 动态计算的单行内容高度(line-height + 上下 padding),能正确检测文本是否换行,不受视口相关 CSS 值的影响。
测量 scrollHeight 前临时设置 min-height: 0,避免 CSS min-height: 52px !important 抬高测量值。
当 getComputedStyle 返回非数值(如 line-height: normal)时,默认 shouldUseMultiline = true 作为安全回退,避免振荡。
将移动端多行 grid 布局从两列 minmax(0, 1fr) auto("left right")改为三列 auto minmax(0, 1fr) auto("left . right"),与桌面端一致,使 + 按钮靠左显示。
Screenshots or Test Results / 运行截图或测试结果
Checklist / 检查清单
😊 If there are new features added in the PR, I have discussed it with the authors through issues/emails, etc.
/ 如果 PR 中有新加入的功能,已经通过 Issue / 邮件等方式和作者讨论过。
👀 My changes have been well-tested, and "Verification Steps" and "Screenshots" have been provided above.
/ 我的更改经过了良好的测试,并已在上方提供了“验证步骤”和“运行截图”。
🤓 I have ensured that no new dependencies are introduced, OR if new dependencies are introduced, they have been added to the appropriate locations in
requirements.txtandpyproject.toml./ 我确保没有引入新依赖库,或者引入了新依赖库的同时将其添加到
requirements.txt和pyproject.toml文件相应位置。😮 My changes do not introduce malicious code.
/ 我的更改没有引入恶意代码。