@usetheo/ui 0.35.1 → 0.35.3
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/README.md
CHANGED
|
@@ -1,7 +1,62 @@
|
|
|
1
1
|
# @usetheo/ui
|
|
2
2
|
|
|
3
|
-
Violet Forge design system — the generic React components
|
|
3
|
+
Violet Forge design system — the generic React components and primitives that form the non-AI
|
|
4
|
+
foundation of the Theo UI stack. Apache-2.0, ESM-only.
|
|
4
5
|
|
|
5
|
-
|
|
6
|
+
This is the layer with **no agent in it**: the shell, the tables, the forms, the feedback states,
|
|
7
|
+
the dashboard pieces. [`@theokit/ui`](https://github.com/usetheokit/theokit-ui) builds on top of it
|
|
8
|
+
with the agent surfaces (chat threads, tool calls, approval cards) and shares the same tokens, so
|
|
9
|
+
the two compose without a visual seam.
|
|
10
|
+
|
|
11
|
+
**Rule of thumb:** if the component would exist in an app with no agent in it, it belongs here.
|
|
12
|
+
|
|
13
|
+
## Install
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
pnpm add @usetheo/ui
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
Or copy a single component, shadcn-style, from the published registry:
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
npx shadcn@latest add https://usetheodev.github.io/usetheo-ui/r/data-table.json
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
## Catalog
|
|
26
|
+
|
|
27
|
+
<!-- BEGIN:catalog -->
|
|
28
|
+
|
|
29
|
+
**87 components** — 45 primitives + 42 composites.
|
|
30
|
+
|
|
31
|
+
### Primitives (45)
|
|
32
|
+
|
|
33
|
+
`ActionBar` · `Alert` · `Avatar` · `Badge` · `Breadcrumb` · `Button` · `Card` · `Checkbox` · `Combobox` · `CopyButton` · `DangerZone` · `DescriptionList` · `Dialog` · `DropdownMenu` · `EmptyState` · `FileDropzone` · `FormField` · `Input` · `JsonViewer` · `Label` · `LoginSplit` · `MetricsPanel` · `Pagination` · `PinInput` · `PlanBadge` · `Progress` · `RadioGroup` · `ScrollArea` · `Select` · `Sheet` · `Sidebar` · `Skeleton` · `Slider` · `SocialAuthRow` · `StatTile` · `StatusDot` · `Switch` · `Table` · `Tabs` · `Textarea` · `Timestamp` · `Toast` · `Tooltip` · `Topnav` · `UpdateBanner`
|
|
34
|
+
|
|
35
|
+
### Composites (42)
|
|
36
|
+
|
|
37
|
+
`AccountMenu` · `AnnotationInput` · `AnnotationSummaryGroup` · `AttributesTable` · `ChatMessageCard` · `CodeBlock` · `CommandPalette` · `CommentThread` · `ConfirmDialog` · `DataTable` · `DatasetItemDiff` · `DeploymentRow` · `DiffView` · `DomainConfig` · `EnvVarEditor` · `EvaluatorForm` · `Histogram` · `IoCards` · `MessageBranchSelector` · `MetricCard` · `PageShell` · `PercentileChart` · `PreviewEnvCard` · `PriceBreakdown` · `ProjectCard` · `PromptTemplateEditor` · `PromptVersionDiff` · `RollbackUi` · `SessionSummary` · `SessionTimeline` · `SeverityBadge` · `SpanGraph` · `SpanTree` · `SpanWaterfall` · `StatusIndicator` · `Stepper` · `TagInput` · `TaskHeader` · `TokenCostBreakdown` · `TraceCompare` · `TraceTranscript` · `TrendChart`
|
|
38
|
+
|
|
39
|
+
<!-- END:catalog -->
|
|
40
|
+
|
|
41
|
+
Generated from `src/components/` by `pnpm sync:readme` — do not edit the block above by hand.
|
|
42
|
+
|
|
43
|
+
## Theming
|
|
44
|
+
|
|
45
|
+
The tokens come from the Violet Forge foundation shipped here (`tailwind-preset`, `themes`, `cn`).
|
|
46
|
+
Consumers that also install `@theokit/ui` get the same token names, so a theme defined once applies
|
|
47
|
+
to both packages.
|
|
48
|
+
|
|
49
|
+
## Development
|
|
50
|
+
|
|
51
|
+
```bash
|
|
52
|
+
pnpm install
|
|
53
|
+
pnpm dev # Ladle catalog
|
|
54
|
+
pnpm test
|
|
55
|
+
pnpm typecheck
|
|
56
|
+
pnpm lint
|
|
57
|
+
pnpm build
|
|
58
|
+
pnpm sync:readme # regenerate the catalog block above
|
|
59
|
+
pnpm registry:build # rebuild registry/r/*.json for the shadcn path
|
|
60
|
+
```
|
|
6
61
|
|
|
7
62
|
> Seeded from `theo-ui` @ `2b46eca` (2026-07-03, AI-exclusive pivot milestone M-B).
|
|
@@ -2,7 +2,7 @@ import { type HTMLAttributes, type ReactNode } from "react";
|
|
|
2
2
|
/**
|
|
3
3
|
* MetricCard — dashboard metric tile (composite).
|
|
4
4
|
*
|
|
5
|
-
*
|
|
5
|
+
* Recurring pattern "Card + CardHeader + value + delta + trend icon" promoted
|
|
6
6
|
* to a first-class composite per ADR-0007 community-best-practices plan.
|
|
7
7
|
*
|
|
8
8
|
* Trend → token mapping (default `invertTrend=false`):
|
|
@@ -51,37 +51,38 @@ export declare function niceMax(values: number[]): number;
|
|
|
51
51
|
*/
|
|
52
52
|
export declare function seriesPath(points: TrendPoint[], xScale: (x: number) => number, yScale: (y: number) => number): string;
|
|
53
53
|
/**
|
|
54
|
-
*
|
|
54
|
+
* Which axis positions receive a label.
|
|
55
55
|
*
|
|
56
|
-
*
|
|
57
|
-
*
|
|
58
|
-
*
|
|
59
|
-
*
|
|
56
|
+
* Labelling 31 points in ~450px is illegible; labelling only the edges does not answer "when was
|
|
57
|
+
* the spike". The density comes from the REAL width (`viewW`, which the ResizeObserver already
|
|
58
|
+
* tracks), with the first and the last ALWAYS present: they are the window's edges, and without
|
|
59
|
+
* them the reader does not know from when to when the chart speaks.
|
|
60
60
|
*
|
|
61
|
-
*
|
|
61
|
+
* Outside the JSX because it is arithmetic, and isolated arithmetic is arithmetic mutation reaches.
|
|
62
62
|
*/
|
|
63
63
|
export declare function xTicks(axisXs: number[], viewW: number): number[];
|
|
64
64
|
/**
|
|
65
|
-
*
|
|
65
|
+
* Which points receive a marker.
|
|
66
66
|
*
|
|
67
|
-
*
|
|
68
|
-
*
|
|
67
|
+
* Two distinct reasons to mark, and the second only appeared once series with gaps came to exist
|
|
68
|
+
* (M144):
|
|
69
69
|
*
|
|
70
|
-
* 1. **
|
|
71
|
-
*
|
|
72
|
-
*
|
|
73
|
-
* 2. **
|
|
74
|
-
* `path`,
|
|
75
|
-
*
|
|
70
|
+
* 1. **Sparse series** (< `SPARSE_MARKER_MAX` FINITE points) — 1-4 points read as a dramatic
|
|
71
|
+
* cliff; the marker anchors the reader on the real data. M76's rule — which now counts data,
|
|
72
|
+
* not slots, because M144's densification broke the equivalence between the two.
|
|
73
|
+
* 2. **Isolated point** — a finite point surrounded by gaps on both sides becomes a lone `M` in
|
|
74
|
+
* the `path`, and a lone `M` **draws nothing**: zero bounding box, invisible. The data exists,
|
|
75
|
+
* it is correct, and the operator does not see it. Measured in M144's e2e
|
|
76
|
+
* (`d="M419.86,92.00 M448.00,36.00"`).
|
|
76
77
|
*
|
|
77
|
-
*
|
|
78
|
-
*
|
|
79
|
-
* rendering as an invisible line"*.
|
|
80
|
-
*
|
|
81
|
-
*
|
|
78
|
+
* The old rule covered only (1), keying on the TOTAL number of points instead of asking whether
|
|
79
|
+
* the point is actually drawn — even though its own comment already stated the intent *"a dot
|
|
80
|
+
* keeps real data from rendering as an invisible line"*. After the densification, a 30-day series
|
|
81
|
+
* with two finite days separated by a gap falls outside (1) and disappears. Chart.js and Plotly
|
|
82
|
+
* mark the isolated point for exactly this reason.
|
|
82
83
|
*
|
|
83
|
-
*
|
|
84
|
-
*
|
|
84
|
+
* Outside the JSX on purpose: it is the decision's arithmetic, and isolated arithmetic is the kind
|
|
85
|
+
* a mutation reaches.
|
|
85
86
|
*/
|
|
86
87
|
export declare function markedPoints(points: TrendPoint[]): TrendPoint[];
|
|
87
88
|
export interface TrendChartProps extends HTMLAttributes<HTMLElement> {
|
|
@@ -98,18 +99,18 @@ export interface TrendChartProps extends HTMLAttributes<HTMLElement> {
|
|
|
98
99
|
*/
|
|
99
100
|
yMax?: number;
|
|
100
101
|
/**
|
|
101
|
-
*
|
|
102
|
+
* Formats the `x` for the axis and for the accessible table. **Optional on purpose.**
|
|
102
103
|
*
|
|
103
|
-
*
|
|
104
|
-
*
|
|
105
|
-
*
|
|
106
|
-
*
|
|
107
|
-
* M144
|
|
104
|
+
* The `x` contract is ambiguous — "bucket index or epoch-ms" — and in practice nearly unanimous:
|
|
105
|
+
* of the consumer's six series factories, five pass an INDEX and one passes epoch-ms. Inferring by
|
|
106
|
+
* magnitude would work, and would be the exact shape of the defect this component has already paid
|
|
107
|
+
* for (M76's marker rule keyed on `points.length` instead of asking what it wanted to know, and
|
|
108
|
+
* M144's densification switched it off silently). The one who knows what `x` means is the caller.
|
|
108
109
|
*
|
|
109
|
-
*
|
|
110
|
+
* Without this prop nothing changes: no X-axis label is drawn and the table keeps numbering.
|
|
110
111
|
*/
|
|
111
112
|
xFormatter?: (x: number) => string;
|
|
112
|
-
/**
|
|
113
|
+
/** Header of the accessible table's first column. "Point" over dates would be dishonest. */
|
|
113
114
|
xLabel?: string;
|
|
114
115
|
}
|
|
115
116
|
declare const TrendChart: import("react").ForwardRefExoticComponent<TrendChartProps & import("react").RefAttributes<HTMLElement>>;
|
package/dist/index.js
CHANGED
|
@@ -593,7 +593,7 @@ var buttonVariants = cva(
|
|
|
593
593
|
},
|
|
594
594
|
size: {
|
|
595
595
|
sm: "h-8 px-3 text-body-sm",
|
|
596
|
-
// md: tier
|
|
596
|
+
// md: tier adjustable via density (CSS var on :root). See D3 ADR of
|
|
597
597
|
// faang-density-tightening plan. Default `comfortable` density makes
|
|
598
598
|
// this 36px (--theo-control-h: 2.25rem). sm and lg stay hardcoded.
|
|
599
599
|
md: "h-[var(--theo-control-h,2rem)] px-[var(--theo-control-px,0.75rem)] text-body-sm",
|
|
@@ -4936,17 +4936,19 @@ function DataTableDefaultBody(props) {
|
|
|
4936
4936
|
}
|
|
4937
4937
|
const totalPages = pagination ? Math.ceil(sortedData.length / effectivePageSize) : 1;
|
|
4938
4938
|
return (
|
|
4939
|
-
// `overflow-x-auto`:
|
|
4940
|
-
//
|
|
4941
|
-
//
|
|
4942
|
-
//
|
|
4939
|
+
// `overflow-x-auto`: a table wider than its container SCROLLS inside it, instead of spilling
|
|
4940
|
+
// over the rest of the page. Measured in the consumer: 11 columns produced 1838 px inside
|
|
4941
|
+
// 1486 px, and the root was only `w-full` — so the excess escaped and broke the whole screen.
|
|
4942
|
+
// It was not one screen's defect: it was this root's, and it reached any consumer with too
|
|
4943
|
+
// many columns.
|
|
4943
4944
|
//
|
|
4944
|
-
//
|
|
4945
|
+
// The virtualised variant already did this; the non-virtualised one had fallen behind.
|
|
4945
4946
|
//
|
|
4946
|
-
//
|
|
4947
|
-
//
|
|
4948
|
-
//
|
|
4949
|
-
//
|
|
4947
|
+
// Declared side effect: with `overflow-x` set to anything other than `visible`, CSS computes
|
|
4948
|
+
// `overflow-y` as `auto` — so this `div` becomes a scroll container, and a `stickyHeader` now
|
|
4949
|
+
// sticks to it rather than to the viewport. For the header to actually stick, the consumer has
|
|
4950
|
+
// to give the container a max height (`className="max-h-[...]"`), which is what makes the
|
|
4951
|
+
// vertical scrolling real.
|
|
4950
4952
|
/* @__PURE__ */ jsxs("div", { className: cn("w-full overflow-x-auto", className), children: [
|
|
4951
4953
|
/* @__PURE__ */ jsxs(Table, { children: [
|
|
4952
4954
|
/* @__PURE__ */ jsx(Table.Header, { className: stickyHeader ? "sticky top-0 z-10 bg-card" : void 0, children: /* @__PURE__ */ jsx(
|
|
@@ -5109,14 +5111,14 @@ function niceMax(values) {
|
|
|
5109
5111
|
}
|
|
5110
5112
|
function seriesPath(points, xScale, yScale) {
|
|
5111
5113
|
const out = [];
|
|
5112
|
-
let
|
|
5114
|
+
let inStretch = false;
|
|
5113
5115
|
for (const p of points) {
|
|
5114
5116
|
if (!Number.isFinite(p.y)) {
|
|
5115
|
-
|
|
5117
|
+
inStretch = false;
|
|
5116
5118
|
continue;
|
|
5117
5119
|
}
|
|
5118
|
-
out.push(`${
|
|
5119
|
-
|
|
5120
|
+
out.push(`${inStretch ? "L" : "M"}${xScale(p.x).toFixed(2)},${yScale(p.y).toFixed(2)}`);
|
|
5121
|
+
inStretch = true;
|
|
5120
5122
|
}
|
|
5121
5123
|
return out.join(" ");
|
|
5122
5124
|
}
|
|
@@ -5128,17 +5130,19 @@ function xTicks(axisXs, viewW) {
|
|
|
5128
5130
|
if (axisXs.length <= 2) return [...axisXs];
|
|
5129
5131
|
const maxTicks = Math.max(2, Math.floor((viewW - PAD.left - PAD.right) / MIN_TICK_PX2));
|
|
5130
5132
|
if (axisXs.length <= maxTicks) return [...axisXs];
|
|
5131
|
-
const
|
|
5132
|
-
const
|
|
5133
|
-
for (let i = 0; i < maxTicks; i++)
|
|
5134
|
-
return [...
|
|
5133
|
+
const step = (axisXs.length - 1) / (maxTicks - 1);
|
|
5134
|
+
const chosen = /* @__PURE__ */ new Set();
|
|
5135
|
+
for (let i = 0; i < maxTicks; i++) chosen.add(Math.round(i * step));
|
|
5136
|
+
return [...chosen].sort((a, b) => a - b).map((i) => axisXs[i]);
|
|
5135
5137
|
}
|
|
5136
5138
|
var SPARSE_MARKER_MAX = 5;
|
|
5137
5139
|
function markedPoints(points) {
|
|
5138
|
-
const
|
|
5139
|
-
const
|
|
5140
|
-
if (
|
|
5141
|
-
return points.filter(
|
|
5140
|
+
const isFinitePoint = (p) => Number.isFinite(p?.y);
|
|
5141
|
+
const finitePoints = points.filter(isFinitePoint);
|
|
5142
|
+
if (finitePoints.length < SPARSE_MARKER_MAX) return finitePoints;
|
|
5143
|
+
return points.filter(
|
|
5144
|
+
(p, i) => isFinitePoint(p) && !isFinitePoint(points[i - 1]) && !isFinitePoint(points[i + 1])
|
|
5145
|
+
);
|
|
5142
5146
|
}
|
|
5143
5147
|
var TrendChart = forwardRef(
|
|
5144
5148
|
({
|
|
@@ -5210,16 +5214,16 @@ var TrendChart = forwardRef(
|
|
|
5210
5214
|
"data-slot": "trend-chart-surface",
|
|
5211
5215
|
className: "relative",
|
|
5212
5216
|
onMouseMove: (e) => {
|
|
5213
|
-
const
|
|
5214
|
-
if (
|
|
5215
|
-
const frac = (e.clientX -
|
|
5216
|
-
const
|
|
5217
|
-
let
|
|
5217
|
+
const box = e.currentTarget.getBoundingClientRect();
|
|
5218
|
+
if (box.width === 0 || axisXs.length === 0) return;
|
|
5219
|
+
const frac = (e.clientX - box.left) / box.width;
|
|
5220
|
+
const target = xMin + frac * (xMax - xMin);
|
|
5221
|
+
let best = 0;
|
|
5218
5222
|
for (let i = 1; i < axisXs.length; i++) {
|
|
5219
|
-
if (Math.abs(axisXs[i] -
|
|
5220
|
-
|
|
5223
|
+
if (Math.abs(axisXs[i] - target) < Math.abs(axisXs[best] - target))
|
|
5224
|
+
best = i;
|
|
5221
5225
|
}
|
|
5222
|
-
setHoverIdx(
|
|
5226
|
+
setHoverIdx(best);
|
|
5223
5227
|
},
|
|
5224
5228
|
onMouseLeave: () => setHoverIdx(null),
|
|
5225
5229
|
children: [
|
package/package.json
CHANGED
|
@@ -1,10 +1,33 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@usetheo/ui",
|
|
3
|
-
"version": "0.35.
|
|
4
|
-
"packageManager": "pnpm@10.32.1+sha512.a706938f0e89ac1456b6563eab4edf1d1faf3368d1191fc5c59790e96dc918e4456ab2e67d613de1043d2e8c81f87303e6b40d4ffeca9df15ef1ad567348f2be",
|
|
3
|
+
"version": "0.35.3",
|
|
5
4
|
"type": "module",
|
|
6
5
|
"license": "Apache-2.0",
|
|
7
|
-
"description": "Violet Forge design system
|
|
6
|
+
"description": "Violet Forge design system — generic React components + primitives (the non-AI foundation of @theokit/ui).",
|
|
7
|
+
"keywords": [
|
|
8
|
+
"react",
|
|
9
|
+
"design-system",
|
|
10
|
+
"components",
|
|
11
|
+
"ui",
|
|
12
|
+
"tailwind",
|
|
13
|
+
"radix",
|
|
14
|
+
"primitives",
|
|
15
|
+
"dashboard",
|
|
16
|
+
"theo",
|
|
17
|
+
"violet-forge"
|
|
18
|
+
],
|
|
19
|
+
"homepage": "https://github.com/usetheodev/usetheo-ui#readme",
|
|
20
|
+
"bugs": {
|
|
21
|
+
"url": "https://github.com/usetheodev/usetheo-ui/issues"
|
|
22
|
+
},
|
|
23
|
+
"repository": {
|
|
24
|
+
"type": "git",
|
|
25
|
+
"url": "git+https://github.com/usetheodev/usetheo-ui.git"
|
|
26
|
+
},
|
|
27
|
+
"publishConfig": {
|
|
28
|
+
"access": "public",
|
|
29
|
+
"provenance": true
|
|
30
|
+
},
|
|
8
31
|
"sideEffects": false,
|
|
9
32
|
"files": [
|
|
10
33
|
"dist"
|
|
@@ -22,19 +45,6 @@
|
|
|
22
45
|
"engines": {
|
|
23
46
|
"node": ">=20"
|
|
24
47
|
},
|
|
25
|
-
"scripts": {
|
|
26
|
-
"dev": "ladle serve",
|
|
27
|
-
"typecheck": "tsc --noEmit",
|
|
28
|
-
"lint": "biome check src",
|
|
29
|
-
"lint:ci": "biome check src",
|
|
30
|
-
"format:check": "biome format src",
|
|
31
|
-
"test": "vitest run",
|
|
32
|
-
"test:run": "vitest run",
|
|
33
|
-
"build": "tsup && tsc -p tsconfig.dts.json",
|
|
34
|
-
"prepublishOnly": "npm run build",
|
|
35
|
-
"registry:build": "tsx scripts/build-registry.ts",
|
|
36
|
-
"registry:validate": "tsx scripts/validate-registry.ts"
|
|
37
|
-
},
|
|
38
48
|
"peerDependencies": {
|
|
39
49
|
"react": ">=18",
|
|
40
50
|
"react-dom": ">=18"
|
|
@@ -64,6 +74,7 @@
|
|
|
64
74
|
},
|
|
65
75
|
"devDependencies": {
|
|
66
76
|
"@biomejs/biome": "^1.9.4",
|
|
77
|
+
"@changesets/cli": "^2.31.1",
|
|
67
78
|
"@ladle/react": "^4.1.2",
|
|
68
79
|
"@tailwindcss/vite": "^4.3.2",
|
|
69
80
|
"@testing-library/jest-dom": "^6.6.3",
|
|
@@ -84,5 +95,21 @@
|
|
|
84
95
|
"vitest": "^4.1.8",
|
|
85
96
|
"vitest-axe": "^0.1.0"
|
|
86
97
|
},
|
|
87
|
-
"_provenance": "seeded from theo-ui @ 2b46eca (2026-07-03, pivot M-B)"
|
|
88
|
-
|
|
98
|
+
"_provenance": "seeded from theo-ui @ 2b46eca (2026-07-03, pivot M-B)",
|
|
99
|
+
"scripts": {
|
|
100
|
+
"dev": "ladle serve",
|
|
101
|
+
"typecheck": "tsc --noEmit",
|
|
102
|
+
"lint": "biome check src",
|
|
103
|
+
"lint:ci": "biome check src",
|
|
104
|
+
"format:check": "biome format src",
|
|
105
|
+
"test": "vitest run",
|
|
106
|
+
"test:run": "vitest run",
|
|
107
|
+
"build": "tsup && tsc -p tsconfig.dts.json",
|
|
108
|
+
"registry:build": "tsx scripts/build-registry.ts",
|
|
109
|
+
"registry:validate": "tsx scripts/validate-registry.ts",
|
|
110
|
+
"changeset": "changeset",
|
|
111
|
+
"version-packages": "changeset version && pnpm run sync:readme",
|
|
112
|
+
"release": "pnpm run build && changeset publish",
|
|
113
|
+
"sync:readme": "tsx scripts/sync-readme.ts"
|
|
114
|
+
}
|
|
115
|
+
}
|