@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 @@
1
+ {"version":3,"file":"button.js","names":[],"sources":["../../src/controls/button.tsx"],"sourcesContent":["/**\n * BUTTON — label + link + look as ONE unit (V2 HEAD kit/controls/link.tsx \"Button\", DESIGN §8.8, CPO D43 · D45 · D46).\n *\n * - <ButtonControl> at rest: one FieldUnit, two rows. The label row drills into the button screen (form.navigate → the\n * \"button\" frame); the link row edits the link in place (LinkQuickEdit).\n * - <ButtonScreen> the one button screen (the frame body): preview · label · link (LinkForm) · appearance (style grid,\n * size, leading icon, arrow).\n * - <ButtonStyleGrid>, <ButtonPreview>, <StyleGlyph> — the pieces both draw.\n *\n * Stored shape (prod `button`, adapters/values.ts buttonToProd / buttonFromProd; backend buttonValueProblem). The kit\n * value is the flattened V2 button the adapter hands in. What this control writes keeps that value's keys:\n * - the look goes in the key the value already uses — `style` when it has one, else `variant` (what prod renderers\n * read) — and never both (buttonToProd names an equal pair as lost, so the dock would refuse the write);\n * - `rel: \"follow\"` is never written (prod's rel list is nofollow · sponsored · ugc) and `newTab: false`/`target` only\n * where the stored value had that key (storedLink);\n * - `icon` is a dock icon name (DOCK_ICON_NAMES): the picker offers only icons that are dock names.\n *\n * \"Full width\" writes `fullWidth: true`, and off writes `false` only where the stored value had the key (as Show arrow);\n * every renderer draws it (hosted `bcms-btn-full`, the SDKs' and in-place publishing's `data-full-width`).\n *\n * Deviation from V2, because prod has nothing behind it: an unset look reads \"Default\" (V2 drew Primary, and guessed\n * Outline for a field named \"secondary\"). The preview is V2's: the site palette (--kit-preview-paper / -ink / -primary /\n * -primary-on / -contrast / -contrast-on / -outline, which a host may set to the project's colours) on the paper, and the\n * chrome swatches in the style grid.\n */\nimport * as React from \"react\";\nimport { IconArrowRight, IconChevronDown, IconChevronRight, IconSearch, IconX } from \"@tabler/icons-react\";\nimport { cn } from \"../lib/cn\";\nimport { isObj } from \"../lib/path\";\nimport { KIT_ICONS, KitIcon, iconLabel } from \"../lib/icons\";\nimport { BUTTON_VARIANTS, DOCK_ICON_NAME_SET } from \"../adapters/prod-types\";\nimport { useForm, useKitEnv } from \"../context\";\nimport { FieldUnit } from \"../engine/grouping\";\nimport { Input } from \"../ui/input\";\nimport { Segmented, Switch } from \"../ui/controls\";\nimport { Popover, PopoverAnchor, PopoverContent, PopoverTrigger } from \"../ui/overlay\";\nimport type { ControlProps } from \"../types\";\nimport { LinkForm, LinkLine, LinkQuickEdit, TARGET_KEYS, finalizeLink, findTarget, hasLink, linkText, normLink, storedLink, useLinkTargets, type ButtonStyle, type LinkValue } from \"./link\";\n\nexport const STYLE_ITEMS: { value: ButtonStyle; label: string }[] = [\n { value: \"primary\", label: \"Primary\" },\n { value: \"secondary\", label: \"Secondary\" },\n { value: \"outline\", label: \"Outline\" },\n { value: \"link\", label: \"Text link\" },\n];\nconst SIZE_LABEL = { sm: \"Small\", md: \"Medium\", lg: \"Large\" } as const;\nconst isVariant = (x: unknown): x is string => typeof x === \"string\" && (BUTTON_VARIANTS as readonly string[]).includes(x);\n\n/** The look prod renders: the first valid of variant, style (buttonToProd's rule). */\nexport function lookOf(v: Pick<LinkValue, \"variant\" | \"style\">): string | undefined {\n return [v.variant, v.style].find(isVariant);\n}\n/** \"Brand\" for a stored look outside the four styles; undefined when unset. */\nexport function lookLabel(look: string | undefined): string {\n if (!look) return \"Default\";\n return STYLE_ITEMS.find((s) => s.value === look)?.label ?? look.charAt(0).toUpperCase() + look.slice(1);\n}\n\n/**\n * The next stored button: `raw` (the value as the field holds it) with `patch` applied, keyed like `raw`. A look in the\n * patch (`style`) lands in the key `raw` uses for it.\n */\nexport function nextButton(raw: unknown, patch: Partial<LinkValue>): LinkValue {\n const base: LinkValue = isObj(raw) ? ({ ...(raw as object) } as LinkValue) : { href: \"\" };\n const { style, ...rest } = patch;\n const out: LinkValue = { ...base, ...rest };\n // prod requires both strings (buttonToProd names a missing one as lost, and the dock refuses the write)\n if (typeof out.href !== \"string\") out.href = \"\";\n if (typeof out.label !== \"string\") out.label = \"\";\n if (style !== undefined) {\n const key = isObj(raw) && raw.style !== undefined ? \"style\" : \"variant\";\n delete out.style;\n delete out.variant;\n out[key] = style;\n }\n return storedLink(out, raw);\n}\n\n/** The icons a button can carry: the kit's drawn icons that are also dock names (the backend checks the name). */\nexport const BUTTON_ICONS: string[] = Object.keys(KIT_ICONS).filter((n) => DOCK_ICON_NAME_SET.has(n));\n\n/** D46: four styles never sit in a row of tabs. The option IS the visual, so it is a 2×2 grid of live previews (one\n * radiogroup: Tab enters on the checked style, arrows move and pick). A stored look outside the four is listed too. */\nexport function ButtonStyleGrid({\n v,\n onPick,\n \"aria-label\": ariaLabel,\n size = \"md\",\n}: {\n v: LinkValue;\n onPick: (s: ButtonStyle) => void;\n \"aria-label\": string;\n size?: \"sm\" | \"md\";\n}) {\n const cur = lookOf(v);\n const items: { value: string; label: string }[] = cur && !STYLE_ITEMS.some((s) => s.value === cur) ? [...STYLE_ITEMS, { value: cur, label: lookLabel(cur) }] : STYLE_ITEMS;\n const onKey = (e: React.KeyboardEvent, i: number) => {\n const d = e.key === \"ArrowRight\" || e.key === \"ArrowDown\" ? 1 : e.key === \"ArrowLeft\" || e.key === \"ArrowUp\" ? -1 : 0;\n if (!d) return;\n e.preventDefault();\n const next = items[(i + d + items.length) % items.length];\n onPick(next.value as ButtonStyle);\n const group = (e.currentTarget as HTMLElement).parentElement;\n requestAnimationFrame(() => group?.querySelector<HTMLElement>(`[data-style=\"${next.value}\"]`)?.focus());\n };\n return (\n <div className=\"grid grid-cols-2 gap-1.5\" role=\"radiogroup\" aria-label={ariaLabel}>\n {items.map((s, i) => {\n const on = cur === s.value;\n return (\n <button\n key={s.value}\n type=\"button\"\n role=\"radio\"\n data-style={s.value}\n aria-checked={on}\n tabIndex={on || (!items.some((x) => x.value === cur) && i === 0) ? 0 : -1}\n onKeyDown={(e) => onKey(e, i)}\n onClick={() => onPick(s.value as ButtonStyle)}\n className={cn(\n \"flex min-w-0 items-center gap-2 rounded-kit-md border px-2 transition-colors\",\n size === \"sm\" ? \"h-8 text-kit-xs\" : \"h-9 text-kit-sm\",\n on ? \"border-[var(--kit-emphasis-line)] bg-kit-selected text-kit-fg\" : \"border-kit-line text-kit-fg-2 hover:border-kit-line-strong hover:text-kit-fg\",\n )}\n >\n <ButtonPreview v={{ ...v, style: s.value as ButtonStyle, variant: undefined, label: \"Aa\", icon: undefined, arrow: false }} small chrome />\n <span className=\"truncate\">{s.label}</span>\n </button>\n );\n })}\n </div>\n );\n}\n\n/**\n * The site's button as the site draws it (V2 link.tsx ButtonPreview: the site palette, not app tokens). On the preview\n * paper it keeps the site's own colours in both themes; `chrome` = drawn on app chrome (the style grid), where the\n * dark-ink styles flip so they still read on a dark panel. Prod looks beyond the four: brand as primary, dark as\n * secondary, any other in the muted kit fill.\n */\nexport function ButtonPreview({ v, className, small, chrome }: { v: LinkValue; className?: string; small?: boolean; chrome?: boolean }) {\n const look = lookOf(v) ?? \"primary\";\n const style = look === \"brand\" ? \"primary\" : look === \"dark\" ? \"secondary\" : look;\n const size = small ? \"sm\" : v.size ?? \"md\";\n return (\n <span\n className={cn(\n \"inline-flex max-w-full items-center justify-center gap-1.5 truncate font-medium transition-colors\",\n size === \"sm\" ? \"h-6 rounded-kit-md px-2 text-kit-xs\" : size === \"lg\" ? \"h-10 rounded-kit-lg px-4 text-kit-base\" : \"h-8 rounded-kit-lg px-3 text-kit-sm\",\n style === \"primary\" && \"bg-kit-preview-primary text-kit-preview-primary-on\",\n style === \"secondary\" && (chrome ? \"bg-kit-preview-contrast text-kit-preview-contrast-on\" : \"bg-kit-preview-ink text-kit-preview-paper\"),\n style === \"outline\" && (chrome ? \"border border-kit-preview-outline text-kit-fg\" : \"border border-kit-preview-ink/25 text-kit-preview-ink\"),\n style === \"link\" && \"h-auto px-0 text-kit-preview-primary underline underline-offset-4\",\n !STYLE_ITEMS.some((x) => x.value === style) && \"bg-kit-muted text-kit-fg\",\n v.fullWidth && !small && \"w-full\",\n className,\n )}\n >\n {v.icon ? <KitIcon name={v.icon} className=\"size-3.5 shrink-0\" /> : null}\n <span className=\"truncate\">{v.label || \"Button\"}</span>\n {v.arrow ? <IconArrowRight className=\"size-3.5 shrink-0\" stroke={1.75} /> : null}\n </span>\n );\n}\n\n/** A 16px neutral glyph of the style (filled · outlined · underlined) — brand-free, so the field stays calm. */\nexport function StyleGlyph({ style, className }: { style?: string; className?: string }) {\n return (\n <span aria-hidden className={cn(\"flex size-4 shrink-0 items-center justify-center\", className)}>\n {style === \"link\" ? (\n <span className=\"h-[2px] w-3.5 rounded-full bg-kit-fg-2\" />\n ) : (\n <span className={cn(\"h-2.5 w-4 rounded-[3px]\", style === \"outline\" ? \"border-[1.5px] border-kit-fg-2\" : style === \"secondary\" || style === \"light\" || style === \"tertiary\" ? \"bg-kit-fg-3\" : \"bg-kit-fg\")} />\n )}\n </span>\n );\n}\n\n/** The leading-icon picker over BUTTON_ICONS, \"No icon\" first: V2's IconPickerGrid (icon.tsx) — search box, 8-column\n * grid in a 224px scroll. The tiles stay one radiogroup (the dash's semantics; V2 draws a listbox). */\nexport function ButtonIconPicker({ value, onPick }: { value?: string; onPick: (icon: string | undefined) => void }) {\n const [q, setQ] = React.useState(\"\");\n const query = q.trim().toLowerCase();\n const shown = query ? BUTTON_ICONS.filter((n) => n.includes(query.replace(/\\s+/g, \"-\"))) : BUTTON_ICONS;\n const tile = (on: boolean) =>\n cn(\"flex aspect-square items-center justify-center rounded-kit-md text-kit-fg-2 transition-colors hover:bg-kit-hover hover:text-kit-fg\", on && \"bg-kit-selected text-kit-fg ring-1 ring-inset ring-kit-line-strong\");\n return (\n <div data-icon-picker className=\"flex flex-col gap-2\">\n <label className=\"flex h-8 items-center gap-2 rounded-kit-md bg-kit-muted px-2.5 text-kit-fg-3 focus-within:bg-kit-field-bg focus-within:ring-1 focus-within:ring-kit-line-strong\">\n <IconSearch className=\"size-4 shrink-0\" stroke={1.5} aria-hidden />\n <input\n autoFocus\n value={q}\n onChange={(e) => setQ(e.target.value)}\n placeholder=\"Search icons\"\n aria-label=\"Search icons\"\n className=\"h-full min-w-0 flex-1 bg-transparent text-kit-sm text-kit-fg outline-none placeholder:text-kit-fg-3\"\n />\n </label>\n <div className=\"max-h-56 overflow-y-auto pr-0.5\">\n <div role=\"radiogroup\" aria-label=\"Leading icon\" className=\"grid gap-0.5\" style={{ gridTemplateColumns: \"repeat(8, minmax(0, 1fr))\" }}>\n {query ? null : (\n <button type=\"button\" role=\"radio\" aria-checked={!value} aria-label=\"No icon\" onClick={() => onPick(undefined)} className={tile(!value)}>\n <IconX className=\"size-4\" stroke={1.5} aria-hidden />\n </button>\n )}\n {shown.map((n) => (\n <button key={n} type=\"button\" role=\"radio\" aria-checked={value === n} aria-label={iconLabel(n)} onClick={() => onPick(n)} className={tile(value === n)}>\n <KitIcon name={n} className=\"size-[18px]\" />\n </button>\n ))}\n </div>\n {shown.length === 0 ? <p className=\"py-6 text-center text-kit-sm text-kit-fg-3\">No icons match “{q}”</p> : null}\n </div>\n </div>\n );\n}\n\n/** The ONE button screen: preview · label · link (+ new tab, rel) · appearance (style, size, icon, arrow). */\nexport function ButtonScreen({ value, onChange, readOnly, title = \"Button\" }: { value: unknown; onChange: (v: LinkValue) => void; readOnly?: boolean; title?: string }) {\n const v = normLink(value);\n const set = (p: Partial<LinkValue>) => onChange(nextButton(value, p));\n const [iconOpen, setIconOpen] = React.useState(false);\n const labelId = React.useId();\n const arrowId = React.useId();\n const fullId = React.useId();\n return (\n <fieldset disabled={readOnly} className=\"flex min-w-0 flex-col gap-5\">\n <div data-button-preview=\"\" className=\"flex min-h-20 items-center justify-center rounded-kit-lg bg-kit-preview-paper px-4 py-5 [filter:var(--kit-paper-filter)]\">\n <ButtonPreview v={v} />\n </div>\n <Row label=\"Label\" htmlFor={labelId}>\n <Input id={labelId} value={v.label ?? \"\"} onChange={(e) => set({ label: e.target.value })} placeholder=\"Shop now\" />\n </Row>\n <div className=\"flex flex-col gap-1.5\" role=\"group\" aria-label={`${title} link`}>\n <span className=\"text-kit-sm font-medium text-kit-fg-2\">Link</span>\n <LinkForm\n readOnly={readOnly}\n value={v}\n onChange={(n) => {\n // a script link is never written; LinkForm says why under the target\n const out = finalizeLink(n);\n if (out) set(linkPart(out));\n }}\n />\n </div>\n <div className=\"flex flex-col gap-4 border-t border-kit-line pt-4\">\n <span className=\"text-kit-xs font-medium text-kit-fg-3\">Appearance</span>\n <Row label=\"Style\">\n <ButtonStyleGrid v={v} aria-label={`${title} style`} onPick={(style) => set({ style })} />\n </Row>\n <Row label=\"Size\">\n <Segmented<\"sm\" | \"md\" | \"lg\">\n aria-label={`${title} size`}\n value={v.size ?? \"md\"}\n onChange={(s) => set({ size: s })}\n items={[\n { value: \"sm\", label: \"Small\" },\n { value: \"md\", label: \"Medium\" },\n { value: \"lg\", label: \"Large\" },\n ]}\n className=\"w-full [&>button]:flex-1\"\n />\n </Row>\n <Row label=\"Leading icon\">\n <Popover open={iconOpen} onOpenChange={setIconOpen}>\n <PopoverTrigger\n render={\n <button\n type=\"button\"\n className=\"flex h-8 w-full items-center gap-2 rounded-kit-md border border-kit-field-border bg-kit-field-bg px-2.5 text-left text-kit-sm text-kit-fg hover:border-kit-field-border-hover\"\n />\n }\n >\n {v.icon ? <KitIcon name={v.icon} className=\"size-4 text-kit-fg-2\" /> : <span className=\"size-4 rounded-kit-md border border-dashed border-[var(--kit-emphasis-line)]\" />}\n <span className={cn(\"flex-1 truncate\", !v.icon && \"text-kit-fg-3\")}>{v.icon ? iconLabel(v.icon) : \"No icon\"}</span>\n <IconChevronDown className=\"size-3.5 text-kit-fg-3\" stroke={1.5} />\n </PopoverTrigger>\n <PopoverContent className=\"w-[300px] p-2\">\n <ButtonIconPicker\n value={v.icon}\n onPick={(k) => {\n set({ icon: k });\n setIconOpen(false);\n }}\n />\n </PopoverContent>\n </Popover>\n </Row>\n <div className=\"flex flex-col gap-2\">\n <label htmlFor={arrowId} className=\"flex min-h-7 cursor-pointer items-center justify-between gap-3\">\n <span className=\"text-kit-sm text-kit-fg-2\">Show arrow</span>\n <Switch disabled={readOnly} id={arrowId} size=\"sm\" checked={!!v.arrow} onCheckedChange={(c) => set({ arrow: c ? true : isObj(value) && \"arrow\" in value ? false : undefined })} />\n </label>\n <label htmlFor={fullId} className=\"flex min-h-7 cursor-pointer items-center justify-between gap-3\">\n <span className=\"text-kit-sm text-kit-fg-2\">Full width</span>\n <Switch\n disabled={readOnly}\n id={fullId}\n size=\"sm\"\n checked={v.fullWidth === true}\n onCheckedChange={(c) => set({ fullWidth: c ? true : isObj(value) && \"fullWidth\" in value ? false : undefined })}\n />\n </label>\n </div>\n </div>\n </fieldset>\n );\n}\n\n/** The link half of a link value (what LinkForm / the quick edit own); the label and the look stay the button's. */\nfunction linkPart(n: LinkValue): Partial<LinkValue> {\n const { label: _l, style: _s, variant: _v, size: _z, arrow: _a, icon: _i, fullWidth: _f, ...link } = n;\n // a key the new link no longer has (a picked page drops the typed email) is cleared, not kept from before\n return { ...TARGET_KEYS, email: undefined, phone: undefined, subject: undefined, ...link };\n}\n\nfunction Row({ label, children, htmlFor }: { label: string; children: React.ReactNode; htmlFor?: string }) {\n return (\n <div className=\"flex flex-col gap-1.5\">\n <label htmlFor={htmlFor} className=\"text-kit-sm font-medium text-kit-fg-2\">\n {label}\n </label>\n {children}\n </div>\n );\n}\n\n/**\n * Button field at rest: ONE unit between two hairlines (fieldset-like).\n * [style glyph] Label ……………… Primary · Medium › → drills into the button screen (\"… › Button\")\n * [page icon] Title /path → edits the link in place\n */\nexport function ButtonControl({ value, onChange, readOnly, id, path, field }: ControlProps) {\n const v = normLink(value);\n const form = useForm();\n const { variant } = useKitEnv();\n const [open, setOpen] = React.useState(false);\n const [editingLink, setEditingLink] = React.useState(false);\n const { targets } = useLinkTargets();\n const target = findTarget(targets, v);\n const linkBtn = React.useRef<HTMLButtonElement>(null);\n const look = lookOf(v);\n const openSettings = () => (form ? form.navigate(path) : setOpen(true));\n const h = variant === \"document\" ? \"h-10\" : \"h-9\";\n const head = (\n <button\n id={id}\n type=\"button\"\n onClick={readOnly && !form ? undefined : openSettings}\n aria-label={`${field.title}: ${v.label || \"no label\"}. Open button settings`}\n className={cn(\"group/bhead flex w-full min-w-0 items-center gap-2.5 px-2.5 text-left outline-none transition-colors hover:bg-kit-hover focus-visible:bg-kit-hover\", h)}\n >\n <StyleGlyph style={look} />\n <span className={cn(\"min-w-0 flex-1 truncate text-kit-sm font-medium\", v.label ? \"text-kit-fg\" : \"text-kit-fg-3\")}>{v.label || \"Add a label\"}</span>\n <span className=\"shrink-0 text-kit-xs text-kit-fg-3\">\n {lookLabel(look)}\n {v.size && v.size !== \"md\" ? ` · ${SIZE_LABEL[v.size]}` : \"\"}\n </span>\n <IconChevronRight className=\"size-4 shrink-0 text-kit-fg-3 transition-transform group-hover/bhead:translate-x-0.5\" stroke={1.5} aria-hidden />\n </button>\n );\n const linkRow =\n editingLink && !readOnly ? (\n <div>\n <LinkQuickEdit\n value={v}\n ariaLabel={`${field.title} link`}\n size=\"sm\"\n bare\n onCommit={(n) => onChange(nextButton(value, n ? linkPart(n) : { ...linkPart({ href: \"\" }), type: \"page\", href: \"\" }))}\n onDone={() => {\n setEditingLink(false);\n requestAnimationFrame(() => linkBtn.current?.focus({ preventScroll: true }));\n }}\n />\n </div>\n ) : (\n <button\n ref={linkBtn}\n type=\"button\"\n disabled={readOnly}\n onClick={() => setEditingLink(true)}\n // V2 link.tsx:1263: the name reads the link's own text (its title, else its address), not the picked target's title\n aria-label={hasLink(v) ? `${field.title} link: ${linkText(v)}. Edit link` : `Add a link to ${field.title.toLowerCase()}`}\n className={cn(\"flex w-full min-w-0 items-center px-2.5 text-left outline-none transition-colors hover:bg-kit-hover focus-visible:bg-kit-hover disabled:cursor-default disabled:hover:bg-transparent\", h)}\n >\n <LinkLine v={v} target={target} />\n </button>\n );\n // CPO D43 + D45: label + link are ONE unit — one border, a hairline between the label row and the link row\n const unit = (\n <FieldUnit data-button-unit=\"\" aria-label={field.title} className=\"overflow-hidden\">\n {head}\n {linkRow}\n </FieldUnit>\n );\n if (form) return unit;\n return (\n <Popover open={open} onOpenChange={setOpen}>\n <PopoverAnchor render={unit} />\n <PopoverContent className=\"w-[360px] p-4\" align=\"start\">\n <ButtonScreen value={value} onChange={onChange} readOnly={readOnly} title={field.title} />\n </PopoverContent>\n </Popover>\n );\n}\n\n/* ── Compact button editor for small surfaces (the canvas popover) ──\n * V2 kit/controls/link.tsx ButtonLinkEditor, ported as is: label + the link element (LinkForm, same Type · target ·\n * options as everywhere) as one unit, then the button's Style. Here beside STYLE_ITEMS, which link.tsx cannot import.\n */\nexport function ButtonLinkEditor({\n value,\n onChange,\n onSubmit,\n styles = STYLE_ITEMS,\n labelFirst = true,\n}: {\n value: LinkValue;\n onChange: (v: LinkValue) => void;\n onSubmit?: () => void;\n /** null = a plain text link (nav, footer and legal links): no style row. */\n styles?: { value: ButtonStyle; label: string }[] | null;\n labelFirst?: boolean;\n}) {\n const v = normLink(value);\n const labelId = React.useId();\n const setStyle = (s: ButtonStyle) => onChange({ ...v, style: s, variant: s });\n return (\n <div className=\"flex flex-col gap-3\">\n {labelFirst ? (\n <div className=\"flex flex-col gap-1.5\">\n <label htmlFor={labelId} className=\"text-kit-xs font-medium text-kit-fg-2\">Label</label>\n <Input id={labelId} size=\"sm\" autoFocus value={v.label ?? \"\"} onChange={(e) => onChange({ ...v, label: e.target.value })} onKeyDown={(e) => e.key === \"Enter\" && (e.preventDefault(), onSubmit?.())} placeholder=\"Shop cookware\" />\n </div>\n ) : null}\n <div className=\"flex flex-col gap-2.5\" role=\"group\" aria-label=\"Link\">\n <span className=\"text-kit-xs font-medium text-kit-fg-2\">Link</span>\n <LinkForm value={v} onChange={(n) => onChange({ ...v, ...n, label: v.label, style: v.style, variant: v.variant })} onEnter={() => onSubmit?.()} />\n </div>\n {styles ? (\n <div className=\"flex items-center justify-between gap-3 border-t border-kit-line pt-2.5\">\n <span className=\"text-kit-xs text-kit-fg-2\">Style</span>\n <Segmented size=\"sm\" aria-label=\"Button style\" value={v.style ?? \"primary\"} onChange={(s) => setStyle(s as ButtonStyle)} items={styles} />\n </div>\n ) : null}\n </div>\n );\n}\n"],"mappings":"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"}
@@ -2,7 +2,7 @@ import { ACTIONS, CONTROLS } from "../engine/kit-field.js";
2
2
  import { EmailControl, SlugControl, SlugGenerate, StringControl, TextControl, UrlControl } from "./text.js";
3
3
  import { ColorControl } from "./color.js";
4
4
  import { NumberControl, RatingControl } from "./number.js";
5
- //#region src/kit/controls/c1.ts
5
+ //#region src/controls/c1.ts
6
6
  var C1_CONTROLS = {
7
7
  string: StringControl,
8
8
  text: TextControl,
@@ -0,0 +1 @@
1
+ {"version":3,"file":"c1.js","names":[],"sources":["../../src/controls/c1.ts"],"sourcesContent":["/**\n * Lane C1 (text, slug, email, url, number, rating, color): the controls and label-row actions this lane ports, keyed by\n * kit type, for the engine's CONTROLS / ACTIONS tables. `registerC1Controls()` puts them in; a registered type stops\n * drawing the host's legacy control.\n */\nimport type { ComponentType } from \"react\";\nimport type { SchemaType } from \"../schema/types\";\nimport type { ControlProps } from \"../types\";\nimport { ACTIONS, CONTROLS } from \"../engine/kit-field\";\nimport { ColorControl } from \"./color\";\nimport { NumberControl, RatingControl } from \"./number\";\nimport { EmailControl, SlugControl, SlugGenerate, StringControl, TextControl, UrlControl } from \"./text\";\n\nexport const C1_CONTROLS: Partial<Record<SchemaType, ComponentType<ControlProps>>> = {\n string: StringControl,\n text: TextControl,\n email: EmailControl,\n url: UrlControl,\n slug: SlugControl,\n number: NumberControl,\n rating: RatingControl,\n color: ColorControl,\n};\nexport const C1_ACTIONS: Partial<Record<SchemaType, ComponentType<ControlProps>>> = { slug: SlugGenerate };\n\nexport function registerC1Controls() {\n Object.assign(CONTROLS, C1_CONTROLS);\n Object.assign(ACTIONS, C1_ACTIONS);\n}\n"],"mappings":";;;;;AAaA,IAAa,cAAwE;CACnF,QAAQ;CACR,MAAM;CACN,OAAO;CACP,KAAK;CACL,MAAM;CACN,QAAQ;CACR,QAAQ;CACR,OAAO;AACT;AACA,IAAa,aAAuE,EAAE,MAAM,aAAa;AAEzG,SAAgB,qBAAqB;CACnC,OAAO,OAAO,UAAU,WAAW;CACnC,OAAO,OAAO,SAAS,UAAU;AACnC"}
@@ -2,7 +2,7 @@ import { CONTROLS } from "../engine/kit-field.js";
2
2
  import { NUMBER_SCALE } from "./number.js";
3
3
  import { BooleanControl, MultiSelectControl, SelectControl, TagsControl } from "./choice.js";
4
4
  import { ScaleControl } from "./scale.js";
5
- //#region src/kit/controls/c2.ts
5
+ //#region src/controls/c2.ts
6
6
  var C2_CONTROLS = {
7
7
  boolean: BooleanControl,
8
8
  select: SelectControl,
@@ -0,0 +1 @@
1
+ {"version":3,"file":"c2.js","names":[],"sources":["../../src/controls/c2.ts"],"sourcesContent":["/**\n * Lane C2 (boolean, select, multiselect, tags, and the scale capsule for a number with a scale): the controls this lane\n * ports, keyed by kit type, for the engine's CONTROLS table. `registerC2Controls()` puts them in and hands the scale\n * control to the number control (lane C1's NUMBER_SCALE hook); a registered type stops drawing the host's legacy control.\n */\nimport type { ComponentType } from \"react\";\nimport type { SchemaType } from \"../schema/types\";\nimport type { ControlProps } from \"../types\";\nimport { CONTROLS } from \"../engine/kit-field\";\nimport { BooleanControl, MultiSelectControl, SelectControl, TagsControl } from \"./choice\";\nimport { NUMBER_SCALE } from \"./number\";\nimport { ScaleControl } from \"./scale\";\n\nexport const C2_CONTROLS: Partial<Record<SchemaType, ComponentType<ControlProps>>> = {\n boolean: BooleanControl,\n select: SelectControl,\n multiselect: MultiSelectControl,\n tags: TagsControl,\n};\n\nexport function registerC2Controls() {\n Object.assign(CONTROLS, C2_CONTROLS);\n NUMBER_SCALE.control = ScaleControl;\n}\n"],"mappings":";;;;;AAaA,IAAa,cAAwE;CACnF,SAAS;CACT,QAAQ;CACR,aAAa;CACb,MAAM;AACR;AAEA,SAAgB,qBAAqB;CACnC,OAAO,OAAO,UAAU,WAAW;CACnC,aAAa,UAAU;AACzB"}
@@ -31,8 +31,13 @@ export declare function optionIcons(options: Option[], className?: string, Glyph
31
31
  export declare function useOwnDescription(ref: React.RefObject<HTMLElement | null>, ownId: string | null): void;
32
32
  /** Boolean switch (used inside the switch card the shell draws). Commits immediately. */
33
33
  export declare function BooleanControl({ field, value, onChange, readOnly, id }: ControlProps): import("react/jsx-runtime").JSX.Element;
34
- export declare function SelectControl({ field, value, onChange, readOnly, id }: ControlProps): import("react/jsx-runtime").JSX.Element;
35
- export declare function MultiSelectControl({ field, value, onChange, readOnly, id }: ControlProps): import("react/jsx-runtime").JSX.Element;
34
+ /**
35
+ * A stored value none of the options names any more (renamed or removed) is kept and flagged under the control, with
36
+ * change-to and remove (H4). @see UnknownValueNote
37
+ */
38
+ export declare function SelectControl(props: ControlProps): import("react/jsx-runtime").JSX.Element;
39
+ /** As `SelectControl`: each stored choice no option names any more is kept and flagged, with change-to and remove. */
40
+ export declare function MultiSelectControl(props: ControlProps): import("react/jsx-runtime").JSX.Element;
36
41
  /** Why a typed tag is not added, or null when it is (the backend's own checks, said in words). */
37
42
  export declare function tagRefusal(tag: string, list: string[]): string | null;
38
43
  /** Chip input. Says so at its limit, and says why a tag was not added, instead of silently dropping it. */
@@ -1,16 +1,18 @@
1
+ import "../adapters/prod-types.js";
2
+ import { dockIconOf } from "../adapters/icons.js";
1
3
  import { cn } from "../lib/cn.js";
2
- import { KitIcon, iconKey } from "../lib/icons.js";
3
4
  import { useKitEnv, useKitServices } from "../context.js";
5
+ import { KitIcon, iconKey } from "../lib/icons.js";
4
6
  import { shortcutHintsOn } from "../ui/shortcut-hint.js";
5
7
  import { Checkbox, Segmented, Switch } from "../ui/controls.js";
6
8
  import { Popover, PopoverContent, PopoverTrigger } from "../ui/overlay.js";
7
9
  import { Select } from "../ui/select.js";
8
10
  import { fitsSegmented } from "../ui/choice-switch.js";
9
- import { dockIconOf } from "../adapters/icons.js";
11
+ import { UnknownValueNote } from "./unknown-value.js";
10
12
  import * as React from "react";
11
- import { IconCheck, IconPlus, IconX } from "@tabler/icons-react";
12
13
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
13
- //#region src/kit/controls/choice.tsx
14
+ import { IconCheck, IconPlus, IconX } from "@tabler/icons-react";
15
+ //#region src/controls/choice.tsx
14
16
  /**
15
17
  * CHOICE — boolean · select · multiselect · tags (V2 HEAD 9829bf1 kit/controls/choice.tsx, DESIGN 8.10–8.12).
16
18
  * Rule (production): few options → segmented, many → dropdown, many values → checkboxes, on/off → switch card.
@@ -101,7 +103,9 @@ function BooleanControl({ field, value, onChange, readOnly, id }) {
101
103
  checked: Boolean(value),
102
104
  disabled: readOnly,
103
105
  onCheckedChange: (c) => onChange(c === true),
104
- "aria-label": field.title
106
+ "aria-label": field.title,
107
+ nativeButton: true,
108
+ render: /* @__PURE__ */ jsx("button", { type: "button" })
105
109
  });
106
110
  return /* @__PURE__ */ jsx(Switch, {
107
111
  id,
@@ -113,7 +117,32 @@ function BooleanControl({ field, value, onChange, readOnly, id }) {
113
117
  render: /* @__PURE__ */ jsx("button", { type: "button" })
114
118
  });
115
119
  }
116
- function SelectControl({ field, value, onChange, readOnly, id }) {
120
+ /**
121
+ * A stored value none of the options names any more (renamed or removed) is kept and flagged under the control, with
122
+ * change-to and remove (H4). @see UnknownValueNote
123
+ */
124
+ function SelectControl(props) {
125
+ const options = opts(props.field.options);
126
+ const v = str(props.value);
127
+ if (v === "" || options.length === 0 || options.some((o) => o.value === v)) return /* @__PURE__ */ jsx(SelectInput, { ...props });
128
+ return /* @__PURE__ */ jsxs("div", {
129
+ className: "flex min-w-0 flex-col gap-1.5",
130
+ children: [/* @__PURE__ */ jsx(SelectInput, { ...props }), /* @__PURE__ */ jsx(UnknownValueNote, {
131
+ items: [{
132
+ key: v,
133
+ label: `“${v}”`,
134
+ options: options.map((o) => ({
135
+ value: o.value,
136
+ label: o.label
137
+ }))
138
+ }],
139
+ onRemap: (_, to) => props.onChange(to),
140
+ onRemove: () => props.onChange(null),
141
+ readOnly: props.readOnly
142
+ })]
143
+ });
144
+ }
145
+ function SelectInput({ field, value, onChange, readOnly, id }) {
117
146
  const { variant } = useKitEnv();
118
147
  const { IconGlyph } = useKitServices();
119
148
  const options = opts(field.options);
@@ -170,7 +199,8 @@ function SelectControl({ field, value, onChange, readOnly, id }) {
170
199
  }, o.value))
171
200
  });
172
201
  if (layout === "cards" || layout === "grid") {
173
- const icons = optionIcons(options, "size-4", IconGlyph);
202
+ const iconsOn = optionIcons(options, "size-4 text-kit-fg", IconGlyph);
203
+ const iconsOff = optionIcons(options, "size-4 text-kit-fg-3", IconGlyph);
174
204
  return /* @__PURE__ */ jsx("div", {
175
205
  role: "radiogroup",
176
206
  id,
@@ -187,12 +217,9 @@ function SelectControl({ field, value, onChange, readOnly, id }) {
187
217
  disabled: readOnly,
188
218
  onClick: () => pick(o.value),
189
219
  onKeyDown: (e) => keys.onKeyDown(e, i),
190
- className: cn("relative flex flex-col items-start gap-1.5 rounded-kit-lg border p-2.5 text-left transition-[border-color,box-shadow] duration-150 focus-visible:outline-offset-[-2px]", on ? "border-[var(--kit-emphasis-line)] bg-kit-control-bg shadow-kit-xs" : "border-kit-line hover:border-kit-line-strong"),
220
+ className: cn("relative flex flex-col items-start gap-1.5 rounded-kit-lg border p-2.5 text-left transition-[border-color,box-shadow] duration-150", on ? "border-[var(--kit-emphasis-line)] bg-kit-control-bg shadow-kit-xs" : "border-kit-line hover:border-kit-line-strong"),
191
221
  children: [
192
- icons[i] ? /* @__PURE__ */ jsx("span", {
193
- className: cn("[&_svg]:size-4", on ? "text-kit-fg" : "text-kit-fg-3"),
194
- children: icons[i]
195
- }) : null,
222
+ (on ? iconsOn : iconsOff)[i] ?? null,
196
223
  /* @__PURE__ */ jsx("span", {
197
224
  className: "text-kit-sm font-medium text-kit-fg",
198
225
  children: o.label
@@ -228,7 +255,30 @@ function SelectControl({ field, value, onChange, readOnly, id }) {
228
255
  }))
229
256
  });
230
257
  }
231
- function MultiSelectControl({ field, value, onChange, readOnly, id }) {
258
+ /** As `SelectControl`: each stored choice no option names any more is kept and flagged, with change-to and remove. */
259
+ function MultiSelectControl(props) {
260
+ const list = Array.isArray(props.value) ? props.value.filter((x) => typeof x === "string") : [];
261
+ const options = opts(props.field.options);
262
+ const unknown = options.length ? list.filter((x) => !options.some((o) => o.value === x)) : [];
263
+ if (unknown.length === 0) return /* @__PURE__ */ jsx(MultiSelectInput, { ...props });
264
+ return /* @__PURE__ */ jsxs("div", {
265
+ className: "flex min-w-0 flex-col gap-1.5",
266
+ children: [/* @__PURE__ */ jsx(MultiSelectInput, { ...props }), /* @__PURE__ */ jsx(UnknownValueNote, {
267
+ items: unknown.map((x) => ({
268
+ key: x,
269
+ label: `“${x}”`,
270
+ options: options.filter((o) => !list.includes(o.value)).map((o) => ({
271
+ value: o.value,
272
+ label: o.label
273
+ }))
274
+ })),
275
+ onRemap: (from, to) => props.onChange(list.map((x) => x === from ? to : x)),
276
+ onRemove: (from) => props.onChange(list.filter((x) => x !== from)),
277
+ readOnly: props.readOnly
278
+ })]
279
+ });
280
+ }
281
+ function MultiSelectInput({ field, value, onChange, readOnly, id }) {
232
282
  const list = Array.isArray(value) ? value.filter((x) => typeof x === "string") : [];
233
283
  const options = opts(field.options);
234
284
  const max = field.validation?.max;
@@ -251,11 +301,13 @@ function MultiSelectControl({ field, value, onChange, readOnly, id }) {
251
301
  children: options.map((o) => {
252
302
  const on = list.includes(o.value);
253
303
  return /* @__PURE__ */ jsxs("label", {
254
- className: cn("flex items-center gap-2.5 rounded-kit-md px-1.5 py-1.5", !on && full ? "cursor-not-allowed" : "cursor-pointer hover:bg-kit-hover"),
304
+ className: cn("flex cursor-pointer items-center gap-2.5 rounded-kit-md px-1.5 py-1.5 hover:bg-kit-hover", !on && full && "cursor-not-allowed hover:bg-transparent"),
255
305
  children: [/* @__PURE__ */ jsx(Checkbox, {
256
306
  checked: on,
257
307
  disabled: readOnly || !on && full,
258
- onCheckedChange: () => toggle(o.value)
308
+ onCheckedChange: () => toggle(o.value),
309
+ nativeButton: true,
310
+ render: /* @__PURE__ */ jsx("button", { type: "button" })
259
311
  }), /* @__PURE__ */ jsx("span", {
260
312
  className: "text-kit-sm text-kit-fg",
261
313
  children: o.label
@@ -296,13 +348,14 @@ function MultiSelectControl({ field, value, onChange, readOnly, id }) {
296
348
  "aria-label": field.title,
297
349
  children: options.map((o) => {
298
350
  const on = list.includes(o.value);
351
+ const blocked = !on && full;
299
352
  return /* @__PURE__ */ jsxs("button", {
300
353
  type: "button",
301
354
  role: "checkbox",
302
355
  "aria-checked": on,
303
- disabled: !on && full,
356
+ disabled: blocked,
304
357
  onClick: () => toggle(o.value),
305
- className: "flex h-8 w-full items-center gap-2 rounded-kit-md px-2 text-left text-kit-sm hover:bg-kit-hover disabled:opacity-40 disabled:hover:bg-transparent",
358
+ className: cn("flex h-8 w-full items-center gap-2 rounded-kit-md px-2 text-left text-kit-sm hover:bg-kit-hover", blocked && "opacity-40 hover:bg-transparent"),
306
359
  children: [/* @__PURE__ */ jsx("span", {
307
360
  className: cn("flex size-4 items-center justify-center rounded-kit-md border", on ? "border-kit-accent bg-kit-accent text-kit-accent-on" : "border-kit-line-strong"),
308
361
  children: on ? /* @__PURE__ */ jsx(IconCheck, {
@@ -405,6 +458,6 @@ function TagsControl({ field, value, onChange, readOnly, id, onBlur }) {
405
458
  });
406
459
  }
407
460
  //#endregion
408
- export { BooleanControl, MultiSelectControl, SelectControl, TagsControl };
461
+ export { BooleanControl, MultiSelectControl, SelectControl, TagsControl, optionIcons, tagRefusal, useOwnDescription };
409
462
 
410
463
  //# sourceMappingURL=choice.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"choice.js","names":[],"sources":["../../src/controls/choice.tsx"],"sourcesContent":["/**\n * CHOICE — boolean · select · multiselect · tags (V2 HEAD 9829bf1 kit/controls/choice.tsx, DESIGN 8.10–8.12).\n * Rule (production): few options → segmented, many → dropdown, many values → checkboxes, on/off → switch card.\n * D46: `layout: \"segmented\"` is a request, not a promise. With 4+ options, or labels that would wrap or truncate\n * in a 340px inspector (`fitsSegmented`), it renders the dropdown instead, so every schema follows the rule.\n *\n * Values are the ones production stores, untouched by any adapter (schema.ts plans them AS_IS): boolean, the option's\n * string, a string[] of option values, a string[] of tags. Tags are written the way the backend judges them\n * (tagsValueProblem: trimmed, case-insensitively unique, at most TAG_VALUE_MAX_LENGTH characters), and a tag the\n * control will not add says why under the box instead of vanishing.\n *\n * Option icons are all or none per list (the schema adapter's rule): a list draws icons only when every option names an\n * icon that can be drawn, so labels stay aligned and no option gets a stand-in glyph. The host's glyphs come first\n * (KitServices.IconGlyph, the BetterCMS set the site renders: every stored option icon is one of its names); with no\n * host renderer, the kit's own drawn icons.\n */\nimport * as React from \"react\";\nimport { IconCheck, IconPlus, IconX } from \"@tabler/icons-react\";\nimport { Checkbox, Segmented, Switch } from \"../ui/controls\";\nimport { Popover, PopoverContent, PopoverTrigger } from \"../ui/overlay\";\nimport { Select } from \"../ui/select\";\nimport { fitsSegmented } from \"../ui/choice-switch\";\nimport { shortcutHintsOn } from \"../ui/shortcut-hint\";\nimport { cn } from \"../lib/cn\";\nimport { KitIcon, iconKey } from \"../lib/icons\";\nimport type { Option } from \"../schema/types\";\nimport { useKitEnv, useKitServices, type KitServices } from \"../context\";\nimport { dockIconOf } from \"../adapters/icons\";\nimport type { ControlProps } from \"../types\";\nimport { TAG_VALUE_MAX_LENGTH } from \"../adapters/prod-types\";\nimport { UnknownValueNote } from \"./unknown-value\";\n\nconst str = (v: unknown) => (typeof v === \"string\" ? v : v == null ? \"\" : String(v));\nconst opts = (o?: Option[]) => o ?? [];\n\n/**\n * Icons for a list: every option's icon when all of them resolve, otherwise none (never a fallback glyph). `Glyph` is\n * the host's renderer (KitServices.IconGlyph): it draws every BetterCMS icon name (the option's kit name read back\n * through dockIconOf); without it, or when a name is not in that set, the kit's own drawn icons.\n */\nexport function optionIcons(options: Option[], className?: string, Glyph?: KitServices[\"IconGlyph\"]): (React.ReactNode | undefined)[] {\n if (options.length === 0) return [];\n const dock = options.map((o) => dockIconOf(o.icon));\n // a block box, as the kit's own <svg> is under preflight: an inline glyph would sit on a line box and grow the row\n if (Glyph && dock.every((n) => n !== undefined)) return dock.map((n) => <Glyph name={n!} className={cn(\"flex\", className)} />);\n const all = options.every((o) => iconKey(o.icon) !== undefined);\n return options.map((o) => (all ? <KitIcon name={o.icon} className={className} /> : undefined));\n}\n\n/** The limit sentence (DESIGN 8.12), shared by multiselect and tags. */\nfunction LimitLine({ max }: { max: number }) {\n return <span className=\"px-0.5 text-kit-xs text-kit-fg-3\">That's the limit of {max}. Remove one to add another.</span>;\n}\n\n/**\n * Roving focus for a radiogroup of buttons (WAI-ARIA radio group, as Segmented does): Tab lands on the selected option\n * (or the first), arrows move and select, Home / End jump.\n */\nfunction useRadioKeys(values: string[], current: string, onPick: (v: string) => void, readOnly?: boolean) {\n const focusable = values.includes(current) ? current : values[0];\n const onKeyDown = (e: React.KeyboardEvent, i: number) => {\n if (readOnly || !values.length) return;\n const n = values.length;\n const next =\n e.key === \"ArrowRight\" || e.key === \"ArrowDown\"\n ? (i + 1) % n\n : e.key === \"ArrowLeft\" || e.key === \"ArrowUp\"\n ? (i - 1 + n) % n\n : e.key === \"Home\"\n ? 0\n : e.key === \"End\"\n ? n - 1\n : -1;\n if (next < 0) return;\n e.preventDefault();\n onPick(values[next]);\n const group = (e.currentTarget as HTMLElement).closest(\"[role=radiogroup]\");\n group?.querySelector<HTMLElement>(`[data-choice-value=\"${CSS.escape(values[next])}\"]`)?.focus();\n };\n return { tabIndexOf: (v: string) => (v === focusable ? 0 : -1), onKeyDown };\n}\n\n/**\n * Adds or removes one id of the control's own in aria-describedby, leaving the ids FieldShell wires (help, issue)\n * in place (as ScaleSlider does).\n */\nexport function useOwnDescription(ref: React.RefObject<HTMLElement | null>, ownId: string | null) {\n const last = React.useRef<string | null>(null);\n React.useEffect(() => {\n const el = ref.current;\n if (!el) return;\n const ids = (el.getAttribute(\"aria-describedby\") ?? \"\").split(\" \").filter((t) => t && t !== last.current && t !== ownId);\n if (ownId) ids.push(ownId);\n if (ids.length) el.setAttribute(\"aria-describedby\", ids.join(\" \"));\n else el.removeAttribute(\"aria-describedby\");\n last.current = ownId;\n });\n}\n\n/** Boolean switch (used inside the switch card the shell draws). Commits immediately. */\nexport function BooleanControl({ field, value, onChange, readOnly, id }: ControlProps) {\n if (field.layout === \"checkbox\")\n return <Checkbox id={id} checked={Boolean(value)} disabled={readOnly} onCheckedChange={(c) => onChange(c === true)} aria-label={field.title} nativeButton render={<button type=\"button\" />} />;\n /* V2's switch is a native <button role=\"switch\"> (Radix); Base UI draws a <span> unless asked for the button */\n return <Switch id={id} checked={Boolean(value)} disabled={readOnly} onCheckedChange={(c) => onChange(c)} aria-label={field.title} nativeButton render={<button type=\"button\" />} />;\n}\n\n/**\n * A stored value none of the options names any more (renamed or removed) is kept and flagged under the control, with\n * change-to and remove (H4). @see UnknownValueNote\n */\nexport function SelectControl(props: ControlProps) {\n const options = opts(props.field.options);\n const v = str(props.value);\n if (v === \"\" || options.length === 0 || options.some((o) => o.value === v)) return <SelectInput {...props} />;\n return (\n <div className=\"flex min-w-0 flex-col gap-1.5\">\n <SelectInput {...props} />\n <UnknownValueNote\n items={[{ key: v, label: `“${v}”`, options: options.map((o) => ({ value: o.value, label: o.label })) }]}\n onRemap={(_, to) => props.onChange(to)}\n onRemove={() => props.onChange(null)}\n readOnly={props.readOnly}\n />\n </div>\n );\n}\n\nfunction SelectInput({ field, value, onChange, readOnly, id }: ControlProps) {\n const { variant } = useKitEnv();\n const { IconGlyph } = useKitServices();\n const options = opts(field.options);\n const v = str(value);\n const fits = fitsSegmented(options.map((o) => o.label));\n const layout = field.layout ?? (fits ? \"segmented\" : \"dropdown\");\n const pick = (n: string) => {\n if (!readOnly && n !== v) onChange(n);\n };\n const keys = useRadioKeys(\n options.map((o) => o.value),\n v,\n pick,\n readOnly,\n );\n\n if (layout === \"segmented\" && fits) {\n const icons = optionIcons(options, \"size-3.5\", IconGlyph);\n return (\n <Segmented\n aria-label={field.title}\n value={v}\n onChange={pick}\n items={options.map((o, i) => ({ value: o.value, label: o.label, icon: icons[i], disabled: readOnly }))}\n className=\"w-full [&>button]:min-w-0 [&>button]:flex-1\"\n />\n );\n }\n if (layout === \"radio\")\n return (\n <div role=\"radiogroup\" id={id} aria-label={field.title} className=\"flex flex-col gap-0.5\">\n {options.map((o, i) => (\n <button\n key={o.value}\n type=\"button\"\n role=\"radio\"\n data-choice-value={o.value}\n aria-checked={o.value === v}\n tabIndex={keys.tabIndexOf(o.value)}\n disabled={readOnly}\n onClick={() => pick(o.value)}\n onKeyDown={(e) => keys.onKeyDown(e, i)}\n className=\"flex items-start gap-2.5 rounded-kit-md px-1.5 py-1.5 text-left hover:bg-kit-hover\"\n >\n <span className={cn(\"mt-0.5 flex size-4 shrink-0 items-center justify-center rounded-full border transition-colors\", o.value === v ? \"border-kit-accent\" : \"border-kit-line-strong\")}>\n {o.value === v ? <span className=\"size-2 rounded-full bg-kit-accent\" /> : null}\n </span>\n <span className=\"min-w-0\">\n <span className=\"block text-kit-sm text-kit-fg\">{o.label}</span>\n {o.description ? <span className=\"block text-kit-xs text-kit-fg-3\">{o.description}</span> : null}\n </span>\n </button>\n ))}\n </div>\n );\n if (layout === \"cards\" || layout === \"grid\") {\n /* V2 draws the icon itself as the button's first child (no wrapper), coloured by the selected state */\n const iconsOn = optionIcons(options, \"size-4 text-kit-fg\", IconGlyph);\n const iconsOff = optionIcons(options, \"size-4 text-kit-fg-3\", IconGlyph);\n return (\n <div role=\"radiogroup\" id={id} aria-label={field.title} className={cn(\"grid gap-1.5\", variant === \"document\" ? \"grid-cols-3\" : \"grid-cols-2\")}>\n {options.map((o, i) => {\n const on = o.value === v;\n return (\n <button\n key={o.value}\n type=\"button\"\n role=\"radio\"\n data-choice-value={o.value}\n aria-checked={on}\n tabIndex={keys.tabIndexOf(o.value)}\n disabled={readOnly}\n onClick={() => pick(o.value)}\n onKeyDown={(e) => keys.onKeyDown(e, i)}\n className={cn(\n \"relative flex flex-col items-start gap-1.5 rounded-kit-lg border p-2.5 text-left transition-[border-color,box-shadow] duration-150\",\n on ? \"border-[var(--kit-emphasis-line)] bg-kit-control-bg shadow-kit-xs\" : \"border-kit-line hover:border-kit-line-strong\",\n )}\n >\n {(on ? iconsOn : iconsOff)[i] ?? null}\n <span className=\"text-kit-sm font-medium text-kit-fg\">{o.label}</span>\n {o.description ? <span className=\"text-kit-xs leading-4 text-kit-fg-3\">{o.description}</span> : null}\n {on ? <IconCheck aria-hidden className=\"absolute right-2 top-2 size-3.5 text-kit-fg\" stroke={2} /> : null}\n </button>\n );\n })}\n </div>\n );\n }\n const icons = optionIcons(options, undefined, IconGlyph);\n return (\n <Select\n id={id}\n aria-label={field.title}\n size={variant === \"document\" ? \"lg\" : \"md\"}\n value={v || undefined}\n disabled={readOnly}\n onValueChange={pick}\n placeholder={field.placeholder ?? \"Select…\"}\n options={options.map((o, i) => ({ value: o.value, label: o.label, description: o.description, icon: icons[i] }))}\n />\n );\n}\n\n/** As `SelectControl`: each stored choice no option names any more is kept and flagged, with change-to and remove. */\nexport function MultiSelectControl(props: ControlProps) {\n const list = Array.isArray(props.value) ? (props.value as unknown[]).filter((x): x is string => typeof x === \"string\") : [];\n const options = opts(props.field.options);\n const unknown = options.length ? list.filter((x) => !options.some((o) => o.value === x)) : [];\n if (unknown.length === 0) return <MultiSelectInput {...props} />;\n return (\n <div className=\"flex min-w-0 flex-col gap-1.5\">\n <MultiSelectInput {...props} />\n <UnknownValueNote\n items={unknown.map((x) => ({ key: x, label: `“${x}”`, options: options.filter((o) => !list.includes(o.value)).map((o) => ({ value: o.value, label: o.label })) }))}\n onRemap={(from, to) => props.onChange(list.map((x) => (x === from ? to : x)))}\n onRemove={(from) => props.onChange(list.filter((x) => x !== from))}\n readOnly={props.readOnly}\n />\n </div>\n );\n}\n\nfunction MultiSelectInput({ field, value, onChange, readOnly, id }: ControlProps) {\n const list = Array.isArray(value) ? (value as unknown[]).filter((x): x is string => typeof x === \"string\") : [];\n const options = opts(field.options);\n const max = field.validation?.max;\n const full = max != null && list.length >= max;\n const toggle = (o: string) => {\n if (readOnly) return;\n if (list.includes(o)) onChange(list.filter((x) => x !== o));\n else if (!full) onChange([...list, o]);\n };\n const label = (val: string) => options.find((o) => o.value === val)?.label ?? val;\n /* V2 draws the control bare; the limit line (ours: say why the next pick is refused) wraps it only while it shows */\n const withLimit = (body: React.ReactElement) =>\n full && !readOnly ? (\n <div className=\"flex flex-col gap-1\">\n {body}\n <LimitLine max={max!} />\n </div>\n ) : (\n body\n );\n if (field.layout === \"checkbox\" || field.layout === \"list\")\n return withLimit(\n <>\n <div id={id} role=\"group\" aria-label={field.title} className=\"flex flex-col gap-0.5\">\n {options.map((o) => {\n const on = list.includes(o.value);\n return (\n <label key={o.value} className={cn(\"flex cursor-pointer items-center gap-2.5 rounded-kit-md px-1.5 py-1.5 hover:bg-kit-hover\", !on && full && \"cursor-not-allowed hover:bg-transparent\")}>\n <Checkbox checked={on} disabled={readOnly || (!on && full)} onCheckedChange={() => toggle(o.value)} nativeButton render={<button type=\"button\" />} />\n <span className=\"text-kit-sm text-kit-fg\">{o.label}</span>\n </label>\n );\n })}\n </div>\n </>,\n );\n return withLimit(\n <>\n <Popover>\n {/* read-only there is no trigger to carry the field id, so the chip row is the named group */}\n <div\n id={readOnly ? id : undefined}\n role={readOnly ? \"group\" : undefined}\n aria-label={readOnly ? field.title : undefined}\n className=\"flex min-h-8 flex-wrap items-center gap-1 rounded-kit-md border border-kit-line-strong bg-kit-field-bg p-1 transition-colors hover:border-kit-line-strong\"\n >\n {list.map((o) => (\n <span key={o} className=\"inline-flex h-6 items-center gap-1 rounded-kit-md border border-kit-line bg-kit-control-bg pl-2 pr-1 text-kit-sm text-kit-fg shadow-kit-xs\">\n {label(o)}\n {readOnly ? null : (\n <button type=\"button\" aria-label={`Remove ${label(o)}`} onClick={() => toggle(o)} className=\"flex rounded-kit-md p-0.5 text-kit-fg-3 hover:bg-kit-hover hover:text-kit-fg\">\n <IconX className=\"size-3\" stroke={1.5} />\n </button>\n )}\n </span>\n ))}\n {readOnly ? null : (\n <PopoverTrigger id={id} className=\"inline-flex h-6 items-center gap-1 rounded-kit-md px-1.5 text-kit-sm text-kit-fg-3 hover:bg-kit-hover hover:text-kit-fg\">\n <IconPlus aria-hidden className=\"size-3.5\" stroke={1.5} />\n {list.length ? \"Add\" : field.placeholder ?? \"Choose…\"}\n </PopoverTrigger>\n )}\n </div>\n <PopoverContent className=\"w-60 p-1\">\n <div role=\"group\" aria-label={field.title}>\n {options.map((o) => {\n const on = list.includes(o.value);\n const blocked = !on && full;\n return (\n <button\n key={o.value}\n type=\"button\"\n role=\"checkbox\"\n aria-checked={on}\n disabled={blocked}\n onClick={() => toggle(o.value)}\n className={cn(\"flex h-8 w-full items-center gap-2 rounded-kit-md px-2 text-left text-kit-sm hover:bg-kit-hover\", blocked && \"opacity-40 hover:bg-transparent\")}\n >\n <span className={cn(\"flex size-4 items-center justify-center rounded-kit-md border\", on ? \"border-kit-accent bg-kit-accent text-kit-accent-on\" : \"border-kit-line-strong\")}>\n {on ? <IconCheck aria-hidden className=\"size-3\" stroke={3} /> : null}\n </span>\n {o.label}\n </button>\n );\n })}\n </div>\n {full ? <div className=\"px-2 pb-1 pt-1.5\"><LimitLine max={max!} /></div> : null}\n </PopoverContent>\n </Popover>\n </>,\n );\n}\n\n/** Why a typed tag is not added, or null when it is (the backend's own checks, said in words). */\nexport function tagRefusal(tag: string, list: string[]): string | null {\n if (Array.from(tag).length > TAG_VALUE_MAX_LENGTH) return `A tag can be up to ${TAG_VALUE_MAX_LENGTH} characters.`;\n const folded = tag.toLowerCase();\n const twin = list.find((t) => t.trim().toLowerCase() === folded);\n if (twin !== undefined) return `\"${twin}\" is already a tag.`;\n return null;\n}\n\n/** Chip input. Says so at its limit, and says why a tag was not added, instead of silently dropping it. */\nexport function TagsControl({ field, value, onChange, readOnly, id, onBlur }: ControlProps) {\n const list = Array.isArray(value) ? (value as unknown[]).map((x) => str(x)) : [];\n const [draft, setDraft] = React.useState(\"\");\n const [refusal, setRefusal] = React.useState<string | null>(null);\n const reasonId = React.useId();\n const inputRef = React.useRef<HTMLInputElement>(null);\n useOwnDescription(inputRef, refusal ? reasonId : null);\n const max = field.validation?.max;\n const full = max != null && list.length >= max;\n const add = () => {\n const t = draft.trim().replace(/,$/, \"\").trim();\n if (!t || full) {\n setDraft(\"\");\n setRefusal(null);\n return;\n }\n const why = tagRefusal(t, list);\n if (why) {\n // keep the text so it can be fixed; the reason reads under the box\n setRefusal(why);\n return;\n }\n onChange([...list, t]);\n setDraft(\"\");\n setRefusal(null);\n };\n return (\n <div className=\"flex flex-col gap-1\">\n <div className=\"flex min-h-8 flex-wrap items-center gap-1 rounded-kit-md border border-kit-line-strong bg-kit-field-bg p-1 transition-colors focus-within:border-kit-line-strong focus-within:bg-kit-field-bg hover:border-kit-line-strong\">\n {list.map((t, i) => (\n <span key={`${t}-${i}`} className=\"inline-flex h-6 items-center gap-1 rounded-kit-md bg-kit-selected pl-2 pr-1 text-kit-sm text-kit-fg\">\n {t}\n {readOnly ? null : (\n <button type=\"button\" aria-label={`Remove ${t}`} onClick={() => onChange(list.filter((_, j) => j !== i))} className=\"flex rounded-kit-md p-0.5 text-kit-fg-3 hover:bg-kit-hover hover:text-kit-fg\">\n <IconX className=\"size-3\" stroke={1.5} />\n </button>\n )}\n </span>\n ))}\n {readOnly ? null : (\n <input\n ref={inputRef}\n id={id}\n value={draft}\n disabled={full}\n onChange={(e) => {\n setDraft(e.target.value);\n if (refusal) setRefusal(null);\n }}\n onBlur={() => {\n add();\n onBlur?.();\n }}\n onKeyDown={(e) => {\n if (e.key === \"Enter\" || e.key === \",\") {\n e.preventDefault();\n add();\n } else if (e.key === \"Backspace\" && !draft && list.length) onChange(list.slice(0, -1));\n }}\n placeholder={full ? \"\" : list.length ? \"Add…\" : field.placeholder ?? (shortcutHintsOn() ? \"Type and press Enter\" : \"Add…\")}\n className=\"h-6 min-w-20 flex-1 bg-transparent px-1.5 text-kit-sm text-kit-fg outline-none placeholder:text-kit-fg-3\"\n />\n )}\n </div>\n {refusal && !readOnly ? (\n <span id={reasonId} role=\"status\" aria-live=\"polite\" className=\"px-0.5 text-kit-xs text-kit-fg-3\">\n {refusal}\n </span>\n ) : null}\n {full && !readOnly ? <LimitLine max={max!} /> : null}\n </div>\n );\n}\n"],"mappings":"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"}
@@ -1,6 +1,6 @@
1
1
  import { CodeControl } from "./code.js";
2
2
  import { CONTROLS } from "../engine/kit-field.js";
3
- //#region src/kit/controls/code-register.ts
3
+ //#region src/controls/code-register.ts
4
4
  /** Lane C3: the code field in the engine's dispatch table (one line per type; merge with other lanes by line). */
5
5
  CONTROLS.code = CodeControl;
6
6
  //#endregion
@@ -0,0 +1 @@
1
+ {"version":3,"file":"code-register.js","names":[],"sources":["../../src/controls/code-register.ts"],"sourcesContent":["/** Lane C3: the code field in the engine's dispatch table (one line per type; merge with other lanes by line). */\nimport { CONTROLS } from \"../engine/kit-field\";\nimport { CodeControl } from \"./code\";\n\nCONTROLS.code = CodeControl;\n"],"mappings":";;;;AAIA,SAAS,OAAO"}
@@ -1,14 +1,14 @@
1
- import { cn } from "../lib/cn.js";
2
- import { isObj } from "../lib/path.js";
3
1
  import { CODE_MAX_LENGTH } from "../adapters/prod-types.js";
2
+ import { cn } from "../lib/cn.js";
4
3
  import { useKitEnv, useKitServices } from "../context.js";
4
+ import { isObj } from "../lib/path.js";
5
5
  import { Button } from "../ui/button.js";
6
6
  import { Modal, ModalBody, ModalContent, ModalFooter, ModalHeader } from "../ui/overlay.js";
7
7
  import { Select } from "../ui/select.js";
8
8
  import * as React from "react";
9
- import { IconAlertTriangle, IconBraces, IconCode, IconMaximize } from "@tabler/icons-react";
10
9
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
11
- //#region src/kit/controls/code.tsx
10
+ import { IconAlertTriangle, IconBraces, IconCode, IconMaximize } from "@tabler/icons-react";
11
+ //#region src/controls/code.tsx
12
12
  /**
13
13
  * CODE — the code field (DESIGN 8.21), V2 controls/misc.tsx (CodeSurface, CodeControl) fitted to what prod stores.
14
14
  *
@@ -103,7 +103,7 @@ function CodeSurface({ kind, value, onChange, language, onLanguage, languages, r
103
103
  toast?.success("Copied");
104
104
  };
105
105
  return /* @__PURE__ */ jsxs("div", {
106
- className: cn("overflow-hidden rounded-kit-lg border bg-kit-subtle transition-colors", invalid || problem ? "border-[var(--kit-field-invalid)]" : "border-kit-line focus-within:border-kit-field-border-focus"),
106
+ className: cn("overflow-hidden rounded-kit-lg border bg-kit-subtle", invalid || problem ? "border-[var(--kit-field-invalid)]" : "border-kit-line"),
107
107
  children: [
108
108
  /* @__PURE__ */ jsxs("div", {
109
109
  className: "flex h-8 items-center justify-between border-b border-kit-line px-2",
@@ -126,7 +126,7 @@ function CodeSurface({ kind, value, onChange, language, onLanguage, languages, r
126
126
  children: [kind === "json" ? /* @__PURE__ */ jsx("button", {
127
127
  type: "button",
128
128
  disabled: readOnly,
129
- className: "rounded-kit-md px-1.5 py-0.5 text-kit-xs text-kit-fg-2 hover:bg-kit-hover hover:text-kit-fg disabled:opacity-50",
129
+ className: "rounded-kit-md px-1.5 py-0.5 text-kit-xs text-kit-fg-2 hover:bg-kit-hover hover:text-kit-fg",
130
130
  onClick: format,
131
131
  children: "Format"
132
132
  }) : null, /* @__PURE__ */ jsx("button", {
@@ -194,7 +194,7 @@ function CodeDialogField({ kind, title, description, text, readOnly, id, invalid
194
194
  setRefusal(null);
195
195
  setOpen(true);
196
196
  },
197
- className: cn("group/code flex w-full min-w-0 items-center gap-2 rounded-kit-md border bg-kit-subtle px-2.5 py-2 text-left outline-none transition-colors hover:border-kit-line-strong focus-visible:outline-2 focus-visible:outline-kit-focus-ring", invalid ? "border-[var(--kit-field-invalid)]" : "border-kit-line"),
197
+ className: cn("group/code flex w-full items-center gap-2 rounded-kit-md border border-kit-line bg-kit-subtle px-2.5 py-2 text-left transition-colors hover:border-kit-line-strong", invalid && "border-[var(--kit-field-invalid)]"),
198
198
  children: [
199
199
  /* @__PURE__ */ jsx(Icon, {
200
200
  className: "size-4 shrink-0 text-kit-fg-3",
@@ -206,7 +206,7 @@ function CodeDialogField({ kind, title, description, text, readOnly, id, invalid
206
206
  children: first || "Empty"
207
207
  }),
208
208
  /* @__PURE__ */ jsx("span", {
209
- className: "shrink-0 text-kit-2xs tabular-nums text-kit-fg-3",
209
+ className: "tabular-nums shrink-0 text-kit-2xs text-kit-fg-3",
210
210
  children: text ? `${text.split("\n").length} lines` : ""
211
211
  }),
212
212
  /* @__PURE__ */ jsx(IconMaximize, {
@@ -246,6 +246,7 @@ function CodeDialogField({ kind, title, description, text, readOnly, id, invalid
246
246
  }) : null] }),
247
247
  /* @__PURE__ */ jsxs(ModalFooter, { children: [
248
248
  /* @__PURE__ */ jsx("span", {
249
+ "data-hint": "shortcuts",
249
250
  className: "text-kit-xs text-kit-fg-3",
250
251
  children: "Esc to close"
251
252
  }),
@@ -391,6 +392,6 @@ function UnreadableValue({ id, title, kind, value }) {
391
392
  });
392
393
  }
393
394
  //#endregion
394
- export { CodeControl, CodeDialogField, CodeSurface, jsonProblem };
395
+ export { CodeControl, CodeDialogField, CodeSurface, UnreadableValue, jsonProblem };
395
396
 
396
397
  //# sourceMappingURL=code.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"code.js","names":[],"sources":["../../src/controls/code.tsx"],"sourcesContent":["/**\n * CODE — the code field (DESIGN 8.21), V2 controls/misc.tsx (CodeSurface, CodeControl) fitted to what prod stores.\n *\n * Values (backend reference-validation `code`, adapters/values.ts codeToProd):\n * \"<p>hi</p>\" a bare string, kept a string\n * { language?: \"html\", code: \"…\" } the object form; only `code` and `language` are written back\n * The language list sits in the surface header. Picking one writes the object form; a value that never changes its\n * language keeps the shape it was stored in. A value over CODE_MAX_LENGTH characters is refused with the reason.\n *\n * Panel: a one-line summary button that opens a `lg` dialog editing a draft (Cancel / Done). Document: the surface\n * inline. The surface: mono 12/20 textarea with line numbers, Tab inserts two spaces (Shift+Tab leaves the field),\n * Copy, and for JSON a Format action and a live \"Invalid JSON · {reason}\" footer (json.tsx).\n */\nimport * as React from \"react\";\nimport { IconAlertTriangle, IconBraces, IconCode, IconMaximize } from \"@tabler/icons-react\";\nimport { cn } from \"../lib/cn\";\nimport { isObj } from \"../lib/path\";\nimport { useKitEnv, useKitServices } from \"../context\";\nimport { CODE_MAX_LENGTH } from \"../adapters/prod-types\";\nimport type { ControlProps } from \"../types\";\nimport { Button } from \"../ui/button\";\nimport { Modal, ModalBody, ModalContent, ModalFooter, ModalHeader } from \"../ui/overlay\";\nimport { Select } from \"../ui/select\";\n\nconst CODE_LANGUAGES: { value: string; label: string }[] = [\n { value: \"html\", label: \"HTML\" },\n { value: \"css\", label: \"CSS\" },\n { value: \"js\", label: \"JS\" },\n { value: \"ts\", label: \"TS\" },\n { value: \"json\", label: \"JSON\" },\n { value: \"liquid\", label: \"Liquid\" },\n { value: \"markdown\", label: \"Markdown\" },\n { value: \"shell\", label: \"Shell\" },\n];\nconst PLAIN = \"plain\";\n\n/** The picker: Plain text, then the field's allowed languages (or the built-in list), then the stored one if it is outside them. */\nfunction languageOptions(language: string | undefined, allowed: string[] | undefined) {\n const list = allowed ? allowed.map((v) => CODE_LANGUAGES.find((l) => l.value === v) ?? { value: v, label: v }) : CODE_LANGUAGES;\n return [{ value: PLAIN, label: \"Plain text\" }, ...list, ...(language && !list.some((l) => l.value === language) ? [{ value: language, label: language }] : [])];\n}\n\n/** Why a JSON text does not parse (\"\" when it does, or is empty). */\nexport function jsonProblem(text: string): string {\n if (!text.trim()) return \"\";\n try {\n JSON.parse(text);\n return \"\";\n } catch (e) {\n return (e as Error).message.replace(/^JSON\\.parse: /, \"\");\n }\n}\n\n/* ── The surface ──────────────────────────────────────────────────────── */\nexport interface CodeSurfaceProps {\n /** \"json\": the JSON header, Format and the parse footer. \"code\": the language list. */\n kind: \"json\" | \"code\";\n value: string;\n onChange: (v: string) => void;\n /** code: the language shown in the header (\"\" = none) and what picking one does; absent = no list */\n language?: string;\n onLanguage?: (language: string) => void;\n /** code: the only languages the field allows (its config.languages); absent = the built-in list */\n languages?: string[];\n readOnly?: boolean;\n id?: string;\n invalid?: boolean;\n minRows?: number;\n label?: string;\n describedBy?: string;\n}\n\nexport function CodeSurface({ kind, value, onChange, language, onLanguage, languages, readOnly, id, invalid, minRows = 8, label, describedBy }: CodeSurfaceProps) {\n const { toast } = useKitServices();\n const lines = Math.max(minRows, value.split(\"\\n\").length);\n const problem = kind === \"json\" ? jsonProblem(value) : value.length > CODE_MAX_LENGTH ? `Code can hold up to ${CODE_MAX_LENGTH.toLocaleString(\"en-US\")} characters; this has ${value.length.toLocaleString(\"en-US\")}.` : \"\";\n const footerId = id ? `${id}-problem` : undefined;\n const format = () => {\n try {\n onChange(JSON.stringify(JSON.parse(value), null, 2));\n toast?.success(\"JSON formatted\");\n } catch {\n toast?.(\"Fix the JSON before formatting\");\n }\n };\n const copy = () => {\n void navigator.clipboard?.writeText(value);\n toast?.success(\"Copied\");\n };\n return (\n <div className={cn(\"overflow-hidden rounded-kit-lg border bg-kit-subtle\", invalid || problem ? \"border-[var(--kit-field-invalid)]\" : \"border-kit-line\")}>\n <div className=\"flex h-8 items-center justify-between border-b border-kit-line px-2\">\n {kind === \"json\" ? (\n <span className=\"px-1 font-kit-mono text-kit-xs text-kit-fg-3\">JSON</span>\n ) : onLanguage ? (\n <Select\n aria-label=\"Code language\"\n size=\"sm\"\n variant=\"ghost\"\n disabled={readOnly}\n value={language || PLAIN}\n onValueChange={(l) => onLanguage(l === PLAIN ? \"\" : l)}\n options={languageOptions(language, languages)}\n />\n ) : (\n <span className=\"px-1 font-kit-mono text-kit-xs text-kit-fg-3\">Code</span>\n )}\n <div className=\"flex items-center gap-1\">\n {kind === \"json\" ? (\n <button type=\"button\" disabled={readOnly} className=\"rounded-kit-md px-1.5 py-0.5 text-kit-xs text-kit-fg-2 hover:bg-kit-hover hover:text-kit-fg\" onClick={format}>\n Format\n </button>\n ) : null}\n <button type=\"button\" className=\"rounded-kit-md px-1.5 py-0.5 text-kit-xs text-kit-fg-2 hover:bg-kit-hover hover:text-kit-fg\" onClick={copy}>\n Copy\n </button>\n </div>\n </div>\n <div className=\"flex max-h-[60vh] overflow-auto font-kit-mono text-kit-xs leading-5\">\n <div aria-hidden className=\"select-none border-r border-kit-line bg-kit-subtle px-2 py-2 text-right text-kit-fg-4\">\n {Array.from({ length: lines }).map((_, i) => (\n <div key={i}>{i + 1}</div>\n ))}\n </div>\n <textarea\n id={id}\n spellCheck={false}\n autoCapitalize=\"off\"\n autoCorrect=\"off\"\n value={value}\n readOnly={readOnly}\n aria-invalid={invalid || !!problem || undefined}\n aria-label={label}\n aria-describedby={[describedBy, problem ? footerId : undefined].filter(Boolean).join(\" \") || undefined}\n onChange={(e) => onChange(e.target.value)}\n onKeyDown={(e) => {\n if (e.key === \"Tab\" && !e.shiftKey && !readOnly) {\n e.preventDefault();\n const el = e.currentTarget;\n const s = el.selectionStart;\n onChange(value.slice(0, s) + \" \" + value.slice(el.selectionEnd));\n requestAnimationFrame(() => el.setSelectionRange(s + 2, s + 2));\n }\n }}\n style={{ height: lines * 20 + 16 }}\n className=\"min-w-0 flex-1 resize-none bg-kit-field-bg px-3 py-2 text-kit-fg outline-none\"\n />\n </div>\n {problem ? (\n <div id={footerId} className=\"border-t border-kit-danger-line bg-kit-danger-soft px-3 py-1.5 text-kit-xs text-kit-danger-fg\">\n {kind === \"json\" ? `Invalid JSON · ${problem}` : problem}\n </div>\n ) : null}\n </div>\n );\n}\n\n/* ── Panel: summary button + dialog over a draft ─────────────────────── */\nexport function CodeDialogField({\n kind, title, description, text, readOnly, id, invalid, language, languages, onDone,\n}: {\n kind: \"json\" | \"code\";\n title: string;\n description?: string;\n text: string;\n readOnly?: boolean;\n id: string;\n invalid?: boolean;\n language?: string;\n languages?: string[];\n /** commit the draft; returns the reason it can't be saved, or null when saved */\n onDone: (draft: string, language: string | undefined) => string | null;\n}) {\n const { toast } = useKitServices();\n const [open, setOpen] = React.useState(false);\n const [draft, setDraft] = React.useState(text);\n const [lang, setLang] = React.useState(language);\n const [refusal, setRefusal] = React.useState<string | null>(null);\n const first = text.split(\"\\n\").find((l) => l.trim()) ?? \"\";\n const Icon = kind === \"json\" ? IconBraces : IconCode;\n return (\n <>\n <button\n id={id}\n type=\"button\"\n aria-haspopup=\"dialog\"\n aria-invalid={invalid || undefined}\n onClick={() => {\n setDraft(text);\n setLang(language);\n setRefusal(null);\n setOpen(true);\n }}\n className={cn(\n \"group/code flex w-full items-center gap-2 rounded-kit-md border border-kit-line bg-kit-subtle px-2.5 py-2 text-left transition-colors hover:border-kit-line-strong\",\n invalid && \"border-[var(--kit-field-invalid)]\",\n )}\n >\n <Icon className=\"size-4 shrink-0 text-kit-fg-3\" stroke={1.5} aria-hidden />\n <span className={cn(\"min-w-0 flex-1 truncate font-kit-mono text-kit-xs\", first ? \"text-kit-fg-2\" : \"text-kit-fg-3\")}>{first || \"Empty\"}</span>\n <span className=\"tabular-nums shrink-0 text-kit-2xs text-kit-fg-3\">{text ? `${text.split(\"\\n\").length} lines` : \"\"}</span>\n <IconMaximize className=\"size-3.5 shrink-0 text-kit-fg-3 group-hover/code:text-kit-fg\" stroke={1.5} aria-hidden />\n </button>\n <Modal open={open} onOpenChange={setOpen}>\n <ModalContent size=\"lg\">\n <ModalHeader title={title} description={description ?? (kind === \"json\" ? \"Structured data for developers\" : \"Custom code\")} />\n <ModalBody>\n <CodeSurface kind={kind} value={draft} onChange={setDraft} language={lang ?? \"\"} onLanguage={kind === \"code\" ? setLang : undefined} languages={languages} readOnly={readOnly} minRows={14} label={title} />\n {refusal ? (\n <p role=\"alert\" className=\"mt-2 flex items-start gap-1.5 text-kit-xs text-kit-danger-fg\">\n <IconAlertTriangle className=\"mt-0.5 size-3.5 shrink-0\" stroke={1.5} aria-hidden />\n {refusal}\n </p>\n ) : null}\n </ModalBody>\n <ModalFooter>\n <span data-hint=\"shortcuts\" className=\"text-kit-xs text-kit-fg-3\">\n Esc to close\n </span>\n <span className=\"mr-auto\" aria-hidden />\n <Button variant=\"ghost\" onClick={() => setOpen(false)}>\n Cancel\n </Button>\n <Button\n variant=\"primary\"\n disabled={readOnly}\n onClick={() => {\n const why = onDone(draft, lang);\n if (why) {\n setRefusal(why);\n toast?.(kind === \"json\" ? \"Invalid JSON\" : \"Can't save this code\", { description: \"Fix it before saving.\" });\n return;\n }\n setOpen(false);\n }}\n >\n Done\n </Button>\n </ModalFooter>\n </ModalContent>\n </Modal>\n </>\n );\n}\n\n/* ── The control ──────────────────────────────────────────────────────── */\ntype CodeRead = { ok: true; code: string; language?: string; object: boolean } | { ok: false };\nfunction readCode(v: unknown): CodeRead {\n if (v == null) return { ok: true, code: \"\", object: false };\n if (typeof v === \"string\") return { ok: true, code: v, object: false };\n if (isObj(v) && typeof v.code === \"string\" && (v.language === undefined || typeof v.language === \"string\")) return { ok: true, code: v.code, language: v.language as string | undefined, object: true };\n return { ok: false };\n}\n\n/** The stored shape for edited code: a string stays a string until a language is picked; the object keeps its form. */\nfunction codeValue(prev: CodeRead & { ok: true }, code: string, language: string | undefined): string | { language?: string; code: string } {\n const lang = language ?? prev.language ?? \"\";\n if (!prev.object && !lang) return code;\n return lang ? { language: lang, code } : { code };\n}\nconst tooLong = (code: string) => (code.length > CODE_MAX_LENGTH ? `Code can hold up to ${CODE_MAX_LENGTH.toLocaleString(\"en-US\")} characters; this has ${code.length.toLocaleString(\"en-US\")}.` : null);\n\nexport function CodeControl({ field, value, onChange, readOnly, id, invalid }: ControlProps) {\n const { variant } = useKitEnv();\n const [refused, setRefused] = React.useState<string | null>(null);\n const read = readCode(value);\n if (!read.ok) return <UnreadableValue id={id} title={field.title} kind=\"code\" value={value} />;\n if (variant === \"document\")\n return (\n <div className=\"flex flex-col gap-1.5\">\n <CodeSurface\n kind=\"code\"\n id={id}\n invalid={invalid || !!refused}\n readOnly={readOnly}\n value={read.code}\n language={read.language ?? \"\"}\n languages={field.languages}\n onChange={(code) => {\n const why = tooLong(code);\n setRefused(why);\n if (!why) onChange(codeValue(read, code, undefined));\n }}\n onLanguage={(l) => onChange(codeValue(read, read.code, l))}\n />\n {refused ? (\n <p role=\"alert\" className=\"text-kit-xs text-kit-danger-fg\">\n {refused}\n </p>\n ) : null}\n </div>\n );\n return (\n <CodeDialogField\n kind=\"code\"\n id={id}\n title={field.title}\n description={field.description || undefined}\n text={read.code}\n language={read.language}\n languages={field.languages}\n readOnly={readOnly}\n invalid={invalid}\n onDone={(draft, lang) => {\n const why = tooLong(draft);\n if (why) return why;\n const next = codeValue(read, draft, lang);\n if (draft !== read.code || (lang ?? \"\") !== (read.language ?? \"\")) onChange(next);\n return null;\n }}\n />\n );\n}\n\n/** A stored value the control cannot read: named, shown, kept as it is (never replaced by a stray edit). */\nexport function UnreadableValue({ id, title, kind, value }: { id: string; title: string; kind: string; value: unknown }) {\n let raw: string;\n try {\n raw = typeof value === \"string\" ? value : JSON.stringify(value, null, 2);\n } catch {\n raw = String(value);\n }\n return (\n <output\n id={id}\n tabIndex={0}\n data-slot={`${kind}-unreadable`}\n className=\"flex min-w-0 items-start gap-2 rounded-kit-md border border-dashed border-kit-line-strong bg-kit-subtle px-2.5 py-2 text-kit-xs text-kit-fg-2 outline-none focus-visible:outline-2 focus-visible:outline-kit-focus-ring\"\n >\n <IconAlertTriangle className=\"mt-0.5 size-3.5 shrink-0 text-kit-warning-fg\" stroke={1.5} aria-hidden />\n <span className=\"min-w-0\">\n {title} holds a value this {kind} editor can't read, so it is kept as it is:{\" \"}\n <span className=\"block max-h-24 overflow-auto whitespace-pre-wrap break-all font-kit-mono text-kit-fg\">{raw}</span>\n </span>\n </output>\n );\n}\n"],"mappings":"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"}
@@ -5,7 +5,7 @@ import { Input } from "../ui/input.js";
5
5
  import { TEXT_FOCUS, str } from "./text.js";
6
6
  import * as React from "react";
7
7
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
8
- //#region src/kit/controls/color.tsx
8
+ //#region src/controls/color.tsx
9
9
  /**
10
10
  * COLOR — site-palette swatches first, then a custom colour (V2 HEAD 9829bf1 kit/controls/misc.tsx, DESIGN §8.13).
11
11
  *
@@ -43,7 +43,7 @@ function ColorControl({ field, value, onChange, readOnly, id, invalid, onBlur })
43
43
  "aria-label": `Choose a colour for ${field.title}`,
44
44
  render: /* @__PURE__ */ jsx("button", {
45
45
  type: "button",
46
- className: "flex h-8 min-w-0 flex-1 items-center gap-2 rounded-kit-md border border-kit-field-border bg-kit-field-bg pl-1 pr-2.5 text-left text-kit-sm shadow-kit-field transition-colors hover:border-kit-field-border-hover disabled:cursor-not-allowed disabled:opacity-60 data-[popup-open]:border-kit-field-border-focus"
46
+ className: "flex h-8 min-w-0 flex-1 items-center gap-2 rounded-kit-md border border-kit-line-strong bg-kit-field-bg pl-1 pr-2.5 text-left text-kit-sm hover:border-kit-line-strong data-[popup-open]:border-kit-line-strong data-[popup-open]:bg-kit-field-bg"
47
47
  }),
48
48
  children: [
49
49
  /* @__PURE__ */ jsx("span", {
@@ -52,7 +52,7 @@ function ColorControl({ field, value, onChange, readOnly, id, invalid, onBlur })
52
52
  }),
53
53
  /* @__PURE__ */ jsx("span", {
54
54
  className: cn("min-w-0 flex-1 truncate", v ? "text-kit-fg" : "text-kit-fg-3"),
55
- children: sw ? sw.name : v ? "Custom" : "No color"
55
+ children: sw ? sw.name : v ? "Custom" : "No colour"
56
56
  }),
57
57
  sw?.token ? /* @__PURE__ */ jsx("span", {
58
58
  className: "truncate font-kit-mono text-kit-2xs text-kit-fg-3",
@@ -74,13 +74,13 @@ function ColorControl({ field, value, onChange, readOnly, id, invalid, onBlur })
74
74
  "aria-label": s.name,
75
75
  "aria-pressed": s.value.toLowerCase() === v.toLowerCase(),
76
76
  onClick: () => write(s.value),
77
- className: cn("relative size-9 rounded-kit-md border border-kit-swatch-ring transition-transform hover:scale-105", s.value.toLowerCase() === v.toLowerCase() && "ring-2 ring-kit-fg ring-offset-2 ring-offset-kit-surface"),
77
+ className: cn("relative size-9 rounded-kit-md border border-kit-swatch-ring transition-transform duration-150 ease-out motion-reduce:transition-none can-hover:hover:scale-[1.02]", s.value.toLowerCase() === v.toLowerCase() && "ring-2 ring-kit-fg ring-offset-2 ring-offset-kit-surface"),
78
78
  style: { background: s.value }
79
79
  })
80
80
  }, s.value))
81
81
  })] }) : null,
82
82
  /* @__PURE__ */ jsxs("label", {
83
- className: cn("flex items-center gap-2 text-kit-xs text-kit-fg-3", palette.length && "mt-3 border-t border-kit-line pt-3"),
83
+ className: cn("mt-3 flex items-center gap-2 border-t border-kit-line pt-3 text-kit-xs text-kit-fg-3", !palette.length && "mt-0 border-t-0 pt-0"),
84
84
  children: ["Custom", /* @__PURE__ */ jsx("input", {
85
85
  type: "color",
86
86
  value: pickerHex(v),
@@ -92,7 +92,7 @@ function ColorControl({ field, value, onChange, readOnly, id, invalid, onBlur })
92
92
  type: "button",
93
93
  onClick: () => write(null),
94
94
  className: "mt-2 w-full rounded-kit-md px-1.5 py-1 text-left text-kit-xs text-kit-fg-2 hover:bg-kit-hover hover:text-kit-fg",
95
- children: "No color"
95
+ children: "No colour"
96
96
  }) : null
97
97
  ]
98
98
  })] }), /* @__PURE__ */ jsx(Input, {
@@ -110,7 +110,7 @@ function ColorControl({ field, value, onChange, readOnly, id, invalid, onBlur })
110
110
  else setDraft(e.target.value);
111
111
  },
112
112
  onBlur,
113
- className: cn(TEXT_FOCUS, "w-28 shrink-0 font-kit-mono")
113
+ className: cn(TEXT_FOCUS, "w-28 shrink-0 font-kit-mono [&_input]:font-kit-mono")
114
114
  })]
115
115
  }), bad ? /* @__PURE__ */ jsxs("p", {
116
116
  id: errId,
@@ -125,6 +125,6 @@ function ColorControl({ field, value, onChange, readOnly, id, invalid, onBlur })
125
125
  });
126
126
  }
127
127
  //#endregion
128
- export { ColorControl };
128
+ export { ColorControl, HEX_COLOR, pickerHex };
129
129
 
130
130
  //# sourceMappingURL=color.js.map