@treeui/mcp 0.6.0 → 0.8.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/README.md +1 -1
- package/dist/{chunk-ITEC3SEF.js → chunk-CEDY3OJ4.js} +6549 -2933
- package/dist/cli.cjs +6549 -2933
- package/dist/cli.js +1 -1
- package/dist/index.cjs +6967 -3011
- package/dist/index.d.cts +7 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.js +419 -79
- package/package.json +20 -1
package/dist/index.d.cts
CHANGED
|
@@ -106,6 +106,13 @@ interface TreeuiTokenEntry {
|
|
|
106
106
|
description?: string;
|
|
107
107
|
/** Per-theme values for tokens that change with `[data-tree-theme]`. */
|
|
108
108
|
themeValues?: Record<string, string>;
|
|
109
|
+
/**
|
|
110
|
+
* True for interaction states the library computes from the semantic layer
|
|
111
|
+
* (hover, press, selected, disabled). They are real, emitted variables an
|
|
112
|
+
* agent may read, but a product must not theme against them — and they rank
|
|
113
|
+
* below the semantic tokens in search so they cannot bury the answer.
|
|
114
|
+
*/
|
|
115
|
+
derived?: boolean;
|
|
109
116
|
}
|
|
110
117
|
interface TreeuiCatalog {
|
|
111
118
|
generatedAt: string;
|
package/dist/index.d.ts
CHANGED
|
@@ -106,6 +106,13 @@ interface TreeuiTokenEntry {
|
|
|
106
106
|
description?: string;
|
|
107
107
|
/** Per-theme values for tokens that change with `[data-tree-theme]`. */
|
|
108
108
|
themeValues?: Record<string, string>;
|
|
109
|
+
/**
|
|
110
|
+
* True for interaction states the library computes from the semantic layer
|
|
111
|
+
* (hover, press, selected, disabled). They are real, emitted variables an
|
|
112
|
+
* agent may read, but a product must not theme against them — and they rank
|
|
113
|
+
* below the semantic tokens in search so they cannot bury the answer.
|
|
114
|
+
*/
|
|
115
|
+
derived?: boolean;
|
|
109
116
|
}
|
|
110
117
|
interface TreeuiCatalog {
|
|
111
118
|
generatedAt: string;
|
package/dist/index.js
CHANGED
|
@@ -11,14 +11,168 @@ import {
|
|
|
11
11
|
searchComponents,
|
|
12
12
|
searchRecipes,
|
|
13
13
|
searchTokens
|
|
14
|
-
} from "./chunk-
|
|
14
|
+
} from "./chunk-CEDY3OJ4.js";
|
|
15
15
|
|
|
16
16
|
// src/catalog-source.ts
|
|
17
17
|
import fs from "fs";
|
|
18
18
|
import path from "path";
|
|
19
19
|
import { parseAllDocuments } from "yaml";
|
|
20
20
|
|
|
21
|
+
// ../tokens/src/primitives.ts
|
|
22
|
+
var treePrimitives = {
|
|
23
|
+
white: "#ffffff",
|
|
24
|
+
black: "#000000",
|
|
25
|
+
/**
|
|
26
|
+
* Neutral ramp. Carries both themes: 0-300 are light-mode surfaces and
|
|
27
|
+
* borders, 700-950 are dark-mode surfaces, and the 400-600 middle is where
|
|
28
|
+
* borders and muted text land in whichever theme needs that luminance.
|
|
29
|
+
*/
|
|
30
|
+
gray: {
|
|
31
|
+
0: "#ffffff",
|
|
32
|
+
50: "#f6f8fa",
|
|
33
|
+
100: "#eff2f5",
|
|
34
|
+
200: "#d0d7de",
|
|
35
|
+
300: "#afb8c1",
|
|
36
|
+
/** Clears 3:1 on every light surface, including the subtle one — control edges. */
|
|
37
|
+
400: "#858c93",
|
|
38
|
+
/** Its dark-mode counterpart, 3:1 on every dark surface. */
|
|
39
|
+
500: "#737c88",
|
|
40
|
+
600: "#59636e",
|
|
41
|
+
650: "#576270",
|
|
42
|
+
700: "#444c56",
|
|
43
|
+
800: "#2d333b",
|
|
44
|
+
850: "#22272e",
|
|
45
|
+
900: "#1c2128",
|
|
46
|
+
950: "#0d1117",
|
|
47
|
+
/** Ink. Not gray-1000: it carries a blue cast, which is why it is named. */
|
|
48
|
+
ink: "#1f2328",
|
|
49
|
+
/** Muted ink for dark surfaces. */
|
|
50
|
+
inkDark: "#adbac7",
|
|
51
|
+
inkDarkMuted: "#95a3b2"
|
|
52
|
+
},
|
|
53
|
+
blue: {
|
|
54
|
+
50: "#ddf4ff",
|
|
55
|
+
300: "#6cb6ff",
|
|
56
|
+
400: "#559cf5",
|
|
57
|
+
450: "#6cabf7",
|
|
58
|
+
500: "#0969da",
|
|
59
|
+
600: "#0550ae",
|
|
60
|
+
800: "#1a3453",
|
|
61
|
+
900: "#0a1a2f"
|
|
62
|
+
},
|
|
63
|
+
/**
|
|
64
|
+
* Secondary accent ramp. Seeded from `#8957e5` and stepped until the mid tone
|
|
65
|
+
* reads as text on its own tint in both themes — see `DECISIONS.md`.
|
|
66
|
+
*/
|
|
67
|
+
purple: {
|
|
68
|
+
50: "#efeaf9",
|
|
69
|
+
300: "#ba9df0",
|
|
70
|
+
400: "#ad8bed",
|
|
71
|
+
500: "#794dcb",
|
|
72
|
+
600: "#633fa6",
|
|
73
|
+
800: "#332e4a"
|
|
74
|
+
},
|
|
75
|
+
green: {
|
|
76
|
+
400: "#59ac5c",
|
|
77
|
+
500: "#1a7f37"
|
|
78
|
+
},
|
|
79
|
+
amber: {
|
|
80
|
+
400: "#c69026",
|
|
81
|
+
500: "#956400"
|
|
82
|
+
},
|
|
83
|
+
red: {
|
|
84
|
+
/** Landed on 4.50:1 against the dark subtle band; nudged for headroom. */
|
|
85
|
+
400: "#f5766e",
|
|
86
|
+
500: "#d1242f"
|
|
87
|
+
},
|
|
88
|
+
/**
|
|
89
|
+
* Categorical data-viz hues. Deliberately not a ramp — these are eight
|
|
90
|
+
* distinct hues chosen for separation under the three common CVD types, each
|
|
91
|
+
* held at >= 3:1 against its own theme's surface so a mark is visible without
|
|
92
|
+
* relying on the legend. Assign in order.
|
|
93
|
+
*/
|
|
94
|
+
dataviz: {
|
|
95
|
+
light: {
|
|
96
|
+
1: "#2a78d6",
|
|
97
|
+
// 2, 3 and 7 were #1baf7a / #eda100 / #e87ba4, measuring 2.82, 2.17 and
|
|
98
|
+
// 2.69 against the light surface — a mark you cannot see is not a
|
|
99
|
+
// category. Darkened along the same hue until each clears 3:1.
|
|
100
|
+
2: "#12855c",
|
|
101
|
+
3: "#8a6100",
|
|
102
|
+
4: "#008300",
|
|
103
|
+
5: "#4a3aa7",
|
|
104
|
+
6: "#e34948",
|
|
105
|
+
7: "#c4587f",
|
|
106
|
+
8: "#eb6834"
|
|
107
|
+
},
|
|
108
|
+
dark: {
|
|
109
|
+
1: "#3987e5",
|
|
110
|
+
2: "#199e70",
|
|
111
|
+
3: "#c98500",
|
|
112
|
+
4: "#008300",
|
|
113
|
+
5: "#9085e9",
|
|
114
|
+
6: "#e66767",
|
|
115
|
+
7: "#d55181",
|
|
116
|
+
8: "#d95926"
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
};
|
|
120
|
+
var treeAlpha = {
|
|
121
|
+
/** Modal and drawer scrim. */
|
|
122
|
+
overlay: { light: 0.5, dark: 0.6 },
|
|
123
|
+
/** Focus ring, over the brand colour. */
|
|
124
|
+
focusRing: 0.32
|
|
125
|
+
};
|
|
126
|
+
|
|
127
|
+
// ../tokens/src/color.ts
|
|
128
|
+
var clampChannel = (value) => Math.min(255, Math.max(0, Math.round(value)));
|
|
129
|
+
var expandShortHex = (hex) => hex.length === 4 ? `#${hex[1]}${hex[1]}${hex[2]}${hex[2]}${hex[3]}${hex[3]}` : hex;
|
|
130
|
+
var parseHex = (value) => {
|
|
131
|
+
const hex = expandShortHex(value.trim());
|
|
132
|
+
const match = /^#([0-9a-fA-F]{6})$/.exec(hex);
|
|
133
|
+
if (!match) {
|
|
134
|
+
throw new Error(`Invalid hex color: "${value}"`);
|
|
135
|
+
}
|
|
136
|
+
const int = Number.parseInt(match[1], 16);
|
|
137
|
+
return {
|
|
138
|
+
r: int >> 16 & 255,
|
|
139
|
+
g: int >> 8 & 255,
|
|
140
|
+
b: int & 255
|
|
141
|
+
};
|
|
142
|
+
};
|
|
143
|
+
var formatHex = ({ r, g, b }) => {
|
|
144
|
+
const toPart = (channel) => clampChannel(channel).toString(16).padStart(2, "0");
|
|
145
|
+
return `#${toPart(r)}${toPart(g)}${toPart(b)}`;
|
|
146
|
+
};
|
|
147
|
+
var mixColors = (a, b, weight) => {
|
|
148
|
+
const t = Math.min(1, Math.max(0, weight));
|
|
149
|
+
return {
|
|
150
|
+
r: a.r + (b.r - a.r) * t,
|
|
151
|
+
g: a.g + (b.g - a.g) * t,
|
|
152
|
+
b: a.b + (b.b - a.b) * t
|
|
153
|
+
};
|
|
154
|
+
};
|
|
155
|
+
var BLACK = { r: 0, g: 0, b: 0 };
|
|
156
|
+
var WHITE = { r: 255, g: 255, b: 255 };
|
|
157
|
+
var darken = (color, amount) => mixColors(color, BLACK, amount);
|
|
158
|
+
var lighten = (color, amount) => mixColors(color, WHITE, amount);
|
|
159
|
+
var channelLuminance = (value) => {
|
|
160
|
+
const channel = value / 255;
|
|
161
|
+
return channel <= 0.03928 ? channel / 12.92 : ((channel + 0.055) / 1.055) ** 2.4;
|
|
162
|
+
};
|
|
163
|
+
var relativeLuminance = ({ r, g, b }) => 0.2126 * channelLuminance(r) + 0.7152 * channelLuminance(g) + 0.0722 * channelLuminance(b);
|
|
164
|
+
var contrastRatio = (a, b) => {
|
|
165
|
+
const luminanceA = relativeLuminance(a);
|
|
166
|
+
const luminanceB = relativeLuminance(b);
|
|
167
|
+
const lighter = Math.max(luminanceA, luminanceB);
|
|
168
|
+
const darker = Math.min(luminanceA, luminanceB);
|
|
169
|
+
return (lighter + 0.05) / (darker + 0.05);
|
|
170
|
+
};
|
|
171
|
+
var bestContrast = (color, candidates) => contrastRatio(color, candidates[0]) >= contrastRatio(color, candidates[1]) ? candidates[0] : candidates[1];
|
|
172
|
+
var withAlpha = ({ r, g, b }, alpha2) => `rgba(${clampChannel(r)}, ${clampChannel(g)}, ${clampChannel(b)}, ${alpha2})`;
|
|
173
|
+
|
|
21
174
|
// ../tokens/src/tokens.ts
|
|
175
|
+
var alpha = (color, amount) => withAlpha(parseHex(color), amount);
|
|
22
176
|
var treeTokens = {
|
|
23
177
|
font: {
|
|
24
178
|
family: {
|
|
@@ -32,7 +186,11 @@ var treeTokens = {
|
|
|
32
186
|
base: "0.9375rem",
|
|
33
187
|
lg: "1.125rem",
|
|
34
188
|
xl: "1.375rem",
|
|
35
|
-
|
|
189
|
+
// `2xl` used to repeat `xl` verbatim, which made every
|
|
190
|
+
// `clamp(xl … 2xl)` a constant and left a hole between 1.375 and 1.75rem.
|
|
191
|
+
// It now fills that hole; `xl` is unchanged, since it is the more used of
|
|
192
|
+
// the two. `tokens.test.ts` keeps the scale strictly increasing.
|
|
193
|
+
"2xl": "1.5rem",
|
|
36
194
|
"3xl": "1.75rem",
|
|
37
195
|
"4xl": "2.25rem",
|
|
38
196
|
"5xl": "3rem"
|
|
@@ -52,6 +210,11 @@ var treeTokens = {
|
|
|
52
210
|
base: "1.5",
|
|
53
211
|
body: "1.6",
|
|
54
212
|
relaxed: "1.65"
|
|
213
|
+
},
|
|
214
|
+
tracking: {
|
|
215
|
+
tight: "-0.02em",
|
|
216
|
+
normal: "0em",
|
|
217
|
+
wide: "0.08em"
|
|
55
218
|
}
|
|
56
219
|
},
|
|
57
220
|
space: {
|
|
@@ -72,10 +235,23 @@ var treeTokens = {
|
|
|
72
235
|
lg: "0.875rem",
|
|
73
236
|
pill: "999px"
|
|
74
237
|
},
|
|
238
|
+
// Elevation. The geometry is theme-independent and lives here; the *colour*
|
|
239
|
+
// comes from `--tree-color-shadow-rgb`, which the theme sets — a slate shadow
|
|
240
|
+
// was being emitted on `:root` and reused verbatim on the dark surface, where
|
|
241
|
+
// a near-black umbra is what actually reads.
|
|
75
242
|
shadow: {
|
|
76
|
-
xs: "0 1px 2px rgba(
|
|
77
|
-
sm: "0 6px 18px rgba(
|
|
78
|
-
md: "0 14px 34px rgba(
|
|
243
|
+
xs: "0 1px 2px rgba(var(--tree-color-shadow-rgb), 0.06)",
|
|
244
|
+
sm: "0 6px 18px rgba(var(--tree-color-shadow-rgb), 0.08)",
|
|
245
|
+
md: "0 14px 34px rgba(var(--tree-color-shadow-rgb), 0.12)",
|
|
246
|
+
// Marketing-scale elevation: a large, soft lift for a hero card or a banded
|
|
247
|
+
// section, where `md` reads flat. Same neutral shadow colour as the smaller
|
|
248
|
+
// steps, so the whole scale stays one family.
|
|
249
|
+
lg: "0 24px 48px -24px rgba(var(--tree-color-shadow-rgb), 0.22)",
|
|
250
|
+
xl: "0 40px 80px -32px rgba(var(--tree-color-shadow-rgb), 0.28)",
|
|
251
|
+
// Elevation tinted by whatever accent is in scope (see `--tree-color-accent-*`
|
|
252
|
+
// and the `accent` prop on TSection/THero/TPageSurface), so a surface's glow
|
|
253
|
+
// follows its accent instead of being written by hand per landing page.
|
|
254
|
+
accent: "0 24px 48px -32px color-mix(in srgb, var(--tree-color-accent-primary) 60%, transparent)"
|
|
79
255
|
},
|
|
80
256
|
// Brand gradient for high-emphasis surfaces (e.g. the primary CTA).
|
|
81
257
|
// References the theme brand vars so it follows light/dark automatically;
|
|
@@ -89,6 +265,15 @@ var treeTokens = {
|
|
|
89
265
|
strong: "1.5px"
|
|
90
266
|
}
|
|
91
267
|
},
|
|
268
|
+
/**
|
|
269
|
+
* Opacity for the parts of a disabled control that carry no text — an icon,
|
|
270
|
+
* a thumbnail, a toolbar. Anywhere a label sits on a surface, disabled is a
|
|
271
|
+
* colour instead (`--tree-color-state-disabled-*`), because opacity cannot be
|
|
272
|
+
* measured for contrast. This replaces eight different hand-picked values.
|
|
273
|
+
*/
|
|
274
|
+
opacity: {
|
|
275
|
+
disabled: "0.5"
|
|
276
|
+
},
|
|
92
277
|
motion: {
|
|
93
278
|
duration: {
|
|
94
279
|
fast: "100ms",
|
|
@@ -153,95 +338,233 @@ var treeThemes = {
|
|
|
153
338
|
light: {
|
|
154
339
|
color: {
|
|
155
340
|
bg: {
|
|
156
|
-
primary:
|
|
157
|
-
surface:
|
|
158
|
-
subtle:
|
|
341
|
+
primary: treePrimitives.gray[50],
|
|
342
|
+
surface: treePrimitives.gray[0],
|
|
343
|
+
subtle: treePrimitives.gray[100]
|
|
159
344
|
},
|
|
160
345
|
border: {
|
|
161
|
-
default:
|
|
162
|
-
strong:
|
|
346
|
+
default: treePrimitives.gray[200],
|
|
347
|
+
strong: treePrimitives.gray[300]
|
|
348
|
+
// `border.interactive` is deliberately absent: WCAG 1.4.11 asks for 3:1
|
|
349
|
+
// on the boundary that *identifies* a control, and `default` measures
|
|
350
|
+
// 1.45:1 here — fine for a card edge, not fine for the only thing
|
|
351
|
+
// telling a user where an input is. The library derives a passing value
|
|
352
|
+
// from `strong` (see states.ts); a product may set one, and it is
|
|
353
|
+
// validated the same way.
|
|
163
354
|
},
|
|
164
355
|
text: {
|
|
165
|
-
primary:
|
|
166
|
-
muted:
|
|
167
|
-
inverse:
|
|
356
|
+
primary: treePrimitives.gray.ink,
|
|
357
|
+
muted: treePrimitives.gray[600],
|
|
358
|
+
inverse: treePrimitives.gray[0]
|
|
168
359
|
},
|
|
360
|
+
/** Umbra as an `r, g, b` triple so the elevation scale can vary alpha. */
|
|
361
|
+
"shadow-rgb": "15, 23, 42",
|
|
169
362
|
brand: {
|
|
170
|
-
primary:
|
|
171
|
-
hover:
|
|
172
|
-
soft:
|
|
173
|
-
contrast:
|
|
363
|
+
primary: treePrimitives.blue[500],
|
|
364
|
+
hover: treePrimitives.blue[600],
|
|
365
|
+
soft: treePrimitives.blue[50],
|
|
366
|
+
contrast: treePrimitives.gray[0]
|
|
367
|
+
},
|
|
368
|
+
// Secondary brand accent — a closed axis, never a free colour. It is what
|
|
369
|
+
// `TTag tone="accent"` paints with, and the default value of the surface
|
|
370
|
+
// `accent` axis (TSection/THero/TPageSurface), which remaps these four
|
|
371
|
+
// variables when a product wants a status hue instead. Derived with
|
|
372
|
+
// `deriveBrandRamp` from #8957e5 so the accent stays legible as text on
|
|
373
|
+
// its own soft tint (measured 4.77:1) and on every background.
|
|
374
|
+
accent: {
|
|
375
|
+
primary: treePrimitives.purple[500],
|
|
376
|
+
hover: treePrimitives.purple[600],
|
|
377
|
+
soft: treePrimitives.purple[50],
|
|
378
|
+
contrast: treePrimitives.gray[0]
|
|
174
379
|
},
|
|
175
380
|
status: {
|
|
176
|
-
success:
|
|
177
|
-
warning:
|
|
178
|
-
error:
|
|
179
|
-
info:
|
|
381
|
+
success: treePrimitives.green[500],
|
|
382
|
+
warning: treePrimitives.amber[500],
|
|
383
|
+
error: treePrimitives.red[500],
|
|
384
|
+
info: treePrimitives.blue[500]
|
|
180
385
|
},
|
|
181
386
|
// Categorical data-viz palette. Fixed hue order (blue → orange), validated
|
|
182
387
|
// for CVD separation and contrast against the light surface. Assign in order;
|
|
183
388
|
// the components cycle after 8 as a fallback, but prefer folding a 9th+
|
|
184
389
|
// category into "Other".
|
|
185
|
-
chart:
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
3: "#eda100",
|
|
189
|
-
4: "#008300",
|
|
190
|
-
5: "#4a3aa7",
|
|
191
|
-
6: "#e34948",
|
|
192
|
-
7: "#e87ba4",
|
|
193
|
-
8: "#eb6834"
|
|
194
|
-
},
|
|
195
|
-
overlay: "rgba(31, 35, 40, 0.5)",
|
|
196
|
-
"focus-ring": "rgba(9, 105, 218, 0.32)"
|
|
390
|
+
chart: treePrimitives.dataviz.light,
|
|
391
|
+
overlay: alpha(treePrimitives.gray.ink, treeAlpha.overlay.light),
|
|
392
|
+
"focus-ring": alpha(treePrimitives.blue[500], treeAlpha.focusRing)
|
|
197
393
|
}
|
|
198
394
|
},
|
|
199
395
|
dark: {
|
|
200
396
|
color: {
|
|
201
397
|
bg: {
|
|
202
|
-
primary:
|
|
203
|
-
surface:
|
|
204
|
-
subtle:
|
|
398
|
+
primary: treePrimitives.gray[900],
|
|
399
|
+
surface: treePrimitives.gray[850],
|
|
400
|
+
subtle: treePrimitives.gray[800]
|
|
205
401
|
},
|
|
206
402
|
border: {
|
|
207
|
-
default:
|
|
208
|
-
strong:
|
|
403
|
+
default: treePrimitives.gray[700],
|
|
404
|
+
strong: treePrimitives.gray[650]
|
|
209
405
|
},
|
|
210
406
|
text: {
|
|
211
|
-
primary:
|
|
212
|
-
muted:
|
|
213
|
-
inverse:
|
|
407
|
+
primary: treePrimitives.gray.inkDark,
|
|
408
|
+
muted: treePrimitives.gray.inkDarkMuted,
|
|
409
|
+
inverse: treePrimitives.gray[900]
|
|
214
410
|
},
|
|
411
|
+
/** Near-black umbra: a slate shadow is invisible on a dark surface. */
|
|
412
|
+
"shadow-rgb": "0, 0, 0",
|
|
215
413
|
brand: {
|
|
216
|
-
primary:
|
|
217
|
-
hover:
|
|
218
|
-
soft:
|
|
219
|
-
contrast:
|
|
414
|
+
primary: treePrimitives.blue[400],
|
|
415
|
+
hover: treePrimitives.blue[450],
|
|
416
|
+
soft: treePrimitives.blue[800],
|
|
417
|
+
contrast: treePrimitives.blue[900]
|
|
418
|
+
},
|
|
419
|
+
// Dark pair of the secondary accent (same #8957e5 seed, stepped for the
|
|
420
|
+
// dark surface). Measured 5.93:1 on bg-primary, 4.67:1 on bg-subtle and
|
|
421
|
+
// 4.72:1 on its own soft tint — AA on every background, and above what
|
|
422
|
+
// the dark brand pair itself clears. `accent.test.ts` holds that bar.
|
|
423
|
+
accent: {
|
|
424
|
+
primary: treePrimitives.purple[400],
|
|
425
|
+
hover: treePrimitives.purple[300],
|
|
426
|
+
soft: treePrimitives.purple[800],
|
|
427
|
+
contrast: treePrimitives.gray[900]
|
|
220
428
|
},
|
|
221
429
|
status: {
|
|
222
|
-
success:
|
|
223
|
-
warning:
|
|
224
|
-
error:
|
|
225
|
-
info:
|
|
430
|
+
success: treePrimitives.green[400],
|
|
431
|
+
warning: treePrimitives.amber[400],
|
|
432
|
+
error: treePrimitives.red[400],
|
|
433
|
+
info: treePrimitives.blue[300]
|
|
226
434
|
},
|
|
227
435
|
// Same hue order stepped for the dark surface (not a separate palette) —
|
|
228
436
|
// each step re-validated for the dark band and >= 3:1 on the dark surface.
|
|
229
|
-
chart:
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
3: "#c98500",
|
|
233
|
-
4: "#008300",
|
|
234
|
-
5: "#9085e9",
|
|
235
|
-
6: "#e66767",
|
|
236
|
-
7: "#d55181",
|
|
237
|
-
8: "#d95926"
|
|
238
|
-
},
|
|
239
|
-
overlay: "rgba(13, 17, 23, 0.6)",
|
|
240
|
-
"focus-ring": "rgba(83, 155, 245, 0.32)"
|
|
437
|
+
chart: treePrimitives.dataviz.dark,
|
|
438
|
+
overlay: alpha(treePrimitives.gray[950], treeAlpha.overlay.dark),
|
|
439
|
+
"focus-ring": alpha(treePrimitives.blue[400], treeAlpha.focusRing)
|
|
241
440
|
}
|
|
242
441
|
}
|
|
243
442
|
};
|
|
244
443
|
|
|
444
|
+
// ../tokens/src/states.ts
|
|
445
|
+
var AA_UI = 3;
|
|
446
|
+
var AA_TEXT = 4.5;
|
|
447
|
+
var WHITE2 = { r: 255, g: 255, b: 255 };
|
|
448
|
+
var BLACK2 = { r: 0, g: 0, b: 0 };
|
|
449
|
+
var STEP = {
|
|
450
|
+
hover: 0.18,
|
|
451
|
+
press: 0.32,
|
|
452
|
+
/** Tint states move toward the solid colour instead of toward black/white. */
|
|
453
|
+
softHover: 0.14,
|
|
454
|
+
softPress: 0.26,
|
|
455
|
+
/** Neutral row/menu surfaces, as a fraction of the ink mixed into the surface. */
|
|
456
|
+
neutralHover: 0.06,
|
|
457
|
+
neutralPress: 0.12
|
|
458
|
+
};
|
|
459
|
+
var DEGENERATE = 1.12;
|
|
460
|
+
var step = (color, amount, mode) => {
|
|
461
|
+
const preferred = mode === "light" ? darken(color, amount) : lighten(color, amount);
|
|
462
|
+
if (contrastRatio(preferred, color) >= DEGENERATE) return preferred;
|
|
463
|
+
const flipped = mode === "light" ? lighten(color, amount) : darken(color, amount);
|
|
464
|
+
return contrastRatio(flipped, color) > contrastRatio(preferred, color) ? flipped : preferred;
|
|
465
|
+
};
|
|
466
|
+
var fadeToward = (from, to, against, minRatio) => {
|
|
467
|
+
let best = from;
|
|
468
|
+
for (let amount = 0.05; amount <= 0.9; amount += 0.05) {
|
|
469
|
+
const candidate = mixColors(from, to, amount);
|
|
470
|
+
if (contrastRatio(candidate, against) < minRatio) break;
|
|
471
|
+
best = candidate;
|
|
472
|
+
}
|
|
473
|
+
return best;
|
|
474
|
+
};
|
|
475
|
+
var quantize = (color) => parseHex(formatHex(color));
|
|
476
|
+
var untilLegible = (color, against, minRatio) => {
|
|
477
|
+
if (contrastRatio(color, against) >= minRatio) return color;
|
|
478
|
+
const goLighter = relativeLuminance(color) >= relativeLuminance(against);
|
|
479
|
+
let candidate = color;
|
|
480
|
+
for (let i = 0; i < 24; i += 1) {
|
|
481
|
+
candidate = goLighter ? lighten(candidate, 0.05) : darken(candidate, 0.05);
|
|
482
|
+
if (contrastRatio(candidate, against) >= minRatio) return candidate;
|
|
483
|
+
}
|
|
484
|
+
return bestContrast(against, [WHITE2, BLACK2]);
|
|
485
|
+
};
|
|
486
|
+
var STATUS_KEYS = ["success", "warning", "error", "info"];
|
|
487
|
+
var deriveStateColors = (color, mode) => {
|
|
488
|
+
const surface = parseHex(color.bg.surface);
|
|
489
|
+
const subtle = parseHex(color.bg.subtle);
|
|
490
|
+
const ink = parseHex(color.text.primary);
|
|
491
|
+
const muted = parseHex(color.text.muted);
|
|
492
|
+
const inverse = parseHex(color.text.inverse);
|
|
493
|
+
const familyStates = (primary, soft) => {
|
|
494
|
+
const base = parseHex(primary);
|
|
495
|
+
const tint = parseHex(soft);
|
|
496
|
+
const softHover = quantize(mixColors(tint, base, STEP.softHover));
|
|
497
|
+
const softPress = quantize(mixColors(tint, base, STEP.softPress));
|
|
498
|
+
return {
|
|
499
|
+
press: formatHex(step(base, STEP.press, mode)),
|
|
500
|
+
"soft-hover": formatHex(softHover),
|
|
501
|
+
"soft-press": formatHex(softPress),
|
|
502
|
+
"on-soft": formatHex(untilLegible(base, tint, AA_TEXT)),
|
|
503
|
+
"on-soft-hover": formatHex(untilLegible(base, softHover, AA_TEXT)),
|
|
504
|
+
"on-soft-press": formatHex(untilLegible(base, softPress, AA_TEXT))
|
|
505
|
+
};
|
|
506
|
+
};
|
|
507
|
+
const brand = familyStates(color.brand.primary, color.brand.soft);
|
|
508
|
+
const accent = familyStates(color.accent.primary, color.accent.soft);
|
|
509
|
+
const status = Object.fromEntries(
|
|
510
|
+
STATUS_KEYS.flatMap((key) => {
|
|
511
|
+
const base = parseHex(color.status[key]);
|
|
512
|
+
const tint = quantize(mixColors(surface, base, 0.14));
|
|
513
|
+
const softHover = quantize(mixColors(tint, base, STEP.softHover));
|
|
514
|
+
return [
|
|
515
|
+
[`${key}-hover`, formatHex(step(base, STEP.hover, mode))],
|
|
516
|
+
[`${key}-press`, formatHex(step(base, STEP.press, mode))],
|
|
517
|
+
[`${key}-soft`, formatHex(tint)],
|
|
518
|
+
[`${key}-soft-hover`, formatHex(softHover)],
|
|
519
|
+
/**
|
|
520
|
+
* The alert's edge. Mixing the neutral border toward the status by a
|
|
521
|
+
* fixed 36% — the recipe the stylesheet used inline — produced a
|
|
522
|
+
* 1.8:1 edge on the tint, i.e. an edge nobody could see. Derived from
|
|
523
|
+
* the status colour instead, softened as far as 3:1 allows.
|
|
524
|
+
*/
|
|
525
|
+
[`${key}-border`, formatHex(quantize(fadeToward(base, tint, tint, AA_UI)))],
|
|
526
|
+
[`${key}-contrast`, formatHex(bestContrast(base, [WHITE2, inverse]))],
|
|
527
|
+
// The status colour as ink on its own tint — soft alerts and badges.
|
|
528
|
+
[`${key}-on-soft`, formatHex(untilLegible(base, tint, AA_TEXT))],
|
|
529
|
+
[`${key}-on-soft-hover`, formatHex(untilLegible(base, softHover, AA_TEXT))]
|
|
530
|
+
];
|
|
531
|
+
})
|
|
532
|
+
);
|
|
533
|
+
const disabledBg = subtle;
|
|
534
|
+
const disabledFg = quantize(fadeToward(muted, disabledBg, disabledBg, AA_UI));
|
|
535
|
+
const disabledBorder = mixColors(parseHex(color.border.default), disabledBg, 0.45);
|
|
536
|
+
return {
|
|
537
|
+
border: {
|
|
538
|
+
/**
|
|
539
|
+
* Control boundaries. Explicit in the semantic layer when a product sets
|
|
540
|
+
* one; derived here from `border.strong` otherwise, pushed until it
|
|
541
|
+
* clears 3:1 on the *subtle* surface — the worst of the three, and the
|
|
542
|
+
* one inputs actually sit on inside a card.
|
|
543
|
+
*/
|
|
544
|
+
interactive: color.border.interactive ?? formatHex(untilLegible(parseHex(color.border.strong), subtle, AA_UI))
|
|
545
|
+
},
|
|
546
|
+
brand,
|
|
547
|
+
accent,
|
|
548
|
+
status,
|
|
549
|
+
state: {
|
|
550
|
+
/** Neutral interactive surfaces: menu items, table rows, ghost buttons. */
|
|
551
|
+
"hover-bg": formatHex(quantize(mixColors(surface, ink, STEP.neutralHover))),
|
|
552
|
+
"press-bg": formatHex(quantize(mixColors(surface, ink, STEP.neutralPress))),
|
|
553
|
+
/**
|
|
554
|
+
* Selection reads as the brand tint. The ink is the brand's derived
|
|
555
|
+
* on-tint ink, not `brand.primary` — on the shipped dark tint those
|
|
556
|
+
* differ, and the raw brand measured 4.44:1 there.
|
|
557
|
+
*/
|
|
558
|
+
"selected-bg": color.brand.soft,
|
|
559
|
+
"selected-fg": brand["on-soft"],
|
|
560
|
+
"selected-border": color.brand.primary,
|
|
561
|
+
"disabled-bg": formatHex(disabledBg),
|
|
562
|
+
"disabled-fg": formatHex(disabledFg),
|
|
563
|
+
"disabled-border": formatHex(disabledBorder)
|
|
564
|
+
}
|
|
565
|
+
};
|
|
566
|
+
};
|
|
567
|
+
|
|
245
568
|
// src/token-source.ts
|
|
246
569
|
var toCssVariable = (path2) => `--tree-${path2.join("-")}`;
|
|
247
570
|
var flattenTokens = (record, path2 = []) => Object.entries(record).flatMap(([key, value]) => {
|
|
@@ -278,21 +601,29 @@ var buildTokenEntries = () => {
|
|
|
278
601
|
);
|
|
279
602
|
const themed = /* @__PURE__ */ new Map();
|
|
280
603
|
for (const [themeName, theme] of Object.entries(treeThemes)) {
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
604
|
+
const mode = themeName === "dark" ? "dark" : "light";
|
|
605
|
+
const derived = { color: deriveStateColors(theme.color, mode) };
|
|
606
|
+
for (const [source, entries] of [
|
|
607
|
+
["semantic", flattenTokens(theme)],
|
|
608
|
+
["derived", flattenTokens(derived)]
|
|
609
|
+
]) {
|
|
610
|
+
for (const [path2, value] of entries) {
|
|
611
|
+
const cssVar = toCssVariable(path2);
|
|
612
|
+
const existing = themed.get(cssVar);
|
|
613
|
+
if (existing) {
|
|
614
|
+
existing.themeValues = { ...existing.themeValues, [themeName]: String(value) };
|
|
615
|
+
continue;
|
|
616
|
+
}
|
|
617
|
+
themed.set(cssVar, {
|
|
618
|
+
cssVar,
|
|
619
|
+
path: path2.join("."),
|
|
620
|
+
value: String(value),
|
|
621
|
+
category: path2[0],
|
|
622
|
+
derived: source === "derived",
|
|
623
|
+
description: source === "derived" ? `${describeToken(path2[0])} Derived by the library from the semantic layer \u2014 read it, do not override it.` : describeToken(path2[0]),
|
|
624
|
+
themeValues: { [themeName]: String(value) }
|
|
625
|
+
});
|
|
287
626
|
}
|
|
288
|
-
themed.set(cssVar, {
|
|
289
|
-
cssVar,
|
|
290
|
-
path: path2.join("."),
|
|
291
|
-
value: String(value),
|
|
292
|
-
category: path2[0],
|
|
293
|
-
description: describeToken(path2[0]),
|
|
294
|
-
themeValues: { [themeName]: String(value) }
|
|
295
|
-
});
|
|
296
627
|
}
|
|
297
628
|
}
|
|
298
629
|
for (const entry of themed.values()) {
|
|
@@ -542,15 +873,24 @@ var buildStoryIndex = (repoRoot) => {
|
|
|
542
873
|
continue;
|
|
543
874
|
}
|
|
544
875
|
const componentName = componentMatch[1];
|
|
545
|
-
const
|
|
546
|
-
|
|
876
|
+
const storyTitle = [...source.matchAll(/title:\s*'([^']+)'/g)].map((match) => match[1]).find((value) => /^(Components|Foundation|Patterns|Showcase)\/.+/.test(value));
|
|
877
|
+
if (!storyTitle) {
|
|
878
|
+
console.warn(
|
|
879
|
+
`[catalog] ${fileName} declares component: ${componentName} but no Storybook meta title \u2014 it will have no category or docs link.`
|
|
880
|
+
);
|
|
881
|
+
}
|
|
547
882
|
const titleParts = storyTitle?.split("/") ?? [];
|
|
548
883
|
const category = titleParts.length > 2 ? titleParts.slice(1, -1).join(" / ") : titleParts[1];
|
|
549
|
-
|
|
884
|
+
const entry = {
|
|
550
885
|
storyFile: path.relative(repoRoot, filePath),
|
|
551
886
|
storyTitle,
|
|
552
887
|
category
|
|
553
|
-
}
|
|
888
|
+
};
|
|
889
|
+
index.set(componentName, entry);
|
|
890
|
+
const fileComponent = `T${fileName.replace(/\.stories\.ts$/, "")}`;
|
|
891
|
+
if (!index.has(fileComponent)) {
|
|
892
|
+
index.set(fileComponent, entry);
|
|
893
|
+
}
|
|
554
894
|
}
|
|
555
895
|
return index;
|
|
556
896
|
};
|
package/package.json
CHANGED
|
@@ -1,8 +1,27 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@treeui/mcp",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.8.0",
|
|
4
4
|
"description": "Model Context Protocol server and AI catalog for TreeUI.",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"author": "TreeUI",
|
|
7
|
+
"homepage": "https://viserion77.github.io/treeui/",
|
|
8
|
+
"repository": {
|
|
9
|
+
"type": "git",
|
|
10
|
+
"url": "git+https://github.com/Viserion77/treeui.git",
|
|
11
|
+
"directory": "packages/mcp"
|
|
12
|
+
},
|
|
13
|
+
"bugs": {
|
|
14
|
+
"url": "https://github.com/Viserion77/treeui/issues"
|
|
15
|
+
},
|
|
16
|
+
"keywords": [
|
|
17
|
+
"treeui",
|
|
18
|
+
"mcp",
|
|
19
|
+
"model-context-protocol",
|
|
20
|
+
"ai",
|
|
21
|
+
"design-system"
|
|
22
|
+
],
|
|
5
23
|
"type": "module",
|
|
24
|
+
"sideEffects": false,
|
|
6
25
|
"main": "./dist/index.cjs",
|
|
7
26
|
"module": "./dist/index.js",
|
|
8
27
|
"types": "./dist/index.d.ts",
|