Proposal Card
Weigh a proposed change against the current plan, then approve or dismiss it: a reroute, a reassignment, a new slot.
import { ProposalCard, ProposalFact, ProposalOption } from '@youj/react'
Installation & usage
npm i @youj/reactFor an app already set up with npx @youj/cli init, which installs the peers (@youj/core, @youj/motion, motion and Base UI) and wires the provider. New app? Start at Installation.
Use a proposal card where someone, often an agent, suggests a change and a person decides: a reroute that saves half an hour, a load moved to another driver, a meeting moved to a free slot. It says where the proposal came from, what it is, then weighs the options side by side, the proposed one drawn as a dashed accent outline like a proposed route on a Route Map or a proposed run on Time Lanes. Its impact reads as figures, and your buttons decide it.
import { Button, ProposalCard } from '@youj/react'
const [status, setStatus] = useState<'pending' | 'approved' | 'dismissed'>('pending')
<ProposalCard
source="Route agent · 92% confidence"
title="Reroute load 4821 via Ridge Rd"
options={[
{ id: 'current', label: 'Harbor Fwy · current', value: '15:49', detail: '+47 min', tone: 'danger' },
{ id: 'proposed', label: 'Ridge Rd · proposed', value: '15:18', detail: '−31 min', proposed: true },
]}
facts={[{ label: 'Time saved', value: '31 min', tone: 'success' }]}
status={status}
resolution="Approved · driver notified"
actions={<Button size="sm" onClick={() => setStatus('approved')}>Approve reroute</Button>}
/>options are the plans side by side, usually the current one and the proposal (proposed: true). Each has a label, a value in mono (an ETA, a price) and a detail for how it moves against plan, inked by its tone. facts are the impact as a row of figures. note is a line over the actions: why it needs a person. You own status: pending shows actions; approved makes the proposal solid, steps the other options back and folds the actions away for your resolution; dismissed fades the proposal and keeps the plan.
Description
A route agent proposes a reroute; approving or dismissing resolves the card, and Undo brings it back.
Code
proposal-card-demo.tsx, the Demo story. The component itself comes from the package.
Reference
Propsoptions, facts, status… (11)
Props
| Prop | Type | |
|---|---|---|
source | ReactNodeWhere it came from, as an eyebrow: an agent's name, a confidence, an age. | – |
titleRequired | ReactNode | – |
description | ReactNode | – |
options | ProposalOption[]The options side by side: usually the current plan, then the proposal. | – |
facts | ProposalFact[]The impact as figures: time saved, extra distance, the window kept. | – |
note | ReactNodeA line over the actions: why it needs a person ("Route changes need approval"). | – |
actions | ReactNodeYour buttons while it's pending. | – |
status | ProposalStatus'pending''approved''dismissed'default 'pending' | 'pending' |
resolution | ReactNodeWhat shows once it's decided, in place of the actions: "Approved by you · 11:58". | – |
headingLevel | 2 | 3 | 4The title's heading level. default 3 | 3 |
Other props pass through: extends ComponentProps<'article'>. | ||
Options
| Prop | Type | |
|---|---|---|
idRequired | string | – |
labelRequired | ReactNode"Harbor Fwy · current". | – |
value | ReactNodeThe figure the options are weighed by: "15:49", "$1,842". | – |
detail | ReactNodeHow it moves against plan: "+47 min". | – |
tone | ProposalTone'neutral''success''warning''danger''accent'The figure's and detail's ink. Default neutral; a proposed option defaults to accent. | – |
proposed | booleanThe option being proposed: a dashed accent outline until it's approved. | – |
StylingParts and data attributes
Styling
Parts: proposal-card (with data-status). Each option row carries data-proposed and, once stepped back, data-muted. The card takes the theme's radius, border and card surface; pass className to place it, for example over a map.
MotionRows, actions and resolution · reduced motion
Motion
| Moment | Tokens | ||
|---|---|---|---|
| Decidedoption rows change their outline, tint and opacity | duration.fastease.standard140ms · cubic-bezier(0.2, 0, 0, 1) | 140mscubic-bezier(0.2, 0, 0, 1) | |
| Actions out, resolution inthe two trade places through Collapse; a reversal continues from the current height | duration.baseease.standard220ms · cubic-bezier(0.2, 0, 0, 1) | 220mscubic-bezier(0.2, 0, 0, 1) |
Reduced motion
Rows change tone in place, and the actions and resolution swap at once.
Reduced motion
Every change lands in place. The status still reads from the outline, the struck-through figure and the resolution text.
AccessibilityArticle, proposed row, resolution
Accessibility
- The card is an
articlenamed by its title;headingLevelsets the title's level (3 by default). - The proposed option says so to screen readers ("Ridge Rd · proposed, Proposed"), from the labels'
proposed, translated by the language packs. - Facts are a description list: each figure is read with its label.
- The resolution sits in a polite status region, so approving or dismissing is announced.