@jackuait/blok 0.6.0-beta.9 → 0.7.0-beta.1

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 (336) hide show
  1. package/dist/blok.mjs +2 -2
  2. package/dist/chunks/{blok-Bn6Q_o8h.mjs → blok-ob9Fwr1L.mjs} +3414 -2975
  3. package/dist/chunks/i18next-B47TKgbU.mjs +1303 -0
  4. package/dist/chunks/{i18next-loader-DjR4d8M7.mjs → i18next-loader-Bu3vFvye.mjs} +2 -2
  5. package/dist/chunks/{index-oe38cp86.mjs → index-CZmRzRIX.mjs} +12 -12
  6. package/dist/chunks/{inline-tool-convert-SRTkyaZn.mjs → inline-tool-convert-CvFW2iie.mjs} +1579 -961
  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 +30 -27
  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 +3537 -1710
  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/constants/data-attributes.ts +7 -0
  153. package/src/components/i18n/locales/am/messages.json +6 -0
  154. package/src/components/i18n/locales/ar/messages.json +6 -0
  155. package/src/components/i18n/locales/az/messages.json +6 -0
  156. package/src/components/i18n/locales/bg/messages.json +6 -0
  157. package/src/components/i18n/locales/bn/messages.json +6 -0
  158. package/src/components/i18n/locales/bs/messages.json +6 -0
  159. package/src/components/i18n/locales/cs/messages.json +6 -0
  160. package/src/components/i18n/locales/da/messages.json +6 -0
  161. package/src/components/i18n/locales/de/messages.json +6 -0
  162. package/src/components/i18n/locales/dv/messages.json +6 -0
  163. package/src/components/i18n/locales/el/messages.json +6 -0
  164. package/src/components/i18n/locales/en/messages.json +6 -0
  165. package/src/components/i18n/locales/es/messages.json +6 -0
  166. package/src/components/i18n/locales/et/messages.json +6 -0
  167. package/src/components/i18n/locales/fa/messages.json +6 -0
  168. package/src/components/i18n/locales/fi/messages.json +6 -0
  169. package/src/components/i18n/locales/fil/messages.json +6 -0
  170. package/src/components/i18n/locales/fr/messages.json +6 -0
  171. package/src/components/i18n/locales/gu/messages.json +6 -0
  172. package/src/components/i18n/locales/he/messages.json +6 -0
  173. package/src/components/i18n/locales/hi/messages.json +6 -0
  174. package/src/components/i18n/locales/hr/messages.json +6 -0
  175. package/src/components/i18n/locales/hu/messages.json +6 -0
  176. package/src/components/i18n/locales/hy/messages.json +6 -0
  177. package/src/components/i18n/locales/id/messages.json +6 -0
  178. package/src/components/i18n/locales/it/messages.json +6 -0
  179. package/src/components/i18n/locales/ja/messages.json +6 -0
  180. package/src/components/i18n/locales/ka/messages.json +6 -0
  181. package/src/components/i18n/locales/km/messages.json +6 -0
  182. package/src/components/i18n/locales/kn/messages.json +6 -0
  183. package/src/components/i18n/locales/ko/messages.json +6 -0
  184. package/src/components/i18n/locales/ku/messages.json +6 -0
  185. package/src/components/i18n/locales/lo/messages.json +6 -0
  186. package/src/components/i18n/locales/lt/messages.json +6 -0
  187. package/src/components/i18n/locales/lv/messages.json +6 -0
  188. package/src/components/i18n/locales/mk/messages.json +6 -0
  189. package/src/components/i18n/locales/ml/messages.json +6 -0
  190. package/src/components/i18n/locales/mn/messages.json +6 -0
  191. package/src/components/i18n/locales/mr/messages.json +6 -0
  192. package/src/components/i18n/locales/ms/messages.json +6 -0
  193. package/src/components/i18n/locales/my/messages.json +6 -0
  194. package/src/components/i18n/locales/ne/messages.json +6 -0
  195. package/src/components/i18n/locales/nl/messages.json +6 -0
  196. package/src/components/i18n/locales/no/messages.json +6 -0
  197. package/src/components/i18n/locales/pa/messages.json +6 -0
  198. package/src/components/i18n/locales/pl/messages.json +6 -0
  199. package/src/components/i18n/locales/ps/messages.json +6 -0
  200. package/src/components/i18n/locales/pt/messages.json +6 -0
  201. package/src/components/i18n/locales/ro/messages.json +6 -0
  202. package/src/components/i18n/locales/ru/messages.json +6 -0
  203. package/src/components/i18n/locales/sd/messages.json +6 -0
  204. package/src/components/i18n/locales/si/messages.json +6 -0
  205. package/src/components/i18n/locales/sk/messages.json +6 -0
  206. package/src/components/i18n/locales/sl/messages.json +6 -0
  207. package/src/components/i18n/locales/sq/messages.json +6 -0
  208. package/src/components/i18n/locales/sr/messages.json +6 -0
  209. package/src/components/i18n/locales/sv/messages.json +6 -0
  210. package/src/components/i18n/locales/sw/messages.json +6 -0
  211. package/src/components/i18n/locales/ta/messages.json +6 -0
  212. package/src/components/i18n/locales/te/messages.json +6 -0
  213. package/src/components/i18n/locales/th/messages.json +6 -0
  214. package/src/components/i18n/locales/tr/messages.json +6 -0
  215. package/src/components/i18n/locales/ug/messages.json +6 -0
  216. package/src/components/i18n/locales/uk/messages.json +6 -0
  217. package/src/components/i18n/locales/ur/messages.json +6 -0
  218. package/src/components/i18n/locales/vi/messages.json +6 -0
  219. package/src/components/i18n/locales/yi/messages.json +6 -0
  220. package/src/components/i18n/locales/zh/messages.json +6 -0
  221. package/src/components/icons/index.ts +61 -7
  222. package/src/components/inline-tools/inline-tool-link.ts +1 -1
  223. package/src/components/inline-tools/inline-tool-marker.ts +737 -0
  224. package/src/components/inline-tools/utils/formatting-range-utils.ts +6 -3
  225. package/src/components/inline-tools/utils/marker-dom-utils.ts +17 -0
  226. package/src/components/modules/api/blocks.ts +34 -9
  227. package/src/components/modules/blockEvents/composers/keyboardNavigation.ts +75 -29
  228. package/src/components/modules/blockEvents/composers/markdownShortcuts.ts +54 -2
  229. package/src/components/modules/blockEvents/constants.ts +12 -0
  230. package/src/components/modules/blockEvents/index.ts +13 -5
  231. package/src/components/modules/blockManager/blockManager.ts +81 -2
  232. package/src/components/modules/blockManager/hierarchy.ts +20 -2
  233. package/src/components/modules/blockManager/operations.ts +70 -35
  234. package/src/components/modules/blockManager/repository.ts +22 -0
  235. package/src/components/modules/blockManager/types.ts +3 -1
  236. package/src/components/modules/blockManager/yjs-sync.ts +173 -39
  237. package/src/components/modules/blockSelection.ts +3 -0
  238. package/src/components/modules/crossBlockSelection.ts +11 -3
  239. package/src/components/modules/drag/preview/DragPreview.ts +10 -2
  240. package/src/components/modules/drag/target/DropTargetDetector.ts +100 -11
  241. package/src/components/modules/drag/utils/drag.constants.ts +1 -1
  242. package/src/components/modules/normalizeInlineImages.ts +263 -0
  243. package/src/components/modules/paste/google-docs-preprocessor.ts +197 -0
  244. package/src/components/modules/paste/handlers/base.ts +43 -2
  245. package/src/components/modules/paste/handlers/html-handler.ts +1 -1
  246. package/src/components/modules/paste/handlers/index.ts +1 -0
  247. package/src/components/modules/paste/handlers/table-cells-handler.ts +104 -0
  248. package/src/components/modules/paste/index.ts +20 -3
  249. package/src/components/modules/readonly.ts +8 -2
  250. package/src/components/modules/rectangleSelection.ts +5 -2
  251. package/src/components/modules/renderer.ts +35 -0
  252. package/src/components/modules/saver.ts +52 -2
  253. package/src/components/modules/toolbar/blockSettings.ts +52 -44
  254. package/src/components/modules/toolbar/index.ts +124 -17
  255. package/src/components/modules/toolbar/inline/index.ts +4 -4
  256. package/src/components/modules/toolbar/plus-button.ts +3 -3
  257. package/src/components/modules/toolbar/settings-toggler.ts +3 -3
  258. package/src/components/modules/toolbar/styles.ts +7 -7
  259. package/src/components/modules/ui.ts +6 -6
  260. package/src/components/modules/uiControllers/controllers/blockHover.ts +16 -2
  261. package/src/components/modules/uiControllers/handlers/touch.ts +83 -10
  262. package/src/components/modules/yjs/block-observer.ts +9 -3
  263. package/src/components/modules/yjs/document-store.ts +10 -7
  264. package/src/components/modules/yjs/types.ts +8 -6
  265. package/src/components/modules/yjs/undo-history.ts +90 -11
  266. package/src/components/selection/fake-background/shadows.ts +1 -1
  267. package/src/components/shared/color-picker.ts +211 -0
  268. package/src/components/shared/color-presets.ts +25 -0
  269. package/src/components/ui/toolbox.ts +27 -11
  270. package/src/components/utils/color-mapping.ts +241 -0
  271. package/src/components/utils/notifier/draw.ts +9 -9
  272. package/src/components/utils/placeholder.ts +24 -8
  273. package/src/components/utils/popover/components/popover-item/popover-item-default/popover-item-default.const.ts +3 -3
  274. package/src/components/utils/popover/components/popover-item/popover-item-default/popover-item-default.ts +15 -12
  275. package/src/components/utils/popover/components/search-input/search-input.const.ts +2 -2
  276. package/src/components/utils/popover/popover-abstract.ts +30 -5
  277. package/src/components/utils/popover/popover-desktop.ts +26 -3
  278. package/src/components/utils/popover/popover-inline.ts +14 -1
  279. package/src/components/utils/popover/popover-mobile.ts +4 -4
  280. package/src/components/utils/popover/popover.const.ts +3 -3
  281. package/src/components/utils/sanitizer.ts +24 -3
  282. package/src/components/utils/tw.ts +17 -5
  283. package/src/full.ts +4 -0
  284. package/src/stories/Header.stories.ts +106 -0
  285. package/src/stories/MarkerColors.stories.ts +730 -0
  286. package/src/stories/Placeholder.stories.ts +7 -2
  287. package/src/stories/Popover.stories.ts +1 -3
  288. package/src/stories/Table.stories.ts +1662 -0
  289. package/src/stories/helpers.ts +2 -0
  290. package/src/styles/main.css +217 -39
  291. package/src/tools/header/index.ts +204 -26
  292. package/src/tools/index.ts +5 -1
  293. package/src/tools/list/caret-manager.ts +28 -10
  294. package/src/tools/list/constants.ts +2 -2
  295. package/src/tools/list/dom-builder.ts +3 -3
  296. package/src/tools/list/static-configs.ts +0 -1
  297. package/src/tools/paragraph/index.ts +9 -5
  298. package/src/tools/table/core/table-commands.ts +99 -0
  299. package/src/tools/table/core/table-controller.ts +231 -0
  300. package/src/tools/table/core/table-events.ts +102 -0
  301. package/src/tools/table/index.ts +1070 -174
  302. package/src/tools/table/ownership/table-event-broker.ts +74 -0
  303. package/src/tools/table/ownership/table-ownership-registry.ts +126 -0
  304. package/src/tools/table/table-add-controls.ts +85 -15
  305. package/src/tools/table/table-cell-blocks.ts +336 -38
  306. package/src/tools/table/table-cell-clipboard.ts +415 -0
  307. package/src/tools/table/table-cell-color-picker.ts +34 -0
  308. package/src/tools/table/table-cell-selection.ts +264 -15
  309. package/src/tools/table/table-core.ts +3 -42
  310. package/src/tools/table/table-heading-toggle.ts +2 -2
  311. package/src/tools/table/table-model.ts +623 -0
  312. package/src/tools/table/table-operations.ts +59 -78
  313. package/src/tools/table/table-resize.ts +15 -11
  314. package/src/tools/table/table-restrictions.ts +69 -3
  315. package/src/tools/table/table-row-col-action-handler.ts +22 -7
  316. package/src/tools/table/table-row-col-controls.ts +129 -12
  317. package/src/tools/table/table-row-col-drag.ts +14 -0
  318. package/src/tools/table/table-scroll-haze.ts +152 -0
  319. package/src/tools/table/types.ts +22 -1
  320. package/src/tools/table/view/table-cell-blocks-adapter.ts +47 -0
  321. package/src/tools/toggle/block-operations.ts +110 -0
  322. package/src/tools/toggle/constants.ts +49 -0
  323. package/src/tools/toggle/dom-builder.ts +125 -0
  324. package/src/tools/toggle/index.ts +280 -0
  325. package/src/tools/toggle/toggle-keyboard.ts +139 -0
  326. package/src/tools/toggle/toggle-lifecycle.ts +80 -0
  327. package/src/tools/toggle/toggle-shortcuts.ts +107 -0
  328. package/src/tools/toggle/types.ts +21 -0
  329. package/src/variants/blok-minimum.ts +13 -0
  330. package/types/api/block.d.ts +13 -0
  331. package/types/api/blocks.d.ts +16 -0
  332. package/types/full.d.ts +2 -0
  333. package/types/tools/table.d.ts +2 -0
  334. package/types/tools-entry.d.ts +2 -1
  335. package/dist/chunks/i18next-CugVlwWp.mjs +0 -1292
  336. package/src/tools/table/data-normalizer.ts +0 -32
@@ -0,0 +1,280 @@
1
+ /**
2
+ * Toggle Tool for the Blok Editor
3
+ * Provides collapsible toggle blocks with an arrow indicator.
4
+ *
5
+ * @license MIT
6
+ */
7
+
8
+ import type {
9
+ API,
10
+ BlockTool,
11
+ BlockToolConstructorOptions,
12
+ ToolboxConfig,
13
+ ConversionConfig,
14
+ ToolSanitizerConfig,
15
+ PasteConfig,
16
+ } from '../../../types';
17
+ import type { MenuConfig } from '../../../types/tools/menu-config';
18
+
19
+ import {
20
+ saveToggleItem,
21
+ mergeToggleItemData,
22
+ setToggleItemData,
23
+ parseHTML,
24
+ } from './block-operations';
25
+ import { PLACEHOLDER_KEY, TOOL_NAME } from './constants';
26
+ import { IconToggleList } from '../../components/icons';
27
+ import { renderToggleItem, updateArrowState, updateChildrenVisibility } from './toggle-lifecycle';
28
+ import { handleToggleEnter, handleToggleBackspace } from './toggle-keyboard';
29
+ import type { ToggleItemData, ToggleItemConfig } from './types';
30
+
31
+ export class ToggleItem implements BlockTool {
32
+ private api: API;
33
+ private readOnly: boolean;
34
+ private _settings: ToggleItemConfig;
35
+ private _data: ToggleItemData;
36
+ private _element: HTMLElement | null = null;
37
+ private _contentElement: HTMLElement | null = null;
38
+ private _arrowElement: HTMLElement | null = null;
39
+ private _isOpen: boolean = false;
40
+
41
+ private blockId?: string;
42
+
43
+ constructor({ data, config, api, readOnly, block }: BlockToolConstructorOptions<ToggleItemData, ToggleItemConfig>) {
44
+ this.api = api;
45
+ this.readOnly = readOnly;
46
+ this._settings = config || {};
47
+ this._data = this.normalizeData(data);
48
+
49
+ if (block) {
50
+ this.blockId = block.id;
51
+ }
52
+ }
53
+
54
+ private normalizeData(data: ToggleItemData | Record<string, never>): ToggleItemData {
55
+ if (typeof data === 'object' && data !== null && 'text' in data) {
56
+ return {
57
+ text: typeof data.text === 'string' ? data.text : '',
58
+ };
59
+ }
60
+
61
+ return { text: '' };
62
+ }
63
+
64
+ private get placeholder(): string {
65
+ if (this._settings.placeholder) {
66
+ return this._settings.placeholder;
67
+ }
68
+
69
+ const translated = this.api.i18n.t(PLACEHOLDER_KEY);
70
+
71
+ if (translated !== PLACEHOLDER_KEY) {
72
+ return translated;
73
+ }
74
+
75
+ return 'Toggle';
76
+ }
77
+
78
+ public render(): HTMLElement {
79
+ const result = renderToggleItem({
80
+ data: this._data,
81
+ readOnly: this.readOnly,
82
+ isOpen: this._isOpen,
83
+ placeholder: this.placeholder,
84
+ keydownHandler: this.readOnly ? null : this.handleKeyDown.bind(this),
85
+ onArrowClick: () => this.toggleOpen(),
86
+ });
87
+
88
+ this._element = result.wrapper;
89
+ this._contentElement = result.contentElement;
90
+ this._arrowElement = result.arrowElement;
91
+
92
+ return this._element;
93
+ }
94
+
95
+ public rendered(): void {
96
+ this.updateChildrenVisibility();
97
+ }
98
+
99
+ public save(): ToggleItemData {
100
+ return saveToggleItem(this._data, this._element, this.getContentElement.bind(this));
101
+ }
102
+
103
+ public validate(_blockData: ToggleItemData): boolean {
104
+ return true;
105
+ }
106
+
107
+ public merge(data: ToggleItemData): void {
108
+ mergeToggleItemData(
109
+ {
110
+ data: this._data,
111
+ getContentElement: this.getContentElement.bind(this),
112
+ parseHTML,
113
+ },
114
+ data
115
+ );
116
+ }
117
+
118
+ public setData(newData: ToggleItemData): boolean {
119
+ const result = setToggleItemData(
120
+ this._data,
121
+ newData,
122
+ this.getContentElement.bind(this)
123
+ );
124
+
125
+ this._data = result.newData;
126
+
127
+ return result.inPlace;
128
+ }
129
+
130
+ public renderSettings(): MenuConfig {
131
+ return [];
132
+ }
133
+
134
+ /**
135
+ * Expand the toggle (no-op if already expanded).
136
+ * Can be called externally via block.call('expand').
137
+ */
138
+ public expand(): void {
139
+ if (this._isOpen) {
140
+ return;
141
+ }
142
+
143
+ this.setOpenState(true);
144
+ }
145
+
146
+ /**
147
+ * Collapse the toggle (no-op if already collapsed).
148
+ * Can be called externally via block.call('collapse').
149
+ */
150
+ public collapse(): void {
151
+ if (!this._isOpen) {
152
+ return;
153
+ }
154
+
155
+ this.setOpenState(false);
156
+ }
157
+
158
+ private getContentElement(): HTMLElement | null {
159
+ return this._contentElement;
160
+ }
161
+
162
+ private setOpenState(open: boolean): void {
163
+ this._isOpen = open;
164
+
165
+ if (this._arrowElement && this._element) {
166
+ updateArrowState(this._arrowElement, this._element, this._isOpen);
167
+ }
168
+
169
+ this.updateChildrenVisibility();
170
+ }
171
+
172
+ private toggleOpen(): void {
173
+ this.setOpenState(!this._isOpen);
174
+ }
175
+
176
+ private updateChildrenVisibility(): void {
177
+ if (this.blockId === undefined) {
178
+ return;
179
+ }
180
+
181
+ updateChildrenVisibility(this.api, this.blockId, this._isOpen);
182
+ }
183
+
184
+ private handleKeyDown(event: KeyboardEvent): void {
185
+ if (event.key === 'Enter' && !event.shiftKey) {
186
+ event.preventDefault();
187
+ void this.handleEnter();
188
+
189
+ return;
190
+ }
191
+
192
+ if (event.key === 'Backspace') {
193
+ void this.handleBackspace(event);
194
+ }
195
+ }
196
+
197
+ private createKeyboardContext(): Parameters<typeof handleToggleEnter>[0] {
198
+ return {
199
+ api: this.api,
200
+ blockId: this.blockId,
201
+ data: this._data,
202
+ element: this._element,
203
+ getContentElement: this.getContentElement.bind(this),
204
+ syncContentFromDOM: this.syncContentFromDOM.bind(this),
205
+ isOpen: this._isOpen,
206
+ setOpen: (open: boolean) => {
207
+ this._isOpen = open;
208
+ },
209
+ };
210
+ }
211
+
212
+ private async handleEnter(): Promise<void> {
213
+ await handleToggleEnter(this.createKeyboardContext());
214
+ }
215
+
216
+ private async handleBackspace(event: KeyboardEvent): Promise<void> {
217
+ await handleToggleBackspace(this.createKeyboardContext(), event);
218
+ }
219
+
220
+ private syncContentFromDOM(): void {
221
+ const contentEl = this.getContentElement();
222
+
223
+ if (contentEl) {
224
+ this._data.text = contentEl.innerHTML;
225
+ }
226
+ }
227
+
228
+ public static get shortcut(): string {
229
+ return 'CMD+ALT+7';
230
+ }
231
+
232
+ public static get toolbox(): ToolboxConfig {
233
+ return {
234
+ icon: IconToggleList,
235
+ title: 'Toggle list',
236
+ titleKey: 'toggleList',
237
+ name: TOOL_NAME,
238
+ searchTerms: ['toggle', 'collapse', 'expand', 'accordion'],
239
+ };
240
+ }
241
+
242
+ public static get conversionConfig(): ConversionConfig {
243
+ return {
244
+ export: 'text',
245
+ import: 'text',
246
+ };
247
+ }
248
+
249
+ public static get sanitize(): ToolSanitizerConfig {
250
+ return {
251
+ text: {
252
+ br: true,
253
+ a: {
254
+ href: true,
255
+ target: '_blank',
256
+ rel: 'nofollow',
257
+ },
258
+ b: true,
259
+ i: true,
260
+ mark: {
261
+ class: true,
262
+ style: true,
263
+ },
264
+ code: true,
265
+ },
266
+ };
267
+ }
268
+
269
+ public static get pasteConfig(): PasteConfig {
270
+ return {
271
+ tags: ['DETAILS'],
272
+ };
273
+ }
274
+
275
+ public static get isReadOnlySupported(): boolean {
276
+ return true;
277
+ }
278
+ }
279
+
280
+ export type { ToggleItemConfig, ToggleItemData };
@@ -0,0 +1,139 @@
1
+ /**
2
+ * Toggle Keyboard - Handles keyboard interactions for toggle items.
3
+ *
4
+ * Extracted from ToggleItem to reduce file size.
5
+ */
6
+
7
+ import type { API } from '../../../types';
8
+
9
+ import { isCaretAtStartOfInput } from '../../components/utils/caret';
10
+
11
+ import { TOOL_NAME } from './constants';
12
+ import type { ToggleItemData } from './types';
13
+
14
+ /**
15
+ * Context for toggle keyboard operations
16
+ */
17
+ export interface ToggleKeyboardContext {
18
+ api: API;
19
+ blockId: string | undefined;
20
+ data: ToggleItemData;
21
+ element: HTMLElement | null;
22
+ getContentElement: () => HTMLElement | null;
23
+ syncContentFromDOM: () => void;
24
+ isOpen: boolean;
25
+ setOpen: (open: boolean) => void;
26
+ }
27
+
28
+ /**
29
+ * Handle Enter key - sync content from DOM and split the block at the caret position.
30
+ *
31
+ * @param context - The toggle keyboard context
32
+ */
33
+ export const handleToggleEnter = async (context: ToggleKeyboardContext): Promise<void> => {
34
+ const { api, blockId, data, getContentElement, syncContentFromDOM } = context;
35
+
36
+ syncContentFromDOM();
37
+
38
+ if (blockId === undefined) {
39
+ return;
40
+ }
41
+
42
+ const contentEl = getContentElement();
43
+ const selection = window.getSelection();
44
+
45
+ if (!contentEl || !selection || selection.rangeCount === 0) {
46
+ return;
47
+ }
48
+
49
+ const range = selection.getRangeAt(0);
50
+ const { beforeContent, afterContent } = splitContentAtRange(contentEl, range);
51
+
52
+ const currentBlockIndex = api.blocks.getBlockIndex(blockId) ?? api.blocks.getCurrentBlockIndex();
53
+
54
+ api.blocks.splitBlock(
55
+ blockId,
56
+ { text: beforeContent },
57
+ TOOL_NAME,
58
+ { text: afterContent },
59
+ currentBlockIndex + 1
60
+ );
61
+
62
+ data.text = beforeContent;
63
+ };
64
+
65
+ /**
66
+ * Handle Backspace key - convert to paragraph when content is empty and caret is at start.
67
+ *
68
+ * When the caret is at the very start of the content element AND the content is empty,
69
+ * converts the toggle to a paragraph block. If the caret is NOT at start, lets the
70
+ * browser handle it (does nothing).
71
+ *
72
+ * @param context - The toggle keyboard context
73
+ * @param event - The keyboard event
74
+ */
75
+ export const handleToggleBackspace = async (
76
+ context: ToggleKeyboardContext,
77
+ event: KeyboardEvent
78
+ ): Promise<void> => {
79
+ const { api, blockId, data, getContentElement } = context;
80
+
81
+ if (blockId === undefined) {
82
+ return;
83
+ }
84
+
85
+ const contentEl = getContentElement();
86
+
87
+ if (!contentEl) {
88
+ return;
89
+ }
90
+
91
+ if (!isCaretAtStartOfInput(contentEl)) {
92
+ return;
93
+ }
94
+
95
+ const text = data.text;
96
+
97
+ if (text !== '') {
98
+ return;
99
+ }
100
+
101
+ event.preventDefault();
102
+
103
+ await api.blocks.convert(blockId, 'paragraph', { text });
104
+ };
105
+
106
+ /**
107
+ * Split content element's HTML at the given range position.
108
+ *
109
+ * @param contentEl - The contenteditable element containing text
110
+ * @param range - The current selection range
111
+ * @returns Object with before/after HTML content
112
+ */
113
+ const splitContentAtRange = (
114
+ contentEl: HTMLElement,
115
+ range: Range
116
+ ): { beforeContent: string; afterContent: string } => {
117
+ if (!contentEl.lastChild) {
118
+ return { beforeContent: '', afterContent: '' };
119
+ }
120
+
121
+ const beforeRange = document.createRange();
122
+ beforeRange.setStart(contentEl, 0);
123
+ beforeRange.setEnd(range.startContainer, range.startOffset);
124
+
125
+ const afterRange = document.createRange();
126
+ afterRange.setStart(range.endContainer, range.endOffset);
127
+ afterRange.setEndAfter(contentEl.lastChild);
128
+
129
+ const beforeDiv = document.createElement('div');
130
+ beforeDiv.appendChild(beforeRange.cloneContents());
131
+
132
+ const afterDiv = document.createElement('div');
133
+ afterDiv.appendChild(afterRange.cloneContents());
134
+
135
+ return {
136
+ beforeContent: beforeDiv.innerHTML,
137
+ afterContent: afterDiv.innerHTML,
138
+ };
139
+ };
@@ -0,0 +1,80 @@
1
+ /**
2
+ * Toggle Lifecycle - Lifecycle methods for ToggleItem (render, state updates).
3
+ *
4
+ * Extracted from ToggleItem to reduce file size.
5
+ */
6
+
7
+ import type { API } from '../../../types';
8
+
9
+ import { setupPlaceholder } from '../../components/utils/placeholder';
10
+
11
+ import { TOGGLE_ATTR } from './constants';
12
+ import { buildToggleItem } from './dom-builder';
13
+ import type { ToggleDOMBuilderContext } from './dom-builder';
14
+
15
+ /**
16
+ * Context for rendering a toggle item
17
+ */
18
+ export interface ToggleRenderContext extends ToggleDOMBuilderContext {
19
+ placeholder: string;
20
+ }
21
+
22
+ /**
23
+ * Result of rendering a toggle item
24
+ */
25
+ export interface ToggleRenderResult {
26
+ wrapper: HTMLElement;
27
+ contentElement: HTMLElement;
28
+ arrowElement: HTMLElement;
29
+ }
30
+
31
+ /**
32
+ * Render a toggle item with placeholder support.
33
+ *
34
+ * @param context - The render context
35
+ * @returns Object containing the wrapper, content, and arrow elements
36
+ */
37
+ export const renderToggleItem = (context: ToggleRenderContext): ToggleRenderResult => {
38
+ const result = buildToggleItem(context);
39
+
40
+ if (result.contentElement) {
41
+ setupPlaceholder(result.contentElement, context.placeholder);
42
+ }
43
+
44
+ return result;
45
+ };
46
+
47
+ /**
48
+ * Update the arrow rotation and wrapper's open state attribute.
49
+ *
50
+ * @param arrowEl - The arrow element to rotate
51
+ * @param wrapper - The wrapper element to update the open attribute on
52
+ * @param isOpen - Whether the toggle is open
53
+ */
54
+ export const updateArrowState = (arrowEl: HTMLElement, wrapper: HTMLElement, isOpen: boolean): void => {
55
+ const { style } = arrowEl;
56
+
57
+ style.transform = isOpen ? 'rotate(90deg)' : '';
58
+ arrowEl.setAttribute('aria-label', isOpen ? 'Collapse' : 'Expand');
59
+ wrapper.setAttribute(TOGGLE_ATTR.toggleOpen, String(isOpen));
60
+ };
61
+
62
+ /**
63
+ * Show or hide child block holders based on the toggle's open state.
64
+ * Children are hidden via the 'hidden' CSS class (display: none), not removed from the DOM.
65
+ *
66
+ * @param api - Blok API instance
67
+ * @param blockId - The toggle block's id
68
+ * @param isOpen - Whether the toggle is currently open (expanded)
69
+ */
70
+ export const updateChildrenVisibility = (api: API, blockId: string, isOpen: boolean): void => {
71
+ const children = api.blocks.getChildren(blockId);
72
+
73
+ for (const child of children) {
74
+ if (isOpen) {
75
+ child.holder.classList.remove('hidden');
76
+ } else {
77
+ child.holder.classList.add('hidden');
78
+ }
79
+ }
80
+ };
@@ -0,0 +1,107 @@
1
+ /**
2
+ * Toggle Shortcuts - Manages the collapse/expand-all keyboard shortcut (CMD+ALT+T).
3
+ *
4
+ * Iterates all blocks in the editor and toggles all toggle blocks:
5
+ * - If any toggle is collapsed, expands all
6
+ * - If all toggles are expanded, collapses all
7
+ */
8
+
9
+ import type { API } from '../../../types';
10
+
11
+ import { Shortcuts } from '../../components/utils/shortcuts';
12
+
13
+ import { TOGGLE_ATTR, TOOL_NAME } from './constants';
14
+
15
+ const COLLAPSE_EXPAND_ALL_SHORTCUT = 'CMD+ALT+T';
16
+
17
+ /**
18
+ * Manages the collapse/expand-all shortcut for toggle blocks.
19
+ */
20
+ export class ToggleShortcuts {
21
+ private readonly api: API;
22
+ private readonly wrapper: HTMLElement;
23
+ private registered = false;
24
+
25
+ constructor(api: API, wrapper: HTMLElement) {
26
+ this.api = api;
27
+ this.wrapper = wrapper;
28
+ }
29
+
30
+ /**
31
+ * Register the CMD+ALT+T shortcut on the document.
32
+ */
33
+ public register(): void {
34
+ if (this.registered) {
35
+ return;
36
+ }
37
+
38
+ Shortcuts.add({
39
+ name: COLLAPSE_EXPAND_ALL_SHORTCUT,
40
+ on: document,
41
+ handler: (event: KeyboardEvent) => {
42
+ if (!this.shouldHandle(event)) {
43
+ return;
44
+ }
45
+
46
+ event.preventDefault();
47
+ this.toggleAll();
48
+ },
49
+ });
50
+
51
+ this.registered = true;
52
+ }
53
+
54
+ /**
55
+ * Unregister the shortcut.
56
+ */
57
+ public unregister(): void {
58
+ if (!this.registered) {
59
+ return;
60
+ }
61
+
62
+ Shortcuts.remove(document, COLLAPSE_EXPAND_ALL_SHORTCUT);
63
+ this.registered = false;
64
+ }
65
+
66
+ /**
67
+ * Only handle the shortcut if the event target is within the editor wrapper.
68
+ */
69
+ private shouldHandle(event: KeyboardEvent): boolean {
70
+ const target = event.target;
71
+
72
+ return target instanceof HTMLElement && this.wrapper.contains(target);
73
+ }
74
+
75
+ /**
76
+ * Toggle all toggle blocks.
77
+ * If any toggle is collapsed, expand all. If all are expanded, collapse all.
78
+ */
79
+ private toggleAll(): void {
80
+ const blockCount = this.api.blocks.getBlocksCount();
81
+ const toggleBlocks: { call: (method: string) => void; isOpen: boolean }[] = [];
82
+
83
+ for (const i of Array.from({ length: blockCount }, (_, idx) => idx)) {
84
+ const block = this.api.blocks.getBlockByIndex(i);
85
+
86
+ if (block === undefined || block.name !== TOOL_NAME) {
87
+ continue;
88
+ }
89
+
90
+ const toggleWrapper = block.holder.querySelector(`[${TOGGLE_ATTR.toggleOpen}]`);
91
+ const isOpen = toggleWrapper?.getAttribute(TOGGLE_ATTR.toggleOpen) === 'true';
92
+
93
+ toggleBlocks.push({ call: (method: string) => block.call(method), isOpen });
94
+ }
95
+
96
+ if (toggleBlocks.length === 0) {
97
+ return;
98
+ }
99
+
100
+ const anyCollapsed = toggleBlocks.some((b) => !b.isOpen);
101
+ const method = anyCollapsed ? 'expand' : 'collapse';
102
+
103
+ for (const block of toggleBlocks) {
104
+ block.call(method);
105
+ }
106
+ }
107
+ }
@@ -0,0 +1,21 @@
1
+ /**
2
+ * Type definitions for the Toggle tool
3
+ */
4
+
5
+ import type { BlockToolData } from '../../../types';
6
+
7
+ /**
8
+ * Tool's input and output data format
9
+ */
10
+ export interface ToggleItemData extends BlockToolData {
11
+ /** Toggle item text content (can include HTML) */
12
+ text: string;
13
+ }
14
+
15
+ /**
16
+ * Tool's config from Editor
17
+ */
18
+ export interface ToggleItemConfig {
19
+ /** Custom placeholder text for empty toggle items */
20
+ placeholder?: string;
21
+ }
@@ -59,6 +59,19 @@ class Blok {
59
59
  public exportAPI(blok: Core): void {
60
60
  const fieldsToExport = ['configuration'];
61
61
  const destroy = (): void => {
62
+ // Mark all modules as destroyed first so any in-flight async work stops gracefully
63
+ Object.values(blok.moduleInstances).forEach((moduleInstance) => {
64
+ if (moduleInstance === undefined || moduleInstance === null) {
65
+ return;
66
+ }
67
+
68
+ if (
69
+ isFunction((moduleInstance as { markDestroyed?: () => void }).markDestroyed)
70
+ ) {
71
+ (moduleInstance as { markDestroyed: () => void }).markDestroyed();
72
+ }
73
+ });
74
+
62
75
  Object.values(blok.moduleInstances).forEach((moduleInstance) => {
63
76
  if (moduleInstance === undefined || moduleInstance === null) {
64
77
  return;
@@ -1,4 +1,5 @@
1
1
  import {BlockToolData, ToolConfig, ToolboxConfigEntry} from '../tools';
2
+ import {BlockTuneData} from '../block-tunes/block-tune-data';
2
3
  import {SavedData} from '../data-formats';
3
4
 
4
5
  /**
@@ -35,6 +36,18 @@ export interface BlockAPI {
35
36
  */
36
37
  readonly selected: boolean;
37
38
 
39
+ /**
40
+ * Last successfully extracted block tool data (synchronous).
41
+ * Useful when async save() is not feasible, e.g. during clipboard operations.
42
+ */
43
+ readonly preservedData: BlockToolData;
44
+
45
+ /**
46
+ * Last successfully extracted tune data (synchronous).
47
+ * Useful when async save() is not feasible, e.g. during clipboard operations.
48
+ */
49
+ readonly preservedTunes: { [name: string]: BlockTuneData };
50
+
38
51
  /**
39
52
  * True if Block has inputs to be focused
40
53
  */
@@ -7,6 +7,12 @@ import {BlockTuneData} from '../block-tunes/block-tune-data';
7
7
  * Describes methods to manipulate with Blok`s blocks
8
8
  */
9
9
  export interface Blocks {
10
+ /**
11
+ * Returns true when a Yjs sync operation (undo/redo) is in progress.
12
+ * Tools can use this to skip cleanup that would interfere with Yjs state management.
13
+ */
14
+ readonly isSyncingFromYjs: boolean;
15
+
10
16
  /**
11
17
  * Remove all blocks from Blok zone
12
18
  */
@@ -175,4 +181,14 @@ export interface Blocks {
175
181
  newBlockData: BlockToolData,
176
182
  insertIndex: number,
177
183
  ): BlockAPI;
184
+
185
+ /**
186
+ * Execute a function within a transaction.
187
+ * All block operations (insert, delete, move) within fn are grouped
188
+ * into a single undo entry. Prevents undo-group splitting that would
189
+ * make structural operations partially undoable.
190
+ *
191
+ * @param fn - The function containing block operations to group
192
+ */
193
+ transact?(fn: () => void): void;
178
194
  }