@kerfjs/ui 5.0.0-beta.92 → 5.0.0-beta.94
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 +9 -2
- package/ai/public-api-signatures-v1.md +70 -10
- package/ai/skill.md +11 -2
- package/ai/webawesome-jsx-signatures-v1.md +1 -1
- package/dist/catalog-resources.d.ts +1 -1
- package/dist/catalog.d.ts +32 -4
- package/dist/catalog.js +76 -3
- package/dist/catalog.js.map +1 -1
- package/dist/chunk-6C6DLP3W.js +31 -0
- package/dist/chunk-6C6DLP3W.js.map +1 -0
- package/dist/{chunk-H45DAZBL.js → chunk-KQDU7Z7P.js} +76 -23
- package/dist/chunk-KQDU7Z7P.js.map +1 -0
- package/dist/index.js +1 -1
- package/dist/{types-oLe_N1w0.d.ts → types-CVgIwSdq.d.ts} +61 -2
- package/dist/wire-catalog.d.ts +36 -4
- package/dist/wire-catalog.js +64 -14
- package/dist/wire-catalog.js.map +1 -1
- package/dist/wire-tab-bars.js +1 -1
- package/docs/catalog.md +77 -0
- package/docs/component-contract.md +9 -0
- package/package.json +7 -1
- package/vite-ux-review.d.mts +44 -0
- package/vite-ux-review.mjs +65 -0
- package/dist/chunk-H45DAZBL.js.map +0 -1
|
@@ -42,6 +42,17 @@ interface CatalogBrand {
|
|
|
42
42
|
/** Logo image URL (rendered decorative). Omit for a text-only brand. */
|
|
43
43
|
logoUrl?: string;
|
|
44
44
|
}
|
|
45
|
+
/**
|
|
46
|
+
* The UX Review capture link a {@link Catalog} shows when it knows the local
|
|
47
|
+
* project directory (see `uxReviewPlugin` and `wireCatalog`'s
|
|
48
|
+
* `onUxReviewProject`).
|
|
49
|
+
*/
|
|
50
|
+
interface CatalogUxReview {
|
|
51
|
+
/** The absolute project directory UX Review files captures under. */
|
|
52
|
+
projectDirectory: string;
|
|
53
|
+
/** The catalog's name in the capture title and context (default `brand.title`). */
|
|
54
|
+
name?: string;
|
|
55
|
+
}
|
|
45
56
|
type CatalogStageRootAttributes = Readonly<Record<`data-${string}`, string | undefined> & {
|
|
46
57
|
'data-catalog-stage'?: never;
|
|
47
58
|
'data-background-style'?: never;
|
|
@@ -62,10 +73,27 @@ interface CatalogSidebarConfig extends Pick<WorkbenchPanel, 'resizable' | 'separ
|
|
|
62
73
|
/** The sidebar header toolbar's configuration (default: no divider; its pane draws one while scrolled). */
|
|
63
74
|
toolbar?: ToolbarConfig;
|
|
64
75
|
}
|
|
76
|
+
/**
|
|
77
|
+
* The Catalog settings pane's configuration, forwarded to its Workbench right
|
|
78
|
+
* rail. Everything is optional; omitted fields keep the Catalog's defaults.
|
|
79
|
+
*/
|
|
80
|
+
interface CatalogSettingsConfig extends Pick<WorkbenchPanel, 'resizable' | 'separator' | 'collapseMotion' | 'presentation' | 'responsiveOverlayAt' | 'compactOverlay'> {
|
|
81
|
+
/**
|
|
82
|
+
* Pane width in px (default 288). With `resizable`, it is the current
|
|
83
|
+
* width: render the app's size signal here and hand the same signal to
|
|
84
|
+
* `wireCatalog`'s `settingsSize`, which writes each committed resize to it.
|
|
85
|
+
*/
|
|
86
|
+
size?: number;
|
|
87
|
+
/** The pane's title (default `Settings`); it also names the toggle. */
|
|
88
|
+
title?: string;
|
|
89
|
+
/** The pane header toolbar's configuration. */
|
|
90
|
+
toolbar?: ToolbarConfig;
|
|
91
|
+
}
|
|
65
92
|
interface CatalogProps {
|
|
66
93
|
/**
|
|
67
94
|
* The catalog's `id` (default `kui-catalog`). Its Workbench derives the
|
|
68
|
-
* sidebar's id from it (`<id>-left-rail`)
|
|
95
|
+
* sidebar's id from it (`<id>-left-rail`) and the settings pane's
|
|
96
|
+
* (`<id>-right-rail`), which `wireCatalog` wires.
|
|
69
97
|
*/
|
|
70
98
|
id?: string;
|
|
71
99
|
brand: CatalogBrand;
|
|
@@ -81,6 +109,35 @@ interface CatalogProps {
|
|
|
81
109
|
/** Show the preview background chooser; `backgroundStyle` remains app-owned. */
|
|
82
110
|
backgroundControl?: boolean;
|
|
83
111
|
headerActions?: KerfUiContent;
|
|
112
|
+
/**
|
|
113
|
+
* The active entry's settings (variant and state controls for its preview).
|
|
114
|
+
* When supplied, the Catalog renders a settings pane beside the stage — a
|
|
115
|
+
* Workbench right rail titled `settingsPanel.title` — with the standard
|
|
116
|
+
* toggle: in the pane's header while it is open, at the end of the entry
|
|
117
|
+
* toolbar while it is collapsed. Omit it (or pass `null`) for an entry with
|
|
118
|
+
* no settings; neither the pane nor the toggle renders. Below the
|
|
119
|
+
* Workbench's `narrow` breakpoint the pane overlays the stage.
|
|
120
|
+
*/
|
|
121
|
+
settings?: KerfUiContent;
|
|
122
|
+
/**
|
|
123
|
+
* Whether the settings pane is collapsed (default `false`). The app owns
|
|
124
|
+
* it; hand the same signal to `wireCatalog`'s `settingsCollapsed`, which
|
|
125
|
+
* flips it from the toggle and makes the pane a transient overlay on a
|
|
126
|
+
* small screen.
|
|
127
|
+
*/
|
|
128
|
+
settingsCollapsed?: boolean;
|
|
129
|
+
/**
|
|
130
|
+
* The settings pane's title, size, resizing, and overlay configuration
|
|
131
|
+
* (default: `Settings`, 288px, not resizable, an overlay below the
|
|
132
|
+
* Workbench's `narrow` breakpoint, `inset` in a compact Workbench).
|
|
133
|
+
*/
|
|
134
|
+
settingsPanel?: CatalogSettingsConfig;
|
|
135
|
+
/**
|
|
136
|
+
* Show a "Capture region" link to UX Review after `headerActions`, preset
|
|
137
|
+
* with the project and the active entry. Supply it once the project is known
|
|
138
|
+
* (`wireCatalog`'s `onUxReviewProject`); omit it on static hosting.
|
|
139
|
+
*/
|
|
140
|
+
uxReview?: CatalogUxReview;
|
|
84
141
|
secondarySections?: CatalogSecondaryGroup;
|
|
85
142
|
sidebarFooter?: KerfUiContent;
|
|
86
143
|
status?: KerfUiContent;
|
|
@@ -95,6 +152,8 @@ interface CatalogProps {
|
|
|
95
152
|
toggleMotionAction?: string;
|
|
96
153
|
selectBackgroundAction?: string;
|
|
97
154
|
toggleSecondaryAction?: string;
|
|
155
|
+
/** The settings pane toggle's `data-action` (default `catalog-toggle-settings`). */
|
|
156
|
+
toggleSettingsAction?: string;
|
|
98
157
|
/**
|
|
99
158
|
* Whether the entry toolbar and description stay pinned above the preview
|
|
100
159
|
* (`fixed`), scroll away with it (`scroll`), or stay pinned while the entry
|
|
@@ -127,4 +186,4 @@ interface CatalogProps {
|
|
|
127
186
|
slot?: string;
|
|
128
187
|
}
|
|
129
188
|
|
|
130
|
-
export type { CatalogResource as C, CatalogBackgroundStyle as a, CatalogProps as b, CatalogBrand as c, CatalogEntry as d, CatalogRelated as e, CatalogSecondaryGroup as f, CatalogSection as g,
|
|
189
|
+
export type { CatalogResource as C, CatalogBackgroundStyle as a, CatalogProps as b, CatalogBrand as c, CatalogEntry as d, CatalogRelated as e, CatalogSecondaryGroup as f, CatalogSection as g, CatalogSettingsConfig as h, CatalogStageRootAttributes as i, CatalogUxReview as j };
|
package/dist/wire-catalog.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Signal } from 'kerfjs';
|
|
2
|
-
import { a as CatalogBackgroundStyle } from './types-
|
|
2
|
+
import { a as CatalogBackgroundStyle } from './types-CVgIwSdq.js';
|
|
3
3
|
import './toolbar.js';
|
|
4
4
|
import './semantic-content-BbzjvSu9.js';
|
|
5
5
|
import './sides-BPSWde0A.js';
|
|
@@ -28,6 +28,11 @@ interface WireCatalogOptions {
|
|
|
28
28
|
onToggleMotion?: () => void;
|
|
29
29
|
/** Report a preview background choice; the app updates `backgroundStyle`. */
|
|
30
30
|
onSelectBackground?: (style: CatalogBackgroundStyle) => void;
|
|
31
|
+
/**
|
|
32
|
+
* Invoked when the settings pane toggle is activated. With
|
|
33
|
+
* `settingsCollapsed`, `wireCatalog` has already flipped the signal.
|
|
34
|
+
*/
|
|
35
|
+
onToggleSettings?: () => void;
|
|
31
36
|
/** Invoked when the secondary (ecosystem) group's disclosure toggle is activated. */
|
|
32
37
|
onToggleSecondary?: () => void;
|
|
33
38
|
/** When set, `?<urlParam>=<id>` is written on select via `history.replaceState`. */
|
|
@@ -44,6 +49,7 @@ interface WireCatalogOptions {
|
|
|
44
49
|
toggleMotionAction?: string;
|
|
45
50
|
selectBackgroundAction?: string;
|
|
46
51
|
toggleSecondaryAction?: string;
|
|
52
|
+
toggleSettingsAction?: string;
|
|
47
53
|
/**
|
|
48
54
|
* The sidebar's app-owned collapsed flag. With it, the catalog's Workbench
|
|
49
55
|
* sidebar is wired like any Workbench rail: it becomes a transient overlay
|
|
@@ -63,8 +69,34 @@ interface WireCatalogOptions {
|
|
|
63
69
|
* catalog remembers the user's sidebar width.
|
|
64
70
|
*/
|
|
65
71
|
sidebarStorageKey?: string;
|
|
72
|
+
/**
|
|
73
|
+
* The settings pane's app-owned collapsed flag, rendered as the Catalog's
|
|
74
|
+
* `settingsCollapsed`. With it, `wireCatalog` owns the pane's toggle (each
|
|
75
|
+
* press flips the signal) and wires the pane like any Workbench rail: a
|
|
76
|
+
* transient overlay on a small screen (collapsed as the breakpoint applies,
|
|
77
|
+
* closed on Escape or a press outside, focus handed back).
|
|
78
|
+
*/
|
|
79
|
+
settingsCollapsed?: Signal<boolean>;
|
|
80
|
+
/**
|
|
81
|
+
* The app-owned settings pane width signal for a Catalog rendered with
|
|
82
|
+
* `settingsPanel={{ resizable: true, size: settingsSize.value }}`. Each
|
|
83
|
+
* committed drag or keyboard resize is written to it.
|
|
84
|
+
*/
|
|
85
|
+
settingsSize?: Signal<number>;
|
|
86
|
+
/**
|
|
87
|
+
* With `settingsSize`, load and save the width under this storage key so
|
|
88
|
+
* the catalog remembers the user's settings pane width.
|
|
89
|
+
*/
|
|
90
|
+
settingsStorageKey?: string;
|
|
66
91
|
/** The Catalog's `id`, when it is not the default `kui-catalog`. */
|
|
67
92
|
id?: string;
|
|
93
|
+
/**
|
|
94
|
+
* Ask the page's server once for its UX Review project directory (served by
|
|
95
|
+
* `uxReviewPlugin` from `@kerfjs/ui/vite-ux-review`) and report it, so the
|
|
96
|
+
* app can render the Catalog with `uxReview`. Never called on static
|
|
97
|
+
* hosting or a server without the plugin.
|
|
98
|
+
*/
|
|
99
|
+
onUxReviewProject?: (projectDirectory: string) => void;
|
|
68
100
|
}
|
|
69
101
|
interface CatalogRevealOptions {
|
|
70
102
|
/** Scroll alignment within the sidebar. Default `'nearest'`. */
|
|
@@ -86,13 +118,13 @@ interface CatalogRevealOptions {
|
|
|
86
118
|
declare function revealCatalogEntry(root: HTMLElement, id: string, { block, inline, behavior, media, }?: CatalogRevealOptions): () => void;
|
|
87
119
|
/**
|
|
88
120
|
* Wire a {@link Catalog}'s interactions with one delegated listener set: sidebar
|
|
89
|
-
* item selection (and the related-entry popup menu), the sidebar collapse toggle,
|
|
90
|
-
* the theme toggle. The app owns the `active`/`collapsed`/`theme` signals and updates
|
|
121
|
+
* item selection (and the related-entry popup menu), the sidebar collapse toggle,
|
|
122
|
+
* the settings pane toggle, and the theme toggle. The app owns the `active`/`collapsed`/`theme` signals and updates
|
|
91
123
|
* them in the callbacks; optionally mirror the active id into the URL via `urlParam`.
|
|
92
124
|
* It also wires the scroll dividers below root (`wireScrollDividers`), so the
|
|
93
125
|
* catalog's panes and every example in it show their chrome dividers only
|
|
94
126
|
* while scrolled. Returns a disposer.
|
|
95
127
|
*/
|
|
96
|
-
declare function wireCatalog(root: HTMLElement, { onSelect, onToggleSidebar, onToggleTheme, onToggleContrast, onToggleMotion, onSelectBackground, onToggleSecondary, urlParam, revealSelection, selectAction, toggleSidebarAction, toggleThemeAction, toggleContrastAction, toggleMotionAction, selectBackgroundAction, toggleSecondaryAction, collapsed, sidebarSize, sidebarStorageKey, id: catalogId, }: WireCatalogOptions): () => void;
|
|
128
|
+
declare function wireCatalog(root: HTMLElement, { onSelect, onToggleSidebar, onToggleTheme, onToggleContrast, onToggleMotion, onSelectBackground, onToggleSecondary, onToggleSettings, urlParam, revealSelection, selectAction, toggleSidebarAction, toggleThemeAction, toggleContrastAction, toggleMotionAction, selectBackgroundAction, toggleSecondaryAction, toggleSettingsAction, collapsed, sidebarSize, sidebarStorageKey, settingsCollapsed, settingsSize, settingsStorageKey, id: catalogId, onUxReviewProject, }: WireCatalogOptions): () => void;
|
|
97
129
|
|
|
98
130
|
export { type CatalogRevealOptions, type WireCatalogOptions, revealCatalogEntry, wireCatalog };
|
package/dist/wire-catalog.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { wireWorkbench } from './chunk-QLA25V2K.js';
|
|
2
2
|
|
|
3
3
|
import { wireScrollDividers } from './chunk-6STQXRT4.js';
|
|
4
|
+
import { loadUxReviewProject } from './chunk-6C6DLP3W.js';
|
|
4
5
|
|
|
5
6
|
import { readTokenSearchField } from './chunk-ROZLJULF.js';
|
|
6
7
|
|
|
@@ -148,6 +149,7 @@ function wireCatalog(root, {
|
|
|
148
149
|
onToggleMotion,
|
|
149
150
|
onSelectBackground,
|
|
150
151
|
onToggleSecondary,
|
|
152
|
+
onToggleSettings,
|
|
151
153
|
urlParam,
|
|
152
154
|
revealSelection,
|
|
153
155
|
selectAction = "catalog-select",
|
|
@@ -157,19 +159,33 @@ function wireCatalog(root, {
|
|
|
157
159
|
toggleMotionAction = "catalog-toggle-motion",
|
|
158
160
|
selectBackgroundAction = "catalog-select-background",
|
|
159
161
|
toggleSecondaryAction = "catalog-toggle-secondary",
|
|
162
|
+
toggleSettingsAction = "catalog-toggle-settings",
|
|
160
163
|
collapsed,
|
|
161
164
|
sidebarSize,
|
|
162
165
|
sidebarStorageKey,
|
|
163
|
-
|
|
166
|
+
settingsCollapsed,
|
|
167
|
+
settingsSize,
|
|
168
|
+
settingsStorageKey,
|
|
169
|
+
id: catalogId = "kui-catalog",
|
|
170
|
+
onUxReviewProject
|
|
164
171
|
}) {
|
|
172
|
+
let disposed = false;
|
|
173
|
+
const view = root.ownerDocument.defaultView;
|
|
174
|
+
if (onUxReviewProject && view)
|
|
175
|
+
void loadUxReviewProject(
|
|
176
|
+
view.location.href,
|
|
177
|
+
(input, init) => view.fetch(input, init)
|
|
178
|
+
).then((directory) => {
|
|
179
|
+
if (directory && !disposed) onUxReviewProject(directory);
|
|
180
|
+
});
|
|
165
181
|
let cancelReveal;
|
|
166
182
|
const select = (id) => {
|
|
167
183
|
onSelect(id);
|
|
168
|
-
const
|
|
169
|
-
if (urlParam &&
|
|
170
|
-
const url = new URL(
|
|
184
|
+
const view2 = root.ownerDocument.defaultView;
|
|
185
|
+
if (urlParam && view2) {
|
|
186
|
+
const url = new URL(view2.location.href);
|
|
171
187
|
url.searchParams.set(urlParam, id);
|
|
172
|
-
|
|
188
|
+
view2.history.replaceState(null, "", url);
|
|
173
189
|
}
|
|
174
190
|
const rail = root.ownerDocument.getElementById(`${catalogId}-left-rail`);
|
|
175
191
|
if (collapsed && !collapsed.peek() && rail && root.ownerDocument.defaultView?.getComputedStyle(rail).position === "absolute")
|
|
@@ -262,20 +278,54 @@ function wireCatalog(root, {
|
|
|
262
278
|
)
|
|
263
279
|
);
|
|
264
280
|
}
|
|
281
|
+
if (settingsCollapsed || onToggleSettings) {
|
|
282
|
+
disposers.push(
|
|
283
|
+
delegate(root, "click", `[data-action="${toggleSettingsAction}"]`, () => {
|
|
284
|
+
if (settingsCollapsed)
|
|
285
|
+
settingsCollapsed.value = !settingsCollapsed.peek();
|
|
286
|
+
onToggleSettings?.();
|
|
287
|
+
})
|
|
288
|
+
);
|
|
289
|
+
}
|
|
290
|
+
const panels = {};
|
|
265
291
|
if (collapsed || sidebarSize)
|
|
292
|
+
panels.leftRail = {
|
|
293
|
+
collapsed,
|
|
294
|
+
size: sidebarSize,
|
|
295
|
+
storageKey: sidebarStorageKey
|
|
296
|
+
};
|
|
297
|
+
if (settingsCollapsed || settingsSize)
|
|
298
|
+
panels.rightRail = {
|
|
299
|
+
collapsed: settingsCollapsed,
|
|
300
|
+
size: settingsSize,
|
|
301
|
+
storageKey: settingsStorageKey
|
|
302
|
+
};
|
|
303
|
+
if (panels.leftRail || panels.rightRail)
|
|
304
|
+
disposers.push(wireWorkbench(root, { id: catalogId, panels }));
|
|
305
|
+
if (onUxReviewProject)
|
|
266
306
|
disposers.push(
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
307
|
+
delegate(
|
|
308
|
+
root,
|
|
309
|
+
"click",
|
|
310
|
+
'a.kui-toolbar-action-link[href^="uxreview://capture"]',
|
|
311
|
+
(_event, element) => {
|
|
312
|
+
const link = element;
|
|
313
|
+
const url = new URL(link.href);
|
|
314
|
+
const context = (url.searchParams.get("context") ?? "").replace(
|
|
315
|
+
/\nPage: [^\n]*$/,
|
|
316
|
+
""
|
|
317
|
+
);
|
|
318
|
+
url.searchParams.set(
|
|
319
|
+
"context",
|
|
320
|
+
`${context}
|
|
321
|
+
Page: ${link.ownerDocument.location.href}`
|
|
322
|
+
);
|
|
323
|
+
link.href = url.href;
|
|
275
324
|
}
|
|
276
|
-
|
|
325
|
+
)
|
|
277
326
|
);
|
|
278
327
|
return () => {
|
|
328
|
+
disposed = true;
|
|
279
329
|
cancelReveal?.();
|
|
280
330
|
for (const dispose of disposers.splice(0)) dispose();
|
|
281
331
|
};
|
package/dist/wire-catalog.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/catalog/wiring/wire-catalog.ts"],"names":[],"mappings":"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","file":"wire-catalog.js","sourcesContent":["import { delegate, type Signal } from 'kerfjs';\n\nimport { readTokenSearchField } from '../../components/forms/token-search-field/token-search-field.js';\nimport { wireWorkbench } from '../../components/layout/workbench/wiring/wire-workbench.js';\nimport { wireScrollDividers } from '../../wiring/wire-scroll-dividers.js';\nimport type { CatalogBackgroundStyle } from '../types.js';\n\nexport interface WireCatalogOptions {\n /** Invoked with the entry id when a sidebar item or a related-entry option is chosen. */\n onSelect: (id: string) => void;\n /** Invoked when the sidebar collapse/expand control is activated. */\n onToggleSidebar?: () => void;\n /** Invoked when the theme toggle is activated. */\n onToggleTheme?: () => void;\n /** Report a contrast-toggle press; the app updates its signal and applies the preference. */\n onToggleContrast?: () => void;\n /** Report a reduced-motion-toggle press; the app updates its signal and applies the preference. */\n onToggleMotion?: () => void;\n /** Report a preview background choice; the app updates `backgroundStyle`. */\n onSelectBackground?: (style: CatalogBackgroundStyle) => void;\n /** Invoked when the secondary (ecosystem) group's disclosure toggle is activated. */\n onToggleSecondary?: () => void;\n /** When set, `?<urlParam>=<id>` is written on select via `history.replaceState`. */\n urlParam?: string;\n /**\n * Reveal the chosen sidebar row after selection. `true` uses desktop-safe\n * defaults; pass options to customize scroll alignment or the media guard.\n */\n revealSelection?: boolean | CatalogRevealOptions;\n selectAction?: string;\n toggleSidebarAction?: string;\n toggleThemeAction?: string;\n toggleContrastAction?: string;\n toggleMotionAction?: string;\n selectBackgroundAction?: string;\n toggleSecondaryAction?: string;\n /**\n * The sidebar's app-owned collapsed flag. With it, the catalog's Workbench\n * sidebar is wired like any Workbench rail: it becomes a transient overlay\n * on a small screen (collapsed as the breakpoint applies, closed on Escape\n * or a press outside, focus handed back), and choosing an entry from the\n * open overlay closes it.\n */\n collapsed?: Signal<boolean>;\n /**\n * The app-owned sidebar width signal for a Catalog rendered with\n * `sidebar={{ resizable: true, size: sidebarSize.value }}`. Each committed\n * drag or keyboard resize is written to it.\n */\n sidebarSize?: Signal<number>;\n /**\n * With `sidebarSize`, load and save the width under this storage key so the\n * catalog remembers the user's sidebar width.\n */\n sidebarStorageKey?: string;\n /** The Catalog's `id`, when it is not the default `kui-catalog`. */\n id?: string;\n}\n\nexport interface CatalogRevealOptions {\n /** Scroll alignment within the sidebar. Default `'nearest'`. */\n block?: ScrollLogicalPosition;\n /** Cross-axis alignment. Default `'nearest'`. */\n inline?: ScrollLogicalPosition;\n /** Scroll behavior. Default `'auto'`. */\n behavior?: ScrollBehavior;\n /**\n * Only reveal when this media query matches. Defaults to the Catalog's\n * desktop layout; pass `false` to reveal at every viewport size.\n */\n media?: string | false;\n}\n\n// The Workbench keeps the sidebar inline above its `narrow` breakpoint (704px).\nconst catalogDesktopMedia = '(min-width: 44.01rem)';\n\n/** Keep the sidebar filter local to the shared Catalog, including across controlled rerenders. */\nfunction wireCatalogFilter(root: HTMLElement): () => void {\n const view = root.ownerDocument.defaultView!;\n let filterValue = '';\n let query = '';\n let currentEditor: HTMLElement | null = null;\n const matches = (name: string) => name.toLocaleLowerCase().includes(query);\n const apply = () => {\n const editor = root.querySelector<HTMLElement>('[data-catalog-filter]');\n const nav = root.querySelector<HTMLElement>('[data-catalog-sidebar]');\n if (!editor || !nav) return;\n if (editor !== currentEditor) {\n currentEditor = editor;\n if (readTokenSearchField(editor).query !== filterValue)\n editor.textContent = filterValue;\n }\n const field = editor.closest<HTMLElement>(\n '[data-component=\"token-search-field\"]',\n )!;\n field.dataset.catalogFilterActive = String(Boolean(query));\n const placeholderVisible = String(!filterValue);\n if (field.dataset.placeholderVisible !== placeholderVisible)\n field.dataset.placeholderVisible = placeholderVisible;\n const clear = field.querySelector<HTMLElement>(\n '[data-action=\"catalog-clear-filter\"]',\n )!;\n clear.style.display = query ? '' : 'none';\n nav.dataset.catalogFilterActive = String(Boolean(query));\n let visibleEntries = 0;\n for (const section of nav.querySelectorAll<HTMLElement>(\n '[data-catalog-section]',\n )) {\n const group = section.closest<HTMLElement>(\n '[data-catalog-secondary-group]',\n );\n const headingMatches =\n matches(section.dataset.catalogSection!) ||\n (group !== null && matches(group.dataset.catalogSecondaryGroup!));\n let sectionEntries = 0;\n for (const entry of section.querySelectorAll<HTMLElement>(\n '[data-catalog-entry-name]',\n )) {\n const visible =\n !query || headingMatches || matches(entry.dataset.catalogEntryName!);\n entry.hidden = !visible;\n if (visible) sectionEntries++;\n }\n section.hidden = Boolean(query) && sectionEntries === 0;\n visibleEntries += sectionEntries;\n }\n for (const group of nav.querySelectorAll<HTMLElement>(\n '[data-catalog-secondary-group]',\n )) {\n group.hidden =\n Boolean(query) &&\n !Array.from(\n group.querySelectorAll<HTMLElement>('[data-catalog-section]'),\n ).some((section) => !section.hidden);\n const toggle = group.querySelector<HTMLElement>('[aria-expanded]');\n const content = group.querySelector<HTMLElement>(\n '[data-catalog-secondary-collapsed]',\n );\n if (toggle && content) {\n const expanded = query\n ? !group.hidden\n : content.dataset.catalogSecondaryCollapsed !== 'true';\n toggle.setAttribute('aria-expanded', String(expanded));\n const arrow = toggle.querySelector<HTMLElement>(\n '[data-component=\"disclosure-arrow\"]',\n );\n if (arrow) {\n arrow.dataset.open = String(expanded);\n arrow.dataset.direction = expanded ? 'down' : 'right';\n arrow.style.setProperty(\n '--_kui-disclosure-arrow-rotation',\n expanded ? '90deg' : '0deg',\n );\n }\n }\n }\n const empty = nav.querySelector<HTMLElement>(\n '[data-catalog-filter-empty]',\n )!;\n empty.dataset.visible = String(Boolean(query) && visibleEntries === 0);\n };\n const onInput = (event: Event) => {\n const target = event.target as HTMLElement | null;\n const editor = target?.closest<HTMLElement>('[data-catalog-filter]');\n if (!editor || !root.contains(editor)) return;\n filterValue = readTokenSearchField(editor).query;\n query = filterValue.trim().toLocaleLowerCase();\n apply();\n };\n const onClick = (event: Event) => {\n const target = event.target as Element;\n if (!target.closest('[data-action=\"catalog-clear-filter\"]')) return;\n const editor = root.querySelector<HTMLElement>('[data-catalog-filter]')!;\n filterValue = '';\n query = '';\n editor.textContent = '';\n apply();\n editor.focus();\n };\n root.addEventListener('input', onInput);\n root.addEventListener('click', onClick);\n const observer = new view.MutationObserver(() => {\n if (filterValue) apply();\n });\n observer.observe(root, {\n attributes: true,\n attributeFilter: ['data-placeholder-visible'],\n childList: true,\n subtree: true,\n });\n apply();\n return () => {\n root.removeEventListener('input', onInput);\n root.removeEventListener('click', onClick);\n observer.disconnect();\n };\n}\n\n/**\n * Reveal one Catalog sidebar entry after the controlled render settles without\n * moving focus. Returns a cancellation function for rapid selection changes.\n */\nexport function revealCatalogEntry(\n root: HTMLElement,\n id: string,\n {\n block = 'nearest',\n inline = 'nearest',\n behavior = 'auto',\n media = catalogDesktopMedia,\n }: CatalogRevealOptions = {},\n): () => void {\n const view = root.ownerDocument.defaultView;\n if (!view || (media && !view.matchMedia(media).matches)) return () => {};\n const frame = view.requestAnimationFrame(() => {\n for (const item of root.querySelectorAll<HTMLElement>('[data-item-id]')) {\n if (item.dataset.itemId !== id) continue;\n item.scrollIntoView({ block, inline, behavior });\n break;\n }\n });\n return () => view.cancelAnimationFrame(frame);\n}\n\n/**\n * Wire a {@link Catalog}'s interactions with one delegated listener set: sidebar\n * item selection (and the related-entry popup menu), the sidebar collapse toggle, and\n * the theme toggle. The app owns the `active`/`collapsed`/`theme` signals and updates\n * them in the callbacks; optionally mirror the active id into the URL via `urlParam`.\n * It also wires the scroll dividers below root (`wireScrollDividers`), so the\n * catalog's panes and every example in it show their chrome dividers only\n * while scrolled. Returns a disposer.\n */\nexport function wireCatalog(\n root: HTMLElement,\n {\n onSelect,\n onToggleSidebar,\n onToggleTheme,\n onToggleContrast,\n onToggleMotion,\n onSelectBackground,\n onToggleSecondary,\n urlParam,\n revealSelection,\n selectAction = 'catalog-select',\n toggleSidebarAction = 'catalog-toggle-sidebar',\n toggleThemeAction = 'catalog-toggle-theme',\n toggleContrastAction = 'catalog-toggle-contrast',\n toggleMotionAction = 'catalog-toggle-motion',\n selectBackgroundAction = 'catalog-select-background',\n toggleSecondaryAction = 'catalog-toggle-secondary',\n collapsed,\n sidebarSize,\n sidebarStorageKey,\n id: catalogId = 'kui-catalog',\n }: WireCatalogOptions,\n): () => void {\n let cancelReveal: (() => void) | undefined;\n const select = (id: string) => {\n onSelect(id);\n const view = root.ownerDocument.defaultView;\n if (urlParam && view) {\n const url = new URL(view.location.href);\n url.searchParams.set(urlParam, id);\n view.history.replaceState(null, '', url);\n }\n // An open overlay sidebar gives way to the entry just chosen from it.\n const rail = root.ownerDocument.getElementById(`${catalogId}-left-rail`);\n if (\n collapsed &&\n !collapsed.peek() &&\n rail &&\n root.ownerDocument.defaultView?.getComputedStyle(rail).position ===\n 'absolute'\n )\n collapsed.value = true;\n if (revealSelection) {\n cancelReveal?.();\n cancelReveal = revealCatalogEntry(\n root,\n id,\n revealSelection === true ? undefined : revealSelection,\n );\n }\n };\n\n const disposers: Array<() => void> = [\n wireScrollDividers(root),\n wireCatalogFilter(root),\n // Sidebar items AND the footer's related-entry popup-menu items both carry\n // `data-action={selectAction}` + `data-item-id`, so one delegated click covers both.\n delegate(\n root,\n 'click',\n `[data-action=\"${selectAction}\"]`,\n (_event, element) => {\n const id = (element as HTMLElement).dataset.itemId;\n if (id) select(id);\n },\n ),\n ];\n if (onToggleSidebar) {\n disposers.push(\n delegate(root, 'click', `[data-action=\"${toggleSidebarAction}\"]`, () =>\n onToggleSidebar(),\n ),\n );\n }\n if (onToggleTheme) {\n disposers.push(\n delegate(root, 'click', `[data-action=\"${toggleThemeAction}\"]`, () =>\n onToggleTheme(),\n ),\n );\n }\n if (onToggleContrast) {\n disposers.push(\n delegate(root, 'click', `[data-action=\"${toggleContrastAction}\"]`, () =>\n onToggleContrast(),\n ),\n );\n }\n if (onToggleMotion) {\n disposers.push(\n delegate(root, 'click', `[data-action=\"${toggleMotionAction}\"]`, () =>\n onToggleMotion(),\n ),\n );\n }\n if (onSelectBackground) {\n disposers.push(\n delegate(\n root,\n 'click',\n `[data-action=\"${selectBackgroundAction}\"]`,\n (_event, element) => {\n const style = element.getAttribute('data-background-choice');\n if (\n style === 'checkerboard' ||\n style === 'vertical-stripes' ||\n style === 'layout-guide' ||\n style === 'surface' ||\n style === 'sunken'\n )\n onSelectBackground(style);\n },\n ),\n );\n }\n if (onToggleSecondary) {\n disposers.push(\n delegate(root, 'click', `[data-action=\"${toggleSecondaryAction}\"]`, () =>\n onToggleSecondary(),\n ),\n );\n }\n if (collapsed || sidebarSize)\n disposers.push(\n wireWorkbench(root, {\n id: catalogId,\n panels: {\n leftRail: {\n collapsed,\n size: sidebarSize,\n storageKey: sidebarStorageKey,\n },\n },\n }),\n );\n return () => {\n cancelReveal?.();\n for (const dispose of disposers.splice(0)) dispose();\n };\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/catalog/wiring/wire-catalog.ts"],"names":["view"],"mappings":"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","file":"wire-catalog.js","sourcesContent":["import { delegate, type Signal } from 'kerfjs';\n\nimport { readTokenSearchField } from '../../components/forms/token-search-field/token-search-field.js';\nimport {\n wireWorkbench,\n type WireWorkbenchOptions,\n} from '../../components/layout/workbench/wiring/wire-workbench.js';\nimport { wireScrollDividers } from '../../wiring/wire-scroll-dividers.js';\nimport type { CatalogBackgroundStyle } from '../types.js';\nimport { loadUxReviewProject } from '../ux-review.js';\n\nexport interface WireCatalogOptions {\n /** Invoked with the entry id when a sidebar item or a related-entry option is chosen. */\n onSelect: (id: string) => void;\n /** Invoked when the sidebar collapse/expand control is activated. */\n onToggleSidebar?: () => void;\n /** Invoked when the theme toggle is activated. */\n onToggleTheme?: () => void;\n /** Report a contrast-toggle press; the app updates its signal and applies the preference. */\n onToggleContrast?: () => void;\n /** Report a reduced-motion-toggle press; the app updates its signal and applies the preference. */\n onToggleMotion?: () => void;\n /** Report a preview background choice; the app updates `backgroundStyle`. */\n onSelectBackground?: (style: CatalogBackgroundStyle) => void;\n /**\n * Invoked when the settings pane toggle is activated. With\n * `settingsCollapsed`, `wireCatalog` has already flipped the signal.\n */\n onToggleSettings?: () => void;\n /** Invoked when the secondary (ecosystem) group's disclosure toggle is activated. */\n onToggleSecondary?: () => void;\n /** When set, `?<urlParam>=<id>` is written on select via `history.replaceState`. */\n urlParam?: string;\n /**\n * Reveal the chosen sidebar row after selection. `true` uses desktop-safe\n * defaults; pass options to customize scroll alignment or the media guard.\n */\n revealSelection?: boolean | CatalogRevealOptions;\n selectAction?: string;\n toggleSidebarAction?: string;\n toggleThemeAction?: string;\n toggleContrastAction?: string;\n toggleMotionAction?: string;\n selectBackgroundAction?: string;\n toggleSecondaryAction?: string;\n toggleSettingsAction?: string;\n /**\n * The sidebar's app-owned collapsed flag. With it, the catalog's Workbench\n * sidebar is wired like any Workbench rail: it becomes a transient overlay\n * on a small screen (collapsed as the breakpoint applies, closed on Escape\n * or a press outside, focus handed back), and choosing an entry from the\n * open overlay closes it.\n */\n collapsed?: Signal<boolean>;\n /**\n * The app-owned sidebar width signal for a Catalog rendered with\n * `sidebar={{ resizable: true, size: sidebarSize.value }}`. Each committed\n * drag or keyboard resize is written to it.\n */\n sidebarSize?: Signal<number>;\n /**\n * With `sidebarSize`, load and save the width under this storage key so the\n * catalog remembers the user's sidebar width.\n */\n sidebarStorageKey?: string;\n /**\n * The settings pane's app-owned collapsed flag, rendered as the Catalog's\n * `settingsCollapsed`. With it, `wireCatalog` owns the pane's toggle (each\n * press flips the signal) and wires the pane like any Workbench rail: a\n * transient overlay on a small screen (collapsed as the breakpoint applies,\n * closed on Escape or a press outside, focus handed back).\n */\n settingsCollapsed?: Signal<boolean>;\n /**\n * The app-owned settings pane width signal for a Catalog rendered with\n * `settingsPanel={{ resizable: true, size: settingsSize.value }}`. Each\n * committed drag or keyboard resize is written to it.\n */\n settingsSize?: Signal<number>;\n /**\n * With `settingsSize`, load and save the width under this storage key so\n * the catalog remembers the user's settings pane width.\n */\n settingsStorageKey?: string;\n /** The Catalog's `id`, when it is not the default `kui-catalog`. */\n id?: string;\n /**\n * Ask the page's server once for its UX Review project directory (served by\n * `uxReviewPlugin` from `@kerfjs/ui/vite-ux-review`) and report it, so the\n * app can render the Catalog with `uxReview`. Never called on static\n * hosting or a server without the plugin.\n */\n onUxReviewProject?: (projectDirectory: string) => void;\n}\n\nexport interface CatalogRevealOptions {\n /** Scroll alignment within the sidebar. Default `'nearest'`. */\n block?: ScrollLogicalPosition;\n /** Cross-axis alignment. Default `'nearest'`. */\n inline?: ScrollLogicalPosition;\n /** Scroll behavior. Default `'auto'`. */\n behavior?: ScrollBehavior;\n /**\n * Only reveal when this media query matches. Defaults to the Catalog's\n * desktop layout; pass `false` to reveal at every viewport size.\n */\n media?: string | false;\n}\n\n// The Workbench keeps the sidebar inline above its `narrow` breakpoint (704px).\nconst catalogDesktopMedia = '(min-width: 44.01rem)';\n\n/** Keep the sidebar filter local to the shared Catalog, including across controlled rerenders. */\nfunction wireCatalogFilter(root: HTMLElement): () => void {\n const view = root.ownerDocument.defaultView!;\n let filterValue = '';\n let query = '';\n let currentEditor: HTMLElement | null = null;\n const matches = (name: string) => name.toLocaleLowerCase().includes(query);\n const apply = () => {\n const editor = root.querySelector<HTMLElement>('[data-catalog-filter]');\n const nav = root.querySelector<HTMLElement>('[data-catalog-sidebar]');\n if (!editor || !nav) return;\n if (editor !== currentEditor) {\n currentEditor = editor;\n if (readTokenSearchField(editor).query !== filterValue)\n editor.textContent = filterValue;\n }\n const field = editor.closest<HTMLElement>(\n '[data-component=\"token-search-field\"]',\n )!;\n field.dataset.catalogFilterActive = String(Boolean(query));\n const placeholderVisible = String(!filterValue);\n if (field.dataset.placeholderVisible !== placeholderVisible)\n field.dataset.placeholderVisible = placeholderVisible;\n const clear = field.querySelector<HTMLElement>(\n '[data-action=\"catalog-clear-filter\"]',\n )!;\n clear.style.display = query ? '' : 'none';\n nav.dataset.catalogFilterActive = String(Boolean(query));\n let visibleEntries = 0;\n for (const section of nav.querySelectorAll<HTMLElement>(\n '[data-catalog-section]',\n )) {\n const group = section.closest<HTMLElement>(\n '[data-catalog-secondary-group]',\n );\n const headingMatches =\n matches(section.dataset.catalogSection!) ||\n (group !== null && matches(group.dataset.catalogSecondaryGroup!));\n let sectionEntries = 0;\n for (const entry of section.querySelectorAll<HTMLElement>(\n '[data-catalog-entry-name]',\n )) {\n const visible =\n !query || headingMatches || matches(entry.dataset.catalogEntryName!);\n entry.hidden = !visible;\n if (visible) sectionEntries++;\n }\n section.hidden = Boolean(query) && sectionEntries === 0;\n visibleEntries += sectionEntries;\n }\n for (const group of nav.querySelectorAll<HTMLElement>(\n '[data-catalog-secondary-group]',\n )) {\n group.hidden =\n Boolean(query) &&\n !Array.from(\n group.querySelectorAll<HTMLElement>('[data-catalog-section]'),\n ).some((section) => !section.hidden);\n const toggle = group.querySelector<HTMLElement>('[aria-expanded]');\n const content = group.querySelector<HTMLElement>(\n '[data-catalog-secondary-collapsed]',\n );\n if (toggle && content) {\n const expanded = query\n ? !group.hidden\n : content.dataset.catalogSecondaryCollapsed !== 'true';\n toggle.setAttribute('aria-expanded', String(expanded));\n const arrow = toggle.querySelector<HTMLElement>(\n '[data-component=\"disclosure-arrow\"]',\n );\n if (arrow) {\n arrow.dataset.open = String(expanded);\n arrow.dataset.direction = expanded ? 'down' : 'right';\n arrow.style.setProperty(\n '--_kui-disclosure-arrow-rotation',\n expanded ? '90deg' : '0deg',\n );\n }\n }\n }\n const empty = nav.querySelector<HTMLElement>(\n '[data-catalog-filter-empty]',\n )!;\n empty.dataset.visible = String(Boolean(query) && visibleEntries === 0);\n };\n const onInput = (event: Event) => {\n const target = event.target as HTMLElement | null;\n const editor = target?.closest<HTMLElement>('[data-catalog-filter]');\n if (!editor || !root.contains(editor)) return;\n filterValue = readTokenSearchField(editor).query;\n query = filterValue.trim().toLocaleLowerCase();\n apply();\n };\n const onClick = (event: Event) => {\n const target = event.target as Element;\n if (!target.closest('[data-action=\"catalog-clear-filter\"]')) return;\n const editor = root.querySelector<HTMLElement>('[data-catalog-filter]')!;\n filterValue = '';\n query = '';\n editor.textContent = '';\n apply();\n editor.focus();\n };\n root.addEventListener('input', onInput);\n root.addEventListener('click', onClick);\n const observer = new view.MutationObserver(() => {\n if (filterValue) apply();\n });\n observer.observe(root, {\n attributes: true,\n attributeFilter: ['data-placeholder-visible'],\n childList: true,\n subtree: true,\n });\n apply();\n return () => {\n root.removeEventListener('input', onInput);\n root.removeEventListener('click', onClick);\n observer.disconnect();\n };\n}\n\n/**\n * Reveal one Catalog sidebar entry after the controlled render settles without\n * moving focus. Returns a cancellation function for rapid selection changes.\n */\nexport function revealCatalogEntry(\n root: HTMLElement,\n id: string,\n {\n block = 'nearest',\n inline = 'nearest',\n behavior = 'auto',\n media = catalogDesktopMedia,\n }: CatalogRevealOptions = {},\n): () => void {\n const view = root.ownerDocument.defaultView;\n if (!view || (media && !view.matchMedia(media).matches)) return () => {};\n const frame = view.requestAnimationFrame(() => {\n for (const item of root.querySelectorAll<HTMLElement>('[data-item-id]')) {\n if (item.dataset.itemId !== id) continue;\n item.scrollIntoView({ block, inline, behavior });\n break;\n }\n });\n return () => view.cancelAnimationFrame(frame);\n}\n\n/**\n * Wire a {@link Catalog}'s interactions with one delegated listener set: sidebar\n * item selection (and the related-entry popup menu), the sidebar collapse toggle,\n * the settings pane toggle, and the theme toggle. The app owns the `active`/`collapsed`/`theme` signals and updates\n * them in the callbacks; optionally mirror the active id into the URL via `urlParam`.\n * It also wires the scroll dividers below root (`wireScrollDividers`), so the\n * catalog's panes and every example in it show their chrome dividers only\n * while scrolled. Returns a disposer.\n */\nexport function wireCatalog(\n root: HTMLElement,\n {\n onSelect,\n onToggleSidebar,\n onToggleTheme,\n onToggleContrast,\n onToggleMotion,\n onSelectBackground,\n onToggleSecondary,\n onToggleSettings,\n urlParam,\n revealSelection,\n selectAction = 'catalog-select',\n toggleSidebarAction = 'catalog-toggle-sidebar',\n toggleThemeAction = 'catalog-toggle-theme',\n toggleContrastAction = 'catalog-toggle-contrast',\n toggleMotionAction = 'catalog-toggle-motion',\n selectBackgroundAction = 'catalog-select-background',\n toggleSecondaryAction = 'catalog-toggle-secondary',\n toggleSettingsAction = 'catalog-toggle-settings',\n collapsed,\n sidebarSize,\n sidebarStorageKey,\n settingsCollapsed,\n settingsSize,\n settingsStorageKey,\n id: catalogId = 'kui-catalog',\n onUxReviewProject,\n }: WireCatalogOptions,\n): () => void {\n let disposed = false;\n const view = root.ownerDocument.defaultView;\n if (onUxReviewProject && view)\n void loadUxReviewProject(view.location.href, (input, init) =>\n view.fetch(input, init),\n ).then((directory) => {\n if (directory && !disposed) onUxReviewProject(directory);\n });\n let cancelReveal: (() => void) | undefined;\n const select = (id: string) => {\n onSelect(id);\n const view = root.ownerDocument.defaultView;\n if (urlParam && view) {\n const url = new URL(view.location.href);\n url.searchParams.set(urlParam, id);\n view.history.replaceState(null, '', url);\n }\n // An open overlay sidebar gives way to the entry just chosen from it.\n const rail = root.ownerDocument.getElementById(`${catalogId}-left-rail`);\n if (\n collapsed &&\n !collapsed.peek() &&\n rail &&\n root.ownerDocument.defaultView?.getComputedStyle(rail).position ===\n 'absolute'\n )\n collapsed.value = true;\n if (revealSelection) {\n cancelReveal?.();\n cancelReveal = revealCatalogEntry(\n root,\n id,\n revealSelection === true ? undefined : revealSelection,\n );\n }\n };\n\n const disposers: Array<() => void> = [\n wireScrollDividers(root),\n wireCatalogFilter(root),\n // Sidebar items AND the footer's related-entry popup-menu items both carry\n // `data-action={selectAction}` + `data-item-id`, so one delegated click covers both.\n delegate(\n root,\n 'click',\n `[data-action=\"${selectAction}\"]`,\n (_event, element) => {\n const id = (element as HTMLElement).dataset.itemId;\n if (id) select(id);\n },\n ),\n ];\n if (onToggleSidebar) {\n disposers.push(\n delegate(root, 'click', `[data-action=\"${toggleSidebarAction}\"]`, () =>\n onToggleSidebar(),\n ),\n );\n }\n if (onToggleTheme) {\n disposers.push(\n delegate(root, 'click', `[data-action=\"${toggleThemeAction}\"]`, () =>\n onToggleTheme(),\n ),\n );\n }\n if (onToggleContrast) {\n disposers.push(\n delegate(root, 'click', `[data-action=\"${toggleContrastAction}\"]`, () =>\n onToggleContrast(),\n ),\n );\n }\n if (onToggleMotion) {\n disposers.push(\n delegate(root, 'click', `[data-action=\"${toggleMotionAction}\"]`, () =>\n onToggleMotion(),\n ),\n );\n }\n if (onSelectBackground) {\n disposers.push(\n delegate(\n root,\n 'click',\n `[data-action=\"${selectBackgroundAction}\"]`,\n (_event, element) => {\n const style = element.getAttribute('data-background-choice');\n if (\n style === 'checkerboard' ||\n style === 'vertical-stripes' ||\n style === 'layout-guide' ||\n style === 'surface' ||\n style === 'sunken'\n )\n onSelectBackground(style);\n },\n ),\n );\n }\n if (onToggleSecondary) {\n disposers.push(\n delegate(root, 'click', `[data-action=\"${toggleSecondaryAction}\"]`, () =>\n onToggleSecondary(),\n ),\n );\n }\n if (settingsCollapsed || onToggleSettings) {\n disposers.push(\n delegate(root, 'click', `[data-action=\"${toggleSettingsAction}\"]`, () => {\n if (settingsCollapsed)\n settingsCollapsed.value = !settingsCollapsed.peek();\n onToggleSettings?.();\n }),\n );\n }\n // One wireWorkbench call owns every wired rail, so overlays stay exclusive.\n const panels: WireWorkbenchOptions['panels'] = {};\n if (collapsed || sidebarSize)\n panels.leftRail = {\n collapsed,\n size: sidebarSize,\n storageKey: sidebarStorageKey,\n };\n if (settingsCollapsed || settingsSize)\n panels.rightRail = {\n collapsed: settingsCollapsed,\n size: settingsSize,\n storageKey: settingsStorageKey,\n };\n if (panels.leftRail || panels.rightRail)\n disposers.push(wireWorkbench(root, { id: catalogId, panels }));\n if (onUxReviewProject)\n // The capture context names the page the review came from. The URL can\n // change after the link rendered (`urlParam`), so stamp it as the link is\n // followed; the browser navigates to the href as it stands after the click.\n disposers.push(\n delegate(\n root,\n 'click',\n 'a.kui-toolbar-action-link[href^=\"uxreview://capture\"]',\n (_event, element) => {\n const link = element as HTMLAnchorElement;\n const url = new URL(link.href);\n const context = (url.searchParams.get('context') ?? '').replace(\n /\\nPage: [^\\n]*$/,\n '',\n );\n url.searchParams.set(\n 'context',\n `${context}\\nPage: ${link.ownerDocument.location.href}`,\n );\n link.href = url.href;\n },\n ),\n );\n return () => {\n disposed = true;\n cancelReveal?.();\n for (const dispose of disposers.splice(0)) dispose();\n };\n}\n"]}
|
package/dist/wire-tab-bars.js
CHANGED
package/docs/catalog.md
CHANGED
|
@@ -64,6 +64,14 @@ expanded? }`. When `collapsible`, the label is a disclosure toggle controlling
|
|
|
64
64
|
`expanded` (the app owns it; wire it with `wireCatalog`'s `onToggleSecondary`).
|
|
65
65
|
- Optional slots: `headerActions` (extra header controls), `sidebarFooter` (extra
|
|
66
66
|
sidebar content), and `status` (a footer status line).
|
|
67
|
+
- **`settings`** — the active entry's settings (variant and state controls for
|
|
68
|
+
its preview). When supplied, the Catalog renders a **Settings** pane beside the
|
|
69
|
+
stage (its Workbench right rail) with the standard collapse toggle: in the
|
|
70
|
+
pane's header while it is open, at the end of the entry toolbar while it is
|
|
71
|
+
collapsed. Omit it (or pass `null`) for an entry with no settings; neither the
|
|
72
|
+
pane nor its toggle renders. Supply only the controls — compose them from
|
|
73
|
+
`ListInsetControl` + `Select` (or other form components) so they share the
|
|
74
|
+
pane's text column; the Catalog owns the pane, its title, and its toggle.
|
|
67
75
|
|
|
68
76
|
The sidebar includes a `TokenSearchField` in its fixed header for every Catalog
|
|
69
77
|
consumer, so the filter remains visible while the entries scroll. `wireCatalog`
|
|
@@ -211,6 +219,9 @@ Catalogs for downstream components should conform to the
|
|
|
211
219
|
contract and can start from the checked
|
|
212
220
|
[`component-catalog-extension.json`](./examples/component-catalog-extension.json)
|
|
213
221
|
example; provide those entries beside Kerf's shipped catalog to AI tools.
|
|
222
|
+
Packages that keep a `kerf.components.json` can generate this file instead of
|
|
223
|
+
hand-maintaining it: set `kerfComponentCatalog.selectionOutput` and run
|
|
224
|
+
`kerf-component-catalog` (see `create-kerf-component`'s README).
|
|
214
225
|
An extension entry may declare `uses` with direct Kerf or extension entry ids,
|
|
215
226
|
plus repository-relative `source` and `demoSource` paths. Keep the ids unique
|
|
216
227
|
and resolvable across both catalogs; paths use `/` separators and cannot
|
|
@@ -454,6 +465,21 @@ revealCatalogEntry(app, initial, { block: "center" });
|
|
|
454
465
|
header's `ToolbarConfig`). A resizable sidebar's width is app state like
|
|
455
466
|
`collapsed`: render your size signal as `sidebar.size` and pass the same signal
|
|
456
467
|
as `wireCatalog`'s `sidebarSize` (plus `sidebarStorageKey` to remember it).
|
|
468
|
+
- **`settingsCollapsed`** is transient UI like `collapsed`: render your signal as
|
|
469
|
+
`settingsCollapsed` and pass the same signal as `wireCatalog`'s
|
|
470
|
+
`settingsCollapsed`. `wireCatalog` then flips it from the toggle (report it
|
|
471
|
+
with `onToggleSettings`, which runs after the flip) and wires the pane as a
|
|
472
|
+
Workbench rail: below the `narrow` breakpoint it starts collapsed and opens as
|
|
473
|
+
an overlay over the stage that Escape or a press outside closes, handing focus
|
|
474
|
+
back to the toggle. The sidebar and settings overlays are exclusive. Without
|
|
475
|
+
the signal, `onToggleSettings` alone reports the press and the app flips its
|
|
476
|
+
own state.
|
|
477
|
+
- **`settingsPanel`** configures the settings pane like `sidebar` configures the
|
|
478
|
+
sidebar: `title` (default `Settings`; it also names the toggle), `size`
|
|
479
|
+
(default 288px), `resizable`, `separator`, `collapseMotion`, `presentation`,
|
|
480
|
+
`responsiveOverlayAt`, `compactOverlay`, and `toolbar`. A resizable pane's
|
|
481
|
+
width is app state: render your signal as `settingsPanel.size` and pass it as
|
|
482
|
+
`wireCatalog`'s `settingsSize` (plus `settingsStorageKey` to remember it).
|
|
457
483
|
- **`mainToolbar` / `footerToolbar`** take the entry toolbar's and the resource
|
|
458
484
|
footer toolbar's `ToolbarConfig` (`dividerSides`, `centerAlign`, `responsive`,
|
|
459
485
|
`responsiveAt`, `safeAreaEdges`). The defaults are a wrapping entry toolbar
|
|
@@ -465,6 +491,57 @@ revealCatalogEntry(app, initial, { block: "center" });
|
|
|
465
491
|
the toggle, the app applies the theme (the shell reads `theme` to show the toggle's
|
|
466
492
|
opposite-state label). Omit `theme` to hide the toggle entirely.
|
|
467
493
|
|
|
494
|
+
## UX Review capture
|
|
495
|
+
|
|
496
|
+
On a local Vite dev or preview server the catalog can offer a **Capture region**
|
|
497
|
+
header link that starts a UX Review region screenshot, preset with the project
|
|
498
|
+
and the active entry. Static hosting has no local project, so the link never
|
|
499
|
+
appears there. Three pieces wire it:
|
|
500
|
+
|
|
501
|
+
```ts
|
|
502
|
+
// vite.config.ts — Node only; never part of the browser bundle.
|
|
503
|
+
import { uxReviewPlugin } from "@kerfjs/ui/vite-ux-review";
|
|
504
|
+
|
|
505
|
+
export default defineConfig({ plugins: [uxReviewPlugin()] });
|
|
506
|
+
```
|
|
507
|
+
|
|
508
|
+
```tsx
|
|
509
|
+
const uxReviewProject = signal<string | null>(null);
|
|
510
|
+
|
|
511
|
+
mount(app, () => (
|
|
512
|
+
<Catalog
|
|
513
|
+
/* …the props above… */
|
|
514
|
+
uxReview={
|
|
515
|
+
uxReviewProject.value
|
|
516
|
+
? { projectDirectory: uxReviewProject.value }
|
|
517
|
+
: undefined
|
|
518
|
+
}
|
|
519
|
+
/>
|
|
520
|
+
));
|
|
521
|
+
|
|
522
|
+
wireCatalog(app, {
|
|
523
|
+
onSelect: (id) => (active.value = id),
|
|
524
|
+
onUxReviewProject: (directory) => (uxReviewProject.value = directory),
|
|
525
|
+
});
|
|
526
|
+
```
|
|
527
|
+
|
|
528
|
+
- **`uxReviewPlugin(options?)`** answers `GET …/__ux-review/project.json` with
|
|
529
|
+
`{ projectDirectory }` on the dev and preview servers, at any base path. The
|
|
530
|
+
directory defaults to the repository holding Vite's `root` (the nearest
|
|
531
|
+
ancestor with `.git`, or `root` itself); pass `projectDirectory` (resolved
|
|
532
|
+
against `root`) to name another.
|
|
533
|
+
- **`wireCatalog`'s `onUxReviewProject`** asks the page's server once and
|
|
534
|
+
reports the directory. It is never called on static hosting or a server
|
|
535
|
+
without the plugin. While wired, following the link stamps the current page
|
|
536
|
+
URL into the capture context.
|
|
537
|
+
- **`Catalog`'s `uxReview`** (`{ projectDirectory, name? }`) renders the link
|
|
538
|
+
after `headerActions`. The capture is titled `<name>: <entry>`, and its
|
|
539
|
+
context names the catalog, the entry's section, and the entry; `name`
|
|
540
|
+
defaults to `brand.title`.
|
|
541
|
+
|
|
542
|
+
The browser helpers behind it, `uxReviewCaptureUrl` and `loadUxReviewProject`,
|
|
543
|
+
are exported from `@kerfjs/ui/catalog` for a capture link placed elsewhere.
|
|
544
|
+
|
|
468
545
|
## Custom action names
|
|
469
546
|
|
|
470
547
|
The shell emits `data-action="catalog-select"` (sidebar items),
|
|
@@ -275,6 +275,9 @@ example. Keep app and Kerf entries as package-qualified inputs, then let people
|
|
|
275
275
|
or AI tools search their combined entries and compare `geometry` before adding
|
|
276
276
|
wrappers or insets. Do not add app-owned entries to Kerf's canonical catalog or
|
|
277
277
|
claim Kerf delivery paths for them.
|
|
278
|
+
Packages that keep a `kerf.components.json` can generate this file instead of
|
|
279
|
+
hand-maintaining it: set `kerfComponentCatalog.selectionOutput` and run
|
|
280
|
+
`kerf-component-catalog` (see `create-kerf-component`'s README).
|
|
278
281
|
Extension entries may add `uses` for direct composition dependencies and
|
|
279
282
|
repository-relative `source` and `demoSource` files. Resolve each dependency
|
|
280
283
|
against the combined Kerf and consumer catalogs; do not duplicate a Kerf id.
|
|
@@ -758,6 +761,12 @@ whole-tab starts after scroll and selection changes, reserving end room so the
|
|
|
758
761
|
last peer can align there. The application still owns selection and tab order.
|
|
759
762
|
ResizeObserver notifications coalesce snap measurements into the next animation
|
|
760
763
|
frame, so inset writes cannot resize the observed strip during observer delivery.
|
|
764
|
+
`wireTabBars` watches the whole root it is given, but a mutation re-measures only
|
|
765
|
+
the bars it touched: a change inside a bar, a newly inserted bar, or a `dir`
|
|
766
|
+
change on an element above one. Content elsewhere in the root (terminal output,
|
|
767
|
+
list updates, streamed text) triggers no style or layout reads. A pinned strip
|
|
768
|
+
re-measures when its own size changes, so a layout change outside the bar still
|
|
769
|
+
reaches it.
|
|
761
770
|
|
|
762
771
|
CSS, the generated wrappers that make it
|
|
763
772
|
reachable, and the registration module are the package's only declared side
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kerfjs/ui",
|
|
3
|
-
"version": "5.0.0-beta.
|
|
3
|
+
"version": "5.0.0-beta.94",
|
|
4
4
|
"description": "Accessible, composable UI primitives for kerf applications.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -56,6 +56,10 @@
|
|
|
56
56
|
"types": "./catalog-projection.d.mts",
|
|
57
57
|
"import": "./catalog-projection.mjs"
|
|
58
58
|
},
|
|
59
|
+
"./vite-ux-review": {
|
|
60
|
+
"types": "./vite-ux-review.d.mts",
|
|
61
|
+
"import": "./vite-ux-review.mjs"
|
|
62
|
+
},
|
|
59
63
|
"./lucide-icon": {
|
|
60
64
|
"types": "./dist/lucide-icon.d.ts",
|
|
61
65
|
"browser": "./dist/browser/lucide-icon.js",
|
|
@@ -412,6 +416,8 @@
|
|
|
412
416
|
"catalog-projection.mjs",
|
|
413
417
|
"catalog-projection.d.mts",
|
|
414
418
|
"catalog-projection-cli.mjs",
|
|
419
|
+
"vite-ux-review.mjs",
|
|
420
|
+
"vite-ux-review.d.mts",
|
|
415
421
|
"scripts/component-catalog-extension-validation.mjs",
|
|
416
422
|
"analyzer",
|
|
417
423
|
"doctor",
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/** Where the endpoint lives, relative to the catalog page. */
|
|
2
|
+
export declare const UX_REVIEW_PROJECT_PATH: '__ux-review/project.json';
|
|
3
|
+
|
|
4
|
+
export interface UxReviewPluginOptions {
|
|
5
|
+
/**
|
|
6
|
+
* The project directory UX Review files captures under, resolved against
|
|
7
|
+
* Vite's `root`. Default: the nearest ancestor of `root` holding `.git`,
|
|
8
|
+
* or `root` itself.
|
|
9
|
+
*/
|
|
10
|
+
projectDirectory?: string;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
/** The connect-style middleware stack of a Vite dev or preview server. */
|
|
14
|
+
export interface UxReviewMiddlewareServer {
|
|
15
|
+
middlewares: {
|
|
16
|
+
use(
|
|
17
|
+
handler: (
|
|
18
|
+
request: { url?: string; method?: string },
|
|
19
|
+
response: {
|
|
20
|
+
statusCode: number;
|
|
21
|
+
setHeader(name: string, value: string): void;
|
|
22
|
+
end(body?: string): void;
|
|
23
|
+
},
|
|
24
|
+
next: () => void,
|
|
25
|
+
) => void,
|
|
26
|
+
): unknown;
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/** A Vite plugin; structurally typed so this module needs no `vite` import. */
|
|
31
|
+
export interface UxReviewPlugin {
|
|
32
|
+
name: 'kerf-ux-review';
|
|
33
|
+
configResolved(config: { root: string }): void;
|
|
34
|
+
configureServer(server: UxReviewMiddlewareServer): void;
|
|
35
|
+
configurePreviewServer(server: UxReviewMiddlewareServer): void;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/** The nearest directory at or above `start` that holds `.git`, else `start`. */
|
|
39
|
+
export declare function findProjectDirectory(start: string): string;
|
|
40
|
+
|
|
41
|
+
/** Serve the UX Review project directory to catalog pages on dev and preview servers. */
|
|
42
|
+
export declare function uxReviewPlugin(
|
|
43
|
+
options?: UxReviewPluginOptions,
|
|
44
|
+
): UxReviewPlugin;
|