@jackuait/blok 0.4.1-beta.5 → 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-Cl_5rkKS.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 +59 -156
  149. package/package.json +48 -16
  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 +0 -5
  381. package/types/configs/blok-config.d.ts +21 -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 +0 -5
  399. package/dist/blok-DvN73wsH.mjs +0 -19922
  400. package/dist/blok.umd.js +0 -166
@@ -0,0 +1,250 @@
1
+ import type { Meta, StoryObj } from '@storybook/html-vite';
2
+ import { waitFor, expect } from 'storybook/test';
3
+ import type { OutputData } from '@/types';
4
+ import { createEditorContainer, simulateClick, waitForToolbar } from './helpers';
5
+ import type { EditorFactoryOptions } from './helpers';
6
+
7
+ interface SelectionArgs extends EditorFactoryOptions {
8
+ minHeight: number;
9
+ data: OutputData | undefined;
10
+ }
11
+
12
+ // Constants
13
+ const BLOCK_TESTID = '[data-blok-testid="block-wrapper"]';
14
+ const INLINE_TOOLBAR_TESTID = '[data-blok-testid="inline-toolbar"]';
15
+ const INLINE_TOOL_INPUT_TESTID = '[data-blok-testid="inline-tool-input"]';
16
+ const CONTENTEDITABLE_SELECTOR = '[contenteditable="true"]';
17
+ const LINK_TOOL_SELECTOR = '[data-blok-item-name="link"]';
18
+
19
+ const TIMEOUT_INIT = { timeout: 5000 };
20
+ const TIMEOUT_ACTION = { timeout: 5000 };
21
+
22
+ const multiLineData: OutputData = {
23
+ time: Date.now(),
24
+ version: '1.0.0',
25
+ blocks: [
26
+ {
27
+ id: 'multi-line-block',
28
+ type: 'paragraph',
29
+ data: {
30
+ text: 'This is the first line of text that spans multiple words. Here is the second sentence with more content. And finally a third sentence to make it longer.',
31
+ },
32
+ },
33
+ ],
34
+ };
35
+
36
+ const multiBlockData: OutputData = {
37
+ time: Date.now(),
38
+ version: '1.0.0',
39
+ blocks: [
40
+ {
41
+ id: 'block-1',
42
+ type: 'paragraph',
43
+ data: { text: 'First paragraph with some text to select from here.' },
44
+ },
45
+ {
46
+ id: 'block-2',
47
+ type: 'paragraph',
48
+ data: { text: 'Second paragraph continues the selection across blocks.' },
49
+ },
50
+ {
51
+ id: 'block-3',
52
+ type: 'paragraph',
53
+ data: { text: 'Third paragraph ends the cross-block selection here.' },
54
+ },
55
+ ],
56
+ };
57
+
58
+ const createEditor = (args: SelectionArgs): HTMLElement => createEditorContainer(args);
59
+
60
+ const meta: Meta<SelectionArgs> = {
61
+ title: 'Components/Selection',
62
+ tags: ['autodocs'],
63
+ args: {
64
+ minHeight: 300,
65
+ data: multiLineData,
66
+ },
67
+ render: createEditor,
68
+ };
69
+
70
+ export default meta;
71
+
72
+
73
+ type Story = StoryObj<SelectionArgs>;
74
+
75
+ /**
76
+ * Selects text across multiple words/strings and opens the link input.
77
+ * This demonstrates the fake background selection behavior when focus moves to the link input.
78
+ */
79
+ export const MultiStringSelectionWithLinkInput: Story = {
80
+ args: {
81
+ data: multiLineData,
82
+ },
83
+ play: async ({ canvasElement, step }) => {
84
+ await step('Wait for editor and toolbar to initialize', async () => {
85
+ await waitFor(
86
+ () => {
87
+ const block = canvasElement.querySelector(BLOCK_TESTID);
88
+
89
+ expect(block).toBeInTheDocument();
90
+ },
91
+ TIMEOUT_INIT
92
+ );
93
+ await waitForToolbar(canvasElement);
94
+ });
95
+
96
+ await step('Select text spanning multiple words', async () => {
97
+ const block = canvasElement.querySelector(BLOCK_TESTID);
98
+ const contentEditable = block?.querySelector(CONTENTEDITABLE_SELECTOR);
99
+
100
+ if (contentEditable) {
101
+ simulateClick(contentEditable);
102
+
103
+ const range = document.createRange();
104
+ const textNode = contentEditable.firstChild;
105
+
106
+ if (textNode && textNode.nodeType === Node.TEXT_NODE) {
107
+ // Select "first line of text that spans multiple words" (characters 12-54)
108
+ range.setStart(textNode, 12);
109
+ range.setEnd(textNode, 54);
110
+ } else {
111
+ range.selectNodeContents(contentEditable);
112
+ }
113
+
114
+ const selection = window.getSelection();
115
+
116
+ selection?.removeAllRanges();
117
+ selection?.addRange(range);
118
+
119
+ (contentEditable as HTMLElement).focus();
120
+ document.dispatchEvent(new Event('selectionchange'));
121
+ }
122
+
123
+ // Wait for debounced selection handler
124
+ await new Promise((resolve) => setTimeout(resolve, 300));
125
+
126
+ await waitFor(
127
+ () => {
128
+ const inlineToolbar = document.querySelector(INLINE_TOOLBAR_TESTID);
129
+
130
+ expect(inlineToolbar).toBeInTheDocument();
131
+ },
132
+ TIMEOUT_ACTION
133
+ );
134
+ });
135
+
136
+ await step('Click link tool to open input', async () => {
137
+ const linkTool = document.querySelector(LINK_TOOL_SELECTOR);
138
+
139
+ expect(linkTool).toBeInTheDocument();
140
+
141
+ if (linkTool) {
142
+ (linkTool as HTMLElement).click();
143
+ }
144
+
145
+ await waitFor(
146
+ () => {
147
+ const linkInput = document.querySelector(INLINE_TOOL_INPUT_TESTID);
148
+
149
+ expect(linkInput).toBeInTheDocument();
150
+
151
+ // Verify fake background is applied to maintain visual selection
152
+ const fakeBackground = document.querySelector('[data-blok-fake-background="true"]');
153
+
154
+ expect(fakeBackground).toBeInTheDocument();
155
+ },
156
+ TIMEOUT_ACTION
157
+ );
158
+ });
159
+ },
160
+ };
161
+
162
+ /**
163
+ * Selects text across multiple blocks/paragraphs and opens the link input.
164
+ * This demonstrates cross-block selection with fake background when focus moves to the link input.
165
+ */
166
+ export const CrossBlockSelectionWithLinkInput: Story = {
167
+ args: {
168
+ data: multiBlockData,
169
+ },
170
+ play: async ({ canvasElement, step }) => {
171
+ await step('Wait for editor and toolbar to initialize', async () => {
172
+ await waitFor(
173
+ () => {
174
+ const blocks = canvasElement.querySelectorAll(BLOCK_TESTID);
175
+
176
+ expect(blocks.length).toBeGreaterThanOrEqual(3);
177
+ },
178
+ TIMEOUT_INIT
179
+ );
180
+ await waitForToolbar(canvasElement);
181
+ });
182
+
183
+ await step('Select text across multiple blocks', async () => {
184
+ const blocks = canvasElement.querySelectorAll(BLOCK_TESTID);
185
+ const firstBlock = blocks[0];
186
+ const lastBlock = blocks[2];
187
+
188
+ const firstContentEditable = firstBlock?.querySelector(CONTENTEDITABLE_SELECTOR);
189
+ const lastContentEditable = lastBlock?.querySelector(CONTENTEDITABLE_SELECTOR);
190
+
191
+ if (firstContentEditable && lastContentEditable) {
192
+ simulateClick(firstContentEditable);
193
+
194
+ const range = document.createRange();
195
+ const firstTextNode = firstContentEditable.firstChild;
196
+ const lastTextNode = lastContentEditable.firstChild;
197
+
198
+ if (firstTextNode && lastTextNode) {
199
+ // Select from "some text" in first block to "cross-block" in third block
200
+ range.setStart(firstTextNode, 22);
201
+ range.setEnd(lastTextNode, 35);
202
+ }
203
+
204
+ const selection = window.getSelection();
205
+
206
+ selection?.removeAllRanges();
207
+ selection?.addRange(range);
208
+
209
+ (firstContentEditable as HTMLElement).focus();
210
+ document.dispatchEvent(new Event('selectionchange'));
211
+ }
212
+
213
+ // Wait for debounced selection handler
214
+ await new Promise((resolve) => setTimeout(resolve, 300));
215
+
216
+ await waitFor(
217
+ () => {
218
+ const inlineToolbar = document.querySelector(INLINE_TOOLBAR_TESTID);
219
+
220
+ expect(inlineToolbar).toBeInTheDocument();
221
+ },
222
+ TIMEOUT_ACTION
223
+ );
224
+ });
225
+
226
+ await step('Click link tool to open input', async () => {
227
+ const linkTool = document.querySelector(LINK_TOOL_SELECTOR);
228
+
229
+ expect(linkTool).toBeInTheDocument();
230
+
231
+ if (linkTool) {
232
+ (linkTool as HTMLElement).click();
233
+ }
234
+
235
+ await waitFor(
236
+ () => {
237
+ const linkInput = document.querySelector(INLINE_TOOL_INPUT_TESTID);
238
+
239
+ expect(linkInput).toBeInTheDocument();
240
+
241
+ // Verify fake background is applied to maintain visual selection across blocks
242
+ const fakeBackgrounds = document.querySelectorAll('[data-blok-fake-background="true"]');
243
+
244
+ expect(fakeBackgrounds.length).toBeGreaterThan(0);
245
+ },
246
+ TIMEOUT_ACTION
247
+ );
248
+ });
249
+ },
250
+ };
@@ -0,0 +1,156 @@
1
+ /**
2
+ * StubBlock.stories.ts - Stories for stub block component.
3
+ *
4
+ * The stub block is displayed when a block's tool is not found/registered.
5
+ * It shows an error state with the tool name and preserves the original data.
6
+ */
7
+ import type { Meta, StoryObj } from '@storybook/html-vite';
8
+ import { waitFor, expect } from 'storybook/test';
9
+ import type { OutputData } from '@/types';
10
+ import { createEditorContainer } from './helpers';
11
+ import type { EditorFactoryOptions } from './helpers';
12
+
13
+ interface StubBlockArgs extends EditorFactoryOptions {
14
+ minHeight: number;
15
+ data: OutputData;
16
+ }
17
+
18
+ const TIMEOUT_INIT = { timeout: 5000 };
19
+
20
+ /**
21
+ * Sample data with a block type that has no registered tool
22
+ */
23
+ const stubBlockData: OutputData = {
24
+ time: Date.now(),
25
+ version: '1.0.0',
26
+ blocks: [
27
+ {
28
+ id: 'stub-block-1',
29
+ type: 'paragraph',
30
+ data: { text: 'This is a regular paragraph block.' },
31
+ },
32
+ {
33
+ id: 'stub-block-2',
34
+ type: 'unknownTool', // This tool doesn't exist - will show stub
35
+ data: { someData: 'preserved data for unknown tool' },
36
+ },
37
+ {
38
+ id: 'stub-block-3',
39
+ type: 'paragraph',
40
+ data: { text: 'Another regular paragraph after the stub.' },
41
+ },
42
+ ],
43
+ };
44
+
45
+ const createEditor = (args: StubBlockArgs): HTMLElement => createEditorContainer(args);
46
+
47
+ const meta: Meta<StubBlockArgs> = {
48
+ title: 'Components/Stub Block',
49
+ tags: ['autodocs'],
50
+ args: {
51
+ minHeight: 300,
52
+ data: stubBlockData,
53
+ },
54
+ render: createEditor,
55
+ };
56
+
57
+ export default meta;
58
+
59
+
60
+ type Story = StoryObj<StubBlockArgs>;
61
+
62
+ /**
63
+ * Stub block shown when tool is not registered.
64
+ * Displays warning icon, tool name, and error message.
65
+ */
66
+ export const MissingTool: Story = {
67
+ args: {
68
+ data: stubBlockData,
69
+ },
70
+ play: async ({ canvasElement, step }) => {
71
+ await step('Wait for stub block to render', async () => {
72
+ await waitFor(
73
+ () => {
74
+ // Look for the stub block by its data attribute
75
+ const stubBlock = canvasElement.querySelector('[data-blok-stub]');
76
+
77
+ expect(stubBlock).toBeTruthy();
78
+ },
79
+ TIMEOUT_INIT
80
+ );
81
+ });
82
+
83
+ await step('Verify stub block structure', async () => {
84
+ const stubBlock = canvasElement.querySelector('[data-blok-stub]');
85
+ const title = stubBlock?.querySelector('[data-blok-stub-title]');
86
+ const subtitle = stubBlock?.querySelector('[data-blok-stub-subtitle]');
87
+
88
+ expect(title).toBeTruthy();
89
+ expect(subtitle).toBeTruthy();
90
+ });
91
+ },
92
+ };
93
+
94
+ /**
95
+ * Multiple stub blocks for different missing tools.
96
+ */
97
+ export const MultipleMissingTools: Story = {
98
+ args: {
99
+ data: {
100
+ time: Date.now(),
101
+ version: '1.0.0',
102
+ blocks: [
103
+ {
104
+ id: 'multi-stub-1',
105
+ type: 'customImage', // Missing tool
106
+ data: { url: 'https://example.com/image.jpg' },
107
+ },
108
+ {
109
+ id: 'multi-stub-2',
110
+ type: 'customVideo', // Missing tool
111
+ data: { videoId: 'abc123' },
112
+ },
113
+ {
114
+ id: 'multi-stub-3',
115
+ type: 'customEmbed', // Missing tool
116
+ data: { embedCode: '<iframe></iframe>' },
117
+ },
118
+ ],
119
+ },
120
+ },
121
+ play: async ({ canvasElement, step }) => {
122
+ await step('Wait for all stub blocks to render', async () => {
123
+ await waitFor(
124
+ () => {
125
+ // Count stub wrapper elements by data attribute
126
+ const stubWrappers = canvasElement.querySelectorAll('[data-blok-stub]');
127
+
128
+ expect(stubWrappers.length).toBe(3);
129
+ },
130
+ TIMEOUT_INIT
131
+ );
132
+ });
133
+ },
134
+ };
135
+
136
+ /**
137
+ * Stub block in read-only mode.
138
+ */
139
+ export const StubInReadOnly: Story = {
140
+ args: {
141
+ data: stubBlockData,
142
+ readOnly: true,
143
+ },
144
+ play: async ({ canvasElement, step }) => {
145
+ await step('Wait for stub block in read-only mode', async () => {
146
+ await waitFor(
147
+ () => {
148
+ const stubBlock = canvasElement.querySelector('[data-blok-stub]');
149
+
150
+ expect(stubBlock).toBeTruthy();
151
+ },
152
+ TIMEOUT_INIT
153
+ );
154
+ });
155
+ },
156
+ };
@@ -0,0 +1,223 @@
1
+ import type { Meta, StoryObj } from '@storybook/html-vite';
2
+ import { userEvent, waitFor, expect } from 'storybook/test';
3
+ import type { OutputData } from '@/types';
4
+ import { createEditorContainer, simulateClick, waitForToolbar, TOOLBAR_TESTID } from './helpers';
5
+ import type { EditorFactoryOptions } from './helpers';
6
+
7
+ interface ToolbarArgs extends EditorFactoryOptions {
8
+ minHeight: number;
9
+ data: OutputData | undefined;
10
+ }
11
+
12
+ // Constants to avoid duplicate strings
13
+ const BLOCK_TESTID = '[data-blok-testid="block-wrapper"]';
14
+ const ACTIONS_TESTID = '[data-blok-testid="toolbar-actions"]';
15
+ const PLUS_BUTTON_TESTID = '[data-blok-testid="plus-button"]';
16
+ const SETTINGS_BUTTON_TESTID = '[data-blok-testid="settings-toggler"]';
17
+
18
+ const TIMEOUT_INIT = { timeout: 5000 };
19
+ const TIMEOUT_ACTION = { timeout: 5000 };
20
+
21
+ const sampleData: OutputData = {
22
+ time: Date.now(),
23
+ version: '1.0.0',
24
+ blocks: [
25
+ {
26
+ id: 'toolbar-block-1',
27
+ type: 'paragraph',
28
+ data: { text: 'First paragraph block for toolbar testing.' },
29
+ },
30
+ {
31
+ id: 'toolbar-block-2',
32
+ type: 'paragraph',
33
+ data: { text: 'Second paragraph block.' },
34
+ },
35
+ {
36
+ id: 'toolbar-block-3',
37
+ type: 'paragraph',
38
+ data: { text: 'Third paragraph block.' },
39
+ },
40
+ ],
41
+ };
42
+
43
+ const createEditor = (args: ToolbarArgs): HTMLElement => createEditorContainer(args);
44
+
45
+ const meta: Meta<ToolbarArgs> = {
46
+ title: 'Components/Toolbar',
47
+ tags: ['autodocs'],
48
+ args: {
49
+ minHeight: 300,
50
+ data: sampleData,
51
+ },
52
+ render: createEditor,
53
+ };
54
+
55
+ export default meta;
56
+
57
+
58
+ type Story = StoryObj<ToolbarArgs>;
59
+
60
+ /**
61
+ * Default state: Toolbar is hidden until a block is focused/hovered.
62
+ */
63
+ export const Default: Story = {
64
+ args: {
65
+ data: sampleData,
66
+ },
67
+ };
68
+
69
+ /**
70
+ * Toolbar visible with actions zone shown when block is hovered.
71
+ */
72
+ export const ToolbarVisible: Story = {
73
+ args: {
74
+ data: sampleData,
75
+ },
76
+ play: async ({ canvasElement, step }) => {
77
+ await step('Wait for editor and toolbar to initialize', async () => {
78
+ await waitFor(
79
+ () => {
80
+ const block = canvasElement.querySelector(BLOCK_TESTID);
81
+
82
+ expect(block).toBeInTheDocument();
83
+ },
84
+ TIMEOUT_INIT
85
+ );
86
+ // Wait for toolbar to be created (happens in requestIdleCallback)
87
+ await waitForToolbar(canvasElement);
88
+ });
89
+
90
+ await step('Click on a block to show toolbar', async () => {
91
+ const block = canvasElement.querySelector(BLOCK_TESTID);
92
+
93
+ if (block) {
94
+ simulateClick(block);
95
+ }
96
+
97
+ await waitFor(
98
+ () => {
99
+ const toolbar = canvasElement.querySelector(TOOLBAR_TESTID);
100
+
101
+ expect(toolbar).toBeInTheDocument();
102
+ expect(toolbar).toHaveAttribute('data-blok-opened', 'true');
103
+ },
104
+ TIMEOUT_ACTION
105
+ );
106
+ });
107
+
108
+ await step('Verify actions zone is visible', async () => {
109
+ await waitFor(
110
+ () => {
111
+ const actionsZone = canvasElement.querySelector(ACTIONS_TESTID);
112
+
113
+ expect(actionsZone).toBeInTheDocument();
114
+ },
115
+ TIMEOUT_ACTION
116
+ );
117
+ });
118
+ },
119
+ };
120
+
121
+ /**
122
+ * Plus button hover state.
123
+ */
124
+ export const PlusButtonHover: Story = {
125
+ args: {
126
+ data: sampleData,
127
+ },
128
+ play: async ({ canvasElement, step }) => {
129
+ await step('Wait for editor and toolbar to initialize', async () => {
130
+ await waitFor(
131
+ () => {
132
+ const block = canvasElement.querySelector(BLOCK_TESTID);
133
+
134
+ expect(block).toBeInTheDocument();
135
+ },
136
+ TIMEOUT_INIT
137
+ );
138
+ // Wait for toolbar to be created (happens in requestIdleCallback)
139
+ await waitForToolbar(canvasElement);
140
+ });
141
+
142
+ await step('Click on block to show toolbar', async () => {
143
+ const block = canvasElement.querySelector(BLOCK_TESTID);
144
+
145
+ if (block) {
146
+ simulateClick(block);
147
+ }
148
+
149
+ await waitFor(
150
+ () => {
151
+ const toolbar = canvasElement.querySelector(TOOLBAR_TESTID);
152
+
153
+ expect(toolbar).toHaveAttribute('data-blok-opened', 'true');
154
+ },
155
+ TIMEOUT_ACTION
156
+ );
157
+ });
158
+
159
+ await step('Hover plus button', async () => {
160
+ const plusButton = canvasElement.querySelector(PLUS_BUTTON_TESTID);
161
+
162
+ if (plusButton) {
163
+ await userEvent.hover(plusButton);
164
+ }
165
+ });
166
+ },
167
+ };
168
+
169
+ /*
170
+ * NOTE: Toolbox opened state lives in EditorModes.stories.ts (ToolboxOpenedMode)
171
+ * Block tunes popover and delete confirmation live in Popover.stories.ts
172
+ * This file focuses on toolbar visibility, button states, and hover interactions.
173
+ */
174
+
175
+ /**
176
+ * Settings button hover state (grab cursor).
177
+ */
178
+ export const SettingsButtonHover: Story = {
179
+ args: {
180
+ data: sampleData,
181
+ },
182
+ play: async ({ canvasElement, step }) => {
183
+ await step('Wait for editor and toolbar to initialize', async () => {
184
+ await waitFor(
185
+ () => {
186
+ const block = canvasElement.querySelector(BLOCK_TESTID);
187
+
188
+ expect(block).toBeInTheDocument();
189
+ },
190
+ TIMEOUT_INIT
191
+ );
192
+ // Wait for toolbar to be created (happens in requestIdleCallback)
193
+ await waitForToolbar(canvasElement);
194
+ });
195
+
196
+ await step('Click on block to show toolbar', async () => {
197
+ const block = canvasElement.querySelector(BLOCK_TESTID);
198
+
199
+ if (block) {
200
+ simulateClick(block);
201
+ }
202
+
203
+ await waitFor(
204
+ () => {
205
+ const actionsZone = canvasElement.querySelector(ACTIONS_TESTID);
206
+
207
+ expect(actionsZone).toBeInTheDocument();
208
+ },
209
+ TIMEOUT_ACTION
210
+ );
211
+ });
212
+
213
+ await step('Hover settings button', async () => {
214
+ const settingsButton = canvasElement.querySelector(SETTINGS_BUTTON_TESTID);
215
+
216
+ if (settingsButton) {
217
+ await userEvent.hover(settingsButton);
218
+ }
219
+ });
220
+ },
221
+ };
222
+
223
+