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

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 (152) hide show
  1. package/README.md +4 -2
  2. package/ai/application-ui-diagnostic-ids-v1.json +1 -0
  3. package/ai/component-catalog-v2.json +138 -5
  4. package/ai/component-catalog-v2.schema.json +2 -1
  5. package/ai/component-catalog.json +208 -16
  6. package/ai/public-api-signatures-v1.md +462 -39
  7. package/ai/skill.md +28 -20
  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/browser/popup-menu.js +3 -0
  15. package/dist/catalog-resources.d.ts +1 -1
  16. package/dist/catalog.d.ts +10 -4
  17. package/dist/catalog.js +243 -300
  18. package/dist/catalog.js.map +1 -1
  19. package/dist/{chunk-7IUSV4XG.js → chunk-24PHKUR3.js} +2 -2
  20. package/dist/chunk-24PHKUR3.js.map +1 -0
  21. package/dist/{chunk-EKYZCRCX.js → chunk-3CGQ7ZNO.js} +54 -22
  22. package/dist/chunk-3CGQ7ZNO.js.map +1 -0
  23. package/dist/{chunk-UKKSMZYT.js → chunk-46263QLK.js} +51 -1
  24. package/dist/chunk-46263QLK.js.map +1 -0
  25. package/dist/chunk-4BIMLITI.js +92 -0
  26. package/dist/chunk-4BIMLITI.js.map +1 -0
  27. package/dist/{chunk-NDUGJ4TU.js → chunk-5NDQABWK.js} +1 -1
  28. package/dist/{chunk-NDUGJ4TU.js.map → chunk-5NDQABWK.js.map} +1 -1
  29. package/dist/{chunk-ZK5EGVFP.js → chunk-5OLVUEND.js} +12 -2
  30. package/dist/chunk-5OLVUEND.js.map +1 -0
  31. package/dist/{chunk-CMUIXJZM.js → chunk-BSKEH3UC.js} +2 -2
  32. package/dist/{chunk-CMUIXJZM.js.map → chunk-BSKEH3UC.js.map} +1 -1
  33. package/dist/chunk-EAX2GSS4.js +384 -0
  34. package/dist/chunk-EAX2GSS4.js.map +1 -0
  35. package/dist/chunk-KH6VUGHU.js +399 -0
  36. package/dist/chunk-KH6VUGHU.js.map +1 -0
  37. package/dist/{chunk-BJJKFVWW.js → chunk-LZXQVUGN.js} +2 -2
  38. package/dist/chunk-LZXQVUGN.js.map +1 -0
  39. package/dist/chunk-N7FHFNT6.js +55 -0
  40. package/dist/chunk-N7FHFNT6.js.map +1 -0
  41. package/dist/{chunk-CCMKJWLX.js → chunk-NE5JAOQS.js} +7 -7
  42. package/dist/chunk-NE5JAOQS.js.map +1 -0
  43. package/dist/chunk-PSHUSWQH.js +18 -0
  44. package/dist/chunk-PSHUSWQH.js.map +1 -0
  45. package/dist/{chunk-KPNTVB7A.js → chunk-R754MHXX.js} +3 -3
  46. package/dist/{chunk-KPNTVB7A.js.map → chunk-R754MHXX.js.map} +1 -1
  47. package/dist/{chunk-HJKRCKDR.js → chunk-RNRUVPJ3.js} +4 -2
  48. package/dist/chunk-RNRUVPJ3.js.map +1 -0
  49. package/dist/{chunk-VOCPXGQN.js → chunk-VHADGP3B.js} +9 -8
  50. package/dist/chunk-VHADGP3B.js.map +1 -0
  51. package/dist/chunk-XQV2B4IL.js +14 -0
  52. package/dist/chunk-XQV2B4IL.js.map +1 -0
  53. package/dist/collapsible-panel.d.ts +46 -15
  54. package/dist/collapsible-panel.js +42 -10
  55. package/dist/collapsible-panel.js.map +1 -1
  56. package/dist/floating-toolbar.d.ts +5 -2
  57. package/dist/floating-toolbar.js +1 -1
  58. package/dist/index.d.ts +1 -0
  59. package/dist/index.js +20 -18
  60. package/dist/list-header.js +1 -1
  61. package/dist/list-inset-text.d.ts +7 -1
  62. package/dist/list-inset-text.js +2 -1
  63. package/dist/panel-toolbar-BFQxFITu.d.ts +52 -0
  64. package/dist/popup-menu-register.d.ts +9 -0
  65. package/dist/popup-menu-register.js +30 -0
  66. package/dist/popup-menu-register.js.map +1 -0
  67. package/dist/popup-menu.d.ts +71 -0
  68. package/dist/popup-menu.js +3 -0
  69. package/dist/popup-menu.js.map +1 -0
  70. package/dist/resizable-region.d.ts +4 -1
  71. package/dist/resizable-region.js +1 -1
  72. package/dist/split-view.js +1 -1
  73. package/dist/state-banner.js +1 -1
  74. package/dist/styles/catalog/components/catalog-example.css +0 -16
  75. package/dist/styles/catalog/components/catalog-stage.css +8 -13
  76. package/dist/styles/catalog/components/catalog.css +8 -18
  77. package/dist/styles/catalog.css +0 -5
  78. package/dist/styles/collapsible-panel.css +88 -10
  79. package/dist/styles/floating-toolbar.css +11 -6
  80. package/dist/styles/popup-menu.css +12 -0
  81. package/dist/styles/resizable-region.css +81 -13
  82. package/dist/styles/state-banner.css +13 -4
  83. package/dist/styles/styles.css +1 -0
  84. package/dist/styles/tab-bar.css +31 -3
  85. package/dist/styles/toolbar-control-group.css +13 -0
  86. package/dist/styles/toolbar.css +43 -2
  87. package/dist/styles/workbench.css +503 -10
  88. package/dist/text.js +1 -1
  89. package/dist/token-search-field.d.ts +10 -1
  90. package/dist/token-search-field.js +1 -1
  91. package/dist/{types-CEsieBZi.d.ts → types-D6vzj-VT.d.ts} +15 -0
  92. package/dist/wire-catalog.d.ts +13 -1
  93. package/dist/wire-catalog.js +18 -3
  94. package/dist/wire-catalog.js.map +1 -1
  95. package/dist/wire-resizable-regions.d.ts +2 -1
  96. package/dist/wire-resizable-regions.js +2 -1
  97. package/dist/wire-sidebar.js +6 -3
  98. package/dist/wire-sidebar.js.map +1 -1
  99. package/dist/wire-tab-bars.js +1 -1
  100. package/dist/wire-token-search-fields.js +1 -1
  101. package/dist/wire-workbench.d.ts +109 -0
  102. package/dist/wire-workbench.js +6 -0
  103. package/dist/wire-workbench.js.map +1 -0
  104. package/dist/workbench.d.ts +166 -6
  105. package/dist/workbench.js +11 -104
  106. package/dist/workbench.js.map +1 -1
  107. package/docs/accessibility.md +66 -10
  108. package/docs/app-layouts.md +12 -1
  109. package/docs/catalog.md +27 -9
  110. package/docs/collapsible-panel.md +114 -1
  111. package/docs/component-contract.md +2 -2
  112. package/docs/component-selection.md +41 -23
  113. package/docs/design/templates/state-banner/danger-dark.svg +1 -1
  114. package/docs/design/templates/state-banner/danger.svg +1 -1
  115. package/docs/design/templates/state-banner/info-dark.svg +1 -1
  116. package/docs/design/templates/state-banner/info.svg +1 -1
  117. package/docs/design/templates/state-banner/success-dark.svg +1 -1
  118. package/docs/design/templates/state-banner/success.svg +1 -1
  119. package/docs/design/templates/state-banner/warning-dark.svg +1 -1
  120. package/docs/design/templates/state-banner/warning.svg +1 -1
  121. package/docs/design/templates/state-banner-dark.svg +1 -1
  122. package/docs/design/templates/state-banner.svg +1 -1
  123. package/docs/document-baseline.md +4 -0
  124. package/docs/layout.md +10 -1
  125. package/docs/recipes.md +48 -39
  126. package/docs/surface-scaffold.md +1 -1
  127. package/docs/type-contracts.md +2 -1
  128. package/docs/ui-analyzer.md +94 -19
  129. package/docs/ui-doctor.md +6 -0
  130. package/docs/ux-demo.md +7 -3
  131. package/docs/webawesome-theme.md +11 -2
  132. package/docs/workbench.md +388 -8
  133. package/llms.txt +13 -8
  134. package/package.json +17 -2
  135. package/ux-demo/recipes/app-shell.tsx +141 -223
  136. package/ux-demo/recipes/collapsible-sidebar.tsx +48 -78
  137. package/ux-demo/recipes/list-detail-dialog.tsx +150 -54
  138. package/ux-demo/recipes/mount-recipe.ts +0 -5
  139. package/ux-demo/recipes/types.ts +0 -1
  140. package/dist/chunk-7IUSV4XG.js.map +0 -1
  141. package/dist/chunk-BJJKFVWW.js.map +0 -1
  142. package/dist/chunk-CCMKJWLX.js.map +0 -1
  143. package/dist/chunk-EKYZCRCX.js.map +0 -1
  144. package/dist/chunk-HJKRCKDR.js.map +0 -1
  145. package/dist/chunk-UKKSMZYT.js.map +0 -1
  146. package/dist/chunk-VOCPXGQN.js.map +0 -1
  147. package/dist/chunk-ZK5EGVFP.js.map +0 -1
  148. package/dist/styles/catalog/components/catalog-detail.css +0 -35
  149. package/dist/styles/catalog/components/catalog-resource-footer.css +0 -37
  150. package/dist/styles/catalog/components/catalog-secondary-sections.css +0 -38
  151. package/dist/styles/catalog/components/catalog-section-list.css +0 -22
  152. package/dist/styles/catalog/components/catalog-sidebar.css +0 -82
@@ -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.53` and `kerfjs@5.0.0-beta.53`. This bounded reference covers only APIs used by the seven-task corpus. It is interface evidence, not an implementation or runtime guarantee.
3
+ Generated from emitted declarations for `@kerfjs/ui@5.0.0-beta.55` and `kerfjs@5.0.0-beta.55`. 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/css-values`
6
6
 
@@ -340,14 +340,93 @@ interface FloatingToolbarProps {
340
340
  * restore button) that sits over the content but NOT over dialogs or overlays
341
341
  * (it is not in the top layer). It is inset from the container edges by
342
342
  * `--kui-floating-toolbar-inset` (default `--kui-space-m`, i.e. 8px more than a
343
- * top toolbar's own inset); override that token to move it. The app owns the
344
- * controls and their behavior — wire them with `delegate()` as usual.
343
+ * top toolbar's own inset); override that token, on the toolbar or an
344
+ * ancestor, to move it. Inside a `Workbench`, `CollapsiblePanel`, or
345
+ * `ResizableRegion` restore corner the corner owns the inset, so the toolbar
346
+ * floats from the corner's own position. The app owns the controls and their
347
+ * behavior — wire them with `delegate()` as usual.
345
348
  */
346
349
  declare function FloatingToolbar({ children, label, position, className, slot, }: FloatingToolbarProps): kerfjs.SafeHtml;
347
350
 
348
351
  export { FloatingToolbar, type FloatingToolbarPosition, type FloatingToolbarProps };
349
352
  ```
350
353
 
354
+ ## `@kerfjs/ui/popup-menu`
355
+
356
+ ```ts
357
+ import { SafeHtml } from 'kerfjs';
358
+ import { K as KerfUiContent } from './semantic-content-BbzjvSu9.js';
359
+
360
+ type PopupMenuPlacement = 'bottom-start' | 'bottom' | 'bottom-end' | 'top-start' | 'top' | 'top-end';
361
+ type PopupMenuDataAttributes = Readonly<Record<`data-${string}`, string | undefined> & {
362
+ 'data-action'?: never;
363
+ 'data-component'?: never;
364
+ 'data-key'?: never;
365
+ 'data-morph-skip-children'?: never;
366
+ }>;
367
+ /** One command in the menu. */
368
+ interface PopupMenuItem {
369
+ kind?: 'item';
370
+ label: string;
371
+ /** Delegated `data-action` the app handles when the item is chosen. */
372
+ action?: string;
373
+ /** Native `wa-dropdown-item` value, reported by its `wa-select` event. */
374
+ value?: string;
375
+ /** Leading icon, typically a `LucideIcon`; it is placed in the item's icon slot. */
376
+ icon?: SafeHtml;
377
+ disabled?: boolean;
378
+ /** Application `data-*` metadata such as a record id. */
379
+ attributes?: PopupMenuDataAttributes;
380
+ }
381
+ /** A labeled group heading; items that follow it belong to the group. */
382
+ interface PopupMenuHeading {
383
+ kind: 'heading';
384
+ label: string;
385
+ }
386
+ /** A separator between groups of items. */
387
+ interface PopupMenuDivider {
388
+ kind: 'divider';
389
+ }
390
+ type PopupMenuEntry = PopupMenuItem | PopupMenuHeading | PopupMenuDivider;
391
+ type PopupMenuTriggerName = {
392
+ /** Visible trigger text, which is also its accessible name. */
393
+ text: string;
394
+ label?: never;
395
+ } | {
396
+ text?: never;
397
+ /**
398
+ * Accessible name of an icon-only trigger, rendered as visually hidden
399
+ * slotted text (a Web Awesome button takes its name from its content).
400
+ */
401
+ label: string;
402
+ };
403
+ type PopupMenuProps = PopupMenuTriggerName & {
404
+ /** Trigger icon, typically a `LucideIcon`, before any visible text. */
405
+ icon?: KerfUiContent;
406
+ items: readonly PopupMenuEntry[];
407
+ /** Where the menu opens relative to its trigger. Defaults to `bottom-start`. */
408
+ placement?: PopupMenuPlacement;
409
+ /** Show the disclosure caret after the trigger content. Defaults to true. */
410
+ caret?: boolean;
411
+ disabled?: boolean;
412
+ /** Application `data-*` metadata on the menu root. */
413
+ rootAttributes?: PopupMenuDataAttributes;
414
+ /** Native named-slot assignment when composed inside a web component. */
415
+ slot?: string;
416
+ };
417
+ /**
418
+ * An action menu: a trigger button that opens a list of commands. Renders the
419
+ * `wa-dropdown` root directly, so a `single` `ToolbarControlGroup` (with
420
+ * `nestedDropdown`) or a `PopupSurface` sizes and insets it as usual. Items
421
+ * dispatch through delegated `data-action`s; the app owns the commands and any
422
+ * open-state reaction. Import `@kerfjs/ui/popup-menu/register` once to register
423
+ * the Web Awesome elements.
424
+ */
425
+ declare function PopupMenu({ text, label, icon, items, placement, caret, disabled, rootAttributes, slot, }: PopupMenuProps): SafeHtml;
426
+
427
+ export { PopupMenu, type PopupMenuDivider, type PopupMenuEntry, type PopupMenuHeading, type PopupMenuItem, type PopupMenuPlacement, type PopupMenuProps };
428
+ ```
429
+
351
430
  ## `@kerfjs/ui/list-header`
352
431
 
353
432
  ```ts
@@ -653,6 +732,10 @@ import * as kerfjs from 'kerfjs';
653
732
  import { S as Sides } from './divider-sides-BzB6rphT.js';
654
733
  import { K as KerfUiContent } from './semantic-content-BbzjvSu9.js';
655
734
 
735
+ type ListInsetTextRootAttributes = Readonly<Record<`data-${string}`, string | undefined> & {
736
+ 'data-component'?: never;
737
+ 'data-sides'?: never;
738
+ }>;
656
739
  interface ListInsetTextProps {
657
740
  /** Text (or inline content) that carries no margin, border, or padding of its own. */
658
741
  children: KerfUiContent | string;
@@ -666,6 +749,8 @@ interface ListInsetTextProps {
666
749
  */
667
750
  horizontalOnly?: boolean;
668
751
  className?: string;
752
+ /** Safe `data-*` metadata; component-owned structural attributes stay protected. */
753
+ rootAttributes?: ListInsetTextRootAttributes;
669
754
  /** Native named-slot assignment when composed inside a web component. */
670
755
  slot?: string;
671
756
  }
@@ -677,7 +762,7 @@ interface ListInsetTextProps {
677
762
  * Pass `horizontalOnly` to keep the horizontal inset but drop the vertical box
678
763
  * space for tight text layout.
679
764
  */
680
- declare function ListInsetText({ children, sides, horizontalOnly, className, slot, }: ListInsetTextProps): kerfjs.SafeHtml;
765
+ declare function ListInsetText({ children, sides, horizontalOnly, className, rootAttributes, slot, }: ListInsetTextProps): kerfjs.SafeHtml;
681
766
 
682
767
  export { ListInsetText, type ListInsetTextProps, Sides };
683
768
  ```
@@ -751,11 +836,13 @@ interface AppTabProps {
751
836
  /** Render as an unanimated loading skeleton, disabling select/close and dragging. */
752
837
  placeholder?: boolean;
753
838
  /**
754
- * Dormant but named: the tab is known and still opening. Keeps `name`
755
- * visible in the quiet text color and as the tab's accessible name, shows
756
- * `trailing` (for example a `LoadingSpinner`), and disables select, close,
757
- * and dragging with `aria-busy`, like `placeholder`. Same pill geometry as
758
- * the live tab, so swapping it in place does not shift the bar.
839
+ * Named and still opening: the tab is known but its content is loading.
840
+ * Keeps `name` visible in the quiet text color and as the tab's accessible
841
+ * name, shows `trailing` (for example a `LoadingSpinner`), and marks the
842
+ * tab `aria-busy`. Unlike `placeholder` it stays selectable — the
843
+ * application shows placeholder content in its panel until loading
844
+ * completes — while close and dragging stay disabled. Same pill geometry
845
+ * as the live tab, so swapping it in place does not shift the bar.
759
846
  * `placeholder` wins when both are set.
760
847
  */
761
848
  pending?: boolean;
@@ -1050,32 +1137,189 @@ export { Pane, type PaneContentElement, type PaneElement, type PaneProps, type P
1050
1137
  import { SafeHtml } from 'kerfjs';
1051
1138
  import { ResizableRegionSeparator, ResizableRegionCollapseMotion, ResizableRegionContentOverflow, ResizableRegionPresentation, ResizableRegionRestorePosition } from './resizable-region.js';
1052
1139
  import { K as KerfUiContent } from './semantic-content-BbzjvSu9.js';
1140
+ import { a as PanelToolbar, b as PanelToggle } from './panel-toolbar-BFQxFITu.js';
1141
+ import { ToolbarProps } from './toolbar.js';
1142
+ import './lucide-icon.js';
1143
+ import 'lucide';
1144
+ import './divider-sides-BzB6rphT.js';
1145
+ import './pane.js';
1053
1146
 
1147
+ /** The standard toggle a Workbench renders for a panel (see {@link PanelToggle}). */
1148
+ type WorkbenchPanelToggle = PanelToggle;
1149
+ /**
1150
+ * A Workbench panel's top toolbar, composed by the Workbench so its groups can
1151
+ * follow the panel's open state (see {@link PanelToolbar} for the roles).
1152
+ * A collapsed rail's `constant` groups and toggle go to the leading edge of
1153
+ * `mainToolbar` (left rail) or its trailing edge (right rail); a collapsed
1154
+ * drawer's go to the trailing edge of `mainBottomToolbar`, else to a
1155
+ * `FloatingToolbar` in the work area's bottom-end corner.
1156
+ */
1157
+ type WorkbenchPanelToolbar = PanelToolbar;
1158
+ /** The work area's top toolbar; collapsed rails add their groups to it. */
1159
+ interface WorkbenchMainToolbar {
1160
+ label: string;
1161
+ /** The work area's title, usually an extra-large `ToolbarText`. */
1162
+ title?: KerfUiContent;
1163
+ /** Groups after the title. */
1164
+ leading?: KerfUiContent;
1165
+ center?: KerfUiContent;
1166
+ /** Groups at the trailing edge, before a collapsed right rail's groups. */
1167
+ trailing?: KerfUiContent;
1168
+ /** The toolbar's narrow-width policy (see `Toolbar.responsive`). */
1169
+ responsive?: ToolbarProps['responsive'];
1170
+ responsiveAt?: ToolbarProps['responsiveAt'];
1171
+ }
1172
+ /** The work area's bottom toolbar; a collapsed drawer adds its groups to it. */
1173
+ interface WorkbenchMainBottomToolbar {
1174
+ label: string;
1175
+ leading?: KerfUiContent;
1176
+ trailing?: KerfUiContent;
1177
+ }
1178
+ /**
1179
+ * The work area: the app's `main` under `mainToolbar` (and above
1180
+ * `mainBottomToolbar`), with each collapsed panel's groups added to the
1181
+ * toolbar on its side. Without either toolbar, `main` renders as given.
1182
+ */
1183
+ /**
1184
+ * Whether the work area's header or footer chrome stays pinned (`fixed`) or
1185
+ * scrolls away with the content (`scroll`).
1186
+ */
1187
+ type WorkbenchChromePlacement = 'fixed' | 'scroll';
1188
+
1189
+ /**
1190
+ * The Workbench container breakpoint below which a panel presents as an
1191
+ * overlay: `narrow` (704px or less) or `compact` (448px or less) — the same
1192
+ * breakpoints as `ResizableRegion`'s `responsiveFillAt` — or `never` to keep
1193
+ * it inline at every width.
1194
+ */
1195
+ type WorkbenchResponsiveOverlayAt = 'compact' | 'narrow' | 'never';
1196
+ /**
1197
+ * How wide a rail's overlay is in a compact (448px or less) Workbench: `inset`
1198
+ * fills the Workbench less a dismiss margin on the side away from the rail's
1199
+ * edge, so a press beside it closes it; `full` fills the Workbench.
1200
+ */
1201
+ type WorkbenchCompactOverlay = 'inset' | 'full';
1202
+ /** Drag-resize limits for a resizable Workbench panel, in px. */
1203
+ interface WorkbenchPanelResizable {
1204
+ /** Smallest size (default 180 for a rail, 120 for the drawer). */
1205
+ min?: number;
1206
+ /** Largest size (default 480). */
1207
+ max?: number;
1208
+ }
1054
1209
  /** A collapsible Workbench panel — a side rail or the bottom drawer. */
1055
1210
  interface WorkbenchPanel {
1056
1211
  content: KerfUiContent;
1212
+ /**
1213
+ * The panel's top toolbar, composed by the Workbench: its `constant` groups
1214
+ * and standard `toggle` move to the work area's toolbar while the panel is
1215
+ * collapsed. With it, `content` renders in a `Pane` below the toolbar.
1216
+ */
1217
+ toolbar?: WorkbenchPanelToolbar;
1218
+ /** Optional bottom toolbar under a `toolbar` panel's content. */
1219
+ footer?: KerfUiContent;
1057
1220
  /** Whether the panel is currently collapsed (the app owns this). */
1058
1221
  collapsed?: boolean;
1059
- /** Rail width, or drawer height, in px. Overrides the CSS default. */
1222
+ /**
1223
+ * Rail width, or drawer height, in px. Overrides the CSS default. For a
1224
+ * resizable panel it is the current size (default 280 for a rail, 220 for
1225
+ * the drawer), clamped to the limits; the app owns it and `wireWorkbench`
1226
+ * reports each resize.
1227
+ */
1060
1228
  size?: number;
1229
+ /**
1230
+ * Opt in to drag and keyboard resizing on the panel's inner separator:
1231
+ * `true` for the default limits, or `{ min, max }`. Off by default. Pair it
1232
+ * with `wireWorkbench` from `@kerfjs/ui/wire-workbench`.
1233
+ */
1234
+ resizable?: boolean | WorkbenchPanelResizable;
1061
1235
  /** Accessible name for the panel region. */
1062
1236
  label?: string;
1063
1237
  separator?: ResizableRegionSeparator;
1064
1238
  collapseMotion?: ResizableRegionCollapseMotion;
1065
1239
  contentOverflow?: ResizableRegionContentOverflow;
1066
1240
  presentation?: ResizableRegionPresentation;
1067
- /** Control shown in a safe-area-aware viewport corner while collapsed. */
1241
+ /**
1242
+ * Present the panel as an overlay, without a separator, below a Workbench
1243
+ * container breakpoint, and inline above it — the CSS decides, so the app
1244
+ * needs no device-class check. A rail overlays from its side at full
1245
+ * height, over the work area and an open drawer; the bottom drawer
1246
+ * overlays the bottom of the work-area column. Rails default to `narrow`
1247
+ * (pass `never` to keep one inline); the drawer defaults to inline.
1248
+ */
1249
+ responsiveOverlayAt?: WorkbenchResponsiveOverlayAt;
1250
+ /**
1251
+ * A rail's overlay width in a compact Workbench (default `inset`: the
1252
+ * Workbench less `--kui-workbench-overlay-dismiss-margin`, 44px). Ignored
1253
+ * by the drawer.
1254
+ */
1255
+ compactOverlay?: WorkbenchCompactOverlay;
1256
+ /**
1257
+ * Control shown while collapsed, in a safe-area-aware corner of the
1258
+ * Workbench (not the viewport); the bottom drawer's sits in the work-area
1259
+ * column. Prefer `toolbar.toggle`, which the Workbench relocates into the
1260
+ * work area's toolbar (or this corner when that toolbar is absent).
1261
+ */
1068
1262
  restoreControl?: SafeHtml;
1069
1263
  restorePosition?: ResizableRegionRestorePosition;
1070
1264
  }
1071
1265
  interface WorkbenchProps {
1266
+ /**
1267
+ * The Workbench's `id`. Each panel's `id` derives from it —
1268
+ * `<id>-left-rail`, `<id>-right-rail`, `<id>-bottom-drawer` — so a toggle
1269
+ * can name the panel it shows and hides with `aria-controls`.
1270
+ */
1072
1271
  id: string;
1073
1272
  label: string;
1074
1273
  /** The central work area. */
1075
1274
  main: KerfUiContent;
1275
+ /**
1276
+ * The work area's top toolbar. A collapsed left rail's `constant` groups
1277
+ * and toggle lead it; a collapsed right rail's trail it. With it, `main`
1278
+ * renders in a `Pane` below the toolbar.
1279
+ */
1280
+ mainToolbar?: WorkbenchMainToolbar;
1281
+ /**
1282
+ * Fixed content under `mainToolbar` — supporting copy such as a
1283
+ * description — divided from the scrolling `main` below it.
1284
+ */
1285
+ mainHeader?: KerfUiContent;
1286
+ /**
1287
+ * Fixed content over `mainBottomToolbar` — a status line or a resource
1288
+ * toolbar — divided from the scrolling `main` above it.
1289
+ */
1290
+ mainFooter?: KerfUiContent;
1291
+ /**
1292
+ * The work area's bottom toolbar. A collapsed drawer's `constant` groups and
1293
+ * toggle trail it; without it they float in the work area's corner.
1294
+ */
1295
+ mainBottomToolbar?: WorkbenchMainBottomToolbar;
1296
+ /**
1297
+ * Whether `mainToolbar` and `mainHeader` stay pinned (`fixed`, default) or
1298
+ * scroll away with `main` (`scroll`) — useful where large text would leave
1299
+ * pinned chrome little room.
1300
+ */
1301
+ mainHeaderPlacement?: WorkbenchChromePlacement;
1302
+ /** The same for `mainFooter` and `mainBottomToolbar` (default `fixed`). */
1303
+ mainFooterPlacement?: WorkbenchChromePlacement;
1076
1304
  leftRail?: WorkbenchPanel;
1077
1305
  rightRail?: WorkbenchPanel;
1078
1306
  bottomDrawer?: WorkbenchPanel;
1307
+ /**
1308
+ * Minimum width, in px, the work area keeps beside the inline rails, fixed
1309
+ * or `resizable` (default 320; `0` turns it off). Resizing a rail stops
1310
+ * where the work area would drop below it, and inline rails shrink
1311
+ * proportionally when the Workbench gets narrower. Workbenches without a
1312
+ * rail ignore it.
1313
+ */
1314
+ mainMinSize?: number;
1315
+ /**
1316
+ * Minimum height, in px, the work area keeps above an inline bottom drawer,
1317
+ * fixed or `resizable` (default 120; `0` turns it off) — the drawer's
1318
+ * counterpart of `mainMinSize`. Resizing the drawer stops where the work
1319
+ * area would drop below it, and the drawer shrinks when the Workbench gets
1320
+ * shorter. Workbenches without a drawer ignore it.
1321
+ */
1322
+ mainMinHeight?: number;
1079
1323
  className?: string;
1080
1324
  /** Native named-slot assignment when composed inside a web component. */
1081
1325
  slot?: string;
@@ -1087,36 +1331,153 @@ interface WorkbenchProps {
1087
1331
  * a composited transform — the instant-width / sliding-content technique, so the
1088
1332
  * work area relayouts once, not per frame. Bottom-drawer content stays anchored
1089
1333
  * to the shell's stable bottom edge throughout that transition. The app owns
1090
- * each `collapsed` flag; the collapse is pure CSS (no wire). See
1091
- * `docs/23-app-layouts.md` §3.3.
1334
+ * each `collapsed` flag; the collapse is pure CSS. A collapsed panel renders
1335
+ * `inert` and `aria-hidden`, so neither Tab nor assistive technology reaches
1336
+ * controls that have slid out of view or an empty landmark (its restore control
1337
+ * lives outside it and stays reachable). A panel may opt in to drag and keyboard resizing with
1338
+ * `resizable`, which `wireWorkbench` drives. See `docs/23-app-layouts.md` §3.3.
1092
1339
  */
1093
- declare function Workbench({ id, label, main, leftRail, rightRail, bottomDrawer, className, slot, }: WorkbenchProps): SafeHtml;
1340
+ declare function Workbench({ id, label, main, leftRail, rightRail, bottomDrawer, mainToolbar, mainHeader, mainFooter, mainBottomToolbar, mainHeaderPlacement, mainFooterPlacement, mainMinSize, mainMinHeight, className, slot, }: WorkbenchProps): SafeHtml;
1094
1341
 
1095
- export { Workbench, type WorkbenchPanel, type WorkbenchProps };
1342
+ export { Workbench, type WorkbenchChromePlacement, type WorkbenchCompactOverlay, type WorkbenchMainBottomToolbar, type WorkbenchMainToolbar, type WorkbenchPanel, type WorkbenchPanelResizable, type WorkbenchPanelToggle, type WorkbenchPanelToolbar, type WorkbenchProps, type WorkbenchResponsiveOverlayAt };
1343
+ ```
1344
+
1345
+ ## `@kerfjs/ui/wire-workbench`
1346
+
1347
+ ```ts
1348
+ import { Signal, ReadonlySignal } from 'kerfjs';
1349
+ import { DeviceClass } from './device-class.js';
1350
+
1351
+ /** A Workbench panel slot, named after its `WorkbenchProps` prop. */
1352
+ type WorkbenchPanelKey = 'leftRail' | 'rightRail' | 'bottomDrawer';
1353
+
1354
+ /** Minimal `localStorage`-shaped store, so the persistence hook is testable. */
1355
+ interface WorkbenchStorage {
1356
+ getItem(key: string): string | null;
1357
+ setItem(key: string, value: string): void;
1358
+ }
1359
+ /** One Workbench panel's app-owned state. */
1360
+ interface WireWorkbenchPanel {
1361
+ /**
1362
+ * The app-owned size signal a `resizable` panel renders as its `size`.
1363
+ * `wireWorkbench` writes each committed resize here; collapsing never
1364
+ * touches it, so an expanded panel returns at the size it had. Omit it for
1365
+ * a panel that is not resizable.
1366
+ */
1367
+ size?: Signal<number>;
1368
+ /**
1369
+ * When set with `size`, the size is loaded from and saved to `storage`
1370
+ * under this key, so the panel remembers the user's size.
1371
+ */
1372
+ storageKey?: string;
1373
+ /**
1374
+ * The app-owned signal the panel renders as its `collapsed`. With it (and
1375
+ * `dismissOverlays`, on by default) `wireWorkbench` treats the panel as a
1376
+ * transient overlay while it presents as one: it collapses when its
1377
+ * `responsiveOverlayAt` breakpoint begins to apply and gets its inline state
1378
+ * back when the breakpoint stops applying, an open overlay takes focus and
1379
+ * keeps Tab inside it, and it closes on Escape or a press outside it.
1380
+ */
1381
+ collapsed?: Signal<boolean>;
1382
+ }
1383
+ /** A resize the user made, after `wireWorkbench` wrote it to the size signal. */
1384
+ interface WorkbenchResize {
1385
+ panel: WorkbenchPanelKey;
1386
+ size: number;
1387
+ source: 'keyboard' | 'pointer';
1388
+ }
1389
+ interface WireWorkbenchOptions {
1390
+ /** The `id` the `Workbench` was rendered with. */
1391
+ id: string;
1392
+ /**
1393
+ * The wired panels, keyed like the `Workbench` props. Render a panel given
1394
+ * a `size` with `resizable` and `size={panel.size.value}`, and one given a
1395
+ * `collapsed` signal with `collapsed={panel.collapsed.value}`.
1396
+ */
1397
+ panels: Partial<Record<WorkbenchPanelKey, WireWorkbenchPanel>>;
1398
+ /**
1399
+ * When provided, resizing is suspended while `deviceClass.compact` is true —
1400
+ * the classes where rails become overlay drawers or are replaced.
1401
+ */
1402
+ deviceClass?: ReadonlySignal<DeviceClass>;
1403
+ /** Persistence store (default `globalThis.localStorage`, if present). */
1404
+ storage?: WorkbenchStorage;
1405
+ /** Keyboard step in px (default 16). */
1406
+ step?: number;
1407
+ /** Shift+arrow step in px (default 64). */
1408
+ largeStep?: number;
1409
+ /** Called after each committed resize. */
1410
+ onResize?: (change: WorkbenchResize) => void;
1411
+ /**
1412
+ * Treat the panels given a `collapsed` signal as transient overlays while
1413
+ * they present as overlays (default `true`), like `wireSidebar`'s compact
1414
+ * overlay: a panel whose `responsiveOverlayAt` breakpoint begins to apply
1415
+ * starts collapsed, with no collapse motion, and gets its inline collapsed
1416
+ * state back when the breakpoint stops applying (and on disposal); an open
1417
+ * overlay panel, responsive or `presentation: "overlay"`, closes on Escape
1418
+ * or a press that starts and ends outside it. A panel that opens as an
1419
+ * overlay takes focus on its first focusable control, and while it is open
1420
+ * Tab and Shift+Tab cycle through its controls instead of reaching the
1421
+ * work area it covers (the ARIA dialog pattern of `wireSidebar`'s compact
1422
+ * overlay); inline panels never move focus. Focus stranded in a closing
1423
+ * panel — however it closed, the app's own control inside it included —
1424
+ * returns to the control that had it when the panel opened, else to the
1425
+ * panel's restore control, else to a control outside the panel whose
1426
+ * `aria-controls` names it (each panel's `id` is its region id, e.g.
1427
+ * `studio-left-rail`) — the fallback for a panel already open at wire-up.
1428
+ * An opener inside a panel that has closed since is skipped. `false` leaves
1429
+ * every `collapsed` write and all focus handling to the app.
1430
+ */
1431
+ dismissOverlays?: boolean;
1432
+ /**
1433
+ * Keep overlays exclusive (default `true`), like `wireSidebar`'s
1434
+ * `exclusiveCompact`: when a panel opens while it presents as an overlay,
1435
+ * every other open overlay panel — rails and the bottom drawer alike —
1436
+ * closes, so one overlay never covers another's controls. Panels presenting
1437
+ * inline are never closed by it. Applies only with `dismissOverlays`.
1438
+ */
1439
+ exclusiveOverlays?: boolean;
1440
+ }
1441
+ /**
1442
+ * Wire a `Workbench`'s panels. For `resizable` panels given a `size` signal:
1443
+ * pointer drags and arrow / Shift+arrow / Home / End on each panel's
1444
+ * separator, clamped to the panel's limits and to the room that leaves the
1445
+ * work area its minimum width and height, committed to the app-owned size signals.
1446
+ * Optional persistence loads and saves each size; optional `deviceClass`
1447
+ * suspends resizing on compact classes. Collapse stays the app's `collapsed`
1448
+ * flag and never changes a size. For panels given a `collapsed` signal,
1449
+ * overlays are transient (`dismissOverlays`): a responsive overlay starts
1450
+ * collapsed, an open overlay takes focus and keeps Tab inside it, it closes
1451
+ * on Escape or an outside press, and
1452
+ * opening one overlay closes the others (`exclusiveOverlays`). Returns a disposer. See `docs/23-app-layouts.md` §3.3.
1453
+ */
1454
+ declare function wireWorkbench(root: HTMLElement, { id, panels, deviceClass, storage, step, largeStep, onResize, dismissOverlays, exclusiveOverlays, }: WireWorkbenchOptions): () => void;
1455
+
1456
+ export { type WireWorkbenchOptions, type WireWorkbenchPanel, type WorkbenchPanelKey, type WorkbenchResize, type WorkbenchStorage, wireWorkbench };
1096
1457
  ```
1097
1458
 
1098
1459
  ## `@kerfjs/ui/collapsible-panel`
1099
1460
 
1100
1461
  ```ts
1101
1462
  import { SafeHtml } from 'kerfjs';
1102
- import { LucideIcon } from './lucide-icon.js';
1463
+ import { P as PanelSide, a as PanelToolbar, b as PanelToggle } from './panel-toolbar-BFQxFITu.js';
1464
+ export { c as collapsiblePanelToggleIcon } from './panel-toolbar-BFQxFITu.js';
1103
1465
  import { ResizableRegionSeparator, ResizableRegionCollapseMotion, ResizableRegionContentOverflow, ResizableRegionPresentation, ResizableRegionRestorePosition } from './resizable-region.js';
1104
1466
  import { K as KerfUiContent } from './semantic-content-BbzjvSu9.js';
1467
+ import './lucide-icon.js';
1105
1468
  import 'lucide';
1106
1469
 
1107
1470
  /** Which edge a {@link CollapsiblePanel} docks to. */
1108
- type CollapsiblePanelSide = 'left' | 'right' | 'bottom';
1471
+ type CollapsiblePanelSide = PanelSide;
1472
+ /** The standard toggle a panel toolbar renders (see {@link CollapsiblePanelToolbar}). */
1473
+ type CollapsiblePanelToolbarToggle = PanelToggle;
1109
1474
  /**
1110
- * The standard collapse/expand icon for a panel `side` and `collapsed` state,
1111
- * so every app's sidebars and drawers use one recognizable convention:
1112
- * `PanelLeft*` for a left rail, `PanelRight*` for a right rail, `PanelBottom*`
1113
- * for a bottom drawer — the `Close` glyph while open, the `Open` glyph while
1114
- * collapsed. Exposed so an app can render its own toggle affordance.
1475
+ * A panel's composed top toolbar. `title` and `panelOnly` groups lead it and
1476
+ * are available only while the panel is open; `constant` groups and the
1477
+ * standard `toggle` trail it while open and move to the app's work-area
1478
+ * toolbar — through {@link CollapsiblePanelRelocated} — while it is collapsed.
1115
1479
  */
1116
- declare function collapsiblePanelToggleIcon(side: CollapsiblePanelSide, collapsed: boolean): {
1117
- icon: Parameters<typeof LucideIcon>[0]['icon'];
1118
- name: string;
1119
- };
1480
+ type CollapsiblePanelToolbar = PanelToolbar;
1120
1481
  interface CollapsiblePanelToggleProps {
1121
1482
  /** The panel this toggle controls. */
1122
1483
  side: CollapsiblePanelSide;
@@ -1153,11 +1514,20 @@ interface CollapsiblePanelProps {
1153
1514
  label?: string;
1154
1515
  /** Panel content. */
1155
1516
  children?: KerfUiContent;
1517
+ /**
1518
+ * The panel's top toolbar, composed so its groups follow the panel's open
1519
+ * state. With it, `children` renders in a `Pane` below the toolbar; render
1520
+ * {@link CollapsiblePanelRelocated} in the app's work-area toolbar so the
1521
+ * `constant` groups and toggle stay reachable while the panel is collapsed.
1522
+ */
1523
+ toolbar?: CollapsiblePanelToolbar;
1524
+ /** Optional bottom toolbar under a `toolbar` panel's content. */
1525
+ footer?: KerfUiContent;
1156
1526
  separator?: ResizableRegionSeparator;
1157
1527
  collapseMotion?: ResizableRegionCollapseMotion;
1158
1528
  contentOverflow?: ResizableRegionContentOverflow;
1159
1529
  presentation?: ResizableRegionPresentation;
1160
- /** Control shown in a safe-area-aware viewport corner while collapsed. */
1530
+ /** Control shown while collapsed, in a safe-area-aware corner of the panel's container (not the viewport). */
1161
1531
  restoreControl?: SafeHtml;
1162
1532
  restorePosition?: ResizableRegionRestorePosition;
1163
1533
  className?: string;
@@ -1169,14 +1539,36 @@ interface CollapsiblePanelProps {
1169
1539
  * slides out via `transform` (one reflow, composited — the same technique
1170
1540
  * `Workbench` and the catalog sidebar use). Bottom-drawer content stays anchored
1171
1541
  * to the panel's fixed bottom edge, so the track cannot move its layout origin
1172
- * underneath the transform transition. The app owns the `collapsed` signal;
1542
+ * underneath the transform transition. A collapsed panel renders `inert` (with
1543
+ * `aria-hidden`), so neither Tab, pointer, nor assistive technology reaches
1544
+ * content that has slid out of view; its `restoreControl` renders outside the
1545
+ * panel and stays reachable.
1546
+ * The app owns the `collapsed` signal;
1173
1547
  * pair it with `wireSidebar` for the toggle, focus, compact-overlay, keyboard,
1174
1548
  * and persistence semantics, and with `CollapsiblePanelToggle` for the standard
1175
1549
  * affordance. See `ui/docs/collapsible-panel.md` and `docs/23-app-layouts.md`.
1176
1550
  */
1177
- declare function CollapsiblePanel({ id, side, collapsed, size, label, children, separator, collapseMotion, contentOverflow, presentation, restoreControl, restorePosition, className, }: CollapsiblePanelProps): SafeHtml;
1551
+ declare function CollapsiblePanel({ id, side, collapsed, size, label, children, toolbar, footer, separator, collapseMotion, contentOverflow, presentation, restoreControl, restorePosition, className, }: CollapsiblePanelProps): SafeHtml;
1552
+ interface CollapsiblePanelRelocatedProps {
1553
+ /** The panel's `id`. */
1554
+ panelId: string;
1555
+ side: CollapsiblePanelSide;
1556
+ /** The panel's current collapsed state. */
1557
+ collapsed: boolean;
1558
+ /** The same `toolbar` the panel receives. */
1559
+ toolbar: CollapsiblePanelToolbar;
1560
+ }
1561
+ /**
1562
+ * A collapsed {@link CollapsiblePanel}'s `constant` groups and standard
1563
+ * toggle, for the app's work-area toolbar — nothing while the panel is open.
1564
+ * Put it first in the leading zone for a left rail, last in the trailing zone
1565
+ * for a right rail, and last in a bottom toolbar (or a `FloatingToolbar`
1566
+ * `restoreControl`) for a bottom drawer. `wireSidebar` hands focus to it when
1567
+ * the panel closes from its own toggle.
1568
+ */
1569
+ declare function CollapsiblePanelRelocated({ panelId, side, collapsed, toolbar, }: CollapsiblePanelRelocatedProps): SafeHtml;
1178
1570
 
1179
- export { CollapsiblePanel, type CollapsiblePanelProps, type CollapsiblePanelSide, CollapsiblePanelToggle, type CollapsiblePanelToggleProps, collapsiblePanelToggleIcon };
1571
+ export { CollapsiblePanel, type CollapsiblePanelProps, CollapsiblePanelRelocated, type CollapsiblePanelRelocatedProps, type CollapsiblePanelSide, CollapsiblePanelToggle, type CollapsiblePanelToggleProps, type CollapsiblePanelToolbar, type CollapsiblePanelToolbarToggle };
1180
1572
  ```
1181
1573
 
1182
1574
  ## `@kerfjs/ui/wire-sidebar`
@@ -1323,6 +1715,9 @@ interface ResizableRegionProps {
1323
1715
  max: number;
1324
1716
  axis?: ResizableRegionAxis;
1325
1717
  edge?: ResizableRegionEdge;
1718
+ /** Snap the track to zero. The region renders `inert` and `aria-hidden`
1719
+ * while collapsed, so neither Tab nor assistive technology reaches it or
1720
+ * lands on an empty landmark; `restoreControl` renders outside the region. */
1326
1721
  collapsed?: boolean;
1327
1722
  transitioning?: boolean;
1328
1723
  /** Whether the separator line is painted. The resize hit target remains available. */
@@ -1335,7 +1730,7 @@ interface ResizableRegionProps {
1335
1730
  presentation?: ResizableRegionPresentation;
1336
1731
  /** Always-available control rendered while collapsed, outside the clipped region. */
1337
1732
  restoreControl?: SafeHtml;
1338
- /** Safe-area-aware viewport corner for `restoreControl`. */
1733
+ /** Safe-area-aware corner of the region's container (not the viewport) for `restoreControl`. */
1339
1734
  restorePosition?: ResizableRegionRestorePosition;
1340
1735
  /** Fill the available inline track and hide the separator below a container breakpoint. */
1341
1736
  responsiveFillAt?: ResizableRegionResponsiveFillAt;
@@ -1364,8 +1759,9 @@ interface WireResizableRegionsOptions {
1364
1759
  onPreview?: (change: ResizeCommit) => void;
1365
1760
  onCommit: (change: ResizeCommit) => void;
1366
1761
  }
1762
+
1367
1763
  /** Wire pointer and separator-keyboard behavior for every ResizableRegion below root. */
1368
- declare function wireResizableRegions(root: HTMLElement, { step, largeStep, onPreview, onCommit, }: WireResizableRegionsOptions): () => void;
1764
+ declare function wireResizableRegions(root: HTMLElement, options: WireResizableRegionsOptions): () => void;
1369
1765
 
1370
1766
  export { type ResizeCommit, type WireResizableRegionsOptions, wireResizableRegions };
1371
1767
  ```
@@ -1442,12 +1838,18 @@ export { DEFAULT_BREAKPOINTS, type DeviceBreakpoints, type DeviceClass, type Dev
1442
1838
  ```ts
1443
1839
  import * as kerfjs from 'kerfjs';
1444
1840
  import { SafeHtml } from 'kerfjs';
1445
- import { a as CatalogProps } from './types-CEsieBZi.js';
1446
- export { b as CatalogBrand, c as CatalogEntry, d as CatalogRelated, C as CatalogResource, e as CatalogSecondaryGroup, f as CatalogSection, g as CatalogStageRootAttributes } from './types-CEsieBZi.js';
1841
+ import { a as CatalogProps } from './types-D6vzj-VT.js';
1842
+ export { b as CatalogBrand, c as CatalogEntry, d as CatalogRelated, C as CatalogResource, e as CatalogSecondaryGroup, f as CatalogSection, g as CatalogStageRootAttributes } from './types-D6vzj-VT.js';
1447
1843
  import { K as KerfUiContent } from './semantic-content-BbzjvSu9.js';
1448
1844
 
1449
- /** Controlled, stateless component-catalog shell. */
1450
- declare function Catalog({ brand, sections, active, content, collapsed, theme, headerActions, secondarySections, sidebarFooter, status, geometryOverlay, stageRootAttributes, selectAction, toggleSidebarAction, toggleThemeAction, toggleSecondaryAction, className, slot, }: CatalogProps): kerfjs.SafeHtml;
1845
+ /**
1846
+ * Controlled, stateless component-catalog shell: a `Workbench` whose left rail
1847
+ * is the catalog navigation and whose work area is the active entry — its
1848
+ * toolbar, description, preview stage, and resource footer. The sidebar's
1849
+ * standard toggle moves into the entry toolbar while it is collapsed, and on
1850
+ * a small screen the sidebar overlays the stage like any Workbench rail.
1851
+ */
1852
+ declare function Catalog({ id, brand, sections, active, content, collapsed, theme, headerActions, secondarySections, sidebarFooter, status, geometryOverlay, stageRootAttributes, selectAction, toggleSidebarAction, toggleThemeAction, toggleSecondaryAction, headerPlacement, footerPlacement, className, slot, }: CatalogProps): kerfjs.SafeHtml;
1451
1853
 
1452
1854
  /** How a specimen aligns its visible edge with its `ListHeader` label. */
1453
1855
  type CatalogExampleAlign = 'glyph' | 'inline-control' | 'none';
@@ -1518,7 +1920,7 @@ export { Catalog, CatalogExample, type CatalogExampleAlign, type CatalogExampleP
1518
1920
  ## `@kerfjs/ui/catalog-resources`
1519
1921
 
1520
1922
  ```ts
1521
- import { C as CatalogResource } from './types-CEsieBZi.js';
1923
+ import { C as CatalogResource } from './types-D6vzj-VT.js';
1522
1924
  import './semantic-content-BbzjvSu9.js';
1523
1925
  import 'kerfjs';
1524
1926
 
@@ -1558,6 +1960,8 @@ export { type CatalogGuidanceKind, type CatalogResourceKind, type CatalogResourc
1558
1960
  ## `@kerfjs/ui/wire-catalog`
1559
1961
 
1560
1962
  ```ts
1963
+ import { Signal } from 'kerfjs';
1964
+
1561
1965
  interface WireCatalogOptions {
1562
1966
  /** Invoked with the entry id when a sidebar item or a related-entry option is chosen. */
1563
1967
  onSelect: (id: string) => void;
@@ -1578,6 +1982,16 @@ interface WireCatalogOptions {
1578
1982
  toggleSidebarAction?: string;
1579
1983
  toggleThemeAction?: string;
1580
1984
  toggleSecondaryAction?: string;
1985
+ /**
1986
+ * The sidebar's app-owned collapsed flag. With it, the catalog's Workbench
1987
+ * sidebar is wired like any Workbench rail: it becomes a transient overlay
1988
+ * on a small screen (collapsed as the breakpoint applies, closed on Escape
1989
+ * or a press outside, focus handed back), and choosing an entry from the
1990
+ * open overlay closes it.
1991
+ */
1992
+ collapsed?: Signal<boolean>;
1993
+ /** The Catalog's `id`, when it is not the default `kui-catalog`. */
1994
+ id?: string;
1581
1995
  }
1582
1996
  interface CatalogRevealOptions {
1583
1997
  /** Scroll alignment within the sidebar. Default `'nearest'`. */
@@ -1612,7 +2026,7 @@ declare function wireCatalogGeometryOverlay(root: HTMLElement): () => void;
1612
2026
  * them in the callbacks; optionally mirror the active id into the URL via `urlParam`.
1613
2027
  * Returns a disposer.
1614
2028
  */
1615
- declare function wireCatalog(root: HTMLElement, { onSelect, onToggleSidebar, onToggleTheme, onToggleSecondary, urlParam, revealSelection, selectAction, toggleSidebarAction, toggleThemeAction, toggleSecondaryAction, }: WireCatalogOptions): () => void;
2029
+ declare function wireCatalog(root: HTMLElement, { onSelect, onToggleSidebar, onToggleTheme, onToggleSecondary, urlParam, revealSelection, selectAction, toggleSidebarAction, toggleThemeAction, toggleSecondaryAction, collapsed, id: catalogId, }: WireCatalogOptions): () => void;
1616
2030
 
1617
2031
  export { type CatalogRevealOptions, type WireCatalogOptions, revealCatalogEntry, wireCatalog, wireCatalogGeometryOverlay };
1618
2032
  ```
@@ -1880,6 +2294,15 @@ interface TokenSearchFieldBaseProps {
1880
2294
  label: string;
1881
2295
  query?: string;
1882
2296
  tokens?: readonly TokenSearchToken[];
2297
+ /**
2298
+ * Editor identity for a programmatic text replacement. The editor's text is
2299
+ * DOM-owned between token changes, so a new `query` with the same tokens
2300
+ * does not re-render it (that would reset the caret on every keystroke).
2301
+ * Change `revision` when the app replaces the text itself — reseeding a
2302
+ * persistent dialog's field on reopen, applying a saved search — and the
2303
+ * editor is rebuilt from `query` and `tokens`.
2304
+ */
2305
+ revision?: string | number;
1883
2306
  placeholder?: string;
1884
2307
  tokenPlaceholder?: string;
1885
2308
  disabled?: boolean;
@@ -1915,7 +2338,7 @@ interface TokenSearchFieldValue {
1915
2338
  query: string;
1916
2339
  tokens: TokenSearchToken[];
1917
2340
  }
1918
- declare function TokenSearchField({ id, label, query, tokens, placeholder, tokenPlaceholder, disabled, autofocus, collapsible, expanded, expandAction, expandLabel, leading, trailing, presentation, editAction, removeAction, clearAction, clearLabel, className, editorAttributes, slot, }: TokenSearchFieldProps): kerfjs.SafeHtml;
2341
+ declare function TokenSearchField({ id, label, query, tokens, revision, placeholder, tokenPlaceholder, disabled, autofocus, collapsible, expanded, expandAction, expandLabel, leading, trailing, presentation, editAction, removeAction, clearAction, clearLabel, className, editorAttributes, slot, }: TokenSearchFieldProps): kerfjs.SafeHtml;
1919
2342
  /** Read editable text and ordered token offsets from a rendered TokenSearchField editor. */
1920
2343
  declare function readTokenSearchField(editor: HTMLElement, knownTokens?: readonly TokenSearchToken[]): TokenSearchFieldValue;
1921
2344
  /** Focus an editor and place its caret at a text offset, skipping atomic token chips. */