@bettercms-ai/kit 1.0.0 → 2.0.0-next.1

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 (619) 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 +94 -31
  8. package/dist/adapters/lossy.js +419 -0
  9. package/dist/adapters/lossy.js.map +1 -0
  10. package/{adapters → dist/adapters}/prod-types.d.ts +91 -26
  11. package/{adapters → dist/adapters}/prod-types.js +82 -13
  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 +1038 -204
  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} +131 -2
  22. package/{context.js → dist/context.js} +44 -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/dist/controls/form-picker-register.d.ts +7 -0
  50. package/{controls → dist/controls}/form-picker-register.js +2 -6
  51. package/dist/controls/form-picker-register.js.map +1 -0
  52. package/{controls → dist/controls}/form-picker.js +11 -9
  53. package/dist/controls/form-picker.js.map +1 -0
  54. package/{controls → dist/controls}/icon-register.js +1 -1
  55. package/dist/controls/icon-register.js.map +1 -0
  56. package/{controls → dist/controls}/icon.d.ts +4 -2
  57. package/{controls → dist/controls}/icon.js +32 -27
  58. package/dist/controls/icon.js.map +1 -0
  59. package/{controls → dist/controls}/index.d.ts +1 -1
  60. package/{controls → dist/controls}/index.js +4 -3
  61. package/dist/controls/index.js.map +1 -0
  62. package/{controls → dist/controls}/json-register.js +1 -1
  63. package/dist/controls/json-register.js.map +1 -0
  64. package/{controls → dist/controls}/json.js +13 -3
  65. package/dist/controls/json.js.map +1 -0
  66. package/{controls → dist/controls}/link.js +116 -200
  67. package/dist/controls/link.js.map +1 -0
  68. package/{controls → dist/controls}/location-register.js +1 -1
  69. package/dist/controls/location-register.js.map +1 -0
  70. package/{controls → dist/controls}/location.js +59 -40
  71. package/dist/controls/location.js.map +1 -0
  72. package/{controls → dist/controls}/media-register.js +1 -1
  73. package/dist/controls/media-register.js.map +1 -0
  74. package/{controls → dist/controls}/media-services.d.ts +6 -0
  75. package/dist/controls/media-services.js +0 -0
  76. package/{controls → dist/controls}/media.d.ts +21 -4
  77. package/{controls → dist/controls}/media.js +407 -130
  78. package/dist/controls/media.js.map +1 -0
  79. package/{controls → dist/controls}/number.js +10 -9
  80. package/dist/controls/number.js.map +1 -0
  81. package/{controls → dist/controls}/reference-register.js +1 -1
  82. package/dist/controls/reference-register.js.map +1 -0
  83. package/{controls → dist/controls}/reference-services.d.ts +4 -0
  84. package/dist/controls/reference-services.js +0 -0
  85. package/{controls → dist/controls}/reference.d.ts +1 -1
  86. package/{controls → dist/controls}/reference.js +93 -77
  87. package/dist/controls/reference.js.map +1 -0
  88. package/dist/controls/rich-text/article-shell.d.ts +145 -0
  89. package/dist/controls/rich-text/article-shell.js +510 -0
  90. package/dist/controls/rich-text/article-shell.js.map +1 -0
  91. package/dist/controls/rich-text/author.d.ts +25 -0
  92. package/dist/controls/rich-text/author.js +104 -0
  93. package/dist/controls/rich-text/author.js.map +1 -0
  94. package/dist/controls/rich-text/blocks.d.ts +60 -0
  95. package/{controls → dist/controls}/rich-text/blocks.js +164 -389
  96. package/dist/controls/rich-text/blocks.js.map +1 -0
  97. package/dist/controls/rich-text/button.d.ts +23 -0
  98. package/dist/controls/rich-text/button.js +85 -0
  99. package/dist/controls/rich-text/button.js.map +1 -0
  100. package/{controls → dist/controls}/rich-text/catalog.d.ts +7 -4
  101. package/{controls → dist/controls}/rich-text/catalog.js +94 -68
  102. package/dist/controls/rich-text/catalog.js.map +1 -0
  103. package/dist/controls/rich-text/checklist.d.ts +24 -0
  104. package/dist/controls/rich-text/checklist.js +115 -0
  105. package/dist/controls/rich-text/checklist.js.map +1 -0
  106. package/{controls → dist/controls}/rich-text/codec.d.ts +9 -1
  107. package/{controls → dist/controls}/rich-text/codec.js +7 -2
  108. package/dist/controls/rich-text/codec.js.map +1 -0
  109. package/dist/controls/rich-text/columns.d.ts +41 -0
  110. package/dist/controls/rich-text/columns.js +181 -0
  111. package/dist/controls/rich-text/columns.js.map +1 -0
  112. package/{controls → dist/controls}/rich-text/component-card.d.ts +1 -1
  113. package/{controls → dist/controls}/rich-text/component-card.js +417 -99
  114. package/dist/controls/rich-text/component-card.js.map +1 -0
  115. package/dist/controls/rich-text/component-panel.d.ts +47 -0
  116. package/dist/controls/rich-text/component-panel.js +141 -0
  117. package/dist/controls/rich-text/component-panel.js.map +1 -0
  118. package/{controls → dist/controls}/rich-text/control.d.ts +1 -2
  119. package/{controls → dist/controls}/rich-text/control.js +84 -42
  120. package/dist/controls/rich-text/control.js.map +1 -0
  121. package/{controls → dist/controls}/rich-text/dom.d.ts +53 -9
  122. package/{controls → dist/controls}/rich-text/dom.js +388 -50
  123. package/dist/controls/rich-text/dom.js.map +1 -0
  124. package/{controls → dist/controls}/rich-text/editor.d.ts +7 -0
  125. package/{controls → dist/controls}/rich-text/editor.js +226 -44
  126. package/dist/controls/rich-text/editor.js.map +1 -0
  127. package/dist/controls/rich-text/embed.d.ts +28 -0
  128. package/dist/controls/rich-text/embed.js +210 -0
  129. package/dist/controls/rich-text/embed.js.map +1 -0
  130. package/{controls → dist/controls}/rich-text/floating.d.ts +6 -1
  131. package/{controls → dist/controls}/rich-text/floating.js +35 -18
  132. package/dist/controls/rich-text/floating.js.map +1 -0
  133. package/dist/controls/rich-text/footnote.d.ts +41 -0
  134. package/dist/controls/rich-text/footnote.js +185 -0
  135. package/dist/controls/rich-text/footnote.js.map +1 -0
  136. package/dist/controls/rich-text/gallery.d.ts +28 -0
  137. package/dist/controls/rich-text/gallery.js +167 -0
  138. package/dist/controls/rich-text/gallery.js.map +1 -0
  139. package/{controls → dist/controls}/rich-text/index.js +1 -1
  140. package/dist/controls/rich-text/index.js.map +1 -0
  141. package/{controls → dist/controls}/rich-text/link-form.d.ts +3 -1
  142. package/dist/controls/rich-text/link-form.js +147 -0
  143. package/dist/controls/rich-text/link-form.js.map +1 -0
  144. package/{controls → dist/controls}/rich-text/markdown.js +4 -2
  145. package/dist/controls/rich-text/markdown.js.map +1 -0
  146. package/{controls → dist/controls}/rich-text/ops.js +17 -15
  147. package/dist/controls/rich-text/ops.js.map +1 -0
  148. package/dist/controls/rich-text/plain.d.ts +17 -0
  149. package/dist/controls/rich-text/plain.js +44 -0
  150. package/dist/controls/rich-text/plain.js.map +1 -0
  151. package/dist/controls/rich-text/related.d.ts +36 -0
  152. package/dist/controls/rich-text/related.js +213 -0
  153. package/dist/controls/rich-text/related.js.map +1 -0
  154. package/dist/controls/rich-text/toc.d.ts +46 -0
  155. package/dist/controls/rich-text/toc.js +161 -0
  156. package/dist/controls/rich-text/toc.js.map +1 -0
  157. package/{controls → dist/controls}/rich-text/toolbar.d.ts +6 -2
  158. package/{controls → dist/controls}/rich-text/toolbar.js +12 -7
  159. package/dist/controls/rich-text/toolbar.js.map +1 -0
  160. package/{controls → dist/controls}/scale.js +5 -5
  161. package/dist/controls/scale.js.map +1 -0
  162. package/dist/controls/slot-register.d.ts +6 -0
  163. package/{controls → dist/controls}/slot-register.js +2 -5
  164. package/dist/controls/slot-register.js.map +1 -0
  165. package/{controls → dist/controls}/slot-services.d.ts +25 -0
  166. package/dist/controls/slot-services.js +155 -0
  167. package/dist/controls/slot-services.js.map +1 -0
  168. package/{controls → dist/controls}/slot.js +42 -24
  169. package/dist/controls/slot.js.map +1 -0
  170. package/{controls → dist/controls}/table/index.js +1 -1
  171. package/dist/controls/table/index.js.map +1 -0
  172. package/{controls → dist/controls}/table/prod.js +3 -3
  173. package/dist/controls/table/prod.js.map +1 -0
  174. package/{controls → dist/controls}/table/refs.js +13 -2
  175. package/dist/controls/table/refs.js.map +1 -0
  176. package/{controls → dist/controls}/table/stored.js +1 -1
  177. package/dist/controls/table/stored.js.map +1 -0
  178. package/{controls → dist/controls}/table/table-editor.js +51 -48
  179. package/dist/controls/table/table-editor.js.map +1 -0
  180. package/{controls → dist/controls}/table/table-link.js +3 -3
  181. package/dist/controls/table/table-link.js.map +1 -0
  182. package/{controls → dist/controls}/table/table.js +3 -3
  183. package/dist/controls/table/table.js.map +1 -0
  184. package/{controls → dist/controls}/text.d.ts +2 -2
  185. package/{controls → dist/controls}/text.js +78 -43
  186. package/dist/controls/text.js.map +1 -0
  187. package/dist/controls/unknown-value.d.ts +17 -0
  188. package/dist/controls/unknown-value.js +66 -0
  189. package/dist/controls/unknown-value.js.map +1 -0
  190. package/dist/core/core.d.ts +70 -0
  191. package/dist/core/core.js +187 -0
  192. package/dist/core/core.js.map +1 -0
  193. package/dist/core/facets.d.ts +355 -0
  194. package/dist/core/facets.js +342 -0
  195. package/dist/core/facets.js.map +1 -0
  196. package/dist/core/index.d.ts +3 -0
  197. package/dist/core/index.js +3 -0
  198. package/{engine → dist/engine}/array.js +34 -21
  199. package/dist/engine/array.js.map +1 -0
  200. package/{engine → dist/engine}/bits.js +1 -1
  201. package/dist/engine/bits.js.map +1 -0
  202. package/{engine → dist/engine}/breadcrumb.d.ts +3 -3
  203. package/{engine → dist/engine}/breadcrumb.js +12 -36
  204. package/dist/engine/breadcrumb.js.map +1 -0
  205. package/{engine → dist/engine}/expand.d.ts +2 -4
  206. package/{engine → dist/engine}/expand.js +5 -22
  207. package/dist/engine/expand.js.map +1 -0
  208. package/{engine → dist/engine}/field-list.js +1 -1
  209. package/dist/engine/field-list.js.map +1 -0
  210. package/{engine → dist/engine}/field-shell.js +249 -121
  211. package/dist/engine/field-shell.js.map +1 -0
  212. package/{engine → dist/engine}/frame.d.ts +3 -1
  213. package/{engine → dist/engine}/frame.js +16 -14
  214. package/dist/engine/frame.js.map +1 -0
  215. package/{engine → dist/engine}/group-summary.d.ts +2 -1
  216. package/{engine → dist/engine}/group-summary.js +7 -3
  217. package/dist/engine/group-summary.js.map +1 -0
  218. package/{engine → dist/engine}/grouping.d.ts +19 -5
  219. package/{engine → dist/engine}/grouping.js +193 -21
  220. package/dist/engine/grouping.js.map +1 -0
  221. package/{engine → dist/engine}/item-list.d.ts +11 -1
  222. package/{engine → dist/engine}/item-list.js +35 -13
  223. package/dist/engine/item-list.js.map +1 -0
  224. package/{engine → dist/engine}/kit-field.js +45 -10
  225. package/dist/engine/kit-field.js.map +1 -0
  226. package/{engine → dist/engine}/schema-form.d.ts +27 -2
  227. package/{engine → dist/engine}/schema-form.js +182 -40
  228. package/dist/engine/schema-form.js.map +1 -0
  229. package/{engine → dist/engine}/slot.js +5 -15
  230. package/dist/engine/slot.js.map +1 -0
  231. package/dist/index.js +58 -0
  232. package/dist/index.js.map +1 -0
  233. package/{kit.css → dist/kit.css} +19 -0
  234. package/{lib → dist/lib}/cn.js +7 -4
  235. package/dist/lib/cn.js.map +1 -0
  236. package/{lib → dist/lib}/columns.js +4 -1
  237. package/dist/lib/columns.js.map +1 -0
  238. package/{lib → dist/lib}/frames.js +2 -2
  239. package/dist/lib/frames.js.map +1 -0
  240. package/dist/lib/icon-image.d.ts +10 -0
  241. package/dist/lib/icon-image.js +8 -0
  242. package/dist/lib/icon-image.js.map +1 -0
  243. package/{lib → dist/lib}/icons.js +4 -3
  244. package/dist/lib/icons.js.map +1 -0
  245. package/dist/lib/input-modality.d.ts +11 -0
  246. package/dist/lib/input-modality.js +47 -0
  247. package/dist/lib/input-modality.js.map +1 -0
  248. package/dist/lib/key-event.d.ts +11 -0
  249. package/dist/lib/key-event.js +16 -0
  250. package/dist/lib/key-event.js.map +1 -0
  251. package/{lib → dist/lib}/path.js +4 -2
  252. package/dist/lib/path.js.map +1 -0
  253. package/{lib → dist/lib}/schema.d.ts +34 -3
  254. package/{lib → dist/lib}/schema.js +110 -13
  255. package/dist/lib/schema.js.map +1 -0
  256. package/{lib → dist/lib}/utils.js +1 -1
  257. package/dist/lib/utils.js.map +1 -0
  258. package/{lib → dist/lib}/validate.d.ts +11 -1
  259. package/{lib → dist/lib}/validate.js +85 -11
  260. package/dist/lib/validate.js.map +1 -0
  261. package/dist/library/analysis.d.ts +23 -0
  262. package/dist/library/analysis.js +160 -0
  263. package/dist/library/analysis.js.map +1 -0
  264. package/dist/library/catalog.d.ts +57 -0
  265. package/dist/library/catalog.js +307 -0
  266. package/dist/library/catalog.js.map +1 -0
  267. package/dist/library/coreNotes.d.ts +8 -0
  268. package/dist/library/coreNotes.js +111 -0
  269. package/dist/library/coreNotes.js.map +1 -0
  270. package/dist/library/coverage.d.ts +40 -0
  271. package/dist/library/coverage.js +59 -0
  272. package/dist/library/coverage.js.map +1 -0
  273. package/dist/library/entries/advanced.entries.d.ts +2 -0
  274. package/dist/library/entries/advanced.entries.js +6579 -0
  275. package/dist/library/entries/advanced.entries.js.map +1 -0
  276. package/dist/library/entries/commerce.entries.d.ts +2 -0
  277. package/dist/library/entries/commerce.entries.js +4140 -0
  278. package/dist/library/entries/commerce.entries.js.map +1 -0
  279. package/dist/library/entries/company.entries.d.ts +2 -0
  280. package/dist/library/entries/company.entries.js +2731 -0
  281. package/dist/library/entries/company.entries.js.map +1 -0
  282. package/dist/library/entries/conversion.entries.d.ts +2 -0
  283. package/dist/library/entries/conversion.entries.js +3707 -0
  284. package/dist/library/entries/conversion.entries.js.map +1 -0
  285. package/dist/library/entries/data.entries.d.ts +7 -0
  286. package/dist/library/entries/data.entries.js +4613 -0
  287. package/dist/library/entries/data.entries.js.map +1 -0
  288. package/dist/library/entries/events.entries.d.ts +2 -0
  289. package/dist/library/entries/events.entries.js +3428 -0
  290. package/dist/library/entries/events.entries.js.map +1 -0
  291. package/dist/library/entries/features.entries.d.ts +2 -0
  292. package/dist/library/entries/features.entries.js +3157 -0
  293. package/dist/library/entries/features.entries.js.map +1 -0
  294. package/dist/library/entries/heroes.entries.d.ts +2 -0
  295. package/dist/library/entries/heroes.entries.js +3401 -0
  296. package/dist/library/entries/heroes.entries.js.map +1 -0
  297. package/dist/library/entries/index.d.ts +3 -0
  298. package/dist/library/entries/index.js +35 -0
  299. package/dist/library/entries/index.js.map +1 -0
  300. package/dist/library/entries/listings.entries.d.ts +2 -0
  301. package/dist/library/entries/listings.entries.js +2976 -0
  302. package/dist/library/entries/listings.entries.js.map +1 -0
  303. package/dist/library/entries/longform.entries.d.ts +2 -0
  304. package/dist/library/entries/longform.entries.js +4227 -0
  305. package/dist/library/entries/longform.entries.js.map +1 -0
  306. package/dist/library/entries/media.entries.d.ts +2 -0
  307. package/dist/library/entries/media.entries.js +2781 -0
  308. package/dist/library/entries/media.entries.js.map +1 -0
  309. package/dist/library/entries/navigation.entries.d.ts +2 -0
  310. package/dist/library/entries/navigation.entries.js +4011 -0
  311. package/dist/library/entries/navigation.entries.js.map +1 -0
  312. package/dist/library/entries/pricing.entries.d.ts +2 -0
  313. package/dist/library/entries/pricing.entries.js +2383 -0
  314. package/dist/library/entries/pricing.entries.js.map +1 -0
  315. package/dist/library/entries/social-proof.entries.d.ts +2 -0
  316. package/dist/library/entries/social-proof.entries.js +2297 -0
  317. package/dist/library/entries/social-proof.entries.js.map +1 -0
  318. package/dist/library/examples/bento.d.ts +92 -0
  319. package/dist/library/examples/bento.js +201 -0
  320. package/dist/library/examples/bento.js.map +1 -0
  321. package/dist/library/examples/blocks.d.ts +14 -0
  322. package/dist/library/examples/blocks.js +313 -0
  323. package/dist/library/examples/blocks.js.map +1 -0
  324. package/dist/library/examples/faq.d.ts +28 -0
  325. package/dist/library/examples/faq.js +230 -0
  326. package/dist/library/examples/faq.js.map +1 -0
  327. package/dist/library/examples/hero.d.ts +43 -0
  328. package/dist/library/examples/hero.js +222 -0
  329. package/dist/library/examples/hero.js.map +1 -0
  330. package/dist/library/examples/index.d.ts +36 -0
  331. package/dist/library/examples/index.js +109 -0
  332. package/dist/library/examples/index.js.map +1 -0
  333. package/dist/library/examples/journalStory.d.ts +93 -0
  334. package/dist/library/examples/journalStory.js +338 -0
  335. package/dist/library/examples/journalStory.js.map +1 -0
  336. package/dist/library/examples/megaMenu.d.ts +134 -0
  337. package/dist/library/examples/megaMenu.js +442 -0
  338. package/dist/library/examples/megaMenu.js.map +1 -0
  339. package/dist/library/examples/pricing.d.ts +103 -0
  340. package/dist/library/examples/pricing.js +479 -0
  341. package/dist/library/examples/pricing.js.map +1 -0
  342. package/dist/library/examples/tabs.d.ts +87 -0
  343. package/dist/library/examples/tabs.js +180 -0
  344. package/dist/library/examples/tabs.js.map +1 -0
  345. package/dist/library/export.d.ts +42 -0
  346. package/dist/library/export.js +80 -0
  347. package/dist/library/export.js.map +1 -0
  348. package/dist/library/index.d.ts +13 -0
  349. package/dist/library/index.js +6 -0
  350. package/dist/library/kit-catalog.json +1511 -0
  351. package/dist/library/types.d.ts +42 -0
  352. package/dist/library/types.js +0 -0
  353. package/{schema → dist/schema}/adapters.js +1 -2
  354. package/dist/schema/adapters.js.map +1 -0
  355. package/{schema → dist/schema}/help.d.ts +2 -0
  356. package/{schema → dist/schema}/help.js +6 -4
  357. package/dist/schema/help.js.map +1 -0
  358. package/{schema → dist/schema}/scale.js +1 -1
  359. package/dist/schema/scale.js.map +1 -0
  360. package/{schema → dist/schema}/sources.js +1 -1
  361. package/dist/schema/sources.js.map +1 -0
  362. package/{schema → dist/schema}/table.js +11 -10
  363. package/dist/schema/table.js.map +1 -0
  364. package/{schema → dist/schema}/types.d.ts +36 -1
  365. package/{schema → dist/schema}/types.js +1 -1
  366. package/dist/schema/types.js.map +1 -0
  367. package/dist/styles.css +2 -0
  368. package/dist/table/table-view.d.ts +14 -0
  369. package/dist/table/table-view.js +140 -0
  370. package/dist/table/table-view.js.map +1 -0
  371. package/dist/table/table.css +73 -0
  372. package/dist/testing/corpus.d.ts +63 -0
  373. package/dist/testing/corpus.js +129 -0
  374. package/dist/testing/corpus.js.map +1 -0
  375. package/dist/testing/test-form.d.ts +11 -0
  376. package/dist/testing/test-form.js +38 -0
  377. package/dist/testing/test-form.js.map +1 -0
  378. package/dist/theme.css +345 -0
  379. package/dist/theme.d.ts +22 -0
  380. package/dist/theme.js +43 -0
  381. package/dist/theme.js.map +1 -0
  382. package/dist/tokens.css +542 -0
  383. package/dist/types.js +0 -0
  384. package/{ui → dist/ui}/action-tray.d.ts +1 -1
  385. package/{ui → dist/ui}/action-tray.js +20 -19
  386. package/dist/ui/action-tray.js.map +1 -0
  387. package/dist/ui/autocomplete.d.ts +58 -0
  388. package/dist/ui/autocomplete.js +194 -0
  389. package/dist/ui/autocomplete.js.map +1 -0
  390. package/{ui → dist/ui}/button.d.ts +3 -3
  391. package/{ui → dist/ui}/button.js +8 -11
  392. package/dist/ui/button.js.map +1 -0
  393. package/{ui → dist/ui}/choice-switch.js +1 -1
  394. package/dist/ui/choice-switch.js.map +1 -0
  395. package/{ui → dist/ui}/controls.js +51 -39
  396. package/dist/ui/controls.js.map +1 -0
  397. package/{ui → dist/ui}/display.d.ts +10 -3
  398. package/{ui → dist/ui}/display.js +57 -46
  399. package/dist/ui/display.js.map +1 -0
  400. package/{ui → dist/ui}/expanded-editor-modal.d.ts +2 -2
  401. package/{ui → dist/ui}/expanded-editor-modal.js +6 -6
  402. package/dist/ui/expanded-editor-modal.js.map +1 -0
  403. package/{ui → dist/ui}/field-context.js +1 -1
  404. package/dist/ui/field-context.js.map +1 -0
  405. package/{ui → dist/ui}/floating-panel.d.ts +1 -1
  406. package/{ui → dist/ui}/floating-panel.js +28 -12
  407. package/dist/ui/floating-panel.js.map +1 -0
  408. package/{ui → dist/ui}/index.d.ts +4 -0
  409. package/dist/ui/index.js +18 -0
  410. package/{ui → dist/ui}/input.d.ts +1 -1
  411. package/{ui → dist/ui}/input.js +9 -9
  412. package/dist/ui/input.js.map +1 -0
  413. package/{ui → dist/ui}/mode-bar.js +3 -3
  414. package/dist/ui/mode-bar.js.map +1 -0
  415. package/{ui → dist/ui}/overlay.d.ts +77 -5
  416. package/dist/ui/overlay.js +697 -0
  417. package/dist/ui/overlay.js.map +1 -0
  418. package/{ui → dist/ui}/path-crumbs.js +37 -3
  419. package/dist/ui/path-crumbs.js.map +1 -0
  420. package/{ui → dist/ui}/presence.js +2 -2
  421. package/dist/ui/presence.js.map +1 -0
  422. package/{ui → dist/ui}/select.js +89 -87
  423. package/dist/ui/select.js.map +1 -0
  424. package/{ui → dist/ui}/shortcut-hint.js +1 -1
  425. package/dist/ui/shortcut-hint.js.map +1 -0
  426. package/dist/ui/spinner.d.ts +24 -0
  427. package/dist/ui/spinner.js +42 -0
  428. package/dist/ui/spinner.js.map +1 -0
  429. package/dist/ui/split-button.d.ts +32 -0
  430. package/dist/ui/split-button.js +60 -0
  431. package/dist/ui/split-button.js.map +1 -0
  432. package/{ui → dist/ui}/surfaces.js +1 -1
  433. package/dist/ui/surfaces.js.map +1 -0
  434. package/dist/ui/tab.d.ts +38 -0
  435. package/dist/ui/tab.js +87 -0
  436. package/dist/ui/tab.js.map +1 -0
  437. package/dist/ui/toast.d.ts +20 -0
  438. package/dist/ui/toast.js +115 -0
  439. package/dist/ui/toast.js.map +1 -0
  440. package/{ui → dist/ui}/tooltip-root.d.ts +4 -3
  441. package/{ui → dist/ui}/tooltip-root.js +9 -8
  442. package/dist/ui/tooltip-root.js.map +1 -0
  443. package/{ui → dist/ui}/variants.js +1 -1
  444. package/dist/ui/variants.js.map +1 -0
  445. package/package.json +83 -23
  446. package/adapters/icons.js.map +0 -1
  447. package/adapters/lossy.js +0 -233
  448. package/adapters/lossy.js.map +0 -1
  449. package/adapters/prod-types.js.map +0 -1
  450. package/adapters/schema.js.map +0 -1
  451. package/adapters/values.js.map +0 -1
  452. package/brand/logo.js +0 -9
  453. package/brand/logo.js.map +0 -1
  454. package/context.js.map +0 -1
  455. package/controls/button.js.map +0 -1
  456. package/controls/c1.js.map +0 -1
  457. package/controls/c2.js.map +0 -1
  458. package/controls/choice.js.map +0 -1
  459. package/controls/code-register.js.map +0 -1
  460. package/controls/code.js.map +0 -1
  461. package/controls/color.js.map +0 -1
  462. package/controls/date-register.js.map +0 -1
  463. package/controls/date-zone.js.map +0 -1
  464. package/controls/date.js.map +0 -1
  465. package/controls/form-picker-register.d.ts +0 -1
  466. package/controls/form-picker-register.js.map +0 -1
  467. package/controls/form-picker.js.map +0 -1
  468. package/controls/icon-register.js.map +0 -1
  469. package/controls/icon.js.map +0 -1
  470. package/controls/index.js.map +0 -1
  471. package/controls/json-register.js.map +0 -1
  472. package/controls/json.js.map +0 -1
  473. package/controls/link.js.map +0 -1
  474. package/controls/location-register.js.map +0 -1
  475. package/controls/location.js.map +0 -1
  476. package/controls/media-register.js.map +0 -1
  477. package/controls/media.js.map +0 -1
  478. package/controls/number.js.map +0 -1
  479. package/controls/reference-register.js.map +0 -1
  480. package/controls/reference.js.map +0 -1
  481. package/controls/rich-text/blocks.d.ts +0 -28
  482. package/controls/rich-text/blocks.js.map +0 -1
  483. package/controls/rich-text/catalog.js.map +0 -1
  484. package/controls/rich-text/codec.js.map +0 -1
  485. package/controls/rich-text/component-card.js.map +0 -1
  486. package/controls/rich-text/control.js.map +0 -1
  487. package/controls/rich-text/dom.js.map +0 -1
  488. package/controls/rich-text/editor.js.map +0 -1
  489. package/controls/rich-text/floating.js.map +0 -1
  490. package/controls/rich-text/index.js.map +0 -1
  491. package/controls/rich-text/link-form.js +0 -111
  492. package/controls/rich-text/link-form.js.map +0 -1
  493. package/controls/rich-text/markdown.js.map +0 -1
  494. package/controls/rich-text/ops.js.map +0 -1
  495. package/controls/rich-text/toolbar.js.map +0 -1
  496. package/controls/scale.js.map +0 -1
  497. package/controls/slot-register.d.ts +0 -1
  498. package/controls/slot-register.js.map +0 -1
  499. package/controls/slot-services.js +0 -38
  500. package/controls/slot-services.js.map +0 -1
  501. package/controls/slot.js.map +0 -1
  502. package/controls/table/index.js.map +0 -1
  503. package/controls/table/prod.js.map +0 -1
  504. package/controls/table/refs.js.map +0 -1
  505. package/controls/table/stored.js.map +0 -1
  506. package/controls/table/table-editor.js.map +0 -1
  507. package/controls/table/table-link.js.map +0 -1
  508. package/controls/table/table.js.map +0 -1
  509. package/controls/text.js.map +0 -1
  510. package/engine/array.js.map +0 -1
  511. package/engine/bits.js.map +0 -1
  512. package/engine/breadcrumb.js.map +0 -1
  513. package/engine/expand.js.map +0 -1
  514. package/engine/field-list.js.map +0 -1
  515. package/engine/field-shell.js.map +0 -1
  516. package/engine/frame.js.map +0 -1
  517. package/engine/group-summary.js.map +0 -1
  518. package/engine/grouping.js.map +0 -1
  519. package/engine/item-list.js.map +0 -1
  520. package/engine/kit-field.js.map +0 -1
  521. package/engine/schema-form.js.map +0 -1
  522. package/engine/slot.js.map +0 -1
  523. package/index.js +0 -55
  524. package/index.js.map +0 -1
  525. package/lib/cn.js.map +0 -1
  526. package/lib/columns.js.map +0 -1
  527. package/lib/frames.js.map +0 -1
  528. package/lib/icons.js.map +0 -1
  529. package/lib/path.js.map +0 -1
  530. package/lib/schema.js.map +0 -1
  531. package/lib/utils.js.map +0 -1
  532. package/lib/validate.js.map +0 -1
  533. package/schema/adapters.js.map +0 -1
  534. package/schema/help.js.map +0 -1
  535. package/schema/scale.js.map +0 -1
  536. package/schema/sources.js.map +0 -1
  537. package/schema/table.js.map +0 -1
  538. package/schema/types.js.map +0 -1
  539. package/ui/action-tray.js.map +0 -1
  540. package/ui/button.js.map +0 -1
  541. package/ui/choice-switch.js.map +0 -1
  542. package/ui/controls.js.map +0 -1
  543. package/ui/display.js.map +0 -1
  544. package/ui/expanded-editor-modal.js.map +0 -1
  545. package/ui/field-context.js.map +0 -1
  546. package/ui/floating-panel.js.map +0 -1
  547. package/ui/index.js +0 -13
  548. package/ui/input.js.map +0 -1
  549. package/ui/mode-bar.js.map +0 -1
  550. package/ui/overlay.js +0 -378
  551. package/ui/overlay.js.map +0 -1
  552. package/ui/path-crumbs.js.map +0 -1
  553. package/ui/presence.js.map +0 -1
  554. package/ui/select.js.map +0 -1
  555. package/ui/shortcut-hint.js.map +0 -1
  556. package/ui/surfaces.js.map +0 -1
  557. package/ui/tooltip-root.js.map +0 -1
  558. package/ui/variants.js.map +0 -1
  559. /package/{_virtual → dist/_virtual}/_rolldown/runtime.js +0 -0
  560. /package/{adapters → dist/adapters}/icons.d.ts +0 -0
  561. /package/{brand → dist/brand}/logo.d.ts +0 -0
  562. /package/{controls → dist/controls}/c1.d.ts +0 -0
  563. /package/{controls → dist/controls}/c2.d.ts +0 -0
  564. /package/{controls → dist/controls}/code-register.d.ts +0 -0
  565. /package/{controls → dist/controls}/code.d.ts +0 -0
  566. /package/{controls → dist/controls}/color.d.ts +0 -0
  567. /package/{controls → dist/controls}/date-register.d.ts +0 -0
  568. /package/{controls → dist/controls}/date-zone.d.ts +0 -0
  569. /package/{controls → dist/controls}/date.d.ts +0 -0
  570. /package/{controls → dist/controls}/form-picker.d.ts +0 -0
  571. /package/{controls → dist/controls}/icon-register.d.ts +0 -0
  572. /package/{controls → dist/controls}/json-register.d.ts +0 -0
  573. /package/{controls → dist/controls}/json.d.ts +0 -0
  574. /package/{controls → dist/controls}/link.d.ts +0 -0
  575. /package/{controls → dist/controls}/location-register.d.ts +0 -0
  576. /package/{controls → dist/controls}/location.d.ts +0 -0
  577. /package/{controls → dist/controls}/media-register.d.ts +0 -0
  578. /package/{controls → dist/controls}/number.d.ts +0 -0
  579. /package/{controls → dist/controls}/reference-register.d.ts +0 -0
  580. /package/{controls → dist/controls}/rich-text/index.d.ts +0 -0
  581. /package/{controls → dist/controls}/rich-text/markdown.d.ts +0 -0
  582. /package/{controls → dist/controls}/rich-text/ops.d.ts +0 -0
  583. /package/{controls → dist/controls}/scale.d.ts +0 -0
  584. /package/{controls → dist/controls}/slot.d.ts +0 -0
  585. /package/{controls → dist/controls}/table/index.d.ts +0 -0
  586. /package/{controls → dist/controls}/table/prod.d.ts +0 -0
  587. /package/{controls → dist/controls}/table/refs.d.ts +0 -0
  588. /package/{controls → dist/controls}/table/stored.d.ts +0 -0
  589. /package/{controls → dist/controls}/table/table-editor.d.ts +0 -0
  590. /package/{controls → dist/controls}/table/table-link.d.ts +0 -0
  591. /package/{controls → dist/controls}/table/table.d.ts +0 -0
  592. /package/{engine → dist/engine}/array.d.ts +0 -0
  593. /package/{engine → dist/engine}/bits.d.ts +0 -0
  594. /package/{engine → dist/engine}/field-list.d.ts +0 -0
  595. /package/{engine → dist/engine}/field-shell.d.ts +0 -0
  596. /package/{engine → dist/engine}/kit-field.d.ts +0 -0
  597. /package/{engine → dist/engine}/slot.d.ts +0 -0
  598. /package/{index.d.ts → dist/index.d.ts} +0 -0
  599. /package/{lib → dist/lib}/cn.d.ts +0 -0
  600. /package/{lib → dist/lib}/columns.d.ts +0 -0
  601. /package/{lib → dist/lib}/frames.d.ts +0 -0
  602. /package/{lib → dist/lib}/icons.d.ts +0 -0
  603. /package/{lib → dist/lib}/path.d.ts +0 -0
  604. /package/{lib → dist/lib}/utils.d.ts +0 -0
  605. /package/{schema → dist/schema}/adapters.d.ts +0 -0
  606. /package/{schema → dist/schema}/scale.d.ts +0 -0
  607. /package/{schema → dist/schema}/sources.d.ts +0 -0
  608. /package/{schema → dist/schema}/table.d.ts +0 -0
  609. /package/{types.d.ts → dist/types.d.ts} +0 -0
  610. /package/{ui → dist/ui}/choice-switch.d.ts +0 -0
  611. /package/{ui → dist/ui}/controls.d.ts +0 -0
  612. /package/{ui → dist/ui}/field-context.d.ts +0 -0
  613. /package/{ui → dist/ui}/mode-bar.d.ts +0 -0
  614. /package/{ui → dist/ui}/path-crumbs.d.ts +0 -0
  615. /package/{ui → dist/ui}/presence.d.ts +0 -0
  616. /package/{ui → dist/ui}/select.d.ts +0 -0
  617. /package/{ui → dist/ui}/shortcut-hint.d.ts +0 -0
  618. /package/{ui → dist/ui}/surfaces.d.ts +0 -0
  619. /package/{ui → dist/ui}/variants.d.ts +0 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"catalog.js","names":[],"sources":["../../../src/controls/rich-text/catalog.tsx"],"sourcesContent":["/**\n * RICH TEXT · the block catalogue shared by the toolbar Insert menu, the gutter \"+\" and the \"/\" slash menu (V2 HEAD\n * controls/rich-text/catalog.tsx, CPO D55).\n *\n * browse Text · Media · Data, grouped, then one quiet \"More components N\" row that opens the components the\n * field may embed (V2 HEAD catalog.tsx MORE), with its own search and a way back (\"All blocks\")\n * search every block and every embeddable component in one list: recently used first among the strong matches,\n * then by match (label, aliases, then description)\n * no match \"No match.\"\n *\n * Only the blocks the field accepts are offered (`features`, from the host's codec: each block is offered only where\n * the field's stored shape has a place for it). Not in this catalogue, and why:\n * Footnote, Gallery, Embed, Columns, Table of contents, Related posts, Author bio\n * production's rich text has no stored block for them yet (plan RT3–RT8; production's embed\n * frames the raw link, which providers refuse, so Video is the one media link offered). A stored embed (an\n * imported `<iframe>`, whose address is already the provider's frame) opens and is edited as V2's Embed block.\n *\n * Components come from the host (KitServices.useInsertableComponents: the project's components, narrowed to the ones\n * the field's config accepts), handed in through CatalogComponentsProvider. Without that service none is offered.\n * Deviation from V2: the library has no inline / page-section placement, so every component sits in one\n * \"Components\" group (V2: \"Article\" and \"Page sections\"), and no live preview flyout is drawn beside a row.\n */\nimport * as React from \"react\";\nimport {\n IconClick, IconListCheck,\n IconArrowLeft, IconBlockquote, IconChevronRight, IconComponents, IconFileText, IconH1, IconH2, IconH3, IconH4, IconH5, IconH6, IconInfoCircle, IconLayoutNavbarCollapse, IconList, IconListDetails, IconListNumbers, IconPhoto,\n IconPilcrow, IconQuote, IconSearch, IconSeparatorHorizontal, IconTable, IconTerminal2, IconVideo,\n} from \"@tabler/icons-react\";\nimport { cn } from \"../../lib/cn\";\nimport { PopoverContent } from \"../../ui/overlay\";\nimport type { RichTextFeature } from \"./codec\";\nimport type { KitInsertableComponent } from \"../component-services\";\n\nexport type BasicId =\n | \"p\" | \"h1\" | \"h2\" | \"h3\" | \"h4\" | \"h5\" | \"h6\" | \"quote\" | \"pullquote\" | \"callout\" | \"toggle\" | \"takeaways\" | \"ul\" | \"ol\" | \"code\" | \"hr\"\n | \"image\" | \"video\" | \"file\" | \"table\" | \"task\" | \"button\";\n\nexport interface CatalogItem {\n key: string;\n /** a basic block (absent on a component, the More components row and the way back) */\n id?: BasicId;\n /** component: embeds `component`; folder: opens More components; back: returns to every block */\n kind?: \"component\" | \"folder\" | \"back\";\n component?: KitInsertableComponent;\n /** the folder row's component count */\n count?: number;\n label: string;\n description: string;\n icon: React.ReactNode;\n /** extra words that find it */\n aliases?: string[];\n}\n\nconst i = (I: React.ComponentType<{ stroke?: number }>) => <I stroke={1.5} />;\ntype Row = [BasicId, string, string, React.ReactNode, string[]?];\nconst rows = (list: Row[]): CatalogItem[] => list.map(([id, label, description, icon, aliases]) => ({ key: id, id, label, description, icon, aliases }));\n\nconst TEXT = rows([\n [\"p\", \"Text\", \"Plain body text\", i(IconPilcrow), [\"paragraph\", \"body\"]],\n [\"h2\", \"Heading 2\", \"Section heading\", i(IconH2), [\"title\", \"subtitle\"]],\n [\"h3\", \"Heading 3\", \"Subsection heading\", i(IconH3)],\n [\"h4\", \"Heading 4\", \"Minor heading\", i(IconH4)],\n [\"quote\", \"Quote\", \"A quoted passage\", i(IconBlockquote), [\"blockquote\"]],\n [\"pullquote\", \"Pull quote\", \"A highlighted line with who said it\", i(IconQuote), [\"pq\", \"testimonial\", \"attribution\"]],\n [\"ul\", \"List\", \"Bulleted list\", i(IconList), [\"bullets\", \"bulleted list\", \"unordered\"]],\n [\"ol\", \"Numbered list\", \"Ordered steps\", i(IconListNumbers), [\"ordered\", \"steps\"]],\n [\"toggle\", \"Toggle\", \"Collapsible title and body\", i(IconLayoutNavbarCollapse), [\"accordion\", \"details\", \"collapse\"]],\n [\"callout\", \"Callout\", \"A highlighted note with a tone\", i(IconInfoCircle), [\"note\", \"tip\", \"warning\", \"aside\"]],\n [\"takeaways\", \"Key takeaways\", \"The story in a few points\", i(IconListDetails), [\"summary\", \"tldr\", \"tl;dr\", \"highlights\"]],\n [\"hr\", \"Divider\", \"A line between parts\", i(IconSeparatorHorizontal), [\"line\", \"separator\", \"rule\"]],\n [\"code\", \"Code\", \"Monospaced snippet\", i(IconTerminal2), [\"code block\", \"snippet\", \"pre\"]],\n]);\nconst MEDIA = rows([\n [\"image\", \"Image\", \"Image with alt text and caption\", i(IconPhoto), [\"img\", \"picture\", \"photo\"]],\n [\"video\", \"Video\", \"A YouTube, Vimeo or video file link\", i(IconVideo), [\"mp4\", \"youtube\", \"yt\", \"vimeo\", \"clip\", \"movie\"]],\n [\"file\", \"File\", \"A downloadable PDF or file\", i(IconFileText), [\"pdf\", \"download\", \"attachment\"]],\n]);\nconst DATA = rows([[\"table\", \"Table\", \"Rows and columns\", i(IconTable), [\"grid\", \"data\", \"comparison\", \"spreadsheet\"]]]);\n/** Found by search, not listed: rare in a body (H1 is the page title). */\nconst SEARCH_ONLY = rows([\n [\"h1\", \"Heading 1\", \"Largest heading\", i(IconH1)],\n [\"h5\", \"Heading 5\", \"Smallest heading\", i(IconH5)],\n [\"h6\", \"Heading 6\", \"Eyebrow heading\", i(IconH6)],\n // V2 catalog.tsx:89, :91 (rare in a story, so found by search)\n [\"task\", \"Checklist\", \"To-do list with checkboxes\", i(IconListCheck), [\"todo\", \"checkbox\"]],\n [\"button\", \"Button\", \"A call to action link\", i(IconClick), [\"link button\"]],\n]);\n\n/** The feature a block needs (Text needs none). */\nconst NEEDS: Record<BasicId, RichTextFeature | null> = {\n p: null, h1: \"h1\", h2: \"h2\", h3: \"h3\", h4: \"h4\", h5: \"h5\", h6: \"h6\", quote: \"blockquote\", ul: \"ul\", ol: \"ol\", code: \"pre\", hr: \"hr\", image: \"image\",\n pullquote: \"pullquote\", takeaways: \"takeaways\", callout: \"callout\", toggle: \"toggle\", video: \"video\", file: \"file\", table: \"table\",\n task: \"checklist\", button: \"button\",\n};\nconst MORE: CatalogItem = { key: \"more\", kind: \"folder\", label: \"More blocks\", description: \"Shared across your site\", icon: i(IconComponents) };\nconst BACK: CatalogItem = { key: \"back\", kind: \"back\", label: \"All blocks\", description: \"\", icon: i(IconArrowLeft) };\nconst componentRow = (c: KitInsertableComponent): CatalogItem => ({\n key: `c:${c.id}`,\n kind: \"component\",\n component: c,\n label: c.name,\n description: c.description || \"Shared across your site\",\n icon: i(IconComponents),\n});\n\n/** The components this field may embed, as the host answered (KitServices.useInsertableComponents). */\nexport interface CatalogComponents {\n components: KitInsertableComponent[];\n loading?: boolean;\n error?: string;\n}\nconst ComponentsContext = React.createContext<CatalogComponents | null>(null);\nexport const CatalogComponentsProvider = ComponentsContext.Provider;\n/** The components this field may embed (a component card's Swap component). */\nexport const useCatalogComponents = () => React.useContext(ComponentsContext);\n\nexport const blockAllowed = (id: BasicId, allows: (f: RichTextFeature) => boolean) => {\n const need = NEEDS[id];\n return !need || allows(need);\n};\n\n/* ── Recently used (per person, CPO D55): this browser's storage; a browser that keeps none just has no recents ── */\nconst RECENTS_KEY = \"kit-rt-insert-recents\";\nlet recents: string[] = (() => {\n try {\n const v = JSON.parse(globalThis.localStorage?.getItem(RECENTS_KEY) ?? \"[]\") as unknown;\n return Array.isArray(v) ? v.filter((x): x is string => typeof x === \"string\") : [];\n } catch {\n return [];\n }\n})();\nconst recentSubs = new Set<() => void>();\n/** Remember a pick so search ranks it first next time. */\nexport function noteRecent(it: CatalogItem) {\n recents = [it.key, ...recents.filter((k) => k !== it.key)].slice(0, 12);\n try {\n globalThis.localStorage?.setItem(RECENTS_KEY, JSON.stringify(recents));\n } catch {\n /* storage is off: recents last for this session */\n }\n recentSubs.forEach((s) => s());\n}\nfunction useRecents() {\n return React.useSyncExternalStore(\n (cb) => {\n recentSubs.add(cb);\n return () => recentSubs.delete(cb);\n },\n () => recents,\n () => recents,\n );\n}\n\nexport interface CatalogSection {\n title: string | null;\n items: CatalogItem[];\n}\n\n/** 5 exact (label, id or alias) · 4 label or alias starts with it · 3 a word of the label starts with it · 2 inside the\n * label · 1 the description. */\nconst score = (q: string, it: CatalogItem) => {\n const l = it.label.toLowerCase();\n const al = it.aliases ?? [];\n if (l === q || it.id === q || al.includes(q)) return 5;\n if (l.startsWith(q) || al.some((a) => a.startsWith(q))) return 4;\n if (l.split(/[\\s-]+/).some((w) => w.startsWith(q))) return 3;\n if (l.includes(q)) return 2;\n return it.description.toLowerCase().includes(q) ? 1 : 0;\n};\n/** Ranked by recently used among the strong matches, then by match, then catalogue order. */\nconst rank = (q: string, list: CatalogItem[], recent: string[]) =>\n list\n .map((it, i) => {\n const s = score(q, it);\n const r = recent.indexOf(it.key);\n return { it, s, strong: s >= 3 ? 1 : 0, r: s >= 3 && r >= 0 ? r : 999, i };\n })\n .filter((x) => x.s > 0)\n .sort((a, b) => b.strong - a.strong || a.r - b.r || b.s - a.s || a.i - b.i)\n .map((x) => x.it);\n\n/** `folder`: the More components view (its way back first, then the components, searched by `query`). */\nexport function useCatalog(query: string, allows: (f: RichTextFeature) => boolean, folder = false, own?: CatalogComponents | null) {\n const recent = useRecents();\n const provided = React.useContext(ComponentsContext);\n // the editor reads its own list (it renders the provider, so cannot read it)\n const lib = own === undefined ? provided : own;\n return React.useMemo(() => {\n const q = query.trim().toLowerCase().replace(/^\\//, \"\");\n const keep = (list: CatalogItem[]) => list.filter((it) => !it.id || blockAllowed(it.id, allows));\n const comps = (lib?.components ?? []).map(componentRow);\n let sections: CatalogSection[];\n let noMatch = false;\n let emptyText = \"No match.\";\n if (folder) {\n const found = q ? rank(q, comps, recent) : comps;\n noMatch = !!q && !!comps.length && !found.length;\n if (!comps.length) emptyText = lib?.error ?? (lib?.loading ? \"Loading blocks…\" : \"This field takes no blocks.\");\n sections = [{ title: null, items: [BACK] }, { title: \"Blocks\", items: found }];\n } else if (q) {\n const found = rank(q, [...keep(TEXT), ...keep(MEDIA), ...keep(DATA), ...keep(SEARCH_ONLY), ...comps], recent);\n noMatch = !found.length;\n sections = [{ title: null, items: found }];\n } else\n sections = [\n { title: \"Text\", items: keep(TEXT) },\n { title: \"Media\", items: keep(MEDIA) },\n { title: \"Data\", items: keep(DATA) },\n // offered while the list loads or failed too: opening it says which\n { title: null, items: lib && (comps.length || lib.loading || lib.error) ? [{ ...MORE, ...(comps.length ? { count: comps.length } : {}) }] : [] },\n ];\n sections = sections.filter((s) => s.items.length);\n const flat = sections.flatMap((s) => s.items);\n const empty = !flat.some((it) => it.kind !== \"back\");\n return { sections, flat, empty, noMatch, emptyText };\n }, [query, allows, recent, lib, folder]);\n}\n\n/* ── The list ───────────────────────────────────────────────────────────\n * Browsing: compact one-line rows (icon · name), grouped. Search results add the one-line description. */\nexport function CatalogList({\n sections,\n flat,\n active,\n onHover,\n onPick,\n empty,\n emptyText = \"No match.\",\n noMatch,\n detail,\n listId,\n className,\n}: {\n sections: CatalogSection[];\n flat: CatalogItem[];\n active: number;\n onHover: (i: number) => void;\n onPick: (it: CatalogItem) => void;\n empty: boolean;\n /** what an empty list says (\"No match.\", or why More components has none) */\n emptyText?: string;\n noMatch?: boolean;\n /** show each row's description (search results, More components) */\n detail?: boolean;\n listId: string;\n className?: string;\n}) {\n const box = React.useRef<HTMLDivElement>(null);\n React.useEffect(() => {\n // scroll only the list (scrollIntoView would also scroll the page behind a floating menu)\n const b = box.current;\n const row = b?.querySelector<HTMLElement>(`[data-idx=\"${active}\"]`);\n if (!b || !row) return;\n if (row.offsetTop < b.scrollTop) b.scrollTop = row.offsetTop - 6;\n else if (row.offsetTop + row.offsetHeight > b.scrollTop + b.clientHeight) b.scrollTop = row.offsetTop + row.offsetHeight - b.clientHeight + 6;\n }, [active]);\n return (\n <div ref={box} id={listId} role=\"listbox\" aria-label=\"Blocks\" className={cn(\"relative max-h-[320px] overflow-y-auto p-1.5\", className)}>\n {noMatch ? <div className=\"px-2 pb-1 pt-1.5 text-kit-sm text-kit-fg-3\">No match.</div> : null}\n {sections.map((s, si) => (\n <div\n key={s.title ?? `s${si}`}\n role=\"group\"\n aria-label={s.title ?? undefined}\n className={cn(!s.title && si > 0 && s.items[0]?.kind === \"folder\" && \"mt-1.5 border-t border-kit-line-subtle pt-1.5\")}\n >\n {s.title ? <div className=\"px-2 pb-0.5 pt-2 text-kit-2xs font-medium text-kit-fg-3\">{s.title}</div> : null}\n {s.items.map((it) => {\n const idx = flat.indexOf(it);\n const on = idx === active;\n const desc = detail && it.kind !== \"back\" && it.kind !== \"folder\" ? it.description : \"\";\n return (\n <button\n key={it.key}\n type=\"button\"\n role=\"option\"\n aria-selected={on}\n aria-description={!desc && it.description ? it.description : undefined}\n data-idx={idx}\n id={`${listId}-${idx}`}\n onMouseDown={(e) => e.preventDefault()}\n onMouseMove={() => !on && onHover(idx)}\n onClick={() => onPick(it)}\n className={cn(\n \"flex w-full items-center gap-2 rounded-kit-md px-2 text-left transition-colors motion-reduce:transition-none\",\n desc ? \"py-1.5\" : \"h-8\",\n it.kind === \"back\" ? \"text-kit-fg-2\" : \"text-kit-fg\",\n on && \"bg-kit-hover text-kit-fg\",\n )}\n >\n <span className={cn(\"flex shrink-0 items-center justify-center text-kit-fg-2 [&_svg]:size-4\", desc ? \"size-7 rounded-kit-md border border-kit-line bg-kit-control-bg\" : \"size-5\")}>\n {it.icon}\n </span>\n <span className=\"min-w-0 flex-1\">\n <span className=\"block truncate text-kit-sm\">{it.label}</span>\n {desc ? <span className=\"block truncate text-kit-xs text-kit-fg-3\">{desc}</span> : null}\n </span>\n {it.count != null ? <span className=\"text-kit-2xs tabular-nums text-kit-fg-3\">{it.count}</span> : null}\n {it.kind === \"folder\" ? <IconChevronRight className=\"size-3.5 shrink-0 text-kit-fg-3\" stroke={1.5} aria-hidden /> : null}\n </button>\n );\n })}\n </div>\n ))}\n {empty ? <div className=\"px-2 py-6 text-center text-kit-sm text-kit-fg-3\">{emptyText}</div> : null}\n </div>\n );\n}\n\nconst Footer = () => (\n <div data-hint=\"shortcuts\" className=\"flex h-7 shrink-0 items-center border-t border-kit-line px-3 text-kit-2xs text-kit-fg-3\">\n <span>\n <kbd className=\"font-kit-sans\">↵</kbd> select · type to search\n </span>\n </div>\n);\n\n/** Shared keyboard model: ↑↓ wrap, Home/End, Enter / Tab, → into More components. Returns true when handled. */\nexport function catalogKey(\n e: React.KeyboardEvent | KeyboardEvent,\n flat: CatalogItem[],\n active: number,\n setActive: (i: number) => void,\n pick: (it: CatalogItem) => void,\n homeEnd = true,\n) {\n const n = flat.length;\n if (!n) return false;\n if (e.key === \"ArrowDown\") return setActive((active + 1) % n), true;\n if (e.key === \"ArrowUp\") return setActive((active - 1 + n) % n), true;\n if (homeEnd && e.key === \"Home\") return setActive(0), true;\n if (homeEnd && e.key === \"End\") return setActive(n - 1), true;\n if (e.key === \"ArrowRight\" && flat[active]?.kind === \"folder\") return pick(flat[active]), true;\n if (e.key === \"Enter\" || e.key === \"Tab\") {\n const it = flat[active];\n if (it) pick(it);\n return true;\n }\n return false;\n}\n\n/* ── Insert menu (popover content for the toolbar \"Insert\" and the gutter \"+\") ─ */\nexport function InsertMenuContent({\n onInsert,\n allows,\n keepFocusOnClose,\n align = \"start\",\n side = \"bottom\",\n}: {\n onInsert: (it: CatalogItem) => void;\n allows: (f: RichTextFeature) => boolean;\n /** after an insert the caret stays in the editor: the menu gives no focus back to its trigger */\n keepFocusOnClose?: () => boolean;\n align?: \"start\" | \"center\" | \"end\";\n side?: \"top\" | \"bottom\" | \"left\" | \"right\";\n}) {\n const [q, setQ] = React.useState(\"\");\n const [active, setActive] = React.useState(0);\n const input = React.useRef<HTMLInputElement>(null);\n const listId = React.useId();\n const [folder, setFolder] = React.useState(false);\n const { sections, flat, empty, emptyText, noMatch } = useCatalog(q, allows, folder);\n // in More components the first row is the way back: the first component starts active\n React.useEffect(() => setActive(folder && flat.length > 1 ? 1 : 0), [q, folder]); // eslint-disable-line react-hooks/exhaustive-deps\n const leave = () => {\n setFolder(false);\n setQ(\"\");\n input.current?.focus();\n };\n const pick = (it: CatalogItem) => {\n if (it.kind === \"folder\") {\n setFolder(true);\n setQ(\"\");\n input.current?.focus();\n } else if (it.kind === \"back\") leave();\n else onInsert(it);\n };\n return (\n <PopoverContent\n side={side}\n align={align}\n className=\"flex max-h-[420px] w-[320px] flex-col overflow-hidden p-0\"\n initialFocus={input}\n finalFocus={keepFocusOnClose ? () => !keepFocusOnClose() : undefined}\n // Esc in More components steps back to every block, wherever focus sits in the menu (the list scrolls, so the\n // browser can focus it): caught before the popover's own Esc, which would close it\n onKeyDownCapture={(e) => {\n if (!folder || e.key !== \"Escape\") return;\n e.preventDefault();\n e.stopPropagation();\n leave();\n }}\n >\n <div className=\"flex h-10 shrink-0 items-center gap-2 border-b border-kit-line px-3\">\n <IconSearch className=\"size-4 shrink-0 text-kit-fg-3\" stroke={1.5} aria-hidden />\n <input\n ref={input}\n value={q}\n onChange={(e) => setQ(e.target.value)}\n onKeyDown={(e) => {\n if (folder && e.key === \"Backspace\" && !q) {\n // ⌫ in an empty search steps back to every block (Esc: the popup's capture above)\n e.preventDefault();\n e.stopPropagation();\n leave();\n } else if (catalogKey(e, flat, active, setActive, pick, !q)) e.preventDefault();\n }}\n role=\"combobox\"\n aria-expanded\n aria-controls={listId}\n aria-activedescendant={flat.length ? `${listId}-${active}` : undefined}\n aria-label={folder ? \"Search blocks\" : \"Search or pick a block\"}\n placeholder={folder ? \"Search blocks\" : \"Search or pick a block\"}\n className=\"h-full min-w-0 flex-1 bg-transparent text-kit-sm text-kit-fg outline-none placeholder:text-kit-fg-3 focus-visible:shadow-none\"\n />\n </div>\n <CatalogList\n sections={sections}\n flat={flat}\n active={active}\n onHover={setActive}\n onPick={pick}\n empty={empty}\n emptyText={emptyText}\n noMatch={noMatch}\n detail={!!q || folder}\n listId={listId}\n className=\"min-h-0 flex-1\"\n />\n <Footer />\n </PopoverContent>\n );\n}\n\n/* ── Slash menu panel (positioned by the editor; never takes focus) ── */\nexport function SlashMenuPanel({\n query,\n folder = false,\n active,\n setActive,\n onPick,\n allows,\n maxHeight,\n}: {\n /** the room the editor found for the menu (collision-aware); the list scrolls inside it */\n maxHeight?: number;\n query: string;\n /** the More components view (the editor keeps it with the rest of the slash state) */\n folder?: boolean;\n active: number;\n setActive: (i: number) => void;\n onPick: (it: CatalogItem) => void;\n allows: (f: RichTextFeature) => boolean;\n}) {\n const listId = React.useId();\n const { sections, flat, empty, emptyText, noMatch } = useCatalog(query, allows, folder);\n return (\n <div\n data-kit-scope=\"\"\n className=\"glass-strong flex w-[320px] flex-col overflow-hidden rounded-kit-xl border border-kit-line\"\n style={maxHeight ? { maxHeight } : undefined}\n onMouseDown={(e) => e.preventDefault()}\n >\n <div className=\"flex h-8 shrink-0 items-center gap-2 border-b border-kit-line px-3 text-kit-sm\">\n <span className={cn(\"flex-1 truncate\", query ? \"text-kit-fg\" : \"text-kit-fg-3\")}>{query ? `${folder ? \"More blocks · \" : \"\"}/${query}` : folder ? \"More blocks\" : \"Type to search\"}</span>\n <kbd data-hint=\"shortcuts\" className=\"font-kit-sans text-kit-2xs text-kit-fg-3\">\n esc\n </kbd>\n </div>\n <CatalogList\n sections={sections}\n flat={flat}\n active={active}\n onHover={setActive}\n onPick={onPick}\n empty={empty}\n emptyText={emptyText}\n noMatch={noMatch}\n detail={!!query || folder}\n listId={listId}\n className=\"max-h-[300px] min-h-0 flex-1\"\n />\n <Footer />\n </div>\n );\n}\n"],"mappings":"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"}
@@ -0,0 +1,24 @@
1
+ /** The box is the item's ::before, 16px at the start of its 28px indent (pl-7); V2 hit-tests 22px. */
2
+ export declare const TASK_HIT_PX = 22;
3
+ /** The task item a node sits in, inside `root` and outside any rich block. */
4
+ export declare function taskItemOf(root: HTMLElement, node: Node | null): HTMLLIElement | null;
5
+ /** Ticks or unticks an item; keeps the editor-only a11y state in step. */
6
+ export declare function setTaskChecked(li: HTMLLIElement, checked: boolean): void;
7
+ /** Catalog insert: the empty line becomes `<ul data-task><li data-checked="false">`, caret inside. */
8
+ export declare function insertChecklist(root: HTMLElement): HTMLLIElement;
9
+ /** "[] " / "[ ] " typed at the start of a paragraph turns it into a task item. Returns true when it converted. */
10
+ export declare function checklistShortcut(root: HTMLElement, data: string | null): boolean;
11
+ /**
12
+ * A press on an item's box toggles it (mousedown, so the caret does not move). Returns true when it ticked; the
13
+ * editor then prevents the default and emits.
14
+ */
15
+ export declare function toggleTaskAtPointer(root: HTMLElement, target: EventTarget | null, clientX: number): boolean;
16
+ /** Space with the caret at the very start of an item ticks it (a leading space is never text). Returns true when it did. */
17
+ export declare function toggleTaskFromKey(root: HTMLElement, key: string): boolean;
18
+ /**
19
+ * After each input: an empty item is unchecked (V2), and every item carries role="checkbox" + aria-checked. Call it
20
+ * from the editor's input handler and after load.
21
+ */
22
+ export declare function syncTaskA11y(root: HTMLElement): void;
23
+ /** Takes the editor-only a11y attributes off a clone before it is stored. */
24
+ export declare function stripTaskA11y(clone: HTMLElement): void;
@@ -0,0 +1,115 @@
1
+ import { placeCaret, textBeforeCaret, topBlock } from "./dom.js";
2
+ import { takeEmptyBlock } from "./ops.js";
3
+ //#region src/controls/rich-text/checklist.tsx
4
+ /**
5
+ * RICH TEXT · Checklist (kit-richtext-ui-spec.md §8): V2's task list, a native list stored as PT `listItem: "check"`
6
+ * with `checked`, written in the editor as `<ul data-task="true"><li data-checked="true|false">`.
7
+ *
8
+ * The look is the editor's (editor.tsx, from V2 rich-text-editor.tsx:54-55); this module is the behaviour:
9
+ * insert V2 ops.ts:147-155: the empty line becomes a one-item unchecked task list, caret inside
10
+ * shortcut V2 ops.ts:224-240: "[] " or "[ ] " at the start of a paragraph
11
+ * tick V2 rich-text-editor.tsx:1314-1321: a press within 22px of the item's left edge toggles it
12
+ * new item V2 rich-text-editor.tsx:821: an empty item is unchecked (Enter after a ticked item starts unticked)
13
+ * a11y signed deviation (e1, 2026-10-24; behaviour only, pixels V2-exact): each item is role="checkbox" with
14
+ * aria-checked, and Space with the caret at the item's start ticks it. Editor-only: stripTaskA11y
15
+ * takes the attributes off the HTML the editor stores.
16
+ */
17
+ /** The box is the item's ::before, 16px at the start of its 28px indent (pl-7); V2 hit-tests 22px. */
18
+ var TASK_HIT_PX = 22;
19
+ var TASK_ITEM = "ul[data-task] > li";
20
+ var isTaskItem = (el) => !!el && el.tagName === "LI" && !!el.parentElement?.hasAttribute("data-task");
21
+ var isChecked = (li) => li.getAttribute("data-checked") === "true";
22
+ /** The task item a node sits in, inside `root` and outside any rich block. */
23
+ function taskItemOf(root, node) {
24
+ const li = (node ? node.nodeType === 1 ? node : node.parentElement : null)?.closest("li") ?? null;
25
+ return isTaskItem(li) && root.contains(li) && !li.closest("[data-rt-isolate]") ? li : null;
26
+ }
27
+ /** Ticks or unticks an item; keeps the editor-only a11y state in step. */
28
+ function setTaskChecked(li, checked) {
29
+ li.setAttribute("data-checked", checked ? "true" : "false");
30
+ li.setAttribute("aria-checked", checked ? "true" : "false");
31
+ }
32
+ /** Catalog insert: the empty line becomes `<ul data-task><li data-checked="false">`, caret inside. */
33
+ function insertChecklist(root) {
34
+ const t = takeEmptyBlock(root);
35
+ const ul = document.createElement("ul");
36
+ ul.setAttribute("data-task", "true");
37
+ ul.innerHTML = `<li data-checked="false"><br></li>`;
38
+ t.replaceWith(ul);
39
+ const li = ul.firstElementChild;
40
+ syncTaskA11y(root);
41
+ placeCaret(li);
42
+ return li;
43
+ }
44
+ /** "[] " / "[ ] " typed at the start of a paragraph turns it into a task item. Returns true when it converted. */
45
+ function checklistShortcut(root, data) {
46
+ if (data !== " ") return false;
47
+ const s = window.getSelection();
48
+ if (!s || !s.rangeCount || !s.isCollapsed) return false;
49
+ const blk = topBlock(root, s.anchorNode);
50
+ if (!blk || blk.tagName !== "P") return false;
51
+ const before = textBeforeCaret(blk)?.replace(/ /g, " ");
52
+ if (before !== "[] " && before !== "[ ] ") return false;
53
+ const r = document.createRange();
54
+ r.selectNodeContents(blk);
55
+ r.setEnd(s.anchorNode, s.anchorOffset);
56
+ r.deleteContents();
57
+ const ul = document.createElement("ul");
58
+ ul.setAttribute("data-task", "true");
59
+ const li = document.createElement("li");
60
+ li.setAttribute("data-checked", "false");
61
+ li.innerHTML = blk.textContent || blk.querySelector("img") ? blk.innerHTML : "<br>";
62
+ ul.append(li);
63
+ blk.replaceWith(ul);
64
+ syncTaskA11y(root);
65
+ placeCaret(li, false);
66
+ return true;
67
+ }
68
+ /**
69
+ * A press on an item's box toggles it (mousedown, so the caret does not move). Returns true when it ticked; the
70
+ * editor then prevents the default and emits.
71
+ */
72
+ function toggleTaskAtPointer(root, target, clientX) {
73
+ const li = target instanceof Node ? taskItemOf(root, target) : null;
74
+ if (!li || clientX - li.getBoundingClientRect().left >= 22) return false;
75
+ setTaskChecked(li, !isChecked(li));
76
+ return true;
77
+ }
78
+ /** Space with the caret at the very start of an item ticks it (a leading space is never text). Returns true when it did. */
79
+ function toggleTaskFromKey(root, key) {
80
+ if (key !== " ") return false;
81
+ const s = window.getSelection();
82
+ if (!s || !s.rangeCount || !s.isCollapsed) return false;
83
+ const li = taskItemOf(root, s.anchorNode);
84
+ if (!li) return false;
85
+ const r = document.createRange();
86
+ r.selectNodeContents(li);
87
+ r.setEnd(s.anchorNode, s.anchorOffset);
88
+ if (r.toString().replace(/​/g, "") !== "") return false;
89
+ setTaskChecked(li, !isChecked(li));
90
+ return true;
91
+ }
92
+ /**
93
+ * After each input: an empty item is unchecked (V2), and every item carries role="checkbox" + aria-checked. Call it
94
+ * from the editor's input handler and after load.
95
+ */
96
+ function syncTaskA11y(root) {
97
+ root.querySelectorAll(TASK_ITEM).forEach((li) => {
98
+ if (li.closest("[data-rt-isolate]")) return;
99
+ if (!(li.textContent ?? "").replace(/​/g, "").trim() && !li.querySelector("img") && isChecked(li)) li.setAttribute("data-checked", "false");
100
+ if (!li.hasAttribute("data-checked")) li.setAttribute("data-checked", "false");
101
+ li.setAttribute("role", "checkbox");
102
+ li.setAttribute("aria-checked", isChecked(li) ? "true" : "false");
103
+ });
104
+ }
105
+ /** Takes the editor-only a11y attributes off a clone before it is stored. */
106
+ function stripTaskA11y(clone) {
107
+ clone.querySelectorAll(TASK_ITEM).forEach((li) => {
108
+ li.removeAttribute("role");
109
+ li.removeAttribute("aria-checked");
110
+ });
111
+ }
112
+ //#endregion
113
+ export { TASK_HIT_PX, checklistShortcut, insertChecklist, setTaskChecked, stripTaskA11y, syncTaskA11y, taskItemOf, toggleTaskAtPointer, toggleTaskFromKey };
114
+
115
+ //# sourceMappingURL=checklist.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"checklist.js","names":[],"sources":["../../../src/controls/rich-text/checklist.tsx"],"sourcesContent":["/**\n * RICH TEXT · Checklist (kit-richtext-ui-spec.md §8): V2's task list, a native list stored as PT `listItem: \"check\"`\n * with `checked`, written in the editor as `<ul data-task=\"true\"><li data-checked=\"true|false\">`.\n *\n * The look is the editor's (editor.tsx, from V2 rich-text-editor.tsx:54-55); this module is the behaviour:\n * insert V2 ops.ts:147-155: the empty line becomes a one-item unchecked task list, caret inside\n * shortcut V2 ops.ts:224-240: \"[] \" or \"[ ] \" at the start of a paragraph\n * tick V2 rich-text-editor.tsx:1314-1321: a press within 22px of the item's left edge toggles it\n * new item V2 rich-text-editor.tsx:821: an empty item is unchecked (Enter after a ticked item starts unticked)\n * a11y signed deviation (e1, 2026-10-24; behaviour only, pixels V2-exact): each item is role=\"checkbox\" with\n * aria-checked, and Space with the caret at the item's start ticks it. Editor-only: stripTaskA11y\n * takes the attributes off the HTML the editor stores.\n */\nimport { placeCaret, textBeforeCaret, topBlock } from \"./dom\";\nimport { takeEmptyBlock } from \"./ops\";\n\n/** The box is the item's ::before, 16px at the start of its 28px indent (pl-7); V2 hit-tests 22px. */\nexport const TASK_HIT_PX = 22;\nconst TASK_ITEM = \"ul[data-task] > li\";\n\nconst isTaskItem = (el: Element | null): el is HTMLLIElement => !!el && el.tagName === \"LI\" && !!el.parentElement?.hasAttribute(\"data-task\");\nconst isChecked = (li: Element) => li.getAttribute(\"data-checked\") === \"true\";\n\n/** The task item a node sits in, inside `root` and outside any rich block. */\nexport function taskItemOf(root: HTMLElement, node: Node | null): HTMLLIElement | null {\n const el = node ? (node.nodeType === 1 ? (node as Element) : node.parentElement) : null;\n const li = el?.closest(\"li\") ?? null;\n return isTaskItem(li) && root.contains(li) && !li.closest(\"[data-rt-isolate]\") ? li : null;\n}\n\n/** Ticks or unticks an item; keeps the editor-only a11y state in step. */\nexport function setTaskChecked(li: HTMLLIElement, checked: boolean) {\n li.setAttribute(\"data-checked\", checked ? \"true\" : \"false\");\n li.setAttribute(\"aria-checked\", checked ? \"true\" : \"false\");\n}\n\n/** Catalog insert: the empty line becomes `<ul data-task><li data-checked=\"false\">`, caret inside. */\nexport function insertChecklist(root: HTMLElement): HTMLLIElement {\n const t = takeEmptyBlock(root);\n const ul = document.createElement(\"ul\");\n ul.setAttribute(\"data-task\", \"true\");\n ul.innerHTML = `<li data-checked=\"false\"><br></li>`;\n t.replaceWith(ul);\n const li = ul.firstElementChild as HTMLLIElement;\n syncTaskA11y(root);\n placeCaret(li);\n return li;\n}\n\n/** \"[] \" / \"[ ] \" typed at the start of a paragraph turns it into a task item. Returns true when it converted. */\nexport function checklistShortcut(root: HTMLElement, data: string | null): boolean {\n if (data !== \" \") return false;\n const s = window.getSelection();\n if (!s || !s.rangeCount || !s.isCollapsed) return false;\n const blk = topBlock(root, s.anchorNode);\n if (!blk || blk.tagName !== \"P\") return false;\n const before = textBeforeCaret(blk)?.replace(/ /g, \" \");\n if (before !== \"[] \" && before !== \"[ ] \") return false;\n const r = document.createRange();\n r.selectNodeContents(blk);\n r.setEnd(s.anchorNode!, s.anchorOffset);\n r.deleteContents();\n const ul = document.createElement(\"ul\");\n ul.setAttribute(\"data-task\", \"true\");\n const li = document.createElement(\"li\");\n li.setAttribute(\"data-checked\", \"false\");\n li.innerHTML = blk.textContent || blk.querySelector(\"img\") ? blk.innerHTML : \"<br>\";\n ul.append(li);\n blk.replaceWith(ul);\n syncTaskA11y(root);\n placeCaret(li, false);\n return true;\n}\n\n/**\n * A press on an item's box toggles it (mousedown, so the caret does not move). Returns true when it ticked; the\n * editor then prevents the default and emits.\n */\nexport function toggleTaskAtPointer(root: HTMLElement, target: EventTarget | null, clientX: number): boolean {\n const li = target instanceof Node ? taskItemOf(root, target) : null;\n if (!li || clientX - li.getBoundingClientRect().left >= TASK_HIT_PX) return false;\n setTaskChecked(li, !isChecked(li));\n return true;\n}\n\n/** Space with the caret at the very start of an item ticks it (a leading space is never text). Returns true when it did. */\nexport function toggleTaskFromKey(root: HTMLElement, key: string): boolean {\n if (key !== \" \") return false;\n const s = window.getSelection();\n if (!s || !s.rangeCount || !s.isCollapsed) return false;\n const li = taskItemOf(root, s.anchorNode);\n if (!li) return false;\n const r = document.createRange();\n r.selectNodeContents(li);\n r.setEnd(s.anchorNode!, s.anchorOffset);\n if (r.toString().replace(/​/g, \"\") !== \"\") return false;\n setTaskChecked(li, !isChecked(li));\n return true;\n}\n\n/**\n * After each input: an empty item is unchecked (V2), and every item carries role=\"checkbox\" + aria-checked. Call it\n * from the editor's input handler and after load.\n */\nexport function syncTaskA11y(root: HTMLElement) {\n root.querySelectorAll<HTMLLIElement>(TASK_ITEM).forEach((li) => {\n if (li.closest(\"[data-rt-isolate]\")) return;\n if (!(li.textContent ?? \"\").replace(/​/g, \"\").trim() && !li.querySelector(\"img\") && isChecked(li)) li.setAttribute(\"data-checked\", \"false\");\n if (!li.hasAttribute(\"data-checked\")) li.setAttribute(\"data-checked\", \"false\");\n li.setAttribute(\"role\", \"checkbox\");\n li.setAttribute(\"aria-checked\", isChecked(li) ? \"true\" : \"false\");\n });\n}\n\n/** Takes the editor-only a11y attributes off a clone before it is stored. */\nexport function stripTaskA11y(clone: HTMLElement) {\n clone.querySelectorAll(TASK_ITEM).forEach((li) => {\n li.removeAttribute(\"role\");\n li.removeAttribute(\"aria-checked\");\n });\n}\n"],"mappings":"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"}
@@ -11,8 +11,9 @@
11
11
  * value is edited by the host's own control instead, with the reason named.
12
12
  */
13
13
  import type { FieldPath, FieldSchema } from "../../schema/types";
14
+ import type { UnknownValue } from "../unknown-value";
14
15
  /** What a field may hold, in the editor's vocabulary. The editor offers nothing outside it. */
15
- export type RichTextFeature = "h1" | "h2" | "h3" | "h4" | "h5" | "h6" | "blockquote" | "ul" | "ol" | "pre" | "hr" | "bold" | "italic" | "underline" | "strike" | "code" | "link" | "image" | "table" | "pullquote" | "takeaways" | "callout" | "toggle" | "video" | "file";
16
+ export type RichTextFeature = "h1" | "h2" | "h3" | "h4" | "h5" | "h6" | "blockquote" | "ul" | "ol" | "pre" | "hr" | "bold" | "italic" | "underline" | "strike" | "sup" | "sub" | "code" | "link" | "image" | "table" | "pullquote" | "takeaways" | "callout" | "toggle" | "video" | "file" | "checklist" | "button" | "embedAspect";
16
17
  export declare const ALL_FEATURES: readonly RichTextFeature[];
17
18
  export interface RichTextRead {
18
19
  /** the HTML the editor opens on */
@@ -27,6 +28,11 @@ export interface RichTextRead {
27
28
  single: boolean;
28
29
  /** links may open in a new tab */
29
30
  newTab: boolean;
31
+ /**
32
+ * the styles, marks and lists the value holds that the field no longer declares: kept by every write, flagged above
33
+ * the editor with change-to and remove (H4; see `remap`). Absent or empty = none.
34
+ */
35
+ undeclared?: UnknownValue[];
30
36
  }
31
37
  export interface RichTextWrite {
32
38
  /** the value to store, in the surface's own shape */
@@ -44,6 +50,8 @@ export interface KitRichTextCodec {
44
50
  write(html: string, at: RichTextAt, prev: unknown): RichTextWrite;
45
51
  /** the same document, ignoring keys, span splits and storage wrapper */
46
52
  same(a: unknown, b: unknown): boolean;
53
+ /** the stored value with one `undeclared` value (its `key`) changed to `to`, or removed (`to` null); the words stay */
54
+ remap?(value: unknown, at: RichTextAt, key: string, to: string | null): unknown;
47
55
  }
48
56
  declare module "../../context" {
49
57
  interface KitServices {
@@ -1,4 +1,4 @@
1
- //#region src/kit/controls/rich-text/codec.ts
1
+ //#region src/controls/rich-text/codec.ts
2
2
  var ALL_FEATURES = [
3
3
  "h1",
4
4
  "h2",
@@ -15,6 +15,8 @@ var ALL_FEATURES = [
15
15
  "italic",
16
16
  "underline",
17
17
  "strike",
18
+ "sup",
19
+ "sub",
18
20
  "code",
19
21
  "link",
20
22
  "image",
@@ -24,7 +26,10 @@ var ALL_FEATURES = [
24
26
  "callout",
25
27
  "toggle",
26
28
  "video",
27
- "file"
29
+ "file",
30
+ "checklist",
31
+ "button",
32
+ "embedAspect"
28
33
  ];
29
34
  //#endregion
30
35
  export { ALL_FEATURES };
@@ -0,0 +1 @@
1
+ {"version":3,"file":"codec.js","names":[],"sources":["../../../src/controls/rich-text/codec.ts"],"sourcesContent":["/**\n * RICH TEXT · the storage contract between the kit editor and its host.\n *\n * The V2 editor edits HTML (contentEditable). Production stores Portable Text, in the shape the classic editor of the\n * same surface writes (a block array for an entry field, the `{ content, html }` envelope for a component prop). The\n * conversion lives in the host, which owns the real converters, schema conformance and the field's Accept config; the\n * kit never imports them. A host with no codec gets its own control for rich text (LegacyFallback), never a guess.\n *\n * The control opens a value only when it survives the trip editor → codec unchanged (`same`), so nothing the HTML\n * editor cannot hold (a checklist's ticks, a link's rel, an image's layout) is dropped by a first keystroke: such a\n * value is edited by the host's own control instead, with the reason named.\n */\nimport type { FieldPath, FieldSchema } from \"../../schema/types\";\nimport type { UnknownValue } from \"../unknown-value\";\n\n/** What a field may hold, in the editor's vocabulary. The editor offers nothing outside it. */\nexport type RichTextFeature =\n | \"h1\" | \"h2\" | \"h3\" | \"h4\" | \"h5\" | \"h6\"\n | \"blockquote\" | \"ul\" | \"ol\" | \"pre\" | \"hr\"\n | \"bold\" | \"italic\" | \"underline\" | \"strike\" | \"sup\" | \"sub\" | \"code\"\n | \"link\" | \"image\"\n /* blocks, each stored as its own Portable Text block (see dom.ts) */\n | \"table\" | \"pullquote\" | \"takeaways\" | \"callout\" | \"toggle\" | \"video\" | \"file\"\n /* a task list (PT listItem \"check\" + checked) and a call-to-action link (the link markDef with button: true) */\n | \"checklist\" | \"button\"\n /* an embed's Shape (aspect): the host declares it once its stored embed keeps one (plan RT3) */\n | \"embedAspect\";\n\nexport const ALL_FEATURES: readonly RichTextFeature[] = [\n \"h1\", \"h2\", \"h3\", \"h4\", \"h5\", \"h6\", \"blockquote\", \"ul\", \"ol\", \"pre\", \"hr\", \"bold\", \"italic\", \"underline\", \"strike\", \"sup\", \"sub\", \"code\", \"link\", \"image\",\n \"table\", \"pullquote\", \"takeaways\", \"callout\", \"toggle\", \"video\", \"file\", \"checklist\", \"button\", \"embedAspect\",\n];\n\nexport interface RichTextRead {\n /** the HTML the editor opens on */\n html: string;\n /** the stored value as the classic editor would open it (compared against the editor's round trip) */\n seed: unknown;\n /** what this value already cannot carry from an earlier editor, in words (\"2 links\"); shown before the first edit */\n losses: string[];\n /** what the field accepts */\n features: RichTextFeature[];\n /** one paragraph, stored inline (allowMultipleParagraphs: false) */\n single: boolean;\n /** links may open in a new tab */\n newTab: boolean;\n /**\n * the styles, marks and lists the value holds that the field no longer declares: kept by every write, flagged above\n * the editor with change-to and remove (H4; see `remap`). Absent or empty = none.\n */\n undeclared?: UnknownValue[];\n}\n\nexport interface RichTextWrite {\n /** the value to store, in the surface's own shape */\n value: unknown;\n /** what the stored shape would drop from this HTML, in words; non-empty = the write is refused */\n losses: string[];\n}\n\nexport interface RichTextAt {\n field: FieldSchema;\n path: FieldPath;\n}\n\nexport interface KitRichTextCodec {\n read(value: unknown, at: RichTextAt): RichTextRead;\n /** `prev` is the stored value being replaced (its keys are reused so an edit does not re-key the document) */\n write(html: string, at: RichTextAt, prev: unknown): RichTextWrite;\n /** the same document, ignoring keys, span splits and storage wrapper */\n same(a: unknown, b: unknown): boolean;\n /** the stored value with one `undeclared` value (its `key`) changed to `to`, or removed (`to` null); the words stay */\n remap?(value: unknown, at: RichTextAt, key: string, to: string | null): unknown;\n}\n\ndeclare module \"../../context\" {\n interface KitServices {\n /**\n * Stored rich text ↔ the HTML the kit editor edits (see controls/rich-text/codec.ts). Absent → a rich text field\n * draws the host's own control for it (LegacyControl).\n */\n richText?: KitRichTextCodec;\n }\n}\n"],"mappings":";AA4BA,IAAa,eAA2C;CACtD;CAAM;CAAM;CAAM;CAAM;CAAM;CAAM;CAAc;CAAM;CAAM;CAAO;CAAM;CAAQ;CAAU;CAAa;CAAU;CAAO;CAAO;CAAQ;CAAQ;CAClJ;CAAS;CAAa;CAAa;CAAW;CAAU;CAAS;CAAQ;CAAa;CAAU;AAClG"}
@@ -0,0 +1,41 @@
1
+ /**
2
+ * RICH TEXT · Columns (kit-richtext-ui-spec.md §4): V2's columns island, stored as the PT block object
3
+ * `{ _type: "columns", gap: "s" | "m" | "l", columns: { _key, content: PortableTextBlock[] }[] }`: 2–4 columns of
4
+ * text blocks only, depth 1 (plan R5). The editor holds each column as its HTML, as V2 does; the codec maps it.
5
+ *
6
+ * block V2 rich-text/blocks.tsx:536-570: a grid of dashed columns (gap s 8px · m 16px · l 28px), each a nested
7
+ * Editable (paragraphs and marks; paste is plain text), and the bar under it: Add column (≤4), Remove column
8
+ * (the last, ≥2), Gap S | M | L, Remove columns. Escape inside a column leaves the island (Island onKeyDown).
9
+ * editable V2 rich-text/blocks.tsx:54-120, ported here (the kit's own PlainEditable is plain text only).
10
+ */
11
+ import * as React from "react";
12
+ import type { IslandCtx } from "./blocks";
13
+ import { type IslandEl } from "./dom";
14
+ export type ColumnsGap = "s" | "m" | "l";
15
+ export interface ColumnsModel {
16
+ gap: ColumnsGap;
17
+ cols: {
18
+ id: string;
19
+ html: string;
20
+ }[];
21
+ }
22
+ export declare const COLUMNS_MIN = 2;
23
+ export declare const COLUMNS_MAX = 4;
24
+ export declare const columnsDefault: () => ColumnsModel;
25
+ /** A small rich-text region inside a block (V2 Editable): paragraphs and marks, plain-text paste, a placeholder. */
26
+ export declare function Editable({ html, onChange, placeholder, className, readOnly, label, autoFocus, ...rest }: {
27
+ html: string;
28
+ onChange: (v: string) => void;
29
+ placeholder?: string;
30
+ className?: string;
31
+ readOnly?: boolean;
32
+ label: string;
33
+ autoFocus?: boolean;
34
+ } & Omit<React.HTMLAttributes<HTMLDivElement>, "onChange">): import("react/jsx-runtime").JSX.Element;
35
+ export declare function ColumnsBlock({ m, set, el, ctx, autoFocus, }: {
36
+ m: ColumnsModel;
37
+ set: (fn: (m: ColumnsModel) => ColumnsModel, label?: string) => void;
38
+ el: IslandEl;
39
+ ctx: IslandCtx;
40
+ autoFocus: boolean;
41
+ }): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,181 @@
1
+ import { cn } from "../../lib/cn.js";
2
+ import { Button, IconButton } from "../../ui/button.js";
3
+ import { Segmented } from "../../ui/controls.js";
4
+ import { Tooltip } from "../../ui/overlay.js";
5
+ import { placeCaret, rid } from "./dom.js";
6
+ import * as React from "react";
7
+ import { jsx, jsxs } from "react/jsx-runtime";
8
+ import { IconMinus, IconPlus, IconTrash } from "@tabler/icons-react";
9
+ //#region src/controls/rich-text/columns.tsx
10
+ /**
11
+ * RICH TEXT · Columns (kit-richtext-ui-spec.md §4): V2's columns island, stored as the PT block object
12
+ * `{ _type: "columns", gap: "s" | "m" | "l", columns: { _key, content: PortableTextBlock[] }[] }`: 2–4 columns of
13
+ * text blocks only, depth 1 (plan R5). The editor holds each column as its HTML, as V2 does; the codec maps it.
14
+ *
15
+ * block V2 rich-text/blocks.tsx:536-570: a grid of dashed columns (gap s 8px · m 16px · l 28px), each a nested
16
+ * Editable (paragraphs and marks; paste is plain text), and the bar under it: Add column (≤4), Remove column
17
+ * (the last, ≥2), Gap S | M | L, Remove columns. Escape inside a column leaves the island (Island onKeyDown).
18
+ * editable V2 rich-text/blocks.tsx:54-120, ported here (the kit's own PlainEditable is plain text only).
19
+ */
20
+ var COLUMNS_MIN = 2;
21
+ var COLUMNS_MAX = 4;
22
+ var columnsDefault = () => ({
23
+ gap: "m",
24
+ cols: [{
25
+ id: rid("col"),
26
+ html: ""
27
+ }, {
28
+ id: rid("col"),
29
+ html: ""
30
+ }]
31
+ });
32
+ var GAP = {
33
+ s: "8px",
34
+ m: "16px",
35
+ l: "28px"
36
+ };
37
+ /** V2 blocks.tsx:191: the controls row under a block, muted at rest, full strength on hover / focus */
38
+ var BAR = "mt-1.5 flex flex-wrap items-center gap-1 text-kit-fg-3 opacity-70 transition-opacity group-hover/blk:opacity-100 group-focus-within/blk:opacity-100 pointer-coarse:opacity-100";
39
+ var Sep = () => /* @__PURE__ */ jsx("span", {
40
+ "aria-hidden": true,
41
+ className: "mx-0.5 h-4 w-px shrink-0 bg-kit-line"
42
+ });
43
+ /** A small rich-text region inside a block (V2 Editable): paragraphs and marks, plain-text paste, a placeholder. */
44
+ function Editable({ html, onChange, placeholder, className, readOnly, label, autoFocus, ...rest }) {
45
+ const ref = React.useRef(null);
46
+ React.useLayoutEffect(() => {
47
+ const el = ref.current;
48
+ if (!el || document.activeElement === el) return;
49
+ if (el.innerHTML !== html) el.innerHTML = html;
50
+ }, [html]);
51
+ React.useEffect(() => {
52
+ if (!autoFocus || !ref.current) return;
53
+ ref.current.focus({ preventScroll: false });
54
+ placeCaret(ref.current);
55
+ }, []);
56
+ return /* @__PURE__ */ jsx("div", {
57
+ ...rest,
58
+ ref,
59
+ role: "textbox",
60
+ "aria-label": label,
61
+ "aria-multiline": true,
62
+ tabIndex: readOnly ? -1 : 0,
63
+ contentEditable: !readOnly,
64
+ suppressContentEditableWarning: true,
65
+ spellCheck: true,
66
+ "data-placeholder": placeholder,
67
+ onInput: (e) => {
68
+ const el = e.currentTarget;
69
+ if (!el.textContent && !el.querySelector("img,br + br")) el.innerHTML = "";
70
+ onChange(el.innerHTML);
71
+ },
72
+ onPaste: (e) => {
73
+ e.preventDefault();
74
+ document.execCommand?.("insertText", false, e.clipboardData.getData("text/plain"));
75
+ },
76
+ className: cn("min-w-0 cursor-text whitespace-pre-wrap break-words outline-none focus-visible:shadow-none empty:before:pointer-events-none empty:before:text-kit-fg-4 empty:before:content-[attr(data-placeholder)]", className)
77
+ });
78
+ }
79
+ function ColumnsBlock({ m, set, el, ctx, autoFocus }) {
80
+ const ro = !!ctx.readOnly;
81
+ return /* @__PURE__ */ jsxs("div", {
82
+ className: "group/blk",
83
+ children: [/* @__PURE__ */ jsx("div", {
84
+ className: "grid",
85
+ style: {
86
+ gridTemplateColumns: `repeat(${m.cols.length}, minmax(0, 1fr))`,
87
+ gap: GAP[m.gap]
88
+ },
89
+ children: m.cols.map((c, i) => /* @__PURE__ */ jsx("div", {
90
+ className: "min-h-14 rounded-kit-md border border-dashed border-kit-line px-2.5 py-2 transition-colors focus-within:border-kit-line-strong hover:border-kit-line-strong",
91
+ children: /* @__PURE__ */ jsx(Editable, {
92
+ label: `Column ${i + 1}`,
93
+ html: c.html,
94
+ readOnly: ro,
95
+ autoFocus: autoFocus && i === 0,
96
+ placeholder: `Column ${i + 1}`,
97
+ onChange: (html) => set((x) => ({
98
+ ...x,
99
+ cols: x.cols.map((y) => y.id === c.id ? {
100
+ ...y,
101
+ html
102
+ } : y)
103
+ }), `Edit column ${i + 1}`),
104
+ className: "min-h-10 [&_p+p]:mt-2"
105
+ })
106
+ }, c.id))
107
+ }), ro ? null : /* @__PURE__ */ jsxs("div", {
108
+ className: BAR,
109
+ children: [
110
+ /* @__PURE__ */ jsx(Button, {
111
+ size: "xs",
112
+ variant: "ghost",
113
+ leftIcon: /* @__PURE__ */ jsx(IconPlus, { stroke: 1.5 }),
114
+ disabled: m.cols.length >= 4,
115
+ onClick: () => set((x) => ({
116
+ ...x,
117
+ cols: [...x.cols, {
118
+ id: rid("col"),
119
+ html: ""
120
+ }]
121
+ }), "Add column"),
122
+ children: "Add column"
123
+ }),
124
+ /* @__PURE__ */ jsx(Button, {
125
+ size: "xs",
126
+ variant: "ghost",
127
+ leftIcon: /* @__PURE__ */ jsx(IconMinus, { stroke: 1.5 }),
128
+ disabled: m.cols.length <= 2,
129
+ onClick: () => set((x) => ({
130
+ ...x,
131
+ cols: x.cols.slice(0, -1)
132
+ }), "Remove column"),
133
+ children: "Remove column"
134
+ }),
135
+ /* @__PURE__ */ jsx(Sep, {}),
136
+ /* @__PURE__ */ jsx("span", {
137
+ className: "px-1 text-kit-xs text-kit-fg-3",
138
+ children: "Gap"
139
+ }),
140
+ /* @__PURE__ */ jsx(Segmented, {
141
+ "aria-label": "Gap",
142
+ size: "sm",
143
+ value: m.gap,
144
+ onChange: (gap) => set((x) => ({
145
+ ...x,
146
+ gap
147
+ }), "Change column gap"),
148
+ items: [
149
+ {
150
+ value: "s",
151
+ label: "S"
152
+ },
153
+ {
154
+ value: "m",
155
+ label: "M"
156
+ },
157
+ {
158
+ value: "l",
159
+ label: "L"
160
+ }
161
+ ]
162
+ }),
163
+ /* @__PURE__ */ jsx("span", { className: "flex-1" }),
164
+ /* @__PURE__ */ jsx(Tooltip, {
165
+ content: "Remove columns",
166
+ children: /* @__PURE__ */ jsx(IconButton, {
167
+ size: "xs",
168
+ label: "Remove columns",
169
+ onClick: () => ctx.remove(el),
170
+ className: "hover:text-kit-danger-fg",
171
+ children: /* @__PURE__ */ jsx(IconTrash, { stroke: 1.5 })
172
+ })
173
+ })
174
+ ]
175
+ })]
176
+ });
177
+ }
178
+ //#endregion
179
+ export { COLUMNS_MAX, COLUMNS_MIN, ColumnsBlock, Editable, columnsDefault };
180
+
181
+ //# sourceMappingURL=columns.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"columns.js","names":[],"sources":["../../../src/controls/rich-text/columns.tsx"],"sourcesContent":["/**\n * RICH TEXT · Columns (kit-richtext-ui-spec.md §4): V2's columns island, stored as the PT block object\n * `{ _type: \"columns\", gap: \"s\" | \"m\" | \"l\", columns: { _key, content: PortableTextBlock[] }[] }`: 2–4 columns of\n * text blocks only, depth 1 (plan R5). The editor holds each column as its HTML, as V2 does; the codec maps it.\n *\n * block V2 rich-text/blocks.tsx:536-570: a grid of dashed columns (gap s 8px · m 16px · l 28px), each a nested\n * Editable (paragraphs and marks; paste is plain text), and the bar under it: Add column (≤4), Remove column\n * (the last, ≥2), Gap S | M | L, Remove columns. Escape inside a column leaves the island (Island onKeyDown).\n * editable V2 rich-text/blocks.tsx:54-120, ported here (the kit's own PlainEditable is plain text only).\n */\nimport * as React from \"react\";\nimport { IconMinus, IconPlus, IconTrash } from \"@tabler/icons-react\";\nimport { cn } from \"../../lib/cn\";\nimport { Button, IconButton } from \"../../ui/button\";\nimport { Segmented } from \"../../ui/controls\";\nimport { Tooltip } from \"../../ui/overlay\";\nimport type { IslandCtx } from \"./blocks\";\nimport { placeCaret, rid, type IslandEl } from \"./dom\";\n\nexport type ColumnsGap = \"s\" | \"m\" | \"l\";\nexport interface ColumnsModel {\n gap: ColumnsGap;\n cols: { id: string; html: string }[];\n}\nexport const COLUMNS_MIN = 2;\nexport const COLUMNS_MAX = 4;\nexport const columnsDefault = (): ColumnsModel => ({ gap: \"m\", cols: [{ id: rid(\"col\"), html: \"\" }, { id: rid(\"col\"), html: \"\" }] });\nconst GAP: Record<ColumnsGap, string> = { s: \"8px\", m: \"16px\", l: \"28px\" };\n/** V2 blocks.tsx:191: the controls row under a block, muted at rest, full strength on hover / focus */\nconst BAR = \"mt-1.5 flex flex-wrap items-center gap-1 text-kit-fg-3 opacity-70 transition-opacity group-hover/blk:opacity-100 group-focus-within/blk:opacity-100 pointer-coarse:opacity-100\";\nconst Sep = () => <span aria-hidden className=\"mx-0.5 h-4 w-px shrink-0 bg-kit-line\" />;\n\n/** A small rich-text region inside a block (V2 Editable): paragraphs and marks, plain-text paste, a placeholder. */\nexport function Editable({\n html, onChange, placeholder, className, readOnly, label, autoFocus, ...rest\n}: {\n html: string;\n onChange: (v: string) => void;\n placeholder?: string;\n className?: string;\n readOnly?: boolean;\n label: string;\n autoFocus?: boolean;\n} & Omit<React.HTMLAttributes<HTMLDivElement>, \"onChange\">) {\n const ref = React.useRef<HTMLDivElement>(null);\n React.useLayoutEffect(() => {\n const el = ref.current;\n if (!el || document.activeElement === el) return;\n if (el.innerHTML !== html) el.innerHTML = html;\n }, [html]);\n React.useEffect(() => {\n if (!autoFocus || !ref.current) return;\n ref.current.focus({ preventScroll: false });\n placeCaret(ref.current);\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, []);\n return (\n <div\n {...rest}\n ref={ref}\n role=\"textbox\"\n aria-label={label}\n aria-multiline\n tabIndex={readOnly ? -1 : 0}\n contentEditable={!readOnly}\n suppressContentEditableWarning\n spellCheck\n data-placeholder={placeholder}\n onInput={(e) => {\n const el = e.currentTarget;\n if (!el.textContent && !el.querySelector(\"img,br + br\")) el.innerHTML = \"\";\n onChange(el.innerHTML);\n }}\n onPaste={(e) => {\n e.preventDefault();\n document.execCommand?.(\"insertText\", false, e.clipboardData.getData(\"text/plain\"));\n }}\n className={cn(\n \"min-w-0 cursor-text whitespace-pre-wrap break-words outline-none focus-visible:shadow-none empty:before:pointer-events-none empty:before:text-kit-fg-4 empty:before:content-[attr(data-placeholder)]\",\n className,\n )}\n />\n );\n}\n\nexport function ColumnsBlock({\n m, set, el, ctx, autoFocus,\n}: {\n m: ColumnsModel;\n set: (fn: (m: ColumnsModel) => ColumnsModel, label?: string) => void;\n el: IslandEl;\n ctx: IslandCtx;\n autoFocus: boolean;\n}) {\n const ro = !!ctx.readOnly;\n return (\n <div className=\"group/blk\">\n <div className=\"grid\" style={{ gridTemplateColumns: `repeat(${m.cols.length}, minmax(0, 1fr))`, gap: GAP[m.gap] }}>\n {m.cols.map((c, i) => (\n <div key={c.id} className=\"min-h-14 rounded-kit-md border border-dashed border-kit-line px-2.5 py-2 transition-colors focus-within:border-kit-line-strong hover:border-kit-line-strong\">\n <Editable\n label={`Column ${i + 1}`}\n html={c.html}\n readOnly={ro}\n autoFocus={autoFocus && i === 0}\n placeholder={`Column ${i + 1}`}\n onChange={(html) => set((x) => ({ ...x, cols: x.cols.map((y) => (y.id === c.id ? { ...y, html } : y)) }), `Edit column ${i + 1}`)}\n className=\"min-h-10 [&_p+p]:mt-2\"\n />\n </div>\n ))}\n </div>\n {ro ? null : (\n <div className={BAR}>\n <Button\n size=\"xs\"\n variant=\"ghost\"\n leftIcon={<IconPlus stroke={1.5} />}\n disabled={m.cols.length >= COLUMNS_MAX}\n onClick={() => set((x) => ({ ...x, cols: [...x.cols, { id: rid(\"col\"), html: \"\" }] }), \"Add column\")}\n >\n Add column\n </Button>\n <Button\n size=\"xs\"\n variant=\"ghost\"\n leftIcon={<IconMinus stroke={1.5} />}\n disabled={m.cols.length <= COLUMNS_MIN}\n onClick={() => set((x) => ({ ...x, cols: x.cols.slice(0, -1) }), \"Remove column\")}\n >\n Remove column\n </Button>\n <Sep />\n <span className=\"px-1 text-kit-xs text-kit-fg-3\">Gap</span>\n <Segmented<ColumnsGap>\n aria-label=\"Gap\"\n size=\"sm\"\n value={m.gap}\n onChange={(gap) => set((x) => ({ ...x, gap }), \"Change column gap\")}\n items={[{ value: \"s\", label: \"S\" }, { value: \"m\", label: \"M\" }, { value: \"l\", label: \"L\" }]}\n />\n <span className=\"flex-1\" />\n <Tooltip content=\"Remove columns\">\n <IconButton size=\"xs\" label=\"Remove columns\" onClick={() => ctx.remove(el)} className=\"hover:text-kit-danger-fg\">\n <IconTrash stroke={1.5} />\n </IconButton>\n </Tooltip>\n </div>\n )}\n </div>\n );\n}\n"],"mappings":"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"}
@@ -2,7 +2,7 @@ import { type KitServices } from "../../context";
2
2
  import type { ComponentModel, IslandEl } from "./dom";
3
3
  import type { IslandCtx } from "./blocks";
4
4
  type UseComponentInfo = NonNullable<KitServices["useComponentInfo"]>;
5
- type SetComponent = (patch: (m: ComponentModel) => ComponentModel, label: string, record?: boolean) => void;
5
+ type SetComponent = (patch: Partial<ComponentModel> | ((m: ComponentModel) => ComponentModel), label: string, record?: boolean) => void;
6
6
  export declare function ComponentCard({ m, el, ctx, use, overrides, set, }: {
7
7
  m: ComponentModel;
8
8
  el: IslandEl;