the claude code sourcemaps leaked march 31
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

at main 73 lines 3.0 kB view raw
1import { useCallback, useContext, useLayoutEffect, useRef } from 'react' 2import CursorDeclarationContext from '../components/CursorDeclarationContext.js' 3import type { DOMElement } from '../dom.js' 4 5/** 6 * Declares where the terminal cursor should be parked after each frame. 7 * 8 * Terminal emulators render IME preedit text at the physical cursor 9 * position, and screen readers / screen magnifiers track the native 10 * cursor — so parking it at the text input's caret makes CJK input 11 * appear inline and lets accessibility tools follow the input. 12 * 13 * Returns a ref callback to attach to the Box that contains the input. 14 * The declared (line, column) is interpreted relative to that Box's 15 * nodeCache rect (populated by renderNodeToOutput). 16 * 17 * Timing: Both ref attach and useLayoutEffect fire in React's layout 18 * phase — after resetAfterCommit calls scheduleRender. scheduleRender 19 * defers onRender via queueMicrotask, so onRender runs AFTER layout 20 * effects commit and reads the fresh declaration on the first frame 21 * (no one-keystroke lag). Test env uses onImmediateRender (synchronous, 22 * no microtask), so tests compensate by calling ink.onRender() 23 * explicitly after render. 24 */ 25export function useDeclaredCursor({ 26 line, 27 column, 28 active, 29}: { 30 line: number 31 column: number 32 active: boolean 33}): (element: DOMElement | null) => void { 34 const setCursorDeclaration = useContext(CursorDeclarationContext) 35 const nodeRef = useRef<DOMElement | null>(null) 36 37 const setNode = useCallback((node: DOMElement | null) => { 38 nodeRef.current = node 39 }, []) 40 41 // When active, set unconditionally. When inactive, clear conditionally 42 // (only if the currently-declared node is ours). The node-identity check 43 // handles two hazards: 44 // 1. A memo()ized active instance elsewhere (e.g. the search input in 45 // a memo'd Footer) doesn't re-render this commit — an inactive 46 // instance re-rendering here must not clobber it. 47 // 2. Sibling handoff (menu focus moving between list items) — when 48 // focus moves opposite to sibling order, the newly-inactive item's 49 // effect runs AFTER the newly-active item's set. Without the node 50 // check it would clobber. 51 // No dep array: must re-declare every commit so the active instance 52 // re-claims the declaration after another instance's unmount-cleanup or 53 // sibling handoff nulls it. 54 useLayoutEffect(() => { 55 const node = nodeRef.current 56 if (active && node) { 57 setCursorDeclaration({ relativeX: column, relativeY: line, node }) 58 } else { 59 setCursorDeclaration(null, node) 60 } 61 }) 62 63 // Clear on unmount (conditionally — another instance may own by then). 64 // Separate effect with empty deps so cleanup only fires once — not on 65 // every line/column change, which would transiently null between commits. 66 useLayoutEffect(() => { 67 return () => { 68 setCursorDeclaration(null, nodeRef.current) 69 } 70 }, [setCursorDeclaration]) 71 72 return setNode 73}