@signal9/era-ui 32.0.0 → 33.0.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 +24 -0
- package/dist/dev/audit-overlay.svelte +2 -2
- package/dist/era-ui.css +1 -1
- package/dist/generated-docs/utilities.json +99 -99
- package/dist/os/pane.svelte +3 -13
- package/dist/styles/index.css +2 -956
- package/dist/styles/typography.css +1 -1
- package/dist/styles/utilities/geometry.css +188 -0
- package/dist/styles/utilities/interaction.css +334 -0
- package/dist/styles/utilities/materials.css +39 -0
- package/dist/styles/utilities/public.css +391 -0
- package/dist/styles/utilities.css +5 -0
- package/dist/ui/card/card.svelte +2 -52
- package/dist/ui/card/card.svelte.d.ts +0 -43
- package/dist/ui/card/variants.d.ts +44 -0
- package/dist/ui/card/variants.js +20 -0
- package/dist/ui/context-menu/context-menu-checkbox-item.svelte +2 -4
- package/dist/ui/context-menu/context-menu-group-heading.svelte +2 -5
- package/dist/ui/context-menu/context-menu-item.svelte +2 -8
- package/dist/ui/context-menu/context-menu-radio-item.svelte +2 -8
- package/dist/ui/context-menu/context-menu-separator.svelte +2 -5
- package/dist/ui/context-menu/context-menu-sub-trigger.svelte +2 -8
- package/dist/ui/dialog/dialog-header.svelte +1 -1
- package/dist/ui/dropdown-menu/dropdown-menu-checkbox-item.svelte +2 -4
- package/dist/ui/dropdown-menu/dropdown-menu-group-heading.svelte +2 -5
- package/dist/ui/dropdown-menu/dropdown-menu-item.svelte +2 -8
- package/dist/ui/dropdown-menu/dropdown-menu-radio-item.svelte +2 -8
- package/dist/ui/dropdown-menu/dropdown-menu-separator.svelte +2 -5
- package/dist/ui/dropdown-menu/dropdown-menu-sub-trigger.svelte +2 -8
- package/dist/ui/menu-recipes.d.ts +6 -0
- package/dist/ui/menu-recipes.js +6 -0
- package/dist/ui/menubar/menubar-checkbox-item.svelte +2 -9
- package/dist/ui/menubar/menubar-group-heading.svelte +2 -5
- package/dist/ui/menubar/menubar-item.svelte +2 -8
- package/dist/ui/menubar/menubar-radio-item.svelte +2 -8
- package/dist/ui/menubar/menubar-separator.svelte +2 -5
- package/dist/ui/menubar/menubar-sub-trigger.svelte +2 -8
- package/dist/ui/pane/pane-close.svelte +7 -26
- package/dist/ui/video-player/video-player.svelte +8 -8
- package/package.json +48 -12
- package/dist/docs/badge.md +0 -18
- package/dist/docs/bits-ui-audit.md +0 -58
- package/dist/docs/button.md +0 -19
- package/dist/docs/chip.md +0 -20
- package/dist/docs/component-docs-core.d.ts +0 -8
- package/dist/docs/component-docs-core.js +0 -73
- package/dist/docs/component-docs.d.ts +0 -2
- package/dist/docs/component-docs.js +0 -25
- package/dist/docs/component-source-scanners.d.ts +0 -18
- package/dist/docs/component-source-scanners.js +0 -46
- package/dist/docs/consumer-import.d.ts +0 -65
- package/dist/docs/consumer-import.js +0 -70
- package/dist/docs/css-utilities.d.ts +0 -58
- package/dist/docs/css-utilities.js +0 -317
- package/dist/docs/extract-props.d.ts +0 -13
- package/dist/docs/extract-props.js +0 -324
- package/dist/docs/generated-docs.d.ts +0 -6
- package/dist/docs/generated-docs.js +0 -30
- package/dist/docs/index.d.ts +0 -5
- package/dist/docs/index.js +0 -66
- package/dist/docs/notes.md +0 -83
- package/dist/docs/scroll-area.md +0 -7
- package/dist/docs/separator.md +0 -20
- package/dist/docs/table.md +0 -35
- package/dist/docs/utilities.d.ts +0 -4
- package/dist/docs/utilities.js +0 -15
- package/dist/generated-docs/accordion.md +0 -57
- package/dist/generated-docs/alert-dialog.md +0 -91
- package/dist/generated-docs/aspect-ratio.md +0 -17
- package/dist/generated-docs/avatar.md +0 -39
- package/dist/generated-docs/badge.md +0 -41
- package/dist/generated-docs/bar.md +0 -41
- package/dist/generated-docs/button-group.md +0 -19
- package/dist/generated-docs/button.md +0 -117
- package/dist/generated-docs/calendar.md +0 -126
- package/dist/generated-docs/card.md +0 -58
- package/dist/generated-docs/checkbox.md +0 -42
- package/dist/generated-docs/chip.md +0 -61
- package/dist/generated-docs/code-block.md +0 -20
- package/dist/generated-docs/collapsible.md +0 -30
- package/dist/generated-docs/combobox.md +0 -74
- package/dist/generated-docs/command-bar.md +0 -3
- package/dist/generated-docs/command.md +0 -126
- package/dist/generated-docs/context-menu.md +0 -104
- package/dist/generated-docs/copy-button.md +0 -29
- package/dist/generated-docs/cycle.md +0 -29
- package/dist/generated-docs/date-field.md +0 -49
- package/dist/generated-docs/date-picker.md +0 -180
- package/dist/generated-docs/date-range-field.md +0 -50
- package/dist/generated-docs/date-range-picker.md +0 -180
- package/dist/generated-docs/dialog.md +0 -94
- package/dist/generated-docs/draggable.md +0 -3
- package/dist/generated-docs/dropdown-menu.md +0 -104
- package/dist/generated-docs/file-upload.md +0 -18
- package/dist/generated-docs/getting-started.md +0 -3
- package/dist/generated-docs/input.md +0 -23
- package/dist/generated-docs/kv.md +0 -20
- package/dist/generated-docs/label.md +0 -17
- package/dist/generated-docs/link-preview.md +0 -40
- package/dist/generated-docs/llm-shell.md +0 -3
- package/dist/generated-docs/llms-full.txt +0 -5201
- package/dist/generated-docs/llms.txt +0 -138
- package/dist/generated-docs/logo.md +0 -24
- package/dist/generated-docs/manifest.json +0 -1685
- package/dist/generated-docs/measurements.md +0 -3
- package/dist/generated-docs/menu.md +0 -11
- package/dist/generated-docs/menubar.md +0 -104
- package/dist/generated-docs/meter.md +0 -101
- package/dist/generated-docs/mode.md +0 -24
- package/dist/generated-docs/nav.md +0 -73
- package/dist/generated-docs/navigation-menu.md +0 -11
- package/dist/generated-docs/notes.md +0 -87
- package/dist/generated-docs/os.md +0 -3
- package/dist/generated-docs/pagination.md +0 -55
- package/dist/generated-docs/pane.md +0 -34
- package/dist/generated-docs/pin-input.md +0 -31
- package/dist/generated-docs/popover.md +0 -43
- package/dist/generated-docs/progress.md +0 -17
- package/dist/generated-docs/radio-group.md +0 -31
- package/dist/generated-docs/range-calendar.md +0 -11
- package/dist/generated-docs/rating-group.md +0 -31
- package/dist/generated-docs/scroll-area.md +0 -65
- package/dist/generated-docs/select.md +0 -67
- package/dist/generated-docs/separator.md +0 -57
- package/dist/generated-docs/sheet.md +0 -11
- package/dist/generated-docs/skeleton.md +0 -18
- package/dist/generated-docs/slider.md +0 -71
- package/dist/generated-docs/spacing.md +0 -3
- package/dist/generated-docs/step.md +0 -51
- package/dist/generated-docs/surfaces.md +0 -3
- package/dist/generated-docs/switch.md +0 -18
- package/dist/generated-docs/table.md +0 -113
- package/dist/generated-docs/tabs.md +0 -48
- package/dist/generated-docs/text.md +0 -3
- package/dist/generated-docs/time-field.md +0 -49
- package/dist/generated-docs/time-range-field.md +0 -50
- package/dist/generated-docs/timeline.md +0 -32
- package/dist/generated-docs/todo.md +0 -3
- package/dist/generated-docs/toggle-group.md +0 -31
- package/dist/generated-docs/toggle.md +0 -20
- package/dist/generated-docs/toolbar.md +0 -11
- package/dist/generated-docs/tooltip.md +0 -40
- package/dist/generated-docs/tree.md +0 -36
- package/dist/generated-docs/utilities.md +0 -1236
- package/dist/generated-docs/video-player.md +0 -73
|
@@ -1,317 +0,0 @@
|
|
|
1
|
-
/*
|
|
2
|
-
* Extracts era's Tailwind v4 `@utility` classes — era-link, era-text-trim,
|
|
3
|
-
* era-shimmer, scrollbar-none, material-popover, … — from the stylesheet source.
|
|
4
|
-
*
|
|
5
|
-
* These are first-class API but they have no JS export and no .svelte file, so
|
|
6
|
-
* nothing else in the doc pipeline can see them: the component barrel misses
|
|
7
|
-
* them, the registry misses them, and a consumer (or an agent) reasoning from
|
|
8
|
-
* "what does era expose for links?" never finds `era-link`. The doc comment
|
|
9
|
-
* above each `@utility` is already thorough, so it — not a hand-maintained list
|
|
10
|
-
* — is the source of truth. This parses it.
|
|
11
|
-
*
|
|
12
|
-
* The convention the parser leans on: an `@use ` line in the comment is the
|
|
13
|
-
* one-line use case (what an agent searches), and the remaining prose is the
|
|
14
|
-
* long description. A utility with no `@use` line still documents fine; it just
|
|
15
|
-
* lands in the docs without a use-case summary.
|
|
16
|
-
*
|
|
17
|
-
* Pure (takes sources, returns data) so both the runtime glob loader and the
|
|
18
|
-
* node build script can drive it — same split as component-source-scanners.ts.
|
|
19
|
-
*/
|
|
20
|
-
/** Files whose utilities are library API. Order fixes the doc's order. */
|
|
21
|
-
const FILE_ORDER = ['index.css'];
|
|
22
|
-
/**
|
|
23
|
-
* `@theme` namespace → the utility prefixes it generates.
|
|
24
|
-
*
|
|
25
|
-
* Half of era's public class API is registered this way rather than as
|
|
26
|
-
* `@utility` blocks — `rounded-control` from `--radius-control`, `shadow-lg`,
|
|
27
|
-
* `bg-highlight`, `text-body`, and the whole spacing scale. They are classes a
|
|
28
|
-
* consumer writes exactly like the others, and until this table existed the
|
|
29
|
-
* doc pipeline could not see any of them: `@utility` was the only thing it
|
|
30
|
-
* parsed, so era's most-used names were also its least-documented.
|
|
31
|
-
*
|
|
32
|
-
* The list per namespace is the SPELLINGS WORTH DOCUMENTING, not everything
|
|
33
|
-
* Tailwind derives — a spacing token really does generate `mt-`, `gap-x-`,
|
|
34
|
-
* `inset-`, `translate-` and a dozen more, and printing all of them per name
|
|
35
|
-
* would bury the point. The prose says the rest.
|
|
36
|
-
*/
|
|
37
|
-
export const THEME_CLASS_PREFIXES = {
|
|
38
|
-
radius: ['rounded'],
|
|
39
|
-
shadow: ['shadow'],
|
|
40
|
-
text: ['text'],
|
|
41
|
-
leading: ['leading'],
|
|
42
|
-
ease: ['ease'],
|
|
43
|
-
color: ['bg', 'text', 'border'],
|
|
44
|
-
spacing: ['p', 'px', 'py', 'gap']
|
|
45
|
-
};
|
|
46
|
-
/** Every prefix a namespace really generates — the map the codemod needs. */
|
|
47
|
-
export const THEME_ALL_PREFIXES = {
|
|
48
|
-
...THEME_CLASS_PREFIXES,
|
|
49
|
-
radius: [
|
|
50
|
-
'rounded',
|
|
51
|
-
...'t,r,b,l,tl,tr,bl,br,s,e,ss,se,es,ee'.split(',').map((s) => `rounded-${s}`)
|
|
52
|
-
],
|
|
53
|
-
color: [
|
|
54
|
-
'bg',
|
|
55
|
-
'text',
|
|
56
|
-
'border',
|
|
57
|
-
'fill',
|
|
58
|
-
'stroke',
|
|
59
|
-
'ring',
|
|
60
|
-
'outline',
|
|
61
|
-
'divide',
|
|
62
|
-
'decoration',
|
|
63
|
-
'caret',
|
|
64
|
-
'accent',
|
|
65
|
-
'from',
|
|
66
|
-
'via',
|
|
67
|
-
'to'
|
|
68
|
-
],
|
|
69
|
-
spacing: [
|
|
70
|
-
'p,px,py,pt,pr,pb,pl,ps,pe',
|
|
71
|
-
'm,mx,my,mt,mr,mb,ml,ms,me',
|
|
72
|
-
'gap,gap-x,gap-y',
|
|
73
|
-
'w,h,size,min-w,min-h,max-w,max-h',
|
|
74
|
-
'inset,inset-x,inset-y,top,right,bottom,left,start,end',
|
|
75
|
-
'translate,translate-x,translate-y,scroll-m,scroll-p,basis,indent'
|
|
76
|
-
]
|
|
77
|
-
.join(',')
|
|
78
|
-
.split(',')
|
|
79
|
-
};
|
|
80
|
-
function cleanComment(raw) {
|
|
81
|
-
return raw
|
|
82
|
-
.split('\n')
|
|
83
|
-
.map((line) => line.replace(/^\s*\*\s?/, '').trimEnd())
|
|
84
|
-
.join('\n')
|
|
85
|
-
.trim();
|
|
86
|
-
}
|
|
87
|
-
/** Split the comment into its `@use` one-liner and the surrounding prose. */
|
|
88
|
-
function splitUseCase(comment) {
|
|
89
|
-
const lines = comment.split('\n');
|
|
90
|
-
const start = lines.findIndex((line) => line.startsWith('@use '));
|
|
91
|
-
if (start === -1)
|
|
92
|
-
return { description: comment.trim() };
|
|
93
|
-
let end = start + 1;
|
|
94
|
-
while (end < lines.length && lines[end].trim() !== '')
|
|
95
|
-
end++;
|
|
96
|
-
const useCase = lines
|
|
97
|
-
.slice(start, end)
|
|
98
|
-
.join(' ')
|
|
99
|
-
.replace(/^@use\s+/, '')
|
|
100
|
-
.replace(/\s+/g, ' ')
|
|
101
|
-
.trim();
|
|
102
|
-
const description = [...lines.slice(0, start), ...lines.slice(end)].join('\n').trim();
|
|
103
|
-
return { useCase, description };
|
|
104
|
-
}
|
|
105
|
-
/** Walk from the opening brace to its match so nested rules survive intact. */
|
|
106
|
-
function blockEnd(source, openBrace) {
|
|
107
|
-
let depth = 0;
|
|
108
|
-
for (let i = openBrace; i < source.length; i++) {
|
|
109
|
-
if (source[i] === '{')
|
|
110
|
-
depth++;
|
|
111
|
-
else if (source[i] === '}' && --depth === 0)
|
|
112
|
-
return i;
|
|
113
|
-
}
|
|
114
|
-
return source.length - 1;
|
|
115
|
-
}
|
|
116
|
-
function parseFile(file, source) {
|
|
117
|
-
const out = [];
|
|
118
|
-
// The comment body may not contain a terminator — a lazy `[\s\S]*?` would
|
|
119
|
-
// happily start at the first comment in the file and run through every `*/`
|
|
120
|
-
// between there and the @utility.
|
|
121
|
-
const pattern = /\/\*((?:(?!\*\/)[\s\S])*)\*\/\s*@utility\s+([\w-]+)\s*\{/g;
|
|
122
|
-
for (const match of source.matchAll(pattern)) {
|
|
123
|
-
const names = [match[2]];
|
|
124
|
-
let end = blockEnd(source, match.index + match[0].length - 1);
|
|
125
|
-
// One doc comment may govern a RUN of consecutive @utility blocks — a
|
|
126
|
-
// ladder like h-icon…h-bar shares one story, and repeating it five times
|
|
127
|
-
// would drown the docs. Attach every block that follows the previous one
|
|
128
|
-
// with nothing but whitespace in between; the next commented block never
|
|
129
|
-
// matches here because the outer pattern requires the comment.
|
|
130
|
-
const next = /^\s*@utility\s+([\w-]+)\s*\{/;
|
|
131
|
-
for (let m; (m = next.exec(source.slice(end + 1)));) {
|
|
132
|
-
names.push(m[1]);
|
|
133
|
-
end = blockEnd(source, end + 1 + m[0].length - 1);
|
|
134
|
-
}
|
|
135
|
-
const { useCase, description } = splitUseCase(cleanComment(match[1]));
|
|
136
|
-
out.push({
|
|
137
|
-
name: names[0],
|
|
138
|
-
names,
|
|
139
|
-
file,
|
|
140
|
-
useCase,
|
|
141
|
-
description,
|
|
142
|
-
css: source.slice(source.indexOf('@utility', match.index), end + 1)
|
|
143
|
-
});
|
|
144
|
-
}
|
|
145
|
-
return out;
|
|
146
|
-
}
|
|
147
|
-
/**
|
|
148
|
-
* The classes one `@theme` key generates, each with the utility PREFIX that
|
|
149
|
-
* generated it — `--spacing-inset-control` → `{ prefix: 'px', name:
|
|
150
|
-
* 'px-inset-control' }`. The prefix cannot be recovered from the name (both
|
|
151
|
-
* `px` and `px-inset` are hyphen-splits of `px-inset-control`), and the codemod
|
|
152
|
-
* matches on it, so it is returned rather than re-derived.
|
|
153
|
-
*/
|
|
154
|
-
export function themeKeyClassEntries(themeKey, prefixes = THEME_CLASS_PREFIXES) {
|
|
155
|
-
const bare = themeKey.replace(/^--/, '');
|
|
156
|
-
// Tailwind's metadata sub-keys (`--text-title--line-height`) configure a
|
|
157
|
-
// scale entry; they are not classes of their own, and listing them as such
|
|
158
|
-
// put `text-title--letter-spacing` in the reference as if a consumer could
|
|
159
|
-
// write it.
|
|
160
|
-
if (bare.includes('--'))
|
|
161
|
-
return [];
|
|
162
|
-
// `--shadow: …` IS the bare `shadow` class — a namespace with no suffix.
|
|
163
|
-
if (prefixes[bare])
|
|
164
|
-
return [{ prefix: bare, name: bare }];
|
|
165
|
-
const cut = bare.indexOf('-');
|
|
166
|
-
if (cut === -1)
|
|
167
|
-
return [];
|
|
168
|
-
const namespace = bare.slice(0, cut);
|
|
169
|
-
const suffix = bare.slice(cut + 1);
|
|
170
|
-
return (prefixes[namespace] ?? []).map((p) => ({ prefix: p, name: `${p}-${suffix}` }));
|
|
171
|
-
}
|
|
172
|
-
/** The class names one `@theme` key generates, e.g. `--radius-control` → `rounded-control`. */
|
|
173
|
-
export function themeKeyClasses(themeKey, prefixes = THEME_CLASS_PREFIXES) {
|
|
174
|
-
return themeKeyClassEntries(themeKey, prefixes).map((e) => e.name);
|
|
175
|
-
}
|
|
176
|
-
/**
|
|
177
|
-
* Named theme scales — the other half of the public class API.
|
|
178
|
-
*
|
|
179
|
-
* Shape parsed: a doc comment followed by a RUN of `--key: var(…)` lines inside
|
|
180
|
-
* `@theme`, exactly like the `@utility` ladder rule above. One comment governs
|
|
181
|
-
* the whole run, so the radius ladder or the spacing scale documents once.
|
|
182
|
-
*/
|
|
183
|
-
function parseTheme(file, source) {
|
|
184
|
-
// Anchored to the start of a line: `@theme` also appears in PROSE (the layering
|
|
185
|
-
// comment in index.css explains that @utility and @theme are Tailwind's to
|
|
186
|
-
// place), and an unanchored match happily started inside that comment, ran to
|
|
187
|
-
// the next `{` it found, and returned garbage — silently dropping every
|
|
188
|
-
// theme-derived class from the docs.
|
|
189
|
-
const theme = source.match(/^@theme[^{]*\{([\s\S]*?)\n\}/m);
|
|
190
|
-
if (!theme)
|
|
191
|
-
return [];
|
|
192
|
-
const body = theme[1];
|
|
193
|
-
const out = [];
|
|
194
|
-
const pattern = /\/\*((?:(?!\*\/)[\s\S])*)\*\/\s*((?:\s*--[\w-]+\s*:[^;]+;\n?)+)/g;
|
|
195
|
-
for (const match of body.matchAll(pattern)) {
|
|
196
|
-
const decls = [...match[2].matchAll(/--[\w-]+\s*:[^;]+;/g)].map((m) => m[0]);
|
|
197
|
-
const names = decls.flatMap((d) => themeKeyClasses(d.slice(0, d.indexOf(':')).trim()));
|
|
198
|
-
// A comment governing only non-class keys (--default-transition-*) has
|
|
199
|
-
// nothing to document — it is internal wiring, not API.
|
|
200
|
-
if (!names.length)
|
|
201
|
-
continue;
|
|
202
|
-
const { useCase, description } = splitUseCase(cleanComment(match[1]));
|
|
203
|
-
out.push({
|
|
204
|
-
name: names[0],
|
|
205
|
-
names,
|
|
206
|
-
file,
|
|
207
|
-
useCase,
|
|
208
|
-
description,
|
|
209
|
-
css: `@theme inline {\n${decls.map((d) => `\t${d}`).join('\n')}\n}`
|
|
210
|
-
});
|
|
211
|
-
}
|
|
212
|
-
return out;
|
|
213
|
-
}
|
|
214
|
-
/**
|
|
215
|
-
* @param sources stylesheet text keyed by path relative to src/lib/styles
|
|
216
|
-
* (e.g. `index.css`, `surfaces/glass.css`).
|
|
217
|
-
*/
|
|
218
|
-
export function parseUtilities(sources) {
|
|
219
|
-
const rank = (file) => {
|
|
220
|
-
const i = FILE_ORDER.indexOf(file);
|
|
221
|
-
return i === -1 ? FILE_ORDER.length : i;
|
|
222
|
-
};
|
|
223
|
-
return Object.entries(sources)
|
|
224
|
-
.sort(([a], [b]) => rank(a) - rank(b) || a.localeCompare(b))
|
|
225
|
-
.flatMap(([file, source]) => [...parseFile(file, source), ...parseTheme(file, source)]);
|
|
226
|
-
}
|
|
227
|
-
const INTRO = [
|
|
228
|
-
"era's styling API is pure class names — write `tier-control px-gutter shadow`,",
|
|
229
|
-
'never the `h-(--era-h-control)` var-class spelling. Everything below rides along',
|
|
230
|
-
'with the stylesheet and needs no import:',
|
|
231
|
-
'',
|
|
232
|
-
'```ts',
|
|
233
|
-
'import "@signal9/era-ui/css";',
|
|
234
|
-
'```',
|
|
235
|
-
'',
|
|
236
|
-
'```svelte',
|
|
237
|
-
'<button class="tier-control px-inset-control shadow text-body">era styled</button>',
|
|
238
|
-
'```',
|
|
239
|
-
'',
|
|
240
|
-
'Alongside the `@utility` classes referenced below, era registers named theme',
|
|
241
|
-
'scales that OVERLOAD the stock Tailwind names, so ordinary-looking markup',
|
|
242
|
-
'renders on-design and responds to every axis (density, surface, corners,',
|
|
243
|
-
'motion):',
|
|
244
|
-
'',
|
|
245
|
-
'| Stock-looking class | What it resolves to |',
|
|
246
|
-
'|---|---|',
|
|
247
|
-
'| `tier-icon/pill/chip/control/bar` | indivisible bounded height + concentric radius |',
|
|
248
|
-
'| `rounded-icon/pill/chip/control/bar` | the concentric radius ladder (collapses on `data-corners="square"`) |',
|
|
249
|
-
'| `rounded-menu-item` | menu-row radius, concentric inside a `rounded-control` panel |',
|
|
250
|
-
'| `shadow` / `shadow-lg` | resting control edge / floating panel chrome, per surface |',
|
|
251
|
-
'| `shadow-well` / `shadow-pressed` / `shadow-highlight` | recessed, pressed/latched, hover-material chrome |',
|
|
252
|
-
'| `bg-well` / `bg-elevated` / `bg-highlight` / `bg-overlay` | surface fills: resting, raised, transient feedback, modal scrim |',
|
|
253
|
-
'| `transition-*` (bare) | duration + easing default to the motion axis |',
|
|
254
|
-
'| `ease-base` / `duration-base` | the motion axis, named explicitly |',
|
|
255
|
-
'| `text-body` | density-derived body/control text size |',
|
|
256
|
-
'| `p-gutter` / `gap-gutter` / `mt-gutter` / … | the spacing scale — EVERY spacing prefix works |',
|
|
257
|
-
'',
|
|
258
|
-
'THE SPACING NAMES IN SIZE ORDER, smallest first, because the names do not',
|
|
259
|
-
'imply it and guessing gets it backwards:',
|
|
260
|
-
'',
|
|
261
|
-
' gutter < panel < field < card < content',
|
|
262
|
-
'',
|
|
263
|
-
'Measured at `data-mode="balanced"`: gutter 5px, field ~9px, card ~11px,',
|
|
264
|
-
'content ~22px. `gutter` is the TIGHT one — the gap between sibling controls',
|
|
265
|
-
"and a rail's own padding. `field` is a text input's side padding, not the",
|
|
266
|
-
'label-to-input gap. Reading them the other way round produces a layout whose',
|
|
267
|
-
'hierarchy is inverted and therefore reads flat.',
|
|
268
|
-
'',
|
|
269
|
-
'The spacing names (`gutter`, `card`, `panel`, `content`, `menu`, `field`, the',
|
|
270
|
-
'`inset-*` and concentric `*-inset-*` insets, `glyph-*`) are registered as a',
|
|
271
|
-
'Tailwind spacing scale, so every prefix derives automatically: `p-`, `px-`,',
|
|
272
|
-
'`pt-`, `mt-`, `gap-`, `gap-x-`, `inset-`, `translate-`, and the rest. The TIER',
|
|
273
|
-
'names (`icon`, `pill`, `chip`, `control`, `bar`) are dimensions, not spacing, so',
|
|
274
|
-
'they are registered per prefix instead — `h-`, `w-`, `min-h-`, `min-w-` and',
|
|
275
|
-
'`size-` — and the two vocabularies deliberately share no word. Putting a tier',
|
|
276
|
-
'in the spacing scale would silently make `px-control` mean 24px of padding.',
|
|
277
|
-
'For chrome, use `tier-T`, which binds `h-T` and `rounded-T`; use the separate',
|
|
278
|
-
'dimension/radius names only for width, minimums, unbounded surfaces, or',
|
|
279
|
-
'asymmetric/docked corners.',
|
|
280
|
-
'',
|
|
281
|
-
'The var form (`h-(--era-h-control)`) still works and is the escape hatch for a',
|
|
282
|
-
'token with no registered name — `--era-sp`, the press-sink offsets, anything',
|
|
283
|
-
'a component reaches for once. `scripts/check-canonical.ts` fails the build if',
|
|
284
|
-
'source uses it where a name exists.'
|
|
285
|
-
].join('\n');
|
|
286
|
-
/**
|
|
287
|
-
* `h-icon` for a single class, `h-icon · h-pill · … · h-bar` for a ladder.
|
|
288
|
-
*
|
|
289
|
-
* Capped, because a theme scale can govern a LOT of spellings: the colour block
|
|
290
|
-
* generates bg-/text-/border- for every token, which is ~60 names and reads as
|
|
291
|
-
* noise in a heading. The prose under each entry states the full rule.
|
|
292
|
-
*/
|
|
293
|
-
const LABEL_CAP = 8;
|
|
294
|
-
const label = (u) => u.names.length > LABEL_CAP
|
|
295
|
-
? `${u.names.slice(0, LABEL_CAP).join(' · ')} · … (${u.names.length} in all)`
|
|
296
|
-
: u.names.join(' · ');
|
|
297
|
-
/** Renders the utilities reference — the generated `utilities.md` body. */
|
|
298
|
-
export function buildUtilitiesDoc(utilities) {
|
|
299
|
-
const lines = ['## Overview', '', INTRO, '', '| Utility | Use it for |', '|---|---|'];
|
|
300
|
-
for (const u of utilities) {
|
|
301
|
-
lines.push(`| ${u.names.map((n) => `\`${n}\``).join(' ')} | ${u.useCase ?? '—'} |`);
|
|
302
|
-
}
|
|
303
|
-
lines.push('');
|
|
304
|
-
for (const u of utilities) {
|
|
305
|
-
lines.push(`## ${label(u)}`, '');
|
|
306
|
-
if (u.useCase)
|
|
307
|
-
lines.push(`**Use it for:** ${u.useCase}`, '');
|
|
308
|
-
if (u.description)
|
|
309
|
-
lines.push(u.description, '');
|
|
310
|
-
lines.push(`Declared in \`${u.file}\`.`, '', '```css', u.css, '```', '');
|
|
311
|
-
}
|
|
312
|
-
return lines.join('\n');
|
|
313
|
-
}
|
|
314
|
-
/** One line per utility (or ladder) for llms.txt — plus its searchable use case. */
|
|
315
|
-
export function buildUtilitiesIndex(utilities) {
|
|
316
|
-
return utilities.map((u) => `- \`${label(u)}\` — ${u.useCase ?? u.description.split('\n')[0]}`);
|
|
317
|
-
}
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
export interface PropSpec {
|
|
2
|
-
name: string;
|
|
3
|
-
type: string;
|
|
4
|
-
optional: boolean;
|
|
5
|
-
default?: string;
|
|
6
|
-
bindable?: boolean;
|
|
7
|
-
description?: string;
|
|
8
|
-
}
|
|
9
|
-
export interface ComponentSpec {
|
|
10
|
-
inherits: string[];
|
|
11
|
-
props: PropSpec[];
|
|
12
|
-
}
|
|
13
|
-
export declare function extractProps(source: string): ComponentSpec | null;
|
|
@@ -1,324 +0,0 @@
|
|
|
1
|
-
export function extractProps(source) {
|
|
2
|
-
const script = extractScript(source);
|
|
3
|
-
if (!script)
|
|
4
|
-
return null;
|
|
5
|
-
const propsIdx = script.indexOf('$props(');
|
|
6
|
-
if (propsIdx === -1)
|
|
7
|
-
return null;
|
|
8
|
-
// Walk backwards through balanced brackets to locate `let { … }: … = $props()`.
|
|
9
|
-
// We find the `=` directly preceding `$props(`, then the matching `:`, then
|
|
10
|
-
// the destructure's closing `}`. Both the `=` and `:` must be at bracket
|
|
11
|
-
// depth 0 so we skip past any `=`/`:` buried inside the destructure or
|
|
12
|
-
// generic type arguments.
|
|
13
|
-
const eqIdx = findPrevTopLevel(script, propsIdx - 1, '=');
|
|
14
|
-
if (eqIdx === -1)
|
|
15
|
-
return null;
|
|
16
|
-
const typeEnd = eqIdx;
|
|
17
|
-
const typeStart = findPrevTopLevel(script, typeEnd - 1, ':');
|
|
18
|
-
if (typeStart === -1)
|
|
19
|
-
return null;
|
|
20
|
-
const typeExpr = script.slice(typeStart + 1, typeEnd).trim();
|
|
21
|
-
// Before `:` should be the destructure's closing `}`.
|
|
22
|
-
let braceEnd = typeStart - 1;
|
|
23
|
-
while (braceEnd >= 0 && /\s/.test(script[braceEnd]))
|
|
24
|
-
braceEnd--;
|
|
25
|
-
if (script[braceEnd] !== '}')
|
|
26
|
-
return null;
|
|
27
|
-
const braceStart = findMatchingOpen(script, braceEnd);
|
|
28
|
-
if (braceStart === -1)
|
|
29
|
-
return null;
|
|
30
|
-
const destructure = script.slice(braceStart + 1, braceEnd);
|
|
31
|
-
const defaults = parseDestructure(destructure);
|
|
32
|
-
const { inherits, literal } = parseTypeExpr(typeExpr);
|
|
33
|
-
// Merge defaults onto literal members; anything declared as bindable in the
|
|
34
|
-
// destructure is marked here too.
|
|
35
|
-
for (const prop of literal) {
|
|
36
|
-
const d = defaults[prop.name];
|
|
37
|
-
if (!d)
|
|
38
|
-
continue;
|
|
39
|
-
if (d.default !== undefined)
|
|
40
|
-
prop.default = d.default;
|
|
41
|
-
if (d.bindable)
|
|
42
|
-
prop.bindable = true;
|
|
43
|
-
}
|
|
44
|
-
// If the destructure introduces bindables not visible in the literal (a
|
|
45
|
-
// forwarded prop like `value` on Slider.Root), surface them anyway so the
|
|
46
|
-
// doc notes binding support.
|
|
47
|
-
for (const [name, d] of Object.entries(defaults)) {
|
|
48
|
-
if (literal.find((p) => p.name === name))
|
|
49
|
-
continue;
|
|
50
|
-
if (!d.bindable)
|
|
51
|
-
continue;
|
|
52
|
-
literal.push({
|
|
53
|
-
name,
|
|
54
|
-
type: '(forwarded)',
|
|
55
|
-
optional: true,
|
|
56
|
-
default: d.default,
|
|
57
|
-
bindable: true
|
|
58
|
-
});
|
|
59
|
-
}
|
|
60
|
-
return { inherits, props: literal };
|
|
61
|
-
}
|
|
62
|
-
function extractScript(source) {
|
|
63
|
-
// A component may have both a `<script module>` (tv() variants, etc.) and
|
|
64
|
-
// the instance `<script>`. $props() lives in the instance block, so scan
|
|
65
|
-
// all blocks and prefer the one that actually contains $props(); fall back
|
|
66
|
-
// to the last non-module block. Reading only the first block silently
|
|
67
|
-
// missed props on module-first components (badge/chip/card/skeleton).
|
|
68
|
-
const blocks = [...source.matchAll(/<script([^>]*)>([\s\S]*?)<\/script>/g)];
|
|
69
|
-
if (blocks.length === 0)
|
|
70
|
-
return null;
|
|
71
|
-
const withProps = blocks.find((b) => b[2].includes('$props('));
|
|
72
|
-
if (withProps)
|
|
73
|
-
return withProps[2];
|
|
74
|
-
const instance = blocks.filter((b) => !/\bmodule\b/.test(b[1])).at(-1);
|
|
75
|
-
return (instance ?? blocks[0])[2];
|
|
76
|
-
}
|
|
77
|
-
// If `src[i]` starts a string, template literal, or comment, skip past it and
|
|
78
|
-
// return the next index. Otherwise returns `i` unchanged so callers can decide
|
|
79
|
-
// what to do with the character.
|
|
80
|
-
function skipNonCode(src, i) {
|
|
81
|
-
const c = src[i];
|
|
82
|
-
// Arrow `=>` is neither a bracket nor an operator we track. Skipping it as a
|
|
83
|
-
// unit keeps the lone `>` from being counted as a generic-bracket close
|
|
84
|
-
// (which corrupted depth on arrow-typed props like `(d: E) => void`) and
|
|
85
|
-
// keeps its `=` from being mistaken for the `= $props()` assignment.
|
|
86
|
-
if (c === '=' && src[i + 1] === '>')
|
|
87
|
-
return i + 2;
|
|
88
|
-
if (c === '"' || c === "'") {
|
|
89
|
-
const quote = c;
|
|
90
|
-
i++;
|
|
91
|
-
while (i < src.length && src[i] !== quote) {
|
|
92
|
-
if (src[i] === '\\')
|
|
93
|
-
i++;
|
|
94
|
-
i++;
|
|
95
|
-
}
|
|
96
|
-
return i + 1;
|
|
97
|
-
}
|
|
98
|
-
if (c === '`') {
|
|
99
|
-
i++;
|
|
100
|
-
while (i < src.length && src[i] !== '`') {
|
|
101
|
-
if (src[i] === '\\')
|
|
102
|
-
i++;
|
|
103
|
-
else if (src[i] === '$' && src[i + 1] === '{') {
|
|
104
|
-
i = findMatchingClose(src, i + 1) + 1;
|
|
105
|
-
continue;
|
|
106
|
-
}
|
|
107
|
-
i++;
|
|
108
|
-
}
|
|
109
|
-
return i + 1;
|
|
110
|
-
}
|
|
111
|
-
if (c === '/' && src[i + 1] === '/') {
|
|
112
|
-
while (i < src.length && src[i] !== '\n')
|
|
113
|
-
i++;
|
|
114
|
-
return i;
|
|
115
|
-
}
|
|
116
|
-
if (c === '/' && src[i + 1] === '*') {
|
|
117
|
-
i += 2;
|
|
118
|
-
while (i < src.length - 1 && !(src[i] === '*' && src[i + 1] === '/'))
|
|
119
|
-
i++;
|
|
120
|
-
return i + 2;
|
|
121
|
-
}
|
|
122
|
-
return i;
|
|
123
|
-
}
|
|
124
|
-
function findMatchingClose(src, openIdx) {
|
|
125
|
-
const open = src[openIdx];
|
|
126
|
-
const close = { '{': '}', '(': ')', '[': ']', '<': '>' }[open];
|
|
127
|
-
if (!close)
|
|
128
|
-
return -1;
|
|
129
|
-
let depth = 0;
|
|
130
|
-
let i = openIdx;
|
|
131
|
-
while (i < src.length) {
|
|
132
|
-
const next = skipNonCode(src, i);
|
|
133
|
-
if (next !== i) {
|
|
134
|
-
i = next;
|
|
135
|
-
continue;
|
|
136
|
-
}
|
|
137
|
-
const c = src[i];
|
|
138
|
-
if (c === open)
|
|
139
|
-
depth++;
|
|
140
|
-
else if (c === close) {
|
|
141
|
-
depth--;
|
|
142
|
-
if (depth === 0)
|
|
143
|
-
return i;
|
|
144
|
-
}
|
|
145
|
-
i++;
|
|
146
|
-
}
|
|
147
|
-
return -1;
|
|
148
|
-
}
|
|
149
|
-
function findMatchingOpen(src, closeIdx) {
|
|
150
|
-
const close = src[closeIdx];
|
|
151
|
-
const open = { '}': '{', ')': '(', ']': '[', '>': '<' }[close];
|
|
152
|
-
if (!open)
|
|
153
|
-
return -1;
|
|
154
|
-
// Rescan forward tracking balance rather than scanning backwards — handling
|
|
155
|
-
// string/comment boundaries in reverse is error-prone.
|
|
156
|
-
const stack = [];
|
|
157
|
-
let i = 0;
|
|
158
|
-
while (i <= closeIdx) {
|
|
159
|
-
const next = skipNonCode(src, i);
|
|
160
|
-
if (next !== i) {
|
|
161
|
-
i = next;
|
|
162
|
-
continue;
|
|
163
|
-
}
|
|
164
|
-
const c = src[i];
|
|
165
|
-
if (c === open)
|
|
166
|
-
stack.push(i);
|
|
167
|
-
else if (c === close) {
|
|
168
|
-
const o = stack.pop();
|
|
169
|
-
if (i === closeIdx)
|
|
170
|
-
return o ?? -1;
|
|
171
|
-
}
|
|
172
|
-
i++;
|
|
173
|
-
}
|
|
174
|
-
return -1;
|
|
175
|
-
}
|
|
176
|
-
function findPrevTopLevel(src, end, token) {
|
|
177
|
-
// Records only matches at bracket depth 0, skipping nested expressions.
|
|
178
|
-
let found = -1;
|
|
179
|
-
let depth = 0;
|
|
180
|
-
let i = 0;
|
|
181
|
-
while (i <= end) {
|
|
182
|
-
const next = skipNonCode(src, i);
|
|
183
|
-
if (next !== i) {
|
|
184
|
-
i = next;
|
|
185
|
-
continue;
|
|
186
|
-
}
|
|
187
|
-
const c = src[i];
|
|
188
|
-
if (c === '{' || c === '(' || c === '[' || c === '<')
|
|
189
|
-
depth++;
|
|
190
|
-
else if (c === '}' || c === ')' || c === ']' || c === '>')
|
|
191
|
-
depth--;
|
|
192
|
-
else if (depth === 0 && c === token)
|
|
193
|
-
found = i;
|
|
194
|
-
i++;
|
|
195
|
-
}
|
|
196
|
-
return found;
|
|
197
|
-
}
|
|
198
|
-
function splitTopLevel(s, delim) {
|
|
199
|
-
const out = [];
|
|
200
|
-
let start = 0;
|
|
201
|
-
let depth = 0;
|
|
202
|
-
let i = 0;
|
|
203
|
-
while (i < s.length) {
|
|
204
|
-
const next = skipNonCode(s, i);
|
|
205
|
-
if (next !== i) {
|
|
206
|
-
i = next;
|
|
207
|
-
continue;
|
|
208
|
-
}
|
|
209
|
-
const c = s[i];
|
|
210
|
-
if (c === '{' || c === '(' || c === '[' || c === '<')
|
|
211
|
-
depth++;
|
|
212
|
-
else if (c === '}' || c === ')' || c === ']' || c === '>')
|
|
213
|
-
depth--;
|
|
214
|
-
else if (depth === 0 && c === delim) {
|
|
215
|
-
out.push(s.slice(start, i));
|
|
216
|
-
start = i + 1;
|
|
217
|
-
}
|
|
218
|
-
i++;
|
|
219
|
-
}
|
|
220
|
-
out.push(s.slice(start));
|
|
221
|
-
return out;
|
|
222
|
-
}
|
|
223
|
-
function parseTypeExpr(typeExpr) {
|
|
224
|
-
const branches = splitTopLevel(typeExpr, '&')
|
|
225
|
-
.map((b) => b.trim())
|
|
226
|
-
.filter(Boolean);
|
|
227
|
-
const inherits = [];
|
|
228
|
-
const literal = [];
|
|
229
|
-
for (const branch of branches) {
|
|
230
|
-
if (branch.startsWith('{')) {
|
|
231
|
-
const close = findMatchingClose(branch, 0);
|
|
232
|
-
if (close === -1)
|
|
233
|
-
continue;
|
|
234
|
-
literal.push(...parseLiteralMembers(branch.slice(1, close)));
|
|
235
|
-
}
|
|
236
|
-
else {
|
|
237
|
-
inherits.push(branch);
|
|
238
|
-
}
|
|
239
|
-
}
|
|
240
|
-
return { inherits, literal };
|
|
241
|
-
}
|
|
242
|
-
function parseLiteralMembers(body) {
|
|
243
|
-
const entries = splitTopLevel(body, ';')
|
|
244
|
-
.map((s) => s.trim())
|
|
245
|
-
.filter(Boolean);
|
|
246
|
-
const props = [];
|
|
247
|
-
for (const entry of entries) {
|
|
248
|
-
let description;
|
|
249
|
-
let remainder = entry;
|
|
250
|
-
const jsdoc = remainder.match(/^\/\*\*([\s\S]*?)\*\/\s*/);
|
|
251
|
-
if (jsdoc) {
|
|
252
|
-
description = jsdoc[1].replace(/^\s*\*\s?/gm, '').trim();
|
|
253
|
-
remainder = remainder.slice(jsdoc[0].length);
|
|
254
|
-
}
|
|
255
|
-
// Strip any remaining leading line comments.
|
|
256
|
-
while (remainder.startsWith('//')) {
|
|
257
|
-
const nl = remainder.indexOf('\n');
|
|
258
|
-
remainder = nl === -1 ? '' : remainder.slice(nl + 1).trimStart();
|
|
259
|
-
}
|
|
260
|
-
const m = remainder.match(/^([A-Za-z_$][\w$]*)(\??)\s*:\s*([\s\S]+)$/);
|
|
261
|
-
if (!m)
|
|
262
|
-
continue;
|
|
263
|
-
props.push({
|
|
264
|
-
name: m[1],
|
|
265
|
-
optional: m[2] === '?',
|
|
266
|
-
type: m[3].trim(),
|
|
267
|
-
description
|
|
268
|
-
});
|
|
269
|
-
}
|
|
270
|
-
return props;
|
|
271
|
-
}
|
|
272
|
-
function parseDestructure(body) {
|
|
273
|
-
const entries = splitTopLevel(body, ',')
|
|
274
|
-
.map((s) => s.trim())
|
|
275
|
-
.filter(Boolean);
|
|
276
|
-
const out = {};
|
|
277
|
-
for (const entry of entries) {
|
|
278
|
-
if (entry.startsWith('...'))
|
|
279
|
-
continue;
|
|
280
|
-
let left = entry;
|
|
281
|
-
let defaultVal;
|
|
282
|
-
const eq = findTopLevelChar(entry, '=');
|
|
283
|
-
if (eq !== -1) {
|
|
284
|
-
left = entry.slice(0, eq).trim();
|
|
285
|
-
defaultVal = entry.slice(eq + 1).trim();
|
|
286
|
-
}
|
|
287
|
-
// Strip alias: `class: className` → name is `class`.
|
|
288
|
-
const colon = findTopLevelChar(left, ':');
|
|
289
|
-
if (colon !== -1)
|
|
290
|
-
left = left.slice(0, colon).trim();
|
|
291
|
-
const bindable = /^\$bindable\b/.test(defaultVal ?? '');
|
|
292
|
-
let normalizedDefault = defaultVal;
|
|
293
|
-
if (bindable && defaultVal) {
|
|
294
|
-
// `$bindable(null)` → `null`; `$bindable<T>(x)` → `x`.
|
|
295
|
-
const paren = defaultVal.indexOf('(');
|
|
296
|
-
const close = paren === -1 ? -1 : findMatchingClose(defaultVal, paren);
|
|
297
|
-
if (paren !== -1 && close !== -1) {
|
|
298
|
-
normalizedDefault = defaultVal.slice(paren + 1, close).trim() || undefined;
|
|
299
|
-
}
|
|
300
|
-
}
|
|
301
|
-
out[left] = { default: normalizedDefault, bindable };
|
|
302
|
-
}
|
|
303
|
-
return out;
|
|
304
|
-
}
|
|
305
|
-
function findTopLevelChar(s, ch) {
|
|
306
|
-
let depth = 0;
|
|
307
|
-
let i = 0;
|
|
308
|
-
while (i < s.length) {
|
|
309
|
-
const next = skipNonCode(s, i);
|
|
310
|
-
if (next !== i) {
|
|
311
|
-
i = next;
|
|
312
|
-
continue;
|
|
313
|
-
}
|
|
314
|
-
const c = s[i];
|
|
315
|
-
if (c === '{' || c === '(' || c === '[' || c === '<')
|
|
316
|
-
depth++;
|
|
317
|
-
else if (c === '}' || c === ')' || c === ']' || c === '>')
|
|
318
|
-
depth--;
|
|
319
|
-
else if (depth === 0 && c === ch)
|
|
320
|
-
return i;
|
|
321
|
-
i++;
|
|
322
|
-
}
|
|
323
|
-
return -1;
|
|
324
|
-
}
|
|
@@ -1,6 +0,0 @@
|
|
|
1
|
-
export declare const docsBySlug: Record<string, string>;
|
|
2
|
-
export declare const knownSlugs: Set<string>;
|
|
3
|
-
/** Served verbatim at /utilities.json so tooling can enumerate the CSS API. */
|
|
4
|
-
export declare const utilitiesJson: string;
|
|
5
|
-
export declare const llmsTxtTemplate: string;
|
|
6
|
-
export declare const llmsFullTxt: string;
|
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
const markdownFiles = import.meta.glob('../generated-docs/*.md', {
|
|
2
|
-
query: '?raw',
|
|
3
|
-
import: 'default',
|
|
4
|
-
eager: true
|
|
5
|
-
});
|
|
6
|
-
const textFiles = import.meta.glob('../generated-docs/*.txt', {
|
|
7
|
-
query: '?raw',
|
|
8
|
-
import: 'default',
|
|
9
|
-
eager: true
|
|
10
|
-
});
|
|
11
|
-
const manifestModules = import.meta.glob('../generated-docs/manifest.json', {
|
|
12
|
-
import: 'default',
|
|
13
|
-
eager: true
|
|
14
|
-
});
|
|
15
|
-
const utilitiesModules = import.meta.glob('../generated-docs/utilities.json', {
|
|
16
|
-
query: '?raw',
|
|
17
|
-
import: 'default',
|
|
18
|
-
eager: true
|
|
19
|
-
});
|
|
20
|
-
function stem(path) {
|
|
21
|
-
return path.replace(/^\.\.\/generated-docs\//, '').replace(/\.(md|txt)$/, '');
|
|
22
|
-
}
|
|
23
|
-
export const docsBySlug = Object.fromEntries(Object.entries(markdownFiles).map(([file, body]) => [stem(file), body]));
|
|
24
|
-
const manifest = Object.values(manifestModules)[0];
|
|
25
|
-
const manifestSlugs = manifest?.entries?.map((entry) => entry.slug) ?? [];
|
|
26
|
-
export const knownSlugs = new Set(manifestSlugs.length ? manifestSlugs : Object.keys(docsBySlug));
|
|
27
|
-
/** Served verbatim at /utilities.json so tooling can enumerate the CSS API. */
|
|
28
|
-
export const utilitiesJson = utilitiesModules['../generated-docs/utilities.json'] ?? '';
|
|
29
|
-
export const llmsTxtTemplate = textFiles['../generated-docs/llms.txt'] ?? '';
|
|
30
|
-
export const llmsFullTxt = textFiles['../generated-docs/llms-full.txt'] ?? '';
|