v0.3.3 bug fixes

This commit is contained in:
2026-03-09 15:39:42 -04:00
parent 31f61cc056
commit c192c4d7a1
8 changed files with 76 additions and 8 deletions

View File

@@ -12,6 +12,20 @@ function isEmojiOnly(str) {
return emojiRegex.test(str.trim());
}
// Convert raw mention syntax to display HTML for the input mirror overlay
function renderInputDisplay(raw) {
// Escape HTML special chars first
const escaped = raw
.replace(/&/g, '&')
.replace(/</g, '&lt;')
.replace(/>/g, '&gt;');
// Replace @[name](id) with bold @name span
return escaped.replace(/@\[([^\]]+)\]\(\d+\)/g,
(_, name) => `<strong class="mention-chip">@${name}</strong>`
);
}
export default function MessageInput({ group, replyTo, onCancelReply, onSend, onTyping }) {
const [text, setText] = useState('');
const [imageFile, setImageFile] = useState(null);
@@ -25,6 +39,7 @@ export default function MessageInput({ group, replyTo, onCancelReply, onSend, on
const [showAttachMenu, setShowAttachMenu] = useState(false);
const [showEmojiPicker, setShowEmojiPicker] = useState(false);
const inputRef = useRef(null);
const mirrorRef = useRef(null);
const typingTimer = useRef(null);
const wasTyping = useRef(false);
const mentionStart = useRef(-1);
@@ -94,8 +109,10 @@ export default function MessageInput({ group, replyTo, onCancelReply, onSend, on
el.style.height = 'auto';
const lineHeight = parseFloat(getComputedStyle(el).lineHeight);
const maxHeight = lineHeight * 5 + 20;
el.style.height = Math.min(el.scrollHeight, maxHeight) + 'px';
const newH = Math.min(el.scrollHeight, maxHeight) + 'px';
el.style.height = newH;
el.style.overflowY = el.scrollHeight > maxHeight ? 'auto' : 'hidden';
if (mirrorRef.current) mirrorRef.current.style.height = newH;
const cur = e.target.selectionStart;
const lastAt = val.lastIndexOf('@', cur - 1);
@@ -160,6 +177,7 @@ export default function MessageInput({ group, replyTo, onCancelReply, onSend, on
if (inputRef.current) {
inputRef.current.style.height = 'auto';
inputRef.current.style.overflowY = 'hidden';
if (mirrorRef.current) mirrorRef.current.style.height = 'auto';
}
// Tag emoji-only messages so they can be rendered large
@@ -334,10 +352,17 @@ export default function MessageInput({ group, replyTo, onCancelReply, onSend, on
)}
<div className="input-wrap">
{/* Mirror overlay renders formatted mention text over the transparent textarea */}
<div
ref={mirrorRef}
className="msg-input msg-input-mirror"
aria-hidden="true"
dangerouslySetInnerHTML={{ __html: renderInputDisplay(text) || '' }}
/>
<textarea
ref={inputRef}
className="msg-input"
placeholder={`Message ${group?.name || ''}...`}
className="msg-input msg-input-raw"
placeholder={!text ? `Message ${group?.name || ''}...` : ''}
value={text}
onChange={handleChange}
onKeyDown={handleKeyDown}