@kerfjs/ui 5.0.0-beta.17 → 5.0.0-beta.21
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 +221 -81
- package/ai/application-ui-diagnostic-ids-v1.json +92 -0
- package/ai/application-ui-profile-sync.cjs +529 -0
- package/ai/application-ui-profile.d.mts +1 -0
- package/ai/application-ui-profile.d.ts +102 -0
- package/ai/application-ui-profile.defaults.json +41 -0
- package/ai/application-ui-profile.mjs +626 -0
- package/ai/application-ui-profile.schema.json +130 -0
- package/ai/catalog-authoring.json +25 -0
- package/ai/catalog-authoring.schema.json +61 -0
- package/ai/compile-time-contracts-v1.json +101 -0
- package/ai/compile-time-contracts-v1.schema.json +49 -0
- package/ai/component-catalog-extension-v2.d.ts +7 -0
- package/ai/component-catalog-extension-v2.schema.json +7 -0
- package/ai/component-catalog-extension.schema.json +79 -0
- package/ai/component-catalog-v2-overrides.json +326 -0
- package/ai/component-catalog-v2.d.ts +67 -0
- package/ai/component-catalog-v2.json +4441 -0
- package/ai/component-catalog-v2.schema.json +246 -0
- package/ai/component-catalog.json +649 -6
- package/ai/component-catalog.schema.json +15 -0
- package/ai/public-api-signatures-v1.md +357 -91
- package/ai/skill.md +95 -50
- package/ai/webawesome-jsx-signatures-v1.md +1 -1
- package/analyzer/cli.mjs +46 -0
- package/analyzer/index.d.mts +45 -0
- package/analyzer/index.mjs +743 -0
- package/analyzer/report.schema.json +66 -0
- package/dist/app-tab.d.ts +1 -1
- package/dist/app-tab.js +1 -1
- package/dist/browser/pane.js +3 -0
- package/dist/browser/sunken-panel.js +3 -0
- package/dist/catalog-resources.d.ts +34 -0
- package/dist/catalog-resources.js +22 -0
- package/dist/catalog-resources.js.map +1 -0
- package/dist/catalog.d.ts +29 -4
- package/dist/catalog.js +302 -84
- package/dist/catalog.js.map +1 -1
- package/dist/chunk-5VTB2BKP.js +35 -0
- package/dist/chunk-5VTB2BKP.js.map +1 -0
- package/dist/chunk-6WTETUZ6.js +21 -0
- package/dist/chunk-6WTETUZ6.js.map +1 -0
- package/dist/chunk-7KEUJIIC.js +218 -0
- package/dist/chunk-7KEUJIIC.js.map +1 -0
- package/dist/chunk-7L6EHUMV.js +31 -0
- package/dist/chunk-7L6EHUMV.js.map +1 -0
- package/dist/{chunk-XXMOARTH.js → chunk-AASLYRGE.js} +57 -16
- package/dist/chunk-AASLYRGE.js.map +1 -0
- package/dist/chunk-BBRXX6PF.js +108 -0
- package/dist/chunk-BBRXX6PF.js.map +1 -0
- package/dist/{chunk-6NLRBSVX.js → chunk-CN2XNTAM.js} +129 -72
- package/dist/chunk-CN2XNTAM.js.map +1 -0
- package/dist/chunk-DPDBVKNA.js +113 -0
- package/dist/chunk-DPDBVKNA.js.map +1 -0
- package/dist/chunk-DSNIYOZ3.js +114 -0
- package/dist/chunk-DSNIYOZ3.js.map +1 -0
- package/dist/chunk-ELSJX4W7.js +68 -0
- package/dist/chunk-ELSJX4W7.js.map +1 -0
- package/dist/{chunk-AHQI52QO.js → chunk-FEY65TBV.js} +6 -2
- package/dist/chunk-FEY65TBV.js.map +1 -0
- package/dist/chunk-JRKSK2HX.js +79 -0
- package/dist/chunk-JRKSK2HX.js.map +1 -0
- package/dist/chunk-K57KRAOV.js +117 -0
- package/dist/chunk-K57KRAOV.js.map +1 -0
- package/dist/chunk-LPOMRC4C.js +25 -0
- package/dist/chunk-LPOMRC4C.js.map +1 -0
- package/dist/chunk-M7JBER5U.js +41 -0
- package/dist/chunk-M7JBER5U.js.map +1 -0
- package/dist/chunk-NENBUYX5.js +79 -0
- package/dist/chunk-NENBUYX5.js.map +1 -0
- package/dist/chunk-OHU6CI22.js +83 -0
- package/dist/chunk-OHU6CI22.js.map +1 -0
- package/dist/{chunk-YGN7OMLT.js → chunk-OZWU5ZPZ.js} +2 -2
- package/dist/chunk-OZWU5ZPZ.js.map +1 -0
- package/dist/chunk-PIDTEQ3U.js +105 -0
- package/dist/chunk-PIDTEQ3U.js.map +1 -0
- package/dist/chunk-PX3YSS5C.js +32 -0
- package/dist/chunk-PX3YSS5C.js.map +1 -0
- package/dist/chunk-PZQVSDLH.js +61 -0
- package/dist/chunk-PZQVSDLH.js.map +1 -0
- package/dist/chunk-QO55FN2Y.js +20 -0
- package/dist/chunk-QO55FN2Y.js.map +1 -0
- package/dist/chunk-QQFJMRIB.js +45 -0
- package/dist/chunk-QQFJMRIB.js.map +1 -0
- package/dist/chunk-RYRIFZCT.js +58 -0
- package/dist/chunk-RYRIFZCT.js.map +1 -0
- package/dist/{chunk-7BR3DO2A.js → chunk-SRSJO5QE.js} +13 -4
- package/dist/chunk-SRSJO5QE.js.map +1 -0
- package/dist/chunk-VLYV65LK.js +38 -0
- package/dist/chunk-VLYV65LK.js.map +1 -0
- package/dist/chunk-W4CXQYSG.js +23 -0
- package/dist/chunk-W4CXQYSG.js.map +1 -0
- package/dist/{chunk-WXMGNX2Y.js → chunk-W7YD6E4N.js} +2 -2
- package/dist/chunk-W7YD6E4N.js.map +1 -0
- package/dist/{chunk-56RJXPHG.js → chunk-Y6LYKFXY.js} +1 -1
- package/dist/{chunk-56RJXPHG.js.map → chunk-Y6LYKFXY.js.map} +1 -1
- package/dist/collapsible-panel.d.ts +2 -2
- package/dist/collapsible-panel.js +47 -6
- package/dist/collapsible-panel.js.map +1 -1
- package/dist/device-class.js +33 -5
- package/dist/device-class.js.map +1 -1
- package/dist/disclosure-arrow.js +1 -1
- package/dist/empty-state.d.ts +1 -1
- package/dist/empty-state.js +1 -1
- package/dist/floating-toolbar.d.ts +1 -1
- package/dist/floating-toolbar.js +1 -1
- package/dist/index.d.ts +6 -4
- package/dist/index.js +27 -25
- package/dist/list-action-row.d.ts +1 -1
- package/dist/list-action-row.js +1 -1
- package/dist/list-header.d.ts +30 -9
- package/dist/list-header.js +1 -1
- package/dist/list-inset-control.d.ts +1 -1
- package/dist/list-inset-control.js +1 -1
- package/dist/list-inset-text.d.ts +1 -1
- package/dist/list-inset-text.js +1 -1
- package/dist/list-item.d.ts +1 -1
- package/dist/list-item.js +1 -1
- package/dist/loading-spinner.js +1 -1
- package/dist/nav-stack.d.ts +1 -1
- package/dist/nav-stack.js +1 -1
- package/dist/pane.d.ts +49 -0
- package/dist/pane.js +4 -0
- package/dist/pane.js.map +1 -0
- package/dist/panel-header.d.ts +10 -4
- package/dist/panel-header.js +1 -1
- package/dist/resizable-region.d.ts +1 -1
- package/dist/resizable-region.js +1 -1
- package/dist/segmented-control.d.ts +6 -6
- package/dist/segmented-control.js +1 -1
- package/dist/select.d.ts +11 -5
- package/dist/select.js +1 -1
- package/dist/skeleton.d.ts +1 -1
- package/dist/skeleton.js +1 -1
- package/dist/split-view.d.ts +1 -1
- package/dist/split-view.js +70 -10
- package/dist/split-view.js.map +1 -1
- package/dist/state-banner.d.ts +4 -3
- package/dist/state-banner.js +1 -1
- package/dist/styles/catalog.css +32 -6
- package/dist/styles/layout.css +2 -20
- package/dist/styles/pane.css +62 -0
- package/dist/styles/segmented-control.css +3 -7
- package/dist/styles/sunken-panel.css +18 -0
- package/dist/sunken-panel.d.ts +16 -0
- package/dist/sunken-panel.js +3 -0
- package/dist/sunken-panel.js.map +1 -0
- package/dist/tab-bar.d.ts +4 -3
- package/dist/tab-bar.js +1 -1
- package/dist/tab-scaffold.d.ts +6 -6
- package/dist/tab-scaffold.js +43 -8
- package/dist/tab-scaffold.js.map +1 -1
- package/dist/token-search-field.d.ts +25 -9
- package/dist/token-search-field.js +1 -1
- package/dist/toolbar-control-group.d.ts +10 -6
- package/dist/toolbar-control-group.js +1 -1
- package/dist/toolbar-text.d.ts +10 -11
- package/dist/toolbar-text.js +1 -1
- package/dist/toolbar.d.ts +1 -1
- package/dist/toolbar.js +1 -1
- package/dist/value-table.d.ts +2 -2
- package/dist/value-table.js +1 -1
- package/dist/wire-catalog.d.ts +31 -2
- package/dist/wire-catalog.js +203 -8
- package/dist/wire-catalog.js.map +1 -1
- package/dist/wire-nav-stack.js +22 -7
- package/dist/wire-nav-stack.js.map +1 -1
- package/dist/wire-resizable-regions.d.ts +1 -1
- package/dist/wire-resizable-regions.js +1 -1
- package/dist/wire-sidebar.js +52 -41
- package/dist/wire-sidebar.js.map +1 -1
- package/dist/wire-tab-bars.d.ts +5 -2
- package/dist/wire-tab-bars.js +1 -1
- package/dist/wire-tab-scaffold.js +9 -4
- package/dist/wire-tab-scaffold.js.map +1 -1
- package/dist/wire-token-search-fields.d.ts +12 -7
- package/dist/wire-token-search-fields.js +1 -1
- package/dist/workbench.d.ts +1 -1
- package/dist/workbench.js +56 -9
- package/dist/workbench.js.map +1 -1
- package/docs/app-layouts.md +7 -7
- package/docs/catalog.md +249 -46
- package/docs/collapsible-panel.md +38 -11
- package/docs/component-contract.md +132 -7
- package/docs/component-selection.md +79 -67
- package/docs/design/templates.md +1 -1
- package/docs/design-philosophy.md +7 -9
- package/docs/device-class.md +8 -8
- package/docs/examples/application-ui-profile.json +60 -0
- package/docs/examples/command-palette-adapter.tsx +67 -17
- package/docs/examples/component-catalog-extension-v2.json +81 -0
- package/docs/examples/component-catalog-extension.json +45 -0
- package/docs/layout.md +51 -32
- package/docs/nav-stack.md +15 -6
- package/docs/recipes.md +4 -4
- package/docs/split-view.md +3 -3
- package/docs/sunken-panel.md +43 -0
- package/docs/tab-scaffold.md +16 -7
- package/docs/type-contracts.md +99 -0
- package/docs/ui-analyzer.md +81 -0
- package/docs/ui-doctor.md +77 -0
- package/docs/ui-evaluator.md +122 -0
- package/docs/webawesome-theme.md +8 -8
- package/docs/workbench.md +18 -5
- package/doctor/cli.mjs +115 -0
- package/doctor/config.schema.json +68 -0
- package/doctor/index.d.mts +116 -0
- package/doctor/index.mjs +1256 -0
- package/doctor/report.schema.json +118 -0
- package/evaluator/cli.mjs +89 -0
- package/evaluator/index.d.mts +90 -0
- package/evaluator/index.mjs +1138 -0
- package/evaluator/report.schema.json +152 -0
- package/llms.txt +58 -15
- package/package.json +70 -10
- package/ux-demo/recipes/app-shell.tsx +206 -10
- package/ux-demo/recipes/collapsible-sidebar.tsx +167 -44
- package/ux-demo/recipes/compact-toolbar.tsx +114 -12
- package/ux-demo/recipes/composer-form.tsx +106 -18
- package/ux-demo/recipes/list-detail-dialog.tsx +144 -8
- package/ux-demo/recipes/list-workspace-states.tsx +165 -8
- package/ux-demo/recipes/loaders.ts +5 -2
- package/ux-demo/recipes/loading-inspector.tsx +124 -41
- package/ux-demo/recipes/mount-recipe.ts +27 -6
- package/ux-demo/recipes/navigation-sidebar.tsx +120 -9
- package/ux-demo/recipes/navigation-stack.tsx +61 -19
- package/ux-demo/recipes/types.ts +3 -1
- package/ux-demo/recipes/workspace-header.tsx +57 -2
- package/dist/chunk-2Z5TWHKQ.js +0 -34
- package/dist/chunk-2Z5TWHKQ.js.map +0 -1
- package/dist/chunk-37T3VNIZ.js +0 -19
- package/dist/chunk-37T3VNIZ.js.map +0 -1
- package/dist/chunk-55DATV3A.js +0 -10
- package/dist/chunk-55DATV3A.js.map +0 -1
- package/dist/chunk-5ATCDSQS.js +0 -42
- package/dist/chunk-5ATCDSQS.js.map +0 -1
- package/dist/chunk-5E2HVJ33.js +0 -10
- package/dist/chunk-5E2HVJ33.js.map +0 -1
- package/dist/chunk-6NLRBSVX.js.map +0 -1
- package/dist/chunk-7BR3DO2A.js.map +0 -1
- package/dist/chunk-7JB7VPRI.js +0 -34
- package/dist/chunk-7JB7VPRI.js.map +0 -1
- package/dist/chunk-7LDCTU7D.js +0 -134
- package/dist/chunk-7LDCTU7D.js.map +0 -1
- package/dist/chunk-AHQI52QO.js.map +0 -1
- package/dist/chunk-AQNKJRFH.js +0 -79
- package/dist/chunk-AQNKJRFH.js.map +0 -1
- package/dist/chunk-AVZHJN6C.js +0 -14
- package/dist/chunk-AVZHJN6C.js.map +0 -1
- package/dist/chunk-B24C4A6T.js +0 -22
- package/dist/chunk-B24C4A6T.js.map +0 -1
- package/dist/chunk-CH4SQ6H5.js +0 -39
- package/dist/chunk-CH4SQ6H5.js.map +0 -1
- package/dist/chunk-DAFFDO33.js +0 -14
- package/dist/chunk-DAFFDO33.js.map +0 -1
- package/dist/chunk-I7INRJO4.js +0 -17
- package/dist/chunk-I7INRJO4.js.map +0 -1
- package/dist/chunk-L4OKFDJY.js +0 -24
- package/dist/chunk-L4OKFDJY.js.map +0 -1
- package/dist/chunk-M5JRI6MN.js +0 -27
- package/dist/chunk-M5JRI6MN.js.map +0 -1
- package/dist/chunk-RNPGFQ33.js +0 -10
- package/dist/chunk-RNPGFQ33.js.map +0 -1
- package/dist/chunk-VPCTCUED.js +0 -10
- package/dist/chunk-VPCTCUED.js.map +0 -1
- package/dist/chunk-WRTAQ7BZ.js +0 -23
- package/dist/chunk-WRTAQ7BZ.js.map +0 -1
- package/dist/chunk-WVPYVDXY.js +0 -15
- package/dist/chunk-WVPYVDXY.js.map +0 -1
- package/dist/chunk-WXMGNX2Y.js.map +0 -1
- package/dist/chunk-XXMOARTH.js.map +0 -1
- package/dist/chunk-YGN7OMLT.js.map +0 -1
- package/dist/chunk-ZQQ6P4SV.js +0 -20
- package/dist/chunk-ZQQ6P4SV.js.map +0 -1
package/dist/tab-scaffold.js
CHANGED
|
@@ -1,14 +1,49 @@
|
|
|
1
1
|
import { jsxs, jsx } from 'kerfjs/jsx-runtime';
|
|
2
2
|
|
|
3
3
|
// src/tab-scaffold.tsx
|
|
4
|
-
function TabScaffold({
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
4
|
+
function TabScaffold({
|
|
5
|
+
id,
|
|
6
|
+
label,
|
|
7
|
+
tabs,
|
|
8
|
+
active,
|
|
9
|
+
className = ""
|
|
10
|
+
}) {
|
|
11
|
+
return /* @__PURE__ */ jsxs(
|
|
12
|
+
"section",
|
|
13
|
+
{
|
|
14
|
+
class: `kui-tab-scaffold ${className}`.trim(),
|
|
15
|
+
id,
|
|
16
|
+
"data-component": "tab-scaffold",
|
|
17
|
+
"data-tab-scaffold-id": id,
|
|
18
|
+
children: [
|
|
19
|
+
/* @__PURE__ */ jsx("div", { class: "kui-tab-scaffold__scenes", children: tabs.map((tab) => /* @__PURE__ */ jsx(
|
|
20
|
+
"div",
|
|
21
|
+
{
|
|
22
|
+
class: "kui-tab-scaffold__scene",
|
|
23
|
+
"data-tab-scaffold-scene": tab.id,
|
|
24
|
+
"data-active": String(tab.id === active),
|
|
25
|
+
"aria-hidden": String(tab.id !== active),
|
|
26
|
+
children: tab.content
|
|
27
|
+
}
|
|
28
|
+
)) }),
|
|
29
|
+
/* @__PURE__ */ jsx("nav", { class: "kui-tab-scaffold__bar", role: "tablist", "aria-label": label, children: tabs.map((tab) => /* @__PURE__ */ jsxs(
|
|
30
|
+
"button",
|
|
31
|
+
{
|
|
32
|
+
type: "button",
|
|
33
|
+
class: "kui-tab-scaffold__tab",
|
|
34
|
+
role: "tab",
|
|
35
|
+
"data-tab-scaffold-tab": tab.id,
|
|
36
|
+
"aria-selected": String(tab.id === active),
|
|
37
|
+
tabindex: tab.id === active ? "0" : "-1",
|
|
38
|
+
children: [
|
|
39
|
+
tab.icon && /* @__PURE__ */ jsx("span", { class: "kui-tab-scaffold__tab-icon", "aria-hidden": "true", children: tab.icon }),
|
|
40
|
+
/* @__PURE__ */ jsx("span", { class: "kui-tab-scaffold__tab-label", children: tab.label })
|
|
41
|
+
]
|
|
42
|
+
}
|
|
43
|
+
)) })
|
|
44
|
+
]
|
|
45
|
+
}
|
|
46
|
+
);
|
|
12
47
|
}
|
|
13
48
|
|
|
14
49
|
export { TabScaffold };
|
package/dist/tab-scaffold.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/tab-scaffold.tsx"],"names":[],"mappings":";;;AA6BO,SAAS,WAAA,
|
|
1
|
+
{"version":3,"sources":["../src/tab-scaffold.tsx"],"names":[],"mappings":";;;AA6BO,SAAS,WAAA,CAA+B;AAAA,EAC7C,EAAA;AAAA,EACA,KAAA;AAAA,EACA,IAAA;AAAA,EACA,MAAA;AAAA,EACA,SAAA,GAAY;AACd,CAAA,EAAyB;AACvB,EAAA,uBACE,IAAA;AAAA,IAAC,SAAA;AAAA,IAAA;AAAA,MACC,KAAA,EAAO,CAAA,iBAAA,EAAoB,SAAS,CAAA,CAAA,CAAG,IAAA,EAAK;AAAA,MAC5C,EAAA;AAAA,MACA,gBAAA,EAAe,cAAA;AAAA,MACf,sBAAA,EAAsB,EAAA;AAAA,MAEtB,QAAA,EAAA;AAAA,wBAAA,GAAA,CAAC,SAAI,KAAA,EAAM,0BAAA,EACR,QAAA,EAAA,IAAA,CAAK,GAAA,CAAI,CAAC,GAAA,qBACT,GAAA;AAAA,UAAC,KAAA;AAAA,UAAA;AAAA,YACC,KAAA,EAAM,yBAAA;AAAA,YACN,2BAAyB,GAAA,CAAI,EAAA;AAAA,YAC7B,aAAA,EAAa,MAAA,CAAO,GAAA,CAAI,EAAA,KAAO,MAAM,CAAA;AAAA,YACrC,aAAA,EAAa,MAAA,CAAO,GAAA,CAAI,EAAA,KAAO,MAAM,CAAA;AAAA,YAEpC,QAAA,EAAA,GAAA,CAAI;AAAA;AAAA,SAER,CAAA,EACH,CAAA;AAAA,wBACA,GAAA,CAAC,KAAA,EAAA,EAAI,KAAA,EAAM,uBAAA,EAAwB,IAAA,EAAK,SAAA,EAAU,YAAA,EAAY,KAAA,EAC3D,QAAA,EAAA,IAAA,CAAK,GAAA,CAAI,CAAC,GAAA,qBACT,IAAA;AAAA,UAAC,QAAA;AAAA,UAAA;AAAA,YACC,IAAA,EAAK,QAAA;AAAA,YACL,KAAA,EAAM,uBAAA;AAAA,YACN,IAAA,EAAK,KAAA;AAAA,YACL,yBAAuB,GAAA,CAAI,EAAA;AAAA,YAC3B,eAAA,EAAe,MAAA,CAAO,GAAA,CAAI,EAAA,KAAO,MAAM,CAAA;AAAA,YACvC,QAAA,EAAU,GAAA,CAAI,EAAA,KAAO,MAAA,GAAS,GAAA,GAAM,IAAA;AAAA,YAEnC,QAAA,EAAA;AAAA,cAAA,GAAA,CAAI,IAAA,wBACF,MAAA,EAAA,EAAK,KAAA,EAAM,8BAA6B,aAAA,EAAY,MAAA,EAClD,cAAI,IAAA,EACP,CAAA;AAAA,8BAEF,GAAA,CAAC,MAAA,EAAA,EAAK,KAAA,EAAM,6BAAA,EAA+B,cAAI,KAAA,EAAM;AAAA;AAAA;AAAA,SAExD,CAAA,EACH;AAAA;AAAA;AAAA,GACF;AAEJ","file":"tab-scaffold.js","sourcesContent":["import type { SafeHtml } from 'kerfjs';\n\nexport interface TabScaffoldTab<Id extends string = string> {\n id: Id;\n label: string;\n /** Decorative icon shown above the label in the bottom bar. */\n icon?: SafeHtml;\n /** The tab's content — typically a `NavStack` so each tab keeps its own stack. */\n content: SafeHtml;\n}\n\nexport interface TabScaffoldProps<Id extends string = string> {\n id: string;\n /** Accessible name for the tab bar. */\n label: string;\n tabs: readonly TabScaffoldTab<Id>[];\n /** The controlled active tab id (the app owns selection). */\n active: NoInfer<Id>;\n className?: string;\n}\n\n/**\n * A mobile-first, iOS-like bottom tab scaffold: a bottom tab bar that switches\n * between major sections, each tab keeping its own content (usually a `NavStack`)\n * mounted so its stack and scroll survive a switch. Controlled — the app owns\n * `active`; wire selection with `@kerfjs/ui/wire-tab-scaffold`'s `wireTabScaffold`.\n * On larger classes, promote the tabs to a `Workbench` rail or sidebar instead of\n * a bottom bar. See `docs/23-app-layouts.md` §3.4.\n */\nexport function TabScaffold<Id extends string>({\n id,\n label,\n tabs,\n active,\n className = '',\n}: TabScaffoldProps<Id>) {\n return (\n <section\n class={`kui-tab-scaffold ${className}`.trim()}\n id={id}\n data-component=\"tab-scaffold\"\n data-tab-scaffold-id={id}\n >\n <div class=\"kui-tab-scaffold__scenes\">\n {tabs.map((tab) => (\n <div\n class=\"kui-tab-scaffold__scene\"\n data-tab-scaffold-scene={tab.id}\n data-active={String(tab.id === active)}\n aria-hidden={String(tab.id !== active)}\n >\n {tab.content}\n </div>\n ))}\n </div>\n <nav class=\"kui-tab-scaffold__bar\" role=\"tablist\" aria-label={label}>\n {tabs.map((tab) => (\n <button\n type=\"button\"\n class=\"kui-tab-scaffold__tab\"\n role=\"tab\"\n data-tab-scaffold-tab={tab.id}\n aria-selected={String(tab.id === active)}\n tabindex={tab.id === active ? '0' : '-1'}\n >\n {tab.icon && (\n <span class=\"kui-tab-scaffold__tab-icon\" aria-hidden=\"true\">\n {tab.icon}\n </span>\n )}\n <span class=\"kui-tab-scaffold__tab-label\">{tab.label}</span>\n </button>\n ))}\n </nav>\n </section>\n );\n}\n"]}
|
|
@@ -6,7 +6,15 @@ interface TokenSearchToken {
|
|
|
6
6
|
offset?: number;
|
|
7
7
|
accessibleLabel?: string;
|
|
8
8
|
}
|
|
9
|
-
|
|
9
|
+
type TokenSearchEditorAttributes = Readonly<Record<`data-${string}`, string | undefined> & {
|
|
10
|
+
'data-component'?: never;
|
|
11
|
+
'data-key'?: never;
|
|
12
|
+
'data-morph-skip'?: never;
|
|
13
|
+
'data-token-search-editor'?: never;
|
|
14
|
+
'data-token-count'?: never;
|
|
15
|
+
'data-placeholder'?: never;
|
|
16
|
+
}>;
|
|
17
|
+
interface TokenSearchFieldBaseProps {
|
|
10
18
|
id: string;
|
|
11
19
|
label: string;
|
|
12
20
|
query?: string;
|
|
@@ -15,12 +23,6 @@ interface TokenSearchFieldProps {
|
|
|
15
23
|
tokenPlaceholder?: string;
|
|
16
24
|
disabled?: boolean;
|
|
17
25
|
autofocus?: boolean;
|
|
18
|
-
/** Allow an empty field to render as one iconic action. */
|
|
19
|
-
collapsible?: boolean;
|
|
20
|
-
/** Keep an empty collapsible field open while the application owns focus. */
|
|
21
|
-
expanded?: boolean;
|
|
22
|
-
expandAction?: string;
|
|
23
|
-
expandLabel?: string;
|
|
24
26
|
leading?: SafeHtml;
|
|
25
27
|
trailing?: SafeHtml;
|
|
26
28
|
editAction?: string;
|
|
@@ -28,8 +30,22 @@ interface TokenSearchFieldProps {
|
|
|
28
30
|
clearAction?: string;
|
|
29
31
|
clearLabel?: string;
|
|
30
32
|
className?: string;
|
|
31
|
-
editorAttributes?:
|
|
33
|
+
editorAttributes?: TokenSearchEditorAttributes;
|
|
32
34
|
}
|
|
35
|
+
type TokenSearchCollapsibleProps = {
|
|
36
|
+
/** Allow an empty field to render as one iconic action. */
|
|
37
|
+
collapsible: true;
|
|
38
|
+
/** Keep an empty collapsible field open while the application owns focus. */
|
|
39
|
+
expanded?: boolean;
|
|
40
|
+
expandAction?: string;
|
|
41
|
+
expandLabel?: string;
|
|
42
|
+
} | {
|
|
43
|
+
collapsible?: false;
|
|
44
|
+
expanded?: never;
|
|
45
|
+
expandAction?: never;
|
|
46
|
+
expandLabel?: never;
|
|
47
|
+
};
|
|
48
|
+
type TokenSearchFieldProps = TokenSearchFieldBaseProps & TokenSearchCollapsibleProps;
|
|
33
49
|
interface TokenSearchFieldValue {
|
|
34
50
|
query: string;
|
|
35
51
|
tokens: TokenSearchToken[];
|
|
@@ -40,4 +56,4 @@ declare function readTokenSearchField(editor: HTMLElement, knownTokens?: readonl
|
|
|
40
56
|
/** Focus an editor and place its caret at a text offset, skipping atomic token chips. */
|
|
41
57
|
declare function placeTokenSearchCaret(editor: HTMLElement, offset?: number): void;
|
|
42
58
|
|
|
43
|
-
export { TokenSearchField, type TokenSearchFieldProps, type TokenSearchFieldValue, type TokenSearchToken, placeTokenSearchCaret, readTokenSearchField };
|
|
59
|
+
export { type TokenSearchEditorAttributes, TokenSearchField, type TokenSearchFieldProps, type TokenSearchFieldValue, type TokenSearchToken, placeTokenSearchCaret, readTokenSearchField };
|
|
@@ -1,17 +1,21 @@
|
|
|
1
1
|
import { SafeHtml } from 'kerfjs';
|
|
2
2
|
|
|
3
|
+
type ToolbarControlGroupAppearance = 'contained' | 'borderless';
|
|
4
|
+
type ToolbarControlGroupTone = 'default' | 'dark';
|
|
5
|
+
type ToolbarControlGroupButtonAppearance = 'plain' | 'push';
|
|
6
|
+
type ToolbarControlGroupShape = 'pill' | 'rounded';
|
|
3
7
|
interface ToolbarControlGroupProps {
|
|
4
8
|
children: SafeHtml | SafeHtml[];
|
|
5
9
|
label?: string;
|
|
6
10
|
className?: string;
|
|
7
11
|
expanded?: boolean;
|
|
8
12
|
single?: boolean;
|
|
9
|
-
appearance?:
|
|
10
|
-
tone?:
|
|
11
|
-
buttonAppearance?:
|
|
13
|
+
appearance?: ToolbarControlGroupAppearance;
|
|
14
|
+
tone?: ToolbarControlGroupTone;
|
|
15
|
+
buttonAppearance?: ToolbarControlGroupButtonAppearance;
|
|
12
16
|
/** Corner shape: fully round `pill` (default) or a softer `rounded` rectangle. */
|
|
13
|
-
shape?:
|
|
17
|
+
shape?: ToolbarControlGroupShape;
|
|
14
18
|
}
|
|
15
|
-
declare function ToolbarControlGroup({ children, label, className, expanded, single, appearance, tone, buttonAppearance, shape }: ToolbarControlGroupProps): SafeHtml;
|
|
19
|
+
declare function ToolbarControlGroup({ children, label, className, expanded, single, appearance, tone, buttonAppearance, shape, }: ToolbarControlGroupProps): SafeHtml;
|
|
16
20
|
|
|
17
|
-
export { ToolbarControlGroup, type ToolbarControlGroupProps };
|
|
21
|
+
export { ToolbarControlGroup, type ToolbarControlGroupAppearance, type ToolbarControlGroupButtonAppearance, type ToolbarControlGroupProps, type ToolbarControlGroupShape, type ToolbarControlGroupTone };
|
package/dist/toolbar-text.d.ts
CHANGED
|
@@ -3,7 +3,7 @@ import * as kerfjs from 'kerfjs';
|
|
|
3
3
|
type ToolbarTextSize = 'xlarge' | 'large' | 'default' | 'small';
|
|
4
4
|
/** ARIA heading level for a title exposed as a heading landmark. */
|
|
5
5
|
type HeadingLevel = 1 | 2 | 3 | 4 | 5 | 6;
|
|
6
|
-
interface
|
|
6
|
+
interface ToolbarTextBaseProps {
|
|
7
7
|
text: string;
|
|
8
8
|
size?: ToolbarTextSize;
|
|
9
9
|
className?: string;
|
|
@@ -17,23 +17,22 @@ interface ToolbarTextProps {
|
|
|
17
17
|
headingLevel?: HeadingLevel;
|
|
18
18
|
/** Render the text as an unanimated loading skeleton instead of its value. */
|
|
19
19
|
placeholder?: boolean;
|
|
20
|
-
/**
|
|
21
|
-
* Wrap onto multiple lines when the text does not fit, instead of the default
|
|
22
|
-
* single line. Combine with `maxLines` to cap the number of lines. Default false.
|
|
23
|
-
*/
|
|
24
|
-
wrap?: boolean;
|
|
25
20
|
/**
|
|
26
21
|
* Show a trailing ellipsis (…) where the text is truncated — on the single line
|
|
27
22
|
* (default), or at the `maxLines` boundary when wrapping. Set false to hard-clip
|
|
28
23
|
* instead. Default true.
|
|
29
24
|
*/
|
|
30
25
|
ellipsis?: boolean;
|
|
31
|
-
/**
|
|
32
|
-
* Cap wrapped text to this many lines, truncating past it. Only takes effect with
|
|
33
|
-
* `wrap`; ignored on a single line. `null`/omitted wraps without a line cap. Default null.
|
|
34
|
-
*/
|
|
35
|
-
maxLines?: number | null;
|
|
36
26
|
}
|
|
27
|
+
type ToolbarTextWrappingProps = {
|
|
28
|
+
/** Wrap onto multiple lines; combine with `maxLines` to cap them. */
|
|
29
|
+
wrap: true;
|
|
30
|
+
maxLines?: number | null;
|
|
31
|
+
} | {
|
|
32
|
+
wrap?: false;
|
|
33
|
+
maxLines?: never;
|
|
34
|
+
};
|
|
35
|
+
type ToolbarTextProps = ToolbarTextBaseProps & ToolbarTextWrappingProps;
|
|
37
36
|
declare function ToolbarText({ text, size, className, id, headingLevel, placeholder, wrap, ellipsis, maxLines, }: ToolbarTextProps): kerfjs.SafeHtml;
|
|
38
37
|
|
|
39
38
|
export { type HeadingLevel, ToolbarText, type ToolbarTextProps, type ToolbarTextSize };
|
package/dist/toolbar-text.js
CHANGED
package/dist/toolbar.d.ts
CHANGED
|
@@ -8,6 +8,6 @@ interface ToolbarProps {
|
|
|
8
8
|
divider?: boolean;
|
|
9
9
|
className?: string;
|
|
10
10
|
}
|
|
11
|
-
declare function Toolbar({ leading, center, trailing, label, divider, className }: ToolbarProps): SafeHtml;
|
|
11
|
+
declare function Toolbar({ leading, center, trailing, label, divider, className, }: ToolbarProps): SafeHtml;
|
|
12
12
|
|
|
13
13
|
export { Toolbar, type ToolbarProps };
|
package/dist/toolbar.js
CHANGED
package/dist/value-table.d.ts
CHANGED
|
@@ -8,13 +8,13 @@ interface ValueTableRowProps {
|
|
|
8
8
|
/** Render the value as an unanimated loading skeleton, keeping the field label. */
|
|
9
9
|
placeholder?: boolean;
|
|
10
10
|
}
|
|
11
|
-
declare function ValueTableRow({ label, value, icon, className, placeholder }: ValueTableRowProps): SafeHtml;
|
|
11
|
+
declare function ValueTableRow({ label, value, icon, className, placeholder, }: ValueTableRowProps): SafeHtml;
|
|
12
12
|
|
|
13
13
|
interface ValueTableProps {
|
|
14
14
|
label: string;
|
|
15
15
|
className?: string;
|
|
16
16
|
children: SafeHtml | readonly SafeHtml[];
|
|
17
17
|
}
|
|
18
|
-
declare function ValueTable({ label, className, children }: ValueTableProps): SafeHtml;
|
|
18
|
+
declare function ValueTable({ label, className, children, }: ValueTableProps): SafeHtml;
|
|
19
19
|
|
|
20
20
|
export { ValueTable, type ValueTableProps, ValueTableRow, type ValueTableRowProps };
|
package/dist/value-table.js
CHANGED
package/dist/wire-catalog.d.ts
CHANGED
|
@@ -9,11 +9,40 @@ interface WireCatalogOptions {
|
|
|
9
9
|
onToggleSecondary?: () => void;
|
|
10
10
|
/** When set, `?<urlParam>=<id>` is written on select via `history.replaceState`. */
|
|
11
11
|
urlParam?: string;
|
|
12
|
+
/**
|
|
13
|
+
* Reveal the chosen sidebar row after selection. `true` uses desktop-safe
|
|
14
|
+
* defaults; pass options to customize scroll alignment or the media guard.
|
|
15
|
+
*/
|
|
16
|
+
revealSelection?: boolean | CatalogRevealOptions;
|
|
12
17
|
selectAction?: string;
|
|
13
18
|
toggleSidebarAction?: string;
|
|
14
19
|
toggleThemeAction?: string;
|
|
15
20
|
toggleSecondaryAction?: string;
|
|
16
21
|
}
|
|
22
|
+
interface CatalogRevealOptions {
|
|
23
|
+
/** Scroll alignment within the sidebar. Default `'nearest'`. */
|
|
24
|
+
block?: ScrollLogicalPosition;
|
|
25
|
+
/** Cross-axis alignment. Default `'nearest'`. */
|
|
26
|
+
inline?: ScrollLogicalPosition;
|
|
27
|
+
/** Scroll behavior. Default `'auto'`. */
|
|
28
|
+
behavior?: ScrollBehavior;
|
|
29
|
+
/**
|
|
30
|
+
* Only reveal when this media query matches. Defaults to the Catalog's
|
|
31
|
+
* desktop layout; pass `false` to reveal at every viewport size.
|
|
32
|
+
*/
|
|
33
|
+
media?: string | false;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Reveal one Catalog sidebar entry after the controlled render settles without
|
|
37
|
+
* moving focus. Returns a cancellation function for rapid selection changes.
|
|
38
|
+
*/
|
|
39
|
+
declare function revealCatalogEntry(root: HTMLElement, id: string, { block, inline, behavior, media, }?: CatalogRevealOptions): () => void;
|
|
40
|
+
/**
|
|
41
|
+
* Keep a Catalog's opt-in geometry overlay synchronized with its preview.
|
|
42
|
+
* Transparent specimens receive a dashed outer bound and positive margins use
|
|
43
|
+
* devtools-style orange bands. Returns a disposer.
|
|
44
|
+
*/
|
|
45
|
+
declare function wireCatalogGeometryOverlay(root: HTMLElement): () => void;
|
|
17
46
|
/**
|
|
18
47
|
* Wire a {@link Catalog}'s interactions with one delegated listener set: sidebar
|
|
19
48
|
* item selection (and the related-entry popup menu), the sidebar collapse toggle, and
|
|
@@ -21,6 +50,6 @@ interface WireCatalogOptions {
|
|
|
21
50
|
* them in the callbacks; optionally mirror the active id into the URL via `urlParam`.
|
|
22
51
|
* Returns a disposer.
|
|
23
52
|
*/
|
|
24
|
-
declare function wireCatalog(root: HTMLElement, { onSelect, onToggleSidebar, onToggleTheme, onToggleSecondary, urlParam, selectAction, toggleSidebarAction, toggleThemeAction, toggleSecondaryAction, }: WireCatalogOptions): () => void;
|
|
53
|
+
declare function wireCatalog(root: HTMLElement, { onSelect, onToggleSidebar, onToggleTheme, onToggleSecondary, urlParam, revealSelection, selectAction, toggleSidebarAction, toggleThemeAction, toggleSecondaryAction, }: WireCatalogOptions): () => void;
|
|
25
54
|
|
|
26
|
-
export { type WireCatalogOptions, wireCatalog };
|
|
55
|
+
export { type CatalogRevealOptions, type WireCatalogOptions, revealCatalogEntry, wireCatalog, wireCatalogGeometryOverlay };
|
package/dist/wire-catalog.js
CHANGED
|
@@ -1,17 +1,177 @@
|
|
|
1
1
|
import { delegate } from 'kerfjs';
|
|
2
2
|
|
|
3
3
|
// src/wire-catalog.ts
|
|
4
|
+
var catalogDesktopMedia = "(min-width: 52.01rem)";
|
|
5
|
+
function revealCatalogEntry(root, id, {
|
|
6
|
+
block = "nearest",
|
|
7
|
+
inline = "nearest",
|
|
8
|
+
behavior = "auto",
|
|
9
|
+
media = catalogDesktopMedia
|
|
10
|
+
} = {}) {
|
|
11
|
+
const view = root.ownerDocument.defaultView;
|
|
12
|
+
if (!view || media && !view.matchMedia(media).matches) return () => {
|
|
13
|
+
};
|
|
14
|
+
const frame = view.requestAnimationFrame(() => {
|
|
15
|
+
for (const item of root.querySelectorAll("[data-item-id]")) {
|
|
16
|
+
if (item.dataset.itemId !== id) continue;
|
|
17
|
+
item.scrollIntoView({ block, inline, behavior });
|
|
18
|
+
break;
|
|
19
|
+
}
|
|
20
|
+
});
|
|
21
|
+
return () => view.cancelAnimationFrame(frame);
|
|
22
|
+
}
|
|
23
|
+
function pixels(value) {
|
|
24
|
+
const number = Number.parseFloat(value);
|
|
25
|
+
if (!Number.isFinite(number)) return 0;
|
|
26
|
+
return value.trim().endsWith("rem") ? number * 16 : number;
|
|
27
|
+
}
|
|
28
|
+
function isTransparent(color) {
|
|
29
|
+
const normalized = color.replace(/\s+/g, "");
|
|
30
|
+
return normalized === "transparent" || /(?:,|\/)0(?:\.0+)?\)$/.test(normalized);
|
|
31
|
+
}
|
|
32
|
+
function isExampleLabel(element) {
|
|
33
|
+
const parent = element.parentElement;
|
|
34
|
+
if (!element.classList.contains("kui-list-header") || !parent?.classList.contains("kui-catalog-example") || element !== parent.firstElementChild)
|
|
35
|
+
return false;
|
|
36
|
+
for (let sibling = element.nextElementSibling; sibling; sibling = sibling.nextElementSibling)
|
|
37
|
+
if (!sibling.classList.contains("kui-catalog-example__note")) return true;
|
|
38
|
+
return false;
|
|
39
|
+
}
|
|
40
|
+
function geometrySpecimens(canvas) {
|
|
41
|
+
const result = [];
|
|
42
|
+
for (const example of canvas.querySelectorAll(
|
|
43
|
+
".kui-catalog-example"
|
|
44
|
+
)) {
|
|
45
|
+
if (example.closest("[data-catalog-geometry-overlay-skip]")) continue;
|
|
46
|
+
for (const child of example.children) {
|
|
47
|
+
if (child.matches("[data-catalog-geometry-overlay]") || child.classList.contains("kui-catalog-example__note") || isExampleLabel(child))
|
|
48
|
+
continue;
|
|
49
|
+
result.push(child);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
for (const element of canvas.querySelectorAll(
|
|
53
|
+
"[data-component]"
|
|
54
|
+
)) {
|
|
55
|
+
if (element.closest("[data-catalog-geometry-overlay]") || element.closest("[data-catalog-geometry-overlay-skip]") || element.closest(".kui-catalog-example"))
|
|
56
|
+
continue;
|
|
57
|
+
const parent = element.parentElement?.closest("[data-component]");
|
|
58
|
+
if (parent && canvas.contains(parent)) continue;
|
|
59
|
+
result.push(element);
|
|
60
|
+
}
|
|
61
|
+
return result;
|
|
62
|
+
}
|
|
63
|
+
function geometryBox(document, className, left, top, width, height) {
|
|
64
|
+
const element = document.createElement("div");
|
|
65
|
+
element.className = className;
|
|
66
|
+
element.style.transform = `translate(${left}px, ${top}px)`;
|
|
67
|
+
element.style.width = `${Math.max(0, width)}px`;
|
|
68
|
+
element.style.height = `${Math.max(0, height)}px`;
|
|
69
|
+
return element;
|
|
70
|
+
}
|
|
71
|
+
function wireCatalogGeometryOverlay(root) {
|
|
72
|
+
const catalog = root.matches('[data-component="catalog"]') ? root : root.querySelector('[data-component="catalog"]');
|
|
73
|
+
const canvas = catalog?.querySelector(".kui-catalog__canvas");
|
|
74
|
+
const layer = catalog?.querySelector(
|
|
75
|
+
"[data-catalog-geometry-overlay]"
|
|
76
|
+
);
|
|
77
|
+
const view = root.ownerDocument.defaultView;
|
|
78
|
+
if (!catalog || !canvas || !layer || !view) return () => {
|
|
79
|
+
};
|
|
80
|
+
let frame = 0;
|
|
81
|
+
const render = () => {
|
|
82
|
+
frame = 0;
|
|
83
|
+
layer.replaceChildren();
|
|
84
|
+
if (catalog.dataset.geometryOverlay !== "true") return;
|
|
85
|
+
const base = canvas.getBoundingClientRect();
|
|
86
|
+
for (const element of geometrySpecimens(canvas)) {
|
|
87
|
+
const rect = element.getBoundingClientRect();
|
|
88
|
+
const style = view.getComputedStyle(element);
|
|
89
|
+
const align = pixels(
|
|
90
|
+
style.getPropertyValue("--kui-catalog-example-align")
|
|
91
|
+
);
|
|
92
|
+
const top = pixels(style.marginTop);
|
|
93
|
+
const right = Math.max(
|
|
94
|
+
0,
|
|
95
|
+
pixels(style.marginRight) - (style.direction === "rtl" ? align : 0)
|
|
96
|
+
);
|
|
97
|
+
const bottom = pixels(style.marginBottom);
|
|
98
|
+
const left = Math.max(
|
|
99
|
+
0,
|
|
100
|
+
pixels(style.marginLeft) - (style.direction === "rtl" ? 0 : align)
|
|
101
|
+
);
|
|
102
|
+
const x = rect.left - base.left + canvas.scrollLeft;
|
|
103
|
+
const y = rect.top - base.top + canvas.scrollTop;
|
|
104
|
+
if (isTransparent(style.backgroundColor))
|
|
105
|
+
layer.append(
|
|
106
|
+
geometryBox(
|
|
107
|
+
root.ownerDocument,
|
|
108
|
+
"kui-catalog__geometry-bound",
|
|
109
|
+
x,
|
|
110
|
+
y,
|
|
111
|
+
rect.width,
|
|
112
|
+
rect.height
|
|
113
|
+
)
|
|
114
|
+
);
|
|
115
|
+
const margins = [
|
|
116
|
+
[top, x - left, y - top, rect.width + left + right, top],
|
|
117
|
+
[bottom, x - left, y + rect.height, rect.width + left + right, bottom],
|
|
118
|
+
[left, x - left, y, left, rect.height],
|
|
119
|
+
[right, x + rect.width, y, right, rect.height]
|
|
120
|
+
];
|
|
121
|
+
for (const [size, marginX, marginY, width, height] of margins) {
|
|
122
|
+
if (size <= 0) continue;
|
|
123
|
+
layer.append(
|
|
124
|
+
geometryBox(
|
|
125
|
+
root.ownerDocument,
|
|
126
|
+
"kui-catalog__geometry-margin",
|
|
127
|
+
marginX,
|
|
128
|
+
marginY,
|
|
129
|
+
width,
|
|
130
|
+
height
|
|
131
|
+
)
|
|
132
|
+
);
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
};
|
|
136
|
+
const schedule = () => {
|
|
137
|
+
if (!frame) frame = view.requestAnimationFrame(render);
|
|
138
|
+
};
|
|
139
|
+
const resizeObserver = new view.ResizeObserver(schedule);
|
|
140
|
+
resizeObserver.observe(canvas);
|
|
141
|
+
const mutationObserver = new view.MutationObserver((records) => {
|
|
142
|
+
if (records.some(
|
|
143
|
+
({ target }) => target !== layer && !layer.contains(target)
|
|
144
|
+
))
|
|
145
|
+
schedule();
|
|
146
|
+
});
|
|
147
|
+
mutationObserver.observe(catalog, {
|
|
148
|
+
attributes: true,
|
|
149
|
+
childList: true,
|
|
150
|
+
subtree: true
|
|
151
|
+
});
|
|
152
|
+
view.addEventListener("resize", schedule);
|
|
153
|
+
render();
|
|
154
|
+
return () => {
|
|
155
|
+
if (frame) view.cancelAnimationFrame(frame);
|
|
156
|
+
resizeObserver.disconnect();
|
|
157
|
+
mutationObserver.disconnect();
|
|
158
|
+
view.removeEventListener("resize", schedule);
|
|
159
|
+
layer.replaceChildren();
|
|
160
|
+
};
|
|
161
|
+
}
|
|
4
162
|
function wireCatalog(root, {
|
|
5
163
|
onSelect,
|
|
6
164
|
onToggleSidebar,
|
|
7
165
|
onToggleTheme,
|
|
8
166
|
onToggleSecondary,
|
|
9
167
|
urlParam,
|
|
168
|
+
revealSelection,
|
|
10
169
|
selectAction = "catalog-select",
|
|
11
170
|
toggleSidebarAction = "catalog-toggle-sidebar",
|
|
12
171
|
toggleThemeAction = "catalog-toggle-theme",
|
|
13
172
|
toggleSecondaryAction = "catalog-toggle-secondary"
|
|
14
173
|
}) {
|
|
174
|
+
let cancelReveal;
|
|
15
175
|
const select = (id) => {
|
|
16
176
|
onSelect(id);
|
|
17
177
|
const view = root.ownerDocument.defaultView;
|
|
@@ -20,29 +180,64 @@ function wireCatalog(root, {
|
|
|
20
180
|
url.searchParams.set(urlParam, id);
|
|
21
181
|
view.history.replaceState(null, "", url);
|
|
22
182
|
}
|
|
183
|
+
if (revealSelection) {
|
|
184
|
+
cancelReveal?.();
|
|
185
|
+
cancelReveal = revealCatalogEntry(
|
|
186
|
+
root,
|
|
187
|
+
id,
|
|
188
|
+
revealSelection === true ? void 0 : revealSelection
|
|
189
|
+
);
|
|
190
|
+
}
|
|
23
191
|
};
|
|
24
192
|
const disposers = [
|
|
25
193
|
// Sidebar items AND the footer's related-entry popup-menu items both carry
|
|
26
194
|
// `data-action={selectAction}` + `data-item-id`, so one delegated click covers both.
|
|
27
|
-
delegate(
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
195
|
+
delegate(
|
|
196
|
+
root,
|
|
197
|
+
"click",
|
|
198
|
+
`[data-action="${selectAction}"]`,
|
|
199
|
+
(_event, element) => {
|
|
200
|
+
const id = element.dataset.itemId;
|
|
201
|
+
if (id) select(id);
|
|
202
|
+
}
|
|
203
|
+
)
|
|
31
204
|
];
|
|
32
205
|
if (onToggleSidebar) {
|
|
33
|
-
disposers.push(
|
|
206
|
+
disposers.push(
|
|
207
|
+
delegate(
|
|
208
|
+
root,
|
|
209
|
+
"click",
|
|
210
|
+
`[data-action="${toggleSidebarAction}"]`,
|
|
211
|
+
() => onToggleSidebar()
|
|
212
|
+
)
|
|
213
|
+
);
|
|
34
214
|
}
|
|
35
215
|
if (onToggleTheme) {
|
|
36
|
-
disposers.push(
|
|
216
|
+
disposers.push(
|
|
217
|
+
delegate(
|
|
218
|
+
root,
|
|
219
|
+
"click",
|
|
220
|
+
`[data-action="${toggleThemeAction}"]`,
|
|
221
|
+
() => onToggleTheme()
|
|
222
|
+
)
|
|
223
|
+
);
|
|
37
224
|
}
|
|
38
225
|
if (onToggleSecondary) {
|
|
39
|
-
disposers.push(
|
|
226
|
+
disposers.push(
|
|
227
|
+
delegate(
|
|
228
|
+
root,
|
|
229
|
+
"click",
|
|
230
|
+
`[data-action="${toggleSecondaryAction}"]`,
|
|
231
|
+
() => onToggleSecondary()
|
|
232
|
+
)
|
|
233
|
+
);
|
|
40
234
|
}
|
|
41
235
|
return () => {
|
|
236
|
+
cancelReveal?.();
|
|
42
237
|
for (const dispose of disposers.splice(0)) dispose();
|
|
43
238
|
};
|
|
44
239
|
}
|
|
45
240
|
|
|
46
|
-
export { wireCatalog };
|
|
241
|
+
export { revealCatalogEntry, wireCatalog, wireCatalogGeometryOverlay };
|
|
47
242
|
|
|
48
243
|
//# sourceMappingURL=wire-catalog.js.map
|
package/dist/wire-catalog.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/wire-catalog.ts"],"names":[],"mappings":";;;AA0BO,SAAS,YACd,IAAA,EACA;AAAA,EACE,QAAA;AAAA,EACA,eAAA;AAAA,EACA,aAAA;AAAA,EACA,iBAAA;AAAA,EACA,QAAA;AAAA,EACA,YAAA,GAAe,gBAAA;AAAA,EACf,mBAAA,GAAsB,wBAAA;AAAA,EACtB,iBAAA,GAAoB,sBAAA;AAAA,EACpB,qBAAA,GAAwB;AAC1B,CAAA,EACY;AACZ,EAAA,MAAM,MAAA,GAAS,CAAC,EAAA,KAAe;AAC7B,IAAA,QAAA,CAAS,EAAE,CAAA;AACX,IAAA,MAAM,IAAA,GAAO,KAAK,aAAA,CAAc,WAAA;AAChC,IAAA,IAAI,YAAY,IAAA,EAAM;AACpB,MAAA,MAAM,GAAA,GAAM,IAAI,GAAA,CAAI,IAAA,CAAK,SAAS,IAAI,CAAA;AACtC,MAAA,GAAA,CAAI,YAAA,CAAa,GAAA,CAAI,QAAA,EAAU,EAAE,CAAA;AACjC,MAAA,IAAA,CAAK,OAAA,CAAQ,YAAA,CAAa,IAAA,EAAM,EAAA,EAAI,GAAG,CAAA;AAAA,IACzC;AAAA,EACF,CAAA;AAEA,EAAA,MAAM,SAAA,GAA+B;AAAA;AAAA;AAAA,IAGnC,QAAA,CAAS,MAAM,OAAA,EAAS,CAAA,cAAA,EAAiB,YAAY,CAAA,EAAA,CAAA,EAAM,CAAC,QAAQ,OAAA,KAAY;AAC9E,MAAA,MAAM,EAAA,GAAM,QAAwB,OAAA,CAAQ,MAAA;AAC5C,MAAA,IAAI,EAAA,SAAW,EAAE,CAAA;AAAA,IACnB,CAAC;AAAA,GACH;AACA,EAAA,IAAI,eAAA,EAAiB;AACnB,IAAA,SAAA,CAAU,IAAA,CAAK,QAAA,CAAS,IAAA,EAAM,OAAA,EAAS,CAAA,cAAA,EAAiB,mBAAmB,CAAA,EAAA,CAAA,EAAM,MAAM,eAAA,EAAiB,CAAC,CAAA;AAAA,EAC3G;AACA,EAAA,IAAI,aAAA,EAAe;AACjB,IAAA,SAAA,CAAU,IAAA,CAAK,QAAA,CAAS,IAAA,EAAM,OAAA,EAAS,CAAA,cAAA,EAAiB,iBAAiB,CAAA,EAAA,CAAA,EAAM,MAAM,aAAA,EAAe,CAAC,CAAA;AAAA,EACvG;AACA,EAAA,IAAI,iBAAA,EAAmB;AACrB,IAAA,SAAA,CAAU,IAAA,CAAK,QAAA,CAAS,IAAA,EAAM,OAAA,EAAS,CAAA,cAAA,EAAiB,qBAAqB,CAAA,EAAA,CAAA,EAAM,MAAM,iBAAA,EAAmB,CAAC,CAAA;AAAA,EAC/G;AACA,EAAA,OAAO,MAAM;AACX,IAAA,KAAA,MAAW,OAAA,IAAW,SAAA,CAAU,MAAA,CAAO,CAAC,GAAG,OAAA,EAAQ;AAAA,EACrD,CAAA;AACF","file":"wire-catalog.js","sourcesContent":["import { delegate } from 'kerfjs';\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 /** 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 selectAction?: string;\n toggleSidebarAction?: string;\n toggleThemeAction?: string;\n toggleSecondaryAction?: string;\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 * Returns a disposer.\n */\nexport function wireCatalog(\n root: HTMLElement,\n {\n onSelect,\n onToggleSidebar,\n onToggleTheme,\n onToggleSecondary,\n urlParam,\n selectAction = 'catalog-select',\n toggleSidebarAction = 'catalog-toggle-sidebar',\n toggleThemeAction = 'catalog-toggle-theme',\n toggleSecondaryAction = 'catalog-toggle-secondary',\n }: WireCatalogOptions,\n): () => void {\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 };\n\n const disposers: Array<() => void> = [\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(root, 'click', `[data-action=\"${selectAction}\"]`, (_event, element) => {\n const id = (element as HTMLElement).dataset.itemId;\n if (id) select(id);\n }),\n ];\n if (onToggleSidebar) {\n disposers.push(delegate(root, 'click', `[data-action=\"${toggleSidebarAction}\"]`, () => onToggleSidebar()));\n }\n if (onToggleTheme) {\n disposers.push(delegate(root, 'click', `[data-action=\"${toggleThemeAction}\"]`, () => onToggleTheme()));\n }\n if (onToggleSecondary) {\n disposers.push(delegate(root, 'click', `[data-action=\"${toggleSecondaryAction}\"]`, () => onToggleSecondary()));\n }\n return () => {\n for (const dispose of disposers.splice(0)) dispose();\n };\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/wire-catalog.ts"],"names":[],"mappings":"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","file":"wire-catalog.js","sourcesContent":["import { delegate } from 'kerfjs';\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 /** 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 toggleSecondaryAction?: 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\nconst catalogDesktopMedia = '(min-width: 52.01rem)';\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\nfunction pixels(value: string): number {\n const number = Number.parseFloat(value);\n if (!Number.isFinite(number)) return 0;\n return value.trim().endsWith('rem') ? number * 16 : number;\n}\n\nfunction isTransparent(color: string): boolean {\n const normalized = color.replace(/\\s+/g, '');\n return (\n normalized === 'transparent' || /(?:,|\\/)0(?:\\.0+)?\\)$/.test(normalized)\n );\n}\n\nfunction isExampleLabel(element: Element): boolean {\n const parent = element.parentElement;\n if (\n !element.classList.contains('kui-list-header') ||\n !parent?.classList.contains('kui-catalog-example') ||\n element !== parent.firstElementChild\n )\n return false;\n for (\n let sibling = element.nextElementSibling;\n sibling;\n sibling = sibling.nextElementSibling\n )\n if (!sibling.classList.contains('kui-catalog-example__note')) return true;\n return false;\n}\n\nfunction geometrySpecimens(canvas: HTMLElement): Element[] {\n const result: Element[] = [];\n for (const example of canvas.querySelectorAll<HTMLElement>(\n '.kui-catalog-example',\n )) {\n if (example.closest('[data-catalog-geometry-overlay-skip]')) continue;\n for (const child of example.children) {\n if (\n child.matches('[data-catalog-geometry-overlay]') ||\n child.classList.contains('kui-catalog-example__note') ||\n isExampleLabel(child)\n )\n continue;\n result.push(child);\n }\n }\n for (const element of canvas.querySelectorAll<HTMLElement>(\n '[data-component]',\n )) {\n if (\n element.closest('[data-catalog-geometry-overlay]') ||\n element.closest('[data-catalog-geometry-overlay-skip]') ||\n element.closest('.kui-catalog-example')\n )\n continue;\n const parent =\n element.parentElement?.closest<HTMLElement>('[data-component]');\n if (parent && canvas.contains(parent)) continue;\n result.push(element);\n }\n return result;\n}\n\nfunction geometryBox(\n document: Document,\n className: string,\n left: number,\n top: number,\n width: number,\n height: number,\n): HTMLElement {\n const element = document.createElement('div');\n element.className = className;\n element.style.transform = `translate(${left}px, ${top}px)`;\n element.style.width = `${Math.max(0, width)}px`;\n element.style.height = `${Math.max(0, height)}px`;\n return element;\n}\n\n/**\n * Keep a Catalog's opt-in geometry overlay synchronized with its preview.\n * Transparent specimens receive a dashed outer bound and positive margins use\n * devtools-style orange bands. Returns a disposer.\n */\nexport function wireCatalogGeometryOverlay(root: HTMLElement): () => void {\n const catalog = root.matches('[data-component=\"catalog\"]')\n ? root\n : root.querySelector<HTMLElement>('[data-component=\"catalog\"]');\n const canvas = catalog?.querySelector<HTMLElement>('.kui-catalog__canvas');\n const layer = catalog?.querySelector<HTMLElement>(\n '[data-catalog-geometry-overlay]',\n );\n const view = root.ownerDocument.defaultView;\n if (!catalog || !canvas || !layer || !view) return () => {};\n\n let frame = 0;\n const render = (): void => {\n frame = 0;\n layer.replaceChildren();\n if (catalog.dataset.geometryOverlay !== 'true') return;\n const base = canvas.getBoundingClientRect();\n for (const element of geometrySpecimens(canvas)) {\n const rect = element.getBoundingClientRect();\n const style = view.getComputedStyle(element);\n const align = pixels(\n style.getPropertyValue('--kui-catalog-example-align'),\n );\n const top = pixels(style.marginTop);\n const right = Math.max(\n 0,\n pixels(style.marginRight) - (style.direction === 'rtl' ? align : 0),\n );\n const bottom = pixels(style.marginBottom);\n const left = Math.max(\n 0,\n pixels(style.marginLeft) - (style.direction === 'rtl' ? 0 : align),\n );\n const x = rect.left - base.left + canvas.scrollLeft;\n const y = rect.top - base.top + canvas.scrollTop;\n if (isTransparent(style.backgroundColor))\n layer.append(\n geometryBox(\n root.ownerDocument,\n 'kui-catalog__geometry-bound',\n x,\n y,\n rect.width,\n rect.height,\n ),\n );\n const margins = [\n [top, x - left, y - top, rect.width + left + right, top],\n [bottom, x - left, y + rect.height, rect.width + left + right, bottom],\n [left, x - left, y, left, rect.height],\n [right, x + rect.width, y, right, rect.height],\n ];\n for (const [size, marginX, marginY, width, height] of margins) {\n if (size <= 0) continue;\n layer.append(\n geometryBox(\n root.ownerDocument,\n 'kui-catalog__geometry-margin',\n marginX,\n marginY,\n width,\n height,\n ),\n );\n }\n }\n };\n const schedule = (): void => {\n if (!frame) frame = view.requestAnimationFrame(render);\n };\n const resizeObserver = new view.ResizeObserver(schedule);\n resizeObserver.observe(canvas);\n const mutationObserver = new view.MutationObserver((records) => {\n if (\n records.some(\n ({ target }) => target !== layer && !layer.contains(target as Node),\n )\n )\n schedule();\n });\n mutationObserver.observe(catalog, {\n attributes: true,\n childList: true,\n subtree: true,\n });\n view.addEventListener('resize', schedule);\n render();\n return () => {\n if (frame) view.cancelAnimationFrame(frame);\n resizeObserver.disconnect();\n mutationObserver.disconnect();\n view.removeEventListener('resize', schedule);\n layer.replaceChildren();\n };\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 * Returns a disposer.\n */\nexport function wireCatalog(\n root: HTMLElement,\n {\n onSelect,\n onToggleSidebar,\n onToggleTheme,\n onToggleSecondary,\n urlParam,\n revealSelection,\n selectAction = 'catalog-select',\n toggleSidebarAction = 'catalog-toggle-sidebar',\n toggleThemeAction = 'catalog-toggle-theme',\n toggleSecondaryAction = 'catalog-toggle-secondary',\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 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 // 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 (onToggleSecondary) {\n disposers.push(\n delegate(root, 'click', `[data-action=\"${toggleSecondaryAction}\"]`, () =>\n onToggleSecondary(),\n ),\n );\n }\n return () => {\n cancelReveal?.();\n for (const dispose of disposers.splice(0)) dispose();\n };\n}\n"]}
|