@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
@@ -7,15 +7,37 @@ import type {
7
7
  ToolboxConfig,
8
8
  } from '../../../types';
9
9
  import type { ToolSanitizerConfig } from '../../../types/configs/sanitizer-config';
10
- import type { MenuConfig } from '../../../types/tools/menu-config';
11
10
  import { DATA_ATTR } from '../../components/constants';
12
11
  import { IconTable } from '../../components/icons';
13
12
  import { twMerge } from '../../components/utils/tw';
14
13
 
15
14
  import { TableAddControls } from './table-add-controls';
16
15
  import { TableCellBlocks } from './table-cell-blocks';
17
- import { BORDER_WIDTH, ROW_ATTR, CELL_ATTR, TableGrid } from './table-core';
16
+ import { TableCellSelection } from './table-cell-selection';
17
+ import { TableGrid } from './table-core';
18
+ import {
19
+ applyPixelWidths,
20
+ computeHalfAvgWidth,
21
+ computeInitialColWidth,
22
+ deleteColumnWithBlockCleanup,
23
+ deleteRowWithBlockCleanup,
24
+ enableScrollOverflow,
25
+ getBlockIdsInColumn,
26
+ getBlockIdsInRow,
27
+ isColumnEmpty,
28
+ isRowEmpty,
29
+ mountCellBlocksReadOnly,
30
+ normalizeTableData,
31
+ populateNewCells,
32
+ readPixelWidths,
33
+ SCROLL_OVERFLOW_CLASSES,
34
+ setupKeyboardNavigation,
35
+ updateHeadingColumnStyles,
36
+ updateHeadingStyles,
37
+ } from './table-operations';
18
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';
19
41
  import { TableRowColControls } from './table-row-col-controls';
20
42
  import type { RowColAction } from './table-row-col-controls';
21
43
  import type { TableData, TableConfig } from './types';
@@ -24,14 +46,12 @@ const DEFAULT_ROWS = 3;
24
46
  const DEFAULT_COLS = 3;
25
47
 
26
48
  const WRAPPER_CLASSES = [
27
- 'overflow-x-auto',
28
49
  'my-2',
50
+ 'pr-5',
29
51
  ];
30
52
 
31
53
  const WRAPPER_EDIT_CLASSES = [
32
54
  'relative',
33
- 'pr-9',
34
- 'pb-9',
35
55
  ];
36
56
 
37
57
  /**
@@ -48,21 +68,21 @@ export class Table implements BlockTool {
48
68
  private addControls: TableAddControls | null = null;
49
69
  private rowColControls: TableRowColControls | null = null;
50
70
  private cellBlocks: TableCellBlocks | null = null;
71
+ private cellSelection: TableCellSelection | null = null;
51
72
  private element: HTMLDivElement | null = null;
52
73
  private blockId: string | undefined;
74
+ private pendingHighlight: PendingHighlight | null = null;
75
+ private isNewTable = false;
53
76
 
54
77
  constructor({ data, config, api, readOnly, block }: BlockToolConstructorOptions<TableData, TableConfig>) {
55
78
  this.api = api;
56
79
  this.readOnly = readOnly;
57
80
  this.config = config ?? {};
58
- this.data = this.normalizeData(data);
81
+ this.data = normalizeTableData(data, config ?? {});
59
82
  this.grid = new TableGrid({ readOnly });
60
83
  this.blockId = block?.id;
61
84
  }
62
85
 
63
- /**
64
- * Toolbox configuration
65
- */
66
86
  public static get toolbox(): ToolboxConfig {
67
87
  return {
68
88
  icon: IconTable,
@@ -98,19 +118,18 @@ export class Table implements BlockTool {
98
118
  };
99
119
  }
100
120
 
101
- /**
102
- * Render the table
103
- */
104
121
  public render(): HTMLDivElement {
105
122
  const wrapper = document.createElement('div');
106
123
 
107
- wrapper.className = twMerge(WRAPPER_CLASSES, !this.readOnly && WRAPPER_EDIT_CLASSES);
124
+ wrapper.className = twMerge(WRAPPER_CLASSES, !this.readOnly && WRAPPER_EDIT_CLASSES, this.data.colWidths && SCROLL_OVERFLOW_CLASSES);
108
125
  wrapper.setAttribute(DATA_ATTR.tool, 'table');
109
126
 
110
127
  if (this.readOnly) {
111
128
  wrapper.setAttribute('data-blok-table-readonly', '');
112
129
  }
113
130
 
131
+ this.isNewTable = this.data.content.length === 0;
132
+
114
133
  const rows = this.data.content.length || this.config.rows || DEFAULT_ROWS;
115
134
  const cols = this.data.content[0]?.length || this.config.cols || DEFAULT_COLS;
116
135
 
@@ -121,30 +140,30 @@ export class Table implements BlockTool {
121
140
  }
122
141
 
123
142
  if (this.data.colWidths) {
124
- this.applyPixelWidths(gridEl, this.data.colWidths);
143
+ applyPixelWidths(gridEl, this.data.colWidths);
125
144
  }
126
145
 
127
146
  wrapper.appendChild(gridEl);
128
147
  this.element = wrapper;
129
148
 
130
149
  if (this.data.withHeadings) {
131
- this.updateHeadingStyles();
150
+ updateHeadingStyles(this.element, this.data.withHeadings);
151
+ }
152
+
153
+ if (this.data.withHeadingColumn) {
154
+ updateHeadingColumnStyles(this.element, this.data.withHeadingColumn);
132
155
  }
133
156
 
134
157
  if (!this.readOnly) {
135
- this.setupKeyboardNavigation(gridEl);
136
158
  this.initCellBlocks(gridEl);
159
+ setupKeyboardNavigation(gridEl, this.cellBlocks);
137
160
  }
138
161
 
139
162
  return wrapper;
140
163
  }
141
164
 
142
- /**
143
- * Called after block element is added to the DOM.
144
- * Initializes resize handles now that pixel widths can be measured.
145
- */
146
165
  public rendered(): void {
147
- if (this.readOnly || !this.element) {
166
+ if (!this.element) {
148
167
  return;
149
168
  }
150
169
 
@@ -154,62 +173,59 @@ export class Table implements BlockTool {
154
173
  return;
155
174
  }
156
175
 
157
- // Initialize cell blocks here (after Yjs fromJSON has run) so that
158
- // cell paragraph blocks are synced to both BlocksStore and Yjs.
159
- // Creating them during render() would cause a desync: fromJSON wipes
160
- // the Yjs array after render() but before rendered().
176
+ if (this.readOnly) {
177
+ mountCellBlocksReadOnly(gridEl, this.data.content, this.api);
178
+
179
+ return;
180
+ }
181
+
161
182
  this.data.content = this.cellBlocks?.initializeCells(this.data.content) ?? this.data.content;
162
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
+
163
196
  this.initResize(gridEl);
164
197
  this.initAddControls(gridEl);
165
198
  this.initRowColControls(gridEl);
199
+ this.initCellSelection(gridEl);
200
+
201
+ if (this.isNewTable) {
202
+ const firstEditable = gridEl.querySelector<HTMLElement>('[contenteditable="true"]');
203
+
204
+ firstEditable?.focus();
205
+ }
166
206
  }
167
207
 
168
- /**
169
- * Extract data from the rendered table
170
- */
171
208
  public save(blockContent: HTMLElement): TableData {
172
209
  const gridEl = blockContent.firstElementChild as HTMLElement;
173
210
  const colWidths = this.data.colWidths;
211
+ const content = this.readOnly
212
+ ? this.data.content
213
+ : this.grid.getData(gridEl);
174
214
 
175
215
  return {
176
216
  withHeadings: this.data.withHeadings,
217
+ withHeadingColumn: this.data.withHeadingColumn,
177
218
  stretched: this.data.stretched,
178
- content: this.grid.getData(gridEl),
219
+ content,
179
220
  ...(colWidths ? { colWidths } : {}),
221
+ ...(this.data.initialColWidth !== undefined ? { initialColWidth: this.data.initialColWidth } : {}),
180
222
  };
181
223
  }
182
224
 
183
- /**
184
- * Validate saved data
185
- */
186
225
  public validate(savedData: TableData): boolean {
187
226
  return savedData.content.length > 0;
188
227
  }
189
228
 
190
- /**
191
- * Render block settings
192
- */
193
- public renderSettings(): MenuConfig {
194
- return [
195
- {
196
- icon: IconTable,
197
- title: this.api.i18n.t(this.data.withHeadings
198
- ? 'tools.table.withoutHeadings'
199
- : 'tools.table.withHeadings'),
200
- onActivate: (): void => {
201
- this.data.withHeadings = !this.data.withHeadings;
202
- this.updateHeadingStyles();
203
- },
204
- closeOnActivate: true,
205
- isActive: this.data.withHeadings,
206
- },
207
- ];
208
- }
209
-
210
- /**
211
- * Handle paste of HTML table
212
- */
213
229
  public onPaste(event: HTMLPasteEvent): void {
214
230
  const content = event.detail.data;
215
231
  const rows = content.querySelectorAll('tr');
@@ -228,18 +244,17 @@ export class Table implements BlockTool {
228
244
  }
229
245
  });
230
246
 
231
- // Detect headings from thead or th elements in first row
232
247
  const hasTheadHeadings = content.querySelector('thead') !== null;
233
248
  const hasThHeadings = rows[0]?.querySelector('th') !== null;
234
249
  const withHeadings = hasTheadHeadings || hasThHeadings;
235
250
 
236
251
  this.data = {
237
252
  withHeadings,
253
+ withHeadingColumn: this.data.withHeadingColumn,
238
254
  stretched: this.data.stretched,
239
255
  content: tableContent,
240
256
  };
241
257
 
242
- // Re-render with new data
243
258
  if (!this.element?.parentNode) {
244
259
  return;
245
260
  }
@@ -258,10 +273,9 @@ export class Table implements BlockTool {
258
273
  }
259
274
  }
260
275
 
261
- /**
262
- * Clean up
263
- */
264
276
  public destroy(): void {
277
+ this.cellBlocks?.deleteAllBlocks();
278
+
265
279
  this.resize?.destroy();
266
280
  this.resize = null;
267
281
  this.addControls?.destroy();
@@ -270,55 +284,33 @@ export class Table implements BlockTool {
270
284
  this.rowColControls = null;
271
285
  this.cellBlocks?.destroy();
272
286
  this.cellBlocks = null;
287
+ this.cellSelection?.destroy();
288
+ this.cellSelection = null;
273
289
  this.element = null;
274
290
  }
275
291
 
276
- private normalizeData(data: TableData | Record<string, never>): TableData {
277
- const isTableData = typeof data === 'object' && data !== null && 'content' in data;
292
+ public deleteRowWithCleanup(rowIndex: number): void {
293
+ const gridEl = this.element?.firstElementChild as HTMLElement | undefined;
278
294
 
279
- if (!isTableData) {
280
- return {
281
- withHeadings: this.config.withHeadings ?? false,
282
- stretched: this.config.stretched ?? false,
283
- content: [],
284
- };
295
+ if (gridEl) {
296
+ deleteRowWithBlockCleanup(gridEl, rowIndex, this.grid, this.cellBlocks);
285
297
  }
286
-
287
- const tableData = data as TableData;
288
- const cols = tableData.content?.[0]?.length;
289
- const colWidths = tableData.colWidths;
290
- const validWidths = colWidths && cols && colWidths.length === cols ? colWidths : undefined;
291
-
292
- return {
293
- withHeadings: tableData.withHeadings ?? this.config.withHeadings ?? false,
294
- stretched: tableData.stretched ?? this.config.stretched ?? false,
295
- content: tableData.content ?? [],
296
- colWidths: validWidths,
297
- };
298
298
  }
299
299
 
300
- private updateHeadingStyles(): void {
301
- if (!this.element) {
302
- return;
303
- }
304
-
305
- const gridEl = this.element.firstElementChild as HTMLElement;
300
+ public deleteColumnWithCleanup(colIndex: number): void {
301
+ const gridEl = this.element?.firstElementChild as HTMLElement | undefined;
306
302
 
307
- if (!gridEl) {
308
- return;
303
+ if (gridEl) {
304
+ this.data.colWidths = deleteColumnWithBlockCleanup(gridEl, colIndex, this.data.colWidths, this.grid, this.cellBlocks);
309
305
  }
306
+ }
310
307
 
311
- const firstRow = gridEl.querySelector('[data-blok-table-row]');
312
-
313
- if (!firstRow) {
314
- return;
315
- }
308
+ public getBlockIdsInRow(rowIndex: number): string[] {
309
+ return getBlockIdsInRow(this.element, this.cellBlocks, rowIndex);
310
+ }
316
311
 
317
- if (this.data.withHeadings) {
318
- firstRow.setAttribute('data-blok-table-heading', '');
319
- } else {
320
- firstRow.removeAttribute('data-blok-table-heading');
321
- }
312
+ public getBlockIdsInColumn(colIndex: number): string[] {
313
+ return getBlockIdsInColumn(this.element, this.cellBlocks, colIndex);
322
314
  }
323
315
 
324
316
  private initAddControls(gridEl: HTMLElement): void {
@@ -328,24 +320,108 @@ export class Table implements BlockTool {
328
320
  return;
329
321
  }
330
322
 
323
+ const dragState = { addedCols: 0 };
324
+
331
325
  this.addControls = new TableAddControls({
332
326
  wrapper: this.element,
333
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
+ },
334
336
  onAddRow: () => {
335
337
  this.grid.addRow(gridEl);
336
- this.populateNewCells(gridEl);
338
+ populateNewCells(gridEl, this.cellBlocks);
339
+ updateHeadingStyles(this.element, this.data.withHeadings);
340
+ updateHeadingColumnStyles(this.element, this.data.withHeadingColumn);
341
+ this.initResize(gridEl);
342
+ this.addControls?.syncRowButtonWidth();
343
+ this.rowColControls?.refresh();
337
344
  },
338
345
  onAddColumn: () => {
339
- const colWidths = this.data.colWidths ?? this.readPixelWidths(gridEl);
340
- const halfAvgWidth = Math.round(
341
- (colWidths.reduce((sum, w) => sum + w, 0) / colWidths.length / 2) * 100
342
- ) / 100;
343
-
344
- this.grid.addColumn(gridEl, undefined, colWidths);
345
- this.data.colWidths = [...colWidths, halfAvgWidth];
346
- this.populateNewCells(gridEl);
346
+ const colWidths = this.data.colWidths ?? readPixelWidths(gridEl);
347
+ const halfWidth = this.data.initialColWidth !== undefined
348
+ ? Math.round((this.data.initialColWidth / 2) * 100) / 100
349
+ : computeHalfAvgWidth(colWidths);
350
+
351
+ this.grid.addColumn(gridEl, undefined, colWidths, halfWidth);
352
+ this.data.colWidths = [...colWidths, halfWidth];
353
+ populateNewCells(gridEl, this.cellBlocks);
354
+ updateHeadingColumnStyles(this.element, this.data.withHeadingColumn);
347
355
  this.initResize(gridEl);
348
356
  this.addControls?.syncRowButtonWidth();
357
+ this.rowColControls?.refresh();
358
+ },
359
+ onDragStart: () => {
360
+ if (this.resize) {
361
+ this.resize.enabled = false;
362
+ }
363
+ this.rowColControls?.hideAllGrips();
364
+ this.rowColControls?.setGripsDisplay(false);
365
+ },
366
+ onDragAddRow: () => {
367
+ this.grid.addRow(gridEl);
368
+ populateNewCells(gridEl, this.cellBlocks);
369
+ updateHeadingStyles(this.element, this.data.withHeadings);
370
+ updateHeadingColumnStyles(this.element, this.data.withHeadingColumn);
371
+ },
372
+ onDragRemoveRow: () => {
373
+ const rowCount = this.grid.getRowCount(gridEl);
374
+
375
+ if (rowCount > 1 && isRowEmpty(gridEl, rowCount - 1)) {
376
+ deleteRowWithBlockCleanup(gridEl, rowCount - 1, this.grid, this.cellBlocks);
377
+ }
378
+ },
379
+ onDragAddCol: () => {
380
+ const colWidths = this.data.colWidths ?? readPixelWidths(gridEl);
381
+ const halfWidth = this.data.initialColWidth !== undefined
382
+ ? Math.round((this.data.initialColWidth / 2) * 100) / 100
383
+ : computeHalfAvgWidth(colWidths);
384
+
385
+ this.grid.addColumn(gridEl, undefined, colWidths, halfWidth);
386
+ this.data.colWidths = [...colWidths, halfWidth];
387
+ applyPixelWidths(gridEl, this.data.colWidths);
388
+ populateNewCells(gridEl, this.cellBlocks);
389
+ updateHeadingColumnStyles(this.element, this.data.withHeadingColumn);
390
+ this.initResize(gridEl);
391
+
392
+ dragState.addedCols++;
393
+
394
+ if (this.element) {
395
+ this.element.scrollLeft = this.element.scrollWidth;
396
+ }
397
+ },
398
+ onDragRemoveCol: () => {
399
+ const colCount = this.grid.getColumnCount(gridEl);
400
+
401
+ if (colCount <= 1 || !isColumnEmpty(gridEl, colCount - 1)) {
402
+ return;
403
+ }
404
+
405
+ this.data.colWidths = deleteColumnWithBlockCleanup(gridEl, colCount - 1, this.data.colWidths, this.grid, this.cellBlocks);
406
+
407
+ if (this.data.colWidths) {
408
+ applyPixelWidths(gridEl, this.data.colWidths);
409
+ }
410
+
411
+ this.initResize(gridEl);
412
+
413
+ dragState.addedCols--;
414
+ },
415
+ onDragEnd: () => {
416
+ this.initResize(gridEl);
417
+ this.addControls?.syncRowButtonWidth();
418
+ this.rowColControls?.refresh();
419
+
420
+ if (this.element) {
421
+ this.element.scrollLeft = dragState.addedCols > 0 ? this.element.scrollWidth : 0;
422
+ }
423
+
424
+ dragState.addedCols = 0;
349
425
  },
350
426
  });
351
427
  }
@@ -362,171 +438,114 @@ export class Table implements BlockTool {
362
438
  getColumnCount: () => this.grid.getColumnCount(gridEl),
363
439
  getRowCount: () => this.grid.getRowCount(gridEl),
364
440
  isHeadingRow: () => this.data.withHeadings,
441
+ isHeadingColumn: () => this.data.withHeadingColumn,
442
+ i18n: this.api.i18n,
365
443
  onAction: (action: RowColAction) => this.handleRowColAction(gridEl, action),
366
444
  onDragStateChange: (isDragging: boolean) => {
367
- if (!this.resize) {
368
- return;
445
+ if (this.resize) {
446
+ this.resize.enabled = !isDragging;
369
447
  }
370
448
 
371
- this.resize.enabled = !isDragging;
449
+ this.addControls?.setDisplay(!isDragging);
450
+
451
+ if (isDragging) {
452
+ this.api.toolbar.close({ setExplicitlyClosed: false });
453
+ }
454
+ },
455
+ onGripClick: (type, index) => {
456
+ if (type === 'row') {
457
+ this.cellSelection?.selectRow(index);
458
+ } else {
459
+ this.cellSelection?.selectColumn(index);
460
+ }
461
+ },
462
+ onGripPopoverClose: () => {
463
+ if (this.pendingHighlight) {
464
+ const { type, index } = this.pendingHighlight;
465
+
466
+ this.pendingHighlight = null;
467
+
468
+ // Lock the grip synchronously so the unlock listener is registered
469
+ // before any external click can race with a deferred RAF
470
+ this.rowColControls?.setActiveGrip(type, index);
471
+
472
+ // Wait for layout so newly inserted cells have dimensions
473
+ requestAnimationFrame(() => {
474
+ if (type === 'row') {
475
+ this.cellSelection?.selectRow(index);
476
+ } else {
477
+ this.cellSelection?.selectColumn(index);
478
+ }
479
+ });
480
+ } else {
481
+ this.cellSelection?.clearActiveSelection();
482
+ }
372
483
  },
373
484
  });
374
485
  }
375
486
 
376
487
  private handleRowColAction(gridEl: HTMLElement, action: RowColAction): void {
377
- switch (action.type) {
378
- case 'insert-row-above':
379
- this.grid.addRow(gridEl, action.index);
380
- this.populateNewCells(gridEl);
381
- break;
382
- case 'insert-row-below':
383
- this.grid.addRow(gridEl, action.index + 1);
384
- this.populateNewCells(gridEl);
385
- break;
386
- case 'insert-col-left':
387
- this.handleInsertColumn(gridEl, action.index);
388
- this.populateNewCells(gridEl);
389
- break;
390
- case 'insert-col-right':
391
- this.handleInsertColumn(gridEl, action.index + 1);
392
- this.populateNewCells(gridEl);
393
- break;
394
- case 'move-row':
395
- this.grid.moveRow(gridEl, action.fromIndex, action.toIndex);
396
- break;
397
- case 'move-col':
398
- this.grid.moveColumn(gridEl, action.fromIndex, action.toIndex);
399
- this.syncColWidthsAfterMove(action.fromIndex, action.toIndex);
400
- break;
401
- case 'delete-row':
402
- this.deleteRowWithBlockCleanup(gridEl, action.index);
403
- break;
404
- case 'delete-col':
405
- this.deleteColumnWithBlockCleanup(gridEl, action.index);
406
- break;
407
- case 'toggle-heading':
408
- this.data.withHeadings = !this.data.withHeadings;
409
- this.updateHeadingStyles();
410
- break;
411
- }
488
+ const result = executeRowColAction(
489
+ gridEl,
490
+ action,
491
+ { grid: this.grid, data: this.data, cellBlocks: this.cellBlocks },
492
+ );
412
493
 
494
+ this.data.colWidths = result.colWidths;
495
+ this.data.withHeadings = result.withHeadings;
496
+ this.data.withHeadingColumn = result.withHeadingColumn;
497
+ this.pendingHighlight = result.pendingHighlight;
498
+
499
+ updateHeadingStyles(this.element, this.data.withHeadings);
500
+ updateHeadingColumnStyles(this.element, this.data.withHeadingColumn);
413
501
  this.initResize(gridEl);
414
502
  this.addControls?.syncRowButtonWidth();
415
503
  this.rowColControls?.refresh();
416
- }
417
-
418
- private handleInsertColumn(gridEl: HTMLElement, index: number): void {
419
- const colWidths = this.data.colWidths ?? this.readPixelWidths(gridEl);
420
-
421
- this.grid.addColumn(gridEl, index, colWidths);
422
-
423
- const halfAvgWidth = Math.round(
424
- (colWidths.reduce((sum, w) => sum + w, 0) / colWidths.length / 2) * 100
425
- ) / 100;
426
- const newWidths = [...colWidths];
427
504
 
428
- newWidths.splice(index, 0, halfAvgWidth);
429
- this.data.colWidths = newWidths;
430
- }
431
-
432
- private syncColWidthsAfterMove(fromIndex: number, toIndex: number): void {
433
- if (!this.data.colWidths) {
505
+ if (!result.moveSelection) {
434
506
  return;
435
507
  }
436
508
 
437
- const widths = [...this.data.colWidths];
438
- const [moved] = widths.splice(fromIndex, 1);
439
-
440
- widths.splice(toIndex, 0, moved);
441
- this.data.colWidths = widths;
442
- }
509
+ // After move operations, select the moved row/column to show where it landed
510
+ const { type: moveType, index: moveIndex } = result.moveSelection;
443
511
 
444
- private syncColWidthsAfterDeleteColumn(index: number): void {
445
- if (!this.data.colWidths) {
446
- return;
512
+ if (moveType === 'row') {
513
+ this.cellSelection?.selectRow(moveIndex);
514
+ } else {
515
+ this.cellSelection?.selectColumn(moveIndex);
447
516
  }
448
517
 
449
- const widths = [...this.data.colWidths];
450
-
451
- widths.splice(index, 1);
452
- this.data.colWidths = widths.length > 0 ? widths : undefined;
518
+ this.rowColControls?.setActiveGrip(moveType, moveIndex);
453
519
  }
454
520
 
455
521
  private initResize(gridEl: HTMLElement): void {
456
522
  this.resize?.destroy();
457
523
 
458
- const widths = this.data.colWidths ?? this.readPixelWidths(gridEl);
459
-
460
- this.resize = new TableResize(gridEl, widths, (newWidths: number[]) => {
461
- this.data.colWidths = newWidths;
462
- });
463
- }
464
-
465
- private readPixelWidths(gridEl: HTMLElement): number[] {
466
- const firstRow = gridEl.querySelector('[data-blok-table-row]');
524
+ const isPercentMode = this.data.colWidths === undefined;
525
+ const widths = this.data.colWidths ?? readPixelWidths(gridEl);
467
526
 
468
- if (!firstRow) {
469
- return [];
527
+ if (!isPercentMode) {
528
+ enableScrollOverflow(this.element);
470
529
  }
471
530
 
472
- const cells = firstRow.querySelectorAll('[data-blok-table-cell]');
473
-
474
- return Array.from(cells).map(cell =>
475
- (cell as HTMLElement).getBoundingClientRect().width
531
+ this.resize = new TableResize(
532
+ gridEl,
533
+ widths,
534
+ (newWidths: number[]) => {
535
+ this.data.colWidths = newWidths;
536
+ enableScrollOverflow(this.element);
537
+ this.rowColControls?.positionGrips();
538
+ },
539
+ () => {
540
+ this.rowColControls?.hideAllGrips();
541
+ },
542
+ () => {
543
+ this.addControls?.syncRowButtonWidth();
544
+ },
545
+ isPercentMode,
476
546
  );
477
547
  }
478
548
 
479
- private applyPixelWidths(grid: HTMLElement, widths: number[]): void {
480
- const totalWidth = widths.reduce((sum, w) => sum + w, 0);
481
- const gridStyle: HTMLElement = grid;
482
-
483
- gridStyle.style.width = `${totalWidth + BORDER_WIDTH}px`;
484
-
485
- const rowEls = grid.querySelectorAll('[data-blok-table-row]');
486
-
487
- rowEls.forEach(row => {
488
- const cells = row.querySelectorAll('[data-blok-table-cell]');
489
-
490
- cells.forEach((node, i) => {
491
- if (i < widths.length) {
492
- const cellEl = node as HTMLElement;
493
-
494
- cellEl.style.width = `${widths[i]}px`;
495
- }
496
- });
497
- });
498
- }
499
-
500
- private setupKeyboardNavigation(gridEl: HTMLElement): void {
501
- gridEl.addEventListener('keydown', (event: KeyboardEvent) => {
502
- const target = event.target as HTMLElement;
503
- const cell = target.closest<HTMLElement>('[data-blok-table-cell]');
504
-
505
- if (!cell) {
506
- return;
507
- }
508
-
509
- const position = this.getCellPosition(gridEl, cell);
510
-
511
- if (position) {
512
- this.cellBlocks?.handleKeyDown(event, position);
513
- }
514
- });
515
- }
516
-
517
- /**
518
- * Ensure every cell in the grid has at least one block.
519
- * Called after addRow / addColumn so new empty cells get an initial paragraph.
520
- * Cells that already contain blocks are left untouched.
521
- */
522
- private populateNewCells(gridEl: HTMLElement): void {
523
- const cells = gridEl.querySelectorAll(`[${CELL_ATTR}]`);
524
-
525
- cells.forEach(cell => {
526
- this.cellBlocks?.ensureCellHasBlock(cell as HTMLElement);
527
- });
528
- }
529
-
530
549
  private initCellBlocks(gridEl: HTMLElement): void {
531
550
  this.cellBlocks = new TableCellBlocks({
532
551
  api: this.api,
@@ -535,117 +554,35 @@ export class Table implements BlockTool {
535
554
  });
536
555
  }
537
556
 
538
- private getCellPosition(gridEl: HTMLElement, cell: HTMLElement): { row: number; col: number } | null {
539
- const rows = Array.from(gridEl.querySelectorAll('[data-blok-table-row]'));
540
-
541
- const rowIndex = rows.findIndex(row => {
542
- const cells = Array.from(row.querySelectorAll('[data-blok-table-cell]'));
543
-
544
- return cells.includes(cell);
545
- });
546
-
547
- if (rowIndex === -1) {
548
- return null;
549
- }
550
-
551
- const cells = Array.from(rows[rowIndex].querySelectorAll('[data-blok-table-cell]'));
552
- const colIndex = cells.indexOf(cell);
553
-
554
- return { row: rowIndex, col: colIndex };
555
- }
556
-
557
- /**
558
- * Delete a row and clean up any nested blocks within its cells
559
- */
560
- public deleteRowWithCleanup(rowIndex: number): void {
561
- const gridEl = this.element?.firstElementChild as HTMLElement | undefined;
562
-
563
- if (gridEl) {
564
- this.deleteRowWithBlockCleanup(gridEl, rowIndex);
565
- }
566
- }
567
-
568
- /**
569
- * Delete a column and clean up any nested blocks within its cells
570
- */
571
- public deleteColumnWithCleanup(colIndex: number): void {
572
- const gridEl = this.element?.firstElementChild as HTMLElement | undefined;
573
-
574
- if (gridEl) {
575
- this.deleteColumnWithBlockCleanup(gridEl, colIndex);
576
- }
577
- }
578
-
579
- private deleteRowWithBlockCleanup(gridEl: HTMLElement, rowIndex: number): void {
580
- const rows = gridEl.querySelectorAll(`[${ROW_ATTR}]`);
581
- const row = rows[rowIndex];
582
-
583
- if (row && this.cellBlocks) {
584
- const cells = row.querySelectorAll(`[${CELL_ATTR}]`);
585
-
586
- this.cellBlocks.deleteBlocks(this.cellBlocks.getBlockIdsFromCells(cells));
587
- }
588
-
589
- this.grid.deleteRow(gridEl, rowIndex);
590
- }
591
-
592
- private deleteColumnWithBlockCleanup(gridEl: HTMLElement, colIndex: number): void {
593
- if (this.cellBlocks) {
594
- const rows = gridEl.querySelectorAll(`[${ROW_ATTR}]`);
595
- const cellsInColumn: Element[] = [];
557
+ private initCellSelection(gridEl: HTMLElement): void {
558
+ this.cellSelection?.destroy();
596
559
 
597
- rows.forEach(row => {
598
- const cells = row.querySelectorAll(`[${CELL_ATTR}]`);
560
+ // Get RectangleSelection from API
561
+ const rectangleSelection = this.api.rectangleSelection;
599
562
 
600
- if (colIndex < cells.length) {
601
- cellsInColumn.push(cells[colIndex]);
563
+ this.cellSelection = new TableCellSelection({
564
+ grid: gridEl,
565
+ rectangleSelection, // Pass reference
566
+ i18n: this.api.i18n,
567
+ onSelectionActiveChange: (hasSelection) => {
568
+ if (this.resize) {
569
+ this.resize.enabled = !hasSelection;
602
570
  }
603
- });
604
-
605
- this.cellBlocks.deleteBlocks(this.cellBlocks.getBlockIdsFromCells(cellsInColumn));
606
- }
607
571
 
608
- this.grid.deleteColumn(gridEl, colIndex);
609
- this.syncColWidthsAfterDeleteColumn(colIndex);
610
- }
611
-
612
- /**
613
- * Get all block IDs from cells in a specific row
614
- */
615
- public getBlockIdsInRow(rowIndex: number): string[] {
616
- if (!this.element) {
617
- return [];
618
- }
619
-
620
- const rows = this.element.querySelectorAll(`[${ROW_ATTR}]`);
621
- const row = rows[rowIndex];
622
-
623
- if (!row) {
624
- return [];
625
- }
626
-
627
- return this.cellBlocks?.getBlockIdsFromCells(row.querySelectorAll(`[${CELL_ATTR}]`)) ?? [];
628
- }
629
-
630
- /**
631
- * Get all block IDs from cells in a specific column
632
- */
633
- public getBlockIdsInColumn(colIndex: number): string[] {
634
- if (!this.element) {
635
- return [];
636
- }
572
+ this.addControls?.setInteractive(!hasSelection);
573
+ this.rowColControls?.setGripsDisplay(!hasSelection);
574
+ },
575
+ onClearContent: (cells) => {
576
+ if (!this.cellBlocks) {
577
+ return;
578
+ }
637
579
 
638
- const rows = this.element.querySelectorAll(`[${ROW_ATTR}]`);
639
- const cellsInColumn: Element[] = [];
580
+ const blockIds = this.cellBlocks.getBlockIdsFromCells(cells);
640
581
 
641
- rows.forEach(row => {
642
- const cells = row.querySelectorAll(`[${CELL_ATTR}]`);
643
-
644
- if (colIndex < cells.length) {
645
- cellsInColumn.push(cells[colIndex]);
646
- }
582
+ this.cellBlocks.deleteBlocks(blockIds);
583
+ },
647
584
  });
648
-
649
- return this.cellBlocks?.getBlockIdsFromCells(cellsInColumn) ?? [];
650
585
  }
651
586
  }
587
+
588
+ export { isInsideTableCell, isRestrictedInTableCell, convertToParagraph } from './table-restrictions';