import { useEffect, useRef, useState } from 'react' import { createPortal } from 'react-dom' import './ClampText.css' /** * Splits a block of AI prose into a finding and its working. * * The employees write the conclusion first and the evidence after it — * "POSP-77341 is active and empanelled for motor." then four sentences of * registry detail. So the first sentence already IS the summary, and lifting it * out gives one without inventing text or asking the model for a second field * it would have to be trusted to keep in step with the first. * * Returns null when the split would be useless: no sentence terminator, a first * sentence so long it is the paragraph again, or one so short it is a fragment * rather than a finding. Those fall back to plain folding. */ function splitLead(value) { const m = value.match(/^(.{40,220}?[.!?])(\s+)(\S[\s\S]*)$/) if (!m) return null return { lead: m[1].trim(), rest: m[3].trim() } } /** * The full text, in a dialog. * * The reasoning used to expand INLINE, and in the audit rail — 320px wide, one * entry per step — a 1,500-character rationale pushed the rest of the lead's * history off the screen to read one sentence of it. Nobody reads a paragraph * in a sidebar. It opens over the page instead: the finding stays on the line, * the working is one click away and one Escape back. */ function ProseDialog({ title, lead, body, onClose }) { const ref = useRef(null) const restore = useRef(null) useEffect(() => { restore.current = document.activeElement ref.current?.focus() const onKey = (e) => { if (e.key === 'Escape') onClose() } document.addEventListener('keydown', onKey) // The page behind must not scroll under the dialog. const prev = document.body.style.overflow document.body.style.overflow = 'hidden' return () => { document.removeEventListener('keydown', onKey) document.body.style.overflow = prev // Focus goes back to the button that opened this, not to the top of the // document — otherwise a keyboard reader loses their place in the trail. if (restore.current instanceof HTMLElement) restore.current.focus() } }, [onClose]) return createPortal(
{lead}
: null} {body.split(/\n{2,}/).map((para, i) =>{para}
)}{value}
const split = splitLead(value) return ({split.lead}
:{value}
} {open ? (