@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
@@ -1,15 +1,19 @@
1
+ import { cropPreset, cropRect, isCropRect } from "../adapters/values.js";
1
2
  import { cn } from "../lib/cn.js";
2
- import { isObj } from "../lib/path.js";
3
3
  import { useKitEnv, useKitServices } from "../context.js";
4
- import { Button } from "../ui/button.js";
4
+ import { isObj } from "../lib/path.js";
5
+ import { Button, IconButton } from "../ui/button.js";
5
6
  import { Progress } from "../ui/controls.js";
6
7
  import { Menu, MenuContent, MenuItem, MenuSeparator, MenuTrigger, Popover, PopoverAnchor, PopoverContent, Tooltip } from "../ui/overlay.js";
8
+ import { RowChrome } from "../engine/bits.js";
9
+ import { isIconImage } from "../lib/icon-image.js";
7
10
  import { Input, Textarea } from "../ui/input.js";
11
+ import { Select } from "../ui/select.js";
8
12
  import { useDragReorder } from "../engine/item-list.js";
9
13
  import * as React from "react";
10
- import { IconAlertTriangle, IconDots, IconDownload, IconExternalLink, IconFileText, IconFocusCentered, IconLink, IconPhoto, IconPlayerPlay, IconPlus, IconReplace, IconTrash, IconUpload, IconVideo, IconWorld, IconX } from "@tabler/icons-react";
11
14
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
12
- //#region src/kit/controls/media.tsx
15
+ import { IconAlertTriangle, IconCrop, IconDots, IconDownload, IconExternalLink, IconFileText, IconFocusCentered, IconLink, IconPhoto, IconPlayerPlay, IconPlus, IconRefresh, IconReplace, IconTrash, IconUpload, IconVideo, IconWorld, IconX } from "@tabler/icons-react";
16
+ //#region src/controls/media.tsx
13
17
  /**
14
18
  * MEDIA — image · gallery · file · video (V2 HEAD 9829bf1 kit/controls/media.tsx, DESIGN.md 8.15).
15
19
  *
@@ -19,8 +23,9 @@ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
19
23
  * (media-services.ts): the kit never imports a feature, and a missing service is named in words, never faked.
20
24
  *
21
25
  * Kit deviations from V2, each because of what the backend stores (adapters/values.ts):
22
- * - no "Crop for this placement" dropdown: `imageToProd` cannot store a crop preset (it becomes a pixel rect only with
23
- * the asset's size, and never reads back as the preset), so the dock would refuse every write that carried one;
26
+ * - "Crop for this placement" is V2's five-crop dropdown, stored as the rect prod keeps (cut from the picture's own size,
27
+ * centred on the focal point); a stored rect reads back as its preset when the size is known, and is kept as it is
28
+ * otherwise. With no size yet, the dropdown waits, and says why;
24
29
  * - a picked asset's width / height / size are read for the caption, never written into the value (prod rebuilds the
25
30
  * value from url, id, name, altText and focal; the rest would be refused);
26
31
  * - where the host stores the URL string only (`imageStoresUrl`, the dock's top-level image props) the value stays a
@@ -31,11 +36,15 @@ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
31
36
  * refuses a half-typed address.
32
37
  */
33
38
  var fileNameFromUrl = (url) => {
34
- const last = url.split("?")[0].split("#")[0].split("/").filter(Boolean).pop() ?? "";
39
+ const inline = /^data:image\/([a-z0-9.+-]+)/i.exec(url.trim());
40
+ if (inline) return `Embedded ${inline[1].replace(/\+xml$/i, "").replace(/^jpeg$/i, "jpg").toUpperCase()} image`;
35
41
  try {
36
- return decodeURIComponent(last);
42
+ const u = new URL(url, typeof window === "undefined" ? "https://x.invalid" : window.location.href);
43
+ if (u.protocol === "data:" || u.protocol === "blob:") return "Image";
44
+ const file = u.pathname.split("/").filter(Boolean).reverse().find((x) => /\.[a-z0-9]{2,5}$/i.test(x));
45
+ return file ? decodeURIComponent(file) : `Image from ${u.hostname.replace(/^www\./, "")}`;
37
46
  } catch {
38
- return last;
47
+ return "Image";
39
48
  }
40
49
  };
41
50
  var normImage = (v) => {
@@ -44,10 +53,10 @@ var normImage = (v) => {
44
53
  };
45
54
  /** What an asset becomes in a value: the keys prod keeps (url, id, name, alt), nothing measured. */
46
55
  var fromAsset = (a) => {
47
- const out = {
56
+ const out = a.id ? {
48
57
  url: a.url,
49
58
  id: a.id
50
- };
59
+ } : { url: a.url };
51
60
  if (a.name) out.name = a.name;
52
61
  if (a.alt) out.alt = a.alt;
53
62
  return out;
@@ -57,6 +66,7 @@ var HTTP = /^https?:\/\/\S+$/i;
57
66
  /** An http(s) URL or a site path: what prod's video value takes (video-value.ts isVideoUrl). */
58
67
  var isVideoUrl = (s) => s === "" || HTTP.test(s.trim()) || /^\/(?!\/)\S*$/.test(s.trim());
59
68
  var NO_ASSET = () => void 0;
69
+ var NO_ICONS = () => [];
60
70
  var NO_SRC = (u) => u;
61
71
  /** The services the media controls read, each hook stable across renders. */
62
72
  function useMedia() {
@@ -183,8 +193,8 @@ function DropWell({ id, title, hint, accept, multiple, icon, disabled, onFiles,
183
193
  className: "text-kit-xs text-kit-fg-3",
184
194
  children: hint
185
195
  }) : null] }),
186
- urlMode && onUrl ? /* @__PURE__ */ jsxs("form", {
187
- className: "flex w-full max-w-sm flex-col gap-1.5",
196
+ urlMode && onUrl ? /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsxs("form", {
197
+ className: "flex w-full max-w-sm items-center gap-1.5",
188
198
  onSubmit: (e) => {
189
199
  e.preventDefault();
190
200
  e.stopPropagation();
@@ -203,26 +213,22 @@ function DropWell({ id, title, hint, accept, multiple, icon, disabled, onFiles,
203
213
  setUrlError(null);
204
214
  }
205
215
  },
206
- children: [/* @__PURE__ */ jsxs("div", {
207
- className: "flex items-center gap-1.5",
208
- children: [/* @__PURE__ */ jsx(Input, {
209
- autoFocus: true,
210
- size: "sm",
211
- value: url,
212
- "aria-label": "Image URL",
213
- "aria-invalid": urlError ? true : void 0,
214
- onChange: (e) => setUrl(e.target.value),
215
- placeholder: "https://…/photo.jpg",
216
- leading: /* @__PURE__ */ jsx(IconLink, { stroke: 1.5 }),
217
- className: "flex-1"
218
- }), /* @__PURE__ */ jsx(Button, {
219
- size: "sm",
220
- type: "submit",
221
- variant: "primary",
222
- children: "Add"
223
- })]
224
- }), urlError ? /* @__PURE__ */ jsx(Reason, { children: urlError }) : null]
225
- }) : /* @__PURE__ */ jsxs("div", {
216
+ children: [/* @__PURE__ */ jsx(Input, {
217
+ autoFocus: true,
218
+ size: "sm",
219
+ value: url,
220
+ "aria-label": "Image URL",
221
+ "aria-invalid": urlError ? true : void 0,
222
+ onChange: (e) => setUrl(e.target.value),
223
+ placeholder: "https://…/photo.jpg",
224
+ leading: /* @__PURE__ */ jsx(IconLink, { stroke: 1.5 })
225
+ }), /* @__PURE__ */ jsx(Button, {
226
+ size: "sm",
227
+ type: "submit",
228
+ variant: "primary",
229
+ children: "Add"
230
+ })]
231
+ }), urlError ? /* @__PURE__ */ jsx(Reason, { children: urlError }) : null] }) : /* @__PURE__ */ jsxs("div", {
226
232
  className: "flex flex-wrap justify-center gap-1.5",
227
233
  children: [
228
234
  onLibrary || refuse ? /* @__PURE__ */ jsx(Button, {
@@ -289,19 +295,114 @@ function DropWell({ id, title, hint, accept, multiple, icon, disabled, onFiles,
289
295
  var NO_SOURCE = "No media library or upload is connected to this editor, so nothing can be chosen here.";
290
296
  var NO_LIBRARY = "No media library is connected to this editor, so nothing can be picked from it here.";
291
297
  var NO_UPLOAD = "No upload is connected to this editor, so files can't be uploaded here.";
292
- function ImageDetails({ v, onChange, readOnly, label, urlOnly, size, asset }) {
298
+ /** Transparency checker on the kit tokens (white in light, dimmed in dark), as the media grid draws it. */
299
+ var CHECKER = "bg-kit-checker-a [background-image:conic-gradient(var(--kit-checker-b)_25%,var(--kit-checker-a)_0_50%,var(--kit-checker-b)_0_75%,var(--kit-checker-a)_0)] [background-size:12px_12px]";
300
+ /** The preview frame's shape bounds: a tall or panoramic picture never makes the dock tall or a sliver. */
301
+ var FRAME_MIN = 1;
302
+ var FRAME_MAX = 2;
303
+ /**
304
+ * How a preview frames a picture of any shape: the frame follows the picture's ratio between square and 2:1, and the
305
+ * picture fits inside it WHOLE, filling the frame's width or height (a portrait is boxed at the sides, a panorama above
306
+ * and below, on the checker). With no known size (still loading, or an SVG with no intrinsic size) the frame is 16:9
307
+ * and the picture is contained. Before 2026-10-16 every picture was cropped to a fixed 16:9 (`object-cover`).
308
+ */
309
+ function frameFit(size) {
310
+ if (!size || !(size.w > 0) || !(size.h > 0)) return {
311
+ frame: 16 / 9,
312
+ image: null,
313
+ fill: "contain"
314
+ };
315
+ const image = size.w / size.h;
316
+ const frame = Math.min(FRAME_MAX, Math.max(FRAME_MIN, image));
317
+ return {
318
+ frame,
319
+ image,
320
+ fill: image < frame ? "height" : "width"
321
+ };
322
+ }
323
+ /** The picture's classes for a fit: it keeps its own ratio and the frame's width or height, never cut. */
324
+ var FIT_CLASS = {
325
+ width: "h-auto max-h-full w-full object-contain",
326
+ height: "h-full w-auto max-w-full object-contain",
327
+ contain: "size-full object-contain"
328
+ };
329
+ /** V2's five crops (kit media.tsx CROPS, D46). */
330
+ var CROPS = [
331
+ {
332
+ value: "original",
333
+ label: "Original",
334
+ ratio: "auto",
335
+ description: "Keep the uploaded shape"
336
+ },
337
+ {
338
+ value: "16:9",
339
+ label: "16:9",
340
+ ratio: "16/9",
341
+ description: "Widescreen"
342
+ },
343
+ {
344
+ value: "4:3",
345
+ label: "4:3",
346
+ ratio: "4/3",
347
+ description: "Landscape"
348
+ },
349
+ {
350
+ value: "1:1",
351
+ label: "1:1",
352
+ ratio: "1/1",
353
+ description: "Square"
354
+ },
355
+ {
356
+ value: "4:5",
357
+ label: "4:5",
358
+ ratio: "4/5",
359
+ description: "Portrait"
360
+ }
361
+ ];
362
+ var CUSTOM_CROP = "custom";
363
+ /** The crop a value shows: its preset, a stored rect read against the picture's size, or a rect that is none of them. */
364
+ function cropChoice(crop, size) {
365
+ if (!crop) return "original";
366
+ if (typeof crop === "string") return crop;
367
+ if (!isCropRect(crop)) return "original";
368
+ return size && cropPreset(crop, size.w, size.h) || CUSTOM_CROP;
369
+ }
370
+ /** A custom rect's own shape (its fractions of the picture, in pixels), when the picture's size is known. */
371
+ function customRatio(crop, size) {
372
+ if (!size || !crop || typeof crop === "string" || !isCropRect(crop)) return void 0;
373
+ const w = (1 - crop.left - crop.right) * size.w;
374
+ const h = (1 - crop.top - crop.bottom) * size.h;
375
+ return w > 0 && h > 0 ? String(w / h) : void 0;
376
+ }
377
+ /** The value with `choice` cut from the picture (centred on its focal point), or with no crop for Original. */
378
+ function withCrop(v, choice, size) {
379
+ const next = { ...v };
380
+ delete next.crop;
381
+ const rect = choice === "original" ? void 0 : cropRect(choice, size.w, size.h, v.focal);
382
+ if (rect) next.crop = rect;
383
+ return next;
384
+ }
385
+ function ImageDetails({ v, onChange, readOnly, label, urlOnly, altOnly = false, size, asset }) {
293
386
  const { src } = useMedia();
294
387
  const focal = v.focal ?? {
295
388
  x: 50,
296
389
  y: 50
297
390
  };
298
- const setFocal = (x, y) => onChange({
299
- ...v,
300
- focal: {
301
- x: Math.round(Math.min(100, Math.max(0, x))),
302
- y: Math.round(Math.min(100, Math.max(0, y)))
303
- }
304
- });
391
+ const choice = cropChoice(v.crop, size);
392
+ const crop = CROPS.find((c) => c.value === choice);
393
+ const own = choice === "original" && size ? frameFit(size) : null;
394
+ const pad = own?.image ? own : null;
395
+ const padRatio = crop && crop.ratio !== "auto" ? crop.ratio : pad ? String(pad.image) : customRatio(v.crop, size) ?? "3/2";
396
+ const setFocal = (x, y) => {
397
+ const next = {
398
+ ...v,
399
+ focal: {
400
+ x: Math.round(Math.min(100, Math.max(0, x))),
401
+ y: Math.round(Math.min(100, Math.max(0, y)))
402
+ }
403
+ };
404
+ onChange(crop && crop.value !== "original" && size ? withCrop(next, crop.value, size) : next);
405
+ };
305
406
  const fromPointer = (e) => {
306
407
  const r = e.currentTarget.getBoundingClientRect();
307
408
  if (!r.width || !r.height) return;
@@ -356,21 +457,29 @@ function ImageDetails({ v, onChange, readOnly, label, urlOnly, size, asset }) {
356
457
  className: "min-h-14 text-kit-sm",
357
458
  "aria-label": `${label} alt text`
358
459
  })]
359
- }), /* @__PURE__ */ jsxs("div", {
460
+ }), altOnly ? /* @__PURE__ */ jsx(Reason, {
461
+ tone: "muted",
462
+ children: "This image block keeps its address and alt text. A crop or focal point isn't stored with it."
463
+ }) : /* @__PURE__ */ jsxs("div", {
360
464
  className: "flex flex-col gap-1.5",
361
465
  children: [
362
466
  /* @__PURE__ */ jsxs("div", {
363
467
  className: "flex items-center justify-between",
364
468
  children: [/* @__PURE__ */ jsxs("span", {
365
469
  className: "flex items-center gap-1 text-kit-xs text-kit-fg-3",
366
- children: [/* @__PURE__ */ jsx(IconFocusCentered, {
470
+ children: [/* @__PURE__ */ jsx(IconCrop, {
367
471
  className: "size-3.5",
368
472
  stroke: 1.5,
369
473
  "aria-hidden": true
370
- }), "Focal point"]
474
+ }), "Crop for this placement"]
371
475
  }), /* @__PURE__ */ jsxs("span", {
372
- className: "tabular-nums text-kit-2xs text-kit-fg-3",
476
+ className: "flex items-center gap-1 text-kit-2xs text-kit-fg-3",
373
477
  children: [
478
+ /* @__PURE__ */ jsx(IconFocusCentered, {
479
+ className: "size-3",
480
+ stroke: 1.5,
481
+ "aria-hidden": true
482
+ }),
374
483
  "Focal ",
375
484
  focal.x,
376
485
  "%, ",
@@ -379,43 +488,71 @@ function ImageDetails({ v, onChange, readOnly, label, urlOnly, size, asset }) {
379
488
  ]
380
489
  })]
381
490
  }),
382
- /* @__PURE__ */ jsxs("div", {
383
- role: "slider",
384
- "aria-label": "Focal point. Click the subject.",
385
- "aria-valuetext": `${focal.x}% across, ${focal.y}% down`,
386
- "aria-valuenow": focal.x,
387
- "aria-valuemin": 0,
388
- "aria-valuemax": 100,
389
- "aria-readonly": readOnly || void 0,
390
- tabIndex: 0,
391
- onPointerDown: (e) => !readOnly && fromPointer(e),
392
- onKeyDown: (e) => {
393
- const d = e.shiftKey ? 10 : 2;
394
- const step = {
395
- ArrowLeft: [-d, 0],
396
- ArrowRight: [d, 0],
397
- ArrowUp: [0, -d],
398
- ArrowDown: [0, d]
399
- }[e.key];
400
- if (!step || readOnly) return;
401
- e.preventDefault();
402
- setFocal(focal.x + step[0], focal.y + step[1]);
403
- },
404
- className: "relative mt-1 aspect-[3/2] cursor-crosshair overflow-hidden rounded-kit-md border border-kit-line bg-kit-muted",
405
- children: [/* @__PURE__ */ jsx("img", {
406
- src: src(v.url),
407
- alt: "",
408
- draggable: false,
409
- className: "pointer-events-none size-full select-none object-cover transition-[object-position] duration-200 motion-reduce:transition-none",
410
- style: { objectPosition: `${focal.x}% ${focal.y}%` }
411
- }), /* @__PURE__ */ jsx("span", {
412
- "aria-hidden": true,
413
- className: "pointer-events-none absolute size-5 -translate-x-1/2 -translate-y-1/2 rounded-full border-2 border-kit-fg-inverse bg-kit-inverse/30 shadow-kit-md transition-[left,top] duration-150 motion-reduce:transition-none",
414
- style: {
415
- left: `${focal.x}%`,
416
- top: `${focal.y}%`
417
- }
418
- })]
491
+ /* @__PURE__ */ jsx(Select, {
492
+ size: "sm",
493
+ "aria-label": `${label} crop`,
494
+ disabled: readOnly || !size,
495
+ triggerClassName: "w-full",
496
+ value: choice,
497
+ onValueChange: (c) => size && c !== CUSTOM_CROP && onChange(withCrop(v, c, size)),
498
+ options: [...CROPS.map((c) => ({
499
+ value: c.value,
500
+ label: c.label,
501
+ meta: c.description
502
+ })), ...choice === CUSTOM_CROP ? [{
503
+ value: CUSTOM_CROP,
504
+ label: "Custom",
505
+ meta: "Cut elsewhere",
506
+ disabled: true
507
+ }] : []]
508
+ }),
509
+ !size && !readOnly ? /* @__PURE__ */ jsx("span", {
510
+ className: "text-kit-2xs text-kit-fg-3",
511
+ children: "The crop is cut from the picture's size, which is still loading."
512
+ }) : null,
513
+ /* @__PURE__ */ jsx("div", {
514
+ className: cn(pad ? "mt-1 flex items-center justify-center overflow-hidden rounded-kit-md border border-kit-line" : "contents", pad && CHECKER),
515
+ style: pad ? { aspectRatio: pad.frame } : void 0,
516
+ children: /* @__PURE__ */ jsxs("div", {
517
+ role: "slider",
518
+ "aria-label": "Focal point. Click the subject.",
519
+ "aria-valuetext": `${focal.x}% across, ${focal.y}% down`,
520
+ "aria-valuenow": focal.x,
521
+ "aria-valuemin": 0,
522
+ "aria-valuemax": 100,
523
+ "aria-readonly": readOnly || void 0,
524
+ tabIndex: 0,
525
+ onPointerDown: (e) => !readOnly && fromPointer(e),
526
+ onKeyDown: (e) => {
527
+ const d = e.shiftKey ? 10 : 2;
528
+ const step = {
529
+ ArrowLeft: [-d, 0],
530
+ ArrowRight: [d, 0],
531
+ ArrowUp: [0, -d],
532
+ ArrowDown: [0, d]
533
+ }[e.key];
534
+ if (!step || readOnly) return;
535
+ e.preventDefault();
536
+ setFocal(focal.x + step[0], focal.y + step[1]);
537
+ },
538
+ "data-pad-ratio": padRatio,
539
+ className: pad ? cn("relative cursor-crosshair overflow-hidden", pad.fill === "height" ? "h-full" : "w-full") : "relative mt-1 cursor-crosshair overflow-hidden rounded-kit-md border border-kit-line bg-kit-muted",
540
+ style: { aspectRatio: padRatio },
541
+ children: [/* @__PURE__ */ jsx("img", {
542
+ src: src(v.url),
543
+ alt: "",
544
+ draggable: false,
545
+ className: "pointer-events-none size-full select-none object-cover transition-[object-position] duration-200",
546
+ style: { objectPosition: `${focal.x}% ${focal.y}%` }
547
+ }), /* @__PURE__ */ jsx("span", {
548
+ "aria-hidden": true,
549
+ className: "pointer-events-none absolute size-5 -translate-x-1/2 -translate-y-1/2 rounded-full border-2 border-kit-media-handle bg-kit-media-handle-ring shadow-kit-md transition-[left,top] duration-150",
550
+ style: {
551
+ left: `${focal.x}%`,
552
+ top: `${focal.y}%`
553
+ }
554
+ })]
555
+ })
419
556
  }),
420
557
  /* @__PURE__ */ jsx("span", {
421
558
  className: "text-kit-2xs text-kit-fg-3",
@@ -423,7 +560,7 @@ function ImageDetails({ v, onChange, readOnly, label, urlOnly, size, asset }) {
423
560
  })
424
561
  ]
425
562
  })] }),
426
- /* @__PURE__ */ jsxs("div", {
563
+ urlOnly || altOnly ? /* @__PURE__ */ jsxs("div", {
427
564
  className: "flex flex-col gap-1.5",
428
565
  children: [/* @__PURE__ */ jsx("span", {
429
566
  className: "text-kit-xs text-kit-fg-3",
@@ -432,6 +569,26 @@ function ImageDetails({ v, onChange, readOnly, label, urlOnly, size, asset }) {
432
569
  className: "truncate font-kit-mono text-kit-xs text-kit-fg",
433
570
  children: asset?.name ?? v.name ?? fileNameFromUrl(v.url)
434
571
  })]
572
+ }) : /* @__PURE__ */ jsxs("label", {
573
+ className: "flex flex-col gap-1.5",
574
+ children: [/* @__PURE__ */ jsx("span", {
575
+ className: "text-kit-xs text-kit-fg-3",
576
+ children: "File name"
577
+ }), /* @__PURE__ */ jsx(Input, {
578
+ size: "sm",
579
+ value: v.name ?? asset?.name ?? fileNameFromUrl(v.url),
580
+ readOnly,
581
+ spellCheck: false,
582
+ autoComplete: "off",
583
+ onChange: (e) => {
584
+ const next = { ...v };
585
+ if (e.target.value) next.name = e.target.value;
586
+ else delete next.name;
587
+ onChange(next);
588
+ },
589
+ className: "font-kit-mono [&_input]:font-kit-mono",
590
+ "aria-label": `${label} file name`
591
+ })]
435
592
  })
436
593
  ]
437
594
  });
@@ -445,19 +602,105 @@ function storedSize(value) {
445
602
  h: height
446
603
  } : void 0;
447
604
  }
448
- var PILL = "flex h-7 items-center gap-1 rounded-full border border-kit-swatch-ring bg-kit-control-bg px-2.5 text-kit-xs font-medium text-kit-fg shadow-kit-sm";
605
+ /**
606
+ * V2's icon control shape (controls/icon.tsx): ONE button — a 24px glyph tile, the field's name, a quiet replace cue —
607
+ * that opens the library. No Replace pill, no ×, no alt text, crop or details: an icon's alt text is "" (aria-hidden on
608
+ * the page) and Remove sits in the picker's footer. Empty: a dashed tile, "Add icon", and an SVG dropped on it uploads.
609
+ */
610
+ function IconImageRow({ id, title, url, readOnly, onOpen, onFiles, busy, pickerOpen }) {
611
+ const row = React.useRef(null);
612
+ const [over, setOver] = React.useState(false);
613
+ const wasOpen = React.useRef(false);
614
+ React.useEffect(() => {
615
+ if (wasOpen.current && !pickerOpen) row.current?.focus({ preventScroll: true });
616
+ wasOpen.current = pickerOpen;
617
+ }, [pickerOpen]);
618
+ const empty = !url;
619
+ const inert = readOnly || busy || !onOpen;
620
+ const droppable = empty && !inert && !!onFiles;
621
+ const chrome = React.useContext(RowChrome);
622
+ return /* @__PURE__ */ jsxs("div", {
623
+ className: cn("flex h-8 min-w-0 items-center rounded-kit-md border bg-kit-field-bg pointer-coarse:min-h-11", "transition-colors duration-[120ms] ease-out motion-reduce:transition-none", over ? "border-kit-emphasis-line bg-kit-hover" : "border-kit-line-strong", inert ? "opacity-60" : "[@media(hover:hover)]:hover:bg-kit-hover"),
624
+ children: [/* @__PURE__ */ jsx(Tooltip, {
625
+ content: title,
626
+ children: /* @__PURE__ */ jsxs("button", {
627
+ ref: row,
628
+ id,
629
+ type: "button",
630
+ "data-slot": "kit-icon-row",
631
+ disabled: inert,
632
+ onClick: onOpen,
633
+ "aria-label": empty ? `Add icon, ${title}` : `Replace ${title}`,
634
+ onDragOver: droppable ? (e) => {
635
+ e.preventDefault();
636
+ setOver(true);
637
+ } : void 0,
638
+ onDragLeave: droppable ? () => setOver(false) : void 0,
639
+ onDrop: droppable ? (e) => {
640
+ e.preventDefault();
641
+ setOver(false);
642
+ onFiles(Array.from(e.dataTransfer.files));
643
+ } : void 0,
644
+ className: "flex min-w-0 flex-1 touch-manipulation items-center gap-3 self-stretch rounded-[5px] pl-[3px] pr-2 text-left text-kit-sm focus-visible:-outline-offset-2 disabled:cursor-not-allowed",
645
+ children: [
646
+ /* @__PURE__ */ jsx("span", {
647
+ "aria-hidden": true,
648
+ className: cn("grid size-6 shrink-0 place-items-center overflow-hidden rounded-kit-sm border", empty ? "border-dashed border-kit-emphasis-line" : cn("border-kit-line p-1", CHECKER)),
649
+ children: empty ? /* @__PURE__ */ jsx(IconPlus, {
650
+ className: "size-3.5 text-kit-fg-3",
651
+ stroke: 1.5
652
+ }) : /* @__PURE__ */ jsx("img", {
653
+ src: url,
654
+ alt: "",
655
+ className: "size-full object-contain"
656
+ })
657
+ }),
658
+ /* @__PURE__ */ jsx("span", {
659
+ "aria-hidden": true,
660
+ className: cn("min-w-0 flex-1 truncate", empty ? "text-kit-fg-3" : "text-kit-fg"),
661
+ children: empty ? busy ? "Uploading…" : "Add icon" : title
662
+ }),
663
+ empty ? null : /* @__PURE__ */ jsx(IconRefresh, {
664
+ "aria-hidden": true,
665
+ className: "size-3.5 shrink-0 text-kit-fg-3",
666
+ stroke: 1.5
667
+ })
668
+ ]
669
+ })
670
+ }), chrome ? /* @__PURE__ */ jsx("span", {
671
+ "data-slot": "kit-icon-row-chrome",
672
+ className: "flex shrink-0 items-center gap-0.5 pr-1 empty:hidden",
673
+ children: chrome
674
+ }) : null]
675
+ });
676
+ }
449
677
  function ImageControl({ field, value, onChange: write, readOnly, id, path }) {
450
678
  const { s, useAsset, src } = useMedia();
451
679
  const env = useKitEnv();
452
680
  const urlOnly = !!s.imageStoresUrl?.(path);
681
+ const altOnly = !urlOnly && !!s.imageAltOnly?.(path);
453
682
  const legacyString = typeof value === "string" || field.valueShape === "string";
454
683
  const v = normImage(value);
455
684
  const asset = useAsset({
456
685
  id: v?.id,
457
686
  url: v?.url ?? ""
458
687
  });
459
- const [natural, setNatural] = React.useState();
460
- React.useEffect(() => setNatural(void 0), [v?.url]);
688
+ const accept = field.svgOnly ? "image/svg+xml" : "image/*";
689
+ const kinds = field.svgOnly ? ["svg"] : ["image", "svg"];
690
+ const [loaded, setLoaded] = React.useState();
691
+ const natural = loaded && v && loaded.url === v.url ? {
692
+ w: loaded.w,
693
+ h: loaded.h
694
+ } : void 0;
695
+ const readNatural = (img) => {
696
+ if (!img || !v || !img.complete || !img.naturalWidth || !img.naturalHeight) return;
697
+ const next = {
698
+ url: v.url,
699
+ w: img.naturalWidth,
700
+ h: img.naturalHeight
701
+ };
702
+ setLoaded((prev) => prev && prev.url === next.url && prev.w === next.w && prev.h === next.h ? prev : next);
703
+ };
461
704
  const stored = storedSize(value);
462
705
  const size = asset?.width && asset.height ? {
463
706
  w: asset.width,
@@ -466,13 +709,68 @@ function ImageControl({ field, value, onChange: write, readOnly, id, path }) {
466
709
  const onChange = (n) => {
467
710
  if (!n) return write(urlOnly ? "" : null);
468
711
  if (urlOnly) return write(n.url);
469
- if (legacyString && !n.alt && !n.focal) return write(n.url);
712
+ if (legacyString && !n.alt && !n.focal && !n.crop && !n.name && !n.id) return write(n.url);
470
713
  write(n);
471
714
  };
472
715
  const [picker, setPicker] = React.useState(false);
473
716
  const [details, setDetails] = React.useState(false);
474
- const up = useUpload("image/*", "image", (a) => a[0] && onChange(fromAsset(a[0])));
717
+ const up = useUpload(accept, "image", (a) => a[0] && onChange(fromAsset(a[0])));
475
718
  const library = s.MediaPicker && !readOnly ? () => setPicker(true) : void 0;
719
+ const known = (s.useSiteIcons ?? NO_ICONS)();
720
+ if (isIconImage(field, value)) {
721
+ const icons = s.useSiteIcons ? [...v ? [{
722
+ url: v.url,
723
+ value,
724
+ current: true
725
+ }] : [], ...known.filter((i) => i.url !== v?.url && !(v?.id && i.assetId === v.id)).map(({ url, value: stored }) => ({
726
+ url,
727
+ value: stored
728
+ }))] : void 0;
729
+ const pickIcon = (stored) => {
730
+ const n = normImage(stored);
731
+ if (n) onChange(fromAsset({
732
+ id: n.id ?? "",
733
+ url: n.url,
734
+ name: n.name,
735
+ alt: n.alt ?? (typeof n.altText === "string" ? n.altText : void 0),
736
+ kind: "svg"
737
+ }));
738
+ setPicker(false);
739
+ };
740
+ return /* @__PURE__ */ jsxs("div", {
741
+ className: "flex flex-col gap-1.5",
742
+ children: [
743
+ /* @__PURE__ */ jsx(IconImageRow, {
744
+ id,
745
+ title: field.title,
746
+ url: v ? src(v.url) : void 0,
747
+ readOnly,
748
+ onOpen: library,
749
+ onFiles: up.run,
750
+ busy: up.progress != null,
751
+ pickerOpen: picker
752
+ }),
753
+ up.error ? /* @__PURE__ */ jsx(Reason, { children: up.error }) : null,
754
+ !readOnly && !library ? /* @__PURE__ */ jsx(Reason, {
755
+ tone: "muted",
756
+ children: NO_LIBRARY
757
+ }) : null,
758
+ /* @__PURE__ */ jsx(MediaPicker, {
759
+ open: picker,
760
+ onOpenChange: setPicker,
761
+ accept: ["svg"],
762
+ title: v ? "Replace icon" : "Select an icon",
763
+ onPick: (a) => a[0] && onChange(fromAsset(a[0])),
764
+ onRemove: v && !readOnly ? () => {
765
+ onChange(null);
766
+ setPicker(false);
767
+ } : void 0,
768
+ icons,
769
+ onPickIcon: readOnly ? void 0 : pickIcon
770
+ })
771
+ ]
772
+ });
773
+ }
476
774
  if (!v) return /* @__PURE__ */ jsxs("div", {
477
775
  className: "flex flex-col gap-1.5",
478
776
  children: [
@@ -480,7 +778,7 @@ function ImageControl({ field, value, onChange: write, readOnly, id, path }) {
480
778
  id,
481
779
  title: "Add an image",
482
780
  hint: "Or drop or paste one here",
483
- accept: "image/*",
781
+ accept,
484
782
  icon: /* @__PURE__ */ jsx(IconPhoto, { stroke: 1.5 }),
485
783
  onFiles: up.run,
486
784
  onLibrary: library,
@@ -496,15 +794,14 @@ function ImageControl({ field, value, onChange: write, readOnly, id, path }) {
496
794
  /* @__PURE__ */ jsx(MediaPicker, {
497
795
  open: picker,
498
796
  onOpenChange: setPicker,
499
- accept: ["image", "svg"],
797
+ accept: kinds,
500
798
  onPick: (a) => a[0] && onChange(fromAsset(a[0]))
501
799
  })
502
800
  ]
503
801
  });
504
- const focal = v.focal ?? {
505
- x: 50,
506
- y: 50
507
- };
802
+ const fit = frameFit(size);
803
+ const vector = asset?.kind === "svg" || !!field.svgOnly || /\.svg(?:$|[?#])/i.test(v.url);
804
+ const cap = fit.image && size && !vector ? size : void 0;
508
805
  const alt = urlOnly ? asset?.alt : v.alt;
509
806
  const name = asset?.name ?? v.name ?? fileNameFromUrl(v.url);
510
807
  const replace = (a) => {
@@ -529,7 +826,10 @@ function ImageControl({ field, value, onChange: write, readOnly, id, path }) {
529
826
  },
530
827
  children: [
531
828
  /* @__PURE__ */ jsxs("div", {
532
- className: "group/img relative aspect-video overflow-hidden rounded-kit-lg border border-kit-line bg-kit-muted",
829
+ "data-slot": "kit-image-frame",
830
+ "data-frame-ratio": String(fit.frame),
831
+ className: cn("group/img relative overflow-hidden rounded-kit-lg border border-kit-line", CHECKER),
832
+ style: { aspectRatio: fit.frame },
533
833
  children: [
534
834
  /* @__PURE__ */ jsx("button", {
535
835
  id,
@@ -537,19 +837,23 @@ function ImageControl({ field, value, onChange: write, readOnly, id, path }) {
537
837
  disabled: readOnly,
538
838
  onClick: () => library ? library() : openDetails(),
539
839
  "aria-label": library ? `Replace ${field.title}` : `${field.title} details`,
540
- className: "block size-full outline-none focus-visible:outline-2 focus-visible:-outline-offset-2 focus-visible:outline-kit-focus-ring focus-visible:[outline-style:solid] [html[data-input-modality=pointer]_&]:focus-visible:outline-none",
840
+ className: "flex size-full items-center justify-center outline-none focus-visible:outline-2 focus-visible:-outline-offset-2 focus-visible:outline-kit-focus-ring focus-visible:[outline-style:solid] [html[data-input-modality=pointer]_&]:focus-visible:outline-none",
541
841
  children: /* @__PURE__ */ jsx("img", {
542
842
  src: src(v.url),
543
843
  alt: alt ?? "",
544
- onLoad: (e) => {
545
- const img = e.currentTarget;
546
- if (img.naturalWidth && img.naturalHeight) setNatural({
547
- w: img.naturalWidth,
548
- h: img.naturalHeight
549
- });
550
- },
551
- className: "size-full object-cover",
552
- style: { objectPosition: `${focal.x}% ${focal.y}%` }
844
+ ref: readNatural,
845
+ onLoad: (e) => readNatural(e.currentTarget),
846
+ "data-fill": fit.fill,
847
+ "data-image-ratio": fit.image ?? void 0,
848
+ "data-cap": cap ? `${cap.w}x${cap.h}` : void 0,
849
+ className: FIT_CLASS[fit.fill],
850
+ style: fit.image ? {
851
+ aspectRatio: fit.image,
852
+ ...cap ? {
853
+ maxWidth: `min(100%, ${cap.w}px)`,
854
+ maxHeight: `min(100%, ${cap.h}px)`
855
+ } : {}
856
+ } : void 0
553
857
  })
554
858
  }),
555
859
  readOnly ? null : /* @__PURE__ */ jsxs("div", {
@@ -557,7 +861,7 @@ function ImageControl({ field, value, onChange: write, readOnly, id, path }) {
557
861
  children: [library ? /* @__PURE__ */ jsxs("button", {
558
862
  type: "button",
559
863
  onClick: library,
560
- className: PILL,
864
+ className: "flex h-7 items-center gap-1 rounded-full border border-kit-swatch-ring bg-kit-media-control px-2.5 text-kit-xs font-medium text-kit-media-control-fg shadow-kit-sm",
561
865
  children: [/* @__PURE__ */ jsx(IconReplace, {
562
866
  className: "size-3.5",
563
867
  stroke: 1.5,
@@ -569,7 +873,7 @@ function ImageControl({ field, value, onChange: write, readOnly, id, path }) {
569
873
  type: "button",
570
874
  "aria-label": "Remove image",
571
875
  onClick: () => onChange(null),
572
- className: cn(PILL, "size-7 justify-center px-0"),
876
+ className: "flex size-7 items-center justify-center rounded-full border border-kit-swatch-ring bg-kit-media-control text-kit-media-control-fg shadow-kit-sm",
573
877
  children: /* @__PURE__ */ jsx(IconX, {
574
878
  className: "size-3.5",
575
879
  stroke: 1.5,
@@ -634,22 +938,25 @@ function ImageControl({ field, value, onChange: write, readOnly, id, path }) {
634
938
  onClick: openDetails,
635
939
  children: "Alt text and details"
636
940
  }),
637
- library ? /* @__PURE__ */ jsx(MenuItem, {
941
+ /* @__PURE__ */ jsx(MenuItem, {
638
942
  icon: /* @__PURE__ */ jsx(IconReplace, { stroke: 1.5 }),
943
+ disabled: !library,
639
944
  onClick: library,
640
945
  children: "Replace"
641
- }) : null,
946
+ }),
642
947
  /* @__PURE__ */ jsx(MenuItem, {
643
948
  icon: /* @__PURE__ */ jsx(IconExternalLink, { stroke: 1.5 }),
644
949
  onClick: () => window.open(src(v.url), "_blank", "noopener"),
645
950
  children: "Open original"
646
951
  }),
647
- readOnly ? null : /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx(MenuSeparator, {}), /* @__PURE__ */ jsx(MenuItem, {
952
+ /* @__PURE__ */ jsx(MenuSeparator, {}),
953
+ /* @__PURE__ */ jsx(MenuItem, {
648
954
  danger: true,
649
955
  icon: /* @__PURE__ */ jsx(IconTrash, { stroke: 1.5 }),
650
- onClick: () => onChange(null),
956
+ disabled: readOnly,
957
+ onClick: () => !readOnly && onChange(null),
651
958
  children: "Remove"
652
- })] })
959
+ })
653
960
  ]
654
961
  })] })]
655
962
  }),
@@ -666,6 +973,7 @@ function ImageControl({ field, value, onChange: write, readOnly, id, path }) {
666
973
  readOnly,
667
974
  label: field.title,
668
975
  urlOnly,
976
+ altOnly,
669
977
  size,
670
978
  asset
671
979
  })
@@ -673,7 +981,7 @@ function ImageControl({ field, value, onChange: write, readOnly, id, path }) {
673
981
  /* @__PURE__ */ jsx(MediaPicker, {
674
982
  open: picker,
675
983
  onOpenChange: setPicker,
676
- accept: ["image", "svg"],
984
+ accept: kinds,
677
985
  onPick: (a) => a[0] && replace(a[0])
678
986
  })
679
987
  ]
@@ -686,10 +994,11 @@ function Thumb({ item, label, readOnly, sort, onRemove, onOpen }) {
686
994
  ref: sort.register(item.key),
687
995
  role: "listitem",
688
996
  style: sort.style(item.key),
689
- className: cn("group/thumb relative aspect-square overflow-hidden rounded-kit-md border border-kit-line bg-kit-muted", sort.active === item.key && "z-10 shadow-kit-lg ring-2 ring-kit-line-strong"),
997
+ className: cn("group/thumb relative aspect-square cursor-grab touch-none overflow-hidden rounded-kit-md border border-kit-line active:cursor-grabbing", CHECKER, sort.active === item.key && "z-10 opacity-90 shadow-kit-lg ring-2 ring-kit-line-strong"),
690
998
  children: [
691
999
  /* @__PURE__ */ jsx("div", {
692
1000
  ...readOnly ? {} : handle,
1001
+ role: void 0,
693
1002
  tabIndex: 0,
694
1003
  "aria-label": readOnly ? label : `${label}, drag to reorder`,
695
1004
  onDoubleClick: onOpen,
@@ -706,11 +1015,12 @@ function Thumb({ item, label, readOnly, sort, onRemove, onOpen }) {
706
1015
  }
707
1016
  if (!readOnly) handle.onKeyDown(e);
708
1017
  },
709
- className: cn("size-full touch-none outline-none focus-visible:outline-2 focus-visible:-outline-offset-2 focus-visible:outline-kit-focus-ring focus-visible:[outline-style:solid] [html[data-input-modality=pointer]_&]:focus-visible:outline-none", !readOnly && "cursor-grab active:cursor-grabbing"),
1018
+ className: "size-full outline-none focus-visible:outline-2 focus-visible:-outline-offset-2 focus-visible:outline-kit-focus-ring focus-visible:[outline-style:solid] [html[data-input-modality=pointer]_&]:focus-visible:outline-none",
710
1019
  children: /* @__PURE__ */ jsx("img", {
711
1020
  src: src(item.v.url),
712
1021
  alt: item.v.alt ?? "",
713
- className: "pointer-events-none size-full select-none object-cover",
1022
+ "data-slot": "kit-gallery-thumb",
1023
+ className: "pointer-events-none size-full select-none object-contain",
714
1024
  draggable: false
715
1025
  })
716
1026
  }),
@@ -721,10 +1031,13 @@ function Thumb({ item, label, readOnly, sort, onRemove, onOpen }) {
721
1031
  }) : null,
722
1032
  readOnly ? null : /* @__PURE__ */ jsx("button", {
723
1033
  type: "button",
724
- "aria-label": `Remove ${label}`,
1034
+ "aria-label": (() => {
1035
+ const what = item.v.alt || item.v.name || fileNameFromUrl(item.v.url);
1036
+ return what ? `Remove ${what}` : "Remove image";
1037
+ })(),
725
1038
  onPointerDown: (e) => e.stopPropagation(),
726
1039
  onClick: onRemove,
727
- className: "absolute right-1 top-1 flex size-6 items-center justify-center rounded-kit-md bg-kit-inverse/80 text-kit-fg-inverse opacity-0 transition-opacity focus-visible:opacity-100 group-hover/thumb:opacity-100 [@media(pointer:coarse)]:opacity-100",
1040
+ className: "absolute right-1 top-1 flex size-6 items-center justify-center rounded-kit-md bg-kit-inverse/80 text-kit-fg-inverse opacity-0 transition-opacity focus-visible:opacity-100 group-hover/thumb:opacity-100 pointer-coarse:opacity-100",
728
1041
  children: /* @__PURE__ */ jsx(IconX, {
729
1042
  className: "size-3.5",
730
1043
  stroke: 1.5,
@@ -735,8 +1048,9 @@ function Thumb({ item, label, readOnly, sort, onRemove, onOpen }) {
735
1048
  });
736
1049
  }
737
1050
  /** An array of images: a sortable grid of tiles with a dashed "Add images" tile last (hidden at `max`). */
738
- function GalleryControl({ value, onChange, readOnly, field, id }) {
1051
+ function GalleryControl({ value, onChange, readOnly, field, id, path }) {
739
1052
  const { s, src } = useMedia();
1053
+ const env = useKitEnv();
740
1054
  const raw = Array.isArray(value) ? value : [];
741
1055
  const seen = /* @__PURE__ */ new Map();
742
1056
  const items = raw.map((x) => {
@@ -756,7 +1070,8 @@ function GalleryControl({ value, onChange, readOnly, field, id }) {
756
1070
  const add = (assets) => write([...raw, ...assets.map((a) => out(fromAsset(a)))]);
757
1071
  const [picker, setPicker] = React.useState(false);
758
1072
  const up = useUpload("image/*", "image", add);
759
- const sort = useDragReorder(items.map((it) => it.key), (from, to) => {
1073
+ const keys = items.map((it) => it.key);
1074
+ const sort = useDragReorder(keys, (from, to) => {
760
1075
  const next = [...raw];
761
1076
  const [moved] = next.splice(from, 1);
762
1077
  next.splice(to, 0, moved);
@@ -781,7 +1096,11 @@ function GalleryControl({ value, onChange, readOnly, field, id }) {
781
1096
  label: noun(i, it),
782
1097
  readOnly,
783
1098
  sort,
784
- onOpen: () => window.open(src(it.v.url), "_blank", "noopener"),
1099
+ onOpen: () => s.editImage && !readOnly ? s.editImage({
1100
+ docId: env.docId,
1101
+ path: [...path, i],
1102
+ title: noun(i, it)
1103
+ }) : window.open(src(it.v.url), "_blank", "noopener"),
785
1104
  onRemove: () => write(raw.filter((_, j) => j !== i))
786
1105
  }, it.key)), canAdd ? /* @__PURE__ */ jsx("div", {
787
1106
  role: "listitem",
@@ -894,58 +1213,59 @@ function FileControl({ value, onChange, readOnly, id }) {
894
1213
  const ext = (name.includes(".") ? name.split(".").pop() : "")?.toUpperCase() || "FILE";
895
1214
  const meta = [ext.toLowerCase(), asset?.size ? formatBytes(asset.size) : null].filter(Boolean).join(" · ");
896
1215
  return /* @__PURE__ */ jsxs("div", {
897
- className: "flex flex-col gap-1.5",
898
- children: [/* @__PURE__ */ jsxs("div", {
899
- className: "flex items-center gap-3 rounded-kit-lg border border-kit-line bg-kit-control-bg p-2",
900
- children: [
901
- /* @__PURE__ */ jsx("span", {
902
- "aria-hidden": true,
903
- className: "flex size-14 shrink-0 items-center justify-center rounded-kit-md border border-kit-line bg-kit-subtle font-kit-mono text-kit-2xs font-medium text-kit-fg-2",
904
- children: ext
905
- }),
906
- /* @__PURE__ */ jsxs("div", {
907
- className: "min-w-0 flex-1",
908
- children: [/* @__PURE__ */ jsx("a", {
909
- id,
910
- href: src(v.url),
911
- target: "_blank",
912
- rel: "noreferrer",
913
- className: "block truncate text-kit-sm font-medium text-kit-accent-fg hover:underline",
914
- children: name
915
- }), /* @__PURE__ */ jsx("div", {
916
- className: "text-kit-xs text-kit-fg-3",
917
- children: meta
918
- })]
1216
+ className: "flex items-center gap-3 rounded-kit-lg border border-kit-line bg-kit-control-bg p-2",
1217
+ children: [
1218
+ /* @__PURE__ */ jsx("span", {
1219
+ "aria-hidden": true,
1220
+ className: "flex size-14 shrink-0 items-center justify-center rounded-kit-md border border-kit-line bg-kit-subtle font-kit-mono text-kit-2xs font-medium text-kit-fg-2",
1221
+ children: ext
1222
+ }),
1223
+ /* @__PURE__ */ jsxs("div", {
1224
+ className: "min-w-0 flex-1",
1225
+ children: [/* @__PURE__ */ jsx("a", {
1226
+ id,
1227
+ href: src(v.url),
1228
+ target: "_blank",
1229
+ rel: "noreferrer",
1230
+ className: "block truncate text-kit-sm font-medium text-kit-accent-fg hover:underline",
1231
+ children: name
1232
+ }), /* @__PURE__ */ jsx("div", {
1233
+ className: "text-kit-xs text-kit-fg-3",
1234
+ children: meta
1235
+ })]
1236
+ }),
1237
+ library ? /* @__PURE__ */ jsx(Button, {
1238
+ size: "sm",
1239
+ variant: "ghost",
1240
+ onClick: library,
1241
+ children: "Replace"
1242
+ }) : null,
1243
+ /* @__PURE__ */ jsxs(Menu, { children: [/* @__PURE__ */ jsx(MenuTrigger, {
1244
+ render: /* @__PURE__ */ jsx(IconButton, {
1245
+ label: "File actions",
1246
+ size: "sm"
919
1247
  }),
920
- library ? /* @__PURE__ */ jsx(Button, {
921
- size: "sm",
922
- variant: "ghost",
923
- onClick: library,
924
- children: "Replace"
925
- }) : null,
926
- /* @__PURE__ */ jsxs(Menu, { children: [/* @__PURE__ */ jsx(MenuTrigger, {
927
- "aria-label": "File actions",
928
- className: "flex size-7 shrink-0 items-center justify-center rounded-kit-md text-kit-fg-3 hover:bg-kit-hover hover:text-kit-fg data-[popup-open]:bg-kit-hover",
929
- children: /* @__PURE__ */ jsx(IconDots, {
930
- className: "size-4",
931
- stroke: 1.5,
932
- "aria-hidden": true
933
- })
934
- }), /* @__PURE__ */ jsxs(MenuContent, {
935
- align: "end",
936
- children: [/* @__PURE__ */ jsx(MenuItem, {
1248
+ children: /* @__PURE__ */ jsx(IconDots, { stroke: 1.5 })
1249
+ }), /* @__PURE__ */ jsxs(MenuContent, {
1250
+ align: "end",
1251
+ children: [
1252
+ /* @__PURE__ */ jsx(MenuItem, {
937
1253
  icon: /* @__PURE__ */ jsx(IconDownload, { stroke: 1.5 }),
938
1254
  onClick: () => window.open(src(v.url), "_blank", "noopener"),
939
1255
  children: "Open"
940
- }), readOnly ? null : /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx(MenuSeparator, {}), /* @__PURE__ */ jsx(MenuItem, {
1256
+ }),
1257
+ /* @__PURE__ */ jsx(MenuSeparator, {}),
1258
+ /* @__PURE__ */ jsx(MenuItem, {
941
1259
  danger: true,
942
1260
  icon: /* @__PURE__ */ jsx(IconTrash, { stroke: 1.5 }),
943
- onClick: () => onChange(null),
1261
+ disabled: readOnly,
1262
+ onClick: () => !readOnly && onChange(null),
944
1263
  children: "Remove"
945
- })] })]
946
- })] })
947
- ]
948
- }), pickerEl]
1264
+ })
1265
+ ]
1266
+ })] }),
1267
+ pickerEl
1268
+ ]
949
1269
  });
950
1270
  }
951
1271
  var videoProvider = (url) => /youtu/.test(url) ? "YouTube" : /vimeo/.test(url) ? "Vimeo" : /loom/.test(url) ? "Loom" : /\.(mp4|webm|mov)(\?|$)/i.test(url) ? "MP4" : url ? "Link" : "";
@@ -968,11 +1288,11 @@ function VideoPreview({ url, poster, title }) {
968
1288
  poster: thumb,
969
1289
  controls: true,
970
1290
  autoPlay: true,
971
- className: "aspect-video w-full rounded-kit-lg border border-kit-line bg-kit-inverse"
1291
+ className: "aspect-video w-full rounded-kit-lg border border-kit-line bg-kit-media-backdrop"
972
1292
  });
973
1293
  const playable = !!yt || isFileVideo(url);
974
1294
  return /* @__PURE__ */ jsxs("div", {
975
- className: "relative aspect-video overflow-hidden rounded-kit-lg border border-kit-line bg-kit-inverse",
1295
+ className: "relative aspect-video overflow-hidden rounded-kit-lg border border-kit-line bg-kit-media-backdrop",
976
1296
  children: [
977
1297
  thumb ? /* @__PURE__ */ jsx("img", {
978
1298
  src: thumb,
@@ -983,7 +1303,7 @@ function VideoPreview({ url, poster, title }) {
983
1303
  type: "button",
984
1304
  "aria-label": playable ? "Play preview" : "Open video link",
985
1305
  onClick: () => playable ? setPlaying(true) : window.open(src(url), "_blank", "noopener"),
986
- className: "absolute inset-0 m-auto flex size-12 items-center justify-center rounded-full bg-kit-control-bg text-kit-fg shadow-kit-lg transition-transform hover:scale-105",
1306
+ className: "absolute inset-0 m-auto flex size-12 items-center justify-center rounded-full bg-kit-media-control text-kit-media-control-fg shadow-kit-lg transition-transform hover:scale-105",
987
1307
  children: playable ? /* @__PURE__ */ jsx(IconPlayerPlay, {
988
1308
  className: "size-5",
989
1309
  stroke: 1.5,
@@ -995,7 +1315,7 @@ function VideoPreview({ url, poster, title }) {
995
1315
  })
996
1316
  }),
997
1317
  /* @__PURE__ */ jsxs("span", {
998
- className: "absolute left-2 top-2 inline-flex items-center gap-1 rounded-kit-md bg-kit-inverse/70 px-1.5 py-0.5 text-kit-xs text-kit-fg-inverse",
1318
+ className: "absolute left-2 top-2 inline-flex items-center gap-1 rounded-kit-md bg-kit-scrim px-1.5 py-0.5 text-kit-xs text-kit-on-scrim",
999
1319
  children: [/* @__PURE__ */ jsx(IconVideo, {
1000
1320
  className: "size-3.5",
1001
1321
  stroke: 1.5,
@@ -1071,6 +1391,6 @@ function VideoControl({ field, value, onChange, readOnly, id, onBlur }) {
1071
1391
  });
1072
1392
  }
1073
1393
  //#endregion
1074
- export { FileControl, GalleryControl, ImageControl, VideoControl };
1394
+ export { FileControl, GalleryControl, ImageControl, MediaPicker, VideoControl, VideoPreview, acceptsFile, cropChoice, fileNameFromUrl, formatBytes, frameFit, fromAsset, isVideoUrl, normImage, useUpload, videoProvider, withCrop, youTubeId };
1075
1395
 
1076
1396
  //# sourceMappingURL=media.js.map