@jackuait/blok 0.4.1-beta.0 → 0.4.1-beta.11

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 (402) hide show
  1. package/README.md +138 -17
  2. package/codemod/README.md +45 -7
  3. package/codemod/migrate-editorjs-to-blok.js +960 -92
  4. package/codemod/test.js +780 -77
  5. package/dist/blok.mjs +5 -2
  6. package/dist/chunks/blok-oNSQ3HA6.mjs +13217 -0
  7. package/dist/chunks/i18next-CugVlwWp.mjs +1292 -0
  8. package/dist/chunks/i18next-loader-BdNRw4n4.mjs +43 -0
  9. package/dist/{index-OwEtDFlk.mjs → chunks/index-DHgXmfki.mjs} +2 -2
  10. package/dist/chunks/inline-tool-convert-CRqgjRim.mjs +1989 -0
  11. package/dist/chunks/messages-0tDXLuyH.mjs +48 -0
  12. package/dist/chunks/messages-2_xedlYw.mjs +48 -0
  13. package/dist/chunks/messages-AHESHJm_.mjs +48 -0
  14. package/dist/chunks/messages-B5hdXZwA.mjs +48 -0
  15. package/dist/chunks/messages-B5jGUnOy.mjs +48 -0
  16. package/dist/chunks/messages-B5puUm7R.mjs +48 -0
  17. package/dist/chunks/messages-B66ZSDCJ.mjs +48 -0
  18. package/dist/chunks/messages-B9Oba7sq.mjs +48 -0
  19. package/dist/chunks/messages-BA0rcTCY.mjs +48 -0
  20. package/dist/chunks/messages-BBJgd5jG.mjs +48 -0
  21. package/dist/chunks/messages-BPqWKx5Z.mjs +48 -0
  22. package/dist/chunks/messages-Bdv-IkfG.mjs +48 -0
  23. package/dist/chunks/messages-BeUhMpsr.mjs +48 -0
  24. package/dist/chunks/messages-Bf6Y3_GI.mjs +48 -0
  25. package/dist/chunks/messages-BiExzWJv.mjs +48 -0
  26. package/dist/chunks/messages-BlpqL8vG.mjs +48 -0
  27. package/dist/chunks/messages-BmKCChWZ.mjs +48 -0
  28. package/dist/chunks/messages-Bn253WWC.mjs +48 -0
  29. package/dist/chunks/messages-BrJHUxQL.mjs +48 -0
  30. package/dist/chunks/messages-C5b7hr_E.mjs +48 -0
  31. package/dist/chunks/messages-C7I_AVH2.mjs +48 -0
  32. package/dist/chunks/messages-CJoBtXU6.mjs +48 -0
  33. package/dist/chunks/messages-CQj2JU2j.mjs +48 -0
  34. package/dist/chunks/messages-CUZ1x1QD.mjs +48 -0
  35. package/dist/chunks/messages-CUy1vn-b.mjs +48 -0
  36. package/dist/chunks/messages-CVeWVKsV.mjs +48 -0
  37. package/dist/chunks/messages-CXHd9SUK.mjs +48 -0
  38. package/dist/chunks/messages-CbMyJSzS.mjs +48 -0
  39. package/dist/chunks/messages-CbhuIWRJ.mjs +48 -0
  40. package/dist/chunks/messages-CeCjVKMW.mjs +48 -0
  41. package/dist/chunks/messages-Cj-t1bdy.mjs +48 -0
  42. package/dist/chunks/messages-CkFT2gle.mjs +48 -0
  43. package/dist/chunks/messages-Cm9aLHeX.mjs +48 -0
  44. package/dist/chunks/messages-CnvW8Slp.mjs +48 -0
  45. package/dist/chunks/messages-Cr-RJ7YB.mjs +48 -0
  46. package/dist/chunks/messages-CrsJ1TEJ.mjs +48 -0
  47. package/dist/chunks/messages-Cu08aLS3.mjs +48 -0
  48. package/dist/chunks/messages-CvaqJFN-.mjs +48 -0
  49. package/dist/chunks/messages-CyDU5lz9.mjs +48 -0
  50. package/dist/chunks/messages-CySyfkMU.mjs +48 -0
  51. package/dist/chunks/messages-Cyi2AMmz.mjs +48 -0
  52. package/dist/chunks/messages-D00OjS2n.mjs +48 -0
  53. package/dist/chunks/messages-DDLgIPDF.mjs +48 -0
  54. package/dist/chunks/messages-DMQIHGRj.mjs +48 -0
  55. package/dist/chunks/messages-DOlC_Tty.mjs +48 -0
  56. package/dist/chunks/messages-DV6shA9b.mjs +48 -0
  57. package/dist/chunks/messages-DY94ykcE.mjs +48 -0
  58. package/dist/chunks/messages-DbVquYKN.mjs +48 -0
  59. package/dist/chunks/messages-DcKOuncK.mjs +48 -0
  60. package/dist/chunks/messages-Dg92dXZ5.mjs +48 -0
  61. package/dist/chunks/messages-DnbbyJT3.mjs +48 -0
  62. package/dist/chunks/messages-DteYq0rv.mjs +48 -0
  63. package/dist/chunks/messages-GC2PhgV3.mjs +48 -0
  64. package/dist/chunks/messages-JGsXAReJ.mjs +48 -0
  65. package/dist/chunks/messages-JZUhXTuV.mjs +48 -0
  66. package/dist/chunks/messages-LvFKBBPa.mjs +48 -0
  67. package/dist/chunks/messages-NP1myMGI.mjs +48 -0
  68. package/dist/chunks/messages-Q4kc_ZtL.mjs +48 -0
  69. package/dist/chunks/messages-RvMHb2Ht.mjs +48 -0
  70. package/dist/chunks/messages-ftMcCEuO.mjs +48 -0
  71. package/dist/chunks/messages-o24dK6CU.mjs +48 -0
  72. package/dist/chunks/messages-pA5TvcAj.mjs +48 -0
  73. package/dist/chunks/messages-rRSHQDCX.mjs +48 -0
  74. package/dist/chunks/messages-srxrv8Yh.mjs +48 -0
  75. package/dist/chunks/messages-wdqp4610.mjs +48 -0
  76. package/dist/chunks/messages-zS1AXZ0y.mjs +48 -0
  77. package/dist/chunks/messages-zSzDzXej.mjs +48 -0
  78. package/dist/full.mjs +50 -0
  79. package/dist/locales.mjs +228 -0
  80. package/dist/messages-0tDXLuyH.mjs +48 -0
  81. package/dist/messages-2_xedlYw.mjs +48 -0
  82. package/dist/messages-AHESHJm_.mjs +48 -0
  83. package/dist/messages-B5hdXZwA.mjs +48 -0
  84. package/dist/messages-B5jGUnOy.mjs +48 -0
  85. package/dist/messages-B5puUm7R.mjs +48 -0
  86. package/dist/messages-B66ZSDCJ.mjs +48 -0
  87. package/dist/messages-B9Oba7sq.mjs +48 -0
  88. package/dist/messages-BA0rcTCY.mjs +48 -0
  89. package/dist/messages-BBJgd5jG.mjs +48 -0
  90. package/dist/messages-BPqWKx5Z.mjs +48 -0
  91. package/dist/messages-Bdv-IkfG.mjs +48 -0
  92. package/dist/messages-BeUhMpsr.mjs +48 -0
  93. package/dist/messages-Bf6Y3_GI.mjs +48 -0
  94. package/dist/messages-BiExzWJv.mjs +48 -0
  95. package/dist/messages-BlpqL8vG.mjs +48 -0
  96. package/dist/messages-BmKCChWZ.mjs +48 -0
  97. package/dist/messages-Bn253WWC.mjs +48 -0
  98. package/dist/messages-BrJHUxQL.mjs +48 -0
  99. package/dist/messages-C5b7hr_E.mjs +48 -0
  100. package/dist/messages-C7I_AVH2.mjs +48 -0
  101. package/dist/messages-CJoBtXU6.mjs +48 -0
  102. package/dist/messages-CQj2JU2j.mjs +48 -0
  103. package/dist/messages-CUZ1x1QD.mjs +48 -0
  104. package/dist/messages-CUy1vn-b.mjs +48 -0
  105. package/dist/messages-CVeWVKsV.mjs +48 -0
  106. package/dist/messages-CXHd9SUK.mjs +48 -0
  107. package/dist/messages-CbMyJSzS.mjs +48 -0
  108. package/dist/messages-CbhuIWRJ.mjs +48 -0
  109. package/dist/messages-CeCjVKMW.mjs +48 -0
  110. package/dist/messages-Cj-t1bdy.mjs +48 -0
  111. package/dist/messages-CkFT2gle.mjs +48 -0
  112. package/dist/messages-Cm9aLHeX.mjs +48 -0
  113. package/dist/messages-CnvW8Slp.mjs +48 -0
  114. package/dist/messages-Cr-RJ7YB.mjs +48 -0
  115. package/dist/messages-CrsJ1TEJ.mjs +48 -0
  116. package/dist/messages-Cu08aLS3.mjs +48 -0
  117. package/dist/messages-CvaqJFN-.mjs +48 -0
  118. package/dist/messages-CyDU5lz9.mjs +48 -0
  119. package/dist/messages-CySyfkMU.mjs +48 -0
  120. package/dist/messages-Cyi2AMmz.mjs +48 -0
  121. package/dist/messages-D00OjS2n.mjs +48 -0
  122. package/dist/messages-DDLgIPDF.mjs +48 -0
  123. package/dist/messages-DMQIHGRj.mjs +48 -0
  124. package/dist/messages-DOlC_Tty.mjs +48 -0
  125. package/dist/messages-DV6shA9b.mjs +48 -0
  126. package/dist/messages-DY94ykcE.mjs +48 -0
  127. package/dist/messages-DbVquYKN.mjs +48 -0
  128. package/dist/messages-DcKOuncK.mjs +48 -0
  129. package/dist/messages-Dg92dXZ5.mjs +48 -0
  130. package/dist/messages-DnbbyJT3.mjs +48 -0
  131. package/dist/messages-DteYq0rv.mjs +48 -0
  132. package/dist/messages-GC2PhgV3.mjs +48 -0
  133. package/dist/messages-JGsXAReJ.mjs +48 -0
  134. package/dist/messages-JZUhXTuV.mjs +48 -0
  135. package/dist/messages-LvFKBBPa.mjs +48 -0
  136. package/dist/messages-NP1myMGI.mjs +48 -0
  137. package/dist/messages-Q4kc_ZtL.mjs +48 -0
  138. package/dist/messages-RvMHb2Ht.mjs +48 -0
  139. package/dist/messages-ftMcCEuO.mjs +48 -0
  140. package/dist/messages-o24dK6CU.mjs +48 -0
  141. package/dist/messages-pA5TvcAj.mjs +48 -0
  142. package/dist/messages-rRSHQDCX.mjs +48 -0
  143. package/dist/messages-srxrv8Yh.mjs +48 -0
  144. package/dist/messages-wdqp4610.mjs +48 -0
  145. package/dist/messages-zS1AXZ0y.mjs +48 -0
  146. package/dist/messages-zSzDzXej.mjs +48 -0
  147. package/dist/tools.mjs +3117 -0
  148. package/dist/vendor.LICENSE.txt +26 -225
  149. package/package.json +63 -24
  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 +1428 -0
  154. package/src/components/block-tunes/block-tune-delete.ts +51 -0
  155. package/src/components/blocks.ts +352 -0
  156. package/src/components/constants/data-attributes.ts +344 -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 +497 -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 +45 -0
  177. package/src/components/i18n/locales/ar/messages.json +45 -0
  178. package/src/components/i18n/locales/az/messages.json +45 -0
  179. package/src/components/i18n/locales/bg/messages.json +45 -0
  180. package/src/components/i18n/locales/bn/messages.json +45 -0
  181. package/src/components/i18n/locales/bs/messages.json +45 -0
  182. package/src/components/i18n/locales/cs/messages.json +45 -0
  183. package/src/components/i18n/locales/da/messages.json +45 -0
  184. package/src/components/i18n/locales/de/messages.json +45 -0
  185. package/src/components/i18n/locales/dv/messages.json +45 -0
  186. package/src/components/i18n/locales/el/messages.json +45 -0
  187. package/src/components/i18n/locales/en/messages.json +45 -0
  188. package/src/components/i18n/locales/es/messages.json +45 -0
  189. package/src/components/i18n/locales/et/messages.json +45 -0
  190. package/src/components/i18n/locales/fa/messages.json +45 -0
  191. package/src/components/i18n/locales/fi/messages.json +45 -0
  192. package/src/components/i18n/locales/fil/messages.json +45 -0
  193. package/src/components/i18n/locales/fr/messages.json +45 -0
  194. package/src/components/i18n/locales/gu/messages.json +45 -0
  195. package/src/components/i18n/locales/he/messages.json +45 -0
  196. package/src/components/i18n/locales/hi/messages.json +45 -0
  197. package/src/components/i18n/locales/hr/messages.json +45 -0
  198. package/src/components/i18n/locales/hu/messages.json +45 -0
  199. package/src/components/i18n/locales/hy/messages.json +45 -0
  200. package/src/components/i18n/locales/id/messages.json +45 -0
  201. package/src/components/i18n/locales/index.ts +231 -0
  202. package/src/components/i18n/locales/it/messages.json +45 -0
  203. package/src/components/i18n/locales/ja/messages.json +45 -0
  204. package/src/components/i18n/locales/ka/messages.json +45 -0
  205. package/src/components/i18n/locales/km/messages.json +45 -0
  206. package/src/components/i18n/locales/kn/messages.json +45 -0
  207. package/src/components/i18n/locales/ko/messages.json +45 -0
  208. package/src/components/i18n/locales/ku/messages.json +45 -0
  209. package/src/components/i18n/locales/lo/messages.json +45 -0
  210. package/src/components/i18n/locales/lt/messages.json +45 -0
  211. package/src/components/i18n/locales/lv/messages.json +45 -0
  212. package/src/components/i18n/locales/mk/messages.json +45 -0
  213. package/src/components/i18n/locales/ml/messages.json +45 -0
  214. package/src/components/i18n/locales/mn/messages.json +45 -0
  215. package/src/components/i18n/locales/mr/messages.json +45 -0
  216. package/src/components/i18n/locales/ms/messages.json +45 -0
  217. package/src/components/i18n/locales/my/messages.json +45 -0
  218. package/src/components/i18n/locales/ne/messages.json +45 -0
  219. package/src/components/i18n/locales/nl/messages.json +45 -0
  220. package/src/components/i18n/locales/no/messages.json +45 -0
  221. package/src/components/i18n/locales/pa/messages.json +45 -0
  222. package/src/components/i18n/locales/pl/messages.json +45 -0
  223. package/src/components/i18n/locales/ps/messages.json +45 -0
  224. package/src/components/i18n/locales/pt/messages.json +45 -0
  225. package/src/components/i18n/locales/ro/messages.json +45 -0
  226. package/src/components/i18n/locales/ru/messages.json +45 -0
  227. package/src/components/i18n/locales/sd/messages.json +45 -0
  228. package/src/components/i18n/locales/si/messages.json +45 -0
  229. package/src/components/i18n/locales/sk/messages.json +45 -0
  230. package/src/components/i18n/locales/sl/messages.json +45 -0
  231. package/src/components/i18n/locales/sq/messages.json +45 -0
  232. package/src/components/i18n/locales/sr/messages.json +45 -0
  233. package/src/components/i18n/locales/sv/messages.json +45 -0
  234. package/src/components/i18n/locales/sw/messages.json +45 -0
  235. package/src/components/i18n/locales/ta/messages.json +45 -0
  236. package/src/components/i18n/locales/te/messages.json +45 -0
  237. package/src/components/i18n/locales/th/messages.json +45 -0
  238. package/src/components/i18n/locales/tr/messages.json +45 -0
  239. package/src/components/i18n/locales/ug/messages.json +45 -0
  240. package/src/components/i18n/locales/uk/messages.json +45 -0
  241. package/src/components/i18n/locales/ur/messages.json +45 -0
  242. package/src/components/i18n/locales/vi/messages.json +45 -0
  243. package/src/components/i18n/locales/yi/messages.json +45 -0
  244. package/src/components/i18n/locales/zh/messages.json +45 -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 +377 -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 +35 -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 +1591 -0
  269. package/src/components/modules/blockManager.ts +1356 -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 +1204 -0
  274. package/src/components/modules/history.ts +1098 -0
  275. package/src/components/modules/i18n.ts +332 -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 +711 -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 +781 -0
  284. package/src/components/modules/toolbar/index.ts +1315 -0
  285. package/src/components/modules/toolbar/inline.ts +956 -0
  286. package/src/components/modules/tools.ts +625 -0
  287. package/src/components/modules/ui.ts +1283 -0
  288. package/src/components/polyfills.ts +113 -0
  289. package/src/components/selection.ts +1179 -0
  290. package/src/components/tools/base.ts +301 -0
  291. package/src/components/tools/block.ts +339 -0
  292. package/src/components/tools/collection.ts +67 -0
  293. package/src/components/tools/factory.ts +138 -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 +601 -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 +680 -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 +186 -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 +178 -0
  330. package/src/components/utils/popover/components/search-input/search-input.types.ts +59 -0
  331. package/src/components/utils/popover/index.ts +13 -0
  332. package/src/components/utils/popover/popover-abstract.ts +457 -0
  333. package/src/components/utils/popover/popover-desktop.ts +676 -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 +110 -0
  344. package/src/components/utils/tooltip.ts +591 -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 +646 -0
  367. package/src/tools/index.ts +45 -0
  368. package/src/tools/list/index.ts +1819 -0
  369. package/src/tools/paragraph/index.ts +412 -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 +9 -1
  378. package/types/api/history.d.ts +7 -0
  379. package/types/api/i18n.d.ts +22 -3
  380. package/types/api/selection.d.ts +6 -0
  381. package/types/api/styles.d.ts +23 -10
  382. package/types/configs/blok-config.d.ts +29 -0
  383. package/types/configs/i18n-config.d.ts +52 -2
  384. package/types/configs/i18n-dictionary.d.ts +16 -90
  385. package/types/data-attributes.d.ts +170 -0
  386. package/types/data-formats/output-data.d.ts +15 -0
  387. package/types/full.d.ts +80 -0
  388. package/types/index.d.ts +30 -13
  389. package/types/locales.d.ts +59 -0
  390. package/types/tools/adapters/inline-tool-adapter.d.ts +10 -0
  391. package/types/tools/block-tool.d.ts +9 -0
  392. package/types/tools/header.d.ts +18 -0
  393. package/types/tools/index.d.ts +1 -0
  394. package/types/tools/list.d.ts +91 -0
  395. package/types/tools/paragraph.d.ts +71 -0
  396. package/types/tools/tool-settings.d.ts +92 -6
  397. package/types/tools/tool.d.ts +6 -0
  398. package/types/tools-entry.d.ts +49 -0
  399. package/types/utils/popover/popover-item.d.ts +18 -5
  400. package/types/utils/popover/popover.d.ts +7 -0
  401. package/dist/blok-D_baBvTG.mjs +0 -25795
  402. package/dist/blok.umd.js +0 -181
@@ -0,0 +1,1081 @@
1
+ /**
2
+ * Class Util
3
+ */
4
+
5
+ import { nanoid } from 'nanoid';
6
+
7
+ /**
8
+ * Possible log levels
9
+ */
10
+ export enum LogLevels {
11
+ VERBOSE = 'VERBOSE',
12
+ INFO = 'INFO',
13
+ WARN = 'WARN',
14
+ ERROR = 'ERROR',
15
+ }
16
+
17
+ /**
18
+ * Allow to use global VERSION, that will be overwritten by Webpack
19
+ */
20
+ declare const VERSION: string;
21
+
22
+ const fallbackBlokVersion = 'dev';
23
+
24
+ /**
25
+ * Returns Blok version injected by bundler or a globally provided fallback.
26
+ */
27
+ export const getBlokVersion = (): string => {
28
+ if (typeof VERSION !== 'undefined') {
29
+ return VERSION;
30
+ }
31
+
32
+ const globalVersion = (typeof globalThis === 'object' && globalThis !== null)
33
+ ? (globalThis as { VERSION?: unknown }).VERSION
34
+ : undefined;
35
+
36
+ if (typeof globalVersion === 'string' && globalVersion.trim() !== '') {
37
+ return globalVersion;
38
+ }
39
+
40
+ return fallbackBlokVersion;
41
+ };
42
+
43
+
44
+ /**
45
+ * Blok utils
46
+ */
47
+
48
+ /**
49
+ * Returns basic key codes as constants
50
+ * @returns {{}}
51
+ */
52
+ export const keyCodes = {
53
+ BACKSPACE: 8,
54
+ TAB: 9,
55
+ ENTER: 13,
56
+ SHIFT: 16,
57
+ CTRL: 17,
58
+ ALT: 18,
59
+ ESC: 27,
60
+ SPACE: 32,
61
+ LEFT: 37,
62
+ UP: 38,
63
+ DOWN: 40,
64
+ RIGHT: 39,
65
+ DELETE: 46,
66
+ // Number keys range (0-9)
67
+ NUMBER_KEY_MIN: 47,
68
+ NUMBER_KEY_MAX: 58,
69
+ // Letter keys range (A-Z)
70
+ LETTER_KEY_MIN: 64,
71
+ LETTER_KEY_MAX: 91,
72
+ META: 91,
73
+ // Numpad keys range
74
+ NUMPAD_KEY_MIN: 95,
75
+ NUMPAD_KEY_MAX: 112,
76
+ // Punctuation keys range (;=,-./`)
77
+ PUNCTUATION_KEY_MIN: 185,
78
+ PUNCTUATION_KEY_MAX: 193,
79
+ // Bracket keys range ([\]')
80
+ BRACKET_KEY_MIN: 218,
81
+ BRACKET_KEY_MAX: 223,
82
+ // Processing key input for certain languages (Chinese, Japanese, etc.)
83
+ PROCESSING_KEY: 229,
84
+ SLASH: 191,
85
+ };
86
+
87
+ /**
88
+ * Return mouse buttons codes
89
+ */
90
+ export const mouseButtons = {
91
+ LEFT: 0,
92
+ WHEEL: 1,
93
+ RIGHT: 2,
94
+ BACKWARD: 3,
95
+ FORWARD: 4,
96
+ };
97
+
98
+ /**
99
+ * Constants for ID generation
100
+ */
101
+ const ID_RANDOM_MULTIPLIER = 100_000_000; // 1e8
102
+ const HEXADECIMAL_RADIX = 16;
103
+
104
+ type UniversalScope = {
105
+ window?: Window;
106
+ document?: Document;
107
+ navigator?: Navigator;
108
+ };
109
+
110
+ const globalScope: UniversalScope | undefined = (() => {
111
+ try {
112
+ return Function('return this')() as UniversalScope;
113
+ } catch {
114
+ return undefined;
115
+ }
116
+ })();
117
+
118
+ if (globalScope && typeof globalScope.window === 'undefined') {
119
+ (globalScope as Record<string, unknown>).window = globalScope;
120
+ }
121
+
122
+ /**
123
+ * Returns globally available window object if it exists.
124
+ */
125
+ const getGlobalWindow = (): Window | undefined => {
126
+ if (globalScope?.window) {
127
+ return globalScope.window;
128
+ }
129
+
130
+ return undefined;
131
+ };
132
+
133
+ /**
134
+ * Returns globally available navigator object if it exists.
135
+ */
136
+ const getGlobalNavigator = (): Navigator | undefined => {
137
+ if (globalScope?.navigator) {
138
+ return globalScope.navigator;
139
+ }
140
+
141
+ const win = getGlobalWindow();
142
+
143
+ return win?.navigator;
144
+ };
145
+
146
+ /**
147
+ * Type representing callable console methods
148
+ */
149
+ type ConsoleMethod = {
150
+ [K in keyof Console]: Console[K] extends (...args: unknown[]) => unknown ? K : never;
151
+ }[keyof Console];
152
+
153
+ /**
154
+ * Custom logger
155
+ * @param {boolean} labeled — if true, Blok label is shown
156
+ * @param {string} msg - message
157
+ * @param {string} type - logging type 'log'|'warn'|'error'|'info'
158
+ * @param {*} [args] - argument to log with a message
159
+ * @param {string} style - additional styling to message
160
+ */
161
+ const _log = (
162
+ labeled: boolean,
163
+ msg: string,
164
+ type: ConsoleMethod = 'log',
165
+ args?: unknown,
166
+ style = 'color: inherit'
167
+ ): void => {
168
+ const consoleRef: Console | undefined = typeof console === 'undefined' ? undefined : console;
169
+
170
+ if (!consoleRef || typeof consoleRef[type] !== 'function') {
171
+ return;
172
+ }
173
+
174
+ const isSimpleType = ['info', 'log', 'warn', 'error'].includes(type);
175
+ const argsToPass: unknown[] = [];
176
+
177
+ switch (_log.logLevel) {
178
+ case LogLevels.ERROR:
179
+ if (type !== 'error') {
180
+ return;
181
+ }
182
+ break;
183
+
184
+ case LogLevels.WARN:
185
+ if (!['error', 'warn'].includes(type)) {
186
+ return;
187
+ }
188
+ break;
189
+
190
+ case LogLevels.INFO:
191
+ if (!isSimpleType || labeled) {
192
+ return;
193
+ }
194
+ break;
195
+ }
196
+
197
+ if (args) {
198
+ argsToPass.push(args);
199
+ }
200
+
201
+ const blokLabelText = `Blok ${getBlokVersion()}`;
202
+ const blokLabelStyle = `line-height: 1em;
203
+ color: #006FEA;
204
+ display: inline-block;
205
+ font-size: 11px;
206
+ line-height: 1em;
207
+ background-color: #fff;
208
+ padding: 4px 9px;
209
+ border-radius: 30px;
210
+ border: 1px solid rgba(56, 138, 229, 0.16);
211
+ margin: 4px 5px 4px 0;`;
212
+
213
+ const formattedMessage = (() => {
214
+ if (!labeled) {
215
+ return msg;
216
+ }
217
+
218
+ if (isSimpleType) {
219
+ argsToPass.unshift(blokLabelStyle, style);
220
+
221
+ return `%c${blokLabelText}%c ${msg}`;
222
+ }
223
+
224
+ return `( ${blokLabelText} )${msg}`;
225
+ })();
226
+
227
+ const callArguments = (() => {
228
+ if (!isSimpleType) {
229
+ return [ formattedMessage ];
230
+ }
231
+
232
+ if (args !== undefined) {
233
+ return [`${formattedMessage} %o`, ...argsToPass];
234
+ }
235
+
236
+ return [formattedMessage, ...argsToPass];
237
+ })();
238
+
239
+ try {
240
+ consoleRef[type](...callArguments);
241
+ } catch (_ignored) {}
242
+ };
243
+
244
+ /**
245
+ * Current log level
246
+ */
247
+ _log.logLevel = LogLevels.VERBOSE;
248
+
249
+ /**
250
+ * Set current log level
251
+ * @param {LogLevels} logLevel - log level to set
252
+ */
253
+ export const setLogLevel = (logLevel: LogLevels): void => {
254
+ _log.logLevel = logLevel;
255
+ };
256
+
257
+ /**
258
+ * _log method proxy without Blok label
259
+ * @param msg - message to log
260
+ * @param type - console method name
261
+ * @param args - optional payload to pass to console
262
+ * @param style - optional css style for the first argument
263
+ */
264
+ export const log = (
265
+ msg: string,
266
+ type: ConsoleMethod = 'log',
267
+ args?: unknown,
268
+ style?: string
269
+ ): void => {
270
+ _log(false, msg, type, args, style);
271
+ };
272
+
273
+ /**
274
+ * _log method proxy with Blok label
275
+ * @param msg - message to log
276
+ * @param type - console method name
277
+ * @param args - optional payload to pass to console
278
+ * @param style - optional css style for the first argument
279
+ */
280
+ export const logLabeled = (
281
+ msg: string,
282
+ type: ConsoleMethod = 'log',
283
+ args?: unknown,
284
+ style?: string
285
+ ): void => {
286
+ _log(true, msg, type, args, style);
287
+ };
288
+
289
+ /**
290
+ * Check if passed variable is a function
291
+ * @param {*} fn - function to check
292
+ * @returns {boolean}
293
+ */
294
+ export const isFunction = (fn: unknown): fn is (...args: unknown[]) => unknown => {
295
+ return typeof fn === 'function';
296
+ };
297
+
298
+ /**
299
+ * Checks if passed argument is a plain object (created by {} or Object constructor)
300
+ * @param {*} v - object to check
301
+ * @returns {boolean}
302
+ */
303
+ export const isObject = (v: unknown): v is object => {
304
+ if (v === null || typeof v !== 'object') {
305
+ return false;
306
+ }
307
+ const proto = Object.getPrototypeOf(v);
308
+
309
+ return proto === null || proto === Object.prototype;
310
+ };
311
+
312
+ /**
313
+ * Checks if passed argument is a string
314
+ * @param {*} v - variable to check
315
+ * @returns {boolean}
316
+ */
317
+ export const isString = (v: unknown): v is string => {
318
+ return typeof v === 'string';
319
+ };
320
+
321
+ /**
322
+ * Checks if passed argument is boolean
323
+ * @param {*} v - variable to check
324
+ * @returns {boolean}
325
+ */
326
+ export const isBoolean = (v: unknown): v is boolean => {
327
+ return typeof v === 'boolean';
328
+ };
329
+
330
+ /**
331
+ * Checks if passed argument is number (including NaN, which has typeof 'number')
332
+ * @param {*} v - variable to check
333
+ * @returns {boolean}
334
+ */
335
+ export const isNumber = (v: unknown): v is number => {
336
+ return typeof v === 'number';
337
+ };
338
+
339
+ /**
340
+ * Checks if passed argument is undefined
341
+ * @param {*} v - variable to check
342
+ * @returns {boolean}
343
+ */
344
+ export const isUndefined = function (v: unknown): v is undefined {
345
+ return v === undefined;
346
+ };
347
+
348
+ /**
349
+ * Checks if value is empty (null, undefined, empty string, empty array, empty object, empty Map/Set)
350
+ * @param {*} value - value to check
351
+ * @returns {boolean}
352
+ */
353
+ export const isEmpty = (value: unknown): boolean => {
354
+ if (value === null || value === undefined) {
355
+ return true;
356
+ }
357
+ if (typeof value === 'string' || Array.isArray(value)) {
358
+ return value.length === 0;
359
+ }
360
+ if (value instanceof Map || value instanceof Set) {
361
+ return value.size === 0;
362
+ }
363
+ if (typeof value === 'object') {
364
+ return Object.keys(value).length === 0;
365
+ }
366
+
367
+ return false;
368
+ };
369
+
370
+ /**
371
+ * Returns true if passed key code is printable (a-Z, 0-9, etc) character.
372
+ * @param {number} keyCode - key code
373
+ * @returns {boolean}
374
+ */
375
+ export const isPrintableKey = (keyCode: number): boolean => {
376
+ return (keyCode > keyCodes.NUMBER_KEY_MIN && keyCode < keyCodes.NUMBER_KEY_MAX) || // number keys
377
+ keyCode === keyCodes.SPACE || keyCode === keyCodes.ENTER || // Space bar & return key(s)
378
+ keyCode === keyCodes.PROCESSING_KEY || // processing key input for certain languages — Chinese, Japanese, etc.
379
+ (keyCode > keyCodes.LETTER_KEY_MIN && keyCode < keyCodes.LETTER_KEY_MAX) || // letter keys
380
+ (keyCode > keyCodes.NUMPAD_KEY_MIN && keyCode < keyCodes.NUMPAD_KEY_MAX) || // Numpad keys
381
+ (keyCode > keyCodes.PUNCTUATION_KEY_MIN && keyCode < keyCodes.PUNCTUATION_KEY_MAX) || // ;=,-./` (in order)
382
+ (keyCode > keyCodes.BRACKET_KEY_MIN && keyCode < keyCodes.BRACKET_KEY_MAX); // [\]' (in order)
383
+ };
384
+
385
+ /**
386
+ * Make array from array-like collection
387
+ * @param {ArrayLike} collection - collection to convert to array
388
+ * @returns {Array}
389
+ */
390
+ export const array = (collection: ArrayLike<any>): any[] => {
391
+ return Array.from(collection);
392
+ };
393
+
394
+ /**
395
+ * Delays method execution
396
+ * @param {Function} method - method to execute
397
+ * @param {number} timeout - timeout in ms
398
+ */
399
+ export const delay = (method: (...args: unknown[]) => unknown, timeout: number) => {
400
+ return function (this: unknown, ...args: unknown[]): void {
401
+ setTimeout(() => method.apply(this, args), timeout);
402
+ };
403
+ };
404
+
405
+ /**
406
+ * Get file extension
407
+ * @param {File} file - file
408
+ * @returns {string}
409
+ */
410
+ export const getFileExtension = (file: File): string => {
411
+ return file.name.split('.').pop() ?? '';
412
+ };
413
+
414
+ /**
415
+ * Check if string is MIME type
416
+ * @param {string} type - string to check
417
+ * @returns {boolean}
418
+ */
419
+ export const isValidMimeType = (type: string): boolean => {
420
+ return /^[-\w]+\/([-+\w]+|\*)$/.test(type);
421
+ };
422
+
423
+ /**
424
+ * Debouncing method
425
+ * Call method after passed time
426
+ *
427
+ * Note that this method returns Function and declared variable need to be called
428
+ * @param {Function} func - function that we're throttling
429
+ * @param {number} wait - time in milliseconds
430
+ * @param {boolean} immediate - call now
431
+ * @returns {Function}
432
+ */
433
+ export const debounce = (func: (...args: unknown[]) => void, wait?: number, immediate?: boolean): (...args: unknown[]) => void => {
434
+ const state = {
435
+ timeoutId: null as ReturnType<typeof setTimeout> | null,
436
+ };
437
+
438
+ return function (this: unknown, ...args: unknown[]): void {
439
+ const later = (): void => {
440
+ state.timeoutId = null;
441
+ if (immediate !== true) {
442
+ func.apply(this, args);
443
+ }
444
+ };
445
+
446
+ const callNow = immediate === true && state.timeoutId === null;
447
+
448
+ if (state.timeoutId !== null) {
449
+ clearTimeout(state.timeoutId);
450
+ }
451
+ state.timeoutId = setTimeout(later, wait);
452
+ if (callNow) {
453
+ func.apply(this, args);
454
+ }
455
+ };
456
+ };
457
+
458
+ /**
459
+ * Returns a function, that, when invoked, will only be triggered at most once during a given window of time.
460
+ * @param func - function to throttle
461
+ * @param wait - function will be called only once for that period
462
+ * @param options - Normally, the throttled function will run as much as it can
463
+ * without ever going more than once per `wait` duration;
464
+ * but if you'd like to disable the execution on the leading edge, pass
465
+ * `{leading: false}`. To disable execution on the trailing edge, ditto.
466
+ */
467
+ export const throttle = (
468
+ func: (...args: unknown[]) => unknown,
469
+ wait: number,
470
+ options?: {leading?: boolean; trailing?: boolean}
471
+ ): ((...args: unknown[]) => unknown) => {
472
+ const leading = options?.leading !== false;
473
+ const trailing = options?.trailing !== false;
474
+
475
+ const state = {
476
+ lastCallTime: undefined as number | undefined,
477
+ lastInvokeTime: 0,
478
+ timerId: undefined as ReturnType<typeof setTimeout> | undefined,
479
+ lastArgs: undefined as unknown[] | undefined,
480
+ lastThis: undefined as unknown,
481
+ };
482
+
483
+ const invokeFunc = (time: number): unknown => {
484
+ state.lastInvokeTime = time;
485
+ const args = state.lastArgs;
486
+ const thisArg = state.lastThis;
487
+
488
+ state.lastArgs = undefined;
489
+ state.lastThis = undefined;
490
+
491
+ return func.apply(thisArg, args ?? []);
492
+ };
493
+
494
+ const remainingWait = (time: number): number => {
495
+ const timeSinceLastCall = time - (state.lastCallTime ?? 0);
496
+ const timeSinceLastInvoke = time - state.lastInvokeTime;
497
+ const timeWaiting = wait - timeSinceLastCall;
498
+
499
+ return trailing ? Math.min(timeWaiting, wait - timeSinceLastInvoke) : timeWaiting;
500
+ };
501
+
502
+ const shouldInvoke = (time: number): boolean => {
503
+ const timeSinceLastCall = time - (state.lastCallTime ?? 0);
504
+ const timeSinceLastInvoke = time - state.lastInvokeTime;
505
+
506
+ return (
507
+ state.lastCallTime === undefined ||
508
+ timeSinceLastCall >= wait ||
509
+ timeSinceLastCall < 0 ||
510
+ timeSinceLastInvoke >= wait
511
+ );
512
+ };
513
+
514
+ const timerExpired = (): void => {
515
+ const time = Date.now();
516
+
517
+ if (!shouldInvoke(time)) {
518
+ state.timerId = setTimeout(timerExpired, remainingWait(time));
519
+
520
+ return;
521
+ }
522
+
523
+ state.timerId = undefined;
524
+ const shouldInvokeTrailing = trailing && state.lastArgs !== undefined;
525
+
526
+ if (shouldInvokeTrailing) {
527
+ invokeFunc(time);
528
+ }
529
+ state.lastArgs = undefined;
530
+ state.lastThis = undefined;
531
+ };
532
+
533
+ const throttled = function (this: unknown, ...args: unknown[]): unknown {
534
+ const time = Date.now();
535
+ const isInvoking = shouldInvoke(time);
536
+
537
+ state.lastArgs = args;
538
+ state.lastThis = this;
539
+ state.lastCallTime = time;
540
+
541
+ const canStartTimer = isInvoking && state.timerId === undefined;
542
+
543
+ if (!canStartTimer) {
544
+ return undefined;
545
+ }
546
+
547
+ state.lastInvokeTime = time;
548
+ state.timerId = setTimeout(timerExpired, wait);
549
+
550
+ return leading ? invokeFunc(time) : undefined;
551
+ };
552
+
553
+ return throttled;
554
+ };
555
+
556
+ /**
557
+ * Returns object with os name as key and boolean as value. Shows current user OS
558
+ */
559
+ export const getUserOS = (): {[key: string]: boolean} => {
560
+ const OS: {[key: string]: boolean} = {
561
+ win: false,
562
+ mac: false,
563
+ x11: false,
564
+ linux: false,
565
+ };
566
+
567
+ const navigatorRef = getGlobalNavigator();
568
+ const userAgent = navigatorRef?.userAgent?.toLowerCase() ?? '';
569
+ const userOS = userAgent ? Object.keys(OS).find((os: string) => userAgent.indexOf(os) !== -1) : undefined;
570
+
571
+ if (userOS !== undefined) {
572
+ OS[userOS] = true;
573
+
574
+ return OS;
575
+ }
576
+
577
+ return OS;
578
+ };
579
+
580
+ /**
581
+ * Capitalizes first letter of the string
582
+ * @param {string} text - text to capitalize
583
+ * @returns {string}
584
+ */
585
+ export const capitalize = (text: string): string => {
586
+ if (!text) {
587
+ return text;
588
+ }
589
+
590
+ return text.slice(0, 1).toUpperCase() + text.slice(1);
591
+ };
592
+
593
+ /**
594
+ * Deep merge two objects recursively. Arrays are overwritten (not merged).
595
+ * Undefined values in source are skipped (matching lodash.mergeWith behavior).
596
+ * @param target - target object
597
+ * @param source - source object
598
+ * @returns new merged object
599
+ */
600
+ const deepMergeTwo = (target: Record<string, unknown>, source: Record<string, unknown>): Record<string, unknown> => {
601
+ const result = { ...target };
602
+
603
+ Object.keys(source).forEach((key) => {
604
+ const targetValue = result[key];
605
+ const sourceValue = source[key];
606
+
607
+ if (sourceValue === undefined) {
608
+ return;
609
+ }
610
+
611
+ const shouldRecurseMerge = isObject(sourceValue) && isObject(targetValue) && !Array.isArray(sourceValue);
612
+
613
+ if (shouldRecurseMerge) {
614
+ result[key] = deepMergeTwo(
615
+ targetValue as Record<string, unknown>,
616
+ sourceValue as Record<string, unknown>
617
+ );
618
+
619
+ return;
620
+ }
621
+
622
+ result[key] = sourceValue;
623
+ });
624
+
625
+ return result;
626
+ };
627
+
628
+ /**
629
+ * Deep merge objects. Arrays are overwritten (not merged).
630
+ * Mutates and returns the target object for compatibility with lodash.mergeWith.
631
+ * @param target - target object to merge into
632
+ * @param sources - source objects to merge from
633
+ * @returns merged object (same reference as target)
634
+ */
635
+ export const deepMerge = <T extends object> (target: T, ...sources: Partial<T>[]): T => {
636
+ if (!isObject(target) || sources.length === 0) {
637
+ return target;
638
+ }
639
+
640
+ const merged = sources.reduce((acc, source) => {
641
+ if (!isObject(source)) {
642
+ return acc;
643
+ }
644
+
645
+ return deepMergeTwo(acc as Record<string, unknown>, source as Record<string, unknown>);
646
+ }, target as Record<string, unknown>);
647
+
648
+ Object.assign(target, merged);
649
+
650
+ return target;
651
+ };
652
+
653
+ /**
654
+ * Make shortcut command more human-readable
655
+ * @param {string} shortcut — string like 'CMD+B'
656
+ */
657
+ export const beautifyShortcut = (shortcut: string): string => {
658
+ const OS = getUserOS();
659
+ const normalizedShortcut = shortcut
660
+ .replace(/shift/gi, '⇧')
661
+ .replace(/backspace/gi, '⌫')
662
+ .replace(/enter/gi, '⏎')
663
+ .replace(/up/gi, '↑')
664
+ .replace(/left/gi, '→')
665
+ .replace(/down/gi, '↓')
666
+ .replace(/right/gi, '←')
667
+ .replace(/escape/gi, '⎋')
668
+ .replace(/insert/gi, 'Ins')
669
+ .replace(/delete/gi, '␡')
670
+ .replace(/\+/gi, ' + ');
671
+
672
+ if (OS.mac) {
673
+ return normalizedShortcut.replace(/ctrl|cmd/gi, '⌘').replace(/alt/gi, '⌥');
674
+ }
675
+
676
+ return normalizedShortcut.replace(/cmd/gi, 'Ctrl').replace(/windows/gi, 'WIN');
677
+ };
678
+
679
+ /**
680
+ * Returns valid URL. If it is going outside and valid, it returns itself
681
+ * If url has `one slash`, then it concatenates with window location origin
682
+ * or when url has `two lack` it appends only protocol
683
+ * @param {string} url - url to prettify
684
+ */
685
+ export const getValidUrl = (url: string): string => {
686
+ try {
687
+ const urlObject = new URL(url);
688
+
689
+ return urlObject.href;
690
+ } catch (_e) {
691
+ // do nothing but handle below
692
+ }
693
+
694
+ const win = getGlobalWindow();
695
+
696
+ if (url.substring(0, 2) === '//') {
697
+ return win ? `${win.location.protocol}${url}` : url;
698
+ }
699
+
700
+ return win ? `${win.location.origin}${url}` : url;
701
+ };
702
+
703
+ /**
704
+ * Create a block id
705
+ * @returns {string}
706
+ */
707
+ export const generateBlockId = (): string => {
708
+ const idLen = 10;
709
+
710
+ return nanoid(idLen);
711
+ };
712
+
713
+ /**
714
+ * Opens new Tab with passed URL
715
+ * @param {string} url - URL address to redirect
716
+ */
717
+ export const openTab = (url: string): void => {
718
+ const win = getGlobalWindow();
719
+
720
+ if (!win) {
721
+ return;
722
+ }
723
+
724
+ win.open(url, '_blank');
725
+ };
726
+
727
+ /**
728
+ * Returns random generated identifier
729
+ * @param {string} prefix - identifier prefix
730
+ * @returns {string}
731
+ */
732
+ export const generateId = (prefix = ''): string => {
733
+ return `${prefix}${(Math.floor(Math.random() * ID_RANDOM_MULTIPLIER)).toString(HEXADECIMAL_RADIX)}`;
734
+ };
735
+
736
+
737
+ type CacheableAccessor<Value> = {
738
+ get?: () => Value;
739
+ set?: (value: Value) => void;
740
+ init?: (value: Value) => Value;
741
+ };
742
+
743
+ type Stage3DecoratorContext = {
744
+ kind: 'method' | 'getter' | 'setter' | 'accessor';
745
+ name: string | symbol;
746
+ static?: boolean;
747
+ private?: boolean;
748
+ access?: {
749
+ get?: () => unknown;
750
+ set?: (value: unknown) => void;
751
+ };
752
+ };
753
+
754
+ type CacheableDecorator = {
755
+ <Member>(
756
+ target: object,
757
+ propertyKey: string | symbol,
758
+ descriptor?: TypedPropertyDescriptor<Member>
759
+ ): TypedPropertyDescriptor<Member> | void;
760
+ <Value = unknown, Arguments extends unknown[] = unknown[]>(
761
+ value: ((...args: Arguments) => Value) | CacheableAccessor<Value>,
762
+ context: Stage3DecoratorContext
763
+ ):
764
+ | ((...args: Arguments) => Value)
765
+ | CacheableAccessor<Value>;
766
+ };
767
+
768
+ const ensureCacheValue = <Value>(
769
+ holder: object,
770
+ cacheKey: string | symbol,
771
+ compute: () => Value
772
+ ): Value => {
773
+ if (!Reflect.has(holder, cacheKey)) {
774
+ Object.defineProperty(holder, cacheKey, {
775
+ configurable: true,
776
+ writable: true,
777
+ value: compute(),
778
+ });
779
+ }
780
+
781
+ return Reflect.get(holder, cacheKey) as Value;
782
+ };
783
+
784
+ const clearCacheValue = (holder: object, cacheKey: string | symbol): void => {
785
+ if (Reflect.has(holder, cacheKey)) {
786
+ Reflect.deleteProperty(holder, cacheKey);
787
+ }
788
+ };
789
+
790
+ const isStage3DecoratorContext = (context: unknown): context is Stage3DecoratorContext => {
791
+ if (typeof context !== 'object' || context === null) {
792
+ return false;
793
+ }
794
+
795
+ return 'kind' in context && 'name' in context;
796
+ };
797
+
798
+ const buildLegacyCacheableDescriptor = (
799
+ target: Record<PropertyKey, unknown>,
800
+ propertyKey: string | symbol,
801
+ descriptor?: TypedPropertyDescriptor<unknown>
802
+ ): TypedPropertyDescriptor<unknown> => {
803
+ const baseDescriptor =
804
+ descriptor ??
805
+ Object.getOwnPropertyDescriptor(target, propertyKey) ??
806
+ (typeof target === 'function'
807
+ ? Object.getOwnPropertyDescriptor((target as unknown as { prototype?: object }).prototype ?? {}, propertyKey)
808
+ : undefined) ??
809
+ {
810
+ configurable: true,
811
+ enumerable: false,
812
+ writable: true,
813
+ value: Reflect.get(target, propertyKey),
814
+ };
815
+
816
+ const descriptorRef = { ...baseDescriptor } as TypedPropertyDescriptor<unknown>;
817
+ const cacheKey: string | symbol = typeof propertyKey === 'symbol' ? propertyKey : `#${propertyKey}Cache`;
818
+ const hasMethodValue = descriptorRef.value !== undefined && typeof descriptorRef.value === 'function';
819
+ const shouldWrapGetter = !hasMethodValue && descriptorRef.get !== undefined;
820
+ const shouldWrapSetter = shouldWrapGetter && descriptorRef.set !== undefined;
821
+
822
+ if (hasMethodValue) {
823
+ const originalMethod = descriptorRef.value as (...methodArgs: unknown[]) => unknown;
824
+
825
+ descriptorRef.value = function (this: object, ...methodArgs: unknown[]): unknown {
826
+ return ensureCacheValue(this, cacheKey, () => originalMethod.apply(this, methodArgs));
827
+ } as typeof originalMethod;
828
+ }
829
+
830
+ if (shouldWrapGetter && descriptorRef.get !== undefined) {
831
+ const originalGetter = descriptorRef.get as () => unknown;
832
+
833
+ descriptorRef.get = function (this: object): unknown {
834
+ return ensureCacheValue(this, cacheKey, () => originalGetter.call(this));
835
+ } as typeof originalGetter;
836
+ }
837
+
838
+ if (shouldWrapSetter && descriptorRef.set !== undefined) {
839
+ const originalSetter = descriptorRef.set;
840
+
841
+ descriptorRef.set = function (this: object, newValue: unknown): void {
842
+ clearCacheValue(this, cacheKey);
843
+ originalSetter.call(this, newValue);
844
+ } as typeof originalSetter;
845
+ }
846
+
847
+ if (!descriptor) {
848
+ return descriptorRef;
849
+ }
850
+
851
+ Object.keys(descriptor).forEach(propertyName => {
852
+ if (!(propertyName in descriptorRef)) {
853
+ Reflect.deleteProperty(descriptor, propertyName as keyof PropertyDescriptor);
854
+ }
855
+ });
856
+
857
+ Object.assign(descriptor, descriptorRef);
858
+
859
+ return descriptor;
860
+ };
861
+
862
+ const applyStage3CacheableDecorator = (
863
+ value: ((...methodArgs: unknown[]) => unknown) | CacheableAccessor<unknown>,
864
+ context: Stage3DecoratorContext
865
+ ): unknown => {
866
+ const cacheKey = Symbol(
867
+ typeof context.name === 'symbol'
868
+ ? `cache:${context.name.description ?? 'symbol'}`
869
+ : `cache:${context.name}`
870
+ );
871
+
872
+ if (context.kind === 'method' && typeof value === 'function') {
873
+ const originalMethod = value as (...methodArgs: unknown[]) => unknown;
874
+
875
+ return function (this: object, ...methodArgs: unknown[]): unknown {
876
+ return ensureCacheValue(this, cacheKey, () => originalMethod.apply(this, methodArgs));
877
+ } as typeof originalMethod;
878
+ }
879
+
880
+ if (context.kind === 'getter' && typeof value === 'function') {
881
+ const originalGetter = value as () => unknown;
882
+
883
+ return function (this: object): unknown {
884
+ return ensureCacheValue(this, cacheKey, () => originalGetter.call(this));
885
+ } as typeof originalGetter;
886
+ }
887
+
888
+ if (context.kind === 'accessor' && typeof value === 'object' && value !== null) {
889
+ const accessor = value as CacheableAccessor<unknown>;
890
+ const fallbackGetter = accessor.get ?? context.access?.get;
891
+ const fallbackSetter = accessor.set ?? context.access?.set;
892
+
893
+ return {
894
+ get(this: object): unknown {
895
+ return fallbackGetter
896
+ ? ensureCacheValue(this, cacheKey, () => fallbackGetter.call(this))
897
+ : undefined;
898
+ },
899
+ set(this: object, newValue: unknown): void {
900
+ clearCacheValue(this, cacheKey);
901
+ fallbackSetter?.call(this, newValue);
902
+ },
903
+ init(initialValue: unknown): unknown {
904
+ return accessor.init ? accessor.init(initialValue) : initialValue;
905
+ },
906
+ } satisfies CacheableAccessor<unknown>;
907
+ }
908
+
909
+ return value;
910
+ };
911
+
912
+ /**
913
+ * Decorator which provides ability to cache method or accessor result.
914
+ * Supports both legacy and TC39 stage 3 decorator semantics.
915
+ * @param args - decorator arguments (legacy: target, propertyKey, descriptor. Stage 3: value, context)
916
+ */
917
+ const cacheableImpl = (...args: unknown[]): unknown => {
918
+ if (args.length === 2 && isStage3DecoratorContext(args[1])) {
919
+ const [value, context] = args as [
920
+ ((...methodArgs: unknown[]) => unknown) | CacheableAccessor<unknown>,
921
+ Stage3DecoratorContext
922
+ ];
923
+
924
+ return applyStage3CacheableDecorator(value, context);
925
+ }
926
+
927
+ const [target, propertyKey, descriptor] = args as [
928
+ Record<PropertyKey, unknown>,
929
+ string | symbol,
930
+ TypedPropertyDescriptor<unknown> | undefined
931
+ ];
932
+
933
+ return buildLegacyCacheableDescriptor(target, propertyKey, descriptor);
934
+ };
935
+
936
+ export const cacheable = cacheableImpl as CacheableDecorator;
937
+
938
+ /**
939
+ * All screens below this width will be treated as mobile;
940
+ */
941
+ export const mobileScreenBreakpoint = 650;
942
+
943
+ /**
944
+ * True if screen has mobile size
945
+ */
946
+ export const isMobileScreen = (): boolean => {
947
+ const win = getGlobalWindow();
948
+
949
+ if (!win || typeof win.matchMedia !== 'function') {
950
+ return false;
951
+ }
952
+
953
+ return win.matchMedia(`(max-width: ${mobileScreenBreakpoint}px)`).matches;
954
+ };
955
+
956
+ /**
957
+ * True if current device runs iOS
958
+ */
959
+ export const isIosDevice = (() => {
960
+ const navigatorRef = getGlobalNavigator();
961
+
962
+ if (!navigatorRef) {
963
+ return false;
964
+ }
965
+
966
+ const userAgent = navigatorRef.userAgent || '';
967
+
968
+ // Use modern User-Agent Client Hints API if available
969
+ const userAgentData = (navigatorRef as Navigator & { userAgentData?: { platform?: string } }).userAgentData;
970
+ const platform = userAgentData?.platform;
971
+
972
+ // Check userAgent string first (most reliable method)
973
+ if (/iP(ad|hone|od)/.test(userAgent)) {
974
+ return true;
975
+ }
976
+
977
+ // Check platform from User-Agent Client Hints API if available
978
+ if (platform !== undefined && platform !== '' && /iP(ad|hone|od)/.test(platform)) {
979
+ return true;
980
+ }
981
+
982
+ // Check for iPad on iOS 13+ (reports as MacIntel with touch support)
983
+ // Only access deprecated platform property when necessary
984
+ const hasTouchSupport = (navigatorRef.maxTouchPoints ?? 0) > 1;
985
+ const getLegacyPlatform = (): string | undefined =>
986
+ // eslint-disable-next-line @typescript-eslint/no-deprecated -- Fallback for older browsers that don't support User-Agent Client Hints
987
+ (navigatorRef as Navigator & { platform?: string })['platform'];
988
+ const platformHint = platform !== undefined && platform !== '' ? platform : undefined;
989
+ const platformValue = hasTouchSupport ? platformHint ?? getLegacyPlatform() : undefined;
990
+
991
+ if (platformValue === 'MacIntel') {
992
+ return true;
993
+ }
994
+
995
+ return false;
996
+ })();
997
+
998
+ /**
999
+ * Compares two arrays deeply for equality
1000
+ * @param arr1 - first array
1001
+ * @param arr2 - second array
1002
+ * @returns {boolean} true if arrays are equal
1003
+ */
1004
+ const arraysEqual = (arr1: unknown[], arr2: unknown[]): boolean => {
1005
+ if (arr1.length !== arr2.length) {
1006
+ return false;
1007
+ }
1008
+
1009
+ return arr1.every((item, index) => equals(item, arr2[index]));
1010
+ };
1011
+
1012
+ /**
1013
+ * Compares two values deeply for equality
1014
+ * @param var1 - value to compare
1015
+ * @param var2 - value to compare with
1016
+ * @returns {boolean} true if they are equal
1017
+ */
1018
+ export const equals = (var1: unknown, var2: unknown): boolean => {
1019
+ if (var1 === var2) {
1020
+ return true;
1021
+ }
1022
+
1023
+ if (var1 === null || var2 === null || typeof var1 !== 'object' || typeof var2 !== 'object') {
1024
+ return false;
1025
+ }
1026
+
1027
+ if (Array.isArray(var1) !== Array.isArray(var2)) {
1028
+ return false;
1029
+ }
1030
+
1031
+ if (Array.isArray(var1) && Array.isArray(var2)) {
1032
+ return arraysEqual(var1, var2);
1033
+ }
1034
+
1035
+ const keys1 = Object.keys(var1);
1036
+ const keys2 = Object.keys(var2);
1037
+
1038
+ if (keys1.length !== keys2.length) {
1039
+ return false;
1040
+ }
1041
+
1042
+ return keys1.every((key) =>
1043
+ Object.prototype.hasOwnProperty.call(var2, key) &&
1044
+ equals((var1 as Record<string, unknown>)[key], (var2 as Record<string, unknown>)[key])
1045
+ );
1046
+ };
1047
+
1048
+ /**
1049
+ * Strips fake background wrapper elements from HTML content.
1050
+ * These elements are used by the inline toolbar for visual selection highlighting
1051
+ * and should not be persisted in saved data.
1052
+ * @param html - HTML content that may contain fake background elements
1053
+ * @returns HTML content with fake background wrappers removed but their content preserved
1054
+ */
1055
+ export const stripFakeBackgroundElements = (html: string): string => {
1056
+ if (!html || !html.includes('data-blok-fake-background')) {
1057
+ return html;
1058
+ }
1059
+
1060
+ const tempDiv = document.createElement('div');
1061
+
1062
+ tempDiv.innerHTML = html;
1063
+
1064
+ const fakeBackgrounds = tempDiv.querySelectorAll('[data-blok-fake-background="true"]');
1065
+
1066
+ fakeBackgrounds.forEach((element) => {
1067
+ const parent = element.parentNode;
1068
+
1069
+ if (!parent) {
1070
+ return;
1071
+ }
1072
+
1073
+ while (element.firstChild) {
1074
+ parent.insertBefore(element.firstChild, element);
1075
+ }
1076
+
1077
+ parent.removeChild(element);
1078
+ });
1079
+
1080
+ return tempDiv.innerHTML;
1081
+ };