@usetheo/ui 0.1.0-next.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.
Files changed (133) hide show
  1. package/CHANGELOG.md +227 -0
  2. package/LICENSE +201 -0
  3. package/README.md +347 -0
  4. package/dist/fonts/LICENSE-GEIST.txt +92 -0
  5. package/dist/fonts/geist-400.woff2 +0 -0
  6. package/dist/fonts/geist-500.woff2 +0 -0
  7. package/dist/fonts/geist-600.woff2 +0 -0
  8. package/dist/fonts/geist-mono-400.woff2 +0 -0
  9. package/dist/fonts/geist-mono-500.woff2 +0 -0
  10. package/dist/fonts/geist-mono-600.woff2 +0 -0
  11. package/dist/fonts-cdn.css +28 -0
  12. package/dist/fonts.css +75 -0
  13. package/dist/index.d.ts +3063 -0
  14. package/dist/index.js +7746 -0
  15. package/dist/index.js.map +1 -0
  16. package/dist/styles.css +88 -0
  17. package/dist/tokens.css +230 -0
  18. package/package.json +520 -0
  19. package/registry/index.json +700 -0
  20. package/registry/r/agent-composer.json +22 -0
  21. package/registry/r/agent-editor.json +27 -0
  22. package/registry/r/agent-error-card.json +22 -0
  23. package/registry/r/agent-event.json +24 -0
  24. package/registry/r/agent-handoff.json +22 -0
  25. package/registry/r/agent-profile.json +23 -0
  26. package/registry/r/agent-starting-state.json +22 -0
  27. package/registry/r/agent-stream.json +27 -0
  28. package/registry/r/agent-streaming.json +22 -0
  29. package/registry/r/agent-timeline.json +22 -0
  30. package/registry/r/agent-types.json +15 -0
  31. package/registry/r/approval-card.json +25 -0
  32. package/registry/r/artifact-preview.json +22 -0
  33. package/registry/r/attachment-chip.json +24 -0
  34. package/registry/r/audit-log-entry.json +23 -0
  35. package/registry/r/auto-compact-notice.json +22 -0
  36. package/registry/r/avatar.json +23 -0
  37. package/registry/r/badge.json +22 -0
  38. package/registry/r/browser-controls.json +22 -0
  39. package/registry/r/build-log-stream.json +19 -0
  40. package/registry/r/button.json +23 -0
  41. package/registry/r/capability-indicator.json +23 -0
  42. package/registry/r/card.json +22 -0
  43. package/registry/r/chat-composer.json +23 -0
  44. package/registry/r/chat-message.json +21 -0
  45. package/registry/r/chat-thread.json +20 -0
  46. package/registry/r/chat-types.json +15 -0
  47. package/registry/r/checkbox.json +23 -0
  48. package/registry/r/cn.json +19 -0
  49. package/registry/r/command-palette.json +25 -0
  50. package/registry/r/context-card.json +23 -0
  51. package/registry/r/context-window-bar.json +20 -0
  52. package/registry/r/cost-meter.json +22 -0
  53. package/registry/r/created-files-card.json +23 -0
  54. package/registry/r/cron-job-card.json +22 -0
  55. package/registry/r/cron-jobs-list.json +23 -0
  56. package/registry/r/deployment-row.json +23 -0
  57. package/registry/r/dialog.json +23 -0
  58. package/registry/r/diff-viewer.json +20 -0
  59. package/registry/r/domain-config.json +25 -0
  60. package/registry/r/empty-state.json +20 -0
  61. package/registry/r/env-var-editor.json +25 -0
  62. package/registry/r/folder-context-card.json +23 -0
  63. package/registry/r/folder-selector.json +22 -0
  64. package/registry/r/form-field.json +23 -0
  65. package/registry/r/hook-config.json +22 -0
  66. package/registry/r/hook-event-log.json +22 -0
  67. package/registry/r/input.json +19 -0
  68. package/registry/r/intent-selector.json +24 -0
  69. package/registry/r/label.json +22 -0
  70. package/registry/r/lane-board.json +20 -0
  71. package/registry/r/live-region-context.json +16 -0
  72. package/registry/r/login-split.json +20 -0
  73. package/registry/r/mcp-server-card.json +22 -0
  74. package/registry/r/mcp-server-list.json +23 -0
  75. package/registry/r/memory-editor.json +23 -0
  76. package/registry/r/mention-menu.json +23 -0
  77. package/registry/r/metrics-panel.json +22 -0
  78. package/registry/r/mode-types.json +15 -0
  79. package/registry/r/model-card.json +23 -0
  80. package/registry/r/model-selector.json +23 -0
  81. package/registry/r/permission-matrix.json +22 -0
  82. package/registry/r/permission-modal.json +24 -0
  83. package/registry/r/permission-types.json +15 -0
  84. package/registry/r/preview-env-card.json +25 -0
  85. package/registry/r/preview-panel.json +21 -0
  86. package/registry/r/progress-checklist.json +23 -0
  87. package/registry/r/project-card.json +25 -0
  88. package/registry/r/project-switcher.json +22 -0
  89. package/registry/r/quick-action-chips.json +21 -0
  90. package/registry/r/radio-group.json +23 -0
  91. package/registry/r/recent-folders-list.json +22 -0
  92. package/registry/r/rollback-ui.json +24 -0
  93. package/registry/r/rule-card.json +23 -0
  94. package/registry/r/rule-editor.json +28 -0
  95. package/registry/r/rule-types.json +18 -0
  96. package/registry/r/run-stats.json +22 -0
  97. package/registry/r/running-tasks-panel.json +22 -0
  98. package/registry/r/safe-href.json +16 -0
  99. package/registry/r/scroll-area.json +22 -0
  100. package/registry/r/select.json +23 -0
  101. package/registry/r/session-list-item.json +20 -0
  102. package/registry/r/session-timeline.json +22 -0
  103. package/registry/r/sheet.json +24 -0
  104. package/registry/r/sidebar.json +19 -0
  105. package/registry/r/skeleton.json +19 -0
  106. package/registry/r/skill-card.json +24 -0
  107. package/registry/r/skill-editor.json +28 -0
  108. package/registry/r/skills-list.json +23 -0
  109. package/registry/r/social-auth-row.json +21 -0
  110. package/registry/r/steps-rail.json +20 -0
  111. package/registry/r/sub-agent-dispatch.json +22 -0
  112. package/registry/r/switch.json +22 -0
  113. package/registry/r/system-prompt-editor.json +22 -0
  114. package/registry/r/tabs.json +22 -0
  115. package/registry/r/tailwind-preset.json +19 -0
  116. package/registry/r/task-header.json +24 -0
  117. package/registry/r/task-plan.json +22 -0
  118. package/registry/r/task-types.json +15 -0
  119. package/registry/r/terminal-panel.json +22 -0
  120. package/registry/r/textarea.json +19 -0
  121. package/registry/r/theme-provider.json +59 -0
  122. package/registry/r/theme-script.json +18 -0
  123. package/registry/r/theo-ui-provider.json +20 -0
  124. package/registry/r/toast.json +30 -0
  125. package/registry/r/token-usage-chart.json +20 -0
  126. package/registry/r/tokens.json +21 -0
  127. package/registry/r/tool-call-card.json +23 -0
  128. package/registry/r/tool-call.json +22 -0
  129. package/registry/r/tool-result.json +20 -0
  130. package/registry/r/tools-list.json +23 -0
  131. package/registry/r/tooltip.json +22 -0
  132. package/registry/r/topnav.json +22 -0
  133. package/registry/r/types.json +15 -0
package/README.md ADDED
@@ -0,0 +1,347 @@
1
+ <div align="center">
2
+
3
+ <img src="https://usetheo.dev/logo-128.webp" alt="Theo" width="96" height="96" />
4
+
5
+ **`@usetheo/ui`**
6
+
7
+ # The UI your agent already needs.
8
+
9
+ A React component library built for AI agent surfaces and PaaS dashboards. **102 components** designed for what you'd otherwise build from scratch.
10
+
11
+ *Editorial typography. Three runtime-swappable themes. shadcn-compatible registry. Apache-2.0.*
12
+
13
+ <!-- BEGIN:counts -->
14
+ [![license](https://img.shields.io/badge/license-Apache--2.0-7C3AED?style=flat-square)](./LICENSE)
15
+ [![react](https://img.shields.io/badge/react-18+-7C3AED?style=flat-square&logo=react&logoColor=white)](https://react.dev)
16
+ [![tests](https://img.shields.io/badge/tests-514%20passing-success?style=flat-square)](#quality-gates)
17
+ [![components](https://img.shields.io/badge/components-101-7C3AED?style=flat-square)](#component-catalog)
18
+ [![shadcn](https://img.shields.io/badge/shadcn-compatible-000?style=flat-square)](https://ui.shadcn.com/docs/registry)
19
+ <!-- END:counts -->
20
+
21
+ [Quickstart](#quickstart) · [Components](#component-catalog) · [Themes](#themes) · [Design System](./docs/design-system.md) · [Quality Gates](./docs/quality-gates.md) · [Contributing](./CONTRIBUTING.md) · [Security](./SECURITY.md)
22
+
23
+ </div>
24
+
25
+ ---
26
+
27
+ ## The shift
28
+
29
+ There is a version of your product where the agent UI is half-built before you start.
30
+
31
+ The chat thread, the tool calls, the streaming assistant message, the model selector, the cost meter, the context window indicator, the audit log row, the permission modal, the deployment status, the build log stream — all rendered. All themed. All accessible. You write product logic. The interface ships with you.
32
+
33
+ ## Why `@usetheo/ui`
34
+
35
+ Most component libraries optimize for marketing pages. `@usetheo/ui` is built for the surfaces that AI agents and PaaS dashboards actually need — surfaces where transparency, density of information, and developer trust matter more than hero sections.
36
+
37
+ - **Built for AI agents.** Primitives for skills, cron jobs, permission matrices, MCP servers, memory editing, hook config, audit logs, model cards, token usage charts, sub-agent dispatch — the components a transparent agent UI actually needs.
38
+ - **Built for PaaS.** Composites for project cards, deployment rows, build log streams, env var editors, domain config, preview environments, rollback flows, metrics panels.
39
+ - **Themeable at runtime.** Ship three themes out of the box, swap them live via `<ThemeProvider />`, or define your own.
40
+ - **shadcn-compatible registry.** Copy individual components into your project (`npx shadcn add …`) or install the whole package — your call.
41
+ - **Framework-agnostic.** Peer-deps on React only. Works under Vite, Next, Remix, Astro, Tanstack Start.
42
+
43
+ The agent UI gap is real — most teams reach for shadcn for the primitives and build the agent-specific parts from scratch, losing weeks before shipping a real surface.
44
+
45
+ | Surface need | `@usetheo/ui` | shadcn / Radix | Tremor | Build it yourself |
46
+ |---|---|---|---|---|
47
+ | Generic primitives (Button, Card, Dialog) | **Yes** (same Radix foundation) | Yes | Limited | Slow |
48
+ | Agent-specific primitives (`AgentEvent`, `ToolCall`, `MCPServerCard`) | **Yes — 81 of them** | None | None | Weeks |
49
+ | PaaS-specific composites (`DeploymentRow`, `BuildLogStream`, `RollbackUI`) | **Yes — 21 of them** | None | None | Weeks |
50
+ | Three runtime-swappable themes | **Built-in** | DIY | DIY | DIY |
51
+ | shadcn-compatible registry | **Yes** | Original | No | N/A |
52
+ | ESM-only, tree-shake via barrel | **Yes** | Yes | Yes | DIY |
53
+ | a11y enforced as a quality gate | **Yes** — vitest-axe on 126 stories | Per-component, manual | Manual | Often skipped |
54
+
55
+ Same Radix UI underneath as shadcn — no philosophy fight. We just shipped the next 102 components you were about to write.
56
+
57
+ ## What you'd build
58
+
59
+ - **Coding assistant interface.** Chat thread, streaming assistant, tool-call timeline, file diff viewer, permission matrix, sub-agent dispatch.
60
+ - **Agent dashboard.** Run stats, session timeline, MCP server admin, cron job scheduler, memory editor, audit log, model card, cost meter.
61
+ - **PaaS dashboard.** Project switcher, deployment row, build log stream, env var editor, domain config, preview environments, rollback flows, metrics panels.
62
+ - **Internal AI tools.** Quick-action chips, intent selector, system-prompt editor, skill manager, rule editor, lane board.
63
+ - **Onboarding & auth surfaces.** Login split, social auth row, folder selector, recent folders list, project card.
64
+
65
+ ---
66
+
67
+ ## How it works
68
+
69
+ Below this line, full technical vocabulary is in play. Installation, themes, the component catalog, design system, quality gates.
70
+
71
+ ## Quickstart
72
+
73
+ ### Option A — install the package
74
+
75
+ ```bash
76
+ pnpm add @usetheo/ui
77
+ ```
78
+
79
+ ```css
80
+ /* app entrypoint */
81
+ @import "@usetheo/ui/tokens.css";
82
+ @import "@usetheo/ui/styles.css";
83
+ ```
84
+
85
+ ```tsx
86
+ import { ThemeProvider, AgentEvent, ToolCall, DeploymentRow } from "@usetheo/ui";
87
+
88
+ export default function App() {
89
+ return (
90
+ <ThemeProvider defaultTheme="violet-forge" defaultMode="dark">
91
+ <AgentEvent kind="thinking" text="Reading repository structure..." />
92
+ <ToolCall name="readFile" status="completed" />
93
+ <DeploymentRow status="ready" env="production" branch="main" />
94
+ </ThemeProvider>
95
+ );
96
+ }
97
+ ```
98
+
99
+ ### Option B — copy individual components (shadcn-style)
100
+
101
+ ```bash
102
+ npx shadcn@latest add https://ui.usetheo.dev/r/button.json
103
+ npx shadcn@latest add https://ui.usetheo.dev/r/deployment-row.json
104
+ ```
105
+
106
+ Every item under [`registry/r/`](./registry/r) is a standalone copy-paste unit with its dependencies declared.
107
+
108
+ **Precondition.** Copy-paste install requires `@/` configured as a path alias in your `tsconfig.json` (`{ "paths": { "@/*": ["./src/*"] } }`) — the shadcn-ui 2.0 convention. Inlined source uses `@/lib/cn` and similar `@/components/ui/...` imports. If your project uses a different alias (Vite default `~/`, etc.), either add the `@/` mapping or rewrite the imports after copy-paste. The shipped `registry/index.json` declares this requirement under `metadata.requires.tsconfigPathAlias`.
109
+
110
+ ### SSR (Next.js / Astro / Remix)
111
+
112
+ Inject `<ThemeScript>` in `<head>` to prevent FOUC and hydration mismatch:
113
+
114
+ ```tsx
115
+ import { ThemeProvider, ThemeScript } from "@usetheo/ui";
116
+
117
+ <html lang="en" suppressHydrationWarning>
118
+ <head>
119
+ <ThemeScript defaultTheme="violet-forge" defaultMode="dark" />
120
+ </head>
121
+ <body>
122
+ <ThemeProvider defaultTheme="violet-forge" defaultMode="dark">
123
+ {children}
124
+ </ThemeProvider>
125
+ </body>
126
+ </html>
127
+ ```
128
+
129
+ ---
130
+
131
+ ## Component catalog
132
+
133
+ <!-- BEGIN:component-catalog-intro -->
134
+ **101 components**, organized by mechanical rule: a *primitive* imports no other `@usetheo/ui` component; a *composite* does.
135
+ <!-- END:component-catalog-intro -->
136
+
137
+ <details>
138
+ <summary>
139
+ <!-- BEGIN:primitives-count -->
140
+ **Primitives** (80) — building blocks
141
+ <!-- END:primitives-count -->
142
+ </summary>
143
+
144
+ <!-- BEGIN:primitives -->
145
+ `AgentErrorCard` · `AgentEvent` · `AgentHandoff` · `AgentProfile` · `AgentStartingState` · `AgentStreaming`
146
+ `ArtifactPreview` · `AttachmentChip` · `AuditLogEntry` · `AutoCompactNotice` · `Avatar` · `Badge`
147
+ `BrowserControls` · `BuildLogStream` · `Button` · `CapabilityIndicator` · `Card` · `ChatMessage`
148
+ `ChatThread` · `Checkbox` · `ContextCard` · `ContextWindowBar` · `CostMeter` · `CreatedFilesCard`
149
+ `CronJobCard` · `Dialog` · `DiffViewer` · `EmptyState` · `FolderContextCard` · `FolderSelector`
150
+ `FormField` · `HookConfig` · `HookEventLog` · `Input` · `IntentSelector` · `Label`
151
+ `LaneBoard` · `LoginSplit` · `MCPServerCard` · `MemoryEditor` · `MentionMenu` · `MetricsPanel`
152
+ `ModelCard` · `ModelSelector` · `PermissionMatrix` · `ProgressChecklist` · `ProjectSwitcher` · `QuickActionChips`
153
+ `RadioGroup` · `RecentFoldersList` · `RuleCard` · `RunStats` · `RunningTasksPanel` · `ScrollArea`
154
+ `Select` · `SessionListItem` · `SessionTimeline` · `Sheet` · `Sidebar` · `Skeleton`
155
+ `SkillCard` · `SocialAuthRow` · `StepsRail` · `SubAgentDispatch` · `Switch` · `SystemPromptEditor`
156
+ `Tabs` · `TaskNode` · `TaskPlan` · `TerminalPanel` · `Textarea` · `Toast`
157
+ `Toaster` · `TokenUsageChart` · `ToolCall` · `ToolCallCard` · `ToolResult` · `ToolsList`
158
+ `Tooltip` · `TopNav`
159
+ <!-- END:primitives -->
160
+
161
+ </details>
162
+
163
+ <details>
164
+ <summary>
165
+ <!-- BEGIN:composites-count -->
166
+ **Composites** (21) — assembled flows
167
+ <!-- END:composites-count -->
168
+ </summary>
169
+
170
+ <!-- BEGIN:composites -->
171
+ `AgentComposer` · `AgentEditor` · `AgentStream` · `AgentTimeline` · `ApprovalCard` · `ChatComposer` · `CommandPalette` · `CronJobsList` · `DeploymentRow` · `DomainConfig` · `EnvVarEditor` · `MCPServerList` · `PermissionModal` · `PreviewEnvCard` · `PreviewPanel` · `ProjectCard` · `RollbackUI` · `RuleEditor` · `SkillEditor` · `SkillsList` · `TaskHeader`
172
+ <!-- END:composites -->
173
+
174
+ </details>
175
+
176
+ Browse them all in **Ladle**:
177
+
178
+ ```bash
179
+ pnpm dev # http://localhost:61000
180
+ ```
181
+
182
+ There's also a playground app for full-page demos:
183
+
184
+ ```bash
185
+ pnpm playground # http://localhost:5180
186
+ ```
187
+
188
+ ---
189
+
190
+ ## Themes
191
+
192
+ Three themes ship out of the box, all driven by HSL-split CSS variables. Swap at runtime with `<ThemeProvider />` + `<ThemeSwitcher />`.
193
+
194
+ | Theme | Vibe | Primary | Accent |
195
+ |---|---|---|---|
196
+ | `violet-forge` *(default)* | Editorial dark, AI workspace energy | Theo violet `#7C3AED` | Burnt sienna `#C96442` |
197
+ | `classic-paper` | Warm light, document-first reading | Indigo `#2563EB` | Amber `#F59E0B` |
198
+ | `aurora-terminal` | High-contrast dev terminal feel | Cyan-aurora `#3DD9D6` | Aurora pink `#FF5C8A` |
199
+
200
+ ```tsx
201
+ import { ThemeProvider, ThemeSwitcher, builtinThemes } from "@usetheo/ui";
202
+
203
+ <ThemeProvider defaultTheme="violet-forge" themes={builtinThemes}>
204
+ <ThemeSwitcher />
205
+ {/* your app */}
206
+ </ThemeProvider>
207
+ ```
208
+
209
+ Define your own theme by extending `Theme` from `@usetheo/ui` — see [`docs/design-system.md`](./docs/design-system.md).
210
+
211
+ ---
212
+
213
+ ## Design system: Violet Forge
214
+
215
+ | Token | Light | Dark |
216
+ |---|---|---|
217
+ | Primary (Theo violet) | `#7C3AED` | `#7C3AED` |
218
+ | Accent (burnt sienna) | `#C96442` | `#C96442` |
219
+ | Background | `#FFFFFF` pure white (Vercel-style) | `#0A0A0A` charcoal |
220
+ | Display font | **Geist Sans** | **Geist Sans** |
221
+ | Body font | **Geist Sans** | **Geist Sans** |
222
+ | Mono | **Geist Mono** | **Geist Mono** |
223
+
224
+ **Type scale (Vercel-inspired):** `64 / 48 / 40 / 32 / 28 / 24 / 20 / 18 / 15 / 14 / 12` px.
225
+
226
+ Full spec: [`docs/design-system.md`](./docs/design-system.md). Visual audit of competitors (Vercel, Railway, Render, Fly.io, Netlify, Coolify): [`docs/design-audit.md`](./docs/design-audit.md).
227
+
228
+ ### Self-hosting fonts
229
+
230
+ By default `@usetheo/ui/styles.css` `@import`s Geist + Geist Mono from `fonts.googleapis.com`. For GDPR-sensitive deployments or strict CSP environments, self-host instead:
231
+
232
+ 1. Download Geist from [Vercel](https://vercel.com/font) (or the `geist` npm package).
233
+ 2. Drop the assets into your `public/fonts/` folder.
234
+ 3. In your app's global CSS, comment the `@usetheo/ui/styles.css` `@import` rule for Google Fonts (or import `@usetheo/ui/tokens.css` only) and add your own `@font-face` blocks for `Geist` and `Geist Mono`.
235
+
236
+ The CSS variables (`--font-body`, `--font-display`, `--font-mono`) are already wired to consume whichever `@font-face` rules are present — no component changes needed.
237
+
238
+ ---
239
+
240
+ ## Quality Gates
241
+
242
+ Every change is validated through a strict chain — no PR ships otherwise.
243
+
244
+ ```bash
245
+ pnpm quality:gates
246
+ ```
247
+
248
+ Runs in order: `format:check` → `lint:ci` → `typecheck` → `test` → `build` → `registry:build` → `registry:validate` → `quality:structure` → `quality:bundle` → `quality:a11y` → `ladle:build`.
249
+
250
+ The structural validator ([`scripts/validate-quality-gates.ts`](./scripts/validate-quality-gates.ts)) enforces taxonomy (primitive vs composite by import graph), registry/test/story presence per item (test gate is **hard-fail**), public-export surface, design-system fidelity (Geist fonts + Vercel type scale), governance files (LICENSE + CHANGELOG), README ↔ exports drift, docs typography drift, composite-via-barrel imports, compound-pattern uniformity (`Object.assign /*#__PURE__*/`), README/architecture census consistency, vitest-axe coverage on ≥30 interactive primitives, and zero stray `*.bak` / `*.json.tmp` artifacts in the working tree. Full spec: [`docs/quality-gates.md`](./docs/quality-gates.md).
251
+
252
+ ---
253
+
254
+ ## Development
255
+
256
+ ```bash
257
+ pnpm install
258
+ pnpm dev # Ladle component preview (http://localhost:61000)
259
+ pnpm playground # Full-page demo app (http://localhost:5180)
260
+ pnpm test # Vitest (vitest run)
261
+ pnpm test:watch # Vitest watch mode
262
+ pnpm test:coverage # Vitest with coverage report
263
+ pnpm typecheck # tsc --noEmit
264
+ pnpm lint # Biome check
265
+ pnpm lint:fix # Biome check --write
266
+ pnpm build # tsup → dist/
267
+ pnpm registry:build # registry/*.json → registry/r/*.json
268
+ pnpm sync:readme # Regenerate README counts + catalog from source
269
+ pnpm test:registry # Fixture install test (registry copy-paste check)
270
+ pnpm quality:gates # full chain
271
+ ```
272
+
273
+ ---
274
+
275
+ ## Architecture
276
+
277
+ ```
278
+ src/
279
+ components/
280
+ primitives/ atomic building blocks (no internal @usetheo/ui deps)
281
+ composites/ assembled flows (compose primitives via barrel imports)
282
+ foundations/ Ladle stories for colors, typography, spacing, elevation, motion
283
+ themes/ ThemeProvider, ThemeScript, ThemeSwitcher, 3 themes
284
+ styles/ tokens.css, fonts.css, global.css
285
+ lib/ cn, types
286
+ test/ Vitest setup (with happy-dom polyfills)
287
+ .ladle/ Ladle config
288
+ registry/ shadcn-compatible registry descriptors (input)
289
+ r/ built registry items (output of registry:build)
290
+ scripts/ build-registry, validate-registry, sync-readme, validate-quality-gates
291
+ docs/ design-system, quality-gates, architecture, design-audit
292
+ tests/ fixture-shadcn-app/ (registry install integration test)
293
+ ```
294
+
295
+ ---
296
+
297
+ ## Bundle & module format
298
+
299
+ - **ESM-only** — `@usetheo/ui` ships a single `dist/index.js` (ESM) plus
300
+ per-component `dist/components/.../index.d.ts` type declarations. No CJS
301
+ build. Consumers running on CommonJS Node need to transpile or use a
302
+ bundler. This is intentional: the four-pillar audience (modern Vite,
303
+ Next 14+, Astro, Remix) is ESM-first.
304
+ - **Tree-shaking via the barrel** — modern bundlers (Vite, esbuild, Rollup,
305
+ webpack 5, Bun) read the `sideEffects: ["**/*.css"]` hint and tree-shake
306
+ unused components from the barrel import (`import { Button } from
307
+ "@usetheo/ui"` drops every other component from the final bundle). No
308
+ per-component subpath exports are needed for this to work.
309
+ - **Subpath imports are aliases (not separate bundles).** `package.json#exports`
310
+ publishes 99 component subpaths (`@usetheo/ui/button`, `@usetheo/ui/agent-event`,
311
+ …). Every subpath resolves to the same `dist/index.js`. tsup is configured with
312
+ `splitting: false` deliberately — a 99-entry split would duplicate shared code
313
+ (cn, types, Radix runtime) into every chunk and inflate the tarball. Subpath
314
+ imports exist for IDE intellisense and import organization. Modern bundlers
315
+ tree-shake the same way whether you write `import { Button } from "@usetheo/ui"`
316
+ or `import { Button } from "@usetheo/ui/button"`. Runtimes that don't tree-shake
317
+ (Jest classic, Node REPL, raw browser ESM) will load the full barrel either way
318
+ — accept that cost or pre-bundle with the consumer's tooling.
319
+ - **CSS distribution** — `dist/styles.css` is the recommended single import
320
+ (combines tokens, fonts self-hosted, Tailwind base/components/utilities).
321
+ `@usetheo/ui/tokens.css`, `@usetheo/ui/fonts.css`, and
322
+ `@usetheo/ui/fonts-cdn.css` (opt-in) are available for finer control.
323
+ - **Self-hosted fonts** — Geist Sans + Geist Mono ship as woff2 under
324
+ `dist/fonts/` (~290 KB total). Opt into Google Fonts CDN with
325
+ `@import "@usetheo/ui/fonts-cdn.css"` instead of the default if you
326
+ prefer not to host static assets.
327
+
328
+ ---
329
+
330
+ ## Status
331
+
332
+ Honest claims only.
333
+
334
+ - **Production.** 102 components, 453 tests passing, zero a11y violations on 126 Ladle stories, bundle size enforced. Quality gates run on every PR.
335
+ - **Registry distribution.** Artifacts shipped at `registry/r/*.json` in this repo; canonical `ui.usetheo.dev/r/*.json` URL is the planned distribution target.
336
+ - **ESM-only.** Modern bundlers only. Consumers on CommonJS Node need to transpile or use a bundler.
337
+ - **Component count is the floor, not the ceiling.** New agent and PaaS surfaces ship through PRs; every addition runs the same quality gates.
338
+
339
+ ## License
340
+
341
+ [Apache-2.0](./LICENSE) © [usetheo.dev](https://usetheo.dev)
342
+
343
+ ## Community
344
+
345
+ - Discord: https://discord.usetheo.dev/
346
+ - X: https://x.com/usetheodev
347
+ - LinkedIn: https://linkedin.com/company/usetheodev
@@ -0,0 +1,92 @@
1
+ Copyright (c) 2023 Vercel, in collaboration with basement.studio
2
+
3
+ This Font Software is licensed under the SIL Open Font License, Version 1.1.
4
+ This license is copied below, and is also available with a FAQ at:
5
+ http://scripts.sil.org/OFL
6
+
7
+ -----------------------------------------------------------
8
+ SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
9
+ -----------------------------------------------------------
10
+
11
+ PREAMBLE
12
+ The goals of the Open Font License (OFL) are to stimulate worldwide
13
+ development of collaborative font projects, to support the font creation
14
+ efforts of academic and linguistic communities, and to provide a free and
15
+ open framework in which fonts may be shared and improved in partnership
16
+ with others.
17
+
18
+ The OFL allows the licensed fonts to be used, studied, modified and
19
+ redistributed freely as long as they are not sold by themselves. The
20
+ fonts, including any derivative works, can be bundled, embedded,
21
+ redistributed and/or sold with any software provided that any reserved
22
+ names are not used by derivative works. The fonts and derivatives,
23
+ however, cannot be released under any other type of license. The
24
+ requirement for fonts to remain under this license does not apply
25
+ to any document created using the fonts or their derivatives.
26
+
27
+ DEFINITIONS
28
+ "Font Software" refers to the set of files released by the Copyright
29
+ Holder(s) under this license and clearly marked as such. This may
30
+ include source files, build scripts and documentation.
31
+
32
+ "Reserved Font Name" refers to any names specified as such after the
33
+ copyright statement(s).
34
+
35
+ "Original Version" refers to the collection of Font Software components as
36
+ distributed by the Copyright Holder(s).
37
+
38
+ "Modified Version" refers to any derivative made by adding to, deleting,
39
+ or substituting -- in part or in whole -- any of the components of the
40
+ Original Version, by changing formats or by porting the Font Software to a
41
+ new environment.
42
+
43
+ "Author" refers to any designer, engineer, programmer, technical
44
+ writer or other person who contributed to the Font Software.
45
+
46
+ PERMISSION AND CONDITIONS
47
+ Permission is hereby granted, free of charge, to any person obtaining
48
+ a copy of the Font Software, to use, study, copy, merge, embed, modify,
49
+ redistribute, and sell modified and unmodified copies of the Font
50
+ Software, subject to the following conditions:
51
+
52
+ 1) Neither the Font Software nor any of its individual components,
53
+ in Original or Modified Versions, may be sold by itself.
54
+
55
+ 2) Original or Modified Versions of the Font Software may be bundled,
56
+ redistributed and/or sold with any software, provided that each copy
57
+ contains the above copyright notice and this license. These can be
58
+ included either as stand-alone text files, human-readable headers or
59
+ in the appropriate machine-readable metadata fields within text or
60
+ binary files as long as those fields can be easily viewed by the user.
61
+
62
+ 3) No Modified Version of the Font Software may use the Reserved Font
63
+ Name(s) unless explicit written permission is granted by the corresponding
64
+ Copyright Holder. This restriction only applies to the primary font name as
65
+ presented to the users.
66
+
67
+ 4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
68
+ Software shall not be used to promote, endorse or advertise any
69
+ Modified Version, except to acknowledge the contribution(s) of the
70
+ Copyright Holder(s) and the Author(s) or with their explicit written
71
+ permission.
72
+
73
+ 5) The Font Software, modified or unmodified, in part or in whole,
74
+ must be distributed entirely under this license, and must not be
75
+ distributed under any other license. The requirement for fonts to
76
+ remain under this license does not apply to any document created
77
+ using the Font Software.
78
+
79
+ TERMINATION
80
+ This license becomes null and void if any of the above conditions are
81
+ not met.
82
+
83
+ DISCLAIMER
84
+ THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
85
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
86
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
87
+ OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
88
+ COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
89
+ INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
90
+ DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
91
+ FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
92
+ OTHER DEALINGS IN THE FONT SOFTWARE.
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
@@ -0,0 +1,28 @@
1
+ /* Theo UI — font loading via Google Fonts CDN (opt-in).
2
+ *
3
+ * Use this entrypoint instead of `@usetheo/ui/fonts.css` if you prefer to
4
+ * fetch Geist + Geist Mono from `fonts.googleapis.com` rather than ship the
5
+ * 290 KB of woff2 assets that the self-hosted entrypoint includes.
6
+ *
7
+ * Trade-offs:
8
+ * - PRO: zero static assets to host; smaller npm tarball footprint for
9
+ * consumers who use a `pnpm dlx` workflow.
10
+ * - CON: third-party network request on every page load; conflicts with
11
+ * strict CSP and GDPR jurisdictions; render-blocking on cold cache.
12
+ *
13
+ * The default for `@usetheo/ui/styles.css` (and `@usetheo/ui/fonts.css`)
14
+ * is the self-hosted path (HIGH-002 / D6). Switch to this only if your
15
+ * threat model permits the third-party fetch.
16
+ *
17
+ * Usage:
18
+ *
19
+ * @import "@usetheo/ui/tokens.css";
20
+ * @import "@usetheo/ui/fonts-cdn.css"; // NOT styles.css (which bundles
21
+ * // the self-hosted @font-face)
22
+ *
23
+ * The CSS variables (`--font-display`, `--font-body`, `--font-mono`) in
24
+ * tokens.css already reference `"Geist"` / `"Geist Mono"`; no component
25
+ * change required when switching entrypoints.
26
+ */
27
+
28
+ @import url("https://fonts.googleapis.com/css2?family=Geist:wght@100..900&family=Geist+Mono:wght@100..900&display=swap");
package/dist/fonts.css ADDED
@@ -0,0 +1,75 @@
1
+ /* Theo UI — font loading (self-hosted by default).
2
+ *
3
+ * Default theme (Violet Forge): Geist Sans + Geist Mono.
4
+ * Vercel-inspired typographic vocabulary — tight letter-spacing on display,
5
+ * 3 strict weights (400 body / 500 UI / 600 display), OpenType "liga"
6
+ * enabled globally. Geist is Vercel's open-source typeface, optimized for
7
+ * product UIs and code surfaces. Licensed under SIL Open Font License
8
+ * (LICENSE-GEIST.txt sits next to the woff2 files in `dist/fonts/`).
9
+ *
10
+ * ── Why self-hosted by default (HIGH-002 / D6) ────────────────────────────
11
+ * The previous default `@import url("https://fonts.googleapis.com/...")`
12
+ * triggered a third-party network request on every page load — friction for
13
+ * CSP-strict deployments, GDPR jurisdictions, and offline-first products.
14
+ * The fonts ship as woff2 next to this CSS; consumers who installed
15
+ * `@usetheo/ui/styles.css` get Geist with zero external dependencies.
16
+ *
17
+ * Asset budget: 6 woff2 files (~290 KB total). Three weights per family
18
+ * cover the entire Violet Forge typescale (display-2xl through code-sm).
19
+ *
20
+ * ── Opt-in CDN ────────────────────────────────────────────────────────────
21
+ * Consumers who prefer Google Fonts CDN (e.g. don't want to host static
22
+ * assets) can use the parallel entrypoint instead:
23
+ *
24
+ * @import "@usetheo/ui/fonts-cdn.css";
25
+ *
26
+ * That file keeps the legacy @import to fonts.googleapis.com.
27
+ */
28
+
29
+ @font-face {
30
+ font-family: "Geist";
31
+ font-style: normal;
32
+ font-weight: 400;
33
+ font-display: swap;
34
+ src: url("./fonts/geist-400.woff2") format("woff2");
35
+ }
36
+
37
+ @font-face {
38
+ font-family: "Geist";
39
+ font-style: normal;
40
+ font-weight: 500;
41
+ font-display: swap;
42
+ src: url("./fonts/geist-500.woff2") format("woff2");
43
+ }
44
+
45
+ @font-face {
46
+ font-family: "Geist";
47
+ font-style: normal;
48
+ font-weight: 600;
49
+ font-display: swap;
50
+ src: url("./fonts/geist-600.woff2") format("woff2");
51
+ }
52
+
53
+ @font-face {
54
+ font-family: "Geist Mono";
55
+ font-style: normal;
56
+ font-weight: 400;
57
+ font-display: swap;
58
+ src: url("./fonts/geist-mono-400.woff2") format("woff2");
59
+ }
60
+
61
+ @font-face {
62
+ font-family: "Geist Mono";
63
+ font-style: normal;
64
+ font-weight: 500;
65
+ font-display: swap;
66
+ src: url("./fonts/geist-mono-500.woff2") format("woff2");
67
+ }
68
+
69
+ @font-face {
70
+ font-family: "Geist Mono";
71
+ font-style: normal;
72
+ font-weight: 600;
73
+ font-display: swap;
74
+ src: url("./fonts/geist-mono-600.woff2") format("woff2");
75
+ }