@sableui/react 0.9.0 → 0.10.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +1 -1
- package/CHANGELOG.md +124 -0
- package/CONTRIBUTING.md +2 -2
- package/DESIGN.md +55 -16
- package/README.md +12 -0
- package/dist/{_contract-C2M1SjBf.d.ts → _contract-CkqXDVww.d.ts} +25 -2
- package/dist/blocks/danger-zone-block.js +3 -3
- package/dist/blocks/danger-zone-block.meta.js +1 -1
- package/dist/blocks/faq-block.js +3 -3
- package/dist/blocks/goal-progress-block.js +1 -1
- package/dist/blocks/notification-list-block.js +1 -1
- package/dist/blocks/pricing-table-block.js +12 -12
- package/dist/blocks/product-card-block.js +3 -3
- package/dist/blocks/product-card-block.meta.js +3 -3
- package/dist/blocks/profile-card-block.js +1 -1
- package/dist/blocks/profile-form-block.js +3 -3
- package/dist/blocks/revenue-breakdown-block.js +5 -5
- package/dist/blocks/stat-row-block.js +3 -3
- package/dist/blocks/task-list-block.js +2 -2
- package/dist/blocks/team-members-block.js +1 -1
- package/dist/blocks/wallet-block.js +4 -4
- package/dist/blocks/wallet-block.meta.js +3 -3
- package/dist/components/accordion/accordion.meta.js +2 -2
- package/dist/components/app-header/app-header.meta.js +1 -1
- package/dist/components/app-shell/app-shell.meta.js +2 -2
- package/dist/components/area-chart/area-chart.meta.js +3 -3
- package/dist/components/badge/badge.js +13 -4
- package/dist/components/badge/badge.meta.js +24 -13
- package/dist/components/badge/badge.variants.js +37 -23
- package/dist/components/banner/banner.meta.js +8 -8
- package/dist/components/banner/banner.variants.js +3 -3
- package/dist/components/bar-chart/bar-chart.meta.js +4 -4
- package/dist/components/breadcrumbs/breadcrumbs.meta.js +1 -1
- package/dist/components/button/button.js +13 -2
- package/dist/components/button/button.meta.js +3 -3
- package/dist/components/card/card.js +16 -7
- package/dist/components/card/card.meta.js +4 -4
- package/dist/components/checkbox-card/checkbox-card.meta.js +10 -10
- package/dist/components/checkbox-card/checkbox-card.variants.js +15 -15
- package/dist/components/code-block/code-block.meta.js +1 -1
- package/dist/components/command-menu/command-menu.js +2 -0
- package/dist/components/command-menu/command-menu.meta.js +1 -1
- package/dist/components/context-card/context-card.meta.js +2 -2
- package/dist/components/destructive-action-modal/destructive-action-modal.meta.js +1 -1
- package/dist/components/dialog/dialog.meta.js +2 -2
- package/dist/components/disclosure-picker/disclosure-picker.js +48 -2
- package/dist/components/disclosure-picker/disclosure-picker.meta.js +3 -2
- package/dist/components/empty-state/empty-state.meta.js +4 -4
- package/dist/components/form/form.js +10 -5
- package/dist/components/gradient-art/gradient-art.meta.js +3 -3
- package/dist/components/label/label.meta.js +1 -1
- package/dist/components/line-chart/line-chart.meta.js +3 -3
- package/dist/components/meter/meter.js +1 -1
- package/dist/components/meter/meter.meta.js +2 -2
- package/dist/components/meter/meter.variants.js +1 -1
- package/dist/components/middle-truncate/middle-truncate.meta.js +4 -4
- package/dist/components/note/note.meta.js +3 -3
- package/dist/components/page-header/page-header.js +1 -1
- package/dist/components/pagination/pagination.meta.js +2 -2
- package/dist/components/phone/phone.meta.js +1 -1
- package/dist/components/pie-chart/pie-chart.meta.js +3 -3
- package/dist/components/pill/pill.js +4 -2
- package/dist/components/pill/pill.meta.js +19 -2
- package/dist/components/pill/pill.variants.js +23 -2
- package/dist/components/popover/popover.meta.js +2 -2
- package/dist/components/radar-chart/radar-chart.meta.js +3 -3
- package/dist/components/radial-chart/radial-chart.meta.js +3 -3
- package/dist/components/radio/radio.meta.js +2 -2
- package/dist/components/radio-card/radio-card.meta.js +6 -6
- package/dist/components/radio-card/radio-card.variants.js +15 -15
- package/dist/components/scroller/scroller.meta.js +1 -1
- package/dist/components/search-input/search-input.meta.js +1 -1
- package/dist/components/section-header/section-header.js +1 -1
- package/dist/components/segmented-bar/segmented-bar.js +1 -1
- package/dist/components/segmented-bar/segmented-bar.meta.js +6 -6
- package/dist/components/segmented-bar/segmented-bar.variants.js +4 -4
- package/dist/components/select/select.meta.js +2 -2
- package/dist/components/sheet/sheet.js +15 -1
- package/dist/components/sheet/sheet.meta.js +1 -1
- package/dist/components/side-nav/side-nav.meta.js +1 -1
- package/dist/components/sidebar/sidebar.meta.js +1 -1
- package/dist/components/sparkline/sparkline.meta.js +4 -4
- package/dist/components/spinner/spinner.meta.js +1 -1
- package/dist/components/status-dot/status-dot.js +4 -1
- package/dist/components/status-dot/status-dot.meta.js +8 -16
- package/dist/components/status-dot/status-dot.variants.js +13 -4
- package/dist/components/stepper/stepper.js +11 -2
- package/dist/components/table/table.meta.js +4 -4
- package/dist/components/tabs/tabs.meta.js +1 -1
- package/dist/components/textarea/textarea.meta.js +2 -2
- package/dist/components/toast/toast.js +1 -0
- package/dist/components/toast/toast.meta.js +1 -1
- package/dist/components/tooltip/tooltip.meta.js +2 -2
- package/dist/file-hashes.json +127 -124
- package/dist/foundations/spacing.js +8 -8
- package/dist/index.d.ts +138 -73
- package/dist/index.js +12 -1
- package/dist/lib/chart/types.js +3 -3
- package/dist/lib/is-promise.js +5 -0
- package/dist/lib/palette.js +103 -0
- package/dist/lib/selection-card.js +4 -4
- package/dist/palette.css +669 -0
- package/dist/patterns/auth-page.js +6 -6
- package/dist/patterns/auth-page.meta.js +3 -3
- package/dist/patterns/brand-landing-page.js +2 -2
- package/dist/patterns/chat-panel.js +2 -2
- package/dist/patterns/dashboard-page.js +71 -71
- package/dist/patterns/dashboard-page.meta.js +5 -5
- package/dist/patterns/feed-page.js +25 -25
- package/dist/patterns/feed-page.meta.js +3 -3
- package/dist/patterns/landing-page.js +1 -1
- package/dist/patterns/list-detail-page.js +17 -17
- package/dist/patterns/settings-page.js +17 -17
- package/dist/presets/index.d.ts +1 -1
- package/dist/presets/index.js +17 -2
- package/dist/styles.css +163 -55
- package/dist/{theme-provider-S0NVJs2Y.d.ts → theme-provider-CdSicAad.d.ts} +1 -1
- package/dist/themes/_contract.js +22 -8
- package/dist/themes/atelier/atelier.css +13 -13
- package/dist/themes/atelier/index.d.ts +1 -1
- package/dist/themes/ember/ember.css +13 -13
- package/dist/themes/ember/index.d.ts +1 -1
- package/dist/themes/index.d.ts +2 -2
- package/dist/themes/meridian/index.d.ts +1 -1
- package/dist/themes/meridian/meridian.css +13 -13
- package/dist/themes/poppy/index.d.ts +1 -1
- package/dist/themes/poppy/poppy.css +19 -16
- package/dist/themes/prism/index.d.ts +1 -1
- package/dist/themes/prism/prism.css +18 -15
- package/dist/themes/sable/index.d.ts +1 -1
- package/dist/themes/sable/sable.css +18 -22
- package/dist/themes/verdant/index.d.ts +1 -1
- package/dist/themes/verdant/verdant.css +15 -15
- package/llms/blocks/danger-zone-block.md +4 -4
- package/llms/blocks/faq-block.md +3 -3
- package/llms/blocks/goal-progress-block.md +1 -1
- package/llms/blocks/notification-list-block.md +1 -1
- package/llms/blocks/pricing-table-block.md +12 -12
- package/llms/blocks/product-card-block.md +6 -6
- package/llms/blocks/profile-card-block.md +1 -1
- package/llms/blocks/profile-form-block.md +3 -3
- package/llms/blocks/revenue-breakdown-block.md +5 -5
- package/llms/blocks/stat-row-block.md +3 -3
- package/llms/blocks/task-list-block.md +2 -2
- package/llms/blocks/team-members-block.md +1 -1
- package/llms/blocks/wallet-block.md +7 -7
- package/llms/components/accordion.md +2 -2
- package/llms/components/app-header.md +1 -1
- package/llms/components/app-shell.md +2 -2
- package/llms/components/area-chart.md +1 -1
- package/llms/components/badge.md +15 -7
- package/llms/components/banner.md +6 -6
- package/llms/components/bar-chart.md +2 -2
- package/llms/components/breadcrumbs.md +1 -1
- package/llms/components/button.md +3 -3
- package/llms/components/card.md +4 -4
- package/llms/components/checkbox-card.md +5 -5
- package/llms/components/code-block.md +1 -1
- package/llms/components/command-menu.md +1 -1
- package/llms/components/context-card.md +2 -2
- package/llms/components/destructive-action-modal.md +1 -1
- package/llms/components/dialog.md +2 -2
- package/llms/components/disclosure-picker.md +2 -1
- package/llms/components/empty-state.md +4 -4
- package/llms/components/gradient-art.md +3 -3
- package/llms/components/label.md +1 -1
- package/llms/components/line-chart.md +1 -1
- package/llms/components/meter.md +2 -2
- package/llms/components/middle-truncate.md +5 -5
- package/llms/components/note.md +3 -3
- package/llms/components/pagination.md +2 -2
- package/llms/components/phone.md +1 -1
- package/llms/components/pie-chart.md +1 -1
- package/llms/components/pill.md +12 -2
- package/llms/components/popover.md +2 -2
- package/llms/components/radar-chart.md +1 -1
- package/llms/components/radial-chart.md +1 -1
- package/llms/components/radio-card.md +4 -4
- package/llms/components/radio.md +2 -2
- package/llms/components/scroller.md +1 -1
- package/llms/components/search-input.md +1 -1
- package/llms/components/segmented-bar.md +7 -7
- package/llms/components/select.md +2 -2
- package/llms/components/sheet.md +1 -1
- package/llms/components/side-nav.md +1 -1
- package/llms/components/sidebar.md +1 -1
- package/llms/components/sparkline.md +2 -2
- package/llms/components/spinner.md +1 -1
- package/llms/components/status-dot.md +4 -4
- package/llms/components/table.md +8 -8
- package/llms/components/tabs.md +1 -1
- package/llms/components/textarea.md +2 -2
- package/llms/components/toast.md +1 -1
- package/llms/components/tooltip.md +2 -2
- package/llms/foundations/spacing.md +7 -7
- package/llms/layout/grid.md +1 -1
- package/llms/layout/page.md +1 -1
- package/llms/layout/region.md +1 -1
- package/llms/layout/split-pane.md +1 -1
- package/llms/patterns/auth-page.md +11 -11
- package/llms/patterns/brand-landing-page.md +2 -2
- package/llms/patterns/chat-panel.md +2 -2
- package/llms/patterns/dashboard-page.md +78 -78
- package/llms/patterns/feed-page.md +31 -31
- package/llms/patterns/landing-page.md +1 -1
- package/llms/patterns/list-detail-page.md +18 -18
- package/llms/patterns/settings-page.md +18 -18
- package/llms/reference/token-intent.md +25 -11
- package/llms/reference/utilities.md +1 -1
- package/llms/tasks/adding-a-component.md +4 -1
- package/llms/tasks/building-a-page.md +40 -0
- package/llms/tasks/building-with-sable.md +4 -0
- package/llms/tasks/converting-an-app.md +3 -1
- package/llms/tasks/using-presets.md +4 -0
- package/llms-full.txt +433 -347
- package/llms.txt +7 -7
- package/package.json +4 -4
- package/registry.json +369 -233
- package/scripts/lint-rules.mjs +26 -5
- package/scripts/sources.mjs +4 -1
- package/skills/sable/SKILL.md +14 -3
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
# ProductCardBlock
|
|
2
2
|
|
|
3
|
-
A product card: edge-to-edge
|
|
3
|
+
A product card: edge-to-edge product image, title and maker, a status Badge, and the price beside a single buy action.
|
|
4
4
|
|
|
5
|
-
**Intent:** Reach for this for a product
|
|
5
|
+
**Intent:** Reach for this for a product or listing in a grid or a featured slot. For a row in a dense list, use an Entity with the image as `leading` instead.
|
|
6
6
|
|
|
7
7
|
**Block:** Commerce · card · designed for 16rem–20rem wide (fills its container up to the max)
|
|
8
8
|
|
|
9
9
|
## Notes
|
|
10
10
|
|
|
11
|
-
- The
|
|
11
|
+
- The image runs to the card's edges; the card clips it to its own corners (overflow-hidden).
|
|
12
12
|
- Prices are `text-mono-lg` — the metric mono tier with tabular figures — never a heading tier.
|
|
13
13
|
- The placeholder art is painted from the palette's decorative tones so it follows the theme; swap it for the product image with real alt text.
|
|
14
14
|
|
|
@@ -23,7 +23,7 @@ A product card: edge-to-edge artwork, title and maker, an edition Badge, and the
|
|
|
23
23
|
import { AspectBox, Badge, Button, Card, CardAction, CardDescription, CardFooter, CardHeader, CardTitle, cn, MediaImage } from "@sableui/react"
|
|
24
24
|
|
|
25
25
|
// `image` is the product shot URL; left empty, it paints art seeded by the title.
|
|
26
|
-
const product = { title: "
|
|
26
|
+
const product = { title: "Linen throw blanket", maker: "Northfield Home", image: "", badge: "New", price: "$64.00" }
|
|
27
27
|
|
|
28
28
|
|
|
29
29
|
export interface ProductCardBlockProps {
|
|
@@ -44,12 +44,12 @@ export function ProductCardBlock({ className, framed = true, onCollect }: Produc
|
|
|
44
44
|
<CardTitle>{product.title}</CardTitle>
|
|
45
45
|
<CardDescription>{product.maker}</CardDescription>
|
|
46
46
|
<CardAction>
|
|
47
|
-
<Badge tone="
|
|
47
|
+
<Badge tone="1">{product.badge}</Badge>
|
|
48
48
|
</CardAction>
|
|
49
49
|
</CardHeader>
|
|
50
50
|
<CardFooter className="justify-between pt-4">
|
|
51
51
|
<span className="text-mono-lg">{product.price}</span>
|
|
52
|
-
<Button onClick={onCollect}>
|
|
52
|
+
<Button onClick={onCollect}>Add to cart</Button>
|
|
53
53
|
</CardFooter>
|
|
54
54
|
</Card>
|
|
55
55
|
)
|
|
@@ -27,7 +27,7 @@ const profile = {
|
|
|
27
27
|
name: "Juno Avery",
|
|
28
28
|
initials: "JA",
|
|
29
29
|
handle: "@juno · Sound and light",
|
|
30
|
-
bio: "Field recordings, slowed down. New
|
|
30
|
+
bio: "Field recordings, slowed down. New track every full moon.",
|
|
31
31
|
stats: [
|
|
32
32
|
{ value: "128", label: "posts" },
|
|
33
33
|
{ value: "4.2k", label: "followers" },
|
|
@@ -26,7 +26,7 @@ const profile = {
|
|
|
26
26
|
name: "Ada Lovelace",
|
|
27
27
|
initials: "AL",
|
|
28
28
|
handle: "ada",
|
|
29
|
-
bio: "
|
|
29
|
+
bio: "Product designer working on tools for small teams. Writing about process every month.",
|
|
30
30
|
timezone: "europe-london",
|
|
31
31
|
}
|
|
32
32
|
|
|
@@ -51,7 +51,7 @@ export function ProfileFormBlock({ className, framed = true, onSave }: ProfileFo
|
|
|
51
51
|
<Card variant={framed ? "default" : "flat"} className={cn("w-full max-w-2xl", className)}>
|
|
52
52
|
<CardHeader>
|
|
53
53
|
<CardTitle render={<h2 />}>Profile</CardTitle>
|
|
54
|
-
<CardDescription>How
|
|
54
|
+
<CardDescription>How your team sees you.</CardDescription>
|
|
55
55
|
</CardHeader>
|
|
56
56
|
{/* The one explicit save: profile text is drafted, then committed. */}
|
|
57
57
|
<Form
|
|
@@ -85,7 +85,7 @@ export function ProfileFormBlock({ className, framed = true, onSave }: ProfileFo
|
|
|
85
85
|
<Input defaultValue={profile.handle} autoComplete="username" spellCheck={false} />
|
|
86
86
|
</Field>
|
|
87
87
|
</Grid>
|
|
88
|
-
<Field label="Bio" name="bio" description="Shown on your profile and
|
|
88
|
+
<Field label="Bio" name="bio" description="Shown on your profile and in comments.">
|
|
89
89
|
<Textarea rows={3} defaultValue={profile.bio} />
|
|
90
90
|
</Field>
|
|
91
91
|
<Grid cols={{ base: 1, sm: 2 }} gap={3}>
|
|
@@ -25,10 +25,10 @@ import { Badge, Card, CardAction, CardContent, CardDescription, CardHeader, cn,
|
|
|
25
25
|
const revenue = { label: "Revenue this month", total: "$12,480", change: "+8.2%" }
|
|
26
26
|
|
|
27
27
|
const segments = [
|
|
28
|
-
{ label: "
|
|
29
|
-
{ label: "
|
|
30
|
-
{ label: "
|
|
31
|
-
{ label: "
|
|
28
|
+
{ label: "Direct", value: 42, tone: "1" },
|
|
29
|
+
{ label: "Partners", value: 27, tone: "2" },
|
|
30
|
+
{ label: "Referrals", value: 19, tone: "3" },
|
|
31
|
+
{ label: "Resellers", value: 12, tone: "info" },
|
|
32
32
|
] as const
|
|
33
33
|
|
|
34
34
|
export interface RevenueBreakdownBlockProps {
|
|
@@ -50,7 +50,7 @@ export function RevenueBreakdownBlock({ className, framed = true }: RevenueBreak
|
|
|
50
50
|
</CardHeader>
|
|
51
51
|
<CardContent className="flex flex-col gap-4 pt-2">
|
|
52
52
|
<span className="text-mono-xl">{revenue.total}</span>
|
|
53
|
-
<SegmentedBar label="Revenue by
|
|
53
|
+
<SegmentedBar label="Revenue by channel" segments={[...segments]} size="lg" />
|
|
54
54
|
{/* Two columns while each entry fits whole, one when they would not:
|
|
55
55
|
sized in em, so a larger type or a narrower card drops to one.
|
|
56
56
|
aria-hidden: the bar already reads every share aloud. */}
|
|
@@ -25,9 +25,9 @@ import { Badge, Card, CardContent, CardDescription, CardHeader, CardTitle, cn, G
|
|
|
25
25
|
|
|
26
26
|
const stats = [
|
|
27
27
|
{ label: "Revenue", value: "$18,240", delta: "+8.2%", up: true, note: "vs. $16,857" },
|
|
28
|
-
{ label: "
|
|
29
|
-
{ label: "
|
|
30
|
-
{ label: "
|
|
28
|
+
{ label: "Orders", value: "1,284", delta: "+3.1%", up: true, note: "182 first-time" },
|
|
29
|
+
{ label: "New customers", value: "312", delta: "+12.4%", up: true, note: "Best month yet" },
|
|
30
|
+
{ label: "Conversion", value: "3.4%", delta: "−0.2%", up: false, note: "6 open trials" },
|
|
31
31
|
]
|
|
32
32
|
|
|
33
33
|
export interface StatRowBlockProps {
|
|
@@ -24,9 +24,9 @@ import { useState, useId } from "react"
|
|
|
24
24
|
import { Badge, Button, Card, CardAction, CardContent, CardFooter, CardHeader, CardTitle, Checkbox, cn, Icon, Label } from "@sableui/react"
|
|
25
25
|
|
|
26
26
|
const tasks = [
|
|
27
|
-
{ title: "Pick the cover type", tag: "Design", tone: "
|
|
27
|
+
{ title: "Pick the cover type", tag: "Design", tone: "2", done: true },
|
|
28
28
|
{ title: "Wire up checkout", tag: "Engineering", tone: "info", done: false },
|
|
29
|
-
{ title: "Draft launch post", tag: "Launch", tone: "
|
|
29
|
+
{ title: "Draft launch post", tag: "Launch", tone: "1", done: false },
|
|
30
30
|
] as const
|
|
31
31
|
|
|
32
32
|
export interface TaskListBlockProps {
|
|
@@ -59,7 +59,7 @@ export function TeamMembersBlock({ className, framed = true, onInvite, onMemberA
|
|
|
59
59
|
subtitle={m.email}
|
|
60
60
|
action={
|
|
61
61
|
<div className="flex items-center gap-2">
|
|
62
|
-
<Badge appearance={m.role === "Pending" ? "outline" : "plain"} tone={m.role === "Owner" ? "
|
|
62
|
+
<Badge appearance={m.role === "Pending" ? "outline" : "plain"} tone={m.role === "Owner" ? "1" : "neutral"} size="sm">
|
|
63
63
|
{m.role}
|
|
64
64
|
</Badge>
|
|
65
65
|
{/* The owner is not managed from here; a placeholder keeps the column aligned. */}
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
A balance card: the balance in the metric mono tier, Send and Receive as an equal pair, and recent activity as Entity rows with signed amounts.
|
|
4
4
|
|
|
5
|
-
**Intent:** Reach for this for
|
|
5
|
+
**Intent:** Reach for this for an account balance, store credit or credits summary with its latest movements. For a full transaction history with filters, use a DataTable.
|
|
6
6
|
|
|
7
7
|
**Block:** Commerce · card · designed for 18rem–20rem wide (fills its container up to the max)
|
|
8
8
|
|
|
@@ -10,24 +10,24 @@ A balance card: the balance in the metric mono tier, Send and Receive as an equa
|
|
|
10
10
|
|
|
11
11
|
- The balance is CardTitle at `text-mono-xl` — tabular figures, never a heading tier — under its label as CardDescription.
|
|
12
12
|
- Send is primary and Receive secondary, side by side at equal width: two directions of one action, with sending the riskier and more frequent.
|
|
13
|
-
- Incoming amounts are `text-success`; outgoing stay muted rather than red, because a
|
|
13
|
+
- Incoming amounts are `text-success`; outgoing stay muted rather than red, because a payout or refund is not an error.
|
|
14
14
|
|
|
15
15
|
## Accessibility
|
|
16
16
|
|
|
17
17
|
- Each activity row's leading swatch is aria-hidden; the title and detail carry the meaning.
|
|
18
|
-
- Amounts keep their sign in text (+
|
|
18
|
+
- Amounts keep their sign in text (+49.00 / -850.00), so the direction does not depend on colour.
|
|
19
19
|
|
|
20
20
|
## Source
|
|
21
21
|
|
|
22
22
|
```tsx
|
|
23
23
|
import { Button, Card, CardContent, CardDescription, CardHeader, CardTitle, cn, Entity, Icon } from "@sableui/react"
|
|
24
24
|
|
|
25
|
-
const balance = "
|
|
25
|
+
const balance = "$2,418.50"
|
|
26
26
|
|
|
27
27
|
const activity = [
|
|
28
|
-
{ title: "
|
|
29
|
-
{ title: "
|
|
30
|
-
{ title: "
|
|
28
|
+
{ title: "Subscription", detail: "Team plan · 2h ago", amount: "+49.00", tone: "1" },
|
|
29
|
+
{ title: "Refund", detail: "Order 1042 · Yesterday", amount: "-24.00", tone: "2" },
|
|
30
|
+
{ title: "Payout", detail: "To checking · Mon", amount: "-850.00", tone: "3" },
|
|
31
31
|
]
|
|
32
32
|
|
|
33
33
|
export interface WalletBlockProps {
|
|
@@ -73,7 +73,7 @@ Use Accordion to reveal a vertical set of related sections while keeping the sur
|
|
|
73
73
|
```tsx
|
|
74
74
|
import { Accordion, AccordionItem, AccordionPanel, AccordionTrigger } from "@sableui/react"
|
|
75
75
|
|
|
76
|
-
<Accordion defaultValue={["a"]}><AccordionItem value="a"><AccordionTrigger>
|
|
76
|
+
<Accordion defaultValue={["a"]}><AccordionItem value="a"><AccordionTrigger>Can I cancel anytime?</AccordionTrigger><AccordionPanel>Yes — from billing settings.</AccordionPanel></AccordionItem><AccordionItem value="b"><AccordionTrigger>How much?</AccordionTrigger><AccordionPanel>$16 per seat each month.</AccordionPanel></AccordionItem></Accordion>
|
|
77
77
|
```
|
|
78
78
|
|
|
79
79
|
### Multiple open
|
|
@@ -89,5 +89,5 @@ import { Accordion, AccordionItem, AccordionPanel, AccordionTrigger } from "@sab
|
|
|
89
89
|
```tsx
|
|
90
90
|
import { Accordion, AccordionItem, AccordionPanel, AccordionTrigger, Icon } from "@sableui/react"
|
|
91
91
|
|
|
92
|
-
<Accordion defaultValue={["a"]}><AccordionItem value="a"><AccordionTrigger indicator={<Icon name="plus" className="text-xs text-muted-foreground transition-transform [[data-panel-open]_&]:rotate-45" />}>
|
|
92
|
+
<Accordion defaultValue={["a"]}><AccordionItem value="a"><AccordionTrigger indicator={<Icon name="plus" className="text-xs text-muted-foreground transition-transform [[data-panel-open]_&]:rotate-45" />}>Can I cancel anytime?</AccordionTrigger><AccordionPanel>Yes — from billing settings.</AccordionPanel></AccordionItem></Accordion>
|
|
93
93
|
```
|
|
@@ -23,7 +23,7 @@ Use AppHeader for compact application chrome at the top of a screen, usually wit
|
|
|
23
23
|
| --- | --- | --- | --- |
|
|
24
24
|
| leading | ReactNode | — | Leading slot — back button, create action, or menu trigger. |
|
|
25
25
|
| title | ReactNode | — | Center slot — brand wordmark or contextual page title. |
|
|
26
|
-
| actions | ReactNode | — | Trailing slot —
|
|
26
|
+
| actions | ReactNode | — | Trailing slot — account menu, action buttons. |
|
|
27
27
|
|
|
28
28
|
## Tokens used
|
|
29
29
|
|
|
@@ -72,7 +72,7 @@ import { AppHeader, AppShell, Banner, BottomNav, BottomNavItem, Icon, PageHeader
|
|
|
72
72
|
// <Link> = your router's link (react-router, next/link, @tanstack/router, …)
|
|
73
73
|
|
|
74
74
|
<AppShell
|
|
75
|
-
banners={<Banner tone="warning">
|
|
75
|
+
banners={<Banner tone="warning">Sync is delayed — changes may be slow to appear.</Banner>}
|
|
76
76
|
header={<AppHeader title="Studio" />}
|
|
77
77
|
sidebar={
|
|
78
78
|
<Sidebar>
|
|
@@ -91,7 +91,7 @@ import { AppHeader, AppShell, Banner, BottomNav, BottomNavItem, Icon, PageHeader
|
|
|
91
91
|
}
|
|
92
92
|
>
|
|
93
93
|
<Region max="feed">
|
|
94
|
-
<PageHeader title="Home" description="Latest posts from
|
|
94
|
+
<PageHeader title="Home" description="Latest posts from people you follow." />
|
|
95
95
|
</Region>
|
|
96
96
|
</AppShell>
|
|
97
97
|
```
|
|
@@ -44,7 +44,7 @@ Use AreaChart for volume over time — visitors, revenue, usage — where the fi
|
|
|
44
44
|
|
|
45
45
|
## Tokens used
|
|
46
46
|
|
|
47
|
-
`tone-
|
|
47
|
+
`tone-1`, `tone-2`, `tone-3`, `tone-info`, `tone-warning`, `primary`, `muted-foreground`, `border`, `popover`, `popover-foreground`, `foreground`, `background`
|
|
48
48
|
|
|
49
49
|
## Motion
|
|
50
50
|
|
package/llms/components/badge.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
**Status:** stable
|
|
4
4
|
|
|
5
|
-
Compact static label, set on two axes: appearance (soft, outline, solid, overlay on media, plain text) and tone (neutral or a
|
|
5
|
+
Compact static label, set on two axes: appearance (soft, outline, solid, overlay on media, plain text) and tone (neutral, a semantic tone, or a palette family like blue for a category with no meaning attached). An optional leading icon, or a status dot (with pulse) for state.
|
|
6
6
|
|
|
7
7
|
**Keywords:** badge, tag, label, status, metadata, chip, pill, tone, category
|
|
8
8
|
|
|
@@ -13,7 +13,7 @@ Use Badge for any short static label: metadata, categories, tone-coded labels, a
|
|
|
13
13
|
### Best practices
|
|
14
14
|
|
|
15
15
|
- Do: Keep badge text short: one to three words or a compact count.
|
|
16
|
-
- Do: Use tone variants when the badge carries meaning, such as success, warning
|
|
16
|
+
- Do: Use tone variants when the badge carries meaning, such as success, warning or destructive, or a decorative tone for a category or plan.
|
|
17
17
|
- Do: Pair icons with text; the icon reinforces meaning but should not be the only cue.
|
|
18
18
|
- Do: Choose appearance and tone separately: appearance is how loud it is (soft by default, solid for emphasis, overlay on images, plain for a status line); tone is what it means.
|
|
19
19
|
- Don't: Use a Badge as a button. If it triggers an action, use Button, Toggle, or a menu item.
|
|
@@ -32,7 +32,7 @@ Use Badge for any short static label: metadata, categories, tone-coded labels, a
|
|
|
32
32
|
| Name | Type | Default | Description |
|
|
33
33
|
| --- | --- | --- | --- |
|
|
34
34
|
| appearance | "soft" \| "outline" \| "solid" \| "overlay" \| "plain" | "soft" | How it is drawn. soft: a tinted fill (neutral is the secondary surface). outline: a hairline. solid: the tone at full strength (neutral is the inverted chip). overlay: legible on images — a dark scrim, or the solid tone. plain: no fill or padding, a status line. |
|
|
35
|
-
| tone | "neutral" \| "
|
|
35
|
+
| tone | "neutral" \| "1" \| "2" \| "3" \| "info" \| "success" \| "warning" \| "destructive" \| "red" \| "orange" \| "yellow" \| "green" \| "teal" \| "blue" \| "purple" \| "pink" | "neutral" | What it means. Every appearance takes every tone. The palette families (red … pink) are categories with no meaning attached — tags, labels, project colours — painted from the theme's generated palette, so they lean toward the brand and read in both modes. |
|
|
36
36
|
| size | "sm" \| "md" | "md" | "sm" uses tighter padding + text-label-sm; "md" is the default look. |
|
|
37
37
|
| icon | ReactNode | — | Optional leading glyph (e.g. <Icon name="lock" />), rendered before the children with the base gap. Ignored when dot is set. |
|
|
38
38
|
| dot | boolean | false | A leading status dot in the badge's tone. With appearance="plain" it is a status line (● Ready). |
|
|
@@ -41,12 +41,12 @@ Use Badge for any short static label: metadata, categories, tone-coded labels, a
|
|
|
41
41
|
## Variants
|
|
42
42
|
|
|
43
43
|
- **appearance**: soft, outline, solid, overlay, plain
|
|
44
|
-
- **tone**: neutral,
|
|
44
|
+
- **tone**: neutral, 1, 2, 3, info, success, warning, destructive, red, orange, yellow, green, teal, blue, purple, pink
|
|
45
45
|
- **size**: sm, md
|
|
46
46
|
|
|
47
47
|
## Tokens used
|
|
48
48
|
|
|
49
|
-
`secondary`, `secondary-foreground`, `border`, `foreground`, `background`, `muted`, `muted-foreground`, `tone-
|
|
49
|
+
`palette-wash`, `palette-wash-strong`, `palette-edge`, `palette-dot`, `palette-solid`, `palette-text`, `palette-solid-ink`, `secondary`, `secondary-foreground`, `border`, `foreground`, `background`, `muted`, `muted-foreground`, `tone-1`, `tone-2`, `tone-3`, `tone-info`, `success`, `tone-warning`, `destructive`, `overlay`, `overlay-foreground`, `tone-1-foreground`, `tone-2-foreground`, `tone-3-foreground`, `tone-info-foreground`, `success-foreground`, `tone-warning-foreground`, `destructive-foreground`
|
|
50
50
|
|
|
51
51
|
## Accessibility
|
|
52
52
|
|
|
@@ -65,7 +65,15 @@ Use Badge for any short static label: metadata, categories, tone-coded labels, a
|
|
|
65
65
|
```tsx
|
|
66
66
|
import { Badge, Row } from "@sableui/react"
|
|
67
67
|
|
|
68
|
-
<Row gap={1}><Badge tone="
|
|
68
|
+
<Row gap={1}><Badge tone="1">Business</Badge><Badge tone="2">Studio</Badge><Badge tone="3">Starter</Badge></Row>
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
### Palette colours (categories)
|
|
72
|
+
|
|
73
|
+
```tsx
|
|
74
|
+
import { Badge, Row } from "@sableui/react"
|
|
75
|
+
|
|
76
|
+
<Row gap={1}><Badge tone="blue">Design</Badge><Badge tone="teal">Research</Badge><Badge tone="orange">Marketing</Badge><Badge tone="pink" appearance="outline">Ops</Badge><Badge tone="purple" appearance="solid">Launch</Badge></Row>
|
|
69
77
|
```
|
|
70
78
|
|
|
71
79
|
### Solid
|
|
@@ -105,7 +113,7 @@ import { Badge } from "@sableui/react"
|
|
|
105
113
|
```tsx
|
|
106
114
|
import { Badge, Icon, Row } from "@sableui/react"
|
|
107
115
|
|
|
108
|
-
<Row gap={1}><Badge>12
|
|
116
|
+
<Row gap={1}><Badge>12 projects</Badge><Badge appearance="outline">Draft</Badge><Badge tone="info" icon={<Icon name="info" />}>Curated</Badge></Row>
|
|
109
117
|
```
|
|
110
118
|
|
|
111
119
|
### Semantic state
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
**Status:** stable
|
|
4
4
|
|
|
5
|
-
Full-width, page-level announcement bar. A tone (neutral, info, success, warning,
|
|
5
|
+
Full-width, page-level announcement bar. A tone (neutral, info, success, warning, the decorative 1, destructive) × an appearance (soft tint or loud solid fill), and an optional leading scope label. Centers its message, or — with a trailing action — switches to a leading-text + trailing-button layout. Optionally sticky and dismissible.
|
|
6
6
|
|
|
7
7
|
**Keywords:** banner, announcement, alert, status, message, warning, success, offline, sticky
|
|
8
8
|
|
|
@@ -31,7 +31,7 @@ Use Banner for page-level or app-level messages that affect the current experien
|
|
|
31
31
|
|
|
32
32
|
| Name | Type | Default | Description |
|
|
33
33
|
| --- | --- | --- | --- |
|
|
34
|
-
| tone | "neutral" \| "info" \| "success" \| "warning" \| "
|
|
34
|
+
| tone | "neutral" \| "info" \| "success" \| "warning" \| "1" \| "destructive" | "neutral" | Neutral surface or a tone that encodes the announcement's intent (info / success / warning / the decorative 1 / destructive). |
|
|
35
35
|
| appearance | "soft" \| "solid" | "soft" | "soft" is a quiet tinted fill; "solid" is the full tone with its paired ink — for loud, can't-miss states (offline, chain-down, RPC errors). |
|
|
36
36
|
| label | ReactNode | — | A short scope label ("Preview", "Staging", a project name) in a leading chip — a Badge that reads on soft and solid fills. |
|
|
37
37
|
| action | ReactNode | — | A trailing action (e.g. a Button). Switches the bar to leading text + trailing action instead of centered text. |
|
|
@@ -42,12 +42,12 @@ Use Banner for page-level or app-level messages that affect the current experien
|
|
|
42
42
|
|
|
43
43
|
## Variants
|
|
44
44
|
|
|
45
|
-
- **tone**: neutral, info, success, warning,
|
|
45
|
+
- **tone**: neutral, info, success, warning, 1, destructive
|
|
46
46
|
- **appearance**: soft, solid
|
|
47
47
|
|
|
48
48
|
## Tokens used
|
|
49
49
|
|
|
50
|
-
`secondary`, `secondary-foreground`, `foreground`, `background`, `tone-info`, `tone-info-foreground`, `success`, `success-foreground`, `tone-warning`, `tone-warning-foreground`, `tone-
|
|
50
|
+
`secondary`, `secondary-foreground`, `foreground`, `background`, `tone-info`, `tone-info-foreground`, `success`, `success-foreground`, `tone-warning`, `tone-warning-foreground`, `tone-1`, `tone-1-foreground`, `destructive`, `destructive-foreground`
|
|
51
51
|
|
|
52
52
|
## Accessibility
|
|
53
53
|
|
|
@@ -75,7 +75,7 @@ import { Banner } from "@sableui/react"
|
|
|
75
75
|
```tsx
|
|
76
76
|
import { Banner } from "@sableui/react"
|
|
77
77
|
|
|
78
|
-
<Banner tone="destructive" appearance="solid" live="assertive">
|
|
78
|
+
<Banner tone="destructive" appearance="solid" live="assertive">Payments are down. Checkout and upgrades are temporarily disabled.</Banner>
|
|
79
79
|
```
|
|
80
80
|
|
|
81
81
|
### Success
|
|
@@ -107,7 +107,7 @@ import { Banner } from "@sableui/react"
|
|
|
107
107
|
```tsx
|
|
108
108
|
import { Banner, Button } from "@sableui/react"
|
|
109
109
|
|
|
110
|
-
<Banner tone="warning" action={<Button variant="outline" size="sm">Reconnect</Button>}>
|
|
110
|
+
<Banner tone="warning" action={<Button variant="outline" size="sm">Reconnect</Button>}>Calendar sync paused.</Banner>
|
|
111
111
|
```
|
|
112
112
|
|
|
113
113
|
### App-shell outage
|
|
@@ -42,13 +42,13 @@ Use BarChart to compare amounts across categories — the default chart for "how
|
|
|
42
42
|
| stacked | boolean \| "expand" | false | Stack the series in one bar, or `"expand"` to show each category as 100%. Unstacked series sit side by side. |
|
|
43
43
|
| labels | boolean \| "inside" | false | Print each bar's value at its end, or (`"inside"`, horizontal) the category name inside the bar as well. |
|
|
44
44
|
| colorBy | "series" \| "index" | "series" | Colour by series, or give each category its own tone (one series). |
|
|
45
|
-
| negativeTone | "
|
|
45
|
+
| negativeTone | "1" \| "2" \| "3" \| "info" \| "warning" \| "primary" \| "neutral" \| "success" \| "destructive" | — | Colour negative values with this tone. |
|
|
46
46
|
| radius | number | 4 | Corner radius of each bar's far end, in px. Stacks round only the outer segment. |
|
|
47
47
|
| barWidth | number | 24 | Maximum thickness of a bar, in px: the band's leftover is air, not a fatter bar. Raise it for a bolder presentation look. |
|
|
48
48
|
|
|
49
49
|
## Tokens used
|
|
50
50
|
|
|
51
|
-
`tone-
|
|
51
|
+
`tone-1`, `tone-2`, `tone-3`, `tone-info`, `tone-warning`, `primary`, `muted-foreground`, `border`, `popover`, `popover-foreground`, `foreground`, `background`
|
|
52
52
|
|
|
53
53
|
## Motion
|
|
54
54
|
|
|
@@ -63,7 +63,7 @@ Use Breadcrumbs to show the user's location inside a hierarchy and provide light
|
|
|
63
63
|
```tsx
|
|
64
64
|
import { BreadcrumbItem, BreadcrumbLink, BreadcrumbPage, Breadcrumbs, BreadcrumbSeparator } from "@sableui/react"
|
|
65
65
|
|
|
66
|
-
<Breadcrumbs><BreadcrumbItem><BreadcrumbLink href="/">Home</BreadcrumbLink></BreadcrumbItem><BreadcrumbSeparator /><BreadcrumbItem><BreadcrumbLink href="/library">Library</BreadcrumbLink></BreadcrumbItem><BreadcrumbSeparator /><BreadcrumbItem><BreadcrumbPage>
|
|
66
|
+
<Breadcrumbs><BreadcrumbItem><BreadcrumbLink href="/">Home</BreadcrumbLink></BreadcrumbItem><BreadcrumbSeparator /><BreadcrumbItem><BreadcrumbLink href="/library">Library</BreadcrumbLink></BreadcrumbItem><BreadcrumbSeparator /><BreadcrumbItem><BreadcrumbPage>Reports</BreadcrumbPage></BreadcrumbItem></Breadcrumbs>
|
|
67
67
|
```
|
|
68
68
|
|
|
69
69
|
### Custom separator
|
|
@@ -88,7 +88,7 @@ Use Button when the user commits an action, submits a form, opens UI, or confirm
|
|
|
88
88
|
```tsx
|
|
89
89
|
import { Button } from "@sableui/react"
|
|
90
90
|
|
|
91
|
-
<Button>
|
|
91
|
+
<Button>Save changes</Button>
|
|
92
92
|
```
|
|
93
93
|
|
|
94
94
|
### Secondary + ghost
|
|
@@ -145,7 +145,7 @@ import { Button, Row } from "@sableui/react"
|
|
|
145
145
|
```tsx
|
|
146
146
|
import { Button, Row } from "@sableui/react"
|
|
147
147
|
|
|
148
|
-
<Row gap={1}><Button variant="secondary">Cancel</Button><Button variant="destructive">Delete
|
|
148
|
+
<Row gap={1}><Button variant="secondary">Cancel</Button><Button variant="destructive">Delete project</Button></Row>
|
|
149
149
|
```
|
|
150
150
|
|
|
151
151
|
### Leading icon
|
|
@@ -228,5 +228,5 @@ import { Button } from "@sableui/react"
|
|
|
228
228
|
```tsx
|
|
229
229
|
import { Banner, Button } from "@sableui/react"
|
|
230
230
|
|
|
231
|
-
<Banner tone="warning" appearance="solid" action={<Button variant="on-color" size="sm">Reconnect</Button>}>
|
|
231
|
+
<Banner tone="warning" appearance="solid" action={<Button variant="on-color" size="sm">Reconnect</Button>}>Calendar sync paused.</Banner>
|
|
232
232
|
```
|
package/llms/components/card.md
CHANGED
|
@@ -83,7 +83,7 @@ Use Card for a discrete thing with its own boundary, such as one product, one no
|
|
|
83
83
|
```tsx
|
|
84
84
|
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@sableui/react"
|
|
85
85
|
|
|
86
|
-
<Card><CardHeader><CardTitle>
|
|
86
|
+
<Card><CardHeader><CardTitle>Studio plan</CardTitle><CardDescription>Up to 10 seats.</CardDescription></CardHeader><CardContent><p className="text-body-md">Every seat gets unlimited projects and shared reports.</p></CardContent></Card>
|
|
87
87
|
```
|
|
88
88
|
|
|
89
89
|
### With a header action
|
|
@@ -91,7 +91,7 @@ import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@sabl
|
|
|
91
91
|
```tsx
|
|
92
92
|
import { Button, Card, CardAction, CardContent, CardHeader, CardTitle, Icon } from "@sableui/react"
|
|
93
93
|
|
|
94
|
-
<Card><CardHeader><CardTitle>
|
|
94
|
+
<Card><CardHeader><CardTitle>Seats</CardTitle><CardAction><Button variant="ghost" size="icon-sm" aria-label="More"><Icon name="ellipsis" /></Button></CardAction></CardHeader><CardContent><p className="text-body-md text-muted-foreground">24 of 100 seats in use.</p></CardContent></Card>
|
|
95
95
|
```
|
|
96
96
|
|
|
97
97
|
### Compact section panel
|
|
@@ -107,7 +107,7 @@ import { Card, CardContent, CardHeader, CardTitle } from "@sableui/react"
|
|
|
107
107
|
```tsx
|
|
108
108
|
import { Badge, Button, Card, CardAction, CardContent, CardDescription, CardFooter, CardHeader, CardTitle } from "@sableui/react"
|
|
109
109
|
|
|
110
|
-
<Card><CardHeader><CardTitle>Midnight Archive</CardTitle><CardDescription>
|
|
110
|
+
<Card><CardHeader><CardTitle>Midnight Archive</CardTitle><CardDescription>Template · 24 pages</CardDescription><CardAction><Badge tone="1">New</Badge></CardAction></CardHeader><CardContent><p className="text-body-sm text-muted-foreground">A project template with a brief, a timeline and a review board.</p></CardContent><CardFooter><Button size="sm">Use template</Button><Button size="sm" variant="ghost">Preview</Button></CardFooter></Card>
|
|
111
111
|
```
|
|
112
112
|
|
|
113
113
|
### Whole card as a link
|
|
@@ -123,7 +123,7 @@ import { Card, CardContent, CardDescription, CardTitle, Icon } from "@sableui/re
|
|
|
123
123
|
```tsx
|
|
124
124
|
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@sableui/react"
|
|
125
125
|
|
|
126
|
-
<Card density="compact"><CardHeader><CardTitle>Revenue</CardTitle><CardDescription>Last 30 days</CardDescription></CardHeader><CardContent><p className="text-heading-3"
|
|
126
|
+
<Card density="compact"><CardHeader><CardTitle>Revenue</CardTitle><CardDescription>Last 30 days</CardDescription></CardHeader><CardContent><p className="text-heading-3">$12,840</p><p className="text-body-sm text-success">+12.8% from previous period</p></CardContent></Card>
|
|
127
127
|
```
|
|
128
128
|
|
|
129
129
|
### List card
|
|
@@ -40,17 +40,17 @@ Use CheckboxCard when an option needs more visual weight, supporting text, or ic
|
|
|
40
40
|
| title | ReactNode | — | The card's primary label (text-title-sm). |
|
|
41
41
|
| description | ReactNode | — | Optional supporting copy beneath the title (text-body-sm, muted). |
|
|
42
42
|
| icon | ReactNode | — | Optional glyph (a solid <Icon>) in the tone colour. Its presence switches to the two-dimensional card RadioCard uses — icon top-left, checkbox top-right, copy below — so the two cards match in one form. |
|
|
43
|
-
| tone | "neutral" \| "
|
|
43
|
+
| tone | "neutral" \| "3" \| "2" \| "1" \| "info" \| "warning" | "neutral" | Semantic colour the checked state carries across the border, checkbox box, and icon. |
|
|
44
44
|
| value | string | — | Names the card inside a group-owned CheckboxGroup: the card is checked when the group's value array includes it. Also the value submitted with a form. Inside a CheckboxGroup, `name` stands in for `value` when `value` is omitted. |
|
|
45
45
|
| checked / onCheckedChange / defaultChecked / disabled | Base UI Checkbox.Root props | — | Standard checkbox state. Without a group-owned value, each card is independent — drive checked/onCheckedChange per item for multi-select. |
|
|
46
46
|
|
|
47
47
|
## Variants
|
|
48
48
|
|
|
49
|
-
- **tone**: neutral,
|
|
49
|
+
- **tone**: neutral, 3, 2, 1, info, warning
|
|
50
50
|
|
|
51
51
|
## Tokens used
|
|
52
52
|
|
|
53
|
-
`input`, `card`, `ring`, `primary`, `primary-foreground`, `accent`, `foreground`, `muted-foreground`, `tone-
|
|
53
|
+
`input`, `card`, `ring`, `primary`, `primary-foreground`, `accent`, `foreground`, `muted-foreground`, `tone-3`, `tone-3-foreground`, `tone-2`, `tone-2-foreground`, `tone-1`, `tone-1-foreground`, `tone-info`, `tone-info-foreground`, `tone-warning`, `tone-warning-foreground`
|
|
54
54
|
|
|
55
55
|
## Accessibility
|
|
56
56
|
|
|
@@ -86,7 +86,7 @@ import { Checkbox, CheckboxCard, CheckboxGroup, Field } from "@sableui/react"
|
|
|
86
86
|
```tsx
|
|
87
87
|
import { CheckboxCard } from "@sableui/react"
|
|
88
88
|
|
|
89
|
-
<CheckboxCard title="Email me a receipt" description="Sent when the
|
|
89
|
+
<CheckboxCard title="Email me a receipt" description="Sent when the payment settles" checked={receipt} onCheckedChange={setReceipt} />
|
|
90
90
|
```
|
|
91
91
|
|
|
92
92
|
### Toned with description
|
|
@@ -94,5 +94,5 @@ import { CheckboxCard } from "@sableui/react"
|
|
|
94
94
|
```tsx
|
|
95
95
|
import { CheckboxCard } from "@sableui/react"
|
|
96
96
|
|
|
97
|
-
<CheckboxCard tone="
|
|
97
|
+
<CheckboxCard tone="1" title="Reports" description="Weekly usage reports by email" defaultChecked />
|
|
98
98
|
```
|
|
@@ -14,7 +14,7 @@ Use CodeBlock for multiline code samples that users may read, inspect, or copy.
|
|
|
14
14
|
|
|
15
15
|
- Do: Give the snippet a filename, or a sentence of surrounding copy, when it helps readers and agents place it.
|
|
16
16
|
- Do: Keep examples complete enough to teach the intended pattern.
|
|
17
|
-
- Do: Wire highlighting once with CodeHighlightProvider and map token colors to semantic tone tokens (keywords → tone-
|
|
17
|
+
- Do: Wire highlighting once with CodeHighlightProvider and map token colors to semantic tone tokens (keywords → tone-1, strings → success, comments → muted-foreground), so code follows the theme instead of a fixed palette.
|
|
18
18
|
- Don't: Do not put short inline identifiers in a CodeBlock; use Code for those.
|
|
19
19
|
- Don't: Do not paste code with the indentation the surrounding file had. A block indented to sit inside your JSX shows the reader leading whitespace that is not part of the example.
|
|
20
20
|
|
|
@@ -112,7 +112,7 @@ import { CommandMenu, CommandMenuGroup, CommandMenuItem } from "@sableui/react"
|
|
|
112
112
|
```tsx
|
|
113
113
|
import { CommandMenu, CommandMenuGroup, CommandMenuItem } from "@sableui/react"
|
|
114
114
|
|
|
115
|
-
<CommandMenu open={open} onOpenChange={setOpen}><CommandMenuGroup label="Create"><CommandMenuItem icon="plus" onSelect={() => createPost()}>New post</CommandMenuItem><CommandMenuItem icon="sparkles" onSelect={() =>
|
|
115
|
+
<CommandMenu open={open} onOpenChange={setOpen}><CommandMenuGroup label="Create"><CommandMenuItem icon="plus" onSelect={() => createPost()}>New post</CommandMenuItem><CommandMenuItem icon="sparkles" onSelect={() => createProject()}>New project</CommandMenuItem></CommandMenuGroup><CommandMenuGroup label="Navigation"><CommandMenuItem icon="home" onSelect={() => navigate("/")}>Home</CommandMenuItem><CommandMenuItem icon="gear" onSelect={() => navigate("/settings")}>Settings</CommandMenuItem></CommandMenuGroup></CommandMenu>
|
|
116
116
|
```
|
|
117
117
|
|
|
118
118
|
### Consumer-owned ranking
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
**Status:** stable
|
|
4
4
|
|
|
5
|
-
Hover/focus-triggered rich preview card over Base UI PreviewCard. Reveals contextual content (a profile,
|
|
5
|
+
Hover/focus-triggered rich preview card over Base UI PreviewCard. Reveals contextual content (a profile, a project summary) from an inline anchor; 20rem-wide surface with delayed open and collision-aware positioning.
|
|
6
6
|
|
|
7
7
|
**Keywords:** context card, rich tooltip, hover card, preview
|
|
8
8
|
|
|
@@ -61,7 +61,7 @@ Use ContextCard to show richer contextual content near a trigger without taking
|
|
|
61
61
|
```tsx
|
|
62
62
|
import { Avatar, ContextCard, ContextCardContent, ContextCardTrigger, Entity } from "@sableui/react"
|
|
63
63
|
|
|
64
|
-
<ContextCard><ContextCardTrigger render={<a href='/u/ada' className='text-title-sm underline-offset-2 hover:underline'>@ada</a>} /><ContextCardContent><Entity className='[--entity-px:0] [--entity-py:0]' leading={<Avatar fallback='AL' size='lg' />} title='Ada Lovelace' subtitle='@ada' /><p className='mt-3 text-body-sm text-muted-foreground'>
|
|
64
|
+
<ContextCard><ContextCardTrigger render={<a href='/u/ada' className='text-title-sm underline-offset-2 hover:underline'>@ada</a>} /><ContextCardContent><Entity className='[--entity-px:0] [--entity-py:0]' leading={<Avatar fallback='AL' size='lg' />} title='Ada Lovelace' subtitle='@ada' /><p className='mt-3 text-body-sm text-muted-foreground'>Product designer. Building tools for small teams.</p></ContextCardContent></ContextCard>
|
|
65
65
|
```
|
|
66
66
|
|
|
67
67
|
### With stat row
|
|
@@ -72,5 +72,5 @@ import { DestructiveActionModal } from "@sableui/react"
|
|
|
72
72
|
```tsx
|
|
73
73
|
import { DestructiveActionModal, Note } from "@sableui/react"
|
|
74
74
|
|
|
75
|
-
<DestructiveActionModal open={open} onOpenChange={setOpen} title='Delete this post?' confirmText='gold rush' confirmLabel='Delete forever' onConfirm={handleDelete}><Note tone='warning'>
|
|
75
|
+
<DestructiveActionModal open={open} onOpenChange={setOpen} title='Delete this post?' confirmText='gold rush' confirmLabel='Delete forever' onConfirm={handleDelete}><Note tone='warning'>People you shared this post with lose access to it.</Note></DestructiveActionModal>
|
|
76
76
|
```
|
|
@@ -107,7 +107,7 @@ import { Button, Carousel, Dialog, DialogContent, DialogTrigger } from "@sableui
|
|
|
107
107
|
```tsx
|
|
108
108
|
import { Button, Dialog, DialogClose, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle, DialogTrigger } from "@sableui/react"
|
|
109
109
|
|
|
110
|
-
<Dialog><DialogTrigger render={<Button>Open</Button>} /><DialogContent><DialogHeader><DialogTitle>
|
|
110
|
+
<Dialog><DialogTrigger render={<Button>Open</Button>} /><DialogContent><DialogHeader><DialogTitle>Plan details</DialogTitle><DialogDescription>Up to 10 seats, billed monthly per seat.</DialogDescription></DialogHeader><DialogFooter><DialogClose render={<Button variant="secondary">Close</Button>} /><DialogClose render={<Button>Upgrade</Button>} /></DialogFooter></DialogContent></Dialog>
|
|
111
111
|
```
|
|
112
112
|
|
|
113
113
|
### Settings form
|
|
@@ -123,5 +123,5 @@ import { Button, Dialog, DialogClose, DialogContent, DialogDescription, DialogFo
|
|
|
123
123
|
```tsx
|
|
124
124
|
import { AlertDialog, AlertDialogClose, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogTitle, AlertDialogTrigger, Button } from "@sableui/react"
|
|
125
125
|
|
|
126
|
-
<AlertDialog><AlertDialogTrigger render={<Button variant="destructive">Delete
|
|
126
|
+
<AlertDialog><AlertDialogTrigger render={<Button variant="destructive">Delete project</Button>} /><AlertDialogContent><AlertDialogHeader><AlertDialogTitle>Delete project?</AlertDialogTitle><AlertDialogDescription>This removes the project and cannot be undone.</AlertDialogDescription></AlertDialogHeader><AlertDialogFooter><AlertDialogClose render={<Button variant="secondary">Cancel</Button>} /><Button variant="destructive" onClick={deleteProject}>Delete project</Button></AlertDialogFooter></AlertDialogContent></AlertDialog>
|
|
127
127
|
```
|
|
@@ -41,7 +41,7 @@ Use DisclosurePicker for one-of-many choices in a docked panel or inspector wher
|
|
|
41
41
|
| DisclosurePickerTrigger | { label?: ReactNode; media?: ReactNode; children?: ReactNode } + Base UI Collapsible.Trigger props | The row. `label` is a muted leading caption on a fixed column so stacked rows align; `media` a leading visual (a ThemePreview tile); children the value, truncated on one line. ArrowDown opens it, and steps into the list once open. |
|
|
42
42
|
| DisclosurePickerPanel | { search?: { value: string; onValueChange(value: string): void; placeholder?: string; label?: string } } + Collapsible.Panel props | Opens beneath the row. `search` opts in to a SearchInput above the list (off by default); it is controlled because the consumer filters, and it is cleared when the row closes. Escape clears a query first, then closes; ArrowDown in the field steps into the list. |
|
|
43
43
|
| DisclosurePickerList | { value: string; onValueChange(value: string): void; aria-label?: string } + div props | A listbox. ArrowUp/ArrowDown, Home/End and type-ahead move focus without applying anything (ArrowUp from the first option returns to the search field); Enter, Space or a click picks the focused option — onValueChange fires once, only when it differs from `value` — and closes the row. Escape closes without a pick. |
|
|
44
|
-
| DisclosurePickerOption | { value: string; children?: ReactNode; media?: ReactNode; note?: ReactNode; disabled?: boolean; textValue?: string } | One option row. `media` is a leading visual (a ThemePreview tile); `note` a muted trailing annotation — options without one show a check when chosen. `disabled` skips it for the keyboard and refuses the pick; `textValue` is what type-ahead matches when the name is not plain text. |
|
|
44
|
+
| DisclosurePickerOption | { value: string; children?: ReactNode; media?: ReactNode; note?: ReactNode; disabled?: boolean; textValue?: string; onRemove?: () => void; removeLabel?: string } | One option row. `media` is a leading visual (a ThemePreview tile); `note` a muted trailing annotation — options without one show a check when chosen. `disabled` skips it for the keyboard and refuses the pick; `textValue` is what type-ahead matches when the name is not plain text. `onRemove` makes the option removable — for entries the person added (an imported preset, a saved font): a trash glyph at the row's end on hover or focus (always on touch), and Delete or Backspace on the focused row; removing never picks, and focus moves to a neighbour first. `removeLabel` is the glyph's tooltip. |
|
|
45
45
|
| DisclosurePickerEmpty | { children?: ReactNode } | The no-match line, rendered in place of the list. |
|
|
46
46
|
| useDisclosurePicker | () => { open: boolean; close(): void; size: "md" \| "xs" } | For a list the picker does not own (a Tree) that should close the row when something is picked. |
|
|
47
47
|
|
|
@@ -73,6 +73,7 @@ Use DisclosurePicker for one-of-many choices in a docked panel or inspector wher
|
|
|
73
73
|
- Why a listbox and not a radio group: a radio group's checked state follows focus, so every arrow press would be a pick — wrong for a choice that opens a confirm, loads a font or resets settings. Base UI ships no standalone listbox (Select is popup-only, Combobox's inline list is focus-in-the-input, Composite is internal), so the keyboard model lives here.
|
|
74
74
|
- Opening from the keyboard (Enter, Space, ArrowDown) moves focus into the panel: the search field when there is one, otherwise the chosen option (or the first). A pointer open focuses the search field on a fine pointer only, so touch does not raise the on-screen keyboard.
|
|
75
75
|
- Escape closes the row without changing the value (clearing a query first) and returns focus to the trigger; a pick does the same. Focus is not pulled back when it has already moved on, e.g. to a confirm dialog the pick opened.
|
|
76
|
+
- A removable option (onRemove) announces aria-keyshortcuts="Delete"; Delete or Backspace removes it and focus moves to the next option (or the previous). The trash glyph is a pointer target only (aria-hidden, not focusable): an option's children are presentational, so a nested button would be unreachable by assistive tech anyway.
|
|
76
77
|
- The panel animates with motion-disclosure, which is static under prefers-reduced-motion or MotionProvider off; the scroll that keeps the row in view is instant, never smooth.
|
|
77
78
|
|
|
78
79
|
## Related
|