@arbol-ai/ui 0.0.0-stage → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +9 -0
- package/LICENSE +21 -0
- package/README.md +98 -2
- package/dist/index.d.ts +217 -0
- package/dist/index.js +239 -0
- package/dist/index.js.map +1 -0
- package/dist/theme.css +533 -0
- package/package.json +118 -4
- package/skills/arbol-ui/references/i18n.md +41 -0
- package/skills/arbol-ui/references/setup.md +79 -0
package/dist/theme.css
ADDED
|
@@ -0,0 +1,533 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @arbol-ai/ui theme: the design tokens, base styles and Tailwind CSS v4 setup every component reads.
|
|
3
|
+
*
|
|
4
|
+
* Import it once, right after Tailwind, in the application's entry stylesheet:
|
|
5
|
+
*
|
|
6
|
+
* @import 'tailwindcss';
|
|
7
|
+
* @import '@arbol-ai/ui/theme.css';
|
|
8
|
+
*
|
|
9
|
+
* What it brings:
|
|
10
|
+
* - `@source`: Tailwind scans the library's own files, so the classes its components use are generated.
|
|
11
|
+
* - tw-animate-css's enter and exit animations, which the components play on React Aria's
|
|
12
|
+
* `data-entering` / `data-exiting` states.
|
|
13
|
+
* - Tokens as CSS variables on `:root`, remapped under `.dark` (dark mode is the `dark` class on an
|
|
14
|
+
* ancestor, usually `<html>`) and under `[data-theme='mono']` (the grayscale appearance; `brand`, the
|
|
15
|
+
* surgical teal, is the default). Tailwind exposes them as utilities through `@theme inline`:
|
|
16
|
+
* `bg-primary`, `text-muted-foreground`, `border-border`, `rounded-field`, `shadow-md`, `bg-gray-a2`…
|
|
17
|
+
*
|
|
18
|
+
* Fonts: the families are named, never shipped. Each stack tries the application's own faces first,
|
|
19
|
+
* then the brand's open faces (Schibsted Grotesk and Martian Mono, SIL Open Font License, which an app
|
|
20
|
+
* can load from Google Fonts or Fontsource), then the system's. Override `--ui-font-sans`,
|
|
21
|
+
* `--ui-font-heading` or `--ui-font-mono` to use other faces.
|
|
22
|
+
*/
|
|
23
|
+
@import 'tw-animate-css';
|
|
24
|
+
@source './';
|
|
25
|
+
|
|
26
|
+
@custom-variant dark (&:is(.dark *));
|
|
27
|
+
|
|
28
|
+
:root {
|
|
29
|
+
--ui-font-sans: 'Arbol Sans', 'Schibsted Grotesk', ui-sans-serif, system-ui, sans-serif;
|
|
30
|
+
--ui-font-heading:
|
|
31
|
+
'Arbol Sans SemiMono', 'Arbol Sans', 'Schibsted Grotesk', ui-sans-serif, system-ui, sans-serif;
|
|
32
|
+
--ui-font-mono: 'Arbol Sans Mono', 'Martian Mono', ui-monospace, monospace;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
@theme inline {
|
|
36
|
+
/* Fonts: the families are named, never shipped (see the header). */
|
|
37
|
+
--font-sans: var(--ui-font-sans);
|
|
38
|
+
--font-heading: var(--ui-font-heading);
|
|
39
|
+
--font-display: var(--ui-font-heading);
|
|
40
|
+
--font-mono: var(--ui-font-mono);
|
|
41
|
+
--font-serif: ui-serif, serif;
|
|
42
|
+
|
|
43
|
+
/* Elevation — the whole `shadow-*` scale routes through the tokens below
|
|
44
|
+
(:root / .dark), so depth is theme-aware like every color. Recipe: layered
|
|
45
|
+
single-digit-opacity stacks; from `md` up, a 1px hairline ring drawn from
|
|
46
|
+
the gray alpha ramp, which the dark theme re-points to low-alpha white —
|
|
47
|
+
the edge inverts with the theme for free. Rings stay OFF `xs`/`sm` on
|
|
48
|
+
purpose: those sit on filled controls (the primary button), where a gray
|
|
49
|
+
ring reads as a dirty edge. */
|
|
50
|
+
--shadow-2xs: var(--elevation-2xs);
|
|
51
|
+
--shadow-xs: var(--elevation-xs);
|
|
52
|
+
--shadow-sm: var(--elevation-sm);
|
|
53
|
+
--shadow-md: var(--elevation-md);
|
|
54
|
+
--shadow-lg: var(--elevation-lg);
|
|
55
|
+
--shadow-xl: var(--elevation-xl);
|
|
56
|
+
--shadow-2xl: var(--elevation-2xl);
|
|
57
|
+
|
|
58
|
+
/* Colors */
|
|
59
|
+
--color-background: var(--background);
|
|
60
|
+
--color-foreground: var(--foreground);
|
|
61
|
+
--color-card: var(--card);
|
|
62
|
+
--color-card-foreground: var(--card-foreground);
|
|
63
|
+
--color-popover: var(--popover);
|
|
64
|
+
--color-popover-foreground: var(--popover-foreground);
|
|
65
|
+
--color-primary: var(--primary);
|
|
66
|
+
--color-primary-foreground: var(--primary-foreground);
|
|
67
|
+
--color-secondary: var(--secondary);
|
|
68
|
+
--color-secondary-foreground: var(--secondary-foreground);
|
|
69
|
+
--color-muted: var(--muted);
|
|
70
|
+
--color-muted-foreground: var(--muted-foreground);
|
|
71
|
+
--color-accent: var(--accent);
|
|
72
|
+
--color-accent-foreground: var(--accent-foreground);
|
|
73
|
+
--color-destructive: var(--destructive);
|
|
74
|
+
--color-success: var(--success);
|
|
75
|
+
--color-warning: var(--warning);
|
|
76
|
+
--color-border: var(--border);
|
|
77
|
+
--color-input: var(--input);
|
|
78
|
+
--color-ring: var(--ring);
|
|
79
|
+
--color-info: var(--info);
|
|
80
|
+
--color-destructive-foreground: var(--destructive-foreground);
|
|
81
|
+
|
|
82
|
+
/* Status scales */
|
|
83
|
+
--color-red-3: var(--red-3);
|
|
84
|
+
--color-red-6: var(--red-6);
|
|
85
|
+
--color-red-9: var(--red-9);
|
|
86
|
+
--color-red-10: var(--red-10);
|
|
87
|
+
--color-red-11: var(--red-11);
|
|
88
|
+
--color-red-a2: var(--red-a2);
|
|
89
|
+
--color-red-a3: var(--red-a3);
|
|
90
|
+
--color-red-a4: var(--red-a4);
|
|
91
|
+
--color-green-3: var(--green-3);
|
|
92
|
+
--color-green-6: var(--green-6);
|
|
93
|
+
--color-green-9: var(--green-9);
|
|
94
|
+
--color-green-10: var(--green-10);
|
|
95
|
+
--color-green-11: var(--green-11);
|
|
96
|
+
--color-green-a2: var(--green-a2);
|
|
97
|
+
--color-green-a3: var(--green-a3);
|
|
98
|
+
--color-green-a4: var(--green-a4);
|
|
99
|
+
--color-amber-3: var(--amber-3);
|
|
100
|
+
--color-amber-6: var(--amber-6);
|
|
101
|
+
--color-amber-9: var(--amber-9);
|
|
102
|
+
--color-amber-10: var(--amber-10);
|
|
103
|
+
--color-amber-11: var(--amber-11);
|
|
104
|
+
--color-amber-a2: var(--amber-a2);
|
|
105
|
+
--color-amber-a3: var(--amber-a3);
|
|
106
|
+
--color-amber-a4: var(--amber-a4);
|
|
107
|
+
--color-blue-3: var(--blue-3);
|
|
108
|
+
--color-blue-6: var(--blue-6);
|
|
109
|
+
--color-blue-9: var(--blue-9);
|
|
110
|
+
--color-blue-10: var(--blue-10);
|
|
111
|
+
--color-blue-11: var(--blue-11);
|
|
112
|
+
--color-blue-a2: var(--blue-a2);
|
|
113
|
+
--color-blue-a3: var(--blue-a3);
|
|
114
|
+
--color-blue-a4: var(--blue-a4);
|
|
115
|
+
|
|
116
|
+
/* Gray scale */
|
|
117
|
+
--color-gray-1: var(--gray-1);
|
|
118
|
+
--color-gray-2: var(--gray-2);
|
|
119
|
+
--color-gray-3: var(--gray-3);
|
|
120
|
+
--color-gray-4: var(--gray-4);
|
|
121
|
+
--color-gray-5: var(--gray-5);
|
|
122
|
+
--color-gray-6: var(--gray-6);
|
|
123
|
+
--color-gray-7: var(--gray-7);
|
|
124
|
+
--color-gray-8: var(--gray-8);
|
|
125
|
+
--color-gray-9: var(--gray-9);
|
|
126
|
+
--color-gray-10: var(--gray-10);
|
|
127
|
+
--color-gray-11: var(--gray-11);
|
|
128
|
+
--color-gray-12: var(--gray-12);
|
|
129
|
+
|
|
130
|
+
/* Gray alpha */
|
|
131
|
+
--color-gray-a1: var(--gray-a1);
|
|
132
|
+
--color-gray-a2: var(--gray-a2);
|
|
133
|
+
--color-gray-a3: var(--gray-a3);
|
|
134
|
+
--color-gray-a4: var(--gray-a4);
|
|
135
|
+
--color-gray-a5: var(--gray-a5);
|
|
136
|
+
--color-gray-a6: var(--gray-a6);
|
|
137
|
+
--color-gray-a7: var(--gray-a7);
|
|
138
|
+
--color-gray-a8: var(--gray-a8);
|
|
139
|
+
--color-gray-a9: var(--gray-a9);
|
|
140
|
+
--color-gray-a10: var(--gray-a10);
|
|
141
|
+
|
|
142
|
+
/* Brand semantic surfaces — theme-aware (see :root / .dark) */
|
|
143
|
+
--color-brand-tint: var(--brand-tint);
|
|
144
|
+
--color-brand-hairline: var(--brand-hairline);
|
|
145
|
+
--color-brand-accent: var(--brand-accent);
|
|
146
|
+
|
|
147
|
+
/* Charts */
|
|
148
|
+
--color-chart-1: var(--chart-1);
|
|
149
|
+
--color-chart-2: var(--chart-2);
|
|
150
|
+
--color-chart-3: var(--chart-3);
|
|
151
|
+
--color-chart-4: var(--chart-4);
|
|
152
|
+
--color-chart-5: var(--chart-5);
|
|
153
|
+
|
|
154
|
+
/* Chart — semantic outcome tokens */
|
|
155
|
+
--color-chart-positive: var(--chart-positive);
|
|
156
|
+
--color-chart-negative: var(--chart-negative);
|
|
157
|
+
--color-chart-caution: var(--chart-caution);
|
|
158
|
+
--color-chart-neutral: var(--chart-neutral);
|
|
159
|
+
|
|
160
|
+
/* Radius */
|
|
161
|
+
--radius: 0.625rem;
|
|
162
|
+
--radius-sm: calc(var(--radius) - 4px);
|
|
163
|
+
--radius-md: calc(var(--radius) - 2px);
|
|
164
|
+
--radius-lg: var(--radius);
|
|
165
|
+
--radius-xl: calc(var(--radius) + 4px);
|
|
166
|
+
--radius-2xl: calc(var(--radius) + 8px);
|
|
167
|
+
--radius-3xl: calc(var(--radius) + 14px);
|
|
168
|
+
|
|
169
|
+
/* Semantic radius (themeable) */
|
|
170
|
+
--radius-field: var(--radius-field);
|
|
171
|
+
--radius-menu: var(--radius-menu);
|
|
172
|
+
--radius-card: var(--radius-card);
|
|
173
|
+
--radius-dialog: var(--radius-dialog);
|
|
174
|
+
|
|
175
|
+
/* Typography */
|
|
176
|
+
--text-2xs: 0.6875rem;
|
|
177
|
+
--text-2xs--line-height: 1rem;
|
|
178
|
+
--text-3xs: 0.625rem;
|
|
179
|
+
--text-3xs--line-height: 0.875rem;
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
:root {
|
|
183
|
+
--background: #ffffff;
|
|
184
|
+
--foreground: #1c1d1e;
|
|
185
|
+
|
|
186
|
+
/* Elevation (see the @theme mapping). Light: soft layered umbra, hairline
|
|
187
|
+
ring from the gray alpha ramp on overlay sizes only. */
|
|
188
|
+
--elevation-2xs: 0 1px 2px rgba(0, 0, 0, 0.04);
|
|
189
|
+
--elevation-xs: 0 1px 2px rgba(0, 0, 0, 0.05), 0 2px 4px rgba(0, 0, 0, 0.03);
|
|
190
|
+
--elevation-sm:
|
|
191
|
+
0 1px 2px rgba(0, 0, 0, 0.05), 0 2px 6px rgba(0, 0, 0, 0.04), 0 4px 12px rgba(0, 0, 0, 0.03);
|
|
192
|
+
--elevation-md:
|
|
193
|
+
0 0 0 1px var(--gray-a2), 0 2px 4px rgba(0, 0, 0, 0.05), 0 6px 14px rgba(0, 0, 0, 0.05),
|
|
194
|
+
0 12px 28px rgba(0, 0, 0, 0.04);
|
|
195
|
+
--elevation-lg:
|
|
196
|
+
0 0 0 1px var(--gray-a3), 0 4px 8px rgba(0, 0, 0, 0.05), 0 10px 22px rgba(0, 0, 0, 0.06),
|
|
197
|
+
0 20px 44px rgba(0, 0, 0, 0.07);
|
|
198
|
+
--elevation-xl:
|
|
199
|
+
0 0 0 1px var(--gray-a3), 0 8px 16px rgba(0, 0, 0, 0.06), 0 16px 36px rgba(0, 0, 0, 0.08),
|
|
200
|
+
0 28px 64px rgba(0, 0, 0, 0.09);
|
|
201
|
+
--elevation-2xl:
|
|
202
|
+
0 0 0 1px var(--gray-a3), 0 12px 24px rgba(0, 0, 0, 0.08), 0 24px 56px rgba(0, 0, 0, 0.11),
|
|
203
|
+
0 40px 96px rgba(0, 0, 0, 0.12);
|
|
204
|
+
|
|
205
|
+
/* Gray scale */
|
|
206
|
+
--gray-1: #ffffff;
|
|
207
|
+
--gray-2: #f5f5f5;
|
|
208
|
+
--gray-3: #e6e6e6;
|
|
209
|
+
--gray-4: #d4d4d4;
|
|
210
|
+
--gray-5: #a3a3a3;
|
|
211
|
+
--gray-6: #656a6e;
|
|
212
|
+
--gray-7: #525252;
|
|
213
|
+
--gray-8: #4c5154;
|
|
214
|
+
--gray-9: #343739;
|
|
215
|
+
--gray-10: #26282a;
|
|
216
|
+
--gray-11: #1c1d1e;
|
|
217
|
+
--gray-12: #000000;
|
|
218
|
+
|
|
219
|
+
/* Gray alpha */
|
|
220
|
+
--gray-a1: rgba(0, 0, 0, 0.05);
|
|
221
|
+
--gray-a2: rgba(0, 0, 0, 0.08);
|
|
222
|
+
--gray-a3: rgba(0, 0, 0, 0.15);
|
|
223
|
+
--gray-a4: rgba(0, 0, 0, 0.35);
|
|
224
|
+
--gray-a5: rgba(0, 0, 0, 0.4);
|
|
225
|
+
--gray-a6: rgba(0, 0, 0, 0.5);
|
|
226
|
+
--gray-a7: rgba(0, 0, 0, 0.6);
|
|
227
|
+
--gray-a8: rgba(0, 0, 0, 0.7);
|
|
228
|
+
--gray-a9: rgba(0, 0, 0, 0.8);
|
|
229
|
+
--gray-a10: rgba(0, 0, 0, 0.95);
|
|
230
|
+
|
|
231
|
+
/* Status scales (theme-independent) */
|
|
232
|
+
--red-3: #fee2e2;
|
|
233
|
+
--red-6: #fca5a5;
|
|
234
|
+
--red-9: #ef4444;
|
|
235
|
+
--red-10: #dc2626;
|
|
236
|
+
--red-11: #b91c1c;
|
|
237
|
+
--green-3: #dcfce7;
|
|
238
|
+
--green-6: #86efac;
|
|
239
|
+
--green-9: #22c55e;
|
|
240
|
+
--green-10: #16a34a;
|
|
241
|
+
--green-11: #15803d;
|
|
242
|
+
--amber-3: #fef3c7;
|
|
243
|
+
--amber-6: #fcd34d;
|
|
244
|
+
--amber-9: #f59e0b;
|
|
245
|
+
--amber-10: #d97706;
|
|
246
|
+
--amber-11: #b45309;
|
|
247
|
+
--blue-3: #dbeafe;
|
|
248
|
+
--blue-6: #93c5fd;
|
|
249
|
+
--blue-9: #3b82f6;
|
|
250
|
+
--blue-10: #2563eb;
|
|
251
|
+
--blue-11: #1d4ed8;
|
|
252
|
+
--red-a2: rgba(239, 68, 68, 0.08);
|
|
253
|
+
--red-a3: rgba(239, 68, 68, 0.15);
|
|
254
|
+
--red-a4: rgba(239, 68, 68, 0.25);
|
|
255
|
+
--green-a2: rgba(34, 197, 94, 0.08);
|
|
256
|
+
--green-a3: rgba(34, 197, 94, 0.15);
|
|
257
|
+
--green-a4: rgba(34, 197, 94, 0.25);
|
|
258
|
+
--amber-a2: rgba(245, 158, 11, 0.08);
|
|
259
|
+
--amber-a3: rgba(245, 158, 11, 0.15);
|
|
260
|
+
--amber-a4: rgba(245, 158, 11, 0.25);
|
|
261
|
+
--blue-a2: rgba(59, 130, 246, 0.08);
|
|
262
|
+
--blue-a3: rgba(59, 130, 246, 0.15);
|
|
263
|
+
--blue-a4: rgba(59, 130, 246, 0.25);
|
|
264
|
+
|
|
265
|
+
/* Semantic radius */
|
|
266
|
+
--radius-field: 0.875rem;
|
|
267
|
+
--radius-menu: 1.125rem;
|
|
268
|
+
--radius-card: 1.125rem;
|
|
269
|
+
--radius-dialog: 1.5rem;
|
|
270
|
+
|
|
271
|
+
/* Brand semantic surfaces (light) */
|
|
272
|
+
--brand-tint: #f2faf8;
|
|
273
|
+
--brand-hairline: #ddf0ea;
|
|
274
|
+
--brand-accent: #0b6d61;
|
|
275
|
+
|
|
276
|
+
/* Semantic colors */
|
|
277
|
+
--card: #ffffff;
|
|
278
|
+
--card-foreground: #1c1d1e;
|
|
279
|
+
--popover: #ffffff;
|
|
280
|
+
--popover-foreground: #1c1d1e;
|
|
281
|
+
--primary: #0d8273;
|
|
282
|
+
--primary-foreground: #ffffff;
|
|
283
|
+
--secondary: #e6e6e6;
|
|
284
|
+
--secondary-foreground: #1c1d1e;
|
|
285
|
+
--muted: #f5f5f5;
|
|
286
|
+
--muted-foreground: #656a6e;
|
|
287
|
+
--accent: var(--gray-a2);
|
|
288
|
+
--accent-foreground: var(--foreground);
|
|
289
|
+
/* Solid red that carries white text at WCAG AA (4.8:1) in both modes; red text uses red-11. */
|
|
290
|
+
--destructive: #dc2626;
|
|
291
|
+
--destructive-foreground: #ffffff;
|
|
292
|
+
--success: var(--green-9);
|
|
293
|
+
--warning: var(--amber-9);
|
|
294
|
+
--info: var(--blue-9);
|
|
295
|
+
--border: var(--gray-a3);
|
|
296
|
+
--input: var(--gray-a3);
|
|
297
|
+
--ring: #14a08c;
|
|
298
|
+
|
|
299
|
+
/* Charts — categorical (brand-aligned) */
|
|
300
|
+
--chart-1: #14a08c;
|
|
301
|
+
--chart-2: #3b82f6;
|
|
302
|
+
--chart-3: #f59e0b;
|
|
303
|
+
--chart-4: #8b5cf6;
|
|
304
|
+
--chart-5: #ef4444;
|
|
305
|
+
|
|
306
|
+
/* Charts — semantic outcome (derived from status scales) */
|
|
307
|
+
--chart-positive: var(--green-10);
|
|
308
|
+
--chart-negative: var(--red-10);
|
|
309
|
+
--chart-caution: var(--amber-10);
|
|
310
|
+
--chart-neutral: var(--gray-6);
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
.dark {
|
|
314
|
+
--background: #1c1d1e;
|
|
315
|
+
--foreground: #f5f5f5;
|
|
316
|
+
|
|
317
|
+
/* Elevation. Dark: black gains depth while the ring — the same gray alpha
|
|
318
|
+
vars, now low-alpha white — becomes the edge that separates a floating
|
|
319
|
+
surface from the surface behind it. */
|
|
320
|
+
--elevation-2xs: 0 1px 2px rgba(0, 0, 0, 0.3);
|
|
321
|
+
--elevation-xs: 0 1px 2px rgba(0, 0, 0, 0.32), 0 2px 4px rgba(0, 0, 0, 0.24);
|
|
322
|
+
--elevation-sm:
|
|
323
|
+
0 1px 2px rgba(0, 0, 0, 0.34), 0 2px 6px rgba(0, 0, 0, 0.28), 0 4px 12px rgba(0, 0, 0, 0.22);
|
|
324
|
+
--elevation-md:
|
|
325
|
+
0 0 0 1px var(--gray-a3), 0 2px 4px rgba(0, 0, 0, 0.34), 0 6px 14px rgba(0, 0, 0, 0.3),
|
|
326
|
+
0 12px 28px rgba(0, 0, 0, 0.26);
|
|
327
|
+
--elevation-lg:
|
|
328
|
+
0 0 0 1px var(--gray-a3), 0 4px 8px rgba(0, 0, 0, 0.36), 0 10px 22px rgba(0, 0, 0, 0.32),
|
|
329
|
+
0 20px 44px rgba(0, 0, 0, 0.3);
|
|
330
|
+
--elevation-xl:
|
|
331
|
+
0 0 0 1px var(--gray-a4), 0 8px 16px rgba(0, 0, 0, 0.38), 0 16px 36px rgba(0, 0, 0, 0.36),
|
|
332
|
+
0 28px 64px rgba(0, 0, 0, 0.34);
|
|
333
|
+
--elevation-2xl:
|
|
334
|
+
0 0 0 1px var(--gray-a4), 0 12px 24px rgba(0, 0, 0, 0.42), 0 24px 56px rgba(0, 0, 0, 0.44),
|
|
335
|
+
0 40px 96px rgba(0, 0, 0, 0.46);
|
|
336
|
+
|
|
337
|
+
/* Gray scale */
|
|
338
|
+
--gray-1: #1c1d1e;
|
|
339
|
+
--gray-2: #262829;
|
|
340
|
+
--gray-3: #343739;
|
|
341
|
+
--gray-4: #4c5154;
|
|
342
|
+
--gray-5: #656a6e;
|
|
343
|
+
--gray-6: #8b9095;
|
|
344
|
+
--gray-7: #a3a8ad;
|
|
345
|
+
--gray-8: #c4c8cc;
|
|
346
|
+
--gray-9: #e6e6e6;
|
|
347
|
+
--gray-10: #f5f5f5;
|
|
348
|
+
--gray-11: #fafafa;
|
|
349
|
+
--gray-12: #ffffff;
|
|
350
|
+
|
|
351
|
+
/* Gray alpha */
|
|
352
|
+
--gray-a1: rgba(255, 255, 255, 0.03);
|
|
353
|
+
--gray-a2: rgba(255, 255, 255, 0.06);
|
|
354
|
+
--gray-a3: rgba(255, 255, 255, 0.1);
|
|
355
|
+
--gray-a4: rgba(255, 255, 255, 0.15);
|
|
356
|
+
--gray-a5: rgba(255, 255, 255, 0.2);
|
|
357
|
+
--gray-a6: rgba(255, 255, 255, 0.3);
|
|
358
|
+
--gray-a7: rgba(255, 255, 255, 0.4);
|
|
359
|
+
--gray-a8: rgba(255, 255, 255, 0.55);
|
|
360
|
+
--gray-a9: rgba(255, 255, 255, 0.7);
|
|
361
|
+
--gray-a10: rgba(255, 255, 255, 0.9);
|
|
362
|
+
|
|
363
|
+
/* Status scale overrides (dark) */
|
|
364
|
+
--red-3: var(--red-a3);
|
|
365
|
+
--red-6: rgba(239, 68, 68, 0.35);
|
|
366
|
+
--red-10: #f87171;
|
|
367
|
+
--red-11: #fca5a5;
|
|
368
|
+
--green-3: var(--green-a3);
|
|
369
|
+
--green-6: rgba(34, 197, 94, 0.35);
|
|
370
|
+
--green-10: #4ade80;
|
|
371
|
+
--green-11: #86efac;
|
|
372
|
+
--amber-3: var(--amber-a3);
|
|
373
|
+
--amber-6: rgba(245, 158, 11, 0.35);
|
|
374
|
+
--amber-10: #fbbf24;
|
|
375
|
+
--amber-11: #fcd34d;
|
|
376
|
+
--blue-3: var(--blue-a3);
|
|
377
|
+
--blue-6: rgba(59, 130, 246, 0.35);
|
|
378
|
+
--blue-10: #60a5fa;
|
|
379
|
+
--blue-11: #93c5fd;
|
|
380
|
+
|
|
381
|
+
/* Brand semantic surfaces (dark) */
|
|
382
|
+
--brand-tint: rgba(76, 189, 167, 0.08);
|
|
383
|
+
--brand-hairline: rgba(76, 189, 167, 0.2);
|
|
384
|
+
--brand-accent: #82d5c4;
|
|
385
|
+
|
|
386
|
+
/* Semantic colors */
|
|
387
|
+
--card: #1c1d1e;
|
|
388
|
+
--card-foreground: #f5f5f5;
|
|
389
|
+
--popover: #262829;
|
|
390
|
+
--popover-foreground: #f5f5f5;
|
|
391
|
+
--primary: #4cbda7;
|
|
392
|
+
--primary-foreground: #052b26;
|
|
393
|
+
--secondary: #343739;
|
|
394
|
+
--secondary-foreground: #f5f5f5;
|
|
395
|
+
--muted: #262829;
|
|
396
|
+
--muted-foreground: #8b9095;
|
|
397
|
+
--accent: var(--gray-a2);
|
|
398
|
+
--accent-foreground: var(--foreground);
|
|
399
|
+
--destructive: #dc2626;
|
|
400
|
+
--destructive-foreground: #ffffff;
|
|
401
|
+
--success: var(--green-9);
|
|
402
|
+
--warning: var(--amber-9);
|
|
403
|
+
--info: var(--blue-9);
|
|
404
|
+
--border: var(--gray-a3);
|
|
405
|
+
--input: var(--gray-a3);
|
|
406
|
+
--ring: rgba(76, 189, 167, 0.5);
|
|
407
|
+
|
|
408
|
+
/* Charts — categorical (brand-aligned) */
|
|
409
|
+
--chart-1: #4cbda7;
|
|
410
|
+
--chart-2: #60a5fa;
|
|
411
|
+
--chart-3: #fbbf24;
|
|
412
|
+
--chart-4: #a78bfa;
|
|
413
|
+
--chart-5: #f87171;
|
|
414
|
+
|
|
415
|
+
color-scheme: dark;
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
/*
|
|
419
|
+
* Appearances: `brand` (surgical teal, the default the tokens above already carry) and `mono` (grayscale).
|
|
420
|
+
* Set `data-theme` on <html>. The selectors include `:root`/`.dark` so they outrank the base blocks.
|
|
421
|
+
*/
|
|
422
|
+
:root[data-theme='brand'] {
|
|
423
|
+
--primary: #0d8273;
|
|
424
|
+
--primary-foreground: #ffffff;
|
|
425
|
+
--ring: #14a08c;
|
|
426
|
+
--brand-tint: #f2faf8;
|
|
427
|
+
--brand-hairline: #ddf0ea;
|
|
428
|
+
--brand-accent: #0b6d61;
|
|
429
|
+
--chart-1: #14a08c;
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
.dark[data-theme='brand'] {
|
|
433
|
+
--primary: #4cbda7;
|
|
434
|
+
--primary-foreground: #052b26;
|
|
435
|
+
--ring: rgba(76, 189, 167, 0.5);
|
|
436
|
+
/* Without these the light tint wins over `.dark`: white rows, invisible text. */
|
|
437
|
+
--brand-tint: rgba(76, 189, 167, 0.08);
|
|
438
|
+
--brand-hairline: rgba(76, 189, 167, 0.2);
|
|
439
|
+
--brand-accent: #82d5c4;
|
|
440
|
+
--chart-1: #4cbda7;
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
:root[data-theme='mono'] {
|
|
444
|
+
--primary: #1c1d1e;
|
|
445
|
+
--primary-foreground: #ffffff;
|
|
446
|
+
--ring: rgba(0, 0, 0, 0.35);
|
|
447
|
+
--brand-tint: var(--gray-a1);
|
|
448
|
+
--brand-hairline: var(--gray-a3);
|
|
449
|
+
--brand-accent: var(--gray-11);
|
|
450
|
+
--chart-1: #52525b;
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
.dark[data-theme='mono'] {
|
|
454
|
+
--primary: #f5f5f5;
|
|
455
|
+
--primary-foreground: #1c1d1e;
|
|
456
|
+
--ring: rgba(255, 255, 255, 0.3);
|
|
457
|
+
--brand-accent: var(--gray-11);
|
|
458
|
+
--chart-1: #a1a1aa;
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
@layer base {
|
|
462
|
+
* {
|
|
463
|
+
@apply border-border outline-ring/50;
|
|
464
|
+
}
|
|
465
|
+
body {
|
|
466
|
+
@apply bg-background text-foreground min-h-dvh;
|
|
467
|
+
}
|
|
468
|
+
html {
|
|
469
|
+
text-rendering: optimizelegibility;
|
|
470
|
+
}
|
|
471
|
+
input::placeholder,
|
|
472
|
+
textarea::placeholder {
|
|
473
|
+
@apply text-muted-foreground;
|
|
474
|
+
}
|
|
475
|
+
/* Everything that acts like a button reads like one. React Aria renders
|
|
476
|
+
options/menu items/tabs as non-button elements, so role selectors carry
|
|
477
|
+
the same promise there. */
|
|
478
|
+
button:not(:disabled),
|
|
479
|
+
[role='button']:not(:disabled),
|
|
480
|
+
[role='option']:not([aria-disabled='true']),
|
|
481
|
+
[role='menuitem']:not([aria-disabled='true']),
|
|
482
|
+
[role='menuitemcheckbox']:not([aria-disabled='true']),
|
|
483
|
+
[role='menuitemradio']:not([aria-disabled='true']),
|
|
484
|
+
[role='tab']:not([aria-disabled='true']),
|
|
485
|
+
[role='radio']:not([aria-disabled='true']),
|
|
486
|
+
[role='checkbox']:not([aria-disabled='true']) {
|
|
487
|
+
@apply cursor-pointer;
|
|
488
|
+
}
|
|
489
|
+
}
|
|
490
|
+
|
|
491
|
+
@utility scrollable {
|
|
492
|
+
scrollbar-color: var(--color-gray-a6) transparent;
|
|
493
|
+
scrollbar-width: thin;
|
|
494
|
+
|
|
495
|
+
&::-webkit-scrollbar {
|
|
496
|
+
width: 10px;
|
|
497
|
+
height: 10px;
|
|
498
|
+
}
|
|
499
|
+
|
|
500
|
+
&::-webkit-scrollbar-track {
|
|
501
|
+
background: transparent;
|
|
502
|
+
}
|
|
503
|
+
|
|
504
|
+
&::-webkit-scrollbar-thumb {
|
|
505
|
+
background-color: var(--color-gray-a6);
|
|
506
|
+
background-clip: content-box;
|
|
507
|
+
border: 2px solid transparent;
|
|
508
|
+
border-radius: 9999px;
|
|
509
|
+
}
|
|
510
|
+
|
|
511
|
+
&::-webkit-scrollbar-thumb:hover {
|
|
512
|
+
background-color: var(--color-gray-a8);
|
|
513
|
+
}
|
|
514
|
+
}
|
|
515
|
+
|
|
516
|
+
/*
|
|
517
|
+
* A control smaller than a fingertip keeps its look, but on a touch screen it takes taps across at
|
|
518
|
+
* least 44 × 44 px (WCAG 2.5.5). The area is drawn from the control, so the control must be positioned
|
|
519
|
+
* (`relative`); a box larger than 44 px keeps its own size.
|
|
520
|
+
*/
|
|
521
|
+
@utility touch-target {
|
|
522
|
+
@media (pointer: coarse) {
|
|
523
|
+
&::after {
|
|
524
|
+
position: absolute;
|
|
525
|
+
top: 50%;
|
|
526
|
+
left: 50%;
|
|
527
|
+
width: max(100%, 2.75rem);
|
|
528
|
+
height: max(100%, 2.75rem);
|
|
529
|
+
content: '';
|
|
530
|
+
translate: -50% -50%;
|
|
531
|
+
}
|
|
532
|
+
}
|
|
533
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,120 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@arbol-ai/ui",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"
|
|
5
|
-
"
|
|
6
|
-
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Arbol's React component library: accessible React Aria Components styled with Tailwind CSS v4, localized in Spanish and English, for building dashboards fast.",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"accessibility",
|
|
7
|
+
"components",
|
|
8
|
+
"dashboard",
|
|
9
|
+
"design-system",
|
|
10
|
+
"i18n",
|
|
11
|
+
"react",
|
|
12
|
+
"react-aria",
|
|
13
|
+
"react-aria-components",
|
|
14
|
+
"tailwindcss",
|
|
15
|
+
"ui"
|
|
16
|
+
],
|
|
17
|
+
"homepage": "https://github.com/getarbol/project-arbol-ui#readme",
|
|
18
|
+
"bugs": {
|
|
19
|
+
"url": "https://github.com/getarbol/project-arbol-ui/issues"
|
|
20
|
+
},
|
|
21
|
+
"license": "MIT",
|
|
22
|
+
"author": "Arbol",
|
|
23
|
+
"repository": {
|
|
24
|
+
"type": "git",
|
|
25
|
+
"url": "git+https://github.com/getarbol/project-arbol-ui.git"
|
|
26
|
+
},
|
|
27
|
+
"files": [
|
|
28
|
+
"dist",
|
|
29
|
+
"skills",
|
|
30
|
+
"README.md",
|
|
31
|
+
"CHANGELOG.md",
|
|
32
|
+
"LICENSE"
|
|
33
|
+
],
|
|
34
|
+
"type": "module",
|
|
35
|
+
"sideEffects": [
|
|
36
|
+
"**/*.css"
|
|
37
|
+
],
|
|
38
|
+
"exports": {
|
|
39
|
+
".": {
|
|
40
|
+
"types": "./dist/index.d.ts",
|
|
41
|
+
"import": "./dist/index.js"
|
|
42
|
+
},
|
|
43
|
+
"./theme.css": "./dist/theme.css",
|
|
44
|
+
"./package.json": "./package.json"
|
|
45
|
+
},
|
|
46
|
+
"scripts": {
|
|
47
|
+
"dev": "vp dev site",
|
|
48
|
+
"build": "vp pack",
|
|
49
|
+
"site:build": "vp build site",
|
|
50
|
+
"typecheck": "tsc -p tsconfig.json && tsc -p tsconfig.node.json",
|
|
51
|
+
"check": "vp check",
|
|
52
|
+
"fix": "vp check --fix",
|
|
53
|
+
"test": "vp test run",
|
|
54
|
+
"test:coverage": "vp test run --coverage",
|
|
55
|
+
"verify": "vp run typecheck && vp check && vp pack && vp build site && vp run verify:package",
|
|
56
|
+
"verify:package": "publint --strict && attw --pack . --profile esm-only --exclude-entrypoints ./theme.css",
|
|
57
|
+
"prepare": "vp config"
|
|
58
|
+
},
|
|
59
|
+
"dependencies": {
|
|
60
|
+
"@internationalized/date": "^3.12.4",
|
|
61
|
+
"@phosphor-icons/react": "^2.1.10",
|
|
62
|
+
"@tanstack/react-table": "^9.3.1",
|
|
63
|
+
"class-variance-authority": "^0.7.1",
|
|
64
|
+
"clsx": "^2.1.1",
|
|
65
|
+
"tailwind-merge": "^3.7.0",
|
|
66
|
+
"tw-animate-css": "^1.4.0"
|
|
67
|
+
},
|
|
68
|
+
"devDependencies": {
|
|
69
|
+
"@arethetypeswrong/cli": "0.18.5",
|
|
70
|
+
"@tailwindcss/vite": "4.3.5",
|
|
71
|
+
"@tanstack/react-form": "1.33.5",
|
|
72
|
+
"@types/node": "26.6.5",
|
|
73
|
+
"@types/react": "19.3.0",
|
|
74
|
+
"@types/react-dom": "19.3.0",
|
|
75
|
+
"@vitejs/plugin-react": "6.2.1",
|
|
76
|
+
"@vitest/browser-playwright": "5.1.0",
|
|
77
|
+
"@vitest/coverage-istanbul": "5.1.0",
|
|
78
|
+
"axe-core": "4.14.0",
|
|
79
|
+
"echarts": "6.1.0",
|
|
80
|
+
"playwright": "1.65.0",
|
|
81
|
+
"publint": "0.3.25",
|
|
82
|
+
"react": "19.3.1",
|
|
83
|
+
"react-aria": "3.53.1",
|
|
84
|
+
"react-aria-components": "1.22.1",
|
|
85
|
+
"react-dom": "19.3.1",
|
|
86
|
+
"tailwindcss": "4.3.5",
|
|
87
|
+
"typescript": "7.0.2",
|
|
88
|
+
"ultracite": "8.1.1",
|
|
89
|
+
"vite": "npm:@voidzero-dev/vite-plus-core@1.5.0",
|
|
90
|
+
"vite-plus": "1.5.0",
|
|
91
|
+
"vitest": "5.1.0",
|
|
92
|
+
"vitest-browser-react": "2.3.0",
|
|
93
|
+
"wrangler": "4.158.0"
|
|
94
|
+
},
|
|
95
|
+
"peerDependencies": {
|
|
96
|
+
"@tanstack/react-form": "^1.30.0",
|
|
97
|
+
"echarts": "^6.0.0",
|
|
98
|
+
"react": "^19.0.0",
|
|
99
|
+
"react-aria": "^3.52.0",
|
|
100
|
+
"react-aria-components": "^1.21.0",
|
|
101
|
+
"react-dom": "^19.0.0",
|
|
102
|
+
"tailwindcss": "^4.1.0"
|
|
103
|
+
},
|
|
104
|
+
"peerDependenciesMeta": {
|
|
105
|
+
"echarts": {
|
|
106
|
+
"optional": true
|
|
107
|
+
},
|
|
108
|
+
"@tanstack/react-form": {
|
|
109
|
+
"optional": true
|
|
110
|
+
}
|
|
111
|
+
},
|
|
112
|
+
"overrides": {
|
|
113
|
+
"vite": "npm:@voidzero-dev/vite-plus-core@1.5.0",
|
|
114
|
+
"vitest": "5.1.0"
|
|
115
|
+
},
|
|
116
|
+
"engines": {
|
|
117
|
+
"node": ">=22.18"
|
|
118
|
+
},
|
|
119
|
+
"packageManager": "bun@1.4.4"
|
|
120
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
# Text and languages
|
|
2
|
+
|
|
3
|
+
There are exactly two kinds of text on a screen built with @arbol-ai/ui.
|
|
4
|
+
|
|
5
|
+
## App copy: always yours
|
|
6
|
+
|
|
7
|
+
Titles, labels, descriptions, column headers, button labels, empty-state sentences, item names: pass them
|
|
8
|
+
through props and children, already translated by the app's own system (Paraglide's `m.*()`, i18next's
|
|
9
|
+
`t()`, or plain Spanish). The library never defaults app copy.
|
|
10
|
+
|
|
11
|
+
```tsx
|
|
12
|
+
<PageHeader>
|
|
13
|
+
<PageTitle>{m.contacts_title()}</PageTitle>
|
|
14
|
+
</PageHeader>
|
|
15
|
+
<SearchField aria-label={m.contacts_search()} placeholder={m.contacts_searchPlaceholder()} />
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
## Library strings: built in, Spanish and English
|
|
19
|
+
|
|
20
|
+
What a component says by itself (a close button's name, "Previous page", "1–15 of 120", "No results",
|
|
21
|
+
screen-reader instructions, "Copied") ships in English (`en-US`) and Latin American Spanish (`es-419`), and
|
|
22
|
+
follows `UIProvider locale`: any `es-*` locale reads Spanish, everything else English. Numbers inside them
|
|
23
|
+
are formatted for the locale (`1.234` in `es-CO`).
|
|
24
|
+
|
|
25
|
+
Replace any of them, in whichever locale is active, with `UIProvider messages`. Values are strings or
|
|
26
|
+
functions of the message's variables, so Paraglide functions plug in directly:
|
|
27
|
+
|
|
28
|
+
```tsx
|
|
29
|
+
<UIProvider locale={locale} messages={{ 'overlay.close': m.ui_close, 'pagination.range': m.ui_pagination_range }}>
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
Variables keep the names Arbol's catalogs use: `first`, `last`, `total`, `count`, `page`, `label`,
|
|
33
|
+
`value`. Many components also take a prop for a single instance (`closeLabel`, `clearLabel`).
|
|
34
|
+
|
|
35
|
+
## Dates, times and numbers
|
|
36
|
+
|
|
37
|
+
Components format with React Aria and `@internationalized/date` in the provider's locale. Spanish
|
|
38
|
+
conventions differ by region (`es-CO`: 12-hour clock, weeks start on Sunday; `es`: 24-hour, Monday): pick
|
|
39
|
+
the locale tag deliberately, and pass `firstDayOfWeek` / `hourCycle` to the date components when the
|
|
40
|
+
product needs another convention. Pass numbers as numbers and dates as `CalendarDate`/`ZonedDateTime`
|
|
41
|
+
values, never pre-formatted strings, so plural rules and formats stay correct.
|