Context Compaction River
ns-ui/context-compaction-riverFreeComponent
Context compaction drawn as a meandering river: live turns are points on one curving channel, and a compacted run of turns necks off into a reopenable, re-injectable oxbow lake sitting 12px off the channel.
Live preview
live · rendered by the registry
Rendered by ns-ui on their own page — this is the component running, not a screenshot of it.Install it
npx shadcn@latest add https://design.helpmarq.com/r/context-compaction-river.jsonSource
1"use client";23import { useEffect, useId, useMemo, useRef, useState, type KeyboardEvent as ReactKeyboardEvent } from "react";45// OxbowTurn — the live conversation drawn as one meandering channel in a6// side rail. Every live turn is a point the channel passes through; the7// curve itself is decorative (aria-hidden SVG) and carries no information a8// screen reader needs, because the same facts live as plain text in a real9// list right below it ("Live context, N turns" / "Compacted: turns 3-9,10// summarized 2 minutes ago").11//12// When turns get folded into a summary, the component doesn't just drop a13// row — the compaction keeps its own place in the sequence, and the channel14// simply stops routing through it: the surviving points ease toward their15// new (tighter) spacing over ~300ms, which is what "the river gets shorter"16// looks like here, while the folded turns settle 12px off the channel as a17// closed oxbow-lake shape carrying a token-count chip. That chip is a real,18// focusable button (never aria-hidden) — opening it reveals the summary and19// a re-inject action in a role=menu popover. Re-inject animates the lake20// back onto the channel before the prop change actually removes it, so nothing21// is left to imagination between "click" and "the turns are back".22//23// The trigger is deliberately open-only (a second click does not close it —24// only Escape, an outside click, or choosing the menu item does). That is25// what keeps a synthetic "press" pass (which clicks the first control once,26// unconditionally) and a later scripted "open this" check from fighting over27// the same toggle.28//29// Positions are computed from each item's index in the full sequence (turn30// or compaction alike), so a compaction never needs its own bookkeeping of31// "where it used to be" — it already has a slot. Turn dots and the channel32// path animate via a direct rAF loop (setAttribute only, no React state on33// the hot path, sleeps once settled) exactly like this repo's other34// spring-driven diagrams. Everything else (the oxbow's 12px settle, its35// entrance/exit) is a plain CSS transform+opacity transition, which reduced36// motion turns off wholesale in favor of an instant fade-and-move.3738export type OxbowTurnEntry = {39 id: string;40 /** short label, e.g. a turn number — used to build "turns 3-9" range text */41 label: string;42};4344export type OxbowTurnItem =45 | { kind: "turn"; id: string; label: string; preview?: string }46 | {47 kind: "compaction";48// … truncated
Files it writes
More from ns-ui
All 228 items| Component | Registry | Kind | Access | Installs | Command |
|---|---|---|---|---|---|
| Accordion Latchaccordion-latch | ns-ui | Components | Free | no deps | |
| Approval Inline Diffapproval-inline-diff | ns-ui | Components | Free | no deps | |
| ASCII Engraving Contourascii-engraving-contour | ns-ui | Components | Free | no deps | |
| ASCII Globe Spinascii-globe-spin | ns-ui | Components | Free | no deps | |
| ASCII Torus Donutascii-torus-donut | ns-ui | Components | Free | no deps | |
| Autosave Ratchetautosave-ratchet | ns-ui | Components | Free | no deps | |
| Avatar Stack Flockavatar-stack-flock | ns-ui | Components | Free | no deps | |
| Background ASCII Ditherbackground-ascii-dither | ns-ui | Components | Free | no deps |
