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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (256) 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-DK-97ZTf.mjs → blok-BOtlKwVO.mjs} +1486 -1354
  5. package/dist/chunks/{i18next-loader-CRollibS.mjs → i18next-loader-CJNShSyT.mjs} +1 -1
  6. package/dist/chunks/{index-jgHmMDND.mjs → index-BUAPAChM.mjs} +1 -1
  7. package/dist/chunks/{inline-tool-convert-BIwvipPw.mjs → inline-tool-convert-UoYdJJic.mjs} +88 -73
  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 +929 -779
  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/i18n/locales/am/messages.json +15 -1
  153. package/src/components/i18n/locales/ar/messages.json +14 -0
  154. package/src/components/i18n/locales/az/messages.json +14 -0
  155. package/src/components/i18n/locales/bg/messages.json +14 -0
  156. package/src/components/i18n/locales/bn/messages.json +25 -11
  157. package/src/components/i18n/locales/bs/messages.json +15 -1
  158. package/src/components/i18n/locales/cs/messages.json +14 -0
  159. package/src/components/i18n/locales/da/messages.json +14 -0
  160. package/src/components/i18n/locales/de/messages.json +14 -0
  161. package/src/components/i18n/locales/dv/messages.json +15 -1
  162. package/src/components/i18n/locales/el/messages.json +15 -1
  163. package/src/components/i18n/locales/en/messages.json +14 -0
  164. package/src/components/i18n/locales/es/messages.json +14 -0
  165. package/src/components/i18n/locales/et/messages.json +14 -0
  166. package/src/components/i18n/locales/fa/messages.json +15 -1
  167. package/src/components/i18n/locales/fi/messages.json +15 -1
  168. package/src/components/i18n/locales/fil/messages.json +20 -6
  169. package/src/components/i18n/locales/fr/messages.json +15 -1
  170. package/src/components/i18n/locales/gu/messages.json +15 -1
  171. package/src/components/i18n/locales/he/messages.json +14 -0
  172. package/src/components/i18n/locales/hi/messages.json +23 -9
  173. package/src/components/i18n/locales/hr/messages.json +14 -0
  174. package/src/components/i18n/locales/hu/messages.json +14 -0
  175. package/src/components/i18n/locales/hy/messages.json +16 -2
  176. package/src/components/i18n/locales/id/messages.json +19 -5
  177. package/src/components/i18n/locales/it/messages.json +14 -0
  178. package/src/components/i18n/locales/ja/messages.json +14 -0
  179. package/src/components/i18n/locales/ka/messages.json +15 -1
  180. package/src/components/i18n/locales/km/messages.json +16 -2
  181. package/src/components/i18n/locales/kn/messages.json +16 -2
  182. package/src/components/i18n/locales/ko/messages.json +14 -0
  183. package/src/components/i18n/locales/ku/messages.json +16 -2
  184. package/src/components/i18n/locales/lo/messages.json +15 -1
  185. package/src/components/i18n/locales/lt/messages.json +15 -1
  186. package/src/components/i18n/locales/lv/messages.json +15 -1
  187. package/src/components/i18n/locales/mk/messages.json +16 -2
  188. package/src/components/i18n/locales/ml/messages.json +16 -2
  189. package/src/components/i18n/locales/mn/messages.json +16 -2
  190. package/src/components/i18n/locales/mr/messages.json +24 -10
  191. package/src/components/i18n/locales/ms/messages.json +17 -3
  192. package/src/components/i18n/locales/my/messages.json +16 -2
  193. package/src/components/i18n/locales/ne/messages.json +24 -10
  194. package/src/components/i18n/locales/nl/messages.json +15 -1
  195. package/src/components/i18n/locales/no/messages.json +16 -2
  196. package/src/components/i18n/locales/pa/messages.json +15 -1
  197. package/src/components/i18n/locales/pl/messages.json +14 -0
  198. package/src/components/i18n/locales/ps/messages.json +17 -3
  199. package/src/components/i18n/locales/pt/messages.json +14 -0
  200. package/src/components/i18n/locales/ro/messages.json +15 -1
  201. package/src/components/i18n/locales/ru/messages.json +14 -0
  202. package/src/components/i18n/locales/sd/messages.json +16 -2
  203. package/src/components/i18n/locales/si/messages.json +23 -9
  204. package/src/components/i18n/locales/sk/messages.json +15 -1
  205. package/src/components/i18n/locales/sl/messages.json +16 -2
  206. package/src/components/i18n/locales/sq/messages.json +16 -2
  207. package/src/components/i18n/locales/sr/messages.json +16 -2
  208. package/src/components/i18n/locales/sv/messages.json +16 -2
  209. package/src/components/i18n/locales/sw/messages.json +16 -2
  210. package/src/components/i18n/locales/ta/messages.json +21 -7
  211. package/src/components/i18n/locales/te/messages.json +40 -26
  212. package/src/components/i18n/locales/th/messages.json +19 -5
  213. package/src/components/i18n/locales/tr/messages.json +15 -1
  214. package/src/components/i18n/locales/ug/messages.json +16 -2
  215. package/src/components/i18n/locales/uk/messages.json +15 -1
  216. package/src/components/i18n/locales/ur/messages.json +15 -1
  217. package/src/components/i18n/locales/vi/messages.json +25 -11
  218. package/src/components/i18n/locales/yi/messages.json +16 -2
  219. package/src/components/i18n/locales/zh/messages.json +15 -1
  220. package/src/components/modules/api/blocks.ts +17 -2
  221. package/src/components/modules/api/history.ts +64 -0
  222. package/src/components/modules/api/index.ts +1 -0
  223. package/src/components/modules/api/readonly.ts +11 -1
  224. package/src/components/modules/blockEvents/composers/markdownShortcuts.ts +12 -1
  225. package/src/components/modules/blockManager/blockManager.ts +7 -0
  226. package/src/components/modules/blockManager/yjs-sync.ts +12 -2
  227. package/src/components/modules/index.ts +3 -0
  228. package/src/components/modules/readonly.ts +11 -0
  229. package/src/components/modules/toolbar/index.ts +29 -7
  230. package/src/components/modules/ui.ts +46 -68
  231. package/src/components/modules/uiControllers/controllers/blockHover.ts +40 -61
  232. package/src/components/modules/yjs/index.ts +23 -0
  233. package/src/components/ui/toolbox.ts +41 -6
  234. package/src/components/utils/popover/components/popover-item/popover-item-default/popover-item-default.ts +3 -1
  235. package/src/components/utils/popover/popover-desktop.ts +27 -8
  236. package/src/tools/table/index.ts +87 -70
  237. package/src/tools/table/table-add-controls.ts +33 -7
  238. package/src/tools/table/table-cell-blocks.ts +77 -5
  239. package/src/tools/table/table-cell-selection.ts +70 -46
  240. package/src/tools/table/table-core.ts +20 -15
  241. package/src/tools/table/table-grip-visuals.ts +4 -4
  242. package/src/tools/table/table-operations.ts +22 -12
  243. package/src/tools/table/table-restrictions.ts +64 -0
  244. package/src/tools/table/table-row-col-action-handler.ts +190 -0
  245. package/src/tools/table/table-row-col-controls.ts +91 -182
  246. package/src/tools/table/table-row-col-drag.ts +4 -4
  247. package/src/tools/table/table-row-col-popover.ts +225 -0
  248. package/src/tools/table/types.ts +2 -0
  249. package/src/types-internal/blok-modules.d.ts +2 -0
  250. package/types/api/history.d.ts +33 -0
  251. package/types/api/index.d.ts +1 -0
  252. package/types/api/readonly.d.ts +12 -2
  253. package/types/index.d.ts +3 -0
  254. package/types/utils/popover/popover.d.ts +7 -0
  255. package/dist/chunks/messages-CySyfkMU.mjs +0 -48
  256. package/dist/messages-CySyfkMU.mjs +0 -48
@@ -324,6 +324,8 @@ export class PopoverItemDefault extends PopoverItem {
324
324
 
325
325
  return twMerge(
326
326
  css.item,
327
+ // Asymmetric padding for vertical popovers (better visual balance)
328
+ !isInline && !isNestedInline && 'pl-2 pr-8',
327
329
  isInline && cssInline.item,
328
330
  isNestedInline && cssNestedInline.item,
329
331
  this.params.isDisabled && css.itemDisabled
@@ -338,7 +340,7 @@ export class PopoverItemDefault extends PopoverItem {
338
340
  css.icon,
339
341
  isInline && 'w-auto h-auto [&_svg]:w-icon [&_svg]:h-icon mobile:[&_svg]:w-icon-mobile mobile:[&_svg]:h-icon-mobile',
340
342
  isNestedInline && 'w-toolbox-btn h-toolbox-btn',
341
- iconWithGap && 'mr-2',
343
+ iconWithGap && 'mr-3',
342
344
  iconWithGap && isInline && 'shadow-none bg-transparent !mr-0',
343
345
  iconWithGap && isNestedInline && '!mr-2',
344
346
  isWobbling && 'animate-wobble'
@@ -217,31 +217,50 @@ export class PopoverDesktop extends PopoverAbstract {
217
217
  this.flipper?.focusItem(0, { skipNextTab: true });
218
218
  }
219
219
 
220
+ /**
221
+ * Updates the popover position dynamically.
222
+ * Used when the trigger position changes or when positioning at caret location.
223
+ * @param position - new DOMRect position for the popover
224
+ */
225
+ public updatePosition(position: DOMRect): void {
226
+ this.params.position = position;
227
+
228
+ // Recalculate and apply position if already shown
229
+ if (this.nodes.popover.hasAttribute('data-blok-popover-opened')) {
230
+ const { top, left } = this.calculatePosition();
231
+
232
+ this.nodes.popover.style.top = `${top}px`;
233
+ this.nodes.popover.style.left = `${left}px`;
234
+ }
235
+ }
236
+
220
237
  /**
221
238
  * Calculates position for the popover
222
239
  */
223
240
  private calculatePosition(): { top: number; left: number } {
224
- if (!this.trigger) {
241
+ // Use provided position if available, otherwise fall back to trigger element
242
+ const rect = this.params.position ?? this.trigger?.getBoundingClientRect();
243
+
244
+ if (!rect) {
225
245
  return {
226
246
  top: 0,
227
247
  left: 0,
228
248
  };
229
249
  }
230
250
 
231
- const triggerRect = this.trigger.getBoundingClientRect();
232
251
  const popoverRect = this.size;
233
252
  const windowWidth = window.innerWidth;
234
253
  const windowHeight = window.innerHeight;
235
254
  const offset = 8;
236
255
 
237
- const initialTop = triggerRect.bottom + offset + window.scrollY;
238
- const shouldFlipTop = (triggerRect.bottom + offset + popoverRect.height > windowHeight + window.scrollY) &&
239
- (triggerRect.top - offset - popoverRect.height > window.scrollY);
240
- const top = shouldFlipTop ? triggerRect.top - offset - popoverRect.height + window.scrollY : initialTop;
256
+ const initialTop = rect.bottom + offset + window.scrollY;
257
+ const shouldFlipTop = (rect.bottom + offset + popoverRect.height > windowHeight + window.scrollY) &&
258
+ (rect.top - offset - popoverRect.height > window.scrollY);
259
+ const top = shouldFlipTop ? rect.top - offset - popoverRect.height + window.scrollY : initialTop;
241
260
 
242
- const initialLeft = triggerRect.left + window.scrollX;
261
+ const initialLeft = rect.left + window.scrollX;
243
262
  const shouldFlipLeft = initialLeft + popoverRect.width > windowWidth + window.scrollX;
244
- const left = shouldFlipLeft ? Math.max(0, triggerRect.right - popoverRect.width + window.scrollX) : initialLeft;
263
+ const left = shouldFlipLeft ? Math.max(0, rect.right - popoverRect.width + window.scrollX) : initialLeft;
245
264
 
246
265
  return {
247
266
  top,
@@ -18,7 +18,7 @@ import { TableGrid } from './table-core';
18
18
  import {
19
19
  applyPixelWidths,
20
20
  computeHalfAvgWidth,
21
- computeInsertColumnWidths,
21
+ computeInitialColWidth,
22
22
  deleteColumnWithBlockCleanup,
23
23
  deleteRowWithBlockCleanup,
24
24
  enableScrollOverflow,
@@ -30,14 +30,14 @@ import {
30
30
  normalizeTableData,
31
31
  populateNewCells,
32
32
  readPixelWidths,
33
- redistributePercentWidths,
34
33
  SCROLL_OVERFLOW_CLASSES,
35
34
  setupKeyboardNavigation,
36
- syncColWidthsAfterMove,
37
35
  updateHeadingColumnStyles,
38
36
  updateHeadingStyles,
39
37
  } from './table-operations';
40
38
  import { TableResize } from './table-resize';
39
+ import { executeRowColAction } from './table-row-col-action-handler';
40
+ import type { PendingHighlight } from './table-row-col-action-handler';
41
41
  import { TableRowColControls } from './table-row-col-controls';
42
42
  import type { RowColAction } from './table-row-col-controls';
43
43
  import type { TableData, TableConfig } from './types';
@@ -71,7 +71,8 @@ export class Table implements BlockTool {
71
71
  private cellSelection: TableCellSelection | null = null;
72
72
  private element: HTMLDivElement | null = null;
73
73
  private blockId: string | undefined;
74
- private pendingHighlight: { type: 'row' | 'col'; index: number } | null = null;
74
+ private pendingHighlight: PendingHighlight | null = null;
75
+ private isNewTable = false;
75
76
 
76
77
  constructor({ data, config, api, readOnly, block }: BlockToolConstructorOptions<TableData, TableConfig>) {
77
78
  this.api = api;
@@ -127,6 +128,8 @@ export class Table implements BlockTool {
127
128
  wrapper.setAttribute('data-blok-table-readonly', '');
128
129
  }
129
130
 
131
+ this.isNewTable = this.data.content.length === 0;
132
+
130
133
  const rows = this.data.content.length || this.config.rows || DEFAULT_ROWS;
131
134
  const cols = this.data.content[0]?.length || this.config.cols || DEFAULT_COLS;
132
135
 
@@ -178,10 +181,28 @@ export class Table implements BlockTool {
178
181
 
179
182
  this.data.content = this.cellBlocks?.initializeCells(this.data.content) ?? this.data.content;
180
183
 
184
+ if (this.isNewTable) {
185
+ populateNewCells(gridEl, this.cellBlocks);
186
+ }
187
+
188
+ if (this.data.initialColWidth === undefined) {
189
+ const widths = this.data.colWidths ?? readPixelWidths(gridEl);
190
+
191
+ this.data.initialColWidth = widths.length > 0
192
+ ? computeInitialColWidth(widths)
193
+ : undefined;
194
+ }
195
+
181
196
  this.initResize(gridEl);
182
197
  this.initAddControls(gridEl);
183
198
  this.initRowColControls(gridEl);
184
199
  this.initCellSelection(gridEl);
200
+
201
+ if (this.isNewTable) {
202
+ const firstEditable = gridEl.querySelector<HTMLElement>('[contenteditable="true"]');
203
+
204
+ firstEditable?.focus();
205
+ }
185
206
  }
186
207
 
187
208
  public save(blockContent: HTMLElement): TableData {
@@ -197,6 +218,7 @@ export class Table implements BlockTool {
197
218
  stretched: this.data.stretched,
198
219
  content,
199
220
  ...(colWidths ? { colWidths } : {}),
221
+ ...(this.data.initialColWidth !== undefined ? { initialColWidth: this.data.initialColWidth } : {}),
200
222
  };
201
223
  }
202
224
 
@@ -252,6 +274,8 @@ export class Table implements BlockTool {
252
274
  }
253
275
 
254
276
  public destroy(): void {
277
+ this.cellBlocks?.deleteAllBlocks();
278
+
255
279
  this.resize?.destroy();
256
280
  this.resize = null;
257
281
  this.addControls?.destroy();
@@ -296,9 +320,19 @@ export class Table implements BlockTool {
296
320
  return;
297
321
  }
298
322
 
323
+ const dragState = { addedCols: 0 };
324
+
299
325
  this.addControls = new TableAddControls({
300
326
  wrapper: this.element,
301
327
  grid: gridEl,
328
+ i18n: this.api.i18n,
329
+ getNewColumnWidth: () => {
330
+ const colWidths = this.data.colWidths ?? readPixelWidths(gridEl);
331
+
332
+ return this.data.initialColWidth !== undefined
333
+ ? Math.round((this.data.initialColWidth / 2) * 100) / 100
334
+ : computeHalfAvgWidth(colWidths);
335
+ },
302
336
  onAddRow: () => {
303
337
  this.grid.addRow(gridEl);
304
338
  populateNewCells(gridEl, this.cellBlocks);
@@ -310,10 +344,12 @@ export class Table implements BlockTool {
310
344
  },
311
345
  onAddColumn: () => {
312
346
  const colWidths = this.data.colWidths ?? readPixelWidths(gridEl);
313
- const halfAvgWidth = computeHalfAvgWidth(colWidths);
347
+ const halfWidth = this.data.initialColWidth !== undefined
348
+ ? Math.round((this.data.initialColWidth / 2) * 100) / 100
349
+ : computeHalfAvgWidth(colWidths);
314
350
 
315
- this.grid.addColumn(gridEl, undefined, colWidths);
316
- this.data.colWidths = [...colWidths, halfAvgWidth];
351
+ this.grid.addColumn(gridEl, undefined, colWidths, halfWidth);
352
+ this.data.colWidths = [...colWidths, halfWidth];
317
353
  populateNewCells(gridEl, this.cellBlocks);
318
354
  updateHeadingColumnStyles(this.element, this.data.withHeadingColumn);
319
355
  this.initResize(gridEl);
@@ -342,14 +378,22 @@ export class Table implements BlockTool {
342
378
  },
343
379
  onDragAddCol: () => {
344
380
  const colWidths = this.data.colWidths ?? readPixelWidths(gridEl);
345
- const halfAvgWidth = computeHalfAvgWidth(colWidths);
381
+ const halfWidth = this.data.initialColWidth !== undefined
382
+ ? Math.round((this.data.initialColWidth / 2) * 100) / 100
383
+ : computeHalfAvgWidth(colWidths);
346
384
 
347
- this.grid.addColumn(gridEl, undefined, colWidths);
348
- this.data.colWidths = [...colWidths, halfAvgWidth];
385
+ this.grid.addColumn(gridEl, undefined, colWidths, halfWidth);
386
+ this.data.colWidths = [...colWidths, halfWidth];
349
387
  applyPixelWidths(gridEl, this.data.colWidths);
350
388
  populateNewCells(gridEl, this.cellBlocks);
351
389
  updateHeadingColumnStyles(this.element, this.data.withHeadingColumn);
352
390
  this.initResize(gridEl);
391
+
392
+ dragState.addedCols++;
393
+
394
+ if (this.element) {
395
+ this.element.scrollLeft = this.element.scrollWidth;
396
+ }
353
397
  },
354
398
  onDragRemoveCol: () => {
355
399
  const colCount = this.grid.getColumnCount(gridEl);
@@ -365,6 +409,8 @@ export class Table implements BlockTool {
365
409
  }
366
410
 
367
411
  this.initResize(gridEl);
412
+
413
+ dragState.addedCols--;
368
414
  },
369
415
  onDragEnd: () => {
370
416
  this.initResize(gridEl);
@@ -372,8 +418,10 @@ export class Table implements BlockTool {
372
418
  this.rowColControls?.refresh();
373
419
 
374
420
  if (this.element) {
375
- this.element.scrollLeft = 0;
421
+ this.element.scrollLeft = dragState.addedCols > 0 ? this.element.scrollWidth : 0;
376
422
  }
423
+
424
+ dragState.addedCols = 0;
377
425
  },
378
426
  });
379
427
  }
@@ -391,6 +439,7 @@ export class Table implements BlockTool {
391
439
  getRowCount: () => this.grid.getRowCount(gridEl),
392
440
  isHeadingRow: () => this.data.withHeadings,
393
441
  isHeadingColumn: () => this.data.withHeadingColumn,
442
+ i18n: this.api.i18n,
394
443
  onAction: (action: RowColAction) => this.handleRowColAction(gridEl, action),
395
444
  onDragStateChange: (isDragging: boolean) => {
396
445
  if (this.resize) {
@@ -434,72 +483,37 @@ export class Table implements BlockTool {
434
483
  }
435
484
 
436
485
  private handleRowColAction(gridEl: HTMLElement, action: RowColAction): void {
437
- switch (action.type) {
438
- case 'insert-row-above':
439
- this.grid.addRow(gridEl, action.index);
440
- populateNewCells(gridEl, this.cellBlocks);
441
- this.pendingHighlight = { type: 'row', index: action.index };
442
- break;
443
- case 'insert-row-below':
444
- this.grid.addRow(gridEl, action.index + 1);
445
- populateNewCells(gridEl, this.cellBlocks);
446
- this.pendingHighlight = { type: 'row', index: action.index + 1 };
447
- break;
448
- case 'insert-col-left':
449
- this.data.colWidths = computeInsertColumnWidths(gridEl, action.index, this.data, this.grid);
450
- populateNewCells(gridEl, this.cellBlocks);
451
- this.pendingHighlight = { type: 'col', index: action.index };
452
- break;
453
- case 'insert-col-right':
454
- this.data.colWidths = computeInsertColumnWidths(gridEl, action.index + 1, this.data, this.grid);
455
- populateNewCells(gridEl, this.cellBlocks);
456
- this.pendingHighlight = { type: 'col', index: action.index + 1 };
457
- break;
458
- case 'move-row':
459
- this.grid.moveRow(gridEl, action.fromIndex, action.toIndex);
460
- break;
461
- case 'move-col':
462
- this.grid.moveColumn(gridEl, action.fromIndex, action.toIndex);
463
- this.data.colWidths = syncColWidthsAfterMove(this.data.colWidths, action.fromIndex, action.toIndex);
464
- break;
465
- case 'delete-row': {
466
- deleteRowWithBlockCleanup(gridEl, action.index, this.grid, this.cellBlocks);
467
- const newRowCount = this.grid.getRowCount(gridEl);
468
- const neighborRow = action.index < newRowCount ? action.index : action.index - 1;
469
-
470
- this.pendingHighlight = { type: 'row', index: neighborRow };
471
- break;
472
- }
473
- case 'delete-col': {
474
- this.data.colWidths = deleteColumnWithBlockCleanup(gridEl, action.index, this.data.colWidths, this.grid, this.cellBlocks);
475
-
476
- if (this.data.colWidths) {
477
- applyPixelWidths(gridEl, this.data.colWidths);
478
- } else {
479
- redistributePercentWidths(gridEl);
480
- }
486
+ const result = executeRowColAction(
487
+ gridEl,
488
+ action,
489
+ { grid: this.grid, data: this.data, cellBlocks: this.cellBlocks },
490
+ );
481
491
 
482
- const newColCount = this.grid.getColumnCount(gridEl);
483
- const neighborCol = action.index < newColCount ? action.index : action.index - 1;
484
-
485
- this.pendingHighlight = { type: 'col', index: neighborCol };
486
- break;
487
- }
488
- case 'toggle-heading':
489
- this.data.withHeadings = !this.data.withHeadings;
490
- this.pendingHighlight = { type: 'row', index: 0 };
491
- break;
492
- case 'toggle-heading-column':
493
- this.data.withHeadingColumn = !this.data.withHeadingColumn;
494
- this.pendingHighlight = { type: 'col', index: 0 };
495
- break;
496
- }
492
+ this.data.colWidths = result.colWidths;
493
+ this.data.withHeadings = result.withHeadings;
494
+ this.data.withHeadingColumn = result.withHeadingColumn;
495
+ this.pendingHighlight = result.pendingHighlight;
497
496
 
498
497
  updateHeadingStyles(this.element, this.data.withHeadings);
499
498
  updateHeadingColumnStyles(this.element, this.data.withHeadingColumn);
500
499
  this.initResize(gridEl);
501
500
  this.addControls?.syncRowButtonWidth();
502
501
  this.rowColControls?.refresh();
502
+
503
+ if (!result.moveSelection) {
504
+ return;
505
+ }
506
+
507
+ // After move operations, select the moved row/column to show where it landed
508
+ const { type: moveType, index: moveIndex } = result.moveSelection;
509
+
510
+ if (moveType === 'row') {
511
+ this.cellSelection?.selectRow(moveIndex);
512
+ } else {
513
+ this.cellSelection?.selectColumn(moveIndex);
514
+ }
515
+
516
+ this.rowColControls?.setActiveGrip(moveType, moveIndex);
503
517
  }
504
518
 
505
519
  private initResize(gridEl: HTMLElement): void {
@@ -547,6 +561,7 @@ export class Table implements BlockTool {
547
561
  this.cellSelection = new TableCellSelection({
548
562
  grid: gridEl,
549
563
  rectangleSelection, // Pass reference
564
+ i18n: this.api.i18n,
550
565
  onSelectionActiveChange: (hasSelection) => {
551
566
  if (this.resize) {
552
567
  this.resize.enabled = !hasSelection;
@@ -567,3 +582,5 @@ export class Table implements BlockTool {
567
582
  });
568
583
  }
569
584
  }
585
+
586
+ export { isInsideTableCell, isRestrictedInTableCell, convertToParagraph } from './table-restrictions';
@@ -1,3 +1,4 @@
1
+ import type { I18n } from '../../../types/api';
1
2
  import { IconPlus } from '../../components/icons';
2
3
  import { createTooltipContent } from '../../components/modules/toolbar/tooltip';
3
4
  import { hide as hideTooltip, onHover } from '../../components/utils/tooltip';
@@ -46,6 +47,7 @@ interface DragState {
46
47
  interface TableAddControlsOptions {
47
48
  wrapper: HTMLElement;
48
49
  grid: HTMLElement;
50
+ i18n: I18n;
49
51
  onAddRow: () => void;
50
52
  onAddColumn: () => void;
51
53
  onDragStart: () => void;
@@ -54,6 +56,8 @@ interface TableAddControlsOptions {
54
56
  onDragAddCol: () => void;
55
57
  onDragRemoveCol: () => void;
56
58
  onDragEnd: () => void;
59
+ /** Returns the pixel width of a newly added column, used as the drag unit size. */
60
+ getNewColumnWidth?: () => number;
57
61
  }
58
62
 
59
63
  /**
@@ -64,6 +68,7 @@ interface TableAddControlsOptions {
64
68
  export class TableAddControls {
65
69
  private wrapper: HTMLElement;
66
70
  private grid: HTMLElement;
71
+ private i18n: I18n;
67
72
  private addRowBtn: HTMLElement;
68
73
  private addColBtn: HTMLElement;
69
74
  private rowHideTimeout: ReturnType<typeof setTimeout> | null = null;
@@ -86,10 +91,12 @@ export class TableAddControls {
86
91
  private boundPointerUp: (e: PointerEvent) => void;
87
92
  private boundRowPointerDown: (e: PointerEvent) => void;
88
93
  private boundColPointerDown: (e: PointerEvent) => void;
94
+ private getNewColumnWidth: (() => number) | undefined;
89
95
 
90
96
  constructor(options: TableAddControlsOptions) {
91
97
  this.wrapper = options.wrapper;
92
98
  this.grid = options.grid;
99
+ this.i18n = options.i18n;
93
100
 
94
101
  this.boundAddRowClick = options.onAddRow;
95
102
  this.boundAddColClick = options.onAddColumn;
@@ -99,6 +106,7 @@ export class TableAddControls {
99
106
  this.onDragAddCol = options.onDragAddCol;
100
107
  this.onDragRemoveCol = options.onDragRemoveCol;
101
108
  this.onDragEnd = options.onDragEnd;
109
+ this.getNewColumnWidth = options.getNewColumnWidth;
102
110
  this.boundMouseMove = this.handleMouseMove.bind(this);
103
111
  this.boundMouseLeave = this.handleMouseLeave.bind(this);
104
112
  this.boundPointerMove = this.handlePointerMove.bind(this);
@@ -151,10 +159,15 @@ export class TableAddControls {
151
159
  * Disables pointer events and hover effects during cell selection.
152
160
  */
153
161
  public setInteractive(interactive: boolean): void {
154
- const pointerEvents = interactive ? '' : 'none';
162
+ if (!interactive) {
163
+ this.addRowBtn.style.pointerEvents = 'none';
164
+ this.addColBtn.style.pointerEvents = 'none';
155
165
 
156
- this.addRowBtn.style.pointerEvents = pointerEvents;
157
- this.addColBtn.style.pointerEvents = pointerEvents;
166
+ return;
167
+ }
168
+
169
+ this.addRowBtn.style.pointerEvents = this.rowVisible ? '' : 'none';
170
+ this.addColBtn.style.pointerEvents = this.colVisible ? '' : 'none';
158
171
  }
159
172
 
160
173
  public destroy(): void {
@@ -274,6 +287,10 @@ export class TableAddControls {
274
287
  return lastRow?.offsetHeight || 30;
275
288
  }
276
289
 
290
+ if (this.getNewColumnWidth) {
291
+ return this.getNewColumnWidth();
292
+ }
293
+
277
294
  const firstRow = this.grid.querySelector('[data-blok-table-row]');
278
295
 
279
296
  if (!firstRow) {
@@ -314,6 +331,7 @@ export class TableAddControls {
314
331
 
315
332
  if (!this.rowVisible) {
316
333
  this.addRowBtn.style.opacity = '1';
334
+ this.addRowBtn.style.pointerEvents = '';
317
335
  this.rowVisible = true;
318
336
  }
319
337
  }
@@ -323,6 +341,7 @@ export class TableAddControls {
323
341
 
324
342
  if (!this.colVisible) {
325
343
  this.addColBtn.style.opacity = '1';
344
+ this.addColBtn.style.pointerEvents = '';
326
345
  this.colVisible = true;
327
346
  }
328
347
  }
@@ -334,6 +353,7 @@ export class TableAddControls {
334
353
 
335
354
  this.rowHideTimeout = setTimeout(() => {
336
355
  this.addRowBtn.style.opacity = '0';
356
+ this.addRowBtn.style.pointerEvents = 'none';
337
357
  this.rowVisible = false;
338
358
  this.rowHideTimeout = null;
339
359
  }, HIDE_DELAY_MS);
@@ -346,6 +366,7 @@ export class TableAddControls {
346
366
 
347
367
  this.colHideTimeout = setTimeout(() => {
348
368
  this.addColBtn.style.opacity = '0';
369
+ this.addColBtn.style.pointerEvents = 'none';
349
370
  this.colVisible = false;
350
371
  this.colHideTimeout = null;
351
372
  }, HIDE_DELAY_MS);
@@ -372,6 +393,10 @@ export class TableAddControls {
372
393
  btn.setAttribute(ADD_ROW_ATTR, '');
373
394
  btn.setAttribute('contenteditable', 'false');
374
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';
375
400
  btn.style.boxSizing = 'content-box';
376
401
  btn.style.width = '100%';
377
402
  btn.style.height = '32px';
@@ -388,8 +413,8 @@ export class TableAddControls {
388
413
  btn.appendChild(visual);
389
414
 
390
415
  onHover(btn, createTooltipContent([
391
- 'Click to add a new row',
392
- 'Drag to add or remove rows',
416
+ this.i18n.t('tools.table.clickToAddRow'),
417
+ this.i18n.t('tools.table.dragToAddRemoveRows'),
393
418
  ]), { placement: 'bottom', marginTop: -16 });
394
419
 
395
420
  return btn;
@@ -402,6 +427,7 @@ export class TableAddControls {
402
427
  btn.setAttribute(ADD_COL_ATTR, '');
403
428
  btn.setAttribute('contenteditable', 'false');
404
429
  btn.style.opacity = '0';
430
+ btn.style.pointerEvents = 'none';
405
431
  btn.style.position = 'absolute';
406
432
  btn.style.right = '-36px';
407
433
  btn.style.top = '0px';
@@ -418,8 +444,8 @@ export class TableAddControls {
418
444
  btn.appendChild(visual);
419
445
 
420
446
  onHover(btn, createTooltipContent([
421
- 'Click to add a new column',
422
- 'Drag to add or remove columns',
447
+ this.i18n.t('tools.table.clickToAddColumn'),
448
+ this.i18n.t('tools.table.dragToAddRemoveColumns'),
423
449
  ]), { placement: 'bottom' });
424
450
 
425
451
  return btn;
@@ -71,6 +71,7 @@ export class TableCellBlocks {
71
71
  this.onNavigateToCell = options.onNavigateToCell;
72
72
 
73
73
  this.api.events.on('block changed', this.handleBlockMutation);
74
+ this.gridElement.addEventListener('click', this.handleCellBlankSpaceClick);
74
75
  }
75
76
 
76
77
  /**
@@ -228,6 +229,7 @@ export class TableCellBlocks {
228
229
  * Initialize all cells with blocks.
229
230
  * - Empty cells or legacy string cells get a new paragraph block.
230
231
  * - Cells that already have block references get those blocks mounted.
232
+ * - If referenced blocks are missing from BlockManager, a fallback paragraph is created.
231
233
  */
232
234
  public initializeCells(content: LegacyCellContent[][]): CellContent[][] {
233
235
  const rowElements = this.gridElement.querySelectorAll(`[${ROW_ATTR}]`);
@@ -256,9 +258,12 @@ export class TableCellBlocks {
256
258
  return;
257
259
  }
258
260
 
259
- if (isCellWithBlocks(cellContent)) {
260
- this.mountBlocksInCell(container, cellContent.blocks);
261
- normalizedRow.push(cellContent);
261
+ const mountedIds = isCellWithBlocks(cellContent)
262
+ ? this.mountBlocksInCell(container, cellContent.blocks)
263
+ : [];
264
+
265
+ if (mountedIds.length > 0) {
266
+ normalizedRow.push({ blocks: mountedIds });
262
267
  } else {
263
268
  const text = typeof cellContent === 'string' ? cellContent : '';
264
269
  const block = this.api.blocks.insert('paragraph', { text }, {}, this.api.blocks.getBlocksCount(), false);
@@ -290,9 +295,12 @@ export class TableCellBlocks {
290
295
  }
291
296
 
292
297
  /**
293
- * Mount existing blocks into a cell container by their IDs
298
+ * Mount existing blocks into a cell container by their IDs.
299
+ * Returns the IDs of blocks that were successfully mounted.
294
300
  */
295
- private mountBlocksInCell(container: HTMLElement, blockIds: string[]): void {
301
+ private mountBlocksInCell(container: HTMLElement, blockIds: string[]): string[] {
302
+ const mountedIds: string[] = [];
303
+
296
304
  for (const blockId of blockIds) {
297
305
  const index = this.api.blocks.getBlockIndex(blockId);
298
306
 
@@ -307,7 +315,10 @@ export class TableCellBlocks {
307
315
  }
308
316
 
309
317
  container.appendChild(block.holder);
318
+ mountedIds.push(blockId);
310
319
  }
320
+
321
+ return mountedIds;
311
322
  }
312
323
 
313
324
  /**
@@ -575,10 +586,71 @@ export class TableCellBlocks {
575
586
  });
576
587
  }
577
588
 
589
+ /**
590
+ * Delete all blocks managed by this table from the BlockManager.
591
+ * Called before the table block itself is removed to prevent orphaned cell blocks.
592
+ */
593
+ public deleteAllBlocks(): void {
594
+ const allCells = this.gridElement.querySelectorAll(`[${CELL_ATTR}]`);
595
+ const blockIds = this.getBlockIdsFromCells(allCells);
596
+
597
+ this.deleteBlocks(blockIds);
598
+ }
599
+
600
+ /**
601
+ * Handle clicks on blank cell space.
602
+ * When a click lands on the cell or blocks container (not on block content),
603
+ * set the caret to the end of the last block in that cell.
604
+ */
605
+ private handleCellBlankSpaceClick = (event: Event): void => {
606
+ const target = event.target as HTMLElement | null;
607
+
608
+ if (!target) {
609
+ return;
610
+ }
611
+
612
+ const isCell = target.hasAttribute(CELL_ATTR);
613
+ const isBlocksContainer = target.hasAttribute(CELL_BLOCKS_ATTR);
614
+
615
+ if (!isCell && !isBlocksContainer) {
616
+ return;
617
+ }
618
+
619
+ const cell = isCell ? target : target.closest<HTMLElement>(`[${CELL_ATTR}]`);
620
+
621
+ if (!cell) {
622
+ return;
623
+ }
624
+
625
+ const container = isCell
626
+ ? cell.querySelector<HTMLElement>(`[${CELL_BLOCKS_ATTR}]`)
627
+ : target;
628
+
629
+ if (!container) {
630
+ return;
631
+ }
632
+
633
+ const blockHolders = container.querySelectorAll('[data-blok-id]');
634
+ const lastHolder = blockHolders[blockHolders.length - 1];
635
+
636
+ if (!lastHolder) {
637
+ return;
638
+ }
639
+
640
+ const blockId = lastHolder.getAttribute('data-blok-id');
641
+
642
+ if (!blockId) {
643
+ return;
644
+ }
645
+
646
+ this.api.caret.setToBlock(blockId, 'end');
647
+ };
648
+
578
649
  /**
579
650
  * Clean up event listeners
580
651
  */
581
652
  destroy(): void {
653
+ this.gridElement.removeEventListener('click', this.handleCellBlankSpaceClick);
582
654
  this.api.events.off('block changed', this.handleBlockMutation);
583
655
  this._activeCellWithBlocks = null;
584
656
  this.cellsPendingCheck.clear();