合并用户文本与AI建议的多行输入字段排版优化求助
嘿,我正在做一个把用户输入(userText)和AI生成建议(aiText)结合在一起的输入框,想要让它们看起来像是同一句话的一部分,哪怕用户还没接受AI的建议。
示意图:输入框内用户输入的文本后跟着AI建议,长文本时AI内容在输入框中间换行,显得很割裂
目前这个输入框是单行的,当aiText内容较长时,会在输入框中间尴尬地换行,看起来非常不连贯。理想状态是如果aiText需要换行,应该从输入组件的最左侧开始,而不是从userText结束的位置接着排。
当前实现代码:
<div onClick={focusContentEditable} className="relative flex justify-start items-start p-3 border border-border bg-[#FFFFFF] text-[#1F1F1F] dark:bg-[#2A2A40] dark:text-[#EAEAEA] focus-within:outline focus-within:outline-[#9462fd] cursor-text rounded-2xl text-left w-full h-20 mx-auto overflow-hidden" > {/* Placeholder */} {userText.trim() === "" && !isFocused && ( <span className="text-gray-400 text-xs">Ask me anything...</span> )} <div className="inline-flex items-baseline"> <span ref={contentEditableRef} className="text-xs border-0 outline-none whitespace-nowrap break-words inline-flex min-h-[20px] w-full" contentEditable={true} suppressContentEditableWarning={true} onInput={handleInput} onKeyDown={handleKeyDown} > {/* {userText} */} </span> <span className={`text-xs text-gray-400 dark:text-gray-600 transition-opacity whitespace-normal inline-flex duration-500 ${ aiText ? "opacity-100" : "opacity-0" }`} contentEditable={false} > {aiText.length > 0 && userText.trim() !== "" && <> {aiText}</>} </span> </div> </div>
遇到的问题:
- 输入框是单行设置,没有适配多行文本的换行逻辑
- 当
aiText内容较长时,会在输入框中间换行,破坏文本整体流畅性 - 希望输入框能根据内容自动增高,让
aiText换行时能从左侧边缘开始
我已经尝试过的方法:
- 使用
contentEditable实现动态文本输入 - 用
inline-flex容器包裹userText和aiText来保持对齐
期望达到的效果:
- 输入框能自动增高以支持多行文本
aiText如果放不下当前行,换行后从输入框左侧开始userText和aiText视觉上是同一句话的一部分
我的解决方案建议:
针对你的问题,核心是布局和换行规则的限制,调整几下样式就能解决:
1. 移除inline-flex的布局束缚
你现在用inline-flex把用户文本和AI文本绑在同一行内,这会导致AI文本换行时只能从当前位置继续。把外层的<div className="inline-flex items-baseline">改成<div className="block">,让两个span按照正常的文本流排列,这样AI文本就会在用户文本后自然换行,新行直接从输入框左侧开始。
2. 让输入框支持自动高度
把输入框的固定高度h-20改成min-h-[80px](可以根据你的需求调整最小高度),同时去掉overflow-hidden(或者改成overflow-y-auto,避免内容过多时溢出)。这样当内容增多,输入框会自动撑开高度。
3. 修复文本换行的样式
- 给用户输入的
contentEditable元素去掉whitespace-nowrap(这个属性会强制文本不换行,导致内容溢出),换成whitespace-pre-wrap或者保留break-words,确保文本能正常换行。 - 移除两个span上的
inline-flex类,改成inline或者直接去掉,让它们作为行内文本元素正常流动。
调整后的核心代码片段:
<div onClick={focusContentEditable} className="relative flex justify-start items-start p-3 border border-border bg-[#FFFFFF] text-[#1F1F1F] dark:bg-[#2A2A40] dark:text-[#EAEAEA] focus-within:outline focus-within:outline-[#9462fd] cursor-text rounded-2xl text-left w-full min-h-[80px] mx-auto overflow-y-auto" > {/* Placeholder */} {userText.trim() === "" && !isFocused && ( <span className="text-gray-400 text-xs">Ask me anything...</span> )} {/* 替换inline-flex为block */} <div className="block"> <span ref={contentEditableRef} className="text-xs border-0 outline-none break-words inline min-h-[20px]" contentEditable={true} suppressContentEditableWarning={true} onInput={handleInput} onKeyDown={handleKeyDown} > {/* {userText} */} </span> <span className={`text-xs text-gray-400 dark:text-gray-600 transition-opacity duration-500 ${ aiText ? "opacity-100" : "opacity-0" }`} contentEditable={false} > {aiText.length > 0 && userText.trim() !== "" && <> {aiText}</>} </span> </div> </div>
4. 优化交互体验
记得处理点击AI文本区域时的聚焦逻辑,让焦点自动跳到用户输入的末尾,这样用户可以直接继续输入,不用手动点击用户文本区域。你可以在focusContentEditable函数里调整光标位置:
const focusContentEditable = () => { const el = contentEditableRef.current; if (el) { el.focus(); // 将光标移动到文本末尾 const range = document.createRange(); const sel = window.getSelection(); range.selectNodeContents(el); range.collapse(false); sel.removeAllRanges(); sel.addRange(range); } };
这样调整后,输入框就能支持多行文本,AI文本换行时也会从左侧开始,视觉上和用户文本完全连贯啦!
备注:内容来源于stack exchange,提问作者Zethyst




