| 1 | import { useLayoutEffect, useState } from "react"; |
| 2 | import { observeResize } from "../../lib/observeResize"; |
| 3 | |
| 4 | export function measureComposerMultilinePrompt(body: HTMLElement): boolean | null { |
| 5 | const editor = body.querySelector<HTMLElement>('[data-testid="composer-editor"]'); |
| 6 | if (!editor || editor.clientWidth === 0) return null; |
| 7 | |
| 8 | const bodyStyle = getComputedStyle(body); |
| 9 | const expandedWidth = |
| 10 | body.clientWidth - |
| 11 | Number.parseFloat(bodyStyle.paddingLeft) - |
| 12 | Number.parseFloat(bodyStyle.paddingRight); |
| 13 | const lineHeight = Number.parseFloat(getComputedStyle(editor).lineHeight); |
| 14 | const range = document.createRange(); |
| 15 | range.selectNodeContents(editor); |
| 16 | const bounds = range.getBoundingClientRect(); |
| 17 | |
| 18 | // Measure content, not the editor's minimum height. While resting, the |
| 19 | // prompt is unwrapped: compare its width with the expanded row so that |
| 20 | // moving the actions inline cannot make collapse and expansion oscillate. |
| 21 | return bounds.height > lineHeight + 1 || bounds.width > expandedWidth + 1; |
| 22 | } |
| 23 | |
| 24 | export function useComposerMultilinePrompt(body: HTMLElement | null): boolean { |
| 25 | const [isMultiline, setIsMultiline] = useState(false); |
| 26 | |
| 27 | useLayoutEffect(() => { |
| 28 | if (!body) return; |
| 29 | const measure = () => { |
| 30 | const next = measureComposerMultilinePrompt(body); |
| 31 | if (next !== null) setIsMultiline(next); |
| 32 | }; |
| 33 | measure(); |
| 34 | const editor = body.querySelector<HTMLElement>('[data-testid="composer-editor"]'); |
| 35 | const stopObserving = observeResize(editor ? [body, editor] : body, measure); |
| 36 | const mutationObserver = new MutationObserver(measure); |
| 37 | mutationObserver.observe(body, { childList: true, characterData: true, subtree: true }); |
| 38 | return () => { |
| 39 | stopObserving(); |
| 40 | mutationObserver.disconnect(); |
| 41 | }; |
| 42 | }, [body]); |
| 43 | |
| 44 | return isMultiline; |
| 45 | } |