@tangle-network/ui 11.35.0 → 11.37.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/CHANGELOG.md +20 -0
- package/README.md +1 -1
- package/dist/code-presentation.d.ts +2 -0
- package/dist/code-presentation.js +2 -0
- package/dist/index.d.ts +8 -5
- package/dist/index.js +6 -3
- package/dist/lib/code-presentation.d.ts +92 -0
- package/dist/lib/code-presentation.js +437 -0
- package/dist/lib/control-presentation.d.ts +34 -1
- package/dist/lib/control-presentation.js +1 -1
- package/dist/lib/focus.d.ts +2 -2
- package/dist/lib/focus.js +3 -2
- package/dist/lib/motion.d.ts +4 -0
- package/dist/lib/motion.js +7 -0
- package/dist/lib/surface-motion.js +105 -0
- package/dist/markdown/api-schema.d.ts +9 -0
- package/dist/markdown/api-schema.js +20 -0
- package/dist/markdown/code-block.d.ts +15 -7
- package/dist/markdown/code-block.js +120 -268
- package/dist/markdown.d.ts +4 -2
- package/dist/markdown.js +4 -2
- package/dist/presentation.d.ts +88 -0
- package/dist/presentation.js +183 -0
- package/dist/primitives/alert-dialog.js +1 -1
- package/dist/primitives/alert.d.ts +1 -2
- package/dist/primitives/button.d.ts +2 -5
- package/dist/primitives/button.js +5 -31
- package/dist/primitives/card.js +3 -7
- package/dist/primitives/code-block.d.ts +1 -1
- package/dist/primitives/date-picker.d.ts +1 -1
- package/dist/primitives/dialog.js +29 -16
- package/dist/primitives/empty-state.js +6 -5
- package/dist/primitives/heading.d.ts +1 -0
- package/dist/primitives/heading.js +3 -2
- package/dist/primitives/help-text.js +2 -1
- package/dist/primitives/input.d.ts +1 -4
- package/dist/primitives/input.js +3 -24
- package/dist/primitives/label.js +1 -2
- package/dist/primitives/metric-strip.js +7 -12
- package/dist/primitives/page-header.d.ts +1 -0
- package/dist/primitives/page-header.js +7 -6
- package/dist/primitives/page-shell.d.ts +8 -2
- package/dist/primitives/page-shell.js +21 -2
- package/dist/primitives/pagination.js +1 -1
- package/dist/primitives/popover.js +11 -3
- package/dist/primitives/sheet.js +29 -19
- package/dist/primitives/skeleton.js +1 -1
- package/dist/primitives/status-pill.d.ts +3 -1
- package/dist/primitives/status-pill.js +12 -3
- package/dist/primitives/table.js +10 -9
- package/dist/primitives/tabs.js +3 -12
- package/dist/primitives/tooltip.js +11 -3
- package/dist/primitives.d.ts +3 -2
- package/dist/primitives.js +2 -1
- package/dist/utils.d.ts +1 -1
- package/package.json +20 -5
- package/src/code-presentation.ts +2 -0
- package/src/lib/code-presentation.ts +257 -0
- package/src/lib/control-presentation.ts +2 -4
- package/src/lib/focus.ts +3 -2
- package/src/lib/motion.ts +7 -0
- package/src/lib/surface-motion.tsx +85 -0
- package/src/markdown/api-presentation.test.tsx +63 -0
- package/src/markdown/api-schema.tsx +9 -0
- package/src/markdown/code-block.tsx +54 -185
- package/src/markdown/index.ts +2 -1
- package/src/presentation.ts +205 -0
- package/src/primitives/alert.tsx +1 -2
- package/src/primitives/button.tsx +6 -41
- package/src/primitives/card.tsx +5 -10
- package/src/primitives/checkbox-separator-sheet-tooltip.test.tsx +2 -1
- package/src/primitives/code-block.tsx +1 -1
- package/src/primitives/control-presentation.test.tsx +2 -7
- package/src/primitives/dialog.tsx +19 -18
- package/src/primitives/empty-state.tsx +6 -5
- package/src/primitives/heading.tsx +4 -2
- package/src/primitives/help-text.tsx +3 -2
- package/src/primitives/input.tsx +3 -31
- package/src/primitives/label.tsx +2 -4
- package/src/primitives/metric-strip.tsx +8 -17
- package/src/primitives/page-header.tsx +8 -5
- package/src/primitives/page-shell.tsx +13 -2
- package/src/primitives/popover.tsx +6 -8
- package/src/primitives/sheet.tsx +16 -11
- package/src/primitives/skeleton.tsx +1 -1
- package/src/primitives/status-pill.test.tsx +1 -0
- package/src/primitives/status-pill.tsx +10 -4
- package/src/primitives/table.tsx +10 -9
- package/src/primitives/tabs.tsx +5 -17
- package/src/primitives/tooltip.tsx +6 -5
- package/src/styles/compat.css +12 -0
- package/src/styles/presentation.css +38 -0
- package/src/primitives/page-shell.test.tsx +0 -24
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
import { controlMotion, surfaceMotion } from "./lib/motion.js";
|
|
2
|
+
import { ixControl, ixControlSoft, ixSelected, ixTabUnderline } from "./lib/interaction.js";
|
|
3
|
+
import { focusFieldInvalid, focusRing } from "./lib/focus.js";
|
|
4
|
+
import { cn } from "./lib/utils.js";
|
|
5
|
+
import { controlHeight, controlRadius, controlSizes, controlSquare, controlText, fieldPresentation, fieldSizes, fieldTouchText } from "./lib/control-presentation.js";
|
|
6
|
+
import { cva } from "class-variance-authority";
|
|
7
|
+
//#region src/presentation.ts
|
|
8
|
+
/** React-free presentation. Consumers scan this published source with Tailwind. */
|
|
9
|
+
const buttonVariants = cva(`inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-lg font-medium ${controlMotion} ${focusRing} disabled:pointer-events-none disabled:opacity-50 aria-disabled:cursor-not-allowed aria-disabled:opacity-50 motion-reduce:active:scale-100 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0`, {
|
|
10
|
+
variants: {
|
|
11
|
+
variant: {
|
|
12
|
+
default: `bg-primary text-primary-foreground hover:bg-primary/90 active:scale-[0.97] ${ixControl}`,
|
|
13
|
+
destructive: `bg-destructive text-destructive-foreground hover:bg-destructive/90 active:scale-[0.97] ${ixControl}`,
|
|
14
|
+
outline: `border border-border bg-card hover:bg-muted active:scale-[0.97] text-foreground ${ixControl}`,
|
|
15
|
+
secondary: `bg-muted border border-border text-foreground hover:bg-muted/80 active:scale-[0.97] ${ixControl}`,
|
|
16
|
+
ghost: `hover:text-foreground text-muted-foreground border border-transparent ${ixControlSoft}`,
|
|
17
|
+
link: `text-[var(--accent-text)] underline-offset-4 hover:underline ${ixControlSoft}`,
|
|
18
|
+
sandbox: `bg-[var(--btn-primary-bg)] text-[var(--btn-primary-text)] border border-[var(--border-accent)] hover:bg-[var(--btn-primary-hover)] active:scale-[0.97] ${ixControl}`
|
|
19
|
+
},
|
|
20
|
+
size: {
|
|
21
|
+
default: `${controlHeight.md} ${controlText.md} ${controlRadius.md} px-4 py-2`,
|
|
22
|
+
md: `${controlHeight.md} ${controlText.md} ${controlRadius.md} px-4 py-2`,
|
|
23
|
+
sm: `${controlHeight.sm} ${controlText.sm} ${controlRadius.sm} px-3`,
|
|
24
|
+
lg: `${controlHeight.lg} ${controlText.lg} ${controlRadius.lg} px-7`,
|
|
25
|
+
display: "tangle-control-display",
|
|
26
|
+
xl: "h-13 rounded-xl px-9 text-base",
|
|
27
|
+
icon: `${controlSquare.md} ${controlText.md} ${controlRadius.md}`,
|
|
28
|
+
"icon-sm": `${controlSquare.sm} ${controlText.sm} ${controlRadius.sm}`,
|
|
29
|
+
"icon-lg": `${controlSquare.lg} ${controlText.lg} ${controlRadius.lg}`,
|
|
30
|
+
...controlSizes
|
|
31
|
+
}
|
|
32
|
+
},
|
|
33
|
+
defaultVariants: {
|
|
34
|
+
variant: "default",
|
|
35
|
+
size: "default"
|
|
36
|
+
}
|
|
37
|
+
});
|
|
38
|
+
const inputVariants = cva(cn("flex w-full border py-1 placeholder:text-[var(--text-dim)] disabled:cursor-not-allowed disabled:opacity-50 file:border-0 file:bg-transparent file:font-medium", fieldPresentation, fieldTouchText), {
|
|
39
|
+
variants: {
|
|
40
|
+
variant: {
|
|
41
|
+
default: "",
|
|
42
|
+
sandbox: "",
|
|
43
|
+
error: focusFieldInvalid
|
|
44
|
+
},
|
|
45
|
+
size: {
|
|
46
|
+
default: fieldSizes.md,
|
|
47
|
+
md: fieldSizes.md,
|
|
48
|
+
sm: fieldSizes.sm,
|
|
49
|
+
lg: fieldSizes.lg,
|
|
50
|
+
compact: cn(fieldSizes.md, controlSizes.compact),
|
|
51
|
+
touch: cn(fieldSizes.md, controlSizes.touch)
|
|
52
|
+
}
|
|
53
|
+
},
|
|
54
|
+
defaultVariants: {
|
|
55
|
+
variant: "default",
|
|
56
|
+
size: "default"
|
|
57
|
+
}
|
|
58
|
+
});
|
|
59
|
+
const tablePresentation = {
|
|
60
|
+
root: "w-full caption-bottom text-sm",
|
|
61
|
+
wrapper: "relative w-full overflow-auto",
|
|
62
|
+
head: "[&_tr]:border-b",
|
|
63
|
+
body: "[&_tr:last-child]:border-0",
|
|
64
|
+
footer: "border-t bg-card font-medium [&>tr]:last:border-b-0",
|
|
65
|
+
row: `border-border border-b ${controlMotion} hover:bg-muted/50 data-[state=selected]:bg-muted/50`,
|
|
66
|
+
columnHeader: "h-12 px-4 text-left align-middle font-medium text-muted-foreground [&:has([role=checkbox])]:pr-0",
|
|
67
|
+
cell: "p-4 align-middle [&:has([role=checkbox])]:pr-0",
|
|
68
|
+
caption: "mt-4 text-muted-foreground text-sm"
|
|
69
|
+
};
|
|
70
|
+
const emptyStatePresentation = {
|
|
71
|
+
root: "flex flex-col items-center justify-center px-4 py-16 text-center",
|
|
72
|
+
icon: "mb-4 rounded-full bg-muted p-4 text-muted-foreground",
|
|
73
|
+
title: "font-semibold text-lg",
|
|
74
|
+
description: "mt-2 max-w-sm text-muted-foreground text-sm",
|
|
75
|
+
action: "mt-6"
|
|
76
|
+
};
|
|
77
|
+
const metricPresentation = {
|
|
78
|
+
strip: "grid min-w-0 rounded-[var(--radius-lg)] border border-border bg-card shadow-[var(--shadow-card)]",
|
|
79
|
+
item: "min-w-0 border-border p-4 sm:p-5",
|
|
80
|
+
value: "mt-1 whitespace-normal [overflow-wrap:anywhere] font-semibold text-xl tabular-nums tracking-tight lg:text-2xl",
|
|
81
|
+
label: "flex min-w-0 flex-wrap items-center gap-2 text-muted-foreground text-sm",
|
|
82
|
+
labelText: "min-w-0 whitespace-normal [overflow-wrap:anywhere]",
|
|
83
|
+
hint: "mt-0.5 whitespace-normal [overflow-wrap:anywhere] text-[var(--text-dim)] text-xs"
|
|
84
|
+
};
|
|
85
|
+
const metricLayouts = {
|
|
86
|
+
3: "grid-cols-2 sm:grid-cols-3 max-sm:[&>div:not(:nth-child(2n+1))]:border-l sm:[&>div:not(:nth-child(3n+1))]:border-l",
|
|
87
|
+
4: "grid-cols-2 sm:grid-cols-4 max-sm:[&>div:not(:nth-child(2n+1))]:border-l sm:[&>div:not(:nth-child(4n+1))]:border-l",
|
|
88
|
+
5: "grid-cols-2 sm:grid-cols-3 lg:grid-cols-5 max-sm:[&>div:not(:nth-child(2n+1))]:border-l sm:max-lg:[&>div:not(:nth-child(3n+1))]:border-l lg:[&>div:not(:nth-child(5n+1))]:border-l",
|
|
89
|
+
6: "grid-cols-2 sm:grid-cols-3 lg:grid-cols-6 max-sm:[&>div:not(:nth-child(2n+1))]:border-l sm:max-lg:[&>div:not(:nth-child(3n+1))]:border-l lg:[&>div:not(:nth-child(6n+1))]:border-l"
|
|
90
|
+
};
|
|
91
|
+
const dialogPresentation = {
|
|
92
|
+
overlay: "fixed inset-0 z-50 bg-black/40",
|
|
93
|
+
transition: surfaceMotion,
|
|
94
|
+
position: "fixed top-[50%] left-[50%] z-50 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%]",
|
|
95
|
+
surface: "gap-4 rounded-lg border bg-card p-6 shadow-lg",
|
|
96
|
+
close: `absolute top-4 right-4 rounded-sm opacity-70 ${controlMotion} hover:opacity-100 focus-visible:opacity-100 disabled:pointer-events-none data-[state=open]:bg-accent data-[state=open]:text-muted-foreground`,
|
|
97
|
+
header: "flex flex-col space-y-1.5 text-center sm:text-left",
|
|
98
|
+
footer: "flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2",
|
|
99
|
+
title: "font-semibold text-lg leading-none tracking-tight",
|
|
100
|
+
description: "text-muted-foreground text-sm"
|
|
101
|
+
};
|
|
102
|
+
/** Native-dialog adapter for Hono/static markup. Radix remains the React Dialog/Sheet owner. */
|
|
103
|
+
function bindDialog(dialog, trigger) {
|
|
104
|
+
const sync = () => trigger.setAttribute("aria-expanded", String(dialog.open));
|
|
105
|
+
const show = () => {
|
|
106
|
+
if (!dialog.open) dialog.showModal();
|
|
107
|
+
sync();
|
|
108
|
+
};
|
|
109
|
+
const close = () => {
|
|
110
|
+
sync();
|
|
111
|
+
trigger.focus();
|
|
112
|
+
};
|
|
113
|
+
const click = (event) => {
|
|
114
|
+
const target = event.target;
|
|
115
|
+
if (target instanceof Element && target.closest("[data-dialog-close]")) dialog.close();
|
|
116
|
+
};
|
|
117
|
+
const key = (event) => {
|
|
118
|
+
if (event.key !== "Tab" || !dialog.open) return;
|
|
119
|
+
const candidates = [...dialog.querySelectorAll("*")].filter((element) => (element.tabIndex >= 0 || element.isContentEditable && !element.hasAttribute("tabindex")) && !element.matches(":disabled") && !element.closest("[inert]") && element.getClientRects().length > 0 && getComputedStyle(element).visibility === "visible");
|
|
120
|
+
const radio = (element) => element instanceof HTMLInputElement && element.type === "radio" && !!element.name;
|
|
121
|
+
const sameRadioGroup = (a, b) => radio(a) && radio(b) && a.name === b.name && a.form === b.form && a.getRootNode() === b.getRootNode();
|
|
122
|
+
const stops = candidates.filter((element) => {
|
|
123
|
+
if (!radio(element)) return true;
|
|
124
|
+
const group = candidates.filter((candidate) => sameRadioGroup(element, candidate));
|
|
125
|
+
return element === (group.find((candidate) => candidate.checked) ?? (event.shiftKey ? group.at(-1) : group[0]));
|
|
126
|
+
}).sort((a, b) => (a.tabIndex > 0 ? a.tabIndex : Infinity) - (b.tabIndex > 0 ? b.tabIndex : Infinity));
|
|
127
|
+
const first = stops[0], last = stops.at(-1), active = document.activeElement;
|
|
128
|
+
if (!first) {
|
|
129
|
+
event.preventDefault();
|
|
130
|
+
dialog.focus();
|
|
131
|
+
return;
|
|
132
|
+
}
|
|
133
|
+
const atBoundary = (boundary) => active === boundary || active instanceof Element && sameRadioGroup(active, boundary);
|
|
134
|
+
if (active === dialog || (event.shiftKey ? atBoundary(first) : atBoundary(last))) {
|
|
135
|
+
event.preventDefault();
|
|
136
|
+
(event.shiftKey ? last : first).focus();
|
|
137
|
+
}
|
|
138
|
+
};
|
|
139
|
+
trigger.setAttribute("aria-haspopup", "dialog");
|
|
140
|
+
if (dialog.id) trigger.setAttribute("aria-controls", dialog.id);
|
|
141
|
+
sync();
|
|
142
|
+
trigger.addEventListener("click", show);
|
|
143
|
+
dialog.addEventListener("close", close);
|
|
144
|
+
dialog.addEventListener("click", click);
|
|
145
|
+
dialog.addEventListener("keydown", key);
|
|
146
|
+
return () => {
|
|
147
|
+
trigger.removeEventListener("click", show);
|
|
148
|
+
dialog.removeEventListener("close", close);
|
|
149
|
+
dialog.removeEventListener("click", click);
|
|
150
|
+
dialog.removeEventListener("keydown", key);
|
|
151
|
+
};
|
|
152
|
+
}
|
|
153
|
+
const labelVariants = cva("font-medium text-[length:var(--font-size-label,0.875rem)] leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70");
|
|
154
|
+
const helpPresentation = {
|
|
155
|
+
root: "text-[length:var(--font-size-help,0.75rem)] leading-4",
|
|
156
|
+
error: "font-medium text-[var(--surface-danger-text)]",
|
|
157
|
+
hint: "text-[var(--text-dim)]"
|
|
158
|
+
};
|
|
159
|
+
const cardPresentation = {
|
|
160
|
+
root: `rounded-[var(--radius-lg)] border text-card-foreground ${controlMotion}`,
|
|
161
|
+
padding: "p-4",
|
|
162
|
+
variants: {
|
|
163
|
+
default: "bg-card border-border shadow-[var(--edge-highlight),var(--shadow-card)]",
|
|
164
|
+
elevated: "bg-muted/50 border-border shadow-[var(--shadow-card)]",
|
|
165
|
+
glass: "bg-card/80 backdrop-blur-xl border-border shadow-[var(--shadow-card)]",
|
|
166
|
+
sandbox: "bg-muted/50 border-primary/20 shadow-[var(--shadow-accent)]"
|
|
167
|
+
}
|
|
168
|
+
};
|
|
169
|
+
/** Canonical segmented, pill and underline navigation presentation. */
|
|
170
|
+
const tabsPresentation = {
|
|
171
|
+
list: {
|
|
172
|
+
default: "inline-flex h-10 items-center justify-center rounded-lg bg-muted p-1 text-muted-foreground",
|
|
173
|
+
pills: "inline-flex items-center gap-2",
|
|
174
|
+
underline: "inline-flex items-center gap-4 border-b border-border"
|
|
175
|
+
},
|
|
176
|
+
trigger: {
|
|
177
|
+
default: `inline-flex items-center justify-center whitespace-nowrap rounded-md px-3 py-1.5 text-sm font-medium ${controlMotion} ${focusRing} disabled:pointer-events-none disabled:opacity-50 ${ixControlSoft} ${ixSelected}`,
|
|
178
|
+
pills: `inline-flex items-center justify-center whitespace-nowrap rounded-full px-4 py-2 text-sm font-medium ${controlMotion} ${focusRing} disabled:pointer-events-none disabled:opacity-50 data-[state=inactive]:text-muted-foreground ${ixControlSoft} ${ixSelected}`,
|
|
179
|
+
underline: `inline-flex items-center justify-center whitespace-nowrap rounded-t-md pb-3 text-sm font-medium ${controlMotion} ${focusRing} disabled:pointer-events-none disabled:opacity-50 border-b-2 border-transparent data-[state=inactive]:text-muted-foreground ${ixTabUnderline}`
|
|
180
|
+
}
|
|
181
|
+
};
|
|
182
|
+
//#endregion
|
|
183
|
+
export { bindDialog, buttonVariants, cardPresentation, controlHeight, controlMotion, controlRadius, controlSizes, controlText, dialogPresentation, emptyStatePresentation, fieldPresentation, fieldSizes, fieldTouchText, helpPresentation, inputVariants, ixControlSoft, ixSelected, ixTabUnderline, labelVariants, metricLayouts, metricPresentation, tablePresentation, tabsPresentation };
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { cn } from "../lib/utils.js";
|
|
3
|
-
import { buttonVariants } from "
|
|
3
|
+
import { buttonVariants } from "../presentation.js";
|
|
4
4
|
import * as React from "react";
|
|
5
5
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
6
6
|
import * as AlertDialogPrimitive from "@radix-ui/react-alert-dialog";
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { StatusTone } from "./status-pill.js";
|
|
2
1
|
import * as React from "react";
|
|
3
2
|
//#region src/primitives/alert.d.ts
|
|
4
3
|
/**
|
|
@@ -13,7 +12,7 @@ import * as React from "react";
|
|
|
13
12
|
* `danger` and `warning` announce themselves (`role="alert"`); the quieter
|
|
14
13
|
* tones are `role="status"` so a screen reader is not interrupted by a note.
|
|
15
14
|
*/
|
|
16
|
-
export type AlertTone =
|
|
15
|
+
export type AlertTone = "neutral" | "info" | "success" | "warning" | "danger";
|
|
17
16
|
export interface AlertProps extends React.HTMLAttributes<HTMLDivElement> {
|
|
18
17
|
tone?: AlertTone;
|
|
19
18
|
/** A leading icon. It takes the tone's colour and sits beside the title. */
|
|
@@ -1,13 +1,10 @@
|
|
|
1
|
+
import { buttonVariants } from "../presentation.js";
|
|
1
2
|
import * as React from "react";
|
|
2
3
|
//#region src/primitives/button.d.ts
|
|
3
|
-
declare const buttonVariants: (props?: ({
|
|
4
|
-
variant?: "default" | "destructive" | "ghost" | "link" | "outline" | "sandbox" | "secondary" | null | undefined;
|
|
5
|
-
size?: "compact" | "default" | "icon" | "icon-lg" | "icon-sm" | "lg" | "md" | "sm" | "touch" | "xl" | null | undefined;
|
|
6
|
-
} & import("class-variance-authority/types").ClassProp) | undefined) => string;
|
|
7
4
|
export interface ButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {
|
|
8
5
|
variant?: "default" | "destructive" | "outline" | "secondary" | "ghost" | "link" | "sandbox" | "bare" | null;
|
|
9
6
|
/** sm 32px, default/md 36px (`--control-height`), lg 44px; icon sizes are squares on the same heights. */
|
|
10
|
-
size?: "default" | "md" | "sm" | "lg" | "xl" | "icon" | "icon-sm" | "icon-lg" | "compact" | "touch" | null;
|
|
7
|
+
size?: "default" | "md" | "sm" | "lg" | "xl" | "display" | "icon" | "icon-sm" | "icon-lg" | "compact" | "touch" | null;
|
|
11
8
|
asChild?: boolean;
|
|
12
9
|
loading?: boolean;
|
|
13
10
|
children?: React.ReactNode;
|
|
@@ -1,41 +1,13 @@
|
|
|
1
|
+
import { controlMotion } from "../lib/motion.js";
|
|
1
2
|
import { ixControl, ixControlSoft, ixSelected } from "../lib/interaction.js";
|
|
2
3
|
import { focusRing } from "../lib/focus.js";
|
|
3
4
|
import { cn } from "../lib/utils.js";
|
|
4
|
-
import {
|
|
5
|
+
import { buttonVariants } from "../presentation.js";
|
|
5
6
|
import { Slot } from "@radix-ui/react-slot";
|
|
6
|
-
import { cva } from "class-variance-authority";
|
|
7
7
|
import * as React from "react";
|
|
8
8
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
9
9
|
//#region src/primitives/button.tsx
|
|
10
|
-
const
|
|
11
|
-
variants: {
|
|
12
|
-
variant: {
|
|
13
|
-
default: `bg-primary text-primary-foreground hover:bg-primary/90 active:scale-[0.97] ${ixControl}`,
|
|
14
|
-
destructive: `bg-destructive text-destructive-foreground hover:bg-destructive/90 active:scale-[0.97] ${ixControl}`,
|
|
15
|
-
outline: `border border-border bg-card hover:bg-muted active:scale-[0.97] text-foreground ${ixControl}`,
|
|
16
|
-
secondary: `bg-muted border border-border text-foreground hover:bg-muted/80 active:scale-[0.97] ${ixControl}`,
|
|
17
|
-
ghost: `hover:text-foreground text-muted-foreground border border-transparent ${ixControlSoft}`,
|
|
18
|
-
link: `text-[var(--accent-text)] underline-offset-4 hover:underline ${ixControlSoft}`,
|
|
19
|
-
sandbox: `bg-[var(--btn-primary-bg)] text-[var(--btn-primary-text)] border border-[var(--border-accent)] hover:bg-[var(--btn-primary-hover)] active:scale-[0.97] ${ixControl}`
|
|
20
|
-
},
|
|
21
|
-
size: {
|
|
22
|
-
default: `${controlHeight.md} ${controlText.md} ${controlRadius.md} px-4 py-2`,
|
|
23
|
-
md: `${controlHeight.md} ${controlText.md} ${controlRadius.md} px-4 py-2`,
|
|
24
|
-
sm: `${controlHeight.sm} ${controlText.sm} ${controlRadius.sm} px-3`,
|
|
25
|
-
lg: `${controlHeight.lg} ${controlText.lg} ${controlRadius.lg} px-7`,
|
|
26
|
-
xl: "h-13 rounded-xl px-9 text-base",
|
|
27
|
-
icon: `${controlSquare.md} ${controlText.md} ${controlRadius.md}`,
|
|
28
|
-
"icon-sm": `${controlSquare.sm} ${controlText.sm} ${controlRadius.sm}`,
|
|
29
|
-
"icon-lg": `${controlSquare.lg} ${controlText.lg} ${controlRadius.lg}`,
|
|
30
|
-
...controlSizes
|
|
31
|
-
}
|
|
32
|
-
},
|
|
33
|
-
defaultVariants: {
|
|
34
|
-
variant: "default",
|
|
35
|
-
size: "default"
|
|
36
|
-
}
|
|
37
|
-
});
|
|
38
|
-
const bareButton = `${focusRing} ${ixControlSoft} disabled:pointer-events-none disabled:opacity-50 aria-disabled:cursor-not-allowed aria-disabled:opacity-50`;
|
|
10
|
+
const bareButton = `${focusRing} ${controlMotion} ${ixControlSoft} disabled:pointer-events-none disabled:opacity-50 aria-disabled:cursor-not-allowed aria-disabled:opacity-50`;
|
|
39
11
|
/** One Button render's classes: variant and size, the toggle states, then the caller's. */
|
|
40
12
|
function buttonClassName(variant, size, pressed, className) {
|
|
41
13
|
const toggle = pressed === void 0 ? void 0 : `${ixControl} ${ixSelected}`;
|
|
@@ -72,6 +44,7 @@ const Button = React.forwardRef(({ className, variant, size, asChild = false, lo
|
|
|
72
44
|
return /* @__PURE__ */ jsx(Slot, {
|
|
73
45
|
className: buttonClassName(variant, size, props["aria-pressed"], className),
|
|
74
46
|
ref,
|
|
47
|
+
"data-variant": size === "display" ? variant ?? "default" : void 0,
|
|
75
48
|
...props,
|
|
76
49
|
...isDisabled ? disabledHandlers(props) : {},
|
|
77
50
|
children: child ? React.cloneElement(child, {
|
|
@@ -91,6 +64,7 @@ const Button = React.forwardRef(({ className, variant, size, asChild = false, lo
|
|
|
91
64
|
return /* @__PURE__ */ jsxs("button", {
|
|
92
65
|
className: buttonClassName(variant, size, props["aria-pressed"], className),
|
|
93
66
|
ref,
|
|
67
|
+
"data-variant": size === "display" ? variant ?? "default" : void 0,
|
|
94
68
|
...props,
|
|
95
69
|
disabled: disabled || loading,
|
|
96
70
|
"aria-busy": loading || props["aria-busy"],
|
package/dist/primitives/card.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import "../lib/interaction.js";
|
|
2
2
|
import { cn } from "../lib/utils.js";
|
|
3
|
+
import { cardPresentation } from "../presentation.js";
|
|
3
4
|
import { Heading } from "./heading.js";
|
|
4
5
|
import * as React from "react";
|
|
5
6
|
import { jsx } from "react/jsx-runtime";
|
|
@@ -15,12 +16,7 @@ import { jsx } from "react/jsx-runtime";
|
|
|
15
16
|
const Card = React.forwardRef(({ className, variant = "default", hover = false, interactive = false, ...props }, ref) => {
|
|
16
17
|
return /* @__PURE__ */ jsx("div", {
|
|
17
18
|
ref,
|
|
18
|
-
className: cn("
|
|
19
|
-
default: "bg-card border-border shadow-[var(--edge-highlight),var(--shadow-card)]",
|
|
20
|
-
elevated: "bg-muted/50 border-border shadow-[var(--shadow-card)]",
|
|
21
|
-
glass: "bg-card/80 backdrop-blur-xl border-border shadow-[var(--shadow-card)]",
|
|
22
|
-
sandbox: "bg-muted/50 border-primary/20 shadow-[var(--shadow-accent)]"
|
|
23
|
-
}[variant], (hover || interactive) && "hover:border-[var(--ix-hover-border)] hover:shadow-[var(--ix-hover)] focus:not-focus-visible:border-[var(--ix-hover-border)] focus:not-focus-visible:shadow-[var(--ix-after)] active:border-[hsl(var(--hsl-ring))] active:shadow-[var(--ix-press)] focus-visible:shadow-none", className),
|
|
19
|
+
className: cn(cardPresentation.root, cardPresentation.variants[variant], (hover || interactive) && "hover:border-[var(--ix-hover-border)] hover:shadow-[var(--ix-hover)] focus:not-focus-visible:border-[var(--ix-hover-border)] focus:not-focus-visible:shadow-[var(--ix-after)] active:border-[hsl(var(--hsl-ring))] active:shadow-[var(--ix-press)] focus-visible:shadow-none", className),
|
|
24
20
|
"data-slot": "card",
|
|
25
21
|
...props
|
|
26
22
|
});
|
|
@@ -48,7 +44,7 @@ const CardDescription = React.forwardRef(({ className, ...props }, ref) => /* @_
|
|
|
48
44
|
CardDescription.displayName = "CardDescription";
|
|
49
45
|
const CardContent = React.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx("div", {
|
|
50
46
|
ref,
|
|
51
|
-
className: cn("
|
|
47
|
+
className: cn(cardPresentation.padding, "[&:not(:first-child)]:pt-0", className),
|
|
52
48
|
...props
|
|
53
49
|
}));
|
|
54
50
|
CardContent.displayName = "CardContent";
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { CodeBlock, CodeBlockProps, CopyButton } from "../markdown/code-block.js";
|
|
1
|
+
import { CodeBlock, CodeBlockProps, CopyButton, CopyButtonProps } from "../markdown/code-block.js";
|
|
2
2
|
//#region src/primitives/code-block.d.ts
|
|
3
3
|
export interface InlineCodeProps extends React.HTMLAttributes<HTMLElement> {}
|
|
4
4
|
export declare function InlineCode({ className, children, ...props }: InlineCodeProps): import("react").JSX.Element;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { CalendarDate, CalendarProps } from "./calendar.js";
|
|
2
1
|
import { ControlSize } from "../lib/control-presentation.js";
|
|
2
|
+
import { CalendarDate, CalendarProps } from "./calendar.js";
|
|
3
3
|
import * as React from "react";
|
|
4
4
|
//#region src/primitives/date-picker.d.ts
|
|
5
5
|
export interface DatePickerProps extends Pick<CalendarProps, "min" | "max" | "isDateDisabled" | "today" | "weekStartsOn" | "locale" | "defaultMonth"> {
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { focusRing } from "../lib/focus.js";
|
|
2
2
|
import { cn } from "../lib/utils.js";
|
|
3
|
+
import { dialogPresentation } from "../presentation.js";
|
|
4
|
+
import { SurfaceMotion } from "../lib/surface-motion.js";
|
|
3
5
|
import * as React from "react";
|
|
4
6
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
5
7
|
import * as DialogPrimitive from "@radix-ui/react-dialog";
|
|
@@ -9,49 +11,60 @@ const Dialog = DialogPrimitive.Root;
|
|
|
9
11
|
const DialogTrigger = DialogPrimitive.Trigger;
|
|
10
12
|
const DialogPortal = DialogPrimitive.Portal;
|
|
11
13
|
const DialogClose = DialogPrimitive.Close;
|
|
12
|
-
const DialogOverlay = React.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(DialogPrimitive.Overlay, {
|
|
14
|
+
const DialogOverlay = React.forwardRef(({ className, asChild, children, ...props }, ref) => /* @__PURE__ */ jsx(DialogPrimitive.Overlay, {
|
|
13
15
|
ref,
|
|
14
|
-
className: cn(
|
|
15
|
-
...props
|
|
16
|
+
className: cn(dialogPresentation.overlay, dialogPresentation.transition, className),
|
|
17
|
+
...props,
|
|
18
|
+
asChild: true,
|
|
19
|
+
children: /* @__PURE__ */ jsx(SurfaceMotion, {
|
|
20
|
+
kind: "overlay",
|
|
21
|
+
asChild,
|
|
22
|
+
children
|
|
23
|
+
})
|
|
16
24
|
}));
|
|
17
25
|
DialogOverlay.displayName = DialogPrimitive.Overlay.displayName;
|
|
18
|
-
const DialogContent = React.forwardRef(({ className, children, variant = "default", hideCloseButton = false, ...props }, ref) => {
|
|
19
|
-
return /* @__PURE__ */ jsxs(DialogPortal, { children: [/* @__PURE__ */ jsx(DialogOverlay, {}), /* @__PURE__ */
|
|
26
|
+
const DialogContent = React.forwardRef(({ className, children, variant = "default", hideCloseButton = false, asChild, ...props }, ref) => {
|
|
27
|
+
return /* @__PURE__ */ jsxs(DialogPortal, { children: [/* @__PURE__ */ jsx(DialogOverlay, {}), /* @__PURE__ */ jsx(DialogPrimitive.Content, {
|
|
20
28
|
ref,
|
|
21
|
-
className: cn(
|
|
29
|
+
className: cn(dialogPresentation.position, dialogPresentation.surface, dialogPresentation.transition, {
|
|
22
30
|
default: "border-border",
|
|
23
31
|
sandbox: "border-[var(--border-accent)] shadow-[var(--shadow-accent)]"
|
|
24
32
|
}[variant], className),
|
|
25
33
|
...props,
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
34
|
+
asChild: true,
|
|
35
|
+
children: /* @__PURE__ */ jsxs(SurfaceMotion, {
|
|
36
|
+
kind: "dialog",
|
|
37
|
+
asChild,
|
|
38
|
+
children: [children, !hideCloseButton && /* @__PURE__ */ jsxs(DialogPrimitive.Close, {
|
|
39
|
+
className: cn(dialogPresentation.close, focusRing),
|
|
40
|
+
children: [/* @__PURE__ */ jsx(X, { className: "h-4 w-4" }), /* @__PURE__ */ jsx("span", {
|
|
41
|
+
className: "sr-only",
|
|
42
|
+
children: "Close"
|
|
43
|
+
})]
|
|
31
44
|
})]
|
|
32
|
-
})
|
|
45
|
+
})
|
|
33
46
|
})] });
|
|
34
47
|
});
|
|
35
48
|
DialogContent.displayName = DialogPrimitive.Content.displayName;
|
|
36
49
|
const DialogHeader = ({ className, ...props }) => /* @__PURE__ */ jsx("div", {
|
|
37
|
-
className: cn(
|
|
50
|
+
className: cn(dialogPresentation.header, className),
|
|
38
51
|
...props
|
|
39
52
|
});
|
|
40
53
|
DialogHeader.displayName = "DialogHeader";
|
|
41
54
|
const DialogFooter = ({ className, ...props }) => /* @__PURE__ */ jsx("div", {
|
|
42
|
-
className: cn(
|
|
55
|
+
className: cn(dialogPresentation.footer, className),
|
|
43
56
|
...props
|
|
44
57
|
});
|
|
45
58
|
DialogFooter.displayName = "DialogFooter";
|
|
46
59
|
const DialogTitle = React.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(DialogPrimitive.Title, {
|
|
47
60
|
ref,
|
|
48
|
-
className: cn(
|
|
61
|
+
className: cn(dialogPresentation.title, className),
|
|
49
62
|
...props
|
|
50
63
|
}));
|
|
51
64
|
DialogTitle.displayName = DialogPrimitive.Title.displayName;
|
|
52
65
|
const DialogDescription = React.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(DialogPrimitive.Description, {
|
|
53
66
|
ref,
|
|
54
|
-
className: cn(
|
|
67
|
+
className: cn(dialogPresentation.description, className),
|
|
55
68
|
...props
|
|
56
69
|
}));
|
|
57
70
|
DialogDescription.displayName = DialogPrimitive.Description.displayName;
|
|
@@ -1,27 +1,28 @@
|
|
|
1
1
|
import { cn } from "../lib/utils.js";
|
|
2
|
+
import { emptyStatePresentation } from "../presentation.js";
|
|
2
3
|
import * as React from "react";
|
|
3
4
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
4
5
|
//#region src/primitives/empty-state.tsx
|
|
5
6
|
const EmptyState = React.forwardRef(({ className, icon, title, description, action, titleAs: Title = "h3", ...props }, ref) => {
|
|
6
7
|
return /* @__PURE__ */ jsxs("div", {
|
|
7
8
|
ref,
|
|
8
|
-
className: cn(
|
|
9
|
+
className: cn(emptyStatePresentation.root, className),
|
|
9
10
|
...props,
|
|
10
11
|
children: [
|
|
11
12
|
icon && /* @__PURE__ */ jsx("div", {
|
|
12
|
-
className:
|
|
13
|
+
className: emptyStatePresentation.icon,
|
|
13
14
|
children: icon
|
|
14
15
|
}),
|
|
15
16
|
/* @__PURE__ */ jsx(Title, {
|
|
16
|
-
className:
|
|
17
|
+
className: emptyStatePresentation.title,
|
|
17
18
|
children: title
|
|
18
19
|
}),
|
|
19
20
|
description && /* @__PURE__ */ jsx("p", {
|
|
20
|
-
className:
|
|
21
|
+
className: emptyStatePresentation.description,
|
|
21
22
|
children: description
|
|
22
23
|
}),
|
|
23
24
|
action && /* @__PURE__ */ jsx("div", {
|
|
24
|
-
className:
|
|
25
|
+
className: emptyStatePresentation.action,
|
|
25
26
|
children: action
|
|
26
27
|
})
|
|
27
28
|
]
|
|
@@ -5,6 +5,7 @@ export type HeadingVariant = "display" | "hero" | "page" | "section" | "subsecti
|
|
|
5
5
|
export interface HeadingProps extends Omit<React.HTMLAttributes<HTMLElement>, "role"> {
|
|
6
6
|
/** Visual treatment, independent of the rendered element. Defaults to section. */
|
|
7
7
|
variant?: HeadingVariant;
|
|
8
|
+
presentation?: "operational" | "expressive";
|
|
8
9
|
/** Semantic element; changing it does not change the visual variant. */
|
|
9
10
|
as?: React.ElementType;
|
|
10
11
|
/**
|
|
@@ -22,13 +22,14 @@ const DEFAULT_TAG = {
|
|
|
22
22
|
* One renderer for page, section and card titles. Use at most one default
|
|
23
23
|
* display/page h1 per page; choose `as` according to the document hierarchy.
|
|
24
24
|
*/
|
|
25
|
-
const Heading = React.forwardRef(({ variant, role, as, className, ...props }, ref) => {
|
|
25
|
+
const Heading = React.forwardRef(({ variant, role, as, className, presentation, ...props }, ref) => {
|
|
26
26
|
const legacyVariant = role && Object.prototype.hasOwnProperty.call(VARIANT_CLASS, role) ? role : void 0;
|
|
27
27
|
const visualVariant = variant ?? legacyVariant ?? "section";
|
|
28
28
|
const Tag = as ?? DEFAULT_TAG[visualVariant];
|
|
29
29
|
return /* @__PURE__ */ jsx(Tag, {
|
|
30
30
|
ref,
|
|
31
|
-
className: cn("[overflow-wrap:anywhere]", VARIANT_CLASS[visualVariant], className),
|
|
31
|
+
className: cn("[overflow-wrap:anywhere]", presentation ? presentation === "expressive" ? "tangle-display" : "tangle-heading" : VARIANT_CLASS[visualVariant], className),
|
|
32
|
+
"data-variant": presentation ? visualVariant : void 0,
|
|
32
33
|
role: legacyVariant ? void 0 : role,
|
|
33
34
|
...props
|
|
34
35
|
});
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { cn } from "../lib/utils.js";
|
|
2
|
+
import { helpPresentation } from "../presentation.js";
|
|
2
3
|
import * as React from "react";
|
|
3
4
|
import { jsx } from "react/jsx-runtime";
|
|
4
5
|
//#region src/primitives/help-text.tsx
|
|
@@ -10,7 +11,7 @@ import { jsx } from "react/jsx-runtime";
|
|
|
10
11
|
const HelpText = React.forwardRef(({ className, tone = "hint", ...props }, ref) => /* @__PURE__ */ jsx("p", {
|
|
11
12
|
ref,
|
|
12
13
|
"data-tone": tone,
|
|
13
|
-
className: cn(
|
|
14
|
+
className: cn(helpPresentation.root, helpPresentation[tone], className),
|
|
14
15
|
...props
|
|
15
16
|
}));
|
|
16
17
|
HelpText.displayName = "HelpText";
|
|
@@ -1,10 +1,7 @@
|
|
|
1
|
+
import { inputVariants } from "../presentation.js";
|
|
1
2
|
import { VariantProps } from "class-variance-authority";
|
|
2
3
|
import * as React from "react";
|
|
3
4
|
//#region src/primitives/input.d.ts
|
|
4
|
-
declare const inputVariants: (props?: ({
|
|
5
|
-
variant?: "default" | "error" | "sandbox" | null | undefined;
|
|
6
|
-
size?: "compact" | "default" | "lg" | "md" | "sm" | "touch" | null | undefined;
|
|
7
|
-
} & import("class-variance-authority/types").ClassProp) | undefined) => string;
|
|
8
5
|
export interface InputProps extends Omit<React.InputHTMLAttributes<HTMLInputElement>, "size">, VariantProps<typeof inputVariants> {
|
|
9
6
|
label?: string;
|
|
10
7
|
error?: string;
|
package/dist/primitives/input.js
CHANGED
|
@@ -1,34 +1,13 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
import
|
|
2
|
+
import "../lib/focus.js";
|
|
3
3
|
import { cn } from "../lib/utils.js";
|
|
4
|
-
import { controlRadius,
|
|
4
|
+
import { controlRadius, controlText, fieldPresentation, fieldTouchText } from "../lib/control-presentation.js";
|
|
5
|
+
import { inputVariants } from "../presentation.js";
|
|
5
6
|
import { HelpText } from "./help-text.js";
|
|
6
7
|
import { Label } from "./label.js";
|
|
7
|
-
import { cva } from "class-variance-authority";
|
|
8
8
|
import * as React from "react";
|
|
9
9
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
10
10
|
//#region src/primitives/input.tsx
|
|
11
|
-
const inputVariants = cva(cn("flex w-full border py-1 placeholder:text-[var(--text-dim)] disabled:cursor-not-allowed disabled:opacity-50 file:border-0 file:bg-transparent file:font-medium", fieldPresentation, fieldTouchText), {
|
|
12
|
-
variants: {
|
|
13
|
-
variant: {
|
|
14
|
-
default: "",
|
|
15
|
-
sandbox: "",
|
|
16
|
-
error: focusFieldInvalid
|
|
17
|
-
},
|
|
18
|
-
size: {
|
|
19
|
-
default: fieldSizes.md,
|
|
20
|
-
md: fieldSizes.md,
|
|
21
|
-
sm: fieldSizes.sm,
|
|
22
|
-
lg: fieldSizes.lg,
|
|
23
|
-
compact: cn(fieldSizes.md, controlSizes.compact),
|
|
24
|
-
touch: cn(fieldSizes.md, controlSizes.touch)
|
|
25
|
-
}
|
|
26
|
-
},
|
|
27
|
-
defaultVariants: {
|
|
28
|
-
variant: "default",
|
|
29
|
-
size: "default"
|
|
30
|
-
}
|
|
31
|
-
});
|
|
32
11
|
function descriptionIds(...ids) {
|
|
33
12
|
return [...new Set(ids.join(" ").split(/\s+/).filter(Boolean))].join(" ") || void 0;
|
|
34
13
|
}
|
package/dist/primitives/label.js
CHANGED
|
@@ -1,11 +1,10 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { cn } from "../lib/utils.js";
|
|
3
|
-
import {
|
|
3
|
+
import { labelVariants } from "../presentation.js";
|
|
4
4
|
import * as React from "react";
|
|
5
5
|
import { jsx } from "react/jsx-runtime";
|
|
6
6
|
import * as LabelPrimitive from "@radix-ui/react-label";
|
|
7
7
|
//#region src/primitives/label.tsx
|
|
8
|
-
const labelVariants = cva("font-medium text-[length:var(--font-size-label,0.875rem)] leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70");
|
|
9
8
|
const Label = React.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(LabelPrimitive.Root, {
|
|
10
9
|
ref,
|
|
11
10
|
className: cn(labelVariants(), className),
|
|
@@ -1,17 +1,12 @@
|
|
|
1
1
|
import { cn } from "../lib/utils.js";
|
|
2
|
+
import { metricLayouts, metricPresentation } from "../presentation.js";
|
|
2
3
|
import { StatusPill } from "./status-pill.js";
|
|
3
4
|
import * as React from "react";
|
|
4
5
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
5
6
|
//#region src/primitives/metric-strip.tsx
|
|
6
|
-
const layouts = {
|
|
7
|
-
3: "grid-cols-2 sm:grid-cols-3 max-sm:[&>div:not(:nth-child(2n+1))]:border-l sm:[&>div:not(:nth-child(3n+1))]:border-l",
|
|
8
|
-
4: "grid-cols-2 sm:grid-cols-4 max-sm:[&>div:not(:nth-child(2n+1))]:border-l sm:[&>div:not(:nth-child(4n+1))]:border-l",
|
|
9
|
-
5: "grid-cols-2 sm:grid-cols-3 lg:grid-cols-5 max-sm:[&>div:not(:nth-child(2n+1))]:border-l sm:max-lg:[&>div:not(:nth-child(3n+1))]:border-l lg:[&>div:not(:nth-child(5n+1))]:border-l",
|
|
10
|
-
6: "grid-cols-2 sm:grid-cols-3 lg:grid-cols-6 max-sm:[&>div:not(:nth-child(2n+1))]:border-l sm:max-lg:[&>div:not(:nth-child(3n+1))]:border-l lg:[&>div:not(:nth-child(6n+1))]:border-l"
|
|
11
|
-
};
|
|
12
7
|
const MetricStrip = React.forwardRef(({ className, children, columns = 4, ...props }, ref) => /* @__PURE__ */ jsx("dl", {
|
|
13
8
|
ref,
|
|
14
|
-
className: cn(
|
|
9
|
+
className: cn(metricPresentation.strip, metricLayouts[columns], className),
|
|
15
10
|
...props,
|
|
16
11
|
children
|
|
17
12
|
}));
|
|
@@ -19,11 +14,11 @@ MetricStrip.displayName = "MetricStrip";
|
|
|
19
14
|
/** A described term; the strip, not this item, decides where separators belong. */
|
|
20
15
|
const Metric = React.forwardRef(({ className, label, value, hint, attention, icon, ...props }, ref) => /* @__PURE__ */ jsxs("div", {
|
|
21
16
|
ref,
|
|
22
|
-
className: cn(
|
|
17
|
+
className: cn(metricPresentation.item, className),
|
|
23
18
|
...props,
|
|
24
19
|
children: [
|
|
25
20
|
/* @__PURE__ */ jsxs("dt", {
|
|
26
|
-
className:
|
|
21
|
+
className: metricPresentation.label,
|
|
27
22
|
children: [
|
|
28
23
|
icon != null && icon !== false && /* @__PURE__ */ jsx("span", {
|
|
29
24
|
"aria-hidden": "true",
|
|
@@ -31,7 +26,7 @@ const Metric = React.forwardRef(({ className, label, value, hint, attention, ico
|
|
|
31
26
|
children: icon
|
|
32
27
|
}),
|
|
33
28
|
/* @__PURE__ */ jsx("span", {
|
|
34
|
-
className:
|
|
29
|
+
className: metricPresentation.labelText,
|
|
35
30
|
children: label
|
|
36
31
|
}),
|
|
37
32
|
attention && /* @__PURE__ */ jsx(StatusPill, {
|
|
@@ -41,12 +36,12 @@ const Metric = React.forwardRef(({ className, label, value, hint, attention, ico
|
|
|
41
36
|
]
|
|
42
37
|
}),
|
|
43
38
|
/* @__PURE__ */ jsx("dd", {
|
|
44
|
-
className: cn(
|
|
39
|
+
className: cn(metricPresentation.value, attention?.tone === "danger" && "text-[var(--surface-danger-text)]"),
|
|
45
40
|
title: typeof value === "string" ? value : void 0,
|
|
46
41
|
children: value
|
|
47
42
|
}),
|
|
48
43
|
hint !== void 0 && hint !== null && hint !== false && hint !== "" && /* @__PURE__ */ jsx("dd", {
|
|
49
|
-
className:
|
|
44
|
+
className: metricPresentation.hint,
|
|
50
45
|
title: typeof hint === "string" ? hint : void 0,
|
|
51
46
|
children: hint
|
|
52
47
|
})
|
|
@@ -7,6 +7,7 @@ import * as React from "react";
|
|
|
7
7
|
*/
|
|
8
8
|
export interface PageHeaderProps extends Omit<React.HTMLAttributes<HTMLElement>, "title"> {
|
|
9
9
|
title: React.ReactNode;
|
|
10
|
+
presentation?: "operational" | "expressive";
|
|
10
11
|
description?: React.ReactNode;
|
|
11
12
|
/** Canonical action slot. If supplied (even null), takes precedence over action. */
|
|
12
13
|
actions?: React.ReactNode;
|