KQ-1307 · REVIEW/THREAD

Review Thread

A draft under review with its discussions pinned in the margin at the height of the passages they are about: one layout pass places every card, the open one exactly on its passage, and when a card grows the cards beneath it glide out of its way. Hovering or focusing a passage or a card brightens the highlight and draws a leader along the passage's underline into the card, rebuilt each frame from the card's own position; replies land on snap, @-mentions complete from a list, and resolving folds the thread back into a one-line check with a dog-eared corner on glide while the check draws on flick. Up and Down walk the threads in reading order, Enter opens one, Escape closes the mention list and then the thread.

KQ-1307 · REVIEW/THREAD

Review of Checkout copy, v3

Waylight Pay · drafted by Mira Okonjo

3 open1 resolved

Paying with Waylight should feel like handing over cash: quick, certain and over before you notice. This draft rewrites every line a buyer reads between the basket and the receipt.

Payment step

The button reads Pay now (3 comments) until the card is checked, then shows the exact amount, so nobody presses a button whose total they have not seen. If a card is declined we say why in one sentence (1 comment) and keep everything they typed.

Saved cards come first, newest on top (resolved, 2 comments). A buyer can remove one from the same row without leaving checkout.

Receipt

The receipt arrives within a minute (2 comments) and names the store the way it appears on the bank statement, so a charge is never a mystery three weeks later.

3 open · 1 resolved · hover a passage

Install

One command — the source lands in your repo. Or copy it from the Code tab.

$ pnpm dlx shadcn@latest add @kinetiq/review-thread

Props

document
ReviewDocument
default defaultReviewDocument
The draft under review: a title, a meta line and its heading and paragraph blocks.
threads / defaultThreads
ReviewThreadData[]
default defaultReviewThreads
The discussions, each anchored to a quote inside one block, with its comments and resolved state. Controlled or uncontrolled.
onThreadsChange
(threads: ReviewThreadData[]) => void
default —
Fires from the reply or the resolve that changed the list, with the whole new list.
people
ReviewPerson[]
default defaultReviewPeople
Everyone who can write here: comment authors and the @-mention list.
me
string
default "mira"
The id of the person replying and resolving.
now
Date | number
default defaultReviewNow
The moment every comment is dated against; the component never reads the clock.
active / defaultActive
string | null
default null
The open thread, or null. Controlled or uncontrolled.
onActiveChange
(id: string | null) => void
default —
Fires when a press, a key or a resolve opens or closes a thread.
onReply
(threadId: string, comment: ReviewComment) => void
default —
A reply was sent, with the comment as stored.
onResolve
(threadId: string, resolved: boolean) => void
default —
A thread was resolved (true) or reopened (false).
onMention
(personId: string, threadId: string) => void
default —
A sent reply mentioned someone.
onRetry
() => void
default —
The Retry button of the error state.
leaders
"curve" | "elbow" | "off"
default "curve"
The line that joins a lit passage to its card: a curve, two rounded right angles, or none (the highlight still brightens).
resolve
"fold" | "tuck" | "off"
default "fold"
What resolving does: fold the thread to a one-line check in place, fold it and tuck it out of the rail behind a Resolved toggle, or no resolving at all.
density
"compact" | "cozy" | "roomy"
default "cozy"
Type size, card padding, avatar size and how many lines of a closed thread show.
highlight
string
default "var(--warn)"
The passages' highlight and leader colour, any CSS colour.
status
"ready" | "loading" | "error"
default "ready"
Loading draws the surface's skeleton; error offers Retry.
placeholder
string
default "Reply, or @ to mention"
The reply composer's placeholder.
label
string
default —
The region's accessible name. Defaults to “Review of” and the title.
sound
boolean
default false
Play a tick on opening and moving between threads and a pop on replying and resolving. Off unless asked for.
disabled
boolean
default false
Reads but does not reply, resolve or open.
className
string
default —
Classes for the root. The root is h-[560px] by default; pass a height to change it.