KQ-1758 · BUG/SNAPSHOT
Bug Snapshot
A bug report that starts from the page it is about: Report a bug flashes the page (or closes a shutter on it, or lifts it toward you), then a copy of the page shrinks along a straight path into the form's thumbnail slot on springs.glide and drops into it on springs.recoil while the form's sections rise into place in cascade order. A drag on the thumbnail draws a highlight or an opaque redaction from the press point, the signed-in address is hidden on its own, environment rows can be removed and restored, and Send becomes its own progress bar that follows the host's progress on glide; a failed upload keeps every word, box and choice. Every box is a button that arrow keys move and Alt with an arrow resizes, Add box draws one from the keyboard, and the category and severity are radiogroups with roving focus.
Arrow keys move the box, Shift moves it further, Alt with an arrow resizes it, Delete removes it.
page · usage report
Install
One command — the source lands in your repo. Or copy it from the Code tab.
$ pnpm dlx shadcn@latest add @kinetiq/bug-snapshot
Props
- page
- ReactNode
- default <BasinworksUsagePage />
- The page the capture shows, drawn into a 16:10 frame: an <svg viewBox> or an element that fills its box.
- pageLabel
- string
- default "Basinworks · Usage report"
- Names the page in the frame's bar and the report header.
- sensitiveAreas
- BugBox[]
- default defaultBugSensitiveAreas
- Areas redacted automatically on every capture, as { id, kind, x, y, w, h } in percent of the page.
- environment
- BugEnvironmentItem[]
- default defaultBugEnvironment
- Environment rows sent with the report as { id, label, value }; each can be removed and restored.
- categories
- BugCategory[]
- default defaultBugCategories
- The kinds of problem offered, as { id, label }.
- severities
- BugSeverity[]
- default defaultBugSeverities
- Severity steps, mildest first, as { id, label, tone? } with tone neutral, accent, warn or danger.
- defaultDraft
- Partial<BugDraft>
- default —
- The draft the form starts from: { category, severity, happened, expected }. Defaults to the first category and medium severity.
- onDraftChange
- (draft: BugDraft) => void
- default —
- Fires with the whole draft whenever a field, category or severity changes.
- open / defaultOpen
- boolean
- default — / false
- Whether the report is open, controlled or initial. Opening captures the page.
- onOpenChange
- (open: boolean) => void
- default —
- Fires from the button that opened or closed the report.
- onCapture
- () => void
- default —
- A capture has landed in the form (on open and on Retake).
- onRedact
- (redactions: BugBox[]) => void
- default —
- Fires with every redaction box after one is added, moved or removed, and after a capture.
- onSubmit
- (report: BugReport, progress: (fraction: number) => void) => void | Promise<unknown>
- default —
- Send was pressed with a valid report. Return a promise to show the upload and call progress(0–1) to drive the bar; a rejection keeps the draft, a resolved string is shown as the reference.
- captureStyle
- "flash" | "shutter" | "lift"
- default "flash"
- How the capture announces itself: a white flash, an ink shutter closing and opening, or the page lifting toward you before it shrinks.
- density
- "compact" | "regular" | "roomy"
- default "regular"
- Control height (28, 32 or 36px), padding, type size and gaps.
- highlightColor
- string
- default "var(--warn)"
- Highlight strokes, washes, numbered badges and the landing flash — any CSS colour.
- maxHeight
- number
- default 540
- Tallest the surface grows before the report scrolls inside it, in px. The page frame is capped to fit it.
- status
- "ready" | "loading" | "error"
- default "ready"
- Whether the environment details have been read: loading shows skeleton rows, error a line with Try again.
- onRetry
- () => void
- default —
- Try again was pressed after the environment failed to read.
- title
- string
- default "Report a bug"
- The report's heading and the surface's accessible name.
- disabled
- boolean
- default false
- Nothing can be opened, drawn or sent.
- className
- string
- default —
- Classes for the surface.
| Prop | Type | Default | Description |
|---|---|---|---|
| page | ReactNode | <BasinworksUsagePage /> | The page the capture shows, drawn into a 16:10 frame: an <svg viewBox> or an element that fills its box. |
| pageLabel | string | "Basinworks · Usage report" | Names the page in the frame's bar and the report header. |
| sensitiveAreas | BugBox[] | defaultBugSensitiveAreas | Areas redacted automatically on every capture, as { id, kind, x, y, w, h } in percent of the page. |
| environment | BugEnvironmentItem[] | defaultBugEnvironment | Environment rows sent with the report as { id, label, value }; each can be removed and restored. |
| categories | BugCategory[] | defaultBugCategories | The kinds of problem offered, as { id, label }. |
| severities | BugSeverity[] | defaultBugSeverities | Severity steps, mildest first, as { id, label, tone? } with tone neutral, accent, warn or danger. |
| defaultDraft | Partial<BugDraft> | — | The draft the form starts from: { category, severity, happened, expected }. Defaults to the first category and medium severity. |
| onDraftChange | (draft: BugDraft) => void | — | Fires with the whole draft whenever a field, category or severity changes. |
| open / defaultOpen | boolean | — / false | Whether the report is open, controlled or initial. Opening captures the page. |
| onOpenChange | (open: boolean) => void | — | Fires from the button that opened or closed the report. |
| onCapture | () => void | — | A capture has landed in the form (on open and on Retake). |
| onRedact | (redactions: BugBox[]) => void | — | Fires with every redaction box after one is added, moved or removed, and after a capture. |
| onSubmit | (report: BugReport, progress: (fraction: number) => void) => void | Promise<unknown> | — | Send was pressed with a valid report. Return a promise to show the upload and call progress(0–1) to drive the bar; a rejection keeps the draft, a resolved string is shown as the reference. |
| captureStyle | "flash" | "shutter" | "lift" | "flash" | How the capture announces itself: a white flash, an ink shutter closing and opening, or the page lifting toward you before it shrinks. |
| density | "compact" | "regular" | "roomy" | "regular" | Control height (28, 32 or 36px), padding, type size and gaps. |
| highlightColor | string | "var(--warn)" | Highlight strokes, washes, numbered badges and the landing flash — any CSS colour. |
| maxHeight | number | 540 | Tallest the surface grows before the report scrolls inside it, in px. The page frame is capped to fit it. |
| status | "ready" | "loading" | "error" | "ready" | Whether the environment details have been read: loading shows skeleton rows, error a line with Try again. |
| onRetry | () => void | — | Try again was pressed after the environment failed to read. |
| title | string | "Report a bug" | The report's heading and the surface's accessible name. |
| disabled | boolean | false | Nothing can be opened, drawn or sent. |
| className | string | — | Classes for the surface. |