* Custom hook for managing JSON collapse state and computations. * * @param lines - Array of code lines * @param showCollapseColumn - Whether collapse functionality is enabled * @param language - Programming language for syntax detection * @returns Object containing collapse state and handlers
( lines: string[], showCollapseColumn: boolean, language: string )
| 335 | * @returns Object containing collapse state and handlers |
| 336 | */ |
| 337 | function useJsonCollapse( |
| 338 | lines: string[], |
| 339 | showCollapseColumn: boolean, |
| 340 | language: string |
| 341 | ): { |
| 342 | collapsedLines: Set<number> |
| 343 | collapsibleLines: Set<number> |
| 344 | collapsibleRegions: Map<number, CollapsibleRegion> |
| 345 | collapsedStringLines: Set<number> |
| 346 | visibleLineIndices: number[] |
| 347 | toggleCollapse: (lineIndex: number) => void |
| 348 | } { |
| 349 | const [collapsedLines, setCollapsedLines] = useState<Set<number>>(() => new Set()) |
| 350 | |
| 351 | const collapsibleRegions = useMemo(() => { |
| 352 | if (!showCollapseColumn || language !== 'json') return new Map<number, CollapsibleRegion>() |
| 353 | return findCollapsibleRegions(lines) |
| 354 | }, [lines, showCollapseColumn, language]) |
| 355 | |
| 356 | const collapsibleLines = useMemo(() => new Set(collapsibleRegions.keys()), [collapsibleRegions]) |
| 357 | |
| 358 | // Track which collapsed lines are string type (need truncation, not hiding) |
| 359 | const collapsedStringLines = useMemo(() => { |
| 360 | const stringLines = new Set<number>() |
| 361 | for (const lineIdx of collapsedLines) { |
| 362 | const region = collapsibleRegions.get(lineIdx) |
| 363 | if (region?.type === 'string') { |
| 364 | stringLines.add(lineIdx) |
| 365 | } |
| 366 | } |
| 367 | return stringLines |
| 368 | }, [collapsedLines, collapsibleRegions]) |
| 369 | |
| 370 | const visibleLineIndices = useMemo(() => { |
| 371 | if (!showCollapseColumn) { |
| 372 | return Array.from({ length: lines.length }, (_, i) => i) |
| 373 | } |
| 374 | return computeVisibleLineIndices(lines.length, collapsedLines, collapsibleRegions) |
| 375 | }, [lines.length, collapsedLines, collapsibleRegions, showCollapseColumn]) |
| 376 | |
| 377 | const toggleCollapse = useCallback((lineIndex: number) => { |
| 378 | setCollapsedLines((prev) => { |
| 379 | const next = new Set(prev) |
| 380 | if (next.has(lineIndex)) { |
| 381 | next.delete(lineIndex) |
| 382 | } else { |
| 383 | next.add(lineIndex) |
| 384 | } |
| 385 | return next |
| 386 | }) |
| 387 | }, []) |
| 388 | |
| 389 | return { |
| 390 | collapsedLines, |
| 391 | collapsibleLines, |
| 392 | collapsibleRegions, |
| 393 | collapsedStringLines, |
| 394 | visibleLineIndices, |
no test coverage detected