KQ-1697 · GOAL/WEAVE
Goal Weave
A goal-selection step whose plan assembles itself: choosing a goal draws a thread out of its card to each of its tasks — the curve split at a growing t on an enter tween, every point rounded — while the tasks arrive from 8px left on springs.glide in a cascade(), and removing a goal retracts its threads and pulls out only the tasks no other goal holds while shared ones stay. The goal cards are checkboxes that lift on springs.snap and follow the arrow keys; plan rows rove with Up and Down, Alt with Up or Down (or a drag of the grip, 1:1 with the release velocity handed to springs.glide) reorders them, and the threads follow every glide from a geometry loop that runs only while something moves.
Set up your workspace
Pick your goals; the plan assembles itself
Up and Down move between tasks; Alt with Up or Down moves a task.
2 goals · 6 tasks · 1 shared
Install
One command — the source lands in your repo. Or copy it from the Code tab.
$ pnpm dlx shadcn@latest add @kinetiq/goal-weave
Props
- goals
- GoalWeaveGoal[]
- default defaultGoalWeaveGoals
- The goals to choose from, { id, title, detail?, icon?, tint? }.
- tasks
- GoalWeaveTask[]
- default defaultGoalWeaveTasks
- Every task a goal can bring, { id, title, minutes?, goals, starter? }; a task in several goals is shared, and starter tasks form the plan while nothing is chosen.
- value / defaultValue
- string[]
- default — / []
- The chosen goal ids, controlled or initial. A host change weaves like a press.
- onGoalsChange
- (ids: string[]) => void
- default —
- Fires from the card, key or click that changed the goals.
- onPlanChange
- (taskIds: string[]) => void
- default —
- Fires with the plan in order whenever goals or a reorder change it.
- onAccept
- (taskIds: string[], goalIds: string[]) => void
- default —
- Use this plan was pressed.
- cardStyle
- "tile" | "chip" | "row"
- default "tile"
- Two-column tiles with icon, title and detail; compact wrapping chips; or a list of rows with task counts.
- threadStyle
- "thread" | "stitch" | "ribbon"
- default "thread"
- A fine 1.5px curve, a dashed stitch, or a soft 6px ribbon.
- accent
- string
- default "var(--accent-bright)"
- The first goal's tint (later goals turn its hue 48° each), the chosen cards and the primary button. Any CSS colour.
- question
- string
- default "What should Fernworks help with?"
- The question over the goal cards; it also names the checkbox group.
- planTitle
- string
- default "Your first week"
- The plan's heading (and the drawer's label on narrow widths).
- acceptLabel
- string
- default "Use this plan"
- The primary button's label.
- maxGoals
- number
- default —
- The most goals that can be chosen at once; the rest turn aria-disabled with the reason.
- status
- "ready" | "loading" | "error"
- default "ready"
- Whether the goals have arrived: loading draws skeleton cards, error a message with Try again.
- onRetry
- () => void
- default —
- Try again was pressed after the goals failed to load.
- maxHeight
- number
- default 560
- The tallest the step grows before its body scrolls, px.
- disabled
- boolean
- default false
- Nothing can be chosen, moved or accepted; the step dims.
- className
- string
- default —
- Classes for the outer section.
| Prop | Type | Default | Description |
|---|---|---|---|
| goals | GoalWeaveGoal[] | defaultGoalWeaveGoals | The goals to choose from, { id, title, detail?, icon?, tint? }. |
| tasks | GoalWeaveTask[] | defaultGoalWeaveTasks | Every task a goal can bring, { id, title, minutes?, goals, starter? }; a task in several goals is shared, and starter tasks form the plan while nothing is chosen. |
| value / defaultValue | string[] | — / [] | The chosen goal ids, controlled or initial. A host change weaves like a press. |
| onGoalsChange | (ids: string[]) => void | — | Fires from the card, key or click that changed the goals. |
| onPlanChange | (taskIds: string[]) => void | — | Fires with the plan in order whenever goals or a reorder change it. |
| onAccept | (taskIds: string[], goalIds: string[]) => void | — | Use this plan was pressed. |
| cardStyle | "tile" | "chip" | "row" | "tile" | Two-column tiles with icon, title and detail; compact wrapping chips; or a list of rows with task counts. |
| threadStyle | "thread" | "stitch" | "ribbon" | "thread" | A fine 1.5px curve, a dashed stitch, or a soft 6px ribbon. |
| accent | string | "var(--accent-bright)" | The first goal's tint (later goals turn its hue 48° each), the chosen cards and the primary button. Any CSS colour. |
| question | string | "What should Fernworks help with?" | The question over the goal cards; it also names the checkbox group. |
| planTitle | string | "Your first week" | The plan's heading (and the drawer's label on narrow widths). |
| acceptLabel | string | "Use this plan" | The primary button's label. |
| maxGoals | number | — | The most goals that can be chosen at once; the rest turn aria-disabled with the reason. |
| status | "ready" | "loading" | "error" | "ready" | Whether the goals have arrived: loading draws skeleton cards, error a message with Try again. |
| onRetry | () => void | — | Try again was pressed after the goals failed to load. |
| maxHeight | number | 560 | The tallest the step grows before its body scrolls, px. |
| disabled | boolean | false | Nothing can be chosen, moved or accepted; the step dims. |
| className | string | — | Classes for the outer section. |