@kerfjs/ui 5.0.0-beta.17 → 5.0.0-beta.18

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (213) hide show
  1. package/README.md +108 -79
  2. package/ai/component-catalog-extension.schema.json +79 -0
  3. package/ai/component-catalog.json +499 -0
  4. package/ai/component-catalog.schema.json +15 -0
  5. package/ai/public-api-signatures-v1.md +67 -31
  6. package/ai/skill.md +58 -49
  7. package/ai/webawesome-jsx-signatures-v1.md +1 -1
  8. package/dist/app-tab.d.ts +1 -1
  9. package/dist/app-tab.js +1 -1
  10. package/dist/catalog.d.ts +10 -3
  11. package/dist/catalog.js +279 -90
  12. package/dist/catalog.js.map +1 -1
  13. package/dist/chunk-43FUQH35.js +83 -0
  14. package/dist/chunk-43FUQH35.js.map +1 -0
  15. package/dist/{chunk-YGN7OMLT.js → chunk-4TRDV6RL.js} +2 -2
  16. package/dist/chunk-4TRDV6RL.js.map +1 -0
  17. package/dist/chunk-6ETZKKAE.js +38 -0
  18. package/dist/chunk-6ETZKKAE.js.map +1 -0
  19. package/dist/chunk-6WTETUZ6.js +21 -0
  20. package/dist/chunk-6WTETUZ6.js.map +1 -0
  21. package/dist/chunk-7L6EHUMV.js +31 -0
  22. package/dist/chunk-7L6EHUMV.js.map +1 -0
  23. package/dist/chunk-BBRXX6PF.js +108 -0
  24. package/dist/chunk-BBRXX6PF.js.map +1 -0
  25. package/dist/chunk-DPDBVKNA.js +113 -0
  26. package/dist/chunk-DPDBVKNA.js.map +1 -0
  27. package/dist/chunk-ELSJX4W7.js +68 -0
  28. package/dist/chunk-ELSJX4W7.js.map +1 -0
  29. package/dist/{chunk-6NLRBSVX.js → chunk-ENVTNLYC.js} +125 -68
  30. package/dist/chunk-ENVTNLYC.js.map +1 -0
  31. package/dist/{chunk-AHQI52QO.js → chunk-FEY65TBV.js} +6 -2
  32. package/dist/chunk-FEY65TBV.js.map +1 -0
  33. package/dist/chunk-JTHUXDN2.js +58 -0
  34. package/dist/chunk-JTHUXDN2.js.map +1 -0
  35. package/dist/chunk-LPOMRC4C.js +25 -0
  36. package/dist/chunk-LPOMRC4C.js.map +1 -0
  37. package/dist/chunk-NENBUYX5.js +79 -0
  38. package/dist/chunk-NENBUYX5.js.map +1 -0
  39. package/dist/{chunk-XXMOARTH.js → chunk-NVWXKU37.js} +57 -16
  40. package/dist/chunk-NVWXKU37.js.map +1 -0
  41. package/dist/chunk-PIDTEQ3U.js +105 -0
  42. package/dist/chunk-PIDTEQ3U.js.map +1 -0
  43. package/dist/chunk-PX3YSS5C.js +32 -0
  44. package/dist/chunk-PX3YSS5C.js.map +1 -0
  45. package/dist/chunk-PZQVSDLH.js +61 -0
  46. package/dist/chunk-PZQVSDLH.js.map +1 -0
  47. package/dist/chunk-QIRXYKCE.js +113 -0
  48. package/dist/chunk-QIRXYKCE.js.map +1 -0
  49. package/dist/chunk-QO55FN2Y.js +20 -0
  50. package/dist/chunk-QO55FN2Y.js.map +1 -0
  51. package/dist/chunk-QQFJMRIB.js +45 -0
  52. package/dist/chunk-QQFJMRIB.js.map +1 -0
  53. package/dist/chunk-S3HKPI7I.js +218 -0
  54. package/dist/chunk-S3HKPI7I.js.map +1 -0
  55. package/dist/{chunk-WXMGNX2Y.js → chunk-S3PCZ7NV.js} +2 -2
  56. package/dist/chunk-S3PCZ7NV.js.map +1 -0
  57. package/dist/{chunk-7BR3DO2A.js → chunk-SRSJO5QE.js} +13 -4
  58. package/dist/chunk-SRSJO5QE.js.map +1 -0
  59. package/dist/chunk-U5IFGQCD.js +117 -0
  60. package/dist/chunk-U5IFGQCD.js.map +1 -0
  61. package/dist/{chunk-56RJXPHG.js → chunk-Y6LYKFXY.js} +1 -1
  62. package/dist/{chunk-56RJXPHG.js.map → chunk-Y6LYKFXY.js.map} +1 -1
  63. package/dist/chunk-ZK2G3VR5.js +35 -0
  64. package/dist/chunk-ZK2G3VR5.js.map +1 -0
  65. package/dist/chunk-ZVI5YST2.js +41 -0
  66. package/dist/chunk-ZVI5YST2.js.map +1 -0
  67. package/dist/collapsible-panel.d.ts +2 -2
  68. package/dist/collapsible-panel.js +47 -6
  69. package/dist/collapsible-panel.js.map +1 -1
  70. package/dist/device-class.js +33 -5
  71. package/dist/device-class.js.map +1 -1
  72. package/dist/disclosure-arrow.js +1 -1
  73. package/dist/empty-state.d.ts +1 -1
  74. package/dist/empty-state.js +1 -1
  75. package/dist/floating-toolbar.d.ts +1 -1
  76. package/dist/floating-toolbar.js +1 -1
  77. package/dist/index.js +25 -25
  78. package/dist/list-action-row.d.ts +1 -1
  79. package/dist/list-action-row.js +1 -1
  80. package/dist/list-header.d.ts +1 -1
  81. package/dist/list-header.js +1 -1
  82. package/dist/list-inset-control.d.ts +1 -1
  83. package/dist/list-inset-control.js +1 -1
  84. package/dist/list-inset-text.d.ts +1 -1
  85. package/dist/list-inset-text.js +1 -1
  86. package/dist/list-item.d.ts +1 -1
  87. package/dist/list-item.js +1 -1
  88. package/dist/loading-spinner.js +1 -1
  89. package/dist/nav-stack.d.ts +1 -1
  90. package/dist/nav-stack.js +1 -1
  91. package/dist/panel-header.d.ts +1 -1
  92. package/dist/panel-header.js +1 -1
  93. package/dist/resizable-region.d.ts +1 -1
  94. package/dist/resizable-region.js +1 -1
  95. package/dist/segmented-control.js +1 -1
  96. package/dist/select.d.ts +1 -1
  97. package/dist/select.js +1 -1
  98. package/dist/skeleton.d.ts +1 -1
  99. package/dist/skeleton.js +1 -1
  100. package/dist/split-view.d.ts +1 -1
  101. package/dist/split-view.js +70 -10
  102. package/dist/split-view.js.map +1 -1
  103. package/dist/state-banner.d.ts +1 -1
  104. package/dist/state-banner.js +1 -1
  105. package/dist/styles/catalog.css +26 -0
  106. package/dist/tab-bar.d.ts +1 -1
  107. package/dist/tab-bar.js +1 -1
  108. package/dist/tab-scaffold.d.ts +1 -1
  109. package/dist/tab-scaffold.js +43 -8
  110. package/dist/tab-scaffold.js.map +1 -1
  111. package/dist/token-search-field.js +1 -1
  112. package/dist/toolbar-control-group.d.ts +1 -1
  113. package/dist/toolbar-control-group.js +1 -1
  114. package/dist/toolbar-text.js +1 -1
  115. package/dist/toolbar.d.ts +1 -1
  116. package/dist/toolbar.js +1 -1
  117. package/dist/value-table.d.ts +2 -2
  118. package/dist/value-table.js +1 -1
  119. package/dist/wire-catalog.d.ts +31 -2
  120. package/dist/wire-catalog.js +203 -8
  121. package/dist/wire-catalog.js.map +1 -1
  122. package/dist/wire-nav-stack.js +22 -7
  123. package/dist/wire-nav-stack.js.map +1 -1
  124. package/dist/wire-resizable-regions.d.ts +1 -1
  125. package/dist/wire-resizable-regions.js +1 -1
  126. package/dist/wire-sidebar.js +52 -41
  127. package/dist/wire-sidebar.js.map +1 -1
  128. package/dist/wire-tab-bars.js +1 -1
  129. package/dist/wire-tab-scaffold.js +9 -4
  130. package/dist/wire-tab-scaffold.js.map +1 -1
  131. package/dist/wire-token-search-fields.d.ts +1 -1
  132. package/dist/wire-token-search-fields.js +1 -1
  133. package/dist/workbench.d.ts +1 -1
  134. package/dist/workbench.js +56 -9
  135. package/dist/workbench.js.map +1 -1
  136. package/docs/app-layouts.md +7 -7
  137. package/docs/catalog.md +108 -24
  138. package/docs/collapsible-panel.md +38 -11
  139. package/docs/component-contract.md +30 -2
  140. package/docs/component-selection.md +71 -63
  141. package/docs/design/templates.md +1 -1
  142. package/docs/design-philosophy.md +5 -5
  143. package/docs/device-class.md +8 -8
  144. package/docs/examples/command-palette-adapter.tsx +67 -17
  145. package/docs/examples/component-catalog-extension.json +45 -0
  146. package/docs/layout.md +19 -19
  147. package/docs/nav-stack.md +15 -6
  148. package/docs/recipes.md +4 -4
  149. package/docs/split-view.md +3 -3
  150. package/docs/tab-scaffold.md +16 -7
  151. package/docs/webawesome-theme.md +8 -8
  152. package/docs/workbench.md +18 -5
  153. package/llms.txt +20 -14
  154. package/package.json +6 -4
  155. package/ux-demo/recipes/app-shell.tsx +206 -10
  156. package/ux-demo/recipes/collapsible-sidebar.tsx +167 -44
  157. package/ux-demo/recipes/compact-toolbar.tsx +114 -12
  158. package/ux-demo/recipes/composer-form.tsx +106 -18
  159. package/ux-demo/recipes/list-detail-dialog.tsx +144 -8
  160. package/ux-demo/recipes/list-workspace-states.tsx +165 -8
  161. package/ux-demo/recipes/loaders.ts +5 -2
  162. package/ux-demo/recipes/loading-inspector.tsx +124 -41
  163. package/ux-demo/recipes/mount-recipe.ts +27 -6
  164. package/ux-demo/recipes/navigation-sidebar.tsx +120 -9
  165. package/ux-demo/recipes/navigation-stack.tsx +61 -19
  166. package/ux-demo/recipes/types.ts +3 -1
  167. package/ux-demo/recipes/workspace-header.tsx +57 -2
  168. package/dist/chunk-2Z5TWHKQ.js +0 -34
  169. package/dist/chunk-2Z5TWHKQ.js.map +0 -1
  170. package/dist/chunk-37T3VNIZ.js +0 -19
  171. package/dist/chunk-37T3VNIZ.js.map +0 -1
  172. package/dist/chunk-55DATV3A.js +0 -10
  173. package/dist/chunk-55DATV3A.js.map +0 -1
  174. package/dist/chunk-5ATCDSQS.js +0 -42
  175. package/dist/chunk-5ATCDSQS.js.map +0 -1
  176. package/dist/chunk-5E2HVJ33.js +0 -10
  177. package/dist/chunk-5E2HVJ33.js.map +0 -1
  178. package/dist/chunk-6NLRBSVX.js.map +0 -1
  179. package/dist/chunk-7BR3DO2A.js.map +0 -1
  180. package/dist/chunk-7JB7VPRI.js +0 -34
  181. package/dist/chunk-7JB7VPRI.js.map +0 -1
  182. package/dist/chunk-7LDCTU7D.js +0 -134
  183. package/dist/chunk-7LDCTU7D.js.map +0 -1
  184. package/dist/chunk-AHQI52QO.js.map +0 -1
  185. package/dist/chunk-AQNKJRFH.js +0 -79
  186. package/dist/chunk-AQNKJRFH.js.map +0 -1
  187. package/dist/chunk-AVZHJN6C.js +0 -14
  188. package/dist/chunk-AVZHJN6C.js.map +0 -1
  189. package/dist/chunk-B24C4A6T.js +0 -22
  190. package/dist/chunk-B24C4A6T.js.map +0 -1
  191. package/dist/chunk-CH4SQ6H5.js +0 -39
  192. package/dist/chunk-CH4SQ6H5.js.map +0 -1
  193. package/dist/chunk-DAFFDO33.js +0 -14
  194. package/dist/chunk-DAFFDO33.js.map +0 -1
  195. package/dist/chunk-I7INRJO4.js +0 -17
  196. package/dist/chunk-I7INRJO4.js.map +0 -1
  197. package/dist/chunk-L4OKFDJY.js +0 -24
  198. package/dist/chunk-L4OKFDJY.js.map +0 -1
  199. package/dist/chunk-M5JRI6MN.js +0 -27
  200. package/dist/chunk-M5JRI6MN.js.map +0 -1
  201. package/dist/chunk-RNPGFQ33.js +0 -10
  202. package/dist/chunk-RNPGFQ33.js.map +0 -1
  203. package/dist/chunk-VPCTCUED.js +0 -10
  204. package/dist/chunk-VPCTCUED.js.map +0 -1
  205. package/dist/chunk-WRTAQ7BZ.js +0 -23
  206. package/dist/chunk-WRTAQ7BZ.js.map +0 -1
  207. package/dist/chunk-WVPYVDXY.js +0 -15
  208. package/dist/chunk-WVPYVDXY.js.map +0 -1
  209. package/dist/chunk-WXMGNX2Y.js.map +0 -1
  210. package/dist/chunk-XXMOARTH.js.map +0 -1
  211. package/dist/chunk-YGN7OMLT.js.map +0 -1
  212. package/dist/chunk-ZQQ6P4SV.js +0 -20
  213. package/dist/chunk-ZQQ6P4SV.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/split-view.tsx"],"names":[],"mappings":";;;;;;AA4CO,SAAS,UAAU,EAAE,EAAA,EAAI,OAAO,IAAA,EAAM,MAAA,EAAQ,UAAU,KAAA,EAAO,YAAA,GAAe,OAAO,SAAA,GAAY,EAAA,EAAI,cAAc,EAAA,EAAI,SAAA,GAAY,QAAQ,SAAA,EAAW,SAAA,GAAY,IAAG,EAAmB;AAC7L,EAAA,IAAI,OAAA,EAAS;AACX,IAAA,MAAM,KAAA,GAAQ,YAAA,GACV,CAAC,EAAE,GAAA,EAAK,MAAA,EAAQ,KAAA,EAAO,SAAA,EAAW,OAAA,EAAS,IAAA,EAAK,EAAG,EAAE,GAAA,EAAK,QAAA,EAAU,KAAA,EAAO,WAAA,EAAa,OAAA,EAAS,MAAA,EAAQ,CAAA,GACzG,CAAC,EAAE,GAAA,EAAK,MAAA,EAAQ,KAAA,EAAO,SAAA,EAAW,OAAA,EAAS,IAAA,EAAM,CAAA;AACrD,IAAA,uBAAO,GAAA,CAAC,SAAI,KAAA,EAAO,CAAA,uCAAA,EAA0C,SAAS,CAAA,CAAA,CAAG,IAAA,EAAK,EAAG,EAAA,EAAQ,gBAAA,EAAe,YAAA,EAAa,mBAAgB,SAAA,EACnI,QAAA,kBAAA,GAAA,CAAC,YAAS,EAAA,EAAI,CAAA,EAAG,EAAE,CAAA,MAAA,CAAA,EAAU,KAAA,EAAc,KAAA,EAAc,SAAA,EAAsB,CAAA,EACjF,CAAA;AAAA,EACF;AACA,EAAA,MAAM,QAAA,GAAW,SAAA,mBACb,GAAA,CAAC,eAAA,EAAA,EAAgB,IAAI,CAAA,EAAG,EAAE,CAAA,KAAA,CAAA,EAAS,KAAA,EAAO,aAAa,MAAA,EAAQ,IAAA,EAAM,SAAA,CAAU,IAAA,EAAM,KAAK,SAAA,CAAU,GAAA,EAAK,GAAA,EAAK,SAAA,CAAU,KACtH,QAAA,kBAAA,GAAA,CAAC,KAAA,EAAA,EAAI,KAAA,EAAM,+BAAA,EAAgC,mBAAe,IAAA,EAAE,QAAA,EAAA,IAAA,EAAK,CAAA,EACnE,CAAA,uBACC,KAAA,EAAA,EAAI,KAAA,EAAM,+BAAA,EAAgC,iBAAA,EAAe,MAAE,QAAA,EAAA,IAAA,EAAK,CAAA;AACrE,EAAA,uBAAO,IAAA,CAAC,KAAA,EAAA,EAAI,KAAA,EAAO,CAAA,eAAA,EAAkB,SAAS,CAAA,CAAA,CAAG,IAAA,EAAK,EAAG,EAAA,EAAQ,gBAAA,EAAe,YAAA,EAAa,iBAAA,EAAgB,OAAA,EAAQ,cAAY,KAAA,EAC9H,QAAA,EAAA;AAAA,IAAA,QAAA;AAAA,oBACD,GAAA,CAAC,SAAI,KAAA,EAAM,iCAAA,EAAkC,qBAAiB,IAAA,EAAC,YAAA,EAAY,WAAA,IAAe,MAAA,EAAY,QAAA,EAAA,MAAA,EAAO;AAAA,GAAA,EAC/G,CAAA;AACF","file":"split-view.js","sourcesContent":["import type { SafeHtml } from 'kerfjs';\n\nimport { NavStack } from './nav-stack.js';\nimport { ResizableRegion } from './resizable-region.js';\n\nexport interface SplitViewResizable {\n size: number;\n min: number;\n max: number;\n}\n\nexport interface SplitViewProps {\n id: string;\n label: string;\n /** The list (primary) pane. */\n list: SafeHtml;\n /** The detail (secondary) pane. */\n detail: SafeHtml;\n /**\n * Compact (\"one pane at a time\") classes — a handset or portrait tablet.\n * Derive from `deviceClass().value.compact`. When true the split collapses to\n * a `NavStack`: the list is the root and the detail is pushed over it.\n */\n compact?: boolean;\n /** In compact mode, whether the detail is currently pushed over the list. */\n detailActive?: boolean;\n /** Title/label for the list (compact NavStack root + region label). */\n listTitle?: string;\n /** Title/label for the detail (compact NavStack pushed view + region label). */\n detailTitle?: string;\n /** Back label for the compact NavStack (default \"Back\"). */\n backLabel?: string;\n /** A resizable separator on roomy classes (min/max px). Omit for a fixed split. */\n resizable?: SplitViewResizable;\n className?: string;\n}\n\n/**\n * A list-detail split. On roomy classes it shows both panes side\n * by side with an optional resizable separator; on compact classes it collapses\n * to a `NavStack` (list → detail). See `docs/23-app-layouts.md` §3.2. Compose the\n * resizable wiring with `wireResizableRegions` and the compact back with\n * `wireNavStack`.\n */\nexport function SplitView({ id, label, list, detail, compact = false, detailActive = false, listTitle = '', detailTitle = '', backLabel = 'Back', resizable, className = '' }: SplitViewProps) {\n if (compact) {\n const views = detailActive\n ? [{ key: 'list', title: listTitle, content: list }, { key: 'detail', title: detailTitle, content: detail }]\n : [{ key: 'list', title: listTitle, content: list }];\n return <div class={`kui-split-view kui-split-view--compact ${className}`.trim()} id={id} data-component=\"split-view\" data-split-mode=\"compact\">\n <NavStack id={`${id}-stack`} label={label} views={views} backLabel={backLabel} />\n </div>;\n }\n const listPane = resizable\n ? <ResizableRegion id={`${id}-list`} label={listTitle || 'List'} size={resizable.size} min={resizable.min} max={resizable.max}>\n <div class=\"kui-split-view__list kui-pane\" data-split-list>{list}</div>\n </ResizableRegion>\n : <div class=\"kui-split-view__list kui-pane\" data-split-list>{list}</div>;\n return <div class={`kui-split-view ${className}`.trim()} id={id} data-component=\"split-view\" data-split-mode=\"split\" aria-label={label}>\n {listPane}\n <div class=\"kui-split-view__detail kui-pane\" data-split-detail aria-label={detailTitle || undefined}>{detail}</div>\n </div>;\n}\n"]}
1
+ {"version":3,"sources":["../src/split-view.tsx"],"names":[],"mappings":";;;;;;AA4CO,SAAS,SAAA,CAAU;AAAA,EACxB,EAAA;AAAA,EACA,KAAA;AAAA,EACA,IAAA;AAAA,EACA,MAAA;AAAA,EACA,OAAA,GAAU,KAAA;AAAA,EACV,YAAA,GAAe,KAAA;AAAA,EACf,SAAA,GAAY,EAAA;AAAA,EACZ,WAAA,GAAc,EAAA;AAAA,EACd,SAAA,GAAY,MAAA;AAAA,EACZ,SAAA;AAAA,EACA,SAAA,GAAY;AACd,CAAA,EAAmB;AACjB,EAAA,IAAI,OAAA,EAAS;AACX,IAAA,MAAM,QAAQ,YAAA,GACV;AAAA,MACE,EAAE,GAAA,EAAK,MAAA,EAAQ,KAAA,EAAO,SAAA,EAAW,SAAS,IAAA,EAAK;AAAA,MAC/C,EAAE,GAAA,EAAK,QAAA,EAAU,KAAA,EAAO,WAAA,EAAa,SAAS,MAAA;AAAO,KACvD,GACA,CAAC,EAAE,GAAA,EAAK,QAAQ,KAAA,EAAO,SAAA,EAAW,OAAA,EAAS,IAAA,EAAM,CAAA;AACrD,IAAA,uBACE,GAAA;AAAA,MAAC,KAAA;AAAA,MAAA;AAAA,QACC,KAAA,EAAO,CAAA,uCAAA,EAA0C,SAAS,CAAA,CAAA,CAAG,IAAA,EAAK;AAAA,QAClE,EAAA;AAAA,QACA,gBAAA,EAAe,YAAA;AAAA,QACf,iBAAA,EAAgB,SAAA;AAAA,QAEhB,QAAA,kBAAA,GAAA;AAAA,UAAC,QAAA;AAAA,UAAA;AAAA,YACC,EAAA,EAAI,GAAG,EAAE,CAAA,MAAA,CAAA;AAAA,YACT,KAAA;AAAA,YACA,KAAA;AAAA,YACA;AAAA;AAAA;AACF;AAAA,KACF;AAAA,EAEJ;AACA,EAAA,MAAM,WAAW,SAAA,mBACf,GAAA;AAAA,IAAC,eAAA;AAAA,IAAA;AAAA,MACC,EAAA,EAAI,GAAG,EAAE,CAAA,KAAA,CAAA;AAAA,MACT,OAAO,SAAA,IAAa,MAAA;AAAA,MACpB,MAAM,SAAA,CAAU,IAAA;AAAA,MAChB,KAAK,SAAA,CAAU,GAAA;AAAA,MACf,KAAK,SAAA,CAAU,GAAA;AAAA,MAEf,8BAAC,KAAA,EAAA,EAAI,KAAA,EAAM,+BAAA,EAAgC,iBAAA,EAAe,MACvD,QAAA,EAAA,IAAA,EACH;AAAA;AAAA,sBAGF,GAAA,CAAC,KAAA,EAAA,EAAI,OAAM,+BAAA,EAAgC,iBAAA,EAAe,MACvD,QAAA,EAAA,IAAA,EACH,CAAA;AAEF,EAAA,uBACE,IAAA;AAAA,IAAC,KAAA;AAAA,IAAA;AAAA,MACC,KAAA,EAAO,CAAA,eAAA,EAAkB,SAAS,CAAA,CAAA,CAAG,IAAA,EAAK;AAAA,MAC1C,EAAA;AAAA,MACA,gBAAA,EAAe,YAAA;AAAA,MACf,iBAAA,EAAgB,OAAA;AAAA,MAChB,YAAA,EAAY,KAAA;AAAA,MAEX,QAAA,EAAA;AAAA,QAAA,QAAA;AAAA,wBACD,GAAA;AAAA,UAAC,KAAA;AAAA,UAAA;AAAA,YACC,KAAA,EAAM,iCAAA;AAAA,YACN,mBAAA,EAAiB,IAAA;AAAA,YACjB,cAAY,WAAA,IAAe,MAAA;AAAA,YAE1B,QAAA,EAAA;AAAA;AAAA;AACH;AAAA;AAAA,GACF;AAEJ","file":"split-view.js","sourcesContent":["import type { SafeHtml } from 'kerfjs';\n\nimport { NavStack } from './nav-stack.js';\nimport { ResizableRegion } from './resizable-region.js';\n\nexport interface SplitViewResizable {\n size: number;\n min: number;\n max: number;\n}\n\nexport interface SplitViewProps {\n id: string;\n label: string;\n /** The list (primary) pane. */\n list: SafeHtml;\n /** The detail (secondary) pane. */\n detail: SafeHtml;\n /**\n * Compact (\"one pane at a time\") classes — a handset or portrait tablet.\n * Derive from `deviceClass().value.compact`. When true the split collapses to\n * a `NavStack`: the list is the root and the detail is pushed over it.\n */\n compact?: boolean;\n /** In compact mode, whether the detail is currently pushed over the list. */\n detailActive?: boolean;\n /** Title/label for the list (compact NavStack root + region label). */\n listTitle?: string;\n /** Title/label for the detail (compact NavStack pushed view + region label). */\n detailTitle?: string;\n /** Back label for the compact NavStack (default \"Back\"). */\n backLabel?: string;\n /** A resizable separator on roomy classes (min/max px). Omit for a fixed split. */\n resizable?: SplitViewResizable;\n className?: string;\n}\n\n/**\n * A list-detail split. On roomy classes it shows both panes side\n * by side with an optional resizable separator; on compact classes it collapses\n * to a `NavStack` (list → detail). See `docs/23-app-layouts.md` §3.2. Compose the\n * resizable wiring with `wireResizableRegions` and the compact back with\n * `wireNavStack`.\n */\nexport function SplitView({\n id,\n label,\n list,\n detail,\n compact = false,\n detailActive = false,\n listTitle = '',\n detailTitle = '',\n backLabel = 'Back',\n resizable,\n className = '',\n}: SplitViewProps) {\n if (compact) {\n const views = detailActive\n ? [\n { key: 'list', title: listTitle, content: list },\n { key: 'detail', title: detailTitle, content: detail },\n ]\n : [{ key: 'list', title: listTitle, content: list }];\n return (\n <div\n class={`kui-split-view kui-split-view--compact ${className}`.trim()}\n id={id}\n data-component=\"split-view\"\n data-split-mode=\"compact\"\n >\n <NavStack\n id={`${id}-stack`}\n label={label}\n views={views}\n backLabel={backLabel}\n />\n </div>\n );\n }\n const listPane = resizable ? (\n <ResizableRegion\n id={`${id}-list`}\n label={listTitle || 'List'}\n size={resizable.size}\n min={resizable.min}\n max={resizable.max}\n >\n <div class=\"kui-split-view__list kui-pane\" data-split-list>\n {list}\n </div>\n </ResizableRegion>\n ) : (\n <div class=\"kui-split-view__list kui-pane\" data-split-list>\n {list}\n </div>\n );\n return (\n <div\n class={`kui-split-view ${className}`.trim()}\n id={id}\n data-component=\"split-view\"\n data-split-mode=\"split\"\n aria-label={label}\n >\n {listPane}\n <div\n class=\"kui-split-view__detail kui-pane\"\n data-split-detail\n aria-label={detailTitle || undefined}\n >\n {detail}\n </div>\n </div>\n );\n}\n"]}
@@ -12,6 +12,6 @@ interface StateBannerProps {
12
12
  /** Render the title and detail as unanimated loading skeletons, keeping the icon and tone. */
13
13
  placeholder?: boolean;
14
14
  }
15
- declare function StateBanner({ title, detail, icon, action, tone, urgency, className, placeholder }: StateBannerProps): SafeHtml;
15
+ declare function StateBanner({ title, detail, icon, action, tone, urgency, className, placeholder, }: StateBannerProps): SafeHtml;
16
16
 
17
17
  export { StateBanner, type StateBannerProps, type StateBannerTone };
@@ -1,4 +1,4 @@
1
- export { StateBanner } from './chunk-I7INRJO4.js';
1
+ export { StateBanner } from './chunk-6ETZKKAE.js';
2
2
 
3
3
 
4
4
  //# sourceMappingURL=state-banner.js.map
@@ -325,6 +325,32 @@
325
325
  place-items: center;
326
326
  }
327
327
 
328
+ /* Optional devtools-style geometry overlay. `wireCatalogGeometryOverlay` draws
329
+ a quiet dashed outer bound for transparent specimens and orange bands for
330
+ non-zero margins. */
331
+ .kui-catalog__geometry-overlay {
332
+ position: absolute;
333
+ z-index: 3;
334
+ pointer-events: none;
335
+ inset: 0;
336
+ }
337
+
338
+ .kui-catalog__geometry-bound,
339
+ .kui-catalog__geometry-margin {
340
+ position: absolute;
341
+ top: 0;
342
+ left: 0;
343
+ box-sizing: border-box;
344
+ }
345
+
346
+ .kui-catalog__geometry-bound {
347
+ border: 1px dashed color-mix(in srgb, var(--kui-color-text) 40%, transparent);
348
+ }
349
+
350
+ .kui-catalog__geometry-margin {
351
+ background: color-mix(in srgb, #f6a94c 55%, transparent);
352
+ }
353
+
328
354
  .kui-catalog__footer {
329
355
  --kui-toolbar-gap: 0.25rem;
330
356
  --kui-toolbar-group-size: 2rem;
package/dist/tab-bar.d.ts CHANGED
@@ -16,6 +16,6 @@ interface TabBarProps {
16
16
  activation?: 'automatic' | 'manual';
17
17
  }
18
18
  /** Render a controlled tab strip. The application owns selection, order, and persistence. */
19
- declare function TabBar({ id, label, children, leading, trailing, className, activation }: TabBarProps): SafeHtml;
19
+ declare function TabBar({ id, label, children, leading, trailing, className, activation, }: TabBarProps): SafeHtml;
20
20
 
21
21
  export { TabBar, type TabBarProps };
package/dist/tab-bar.js CHANGED
@@ -1,3 +1,3 @@
1
- export { TabBar } from './chunk-AVZHJN6C.js';
1
+ export { TabBar } from './chunk-ZVI5YST2.js';
2
2
 
3
3
  //# sourceMappingURL=tab-bar.js.map
@@ -25,6 +25,6 @@ interface TabScaffoldProps {
25
25
  * On larger classes, promote the tabs to a `Workbench` rail or sidebar instead of
26
26
  * a bottom bar. See `docs/23-app-layouts.md` §3.4.
27
27
  */
28
- declare function TabScaffold({ id, label, tabs, active, className }: TabScaffoldProps): SafeHtml;
28
+ declare function TabScaffold({ id, label, tabs, active, className, }: TabScaffoldProps): SafeHtml;
29
29
 
30
30
  export { TabScaffold, type TabScaffoldProps, type TabScaffoldTab };
@@ -1,14 +1,49 @@
1
1
  import { jsxs, jsx } from 'kerfjs/jsx-runtime';
2
2
 
3
3
  // src/tab-scaffold.tsx
4
- function TabScaffold({ id, label, tabs, active, className = "" }) {
5
- return /* @__PURE__ */ jsxs("section", { class: `kui-tab-scaffold ${className}`.trim(), id, "data-component": "tab-scaffold", "data-tab-scaffold-id": id, children: [
6
- /* @__PURE__ */ jsx("div", { class: "kui-tab-scaffold__scenes", children: tabs.map((tab) => /* @__PURE__ */ jsx("div", { class: "kui-tab-scaffold__scene", "data-tab-scaffold-scene": tab.id, "data-active": String(tab.id === active), "aria-hidden": String(tab.id !== active), children: tab.content })) }),
7
- /* @__PURE__ */ jsx("nav", { class: "kui-tab-scaffold__bar", role: "tablist", "aria-label": label, children: tabs.map((tab) => /* @__PURE__ */ jsxs("button", { type: "button", class: "kui-tab-scaffold__tab", role: "tab", "data-tab-scaffold-tab": tab.id, "aria-selected": String(tab.id === active), tabindex: tab.id === active ? "0" : "-1", children: [
8
- tab.icon && /* @__PURE__ */ jsx("span", { class: "kui-tab-scaffold__tab-icon", "aria-hidden": "true", children: tab.icon }),
9
- /* @__PURE__ */ jsx("span", { class: "kui-tab-scaffold__tab-label", children: tab.label })
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 };
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/tab-scaffold.tsx"],"names":[],"mappings":";;;AA6BO,SAAS,WAAA,CAAY,EAAE,EAAA,EAAI,KAAA,EAAO,MAAM,MAAA,EAAQ,SAAA,GAAY,IAAG,EAAqB;AACzF,EAAA,uBAAO,IAAA,CAAC,SAAA,EAAA,EAAQ,KAAA,EAAO,CAAA,iBAAA,EAAoB,SAAS,CAAA,CAAA,CAAG,IAAA,EAAK,EAAG,EAAA,EAAQ,gBAAA,EAAe,cAAA,EAAe,sBAAA,EAAsB,EAAA,EACzH,QAAA,EAAA;AAAA,oBAAA,GAAA,CAAC,KAAA,EAAA,EAAI,KAAA,EAAM,0BAAA,EACR,QAAA,EAAA,IAAA,CAAK,GAAA,CAAI,CAAC,GAAA,qBAAQ,GAAA,CAAC,KAAA,EAAA,EAAI,KAAA,EAAM,yBAAA,EAA0B,yBAAA,EAAyB,GAAA,CAAI,EAAA,EAAI,aAAA,EAAa,MAAA,CAAO,GAAA,CAAI,EAAA,KAAO,MAAM,CAAA,EAAG,aAAA,EAAa,MAAA,CAAO,GAAA,CAAI,EAAA,KAAO,MAAM,CAAA,EAAI,QAAA,EAAA,GAAA,CAAI,OAAA,EAAQ,CAAM,CAAA,EAC9L,CAAA;AAAA,oBACA,GAAA,CAAC,KAAA,EAAA,EAAI,KAAA,EAAM,uBAAA,EAAwB,MAAK,SAAA,EAAU,YAAA,EAAY,KAAA,EAC3D,QAAA,EAAA,IAAA,CAAK,IAAI,CAAC,GAAA,qBAAQ,IAAA,CAAC,QAAA,EAAA,EAAO,MAAK,QAAA,EAAS,KAAA,EAAM,uBAAA,EAAwB,IAAA,EAAK,KAAA,EAAM,uBAAA,EAAuB,GAAA,CAAI,EAAA,EAAI,iBAAe,MAAA,CAAO,GAAA,CAAI,EAAA,KAAO,MAAM,GAAG,QAAA,EAAU,GAAA,CAAI,EAAA,KAAO,MAAA,GAAS,MAAM,IAAA,EAC5L,QAAA,EAAA;AAAA,MAAA,GAAA,CAAI,IAAA,wBAAS,MAAA,EAAA,EAAK,KAAA,EAAM,8BAA6B,aAAA,EAAY,MAAA,EAAQ,cAAI,IAAA,EAAK,CAAA;AAAA,sBACnF,GAAA,CAAC,MAAA,EAAA,EAAK,KAAA,EAAM,6BAAA,EAA+B,cAAI,KAAA,EAAM;AAAA,KAAA,EACvD,CAAS,CAAA,EACX;AAAA,GAAA,EACF,CAAA;AACF","file":"tab-scaffold.js","sourcesContent":["import type { SafeHtml } from 'kerfjs';\n\nexport interface TabScaffoldTab {\n id: string;\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 {\n id: string;\n /** Accessible name for the tab bar. */\n label: string;\n tabs: TabScaffoldTab[];\n /** The controlled active tab id (the app owns selection). */\n active: string;\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, label, tabs, active, className = '' }: TabScaffoldProps) {\n return <section class={`kui-tab-scaffold ${className}`.trim()} id={id} data-component=\"tab-scaffold\" data-tab-scaffold-id={id}>\n <div class=\"kui-tab-scaffold__scenes\">\n {tabs.map((tab) => <div class=\"kui-tab-scaffold__scene\" data-tab-scaffold-scene={tab.id} data-active={String(tab.id === active)} aria-hidden={String(tab.id !== active)}>{tab.content}</div>)}\n </div>\n <nav class=\"kui-tab-scaffold__bar\" role=\"tablist\" aria-label={label}>\n {tabs.map((tab) => <button type=\"button\" class=\"kui-tab-scaffold__tab\" role=\"tab\" data-tab-scaffold-tab={tab.id} aria-selected={String(tab.id === active)} tabindex={tab.id === active ? '0' : '-1'}>\n {tab.icon && <span class=\"kui-tab-scaffold__tab-icon\" aria-hidden=\"true\">{tab.icon}</span>}\n <span class=\"kui-tab-scaffold__tab-label\">{tab.label}</span>\n </button>)}\n </nav>\n </section>;\n}\n"]}
1
+ {"version":3,"sources":["../src/tab-scaffold.tsx"],"names":[],"mappings":";;;AA6BO,SAAS,WAAA,CAAY;AAAA,EAC1B,EAAA;AAAA,EACA,KAAA;AAAA,EACA,IAAA;AAAA,EACA,MAAA;AAAA,EACA,SAAA,GAAY;AACd,CAAA,EAAqB;AACnB,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 {\n id: string;\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 {\n id: string;\n /** Accessible name for the tab bar. */\n label: string;\n tabs: TabScaffoldTab[];\n /** The controlled active tab id (the app owns selection). */\n active: string;\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({\n id,\n label,\n tabs,\n active,\n className = '',\n}: TabScaffoldProps) {\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"]}
@@ -1,4 +1,4 @@
1
- export { TokenSearchField, placeTokenSearchCaret, readTokenSearchField } from './chunk-7LDCTU7D.js';
1
+ export { TokenSearchField, placeTokenSearchCaret, readTokenSearchField } from './chunk-S3HKPI7I.js';
2
2
 
3
3
 
4
4
  //# sourceMappingURL=token-search-field.js.map
@@ -12,6 +12,6 @@ interface ToolbarControlGroupProps {
12
12
  /** Corner shape: fully round `pill` (default) or a softer `rounded` rectangle. */
13
13
  shape?: 'pill' | 'rounded';
14
14
  }
15
- declare function ToolbarControlGroup({ children, label, className, expanded, single, appearance, tone, buttonAppearance, shape }: ToolbarControlGroupProps): SafeHtml;
15
+ declare function ToolbarControlGroup({ children, label, className, expanded, single, appearance, tone, buttonAppearance, shape, }: ToolbarControlGroupProps): SafeHtml;
16
16
 
17
17
  export { ToolbarControlGroup, type ToolbarControlGroupProps };
@@ -1,3 +1,3 @@
1
- export { ToolbarControlGroup } from './chunk-RNPGFQ33.js';
1
+ export { ToolbarControlGroup } from './chunk-ZK2G3VR5.js';
2
2
 
3
3
  //# sourceMappingURL=toolbar-control-group.js.map
@@ -1,4 +1,4 @@
1
- export { ToolbarText } from './chunk-WXMGNX2Y.js';
1
+ export { ToolbarText } from './chunk-S3PCZ7NV.js';
2
2
 
3
3
 
4
4
  //# sourceMappingURL=toolbar-text.js.map
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
@@ -1,3 +1,3 @@
1
- export { Toolbar } from './chunk-DAFFDO33.js';
1
+ export { Toolbar } from './chunk-7L6EHUMV.js';
2
2
 
3
3
  //# sourceMappingURL=toolbar.js.map
@@ -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 };
@@ -1,4 +1,4 @@
1
- export { ValueTable, ValueTableRow } from './chunk-37T3VNIZ.js';
1
+ export { ValueTable, ValueTableRow } from './chunk-QQFJMRIB.js';
2
2
 
3
3
 
4
4
  //# sourceMappingURL=value-table.js.map
@@ -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 };
@@ -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(root, "click", `[data-action="${selectAction}"]`, (_event, element) => {
28
- const id = element.dataset.itemId;
29
- if (id) select(id);
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(delegate(root, "click", `[data-action="${toggleSidebarAction}"]`, () => onToggleSidebar()));
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(delegate(root, "click", `[data-action="${toggleThemeAction}"]`, () => onToggleTheme()));
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(delegate(root, "click", `[data-action="${toggleSecondaryAction}"]`, () => onToggleSecondary()));
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
@@ -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"]}