@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":"editor.js","names":[],"sources":["../../../src/controls/rich-text/editor.tsx"],"sourcesContent":["/**\n * RICH TEXT — the boxed rich-text editor (V2 HEAD controls/rich-text-editor.tsx, Figma 60995-5431, CPO D49 / D54 / D55).\n *\n * contentEditable + execCommand keeps it dependency-free; the value is clean HTML, which the field's control turns into\n * the stored value through the host's codec (./codec.ts). Rich blocks (an image) are React \"islands\" rendered into\n * contenteditable=false nodes and written back as static HTML, so a re-mount restores them (./dom.ts).\n *\n * ./toolbar.tsx the field toolbar (no room at rest, folds into the chevron by width)\n * ./catalog.tsx Insert menu, slash menu and the shared block catalogue\n * ./blocks.tsx the rich blocks (an image)\n * ./markdown.ts HTML ⇄ Markdown for the Markdown toggle and pasting\n * ./ops.ts pure DOM block operations (insert, turn into, move, duplicate, live Markdown, field rules)\n * ./floating.tsx the selection bubble\n * ./dom.ts hydrate / serialize / sanitize and selection helpers\n *\n * Everything the editor offers is limited to what the field accepts (`features`): a toolbar button, a slash command, a\n * Markdown shortcut or pasted markup the field cannot hold is not offered, or is turned into what it can hold and said so.\n */\nimport * as React from \"react\";\nimport { createPortal, flushSync } from \"react-dom\";\nimport { AnimatePresence, motion, useReducedMotion } from \"framer-motion\";\nimport { IconArrowBarToDown, IconArrowBarToUp, IconCopy, IconGripVertical, IconPlus, IconTransform, IconTrash } from \"@tabler/icons-react\";\nimport { cn } from \"../../lib/cn\";\nimport { eventKey } from \"../../lib/key-event\";\nimport { useKitEnv, useKitServices, type AiPreset } from \"../../context\";\nimport { Button } from \"../../ui/button\";\nimport { Textarea } from \"../../ui/input\";\nimport { ExpandedEditorModal } from \"../../ui/expanded-editor-modal\";\nimport { Menu, MenuContent, MenuItem, MenuSeparator, MenuSub, MenuSubContent, MenuSubTrigger, MenuTrigger, Popover, PopoverAnchor, PopoverContent, PopoverTrigger, Tooltip } from \"../../ui/overlay\";\nimport { shortcutHintsOn } from \"../../ui/shortcut-hint\";\nimport { ALL_FEATURES, type RichTextFeature } from \"./codec\";\nimport { COMPONENT_INSERT_TOAST, type KitHistoryStep } from \"../component-services\";\nimport { Island, type IslandCtx } from \"./blocks\";\nimport { openComponentPanel } from \"./component-panel\";\nimport { CatalogComponentsProvider, InsertMenuContent, SlashMenuPanel, blockAllowed, catalogKey, noteRecent, useCatalog, type CatalogComponents, type CatalogItem } from \"./catalog\";\nimport {\n closestBlock, createIsland, defaultModel, editingHost, esc, hydrate, isEmptyHtml, placeCaret, rangeRect, rid, sanitize,\n serialize, textBeforeCaret, topBlock, type IslandEl, type IslandModels, type IslandKind,\n} from \"./dom\";\nimport { htmlToMarkdown, looksLikeMarkdown, markdownToHtml } from \"./markdown\";\nimport * as ops from \"./ops\";\nimport { SelectionBubble } from \"./floating\";\nimport { LinkForm, type TextLink } from \"./link-form\";\nimport { EMPTY_FMT, FormatToolbar, MARK_FEATURE, stylesFor, type Fmt, type MarkCmd } from \"./toolbar\";\n\n/* ── Prose styles for the editable surface (kit tokens only) ──\n * Every descendant rule skips `[data-rt-isolate]` subtrees, as V2's (rich-text-editor.tsx:46-58): a block's own UI inside\n * the writing surface (a table island's column headers, a component card's form) is app UI, not prose. */\nexport const RT_PROSE =\n \"text-kit-base leading-[1.6] text-kit-fg [&>*+*]:mt-3 \" +\n // BUG-7: a styled run keeps the SITE's class (the stored design), but the site's stylesheet is not here. Only the\n // utilities the dashboard happens to build apply: `text-transparent` without its `bg-clip-text` gradient drew the\n // words invisible. The run's text is drawn as text; the class itself is kept, so a save writes it back unchanged.\n \"[&_span[class]:not([data-rt-isolate]_*)]:!text-inherit [&_span[class]:not([data-rt-isolate]_*)]:![-webkit-text-fill-color:currentColor] [&_span[class]:not([data-rt-isolate]_*)]:!bg-none [&_span[class]:not([data-rt-isolate]_*)]:!opacity-100 [&_span[class]:not([data-rt-isolate]_*)]:!visible \" +\n \"[&_h1:not([data-rt-isolate]_*)]:text-[28px] [&_h1:not([data-rt-isolate]_*)]:font-semibold [&_h1:not([data-rt-isolate]_*)]:leading-9 [&_h1:not([data-rt-isolate]_*)]:tracking-[-0.01em] [&_h2:not([data-rt-isolate]_*)]:text-[22px] [&_h2:not([data-rt-isolate]_*)]:font-semibold [&_h2:not([data-rt-isolate]_*)]:leading-8 [&_h2:not([data-rt-isolate]_*)]:tracking-[-0.01em] \" +\n \"[&_h3:not([data-rt-isolate]_*)]:text-kit-lg [&_h3:not([data-rt-isolate]_*)]:font-semibold [&_h4:not([data-rt-isolate]_*)]:text-kit-md [&_h4:not([data-rt-isolate]_*)]:font-semibold [&_h5:not([data-rt-isolate]_*)]:text-kit-base [&_h5:not([data-rt-isolate]_*)]:font-semibold [&_h6:not([data-rt-isolate]_*)]:text-kit-sm [&_h6:not([data-rt-isolate]_*)]:font-semibold [&_h6:not([data-rt-isolate]_*)]:uppercase [&_h6:not([data-rt-isolate]_*)]:tracking-wide [&_h6:not([data-rt-isolate]_*)]:text-kit-fg-2 [&>h1]:mt-6 [&>h2]:mt-6 [&>h3]:mt-5 [&>*:first-child]:mt-0 \" +\n // a block's own list (key takeaways, V2 data-rt-isolate) is app UI, not body prose: V2 rich-text-editor.tsx skips it\n \"[&_ul:not([data-rt-isolate]_*)]:list-disc [&_ul:not([data-rt-isolate]_*)]:pl-5 [&_ol:not([data-rt-isolate]_*)]:list-decimal [&_ol:not([data-rt-isolate]_*)]:pl-5 [&_li:not([data-rt-isolate]_*)]:pl-1 [&_li+li:not([data-rt-isolate]_*)]:mt-1 [&_li:not([data-rt-isolate]_*)]:marker:text-kit-fg-3 \" +\n \"[&_ul[data-task]:not([data-rt-isolate]_*)]:list-none [&_ul[data-task]:not([data-rt-isolate]_*)]:pl-0 [&_ul[data-task]>li:not([data-rt-isolate]_*)]:relative [&_ul[data-task]>li:not([data-rt-isolate]_*)]:pl-7 [&_ul[data-task]>li:not([data-rt-isolate]_*)]:before:absolute [&_ul[data-task]>li:not([data-rt-isolate]_*)]:before:left-0 [&_ul[data-task]>li:not([data-rt-isolate]_*)]:before:top-[0.2em] [&_ul[data-task]>li:not([data-rt-isolate]_*)]:before:flex [&_ul[data-task]>li:not([data-rt-isolate]_*)]:before:size-4 [&_ul[data-task]>li:not([data-rt-isolate]_*)]:before:items-center [&_ul[data-task]>li:not([data-rt-isolate]_*)]:before:justify-center [&_ul[data-task]>li:not([data-rt-isolate]_*)]:before:rounded-kit-md [&_ul[data-task]>li:not([data-rt-isolate]_*)]:before:border [&_ul[data-task]>li:not([data-rt-isolate]_*)]:before:border-kit-line-strong [&_ul[data-task]>li:not([data-rt-isolate]_*)]:before:bg-kit-surface [&_ul[data-task]>li:not([data-rt-isolate]_*)]:before:text-[11px] [&_ul[data-task]>li:not([data-rt-isolate]_*)]:before:font-semibold [&_ul[data-task]>li:not([data-rt-isolate]_*)]:before:leading-none [&_ul[data-task]>li:not([data-rt-isolate]_*)]:before:content-[''] \" +\n \"[&_ul[data-task]>li[data-checked=true]:not([data-rt-isolate]_*)]:text-kit-fg-3 [&_ul[data-task]>li[data-checked=true]:not([data-rt-isolate]_*)]:line-through [&_ul[data-task]>li[data-checked=true]:not([data-rt-isolate]_*)]:before:border-kit-inverse [&_ul[data-task]>li[data-checked=true]:not([data-rt-isolate]_*)]:before:bg-kit-inverse [&_ul[data-task]>li[data-checked=true]:not([data-rt-isolate]_*)]:before:text-kit-fg-inverse [&_ul[data-task]>li[data-checked=true]:not([data-rt-isolate]_*)]:before:content-['✓'] \" +\n \"[&_blockquote:not([data-rt-isolate]_*)]:border-l-2 [&_blockquote:not([data-rt-isolate]_*)]:border-kit-line-strong [&_blockquote:not([data-rt-isolate]_*)]:pl-4 [&_blockquote:not([data-rt-isolate]_*)]:text-kit-fg-2 [&_blockquote:not([data-rt-isolate]_*)]:italic \" +\n \"[&_a:not([data-rt-isolate]_*)]:text-kit-accent-fg [&_a:not([data-rt-isolate]_*)]:underline [&_a:not([data-rt-isolate]_*)]:decoration-kit-accent-line [&_a:not([data-rt-isolate]_*)]:underline-offset-2 \" +\n \"[&_a[data-button]:not([data-rt-isolate]_*)]:inline-flex [&_a[data-button]:not([data-rt-isolate]_*)]:h-9 [&_a[data-button]:not([data-rt-isolate]_*)]:items-center [&_a[data-button]:not([data-rt-isolate]_*)]:rounded-kit-md [&_a[data-button]:not([data-rt-isolate]_*)]:bg-kit-inverse [&_a[data-button]:not([data-rt-isolate]_*)]:px-3.5 [&_a[data-button]:not([data-rt-isolate]_*)]:text-kit-sm [&_a[data-button]:not([data-rt-isolate]_*)]:font-medium [&_a[data-button]:not([data-rt-isolate]_*)]:text-kit-fg-inverse [&_a[data-button]:not([data-rt-isolate]_*)]:no-underline \" +\n // a glossary term (`<abbr data-term title>`) reads as a dotted underline; a footnote marker as a small superscript\n \"[&_abbr:not([data-rt-isolate]_*)]:cursor-help [&_abbr:not([data-rt-isolate]_*)]:underline [&_abbr:not([data-rt-isolate]_*)]:decoration-dotted [&_abbr:not([data-rt-isolate]_*)]:underline-offset-2 [&_sup:not([data-rt-isolate]_*)]:text-[0.7em] [&_sup:not([data-rt-isolate]_*)]:leading-none \" +\n \"[&_code:not([data-rt-isolate]_*)]:rounded-kit-md [&_code:not([data-rt-isolate]_*)]:bg-kit-muted [&_code:not([data-rt-isolate]_*)]:px-1 [&_code:not([data-rt-isolate]_*)]:py-px [&_code:not([data-rt-isolate]_*)]:font-kit-mono [&_code:not([data-rt-isolate]_*)]:text-[0.9em] \" +\n \"[&_pre:not([data-rt-isolate]_*)]:overflow-x-auto [&_pre:not([data-rt-isolate]_*)]:whitespace-pre-wrap [&_pre:not([data-rt-isolate]_*)]:rounded-kit-lg [&_pre:not([data-rt-isolate]_*)]:bg-kit-code [&_pre:not([data-rt-isolate]_*)]:text-kit-code-fg [&_pre:not([data-rt-isolate]_*)]:p-3 [&_pre:not([data-rt-isolate]_*)]:font-kit-mono [&_pre:not([data-rt-isolate]_*)]:text-kit-sm [&_pre:not([data-rt-isolate]_*)]:border [&_pre:not([data-rt-isolate]_*)]:border-kit-line \" +\n \"[&_pre_code:not([data-rt-isolate]_*)]:rounded-none [&_pre_code:not([data-rt-isolate]_*)]:bg-transparent [&_pre_code:not([data-rt-isolate]_*)]:p-0 [&_pre_code:not([data-rt-isolate]_*)]:text-[1em] \" +\n \"[&_hr:not([data-rt-isolate]_*)]:my-6 [&_hr:not([data-rt-isolate]_*)]:border-kit-line \" +\n // V2 rich-text-editor.tsx 64-65: an image's figure sits 16px off its neighbours (my-4), the picture framed\n \"[&_figure:not([data-rt-isolate]_*)]:my-4 [&_img:not([data-rt-isolate]_*)]:rounded-kit-lg [&_img:not([data-rt-isolate]_*)]:border [&_img:not([data-rt-isolate]_*)]:border-kit-line [&_figcaption:not([data-rt-isolate]_*)]:mt-1.5 [&_figcaption:not([data-rt-isolate]_*)]:text-center [&_figcaption:not([data-rt-isolate]_*)]:text-kit-sm [&_figcaption:not([data-rt-isolate]_*)]:text-kit-fg-3 \" +\n \"[&_figure_img:not([data-rt-isolate]_*)]:block [&_figure[data-size=s]_img:not([data-rt-isolate]_*)]:w-1/3 [&_figure[data-size=m]_img:not([data-rt-isolate]_*)]:w-1/2 [&_figure[data-size=l]_img:not([data-rt-isolate]_*)]:w-3/4 [&_figure[data-align=center]_img:not([data-rt-isolate]_*)]:mx-auto [&_figure[data-align=right]_img:not([data-rt-isolate]_*)]:ml-auto [&_figure[data-align=full]_img:not([data-rt-isolate]_*)]:w-full \" +\n \"[&_div[data-callout]:not([data-rt-isolate]_*)]:rounded-kit-lg [&_div[data-callout]:not([data-rt-isolate]_*)]:border [&_div[data-callout]:not([data-rt-isolate]_*)]:border-kit-info-line [&_div[data-callout]:not([data-rt-isolate]_*)]:bg-kit-info-soft [&_div[data-callout]:not([data-rt-isolate]_*)]:px-4 [&_div[data-callout]:not([data-rt-isolate]_*)]:py-3 [&_div[data-callout]:not([data-rt-isolate]_*)]:text-kit-fg \" +\n \"[&_div[data-callout=tip]:not([data-rt-isolate]_*)]:border-kit-success-line [&_div[data-callout=tip]:not([data-rt-isolate]_*)]:bg-kit-success-soft [&_div[data-callout=warning]:not([data-rt-isolate]_*)]:border-kit-warning-line [&_div[data-callout=warning]:not([data-rt-isolate]_*)]:bg-kit-warning-soft [&_div[data-callout]>p[data-title]:not([data-rt-isolate]_*)]:font-medium \" +\n \"[&_details:not([data-rt-isolate]_*)]:rounded-kit-md [&_summary:not([data-rt-isolate]_*)]:cursor-pointer [&_summary:not([data-rt-isolate]_*)]:font-medium [&_details>div:not([data-rt-isolate]_*)]:mt-1 [&_details>div:not([data-rt-isolate]_*)]:border-l [&_details>div:not([data-rt-isolate]_*)]:border-kit-line [&_details>div:not([data-rt-isolate]_*)]:pl-4 [&_details>div:not([data-rt-isolate]_*)]:ml-1 \" +\n \"[&_div[data-rt=columns]:not([data-rt-isolate]_*)]:grid [&_div[data-rt=columns]:not([data-rt-isolate]_*)]:gap-4 [&_div[data-cols='2']:not([data-rt-isolate]_*)]:grid-cols-2 [&_div[data-cols='3']:not([data-rt-isolate]_*)]:grid-cols-3 [&_div[data-cols='4']:not([data-rt-isolate]_*)]:grid-cols-4 [&_div[data-gap=s]:not([data-rt-isolate]_*)]:gap-2 [&_div[data-gap=l]:not([data-rt-isolate]_*)]:gap-7 \" +\n \"[&_div[data-rt=file]:not([data-rt-isolate]_*)]:rounded-kit-lg [&_div[data-rt=file]:not([data-rt-isolate]_*)]:border [&_div[data-rt=file]:not([data-rt-isolate]_*)]:border-kit-line [&_div[data-rt=file]:not([data-rt-isolate]_*)]:px-3 [&_div[data-rt=file]:not([data-rt-isolate]_*)]:py-2.5 [&_div[data-rt=file]:not([data-rt-isolate]_*)]:text-kit-sm \" +\n \"[&_div[data-embed]:not([data-rt-isolate]_*)]:flex [&_div[data-embed]:not([data-rt-isolate]_*)]:aspect-video [&_div[data-embed]:not([data-rt-isolate]_*)]:items-center [&_div[data-embed]:not([data-rt-isolate]_*)]:justify-center [&_div[data-embed]:not([data-rt-isolate]_*)]:rounded-kit-lg [&_div[data-embed]:not([data-rt-isolate]_*)]:border [&_div[data-embed]:not([data-rt-isolate]_*)]:border-kit-line [&_div[data-embed]:not([data-rt-isolate]_*)]:bg-kit-subtle [&_div[data-embed]:not([data-rt-isolate]_*)]:text-kit-sm [&_div[data-embed]:not([data-rt-isolate]_*)]:text-kit-fg-3 \" +\n \"[&_div[data-block]:not([data-rt-isolate]_*)]:flex [&_div[data-block]:not([data-rt-isolate]_*)]:items-center [&_div[data-block]:not([data-rt-isolate]_*)]:gap-2 [&_div[data-block]:not([data-rt-isolate]_*)]:rounded-kit-lg [&_div[data-block]:not([data-rt-isolate]_*)]:border [&_div[data-block]:not([data-rt-isolate]_*)]:border-dashed [&_div[data-block]:not([data-rt-isolate]_*)]:border-kit-accent-line [&_div[data-block]:not([data-rt-isolate]_*)]:bg-kit-accent-softer [&_div[data-block]:not([data-rt-isolate]_*)]:px-3 [&_div[data-block]:not([data-rt-isolate]_*)]:py-3 [&_div[data-block]:not([data-rt-isolate]_*)]:text-kit-sm [&_div[data-block]:not([data-rt-isolate]_*)]:text-kit-accent-fg \" +\n \"[&_table:not([data-rt-isolate]_*)]:w-full [&_table:not([data-rt-isolate]_*)]:border-collapse [&_table:not([data-rt-isolate]_*)]:text-kit-sm [&_td:not([data-rt-isolate]_*)]:border [&_td:not([data-rt-isolate]_*)]:border-kit-line [&_td:not([data-rt-isolate]_*)]:px-2.5 [&_td:not([data-rt-isolate]_*)]:py-1.5 [&_td:not([data-rt-isolate]_*)]:align-top [&_th:not([data-rt-isolate]_*)]:border [&_th:not([data-rt-isolate]_*)]:border-kit-line [&_th:not([data-rt-isolate]_*)]:bg-kit-subtle [&_th:not([data-rt-isolate]_*)]:px-2.5 [&_th:not([data-rt-isolate]_*)]:py-1.5 [&_th:not([data-rt-isolate]_*)]:text-left [&_th:not([data-rt-isolate]_*)]:align-top [&_th:not([data-rt-isolate]_*)]:font-medium\";\n\n/** Panel density (≈340px inspector): 13px text, smaller headings. */\nexport const RT_PANEL = \"text-kit-sm leading-[1.6] [&_h1:not([data-rt-isolate]_*)]:text-kit-xl [&_h1:not([data-rt-isolate]_*)]:leading-7 [&_h2:not([data-rt-isolate]_*)]:text-kit-lg [&_h2:not([data-rt-isolate]_*)]:leading-7 [&_h3:not([data-rt-isolate]_*)]:text-kit-md [&_h4:not([data-rt-isolate]_*)]:text-kit-base [&_h5:not([data-rt-isolate]_*)]:text-kit-sm [&_h6:not([data-rt-isolate]_*)]:text-kit-xs\";\n\n/** execCommand, where the engine has it (it returns false where it does not). */\nconst exec = (cmd: string, arg?: string): boolean => {\n try {\n return typeof document.execCommand === \"function\" && document.execCommand(cmd, false, arg);\n } catch {\n return false;\n }\n};\n/** A footnote marker (`<sup data-footnote>`, or the table's `<sup><a href=\"#…-fn-n\">`): never an x² mark. */\nconst FOOTNOTE_SUP = \"sup[data-footnote], sup:has(> a[href*='-fn-'])\";\n/** x² / x₂ (V2): on inside the same mark takes it off (unwrap, keeping the words selected); inside the other one swaps;\n * otherwise the browser wraps the selection. Footnote markers are never touched. */\nfunction toggleScript(root: HTMLElement, tag: \"sup\" | \"sub\") {\n const s = window.getSelection();\n if (!s || !s.rangeCount) return;\n const at = (n: Node | null) => (n?.nodeType === 1 ? (n as HTMLElement) : (n?.parentElement ?? null));\n const find = (t: \"sup\" | \"sub\") => {\n const el = at(s.anchorNode)?.closest<HTMLElement>(t === \"sup\" ? `sup:not(${FOOTNOTE_SUP})` : \"sub\");\n return el && root.contains(el) ? el : null;\n };\n const unwrap = (el: HTMLElement) => {\n const first = el.firstChild;\n const last = el.lastChild;\n el.replaceWith(...Array.from(el.childNodes));\n if (first && last) {\n const r = document.createRange();\n r.setStartBefore(first);\n r.setEndAfter(last);\n s.removeAllRanges();\n s.addRange(r);\n }\n };\n const same = find(tag);\n if (same) return unwrap(same);\n const other = find(tag === \"sup\" ? \"sub\" : \"sup\");\n if (other) unwrap(other);\n exec(tag === \"sup\" ? \"superscript\" : \"subscript\");\n}\n\n/** Focus is in another text field (the comment composer, a link input) while the page's selection stays in this editor. */\nconst typingElsewhere = (el: HTMLElement | null) => {\n const ae = document.activeElement;\n return !!el && !!ae && ae !== el && !el.contains(ae) && ae.matches(\"input, textarea, [contenteditable='true']\");\n};\nconst queryState = (c: string) => {\n try {\n return typeof document.queryCommandState === \"function\" && document.queryCommandState(c);\n } catch {\n return false;\n }\n};\n/** Insert HTML at the caret: the browser's own insert (undoable), else by hand. */\nfunction insertHtmlAtCaret(html: string) {\n if (exec(\"insertHTML\", html)) return;\n const s = window.getSelection();\n if (!s || !s.rangeCount) return;\n const r = s.getRangeAt(0);\n r.deleteContents();\n const tpl = document.createElement(\"template\");\n tpl.innerHTML = sanitize(html);\n const last = tpl.content.lastChild;\n r.insertNode(tpl.content);\n if (last) {\n r.setStartAfter(last);\n r.collapse(true);\n s.removeAllRanges();\n s.addRange(r);\n }\n}\n/* ── Word count (V2 rich-text-editor.tsx:115-128 + article.ts countWords, CPO D54 / D55) ──\n * Words = what the writer wrote once, in the flow a reader follows: text, headings, lists, quotes, callouts, toggles,\n * table cells and image captions. Not counted: components (counted apart), a pull quote (it repeats a line of the\n * story), key takeaways (they restate it), embeds, video and file links. */\nconst NOT_COUNTED = \"[data-rt=component],[data-rt=pullquote],[data-rt=takeaways],[data-rt=embed],[data-rt=video],[data-rt=file]\";\nconst WORDS = (s: string) => s.replace(/\\u200b/g, \"\").trim().split(/\\s+/).filter(Boolean).length;\nexport function countWords(html: string): number {\n if (!html) return 0;\n if (!/data-rt=\"(?:component|pullquote|takeaways|embed|video|file)\"/.test(html) || typeof DOMParser === \"undefined\")\n // A block's end and a line break part words; any other tag is a mark inside one (\"<strong>Screw</strong>Fast,\").\n return WORDS(html.replace(/<\\/(p|li|h[1-6]|blockquote|pre|figcaption|td|th|summary|div)>|<br\\s*\\/?>/g, \" \").replace(/<[^>]+>/g, \"\").replace(/&nbsp;|&[a-z]+;/g, \" \"));\n const doc = new DOMParser().parseFromString(`<body>${html}</body>`, \"text/html\");\n doc.body.querySelectorAll(NOT_COUNTED).forEach((n) => n.remove());\n doc.body.querySelectorAll(\"p,li,h1,h2,h3,h4,h5,h6,td,th,figcaption,summary,pre,blockquote,div\").forEach((n) => n.append(\" \"));\n return WORDS(doc.body.textContent ?? \"\");\n}\n/** Linked component instances in the body. */\nexport const countComponents = (html: string) => (html.match(/data-rt=\"component\"/g) ?? []).length;\n/** \"1,840 words · 3 components\" */\nexport const bodyCountLabel = (html: string) => {\n const w = countWords(html);\n const c = countComponents(html);\n return `${w.toLocaleString(\"en-US\")} ${w === 1 ? \"word\" : \"words\"}${c ? ` · ${c} ${c === 1 ? \"block\" : \"blocks\"}` : \"\"}`;\n};\n\nfunction insertTextAtCaret(text: string) {\n if (exec(\"insertText\", text)) return;\n const s = window.getSelection();\n if (!s || !s.rangeCount) return;\n const r = s.getRangeAt(0);\n r.deleteContents();\n const t = document.createTextNode(text);\n r.insertNode(t);\n r.setStartAfter(t);\n r.collapse(true);\n s.removeAllRanges();\n s.addRange(r);\n}\n\n/** The slash menu at full height (header 32, list 300, footer 28, borders), the least it shrinks to, and the gap it keeps from the window's edge. */\nconst SLASH_MENU_H = 362;\nconst SLASH_MIN_H = 160;\nconst SLASH_EDGE = 8;\n\n/**\n * Where the slash menu goes, collision-aware: below the caret when the whole menu fits there, else on the side with\n * more room, and never taller than that room (its list scrolls), so the last row (More components) stays reachable in\n * a short window.\n */\nexport function slashPlacement(caret: { top: number; bottom: number }, viewportH: number): { flipUp: boolean; maxHeight: number } {\n const below = viewportH - caret.bottom - 6 - SLASH_EDGE;\n const above = caret.top - 6 - SLASH_EDGE;\n const flipUp = below < SLASH_MENU_H && above > below;\n return { flipUp, maxHeight: Math.max(SLASH_MIN_H, Math.min(SLASH_MENU_H, flipUp ? above : below)) };\n}\n\ntype IslandStep = { el: IslandEl; before: IslandModels[IslandKind]; label: string; at: number };\n/** A step the host's history holds (KitServices.historyStep); its undo and redo are the host's, while it is next. */\ntype HostStep = { label: string; step: KitHistoryStep };\ntype GutterState = { el: HTMLElement; top: number; height: number };\ntype SlashState = { rect: DOMRect; node: Text; offset: number; query: string; folder: boolean; active: number };\ntype LinkState = { rect: DOMRect; initial: TextLink; existing: HTMLAnchorElement | null };\ntype Notice = { message: string; description?: string; action?: { label: string; onClick: () => void } };\n\nexport interface RichTextEditorProps {\n value: string;\n onChange: (html: string) => void;\n readOnly?: boolean;\n placeholder?: string;\n docKey: string;\n /** what the field accepts; the editor offers nothing else (default: everything) */\n features?: readonly RichTextFeature[];\n /** a one-paragraph field: Enter starts no new block */\n single?: boolean;\n /** links may open in a new tab */\n allowNewTab?: boolean;\n /** the writing surface's id (the field label's `for`; its label is `${id}-label`) */\n id?: string;\n invalid?: boolean;\n /** panel = narrow (~340px) inspector, document = the full editor column. */\n variant?: \"panel\" | \"document\";\n /** CPO D49: the expanded editor's breadcrumb, root → this field (\"Alternating feature rows\", \"Thin walls\", \"Body\"). */\n expandCrumbs?: string[];\n /** Controlled expanded modal (a host's label-row action opens it too). */\n expandedOpen?: boolean;\n onExpandedOpenChange?: (open: boolean) => void;\n /** This editor IS the body of the expanded modal: toolbar always shown, tall writing surface. */\n inModal?: boolean;\n /** Already the full editor: no Expand button. */\n hideFullscreen?: boolean;\n /** Scroll the writing surface beyond this height (px). */\n maxHeight?: number;\n autoFocus?: boolean;\n /** Shows the toolbar Comment button. */\n onComment?: (quote: string) => void;\n /** the components this field may embed (the insert menus' More components); absent → none offered */\n components?: CatalogComponents;\n}\n\n/* ── Editor ────────────────────────────────────────────────────────── */\nexport function RichTextEditor({\n value,\n onChange,\n readOnly,\n placeholder,\n docKey,\n features = ALL_FEATURES,\n single,\n allowNewTab = true,\n id,\n invalid,\n variant = \"document\",\n expandCrumbs,\n expandedOpen,\n onExpandedOpenChange,\n inModal,\n hideFullscreen,\n maxHeight,\n autoFocus,\n onComment,\n components,\n}: RichTextEditorProps) {\n const hints = shortcutHintsOn();\n const ph = placeholder ?? (hints ? \"Type '/' for commands\" : \"Write something…\");\n const dense = variant === \"panel\";\n const ref = React.useRef<HTMLDivElement>(null);\n const wrap = React.useRef<HTMLDivElement>(null);\n const scroller = React.useRef<HTMLDivElement>(null);\n const saved = React.useRef<Range | null>(null);\n const known = React.useRef<string | null>(null);\n const pending = React.useRef<string | null>(null);\n /** a host undo just ran: its value is loaded even while the editor has focus (⌘Z here) */\n const forceLoad = React.useRef(false);\n const prevDoc = React.useRef<string | null>(null);\n const onChangeRef = React.useRef(onChange);\n onChangeRef.current = onChange;\n const valueRef = React.useRef(value);\n valueRef.current = value;\n const services = useKitServices();\n const env = useKitEnv();\n const featureKey = features.join(\",\");\n // eslint-disable-next-line react-hooks/exhaustive-deps\n const allows = React.useCallback((f: RichTextFeature) => features.includes(f), [featureKey]);\n\n const [empty, setEmpty] = React.useState(isEmptyHtml(value));\n const [words, setWords] = React.useState(() => countWords(value));\n const [comps, setComps] = React.useState(() => countComponents(value));\n const [fmt, setFmt] = React.useState<Fmt>(EMPTY_FMT);\n const [modalOwn, setModalOwn] = React.useState(false);\n const modalOpen = expandedOpen ?? modalOwn;\n const setModalOpen = (o: boolean) => (onExpandedOpenChange ? onExpandedOpenChange(o) : setModalOwn(o));\n const [md, setMd] = React.useState<{ text: string; original: string } | null>(null);\n const [mdConfirm, setMdConfirm] = React.useState(false);\n // Reduced motion: the Markdown confirm fades only (no slide).\n const reduceMotion = useReducedMotion();\n const [bubble, setBubble] = React.useState<DOMRect | null>(null);\n /** Comment was picked: the toolbar stays away until the next click or key inside this editor */\n const [quiet, setQuiet] = React.useState(false);\n React.useEffect(() => {\n const el = ref.current;\n if (!quiet || !el) return;\n const wake = () => setQuiet(false);\n el.addEventListener(\"mousedown\", wake);\n el.addEventListener(\"keydown\", wake);\n return () => {\n el.removeEventListener(\"mousedown\", wake);\n el.removeEventListener(\"keydown\", wake);\n };\n }, [quiet]);\n const [slash, setSlash] = React.useState<SlashState | null>(null);\n const [gutter, setGutter] = React.useState<GutterState | null>(null);\n const [blockMenu, setBlockMenu] = React.useState(false);\n const [gutterInsert, setGutterInsert] = React.useState(false);\n const gutterTarget = React.useRef<HTMLElement | null>(null);\n // D58: AI writing help follows ai.use and needs the host's AI service; without both no AI entry point is drawn.\n const canAI = env.can(\"ai.use\") && !!services.aiRewrite;\n const aiAttempt = React.useRef(0);\n const [link, setLink] = React.useState<LinkState | null>(null);\n const [drag, setDrag] = React.useState<{ from: HTMLElement; line: number | null; target: Element | null } | null>(null);\n const [focused, setFocused] = React.useState(false);\n const [menus, setMenus] = React.useState({ style: false, more: false });\n const [insertOpen, setInsertOpen] = React.useState(false);\n const inserted = React.useRef(false);\n const [islands, setIslands] = React.useState<{ id: string; el: IslandEl }[]>([]);\n const hist = React.useRef<{ past: IslandStep[]; future: IslandStep[]; textAt: number; hosts: HostStep[] }>({ past: [], future: [], textAt: 0, hosts: [] });\n const [width, setWidth] = React.useState(720);\n /* The block gutter (+ / grip) never reserves room inside the field: it floats in the space LEFT of the box when the\n host leaves ≥ 48px there (document columns), and sits in the box's padding otherwise. */\n const [gutterRoom, setGutterRoom] = React.useState(false);\n const blurTimer = React.useRef<number | undefined>(undefined);\n const [notice, setNotice] = React.useState<Notice | null>(null);\n\n const expanded = !!inModal;\n const toolbarOpen = !readOnly && (focused || menus.style || menus.more || insertOpen || expanded || !!md || !!link);\n const scrollable = !!maxHeight && !expanded;\n\n /** A refusal or a result the author must see: the host's toaster, else a line under the editor. Never silent. */\n const notify = React.useCallback(\n (message: string, opts: { description?: string; action?: Notice[\"action\"] } = {}) => {\n if (services.toast) services.toast(message, opts);\n else setNotice({ message, ...opts });\n },\n [services],\n );\n React.useEffect(() => {\n if (!notice) return;\n const t = window.setTimeout(() => setNotice(null), 8000);\n return () => window.clearTimeout(t);\n }, [notice]);\n\n /* ── islands ─────────────────────────────────────────────────────── */\n const syncIslands = React.useCallback(() => {\n const el = ref.current;\n if (!el) return setIslands((p) => (p.length ? [] : p));\n const list = Array.from(el.querySelectorAll<IslandEl>(\":scope > [data-rt-island]\"));\n const seen = new Set<string>();\n for (const x of list) {\n if (!x.__rt) {\n // a copy the browser made (drag/drop, native undo of a clone): start it fresh\n x.innerHTML = \"\";\n x.__rt = defaultModel(x.getAttribute(\"data-rt-island\") as IslandKind);\n delete x.dataset.rtId;\n }\n if (!x.dataset.rtId || seen.has(x.dataset.rtId)) x.dataset.rtId = rid(\"i\");\n seen.add(x.dataset.rtId);\n }\n setIslands((prev) => (prev.length === list.length && prev.every((p, i) => p.el === list[i]) ? prev : list.map((x) => ({ id: x.dataset.rtId!, el: x }))));\n }, []);\n\n /* ── value in / out ──────────────────────────────────────────────── */\n const load = React.useCallback(\n (html: string) => {\n const el = ref.current;\n if (!el) return;\n el.innerHTML = sanitize(html || \"\") || \"<p><br></p>\";\n hydrate(el);\n known.current = html;\n setEmpty(isEmptyHtml(html));\n setWords(countWords(html));\n setComps(countComponents(html));\n syncIslands();\n },\n [syncIslands],\n );\n\n const emit = React.useCallback(() => {\n const el = ref.current;\n if (!el) return;\n syncIslands();\n const html = serialize(el);\n setEmpty(isEmptyHtml(html) && !el.querySelector(\":scope > [data-rt-island], :scope > hr\"));\n setWords(countWords(html));\n setComps(countComponents(html));\n if (html === known.current) return;\n forceLoad.current = false;\n known.current = html;\n onChangeRef.current(html);\n }, [syncIslands]);\n\n React.useLayoutEffect(() => {\n const el = ref.current;\n if (!el) return;\n const docChanged = prevDoc.current !== null && prevDoc.current !== docKey;\n prevDoc.current = docKey;\n if (pending.current !== null) {\n const h = pending.current;\n pending.current = null;\n load(h);\n return;\n }\n if (forceLoad.current && value !== known.current) {\n forceLoad.current = false;\n load(value);\n return;\n }\n if (docChanged || !el.firstChild || (value !== known.current && !wrap.current?.contains(document.activeElement))) load(value);\n }, [value, docKey, md, load]);\n\n React.useEffect(() => {\n setMd(null);\n setMdConfirm(false);\n setSlash(null);\n setLink(null);\n setGutter(null);\n }, [docKey]);\n\n React.useEffect(() => {\n exec(\"defaultParagraphSeparator\", \"p\");\n if (autoFocus && ref.current && !readOnly) {\n ref.current.focus({ preventScroll: true });\n placeCaret(ref.current.lastElementChild ?? ref.current);\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, []);\n\n React.useEffect(() => {\n const w = wrap.current;\n if (!w || typeof ResizeObserver === \"undefined\") return;\n const measureRoom = () => {\n let a = w.parentElement;\n while (a && a !== document.body) {\n const cs = getComputedStyle(a);\n if (cs.overflowX !== \"visible\" || cs.overflowY !== \"visible\") break;\n a = a.parentElement;\n }\n const left = w.getBoundingClientRect().left - (a ? a.getBoundingClientRect().left : 0);\n setGutterRoom(left >= 48);\n };\n const ro = new ResizeObserver(([e]) => {\n setWidth(Math.round(e.contentRect.width));\n measureRoom();\n });\n ro.observe(w);\n return () => ro.disconnect();\n }, []);\n\n /* the toolbar sticks below any sticky header (e.g. field tabs) in the same scroll area */\n const [stickyTop, setStickyTop] = React.useState(0);\n React.useEffect(() => {\n const w = wrap.current;\n if (!toolbarOpen || dense || !w) return;\n let sp = w.parentElement;\n while (sp && !/(auto|scroll)/.test(getComputedStyle(sp).overflowY)) sp = sp.parentElement;\n if (!sp) return setStickyTop(0);\n let top = 0;\n sp.querySelectorAll<HTMLElement>(\".sticky\").forEach((h) => {\n if (h.contains(w) || w.contains(h) || !(h.compareDocumentPosition(w) & Node.DOCUMENT_POSITION_FOLLOWING)) return;\n const cs = getComputedStyle(h);\n if (cs.position !== \"sticky\") return;\n top = Math.max(top, (parseFloat(cs.top) || 0) + h.offsetHeight);\n });\n setStickyTop(top);\n }, [toolbarOpen, dense]);\n\n // the slash menu follows the caret when anything scrolls; it closes only when the caret has left the \"/\" it was opened for\n const hasSlash = !!slash;\n React.useEffect(() => {\n if (!hasSlash) return;\n let raf = 0;\n const on = (e: Event) => {\n if (e.target instanceof Element && e.target.closest(\"[role=listbox]\")) return;\n cancelAnimationFrame(raf);\n raf = requestAnimationFrame(() =>\n setSlash((sl) => {\n const s = window.getSelection();\n if (!sl || !s || !s.rangeCount || s.getRangeAt(0).startContainer !== sl.node) return null;\n const rect = rangeRect(s.getRangeAt(0), sl.node.parentElement ?? ref.current);\n return rect.top === sl.rect.top && rect.left === sl.rect.left ? sl : { ...sl, rect };\n }),\n );\n };\n window.addEventListener(\"scroll\", on, true);\n return () => {\n cancelAnimationFrame(raf);\n window.removeEventListener(\"scroll\", on, true);\n };\n }, [hasSlash]);\n\n // keep the bubble on the selection while anything scrolls (incl. the toolbar sliding open)\n const hasBubble = !!bubble;\n React.useEffect(() => {\n if (!hasBubble) return;\n let raf = 0;\n const on = () => {\n cancelAnimationFrame(raf);\n raf = requestAnimationFrame(() => {\n const s = window.getSelection();\n const ok = s && s.rangeCount && !s.isCollapsed && ref.current?.contains(s.anchorNode) && !typingElsewhere(ref.current);\n setBubble(ok ? rangeRect(s!.getRangeAt(0), ref.current) : null);\n });\n };\n window.addEventListener(\"scroll\", on, true);\n window.addEventListener(\"resize\", on);\n // The toolbar sliding open moves the words without a scroll: the bubble sat on the selected word.\n const box = new ResizeObserver(on);\n if (wrap.current) box.observe(wrap.current);\n return () => {\n cancelAnimationFrame(raf);\n box.disconnect();\n window.removeEventListener(\"scroll\", on, true);\n window.removeEventListener(\"resize\", on);\n };\n }, [hasBubble]);\n\n /* ── selection ───────────────────────────────────────────────────── */\n const saveSel = () => {\n const s = window.getSelection();\n if (s && s.rangeCount && ref.current?.contains(s.anchorNode)) saved.current = s.getRangeAt(0).cloneRange();\n };\n const restoreSel = () => {\n const el = ref.current;\n if (!el) return;\n const r = saved.current;\n const s = window.getSelection();\n if (r && el.contains(r.startContainer) && s) {\n (editingHost(r.startContainer) ?? el).focus({ preventScroll: true });\n s.removeAllRanges();\n s.addRange(r);\n } else {\n el.focus({ preventScroll: true });\n placeCaret(el.lastElementChild ?? el);\n }\n };\n\n const refresh = React.useCallback(() => {\n const el = ref.current;\n const s = window.getSelection();\n if (!el || !s || !s.rangeCount || !el.contains(s.anchorNode)) return;\n // typing somewhere else (the comment composer, a link field) keeps the page's selection here: no toolbar over it\n if (typingElsewhere(el)) {\n setBubble(null);\n return;\n }\n saved.current = s.getRangeAt(0).cloneRange();\n const anchorEl = s.anchorNode?.nodeType === 1 ? (s.anchorNode as HTMLElement) : s.anchorNode?.parentElement;\n const inIsland = !!anchorEl?.closest(\"[data-rt-island]\");\n const tb = topBlock(el, s.anchorNode);\n const r = s.getRangeAt(0);\n const hasSel = !s.isCollapsed && !!r.toString().trim();\n const next: Fmt = {\n bold: queryState(\"bold\") && !/^H[1-6]$/.test(tb?.tagName ?? \"\"),\n italic: queryState(\"italic\"),\n underline: queryState(\"underline\"),\n strike: queryState(\"strikeThrough\"),\n // our own check: the base CSS resets sup/sub alignment, so the browser's own state for them always reads false\n sup: !!anchorEl?.closest(`sup:not(${FOOTNOTE_SUP})`),\n sub: !!anchorEl?.closest(\"sub\"),\n ul: !inIsland && tb?.tagName === \"UL\",\n ol: !inIsland && tb?.tagName === \"OL\",\n block: inIsland ? \"island\" : (tb?.tagName.toLowerCase() ?? \"p\"),\n hasSel,\n onLink: !!anchorEl?.closest(\"a\"),\n };\n setFmt((p) => (JSON.stringify(p) === JSON.stringify(next) ? p : next));\n setBubble(hasSel ? rangeRect(r, el) : null);\n el.querySelectorAll(\":scope > [data-hint]\").forEach((n) => (n !== tb || n.textContent) && n.removeAttribute(\"data-hint\"));\n if (tb && tb.tagName === \"P\" && s.isCollapsed && !tb.textContent && !tb.querySelector(\"img\") && document.activeElement === el && shortcutHintsOn()) tb.setAttribute(\"data-hint\", \"Type '/' for commands\");\n }, []);\n\n React.useEffect(() => {\n const on = () => refresh();\n // focus moving into another text field (the comment composer opening) fires no selectionchange: hide on focusin too\n const away = () => typingElsewhere(ref.current) && setBubble(null);\n document.addEventListener(\"selectionchange\", on);\n document.addEventListener(\"focusin\", away);\n return () => {\n document.removeEventListener(\"selectionchange\", on);\n document.removeEventListener(\"focusin\", away);\n };\n }, [refresh]);\n\n const run = (fn: () => void) => {\n restoreSel();\n fn();\n emit();\n refresh();\n };\n\n /* ── gutter ──────────────────────────────────────────────────────── */\n const placeGutter = (b: HTMLElement | null) => {\n const sc = scroller.current;\n if (!b || !sc) return setGutter(null);\n const sr = sc.getBoundingClientRect();\n const br = b.getBoundingClientRect();\n setGutter((g) => {\n const top = br.top - sr.top + sc.scrollTop;\n return g && g.el === b && g.top === top ? g : { el: b, top, height: br.height };\n });\n };\n const currentBlock = (): HTMLElement | null => {\n const el = ref.current;\n if (!el) return null;\n const s = window.getSelection();\n return topBlock(el, s && s.rangeCount && el.contains(s.anchorNode) ? s.anchorNode : document.activeElement);\n };\n\n /* ── block operations (DOM work lives in ./ops) ─────────── */\n const deleteBlock = (b: HTMLElement) => {\n const el = ref.current;\n if (!el || !el.contains(b)) return;\n const next = b.nextSibling;\n b.remove();\n let filler: HTMLElement | null = null;\n if (!el.firstElementChild) {\n filler = document.createElement(\"p\");\n filler.innerHTML = \"<br>\";\n el.append(filler);\n }\n setGutter(null);\n setBlockMenu(false);\n emit();\n notify(\"Block deleted\", {\n action: {\n label: \"Undo\",\n onClick: () => {\n const root = ref.current;\n if (!root) return;\n if (filler?.isConnected && !filler.textContent) filler.remove();\n if (next && next.parentNode === root) root.insertBefore(b, next);\n else root.append(b);\n emit();\n },\n },\n });\n };\n\n const duplicateBlock = (b: HTMLElement) => {\n const c = ops.duplicateBlock(b);\n emit();\n if (gutter) placeGutter(c);\n };\n\n const moveBlock = (b: HTMLElement, dir: -1 | 1) => {\n if (!ops.moveBlock(b, dir)) return;\n emit();\n if (gutter) requestAnimationFrame(() => placeGutter(b));\n };\n\n const turnInto = (b: HTMLElement | null, tag: string) => {\n const el = ref.current;\n if (el && ops.turnInto(el, b, tag)) emit();\n };\n\n const exitIsland = (x: HTMLElement) => {\n const el = ref.current;\n if (!el || !el.contains(x)) return;\n const next = ops.ensureLineAfter(x);\n el.focus({ preventScroll: true });\n placeCaret(next, false);\n emit();\n };\n\n const insertBlock = (it: CatalogItem) => {\n const el = ref.current;\n if (!el || readOnly) return;\n if (it.kind === \"component\" && it.component) {\n // V2 insert: a fresh linked instance, ONE undo step\n const c = it.component;\n noteRecent(it);\n const made: { el: IslandEl | null } = { el: null };\n oneStep(`Insert ${c.name}`, () => {\n const isl = (made.el = ops.insertIsland(el, \"component\", { ...defaultModel(\"component\"), ref: c.id, name: c.name }));\n emit();\n return isl;\n });\n refresh();\n // V2 insert: its properties open beside it, and the toast says what a shared component is\n if (made.el && services.useComponentInfo) openComponentPanel(made.el);\n services.toast?.(`${c.name} added`, { description: COMPONENT_INSERT_TOAST });\n return;\n }\n if (!it.id || !blockAllowed(it.id, allows)) return;\n noteRecent(it);\n ops.insertBasic(el, it.id);\n emit();\n refresh();\n };\n\n /* ── slash menu ──────────────────────────────────────────────────── */\n const slashCat = useCatalog(slash?.query ?? \"\", allows, slash?.folder ?? false, components ?? null);\n const caretRect = () => {\n const s = window.getSelection();\n if (!s || !s.rangeCount) return null;\n return rangeRect(s.getRangeAt(0), topBlock(ref.current, s.anchorNode) ?? ref.current);\n };\n const pickSlash = (it: CatalogItem) => {\n if (it.kind === \"folder\") return setSlash((s) => s && { ...s, folder: true, active: 1 });\n if (it.kind === \"back\") return setSlash((s) => s && { ...s, folder: false, active: 0 });\n const sl = slash;\n setSlash(null);\n if (sl) {\n try {\n const r = document.createRange();\n r.setStart(sl.node, sl.offset);\n r.setEnd(sl.node, Math.min(sl.node.length, sl.offset + 1 + sl.query.length));\n r.deleteContents();\n const c = document.createRange();\n c.setStart(sl.node, Math.min(sl.offset, sl.node.length));\n c.collapse(true);\n const s = window.getSelection();\n s?.removeAllRanges();\n s?.addRange(c);\n } catch {\n /* the text moved */\n }\n // A component is ONE step of the host's history, recorded from the body as it stands when the step starts: the\n // typed \"/query\" goes first, flushed, so an undo of the insert never brings it back as a paragraph.\n if (it.kind === \"component\") flushSync(() => emit());\n }\n insertBlock(it);\n };\n\n const toggleInlineCode = () => {\n const el = ref.current;\n const s = window.getSelection();\n if (!el || !s || !s.rangeCount || !allows(\"code\")) return;\n const anchorEl = s.anchorNode?.nodeType === 1 ? (s.anchorNode as HTMLElement) : s.anchorNode?.parentElement;\n const code = anchorEl?.closest(\"code\");\n if (code && el.contains(code) && !code.closest(\"pre\")) {\n code.replaceWith(...Array.from(code.childNodes));\n emit();\n return;\n }\n const text = s.toString();\n if (!text) return void notify(\"Select some text first\", { description: \"Or wrap words in backticks to format them as code.\" });\n insertHtmlAtCaret(`<code>${esc(text)}</code>`);\n emit();\n };\n\n /* ── keyboard ────────────────────────────────────────────────────── */\n const onKeyDown = (e: React.KeyboardEvent<HTMLDivElement>) => {\n if (slash) {\n if (e.key === \"Escape\") {\n e.preventDefault();\n e.stopPropagation();\n setSlash(slash.folder ? { ...slash, folder: false, active: 0 } : null);\n return;\n }\n if (catalogKey(e, slashCat.flat, slash.active, (a) => setSlash((s) => s && { ...s, active: a }), pickSlash, false)) {\n e.preventDefault();\n return;\n }\n }\n const mod = e.metaKey || e.ctrlKey;\n const k = eventKey(e);\n if (mod && !e.altKey && k === \"k\") {\n e.preventDefault();\n saveSel();\n openLink();\n return;\n }\n if (mod && !e.altKey && !e.shiftKey && k === \"e\") {\n e.preventDefault();\n toggleInlineCode();\n return;\n }\n // the browser's own mark shortcuts, only for the marks the field keeps\n if (mod && !e.altKey && !e.shiftKey && ((k === \"b\" && !allows(\"bold\")) || (k === \"i\" && !allows(\"italic\")) || (k === \"u\" && !allows(\"underline\")))) {\n e.preventDefault();\n return;\n }\n if (mod && e.altKey && /^Digit[0-6]$/.test(e.code)) {\n e.preventDefault();\n const n = Number(e.code.slice(5));\n const tag = n === 0 ? \"p\" : `h${n}`;\n if (tag === \"p\" || allows(tag as RichTextFeature)) turnInto(currentBlock(), tag);\n return;\n }\n if (e.key === \"Enter\" && !mod && !e.shiftKey) {\n // a one-paragraph field has no second block to start\n if (single) {\n e.preventDefault();\n return;\n }\n // Enter on an empty quote or heading line leaves it for a paragraph\n const cb = currentBlock();\n if (cb && /^(BLOCKQUOTE|H[1-6])$/.test(cb.tagName) && !cb.textContent?.replace(/​/g, \"\").trim()) {\n e.preventDefault();\n turnInto(cb, \"p\");\n return;\n }\n // Enter at the end of a quote starts a paragraph (not another quote)\n const sel = window.getSelection();\n if (cb?.tagName === \"BLOCKQUOTE\" && sel?.isCollapsed && sel.rangeCount && !cb.querySelector(\"p\")) {\n const rest = document.createRange();\n rest.selectNodeContents(cb);\n rest.setStart(sel.anchorNode!, sel.anchorOffset);\n if (!rest.toString().trim()) {\n e.preventDefault();\n const p = document.createElement(\"p\");\n p.innerHTML = \"<br>\";\n cb.after(p);\n placeCaret(p);\n emit();\n return;\n }\n }\n const s = window.getSelection();\n const pre = s?.anchorNode && (s.anchorNode.nodeType === 1 ? (s.anchorNode as HTMLElement) : s.anchorNode.parentElement)?.closest(\"pre\");\n if (pre && ref.current?.contains(pre)) {\n e.preventDefault();\n exec(\"insertLineBreak\");\n return;\n }\n }\n if (e.key === \"ArrowDown\" && !mod && !e.shiftKey && !single) {\n // leave a trailing heading / quote / code block / list\n const b = currentBlock();\n const s = window.getSelection();\n if (b && !b.nextElementSibling && b.tagName !== \"P\" && !b.hasAttribute(\"data-rt-island\") && s?.isCollapsed && s.rangeCount) {\n const rest = document.createRange();\n rest.selectNodeContents(b);\n rest.setStart(s.anchorNode!, s.anchorOffset);\n if (!rest.toString().trim()) {\n e.preventDefault();\n const p = ops.ensureLineAfter(b);\n placeCaret(p, false);\n emit();\n }\n }\n }\n };\n\n /** Block-level shortcuts; runs for the surface and for text inside rich blocks. */\n const onWrapKeyDown = (e: React.KeyboardEvent<HTMLDivElement>) => {\n if (e.defaultPrevented) return;\n const mod = e.metaKey || e.ctrlKey;\n if (mod && e.key === \"Enter\" && !hideFullscreen) {\n e.preventDefault();\n setModalOpen(true);\n return;\n }\n if (md || readOnly) return;\n const t = e.target as HTMLElement;\n if (!ref.current?.contains(t) || t.tagName === \"INPUT\" || t.tagName === \"TEXTAREA\") return;\n if (undoKey(e)) return;\n if (single) return;\n if (mod && !e.shiftKey && !e.altKey && eventKey(e) === \"d\") {\n e.preventDefault();\n const b = currentBlock();\n if (b) duplicateBlock(b);\n return;\n }\n if (mod && e.shiftKey && (e.key === \"ArrowUp\" || e.key === \"ArrowDown\")) {\n e.preventDefault();\n const b = currentBlock();\n if (b) moveBlock(b, e.key === \"ArrowUp\" ? -1 : 1);\n }\n };\n\n const onInput = (e: React.FormEvent<HTMLDivElement>) => {\n if (e.target !== ref.current) return;\n const ne = e.nativeEvent as InputEvent;\n if (ne.inputType !== \"historyUndo\" && ne.inputType !== \"historyRedo\") {\n hist.current.textAt = Date.now();\n hist.current.future = [];\n }\n if (!single && ne.inputType === \"insertText\" && (ne.data === \" \" || ne.data === \"-\") && ops.liveMarkdown(ref.current!, ne.data, allows)) {\n setSlash(null);\n emit();\n return;\n }\n if (ne.inputType === \"insertText\" && ne.data === \"`\" && allows(\"code\")) ops.liveInlineCode();\n emit();\n const s = window.getSelection();\n if (!s || !s.rangeCount) return setSlash(null);\n const r = s.getRangeAt(0);\n if (!slash) {\n // \"/\" opens the menu only at the very start of a block, and only in a field that takes more than one block\n if (single || ne.inputType !== \"insertText\" || ne.data !== \"/\" || r.startContainer.nodeType !== 3) return;\n const blk = closestBlock(ref.current!, r.startContainer);\n if (!blk || textBeforeCaret(blk) !== \"/\") return;\n const rect = caretRect();\n if (rect) setSlash({ rect, node: r.startContainer as Text, offset: r.startOffset - 1, query: \"\", folder: false, active: 0 });\n return;\n }\n if (r.startContainer !== slash.node || r.startOffset <= slash.offset || slash.node.data[slash.offset] !== \"/\") return setSlash(null);\n const q = slash.node.data.slice(slash.offset + 1, r.startOffset);\n if (/\\s/.test(q) || q.length > 24) return setSlash(null);\n setSlash({ ...slash, query: q, active: slash.folder ? 1 : 0 });\n };\n\n /* ── links ───────────────────────────────────────────────────────── */\n const openLink = () => {\n if (!allows(\"link\")) return;\n restoreSel();\n const s = window.getSelection();\n const anchorEl = s?.anchorNode?.nodeType === 1 ? (s.anchorNode as HTMLElement) : s?.anchorNode?.parentElement;\n const anchor = (anchorEl?.closest(\"a\") as HTMLAnchorElement | null) ?? null;\n if (!anchor && (!s || s.isCollapsed || !s.toString().trim())) {\n notify(\"Select some text first\", { description: hints ? \"Then press ⌘K to link it.\" : \"Then link it.\" });\n return;\n }\n const rect = s && s.rangeCount ? rangeRect(s.getRangeAt(0), ref.current) : ref.current!.getBoundingClientRect();\n setBubble(null);\n setLink({ rect, existing: anchor, initial: anchor ? { href: anchor.getAttribute(\"href\") ?? \"\", newTab: anchor.getAttribute(\"target\") === \"_blank\" } : { href: \"\" } });\n };\n const saveLink = (v: TextLink) => {\n const l = link;\n setLink(null);\n if (!l) return;\n if (l.existing) {\n l.existing.setAttribute(\"href\", v.href);\n if (v.newTab) l.existing.setAttribute(\"target\", \"_blank\");\n else l.existing.removeAttribute(\"target\");\n emit();\n return;\n }\n run(() => {\n const text = window.getSelection()?.toString() || v.href;\n insertHtmlAtCaret(`<a href=\"${esc(v.href).replace(/\"/g, \"&quot;\")}\"${v.newTab ? ` target=\"_blank\"` : \"\"}>${esc(text)}</a>`);\n });\n };\n\n /* ── AI rewrite of the selection (the host's service) ────────────── */\n const aiRewrite = (preset: AiPreset) => {\n const rewrite = services.aiRewrite;\n restoreSel();\n const range = saved.current?.cloneRange();\n const text = range?.toString() ?? \"\";\n if (!rewrite || !range || !text.trim()) return;\n setBubble(null);\n Promise.resolve()\n .then(() => rewrite(text, preset, aiAttempt.current++))\n .then(\n (out) => {\n const el = ref.current;\n if (!el || !el.contains(range.startContainer) || range.toString() !== text) {\n notify(\"The text changed before the rewrite came back\", { description: \"Nothing was replaced. Select it again to retry.\" });\n return;\n }\n el.focus({ preventScroll: true });\n const s = window.getSelection();\n s?.removeAllRanges();\n s?.addRange(range);\n insertTextAtCaret(out);\n emit();\n notify(\"Rewritten with AI\", { description: hints ? \"Press ⌘Z to undo\" : undefined });\n },\n (err: unknown) => notify(\"Could not rewrite the selection\", { description: err instanceof Error ? err.message : String(err) }),\n );\n };\n\n /* ── drag to reorder via the grip ────────────────────────────────── */\n const onGripDown = (e: React.PointerEvent) => {\n if (!gutter) return;\n startDrag(gutter.el, e, () => setBlockMenu(true));\n };\n /** Drag a top-level block (the gutter grip) to a new position; a tap calls `onTap`. */\n const startDrag = (from: HTMLElement, e: React.PointerEvent, onTap?: () => void) => {\n if (readOnly || e.button !== 0) return;\n e.preventDefault();\n const start = e.clientY;\n let moved = false;\n const kids = () => Array.from(ref.current?.children ?? []);\n const move = (ev: PointerEvent) => {\n if (!moved && Math.abs(ev.clientY - start) < 4) return;\n moved = true;\n const sc = scroller.current!;\n const sr = sc.getBoundingClientRect();\n let target: Element | null = null;\n let line = 0;\n for (const k of kids()) {\n const r = k.getBoundingClientRect();\n if (ev.clientY < r.top + r.height / 2) {\n target = k;\n line = r.top - sr.top + sc.scrollTop - 4;\n break;\n }\n line = r.bottom - sr.top + sc.scrollTop + 4;\n }\n setDrag({ from, line, target });\n };\n const up = () => {\n window.removeEventListener(\"pointermove\", move);\n window.removeEventListener(\"pointerup\", up);\n if (!moved) {\n onTap?.();\n return;\n }\n setDrag((d) => {\n if (d && d.target !== d.from) {\n if (d.target) d.target.before(d.from);\n else ref.current?.append(d.from);\n setTimeout(emit, 0);\n }\n return null;\n });\n };\n window.addEventListener(\"pointermove\", move);\n window.addEventListener(\"pointerup\", up);\n };\n\n /* ── pasted and converted markup keeps to the field's rules ──────── */\n const conform = (html: string): string => {\n const r = ops.restrictHtml(html, allows);\n if (r.dropped.length) notify(`This field keeps no ${r.dropped.join(\" or \")}`, { description: \"They were left out; the text around them was kept.\" });\n return r.html;\n };\n\n /* ── Markdown mode ───────────────────────────────────────────────── */\n const toggleMarkdown = () => {\n if (!md) {\n const html = ref.current ? serialize(ref.current) : value;\n const text = htmlToMarkdown(html);\n setMd({ text, original: text });\n setSlash(null);\n setGutter(null);\n setBubble(null);\n setLink(null);\n return;\n }\n if (md.text === md.original) {\n setMd(null);\n setMdConfirm(false);\n return;\n }\n setMdConfirm(true);\n };\n const convertMarkdown = () => {\n if (!md) return;\n let html: string;\n try {\n html = conform(markdownToHtml(md.text));\n } catch (err) {\n notify(\"Could not convert this Markdown\", { description: `${err instanceof Error ? err.message : String(err)}. Your rich text is unchanged.` });\n return;\n }\n pending.current = html;\n known.current = html;\n onChangeRef.current(html);\n setMd(null);\n setMdConfirm(false);\n };\n\n /* ── One undo history (CPO D54): typing is the browser's own undo; an island write (an image's address or alt text)\n is a step on this stack. ⌘Z takes whichever happened last. ── */\n /** A host step's undo or redo; its value then loads even here, with the caret in the editor. */\n const runHost = (run: () => true | string): true | string => {\n forceLoad.current = true;\n const r = run();\n if (r !== true) forceLoad.current = false;\n return r;\n };\n /**\n * This body's host step that is the host's next undo (or redo) NOW. The host's toolbar moves these steps too: after\n * its Undo then Redo, the step is the latest change again, so ⌘Z here undoes it. Any later change in this body is a\n * host step of its own (the body's value is the host's), so a host step that is next is the latest change here.\n */\n const hostNext = (way: \"undo\" | \"redo\"): HostStep | null => {\n const hs = hist.current.hosts;\n for (let i = hs.length - 1; i >= 0; i--) if (hs[i].step.next() === way) return hs[i];\n return null;\n };\n const islandUndo = (): boolean => {\n const host = hostNext(\"undo\");\n if (host) {\n const r = runHost(host.step.undo);\n if (r !== true) notify(\"Nothing was undone\", { description: r });\n return true;\n }\n const h = hist.current;\n // a step whose island is gone has nothing to undo\n while (h.past.length && !h.past[h.past.length - 1].el.isConnected) h.past.pop();\n const step = h.past[h.past.length - 1];\n if (!step || step.at < h.textAt) return false;\n if (!step.el.__rtSet) return false;\n h.past.pop();\n h.future.push({ ...step, before: step.el.__rt!, at: Date.now() });\n step.el.__rtSet(step.before);\n return true;\n };\n const islandRedo = (): boolean => {\n const host = hostNext(\"redo\");\n if (host) {\n const r = runHost(host.step.redo);\n if (r !== true) notify(\"Nothing was redone\", { description: r });\n return true;\n }\n const h = hist.current;\n const step = h.future.pop();\n if (!step || !step.el.isConnected || !step.el.__rtSet) return false;\n h.past.push({ ...step, before: step.el.__rt!, at: Date.now() });\n step.el.__rtSet(step.before);\n return true;\n };\n /**\n * One action as ONE undo step (a separate copy, \"use shared version again\", a component inserted): in the host's\n * history when it keeps one (KitServices.historyStep: its toolbar Undo, an Undo toast and ⌘Z here are the same\n * undo), else in this editor's own (`before`: the model the island had; an insert has none, and stays as undoable\n * as any block inserted here). `write` makes the change and answers the island it changed. Answers its undo.\n */\n const oneStep = (label: string, write: () => IslandEl | null, before?: IslandModels[IslandKind]): (() => true | string) => {\n const h = hist.current;\n const made: { el: IslandEl | null } = { el: null };\n const historyStep = services.historyStep;\n const step = historyStep\n ? historyStep(() => {\n made.el = write();\n })\n : ((made.el = write()), null);\n const el = made.el;\n if (step) {\n h.hosts = [...h.hosts, { label, step }].slice(-100);\n return () => runHost(step.undo);\n }\n if (!el || !before) return () => \"This change has no undo step here.\";\n const s: IslandStep = { el, before, label, at: Date.now() };\n h.past = [...h.past, s].slice(-100);\n h.future = [];\n return () => {\n if (!h.past.includes(s)) return \"It was undone already.\";\n if (h.past[h.past.length - 1] !== s || s.at < h.textAt) return \"Changes made after it come first. Press ⌘Z to undo them.\";\n return islandUndo() ? true : \"The block was removed, so there is nothing to undo.\";\n };\n };\n const record = (el: IslandEl, before: IslandModels[IslandKind], label: string, coalesce?: boolean) => {\n const h = hist.current;\n const now = Date.now();\n const top = h.past[h.past.length - 1];\n // typing in one field coalesces (~500ms), unless the text was edited in between\n if (coalesce && top && top.el === el && top.label === label && now - top.at < 500 && top.at > h.textAt) top.at = now;\n else h.past = [...h.past, { el, before, label, at: now }].slice(-100);\n h.future = [];\n };\n const undoKey = (e: React.KeyboardEvent): boolean => {\n const mod = e.metaKey || e.ctrlKey;\n if (!mod || e.altKey || eventKey(e) !== \"z\") return false;\n if (e.shiftKey) {\n if (!islandRedo()) return false;\n e.preventDefault();\n return true;\n }\n if (islandUndo()) {\n e.preventDefault();\n return true;\n }\n if (!hist.current.past.length || !ref.current) return false;\n e.preventDefault();\n const before = ref.current.innerHTML;\n exec(\"undo\");\n if (ref.current.innerHTML === before) {\n hist.current.textAt = 0;\n islandUndo();\n }\n return true;\n };\n\n /* ── API for islands (stable) ────────────────────────────────────── */\n const api = React.useRef({ emit, deleteBlock, exitIsland, record, oneStep, notify, duplicateBlock, moveBlock, islandUndo, islandRedo, startDrag });\n api.current = { emit, deleteBlock, exitIsland, record, oneStep, notify, duplicateBlock, moveBlock, islandUndo, islandRedo, startDrag };\n const islandCtx = React.useMemo<IslandCtx>(\n () => ({\n readOnly,\n dense,\n emit: () => api.current.emit(),\n remove: (x) => api.current.deleteBlock(x),\n exit: (x) => api.current.exitIsland(x),\n record: (x, before, label, coalesce) => api.current.record(x, before, label, coalesce),\n step: (label, write, before) => api.current.oneStep(label, write, before),\n notify: (message, description) => api.current.notify(message, { description }),\n duplicate: (x) => api.current.duplicateBlock(x),\n move: (x, dir) => api.current.moveBlock(x, dir),\n undo: () => api.current.islandUndo(),\n redo: () => api.current.islandRedo(),\n drag: (x, e) => api.current.startDrag(x, e),\n }),\n [readOnly, dense],\n );\n\n const commentSel = onComment\n ? () => {\n restoreSel();\n const q = window.getSelection()?.toString().trim();\n // the comment popover takes over: the selection toolbar steps away so it never sits on the composer\n setBubble(null);\n setQuiet(true);\n if (q) onComment(q);\n }\n : undefined;\n const onMark = (cmd: MarkCmd) =>\n allows(MARK_FEATURE[cmd]) &&\n run(() =>\n cmd === \"superscript\" || cmd === \"subscript\" ? ref.current && toggleScript(ref.current, cmd === \"superscript\" ? \"sup\" : \"sub\") : exec(cmd),\n );\n const onStyle = (tag: string) => {\n restoreSel();\n turnInto(currentBlock(), tag);\n refresh();\n };\n\n /* ── render ──────────────────────────────────────────────────────── */\n const { flipUp, maxHeight: slashMaxH } = slash ? slashPlacement(slash.rect, window.innerHeight) : { flipUp: false, maxHeight: SLASH_MENU_H };\n const gBlock = gutter?.el;\n const gIsText = !!gBlock && !gBlock.hasAttribute(\"data-rt-island\") && gBlock.tagName !== \"HR\";\n const btn = dense ? \"size-5 [&_svg:not([data-rt-isolate]_*)]:size-3.5\" : \"size-[22px] [&_svg:not([data-rt-isolate]_*)]:size-3.5\";\n /* outside: + and grip float left of the box · inset: a slim grip sits in the 16px padding (insert via / or the\n toolbar) · none: compact inspector fields and one-paragraph fields */\n const gutterMode: \"outside\" | \"inset\" | \"none\" = readOnly || dense || single ? \"none\" : gutterRoom ? \"outside\" : \"inset\";\n const showGutter = gutterMode !== \"none\";\n const minH = expanded ? \"min-h-[60vh]\" : single ? \"min-h-9\" : dense ? \"min-h-[120px]\" : \"min-h-[190px]\";\n const turnStyles = stylesFor(allows).filter((s) => [\"p\", \"h1\", \"h2\", \"h3\", \"blockquote\"].includes(s.tag));\n\n return (\n <CatalogComponentsProvider value={components ?? null}>\n <div\n ref={wrap}\n data-rt-editor=\"\"\n className={cn(\n \"relative [--rt-toolbar-h:2rem] pointer-coarse:[--rt-toolbar-h:2.75rem]\",\n \"rounded-kit-lg border transition-colors duration-150\",\n /* the expanded modal is raised: the editor sits level with it, never below (D56) */\n expanded ? \"bg-[var(--kit-surface-raised)]\" : \"bg-kit-surface\",\n /* V2 rich-text-editor.tsx:1152: line at rest, line-strong while the toolbar is open; an invalid value (dash) keeps its edge */\n invalid ? \"border-[var(--kit-field-invalid)]\" : toolbarOpen ? \"border-kit-line-strong\" : \"border-kit-line\",\n )}\n /* what the sticky toolbar covers at the top of the scroll area */\n style={{ \"--rt-sticky-top\": toolbarOpen && !dense ? `calc(${stickyTop}px + var(--rt-toolbar-h))` : \"var(--kit-sticky-top, 0px)\" } as React.CSSProperties}\n onMouseLeave={() => !blockMenu && !gutterInsert && !drag && setGutter(null)}\n onKeyDown={onWrapKeyDown}\n onFocus={() => {\n window.clearTimeout(blurTimer.current);\n setFocused(true);\n }}\n onBlur={() => {\n window.clearTimeout(blurTimer.current);\n blurTimer.current = window.setTimeout(() => {\n const a = document.activeElement;\n if (wrap.current?.contains(a) || a?.closest(\"[role=menu],[role=dialog],[role=listbox],[data-floating-layer]\")) return;\n setFocused(false);\n setBubble(null);\n ref.current?.querySelectorAll(\"[data-hint]\").forEach((n) => n.removeAttribute(\"data-hint\"));\n if (valueRef.current !== known.current && !md) load(valueRef.current);\n }, 400);\n }}\n >\n {readOnly ? null : (\n <FormatToolbar\n open={toolbarOpen}\n sticky={!dense}\n stickyTop={stickyTop}\n width={width}\n dense={dense}\n fmt={fmt}\n md={!!md}\n allows={allows}\n hideFullscreen={hideFullscreen}\n insertOpen={insertOpen}\n setInsertOpen={(o) => {\n if (o) inserted.current = false;\n setInsertOpen(o);\n }}\n onMenuOpen={(name, o) => setMenus((m) => ({ ...m, [name]: o }))}\n onStyle={onStyle}\n onMark={onMark}\n onList={(kind) =>\n allows(kind) &&\n run(() => {\n // Chrome nests the list inside a heading/quote (<h2><ul>…) — turn the line into a paragraph first.\n const b = currentBlock();\n if (b && /^(H[1-6]|BLOCKQUOTE)$/.test(b.tagName)) turnInto(b, \"p\");\n exec(kind === \"ul\" ? \"insertUnorderedList\" : \"insertOrderedList\");\n // …and it can still leave <p><ul>…</ul></p>; lift the list out of any text block.\n ref.current?.querySelectorAll(\":is(p,h1,h2,h3,h4,h5,h6,blockquote) > :is(ul,ol)\").forEach((list) => {\n const host = list.parentElement!;\n host.replaceWith(...Array.from(host.childNodes).filter((n) => n.nodeType === 1 || n.textContent?.trim()));\n });\n })\n }\n onLink={openLink}\n onClear={() =>\n run(() => {\n exec(\"removeFormat\");\n exec(\"unlink\");\n })\n }\n onComment={commentSel}\n onInlineCode={() => {\n restoreSel();\n toggleInlineCode();\n }}\n onCodeBlock={() => {\n restoreSel();\n if (allows(\"pre\")) turnInto(currentBlock(), \"pre\");\n }}\n onInsert={(it) => {\n inserted.current = true;\n restoreSel();\n insertBlock(it);\n setInsertOpen(false);\n }}\n keepFocusOnInsertClose={() => inserted.current}\n onFullscreen={() => setModalOpen(true)}\n onMarkdown={toggleMarkdown}\n saveSel={saveSel}\n />\n )}\n\n {md ? (\n <div className=\"px-3 pb-2.5 pt-2.5\">\n <Textarea\n aria-label=\"Field content as Markdown\"\n spellCheck={false}\n value={md.text}\n readOnly={readOnly}\n onChange={(e) => {\n setMd({ ...md, text: e.target.value });\n setMdConfirm(false);\n }}\n className={cn(\"font-kit-mono text-kit-xs leading-5\", expanded ? \"min-h-[60vh]\" : dense ? \"min-h-[120px]\" : \"min-h-[190px]\")}\n style={scrollable ? { maxHeight } : undefined}\n />\n <p className=\"mt-1.5 text-kit-2xs text-kit-fg-3\">Markdown. Switching back converts it to blocks.</p>\n <AnimatePresence initial={false}>\n {mdConfirm ? (\n <motion.div\n key=\"confirm\"\n initial={{ opacity: 0, y: reduceMotion ? 0 : 4 }}\n animate={{ opacity: 1, y: 0 }}\n exit={{ opacity: 0, y: reduceMotion ? 0 : 4 }}\n transition={{ duration: 0.15 }}\n role=\"alertdialog\"\n aria-label=\"Convert edited Markdown?\"\n className=\"mt-2 flex flex-wrap items-center gap-2 rounded-kit-lg border border-kit-line bg-kit-subtle px-3 py-2\"\n >\n <span className=\"flex-1 text-kit-sm font-medium text-kit-fg\">Convert edited Markdown?</span>\n <Button size=\"xs\" variant=\"ghost\" onClick={() => setMdConfirm(false)}>\n Keep editing Markdown\n </Button>\n <Button size=\"xs\" variant=\"primary\" autoFocus onClick={convertMarkdown}>\n Convert to rich text\n </Button>\n </motion.div>\n ) : null}\n </AnimatePresence>\n </div>\n ) : (\n <div\n ref={scroller}\n className={cn(\"relative\", scrollable && \"overflow-y-auto\")}\n style={scrollable ? { maxHeight } : undefined}\n onMouseMove={(e) => {\n if (drag || blockMenu || gutterInsert || !showGutter) return;\n const t = e.target as HTMLElement;\n if (t.closest(\"[data-rt-gutter]\")) return;\n const b = topBlock(ref.current, t);\n // a component card carries its own handle and ⋯ menu (V2 rich-text-editor.tsx:1297-1298): no second grip beside it\n placeGutter(b?.getAttribute(\"data-rt-island\") === \"component\" ? null : b);\n }}\n >\n <div\n ref={ref}\n id={inModal ? undefined : id}\n role=\"textbox\"\n aria-multiline={!single}\n aria-labelledby={!inModal && id ? `${id}-label` : undefined}\n aria-label=\"Rich text\"\n aria-placeholder={ph}\n aria-readonly={readOnly || undefined}\n aria-invalid={invalid || undefined}\n contentEditable={!readOnly}\n suppressContentEditableWarning\n spellCheck\n tabIndex={readOnly ? 0 : undefined}\n onInput={onInput}\n onKeyDown={onKeyDown}\n onKeyUp={refresh}\n onMouseUp={refresh}\n onPaste={(e) => {\n if (readOnly) return;\n const files = Array.from(e.clipboardData.files).filter((f) => f.type.startsWith(\"image/\"));\n if (files.length) {\n e.preventDefault();\n notify(allows(\"image\") ? \"Add images from the media library\" : \"This field keeps no images\", {\n description: allows(\"image\") ? \"A pasted file has no address the page can show it from. Use Insert › Image.\" : undefined,\n });\n return;\n }\n const text = e.clipboardData.getData(\"text/plain\");\n e.preventDefault();\n if (!text) return;\n if (single || (!/\\n/.test(text.trim()) && !looksLikeMarkdown(text))) {\n insertTextAtCaret(single ? text.replace(/\\s*\\n\\s*/g, \" \") : text);\n emit();\n return;\n }\n let html: string;\n try {\n html = markdownToHtml(text);\n } catch {\n html = text.split(/\\n{2,}/).map((p) => `<p>${esc(p.trim()).replace(/\\n/g, \"<br>\")}</p>`).join(\"\");\n }\n insertHtmlAtCaret(conform(html));\n if (ref.current) hydrate(ref.current);\n emit();\n }}\n onDragOver={(e) => {\n if (e.dataTransfer.types.includes(\"application/x-bcms-asset\") && allows(\"image\")) e.preventDefault();\n }}\n onDrop={(e) => {\n const asset = e.dataTransfer.getData(\"application/x-bcms-asset\");\n if (!asset || readOnly || !allows(\"image\")) return;\n e.preventDefault();\n try {\n const a = JSON.parse(asset) as { url: string; alt?: string; name: string };\n const b = topBlock(ref.current, e.target as Node);\n const isl = createIsland(\"image\", defaultModel(\"image\", { src: a.url, alt: a.alt ?? \"\" }));\n if (b) b.after(isl);\n else ref.current?.append(isl);\n ops.ensureLineAfter(isl);\n emit();\n } catch {\n notify(\"That drop is not an image from the media library\");\n }\n }}\n className={cn(\n RT_PROSE,\n dense && RT_PANEL,\n \"peer relative outline-none focus-visible:shadow-none [&_*:not([data-rt-isolate]_*)]:outline-none\",\n \"[&>p[data-hint]]:before:pointer-events-none [&>p[data-hint]]:before:float-left [&>p[data-hint]]:before:h-0 [&>p[data-hint]]:before:text-kit-fg-4 [&>p[data-hint]]:before:content-[attr(data-hint)]\",\n \"[&_a[data-button]:not([data-rt-isolate]_*)]:cursor-pointer [&_ul[data-task]>li:not([data-rt-isolate]_*)]:before:cursor-pointer\",\n \"[&_sup[data-rt=fn]]:mx-px [&_sup[data-rt=fn]]:cursor-pointer [&_sup[data-rt=fn]]:rounded-kit-sm [&_sup[data-rt=fn]]:px-0.5 [&_sup[data-rt=fn]]:text-[0.72em] [&_sup[data-rt=fn]]:font-semibold [&_sup[data-rt=fn]]:text-kit-accent-fg [&_sup[data-rt=fn]:hover]:bg-kit-accent-soft\",\n dense ? \"px-2.5 py-2\" : \"px-4 py-3.5\",\n minH,\n )}\n />\n {empty ? (\n <div aria-hidden className={cn(\"pointer-events-none absolute text-kit-fg-4 peer-focus:hidden\", dense ? \"text-kit-sm\" : \"text-kit-base\", dense ? \"left-2.5 top-2\" : \"left-4 top-3.5\")}>\n {ph}\n </div>\n ) : null}\n\n {/* Block gutter (+ / grip) */}\n {gutter && showGutter ? (\n <div\n data-rt-gutter=\"\"\n /* z-3: under the sticky toolbar (z-4), so a tall block's grip never paints over it */\n className={cn(\"absolute z-[3] flex items-start\", gutterMode === \"outside\" ? \"-left-12 pr-1\" : \"left-0\")}\n style={{ top: gutter.top + Math.max(-2, Math.min(4, gutter.height / 2 - 12)) }}\n >\n {gutterMode === \"outside\" ? (\n <Popover\n open={gutterInsert}\n onOpenChange={(o) => {\n if (o) {\n gutterTarget.current = gutter.el;\n inserted.current = false;\n }\n setGutterInsert(o);\n }}\n >\n <Tooltip content=\"Add a block below\" disabled={gutterInsert}>\n <PopoverTrigger\n aria-label=\"Add a block below\"\n className={cn(\"flex 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\", btn)}\n >\n <IconPlus stroke={1.5} aria-hidden />\n </PopoverTrigger>\n </Tooltip>\n {gutterInsert ? (\n <InsertMenuContent\n side=\"bottom\"\n align=\"start\"\n allows={allows}\n keepFocusOnClose={() => inserted.current}\n onInsert={(it) => {\n const b = gutterTarget.current;\n const el = ref.current;\n inserted.current = true;\n setGutterInsert(false);\n if (!b || !el || !el.contains(b)) return;\n const p = document.createElement(\"p\");\n p.innerHTML = \"<br>\";\n b.after(p);\n el.focus({ preventScroll: true });\n placeCaret(p);\n insertBlock(it);\n }}\n />\n ) : null}\n </Popover>\n ) : null}\n <Menu open={blockMenu} onOpenChange={setBlockMenu}>\n <Tooltip content=\"Drag to move, click for options\" disabled={blockMenu || !!drag}>\n <MenuTrigger\n aria-label=\"Block options\"\n onPointerDown={onGripDown}\n onKeyDown={(e) => {\n if (e.key === \"Enter\" || e.key === \" \") {\n e.preventDefault();\n setBlockMenu(true);\n }\n }}\n className={cn(\n \"flex cursor-grab items-center justify-center rounded-kit-md text-kit-fg-3 hover:bg-kit-hover hover:text-kit-fg active:cursor-grabbing\",\n gutterMode === \"inset\" ? \"h-[22px] w-4 rounded-kit-sm [&_svg:not([data-rt-isolate]_*)]:size-3.5\" : btn,\n (blockMenu || drag) && \"bg-kit-hover text-kit-fg\",\n )}\n >\n <IconGripVertical stroke={1.5} aria-hidden />\n </MenuTrigger>\n </Tooltip>\n <MenuContent className=\"w-56\" align=\"start\" finalFocus={false}>\n {turnStyles.length > 1 ? (\n <MenuSub>\n <MenuSubTrigger icon={<IconTransform stroke={1.5} />} disabled={!gIsText}>\n Turn into\n </MenuSubTrigger>\n <MenuSubContent className=\"w-48\">\n {turnStyles.map((t) => (\n <MenuItem key={t.tag} icon={t.icon} onClick={() => turnInto(gBlock ?? null, t.tag)}>\n {t.label}\n </MenuItem>\n ))}\n </MenuSubContent>\n </MenuSub>\n ) : null}\n <MenuItem icon={<IconCopy stroke={1.5} />} shortcut=\"⌘D\" onClick={() => gBlock && duplicateBlock(gBlock)}>\n Duplicate\n </MenuItem>\n <MenuItem icon={<IconArrowBarToUp stroke={1.5} />} shortcut=\"⌘⇧↑\" disabled={!gBlock?.previousElementSibling} onClick={() => gBlock && moveBlock(gBlock, -1)}>\n Move up\n </MenuItem>\n <MenuItem icon={<IconArrowBarToDown stroke={1.5} />} shortcut=\"⌘⇧↓\" disabled={!gBlock?.nextElementSibling} onClick={() => gBlock && moveBlock(gBlock, 1)}>\n Move down\n </MenuItem>\n <MenuSeparator />\n <MenuItem danger icon={<IconTrash stroke={1.5} />} onClick={() => gBlock && deleteBlock(gBlock)}>\n Delete\n </MenuItem>\n </MenuContent>\n </Menu>\n </div>\n ) : null}\n {drag?.line != null ? <div className=\"pointer-events-none absolute inset-x-3 z-[6] h-0.5 rounded-full bg-kit-info\" style={{ top: drag.line }} /> : null}\n\n {/* Rich blocks render into their contenteditable=false hosts */}\n {islands.map(({ id: key, el }) => createPortal(<Island el={el} ctx={islandCtx} />, el, key))}\n </div>\n )}\n\n {/* Footer meta (V2 rich-text-editor.tsx:1563-1571), and any refusal said in place when the host has no toaster */}\n <div className=\"flex h-7 items-center justify-end gap-3 rounded-b-kit-lg border-t border-kit-line-subtle px-3 text-kit-2xs text-kit-fg-3\">\n {notice ? (\n <span role=\"status\" aria-live=\"polite\" className=\"mr-auto min-w-0 truncate text-kit-fg-2\">\n {notice.message}\n {notice.description ? ` ${notice.description}` : \"\"}\n {notice.action ? (\n <button\n type=\"button\"\n className=\"ml-1.5 font-medium text-kit-fg underline underline-offset-2\"\n onClick={() => {\n notice.action!.onClick();\n setNotice(null);\n }}\n >\n {notice.action.label}\n </button>\n ) : null}\n </span>\n ) : null}\n <span className=\"tabular-nums\">\n {words.toLocaleString(\"en-US\")} {words === 1 ? \"word\" : \"words\"}\n {comps ? ` · ${comps} ${comps === 1 ? \"block\" : \"blocks\"}` : \"\"} · {Math.max(1, Math.round(words / 220))} min read\n </span>\n </div>\n\n {/* Bubble toolbar on selection: a toolbar menu owns the moment, so the bubble steps aside while one is open */}\n {bubble && !quiet && !readOnly && !slash && !link && !md && !menus.style && !menus.more && !insertOpen ? (\n <SelectionBubble\n rect={bubble}\n avoid={toolbarOpen ? wrap.current?.querySelector<HTMLElement>('[role=\"toolbar\"][aria-label=\"Text formatting\"]')?.getBoundingClientRect() : null}\n fmt={fmt}\n allows={allows}\n saveSel={saveSel}\n onAi={canAI ? aiRewrite : undefined}\n onStyle={onStyle}\n onMark={onMark}\n onInlineCode={() => {\n restoreSel();\n toggleInlineCode();\n }}\n onLink={openLink}\n onComment={commentSel}\n />\n ) : null}\n\n {/* Slash menu (opens only at the start of a block; never takes focus) */}\n {slash && !md\n ? createPortal(\n <>\n <div data-floating-layer=\"\" className=\"pointer-events-auto fixed inset-0 z-[var(--kit-z-popover,84)]\" onMouseDown={() => setSlash(null)} />\n <motion.div\n initial={{ opacity: 0, y: flipUp ? -4 : 4 }}\n animate={{ opacity: 1, y: 0 }}\n transition={{ duration: 0.14 }}\n style={{\n left: Math.min(window.innerWidth - 330, Math.max(8, slash.rect.left)),\n ...(flipUp ? { bottom: window.innerHeight - slash.rect.top + 6 } : { top: slash.rect.bottom + 6 }),\n }}\n data-floating-layer=\"\"\n className=\"pointer-events-auto fixed z-[calc(var(--kit-z-popover,84)_+_1)]\"\n >\n <SlashMenuPanel query={slash.query} folder={slash.folder} active={slash.active} allows={allows} setActive={(a) => setSlash((s) => s && { ...s, active: a })} onPick={pickSlash} maxHeight={slashMaxH} />\n </motion.div>\n </>,\n document.body,\n )\n : null}\n\n {/* Link popover anchored to the selection */}\n <Popover open={!!link} onOpenChange={(o) => !o && setLink(null)}>\n <PopoverAnchor\n render={<span className=\"pointer-events-none fixed\" style={link ? { top: link.rect.bottom, left: link.rect.left, width: Math.max(1, link.rect.width), height: 1 } : { top: 0, left: 0 }} />}\n />\n <PopoverContent className=\"w-[340px] rounded-kit-lg p-3\" finalFocus={false}>\n {link ? (\n <div className=\"flex flex-col gap-2\">\n <LinkForm\n initial={link.initial}\n allowNewTab={allowNewTab}\n onSave={saveLink}\n onCancel={() => setLink(null)}\n onDetach={\n link.existing\n ? () => {\n const a = link.existing!;\n a.replaceWith(...Array.from(a.childNodes));\n setLink(null);\n emit();\n }\n : undefined\n }\n />\n </div>\n ) : null}\n </PopoverContent>\n </Popover>\n {!hideFullscreen ? (\n <ExpandedEditorModal open={modalOpen} onOpenChange={setModalOpen} crumbs={expandCrumbs?.length ? expandCrumbs : [\"Text\"]} returnFocus={() => ref.current} meta={bodyCountLabel(value)}>\n {modalOpen ? (\n <RichTextEditor\n value={value}\n onChange={onChange}\n readOnly={readOnly}\n placeholder={placeholder}\n docKey={`${docKey}:expanded`}\n features={features}\n single={single}\n allowNewTab={allowNewTab}\n expandCrumbs={expandCrumbs}\n variant=\"document\"\n hideFullscreen\n inModal\n autoFocus\n onComment={onComment}\n components={components}\n />\n ) : null}\n </ExpandedEditorModal>\n ) : null}\n </div>\n </CatalogComponentsProvider>\n );\n}\n\n"],"mappings":"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"}
@@ -1,3 +1,8 @@
1
+ /**
2
+ * RICH TEXT · the selection bubble: AI rewrite, style, marks, link (V2 HEAD controls/rich-text/floating.tsx).
3
+ * V2's inline "Ask AI" prompt took free text; the host's AI service rewrites by preset only, so it is not drawn.
4
+ */
5
+ import * as React from "react";
1
6
  import type { AiPreset } from "../../context";
2
7
  import type { RichTextFeature } from "./codec";
3
8
  import { type Fmt, type MarkCmd } from "./toolbar";
@@ -20,4 +25,4 @@ export declare function SelectionBubble({ rect, fmt, allows, saveSel, onAi, onSt
20
25
  onInlineCode: () => void;
21
26
  onLink: () => void;
22
27
  onComment?: () => void;
23
- }): import("react").ReactPortal;
28
+ }): React.ReactPortal;
@@ -1,11 +1,11 @@
1
1
  import { Sparkle } from "../../ui/button.js";
2
2
  import { Menu, MenuContent, MenuItem, MenuTrigger } from "../../ui/overlay.js";
3
3
  import { StyleMenu, ToolButton, stylesFor } from "./toolbar.js";
4
- import { IconBold, IconCode, IconItalic, IconLink, IconMessage, IconStrikethrough, IconUnderline } from "@tabler/icons-react";
4
+ import * as React from "react";
5
5
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
6
- import { motion } from "framer-motion";
6
+ import { IconBold, IconCode, IconItalic, IconLink, IconMessage, IconStrikethrough, IconSubscript, IconSuperscript, IconUnderline } from "@tabler/icons-react";
7
7
  import { createPortal } from "react-dom";
8
- //#region src/kit/controls/rich-text/floating.tsx
8
+ //#region src/controls/rich-text/floating.tsx
9
9
  /**
10
10
  * RICH TEXT · the selection bubble: AI rewrite, style, marks, link (V2 HEAD controls/rich-text/floating.tsx).
11
11
  * V2's inline "Ask AI" prompt took free text; the host's AI service rewrites by preset only, so it is not drawn.
@@ -33,26 +33,28 @@ function SelectionBubble({ rect, fmt, allows, saveSel, onAi, onStyle, onMark, on
33
33
  const above = rect.top - 44;
34
34
  const top = above < 8 || !!avoid && above < avoid.bottom + 4 && above + 36 > avoid.top ? rect.bottom + 8 : above;
35
35
  const styles = stylesFor(allows);
36
- return createPortal(/* @__PURE__ */ jsxs(motion.div, {
37
- initial: {
38
- opacity: 0,
39
- y: 4
40
- },
41
- animate: {
42
- opacity: 1,
43
- y: 0
44
- },
45
- transition: { duration: .14 },
36
+ const ref = React.useRef(null);
37
+ const [w, setW] = React.useState(460);
38
+ React.useLayoutEffect(() => {
39
+ if (ref.current) setW(ref.current.offsetWidth);
40
+ }, [
41
+ fmt.block,
42
+ !!onAi,
43
+ !!onComment
44
+ ]);
45
+ return createPortal(/* @__PURE__ */ jsxs("div", {
46
46
  onMouseDown: (e) => {
47
47
  if (!e.target.closest("button")) e.preventDefault();
48
48
  },
49
+ ref,
49
50
  style: {
50
51
  top,
51
- left: Math.min(window.innerWidth - 400, Math.max(8, rect.left + rect.width / 2 - 190))
52
+ boxShadow: "var(--kit-shadow-sm)",
53
+ left: Math.min(window.innerWidth - w - 8, Math.max(8, rect.left + rect.width / 2 - w / 2))
52
54
  },
53
55
  "data-floating-layer": "",
54
56
  "data-kit-scope": "",
55
- className: "pointer-events-auto fixed z-[85] flex h-9 items-center gap-0.5 rounded-kit-lg border border-kit-line bg-kit-surface px-1 text-kit-fg shadow-kit-sm [.dark_&]:border-kit-line-strong [.dark_&]:bg-[#252528]",
57
+ className: "glass-strong pointer-events-auto fixed z-[calc(var(--kit-z-popover,84)_+_1)] flex h-9 items-center gap-0.5 rounded-kit-lg border border-kit-line px-1",
56
58
  role: "toolbar",
57
59
  "aria-label": "Selection formatting",
58
60
  children: [
@@ -110,6 +112,18 @@ function SelectionBubble({ rect, fmt, allows, saveSel, onAi, onStyle, onMark, on
110
112
  active: fmt.strike,
111
113
  onClick: () => onMark("strikeThrough")
112
114
  }) : null,
115
+ allows("sup") ? /* @__PURE__ */ jsx(ToolButton, {
116
+ label: "Superscript",
117
+ icon: /* @__PURE__ */ jsx(IconSuperscript, { stroke: 1.5 }),
118
+ active: fmt.sup,
119
+ onClick: () => onMark("superscript")
120
+ }) : null,
121
+ allows("sub") ? /* @__PURE__ */ jsx(ToolButton, {
122
+ label: "Subscript",
123
+ icon: /* @__PURE__ */ jsx(IconSubscript, { stroke: 1.5 }),
124
+ active: fmt.sub,
125
+ onClick: () => onMark("subscript")
126
+ }) : null,
113
127
  allows("code") ? /* @__PURE__ */ jsx(ToolButton, {
114
128
  label: "Inline code",
115
129
  icon: /* @__PURE__ */ jsx(IconCode, { stroke: 1.5 }),
@@ -123,15 +137,18 @@ function SelectionBubble({ rect, fmt, allows, saveSel, onAi, onStyle, onMark, on
123
137
  active: fmt.onLink,
124
138
  onClick: onLink
125
139
  }) : null,
126
- onComment ? /* @__PURE__ */ jsx(ToolButton, {
140
+ onComment ? /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx("span", {
141
+ "aria-hidden": true,
142
+ className: "mx-0.5 h-4 w-px bg-kit-line"
143
+ }), /* @__PURE__ */ jsx(ToolButton, {
127
144
  label: "Comment",
128
145
  icon: /* @__PURE__ */ jsx(IconMessage, { stroke: 1.5 }),
129
146
  onClick: onComment
130
- }) : null
147
+ })] }) : null
131
148
  ]
132
149
  }), document.body);
133
150
  }
134
151
  //#endregion
135
- export { SelectionBubble };
152
+ export { BUBBLE_AI, SelectionBubble };
136
153
 
137
154
  //# sourceMappingURL=floating.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"floating.js","names":[],"sources":["../../../src/controls/rich-text/floating.tsx"],"sourcesContent":["/**\n * RICH TEXT · the selection bubble: AI rewrite, style, marks, link (V2 HEAD controls/rich-text/floating.tsx).\n * V2's inline \"Ask AI\" prompt took free text; the host's AI service rewrites by preset only, so it is not drawn.\n */\nimport * as React from \"react\";\nimport { createPortal } from \"react-dom\";\nimport { IconBold, IconCode, IconItalic, IconLink, IconMessage, IconStrikethrough, IconSubscript, IconSuperscript, IconUnderline } from \"@tabler/icons-react\";\nimport { Sparkle } from \"../../ui/button\";\nimport { Menu, MenuContent, MenuItem, MenuTrigger } from \"../../ui/overlay\";\nimport type { AiPreset } from \"../../context\";\nimport type { RichTextFeature } from \"./codec\";\nimport { StyleMenu, ToolButton, stylesFor, type Fmt, type MarkCmd } from \"./toolbar\";\n\n/** The bubble's rewrite directions (V2: improve, shorter, punchier, grammar), as the host service's presets. */\nexport const BUBBLE_AI: { id: AiPreset; label: string }[] = [\n { id: \"improve\", label: \"Improve writing\" },\n { id: \"shorter\", label: \"Make shorter\" },\n { id: \"simplify\", label: \"Simplify\" },\n { id: \"grammar\", label: \"Fix spelling and grammar\" },\n];\n\nexport function SelectionBubble({\n rect,\n fmt,\n allows,\n saveSel,\n onAi,\n onStyle,\n onMark,\n onInlineCode,\n onLink,\n onComment,\n avoid,\n}: {\n rect: DOMRect;\n /** The editor's own toolbar row (when it is open): the bubble never sits on top of it. */\n avoid?: DOMRect | null;\n fmt: Fmt;\n allows: (f: RichTextFeature) => boolean;\n saveSel: () => void;\n /** Absent when the person has no AI (D58: ai.use) or the host has no AI service: the AI menu and its divider are not drawn. */\n onAi?: (preset: AiPreset) => void;\n onStyle: (tag: string) => void;\n onMark: (cmd: MarkCmd) => void;\n onInlineCode: () => void;\n onLink: () => void;\n onComment?: () => void;\n}) {\n // Above the selection by default; flips below it when above would cover the editor's toolbar or leave the viewport.\n const above = rect.top - 44;\n const blocked = above < 8 || (!!avoid && above < avoid.bottom + 4 && above + 36 > avoid.top);\n const top = blocked ? rect.bottom + 8 : above;\n const styles = stylesFor(allows);\n // centre on the selection with the bubble's real width (it grows with AI, style and comment), never past either edge\n const ref = React.useRef<HTMLDivElement>(null);\n const [w, setW] = React.useState(460);\n React.useLayoutEffect(() => {\n if (ref.current) setW(ref.current.offsetWidth);\n }, [fmt.block, !!onAi, !!onComment]);\n return createPortal(\n // No entrance motion: the bubble shows on every text selection, a 100+/day action.\n <div\n onMouseDown={(e) => {\n if (!(e.target as HTMLElement).closest(\"button\")) e.preventDefault();\n }}\n ref={ref}\n style={{ top, boxShadow: \"var(--kit-shadow-sm)\", left: Math.min(window.innerWidth - w - 8, Math.max(8, rect.left + rect.width / 2 - w / 2)) }}\n data-floating-layer=\"\"\n data-kit-scope=\"\"\n /* V2 floating.tsx:57-59: glass-strong for the raised fill and hairline; the tight shadow-sm (inline, so it beats the\n glass drop) keeps the shadow off the selected text right under the bubble */\n className=\"glass-strong pointer-events-auto fixed z-[calc(var(--kit-z-popover,84)_+_1)] flex h-9 items-center gap-0.5 rounded-kit-lg border border-kit-line px-1\"\n role=\"toolbar\"\n aria-label=\"Selection formatting\"\n >\n {onAi ? (\n <>\n <Menu>\n <MenuTrigger\n onMouseDown={(e) => {\n e.preventDefault();\n saveSel();\n }}\n className=\"flex h-7 items-center gap-1.5 rounded-kit-md px-2 text-kit-sm text-kit-fg hover:bg-kit-hover data-[popup-open]:bg-kit-hover\"\n >\n <Sparkle size={14} /> Improve writing\n </MenuTrigger>\n <MenuContent className=\"w-52\" finalFocus={false}>\n {BUBBLE_AI.map((p) => (\n <MenuItem key={p.id} icon={<Sparkle size={16} />} onClick={() => onAi(p.id)}>\n {p.label}\n </MenuItem>\n ))}\n </MenuContent>\n </Menu>\n <span aria-hidden className=\"mx-0.5 h-4 w-px bg-kit-line\" />\n </>\n ) : null}\n {fmt.block !== \"island\" && styles.length > 1 ? (\n <>\n <StyleMenu block={fmt.block} styles={styles} onPick={onStyle} />\n <span aria-hidden className=\"mx-0.5 h-4 w-px bg-kit-line\" />\n </>\n ) : null}\n {allows(\"bold\") ? <ToolButton label=\"Bold\" icon={<IconBold stroke={1.5} />} shortcut=\"⌘B\" active={fmt.bold} onClick={() => onMark(\"bold\")} /> : null}\n {allows(\"italic\") ? <ToolButton label=\"Italic\" icon={<IconItalic stroke={1.5} />} shortcut=\"⌘I\" active={fmt.italic} onClick={() => onMark(\"italic\")} /> : null}\n {allows(\"underline\") ? <ToolButton label=\"Underline\" icon={<IconUnderline stroke={1.5} />} shortcut=\"⌘U\" active={fmt.underline} onClick={() => onMark(\"underline\")} /> : null}\n {allows(\"strike\") ? <ToolButton label=\"Strikethrough\" icon={<IconStrikethrough stroke={1.5} />} active={fmt.strike} onClick={() => onMark(\"strikeThrough\")} /> : null}\n {/* x² and x₂: one at a time (picking one inside the other swaps them) */}\n {allows(\"sup\") ? <ToolButton label=\"Superscript\" icon={<IconSuperscript stroke={1.5} />} active={fmt.sup} onClick={() => onMark(\"superscript\")} /> : null}\n {allows(\"sub\") ? <ToolButton label=\"Subscript\" icon={<IconSubscript stroke={1.5} />} active={fmt.sub} onClick={() => onMark(\"subscript\")} /> : null}\n {allows(\"code\") ? <ToolButton label=\"Inline code\" icon={<IconCode stroke={1.5} />} shortcut=\"⌘E\" onClick={onInlineCode} /> : null}\n {allows(\"link\") ? <ToolButton label=\"Link\" icon={<IconLink stroke={1.5} />} shortcut=\"⌘K\" active={fmt.onLink} onClick={onLink} /> : null}\n {onComment ? (\n <>\n <span aria-hidden className=\"mx-0.5 h-4 w-px bg-kit-line\" />\n <ToolButton label=\"Comment\" icon={<IconMessage stroke={1.5} />} onClick={onComment} />\n </>\n ) : null}\n </div>,\n document.body,\n );\n}\n"],"mappings":";;;;;;;;;;;;;AAcA,IAAa,YAA+C;CAC1D;EAAE,IAAI;EAAW,OAAO;CAAkB;CAC1C;EAAE,IAAI;EAAW,OAAO;CAAe;CACvC;EAAE,IAAI;EAAY,OAAO;CAAW;CACpC;EAAE,IAAI;EAAW,OAAO;CAA2B;AACrD;AAEA,SAAgB,gBAAgB,EAC9B,MACA,KACA,QACA,SACA,MACA,SACA,QACA,cACA,QACA,WACA,SAeC;CAED,MAAM,QAAQ,KAAK,MAAM;CAEzB,MAAM,MADU,QAAQ,KAAM,CAAC,CAAC,SAAS,QAAQ,MAAM,SAAS,KAAK,QAAQ,KAAK,MAAM,MAClE,KAAK,SAAS,IAAI;CACxC,MAAM,SAAS,UAAU,MAAM;CAE/B,MAAM,MAAM,MAAM,OAAuB,IAAI;CAC7C,MAAM,CAAC,GAAG,QAAQ,MAAM,SAAS,GAAG;CACpC,MAAM,sBAAsB;EAC1B,IAAI,IAAI,SAAS,KAAK,IAAI,QAAQ,WAAW;CAC/C,GAAG;EAAC,IAAI;EAAO,CAAC,CAAC;EAAM,CAAC,CAAC;CAAS,CAAC;CACnC,OAAO,aAEL,qBAAC,OAAD;EACE,cAAc,MAAM;GAClB,IAAI,CAAE,EAAE,OAAuB,QAAQ,QAAQ,GAAG,EAAE,eAAe;EACrE;EACK;EACL,OAAO;GAAE;GAAK,WAAW;GAAwB,MAAM,KAAK,IAAI,OAAO,aAAa,IAAI,GAAG,KAAK,IAAI,GAAG,KAAK,OAAO,KAAK,QAAQ,IAAI,IAAI,CAAC,CAAC;EAAE;EAC5I,uBAAoB;EACpB,kBAAe;EAGf,WAAU;EACV,MAAK;EACL,cAAW;EAZb,UAAA;GAcG,OACC,qBAAA,UAAA,EAAA,UAAA,CACE,qBAAC,MAAD,EAAA,UAAA,CACE,qBAAC,aAAD;IACE,cAAc,MAAM;KAClB,EAAE,eAAe;KACjB,QAAQ;IACV;IACA,WAAU;IALZ,UAAA,CAOE,oBAAC,SAAD,EAAS,MAAM,GAAK,CAAA,GAAC,kBACV;GACb,CAAA,GAAA,oBAAC,aAAD;IAAa,WAAU;IAAO,YAAY;IACvC,UAAA,UAAU,KAAK,MACd,oBAAC,UAAD;KAAqB,MAAM,oBAAC,SAAD,EAAS,MAAM,GAAK,CAAA;KAAG,eAAe,KAAK,EAAE,EAAE;KACvE,UAAA,EAAE;IACK,GAFK,EAAE,EAEP,CACX;GACU,CAAA,CACT,EAAA,CAAA,GACN,oBAAC,QAAD;IAAM,eAAA;IAAY,WAAU;GAA+B,CAAA,CAC3D,EAAA,CAAA,IACA;GACH,IAAI,UAAU,YAAY,OAAO,SAAS,IACzC,qBAAA,UAAA,EAAA,UAAA,CACE,oBAAC,WAAD;IAAW,OAAO,IAAI;IAAe;IAAQ,QAAQ;GAAU,CAAA,GAC/D,oBAAC,QAAD;IAAM,eAAA;IAAY,WAAU;GAA+B,CAAA,CAC3D,EAAA,CAAA,IACA;GACH,OAAO,MAAM,IAAI,oBAAC,YAAD;IAAY,OAAM;IAAO,MAAM,oBAAC,UAAD,EAAU,QAAQ,IAAM,CAAA;IAAG,UAAS;IAAK,QAAQ,IAAI;IAAM,eAAe,OAAO,MAAM;GAAI,CAAA,IAAI;GAC/I,OAAO,QAAQ,IAAI,oBAAC,YAAD;IAAY,OAAM;IAAS,MAAM,oBAAC,YAAD,EAAY,QAAQ,IAAM,CAAA;IAAG,UAAS;IAAK,QAAQ,IAAI;IAAQ,eAAe,OAAO,QAAQ;GAAI,CAAA,IAAI;GACzJ,OAAO,WAAW,IAAI,oBAAC,YAAD;IAAY,OAAM;IAAY,MAAM,oBAAC,eAAD,EAAe,QAAQ,IAAM,CAAA;IAAG,UAAS;IAAK,QAAQ,IAAI;IAAW,eAAe,OAAO,WAAW;GAAI,CAAA,IAAI;GACxK,OAAO,QAAQ,IAAI,oBAAC,YAAD;IAAY,OAAM;IAAgB,MAAM,oBAAC,mBAAD,EAAmB,QAAQ,IAAM,CAAA;IAAG,QAAQ,IAAI;IAAQ,eAAe,OAAO,eAAe;GAAI,CAAA,IAAI;GAEhK,OAAO,KAAK,IAAI,oBAAC,YAAD;IAAY,OAAM;IAAc,MAAM,oBAAC,iBAAD,EAAiB,QAAQ,IAAM,CAAA;IAAG,QAAQ,IAAI;IAAK,eAAe,OAAO,aAAa;GAAI,CAAA,IAAI;GACpJ,OAAO,KAAK,IAAI,oBAAC,YAAD;IAAY,OAAM;IAAY,MAAM,oBAAC,eAAD,EAAe,QAAQ,IAAM,CAAA;IAAG,QAAQ,IAAI;IAAK,eAAe,OAAO,WAAW;GAAI,CAAA,IAAI;GAC9I,OAAO,MAAM,IAAI,oBAAC,YAAD;IAAY,OAAM;IAAc,MAAM,oBAAC,UAAD,EAAU,QAAQ,IAAM,CAAA;IAAG,UAAS;IAAK,SAAS;GAAe,CAAA,IAAI;GAC5H,OAAO,MAAM,IAAI,oBAAC,YAAD;IAAY,OAAM;IAAO,MAAM,oBAAC,UAAD,EAAU,QAAQ,IAAM,CAAA;IAAG,UAAS;IAAK,QAAQ,IAAI;IAAQ,SAAS;GAAS,CAAA,IAAI;GACnI,YACC,qBAAA,UAAA,EAAA,UAAA,CACE,oBAAC,QAAD;IAAM,eAAA;IAAY,WAAU;GAA+B,CAAA,GAC3D,oBAAC,YAAD;IAAY,OAAM;IAAU,MAAM,oBAAC,aAAD,EAAa,QAAQ,IAAM,CAAA;IAAG,SAAS;GAAY,CAAA,CACrF,EAAA,CAAA,IACA;EACD;CACL,CAAA,GAAA,SAAS,IACX;AACF"}
@@ -1,6 +1,6 @@
1
1
  import { ACTIONS, CONTROLS } from "../../engine/kit-field.js";
2
2
  import { RichTextControl, RichTextExpandAction } from "./control.js";
3
- //#region src/kit/controls/rich-text/index.ts
3
+ //#region src/controls/rich-text/index.ts
4
4
  /**
5
5
  * Rich text: registers the control and its label-row action (one line each, so lanes merge cleanly).
6
6
  * Imported for its side effect by whatever loads the kit's controls; import the parts themselves by path.
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","names":[],"sources":["../../../src/controls/rich-text/index.ts"],"sourcesContent":["/**\n * Rich text: registers the control and its label-row action (one line each, so lanes merge cleanly).\n * Imported for its side effect by whatever loads the kit's controls; import the parts themselves by path.\n */\nimport { ACTIONS, CONTROLS } from \"../../engine/kit-field\";\nimport { RichTextControl, RichTextExpandAction } from \"./control\";\n\nCONTROLS.richtext = RichTextControl;\nACTIONS.richtext = RichTextExpandAction;\n"],"mappings":";;;;;;;AAOA,SAAS,WAAW;AACpB,QAAQ,WAAW"}
@@ -0,0 +1,147 @@
1
+ import { Button } from "../../ui/button.js";
2
+ import { Switch } from "../../ui/controls.js";
3
+ import { Input } from "../../ui/input.js";
4
+ import { LinkLine, normLink } from "../link.js";
5
+ import * as React from "react";
6
+ import { jsx, jsxs } from "react/jsx-runtime";
7
+ import { IconLink } from "@tabler/icons-react";
8
+ //#region src/controls/rich-text/link-form.tsx
9
+ /**
10
+ * RICH TEXT · the link popover's body for a link inside the text, in V2's link panel chrome (controls/link.tsx
11
+ * LinkPopoverBody: what it links to now · the address · Remove link · Cancel · Apply): the address, and "Open in new tab"
12
+ * when the field allows it. A text link stores its address and target only (production's link mark), so V2's link type
13
+ * select and rel choice, which belong to the link FIELD, are not offered here.
14
+ */
15
+ /** An address a link may carry: http(s), mailto, tel, a site path or an in-page anchor. */
16
+ function linkProblem(href) {
17
+ const h = href.trim();
18
+ if (!h) return "Add an address first.";
19
+ if (/^(https?:\/\/[^\s]+|mailto:[^\s]+|tel:[+\d][\d\s()-]*|\/(?!\/)[^\s]*|#[^\s]+)$/i.test(h)) return null;
20
+ if (/^[a-z][a-z0-9+.-]*:/i.test(h)) return "Use an address that starts with https://, mailto: or tel:.";
21
+ if (/^[^\s/]+\.[^\s]+$/.test(h)) return `Add https:// in front: https://${h}`;
22
+ return "Use a full address (https://…), a page path (/about) or an anchor (#section).";
23
+ }
24
+ function LinkForm({ initial, allowNewTab, onSave, onCancel, onDetach }) {
25
+ const [href, setHref] = React.useState(initial.href);
26
+ const [newTab, setNewTab] = React.useState(!!initial.newTab);
27
+ const [problem, setProblem] = React.useState(null);
28
+ const urlId = React.useId();
29
+ const tabId = React.useId();
30
+ const errId = React.useId();
31
+ const start = initial.href.trim();
32
+ const changed = href.trim() !== start || allowNewTab && newTab !== !!initial.newTab;
33
+ const ok = !linkProblem(href);
34
+ return /* @__PURE__ */ jsxs("form", {
35
+ className: "flex flex-col gap-3",
36
+ onSubmit: (e) => {
37
+ e.preventDefault();
38
+ const p = linkProblem(href);
39
+ setProblem(p);
40
+ if (!p) onSave({
41
+ href: href.trim(),
42
+ newTab: allowNewTab && newTab
43
+ });
44
+ },
45
+ children: [
46
+ /* @__PURE__ */ jsxs("div", {
47
+ className: "flex min-w-0 flex-col gap-1",
48
+ children: [/* @__PURE__ */ jsx("span", {
49
+ className: "text-kit-sm font-medium text-kit-fg",
50
+ children: "Link"
51
+ }), start ? /* @__PURE__ */ jsx("span", {
52
+ className: "flex min-w-0 text-kit-fg-2",
53
+ children: /* @__PURE__ */ jsx(LinkLine, { v: normLink({
54
+ href: start,
55
+ newTab: !!initial.newTab
56
+ }) })
57
+ }) : /* @__PURE__ */ jsx("span", {
58
+ className: "text-kit-xs text-kit-fg-3",
59
+ children: "No link yet"
60
+ })]
61
+ }),
62
+ /* @__PURE__ */ jsxs("div", {
63
+ className: "flex flex-col gap-1.5",
64
+ onBlur: (e) => {
65
+ if (!e.currentTarget.contains(e.relatedTarget) && href.trim()) setProblem(linkProblem(href));
66
+ },
67
+ children: [
68
+ /* @__PURE__ */ jsx("label", {
69
+ htmlFor: urlId,
70
+ className: "text-kit-xs text-kit-fg-2",
71
+ children: "Link to"
72
+ }),
73
+ /* @__PURE__ */ jsx(Input, {
74
+ id: urlId,
75
+ autoFocus: true,
76
+ size: "sm",
77
+ value: href,
78
+ onChange: (e) => {
79
+ setHref(e.target.value);
80
+ if (problem) setProblem(null);
81
+ },
82
+ onKeyDown: (e) => {
83
+ if (e.key === "Enter" && !ok) {
84
+ e.preventDefault();
85
+ setProblem(linkProblem(href));
86
+ }
87
+ },
88
+ placeholder: "https://… or /page",
89
+ leading: /* @__PURE__ */ jsx(IconLink, { stroke: 1.5 }),
90
+ "aria-invalid": problem ? true : void 0,
91
+ "aria-describedby": problem ? errId : void 0
92
+ }),
93
+ problem ? /* @__PURE__ */ jsx("p", {
94
+ id: errId,
95
+ role: "alert",
96
+ className: "text-kit-xs text-kit-danger-fg",
97
+ children: problem
98
+ }) : null
99
+ ]
100
+ }),
101
+ allowNewTab ? /* @__PURE__ */ jsxs("label", {
102
+ htmlFor: tabId,
103
+ className: "flex min-h-7 items-center justify-between gap-3",
104
+ children: [/* @__PURE__ */ jsx("span", {
105
+ className: "text-kit-xs text-kit-fg-2",
106
+ children: "Open in new tab"
107
+ }), /* @__PURE__ */ jsx(Switch, {
108
+ id: tabId,
109
+ size: "sm",
110
+ checked: newTab,
111
+ onCheckedChange: setNewTab
112
+ })]
113
+ }) : null,
114
+ /* @__PURE__ */ jsxs("div", {
115
+ className: "flex items-center gap-2 border-t border-kit-line pt-2.5",
116
+ children: [
117
+ onDetach ? /* @__PURE__ */ jsx(Button, {
118
+ type: "button",
119
+ size: "xs",
120
+ variant: "danger-ghost",
121
+ onClick: onDetach,
122
+ children: "Remove link"
123
+ }) : null,
124
+ /* @__PURE__ */ jsx("span", { className: "flex-1" }),
125
+ /* @__PURE__ */ jsx(Button, {
126
+ type: "button",
127
+ size: "xs",
128
+ variant: "ghost",
129
+ onClick: onCancel,
130
+ children: "Cancel"
131
+ }),
132
+ /* @__PURE__ */ jsx(Button, {
133
+ type: "submit",
134
+ size: "xs",
135
+ variant: "primary",
136
+ disabled: !changed || !ok,
137
+ children: "Apply"
138
+ })
139
+ ]
140
+ })
141
+ ]
142
+ });
143
+ }
144
+ //#endregion
145
+ export { LinkForm, linkProblem };
146
+
147
+ //# sourceMappingURL=link-form.js.map