@corbits/react-ui 0.1.0 → 0.3.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 +174 -499
- package/README.md +228 -85
- package/dist/blocks/login/auth-layout.d.ts +1 -1
- package/dist/blocks/login/auth-layout.js +3 -33
- package/dist/blocks/login/login-form.js +6 -119
- package/dist/hooks/use-command-palette-navigation.js +18 -17
- package/dist/hooks/use-controllable-state.d.ts +2 -2
- package/dist/hooks/use-controllable-state.js +23 -15
- package/dist/hooks/use-delayed-autofocus.js +10 -11
- package/dist/hooks/use-dismissable-popover.d.ts +2 -2
- package/dist/hooks/use-dismissable-popover.js +21 -29
- package/dist/hooks/use-list-selection.js +54 -85
- package/dist/hooks/use-prefers-reduced-motion.js +8 -4
- package/dist/hooks/use-scroll-current-into-view.js +5 -7
- package/dist/index.d.ts +0 -11
- package/dist/index.js +10 -19
- package/dist/lib/artifact.js +16 -35
- package/dist/lib/chart-geometry.js +33 -20
- package/dist/lib/chart-palette.js +17 -31
- package/dist/lib/chat-message.js +32 -13
- package/dist/lib/chat-parts.js +2 -1
- package/dist/lib/csv.js +42 -26
- package/dist/lib/metrics.js +30 -48
- package/dist/lib/now-item.js +26 -25
- package/dist/lib/relative-time.js +14 -29
- package/dist/lib/theme.js +32 -30
- package/dist/lib/url.js +9 -8
- package/dist/lib/workflow-display-flow.js +37 -33
- package/dist/lib/workflow-registry.d.ts +0 -41
- package/dist/lib/workflow-registry.js +13 -23
- package/dist/lib/workflow-run-error.js +16 -20
- package/dist/lib/workflow-run-progress.js +94 -52
- package/dist/lib/workflow-run.js +17 -13
- package/dist/styles.css +257 -19
- package/dist/test/render-hook.js +11 -12
- package/dist/theme.css +92 -14
- package/dist/ui/agent-turn.d.ts +1 -1
- package/dist/ui/agent-turn.js +4 -37
- package/dist/ui/animated-number.js +15 -28
- package/dist/ui/approval-card.js +5 -90
- package/dist/ui/artifact-body.js +47 -125
- package/dist/ui/artifact-notice.d.ts +1 -1
- package/dist/ui/artifact-notice.js +9 -16
- package/dist/ui/avatar.d.ts +21 -4
- package/dist/ui/avatar.js +40 -49
- package/dist/ui/badge.js +4 -12
- package/dist/ui/bar-chart.d.ts +1 -1
- package/dist/ui/bar-chart.js +22 -74
- package/dist/ui/block-card.js +7 -45
- package/dist/ui/boot-screen.d.ts +1 -1
- package/dist/ui/boot-screen.js +4 -33
- package/dist/ui/bulk-action-bar.d.ts +1 -1
- package/dist/ui/bulk-action-bar.js +14 -33
- package/dist/ui/button.js +10 -24
- package/dist/ui/card.js +5 -25
- package/dist/ui/category-bars.js +14 -59
- package/dist/ui/chart-frame.d.ts +2 -2
- package/dist/ui/chart-frame.js +6 -85
- package/dist/ui/chat-composer.js +4 -16
- package/dist/ui/chat-dock-timing.js +7 -3
- package/dist/ui/chat-input.js +20 -100
- package/dist/ui/chat-panel.d.ts +1 -1
- package/dist/ui/chat-panel.js +7 -41
- package/dist/ui/chat-thread.js +13 -31
- package/dist/ui/checkbox.js +10 -52
- package/dist/ui/command-palette.js +85 -246
- package/dist/ui/compare-body.d.ts +1 -1
- package/dist/ui/compare-body.js +28 -98
- package/dist/ui/confirm-button.js +8 -15
- package/dist/ui/corbits-mark.js +7 -16
- package/dist/ui/csv-table.d.ts +1 -1
- package/dist/ui/csv-table.js +8 -50
- package/dist/ui/dialog.d.ts +1 -1
- package/dist/ui/dialog.js +32 -62
- package/dist/ui/dictation-status-line.js +7 -25
- package/dist/ui/dither-canvas.d.ts +1 -1
- package/dist/ui/dither-canvas.js +31 -56
- package/dist/ui/embed-body.d.ts +1 -1
- package/dist/ui/embed-body.js +7 -56
- package/dist/ui/empty-state.d.ts +1 -1
- package/dist/ui/empty-state.js +3 -26
- package/dist/ui/file-input.js +17 -37
- package/dist/ui/filter-bar.d.ts +1 -1
- package/dist/ui/filter-bar.js +11 -71
- package/dist/ui/filter-chip.d.ts +1 -1
- package/dist/ui/filter-chip.js +7 -15
- package/dist/ui/gate-block.d.ts +2 -1
- package/dist/ui/gate-block.js +4 -29
- package/dist/ui/horizontal-stepper.d.ts +1 -1
- package/dist/ui/horizontal-stepper.js +18 -45
- package/dist/ui/input.js +1 -6
- package/dist/ui/inspector-shell.d.ts +5 -5
- package/dist/ui/inspector-shell.js +14 -81
- package/dist/ui/intake-form.d.ts +1 -1
- package/dist/ui/intake-form.js +21 -97
- package/dist/ui/kind-card-grid.js +9 -31
- package/dist/ui/library-page-header.js +4 -32
- package/dist/ui/list-detail.js +5 -35
- package/dist/ui/live-run-banner.d.ts +1 -1
- package/dist/ui/live-run-banner.js +5 -15
- package/dist/ui/live-status-line.js +6 -24
- package/dist/ui/menu.js +7 -24
- package/dist/ui/message-bubble.d.ts +3 -3
- package/dist/ui/message-bubble.js +5 -44
- package/dist/ui/mic-button.d.ts +1 -1
- package/dist/ui/mic-button.js +15 -21
- package/dist/ui/mic-permission-dialog.js +5 -41
- package/dist/ui/notifications-bell.js +9 -43
- package/dist/ui/now-cards.d.ts +2 -2
- package/dist/ui/now-cards.js +16 -94
- package/dist/ui/page-panel.js +11 -11
- package/dist/ui/page-shell.js +4 -11
- package/dist/ui/parts-renderer.js +51 -149
- package/dist/ui/profile-card.js +7 -111
- package/dist/ui/progress-checklist.js +11 -49
- package/dist/ui/provider-mark.d.ts +2 -2
- package/dist/ui/provider-mark.js +9 -16
- package/dist/ui/quick-reply-chips.js +6 -14
- package/dist/ui/quote-card.js +12 -32
- package/dist/ui/reasoning-block.d.ts +1 -1
- package/dist/ui/reasoning-block.js +14 -33
- package/dist/ui/research-body.js +32 -213
- package/dist/ui/rich-empty-state.js +6 -48
- package/dist/ui/run-now-button.js +14 -15
- package/dist/ui/section.d.ts +1 -1
- package/dist/ui/section.js +4 -40
- package/dist/ui/select.js +1 -15
- package/dist/ui/selection-checkbox.d.ts +1 -1
- package/dist/ui/selection-checkbox.js +11 -29
- package/dist/ui/settings-panel.js +7 -50
- package/dist/ui/shimmer-text.js +3 -6
- package/dist/ui/sidebar-item-row.d.ts +1 -1
- package/dist/ui/sidebar-item-row.js +9 -39
- package/dist/ui/sidebar-panel.js +15 -40
- package/dist/ui/sidebar.js +15 -76
- package/dist/ui/skeleton.js +3 -7
- package/dist/ui/sortable-table.js +29 -72
- package/dist/ui/sparkline.js +14 -38
- package/dist/ui/stat-grid.js +17 -52
- package/dist/ui/status-dot.d.ts +1 -1
- package/dist/ui/status-dot.js +8 -20
- package/dist/ui/step-list.d.ts +1 -0
- package/dist/ui/step-list.js +11 -50
- package/dist/ui/switch.js +4 -16
- package/dist/ui/table.js +7 -32
- package/dist/ui/tabs.js +39 -54
- package/dist/ui/textarea.js +10 -19
- package/dist/ui/theme-provider.js +54 -78
- package/dist/ui/theme-toggle.js +13 -16
- package/dist/ui/thinking-indicator.js +3 -15
- package/dist/ui/thinking-label.js +16 -35
- package/dist/ui/thinking-mark.d.ts +1 -1
- package/dist/ui/thinking-mark.js +4 -145
- package/dist/ui/time-series-chart.js +43 -174
- package/dist/ui/toast.js +12 -20
- package/dist/ui/token-mosaic.js +5 -43
- package/dist/ui/tool-block.js +18 -70
- package/dist/ui/tool-narrative.d.ts +1 -1
- package/dist/ui/tool-narrative.js +10 -57
- package/dist/ui/tool-picker.js +57 -145
- package/dist/ui/tooltip.d.ts +1 -1
- package/dist/ui/tooltip.js +4 -33
- package/dist/ui/top-bar.js +14 -72
- package/dist/ui/trace-waterfall.d.ts +1 -1
- package/dist/ui/trace-waterfall.js +21 -93
- package/dist/ui/typing-indicator.d.ts +1 -1
- package/dist/ui/typing-indicator.js +4 -18
- package/dist/ui/view-toggle.js +10 -29
- package/dist/ui/voice-waveform.js +3 -11
- package/package.json +96 -535
|
@@ -14,7 +14,7 @@ export type SidebarItemRowProps = {
|
|
|
14
14
|
* one more frame (~150ms) so the leave transition gets to play. List
|
|
15
15
|
* membership is the consumer's data — nothing here manages it for you.
|
|
16
16
|
*/
|
|
17
|
-
readonly leaving?: boolean;
|
|
17
|
+
readonly leaving?: boolean | undefined;
|
|
18
18
|
readonly onSelect?: () => void;
|
|
19
19
|
readonly className?: string;
|
|
20
20
|
};
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
"use client";
|
|
1
2
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
3
|
import { useEffect, useState } from "react";
|
|
3
4
|
import { cn } from "../lib/utils.js";
|
|
@@ -19,46 +20,15 @@ import { cn } from "../lib/utils.js";
|
|
|
19
20
|
* component to supply one.
|
|
20
21
|
*
|
|
21
22
|
* Not `ui/sidebar`'s `SidebarItem` — that's the single-column family's row.
|
|
22
|
-
*/
|
|
23
|
+
*/
|
|
24
|
+
export function SidebarItemRow({ name, leading, meta, action, unread = false, selected = false, leaving = false, onSelect, className, }) {
|
|
23
25
|
const [mounted, setMounted] = useState(false);
|
|
24
|
-
useEffect(()=>{
|
|
25
|
-
const raf = requestAnimationFrame(()=>setMounted(true));
|
|
26
|
-
return ()=>cancelAnimationFrame(raf);
|
|
26
|
+
useEffect(() => {
|
|
27
|
+
const raf = requestAnimationFrame(() => setMounted(true));
|
|
28
|
+
return () => cancelAnimationFrame(raf);
|
|
27
29
|
}, []);
|
|
28
30
|
const state = !mounted ? "entering" : leaving ? "leaving" : "visible";
|
|
29
|
-
return
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
className: cn("group/row transition-[transform,opacity] duration-150 ease-out", state === "entering" && "-translate-y-1 opacity-0", state === "leaving" && "pointer-events-none translate-y-1 opacity-0", state === "visible" && "translate-y-0 opacity-100", className),
|
|
33
|
-
children: /*#__PURE__*/ _jsxs("div", {
|
|
34
|
-
className: cn("flex w-full items-center gap-2 rounded-[var(--sidebar-row-radius)] pr-1.5 text-sm transition-colors", selected ? "bg-[var(--sidebar-row-selected-bg)] text-primary-emphasis" : "text-foreground hover:bg-muted"),
|
|
35
|
-
children: [
|
|
36
|
-
/*#__PURE__*/ _jsxs("button", {
|
|
37
|
-
type: "button",
|
|
38
|
-
"aria-current": selected ? "true" : undefined,
|
|
39
|
-
onClick: onSelect,
|
|
40
|
-
className: "flex min-w-0 flex-1 items-center gap-2 rounded-[var(--sidebar-row-radius)] py-1.5 pl-2 text-left active:brightness-95",
|
|
41
|
-
children: [
|
|
42
|
-
leading === undefined ? null : /*#__PURE__*/ _jsx("span", {
|
|
43
|
-
className: "grid size-5 shrink-0 place-items-center [&_svg]:size-4",
|
|
44
|
-
"aria-hidden": true,
|
|
45
|
-
children: leading
|
|
46
|
-
}),
|
|
47
|
-
/*#__PURE__*/ _jsx("span", {
|
|
48
|
-
className: cn("min-w-0 flex-1 truncate", unread && "font-semibold"),
|
|
49
|
-
children: name
|
|
50
|
-
}),
|
|
51
|
-
meta === undefined ? null : /*#__PURE__*/ _jsx("span", {
|
|
52
|
-
className: "flex shrink-0 items-center gap-1.5",
|
|
53
|
-
children: meta
|
|
54
|
-
})
|
|
55
|
-
]
|
|
56
|
-
}),
|
|
57
|
-
action === undefined ? null : /*#__PURE__*/ _jsx("span", {
|
|
58
|
-
className: "shrink-0 opacity-0 transition-opacity group-hover/row:opacity-100 group-focus-within/row:opacity-100",
|
|
59
|
-
children: action
|
|
60
|
-
})
|
|
61
|
-
]
|
|
62
|
-
})
|
|
63
|
-
});
|
|
31
|
+
return (_jsx("li", { "data-slot": "sidebar-item-row", "data-state": state, className: cn("group/row transition-[transform,opacity] duration-150 ease-out", state === "entering" && "-translate-y-1 opacity-0", state === "leaving" && "pointer-events-none translate-y-1 opacity-0", state === "visible" && "translate-y-0 opacity-100", className), children: _jsxs("div", { className: cn("flex w-full items-center gap-2 rounded-[var(--sidebar-row-radius)] pr-1.5 text-sm transition-colors", selected
|
|
32
|
+
? "bg-[var(--sidebar-row-selected-bg)] text-primary-emphasis"
|
|
33
|
+
: "text-foreground hover:bg-muted"), children: [_jsxs("button", { type: "button", "aria-current": selected ? "true" : undefined, onClick: onSelect, className: "flex min-w-0 flex-1 items-center gap-2 rounded-[var(--sidebar-row-radius)] py-1.5 pl-2 text-left active:brightness-95", children: [leading === undefined ? null : (_jsx("span", { className: "grid size-5 shrink-0 place-items-center [&_svg]:size-4", "aria-hidden": true, children: leading })), _jsx("span", { className: cn("min-w-0 flex-1 truncate", unread && "font-semibold"), children: name }), meta === undefined ? null : (_jsx("span", { className: "flex shrink-0 items-center gap-1.5", children: meta }))] }), action === undefined ? null : (_jsx("span", { className: "shrink-0 opacity-0 transition-opacity group-hover/row:opacity-100 group-focus-within/row:opacity-100", children: action }))] }) }));
|
|
64
34
|
}
|
package/dist/ui/sidebar-panel.js
CHANGED
|
@@ -5,52 +5,27 @@ import { cn } from "../lib/utils.js";
|
|
|
5
5
|
* assembles `SidebarPanelHeader`, `SidebarPanelPins`, `SidebarPanelBody` and
|
|
6
6
|
* `SidebarPanelFooter` in whatever combination the active page calls for, and
|
|
7
7
|
* the root only supplies the width, the border and the flex column.
|
|
8
|
-
*/
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
className: cn("flex h-full w-72 shrink-0 flex-col border-r border-border bg-card text-card-foreground", className),
|
|
12
|
-
...props
|
|
13
|
-
});
|
|
8
|
+
*/
|
|
9
|
+
export function SidebarPanel({ className, ...props }) {
|
|
10
|
+
return (_jsx("div", { "data-slot": "sidebar-panel", className: cn("flex h-full w-72 shrink-0 flex-col border-r border-border bg-card text-card-foreground", className), ...props }));
|
|
14
11
|
}
|
|
15
|
-
/** Not `ui/sidebar`'s `SidebarHeader` — that's the single-column family's header slot. */
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
className: cn("flex min-h-14 shrink-0 items-center justify-between gap-2 border-b border-border px-3", className),
|
|
19
|
-
...props,
|
|
20
|
-
children: [
|
|
21
|
-
/*#__PURE__*/ _jsx("h2", {
|
|
22
|
-
className: "min-w-0 truncate text-sm font-semibold",
|
|
23
|
-
children: title
|
|
24
|
-
}),
|
|
25
|
-
action === undefined ? null : /*#__PURE__*/ _jsx("div", {
|
|
26
|
-
className: "shrink-0",
|
|
27
|
-
children: action
|
|
28
|
-
})
|
|
29
|
-
]
|
|
30
|
-
});
|
|
12
|
+
/** Not `ui/sidebar`'s `SidebarHeader` — that's the single-column family's header slot. */
|
|
13
|
+
export function SidebarPanelHeader({ title, action, className, ...props }) {
|
|
14
|
+
return (_jsxs("div", { "data-slot": "sidebar-panel-header", className: cn("flex min-h-14 shrink-0 items-center justify-between gap-2 border-b border-border px-3", className), ...props, children: [_jsx("h2", { className: "min-w-0 truncate text-sm font-semibold", children: title }), action === undefined ? null : _jsx("div", { className: "shrink-0", children: action })] }));
|
|
31
15
|
}
|
|
32
16
|
/**
|
|
33
17
|
* Global pins live above the per-page sections and never scroll away with
|
|
34
18
|
* them — that is the entire reason this is a separate slot rather than just
|
|
35
19
|
* the first `SidebarPanelSection` inside the body.
|
|
36
|
-
*/
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
className: cn("shrink-0 border-b border-border px-2 py-2", className),
|
|
40
|
-
...props
|
|
41
|
-
});
|
|
20
|
+
*/
|
|
21
|
+
export function SidebarPanelPins({ className, ...props }) {
|
|
22
|
+
return (_jsx("div", { "data-slot": "sidebar-panel-pins", className: cn("shrink-0 border-b border-border px-2 py-2", className), ...props }));
|
|
42
23
|
}
|
|
43
|
-
/** The scrollable region: sections go here. Everything above and below it is pinned. */
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
className: cn("min-h-0 flex-1 overflow-y-auto py-1", className),
|
|
47
|
-
...props
|
|
48
|
-
});
|
|
24
|
+
/** The scrollable region: sections go here. Everything above and below it is pinned. */
|
|
25
|
+
export function SidebarPanelBody({ className, ...props }) {
|
|
26
|
+
return (_jsx("div", { "data-slot": "sidebar-panel-body", className: cn("min-h-0 flex-1 overflow-y-auto py-1", className), ...props }));
|
|
49
27
|
}
|
|
50
|
-
/** Not `ui/sidebar`'s `SidebarFooter` — that's the single-column family's footer slot. */
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
className: cn("shrink-0 border-t border-border p-2", className),
|
|
54
|
-
...props
|
|
55
|
-
});
|
|
28
|
+
/** Not `ui/sidebar`'s `SidebarFooter` — that's the single-column family's footer slot. */
|
|
29
|
+
export function SidebarPanelFooter({ className, ...props }) {
|
|
30
|
+
return (_jsx("div", { "data-slot": "sidebar-panel-footer", className: cn("shrink-0 border-t border-border p-2", className), ...props }));
|
|
56
31
|
}
|
package/dist/ui/sidebar.js
CHANGED
|
@@ -17,95 +17,34 @@ import { cn } from "../lib/utils.js";
|
|
|
17
17
|
*
|
|
18
18
|
* Collapsing hides labels with `sr-only`, never `hidden`: the icon-only rail
|
|
19
19
|
* must keep its accessible names or it is unusable with a screen reader.
|
|
20
|
-
*/
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
"data-collapsed": collapsed,
|
|
24
|
-
className: cn("group/sidebar flex h-full shrink-0 flex-col border-r border-border bg-card text-card-foreground", "w-60 transition-[width] duration-200 data-[collapsed=true]:w-14", className),
|
|
25
|
-
...props
|
|
26
|
-
});
|
|
20
|
+
*/
|
|
21
|
+
export function Sidebar({ collapsed = false, className, ...props }) {
|
|
22
|
+
return (_jsx("aside", { "data-slot": "sidebar", "data-collapsed": collapsed, className: cn("group/sidebar flex h-full shrink-0 flex-col border-r border-border bg-card text-card-foreground", "w-60 transition-[width] duration-200 data-[collapsed=true]:w-14", className), ...props }));
|
|
27
23
|
}
|
|
28
24
|
export function SidebarHeader({ className, ...props }) {
|
|
29
|
-
return
|
|
30
|
-
"data-slot": "sidebar-header",
|
|
31
|
-
className: cn("flex min-h-14 items-center gap-2 border-b border-border px-3", className),
|
|
32
|
-
...props
|
|
33
|
-
});
|
|
25
|
+
return (_jsx("div", { "data-slot": "sidebar-header", className: cn("flex min-h-14 items-center gap-2 border-b border-border px-3", className), ...props }));
|
|
34
26
|
}
|
|
35
27
|
export function SidebarContent({ className, ...props }) {
|
|
36
|
-
return
|
|
37
|
-
"data-slot": "sidebar-content",
|
|
38
|
-
className: cn("min-h-0 flex-1 overflow-y-auto py-2", className),
|
|
39
|
-
...props
|
|
40
|
-
});
|
|
28
|
+
return (_jsx("div", { "data-slot": "sidebar-content", className: cn("min-h-0 flex-1 overflow-y-auto py-2", className), ...props }));
|
|
41
29
|
}
|
|
42
30
|
export function SidebarFooter({ className, ...props }) {
|
|
43
|
-
return
|
|
44
|
-
"data-slot": "sidebar-footer",
|
|
45
|
-
className: cn("border-t border-border p-2", className),
|
|
46
|
-
...props
|
|
47
|
-
});
|
|
31
|
+
return (_jsx("div", { "data-slot": "sidebar-footer", className: cn("border-t border-border p-2", className), ...props }));
|
|
48
32
|
}
|
|
49
|
-
/** One nav section. `label` is required — an unlabelled group is invisible to AT. */
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
"aria-label": label,
|
|
53
|
-
className: cn("px-2 py-1", className),
|
|
54
|
-
...props,
|
|
55
|
-
children: [
|
|
56
|
-
/*#__PURE__*/ _jsx("p", {
|
|
57
|
-
className: "px-2 py-1 text-[11px] font-semibold tracking-[0.12em] text-muted-foreground uppercase group-data-[collapsed=true]/sidebar:sr-only",
|
|
58
|
-
children: label
|
|
59
|
-
}),
|
|
60
|
-
/*#__PURE__*/ _jsx("ul", {
|
|
61
|
-
className: "flex flex-col gap-0.5",
|
|
62
|
-
children: children
|
|
63
|
-
})
|
|
64
|
-
]
|
|
65
|
-
});
|
|
33
|
+
/** One nav section. `label` is required — an unlabelled group is invisible to AT. */
|
|
34
|
+
export function SidebarSection({ label, className, children, ...props }) {
|
|
35
|
+
return (_jsxs("nav", { "data-slot": "sidebar-section", "aria-label": label, className: cn("px-2 py-1", className), ...props, children: [_jsx("p", { className: "px-2 py-1 text-[11px] font-semibold tracking-[0.12em] text-muted-foreground uppercase group-data-[collapsed=true]/sidebar:sr-only", children: label }), _jsx("ul", { className: "flex flex-col gap-0.5", children: children })] }));
|
|
66
36
|
}
|
|
67
37
|
export function SidebarItem({ active = false, icon, count, asChild = false, className, children, ...props }) {
|
|
68
38
|
const Comp = asChild ? Slot : "a";
|
|
69
|
-
return
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
"aria-current": active ? "page" : undefined,
|
|
73
|
-
className: cn("flex items-center gap-2.5 rounded-md px-2 py-2 text-sm transition-colors", "group-data-[collapsed=true]/sidebar:justify-center", active ? "bg-primary/10 font-medium text-primary-emphasis" : "text-muted-foreground hover:bg-muted hover:text-foreground", className),
|
|
74
|
-
...props,
|
|
75
|
-
children: [
|
|
76
|
-
icon === undefined ? null : /*#__PURE__*/ _jsx("span", {
|
|
77
|
-
className: "grid size-4 shrink-0 place-items-center [&_svg]:size-4",
|
|
78
|
-
"aria-hidden": true,
|
|
79
|
-
children: icon
|
|
80
|
-
}),
|
|
81
|
-
/*#__PURE__*/ _jsx("span", {
|
|
82
|
-
className: "min-w-0 flex-1 truncate group-data-[collapsed=true]/sidebar:sr-only",
|
|
83
|
-
children: children
|
|
84
|
-
}),
|
|
85
|
-
count === undefined ? null : /*#__PURE__*/ _jsx("span", {
|
|
86
|
-
className: "shrink-0 rounded-full bg-muted px-1.5 py-0.5 font-mono text-[11px] text-muted-foreground group-data-[collapsed=true]/sidebar:sr-only",
|
|
87
|
-
children: count
|
|
88
|
-
})
|
|
89
|
-
]
|
|
90
|
-
})
|
|
91
|
-
});
|
|
39
|
+
return (_jsx("li", { children: _jsxs(Comp, { "data-slot": "sidebar-item", "aria-current": active ? "page" : undefined, className: cn("flex items-center gap-2.5 rounded-md px-2 py-2 text-sm transition-colors", "group-data-[collapsed=true]/sidebar:justify-center", active
|
|
40
|
+
? "bg-primary/10 font-medium text-primary-emphasis"
|
|
41
|
+
: "text-muted-foreground hover:bg-muted hover:text-foreground", className), ...props, children: [icon === undefined ? null : (_jsx("span", { className: "grid size-4 shrink-0 place-items-center [&_svg]:size-4", "aria-hidden": true, children: icon })), _jsx("span", { className: "min-w-0 flex-1 truncate group-data-[collapsed=true]/sidebar:sr-only", children: children }), count === undefined ? null : (_jsx("span", { className: "shrink-0 rounded-full bg-muted px-1.5 py-0.5 font-mono text-[11px] text-muted-foreground group-data-[collapsed=true]/sidebar:sr-only", children: count }))] }) }));
|
|
92
42
|
}
|
|
93
43
|
/**
|
|
94
44
|
* Collapse control. `aria-expanded` describes the rail it controls, so pass the
|
|
95
45
|
* rail's id in `aria-controls` when the button lives outside the `<aside>`.
|
|
96
|
-
*/
|
|
46
|
+
*/
|
|
47
|
+
export function SidebarCollapseToggle({ collapsed, onToggle, className, ...props }) {
|
|
97
48
|
const Icon = collapsed ? PanelLeftOpen : PanelLeftClose;
|
|
98
|
-
return
|
|
99
|
-
type: "button",
|
|
100
|
-
"data-slot": "sidebar-collapse-toggle",
|
|
101
|
-
"aria-expanded": !collapsed,
|
|
102
|
-
"aria-label": collapsed ? "Expand sidebar" : "Collapse sidebar",
|
|
103
|
-
onClick: onToggle,
|
|
104
|
-
className: cn("grid size-8 shrink-0 place-items-center rounded-md text-muted-foreground transition-colors hover:bg-muted hover:text-foreground", className),
|
|
105
|
-
...props,
|
|
106
|
-
children: /*#__PURE__*/ _jsx(Icon, {
|
|
107
|
-
className: "size-4",
|
|
108
|
-
"aria-hidden": true
|
|
109
|
-
})
|
|
110
|
-
});
|
|
49
|
+
return (_jsx("button", { type: "button", "data-slot": "sidebar-collapse-toggle", "aria-expanded": !collapsed, "aria-label": collapsed ? "Expand sidebar" : "Collapse sidebar", onClick: onToggle, className: cn("grid size-8 shrink-0 place-items-center rounded-md text-muted-foreground transition-colors hover:bg-muted hover:text-foreground", className), ...props, children: _jsx(Icon, { className: "size-4", "aria-hidden": true }) }));
|
|
111
50
|
}
|
package/dist/ui/skeleton.js
CHANGED
|
@@ -10,11 +10,7 @@ import { cn } from "../lib/utils.js";
|
|
|
10
10
|
* `aria-hidden`, always. A screen reader should hear "Loading…" once from a
|
|
11
11
|
* sibling `role="status"`, not the geometry of six grey boxes. If you render
|
|
12
12
|
* these, render a status line with them.
|
|
13
|
-
*/
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
"aria-hidden": true,
|
|
17
|
-
className: cn("animate-pulse rounded-md bg-muted", className),
|
|
18
|
-
...props
|
|
19
|
-
});
|
|
13
|
+
*/
|
|
14
|
+
export function Skeleton({ className, ...props }) {
|
|
15
|
+
return (_jsx("div", { "data-slot": "skeleton", "aria-hidden": true, className: cn("animate-pulse rounded-md bg-muted", className), ...props }));
|
|
20
16
|
}
|
|
@@ -1,9 +1,10 @@
|
|
|
1
|
-
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
3
|
import { ChevronDown, ChevronUp, ChevronsUpDown } from "lucide-react";
|
|
3
4
|
import { useMemo, useState } from "react";
|
|
4
5
|
import { cn } from "../lib/utils.js";
|
|
5
6
|
import { EmptyState } from "./empty-state.js";
|
|
6
|
-
import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "./table.js";
|
|
7
|
+
import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow, } from "./table.js";
|
|
7
8
|
/**
|
|
8
9
|
* A table you can sort by clicking a header.
|
|
9
10
|
*
|
|
@@ -18,86 +19,42 @@ import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from ".
|
|
|
18
19
|
* invisible to a screen reader, and sort order is exactly the sort of state
|
|
19
20
|
* that goes unnoticed without it. Inactive sortable headers show a neutral
|
|
20
21
|
* affordance so it is discoverable which columns can be sorted at all.
|
|
21
|
-
*/
|
|
22
|
+
*/
|
|
23
|
+
export function SortableTable({ caption, rows, columns, rowKey, initialSort, empty, className, }) {
|
|
22
24
|
const [sort, setSort] = useState(initialSort ?? null);
|
|
23
|
-
const sorted = useMemo(()=>{
|
|
24
|
-
if (sort === null)
|
|
25
|
-
|
|
26
|
-
|
|
25
|
+
const sorted = useMemo(() => {
|
|
26
|
+
if (sort === null)
|
|
27
|
+
return rows;
|
|
28
|
+
const column = columns.find((candidate) => candidate.key === sort.key);
|
|
29
|
+
if (column?.sortValue === undefined)
|
|
30
|
+
return rows;
|
|
27
31
|
const { sortValue } = column;
|
|
28
32
|
// Sorts a copy: `rows` belongs to the caller and may be frozen.
|
|
29
|
-
return [
|
|
30
|
-
...rows
|
|
31
|
-
].sort((a, b)=>{
|
|
33
|
+
return [...rows].sort((a, b) => {
|
|
32
34
|
const left = sortValue(a);
|
|
33
35
|
const right = sortValue(b);
|
|
34
|
-
const comparison = typeof left === "number" && typeof right === "number"
|
|
36
|
+
const comparison = typeof left === "number" && typeof right === "number"
|
|
37
|
+
? left - right
|
|
38
|
+
: // localeCompare so "Ä" sorts next to "A" rather than after "Z".
|
|
39
|
+
String(left).localeCompare(String(right));
|
|
35
40
|
return sort.direction === "asc" ? comparison : -comparison;
|
|
36
41
|
});
|
|
37
|
-
}, [
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
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
|
-
});
|
|
42
|
+
}, [rows, columns, sort]);
|
|
43
|
+
const toggle = (key) => {
|
|
44
|
+
setSort((current) => current?.key === key
|
|
45
|
+
? { key, direction: current.direction === "asc" ? "desc" : "asc" }
|
|
46
|
+
: { key, direction: "asc" });
|
|
50
47
|
};
|
|
51
48
|
if (rows.length === 0) {
|
|
52
|
-
return
|
|
53
|
-
children: empty ?? /*#__PURE__*/ _jsx(EmptyState, {
|
|
54
|
-
title: "Nothing to show"
|
|
55
|
-
})
|
|
56
|
-
});
|
|
49
|
+
return _jsx(_Fragment, { children: empty ?? _jsx(EmptyState, { title: "Nothing to show" }) });
|
|
57
50
|
}
|
|
58
|
-
return
|
|
59
|
-
"aria-label": caption,
|
|
60
|
-
className: className,
|
|
61
|
-
children: [
|
|
62
|
-
/*#__PURE__*/ _jsx(TableHeader, {
|
|
63
|
-
children: /*#__PURE__*/ _jsx(TableRow, {
|
|
64
|
-
children: columns.map((column)=>{
|
|
51
|
+
return (_jsxs(Table, { "aria-label": caption, className: className, children: [_jsx(TableHeader, { children: _jsx(TableRow, { children: columns.map((column) => {
|
|
65
52
|
const active = sort?.key === column.key;
|
|
66
53
|
const sortable = column.sortValue !== undefined;
|
|
67
|
-
return
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
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
|
-
});
|
|
54
|
+
return (_jsx(TableHead, { scope: "col", "aria-sort": active
|
|
55
|
+
? sort.direction === "asc"
|
|
56
|
+
? "ascending"
|
|
57
|
+
: "descending"
|
|
58
|
+
: undefined, className: cn(column.align === "right" && "text-right", column.className), children: sortable ? (_jsxs("button", { type: "button", onClick: () => toggle(column.key), className: cn("inline-flex items-center gap-1 rounded-sm transition-colors hover:text-foreground", !active && "text-muted-foreground"), children: [column.header, active ? (sort.direction === "asc" ? (_jsx(ChevronUp, { className: "size-3.5", "aria-hidden": true })) : (_jsx(ChevronDown, { className: "size-3.5", "aria-hidden": true }))) : (_jsx(ChevronsUpDown, { className: "size-3.5 opacity-50", "aria-hidden": true }))] })) : (column.header) }, column.key));
|
|
59
|
+
}) }) }), _jsx(TableBody, { children: sorted.map((row) => (_jsx(TableRow, { children: columns.map((column) => (_jsx(TableCell, { className: cn(column.align === "right" && "text-right", column.className), children: column.cell(row) }, column.key))) }, rowKey(row)))) })] }));
|
|
103
60
|
}
|
package/dist/ui/sparkline.js
CHANGED
|
@@ -19,50 +19,26 @@ const HEIGHT = 24;
|
|
|
19
19
|
* `role="img"` with the caller's summary as its name. The summary is required
|
|
20
20
|
* for the same reason `alt` is: a picture with no text alternative is simply
|
|
21
21
|
* missing for some readers, and this one has no fallback content to fall back to.
|
|
22
|
-
*/
|
|
22
|
+
*/
|
|
23
|
+
export function Sparkline({ values, summary, className }) {
|
|
23
24
|
if (values.length < 2) {
|
|
24
|
-
return
|
|
25
|
-
className: cn("inline-block", className),
|
|
26
|
-
role: "img",
|
|
27
|
-
"aria-label": summary
|
|
28
|
-
});
|
|
25
|
+
return (_jsx("span", { className: cn("inline-block", className), role: "img", "aria-label": summary }));
|
|
29
26
|
}
|
|
30
27
|
const min = Math.min(...values);
|
|
31
28
|
const max = Math.max(...values);
|
|
32
29
|
const span = max - min;
|
|
33
30
|
const stepX = WIDTH / (values.length - 1);
|
|
34
|
-
const points = values.map((value, index)=>({
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
31
|
+
const points = values.map((value, index) => ({
|
|
32
|
+
x: index * stepX,
|
|
33
|
+
// A flat series has no span to scale against; centre it rather than
|
|
34
|
+
// dividing by zero.
|
|
35
|
+
y: span === 0
|
|
36
|
+
? HEIGHT / 2
|
|
37
|
+
: HEIGHT - scaleLinear(value - min, span, HEIGHT - 4) - 2,
|
|
38
|
+
}));
|
|
40
39
|
const last = points[points.length - 1];
|
|
41
|
-
return
|
|
42
|
-
|
|
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
|
|
40
|
+
return (_jsxs("svg", { viewBox: `0 0 ${WIDTH} ${HEIGHT}`, className: cn("h-6 w-24", className), role: "img", "aria-label": summary, focusable: "false", children: [_jsx("path", { d: linePath(points), fill: "none", stroke: seriesColor(0), strokeWidth: 2, strokeLinecap: "round", strokeLinejoin: "round" }), last === undefined ? null : (
|
|
41
|
+
// The end dot marks "now" — which end is the current period is
|
|
57
42
|
// otherwise ambiguous on a shape with no axis.
|
|
58
|
-
|
|
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
|
-
});
|
|
43
|
+
_jsx("circle", { cx: last.x, cy: last.y, r: 2.5, fill: seriesColor(0), stroke: "var(--card)", strokeWidth: 2 }))] }));
|
|
68
44
|
}
|
package/dist/ui/stat-grid.js
CHANGED
|
@@ -7,7 +7,7 @@ const COLUMN_CLASS = {
|
|
|
7
7
|
2: "grid-cols-2",
|
|
8
8
|
3: "grid-cols-2 sm:grid-cols-3",
|
|
9
9
|
4: "grid-cols-2 sm:grid-cols-4",
|
|
10
|
-
5: "grid-cols-2 sm:grid-cols-5"
|
|
10
|
+
5: "grid-cols-2 sm:grid-cols-5",
|
|
11
11
|
};
|
|
12
12
|
/**
|
|
13
13
|
* The KPI band: a fixed responsive grid of `StatGridItem`s.
|
|
@@ -15,15 +15,15 @@ const COLUMN_CLASS = {
|
|
|
15
15
|
* Fixed columns rather than auto-fit, because a KPI row is designed as a set —
|
|
16
16
|
* four headline numbers are four columns, and a row that reflows to five-up on
|
|
17
17
|
* a wider screen silently reorders what the reader compares side by side.
|
|
18
|
-
*/
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
children: children
|
|
22
|
-
});
|
|
18
|
+
*/
|
|
19
|
+
export function StatGrid({ children, columns = 4, className }) {
|
|
20
|
+
return (_jsx("div", { className: cn("grid gap-3", COLUMN_CLASS[columns], className), children: children }));
|
|
23
21
|
}
|
|
24
22
|
function statValueClass(accent, danger) {
|
|
25
|
-
if (danger === true)
|
|
26
|
-
|
|
23
|
+
if (danger === true)
|
|
24
|
+
return "text-destructive";
|
|
25
|
+
if (accent === true)
|
|
26
|
+
return "text-primary-emphasis";
|
|
27
27
|
return "text-foreground";
|
|
28
28
|
}
|
|
29
29
|
/**
|
|
@@ -36,52 +36,17 @@ function statValueClass(accent, danger) {
|
|
|
36
36
|
* wearing `role="button"`) so keyboard activation is native. Shared layout
|
|
37
37
|
* classes stay identical; only the interactive shell adds hover/press
|
|
38
38
|
* affordance and the `text-left`/`w-full` button reset.
|
|
39
|
-
*/
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
summary: sparklineLabel ?? `${label} trend`
|
|
43
|
-
}) : null);
|
|
39
|
+
*/
|
|
40
|
+
export function StatGridItem({ label, value, sub, accent, danger, emphasis, delta, sparkline, sparklineValues, sparklineLabel, onClick, className, }) {
|
|
41
|
+
const sparklineNode = sparkline ??
|
|
42
|
+
(sparklineValues !== undefined && sparklineValues.length > 0 ? (_jsx(Sparkline, { values: sparklineValues, summary: sparklineLabel ?? `${label} trend` })) : null);
|
|
44
43
|
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 =
|
|
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
|
-
});
|
|
44
|
+
const body = (_jsxs(_Fragment, { children: [_jsx("span", { className: "text-[10px] font-semibold tracking-[0.12em] uppercase text-muted-foreground", children: label }), _jsxs("div", { className: "flex items-baseline gap-2", children: [_jsx("span", { className: cn("font-black leading-none tabular-nums", emphasis === true ? "text-[34px]" : "text-[26px]", statValueClass(accent, danger)), children: value }), delta] }), sparklineNode === null ? null : (_jsx("div", { className: "mt-0.5", children: sparklineNode })), sub === undefined ? null : (_jsx("span", { className: "text-[10px] tracking-[0.08em] uppercase text-muted-foreground", children: sub }))] }));
|
|
71
45
|
if (onClick === undefined) {
|
|
72
|
-
return
|
|
73
|
-
"data-slot": "stat-grid-item",
|
|
74
|
-
className: shell,
|
|
75
|
-
children: body
|
|
76
|
-
});
|
|
46
|
+
return (_jsx("div", { "data-slot": "stat-grid-item", className: shell, children: body }));
|
|
77
47
|
}
|
|
78
|
-
return
|
|
79
|
-
|
|
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.
|
|
48
|
+
return (_jsx("button", { type: "button", "data-slot": "stat-grid-item", onClick: onClick, className: cn(shell,
|
|
49
|
+
// text-left/w-full: button UA styles centre content and shrink-wrap.
|
|
83
50
|
// 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
|
-
});
|
|
51
|
+
"w-full cursor-pointer text-left transition-colors hover:border-primary-emphasis active:brightness-95"), children: body }));
|
|
87
52
|
}
|
package/dist/ui/status-dot.d.ts
CHANGED
|
@@ -10,4 +10,4 @@ export type StatusDotProps = {
|
|
|
10
10
|
readonly className?: string;
|
|
11
11
|
};
|
|
12
12
|
export type StatusDotSize = "xs" | "sm";
|
|
13
|
-
export declare function StatusDot({ label, live, tone, size, className }: StatusDotProps): import("react").JSX.Element;
|
|
13
|
+
export declare function StatusDot({ label, live, tone, size, className, }: StatusDotProps): import("react").JSX.Element;
|
package/dist/ui/status-dot.js
CHANGED
|
@@ -11,14 +11,15 @@ import { cn } from "../lib/utils.js";
|
|
|
11
11
|
*
|
|
12
12
|
* Classes are spelled out rather than composed at runtime — Tailwind's scanner
|
|
13
13
|
* only emits utilities it can see literally in the source.
|
|
14
|
-
*/
|
|
14
|
+
*/
|
|
15
|
+
const TONE_CLASS = {
|
|
15
16
|
neutral: "bg-muted-foreground",
|
|
16
17
|
emphasis: "bg-primary-emphasis",
|
|
17
18
|
// success/warning use emphasis orange until dedicated high-contrast
|
|
18
19
|
// fills clear 3:1 at 8px; Badge remains the full-status carrier.
|
|
19
20
|
success: "bg-primary-emphasis",
|
|
20
21
|
warning: "bg-primary-emphasis",
|
|
21
|
-
danger: "bg-destructive"
|
|
22
|
+
danger: "bg-destructive",
|
|
22
23
|
};
|
|
23
24
|
/**
|
|
24
25
|
* A state marker carrying its own accessible name — a coloured dot with no
|
|
@@ -28,24 +29,11 @@ import { cn } from "../lib/utils.js";
|
|
|
28
29
|
* The `live` ring is a separate `aria-hidden` element: motion says "still
|
|
29
30
|
* changing" to people who can see it, and the label already says so to those
|
|
30
31
|
* who cannot. It stills under the theme's reduced-motion rule.
|
|
31
|
-
*/
|
|
32
|
+
*/
|
|
33
|
+
const SIZE_CLASS = {
|
|
32
34
|
xs: "size-1.5",
|
|
33
|
-
sm: "size-2"
|
|
35
|
+
sm: "size-2",
|
|
34
36
|
};
|
|
35
|
-
export function StatusDot({ label, live = false, tone = "neutral", size = "sm", className }) {
|
|
36
|
-
return
|
|
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
|
-
});
|
|
37
|
+
export function StatusDot({ label, live = false, tone = "neutral", size = "sm", className, }) {
|
|
38
|
+
return (_jsxs("span", { role: "img", "aria-label": label, className: cn("relative inline-flex shrink-0", SIZE_CLASS[size], className), children: [live ? (_jsx("span", { "aria-hidden": true, className: cn("absolute inset-0 rounded-full [animation:corbits-status-pulse_1.8s_ease-out_infinite]", TONE_CLASS[tone]) })) : null, _jsx("span", { "aria-hidden": true, className: cn("relative size-full rounded-full", TONE_CLASS[tone]) })] }));
|
|
51
39
|
}
|
package/dist/ui/step-list.d.ts
CHANGED