KQ-1638 · HOVER/FORECAST
Hover Forecast
A trip board whose filter menus show what an option would remove before you choose it: resting on an option turns the cards it would drop into dashed ghosts that fade and lean aside about their foot, row by row down the grid on springs.snap, while the forecast count rolls on snap and the share meter glides on springs.glide; leaving the option springs them back, and committing exits the ghosts on the exit ease while the survivors glide into place. Arrow keys move through each menu previewing as they go, Enter or Space commits, Escape abandons, and the trip cards are one roving tab stop moved by arrows across the measured columns.
Open a filter to preview it. Arrow keys preview options, Enter applies, Escape keeps the current results. Arrow keys move between trips.
This week's trips
Waylight · 14–18 Oct
Showing all 12
12 trips · no filters
Install
One command — the source lands in your repo. Or copy it from the Code tab.
$ pnpm dlx shadcn@latest add @kinetiq/hover-forecast
Props
- ghostOpacity
- number
- default 0.3
- How faint a card the previewed option would remove becomes, 0–1.
- layout
- "cards" | "compact" | "rows"
- default "cards"
- Full trip cards with a route line, two-line compact cards, or one-line rows.
- motionScale
- number
- default 1
- Scales the ghosts' lean, their step aside and the stagger, 0–2; 0 keeps the fade only.
- records
- ForecastTrip[]
- default defaultForecastTrips
- The trips on the board.
- filters
- ForecastFilter[]
- default defaultForecastFilters
- The filter menus in bar order; each option carries a match(trip) predicate.
- value / defaultValue
- ForecastValue
- default {}
- The applied selection: filter id to option id, or null for any. Controlled or initial.
- onApply
- (value: ForecastValue, change: ForecastChange) => void
- default —
- Fires when an option is committed or the filters are reset, with the whole new selection.
- onPreview
- (preview: ForecastPreview | null) => void
- default —
- Fires when a preview starts, moves or ends, so results can be fetched ahead of the commit.
- forecast
- (value: ForecastValue) => number | Promise<number>
- default counts matching records
- The would-be total for a previewed selection; pending, zero and failed answers are each worded plainly.
- onOpen
- (trip: ForecastTrip) => void
- default —
- A trip card was opened (click or Enter).
- status
- "ready" | "loading" | "error"
- default "ready"
- Whether the trips have arrived: skeleton cards while loading, a retry when they failed.
- onRetry
- () => void
- default —
- Try again was pressed after the trips failed to load.
- title
- string
- default "This week's trips"
- The board's heading.
- subtitle
- string
- default "Waylight · 14–18 Oct"
- The line under the heading.
- noun
- { one: string; other: string }
- default { one: "trip", other: "trips" }
- What one record is called in counts and sentences.
- formatFare
- (fare: number) => string
- default whole dollars
- Prints a fare.
- label
- string
- default the title
- The board's accessible name.
- disabled
- boolean
- default false
- Read only: menus do not open and cards do not open.
- className
- string
- default —
- Classes for the surface; give it a height and the grid scrolls inside it.
| Prop | Type | Default | Description |
|---|---|---|---|
| ghostOpacity | number | 0.3 | How faint a card the previewed option would remove becomes, 0–1. |
| layout | "cards" | "compact" | "rows" | "cards" | Full trip cards with a route line, two-line compact cards, or one-line rows. |
| motionScale | number | 1 | Scales the ghosts' lean, their step aside and the stagger, 0–2; 0 keeps the fade only. |
| records | ForecastTrip[] | defaultForecastTrips | The trips on the board. |
| filters | ForecastFilter[] | defaultForecastFilters | The filter menus in bar order; each option carries a match(trip) predicate. |
| value / defaultValue | ForecastValue | {} | The applied selection: filter id to option id, or null for any. Controlled or initial. |
| onApply | (value: ForecastValue, change: ForecastChange) => void | — | Fires when an option is committed or the filters are reset, with the whole new selection. |
| onPreview | (preview: ForecastPreview | null) => void | — | Fires when a preview starts, moves or ends, so results can be fetched ahead of the commit. |
| forecast | (value: ForecastValue) => number | Promise<number> | counts matching records | The would-be total for a previewed selection; pending, zero and failed answers are each worded plainly. |
| onOpen | (trip: ForecastTrip) => void | — | A trip card was opened (click or Enter). |
| status | "ready" | "loading" | "error" | "ready" | Whether the trips have arrived: skeleton cards while loading, a retry when they failed. |
| onRetry | () => void | — | Try again was pressed after the trips failed to load. |
| title | string | "This week's trips" | The board's heading. |
| subtitle | string | "Waylight · 14–18 Oct" | The line under the heading. |
| noun | { one: string; other: string } | { one: "trip", other: "trips" } | What one record is called in counts and sentences. |
| formatFare | (fare: number) => string | whole dollars | Prints a fare. |
| label | string | the title | The board's accessible name. |
| disabled | boolean | false | Read only: menus do not open and cards do not open. |
| className | string | — | Classes for the surface; give it a height and the grid scrolls inside it. |