@candor-ui/react 0.0.0-stage → 1.0.1

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 (100) hide show
  1. package/LICENSE +24 -0
  2. package/README.md +187 -2
  3. package/dist/adapters/ag-ui.d.ts +75 -0
  4. package/dist/adapters/ag-ui.js +441 -0
  5. package/dist/adapters/ai-sdk.d.ts +22 -0
  6. package/dist/adapters/ai-sdk.js +129 -0
  7. package/dist/adapters/claude-agent-sdk.d.ts +80 -0
  8. package/dist/adapters/claude-agent-sdk.js +265 -0
  9. package/dist/adapters/claude-agent-server.d.ts +53 -0
  10. package/dist/adapters/claude-agent-server.js +104 -0
  11. package/dist/adapters/use-ag-ui.d.ts +55 -0
  12. package/dist/adapters/use-ag-ui.js +168 -0
  13. package/dist/adapters/use-candor-chat.d.ts +40 -0
  14. package/dist/adapters/use-candor-chat.js +56 -0
  15. package/dist/adapters/use-claude-agent.d.ts +48 -0
  16. package/dist/adapters/use-claude-agent.js +143 -0
  17. package/dist/ag-ui.d.ts +2 -0
  18. package/dist/ag-ui.js +2 -0
  19. package/dist/ai-sdk.d.ts +2 -0
  20. package/dist/ai-sdk.js +2 -0
  21. package/dist/blocks/copy-field.d.ts +13 -0
  22. package/dist/blocks/copy-field.js +15 -0
  23. package/dist/blocks/degraded-panel.d.ts +19 -0
  24. package/dist/blocks/degraded-panel.js +14 -0
  25. package/dist/blocks/locked.d.ts +26 -0
  26. package/dist/blocks/locked.js +36 -0
  27. package/dist/blocks/relative-time.d.ts +13 -0
  28. package/dist/blocks/relative-time.js +62 -0
  29. package/dist/blocks/status-dot.d.ts +16 -0
  30. package/dist/blocks/status-dot.js +25 -0
  31. package/dist/blocks/step-list.d.ts +23 -0
  32. package/dist/blocks/step-list.js +37 -0
  33. package/dist/blocks/streaming-text.d.ts +17 -0
  34. package/dist/blocks/streaming-text.js +14 -0
  35. package/dist/blocks/surface.d.ts +9 -0
  36. package/dist/blocks/surface.js +35 -0
  37. package/dist/blocks/terms.d.ts +24 -0
  38. package/dist/blocks/terms.js +17 -0
  39. package/dist/chat/agent-avatar.d.ts +34 -0
  40. package/dist/chat/agent-avatar.js +42 -0
  41. package/dist/chat/card-registry.d.ts +39 -0
  42. package/dist/chat/card-registry.js +49 -0
  43. package/dist/chat/citation.d.ts +29 -0
  44. package/dist/chat/citation.js +44 -0
  45. package/dist/chat/composer.d.ts +54 -0
  46. package/dist/chat/composer.js +168 -0
  47. package/dist/chat/context-meter.d.ts +14 -0
  48. package/dist/chat/context-meter.js +30 -0
  49. package/dist/chat/entity-chip.d.ts +37 -0
  50. package/dist/chat/entity-chip.js +52 -0
  51. package/dist/chat/message-actions.d.ts +21 -0
  52. package/dist/chat/message-actions.js +20 -0
  53. package/dist/chat/message-content.d.ts +25 -0
  54. package/dist/chat/message-content.js +122 -0
  55. package/dist/chat/message.d.ts +39 -0
  56. package/dist/chat/message.js +44 -0
  57. package/dist/chat/payload.d.ts +16 -0
  58. package/dist/chat/payload.js +18 -0
  59. package/dist/chat/prompt-suggestions.d.ts +20 -0
  60. package/dist/chat/prompt-suggestions.js +18 -0
  61. package/dist/chat/reasoning.d.ts +18 -0
  62. package/dist/chat/reasoning.js +31 -0
  63. package/dist/chat/thread.d.ts +18 -0
  64. package/dist/chat/thread.js +60 -0
  65. package/dist/chat/tool-call.d.ts +19 -0
  66. package/dist/chat/tool-call.js +33 -0
  67. package/dist/claude-server.d.ts +1 -0
  68. package/dist/claude-server.js +2 -0
  69. package/dist/claude.d.ts +2 -0
  70. package/dist/claude.js +2 -0
  71. package/dist/index.d.ts +40 -0
  72. package/dist/index.js +38 -0
  73. package/dist/lib/chat.d.ts +241 -0
  74. package/dist/lib/chat.js +1 -0
  75. package/dist/lib/know.d.ts +123 -0
  76. package/dist/lib/know.js +1 -0
  77. package/dist/lib/render-prop.d.ts +16 -0
  78. package/dist/lib/render-prop.js +7 -0
  79. package/dist/lib/safe-markdown.d.ts +12 -0
  80. package/dist/lib/safe-markdown.js +98 -0
  81. package/dist/lib/status.d.ts +21 -0
  82. package/dist/lib/status.js +26 -0
  83. package/dist/lib/use-copy.d.ts +10 -0
  84. package/dist/lib/use-copy.js +24 -0
  85. package/dist/lib/use-shortcut.d.ts +15 -0
  86. package/dist/lib/use-shortcut.js +62 -0
  87. package/dist/lib/utils.d.ts +2 -0
  88. package/dist/lib/utils.js +5 -0
  89. package/dist/styles.css +460 -0
  90. package/dist/ui/button.d.ts +12 -0
  91. package/dist/ui/button.js +41 -0
  92. package/dist/ui/collapsible.d.ts +6 -0
  93. package/dist/ui/collapsible.js +15 -0
  94. package/dist/ui/popover.d.ts +11 -0
  95. package/dist/ui/popover.js +29 -0
  96. package/dist/ui/skeleton.d.ts +2 -0
  97. package/dist/ui/skeleton.js +6 -0
  98. package/dist/ui/tooltip.d.ts +9 -0
  99. package/dist/ui/tooltip.js +24 -0
  100. package/package.json +90 -4
@@ -0,0 +1,26 @@
1
+ export const statusLabel = {
2
+ idle: "Not started",
3
+ queued: "Queued",
4
+ running: "Running",
5
+ waiting: "Needs you",
6
+ blocked: "Blocked",
7
+ succeeded: "Done",
8
+ failed: "Failed",
9
+ cancelled: "Cancelled",
10
+ skipped: "Skipped",
11
+ };
12
+ /** The Badge variant that carries each status. */
13
+ export const statusTone = {
14
+ idle: "outline",
15
+ queued: "secondary",
16
+ running: "running",
17
+ waiting: "warning",
18
+ blocked: "outline",
19
+ succeeded: "success",
20
+ failed: "destructive",
21
+ cancelled: "outline",
22
+ skipped: "outline",
23
+ };
24
+ export function isTerminal(status) {
25
+ return status === "succeeded" || status === "failed" || status === "cancelled" || status === "skipped";
26
+ }
@@ -0,0 +1,10 @@
1
+ export type CopyState = "idle" | "copying" | "copied" | "failed";
2
+ /**
3
+ * Copy text and report what actually happened. "copied" only after the
4
+ * clipboard write resolves; a refused write reports "failed" (Candor's honest
5
+ * copy control: no success signal without a settled outcome).
6
+ */
7
+ export declare function useCopy(resetAfter?: number): {
8
+ state: CopyState;
9
+ copy: (text: string) => Promise<void>;
10
+ };
@@ -0,0 +1,24 @@
1
+ import * as React from "react";
2
+ /**
3
+ * Copy text and report what actually happened. "copied" only after the
4
+ * clipboard write resolves; a refused write reports "failed" (Candor's honest
5
+ * copy control: no success signal without a settled outcome).
6
+ */
7
+ export function useCopy(resetAfter = 1600) {
8
+ const [state, setState] = React.useState("idle");
9
+ const timer = React.useRef(undefined);
10
+ React.useEffect(() => () => window.clearTimeout(timer.current), []);
11
+ const copy = React.useCallback(async (text) => {
12
+ setState("copying");
13
+ try {
14
+ await navigator.clipboard.writeText(text);
15
+ setState("copied");
16
+ }
17
+ catch {
18
+ setState("failed");
19
+ }
20
+ window.clearTimeout(timer.current);
21
+ timer.current = window.setTimeout(() => setState("idle"), resetAfter);
22
+ }, [resetAfter]);
23
+ return { state, copy };
24
+ }
@@ -0,0 +1,15 @@
1
+ /** True on Apple platforms, where "mod" is ⌘ rather than Ctrl. */
2
+ export declare function isApple(): boolean;
3
+ /**
4
+ * The keys of a combo as they should be printed: "mod+k" → ["⌘", "K"] on a
5
+ * Mac and ["Ctrl", "K"] elsewhere.
6
+ */
7
+ export declare function comboKeys(combo: string): string[];
8
+ /**
9
+ * Run `handler` when a key combo is pressed anywhere on the page: "mod+k",
10
+ * "mod+shift+o", "?", "escape". A combo without mod or alt is ignored while
11
+ * the person is typing in a field, so "?" still types a question mark.
12
+ */
13
+ export declare function useShortcut(combo: string, handler: (e: KeyboardEvent) => void, { enabled }?: {
14
+ enabled?: boolean;
15
+ }): void;
@@ -0,0 +1,62 @@
1
+ import * as React from "react";
2
+ /** True on Apple platforms, where "mod" is ⌘ rather than Ctrl. */
3
+ export function isApple() {
4
+ return typeof navigator !== "undefined" && /Mac|iPhone|iPad/.test(navigator.platform || navigator.userAgent);
5
+ }
6
+ /**
7
+ * The keys of a combo as they should be printed: "mod+k" → ["⌘", "K"] on a
8
+ * Mac and ["Ctrl", "K"] elsewhere.
9
+ */
10
+ export function comboKeys(combo) {
11
+ const apple = isApple();
12
+ const names = {
13
+ mod: apple ? "⌘" : "Ctrl",
14
+ shift: apple ? "⇧" : "Shift",
15
+ alt: apple ? "⌥" : "Alt",
16
+ enter: "↵",
17
+ escape: "Esc",
18
+ up: "↑",
19
+ down: "↓",
20
+ };
21
+ return combo.split("+").map((k) => names[k] ?? (k.length === 1 ? k.toUpperCase() : k));
22
+ }
23
+ function typing(target) {
24
+ const el = target;
25
+ return !!el && (el.isContentEditable || /^(INPUT|TEXTAREA|SELECT)$/.test(el.tagName));
26
+ }
27
+ /**
28
+ * Run `handler` when a key combo is pressed anywhere on the page: "mod+k",
29
+ * "mod+shift+o", "?", "escape". A combo without mod or alt is ignored while
30
+ * the person is typing in a field, so "?" still types a question mark.
31
+ */
32
+ export function useShortcut(combo, handler, { enabled = true } = {}) {
33
+ const latest = React.useRef(handler);
34
+ React.useEffect(() => {
35
+ latest.current = handler;
36
+ });
37
+ React.useEffect(() => {
38
+ if (!enabled)
39
+ return;
40
+ const parts = combo.toLowerCase().split("+");
41
+ const key = parts[parts.length - 1];
42
+ const mod = parts.includes("mod");
43
+ const shift = parts.includes("shift");
44
+ const alt = parts.includes("alt");
45
+ const onKey = (e) => {
46
+ const modDown = isApple() ? e.metaKey : e.ctrlKey;
47
+ if (mod !== modDown || alt !== e.altKey)
48
+ return;
49
+ // "?" arrives with shift held; only compare shift when the combo names it.
50
+ if (shift && !e.shiftKey)
51
+ return;
52
+ if (e.key.toLowerCase() !== key)
53
+ return;
54
+ if (!mod && !alt && typing(e.target))
55
+ return;
56
+ e.preventDefault();
57
+ latest.current(e);
58
+ };
59
+ window.addEventListener("keydown", onKey);
60
+ return () => window.removeEventListener("keydown", onKey);
61
+ }, [combo, enabled]);
62
+ }
@@ -0,0 +1,2 @@
1
+ import { type ClassValue } from "clsx";
2
+ export declare function cn(...inputs: ClassValue[]): string;
@@ -0,0 +1,5 @@
1
+ import { clsx } from "clsx";
2
+ import { twMerge } from "tailwind-merge";
3
+ export function cn(...inputs) {
4
+ return twMerge(clsx(inputs));
5
+ }
@@ -0,0 +1,460 @@
1
+ /*
2
+ * @candor-ui/react: Candor UI's theme and tokens, for Tailwind CSS 4. MIT, (c) Methodic LLC.
3
+ * Built from src/styles/candor.css and candor-theme.css; don't edit here.
4
+ *
5
+ * @import "tailwindcss";
6
+ * @import "@candor-ui/react/styles.css";
7
+ *
8
+ * The @source below makes Tailwind generate the classes the components use, so they're styled even though
9
+ * Tailwind skips node_modules when it scans your app.
10
+ */
11
+ @import "@fontsource-variable/inter/opsz.css";
12
+ @import "tw-animate-css";
13
+
14
+ @source "./**/*.js";
15
+
16
+ /*
17
+ * Candor's default colours. GENERATED by scripts/theme.mjs from its data,
18
+ * after checking every text/ground pairing for contrast (40 pairings in
19
+ * each of 3 themes); edit there, not here.
20
+ * Light is the default; dark and high contrast follow data-theme, and the
21
+ * system setting when no data-theme is set.
22
+ */
23
+ :root {
24
+ color-scheme: light;
25
+ --background: oklch(0.985 0.002 262);
26
+ --card: oklch(1 0 0);
27
+ --popover: oklch(1 0 0);
28
+ --sunken: oklch(0.972 0.003 262);
29
+ --chrome: oklch(0.976 0.003 262);
30
+ --muted: oklch(0.955 0.004 262);
31
+ --accent: oklch(0.945 0.006 262);
32
+ --foreground: oklch(0.21 0.014 265);
33
+ --muted-foreground: oklch(0.46 0.016 265);
34
+ --faint-foreground: oklch(0.52 0.012 265);
35
+ --border: oklch(0.915 0.005 262);
36
+ --border-strong: oklch(0.85 0.007 262);
37
+ --input: oklch(0.62 0.01 262);
38
+ --ring: oklch(0.55 0.19 262);
39
+ --primary: oklch(0.53 0.19 262);
40
+ --primary-foreground: oklch(1 0 0);
41
+ --primary-hover: oklch(0.48 0.19 262);
42
+ --accent-weak: oklch(0.95 0.03 262);
43
+ --accent-text: oklch(0.45 0.18 262);
44
+ --destructive: oklch(0.55 0.2 27);
45
+ --destructive-weak: oklch(0.962 0.024 27);
46
+ --destructive-text: oklch(0.47 0.17 27);
47
+ --on-destructive: oklch(1 0 0);
48
+ --warning: oklch(0.77 0.15 75);
49
+ --warning-weak: oklch(0.968 0.045 90);
50
+ --warning-text: oklch(0.46 0.1 60);
51
+ --success: oklch(0.53 0.13 155);
52
+ --success-weak: oklch(0.962 0.035 155);
53
+ --success-text: oklch(0.43 0.1 155);
54
+ --on-success: oklch(1 0 0);
55
+ --attention: oklch(0.56 0.2 300);
56
+ --attention-weak: oklch(0.962 0.03 300);
57
+ --attention-text: oklch(0.47 0.18 300);
58
+ --surface-agent: oklch(1 0 0);
59
+ --surface-user: oklch(0.952 0.022 262);
60
+ --text-provisional: oklch(0.48 0.11 60);
61
+ --series-1: #2a78d6;
62
+ --series-2: #eb6834;
63
+ --series-3: #1baf7a;
64
+ --series-4: #eda100;
65
+ --series-5: #e87ba4;
66
+ --series-6: #008300;
67
+ --chart-1: var(--series-1);
68
+ --chart-2: var(--series-2);
69
+ --chart-3: var(--series-3);
70
+ --chart-4: var(--series-4);
71
+ --chart-5: var(--series-5);
72
+ }
73
+
74
+ [data-theme="dark"] {
75
+ color-scheme: dark;
76
+ --background: oklch(0.16 0.006 265);
77
+ --card: oklch(0.195 0.007 265);
78
+ --popover: oklch(0.215 0.008 265);
79
+ --sunken: oklch(0.14 0.006 265);
80
+ --chrome: oklch(0.175 0.007 265);
81
+ --muted: oklch(0.25 0.008 265);
82
+ --accent: oklch(0.27 0.009 265);
83
+ --foreground: oklch(0.95 0.004 265);
84
+ --muted-foreground: oklch(0.74 0.012 265);
85
+ --faint-foreground: oklch(0.66 0.012 265);
86
+ --border: oklch(0.285 0.008 265);
87
+ --border-strong: oklch(0.36 0.01 265);
88
+ --input: oklch(0.5 0.012 265);
89
+ --ring: oklch(0.68 0.15 262);
90
+ --primary: oklch(0.68 0.15 262);
91
+ --primary-foreground: oklch(0.16 0.02 262);
92
+ --primary-hover: oklch(0.74 0.13 262);
93
+ --accent-weak: oklch(0.29 0.06 262);
94
+ --accent-text: oklch(0.8 0.11 262);
95
+ --destructive: oklch(0.66 0.19 25);
96
+ --destructive-weak: oklch(0.28 0.06 25);
97
+ --destructive-text: oklch(0.8 0.12 25);
98
+ --on-destructive: oklch(0.16 0.02 25);
99
+ --warning: oklch(0.8 0.14 80);
100
+ --warning-weak: oklch(0.29 0.05 75);
101
+ --warning-text: oklch(0.86 0.11 85);
102
+ --success: oklch(0.7 0.14 155);
103
+ --success-weak: oklch(0.27 0.05 155);
104
+ --success-text: oklch(0.82 0.11 155);
105
+ --on-success: oklch(0.16 0.02 155);
106
+ --attention: oklch(0.7 0.16 300);
107
+ --attention-weak: oklch(0.29 0.06 300);
108
+ --attention-text: oklch(0.82 0.11 300);
109
+ --surface-agent: oklch(0.195 0.007 265);
110
+ --surface-user: oklch(0.27 0.035 262);
111
+ --text-provisional: oklch(0.84 0.1 75);
112
+ --series-1: #3987e5;
113
+ --series-2: #d95926;
114
+ --series-3: #199e70;
115
+ --series-4: #c98500;
116
+ --series-5: #d55181;
117
+ --series-6: #008300;
118
+ --chart-1: var(--series-1);
119
+ --chart-2: var(--series-2);
120
+ --chart-3: var(--series-3);
121
+ --chart-4: var(--series-4);
122
+ --chart-5: var(--series-5);
123
+ }
124
+
125
+ @media (prefers-color-scheme: dark) {
126
+ :root:not([data-theme]) {
127
+ color-scheme: dark;
128
+ --background: oklch(0.16 0.006 265);
129
+ --card: oklch(0.195 0.007 265);
130
+ --popover: oklch(0.215 0.008 265);
131
+ --sunken: oklch(0.14 0.006 265);
132
+ --chrome: oklch(0.175 0.007 265);
133
+ --muted: oklch(0.25 0.008 265);
134
+ --accent: oklch(0.27 0.009 265);
135
+ --foreground: oklch(0.95 0.004 265);
136
+ --muted-foreground: oklch(0.74 0.012 265);
137
+ --faint-foreground: oklch(0.66 0.012 265);
138
+ --border: oklch(0.285 0.008 265);
139
+ --border-strong: oklch(0.36 0.01 265);
140
+ --input: oklch(0.5 0.012 265);
141
+ --ring: oklch(0.68 0.15 262);
142
+ --primary: oklch(0.68 0.15 262);
143
+ --primary-foreground: oklch(0.16 0.02 262);
144
+ --primary-hover: oklch(0.74 0.13 262);
145
+ --accent-weak: oklch(0.29 0.06 262);
146
+ --accent-text: oklch(0.8 0.11 262);
147
+ --destructive: oklch(0.66 0.19 25);
148
+ --destructive-weak: oklch(0.28 0.06 25);
149
+ --destructive-text: oklch(0.8 0.12 25);
150
+ --on-destructive: oklch(0.16 0.02 25);
151
+ --warning: oklch(0.8 0.14 80);
152
+ --warning-weak: oklch(0.29 0.05 75);
153
+ --warning-text: oklch(0.86 0.11 85);
154
+ --success: oklch(0.7 0.14 155);
155
+ --success-weak: oklch(0.27 0.05 155);
156
+ --success-text: oklch(0.82 0.11 155);
157
+ --on-success: oklch(0.16 0.02 155);
158
+ --attention: oklch(0.7 0.16 300);
159
+ --attention-weak: oklch(0.29 0.06 300);
160
+ --attention-text: oklch(0.82 0.11 300);
161
+ --surface-agent: oklch(0.195 0.007 265);
162
+ --surface-user: oklch(0.27 0.035 262);
163
+ --text-provisional: oklch(0.84 0.1 75);
164
+ --series-1: #3987e5;
165
+ --series-2: #d95926;
166
+ --series-3: #199e70;
167
+ --series-4: #c98500;
168
+ --series-5: #d55181;
169
+ --series-6: #008300;
170
+ --chart-1: var(--series-1);
171
+ --chart-2: var(--series-2);
172
+ --chart-3: var(--series-3);
173
+ --chart-4: var(--series-4);
174
+ --chart-5: var(--series-5);
175
+ }
176
+ }
177
+
178
+ [data-theme="hc"] {
179
+ color-scheme: light;
180
+ --background: oklch(1 0 0);
181
+ --card: oklch(1 0 0);
182
+ --popover: oklch(1 0 0);
183
+ --sunken: oklch(0.975 0 0);
184
+ --chrome: oklch(0.97 0 0);
185
+ --muted: oklch(0.94 0 0);
186
+ --accent: oklch(0.92 0 0);
187
+ --foreground: oklch(0.1 0 0);
188
+ --muted-foreground: oklch(0.27 0.01 265);
189
+ --faint-foreground: oklch(0.33 0.01 265);
190
+ --border: oklch(0.45 0.01 265);
191
+ --border-strong: oklch(0.3 0.01 265);
192
+ --input: oklch(0.3 0.01 265);
193
+ --ring: oklch(0.4 0.2 262);
194
+ --primary: oklch(0.4 0.2 262);
195
+ --primary-foreground: oklch(1 0 0);
196
+ --primary-hover: oklch(0.33 0.18 262);
197
+ --accent-weak: oklch(0.93 0.035 262);
198
+ --accent-text: oklch(0.33 0.17 262);
199
+ --destructive: oklch(0.42 0.18 27);
200
+ --destructive-weak: oklch(0.962 0.024 27);
201
+ --destructive-text: oklch(0.36 0.15 27);
202
+ --on-destructive: oklch(1 0 0);
203
+ --warning: oklch(0.42 0.1 60);
204
+ --warning-weak: oklch(0.968 0.045 90);
205
+ --warning-text: oklch(0.34 0.08 60);
206
+ --success: oklch(0.38 0.1 155);
207
+ --success-weak: oklch(0.962 0.035 155);
208
+ --success-text: oklch(0.32 0.08 155);
209
+ --on-success: oklch(1 0 0);
210
+ --attention: oklch(0.38 0.18 300);
211
+ --attention-weak: oklch(0.962 0.03 300);
212
+ --attention-text: oklch(0.33 0.16 300);
213
+ --surface-agent: oklch(1 0 0);
214
+ --surface-user: oklch(0.93 0.03 262);
215
+ --text-provisional: oklch(0.36 0.09 60);
216
+ --series-1: #1c5cab;
217
+ --series-2: #b9461b;
218
+ --series-3: #0b7a5c;
219
+ --series-4: #946000;
220
+ --series-5: #a8325f;
221
+ --series-6: #006400;
222
+ --chart-1: var(--series-1);
223
+ --chart-2: var(--series-2);
224
+ --chart-3: var(--series-3);
225
+ --chart-4: var(--series-4);
226
+ --chart-5: var(--series-5);
227
+ }
228
+
229
+ /*
230
+ * Candor UI's theme: its roles, mapped onto shadcn's variables and Tailwind.
231
+ *
232
+ * Colours live in candor-theme.css, generated by scripts/theme.mjs after every
233
+ * text/ground pairing is checked for contrast in light, dark and high contrast
234
+ * (data-theme="light" | "dark" | "hc"; no attribute follows the system). Chart
235
+ * series are validated for colour-vision deficiency with the dataviz validator.
236
+ *
237
+ * To restyle, override the roles after this file: colours by their shadcn names
238
+ * (--primary, --background…), everything else by its --cd-* name. A brand theme
239
+ * is just such a file.
240
+ */
241
+ @custom-variant dark (&:where([data-theme="dark"], [data-theme="dark"] *));
242
+
243
+ :root {
244
+ --cd-font: "Inter Variable", system-ui, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
245
+ --cd-font-display: "Inter Variable", system-ui, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
246
+ --cd-font-mono: ui-monospace, "SF Mono", Menlo, Consolas, "Liberation Mono", monospace;
247
+
248
+ /* A dense app scale: body is 13px, comfortable body 14px. */
249
+ --cd-text-2xs: 0.6875rem;
250
+ --cd-text-xs: 0.75rem;
251
+ --cd-text-sm: 0.8125rem;
252
+ --cd-text-md: 0.875rem;
253
+ --cd-text-lg: 1rem;
254
+ --cd-text-xl: 1.25rem;
255
+ --cd-text-2xl: 1.5rem;
256
+ --cd-text-3xl: 1.75rem;
257
+ --cd-text-4xl: 2rem;
258
+ --cd-text-5xl: 2.5rem;
259
+ --cd-tracking-body: -0.011em;
260
+ --cd-weight-heading: 620;
261
+
262
+ --cd-radius-xs: 4px;
263
+ --cd-radius-sm: 5px;
264
+ --cd-radius-md: 7px;
265
+ --cd-radius-lg: 10px;
266
+ --cd-radius-xl: 12px;
267
+ --cd-radius-2xl: 16px;
268
+ --cd-radius-button: 8px;
269
+ --cd-radius-tile: 24px;
270
+
271
+ --cd-shadow: oklch(0.2 0.02 265 / 0.07);
272
+ --cd-elev-1: 0 1px 2px var(--cd-shadow);
273
+ --cd-elev-2: 0 1px 2px var(--cd-shadow), 0 2px 8px var(--cd-shadow);
274
+ --cd-elev-3: 0 12px 40px -12px oklch(0.2 0.02 265 / 0.16), 0 1px 2px var(--cd-shadow);
275
+ --cd-elev-4: 0 2px 4px var(--cd-shadow), 0 16px 40px oklch(0.2 0.02 265 / 0.14);
276
+
277
+ --cd-ease: cubic-bezier(0.2, 0, 0, 1);
278
+ --cd-ease-inout: cubic-bezier(0.4, 0, 0.2, 1);
279
+ --cd-ease-spring: linear(0, 0.4 15%, 0.7 30%, 1 50%, 0.95 65%, 1.02 80%, 1 100%);
280
+
281
+ --radius: var(--cd-radius-lg);
282
+
283
+ --sidebar: var(--chrome);
284
+ --sidebar-foreground: var(--foreground);
285
+ --sidebar-primary: var(--primary);
286
+ --sidebar-primary-foreground: var(--primary-foreground);
287
+ --sidebar-accent: var(--accent);
288
+ --sidebar-accent-foreground: var(--foreground);
289
+ --sidebar-border: var(--border);
290
+ --sidebar-ring: var(--ring);
291
+
292
+ --card-foreground: var(--foreground);
293
+ --popover-foreground: var(--foreground);
294
+ --secondary: var(--muted);
295
+ --secondary-foreground: var(--foreground);
296
+ --accent-foreground: var(--foreground);
297
+ }
298
+ [data-theme="dark"] {
299
+ --cd-shadow: oklch(0 0 0 / 0.35);
300
+ }
301
+ @media (prefers-color-scheme: dark) {
302
+ :root:not([data-theme]) {
303
+ --cd-shadow: oklch(0 0 0 / 0.35);
304
+ }
305
+ }
306
+
307
+ @theme inline {
308
+ --font-sans: var(--cd-font);
309
+ --font-display: var(--cd-font-display);
310
+ --font-mono: var(--cd-font-mono);
311
+
312
+ --text-2xs: var(--cd-text-2xs);
313
+ --text-2xs--line-height: 1rem;
314
+ --text-xs: var(--cd-text-xs);
315
+ --text-xs--line-height: 1rem;
316
+ --text-sm: var(--cd-text-sm);
317
+ --text-sm--line-height: 1.25rem;
318
+ --text-base: var(--cd-text-md);
319
+ --text-base--line-height: 1.375rem;
320
+ --text-lg: var(--cd-text-lg);
321
+ --text-lg--line-height: 1.5rem;
322
+ --text-xl: var(--cd-text-xl);
323
+ --text-xl--line-height: 1.75rem;
324
+ --text-2xl: var(--cd-text-2xl);
325
+ --text-2xl--line-height: 1.2;
326
+ --text-3xl: var(--cd-text-3xl);
327
+ --text-3xl--line-height: 1.15;
328
+ --text-4xl: var(--cd-text-4xl);
329
+ --text-4xl--line-height: 1.1;
330
+ --text-5xl: var(--cd-text-5xl);
331
+ --text-5xl--line-height: 1.05;
332
+
333
+ --color-background: var(--background);
334
+ --color-foreground: var(--foreground);
335
+ --color-card: var(--card);
336
+ --color-card-foreground: var(--card-foreground);
337
+ --color-popover: var(--popover);
338
+ --color-popover-foreground: var(--popover-foreground);
339
+ --color-muted: var(--muted);
340
+ --color-muted-foreground: var(--muted-foreground);
341
+ --color-faint-foreground: var(--faint-foreground);
342
+ --color-sunken: var(--sunken);
343
+ --color-chrome: var(--chrome);
344
+ --color-border: var(--border);
345
+ --color-border-strong: var(--border-strong);
346
+ --color-input: var(--input);
347
+ --color-ring: var(--ring);
348
+ --color-primary: var(--primary);
349
+ --color-primary-foreground: var(--primary-foreground);
350
+ --color-primary-hover: var(--primary-hover);
351
+ --color-secondary: var(--secondary);
352
+ --color-secondary-foreground: var(--secondary-foreground);
353
+ --color-accent: var(--accent);
354
+ --color-accent-foreground: var(--accent-foreground);
355
+ --color-accent-weak: var(--accent-weak);
356
+ --color-accent-text: var(--accent-text);
357
+ --color-destructive: var(--destructive);
358
+ --color-destructive-weak: var(--destructive-weak);
359
+ --color-destructive-text: var(--destructive-text);
360
+ --color-on-destructive: var(--on-destructive);
361
+ --color-on-success: var(--on-success);
362
+ --color-warning: var(--warning);
363
+ --color-warning-weak: var(--warning-weak);
364
+ --color-warning-text: var(--warning-text);
365
+ --color-success: var(--success);
366
+ --color-success-weak: var(--success-weak);
367
+ --color-success-text: var(--success-text);
368
+ --color-attention: var(--attention);
369
+ --color-attention-weak: var(--attention-weak);
370
+ --color-attention-text: var(--attention-text);
371
+ --color-surface-agent: var(--surface-agent);
372
+ --color-surface-user: var(--surface-user);
373
+ --color-provisional: var(--text-provisional);
374
+ --color-chart-1: var(--chart-1);
375
+ --color-chart-2: var(--chart-2);
376
+ --color-chart-3: var(--chart-3);
377
+ --color-chart-4: var(--chart-4);
378
+ --color-chart-5: var(--chart-5);
379
+ --color-sidebar: var(--sidebar);
380
+ --color-sidebar-foreground: var(--sidebar-foreground);
381
+ --color-sidebar-primary: var(--sidebar-primary);
382
+ --color-sidebar-primary-foreground: var(--sidebar-primary-foreground);
383
+ --color-sidebar-accent: var(--sidebar-accent);
384
+ --color-sidebar-accent-foreground: var(--sidebar-accent-foreground);
385
+ --color-sidebar-border: var(--sidebar-border);
386
+ --color-sidebar-ring: var(--sidebar-ring);
387
+
388
+ --radius-xs: var(--cd-radius-xs);
389
+ --radius-sm: var(--cd-radius-sm);
390
+ --radius-md: var(--cd-radius-md);
391
+ --radius-lg: var(--cd-radius-lg);
392
+ --radius-xl: var(--cd-radius-xl);
393
+ --radius-2xl: var(--cd-radius-2xl);
394
+ --radius-button: var(--cd-radius-button);
395
+ --radius-tile: var(--cd-radius-tile);
396
+
397
+ --shadow-xs: var(--cd-elev-1);
398
+ --shadow-sm: var(--cd-elev-1);
399
+ --shadow-raised: var(--cd-elev-2);
400
+ --shadow-float: var(--cd-elev-3);
401
+ --shadow-overlay: var(--cd-elev-4);
402
+
403
+ --ease-standard: var(--cd-ease);
404
+ --ease-inout: var(--cd-ease-inout);
405
+ --ease-spring: var(--cd-ease-spring);
406
+
407
+ --animate-shimmer: shimmer 2.2s linear infinite;
408
+ --animate-pulse-dot: pulse-dot 1.6s var(--cd-ease) infinite;
409
+ --animate-rise-in: rise-in 240ms var(--cd-ease) both;
410
+ --animate-caret: caret 1s steps(2, start) infinite;
411
+ }
412
+
413
+ @keyframes shimmer {
414
+ from { background-position: 200% 0; }
415
+ to { background-position: -200% 0; }
416
+ }
417
+ @keyframes pulse-dot {
418
+ 0%, 100% { box-shadow: 0 0 0 0 color-mix(in oklab, currentColor 45%, transparent); }
419
+ 70% { box-shadow: 0 0 0 5px transparent; }
420
+ }
421
+ @keyframes rise-in {
422
+ from { opacity: 0; transform: translateY(4px); }
423
+ to { opacity: 1; transform: none; }
424
+ }
425
+ @keyframes caret {
426
+ to { visibility: hidden; }
427
+ }
428
+
429
+ @media (prefers-reduced-motion: reduce) {
430
+ *, *::before, *::after {
431
+ animation-duration: 0.001ms !important;
432
+ animation-iteration-count: 1 !important;
433
+ transition-duration: 0.001ms !important;
434
+ scroll-behavior: auto !important;
435
+ }
436
+ }
437
+
438
+ @layer base {
439
+ * {
440
+ @apply border-border outline-ring/50;
441
+ }
442
+ body {
443
+ @apply bg-background text-foreground font-sans text-sm;
444
+ letter-spacing: var(--cd-tracking-body);
445
+ }
446
+ h1, h2, h3, h4 {
447
+ font-family: var(--cd-font-display);
448
+ font-variation-settings: "opsz" 32;
449
+ font-weight: var(--cd-weight-heading);
450
+ }
451
+ }
452
+
453
+ @utility shimmer-text {
454
+ background: linear-gradient(90deg, var(--muted-foreground) 0%, var(--muted-foreground) 40%, var(--foreground) 50%, var(--muted-foreground) 60%, var(--muted-foreground) 100%);
455
+ background-size: 200% 100%;
456
+ -webkit-background-clip: text;
457
+ background-clip: text;
458
+ color: transparent;
459
+ animation: var(--animate-shimmer);
460
+ }
@@ -0,0 +1,12 @@
1
+ import * as React from "react";
2
+ import { type VariantProps } from "class-variance-authority";
3
+ import { type RenderProp } from "../lib/render-prop.js";
4
+ declare const buttonVariants: (props?: ({
5
+ variant?: "outline" | "secondary" | "destructive" | "link" | "default" | "ghost" | null | undefined;
6
+ size?: "default" | "xs" | "sm" | "lg" | "icon" | "icon-xs" | "icon-sm" | "icon-lg" | null | undefined;
7
+ } & import("class-variance-authority/types").ClassProp) | undefined) => string;
8
+ declare function Button(allProps: React.ComponentProps<"button"> & VariantProps<typeof buttonVariants> & {
9
+ /** Render the child element (a link, say) with the button's styles instead of a <button>. */
10
+ asChild?: boolean;
11
+ } & RenderProp): React.JSX.Element;
12
+ export { Button, buttonVariants };
@@ -0,0 +1,41 @@
1
+ "use client";
2
+ import { jsx as _jsx } from "react/jsx-runtime";
3
+ import * as React from "react";
4
+ import { cva } from "class-variance-authority";
5
+ import { Slot } from "radix-ui";
6
+ import { withRender } from "../lib/render-prop.js";
7
+ import { cn } from "../lib/utils.js";
8
+ // The accent fills the one primary act, the radius is the theme's
9
+ // --cd-radius-button, and buttons press down slightly on :active.
10
+ const buttonVariants = cva("inline-flex shrink-0 items-center justify-center gap-2 rounded-button text-sm font-medium whitespace-nowrap outline-none select-none transition-[background-color,color,border-color,box-shadow,transform,opacity] duration-150 ease-standard active:scale-[0.98] focus-visible:ring-[3px] focus-visible:ring-ring/40 disabled:pointer-events-none disabled:opacity-45 data-[locked]:cursor-not-allowed data-[locked]:opacity-45 data-[locked]:active:scale-100 aria-invalid:ring-destructive/25 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4", {
11
+ variants: {
12
+ variant: {
13
+ default: "bg-primary text-primary-foreground hover:bg-primary-hover",
14
+ destructive: "bg-destructive text-on-destructive hover:bg-destructive/90 focus-visible:ring-destructive/25",
15
+ outline: "border border-input bg-card hover:bg-accent",
16
+ secondary: "bg-secondary text-secondary-foreground hover:bg-accent",
17
+ ghost: "text-muted-foreground hover:bg-accent hover:text-accent-foreground",
18
+ link: "text-accent-text underline-offset-4 hover:underline active:scale-100",
19
+ },
20
+ size: {
21
+ default: "h-8 px-3.5 has-[>svg]:px-3",
22
+ xs: "h-6 gap-1 px-2 text-xs has-[>svg]:px-1.5 [&_svg:not([class*='size-'])]:size-3",
23
+ sm: "h-7 gap-1.5 px-2.5 text-xs has-[>svg]:px-2 [&_svg:not([class*='size-'])]:size-3.5",
24
+ lg: "h-10 px-5 text-base has-[>svg]:px-4",
25
+ icon: "size-8",
26
+ "icon-xs": "size-6 [&_svg:not([class*='size-'])]:size-3",
27
+ "icon-sm": "size-7 [&_svg:not([class*='size-'])]:size-3.5",
28
+ "icon-lg": "size-10",
29
+ },
30
+ },
31
+ defaultVariants: {
32
+ variant: "default",
33
+ size: "default",
34
+ },
35
+ });
36
+ function Button(allProps) {
37
+ const { className, variant = "default", size = "default", asChild = false, ...props } = withRender(allProps);
38
+ const Comp = asChild ? Slot.Root : "button";
39
+ return (_jsx(Comp, { "data-slot": "button", "data-variant": variant, "data-size": size, className: cn(buttonVariants({ variant, size, className })), ...props }));
40
+ }
41
+ export { Button, buttonVariants };
@@ -0,0 +1,6 @@
1
+ import { Collapsible as CollapsiblePrimitive } from "radix-ui";
2
+ import { type RenderProp } from "../lib/render-prop.js";
3
+ declare function Collapsible({ ...props }: React.ComponentProps<typeof CollapsiblePrimitive.Root>): import("react").JSX.Element;
4
+ declare function CollapsibleTrigger(allProps: React.ComponentProps<typeof CollapsiblePrimitive.CollapsibleTrigger> & RenderProp): import("react").JSX.Element;
5
+ declare function CollapsibleContent({ ...props }: React.ComponentProps<typeof CollapsiblePrimitive.CollapsibleContent>): import("react").JSX.Element;
6
+ export { Collapsible, CollapsibleTrigger, CollapsibleContent };