@jackuait/blok 0.4.1-beta.4 → 0.4.1-beta.6

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 (400) hide show
  1. package/README.md +136 -17
  2. package/codemod/README.md +16 -0
  3. package/codemod/migrate-editorjs-to-blok.js +868 -92
  4. package/codemod/test.js +682 -77
  5. package/dist/blok.mjs +5 -2
  6. package/dist/chunks/blok-B5qs7C5l.mjs +12838 -0
  7. package/dist/chunks/i18next-CugVlwWp.mjs +1292 -0
  8. package/dist/chunks/i18next-loader-CTrK3HzG.mjs +43 -0
  9. package/dist/{index-XWGz4gev.mjs → chunks/index-DDpzQn-0.mjs} +2 -2
  10. package/dist/chunks/inline-tool-convert-RBcopmCh.mjs +1988 -0
  11. package/dist/chunks/messages-2434tVOK.mjs +47 -0
  12. package/dist/chunks/messages-3DcCwXMF.mjs +47 -0
  13. package/dist/chunks/messages-4kMwVAKY.mjs +47 -0
  14. package/dist/chunks/messages-57uL5htT.mjs +47 -0
  15. package/dist/chunks/messages-76-iJV9Q.mjs +47 -0
  16. package/dist/chunks/messages-8p86Eyf2.mjs +47 -0
  17. package/dist/chunks/messages-BBX0p0Pi.mjs +47 -0
  18. package/dist/chunks/messages-BCm2eudQ.mjs +47 -0
  19. package/dist/chunks/messages-BFiUomgG.mjs +47 -0
  20. package/dist/chunks/messages-BIPNHHAV.mjs +47 -0
  21. package/dist/chunks/messages-BUlwu9mo.mjs +47 -0
  22. package/dist/chunks/messages-BX-DPa-z.mjs +47 -0
  23. package/dist/chunks/messages-BextV3Qh.mjs +47 -0
  24. package/dist/chunks/messages-BiPSFlUG.mjs +47 -0
  25. package/dist/chunks/messages-BiXe9G-O.mjs +47 -0
  26. package/dist/chunks/messages-Bl5z_Igo.mjs +47 -0
  27. package/dist/chunks/messages-BnsE97ku.mjs +47 -0
  28. package/dist/chunks/messages-BoO8gsVD.mjs +47 -0
  29. package/dist/chunks/messages-BqWaOGMn.mjs +47 -0
  30. package/dist/chunks/messages-BqkL2_Ro.mjs +47 -0
  31. package/dist/chunks/messages-BvCkXKX-.mjs +47 -0
  32. package/dist/chunks/messages-C6tbPLoj.mjs +47 -0
  33. package/dist/chunks/messages-CA6T3-gQ.mjs +47 -0
  34. package/dist/chunks/messages-CFFPFdWP.mjs +47 -0
  35. package/dist/chunks/messages-CFrKE-TN.mjs +47 -0
  36. package/dist/chunks/messages-CHz8VlG-.mjs +47 -0
  37. package/dist/chunks/messages-CLixzySl.mjs +47 -0
  38. package/dist/chunks/messages-CV7OM_qk.mjs +47 -0
  39. package/dist/chunks/messages-CXHt3eCC.mjs +47 -0
  40. package/dist/chunks/messages-CbmsBrB0.mjs +47 -0
  41. package/dist/chunks/messages-Ceo1KtFx.mjs +47 -0
  42. package/dist/chunks/messages-Cm0LJLtB.mjs +47 -0
  43. package/dist/chunks/messages-CmymP_Ar.mjs +47 -0
  44. package/dist/chunks/messages-D0ohMB5H.mjs +47 -0
  45. package/dist/chunks/messages-D3GrDwXh.mjs +47 -0
  46. package/dist/chunks/messages-D3vTzIpL.mjs +47 -0
  47. package/dist/chunks/messages-D5WeksbV.mjs +47 -0
  48. package/dist/chunks/messages-DGaab4EP.mjs +47 -0
  49. package/dist/chunks/messages-DKha57ZU.mjs +47 -0
  50. package/dist/chunks/messages-DOaujgMW.mjs +47 -0
  51. package/dist/chunks/messages-DVbPLd_0.mjs +47 -0
  52. package/dist/chunks/messages-D_FCyfW6.mjs +47 -0
  53. package/dist/chunks/messages-Dd5iZN3c.mjs +47 -0
  54. package/dist/chunks/messages-DehM7135.mjs +47 -0
  55. package/dist/chunks/messages-Dg1OHftD.mjs +47 -0
  56. package/dist/chunks/messages-Di6Flq-b.mjs +47 -0
  57. package/dist/chunks/messages-Dqhhex6e.mjs +47 -0
  58. package/dist/chunks/messages-DueVe0F1.mjs +47 -0
  59. package/dist/chunks/messages-Dx3eFwI0.mjs +47 -0
  60. package/dist/chunks/messages-FOtiUoKl.mjs +47 -0
  61. package/dist/chunks/messages-FTOZNhRD.mjs +47 -0
  62. package/dist/chunks/messages-IQxGfQIV.mjs +47 -0
  63. package/dist/chunks/messages-JF2fzCkK.mjs +47 -0
  64. package/dist/chunks/messages-MOGl7I5v.mjs +47 -0
  65. package/dist/chunks/messages-QgYhPL-3.mjs +47 -0
  66. package/dist/chunks/messages-WYWIbQwo.mjs +47 -0
  67. package/dist/chunks/messages-a6A_LgDv.mjs +47 -0
  68. package/dist/chunks/messages-bSf31LJi.mjs +47 -0
  69. package/dist/chunks/messages-diGozhTn.mjs +47 -0
  70. package/dist/chunks/messages-er-kd-VO.mjs +47 -0
  71. package/dist/chunks/messages-ez3w5NBn.mjs +47 -0
  72. package/dist/chunks/messages-f3uXjegd.mjs +47 -0
  73. package/dist/chunks/messages-ohwI1UGv.mjs +47 -0
  74. package/dist/chunks/messages-p9BZJaFV.mjs +47 -0
  75. package/dist/chunks/messages-qIQ4L4rw.mjs +47 -0
  76. package/dist/chunks/messages-qWkXPggi.mjs +47 -0
  77. package/dist/chunks/messages-w5foGze_.mjs +47 -0
  78. package/dist/full.mjs +50 -0
  79. package/dist/locales.mjs +227 -0
  80. package/dist/messages-2434tVOK.mjs +47 -0
  81. package/dist/messages-3DcCwXMF.mjs +47 -0
  82. package/dist/messages-4kMwVAKY.mjs +47 -0
  83. package/dist/messages-57uL5htT.mjs +47 -0
  84. package/dist/messages-76-iJV9Q.mjs +47 -0
  85. package/dist/messages-8p86Eyf2.mjs +47 -0
  86. package/dist/messages-BBX0p0Pi.mjs +47 -0
  87. package/dist/messages-BCm2eudQ.mjs +47 -0
  88. package/dist/messages-BFiUomgG.mjs +47 -0
  89. package/dist/messages-BIPNHHAV.mjs +47 -0
  90. package/dist/messages-BUlwu9mo.mjs +47 -0
  91. package/dist/messages-BX-DPa-z.mjs +47 -0
  92. package/dist/messages-BextV3Qh.mjs +47 -0
  93. package/dist/messages-BiPSFlUG.mjs +47 -0
  94. package/dist/messages-BiXe9G-O.mjs +47 -0
  95. package/dist/messages-Bl5z_Igo.mjs +47 -0
  96. package/dist/messages-BnsE97ku.mjs +47 -0
  97. package/dist/messages-BoO8gsVD.mjs +47 -0
  98. package/dist/messages-BqWaOGMn.mjs +47 -0
  99. package/dist/messages-BqkL2_Ro.mjs +47 -0
  100. package/dist/messages-BvCkXKX-.mjs +47 -0
  101. package/dist/messages-C6tbPLoj.mjs +47 -0
  102. package/dist/messages-CA6T3-gQ.mjs +47 -0
  103. package/dist/messages-CFFPFdWP.mjs +47 -0
  104. package/dist/messages-CFrKE-TN.mjs +47 -0
  105. package/dist/messages-CHz8VlG-.mjs +47 -0
  106. package/dist/messages-CLixzySl.mjs +47 -0
  107. package/dist/messages-CV7OM_qk.mjs +47 -0
  108. package/dist/messages-CXHt3eCC.mjs +47 -0
  109. package/dist/messages-CbmsBrB0.mjs +47 -0
  110. package/dist/messages-Ceo1KtFx.mjs +47 -0
  111. package/dist/messages-Cm0LJLtB.mjs +47 -0
  112. package/dist/messages-CmymP_Ar.mjs +47 -0
  113. package/dist/messages-D0ohMB5H.mjs +47 -0
  114. package/dist/messages-D3GrDwXh.mjs +47 -0
  115. package/dist/messages-D3vTzIpL.mjs +47 -0
  116. package/dist/messages-D5WeksbV.mjs +47 -0
  117. package/dist/messages-DGaab4EP.mjs +47 -0
  118. package/dist/messages-DKha57ZU.mjs +47 -0
  119. package/dist/messages-DOaujgMW.mjs +47 -0
  120. package/dist/messages-DVbPLd_0.mjs +47 -0
  121. package/dist/messages-D_FCyfW6.mjs +47 -0
  122. package/dist/messages-Dd5iZN3c.mjs +47 -0
  123. package/dist/messages-DehM7135.mjs +47 -0
  124. package/dist/messages-Dg1OHftD.mjs +47 -0
  125. package/dist/messages-Di6Flq-b.mjs +47 -0
  126. package/dist/messages-Dqhhex6e.mjs +47 -0
  127. package/dist/messages-DueVe0F1.mjs +47 -0
  128. package/dist/messages-Dx3eFwI0.mjs +47 -0
  129. package/dist/messages-FOtiUoKl.mjs +47 -0
  130. package/dist/messages-FTOZNhRD.mjs +47 -0
  131. package/dist/messages-IQxGfQIV.mjs +47 -0
  132. package/dist/messages-JF2fzCkK.mjs +47 -0
  133. package/dist/messages-MOGl7I5v.mjs +47 -0
  134. package/dist/messages-QgYhPL-3.mjs +47 -0
  135. package/dist/messages-WYWIbQwo.mjs +47 -0
  136. package/dist/messages-a6A_LgDv.mjs +47 -0
  137. package/dist/messages-bSf31LJi.mjs +47 -0
  138. package/dist/messages-diGozhTn.mjs +47 -0
  139. package/dist/messages-er-kd-VO.mjs +47 -0
  140. package/dist/messages-ez3w5NBn.mjs +47 -0
  141. package/dist/messages-f3uXjegd.mjs +47 -0
  142. package/dist/messages-ohwI1UGv.mjs +47 -0
  143. package/dist/messages-p9BZJaFV.mjs +47 -0
  144. package/dist/messages-qIQ4L4rw.mjs +47 -0
  145. package/dist/messages-qWkXPggi.mjs +47 -0
  146. package/dist/messages-w5foGze_.mjs +47 -0
  147. package/dist/tools.mjs +3073 -0
  148. package/dist/vendor.LICENSE.txt +26 -225
  149. package/package.json +49 -23
  150. package/src/blok.ts +267 -0
  151. package/src/components/__module.ts +139 -0
  152. package/src/components/block/api.ts +155 -0
  153. package/src/components/block/index.ts +1427 -0
  154. package/src/components/block-tunes/block-tune-delete.ts +51 -0
  155. package/src/components/blocks.ts +338 -0
  156. package/src/components/constants/data-attributes.ts +342 -0
  157. package/src/components/constants.ts +76 -0
  158. package/src/components/core.ts +392 -0
  159. package/src/components/dom.ts +773 -0
  160. package/src/components/domIterator.ts +189 -0
  161. package/src/components/errors/critical.ts +5 -0
  162. package/src/components/events/BlockChanged.ts +16 -0
  163. package/src/components/events/BlockHovered.ts +21 -0
  164. package/src/components/events/BlockSettingsClosed.ts +12 -0
  165. package/src/components/events/BlockSettingsOpened.ts +12 -0
  166. package/src/components/events/BlokMobileLayoutToggled.ts +15 -0
  167. package/src/components/events/FakeCursorAboutToBeToggled.ts +17 -0
  168. package/src/components/events/FakeCursorHaveBeenSet.ts +17 -0
  169. package/src/components/events/HistoryStateChanged.ts +19 -0
  170. package/src/components/events/RedactorDomChanged.ts +14 -0
  171. package/src/components/events/index.ts +46 -0
  172. package/src/components/flipper.ts +481 -0
  173. package/src/components/i18n/i18next-loader.ts +84 -0
  174. package/src/components/i18n/lightweight-i18n.ts +86 -0
  175. package/src/components/i18n/locales/TRANSLATION_GUIDELINES.md +113 -0
  176. package/src/components/i18n/locales/am/messages.json +44 -0
  177. package/src/components/i18n/locales/ar/messages.json +44 -0
  178. package/src/components/i18n/locales/az/messages.json +44 -0
  179. package/src/components/i18n/locales/bg/messages.json +44 -0
  180. package/src/components/i18n/locales/bn/messages.json +44 -0
  181. package/src/components/i18n/locales/bs/messages.json +44 -0
  182. package/src/components/i18n/locales/cs/messages.json +44 -0
  183. package/src/components/i18n/locales/da/messages.json +44 -0
  184. package/src/components/i18n/locales/de/messages.json +44 -0
  185. package/src/components/i18n/locales/dv/messages.json +44 -0
  186. package/src/components/i18n/locales/el/messages.json +44 -0
  187. package/src/components/i18n/locales/en/messages.json +44 -0
  188. package/src/components/i18n/locales/es/messages.json +44 -0
  189. package/src/components/i18n/locales/et/messages.json +44 -0
  190. package/src/components/i18n/locales/fa/messages.json +44 -0
  191. package/src/components/i18n/locales/fi/messages.json +44 -0
  192. package/src/components/i18n/locales/fil/messages.json +44 -0
  193. package/src/components/i18n/locales/fr/messages.json +44 -0
  194. package/src/components/i18n/locales/gu/messages.json +44 -0
  195. package/src/components/i18n/locales/he/messages.json +44 -0
  196. package/src/components/i18n/locales/hi/messages.json +44 -0
  197. package/src/components/i18n/locales/hr/messages.json +44 -0
  198. package/src/components/i18n/locales/hu/messages.json +44 -0
  199. package/src/components/i18n/locales/hy/messages.json +44 -0
  200. package/src/components/i18n/locales/id/messages.json +44 -0
  201. package/src/components/i18n/locales/index.ts +225 -0
  202. package/src/components/i18n/locales/it/messages.json +44 -0
  203. package/src/components/i18n/locales/ja/messages.json +44 -0
  204. package/src/components/i18n/locales/ka/messages.json +44 -0
  205. package/src/components/i18n/locales/km/messages.json +44 -0
  206. package/src/components/i18n/locales/kn/messages.json +44 -0
  207. package/src/components/i18n/locales/ko/messages.json +44 -0
  208. package/src/components/i18n/locales/ku/messages.json +44 -0
  209. package/src/components/i18n/locales/lo/messages.json +44 -0
  210. package/src/components/i18n/locales/lt/messages.json +44 -0
  211. package/src/components/i18n/locales/lv/messages.json +44 -0
  212. package/src/components/i18n/locales/mk/messages.json +44 -0
  213. package/src/components/i18n/locales/ml/messages.json +44 -0
  214. package/src/components/i18n/locales/mn/messages.json +44 -0
  215. package/src/components/i18n/locales/mr/messages.json +44 -0
  216. package/src/components/i18n/locales/ms/messages.json +44 -0
  217. package/src/components/i18n/locales/my/messages.json +44 -0
  218. package/src/components/i18n/locales/ne/messages.json +44 -0
  219. package/src/components/i18n/locales/nl/messages.json +44 -0
  220. package/src/components/i18n/locales/no/messages.json +44 -0
  221. package/src/components/i18n/locales/pa/messages.json +44 -0
  222. package/src/components/i18n/locales/pl/messages.json +44 -0
  223. package/src/components/i18n/locales/ps/messages.json +44 -0
  224. package/src/components/i18n/locales/pt/messages.json +44 -0
  225. package/src/components/i18n/locales/ro/messages.json +44 -0
  226. package/src/components/i18n/locales/ru/messages.json +44 -0
  227. package/src/components/i18n/locales/sd/messages.json +44 -0
  228. package/src/components/i18n/locales/si/messages.json +44 -0
  229. package/src/components/i18n/locales/sk/messages.json +44 -0
  230. package/src/components/i18n/locales/sl/messages.json +44 -0
  231. package/src/components/i18n/locales/sq/messages.json +44 -0
  232. package/src/components/i18n/locales/sr/messages.json +44 -0
  233. package/src/components/i18n/locales/sv/messages.json +44 -0
  234. package/src/components/i18n/locales/sw/messages.json +44 -0
  235. package/src/components/i18n/locales/ta/messages.json +44 -0
  236. package/src/components/i18n/locales/te/messages.json +44 -0
  237. package/src/components/i18n/locales/th/messages.json +44 -0
  238. package/src/components/i18n/locales/tr/messages.json +44 -0
  239. package/src/components/i18n/locales/ug/messages.json +44 -0
  240. package/src/components/i18n/locales/uk/messages.json +44 -0
  241. package/src/components/i18n/locales/ur/messages.json +44 -0
  242. package/src/components/i18n/locales/vi/messages.json +44 -0
  243. package/src/components/i18n/locales/yi/messages.json +44 -0
  244. package/src/components/i18n/locales/zh/messages.json +44 -0
  245. package/src/components/icons/index.ts +242 -0
  246. package/src/components/inline-tools/inline-tool-bold.ts +2213 -0
  247. package/src/components/inline-tools/inline-tool-convert.ts +141 -0
  248. package/src/components/inline-tools/inline-tool-italic.ts +500 -0
  249. package/src/components/inline-tools/inline-tool-link.ts +539 -0
  250. package/src/components/modules/api/blocks.ts +363 -0
  251. package/src/components/modules/api/caret.ts +125 -0
  252. package/src/components/modules/api/events.ts +51 -0
  253. package/src/components/modules/api/history.ts +73 -0
  254. package/src/components/modules/api/i18n.ts +33 -0
  255. package/src/components/modules/api/index.ts +39 -0
  256. package/src/components/modules/api/inlineToolbar.ts +33 -0
  257. package/src/components/modules/api/listeners.ts +56 -0
  258. package/src/components/modules/api/notifier.ts +46 -0
  259. package/src/components/modules/api/readonly.ts +39 -0
  260. package/src/components/modules/api/sanitizer.ts +30 -0
  261. package/src/components/modules/api/saver.ts +52 -0
  262. package/src/components/modules/api/selection.ts +48 -0
  263. package/src/components/modules/api/styles.ts +72 -0
  264. package/src/components/modules/api/toolbar.ts +79 -0
  265. package/src/components/modules/api/tools.ts +16 -0
  266. package/src/components/modules/api/tooltip.ts +67 -0
  267. package/src/components/modules/api/ui.ts +36 -0
  268. package/src/components/modules/blockEvents.ts +1375 -0
  269. package/src/components/modules/blockManager.ts +1348 -0
  270. package/src/components/modules/blockSelection.ts +708 -0
  271. package/src/components/modules/caret.ts +853 -0
  272. package/src/components/modules/crossBlockSelection.ts +329 -0
  273. package/src/components/modules/dragManager.ts +1141 -0
  274. package/src/components/modules/history.ts +1098 -0
  275. package/src/components/modules/i18n.ts +325 -0
  276. package/src/components/modules/index.ts +139 -0
  277. package/src/components/modules/modificationsObserver.ts +147 -0
  278. package/src/components/modules/paste.ts +1092 -0
  279. package/src/components/modules/readonly.ts +136 -0
  280. package/src/components/modules/rectangleSelection.ts +668 -0
  281. package/src/components/modules/renderer.ts +155 -0
  282. package/src/components/modules/saver.ts +283 -0
  283. package/src/components/modules/toolbar/blockSettings.ts +776 -0
  284. package/src/components/modules/toolbar/index.ts +1311 -0
  285. package/src/components/modules/toolbar/inline.ts +956 -0
  286. package/src/components/modules/tools.ts +589 -0
  287. package/src/components/modules/ui.ts +1179 -0
  288. package/src/components/polyfills.ts +113 -0
  289. package/src/components/selection.ts +1189 -0
  290. package/src/components/tools/base.ts +274 -0
  291. package/src/components/tools/block.ts +291 -0
  292. package/src/components/tools/collection.ts +67 -0
  293. package/src/components/tools/factory.ts +85 -0
  294. package/src/components/tools/inline.ts +71 -0
  295. package/src/components/tools/tune.ts +33 -0
  296. package/src/components/ui/toolbox.ts +497 -0
  297. package/src/components/utils/announcer.ts +205 -0
  298. package/src/components/utils/api.ts +20 -0
  299. package/src/components/utils/bem.ts +26 -0
  300. package/src/components/utils/blocks.ts +284 -0
  301. package/src/components/utils/caret.ts +1067 -0
  302. package/src/components/utils/data-model-transform.ts +382 -0
  303. package/src/components/utils/events.ts +117 -0
  304. package/src/components/utils/keyboard.ts +60 -0
  305. package/src/components/utils/listeners.ts +296 -0
  306. package/src/components/utils/mutations.ts +39 -0
  307. package/src/components/utils/notifier/draw.ts +190 -0
  308. package/src/components/utils/notifier/index.ts +66 -0
  309. package/src/components/utils/notifier/types.ts +1 -0
  310. package/src/components/utils/notifier.ts +77 -0
  311. package/src/components/utils/placeholder.ts +140 -0
  312. package/src/components/utils/popover/components/hint/hint.const.ts +10 -0
  313. package/src/components/utils/popover/components/hint/hint.ts +46 -0
  314. package/src/components/utils/popover/components/hint/index.ts +6 -0
  315. package/src/components/utils/popover/components/popover-header/index.ts +2 -0
  316. package/src/components/utils/popover/components/popover-header/popover-header.const.ts +8 -0
  317. package/src/components/utils/popover/components/popover-header/popover-header.ts +80 -0
  318. package/src/components/utils/popover/components/popover-header/popover-header.types.ts +14 -0
  319. package/src/components/utils/popover/components/popover-item/index.ts +13 -0
  320. package/src/components/utils/popover/components/popover-item/popover-item-default/popover-item-default.const.ts +50 -0
  321. package/src/components/utils/popover/components/popover-item/popover-item-default/popover-item-default.ts +666 -0
  322. package/src/components/utils/popover/components/popover-item/popover-item-html/popover-item-html.const.ts +14 -0
  323. package/src/components/utils/popover/components/popover-item/popover-item-html/popover-item-html.ts +136 -0
  324. package/src/components/utils/popover/components/popover-item/popover-item-separator/popover-item-separator.const.ts +20 -0
  325. package/src/components/utils/popover/components/popover-item/popover-item-separator/popover-item-separator.ts +117 -0
  326. package/src/components/utils/popover/components/popover-item/popover-item.ts +187 -0
  327. package/src/components/utils/popover/components/search-input/index.ts +2 -0
  328. package/src/components/utils/popover/components/search-input/search-input.const.ts +8 -0
  329. package/src/components/utils/popover/components/search-input/search-input.ts +181 -0
  330. package/src/components/utils/popover/components/search-input/search-input.types.ts +30 -0
  331. package/src/components/utils/popover/index.ts +13 -0
  332. package/src/components/utils/popover/popover-abstract.ts +448 -0
  333. package/src/components/utils/popover/popover-desktop.ts +643 -0
  334. package/src/components/utils/popover/popover-inline.ts +338 -0
  335. package/src/components/utils/popover/popover-mobile.ts +201 -0
  336. package/src/components/utils/popover/popover.const.ts +81 -0
  337. package/src/components/utils/popover/utils/popover-states-history.ts +72 -0
  338. package/src/components/utils/promise-queue.ts +43 -0
  339. package/src/components/utils/sanitizer.ts +537 -0
  340. package/src/components/utils/scroll-locker.ts +87 -0
  341. package/src/components/utils/shortcut.ts +231 -0
  342. package/src/components/utils/shortcuts.ts +113 -0
  343. package/src/components/utils/tools.ts +105 -0
  344. package/src/components/utils/tooltip.ts +642 -0
  345. package/src/components/utils/tw.ts +241 -0
  346. package/src/components/utils.ts +1081 -0
  347. package/src/env.d.ts +13 -0
  348. package/src/full.ts +69 -0
  349. package/src/locales.ts +51 -0
  350. package/src/stories/Block.stories.ts +498 -0
  351. package/src/stories/EditorModes.stories.ts +505 -0
  352. package/src/stories/Header.stories.ts +137 -0
  353. package/src/stories/InlineToolbar.stories.ts +498 -0
  354. package/src/stories/List.stories.ts +259 -0
  355. package/src/stories/Notifier.stories.ts +340 -0
  356. package/src/stories/Paragraph.stories.ts +112 -0
  357. package/src/stories/Placeholder.stories.ts +319 -0
  358. package/src/stories/Popover.stories.ts +844 -0
  359. package/src/stories/Selection.stories.ts +250 -0
  360. package/src/stories/StubBlock.stories.ts +156 -0
  361. package/src/stories/Toolbar.stories.ts +223 -0
  362. package/src/stories/Toolbox.stories.ts +166 -0
  363. package/src/stories/Tooltip.stories.ts +198 -0
  364. package/src/stories/helpers.ts +463 -0
  365. package/src/styles/main.css +123 -0
  366. package/src/tools/header/index.ts +570 -0
  367. package/src/tools/index.ts +38 -0
  368. package/src/tools/list/index.ts +1803 -0
  369. package/src/tools/paragraph/index.ts +411 -0
  370. package/src/tools/stub/index.ts +107 -0
  371. package/src/types-internal/blok-modules.d.ts +87 -0
  372. package/src/types-internal/html-janitor.d.ts +28 -0
  373. package/src/types-internal/module-config.d.ts +11 -0
  374. package/src/variants/all-locales.ts +155 -0
  375. package/src/variants/blok-maximum.ts +20 -0
  376. package/src/variants/blok-minimum.ts +243 -0
  377. package/types/api/blocks.d.ts +1 -1
  378. package/types/api/i18n.d.ts +5 -3
  379. package/types/api/selection.d.ts +6 -0
  380. package/types/api/styles.d.ts +23 -10
  381. package/types/configs/blok-config.d.ts +29 -0
  382. package/types/configs/i18n-config.d.ts +52 -2
  383. package/types/configs/i18n-dictionary.d.ts +16 -90
  384. package/types/data-attributes.d.ts +169 -0
  385. package/types/data-formats/output-data.d.ts +15 -0
  386. package/types/full.d.ts +80 -0
  387. package/types/index.d.ts +9 -12
  388. package/types/locales.d.ts +59 -0
  389. package/types/tools/adapters/inline-tool-adapter.d.ts +10 -0
  390. package/types/tools/block-tool.d.ts +9 -0
  391. package/types/tools/header.d.ts +18 -0
  392. package/types/tools/index.d.ts +1 -0
  393. package/types/tools/list.d.ts +91 -0
  394. package/types/tools/paragraph.d.ts +71 -0
  395. package/types/tools/tool-settings.d.ts +16 -2
  396. package/types/tools/tool.d.ts +6 -0
  397. package/types/tools-entry.d.ts +49 -0
  398. package/types/utils/popover/popover-item.d.ts +6 -5
  399. package/dist/blok-B870U2fw.mjs +0 -25803
  400. package/dist/blok.umd.js +0 -181
package/dist/tools.mjs ADDED
@@ -0,0 +1,3073 @@
1
+ var nt = Object.defineProperty, rt = Object.defineProperties;
2
+ var st = Object.getOwnPropertyDescriptors;
3
+ var K = Object.getOwnPropertySymbols;
4
+ var ot = Object.prototype.hasOwnProperty, it = Object.prototype.propertyIsEnumerable;
5
+ var U = (f, t, e) => t in f ? nt(f, t, { enumerable: !0, configurable: !0, writable: !0, value: e }) : f[t] = e, w = (f, t) => {
6
+ for (var e in t || (t = {}))
7
+ ot.call(t, e) && U(f, e, t[e]);
8
+ if (K)
9
+ for (var e of K(t))
10
+ it.call(t, e) && U(f, e, t[e]);
11
+ return f;
12
+ }, P = (f, t) => rt(f, st(t));
13
+ import { t as L, D as g, a9 as et, aa as at, ab as lt, ac as ct, ad as dt, ae as ut, af as ht, ag as ft, ah as pt, ai as G, aj as j, ak as $, f as A, al as gt, am as mt, S as H, P as Et, an as Tt, l as Ct, J as At } from "./chunks/inline-tool-convert-RBcopmCh.mjs";
14
+ import { a0 as Ot } from "./chunks/inline-tool-convert-RBcopmCh.mjs";
15
+ const W = [
16
+ "empty:before:pointer-events-none",
17
+ "empty:before:text-gray-text",
18
+ "empty:before:cursor-text",
19
+ "empty:before:content-[attr(data-placeholder)]",
20
+ "[&[data-blok-empty=true]]:before:pointer-events-none",
21
+ "[&[data-blok-empty=true]]:before:text-gray-text",
22
+ "[&[data-blok-empty=true]]:before:cursor-text",
23
+ "[&[data-blok-empty=true]]:before:content-[attr(data-placeholder)]"
24
+ ], yt = [
25
+ "empty:focus:before:pointer-events-none",
26
+ "empty:focus:before:text-gray-text",
27
+ "empty:focus:before:cursor-text",
28
+ "empty:focus:before:content-[attr(data-blok-placeholder-active)]",
29
+ "[&[data-empty=true]:focus]:before:pointer-events-none",
30
+ "[&[data-empty=true]:focus]:before:text-gray-text",
31
+ "[&[data-empty=true]:focus]:before:cursor-text",
32
+ "[&[data-empty=true]:focus]:before:content-[attr(data-blok-placeholder-active)]"
33
+ ], bt = (f) => {
34
+ const t = f.innerHTML.trim();
35
+ return t === "" || t === "<br>";
36
+ }, St = (f) => {
37
+ f.innerHTML === "<br>" && (f.innerHTML = "");
38
+ const t = window.getSelection();
39
+ if (!t) return;
40
+ const e = document.createRange();
41
+ e.selectNodeContents(f), e.collapse(!0), t.removeAllRanges(), t.addRange(e);
42
+ }, Nt = (f) => {
43
+ bt(f) && St(f);
44
+ }, z = (f, t, e = "data-placeholder") => {
45
+ f.setAttribute(e, t != null ? t : "");
46
+ const n = () => Nt(f);
47
+ f.addEventListener("focus", n), f.addEventListener("input", n);
48
+ }, Bt = (f) => {
49
+ const t = document.createElement("div");
50
+ t.innerHTML = f.trim();
51
+ const e = document.createDocumentFragment();
52
+ return e.append(...Array.from(t.childNodes)), e;
53
+ }, M = class M {
54
+ /**
55
+ * Default placeholder for Paragraph Tool
56
+ *
57
+ * @returns empty string
58
+ */
59
+ static get DEFAULT_PLACEHOLDER() {
60
+ return "";
61
+ }
62
+ /**
63
+ * Render plugin's main Element and fill it with saved data
64
+ *
65
+ * @param options - constructor options
66
+ * @param options.data - previously saved data
67
+ * @param options.config - user config for Tool
68
+ * @param options.api - editor.js api
69
+ * @param options.readOnly - read only mode flag
70
+ */
71
+ constructor({ data: t, config: e, api: n, readOnly: r }) {
72
+ var s, o, a;
73
+ this.api = n, this.readOnly = r, this.readOnly || (this.onKeyUp = this.onKeyUp.bind(this)), this._placeholder = (s = e == null ? void 0 : e.placeholder) != null ? s : M.DEFAULT_PLACEHOLDER, this._data = t != null ? t : { text: "" }, this._element = null, this._preserveBlank = (o = e == null ? void 0 : e.preserveBlank) != null ? o : !1, this._styles = (a = e == null ? void 0 : e.styles) != null ? a : {};
74
+ }
75
+ /**
76
+ * Check if text content is empty and set empty string to inner html.
77
+ * We need this because some browsers (e.g. Safari) insert <br> into empty contenteditable elements
78
+ *
79
+ * @param e - key up event
80
+ */
81
+ onKeyUp(t) {
82
+ if (t.code !== "Backspace" && t.code !== "Delete" || !this._element)
83
+ return;
84
+ const { textContent: e } = this._element;
85
+ e === "" && (this._element.innerHTML = "");
86
+ }
87
+ /**
88
+ * Build inline styles from style configuration
89
+ *
90
+ * @returns Partial CSSStyleDeclaration with custom styles
91
+ */
92
+ buildInlineStyles() {
93
+ const t = {};
94
+ return this._styles.size && (t.fontSize = this._styles.size), this._styles.lineHeight && (t.lineHeight = this._styles.lineHeight), this._styles.marginTop && (t.marginTop = this._styles.marginTop), this._styles.marginBottom && (t.marginBottom = this._styles.marginBottom), t;
95
+ }
96
+ drawView() {
97
+ const t = document.createElement("DIV");
98
+ t.className = L(
99
+ this.api.styles.block,
100
+ M.WRAPPER_CLASSES,
101
+ yt
102
+ ), t.setAttribute(g.tool, "paragraph"), t.contentEditable = "false";
103
+ const e = this.buildInlineStyles();
104
+ return Object.keys(e).length > 0 && Object.assign(t.style, e), this._data.text && (t.innerHTML = this._data.text), this.readOnly ? t.setAttribute("data-blok-placeholder-active", this.api.i18n.t(this._placeholder)) : (t.contentEditable = "true", t.addEventListener("keyup", this.onKeyUp), z(t, this.api.i18n.t(this._placeholder), "data-blok-placeholder-active")), t;
105
+ }
106
+ /**
107
+ * Return Tool's view
108
+ *
109
+ * @returns HTMLDivElement
110
+ */
111
+ render() {
112
+ return this._element = this.drawView(), this._element;
113
+ }
114
+ /**
115
+ * Method that specified how to merge two Text blocks.
116
+ * Called by Editor by backspace at the beginning of the Block
117
+ *
118
+ * @param data - saved data to merge with current block
119
+ */
120
+ merge(t) {
121
+ if (!this._element)
122
+ return;
123
+ this._data.text += t.text;
124
+ const e = Bt(t.text);
125
+ this._element.appendChild(e), this._element.normalize();
126
+ }
127
+ /**
128
+ * Validate Paragraph block data:
129
+ * - check for emptiness
130
+ *
131
+ * @param savedData - data received after saving
132
+ * @returns false if saved data is not correct, otherwise true
133
+ */
134
+ validate(t) {
135
+ return !(t.text.trim() === "" && !this._preserveBlank);
136
+ }
137
+ /**
138
+ * Extract Tool's data from the view
139
+ *
140
+ * @param toolsContent - Paragraph tools rendered view
141
+ * @returns saved data
142
+ */
143
+ save(t) {
144
+ return {
145
+ text: et(t.innerHTML)
146
+ };
147
+ }
148
+ /**
149
+ * On paste callback fired from Editor.
150
+ *
151
+ * @param event - event with pasted data
152
+ */
153
+ onPaste(t) {
154
+ const e = t.detail;
155
+ if (!("data" in e))
156
+ return;
157
+ const r = {
158
+ text: e.data.innerHTML
159
+ };
160
+ this._data = r, window.requestAnimationFrame(() => {
161
+ this._element && (this._element.innerHTML = this._data.text || "");
162
+ });
163
+ }
164
+ /**
165
+ * Enable Conversion Toolbar. Paragraph can be converted to/from other tools
166
+ *
167
+ * @returns ConversionConfig
168
+ */
169
+ static get conversionConfig() {
170
+ return {
171
+ export: "text",
172
+ // to convert Paragraph to other block, use 'text' property of saved data
173
+ import: "text"
174
+ // to convert other block's exported string to Paragraph, fill 'text' property of tool data
175
+ };
176
+ }
177
+ /**
178
+ * Sanitizer rules
179
+ *
180
+ * @returns SanitizerConfig
181
+ */
182
+ static get sanitize() {
183
+ return {
184
+ text: {
185
+ br: !0
186
+ }
187
+ };
188
+ }
189
+ /**
190
+ * Returns true to notify the core that read-only mode is supported
191
+ *
192
+ * @returns true
193
+ */
194
+ static get isReadOnlySupported() {
195
+ return !0;
196
+ }
197
+ /**
198
+ * Used by Editor paste handling API.
199
+ * Provides configuration to handle P tags.
200
+ *
201
+ * @returns PasteConfig
202
+ */
203
+ static get pasteConfig() {
204
+ return {
205
+ tags: ["P"]
206
+ };
207
+ }
208
+ /**
209
+ * Icon and title for displaying at the Toolbox
210
+ *
211
+ * @returns ToolboxConfig
212
+ */
213
+ static get toolbox() {
214
+ return {
215
+ icon: at,
216
+ title: "Text",
217
+ titleKey: "text"
218
+ };
219
+ }
220
+ };
221
+ M.WRAPPER_CLASSES = [
222
+ "leading-[1.6em]",
223
+ "outline-none",
224
+ "mt-[2px]",
225
+ "mb-px",
226
+ "[&>p:first-of-type]:mt-0",
227
+ "[&>p:last-of-type]:mb-0"
228
+ ];
229
+ let X = M;
230
+ const I = class I {
231
+ /**
232
+ * Render plugin's main Element and fill it with saved data
233
+ *
234
+ * @param options - constructor options
235
+ * @param options.data - previously saved data
236
+ * @param options.config - user config for Tool
237
+ * @param options.api - Editor API
238
+ * @param options.readOnly - read only mode flag
239
+ */
240
+ constructor({ data: t, config: e, api: n, readOnly: r }) {
241
+ this.api = n, this.readOnly = r, this._settings = e || {}, this._data = this.normalizeData(t), this._element = this.getTag();
242
+ }
243
+ /**
244
+ * Styles
245
+ * @deprecated Use data-blok-tool attribute instead (DATA_ATTR.tool)
246
+ */
247
+ get _CSS() {
248
+ return {
249
+ block: this.api.styles.block,
250
+ wrapper: ""
251
+ };
252
+ }
253
+ /**
254
+ * Check if data is valid HeaderData
255
+ *
256
+ * @param data - data to check
257
+ * @returns true if data is HeaderData
258
+ */
259
+ isHeaderData(t) {
260
+ return typeof t == "object" && t !== null && "text" in t;
261
+ }
262
+ /**
263
+ * Normalize input data
264
+ *
265
+ * @param data - saved data to process
266
+ * @returns normalized HeaderData
267
+ */
268
+ normalizeData(t) {
269
+ if (!this.isHeaderData(t))
270
+ return { text: "", level: this.defaultLevel.number };
271
+ const e = parseInt(String(t.level)), n = t.level !== void 0 && !isNaN(e);
272
+ return {
273
+ text: t.text || "",
274
+ level: n ? e : this.defaultLevel.number
275
+ };
276
+ }
277
+ /**
278
+ * Return Tool's view
279
+ *
280
+ * @returns HTMLHeadingElement
281
+ */
282
+ render() {
283
+ return this._element;
284
+ }
285
+ /**
286
+ * Returns header block tunes config
287
+ *
288
+ * @returns MenuConfig array
289
+ */
290
+ renderSettings() {
291
+ return this.levels.map((t) => {
292
+ const e = this.api.i18n.t(t.nameKey), n = e !== t.nameKey ? e : t.name;
293
+ return {
294
+ icon: t.icon,
295
+ title: n,
296
+ onActivate: () => this.setLevel(t.number),
297
+ closeOnActivate: !0,
298
+ isActive: this.currentLevel.number === t.number,
299
+ dataset: {
300
+ "blok-header-level": String(t.number)
301
+ }
302
+ };
303
+ });
304
+ }
305
+ /**
306
+ * Callback for Block's settings buttons
307
+ *
308
+ * @param level - level to set
309
+ */
310
+ setLevel(t) {
311
+ this.data = {
312
+ level: t,
313
+ text: this.data.text
314
+ };
315
+ }
316
+ /**
317
+ * Method that specified how to merge two Text blocks.
318
+ * Called by Editor by backspace at the beginning of the Block
319
+ *
320
+ * @param data - saved data to merge with current block
321
+ */
322
+ merge(t) {
323
+ this._element.insertAdjacentHTML("beforeend", t.text);
324
+ }
325
+ /**
326
+ * Validate Text block data:
327
+ * - check for emptiness
328
+ *
329
+ * @param blockData - data received after saving
330
+ * @returns false if saved data is not correct, otherwise true
331
+ */
332
+ validate(t) {
333
+ return t.text.trim() !== "";
334
+ }
335
+ /**
336
+ * Extract Tool's data from the view
337
+ *
338
+ * @param toolsContent - Text tools rendered view
339
+ * @returns saved data
340
+ */
341
+ save(t) {
342
+ return {
343
+ text: t.innerHTML,
344
+ level: this.currentLevel.number
345
+ };
346
+ }
347
+ /**
348
+ * Allow Header to be converted to/from other blocks
349
+ */
350
+ static get conversionConfig() {
351
+ return {
352
+ export: "text",
353
+ // use 'text' property for other blocks
354
+ import: "text"
355
+ // fill 'text' property from other block's export string
356
+ };
357
+ }
358
+ /**
359
+ * Sanitizer Rules
360
+ */
361
+ static get sanitize() {
362
+ return {
363
+ level: !1,
364
+ text: {}
365
+ };
366
+ }
367
+ /**
368
+ * Returns true to notify core that read-only is supported
369
+ *
370
+ * @returns true
371
+ */
372
+ static get isReadOnlySupported() {
373
+ return !0;
374
+ }
375
+ /**
376
+ * Get current Tool's data
377
+ *
378
+ * @returns Current data
379
+ */
380
+ get data() {
381
+ return this._data.text = this._element.innerHTML, this._data.level = this.currentLevel.number, this._data;
382
+ }
383
+ /**
384
+ * Store data in plugin:
385
+ * - at the this._data property
386
+ * - at the HTML
387
+ *
388
+ * @param data - data to set
389
+ */
390
+ set data(t) {
391
+ if (this._data = this.normalizeData(t), t.level !== void 0 && this._element.parentNode) {
392
+ const e = this.getTag();
393
+ e.innerHTML = this._element.innerHTML, this._element.parentNode.replaceChild(e, this._element), this._element = e;
394
+ }
395
+ t.text !== void 0 && (this._element.innerHTML = this._data.text || "");
396
+ }
397
+ /**
398
+ * Get tag for target level
399
+ * By default returns second-leveled header
400
+ *
401
+ * @returns HTMLHeadingElement
402
+ */
403
+ getTag() {
404
+ const t = document.createElement(this.currentLevel.tag);
405
+ t.innerHTML = this._data.text || "", t.className = L(I.BASE_STYLES, this.currentLevel.styles, W);
406
+ const { inlineStyles: e } = this.currentLevel;
407
+ return e && Object.assign(t.style, e), t.setAttribute(g.tool, "header"), t.contentEditable = this.readOnly ? "false" : "true", this.readOnly ? t.setAttribute("data-placeholder", this.api.i18n.t(this._settings.placeholder || "")) : z(t, this.api.i18n.t(this._settings.placeholder || "")), t;
408
+ }
409
+ /**
410
+ * Get current level
411
+ *
412
+ * @returns Level object
413
+ */
414
+ get currentLevel() {
415
+ const t = this.levels.find((e) => e.number === this._data.level);
416
+ return t != null ? t : this.defaultLevel;
417
+ }
418
+ /**
419
+ * Return default level
420
+ *
421
+ * @returns Level object
422
+ */
423
+ get defaultLevel() {
424
+ if (!this._settings.defaultLevel)
425
+ return this.levels[1];
426
+ const t = this.levels.find((e) => e.number === this._settings.defaultLevel);
427
+ return t || (console.warn("(ง'̀-'́)ง Heading Tool: the default level specified was not found in available levels"), this.levels[1]);
428
+ }
429
+ /**
430
+ * Available header levels
431
+ *
432
+ * @returns Level array
433
+ */
434
+ get levels() {
435
+ const t = this._settings.levelOverrides || {}, e = I.DEFAULT_LEVELS.map((n) => {
436
+ var o;
437
+ const r = t[n.number] || {}, s = {};
438
+ return r.size && (s.fontSize = r.size), r.marginTop && (s.marginTop = r.marginTop), r.marginBottom && (s.marginBottom = r.marginBottom), {
439
+ number: n.number,
440
+ tag: ((o = r.tag) == null ? void 0 : o.toUpperCase()) || n.tag,
441
+ nameKey: n.nameKey,
442
+ name: r.name || n.name,
443
+ icon: n.icon,
444
+ styles: n.styles,
445
+ inlineStyles: s
446
+ };
447
+ });
448
+ return this._settings.levels ? e.filter((n) => this._settings.levels.includes(n.number)) : e;
449
+ }
450
+ /**
451
+ * Handle H1-H6 tags on paste to substitute it with header Tool
452
+ *
453
+ * @param event - event with pasted content
454
+ */
455
+ onPaste(t) {
456
+ var a;
457
+ const e = t.detail;
458
+ if (!("data" in e))
459
+ return;
460
+ const n = e.data, s = (a = {
461
+ H1: 1,
462
+ H2: 2,
463
+ H3: 3,
464
+ H4: 4,
465
+ H5: 5,
466
+ H6: 6
467
+ }[n.tagName]) != null ? a : this.defaultLevel.number, o = this._settings.levels ? this._settings.levels.reduce((l, d) => Math.abs(d - s) < Math.abs(l - s) ? d : l) : s;
468
+ this.data = {
469
+ level: o,
470
+ text: n.innerHTML
471
+ };
472
+ }
473
+ /**
474
+ * Used by Editor paste handling API.
475
+ * Provides configuration to handle H1-H6 tags.
476
+ *
477
+ * @returns PasteConfig
478
+ */
479
+ static get pasteConfig() {
480
+ return {
481
+ tags: ["H1", "H2", "H3", "H4", "H5", "H6"]
482
+ };
483
+ }
484
+ /**
485
+ * Get Tool toolbox settings
486
+ * icon - Tool icon's SVG
487
+ * title - title to show in toolbox
488
+ *
489
+ * @returns ToolboxConfig
490
+ */
491
+ static get toolbox() {
492
+ return {
493
+ icon: pt,
494
+ title: "Heading",
495
+ titleKey: "heading"
496
+ };
497
+ }
498
+ };
499
+ I.BASE_STYLES = "py-[3px] px-[2px] m-0 !leading-[1.3] outline-none [&_p]:!p-0 [&_p]:!m-0 [&_div]:!p-0 [&_div]:!m-0", I.DEFAULT_LEVELS = [
500
+ { number: 1, tag: "H1", nameKey: "tools.header.heading1", name: "Heading 1", icon: lt, styles: "text-4xl font-bold mt-8 mb-1" },
501
+ { number: 2, tag: "H2", nameKey: "tools.header.heading2", name: "Heading 2", icon: ct, styles: "text-3xl font-semibold mt-6 mb-px" },
502
+ { number: 3, tag: "H3", nameKey: "tools.header.heading3", name: "Heading 3", icon: dt, styles: "text-2xl font-semibold mt-4 mb-px" },
503
+ { number: 4, tag: "H4", nameKey: "tools.header.heading4", name: "Heading 4", icon: ut, styles: "text-xl font-semibold mt-3 mb-px" },
504
+ { number: 5, tag: "H5", nameKey: "tools.header.heading5", name: "Heading 5", icon: ht, styles: "text-base font-semibold mt-3 mb-px" },
505
+ { number: 6, tag: "H6", nameKey: "tools.header.heading6", name: "Heading 6", icon: ft, styles: "text-sm font-semibold mt-3 mb-px" }
506
+ ];
507
+ let Y = I;
508
+ const u = class u {
509
+ constructor({ data: t, config: e, api: n, readOnly: r, block: s }) {
510
+ this._element = null, this.handleBlockChanged = (o) => {
511
+ var l;
512
+ const a = o;
513
+ ((l = a == null ? void 0 : a.event) == null ? void 0 : l.type) === "block-removed" && (u.pendingMarkerUpdate || (u.pendingMarkerUpdate = !0, requestAnimationFrame(() => {
514
+ u.pendingMarkerUpdate = !1, this.updateAllOrderedListMarkers();
515
+ })));
516
+ }, this.api = n, this.readOnly = r, this._settings = e || {}, this._data = this.normalizeData(t), s && (this.blockId = s.id), this._data.style === "ordered" && this.api.events.on("block changed", this.handleBlockChanged);
517
+ }
518
+ normalizeData(t) {
519
+ var n;
520
+ const e = this._settings.defaultStyle || "unordered";
521
+ return !t || typeof t != "object" ? {
522
+ text: "",
523
+ style: e,
524
+ checked: !1,
525
+ depth: 0
526
+ } : w({
527
+ text: t.text || "",
528
+ style: t.style || e,
529
+ checked: !!t.checked,
530
+ depth: (n = t.depth) != null ? n : 0
531
+ }, t.start !== void 0 && t.start !== 1 ? { start: t.start } : {});
532
+ }
533
+ get currentStyleConfig() {
534
+ return u.STYLE_CONFIGS.find((t) => t.style === this._data.style) || u.STYLE_CONFIGS[0];
535
+ }
536
+ get availableStyles() {
537
+ const t = this._settings.styles;
538
+ return !t || t.length === 0 ? u.STYLE_CONFIGS : u.STYLE_CONFIGS.filter((e) => t.includes(e.style));
539
+ }
540
+ get itemColor() {
541
+ return this._settings.itemColor;
542
+ }
543
+ get itemSize() {
544
+ return this._settings.itemSize;
545
+ }
546
+ get placeholder() {
547
+ return this.api.i18n.t(u.DEFAULT_PLACEHOLDER);
548
+ }
549
+ applyItemStyles(t) {
550
+ const e = t.style;
551
+ this.itemColor && (e.color = this.itemColor), this.itemSize && (e.fontSize = this.itemSize);
552
+ }
553
+ setupItemPlaceholder(t) {
554
+ this.readOnly || z(t, this.placeholder);
555
+ }
556
+ render() {
557
+ return this._element = this.createItemElement(), this._element;
558
+ }
559
+ /**
560
+ * Called after block content is added to the page.
561
+ * Updates the marker with the correct index now that we know our position,
562
+ * and also updates all sibling list items since their indices may have changed.
563
+ */
564
+ rendered() {
565
+ this.updateMarkersAfterPositionChange();
566
+ }
567
+ /**
568
+ * Called after block was moved.
569
+ * Validates and adjusts depth to follow list formation rules,
570
+ * then updates the marker to reflect the new position.
571
+ */
572
+ moved(t) {
573
+ this.validateAndAdjustDepthAfterMove(t.detail.toIndex), this.updateMarkersAfterPositionChange();
574
+ }
575
+ /**
576
+ * Updates this block's marker and all sibling ordered list markers.
577
+ * Called after this block's position may have changed (rendered, moved).
578
+ */
579
+ updateMarkersAfterPositionChange() {
580
+ this._data.style !== "ordered" || !this._element || (this.updateMarker(), this.updateSiblingListMarkers());
581
+ }
582
+ /**
583
+ * Validates and adjusts the depth of this list item after a drag-and-drop move.
584
+ * Ensures the depth follows list formation rules:
585
+ * 1. First item (index 0) must be at depth 0
586
+ * 2. Item depth cannot exceed previousItem.depth + 1
587
+ * 3. When dropped between nested items, adopt the sibling's depth
588
+ *
589
+ * @param newIndex - The new index where the block was moved to
590
+ */
591
+ validateAndAdjustDepthAfterMove(t) {
592
+ const e = this.getDepth(), n = this.calculateMaxAllowedDepth(t), r = this.calculateTargetDepthForPosition(t, n);
593
+ e !== r && this.adjustDepthTo(r);
594
+ }
595
+ /**
596
+ * Calculates the target depth for a list item dropped at the given index.
597
+ * When dropping into a nested context, the item should match the sibling's depth.
598
+ *
599
+ * @param blockIndex - The index where the block was dropped
600
+ * @param maxAllowedDepth - The maximum allowed depth at this position
601
+ * @returns The target depth for the dropped item
602
+ */
603
+ calculateTargetDepthForPosition(t, e) {
604
+ const n = this.getDepth();
605
+ if (n > e)
606
+ return e;
607
+ const r = this.api.blocks.getBlockByIndex(t + 1), s = r && r.name === u.TOOL_NAME, o = s ? this.getBlockDepth(r) : 0;
608
+ if (s && o > n && o <= e)
609
+ return o;
610
+ const l = t > 0 ? this.api.blocks.getBlockByIndex(t - 1) : null, d = l && l.name === u.TOOL_NAME, c = d ? this.getBlockDepth(l) : 0;
611
+ return d && !s && c > n && c <= e ? c : n;
612
+ }
613
+ /**
614
+ * Calculates the maximum allowed depth for a list item at the given index.
615
+ *
616
+ * Rules:
617
+ * 1. First item (index 0) must be at depth 0
618
+ * 2. For other items: maxDepth = previousListItem.depth + 1
619
+ * 3. If previous block is not a list item, maxDepth = 0
620
+ *
621
+ * @param blockIndex - The index of the block
622
+ * @returns The maximum allowed depth (0 or more)
623
+ */
624
+ calculateMaxAllowedDepth(t) {
625
+ if (t === 0)
626
+ return 0;
627
+ const e = this.api.blocks.getBlockByIndex(t - 1);
628
+ return !e || e.name !== u.TOOL_NAME ? 0 : this.getBlockDepth(e) + 1;
629
+ }
630
+ /**
631
+ * Adjusts the depth of this list item to the specified value.
632
+ * Updates internal data and the DOM element's indentation.
633
+ *
634
+ * @param newDepth - The new depth value
635
+ */
636
+ adjustDepthTo(t) {
637
+ var n;
638
+ this._data.depth = t, this._element && this._element.setAttribute("data-list-depth", String(t));
639
+ const e = (n = this._element) == null ? void 0 : n.querySelector('[role="listitem"]');
640
+ e instanceof HTMLElement && (e.style.marginLeft = t > 0 ? `${t * u.INDENT_PER_LEVEL}px` : "");
641
+ }
642
+ /**
643
+ * Called when this block is about to be removed.
644
+ * Updates sibling ordered list markers to renumber correctly after removal.
645
+ */
646
+ removed() {
647
+ this._data.style === "ordered" && (this.api.events.off("block changed", this.handleBlockChanged), requestAnimationFrame(() => {
648
+ this.updateAllOrderedListMarkers();
649
+ }));
650
+ }
651
+ /**
652
+ * Update markers on all ordered list items in the editor.
653
+ * Called when a list item is removed to ensure correct renumbering.
654
+ */
655
+ updateAllOrderedListMarkers() {
656
+ const t = this.api.blocks.getBlocksCount();
657
+ Array.from({ length: t }, (e, n) => n).forEach((e) => {
658
+ const n = this.api.blocks.getBlockByIndex(e);
659
+ if (!n || n.name !== u.TOOL_NAME)
660
+ return;
661
+ const r = n.holder;
662
+ r != null && r.querySelector('[data-list-style="ordered"]') && this.updateBlockMarker(n);
663
+ });
664
+ }
665
+ /**
666
+ * Update marker if this is an ordered list item.
667
+ */
668
+ updateMarkerIfOrdered() {
669
+ this._data.style !== "ordered" || !this._element || this.updateMarker();
670
+ }
671
+ /**
672
+ * Update the marker element with the correct index.
673
+ * Called after the block is rendered and positioned.
674
+ */
675
+ updateMarker() {
676
+ var s;
677
+ const t = (s = this._element) == null ? void 0 : s.querySelector("[data-list-marker]");
678
+ if (!t)
679
+ return;
680
+ const e = this.getDepth(), n = this.getSiblingIndex(), r = this.getOrderedMarkerText(n, e);
681
+ t.textContent = r;
682
+ }
683
+ /**
684
+ * Update markers on all sibling ordered list items.
685
+ * Called when this block is moved to ensure all list numbers are correct.
686
+ * Respects style boundaries - only updates items with the same style.
687
+ */
688
+ updateSiblingListMarkers() {
689
+ var o;
690
+ const t = this.blockId ? (o = this.api.blocks.getBlockIndex(this.blockId)) != null ? o : this.api.blocks.getCurrentBlockIndex() : this.api.blocks.getCurrentBlockIndex(), e = this.getDepth(), n = this._data.style, r = this.api.blocks.getBlocksCount(), s = this.findListGroupStartIndex(t, e, n);
691
+ this.updateMarkersInRange(s, r, t, e, n);
692
+ }
693
+ /**
694
+ * Find the starting index of a list group by walking backwards.
695
+ * Stops at style boundaries at the same depth (when encountering a different list style).
696
+ * Items at deeper depths are skipped regardless of their style.
697
+ */
698
+ findListGroupStartIndex(t, e, n) {
699
+ const r = (s, o) => {
700
+ if (s < 0)
701
+ return o;
702
+ const a = this.api.blocks.getBlockByIndex(s);
703
+ if (!a || a.name !== u.TOOL_NAME)
704
+ return o;
705
+ const l = this.getBlockDepth(a);
706
+ if (l < e)
707
+ return o;
708
+ if (l > e)
709
+ return r(s - 1, o);
710
+ const d = this.getBlockStyle(a);
711
+ return n !== void 0 && d !== n ? o : r(s - 1, s);
712
+ };
713
+ return r(t - 1, t);
714
+ }
715
+ /**
716
+ * Update markers for all list items in a range at the given depth.
717
+ * Stops at style boundaries at the same depth (when encountering a different list style).
718
+ * Items at deeper depths are skipped regardless of their style.
719
+ */
720
+ updateMarkersInRange(t, e, n, r, s) {
721
+ const o = (a) => {
722
+ if (a >= e)
723
+ return;
724
+ if (a === n) {
725
+ o(a + 1);
726
+ return;
727
+ }
728
+ const l = this.api.blocks.getBlockByIndex(a);
729
+ if (!l || l.name !== u.TOOL_NAME)
730
+ return;
731
+ const d = this.getBlockDepth(l);
732
+ if (d < r)
733
+ return;
734
+ if (d > r) {
735
+ o(a + 1);
736
+ return;
737
+ }
738
+ const c = this.getBlockStyle(l);
739
+ s !== void 0 && c !== s || (this.updateBlockMarker(l), o(a + 1));
740
+ };
741
+ o(t);
742
+ }
743
+ /**
744
+ * Get the depth of a block by reading from its DOM
745
+ */
746
+ getBlockDepth(t) {
747
+ if (!t)
748
+ return 0;
749
+ const e = t.holder, n = e == null ? void 0 : e.querySelector('[role="listitem"]'), r = n == null ? void 0 : n.getAttribute("style"), s = r == null ? void 0 : r.match(/margin-left:\s*(\d+)px/);
750
+ return s ? Math.round(parseInt(s[1], 10) / u.INDENT_PER_LEVEL) : 0;
751
+ }
752
+ /**
753
+ * Get the style of a block by reading from its DOM
754
+ */
755
+ getBlockStyle(t) {
756
+ if (!t)
757
+ return null;
758
+ const e = t.holder, n = e == null ? void 0 : e.querySelector("[data-list-style]");
759
+ return (n == null ? void 0 : n.getAttribute("data-list-style")) || null;
760
+ }
761
+ /**
762
+ * Update the marker of a specific block by finding its marker element and recalculating
763
+ */
764
+ updateBlockMarker(t) {
765
+ if (!t)
766
+ return;
767
+ const e = t.holder, n = e == null ? void 0 : e.querySelector('[data-list-style="ordered"]');
768
+ if (!n)
769
+ return;
770
+ const r = n.querySelector("[data-list-marker]");
771
+ if (!r)
772
+ return;
773
+ const s = this.api.blocks.getBlockIndex(t.id);
774
+ if (s == null)
775
+ return;
776
+ const o = this.getBlockDepth(t), a = this.getBlockStyle(t) || "ordered", l = this.countPrecedingSiblingsAtDepth(s, o, a), c = this.getListStartValueForBlock(s, o, l, a) + l, h = this.formatOrderedMarker(c, o);
777
+ r.textContent = h;
778
+ }
779
+ /**
780
+ * Format an ordered list marker based on the number and depth
781
+ */
782
+ formatOrderedMarker(t, e) {
783
+ const n = e % 3;
784
+ return n === 1 ? `${this.numberToLowerAlpha(t)}.` : n === 2 ? `${this.numberToLowerRoman(t)}.` : `${t}.`;
785
+ }
786
+ /**
787
+ * Count preceding list items at the same depth and style for a given block index
788
+ */
789
+ countPrecedingSiblingsAtDepth(t, e, n) {
790
+ return t <= 0 ? 0 : this.countPrecedingListItemsAtDepthFromIndex(t - 1, e, n);
791
+ }
792
+ /**
793
+ * Recursively count preceding list items at the given depth and style starting from index.
794
+ * Stops at style boundaries at the same depth (when encountering a different list style).
795
+ * Items at deeper depths are skipped regardless of their style.
796
+ */
797
+ countPrecedingListItemsAtDepthFromIndex(t, e, n) {
798
+ if (t < 0)
799
+ return 0;
800
+ const r = this.api.blocks.getBlockByIndex(t);
801
+ if (!r || r.name !== u.TOOL_NAME)
802
+ return 0;
803
+ const s = this.getBlockDepth(r);
804
+ if (s < e)
805
+ return 0;
806
+ if (s > e)
807
+ return this.countPrecedingListItemsAtDepthFromIndex(t - 1, e, n);
808
+ const o = this.getBlockStyle(r);
809
+ return n !== void 0 && o !== n ? 0 : 1 + this.countPrecedingListItemsAtDepthFromIndex(t - 1, e, n);
810
+ }
811
+ /**
812
+ * Get the list start value for a block at a given index and depth
813
+ */
814
+ getListStartValueForBlock(t, e, n, r) {
815
+ if (n === 0)
816
+ return this.getBlockStartValue(t);
817
+ const s = this.findFirstListItemIndexFromBlock(t - 1, e, n, r);
818
+ return s === null ? 1 : this.getBlockStartValue(s);
819
+ }
820
+ /**
821
+ * Get the start value from a block's data-list-start attribute
822
+ */
823
+ getBlockStartValue(t) {
824
+ const e = this.api.blocks.getBlockByIndex(t);
825
+ if (!e)
826
+ return 1;
827
+ const n = e.holder, r = n == null ? void 0 : n.querySelector("[data-list-style]"), s = r == null ? void 0 : r.getAttribute("data-list-start");
828
+ return s ? parseInt(s, 10) : 1;
829
+ }
830
+ /**
831
+ * Find the first list item in a consecutive group.
832
+ * Stops at style boundaries at the same depth (when encountering a different list style).
833
+ * Items at deeper depths are skipped regardless of their style.
834
+ */
835
+ findFirstListItemIndexFromBlock(t, e, n, r) {
836
+ if (t < 0 || n <= 0)
837
+ return t + 1;
838
+ const s = this.api.blocks.getBlockByIndex(t);
839
+ if (!s || s.name !== u.TOOL_NAME)
840
+ return t + 1;
841
+ const o = this.getBlockDepth(s);
842
+ if (o < e)
843
+ return t + 1;
844
+ if (o > e)
845
+ return this.findFirstListItemIndexFromBlock(t - 1, e, n, r);
846
+ const a = this.getBlockStyle(s);
847
+ return r !== void 0 && a !== r ? t + 1 : this.findFirstListItemIndexFromBlock(t - 1, e, n - 1, r);
848
+ }
849
+ createItemElement() {
850
+ const { style: t } = this._data, e = document.createElement("div");
851
+ e.className = u.BASE_STYLES, e.setAttribute(g.tool, u.TOOL_NAME), e.setAttribute("data-list-style", t), e.setAttribute("data-list-depth", String(this.getDepth())), this._data.start !== void 0 && this._data.start !== 1 && e.setAttribute("data-list-start", String(this._data.start));
852
+ const n = t === "checklist" ? this.createChecklistContent() : this.createStandardContent();
853
+ return e.appendChild(n), this.readOnly || e.addEventListener("keydown", this.handleKeyDown.bind(this)), e;
854
+ }
855
+ createStandardContent() {
856
+ const t = document.createElement("div");
857
+ t.setAttribute("role", "listitem"), t.className = L(u.ITEM_STYLES, "flex", ...W), this.applyItemStyles(t);
858
+ const e = this.getDepth();
859
+ e > 0 && (t.style.marginLeft = `${e * u.INDENT_PER_LEVEL}px`);
860
+ const n = this.createListMarker();
861
+ n.setAttribute("data-list-marker", "true"), t.appendChild(n);
862
+ const r = document.createElement("div");
863
+ return r.className = L("flex-1 min-w-0 outline-none", ...W), r.contentEditable = this.readOnly ? "false" : "true", r.innerHTML = this._data.text, this.setupItemPlaceholder(r), t.appendChild(r), t;
864
+ }
865
+ createChecklistContent() {
866
+ const t = document.createElement("div");
867
+ t.setAttribute("role", "listitem"), t.className = u.CHECKLIST_ITEM_STYLES, this.applyItemStyles(t);
868
+ const e = this.getDepth();
869
+ e > 0 && (t.style.marginLeft = `${e * u.INDENT_PER_LEVEL}px`);
870
+ const n = document.createElement("input");
871
+ n.type = "checkbox", n.className = u.CHECKBOX_STYLES, n.checked = !!this._data.checked, n.disabled = this.readOnly;
872
+ const r = document.createElement("div");
873
+ return r.className = L(
874
+ "flex-1 outline-none leading-[1.6em]",
875
+ this._data.checked ? "line-through opacity-60" : "",
876
+ ...W
877
+ ), r.contentEditable = this.readOnly ? "false" : "true", r.innerHTML = this._data.text, this.setupItemPlaceholder(r), this.readOnly || n.addEventListener("change", () => {
878
+ this._data.checked = n.checked, r.classList.toggle("line-through", n.checked), r.classList.toggle("opacity-60", n.checked);
879
+ }), t.appendChild(n), t.appendChild(r), t;
880
+ }
881
+ /**
882
+ * Create the marker element (bullet or number) for a list item
883
+ */
884
+ createListMarker() {
885
+ const t = document.createElement("span");
886
+ t.className = "flex-shrink-0 select-none", t.setAttribute("aria-hidden", "true"), t.contentEditable = "false";
887
+ const e = this.getDepth();
888
+ if (this._data.style === "ordered") {
889
+ const n = this.getSiblingIndex(), r = this.getOrderedMarkerText(n, e);
890
+ t.textContent = r, t.className = L(t.className, "text-right"), t.style.paddingRight = "11px", t.style.minWidth = "fit-content";
891
+ } else {
892
+ const n = this.getBulletCharacter(e);
893
+ t.textContent = n, t.className = L(t.className, "w-6 text-center flex justify-center"), t.style.paddingLeft = "1px", t.style.paddingRight = "13px", t.style.fontSize = "24px", t.style.fontFamily = "Arial";
894
+ }
895
+ return t;
896
+ }
897
+ /**
898
+ * Calculate the index of this ListItem among consecutive siblings with the same style.
899
+ * This is used to determine the correct number for ordered lists.
900
+ */
901
+ getSiblingIndex() {
902
+ var n;
903
+ const t = this.blockId ? (n = this.api.blocks.getBlockIndex(this.blockId)) != null ? n : this.api.blocks.getCurrentBlockIndex() : this.api.blocks.getCurrentBlockIndex();
904
+ if (t <= 0)
905
+ return 0;
906
+ const e = this.getDepth();
907
+ return this.countPrecedingListItemsAtDepth(t - 1, e);
908
+ }
909
+ /**
910
+ * Recursively count consecutive preceding list blocks at the same depth and style.
911
+ * Stops when encountering a block that's not a list, a list at a shallower depth (parent),
912
+ * or a list with a different style at the same depth (treating style changes as list boundaries).
913
+ * Items at deeper depths are skipped regardless of their style.
914
+ */
915
+ countPrecedingListItemsAtDepth(t, e) {
916
+ var c;
917
+ if (t < 0)
918
+ return 0;
919
+ const n = this.api.blocks.getBlockByIndex(t);
920
+ if (!n || n.name !== u.TOOL_NAME)
921
+ return 0;
922
+ const r = n.holder, s = r == null ? void 0 : r.querySelector("[data-list-style]"), o = (c = s == null ? void 0 : s.querySelector('[role="listitem"]')) == null ? void 0 : c.getAttribute("style"), a = o == null ? void 0 : o.match(/margin-left:\s*(\d+)px/), l = a ? Math.round(parseInt(a[1], 10) / u.INDENT_PER_LEVEL) : 0;
923
+ return l < e ? 0 : l > e ? this.countPrecedingListItemsAtDepth(t - 1, e) : (s == null ? void 0 : s.getAttribute("data-list-style")) !== this._data.style ? 0 : 1 + this.countPrecedingListItemsAtDepth(t - 1, e);
924
+ }
925
+ /**
926
+ * Get the depth of this item in the hierarchy (0 = root level)
927
+ */
928
+ getDepth() {
929
+ var t;
930
+ return (t = this._data.depth) != null ? t : 0;
931
+ }
932
+ /**
933
+ * Get the appropriate bullet character based on nesting depth
934
+ */
935
+ getBulletCharacter(t) {
936
+ const e = ["•", "◦", "▪"];
937
+ return e[t % e.length];
938
+ }
939
+ /**
940
+ * Get the ordered list marker text based on depth and index
941
+ */
942
+ getOrderedMarkerText(t, e) {
943
+ const r = this.getListStartValue(t, e) + t;
944
+ switch (e % 3) {
945
+ case 0:
946
+ return `${r}.`;
947
+ case 1:
948
+ return `${this.numberToLowerAlpha(r)}.`;
949
+ case 2:
950
+ return `${this.numberToLowerRoman(r)}.`;
951
+ default:
952
+ return `${r}.`;
953
+ }
954
+ }
955
+ /**
956
+ * Get the starting number for this list group.
957
+ * Looks up the first item in the consecutive list group to find its start value.
958
+ */
959
+ getListStartValue(t, e) {
960
+ var d, c;
961
+ if (t === 0)
962
+ return (d = this._data.start) != null ? d : 1;
963
+ const n = this.blockId ? (c = this.api.blocks.getBlockIndex(this.blockId)) != null ? c : this.api.blocks.getCurrentBlockIndex() : this.api.blocks.getCurrentBlockIndex(), r = this.findFirstListItemIndex(n - 1, e, t);
964
+ if (r === null)
965
+ return 1;
966
+ const s = this.api.blocks.getBlockByIndex(r);
967
+ if (!s)
968
+ return 1;
969
+ const o = s.holder, a = o == null ? void 0 : o.querySelector("[data-list-style]"), l = a == null ? void 0 : a.getAttribute("data-list-start");
970
+ return l ? parseInt(l, 10) : 1;
971
+ }
972
+ /**
973
+ * Find the index of the first list item in this consecutive group.
974
+ * Walks backwards through the blocks counting items at the same depth and style.
975
+ * Stops at style boundaries at the same depth (when encountering a different list style).
976
+ * Items at deeper depths are skipped regardless of their style.
977
+ */
978
+ findFirstListItemIndex(t, e, n) {
979
+ var h;
980
+ if (t < 0 || n <= 0)
981
+ return t + 1;
982
+ const r = this.api.blocks.getBlockByIndex(t);
983
+ if (!r || r.name !== u.TOOL_NAME)
984
+ return t + 1;
985
+ const s = r.holder, o = s == null ? void 0 : s.querySelector("[data-list-style]"), a = (h = o == null ? void 0 : o.querySelector('[role="listitem"]')) == null ? void 0 : h.getAttribute("style"), l = a == null ? void 0 : a.match(/margin-left:\s*(\d+)px/), d = l ? Math.round(parseInt(l[1], 10) / u.INDENT_PER_LEVEL) : 0;
986
+ return d < e ? t + 1 : d > e ? this.findFirstListItemIndex(t - 1, e, n) : (o == null ? void 0 : o.getAttribute("data-list-style")) !== this._data.style ? t + 1 : this.findFirstListItemIndex(t - 1, e, n - 1);
987
+ }
988
+ numberToLowerAlpha(t) {
989
+ const e = (n) => {
990
+ if (n <= 0) return "";
991
+ const r = n - 1;
992
+ return e(Math.floor(r / 26)) + String.fromCharCode(97 + r % 26);
993
+ };
994
+ return e(t);
995
+ }
996
+ numberToLowerRoman(t) {
997
+ const e = [
998
+ [1e3, "m"],
999
+ [900, "cm"],
1000
+ [500, "d"],
1001
+ [400, "cd"],
1002
+ [100, "c"],
1003
+ [90, "xc"],
1004
+ [50, "l"],
1005
+ [40, "xl"],
1006
+ [10, "x"],
1007
+ [9, "ix"],
1008
+ [5, "v"],
1009
+ [4, "iv"],
1010
+ [1, "i"]
1011
+ ], n = (r, s) => {
1012
+ if (r <= 0 || s >= e.length) return "";
1013
+ const [o, a] = e[s];
1014
+ return r >= o ? a + n(r - o, s) : n(r, s + 1);
1015
+ };
1016
+ return n(t, 0);
1017
+ }
1018
+ handleKeyDown(t) {
1019
+ if (t.key === "Enter" && !t.shiftKey) {
1020
+ t.preventDefault(), this.handleEnter();
1021
+ return;
1022
+ }
1023
+ if (t.key === "Backspace") {
1024
+ this.handleBackspace(t);
1025
+ return;
1026
+ }
1027
+ if (t.key === "Tab" && t.shiftKey) {
1028
+ t.preventDefault(), this.handleOutdent();
1029
+ return;
1030
+ }
1031
+ t.key === "Tab" && (t.preventDefault(), this.handleIndent());
1032
+ }
1033
+ async handleEnter() {
1034
+ const t = window.getSelection();
1035
+ if (!t || !this._element) return;
1036
+ const e = this.getContentElement();
1037
+ if (!e) return;
1038
+ const n = e.innerHTML.trim();
1039
+ if (n === "" || n === "<br>") {
1040
+ await this.exitListOrOutdent();
1041
+ return;
1042
+ }
1043
+ const r = t.getRangeAt(0), { beforeContent: s, afterContent: o } = this.splitContentAtCursor(e, r);
1044
+ e.innerHTML = s, this._data.text = s;
1045
+ const a = this.api.blocks.getCurrentBlockIndex(), l = this.api.blocks.insert(u.TOOL_NAME, {
1046
+ text: o,
1047
+ style: this._data.style,
1048
+ checked: !1,
1049
+ depth: this._data.depth
1050
+ }, void 0, a + 1, !0);
1051
+ this.setCaretToBlockContent(l, "start");
1052
+ }
1053
+ async exitListOrOutdent() {
1054
+ const t = this.api.blocks.getCurrentBlockIndex();
1055
+ if (this.getDepth() > 0) {
1056
+ await this.handleOutdent();
1057
+ return;
1058
+ }
1059
+ await this.api.blocks.delete(t);
1060
+ const n = this.api.blocks.insert("paragraph", { text: "" }, void 0, t, !0);
1061
+ this.setCaretToBlockContent(n, "start");
1062
+ }
1063
+ async handleBackspace(t) {
1064
+ const e = window.getSelection();
1065
+ if (!e || !this._element) return;
1066
+ const n = e.getRangeAt(0), r = this.getContentElement();
1067
+ if (!r) return;
1068
+ this.syncContentFromDOM();
1069
+ const s = this.api.blocks.getCurrentBlockIndex(), o = this._data.text, a = this.getDepth();
1070
+ if (this.isEntireContentSelected(r, n) && !e.isCollapsed) {
1071
+ t.preventDefault(), r.innerHTML = "", this._data.text = "";
1072
+ const c = document.createRange();
1073
+ c.setStart(r, 0), c.collapse(!0), e.removeAllRanges(), e.addRange(c);
1074
+ return;
1075
+ }
1076
+ if (!this.isAtStart(r, n)) return;
1077
+ t.preventDefault(), await this.api.blocks.delete(s);
1078
+ const d = this.api.blocks.insert(
1079
+ "paragraph",
1080
+ { text: o },
1081
+ void 0,
1082
+ s,
1083
+ !0
1084
+ );
1085
+ a > 0 && requestAnimationFrame(() => {
1086
+ const c = d.holder;
1087
+ c && (c.style.marginLeft = `${a * u.INDENT_PER_LEVEL}px`, c.setAttribute("data-blok-depth", String(a)));
1088
+ }), this.setCaretToBlockContent(d, "start");
1089
+ }
1090
+ /**
1091
+ * Collect all text nodes from an element
1092
+ * @param node - Node to collect text nodes from
1093
+ * @returns Array of text nodes
1094
+ */
1095
+ collectTextNodes(t) {
1096
+ var e;
1097
+ return t.nodeType === Node.TEXT_NODE ? [t] : (e = t.hasChildNodes) != null && e.call(t) ? Array.from(t.childNodes).flatMap((n) => this.collectTextNodes(n)) : [];
1098
+ }
1099
+ /**
1100
+ * Find the text node and offset for a given character position
1101
+ * @param textNodes - Array of text nodes to search through
1102
+ * @param targetPosition - Character position to find
1103
+ * @returns Object with node and offset, or null if not found
1104
+ */
1105
+ findCaretPosition(t, e) {
1106
+ const n = t.reduce(
1107
+ (r, s) => {
1108
+ var a, l;
1109
+ if (r.found) return r;
1110
+ const o = (l = (a = s.textContent) == null ? void 0 : a.length) != null ? l : 0;
1111
+ return r.charCount + o >= e ? {
1112
+ found: !0,
1113
+ charCount: r.charCount,
1114
+ node: s,
1115
+ offset: e - r.charCount
1116
+ } : P(w({}, r), {
1117
+ charCount: r.charCount + o
1118
+ });
1119
+ },
1120
+ { found: !1, charCount: 0, node: null, offset: 0 }
1121
+ );
1122
+ return n.node ? { node: n.node, offset: n.offset } : null;
1123
+ }
1124
+ /**
1125
+ * Sync the current DOM content to the data model
1126
+ */
1127
+ syncContentFromDOM() {
1128
+ var n;
1129
+ const t = this.getContentElement();
1130
+ if (t && (this._data.text = t.innerHTML), this._data.style !== "checklist")
1131
+ return;
1132
+ const e = (n = this._element) == null ? void 0 : n.querySelector('input[type="checkbox"]');
1133
+ e && (this._data.checked = e.checked);
1134
+ }
1135
+ /**
1136
+ * Get the depth of the parent list item by walking backwards through preceding items.
1137
+ * A parent is the first preceding list item with a depth less than the current item.
1138
+ * @param blockIndex - The index of the current block
1139
+ * @returns The parent's depth, or -1 if no parent exists (at root level)
1140
+ */
1141
+ getParentDepth(t) {
1142
+ const e = this.getDepth(), n = (r) => {
1143
+ if (r < 0)
1144
+ return -1;
1145
+ const s = this.api.blocks.getBlockByIndex(r);
1146
+ if (!s || s.name !== u.TOOL_NAME)
1147
+ return -1;
1148
+ const o = this.getBlockDepth(s);
1149
+ return o < e ? o : n(r - 1);
1150
+ };
1151
+ return n(t - 1);
1152
+ }
1153
+ async handleIndent() {
1154
+ const t = this.api.blocks.getCurrentBlockIndex();
1155
+ if (t === 0) return;
1156
+ const e = this.api.blocks.getBlockByIndex(t - 1);
1157
+ if (!e || e.name !== u.TOOL_NAME) return;
1158
+ const n = this.getDepth(), r = this.getBlockDepth(e);
1159
+ if (n > r) return;
1160
+ this.syncContentFromDOM();
1161
+ const s = n + 1;
1162
+ this._data.depth = s;
1163
+ const o = await this.api.blocks.update(this.blockId || "", P(w({}, this._data), {
1164
+ depth: s
1165
+ }));
1166
+ this.setCaretToBlockContent(o);
1167
+ }
1168
+ async handleOutdent() {
1169
+ const t = this.getDepth();
1170
+ if (t === 0) return;
1171
+ this.syncContentFromDOM();
1172
+ const e = t - 1;
1173
+ this._data.depth = e;
1174
+ const n = await this.api.blocks.update(this.blockId || "", P(w({}, this._data), {
1175
+ depth: e
1176
+ }));
1177
+ this.setCaretToBlockContent(n);
1178
+ }
1179
+ getContentElement() {
1180
+ return this._element ? this._data.style === "checklist" ? this._element.querySelector("[contenteditable]") : this._element.querySelector("div.flex-1") : null;
1181
+ }
1182
+ /**
1183
+ * Sets caret to the content element of a block after ensuring DOM is ready.
1184
+ * Uses requestAnimationFrame to wait for the browser to process DOM updates.
1185
+ * @param block - BlockAPI to set caret to
1186
+ * @param position - 'start' or 'end' position (defaults to 'end')
1187
+ */
1188
+ setCaretToBlockContent(t, e = "end") {
1189
+ requestAnimationFrame(() => {
1190
+ const n = t.holder;
1191
+ if (!n) return;
1192
+ const r = n.querySelector('[contenteditable="true"]');
1193
+ if (!r) {
1194
+ this.api.caret.setToBlock(t, e);
1195
+ return;
1196
+ }
1197
+ r.focus();
1198
+ const s = window.getSelection();
1199
+ if (!s) return;
1200
+ const o = document.createRange();
1201
+ e === "start" ? (o.setStart(r, 0), o.collapse(!0)) : (o.selectNodeContents(r), o.collapse(!1)), s.removeAllRanges(), s.addRange(o);
1202
+ });
1203
+ }
1204
+ isAtStart(t, e) {
1205
+ const n = document.createRange();
1206
+ return n.selectNodeContents(t), n.setEnd(e.startContainer, e.startOffset), n.toString().length === 0;
1207
+ }
1208
+ /**
1209
+ * Check if the entire content of an element is selected
1210
+ * @param element - The content element to check
1211
+ * @param range - The current selection range
1212
+ * @returns true if the entire content is selected
1213
+ */
1214
+ isEntireContentSelected(t, e) {
1215
+ const n = document.createRange();
1216
+ n.selectNodeContents(t), n.setEnd(e.startContainer, e.startOffset);
1217
+ const r = n.toString().length === 0, s = document.createRange();
1218
+ s.selectNodeContents(t), s.setStart(e.endContainer, e.endOffset);
1219
+ const o = s.toString().length === 0;
1220
+ return r && o;
1221
+ }
1222
+ splitContentAtCursor(t, e) {
1223
+ const n = document.createRange();
1224
+ n.setStart(t, 0), n.setEnd(e.startContainer, e.startOffset);
1225
+ const r = document.createRange();
1226
+ return r.setStart(e.endContainer, e.endOffset), r.setEndAfter(t.lastChild || t), {
1227
+ beforeContent: this.getFragmentHTML(n.cloneContents()),
1228
+ afterContent: this.getFragmentHTML(r.cloneContents())
1229
+ };
1230
+ }
1231
+ getFragmentHTML(t) {
1232
+ const e = document.createElement("div");
1233
+ return e.appendChild(t), e.innerHTML;
1234
+ }
1235
+ renderSettings() {
1236
+ return this.availableStyles.map((t) => ({
1237
+ icon: t.icon,
1238
+ label: this.api.i18n.t(`toolNames.${t.name}`),
1239
+ onActivate: () => this.setStyle(t.style),
1240
+ closeOnActivate: !0,
1241
+ isActive: this._data.style === t.style
1242
+ }));
1243
+ }
1244
+ setStyle(t) {
1245
+ const e = this._data.style;
1246
+ this._data.style = t, this.rerender(), e !== t && requestAnimationFrame(() => {
1247
+ this.updateAllOrderedListMarkers();
1248
+ });
1249
+ }
1250
+ rerender() {
1251
+ if (!this._element) return;
1252
+ const t = this._element.parentNode;
1253
+ if (!t) return;
1254
+ const e = this.createItemElement();
1255
+ t.replaceChild(e, this._element), this._element = e;
1256
+ }
1257
+ validate(t) {
1258
+ return typeof t.text == "string";
1259
+ }
1260
+ save() {
1261
+ if (!this._element) return this._data;
1262
+ const t = this.getContentElement(), n = {
1263
+ text: t ? et(t.innerHTML) : this._data.text,
1264
+ style: this._data.style,
1265
+ checked: this._data.checked
1266
+ };
1267
+ return this._data.start !== void 0 && this._data.start !== 1 && (n.start = this._data.start), this._data.depth !== void 0 && this._data.depth > 0 && (n.depth = this._data.depth), n;
1268
+ }
1269
+ merge(t) {
1270
+ if (!this._element)
1271
+ return;
1272
+ this._data.text += t.text;
1273
+ const e = this.getContentElement();
1274
+ if (e && t.text) {
1275
+ const n = this.parseHtml(t.text);
1276
+ e.appendChild(n), e.normalize();
1277
+ }
1278
+ }
1279
+ /**
1280
+ * Parse HTML string into a DocumentFragment
1281
+ * @param html - HTML string to parse
1282
+ * @returns DocumentFragment with parsed nodes
1283
+ */
1284
+ parseHtml(t) {
1285
+ const e = document.createElement("div");
1286
+ e.innerHTML = t.trim();
1287
+ const n = document.createDocumentFragment();
1288
+ return n.append(...Array.from(e.childNodes)), n;
1289
+ }
1290
+ static get conversionConfig() {
1291
+ return {
1292
+ export: (t) => t.text,
1293
+ import: (t) => ({
1294
+ text: t,
1295
+ style: "unordered",
1296
+ checked: !1
1297
+ })
1298
+ };
1299
+ }
1300
+ static get sanitize() {
1301
+ return {
1302
+ text: {
1303
+ br: !0,
1304
+ a: !0,
1305
+ b: !0,
1306
+ i: !0,
1307
+ mark: !0
1308
+ }
1309
+ };
1310
+ }
1311
+ static get pasteConfig() {
1312
+ return { tags: ["LI"] };
1313
+ }
1314
+ onPaste(t) {
1315
+ const e = t.detail;
1316
+ if (!("data" in e)) return;
1317
+ const n = e.data, r = n.innerHTML || n.textContent || "", s = n.querySelector('input[type="checkbox"]'), o = (s == null ? void 0 : s.checked) || !1;
1318
+ this._data = {
1319
+ text: r,
1320
+ style: this.detectStyleFromPastedContent(n),
1321
+ checked: o
1322
+ }, this.rerender();
1323
+ }
1324
+ /**
1325
+ * Detect list style from pasted content based on parent element
1326
+ */
1327
+ detectStyleFromPastedContent(t) {
1328
+ const e = t.parentElement;
1329
+ return e ? e.tagName === "OL" ? "ordered" : e.tagName !== "UL" ? this._data.style : t.querySelector('input[type="checkbox"]') ? "checklist" : "unordered" : this._data.style;
1330
+ }
1331
+ static get isReadOnlySupported() {
1332
+ return !0;
1333
+ }
1334
+ /**
1335
+ * Returns the horizontal offset of the content at the hovered element.
1336
+ * Used by the toolbar to position itself closer to nested list items.
1337
+ *
1338
+ * @param hoveredElement - The element that is currently being hovered
1339
+ * @returns Object with left offset in pixels based on the list item's depth
1340
+ */
1341
+ getContentOffset(t) {
1342
+ var r;
1343
+ const e = (r = t.closest('[role="listitem"]')) != null ? r : t.querySelector('[role="listitem"]'), n = this.getMarginLeftFromElement(e);
1344
+ return n !== void 0 ? n : this.getOffsetFromDepthAttribute(t);
1345
+ }
1346
+ /**
1347
+ * Extracts the margin-left value from an element's inline style
1348
+ * @param element - The element to extract margin-left from
1349
+ * @returns Object with left offset if valid margin-left found, undefined otherwise
1350
+ */
1351
+ getMarginLeftFromElement(t) {
1352
+ if (!t)
1353
+ return;
1354
+ const n = (t.getAttribute("style") || "").match(/margin-left:\s*(\d+)px/);
1355
+ if (!n)
1356
+ return;
1357
+ const r = parseInt(n[1], 10);
1358
+ return r > 0 ? { left: r } : void 0;
1359
+ }
1360
+ /**
1361
+ * Gets the offset from the data-list-depth attribute
1362
+ * @param hoveredElement - The element to start searching from
1363
+ * @returns Object with left offset based on depth, undefined if depth is 0 or not found
1364
+ */
1365
+ getOffsetFromDepthAttribute(t) {
1366
+ const e = t.closest("[data-list-depth]");
1367
+ if (!e)
1368
+ return;
1369
+ const n = e.getAttribute("data-list-depth");
1370
+ if (n === null)
1371
+ return;
1372
+ const r = parseInt(n, 10);
1373
+ return r > 0 ? { left: r * u.INDENT_PER_LEVEL } : void 0;
1374
+ }
1375
+ static get toolbox() {
1376
+ return [
1377
+ {
1378
+ icon: G,
1379
+ title: "Bulleted list",
1380
+ titleKey: "bulletedList",
1381
+ data: { style: "unordered" },
1382
+ name: "bulleted-list"
1383
+ },
1384
+ {
1385
+ icon: j,
1386
+ title: "Numbered list",
1387
+ titleKey: "numberedList",
1388
+ data: { style: "ordered" },
1389
+ name: "numbered-list"
1390
+ },
1391
+ {
1392
+ icon: $,
1393
+ title: "To-do list",
1394
+ titleKey: "todoList",
1395
+ data: { style: "checklist" },
1396
+ name: "check-list"
1397
+ }
1398
+ ];
1399
+ }
1400
+ };
1401
+ u.BASE_STYLES = "outline-none", u.ITEM_STYLES = "outline-none py-0.5 pl-0.5 leading-[1.6em]", u.CHECKLIST_ITEM_STYLES = "flex items-start py-0.5 pl-0.5", u.CHECKBOX_STYLES = "mt-1 w-4 mr-2 h-4 cursor-pointer accent-current", u.STYLE_CONFIGS = [
1402
+ { style: "unordered", name: "bulletedList", icon: G },
1403
+ { style: "ordered", name: "numberedList", icon: j },
1404
+ { style: "checklist", name: "todoList", icon: $ }
1405
+ ], u.pendingMarkerUpdate = !1, u.DEFAULT_PLACEHOLDER = "List", u.INDENT_PER_LEVEL = 24, u.TOOL_NAME = "list";
1406
+ let J = u;
1407
+ const i = class i {
1408
+ /**
1409
+ * Sanitizer Rule
1410
+ * Leave <strong> tags
1411
+ * @returns {object}
1412
+ */
1413
+ static get sanitize() {
1414
+ return {
1415
+ strong: {},
1416
+ b: {}
1417
+ };
1418
+ }
1419
+ /**
1420
+ * Normalize any remaining legacy <b> tags within the blok wrapper
1421
+ */
1422
+ static normalizeAllBoldTags() {
1423
+ if (typeof document == "undefined")
1424
+ return;
1425
+ const t = `${A(g.interface)} b, ${A(g.editor)} b`;
1426
+ document.querySelectorAll(t).forEach((e) => {
1427
+ i.ensureStrongElement(e);
1428
+ });
1429
+ }
1430
+ /**
1431
+ * Normalize bold tags within a mutated node if it belongs to the blok
1432
+ * @param node - The node affected by mutation
1433
+ */
1434
+ static normalizeBoldInNode(t) {
1435
+ var r;
1436
+ const e = t.nodeType === Node.ELEMENT_NODE ? t : t.parentElement;
1437
+ !e || typeof e.closest != "function" || !e.closest(`${A(g.interface)}, ${A(g.editor)}`) || (e.tagName === "B" && i.ensureStrongElement(e), (r = e.querySelectorAll) == null || r.call(e, "b").forEach((s) => {
1438
+ i.ensureStrongElement(s);
1439
+ }));
1440
+ }
1441
+ /**
1442
+ *
1443
+ */
1444
+ constructor() {
1445
+ typeof document != "undefined" && (i.instances.add(this), i.initializeGlobalListeners());
1446
+ }
1447
+ /**
1448
+ * Ensure global event listeners are registered once per document
1449
+ */
1450
+ static initializeGlobalListeners() {
1451
+ return typeof document == "undefined" ? !1 : (i.shortcutListenerRegistered || (document.addEventListener("keydown", i.handleShortcut, !0), i.shortcutListenerRegistered = !0), i.selectionListenerRegistered || (document.addEventListener("selectionchange", i.handleGlobalSelectionChange, !0), i.selectionListenerRegistered = !0), i.inputListenerRegistered || (document.addEventListener("input", i.handleGlobalInput, !0), i.inputListenerRegistered = !0), i.beforeInputListenerRegistered || (document.addEventListener("beforeinput", i.handleBeforeInput, !0), i.beforeInputListenerRegistered = !0), i.ensureMutationObserver(), !0);
1452
+ }
1453
+ /**
1454
+ * Ensure that text typed after exiting a collapsed bold selection stays outside of the bold element
1455
+ */
1456
+ static maintainCollapsedExitState() {
1457
+ var t, e, n, r, s;
1458
+ if (typeof document != "undefined")
1459
+ for (const o of Array.from(i.collapsedExitRecords)) {
1460
+ const a = i.resolveBoundary(o);
1461
+ if (!a) {
1462
+ i.collapsedExitRecords.delete(o);
1463
+ continue;
1464
+ }
1465
+ o.boundary = a.boundary, o.boldElement = a.boldElement;
1466
+ const l = a.boundary, d = a.boldElement, c = o.allowedLength, h = (t = d.textContent) != null ? t : "";
1467
+ if (h.length > c) {
1468
+ const b = h.slice(0, c), S = h.slice(c);
1469
+ d.textContent = b, l.textContent = ((e = l.textContent) != null ? e : "") + S;
1470
+ }
1471
+ const p = (n = l.textContent) != null ? n : "";
1472
+ p.length > 1 && p.startsWith("​") && (l.textContent = p.slice(1));
1473
+ const T = window.getSelection();
1474
+ i.ensureCaretAtBoundary(T, l), i.scheduleBoundaryCaretAdjustment(l);
1475
+ const y = (r = l.textContent) != null ? r : "", m = y.replace(/\u200B/g, ""), C = m.match(/^\s+/), E = /\S/.test(m), N = y.startsWith("​");
1476
+ C && (o.hasLeadingSpace = !0, o.leadingWhitespace = C[0]), E && (o.hasTypedContent = !0);
1477
+ const B = /^\s/.test(m), x = o.hasTypedContent && !N && ((s = d.textContent) != null ? s : "").length <= c, v = o.hasLeadingSpace && o.hasTypedContent && !B;
1478
+ if (x && v) {
1479
+ const b = y.replace(/^[\u200B\s]+/, ""), S = o.leadingWhitespace || " ";
1480
+ l.textContent = `${S}${b}`, i.ensureCaretAtBoundary(T, l);
1481
+ }
1482
+ x && i.collapsedExitRecords.delete(o);
1483
+ }
1484
+ }
1485
+ /**
1486
+ * Ensure the caret remains at the end of the boundary text node when exiting bold
1487
+ * @param selection - Current document selection
1488
+ * @param boundary - Text node following the bold element
1489
+ */
1490
+ static ensureCaretAtBoundary(t, e) {
1491
+ !t || !t.isCollapsed || i.setCaretToBoundaryEnd(t, e);
1492
+ }
1493
+ /**
1494
+ * Ensure the caret remains at the end of the boundary text node after the current microtask queue is flushed
1495
+ * @param boundary - Boundary text node that should keep the caret at its end
1496
+ */
1497
+ static scheduleBoundaryCaretAdjustment(t) {
1498
+ i.pendingBoundaryCaretAdjustments.has(t) || (i.pendingBoundaryCaretAdjustments.add(t), setTimeout(() => {
1499
+ var s, o, a;
1500
+ i.pendingBoundaryCaretAdjustments.delete(t);
1501
+ const e = (s = t.ownerDocument) != null ? s : typeof document != "undefined" ? document : null;
1502
+ if (!e)
1503
+ return;
1504
+ const n = e.getSelection();
1505
+ if (!n || !n.isCollapsed || n.anchorNode !== t)
1506
+ return;
1507
+ const r = (a = (o = t.textContent) == null ? void 0 : o.length) != null ? a : 0;
1508
+ n.anchorOffset !== r && i.setCaret(n, t, r);
1509
+ }, 0));
1510
+ }
1511
+ /**
1512
+ * Ensure there is a text node immediately following the provided bold element.
1513
+ * Creates one when necessary.
1514
+ * @param boldElement - Bold element that precedes the boundary
1515
+ * @returns The text node following the bold element or null if it cannot be created
1516
+ */
1517
+ static ensureTextNodeAfter(t) {
1518
+ var o;
1519
+ const e = t.nextSibling;
1520
+ if ((e == null ? void 0 : e.nodeType) === Node.TEXT_NODE)
1521
+ return e;
1522
+ const n = t.parentNode;
1523
+ if (!n)
1524
+ return null;
1525
+ const r = (o = t.ownerDocument) != null ? o : typeof document != "undefined" ? document : null;
1526
+ if (!r)
1527
+ return null;
1528
+ const s = r.createTextNode("");
1529
+ return n.insertBefore(s, e), s;
1530
+ }
1531
+ /**
1532
+ * Resolve the boundary text node tracked for a collapsed exit record.
1533
+ * @param record - Collapsed exit tracking record
1534
+ * @returns The aligned boundary text node or null when it cannot be determined
1535
+ */
1536
+ static resolveBoundary(t) {
1537
+ if (!t.boldElement.isConnected)
1538
+ return null;
1539
+ const e = i.ensureStrongElement(t.boldElement), n = t.boundary, s = n.isConnected && n.previousSibling === e ? n : i.ensureTextNodeAfter(e);
1540
+ return s ? {
1541
+ boundary: s,
1542
+ boldElement: e
1543
+ } : null;
1544
+ }
1545
+ /**
1546
+ * Move caret to the end of the provided boundary text node
1547
+ * @param selection - Current selection to update
1548
+ * @param boundary - Boundary text node that hosts the caret
1549
+ */
1550
+ static setCaretToBoundaryEnd(t, e) {
1551
+ var s, o;
1552
+ const n = document.createRange(), r = (o = (s = e.textContent) == null ? void 0 : s.length) != null ? o : 0;
1553
+ n.setStart(e, r), n.collapse(!0), t.removeAllRanges(), t.addRange(n);
1554
+ }
1555
+ /**
1556
+ * Recursively check if a node or any of its parents is a bold tag (<strong>)
1557
+ * @param node - The node to check
1558
+ */
1559
+ static hasBoldParent(t) {
1560
+ return t ? t.nodeType === Node.ELEMENT_NODE && i.isBoldTag(t) ? !0 : i.hasBoldParent(t.parentNode) : !1;
1561
+ }
1562
+ /**
1563
+ * Recursively find a bold element (<strong>) in the parent chain
1564
+ * @param node - The node to start searching from
1565
+ */
1566
+ static findBoldElement(t) {
1567
+ return t ? t.nodeType === Node.ELEMENT_NODE && i.isBoldTag(t) ? i.ensureStrongElement(t) : i.findBoldElement(t.parentNode) : null;
1568
+ }
1569
+ /**
1570
+ * Check if an element is a bold tag (<strong> for conversion)
1571
+ * @param node - The element to check
1572
+ */
1573
+ static isBoldTag(t) {
1574
+ const e = t.tagName;
1575
+ return e === "B" || e === "STRONG";
1576
+ }
1577
+ /**
1578
+ * Ensure an element is a <strong> tag, converting from <b> if needed
1579
+ * @param element - The element to ensure is a strong tag
1580
+ */
1581
+ static ensureStrongElement(t) {
1582
+ if (t.tagName === "STRONG")
1583
+ return t;
1584
+ const e = document.createElement("strong");
1585
+ for (t.hasAttributes() && Array.from(t.attributes).forEach((n) => {
1586
+ e.setAttribute(n.name, n.value);
1587
+ }); t.firstChild; )
1588
+ e.appendChild(t.firstChild);
1589
+ return t.replaceWith(e), e;
1590
+ }
1591
+ /**
1592
+ * Merge two strong elements by moving children from right to left
1593
+ * @param left - The left strong element to merge into
1594
+ * @param right - The right strong element to merge from
1595
+ */
1596
+ static mergeStrongNodes(t, e) {
1597
+ const n = i.ensureStrongElement(t), r = i.ensureStrongElement(e);
1598
+ for (; r.firstChild; )
1599
+ n.appendChild(r.firstChild);
1600
+ return r.remove(), n;
1601
+ }
1602
+ /**
1603
+ * Create button for Inline Toolbar
1604
+ */
1605
+ render() {
1606
+ return {
1607
+ icon: gt,
1608
+ name: "bold",
1609
+ onActivate: () => {
1610
+ this.toggleBold();
1611
+ },
1612
+ isActive: () => {
1613
+ const t = window.getSelection();
1614
+ return t ? this.isSelectionVisuallyBold(t) : !1;
1615
+ }
1616
+ };
1617
+ }
1618
+ /**
1619
+ * Apply or remove bold formatting using modern Selection API
1620
+ */
1621
+ toggleBold() {
1622
+ const t = window.getSelection();
1623
+ if (!t || t.rangeCount === 0)
1624
+ return;
1625
+ const e = t.getRangeAt(0);
1626
+ if (e.collapsed) {
1627
+ this.toggleCollapsedSelection();
1628
+ return;
1629
+ }
1630
+ this.isRangeBold(e, { ignoreWhitespace: !0 }) ? this.unwrapBoldTags(e) : this.wrapWithBold(e);
1631
+ }
1632
+ /**
1633
+ * Check if current selection is within a bold tag (<strong>)
1634
+ * @param selection - The Selection object to check
1635
+ */
1636
+ isSelectionVisuallyBold(t) {
1637
+ if (!t || t.rangeCount === 0)
1638
+ return !1;
1639
+ const e = t.getRangeAt(0);
1640
+ return this.isRangeBold(e, { ignoreWhitespace: !0 });
1641
+ }
1642
+ /**
1643
+ * Wrap selection with <strong> tag
1644
+ * @param range - The Range object containing the selection to wrap
1645
+ */
1646
+ wrapWithBold(t) {
1647
+ const e = this.getRangeHtmlWithoutBold(t), n = this.replaceRangeWithHtml(t, `<strong>${e}</strong>`), r = window.getSelection();
1648
+ r && n && (r.removeAllRanges(), r.addRange(n)), i.normalizeAllBoldTags();
1649
+ const s = this.findBoldElementFromRangeOrSelection(n, r);
1650
+ if (!s) {
1651
+ this.notifySelectionChange();
1652
+ return;
1653
+ }
1654
+ const o = this.mergeAdjacentBold(s);
1655
+ this.normalizeWhitespaceAround(o), this.selectElementContents(o), i.normalizeBoldTagsWithinBlok(window.getSelection()), i.replaceNbspInBlock(window.getSelection()), this.notifySelectionChange();
1656
+ }
1657
+ /**
1658
+ * Remove bold tags (<strong>) while preserving content
1659
+ * @param range - The Range object containing the selection to unwrap
1660
+ */
1661
+ unwrapBoldTags(t) {
1662
+ const e = this.collectBoldAncestors(t), n = window.getSelection();
1663
+ if (!n)
1664
+ return;
1665
+ const r = document.createElement("span"), s = t.extractContents();
1666
+ r.setAttribute("data-blok-bold-marker", `unwrap-${i.markerSequence++}`), r.appendChild(s), this.removeNestedBold(r), t.insertNode(r);
1667
+ const o = document.createRange();
1668
+ for (o.selectNodeContents(r), n.removeAllRanges(), n.addRange(o); ; ) {
1669
+ const c = i.findBoldElement(r);
1670
+ if (!c)
1671
+ break;
1672
+ this.moveMarkerOutOfBold(r, c);
1673
+ }
1674
+ const a = r.firstChild, l = r.lastChild;
1675
+ this.unwrapElement(r);
1676
+ const d = a && l ? (() => {
1677
+ const c = document.createRange();
1678
+ return c.setStartBefore(a), c.setEndAfter(l), n.removeAllRanges(), n.addRange(c), c;
1679
+ })() : void 0;
1680
+ d || n.removeAllRanges(), this.replaceNbspWithinRange(d), i.normalizeBoldTagsWithinBlok(n), i.replaceNbspInBlock(n), i.removeEmptyBoldElements(n), e.forEach((c) => {
1681
+ i.isElementEmpty(c) && c.remove();
1682
+ }), this.notifySelectionChange();
1683
+ }
1684
+ /**
1685
+ * Replace the current range contents with provided HTML snippet
1686
+ * @param range - Range to replace
1687
+ * @param html - HTML string to insert
1688
+ * @returns range spanning inserted content
1689
+ */
1690
+ replaceRangeWithHtml(t, e) {
1691
+ var a, l;
1692
+ const n = i.createFragmentFromHtml(e), r = (a = n.firstChild) != null ? a : null, s = (l = n.lastChild) != null ? l : null;
1693
+ if (t.deleteContents(), !r || !s)
1694
+ return;
1695
+ t.insertNode(n);
1696
+ const o = document.createRange();
1697
+ return o.setStartBefore(r), o.setEndAfter(s), o;
1698
+ }
1699
+ /**
1700
+ * Move a temporary marker element outside of a bold ancestor while preserving content order
1701
+ * @param marker - Marker element wrapping the selection contents
1702
+ * @param boldElement - Bold ancestor containing the marker
1703
+ */
1704
+ moveMarkerOutOfBold(t, e) {
1705
+ const n = e.parentNode;
1706
+ if (!n)
1707
+ return;
1708
+ if (Array.from(e.childNodes).forEach((l) => {
1709
+ var d;
1710
+ l.nodeType === Node.TEXT_NODE && ((d = l.textContent) != null ? d : "").length === 0 && l.remove();
1711
+ }), e.childNodes.length === 1 && e.firstChild === t) {
1712
+ e.replaceWith(t);
1713
+ return;
1714
+ }
1715
+ if (e.firstChild === t) {
1716
+ n.insertBefore(t, e);
1717
+ return;
1718
+ }
1719
+ if (e.lastChild === t) {
1720
+ n.insertBefore(t, e.nextSibling);
1721
+ return;
1722
+ }
1723
+ const a = e.cloneNode(!1);
1724
+ for (; t.nextSibling; )
1725
+ a.appendChild(t.nextSibling);
1726
+ n.insertBefore(a, e.nextSibling), n.insertBefore(t, a);
1727
+ }
1728
+ /**
1729
+ * Select all contents of an element
1730
+ * @param element - The element whose contents should be selected
1731
+ */
1732
+ selectElementContents(t) {
1733
+ const e = window.getSelection();
1734
+ if (!e)
1735
+ return;
1736
+ const n = document.createRange();
1737
+ n.selectNodeContents(t), e.removeAllRanges(), e.addRange(n);
1738
+ }
1739
+ /**
1740
+ * Check if a range contains bold text
1741
+ * @param range - The range to check
1742
+ * @param options - Options for checking bold status
1743
+ * @param options.ignoreWhitespace - Whether to ignore whitespace-only text nodes
1744
+ */
1745
+ isRangeBold(t, e) {
1746
+ var s;
1747
+ if (t.collapsed)
1748
+ return !!i.findBoldElement(t.startContainer);
1749
+ const n = document.createTreeWalker(
1750
+ t.commonAncestorContainer,
1751
+ NodeFilter.SHOW_TEXT,
1752
+ {
1753
+ acceptNode: (o) => {
1754
+ try {
1755
+ return t.intersectsNode(o) ? NodeFilter.FILTER_ACCEPT : NodeFilter.FILTER_REJECT;
1756
+ } catch (a) {
1757
+ const l = document.createRange();
1758
+ l.selectNodeContents(o);
1759
+ const d = t.compareBoundaryPoints(Range.END_TO_START, l) > 0, c = t.compareBoundaryPoints(Range.START_TO_END, l) < 0;
1760
+ return d && c ? NodeFilter.FILTER_ACCEPT : NodeFilter.FILTER_REJECT;
1761
+ }
1762
+ }
1763
+ }
1764
+ ), r = [];
1765
+ for (; n.nextNode(); ) {
1766
+ const o = n.currentNode, a = (s = o.textContent) != null ? s : "";
1767
+ e.ignoreWhitespace && a.trim().length === 0 || a.length !== 0 && r.push(o);
1768
+ }
1769
+ return r.length === 0 ? !!i.findBoldElement(t.startContainer) : r.every((o) => i.hasBoldParent(o));
1770
+ }
1771
+ /**
1772
+ * Remove nested bold tags from a root node
1773
+ * @param root - The root node to process
1774
+ */
1775
+ removeNestedBold(t) {
1776
+ var n;
1777
+ const e = (n = t.querySelectorAll) == null ? void 0 : n.call(t, "b,strong");
1778
+ e && e.forEach((r) => {
1779
+ this.unwrapElement(r);
1780
+ });
1781
+ }
1782
+ /**
1783
+ * Unwrap an element by moving its children to the parent
1784
+ * @param element - The element to unwrap
1785
+ */
1786
+ unwrapElement(t) {
1787
+ const e = t.parentNode;
1788
+ if (!e) {
1789
+ t.remove();
1790
+ return;
1791
+ }
1792
+ for (; t.firstChild; )
1793
+ e.insertBefore(t.firstChild, t);
1794
+ e.removeChild(t);
1795
+ }
1796
+ /**
1797
+ * Find bold element from an inserted range or fall back to selection
1798
+ * @param insertedRange - Range spanning inserted content
1799
+ * @param selection - Current selection as fallback
1800
+ */
1801
+ findBoldElementFromRangeOrSelection(t, e) {
1802
+ if (!t)
1803
+ return e ? i.findBoldElement(e.focusNode) : null;
1804
+ const n = i.findBoldElement(t.startContainer);
1805
+ if (n)
1806
+ return n;
1807
+ const r = i.findBoldElement(t.commonAncestorContainer);
1808
+ return r || (t.startContainer.nodeType === Node.ELEMENT_NODE && i.isBoldTag(t.startContainer) ? t.startContainer : null);
1809
+ }
1810
+ /**
1811
+ * Merge adjacent bold elements into a single element
1812
+ * @param element - The bold element to merge with adjacent elements
1813
+ */
1814
+ mergeAdjacentBold(t) {
1815
+ const e = i.ensureStrongElement(t), n = e.previousSibling, r = n && n.nodeType === Node.ELEMENT_NODE && i.isBoldTag(n) ? i.mergeStrongNodes(n, e) : e, s = r.nextSibling;
1816
+ return s && s.nodeType === Node.ELEMENT_NODE && i.isBoldTag(s) ? i.mergeStrongNodes(r, s) : r;
1817
+ }
1818
+ /**
1819
+ * Toggle bold formatting for a collapsed selection (caret position)
1820
+ * Exits bold if caret is inside a bold element, otherwise starts a new bold element
1821
+ */
1822
+ toggleCollapsedSelection() {
1823
+ const t = window.getSelection();
1824
+ if (!t || t.rangeCount === 0)
1825
+ return;
1826
+ const e = t.getRangeAt(0), n = i.findBoldElement(e.startContainer), r = (() => {
1827
+ if (n && n.getAttribute(i.DATA_ATTR_COLLAPSED_ACTIVE) !== "true")
1828
+ return i.exitCollapsedBold(t, n);
1829
+ const s = n != null ? n : i.getBoundaryBold(e);
1830
+ return s ? i.exitCollapsedBold(t, s) : this.startCollapsedBold(e);
1831
+ })();
1832
+ document.dispatchEvent(new Event("selectionchange")), r && (t.removeAllRanges(), t.addRange(r)), i.normalizeBoldTagsWithinBlok(t), i.replaceNbspInBlock(t), i.removeEmptyBoldElements(t), this.notifySelectionChange();
1833
+ }
1834
+ /**
1835
+ * Insert a bold wrapper at the caret so newly typed text becomes bold
1836
+ * @param range - Current collapsed range
1837
+ */
1838
+ startCollapsedBold(t) {
1839
+ if (!t.collapsed)
1840
+ return;
1841
+ const e = document.createElement("strong"), n = document.createTextNode("");
1842
+ e.appendChild(n), e.setAttribute(i.DATA_ATTR_COLLAPSED_ACTIVE, "true");
1843
+ const r = t.startContainer, s = t.startOffset;
1844
+ if (!(r.nodeType === Node.TEXT_NODE ? this.insertCollapsedBoldIntoText(r, e, s) : r.nodeType === Node.ELEMENT_NODE ? (this.insertCollapsedBoldIntoElement(r, e, s), !0) : !1))
1845
+ return;
1846
+ const a = window.getSelection(), l = document.createRange();
1847
+ l.setStart(n, 0), l.collapse(!0);
1848
+ const d = this.mergeAdjacentBold(e);
1849
+ return i.normalizeBoldTagsWithinBlok(a), i.replaceNbspInBlock(a), i.removeEmptyBoldElements(a), a && (a.removeAllRanges(), a.addRange(l)), this.notifySelectionChange(), d.firstChild instanceof Text ? (() => {
1850
+ var h, p;
1851
+ const c = document.createRange();
1852
+ return c.setStart(d.firstChild, (p = (h = d.firstChild.textContent) == null ? void 0 : h.length) != null ? p : 0), c.collapse(!0), c;
1853
+ })() : l;
1854
+ }
1855
+ /**
1856
+ * Insert a collapsed bold wrapper when the caret resides inside a text node
1857
+ * @param text - Text node containing the caret
1858
+ * @param strong - Strong element to insert
1859
+ * @param offset - Caret offset within the text node
1860
+ * @returns true when insertion succeeded
1861
+ */
1862
+ insertCollapsedBoldIntoText(t, e, n) {
1863
+ var c;
1864
+ const r = t, s = r.parentNode;
1865
+ if (!s)
1866
+ return !1;
1867
+ const o = (c = r.textContent) != null ? c : "", a = o.slice(0, n), l = o.slice(n);
1868
+ r.textContent = a;
1869
+ const d = l.length ? document.createTextNode(l) : null;
1870
+ return d && s.insertBefore(d, r.nextSibling), s.insertBefore(e, d != null ? d : r.nextSibling), e.setAttribute(i.DATA_ATTR_PREV_LENGTH, a.length.toString()), !0;
1871
+ }
1872
+ /**
1873
+ * Insert a collapsed bold wrapper directly into an element container
1874
+ * @param element - Container element
1875
+ * @param strong - Strong element to insert
1876
+ * @param offset - Index at which to insert the strong element
1877
+ */
1878
+ insertCollapsedBoldIntoElement(t, e, n) {
1879
+ var s;
1880
+ const r = (s = t.childNodes[n]) != null ? s : null;
1881
+ t.insertBefore(e, r), e.setAttribute(i.DATA_ATTR_PREV_LENGTH, "0");
1882
+ }
1883
+ /**
1884
+ * Check if an element is empty (has no text content)
1885
+ * @param element - The element to check
1886
+ */
1887
+ static isElementEmpty(t) {
1888
+ var e;
1889
+ return ((e = t.textContent) != null ? e : "").length === 0;
1890
+ }
1891
+ /**
1892
+ *
1893
+ */
1894
+ notifySelectionChange() {
1895
+ i.enforceCollapsedBoldLengths(window.getSelection()), document.dispatchEvent(new Event("selectionchange")), this.updateToolbarButtonState();
1896
+ }
1897
+ /**
1898
+ * Ensure inline toolbar button reflects the actual bold state after programmatic toggles
1899
+ */
1900
+ updateToolbarButtonState() {
1901
+ const t = window.getSelection();
1902
+ if (!t)
1903
+ return;
1904
+ const e = t.anchorNode, n = (e == null ? void 0 : e.nodeType) === Node.ELEMENT_NODE ? e : e == null ? void 0 : e.parentElement, r = n == null ? void 0 : n.closest(A(g.editor));
1905
+ if (!r)
1906
+ return;
1907
+ const s = r.querySelector("[data-blok-testid=inline-toolbar]");
1908
+ if (!(s instanceof HTMLElement))
1909
+ return;
1910
+ const o = s.querySelector('[data-blok-item-name="bold"]');
1911
+ if (!(o instanceof HTMLElement))
1912
+ return;
1913
+ this.isSelectionVisuallyBold(t) ? o.setAttribute("data-blok-popover-item-active", "true") : o.removeAttribute("data-blok-popover-item-active");
1914
+ }
1915
+ /**
1916
+ * Normalize whitespace around a bold element
1917
+ * @param element - The bold element to normalize whitespace around
1918
+ */
1919
+ normalizeWhitespaceAround(t) {
1920
+ i.replaceNbspWithSpace(t.previousSibling), i.replaceNbspWithSpace(t.nextSibling);
1921
+ }
1922
+ /**
1923
+ * Replace non-breaking spaces with regular spaces in a text node
1924
+ * @param node - The text node to process
1925
+ */
1926
+ static replaceNbspWithSpace(t) {
1927
+ var r;
1928
+ if (!t || t.nodeType !== Node.TEXT_NODE)
1929
+ return;
1930
+ const e = t, n = (r = e.textContent) != null ? r : "";
1931
+ n.includes(" ") && (e.textContent = n.replace(/\u00A0/g, " "));
1932
+ }
1933
+ /**
1934
+ * Restore a selection range from marker elements
1935
+ * @param markerId - The ID of the markers used to mark the selection
1936
+ */
1937
+ restoreSelectionFromMarkers(t) {
1938
+ const e = document.querySelector(`[data-blok-bold-marker="${t}-start"]`), n = document.querySelector(`[data-blok-bold-marker="${t}-end"]`);
1939
+ if (!e || !n) {
1940
+ e == null || e.remove(), n == null || n.remove();
1941
+ return;
1942
+ }
1943
+ const r = window.getSelection();
1944
+ if (!r) {
1945
+ e.remove(), n.remove();
1946
+ return;
1947
+ }
1948
+ const s = document.createRange();
1949
+ return s.setStartAfter(e), s.setEndBefore(n), r.removeAllRanges(), r.addRange(s), e.remove(), n.remove(), s;
1950
+ }
1951
+ /**
1952
+ * Replace non-breaking spaces with regular spaces within a range
1953
+ * @param range - The range to process
1954
+ */
1955
+ replaceNbspWithinRange(t) {
1956
+ if (!t)
1957
+ return;
1958
+ const e = document.createTreeWalker(
1959
+ t.commonAncestorContainer,
1960
+ NodeFilter.SHOW_TEXT,
1961
+ {
1962
+ acceptNode: (n) => {
1963
+ try {
1964
+ return t.intersectsNode(n) ? NodeFilter.FILTER_ACCEPT : NodeFilter.FILTER_REJECT;
1965
+ } catch (r) {
1966
+ const s = document.createRange();
1967
+ s.selectNodeContents(n);
1968
+ const o = t.compareBoundaryPoints(Range.END_TO_START, s) > 0, a = t.compareBoundaryPoints(Range.START_TO_END, s) < 0;
1969
+ return o && a ? NodeFilter.FILTER_ACCEPT : NodeFilter.FILTER_REJECT;
1970
+ }
1971
+ }
1972
+ }
1973
+ );
1974
+ for (; e.nextNode(); )
1975
+ i.replaceNbspWithSpace(e.currentNode);
1976
+ }
1977
+ /**
1978
+ * Normalize all bold tags within the blok to <strong> tags
1979
+ * Converts any legacy <b> tags to <strong> tags
1980
+ * @param selection - The current selection to determine the blok context
1981
+ */
1982
+ static normalizeBoldTagsWithinBlok(t) {
1983
+ var s;
1984
+ const e = (s = t == null ? void 0 : t.anchorNode) != null ? s : t == null ? void 0 : t.focusNode;
1985
+ if (!e)
1986
+ return;
1987
+ const n = e.nodeType === Node.ELEMENT_NODE ? e : e.parentElement, r = n == null ? void 0 : n.closest(A(g.editor));
1988
+ r && r.querySelectorAll("b").forEach((o) => {
1989
+ i.ensureStrongElement(o);
1990
+ });
1991
+ }
1992
+ /**
1993
+ * Replace non-breaking spaces with regular spaces in the block containing the selection
1994
+ * @param selection - The current selection to determine the block context
1995
+ */
1996
+ static replaceNbspInBlock(t) {
1997
+ var o;
1998
+ const e = (o = t == null ? void 0 : t.anchorNode) != null ? o : t == null ? void 0 : t.focusNode;
1999
+ if (!e)
2000
+ return;
2001
+ const n = e.nodeType === Node.ELEMENT_NODE ? e : e.parentElement, r = n == null ? void 0 : n.closest('[data-blok-component="paragraph"]');
2002
+ if (!r)
2003
+ return;
2004
+ const s = document.createTreeWalker(r, NodeFilter.SHOW_TEXT);
2005
+ for (; s.nextNode(); )
2006
+ i.replaceNbspWithSpace(s.currentNode);
2007
+ r.querySelectorAll("b").forEach((a) => {
2008
+ i.ensureStrongElement(a);
2009
+ });
2010
+ }
2011
+ /**
2012
+ * Remove empty bold elements within the current block
2013
+ * @param selection - The current selection to determine the block context
2014
+ */
2015
+ static removeEmptyBoldElements(t) {
2016
+ var o, a;
2017
+ const e = (o = t == null ? void 0 : t.anchorNode) != null ? o : t == null ? void 0 : t.focusNode;
2018
+ if (!e)
2019
+ return;
2020
+ const n = e.nodeType === Node.ELEMENT_NODE ? e : e.parentElement, r = n == null ? void 0 : n.closest('[data-blok-component="paragraph"]');
2021
+ if (!r)
2022
+ return;
2023
+ const s = (a = t == null ? void 0 : t.focusNode) != null ? a : null;
2024
+ r.querySelectorAll("strong").forEach((l) => {
2025
+ var h;
2026
+ const d = l.getAttribute(i.DATA_ATTR_COLLAPSED_ACTIVE) === "true", c = l.hasAttribute(i.DATA_ATTR_COLLAPSED_LENGTH);
2027
+ d || c || ((h = l.textContent) != null ? h : "").length === 0 && !i.isNodeWithin(s, l) && l.remove();
2028
+ });
2029
+ }
2030
+ /**
2031
+ * Ensure collapsed bold placeholders absorb newly typed text
2032
+ * @param selection - The current selection to determine the blok context
2033
+ */
2034
+ static synchronizeCollapsedBold(t) {
2035
+ var o, a;
2036
+ const e = (o = t == null ? void 0 : t.anchorNode) != null ? o : t == null ? void 0 : t.focusNode, n = e && e.nodeType === Node.ELEMENT_NODE ? e : e == null ? void 0 : e.parentElement, r = (a = n == null ? void 0 : n.closest(A(g.editor))) != null ? a : n == null ? void 0 : n.ownerDocument;
2037
+ if (!r)
2038
+ return;
2039
+ const s = `strong[${i.DATA_ATTR_COLLAPSED_ACTIVE}="true"]`;
2040
+ r.querySelectorAll(s).forEach((l) => {
2041
+ var k, R, F, V, q;
2042
+ const d = l.getAttribute(i.DATA_ATTR_PREV_LENGTH), c = l.previousSibling;
2043
+ if (!d || !c || c.nodeType !== Node.TEXT_NODE)
2044
+ return;
2045
+ const h = Number(d);
2046
+ if (!Number.isFinite(h))
2047
+ return;
2048
+ const p = c, T = (k = p.textContent) != null ? k : "";
2049
+ if (T.length <= h)
2050
+ return;
2051
+ const y = T.slice(0, h), m = T.slice(h);
2052
+ p.textContent = y;
2053
+ const C = m.match(/^[\u00A0\s]+/);
2054
+ if (C && !l.hasAttribute(i.DATA_ATTR_LEADING_WHITESPACE) && l.setAttribute(i.DATA_ATTR_LEADING_WHITESPACE, C[0]), m.length === 0)
2055
+ return;
2056
+ const E = (R = l.textContent) != null ? R : "", N = E + m, B = (F = l.getAttribute(i.DATA_ATTR_LEADING_WHITESPACE)) != null ? F : "", v = B.length > 0 && E.length === 0 && !N.startsWith(B) ? B + N : N, b = document.createTextNode(v);
2057
+ for (; l.firstChild; )
2058
+ l.removeChild(l.firstChild);
2059
+ if (l.appendChild(b), !(t != null && t.isCollapsed) || !i.isNodeWithin(t.focusNode, p))
2060
+ return;
2061
+ const S = document.createRange(), _ = (q = (V = b.textContent) == null ? void 0 : V.length) != null ? q : 0;
2062
+ S.setStart(b, _), S.collapse(!0), t.removeAllRanges(), t.addRange(S);
2063
+ });
2064
+ }
2065
+ /**
2066
+ * Ensure caret is positioned after boundary bold elements when toggling collapsed selections
2067
+ * @param selection - Current selection
2068
+ */
2069
+ static moveCaretAfterBoundaryBold(t) {
2070
+ if (!t.rangeCount)
2071
+ return;
2072
+ const e = t.getRangeAt(0);
2073
+ if (!e.collapsed)
2074
+ return;
2075
+ const n = i.findBoldElement(e.startContainer);
2076
+ (n == null ? void 0 : n.getAttribute(i.DATA_ATTR_COLLAPSED_ACTIVE)) !== "true" && (i.moveCaretFromElementContainer(t, e) || i.moveCaretFromTextContainer(t, e));
2077
+ }
2078
+ /**
2079
+ * Locate a bold element adjacent to a collapsed range
2080
+ * @param range - Range to inspect
2081
+ */
2082
+ static getAdjacentBold(t) {
2083
+ const e = t.startContainer;
2084
+ return e.nodeType === Node.TEXT_NODE ? i.getBoldAdjacentToText(t, e) : e.nodeType === Node.ELEMENT_NODE ? i.getBoldAdjacentToElement(t, e) : null;
2085
+ }
2086
+ /**
2087
+ * Get bold element adjacent to a text node container
2088
+ * @param range - Current collapsed range
2089
+ * @param textNode - Text node hosting the caret
2090
+ */
2091
+ static getBoldAdjacentToText(t, e) {
2092
+ var o, a;
2093
+ const n = (a = (o = e.textContent) == null ? void 0 : o.length) != null ? a : 0, r = e.previousSibling;
2094
+ if (t.startOffset === 0 && i.isBoldElement(r))
2095
+ return r;
2096
+ if (t.startOffset !== n)
2097
+ return null;
2098
+ const s = e.nextSibling;
2099
+ return i.isBoldElement(s) ? s : null;
2100
+ }
2101
+ /**
2102
+ * Get bold element adjacent to an element container
2103
+ * @param range - Current collapsed range
2104
+ * @param element - Element containing the caret
2105
+ */
2106
+ static getBoldAdjacentToElement(t, e) {
2107
+ var s, o;
2108
+ const n = t.startOffset > 0 && (s = e.childNodes[t.startOffset - 1]) != null ? s : null;
2109
+ if (i.isBoldElement(n))
2110
+ return n;
2111
+ const r = (o = e.childNodes[t.startOffset]) != null ? o : null;
2112
+ return i.isBoldElement(r) ? r : null;
2113
+ }
2114
+ /**
2115
+ * Exit collapsed bold state when caret no longer resides within bold content
2116
+ * @param selection - Current selection
2117
+ * @param range - Collapsed range after toggling bold
2118
+ */
2119
+ static exitCollapsedIfNeeded(t, e) {
2120
+ var o;
2121
+ if (!!i.findBoldElement(e.startContainer))
2122
+ return;
2123
+ const r = (o = i.getBoundaryBold(e)) != null ? o : i.getAdjacentBold(e);
2124
+ if (!r)
2125
+ return;
2126
+ const s = i.exitCollapsedBold(t, r);
2127
+ s && (t.removeAllRanges(), t.addRange(s));
2128
+ }
2129
+ /**
2130
+ * Adjust caret when selection container is an element adjacent to bold content
2131
+ * @param selection - Current selection
2132
+ * @param range - Collapsed range to inspect
2133
+ * @returns true when caret position was updated
2134
+ */
2135
+ static moveCaretFromElementContainer(t, e) {
2136
+ if (e.startContainer.nodeType !== Node.ELEMENT_NODE)
2137
+ return !1;
2138
+ const n = e.startContainer;
2139
+ return i.moveCaretAfterPreviousBold(t, n, e.startOffset) ? !0 : i.moveCaretBeforeNextBold(t, n, e.startOffset);
2140
+ }
2141
+ /**
2142
+ * Move caret after the bold node that precedes the caret when possible
2143
+ * @param selection - Current selection
2144
+ * @param element - Container element
2145
+ * @param offset - Caret offset within the container
2146
+ */
2147
+ static moveCaretAfterPreviousBold(t, e, n) {
2148
+ var a, l, d;
2149
+ const r = n > 0 && (a = e.childNodes[n - 1]) != null ? a : null;
2150
+ if (!i.isBoldElement(r))
2151
+ return !1;
2152
+ const s = i.ensureFollowingTextNode(r, r.nextSibling);
2153
+ if (!s)
2154
+ return !1;
2155
+ const o = (d = (l = s.textContent) == null ? void 0 : l.length) != null ? d : 0;
2156
+ return i.setCaret(t, s, o), !0;
2157
+ }
2158
+ /**
2159
+ * Move caret before the bold node that follows the caret, ensuring there's a text node to receive input
2160
+ * @param selection - Current selection
2161
+ * @param element - Container element
2162
+ * @param offset - Caret offset within the container
2163
+ */
2164
+ static moveCaretBeforeNextBold(t, e, n) {
2165
+ var o;
2166
+ const r = (o = e.childNodes[n]) != null ? o : null;
2167
+ if (!i.isBoldElement(r))
2168
+ return !1;
2169
+ const s = i.ensureFollowingTextNode(r, r.nextSibling);
2170
+ return s ? (i.setCaret(t, s, 0), !0) : (i.setCaretAfterNode(t, r), !0);
2171
+ }
2172
+ /**
2173
+ * Adjust caret when selection container is a text node adjacent to bold content
2174
+ * @param selection - Current selection
2175
+ * @param range - Collapsed range to inspect
2176
+ */
2177
+ static moveCaretFromTextContainer(t, e) {
2178
+ var d, c, h;
2179
+ if (e.startContainer.nodeType !== Node.TEXT_NODE)
2180
+ return;
2181
+ const n = e.startContainer, r = n.previousSibling, s = (d = n.textContent) != null ? d : "", o = /^\s/.test(s);
2182
+ if (e.startOffset === 0 && i.isBoldElement(r) && (s.length === 0 || o)) {
2183
+ i.setCaret(t, n, s.length);
2184
+ return;
2185
+ }
2186
+ const a = i.findBoldElement(n);
2187
+ if (!a || e.startOffset !== ((h = (c = n.textContent) == null ? void 0 : c.length) != null ? h : 0))
2188
+ return;
2189
+ const l = i.ensureFollowingTextNode(a, a.nextSibling);
2190
+ if (l) {
2191
+ i.setCaret(t, l, 0);
2192
+ return;
2193
+ }
2194
+ i.setCaretAfterNode(t, a);
2195
+ }
2196
+ /**
2197
+ * Ensure caret is positioned at the end of a collapsed boundary text node before the browser processes a printable keydown
2198
+ * @param event - Keydown event fired before browser input handling
2199
+ */
2200
+ static guardCollapsedBoundaryKeydown(t) {
2201
+ var l;
2202
+ if (t.defaultPrevented || t.metaKey || t.ctrlKey || t.altKey || t.key.length !== 1)
2203
+ return;
2204
+ const n = window.getSelection();
2205
+ if (!n || !n.isCollapsed || n.rangeCount === 0)
2206
+ return;
2207
+ const r = n.getRangeAt(0);
2208
+ if (r.startContainer.nodeType !== Node.TEXT_NODE)
2209
+ return;
2210
+ const s = r.startContainer, o = (l = s.textContent) != null ? l : "";
2211
+ if (o.length === 0 || r.startOffset !== 0)
2212
+ return;
2213
+ const a = s.previousSibling;
2214
+ i.isBoldElement(a) && /^\s/.test(o) && i.setCaret(n, s, o.length);
2215
+ }
2216
+ /**
2217
+ * Determine whether a node is a bold element (<strong>/<b>)
2218
+ * @param node - Node to inspect
2219
+ */
2220
+ static isBoldElement(t) {
2221
+ return !!(t && t.nodeType === Node.ELEMENT_NODE && i.isBoldTag(t));
2222
+ }
2223
+ /**
2224
+ * Place caret at the provided offset within a text node
2225
+ * @param selection - Current selection
2226
+ * @param node - Target text node
2227
+ * @param offset - Offset within the text node
2228
+ */
2229
+ static setCaret(t, e, n) {
2230
+ const r = document.createRange();
2231
+ r.setStart(e, n), r.collapse(!0), t.removeAllRanges(), t.addRange(r);
2232
+ }
2233
+ /**
2234
+ * Position caret immediately after the provided node
2235
+ * @param selection - Current selection
2236
+ * @param node - Reference node
2237
+ */
2238
+ static setCaretAfterNode(t, e) {
2239
+ if (!e)
2240
+ return;
2241
+ const n = document.createRange();
2242
+ n.setStartAfter(e), n.collapse(!0), t.removeAllRanges(), t.addRange(n);
2243
+ }
2244
+ /**
2245
+ * Ensure there is a text node immediately following a bold element to accept new input
2246
+ * @param boldElement - Bold element after which text should be inserted
2247
+ * @param referenceNode - Node that currently follows the bold element
2248
+ */
2249
+ static ensureFollowingTextNode(t, e) {
2250
+ const n = t.parentNode;
2251
+ if (!n)
2252
+ return null;
2253
+ if (e && e.nodeType === Node.TEXT_NODE)
2254
+ return e;
2255
+ const r = document.createTextNode("");
2256
+ return n.insertBefore(r, e), r;
2257
+ }
2258
+ /**
2259
+ * Enforce length limits on collapsed bold elements
2260
+ * @param selection - The current selection to determine the blok context
2261
+ */
2262
+ static enforceCollapsedBoldLengths(t) {
2263
+ var o;
2264
+ const e = (o = t == null ? void 0 : t.anchorNode) != null ? o : t == null ? void 0 : t.focusNode;
2265
+ if (!e)
2266
+ return;
2267
+ const n = e.nodeType === Node.ELEMENT_NODE ? e : e.parentElement, r = n == null ? void 0 : n.closest(A(g.editor));
2268
+ if (!r)
2269
+ return;
2270
+ r.querySelectorAll(`strong[${i.DATA_ATTR_COLLAPSED_LENGTH}]`).forEach((a) => {
2271
+ var x, v, b, S, _;
2272
+ const l = a, d = l.getAttribute(i.DATA_ATTR_COLLAPSED_LENGTH);
2273
+ if (!d)
2274
+ return;
2275
+ const c = Number(d), h = (x = l.textContent) != null ? x : "";
2276
+ if (!Number.isFinite(c))
2277
+ return;
2278
+ const p = h.length > c, T = p ? i.splitCollapsedBoldText(l, c, h) : null, y = l.getAttribute(i.DATA_ATTR_PREV_LENGTH), m = y ? Number(y) : NaN, C = l.previousSibling, E = (C == null ? void 0 : C.nodeType) === Node.TEXT_NODE ? C : null, N = (v = E == null ? void 0 : E.textContent) != null ? v : "", B = !!(y && Number.isFinite(m) && E && N.length > m);
2279
+ if (B && E) {
2280
+ const k = N.slice(0, m), R = N.slice(m);
2281
+ E.textContent = k;
2282
+ const F = document.createTextNode(R);
2283
+ (b = l.parentNode) == null || b.insertBefore(F, l.nextSibling);
2284
+ }
2285
+ if (B && l.removeAttribute(i.DATA_ATTR_PREV_LENGTH), t != null && t.isCollapsed && T && i.isNodeWithin(t.focusNode, l)) {
2286
+ const k = document.createRange(), R = (_ = (S = T.textContent) == null ? void 0 : S.length) != null ? _ : 0;
2287
+ k.setStart(T, R), k.collapse(!0), t.removeAllRanges(), t.addRange(k);
2288
+ }
2289
+ p && l.removeAttribute(i.DATA_ATTR_COLLAPSED_LENGTH);
2290
+ });
2291
+ }
2292
+ /**
2293
+ * Split text content exceeding the allowed collapsed bold length and move the excess outside
2294
+ * @param boldEl - Bold element hosting the collapsed selection
2295
+ * @param allowedLength - Maximum allowed length for the collapsed bold
2296
+ * @param currentText - Current text content inside the bold element
2297
+ */
2298
+ static splitCollapsedBoldText(t, e, n) {
2299
+ const r = t, s = r.parentNode;
2300
+ if (!s)
2301
+ return null;
2302
+ const o = n.slice(0, e), a = n.slice(e);
2303
+ r.textContent = o;
2304
+ const l = document.createTextNode(a);
2305
+ return s.insertBefore(l, r.nextSibling), l;
2306
+ }
2307
+ /**
2308
+ * Check if a node is within the provided container
2309
+ * @param target - Node to test
2310
+ * @param container - Potential ancestor container
2311
+ */
2312
+ static isNodeWithin(t, e) {
2313
+ return t ? t === e || e.contains(t) : !1;
2314
+ }
2315
+ /**
2316
+ *
2317
+ */
2318
+ static handleGlobalSelectionChange() {
2319
+ i.refreshSelectionState("selectionchange");
2320
+ }
2321
+ /**
2322
+ *
2323
+ */
2324
+ static handleGlobalInput() {
2325
+ i.refreshSelectionState("input");
2326
+ }
2327
+ /**
2328
+ * Normalize selection state after blok input or selection updates
2329
+ * @param source - The event source triggering the refresh
2330
+ */
2331
+ static refreshSelectionState(t) {
2332
+ const e = window.getSelection();
2333
+ i.enforceCollapsedBoldLengths(e), i.maintainCollapsedExitState(), i.synchronizeCollapsedBold(e), i.normalizeBoldTagsWithinBlok(e), i.removeEmptyBoldElements(e), t === "input" && e && i.moveCaretAfterBoundaryBold(e), i.normalizeAllBoldTags();
2334
+ }
2335
+ /**
2336
+ * Ensure mutation observer is registered to convert legacy <b> tags
2337
+ */
2338
+ static ensureMutationObserver() {
2339
+ if (typeof MutationObserver == "undefined" || i.mutationObserver)
2340
+ return;
2341
+ const t = new MutationObserver((e) => {
2342
+ if (!i.isProcessingMutation) {
2343
+ i.isProcessingMutation = !0;
2344
+ try {
2345
+ e.forEach((n) => {
2346
+ n.addedNodes.forEach((r) => {
2347
+ i.normalizeBoldInNode(r);
2348
+ }), n.type === "characterData" && n.target && i.normalizeBoldInNode(n.target);
2349
+ });
2350
+ } finally {
2351
+ i.isProcessingMutation = !1;
2352
+ }
2353
+ }
2354
+ });
2355
+ t.observe(document.body, {
2356
+ subtree: !0,
2357
+ childList: !0,
2358
+ characterData: !0
2359
+ }), i.mutationObserver = t;
2360
+ }
2361
+ /**
2362
+ * Prevent the browser's native bold command to avoid <b> wrappers
2363
+ * @param event - BeforeInput event fired by the browser
2364
+ */
2365
+ static handleBeforeInput(t) {
2366
+ if (t.inputType !== "formatBold")
2367
+ return;
2368
+ const e = window.getSelection(), n = !!(e && i.isSelectionInsideBlok(e)), r = i.isEventTargetInsideBlok(t.target);
2369
+ !n && !r || (t.preventDefault(), t.stopPropagation(), t.stopImmediatePropagation(), i.normalizeAllBoldTags());
2370
+ }
2371
+ /**
2372
+ * Attempt to toggle bold via the browser's native command
2373
+ * @param selection - Current selection
2374
+ */
2375
+ /**
2376
+ * Exit a collapsed bold selection by moving the caret outside the bold element
2377
+ * @param selection - The current selection
2378
+ * @param boldElement - The bold element to exit from
2379
+ */
2380
+ static exitCollapsedBold(t, e) {
2381
+ const n = i.ensureStrongElement(e), r = n.parentNode;
2382
+ if (r)
2383
+ return i.isElementEmpty(n) ? i.removeEmptyBoldElement(t, n, r) : i.exitCollapsedBoldWithContent(t, n, r);
2384
+ }
2385
+ /**
2386
+ * Remove an empty bold element and place the caret before its position
2387
+ * @param selection - Current selection
2388
+ * @param boldElement - Bold element to remove
2389
+ * @param parent - Parent node that hosts the bold element
2390
+ */
2391
+ static removeEmptyBoldElement(t, e, n) {
2392
+ const r = document.createRange();
2393
+ return r.setStartBefore(e), r.collapse(!0), n.removeChild(e), t.removeAllRanges(), t.addRange(r), r;
2394
+ }
2395
+ /**
2396
+ * Exit a collapsed bold state when the bold element still contains text
2397
+ * @param selection - Current selection
2398
+ * @param boldElement - Bold element currently wrapping the caret
2399
+ * @param parent - Parent node that hosts the bold element
2400
+ */
2401
+ static exitCollapsedBoldWithContent(t, e, n) {
2402
+ var p, T, y, m, C, E;
2403
+ e.setAttribute(i.DATA_ATTR_COLLAPSED_LENGTH, ((T = (p = e.textContent) == null ? void 0 : p.length) != null ? T : 0).toString()), e.removeAttribute(i.DATA_ATTR_PREV_LENGTH), e.removeAttribute(i.DATA_ATTR_COLLAPSED_ACTIVE), e.removeAttribute(i.DATA_ATTR_LEADING_WHITESPACE);
2404
+ const r = e.nextSibling, s = !r || r.nodeType !== Node.TEXT_NODE, o = s ? document.createTextNode("​") : null;
2405
+ o && n.insertBefore(o, r);
2406
+ const a = o != null ? o : r;
2407
+ !s && ((y = a.textContent) != null ? y : "").length === 0 && (a.textContent = "​");
2408
+ const l = document.createRange(), c = ((m = a.textContent) != null ? m : "").startsWith("​") ? 1 : 0;
2409
+ l.setStart(a, c), l.collapse(!0), t.removeAllRanges(), t.addRange(l);
2410
+ const h = i.ensureStrongElement(e);
2411
+ return i.collapsedExitRecords.add({
2412
+ boundary: a,
2413
+ boldElement: h,
2414
+ allowedLength: (E = (C = h.textContent) == null ? void 0 : C.length) != null ? E : 0,
2415
+ hasLeadingSpace: !1,
2416
+ hasTypedContent: !1,
2417
+ leadingWhitespace: ""
2418
+ }), l;
2419
+ }
2420
+ /**
2421
+ * Get a bold element at the boundary of a collapsed range
2422
+ * @param range - The collapsed range to check
2423
+ */
2424
+ static getBoundaryBold(t) {
2425
+ const e = t.startContainer;
2426
+ return e.nodeType === Node.TEXT_NODE ? i.getBoundaryBoldForText(t, e) : e.nodeType === Node.ELEMENT_NODE ? i.getBoundaryBoldForElement(t, e) : null;
2427
+ }
2428
+ /**
2429
+ * Get boundary bold when caret resides inside a text node
2430
+ * @param range - Collapsed range
2431
+ * @param textNode - Text container
2432
+ */
2433
+ static getBoundaryBoldForText(t, e) {
2434
+ var s, o;
2435
+ const n = (o = (s = e.textContent) == null ? void 0 : s.length) != null ? o : 0;
2436
+ if (t.startOffset === n)
2437
+ return i.findBoldElement(e);
2438
+ if (t.startOffset !== 0)
2439
+ return null;
2440
+ const r = e.previousSibling;
2441
+ return i.isBoldElement(r) ? r : null;
2442
+ }
2443
+ /**
2444
+ * Get boundary bold when caret container is an element
2445
+ * @param range - Collapsed range
2446
+ * @param element - Element container
2447
+ */
2448
+ static getBoundaryBoldForElement(t, e) {
2449
+ if (t.startOffset <= 0)
2450
+ return null;
2451
+ const n = e.childNodes[t.startOffset - 1];
2452
+ return i.isBoldElement(n) ? n : null;
2453
+ }
2454
+ /**
2455
+ * Handle keyboard shortcut for bold when selection is collapsed
2456
+ * @param event - The keyboard event
2457
+ */
2458
+ static handleShortcut(t) {
2459
+ var r;
2460
+ if (i.guardCollapsedBoundaryKeydown(t), !i.isBoldShortcut(t))
2461
+ return;
2462
+ const e = window.getSelection();
2463
+ if (!e || !e.rangeCount || !i.isSelectionInsideBlok(e))
2464
+ return;
2465
+ const n = (r = i.instances.values().next().value) != null ? r : new i();
2466
+ n && (t.preventDefault(), t.stopPropagation(), t.stopImmediatePropagation(), n.toggleBold());
2467
+ }
2468
+ /**
2469
+ * Check if a keyboard event is the bold shortcut (Cmd/Ctrl+B)
2470
+ * @param event - The keyboard event to check
2471
+ */
2472
+ static isBoldShortcut(t) {
2473
+ return !((typeof navigator != "undefined" ? navigator.userAgent.toLowerCase() : "").includes("mac") ? t.metaKey : t.ctrlKey) || t.altKey ? !1 : t.key.toLowerCase() === "b";
2474
+ }
2475
+ /**
2476
+ * Check if a selection is inside the blok
2477
+ * @param selection - The selection to check
2478
+ */
2479
+ static isSelectionInsideBlok(t) {
2480
+ const e = t.anchorNode;
2481
+ if (!e)
2482
+ return !1;
2483
+ const n = e.nodeType === Node.ELEMENT_NODE ? e : e.parentElement;
2484
+ return !!(n != null && n.closest(A(g.editor)));
2485
+ }
2486
+ /**
2487
+ * Check if an event target resides inside the blok wrapper
2488
+ * @param target - Event target to inspect
2489
+ */
2490
+ static isEventTargetInsideBlok(t) {
2491
+ var n;
2492
+ if (!t || typeof Node == "undefined")
2493
+ return !1;
2494
+ if (t instanceof Element)
2495
+ return !!t.closest(A(g.editor));
2496
+ if (t instanceof Text)
2497
+ return !!((n = t.parentElement) != null && n.closest(A(g.editor)));
2498
+ if (typeof ShadowRoot != "undefined" && t instanceof ShadowRoot)
2499
+ return i.isEventTargetInsideBlok(t.host);
2500
+ if (!(t instanceof Node))
2501
+ return !1;
2502
+ const e = t.parentNode;
2503
+ return e ? e instanceof Element ? !!e.closest(A(g.editor)) : i.isEventTargetInsideBlok(e) : !1;
2504
+ }
2505
+ /**
2506
+ * Get HTML content of a range with bold tags removed
2507
+ * @param range - The range to extract HTML from
2508
+ */
2509
+ getRangeHtmlWithoutBold(t) {
2510
+ const e = t.cloneContents();
2511
+ this.removeNestedBold(e);
2512
+ const n = document.createElement("div");
2513
+ return n.appendChild(e), n.innerHTML;
2514
+ }
2515
+ /**
2516
+ * Convert an HTML snippet to a document fragment
2517
+ * @param html - HTML string to convert
2518
+ */
2519
+ static createFragmentFromHtml(t) {
2520
+ const e = document.createElement("template");
2521
+ return e.innerHTML = t, e.content;
2522
+ }
2523
+ /**
2524
+ * Collect all bold ancestor elements within a range
2525
+ * @param range - The range to search for bold ancestors
2526
+ */
2527
+ collectBoldAncestors(t) {
2528
+ const e = /* @__PURE__ */ new Set(), n = document.createTreeWalker(
2529
+ t.commonAncestorContainer,
2530
+ NodeFilter.SHOW_TEXT,
2531
+ {
2532
+ acceptNode: (r) => {
2533
+ try {
2534
+ return t.intersectsNode(r) ? NodeFilter.FILTER_ACCEPT : NodeFilter.FILTER_REJECT;
2535
+ } catch (s) {
2536
+ const o = document.createRange();
2537
+ o.selectNodeContents(r);
2538
+ const a = t.compareBoundaryPoints(Range.END_TO_START, o) > 0, l = t.compareBoundaryPoints(Range.START_TO_END, o) < 0;
2539
+ return a && l ? NodeFilter.FILTER_ACCEPT : NodeFilter.FILTER_REJECT;
2540
+ }
2541
+ }
2542
+ }
2543
+ );
2544
+ for (; n.nextNode(); ) {
2545
+ const r = i.findBoldElement(n.currentNode);
2546
+ r && e.add(r);
2547
+ }
2548
+ return Array.from(e);
2549
+ }
2550
+ };
2551
+ i.isInline = !0, i.title = "Bold", i.titleKey = "bold", i.shortcutListenerRegistered = !1, i.selectionListenerRegistered = !1, i.inputListenerRegistered = !1, i.beforeInputListenerRegistered = !1, i.globalListenersInitialized = i.initializeGlobalListeners(), i.collapsedExitRecords = /* @__PURE__ */ new Set(), i.markerSequence = 0, i.isProcessingMutation = !1, i.DATA_ATTR_COLLAPSED_LENGTH = "data-blok-bold-collapsed-length", i.DATA_ATTR_COLLAPSED_ACTIVE = "data-blok-bold-collapsed-active", i.DATA_ATTR_PREV_LENGTH = "data-blok-bold-prev-length", i.DATA_ATTR_LEADING_WHITESPACE = "data-blok-bold-leading-ws", i.instances = /* @__PURE__ */ new Set(), i.pendingBoundaryCaretAdjustments = /* @__PURE__ */ new WeakSet(), i.shortcut = "CMD+B";
2552
+ let Z = i;
2553
+ const O = class O {
2554
+ /**
2555
+ * Sanitizer Rule
2556
+ * Leave <i> and <em> tags
2557
+ * @returns {object}
2558
+ */
2559
+ static get sanitize() {
2560
+ return {
2561
+ i: {},
2562
+ em: {}
2563
+ };
2564
+ }
2565
+ /**
2566
+ * Create button for Inline Toolbar
2567
+ */
2568
+ render() {
2569
+ return {
2570
+ icon: mt,
2571
+ name: "italic",
2572
+ onActivate: () => {
2573
+ this.toggleItalic();
2574
+ },
2575
+ isActive: () => {
2576
+ const t = window.getSelection();
2577
+ return t ? this.isSelectionVisuallyItalic(t) : !1;
2578
+ }
2579
+ };
2580
+ }
2581
+ /**
2582
+ * Apply or remove italic formatting using modern Selection API
2583
+ */
2584
+ toggleItalic() {
2585
+ const t = window.getSelection();
2586
+ if (!t || t.rangeCount === 0)
2587
+ return;
2588
+ const e = t.getRangeAt(0);
2589
+ if (e.collapsed) {
2590
+ this.toggleCollapsedItalic(e, t);
2591
+ return;
2592
+ }
2593
+ this.isRangeItalic(e, { ignoreWhitespace: !0 }) ? this.unwrapItalicTags(e) : this.wrapWithItalic(e);
2594
+ }
2595
+ /**
2596
+ * Handle toggle for collapsed selection (caret)
2597
+ * @param range - Current range
2598
+ * @param selection - Current selection
2599
+ */
2600
+ toggleCollapsedItalic(t, e) {
2601
+ if (this.isRangeItalic(t, { ignoreWhitespace: !0 })) {
2602
+ const r = document.createTextNode("​");
2603
+ t.insertNode(r), t.selectNode(r), this.unwrapItalicTags(t);
2604
+ const s = document.createRange();
2605
+ s.setStart(r, 1), s.setEnd(r, 1), e.removeAllRanges(), e.addRange(s);
2606
+ } else {
2607
+ const r = document.createElement("i"), s = document.createTextNode("​");
2608
+ r.appendChild(s), t.insertNode(r);
2609
+ const o = document.createRange();
2610
+ o.setStart(s, 1), o.setEnd(s, 1), e.removeAllRanges(), e.addRange(o);
2611
+ }
2612
+ }
2613
+ /**
2614
+ * Check if current selection is within an italic tag
2615
+ * @param selection - The Selection object to check
2616
+ */
2617
+ isSelectionVisuallyItalic(t) {
2618
+ if (!t || t.rangeCount === 0)
2619
+ return !1;
2620
+ const e = t.getRangeAt(0);
2621
+ return this.isRangeItalic(e, { ignoreWhitespace: !0 });
2622
+ }
2623
+ /**
2624
+ * Check if a range contains italic text
2625
+ * @param range - The range to check
2626
+ * @param options - Options for checking italic status
2627
+ */
2628
+ isRangeItalic(t, e) {
2629
+ var s;
2630
+ if (t.collapsed)
2631
+ return !!this.findItalicElement(t.startContainer);
2632
+ const n = document.createTreeWalker(
2633
+ t.commonAncestorContainer,
2634
+ NodeFilter.SHOW_TEXT,
2635
+ {
2636
+ acceptNode: (o) => {
2637
+ try {
2638
+ return t.intersectsNode(o) ? NodeFilter.FILTER_ACCEPT : NodeFilter.FILTER_REJECT;
2639
+ } catch (a) {
2640
+ const l = document.createRange();
2641
+ l.selectNodeContents(o);
2642
+ const d = t.compareBoundaryPoints(Range.END_TO_START, l) > 0, c = t.compareBoundaryPoints(Range.START_TO_END, l) < 0;
2643
+ return d && c ? NodeFilter.FILTER_ACCEPT : NodeFilter.FILTER_REJECT;
2644
+ }
2645
+ }
2646
+ }
2647
+ ), r = [];
2648
+ for (; n.nextNode(); ) {
2649
+ const o = n.currentNode, a = (s = o.textContent) != null ? s : "";
2650
+ e.ignoreWhitespace && a.trim().length === 0 || a.length !== 0 && r.push(o);
2651
+ }
2652
+ return r.length === 0 ? !!this.findItalicElement(t.startContainer) : r.every((o) => this.hasItalicParent(o));
2653
+ }
2654
+ /**
2655
+ * Wrap selection with <i> tag
2656
+ * @param range - The Range object containing the selection to wrap
2657
+ */
2658
+ wrapWithItalic(t) {
2659
+ const e = this.getRangeHtmlWithoutItalic(t), n = this.replaceRangeWithHtml(t, `<i>${e}</i>`), r = window.getSelection();
2660
+ r && n && (r.removeAllRanges(), r.addRange(n));
2661
+ }
2662
+ /**
2663
+ * Remove italic tags (<i>/<em>) while preserving content
2664
+ * @param range - The Range object containing the selection to unwrap
2665
+ */
2666
+ unwrapItalicTags(t) {
2667
+ const e = this.collectItalicAncestors(t), n = window.getSelection();
2668
+ if (!n)
2669
+ return;
2670
+ const r = document.createElement("span"), s = t.extractContents();
2671
+ r.appendChild(s), this.removeNestedItalic(r), t.insertNode(r);
2672
+ const o = document.createRange();
2673
+ for (o.selectNodeContents(r), n.removeAllRanges(), n.addRange(o); ; ) {
2674
+ const c = this.findItalicElement(r);
2675
+ if (!c)
2676
+ break;
2677
+ this.moveMarkerOutOfItalic(r, c);
2678
+ }
2679
+ const a = r.firstChild, l = r.lastChild;
2680
+ this.unwrapElement(r), (a && l ? (() => {
2681
+ const c = document.createRange();
2682
+ return c.setStartBefore(a), c.setEndAfter(l), n.removeAllRanges(), n.addRange(c), c;
2683
+ })() : void 0) || n.removeAllRanges(), e.forEach((c) => {
2684
+ var h;
2685
+ ((h = c.textContent) != null ? h : "").length === 0 && c.remove();
2686
+ });
2687
+ }
2688
+ /**
2689
+ * Check if a node or any of its parents is an italic tag
2690
+ * @param node - The node to check
2691
+ */
2692
+ hasItalicParent(t) {
2693
+ return t ? t.nodeType === Node.ELEMENT_NODE && this.isItalicTag(t) ? !0 : this.hasItalicParent(t.parentNode) : !1;
2694
+ }
2695
+ /**
2696
+ * Find an italic element in the parent chain
2697
+ * @param node - The node to start searching from
2698
+ */
2699
+ findItalicElement(t) {
2700
+ return t ? t.nodeType === Node.ELEMENT_NODE && this.isItalicTag(t) ? t : this.findItalicElement(t.parentNode) : null;
2701
+ }
2702
+ /**
2703
+ * Check if an element is an italic tag (<i> or <em>)
2704
+ * @param node - The element to check
2705
+ */
2706
+ isItalicTag(t) {
2707
+ const e = t.tagName;
2708
+ return e === "I" || e === "EM";
2709
+ }
2710
+ /**
2711
+ * Collect all italic ancestor elements within a range
2712
+ * @param range - The range to search for italic ancestors
2713
+ */
2714
+ collectItalicAncestors(t) {
2715
+ const e = /* @__PURE__ */ new Set(), n = document.createTreeWalker(
2716
+ t.commonAncestorContainer,
2717
+ NodeFilter.SHOW_TEXT,
2718
+ {
2719
+ acceptNode: (r) => {
2720
+ try {
2721
+ return t.intersectsNode(r) ? NodeFilter.FILTER_ACCEPT : NodeFilter.FILTER_REJECT;
2722
+ } catch (s) {
2723
+ const o = document.createRange();
2724
+ o.selectNodeContents(r);
2725
+ const a = t.compareBoundaryPoints(Range.END_TO_START, o) > 0, l = t.compareBoundaryPoints(Range.START_TO_END, o) < 0;
2726
+ return a && l ? NodeFilter.FILTER_ACCEPT : NodeFilter.FILTER_REJECT;
2727
+ }
2728
+ }
2729
+ }
2730
+ );
2731
+ for (; n.nextNode(); ) {
2732
+ const r = this.findItalicElement(n.currentNode);
2733
+ r && e.add(r);
2734
+ }
2735
+ return Array.from(e);
2736
+ }
2737
+ /**
2738
+ * Get HTML content of a range with italic tags removed
2739
+ * @param range - The range to extract HTML from
2740
+ */
2741
+ getRangeHtmlWithoutItalic(t) {
2742
+ const e = t.cloneContents();
2743
+ this.removeNestedItalic(e);
2744
+ const n = document.createElement("div");
2745
+ return n.appendChild(e), n.innerHTML;
2746
+ }
2747
+ /**
2748
+ * Remove nested italic tags from a root node
2749
+ * @param root - The root node to process
2750
+ */
2751
+ removeNestedItalic(t) {
2752
+ var n;
2753
+ const e = (n = t.querySelectorAll) == null ? void 0 : n.call(t, "i,em");
2754
+ e && e.forEach((r) => {
2755
+ this.unwrapElement(r);
2756
+ });
2757
+ }
2758
+ /**
2759
+ * Unwrap an element by moving its children to the parent
2760
+ * @param element - The element to unwrap
2761
+ */
2762
+ unwrapElement(t) {
2763
+ const e = t.parentNode;
2764
+ if (!e) {
2765
+ t.remove();
2766
+ return;
2767
+ }
2768
+ for (; t.firstChild; )
2769
+ e.insertBefore(t.firstChild, t);
2770
+ e.removeChild(t);
2771
+ }
2772
+ /**
2773
+ * Replace the current range contents with provided HTML snippet
2774
+ * @param range - Range to replace
2775
+ * @param html - HTML string to insert
2776
+ */
2777
+ replaceRangeWithHtml(t, e) {
2778
+ var a, l;
2779
+ const n = this.createFragmentFromHtml(e), r = (a = n.firstChild) != null ? a : null, s = (l = n.lastChild) != null ? l : null;
2780
+ if (t.deleteContents(), !r || !s)
2781
+ return;
2782
+ t.insertNode(n);
2783
+ const o = document.createRange();
2784
+ return o.setStartBefore(r), o.setEndAfter(s), o;
2785
+ }
2786
+ /**
2787
+ * Convert an HTML snippet to a document fragment
2788
+ * @param html - HTML string to convert
2789
+ */
2790
+ createFragmentFromHtml(t) {
2791
+ const e = document.createElement("template");
2792
+ return e.innerHTML = t, e.content;
2793
+ }
2794
+ /**
2795
+ * Move a temporary marker element outside of an italic ancestor while preserving content order
2796
+ * @param marker - Marker element wrapping the selection contents
2797
+ * @param italicElement - Italic ancestor containing the marker
2798
+ */
2799
+ moveMarkerOutOfItalic(t, e) {
2800
+ const n = e.parentNode;
2801
+ if (!n)
2802
+ return;
2803
+ if (Array.from(e.childNodes).forEach((l) => {
2804
+ var d;
2805
+ l.nodeType === Node.TEXT_NODE && ((d = l.textContent) != null ? d : "").length === 0 && l.remove();
2806
+ }), e.childNodes.length === 1 && e.firstChild === t) {
2807
+ e.replaceWith(t);
2808
+ return;
2809
+ }
2810
+ if (e.firstChild === t) {
2811
+ n.insertBefore(t, e);
2812
+ return;
2813
+ }
2814
+ if (e.lastChild === t) {
2815
+ n.insertBefore(t, e.nextSibling);
2816
+ return;
2817
+ }
2818
+ const a = e.cloneNode(!1);
2819
+ for (; t.nextSibling; )
2820
+ a.appendChild(t.nextSibling);
2821
+ n.insertBefore(a, e.nextSibling), n.insertBefore(t, a);
2822
+ }
2823
+ };
2824
+ O.isInline = !0, O.title = "Italic", O.titleKey = "italic", O.shortcut = "CMD+I";
2825
+ let Q = O;
2826
+ const D = class D {
2827
+ /**
2828
+ * @param api - Blok API
2829
+ */
2830
+ constructor({ api: t }) {
2831
+ this.INPUT_BASE_CLASSES = "hidden w-full m-0 px-2 py-1 text-sm leading-[22px] font-medium bg-item-hover-bg border border-[rgba(226,226,229,0.2)] rounded-md outline-none box-border appearance-none font-[inherit] placeholder:text-gray-text mobile:text-[15px] mobile:font-medium", this.DATA_ATTRIBUTES = {
2832
+ buttonActive: "data-blok-link-tool-active",
2833
+ buttonUnlink: "data-blok-link-tool-unlink",
2834
+ inputOpened: "data-blok-link-tool-input-opened"
2835
+ }, this.nodes = {
2836
+ input: null,
2837
+ button: null
2838
+ }, this.inputOpened = !1, this.unlinkAvailable = !1, this.handleButtonClick = (e) => {
2839
+ !this.inputOpened || !this.unlinkAvailable || (e.preventDefault(), e.stopPropagation(), e.stopImmediatePropagation(), this.restoreSelection(), this.unlink(), this.inlineToolbar.close());
2840
+ }, this.toolbar = t.toolbar, this.inlineToolbar = t.inlineToolbar, this.notifier = t.notifier, this.i18n = t.i18n, this.selection = new H(), this.nodes.input = this.createInput();
2841
+ }
2842
+ /**
2843
+ * Sanitizer Rule
2844
+ * Leave <a> tags
2845
+ * @returns {object}
2846
+ */
2847
+ static get sanitize() {
2848
+ return {
2849
+ a: {
2850
+ href: !0,
2851
+ target: "_blank",
2852
+ rel: "nofollow"
2853
+ }
2854
+ };
2855
+ }
2856
+ /**
2857
+ * Create button for Inline Toolbar
2858
+ */
2859
+ render() {
2860
+ return {
2861
+ icon: Tt,
2862
+ name: "link",
2863
+ isActive: () => !!this.selection.findParentTag("A"),
2864
+ children: {
2865
+ hideChevron: !0,
2866
+ items: [
2867
+ {
2868
+ type: Et.Html,
2869
+ element: this.nodes.input
2870
+ }
2871
+ ],
2872
+ onOpen: () => {
2873
+ this.openActions(!0);
2874
+ },
2875
+ onClose: () => {
2876
+ this.closeActions();
2877
+ }
2878
+ }
2879
+ };
2880
+ }
2881
+ /**
2882
+ * Input for the link
2883
+ */
2884
+ createInput() {
2885
+ const t = document.createElement("input");
2886
+ return t.placeholder = this.i18n.t("tools.link.addLink"), t.enterKeyHint = "done", t.className = this.INPUT_BASE_CLASSES, t.setAttribute("data-blok-testid", "inline-tool-input"), this.setBooleanStateAttribute(t, this.DATA_ATTRIBUTES.inputOpened, !1), t.addEventListener("keydown", (e) => {
2887
+ e.key === "Enter" && this.enterPressed(e);
2888
+ }), t;
2889
+ }
2890
+ /**
2891
+ * @param {boolean} needFocus - on link creation we need to focus input. On editing - nope.
2892
+ */
2893
+ openActions(t = !1) {
2894
+ if (!this.nodes.input)
2895
+ return;
2896
+ const e = this.selection.findParentTag("A"), n = !!e;
2897
+ if (this.updateButtonStateAttributes(n), this.unlinkAvailable = n, e) {
2898
+ const r = e.getAttribute("href");
2899
+ this.nodes.input.value = r !== null ? r : "";
2900
+ } else
2901
+ this.nodes.input.value = "";
2902
+ this.nodes.input.className = L(this.INPUT_BASE_CLASSES, "block"), this.setBooleanStateAttribute(this.nodes.input, this.DATA_ATTRIBUTES.inputOpened, !0), this.selection.setFakeBackground(), this.selection.save(), t && this.focusInputWithRetry(), this.inputOpened = !0;
2903
+ }
2904
+ /**
2905
+ * Ensures the link input receives focus even if other listeners steal it
2906
+ */
2907
+ focusInputWithRetry() {
2908
+ this.nodes.input && (this.nodes.input.focus(), !(typeof window == "undefined" || typeof document == "undefined") && window.setTimeout(() => {
2909
+ var t;
2910
+ document.activeElement !== this.nodes.input && ((t = this.nodes.input) == null || t.focus());
2911
+ }, 0));
2912
+ }
2913
+ /**
2914
+ * Resolve the current inline toolbar button element
2915
+ */
2916
+ getButtonElement() {
2917
+ const t = document.querySelector(
2918
+ `${A(g.interface, At)} [data-blok-item-name="link"]`
2919
+ );
2920
+ return t && t !== this.nodes.button && (t.addEventListener("click", this.handleButtonClick, !0), this.nodes.button = t), t;
2921
+ }
2922
+ /**
2923
+ * Update button state attributes for e2e hooks
2924
+ * @param hasAnchor - Optional override for anchor presence
2925
+ */
2926
+ updateButtonStateAttributes(t) {
2927
+ const e = this.getButtonElement();
2928
+ if (!e)
2929
+ return;
2930
+ const n = typeof t == "boolean" ? t : !!this.selection.findParentTag("A");
2931
+ this.setBooleanStateAttribute(e, this.DATA_ATTRIBUTES.buttonActive, n), this.setBooleanStateAttribute(e, this.DATA_ATTRIBUTES.buttonUnlink, n);
2932
+ }
2933
+ /**
2934
+ * Close input
2935
+ * @param {boolean} clearSavedSelection — we don't need to clear saved selection
2936
+ * on toggle-clicks on the icon of opened Toolbar
2937
+ */
2938
+ closeActions(t = !0) {
2939
+ (this.selection.isFakeBackgroundEnabled || t && this.selection.savedSelectionRange) && this.restoreSelection(), this.nodes.input && (this.nodes.input.className = this.INPUT_BASE_CLASSES, this.setBooleanStateAttribute(this.nodes.input, this.DATA_ATTRIBUTES.inputOpened, !1), this.nodes.input.value = "", this.updateButtonStateAttributes(!1), this.unlinkAvailable = !1, t && this.selection.clearSaved(), this.inputOpened = !1);
2940
+ }
2941
+ /**
2942
+ * Restore selection after closing actions
2943
+ */
2944
+ restoreSelection() {
2945
+ const t = new H(), e = H.isAtBlok;
2946
+ if (e && t.save(), this.selection.removeFakeBackground(), this.selection.restore(), !e && this.selection.savedSelectionRange) {
2947
+ const s = this.selection.savedSelectionRange.commonAncestorContainer, o = s.nodeType === Node.ELEMENT_NODE ? s : s.parentElement;
2948
+ o == null || o.focus();
2949
+ }
2950
+ if (!e)
2951
+ return;
2952
+ t.restore();
2953
+ const n = t.savedSelectionRange;
2954
+ if (n) {
2955
+ const r = n.commonAncestorContainer, s = r.nodeType === Node.ELEMENT_NODE ? r : r.parentElement;
2956
+ s == null || s.focus();
2957
+ }
2958
+ }
2959
+ /**
2960
+ * Enter pressed on input
2961
+ * @param {KeyboardEvent} event - enter keydown event
2962
+ */
2963
+ enterPressed(t) {
2964
+ if (!this.nodes.input)
2965
+ return;
2966
+ const e = this.nodes.input.value || "";
2967
+ if (!e.trim()) {
2968
+ this.selection.restore(), this.unlink(), t.preventDefault(), this.closeActions(), this.inlineToolbar.close();
2969
+ return;
2970
+ }
2971
+ if (!this.validateURL(e)) {
2972
+ this.notifier.show({
2973
+ message: this.i18n.t("tools.link.invalidLink"),
2974
+ style: "error"
2975
+ }), Ct("Incorrect Link pasted", "warn", e);
2976
+ return;
2977
+ }
2978
+ const n = this.prepareLink(e);
2979
+ this.selection.removeFakeBackground(), this.selection.restore(), this.insertLink(n), t.preventDefault(), t.stopPropagation(), t.stopImmediatePropagation(), this.selection.collapseToEnd(), this.inlineToolbar.close();
2980
+ }
2981
+ /**
2982
+ * Detects if passed string is URL
2983
+ * @param {string} str - string to validate
2984
+ * @returns {boolean}
2985
+ */
2986
+ validateURL(t) {
2987
+ return !/\s/.test(t);
2988
+ }
2989
+ /**
2990
+ * Process link before injection
2991
+ * - sanitize
2992
+ * - add protocol for links like 'google.com'
2993
+ * @param {string} link - raw user input
2994
+ */
2995
+ prepareLink(t) {
2996
+ return this.addProtocol(t.trim());
2997
+ }
2998
+ /**
2999
+ * Add 'http' protocol to the links like 'vc.ru', 'google.com'
3000
+ * @param {string} link - string to process
3001
+ */
3002
+ addProtocol(t) {
3003
+ if (/^(\w+):(\/\/)?/.test(t))
3004
+ return t;
3005
+ const e = /^\/[^/\s]/.test(t), n = t.substring(0, 1) === "#", r = /^\/\/[^/\s]/.test(t);
3006
+ return !e && !n && !r ? "http://" + t : t;
3007
+ }
3008
+ /**
3009
+ * Inserts <a> tag with "href"
3010
+ * @param {string} link - "href" value
3011
+ */
3012
+ insertLink(t) {
3013
+ const e = this.selection.findParentTag("A");
3014
+ if (e) {
3015
+ this.selection.expandToTag(e), e.href = t, e.target = "_blank", e.rel = "nofollow";
3016
+ return;
3017
+ }
3018
+ const n = H.range;
3019
+ if (!n)
3020
+ return;
3021
+ const r = document.createElement("a");
3022
+ r.href = t, r.target = "_blank", r.rel = "nofollow", r.appendChild(n.extractContents()), n.insertNode(r), this.selection.expandToTag(r);
3023
+ }
3024
+ /**
3025
+ * Removes <a> tag
3026
+ */
3027
+ unlink() {
3028
+ const t = this.selection.findParentTag("A");
3029
+ t && (this.unwrap(t), this.updateButtonStateAttributes(!1), this.unlinkAvailable = !1);
3030
+ }
3031
+ /**
3032
+ * Unwrap passed node
3033
+ * @param term - node to unwrap
3034
+ */
3035
+ unwrap(t) {
3036
+ var n;
3037
+ const e = document.createDocumentFragment();
3038
+ for (; t.firstChild; )
3039
+ e.appendChild(t.firstChild);
3040
+ (n = t.parentNode) == null || n.replaceChild(e, t);
3041
+ }
3042
+ /**
3043
+ * Persist state as data attributes for testing hooks
3044
+ * @param element - The HTML element to set the attribute on, or null
3045
+ * @param attributeName - The name of the attribute to set
3046
+ * @param state - The boolean state value to persist
3047
+ */
3048
+ setBooleanStateAttribute(t, e, n) {
3049
+ t && t.setAttribute(e, n ? "true" : "false");
3050
+ }
3051
+ };
3052
+ D.isInline = !0, D.title = "Link", D.titleKey = "link", D.shortcut = "CMD+K";
3053
+ let tt = D;
3054
+ const xt = {
3055
+ paragraph: { inlineToolbar: !0, config: { preserveBlank: !0 } },
3056
+ header: { inlineToolbar: !0 },
3057
+ list: { inlineToolbar: !0 }
3058
+ }, vt = {
3059
+ bold: {},
3060
+ italic: {},
3061
+ link: {}
3062
+ };
3063
+ export {
3064
+ Z as Bold,
3065
+ Ot as Convert,
3066
+ Y as Header,
3067
+ Q as Italic,
3068
+ tt as Link,
3069
+ J as List,
3070
+ X as Paragraph,
3071
+ xt as defaultBlockTools,
3072
+ vt as defaultInlineTools
3073
+ };