@ceebee/ui 0.4.0 → 0.5.2
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/dist/client.d.ts +128 -18
- package/dist/client.js +452 -160
- package/dist/index.d.ts +58 -10
- package/dist/index.js +78 -18
- package/dist/styles.css +609 -250
- package/package.json +6 -6
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as react from 'react';
|
|
2
|
-
import { ReactNode } from 'react';
|
|
2
|
+
import { ReactNode, AnchorHTMLAttributes, ReactElement } from 'react';
|
|
3
3
|
|
|
4
4
|
/** Joins class names, dropping falsy values. No merge logic: the library never emits
|
|
5
5
|
* conflicting utility classes, so the "last wins" problem tailwind-merge solves does not exist. */
|
|
@@ -45,7 +45,7 @@ interface StackProps {
|
|
|
45
45
|
children?: ReactNode;
|
|
46
46
|
}
|
|
47
47
|
/** Flex layout whose gap can only be a spacing token — the reason the library has no raw padding. */
|
|
48
|
-
declare function
|
|
48
|
+
declare function Flex({ direction, gap, align, justify, wrap, className, children, }: StackProps): react.JSX.Element;
|
|
49
49
|
interface GridProps {
|
|
50
50
|
/** Column count at the widest breakpoint; the grid collapses on its own below it. */
|
|
51
51
|
columns?: 1 | 2 | 3 | 4 | 6 | 12;
|
|
@@ -81,6 +81,54 @@ interface HeadingProps {
|
|
|
81
81
|
/** Level and size are separate on purpose: document structure is not a font size. */
|
|
82
82
|
declare function Heading({ level, size, className, children }: HeadingProps): react.JSX.Element;
|
|
83
83
|
|
|
84
|
+
interface LinkButtonProps extends Omit<AnchorHTMLAttributes<HTMLAnchorElement>, 'color'> {
|
|
85
|
+
variant?: 'solid' | 'soft' | 'outline' | 'ghost';
|
|
86
|
+
tone?: Tone;
|
|
87
|
+
size?: Size;
|
|
88
|
+
iconStart?: ReactNode;
|
|
89
|
+
iconEnd?: ReactNode;
|
|
90
|
+
children?: ReactNode;
|
|
91
|
+
/**
|
|
92
|
+
* Render something else in the anchor's place — a router's own Link, which has
|
|
93
|
+
* to stay itself or client-side navigation is lost. It receives the classes
|
|
94
|
+
* and the tone; everything else it keeps. The same `render` seam Base UI uses
|
|
95
|
+
* elsewhere in this library.
|
|
96
|
+
*/
|
|
97
|
+
render?: ReactElement;
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* A link wearing a button's clothes.
|
|
101
|
+
*
|
|
102
|
+
* Not a `Button` with an `href`. A link navigates and a button acts, and the
|
|
103
|
+
* difference is not decoration: a link can be opened in a new tab, copied,
|
|
104
|
+
* dragged to a bookmark bar and reached by a screen reader's list of links,
|
|
105
|
+
* while a button can be disabled and submit a form. Those are different
|
|
106
|
+
* contracts, so they are different components (ADR 0014).
|
|
107
|
+
*
|
|
108
|
+
* What they share is the look, and that is shared literally — the same
|
|
109
|
+
* `cb-button` classes rather than a second set that would agree today and drift
|
|
110
|
+
* apart later. It is server-safe: an anchor needs no hook, no handler and no
|
|
111
|
+
* motion, so it stays a Server Component (ADR 0004). The press animation is
|
|
112
|
+
* Button's alone, which is honest: a link does not depress, it goes somewhere.
|
|
113
|
+
*/
|
|
114
|
+
declare function LinkButton({ variant, tone, size, iconStart, iconEnd, className, children, render, ...rest }: LinkButtonProps): react.JSX.Element;
|
|
115
|
+
|
|
116
|
+
interface DividerProps {
|
|
117
|
+
/** A word or two sitting in the rule, for a section break that names itself. */
|
|
118
|
+
children?: ReactNode;
|
|
119
|
+
orientation?: 'horizontal' | 'vertical';
|
|
120
|
+
className?: string;
|
|
121
|
+
}
|
|
122
|
+
/**
|
|
123
|
+
* A rule between things.
|
|
124
|
+
*
|
|
125
|
+
* `<hr>` when it separates content, because that is what the element means and
|
|
126
|
+
* a screen reader announces it. With a label it becomes a `<div>` carrying the
|
|
127
|
+
* rule in its borders instead — an `<hr>` may not contain anything, and a
|
|
128
|
+
* separator that says which section is starting is worth more than the element.
|
|
129
|
+
*/
|
|
130
|
+
declare function Divider({ children, orientation, className }: DividerProps): react.JSX.Element;
|
|
131
|
+
|
|
84
132
|
interface BadgeProps {
|
|
85
133
|
children: ReactNode;
|
|
86
134
|
tone?: Tone;
|
|
@@ -102,7 +150,7 @@ interface EmptyStateProps {
|
|
|
102
150
|
variant?: 'first-run' | 'search' | 'error';
|
|
103
151
|
className?: string;
|
|
104
152
|
}
|
|
105
|
-
declare function
|
|
153
|
+
declare function Empty({ title, description, icon, actions, variant, className }: EmptyStateProps): react.JSX.Element;
|
|
106
154
|
|
|
107
155
|
interface SpinnerProps {
|
|
108
156
|
size?: 'sm' | 'md' | 'lg';
|
|
@@ -112,7 +160,7 @@ interface SpinnerProps {
|
|
|
112
160
|
className?: string;
|
|
113
161
|
}
|
|
114
162
|
/** Server-safe: a CSS animation, no state. It stops turning under reduced motion. */
|
|
115
|
-
declare function
|
|
163
|
+
declare function Spin({ size, tone, label, className }: SpinnerProps): react.JSX.Element;
|
|
116
164
|
interface ProgressBarProps {
|
|
117
165
|
/** Omit for an indeterminate bar — "something is happening, duration unknown". */
|
|
118
166
|
value?: number;
|
|
@@ -371,7 +419,7 @@ interface BreadcrumbsProps {
|
|
|
371
419
|
* Server-safe. The last crumb is the current page: it is text with `aria-current`, not a link,
|
|
372
420
|
* because a link to where you already are is a dead end for keyboard and screen reader users.
|
|
373
421
|
*/
|
|
374
|
-
declare function
|
|
422
|
+
declare function Breadcrumb({ items, maxItems, className }: BreadcrumbsProps): react.JSX.Element;
|
|
375
423
|
|
|
376
424
|
interface Step {
|
|
377
425
|
label: ReactNode;
|
|
@@ -388,7 +436,7 @@ interface StepperProps {
|
|
|
388
436
|
* Progress through an ordered sequence — the thing Tabs must not be used for. Server-safe:
|
|
389
437
|
* it displays position, it does not navigate.
|
|
390
438
|
*/
|
|
391
|
-
declare function
|
|
439
|
+
declare function Steps({ steps, current, orientation, className }: StepperProps): react.JSX.Element;
|
|
392
440
|
|
|
393
441
|
interface StatCardProps {
|
|
394
442
|
label: string;
|
|
@@ -406,15 +454,15 @@ interface StatCardProps {
|
|
|
406
454
|
className?: string;
|
|
407
455
|
}
|
|
408
456
|
/** The tinted metric tile the reference board repeats on every dashboard. */
|
|
409
|
-
declare function
|
|
410
|
-
declare namespace
|
|
457
|
+
declare function Statistic({ label, value, delta, caption, hue, icon, visual, className }: StatCardProps): react.JSX.Element;
|
|
458
|
+
declare namespace Statistic {
|
|
411
459
|
var Skeleton: typeof StatCardSkeleton;
|
|
412
460
|
}
|
|
413
461
|
interface StatCardSkeletonProps {
|
|
414
462
|
withVisual?: boolean;
|
|
415
463
|
className?: string;
|
|
416
464
|
}
|
|
417
|
-
/** Built from
|
|
465
|
+
/** Built from Statistic's own spacing, so the tile does not resize when data arrives (ADR 0009). */
|
|
418
466
|
declare function StatCardSkeleton({ withVisual, className }: StatCardSkeletonProps): react.JSX.Element;
|
|
419
467
|
|
|
420
|
-
export { Avatar, AvatarGroup, type AvatarGroupProps, type AvatarProps, Badge, type BadgeProps, BarMini, type BarMiniProps,
|
|
468
|
+
export { Avatar, AvatarGroup, type AvatarGroupProps, type AvatarProps, Badge, type BadgeProps, BarMini, type BarMiniProps, Breadcrumb, type BreadcrumbsProps, Container, type ContainerProps, type Crumb, type DecorHue, Divider, type DividerProps, Donut, type DonutArc, type DonutProps, type DonutSlice, Empty, type EmptyStateProps, Flex, type GlassStyle, Grid, type GridProps, Heading, type HeadingProps, Leaderboard, type LeaderboardEntry, type LeaderboardProps, type LeaderboardSkeletonProps, LinkButton, type LinkButtonProps, ProgressBar, type ProgressBarProps, ProgressRing, type ProgressRingProps, type RingGeometry, type Size, Skeleton, type SkeletonProps, type SkeletonTextProps, Sparkline, type SparklineGeometry, type SparklineProps, Spin, type SpinnerProps, type StackProps, type StatCardProps, type StatCardSkeletonProps, Statistic, type Step, type StepperProps, Steps, Surface, type SurfaceProps, type SurfaceVariant, Text, type TextProps, Timeline, type TimelineEntry, type TimelineProps, type TimelineSkeletonProps, type Tone, cn, donutArcs, hueForName, initialsOf, ringGeometry, sparklineGeometry };
|
package/dist/index.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import { jsx, jsxs } from 'react/jsx-runtime';
|
|
1
|
+
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
2
|
+
import { isValidElement, cloneElement } from 'react';
|
|
2
3
|
import { ChevronRight, Check } from 'lucide-react';
|
|
3
4
|
|
|
4
5
|
// src/lib/cn.ts
|
|
@@ -38,7 +39,7 @@ function Surface({
|
|
|
38
39
|
}
|
|
39
40
|
);
|
|
40
41
|
}
|
|
41
|
-
function
|
|
42
|
+
function Flex({
|
|
42
43
|
direction = "column",
|
|
43
44
|
gap = 4,
|
|
44
45
|
align = "stretch",
|
|
@@ -47,11 +48,11 @@ function Stack({
|
|
|
47
48
|
className,
|
|
48
49
|
children
|
|
49
50
|
}) {
|
|
50
|
-
const style = { "--cb-
|
|
51
|
+
const style = { "--cb-flex-gap": `var(--cb-space-${gap})` };
|
|
51
52
|
return /* @__PURE__ */ jsx(
|
|
52
53
|
"div",
|
|
53
54
|
{
|
|
54
|
-
className: cn("cb-
|
|
55
|
+
className: cn("cb-flex", `cb-flex--${direction}`, wrap && "cb-flex--wrap", className),
|
|
55
56
|
style,
|
|
56
57
|
"data-align": align,
|
|
57
58
|
"data-justify": justify,
|
|
@@ -93,13 +94,72 @@ function Heading({ level = 2, size, className, children }) {
|
|
|
93
94
|
const resolved = size ?? ["3xl", "2xl", "xl", "lg"][level - 1] ?? "lg";
|
|
94
95
|
return /* @__PURE__ */ jsx(Tag, { className: cn("cb-heading", `cb-text--${resolved}`, className), children });
|
|
95
96
|
}
|
|
97
|
+
function LinkButton({
|
|
98
|
+
variant = "solid",
|
|
99
|
+
tone = "brand",
|
|
100
|
+
size = "md",
|
|
101
|
+
iconStart,
|
|
102
|
+
iconEnd,
|
|
103
|
+
className,
|
|
104
|
+
children,
|
|
105
|
+
render,
|
|
106
|
+
...rest
|
|
107
|
+
}) {
|
|
108
|
+
const iconOnly = children === void 0 || children === null || children === false || children === "";
|
|
109
|
+
const classes = cn(
|
|
110
|
+
"cb-button",
|
|
111
|
+
"cb-link-button",
|
|
112
|
+
`cb-button--${variant}`,
|
|
113
|
+
`cb-button--${size}`,
|
|
114
|
+
iconOnly && "cb-button--icon",
|
|
115
|
+
className
|
|
116
|
+
);
|
|
117
|
+
const body = /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
118
|
+
iconStart,
|
|
119
|
+
iconOnly ? null : /* @__PURE__ */ jsx("span", { className: "cb-button__label", children }),
|
|
120
|
+
iconOnly ? null : iconEnd
|
|
121
|
+
] });
|
|
122
|
+
if (render && isValidElement(render)) {
|
|
123
|
+
return cloneElement(render, {
|
|
124
|
+
className: cn(classes, render.props.className),
|
|
125
|
+
"data-tone": tone,
|
|
126
|
+
...rest,
|
|
127
|
+
children: body
|
|
128
|
+
});
|
|
129
|
+
}
|
|
130
|
+
return /* @__PURE__ */ jsx(
|
|
131
|
+
"a",
|
|
132
|
+
{
|
|
133
|
+
className: cn(
|
|
134
|
+
"cb-button",
|
|
135
|
+
"cb-link-button",
|
|
136
|
+
`cb-button--${variant}`,
|
|
137
|
+
`cb-button--${size}`,
|
|
138
|
+
iconOnly && "cb-button--icon",
|
|
139
|
+
className
|
|
140
|
+
),
|
|
141
|
+
"data-tone": tone,
|
|
142
|
+
...rest,
|
|
143
|
+
children: body
|
|
144
|
+
}
|
|
145
|
+
);
|
|
146
|
+
}
|
|
147
|
+
function Divider({ children, orientation = "horizontal", className }) {
|
|
148
|
+
if (orientation === "vertical") {
|
|
149
|
+
return /* @__PURE__ */ jsx("span", { className: cn("cb-divider", "cb-divider--vertical", className), role: "separator", "aria-orientation": "vertical" });
|
|
150
|
+
}
|
|
151
|
+
if (children) {
|
|
152
|
+
return /* @__PURE__ */ jsx("div", { className: cn("cb-divider", "cb-divider--labelled", className), role: "separator", children: /* @__PURE__ */ jsx("span", { className: "cb-divider__label", children }) });
|
|
153
|
+
}
|
|
154
|
+
return /* @__PURE__ */ jsx("hr", { className: cn("cb-divider", className) });
|
|
155
|
+
}
|
|
96
156
|
function Badge({ children, tone = "neutral", variant = "soft", size = "md", dot, className }) {
|
|
97
157
|
return /* @__PURE__ */ jsxs("span", { className: cn("cb-badge", `cb-badge--${variant}`, `cb-badge--${size}`, className), "data-tone": tone, children: [
|
|
98
158
|
dot ? /* @__PURE__ */ jsx("span", { className: "cb-badge__dot", "aria-hidden": "true" }) : null,
|
|
99
159
|
children
|
|
100
160
|
] });
|
|
101
161
|
}
|
|
102
|
-
function
|
|
162
|
+
function Empty({ title, description, icon, actions, variant = "first-run", className }) {
|
|
103
163
|
return /* @__PURE__ */ jsxs("div", { className: cn("cb-empty", className), "data-variant": variant, children: [
|
|
104
164
|
icon ? /* @__PURE__ */ jsx("span", { className: "cb-empty__icon", children: icon }) : null,
|
|
105
165
|
/* @__PURE__ */ jsx("p", { className: "cb-empty__title", children: title }),
|
|
@@ -107,11 +167,11 @@ function EmptyState({ title, description, icon, actions, variant = "first-run",
|
|
|
107
167
|
actions ? /* @__PURE__ */ jsx("div", { className: "cb-empty__actions", children: actions }) : null
|
|
108
168
|
] });
|
|
109
169
|
}
|
|
110
|
-
function
|
|
170
|
+
function Spin({ size = "md", tone = "brand", label, className }) {
|
|
111
171
|
return /* @__PURE__ */ jsx(
|
|
112
172
|
"span",
|
|
113
173
|
{
|
|
114
|
-
className: cn("cb-
|
|
174
|
+
className: cn("cb-spin", `cb-spin--${size}`, className),
|
|
115
175
|
"data-tone": tone,
|
|
116
176
|
role: label ? "status" : void 0,
|
|
117
177
|
"aria-label": label,
|
|
@@ -430,7 +490,7 @@ function LeaderboardSkeleton({ rows = 5, className }) {
|
|
|
430
490
|
] }, index)) });
|
|
431
491
|
}
|
|
432
492
|
var Leaderboard = Object.assign(LeaderboardRoot, { Skeleton: LeaderboardSkeleton });
|
|
433
|
-
function
|
|
493
|
+
function Breadcrumb({ items, maxItems = 4, className }) {
|
|
434
494
|
const collapsed = items.length > maxItems ? [items[0], { label: "\u2026" }, ...items.slice(items.length - (maxItems - 2))] : items;
|
|
435
495
|
return /* @__PURE__ */ jsx("nav", { className: cn("cb-crumbs", className), "aria-label": "Breadcrumb", children: /* @__PURE__ */ jsx("ol", { className: "cb-crumbs__list", children: collapsed.map((crumb, index) => {
|
|
436
496
|
const isLast = index === collapsed.length - 1;
|
|
@@ -440,22 +500,22 @@ function Breadcrumbs({ items, maxItems = 4, className }) {
|
|
|
440
500
|
] }, `${String(crumb.label)}-${index}`);
|
|
441
501
|
}) }) });
|
|
442
502
|
}
|
|
443
|
-
function
|
|
444
|
-
return /* @__PURE__ */ jsx("ol", { className: cn("cb-
|
|
503
|
+
function Steps({ steps, current, orientation = "horizontal", className }) {
|
|
504
|
+
return /* @__PURE__ */ jsx("ol", { className: cn("cb-steps", `cb-steps--${orientation}`, className), children: steps.map((step, index) => {
|
|
445
505
|
const state = index < current ? "done" : index === current ? "current" : "todo";
|
|
446
|
-
return /* @__PURE__ */ jsxs("li", { className: "cb-
|
|
447
|
-
/* @__PURE__ */ jsx("span", { className: "cb-
|
|
448
|
-
/* @__PURE__ */ jsxs("span", { className: "cb-
|
|
449
|
-
/* @__PURE__ */ jsxs("span", { className: "cb-
|
|
506
|
+
return /* @__PURE__ */ jsxs("li", { className: "cb-steps__step", "data-state": state, children: [
|
|
507
|
+
/* @__PURE__ */ jsx("span", { className: "cb-steps__marker", "aria-hidden": "true", children: state === "done" ? /* @__PURE__ */ jsx(Check, { size: 13, strokeWidth: 3 }) : index + 1 }),
|
|
508
|
+
/* @__PURE__ */ jsxs("span", { className: "cb-steps__text", children: [
|
|
509
|
+
/* @__PURE__ */ jsxs("span", { className: "cb-steps__label", children: [
|
|
450
510
|
step.label,
|
|
451
511
|
/* @__PURE__ */ jsx("span", { className: "cb-visually-hidden", children: state === "done" ? " (completed)" : state === "current" ? " (current step)" : "" })
|
|
452
512
|
] }),
|
|
453
|
-
step.description ? /* @__PURE__ */ jsx("span", { className: "cb-
|
|
513
|
+
step.description ? /* @__PURE__ */ jsx("span", { className: "cb-steps__description", children: step.description }) : null
|
|
454
514
|
] })
|
|
455
515
|
] }, index);
|
|
456
516
|
}) });
|
|
457
517
|
}
|
|
458
|
-
function
|
|
518
|
+
function Statistic({ label, value, delta, caption, hue, icon, visual, className }) {
|
|
459
519
|
return /* @__PURE__ */ jsxs(Surface, { variant: "tinted", hue, radius: "lg", padding: "md", className: cn("cb-stat", className), children: [
|
|
460
520
|
/* @__PURE__ */ jsxs("div", { className: "cb-stat__head", children: [
|
|
461
521
|
/* @__PURE__ */ jsx(Text, { size: "sm", tone: "muted", weight: "medium", children: label }),
|
|
@@ -483,6 +543,6 @@ function StatCardSkeleton({ withVisual = false, className }) {
|
|
|
483
543
|
] })
|
|
484
544
|
] });
|
|
485
545
|
}
|
|
486
|
-
|
|
546
|
+
Statistic.Skeleton = StatCardSkeleton;
|
|
487
547
|
|
|
488
|
-
export { Avatar, AvatarGroup, Badge, BarMini,
|
|
548
|
+
export { Avatar, AvatarGroup, Badge, BarMini, Breadcrumb, Container, Divider, Donut, Empty, Flex, Grid, Heading, Leaderboard, LinkButton, ProgressBar, ProgressRing, Skeleton, Sparkline, Spin, Statistic, Steps, Surface, Text, Timeline, cn, donutArcs, hueForName, initialsOf, ringGeometry, sparklineGeometry };
|