@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":"link-form.js","names":[],"sources":["../../../src/controls/rich-text/link-form.tsx"],"sourcesContent":["/**\n * RICH TEXT · the link popover's body for a link inside the text, in V2's link panel chrome (controls/link.tsx\n * LinkPopoverBody: what it links to now · the address · Remove link · Cancel · Apply): the address, and \"Open in new tab\"\n * when the field allows it. A text link stores its address and target only (production's link mark), so V2's link type\n * select and rel choice, which belong to the link FIELD, are not offered here.\n */\nimport * as React from \"react\";\nimport { IconLink } from \"@tabler/icons-react\";\nimport { Button } from \"../../ui/button\";\nimport { Switch } from \"../../ui/controls\";\nimport { Input } from \"../../ui/input\";\nimport { LinkLine, normLink } from \"../link\";\n\nexport interface TextLink {\n href: string;\n newTab?: boolean;\n}\n\n/** An address a link may carry: http(s), mailto, tel, a site path or an in-page anchor. */\nexport function linkProblem(href: string): string | null {\n const h = href.trim();\n if (!h) return \"Add an address first.\";\n if (/^(https?:\\/\\/[^\\s]+|mailto:[^\\s]+|tel:[+\\d][\\d\\s()-]*|\\/(?!\\/)[^\\s]*|#[^\\s]+)$/i.test(h)) return null;\n if (/^[a-z][a-z0-9+.-]*:/i.test(h)) return \"Use an address that starts with https://, mailto: or tel:.\";\n if (/^[^\\s/]+\\.[^\\s]+$/.test(h)) return `Add https:// in front: https://${h}`;\n return \"Use a full address (https://…), a page path (/about) or an anchor (#section).\";\n}\n\nexport function LinkForm({\n initial,\n allowNewTab,\n onSave,\n onCancel,\n onDetach,\n}: {\n initial: TextLink;\n allowNewTab: boolean;\n onSave: (v: TextLink) => void;\n onCancel: () => void;\n onDetach?: () => void;\n}) {\n const [href, setHref] = React.useState(initial.href);\n const [newTab, setNewTab] = React.useState(!!initial.newTab);\n const [problem, setProblem] = React.useState<string | null>(null);\n const urlId = React.useId();\n const tabId = React.useId();\n const errId = React.useId();\n const start = initial.href.trim();\n // V2 LinkPopoverBody (controls/link.tsx): Apply only when something changed and the link can be saved\n const changed = href.trim() !== start || (allowNewTab && newTab !== !!initial.newTab);\n const ok = !linkProblem(href);\n return (\n <form\n className=\"flex flex-col gap-3\"\n onSubmit={(e) => {\n e.preventDefault();\n const p = linkProblem(href);\n setProblem(p);\n if (!p) onSave({ href: href.trim(), newTab: allowNewTab && newTab });\n }}\n >\n <div className=\"flex min-w-0 flex-col gap-1\">\n <span className=\"text-kit-sm font-medium text-kit-fg\">Link</span>\n {start ? (\n <span className=\"flex min-w-0 text-kit-fg-2\">\n <LinkLine v={normLink({ href: start, newTab: !!initial.newTab })} />\n </span>\n ) : (\n <span className=\"text-kit-xs text-kit-fg-3\">No link yet</span>\n )}\n </div>\n <div\n className=\"flex flex-col gap-1.5\"\n onBlur={(e) => {\n if (!e.currentTarget.contains(e.relatedTarget as Node) && href.trim()) setProblem(linkProblem(href));\n }}\n >\n <label htmlFor={urlId} className=\"text-kit-xs text-kit-fg-2\">\n Link to\n </label>\n <Input\n id={urlId}\n autoFocus\n size=\"sm\"\n value={href}\n onChange={(e) => {\n setHref(e.target.value);\n if (problem) setProblem(null);\n }}\n onKeyDown={(e) => {\n // Apply is disabled while the address cannot be saved, so Enter says why instead of doing nothing\n if (e.key === \"Enter\" && !ok) {\n e.preventDefault();\n setProblem(linkProblem(href));\n }\n }}\n placeholder=\"https://… or /page\"\n leading={<IconLink stroke={1.5} />}\n aria-invalid={problem ? true : undefined}\n aria-describedby={problem ? errId : undefined}\n />\n {problem ? (\n <p id={errId} role=\"alert\" className=\"text-kit-xs text-kit-danger-fg\">\n {problem}\n </p>\n ) : null}\n </div>\n {allowNewTab ? (\n <label htmlFor={tabId} className=\"flex min-h-7 items-center justify-between gap-3\">\n <span className=\"text-kit-xs text-kit-fg-2\">Open in new tab</span>\n <Switch id={tabId} size=\"sm\" checked={newTab} onCheckedChange={setNewTab} />\n </label>\n ) : null}\n <div className=\"flex items-center gap-2 border-t border-kit-line pt-2.5\">\n {onDetach ? (\n <Button type=\"button\" size=\"xs\" variant=\"danger-ghost\" onClick={onDetach}>\n Remove link\n </Button>\n ) : null}\n <span className=\"flex-1\" />\n <Button type=\"button\" size=\"xs\" variant=\"ghost\" onClick={onCancel}>\n Cancel\n </Button>\n <Button type=\"submit\" size=\"xs\" variant=\"primary\" disabled={!changed || !ok}>\n Apply\n </Button>\n </div>\n </form>\n );\n}\n"],"mappings":"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"}
@@ -1,5 +1,5 @@
1
1
  import { esc, escAttr, sanitize } from "./dom.js";
2
- //#region src/kit/controls/rich-text/markdown.ts
2
+ //#region src/controls/rich-text/markdown.ts
3
3
  /**
4
4
  * RICH TEXT · a small HTML ⇄ Markdown converter for the field's Markdown mode and for pasting (V2 HEAD
5
5
  * controls/rich-text/markdown.ts). Covers headings, bold/italic/strike/underline, inline code, links, images, lists,
@@ -31,6 +31,8 @@ function inline(node, inCode = false) {
31
31
  case "STRIKE":
32
32
  case "DEL": return wrap("~~");
33
33
  case "U": return `<u>${kids()}</u>`;
34
+ case "SUP": return el.matches("[data-footnote]") || el.querySelector(":scope > a[href*='-fn-']") ? kids() : `<sup>${kids()}</sup>`;
35
+ case "SUB": return `<sub>${kids()}</sub>`;
34
36
  case "CODE": return "`" + (el.textContent ?? "").replace(/`/g, "") + "`";
35
37
  case "BR": return " \n";
36
38
  case "IMG": return `![${el.getAttribute("alt") ?? ""}](${el.getAttribute("src") ?? ""})`;
@@ -174,6 +176,6 @@ function markdownToHtml(md) {
174
176
  /** Does pasted plain text look like Markdown worth converting into blocks? */
175
177
  var looksLikeMarkdown = (t) => /\n\s*\n/.test(t) || /^(#{1,6}\s|[-*+]\s|\d+[.)]\s|>\s|```|---)/m.test(t) || /\*\*[^*]+\*\*|\[[^\]]+\]\([^)]+\)/.test(t);
176
178
  //#endregion
177
- export { htmlToMarkdown, looksLikeMarkdown, markdownToHtml };
179
+ export { htmlToMarkdown, inlineMd, looksLikeMarkdown, markdownToHtml };
178
180
 
179
181
  //# sourceMappingURL=markdown.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"markdown.js","names":[],"sources":["../../../src/controls/rich-text/markdown.ts"],"sourcesContent":["/**\n * RICH TEXT · a small HTML ⇄ Markdown converter for the field's Markdown mode and for pasting (V2 HEAD\n * controls/rich-text/markdown.ts). Covers headings, bold/italic/strike/underline, inline code, links, images, lists,\n * quotes, code blocks, rules and paragraphs. Anything else is kept as one line of raw HTML, which the reverse direction\n * passes through untouched (and the field's own rules then decide whether it may stay).\n */\nimport { esc, escAttr, sanitize } from \"./dom\";\n\n/* ── HTML → Markdown ───────────────────────────────────────────────── */\nconst escText = (s: string) => s.replace(/([\\\\`*[\\]~])/g, \"\\\\$1\");\n\nfunction inline(node: Node, inCode = false): string {\n if (node.nodeType === 3) {\n const t = (node.textContent ?? \"\").replace(/ /g, \" \");\n return inCode ? t : escText(t.replace(/\\s+/g, \" \"));\n }\n if (node.nodeType !== 1) return \"\";\n const el = node as HTMLElement;\n const kids = () => Array.from(el.childNodes).map((c) => inline(c, inCode)).join(\"\");\n const wrap = (mark: string) => {\n const inner = kids();\n if (!inner.trim()) return inner;\n const lead = inner.match(/^\\s*/)![0];\n const trail = inner.match(/\\s*$/)![0];\n return `${lead}${mark}${inner.trim()}${mark}${trail}`;\n };\n switch (el.tagName) {\n case \"STRONG\":\n case \"B\":\n return wrap(\"**\");\n case \"EM\":\n case \"I\":\n return wrap(\"_\");\n case \"S\":\n case \"STRIKE\":\n case \"DEL\":\n return wrap(\"~~\");\n case \"U\":\n return `<u>${kids()}</u>`;\n // footnote markers are written elsewhere; a plain x² / x₂ stays inline HTML, which Markdown allows\n case \"SUP\":\n return el.matches(\"[data-footnote]\") || el.querySelector(\":scope > a[href*='-fn-']\") ? kids() : `<sup>${kids()}</sup>`;\n case \"SUB\":\n return `<sub>${kids()}</sub>`;\n case \"CODE\":\n return \"`\" + (el.textContent ?? \"\").replace(/`/g, \"\") + \"`\";\n case \"BR\":\n return \" \\n\";\n case \"IMG\":\n return `![${el.getAttribute(\"alt\") ?? \"\"}](${el.getAttribute(\"src\") ?? \"\"})`;\n case \"A\":\n // a link that carries more than its address (opens in a new tab) keeps its markup, so Markdown mode drops nothing\n if (el.hasAttribute(\"target\")) return el.outerHTML;\n return `[${kids()}](${el.getAttribute(\"href\") ?? \"\"})`;\n default:\n return kids();\n }\n}\n\nfunction list(el: HTMLElement): string | null {\n if (el.querySelector(\"ul ul, ul ol, ol ol, ol ul, li > p + p\")) return null;\n return Array.from(el.children)\n .filter((li) => li.tagName === \"LI\")\n .map((li, i) => (el.tagName === \"OL\" ? `${i + 1}. ` : \"- \") + inline(li).trim().replace(/ {2}\\n/g, \" \"))\n .join(\"\\n\");\n}\n\nexport function htmlToMarkdown(html: string): string {\n const doc = new DOMParser().parseFromString(`<body>${html}</body>`, \"text/html\");\n const out: string[] = [];\n for (const node of Array.from(doc.body.childNodes)) {\n if (node.nodeType === 3) {\n const t = inline(node).trim();\n if (t) out.push(t);\n continue;\n }\n if (node.nodeType !== 1) continue;\n const el = node as HTMLElement;\n const tag = el.tagName;\n const raw = () => out.push(el.outerHTML.replace(/\\n+/g, \" \"));\n if (/^H[1-6]$/.test(tag)) out.push(`${\"#\".repeat(Number(tag[1]))} ${inline(el).trim()}`);\n else if (tag === \"P\") {\n const s = inline(el).trim().replace(/^([#>]|\\d+\\.|[-+] |-{3})/, \"\\\\$1\");\n if (s) out.push(s);\n } else if (tag === \"UL\" || tag === \"OL\") {\n const l = list(el);\n if (l === null) raw();\n else out.push(l);\n } else if (tag === \"BLOCKQUOTE\") {\n const paras = el.querySelector(\"p,div\") ? Array.from(el.children).map((c) => inline(c).trim()) : [inline(el).trim()];\n out.push(paras.filter(Boolean).map((p) => p.split(\"\\n\").map((l) => `> ${l}`).join(\"\\n\")).join(\"\\n>\\n\"));\n } else if (tag === \"PRE\") out.push(\"```\\n\" + (el.textContent ?? \"\").replace(/\\n$/, \"\") + \"\\n```\");\n else if (tag === \"HR\") out.push(\"---\");\n else if (tag === \"FIGURE\" && el.querySelector(\":scope > img\")) {\n const img = el.querySelector(\"img\")!;\n const cap = el.querySelector(\"figcaption\")?.textContent?.trim();\n out.push(`![${img.getAttribute(\"alt\") ?? \"\"}](${img.getAttribute(\"src\") ?? \"\"}${cap ? ` \"${cap.replace(/\"/g, \"'\")}\"` : \"\"})`);\n } else raw();\n }\n return out.join(\"\\n\\n\") + (out.length ? \"\\n\" : \"\");\n}\n\n/* ── Markdown → HTML ───────────────────────────────────────────────── */\nconst safeHref = (h: string) => (/^\\s*(javascript|vbscript|data:text)/i.test(h) ? \"#\" : h);\n\nexport function inlineMd(src: string): string {\n const slots: string[] = [];\n const hold = (html: string) => `\\u0000${slots.push(html) - 1}\\u0000`;\n let s = src.replace(/\\\\([\\\\`*_[\\]~#>+\\-.!])/g, (_, c: string) => hold(esc(c)));\n s = s.replace(/`([^`]+)`/g, (_, c: string) => hold(`<code>${esc(c)}</code>`));\n s = s.replace(/<a [^>]*>.*?<\\/a>/g, (m) => hold(m));\n s = esc(s);\n s = s.replace(/&lt;(\\/?)u&gt;/g, \"<$1u>\");\n s = s.replace(/!\\[([^\\]]*)\\]\\(([^)\\s]+)\\)/g, (_, a: string, u: string) => hold(`<img src=\"${escAttr(safeHref(u))}\" alt=\"${escAttr(a)}\">`));\n s = s.replace(/\\[([^\\]]+)\\]\\(([^)\\s]+)\\)/g, (_, t: string, u: string) => `<a href=\"${escAttr(safeHref(u))}\">${t}</a>`);\n s = s.replace(/\\*\\*([^*]+?)\\*\\*/g, \"<strong>$1</strong>\");\n s = s.replace(/__([^_]+?)__/g, \"<strong>$1</strong>\");\n s = s.replace(/(^|[^\\w*])\\*([^*\\s][^*]*?)\\*(?!\\*)/g, \"$1<em>$2</em>\");\n s = s.replace(/(^|[^\\w])_([^_\\s][^_]*?)_(?!\\w)/g, \"$1<em>$2</em>\");\n s = s.replace(/~~([^~]+?)~~/g, \"<s>$1</s>\");\n s = s.replace(/ {2,}\\n/g, \"<br>\").replace(/\\n/g, \" \");\n return s.replace(/\\u0000(\\d+)\\u0000/g, (_, i: string) => slots[Number(i)]);\n}\n\nconst RAW_BLOCK = /^<\\/?(div|table|figure|details|ul|ol|p|h[1-6]|blockquote|pre|hr|section|aside)\\b/i;\nconst RE = {\n fence: /^\\s*```/,\n heading: /^(#{1,6})\\s+(.*?)\\s*#*\\s*$/,\n hr: /^\\s*(-{3,}|\\*{3,}|_{3,})\\s*$/,\n image: /^!\\[([^\\]]*)\\]\\(([^)\\s]+)(?:\\s+\"([^\"]*)\")?\\)\\s*$/,\n quote: /^\\s*>/,\n ul: /^\\s*[-*+]\\s+(.*)$/,\n ol: /^\\s*\\d+[.)]\\s+(.*)$/,\n};\nconst startsBlock = (l: string) => RE.fence.test(l) || RE.heading.test(l) || RE.hr.test(l) || RE.quote.test(l) || RE.ul.test(l) || RE.ol.test(l) || RAW_BLOCK.test(l.trim());\n\n/** Throws on Markdown it cannot read (e.g. an unclosed code fence). */\nexport function markdownToHtml(md: string): string {\n const lines = md.replace(/\\r\\n?/g, \"\\n\").split(\"\\n\");\n const out: string[] = [];\n let i = 0;\n while (i < lines.length) {\n const line = lines[i];\n if (!line.trim()) {\n i++;\n continue;\n }\n if (RE.fence.test(line)) {\n const code: string[] = [];\n i++;\n while (i < lines.length && !RE.fence.test(lines[i])) code.push(lines[i++]);\n if (i >= lines.length) throw new Error(\"Unclosed code block\");\n i++;\n out.push(`<pre>${esc(code.join(\"\\n\"))}</pre>`);\n continue;\n }\n if (RAW_BLOCK.test(line.trim())) {\n const raw: string[] = [];\n while (i < lines.length && lines[i].trim()) raw.push(lines[i++]);\n out.push(raw.join(\" \"));\n continue;\n }\n let m = line.match(RE.heading);\n if (m) {\n out.push(`<h${m[1].length}>${inlineMd(m[2])}</h${m[1].length}>`);\n i++;\n continue;\n }\n if (RE.hr.test(line)) {\n out.push(\"<hr>\");\n i++;\n continue;\n }\n m = line.match(RE.image);\n if (m) {\n // an image keeps no caption in production rich text: a title becomes the line under it, never dropped\n out.push(`<figure><img src=\"${escAttr(safeHref(m[2]))}\" alt=\"${escAttr(m[1])}\"></figure>${m[3] ? `<p>${esc(m[3])}</p>` : \"\"}`);\n i++;\n continue;\n }\n if (RE.quote.test(line)) {\n const q: string[] = [];\n while (i < lines.length && RE.quote.test(lines[i])) q.push(lines[i++].replace(/^\\s*> ?/, \"\"));\n out.push(`<blockquote>${q.join(\"\\n\").split(/\\n\\s*\\n/).map(inlineMd).join(\"<br><br>\")}</blockquote>`);\n continue;\n }\n if (RE.ul.test(line) || RE.ol.test(line)) {\n const ordered = !RE.ul.test(line);\n const re = ordered ? RE.ol : RE.ul;\n const items: string[] = [];\n while (i < lines.length && re.test(lines[i])) items.push(`<li>${inlineMd(lines[i++].match(re)![1])}</li>`);\n out.push(ordered ? `<ol>${items.join(\"\")}</ol>` : `<ul>${items.join(\"\")}</ul>`);\n continue;\n }\n const para: string[] = [];\n while (i < lines.length && lines[i].trim() && (para.length === 0 || !startsBlock(lines[i]))) para.push(lines[i++]);\n out.push(`<p>${inlineMd(para.join(\"\\n\"))}</p>`);\n }\n return sanitize(out.join(\"\"));\n}\n\n/** Does pasted plain text look like Markdown worth converting into blocks? */\nexport const looksLikeMarkdown = (t: string) => /\\n\\s*\\n/.test(t) || /^(#{1,6}\\s|[-*+]\\s|\\d+[.)]\\s|>\\s|```|---)/m.test(t) || /\\*\\*[^*]+\\*\\*|\\[[^\\]]+\\]\\([^)]+\\)/.test(t);\n"],"mappings":"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"}
@@ -1,5 +1,5 @@
1
1
  import { cloneModel, closestBlock, createIsland, defaultModel, esc, placeCaret, textBeforeCaret, topBlock } from "./dom.js";
2
- //#region src/kit/controls/rich-text/ops.ts
2
+ //#region src/controls/rich-text/ops.ts
3
3
  /**
4
4
  * RICH TEXT · pure DOM block operations on the editor surface (V2 HEAD controls/rich-text/ops.ts; no React, no
5
5
  * emitting). The editor wraps each one, then serializes and emits the new value.
@@ -285,20 +285,22 @@ function restrictHtml(html, allows) {
285
285
  const mark = MARK_FEATURE[ch.tagName];
286
286
  const block = BLOCK_FEATURE[ch.tagName];
287
287
  if (mark && !allows(mark)) ch.replaceWith(...Array.from(ch.childNodes));
288
- else if (block && !allows(block)) if (block === "hr" || block === "image") {
289
- dropped.add(FEATURE_WORD[block]);
290
- ch.remove();
291
- } else if (block === "ul" || block === "ol") {
292
- const ps = Array.from(ch.children).map((li) => {
288
+ else if (block && !allows(block)) {
289
+ if (block === "hr" || block === "image") {
290
+ dropped.add(FEATURE_WORD[block]);
291
+ ch.remove();
292
+ } else if (block === "ul" || block === "ol") {
293
+ const ps = Array.from(ch.children).map((li) => {
294
+ const p = doc.createElement("p");
295
+ p.innerHTML = li.innerHTML;
296
+ return p;
297
+ });
298
+ ch.replaceWith(...ps);
299
+ } else {
293
300
  const p = doc.createElement("p");
294
- p.innerHTML = li.innerHTML;
295
- return p;
296
- });
297
- ch.replaceWith(...ps);
298
- } else {
299
- const p = doc.createElement("p");
300
- p.innerHTML = block === "pre" ? esc(ch.textContent ?? "").replace(/\n/g, "<br>") : ch.innerHTML;
301
- ch.replaceWith(p);
301
+ p.innerHTML = block === "pre" ? esc(ch.textContent ?? "").replace(/\n/g, "<br>") : ch.innerHTML;
302
+ ch.replaceWith(p);
303
+ }
302
304
  }
303
305
  }
304
306
  };
@@ -309,6 +311,6 @@ function restrictHtml(html, allows) {
309
311
  };
310
312
  }
311
313
  //#endregion
312
- export { duplicateBlock, ensureLineAfter, insertBasic, insertIsland, liveInlineCode, liveMarkdown, moveBlock, restrictHtml, turnInto };
314
+ export { duplicateBlock, ensureLineAfter, insertBasic, insertIsland, liveInlineCode, liveMarkdown, moveBlock, restrictHtml, takeEmptyBlock, turnInto };
313
315
 
314
316
  //# sourceMappingURL=ops.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ops.js","names":[],"sources":["../../../src/controls/rich-text/ops.ts"],"sourcesContent":["/**\n * RICH TEXT · pure DOM block operations on the editor surface (V2 HEAD controls/rich-text/ops.ts; no React, no\n * emitting). The editor wraps each one, then serializes and emits the new value.\n */\nimport { closestBlock, cloneModel, createIsland, defaultModel, esc, placeCaret, textBeforeCaret, topBlock, type IslandEl, type IslandKind, type IslandModels } from \"./dom\";\nimport type { RichTextFeature } from \"./codec\";\nimport type { BasicId } from \"./catalog\";\n\nconst emptyP = () => {\n const p = document.createElement(\"p\");\n p.innerHTML = \"<br>\";\n return p;\n};\nconst isWritable = (el: Element | null): el is HTMLElement => !!el && !el.hasAttribute(\"data-rt-island\") && el.tagName !== \"HR\";\n\n/** The writable line after a block, created when the block is last or followed by another rich block. */\nexport function ensureLineAfter(b: Element): HTMLElement {\n const next = b.nextElementSibling;\n if (isWritable(next)) return next;\n const p = emptyP();\n b.after(p);\n return p;\n}\n\nexport function duplicateBlock(b: HTMLElement): HTMLElement {\n let c: HTMLElement;\n if (b.hasAttribute(\"data-rt-island\")) {\n const k = b.getAttribute(\"data-rt-island\") as IslandKind;\n c = createIsland(k, cloneModel(k, (b as IslandEl).__rt as never));\n } else {\n c = b.cloneNode(true) as HTMLElement;\n c.removeAttribute(\"data-hint\");\n }\n b.after(c);\n return c;\n}\n\n/** Moves a block one step, keeping the caret where it was. Returns false at the edge. */\nexport function moveBlock(b: HTMLElement, dir: -1 | 1): boolean {\n const sib = dir < 0 ? b.previousElementSibling : b.nextElementSibling;\n if (!sib) return false;\n const s = window.getSelection();\n // ranges are live (a move collapses them), so keep the raw caret position\n const at = s && s.rangeCount ? { n: s.getRangeAt(0).startContainer, o: s.getRangeAt(0).startOffset } : null;\n const host = document.activeElement as HTMLElement | null;\n if (dir < 0) sib.before(b);\n else sib.after(b);\n if (at && s && b.contains(at.n)) {\n host?.focus({ preventScroll: true });\n const r = document.createRange();\n r.setStart(at.n, Math.min(at.o, at.n.nodeType === 3 ? (at.n as Text).length : at.n.childNodes.length));\n r.collapse(true);\n s.removeAllRanges();\n s.addRange(r);\n }\n return true;\n}\n\n/** Text / Heading / Quote / Code. Returns the new element, or null when nothing changed. */\nexport function turnInto(root: HTMLElement, b: HTMLElement | null, tag: string): HTMLElement | null {\n if (!b || b.parentNode !== root || b.hasAttribute(\"data-rt-island\") || b.tagName === \"HR\") return null;\n if (b.tagName.toLowerCase() === tag) return null;\n const inner =\n b.tagName === \"UL\" || b.tagName === \"OL\"\n ? Array.from(b.children).map((c) => c.innerHTML).join(\"<br>\")\n : b.tagName === \"PRE\"\n ? esc(b.textContent ?? \"\").replace(/\\n/g, \"<br>\")\n : b.innerHTML;\n const n = document.createElement(tag);\n n.innerHTML = tag === \"pre\" ? esc((b.textContent ?? \"\").replace(/​/g, \"\")) || \"<br>\" : inner || \"<br>\";\n b.replaceWith(n);\n root.focus({ preventScroll: true });\n placeCaret(n);\n return n;\n}\n\n/** An empty paragraph at the caret to build a block from (reuses the current one when it is empty). */\nexport function takeEmptyBlock(root: HTMLElement): HTMLElement {\n const s = window.getSelection();\n const anchor = s && s.rangeCount && root.contains(s.anchorNode) ? s.anchorNode : null;\n const li = anchor ? closestBlock(root, anchor) : null;\n let b = topBlock(root, anchor);\n if (li && li.tagName === \"LI\" && !li.textContent?.trim()) {\n const list = li.parentElement!;\n li.remove();\n if (!list.children.length) {\n const p = emptyP();\n list.replaceWith(p);\n b = p;\n } else b = list;\n }\n root.focus({ preventScroll: true });\n if (b && b.tagName === \"P\" && !b.textContent?.replace(/​/g, \"\").trim() && !b.querySelector(\"img\")) {\n b.innerHTML = \"<br>\";\n placeCaret(b);\n return b;\n }\n // an empty heading, quote or code line (e.g. \"/\" typed on one) is reused too, so no empty block is left behind\n if (b && /^(H[1-6]|BLOCKQUOTE|PRE)$/.test(b.tagName) && !b.textContent?.replace(/​/g, \"\").trim()) {\n const p = emptyP();\n b.replaceWith(p);\n placeCaret(p);\n return p;\n }\n const p = emptyP();\n if (b) b.after(p);\n else root.append(p);\n placeCaret(p);\n return p;\n}\n\nexport function insertIsland<K extends IslandKind>(root: HTMLElement, kind: K, model: IslandModels[K] = defaultModel(kind)): IslandEl {\n const target = takeEmptyBlock(root);\n const isl = createIsland(kind, model);\n isl.__rtFocus = true;\n target.before(isl);\n // keep the document tidy: reuse the line that already follows instead of leaving an empty one\n const next = target.nextElementSibling;\n if (isWritable(next)) {\n target.remove();\n placeCaret(next, false);\n } else placeCaret(target);\n return isl;\n}\n\n/** Inserts a basic block at the caret. */\nexport function insertBasic(root: HTMLElement, id: BasicId) {\n switch (id) {\n case \"p\":\n takeEmptyBlock(root);\n return;\n case \"h1\": case \"h2\": case \"h3\": case \"h4\": case \"h5\": case \"h6\":\n turnInto(root, takeEmptyBlock(root), id);\n return;\n case \"quote\":\n turnInto(root, takeEmptyBlock(root), \"blockquote\");\n return;\n case \"code\":\n turnInto(root, takeEmptyBlock(root), \"pre\");\n return;\n case \"ul\": case \"ol\": {\n const t = takeEmptyBlock(root);\n const l = document.createElement(id);\n l.innerHTML = \"<li><br></li>\";\n t.replaceWith(l);\n placeCaret(l.firstElementChild!);\n return;\n }\n case \"hr\": {\n const t = takeEmptyBlock(root);\n t.before(document.createElement(\"hr\"));\n placeCaret(t);\n return;\n }\n case \"image\": case \"table\": case \"pullquote\": case \"takeaways\": case \"callout\": case \"toggle\": case \"video\": case \"file\":\n insertIsland(root, id);\n return;\n }\n}\n\n/**\n * \"# \", \"> \", \"- \", \"1. \" and \"---\" at the start of a paragraph, each only when the field accepts what it makes.\n * Returns true when it converted.\n */\nexport function liveMarkdown(root: HTMLElement, data: string | null, allows: (f: RichTextFeature) => boolean = () => true): boolean {\n const s = window.getSelection();\n if (!s || !s.rangeCount || !s.isCollapsed) return false;\n const blk = topBlock(root, s.anchorNode);\n if (!blk || blk.tagName !== \"P\") return false;\n const before = textBeforeCaret(blk)?.replace(/ /g, \" \");\n if (before == null) return false;\n if (data === \"-\" && before === \"---\" && (blk.textContent ?? \"\").replace(/ /g, \" \") === \"---\") {\n if (!allows(\"hr\")) return false;\n const p = emptyP();\n blk.replaceWith(document.createElement(\"hr\"), p);\n placeCaret(p);\n return true;\n }\n if (data !== \" \") return false;\n const h = before.match(/^(#{1,6}) $/);\n let tag = h ? `h${h[1].length}` : before === \"> \" ? \"blockquote\" : null;\n let list = before === \"- \" || before === \"* \" ? \"ul\" : /^1[.)] $/.test(before) ? \"ol\" : null;\n if (tag && !allows(tag as RichTextFeature)) tag = null;\n if (list && !allows(list as RichTextFeature)) list = null;\n if (!tag && !list) return false;\n const r = document.createRange();\n r.selectNodeContents(blk);\n r.setEnd(s.anchorNode!, s.anchorOffset);\n r.deleteContents();\n const html = blk.textContent || blk.querySelector(\"img\") ? blk.innerHTML : \"<br>\";\n let target: HTMLElement;\n if (tag) {\n target = document.createElement(tag);\n target.innerHTML = html;\n blk.replaceWith(target);\n } else {\n const l = document.createElement(list!);\n target = document.createElement(\"li\");\n target.innerHTML = html;\n l.append(target);\n blk.replaceWith(l);\n }\n placeCaret(target, false);\n return true;\n}\n\n/** `text` typed between backticks becomes inline code. */\nexport function liveInlineCode(): boolean {\n const s = window.getSelection();\n if (!s || !s.rangeCount || !s.isCollapsed) return false;\n const r = s.getRangeAt(0);\n if (r.startContainer.nodeType !== 3 || r.startContainer.parentElement?.closest(\"code,pre\")) return false;\n const node = r.startContainer as Text;\n const m = node.data.slice(0, r.startOffset).match(/`([^`\\n]+)`$/);\n if (!m) return false;\n const del = document.createRange();\n del.setStart(node, r.startOffset - m[0].length);\n del.setEnd(node, r.startOffset);\n del.deleteContents();\n const code = document.createElement(\"code\");\n code.textContent = m[1];\n del.insertNode(code);\n const next = code.nextSibling;\n if (next && next.nodeType === 3 && next.textContent) {\n const c = document.createRange();\n c.setStart(next, 0);\n c.collapse(true);\n s.removeAllRanges();\n s.addRange(c);\n } else {\n const after = document.createTextNode(\"​\");\n code.after(after);\n placeCaret(after);\n }\n return true;\n}\n\n/* ── What a field accepts, applied to HTML that arrives from outside (paste, Markdown) ── */\nconst MARK_FEATURE: Record<string, RichTextFeature> = {\n STRONG: \"bold\", B: \"bold\", EM: \"italic\", I: \"italic\", U: \"underline\", S: \"strike\", STRIKE: \"strike\", DEL: \"strike\", CODE: \"code\", A: \"link\",\n};\nconst BLOCK_FEATURE: Record<string, RichTextFeature> = {\n H1: \"h1\", H2: \"h2\", H3: \"h3\", H4: \"h4\", H5: \"h5\", H6: \"h6\", BLOCKQUOTE: \"blockquote\", UL: \"ul\", OL: \"ol\", PRE: \"pre\", HR: \"hr\", FIGURE: \"image\", IMG: \"image\",\n};\nconst FEATURE_WORD: Partial<Record<RichTextFeature, string>> = {\n image: \"images\", hr: \"dividers\", pre: \"code blocks\", ul: \"bulleted lists\", ol: \"numbered lists\", blockquote: \"quotes\", link: \"links\",\n};\n\n/**\n * HTML with every element the field does not accept turned into what it does: a heading / quote / code block becomes a\n * paragraph, a list becomes one paragraph per item, a mark or link is unwrapped to its text, a divider or image is\n * removed. `dropped` names what was taken out entirely (said to the author, never silent).\n */\nexport function restrictHtml(html: string, allows: (f: RichTextFeature) => boolean): { html: string; dropped: string[] } {\n if (!html) return { html, dropped: [] };\n const doc = new DOMParser().parseFromString(`<body>${html}</body>`, \"text/html\");\n const dropped = new Set<string>();\n const walk = (el: Element) => {\n for (const ch of Array.from(el.children)) {\n walk(ch);\n const mark = MARK_FEATURE[ch.tagName];\n const block = BLOCK_FEATURE[ch.tagName];\n if (mark && !allows(mark)) ch.replaceWith(...Array.from(ch.childNodes));\n else if (block && !allows(block)) {\n if (block === \"hr\" || block === \"image\") {\n dropped.add(FEATURE_WORD[block]!);\n ch.remove();\n } else if (block === \"ul\" || block === \"ol\") {\n const ps = Array.from(ch.children).map((li) => {\n const p = doc.createElement(\"p\");\n p.innerHTML = li.innerHTML;\n return p;\n });\n ch.replaceWith(...ps);\n } else {\n const p = doc.createElement(\"p\");\n p.innerHTML = block === \"pre\" ? esc(ch.textContent ?? \"\").replace(/\\n/g, \"<br>\") : ch.innerHTML;\n ch.replaceWith(p);\n }\n }\n }\n };\n walk(doc.body);\n return { html: doc.body.innerHTML, dropped: [...dropped] };\n}\n"],"mappings":"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"}
@@ -0,0 +1,17 @@
1
+ /**
2
+ * Plain paragraphs as a growing textarea (V2's `text` control), for hosts where V2 shows long text as a textarea
3
+ * rather than the rich editor: the canvas Values popover. A rich-text value whose html is only plain paragraphs
4
+ * reads as one line per `<p>`; one that carries marks, links, line breaks, lists or attributes returns null and
5
+ * keeps the rich editor, so editing never strips them. The textarea's text goes back as one `<p>` per line through
6
+ * the field's own codec, so the stored shape is the field's as before.
7
+ */
8
+ import * as React from "react";
9
+ /** The html as textarea text — one line per `<p>` — or null when a textarea cannot carry it back unchanged. */
10
+ export declare function plainParagraphs(html: unknown): string | null;
11
+ /** Textarea text back to the paragraph html `plainParagraphs` reads: one `<p>` per line. */
12
+ export declare function paragraphsHtml(text: string): string;
13
+ /** Inside this scope a rich-text field holding plain paragraphs is drawn as V2's growing textarea. */
14
+ export declare function PlainRichTextScope({ children }: {
15
+ children: React.ReactNode;
16
+ }): import("react/jsx-runtime").JSX.Element;
17
+ export declare const usePlainRichText: () => boolean;
@@ -0,0 +1,44 @@
1
+ import * as React from "react";
2
+ import { jsx } from "react/jsx-runtime";
3
+ //#region src/controls/rich-text/plain.tsx
4
+ /**
5
+ * Plain paragraphs as a growing textarea (V2's `text` control), for hosts where V2 shows long text as a textarea
6
+ * rather than the rich editor: the canvas Values popover. A rich-text value whose html is only plain paragraphs
7
+ * reads as one line per `<p>`; one that carries marks, links, line breaks, lists or attributes returns null and
8
+ * keeps the rich editor, so editing never strips them. The textarea's text goes back as one `<p>` per line through
9
+ * the field's own codec, so the stored shape is the field's as before.
10
+ */
11
+ /** The html as textarea text — one line per `<p>` — or null when a textarea cannot carry it back unchanged. */
12
+ function plainParagraphs(html) {
13
+ if (html === void 0 || html === null || html === "") return "";
14
+ if (typeof html !== "string") return null;
15
+ const body = new DOMParser().parseFromString(html, "text/html").body;
16
+ const lines = [];
17
+ for (const node of Array.from(body.childNodes)) {
18
+ if (node.nodeType === Node.TEXT_NODE && !node.textContent?.trim()) continue;
19
+ if (node.nodeType !== Node.ELEMENT_NODE) return null;
20
+ const el = node;
21
+ if (el.tagName !== "P" || el.attributes.length || Array.from(el.childNodes).some((c) => c.nodeType !== Node.TEXT_NODE)) return null;
22
+ if (el.textContent?.includes("\n")) return null;
23
+ lines.push(el.textContent ?? "");
24
+ }
25
+ return lines.join("\n");
26
+ }
27
+ var escapeHtml = (s) => s.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
28
+ /** Textarea text back to the paragraph html `plainParagraphs` reads: one `<p>` per line. */
29
+ function paragraphsHtml(text) {
30
+ return text.split(/\r?\n/).map((line) => `<p>${escapeHtml(line)}</p>`).join("");
31
+ }
32
+ var PlainRichText = React.createContext(false);
33
+ /** Inside this scope a rich-text field holding plain paragraphs is drawn as V2's growing textarea. */
34
+ function PlainRichTextScope({ children }) {
35
+ return /* @__PURE__ */ jsx(PlainRichText.Provider, {
36
+ value: true,
37
+ children
38
+ });
39
+ }
40
+ var usePlainRichText = () => React.useContext(PlainRichText);
41
+ //#endregion
42
+ export { PlainRichTextScope, paragraphsHtml, plainParagraphs, usePlainRichText };
43
+
44
+ //# sourceMappingURL=plain.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plain.js","names":[],"sources":["../../../src/controls/rich-text/plain.tsx"],"sourcesContent":["/**\n * Plain paragraphs as a growing textarea (V2's `text` control), for hosts where V2 shows long text as a textarea\n * rather than the rich editor: the canvas Values popover. A rich-text value whose html is only plain paragraphs\n * reads as one line per `<p>`; one that carries marks, links, line breaks, lists or attributes returns null and\n * keeps the rich editor, so editing never strips them. The textarea's text goes back as one `<p>` per line through\n * the field's own codec, so the stored shape is the field's as before.\n */\nimport * as React from \"react\";\n\n/** The html as textarea text — one line per `<p>` — or null when a textarea cannot carry it back unchanged. */\nexport function plainParagraphs(html: unknown): string | null {\n if (html === undefined || html === null || html === \"\") return \"\";\n if (typeof html !== \"string\") return null;\n const body = new DOMParser().parseFromString(html, \"text/html\").body;\n const lines: string[] = [];\n for (const node of Array.from(body.childNodes)) {\n if (node.nodeType === Node.TEXT_NODE && !node.textContent?.trim()) continue;\n if (node.nodeType !== Node.ELEMENT_NODE) return null;\n const el = node as Element;\n if (el.tagName !== \"P\" || el.attributes.length || Array.from(el.childNodes).some((c) => c.nodeType !== Node.TEXT_NODE)) return null;\n if (el.textContent?.includes(\"\\n\")) return null;\n lines.push(el.textContent ?? \"\");\n }\n return lines.join(\"\\n\");\n}\n\nconst escapeHtml = (s: string) => s.replace(/&/g, \"&amp;\").replace(/</g, \"&lt;\").replace(/>/g, \"&gt;\");\n\n/** Textarea text back to the paragraph html `plainParagraphs` reads: one `<p>` per line. */\nexport function paragraphsHtml(text: string): string {\n return text.split(/\\r?\\n/).map((line) => `<p>${escapeHtml(line)}</p>`).join(\"\");\n}\n\nconst PlainRichText = React.createContext(false);\n\n/** Inside this scope a rich-text field holding plain paragraphs is drawn as V2's growing textarea. */\nexport function PlainRichTextScope({ children }: { children: React.ReactNode }) {\n return <PlainRichText.Provider value>{children}</PlainRichText.Provider>;\n}\n\nexport const usePlainRichText = () => React.useContext(PlainRichText);\n"],"mappings":";;;;;;;;;;;AAUA,SAAgB,gBAAgB,MAA8B;CAC5D,IAAI,SAAS,KAAA,KAAa,SAAS,QAAQ,SAAS,IAAI,OAAO;CAC/D,IAAI,OAAO,SAAS,UAAU,OAAO;CACrC,MAAM,OAAO,IAAI,UAAU,CAAC,CAAC,gBAAgB,MAAM,WAAW,CAAC,CAAC;CAChE,MAAM,QAAkB,CAAC;CACzB,KAAK,MAAM,QAAQ,MAAM,KAAK,KAAK,UAAU,GAAG;EAC9C,IAAI,KAAK,aAAa,KAAK,aAAa,CAAC,KAAK,aAAa,KAAK,GAAG;EACnE,IAAI,KAAK,aAAa,KAAK,cAAc,OAAO;EAChD,MAAM,KAAK;EACX,IAAI,GAAG,YAAY,OAAO,GAAG,WAAW,UAAU,MAAM,KAAK,GAAG,UAAU,CAAC,CAAC,MAAM,MAAM,EAAE,aAAa,KAAK,SAAS,GAAG,OAAO;EAC/H,IAAI,GAAG,aAAa,SAAS,IAAI,GAAG,OAAO;EAC3C,MAAM,KAAK,GAAG,eAAe,EAAE;CACjC;CACA,OAAO,MAAM,KAAK,IAAI;AACxB;AAEA,IAAM,cAAc,MAAc,EAAE,QAAQ,MAAM,OAAO,CAAC,CAAC,QAAQ,MAAM,MAAM,CAAC,CAAC,QAAQ,MAAM,MAAM;;AAGrG,SAAgB,eAAe,MAAsB;CACnD,OAAO,KAAK,MAAM,OAAO,CAAC,CAAC,KAAK,SAAS,MAAM,WAAW,IAAI,EAAE,KAAK,CAAC,CAAC,KAAK,EAAE;AAChF;AAEA,IAAM,gBAAgB,MAAM,cAAc,KAAK;;AAG/C,SAAgB,mBAAmB,EAAE,YAA2C;CAC9E,OAAO,oBAAC,cAAc,UAAf;EAAwB,OAAA;EAAO;CAAiC,CAAA;AACzE;AAEA,IAAa,yBAAyB,MAAM,WAAW,aAAa"}
@@ -13,6 +13,8 @@ export interface Fmt {
13
13
  italic: boolean;
14
14
  underline: boolean;
15
15
  strike: boolean;
16
+ sup: boolean;
17
+ sub: boolean;
16
18
  ul: boolean;
17
19
  ol: boolean;
18
20
  /** lower-case tag of the caret's top-level block, or "island" */
@@ -21,7 +23,7 @@ export interface Fmt {
21
23
  onLink: boolean;
22
24
  }
23
25
  export declare const EMPTY_FMT: Fmt;
24
- export type MarkCmd = "bold" | "italic" | "underline" | "strikeThrough";
26
+ export type MarkCmd = "bold" | "italic" | "underline" | "strikeThrough" | "superscript" | "subscript";
25
27
  export declare const MARK_FEATURE: Record<MarkCmd, RichTextFeature>;
26
28
  export declare const STYLES: {
27
29
  tag: string;
@@ -36,7 +38,7 @@ export declare const stylesFor: (allows: (f: RichTextFeature) => boolean) => {
36
38
  short: string;
37
39
  icon: React.ReactNode;
38
40
  }[];
39
- export declare function ToolButton({ label, tip, icon, onClick, active, disabled, shortcut, children, className, }: {
41
+ export declare function ToolButton({ label, tip, icon, onClick, active, disabled, shortcut, children, className, side, }: {
40
42
  label: string;
41
43
  tip?: string;
42
44
  icon: React.ReactNode;
@@ -46,6 +48,8 @@ export declare function ToolButton({ label, tip, icon, onClick, active, disabled
46
48
  shortcut?: string;
47
49
  children?: React.ReactNode;
48
50
  className?: string;
51
+ /** The tooltip's side; the overlay's default (top) when omitted. */
52
+ side?: "top" | "bottom" | "left" | "right";
49
53
  }): import("react/jsx-runtime").JSX.Element;
50
54
  /** "Block style" dropdown. Compact trigger: Text / H1…H6 / Quote. */
51
55
  export declare function StyleMenu({ block, styles, onPick, onOpenChange, disabled, className, }: {
@@ -2,14 +2,16 @@ import { cn } from "../../lib/cn.js";
2
2
  import { Menu, MenuContent, MenuItem, MenuSeparator, MenuTrigger, Popover, PopoverTrigger, Tooltip } from "../../ui/overlay.js";
3
3
  import { InsertMenuContent } from "./catalog.js";
4
4
  import "react";
5
- import { IconArrowsMaximize, IconBlockquote, IconBold, IconCheck, IconChevronDown, IconClearFormatting, IconCode, IconH1, IconH2, IconH3, IconH4, IconH5, IconH6, IconItalic, IconLink, IconList, IconListNumbers, IconMarkdown, IconMarkdownOff, IconMessage, IconPilcrow, IconPlus, IconStrikethrough, IconTerminal2, IconUnderline } from "@tabler/icons-react";
6
5
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
7
- //#region src/kit/controls/rich-text/toolbar.tsx
6
+ import { IconArrowsMaximize, IconBlockquote, IconBold, IconCheck, IconChevronDown, IconClearFormatting, IconCode, IconH1, IconH2, IconH3, IconH4, IconH5, IconH6, IconItalic, IconLink, IconList, IconListNumbers, IconMarkdown, IconMarkdownOff, IconMessage, IconPilcrow, IconPlus, IconStrikethrough, IconTerminal2, IconUnderline } from "@tabler/icons-react";
7
+ //#region src/controls/rich-text/toolbar.tsx
8
8
  var EMPTY_FMT = {
9
9
  bold: false,
10
10
  italic: false,
11
11
  underline: false,
12
12
  strike: false,
13
+ sup: false,
14
+ sub: false,
13
15
  ul: false,
14
16
  ol: false,
15
17
  block: "p",
@@ -20,7 +22,9 @@ var MARK_FEATURE = {
20
22
  bold: "bold",
21
23
  italic: "italic",
22
24
  underline: "underline",
23
- strikeThrough: "strike"
25
+ strikeThrough: "strike",
26
+ superscript: "sup",
27
+ subscript: "sub"
24
28
  };
25
29
  var STYLES = [
26
30
  {
@@ -75,10 +79,11 @@ var STYLES = [
75
79
  /** The block styles a field accepts (Text always). */
76
80
  var stylesFor = (allows) => STYLES.filter((s) => s.tag === "p" || allows(s.tag));
77
81
  var keepCaret = (e) => e.preventDefault();
78
- function ToolButton({ label, tip, icon, onClick, active, disabled, shortcut, children, className }) {
82
+ function ToolButton({ label, tip, icon, onClick, active, disabled, shortcut, children, className, side }) {
79
83
  return /* @__PURE__ */ jsx(Tooltip, {
80
84
  content: tip ?? label,
81
85
  shortcut,
86
+ side,
82
87
  children: /* @__PURE__ */ jsxs("button", {
83
88
  type: "button",
84
89
  "aria-label": label,
@@ -155,7 +160,7 @@ function FormatToolbar({ open, sticky, stickyTop = 0, width, dense, fmt, md, all
155
160
  const markLabel = (m) => m === "underline" ? "Underline" : "Strikethrough";
156
161
  const more = foldUS && marks.length || foldLists && lists.length || foldClear || foldMd || allows("code") || allows("pre");
157
162
  return /* @__PURE__ */ jsx("div", {
158
- className: cn("overflow-clip rounded-t-kit-lg transition-[height] duration-150 ease-out", open ? "h-8 pointer-coarse:h-11" : "h-0", sticky && open && "sticky z-[4]"),
163
+ className: cn("overflow-clip rounded-t-kit-lg", open ? "h-8 pointer-coarse:h-11" : "h-0", sticky && open && "sticky z-[4]"),
159
164
  style: sticky && open ? { top: stickyTop } : void 0,
160
165
  inert: !open,
161
166
  "aria-hidden": !open,
@@ -165,7 +170,7 @@ function FormatToolbar({ open, sticky, stickyTop = 0, width, dense, fmt, md, all
165
170
  onMouseDown: (e) => {
166
171
  if (!e.target.closest("button")) e.preventDefault();
167
172
  },
168
- className: cn("flex h-full items-center gap-0.5 border-b border-kit-line bg-kit-subtle px-1 transition-opacity duration-[120ms] ease-out", open ? "opacity-100" : "opacity-0"),
173
+ className: cn("flex h-full items-center gap-0.5 border-b border-kit-line bg-kit-subtle px-1 transition-opacity duration-[120ms] ease-out motion-reduce:transition-none", open ? "opacity-100" : "opacity-0"),
169
174
  children: [
170
175
  styles.length > 1 ? /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx(StyleMenu, {
171
176
  block: fmt.block,
@@ -333,6 +338,6 @@ function FormatToolbar({ open, sticky, stickyTop = 0, width, dense, fmt, md, all
333
338
  });
334
339
  }
335
340
  //#endregion
336
- export { EMPTY_FMT, FormatToolbar, MARK_FEATURE, StyleMenu, ToolButton, stylesFor };
341
+ export { EMPTY_FMT, FormatToolbar, MARK_FEATURE, STYLES, StyleMenu, ToolButton, stylesFor };
337
342
 
338
343
  //# sourceMappingURL=toolbar.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"toolbar.js","names":[],"sources":["../../../src/controls/rich-text/toolbar.tsx"],"sourcesContent":["/**\n * RICH TEXT · the field toolbar (V2 HEAD controls/rich-text/toolbar.tsx, production order):\n * Style ▾ | B I U S | • 1. | Link, Clear formatting, Comment | ▾ more | + Insert ····· Markdown · Open full editor\n * The overflow is a chevron next to the formatting, never a second \"⋯\" (the field's label row owns the one ⋯ menu).\n * It takes no room at rest (h-0, inert, aria-hidden) and slides open to 32px when the field is in use. Items fold into\n * \"More formatting options\" as the field narrows. A control whose element the field does not accept is not drawn.\n */\nimport * as React from \"react\";\nimport {\n IconArrowsMaximize, IconBlockquote, IconBold, IconCheck, IconChevronDown, IconClearFormatting, IconCode, IconH1, IconH2, IconH3, IconH4, IconH5,\n IconH6, IconItalic, IconLink, IconList, IconListNumbers, IconMarkdown, IconMarkdownOff, IconMessage, IconPilcrow, IconPlus, IconStrikethrough,\n IconTerminal2, IconUnderline,\n} from \"@tabler/icons-react\";\nimport { cn } from \"../../lib/cn\";\nimport { Menu, MenuContent, MenuItem, MenuSeparator, MenuTrigger, Popover, PopoverTrigger, Tooltip } from \"../../ui/overlay\";\nimport { InsertMenuContent, type CatalogItem } from \"./catalog\";\nimport type { RichTextFeature } from \"./codec\";\n\nexport interface Fmt {\n bold: boolean;\n italic: boolean;\n underline: boolean;\n strike: boolean;\n sup: boolean;\n sub: boolean;\n ul: boolean;\n ol: boolean;\n /** lower-case tag of the caret's top-level block, or \"island\" */\n block: string;\n hasSel: boolean;\n onLink: boolean;\n}\nexport const EMPTY_FMT: Fmt = { bold: false, italic: false, underline: false, strike: false, sup: false, sub: false, ul: false, ol: false, block: \"p\", hasSel: false, onLink: false };\n\nexport type MarkCmd = \"bold\" | \"italic\" | \"underline\" | \"strikeThrough\" | \"superscript\" | \"subscript\";\nexport const MARK_FEATURE: Record<MarkCmd, RichTextFeature> = { bold: \"bold\", italic: \"italic\", underline: \"underline\", strikeThrough: \"strike\", superscript: \"sup\", subscript: \"sub\" };\n\nexport const STYLES: { tag: string; label: string; short: string; icon: React.ReactNode }[] = [\n { tag: \"p\", label: \"Text\", short: \"Text\", icon: <IconPilcrow stroke={1.5} /> },\n { tag: \"h1\", label: \"Heading 1\", short: \"H1\", icon: <IconH1 stroke={1.5} /> },\n { tag: \"h2\", label: \"Heading 2\", short: \"H2\", icon: <IconH2 stroke={1.5} /> },\n { tag: \"h3\", label: \"Heading 3\", short: \"H3\", icon: <IconH3 stroke={1.5} /> },\n { tag: \"h4\", label: \"Heading 4\", short: \"H4\", icon: <IconH4 stroke={1.5} /> },\n { tag: \"h5\", label: \"Heading 5\", short: \"H5\", icon: <IconH5 stroke={1.5} /> },\n { tag: \"h6\", label: \"Heading 6\", short: \"H6\", icon: <IconH6 stroke={1.5} /> },\n { tag: \"blockquote\", label: \"Quote\", short: \"Quote\", icon: <IconBlockquote stroke={1.5} /> },\n];\n/** The block styles a field accepts (Text always). */\nexport const stylesFor = (allows: (f: RichTextFeature) => boolean) => STYLES.filter((s) => s.tag === \"p\" || allows(s.tag as RichTextFeature));\n\nconst keepCaret = (e: React.MouseEvent) => e.preventDefault();\n\nexport function ToolButton({\n label,\n tip,\n icon,\n onClick,\n active,\n disabled,\n shortcut,\n children,\n className,\n side,\n}: {\n label: string;\n tip?: string;\n icon: React.ReactNode;\n onClick?: () => void;\n active?: boolean;\n disabled?: boolean;\n shortcut?: string;\n children?: React.ReactNode;\n className?: string;\n /** The tooltip's side; the overlay's default (top) when omitted. */\n side?: \"top\" | \"bottom\" | \"left\" | \"right\";\n}) {\n return (\n <Tooltip content={tip ?? label} shortcut={shortcut} side={side}>\n <button\n type=\"button\"\n aria-label={label}\n aria-pressed={active}\n aria-disabled={disabled || undefined}\n onMouseDown={keepCaret}\n onClick={() => !disabled && onClick?.()}\n className={cn(\n \"flex h-7 min-w-7 shrink-0 items-center justify-center gap-1 rounded-kit-md px-1.5 text-kit-sm text-kit-fg-2 transition-colors hover:bg-kit-hover hover:text-kit-fg [&_svg]:size-4\",\n active && \"bg-kit-selected text-kit-fg\",\n disabled && \"opacity-40 hover:bg-transparent hover:text-kit-fg-2\",\n className,\n )}\n >\n {icon}\n {children}\n </button>\n </Tooltip>\n );\n}\n\n/** \"Block style\" dropdown. Compact trigger: Text / H1…H6 / Quote. */\nexport function StyleMenu({\n block,\n styles,\n onPick,\n onOpenChange,\n disabled,\n className,\n}: {\n block: string;\n styles: typeof STYLES;\n onPick: (tag: string) => void;\n onOpenChange?: (o: boolean) => void;\n disabled?: boolean;\n className?: string;\n}) {\n const cur = STYLES.find((s) => s.tag === block);\n return (\n <Menu onOpenChange={onOpenChange}>\n <Tooltip content=\"Block style\">\n <MenuTrigger\n disabled={disabled}\n aria-label=\"Block style\"\n onMouseDown={keepCaret}\n className={cn(\n \"flex h-7 shrink-0 items-center gap-1 rounded-kit-md pl-2 pr-1.5 text-kit-sm font-medium text-kit-fg hover:bg-kit-hover disabled:opacity-40 data-[popup-open]:bg-kit-hover\",\n !cur && \"text-kit-fg-2\",\n className,\n )}\n >\n {cur?.short ?? \"Text\"}\n <IconChevronDown className=\"size-3.5 text-kit-fg-3\" stroke={1.5} aria-hidden />\n </MenuTrigger>\n </Tooltip>\n <MenuContent className=\"w-48\" finalFocus={false}>\n {styles.map((s) => (\n <MenuItem key={s.tag} icon={s.icon} onClick={() => onPick(s.tag)}>\n <span className=\"flex w-full items-center justify-between\">\n {s.label}\n {block === s.tag ? <IconCheck className=\"size-3.5 text-kit-fg-2\" stroke={2} aria-hidden /> : null}\n </span>\n </MenuItem>\n ))}\n </MenuContent>\n </Menu>\n );\n}\n\nconst Sep = () => <span aria-hidden className=\"mx-1 h-4 w-px shrink-0 bg-kit-line\" />;\n\nexport function FormatToolbar({\n open,\n sticky,\n stickyTop = 0,\n width,\n dense,\n fmt,\n md,\n allows,\n hideFullscreen,\n insertOpen,\n setInsertOpen,\n onMenuOpen,\n onStyle,\n onMark,\n onList,\n onLink,\n onClear,\n onComment,\n onInlineCode,\n onCodeBlock,\n onInsert,\n keepFocusOnInsertClose,\n onFullscreen,\n onMarkdown,\n saveSel,\n}: {\n open: boolean;\n sticky: boolean;\n stickyTop?: number;\n width: number;\n dense: boolean;\n fmt: Fmt;\n md: boolean;\n allows: (f: RichTextFeature) => boolean;\n hideFullscreen?: boolean;\n insertOpen: boolean;\n setInsertOpen: (o: boolean) => void;\n onMenuOpen: (name: \"style\" | \"more\", o: boolean) => void;\n onStyle: (tag: string) => void;\n onMark: (cmd: MarkCmd) => void;\n onList: (kind: \"ul\" | \"ol\") => void;\n onLink: () => void;\n onClear: () => void;\n onComment?: () => void;\n onInlineCode: () => void;\n onCodeBlock: () => void;\n onInsert: (it: CatalogItem) => void;\n keepFocusOnInsertClose: () => boolean;\n onFullscreen: () => void;\n onMarkdown: () => void;\n saveSel: () => void;\n}) {\n const w = width - (dense ? 40 : 0);\n const foldUS = w < 430;\n const foldLists = w < 480;\n const foldMd = w < 400;\n const foldClear = w < 360;\n const insertLabel = w >= 590;\n const off = md;\n const styles = stylesFor(allows);\n const marks = ([\"underline\", \"strikeThrough\"] as const).filter((m) => allows(MARK_FEATURE[m]));\n const lists = ([\"ul\", \"ol\"] as const).filter((l) => allows(l));\n const linkTip = fmt.hasSel || fmt.onLink ? \"Link\" : \"Link (select some text first)\";\n const commentTip = fmt.hasSel ? \"Comment\" : \"Comment (select some text first)\";\n const check = (on: boolean) => (on ? <IconCheck className=\"ml-auto size-3.5 text-kit-fg-2\" stroke={2} aria-hidden /> : null);\n const listIcon = (l: \"ul\" | \"ol\") => (l === \"ul\" ? <IconList stroke={1.5} /> : <IconListNumbers stroke={1.5} />);\n const listLabel = (l: \"ul\" | \"ol\") => (l === \"ul\" ? \"Bulleted list\" : \"Numbered list\");\n const markIcon = (m: \"underline\" | \"strikeThrough\") => (m === \"underline\" ? <IconUnderline stroke={1.5} /> : <IconStrikethrough stroke={1.5} />);\n const markLabel = (m: \"underline\" | \"strikeThrough\") => (m === \"underline\" ? \"Underline\" : \"Strikethrough\");\n const more = (foldUS && marks.length) || (foldLists && lists.length) || foldClear || foldMd || allows(\"code\") || allows(\"pre\");\n\n return (\n <div\n // Opens at once: it shows on every focus of the body, and a height animation is layout work every frame.\n className={cn(\"overflow-clip rounded-t-kit-lg\", open ? \"h-8 pointer-coarse:h-11\" : \"h-0\", sticky && open && \"sticky z-[4]\")}\n style={sticky && open ? { top: stickyTop } : undefined}\n inert={!open}\n aria-hidden={!open}\n >\n <div\n role=\"toolbar\"\n aria-label=\"Text formatting\"\n onMouseDown={(e) => {\n if (!(e.target as HTMLElement).closest(\"button\")) e.preventDefault();\n }}\n className={cn(\"flex h-full items-center gap-0.5 border-b border-kit-line bg-kit-subtle px-1 transition-opacity duration-[120ms] ease-out motion-reduce:transition-none\", open ? \"opacity-100\" : \"opacity-0\")}\n >\n {styles.length > 1 ? (\n <>\n <StyleMenu block={fmt.block} styles={styles} onPick={onStyle} disabled={off} onOpenChange={(o) => onMenuOpen(\"style\", o)} />\n <Sep />\n </>\n ) : null}\n {allows(\"bold\") ? <ToolButton label=\"Bold\" icon={<IconBold stroke={1.5} />} shortcut=\"⌘B\" active={fmt.bold} disabled={off} onClick={() => onMark(\"bold\")} /> : null}\n {allows(\"italic\") ? <ToolButton label=\"Italic\" icon={<IconItalic stroke={1.5} />} shortcut=\"⌘I\" active={fmt.italic} disabled={off} onClick={() => onMark(\"italic\")} /> : null}\n {foldUS\n ? null\n : marks.map((m) => (\n <ToolButton key={m} label={markLabel(m)} icon={markIcon(m)} shortcut={m === \"underline\" ? \"⌘U\" : undefined} active={m === \"underline\" ? fmt.underline : fmt.strike} disabled={off} onClick={() => onMark(m)} />\n ))}\n {foldLists || !lists.length ? null : (\n <>\n <Sep />\n {lists.map((l) => (\n <ToolButton key={l} label={listLabel(l)} icon={listIcon(l)} active={fmt[l]} disabled={off} onClick={() => onList(l)} />\n ))}\n </>\n )}\n <Sep />\n {allows(\"link\") ? (\n <ToolButton label=\"Link\" tip={linkTip} icon={<IconLink stroke={1.5} />} shortcut={fmt.hasSel || fmt.onLink ? \"⌘K\" : undefined} active={fmt.onLink} disabled={off || !(fmt.hasSel || fmt.onLink)} onClick={onLink} />\n ) : null}\n {foldClear ? null : <ToolButton label=\"Clear formatting\" icon={<IconClearFormatting stroke={1.5} />} disabled={off} onClick={onClear} />}\n {onComment ? <ToolButton label=\"Comment\" tip={commentTip} icon={<IconMessage stroke={1.5} />} disabled={off || !fmt.hasSel} onClick={onComment} /> : null}\n {more ? (\n <Menu onOpenChange={(o) => onMenuOpen(\"more\", o)}>\n <Tooltip content=\"More formatting\">\n <MenuTrigger\n aria-label=\"More formatting options\"\n onMouseDown={(e) => {\n e.preventDefault();\n saveSel();\n }}\n className=\"flex h-7 w-5 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 data-[popup-open]:text-kit-fg [&_svg]:size-3.5\"\n >\n <IconChevronDown stroke={1.5} aria-hidden />\n </MenuTrigger>\n </Tooltip>\n <MenuContent align=\"start\" className=\"w-56\" finalFocus={false}>\n {foldUS\n ? marks.map((m) => (\n <MenuItem key={m} disabled={off} icon={markIcon(m)} shortcut={m === \"underline\" ? \"⌘U\" : undefined} onClick={() => onMark(m)}>\n <span className=\"flex w-full items-center\">\n {markLabel(m)}\n {check(m === \"underline\" ? fmt.underline : fmt.strike)}\n </span>\n </MenuItem>\n ))\n : null}\n {foldLists\n ? lists.map((l) => (\n <MenuItem key={l} disabled={off} icon={listIcon(l)} onClick={() => onList(l)}>\n {listLabel(l)}\n </MenuItem>\n ))\n : null}\n {foldClear ? (\n <MenuItem disabled={off} icon={<IconClearFormatting stroke={1.5} />} onClick={onClear}>\n Clear formatting\n </MenuItem>\n ) : null}\n {foldMd ? (\n <MenuItem icon={md ? <IconMarkdownOff stroke={1.5} /> : <IconMarkdown stroke={1.5} />} onClick={onMarkdown}>\n {md ? \"Return to rich text\" : \"View and edit as Markdown\"}\n </MenuItem>\n ) : null}\n {(foldUS && marks.length) || (foldLists && lists.length) || foldClear || foldMd ? <MenuSeparator /> : null}\n {allows(\"code\") ? (\n <MenuItem disabled={off} icon={<IconCode stroke={1.5} />} shortcut=\"⌘E\" onClick={onInlineCode}>\n Inline code\n </MenuItem>\n ) : null}\n {allows(\"pre\") ? (\n <MenuItem disabled={off} icon={<IconTerminal2 stroke={1.5} />} onClick={onCodeBlock}>\n Code\n </MenuItem>\n ) : null}\n </MenuContent>\n </Menu>\n ) : null}\n <Sep />\n <Popover open={insertOpen} onOpenChange={setInsertOpen}>\n <Tooltip content=\"Insert a block\">\n <PopoverTrigger\n disabled={off}\n aria-label=\"Insert\"\n onMouseDown={() => saveSel()}\n className=\"flex h-7 shrink-0 items-center gap-1 rounded-kit-md px-1.5 text-kit-sm text-kit-fg-2 hover:bg-kit-hover hover:text-kit-fg disabled:opacity-40 data-[popup-open]:bg-kit-hover data-[popup-open]:text-kit-fg [&_svg]:size-4\"\n >\n <IconPlus stroke={1.5} aria-hidden />\n {insertLabel ? \"Insert\" : null}\n </PopoverTrigger>\n </Tooltip>\n {insertOpen ? <InsertMenuContent allows={allows} onInsert={onInsert} keepFocusOnClose={keepFocusOnInsertClose} /> : null}\n </Popover>\n\n <span className=\"min-w-1 flex-1\" />\n\n {foldMd ? null : (\n <ToolButton label={md ? \"Return to rich text\" : \"View and edit as Markdown\"} icon={md ? <IconMarkdownOff stroke={1.5} /> : <IconMarkdown stroke={1.5} />} active={md} onClick={onMarkdown} />\n )}\n {hideFullscreen ? null : <ToolButton label=\"Expand editor\" icon={<IconArrowsMaximize stroke={1.5} />} shortcut=\"⌘↵\" onClick={onFullscreen} />}\n </div>\n </div>\n );\n}\n"],"mappings":"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"}
@@ -5,7 +5,7 @@ import { UNIT_NAMES, customPx, customRules, defaultUnit, fieldScale, formatNumbe
5
5
  import * as React from "react";
6
6
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
7
7
  import { Tooltip } from "@base-ui/react/tooltip";
8
- //#region src/kit/controls/scale.tsx
8
+ //#region src/controls/scale.tsx
9
9
  /**
10
10
  * SCALE — one control, two modes (CPO D41), in the designer's CAPSULE: a muted 32px capsule, a soft fill to the value,
11
11
  * a 3px bar thumb at the fill's end (always right of the label), the label inside on the left (panels) and the value
@@ -297,7 +297,7 @@ function ScaleSlider({ scale, value, onChange, label, id, disabled, readOnly, in
297
297
  onPointerUp: () => setDragging(false),
298
298
  onPointerCancel: () => setDragging(false),
299
299
  onDoubleClick: () => beginEdit(),
300
- className: cn("group/cap relative flex h-8 w-full touch-none select-none items-center overflow-hidden rounded-kit-md bg-kit-muted transition-[background-color,box-shadow]", inert ? "cursor-not-allowed" : "cursor-ew-resize hover:bg-kit-hover", disabled && "opacity-50", kbFocus && !editing && !error && "shadow-[0_0_0_2px_var(--kit-surface),0_0_0_4px_var(--kit-focus-ring)]", editing && !error && "shadow-[inset_0_0_0_1px_var(--kit-line-strong)]", error && "shadow-[inset_0_0_0_1px_var(--kit-danger)]"),
300
+ className: cn("group/cap relative flex h-8 w-full touch-none select-none items-center overflow-hidden rounded-kit-md bg-kit-muted transition-[background-color,box-shadow]", inert ? "cursor-not-allowed" : "cursor-ew-resize hover:bg-kit-hover", disabled && "opacity-50", kbFocus && !editing && !error && "shadow-[var(--kit-ring-focus,0_0_0_2px_var(--kit-surface),0_0_0_4px_var(--kit-focus-ring))]", editing && !error && "shadow-[inset_0_0_0_1px_var(--kit-line-strong)]", error && "shadow-[inset_0_0_0_1px_var(--kit-danger)]"),
301
301
  children: [
302
302
  pos >= 0 ? /* @__PURE__ */ jsx("div", {
303
303
  "aria-hidden": true,
@@ -327,7 +327,7 @@ function ScaleSlider({ scale, value, onChange, label, id, disabled, readOnly, in
327
327
  setKbFocus(false);
328
328
  onBlur?.();
329
329
  },
330
- className: cn("absolute top-1/2 z-[1] h-4 w-[3px] -translate-x-full -translate-y-1/2 rounded-full bg-kit-fg-3 opacity-0 outline-none focus-visible:!shadow-none focus-visible:!outline-none", !inert && "group-hover/cap:opacity-100", "focus-visible:opacity-100", dragging && "opacity-100", (pos < 0 || editing) && "!opacity-0", !dragging && "motion-safe:transition-[left,opacity] motion-safe:duration-75"),
330
+ className: cn("absolute top-1/2 z-[1] h-4 w-[3px] -translate-x-full -translate-y-1/2 cursor-[inherit] rounded-full bg-kit-fg-3 opacity-0 outline-none focus-visible:!shadow-none focus-visible:!outline-none", !inert && "group-hover/cap:opacity-100", "focus-visible:opacity-100", dragging && "opacity-100", (pos < 0 || editing) && "!opacity-0", !dragging && "motion-safe:transition-[left,opacity] motion-safe:duration-75"),
331
331
  style: { left: `min(calc(${fillW} - 4px), calc(100% - ${valueW}px - 2px))` }
332
332
  }),
333
333
  inlineLabel ? /* @__PURE__ */ jsxs("span", {
@@ -417,7 +417,7 @@ function ScaleSlider({ scale, value, onChange, label, id, disabled, readOnly, in
417
417
  stepTokens(e.key === "ArrowUp" ? 1 : -1, e);
418
418
  }
419
419
  },
420
- className: cn("h-6 min-w-0 bg-transparent p-0 text-right text-kit-xs tabular-nums text-kit-fg outline-none placeholder:text-kit-fg-4 focus:shadow-none focus-visible:shadow-none focus-visible:outline-none selection:bg-kit-selected", isCustom || editing ? "font-normal" : "font-medium", !editing && "pointer-events-none")
420
+ className: cn("tabular-nums h-6 min-w-0 bg-transparent p-0 text-right text-kit-xs text-kit-fg outline-none placeholder:text-kit-fg-4 focus:shadow-none focus-visible:shadow-none selection:bg-kit-selected", isCustom || editing ? "font-normal" : "font-medium", !editing && "pointer-events-none")
421
421
  }),
422
422
  !tokenOnly || editing ? unitsList.length > 1 ? /* @__PURE__ */ jsx(Tooltip$1, {
423
423
  content: `Units: ${unitsList.join(", ")} — click to switch, or type one (24%)`,
@@ -558,6 +558,6 @@ function ScaleControl({ field, value, onChange, readOnly, id, invalid, onBlur })
558
558
  });
559
559
  }
560
560
  //#endregion
561
- export { ScaleControl };
561
+ export { ScaleControl, ScaleSlider };
562
562
 
563
563
  //# sourceMappingURL=scale.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scale.js","names":[],"sources":["../../src/controls/scale.tsx"],"sourcesContent":["/**\n * SCALE — one control, two modes (CPO D41), in the designer's CAPSULE: a muted 32px capsule, a soft fill to the value,\n * a 3px bar thumb at the fill's end (always right of the label), the label inside on the left (panels) and the value\n * inside on the right. Drag anywhere to slide (always snaps to the steps), ←→ / Home / End / PageUp / PageDown.\n * · Fixed only (default): steps snap; the readout shows the token (\"Large\"), its tooltip the size (88px); scrub it sideways.\n * · Fixed + custom (`allowCustom`): DIRECT edit, no mode switch — one click on the value puts the caret there with the\n * value selected; double-click anywhere or just start typing on the focused capsule does the same. \"24\", \"24px\", \"5%\",\n * \"xl\" apply live; Enter / Tab / blur commit, Esc reverts. The unit is plain suffix text (parsed from what you type;\n * with several units, clicking it cycles them). While typing, token chips under the capsule pick a step in one click;\n * ↑↓ step the tokens. A custom value shows a small accent dot and sits proportionally between its tokens.\n * Used by the Block Kit number control (`field.scale`, or the legacy `layout: \"slider\"`) and by the Visuals panels.\n *\n * Port of V2 HEAD 9829bf1 kit/controls/scale.tsx. V2 tokens map to the kit's (bg-muted → bg-kit-muted, --ring-focus →\n * the kit focus ring). V2's native `title=` hints become kit tooltips (the dashboard bans native title tooltips); the\n * custom value keeps ONE tooltip mounted and closes it while typing, so the input never remounts mid-edit.\n * Values are stored as they are (adapters/values.ts scaleToProd): a number, a token step's string, or { value, unit }.\n */\nimport * as React from \"react\";\nimport { Tooltip as TooltipPrimitive } from \"@base-ui/react/tooltip\";\nimport { Tooltip } from \"../ui/overlay\";\nimport { TooltipLayer, TooltipRoot } from \"../ui/tooltip-root\";\nimport { cn } from \"../lib/cn\";\nimport {\n customPx, customRules, defaultUnit, formatNumber, isCustomValue, isTokenScale, nearestTokenIndex, parseScaleInput, rangeOf, resolveScale, roundTo,\n scaleHint, UNIT_NAMES, validateCustom, fieldScale,\n} from \"../schema/scale\";\nimport type { ScaleCustomValue, ScaleSchema, ScaleUnit, ScaleValue } from \"../schema/types\";\nimport type { ControlProps } from \"../types\";\n\nexport interface ScaleSliderProps {\n scale: ScaleSchema;\n value: unknown;\n onChange: (v: ScaleValue) => void;\n /** Accessible name (the field title). */\n label: string;\n /** id for the primary control: the input when custom is allowed, otherwise the slider thumb. */\n id?: string;\n disabled?: boolean;\n readOnly?: boolean;\n invalid?: boolean;\n /** an error from outside (schema validation, a design-system demo); a parse error from typing wins */\n error?: string;\n /** \"form\" (Block Kit: label above, tick labels under the track) · \"panel\" (inspector row: inline scrub label). */\n density?: \"form\" | \"panel\";\n /** panel: show the label inline on the left (it scrubs). */\n inlineLabel?: boolean;\n icon?: React.ReactNode;\n /** panel: extra classes for the inline label. */\n labelClassName?: string;\n /** a unit word that isn't a CSS unit (\"items\", \"s\") — shown after numbers */\n suffix?: string;\n /** readout for range values (legacy `format`) */\n format?: (n: number) => string;\n onBlur?: () => void;\n /** Enter committed a typed value (custom fields) or was pressed on a fixed capsule — hosts like the canvas popover close on it */\n onEnter?: () => void;\n /** start in edit mode with the value selected (the canvas badge → in-place edit) */\n autoEdit?: boolean;\n /** Tab / Shift+Tab while typing: commit, then the host moves to the next / previous size (canvas popover sides) */\n onTab?: (dir: 1 | -1) => void;\n className?: string;\n}\n\nconst clamp = (n: number, lo: number, hi: number) => Math.min(hi, Math.max(lo, n));\n\n/** Horizontal scrubbing (Figma-style) on any element: drag → whole steps; click without moving → onClick. */\nfunction useScrub(onSteps: (delta: number, e: PointerEvent | React.PointerEvent) => void, pxPerStep: number, onClick?: () => void) {\n const st = React.useRef<{ x: number; moved: boolean; last: number } | null>(null);\n return {\n onPointerDown(e: React.PointerEvent) {\n if (e.button !== 0) return;\n e.preventDefault();\n (e.currentTarget as HTMLElement).setPointerCapture(e.pointerId);\n st.current = { x: e.clientX, moved: false, last: 0 };\n },\n onPointerMove(e: React.PointerEvent) {\n const s = st.current;\n if (!s) return;\n const dx = e.clientX - s.x;\n if (!s.moved && Math.abs(dx) < 3) return;\n s.moved = true;\n const steps = Math.trunc(dx / pxPerStep);\n if (steps !== s.last) {\n onSteps(steps - s.last, e);\n s.last = steps;\n }\n },\n onPointerUp() {\n const s = st.current;\n st.current = null;\n if (s && !s.moved) onClick?.();\n },\n onPointerCancel() {\n st.current = null;\n },\n };\n}\n\nexport function ScaleSlider({\n scale,\n value,\n onChange,\n label,\n id,\n disabled,\n readOnly,\n invalid,\n error: externalError,\n inlineLabel,\n icon,\n labelClassName,\n suffix,\n format,\n onBlur,\n onEnter,\n autoEdit,\n onTab,\n className,\n}: ScaleSliderProps) {\n const uid = React.useId();\n const errId = `scale-err-${uid}`; // must NOT start with the field id: FieldShell strips its own `${id}-…` ids\n const tokens = isTokenScale(scale) ? scale.steps : null;\n const range = rangeOf(scale);\n const custom = customRules(scale);\n const r = resolveScale(scale, value, suffix);\n const isCustom = isCustomValue(value);\n const inert = disabled || readOnly;\n\n /* ── position on the track (0..1); -1 = can't place (custom % on a px scale) ── */\n const count = tokens ? tokens.length : 0;\n const nearest = isCustom ? (tokens ? nearestTokenIndex(scale, value as ScaleCustomValue) : -1) : -1;\n let pos: number;\n if (tokens) {\n const i = isCustom ? nearest : r.index ?? 0;\n pos = i < 0 ? -1 : count > 1 ? i / (count - 1) : 0;\n } else {\n const lo = range!.min;\n const hi = range!.max;\n const n = isCustom\n ? (value as ScaleCustomValue).unit === defaultUnit(scale)\n ? (value as ScaleCustomValue).value\n : NaN\n : typeof value === \"number\"\n ? value\n : lo;\n pos = Number.isNaN(n) ? -1 : (clamp(n, lo, hi) - lo) / (hi - lo || 1);\n }\n const step = range?.step ?? 1;\n\n /* ── value moves ── */\n const tokenAt = (i: number) => tokens![clamp(i, 0, count - 1)].value;\n const currentIndex = () => (isCustom ? Math.max(0, nearest) : r.index ?? 0);\n const numAt = (n: number) => roundTo(clamp(n, range!.min, range!.max), step);\n const currentNum = () => (typeof value === \"number\" ? value : isCustom && pos >= 0 ? (value as ScaleCustomValue).value : range!.min);\n const fromFraction = (f: number): ScaleValue => (tokens ? tokenAt(Math.round(f * (count - 1))) : numAt(range!.min + f * (range!.max - range!.min)));\n const nudgeScale = (d: number): ScaleValue => (tokens ? tokenAt(currentIndex() + d) : numAt(currentNum() + d * step));\n const backToScale = (): ScaleValue => (tokens ? tokenAt(nearest >= 0 ? nearest : Math.floor((count - 1) / 2)) : numAt(currentNum()));\n const commit = (v: ScaleValue) => {\n if (inert) return;\n if (JSON.stringify(v) !== JSON.stringify(value)) onChange(v);\n };\n\n /* ── custom values sit proportionally between the tokens they fall between (px interpolation) ── */\n let between: [number, number] | null = null;\n if (tokens && isCustom) {\n const px = customPx(value as ScaleCustomValue);\n const pts = tokens.map((t, i) => ({ i, px: t.px })).filter((t): t is { i: number; px: number } => t.px != null);\n if (px != null && pts.length >= 2) {\n let f = -1;\n if (px <= pts[0].px) f = pts[0].i;\n else if (px >= pts[pts.length - 1].px) f = pts[pts.length - 1].i;\n else\n for (let k = 0; k < pts.length - 1; k++) {\n const a = pts[k];\n const b = pts[k + 1];\n if (px >= a.px && px <= b.px) {\n f = a.i + ((px - a.px) / Math.max(1, b.px - a.px)) * (b.i - a.i);\n between = [a.i, b.i];\n break;\n }\n }\n pos = f < 0 ? -1 : count > 1 ? f / (count - 1) : 0;\n }\n }\n\n /* ── geometry: the fill starts AFTER the inline label, so the thumb never sits on the label ── */\n const trackRef = React.useRef<HTMLDivElement>(null);\n const thumbRef = React.useRef<HTMLDivElement>(null);\n const labelRef = React.useRef<HTMLSpanElement>(null);\n const [labelW, setLabelW] = React.useState(28);\n const valueRef = React.useRef<HTMLSpanElement>(null);\n const [valueW, setValueW] = React.useState(40);\n React.useLayoutEffect(() => {\n const el = valueRef.current;\n if (!el) return;\n const measure = () => setValueW(Math.ceil(el.getBoundingClientRect().width));\n measure();\n const ro = new ResizeObserver(measure);\n ro.observe(el);\n return () => ro.disconnect();\n }, [custom]);\n React.useLayoutEffect(() => {\n const el = labelRef.current;\n if (!el) return setLabelW(28);\n const measure = () => setLabelW(Math.max(28, Math.ceil(el.getBoundingClientRect().width) + 4));\n measure();\n const ro = new ResizeObserver(measure);\n ro.observe(el);\n return () => ro.disconnect();\n }, [inlineLabel, label]);\n const [dragging, setDragging] = React.useState(false);\n /* keyboard-only ring: follows the app's data-input-modality (D29), never after a click */\n const [kbFocus, setKbFocus] = React.useState(false);\n const fracFromX = (x: number) => {\n const rect = trackRef.current!.getBoundingClientRect();\n return clamp((x - rect.left - labelW) / Math.max(1, rect.width - labelW), 0, 1);\n };\n\n /* ── direct edit (custom fields): click the value, double-click anywhere, or just type ── */\n const inputRef = React.useRef<HTMLInputElement>(null);\n const [draft, setDraft] = React.useState<string | null>(null);\n const [typedError, setError] = React.useState<string | null>(null);\n const error = typedError ?? externalError ?? null;\n const [unitHint, setUnitHint] = React.useState<ScaleUnit | undefined>(undefined);\n const [editing, setEditing] = React.useState(false);\n const editStart = React.useRef<unknown>(value);\n const justBegan = React.useRef(false); // the click that opened editing must not drop a caret over the selection\n const shownUnit: ScaleUnit | undefined = unitHint ?? (isCustom ? (value as ScaleCustomValue).unit : defaultUnit(scale) ?? custom?.units[0]);\n const fixedText = r.kind === \"number\" && format && typeof value === \"number\" ? format(value) : r.label;\n const valueText = isCustom ? formatNumber((value as ScaleCustomValue).value) : r.kind === \"token\" ? r.label : r.kind === \"number\" ? formatNumber(value as number) : \"\";\n const inputText = draft ?? valueText;\n const tokenOnly = !isCustom && r.kind === \"token\"; // unit suffix is meaningless next to \"Medium\"\n\n const beginEdit = (seed?: string) => {\n if (inert || !custom) return;\n if (!editing) editStart.current = value;\n setEditing(true);\n setError(null);\n const el = inputRef.current;\n if (!el) return;\n el.focus({ preventScroll: true }); // synchronous: the next keystrokes land in the input\n if (seed != null) {\n setDraft(seed);\n applyText(seed);\n requestAnimationFrame(() => inputRef.current?.setSelectionRange(seed.length, seed.length));\n } else {\n el.select();\n justBegan.current = true;\n }\n };\n const endEdit = (how: \"commit\" | \"revert\", focusThumb: boolean) => {\n if (how === \"revert\") commit(editStart.current as ScaleValue);\n setDraft(null);\n setError(null);\n setUnitHint(undefined);\n setEditing(false);\n if (focusThumb) thumbRef.current?.focus({ preventScroll: true });\n };\n /** Applies what's typed LIVE when it parses; otherwise shows the reason and keeps the last good value. */\n function applyText(text: string, showError = false) {\n if (!text.trim()) return setError(null);\n const res = parseScaleInput(scale, text, unitHint);\n if (res.ok) {\n setError(null);\n commit(res.value);\n return true;\n }\n // half-typed (\"x\" on the way to \"xl\") stays quiet; the reason shows when you try to commit\n setError(showError ? res.error : null);\n return false;\n }\n /** ↑↓ while editing: step the tokens (from a custom value, the next token in that direction). */\n const stepTokens = (dir: 1 | -1, e: { shiftKey: boolean }) => {\n if (tokens && isCustom) {\n const lo = between ? between[0] : nearest;\n const hi = between ? between[1] : nearest;\n commit(tokenAt(dir > 0 ? (between ? hi : nearest + 1) : between ? lo : nearest - 1));\n } else commit(nudgeScale(dir * (!tokens && e.shiftKey ? 10 : 1)));\n setDraft(null);\n setError(null);\n };\n /* keep the field's text in sync with outside changes (drag, undo) while not typing: adjusted during render when the\n value changes (V2 did this in an effect keyed on `value`) */\n const valueKey = JSON.stringify(value ?? null);\n const [seenValue, setSeenValue] = React.useState(valueKey);\n if (seenValue !== valueKey) {\n setSeenValue(valueKey);\n if (draft == null && !externalError && typedError !== null) setError(null);\n }\n\n const unitsList = custom?.units ?? [];\n const cycleUnit = () => {\n if (inert || unitsList.length < 2) return;\n const cur = shownUnit && unitsList.includes(shownUnit) ? shownUnit : unitsList[0];\n const next = unitsList[(unitsList.indexOf(cur) + 1) % unitsList.length];\n setUnitHint(next);\n if (isCustom) {\n const cv: ScaleCustomValue = { value: (value as ScaleCustomValue).value, unit: next };\n // 720px → % would be out of range: keep the value, select the number and let the next keystrokes be in the new unit\n if (validateCustom(scale, cv)) beginEdit();\n else {\n setError(null);\n commit(cv);\n }\n } else beginEdit();\n };\n\n const onTrackKey = (e: React.KeyboardEvent) => {\n if (inert) return;\n /* just start typing: a digit, a dot or a letter opens the value with that character */\n if (custom && !e.metaKey && !e.ctrlKey && !e.altKey && e.key.length === 1 && /[0-9.a-z%]/i.test(e.key)) {\n e.preventDefault();\n beginEdit(e.key);\n return;\n }\n if (e.key === \"Enter\" && onEnter) {\n e.preventDefault();\n onEnter();\n return;\n }\n const big = tokens ? 2 : Math.max(1, Math.round((range!.max - range!.min) / step / 10));\n const mult = e.shiftKey && !tokens ? 10 : 1;\n let next: ScaleValue | null = null;\n if (e.key === \"ArrowRight\" || e.key === \"ArrowUp\") next = isCustom ? (tokens ? tokenAt(between ? between[1] : nearest + 1) : backToScale()) : nudgeScale(mult);\n else if (e.key === \"ArrowLeft\" || e.key === \"ArrowDown\") next = isCustom ? (tokens ? tokenAt(between ? between[0] : nearest - 1) : backToScale()) : nudgeScale(-mult);\n else if (e.key === \"PageUp\") next = nudgeScale(big);\n else if (e.key === \"PageDown\") next = nudgeScale(-big);\n else if (e.key === \"Home\") next = tokens ? tokenAt(0) : range!.min;\n else if (e.key === \"End\") next = tokens ? tokenAt(count - 1) : range!.max;\n if (next == null) return;\n e.preventDefault();\n commit(next);\n };\n\n /* aria-describedby: add/remove our error id without clobbering the ids FieldShell wires (help, ⓘ, issue). */\n React.useEffect(() => {\n for (const el of [inputRef.current, thumbRef.current]) {\n if (!el) continue;\n const own = (el.getAttribute(\"aria-describedby\") ?? \"\").split(\" \").filter((t) => t && t !== errId);\n const next = error ? [...own, errId] : own;\n if (next.length) el.setAttribute(\"aria-describedby\", next.join(\" \"));\n else el.removeAttribute(\"aria-describedby\");\n }\n }, [error, errId, editing]);\n\n React.useEffect(() => {\n // eslint-disable-next-line react-hooks/set-state-in-effect -- autoEdit focuses the input on mount (a DOM sync), once\n if (autoEdit) beginEdit();\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, []);\n\n /* fixed fields: scrub the readout sideways (Figma-style) */\n const scrubPx = tokens ? 16 : Math.max(3, Math.min(12, 160 / ((range!.max - range!.min) / step)));\n const readoutScrub = useScrub((delta, e) => !inert && commit(nudgeScale(delta * (!tokens && e.shiftKey ? 10 : 1))), scrubPx);\n\n const betweenText = isCustom\n ? tokens && between\n ? `Custom value · between ${tokens[between[0]].label} and ${tokens[between[1]].label}`\n : tokens && nearest >= 0\n ? `Custom value · near ${tokens[nearest].label}`\n : \"Custom value\"\n : undefined;\n const pct = Math.max(0, pos);\n const fillW = `calc(${labelW}px + (100% - ${labelW}px) * ${pct})`;\n const tooltip = r.kind === \"token\" && r.css ? scaleHint(r) : betweenText;\n const presets = custom ? scale.presets ?? [] : [];\n const showChips = editing && ((!!tokens && count <= 9) || presets.length > 0);\n\n return (\n <div className={cn(\"min-w-0\", className)} data-scale-mode={custom ? \"custom\" : \"fixed\"}>\n <div\n ref={trackRef}\n onPointerDown={(e) => {\n if (inert || e.button !== 0) return;\n if ((e.target as HTMLElement).closest(\"[data-scale-value]\")) return; // the value area edits, it doesn't scrub\n e.preventDefault();\n (e.currentTarget as HTMLElement).setPointerCapture(e.pointerId);\n setDragging(true);\n setKbFocus(false);\n if (editing) endEdit(\"commit\", false);\n commit(fromFraction(fracFromX(e.clientX)));\n thumbRef.current?.focus({ preventScroll: true });\n }}\n onPointerMove={(e) => dragging && commit(fromFraction(fracFromX(e.clientX)))}\n onPointerUp={() => setDragging(false)}\n onPointerCancel={() => setDragging(false)}\n onDoubleClick={() => beginEdit()}\n className={cn(\n \"group/cap relative flex h-8 w-full touch-none select-none items-center overflow-hidden rounded-kit-md bg-kit-muted transition-[background-color,box-shadow]\",\n inert ? \"cursor-not-allowed\" : \"cursor-ew-resize hover:bg-kit-hover\",\n disabled && \"opacity-50\",\n /* neutral, keyboard-only ring (never after a click); a quiet 1px inner line while typing; red only for an error */\n kbFocus && !editing && !error && \"shadow-[var(--kit-ring-focus,0_0_0_2px_var(--kit-surface),0_0_0_4px_var(--kit-focus-ring))]\",\n editing && !error && \"shadow-[inset_0_0_0_1px_var(--kit-line-strong)]\",\n error && \"shadow-[inset_0_0_0_1px_var(--kit-danger)]\",\n )}\n >\n {pos >= 0 ? (\n <div\n aria-hidden\n className={cn(\n \"absolute inset-y-0 left-0 rounded-l-kit-md bg-[color-mix(in_oklab,var(--kit-fg)_9%,transparent)]\",\n !dragging && \"motion-safe:transition-[width] motion-safe:duration-75\",\n )}\n style={{ width: fillW }}\n />\n ) : null}\n {/* thumb = the designer's 3px bar at the fill's end — always right of the label; it is the focusable slider */}\n <div\n ref={thumbRef}\n id={custom ? undefined : id}\n role=\"slider\"\n tabIndex={disabled ? -1 : 0}\n aria-label={label}\n aria-valuemin={tokens ? 0 : range!.min}\n aria-valuemax={tokens ? count - 1 : range!.max}\n aria-valuenow={tokens ? currentIndex() : clamp(currentNum(), range!.min, range!.max)}\n aria-valuetext={r.spoken}\n aria-disabled={disabled || undefined}\n aria-readonly={readOnly || undefined}\n aria-invalid={(!custom && invalid) || undefined}\n aria-orientation=\"horizontal\"\n onKeyDown={(e) => {\n setKbFocus(true);\n onTrackKey(e);\n }}\n onFocus={() => setKbFocus(document.documentElement.dataset.inputModality === \"keyboard\")}\n onBlur={() => {\n setKbFocus(false);\n onBlur?.();\n }}\n className={cn(\n // cursor-[inherit]: V2's thumb takes the capsule's ew-resize; the dash cursor contract would give [role=slider] a pointer\n \"absolute top-1/2 z-[1] h-4 w-[3px] -translate-x-full -translate-y-1/2 cursor-[inherit] rounded-full bg-kit-fg-3 opacity-0 outline-none focus-visible:!shadow-none focus-visible:!outline-none\",\n !inert && \"group-hover/cap:opacity-100\",\n \"focus-visible:opacity-100\",\n dragging && \"opacity-100\",\n (pos < 0 || editing) && \"!opacity-0\",\n !dragging && \"motion-safe:transition-[left,opacity] motion-safe:duration-75\",\n )}\n style={{ left: `min(calc(${fillW} - 4px), calc(100% - ${valueW}px - 2px))` /* never on the label, never on the value */ }}\n />\n {inlineLabel ? (\n <span ref={labelRef} className={cn(\"pointer-events-none relative z-[2] flex min-w-0 shrink items-center gap-1.5 pl-3 pr-1 text-kit-xs text-kit-fg-2 [&_svg]:size-3.5\", labelClassName)}>\n {icon}\n <span className=\"truncate\">{label}</span>\n </span>\n ) : null}\n <span className=\"flex-1\" />\n\n {/* value — inside the capsule on the right */}\n {custom ? (\n /* one tooltip stays mounted and closes while typing, so the input never remounts mid-edit */\n <StableTip content={tooltip} off={editing}>\n <span\n ref={valueRef}\n data-scale-value\n onPointerDown={(e) => {\n if (inert || e.button !== 0) return;\n e.stopPropagation();\n if (!editing) {\n e.preventDefault();\n beginEdit(); // one click: caret in place, the value selected\n }\n }}\n onMouseUp={(e) => {\n if (!justBegan.current) return;\n justBegan.current = false;\n e.preventDefault();\n inputRef.current?.select();\n }}\n onMouseDown={(e) => {\n // the browser's own mousedown focus would pull focus back off the input we just focused\n if (!editing || e.target !== inputRef.current) e.preventDefault();\n }}\n className={cn(\"relative z-[2] flex h-full shrink-0 items-center gap-1 pl-2 pr-3\", !inert && \"cursor-text\")}\n >\n {isCustom && !editing ? <span aria-hidden className=\"size-1.5 shrink-0 rounded-full bg-kit-accent\" /> : null}\n <input\n ref={inputRef}\n id={id}\n inputMode=\"text\"\n autoComplete=\"off\"\n spellCheck={false}\n aria-label={`${label} value`}\n aria-description={betweenText}\n aria-invalid={!!error || invalid || undefined}\n readOnly={readOnly}\n disabled={disabled}\n tabIndex={-1}\n value={inputText}\n size={1}\n style={{ width: `${Math.max(1, inputText.length) + 0.5}ch` }}\n onFocus={() => {\n if (!editing) beginEdit();\n }}\n onBlur={() => {\n if (!editing) return;\n if (draft != null && draft.trim() && !parseScaleInput(scale, draft, unitHint).ok) endEdit(\"revert\", false);\n else endEdit(\"commit\", false);\n onBlur?.();\n }}\n onChange={(e) => {\n setDraft(e.target.value);\n applyText(e.target.value);\n }}\n onWheel={(e) => e.currentTarget.blur()}\n onKeyDown={(e) => {\n e.stopPropagation();\n if (e.key === \"Tab\" && onTab) {\n e.preventDefault();\n if (draft != null && !applyText(draft, true)) return; // stay and fix it\n endEdit(\"commit\", false);\n onTab(e.shiftKey ? -1 : 1);\n } else if (e.key === \"Enter\") {\n e.preventDefault();\n if (draft != null && !applyText(draft, true)) return; // stay and fix it\n endEdit(\"commit\", true);\n onEnter?.();\n } else if (e.key === \"Escape\") {\n e.preventDefault();\n endEdit(\"revert\", true);\n } else if (e.key === \"ArrowUp\" || e.key === \"ArrowDown\") {\n e.preventDefault();\n stepTokens(e.key === \"ArrowUp\" ? 1 : -1, e);\n }\n }}\n className={cn(\n \"tabular-nums h-6 min-w-0 bg-transparent p-0 text-right text-kit-xs text-kit-fg outline-none placeholder:text-kit-fg-4 focus:shadow-none focus-visible:shadow-none selection:bg-kit-selected\",\n isCustom || editing ? \"font-normal\" : \"font-medium\",\n !editing && \"pointer-events-none\",\n )}\n />\n {!tokenOnly || editing ? (\n unitsList.length > 1 ? (\n <Tooltip content={`Units: ${unitsList.join(\", \")} — click to switch, or type one (24%)`}>\n <button\n type=\"button\"\n tabIndex={-1}\n disabled={inert}\n onPointerDown={(e) => {\n e.stopPropagation();\n e.preventDefault(); // keep the caret in the value\n }}\n onClick={cycleUnit}\n aria-label={`Unit: ${shownUnit ? UNIT_NAMES[shownUnit] : \"none\"}. Switch unit`}\n className=\"rounded-kit-xs text-kit-xs text-kit-fg-3 transition-colors hover:text-kit-fg\"\n >\n {shownUnit}\n </button>\n </Tooltip>\n ) : (\n <span aria-hidden className=\"text-kit-xs text-kit-fg-3\">{shownUnit}</span>\n )\n ) : null}\n </span>\n </StableTip>\n ) : (\n <Tooltip content={tooltip}>\n <span\n ref={valueRef}\n aria-hidden\n {...(inert ? {} : readoutScrub)}\n className={cn(\"relative z-[2] whitespace-nowrap pl-2 pr-3 text-kit-xs font-medium tabular-nums text-kit-fg\", !inert && \"cursor-ew-resize\")}\n >\n {fixedText}\n </span>\n </Tooltip>\n )}\n </div>\n\n {/* quick tokens while typing — one click picks a step and leaves edit mode */}\n {showChips ? (\n <div role=\"group\" aria-label={`${label} steps`} className=\"mt-1 flex flex-wrap items-center gap-0.5\">\n {(tokens && count <= 9 ? tokens : []).map((t, i) => {\n const on = !isCustom && r.index === i;\n return (\n <Tooltip key={t.value} content={t.px != null ? `${t.title ?? t.label} · ${t.px}px` : t.css ? `${t.title ?? t.label} · ${t.css}` : t.title}>\n <button\n type=\"button\"\n tabIndex={-1}\n aria-pressed={on}\n onPointerDown={(e) => e.preventDefault() /* keep the caret until the click lands */}\n onClick={() => {\n commit(t.value);\n endEdit(\"commit\", true);\n }}\n className={cn(\n \"h-5 rounded-kit-sm px-1.5 text-kit-2xs transition-colors\",\n on ? \"bg-kit-selected font-medium text-kit-fg\" : \"text-kit-fg-3 hover:bg-kit-hover hover:text-kit-fg\",\n )}\n >\n {shortToken(t.label)}\n </button>\n </Tooltip>\n );\n })}\n {/* developer presets: extra quick picks after the steps, behind a hairline */}\n {presets.length ? (\n <>\n {tokens && count <= 9 ? <span aria-hidden className=\"mx-1 h-3 w-px bg-kit-line-strong\" /> : null}\n {presets.map((p, i) => {\n const pr = resolveScale(scale, p.value, suffix);\n const on = JSON.stringify(p.value) === JSON.stringify(value);\n return (\n <Tooltip key={`preset-${i}`} content={p.label ? `${p.label} · ${pr.label}` : pr.label}>\n <button\n type=\"button\"\n tabIndex={-1}\n aria-pressed={on}\n onPointerDown={(e) => e.preventDefault()}\n onClick={() => {\n commit(p.value);\n endEdit(\"commit\", true);\n }}\n className={cn(\"h-5 rounded-kit-sm px-1.5 text-kit-2xs tabular-nums transition-colors\", on ? \"bg-kit-selected font-medium text-kit-fg\" : \"text-kit-fg-3 hover:bg-kit-hover hover:text-kit-fg\")}\n >\n {pr.label}\n </button>\n </Tooltip>\n );\n })}\n </>\n ) : null}\n </div>\n ) : null}\n {error ? (\n <p id={errId} role=\"status\" aria-live=\"polite\" className=\"mt-1 text-kit-xs text-kit-danger-fg\">\n {error}\n </p>\n ) : null}\n </div>\n );\n}\n\n/**\n * A tooltip whose trigger never changes tree shape: `off` (typing) or no content keeps it closed instead of unwrapping\n * the child, which would remount the input inside it and drop the caret.\n */\nfunction StableTip({ content, off, children }: { content?: string; off?: boolean; children: React.ReactElement }) {\n const closed = off || !content;\n return (\n <TooltipRoot open={closed ? false : undefined}>\n <TooltipPrimitive.Trigger delay={350} render={children} />\n <TooltipLayer>\n <span className=\"line-clamp-[8] min-w-0 whitespace-normal [overflow-wrap:anywhere]\">{content}</span>\n </TooltipLayer>\n </TooltipRoot>\n );\n}\n\n/** \"Medium\" → \"M\", \"Extra large\"/\"XL\" → \"XL\", \"Full bleed\" stays readable. */\nfunction shortToken(label: string) {\n const map: Record<string, string> = { None: \"0\", Small: \"S\", Medium: \"M\", Large: \"L\" };\n return map[label] ?? label;\n}\n\n/** Block Kit adapter: `field.scale` (or legacy `layout: \"slider\"` + numeric). */\nexport function ScaleControl({ field, value, onChange, readOnly, id, invalid, onBlur }: ControlProps) {\n const scale = fieldScale(field)!;\n const unit = field.numeric?.unit;\n const suffix = unit && ![\"px\", \"%\", \"rem\", \"em\", \"vw\", \"vh\"].includes(unit) ? unit : undefined;\n return (\n <ScaleSlider\n scale={scale}\n value={value ?? field.initialValue}\n onChange={(v) => onChange(v)}\n label={field.title}\n id={id}\n readOnly={readOnly}\n invalid={invalid}\n suffix={suffix}\n onBlur={onBlur}\n density=\"form\"\n />\n );\n}\n"],"mappings":"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"}
@@ -2,7 +2,7 @@ import { JsonControl } from "./json.js";
2
2
  import { CONTROLS } from "../engine/kit-field.js";
3
3
  import { ComponentSlotControl } from "./slot.js";
4
4
  import { createElement } from "react";
5
- //#region src/kit/controls/slot-register.ts
5
+ //#region src/controls/slot-register.ts
6
6
  /**
7
7
  * Lane L3: a component slot (a json field the host marks `componentSlot`) draws the slot control; every other json
8
8
  * field keeps the json editor. Imported after json-register (kit barrel), so it wraps the registered json control.
@@ -0,0 +1 @@
1
+ {"version":3,"file":"slot-register.js","names":[],"sources":["../../src/controls/slot-register.ts"],"sourcesContent":["/**\n * Lane L3: a component slot (a json field the host marks `componentSlot`) draws the slot control; every other json\n * field keeps the json editor. Imported after json-register (kit barrel), so it wraps the registered json control.\n */\nimport { createElement } from \"react\";\nimport type { ControlProps } from \"../types\";\nimport { CONTROLS } from \"../engine/kit-field\";\nimport { JsonControl } from \"./json\";\nimport { ComponentSlotControl } from \"./slot\";\n\nconst Json = CONTROLS.json ?? JsonControl;\nCONTROLS.json = function JsonOrSlotControl(props: ControlProps) {\n return createElement(props.field.componentSlot ? ComponentSlotControl : Json, props);\n};\n"],"mappings":";;;;;;;;;AAUA,IAAM,OAAO,SAAS,QAAQ;AAC9B,SAAS,OAAO,SAAS,kBAAkB,OAAqB;CAC9D,OAAO,cAAc,MAAM,MAAM,gBAAgB,uBAAuB,MAAM,KAAK;AACrF"}