46 lines · 1.8 KB · TypeScript
RawDownload
import { useLayoutEffect, useState } from "react"; export function measureComposerMultilinePrompt(body: HTMLElement): boolean | null {  const editor = body.querySelector<HTMLElement>('[data-testid="composer-editor"]');  if (!editor || editor.clientWidth === 0) return null;   const bodyStyle = getComputedStyle(body);  const expandedWidth =    body.clientWidth -    Number.parseFloat(bodyStyle.paddingLeft) -    Number.parseFloat(bodyStyle.paddingRight);  const lineHeight = Number.parseFloat(getComputedStyle(editor).lineHeight);  const range = document.createRange();  range.selectNodeContents(editor);  const bounds = range.getBoundingClientRect();   // Measure content, not the editor's minimum height. While resting, the  // prompt is unwrapped: compare its width with the expanded row so that  // moving the actions inline cannot make collapse and expansion oscillate.  return bounds.height > lineHeight + 1 || bounds.width > expandedWidth + 1;} export function useComposerMultilinePrompt(body: HTMLElement | null): boolean {  const [isMultiline, setIsMultiline] = useState(false);   useLayoutEffect(() => {    if (!body) return;    const measure = () => {      const next = measureComposerMultilinePrompt(body);      if (next !== null) setIsMultiline(next);    };    measure();    const resizeObserver = new ResizeObserver(measure);    resizeObserver.observe(body);    const editor = body.querySelector<HTMLElement>('[data-testid="composer-editor"]');    if (editor) resizeObserver.observe(editor);    const mutationObserver = new MutationObserver(measure);    mutationObserver.observe(body, { childList: true, characterData: true, subtree: true });    return () => {      resizeObserver.disconnect();      mutationObserver.disconnect();    };  }, [body]);   return isMultiline;}