@sableui/react 0.9.1 → 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 +95 -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.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.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/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.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/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.meta.js +1 -1
- package/dist/components/tooltip/tooltip.meta.js +2 -2
- package/dist/file-hashes.json +120 -118
- package/dist/foundations/spacing.js +8 -8
- package/dist/index.d.ts +137 -72
- package/dist/index.js +12 -1
- package/dist/lib/chart/types.js +3 -3
- 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 +115 -50
- 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/converting-an-app.md +3 -1
- package/llms/tasks/using-presets.md +4 -0
- package/llms-full.txt +429 -347
- package/llms.txt +7 -7
- package/package.json +4 -4
- package/registry.json +369 -233
- package/scripts/lint-rules.mjs +26 -5
- package/skills/sable/SKILL.md +14 -3
|
@@ -8,10 +8,10 @@ import { Grid } from "../layout/index.js";
|
|
|
8
8
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
9
9
|
var revenue = { label: "Revenue this month", total: "$12,480", change: "+8.2%" };
|
|
10
10
|
var segments = [
|
|
11
|
-
{ label: "
|
|
12
|
-
{ label: "
|
|
13
|
-
{ label: "
|
|
14
|
-
{ label: "
|
|
11
|
+
{ label: "Direct", value: 42, tone: "1" },
|
|
12
|
+
{ label: "Partners", value: 27, tone: "2" },
|
|
13
|
+
{ label: "Referrals", value: 19, tone: "3" },
|
|
14
|
+
{ label: "Resellers", value: 12, tone: "info" }
|
|
15
15
|
];
|
|
16
16
|
function RevenueBreakdownBlock({ className, framed = true }) {
|
|
17
17
|
return /* @__PURE__ */ jsxs(Card, { variant: framed ? "default" : "flat", className: cn("w-full max-w-xs", className), children: [
|
|
@@ -21,7 +21,7 @@ function RevenueBreakdownBlock({ className, framed = true }) {
|
|
|
21
21
|
] }),
|
|
22
22
|
/* @__PURE__ */ jsxs(CardContent, { className: "flex flex-col gap-4 pt-2", children: [
|
|
23
23
|
/* @__PURE__ */ jsx("span", { className: "text-mono-xl", children: revenue.total }),
|
|
24
|
-
/* @__PURE__ */ jsx(SegmentedBar, { label: "Revenue by
|
|
24
|
+
/* @__PURE__ */ jsx(SegmentedBar, { label: "Revenue by channel", segments: [...segments], size: "lg" }),
|
|
25
25
|
/* @__PURE__ */ jsx(Grid, { "aria-hidden": true, minItemWidth: "9.5em", gap: "calc(var(--spacing) * 1.5) calc(var(--spacing) * 4)", children: segments.map((s) => /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 text-body-sm", children: [
|
|
26
26
|
/* @__PURE__ */ jsx(StatusDot, { tone: s.tone }),
|
|
27
27
|
/* @__PURE__ */ jsx("span", { className: "flex-1 text-muted-foreground", children: s.label }),
|
|
@@ -7,9 +7,9 @@ import { Grid, Row } from "../layout/index.js";
|
|
|
7
7
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
8
8
|
var stats = [
|
|
9
9
|
{ label: "Revenue", value: "$18,240", delta: "+8.2%", up: true, note: "vs. $16,857" },
|
|
10
|
-
{ label: "
|
|
11
|
-
{ label: "
|
|
12
|
-
{ label: "
|
|
10
|
+
{ label: "Orders", value: "1,284", delta: "+3.1%", up: true, note: "182 first-time" },
|
|
11
|
+
{ label: "New customers", value: "312", delta: "+12.4%", up: true, note: "Best month yet" },
|
|
12
|
+
{ label: "Conversion", value: "3.4%", delta: "\u22120.2%", up: false, note: "6 open trials" }
|
|
13
13
|
];
|
|
14
14
|
function StatRowBlock({ className }) {
|
|
15
15
|
return /* @__PURE__ */ jsx(Grid, { cols: { base: 2, xl: 4 }, gap: 3, className: cn("w-full", className), children: stats.map((stat) => /* @__PURE__ */ jsxs(Card, { children: [
|
|
@@ -9,9 +9,9 @@ import { Icon } from "../icon/index.js";
|
|
|
9
9
|
import { cn } from "../lib/cn.js";
|
|
10
10
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
11
11
|
var tasks = [
|
|
12
|
-
{ title: "Pick the cover type", tag: "Design", tone: "
|
|
12
|
+
{ title: "Pick the cover type", tag: "Design", tone: "2", done: true },
|
|
13
13
|
{ title: "Wire up checkout", tag: "Engineering", tone: "info", done: false },
|
|
14
|
-
{ title: "Draft launch post", tag: "Launch", tone: "
|
|
14
|
+
{ title: "Draft launch post", tag: "Launch", tone: "1", done: false }
|
|
15
15
|
];
|
|
16
16
|
function TaskListBlock({ className, framed = true, onAddTask }) {
|
|
17
17
|
const [done, setDone] = useState(tasks.map((t) => t.done));
|
|
@@ -32,7 +32,7 @@ function TeamMembersBlock({ className, framed = true, onInvite, onMemberAction }
|
|
|
32
32
|
title: m.name,
|
|
33
33
|
subtitle: m.email,
|
|
34
34
|
action: /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
|
|
35
|
-
/* @__PURE__ */ jsx(Badge, { appearance: m.role === "Pending" ? "outline" : "plain", tone: m.role === "Owner" ? "
|
|
35
|
+
/* @__PURE__ */ jsx(Badge, { appearance: m.role === "Pending" ? "outline" : "plain", tone: m.role === "Owner" ? "1" : "neutral", size: "sm", children: m.role }),
|
|
36
36
|
m.role === "Owner" ? /* @__PURE__ */ jsx("span", { "aria-hidden": true, className: "size-(--control-sm)" }) : /* @__PURE__ */ jsxs(OverflowMenu, { label: `Manage ${m.name}`, size: "icon-sm", children: [
|
|
37
37
|
m.role === "Pending" ? /* @__PURE__ */ jsx(MenuItem, { onClick: () => onMemberAction?.(m.id, "resend"), children: "Resend invite" }) : m.role === "Admin" ? /* @__PURE__ */ jsx(MenuItem, { onClick: () => onMemberAction?.(m.id, "make-member"), children: "Make member" }) : /* @__PURE__ */ jsx(MenuItem, { onClick: () => onMemberAction?.(m.id, "make-admin"), children: "Make admin" }),
|
|
38
38
|
/* @__PURE__ */ jsx(MenuSeparator, {}),
|
|
@@ -5,11 +5,11 @@ import { Entity } from "../components/entity/index.js";
|
|
|
5
5
|
import { Icon } from "../icon/index.js";
|
|
6
6
|
import { cn } from "../lib/cn.js";
|
|
7
7
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
8
|
-
var balance = "
|
|
8
|
+
var balance = "$2,418.50";
|
|
9
9
|
var activity = [
|
|
10
|
-
{ title: "
|
|
11
|
-
{ title: "
|
|
12
|
-
{ title: "
|
|
10
|
+
{ title: "Subscription", detail: "Team plan \xB7 2h ago", amount: "+49.00", tone: "1" },
|
|
11
|
+
{ title: "Refund", detail: "Order 1042 \xB7 Yesterday", amount: "-24.00", tone: "2" },
|
|
12
|
+
{ title: "Payout", detail: "To checking \xB7 Mon", amount: "-850.00", tone: "3" }
|
|
13
13
|
];
|
|
14
14
|
function WalletBlock({ className, framed = true, onSend, onReceive }) {
|
|
15
15
|
return /* @__PURE__ */ jsxs(Card, { variant: framed ? "default" : "flat", className: cn("w-full max-w-xs", className), children: [
|
|
@@ -5,15 +5,15 @@ var walletBlockMeta = {
|
|
|
5
5
|
kind: "card",
|
|
6
6
|
width: { min: "18rem", max: "20rem" },
|
|
7
7
|
summary: "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.",
|
|
8
|
-
intent: "Reach for this for
|
|
8
|
+
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.",
|
|
9
9
|
notes: [
|
|
10
10
|
"The balance is CardTitle at `text-mono-xl` \u2014 tabular figures, never a heading tier \u2014 under its label as CardDescription.",
|
|
11
11
|
"Send is primary and Receive secondary, side by side at equal width: two directions of one action, with sending the riskier and more frequent.",
|
|
12
|
-
"Incoming amounts are `text-success`; outgoing stay muted rather than red, because a
|
|
12
|
+
"Incoming amounts are `text-success`; outgoing stay muted rather than red, because a payout or refund is not an error."
|
|
13
13
|
],
|
|
14
14
|
a11y: [
|
|
15
15
|
"Each activity row's leading swatch is aria-hidden; the title and detail carry the meaning.",
|
|
16
|
-
"Amounts keep their sign in text (+
|
|
16
|
+
"Amounts keep their sign in text (+49.00 / -850.00), so the direction does not depend on colour."
|
|
17
17
|
]
|
|
18
18
|
};
|
|
19
19
|
export {
|
|
@@ -138,7 +138,7 @@ var accordionMeta = {
|
|
|
138
138
|
examples: [
|
|
139
139
|
{
|
|
140
140
|
label: "Single (default)",
|
|
141
|
-
code: '<Accordion defaultValue={["a"]}><AccordionItem value="a"><AccordionTrigger>
|
|
141
|
+
code: '<Accordion defaultValue={["a"]}><AccordionItem value="a"><AccordionTrigger>Can I cancel anytime?</AccordionTrigger><AccordionPanel>Yes \u2014 from billing settings.</AccordionPanel></AccordionItem><AccordionItem value="b"><AccordionTrigger>How much?</AccordionTrigger><AccordionPanel>$16 per seat each month.</AccordionPanel></AccordionItem></Accordion>'
|
|
142
142
|
},
|
|
143
143
|
{
|
|
144
144
|
label: "Multiple open",
|
|
@@ -146,7 +146,7 @@ var accordionMeta = {
|
|
|
146
146
|
},
|
|
147
147
|
{
|
|
148
148
|
label: "Custom indicator (plus-becomes-\xD7)",
|
|
149
|
-
code: '<Accordion defaultValue={["a"]}><AccordionItem value="a"><AccordionTrigger indicator={<Icon name="plus" className="text-xs text-muted-foreground transition-transform [[data-panel-open]_&]:rotate-45" />}>
|
|
149
|
+
code: '<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 \u2014 from billing settings.</AccordionPanel></AccordionItem></Accordion>'
|
|
150
150
|
}
|
|
151
151
|
]
|
|
152
152
|
};
|
|
@@ -133,7 +133,7 @@ var appShellMeta = {
|
|
|
133
133
|
{
|
|
134
134
|
label: "Full frame",
|
|
135
135
|
code: `<AppShell
|
|
136
|
-
banners={<Banner tone="warning">
|
|
136
|
+
banners={<Banner tone="warning">Sync is delayed \u2014 changes may be slow to appear.</Banner>}
|
|
137
137
|
header={<AppHeader title="Studio" />}
|
|
138
138
|
sidebar={
|
|
139
139
|
<Sidebar>
|
|
@@ -152,7 +152,7 @@ var appShellMeta = {
|
|
|
152
152
|
}
|
|
153
153
|
>
|
|
154
154
|
<Region max="feed">
|
|
155
|
-
<PageHeader title="Home" description="Latest posts from
|
|
155
|
+
<PageHeader title="Home" description="Latest posts from people you follow." />
|
|
156
156
|
</Region>
|
|
157
157
|
</AppShell>`
|
|
158
158
|
},
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
// src/components/badge/badge.tsx
|
|
2
2
|
import { cn } from "../../lib/cn.js";
|
|
3
|
+
import { isPaletteColor } from "../../lib/palette.js";
|
|
3
4
|
import { trimLabel } from "../../lib/trim-label.js";
|
|
4
5
|
import { StatusDot } from "../status-dot/index.js";
|
|
5
6
|
import { badgeVariants } from "./badge.variants.js";
|
|
@@ -15,10 +16,18 @@ function Badge({
|
|
|
15
16
|
children,
|
|
16
17
|
...props
|
|
17
18
|
}) {
|
|
18
|
-
return /* @__PURE__ */ jsxs(
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
19
|
+
return /* @__PURE__ */ jsxs(
|
|
20
|
+
"span",
|
|
21
|
+
{
|
|
22
|
+
"data-palette": isPaletteColor(tone) ? tone : void 0,
|
|
23
|
+
className: cn(badgeVariants({ appearance, tone, size }), "[&_svg]:shrink-0", className),
|
|
24
|
+
...props,
|
|
25
|
+
children: [
|
|
26
|
+
dot ? /* @__PURE__ */ jsx(StatusDot, { tone, pulse, size: size === "sm" ? "sm" : "md" }) : icon,
|
|
27
|
+
trimLabel(children)
|
|
28
|
+
]
|
|
29
|
+
}
|
|
30
|
+
);
|
|
22
31
|
}
|
|
23
32
|
Badge.displayName = "Badge";
|
|
24
33
|
export {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// src/components/badge/badge.meta.ts
|
|
2
2
|
var badgeMeta = {
|
|
3
3
|
name: "Badge",
|
|
4
|
-
summary: "Compact static label, set on two axes: appearance (soft, outline, solid, overlay on media, plain text) and tone (neutral or a
|
|
4
|
+
summary: "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.",
|
|
5
5
|
keywords: [
|
|
6
6
|
"badge",
|
|
7
7
|
"tag",
|
|
@@ -22,7 +22,7 @@ var badgeMeta = {
|
|
|
22
22
|
},
|
|
23
23
|
{
|
|
24
24
|
guidance: "do",
|
|
25
|
-
description: "Use tone variants when the badge carries meaning, such as success, warning
|
|
25
|
+
description: "Use tone variants when the badge carries meaning, such as success, warning or destructive, or a decorative tone for a category or plan."
|
|
26
26
|
},
|
|
27
27
|
{
|
|
28
28
|
guidance: "do",
|
|
@@ -73,9 +73,9 @@ var badgeMeta = {
|
|
|
73
73
|
},
|
|
74
74
|
{
|
|
75
75
|
name: "tone",
|
|
76
|
-
type: '"neutral" | "
|
|
76
|
+
type: '"neutral" | "1" | "2" | "3" | "info" | "success" | "warning" | "destructive" | "red" | "orange" | "yellow" | "green" | "teal" | "blue" | "purple" | "pink"',
|
|
77
77
|
default: '"neutral"',
|
|
78
|
-
description: "What it means. Every appearance takes every tone."
|
|
78
|
+
description: "What it means. Every appearance takes every tone. The palette families (red \u2026 pink) are categories with no meaning attached \u2014 tags, labels, project colours \u2014 painted from the theme's generated palette, so they lean toward the brand and read in both modes."
|
|
79
79
|
},
|
|
80
80
|
{
|
|
81
81
|
name: "size",
|
|
@@ -103,10 +103,17 @@ var badgeMeta = {
|
|
|
103
103
|
],
|
|
104
104
|
variants: {
|
|
105
105
|
appearance: ["soft", "outline", "solid", "overlay", "plain"],
|
|
106
|
-
tone: ["neutral", "
|
|
106
|
+
tone: ["neutral", "1", "2", "3", "info", "success", "warning", "destructive", "red", "orange", "yellow", "green", "teal", "blue", "purple", "pink"],
|
|
107
107
|
size: ["sm", "md"]
|
|
108
108
|
},
|
|
109
109
|
tokensUsed: [
|
|
110
|
+
"palette-wash",
|
|
111
|
+
"palette-wash-strong",
|
|
112
|
+
"palette-edge",
|
|
113
|
+
"palette-dot",
|
|
114
|
+
"palette-solid",
|
|
115
|
+
"palette-text",
|
|
116
|
+
"palette-solid-ink",
|
|
110
117
|
"secondary",
|
|
111
118
|
"secondary-foreground",
|
|
112
119
|
"border",
|
|
@@ -114,18 +121,18 @@ var badgeMeta = {
|
|
|
114
121
|
"background",
|
|
115
122
|
"muted",
|
|
116
123
|
"muted-foreground",
|
|
117
|
-
"tone-
|
|
118
|
-
"tone-
|
|
119
|
-
"tone-
|
|
124
|
+
"tone-1",
|
|
125
|
+
"tone-2",
|
|
126
|
+
"tone-3",
|
|
120
127
|
"tone-info",
|
|
121
128
|
"success",
|
|
122
129
|
"tone-warning",
|
|
123
130
|
"destructive",
|
|
124
131
|
"overlay",
|
|
125
132
|
"overlay-foreground",
|
|
126
|
-
"tone-
|
|
127
|
-
"tone-
|
|
128
|
-
"tone-
|
|
133
|
+
"tone-1-foreground",
|
|
134
|
+
"tone-2-foreground",
|
|
135
|
+
"tone-3-foreground",
|
|
129
136
|
"tone-info-foreground",
|
|
130
137
|
"success-foreground",
|
|
131
138
|
"tone-warning-foreground",
|
|
@@ -138,7 +145,11 @@ var badgeMeta = {
|
|
|
138
145
|
examples: [
|
|
139
146
|
{
|
|
140
147
|
label: "Tones",
|
|
141
|
-
code: '<Row gap={1}><Badge tone="
|
|
148
|
+
code: '<Row gap={1}><Badge tone="1">Business</Badge><Badge tone="2">Studio</Badge><Badge tone="3">Starter</Badge></Row>'
|
|
149
|
+
},
|
|
150
|
+
{
|
|
151
|
+
label: "Palette colours (categories)",
|
|
152
|
+
code: '<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>'
|
|
142
153
|
},
|
|
143
154
|
{
|
|
144
155
|
label: "Solid",
|
|
@@ -158,7 +169,7 @@ var badgeMeta = {
|
|
|
158
169
|
},
|
|
159
170
|
{
|
|
160
171
|
label: "Metadata row",
|
|
161
|
-
code: '<Row gap={1}><Badge>12
|
|
172
|
+
code: '<Row gap={1}><Badge>12 projects</Badge><Badge appearance="outline">Draft</Badge><Badge tone="info" icon={<Icon name="info" />}>Curated</Badge></Row>'
|
|
162
173
|
},
|
|
163
174
|
{
|
|
164
175
|
label: "Semantic state",
|
|
@@ -1,64 +1,78 @@
|
|
|
1
1
|
// src/components/badge/badge.variants.ts
|
|
2
2
|
import { cva } from "class-variance-authority";
|
|
3
|
-
|
|
3
|
+
import { PALETTE_COLORS } from "../../lib/palette.js";
|
|
4
|
+
var BADGE_TONES = ["neutral", "1", "2", "3", "info", "success", "warning", "destructive", ...PALETTE_COLORS];
|
|
4
5
|
var BADGE_APPEARANCES = ["soft", "outline", "solid", "overlay", "plain"];
|
|
6
|
+
var FAMILY = {
|
|
7
|
+
soft: "bg-palette-wash text-palette-text",
|
|
8
|
+
outline: "border border-palette-edge text-palette-text",
|
|
9
|
+
solid: "bg-palette-solid text-palette-solid-ink",
|
|
10
|
+
overlay: "bg-palette-solid text-palette-solid-ink",
|
|
11
|
+
plain: "text-foreground"
|
|
12
|
+
};
|
|
13
|
+
var families = (appearance) => Object.fromEntries(PALETTE_COLORS.map((color) => [color, FAMILY[appearance]]));
|
|
5
14
|
var MATRIX = {
|
|
6
15
|
// The ink is the tone pulled a quarter of the way to the page's own ink. The
|
|
7
16
|
// raw tone clears 4.5:1 on the page, but on its own 15% wash it did not
|
|
8
|
-
// (light info 4.2:1, dark
|
|
17
|
+
// (light info 4.2:1, dark tone 1 3.6:1, most of Verdant's tones ~4.1:1).
|
|
9
18
|
// Mixing toward --foreground moves it AWAY from the wash in both modes and
|
|
10
19
|
// every theme, and keeps the hue. Status tones mix from their -text token,
|
|
11
20
|
// not the fill: dark fills now sit low enough for a white label, and ink
|
|
12
21
|
// mixed from them fell under 4.5:1 (Meridian dark destructive, 3.8:1).
|
|
13
22
|
soft: {
|
|
14
23
|
neutral: "bg-secondary text-secondary-foreground",
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
24
|
+
"3": "bg-tone-3/15 text-[color-mix(in_oklch,var(--tone-3)_75%,var(--foreground))]",
|
|
25
|
+
"2": "bg-tone-2/15 text-[color-mix(in_oklch,var(--tone-2)_75%,var(--foreground))]",
|
|
26
|
+
"1": "bg-tone-1/15 text-[color-mix(in_oklch,var(--tone-1)_75%,var(--foreground))]",
|
|
18
27
|
info: "bg-tone-info/15 text-[color-mix(in_oklch,var(--tone-info-text)_75%,var(--foreground))]",
|
|
19
28
|
success: "bg-success/15 text-[color-mix(in_oklch,var(--success-text)_75%,var(--foreground))]",
|
|
20
29
|
warning: "bg-tone-warning/15 text-[color-mix(in_oklch,var(--tone-warning-text)_75%,var(--foreground))]",
|
|
21
|
-
destructive: "bg-destructive/15 text-[color-mix(in_oklch,var(--destructive-text)_75%,var(--foreground))]"
|
|
30
|
+
destructive: "bg-destructive/15 text-[color-mix(in_oklch,var(--destructive-text)_75%,var(--foreground))]",
|
|
31
|
+
...families("soft")
|
|
22
32
|
},
|
|
23
33
|
outline: {
|
|
24
34
|
neutral: "border border-border text-foreground",
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
35
|
+
"3": "border border-tone-3/50 text-tone-3",
|
|
36
|
+
"2": "border border-tone-2/50 text-tone-2",
|
|
37
|
+
"1": "border border-tone-1/50 text-tone-1",
|
|
28
38
|
info: "border border-tone-info/50 text-tone-info",
|
|
29
39
|
success: "border border-success/50 text-success",
|
|
30
40
|
warning: "border border-tone-warning/50 text-tone-warning",
|
|
31
|
-
destructive: "border border-destructive/50 text-destructive"
|
|
41
|
+
destructive: "border border-destructive/50 text-destructive",
|
|
42
|
+
...families("outline")
|
|
32
43
|
},
|
|
33
44
|
solid: {
|
|
34
45
|
neutral: "bg-foreground text-background",
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
46
|
+
"3": "bg-tone-3 text-tone-3-foreground",
|
|
47
|
+
"2": "bg-tone-2 text-tone-2-foreground",
|
|
48
|
+
"1": "bg-tone-1 text-tone-1-foreground",
|
|
38
49
|
info: "bg-tone-info text-tone-info-foreground",
|
|
39
50
|
success: "bg-success text-success-foreground",
|
|
40
51
|
warning: "bg-tone-warning text-tone-warning-foreground",
|
|
41
|
-
destructive: "bg-destructive text-destructive-foreground"
|
|
52
|
+
destructive: "bg-destructive text-destructive-foreground",
|
|
53
|
+
...families("solid")
|
|
42
54
|
},
|
|
43
55
|
overlay: {
|
|
44
56
|
neutral: "bg-overlay/85 text-overlay-foreground",
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
57
|
+
"3": "bg-tone-3 text-tone-3-foreground",
|
|
58
|
+
"2": "bg-tone-2 text-tone-2-foreground",
|
|
59
|
+
"1": "bg-tone-1 text-tone-1-foreground",
|
|
48
60
|
info: "bg-tone-info text-tone-info-foreground",
|
|
49
61
|
success: "bg-success text-success-foreground",
|
|
50
62
|
warning: "bg-tone-warning text-tone-warning-foreground",
|
|
51
|
-
destructive: "bg-destructive text-destructive-foreground"
|
|
63
|
+
destructive: "bg-destructive text-destructive-foreground",
|
|
64
|
+
...families("overlay")
|
|
52
65
|
},
|
|
53
66
|
plain: {
|
|
54
67
|
neutral: "text-muted-foreground",
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
68
|
+
"3": "text-foreground",
|
|
69
|
+
"2": "text-foreground",
|
|
70
|
+
"1": "text-foreground",
|
|
58
71
|
info: "text-foreground",
|
|
59
72
|
success: "text-foreground",
|
|
60
73
|
warning: "text-foreground",
|
|
61
|
-
destructive: "text-destructive"
|
|
74
|
+
destructive: "text-destructive",
|
|
75
|
+
...families("plain")
|
|
62
76
|
}
|
|
63
77
|
};
|
|
64
78
|
var badgeVariants = cva(
|
|
@@ -75,7 +89,7 @@ var badgeVariants = cva(
|
|
|
75
89
|
overlay: "gap-1 border border-transparent",
|
|
76
90
|
plain: "gap-1.5"
|
|
77
91
|
},
|
|
78
|
-
tone: { neutral: "",
|
|
92
|
+
tone: { neutral: "", "1": "", "2": "", "3": "", info: "", success: "", warning: "", destructive: "", red: "", orange: "", yellow: "", green: "", teal: "", blue: "", purple: "", pink: "" },
|
|
79
93
|
size: {
|
|
80
94
|
sm: "text-label-sm",
|
|
81
95
|
md: "text-label-md"
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// src/components/banner/banner.meta.ts
|
|
2
2
|
var bannerMeta = {
|
|
3
3
|
name: "Banner",
|
|
4
|
-
summary: "Full-width, page-level announcement bar. A tone (neutral, info, success, warning,
|
|
4
|
+
summary: "Full-width, page-level announcement bar. A tone (neutral, info, success, warning, the decorative 1, destructive) \xD7 an appearance (soft tint or loud solid fill), and an optional leading scope label. Centers its message, or \u2014 with a trailing action \u2014 switches to a leading-text + trailing-button layout. Optionally sticky and dismissible.",
|
|
5
5
|
keywords: [
|
|
6
6
|
"banner",
|
|
7
7
|
"announcement",
|
|
@@ -67,9 +67,9 @@ var bannerMeta = {
|
|
|
67
67
|
props: [
|
|
68
68
|
{
|
|
69
69
|
name: "tone",
|
|
70
|
-
type: '"neutral" | "info" | "success" | "warning" | "
|
|
70
|
+
type: '"neutral" | "info" | "success" | "warning" | "1" | "destructive"',
|
|
71
71
|
default: '"neutral"',
|
|
72
|
-
description: "Neutral surface or a tone that encodes the announcement's intent (info / success / warning /
|
|
72
|
+
description: "Neutral surface or a tone that encodes the announcement's intent (info / success / warning / the decorative 1 / destructive)."
|
|
73
73
|
},
|
|
74
74
|
{
|
|
75
75
|
name: "appearance",
|
|
@@ -112,7 +112,7 @@ var bannerMeta = {
|
|
|
112
112
|
}
|
|
113
113
|
],
|
|
114
114
|
variants: {
|
|
115
|
-
tone: ["neutral", "info", "success", "warning", "
|
|
115
|
+
tone: ["neutral", "info", "success", "warning", "1", "destructive"],
|
|
116
116
|
appearance: ["soft", "solid"]
|
|
117
117
|
},
|
|
118
118
|
tokensUsed: [
|
|
@@ -126,8 +126,8 @@ var bannerMeta = {
|
|
|
126
126
|
"success-foreground",
|
|
127
127
|
"tone-warning",
|
|
128
128
|
"tone-warning-foreground",
|
|
129
|
-
"tone-
|
|
130
|
-
"tone-
|
|
129
|
+
"tone-1",
|
|
130
|
+
"tone-1-foreground",
|
|
131
131
|
"destructive",
|
|
132
132
|
"destructive-foreground"
|
|
133
133
|
],
|
|
@@ -143,7 +143,7 @@ var bannerMeta = {
|
|
|
143
143
|
},
|
|
144
144
|
{
|
|
145
145
|
label: "Solid (loud)",
|
|
146
|
-
code: '<Banner tone="destructive" appearance="solid" live="assertive">
|
|
146
|
+
code: '<Banner tone="destructive" appearance="solid" live="assertive">Payments are down. Checkout and upgrades are temporarily disabled.</Banner>'
|
|
147
147
|
},
|
|
148
148
|
{
|
|
149
149
|
label: "Success",
|
|
@@ -159,7 +159,7 @@ var bannerMeta = {
|
|
|
159
159
|
},
|
|
160
160
|
{
|
|
161
161
|
label: "Recoverable warning",
|
|
162
|
-
code: '<Banner tone="warning" action={<Button variant="outline" size="sm">Reconnect</Button>}>
|
|
162
|
+
code: '<Banner tone="warning" action={<Button variant="outline" size="sm">Reconnect</Button>}>Calendar sync paused.</Banner>'
|
|
163
163
|
},
|
|
164
164
|
{
|
|
165
165
|
label: "App-shell outage",
|
|
@@ -9,7 +9,7 @@ var bannerVariants = cva(
|
|
|
9
9
|
info: "",
|
|
10
10
|
success: "",
|
|
11
11
|
warning: "",
|
|
12
|
-
|
|
12
|
+
"1": "",
|
|
13
13
|
destructive: ""
|
|
14
14
|
},
|
|
15
15
|
appearance: {
|
|
@@ -23,14 +23,14 @@ var bannerVariants = cva(
|
|
|
23
23
|
{ tone: "info", appearance: "soft", class: "bg-tone-info/15 text-foreground" },
|
|
24
24
|
{ tone: "success", appearance: "soft", class: "bg-success/15 text-foreground" },
|
|
25
25
|
{ tone: "warning", appearance: "soft", class: "bg-tone-warning/15 text-foreground" },
|
|
26
|
-
{ tone: "
|
|
26
|
+
{ tone: "1", appearance: "soft", class: "bg-tone-1/15 text-foreground" },
|
|
27
27
|
{ tone: "destructive", appearance: "soft", class: "bg-destructive/15 text-foreground" },
|
|
28
28
|
// Solid — the full tone fill with its paired ink, for loud states.
|
|
29
29
|
{ tone: "neutral", appearance: "solid", class: "bg-foreground text-background" },
|
|
30
30
|
{ tone: "info", appearance: "solid", class: "bg-tone-info text-tone-info-foreground" },
|
|
31
31
|
{ tone: "success", appearance: "solid", class: "bg-success text-success-foreground" },
|
|
32
32
|
{ tone: "warning", appearance: "solid", class: "bg-tone-warning text-tone-warning-foreground" },
|
|
33
|
-
{ tone: "
|
|
33
|
+
{ tone: "1", appearance: "solid", class: "bg-tone-1 text-tone-1-foreground" },
|
|
34
34
|
{ tone: "destructive", appearance: "solid", class: "bg-destructive text-destructive-foreground" }
|
|
35
35
|
],
|
|
36
36
|
defaultVariants: {
|
|
@@ -164,7 +164,7 @@ var barChartMeta = {
|
|
|
164
164
|
},
|
|
165
165
|
{
|
|
166
166
|
name: "negativeTone",
|
|
167
|
-
type: '"
|
|
167
|
+
type: '"1" | "2" | "3" | "info" | "warning" | "primary" | "neutral" | "success" | "destructive"',
|
|
168
168
|
description: "Colour negative values with this tone."
|
|
169
169
|
},
|
|
170
170
|
{
|
|
@@ -181,9 +181,9 @@ var barChartMeta = {
|
|
|
181
181
|
}
|
|
182
182
|
],
|
|
183
183
|
tokensUsed: [
|
|
184
|
-
"tone-
|
|
185
|
-
"tone-
|
|
186
|
-
"tone-
|
|
184
|
+
"tone-1",
|
|
185
|
+
"tone-2",
|
|
186
|
+
"tone-3",
|
|
187
187
|
"tone-info",
|
|
188
188
|
"tone-warning",
|
|
189
189
|
"primary",
|
|
@@ -98,7 +98,7 @@ var breadcrumbsMeta = {
|
|
|
98
98
|
examples: [
|
|
99
99
|
{
|
|
100
100
|
label: "Three-level trail",
|
|
101
|
-
code: '<Breadcrumbs><BreadcrumbItem><BreadcrumbLink href="/">Home</BreadcrumbLink></BreadcrumbItem><BreadcrumbSeparator /><BreadcrumbItem><BreadcrumbLink href="/library">Library</BreadcrumbLink></BreadcrumbItem><BreadcrumbSeparator /><BreadcrumbItem><BreadcrumbPage>
|
|
101
|
+
code: '<Breadcrumbs><BreadcrumbItem><BreadcrumbLink href="/">Home</BreadcrumbLink></BreadcrumbItem><BreadcrumbSeparator /><BreadcrumbItem><BreadcrumbLink href="/library">Library</BreadcrumbLink></BreadcrumbItem><BreadcrumbSeparator /><BreadcrumbItem><BreadcrumbPage>Reports</BreadcrumbPage></BreadcrumbItem></Breadcrumbs>'
|
|
102
102
|
},
|
|
103
103
|
{
|
|
104
104
|
label: "Custom separator",
|
|
@@ -232,7 +232,7 @@ var buttonMeta = {
|
|
|
232
232
|
"loading sets aria-busy and disables activation (disabled on a native button, aria-disabled on a render element) so the action can't double-fire."
|
|
233
233
|
],
|
|
234
234
|
examples: [
|
|
235
|
-
{ label: "Primary", code: "<Button>
|
|
235
|
+
{ label: "Primary", code: "<Button>Save changes</Button>" },
|
|
236
236
|
{
|
|
237
237
|
label: "Secondary + ghost",
|
|
238
238
|
code: '<Row gap={1}><Button variant="secondary">Cancel</Button><Button variant="ghost">Skip</Button></Row>'
|
|
@@ -259,7 +259,7 @@ var buttonMeta = {
|
|
|
259
259
|
},
|
|
260
260
|
{
|
|
261
261
|
label: "Destructive with confirmation copy",
|
|
262
|
-
code: '<Row gap={1}><Button variant="secondary">Cancel</Button><Button variant="destructive">Delete
|
|
262
|
+
code: '<Row gap={1}><Button variant="secondary">Cancel</Button><Button variant="destructive">Delete project</Button></Row>'
|
|
263
263
|
},
|
|
264
264
|
{
|
|
265
265
|
label: "Leading icon",
|
|
@@ -302,7 +302,7 @@ var buttonMeta = {
|
|
|
302
302
|
},
|
|
303
303
|
{
|
|
304
304
|
label: "Action in a solid Banner",
|
|
305
|
-
code: '<Banner tone="warning" appearance="solid" action={<Button variant="on-color" size="sm">Reconnect</Button>}>
|
|
305
|
+
code: '<Banner tone="warning" appearance="solid" action={<Button variant="on-color" size="sm">Reconnect</Button>}>Calendar sync paused.</Banner>'
|
|
306
306
|
}
|
|
307
307
|
]
|
|
308
308
|
};
|
|
@@ -11,9 +11,9 @@ var DENSITY_PAD = {
|
|
|
11
11
|
compact: "calc(var(--spacing) * 4)"
|
|
12
12
|
// p-4
|
|
13
13
|
};
|
|
14
|
-
var INTERACTIVE_BASE = "[&:is(a[href],button)]:motion-interactive [&:is(a[href],button)]:cursor-pointer [&:is(button)]:w-full [&:is(button)]:text-start focus-visible:
|
|
14
|
+
var INTERACTIVE_BASE = "[&:is(a[href],button)]:motion-interactive [&:is(a[href],button)]:cursor-pointer [&:is(button)]:w-full [&:is(button)]:text-start focus-visible:ring-2 focus-visible:ring-ring";
|
|
15
15
|
var INTERACTIVE_HOVER = {
|
|
16
|
-
default: "[&:is(a[href],button)]:hover:
|
|
16
|
+
default: "[&:is(a[href],button)]:hover:outline-border-strong [&:is(a[href],button)]:hover:shadow-md",
|
|
17
17
|
flat: "[&:is(a[href],button)]:hover:bg-muted"
|
|
18
18
|
};
|
|
19
19
|
function Card({
|
|
@@ -41,9 +41,15 @@ function Card({
|
|
|
41
41
|
// sable-frame — at Sable's paddings the subtraction runs to ~0, and a
|
|
42
42
|
// near-square box inside a rounded card reads as another system.
|
|
43
43
|
// A field or panel inside reads it (ChatComposer does).
|
|
44
|
-
"[--card-inner-radius:max(var(--radius-sm),calc(var(--radius-lg)-var(--card-p)
|
|
44
|
+
"[--card-inner-radius:max(var(--radius-sm),calc(var(--radius-lg)-var(--card-p)))]",
|
|
45
45
|
// Declares its surface so sable-well / sable-surface-interactive inside derive from the card.
|
|
46
|
-
|
|
46
|
+
// The edge is an outline drawn 1px INSIDE the box, not a border: it
|
|
47
|
+
// takes no space, so the card's padding is whole baseline steps and
|
|
48
|
+
// its content starts on the rhythm instead of a pixel below it. It
|
|
49
|
+
// paints above the card's in-flow content (a flush table's row fill);
|
|
50
|
+
// a positioned child with a fill of its own would cover it, which no
|
|
51
|
+
// card part has. DESIGN.md → Vertical rhythm.
|
|
52
|
+
variant === "default" && "outline-1 -outline-offset-1 outline-border bg-card shadow-sm [--sable-surface-bg:var(--card)]",
|
|
47
53
|
// A CardList or a flush CardContent (an edge-to-edge Table) runs its
|
|
48
54
|
// rows to the card's edges, and a row's hover fill or a TableFooter's
|
|
49
55
|
// tint would otherwise poke square corners out past the card's
|
|
@@ -154,12 +160,15 @@ function CardList({
|
|
|
154
160
|
{
|
|
155
161
|
"data-slot": "card-list",
|
|
156
162
|
className: cn(
|
|
157
|
-
"flex flex-col
|
|
163
|
+
"flex flex-col [--entity-radius:0px] [--entity-px:var(--card-p,--spacing(6))] [--entity-py:calc(var(--card-p,--spacing(6))/2)]",
|
|
158
164
|
// Between rows the half padding is enough (each side of a hairline
|
|
159
165
|
// gets it); against the card's own edge the first and last rows take
|
|
160
166
|
// the full card padding, so the list is inset like every other card.
|
|
161
167
|
"*:first:pt-[var(--card-p,--spacing(6))] *:last:pb-[var(--card-p,--spacing(6))]",
|
|
162
|
-
|
|
168
|
+
// Hairlines between rows are inset shadows, not borders: a 1px border
|
|
169
|
+
// per row pushed every row below it a pixel further off the rhythm.
|
|
170
|
+
"[&>*+*]:shadow-[inset_0_1px_0_var(--border)]",
|
|
171
|
+
"[[data-slot=card-header]+&]:mt-[calc(var(--card-p,--spacing(6))/2)] [[data-slot=card-header]+&>*:first-child]:shadow-[inset_0_1px_0_var(--border)]",
|
|
163
172
|
className
|
|
164
173
|
),
|
|
165
174
|
...props
|
|
@@ -182,7 +191,7 @@ function CardFooter({
|
|
|
182
191
|
className: cn(
|
|
183
192
|
"flex items-center gap-2 p-[var(--card-p,--spacing(6))] pt-0",
|
|
184
193
|
"[[data-slot=card-header]+&]:pt-[var(--card-p,--spacing(6))]",
|
|
185
|
-
"[:is([data-slot=card-list],[data-slot=card-content][data-flush])+&]:
|
|
194
|
+
"[:is([data-slot=card-list],[data-slot=card-content][data-flush])+&]:shadow-[inset_0_1px_0_var(--border)] [:is([data-slot=card-list],[data-slot=card-content][data-flush])+&]:pt-[var(--card-p,--spacing(6))]",
|
|
186
195
|
className,
|
|
187
196
|
stacked && "mt-auto flex-col-reverse items-stretch justify-start"
|
|
188
197
|
),
|