@bettercms-ai/kit 1.0.0 → 2.0.0

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 (587) hide show
  1. package/README.md +33 -0
  2. package/dist/adapters/dock-values.d.ts +28 -0
  3. package/dist/adapters/dock-values.js +41 -0
  4. package/dist/adapters/dock-values.js.map +1 -0
  5. package/{adapters → dist/adapters}/icons.js +2 -2
  6. package/dist/adapters/icons.js.map +1 -0
  7. package/{adapters → dist/adapters}/lossy.d.ts +90 -31
  8. package/dist/adapters/lossy.js +414 -0
  9. package/dist/adapters/lossy.js.map +1 -0
  10. package/{adapters → dist/adapters}/prod-types.d.ts +82 -4
  11. package/{adapters → dist/adapters}/prod-types.js +71 -3
  12. package/dist/adapters/prod-types.js.map +1 -0
  13. package/{adapters → dist/adapters}/schema.d.ts +40 -1
  14. package/{adapters → dist/adapters}/schema.js +996 -179
  15. package/dist/adapters/schema.js.map +1 -0
  16. package/{adapters → dist/adapters}/values.d.ts +26 -5
  17. package/{adapters → dist/adapters}/values.js +87 -17
  18. package/dist/adapters/values.js.map +1 -0
  19. package/dist/brand/logo.js +96 -0
  20. package/dist/brand/logo.js.map +1 -0
  21. package/{context.d.ts → dist/context.d.ts} +92 -2
  22. package/{context.js → dist/context.js} +5 -2
  23. package/dist/context.js.map +1 -0
  24. package/{controls → dist/controls}/button.d.ts +19 -5
  25. package/{controls → dist/controls}/button.js +125 -54
  26. package/dist/controls/button.js.map +1 -0
  27. package/{controls → dist/controls}/c1.js +1 -1
  28. package/dist/controls/c1.js.map +1 -0
  29. package/{controls → dist/controls}/c2.js +1 -1
  30. package/dist/controls/c2.js.map +1 -0
  31. package/{controls → dist/controls}/choice.d.ts +7 -2
  32. package/{controls → dist/controls}/choice.js +71 -18
  33. package/dist/controls/choice.js.map +1 -0
  34. package/{controls → dist/controls}/code-register.js +1 -1
  35. package/dist/controls/code-register.js.map +1 -0
  36. package/{controls → dist/controls}/code.js +10 -9
  37. package/dist/controls/code.js.map +1 -0
  38. package/{controls → dist/controls}/color.js +8 -8
  39. package/dist/controls/color.js.map +1 -0
  40. package/{controls → dist/controls}/component-services.d.ts +42 -0
  41. package/dist/controls/component-services.js +7 -0
  42. package/dist/controls/component-services.js.map +1 -0
  43. package/{controls → dist/controls}/date-register.js +1 -1
  44. package/dist/controls/date-register.js.map +1 -0
  45. package/{controls → dist/controls}/date-zone.js +8 -2
  46. package/dist/controls/date-zone.js.map +1 -0
  47. package/{controls → dist/controls}/date.js +32 -24
  48. package/dist/controls/date.js.map +1 -0
  49. package/{controls → dist/controls}/form-picker-register.js +1 -1
  50. package/dist/controls/form-picker-register.js.map +1 -0
  51. package/{controls → dist/controls}/form-picker.js +11 -9
  52. package/dist/controls/form-picker.js.map +1 -0
  53. package/{controls → dist/controls}/icon-register.js +1 -1
  54. package/dist/controls/icon-register.js.map +1 -0
  55. package/{controls → dist/controls}/icon.d.ts +4 -2
  56. package/{controls → dist/controls}/icon.js +32 -27
  57. package/dist/controls/icon.js.map +1 -0
  58. package/{controls → dist/controls}/index.d.ts +1 -1
  59. package/{controls → dist/controls}/index.js +4 -3
  60. package/dist/controls/index.js.map +1 -0
  61. package/{controls → dist/controls}/json-register.js +1 -1
  62. package/dist/controls/json-register.js.map +1 -0
  63. package/{controls → dist/controls}/json.js +13 -3
  64. package/dist/controls/json.js.map +1 -0
  65. package/{controls → dist/controls}/link.js +6 -6
  66. package/dist/controls/link.js.map +1 -0
  67. package/{controls → dist/controls}/location-register.js +1 -1
  68. package/dist/controls/location-register.js.map +1 -0
  69. package/{controls → dist/controls}/location.js +64 -40
  70. package/dist/controls/location.js.map +1 -0
  71. package/{controls → dist/controls}/media-register.js +1 -1
  72. package/dist/controls/media-register.js.map +1 -0
  73. package/{controls → dist/controls}/media-services.d.ts +6 -0
  74. package/dist/controls/media-services.js +0 -0
  75. package/{controls → dist/controls}/media.d.ts +35 -4
  76. package/{controls → dist/controls}/media.js +491 -171
  77. package/dist/controls/media.js.map +1 -0
  78. package/{controls → dist/controls}/number.js +10 -9
  79. package/dist/controls/number.js.map +1 -0
  80. package/{controls → dist/controls}/reference-register.js +1 -1
  81. package/dist/controls/reference-register.js.map +1 -0
  82. package/{controls → dist/controls}/reference-services.d.ts +4 -0
  83. package/dist/controls/reference-services.js +0 -0
  84. package/{controls → dist/controls}/reference.d.ts +1 -1
  85. package/{controls → dist/controls}/reference.js +93 -77
  86. package/dist/controls/reference.js.map +1 -0
  87. package/dist/controls/rich-text/blocks.d.ts +49 -0
  88. package/{controls → dist/controls}/rich-text/blocks.js +471 -144
  89. package/dist/controls/rich-text/blocks.js.map +1 -0
  90. package/{controls → dist/controls}/rich-text/catalog.d.ts +4 -1
  91. package/{controls → dist/controls}/rich-text/catalog.js +75 -65
  92. package/dist/controls/rich-text/catalog.js.map +1 -0
  93. package/{controls → dist/controls}/rich-text/codec.d.ts +9 -1
  94. package/{controls → dist/controls}/rich-text/codec.js +3 -1
  95. package/dist/controls/rich-text/codec.js.map +1 -0
  96. package/{controls → dist/controls}/rich-text/component-card.d.ts +1 -1
  97. package/{controls → dist/controls}/rich-text/component-card.js +417 -99
  98. package/dist/controls/rich-text/component-card.js.map +1 -0
  99. package/dist/controls/rich-text/component-panel.d.ts +47 -0
  100. package/dist/controls/rich-text/component-panel.js +141 -0
  101. package/dist/controls/rich-text/component-panel.js.map +1 -0
  102. package/{controls → dist/controls}/rich-text/control.d.ts +1 -2
  103. package/{controls → dist/controls}/rich-text/control.js +84 -42
  104. package/dist/controls/rich-text/control.js.map +1 -0
  105. package/{controls → dist/controls}/rich-text/dom.d.ts +52 -9
  106. package/{controls → dist/controls}/rich-text/dom.js +379 -50
  107. package/dist/controls/rich-text/dom.js.map +1 -0
  108. package/{controls → dist/controls}/rich-text/editor.d.ts +7 -0
  109. package/{controls → dist/controls}/rich-text/editor.js +148 -48
  110. package/dist/controls/rich-text/editor.js.map +1 -0
  111. package/{controls → dist/controls}/rich-text/floating.d.ts +6 -1
  112. package/{controls → dist/controls}/rich-text/floating.js +35 -18
  113. package/dist/controls/rich-text/floating.js.map +1 -0
  114. package/{controls → dist/controls}/rich-text/index.js +1 -1
  115. package/dist/controls/rich-text/index.js.map +1 -0
  116. package/dist/controls/rich-text/link-form.js +147 -0
  117. package/dist/controls/rich-text/link-form.js.map +1 -0
  118. package/{controls → dist/controls}/rich-text/markdown.js +4 -2
  119. package/dist/controls/rich-text/markdown.js.map +1 -0
  120. package/{controls → dist/controls}/rich-text/ops.js +17 -15
  121. package/dist/controls/rich-text/ops.js.map +1 -0
  122. package/dist/controls/rich-text/plain.d.ts +17 -0
  123. package/dist/controls/rich-text/plain.js +44 -0
  124. package/dist/controls/rich-text/plain.js.map +1 -0
  125. package/{controls → dist/controls}/rich-text/toolbar.d.ts +6 -2
  126. package/{controls → dist/controls}/rich-text/toolbar.js +12 -7
  127. package/dist/controls/rich-text/toolbar.js.map +1 -0
  128. package/{controls → dist/controls}/scale.js +5 -5
  129. package/dist/controls/scale.js.map +1 -0
  130. package/{controls → dist/controls}/slot-register.js +1 -1
  131. package/dist/controls/slot-register.js.map +1 -0
  132. package/{controls → dist/controls}/slot-services.d.ts +25 -0
  133. package/dist/controls/slot-services.js +155 -0
  134. package/dist/controls/slot-services.js.map +1 -0
  135. package/{controls → dist/controls}/slot.js +42 -24
  136. package/dist/controls/slot.js.map +1 -0
  137. package/{controls → dist/controls}/table/index.js +1 -1
  138. package/dist/controls/table/index.js.map +1 -0
  139. package/{controls → dist/controls}/table/prod.js +3 -3
  140. package/dist/controls/table/prod.js.map +1 -0
  141. package/{controls → dist/controls}/table/refs.js +13 -2
  142. package/dist/controls/table/refs.js.map +1 -0
  143. package/{controls → dist/controls}/table/stored.js +1 -1
  144. package/dist/controls/table/stored.js.map +1 -0
  145. package/{controls → dist/controls}/table/table-editor.js +51 -48
  146. package/dist/controls/table/table-editor.js.map +1 -0
  147. package/{controls → dist/controls}/table/table-link.js +3 -3
  148. package/dist/controls/table/table-link.js.map +1 -0
  149. package/{controls → dist/controls}/table/table.js +3 -3
  150. package/dist/controls/table/table.js.map +1 -0
  151. package/{controls → dist/controls}/text.d.ts +2 -2
  152. package/{controls → dist/controls}/text.js +78 -43
  153. package/dist/controls/text.js.map +1 -0
  154. package/dist/controls/unknown-value.d.ts +17 -0
  155. package/dist/controls/unknown-value.js +66 -0
  156. package/dist/controls/unknown-value.js.map +1 -0
  157. package/dist/core/core.d.ts +63 -0
  158. package/dist/core/core.js +171 -0
  159. package/dist/core/core.js.map +1 -0
  160. package/dist/core/facets.d.ts +347 -0
  161. package/dist/core/facets.js +334 -0
  162. package/dist/core/facets.js.map +1 -0
  163. package/dist/core/index.d.ts +3 -0
  164. package/dist/core/index.js +3 -0
  165. package/{engine → dist/engine}/array.js +34 -21
  166. package/dist/engine/array.js.map +1 -0
  167. package/{engine → dist/engine}/bits.js +1 -1
  168. package/dist/engine/bits.js.map +1 -0
  169. package/{engine → dist/engine}/breadcrumb.d.ts +3 -3
  170. package/{engine → dist/engine}/breadcrumb.js +12 -36
  171. package/dist/engine/breadcrumb.js.map +1 -0
  172. package/{engine → dist/engine}/expand.d.ts +2 -4
  173. package/{engine → dist/engine}/expand.js +5 -22
  174. package/dist/engine/expand.js.map +1 -0
  175. package/{engine → dist/engine}/field-list.js +1 -1
  176. package/dist/engine/field-list.js.map +1 -0
  177. package/{engine → dist/engine}/field-shell.js +249 -121
  178. package/dist/engine/field-shell.js.map +1 -0
  179. package/{engine → dist/engine}/frame.d.ts +3 -1
  180. package/{engine → dist/engine}/frame.js +16 -14
  181. package/dist/engine/frame.js.map +1 -0
  182. package/{engine → dist/engine}/group-summary.d.ts +2 -1
  183. package/{engine → dist/engine}/group-summary.js +7 -3
  184. package/dist/engine/group-summary.js.map +1 -0
  185. package/{engine → dist/engine}/grouping.d.ts +19 -5
  186. package/{engine → dist/engine}/grouping.js +193 -21
  187. package/dist/engine/grouping.js.map +1 -0
  188. package/{engine → dist/engine}/item-list.d.ts +11 -1
  189. package/{engine → dist/engine}/item-list.js +35 -13
  190. package/dist/engine/item-list.js.map +1 -0
  191. package/{engine → dist/engine}/kit-field.js +45 -10
  192. package/dist/engine/kit-field.js.map +1 -0
  193. package/{engine → dist/engine}/schema-form.d.ts +27 -2
  194. package/{engine → dist/engine}/schema-form.js +182 -40
  195. package/dist/engine/schema-form.js.map +1 -0
  196. package/{engine → dist/engine}/slot.js +5 -15
  197. package/dist/engine/slot.js.map +1 -0
  198. package/dist/index.js +47 -0
  199. package/dist/index.js.map +1 -0
  200. package/{kit.css → dist/kit.css} +19 -0
  201. package/{lib → dist/lib}/cn.js +7 -4
  202. package/dist/lib/cn.js.map +1 -0
  203. package/{lib → dist/lib}/columns.js +4 -1
  204. package/dist/lib/columns.js.map +1 -0
  205. package/{lib → dist/lib}/frames.js +2 -2
  206. package/dist/lib/frames.js.map +1 -0
  207. package/dist/lib/icon-image.d.ts +10 -0
  208. package/dist/lib/icon-image.js +8 -0
  209. package/dist/lib/icon-image.js.map +1 -0
  210. package/{lib → dist/lib}/icons.js +4 -3
  211. package/dist/lib/icons.js.map +1 -0
  212. package/dist/lib/input-modality.d.ts +11 -0
  213. package/dist/lib/input-modality.js +47 -0
  214. package/dist/lib/input-modality.js.map +1 -0
  215. package/dist/lib/key-event.d.ts +11 -0
  216. package/dist/lib/key-event.js +16 -0
  217. package/dist/lib/key-event.js.map +1 -0
  218. package/{lib → dist/lib}/path.js +4 -2
  219. package/dist/lib/path.js.map +1 -0
  220. package/{lib → dist/lib}/schema.d.ts +34 -3
  221. package/{lib → dist/lib}/schema.js +110 -13
  222. package/dist/lib/schema.js.map +1 -0
  223. package/{lib → dist/lib}/utils.js +1 -1
  224. package/dist/lib/utils.js.map +1 -0
  225. package/{lib → dist/lib}/validate.d.ts +11 -1
  226. package/{lib → dist/lib}/validate.js +85 -11
  227. package/dist/lib/validate.js.map +1 -0
  228. package/dist/library/analysis.d.ts +23 -0
  229. package/dist/library/analysis.js +160 -0
  230. package/dist/library/analysis.js.map +1 -0
  231. package/dist/library/catalog.d.ts +57 -0
  232. package/dist/library/catalog.js +307 -0
  233. package/dist/library/catalog.js.map +1 -0
  234. package/dist/library/coreNotes.d.ts +8 -0
  235. package/dist/library/coreNotes.js +111 -0
  236. package/dist/library/coreNotes.js.map +1 -0
  237. package/dist/library/coverage.d.ts +40 -0
  238. package/dist/library/coverage.js +59 -0
  239. package/dist/library/coverage.js.map +1 -0
  240. package/dist/library/entries/advanced.entries.d.ts +2 -0
  241. package/dist/library/entries/advanced.entries.js +6579 -0
  242. package/dist/library/entries/advanced.entries.js.map +1 -0
  243. package/dist/library/entries/commerce.entries.d.ts +2 -0
  244. package/dist/library/entries/commerce.entries.js +4140 -0
  245. package/dist/library/entries/commerce.entries.js.map +1 -0
  246. package/dist/library/entries/company.entries.d.ts +2 -0
  247. package/dist/library/entries/company.entries.js +2731 -0
  248. package/dist/library/entries/company.entries.js.map +1 -0
  249. package/dist/library/entries/conversion.entries.d.ts +2 -0
  250. package/dist/library/entries/conversion.entries.js +3707 -0
  251. package/dist/library/entries/conversion.entries.js.map +1 -0
  252. package/dist/library/entries/data.entries.d.ts +7 -0
  253. package/dist/library/entries/data.entries.js +4613 -0
  254. package/dist/library/entries/data.entries.js.map +1 -0
  255. package/dist/library/entries/events.entries.d.ts +2 -0
  256. package/dist/library/entries/events.entries.js +3428 -0
  257. package/dist/library/entries/events.entries.js.map +1 -0
  258. package/dist/library/entries/features.entries.d.ts +2 -0
  259. package/dist/library/entries/features.entries.js +3157 -0
  260. package/dist/library/entries/features.entries.js.map +1 -0
  261. package/dist/library/entries/heroes.entries.d.ts +2 -0
  262. package/dist/library/entries/heroes.entries.js +3401 -0
  263. package/dist/library/entries/heroes.entries.js.map +1 -0
  264. package/dist/library/entries/index.d.ts +3 -0
  265. package/dist/library/entries/index.js +35 -0
  266. package/dist/library/entries/index.js.map +1 -0
  267. package/dist/library/entries/listings.entries.d.ts +2 -0
  268. package/dist/library/entries/listings.entries.js +2976 -0
  269. package/dist/library/entries/listings.entries.js.map +1 -0
  270. package/dist/library/entries/longform.entries.d.ts +2 -0
  271. package/dist/library/entries/longform.entries.js +4227 -0
  272. package/dist/library/entries/longform.entries.js.map +1 -0
  273. package/dist/library/entries/media.entries.d.ts +2 -0
  274. package/dist/library/entries/media.entries.js +2781 -0
  275. package/dist/library/entries/media.entries.js.map +1 -0
  276. package/dist/library/entries/navigation.entries.d.ts +2 -0
  277. package/dist/library/entries/navigation.entries.js +4011 -0
  278. package/dist/library/entries/navigation.entries.js.map +1 -0
  279. package/dist/library/entries/pricing.entries.d.ts +2 -0
  280. package/dist/library/entries/pricing.entries.js +2383 -0
  281. package/dist/library/entries/pricing.entries.js.map +1 -0
  282. package/dist/library/entries/social-proof.entries.d.ts +2 -0
  283. package/dist/library/entries/social-proof.entries.js +2297 -0
  284. package/dist/library/entries/social-proof.entries.js.map +1 -0
  285. package/dist/library/examples/bento.d.ts +92 -0
  286. package/dist/library/examples/bento.js +201 -0
  287. package/dist/library/examples/bento.js.map +1 -0
  288. package/dist/library/examples/blocks.d.ts +14 -0
  289. package/dist/library/examples/blocks.js +313 -0
  290. package/dist/library/examples/blocks.js.map +1 -0
  291. package/dist/library/examples/faq.d.ts +28 -0
  292. package/dist/library/examples/faq.js +230 -0
  293. package/dist/library/examples/faq.js.map +1 -0
  294. package/dist/library/examples/hero.d.ts +43 -0
  295. package/dist/library/examples/hero.js +222 -0
  296. package/dist/library/examples/hero.js.map +1 -0
  297. package/dist/library/examples/index.d.ts +36 -0
  298. package/dist/library/examples/index.js +109 -0
  299. package/dist/library/examples/index.js.map +1 -0
  300. package/dist/library/examples/journalStory.d.ts +93 -0
  301. package/dist/library/examples/journalStory.js +338 -0
  302. package/dist/library/examples/journalStory.js.map +1 -0
  303. package/dist/library/examples/megaMenu.d.ts +134 -0
  304. package/dist/library/examples/megaMenu.js +442 -0
  305. package/dist/library/examples/megaMenu.js.map +1 -0
  306. package/dist/library/examples/pricing.d.ts +103 -0
  307. package/dist/library/examples/pricing.js +479 -0
  308. package/dist/library/examples/pricing.js.map +1 -0
  309. package/dist/library/examples/tabs.d.ts +87 -0
  310. package/dist/library/examples/tabs.js +180 -0
  311. package/dist/library/examples/tabs.js.map +1 -0
  312. package/dist/library/export.d.ts +42 -0
  313. package/dist/library/export.js +80 -0
  314. package/dist/library/export.js.map +1 -0
  315. package/dist/library/index.d.ts +13 -0
  316. package/dist/library/index.js +6 -0
  317. package/dist/library/kit-catalog.json +1510 -0
  318. package/dist/library/types.d.ts +42 -0
  319. package/dist/library/types.js +0 -0
  320. package/{schema → dist/schema}/adapters.js +1 -2
  321. package/dist/schema/adapters.js.map +1 -0
  322. package/{schema → dist/schema}/help.d.ts +2 -0
  323. package/{schema → dist/schema}/help.js +6 -4
  324. package/dist/schema/help.js.map +1 -0
  325. package/{schema → dist/schema}/scale.js +1 -1
  326. package/dist/schema/scale.js.map +1 -0
  327. package/{schema → dist/schema}/sources.js +1 -1
  328. package/dist/schema/sources.js.map +1 -0
  329. package/{schema → dist/schema}/table.js +11 -10
  330. package/dist/schema/table.js.map +1 -0
  331. package/{schema → dist/schema}/types.d.ts +29 -1
  332. package/{schema → dist/schema}/types.js +1 -1
  333. package/dist/schema/types.js.map +1 -0
  334. package/dist/styles.css +2 -0
  335. package/dist/table/table-view.d.ts +14 -0
  336. package/dist/table/table-view.js +140 -0
  337. package/dist/table/table-view.js.map +1 -0
  338. package/dist/table/table.css +73 -0
  339. package/dist/testing/corpus.d.ts +63 -0
  340. package/dist/testing/corpus.js +129 -0
  341. package/dist/testing/corpus.js.map +1 -0
  342. package/dist/testing/test-form.d.ts +11 -0
  343. package/dist/testing/test-form.js +38 -0
  344. package/dist/testing/test-form.js.map +1 -0
  345. package/dist/theme.css +345 -0
  346. package/dist/theme.d.ts +22 -0
  347. package/dist/theme.js +43 -0
  348. package/dist/theme.js.map +1 -0
  349. package/dist/tokens.css +542 -0
  350. package/dist/types.js +0 -0
  351. package/{ui → dist/ui}/action-tray.d.ts +1 -1
  352. package/{ui → dist/ui}/action-tray.js +20 -19
  353. package/dist/ui/action-tray.js.map +1 -0
  354. package/dist/ui/autocomplete.d.ts +30 -0
  355. package/dist/ui/autocomplete.js +139 -0
  356. package/dist/ui/autocomplete.js.map +1 -0
  357. package/{ui → dist/ui}/button.d.ts +3 -3
  358. package/{ui → dist/ui}/button.js +6 -7
  359. package/dist/ui/button.js.map +1 -0
  360. package/{ui → dist/ui}/choice-switch.js +1 -1
  361. package/dist/ui/choice-switch.js.map +1 -0
  362. package/{ui → dist/ui}/controls.js +51 -39
  363. package/dist/ui/controls.js.map +1 -0
  364. package/{ui → dist/ui}/display.d.ts +10 -3
  365. package/{ui → dist/ui}/display.js +57 -46
  366. package/dist/ui/display.js.map +1 -0
  367. package/{ui → dist/ui}/expanded-editor-modal.d.ts +2 -2
  368. package/{ui → dist/ui}/expanded-editor-modal.js +6 -6
  369. package/dist/ui/expanded-editor-modal.js.map +1 -0
  370. package/{ui → dist/ui}/field-context.js +1 -1
  371. package/dist/ui/field-context.js.map +1 -0
  372. package/{ui → dist/ui}/floating-panel.d.ts +1 -1
  373. package/{ui → dist/ui}/floating-panel.js +28 -12
  374. package/dist/ui/floating-panel.js.map +1 -0
  375. package/{ui → dist/ui}/index.d.ts +4 -0
  376. package/dist/ui/index.js +18 -0
  377. package/{ui → dist/ui}/input.d.ts +1 -1
  378. package/{ui → dist/ui}/input.js +9 -9
  379. package/dist/ui/input.js.map +1 -0
  380. package/{ui → dist/ui}/mode-bar.js +3 -3
  381. package/dist/ui/mode-bar.js.map +1 -0
  382. package/{ui → dist/ui}/overlay.d.ts +77 -5
  383. package/dist/ui/overlay.js +697 -0
  384. package/dist/ui/overlay.js.map +1 -0
  385. package/{ui → dist/ui}/path-crumbs.js +37 -3
  386. package/dist/ui/path-crumbs.js.map +1 -0
  387. package/{ui → dist/ui}/presence.js +2 -2
  388. package/dist/ui/presence.js.map +1 -0
  389. package/{ui → dist/ui}/select.js +89 -87
  390. package/dist/ui/select.js.map +1 -0
  391. package/{ui → dist/ui}/shortcut-hint.js +1 -1
  392. package/dist/ui/shortcut-hint.js.map +1 -0
  393. package/dist/ui/spinner.d.ts +24 -0
  394. package/dist/ui/spinner.js +42 -0
  395. package/dist/ui/spinner.js.map +1 -0
  396. package/dist/ui/split-button.d.ts +32 -0
  397. package/dist/ui/split-button.js +60 -0
  398. package/dist/ui/split-button.js.map +1 -0
  399. package/{ui → dist/ui}/surfaces.js +1 -1
  400. package/dist/ui/surfaces.js.map +1 -0
  401. package/dist/ui/tab.d.ts +38 -0
  402. package/dist/ui/tab.js +87 -0
  403. package/dist/ui/tab.js.map +1 -0
  404. package/dist/ui/toast.d.ts +20 -0
  405. package/dist/ui/toast.js +115 -0
  406. package/dist/ui/toast.js.map +1 -0
  407. package/{ui → dist/ui}/tooltip-root.d.ts +4 -3
  408. package/{ui → dist/ui}/tooltip-root.js +9 -8
  409. package/dist/ui/tooltip-root.js.map +1 -0
  410. package/{ui → dist/ui}/variants.js +1 -1
  411. package/dist/ui/variants.js.map +1 -0
  412. package/package.json +77 -23
  413. package/adapters/icons.js.map +0 -1
  414. package/adapters/lossy.js +0 -233
  415. package/adapters/lossy.js.map +0 -1
  416. package/adapters/prod-types.js.map +0 -1
  417. package/adapters/schema.js.map +0 -1
  418. package/adapters/values.js.map +0 -1
  419. package/brand/logo.js +0 -9
  420. package/brand/logo.js.map +0 -1
  421. package/context.js.map +0 -1
  422. package/controls/button.js.map +0 -1
  423. package/controls/c1.js.map +0 -1
  424. package/controls/c2.js.map +0 -1
  425. package/controls/choice.js.map +0 -1
  426. package/controls/code-register.js.map +0 -1
  427. package/controls/code.js.map +0 -1
  428. package/controls/color.js.map +0 -1
  429. package/controls/date-register.js.map +0 -1
  430. package/controls/date-zone.js.map +0 -1
  431. package/controls/date.js.map +0 -1
  432. package/controls/form-picker-register.js.map +0 -1
  433. package/controls/form-picker.js.map +0 -1
  434. package/controls/icon-register.js.map +0 -1
  435. package/controls/icon.js.map +0 -1
  436. package/controls/index.js.map +0 -1
  437. package/controls/json-register.js.map +0 -1
  438. package/controls/json.js.map +0 -1
  439. package/controls/link.js.map +0 -1
  440. package/controls/location-register.js.map +0 -1
  441. package/controls/location.js.map +0 -1
  442. package/controls/media-register.js.map +0 -1
  443. package/controls/media.js.map +0 -1
  444. package/controls/number.js.map +0 -1
  445. package/controls/reference-register.js.map +0 -1
  446. package/controls/reference.js.map +0 -1
  447. package/controls/rich-text/blocks.d.ts +0 -28
  448. package/controls/rich-text/blocks.js.map +0 -1
  449. package/controls/rich-text/catalog.js.map +0 -1
  450. package/controls/rich-text/codec.js.map +0 -1
  451. package/controls/rich-text/component-card.js.map +0 -1
  452. package/controls/rich-text/control.js.map +0 -1
  453. package/controls/rich-text/dom.js.map +0 -1
  454. package/controls/rich-text/editor.js.map +0 -1
  455. package/controls/rich-text/floating.js.map +0 -1
  456. package/controls/rich-text/index.js.map +0 -1
  457. package/controls/rich-text/link-form.js +0 -111
  458. package/controls/rich-text/link-form.js.map +0 -1
  459. package/controls/rich-text/markdown.js.map +0 -1
  460. package/controls/rich-text/ops.js.map +0 -1
  461. package/controls/rich-text/toolbar.js.map +0 -1
  462. package/controls/scale.js.map +0 -1
  463. package/controls/slot-register.js.map +0 -1
  464. package/controls/slot-services.js +0 -38
  465. package/controls/slot-services.js.map +0 -1
  466. package/controls/slot.js.map +0 -1
  467. package/controls/table/index.js.map +0 -1
  468. package/controls/table/prod.js.map +0 -1
  469. package/controls/table/refs.js.map +0 -1
  470. package/controls/table/stored.js.map +0 -1
  471. package/controls/table/table-editor.js.map +0 -1
  472. package/controls/table/table-link.js.map +0 -1
  473. package/controls/table/table.js.map +0 -1
  474. package/controls/text.js.map +0 -1
  475. package/engine/array.js.map +0 -1
  476. package/engine/bits.js.map +0 -1
  477. package/engine/breadcrumb.js.map +0 -1
  478. package/engine/expand.js.map +0 -1
  479. package/engine/field-list.js.map +0 -1
  480. package/engine/field-shell.js.map +0 -1
  481. package/engine/frame.js.map +0 -1
  482. package/engine/group-summary.js.map +0 -1
  483. package/engine/grouping.js.map +0 -1
  484. package/engine/item-list.js.map +0 -1
  485. package/engine/kit-field.js.map +0 -1
  486. package/engine/schema-form.js.map +0 -1
  487. package/engine/slot.js.map +0 -1
  488. package/index.js +0 -55
  489. package/index.js.map +0 -1
  490. package/lib/cn.js.map +0 -1
  491. package/lib/columns.js.map +0 -1
  492. package/lib/frames.js.map +0 -1
  493. package/lib/icons.js.map +0 -1
  494. package/lib/path.js.map +0 -1
  495. package/lib/schema.js.map +0 -1
  496. package/lib/utils.js.map +0 -1
  497. package/lib/validate.js.map +0 -1
  498. package/schema/adapters.js.map +0 -1
  499. package/schema/help.js.map +0 -1
  500. package/schema/scale.js.map +0 -1
  501. package/schema/sources.js.map +0 -1
  502. package/schema/table.js.map +0 -1
  503. package/schema/types.js.map +0 -1
  504. package/ui/action-tray.js.map +0 -1
  505. package/ui/button.js.map +0 -1
  506. package/ui/choice-switch.js.map +0 -1
  507. package/ui/controls.js.map +0 -1
  508. package/ui/display.js.map +0 -1
  509. package/ui/expanded-editor-modal.js.map +0 -1
  510. package/ui/field-context.js.map +0 -1
  511. package/ui/floating-panel.js.map +0 -1
  512. package/ui/index.js +0 -13
  513. package/ui/input.js.map +0 -1
  514. package/ui/mode-bar.js.map +0 -1
  515. package/ui/overlay.js +0 -378
  516. package/ui/overlay.js.map +0 -1
  517. package/ui/path-crumbs.js.map +0 -1
  518. package/ui/presence.js.map +0 -1
  519. package/ui/select.js.map +0 -1
  520. package/ui/shortcut-hint.js.map +0 -1
  521. package/ui/surfaces.js.map +0 -1
  522. package/ui/tooltip-root.js.map +0 -1
  523. package/ui/variants.js.map +0 -1
  524. /package/{_virtual → dist/_virtual}/_rolldown/runtime.js +0 -0
  525. /package/{adapters → dist/adapters}/icons.d.ts +0 -0
  526. /package/{brand → dist/brand}/logo.d.ts +0 -0
  527. /package/{controls → dist/controls}/c1.d.ts +0 -0
  528. /package/{controls → dist/controls}/c2.d.ts +0 -0
  529. /package/{controls → dist/controls}/code-register.d.ts +0 -0
  530. /package/{controls → dist/controls}/code.d.ts +0 -0
  531. /package/{controls → dist/controls}/color.d.ts +0 -0
  532. /package/{controls → dist/controls}/date-register.d.ts +0 -0
  533. /package/{controls → dist/controls}/date-zone.d.ts +0 -0
  534. /package/{controls → dist/controls}/date.d.ts +0 -0
  535. /package/{controls → dist/controls}/form-picker-register.d.ts +0 -0
  536. /package/{controls → dist/controls}/form-picker.d.ts +0 -0
  537. /package/{controls → dist/controls}/icon-register.d.ts +0 -0
  538. /package/{controls → dist/controls}/json-register.d.ts +0 -0
  539. /package/{controls → dist/controls}/json.d.ts +0 -0
  540. /package/{controls → dist/controls}/link.d.ts +0 -0
  541. /package/{controls → dist/controls}/location-register.d.ts +0 -0
  542. /package/{controls → dist/controls}/location.d.ts +0 -0
  543. /package/{controls → dist/controls}/media-register.d.ts +0 -0
  544. /package/{controls → dist/controls}/number.d.ts +0 -0
  545. /package/{controls → dist/controls}/reference-register.d.ts +0 -0
  546. /package/{controls → dist/controls}/rich-text/index.d.ts +0 -0
  547. /package/{controls → dist/controls}/rich-text/link-form.d.ts +0 -0
  548. /package/{controls → dist/controls}/rich-text/markdown.d.ts +0 -0
  549. /package/{controls → dist/controls}/rich-text/ops.d.ts +0 -0
  550. /package/{controls → dist/controls}/scale.d.ts +0 -0
  551. /package/{controls → dist/controls}/slot-register.d.ts +0 -0
  552. /package/{controls → dist/controls}/slot.d.ts +0 -0
  553. /package/{controls → dist/controls}/table/index.d.ts +0 -0
  554. /package/{controls → dist/controls}/table/prod.d.ts +0 -0
  555. /package/{controls → dist/controls}/table/refs.d.ts +0 -0
  556. /package/{controls → dist/controls}/table/stored.d.ts +0 -0
  557. /package/{controls → dist/controls}/table/table-editor.d.ts +0 -0
  558. /package/{controls → dist/controls}/table/table-link.d.ts +0 -0
  559. /package/{controls → dist/controls}/table/table.d.ts +0 -0
  560. /package/{engine → dist/engine}/array.d.ts +0 -0
  561. /package/{engine → dist/engine}/bits.d.ts +0 -0
  562. /package/{engine → dist/engine}/field-list.d.ts +0 -0
  563. /package/{engine → dist/engine}/field-shell.d.ts +0 -0
  564. /package/{engine → dist/engine}/kit-field.d.ts +0 -0
  565. /package/{engine → dist/engine}/slot.d.ts +0 -0
  566. /package/{index.d.ts → dist/index.d.ts} +0 -0
  567. /package/{lib → dist/lib}/cn.d.ts +0 -0
  568. /package/{lib → dist/lib}/columns.d.ts +0 -0
  569. /package/{lib → dist/lib}/frames.d.ts +0 -0
  570. /package/{lib → dist/lib}/icons.d.ts +0 -0
  571. /package/{lib → dist/lib}/path.d.ts +0 -0
  572. /package/{lib → dist/lib}/utils.d.ts +0 -0
  573. /package/{schema → dist/schema}/adapters.d.ts +0 -0
  574. /package/{schema → dist/schema}/scale.d.ts +0 -0
  575. /package/{schema → dist/schema}/sources.d.ts +0 -0
  576. /package/{schema → dist/schema}/table.d.ts +0 -0
  577. /package/{types.d.ts → dist/types.d.ts} +0 -0
  578. /package/{ui → dist/ui}/choice-switch.d.ts +0 -0
  579. /package/{ui → dist/ui}/controls.d.ts +0 -0
  580. /package/{ui → dist/ui}/field-context.d.ts +0 -0
  581. /package/{ui → dist/ui}/mode-bar.d.ts +0 -0
  582. /package/{ui → dist/ui}/path-crumbs.d.ts +0 -0
  583. /package/{ui → dist/ui}/presence.d.ts +0 -0
  584. /package/{ui → dist/ui}/select.d.ts +0 -0
  585. /package/{ui → dist/ui}/shortcut-hint.d.ts +0 -0
  586. /package/{ui → dist/ui}/surfaces.d.ts +0 -0
  587. /package/{ui → dist/ui}/variants.d.ts +0 -0
@@ -0,0 +1,307 @@
1
+ import { BLOCK_LIBRARY, EXAMPLES } from "./examples/index.js";
2
+ import { KIT_LIBRARY } from "./entries/index.js";
3
+ import { CORE_NOTES } from "./coreNotes.js";
4
+ //#region src/library/catalog.ts
5
+ /**
6
+ * Kit Library catalog — the library entries (`./entries/*.entries.ts`) plus the
7
+ * original Block Kit examples ("Core examples"), normalised into one list the page, the coverage matrix and
8
+ * the search use. Pure data: no React.
9
+ */
10
+ var CORE_CATEGORY = "Core examples";
11
+ /** Display order of the categories (the contract's union order). */
12
+ var CATEGORY_ORDER = [
13
+ "Navigation & chrome",
14
+ "Heroes",
15
+ "Features & storytelling",
16
+ "Social proof",
17
+ "Media & galleries",
18
+ "Commerce",
19
+ "Pricing & plans",
20
+ "Conversion & forms",
21
+ "Listings & feeds",
22
+ "Long-form & docs",
23
+ "Company & people",
24
+ "Events & places",
25
+ "Data & interactive",
26
+ "Advanced patterns"
27
+ ];
28
+ /** Every edge tag, in a reading order (structure → content → behaviour → output). */
29
+ var EDGE_TAGS = [
30
+ {
31
+ tag: "deep-nesting",
32
+ label: "Deep nesting",
33
+ hint: "4+ levels of drill-in"
34
+ },
35
+ {
36
+ tag: "repeater",
37
+ label: "Repeater",
38
+ hint: "Arrays of objects"
39
+ },
40
+ {
41
+ tag: "polymorphic-array",
42
+ label: "Polymorphic array",
43
+ hint: "Array of mixed block types"
44
+ },
45
+ {
46
+ tag: "slots",
47
+ label: "Slots",
48
+ hint: "Blocks placed inside a block"
49
+ },
50
+ {
51
+ tag: "variants",
52
+ label: "Variants",
53
+ hint: "Layout variants of one block"
54
+ },
55
+ {
56
+ tag: "conditional",
57
+ label: "Conditional",
58
+ hint: "Fields shown or hidden by other values"
59
+ },
60
+ {
61
+ tag: "references",
62
+ label: "References",
63
+ hint: "Links to pages or CMS items"
64
+ },
65
+ {
66
+ tag: "dynamic-query",
67
+ label: "Dynamic query",
68
+ hint: "Pulls N items from a collection by filter"
69
+ },
70
+ {
71
+ tag: "global-synced",
72
+ label: "Global / synced",
73
+ hint: "Shared block with per-instance overrides"
74
+ },
75
+ {
76
+ tag: "localized",
77
+ label: "Localized",
78
+ hint: "Per-field translations"
79
+ },
80
+ {
81
+ tag: "rich-text",
82
+ label: "Rich text",
83
+ hint: "Portable text body with embeds"
84
+ },
85
+ {
86
+ tag: "media-heavy",
87
+ label: "Media-heavy",
88
+ hint: "Images, video, galleries, focal points"
89
+ },
90
+ {
91
+ tag: "embed",
92
+ label: "Embed",
93
+ hint: "iframe, HTML, code or third-party"
94
+ },
95
+ {
96
+ tag: "form",
97
+ label: "Form",
98
+ hint: "Collects visitor input"
99
+ },
100
+ {
101
+ tag: "commerce",
102
+ label: "Commerce",
103
+ hint: "Price, inventory, variants"
104
+ },
105
+ {
106
+ tag: "personalization",
107
+ label: "Personalization",
108
+ hint: "Audience or A/B variants"
109
+ },
110
+ {
111
+ tag: "validation",
112
+ label: "Validation",
113
+ hint: "Limits, required, patterns"
114
+ },
115
+ {
116
+ tag: "a11y",
117
+ label: "Accessibility",
118
+ hint: "Alt text, captions, labels"
119
+ },
120
+ {
121
+ tag: "seo-structured",
122
+ label: "SEO structured",
123
+ hint: "Emits JSON-LD"
124
+ },
125
+ {
126
+ tag: "responsive-layout",
127
+ label: "Responsive layout",
128
+ hint: "Per-breakpoint layout settings"
129
+ }
130
+ ];
131
+ var TAG_LABEL = Object.fromEntries(EDGE_TAGS.map((t) => [t.tag, t.label]));
132
+ /** Edge cases the original examples exercise (they predate the contract, so the library assigns them). */
133
+ var CORE_TAGS = {
134
+ faq: [
135
+ "repeater",
136
+ "conditional",
137
+ "validation",
138
+ "dynamic-query"
139
+ ],
140
+ megaMenu: [
141
+ "deep-nesting",
142
+ "repeater",
143
+ "global-synced",
144
+ "validation"
145
+ ],
146
+ tabs: [
147
+ "slots",
148
+ "polymorphic-array",
149
+ "repeater",
150
+ "variants"
151
+ ],
152
+ pricing: [
153
+ "repeater",
154
+ "conditional",
155
+ "commerce",
156
+ "variants",
157
+ "validation"
158
+ ],
159
+ bento: [
160
+ "slots",
161
+ "polymorphic-array",
162
+ "variants",
163
+ "responsive-layout",
164
+ "media-heavy"
165
+ ],
166
+ journalStory: [
167
+ "rich-text",
168
+ "references",
169
+ "media-heavy",
170
+ "seo-structured",
171
+ "localized",
172
+ "validation",
173
+ "embed"
174
+ ],
175
+ hero: [
176
+ "variants",
177
+ "media-heavy",
178
+ "localized",
179
+ "a11y"
180
+ ]
181
+ };
182
+ var CORE_LAYOUT = {
183
+ faq: "accordion",
184
+ megaMenu: "nav",
185
+ tabs: "tabs",
186
+ pricing: "grid-3",
187
+ bento: "bento",
188
+ journalStory: "article",
189
+ hero: "split"
190
+ };
191
+ var hayOf = (parts) => parts.filter(Boolean).join("  ").toLowerCase();
192
+ function fromEntry(e) {
193
+ return {
194
+ id: e.id,
195
+ ex: e,
196
+ entry: e,
197
+ core: false,
198
+ category: e.category,
199
+ tags: e.tags ?? [],
200
+ notes: e.notes,
201
+ brand: e.brand,
202
+ previewLayout: e.previewLayout,
203
+ hay: hayOf([
204
+ e.label,
205
+ e.schema.title,
206
+ e.schema.name,
207
+ e.schema.description,
208
+ e.proves,
209
+ e.category,
210
+ e.brand,
211
+ ...(e.tags ?? []).map((t) => `${t} ${TAG_LABEL[t] ?? ""}`),
212
+ ...e.notes?.htmlSignals ?? []
213
+ ])
214
+ };
215
+ }
216
+ function fromCore(x) {
217
+ const tags = CORE_TAGS[x.id] ?? [];
218
+ const notes = CORE_NOTES[x.id];
219
+ return {
220
+ id: `core-${x.id}`,
221
+ ex: x,
222
+ core: true,
223
+ category: CORE_CATEGORY,
224
+ tags,
225
+ notes,
226
+ brand: "Caldera",
227
+ previewLayout: CORE_LAYOUT[x.id],
228
+ hay: hayOf([
229
+ x.label,
230
+ x.schema.title,
231
+ x.schema.name,
232
+ x.schema.description,
233
+ x.proves,
234
+ CORE_CATEGORY,
235
+ ...tags.map((t) => `${t} ${TAG_LABEL[t] ?? ""}`),
236
+ ...notes?.htmlSignals ?? []
237
+ ])
238
+ };
239
+ }
240
+ var catRank = (c) => {
241
+ const i = CATEGORY_ORDER.indexOf(c);
242
+ return c === "Core examples" ? 1e3 : i === -1 ? 500 : i;
243
+ };
244
+ /** Library entries (sorted by category order, then file order) followed by the core examples. Ids are unique. */
245
+ function buildCatalog(library = KIT_LIBRARY) {
246
+ const seen = /* @__PURE__ */ new Set();
247
+ return [...library.filter((e) => e && e.id && e.schema && !seen.has(e.id) && (seen.add(e.id), true)).map(fromEntry).map((it, i) => ({
248
+ it,
249
+ i
250
+ })).sort((a, b) => catRank(a.it.category) - catRank(b.it.category) || a.i - b.i).map((x) => x.it), ...EXAMPLES.map(fromCore)];
251
+ }
252
+ var CATALOG = buildCatalog();
253
+ /** Categories present in a list, in display order, with counts. */
254
+ function categoriesOf(items) {
255
+ const m = /* @__PURE__ */ new Map();
256
+ for (const it of items) m.set(it.category, (m.get(it.category) ?? 0) + 1);
257
+ return [...m.entries()].sort((a, b) => catRank(a[0]) - catRank(b[0])).map(([category, count]) => ({
258
+ category,
259
+ count
260
+ }));
261
+ }
262
+ /** Every term must appear somewhere in the haystack. */
263
+ function matches(it, terms, tags) {
264
+ if (tags.length && !tags.every((t) => it.tags.includes(t))) return false;
265
+ return terms.every((t) => it.hay.includes(t));
266
+ }
267
+ var termsOf = (q) => q.trim().toLowerCase().split(/\s+/).filter(Boolean);
268
+ /**
269
+ * Block schemas a slot can resolve: the shared example blocks plus every library entry whose schema is a block
270
+ * (so an entry may place another entry's block in a slot by its schema name). First definition wins.
271
+ */
272
+ var LIBRARY_BLOCKS = (() => {
273
+ const out = [];
274
+ const names = /* @__PURE__ */ new Set();
275
+ for (const s of [
276
+ ...BLOCK_LIBRARY,
277
+ ...KIT_LIBRARY.flatMap((e) => e.blocks ?? []),
278
+ ...KIT_LIBRARY.map((e) => e.schema)
279
+ ]) {
280
+ if (!s?.name || names.has(s.name)) continue;
281
+ names.add(s.name);
282
+ out.push(s);
283
+ }
284
+ return out;
285
+ })();
286
+ var BLOCK_BY_NAME = new Map(LIBRARY_BLOCKS.map((b) => [b.name, b]));
287
+ var resolveLibraryBlock = (type) => BLOCK_BY_NAME.get(type);
288
+ /** Blocks offered by "+ Add block": only real blocks (not entries / pages). */
289
+ var PICKABLE_BLOCKS = LIBRARY_BLOCKS.filter((b) => b.kind === "block");
290
+ /** Slot resolution for one catalog item: its entry-local `blocks` first (contract), then the shared library. */
291
+ function blocksFor(it) {
292
+ const local = it.entry?.blocks?.filter((b) => b?.name) ?? [];
293
+ if (!local.length) return {
294
+ resolve: resolveLibraryBlock,
295
+ library: PICKABLE_BLOCKS
296
+ };
297
+ const own = new Map(local.map((b) => [b.name, b]));
298
+ const names = new Set(local.map((b) => b.name));
299
+ return {
300
+ resolve: (type) => own.get(type) ?? BLOCK_BY_NAME.get(type),
301
+ library: [...local, ...PICKABLE_BLOCKS.filter((b) => !names.has(b.name))]
302
+ };
303
+ }
304
+ //#endregion
305
+ export { CATALOG, CATEGORY_ORDER, CORE_CATEGORY, EDGE_TAGS, LIBRARY_BLOCKS, PICKABLE_BLOCKS, TAG_LABEL, blocksFor, buildCatalog, categoriesOf, matches, resolveLibraryBlock, termsOf };
306
+
307
+ //# sourceMappingURL=catalog.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"catalog.js","names":[],"sources":["../../src/library/catalog.ts"],"sourcesContent":["/**\n * Kit Library catalog — the library entries (`./entries/*.entries.ts`) plus the\n * original Block Kit examples (\"Core examples\"), normalised into one list the page, the coverage matrix and\n * the search use. Pure data: no React.\n */\nimport { BLOCK_LIBRARY, EXAMPLES, type KitExample } from \"./examples\";\nimport { KIT_LIBRARY } from \"./entries\";\nimport { CORE_NOTES } from \"./coreNotes\";\nimport type { EdgeTag, KitCategory, KitEntry, KitModelNotes, KitPreviewLayout } from \"./types\";\nimport type { TypeSchema } from \"../schema/types\";\n\nexport const CORE_CATEGORY = \"Core examples\" as const;\nexport type CatalogCategory = KitCategory | typeof CORE_CATEGORY;\n\n/** Display order of the categories (the contract's union order). */\nexport const CATEGORY_ORDER: KitCategory[] = [\n \"Navigation & chrome\",\n \"Heroes\",\n \"Features & storytelling\",\n \"Social proof\",\n \"Media & galleries\",\n \"Commerce\",\n \"Pricing & plans\",\n \"Conversion & forms\",\n \"Listings & feeds\",\n \"Long-form & docs\",\n \"Company & people\",\n \"Events & places\",\n \"Data & interactive\",\n \"Advanced patterns\",\n];\n\n/** Every edge tag, in a reading order (structure → content → behaviour → output). */\nexport const EDGE_TAGS: { tag: EdgeTag; label: string; hint: string }[] = [\n { tag: \"deep-nesting\", label: \"Deep nesting\", hint: \"4+ levels of drill-in\" },\n { tag: \"repeater\", label: \"Repeater\", hint: \"Arrays of objects\" },\n { tag: \"polymorphic-array\", label: \"Polymorphic array\", hint: \"Array of mixed block types\" },\n { tag: \"slots\", label: \"Slots\", hint: \"Blocks placed inside a block\" },\n { tag: \"variants\", label: \"Variants\", hint: \"Layout variants of one block\" },\n { tag: \"conditional\", label: \"Conditional\", hint: \"Fields shown or hidden by other values\" },\n { tag: \"references\", label: \"References\", hint: \"Links to pages or CMS items\" },\n { tag: \"dynamic-query\", label: \"Dynamic query\", hint: \"Pulls N items from a collection by filter\" },\n { tag: \"global-synced\", label: \"Global / synced\", hint: \"Shared block with per-instance overrides\" },\n { tag: \"localized\", label: \"Localized\", hint: \"Per-field translations\" },\n { tag: \"rich-text\", label: \"Rich text\", hint: \"Portable text body with embeds\" },\n { tag: \"media-heavy\", label: \"Media-heavy\", hint: \"Images, video, galleries, focal points\" },\n { tag: \"embed\", label: \"Embed\", hint: \"iframe, HTML, code or third-party\" },\n { tag: \"form\", label: \"Form\", hint: \"Collects visitor input\" },\n { tag: \"commerce\", label: \"Commerce\", hint: \"Price, inventory, variants\" },\n { tag: \"personalization\", label: \"Personalization\", hint: \"Audience or A/B variants\" },\n { tag: \"validation\", label: \"Validation\", hint: \"Limits, required, patterns\" },\n { tag: \"a11y\", label: \"Accessibility\", hint: \"Alt text, captions, labels\" },\n { tag: \"seo-structured\", label: \"SEO structured\", hint: \"Emits JSON-LD\" },\n { tag: \"responsive-layout\", label: \"Responsive layout\", hint: \"Per-breakpoint layout settings\" },\n];\nexport const TAG_LABEL: Record<string, string> = Object.fromEntries(EDGE_TAGS.map((t) => [t.tag, t.label]));\n\nexport interface CatalogItem {\n /** URL id: the entry id, or `core-{id}` for the original examples */\n id: string;\n ex: KitExample;\n entry?: KitEntry;\n core: boolean;\n category: CatalogCategory;\n tags: EdgeTag[];\n notes?: KitModelNotes;\n brand?: string;\n previewLayout?: KitPreviewLayout;\n /** lower-cased haystack: name, description, proves, category, tags, html signals, brand */\n hay: string;\n}\n\n/** Edge cases the original examples exercise (they predate the contract, so the library assigns them). */\nconst CORE_TAGS: Record<string, EdgeTag[]> = {\n faq: [\"repeater\", \"conditional\", \"validation\", \"dynamic-query\"],\n megaMenu: [\"deep-nesting\", \"repeater\", \"global-synced\", \"validation\"],\n tabs: [\"slots\", \"polymorphic-array\", \"repeater\", \"variants\"],\n pricing: [\"repeater\", \"conditional\", \"commerce\", \"variants\", \"validation\"],\n bento: [\"slots\", \"polymorphic-array\", \"variants\", \"responsive-layout\", \"media-heavy\"],\n journalStory: [\"rich-text\", \"references\", \"media-heavy\", \"seo-structured\", \"localized\", \"validation\", \"embed\"],\n hero: [\"variants\", \"media-heavy\", \"localized\", \"a11y\"],\n};\nconst CORE_LAYOUT: Record<string, KitPreviewLayout> = {\n faq: \"accordion\", megaMenu: \"nav\", tabs: \"tabs\", pricing: \"grid-3\", bento: \"bento\", journalStory: \"article\", hero: \"split\",\n};\n\nconst hayOf = (parts: (string | undefined)[]) => parts.filter(Boolean).join(\" \\u0001 \").toLowerCase();\n\nfunction fromEntry(e: KitEntry): CatalogItem {\n return {\n id: e.id,\n ex: e,\n entry: e,\n core: false,\n category: e.category,\n tags: e.tags ?? [],\n notes: e.notes,\n brand: e.brand,\n previewLayout: e.previewLayout,\n hay: hayOf([e.label, e.schema.title, e.schema.name, e.schema.description, e.proves, e.category, e.brand, ...(e.tags ?? []).map((t) => `${t} ${TAG_LABEL[t] ?? \"\"}`), ...(e.notes?.htmlSignals ?? [])]),\n };\n}\nfunction fromCore(x: KitExample): CatalogItem {\n const tags = CORE_TAGS[x.id] ?? [];\n const notes = CORE_NOTES[x.id];\n return {\n id: `core-${x.id}`,\n ex: x,\n core: true,\n category: CORE_CATEGORY,\n tags,\n notes,\n brand: \"Caldera\",\n previewLayout: CORE_LAYOUT[x.id],\n hay: hayOf([x.label, x.schema.title, x.schema.name, x.schema.description, x.proves, CORE_CATEGORY, ...tags.map((t) => `${t} ${TAG_LABEL[t] ?? \"\"}`), ...(notes?.htmlSignals ?? [])]),\n };\n}\n\nconst catRank = (c: CatalogCategory) => {\n const i = CATEGORY_ORDER.indexOf(c as KitCategory);\n return c === CORE_CATEGORY ? 1000 : i === -1 ? 500 : i;\n};\n\n/** Library entries (sorted by category order, then file order) followed by the core examples. Ids are unique. */\nexport function buildCatalog(library: KitEntry[] = KIT_LIBRARY): CatalogItem[] {\n const seen = new Set<string>();\n const lib = library\n .filter((e) => e && e.id && e.schema && !seen.has(e.id) && (seen.add(e.id), true))\n .map(fromEntry)\n .map((it, i) => ({ it, i }))\n .sort((a, b) => catRank(a.it.category) - catRank(b.it.category) || a.i - b.i)\n .map((x) => x.it);\n return [...lib, ...EXAMPLES.map(fromCore)];\n}\n\nexport const CATALOG: CatalogItem[] = buildCatalog();\n\n/** Categories present in a list, in display order, with counts. */\nexport function categoriesOf(items: CatalogItem[]): { category: CatalogCategory; count: number }[] {\n const m = new Map<CatalogCategory, number>();\n for (const it of items) m.set(it.category, (m.get(it.category) ?? 0) + 1);\n return [...m.entries()].sort((a, b) => catRank(a[0]) - catRank(b[0])).map(([category, count]) => ({ category, count }));\n}\n\n/** Every term must appear somewhere in the haystack. */\nexport function matches(it: CatalogItem, terms: string[], tags: EdgeTag[]): boolean {\n if (tags.length && !tags.every((t) => it.tags.includes(t))) return false;\n return terms.every((t) => it.hay.includes(t));\n}\nexport const termsOf = (q: string) => q.trim().toLowerCase().split(/\\s+/).filter(Boolean);\n\n/**\n * Block schemas a slot can resolve: the shared example blocks plus every library entry whose schema is a block\n * (so an entry may place another entry's block in a slot by its schema name). First definition wins.\n */\nexport const LIBRARY_BLOCKS: TypeSchema[] = (() => {\n const out: TypeSchema[] = [];\n const names = new Set<string>();\n for (const s of [...BLOCK_LIBRARY, ...KIT_LIBRARY.flatMap((e) => e.blocks ?? []), ...KIT_LIBRARY.map((e) => e.schema)]) {\n if (!s?.name || names.has(s.name)) continue;\n names.add(s.name);\n out.push(s);\n }\n return out;\n})();\nconst BLOCK_BY_NAME = new Map(LIBRARY_BLOCKS.map((b) => [b.name, b]));\nexport const resolveLibraryBlock = (type: string) => BLOCK_BY_NAME.get(type);\n/** Blocks offered by \"+ Add block\": only real blocks (not entries / pages). */\nexport const PICKABLE_BLOCKS: TypeSchema[] = LIBRARY_BLOCKS.filter((b) => b.kind === \"block\");\n\n/** Slot resolution for one catalog item: its entry-local `blocks` first (contract), then the shared library. */\nexport function blocksFor(it: CatalogItem): { resolve: (type: string) => TypeSchema | undefined; library: TypeSchema[] } {\n const local = it.entry?.blocks?.filter((b) => b?.name) ?? [];\n if (!local.length) return { resolve: resolveLibraryBlock, library: PICKABLE_BLOCKS };\n const own = new Map(local.map((b) => [b.name, b]));\n const names = new Set(local.map((b) => b.name));\n return {\n resolve: (type) => own.get(type) ?? BLOCK_BY_NAME.get(type),\n library: [...local, ...PICKABLE_BLOCKS.filter((b) => !names.has(b.name))],\n };\n}\n"],"mappings":"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"}
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Model notes for the seven core examples (src/kit/library/examples). They predate the entry contract, so the
3
+ * catalog attaches these by example id, as it does CORE_TAGS. Every claim is sourced from the example's own schema
4
+ * and `proves`, the backend skill's worked examples (hero, pricing, FAQ, blog entry, mega menu, tabs) and the MCP
5
+ * playbook §2–§5 and §14. The `mcp` text is in create_component / update_layout / create_content_model terms.
6
+ */
7
+ import type { KitModelNotes } from "./types";
8
+ export declare const CORE_NOTES: Record<string, KitModelNotes>;
@@ -0,0 +1,111 @@
1
+ //#region src/library/coreNotes.ts
2
+ var CORE_NOTES = {
3
+ faq: {
4
+ why: "Questions are same-shaped rows, so `items` is one list whose row holds a plain-string question and a rich-text answer (bold, links and lists live in answers). `source` switches between questions written here and references into a FAQs collection; each list shows only for its own choice, so the two never disagree. Search, rich results, columns and the anchor are Settings, not copy, and the anchor is locked to people who manage the schema.",
5
+ htmlSignals: [
6
+ "Repeated <details> with a <summary> holding the question (often an <h3> plus a chevron <svg>) and a body <div> holding the answer",
7
+ "The first <details> carries `open`",
8
+ "A hand-written <script type=\"application/ld+json\"> with \"@type\":\"FAQPage\" beside the band",
9
+ "A closing line with a support link under the list (\"Still stuck? Talk to support\")"
10
+ ],
11
+ mcp: "create_component with sectionType 'FAQ'; each prop needs a `target` into your own blockJson (a root `section` with `style`). eyebrow/heading/intro → text props on heading/text blocks. items → ONE `table` prop: config.fields question (text, required) + answer (richtext, required), plus category (select) and open (boolean); ui { preview: { title: 'question' }, itemLabel: 'Question', icon: 'help-circle' }. source → a select with ui.control 'segmented'; give items and collection a `showIf` on source ('inline' / 'collection'), placed after source. collection → multi-reference with config.contentModelId of the FAQs model. showSearch/richResults/columns/anchor → ui.tab 'Settings'. Accordion and Two columns are two components sharing sectionType 'FAQ' with the same prop keys.",
12
+ pitfalls: [
13
+ "richResults does nothing by itself: FAQPage markup comes from update_page schemaType 'FAQPage', and the builder finds the first list whose rows have keys containing `question` and `answer`. Delete the hand-written JSON-LD.",
14
+ "`open` on the first item is behaviour in the worked example and stays in the template; keep the per-item boolean only if the template reads it.",
15
+ "Bind the question on the <h3>, not the <summary>, or a save erases the chevron."
16
+ ]
17
+ },
18
+ megaMenu: {
19
+ why: "The navigation is a GLOBAL block: one copy synced across every page, edited once. Its menu is five levels deep (Navigation › menu item › column › link › badge) to prove drill-in and breadcrumb truncation. A menu item `kind` decides whether it is a plain link or opens a mega panel of columns plus a featured card, so a link row never carries panel data. Sticky, transparent and the mobile style sit in a Behaviour tab; the logo and its screen-reader text share a Brand fieldset.",
20
+ htmlSignals: [
21
+ "A <header> on every page holding <nav aria-label=\"Main\"> with a logo <a><img></a> and a <ul> of menu items",
22
+ "A <button aria-expanded aria-controls> that opens a hidden panel, beside plain <a> items that just link",
23
+ "Panel columns: a title <p> over a <ul> of links, each link a label <span>, an optional description <span> and an optional badge (\"New\")",
24
+ "Sign-in link and a primary button at the end of the bar"
25
+ ],
26
+ mcp: "Site chrome is the Layout, never a page section: get_layout, then update_layout scope 'global' with `add-field` commands on the reserved `navigation` Section (ifMatch from get_layout), set-field-value for the rows, publish_layout. Read the Section's existing logo, link and button fields first and add only what is missing. If the header is a component placed with `add-component`, each prop needs a `target` into your own blockJson: items → a `table` prop (ui { itemLabel: 'Menu item', preview: { title: 'label' } }) whose rows hold label, link (a `link` value), kind (select) and ONE nested `table` of links with `column` as a text sub-field; cta → a `button` prop on a button block's `props`. logo/logoText → ui.group 'brand'; sticky/transparent/mobile → ui.tab 'Behaviour'.",
27
+ pitfalls: [
28
+ "Two list levels is the cap for a component's props and the depth chrome is proven to bind at: store menu → links and put the column title on each link row. The kit's third level (columns) and the badge object do not fit; flatten the badge to a scalar on the link row.",
29
+ "A nav placed on a page as a section renders nowhere, and a page that draws its own header gets no Layout copy on top: remove page-level copies.",
30
+ "The worked example keeps `sticky`, colours and height in code; expose the Behaviour props only if the template reads them."
31
+ ]
32
+ },
33
+ tabs: {
34
+ why: "Tabs are a list (2–6), and each tab is a label, an optional icon and a SLOT of blocks, so a panel can hold text, images, features, stats, quotes, CTA cards, product cards or video in any order. The allow list keeps panels to small content blocks. Which tab opens first and whether the URL remembers it are settings; underline, pills and side tabs are layout variants.",
35
+ htmlSignals: [
36
+ "A role=\"tablist\" of <button role=\"tab\" aria-controls aria-selected>, often each with an icon <i>",
37
+ "One role=\"tabpanel\" per tab, all but the first `hidden`",
38
+ "Panels that hold their own rows of cards, images and stats rather than one paragraph"
39
+ ],
40
+ mcp: "A band one page owns can stay a `section` block holding a `tabs` block {tabs:[{id,label,children}]} (worked example 8). As a component: create_component with a sectionType naming the family (e.g. 'Tabs'); each prop needs a `target` into your own blockJson. tabs → ONE `table` prop (ui { itemLabel: 'Tab', preview: { title: 'label' }, icon: 'layout-list' }) with config.fields label (text, required), icon (`icon`) and content: a `slot` sub-field with config.multiple, maxItems 6 and config.componentIds; point the table at your tabs block the way §14's slider table targets props.slides. heading → text prop; defaultTab → number with config.min 1, max 6. Underline, Pills and Side tabs are three components sharing sectionType 'Tabs' with the same prop keys.",
41
+ pitfalls: [
42
+ "The kit's slot allow list names kit blocks, not components: config.componentIds must list published components of this project.",
43
+ "Slot children are `{ componentId, overrides? }` with no `_variant`: a variant is its own component.",
44
+ "Give every block, tab and instance a stable `id`; changing one orphans the edits made against it."
45
+ ]
46
+ },
47
+ pricing: {
48
+ why: "Tiers are same-shaped rows (1–4). A tier's priceType decides what shows: a fixed tier shows the amount and billing interval, a custom tier swaps in a Contact sales button, so a tier never shows a price and 'Contact sales' at once. Features are tiny rows (label, included, tooltip) that open inline. The comparison table, currency, the monthly/yearly switch and its discount are Display settings; Three tiers, Two tiers and Comparison table are variants.",
49
+ htmlSignals: [
50
+ "A grid of plan <article>s, each with an <h3> name, a short audience line, a price, a <ul class=\"checks\"> and one CTA <a>",
51
+ "One card flagged with a ribbon or modifier class (\"Most popular\")",
52
+ "A price <span> with data-monthly / data-yearly next to a role=\"radiogroup\" billing toggle (\"Save 20%\")",
53
+ "A price in words (\"Let's talk\") linking to contact sales instead of an amount",
54
+ "A <table class=\"compare\"> with one column per plan and check / cross icons labelled by aria-label"
55
+ ],
56
+ mcp: "create_component with sectionType 'Pricing' and category 'conversion'; it lands as a draft, then publish_component. Each prop needs a `target` into your own blockJson: tiers → ONE `table` prop targeting props.rows of a `section` block whose children mirror one row, ui { itemLabel: 'Tier', preview: { title: 'name' }, icon: 'tiers' }; its config.fields hold name, tagline, priceType (select, ui.control 'segmented'), price (number) and interval with `showIf` priceType eq 'fixed', contactSales and cta as `button` sub-fields, featured (boolean) and features as a nested `table` of scalars. comparison → a second `table` prop, one row per feature and one key per tier. currency/toggle/discount → ui.tab 'Display'. Variants are sibling components sharing sectionType 'Pricing' and the same prop keys.",
57
+ pitfalls: [
58
+ "Store numbers, never '$24/mo'. A price in words is its own text key, shown when the numbers are empty.",
59
+ "The nested features table is the deepest a prop goes: its rows take scalars only.",
60
+ "A tier added to the comparison is a new sub-field, a schema change. No Offer JSON-LD is built from prices; paste it as `schema` on update_page when needed."
61
+ ]
62
+ },
63
+ bento: {
64
+ why: "A bento is a SLOT of 3–9 cells, and each cell is any allowed block (image, stat, quote, text, CTA card, product card, video). Size (1×1, 2×1, 1×2, 2×2) and surface (light, dark, brand) belong to the cell's place in this grid, not to the block, so they are per-slot settings rather than fields on every block. The gap is a design select; four and three columns are variants.",
65
+ htmlSignals: [
66
+ "A grid section whose cells span different column/row counts (wide, tall and large tiles beside small ones)",
67
+ "Cells of mixed kinds in one grid: a photo, a big number with a label, a quote, a product card, a CTA card, a video",
68
+ "Some cells on a dark or brand-coloured surface while their neighbours are light"
69
+ ],
70
+ mcp: "create_component with a sectionType naming the family (e.g. 'Bento'); each prop needs a `target` into your own blockJson. cells → a `slot` prop with config.multiple, minItems 3, maxItems 9, config.componentIds of your published cell components, and config.slotSettings span (select 1x1/2x1/1x2/2x2, ui.control 'cards') and tone (select light/dark/brand, ui.control 'segmented'); target a container's child list (props.children on a section, props.columns.<n> on a columns block). Each child is `{ componentId, overrides? }` and its settings sit in `_settings`. eyebrow/heading → text props; gap → select with ui.control 'segmented'. 4 columns and 3 columns are two components sharing sectionType 'Bento' with the same prop keys.",
71
+ pitfalls: [
72
+ "The kit's allow list names kit blocks; config.componentIds must name this project's published components, and the renderer needs their definitions or every cell draws empty.",
73
+ "A slot child has no `_variant`: a variant is its own component.",
74
+ "slotSettings are leaf fields only; a cell's own copy stays in the cell component's props."
75
+ ]
76
+ },
77
+ journalStory: {
78
+ why: "A story is an ENTRY, one of many, with its own URL: content in groups (Content, Media, Settings) and fieldsets (Byline, a collapsed Gear review, Publishing). Authors and topics are references to their own collections, not copied names; the reviewed product is a reference to commerce. The body is the one long rich-text field. Layout, accent, internal tags, related stories and developer-only custom CSS are Settings. It proves references, rich text, SEO-friendly limits (title, excerpt) and changed-since-publish.",
79
+ htmlSignals: [
80
+ "An <article> (often itemtype BlogPosting) with an <h1>, a dek <p>, a byline with <a rel=\"author\"> and <time datetime>",
81
+ "A cover <figure> with <img> and <figcaption> above a prose body of <h2>, <p>, lists, figures, tables and code",
82
+ "A topic link above the title and a reading time (\"7 min read\") in the byline",
83
+ "One of many pages under a shared route such as /blog/<slug>"
84
+ ],
85
+ mcp: "Not a component: create_content_model for the stories (a collection with urlPattern '/blog/:slug' and one dynamic page), and create_content_entry per story. Find or create the author and topic entries first and reference them by id. title, slug, excerpt, cover, gallery and film are fields; body is the ONE `document` field (top level, at most one per schema); dates are ISO 8601 with their offset. Publish authors and topics, then the post, then the template page. The `component` shape below is props-shaped only for comparison; if you place a story teaser as a component, each prop needs a `target` into your own blockJson.",
86
+ pitfalls: [
87
+ "Never model SEO fields: entry meta (metaTitle, metaDescription, og, canonical) goes in update_content_entry `meta`, and BlogPosting markup is automatic for a collection with a body, a date and an author.",
88
+ "Reading time is computed by the template; no field stores it today, so don't copy \"7 min read\" into readingTime.",
89
+ "Bind the body wrapper as kind `document`, never `richtext`, or a save repaints the article from plain text."
90
+ ]
91
+ },
92
+ hero: {
93
+ why: "The opening band: an eyebrow, a headline (required, 90 max, 60 recommended), supporting text, two buttons and a proof line of rating plus label. Each button is one unit, so label, link and look travel together. The proof is a small object because the stars are drawn from the number. Media (a required image, an optional background video) and Design (alignment, theme, overlay, fill-the-screen) are their own tabs, so copy, media and look never mix; split, centered and full-bleed are variants.",
94
+ htmlSignals: [
95
+ "The first <section> after the header with one <h1>, a short eyebrow <p> above it and a lede <p> below",
96
+ "Two links styled as buttons (btn-primary / btn-ghost), sometimes with an arrow icon",
97
+ "A <picture>/<img> beside the copy (split) or absolutely positioned behind it with a dark scrim <div> (full-bleed)",
98
+ "A rating line: star glyphs with aria-label=\"Rated 4.8 out of 5\" and \"from 310 reviews\""
99
+ ],
100
+ mcp: "create_component with sectionType 'Hero' and category 'hero'; root is a `section` block with `style`, content in props.children. Each prop needs a `target` into your own blockJson: eyebrow/body → text props on text blocks (props.html), heading → props.text of a level-1 heading block, primary/secondary → one `button` prop each (label, link and look in one unit) on a button block's `props`, image → an `image` prop on an image block's props.src plus a text prop on props.alt, video → a video block's props.url, proof → an `object` prop with config.fields rating (number) and label (text). Put image/video in ui.tab 'Media' and align/theme/overlay/fullHeight in ui.tab 'Design' (theme with ui.control 'segmented'). Split image, Centered and Full-bleed image are three components sharing sectionType 'Hero' with the same prop keys.",
101
+ pitfalls: [
102
+ "Overlay and height have no section token today: the scrim and spacing stay in the template's classes unless the template reads those props.",
103
+ "object-position is the image's focal point (50% 35% → { x: 0.5, y: 0.35 }); store the number 4.8, never the star glyphs.",
104
+ "A variant that renames a key (title vs heading) silently drops that content on a swap."
105
+ ]
106
+ }
107
+ };
108
+ //#endregion
109
+ export { CORE_NOTES };
110
+
111
+ //# sourceMappingURL=coreNotes.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"coreNotes.js","names":[],"sources":["../../src/library/coreNotes.ts"],"sourcesContent":["/**\n * Model notes for the seven core examples (src/kit/library/examples). They predate the entry contract, so the\n * catalog attaches these by example id, as it does CORE_TAGS. Every claim is sourced from the example's own schema\n * and `proves`, the backend skill's worked examples (hero, pricing, FAQ, blog entry, mega menu, tabs) and the MCP\n * playbook §2–§5 and §14. The `mcp` text is in create_component / update_layout / create_content_model terms.\n */\nimport type { KitModelNotes } from \"./types\";\n\nexport const CORE_NOTES: Record<string, KitModelNotes> = {\n faq: {\n why:\n \"Questions are same-shaped rows, so `items` is one list whose row holds a plain-string question and a rich-text answer (bold, links and lists live in answers). `source` switches between questions written here and references into a FAQs collection; each list shows only for its own choice, so the two never disagree. Search, rich results, columns and the anchor are Settings, not copy, and the anchor is locked to people who manage the schema.\",\n htmlSignals: [\n \"Repeated <details> with a <summary> holding the question (often an <h3> plus a chevron <svg>) and a body <div> holding the answer\",\n \"The first <details> carries `open`\",\n \"A hand-written <script type=\\\"application/ld+json\\\"> with \\\"@type\\\":\\\"FAQPage\\\" beside the band\",\n \"A closing line with a support link under the list (\\\"Still stuck? Talk to support\\\")\",\n ],\n mcp:\n \"create_component with sectionType 'FAQ'; each prop needs a `target` into your own blockJson (a root `section` with `style`). eyebrow/heading/intro → text props on heading/text blocks. items → ONE `table` prop: config.fields question (text, required) + answer (richtext, required), plus category (select) and open (boolean); ui { preview: { title: 'question' }, itemLabel: 'Question', icon: 'help-circle' }. source → a select with ui.control 'segmented'; give items and collection a `showIf` on source ('inline' / 'collection'), placed after source. collection → multi-reference with config.contentModelId of the FAQs model. showSearch/richResults/columns/anchor → ui.tab 'Settings'. Accordion and Two columns are two components sharing sectionType 'FAQ' with the same prop keys.\",\n pitfalls: [\n \"richResults does nothing by itself: FAQPage markup comes from update_page schemaType 'FAQPage', and the builder finds the first list whose rows have keys containing `question` and `answer`. Delete the hand-written JSON-LD.\",\n \"`open` on the first item is behaviour in the worked example and stays in the template; keep the per-item boolean only if the template reads it.\",\n \"Bind the question on the <h3>, not the <summary>, or a save erases the chevron.\",\n ],\n },\n megaMenu: {\n why:\n \"The navigation is a GLOBAL block: one copy synced across every page, edited once. Its menu is five levels deep (Navigation › menu item › column › link › badge) to prove drill-in and breadcrumb truncation. A menu item `kind` decides whether it is a plain link or opens a mega panel of columns plus a featured card, so a link row never carries panel data. Sticky, transparent and the mobile style sit in a Behaviour tab; the logo and its screen-reader text share a Brand fieldset.\",\n htmlSignals: [\n \"A <header> on every page holding <nav aria-label=\\\"Main\\\"> with a logo <a><img></a> and a <ul> of menu items\",\n \"A <button aria-expanded aria-controls> that opens a hidden panel, beside plain <a> items that just link\",\n \"Panel columns: a title <p> over a <ul> of links, each link a label <span>, an optional description <span> and an optional badge (\\\"New\\\")\",\n \"Sign-in link and a primary button at the end of the bar\",\n ],\n mcp:\n \"Site chrome is the Layout, never a page section: get_layout, then update_layout scope 'global' with `add-field` commands on the reserved `navigation` Section (ifMatch from get_layout), set-field-value for the rows, publish_layout. Read the Section's existing logo, link and button fields first and add only what is missing. If the header is a component placed with `add-component`, each prop needs a `target` into your own blockJson: items → a `table` prop (ui { itemLabel: 'Menu item', preview: { title: 'label' } }) whose rows hold label, link (a `link` value), kind (select) and ONE nested `table` of links with `column` as a text sub-field; cta → a `button` prop on a button block's `props`. logo/logoText → ui.group 'brand'; sticky/transparent/mobile → ui.tab 'Behaviour'.\",\n pitfalls: [\n \"Two list levels is the cap for a component's props and the depth chrome is proven to bind at: store menu → links and put the column title on each link row. The kit's third level (columns) and the badge object do not fit; flatten the badge to a scalar on the link row.\",\n \"A nav placed on a page as a section renders nowhere, and a page that draws its own header gets no Layout copy on top: remove page-level copies.\",\n \"The worked example keeps `sticky`, colours and height in code; expose the Behaviour props only if the template reads them.\",\n ],\n },\n tabs: {\n why:\n \"Tabs are a list (2–6), and each tab is a label, an optional icon and a SLOT of blocks, so a panel can hold text, images, features, stats, quotes, CTA cards, product cards or video in any order. The allow list keeps panels to small content blocks. Which tab opens first and whether the URL remembers it are settings; underline, pills and side tabs are layout variants.\",\n htmlSignals: [\n \"A role=\\\"tablist\\\" of <button role=\\\"tab\\\" aria-controls aria-selected>, often each with an icon <i>\",\n \"One role=\\\"tabpanel\\\" per tab, all but the first `hidden`\",\n \"Panels that hold their own rows of cards, images and stats rather than one paragraph\",\n ],\n mcp:\n \"A band one page owns can stay a `section` block holding a `tabs` block {tabs:[{id,label,children}]} (worked example 8). As a component: create_component with a sectionType naming the family (e.g. 'Tabs'); each prop needs a `target` into your own blockJson. tabs → ONE `table` prop (ui { itemLabel: 'Tab', preview: { title: 'label' }, icon: 'layout-list' }) with config.fields label (text, required), icon (`icon`) and content: a `slot` sub-field with config.multiple, maxItems 6 and config.componentIds; point the table at your tabs block the way §14's slider table targets props.slides. heading → text prop; defaultTab → number with config.min 1, max 6. Underline, Pills and Side tabs are three components sharing sectionType 'Tabs' with the same prop keys.\",\n pitfalls: [\n \"The kit's slot allow list names kit blocks, not components: config.componentIds must list published components of this project.\",\n \"Slot children are `{ componentId, overrides? }` with no `_variant`: a variant is its own component.\",\n \"Give every block, tab and instance a stable `id`; changing one orphans the edits made against it.\",\n ],\n },\n pricing: {\n why:\n \"Tiers are same-shaped rows (1–4). A tier's priceType decides what shows: a fixed tier shows the amount and billing interval, a custom tier swaps in a Contact sales button, so a tier never shows a price and 'Contact sales' at once. Features are tiny rows (label, included, tooltip) that open inline. The comparison table, currency, the monthly/yearly switch and its discount are Display settings; Three tiers, Two tiers and Comparison table are variants.\",\n htmlSignals: [\n \"A grid of plan <article>s, each with an <h3> name, a short audience line, a price, a <ul class=\\\"checks\\\"> and one CTA <a>\",\n \"One card flagged with a ribbon or modifier class (\\\"Most popular\\\")\",\n \"A price <span> with data-monthly / data-yearly next to a role=\\\"radiogroup\\\" billing toggle (\\\"Save 20%\\\")\",\n \"A price in words (\\\"Let's talk\\\") linking to contact sales instead of an amount\",\n \"A <table class=\\\"compare\\\"> with one column per plan and check / cross icons labelled by aria-label\",\n ],\n mcp:\n \"create_component with sectionType 'Pricing' and category 'conversion'; it lands as a draft, then publish_component. Each prop needs a `target` into your own blockJson: tiers → ONE `table` prop targeting props.rows of a `section` block whose children mirror one row, ui { itemLabel: 'Tier', preview: { title: 'name' }, icon: 'tiers' }; its config.fields hold name, tagline, priceType (select, ui.control 'segmented'), price (number) and interval with `showIf` priceType eq 'fixed', contactSales and cta as `button` sub-fields, featured (boolean) and features as a nested `table` of scalars. comparison → a second `table` prop, one row per feature and one key per tier. currency/toggle/discount → ui.tab 'Display'. Variants are sibling components sharing sectionType 'Pricing' and the same prop keys.\",\n pitfalls: [\n \"Store numbers, never '$24/mo'. A price in words is its own text key, shown when the numbers are empty.\",\n \"The nested features table is the deepest a prop goes: its rows take scalars only.\",\n \"A tier added to the comparison is a new sub-field, a schema change. No Offer JSON-LD is built from prices; paste it as `schema` on update_page when needed.\",\n ],\n },\n bento: {\n why:\n \"A bento is a SLOT of 3–9 cells, and each cell is any allowed block (image, stat, quote, text, CTA card, product card, video). Size (1×1, 2×1, 1×2, 2×2) and surface (light, dark, brand) belong to the cell's place in this grid, not to the block, so they are per-slot settings rather than fields on every block. The gap is a design select; four and three columns are variants.\",\n htmlSignals: [\n \"A grid section whose cells span different column/row counts (wide, tall and large tiles beside small ones)\",\n \"Cells of mixed kinds in one grid: a photo, a big number with a label, a quote, a product card, a CTA card, a video\",\n \"Some cells on a dark or brand-coloured surface while their neighbours are light\",\n ],\n mcp:\n \"create_component with a sectionType naming the family (e.g. 'Bento'); each prop needs a `target` into your own blockJson. cells → a `slot` prop with config.multiple, minItems 3, maxItems 9, config.componentIds of your published cell components, and config.slotSettings span (select 1x1/2x1/1x2/2x2, ui.control 'cards') and tone (select light/dark/brand, ui.control 'segmented'); target a container's child list (props.children on a section, props.columns.<n> on a columns block). Each child is `{ componentId, overrides? }` and its settings sit in `_settings`. eyebrow/heading → text props; gap → select with ui.control 'segmented'. 4 columns and 3 columns are two components sharing sectionType 'Bento' with the same prop keys.\",\n pitfalls: [\n \"The kit's allow list names kit blocks; config.componentIds must name this project's published components, and the renderer needs their definitions or every cell draws empty.\",\n \"A slot child has no `_variant`: a variant is its own component.\",\n \"slotSettings are leaf fields only; a cell's own copy stays in the cell component's props.\",\n ],\n },\n journalStory: {\n why:\n \"A story is an ENTRY, one of many, with its own URL: content in groups (Content, Media, Settings) and fieldsets (Byline, a collapsed Gear review, Publishing). Authors and topics are references to their own collections, not copied names; the reviewed product is a reference to commerce. The body is the one long rich-text field. Layout, accent, internal tags, related stories and developer-only custom CSS are Settings. It proves references, rich text, SEO-friendly limits (title, excerpt) and changed-since-publish.\",\n htmlSignals: [\n \"An <article> (often itemtype BlogPosting) with an <h1>, a dek <p>, a byline with <a rel=\\\"author\\\"> and <time datetime>\",\n \"A cover <figure> with <img> and <figcaption> above a prose body of <h2>, <p>, lists, figures, tables and code\",\n \"A topic link above the title and a reading time (\\\"7 min read\\\") in the byline\",\n \"One of many pages under a shared route such as /blog/<slug>\",\n ],\n mcp:\n \"Not a component: create_content_model for the stories (a collection with urlPattern '/blog/:slug' and one dynamic page), and create_content_entry per story. Find or create the author and topic entries first and reference them by id. title, slug, excerpt, cover, gallery and film are fields; body is the ONE `document` field (top level, at most one per schema); dates are ISO 8601 with their offset. Publish authors and topics, then the post, then the template page. The `component` shape below is props-shaped only for comparison; if you place a story teaser as a component, each prop needs a `target` into your own blockJson.\",\n pitfalls: [\n \"Never model SEO fields: entry meta (metaTitle, metaDescription, og, canonical) goes in update_content_entry `meta`, and BlogPosting markup is automatic for a collection with a body, a date and an author.\",\n \"Reading time is computed by the template; no field stores it today, so don't copy \\\"7 min read\\\" into readingTime.\",\n \"Bind the body wrapper as kind `document`, never `richtext`, or a save repaints the article from plain text.\",\n ],\n },\n hero: {\n why:\n \"The opening band: an eyebrow, a headline (required, 90 max, 60 recommended), supporting text, two buttons and a proof line of rating plus label. Each button is one unit, so label, link and look travel together. The proof is a small object because the stars are drawn from the number. Media (a required image, an optional background video) and Design (alignment, theme, overlay, fill-the-screen) are their own tabs, so copy, media and look never mix; split, centered and full-bleed are variants.\",\n htmlSignals: [\n \"The first <section> after the header with one <h1>, a short eyebrow <p> above it and a lede <p> below\",\n \"Two links styled as buttons (btn-primary / btn-ghost), sometimes with an arrow icon\",\n \"A <picture>/<img> beside the copy (split) or absolutely positioned behind it with a dark scrim <div> (full-bleed)\",\n \"A rating line: star glyphs with aria-label=\\\"Rated 4.8 out of 5\\\" and \\\"from 310 reviews\\\"\",\n ],\n mcp:\n \"create_component with sectionType 'Hero' and category 'hero'; root is a `section` block with `style`, content in props.children. Each prop needs a `target` into your own blockJson: eyebrow/body → text props on text blocks (props.html), heading → props.text of a level-1 heading block, primary/secondary → one `button` prop each (label, link and look in one unit) on a button block's `props`, image → an `image` prop on an image block's props.src plus a text prop on props.alt, video → a video block's props.url, proof → an `object` prop with config.fields rating (number) and label (text). Put image/video in ui.tab 'Media' and align/theme/overlay/fullHeight in ui.tab 'Design' (theme with ui.control 'segmented'). Split image, Centered and Full-bleed image are three components sharing sectionType 'Hero' with the same prop keys.\",\n pitfalls: [\n \"Overlay and height have no section token today: the scrim and spacing stay in the template's classes unless the template reads those props.\",\n \"object-position is the image's focal point (50% 35% → { x: 0.5, y: 0.35 }); store the number 4.8, never the star glyphs.\",\n \"A variant that renames a key (title vs heading) silently drops that content on a swap.\",\n ],\n },\n};\n"],"mappings":";AAQA,IAAa,aAA4C;CACvD,KAAK;EACH,KACE;EACF,aAAa;GACX;GACA;GACA;GACA;EACF;EACA,KACE;EACF,UAAU;GACR;GACA;GACA;EACF;CACF;CACA,UAAU;EACR,KACE;EACF,aAAa;GACX;GACA;GACA;GACA;EACF;EACA,KACE;EACF,UAAU;GACR;GACA;GACA;EACF;CACF;CACA,MAAM;EACJ,KACE;EACF,aAAa;GACX;GACA;GACA;EACF;EACA,KACE;EACF,UAAU;GACR;GACA;GACA;EACF;CACF;CACA,SAAS;EACP,KACE;EACF,aAAa;GACX;GACA;GACA;GACA;GACA;EACF;EACA,KACE;EACF,UAAU;GACR;GACA;GACA;EACF;CACF;CACA,OAAO;EACL,KACE;EACF,aAAa;GACX;GACA;GACA;EACF;EACA,KACE;EACF,UAAU;GACR;GACA;GACA;EACF;CACF;CACA,cAAc;EACZ,KACE;EACF,aAAa;GACX;GACA;GACA;GACA;EACF;EACA,KACE;EACF,UAAU;GACR;GACA;GACA;EACF;CACF;CACA,MAAM;EACJ,KACE;EACF,aAAa;GACX;GACA;GACA;GACA;EACF;EACA,KACE;EACF,UAAU;GACR;GACA;GACA;EACF;CACF;AACF"}
@@ -0,0 +1,40 @@
1
+ import { type EntryStats } from "./analysis";
2
+ import { type CatalogCategory, type CatalogItem } from "./catalog";
3
+ export type CoverageView = "tags" | "types" | "features";
4
+ export interface CoverageColumn {
5
+ key: string;
6
+ label: string;
7
+ hint?: string;
8
+ /** 0 when the entry does not test it; a count for field types, 1 otherwise */
9
+ get: (it: CatalogItem, s: EntryStats) => number;
10
+ }
11
+ export interface CoverageRow {
12
+ it: CatalogItem;
13
+ s: EntryStats;
14
+ }
15
+ export interface Coverage {
16
+ rows: CoverageRow[];
17
+ columns: CoverageColumn[];
18
+ /** per column: how many entries test it */
19
+ totals: number[];
20
+ /** columns under the bar: fewer than 3 entries for edge cases, none for field types; never flagged for features */
21
+ thin: {
22
+ column: CoverageColumn;
23
+ count: number;
24
+ }[];
25
+ categories: {
26
+ category: CatalogCategory;
27
+ count: number;
28
+ }[];
29
+ facts: {
30
+ sections: number;
31
+ categories: number;
32
+ tagsCovered: number;
33
+ tagsTotal: number;
34
+ typesUsed: number;
35
+ typesTotal: number;
36
+ fields: number;
37
+ deepest: number;
38
+ };
39
+ }
40
+ export declare function coverageOf(view: CoverageView, withCore: boolean, catalog?: CatalogItem[]): Coverage;
@@ -0,0 +1,59 @@
1
+ import { FEATURE_COLUMNS, TYPE_COLUMNS, statsOf } from "./analysis.js";
2
+ import { CATALOG, EDGE_TAGS, blocksFor, categoriesOf } from "./catalog.js";
3
+ //#region src/library/coverage.ts
4
+ /** Field-type columns: the fixed reading order, then any type the schema language grows later, sorted. */
5
+ function typeColumns(rows) {
6
+ const extra = /* @__PURE__ */ new Set();
7
+ for (const r of rows) for (const t of Object.keys(r.s.types)) if (!TYPE_COLUMNS.includes(t)) extra.add(t);
8
+ return [...TYPE_COLUMNS, ...[...extra].sort()];
9
+ }
10
+ function coverageOf(view, withCore, catalog = CATALOG) {
11
+ const items = catalog.filter((c) => withCore || !c.core);
12
+ const rows = items.map((it) => ({
13
+ it,
14
+ s: statsOf(it, blocksFor(it).resolve)
15
+ }));
16
+ const types = typeColumns(rows);
17
+ const columns = view === "tags" ? EDGE_TAGS.map((t) => ({
18
+ key: t.tag,
19
+ label: t.label,
20
+ hint: t.hint,
21
+ get: (it) => it.tags.includes(t.tag) ? 1 : 0
22
+ })) : view === "types" ? types.map((t) => ({
23
+ key: t,
24
+ label: t,
25
+ get: (_it, s) => s.types[t] ?? 0
26
+ })) : FEATURE_COLUMNS.map((f) => ({
27
+ key: f.key,
28
+ label: f.label,
29
+ get: (_it, s) => s.features[f.key] ? 1 : 0
30
+ }));
31
+ const totals = columns.map((c) => rows.reduce((n, r) => n + (c.get(r.it, r.s) > 0 ? 1 : 0), 0));
32
+ const bar = view === "tags" ? 3 : 1;
33
+ const thin = view === "features" ? [] : columns.map((column, i) => ({
34
+ column,
35
+ count: totals[i]
36
+ })).filter((x) => x.count < bar);
37
+ const categories = categoriesOf(items);
38
+ return {
39
+ rows,
40
+ columns,
41
+ totals,
42
+ thin,
43
+ categories,
44
+ facts: {
45
+ sections: rows.length,
46
+ categories: categories.length,
47
+ tagsCovered: EDGE_TAGS.filter((t) => rows.some((r) => r.it.tags.includes(t.tag))).length,
48
+ tagsTotal: EDGE_TAGS.length,
49
+ typesUsed: types.filter((t) => rows.some((r) => (r.s.types[t] ?? 0) > 0)).length,
50
+ typesTotal: types.length,
51
+ fields: rows.reduce((n, r) => n + r.s.fields, 0),
52
+ deepest: rows.reduce((m, r) => Math.max(m, r.s.depth), 0)
53
+ }
54
+ };
55
+ }
56
+ //#endregion
57
+ export { coverageOf };
58
+
59
+ //# sourceMappingURL=coverage.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"coverage.js","names":[],"sources":["../../src/library/coverage.ts"],"sourcesContent":["/**\n * Coverage matrix logic: what the library actually tests. Entries against edge cases, field types (how many\n * fields of each) or schema features, plus the deepest drill-in per entry and the columns nothing (or too little)\n * tests. The V2 /kit/coverage page computed this inline; it lives here so the page only draws it.\n */\nimport type { SchemaType } from \"../schema/types\";\nimport { FEATURE_COLUMNS, statsOf, TYPE_COLUMNS, type EntryStats } from \"./analysis\";\nimport { blocksFor, CATALOG, categoriesOf, EDGE_TAGS, type CatalogCategory, type CatalogItem } from \"./catalog\";\n\nexport type CoverageView = \"tags\" | \"types\" | \"features\";\n\nexport interface CoverageColumn {\n key: string;\n label: string;\n hint?: string;\n /** 0 when the entry does not test it; a count for field types, 1 otherwise */\n get: (it: CatalogItem, s: EntryStats) => number;\n}\n\nexport interface CoverageRow {\n it: CatalogItem;\n s: EntryStats;\n}\n\nexport interface Coverage {\n rows: CoverageRow[];\n columns: CoverageColumn[];\n /** per column: how many entries test it */\n totals: number[];\n /** columns under the bar: fewer than 3 entries for edge cases, none for field types; never flagged for features */\n thin: { column: CoverageColumn; count: number }[];\n categories: { category: CatalogCategory; count: number }[];\n facts: { sections: number; categories: number; tagsCovered: number; tagsTotal: number; typesUsed: number; typesTotal: number; fields: number; deepest: number };\n}\n\n/** Field-type columns: the fixed reading order, then any type the schema language grows later, sorted. */\nfunction typeColumns(rows: CoverageRow[]): SchemaType[] {\n const extra = new Set<string>();\n for (const r of rows) for (const t of Object.keys(r.s.types)) if (!(TYPE_COLUMNS as string[]).includes(t)) extra.add(t);\n return [...TYPE_COLUMNS, ...([...extra].sort() as SchemaType[])];\n}\n\nexport function coverageOf(view: CoverageView, withCore: boolean, catalog: CatalogItem[] = CATALOG): Coverage {\n const items = catalog.filter((c) => withCore || !c.core);\n const rows = items.map((it) => ({ it, s: statsOf(it, blocksFor(it).resolve) }));\n const types = typeColumns(rows);\n const columns: CoverageColumn[] =\n view === \"tags\"\n ? EDGE_TAGS.map((t) => ({ key: t.tag, label: t.label, hint: t.hint, get: (it) => (it.tags.includes(t.tag) ? 1 : 0) }))\n : view === \"types\"\n ? types.map((t) => ({ key: t, label: t, get: (_it, s) => s.types[t] ?? 0 }))\n : FEATURE_COLUMNS.map((f) => ({ key: f.key, label: f.label, get: (_it, s) => (s.features[f.key] ? 1 : 0) }));\n const totals = columns.map((c) => rows.reduce((n, r) => n + (c.get(r.it, r.s) > 0 ? 1 : 0), 0));\n const bar = view === \"tags\" ? 3 : 1;\n const thin = view === \"features\" ? [] : columns.map((column, i) => ({ column, count: totals[i] })).filter((x) => x.count < bar);\n const categories = categoriesOf(items);\n return {\n rows,\n columns,\n totals,\n thin,\n categories,\n facts: {\n sections: rows.length,\n categories: categories.length,\n tagsCovered: EDGE_TAGS.filter((t) => rows.some((r) => r.it.tags.includes(t.tag))).length,\n tagsTotal: EDGE_TAGS.length,\n typesUsed: types.filter((t) => rows.some((r) => (r.s.types[t] ?? 0) > 0)).length,\n typesTotal: types.length,\n fields: rows.reduce((n, r) => n + r.s.fields, 0),\n deepest: rows.reduce((m, r) => Math.max(m, r.s.depth), 0),\n },\n };\n}\n"],"mappings":";;;;AAoCA,SAAS,YAAY,MAAmC;CACtD,MAAM,wBAAQ,IAAI,IAAY;CAC9B,KAAK,MAAM,KAAK,MAAM,KAAK,MAAM,KAAK,OAAO,KAAK,EAAE,EAAE,KAAK,GAAG,IAAI,CAAE,aAA0B,SAAS,CAAC,GAAG,MAAM,IAAI,CAAC;CACtH,OAAO,CAAC,GAAG,cAAc,GAAI,CAAC,GAAG,KAAK,CAAC,CAAC,KAAK,CAAkB;AACjE;AAEA,SAAgB,WAAW,MAAoB,UAAmB,UAAyB,SAAmB;CAC5G,MAAM,QAAQ,QAAQ,QAAQ,MAAM,YAAY,CAAC,EAAE,IAAI;CACvD,MAAM,OAAO,MAAM,KAAK,QAAQ;EAAE;EAAI,GAAG,QAAQ,IAAI,UAAU,EAAE,CAAC,CAAC,OAAO;CAAE,EAAE;CAC9E,MAAM,QAAQ,YAAY,IAAI;CAC9B,MAAM,UACJ,SAAS,SACL,UAAU,KAAK,OAAO;EAAE,KAAK,EAAE;EAAK,OAAO,EAAE;EAAO,MAAM,EAAE;EAAM,MAAM,OAAQ,GAAG,KAAK,SAAS,EAAE,GAAG,IAAI,IAAI;CAAG,EAAE,IACnH,SAAS,UACP,MAAM,KAAK,OAAO;EAAE,KAAK;EAAG,OAAO;EAAG,MAAM,KAAK,MAAM,EAAE,MAAM,MAAM;CAAE,EAAE,IACzE,gBAAgB,KAAK,OAAO;EAAE,KAAK,EAAE;EAAK,OAAO,EAAE;EAAO,MAAM,KAAK,MAAO,EAAE,SAAS,EAAE,OAAO,IAAI;CAAG,EAAE;CACjH,MAAM,SAAS,QAAQ,KAAK,MAAM,KAAK,QAAQ,GAAG,MAAM,KAAK,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,IAAI,IAAI,IAAI,IAAI,CAAC,CAAC;CAC9F,MAAM,MAAM,SAAS,SAAS,IAAI;CAClC,MAAM,OAAO,SAAS,aAAa,CAAC,IAAI,QAAQ,KAAK,QAAQ,OAAO;EAAE;EAAQ,OAAO,OAAO;CAAG,EAAE,CAAC,CAAC,QAAQ,MAAM,EAAE,QAAQ,GAAG;CAC9H,MAAM,aAAa,aAAa,KAAK;CACrC,OAAO;EACL;EACA;EACA;EACA;EACA;EACA,OAAO;GACL,UAAU,KAAK;GACf,YAAY,WAAW;GACvB,aAAa,UAAU,QAAQ,MAAM,KAAK,MAAM,MAAM,EAAE,GAAG,KAAK,SAAS,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC;GAClF,WAAW,UAAU;GACrB,WAAW,MAAM,QAAQ,MAAM,KAAK,MAAM,OAAO,EAAE,EAAE,MAAM,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC;GAC1E,YAAY,MAAM;GAClB,QAAQ,KAAK,QAAQ,GAAG,MAAM,IAAI,EAAE,EAAE,QAAQ,CAAC;GAC/C,SAAS,KAAK,QAAQ,GAAG,MAAM,KAAK,IAAI,GAAG,EAAE,EAAE,KAAK,GAAG,CAAC;EAC1D;CACF;AACF"}
@@ -0,0 +1,2 @@
1
+ import type { KitEntry } from "../types";
2
+ export declare const ENTRIES: KitEntry[];