@jackuait/blok 0.6.0-beta.8 → 0.6.0

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 (320) hide show
  1. package/dist/blok.mjs +2 -2
  2. package/dist/chunks/{blok-bzxy6Olq.mjs → blok-BAh1rvUC.mjs} +3410 -2927
  3. package/dist/chunks/i18next-B47TKgbU.mjs +1303 -0
  4. package/dist/chunks/{i18next-loader-CzL6YHyQ.mjs → i18next-loader-CHtGO6IK.mjs} +2 -2
  5. package/dist/chunks/{index-DSSrx_Co.mjs → index-DBWWKrDe.mjs} +12 -12
  6. package/dist/chunks/{inline-tool-convert-D4SXxjDd.mjs → inline-tool-convert-DduRc0fF.mjs} +1467 -951
  7. package/dist/chunks/{messages-BogRq8lt.mjs → messages-0AbcLMLm.mjs} +6 -0
  8. package/dist/chunks/{messages-DJDG55Vq.mjs → messages-0E0AkrNu.mjs} +6 -0
  9. package/dist/{messages-DnXLrlHh.mjs → chunks/messages-4v4MuVEc.mjs} +6 -0
  10. package/dist/chunks/{messages-DnIhyAJk.mjs → messages-62v-CLC-.mjs} +6 -0
  11. package/dist/chunks/{messages-Dzwxv9v1.mjs → messages-8DeO60Oo.mjs} +6 -0
  12. package/dist/chunks/{messages-B1Aww8q7.mjs → messages-8IPXkrDl.mjs} +6 -0
  13. package/dist/{messages-uKX8WBaD.mjs → chunks/messages-96kNZDll.mjs} +6 -0
  14. package/dist/chunks/{messages-BL0tXcDf.mjs → messages-B1FZ8lxU.mjs} +6 -0
  15. package/dist/{messages-DBn76jVV.mjs → chunks/messages-B217znr-.mjs} +8 -2
  16. package/dist/{messages-DT4dP5uK.mjs → chunks/messages-B8WNljW3.mjs} +6 -0
  17. package/dist/chunks/{messages-BdeLo0N9.mjs → messages-BC8IN4Bf.mjs} +6 -0
  18. package/dist/{messages-CZygwLwM.mjs → chunks/messages-BI43k_BD.mjs} +6 -0
  19. package/dist/{messages-CzTufCHu.mjs → chunks/messages-BJ6zrz2j.mjs} +6 -0
  20. package/dist/{messages-BoJc_p1r.mjs → chunks/messages-BUl_Rcnj.mjs} +6 -0
  21. package/dist/chunks/{messages-CnwibSvh.mjs → messages-BZlmVRwn.mjs} +6 -0
  22. package/dist/{messages-C2htQ_3F.mjs → chunks/messages-BcpCubnC.mjs} +6 -0
  23. package/dist/{messages-D5C3J9qr.mjs → chunks/messages-Bm-E4iRC.mjs} +6 -0
  24. package/dist/chunks/{messages-BELRf6DU.mjs → messages-C4jL-90N.mjs} +6 -0
  25. package/dist/chunks/{messages-1fC8IMyX.mjs → messages-CDBLbUOQ.mjs} +6 -0
  26. package/dist/chunks/{messages-7QoX8DkW.mjs → messages-CH4hrauY.mjs} +6 -0
  27. package/dist/{messages-Dz9L52ol.mjs → chunks/messages-CRJ_mchV.mjs} +6 -0
  28. package/dist/chunks/{messages-JELdtT6E.mjs → messages-CW4c4cRk.mjs} +6 -0
  29. package/dist/chunks/{messages-CKI54h6O.mjs → messages-C_4otP7U.mjs} +6 -0
  30. package/dist/{messages-R3hUSvr3.mjs → chunks/messages-CfiyT2Wi.mjs} +6 -0
  31. package/dist/{messages-CJdUsQ-c.mjs → chunks/messages-CgTq3QhU.mjs} +6 -0
  32. package/dist/chunks/{messages-D1Hv8XGo.mjs → messages-Chb7k3Rg.mjs} +6 -0
  33. package/dist/{messages-Q7AO_FLv.mjs → chunks/messages-Cjjo7yHR.mjs} +6 -0
  34. package/dist/{messages-C99mq906.mjs → chunks/messages-Cl6ayUaq.mjs} +6 -0
  35. package/dist/chunks/{messages-Diu6jAaR.mjs → messages-CmR9ftc_.mjs} +6 -0
  36. package/dist/chunks/{messages-LPVfA-8K.mjs → messages-Cr49Nt3U.mjs} +6 -0
  37. package/dist/chunks/{messages-DqM1LFg5.mjs → messages-Cr94GzbX.mjs} +6 -0
  38. package/dist/{messages-BWF-zUpY.mjs → chunks/messages-CrCYPCk3.mjs} +6 -0
  39. package/dist/{messages-D-ZtY5v0.mjs → chunks/messages-Cs8zmZ3L.mjs} +6 -0
  40. package/dist/{messages-DprmQg6V.mjs → chunks/messages-CzK0LEhb.mjs} +6 -0
  41. package/dist/chunks/{messages-BSbjsyHY.mjs → messages-D00x4S8o.mjs} +6 -0
  42. package/dist/chunks/{messages-Xq8UmkVs.mjs → messages-D1mn7Zd5.mjs} +6 -0
  43. package/dist/chunks/{messages-BC86qLvI.mjs → messages-D2NOpHn9.mjs} +6 -0
  44. package/dist/{messages-kep5wtm4.mjs → chunks/messages-D4qqwVgQ.mjs} +6 -0
  45. package/dist/chunks/{messages-7W4d0DwD.mjs → messages-D5S1Dnpm.mjs} +6 -0
  46. package/dist/{messages-CY8_RyFE.mjs → chunks/messages-D7u2bmP2.mjs} +6 -0
  47. package/dist/chunks/{messages-BFG6Wlgy.mjs → messages-D85FqxgY.mjs} +6 -0
  48. package/dist/{messages-DLfR5bMd.mjs → chunks/messages-D9ndgBnU.mjs} +6 -0
  49. package/dist/{messages-CVw84KdI.mjs → chunks/messages-DDTQgImT.mjs} +6 -0
  50. package/dist/{messages-_ErNTNhk.mjs → chunks/messages-DH_jBeED.mjs} +6 -0
  51. package/dist/chunks/{messages-CMkNSDTo.mjs → messages-DRXWF0PV.mjs} +6 -0
  52. package/dist/chunks/{messages-BYyy6Wqf.mjs → messages-DVQvl8Qj.mjs} +6 -0
  53. package/dist/chunks/{messages-CznZadDf.mjs → messages-DXktiao_.mjs} +6 -0
  54. package/dist/chunks/{messages-DhLKYm2j.mjs → messages-DdK-nFGm.mjs} +6 -0
  55. package/dist/chunks/{messages-BMXCuEKO.mjs → messages-DlJbPF2T.mjs} +6 -0
  56. package/dist/chunks/{messages-CvGLfqmV.mjs → messages-DnVlmiNT.mjs} +6 -0
  57. package/dist/{messages-Z9nEU2xK.mjs → chunks/messages-DviiFSv2.mjs} +6 -0
  58. package/dist/chunks/{messages-BB5z9Uba.mjs → messages-DzqM3Fel.mjs} +6 -0
  59. package/dist/{messages-w7v1GNaE.mjs → chunks/messages-Dzzn6XoD.mjs} +6 -0
  60. package/dist/{messages-CqWJcCbY.mjs → chunks/messages-GSByFygY.mjs} +6 -0
  61. package/dist/chunks/{messages-_ncGrKHh.mjs → messages-L_kl2Qvh.mjs} +6 -0
  62. package/dist/chunks/{messages-BrPFGbM-.mjs → messages-Phkd7XmE.mjs} +6 -0
  63. package/dist/{messages-BU2nlrLK.mjs → chunks/messages-RonBBCnh.mjs} +6 -0
  64. package/dist/{messages-Bmu_S7GM.mjs → chunks/messages-VDriF5Qy.mjs} +6 -0
  65. package/dist/{messages-CLhcMlTc.mjs → chunks/messages-ZjUAIWb1.mjs} +6 -0
  66. package/dist/{messages-9SihnaXQ.mjs → chunks/messages-b1EdvUm0.mjs} +6 -0
  67. package/dist/{messages-DvFLX36Q.mjs → chunks/messages-begYOTgC.mjs} +6 -0
  68. package/dist/{messages-BMv4xwIr.mjs → chunks/messages-jrncnb-H.mjs} +6 -0
  69. package/dist/{messages-D5iv1Kox.mjs → chunks/messages-nefz1S71.mjs} +6 -0
  70. package/dist/{messages-CQwpzUFp.mjs → chunks/messages-ucTVgS5G.mjs} +6 -0
  71. package/dist/chunks/{messages-DBRw-7Zc.mjs → messages-v3GipbFl.mjs} +6 -0
  72. package/dist/{messages-C9eaarcK.mjs → chunks/messages-wmi-iFkH.mjs} +6 -0
  73. package/dist/chunks/{messages-O5tQus_0.mjs → messages-yHcs38yI.mjs} +6 -0
  74. package/dist/full.mjs +2 -2
  75. package/dist/locales.mjs +90 -84
  76. package/dist/{messages-BogRq8lt.mjs → messages-0AbcLMLm.mjs} +6 -0
  77. package/dist/{messages-DJDG55Vq.mjs → messages-0E0AkrNu.mjs} +6 -0
  78. package/dist/{chunks/messages-DnXLrlHh.mjs → messages-4v4MuVEc.mjs} +6 -0
  79. package/dist/{messages-DnIhyAJk.mjs → messages-62v-CLC-.mjs} +6 -0
  80. package/dist/{messages-Dzwxv9v1.mjs → messages-8DeO60Oo.mjs} +6 -0
  81. package/dist/{messages-B1Aww8q7.mjs → messages-8IPXkrDl.mjs} +6 -0
  82. package/dist/{chunks/messages-uKX8WBaD.mjs → messages-96kNZDll.mjs} +6 -0
  83. package/dist/{messages-BL0tXcDf.mjs → messages-B1FZ8lxU.mjs} +6 -0
  84. package/dist/{chunks/messages-DBn76jVV.mjs → messages-B217znr-.mjs} +8 -2
  85. package/dist/{chunks/messages-DT4dP5uK.mjs → messages-B8WNljW3.mjs} +6 -0
  86. package/dist/{messages-BdeLo0N9.mjs → messages-BC8IN4Bf.mjs} +6 -0
  87. package/dist/{chunks/messages-CZygwLwM.mjs → messages-BI43k_BD.mjs} +6 -0
  88. package/dist/{chunks/messages-CzTufCHu.mjs → messages-BJ6zrz2j.mjs} +6 -0
  89. package/dist/{chunks/messages-BoJc_p1r.mjs → messages-BUl_Rcnj.mjs} +6 -0
  90. package/dist/{messages-CnwibSvh.mjs → messages-BZlmVRwn.mjs} +6 -0
  91. package/dist/{chunks/messages-C2htQ_3F.mjs → messages-BcpCubnC.mjs} +6 -0
  92. package/dist/{chunks/messages-D5C3J9qr.mjs → messages-Bm-E4iRC.mjs} +6 -0
  93. package/dist/{messages-BELRf6DU.mjs → messages-C4jL-90N.mjs} +6 -0
  94. package/dist/{messages-1fC8IMyX.mjs → messages-CDBLbUOQ.mjs} +6 -0
  95. package/dist/{messages-7QoX8DkW.mjs → messages-CH4hrauY.mjs} +6 -0
  96. package/dist/{chunks/messages-Dz9L52ol.mjs → messages-CRJ_mchV.mjs} +6 -0
  97. package/dist/{messages-JELdtT6E.mjs → messages-CW4c4cRk.mjs} +6 -0
  98. package/dist/{messages-CKI54h6O.mjs → messages-C_4otP7U.mjs} +6 -0
  99. package/dist/{chunks/messages-R3hUSvr3.mjs → messages-CfiyT2Wi.mjs} +6 -0
  100. package/dist/{chunks/messages-CJdUsQ-c.mjs → messages-CgTq3QhU.mjs} +6 -0
  101. package/dist/{messages-D1Hv8XGo.mjs → messages-Chb7k3Rg.mjs} +6 -0
  102. package/dist/{chunks/messages-Q7AO_FLv.mjs → messages-Cjjo7yHR.mjs} +6 -0
  103. package/dist/{chunks/messages-C99mq906.mjs → messages-Cl6ayUaq.mjs} +6 -0
  104. package/dist/{messages-Diu6jAaR.mjs → messages-CmR9ftc_.mjs} +6 -0
  105. package/dist/{messages-LPVfA-8K.mjs → messages-Cr49Nt3U.mjs} +6 -0
  106. package/dist/{messages-DqM1LFg5.mjs → messages-Cr94GzbX.mjs} +6 -0
  107. package/dist/{chunks/messages-BWF-zUpY.mjs → messages-CrCYPCk3.mjs} +6 -0
  108. package/dist/{chunks/messages-D-ZtY5v0.mjs → messages-Cs8zmZ3L.mjs} +6 -0
  109. package/dist/{chunks/messages-DprmQg6V.mjs → messages-CzK0LEhb.mjs} +6 -0
  110. package/dist/{messages-BSbjsyHY.mjs → messages-D00x4S8o.mjs} +6 -0
  111. package/dist/{messages-Xq8UmkVs.mjs → messages-D1mn7Zd5.mjs} +6 -0
  112. package/dist/{messages-BC86qLvI.mjs → messages-D2NOpHn9.mjs} +6 -0
  113. package/dist/{chunks/messages-kep5wtm4.mjs → messages-D4qqwVgQ.mjs} +6 -0
  114. package/dist/{messages-7W4d0DwD.mjs → messages-D5S1Dnpm.mjs} +6 -0
  115. package/dist/{chunks/messages-CY8_RyFE.mjs → messages-D7u2bmP2.mjs} +6 -0
  116. package/dist/{messages-BFG6Wlgy.mjs → messages-D85FqxgY.mjs} +6 -0
  117. package/dist/{chunks/messages-DLfR5bMd.mjs → messages-D9ndgBnU.mjs} +6 -0
  118. package/dist/{chunks/messages-CVw84KdI.mjs → messages-DDTQgImT.mjs} +6 -0
  119. package/dist/{chunks/messages-_ErNTNhk.mjs → messages-DH_jBeED.mjs} +6 -0
  120. package/dist/{messages-CMkNSDTo.mjs → messages-DRXWF0PV.mjs} +6 -0
  121. package/dist/{messages-BYyy6Wqf.mjs → messages-DVQvl8Qj.mjs} +6 -0
  122. package/dist/{messages-CznZadDf.mjs → messages-DXktiao_.mjs} +6 -0
  123. package/dist/{messages-DhLKYm2j.mjs → messages-DdK-nFGm.mjs} +6 -0
  124. package/dist/{messages-BMXCuEKO.mjs → messages-DlJbPF2T.mjs} +6 -0
  125. package/dist/{messages-CvGLfqmV.mjs → messages-DnVlmiNT.mjs} +6 -0
  126. package/dist/{chunks/messages-Z9nEU2xK.mjs → messages-DviiFSv2.mjs} +6 -0
  127. package/dist/{messages-BB5z9Uba.mjs → messages-DzqM3Fel.mjs} +6 -0
  128. package/dist/{chunks/messages-w7v1GNaE.mjs → messages-Dzzn6XoD.mjs} +6 -0
  129. package/dist/{chunks/messages-CqWJcCbY.mjs → messages-GSByFygY.mjs} +6 -0
  130. package/dist/{messages-_ncGrKHh.mjs → messages-L_kl2Qvh.mjs} +6 -0
  131. package/dist/{messages-BrPFGbM-.mjs → messages-Phkd7XmE.mjs} +6 -0
  132. package/dist/{chunks/messages-BU2nlrLK.mjs → messages-RonBBCnh.mjs} +6 -0
  133. package/dist/{chunks/messages-Bmu_S7GM.mjs → messages-VDriF5Qy.mjs} +6 -0
  134. package/dist/{chunks/messages-CLhcMlTc.mjs → messages-ZjUAIWb1.mjs} +6 -0
  135. package/dist/{chunks/messages-9SihnaXQ.mjs → messages-b1EdvUm0.mjs} +6 -0
  136. package/dist/{chunks/messages-DvFLX36Q.mjs → messages-begYOTgC.mjs} +6 -0
  137. package/dist/{chunks/messages-BMv4xwIr.mjs → messages-jrncnb-H.mjs} +6 -0
  138. package/dist/{chunks/messages-D5iv1Kox.mjs → messages-nefz1S71.mjs} +6 -0
  139. package/dist/{chunks/messages-CQwpzUFp.mjs → messages-ucTVgS5G.mjs} +6 -0
  140. package/dist/{messages-DBRw-7Zc.mjs → messages-v3GipbFl.mjs} +6 -0
  141. package/dist/{chunks/messages-C9eaarcK.mjs → messages-wmi-iFkH.mjs} +6 -0
  142. package/dist/{messages-O5tQus_0.mjs → messages-yHcs38yI.mjs} +6 -0
  143. package/dist/tools.mjs +3194 -1690
  144. package/dist/vendor.LICENSE.txt +109 -109
  145. package/package.json +43 -57
  146. package/src/blok.ts +12 -0
  147. package/src/components/__module.ts +21 -0
  148. package/src/components/block/api.ts +17 -0
  149. package/src/components/block/style-manager.ts +6 -2
  150. package/src/components/block/tool-renderer.ts +33 -30
  151. package/src/components/blocks.ts +132 -15
  152. package/src/components/i18n/locales/am/messages.json +6 -0
  153. package/src/components/i18n/locales/ar/messages.json +6 -0
  154. package/src/components/i18n/locales/az/messages.json +6 -0
  155. package/src/components/i18n/locales/bg/messages.json +6 -0
  156. package/src/components/i18n/locales/bn/messages.json +6 -0
  157. package/src/components/i18n/locales/bs/messages.json +6 -0
  158. package/src/components/i18n/locales/cs/messages.json +6 -0
  159. package/src/components/i18n/locales/da/messages.json +6 -0
  160. package/src/components/i18n/locales/de/messages.json +6 -0
  161. package/src/components/i18n/locales/dv/messages.json +6 -0
  162. package/src/components/i18n/locales/el/messages.json +6 -0
  163. package/src/components/i18n/locales/en/messages.json +6 -0
  164. package/src/components/i18n/locales/es/messages.json +6 -0
  165. package/src/components/i18n/locales/et/messages.json +6 -0
  166. package/src/components/i18n/locales/fa/messages.json +6 -0
  167. package/src/components/i18n/locales/fi/messages.json +6 -0
  168. package/src/components/i18n/locales/fil/messages.json +6 -0
  169. package/src/components/i18n/locales/fr/messages.json +6 -0
  170. package/src/components/i18n/locales/gu/messages.json +6 -0
  171. package/src/components/i18n/locales/he/messages.json +6 -0
  172. package/src/components/i18n/locales/hi/messages.json +6 -0
  173. package/src/components/i18n/locales/hr/messages.json +6 -0
  174. package/src/components/i18n/locales/hu/messages.json +6 -0
  175. package/src/components/i18n/locales/hy/messages.json +6 -0
  176. package/src/components/i18n/locales/id/messages.json +6 -0
  177. package/src/components/i18n/locales/it/messages.json +6 -0
  178. package/src/components/i18n/locales/ja/messages.json +6 -0
  179. package/src/components/i18n/locales/ka/messages.json +6 -0
  180. package/src/components/i18n/locales/km/messages.json +6 -0
  181. package/src/components/i18n/locales/kn/messages.json +6 -0
  182. package/src/components/i18n/locales/ko/messages.json +6 -0
  183. package/src/components/i18n/locales/ku/messages.json +6 -0
  184. package/src/components/i18n/locales/lo/messages.json +6 -0
  185. package/src/components/i18n/locales/lt/messages.json +6 -0
  186. package/src/components/i18n/locales/lv/messages.json +6 -0
  187. package/src/components/i18n/locales/mk/messages.json +6 -0
  188. package/src/components/i18n/locales/ml/messages.json +6 -0
  189. package/src/components/i18n/locales/mn/messages.json +6 -0
  190. package/src/components/i18n/locales/mr/messages.json +6 -0
  191. package/src/components/i18n/locales/ms/messages.json +6 -0
  192. package/src/components/i18n/locales/my/messages.json +6 -0
  193. package/src/components/i18n/locales/ne/messages.json +6 -0
  194. package/src/components/i18n/locales/nl/messages.json +6 -0
  195. package/src/components/i18n/locales/no/messages.json +6 -0
  196. package/src/components/i18n/locales/pa/messages.json +6 -0
  197. package/src/components/i18n/locales/pl/messages.json +6 -0
  198. package/src/components/i18n/locales/ps/messages.json +6 -0
  199. package/src/components/i18n/locales/pt/messages.json +6 -0
  200. package/src/components/i18n/locales/ro/messages.json +6 -0
  201. package/src/components/i18n/locales/ru/messages.json +6 -0
  202. package/src/components/i18n/locales/sd/messages.json +6 -0
  203. package/src/components/i18n/locales/si/messages.json +6 -0
  204. package/src/components/i18n/locales/sk/messages.json +6 -0
  205. package/src/components/i18n/locales/sl/messages.json +6 -0
  206. package/src/components/i18n/locales/sq/messages.json +6 -0
  207. package/src/components/i18n/locales/sr/messages.json +6 -0
  208. package/src/components/i18n/locales/sv/messages.json +6 -0
  209. package/src/components/i18n/locales/sw/messages.json +6 -0
  210. package/src/components/i18n/locales/ta/messages.json +6 -0
  211. package/src/components/i18n/locales/te/messages.json +6 -0
  212. package/src/components/i18n/locales/th/messages.json +6 -0
  213. package/src/components/i18n/locales/tr/messages.json +6 -0
  214. package/src/components/i18n/locales/ug/messages.json +6 -0
  215. package/src/components/i18n/locales/uk/messages.json +6 -0
  216. package/src/components/i18n/locales/ur/messages.json +6 -0
  217. package/src/components/i18n/locales/vi/messages.json +6 -0
  218. package/src/components/i18n/locales/yi/messages.json +6 -0
  219. package/src/components/i18n/locales/zh/messages.json +6 -0
  220. package/src/components/icons/index.ts +17 -0
  221. package/src/components/inline-tools/inline-tool-link.ts +1 -1
  222. package/src/components/inline-tools/inline-tool-marker.ts +737 -0
  223. package/src/components/inline-tools/utils/formatting-range-utils.ts +6 -3
  224. package/src/components/inline-tools/utils/marker-dom-utils.ts +17 -0
  225. package/src/components/modules/api/blocks.ts +34 -9
  226. package/src/components/modules/blockEvents/composers/keyboardNavigation.ts +75 -29
  227. package/src/components/modules/blockEvents/index.ts +13 -5
  228. package/src/components/modules/blockManager/blockManager.ts +81 -2
  229. package/src/components/modules/blockManager/hierarchy.ts +20 -2
  230. package/src/components/modules/blockManager/operations.ts +70 -35
  231. package/src/components/modules/blockManager/repository.ts +22 -0
  232. package/src/components/modules/blockManager/types.ts +3 -1
  233. package/src/components/modules/blockManager/yjs-sync.ts +173 -39
  234. package/src/components/modules/blockSelection.ts +3 -0
  235. package/src/components/modules/crossBlockSelection.ts +11 -3
  236. package/src/components/modules/drag/preview/DragPreview.ts +10 -2
  237. package/src/components/modules/drag/target/DropTargetDetector.ts +100 -11
  238. package/src/components/modules/drag/utils/drag.constants.ts +1 -1
  239. package/src/components/modules/normalizeInlineImages.ts +263 -0
  240. package/src/components/modules/paste/google-docs-preprocessor.ts +197 -0
  241. package/src/components/modules/paste/handlers/base.ts +43 -2
  242. package/src/components/modules/paste/handlers/html-handler.ts +1 -1
  243. package/src/components/modules/paste/handlers/index.ts +1 -0
  244. package/src/components/modules/paste/handlers/table-cells-handler.ts +104 -0
  245. package/src/components/modules/paste/index.ts +20 -3
  246. package/src/components/modules/readonly.ts +8 -2
  247. package/src/components/modules/rectangleSelection.ts +5 -2
  248. package/src/components/modules/renderer.ts +35 -0
  249. package/src/components/modules/saver.ts +52 -2
  250. package/src/components/modules/toolbar/blockSettings.ts +52 -44
  251. package/src/components/modules/toolbar/index.ts +124 -17
  252. package/src/components/modules/toolbar/inline/index.ts +4 -4
  253. package/src/components/modules/toolbar/plus-button.ts +3 -3
  254. package/src/components/modules/toolbar/settings-toggler.ts +3 -3
  255. package/src/components/modules/toolbar/styles.ts +7 -7
  256. package/src/components/modules/ui.ts +6 -6
  257. package/src/components/modules/uiControllers/controllers/blockHover.ts +16 -2
  258. package/src/components/modules/uiControllers/handlers/touch.ts +83 -10
  259. package/src/components/modules/yjs/block-observer.ts +9 -3
  260. package/src/components/modules/yjs/document-store.ts +10 -7
  261. package/src/components/modules/yjs/types.ts +8 -6
  262. package/src/components/modules/yjs/undo-history.ts +90 -11
  263. package/src/components/selection/fake-background/shadows.ts +1 -1
  264. package/src/components/shared/color-picker.ts +211 -0
  265. package/src/components/shared/color-presets.ts +25 -0
  266. package/src/components/ui/toolbox.ts +19 -11
  267. package/src/components/utils/color-mapping.ts +241 -0
  268. package/src/components/utils/notifier/draw.ts +9 -9
  269. package/src/components/utils/placeholder.ts +24 -8
  270. package/src/components/utils/popover/components/popover-item/popover-item-default/popover-item-default.const.ts +2 -2
  271. package/src/components/utils/popover/components/popover-item/popover-item-default/popover-item-default.ts +14 -12
  272. package/src/components/utils/popover/components/search-input/search-input.const.ts +2 -2
  273. package/src/components/utils/popover/popover-abstract.ts +27 -3
  274. package/src/components/utils/popover/popover-desktop.ts +26 -3
  275. package/src/components/utils/popover/popover-inline.ts +14 -1
  276. package/src/components/utils/popover/popover-mobile.ts +4 -4
  277. package/src/components/utils/popover/popover.const.ts +2 -2
  278. package/src/components/utils/sanitizer.ts +24 -3
  279. package/src/components/utils/tw.ts +17 -5
  280. package/src/stories/Header.stories.ts +106 -0
  281. package/src/stories/MarkerColors.stories.ts +730 -0
  282. package/src/stories/Popover.stories.ts +1 -3
  283. package/src/stories/Table.stories.ts +1662 -0
  284. package/src/styles/main.css +207 -37
  285. package/src/tools/header/index.ts +1 -1
  286. package/src/tools/index.ts +3 -1
  287. package/src/tools/list/caret-manager.ts +28 -10
  288. package/src/tools/list/constants.ts +2 -2
  289. package/src/tools/list/dom-builder.ts +3 -3
  290. package/src/tools/list/static-configs.ts +0 -1
  291. package/src/tools/paragraph/index.ts +15 -7
  292. package/src/tools/table/core/table-commands.ts +99 -0
  293. package/src/tools/table/core/table-controller.ts +231 -0
  294. package/src/tools/table/core/table-events.ts +102 -0
  295. package/src/tools/table/index.ts +1070 -174
  296. package/src/tools/table/ownership/table-event-broker.ts +74 -0
  297. package/src/tools/table/ownership/table-ownership-registry.ts +126 -0
  298. package/src/tools/table/table-add-controls.ts +85 -15
  299. package/src/tools/table/table-cell-blocks.ts +336 -38
  300. package/src/tools/table/table-cell-clipboard.ts +415 -0
  301. package/src/tools/table/table-cell-color-picker.ts +34 -0
  302. package/src/tools/table/table-cell-selection.ts +264 -15
  303. package/src/tools/table/table-core.ts +3 -42
  304. package/src/tools/table/table-heading-toggle.ts +2 -2
  305. package/src/tools/table/table-model.ts +623 -0
  306. package/src/tools/table/table-operations.ts +59 -78
  307. package/src/tools/table/table-resize.ts +15 -11
  308. package/src/tools/table/table-restrictions.ts +69 -3
  309. package/src/tools/table/table-row-col-action-handler.ts +22 -7
  310. package/src/tools/table/table-row-col-controls.ts +129 -12
  311. package/src/tools/table/table-row-col-drag.ts +14 -0
  312. package/src/tools/table/table-scroll-haze.ts +152 -0
  313. package/src/tools/table/types.ts +22 -1
  314. package/src/tools/table/view/table-cell-blocks-adapter.ts +47 -0
  315. package/src/variants/blok-minimum.ts +13 -0
  316. package/types/api/block.d.ts +13 -0
  317. package/types/api/blocks.d.ts +16 -0
  318. package/types/tools/table.d.ts +2 -0
  319. package/dist/chunks/i18next-CugVlwWp.mjs +0 -1292
  320. package/src/tools/table/data-normalizer.ts +0 -32
@@ -1,5 +1,8 @@
1
1
  import type { PasteEvent, PasteEventDetail } from '../../../../../types';
2
2
  import type { BlokModules } from '../../../../types-internal/blok-modules';
3
+ import { getRestrictedTools } from '../../../../tools/table/table-restrictions';
4
+ import { Dom } from '../../../dom';
5
+ import { clean } from '../../../utils/sanitizer';
3
6
  import type { SanitizerConfigBuilder } from '../sanitizer-config';
4
7
  import type { ToolRegistry } from '../tool-registry';
5
8
  import type { HandlerContext, PasteData } from '../types';
@@ -65,6 +68,34 @@ export abstract class BasePasteHandler implements PasteHandler {
65
68
  return isCurrentBlockDefault && currentBlock.isEmpty;
66
69
  }
67
70
 
71
+ /**
72
+ * If we're inside a table cell and any pasted item uses a tool that can't
73
+ * be nested in table cells (e.g. table, header), redirect the insertion
74
+ * point to the parent table block. This prevents new block DOM elements
75
+ * from being placed inside the existing table's grid structure, which
76
+ * would corrupt the table's saved data.
77
+ */
78
+ private redirectToTableParentIfNeeded(data: PasteData[], BlockManager: BlokModules['BlockManager']): void {
79
+ const currentBlock = BlockManager.currentBlock;
80
+ const isInsideTableCell = currentBlock?.holder?.closest('[data-blok-table-cell-blocks]');
81
+ const restricted = new Set(getRestrictedTools());
82
+ const hasRestrictedTools = data.some(item => restricted.has(item.tool));
83
+
84
+ if (!isInsideTableCell || !hasRestrictedTools || currentBlock === undefined) {
85
+ return;
86
+ }
87
+
88
+ const tableBlockHolder = currentBlock.holder
89
+ .closest('[data-blok-tool="table"]')
90
+ ?.closest('[data-blok-element]') as HTMLElement | null;
91
+
92
+ if (!tableBlockHolder) {
93
+ return;
94
+ }
95
+
96
+ BlockManager.setCurrentBlockByChildNode(tableBlockHolder);
97
+ }
98
+
68
99
  /**
69
100
  * Insert paste data as blocks.
70
101
  */
@@ -82,7 +113,19 @@ export abstract class BasePasteHandler implements PasteHandler {
82
113
  const isMultipleItems = data.length > 1;
83
114
 
84
115
  if (isMultipleItems) {
116
+ this.redirectToTableParentIfNeeded(data, BlockManager);
117
+
85
118
  for (const [index, pasteData] of data.entries()) {
119
+ /**
120
+ * Force each pasted block into its own Yjs undo entry so that
121
+ * Ctrl+Z removes them one at a time.
122
+ *
123
+ * paste() wraps insert() in withAtomicOperation() which suppresses
124
+ * the normal stopCapturing() from currentBlockIndexValue changes.
125
+ * Without this, consecutive addBlock() calls within the 500ms
126
+ * captureTimeout get merged into a single undo entry.
127
+ */
128
+ this.Blok.YjsManager.stopCapturing();
86
129
  await this.insertBlock(pasteData, index === 0 && canReplaceCurrentBlock);
87
130
  }
88
131
 
@@ -129,7 +172,6 @@ export abstract class BasePasteHandler implements PasteHandler {
129
172
  protected async processSingleBlock(dataToInsert: PasteData, canReplaceCurrentBlock: boolean): Promise<void> {
130
173
  const { Caret, BlockManager } = this.Blok;
131
174
  const { currentBlock } = BlockManager;
132
- const { Dom } = await import('../../../dom');
133
175
  const $ = Dom;
134
176
 
135
177
  if (
@@ -159,7 +201,6 @@ export abstract class BasePasteHandler implements PasteHandler {
159
201
  return;
160
202
  }
161
203
 
162
- const { clean } = await import('../../../utils/sanitizer');
163
204
  const currentToolSanitizeConfig = currentBlock.tool.baseSanitizeConfig;
164
205
 
165
206
  Caret.insertContentAtCaretPosition(
@@ -107,7 +107,7 @@ export class HtmlHandler extends BasePasteHandler implements PasteHandler {
107
107
  const toolTags = this.buildToolTags(tool);
108
108
 
109
109
  const structuralSanitizeConfig = this.sanitizerBuilder.getStructuralTagsConfig(content);
110
- const customConfig = Object.assign({}, structuralSanitizeConfig, toolTags, tool.baseSanitizeConfig);
110
+ const customConfig: SanitizerConfig = { ...structuralSanitizeConfig, ...toolTags, ...tool.baseSanitizeConfig, br: {} };
111
111
  const sanitizedContent = this.sanitizeContent(content, customConfig);
112
112
 
113
113
  if (!sanitizedContent) {
@@ -5,4 +5,5 @@ export { BlokDataHandler } from './blok-data-handler';
5
5
  export { FilesHandler } from './files-handler';
6
6
  export { HtmlHandler } from './html-handler';
7
7
  export { PatternHandler } from './pattern-handler';
8
+ export { TableCellsHandler } from './table-cells-handler';
8
9
  export { TextHandler } from './text-handler';
@@ -0,0 +1,104 @@
1
+ import type { BlokModules } from '../../../../types-internal/blok-modules';
2
+ import { parseClipboardHtml } from '../../../../tools/table/table-cell-clipboard';
3
+ import type { CellContent, LegacyCellContent } from '../../../../tools/table/types';
4
+ import type { SanitizerConfigBuilder } from '../sanitizer-config';
5
+ import type { ToolRegistry } from '../tool-registry';
6
+ import type { HandlerContext } from '../types';
7
+
8
+ import type { PasteHandler } from './base';
9
+ import { BasePasteHandler } from './base';
10
+
11
+ /**
12
+ * Handles pasting table cell clipboard data outside of a table.
13
+ * Creates a new Table block with the pasted cell content.
14
+ * Priority 90: higher than HTML (40) but lower than BlokData (100).
15
+ */
16
+ export class TableCellsHandler extends BasePasteHandler implements PasteHandler {
17
+ constructor(
18
+ Blok: BlokModules,
19
+ toolRegistry: ToolRegistry,
20
+ sanitizerBuilder: SanitizerConfigBuilder,
21
+ ) {
22
+ super(Blok, toolRegistry, sanitizerBuilder);
23
+ }
24
+
25
+ canHandle(data: unknown): number {
26
+ if (typeof data !== 'string') {
27
+ return 0;
28
+ }
29
+
30
+ return parseClipboardHtml(data) !== null ? 90 : 0;
31
+ }
32
+
33
+ async handle(data: unknown, context: HandlerContext): Promise<boolean> {
34
+ if (typeof data !== 'string') {
35
+ return false;
36
+ }
37
+
38
+ const payload = parseClipboardHtml(data);
39
+
40
+ if (!payload) {
41
+ return false;
42
+ }
43
+
44
+ // If cursor is inside a table cell, let the grid paste listener handle it
45
+ const activeElement = document.activeElement as HTMLElement | null;
46
+
47
+ if (activeElement?.closest('[data-blok-table-cell]')) {
48
+ return false;
49
+ }
50
+
51
+ const { BlockManager, Caret } = this.Blok;
52
+
53
+ // Build table content from the clipboard payload.
54
+ // When a cell has color or textColor, use a CellContent object to preserve
55
+ // the colors — the Table tool will create paragraph blocks during its
56
+ // rendered() lifecycle. For cells without colors, store plain text strings
57
+ // which the Table tool migrates to blocks normally.
58
+ const content: LegacyCellContent[][] = payload.cells.map(row =>
59
+ row.map(cell => {
60
+ const text = cell.blocks.length === 0
61
+ ? ''
62
+ : cell.blocks
63
+ .map(b => (typeof b.data.text === 'string' ? b.data.text : ''))
64
+ .join(' ');
65
+
66
+ const hasColor = cell.color !== undefined;
67
+ const hasTextColor = cell.textColor !== undefined;
68
+
69
+ if (!hasColor && !hasTextColor) {
70
+ return text;
71
+ }
72
+
73
+ const cellContent: CellContent = { blocks: [], text };
74
+
75
+ if (hasColor) {
76
+ cellContent.color = cell.color;
77
+ }
78
+
79
+ if (hasTextColor) {
80
+ cellContent.textColor = cell.textColor;
81
+ }
82
+
83
+ return cellContent;
84
+ }),
85
+ );
86
+
87
+ const tableData = {
88
+ withHeadings: false,
89
+ withHeadingColumn: false,
90
+ content,
91
+ };
92
+
93
+ const canReplace = context.canReplaceCurrentBlock;
94
+ const block = BlockManager.insert({
95
+ tool: 'table',
96
+ data: tableData,
97
+ replace: canReplace,
98
+ });
99
+
100
+ Caret.setToBlock(block, Caret.positions.END);
101
+
102
+ return true;
103
+ }
104
+ }
@@ -3,11 +3,13 @@ import { Module } from '../../__module';
3
3
  import { Dom as dom$ } from '../../dom';
4
4
  import { composeSanitizerConfig, clean } from '../../utils/sanitizer';
5
5
 
6
+ import { preprocessGoogleDocsHtml } from './google-docs-preprocessor';
6
7
  import type { PasteHandler } from './handlers/base';
7
8
  import { BlokDataHandler } from './handlers/blok-data-handler';
8
9
  import { FilesHandler } from './handlers/files-handler';
9
10
  import { HtmlHandler } from './handlers/html-handler';
10
11
  import { PatternHandler } from './handlers/pattern-handler';
12
+ import { TableCellsHandler } from './handlers/table-cells-handler';
11
13
  import { TextHandler } from './handlers/text-handler';
12
14
  import { SanitizerConfigBuilder } from './sanitizer-config';
13
15
  import { ToolRegistry } from './tool-registry';
@@ -44,6 +46,7 @@ export class Paste extends Module {
44
46
  // Initialize handlers in priority order (higher priority first)
45
47
  this.handlers = [
46
48
  new BlokDataHandler(this.Blok, this.toolRegistry, this.sanitizerBuilder, this.config),
49
+ new TableCellsHandler(this.Blok, this.toolRegistry, this.sanitizerBuilder),
47
50
  new FilesHandler(this.Blok, this.toolRegistry, this.sanitizerBuilder),
48
51
  new PatternHandler(this.Blok, this.toolRegistry, this.sanitizerBuilder),
49
52
  new HtmlHandler(this.Blok, this.toolRegistry, this.sanitizerBuilder),
@@ -128,7 +131,8 @@ export class Paste extends Module {
128
131
  const canReplaceCurrentBlock = Boolean(
129
132
  currentBlock &&
130
133
  currentBlock.tool.isDefault &&
131
- currentBlock.isEmpty
134
+ currentBlock.isEmpty &&
135
+ !currentBlock.holder?.closest('[data-blok-table-cell-blocks]')
132
136
  );
133
137
 
134
138
  const context: HandlerContext = {
@@ -175,6 +179,10 @@ export class Paste extends Module {
175
179
  return blokData;
176
180
  }
177
181
 
182
+ if (handler instanceof TableCellsHandler) {
183
+ return rawHtmlData;
184
+ }
185
+
178
186
  if (handler instanceof FilesHandler) {
179
187
  return dataTransfer;
180
188
  }
@@ -201,7 +209,8 @@ export class Paste extends Module {
201
209
  { br: {} }
202
210
  );
203
211
 
204
- const cleanData = clean(rawHtmlData, customConfig);
212
+ const preprocessed = preprocessGoogleDocsHtml(rawHtmlData);
213
+ const cleanData = clean(preprocessed, customConfig);
205
214
  const cleanDataIsHtml = dom$.isHTMLString(cleanData);
206
215
  const shouldProcessAsPlain = !cleanData.trim() || (cleanData.trim() === plainData || !cleanDataIsHtml);
207
216
 
@@ -267,6 +276,14 @@ export class Paste extends Module {
267
276
  * Check if Blok should process pasted data and pass data transfer object to handler.
268
277
  */
269
278
  private handlePasteEvent = async (event: ClipboardEvent): Promise<void> => {
279
+ /**
280
+ * If the event was already handled (e.g., by the table grid paste listener),
281
+ * skip processing to prevent duplicate content insertion.
282
+ */
283
+ if (event.defaultPrevented) {
284
+ return;
285
+ }
286
+
270
287
  const { BlockManager, Toolbar } = this.Blok;
271
288
 
272
289
  const currentBlock = BlockManager.setCurrentBlockByChildNode(event.target as HTMLElement);
@@ -288,6 +305,6 @@ export class Paste extends Module {
288
305
  await this.processDataTransfer(event.clipboardData);
289
306
  }
290
307
 
291
- Toolbar.close();
308
+ Toolbar.moveAndOpen();
292
309
  };
293
310
  }
@@ -117,8 +117,14 @@ export class ReadOnly extends Module {
117
117
  return this.readOnlyEnabled;
118
118
  }
119
119
 
120
- await this.Blok.BlockManager.clear();
121
- await this.Blok.Renderer.render(savedBlocks.blocks);
120
+ this.Blok.Renderer.markRenderStart();
121
+
122
+ try {
123
+ await this.Blok.BlockManager.clear();
124
+ await this.Blok.Renderer.render(savedBlocks.blocks);
125
+ } finally {
126
+ this.Blok.Renderer.markRenderEnd();
127
+ }
122
128
 
123
129
  this.Blok.ModificationsObserver.enable();
124
130
 
@@ -611,9 +611,12 @@ export class RectangleSelection extends Module {
611
611
  };
612
612
  }
613
613
  const blockInCurrentPos = this.Blok.BlockManager.getBlockByChildNode(elementUnderMouse);
614
+ const rootBlock = blockInCurrentPos !== undefined
615
+ ? this.Blok.BlockManager.resolveToRootBlock(blockInCurrentPos)
616
+ : undefined;
614
617
 
615
- const index = blockInCurrentPos !== undefined
616
- ? this.Blok.BlockManager.blocks.findIndex((block) => block.holder === blockInCurrentPos.holder)
618
+ const index = rootBlock !== undefined
619
+ ? this.Blok.BlockManager.blocks.findIndex((block) => block.holder === rootBlock.holder)
617
620
  : undefined;
618
621
 
619
622
  return {
@@ -20,6 +20,41 @@ export class Renderer extends Module {
20
20
  */
21
21
  private detectedInputFormat: DataFormatAnalysis['format'] = 'flat';
22
22
 
23
+ /**
24
+ * Promise that resolves when an in-progress render operation completes.
25
+ * Used by Saver to wait for render to finish before reading blocks.
26
+ * null when no render is in progress.
27
+ */
28
+ public pendingRender: Promise<void> | null = null;
29
+
30
+ /**
31
+ * Resolve function for the current pendingRender promise.
32
+ * Called when the render operation is done (in finally block).
33
+ */
34
+ private resolvePendingRender: (() => void) | null = null;
35
+
36
+ /**
37
+ * Signals that a render operation is starting.
38
+ * Sets pendingRender so that Saver can await it.
39
+ */
40
+ public markRenderStart(): void {
41
+ this.pendingRender = new Promise<void>((resolve) => {
42
+ this.resolvePendingRender = resolve;
43
+ });
44
+ }
45
+
46
+ /**
47
+ * Signals that a render operation has completed.
48
+ * Resolves pendingRender so that any waiting Saver call can proceed.
49
+ */
50
+ public markRenderEnd(): void {
51
+ if (this.resolvePendingRender !== null) {
52
+ this.resolvePendingRender();
53
+ this.resolvePendingRender = null;
54
+ }
55
+ this.pendingRender = null;
56
+ }
57
+
23
58
  /**
24
59
  * Get the detected input format
25
60
  */
@@ -12,6 +12,7 @@ import type { Block } from '../block';
12
12
  import { getBlokVersion, isEmpty, isObject, log, logLabeled } from '../utils';
13
13
  import { collapseToLegacy, shouldCollapseToLegacy } from '../utils/data-model-transform';
14
14
  import { sanitizeBlocks } from '../utils/sanitizer';
15
+ import { normalizeInlineImages } from './normalizeInlineImages';
15
16
 
16
17
  type SaverValidatedData = ValidatedData & {
17
18
  tunes?: Record<string, BlockTuneData>;
@@ -40,10 +41,52 @@ export class Saver extends Module {
40
41
  private lastSaveError?: unknown;
41
42
 
42
43
  /**
43
- * Composes new chain of Promises to fire them alternatelly
44
+ * Stores the in-flight save promise for deduplication.
45
+ * If a save is already in progress, subsequent calls return the same promise.
46
+ */
47
+ private pendingSave: Promise<OutputData | undefined> | null = null;
48
+
49
+ /**
50
+ * Composes new chain of Promises to fire them alternatelly.
51
+ * Deduplicates concurrent calls — if a save is already in-flight, returns the same promise.
44
52
  * @returns {OutputData | undefined}
45
53
  */
46
54
  public async save(): Promise<OutputData | undefined> {
55
+ if (this.isDestroyed) {
56
+ return undefined;
57
+ }
58
+
59
+ if (this.pendingSave !== null) {
60
+ return this.pendingSave;
61
+ }
62
+
63
+ this.pendingSave = this.doSave();
64
+
65
+ try {
66
+ return await this.pendingSave;
67
+ } finally {
68
+ this.pendingSave = null;
69
+ }
70
+ }
71
+
72
+ /**
73
+ * Internal save implementation.
74
+ * Waits for any pending render to complete before reading blocks.
75
+ * @returns {OutputData | undefined}
76
+ */
77
+ private async doSave(): Promise<OutputData | undefined> {
78
+ // Wait for any in-progress render to complete before reading blocks
79
+ const pendingRender = this.Blok.Renderer?.pendingRender;
80
+
81
+ if (pendingRender !== null && pendingRender !== undefined) {
82
+ await pendingRender;
83
+ }
84
+
85
+ // Check again after awaiting — editor may have been destroyed during the wait
86
+ if (this.isDestroyed) {
87
+ return undefined;
88
+ }
89
+
47
90
  const { BlockManager, Tools } = this.Blok;
48
91
  const blocks = BlockManager.blocks;
49
92
 
@@ -75,7 +118,14 @@ export class Saver extends Module {
75
118
  this.config.sanitizer as SanitizerConfig
76
119
  );
77
120
 
78
- return this.makeOutput(sanitizedData);
121
+ const normalizedData = normalizeInlineImages(sanitizedData);
122
+
123
+ // Check destruction one more time after async block.save() operations
124
+ if (this.isDestroyed) {
125
+ return undefined;
126
+ }
127
+
128
+ return this.makeOutput(normalizedData);
79
129
  } catch (error: unknown) {
80
130
  this.lastSaveError = error;
81
131
 
@@ -160,61 +160,69 @@ export class BlockSettings extends Module<BlockSettingsNodes> {
160
160
  * Set isOpening flag BEFORE async operations to prevent toolbar from moving
161
161
  * while menu items are being created. This fixes a bug where hovering over a different
162
162
  * block during async getTunesItems() causes the toolbar to reposition incorrectly.
163
+ *
164
+ * Wrapped in try/catch to guarantee isOpening is always reset — if any step
165
+ * (getTunes, getTunesItems, PopoverClass constructor) throws, without cleanup
166
+ * the flag stays true and the toolbar permanently stops appearing on hover.
163
167
  */
164
168
  this.isOpening = true;
165
169
 
166
- /**
167
- * If block settings contains any inputs, focus will be set there,
168
- * so we need to save current selection to restore it after block settings is closed
169
- */
170
- this.selection.save();
170
+ try {
171
+ /**
172
+ * If block settings contains any inputs, focus will be set there,
173
+ * so we need to save current selection to restore it after block settings is closed
174
+ */
175
+ this.selection.save();
171
176
 
172
- /**
173
- * Highlight content of a Block we are working with
174
- * For multiple blocks, they should already be selected
175
- */
176
- if (!hasMultipleBlocksSelected) {
177
- this.Blok.BlockSelection.selectBlock(block);
178
- this.Blok.BlockSelection.clearCache();
179
- }
177
+ /**
178
+ * Highlight content of a Block we are working with
179
+ * For multiple blocks, they should already be selected
180
+ */
181
+ if (!hasMultipleBlocksSelected) {
182
+ this.Blok.BlockSelection.selectBlock(block);
183
+ this.Blok.BlockSelection.clearCache();
184
+ }
180
185
 
181
- /** Get tool's settings data - only relevant for single block selection */
182
- const { toolTunes, commonTunes } = block.getTunes();
183
-
184
- const PopoverClass = isMobileScreen() ? PopoverMobile : PopoverDesktop;
185
- const popoverParams: PopoverParams & { flipper?: Flipper } = {
186
- searchable: false,
187
- trigger: trigger || this.nodes.wrapper,
188
- items: await this.getTunesItems(block, commonTunes, toolTunes),
189
- scopeElement: this.Blok.API.methods.ui.nodes.redactor,
190
- messages: {
191
- nothingFound: this.Blok.I18n.t('popover.nothingFound'),
192
- search: this.Blok.I18n.t('popover.search'),
193
- },
194
- };
186
+ /** Get tool's settings data - only relevant for single block selection */
187
+ const { toolTunes, commonTunes } = block.getTunes();
188
+
189
+ const PopoverClass = isMobileScreen() ? PopoverMobile : PopoverDesktop;
190
+ const popoverParams: PopoverParams & { flipper?: Flipper } = {
191
+ searchable: false,
192
+ trigger: trigger || this.nodes.wrapper,
193
+ items: await this.getTunesItems(block, commonTunes, toolTunes),
194
+ scopeElement: this.Blok.API.methods.ui.nodes.redactor,
195
+ messages: {
196
+ nothingFound: this.Blok.I18n.t('popover.nothingFound'),
197
+ search: this.Blok.I18n.t('popover.search'),
198
+ },
199
+ };
195
200
 
196
- if (PopoverClass === PopoverDesktop) {
197
- popoverParams.flipper = this.flipperInstance;
198
- }
201
+ if (PopoverClass === PopoverDesktop) {
202
+ popoverParams.flipper = this.flipperInstance;
203
+ }
199
204
 
200
- this.popover = new PopoverClass(popoverParams);
201
- this.popover.getElement().setAttribute('data-blok-testid', 'block-tunes-popover');
205
+ this.popover = new PopoverClass(popoverParams);
206
+ this.popover.getElement().setAttribute('data-blok-testid', 'block-tunes-popover');
202
207
 
203
- this.popover.on(PopoverEvent.Closed, this.onPopoverClose);
208
+ this.popover.on(PopoverEvent.Closed, this.onPopoverClose);
204
209
 
205
- /**
206
- * Set opened flag AFTER popover is created to prevent race conditions
207
- * where close() is called during the async getTunesItems() call
208
- * when opened=true but popover is still null
209
- */
210
- this.opened = true;
211
- this.isOpening = false; // Clear isOpening flag after popover is created
210
+ /**
211
+ * Set opened flag AFTER popover is created to prevent race conditions
212
+ * where close() is called during the async getTunesItems() call
213
+ * when opened=true but popover is still null
214
+ */
215
+ this.opened = true;
216
+ this.isOpening = false;
212
217
 
213
- /** Tell to subscribers that block settings is opened */
214
- this.eventsDispatcher.emit(this.events.opened);
218
+ /** Tell to subscribers that block settings is opened */
219
+ this.eventsDispatcher.emit(this.events.opened);
215
220
 
216
- this.popover.show();
217
- this.attachFlipperKeydownListener(block);
221
+ this.popover.show();
222
+ this.attachFlipperKeydownListener(block);
223
+ } catch {
224
+ this.isOpening = false;
225
+ }
218
226
  }
219
227
 
220
228
  /**