@corbits/react-ui 0.1.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/LICENSE +501 -0
- package/README.md +125 -0
- package/dist/blocks/login/auth-layout.d.ts +38 -0
- package/dist/blocks/login/auth-layout.js +52 -0
- package/dist/blocks/login/login-form.d.ts +60 -0
- package/dist/blocks/login/login-form.js +151 -0
- package/dist/hooks/use-command-palette-navigation.d.ts +25 -0
- package/dist/hooks/use-command-palette-navigation.js +52 -0
- package/dist/hooks/use-controllable-state.d.ts +28 -0
- package/dist/hooks/use-controllable-state.js +44 -0
- package/dist/hooks/use-delayed-autofocus.d.ts +9 -0
- package/dist/hooks/use-delayed-autofocus.js +20 -0
- package/dist/hooks/use-dismissable-popover.d.ts +37 -0
- package/dist/hooks/use-dismissable-popover.js +64 -0
- package/dist/hooks/use-list-selection.d.ts +66 -0
- package/dist/hooks/use-list-selection.js +147 -0
- package/dist/hooks/use-prefers-reduced-motion.d.ts +13 -0
- package/dist/hooks/use-prefers-reduced-motion.js +28 -0
- package/dist/hooks/use-scroll-current-into-view.d.ts +19 -0
- package/dist/hooks/use-scroll-current-into-view.js +33 -0
- package/dist/index.d.ts +122 -0
- package/dist/index.js +131 -0
- package/dist/lib/artifact.d.ts +72 -0
- package/dist/lib/artifact.js +67 -0
- package/dist/lib/chart-geometry.d.ts +62 -0
- package/dist/lib/chart-geometry.js +86 -0
- package/dist/lib/chart-palette.d.ts +76 -0
- package/dist/lib/chart-palette.js +92 -0
- package/dist/lib/chat-message.d.ts +115 -0
- package/dist/lib/chat-message.js +41 -0
- package/dist/lib/chat-parts.d.ts +64 -0
- package/dist/lib/chat-parts.js +16 -0
- package/dist/lib/csv.d.ts +60 -0
- package/dist/lib/csv.js +108 -0
- package/dist/lib/metrics.d.ts +70 -0
- package/dist/lib/metrics.js +101 -0
- package/dist/lib/now-item.d.ts +65 -0
- package/dist/lib/now-item.js +59 -0
- package/dist/lib/relative-time.d.ts +9 -0
- package/dist/lib/relative-time.js +47 -0
- package/dist/lib/theme.d.ts +30 -0
- package/dist/lib/theme.js +77 -0
- package/dist/lib/url.d.ts +26 -0
- package/dist/lib/url.js +37 -0
- package/dist/lib/utils.d.ts +2 -0
- package/dist/lib/utils.js +5 -0
- package/dist/lib/workflow-display-flow.d.ts +83 -0
- package/dist/lib/workflow-display-flow.js +104 -0
- package/dist/lib/workflow-registry.d.ts +90 -0
- package/dist/lib/workflow-registry.js +56 -0
- package/dist/lib/workflow-run-error.d.ts +31 -0
- package/dist/lib/workflow-run-error.js +105 -0
- package/dist/lib/workflow-run-progress.d.ts +97 -0
- package/dist/lib/workflow-run-progress.js +135 -0
- package/dist/lib/workflow-run.d.ts +43 -0
- package/dist/lib/workflow-run.js +56 -0
- package/dist/styles.css +3080 -0
- package/dist/test/render-hook.d.ts +14 -0
- package/dist/test/render-hook.js +38 -0
- package/dist/theme.css +628 -0
- package/dist/ui/agent-turn.d.ts +26 -0
- package/dist/ui/agent-turn.js +60 -0
- package/dist/ui/animated-number.d.ts +25 -0
- package/dist/ui/animated-number.js +63 -0
- package/dist/ui/approval-card.d.ts +46 -0
- package/dist/ui/approval-card.js +116 -0
- package/dist/ui/artifact-body.d.ts +26 -0
- package/dist/ui/artifact-body.js +170 -0
- package/dist/ui/artifact-notice.d.ts +21 -0
- package/dist/ui/artifact-notice.js +36 -0
- package/dist/ui/avatar.d.ts +37 -0
- package/dist/ui/avatar.js +73 -0
- package/dist/ui/badge.d.ts +10 -0
- package/dist/ui/badge.js +35 -0
- package/dist/ui/bar-chart.d.ts +38 -0
- package/dist/ui/bar-chart.js +118 -0
- package/dist/ui/block-card.d.ts +29 -0
- package/dist/ui/block-card.js +66 -0
- package/dist/ui/boot-screen.d.ts +23 -0
- package/dist/ui/boot-screen.js +49 -0
- package/dist/ui/bulk-action-bar.d.ts +37 -0
- package/dist/ui/bulk-action-bar.js +64 -0
- package/dist/ui/button.d.ts +12 -0
- package/dist/ui/button.js +73 -0
- package/dist/ui/card.d.ts +6 -0
- package/dist/ui/card.js +37 -0
- package/dist/ui/category-bars.d.ts +20 -0
- package/dist/ui/category-bars.js +69 -0
- package/dist/ui/chart-frame.d.ts +54 -0
- package/dist/ui/chart-frame.js +108 -0
- package/dist/ui/chat-composer.d.ts +24 -0
- package/dist/ui/chat-composer.js +32 -0
- package/dist/ui/chat-dock-timing.d.ts +15 -0
- package/dist/ui/chat-dock-timing.js +11 -0
- package/dist/ui/chat-input.d.ts +38 -0
- package/dist/ui/chat-input.js +138 -0
- package/dist/ui/chat-panel.d.ts +20 -0
- package/dist/ui/chat-panel.js +56 -0
- package/dist/ui/chat-thread.d.ts +28 -0
- package/dist/ui/chat-thread.js +61 -0
- package/dist/ui/checkbox.d.ts +25 -0
- package/dist/ui/checkbox.js +63 -0
- package/dist/ui/command-palette.d.ts +100 -0
- package/dist/ui/command-palette.js +341 -0
- package/dist/ui/compare-body.d.ts +52 -0
- package/dist/ui/compare-body.js +140 -0
- package/dist/ui/confirm-button.d.ts +29 -0
- package/dist/ui/confirm-button.js +41 -0
- package/dist/ui/corbits-mark.d.ts +29 -0
- package/dist/ui/corbits-mark.js +33 -0
- package/dist/ui/csv-table.d.ts +22 -0
- package/dist/ui/csv-table.js +85 -0
- package/dist/ui/dialog.d.ts +37 -0
- package/dist/ui/dialog.js +105 -0
- package/dist/ui/dictation-status-line.d.ts +20 -0
- package/dist/ui/dictation-status-line.js +38 -0
- package/dist/ui/dither-canvas.d.ts +31 -0
- package/dist/ui/dither-canvas.js +169 -0
- package/dist/ui/embed-body.d.ts +30 -0
- package/dist/ui/embed-body.js +92 -0
- package/dist/ui/empty-state.d.ts +26 -0
- package/dist/ui/empty-state.js +42 -0
- package/dist/ui/file-input.d.ts +25 -0
- package/dist/ui/file-input.js +66 -0
- package/dist/ui/filter-bar.d.ts +42 -0
- package/dist/ui/filter-bar.js +95 -0
- package/dist/ui/filter-chip.d.ts +14 -0
- package/dist/ui/filter-chip.js +23 -0
- package/dist/ui/gate-block.d.ts +16 -0
- package/dist/ui/gate-block.js +37 -0
- package/dist/ui/horizontal-stepper.d.ts +13 -0
- package/dist/ui/horizontal-stepper.js +65 -0
- package/dist/ui/input.d.ts +2 -0
- package/dist/ui/input.js +14 -0
- package/dist/ui/inspector-shell.d.ts +47 -0
- package/dist/ui/inspector-shell.js +98 -0
- package/dist/ui/intake-form.d.ts +39 -0
- package/dist/ui/intake-form.js +119 -0
- package/dist/ui/kind-card-grid.d.ts +23 -0
- package/dist/ui/kind-card-grid.js +43 -0
- package/dist/ui/library-page-header.d.ts +20 -0
- package/dist/ui/library-page-header.js +43 -0
- package/dist/ui/list-detail.d.ts +28 -0
- package/dist/ui/list-detail.js +55 -0
- package/dist/ui/live-run-banner.d.ts +13 -0
- package/dist/ui/live-run-banner.js +23 -0
- package/dist/ui/live-status-line.d.ts +22 -0
- package/dist/ui/live-status-line.js +37 -0
- package/dist/ui/menu.d.ts +18 -0
- package/dist/ui/menu.js +45 -0
- package/dist/ui/message-bubble.d.ts +24 -0
- package/dist/ui/message-bubble.js +64 -0
- package/dist/ui/mic-button.d.ts +35 -0
- package/dist/ui/mic-button.js +61 -0
- package/dist/ui/mic-permission-dialog.d.ts +20 -0
- package/dist/ui/mic-permission-dialog.js +50 -0
- package/dist/ui/notifications-bell.d.ts +28 -0
- package/dist/ui/notifications-bell.js +69 -0
- package/dist/ui/now-cards.d.ts +37 -0
- package/dist/ui/now-cards.js +116 -0
- package/dist/ui/page-panel.d.ts +37 -0
- package/dist/ui/page-panel.js +23 -0
- package/dist/ui/page-shell.d.ts +21 -0
- package/dist/ui/page-shell.js +26 -0
- package/dist/ui/parts-renderer.d.ts +22 -0
- package/dist/ui/parts-renderer.js +234 -0
- package/dist/ui/profile-card.d.ts +39 -0
- package/dist/ui/profile-card.js +124 -0
- package/dist/ui/progress-checklist.d.ts +25 -0
- package/dist/ui/progress-checklist.js +70 -0
- package/dist/ui/provider-mark.d.ts +32 -0
- package/dist/ui/provider-mark.js +31 -0
- package/dist/ui/quick-reply-chips.d.ts +14 -0
- package/dist/ui/quick-reply-chips.js +24 -0
- package/dist/ui/quote-card.d.ts +39 -0
- package/dist/ui/quote-card.js +66 -0
- package/dist/ui/reasoning-block.d.ts +35 -0
- package/dist/ui/reasoning-block.js +60 -0
- package/dist/ui/research-body.d.ts +70 -0
- package/dist/ui/research-body.js +270 -0
- package/dist/ui/rich-empty-state.d.ts +35 -0
- package/dist/ui/rich-empty-state.js +65 -0
- package/dist/ui/run-now-button.d.ts +23 -0
- package/dist/ui/run-now-button.js +42 -0
- package/dist/ui/section.d.ts +20 -0
- package/dist/ui/section.js +48 -0
- package/dist/ui/select.d.ts +2 -0
- package/dist/ui/select.js +22 -0
- package/dist/ui/selection-checkbox.d.ts +42 -0
- package/dist/ui/selection-checkbox.js +54 -0
- package/dist/ui/settings-panel.d.ts +35 -0
- package/dist/ui/settings-panel.js +68 -0
- package/dist/ui/shimmer-text.d.ts +19 -0
- package/dist/ui/shimmer-text.js +20 -0
- package/dist/ui/sidebar-item-row.d.ts +40 -0
- package/dist/ui/sidebar-item-row.js +64 -0
- package/dist/ui/sidebar-panel.d.ts +25 -0
- package/dist/ui/sidebar-panel.js +56 -0
- package/dist/ui/sidebar.d.ts +46 -0
- package/dist/ui/sidebar.js +111 -0
- package/dist/ui/skeleton.d.ts +13 -0
- package/dist/ui/skeleton.js +20 -0
- package/dist/ui/sortable-table.d.ts +43 -0
- package/dist/ui/sortable-table.js +103 -0
- package/dist/ui/sparkline.d.ts +27 -0
- package/dist/ui/sparkline.js +68 -0
- package/dist/ui/stat-grid.d.ts +55 -0
- package/dist/ui/stat-grid.js +87 -0
- package/dist/ui/status-dot.d.ts +13 -0
- package/dist/ui/status-dot.js +51 -0
- package/dist/ui/step-list.d.ts +21 -0
- package/dist/ui/step-list.js +77 -0
- package/dist/ui/switch.d.ts +23 -0
- package/dist/ui/switch.js +29 -0
- package/dist/ui/table.d.ts +8 -0
- package/dist/ui/table.js +48 -0
- package/dist/ui/tabs.d.ts +44 -0
- package/dist/ui/tabs.js +101 -0
- package/dist/ui/textarea.d.ts +8 -0
- package/dist/ui/textarea.js +32 -0
- package/dist/ui/theme-provider.d.ts +36 -0
- package/dist/ui/theme-provider.js +126 -0
- package/dist/ui/theme-toggle.d.ts +11 -0
- package/dist/ui/theme-toggle.js +32 -0
- package/dist/ui/thinking-indicator.d.ts +7 -0
- package/dist/ui/thinking-indicator.js +19 -0
- package/dist/ui/thinking-label.d.ts +19 -0
- package/dist/ui/thinking-label.js +54 -0
- package/dist/ui/thinking-mark.d.ts +10 -0
- package/dist/ui/thinking-mark.js +153 -0
- package/dist/ui/time-series-chart.d.ts +55 -0
- package/dist/ui/time-series-chart.js +249 -0
- package/dist/ui/toast.d.ts +16 -0
- package/dist/ui/toast.js +41 -0
- package/dist/ui/token-mosaic.d.ts +22 -0
- package/dist/ui/token-mosaic.js +65 -0
- package/dist/ui/tool-block.d.ts +54 -0
- package/dist/ui/tool-block.js +170 -0
- package/dist/ui/tool-narrative.d.ts +22 -0
- package/dist/ui/tool-narrative.js +77 -0
- package/dist/ui/tool-picker.d.ts +44 -0
- package/dist/ui/tool-picker.js +200 -0
- package/dist/ui/tooltip.d.ts +21 -0
- package/dist/ui/tooltip.js +48 -0
- package/dist/ui/top-bar.d.ts +53 -0
- package/dist/ui/top-bar.js +98 -0
- package/dist/ui/trace-waterfall.d.ts +38 -0
- package/dist/ui/trace-waterfall.js +121 -0
- package/dist/ui/typing-indicator.d.ts +9 -0
- package/dist/ui/typing-indicator.js +25 -0
- package/dist/ui/view-toggle.d.ts +17 -0
- package/dist/ui/view-toggle.js +46 -0
- package/dist/ui/voice-waveform.d.ts +16 -0
- package/dist/ui/voice-waveform.js +23 -0
- package/package.json +583 -0
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
|
+
import { ChevronDown, ChevronUp, ChevronsUpDown } from "lucide-react";
|
|
3
|
+
import { useMemo, useState } from "react";
|
|
4
|
+
import { cn } from "../lib/utils.js";
|
|
5
|
+
import { EmptyState } from "./empty-state.js";
|
|
6
|
+
import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "./table.js";
|
|
7
|
+
/**
|
|
8
|
+
* A table you can sort by clicking a header.
|
|
9
|
+
*
|
|
10
|
+
* Rows are an array, not a `DataPort` collection — this sorts client-side over
|
|
11
|
+
* rows it already has, which is only correct for a set small enough to hold in
|
|
12
|
+
* full. Once the data is paginated, sorting has to happen at the source or the
|
|
13
|
+
* user is sorting one page and being told it is the whole set; use `DataTable`
|
|
14
|
+
* with a server-sorted request for that. The two are different tools and this
|
|
15
|
+
* one does not pretend to be the other.
|
|
16
|
+
*
|
|
17
|
+
* `aria-sort` on the active header is the part that matters. A caret glyph is
|
|
18
|
+
* invisible to a screen reader, and sort order is exactly the sort of state
|
|
19
|
+
* that goes unnoticed without it. Inactive sortable headers show a neutral
|
|
20
|
+
* affordance so it is discoverable which columns can be sorted at all.
|
|
21
|
+
*/ export function SortableTable({ caption, rows, columns, rowKey, initialSort, empty, className }) {
|
|
22
|
+
const [sort, setSort] = useState(initialSort ?? null);
|
|
23
|
+
const sorted = useMemo(()=>{
|
|
24
|
+
if (sort === null) return rows;
|
|
25
|
+
const column = columns.find((candidate)=>candidate.key === sort.key);
|
|
26
|
+
if (column?.sortValue === undefined) return rows;
|
|
27
|
+
const { sortValue } = column;
|
|
28
|
+
// Sorts a copy: `rows` belongs to the caller and may be frozen.
|
|
29
|
+
return [
|
|
30
|
+
...rows
|
|
31
|
+
].sort((a, b)=>{
|
|
32
|
+
const left = sortValue(a);
|
|
33
|
+
const right = sortValue(b);
|
|
34
|
+
const comparison = typeof left === "number" && typeof right === "number" ? left - right : String(left).localeCompare(String(right));
|
|
35
|
+
return sort.direction === "asc" ? comparison : -comparison;
|
|
36
|
+
});
|
|
37
|
+
}, [
|
|
38
|
+
rows,
|
|
39
|
+
columns,
|
|
40
|
+
sort
|
|
41
|
+
]);
|
|
42
|
+
const toggle = (key)=>{
|
|
43
|
+
setSort((current)=>current?.key === key ? {
|
|
44
|
+
key,
|
|
45
|
+
direction: current.direction === "asc" ? "desc" : "asc"
|
|
46
|
+
} : {
|
|
47
|
+
key,
|
|
48
|
+
direction: "asc"
|
|
49
|
+
});
|
|
50
|
+
};
|
|
51
|
+
if (rows.length === 0) {
|
|
52
|
+
return /*#__PURE__*/ _jsx(_Fragment, {
|
|
53
|
+
children: empty ?? /*#__PURE__*/ _jsx(EmptyState, {
|
|
54
|
+
title: "Nothing to show"
|
|
55
|
+
})
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
return /*#__PURE__*/ _jsxs(Table, {
|
|
59
|
+
"aria-label": caption,
|
|
60
|
+
className: className,
|
|
61
|
+
children: [
|
|
62
|
+
/*#__PURE__*/ _jsx(TableHeader, {
|
|
63
|
+
children: /*#__PURE__*/ _jsx(TableRow, {
|
|
64
|
+
children: columns.map((column)=>{
|
|
65
|
+
const active = sort?.key === column.key;
|
|
66
|
+
const sortable = column.sortValue !== undefined;
|
|
67
|
+
return /*#__PURE__*/ _jsx(TableHead, {
|
|
68
|
+
scope: "col",
|
|
69
|
+
"aria-sort": active ? sort.direction === "asc" ? "ascending" : "descending" : undefined,
|
|
70
|
+
className: cn(column.align === "right" && "text-right", column.className),
|
|
71
|
+
children: sortable ? /*#__PURE__*/ _jsxs("button", {
|
|
72
|
+
type: "button",
|
|
73
|
+
onClick: ()=>toggle(column.key),
|
|
74
|
+
className: cn("inline-flex items-center gap-1 rounded-sm transition-colors hover:text-foreground", !active && "text-muted-foreground"),
|
|
75
|
+
children: [
|
|
76
|
+
column.header,
|
|
77
|
+
active ? sort.direction === "asc" ? /*#__PURE__*/ _jsx(ChevronUp, {
|
|
78
|
+
className: "size-3.5",
|
|
79
|
+
"aria-hidden": true
|
|
80
|
+
}) : /*#__PURE__*/ _jsx(ChevronDown, {
|
|
81
|
+
className: "size-3.5",
|
|
82
|
+
"aria-hidden": true
|
|
83
|
+
}) : /*#__PURE__*/ _jsx(ChevronsUpDown, {
|
|
84
|
+
className: "size-3.5 opacity-50",
|
|
85
|
+
"aria-hidden": true
|
|
86
|
+
})
|
|
87
|
+
]
|
|
88
|
+
}) : column.header
|
|
89
|
+
}, column.key);
|
|
90
|
+
})
|
|
91
|
+
})
|
|
92
|
+
}),
|
|
93
|
+
/*#__PURE__*/ _jsx(TableBody, {
|
|
94
|
+
children: sorted.map((row)=>/*#__PURE__*/ _jsx(TableRow, {
|
|
95
|
+
children: columns.map((column)=>/*#__PURE__*/ _jsx(TableCell, {
|
|
96
|
+
className: cn(column.align === "right" && "text-right", column.className),
|
|
97
|
+
children: column.cell(row)
|
|
98
|
+
}, column.key))
|
|
99
|
+
}, rowKey(row)))
|
|
100
|
+
})
|
|
101
|
+
]
|
|
102
|
+
});
|
|
103
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
export type SparklineProps = {
|
|
2
|
+
readonly values: readonly number[];
|
|
3
|
+
/**
|
|
4
|
+
* What the shape means, in words — "Up 12% over 30 days". Without it the
|
|
5
|
+
* sparkline is invisible to anyone not looking at it, and a shape with no
|
|
6
|
+
* axes and no labels cannot be inferred from its markup.
|
|
7
|
+
*/
|
|
8
|
+
readonly summary: string;
|
|
9
|
+
readonly className?: string;
|
|
10
|
+
};
|
|
11
|
+
/**
|
|
12
|
+
* A trend, at the size of a word.
|
|
13
|
+
*
|
|
14
|
+
* No axes, no ticks, no labels — that is the form, not an omission. A sparkline
|
|
15
|
+
* says "rising", "flat", "spiky" beside a number that says exactly how much; the
|
|
16
|
+
* moment it needs a scale it has outgrown itself and wants to be a chart.
|
|
17
|
+
*
|
|
18
|
+
* It is scaled between the series' own minimum and maximum rather than from
|
|
19
|
+
* zero. This is the one place a non-zero baseline is right: the shape is the
|
|
20
|
+
* only message, and anchoring to zero flattens every real series into a
|
|
21
|
+
* horizontal line near the top of a 24px box.
|
|
22
|
+
*
|
|
23
|
+
* `role="img"` with the caller's summary as its name. The summary is required
|
|
24
|
+
* for the same reason `alt` is: a picture with no text alternative is simply
|
|
25
|
+
* missing for some readers, and this one has no fallback content to fall back to.
|
|
26
|
+
*/
|
|
27
|
+
export declare function Sparkline({ values, summary, className }: SparklineProps): import("react").JSX.Element;
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { linePath, scaleLinear } from "../lib/chart-geometry.js";
|
|
3
|
+
import { seriesColor } from "../lib/chart-palette.js";
|
|
4
|
+
import { cn } from "../lib/utils.js";
|
|
5
|
+
const WIDTH = 96;
|
|
6
|
+
const HEIGHT = 24;
|
|
7
|
+
/**
|
|
8
|
+
* A trend, at the size of a word.
|
|
9
|
+
*
|
|
10
|
+
* No axes, no ticks, no labels — that is the form, not an omission. A sparkline
|
|
11
|
+
* says "rising", "flat", "spiky" beside a number that says exactly how much; the
|
|
12
|
+
* moment it needs a scale it has outgrown itself and wants to be a chart.
|
|
13
|
+
*
|
|
14
|
+
* It is scaled between the series' own minimum and maximum rather than from
|
|
15
|
+
* zero. This is the one place a non-zero baseline is right: the shape is the
|
|
16
|
+
* only message, and anchoring to zero flattens every real series into a
|
|
17
|
+
* horizontal line near the top of a 24px box.
|
|
18
|
+
*
|
|
19
|
+
* `role="img"` with the caller's summary as its name. The summary is required
|
|
20
|
+
* for the same reason `alt` is: a picture with no text alternative is simply
|
|
21
|
+
* missing for some readers, and this one has no fallback content to fall back to.
|
|
22
|
+
*/ export function Sparkline({ values, summary, className }) {
|
|
23
|
+
if (values.length < 2) {
|
|
24
|
+
return /*#__PURE__*/ _jsx("span", {
|
|
25
|
+
className: cn("inline-block", className),
|
|
26
|
+
role: "img",
|
|
27
|
+
"aria-label": summary
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
const min = Math.min(...values);
|
|
31
|
+
const max = Math.max(...values);
|
|
32
|
+
const span = max - min;
|
|
33
|
+
const stepX = WIDTH / (values.length - 1);
|
|
34
|
+
const points = values.map((value, index)=>({
|
|
35
|
+
x: index * stepX,
|
|
36
|
+
// A flat series has no span to scale against; centre it rather than
|
|
37
|
+
// dividing by zero.
|
|
38
|
+
y: span === 0 ? HEIGHT / 2 : HEIGHT - scaleLinear(value - min, span, HEIGHT - 4) - 2
|
|
39
|
+
}));
|
|
40
|
+
const last = points[points.length - 1];
|
|
41
|
+
return /*#__PURE__*/ _jsxs("svg", {
|
|
42
|
+
viewBox: `0 0 ${WIDTH} ${HEIGHT}`,
|
|
43
|
+
className: cn("h-6 w-24", className),
|
|
44
|
+
role: "img",
|
|
45
|
+
"aria-label": summary,
|
|
46
|
+
focusable: "false",
|
|
47
|
+
children: [
|
|
48
|
+
/*#__PURE__*/ _jsx("path", {
|
|
49
|
+
d: linePath(points),
|
|
50
|
+
fill: "none",
|
|
51
|
+
stroke: seriesColor(0),
|
|
52
|
+
strokeWidth: 2,
|
|
53
|
+
strokeLinecap: "round",
|
|
54
|
+
strokeLinejoin: "round"
|
|
55
|
+
}),
|
|
56
|
+
last === undefined ? null : // The end dot marks "now" — which end is the current period is
|
|
57
|
+
// otherwise ambiguous on a shape with no axis.
|
|
58
|
+
/*#__PURE__*/ _jsx("circle", {
|
|
59
|
+
cx: last.x,
|
|
60
|
+
cy: last.y,
|
|
61
|
+
r: 2.5,
|
|
62
|
+
fill: seriesColor(0),
|
|
63
|
+
stroke: "var(--card)",
|
|
64
|
+
strokeWidth: 2
|
|
65
|
+
})
|
|
66
|
+
]
|
|
67
|
+
});
|
|
68
|
+
}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import type { ReactNode } from "react";
|
|
2
|
+
export type StatGridColumns = 2 | 3 | 4 | 5;
|
|
3
|
+
export type StatGridProps = {
|
|
4
|
+
readonly children: ReactNode;
|
|
5
|
+
/** Responsive column count; defaults to four-up on wide screens. */
|
|
6
|
+
readonly columns?: StatGridColumns;
|
|
7
|
+
readonly className?: string;
|
|
8
|
+
};
|
|
9
|
+
/**
|
|
10
|
+
* The KPI band: a fixed responsive grid of `StatGridItem`s.
|
|
11
|
+
*
|
|
12
|
+
* Fixed columns rather than auto-fit, because a KPI row is designed as a set —
|
|
13
|
+
* four headline numbers are four columns, and a row that reflows to five-up on
|
|
14
|
+
* a wider screen silently reorders what the reader compares side by side.
|
|
15
|
+
*/
|
|
16
|
+
export declare function StatGrid({ children, columns, className }: StatGridProps): import("react").JSX.Element;
|
|
17
|
+
export type StatGridItemProps = {
|
|
18
|
+
readonly label: string;
|
|
19
|
+
/** Pre-formatted. The tile does not know your units. */
|
|
20
|
+
readonly value: string;
|
|
21
|
+
/** Small print under the number — a rate, a share, a caveat. */
|
|
22
|
+
readonly sub?: ReactNode;
|
|
23
|
+
/** Orange action tone — reserve for genuine action/positive emphasis. */
|
|
24
|
+
readonly accent?: boolean;
|
|
25
|
+
/** Semantic danger — failure counts, not the action accent. */
|
|
26
|
+
readonly danger?: boolean;
|
|
27
|
+
/** Headline tile: larger value + padding. */
|
|
28
|
+
readonly emphasis?: boolean;
|
|
29
|
+
/** Optional period-over-period badge (e.g. a `DeltaBadge`). */
|
|
30
|
+
readonly delta?: ReactNode;
|
|
31
|
+
/** Custom sparkline slot; overrides `sparklineValues` when both are set. */
|
|
32
|
+
readonly sparkline?: ReactNode;
|
|
33
|
+
/** When set (and `sparkline` is omitted), renders the built-in trend line. */
|
|
34
|
+
readonly sparklineValues?: readonly number[];
|
|
35
|
+
/** Words for the built-in trend's shape; defaults to "{label} trend". */
|
|
36
|
+
readonly sparklineLabel?: string;
|
|
37
|
+
/**
|
|
38
|
+
* When set, the tile is a real `<button>` and activates on click/Enter/Space.
|
|
39
|
+
* Static tiles stay a non-interactive `div` so they do not join the tab order.
|
|
40
|
+
*/
|
|
41
|
+
readonly onClick?: () => void;
|
|
42
|
+
readonly className?: string;
|
|
43
|
+
};
|
|
44
|
+
/**
|
|
45
|
+
* One KPI: caption label, headline number, optional delta, trend and small
|
|
46
|
+
* print. The value never carries direction by colour alone — `accent` and
|
|
47
|
+
* `danger` are semantic tones the caller opts into, and the delta slot carries
|
|
48
|
+
* its own words.
|
|
49
|
+
*
|
|
50
|
+
* Interaction is opt-in. With `onClick`, the shell is a `<button>` (not a div
|
|
51
|
+
* wearing `role="button"`) so keyboard activation is native. Shared layout
|
|
52
|
+
* classes stay identical; only the interactive shell adds hover/press
|
|
53
|
+
* affordance and the `text-left`/`w-full` button reset.
|
|
54
|
+
*/
|
|
55
|
+
export declare function StatGridItem({ label, value, sub, accent, danger, emphasis, delta, sparkline, sparklineValues, sparklineLabel, onClick, className, }: StatGridItemProps): import("react").JSX.Element;
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
|
+
import { cn } from "../lib/utils.js";
|
|
3
|
+
import { Sparkline } from "./sparkline.js";
|
|
4
|
+
// Spelled out rather than composed at runtime — Tailwind's scanner only emits
|
|
5
|
+
// utilities it can see literally in the source.
|
|
6
|
+
const COLUMN_CLASS = {
|
|
7
|
+
2: "grid-cols-2",
|
|
8
|
+
3: "grid-cols-2 sm:grid-cols-3",
|
|
9
|
+
4: "grid-cols-2 sm:grid-cols-4",
|
|
10
|
+
5: "grid-cols-2 sm:grid-cols-5"
|
|
11
|
+
};
|
|
12
|
+
/**
|
|
13
|
+
* The KPI band: a fixed responsive grid of `StatGridItem`s.
|
|
14
|
+
*
|
|
15
|
+
* Fixed columns rather than auto-fit, because a KPI row is designed as a set —
|
|
16
|
+
* four headline numbers are four columns, and a row that reflows to five-up on
|
|
17
|
+
* a wider screen silently reorders what the reader compares side by side.
|
|
18
|
+
*/ export function StatGrid({ children, columns = 4, className }) {
|
|
19
|
+
return /*#__PURE__*/ _jsx("div", {
|
|
20
|
+
className: cn("grid gap-3", COLUMN_CLASS[columns], className),
|
|
21
|
+
children: children
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
function statValueClass(accent, danger) {
|
|
25
|
+
if (danger === true) return "text-destructive";
|
|
26
|
+
if (accent === true) return "text-primary-emphasis";
|
|
27
|
+
return "text-foreground";
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* One KPI: caption label, headline number, optional delta, trend and small
|
|
31
|
+
* print. The value never carries direction by colour alone — `accent` and
|
|
32
|
+
* `danger` are semantic tones the caller opts into, and the delta slot carries
|
|
33
|
+
* its own words.
|
|
34
|
+
*
|
|
35
|
+
* Interaction is opt-in. With `onClick`, the shell is a `<button>` (not a div
|
|
36
|
+
* wearing `role="button"`) so keyboard activation is native. Shared layout
|
|
37
|
+
* classes stay identical; only the interactive shell adds hover/press
|
|
38
|
+
* affordance and the `text-left`/`w-full` button reset.
|
|
39
|
+
*/ export function StatGridItem({ label, value, sub, accent, danger, emphasis, delta, sparkline, sparklineValues, sparklineLabel, onClick, className }) {
|
|
40
|
+
const sparklineNode = sparkline ?? (sparklineValues !== undefined && sparklineValues.length > 0 ? /*#__PURE__*/ _jsx(Sparkline, {
|
|
41
|
+
values: sparklineValues,
|
|
42
|
+
summary: sparklineLabel ?? `${label} trend`
|
|
43
|
+
}) : null);
|
|
44
|
+
const shell = cn("flex flex-col gap-1.5 rounded-lg border border-border bg-card", emphasis === true ? "p-5 shadow-sm" : "p-4", className);
|
|
45
|
+
const body = /*#__PURE__*/ _jsxs(_Fragment, {
|
|
46
|
+
children: [
|
|
47
|
+
/*#__PURE__*/ _jsx("span", {
|
|
48
|
+
className: "text-[10px] font-semibold tracking-[0.12em] uppercase text-muted-foreground",
|
|
49
|
+
children: label
|
|
50
|
+
}),
|
|
51
|
+
/*#__PURE__*/ _jsxs("div", {
|
|
52
|
+
className: "flex items-baseline gap-2",
|
|
53
|
+
children: [
|
|
54
|
+
/*#__PURE__*/ _jsx("span", {
|
|
55
|
+
className: cn("font-black leading-none tabular-nums", emphasis === true ? "text-[34px]" : "text-[26px]", statValueClass(accent, danger)),
|
|
56
|
+
children: value
|
|
57
|
+
}),
|
|
58
|
+
delta
|
|
59
|
+
]
|
|
60
|
+
}),
|
|
61
|
+
sparklineNode === null ? null : /*#__PURE__*/ _jsx("div", {
|
|
62
|
+
className: "mt-0.5",
|
|
63
|
+
children: sparklineNode
|
|
64
|
+
}),
|
|
65
|
+
sub === undefined ? null : /*#__PURE__*/ _jsx("span", {
|
|
66
|
+
className: "text-[10px] tracking-[0.08em] uppercase text-muted-foreground",
|
|
67
|
+
children: sub
|
|
68
|
+
})
|
|
69
|
+
]
|
|
70
|
+
});
|
|
71
|
+
if (onClick === undefined) {
|
|
72
|
+
return /*#__PURE__*/ _jsx("div", {
|
|
73
|
+
"data-slot": "stat-grid-item",
|
|
74
|
+
className: shell,
|
|
75
|
+
children: body
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
return /*#__PURE__*/ _jsx("button", {
|
|
79
|
+
type: "button",
|
|
80
|
+
"data-slot": "stat-grid-item",
|
|
81
|
+
onClick: onClick,
|
|
82
|
+
className: cn(shell, // text-left/w-full: button UA styles centre content and shrink-wrap.
|
|
83
|
+
// Hover/press only on the interactive shell so static tiles stay quiet.
|
|
84
|
+
"w-full cursor-pointer text-left transition-colors hover:border-primary-emphasis active:brightness-95"),
|
|
85
|
+
children: body
|
|
86
|
+
});
|
|
87
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export type StatusDotTone = "neutral" | "emphasis" | "success" | "warning" | "danger";
|
|
2
|
+
export type StatusDotProps = {
|
|
3
|
+
/** Names the state for assistive tech. Required — a bare colour says nothing. */
|
|
4
|
+
readonly label: string;
|
|
5
|
+
/** Adds a ring that pulses outward: this state is live and still changing. */
|
|
6
|
+
readonly live?: boolean;
|
|
7
|
+
readonly tone?: StatusDotTone;
|
|
8
|
+
/** `sm` (8px, default) beside body text; `xs` (6px) inside dense chrome. */
|
|
9
|
+
readonly size?: StatusDotSize;
|
|
10
|
+
readonly className?: string;
|
|
11
|
+
};
|
|
12
|
+
export type StatusDotSize = "xs" | "sm";
|
|
13
|
+
export declare function StatusDot({ label, live, tone, size, className }: StatusDotProps): import("react").JSX.Element;
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { cn } from "../lib/utils.js";
|
|
3
|
+
/**
|
|
4
|
+
* Three tones, not one per status, and that is deliberate. A dot is a non-text
|
|
5
|
+
* UI element and has to clear 3:1 against both the page and a card; the only
|
|
6
|
+
* fills in the theme that do so at 8px are the emphasis orange, the destructive
|
|
7
|
+
* red and the muted ink. A green "done" dot would have to invent a token, and
|
|
8
|
+
* the run's own `Badge` already carries the full status colour on a
|
|
9
|
+
* contrast-tested fill/foreground pair. The dot marks *liveness*; the badge
|
|
10
|
+
* names the state.
|
|
11
|
+
*
|
|
12
|
+
* Classes are spelled out rather than composed at runtime — Tailwind's scanner
|
|
13
|
+
* only emits utilities it can see literally in the source.
|
|
14
|
+
*/ const TONE_CLASS = {
|
|
15
|
+
neutral: "bg-muted-foreground",
|
|
16
|
+
emphasis: "bg-primary-emphasis",
|
|
17
|
+
// success/warning use emphasis orange until dedicated high-contrast
|
|
18
|
+
// fills clear 3:1 at 8px; Badge remains the full-status carrier.
|
|
19
|
+
success: "bg-primary-emphasis",
|
|
20
|
+
warning: "bg-primary-emphasis",
|
|
21
|
+
danger: "bg-destructive"
|
|
22
|
+
};
|
|
23
|
+
/**
|
|
24
|
+
* A state marker carrying its own accessible name — a coloured dot with no
|
|
25
|
+
* label is invisible to a screen reader, so the label is required rather than
|
|
26
|
+
* optional.
|
|
27
|
+
*
|
|
28
|
+
* The `live` ring is a separate `aria-hidden` element: motion says "still
|
|
29
|
+
* changing" to people who can see it, and the label already says so to those
|
|
30
|
+
* who cannot. It stills under the theme's reduced-motion rule.
|
|
31
|
+
*/ const SIZE_CLASS = {
|
|
32
|
+
xs: "size-1.5",
|
|
33
|
+
sm: "size-2"
|
|
34
|
+
};
|
|
35
|
+
export function StatusDot({ label, live = false, tone = "neutral", size = "sm", className }) {
|
|
36
|
+
return /*#__PURE__*/ _jsxs("span", {
|
|
37
|
+
role: "img",
|
|
38
|
+
"aria-label": label,
|
|
39
|
+
className: cn("relative inline-flex shrink-0", SIZE_CLASS[size], className),
|
|
40
|
+
children: [
|
|
41
|
+
live ? /*#__PURE__*/ _jsx("span", {
|
|
42
|
+
"aria-hidden": true,
|
|
43
|
+
className: cn("absolute inset-0 rounded-full [animation:corbits-status-pulse_1.8s_ease-out_infinite]", TONE_CLASS[tone])
|
|
44
|
+
}) : null,
|
|
45
|
+
/*#__PURE__*/ _jsx("span", {
|
|
46
|
+
"aria-hidden": true,
|
|
47
|
+
className: cn("relative size-full rounded-full", TONE_CLASS[tone])
|
|
48
|
+
})
|
|
49
|
+
]
|
|
50
|
+
});
|
|
51
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { StepListItem } from "../lib/workflow-registry.js";
|
|
2
|
+
export type StepListRowProps = {
|
|
3
|
+
readonly step: StepListItem;
|
|
4
|
+
readonly className?: string;
|
|
5
|
+
};
|
|
6
|
+
/** One step row — a mark carrying its own glyph and colour, a name, and the
|
|
7
|
+
* status spelled out in text so it never depends on colour alone. */
|
|
8
|
+
export declare function StepListRow({ step, className }: StepListRowProps): import("react").JSX.Element;
|
|
9
|
+
export type StepListProps = {
|
|
10
|
+
readonly steps: readonly StepListItem[];
|
|
11
|
+
/** Names the list. Required — a bare sequence of rows has no subject. */
|
|
12
|
+
readonly label?: string;
|
|
13
|
+
readonly className?: string;
|
|
14
|
+
};
|
|
15
|
+
/**
|
|
16
|
+
* A run's steps and how far along each one is. `aria-live="polite"` so a
|
|
17
|
+
* step flipping to done or failed is announced without stealing focus from
|
|
18
|
+
* wherever the reader actually is — the same rule `progress-checklist.tsx`
|
|
19
|
+
* follows for a long-running operation's checklist.
|
|
20
|
+
*/
|
|
21
|
+
export declare function StepList({ steps, label, className }: StepListProps): import("react").JSX.Element | null;
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { Check, X } from "lucide-react";
|
|
3
|
+
import { cn } from "../lib/utils.js";
|
|
4
|
+
import { StatusDot } from "./status-dot.js";
|
|
5
|
+
const STATE_LABEL = {
|
|
6
|
+
pending: "Pending",
|
|
7
|
+
active: "Now",
|
|
8
|
+
done: "Done",
|
|
9
|
+
failed: "Failed"
|
|
10
|
+
};
|
|
11
|
+
const MARK_CLASS = {
|
|
12
|
+
pending: "border-input text-muted-foreground",
|
|
13
|
+
active: "border-primary-emphasis bg-primary/10 text-primary-emphasis",
|
|
14
|
+
done: "border-transparent bg-success text-success-foreground",
|
|
15
|
+
failed: "border-transparent bg-destructive text-destructive-foreground"
|
|
16
|
+
};
|
|
17
|
+
const LABEL_CLASS = {
|
|
18
|
+
pending: "text-muted-foreground",
|
|
19
|
+
active: "font-medium text-primary-emphasis",
|
|
20
|
+
done: "text-foreground",
|
|
21
|
+
failed: "font-medium text-destructive"
|
|
22
|
+
};
|
|
23
|
+
/** One step row — a mark carrying its own glyph and colour, a name, and the
|
|
24
|
+
* status spelled out in text so it never depends on colour alone. */ export function StepListRow({ step, className }) {
|
|
25
|
+
return /*#__PURE__*/ _jsxs("li", {
|
|
26
|
+
"data-step-status": step.status,
|
|
27
|
+
className: cn("grid grid-cols-[20px_minmax(0,1fr)_auto] items-start gap-2 py-1.5", className),
|
|
28
|
+
children: [
|
|
29
|
+
/*#__PURE__*/ _jsx("span", {
|
|
30
|
+
"aria-hidden": true,
|
|
31
|
+
className: cn("mt-0.5 grid size-5 place-items-center rounded-sm border text-[10px] font-semibold", MARK_CLASS[step.status]),
|
|
32
|
+
children: step.status === "done" ? /*#__PURE__*/ _jsx(Check, {
|
|
33
|
+
className: "size-3"
|
|
34
|
+
}) : step.status === "failed" ? /*#__PURE__*/ _jsx(X, {
|
|
35
|
+
className: "size-3"
|
|
36
|
+
}) : step.status === "active" ? /*#__PURE__*/ _jsx(StatusDot, {
|
|
37
|
+
label: "",
|
|
38
|
+
tone: "emphasis",
|
|
39
|
+
live: true
|
|
40
|
+
}) : null
|
|
41
|
+
}),
|
|
42
|
+
/*#__PURE__*/ _jsxs("span", {
|
|
43
|
+
className: "min-w-0",
|
|
44
|
+
children: [
|
|
45
|
+
/*#__PURE__*/ _jsx("span", {
|
|
46
|
+
className: cn("block truncate text-sm", LABEL_CLASS[step.status]),
|
|
47
|
+
children: step.name
|
|
48
|
+
}),
|
|
49
|
+
step.meta === undefined ? null : /*#__PURE__*/ _jsx("span", {
|
|
50
|
+
className: "block truncate text-xs text-muted-foreground",
|
|
51
|
+
children: step.meta
|
|
52
|
+
})
|
|
53
|
+
]
|
|
54
|
+
}),
|
|
55
|
+
/*#__PURE__*/ _jsx("span", {
|
|
56
|
+
className: "shrink-0 text-[10.5px] font-bold uppercase tracking-[0.05em] text-muted-foreground",
|
|
57
|
+
children: STATE_LABEL[step.status]
|
|
58
|
+
})
|
|
59
|
+
]
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* A run's steps and how far along each one is. `aria-live="polite"` so a
|
|
64
|
+
* step flipping to done or failed is announced without stealing focus from
|
|
65
|
+
* wherever the reader actually is — the same rule `progress-checklist.tsx`
|
|
66
|
+
* follows for a long-running operation's checklist.
|
|
67
|
+
*/ export function StepList({ steps, label = "Steps", className }) {
|
|
68
|
+
if (steps.length === 0) return null;
|
|
69
|
+
return /*#__PURE__*/ _jsx("ol", {
|
|
70
|
+
"aria-label": label,
|
|
71
|
+
"aria-live": "polite",
|
|
72
|
+
className: cn("flex flex-col", className),
|
|
73
|
+
children: steps.map((step)=>/*#__PURE__*/ _jsx(StepListRow, {
|
|
74
|
+
step: step
|
|
75
|
+
}, step.id))
|
|
76
|
+
});
|
|
77
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
export type SwitchProps = {
|
|
2
|
+
readonly checked: boolean;
|
|
3
|
+
readonly onCheckedChange: (checked: boolean) => void;
|
|
4
|
+
/** Accessible name. Omit only when a `<label htmlFor>` already names it. */
|
|
5
|
+
readonly label?: string;
|
|
6
|
+
readonly id?: string;
|
|
7
|
+
readonly disabled?: boolean;
|
|
8
|
+
/** Ids of the text describing the setting, for `aria-describedby`. */
|
|
9
|
+
readonly describedBy?: string;
|
|
10
|
+
readonly className?: string;
|
|
11
|
+
};
|
|
12
|
+
/**
|
|
13
|
+
* An on/off setting.
|
|
14
|
+
*
|
|
15
|
+
* `role="switch"` on a real `<button>`, not a styled checkbox: a switch takes
|
|
16
|
+
* effect immediately and a checkbox implies a form you still have to submit.
|
|
17
|
+
* Screen readers say "on/off" for a switch and "checked/unchecked" for a
|
|
18
|
+
* checkbox, and that difference is the whole reason the role exists.
|
|
19
|
+
*
|
|
20
|
+
* The knob is a `<span>` inside the button rather than a `::after`, so its
|
|
21
|
+
* transform animates independently of the track's colour transition.
|
|
22
|
+
*/
|
|
23
|
+
export declare function Switch({ checked, onCheckedChange, label, id, disabled, describedBy, className, }: SwitchProps): import("react").JSX.Element;
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { cn } from "../lib/utils.js";
|
|
3
|
+
/**
|
|
4
|
+
* An on/off setting.
|
|
5
|
+
*
|
|
6
|
+
* `role="switch"` on a real `<button>`, not a styled checkbox: a switch takes
|
|
7
|
+
* effect immediately and a checkbox implies a form you still have to submit.
|
|
8
|
+
* Screen readers say "on/off" for a switch and "checked/unchecked" for a
|
|
9
|
+
* checkbox, and that difference is the whole reason the role exists.
|
|
10
|
+
*
|
|
11
|
+
* The knob is a `<span>` inside the button rather than a `::after`, so its
|
|
12
|
+
* transform animates independently of the track's colour transition.
|
|
13
|
+
*/ export function Switch({ checked, onCheckedChange, label, id, disabled = false, describedBy, className }) {
|
|
14
|
+
return /*#__PURE__*/ _jsx("button", {
|
|
15
|
+
type: "button",
|
|
16
|
+
id: id,
|
|
17
|
+
role: "switch",
|
|
18
|
+
"aria-checked": checked,
|
|
19
|
+
"aria-label": label,
|
|
20
|
+
"aria-describedby": describedBy,
|
|
21
|
+
disabled: disabled,
|
|
22
|
+
onClick: ()=>onCheckedChange(!checked),
|
|
23
|
+
className: cn("inline-flex h-5 w-9 shrink-0 items-center rounded-full border border-transparent p-0.5 transition-colors disabled:opacity-50", checked ? "bg-primary" : "bg-input", className),
|
|
24
|
+
children: /*#__PURE__*/ _jsx("span", {
|
|
25
|
+
"aria-hidden": true,
|
|
26
|
+
className: cn("size-4 rounded-full bg-background transition-transform", checked && "translate-x-4")
|
|
27
|
+
})
|
|
28
|
+
});
|
|
29
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type * as React from "react";
|
|
2
|
+
export declare function Table({ className, ...props }: React.ComponentProps<"table">): React.JSX.Element;
|
|
3
|
+
export declare function TableHeader({ className, ...props }: React.ComponentProps<"thead">): React.JSX.Element;
|
|
4
|
+
export declare function TableBody({ className, ...props }: React.ComponentProps<"tbody">): React.JSX.Element;
|
|
5
|
+
export declare function TableRow({ className, ...props }: React.ComponentProps<"tr">): React.JSX.Element;
|
|
6
|
+
export declare function TableHead({ className, ...props }: React.ComponentProps<"th">): React.JSX.Element;
|
|
7
|
+
export declare function TableCell({ className, ...props }: React.ComponentProps<"td">): React.JSX.Element;
|
|
8
|
+
export declare function TableCaption({ className, ...props }: React.ComponentProps<"caption">): React.JSX.Element;
|
package/dist/ui/table.js
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { cn } from "../lib/utils.js";
|
|
3
|
+
export function Table({ className, ...props }) {
|
|
4
|
+
return /*#__PURE__*/ _jsx("div", {
|
|
5
|
+
className: "relative w-full overflow-x-auto",
|
|
6
|
+
children: /*#__PURE__*/ _jsx("table", {
|
|
7
|
+
"data-slot": "table",
|
|
8
|
+
className: cn("w-full caption-bottom text-sm", className),
|
|
9
|
+
...props
|
|
10
|
+
})
|
|
11
|
+
});
|
|
12
|
+
}
|
|
13
|
+
export function TableHeader({ className, ...props }) {
|
|
14
|
+
return /*#__PURE__*/ _jsx("thead", {
|
|
15
|
+
className: cn("[&_tr]:border-b [&_tr]:border-border", className),
|
|
16
|
+
...props
|
|
17
|
+
});
|
|
18
|
+
}
|
|
19
|
+
export function TableBody({ className, ...props }) {
|
|
20
|
+
return /*#__PURE__*/ _jsx("tbody", {
|
|
21
|
+
className: cn("[&_tr:last-child]:border-0", className),
|
|
22
|
+
...props
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
export function TableRow({ className, ...props }) {
|
|
26
|
+
return /*#__PURE__*/ _jsx("tr", {
|
|
27
|
+
className: cn("border-b border-border transition-colors hover:bg-muted", className),
|
|
28
|
+
...props
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
export function TableHead({ className, ...props }) {
|
|
32
|
+
return /*#__PURE__*/ _jsx("th", {
|
|
33
|
+
className: cn("h-10 px-3 text-left align-middle font-medium text-muted-foreground", className),
|
|
34
|
+
...props
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
export function TableCell({ className, ...props }) {
|
|
38
|
+
return /*#__PURE__*/ _jsx("td", {
|
|
39
|
+
className: cn("p-3 align-middle", className),
|
|
40
|
+
...props
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
export function TableCaption({ className, ...props }) {
|
|
44
|
+
return /*#__PURE__*/ _jsx("caption", {
|
|
45
|
+
className: cn("mt-3 text-sm text-muted-foreground", className),
|
|
46
|
+
...props
|
|
47
|
+
});
|
|
48
|
+
}
|