@jackuait/blok 0.4.1-beta.1 → 0.4.1-beta.12

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 (403) 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-BU6NwVkN.mjs +13239 -0
  7. package/dist/chunks/i18next-CugVlwWp.mjs +1292 -0
  8. package/dist/chunks/i18next-loader-D8GzSwio.mjs +43 -0
  9. package/dist/{index-CEXLTV6f.mjs → chunks/index-C5e_WLFg.mjs} +2 -2
  10. package/dist/chunks/inline-tool-convert-CLUxkCe_.mjs +1990 -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 +3126 -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 +142 -0
  248. package/src/components/inline-tools/inline-tool-italic.ts +500 -0
  249. package/src/components/inline-tools/inline-tool-link.ts +540 -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 +782 -0
  284. package/src/components/modules/toolbar/index.ts +1296 -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 +610 -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 +197 -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 +682 -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 +759 -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 +126 -0
  366. package/src/tools/header/index.ts +647 -0
  367. package/src/tools/index.ts +45 -0
  368. package/src/tools/list/index.ts +1826 -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/configs/sanitizer-config.d.ts +25 -1
  386. package/types/data-attributes.d.ts +170 -0
  387. package/types/data-formats/output-data.d.ts +15 -0
  388. package/types/full.d.ts +80 -0
  389. package/types/index.d.ts +30 -13
  390. package/types/locales.d.ts +59 -0
  391. package/types/tools/adapters/inline-tool-adapter.d.ts +10 -0
  392. package/types/tools/block-tool.d.ts +11 -2
  393. package/types/tools/header.d.ts +18 -0
  394. package/types/tools/index.d.ts +1 -0
  395. package/types/tools/list.d.ts +91 -0
  396. package/types/tools/paragraph.d.ts +71 -0
  397. package/types/tools/tool-settings.d.ts +99 -6
  398. package/types/tools/tool.d.ts +6 -0
  399. package/types/tools-entry.d.ts +49 -0
  400. package/types/utils/popover/popover-item.d.ts +24 -5
  401. package/types/utils/popover/popover.d.ts +13 -0
  402. package/dist/blok-C8XbyLHh.mjs +0 -25795
  403. package/dist/blok.umd.js +0 -181
@@ -0,0 +1,759 @@
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 DELETE_BUTTON_SELECTOR = '[data-blok-item-name="delete"]';
25
+ const CONVERT_TO_SELECTOR = '[data-blok-item-name="convert-to"]';
26
+ const NESTED_POPOVER_SELECTOR = '[data-blok-nested="true"]';
27
+
28
+ const TIMEOUT_INIT = { timeout: 5000 };
29
+ const TIMEOUT_ACTION = { timeout: 5000 };
30
+
31
+ const sampleData: OutputData = {
32
+ time: Date.now(),
33
+ version: '1.0.0',
34
+ blocks: [
35
+ {
36
+ id: 'popover-block-1',
37
+ type: 'paragraph',
38
+ data: { text: 'Block for testing popover states and interactions.' },
39
+ },
40
+ {
41
+ id: 'popover-block-2',
42
+ type: 'paragraph',
43
+ data: { text: 'Second block for additional testing.' },
44
+ },
45
+ ],
46
+ };
47
+
48
+ const createEditor = (args: PopoverArgs): HTMLElement => createEditorContainer(args);
49
+
50
+ const meta: Meta<PopoverArgs> = {
51
+ title: 'Components/Popover',
52
+ tags: ['autodocs'],
53
+ args: {
54
+ minHeight: 350,
55
+ data: sampleData,
56
+ },
57
+ render: createEditor,
58
+ };
59
+
60
+ export default meta;
61
+
62
+
63
+ type Story = StoryObj<PopoverArgs>;
64
+
65
+ /*
66
+ * NOTE: Toolbox opened state lives in EditorModes.stories.ts (ToolboxOpenedMode)
67
+ * This file focuses on popover-specific states: hover, focus, search, confirmation.
68
+ */
69
+
70
+ /**
71
+ * Default state: Popover is closed.
72
+ */
73
+ export const Default: Story = {
74
+ args: {
75
+ data: sampleData,
76
+ },
77
+ };
78
+
79
+ /**
80
+ * Popover item hover state.
81
+ * Note: Waits for pointer-events to be enabled before hovering.
82
+ */
83
+ export const ItemHoverState: Story = {
84
+ args: {
85
+ data: sampleData,
86
+ },
87
+ play: async ({ canvasElement, step }) => {
88
+ await step('Wait for editor and toolbar to initialize', async () => {
89
+ await waitFor(
90
+ () => {
91
+ const block = canvasElement.querySelector(BLOCK_TESTID);
92
+
93
+ expect(block).toBeInTheDocument();
94
+ },
95
+ TIMEOUT_INIT
96
+ );
97
+ // Wait for toolbar to be created (happens in requestIdleCallback)
98
+ await waitForToolbar(canvasElement);
99
+ });
100
+
101
+ await step('Click block to show toolbar', async () => {
102
+ const block = canvasElement.querySelector(BLOCK_TESTID);
103
+
104
+ if (block) {
105
+ simulateClick(block);
106
+ }
107
+
108
+ await waitFor(
109
+ () => {
110
+ const toolbar = canvasElement.querySelector(TOOLBAR_TESTID);
111
+
112
+ expect(toolbar).toHaveAttribute('data-blok-opened', 'true');
113
+ },
114
+ TIMEOUT_ACTION
115
+ );
116
+ });
117
+
118
+ await step('Open toolbox and hover item', async () => {
119
+ const plusButton = canvasElement.querySelector(PLUS_BUTTON_TESTID);
120
+
121
+ if (plusButton) {
122
+ simulateClick(plusButton);
123
+ }
124
+
125
+ // Wait for popover to open AND for pointer-events to be enabled
126
+ await waitForPointerEvents('[data-blok-popover-opened="true"] [data-blok-testid="popover-container"]');
127
+
128
+ // Small delay for CSS animation to complete
129
+ await new Promise((resolve) => setTimeout(resolve, 150));
130
+
131
+ const popoverItem = document.querySelector(POPOVER_ITEM_TESTID);
132
+
133
+ if (popoverItem) {
134
+ // Add data-blok-force-hover attribute to show hover styles in headless browsers
135
+ // The CSS uses this attribute instead of :hover for testing compatibility
136
+ popoverItem.setAttribute('data-blok-force-hover', 'true');
137
+ await userEvent.hover(popoverItem);
138
+ }
139
+ });
140
+ },
141
+ };
142
+
143
+ /**
144
+ * Popover item focused state (keyboard navigation).
145
+ */
146
+ export const ItemFocusedState: Story = {
147
+ args: {
148
+ data: sampleData,
149
+ },
150
+ play: async ({ canvasElement, step }) => {
151
+ await step('Wait for editor and toolbar to initialize', async () => {
152
+ await waitFor(
153
+ () => {
154
+ const block = canvasElement.querySelector(BLOCK_TESTID);
155
+
156
+ expect(block).toBeInTheDocument();
157
+ },
158
+ TIMEOUT_INIT
159
+ );
160
+ // Wait for toolbar to be created (happens in requestIdleCallback)
161
+ await waitForToolbar(canvasElement);
162
+ });
163
+
164
+ await step('Click block to show toolbar', async () => {
165
+ const block = canvasElement.querySelector(BLOCK_TESTID);
166
+
167
+ if (block) {
168
+ simulateClick(block);
169
+ }
170
+
171
+ await waitFor(
172
+ () => {
173
+ const toolbar = canvasElement.querySelector(TOOLBAR_TESTID);
174
+
175
+ expect(toolbar).toHaveAttribute('data-blok-opened', 'true');
176
+ },
177
+ TIMEOUT_ACTION
178
+ );
179
+ });
180
+
181
+ await step('Open toolbox and navigate with keyboard', async () => {
182
+ const plusButton = canvasElement.querySelector(PLUS_BUTTON_TESTID);
183
+
184
+ if (plusButton) {
185
+ await userEvent.click(plusButton);
186
+ }
187
+
188
+ await waitFor(
189
+ () => {
190
+ // Popover is appended to document.body, not inside the canvas
191
+ const popover = document.querySelector(POPOVER_OPENED_SELECTOR);
192
+
193
+ expect(popover).toBeInTheDocument();
194
+ },
195
+ TIMEOUT_ACTION
196
+ );
197
+
198
+ // Wait for popover to fully initialize before keyboard navigation
199
+ await new Promise((resolve) => setTimeout(resolve, 100));
200
+
201
+ // Find a popover item or the popover container to dispatch from
202
+ const popoverItem = document.querySelector(POPOVER_ITEM_TESTID);
203
+ const popover = document.querySelector(POPOVER_OPENED_SELECTOR);
204
+ const targetElement = popoverItem ?? popover ?? document.body;
205
+
206
+ // Dispatch ArrowDown event from the popover element for flipper to catch
207
+ dispatchKeyboardEvent('ArrowDown', { target: targetElement });
208
+
209
+ await waitFor(
210
+ () => {
211
+ // Popover items are inside the popover which is in document.body
212
+ const focusedItem = document.querySelector(ITEM_FOCUSED_SELECTOR);
213
+
214
+ expect(focusedItem).toBeInTheDocument();
215
+ },
216
+ TIMEOUT_ACTION
217
+ );
218
+ });
219
+ },
220
+ };
221
+
222
+ /**
223
+ * Block tunes popover with convert-to nested items.
224
+ */
225
+ export const BlockTunesPopover: Story = {
226
+ args: {
227
+ data: sampleData,
228
+ },
229
+ play: async ({ canvasElement, step }) => {
230
+ await step('Wait for editor and toolbar to initialize', async () => {
231
+ await waitFor(
232
+ () => {
233
+ const block = canvasElement.querySelector(BLOCK_TESTID);
234
+
235
+ expect(block).toBeInTheDocument();
236
+ },
237
+ TIMEOUT_INIT
238
+ );
239
+ // Wait for toolbar to be created (happens in requestIdleCallback)
240
+ await waitForToolbar(canvasElement);
241
+ });
242
+
243
+ await step('Click block to show toolbar', async () => {
244
+ const block = canvasElement.querySelector(BLOCK_TESTID);
245
+
246
+ if (block) {
247
+ simulateClick(block);
248
+ }
249
+
250
+ await waitFor(
251
+ () => {
252
+ const actionsZone = canvasElement.querySelector(ACTIONS_TESTID);
253
+
254
+ expect(actionsZone).toBeInTheDocument();
255
+ },
256
+ TIMEOUT_ACTION
257
+ );
258
+ });
259
+
260
+ await step('Open block tunes', async () => {
261
+ const settingsButton = canvasElement.querySelector(SETTINGS_BUTTON_TESTID);
262
+
263
+ if (settingsButton) {
264
+ simulateClick(settingsButton);
265
+ }
266
+
267
+ await waitFor(
268
+ () => {
269
+ // Block tunes popover is appended to document.body
270
+ const blockTunesPopover = document.querySelector(BLOCK_TUNES_POPOVER_TESTID);
271
+
272
+ expect(blockTunesPopover).toBeInTheDocument();
273
+ },
274
+ TIMEOUT_ACTION
275
+ );
276
+ });
277
+ },
278
+ };
279
+
280
+ /**
281
+ * Popover confirmation state - demonstrates the visual appearance of an item in confirmation mode.
282
+ * Note: This manually applies confirmation styling since the default delete tune doesn't have confirmation.
283
+ */
284
+ export const ConfirmationState: Story = {
285
+ args: {
286
+ data: sampleData,
287
+ },
288
+ play: async ({ canvasElement, step }) => {
289
+ await step('Wait for editor and toolbar to initialize', async () => {
290
+ await waitFor(
291
+ () => {
292
+ const block = canvasElement.querySelector(BLOCK_TESTID);
293
+
294
+ expect(block).toBeInTheDocument();
295
+ },
296
+ TIMEOUT_INIT
297
+ );
298
+ // Wait for toolbar to be created (happens in requestIdleCallback)
299
+ await waitForToolbar(canvasElement);
300
+ });
301
+
302
+ await step('Click block to show toolbar', async () => {
303
+ const block = canvasElement.querySelector(BLOCK_TESTID);
304
+
305
+ if (block) {
306
+ simulateClick(block);
307
+ }
308
+
309
+ await waitFor(
310
+ () => {
311
+ const actionsZone = canvasElement.querySelector(ACTIONS_TESTID);
312
+
313
+ expect(actionsZone).toBeInTheDocument();
314
+ },
315
+ TIMEOUT_ACTION
316
+ );
317
+ });
318
+
319
+ await step('Open block tunes', async () => {
320
+ const settingsButton = canvasElement.querySelector(SETTINGS_BUTTON_TESTID);
321
+
322
+ if (settingsButton) {
323
+ simulateClick(settingsButton);
324
+ }
325
+
326
+ await waitFor(
327
+ () => {
328
+ // Block tunes popover is appended to document.body
329
+ const blockTunesPopover = document.querySelector(BLOCK_TUNES_POPOVER_TESTID);
330
+
331
+ expect(blockTunesPopover).toBeInTheDocument();
332
+ },
333
+ TIMEOUT_ACTION
334
+ );
335
+ });
336
+
337
+ await step('Apply confirmation state styling to delete button', async () => {
338
+ // Wait for popover items to be fully rendered
339
+ await new Promise((resolve) => setTimeout(resolve, 200));
340
+
341
+ // Delete button is inside the popover which is in document.body
342
+ const deleteButton = document.querySelector(DELETE_BUTTON_SELECTOR);
343
+
344
+ if (deleteButton) {
345
+ // Manually apply confirmation state styling for visual demonstration
346
+ // This matches the styling applied by popover-item-default.ts applyConfirmationState()
347
+ deleteButton.setAttribute('data-blok-popover-item-confirmation', 'true');
348
+ deleteButton.setAttribute('data-blok-popover-item-no-hover', 'true');
349
+ deleteButton.setAttribute('data-blok-popover-item-no-focus', 'true');
350
+ // eslint-disable-next-line internal-storybook/no-class-selectors
351
+ deleteButton.classList.add('!bg-item-confirm-bg', '!text-white');
352
+ }
353
+
354
+ await waitFor(
355
+ () => {
356
+ // Confirmation button is inside the popover which is in document.body
357
+ const confirmButton = document.querySelector(CONFIRMATION_SELECTOR);
358
+
359
+ expect(confirmButton).toBeInTheDocument();
360
+ },
361
+ TIMEOUT_ACTION
362
+ );
363
+
364
+ // Add hover state to confirmation button for visual testing in headless browsers
365
+ const confirmButton = document.querySelector(CONFIRMATION_SELECTOR);
366
+
367
+ if (confirmButton) {
368
+ confirmButton.setAttribute('data-blok-force-hover', 'true');
369
+ await userEvent.hover(confirmButton);
370
+ }
371
+ });
372
+ },
373
+ };
374
+
375
+ /**
376
+ * Popover search/filter functionality (in block settings).
377
+ */
378
+ export const SearchFiltering: Story = {
379
+ args: {
380
+ data: sampleData,
381
+ },
382
+ play: async ({ canvasElement, step }) => {
383
+ await step('Wait for editor and toolbar to initialize', async () => {
384
+ await waitFor(
385
+ () => {
386
+ const block = canvasElement.querySelector(BLOCK_TESTID);
387
+
388
+ expect(block).toBeInTheDocument();
389
+ },
390
+ TIMEOUT_INIT
391
+ );
392
+ // Wait for toolbar to be created (happens in requestIdleCallback)
393
+ await waitForToolbar(canvasElement);
394
+ });
395
+
396
+ await step('Click block to show toolbar', async () => {
397
+ const block = canvasElement.querySelector(BLOCK_TESTID);
398
+
399
+ if (block) {
400
+ simulateClick(block);
401
+ }
402
+
403
+ await waitFor(
404
+ () => {
405
+ const toolbar = canvasElement.querySelector(TOOLBAR_TESTID);
406
+
407
+ expect(toolbar).toHaveAttribute('data-blok-opened', 'true');
408
+ },
409
+ TIMEOUT_ACTION
410
+ );
411
+ });
412
+
413
+ await step('Open block settings', async () => {
414
+ const settingsButton = canvasElement.querySelector(SETTINGS_BUTTON_TESTID);
415
+
416
+ if (settingsButton) {
417
+ simulateClick(settingsButton);
418
+ }
419
+
420
+ await waitFor(
421
+ () => {
422
+ // Block tunes popover is appended to document.body
423
+ const blockTunesPopover = document.querySelector(BLOCK_TUNES_POPOVER_TESTID);
424
+
425
+ expect(blockTunesPopover).toBeInTheDocument();
426
+ },
427
+ TIMEOUT_ACTION
428
+ );
429
+ });
430
+
431
+ await step('Type to filter items', async () => {
432
+ // Wait for popover to be fully rendered
433
+ await new Promise((resolve) => setTimeout(resolve, 100));
434
+
435
+ // Use helper to focus search input and type
436
+ focusSearchInput('delete');
437
+
438
+ await new Promise((resolve) => setTimeout(resolve, 300));
439
+
440
+ // Verify the popover is still open and filtering worked
441
+ await waitFor(
442
+ () => {
443
+ const popover = document.querySelector(POPOVER_OPENED_SELECTOR);
444
+
445
+ expect(popover).toBeInTheDocument();
446
+ },
447
+ TIMEOUT_ACTION
448
+ );
449
+ });
450
+ },
451
+ };
452
+
453
+ /**
454
+ * Popover item in disabled state.
455
+ */
456
+ export const DisabledItem: Story = {
457
+ args: {
458
+ data: sampleData,
459
+ },
460
+ play: async ({ canvasElement, step }) => {
461
+ await step('Wait for editor and toolbar to initialize', async () => {
462
+ await waitFor(
463
+ () => {
464
+ const block = canvasElement.querySelector(BLOCK_TESTID);
465
+
466
+ expect(block).toBeInTheDocument();
467
+ },
468
+ TIMEOUT_INIT
469
+ );
470
+ await waitForToolbar(canvasElement);
471
+ });
472
+
473
+ await step('Click block to show toolbar', async () => {
474
+ const block = canvasElement.querySelector(BLOCK_TESTID);
475
+
476
+ if (block) {
477
+ simulateClick(block);
478
+ }
479
+
480
+ await waitFor(
481
+ () => {
482
+ const toolbar = canvasElement.querySelector(TOOLBAR_TESTID);
483
+
484
+ expect(toolbar).toHaveAttribute('data-blok-opened', 'true');
485
+ },
486
+ TIMEOUT_ACTION
487
+ );
488
+ });
489
+
490
+ await step('Open toolbox and disable an item', async () => {
491
+ const plusButton = canvasElement.querySelector(PLUS_BUTTON_TESTID);
492
+
493
+ if (plusButton) {
494
+ simulateClick(plusButton);
495
+ }
496
+
497
+ await waitFor(
498
+ () => {
499
+ const popover = document.querySelector(POPOVER_OPENED_SELECTOR);
500
+
501
+ expect(popover).toBeInTheDocument();
502
+ },
503
+ TIMEOUT_ACTION
504
+ );
505
+
506
+ // Wait for items to render then add disabled styling to first item
507
+ await new Promise((resolve) => setTimeout(resolve, 150));
508
+
509
+ const popoverItem = document.querySelector(POPOVER_ITEM_TESTID);
510
+
511
+ if (popoverItem) {
512
+ // Add the proper disabled classes and attribute that match the real implementation
513
+ // The itemDisabled class from popover-item-default.const.ts is:
514
+ // 'cursor-default pointer-events-none text-text-secondary'
515
+ // eslint-disable-next-line internal-storybook/no-class-selectors
516
+ popoverItem.classList.add('cursor-default', 'pointer-events-none', 'text-text-secondary');
517
+ popoverItem.setAttribute('data-blok-disabled', 'true');
518
+ }
519
+
520
+ await waitFor(
521
+ () => {
522
+ const disabledItem = document.querySelector('[data-blok-disabled="true"]');
523
+
524
+ expect(disabledItem).toBeInTheDocument();
525
+ },
526
+ TIMEOUT_ACTION
527
+ );
528
+ });
529
+ },
530
+ };
531
+
532
+ /**
533
+ * Mobile popover layout (full-width bottom sheet style).
534
+ */
535
+ export const MobilePopover: Story = {
536
+ args: {
537
+ data: sampleData,
538
+ minHeight: 400,
539
+ },
540
+ parameters: {
541
+ viewport: {
542
+ defaultViewport: 'mobile1',
543
+ },
544
+ chromatic: {
545
+ viewports: [375],
546
+ },
547
+ },
548
+ play: async ({ canvasElement, step }) => {
549
+ await step('Wait for editor and toolbar to initialize', async () => {
550
+ await waitFor(
551
+ () => {
552
+ const block = canvasElement.querySelector(BLOCK_TESTID);
553
+
554
+ expect(block).toBeInTheDocument();
555
+ },
556
+ TIMEOUT_INIT
557
+ );
558
+ await waitForToolbar(canvasElement);
559
+ });
560
+
561
+ await step('Click block to show toolbar', async () => {
562
+ const block = canvasElement.querySelector(BLOCK_TESTID);
563
+
564
+ if (block) {
565
+ simulateClick(block);
566
+ }
567
+
568
+ await waitFor(
569
+ () => {
570
+ const toolbar = canvasElement.querySelector(TOOLBAR_TESTID);
571
+
572
+ expect(toolbar).toHaveAttribute('data-blok-opened', 'true');
573
+ },
574
+ TIMEOUT_ACTION
575
+ );
576
+ });
577
+
578
+ await step('Open toolbox in mobile view', async () => {
579
+ const plusButton = canvasElement.querySelector(PLUS_BUTTON_TESTID);
580
+
581
+ if (plusButton) {
582
+ simulateClick(plusButton);
583
+ }
584
+
585
+ await waitFor(
586
+ () => {
587
+ const popover = document.querySelector(POPOVER_OPENED_SELECTOR);
588
+
589
+ expect(popover).toBeInTheDocument();
590
+ },
591
+ TIMEOUT_ACTION
592
+ );
593
+ });
594
+ },
595
+ };
596
+
597
+ /**
598
+ * Mobile overlay backdrop (semi-transparent background).
599
+ */
600
+ export const MobileOverlay: Story = {
601
+ args: {
602
+ data: sampleData,
603
+ minHeight: 400,
604
+ },
605
+ parameters: {
606
+ viewport: {
607
+ defaultViewport: 'mobile1',
608
+ },
609
+ chromatic: {
610
+ viewports: [375],
611
+ },
612
+ },
613
+ play: async ({ canvasElement, step }) => {
614
+ await step('Wait for editor and toolbar to initialize', async () => {
615
+ await waitFor(
616
+ () => {
617
+ const block = canvasElement.querySelector(BLOCK_TESTID);
618
+
619
+ expect(block).toBeInTheDocument();
620
+ },
621
+ TIMEOUT_INIT
622
+ );
623
+ await waitForToolbar(canvasElement);
624
+ });
625
+
626
+ await step('Click block to show toolbar', async () => {
627
+ const block = canvasElement.querySelector(BLOCK_TESTID);
628
+
629
+ if (block) {
630
+ simulateClick(block);
631
+ }
632
+
633
+ await waitFor(
634
+ () => {
635
+ const actionsZone = canvasElement.querySelector(ACTIONS_TESTID);
636
+
637
+ expect(actionsZone).toBeInTheDocument();
638
+ },
639
+ TIMEOUT_ACTION
640
+ );
641
+ });
642
+
643
+ await step('Open block tunes to show mobile overlay', async () => {
644
+ const settingsButton = canvasElement.querySelector(SETTINGS_BUTTON_TESTID);
645
+
646
+ if (settingsButton) {
647
+ simulateClick(settingsButton);
648
+ }
649
+
650
+ await waitFor(
651
+ () => {
652
+ const popover = document.querySelector(POPOVER_OPENED_SELECTOR);
653
+
654
+ expect(popover).toBeInTheDocument();
655
+
656
+ // On mobile, the overlay should be visible - check for overlay element
657
+ const popoverElements = document.querySelectorAll('[data-blok-popover-opened="true"]');
658
+ const hasOverlay = Array.from(popoverElements).some(p =>
659
+ p.querySelector('[data-blok-testid="popover-overlay"]')
660
+ );
661
+
662
+ // Overlay exists (visibility controlled by CSS media queries)
663
+ expect(hasOverlay || popover).toBeTruthy();
664
+ },
665
+ TIMEOUT_ACTION
666
+ );
667
+ });
668
+ },
669
+ };
670
+
671
+ /**
672
+ * Block settings menu with convert-to dropdown open.
673
+ */
674
+ export const BlockSettingsConvertToOpen: Story = {
675
+ args: {
676
+ data: sampleData,
677
+ tools: {
678
+ header: Header,
679
+ },
680
+ },
681
+ play: async ({ canvasElement, step }) => {
682
+ await step('Wait for editor and toolbar to initialize', async () => {
683
+ await waitFor(
684
+ () => {
685
+ const block = canvasElement.querySelector(BLOCK_TESTID);
686
+
687
+ expect(block).toBeInTheDocument();
688
+ },
689
+ TIMEOUT_INIT
690
+ );
691
+ await waitForToolbar(canvasElement);
692
+ });
693
+
694
+ await step('Click block to show toolbar', async () => {
695
+ const block = canvasElement.querySelector(BLOCK_TESTID);
696
+
697
+ if (block) {
698
+ simulateClick(block);
699
+ }
700
+
701
+ await waitFor(
702
+ () => {
703
+ const actionsZone = canvasElement.querySelector(ACTIONS_TESTID);
704
+
705
+ expect(actionsZone).toBeInTheDocument();
706
+ },
707
+ TIMEOUT_ACTION
708
+ );
709
+ });
710
+
711
+ await step('Open block settings', async () => {
712
+ const settingsButton = canvasElement.querySelector(SETTINGS_BUTTON_TESTID);
713
+
714
+ if (settingsButton) {
715
+ simulateClick(settingsButton);
716
+ }
717
+
718
+ await waitFor(
719
+ () => {
720
+ const blockTunesPopover = document.querySelector(BLOCK_TUNES_POPOVER_TESTID);
721
+
722
+ expect(blockTunesPopover).toBeInTheDocument();
723
+ },
724
+ TIMEOUT_ACTION
725
+ );
726
+ });
727
+
728
+ await step('Click convert-to button to open nested popover', async () => {
729
+ // Wait for the convert-to button to appear (it's rendered async after block settings opens)
730
+ await waitFor(
731
+ () => {
732
+ const convertToButton = document.querySelector(CONVERT_TO_SELECTOR);
733
+
734
+ expect(convertToButton).toBeInTheDocument();
735
+ },
736
+ TIMEOUT_ACTION
737
+ );
738
+
739
+ const convertToButton = document.querySelector(CONVERT_TO_SELECTOR);
740
+
741
+ if (convertToButton) {
742
+ simulateClick(convertToButton);
743
+ }
744
+
745
+ // Wait for the popover animation
746
+ await new Promise((resolve) => setTimeout(resolve, 100));
747
+
748
+ await waitFor(
749
+ () => {
750
+ // The nested popover should be opened
751
+ const nestedPopover = document.querySelector(NESTED_POPOVER_SELECTOR + POPOVER_OPENED_SELECTOR);
752
+
753
+ expect(nestedPopover).toBeInTheDocument();
754
+ },
755
+ TIMEOUT_ACTION
756
+ );
757
+ });
758
+ },
759
+ };