@jackuait/blok 0.6.0-beta.0 → 0.6.0-beta.10

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 (286) hide show
  1. package/README.md +16 -169
  2. package/bin/blok.mjs +10 -0
  3. package/dist/blok.mjs +2 -2
  4. package/dist/chunks/{blok-Bu9S3SsR.mjs → blok-Buf0btS7.mjs} +2267 -2024
  5. package/dist/chunks/{i18next-loader-CKuXJ0Av.mjs → i18next-loader-CVf_ZfwA.mjs} +1 -1
  6. package/dist/chunks/{index-jtZaryNw.mjs → index-C6jsfLLp.mjs} +1 -1
  7. package/dist/chunks/{inline-tool-convert-CFjyrH30.mjs → inline-tool-convert-BKKEoOqB.mjs} +710 -570
  8. package/dist/chunks/{messages-C5b7hr_E.mjs → messages-1fC8IMyX.mjs} +16 -2
  9. package/dist/chunks/{messages-CQj2JU2j.mjs → messages-7QoX8DkW.mjs} +23 -9
  10. package/dist/{messages-LvFKBBPa.mjs → chunks/messages-7W4d0DwD.mjs} +15 -1
  11. package/dist/{messages-Bn253WWC.mjs → chunks/messages-9SihnaXQ.mjs} +14 -0
  12. package/dist/{messages-Bf6Y3_GI.mjs → chunks/messages-B1Aww8q7.mjs} +16 -2
  13. package/dist/{messages-pA5TvcAj.mjs → chunks/messages-BB5z9Uba.mjs} +14 -0
  14. package/dist/chunks/{messages-wdqp4610.mjs → messages-BC86qLvI.mjs} +17 -3
  15. package/dist/chunks/{messages-o24dK6CU.mjs → messages-BELRf6DU.mjs} +16 -2
  16. package/dist/chunks/{messages-CUZ1x1QD.mjs → messages-BFG6Wlgy.mjs} +16 -2
  17. package/dist/{messages-B5puUm7R.mjs → chunks/messages-BL0tXcDf.mjs} +15 -1
  18. package/dist/chunks/{messages-zS1AXZ0y.mjs → messages-BMXCuEKO.mjs} +19 -5
  19. package/dist/{messages-CyDU5lz9.mjs → chunks/messages-BMv4xwIr.mjs} +16 -2
  20. package/dist/chunks/{messages-BeUhMpsr.mjs → messages-BSbjsyHY.mjs} +25 -11
  21. package/dist/chunks/{messages-JGsXAReJ.mjs → messages-BU2nlrLK.mjs} +16 -2
  22. package/dist/chunks/{messages-srxrv8Yh.mjs → messages-BWF-zUpY.mjs} +17 -3
  23. package/dist/{messages-CXHd9SUK.mjs → chunks/messages-BYyy6Wqf.mjs} +14 -0
  24. package/dist/chunks/{messages-DOlC_Tty.mjs → messages-BdeLo0N9.mjs} +24 -10
  25. package/dist/chunks/{messages-B5jGUnOy.mjs → messages-Bmu_S7GM.mjs} +14 -0
  26. package/dist/chunks/{messages-BmKCChWZ.mjs → messages-BoJc_p1r.mjs} +14 -0
  27. package/dist/chunks/{messages-CvaqJFN-.mjs → messages-BogRq8lt.mjs} +15 -1
  28. package/dist/chunks/{messages-NP1myMGI.mjs → messages-BrPFGbM-.mjs} +14 -0
  29. package/dist/chunks/{messages-D00OjS2n.mjs → messages-C2htQ_3F.mjs} +24 -10
  30. package/dist/chunks/{messages-BiExzWJv.mjs → messages-C99mq906.mjs} +15 -1
  31. package/dist/chunks/{messages-CkFT2gle.mjs → messages-C9eaarcK.mjs} +20 -6
  32. package/dist/chunks/{messages-BrJHUxQL.mjs → messages-CJdUsQ-c.mjs} +15 -1
  33. package/dist/chunks/messages-CKI54h6O.mjs +62 -0
  34. package/dist/{messages-CrsJ1TEJ.mjs → chunks/messages-CLhcMlTc.mjs} +15 -1
  35. package/dist/{messages-CnvW8Slp.mjs → chunks/messages-CMkNSDTo.mjs} +17 -3
  36. package/dist/{messages-BlpqL8vG.mjs → chunks/messages-CQwpzUFp.mjs} +19 -5
  37. package/dist/chunks/{messages-Cu08aLS3.mjs → messages-CVw84KdI.mjs} +21 -7
  38. package/dist/chunks/{messages-B9Oba7sq.mjs → messages-CY8_RyFE.mjs} +15 -1
  39. package/dist/chunks/{messages-B5hdXZwA.mjs → messages-CZygwLwM.mjs} +15 -1
  40. package/dist/chunks/{messages-CVeWVKsV.mjs → messages-CnwibSvh.mjs} +14 -0
  41. package/dist/chunks/{messages-DbVquYKN.mjs → messages-CqWJcCbY.mjs} +14 -0
  42. package/dist/{messages-Dg92dXZ5.mjs → chunks/messages-CvGLfqmV.mjs} +14 -0
  43. package/dist/{messages-AHESHJm_.mjs → chunks/messages-CzTufCHu.mjs} +14 -0
  44. package/dist/chunks/{messages-Cj-t1bdy.mjs → messages-CznZadDf.mjs} +15 -1
  45. package/dist/chunks/{messages-DMQIHGRj.mjs → messages-D-ZtY5v0.mjs} +14 -0
  46. package/dist/chunks/{messages-rRSHQDCX.mjs → messages-D1Hv8XGo.mjs} +14 -0
  47. package/dist/chunks/{messages-0tDXLuyH.mjs → messages-D5C3J9qr.mjs} +15 -1
  48. package/dist/chunks/{messages-RvMHb2Ht.mjs → messages-D5iv1Kox.mjs} +16 -2
  49. package/dist/{messages-zSzDzXej.mjs → chunks/messages-DBRw-7Zc.mjs} +16 -2
  50. package/dist/chunks/{messages-CeCjVKMW.mjs → messages-DBn76jVV.mjs} +16 -2
  51. package/dist/chunks/{messages-C7I_AVH2.mjs → messages-DJDG55Vq.mjs} +16 -2
  52. package/dist/{messages-DDLgIPDF.mjs → chunks/messages-DLfR5bMd.mjs} +16 -2
  53. package/dist/{messages-CbhuIWRJ.mjs → chunks/messages-DT4dP5uK.mjs} +15 -1
  54. package/dist/chunks/{messages-B66ZSDCJ.mjs → messages-DhLKYm2j.mjs} +15 -1
  55. package/dist/{messages-BPqWKx5Z.mjs → chunks/messages-Diu6jAaR.mjs} +17 -3
  56. package/dist/{messages-BA0rcTCY.mjs → chunks/messages-DnIhyAJk.mjs} +18 -4
  57. package/dist/chunks/{messages-DV6shA9b.mjs → messages-DnXLrlHh.mjs} +14 -0
  58. package/dist/chunks/{messages-DcKOuncK.mjs → messages-DprmQg6V.mjs} +16 -2
  59. package/dist/{messages-CJoBtXU6.mjs → chunks/messages-DqM1LFg5.mjs} +14 -0
  60. package/dist/chunks/{messages-Cyi2AMmz.mjs → messages-DvFLX36Q.mjs} +25 -11
  61. package/dist/chunks/{messages-DnbbyJT3.mjs → messages-Dz9L52ol.mjs} +16 -2
  62. package/dist/chunks/{messages-GC2PhgV3.mjs → messages-Dzwxv9v1.mjs} +23 -9
  63. package/dist/chunks/{messages-Q4kc_ZtL.mjs → messages-JELdtT6E.mjs} +15 -1
  64. package/dist/{messages-DY94ykcE.mjs → chunks/messages-LPVfA-8K.mjs} +14 -0
  65. package/dist/{messages-Cr-RJ7YB.mjs → chunks/messages-O5tQus_0.mjs} +14 -0
  66. package/dist/chunks/{messages-CbMyJSzS.mjs → messages-Q7AO_FLv.mjs} +17 -3
  67. package/dist/chunks/{messages-2_xedlYw.mjs → messages-R3hUSvr3.mjs} +15 -1
  68. package/dist/{messages-CUy1vn-b.mjs → chunks/messages-Xq8UmkVs.mjs} +14 -0
  69. package/dist/chunks/{messages-BBJgd5jG.mjs → messages-Z9nEU2xK.mjs} +16 -2
  70. package/dist/chunks/{messages-Cm9aLHeX.mjs → messages-_ErNTNhk.mjs} +15 -1
  71. package/dist/chunks/{messages-JZUhXTuV.mjs → messages-_ncGrKHh.mjs} +16 -2
  72. package/dist/chunks/{messages-ftMcCEuO.mjs → messages-kep5wtm4.mjs} +15 -1
  73. package/dist/chunks/{messages-DteYq0rv.mjs → messages-uKX8WBaD.mjs} +16 -2
  74. package/dist/chunks/{messages-Bdv-IkfG.mjs → messages-w7v1GNaE.mjs} +15 -1
  75. package/dist/cli.mjs +50 -0
  76. package/dist/full.mjs +15 -15
  77. package/dist/locales.mjs +102 -88
  78. package/dist/{messages-C5b7hr_E.mjs → messages-1fC8IMyX.mjs} +16 -2
  79. package/dist/{messages-CQj2JU2j.mjs → messages-7QoX8DkW.mjs} +23 -9
  80. package/dist/{chunks/messages-LvFKBBPa.mjs → messages-7W4d0DwD.mjs} +15 -1
  81. package/dist/{chunks/messages-Bn253WWC.mjs → messages-9SihnaXQ.mjs} +14 -0
  82. package/dist/{chunks/messages-Bf6Y3_GI.mjs → messages-B1Aww8q7.mjs} +16 -2
  83. package/dist/{chunks/messages-pA5TvcAj.mjs → messages-BB5z9Uba.mjs} +14 -0
  84. package/dist/{messages-wdqp4610.mjs → messages-BC86qLvI.mjs} +17 -3
  85. package/dist/{messages-o24dK6CU.mjs → messages-BELRf6DU.mjs} +16 -2
  86. package/dist/{messages-CUZ1x1QD.mjs → messages-BFG6Wlgy.mjs} +16 -2
  87. package/dist/{chunks/messages-B5puUm7R.mjs → messages-BL0tXcDf.mjs} +15 -1
  88. package/dist/{messages-zS1AXZ0y.mjs → messages-BMXCuEKO.mjs} +19 -5
  89. package/dist/{chunks/messages-CyDU5lz9.mjs → messages-BMv4xwIr.mjs} +16 -2
  90. package/dist/{messages-BeUhMpsr.mjs → messages-BSbjsyHY.mjs} +25 -11
  91. package/dist/{messages-JGsXAReJ.mjs → messages-BU2nlrLK.mjs} +16 -2
  92. package/dist/{messages-srxrv8Yh.mjs → messages-BWF-zUpY.mjs} +17 -3
  93. package/dist/{chunks/messages-CXHd9SUK.mjs → messages-BYyy6Wqf.mjs} +14 -0
  94. package/dist/{messages-DOlC_Tty.mjs → messages-BdeLo0N9.mjs} +24 -10
  95. package/dist/{messages-B5jGUnOy.mjs → messages-Bmu_S7GM.mjs} +14 -0
  96. package/dist/{messages-BmKCChWZ.mjs → messages-BoJc_p1r.mjs} +14 -0
  97. package/dist/{messages-CvaqJFN-.mjs → messages-BogRq8lt.mjs} +15 -1
  98. package/dist/{messages-NP1myMGI.mjs → messages-BrPFGbM-.mjs} +14 -0
  99. package/dist/{messages-D00OjS2n.mjs → messages-C2htQ_3F.mjs} +24 -10
  100. package/dist/{messages-BiExzWJv.mjs → messages-C99mq906.mjs} +15 -1
  101. package/dist/{messages-CkFT2gle.mjs → messages-C9eaarcK.mjs} +20 -6
  102. package/dist/{messages-BrJHUxQL.mjs → messages-CJdUsQ-c.mjs} +15 -1
  103. package/dist/messages-CKI54h6O.mjs +62 -0
  104. package/dist/{chunks/messages-CrsJ1TEJ.mjs → messages-CLhcMlTc.mjs} +15 -1
  105. package/dist/{chunks/messages-CnvW8Slp.mjs → messages-CMkNSDTo.mjs} +17 -3
  106. package/dist/{chunks/messages-BlpqL8vG.mjs → messages-CQwpzUFp.mjs} +19 -5
  107. package/dist/{messages-Cu08aLS3.mjs → messages-CVw84KdI.mjs} +21 -7
  108. package/dist/{messages-B9Oba7sq.mjs → messages-CY8_RyFE.mjs} +15 -1
  109. package/dist/{messages-B5hdXZwA.mjs → messages-CZygwLwM.mjs} +15 -1
  110. package/dist/{messages-CVeWVKsV.mjs → messages-CnwibSvh.mjs} +14 -0
  111. package/dist/{messages-DbVquYKN.mjs → messages-CqWJcCbY.mjs} +14 -0
  112. package/dist/{chunks/messages-Dg92dXZ5.mjs → messages-CvGLfqmV.mjs} +14 -0
  113. package/dist/{chunks/messages-AHESHJm_.mjs → messages-CzTufCHu.mjs} +14 -0
  114. package/dist/{messages-Cj-t1bdy.mjs → messages-CznZadDf.mjs} +15 -1
  115. package/dist/{messages-DMQIHGRj.mjs → messages-D-ZtY5v0.mjs} +14 -0
  116. package/dist/{messages-rRSHQDCX.mjs → messages-D1Hv8XGo.mjs} +14 -0
  117. package/dist/{messages-0tDXLuyH.mjs → messages-D5C3J9qr.mjs} +15 -1
  118. package/dist/{messages-RvMHb2Ht.mjs → messages-D5iv1Kox.mjs} +16 -2
  119. package/dist/{chunks/messages-zSzDzXej.mjs → messages-DBRw-7Zc.mjs} +16 -2
  120. package/dist/{messages-CeCjVKMW.mjs → messages-DBn76jVV.mjs} +16 -2
  121. package/dist/{messages-C7I_AVH2.mjs → messages-DJDG55Vq.mjs} +16 -2
  122. package/dist/{chunks/messages-DDLgIPDF.mjs → messages-DLfR5bMd.mjs} +16 -2
  123. package/dist/{chunks/messages-CbhuIWRJ.mjs → messages-DT4dP5uK.mjs} +15 -1
  124. package/dist/{messages-B66ZSDCJ.mjs → messages-DhLKYm2j.mjs} +15 -1
  125. package/dist/{chunks/messages-BPqWKx5Z.mjs → messages-Diu6jAaR.mjs} +17 -3
  126. package/dist/{chunks/messages-BA0rcTCY.mjs → messages-DnIhyAJk.mjs} +18 -4
  127. package/dist/{messages-DV6shA9b.mjs → messages-DnXLrlHh.mjs} +14 -0
  128. package/dist/{messages-DcKOuncK.mjs → messages-DprmQg6V.mjs} +16 -2
  129. package/dist/{chunks/messages-CJoBtXU6.mjs → messages-DqM1LFg5.mjs} +14 -0
  130. package/dist/{messages-Cyi2AMmz.mjs → messages-DvFLX36Q.mjs} +25 -11
  131. package/dist/{messages-DnbbyJT3.mjs → messages-Dz9L52ol.mjs} +16 -2
  132. package/dist/{messages-GC2PhgV3.mjs → messages-Dzwxv9v1.mjs} +23 -9
  133. package/dist/{messages-Q4kc_ZtL.mjs → messages-JELdtT6E.mjs} +15 -1
  134. package/dist/{chunks/messages-DY94ykcE.mjs → messages-LPVfA-8K.mjs} +14 -0
  135. package/dist/{chunks/messages-Cr-RJ7YB.mjs → messages-O5tQus_0.mjs} +14 -0
  136. package/dist/{messages-CbMyJSzS.mjs → messages-Q7AO_FLv.mjs} +17 -3
  137. package/dist/{messages-2_xedlYw.mjs → messages-R3hUSvr3.mjs} +15 -1
  138. package/dist/{chunks/messages-CUy1vn-b.mjs → messages-Xq8UmkVs.mjs} +14 -0
  139. package/dist/{messages-BBJgd5jG.mjs → messages-Z9nEU2xK.mjs} +16 -2
  140. package/dist/{messages-Cm9aLHeX.mjs → messages-_ErNTNhk.mjs} +15 -1
  141. package/dist/{messages-JZUhXTuV.mjs → messages-_ncGrKHh.mjs} +16 -2
  142. package/dist/{messages-ftMcCEuO.mjs → messages-kep5wtm4.mjs} +15 -1
  143. package/dist/{messages-DteYq0rv.mjs → messages-uKX8WBaD.mjs} +16 -2
  144. package/dist/{messages-Bdv-IkfG.mjs → messages-w7v1GNaE.mjs} +15 -1
  145. package/dist/tools.mjs +2005 -1267
  146. package/dist/vendor.LICENSE.txt +1 -1
  147. package/package.json +15 -14
  148. package/src/cli/commands/migration.ts +16 -0
  149. package/src/cli/commands/migrationContent.ts +6 -0
  150. package/src/cli/index.ts +47 -0
  151. package/src/cli/utils/output.ts +10 -0
  152. package/src/components/block-tunes/block-tune-delete.ts +3 -2
  153. package/src/components/blocks.ts +23 -6
  154. package/src/components/constants/data-attributes.ts +2 -0
  155. package/src/components/i18n/locales/am/messages.json +15 -1
  156. package/src/components/i18n/locales/ar/messages.json +14 -0
  157. package/src/components/i18n/locales/az/messages.json +14 -0
  158. package/src/components/i18n/locales/bg/messages.json +14 -0
  159. package/src/components/i18n/locales/bn/messages.json +25 -11
  160. package/src/components/i18n/locales/bs/messages.json +15 -1
  161. package/src/components/i18n/locales/cs/messages.json +14 -0
  162. package/src/components/i18n/locales/da/messages.json +14 -0
  163. package/src/components/i18n/locales/de/messages.json +14 -0
  164. package/src/components/i18n/locales/dv/messages.json +15 -1
  165. package/src/components/i18n/locales/el/messages.json +15 -1
  166. package/src/components/i18n/locales/en/messages.json +14 -0
  167. package/src/components/i18n/locales/es/messages.json +14 -0
  168. package/src/components/i18n/locales/et/messages.json +14 -0
  169. package/src/components/i18n/locales/fa/messages.json +15 -1
  170. package/src/components/i18n/locales/fi/messages.json +15 -1
  171. package/src/components/i18n/locales/fil/messages.json +20 -6
  172. package/src/components/i18n/locales/fr/messages.json +15 -1
  173. package/src/components/i18n/locales/gu/messages.json +15 -1
  174. package/src/components/i18n/locales/he/messages.json +14 -0
  175. package/src/components/i18n/locales/hi/messages.json +23 -9
  176. package/src/components/i18n/locales/hr/messages.json +14 -0
  177. package/src/components/i18n/locales/hu/messages.json +14 -0
  178. package/src/components/i18n/locales/hy/messages.json +16 -2
  179. package/src/components/i18n/locales/id/messages.json +19 -5
  180. package/src/components/i18n/locales/it/messages.json +14 -0
  181. package/src/components/i18n/locales/ja/messages.json +14 -0
  182. package/src/components/i18n/locales/ka/messages.json +15 -1
  183. package/src/components/i18n/locales/km/messages.json +16 -2
  184. package/src/components/i18n/locales/kn/messages.json +16 -2
  185. package/src/components/i18n/locales/ko/messages.json +14 -0
  186. package/src/components/i18n/locales/ku/messages.json +16 -2
  187. package/src/components/i18n/locales/lo/messages.json +15 -1
  188. package/src/components/i18n/locales/lt/messages.json +15 -1
  189. package/src/components/i18n/locales/lv/messages.json +15 -1
  190. package/src/components/i18n/locales/mk/messages.json +16 -2
  191. package/src/components/i18n/locales/ml/messages.json +16 -2
  192. package/src/components/i18n/locales/mn/messages.json +16 -2
  193. package/src/components/i18n/locales/mr/messages.json +24 -10
  194. package/src/components/i18n/locales/ms/messages.json +17 -3
  195. package/src/components/i18n/locales/my/messages.json +16 -2
  196. package/src/components/i18n/locales/ne/messages.json +24 -10
  197. package/src/components/i18n/locales/nl/messages.json +15 -1
  198. package/src/components/i18n/locales/no/messages.json +16 -2
  199. package/src/components/i18n/locales/pa/messages.json +15 -1
  200. package/src/components/i18n/locales/pl/messages.json +14 -0
  201. package/src/components/i18n/locales/ps/messages.json +17 -3
  202. package/src/components/i18n/locales/pt/messages.json +14 -0
  203. package/src/components/i18n/locales/ro/messages.json +15 -1
  204. package/src/components/i18n/locales/ru/messages.json +14 -0
  205. package/src/components/i18n/locales/sd/messages.json +16 -2
  206. package/src/components/i18n/locales/si/messages.json +23 -9
  207. package/src/components/i18n/locales/sk/messages.json +15 -1
  208. package/src/components/i18n/locales/sl/messages.json +16 -2
  209. package/src/components/i18n/locales/sq/messages.json +16 -2
  210. package/src/components/i18n/locales/sr/messages.json +16 -2
  211. package/src/components/i18n/locales/sv/messages.json +16 -2
  212. package/src/components/i18n/locales/sw/messages.json +16 -2
  213. package/src/components/i18n/locales/ta/messages.json +21 -7
  214. package/src/components/i18n/locales/te/messages.json +40 -26
  215. package/src/components/i18n/locales/th/messages.json +19 -5
  216. package/src/components/i18n/locales/tr/messages.json +15 -1
  217. package/src/components/i18n/locales/ug/messages.json +16 -2
  218. package/src/components/i18n/locales/uk/messages.json +15 -1
  219. package/src/components/i18n/locales/ur/messages.json +15 -1
  220. package/src/components/i18n/locales/vi/messages.json +25 -11
  221. package/src/components/i18n/locales/yi/messages.json +16 -2
  222. package/src/components/i18n/locales/zh/messages.json +15 -1
  223. package/src/components/icons/index.ts +104 -83
  224. package/src/components/modules/api/blocks.ts +35 -2
  225. package/src/components/modules/api/history.ts +64 -0
  226. package/src/components/modules/api/index.ts +2 -0
  227. package/src/components/modules/api/readonly.ts +11 -1
  228. package/src/components/modules/blockEvents/composers/markdownShortcuts.ts +12 -1
  229. package/src/components/modules/blockManager/blockManager.ts +7 -0
  230. package/src/components/modules/blockManager/operations.ts +3 -2
  231. package/src/components/modules/blockManager/types.ts +3 -1
  232. package/src/components/modules/blockManager/yjs-sync.ts +12 -2
  233. package/src/components/modules/index.ts +3 -0
  234. package/src/components/modules/normalizeInlineImages.ts +263 -0
  235. package/src/components/modules/readonly.ts +11 -0
  236. package/src/components/modules/rectangleSelection.ts +19 -3
  237. package/src/components/modules/saver.ts +7 -3
  238. package/src/components/modules/toolbar/blockSettings.ts +3 -3
  239. package/src/components/modules/toolbar/index.ts +72 -14
  240. package/src/components/modules/toolbar/plus-button.ts +24 -3
  241. package/src/components/modules/toolbar/settings-toggler.ts +3 -5
  242. package/src/components/modules/ui.ts +46 -68
  243. package/src/components/modules/uiControllers/controllers/blockHover.ts +49 -61
  244. package/src/components/modules/uiControllers/controllers/keyboard.ts +17 -11
  245. package/src/components/modules/uiControllers/handlers/click.ts +0 -12
  246. package/src/components/modules/yjs/index.ts +23 -0
  247. package/src/components/ui/toolbox.ts +41 -6
  248. package/src/components/utils/placeholder.ts +16 -0
  249. package/src/components/utils/popover/components/popover-item/popover-item-default/popover-item-default.const.ts +2 -1
  250. package/src/components/utils/popover/components/popover-item/popover-item-default/popover-item-default.ts +6 -1
  251. package/src/components/utils/popover/index.ts +1 -0
  252. package/src/components/utils/popover/popover-abstract.ts +11 -1
  253. package/src/components/utils/popover/popover-desktop.ts +27 -8
  254. package/src/components/utils/popover/popover-registry.ts +188 -0
  255. package/src/components/utils/sanitizer.ts +23 -2
  256. package/src/components/utils/tooltip.ts +2 -24
  257. package/src/styles/main.css +22 -0
  258. package/src/tools/paragraph/index.ts +12 -4
  259. package/src/tools/table/data-normalizer.ts +1 -0
  260. package/src/tools/table/index.ts +283 -346
  261. package/src/tools/table/table-add-controls.ts +353 -47
  262. package/src/tools/table/table-cell-blocks.ts +95 -7
  263. package/src/tools/table/table-cell-selection.ts +648 -0
  264. package/src/tools/table/table-core.ts +21 -32
  265. package/src/tools/table/table-grip-visuals.ts +96 -0
  266. package/src/tools/table/table-heading-toggle.ts +127 -0
  267. package/src/tools/table/table-operations.ts +475 -0
  268. package/src/tools/table/table-resize.ts +27 -6
  269. package/src/tools/table/table-restrictions.ts +64 -0
  270. package/src/tools/table/table-row-col-action-handler.ts +190 -0
  271. package/src/tools/table/table-row-col-controls.ts +265 -211
  272. package/src/tools/table/table-row-col-drag.ts +4 -4
  273. package/src/tools/table/table-row-col-popover.ts +225 -0
  274. package/src/tools/table/types.ts +4 -0
  275. package/src/types-internal/blok-modules.d.ts +2 -0
  276. package/types/api/blocks.d.ts +8 -0
  277. package/types/api/history.d.ts +33 -0
  278. package/types/api/index.d.ts +1 -0
  279. package/types/api/readonly.d.ts +12 -2
  280. package/types/index.d.ts +10 -0
  281. package/types/tools/table.d.ts +67 -0
  282. package/types/tools-entry.d.ts +4 -0
  283. package/types/utils/popover/popover-item.d.ts +6 -0
  284. package/types/utils/popover/popover.d.ts +7 -0
  285. package/dist/chunks/messages-CySyfkMU.mjs +0 -48
  286. package/dist/messages-CySyfkMU.mjs +0 -48
@@ -1,59 +1,118 @@
1
+ import type { I18n } from '../../../types/api';
2
+ import { IconPlus } from '../../components/icons';
3
+ import { createTooltipContent } from '../../components/modules/toolbar/tooltip';
4
+ import { hide as hideTooltip, onHover } from '../../components/utils/tooltip';
1
5
  import { twMerge } from '../../components/utils/tw';
2
6
 
3
7
  const ADD_ROW_ATTR = 'data-blok-table-add-row';
4
8
  const ADD_COL_ATTR = 'data-blok-table-add-col';
5
9
  const HIDE_DELAY_MS = 150;
10
+ const DRAG_THRESHOLD = 5;
6
11
 
7
- const SHARED_CLASSES = [
12
+ /**
13
+ * How close (px) the cursor must be to a grid edge for
14
+ * the corresponding add button to appear.
15
+ */
16
+ const PROXIMITY_PX = 40;
17
+
18
+ const HIT_AREA_CLASSES = [
8
19
  'flex',
9
20
  'items-center',
10
21
  'justify-center',
11
- 'cursor-pointer',
12
- 'border',
13
- 'border-gray-300',
14
- 'rounded-full',
15
- 'hover:bg-gray-50',
16
22
  'transition-opacity',
17
23
  'duration-150',
18
24
  ];
19
25
 
20
- const PLUS_CLASSES = [
21
- 'text-gray-400',
22
- 'text-sm',
23
- 'select-none',
24
- 'pointer-events-none',
26
+ const VISUAL_CLASSES = [
27
+ 'flex',
28
+ 'items-center',
29
+ 'justify-center',
30
+ 'border',
31
+ 'border-gray-300',
32
+ 'rounded-full',
33
+ 'group-hover/add:bg-gray-50',
25
34
  ];
26
35
 
36
+ const ICON_SIZE = '12';
37
+
38
+ interface DragState {
39
+ axis: 'row' | 'col';
40
+ startPos: number;
41
+ unitSize: number;
42
+ addedCount: number;
43
+ pointerId: number;
44
+ didDrag: boolean;
45
+ }
46
+
27
47
  interface TableAddControlsOptions {
28
48
  wrapper: HTMLElement;
29
49
  grid: HTMLElement;
50
+ i18n: I18n;
30
51
  onAddRow: () => void;
31
52
  onAddColumn: () => void;
53
+ onDragStart: () => void;
54
+ onDragAddRow: () => void;
55
+ onDragRemoveRow: () => void;
56
+ onDragAddCol: () => void;
57
+ onDragRemoveCol: () => void;
58
+ onDragEnd: () => void;
59
+ /** Returns the pixel width of a newly added column, used as the drag unit size. */
60
+ getNewColumnWidth?: () => number;
32
61
  }
33
62
 
34
63
  /**
35
64
  * Manages hover-to-reveal "+" buttons for adding rows and columns to the table.
65
+ * Buttons only appear when the cursor is near the relevant edge of the grid.
66
+ * Supports both click (add one) and drag (add multiple) interactions.
36
67
  */
37
68
  export class TableAddControls {
38
69
  private wrapper: HTMLElement;
39
70
  private grid: HTMLElement;
71
+ private i18n: I18n;
40
72
  private addRowBtn: HTMLElement;
41
73
  private addColBtn: HTMLElement;
42
- private hideTimeout: ReturnType<typeof setTimeout> | null = null;
74
+ private rowHideTimeout: ReturnType<typeof setTimeout> | null = null;
75
+ private colHideTimeout: ReturnType<typeof setTimeout> | null = null;
76
+ private rowVisible = false;
77
+ private colVisible = false;
78
+ private dragState: DragState | null = null;
43
79
 
44
- private boundMouseEnter: () => void;
80
+ private boundMouseMove: (e: MouseEvent) => void;
45
81
  private boundMouseLeave: () => void;
46
82
  private boundAddRowClick: () => void;
47
83
  private boundAddColClick: () => void;
84
+ private onDragStart: () => void;
85
+ private onDragAddRow: () => void;
86
+ private onDragRemoveRow: () => void;
87
+ private onDragAddCol: () => void;
88
+ private onDragRemoveCol: () => void;
89
+ private onDragEnd: () => void;
90
+ private boundPointerMove: (e: PointerEvent) => void;
91
+ private boundPointerUp: (e: PointerEvent) => void;
92
+ private boundRowPointerDown: (e: PointerEvent) => void;
93
+ private boundColPointerDown: (e: PointerEvent) => void;
94
+ private getNewColumnWidth: (() => number) | undefined;
48
95
 
49
96
  constructor(options: TableAddControlsOptions) {
50
97
  this.wrapper = options.wrapper;
51
98
  this.grid = options.grid;
99
+ this.i18n = options.i18n;
52
100
 
53
101
  this.boundAddRowClick = options.onAddRow;
54
102
  this.boundAddColClick = options.onAddColumn;
55
- this.boundMouseEnter = this.show.bind(this);
56
- this.boundMouseLeave = this.scheduleHide.bind(this);
103
+ this.onDragStart = options.onDragStart;
104
+ this.onDragAddRow = options.onDragAddRow;
105
+ this.onDragRemoveRow = options.onDragRemoveRow;
106
+ this.onDragAddCol = options.onDragAddCol;
107
+ this.onDragRemoveCol = options.onDragRemoveCol;
108
+ this.onDragEnd = options.onDragEnd;
109
+ this.getNewColumnWidth = options.getNewColumnWidth;
110
+ this.boundMouseMove = this.handleMouseMove.bind(this);
111
+ this.boundMouseLeave = this.handleMouseLeave.bind(this);
112
+ this.boundPointerMove = this.handlePointerMove.bind(this);
113
+ this.boundPointerUp = this.handlePointerUp.bind(this);
114
+ this.boundRowPointerDown = (e: PointerEvent): void => this.handlePointerDown('row', e);
115
+ this.boundColPointerDown = (e: PointerEvent): void => this.handlePointerDown('col', e);
57
116
 
58
117
  this.addRowBtn = this.createAddRowButton();
59
118
  this.addColBtn = this.createAddColumnButton();
@@ -62,11 +121,12 @@ export class TableAddControls {
62
121
  this.grid.appendChild(this.addColBtn);
63
122
  this.syncRowButtonWidth();
64
123
 
65
- this.wrapper.addEventListener('mouseenter', this.boundMouseEnter);
124
+ this.wrapper.addEventListener('mousemove', this.boundMouseMove);
66
125
  this.wrapper.addEventListener('mouseleave', this.boundMouseLeave);
67
126
 
68
- this.addRowBtn.addEventListener('click', this.boundAddRowClick);
69
- this.addColBtn.addEventListener('click', this.boundAddColClick);
127
+ this.addRowBtn.addEventListener('pointerdown', this.boundRowPointerDown);
128
+ this.addColBtn.addEventListener('pointerdown', this.boundColPointerDown);
129
+
70
130
  }
71
131
 
72
132
  /**
@@ -83,55 +143,279 @@ export class TableAddControls {
83
143
  : '100%';
84
144
  }
85
145
 
146
+ /**
147
+ * Toggle display of both add buttons.
148
+ * Used to hide controls during row/column drag operations.
149
+ */
150
+ public setDisplay(visible: boolean): void {
151
+ const display = visible ? '' : 'none';
152
+
153
+ this.addRowBtn.style.display = display;
154
+ this.addColBtn.style.display = display;
155
+ }
156
+
157
+ /**
158
+ * Toggle interactivity of both add buttons without removing them from the DOM.
159
+ * Disables pointer events and hover effects during cell selection.
160
+ */
161
+ public setInteractive(interactive: boolean): void {
162
+ if (!interactive) {
163
+ this.addRowBtn.style.pointerEvents = 'none';
164
+ this.addColBtn.style.pointerEvents = 'none';
165
+
166
+ return;
167
+ }
168
+
169
+ this.addRowBtn.style.pointerEvents = this.rowVisible ? '' : 'none';
170
+ this.addColBtn.style.pointerEvents = this.colVisible ? '' : 'none';
171
+ }
172
+
86
173
  public destroy(): void {
87
- this.wrapper.removeEventListener('mouseenter', this.boundMouseEnter);
174
+ this.wrapper.removeEventListener('mousemove', this.boundMouseMove);
88
175
  this.wrapper.removeEventListener('mouseleave', this.boundMouseLeave);
89
- this.addRowBtn.removeEventListener('click', this.boundAddRowClick);
90
- this.addColBtn.removeEventListener('click', this.boundAddColClick);
176
+ this.addRowBtn.removeEventListener('pointerdown', this.boundRowPointerDown);
177
+ this.addColBtn.removeEventListener('pointerdown', this.boundColPointerDown);
178
+
179
+ if (this.dragState) {
180
+ const target = this.dragState.axis === 'row' ? this.addRowBtn : this.addColBtn;
91
181
 
92
- if (this.hideTimeout !== null) {
93
- clearTimeout(this.hideTimeout);
94
- this.hideTimeout = null;
182
+ target.removeEventListener('pointermove', this.boundPointerMove);
183
+ target.removeEventListener('pointerup', this.boundPointerUp);
184
+ document.body.style.cursor = '';
185
+ this.dragState = null;
95
186
  }
96
187
 
188
+ this.clearRowTimeout();
189
+ this.clearColTimeout();
190
+
97
191
  this.addRowBtn.remove();
98
192
  this.addColBtn.remove();
99
193
  }
100
194
 
101
- private show(): void {
102
- if (this.hideTimeout !== null) {
103
- clearTimeout(this.hideTimeout);
104
- this.hideTimeout = null;
195
+ private handlePointerDown(axis: 'row' | 'col', e: PointerEvent): void {
196
+ e.preventDefault();
197
+
198
+ const target = axis === 'row' ? this.addRowBtn : this.addColBtn;
199
+
200
+ target.setPointerCapture(e.pointerId);
201
+
202
+ const unitSize = this.measureUnitSize(axis);
203
+
204
+ this.dragState = {
205
+ axis,
206
+ startPos: axis === 'row' ? e.clientY : e.clientX,
207
+ unitSize,
208
+ addedCount: 0,
209
+ pointerId: e.pointerId,
210
+ didDrag: false,
211
+ };
212
+
213
+ target.addEventListener('pointermove', this.boundPointerMove);
214
+ target.addEventListener('pointerup', this.boundPointerUp);
215
+ }
216
+
217
+ private handlePointerMove(e: PointerEvent): void {
218
+ if (!this.dragState) {
219
+ return;
220
+ }
221
+
222
+ const { axis, startPos, unitSize } = this.dragState;
223
+ const currentPos = axis === 'row' ? e.clientY : e.clientX;
224
+ const delta = currentPos - startPos;
225
+ const targetCount = Math.floor(delta / unitSize);
226
+
227
+ while (this.dragState.addedCount < targetCount) {
228
+ if (axis === 'row') {
229
+ this.onDragAddRow();
230
+ } else {
231
+ this.onDragAddCol();
232
+ }
233
+
234
+ this.dragState.addedCount++;
105
235
  }
106
236
 
107
- this.addRowBtn.style.opacity = '1';
108
- this.addColBtn.style.opacity = '1';
237
+ while (this.dragState.addedCount > targetCount) {
238
+ if (axis === 'row') {
239
+ this.onDragRemoveRow();
240
+ } else {
241
+ this.onDragRemoveCol();
242
+ }
243
+
244
+ this.dragState.addedCount--;
245
+ }
246
+
247
+ if (Math.abs(delta) > DRAG_THRESHOLD && !this.dragState.didDrag) {
248
+ this.dragState.didDrag = true;
249
+ document.body.style.cursor = axis === 'row' ? 'row-resize' : 'col-resize';
250
+ hideTooltip();
251
+ this.onDragStart();
252
+ }
109
253
  }
110
254
 
111
- private scheduleHide(): void {
112
- this.hideTimeout = setTimeout(() => {
255
+ private handlePointerUp(_e: PointerEvent): void {
256
+ if (!this.dragState) {
257
+ return;
258
+ }
259
+
260
+ const { axis, pointerId, didDrag } = this.dragState;
261
+
262
+ const target = axis === 'row' ? this.addRowBtn : this.addColBtn;
263
+
264
+ target.releasePointerCapture(pointerId);
265
+ target.removeEventListener('pointermove', this.boundPointerMove);
266
+ target.removeEventListener('pointerup', this.boundPointerUp);
267
+
268
+ document.body.style.cursor = '';
269
+ this.dragState = null;
270
+
271
+ if (!didDrag) {
272
+ const clickHandler = axis === 'row' ? this.boundAddRowClick : this.boundAddColClick;
273
+
274
+ clickHandler();
275
+
276
+ return;
277
+ }
278
+
279
+ this.onDragEnd();
280
+ }
281
+
282
+ private measureUnitSize(axis: 'row' | 'col'): number {
283
+ if (axis === 'row') {
284
+ const rows = this.grid.querySelectorAll('[data-blok-table-row]');
285
+ const lastRow = rows[rows.length - 1] as HTMLElement | undefined;
286
+
287
+ return lastRow?.offsetHeight || 30;
288
+ }
289
+
290
+ if (this.getNewColumnWidth) {
291
+ return this.getNewColumnWidth() || 100;
292
+ }
293
+
294
+ const firstRow = this.grid.querySelector('[data-blok-table-row]');
295
+
296
+ if (!firstRow) {
297
+ return 100;
298
+ }
299
+
300
+ const cells = firstRow.querySelectorAll('[data-blok-table-cell]');
301
+ const lastCell = cells[cells.length - 1] as HTMLElement | undefined;
302
+
303
+ return lastCell?.offsetWidth || 100;
304
+ }
305
+
306
+ private handleMouseMove(e: MouseEvent): void {
307
+ const gridRect = this.grid.getBoundingClientRect();
308
+ const distFromBottom = Math.abs(e.clientY - gridRect.bottom);
309
+ const distFromRight = Math.abs(e.clientX - gridRect.right);
310
+
311
+ if (distFromBottom <= PROXIMITY_PX) {
312
+ this.showRow();
313
+ } else {
314
+ this.scheduleHideRow();
315
+ }
316
+
317
+ if (distFromRight <= PROXIMITY_PX) {
318
+ this.showCol();
319
+ } else {
320
+ this.scheduleHideCol();
321
+ }
322
+ }
323
+
324
+ private handleMouseLeave(): void {
325
+ this.scheduleHideRow();
326
+ this.scheduleHideCol();
327
+ }
328
+
329
+ private showRow(): void {
330
+ this.clearRowTimeout();
331
+
332
+ if (!this.rowVisible) {
333
+ this.addRowBtn.style.opacity = '1';
334
+ this.addRowBtn.style.pointerEvents = '';
335
+ this.rowVisible = true;
336
+ }
337
+ }
338
+
339
+ private showCol(): void {
340
+ this.clearColTimeout();
341
+
342
+ if (!this.colVisible) {
343
+ this.addColBtn.style.opacity = '1';
344
+ this.addColBtn.style.pointerEvents = '';
345
+ this.colVisible = true;
346
+ }
347
+ }
348
+
349
+ private scheduleHideRow(): void {
350
+ if (!this.rowVisible || this.rowHideTimeout !== null || this.dragState?.axis === 'row') {
351
+ return;
352
+ }
353
+
354
+ this.rowHideTimeout = setTimeout(() => {
113
355
  this.addRowBtn.style.opacity = '0';
356
+ this.addRowBtn.style.pointerEvents = 'none';
357
+ this.rowVisible = false;
358
+ this.rowHideTimeout = null;
359
+ }, HIDE_DELAY_MS);
360
+ }
361
+
362
+ private scheduleHideCol(): void {
363
+ if (!this.colVisible || this.colHideTimeout !== null || this.dragState?.axis === 'col') {
364
+ return;
365
+ }
366
+
367
+ this.colHideTimeout = setTimeout(() => {
114
368
  this.addColBtn.style.opacity = '0';
115
- this.hideTimeout = null;
369
+ this.addColBtn.style.pointerEvents = 'none';
370
+ this.colVisible = false;
371
+ this.colHideTimeout = null;
116
372
  }, HIDE_DELAY_MS);
117
373
  }
118
374
 
375
+ private clearRowTimeout(): void {
376
+ if (this.rowHideTimeout !== null) {
377
+ clearTimeout(this.rowHideTimeout);
378
+ this.rowHideTimeout = null;
379
+ }
380
+ }
381
+
382
+ private clearColTimeout(): void {
383
+ if (this.colHideTimeout !== null) {
384
+ clearTimeout(this.colHideTimeout);
385
+ this.colHideTimeout = null;
386
+ }
387
+ }
388
+
119
389
  private createAddRowButton(): HTMLElement {
120
390
  const btn = document.createElement('div');
121
391
 
122
- btn.className = twMerge(SHARED_CLASSES);
392
+ btn.className = twMerge(HIT_AREA_CLASSES, 'group/add', 'items-start', 'cursor-row-resize');
123
393
  btn.setAttribute(ADD_ROW_ATTR, '');
124
394
  btn.setAttribute('contenteditable', 'false');
125
395
  btn.style.opacity = '0';
396
+ btn.style.pointerEvents = 'none';
397
+ btn.style.position = 'absolute';
398
+ btn.style.left = '0';
399
+ btn.style.bottom = '-36px';
400
+ btn.style.boxSizing = 'content-box';
126
401
  btn.style.width = '100%';
127
- btn.style.height = '28px';
128
- btn.style.marginTop = '4px';
402
+ btn.style.height = '32px';
403
+ btn.style.padding = '4px 8px 0';
404
+ btn.style.marginLeft = '-8px';
129
405
 
130
- const plus = document.createElement('span');
406
+ const visual = document.createElement('div');
131
407
 
132
- plus.className = twMerge(PLUS_CLASSES);
133
- plus.textContent = '+';
134
- btn.appendChild(plus);
408
+ visual.className = twMerge(VISUAL_CLASSES);
409
+ visual.style.width = '100%';
410
+ visual.style.height = '16px';
411
+
412
+ this.appendIcon(visual);
413
+ btn.appendChild(visual);
414
+
415
+ onHover(btn, createTooltipContent([
416
+ this.i18n.t('tools.table.clickToAddRow'),
417
+ this.i18n.t('tools.table.dragToAddRemoveRows'),
418
+ ]), { placement: 'bottom', marginTop: -16 });
135
419
 
136
420
  return btn;
137
421
  }
@@ -139,22 +423,44 @@ export class TableAddControls {
139
423
  private createAddColumnButton(): HTMLElement {
140
424
  const btn = document.createElement('div');
141
425
 
142
- btn.className = twMerge(SHARED_CLASSES);
426
+ btn.className = twMerge(HIT_AREA_CLASSES, 'group/add', 'justify-start', 'cursor-col-resize');
143
427
  btn.setAttribute(ADD_COL_ATTR, '');
144
428
  btn.setAttribute('contenteditable', 'false');
145
429
  btn.style.opacity = '0';
430
+ btn.style.pointerEvents = 'none';
146
431
  btn.style.position = 'absolute';
147
- btn.style.right = '-32px';
432
+ btn.style.right = '-36px';
148
433
  btn.style.top = '0px';
149
434
  btn.style.bottom = '0px';
150
- btn.style.width = '28px';
435
+ btn.style.width = '32px';
436
+
437
+ const visual = document.createElement('div');
151
438
 
152
- const plus = document.createElement('span');
439
+ visual.className = twMerge(VISUAL_CLASSES);
440
+ visual.style.width = '16px';
441
+ visual.style.height = '100%';
153
442
 
154
- plus.className = twMerge(PLUS_CLASSES);
155
- plus.textContent = '+';
156
- btn.appendChild(plus);
443
+ this.appendIcon(visual);
444
+ btn.appendChild(visual);
445
+
446
+ onHover(btn, createTooltipContent([
447
+ this.i18n.t('tools.table.clickToAddColumn'),
448
+ this.i18n.t('tools.table.dragToAddRemoveColumns'),
449
+ ]), { placement: 'bottom' });
157
450
 
158
451
  return btn;
159
452
  }
453
+
454
+ private appendIcon(parent: HTMLElement): void {
455
+ parent.insertAdjacentHTML('beforeend', IconPlus);
456
+
457
+ const svg = parent.querySelector('svg');
458
+
459
+ if (svg) {
460
+ svg.setAttribute('width', ICON_SIZE);
461
+ svg.setAttribute('height', ICON_SIZE);
462
+ svg.setAttribute('viewBox', '0 0 24 24');
463
+ svg.classList.add('text-gray-500', 'pointer-events-none');
464
+ }
465
+ }
160
466
  }
@@ -45,6 +45,7 @@ interface TableCellBlocksOptions {
45
45
  export class TableCellBlocks {
46
46
  private api: API;
47
47
  private gridElement: HTMLElement;
48
+ private tableBlockId: string;
48
49
  private _activeCellWithBlocks: CellPosition | null = null;
49
50
  private onNavigateToCell?: CellNavigationCallback;
50
51
 
@@ -68,9 +69,11 @@ export class TableCellBlocks {
68
69
  constructor(options: TableCellBlocksOptions) {
69
70
  this.api = options.api;
70
71
  this.gridElement = options.gridElement;
72
+ this.tableBlockId = options.tableBlockId;
71
73
  this.onNavigateToCell = options.onNavigateToCell;
72
74
 
73
75
  this.api.events.on('block changed', this.handleBlockMutation);
76
+ this.gridElement.addEventListener('click', this.handleCellBlankSpaceClick);
74
77
  }
75
78
 
76
79
  /**
@@ -228,6 +231,7 @@ export class TableCellBlocks {
228
231
  * Initialize all cells with blocks.
229
232
  * - Empty cells or legacy string cells get a new paragraph block.
230
233
  * - Cells that already have block references get those blocks mounted.
234
+ * - If referenced blocks are missing from BlockManager, a fallback paragraph is created.
231
235
  */
232
236
  public initializeCells(content: LegacyCellContent[][]): CellContent[][] {
233
237
  const rowElements = this.gridElement.querySelectorAll(`[${ROW_ATTR}]`);
@@ -256,14 +260,18 @@ export class TableCellBlocks {
256
260
  return;
257
261
  }
258
262
 
259
- if (isCellWithBlocks(cellContent)) {
260
- this.mountBlocksInCell(container, cellContent.blocks);
261
- normalizedRow.push(cellContent);
263
+ const mountedIds = isCellWithBlocks(cellContent)
264
+ ? this.mountBlocksInCell(container, cellContent.blocks)
265
+ : [];
266
+
267
+ if (mountedIds.length > 0) {
268
+ normalizedRow.push({ blocks: mountedIds });
262
269
  } else {
263
270
  const text = typeof cellContent === 'string' ? cellContent : '';
264
271
  const block = this.api.blocks.insert('paragraph', { text }, {}, this.api.blocks.getBlocksCount(), false);
265
272
 
266
273
  container.appendChild(block.holder);
274
+ this.api.blocks.setBlockParent(block.id, this.tableBlockId);
267
275
  normalizedRow.push({ blocks: [block.id] });
268
276
  }
269
277
 
@@ -290,9 +298,12 @@ export class TableCellBlocks {
290
298
  }
291
299
 
292
300
  /**
293
- * Mount existing blocks into a cell container by their IDs
301
+ * Mount existing blocks into a cell container by their IDs.
302
+ * Returns the IDs of blocks that were successfully mounted.
294
303
  */
295
- private mountBlocksInCell(container: HTMLElement, blockIds: string[]): void {
304
+ private mountBlocksInCell(container: HTMLElement, blockIds: string[]): string[] {
305
+ const mountedIds: string[] = [];
306
+
296
307
  for (const blockId of blockIds) {
297
308
  const index = this.api.blocks.getBlockIndex(blockId);
298
309
 
@@ -307,7 +318,11 @@ export class TableCellBlocks {
307
318
  }
308
319
 
309
320
  container.appendChild(block.holder);
321
+ this.api.blocks.setBlockParent(blockId, this.tableBlockId);
322
+ mountedIds.push(blockId);
310
323
  }
324
+
325
+ return mountedIds;
311
326
  }
312
327
 
313
328
  /**
@@ -333,6 +348,7 @@ export class TableCellBlocks {
333
348
  }
334
349
 
335
350
  container.appendChild(block.holder);
351
+ this.api.blocks.setBlockParent(blockId, this.tableBlockId);
336
352
  this.stripPlaceholders(container);
337
353
  }
338
354
 
@@ -391,6 +407,7 @@ export class TableCellBlocks {
391
407
  const block = this.api.blocks.insert('paragraph', { text: '' }, {}, this.api.blocks.getBlocksCount(), true);
392
408
 
393
409
  container.appendChild(block.holder);
410
+ this.api.blocks.setBlockParent(block.id, this.tableBlockId);
394
411
  this.stripPlaceholders(container);
395
412
  }
396
413
 
@@ -454,10 +471,20 @@ export class TableCellBlocks {
454
471
  }
455
472
 
456
473
  // For non-replace inserts: if the holder is already in a cell (placed
457
- // by insertToDOM next to an adjacent cell block), no action needed.
474
+ // by insertToDOM next to an adjacent cell block), just strip placeholders.
458
475
  const holder = detail.target.holder;
476
+ const existingContainer = holder.closest<HTMLElement>(`[${CELL_BLOCKS_ATTR}]`);
477
+
478
+ if (existingContainer) {
479
+ this.stripPlaceholders(existingContainer);
459
480
 
460
- if (holder.closest(`[${CELL_BLOCKS_ATTR}]`)) {
481
+ return;
482
+ }
483
+
484
+ // Only claim blocks whose holder is inside this table's grid.
485
+ // Blocks placed outside the grid (e.g., via replaceWith during toolbox
486
+ // insertion) should not be pulled into a cell by adjacency.
487
+ if (!this.gridElement.contains(holder)) {
461
488
  return;
462
489
  }
463
490
 
@@ -572,10 +599,71 @@ export class TableCellBlocks {
572
599
  });
573
600
  }
574
601
 
602
+ /**
603
+ * Delete all blocks managed by this table from the BlockManager.
604
+ * Called before the table block itself is removed to prevent orphaned cell blocks.
605
+ */
606
+ public deleteAllBlocks(): void {
607
+ const allCells = this.gridElement.querySelectorAll(`[${CELL_ATTR}]`);
608
+ const blockIds = this.getBlockIdsFromCells(allCells);
609
+
610
+ this.deleteBlocks(blockIds);
611
+ }
612
+
613
+ /**
614
+ * Handle clicks on blank cell space.
615
+ * When a click lands on the cell or blocks container (not on block content),
616
+ * set the caret to the end of the last block in that cell.
617
+ */
618
+ private handleCellBlankSpaceClick = (event: Event): void => {
619
+ const target = event.target as HTMLElement | null;
620
+
621
+ if (!target) {
622
+ return;
623
+ }
624
+
625
+ const isCell = target.hasAttribute(CELL_ATTR);
626
+ const isBlocksContainer = target.hasAttribute(CELL_BLOCKS_ATTR);
627
+
628
+ if (!isCell && !isBlocksContainer) {
629
+ return;
630
+ }
631
+
632
+ const cell = isCell ? target : target.closest<HTMLElement>(`[${CELL_ATTR}]`);
633
+
634
+ if (!cell) {
635
+ return;
636
+ }
637
+
638
+ const container = isCell
639
+ ? cell.querySelector<HTMLElement>(`[${CELL_BLOCKS_ATTR}]`)
640
+ : target;
641
+
642
+ if (!container) {
643
+ return;
644
+ }
645
+
646
+ const blockHolders = container.querySelectorAll('[data-blok-id]');
647
+ const lastHolder = blockHolders[blockHolders.length - 1];
648
+
649
+ if (!lastHolder) {
650
+ return;
651
+ }
652
+
653
+ const blockId = lastHolder.getAttribute('data-blok-id');
654
+
655
+ if (!blockId) {
656
+ return;
657
+ }
658
+
659
+ this.api.caret.setToBlock(blockId, 'end');
660
+ };
661
+
575
662
  /**
576
663
  * Clean up event listeners
577
664
  */
578
665
  destroy(): void {
666
+ this.gridElement.removeEventListener('click', this.handleCellBlankSpaceClick);
579
667
  this.api.events.off('block changed', this.handleBlockMutation);
580
668
  this._activeCellWithBlocks = null;
581
669
  this.cellsPendingCheck.clear();