Skip to content

fix: resolve mobile chat input freeze and multiline attachment button alignment#9202

Open
leafliber wants to merge 3 commits into
AstrBotDevs:masterfrom
leafliber:fix/chat-input-mobile-oscillation
Open

fix: resolve mobile chat input freeze and multiline attachment button alignment#9202
leafliber wants to merge 3 commits into
AstrBotDevs:masterfrom
leafliber:fix/chat-input-mobile-oscillation

Conversation

@leafliber

@leafliber leafliber commented Jul 10, 2026

Copy link
Copy Markdown
Contributor

Modifications / 改动点

Fixes: #9181

文件:dashboard/src/components/chat/ChatInput.vue

  1. 修复 autoResize() 无限振荡循环
    将硬编码的 minHeight + 8 阈值替换为通过 getComputedStyle() 动态计算的单行内容高度(line-height + 上下 padding),能正确检测文本是否换行,不受视口相关 CSS 值的影响。
    测量 scrollHeight 前临时设置 min-height: 0,避免 CSS min-height: 52px !important 抬高测量值。
    当 getComputedStyle 返回非数值(如 line-height: normal)时,默认 shouldUseMultiline = true 作为安全回退,避免振荡。
  2. 修复移动端多行附件按钮对齐
    将移动端多行 grid 布局从两列 minmax(0, 1fr) auto("left right")改为三列 auto minmax(0, 1fr) auto("left . right"),与桌面端一致,使 + 按钮靠左显示。
  • This is NOT a breaking change. / 这不是一个破坏性变更。

Screenshots or Test Results / 运行截图或测试结果

image

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.txt and pyproject.toml.
    / 我确保没有引入新依赖库,或者引入了新依赖库的同时将其添加到 requirements.txtpyproject.toml 文件相应位置。

  • 😮 My changes do not introduce malicious code.
    / 我的更改没有引入恶意代码。

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.
@dosubot dosubot Bot added size:S This PR changes 10-29 lines, ignoring generated files. area:webui The bug / feature is about webui(dashboard) of astrbot. feature:chatui The bug / feature is about astrbot's chatui, webchat labels Jul 10, 2026

@sourcery-ai sourcery-ai 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.

Hey - I've left some high level feedback:

  • 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.
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.

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

@gemini-code-assist gemini-code-assist 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.

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.

Comment on lines +659 to +670
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);

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.

high

问题分析

  1. 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") 恢复。

  2. 更健壮的 lineHeightpaddingVertical 计算
    如果 line-height 计算结果为 "normal"parseFloat 会返回 NaN。虽然代码中处理了 canMeasure,但如果 canMeasurefalseshouldUseMultiline 会一直为 true,导致输入框无法缩回单行。
    解决方案:在 lineHeightNaN 时,通过 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.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area:webui The bug / feature is about webui(dashboard) of astrbot. feature:chatui The bug / feature is about astrbot's chatui, webchat size:S This PR changes 10-29 lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug] 在移动端使用WebUI输入时,达到输入框视觉边界,浏览器和输入法都会崩溃

1 participant