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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (400) hide show
  1. package/README.md +136 -17
  2. package/codemod/README.md +16 -0
  3. package/codemod/migrate-editorjs-to-blok.js +868 -92
  4. package/codemod/test.js +682 -77
  5. package/dist/blok.mjs +5 -2
  6. package/dist/chunks/blok-B5qs7C5l.mjs +12838 -0
  7. package/dist/chunks/i18next-CugVlwWp.mjs +1292 -0
  8. package/dist/chunks/i18next-loader-CTrK3HzG.mjs +43 -0
  9. package/dist/{index-XWGz4gev.mjs → chunks/index-DDpzQn-0.mjs} +2 -2
  10. package/dist/chunks/inline-tool-convert-RBcopmCh.mjs +1988 -0
  11. package/dist/chunks/messages-2434tVOK.mjs +47 -0
  12. package/dist/chunks/messages-3DcCwXMF.mjs +47 -0
  13. package/dist/chunks/messages-4kMwVAKY.mjs +47 -0
  14. package/dist/chunks/messages-57uL5htT.mjs +47 -0
  15. package/dist/chunks/messages-76-iJV9Q.mjs +47 -0
  16. package/dist/chunks/messages-8p86Eyf2.mjs +47 -0
  17. package/dist/chunks/messages-BBX0p0Pi.mjs +47 -0
  18. package/dist/chunks/messages-BCm2eudQ.mjs +47 -0
  19. package/dist/chunks/messages-BFiUomgG.mjs +47 -0
  20. package/dist/chunks/messages-BIPNHHAV.mjs +47 -0
  21. package/dist/chunks/messages-BUlwu9mo.mjs +47 -0
  22. package/dist/chunks/messages-BX-DPa-z.mjs +47 -0
  23. package/dist/chunks/messages-BextV3Qh.mjs +47 -0
  24. package/dist/chunks/messages-BiPSFlUG.mjs +47 -0
  25. package/dist/chunks/messages-BiXe9G-O.mjs +47 -0
  26. package/dist/chunks/messages-Bl5z_Igo.mjs +47 -0
  27. package/dist/chunks/messages-BnsE97ku.mjs +47 -0
  28. package/dist/chunks/messages-BoO8gsVD.mjs +47 -0
  29. package/dist/chunks/messages-BqWaOGMn.mjs +47 -0
  30. package/dist/chunks/messages-BqkL2_Ro.mjs +47 -0
  31. package/dist/chunks/messages-BvCkXKX-.mjs +47 -0
  32. package/dist/chunks/messages-C6tbPLoj.mjs +47 -0
  33. package/dist/chunks/messages-CA6T3-gQ.mjs +47 -0
  34. package/dist/chunks/messages-CFFPFdWP.mjs +47 -0
  35. package/dist/chunks/messages-CFrKE-TN.mjs +47 -0
  36. package/dist/chunks/messages-CHz8VlG-.mjs +47 -0
  37. package/dist/chunks/messages-CLixzySl.mjs +47 -0
  38. package/dist/chunks/messages-CV7OM_qk.mjs +47 -0
  39. package/dist/chunks/messages-CXHt3eCC.mjs +47 -0
  40. package/dist/chunks/messages-CbmsBrB0.mjs +47 -0
  41. package/dist/chunks/messages-Ceo1KtFx.mjs +47 -0
  42. package/dist/chunks/messages-Cm0LJLtB.mjs +47 -0
  43. package/dist/chunks/messages-CmymP_Ar.mjs +47 -0
  44. package/dist/chunks/messages-D0ohMB5H.mjs +47 -0
  45. package/dist/chunks/messages-D3GrDwXh.mjs +47 -0
  46. package/dist/chunks/messages-D3vTzIpL.mjs +47 -0
  47. package/dist/chunks/messages-D5WeksbV.mjs +47 -0
  48. package/dist/chunks/messages-DGaab4EP.mjs +47 -0
  49. package/dist/chunks/messages-DKha57ZU.mjs +47 -0
  50. package/dist/chunks/messages-DOaujgMW.mjs +47 -0
  51. package/dist/chunks/messages-DVbPLd_0.mjs +47 -0
  52. package/dist/chunks/messages-D_FCyfW6.mjs +47 -0
  53. package/dist/chunks/messages-Dd5iZN3c.mjs +47 -0
  54. package/dist/chunks/messages-DehM7135.mjs +47 -0
  55. package/dist/chunks/messages-Dg1OHftD.mjs +47 -0
  56. package/dist/chunks/messages-Di6Flq-b.mjs +47 -0
  57. package/dist/chunks/messages-Dqhhex6e.mjs +47 -0
  58. package/dist/chunks/messages-DueVe0F1.mjs +47 -0
  59. package/dist/chunks/messages-Dx3eFwI0.mjs +47 -0
  60. package/dist/chunks/messages-FOtiUoKl.mjs +47 -0
  61. package/dist/chunks/messages-FTOZNhRD.mjs +47 -0
  62. package/dist/chunks/messages-IQxGfQIV.mjs +47 -0
  63. package/dist/chunks/messages-JF2fzCkK.mjs +47 -0
  64. package/dist/chunks/messages-MOGl7I5v.mjs +47 -0
  65. package/dist/chunks/messages-QgYhPL-3.mjs +47 -0
  66. package/dist/chunks/messages-WYWIbQwo.mjs +47 -0
  67. package/dist/chunks/messages-a6A_LgDv.mjs +47 -0
  68. package/dist/chunks/messages-bSf31LJi.mjs +47 -0
  69. package/dist/chunks/messages-diGozhTn.mjs +47 -0
  70. package/dist/chunks/messages-er-kd-VO.mjs +47 -0
  71. package/dist/chunks/messages-ez3w5NBn.mjs +47 -0
  72. package/dist/chunks/messages-f3uXjegd.mjs +47 -0
  73. package/dist/chunks/messages-ohwI1UGv.mjs +47 -0
  74. package/dist/chunks/messages-p9BZJaFV.mjs +47 -0
  75. package/dist/chunks/messages-qIQ4L4rw.mjs +47 -0
  76. package/dist/chunks/messages-qWkXPggi.mjs +47 -0
  77. package/dist/chunks/messages-w5foGze_.mjs +47 -0
  78. package/dist/full.mjs +50 -0
  79. package/dist/locales.mjs +227 -0
  80. package/dist/messages-2434tVOK.mjs +47 -0
  81. package/dist/messages-3DcCwXMF.mjs +47 -0
  82. package/dist/messages-4kMwVAKY.mjs +47 -0
  83. package/dist/messages-57uL5htT.mjs +47 -0
  84. package/dist/messages-76-iJV9Q.mjs +47 -0
  85. package/dist/messages-8p86Eyf2.mjs +47 -0
  86. package/dist/messages-BBX0p0Pi.mjs +47 -0
  87. package/dist/messages-BCm2eudQ.mjs +47 -0
  88. package/dist/messages-BFiUomgG.mjs +47 -0
  89. package/dist/messages-BIPNHHAV.mjs +47 -0
  90. package/dist/messages-BUlwu9mo.mjs +47 -0
  91. package/dist/messages-BX-DPa-z.mjs +47 -0
  92. package/dist/messages-BextV3Qh.mjs +47 -0
  93. package/dist/messages-BiPSFlUG.mjs +47 -0
  94. package/dist/messages-BiXe9G-O.mjs +47 -0
  95. package/dist/messages-Bl5z_Igo.mjs +47 -0
  96. package/dist/messages-BnsE97ku.mjs +47 -0
  97. package/dist/messages-BoO8gsVD.mjs +47 -0
  98. package/dist/messages-BqWaOGMn.mjs +47 -0
  99. package/dist/messages-BqkL2_Ro.mjs +47 -0
  100. package/dist/messages-BvCkXKX-.mjs +47 -0
  101. package/dist/messages-C6tbPLoj.mjs +47 -0
  102. package/dist/messages-CA6T3-gQ.mjs +47 -0
  103. package/dist/messages-CFFPFdWP.mjs +47 -0
  104. package/dist/messages-CFrKE-TN.mjs +47 -0
  105. package/dist/messages-CHz8VlG-.mjs +47 -0
  106. package/dist/messages-CLixzySl.mjs +47 -0
  107. package/dist/messages-CV7OM_qk.mjs +47 -0
  108. package/dist/messages-CXHt3eCC.mjs +47 -0
  109. package/dist/messages-CbmsBrB0.mjs +47 -0
  110. package/dist/messages-Ceo1KtFx.mjs +47 -0
  111. package/dist/messages-Cm0LJLtB.mjs +47 -0
  112. package/dist/messages-CmymP_Ar.mjs +47 -0
  113. package/dist/messages-D0ohMB5H.mjs +47 -0
  114. package/dist/messages-D3GrDwXh.mjs +47 -0
  115. package/dist/messages-D3vTzIpL.mjs +47 -0
  116. package/dist/messages-D5WeksbV.mjs +47 -0
  117. package/dist/messages-DGaab4EP.mjs +47 -0
  118. package/dist/messages-DKha57ZU.mjs +47 -0
  119. package/dist/messages-DOaujgMW.mjs +47 -0
  120. package/dist/messages-DVbPLd_0.mjs +47 -0
  121. package/dist/messages-D_FCyfW6.mjs +47 -0
  122. package/dist/messages-Dd5iZN3c.mjs +47 -0
  123. package/dist/messages-DehM7135.mjs +47 -0
  124. package/dist/messages-Dg1OHftD.mjs +47 -0
  125. package/dist/messages-Di6Flq-b.mjs +47 -0
  126. package/dist/messages-Dqhhex6e.mjs +47 -0
  127. package/dist/messages-DueVe0F1.mjs +47 -0
  128. package/dist/messages-Dx3eFwI0.mjs +47 -0
  129. package/dist/messages-FOtiUoKl.mjs +47 -0
  130. package/dist/messages-FTOZNhRD.mjs +47 -0
  131. package/dist/messages-IQxGfQIV.mjs +47 -0
  132. package/dist/messages-JF2fzCkK.mjs +47 -0
  133. package/dist/messages-MOGl7I5v.mjs +47 -0
  134. package/dist/messages-QgYhPL-3.mjs +47 -0
  135. package/dist/messages-WYWIbQwo.mjs +47 -0
  136. package/dist/messages-a6A_LgDv.mjs +47 -0
  137. package/dist/messages-bSf31LJi.mjs +47 -0
  138. package/dist/messages-diGozhTn.mjs +47 -0
  139. package/dist/messages-er-kd-VO.mjs +47 -0
  140. package/dist/messages-ez3w5NBn.mjs +47 -0
  141. package/dist/messages-f3uXjegd.mjs +47 -0
  142. package/dist/messages-ohwI1UGv.mjs +47 -0
  143. package/dist/messages-p9BZJaFV.mjs +47 -0
  144. package/dist/messages-qIQ4L4rw.mjs +47 -0
  145. package/dist/messages-qWkXPggi.mjs +47 -0
  146. package/dist/messages-w5foGze_.mjs +47 -0
  147. package/dist/tools.mjs +3073 -0
  148. package/dist/vendor.LICENSE.txt +26 -225
  149. package/package.json +49 -23
  150. package/src/blok.ts +267 -0
  151. package/src/components/__module.ts +139 -0
  152. package/src/components/block/api.ts +155 -0
  153. package/src/components/block/index.ts +1427 -0
  154. package/src/components/block-tunes/block-tune-delete.ts +51 -0
  155. package/src/components/blocks.ts +338 -0
  156. package/src/components/constants/data-attributes.ts +342 -0
  157. package/src/components/constants.ts +76 -0
  158. package/src/components/core.ts +392 -0
  159. package/src/components/dom.ts +773 -0
  160. package/src/components/domIterator.ts +189 -0
  161. package/src/components/errors/critical.ts +5 -0
  162. package/src/components/events/BlockChanged.ts +16 -0
  163. package/src/components/events/BlockHovered.ts +21 -0
  164. package/src/components/events/BlockSettingsClosed.ts +12 -0
  165. package/src/components/events/BlockSettingsOpened.ts +12 -0
  166. package/src/components/events/BlokMobileLayoutToggled.ts +15 -0
  167. package/src/components/events/FakeCursorAboutToBeToggled.ts +17 -0
  168. package/src/components/events/FakeCursorHaveBeenSet.ts +17 -0
  169. package/src/components/events/HistoryStateChanged.ts +19 -0
  170. package/src/components/events/RedactorDomChanged.ts +14 -0
  171. package/src/components/events/index.ts +46 -0
  172. package/src/components/flipper.ts +481 -0
  173. package/src/components/i18n/i18next-loader.ts +84 -0
  174. package/src/components/i18n/lightweight-i18n.ts +86 -0
  175. package/src/components/i18n/locales/TRANSLATION_GUIDELINES.md +113 -0
  176. package/src/components/i18n/locales/am/messages.json +44 -0
  177. package/src/components/i18n/locales/ar/messages.json +44 -0
  178. package/src/components/i18n/locales/az/messages.json +44 -0
  179. package/src/components/i18n/locales/bg/messages.json +44 -0
  180. package/src/components/i18n/locales/bn/messages.json +44 -0
  181. package/src/components/i18n/locales/bs/messages.json +44 -0
  182. package/src/components/i18n/locales/cs/messages.json +44 -0
  183. package/src/components/i18n/locales/da/messages.json +44 -0
  184. package/src/components/i18n/locales/de/messages.json +44 -0
  185. package/src/components/i18n/locales/dv/messages.json +44 -0
  186. package/src/components/i18n/locales/el/messages.json +44 -0
  187. package/src/components/i18n/locales/en/messages.json +44 -0
  188. package/src/components/i18n/locales/es/messages.json +44 -0
  189. package/src/components/i18n/locales/et/messages.json +44 -0
  190. package/src/components/i18n/locales/fa/messages.json +44 -0
  191. package/src/components/i18n/locales/fi/messages.json +44 -0
  192. package/src/components/i18n/locales/fil/messages.json +44 -0
  193. package/src/components/i18n/locales/fr/messages.json +44 -0
  194. package/src/components/i18n/locales/gu/messages.json +44 -0
  195. package/src/components/i18n/locales/he/messages.json +44 -0
  196. package/src/components/i18n/locales/hi/messages.json +44 -0
  197. package/src/components/i18n/locales/hr/messages.json +44 -0
  198. package/src/components/i18n/locales/hu/messages.json +44 -0
  199. package/src/components/i18n/locales/hy/messages.json +44 -0
  200. package/src/components/i18n/locales/id/messages.json +44 -0
  201. package/src/components/i18n/locales/index.ts +225 -0
  202. package/src/components/i18n/locales/it/messages.json +44 -0
  203. package/src/components/i18n/locales/ja/messages.json +44 -0
  204. package/src/components/i18n/locales/ka/messages.json +44 -0
  205. package/src/components/i18n/locales/km/messages.json +44 -0
  206. package/src/components/i18n/locales/kn/messages.json +44 -0
  207. package/src/components/i18n/locales/ko/messages.json +44 -0
  208. package/src/components/i18n/locales/ku/messages.json +44 -0
  209. package/src/components/i18n/locales/lo/messages.json +44 -0
  210. package/src/components/i18n/locales/lt/messages.json +44 -0
  211. package/src/components/i18n/locales/lv/messages.json +44 -0
  212. package/src/components/i18n/locales/mk/messages.json +44 -0
  213. package/src/components/i18n/locales/ml/messages.json +44 -0
  214. package/src/components/i18n/locales/mn/messages.json +44 -0
  215. package/src/components/i18n/locales/mr/messages.json +44 -0
  216. package/src/components/i18n/locales/ms/messages.json +44 -0
  217. package/src/components/i18n/locales/my/messages.json +44 -0
  218. package/src/components/i18n/locales/ne/messages.json +44 -0
  219. package/src/components/i18n/locales/nl/messages.json +44 -0
  220. package/src/components/i18n/locales/no/messages.json +44 -0
  221. package/src/components/i18n/locales/pa/messages.json +44 -0
  222. package/src/components/i18n/locales/pl/messages.json +44 -0
  223. package/src/components/i18n/locales/ps/messages.json +44 -0
  224. package/src/components/i18n/locales/pt/messages.json +44 -0
  225. package/src/components/i18n/locales/ro/messages.json +44 -0
  226. package/src/components/i18n/locales/ru/messages.json +44 -0
  227. package/src/components/i18n/locales/sd/messages.json +44 -0
  228. package/src/components/i18n/locales/si/messages.json +44 -0
  229. package/src/components/i18n/locales/sk/messages.json +44 -0
  230. package/src/components/i18n/locales/sl/messages.json +44 -0
  231. package/src/components/i18n/locales/sq/messages.json +44 -0
  232. package/src/components/i18n/locales/sr/messages.json +44 -0
  233. package/src/components/i18n/locales/sv/messages.json +44 -0
  234. package/src/components/i18n/locales/sw/messages.json +44 -0
  235. package/src/components/i18n/locales/ta/messages.json +44 -0
  236. package/src/components/i18n/locales/te/messages.json +44 -0
  237. package/src/components/i18n/locales/th/messages.json +44 -0
  238. package/src/components/i18n/locales/tr/messages.json +44 -0
  239. package/src/components/i18n/locales/ug/messages.json +44 -0
  240. package/src/components/i18n/locales/uk/messages.json +44 -0
  241. package/src/components/i18n/locales/ur/messages.json +44 -0
  242. package/src/components/i18n/locales/vi/messages.json +44 -0
  243. package/src/components/i18n/locales/yi/messages.json +44 -0
  244. package/src/components/i18n/locales/zh/messages.json +44 -0
  245. package/src/components/icons/index.ts +242 -0
  246. package/src/components/inline-tools/inline-tool-bold.ts +2213 -0
  247. package/src/components/inline-tools/inline-tool-convert.ts +141 -0
  248. package/src/components/inline-tools/inline-tool-italic.ts +500 -0
  249. package/src/components/inline-tools/inline-tool-link.ts +539 -0
  250. package/src/components/modules/api/blocks.ts +363 -0
  251. package/src/components/modules/api/caret.ts +125 -0
  252. package/src/components/modules/api/events.ts +51 -0
  253. package/src/components/modules/api/history.ts +73 -0
  254. package/src/components/modules/api/i18n.ts +33 -0
  255. package/src/components/modules/api/index.ts +39 -0
  256. package/src/components/modules/api/inlineToolbar.ts +33 -0
  257. package/src/components/modules/api/listeners.ts +56 -0
  258. package/src/components/modules/api/notifier.ts +46 -0
  259. package/src/components/modules/api/readonly.ts +39 -0
  260. package/src/components/modules/api/sanitizer.ts +30 -0
  261. package/src/components/modules/api/saver.ts +52 -0
  262. package/src/components/modules/api/selection.ts +48 -0
  263. package/src/components/modules/api/styles.ts +72 -0
  264. package/src/components/modules/api/toolbar.ts +79 -0
  265. package/src/components/modules/api/tools.ts +16 -0
  266. package/src/components/modules/api/tooltip.ts +67 -0
  267. package/src/components/modules/api/ui.ts +36 -0
  268. package/src/components/modules/blockEvents.ts +1375 -0
  269. package/src/components/modules/blockManager.ts +1348 -0
  270. package/src/components/modules/blockSelection.ts +708 -0
  271. package/src/components/modules/caret.ts +853 -0
  272. package/src/components/modules/crossBlockSelection.ts +329 -0
  273. package/src/components/modules/dragManager.ts +1141 -0
  274. package/src/components/modules/history.ts +1098 -0
  275. package/src/components/modules/i18n.ts +325 -0
  276. package/src/components/modules/index.ts +139 -0
  277. package/src/components/modules/modificationsObserver.ts +147 -0
  278. package/src/components/modules/paste.ts +1092 -0
  279. package/src/components/modules/readonly.ts +136 -0
  280. package/src/components/modules/rectangleSelection.ts +668 -0
  281. package/src/components/modules/renderer.ts +155 -0
  282. package/src/components/modules/saver.ts +283 -0
  283. package/src/components/modules/toolbar/blockSettings.ts +776 -0
  284. package/src/components/modules/toolbar/index.ts +1311 -0
  285. package/src/components/modules/toolbar/inline.ts +956 -0
  286. package/src/components/modules/tools.ts +589 -0
  287. package/src/components/modules/ui.ts +1179 -0
  288. package/src/components/polyfills.ts +113 -0
  289. package/src/components/selection.ts +1189 -0
  290. package/src/components/tools/base.ts +274 -0
  291. package/src/components/tools/block.ts +291 -0
  292. package/src/components/tools/collection.ts +67 -0
  293. package/src/components/tools/factory.ts +85 -0
  294. package/src/components/tools/inline.ts +71 -0
  295. package/src/components/tools/tune.ts +33 -0
  296. package/src/components/ui/toolbox.ts +497 -0
  297. package/src/components/utils/announcer.ts +205 -0
  298. package/src/components/utils/api.ts +20 -0
  299. package/src/components/utils/bem.ts +26 -0
  300. package/src/components/utils/blocks.ts +284 -0
  301. package/src/components/utils/caret.ts +1067 -0
  302. package/src/components/utils/data-model-transform.ts +382 -0
  303. package/src/components/utils/events.ts +117 -0
  304. package/src/components/utils/keyboard.ts +60 -0
  305. package/src/components/utils/listeners.ts +296 -0
  306. package/src/components/utils/mutations.ts +39 -0
  307. package/src/components/utils/notifier/draw.ts +190 -0
  308. package/src/components/utils/notifier/index.ts +66 -0
  309. package/src/components/utils/notifier/types.ts +1 -0
  310. package/src/components/utils/notifier.ts +77 -0
  311. package/src/components/utils/placeholder.ts +140 -0
  312. package/src/components/utils/popover/components/hint/hint.const.ts +10 -0
  313. package/src/components/utils/popover/components/hint/hint.ts +46 -0
  314. package/src/components/utils/popover/components/hint/index.ts +6 -0
  315. package/src/components/utils/popover/components/popover-header/index.ts +2 -0
  316. package/src/components/utils/popover/components/popover-header/popover-header.const.ts +8 -0
  317. package/src/components/utils/popover/components/popover-header/popover-header.ts +80 -0
  318. package/src/components/utils/popover/components/popover-header/popover-header.types.ts +14 -0
  319. package/src/components/utils/popover/components/popover-item/index.ts +13 -0
  320. package/src/components/utils/popover/components/popover-item/popover-item-default/popover-item-default.const.ts +50 -0
  321. package/src/components/utils/popover/components/popover-item/popover-item-default/popover-item-default.ts +666 -0
  322. package/src/components/utils/popover/components/popover-item/popover-item-html/popover-item-html.const.ts +14 -0
  323. package/src/components/utils/popover/components/popover-item/popover-item-html/popover-item-html.ts +136 -0
  324. package/src/components/utils/popover/components/popover-item/popover-item-separator/popover-item-separator.const.ts +20 -0
  325. package/src/components/utils/popover/components/popover-item/popover-item-separator/popover-item-separator.ts +117 -0
  326. package/src/components/utils/popover/components/popover-item/popover-item.ts +187 -0
  327. package/src/components/utils/popover/components/search-input/index.ts +2 -0
  328. package/src/components/utils/popover/components/search-input/search-input.const.ts +8 -0
  329. package/src/components/utils/popover/components/search-input/search-input.ts +181 -0
  330. package/src/components/utils/popover/components/search-input/search-input.types.ts +30 -0
  331. package/src/components/utils/popover/index.ts +13 -0
  332. package/src/components/utils/popover/popover-abstract.ts +448 -0
  333. package/src/components/utils/popover/popover-desktop.ts +643 -0
  334. package/src/components/utils/popover/popover-inline.ts +338 -0
  335. package/src/components/utils/popover/popover-mobile.ts +201 -0
  336. package/src/components/utils/popover/popover.const.ts +81 -0
  337. package/src/components/utils/popover/utils/popover-states-history.ts +72 -0
  338. package/src/components/utils/promise-queue.ts +43 -0
  339. package/src/components/utils/sanitizer.ts +537 -0
  340. package/src/components/utils/scroll-locker.ts +87 -0
  341. package/src/components/utils/shortcut.ts +231 -0
  342. package/src/components/utils/shortcuts.ts +113 -0
  343. package/src/components/utils/tools.ts +105 -0
  344. package/src/components/utils/tooltip.ts +642 -0
  345. package/src/components/utils/tw.ts +241 -0
  346. package/src/components/utils.ts +1081 -0
  347. package/src/env.d.ts +13 -0
  348. package/src/full.ts +69 -0
  349. package/src/locales.ts +51 -0
  350. package/src/stories/Block.stories.ts +498 -0
  351. package/src/stories/EditorModes.stories.ts +505 -0
  352. package/src/stories/Header.stories.ts +137 -0
  353. package/src/stories/InlineToolbar.stories.ts +498 -0
  354. package/src/stories/List.stories.ts +259 -0
  355. package/src/stories/Notifier.stories.ts +340 -0
  356. package/src/stories/Paragraph.stories.ts +112 -0
  357. package/src/stories/Placeholder.stories.ts +319 -0
  358. package/src/stories/Popover.stories.ts +844 -0
  359. package/src/stories/Selection.stories.ts +250 -0
  360. package/src/stories/StubBlock.stories.ts +156 -0
  361. package/src/stories/Toolbar.stories.ts +223 -0
  362. package/src/stories/Toolbox.stories.ts +166 -0
  363. package/src/stories/Tooltip.stories.ts +198 -0
  364. package/src/stories/helpers.ts +463 -0
  365. package/src/styles/main.css +123 -0
  366. package/src/tools/header/index.ts +570 -0
  367. package/src/tools/index.ts +38 -0
  368. package/src/tools/list/index.ts +1803 -0
  369. package/src/tools/paragraph/index.ts +411 -0
  370. package/src/tools/stub/index.ts +107 -0
  371. package/src/types-internal/blok-modules.d.ts +87 -0
  372. package/src/types-internal/html-janitor.d.ts +28 -0
  373. package/src/types-internal/module-config.d.ts +11 -0
  374. package/src/variants/all-locales.ts +155 -0
  375. package/src/variants/blok-maximum.ts +20 -0
  376. package/src/variants/blok-minimum.ts +243 -0
  377. package/types/api/blocks.d.ts +1 -1
  378. package/types/api/i18n.d.ts +5 -3
  379. package/types/api/selection.d.ts +6 -0
  380. package/types/api/styles.d.ts +23 -10
  381. package/types/configs/blok-config.d.ts +29 -0
  382. package/types/configs/i18n-config.d.ts +52 -2
  383. package/types/configs/i18n-dictionary.d.ts +16 -90
  384. package/types/data-attributes.d.ts +169 -0
  385. package/types/data-formats/output-data.d.ts +15 -0
  386. package/types/full.d.ts +80 -0
  387. package/types/index.d.ts +9 -12
  388. package/types/locales.d.ts +59 -0
  389. package/types/tools/adapters/inline-tool-adapter.d.ts +10 -0
  390. package/types/tools/block-tool.d.ts +9 -0
  391. package/types/tools/header.d.ts +18 -0
  392. package/types/tools/index.d.ts +1 -0
  393. package/types/tools/list.d.ts +91 -0
  394. package/types/tools/paragraph.d.ts +71 -0
  395. package/types/tools/tool-settings.d.ts +16 -2
  396. package/types/tools/tool.d.ts +6 -0
  397. package/types/tools-entry.d.ts +49 -0
  398. package/types/utils/popover/popover-item.d.ts +6 -5
  399. package/dist/blok-B870U2fw.mjs +0 -25803
  400. package/dist/blok.umd.js +0 -181
@@ -0,0 +1,844 @@
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, dispatchKeyboardEvent, focusSearchInput, waitForPointerEvents } from './helpers';
5
+ import type { EditorFactoryOptions } from './helpers';
6
+ import { Header } from '../tools/header';
7
+
8
+ interface PopoverArgs extends EditorFactoryOptions {
9
+ minHeight: number;
10
+ data: OutputData | undefined;
11
+ }
12
+
13
+ // Constants
14
+ const BLOCK_TESTID = '[data-blok-testid="block-wrapper"]';
15
+ const ACTIONS_TESTID = '[data-blok-testid="toolbar-actions"]';
16
+ const PLUS_BUTTON_TESTID = '[data-blok-testid="plus-button"]';
17
+ const SETTINGS_BUTTON_TESTID = '[data-blok-testid="settings-toggler"]';
18
+ const BLOCK_TUNES_POPOVER_TESTID = '[data-blok-testid="block-tunes-popover"]';
19
+ const POPOVER_ITEM_TESTID = '[data-blok-testid="popover-item"]';
20
+
21
+ const POPOVER_OPENED_SELECTOR = '[data-blok-popover-opened="true"]';
22
+ const ITEM_FOCUSED_SELECTOR = '[data-blok-focused=\"true\"]';
23
+ const CONFIRMATION_SELECTOR = '[data-blok-popover-item-confirmation="true"]';
24
+ const NOTHING_FOUND_SELECTOR = '[data-blok-nothing-found-displayed="true"]';
25
+ const DELETE_BUTTON_SELECTOR = '[data-blok-item-name="delete"]';
26
+ const CONVERT_TO_SELECTOR = '[data-blok-item-name="convert-to"]';
27
+ const NESTED_POPOVER_SELECTOR = '[data-blok-nested="true"]';
28
+
29
+ const TIMEOUT_INIT = { timeout: 5000 };
30
+ const TIMEOUT_ACTION = { timeout: 5000 };
31
+
32
+ const sampleData: OutputData = {
33
+ time: Date.now(),
34
+ version: '1.0.0',
35
+ blocks: [
36
+ {
37
+ id: 'popover-block-1',
38
+ type: 'paragraph',
39
+ data: { text: 'Block for testing popover states and interactions.' },
40
+ },
41
+ {
42
+ id: 'popover-block-2',
43
+ type: 'paragraph',
44
+ data: { text: 'Second block for additional testing.' },
45
+ },
46
+ ],
47
+ };
48
+
49
+ const createEditor = (args: PopoverArgs): HTMLElement => createEditorContainer(args);
50
+
51
+ const meta: Meta<PopoverArgs> = {
52
+ title: 'Components/Popover',
53
+ tags: ['autodocs'],
54
+ args: {
55
+ minHeight: 350,
56
+ data: sampleData,
57
+ },
58
+ render: createEditor,
59
+ };
60
+
61
+ export default meta;
62
+
63
+
64
+ type Story = StoryObj<PopoverArgs>;
65
+
66
+ /*
67
+ * NOTE: Toolbox opened state lives in EditorModes.stories.ts (ToolboxOpenedMode)
68
+ * This file focuses on popover-specific states: hover, focus, search, confirmation.
69
+ */
70
+
71
+ /**
72
+ * Default state: Popover is closed.
73
+ */
74
+ export const Default: Story = {
75
+ args: {
76
+ data: sampleData,
77
+ },
78
+ };
79
+
80
+ /**
81
+ * Popover item hover state.
82
+ * Note: Waits for pointer-events to be enabled before hovering.
83
+ */
84
+ export const ItemHoverState: Story = {
85
+ args: {
86
+ data: sampleData,
87
+ },
88
+ play: async ({ canvasElement, step }) => {
89
+ await step('Wait for editor and toolbar to initialize', async () => {
90
+ await waitFor(
91
+ () => {
92
+ const block = canvasElement.querySelector(BLOCK_TESTID);
93
+
94
+ expect(block).toBeInTheDocument();
95
+ },
96
+ TIMEOUT_INIT
97
+ );
98
+ // Wait for toolbar to be created (happens in requestIdleCallback)
99
+ await waitForToolbar(canvasElement);
100
+ });
101
+
102
+ await step('Click block to show toolbar', async () => {
103
+ const block = canvasElement.querySelector(BLOCK_TESTID);
104
+
105
+ if (block) {
106
+ simulateClick(block);
107
+ }
108
+
109
+ await waitFor(
110
+ () => {
111
+ const toolbar = canvasElement.querySelector(TOOLBAR_TESTID);
112
+
113
+ expect(toolbar).toHaveAttribute('data-blok-opened', 'true');
114
+ },
115
+ TIMEOUT_ACTION
116
+ );
117
+ });
118
+
119
+ await step('Open toolbox and hover item', async () => {
120
+ const plusButton = canvasElement.querySelector(PLUS_BUTTON_TESTID);
121
+
122
+ if (plusButton) {
123
+ simulateClick(plusButton);
124
+ }
125
+
126
+ // Wait for popover to open AND for pointer-events to be enabled
127
+ await waitForPointerEvents('[data-blok-popover-opened="true"] [data-blok-testid="popover-container"]');
128
+
129
+ // Small delay for CSS animation to complete
130
+ await new Promise((resolve) => setTimeout(resolve, 150));
131
+
132
+ const popoverItem = document.querySelector(POPOVER_ITEM_TESTID);
133
+
134
+ if (popoverItem) {
135
+ // Add data-blok-force-hover attribute to show hover styles in headless browsers
136
+ // The CSS uses this attribute instead of :hover for testing compatibility
137
+ popoverItem.setAttribute('data-blok-force-hover', 'true');
138
+ await userEvent.hover(popoverItem);
139
+ }
140
+ });
141
+ },
142
+ };
143
+
144
+ /**
145
+ * Popover item focused state (keyboard navigation).
146
+ */
147
+ export const ItemFocusedState: Story = {
148
+ args: {
149
+ data: sampleData,
150
+ },
151
+ play: async ({ canvasElement, step }) => {
152
+ await step('Wait for editor and toolbar to initialize', async () => {
153
+ await waitFor(
154
+ () => {
155
+ const block = canvasElement.querySelector(BLOCK_TESTID);
156
+
157
+ expect(block).toBeInTheDocument();
158
+ },
159
+ TIMEOUT_INIT
160
+ );
161
+ // Wait for toolbar to be created (happens in requestIdleCallback)
162
+ await waitForToolbar(canvasElement);
163
+ });
164
+
165
+ await step('Click block to show toolbar', async () => {
166
+ const block = canvasElement.querySelector(BLOCK_TESTID);
167
+
168
+ if (block) {
169
+ simulateClick(block);
170
+ }
171
+
172
+ await waitFor(
173
+ () => {
174
+ const toolbar = canvasElement.querySelector(TOOLBAR_TESTID);
175
+
176
+ expect(toolbar).toHaveAttribute('data-blok-opened', 'true');
177
+ },
178
+ TIMEOUT_ACTION
179
+ );
180
+ });
181
+
182
+ await step('Open toolbox and navigate with keyboard', async () => {
183
+ const plusButton = canvasElement.querySelector(PLUS_BUTTON_TESTID);
184
+
185
+ if (plusButton) {
186
+ await userEvent.click(plusButton);
187
+ }
188
+
189
+ await waitFor(
190
+ () => {
191
+ // Popover is appended to document.body, not inside the canvas
192
+ const popover = document.querySelector(POPOVER_OPENED_SELECTOR);
193
+
194
+ expect(popover).toBeInTheDocument();
195
+ },
196
+ TIMEOUT_ACTION
197
+ );
198
+
199
+ // Wait for popover to fully initialize before keyboard navigation
200
+ await new Promise((resolve) => setTimeout(resolve, 100));
201
+
202
+ // Find a popover item or the popover container to dispatch from
203
+ const popoverItem = document.querySelector(POPOVER_ITEM_TESTID);
204
+ const popover = document.querySelector(POPOVER_OPENED_SELECTOR);
205
+ const targetElement = popoverItem ?? popover ?? document.body;
206
+
207
+ // Dispatch ArrowDown event from the popover element for flipper to catch
208
+ dispatchKeyboardEvent('ArrowDown', { target: targetElement });
209
+
210
+ await waitFor(
211
+ () => {
212
+ // Popover items are inside the popover which is in document.body
213
+ const focusedItem = document.querySelector(ITEM_FOCUSED_SELECTOR);
214
+
215
+ expect(focusedItem).toBeInTheDocument();
216
+ },
217
+ TIMEOUT_ACTION
218
+ );
219
+ });
220
+ },
221
+ };
222
+
223
+ /**
224
+ * Block tunes popover with convert-to nested items.
225
+ */
226
+ export const BlockTunesPopover: Story = {
227
+ args: {
228
+ data: sampleData,
229
+ },
230
+ play: async ({ canvasElement, step }) => {
231
+ await step('Wait for editor and toolbar to initialize', async () => {
232
+ await waitFor(
233
+ () => {
234
+ const block = canvasElement.querySelector(BLOCK_TESTID);
235
+
236
+ expect(block).toBeInTheDocument();
237
+ },
238
+ TIMEOUT_INIT
239
+ );
240
+ // Wait for toolbar to be created (happens in requestIdleCallback)
241
+ await waitForToolbar(canvasElement);
242
+ });
243
+
244
+ await step('Click block to show toolbar', async () => {
245
+ const block = canvasElement.querySelector(BLOCK_TESTID);
246
+
247
+ if (block) {
248
+ simulateClick(block);
249
+ }
250
+
251
+ await waitFor(
252
+ () => {
253
+ const actionsZone = canvasElement.querySelector(ACTIONS_TESTID);
254
+
255
+ expect(actionsZone).toBeInTheDocument();
256
+ },
257
+ TIMEOUT_ACTION
258
+ );
259
+ });
260
+
261
+ await step('Open block tunes', async () => {
262
+ const settingsButton = canvasElement.querySelector(SETTINGS_BUTTON_TESTID);
263
+
264
+ if (settingsButton) {
265
+ simulateClick(settingsButton);
266
+ }
267
+
268
+ await waitFor(
269
+ () => {
270
+ // Block tunes popover is appended to document.body
271
+ const blockTunesPopover = document.querySelector(BLOCK_TUNES_POPOVER_TESTID);
272
+
273
+ expect(blockTunesPopover).toBeInTheDocument();
274
+ },
275
+ TIMEOUT_ACTION
276
+ );
277
+ });
278
+ },
279
+ };
280
+
281
+ /**
282
+ * Popover confirmation state - demonstrates the visual appearance of an item in confirmation mode.
283
+ * Note: This manually applies confirmation styling since the default delete tune doesn't have confirmation.
284
+ */
285
+ export const ConfirmationState: Story = {
286
+ args: {
287
+ data: sampleData,
288
+ },
289
+ play: async ({ canvasElement, step }) => {
290
+ await step('Wait for editor and toolbar to initialize', async () => {
291
+ await waitFor(
292
+ () => {
293
+ const block = canvasElement.querySelector(BLOCK_TESTID);
294
+
295
+ expect(block).toBeInTheDocument();
296
+ },
297
+ TIMEOUT_INIT
298
+ );
299
+ // Wait for toolbar to be created (happens in requestIdleCallback)
300
+ await waitForToolbar(canvasElement);
301
+ });
302
+
303
+ await step('Click block to show toolbar', async () => {
304
+ const block = canvasElement.querySelector(BLOCK_TESTID);
305
+
306
+ if (block) {
307
+ simulateClick(block);
308
+ }
309
+
310
+ await waitFor(
311
+ () => {
312
+ const actionsZone = canvasElement.querySelector(ACTIONS_TESTID);
313
+
314
+ expect(actionsZone).toBeInTheDocument();
315
+ },
316
+ TIMEOUT_ACTION
317
+ );
318
+ });
319
+
320
+ await step('Open block tunes', async () => {
321
+ const settingsButton = canvasElement.querySelector(SETTINGS_BUTTON_TESTID);
322
+
323
+ if (settingsButton) {
324
+ simulateClick(settingsButton);
325
+ }
326
+
327
+ await waitFor(
328
+ () => {
329
+ // Block tunes popover is appended to document.body
330
+ const blockTunesPopover = document.querySelector(BLOCK_TUNES_POPOVER_TESTID);
331
+
332
+ expect(blockTunesPopover).toBeInTheDocument();
333
+ },
334
+ TIMEOUT_ACTION
335
+ );
336
+ });
337
+
338
+ await step('Apply confirmation state styling to delete button', async () => {
339
+ // Wait for popover items to be fully rendered
340
+ await new Promise((resolve) => setTimeout(resolve, 200));
341
+
342
+ // Delete button is inside the popover which is in document.body
343
+ const deleteButton = document.querySelector(DELETE_BUTTON_SELECTOR);
344
+
345
+ if (deleteButton) {
346
+ // Manually apply confirmation state styling for visual demonstration
347
+ // This matches the styling applied by popover-item-default.ts applyConfirmationState()
348
+ deleteButton.setAttribute('data-blok-popover-item-confirmation', 'true');
349
+ deleteButton.setAttribute('data-blok-popover-item-no-hover', 'true');
350
+ deleteButton.setAttribute('data-blok-popover-item-no-focus', 'true');
351
+ // eslint-disable-next-line internal-storybook/no-class-selectors
352
+ deleteButton.classList.add('!bg-item-confirm-bg', '!text-white');
353
+ }
354
+
355
+ await waitFor(
356
+ () => {
357
+ // Confirmation button is inside the popover which is in document.body
358
+ const confirmButton = document.querySelector(CONFIRMATION_SELECTOR);
359
+
360
+ expect(confirmButton).toBeInTheDocument();
361
+ },
362
+ TIMEOUT_ACTION
363
+ );
364
+
365
+ // Add hover state to confirmation button for visual testing in headless browsers
366
+ const confirmButton = document.querySelector(CONFIRMATION_SELECTOR);
367
+
368
+ if (confirmButton) {
369
+ confirmButton.setAttribute('data-blok-force-hover', 'true');
370
+ await userEvent.hover(confirmButton);
371
+ }
372
+ });
373
+ },
374
+ };
375
+
376
+ /**
377
+ * Popover search/filter functionality (in block settings).
378
+ */
379
+ export const SearchFiltering: Story = {
380
+ args: {
381
+ data: sampleData,
382
+ },
383
+ play: async ({ canvasElement, step }) => {
384
+ await step('Wait for editor and toolbar to initialize', async () => {
385
+ await waitFor(
386
+ () => {
387
+ const block = canvasElement.querySelector(BLOCK_TESTID);
388
+
389
+ expect(block).toBeInTheDocument();
390
+ },
391
+ TIMEOUT_INIT
392
+ );
393
+ // Wait for toolbar to be created (happens in requestIdleCallback)
394
+ await waitForToolbar(canvasElement);
395
+ });
396
+
397
+ await step('Click block to show toolbar', async () => {
398
+ const block = canvasElement.querySelector(BLOCK_TESTID);
399
+
400
+ if (block) {
401
+ simulateClick(block);
402
+ }
403
+
404
+ await waitFor(
405
+ () => {
406
+ const toolbar = canvasElement.querySelector(TOOLBAR_TESTID);
407
+
408
+ expect(toolbar).toHaveAttribute('data-blok-opened', 'true');
409
+ },
410
+ TIMEOUT_ACTION
411
+ );
412
+ });
413
+
414
+ await step('Open block settings', async () => {
415
+ const settingsButton = canvasElement.querySelector(SETTINGS_BUTTON_TESTID);
416
+
417
+ if (settingsButton) {
418
+ simulateClick(settingsButton);
419
+ }
420
+
421
+ await waitFor(
422
+ () => {
423
+ // Block tunes popover is appended to document.body
424
+ const blockTunesPopover = document.querySelector(BLOCK_TUNES_POPOVER_TESTID);
425
+
426
+ expect(blockTunesPopover).toBeInTheDocument();
427
+ },
428
+ TIMEOUT_ACTION
429
+ );
430
+ });
431
+
432
+ await step('Type to filter items', async () => {
433
+ // Wait for popover to be fully rendered
434
+ await new Promise((resolve) => setTimeout(resolve, 100));
435
+
436
+ // Use helper to focus search input and type
437
+ focusSearchInput('delete');
438
+
439
+ await new Promise((resolve) => setTimeout(resolve, 300));
440
+
441
+ // Verify the popover is still open and filtering worked
442
+ await waitFor(
443
+ () => {
444
+ const popover = document.querySelector(POPOVER_OPENED_SELECTOR);
445
+
446
+ expect(popover).toBeInTheDocument();
447
+ },
448
+ TIMEOUT_ACTION
449
+ );
450
+ });
451
+ },
452
+ };
453
+
454
+ /**
455
+ * Popover nothing found message (in block settings).
456
+ */
457
+ export const NothingFoundMessage: Story = {
458
+ args: {
459
+ data: sampleData,
460
+ },
461
+ play: async ({ canvasElement, step }) => {
462
+ await step('Wait for editor and toolbar to initialize', async () => {
463
+ await waitFor(
464
+ () => {
465
+ const block = canvasElement.querySelector(BLOCK_TESTID);
466
+
467
+ expect(block).toBeInTheDocument();
468
+ },
469
+ TIMEOUT_INIT
470
+ );
471
+ // Wait for toolbar to be created (happens in requestIdleCallback)
472
+ await waitForToolbar(canvasElement);
473
+ });
474
+
475
+ await step('Click block to show toolbar', async () => {
476
+ const block = canvasElement.querySelector(BLOCK_TESTID);
477
+
478
+ if (block) {
479
+ simulateClick(block);
480
+ }
481
+
482
+ await waitFor(
483
+ () => {
484
+ const toolbar = canvasElement.querySelector(TOOLBAR_TESTID);
485
+
486
+ expect(toolbar).toHaveAttribute('data-blok-opened', 'true');
487
+ },
488
+ TIMEOUT_ACTION
489
+ );
490
+ });
491
+
492
+ await step('Open block settings', async () => {
493
+ const settingsButton = canvasElement.querySelector(SETTINGS_BUTTON_TESTID);
494
+
495
+ if (settingsButton) {
496
+ await userEvent.click(settingsButton);
497
+ }
498
+
499
+ await waitFor(
500
+ () => {
501
+ // Block tunes popover is appended to document.body
502
+ const blockTunesPopover = document.querySelector(BLOCK_TUNES_POPOVER_TESTID);
503
+
504
+ expect(blockTunesPopover).toBeInTheDocument();
505
+ },
506
+ TIMEOUT_ACTION
507
+ );
508
+ });
509
+
510
+ await step('Search for non-existent item', async () => {
511
+ // Wait for popover to be fully rendered and search input to be available
512
+ await new Promise((resolve) => setTimeout(resolve, 100));
513
+
514
+ // Find and focus the search input inside the popover
515
+ const searchInput = document.querySelector('[data-blok-testid="popover-search-input"]') as HTMLInputElement;
516
+
517
+ if (searchInput) {
518
+ searchInput.focus();
519
+ // Type directly into the input
520
+ searchInput.value = 'xyznonexistent';
521
+ // Trigger input event to notify the search handler
522
+ searchInput.dispatchEvent(new Event('input', { bubbles: true }));
523
+ }
524
+
525
+ await waitFor(
526
+ () => {
527
+ // Nothing found message is inside the popover which is in document.body
528
+ const nothingFound = document.querySelector(NOTHING_FOUND_SELECTOR);
529
+
530
+ expect(nothingFound).toBeInTheDocument();
531
+ },
532
+ TIMEOUT_ACTION
533
+ );
534
+ });
535
+ },
536
+ };
537
+
538
+ /**
539
+ * Popover item in disabled state.
540
+ */
541
+ export const DisabledItem: Story = {
542
+ args: {
543
+ data: sampleData,
544
+ },
545
+ play: async ({ canvasElement, step }) => {
546
+ await step('Wait for editor and toolbar to initialize', async () => {
547
+ await waitFor(
548
+ () => {
549
+ const block = canvasElement.querySelector(BLOCK_TESTID);
550
+
551
+ expect(block).toBeInTheDocument();
552
+ },
553
+ TIMEOUT_INIT
554
+ );
555
+ await waitForToolbar(canvasElement);
556
+ });
557
+
558
+ await step('Click block to show toolbar', async () => {
559
+ const block = canvasElement.querySelector(BLOCK_TESTID);
560
+
561
+ if (block) {
562
+ simulateClick(block);
563
+ }
564
+
565
+ await waitFor(
566
+ () => {
567
+ const toolbar = canvasElement.querySelector(TOOLBAR_TESTID);
568
+
569
+ expect(toolbar).toHaveAttribute('data-blok-opened', 'true');
570
+ },
571
+ TIMEOUT_ACTION
572
+ );
573
+ });
574
+
575
+ await step('Open toolbox and disable an item', async () => {
576
+ const plusButton = canvasElement.querySelector(PLUS_BUTTON_TESTID);
577
+
578
+ if (plusButton) {
579
+ simulateClick(plusButton);
580
+ }
581
+
582
+ await waitFor(
583
+ () => {
584
+ const popover = document.querySelector(POPOVER_OPENED_SELECTOR);
585
+
586
+ expect(popover).toBeInTheDocument();
587
+ },
588
+ TIMEOUT_ACTION
589
+ );
590
+
591
+ // Wait for items to render then add disabled styling to first item
592
+ await new Promise((resolve) => setTimeout(resolve, 150));
593
+
594
+ const popoverItem = document.querySelector(POPOVER_ITEM_TESTID);
595
+
596
+ if (popoverItem) {
597
+ // Add the proper disabled classes and attribute that match the real implementation
598
+ // The itemDisabled class from popover-item-default.const.ts is:
599
+ // 'cursor-default pointer-events-none text-text-secondary'
600
+ // eslint-disable-next-line internal-storybook/no-class-selectors
601
+ popoverItem.classList.add('cursor-default', 'pointer-events-none', 'text-text-secondary');
602
+ popoverItem.setAttribute('data-blok-disabled', 'true');
603
+ }
604
+
605
+ await waitFor(
606
+ () => {
607
+ const disabledItem = document.querySelector('[data-blok-disabled="true"]');
608
+
609
+ expect(disabledItem).toBeInTheDocument();
610
+ },
611
+ TIMEOUT_ACTION
612
+ );
613
+ });
614
+ },
615
+ };
616
+
617
+ /**
618
+ * Mobile popover layout (full-width bottom sheet style).
619
+ */
620
+ export const MobilePopover: Story = {
621
+ args: {
622
+ data: sampleData,
623
+ minHeight: 400,
624
+ },
625
+ parameters: {
626
+ viewport: {
627
+ defaultViewport: 'mobile1',
628
+ },
629
+ chromatic: {
630
+ viewports: [375],
631
+ },
632
+ },
633
+ play: async ({ canvasElement, step }) => {
634
+ await step('Wait for editor and toolbar to initialize', async () => {
635
+ await waitFor(
636
+ () => {
637
+ const block = canvasElement.querySelector(BLOCK_TESTID);
638
+
639
+ expect(block).toBeInTheDocument();
640
+ },
641
+ TIMEOUT_INIT
642
+ );
643
+ await waitForToolbar(canvasElement);
644
+ });
645
+
646
+ await step('Click block to show toolbar', async () => {
647
+ const block = canvasElement.querySelector(BLOCK_TESTID);
648
+
649
+ if (block) {
650
+ simulateClick(block);
651
+ }
652
+
653
+ await waitFor(
654
+ () => {
655
+ const toolbar = canvasElement.querySelector(TOOLBAR_TESTID);
656
+
657
+ expect(toolbar).toHaveAttribute('data-blok-opened', 'true');
658
+ },
659
+ TIMEOUT_ACTION
660
+ );
661
+ });
662
+
663
+ await step('Open toolbox in mobile view', async () => {
664
+ const plusButton = canvasElement.querySelector(PLUS_BUTTON_TESTID);
665
+
666
+ if (plusButton) {
667
+ simulateClick(plusButton);
668
+ }
669
+
670
+ await waitFor(
671
+ () => {
672
+ const popover = document.querySelector(POPOVER_OPENED_SELECTOR);
673
+
674
+ expect(popover).toBeInTheDocument();
675
+ },
676
+ TIMEOUT_ACTION
677
+ );
678
+ });
679
+ },
680
+ };
681
+
682
+ /**
683
+ * Mobile overlay backdrop (semi-transparent background).
684
+ */
685
+ export const MobileOverlay: Story = {
686
+ args: {
687
+ data: sampleData,
688
+ minHeight: 400,
689
+ },
690
+ parameters: {
691
+ viewport: {
692
+ defaultViewport: 'mobile1',
693
+ },
694
+ chromatic: {
695
+ viewports: [375],
696
+ },
697
+ },
698
+ play: async ({ canvasElement, step }) => {
699
+ await step('Wait for editor and toolbar to initialize', async () => {
700
+ await waitFor(
701
+ () => {
702
+ const block = canvasElement.querySelector(BLOCK_TESTID);
703
+
704
+ expect(block).toBeInTheDocument();
705
+ },
706
+ TIMEOUT_INIT
707
+ );
708
+ await waitForToolbar(canvasElement);
709
+ });
710
+
711
+ await step('Click block to show toolbar', async () => {
712
+ const block = canvasElement.querySelector(BLOCK_TESTID);
713
+
714
+ if (block) {
715
+ simulateClick(block);
716
+ }
717
+
718
+ await waitFor(
719
+ () => {
720
+ const actionsZone = canvasElement.querySelector(ACTIONS_TESTID);
721
+
722
+ expect(actionsZone).toBeInTheDocument();
723
+ },
724
+ TIMEOUT_ACTION
725
+ );
726
+ });
727
+
728
+ await step('Open block tunes to show mobile overlay', async () => {
729
+ const settingsButton = canvasElement.querySelector(SETTINGS_BUTTON_TESTID);
730
+
731
+ if (settingsButton) {
732
+ simulateClick(settingsButton);
733
+ }
734
+
735
+ await waitFor(
736
+ () => {
737
+ const popover = document.querySelector(POPOVER_OPENED_SELECTOR);
738
+
739
+ expect(popover).toBeInTheDocument();
740
+
741
+ // On mobile, the overlay should be visible - check for overlay element
742
+ const popoverElements = document.querySelectorAll('[data-blok-popover-opened="true"]');
743
+ const hasOverlay = Array.from(popoverElements).some(p =>
744
+ p.querySelector('[data-blok-testid="popover-overlay"]')
745
+ );
746
+
747
+ // Overlay exists (visibility controlled by CSS media queries)
748
+ expect(hasOverlay || popover).toBeTruthy();
749
+ },
750
+ TIMEOUT_ACTION
751
+ );
752
+ });
753
+ },
754
+ };
755
+
756
+ /**
757
+ * Block settings menu with convert-to dropdown open.
758
+ */
759
+ export const BlockSettingsConvertToOpen: Story = {
760
+ args: {
761
+ data: sampleData,
762
+ tools: {
763
+ header: Header,
764
+ },
765
+ },
766
+ play: async ({ canvasElement, step }) => {
767
+ await step('Wait for editor and toolbar to initialize', async () => {
768
+ await waitFor(
769
+ () => {
770
+ const block = canvasElement.querySelector(BLOCK_TESTID);
771
+
772
+ expect(block).toBeInTheDocument();
773
+ },
774
+ TIMEOUT_INIT
775
+ );
776
+ await waitForToolbar(canvasElement);
777
+ });
778
+
779
+ await step('Click block to show toolbar', async () => {
780
+ const block = canvasElement.querySelector(BLOCK_TESTID);
781
+
782
+ if (block) {
783
+ simulateClick(block);
784
+ }
785
+
786
+ await waitFor(
787
+ () => {
788
+ const actionsZone = canvasElement.querySelector(ACTIONS_TESTID);
789
+
790
+ expect(actionsZone).toBeInTheDocument();
791
+ },
792
+ TIMEOUT_ACTION
793
+ );
794
+ });
795
+
796
+ await step('Open block settings', async () => {
797
+ const settingsButton = canvasElement.querySelector(SETTINGS_BUTTON_TESTID);
798
+
799
+ if (settingsButton) {
800
+ simulateClick(settingsButton);
801
+ }
802
+
803
+ await waitFor(
804
+ () => {
805
+ const blockTunesPopover = document.querySelector(BLOCK_TUNES_POPOVER_TESTID);
806
+
807
+ expect(blockTunesPopover).toBeInTheDocument();
808
+ },
809
+ TIMEOUT_ACTION
810
+ );
811
+ });
812
+
813
+ await step('Click convert-to button to open nested popover', async () => {
814
+ // Wait for the convert-to button to appear (it's rendered async after block settings opens)
815
+ await waitFor(
816
+ () => {
817
+ const convertToButton = document.querySelector(CONVERT_TO_SELECTOR);
818
+
819
+ expect(convertToButton).toBeInTheDocument();
820
+ },
821
+ TIMEOUT_ACTION
822
+ );
823
+
824
+ const convertToButton = document.querySelector(CONVERT_TO_SELECTOR);
825
+
826
+ if (convertToButton) {
827
+ simulateClick(convertToButton);
828
+ }
829
+
830
+ // Wait for the popover animation
831
+ await new Promise((resolve) => setTimeout(resolve, 100));
832
+
833
+ await waitFor(
834
+ () => {
835
+ // The nested popover should be opened
836
+ const nestedPopover = document.querySelector(NESTED_POPOVER_SELECTOR + POPOVER_OPENED_SELECTOR);
837
+
838
+ expect(nestedPopover).toBeInTheDocument();
839
+ },
840
+ TIMEOUT_ACTION
841
+ );
842
+ });
843
+ },
844
+ };