@kerfjs/ui 5.0.0-beta.56 → 5.0.0-beta.58

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 (287) hide show
  1. package/README.md +81 -37
  2. package/ai/application-ui-diagnostic-ids-v1.json +9 -1
  3. package/ai/application-ui-profile-sync.cjs +1 -1
  4. package/ai/application-ui-profile.defaults.json +63 -8
  5. package/ai/application-ui-profile.mjs +1 -1
  6. package/ai/component-catalog.json +211 -33
  7. package/ai/component-catalog.schema.json +2 -0
  8. package/ai/component-class-owners.cjs +83 -0
  9. package/ai/component-composition-extension.d.ts +7 -0
  10. package/ai/component-composition-extension.schema.json +7 -0
  11. package/ai/{component-catalog-v2-overrides.json → component-composition-rules.json} +2 -1
  12. package/ai/{component-catalog-v2.d.ts → component-composition.d.ts} +9 -5
  13. package/ai/{component-catalog-v2.json → component-composition.json} +155 -24
  14. package/ai/{component-catalog-v2.schema.json → component-composition.schema.json} +21 -5
  15. package/ai/components/README.md +170 -0
  16. package/ai/components/application-tabs.md +65 -0
  17. package/ai/components/badge.md +72 -0
  18. package/ai/components/collapsible-panel.md +102 -0
  19. package/ai/components/content-item.md +90 -0
  20. package/ai/components/disclosure-arrow.md +77 -0
  21. package/ai/components/document-baseline.md +75 -0
  22. package/ai/components/empty-state.md +80 -0
  23. package/ai/components/feedback.md +71 -0
  24. package/ai/components/floating-toolbar.md +80 -0
  25. package/ai/components/foundation.md +65 -0
  26. package/ai/components/grid.md +93 -0
  27. package/ai/components/headers.md +63 -0
  28. package/ai/components/layout.md +75 -0
  29. package/ai/components/list-action-row.md +91 -0
  30. package/ai/components/list-header.md +89 -0
  31. package/ai/components/list-inset-control.md +74 -0
  32. package/ai/components/list-inset-text.md +72 -0
  33. package/ai/components/list-item.md +88 -0
  34. package/ai/components/list.md +103 -0
  35. package/ai/components/loading-spinner.md +72 -0
  36. package/ai/components/lucide-icon.md +66 -0
  37. package/ai/components/nav-stack.md +103 -0
  38. package/ai/components/pane.md +100 -0
  39. package/ai/components/popup-menu.md +82 -0
  40. package/ai/components/recipe-app-shell.md +57 -0
  41. package/ai/components/recipe-collapsible-sidebar.md +57 -0
  42. package/ai/components/recipe-compact-toolbar.md +57 -0
  43. package/ai/components/recipe-composer-form.md +57 -0
  44. package/ai/components/recipe-list-detail-dialog.md +57 -0
  45. package/ai/components/recipe-list-workspace-states.md +57 -0
  46. package/ai/components/recipe-loading-inspector.md +57 -0
  47. package/ai/components/recipe-navigation-sidebar.md +57 -0
  48. package/ai/components/recipe-navigation-stack.md +57 -0
  49. package/ai/components/recipe-workspace-header.md +57 -0
  50. package/ai/components/resize.md +101 -0
  51. package/ai/components/row.md +96 -0
  52. package/ai/components/segmented-control.md +82 -0
  53. package/ai/components/select.md +107 -0
  54. package/ai/components/skeleton.md +84 -0
  55. package/ai/components/spacer.md +86 -0
  56. package/ai/components/split-view.md +102 -0
  57. package/ai/components/state-banner.md +92 -0
  58. package/ai/components/sunken-panel.md +79 -0
  59. package/ai/components/surface-scaffold.md +78 -0
  60. package/ai/components/tab-bar.md +112 -0
  61. package/ai/components/tab-scaffold.md +94 -0
  62. package/ai/components/tabs.md +90 -0
  63. package/ai/components/text.md +82 -0
  64. package/ai/components/token-search-field.md +101 -0
  65. package/ai/components/toolbar-control-group.md +102 -0
  66. package/ai/components/toolbar-text.md +76 -0
  67. package/ai/components/toolbar.md +95 -0
  68. package/ai/components/value-table.md +72 -0
  69. package/ai/components/wa-accordion-item.md +55 -0
  70. package/ai/components/wa-accordion.md +65 -0
  71. package/ai/components/wa-animated-image.md +55 -0
  72. package/ai/components/wa-animation.md +55 -0
  73. package/ai/components/wa-avatar.md +55 -0
  74. package/ai/components/wa-badge.md +55 -0
  75. package/ai/components/wa-breadcrumb-item.md +53 -0
  76. package/ai/components/wa-breadcrumb.md +55 -0
  77. package/ai/components/wa-button-group.md +59 -0
  78. package/ai/components/wa-button.md +55 -0
  79. package/ai/components/wa-callout.md +58 -0
  80. package/ai/components/wa-card.md +59 -0
  81. package/ai/components/wa-carousel-item.md +53 -0
  82. package/ai/components/wa-carousel.md +55 -0
  83. package/ai/components/wa-checkbox-group.md +55 -0
  84. package/ai/components/wa-checkbox.md +55 -0
  85. package/ai/components/wa-color-picker.md +55 -0
  86. package/ai/components/wa-comparison.md +55 -0
  87. package/ai/components/wa-copy-button.md +55 -0
  88. package/ai/components/wa-details.md +61 -0
  89. package/ai/components/wa-dialog.md +59 -0
  90. package/ai/components/wa-divider.md +53 -0
  91. package/ai/components/wa-drawer.md +55 -0
  92. package/ai/components/wa-dropdown-item.md +60 -0
  93. package/ai/components/wa-dropdown.md +60 -0
  94. package/ai/components/wa-format-bytes.md +53 -0
  95. package/ai/components/wa-format-date.md +53 -0
  96. package/ai/components/wa-format-number.md +53 -0
  97. package/ai/components/wa-icon.md +58 -0
  98. package/ai/components/wa-include.md +53 -0
  99. package/ai/components/wa-input.md +59 -0
  100. package/ai/components/wa-intersection-observer.md +53 -0
  101. package/ai/components/wa-known-date.md +53 -0
  102. package/ai/components/wa-markdown.md +53 -0
  103. package/ai/components/wa-mutation-observer.md +53 -0
  104. package/ai/components/wa-number-input.md +55 -0
  105. package/ai/components/wa-option.md +59 -0
  106. package/ai/components/wa-otp-input.md +53 -0
  107. package/ai/components/wa-page.md +53 -0
  108. package/ai/components/wa-pagination.md +55 -0
  109. package/ai/components/wa-popover.md +55 -0
  110. package/ai/components/wa-popup.md +53 -0
  111. package/ai/components/wa-progress-bar.md +53 -0
  112. package/ai/components/wa-progress-ring.md +53 -0
  113. package/ai/components/wa-qr-code.md +53 -0
  114. package/ai/components/wa-radio-group.md +59 -0
  115. package/ai/components/wa-radio.md +55 -0
  116. package/ai/components/wa-random-content.md +53 -0
  117. package/ai/components/wa-rating.md +55 -0
  118. package/ai/components/wa-relative-time.md +53 -0
  119. package/ai/components/wa-resize-observer.md +53 -0
  120. package/ai/components/wa-scroller.md +53 -0
  121. package/ai/components/wa-select.md +63 -0
  122. package/ai/components/wa-skeleton.md +53 -0
  123. package/ai/components/wa-slider.md +55 -0
  124. package/ai/components/wa-spinner.md +58 -0
  125. package/ai/components/wa-split-panel.md +58 -0
  126. package/ai/components/wa-switch.md +53 -0
  127. package/ai/components/wa-tab-group.md +69 -0
  128. package/ai/components/wa-tab-panel.md +60 -0
  129. package/ai/components/wa-tab.md +59 -0
  130. package/ai/components/wa-tag.md +59 -0
  131. package/ai/components/wa-textarea.md +53 -0
  132. package/ai/components/wa-time-input.md +55 -0
  133. package/ai/components/wa-toast-item.md +60 -0
  134. package/ai/components/wa-toast.md +60 -0
  135. package/ai/components/wa-tooltip.md +55 -0
  136. package/ai/components/wa-tree-item.md +55 -0
  137. package/ai/components/wa-tree.md +55 -0
  138. package/ai/components/wa-zoomable-frame.md +55 -0
  139. package/ai/components/workbench.md +114 -0
  140. package/ai/public-api-signatures-v1.md +174 -43
  141. package/ai/skill.md +100 -48
  142. package/ai/webawesome-jsx-signatures-v1.md +1 -1
  143. package/analyzer/component-ownership.d.mts +56 -0
  144. package/analyzer/component-ownership.mjs +184 -0
  145. package/analyzer/index.d.mts +3 -0
  146. package/analyzer/index.mjs +274 -20
  147. package/analyzer/selectors.d.mts +21 -0
  148. package/analyzer/selectors.mjs +212 -0
  149. package/dist/browser/catalog.js +25 -0
  150. package/dist/browser/collapsible-panel.js +7 -0
  151. package/dist/browser/nav-stack.js +8 -0
  152. package/dist/browser/split-view.js +10 -0
  153. package/dist/browser/tab-scaffold.js +4 -0
  154. package/dist/browser/workbench.js +10 -0
  155. package/dist/catalog-resources.d.ts +2 -2
  156. package/dist/catalog.d.ts +3 -3
  157. package/dist/catalog.js +8 -7
  158. package/dist/catalog.js.map +1 -1
  159. package/dist/{chunk-QQOTQTDD.js → chunk-2CCMJTVY.js} +13 -10
  160. package/dist/chunk-2CCMJTVY.js.map +1 -0
  161. package/dist/{chunk-PK4N5QTO.js → chunk-553ASUK6.js} +2 -3
  162. package/dist/chunk-553ASUK6.js.map +1 -0
  163. package/dist/{chunk-G33XC2NB.js → chunk-6YFHCLHG.js} +2 -2
  164. package/dist/chunk-6YFHCLHG.js.map +1 -0
  165. package/dist/{chunk-ZIYOJFZD.js → chunk-7JUBXOIV.js} +17 -4
  166. package/dist/chunk-7JUBXOIV.js.map +1 -0
  167. package/dist/{chunk-T4UZTNZ4.js → chunk-EVYKTVBQ.js} +2 -11
  168. package/dist/chunk-EVYKTVBQ.js.map +1 -0
  169. package/dist/{chunk-AK67F6QN.js → chunk-EZVNC4J6.js} +4 -1
  170. package/dist/chunk-EZVNC4J6.js.map +1 -0
  171. package/dist/{chunk-MA6Z6EIM.js → chunk-F4QMLOXJ.js} +3 -2
  172. package/dist/chunk-F4QMLOXJ.js.map +1 -0
  173. package/dist/chunk-JCV4GXWB.js +249 -0
  174. package/dist/chunk-JCV4GXWB.js.map +1 -0
  175. package/dist/chunk-K47P7QZC.js +17 -0
  176. package/dist/chunk-K47P7QZC.js.map +1 -0
  177. package/dist/{chunk-MOBRFZH3.js → chunk-OUK6QRDR.js} +2 -12
  178. package/dist/chunk-OUK6QRDR.js.map +1 -0
  179. package/dist/{chunk-VNPQDCQZ.js → chunk-QOWG4ZCL.js} +3 -2
  180. package/dist/chunk-QOWG4ZCL.js.map +1 -0
  181. package/dist/{chunk-V65EOWNF.js → chunk-QPUPLNNB.js} +20 -8
  182. package/dist/chunk-QPUPLNNB.js.map +1 -0
  183. package/dist/{chunk-O3EXIBEZ.js → chunk-W4XKTST6.js} +8 -7
  184. package/dist/chunk-W4XKTST6.js.map +1 -0
  185. package/dist/{chunk-K6UNVKDK.js → chunk-XDKAYSVD.js} +3 -1
  186. package/dist/chunk-XDKAYSVD.js.map +1 -0
  187. package/dist/collapsible-panel.d.ts +9 -9
  188. package/dist/collapsible-panel.js +2 -2
  189. package/dist/collapsible-panel.js.map +1 -1
  190. package/dist/index.d.ts +2 -1
  191. package/dist/index.js +11 -9
  192. package/dist/list-action-row.js +2 -1
  193. package/dist/list-header.js +1 -1
  194. package/dist/list-item.js +2 -1
  195. package/dist/nav-stack.d.ts +13 -1
  196. package/dist/nav-stack.js +1 -1
  197. package/dist/pane.d.ts +20 -3
  198. package/dist/pane.js +1 -1
  199. package/dist/{panel-toolbar-C8sF-YZC.d.ts → panel-toolbar-DqwtBxQL.d.ts} +13 -13
  200. package/dist/select.js +1 -1
  201. package/dist/split-view.d.ts +3 -3
  202. package/dist/split-view.js +3 -2
  203. package/dist/split-view.js.map +1 -1
  204. package/dist/state-banner.js +1 -1
  205. package/dist/styles/app-tab.css +31 -0
  206. package/dist/styles/badge.css +19 -11
  207. package/dist/styles/collapsible-panel.css +13 -9
  208. package/dist/styles/floating-toolbar.css +25 -6
  209. package/dist/styles/list-header.css +0 -12
  210. package/dist/styles/list.css +4 -4
  211. package/dist/styles/nav-stack.css +46 -19
  212. package/dist/styles/pane.css +50 -0
  213. package/dist/styles/popup-menu.css +151 -0
  214. package/dist/styles/resizable-region.css +22 -10
  215. package/dist/styles/select.css +28 -14
  216. package/dist/styles/skeleton.css +30 -3
  217. package/dist/styles/split-view.css +10 -7
  218. package/dist/styles/state-banner.css +0 -19
  219. package/dist/styles/surface-scaffold.css +8 -3
  220. package/dist/styles/tab-bar.css +79 -28
  221. package/dist/styles/tab-scaffold.css +25 -1
  222. package/dist/styles/text.css +16 -0
  223. package/dist/styles/toolbar-control-group.css +121 -66
  224. package/dist/styles/toolbar-text.css +21 -0
  225. package/dist/styles/toolbar.css +8 -32
  226. package/dist/styles/workbench.css +18 -18
  227. package/dist/tab-scaffold.d.ts +11 -1
  228. package/dist/tab-scaffold.js +2 -0
  229. package/dist/tab-scaffold.js.map +1 -1
  230. package/dist/toolbar-control-group.d.ts +3 -1
  231. package/dist/toolbar-control-group.js +1 -1
  232. package/dist/toolbar-text.d.ts +7 -1
  233. package/dist/toolbar-text.js +1 -1
  234. package/dist/toolbar.d.ts +8 -1
  235. package/dist/toolbar.js +1 -1
  236. package/dist/{types-DXAGogOS.d.ts → types-BuHELdXR.d.ts} +1 -1
  237. package/dist/wire-catalog.d.ts +3 -1
  238. package/dist/wire-catalog.js +2 -0
  239. package/dist/wire-catalog.js.map +1 -1
  240. package/dist/wire-scroll-dividers.d.ts +69 -0
  241. package/dist/wire-scroll-dividers.js +3 -0
  242. package/dist/wire-scroll-dividers.js.map +1 -0
  243. package/dist/workbench.d.ts +17 -16
  244. package/dist/workbench.js +1 -1
  245. package/docs/app-layouts.md +9 -1
  246. package/docs/catalog.md +10 -5
  247. package/docs/collapsible-panel.md +22 -13
  248. package/docs/component-contract.md +147 -21
  249. package/docs/component-selection.md +21 -8
  250. package/docs/design/templates/tab-bar/workspace-tabs-dark.svg +1 -1
  251. package/docs/design/templates/tab-bar/workspace-tabs.svg +1 -1
  252. package/docs/design/templates/tab-bar-dark.svg +1 -1
  253. package/docs/design/templates/tab-bar.svg +1 -1
  254. package/docs/design-philosophy.md +30 -3
  255. package/docs/examples/application-ui-profile.json +4 -4
  256. package/docs/examples/{component-catalog-extension-v2.json → component-composition-extension.json} +3 -3
  257. package/docs/layout.md +82 -3
  258. package/docs/nav-stack.md +33 -3
  259. package/docs/split-view.md +10 -5
  260. package/docs/tab-scaffold.md +23 -1
  261. package/docs/type-contracts.md +4 -3
  262. package/docs/ui-analyzer.md +99 -5
  263. package/docs/ui-doctor.md +10 -0
  264. package/docs/workbench.md +31 -20
  265. package/doctor/index.mjs +6 -1
  266. package/llms.txt +85 -20
  267. package/package.json +17 -5
  268. package/ux-demo/recipes/collapsible-sidebar.tsx +0 -1
  269. package/ux-demo/recipes/composer-form.tsx +0 -1
  270. package/ux-demo/recipes/list-detail-dialog.tsx +0 -2
  271. package/ux-demo/recipes/list-workspace-states.tsx +0 -1
  272. package/ux-demo/recipes/loading-inspector.tsx +0 -1
  273. package/ux-demo/recipes/workspace-header.tsx +0 -1
  274. package/ai/component-catalog-extension-v2.d.ts +0 -7
  275. package/ai/component-catalog-extension-v2.schema.json +0 -7
  276. package/dist/chunk-AK67F6QN.js.map +0 -1
  277. package/dist/chunk-G33XC2NB.js.map +0 -1
  278. package/dist/chunk-K6UNVKDK.js.map +0 -1
  279. package/dist/chunk-MA6Z6EIM.js.map +0 -1
  280. package/dist/chunk-MOBRFZH3.js.map +0 -1
  281. package/dist/chunk-O3EXIBEZ.js.map +0 -1
  282. package/dist/chunk-PK4N5QTO.js.map +0 -1
  283. package/dist/chunk-QQOTQTDD.js.map +0 -1
  284. package/dist/chunk-T4UZTNZ4.js.map +0 -1
  285. package/dist/chunk-V65EOWNF.js.map +0 -1
  286. package/dist/chunk-VNPQDCQZ.js.map +0 -1
  287. package/dist/chunk-ZIYOJFZD.js.map +0 -1
package/docs/catalog.md CHANGED
@@ -281,7 +281,7 @@ import {
281
281
  wireCatalog,
282
282
  wireCatalogGeometryOverlay,
283
283
  } from "@kerfjs/ui/wire-catalog";
284
- import "@kerfjs/ui/styles.css"; // or import each primitive's CSS + @kerfjs/ui/catalog.css
284
+ // A CSS-aware (browser-condition) bundler loads the Catalog's CSS with its import.
285
285
 
286
286
  type DemoKind = "component" | "composition";
287
287
  type DemoEntry = CatalogSection["entries"][number] & { kind: DemoKind };
@@ -411,7 +411,9 @@ revealCatalogEntry(app, initial, { block: "center" });
411
411
  - **`mainToolbar` / `footerToolbar`** take the entry toolbar's and the resource
412
412
  footer toolbar's `ToolbarConfig` (`dividerSides`, `centerAlign`, `responsive`,
413
413
  `responsiveAt`, `safeAreaEdges`). The defaults are a wrapping entry toolbar
414
- and a divider-free footer toolbar that stacks at `narrow`; an omitted or
414
+ and a footer toolbar that stacks at `narrow`, all without dividers of their
415
+ own: `wireCatalog` wires `wireScrollDividers`, so the shell's panes draw
416
+ their chrome dividers only while scrolled; an omitted or
415
417
  `undefined` field keeps them. Configure these instead of styling the shell.
416
418
  - **`theme`** is a global preference — the app's signal; `wireCatalog` only reports
417
419
  the toggle, the app applies the theme (the shell reads `theme` to show the toggle's
@@ -429,7 +431,10 @@ matching options on `wireCatalog`) if they collide with your own action table.
429
431
  `Catalog` composes public components (`Workbench`, `Pane`, `Toolbar`, `List`,
430
432
  `ListHeader`, `ListItem`, `ListInsetText`, `Text`, …) and owns only the preview stage
431
433
  (the checkerboard and centered canvas), the geometry overlay, the example viewport
432
- options, and the brand mark's size. Import `@kerfjs/ui/styles.css` for the whole
433
- layer, or `@kerfjs/ui/catalog.css` plus `@kerfjs/ui/workbench.css` and each composed
434
- primitive's CSS. Like any Workbench it needs a definite containing height — the
434
+ options, and the brand mark's size. A bundler that honors the `browser` export
435
+ condition loads the Catalog's stylesheets and those of every component it renders
436
+ internally with the `@kerfjs/ui/catalog` import alone — no dependence on which other
437
+ subpaths the app happens to import. Without that condition, import
438
+ `@kerfjs/ui/styles.css` for the whole layer, or `@kerfjs/ui/catalog.css` plus
439
+ `@kerfjs/ui/workbench.css` and each composed primitive's CSS. Like any Workbench it needs a definite containing height — the
435
440
  `@kerfjs/ui/document.css` baseline's `.kui-app-root`.
@@ -10,7 +10,10 @@ subpath-only, tree-shakeable modules that add nothing to the main barrel.
10
10
  npm install @kerfjs/ui # kerfjs is a peer
11
11
  ```
12
12
 
13
- Import the panel CSS (`@kerfjs/ui/collapsible-panel.css`) alongside `foundation.css`.
13
+ A browser bundler that honors the `browser` export condition loads the panel's CSS
14
+ and that of the components it renders (`Pane`, `Toolbar`, `ToolbarControlGroup`,
15
+ `LucideIcon`) with `@kerfjs/ui/collapsible-panel`. Without that condition, import
16
+ `@kerfjs/ui/collapsible-panel.css` plus those stylesheets alongside `foundation.css`.
14
17
 
15
18
  ## The pieces
16
19
 
@@ -126,33 +129,40 @@ Give a panel a `toolbar` (the same roles as a
126
129
  [Workbench panel toolbar](workbench.md#panel-toolbars)) and it composes its own
127
130
  top toolbar over a `Pane`, with an optional `footer` below its content:
128
131
 
129
- - `title` and `panelOnly` groups lead it and are available only while it is open,
130
- as is optional `center` content;
131
- - `constant` groups and the standard `toggle: { action, name, showLabel?,
132
- hideLabel? }` trail it.
132
+ - `title` precedes the `leading` zone; `leading`, `center`, and `trailing`
133
+ place groups wherever the open panel needs them;
134
+ - a `ToolbarControlGroup` marked `relocateOnCollapse` stays available in the
135
+ work area when the panel closes; the standard `toggle: { action, name,
136
+ showLabel?, hideLabel? }` is always the final group.
133
137
 
134
138
  The toolbar also takes the `Toolbar`'s configuration (`dividerSides`,
135
- `centerAlign`, `responsive`, `responsiveAt`, `safeAreaEdges`); it keeps its
136
- bottom divider unless `dividerSides` says otherwise. The `Pane` under it takes
137
- the panel's `pane` (`PaneConfig`: `contentElement`, `contentLabel`,
138
- `separators`, `safeAreaEdges`) — for example `{ contentElement: "nav",
139
+ `centerAlign`, `responsive`, `responsiveAt`, `safeAreaEdges`); it draws no
140
+ divider of its own unless `dividerSides` says so. The `Pane` under it draws
141
+ the line under the toolbar only while its content is scrolled (see
142
+ [Scroll dividers](./layout.md#scroll-dividers)), and takes the panel's `pane`
143
+ (`PaneConfig`: `contentElement`, `contentLabel`, `separators`,
144
+ `safeAreaEdges`, `chromeDividers`) — for example `{ contentElement: "nav",
139
145
  contentLabel: "Sections" }` for a navigation rail. An omitted or `undefined`
140
146
  field keeps the `Pane` default; without a `toolbar` there is no `Pane`, so
141
147
  `pane` is ignored.
142
148
 
143
149
  A standalone panel does not own the rest of the screen, so the app places a
144
150
  `CollapsiblePanelRelocated` in its own work-area toolbar: it renders the panel's
145
- `constant` groups and toggle while the panel is collapsed, and nothing while it
151
+ marked groups and toggle while the panel is collapsed, and nothing while it
146
152
  is open. Put it first in the leading zone for a left rail, last in the trailing
147
153
  zone for a right rail, and last in a bottom toolbar for a bottom drawer. With no
148
154
  bottom toolbar, pass it inside a `FloatingToolbar` as the drawer's
149
155
  `restoreControl`.
156
+ Marked groups move in `leading`, `center`, `trailing` order. Pass each marked
157
+ group directly or in an array rather than wrapping it in a JSX fragment, so
158
+ the panel can read its render-time annotation. Its copy in the closed panel is
159
+ inert; avoid duplicate `id` attributes on marked groups.
150
160
 
151
161
  ```tsx
152
162
  const toolbar: CollapsiblePanelToolbar = {
153
163
  label: "Navigator",
154
- panelOnly: <NewFileGroup />,
155
- constant: <SearchGroup />,
164
+ leading: <NewFileGroup />,
165
+ trailing: <ToolbarControlGroup relocateOnCollapse label="Search files"><SearchButton /></ToolbarControlGroup>,
156
166
  toggle: { action: "toggle-nav", name: "navigator" },
157
167
  };
158
168
 
@@ -241,7 +251,6 @@ import {
241
251
  CollapsiblePanelToggle,
242
252
  } from "@kerfjs/ui/collapsible-panel";
243
253
  import { wireSidebar } from "@kerfjs/ui/wire-sidebar";
244
- import "@kerfjs/ui/collapsible-panel.css";
245
254
 
246
255
  const device = deviceClass();
247
256
  // Start collapsed on a compact device; `inlineCollapsed` keeps the open inline
@@ -18,12 +18,33 @@ package delivery paths, Web Awesome's installed manifest, AI guidance, and
18
18
  documentation links. Nuanced prose in this contract and the selection guide
19
19
  remains authored rather than generated.
20
20
 
21
- ### Composition catalog v2
22
-
23
- [`component-catalog-v2.json`](../ai/component-catalog-v2.json) adds a formal,
24
- machine-evaluable composition layer without changing the v1 selection and
25
- delivery contract. Every v1 entry projects once, in order, under the stable
26
- qualified key `package:id`. Each v2 entry explicitly covers parents/contexts,
21
+ ### Markdown component reference (AI entry point)
22
+
23
+ [`ai/components/README.md`](../ai/components/README.md) and one
24
+ `ai/components/<id>.md` page per catalog entry are the assistant-facing view of
25
+ both catalogs. An assistant reads the index, then only the pages it uses,
26
+ instead of loading the full JSON. Each page merges the entry's selection facts
27
+ (purpose, use/avoid, alternatives), delivery (JavaScript subpath, CSS,
28
+ registration, wiring helpers), a link into `public-api-signatures-v1.md` for
29
+ exact props, composition (parents, contexts, zones with their JSX prop and
30
+ cardinality, children), state and wiring ownership including wiring-owned
31
+ state attributes, geometry, accessibility obligations, public class and token
32
+ hooks framed as a styling boundary (components own their styles; configure
33
+ through props rather than overriding internals), and `KUI-C###` diagnostics
34
+ with their conditions. `scripts/sync-component-docs.mjs` renders them only from
35
+ `component-catalog.json` and `component-composition.json` (plus the signature
36
+ file's module headings for anchors), sorted and Prettier-formatted;
37
+ `check:catalog` rejects a stale, missing, or orphaned page. The JSON files stay
38
+ the canonical tool-facing sources.
39
+
40
+ ### Composition catalog
41
+
42
+ [`component-composition.json`](../ai/component-composition.json) adds a formal,
43
+ machine-evaluable composition layer beside `component-catalog.json` without
44
+ changing its selection and delivery contract; it is a generated companion, not
45
+ a newer version of that catalog. Every component-catalog entry projects once,
46
+ in order, under the stable qualified key `package:id`. Each composition entry
47
+ explicitly covers parents/contexts,
27
48
  named zones and cardinality, optional explicit JSX prop bindings, child concepts, state ownership, required wiring,
28
49
  responsive ownership, layout and geometry, accessibility obligations, public
29
50
  CSS boundaries, diagnostics, and provenance. A wrapper entry may add
@@ -31,6 +52,18 @@ CSS boundaries, diagnostics, and provenance. A wrapper entry may add
31
52
  composition checks treat its elements as each root rather than as an unknown
32
53
  child.
33
54
 
55
+ `boundaries.placeableClasses` names the subset of `publicClasses` an
56
+ application may write onto its own elements (layout utilities, the document
57
+ root, item geometry on another carrier); absent means none, and every other
58
+ public class is the component's rendered anatomy. `boundaries.rootElement`
59
+ names the element a component renders around its own placeable classes
60
+ (`content-item`: `div`), so a plain element of that tag carrying them is still
61
+ the component recreated. `eslint-plugin-kerfjs`'s `ui-public-boundaries`
62
+ reports both as `KUI-L103` with the export to render — for `@kerfjs/ui` and for
63
+ every consumer catalog a `.kerf-ui-profile.json` declares, whatever the class
64
+ prefix. `create-kerf-component` packages declare the same fields in
65
+ `kerf.components.json`.
66
+
34
67
  An entry's optional `cssValueProps` makes CSS-adjacent prop grammar equally
35
68
  machine-evaluable. Each path records the property grammar, finite shorthands,
36
69
  canonical versus exceptional spacing choices, standalone and expression-only
@@ -46,7 +79,8 @@ ESLint, `kerf-ui-analyze`, and `kerf-ui-doctor` then issue the same stable
46
79
  (`on`), the `helper` that writes it, and what it means. An application must not
47
80
  render, remove, or treat these attributes as its own state; tools use the list
48
81
  to tell them apart from app-authored attributes. They are declared once, on the
49
- helper's wiring item in the v1 catalog, and v2 flattens them. `check:catalog`
82
+ helper's wiring item in the component catalog, and the composition catalog
83
+ flattens them. `check:catalog`
50
84
  reads each `wire*` helper's source and fails when its declarations differ from
51
85
  the `data-*` attributes it actually writes. First-party entries always carry
52
86
  the list, empty when their helpers write none; it is optional in extension
@@ -55,7 +89,7 @@ catalogs.
55
89
  The generator starts with permissive defaults. An `any` mode records that the
56
90
  catalog has no defensible prohibition; it does not claim every composition is
57
91
  recommended. Objective rules live in
58
- `component-catalog-v2-overrides.json` and may carry stable `KUI-C###`
92
+ `component-composition-rules.json` and may carry stable `KUI-C###`
59
93
  diagnostics. A tool reports a diagnostic only after proving its exact `when`
60
94
  condition. Subjective choice, product policy, and visual taste remain prose.
61
95
 
@@ -64,7 +98,7 @@ Use `children` for one homogeneous primary region; use explicit named
64
98
  `SafeHtml` props for semantic positions or replacement content such as
65
99
  `header`, `footer`, `leading`, `trailing`, `icon`, and `action`. These are typed
66
100
  function-component props, not native web-component `<slot>` elements and not a
67
- generic `slots={{...}}` object. A v2 zone declares `jsx.prop` only when tooling
101
+ generic `slots={{...}}` object. A composition zone declares `jsx.prop` only when tooling
68
102
  can soundly bind that zone to one public JSX prop; `children` is spelled
69
103
  explicitly. Zones without that binding remain guidance and are never guessed
70
104
  from their ids. Static tools inspect only visible JSX structure and leave
@@ -85,13 +119,14 @@ can return a region plus a sibling restore control, leaving no single root that
85
119
  can truthfully own native slot assignment. Their single-root controls and all
86
120
  alternate-root branches of supported components retain the contract.
87
121
 
88
- V1 consumers continue unchanged. V2 consumers read v1 for selection/delivery
89
- and v2 for composition. `npm run catalog:sync` projects every new component,
122
+ Component-catalog consumers continue unchanged. Composition-aware consumers
123
+ read `component-catalog.json` for selection/delivery and
124
+ `component-composition.json` for composition. `npm run catalog:sync` projects every new component,
90
125
  recipe, and supported Web Awesome entry, and the completeness gate prevents
91
- silent omissions. Downstream catalogs use the v2 extension schema and types,
126
+ silent omissions. Downstream catalogs use the composition extension schema and types,
92
127
  retain their own package identity, and qualify cross-catalog references. See
93
128
  the checked
94
- [`component-catalog-extension-v2.json`](./examples/component-catalog-extension-v2.json)
129
+ [`component-composition-extension.json`](./examples/component-composition-extension.json)
95
130
  application-owned example.
96
131
 
97
132
  ### Compile-time contract boundary
@@ -117,10 +152,11 @@ layout/responsive conventions, and narrow rule exceptions there. Product
117
152
  records, copy, permissions, user preferences, and transport state do not belong
118
153
  in this policy file.
119
154
 
120
- Every catalog location names a v2 composition artifact. `selection` is optional
121
- for consumer packages whose generated metadata declares v1 selection guidance
122
- not applicable; `@kerfjs/ui` retains its required v1 selection artifact. This
123
- lets a generated `component-catalog-v2.json` participate directly without a
155
+ Every catalog location names a composition artifact. `selection` is optional
156
+ for consumer packages whose generated metadata declares component-catalog
157
+ selection guidance not applicable; `@kerfjs/ui` retains its required
158
+ `component-catalog.json` selection artifact. This
159
+ lets a generated `component-composition.json` participate directly without a
124
160
  fabricated compatibility file.
125
161
 
126
162
  Discovery and precedence are deterministic:
@@ -147,6 +183,22 @@ I/O.
147
183
  See the
148
184
  [`application-ui-profile.json`](./examples/application-ui-profile.json) example.
149
185
 
186
+ The package defaults avoid every `Discouraged` Web Awesome entry — each
187
+ `webawesome` catalog entry whose `recommendation` is not `supported`, except the
188
+ encouraged `wa-popup` primitive — under a concept whose `preferred` value is the
189
+ Kerf component that wraps or replaces it (`command-menu` → `PopupMenu`,
190
+ `value-selection` → `Select`, `application-tabs` → `TabBar`, `icon` →
191
+ `LucideIcon`, `resizable-pane` → `ResizableRegion`, `exclusive-choice` →
192
+ `SegmentedControl`, `hierarchy-navigation` → `List`, `embedded-media` →
193
+ `ContentItem`). `eslint-plugin-kerfjs` `ui-preferences` (`KUI-L301`, also run by
194
+ `kerf-ui-doctor`) therefore reports a Discouraged element written directly as a
195
+ JSX tag (`<wa-dropdown>`) as well as through an imported component. A declared
196
+ component's own source file is exempt, because that wrapper is the sanctioned
197
+ owner of the element it renders. A unit test holds the avoid set and the
198
+ catalog's Discouraged set equal in both directions, so neither can drift. A
199
+ product that genuinely needs one of these elements records a narrow `KUI-L301`
200
+ profile exception for the file that renders it.
201
+
150
202
  Catalog detail footers use one standard resource vocabulary and order. Build
151
203
  them with `catalogResources()` from `@kerfjs/ui/catalog-resources`: `Demo source`
152
204
  first, optional `Component source` and `Design template`, then `Guidance`.
@@ -232,7 +284,72 @@ documented props and tokens; package components may compose other components
232
284
  only through those public contracts, never by styling a child's classes from a
233
285
  parent stylesheet.
234
286
 
235
- The v2 composition catalog additionally requires `boundaries.rootClass` to be
287
+ Inside the package, a component never styles another component or writes
288
+ another component's variables. When a child must adapt to a composing parent,
289
+ the child styles itself in that context from its own stylesheet: the parent's
290
+ class and state appear only in an ancestor compound, the styled compound is
291
+ the child's own class (or one of the child's own unclassed internals below
292
+ it), and the child reads context values the parent provides under the
293
+ parent's name. `ResizableRegion` widens its edge extent by the unsafe inset a
294
+ split `SplitView` provides, and a `Skeleton` derives its fill from a solid
295
+ `Badge`'s on-solid color, both in their own stylesheets; an `AppTab` rounds its
296
+ outer corners in a segmented `TabBar` and shares a fill-allocated strip from
297
+ `app-tab.css`. A `PopupMenu` sizes
298
+ its trigger and applies a group's `menuInset` in its own stylesheet, and an
299
+ icon-only `Select` reads the control slot a `ToolbarControlGroup` provides
300
+ (`--_kui-toolbar-control-group-slot-*`). A parent may still style its own
301
+ elements keyed on a child's state, naming the child by class inside `:has()`
302
+ (`:has(> .kui-select[open])`, or `TabBar` insetting a segmented strip that
303
+ holds compact tabs), and it keeps styling raw native and raw Web
304
+ Awesome children no kerf component owns, excluding kerf children by class
305
+ (`wa-dropdown:not(.kui-popup-menu)`). `npm run check:css-ownership` enforces
306
+ this in every component stylesheet (a `src/*.css` with a same-basename
307
+ component), deriving the component names, the Web Awesome tags each component
308
+ renders, and its composed children from `src/*.tsx`:
309
+
310
+ - **Foreign classes.** Another component's class or `[data-component]` may
311
+ appear only in an ancestor compound or inside `:has()` / `:not()`; the
312
+ styled compound is the stylesheet's own class.
313
+ - **Owned Web Awesome tags.** Kerf components are named by class, never by a
314
+ `wa-*` tag they render. A tag another component renders (`wa-dropdown`,
315
+ `wa-select`, `wa-option`, a `PopupMenu`'s trigger `wa-button`) — as the
316
+ subject, or as an ancestor whose internals the rule reaches — must be scoped
317
+ to that component by its class or excluded with `:not()`. A direct child
318
+ that cannot be the owner's internal
319
+ (`.kui-toolbar-control-group > wa-button`) needs no exclusion.
320
+ - **Variables.** A stylesheet writes only its own `--_kui-<self>-*` private
321
+ variables, and never overrides a public `--kui-<other>-*` token that another
322
+ component reads. Shared foundation tokens (`--kui-layout-*`,
323
+ `--kui-color-*`, …) are not any one component's. Context a parent provides
324
+ is named after the parent.
325
+ - **Context on any child.** Custom properties set on a subject that can be any
326
+ element (`.kui-x > *`, `> :not(…)`) also land on composed components' roots.
327
+ - **Hook classes.** A class the component places on a composed kerf child's
328
+ root (`<ToolbarText className="kui-nav-stack__title">`, a class NavStack once styled) may not be styled;
329
+ the child styles itself in that context instead.
330
+
331
+ The documented exceptions live with their reasons in
332
+ `scripts/lib/css-ownership.mjs`, and an exception that stops matching fails the
333
+ check, so the list only shrinks. The layout regions' inherited edge-inset
334
+ context (`--kui-edge-inset-*` handed to a sole Pane or layout child and cleared
335
+ for any other content, and a Toolbar clearing it for its zones) is the one
336
+ design exception; the others name the open fix ticket.
337
+
338
+ Applications and component packages built on the package follow the same
339
+ rules, and the downstream tools enforce them against the composition catalog
340
+ instead of package source: `kerf-ui-analyze` / `kerf-ui-doctor` report a rule
341
+ whose subject is another package's component (`KUI-L019`), another
342
+ component's private `--_*` variable (`KUI-L020`), an override of a token a
343
+ typed prop sets (`KUI-L021`), and a hook class on a component's root
344
+ (`KUI-L022`); `eslint-plugin-kerfjs`'s `ui-component-ownership` reports
345
+ `KUI-L020` / `KUI-L021` in script. Both share the selector parsing in
346
+ `analyzer/selectors.mjs` with `check:css-ownership`, and
347
+ `check:css-ownership` fails when a component renders a Web Awesome tag the
348
+ catalog does not list, so `KUI-L019` keeps covering every tag a kerf component
349
+ renders. Each finding names the configuration to use and routes a missing
350
+ prop to a component-gap report (see [the analyzer guide](./ui-analyzer.md#component-ownership-kui-l019kui-l022)).
351
+
352
+ The composition catalog additionally requires `boundaries.rootClass` to be
236
353
  either one exact member of `publicClasses` or `null` when the entry has no
237
354
  rendered class root. Runtime geometry tooling uses this explicit field; array
238
355
  order never implies root ownership.
@@ -262,7 +379,11 @@ primary label should wrap rather than truncate. A single-line row ends its
262
379
  primary label and description with an ellipsis before the trailing status
263
380
  slot, even when the label is one long word; a `multiline` row wraps instead,
264
381
  breaking a word wider than the label column (a long component or file name)
265
- rather than letting it run under the trailing slot. `ListActionRow` labels
382
+ rather than letting it run under the trailing slot. A string label in a
383
+ `multiline` row gets line-break opportunities at its camelCase and acronym
384
+ boundaries, so `QuickTicketComposer` wraps as `QuickTicket` / `Composer`
385
+ rather than mid-word; breaking anywhere is only the last resort for a single
386
+ word that is still too wide. The text and accessible name are unchanged. `ListActionRow` labels
266
387
  follow the same single-line and `multiline` rules before the trailing action.
267
388
 
268
389
  `DisclosureArrow` uses an 18px root-scaled visual by default. Pass its typed
@@ -308,7 +429,9 @@ inset. `ToolbarControlGroup` publishes its derived radius to nested toolbar
308
429
  highlights concentric when the group switches between pill and rounded shapes.
309
430
 
310
431
  `ResizableRegion` owns the Hot Sheet 2 split treatment: a persistent 1px
311
- separator with a compact grip that appears on hover or keyboard focus. Override
432
+ separator with a compact grip that appears on hover or keyboard focus. The grip
433
+ is drawn centered on the separator line even though the pointer target is wider
434
+ than the line, so the handle never reads as offset into a pane. Override
312
435
  `--kui-resizable-region-separator-color`,
313
436
  `--kui-resizable-region-handle-color`, or
314
437
  `--kui-resizable-region-handle-active-color` on a region when its containing
@@ -362,7 +485,10 @@ group that replaces wider toolbar controls below the Toolbar's compact container
362
485
  breakpoint; do not hide the group with an application class. Reach for
363
486
  `wa-button` only when you need
364
487
  a Web Awesome feature; a popup menu is a `PopupMenu`, which renders its own
365
- trigger. For a compact mixed-content group, set `nestedDropdown`; a
488
+ trigger. Nothing wraps inside a group: an icon sits beside its label on one
489
+ row, and a group's controls never break onto a second line — the group sizes
490
+ to its content and the enclosing `Toolbar`'s responsive policy relocates whole
491
+ groups. For a compact mixed-content group, set `nestedDropdown`; a
366
492
  text-and-caret trigger grows to its intrinsic width while an icon-only trigger
367
493
  can remain square. A compact icon `<button>` is a 32px circle, so a selected
368
494
  compact segment never becomes an oval. An icon-only `Select` joins a group as
@@ -5,7 +5,7 @@ Use the shipped [`component-catalog.json`](../ai/component-catalog.json) when a
5
5
  tool needs exhaustive structured facts; this page remains the concise human
6
6
  decision procedure.
7
7
 
8
- 1. Search the [Kerf UX catalog](./ux-demo.md) and the supported Web Awesome set.
8
+ 1. Search the [Kerf UX catalog](./ux-demo.md) and the supported Web Awesome set. Prefer a Kerf UI component over a Web Awesome component over a raw HTML tag, using each naturally for what it is good at.
9
9
  2. Reuse a primitive when its purpose, anatomy, state, and interaction match.
10
10
  3. Compose primitives for recurring layout through public props and tokens. Do not select one component from another component's stylesheet.
11
11
  4. Add a thin application adapter for product copy, domain mapping, actions, routing, persistence, permissions, and transport.
@@ -149,6 +149,7 @@ an upstream component or recipe request.
149
149
  | Inset bare text — `ListInsetText` | A plain string or inline content with no margin, border, or padding of its own must sit in a `.kui-content` list with its text edge aligned to the bordered items around it. | Do not use it to wrap a component that already owns content-item geometry (`ListItem`, `StateBanner`, a `.kui-content-item`) — that double-insets it. Do not hand-roll the 8px margin / 1px border / 8px padding. | Pass the text or inline `SafeHtml` as children; it supplies the 8px inline margin, 1px transparent border, and 8px padding so the text edge lands at the standard 17px inset. Pass `sides="rl"` to keep that horizontal inset but drop the vertical margin, border, and padding for tight text layout. | The text, copy, and localization. | `@kerfjs/ui/list-inset-text` | [Pane geometry](../README.md#component-subpaths) |
150
150
  | Self-contained content child — `ContentItem` | An ordinary surface-like child of a `Pane` or `.kui-content` stack needs the shared 8px margin / 1px border / 8px padding geometry; pass `frame="framed"` only when it marks a real distinction and must read as visibly bounded, and `shape="pill"` for the 22px radius. | Do not wrap a component that already owns content-item geometry (`ListItem`, `ListHeader`, `StateBanner`, `Toolbar`, `ValueTable`) or pad around it — that double-insets. Do not frame an item only to make it look contained. Use `SunkenPanel` for a lowered filled surface and `ListInsetText` for bare text that only needs to align. | Pass the item content as children; choose `frame` (`none` default, `framed`) and `shape` (`rounded` default, `pill`) instead of writing `.kui-content-item` modifier classes. Put safe `data-*` metadata in `rootAttributes`; `ariaLabel` names a distinct region and `focusTarget` makes it a programmatic focus target. | The content and whether it marks a distinction worth a visible frame. | `@kerfjs/ui/content-item` | [Content items](./layout.md#content-items) |
151
151
  | Application column — `Pane` | A sidebar, main area, inspector, or dialog needs shared vertical header/content/footer organization, one scroll owner, and optional edge separators. | Do not pad the pane shell, wrap child-owned geometry in competing insets, invent unrelated centered measures, or leave an icon-only rail for a hidden pane. | Import `Pane`, use `children` for its homogeneous primary content and the named `SafeHtml` prop slots `header`/`footer` for optional fixed chrome, then opt into only the needed logical-edge separators; add `ContentItem` children as needed. A visible pane owns collapse in its toolbar; move a hidden inline-start pane's restore control to the main toolbar leading edge and an inline-end pane's restore control to its trailing edge. | Layout hierarchy, reading width, responsive relocation, pane visibility state, slot semantics, labels, and separator placement. | `@kerfjs/ui/pane` | [Pane anatomy](./layout.md#anatomy) |
152
+ | Scroll dividers — `wireScrollDividers` | Pinned chrome (a `Pane` header or footer, a `NavStack` top chrome or bottom toolbar, a `TabScaffold` bar, the sides of a `TabBar` strip, or app-owned chrome around a scroller) needs a divider only while content is scrolled away beneath it. | Do not keep a static toolbar divider to fake it or write a border onto another component; each component draws its own line from the wiring's state. | Call `wireScrollDividers` once at the app root and retain the disposer; it covers every `Pane`, `NavStack`, `TabScaffold`, and `TabBar` below it. Name app-owned arrangements in `targets` by id; a `Toolbar` or `List` named as chrome draws its facing side. Configure a pane with `chromeDividers` (`scroll` default, `always`, `none`). | Which panes follow the scroll, app-owned targets, and the disposer. | `@kerfjs/ui/wire-scroll-dividers` | [Scroll dividers](./layout.md#scroll-dividers) |
152
153
  | One-pane navigation — `NavStack` | A compact flow pushes into details while keeping earlier views mounted, or a single-pane screen needs the same stable layout contract. | Do not use it when list and detail should remain visible together; use `SplitView`. Do not use it alone for co-equal top-level destinations; use one stack per `TabScaffold` tab. | Keep the ordered view array controlled, put view-specific bottom chrome on each view (or use the component fallback), import its CSS explicitly, and call `wireNavStack` for back delegation, content-slide/chrome-cross-fade transitions, and focus move/restore. Mark a preferred initial target with `data-nav-focus` when DOM order is insufficient. | View keys/content/titles, push and pop actions, preferred initial focus targets, and per-view or persistent bottom toolbar content. | `@kerfjs/ui/nav-stack` | [App-layout decision matrix](./app-layouts.md#decision-matrix) |
153
154
  | Responsive list-detail — `SplitView` | A primary list and related detail belong together on roomy devices but become a one-pane drill-down on compact devices. | Do not use it for a single linear flow or a multi-panel editor shell. | Provide controlled selection/detail state and device class; opt into resize wiring only when the separator is user adjustable. | Selection, detail content, compact back action, device policy, and optional persisted width. | `@kerfjs/ui/split-view` | [App-layout decision matrix](./app-layouts.md#decision-matrix) |
154
155
  | Compact top-level destinations — `TabScaffold` | A handset or portrait-tablet app has two to five co-equal destinations whose scenes and nested navigation must remain mounted across switches. | Do not use it for document tabs, reorderable work items, or a desktop navigation rail. | Keep the active id controlled, import its CSS explicitly, and call `wireTabScaffold`; commonly place one `NavStack` in each tab scene. | Destination definitions, active id, routing, persistence, and roomy-device replacement. | `@kerfjs/ui/tab-scaffold` | [App-layout decision matrix](./app-layouts.md#decision-matrix) |
@@ -190,9 +191,10 @@ an upstream component or recipe request.
190
191
  on the component instead of adding application descendant width/height fixes.
191
192
  It paints `--kui-color-surface` itself (an inline region stays transparent),
192
193
  so do not add a background to make an overlay opaque.
193
- - Give `Workbench` panels a `toolbar` (title, panel-only groups, constant
194
+ - Give `Workbench` panels a `toolbar` (title, `leading` / `center` / `trailing`
194
195
  groups, and a standard `toggle`) and the work area a `mainToolbar` /
195
- `mainBottomToolbar`: the Workbench moves a closed panel's constant groups
196
+ `mainBottomToolbar`: the Workbench moves a closed panel's groups marked
197
+ `relocateOnCollapse`
196
198
  and toggle into the work area's toolbar, so never hand-place or duplicate
197
199
  panel toggles. See [Workbench panel toolbars](workbench.md#panel-toolbars).
198
200
  - Configure application panels through the shared `separator`, `collapseMotion`,
@@ -224,10 +226,18 @@ copy below as app-owned content. Size the title to its track: a narrow
224
226
  peripheral rail or drawer (a navigator, inspector, or console beside a work
225
227
  area that carries the extra-large title, often with its own close control in
226
228
  the header) labels itself with the default size, because extra-large truncates
227
- there — "Inspector" becomes "Ins…" in a 160px rail. A bottom divider is
228
- enabled by default. Set `dividerSides=""` for none, or
229
- use the canonical physical-edge combinations (`t`, `r`, `b`, `l`, in that
230
- order—for example `tr` or `trbl`) when the toolbar owns other separator edges.
229
+ there — "Inspector" becomes "Ins…" in a 160px rail. Nothing wraps inside a
230
+ `ToolbarControlGroup`: an icon sits beside its label on one row and the group
231
+ sizes to its content, so a row that does not fit relocates whole groups
232
+ through the toolbar's `responsive` policy rather than breaking a group. A
233
+ toolbar draws no divider by default: pinned over or under scrolling content,
234
+ it gets one from the scroll state instead — the `Pane` it heads draws the line
235
+ only while content is scrolled beneath it, once `wireScrollDividers` is wired
236
+ (see [Scroll dividers](./layout.md#scroll-dividers)). Set `dividerSides` to the
237
+ canonical physical-edge combinations (`t`, `r`, `b`, `l`, in that order—for
238
+ example `b`, `tr`, or `trbl`) only when the toolbar owns a permanent separator
239
+ edge. Dividers earn their place: never fake one with a border or pad below one
240
+ to make it look right.
231
241
 
232
242
  Common toolbar patterns:
233
243
 
@@ -317,7 +327,10 @@ Web Awesome catalog coverage means supported and themed, not preferred. Import
317
327
  registration, and the CSS-only `@kerfjs/ui/webawesome.css` theme. The UX catalog
318
328
  marks the superseded or exceptional choices below with a visible `Discouraged`
319
329
  tag; Popup remains untagged because low-level anchored positioning can be the
320
- right primitive.
330
+ right primitive. Never render a `Discouraged` element directly in application,
331
+ demo, or recipe markup: reach it only through the Kerf component that wraps or
332
+ replaces it (`PopupMenu` renders `wa-dropdown`; `Select` renders `wa-select` /
333
+ `wa-option`), and file a component gap rather than dropping to the raw tag.
321
334
 
322
335
  | Web Awesome choice | Kerf decision |
323
336
  | ------------------------------------------------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------- |
@@ -1 +1 @@
1
- <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 640 96" width="640" height="96"><defs><clipPath id="cp0"><rect x="28" y="28" width="584" height="44"/></clipPath><clipPath id="ov1"><rect x="29" y="29" width="582" height="42" rx="21"/></clipPath><filter id="sh2" x="-50%" y="-50%" width="200%" height="200%"><feGaussianBlur stdDeviation="1.5"/></filter><clipPath id="cp3"><rect x="67" y="42" width="16.4" height="16"/></clipPath><clipPath id="cp5"><rect x="91.4" y="42.5" width="74.4" height="15"/></clipPath><clipPath id="ct6"><rect x="91.4" y="42.5" width="74.4" height="15"/></clipPath><clipPath id="cp7"><rect x="240.5" y="42" width="16.5" height="16"/></clipPath><clipPath id="cp9"><rect x="264.5" y="42.5" width="47.7" height="15"/></clipPath><clipPath id="ct10"><rect x="264.5" y="42.5" width="47.7" height="15"/></clipPath><clipPath id="cp11"><rect x="387" y="42" width="16" height="16"/></clipPath><clipPath id="cp13"><rect x="411" y="42.5" width="60" height="15"/></clipPath><clipPath id="ct14"><rect x="411" y="42.5" width="60" height="15"/></clipPath></defs><g clip-path="url(#cp0)"><rect x="28.5" y="28.5" width="583" height="43" rx="21.5" fill="none" stroke="rgba(0,0,0,0)" stroke-width="1"/></g><g clip-path="url(#ov1)"><rect x="30" y="31" width="173.1" height="40" rx="20" fill="rgba(0,0,0,0.5)" filter="url(#sh2)"/><rect x="30" y="30" width="173.1" height="40" rx="20" fill="rgb(28,28,30)"/><rect x="30.5" y="30.5" width="172" height="39" rx="19.5" fill="none" stroke="rgba(72,72,74,0.8)" stroke-width="1"/><g clip-path="url(#cp3)"><g color="rgb(138, 203, 255)"><clipPath id="svgic4"><rect x="67.4" y="42" width="16" height="16"/></clipPath><g clip-path="url(#svgic4)"><g transform="translate(67.39 42)scale(.66667)"><path d="M6 22a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h8a2 2 0 0 1 1.7.7l3.6 3.6A2 2 0 0 1 20 8v12a2 2 0 0 1-2 2Z" style="marker:none;vector-effect:none;color-interpolation:srgb" fill="none" stroke="rgb(138, 203, 255)" stroke-width="2px" stroke-dasharray="none" stroke-linecap="round" stroke-linejoin="round" stroke-opacity="1" fill-opacity="1" opacity="1"/><path d="M14 2v5a1 1 0 0 0 1 1h5" style="marker:none;vector-effect:none;color-interpolation:srgb" fill="none" stroke="rgb(138, 203, 255)" stroke-width="2px" stroke-dasharray="none" stroke-linecap="round" stroke-linejoin="round" stroke-opacity="1" fill-opacity="1" opacity="1"/><path d="M10 9H8" style="marker:none;vector-effect:none;color-interpolation:srgb" fill="none" stroke="rgb(138, 203, 255)" stroke-width="2px" stroke-dasharray="none" stroke-linecap="round" stroke-linejoin="round" stroke-opacity="1" fill-opacity="1" opacity="1"/><path d="M16 13H8" style="marker:none;vector-effect:none;color-interpolation:srgb" fill="none" stroke="rgb(138, 203, 255)" stroke-width="2px" stroke-dasharray="none" stroke-linecap="round" stroke-linejoin="round" stroke-opacity="1" fill-opacity="1" opacity="1"/><path d="M16 17H8" style="marker:none;vector-effect:none;color-interpolation:srgb" fill="none" stroke="rgb(138, 203, 255)" stroke-width="2px" stroke-dasharray="none" stroke-linecap="round" stroke-linejoin="round" stroke-opacity="1" fill-opacity="1" opacity="1"/></g></g></g></g><g clip-path="url(#cp5)"><g clip-path="url(#ct6)"><text x="91.39" y="54.5" font-family="system-ui, &quot;-apple-system&quot;, sans-serif" font-size="12" font-weight="650" fill="rgb(138,203,255)">README.md</text></g></g></g><g clip-path="url(#ov1)"><rect x="203.5" y="30.5" width="146" height="39" rx="19.5" fill="none" stroke="rgba(0,0,0,0)" stroke-width="1"/><g clip-path="url(#cp7)"><g color="rgb(174, 174, 178)"><clipPath id="svgic8"><rect x="240.5" y="42" width="16" height="16"/></clipPath><g clip-path="url(#svgic8)"><g transform="translate(240.531 42)scale(.66667)"><path d="M6 22a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h8a2 2 0 0 1 1.7.7l3.6 3.6A2 2 0 0 1 20 8v12a2 2 0 0 1-2 2Z" style="marker:none;vector-effect:none;color-interpolation:srgb" fill="none" stroke="rgb(174, 174, 178)" stroke-width="2px" stroke-dasharray="none" stroke-linecap="round" stroke-linejoin="round" stroke-opacity="1" fill-opacity="1" opacity="1"/><path d="M14 2v5a1 1 0 0 0 1 1h5" style="marker:none;vector-effect:none;color-interpolation:srgb" fill="none" stroke="rgb(174, 174, 178)" stroke-width="2px" stroke-dasharray="none" stroke-linecap="round" stroke-linejoin="round" stroke-opacity="1" fill-opacity="1" opacity="1"/><path d="M10 9H8" style="marker:none;vector-effect:none;color-interpolation:srgb" fill="none" stroke="rgb(174, 174, 178)" stroke-width="2px" stroke-dasharray="none" stroke-linecap="round" stroke-linejoin="round" stroke-opacity="1" fill-opacity="1" opacity="1"/><path d="M16 13H8" style="marker:none;vector-effect:none;color-interpolation:srgb" fill="none" stroke="rgb(174, 174, 178)" stroke-width="2px" stroke-dasharray="none" stroke-linecap="round" stroke-linejoin="round" stroke-opacity="1" fill-opacity="1" opacity="1"/><path d="M16 17H8" style="marker:none;vector-effect:none;color-interpolation:srgb" fill="none" stroke="rgb(174, 174, 178)" stroke-width="2px" stroke-dasharray="none" stroke-linecap="round" stroke-linejoin="round" stroke-opacity="1" fill-opacity="1" opacity="1"/></g></g></g></g><g clip-path="url(#cp9)"><g clip-path="url(#ct10)"><text x="264.53" y="54.5" font-family="system-ui, &quot;-apple-system&quot;, sans-serif" font-size="12" font-weight="650" fill="rgb(174,174,178)">index.ts</text></g></g></g><g clip-path="url(#ov1)"><rect x="350.5" y="30.5" width="157" height="39" rx="19.5" fill="none" stroke="rgba(0,0,0,0)" stroke-width="1"/><g clip-path="url(#cp11)"><g color="rgb(174, 174, 178)"><clipPath id="svgic12"><rect x="387" y="42" width="16" height="16"/></clipPath><g clip-path="url(#svgic12)"><g transform="translate(387.031 42)scale(.66667)"><path d="M6 22a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h8a2 2 0 0 1 1.7.7l3.6 3.6A2 2 0 0 1 20 8v12a2 2 0 0 1-2 2Z" style="marker:none;vector-effect:none;color-interpolation:srgb" fill="none" stroke="rgb(174, 174, 178)" stroke-width="2px" stroke-dasharray="none" stroke-linecap="round" stroke-linejoin="round" stroke-opacity="1" fill-opacity="1" opacity="1"/><path d="M14 2v5a1 1 0 0 0 1 1h5" style="marker:none;vector-effect:none;color-interpolation:srgb" fill="none" stroke="rgb(174, 174, 178)" stroke-width="2px" stroke-dasharray="none" stroke-linecap="round" stroke-linejoin="round" stroke-opacity="1" fill-opacity="1" opacity="1"/><path d="M10 9H8" style="marker:none;vector-effect:none;color-interpolation:srgb" fill="none" stroke="rgb(174, 174, 178)" stroke-width="2px" stroke-dasharray="none" stroke-linecap="round" stroke-linejoin="round" stroke-opacity="1" fill-opacity="1" opacity="1"/><path d="M16 13H8" style="marker:none;vector-effect:none;color-interpolation:srgb" fill="none" stroke="rgb(174, 174, 178)" stroke-width="2px" stroke-dasharray="none" stroke-linecap="round" stroke-linejoin="round" stroke-opacity="1" fill-opacity="1" opacity="1"/><path d="M16 17H8" style="marker:none;vector-effect:none;color-interpolation:srgb" fill="none" stroke="rgb(174, 174, 178)" stroke-width="2px" stroke-dasharray="none" stroke-linecap="round" stroke-linejoin="round" stroke-opacity="1" fill-opacity="1" opacity="1"/></g></g></g></g><g clip-path="url(#cp13)"><g clip-path="url(#ct14)"><text x="411.03" y="54.5" font-family="system-ui, &quot;-apple-system&quot;, sans-serif" font-size="12" font-weight="650" fill="rgb(174,174,178)">styles.css</text></g></g></g></svg>
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 640 96" width="640" height="96"><defs><clipPath id="cp0"><rect x="28" y="28" width="584" height="44"/></clipPath><clipPath id="ov1"><rect x="29" y="29" width="582" height="42" rx="21"/></clipPath><filter id="sh2" x="-50%" y="-50%" width="200%" height="200%"><feGaussianBlur stdDeviation="1.5"/></filter><clipPath id="cp3"><rect x="67" y="42" width="16.4" height="16"/></clipPath><clipPath id="cp5"><rect x="91.4" y="42.5" width="74.4" height="15"/></clipPath><clipPath id="ct6"><rect x="91.4" y="42.5" width="74.4" height="15"/></clipPath><clipPath id="cp7"><rect x="240.5" y="42" width="16.5" height="16"/></clipPath><clipPath id="cp9"><rect x="264.5" y="42.5" width="47.7" height="15"/></clipPath><clipPath id="ct10"><rect x="264.5" y="42.5" width="47.7" height="15"/></clipPath><clipPath id="cp11"><rect x="387" y="42" width="16" height="16"/></clipPath><clipPath id="cp13"><rect x="411" y="42.5" width="60" height="15"/></clipPath><clipPath id="ct14"><rect x="411" y="42.5" width="60" height="15"/></clipPath></defs><g clip-path="url(#cp0)"><rect x="28.5" y="28.5" width="583" height="43" rx="21.5" fill="none" stroke="rgba(0,0,0,0)" stroke-width="1"/></g><g data-domotion-pseudo-source="blink-pseudo-fragment-v1" data-domotion-pseudo="::before" data-domotion-pseudo-owner="source-fragments"><g/></g><g data-domotion-pseudo-source="blink-pseudo-fragment-v1" data-domotion-pseudo="::after" data-domotion-pseudo-owner="source-fragments"><g/></g><g clip-path="url(#ov1)"><rect x="30" y="31" width="173.1" height="40" rx="20" fill="rgba(0,0,0,0.5)" filter="url(#sh2)"/><rect x="30" y="30" width="173.1" height="40" rx="20" fill="rgb(28,28,30)"/><rect x="30.5" y="30.5" width="172" height="39" rx="19.5" fill="none" stroke="rgba(72,72,74,0.8)" stroke-width="1"/><g clip-path="url(#cp3)"><g color="rgb(138, 203, 255)"><clipPath id="svgic4"><rect x="67.4" y="42" width="16" height="16"/></clipPath><g clip-path="url(#svgic4)"><g transform="translate(67.39 42)scale(.66667)"><path d="M6 22a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h8a2 2 0 0 1 1.7.7l3.6 3.6A2 2 0 0 1 20 8v12a2 2 0 0 1-2 2Z" style="marker:none;vector-effect:none;color-interpolation:srgb" fill="none" stroke="rgb(138, 203, 255)" stroke-width="2px" stroke-dasharray="none" stroke-linecap="round" stroke-linejoin="round" stroke-opacity="1" fill-opacity="1" opacity="1"/><path d="M14 2v5a1 1 0 0 0 1 1h5" style="marker:none;vector-effect:none;color-interpolation:srgb" fill="none" stroke="rgb(138, 203, 255)" stroke-width="2px" stroke-dasharray="none" stroke-linecap="round" stroke-linejoin="round" stroke-opacity="1" fill-opacity="1" opacity="1"/><path d="M10 9H8" style="marker:none;vector-effect:none;color-interpolation:srgb" fill="none" stroke="rgb(138, 203, 255)" stroke-width="2px" stroke-dasharray="none" stroke-linecap="round" stroke-linejoin="round" stroke-opacity="1" fill-opacity="1" opacity="1"/><path d="M16 13H8" style="marker:none;vector-effect:none;color-interpolation:srgb" fill="none" stroke="rgb(138, 203, 255)" stroke-width="2px" stroke-dasharray="none" stroke-linecap="round" stroke-linejoin="round" stroke-opacity="1" fill-opacity="1" opacity="1"/><path d="M16 17H8" style="marker:none;vector-effect:none;color-interpolation:srgb" fill="none" stroke="rgb(138, 203, 255)" stroke-width="2px" stroke-dasharray="none" stroke-linecap="round" stroke-linejoin="round" stroke-opacity="1" fill-opacity="1" opacity="1"/></g></g></g></g><g clip-path="url(#cp5)"><g clip-path="url(#ct6)"><text x="91.39" y="54.5" font-family="system-ui, &quot;-apple-system&quot;, sans-serif" font-size="12" font-weight="650" fill="rgb(138,203,255)">README.md</text></g></g></g><g clip-path="url(#ov1)"><rect x="203.5" y="30.5" width="146" height="39" rx="19.5" fill="none" stroke="rgba(0,0,0,0)" stroke-width="1"/><g clip-path="url(#cp7)"><g color="rgb(174, 174, 178)"><clipPath id="svgic8"><rect x="240.5" y="42" width="16" height="16"/></clipPath><g clip-path="url(#svgic8)"><g transform="translate(240.531 42)scale(.66667)"><path d="M6 22a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h8a2 2 0 0 1 1.7.7l3.6 3.6A2 2 0 0 1 20 8v12a2 2 0 0 1-2 2Z" style="marker:none;vector-effect:none;color-interpolation:srgb" fill="none" stroke="rgb(174, 174, 178)" stroke-width="2px" stroke-dasharray="none" stroke-linecap="round" stroke-linejoin="round" stroke-opacity="1" fill-opacity="1" opacity="1"/><path d="M14 2v5a1 1 0 0 0 1 1h5" style="marker:none;vector-effect:none;color-interpolation:srgb" fill="none" stroke="rgb(174, 174, 178)" stroke-width="2px" stroke-dasharray="none" stroke-linecap="round" stroke-linejoin="round" stroke-opacity="1" fill-opacity="1" opacity="1"/><path d="M10 9H8" style="marker:none;vector-effect:none;color-interpolation:srgb" fill="none" stroke="rgb(174, 174, 178)" stroke-width="2px" stroke-dasharray="none" stroke-linecap="round" stroke-linejoin="round" stroke-opacity="1" fill-opacity="1" opacity="1"/><path d="M16 13H8" style="marker:none;vector-effect:none;color-interpolation:srgb" fill="none" stroke="rgb(174, 174, 178)" stroke-width="2px" stroke-dasharray="none" stroke-linecap="round" stroke-linejoin="round" stroke-opacity="1" fill-opacity="1" opacity="1"/><path d="M16 17H8" style="marker:none;vector-effect:none;color-interpolation:srgb" fill="none" stroke="rgb(174, 174, 178)" stroke-width="2px" stroke-dasharray="none" stroke-linecap="round" stroke-linejoin="round" stroke-opacity="1" fill-opacity="1" opacity="1"/></g></g></g></g><g clip-path="url(#cp9)"><g clip-path="url(#ct10)"><text x="264.53" y="54.5" font-family="system-ui, &quot;-apple-system&quot;, sans-serif" font-size="12" font-weight="650" fill="rgb(174,174,178)">index.ts</text></g></g></g><g clip-path="url(#ov1)"><rect x="350.5" y="30.5" width="157" height="39" rx="19.5" fill="none" stroke="rgba(0,0,0,0)" stroke-width="1"/><g clip-path="url(#cp11)"><g color="rgb(174, 174, 178)"><clipPath id="svgic12"><rect x="387" y="42" width="16" height="16"/></clipPath><g clip-path="url(#svgic12)"><g transform="translate(387.031 42)scale(.66667)"><path d="M6 22a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h8a2 2 0 0 1 1.7.7l3.6 3.6A2 2 0 0 1 20 8v12a2 2 0 0 1-2 2Z" style="marker:none;vector-effect:none;color-interpolation:srgb" fill="none" stroke="rgb(174, 174, 178)" stroke-width="2px" stroke-dasharray="none" stroke-linecap="round" stroke-linejoin="round" stroke-opacity="1" fill-opacity="1" opacity="1"/><path d="M14 2v5a1 1 0 0 0 1 1h5" style="marker:none;vector-effect:none;color-interpolation:srgb" fill="none" stroke="rgb(174, 174, 178)" stroke-width="2px" stroke-dasharray="none" stroke-linecap="round" stroke-linejoin="round" stroke-opacity="1" fill-opacity="1" opacity="1"/><path d="M10 9H8" style="marker:none;vector-effect:none;color-interpolation:srgb" fill="none" stroke="rgb(174, 174, 178)" stroke-width="2px" stroke-dasharray="none" stroke-linecap="round" stroke-linejoin="round" stroke-opacity="1" fill-opacity="1" opacity="1"/><path d="M16 13H8" style="marker:none;vector-effect:none;color-interpolation:srgb" fill="none" stroke="rgb(174, 174, 178)" stroke-width="2px" stroke-dasharray="none" stroke-linecap="round" stroke-linejoin="round" stroke-opacity="1" fill-opacity="1" opacity="1"/><path d="M16 17H8" style="marker:none;vector-effect:none;color-interpolation:srgb" fill="none" stroke="rgb(174, 174, 178)" stroke-width="2px" stroke-dasharray="none" stroke-linecap="round" stroke-linejoin="round" stroke-opacity="1" fill-opacity="1" opacity="1"/></g></g></g></g><g clip-path="url(#cp13)"><g clip-path="url(#ct14)"><text x="411.03" y="54.5" font-family="system-ui, &quot;-apple-system&quot;, sans-serif" font-size="12" font-weight="650" fill="rgb(174,174,178)">styles.css</text></g></g></g></svg>
@@ -1 +1 @@
1
- <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 640 96" width="640" height="96"><defs><clipPath id="cp0"><rect x="28" y="28" width="584" height="44"/></clipPath><clipPath id="ov1"><rect x="29" y="29" width="582" height="42" rx="21"/></clipPath><filter id="sh2" x="-50%" y="-50%" width="200%" height="200%"><feGaussianBlur stdDeviation="1.5"/></filter><clipPath id="cp3"><rect x="67" y="42" width="16.4" height="16"/></clipPath><clipPath id="cp5"><rect x="91.4" y="42.5" width="74.4" height="15"/></clipPath><clipPath id="ct6"><rect x="91.4" y="42.5" width="74.4" height="15"/></clipPath><clipPath id="cp7"><rect x="240.5" y="42" width="16.5" height="16"/></clipPath><clipPath id="cp9"><rect x="264.5" y="42.5" width="47.7" height="15"/></clipPath><clipPath id="ct10"><rect x="264.5" y="42.5" width="47.7" height="15"/></clipPath><clipPath id="cp11"><rect x="387" y="42" width="16" height="16"/></clipPath><clipPath id="cp13"><rect x="411" y="42.5" width="60" height="15"/></clipPath><clipPath id="ct14"><rect x="411" y="42.5" width="60" height="15"/></clipPath></defs><g clip-path="url(#cp0)"><rect x="28.5" y="28.5" width="583" height="43" rx="21.5" fill="none" stroke="rgba(0,0,0,0)" stroke-width="1"/></g><g clip-path="url(#ov1)"><rect x="30" y="31" width="173.1" height="40" rx="20" fill="rgba(0,0,0,0.14)" filter="url(#sh2)"/><rect x="30" y="30" width="173.1" height="40" rx="20" fill="rgb(255,255,255)"/><rect x="30.5" y="30.5" width="172" height="39" rx="19.5" fill="none" stroke="rgba(209,209,214,0.8)" stroke-width="1"/><g clip-path="url(#cp3)"><g color="rgb(12, 98, 243)"><clipPath id="svgic4"><rect x="67.4" y="42" width="16" height="16"/></clipPath><g clip-path="url(#svgic4)"><g transform="translate(67.39 42)scale(.66667)"><path d="M6 22a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h8a2 2 0 0 1 1.7.7l3.6 3.6A2 2 0 0 1 20 8v12a2 2 0 0 1-2 2Z" style="marker:none;vector-effect:none;color-interpolation:srgb" fill="none" stroke="rgb(12, 98, 243)" stroke-width="2px" stroke-dasharray="none" stroke-linecap="round" stroke-linejoin="round" stroke-opacity="1" fill-opacity="1" opacity="1"/><path d="M14 2v5a1 1 0 0 0 1 1h5" style="marker:none;vector-effect:none;color-interpolation:srgb" fill="none" stroke="rgb(12, 98, 243)" stroke-width="2px" stroke-dasharray="none" stroke-linecap="round" stroke-linejoin="round" stroke-opacity="1" fill-opacity="1" opacity="1"/><path d="M10 9H8" style="marker:none;vector-effect:none;color-interpolation:srgb" fill="none" stroke="rgb(12, 98, 243)" stroke-width="2px" stroke-dasharray="none" stroke-linecap="round" stroke-linejoin="round" stroke-opacity="1" fill-opacity="1" opacity="1"/><path d="M16 13H8" style="marker:none;vector-effect:none;color-interpolation:srgb" fill="none" stroke="rgb(12, 98, 243)" stroke-width="2px" stroke-dasharray="none" stroke-linecap="round" stroke-linejoin="round" stroke-opacity="1" fill-opacity="1" opacity="1"/><path d="M16 17H8" style="marker:none;vector-effect:none;color-interpolation:srgb" fill="none" stroke="rgb(12, 98, 243)" stroke-width="2px" stroke-dasharray="none" stroke-linecap="round" stroke-linejoin="round" stroke-opacity="1" fill-opacity="1" opacity="1"/></g></g></g></g><g clip-path="url(#cp5)"><g clip-path="url(#ct6)"><text x="91.39" y="54.5" font-family="system-ui, &quot;-apple-system&quot;, sans-serif" font-size="12" font-weight="650" fill="rgb(12,98,243)">README.md</text></g></g></g><g clip-path="url(#ov1)"><rect x="203.5" y="30.5" width="146" height="39" rx="19.5" fill="none" stroke="rgba(0,0,0,0)" stroke-width="1"/><g clip-path="url(#cp7)"><g color="rgb(110, 110, 115)"><clipPath id="svgic8"><rect x="240.5" y="42" width="16" height="16"/></clipPath><g clip-path="url(#svgic8)"><g transform="translate(240.531 42)scale(.66667)"><path d="M6 22a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h8a2 2 0 0 1 1.7.7l3.6 3.6A2 2 0 0 1 20 8v12a2 2 0 0 1-2 2Z" style="marker:none;vector-effect:none;color-interpolation:srgb" fill="none" stroke="rgb(110, 110, 115)" stroke-width="2px" stroke-dasharray="none" stroke-linecap="round" stroke-linejoin="round" stroke-opacity="1" fill-opacity="1" opacity="1"/><path d="M14 2v5a1 1 0 0 0 1 1h5" style="marker:none;vector-effect:none;color-interpolation:srgb" fill="none" stroke="rgb(110, 110, 115)" stroke-width="2px" stroke-dasharray="none" stroke-linecap="round" stroke-linejoin="round" stroke-opacity="1" fill-opacity="1" opacity="1"/><path d="M10 9H8" style="marker:none;vector-effect:none;color-interpolation:srgb" fill="none" stroke="rgb(110, 110, 115)" stroke-width="2px" stroke-dasharray="none" stroke-linecap="round" stroke-linejoin="round" stroke-opacity="1" fill-opacity="1" opacity="1"/><path d="M16 13H8" style="marker:none;vector-effect:none;color-interpolation:srgb" fill="none" stroke="rgb(110, 110, 115)" stroke-width="2px" stroke-dasharray="none" stroke-linecap="round" stroke-linejoin="round" stroke-opacity="1" fill-opacity="1" opacity="1"/><path d="M16 17H8" style="marker:none;vector-effect:none;color-interpolation:srgb" fill="none" stroke="rgb(110, 110, 115)" stroke-width="2px" stroke-dasharray="none" stroke-linecap="round" stroke-linejoin="round" stroke-opacity="1" fill-opacity="1" opacity="1"/></g></g></g></g><g clip-path="url(#cp9)"><g clip-path="url(#ct10)"><text x="264.53" y="54.5" font-family="system-ui, &quot;-apple-system&quot;, sans-serif" font-size="12" font-weight="650" fill="rgb(110,110,115)">index.ts</text></g></g></g><g clip-path="url(#ov1)"><rect x="350.5" y="30.5" width="157" height="39" rx="19.5" fill="none" stroke="rgba(0,0,0,0)" stroke-width="1"/><g clip-path="url(#cp11)"><g color="rgb(110, 110, 115)"><clipPath id="svgic12"><rect x="387" y="42" width="16" height="16"/></clipPath><g clip-path="url(#svgic12)"><g transform="translate(387.031 42)scale(.66667)"><path d="M6 22a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h8a2 2 0 0 1 1.7.7l3.6 3.6A2 2 0 0 1 20 8v12a2 2 0 0 1-2 2Z" style="marker:none;vector-effect:none;color-interpolation:srgb" fill="none" stroke="rgb(110, 110, 115)" stroke-width="2px" stroke-dasharray="none" stroke-linecap="round" stroke-linejoin="round" stroke-opacity="1" fill-opacity="1" opacity="1"/><path d="M14 2v5a1 1 0 0 0 1 1h5" style="marker:none;vector-effect:none;color-interpolation:srgb" fill="none" stroke="rgb(110, 110, 115)" stroke-width="2px" stroke-dasharray="none" stroke-linecap="round" stroke-linejoin="round" stroke-opacity="1" fill-opacity="1" opacity="1"/><path d="M10 9H8" style="marker:none;vector-effect:none;color-interpolation:srgb" fill="none" stroke="rgb(110, 110, 115)" stroke-width="2px" stroke-dasharray="none" stroke-linecap="round" stroke-linejoin="round" stroke-opacity="1" fill-opacity="1" opacity="1"/><path d="M16 13H8" style="marker:none;vector-effect:none;color-interpolation:srgb" fill="none" stroke="rgb(110, 110, 115)" stroke-width="2px" stroke-dasharray="none" stroke-linecap="round" stroke-linejoin="round" stroke-opacity="1" fill-opacity="1" opacity="1"/><path d="M16 17H8" style="marker:none;vector-effect:none;color-interpolation:srgb" fill="none" stroke="rgb(110, 110, 115)" stroke-width="2px" stroke-dasharray="none" stroke-linecap="round" stroke-linejoin="round" stroke-opacity="1" fill-opacity="1" opacity="1"/></g></g></g></g><g clip-path="url(#cp13)"><g clip-path="url(#ct14)"><text x="411.03" y="54.5" font-family="system-ui, &quot;-apple-system&quot;, sans-serif" font-size="12" font-weight="650" fill="rgb(110,110,115)">styles.css</text></g></g></g></svg>
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 640 96" width="640" height="96"><defs><clipPath id="cp0"><rect x="28" y="28" width="584" height="44"/></clipPath><clipPath id="ov1"><rect x="29" y="29" width="582" height="42" rx="21"/></clipPath><filter id="sh2" x="-50%" y="-50%" width="200%" height="200%"><feGaussianBlur stdDeviation="1.5"/></filter><clipPath id="cp3"><rect x="67" y="42" width="16.4" height="16"/></clipPath><clipPath id="cp5"><rect x="91.4" y="42.5" width="74.4" height="15"/></clipPath><clipPath id="ct6"><rect x="91.4" y="42.5" width="74.4" height="15"/></clipPath><clipPath id="cp7"><rect x="240.5" y="42" width="16.5" height="16"/></clipPath><clipPath id="cp9"><rect x="264.5" y="42.5" width="47.7" height="15"/></clipPath><clipPath id="ct10"><rect x="264.5" y="42.5" width="47.7" height="15"/></clipPath><clipPath id="cp11"><rect x="387" y="42" width="16" height="16"/></clipPath><clipPath id="cp13"><rect x="411" y="42.5" width="60" height="15"/></clipPath><clipPath id="ct14"><rect x="411" y="42.5" width="60" height="15"/></clipPath></defs><g clip-path="url(#cp0)"><rect x="28.5" y="28.5" width="583" height="43" rx="21.5" fill="none" stroke="rgba(0,0,0,0)" stroke-width="1"/></g><g data-domotion-pseudo-source="blink-pseudo-fragment-v1" data-domotion-pseudo="::before" data-domotion-pseudo-owner="source-fragments"><g/></g><g data-domotion-pseudo-source="blink-pseudo-fragment-v1" data-domotion-pseudo="::after" data-domotion-pseudo-owner="source-fragments"><g/></g><g clip-path="url(#ov1)"><rect x="30" y="31" width="173.1" height="40" rx="20" fill="rgba(0,0,0,0.14)" filter="url(#sh2)"/><rect x="30" y="30" width="173.1" height="40" rx="20" fill="rgb(255,255,255)"/><rect x="30.5" y="30.5" width="172" height="39" rx="19.5" fill="none" stroke="rgba(209,209,214,0.8)" stroke-width="1"/><g clip-path="url(#cp3)"><g color="rgb(12, 98, 243)"><clipPath id="svgic4"><rect x="67.4" y="42" width="16" height="16"/></clipPath><g clip-path="url(#svgic4)"><g transform="translate(67.39 42)scale(.66667)"><path d="M6 22a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h8a2 2 0 0 1 1.7.7l3.6 3.6A2 2 0 0 1 20 8v12a2 2 0 0 1-2 2Z" style="marker:none;vector-effect:none;color-interpolation:srgb" fill="none" stroke="rgb(12, 98, 243)" stroke-width="2px" stroke-dasharray="none" stroke-linecap="round" stroke-linejoin="round" stroke-opacity="1" fill-opacity="1" opacity="1"/><path d="M14 2v5a1 1 0 0 0 1 1h5" style="marker:none;vector-effect:none;color-interpolation:srgb" fill="none" stroke="rgb(12, 98, 243)" stroke-width="2px" stroke-dasharray="none" stroke-linecap="round" stroke-linejoin="round" stroke-opacity="1" fill-opacity="1" opacity="1"/><path d="M10 9H8" style="marker:none;vector-effect:none;color-interpolation:srgb" fill="none" stroke="rgb(12, 98, 243)" stroke-width="2px" stroke-dasharray="none" stroke-linecap="round" stroke-linejoin="round" stroke-opacity="1" fill-opacity="1" opacity="1"/><path d="M16 13H8" style="marker:none;vector-effect:none;color-interpolation:srgb" fill="none" stroke="rgb(12, 98, 243)" stroke-width="2px" stroke-dasharray="none" stroke-linecap="round" stroke-linejoin="round" stroke-opacity="1" fill-opacity="1" opacity="1"/><path d="M16 17H8" style="marker:none;vector-effect:none;color-interpolation:srgb" fill="none" stroke="rgb(12, 98, 243)" stroke-width="2px" stroke-dasharray="none" stroke-linecap="round" stroke-linejoin="round" stroke-opacity="1" fill-opacity="1" opacity="1"/></g></g></g></g><g clip-path="url(#cp5)"><g clip-path="url(#ct6)"><text x="91.39" y="54.5" font-family="system-ui, &quot;-apple-system&quot;, sans-serif" font-size="12" font-weight="650" fill="rgb(12,98,243)">README.md</text></g></g></g><g clip-path="url(#ov1)"><rect x="203.5" y="30.5" width="146" height="39" rx="19.5" fill="none" stroke="rgba(0,0,0,0)" stroke-width="1"/><g clip-path="url(#cp7)"><g color="rgb(110, 110, 115)"><clipPath id="svgic8"><rect x="240.5" y="42" width="16" height="16"/></clipPath><g clip-path="url(#svgic8)"><g transform="translate(240.531 42)scale(.66667)"><path d="M6 22a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h8a2 2 0 0 1 1.7.7l3.6 3.6A2 2 0 0 1 20 8v12a2 2 0 0 1-2 2Z" style="marker:none;vector-effect:none;color-interpolation:srgb" fill="none" stroke="rgb(110, 110, 115)" stroke-width="2px" stroke-dasharray="none" stroke-linecap="round" stroke-linejoin="round" stroke-opacity="1" fill-opacity="1" opacity="1"/><path d="M14 2v5a1 1 0 0 0 1 1h5" style="marker:none;vector-effect:none;color-interpolation:srgb" fill="none" stroke="rgb(110, 110, 115)" stroke-width="2px" stroke-dasharray="none" stroke-linecap="round" stroke-linejoin="round" stroke-opacity="1" fill-opacity="1" opacity="1"/><path d="M10 9H8" style="marker:none;vector-effect:none;color-interpolation:srgb" fill="none" stroke="rgb(110, 110, 115)" stroke-width="2px" stroke-dasharray="none" stroke-linecap="round" stroke-linejoin="round" stroke-opacity="1" fill-opacity="1" opacity="1"/><path d="M16 13H8" style="marker:none;vector-effect:none;color-interpolation:srgb" fill="none" stroke="rgb(110, 110, 115)" stroke-width="2px" stroke-dasharray="none" stroke-linecap="round" stroke-linejoin="round" stroke-opacity="1" fill-opacity="1" opacity="1"/><path d="M16 17H8" style="marker:none;vector-effect:none;color-interpolation:srgb" fill="none" stroke="rgb(110, 110, 115)" stroke-width="2px" stroke-dasharray="none" stroke-linecap="round" stroke-linejoin="round" stroke-opacity="1" fill-opacity="1" opacity="1"/></g></g></g></g><g clip-path="url(#cp9)"><g clip-path="url(#ct10)"><text x="264.53" y="54.5" font-family="system-ui, &quot;-apple-system&quot;, sans-serif" font-size="12" font-weight="650" fill="rgb(110,110,115)">index.ts</text></g></g></g><g clip-path="url(#ov1)"><rect x="350.5" y="30.5" width="157" height="39" rx="19.5" fill="none" stroke="rgba(0,0,0,0)" stroke-width="1"/><g clip-path="url(#cp11)"><g color="rgb(110, 110, 115)"><clipPath id="svgic12"><rect x="387" y="42" width="16" height="16"/></clipPath><g clip-path="url(#svgic12)"><g transform="translate(387.031 42)scale(.66667)"><path d="M6 22a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h8a2 2 0 0 1 1.7.7l3.6 3.6A2 2 0 0 1 20 8v12a2 2 0 0 1-2 2Z" style="marker:none;vector-effect:none;color-interpolation:srgb" fill="none" stroke="rgb(110, 110, 115)" stroke-width="2px" stroke-dasharray="none" stroke-linecap="round" stroke-linejoin="round" stroke-opacity="1" fill-opacity="1" opacity="1"/><path d="M14 2v5a1 1 0 0 0 1 1h5" style="marker:none;vector-effect:none;color-interpolation:srgb" fill="none" stroke="rgb(110, 110, 115)" stroke-width="2px" stroke-dasharray="none" stroke-linecap="round" stroke-linejoin="round" stroke-opacity="1" fill-opacity="1" opacity="1"/><path d="M10 9H8" style="marker:none;vector-effect:none;color-interpolation:srgb" fill="none" stroke="rgb(110, 110, 115)" stroke-width="2px" stroke-dasharray="none" stroke-linecap="round" stroke-linejoin="round" stroke-opacity="1" fill-opacity="1" opacity="1"/><path d="M16 13H8" style="marker:none;vector-effect:none;color-interpolation:srgb" fill="none" stroke="rgb(110, 110, 115)" stroke-width="2px" stroke-dasharray="none" stroke-linecap="round" stroke-linejoin="round" stroke-opacity="1" fill-opacity="1" opacity="1"/><path d="M16 17H8" style="marker:none;vector-effect:none;color-interpolation:srgb" fill="none" stroke="rgb(110, 110, 115)" stroke-width="2px" stroke-dasharray="none" stroke-linecap="round" stroke-linejoin="round" stroke-opacity="1" fill-opacity="1" opacity="1"/></g></g></g></g><g clip-path="url(#cp13)"><g clip-path="url(#ct14)"><text x="411.03" y="54.5" font-family="system-ui, &quot;-apple-system&quot;, sans-serif" font-size="12" font-weight="650" fill="rgb(110,110,115)">styles.css</text></g></g></g></svg>