@kerfjs/ui 5.0.0-beta.53 → 5.0.0-beta.54

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (69) hide show
  1. package/README.md +1 -0
  2. package/ai/application-ui-diagnostic-ids-v1.json +1 -0
  3. package/ai/component-catalog-v2.json +82 -6
  4. package/ai/component-catalog-v2.schema.json +2 -1
  5. package/ai/component-catalog.json +105 -10
  6. package/ai/public-api-signatures-v1.md +204 -18
  7. package/ai/skill.md +23 -17
  8. package/ai/webawesome-jsx-signatures-v1.md +1 -1
  9. package/analyzer/index.mjs +48 -0
  10. package/analyzer/loud-pairs.d.mts +49 -0
  11. package/analyzer/loud-pairs.mjs +357 -0
  12. package/dist/app-tab.d.ts +7 -5
  13. package/dist/app-tab.js +1 -1
  14. package/dist/{chunk-EKYZCRCX.js → chunk-3CGQ7ZNO.js} +54 -22
  15. package/dist/chunk-3CGQ7ZNO.js.map +1 -0
  16. package/dist/{chunk-UKKSMZYT.js → chunk-46263QLK.js} +51 -1
  17. package/dist/chunk-46263QLK.js.map +1 -0
  18. package/dist/{chunk-NDUGJ4TU.js → chunk-5NDQABWK.js} +1 -1
  19. package/dist/{chunk-NDUGJ4TU.js.map → chunk-5NDQABWK.js.map} +1 -1
  20. package/dist/{chunk-CCMKJWLX.js → chunk-NE5JAOQS.js} +7 -7
  21. package/dist/chunk-NE5JAOQS.js.map +1 -0
  22. package/dist/chunk-PSHUSWQH.js +18 -0
  23. package/dist/chunk-PSHUSWQH.js.map +1 -0
  24. package/dist/{chunk-VOCPXGQN.js → chunk-VHADGP3B.js} +9 -8
  25. package/dist/chunk-VHADGP3B.js.map +1 -0
  26. package/dist/chunk-XQV2B4IL.js +14 -0
  27. package/dist/chunk-XQV2B4IL.js.map +1 -0
  28. package/dist/collapsible-panel.d.ts +6 -2
  29. package/dist/collapsible-panel.js +1 -0
  30. package/dist/collapsible-panel.js.map +1 -1
  31. package/dist/floating-toolbar.d.ts +5 -2
  32. package/dist/floating-toolbar.js +1 -1
  33. package/dist/index.js +6 -5
  34. package/dist/resizable-region.d.ts +4 -1
  35. package/dist/resizable-region.js +1 -1
  36. package/dist/split-view.js +1 -1
  37. package/dist/styles/collapsible-panel.css +88 -10
  38. package/dist/styles/floating-toolbar.css +11 -6
  39. package/dist/styles/resizable-region.css +81 -13
  40. package/dist/styles/workbench.css +472 -10
  41. package/dist/wire-resizable-regions.d.ts +2 -1
  42. package/dist/wire-resizable-regions.js +2 -1
  43. package/dist/wire-tab-bars.js +1 -1
  44. package/dist/wire-workbench.d.ts +109 -0
  45. package/dist/wire-workbench.js +355 -0
  46. package/dist/wire-workbench.js.map +1 -0
  47. package/dist/workbench.d.ts +65 -6
  48. package/dist/workbench.js +180 -76
  49. package/dist/workbench.js.map +1 -1
  50. package/docs/accessibility.md +54 -9
  51. package/docs/app-layouts.md +12 -1
  52. package/docs/collapsible-panel.md +59 -1
  53. package/docs/component-selection.md +16 -6
  54. package/docs/document-baseline.md +4 -0
  55. package/docs/layout.md +5 -1
  56. package/docs/recipes.md +5 -3
  57. package/docs/type-contracts.md +2 -1
  58. package/docs/ui-analyzer.md +94 -19
  59. package/docs/ui-doctor.md +6 -0
  60. package/docs/ux-demo.md +1 -1
  61. package/docs/webawesome-theme.md +11 -2
  62. package/docs/workbench.md +302 -7
  63. package/llms.txt +7 -3
  64. package/package.json +5 -1
  65. package/ux-demo/recipes/collapsible-sidebar.tsx +8 -7
  66. package/dist/chunk-CCMKJWLX.js.map +0 -1
  67. package/dist/chunk-EKYZCRCX.js.map +0 -1
  68. package/dist/chunk-UKKSMZYT.js.map +0 -1
  69. package/dist/chunk-VOCPXGQN.js.map +0 -1
@@ -25,6 +25,12 @@
25
25
  --kui-edge-inset-inline-end,
26
26
  var(--kui-safe-area-inline-end, env(safe-area-inset-right, 0px))
27
27
  );
28
+ /* The content keeps its fixed expanded size (collapsing slides it rather
29
+ than squeezing it), so a flex parent must never shrink the track below
30
+ that size: a shrunk track only clips the content's trailing edge (a
31
+ rail's row badges, a drawer's last row). The panel holds its size and
32
+ the sibling work area gives way. */
33
+ flex-shrink: 0;
28
34
  overflow: hidden;
29
35
  background: var(--kui-color-surface);
30
36
  }
@@ -265,37 +271,109 @@
265
271
  display: none;
266
272
  }
267
273
 
274
+ /* A collapsed panel's restore control floats in a corner of the panel's own
275
+ container, never of the viewport, so a panel embedded in a page cannot float
276
+ it over page content outside that container. The container becomes the
277
+ corner's containing block and isolates its stacking only while a restore
278
+ control is shown, at zero specificity so an app's own positioning of that
279
+ container wins. The corner is inset from the container's edges plus the
280
+ unsafe area of each edge it reaches. The control belongs to the layer
281
+ beneath open overlays, two below the overlay z-index and so below the
282
+ compact overlay's backdrop: an open overlay covers it as it covers the rest
283
+ of the page, the Workbench rule. A collapsed overlay passes pointer events
284
+ through, so the control is usable again as soon as the overlay closes. */
285
+ :where(:has(> .kui-collapsible-panel__restore)) {
286
+ position: relative;
287
+ isolation: isolate;
288
+ anchor-scope: --kui-restore-drawer;
289
+ }
290
+
291
+ /* An expanded bottom drawer beside the collapsed panel — a direct child of
292
+ that container or of one of its direct children (the app's work-area
293
+ column) — owns the container's bottom, so the corner floats above the
294
+ drawer's top edge instead of over it. The drawer publishes that edge as an
295
+ anchor; a drawer nested deeper, inside the work area's own content, belongs
296
+ to another layout and is scoped out. Without anchor positioning the corner
297
+ keeps the container's bottom edge. */
298
+ .kui-collapsible-panel--bottom[data-presentation="inline"]:not(
299
+ [data-collapsed="true"],
300
+ [data-collapsible-overlay="true"] *,
301
+ [data-collapsible-responsive="hidden"] *
302
+ ) {
303
+ anchor-name: --kui-restore-drawer;
304
+ }
305
+
306
+ :where(:has(> .kui-collapsible-panel__restore)) > * > * > * {
307
+ anchor-scope: --kui-restore-drawer;
308
+ }
309
+
268
310
  .kui-collapsible-panel__restore {
269
- position: fixed;
270
- z-index: var(--kui-collapsible-panel-restore-z, 42);
311
+ --_kui-collapsible-panel-restore-inset: var(
312
+ --kui-collapsible-panel-restore-inset,
313
+ 1rem
314
+ );
315
+ /* The corner owns the inset, so a FloatingToolbar composed here floats
316
+ from this point instead of adding its own inset on top. */
317
+ --kui-floating-toolbar-inset: 0px;
318
+ position: absolute;
319
+ z-index: var(
320
+ --kui-collapsible-panel-restore-z,
321
+ calc(var(--kui-collapsible-panel-overlay-z, 40) - 2)
322
+ );
323
+ position-visibility: always;
271
324
  inset-block-end: calc(
272
- var(--kui-collapsible-panel-restore-inset, 1rem) +
273
- var(--kui-safe-area-block-end, env(safe-area-inset-bottom, 0px))
325
+ var(--_kui-collapsible-panel-restore-inset) +
326
+ var(
327
+ --kui-edge-inset-block-end,
328
+ var(--kui-safe-area-block-end, env(safe-area-inset-bottom, 0px))
329
+ )
330
+ );
331
+ /* Above an expanded drawer's top edge when one is in scope (see above). */
332
+ inset-block-end: calc(
333
+ var(--_kui-collapsible-panel-restore-inset) +
334
+ anchor(
335
+ --kui-restore-drawer top,
336
+ var(
337
+ --kui-edge-inset-block-end,
338
+ var(--kui-safe-area-block-end, env(safe-area-inset-bottom, 0px))
339
+ )
340
+ )
274
341
  );
275
342
  }
276
343
 
277
344
  .kui-collapsible-panel__restore[data-position="bottom-start"] {
278
345
  inset-inline-start: calc(
279
- var(--kui-collapsible-panel-restore-inset, 1rem) +
280
- var(--kui-safe-area-inline-start, env(safe-area-inset-left, 0px))
346
+ var(--_kui-collapsible-panel-restore-inset) +
347
+ var(
348
+ --kui-edge-inset-inline-start,
349
+ var(--kui-safe-area-inline-start, env(safe-area-inset-left, 0px))
350
+ )
281
351
  );
282
352
  }
283
353
 
284
354
  .kui-collapsible-panel__restore[data-position="bottom-end"] {
285
355
  inset-inline-end: calc(
286
- var(--kui-collapsible-panel-restore-inset, 1rem) +
287
- var(--kui-safe-area-inline-end, env(safe-area-inset-right, 0px))
356
+ var(--_kui-collapsible-panel-restore-inset) +
357
+ var(
358
+ --kui-edge-inset-inline-end,
359
+ var(--kui-safe-area-inline-end, env(safe-area-inset-right, 0px))
360
+ )
288
361
  );
289
362
  }
290
363
 
291
364
  /* A button does not stretch between its insets the way a div does, so the
292
- backdrop sizes itself to its containing block explicitly. */
365
+ backdrop sizes itself to its containing block explicitly. It sits one below
366
+ the overlay z-index, so an app that moves the overlay moves the backdrop
367
+ with it, and the restore controls stay beneath both. */
293
368
  .kui-collapsible-panel__backdrop {
294
369
  position: fixed;
295
370
  inset: 0;
296
371
  width: 100%;
297
372
  height: 100%;
298
- z-index: var(--kui-collapsible-panel-backdrop-z, 39);
373
+ z-index: var(
374
+ --kui-collapsible-panel-backdrop-z,
375
+ calc(var(--kui-collapsible-panel-overlay-z, 40) - 1)
376
+ );
299
377
  border: 0;
300
378
  padding: 0;
301
379
  background: var(--kui-color-scrim, rgb(0 0 0 / 32%));
@@ -1,7 +1,12 @@
1
1
  .kui-floating-toolbar {
2
2
  /* Inset from the container edges: a top toolbar sits 8px in, so this floats an
3
- extra 8px past that (--kui-space-m = 16px). Override the token to reposition. */
4
- --kui-floating-toolbar-inset: var(--kui-space-m, 1rem);
3
+ extra 8px past that (--kui-space-m = 16px). Override the token to reposition,
4
+ on the toolbar or on an ancestor composition boundary: a Workbench restore
5
+ corner sets it to 0 because the corner already owns the inset. */
6
+ --_kui-floating-toolbar-inset: var(
7
+ --kui-floating-toolbar-inset,
8
+ var(--kui-space-m, 1rem)
9
+ );
5
10
 
6
11
  /* Floats above the main content of its nearest positioned ancestor. z-index
7
12
  stays low so it never covers dialogs/overlays (it is not top-layer). Forced
@@ -15,19 +20,19 @@
15
20
  }
16
21
 
17
22
  .kui-floating-toolbar[data-position^="bottom"] {
18
- inset-block-end: var(--kui-floating-toolbar-inset);
23
+ inset-block-end: var(--_kui-floating-toolbar-inset);
19
24
  }
20
25
 
21
26
  .kui-floating-toolbar[data-position^="top"] {
22
- inset-block-start: var(--kui-floating-toolbar-inset);
27
+ inset-block-start: var(--_kui-floating-toolbar-inset);
23
28
  }
24
29
 
25
30
  .kui-floating-toolbar[data-position$="-end"] {
26
- inset-inline-end: var(--kui-floating-toolbar-inset);
31
+ inset-inline-end: var(--_kui-floating-toolbar-inset);
27
32
  }
28
33
 
29
34
  .kui-floating-toolbar[data-position$="-start"] {
30
- inset-inline-start: var(--kui-floating-toolbar-inset);
35
+ inset-inline-start: var(--_kui-floating-toolbar-inset);
31
36
  }
32
37
 
33
38
  /* The centered edges span from the middle rather than an inline edge. */
@@ -146,16 +146,22 @@
146
146
 
147
147
  /* Responsive replacement policies. Overlay regions stay on their logical edge
148
148
  and stop participating in the parent's flex tracks; hidden regions are fully
149
- replaced by application-owned compact UI. */
149
+ replaced by application-owned compact UI. An overlay floats over the work
150
+ area, so it paints the surface like an overlay CollapsiblePanel: without it
151
+ the content beneath (and the restore control stacked below it) shows
152
+ through the shadowed box. An inline region stays transparent and shows its
153
+ host's background. */
150
154
  .kui-resizable-region[data-presentation="overlay"] {
151
155
  position: absolute;
152
156
  z-index: var(--kui-resizable-region-overlay-z, 41);
153
- max-width: var(--kui-resizable-region-overlay-max-width, 85vw);
154
- max-height: var(--kui-resizable-region-overlay-max-height, 85vh);
157
+ background: var(--kui-color-surface);
155
158
  box-shadow: var(--kui-shadow-l);
156
159
  }
160
+ /* Each overlay maximum caps only the resizable axis: a side overlay spans its
161
+ host's full height and a drawer its full width, like their inline tracks. */
157
162
  .kui-resizable-region[data-presentation="overlay"][data-axis="horizontal"] {
158
163
  inset-block: 0;
164
+ max-width: var(--kui-resizable-region-overlay-max-width, 85vw);
159
165
  }
160
166
  .kui-resizable-region[data-presentation="overlay"][data-axis="horizontal"][data-edge="end"] {
161
167
  inset-inline-start: 0;
@@ -165,6 +171,7 @@
165
171
  }
166
172
  .kui-resizable-region[data-presentation="overlay"][data-axis="vertical"] {
167
173
  inset-inline: 0;
174
+ max-height: var(--kui-resizable-region-overlay-max-height, 85vh);
168
175
  }
169
176
  .kui-resizable-region[data-presentation="overlay"][data-axis="vertical"][data-edge="end"] {
170
177
  inset-block-start: 0;
@@ -229,26 +236,87 @@
229
236
  }
230
237
  }
231
238
 
232
- /* A collapsed panel can supply its own affordance while Kerf owns consistent,
233
- safe-area-aware viewport placement. */
239
+ /* A collapsed region can supply its own affordance. It floats in a corner of
240
+ the region's own container, never of the viewport, so a region embedded in a
241
+ page cannot float it over page content outside that container. The
242
+ container becomes the corner's containing block and isolates its stacking
243
+ only while a restore control is shown, at zero specificity so an app's own
244
+ positioning of that container wins. The corner is inset from the
245
+ container's edges plus the unsafe area of each edge it reaches. The
246
+ control belongs to the layer beneath open overlays, two below the overlay
247
+ z-index: an open overlay region covers it as it covers the rest of the
248
+ work area, the Workbench rule. A collapsed overlay drops its pointer
249
+ events, so the control is usable again as soon as the overlay closes. */
250
+ :where(:has(> .kui-resizable-region__restore)) {
251
+ position: relative;
252
+ isolation: isolate;
253
+ anchor-scope: --kui-restore-drawer;
254
+ }
255
+ /* An expanded bottom region (a vertical region resized from its top edge)
256
+ beside the collapsed one — a direct child of that container or of one of
257
+ its direct children (the app's work-area column) — owns the container's
258
+ bottom, so the corner floats above the drawer's top edge instead of over
259
+ it. CollapsiblePanel drawers publish the same anchor. A drawer nested
260
+ deeper, inside the work area's own content, belongs to another layout and
261
+ is scoped out. Without anchor positioning the corner keeps the container's
262
+ bottom edge. */
263
+ .kui-resizable-region[data-axis="vertical"][data-edge="start"][data-presentation="inline"]:not(
264
+ [data-collapsed="true"]
265
+ ) {
266
+ anchor-name: --kui-restore-drawer;
267
+ }
268
+ :where(:has(> .kui-resizable-region__restore)) > * > * > * {
269
+ anchor-scope: --kui-restore-drawer;
270
+ }
234
271
  .kui-resizable-region__restore {
235
- position: fixed;
236
- z-index: var(--kui-resizable-region-restore-z, 42);
272
+ --_kui-resizable-region-restore-inset: var(
273
+ --kui-resizable-region-restore-inset,
274
+ 1rem
275
+ );
276
+ /* The corner owns the inset, so a FloatingToolbar composed here floats
277
+ from this point instead of adding its own inset on top. */
278
+ --kui-floating-toolbar-inset: 0px;
279
+ position: absolute;
280
+ z-index: var(
281
+ --kui-resizable-region-restore-z,
282
+ calc(var(--kui-resizable-region-overlay-z, 41) - 2)
283
+ );
284
+ position-visibility: always;
285
+ inset-block-end: calc(
286
+ var(--_kui-resizable-region-restore-inset) +
287
+ var(
288
+ --kui-edge-inset-block-end,
289
+ var(--kui-safe-area-block-end, env(safe-area-inset-bottom, 0px))
290
+ )
291
+ );
292
+ /* Above an expanded drawer's top edge when one is in scope (see above). */
237
293
  inset-block-end: calc(
238
- var(--kui-resizable-region-restore-inset, 1rem) +
239
- var(--kui-safe-area-block-end, env(safe-area-inset-bottom, 0px))
294
+ var(--_kui-resizable-region-restore-inset) +
295
+ anchor(
296
+ --kui-restore-drawer top,
297
+ var(
298
+ --kui-edge-inset-block-end,
299
+ var(--kui-safe-area-block-end, env(safe-area-inset-bottom, 0px))
300
+ )
301
+ )
240
302
  );
241
303
  }
242
304
  .kui-resizable-region__restore[data-position="bottom-start"] {
243
305
  inset-inline-start: calc(
244
- var(--kui-resizable-region-restore-inset, 1rem) +
245
- var(--kui-safe-area-inline-start, env(safe-area-inset-left, 0px))
306
+ var(--_kui-resizable-region-restore-inset) +
307
+ var(
308
+ --kui-edge-inset-inline-start,
309
+ var(--kui-safe-area-inline-start, env(safe-area-inset-left, 0px))
310
+ )
246
311
  );
247
312
  }
248
313
  .kui-resizable-region__restore[data-position="bottom-end"] {
249
314
  inset-inline-end: calc(
250
- var(--kui-resizable-region-restore-inset, 1rem) +
251
- var(--kui-safe-area-inline-end, env(safe-area-inset-right, 0px))
315
+ var(--_kui-resizable-region-restore-inset) +
316
+ var(
317
+ --kui-edge-inset-inline-end,
318
+ var(--kui-safe-area-inline-end, env(safe-area-inset-right, 0px))
319
+ )
252
320
  );
253
321
  }
254
322
  .kui-resizable-region__handle {