@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.
- package/README.md +81 -37
- package/ai/application-ui-diagnostic-ids-v1.json +9 -1
- package/ai/application-ui-profile-sync.cjs +1 -1
- package/ai/application-ui-profile.defaults.json +63 -8
- package/ai/application-ui-profile.mjs +1 -1
- package/ai/component-catalog.json +211 -33
- package/ai/component-catalog.schema.json +2 -0
- package/ai/component-class-owners.cjs +83 -0
- package/ai/component-composition-extension.d.ts +7 -0
- package/ai/component-composition-extension.schema.json +7 -0
- package/ai/{component-catalog-v2-overrides.json → component-composition-rules.json} +2 -1
- package/ai/{component-catalog-v2.d.ts → component-composition.d.ts} +9 -5
- package/ai/{component-catalog-v2.json → component-composition.json} +155 -24
- package/ai/{component-catalog-v2.schema.json → component-composition.schema.json} +21 -5
- package/ai/components/README.md +170 -0
- package/ai/components/application-tabs.md +65 -0
- package/ai/components/badge.md +72 -0
- package/ai/components/collapsible-panel.md +102 -0
- package/ai/components/content-item.md +90 -0
- package/ai/components/disclosure-arrow.md +77 -0
- package/ai/components/document-baseline.md +75 -0
- package/ai/components/empty-state.md +80 -0
- package/ai/components/feedback.md +71 -0
- package/ai/components/floating-toolbar.md +80 -0
- package/ai/components/foundation.md +65 -0
- package/ai/components/grid.md +93 -0
- package/ai/components/headers.md +63 -0
- package/ai/components/layout.md +75 -0
- package/ai/components/list-action-row.md +91 -0
- package/ai/components/list-header.md +89 -0
- package/ai/components/list-inset-control.md +74 -0
- package/ai/components/list-inset-text.md +72 -0
- package/ai/components/list-item.md +88 -0
- package/ai/components/list.md +103 -0
- package/ai/components/loading-spinner.md +72 -0
- package/ai/components/lucide-icon.md +66 -0
- package/ai/components/nav-stack.md +103 -0
- package/ai/components/pane.md +100 -0
- package/ai/components/popup-menu.md +82 -0
- package/ai/components/recipe-app-shell.md +57 -0
- package/ai/components/recipe-collapsible-sidebar.md +57 -0
- package/ai/components/recipe-compact-toolbar.md +57 -0
- package/ai/components/recipe-composer-form.md +57 -0
- package/ai/components/recipe-list-detail-dialog.md +57 -0
- package/ai/components/recipe-list-workspace-states.md +57 -0
- package/ai/components/recipe-loading-inspector.md +57 -0
- package/ai/components/recipe-navigation-sidebar.md +57 -0
- package/ai/components/recipe-navigation-stack.md +57 -0
- package/ai/components/recipe-workspace-header.md +57 -0
- package/ai/components/resize.md +101 -0
- package/ai/components/row.md +96 -0
- package/ai/components/segmented-control.md +82 -0
- package/ai/components/select.md +107 -0
- package/ai/components/skeleton.md +84 -0
- package/ai/components/spacer.md +86 -0
- package/ai/components/split-view.md +102 -0
- package/ai/components/state-banner.md +92 -0
- package/ai/components/sunken-panel.md +79 -0
- package/ai/components/surface-scaffold.md +78 -0
- package/ai/components/tab-bar.md +112 -0
- package/ai/components/tab-scaffold.md +94 -0
- package/ai/components/tabs.md +90 -0
- package/ai/components/text.md +82 -0
- package/ai/components/token-search-field.md +101 -0
- package/ai/components/toolbar-control-group.md +102 -0
- package/ai/components/toolbar-text.md +76 -0
- package/ai/components/toolbar.md +95 -0
- package/ai/components/value-table.md +72 -0
- package/ai/components/wa-accordion-item.md +55 -0
- package/ai/components/wa-accordion.md +65 -0
- package/ai/components/wa-animated-image.md +55 -0
- package/ai/components/wa-animation.md +55 -0
- package/ai/components/wa-avatar.md +55 -0
- package/ai/components/wa-badge.md +55 -0
- package/ai/components/wa-breadcrumb-item.md +53 -0
- package/ai/components/wa-breadcrumb.md +55 -0
- package/ai/components/wa-button-group.md +59 -0
- package/ai/components/wa-button.md +55 -0
- package/ai/components/wa-callout.md +58 -0
- package/ai/components/wa-card.md +59 -0
- package/ai/components/wa-carousel-item.md +53 -0
- package/ai/components/wa-carousel.md +55 -0
- package/ai/components/wa-checkbox-group.md +55 -0
- package/ai/components/wa-checkbox.md +55 -0
- package/ai/components/wa-color-picker.md +55 -0
- package/ai/components/wa-comparison.md +55 -0
- package/ai/components/wa-copy-button.md +55 -0
- package/ai/components/wa-details.md +61 -0
- package/ai/components/wa-dialog.md +59 -0
- package/ai/components/wa-divider.md +53 -0
- package/ai/components/wa-drawer.md +55 -0
- package/ai/components/wa-dropdown-item.md +60 -0
- package/ai/components/wa-dropdown.md +60 -0
- package/ai/components/wa-format-bytes.md +53 -0
- package/ai/components/wa-format-date.md +53 -0
- package/ai/components/wa-format-number.md +53 -0
- package/ai/components/wa-icon.md +58 -0
- package/ai/components/wa-include.md +53 -0
- package/ai/components/wa-input.md +59 -0
- package/ai/components/wa-intersection-observer.md +53 -0
- package/ai/components/wa-known-date.md +53 -0
- package/ai/components/wa-markdown.md +53 -0
- package/ai/components/wa-mutation-observer.md +53 -0
- package/ai/components/wa-number-input.md +55 -0
- package/ai/components/wa-option.md +59 -0
- package/ai/components/wa-otp-input.md +53 -0
- package/ai/components/wa-page.md +53 -0
- package/ai/components/wa-pagination.md +55 -0
- package/ai/components/wa-popover.md +55 -0
- package/ai/components/wa-popup.md +53 -0
- package/ai/components/wa-progress-bar.md +53 -0
- package/ai/components/wa-progress-ring.md +53 -0
- package/ai/components/wa-qr-code.md +53 -0
- package/ai/components/wa-radio-group.md +59 -0
- package/ai/components/wa-radio.md +55 -0
- package/ai/components/wa-random-content.md +53 -0
- package/ai/components/wa-rating.md +55 -0
- package/ai/components/wa-relative-time.md +53 -0
- package/ai/components/wa-resize-observer.md +53 -0
- package/ai/components/wa-scroller.md +53 -0
- package/ai/components/wa-select.md +63 -0
- package/ai/components/wa-skeleton.md +53 -0
- package/ai/components/wa-slider.md +55 -0
- package/ai/components/wa-spinner.md +58 -0
- package/ai/components/wa-split-panel.md +58 -0
- package/ai/components/wa-switch.md +53 -0
- package/ai/components/wa-tab-group.md +69 -0
- package/ai/components/wa-tab-panel.md +60 -0
- package/ai/components/wa-tab.md +59 -0
- package/ai/components/wa-tag.md +59 -0
- package/ai/components/wa-textarea.md +53 -0
- package/ai/components/wa-time-input.md +55 -0
- package/ai/components/wa-toast-item.md +60 -0
- package/ai/components/wa-toast.md +60 -0
- package/ai/components/wa-tooltip.md +55 -0
- package/ai/components/wa-tree-item.md +55 -0
- package/ai/components/wa-tree.md +55 -0
- package/ai/components/wa-zoomable-frame.md +55 -0
- package/ai/components/workbench.md +114 -0
- package/ai/public-api-signatures-v1.md +174 -43
- package/ai/skill.md +100 -48
- package/ai/webawesome-jsx-signatures-v1.md +1 -1
- package/analyzer/component-ownership.d.mts +56 -0
- package/analyzer/component-ownership.mjs +184 -0
- package/analyzer/index.d.mts +3 -0
- package/analyzer/index.mjs +274 -20
- package/analyzer/selectors.d.mts +21 -0
- package/analyzer/selectors.mjs +212 -0
- package/dist/browser/catalog.js +25 -0
- package/dist/browser/collapsible-panel.js +7 -0
- package/dist/browser/nav-stack.js +8 -0
- package/dist/browser/split-view.js +10 -0
- package/dist/browser/tab-scaffold.js +4 -0
- package/dist/browser/workbench.js +10 -0
- package/dist/catalog-resources.d.ts +2 -2
- package/dist/catalog.d.ts +3 -3
- package/dist/catalog.js +8 -7
- package/dist/catalog.js.map +1 -1
- package/dist/{chunk-QQOTQTDD.js → chunk-2CCMJTVY.js} +13 -10
- package/dist/chunk-2CCMJTVY.js.map +1 -0
- package/dist/{chunk-PK4N5QTO.js → chunk-553ASUK6.js} +2 -3
- package/dist/chunk-553ASUK6.js.map +1 -0
- package/dist/{chunk-G33XC2NB.js → chunk-6YFHCLHG.js} +2 -2
- package/dist/chunk-6YFHCLHG.js.map +1 -0
- package/dist/{chunk-ZIYOJFZD.js → chunk-7JUBXOIV.js} +17 -4
- package/dist/chunk-7JUBXOIV.js.map +1 -0
- package/dist/{chunk-T4UZTNZ4.js → chunk-EVYKTVBQ.js} +2 -11
- package/dist/chunk-EVYKTVBQ.js.map +1 -0
- package/dist/{chunk-AK67F6QN.js → chunk-EZVNC4J6.js} +4 -1
- package/dist/chunk-EZVNC4J6.js.map +1 -0
- package/dist/{chunk-MA6Z6EIM.js → chunk-F4QMLOXJ.js} +3 -2
- package/dist/chunk-F4QMLOXJ.js.map +1 -0
- package/dist/chunk-JCV4GXWB.js +249 -0
- package/dist/chunk-JCV4GXWB.js.map +1 -0
- package/dist/chunk-K47P7QZC.js +17 -0
- package/dist/chunk-K47P7QZC.js.map +1 -0
- package/dist/{chunk-MOBRFZH3.js → chunk-OUK6QRDR.js} +2 -12
- package/dist/chunk-OUK6QRDR.js.map +1 -0
- package/dist/{chunk-VNPQDCQZ.js → chunk-QOWG4ZCL.js} +3 -2
- package/dist/chunk-QOWG4ZCL.js.map +1 -0
- package/dist/{chunk-V65EOWNF.js → chunk-QPUPLNNB.js} +20 -8
- package/dist/chunk-QPUPLNNB.js.map +1 -0
- package/dist/{chunk-O3EXIBEZ.js → chunk-W4XKTST6.js} +8 -7
- package/dist/chunk-W4XKTST6.js.map +1 -0
- package/dist/{chunk-K6UNVKDK.js → chunk-XDKAYSVD.js} +3 -1
- package/dist/chunk-XDKAYSVD.js.map +1 -0
- package/dist/collapsible-panel.d.ts +9 -9
- package/dist/collapsible-panel.js +2 -2
- package/dist/collapsible-panel.js.map +1 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.js +11 -9
- package/dist/list-action-row.js +2 -1
- package/dist/list-header.js +1 -1
- package/dist/list-item.js +2 -1
- package/dist/nav-stack.d.ts +13 -1
- package/dist/nav-stack.js +1 -1
- package/dist/pane.d.ts +20 -3
- package/dist/pane.js +1 -1
- package/dist/{panel-toolbar-C8sF-YZC.d.ts → panel-toolbar-DqwtBxQL.d.ts} +13 -13
- package/dist/select.js +1 -1
- package/dist/split-view.d.ts +3 -3
- package/dist/split-view.js +3 -2
- package/dist/split-view.js.map +1 -1
- package/dist/state-banner.js +1 -1
- package/dist/styles/app-tab.css +31 -0
- package/dist/styles/badge.css +19 -11
- package/dist/styles/collapsible-panel.css +13 -9
- package/dist/styles/floating-toolbar.css +25 -6
- package/dist/styles/list-header.css +0 -12
- package/dist/styles/list.css +4 -4
- package/dist/styles/nav-stack.css +46 -19
- package/dist/styles/pane.css +50 -0
- package/dist/styles/popup-menu.css +151 -0
- package/dist/styles/resizable-region.css +22 -10
- package/dist/styles/select.css +28 -14
- package/dist/styles/skeleton.css +30 -3
- package/dist/styles/split-view.css +10 -7
- package/dist/styles/state-banner.css +0 -19
- package/dist/styles/surface-scaffold.css +8 -3
- package/dist/styles/tab-bar.css +79 -28
- package/dist/styles/tab-scaffold.css +25 -1
- package/dist/styles/text.css +16 -0
- package/dist/styles/toolbar-control-group.css +121 -66
- package/dist/styles/toolbar-text.css +21 -0
- package/dist/styles/toolbar.css +8 -32
- package/dist/styles/workbench.css +18 -18
- package/dist/tab-scaffold.d.ts +11 -1
- package/dist/tab-scaffold.js +2 -0
- package/dist/tab-scaffold.js.map +1 -1
- package/dist/toolbar-control-group.d.ts +3 -1
- package/dist/toolbar-control-group.js +1 -1
- package/dist/toolbar-text.d.ts +7 -1
- package/dist/toolbar-text.js +1 -1
- package/dist/toolbar.d.ts +8 -1
- package/dist/toolbar.js +1 -1
- package/dist/{types-DXAGogOS.d.ts → types-BuHELdXR.d.ts} +1 -1
- package/dist/wire-catalog.d.ts +3 -1
- package/dist/wire-catalog.js +2 -0
- package/dist/wire-catalog.js.map +1 -1
- package/dist/wire-scroll-dividers.d.ts +69 -0
- package/dist/wire-scroll-dividers.js +3 -0
- package/dist/wire-scroll-dividers.js.map +1 -0
- package/dist/workbench.d.ts +17 -16
- package/dist/workbench.js +1 -1
- package/docs/app-layouts.md +9 -1
- package/docs/catalog.md +10 -5
- package/docs/collapsible-panel.md +22 -13
- package/docs/component-contract.md +147 -21
- package/docs/component-selection.md +21 -8
- package/docs/design/templates/tab-bar/workspace-tabs-dark.svg +1 -1
- package/docs/design/templates/tab-bar/workspace-tabs.svg +1 -1
- package/docs/design/templates/tab-bar-dark.svg +1 -1
- package/docs/design/templates/tab-bar.svg +1 -1
- package/docs/design-philosophy.md +30 -3
- package/docs/examples/application-ui-profile.json +4 -4
- package/docs/examples/{component-catalog-extension-v2.json → component-composition-extension.json} +3 -3
- package/docs/layout.md +82 -3
- package/docs/nav-stack.md +33 -3
- package/docs/split-view.md +10 -5
- package/docs/tab-scaffold.md +23 -1
- package/docs/type-contracts.md +4 -3
- package/docs/ui-analyzer.md +99 -5
- package/docs/ui-doctor.md +10 -0
- package/docs/workbench.md +31 -20
- package/doctor/index.mjs +6 -1
- package/llms.txt +85 -20
- package/package.json +17 -5
- package/ux-demo/recipes/collapsible-sidebar.tsx +0 -1
- package/ux-demo/recipes/composer-form.tsx +0 -1
- package/ux-demo/recipes/list-detail-dialog.tsx +0 -2
- package/ux-demo/recipes/list-workspace-states.tsx +0 -1
- package/ux-demo/recipes/loading-inspector.tsx +0 -1
- package/ux-demo/recipes/workspace-header.tsx +0 -1
- package/ai/component-catalog-extension-v2.d.ts +0 -7
- package/ai/component-catalog-extension-v2.schema.json +0 -7
- package/dist/chunk-AK67F6QN.js.map +0 -1
- package/dist/chunk-G33XC2NB.js.map +0 -1
- package/dist/chunk-K6UNVKDK.js.map +0 -1
- package/dist/chunk-MA6Z6EIM.js.map +0 -1
- package/dist/chunk-MOBRFZH3.js.map +0 -1
- package/dist/chunk-O3EXIBEZ.js.map +0 -1
- package/dist/chunk-PK4N5QTO.js.map +0 -1
- package/dist/chunk-QQOTQTDD.js.map +0 -1
- package/dist/chunk-T4UZTNZ4.js.map +0 -1
- package/dist/chunk-V65EOWNF.js.map +0 -1
- package/dist/chunk-VNPQDCQZ.js.map +0 -1
- 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
|
-
|
|
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
|
|
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.
|
|
433
|
-
|
|
434
|
-
|
|
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
|
-
|
|
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`
|
|
130
|
-
|
|
131
|
-
- `
|
|
132
|
-
|
|
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
|
|
136
|
-
|
|
137
|
-
the
|
|
138
|
-
|
|
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
|
-
|
|
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
|
-
|
|
155
|
-
|
|
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
|
-
###
|
|
22
|
-
|
|
23
|
-
[`
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
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
|
|
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-
|
|
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
|
|
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
|
-
|
|
89
|
-
|
|
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
|
|
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-
|
|
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
|
|
121
|
-
for consumer packages whose generated metadata declares
|
|
122
|
-
not applicable; `@kerfjs/ui` retains its required
|
|
123
|
-
|
|
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
|
-
|
|
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.
|
|
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.
|
|
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.
|
|
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,
|
|
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
|
|
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.
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
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, "-apple-system", 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, "-apple-system", 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, "-apple-system", 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, "-apple-system", 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, "-apple-system", 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, "-apple-system", 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, "-apple-system", 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, "-apple-system", 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, "-apple-system", 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, "-apple-system", 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, "-apple-system", 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, "-apple-system", sans-serif" font-size="12" font-weight="650" fill="rgb(110,110,115)">styles.css</text></g></g></g></svg>
|