@kerfjs/ui 5.0.0-beta.22 → 5.0.0-beta.23
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 +11 -3
- package/ai/component-catalog-v2.json +223 -0
- package/ai/component-catalog.json +237 -0
- package/ai/component-catalog.schema.json +1 -0
- package/ai/public-api-signatures-v1.md +1 -1
- package/ai/webawesome-jsx-signatures-v1.md +1 -1
- package/analyzer/index.mjs +2 -8
- package/docs/component-selection.md +12 -0
- package/docs/ui-analyzer.md +5 -0
- package/docs/ui-doctor.md +6 -1
- package/docs/ux-demo.md +1 -1
- package/docs/workbench.md +13 -0
- package/doctor/eslint-diagnostics.d.mts +8 -0
- package/doctor/eslint-diagnostics.mjs +7 -0
- package/doctor/index.mjs +8 -10
- package/package.json +2 -1
- package/traversal-exclusions.mjs +21 -0
package/README.md
CHANGED
|
@@ -146,6 +146,13 @@ as a `New` marker.
|
|
|
146
146
|
| `PanelHeader` | `@kerfjs/ui/panel-header` | `@kerfjs/ui/panel-header.css` |
|
|
147
147
|
| `ValueTable`, `ValueTableRow` | `@kerfjs/ui/value-table` | `@kerfjs/ui/value-table.css` |
|
|
148
148
|
|
|
149
|
+
Opt-in application layouts keep JavaScript and CSS explicit. For the
|
|
150
|
+
desktop-class multi-panel shell, import `Workbench` from
|
|
151
|
+
`@kerfjs/ui/workbench` and load `@kerfjs/ui/workbench.css`; its supported
|
|
152
|
+
classes and size tokens are cataloged under the `workbench` entry. See
|
|
153
|
+
[`docs/workbench.md`](./docs/workbench.md) for panel ownership and responsive
|
|
154
|
+
replacement guidance.
|
|
155
|
+
|
|
149
156
|
`PanelHeader` is a plain `Toolbar` used as a panel, dialog, or page heading: an
|
|
150
157
|
optional icon control group (given a brand fill with a matching border), the
|
|
151
158
|
title as extra-large `ToolbarText`, the app's trailing action controls, and an
|
|
@@ -331,9 +338,10 @@ that convenience import, also import `@kerfjs/ui/styles.css`, which deliberately
|
|
|
331
338
|
contains the complete layer. Non-browser/SSR tools resolve the pure `import`
|
|
332
339
|
condition automatically; `@kerfjs/ui/unstyled` is the explicit CSS-free root
|
|
333
340
|
entry for a browser build with a custom styling pipeline. The exported
|
|
334
|
-
|
|
335
|
-
delivery.
|
|
336
|
-
|
|
341
|
+
`@kerfjs/ui/foundation.css` and component CSS paths remain available for fully
|
|
342
|
+
manual delivery. Its complete supported `--kui-*` token surface is cataloged
|
|
343
|
+
under the `foundation` entry. Load application overrides after package styles,
|
|
344
|
+
or scope variables directly on a component instance.
|
|
337
345
|
|
|
338
346
|
## Pane and content geometry
|
|
339
347
|
|
|
@@ -141,6 +141,157 @@
|
|
|
141
141
|
"composition": "generated-permissive-default"
|
|
142
142
|
}
|
|
143
143
|
},
|
|
144
|
+
{
|
|
145
|
+
"key": "@kerfjs/ui:foundation",
|
|
146
|
+
"package": "@kerfjs/ui",
|
|
147
|
+
"id": "foundation",
|
|
148
|
+
"name": "Foundation tokens",
|
|
149
|
+
"kind": "composition",
|
|
150
|
+
"source": "kerf",
|
|
151
|
+
"parents": { "mode": "any", "entries": [] },
|
|
152
|
+
"contexts": ["application-ui"],
|
|
153
|
+
"zones": [],
|
|
154
|
+
"children": { "mode": "any", "concepts": [], "requiredConcepts": [] },
|
|
155
|
+
"state": [
|
|
156
|
+
{
|
|
157
|
+
"id": "application theme overrides",
|
|
158
|
+
"owner": "application",
|
|
159
|
+
"required": false
|
|
160
|
+
},
|
|
161
|
+
{
|
|
162
|
+
"id": "responsive policy at the cataloged device-class breakpoints",
|
|
163
|
+
"owner": "application",
|
|
164
|
+
"required": false
|
|
165
|
+
}
|
|
166
|
+
],
|
|
167
|
+
"wiring": { "required": false, "helpers": [], "obligations": [] },
|
|
168
|
+
"responsive": { "owner": "not-applicable", "behaviors": [] },
|
|
169
|
+
"layout": {
|
|
170
|
+
"roles": ["foundation"],
|
|
171
|
+
"geometry": { "margin": "none", "border": "none", "padding": "none" }
|
|
172
|
+
},
|
|
173
|
+
"accessibility": {
|
|
174
|
+
"obligations": [
|
|
175
|
+
"Preserve semantic contrast relationships and the visible focus ring when overriding foundation colors."
|
|
176
|
+
]
|
|
177
|
+
},
|
|
178
|
+
"boundaries": {
|
|
179
|
+
"rootClass": null,
|
|
180
|
+
"publicClasses": [],
|
|
181
|
+
"publicTokens": [
|
|
182
|
+
"--kui-font-sans",
|
|
183
|
+
"--kui-font-mono",
|
|
184
|
+
"--kui-font-2xs",
|
|
185
|
+
"--kui-font-xs",
|
|
186
|
+
"--kui-font-s",
|
|
187
|
+
"--kui-font-m",
|
|
188
|
+
"--kui-font-l",
|
|
189
|
+
"--kui-font-2xl",
|
|
190
|
+
"--kui-font-weight-semibold",
|
|
191
|
+
"--kui-space-none",
|
|
192
|
+
"--kui-space-2xs",
|
|
193
|
+
"--kui-space-xs",
|
|
194
|
+
"--kui-space-s",
|
|
195
|
+
"--kui-space-m",
|
|
196
|
+
"--kui-space-l",
|
|
197
|
+
"--kui-space-xl",
|
|
198
|
+
"--kui-bp-mobile",
|
|
199
|
+
"--kui-bp-tablet",
|
|
200
|
+
"--kui-bp-desktop",
|
|
201
|
+
"--kui-bp-xl-desktop",
|
|
202
|
+
"--kui-layout-inline-margin",
|
|
203
|
+
"--kui-layout-item-border-width",
|
|
204
|
+
"--kui-layout-item-padding",
|
|
205
|
+
"--kui-layout-item-gap",
|
|
206
|
+
"--kui-layout-content-gap",
|
|
207
|
+
"--kui-layout-control-gap",
|
|
208
|
+
"--kui-layout-metadata-gap",
|
|
209
|
+
"--kui-layout-rounded-radius",
|
|
210
|
+
"--kui-layout-pill-radius",
|
|
211
|
+
"--kui-toolbar-group-inner-size",
|
|
212
|
+
"--kui-toolbar-group-size",
|
|
213
|
+
"--kui-toolbar-gap",
|
|
214
|
+
"--kui-radius-s",
|
|
215
|
+
"--kui-radius-m",
|
|
216
|
+
"--kui-radius-l",
|
|
217
|
+
"--kui-radius-circle",
|
|
218
|
+
"--kui-radius-pill",
|
|
219
|
+
"--kui-disclosure-icon-scale",
|
|
220
|
+
"--kui-color-surface",
|
|
221
|
+
"--kui-color-surface-raised",
|
|
222
|
+
"--kui-color-surface-lowered",
|
|
223
|
+
"--kui-color-text",
|
|
224
|
+
"--kui-color-text-quiet",
|
|
225
|
+
"--kui-color-text-link",
|
|
226
|
+
"--kui-color-neutral-fill-quiet",
|
|
227
|
+
"--kui-color-neutral-fill-normal",
|
|
228
|
+
"--kui-color-neutral-fill-loud",
|
|
229
|
+
"--kui-color-neutral-border-quiet",
|
|
230
|
+
"--kui-color-neutral-border-normal",
|
|
231
|
+
"--kui-color-neutral-border-loud",
|
|
232
|
+
"--kui-color-neutral-on-quiet",
|
|
233
|
+
"--kui-color-neutral-on-normal",
|
|
234
|
+
"--kui-color-neutral-on-loud",
|
|
235
|
+
"--kui-color-brand-fill-loud",
|
|
236
|
+
"--kui-color-brand-fill-quiet",
|
|
237
|
+
"--kui-color-brand-fill-normal",
|
|
238
|
+
"--kui-color-brand-border-quiet",
|
|
239
|
+
"--kui-color-brand-border-normal",
|
|
240
|
+
"--kui-color-brand-border-loud",
|
|
241
|
+
"--kui-color-brand-on-quiet",
|
|
242
|
+
"--kui-color-brand-on-normal",
|
|
243
|
+
"--kui-color-brand-on-loud",
|
|
244
|
+
"--kui-color-brand-on-fill",
|
|
245
|
+
"--kui-color-success-fill-loud",
|
|
246
|
+
"--kui-color-success-fill-quiet",
|
|
247
|
+
"--kui-color-success-fill-normal",
|
|
248
|
+
"--kui-color-success-border-quiet",
|
|
249
|
+
"--kui-color-success-border-normal",
|
|
250
|
+
"--kui-color-success-border-loud",
|
|
251
|
+
"--kui-color-success-on-quiet",
|
|
252
|
+
"--kui-color-success-on-normal",
|
|
253
|
+
"--kui-color-success-on-loud",
|
|
254
|
+
"--kui-color-success-on-fill",
|
|
255
|
+
"--kui-color-warning-fill-loud",
|
|
256
|
+
"--kui-color-warning-fill-quiet",
|
|
257
|
+
"--kui-color-warning-fill-normal",
|
|
258
|
+
"--kui-color-warning-border-quiet",
|
|
259
|
+
"--kui-color-warning-border-normal",
|
|
260
|
+
"--kui-color-warning-border-loud",
|
|
261
|
+
"--kui-color-warning-on-quiet",
|
|
262
|
+
"--kui-color-warning-on-normal",
|
|
263
|
+
"--kui-color-warning-on-loud",
|
|
264
|
+
"--kui-color-warning-on-fill",
|
|
265
|
+
"--kui-color-danger-fill-loud",
|
|
266
|
+
"--kui-color-danger-fill-quiet",
|
|
267
|
+
"--kui-color-danger-fill-normal",
|
|
268
|
+
"--kui-color-danger-border-quiet",
|
|
269
|
+
"--kui-color-danger-border-normal",
|
|
270
|
+
"--kui-color-danger-border-loud",
|
|
271
|
+
"--kui-color-danger-on-quiet",
|
|
272
|
+
"--kui-color-danger-on-normal",
|
|
273
|
+
"--kui-color-danger-on-loud",
|
|
274
|
+
"--kui-color-border",
|
|
275
|
+
"--kui-color-border-quiet",
|
|
276
|
+
"--kui-color-accent",
|
|
277
|
+
"--kui-color-accent-text",
|
|
278
|
+
"--kui-color-success",
|
|
279
|
+
"--kui-color-success-text",
|
|
280
|
+
"--kui-color-warning",
|
|
281
|
+
"--kui-color-warning-text",
|
|
282
|
+
"--kui-color-danger",
|
|
283
|
+
"--kui-color-danger-text",
|
|
284
|
+
"--kui-focus-ring",
|
|
285
|
+
"--kui-shadow-s",
|
|
286
|
+
"--kui-shadow-l"
|
|
287
|
+
]
|
|
288
|
+
},
|
|
289
|
+
"diagnostics": [],
|
|
290
|
+
"provenance": {
|
|
291
|
+
"selection": "ai/component-catalog.json",
|
|
292
|
+
"composition": "generated-permissive-default"
|
|
293
|
+
}
|
|
294
|
+
},
|
|
144
295
|
{
|
|
145
296
|
"key": "@kerfjs/ui:layout",
|
|
146
297
|
"package": "@kerfjs/ui",
|
|
@@ -282,6 +433,78 @@
|
|
|
282
433
|
"composition": "generated-permissive-default"
|
|
283
434
|
}
|
|
284
435
|
},
|
|
436
|
+
{
|
|
437
|
+
"key": "@kerfjs/ui:workbench",
|
|
438
|
+
"package": "@kerfjs/ui",
|
|
439
|
+
"id": "workbench",
|
|
440
|
+
"name": "Workbench",
|
|
441
|
+
"kind": "component",
|
|
442
|
+
"source": "kerf",
|
|
443
|
+
"parents": { "mode": "any", "entries": [] },
|
|
444
|
+
"contexts": ["application-ui"],
|
|
445
|
+
"zones": [],
|
|
446
|
+
"children": { "mode": "any", "concepts": [], "requiredConcepts": [] },
|
|
447
|
+
"state": [
|
|
448
|
+
{
|
|
449
|
+
"id": "panel presence and content",
|
|
450
|
+
"owner": "application",
|
|
451
|
+
"required": false
|
|
452
|
+
},
|
|
453
|
+
{ "id": "collapsed state", "owner": "application", "required": false },
|
|
454
|
+
{ "id": "panel sizes", "owner": "application", "required": false },
|
|
455
|
+
{
|
|
456
|
+
"id": "responsive replacement below desktop",
|
|
457
|
+
"owner": "application",
|
|
458
|
+
"required": false
|
|
459
|
+
},
|
|
460
|
+
{
|
|
461
|
+
"id": "collapse controls and focus policy",
|
|
462
|
+
"owner": "application",
|
|
463
|
+
"required": false
|
|
464
|
+
}
|
|
465
|
+
],
|
|
466
|
+
"wiring": { "required": false, "helpers": [], "obligations": [] },
|
|
467
|
+
"responsive": { "owner": "not-applicable", "behaviors": [] },
|
|
468
|
+
"layout": {
|
|
469
|
+
"roles": ["structure"],
|
|
470
|
+
"geometry": {
|
|
471
|
+
"margin": "none",
|
|
472
|
+
"border": "self",
|
|
473
|
+
"padding": "child",
|
|
474
|
+
"notes": [
|
|
475
|
+
"Workbench owns the rail and drawer separators; each region's content owns its internal padding and scroll behavior."
|
|
476
|
+
]
|
|
477
|
+
}
|
|
478
|
+
},
|
|
479
|
+
"accessibility": {
|
|
480
|
+
"obligations": [
|
|
481
|
+
"Give the Workbench and each meaningful rail or drawer an accessible label.",
|
|
482
|
+
"Keep collapse controls outside the disappearing region and move focus when a controlled rerender replaces a collapse control with its restore control."
|
|
483
|
+
]
|
|
484
|
+
},
|
|
485
|
+
"boundaries": {
|
|
486
|
+
"rootClass": "kui-workbench",
|
|
487
|
+
"publicClasses": [
|
|
488
|
+
"kui-workbench",
|
|
489
|
+
"kui-workbench__rail",
|
|
490
|
+
"kui-workbench__rail--left",
|
|
491
|
+
"kui-workbench__rail--right",
|
|
492
|
+
"kui-workbench__center",
|
|
493
|
+
"kui-workbench__main",
|
|
494
|
+
"kui-workbench__drawer",
|
|
495
|
+
"kui-workbench__panel-content"
|
|
496
|
+
],
|
|
497
|
+
"publicTokens": [
|
|
498
|
+
"--kui-workbench-rail-width",
|
|
499
|
+
"--kui-workbench-drawer-height"
|
|
500
|
+
]
|
|
501
|
+
},
|
|
502
|
+
"diagnostics": [],
|
|
503
|
+
"provenance": {
|
|
504
|
+
"selection": "ai/component-catalog.json",
|
|
505
|
+
"composition": "generated-permissive-default"
|
|
506
|
+
}
|
|
507
|
+
},
|
|
285
508
|
{
|
|
286
509
|
"key": "@kerfjs/ui:sunken-panel",
|
|
287
510
|
"package": "@kerfjs/ui",
|
|
@@ -248,6 +248,160 @@
|
|
|
248
248
|
"recipe": "docs/webawesome-theme.md#component-selection-guidance"
|
|
249
249
|
}
|
|
250
250
|
},
|
|
251
|
+
{
|
|
252
|
+
"id": "foundation",
|
|
253
|
+
"name": "Foundation tokens",
|
|
254
|
+
"category": "Foundation",
|
|
255
|
+
"kind": "composition",
|
|
256
|
+
"source": "kerf",
|
|
257
|
+
"description": "The complete public typography, spacing, breakpoint, geometry, radius, color, focus, and shadow token surface shipped by foundation.css.",
|
|
258
|
+
"uses": [],
|
|
259
|
+
"purpose": "Provide the shared semantic token foundation for application themes and every styled Kerf UI component.",
|
|
260
|
+
"publicExports": [],
|
|
261
|
+
"useWhen": [
|
|
262
|
+
"Theme a Kerf application globally or reuse the shipped semantic typography, spacing, geometry, color, focus, and shadow values in application-owned composition CSS."
|
|
263
|
+
],
|
|
264
|
+
"avoidWhen": [
|
|
265
|
+
"Do not replace a component-specific prop or token with a broad foundation override when only one component instance should change."
|
|
266
|
+
],
|
|
267
|
+
"alternatives": [],
|
|
268
|
+
"appOwns": [
|
|
269
|
+
"application theme overrides",
|
|
270
|
+
"responsive policy at the cataloged device-class breakpoints"
|
|
271
|
+
],
|
|
272
|
+
"variants": [
|
|
273
|
+
"light",
|
|
274
|
+
"dark"
|
|
275
|
+
],
|
|
276
|
+
"accessibility": [
|
|
277
|
+
"Preserve semantic contrast relationships and the visible focus ring when overriding foundation colors."
|
|
278
|
+
],
|
|
279
|
+
"geometry": {
|
|
280
|
+
"margin": "none",
|
|
281
|
+
"border": "none",
|
|
282
|
+
"padding": "none"
|
|
283
|
+
},
|
|
284
|
+
"delivery": {
|
|
285
|
+
"manualCssImport": "@kerfjs/ui/foundation.css",
|
|
286
|
+
"sideEffects": [
|
|
287
|
+
"css"
|
|
288
|
+
]
|
|
289
|
+
},
|
|
290
|
+
"wiring": [],
|
|
291
|
+
"publicClasses": [],
|
|
292
|
+
"publicTokens": [
|
|
293
|
+
"--kui-font-sans",
|
|
294
|
+
"--kui-font-mono",
|
|
295
|
+
"--kui-font-2xs",
|
|
296
|
+
"--kui-font-xs",
|
|
297
|
+
"--kui-font-s",
|
|
298
|
+
"--kui-font-m",
|
|
299
|
+
"--kui-font-l",
|
|
300
|
+
"--kui-font-2xl",
|
|
301
|
+
"--kui-font-weight-semibold",
|
|
302
|
+
"--kui-space-none",
|
|
303
|
+
"--kui-space-2xs",
|
|
304
|
+
"--kui-space-xs",
|
|
305
|
+
"--kui-space-s",
|
|
306
|
+
"--kui-space-m",
|
|
307
|
+
"--kui-space-l",
|
|
308
|
+
"--kui-space-xl",
|
|
309
|
+
"--kui-bp-mobile",
|
|
310
|
+
"--kui-bp-tablet",
|
|
311
|
+
"--kui-bp-desktop",
|
|
312
|
+
"--kui-bp-xl-desktop",
|
|
313
|
+
"--kui-layout-inline-margin",
|
|
314
|
+
"--kui-layout-item-border-width",
|
|
315
|
+
"--kui-layout-item-padding",
|
|
316
|
+
"--kui-layout-item-gap",
|
|
317
|
+
"--kui-layout-content-gap",
|
|
318
|
+
"--kui-layout-control-gap",
|
|
319
|
+
"--kui-layout-metadata-gap",
|
|
320
|
+
"--kui-layout-rounded-radius",
|
|
321
|
+
"--kui-layout-pill-radius",
|
|
322
|
+
"--kui-toolbar-group-inner-size",
|
|
323
|
+
"--kui-toolbar-group-size",
|
|
324
|
+
"--kui-toolbar-gap",
|
|
325
|
+
"--kui-radius-s",
|
|
326
|
+
"--kui-radius-m",
|
|
327
|
+
"--kui-radius-l",
|
|
328
|
+
"--kui-radius-circle",
|
|
329
|
+
"--kui-radius-pill",
|
|
330
|
+
"--kui-disclosure-icon-scale",
|
|
331
|
+
"--kui-color-surface",
|
|
332
|
+
"--kui-color-surface-raised",
|
|
333
|
+
"--kui-color-surface-lowered",
|
|
334
|
+
"--kui-color-text",
|
|
335
|
+
"--kui-color-text-quiet",
|
|
336
|
+
"--kui-color-text-link",
|
|
337
|
+
"--kui-color-neutral-fill-quiet",
|
|
338
|
+
"--kui-color-neutral-fill-normal",
|
|
339
|
+
"--kui-color-neutral-fill-loud",
|
|
340
|
+
"--kui-color-neutral-border-quiet",
|
|
341
|
+
"--kui-color-neutral-border-normal",
|
|
342
|
+
"--kui-color-neutral-border-loud",
|
|
343
|
+
"--kui-color-neutral-on-quiet",
|
|
344
|
+
"--kui-color-neutral-on-normal",
|
|
345
|
+
"--kui-color-neutral-on-loud",
|
|
346
|
+
"--kui-color-brand-fill-loud",
|
|
347
|
+
"--kui-color-brand-fill-quiet",
|
|
348
|
+
"--kui-color-brand-fill-normal",
|
|
349
|
+
"--kui-color-brand-border-quiet",
|
|
350
|
+
"--kui-color-brand-border-normal",
|
|
351
|
+
"--kui-color-brand-border-loud",
|
|
352
|
+
"--kui-color-brand-on-quiet",
|
|
353
|
+
"--kui-color-brand-on-normal",
|
|
354
|
+
"--kui-color-brand-on-loud",
|
|
355
|
+
"--kui-color-brand-on-fill",
|
|
356
|
+
"--kui-color-success-fill-loud",
|
|
357
|
+
"--kui-color-success-fill-quiet",
|
|
358
|
+
"--kui-color-success-fill-normal",
|
|
359
|
+
"--kui-color-success-border-quiet",
|
|
360
|
+
"--kui-color-success-border-normal",
|
|
361
|
+
"--kui-color-success-border-loud",
|
|
362
|
+
"--kui-color-success-on-quiet",
|
|
363
|
+
"--kui-color-success-on-normal",
|
|
364
|
+
"--kui-color-success-on-loud",
|
|
365
|
+
"--kui-color-success-on-fill",
|
|
366
|
+
"--kui-color-warning-fill-loud",
|
|
367
|
+
"--kui-color-warning-fill-quiet",
|
|
368
|
+
"--kui-color-warning-fill-normal",
|
|
369
|
+
"--kui-color-warning-border-quiet",
|
|
370
|
+
"--kui-color-warning-border-normal",
|
|
371
|
+
"--kui-color-warning-border-loud",
|
|
372
|
+
"--kui-color-warning-on-quiet",
|
|
373
|
+
"--kui-color-warning-on-normal",
|
|
374
|
+
"--kui-color-warning-on-loud",
|
|
375
|
+
"--kui-color-warning-on-fill",
|
|
376
|
+
"--kui-color-danger-fill-loud",
|
|
377
|
+
"--kui-color-danger-fill-quiet",
|
|
378
|
+
"--kui-color-danger-fill-normal",
|
|
379
|
+
"--kui-color-danger-border-quiet",
|
|
380
|
+
"--kui-color-danger-border-normal",
|
|
381
|
+
"--kui-color-danger-border-loud",
|
|
382
|
+
"--kui-color-danger-on-quiet",
|
|
383
|
+
"--kui-color-danger-on-normal",
|
|
384
|
+
"--kui-color-danger-on-loud",
|
|
385
|
+
"--kui-color-border",
|
|
386
|
+
"--kui-color-border-quiet",
|
|
387
|
+
"--kui-color-accent",
|
|
388
|
+
"--kui-color-accent-text",
|
|
389
|
+
"--kui-color-success",
|
|
390
|
+
"--kui-color-success-text",
|
|
391
|
+
"--kui-color-warning",
|
|
392
|
+
"--kui-color-warning-text",
|
|
393
|
+
"--kui-color-danger",
|
|
394
|
+
"--kui-color-danger-text",
|
|
395
|
+
"--kui-focus-ring",
|
|
396
|
+
"--kui-shadow-s",
|
|
397
|
+
"--kui-shadow-l"
|
|
398
|
+
],
|
|
399
|
+
"links": {
|
|
400
|
+
"catalogRoute": "?component=foundation",
|
|
401
|
+
"documentation": "docs/component-selection.md",
|
|
402
|
+
"recipe": "docs/component-selection.md#foundation-tokens"
|
|
403
|
+
}
|
|
404
|
+
},
|
|
251
405
|
{
|
|
252
406
|
"id": "layout",
|
|
253
407
|
"name": "Application layout",
|
|
@@ -401,6 +555,89 @@
|
|
|
401
555
|
"recipe": "docs/layout.md#anatomy"
|
|
402
556
|
}
|
|
403
557
|
},
|
|
558
|
+
{
|
|
559
|
+
"id": "workbench",
|
|
560
|
+
"name": "Workbench",
|
|
561
|
+
"category": "Structure",
|
|
562
|
+
"kind": "component",
|
|
563
|
+
"source": "kerf",
|
|
564
|
+
"description": "A desktop-class multi-panel workspace with independently collapsible left and right rails and a bottom drawer around one central work area.",
|
|
565
|
+
"uses": [],
|
|
566
|
+
"purpose": "Arrange a complex tool or editor as a stable central work area with optional peripheral rails and a bottom drawer.",
|
|
567
|
+
"publicExports": [
|
|
568
|
+
"Workbench",
|
|
569
|
+
"WorkbenchPanel",
|
|
570
|
+
"WorkbenchProps"
|
|
571
|
+
],
|
|
572
|
+
"useWhen": [
|
|
573
|
+
"A desktop-class tool needs a central work area plus independently collapsible navigator, inspector, or console regions."
|
|
574
|
+
],
|
|
575
|
+
"avoidWhen": [
|
|
576
|
+
"Do not shrink the full multi-panel shell onto compact devices; present peripheral content through NavStack or overlay drawers instead.",
|
|
577
|
+
"Do not use Workbench for one standalone collapsible rail or drawer; use CollapsiblePanel."
|
|
578
|
+
],
|
|
579
|
+
"alternatives": [
|
|
580
|
+
{
|
|
581
|
+
"id": "pane",
|
|
582
|
+
"relationship": "composes-with",
|
|
583
|
+
"when": "Use Pane inside Workbench regions when fixed header/footer chrome must surround one scroll owner."
|
|
584
|
+
}
|
|
585
|
+
],
|
|
586
|
+
"appOwns": [
|
|
587
|
+
"panel presence and content",
|
|
588
|
+
"collapsed state",
|
|
589
|
+
"panel sizes",
|
|
590
|
+
"responsive replacement below desktop",
|
|
591
|
+
"collapse controls and focus policy"
|
|
592
|
+
],
|
|
593
|
+
"variants": [
|
|
594
|
+
"main only",
|
|
595
|
+
"left rail",
|
|
596
|
+
"right rail",
|
|
597
|
+
"bottom drawer",
|
|
598
|
+
"all panels",
|
|
599
|
+
"independently collapsed panels"
|
|
600
|
+
],
|
|
601
|
+
"accessibility": [
|
|
602
|
+
"Give the Workbench and each meaningful rail or drawer an accessible label.",
|
|
603
|
+
"Keep collapse controls outside the disappearing region and move focus when a controlled rerender replaces a collapse control with its restore control."
|
|
604
|
+
],
|
|
605
|
+
"geometry": {
|
|
606
|
+
"margin": "none",
|
|
607
|
+
"border": "self",
|
|
608
|
+
"padding": "child",
|
|
609
|
+
"notes": [
|
|
610
|
+
"Workbench owns the rail and drawer separators; each region's content owns its internal padding and scroll behavior."
|
|
611
|
+
]
|
|
612
|
+
},
|
|
613
|
+
"delivery": {
|
|
614
|
+
"moduleImport": "@kerfjs/ui/workbench",
|
|
615
|
+
"manualCssImport": "@kerfjs/ui/workbench.css",
|
|
616
|
+
"sideEffects": [
|
|
617
|
+
"manual-css"
|
|
618
|
+
]
|
|
619
|
+
},
|
|
620
|
+
"wiring": [],
|
|
621
|
+
"publicClasses": [
|
|
622
|
+
"kui-workbench",
|
|
623
|
+
"kui-workbench__rail",
|
|
624
|
+
"kui-workbench__rail--left",
|
|
625
|
+
"kui-workbench__rail--right",
|
|
626
|
+
"kui-workbench__center",
|
|
627
|
+
"kui-workbench__main",
|
|
628
|
+
"kui-workbench__drawer",
|
|
629
|
+
"kui-workbench__panel-content"
|
|
630
|
+
],
|
|
631
|
+
"publicTokens": [
|
|
632
|
+
"--kui-workbench-rail-width",
|
|
633
|
+
"--kui-workbench-drawer-height"
|
|
634
|
+
],
|
|
635
|
+
"links": {
|
|
636
|
+
"catalogRoute": "?component=workbench",
|
|
637
|
+
"documentation": "docs/workbench.md",
|
|
638
|
+
"recipe": "docs/workbench.md#state-lives-in-the-app"
|
|
639
|
+
}
|
|
640
|
+
},
|
|
404
641
|
{
|
|
405
642
|
"id": "sunken-panel",
|
|
406
643
|
"name": "SunkenPanel",
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Public API signatures for the UI authoring corpus
|
|
2
2
|
|
|
3
|
-
Generated from emitted declarations for `@kerfjs/ui@5.0.0-beta.
|
|
3
|
+
Generated from emitted declarations for `@kerfjs/ui@5.0.0-beta.23` and `kerfjs@5.0.0-beta.23`. This bounded reference covers only APIs used by the seven-task corpus. It is interface evidence, not an implementation or runtime guarantee.
|
|
4
4
|
|
|
5
5
|
## `@kerfjs/ui/disclosure-arrow`
|
|
6
6
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Web Awesome JSX signatures for the UI authoring corpus
|
|
2
2
|
|
|
3
|
-
Generated from the emitted `@kerfjs/ui@5.0.0-beta.
|
|
3
|
+
Generated from the emitted `@kerfjs/ui@5.0.0-beta.23` declaration boundary. Import `@kerfjs/ui/webawesome` for type effects when authoring direct `wa-*` JSX. The module emits no runtime behavior and does not register custom elements.
|
|
4
4
|
|
|
5
5
|
```ts
|
|
6
6
|
import { KerfCustomElement } from 'kerfjs/jsx-runtime';
|
package/analyzer/index.mjs
CHANGED
|
@@ -13,6 +13,7 @@ import postcss from 'postcss';
|
|
|
13
13
|
import ts from 'typescript';
|
|
14
14
|
|
|
15
15
|
import { loadApplicationUiProfile } from '../ai/application-ui-profile.mjs';
|
|
16
|
+
import { isUiTraversalExcluded } from '../traversal-exclusions.mjs';
|
|
16
17
|
|
|
17
18
|
export const UI_ANALYSIS_SCHEMA_VERSION = 1;
|
|
18
19
|
|
|
@@ -36,16 +37,10 @@ const spacingProperties = /^(?:margin|padding|gap|inset)(?:-|$)/;
|
|
|
36
37
|
const dimensionProperties =
|
|
37
38
|
/^(?:width|height|min-width|max-width|min-height|max-height)$/;
|
|
38
39
|
const approvedSpacing = new Set([0, 4, 8, 16, 24]);
|
|
39
|
-
const ignoredDirectories = new Set([
|
|
40
|
-
'.git',
|
|
41
|
-
'coverage',
|
|
42
|
-
'dist',
|
|
43
|
-
'node_modules',
|
|
44
|
-
]);
|
|
45
|
-
|
|
46
40
|
async function collectFiles(root, paths) {
|
|
47
41
|
const files = [];
|
|
48
42
|
const visit = async (path) => {
|
|
43
|
+
if (isUiTraversalExcluded(root, path)) return;
|
|
49
44
|
const details = await stat(path);
|
|
50
45
|
if (details.isFile()) {
|
|
51
46
|
if (sourceExtensions.has(extname(path)) || path.endsWith('.css'))
|
|
@@ -54,7 +49,6 @@ async function collectFiles(root, paths) {
|
|
|
54
49
|
}
|
|
55
50
|
const entries = await readdir(path, { withFileTypes: true });
|
|
56
51
|
for (const entry of entries) {
|
|
57
|
-
if (entry.isDirectory() && ignoredDirectories.has(entry.name)) continue;
|
|
58
52
|
const child = resolve(path, entry.name);
|
|
59
53
|
if (entry.isDirectory()) await visit(child);
|
|
60
54
|
else if (
|
|
@@ -24,6 +24,18 @@ fix the surrounding layout instead of overriding a control. See
|
|
|
24
24
|
[`design-philosophy.md`](./design-philosophy.md) "Reach for the primitive, not for
|
|
25
25
|
CSS".
|
|
26
26
|
|
|
27
|
+
## Foundation tokens
|
|
28
|
+
|
|
29
|
+
Import `@kerfjs/ui/foundation.css` when application-owned composition CSS needs
|
|
30
|
+
the same semantic typography, spacing, device breakpoints, geometry, radii,
|
|
31
|
+
colors, focus ring, or shadows as Kerf components. Its complete supported
|
|
32
|
+
`--kui-*` surface is cataloged by the `foundation` entry; tools may treat that
|
|
33
|
+
entry as the public allowlist rather than inferring stability from CSS text.
|
|
34
|
+
Override these tokens globally for an application theme or on the narrowest
|
|
35
|
+
useful subtree. Prefer a component prop or component-specific token when the
|
|
36
|
+
change belongs to one component or instance, and preserve the documented
|
|
37
|
+
foreground/background contrast relationships and visible focus ring.
|
|
38
|
+
|
|
27
39
|
## Production recipes
|
|
28
40
|
|
|
29
41
|
Use the [complete recipe guide](./recipes.md) when several primitives form one
|
package/docs/ui-analyzer.md
CHANGED
|
@@ -28,6 +28,11 @@ its reachable project-local styles into the report, including quoted or
|
|
|
28
28
|
unquoted `url()` imports; external package styles remain outside the consumer
|
|
29
29
|
boundary.
|
|
30
30
|
|
|
31
|
+
Recursive discovery excludes generated and tool-owned trees, including any
|
|
32
|
+
nested `.claude/worktrees` checkout. Those checkouts are separate repositories,
|
|
33
|
+
not application source, and cannot contribute files, diagnostics, profile
|
|
34
|
+
policy, or analysis inputs to the containing application.
|
|
35
|
+
|
|
31
36
|
## Diagnostics and exit behavior
|
|
32
37
|
|
|
33
38
|
| Rule | Kind | Meaning |
|
package/docs/ui-doctor.md
CHANGED
|
@@ -15,7 +15,7 @@ The default terminal output is short and repair-oriented. `--format json` emits
|
|
|
15
15
|
|
|
16
16
|
The catalog stage discovers the package-default application UI profile and workspace/root-to-leaf directory layers. It validates referenced selection/composition catalogs and, when a workspace declares `package.json#kerfComponentCatalog`, invokes the installed `create-kerf-component` catalog checker to validate metadata, source exports, schema conformance, and generated-output drift. This checker reads source text; it does not import application modules.
|
|
17
17
|
|
|
18
|
-
TypeScript uses the compiler API with `noEmit`. ESLint loads the installed `eslint-plugin-kerfjs` `recommended-ui` preset (`--eslint strict-ui` opts into advisory rules as errors). Stable KUI identifiers come from the packaged `application-ui-diagnostic-ids-v1.json` registry; the doctor also reads installed ESLint message metadata for semantic conflict detection instead of duplicating rule definitions. The analyzer calls the public `@kerfjs/ui/analyzer` contract. None of these stages executes generated application code.
|
|
18
|
+
TypeScript uses the compiler API with `noEmit`. ESLint loads the installed `eslint-plugin-kerfjs` `recommended-ui` preset (`--eslint strict-ui` opts into advisory rules as errors). This is deliberately an isolated Kerf lint pass rather than the consumer's complete ESLint configuration. Inline directives for consumer-owned plugins, such as `@typescript-eslint`, therefore do not produce false "rule definition not found" diagnostics; the consumer's normal ESLint command remains authoritative for those rules. Unknown `kerfjs/*` directives still fail the doctor pass. Stable KUI identifiers come from the packaged `application-ui-diagnostic-ids-v1.json` registry; the doctor also reads installed ESLint message metadata for semantic conflict detection instead of duplicating rule definitions. The analyzer calls the public `@kerfjs/ui/analyzer` contract. None of these stages executes generated application code.
|
|
19
19
|
|
|
20
20
|
The browser evaluator is different: it runs the application and is disabled by default. It only runs when configuration supplies `browser.url` or the command receives `--browser-url`. Start and authorize the target application separately.
|
|
21
21
|
|
|
@@ -25,6 +25,11 @@ An unavailable or failed stage does not prevent independent stages from reportin
|
|
|
25
25
|
|
|
26
26
|
`--full` is the default and analyzes the selected package. `--changed` reads tracked and untracked paths from Git unless one or more `--path` values are supplied. An empty changed set is a configuration error instead of a false-clean success. With `--package`, workspace-relative Git paths are converted to package-relative paths before TypeScript, ESLint, and analyzer selection; paths outside the selected package are ignored.
|
|
27
27
|
|
|
28
|
+
Full traversal treats nested `.claude/worktrees` checkouts as tool-owned
|
|
29
|
+
repositories rather than application source. Their files are excluded
|
|
30
|
+
consistently from TypeScript, ESLint, analyzer discovery, and cache inputs, even
|
|
31
|
+
when the nested checkout lives below another application directory.
|
|
32
|
+
|
|
28
33
|
TypeScript constructs the selected package's program so compiler options retain their real meaning, while its root inputs are narrowed to changed source files. Use `--full` for release gates.
|
|
29
34
|
|
|
30
35
|
## Configuration and suppressions
|
package/docs/ux-demo.md
CHANGED
|
@@ -10,7 +10,7 @@ deterministic state, and semantic layout owners from the [recipe guide](./recipe
|
|
|
10
10
|
- The `ListActionRow` route demonstrates sibling primary/trailing native controls, independent disabled states, controlled selection, first-line leading-icon alignment for wrapped labels, and an application-owned native popover relationship without nesting controls. The `ListItem` route demonstrates the same multiline leading-icon anchor alongside its single-control navigation contract.
|
|
11
11
|
- The `AppTab` route demonstrates a runtime-filtered domain metadata slot and a decorative replacement close icon without changing TabBar selection, close, reorder, or focus ownership. The `ResizableRegion` route likewise replaces only the decorative handle glyph while retaining separator semantics and shared wiring.
|
|
12
12
|
- Every first-party visual component and every free Web Awesome 3.12 component has its own stable `?component=<id>` URL and focused demo. Composite header, menu, feedback, and theme scenarios remain addressable alongside their subcomponents; the root opens the first Kerf component.
|
|
13
|
-
- `ai/component-catalog.json` is the canonical catalog metadata. A deterministic checked-in projection supplies the demo's unique id, category, kind (`component`, `composition`, or `recipe`), source (`kerf` or `webawesome`), name, description, recommendation, direct `uses` dependencies, existing documentation path, and demo-source path; first-party, recipe, and Web Awesome renderer maps are exhaustively typed against its generated id unions. Non-supported Web Awesome recommendations project to a visible `Discouraged` sidebar tag, with Popup as the deliberate conditional exception. Demo paths resolve to the matching `ui/ux-demo/demos/<id>.tsx` or `ui/ux-demo/recipes/*.tsx` file, or to `ui/ux-demo/webawesome-demos.tsx` for Web Awesome entries. `ui/ux-demo/main.tsx` owns only the catalog shell, shared state, routing, and interaction wiring. First-party component entries additionally derive `ui/src/<
|
|
13
|
+
- `ai/component-catalog.json` is the canonical catalog metadata. A deterministic checked-in projection supplies the demo's unique id, category, kind (`component`, `composition`, or `recipe`), source (`kerf` or `webawesome`), name, description, recommendation, direct `uses` dependencies, existing documentation path, and demo-source path; first-party, recipe, and Web Awesome renderer maps are exhaustively typed against its generated id unions. Non-supported Web Awesome recommendations project to a visible `Discouraged` sidebar tag, with Popup as the deliberate conditional exception. Demo paths resolve to the matching `ui/ux-demo/demos/<id>.tsx` or `ui/ux-demo/recipes/*.tsx` file, or to `ui/ux-demo/webawesome-demos.tsx` for Web Awesome entries. `ui/ux-demo/main.tsx` owns only the catalog shell, shared state, routing, and interaction wiring. First-party component entries additionally derive `ui/src/<public-subpath>.tsx` from their canonical `delivery.browserImport` or opt-in `delivery.moduleImport`.
|
|
14
14
|
- Every detail footer groups compact `Demo source` and `Guidance` actions; first-party component details also expose `Component source`. Web Awesome details say `Integration guidance` to distinguish the local integration contract from the upstream component implementation. Each button retains its repository-relative path in the DOM for verification and uses a deploy-safe absolute GitHub blob URL with a contextual new-tab name; the demo does not depend on a local source server or add a package runtime export. At phone widths, the resource group and related-component selector stack as full-width rows, with any resource overflow contained locally so labels cannot overlap the selector or widen the document.
|
|
15
15
|
- The master/detail shell groups first-party routes by category with production `ListHeader` and `ListItem` components. Catalog entries can supply short reusable trailing tags; the Web Awesome projection uses them to label exactly the 15 discouraged choices. The 70 ecosystem components live in a separate `Web Awesome` disclosure with seven subgroups, so they remain discoverable without being presented as first-class `@kerfjs/ui` exports. Direct Web Awesome routes open the disclosure and reveal the selected row at wide sizes; narrow layouts keep the expanded list in document flow rather than introducing a competing nested scroller.
|
|
16
16
|
- The shell itself uses `@kerfjs/ui/layout.css`: sidebars, details, previews, dialogs, and resize specimens share unpadded panes plus self-contained content items. Its sidebar identity uses the Kerf logo beside a vertically centered title, with the subtitle in its own aligned row like `PanelHeader`; the current-view heading is also a toolbar. Collapsing the catalog removes the pane completely and moves its restore action to the main toolbar's leading edge instead of leaving an icon-only rail. The selected view description remains inset below the page toolbar. The checkerboard belongs to the complete scrollable preview region rather than a nested card. A lightly separated footer keeps live status above compact source, guidance, and relationship groups. The focused `ResizableRegion` specimen stretches its surface through the available stage height and reports committed width in that shared status footer; narrow layouts retain local horizontal access when the pane is resized wider than the stage, and the split remains readable at 200% root scaling. Geometry coverage checks wide, intermediate, narrow, and 200% zoom layouts.
|
package/docs/workbench.md
CHANGED
|
@@ -49,6 +49,19 @@ Each `WorkbenchPanel` takes `content`, an optional `collapsed`, an optional
|
|
|
49
49
|
`--kui-workbench-rail-width` 280px, `--kui-workbench-drawer-height` 220px), and
|
|
50
50
|
an optional `label`.
|
|
51
51
|
|
|
52
|
+
## Public styling boundary
|
|
53
|
+
|
|
54
|
+
Import `@kerfjs/ui/workbench.css` after the component subpath. Applications may
|
|
55
|
+
set `--kui-workbench-rail-width` and `--kui-workbench-drawer-height` on a
|
|
56
|
+
Workbench instance. The supported composition classes are `.kui-workbench`,
|
|
57
|
+
`.kui-workbench__rail`, `.kui-workbench__rail--left`,
|
|
58
|
+
`.kui-workbench__rail--right`, `.kui-workbench__center`,
|
|
59
|
+
`.kui-workbench__main`, `.kui-workbench__drawer`, and
|
|
60
|
+
`.kui-workbench__panel-content`; these exact hooks are cataloged for tools that
|
|
61
|
+
must classify public application selectors. Prefer the component props and two
|
|
62
|
+
size tokens before selecting internal anatomy, and do not target its data
|
|
63
|
+
attributes or descendant tags as styling contracts.
|
|
64
|
+
|
|
52
65
|
## How the collapse animates
|
|
53
66
|
|
|
54
67
|
Collapsing snaps the panel's flex track to zero in a single reflow (so the work
|
package/doctor/index.mjs
CHANGED
|
@@ -23,6 +23,8 @@ import { createRequire } from 'node:module';
|
|
|
23
23
|
import { loadApplicationUiProfile } from '../ai/application-ui-profile.mjs';
|
|
24
24
|
import { analyzeUiProject, UI_ANALYSIS_RULES } from '../analyzer/index.mjs';
|
|
25
25
|
import { evaluateUi, UI_EVALUATION_RULES } from '../evaluator/index.mjs';
|
|
26
|
+
import { isForeignRuleDefinitionDiagnostic } from './eslint-diagnostics.mjs';
|
|
27
|
+
import { isUiTraversalExcluded } from '../traversal-exclusions.mjs';
|
|
26
28
|
|
|
27
29
|
export const UI_DOCTOR_SCHEMA_VERSION = 1;
|
|
28
30
|
export const UI_DOCTOR_EXIT = Object.freeze({
|
|
@@ -54,14 +56,6 @@ const sourceExtensions = new Set([
|
|
|
54
56
|
'.cts',
|
|
55
57
|
'.css',
|
|
56
58
|
]);
|
|
57
|
-
const ignoredDirectories = new Set([
|
|
58
|
-
'.git',
|
|
59
|
-
'.kerf-cache',
|
|
60
|
-
'coverage',
|
|
61
|
-
'dist',
|
|
62
|
-
'kerf-ui-evidence',
|
|
63
|
-
'node_modules',
|
|
64
|
-
]);
|
|
65
59
|
const defaultStages = Object.freeze({
|
|
66
60
|
catalog: true,
|
|
67
61
|
typescript: true,
|
|
@@ -361,6 +355,7 @@ export async function resolveUiDoctorPackage(root, selector) {
|
|
|
361
355
|
async function collectInputs(root, paths) {
|
|
362
356
|
const result = [];
|
|
363
357
|
const visit = async (path) => {
|
|
358
|
+
if (isUiTraversalExcluded(root, path)) return;
|
|
364
359
|
let details;
|
|
365
360
|
try {
|
|
366
361
|
details = await stat(path);
|
|
@@ -381,7 +376,6 @@ async function collectInputs(root, paths) {
|
|
|
381
376
|
return;
|
|
382
377
|
}
|
|
383
378
|
for (const entry of await readdir(path, { withFileTypes: true })) {
|
|
384
|
-
if (entry.isDirectory() && ignoredDirectories.has(entry.name)) continue;
|
|
385
379
|
await visit(resolve(path, entry.name));
|
|
386
380
|
}
|
|
387
381
|
};
|
|
@@ -777,6 +771,9 @@ async function runTypeScript({ packageRoot, paths }) {
|
|
|
777
771
|
{ ...ts.default.sys, onUnRecoverableConfigFileDiagnostic: () => {} },
|
|
778
772
|
);
|
|
779
773
|
if (!parsed) throw new Error('TypeScript could not parse tsconfig.json.');
|
|
774
|
+
parsed.fileNames = parsed.fileNames.filter(
|
|
775
|
+
(file) => !isUiTraversalExcluded(packageRoot, file),
|
|
776
|
+
);
|
|
780
777
|
if (paths?.length) {
|
|
781
778
|
const selected = new Set(paths.map((path) => resolve(packageRoot, path)));
|
|
782
779
|
parsed.fileNames = parsed.fileNames.filter((file) => selected.has(file));
|
|
@@ -850,7 +847,7 @@ async function runEslint({
|
|
|
850
847
|
},
|
|
851
848
|
},
|
|
852
849
|
};
|
|
853
|
-
const configs = [base];
|
|
850
|
+
const configs = [{ ignores: ['**/.claude/worktrees/**'] }, base];
|
|
854
851
|
if (usesTypeScript) {
|
|
855
852
|
const parserModule = await importFrom(
|
|
856
853
|
packageRoot,
|
|
@@ -879,6 +876,7 @@ async function runEslint({
|
|
|
879
876
|
const diagnostics = [];
|
|
880
877
|
for (const result of results)
|
|
881
878
|
for (const item of result.messages) {
|
|
879
|
+
if (isForeignRuleDefinitionDiagnostic(item)) continue;
|
|
882
880
|
const code = item.message.match(/\bKUI-[A-Z]\d{3}\b/)?.[0];
|
|
883
881
|
diagnostics.push(
|
|
884
882
|
normalizedDiagnostic({
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kerfjs/ui",
|
|
3
|
-
"version": "5.0.0-beta.
|
|
3
|
+
"version": "5.0.0-beta.23",
|
|
4
4
|
"description": "Accessible, composable UI primitives for kerf applications.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -301,6 +301,7 @@
|
|
|
301
301
|
"analyzer",
|
|
302
302
|
"doctor",
|
|
303
303
|
"evaluator",
|
|
304
|
+
"traversal-exclusions.mjs",
|
|
304
305
|
"docs",
|
|
305
306
|
"ux-demo/recipes",
|
|
306
307
|
"llms.txt",
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { relative, sep } from 'node:path';
|
|
2
|
+
|
|
3
|
+
const ignoredDirectoryNames = new Set([
|
|
4
|
+
'.git',
|
|
5
|
+
'.kerf-cache',
|
|
6
|
+
'coverage',
|
|
7
|
+
'dist',
|
|
8
|
+
'kerf-ui-evidence',
|
|
9
|
+
'node_modules',
|
|
10
|
+
]);
|
|
11
|
+
|
|
12
|
+
export function isUiTraversalExcluded(root, candidate) {
|
|
13
|
+
const segments = relative(root, candidate).split(sep);
|
|
14
|
+
return (
|
|
15
|
+
segments.some((segment) => ignoredDirectoryNames.has(segment)) ||
|
|
16
|
+
segments.some(
|
|
17
|
+
(segment, index) =>
|
|
18
|
+
segment === '.claude' && segments[index + 1] === 'worktrees',
|
|
19
|
+
)
|
|
20
|
+
);
|
|
21
|
+
}
|