@jackuait/blok 0.10.0-beta.9 → 0.10.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (269) hide show
  1. package/dist/blok.mjs +2 -2
  2. package/dist/chunks/{blok-DDu252IK.mjs → blok-u_68bnlk.mjs} +1617 -1562
  3. package/dist/chunks/{constants-DMW9a31I.mjs → constants-VDhCUk4c.mjs} +56 -48
  4. package/dist/chunks/{i18next-loader-CwsYu0n6.mjs → i18next-loader-CDnSPae_.mjs} +1 -1
  5. package/dist/chunks/{lightweight-i18n-Cvv8CWh4.mjs → lightweight-i18n-DZmo8dAI.mjs} +1 -0
  6. package/dist/chunks/{messages-DG-4DPmP.mjs → messages-1_6UkKLS.mjs} +1 -0
  7. package/dist/{messages-CqXtJTpU.mjs → chunks/messages-4Ck88DYZ2.mjs} +1 -0
  8. package/dist/chunks/{messages-DGL1ySqb2.mjs → messages-8Ld7P_9j2.mjs} +1 -0
  9. package/dist/{messages-DLX_iBDJ.mjs → chunks/messages-BAlZjPcl.mjs} +1 -0
  10. package/dist/chunks/{messages-p1mbe__S.mjs → messages-BHMiK51R.mjs} +1 -0
  11. package/dist/chunks/{messages-Cdf0W9H02.mjs → messages-BJ-vT1SU2.mjs} +1 -0
  12. package/dist/{messages-Smt4GBbj.mjs → chunks/messages-BK8Cp2d0.mjs} +1 -0
  13. package/dist/{messages-Ci0KqX-J.mjs → chunks/messages-BKN3YVIj.mjs} +1 -0
  14. package/dist/chunks/{messages-BXM80fdr2.mjs → messages-BMD37y3q2.mjs} +1 -0
  15. package/dist/{messages-B19o-Teb.mjs → chunks/messages-BONyZroH.mjs} +1 -0
  16. package/dist/{messages-BwHs4cm1.mjs → chunks/messages-BRAoJpOu.mjs} +1 -0
  17. package/dist/{messages-DY4IqlhY.mjs → chunks/messages-BRoa9tGl.mjs} +1 -0
  18. package/dist/chunks/{messages-RInp1ytX.mjs → messages-BbEW9bQz.mjs} +1 -0
  19. package/dist/{messages-BIHc0KHY.mjs → chunks/messages-BeGZqQwz.mjs} +1 -0
  20. package/dist/{messages-CmB406HW.mjs → chunks/messages-BfAcUavP.mjs} +1 -0
  21. package/dist/chunks/{messages-Cu-Wevxs2.mjs → messages-BgM91Lxm2.mjs} +1 -0
  22. package/dist/{messages-BYNcD6uR.mjs → chunks/messages-BlxwW7M6.mjs} +1 -0
  23. package/dist/chunks/{messages-rCd0Rrw6.mjs → messages-Bz0-KNEB.mjs} +1 -0
  24. package/dist/{messages-7QD-X6XT2.mjs → chunks/messages-C0IFfhnp.mjs} +1 -0
  25. package/dist/{messages-Dl5Y2-Ia.mjs → chunks/messages-C15z2r5U.mjs} +1 -0
  26. package/dist/chunks/{messages-MxpWO1db.mjs → messages-C1S9ztpF.mjs} +1 -0
  27. package/dist/chunks/{messages-8IHf7ZP3.mjs → messages-CC_noR8y.mjs} +1 -0
  28. package/dist/chunks/{messages-COO5xmcA.mjs → messages-CD_MnBln.mjs} +1 -0
  29. package/dist/chunks/{messages-BYlSMRkd.mjs → messages-CIfUm1Oa.mjs} +1 -0
  30. package/dist/{messages-BbYq1pk-.mjs → chunks/messages-CPBN4zWc.mjs} +1 -0
  31. package/dist/{messages-DPA-mMWC2.mjs → chunks/messages-CQBo3lmL2.mjs} +1 -0
  32. package/dist/{messages-DnGJD4TL.mjs → chunks/messages-CRF7nNrO.mjs} +1 -0
  33. package/dist/{messages-D8FQWulF2.mjs → chunks/messages-CTCe595D2.mjs} +1 -0
  34. package/dist/{messages-BRZX964b2.mjs → chunks/messages-CW35K1pq.mjs} +1 -0
  35. package/dist/{messages-DnG0ef8t2.mjs → chunks/messages-CZSlfnkO2.mjs} +1 -0
  36. package/dist/chunks/{messages-iS34FHFB.mjs → messages-ChK7v1PV.mjs} +1 -0
  37. package/dist/{messages-BiUGXvYr2.mjs → chunks/messages-Clku7Cf-2.mjs} +1 -0
  38. package/dist/{messages-DIJlIqlQ2.mjs → chunks/messages-CszmHAvQ.mjs} +1 -0
  39. package/dist/chunks/{messages-DWu1r4gc2.mjs → messages-CvANwuht2.mjs} +1 -0
  40. package/dist/{messages-nUVjeh7K.mjs → chunks/messages-CxiURE2X.mjs} +1 -0
  41. package/dist/chunks/{messages-A_MkXDlG.mjs → messages-CxxyR4vY.mjs} +1 -0
  42. package/dist/{messages-ynAe7ewZ.mjs → chunks/messages-D22e9h7V2.mjs} +1 -0
  43. package/dist/{messages-DYTTu0O12.mjs → chunks/messages-D7dx_6k8.mjs} +1 -0
  44. package/dist/chunks/{messages-BA8Iv99Y2.mjs → messages-DBMaLL8b2.mjs} +1 -0
  45. package/dist/{messages-DbySKTKt2.mjs → chunks/messages-DB_-5Xln.mjs} +1 -0
  46. package/dist/{messages-CcF4y-E4.mjs → chunks/messages-DEBy3nuJ2.mjs} +1 -0
  47. package/dist/chunks/{messages-NEqrrYvE2.mjs → messages-DMoERagV2.mjs} +1 -0
  48. package/dist/chunks/{messages-Bxvi1ebN.mjs → messages-DPzHD51Y.mjs} +1 -0
  49. package/dist/chunks/{messages-jfVpL9c-2.mjs → messages-DSrdy9Nw2.mjs} +1 -0
  50. package/dist/chunks/{messages-Cmf6NhSC.mjs → messages-DTN1XGll.mjs} +1 -0
  51. package/dist/{messages-5jvKxQNu2.mjs → chunks/messages-DUeiPraX.mjs} +1 -0
  52. package/dist/chunks/{messages-G416eyjY.mjs → messages-DUr9WAkD.mjs} +1 -0
  53. package/dist/chunks/{messages-Ck81cQkn2.mjs → messages-DVr1sqfI2.mjs} +1 -0
  54. package/dist/{messages-BYmmMDrN2.mjs → chunks/messages-DjvaiALg2.mjs} +1 -0
  55. package/dist/chunks/{messages-D55HRx5O2.mjs → messages-DrfRYiM32.mjs} +1 -0
  56. package/dist/chunks/{messages-B2N4fUi72.mjs → messages-DtoId_bw2.mjs} +1 -0
  57. package/dist/{messages-Bq3F2Tp_.mjs → chunks/messages-Du2BffA7.mjs} +1 -0
  58. package/dist/{messages-CjbnogEC.mjs → chunks/messages-DxHh0O8j2.mjs} +1 -0
  59. package/dist/{messages-BECMxmfX.mjs → chunks/messages-EDMC5ukV.mjs} +1 -0
  60. package/dist/{messages-BTQPpoM42.mjs → chunks/messages-ElIGUi0O2.mjs} +1 -0
  61. package/dist/chunks/{messages-BhzzNkN-.mjs → messages-JSQjKQ8I.mjs} +1 -0
  62. package/dist/{messages-CWIXvnDf2.mjs → chunks/messages-Q7-4ZJLB2.mjs} +1 -0
  63. package/dist/chunks/{messages-DOuS1Qge.mjs → messages-QMOmwcZb.mjs} +1 -0
  64. package/dist/{messages-hWwSRF-2.mjs → chunks/messages-QilfinOn2.mjs} +1 -0
  65. package/dist/{messages-BmAn22OX.mjs → chunks/messages-a07QVz8U.mjs} +1 -0
  66. package/dist/chunks/{messages-BYxLFj7y.mjs → messages-eFd4YYzt.mjs} +1 -0
  67. package/dist/chunks/{messages-BSghd0ez.mjs → messages-euM2m3wQ.mjs} +1 -0
  68. package/dist/chunks/{messages-BVjoM7P0.mjs → messages-kGmxkeFH.mjs} +1 -0
  69. package/dist/{messages-DMr62KiO2.mjs → chunks/messages-oMc7qugU2.mjs} +1 -0
  70. package/dist/chunks/{messages-DzTk8bJ5.mjs → messages-sDdNf8O9.mjs} +1 -0
  71. package/dist/{messages-Bm0Feca1.mjs → chunks/messages-wl8YrvGG.mjs} +1 -0
  72. package/dist/chunks/{messages-BAsb5CgZ.mjs → messages-zt6zdYWh.mjs} +1 -0
  73. package/dist/chunks/{tools-XmzH2rgQ.mjs → tools-1ZFajlGN.mjs} +1619 -1307
  74. package/dist/full.mjs +3 -3
  75. package/dist/locales.mjs +68 -67
  76. package/dist/{messages-F2xRoY1w.mjs → messages-2ZWBTerL.mjs} +1 -0
  77. package/dist/{messages-Dl3Sv6Rq2.mjs → messages-53w0fPZS2.mjs} +1 -0
  78. package/dist/{chunks/messages-BDZA10kl2.mjs → messages-98nQiC7t2.mjs} +1 -0
  79. package/dist/{chunks/messages-JyvWu4rf2.mjs → messages-A96tMxeU.mjs} +1 -0
  80. package/dist/{messages-Ce6KVEbT.mjs → messages-BE_z-zrb.mjs} +1 -0
  81. package/dist/{chunks/messages-CSJ_zb3a2.mjs → messages-BK_LsgY4.mjs} +1 -0
  82. package/dist/{messages-CJTy6JZt.mjs → messages-BbJ7ZXY8.mjs} +1 -0
  83. package/dist/{chunks/messages-DMVXnAYj.mjs → messages-BcVB3osF.mjs} +1 -0
  84. package/dist/{chunks/messages-CSL-6xfb2.mjs → messages-BckDk9aq2.mjs} +1 -0
  85. package/dist/{chunks/messages-C0HvoMPb.mjs → messages-Be_2RHZD.mjs} +1 -0
  86. package/dist/{chunks/messages-Dr0Ekmbz.mjs → messages-BesJaI6A.mjs} +1 -0
  87. package/dist/{chunks/messages-D3zojZ94.mjs → messages-BiTMwiKH.mjs} +1 -0
  88. package/dist/{messages-B1ZUQagA.mjs → messages-BmH2cQHQ.mjs} +1 -0
  89. package/dist/{chunks/messages-Bfnq1xv4.mjs → messages-BrOWqNCu2.mjs} +1 -0
  90. package/dist/{messages-Dnp9N6RU2.mjs → messages-Brd5R-da2.mjs} +1 -0
  91. package/dist/{chunks/messages-DJoNVjqP.mjs → messages-C0GSBBCo2.mjs} +1 -0
  92. package/dist/{messages-Dw__BcTj.mjs → messages-C1vc5584.mjs} +1 -0
  93. package/dist/{messages-aMXpHt5X2.mjs → messages-C6ONf71u2.mjs} +1 -0
  94. package/dist/{chunks/messages-BeFqtIrc2.mjs → messages-C7lJg8fy2.mjs} +1 -0
  95. package/dist/{messages-CSUHBs4c2.mjs → messages-CRNogopy2.mjs} +1 -0
  96. package/dist/{messages-DLlc9QPw.mjs → messages-CT-Kdas6.mjs} +1 -0
  97. package/dist/{chunks/messages-DlLXpgWM2.mjs → messages-CTTmWn4Y2.mjs} +1 -0
  98. package/dist/{messages-D0aw5_0k2.mjs → messages-CZbcxlZt2.mjs} +1 -0
  99. package/dist/{chunks/messages-Bp8qin1R.mjs → messages-C_Qn9SbQ.mjs} +1 -0
  100. package/dist/{messages-96iaAUds2.mjs → messages-CdEASHDp2.mjs} +1 -0
  101. package/dist/{messages-Dy-Y_nEI.mjs → messages-CdduYw-q.mjs} +1 -0
  102. package/dist/{chunks/messages-Je5YvxiY.mjs → messages-Che99vKP.mjs} +1 -0
  103. package/dist/{messages-nlhESX9t.mjs → messages-CisR4PNV.mjs} +1 -0
  104. package/dist/{chunks/messages-BE6lHKwf.mjs → messages-ClGvlFcH2.mjs} +1 -0
  105. package/dist/{chunks/messages-FWfsxpBz.mjs → messages-CnuH-BZK2.mjs} +1 -0
  106. package/dist/{chunks/messages-aZcy0JQq2.mjs → messages-D0005ti32.mjs} +1 -0
  107. package/dist/{messages-B7ieAJBd2.mjs → messages-D05jqBIa2.mjs} +1 -0
  108. package/dist/{messages-DTh9a8mR.mjs → messages-D0lLw9KM.mjs} +1 -0
  109. package/dist/{chunks/messages-ihCjSFJI2.mjs → messages-D3rwCtKn.mjs} +1 -0
  110. package/dist/{chunks/messages-xuqyb6Ff2.mjs → messages-D6VIFnSW.mjs} +1 -0
  111. package/dist/{chunks/messages-KdawW5Na.mjs → messages-D81w6AmW.mjs} +1 -0
  112. package/dist/{chunks/messages-BUVhHx0q2.mjs → messages-DBhvm8NK.mjs} +1 -0
  113. package/dist/{chunks/messages-C7VGpihw.mjs → messages-DK6dA0O2.mjs} +1 -0
  114. package/dist/{messages-rk-A1Wa42.mjs → messages-DKHbt-7l2.mjs} +1 -0
  115. package/dist/{messages-BIoeoik5.mjs → messages-DM4Gjc9h.mjs} +1 -0
  116. package/dist/{chunks/messages-B9kmbUWV.mjs → messages-DODrhcop.mjs} +1 -0
  117. package/dist/{messages-BsycN_JI2.mjs → messages-DOGbHYv-2.mjs} +1 -0
  118. package/dist/{chunks/messages-BQYvBqm2.mjs → messages-DQORja0D.mjs} +1 -0
  119. package/dist/{chunks/messages-CVdpweyf2.mjs → messages-DSmxJWju2.mjs} +1 -0
  120. package/dist/{messages-CR_L_UtK.mjs → messages-DVL0KZE5.mjs} +1 -0
  121. package/dist/{chunks/messages-Cs81Z_Bh.mjs → messages-DYuD5-rO.mjs} +1 -0
  122. package/dist/{chunks/messages-CKBhDGI3.mjs → messages-Ddq3Ce3E2.mjs} +1 -0
  123. package/dist/{messages-xh2eOLvs.mjs → messages-DfFZ6Yj5.mjs} +1 -0
  124. package/dist/{chunks/messages-C6Mpiacw.mjs → messages-Dnd5YSWv.mjs} +1 -0
  125. package/dist/{messages-BJeGJksD.mjs → messages-Do7Xjy0n.mjs} +1 -0
  126. package/dist/{chunks/messages-C3aX3q0H.mjs → messages-DopaMHC42.mjs} +1 -0
  127. package/dist/{messages-dv19AkyJ.mjs → messages-DpJGbx3q.mjs} +1 -0
  128. package/dist/{messages-DBiVgUs2.mjs → messages-DpwMKDV0.mjs} +1 -0
  129. package/dist/{messages-j7o5rT9s.mjs → messages-Dqu4aX9s.mjs} +1 -0
  130. package/dist/{chunks/messages-BjadX8jR2.mjs → messages-E8NjqzWq2.mjs} +1 -0
  131. package/dist/{messages-aWZH50vu2.mjs → messages-JNrYldAa2.mjs} +1 -0
  132. package/dist/{chunks/messages-B4UMuyjT.mjs → messages-LMaR2_bE.mjs} +1 -0
  133. package/dist/{messages-E_ZuzGDt.mjs → messages-LYJbLq_F.mjs} +1 -0
  134. package/dist/{chunks/messages-D9N2MvQx2.mjs → messages-Q5sQeVap2.mjs} +1 -0
  135. package/dist/{chunks/messages-Bphq_Bt3.mjs → messages-Xc0KUbYl.mjs} +1 -0
  136. package/dist/{chunks/messages-DlonA3wa.mjs → messages-_PLyRfVw.mjs} +1 -0
  137. package/dist/{chunks/messages-TRUuyiFB.mjs → messages-apA6BStA.mjs} +1 -0
  138. package/dist/{chunks/messages-B0vPBsWq.mjs → messages-bkGniiaz.mjs} +1 -0
  139. package/dist/{messages-DkLU_rWm.mjs → messages-neGD3WGq.mjs} +1 -0
  140. package/dist/{messages-Ddnj2iTG2.mjs → messages-qbKjjvgd2.mjs} +1 -0
  141. package/dist/{messages-BiiongNz2.mjs → messages-qfvXgPpu2.mjs} +1 -0
  142. package/dist/{messages-Dvn35ksS.mjs → messages-uwK7ktqk.mjs} +1 -0
  143. package/dist/react.mjs +2 -2
  144. package/dist/tools.mjs +2 -2
  145. package/package.json +3 -5
  146. package/src/cli/commands/convert-gdocs/index.ts +26 -0
  147. package/src/cli/commands/convert-html/block-builder.ts +392 -0
  148. package/src/cli/commands/convert-html/id-generator.ts +11 -0
  149. package/src/cli/commands/convert-html/index.ts +23 -0
  150. package/src/cli/commands/convert-html/preprocessor.ts +422 -0
  151. package/src/cli/commands/convert-html/sanitizer.ts +93 -0
  152. package/src/cli/commands/convert-html/types.ts +15 -0
  153. package/src/cli/index.ts +56 -5
  154. package/src/components/block/index.ts +58 -10
  155. package/src/components/constants/data-attributes.ts +10 -0
  156. package/src/components/i18n/locales/am/messages.json +1 -0
  157. package/src/components/i18n/locales/ar/messages.json +1 -0
  158. package/src/components/i18n/locales/az/messages.json +1 -0
  159. package/src/components/i18n/locales/bg/messages.json +1 -0
  160. package/src/components/i18n/locales/bn/messages.json +1 -0
  161. package/src/components/i18n/locales/bs/messages.json +1 -0
  162. package/src/components/i18n/locales/cs/messages.json +1 -0
  163. package/src/components/i18n/locales/da/messages.json +1 -0
  164. package/src/components/i18n/locales/de/messages.json +1 -0
  165. package/src/components/i18n/locales/dv/messages.json +1 -0
  166. package/src/components/i18n/locales/el/messages.json +1 -0
  167. package/src/components/i18n/locales/en/messages.json +1 -0
  168. package/src/components/i18n/locales/es/messages.json +1 -0
  169. package/src/components/i18n/locales/et/messages.json +1 -0
  170. package/src/components/i18n/locales/fa/messages.json +1 -0
  171. package/src/components/i18n/locales/fi/messages.json +1 -0
  172. package/src/components/i18n/locales/fil/messages.json +1 -0
  173. package/src/components/i18n/locales/fr/messages.json +1 -0
  174. package/src/components/i18n/locales/gu/messages.json +1 -0
  175. package/src/components/i18n/locales/he/messages.json +1 -0
  176. package/src/components/i18n/locales/hi/messages.json +1 -0
  177. package/src/components/i18n/locales/hr/messages.json +1 -0
  178. package/src/components/i18n/locales/hu/messages.json +1 -0
  179. package/src/components/i18n/locales/hy/messages.json +1 -0
  180. package/src/components/i18n/locales/id/messages.json +1 -0
  181. package/src/components/i18n/locales/it/messages.json +1 -0
  182. package/src/components/i18n/locales/ja/messages.json +1 -0
  183. package/src/components/i18n/locales/ka/messages.json +1 -0
  184. package/src/components/i18n/locales/km/messages.json +1 -0
  185. package/src/components/i18n/locales/kn/messages.json +1 -0
  186. package/src/components/i18n/locales/ko/messages.json +1 -0
  187. package/src/components/i18n/locales/ku/messages.json +1 -0
  188. package/src/components/i18n/locales/lo/messages.json +1 -0
  189. package/src/components/i18n/locales/lt/messages.json +1 -0
  190. package/src/components/i18n/locales/lv/messages.json +1 -0
  191. package/src/components/i18n/locales/mk/messages.json +1 -0
  192. package/src/components/i18n/locales/ml/messages.json +1 -0
  193. package/src/components/i18n/locales/mn/messages.json +1 -0
  194. package/src/components/i18n/locales/mr/messages.json +1 -0
  195. package/src/components/i18n/locales/ms/messages.json +1 -0
  196. package/src/components/i18n/locales/my/messages.json +1 -0
  197. package/src/components/i18n/locales/ne/messages.json +1 -0
  198. package/src/components/i18n/locales/nl/messages.json +1 -0
  199. package/src/components/i18n/locales/no/messages.json +1 -0
  200. package/src/components/i18n/locales/pa/messages.json +1 -0
  201. package/src/components/i18n/locales/pl/messages.json +1 -0
  202. package/src/components/i18n/locales/ps/messages.json +1 -0
  203. package/src/components/i18n/locales/pt/messages.json +1 -0
  204. package/src/components/i18n/locales/ro/messages.json +1 -0
  205. package/src/components/i18n/locales/ru/messages.json +1 -0
  206. package/src/components/i18n/locales/sd/messages.json +1 -0
  207. package/src/components/i18n/locales/si/messages.json +1 -0
  208. package/src/components/i18n/locales/sk/messages.json +1 -0
  209. package/src/components/i18n/locales/sl/messages.json +1 -0
  210. package/src/components/i18n/locales/sq/messages.json +1 -0
  211. package/src/components/i18n/locales/sr/messages.json +1 -0
  212. package/src/components/i18n/locales/sv/messages.json +1 -0
  213. package/src/components/i18n/locales/sw/messages.json +1 -0
  214. package/src/components/i18n/locales/ta/messages.json +1 -0
  215. package/src/components/i18n/locales/te/messages.json +1 -0
  216. package/src/components/i18n/locales/th/messages.json +1 -0
  217. package/src/components/i18n/locales/tr/messages.json +1 -0
  218. package/src/components/i18n/locales/ug/messages.json +1 -0
  219. package/src/components/i18n/locales/uk/messages.json +1 -0
  220. package/src/components/i18n/locales/ur/messages.json +1 -0
  221. package/src/components/i18n/locales/vi/messages.json +1 -0
  222. package/src/components/i18n/locales/yi/messages.json +1 -0
  223. package/src/components/i18n/locales/zh/messages.json +1 -0
  224. package/src/components/icons/index.ts +29 -18
  225. package/src/components/modules/blockEvents/composers/keyboardNavigation.ts +18 -0
  226. package/src/components/modules/blockManager/hierarchy.ts +4 -1
  227. package/src/components/modules/readonly.ts +46 -0
  228. package/src/components/modules/rectangleSelection.ts +25 -5
  229. package/src/components/modules/toolbar/index.ts +96 -19
  230. package/src/components/modules/toolbar/positioning.ts +11 -2
  231. package/src/components/modules/toolbar/styles.ts +0 -2
  232. package/src/components/modules/uiControllers/controllers/blockHover.ts +44 -1
  233. package/src/components/tools/block.ts +10 -0
  234. package/src/components/utils/placeholder.ts +9 -2
  235. package/src/components/utils/popover/components/popover-item/popover-item-default/popover-item-default.ts +11 -0
  236. package/src/components/utils/popover/popover-abstract.ts +7 -0
  237. package/src/styles/main.css +16 -0
  238. package/src/tools/callout/constants.ts +2 -1
  239. package/src/tools/callout/dom-builder.ts +13 -1
  240. package/src/tools/callout/index.ts +21 -7
  241. package/src/tools/code/constants.ts +28 -8
  242. package/src/tools/code/dom-builder.ts +133 -64
  243. package/src/tools/code/index.ts +280 -91
  244. package/src/tools/code/language-detector.ts +118 -0
  245. package/src/tools/divider/index.ts +5 -0
  246. package/src/tools/header/index.ts +47 -1
  247. package/src/tools/list/dom-builder.ts +3 -1
  248. package/src/tools/list/index.ts +55 -3
  249. package/src/tools/list/list-helpers.ts +2 -2
  250. package/src/tools/nested-blocks.ts +25 -0
  251. package/src/tools/paragraph/index.ts +47 -6
  252. package/src/tools/quote/index.ts +43 -8
  253. package/src/tools/stub/index.ts +10 -0
  254. package/src/tools/table/index.ts +238 -6
  255. package/src/tools/table/table-add-controls.ts +37 -5
  256. package/src/tools/table/table-cell-blocks.ts +57 -18
  257. package/src/tools/table/table-core.ts +2 -0
  258. package/src/tools/table/table-corner-drag.ts +247 -0
  259. package/src/tools/table/table-operations.ts +41 -14
  260. package/src/tools/toggle/dom-builder.ts +1 -0
  261. package/src/tools/toggle/index.ts +25 -0
  262. package/src/tools/toggle/toggle-lifecycle.ts +5 -4
  263. package/src/types-internal/jsdom.d.ts +9 -0
  264. package/types/tools/adapters/block-tool-adapter.d.ts +6 -0
  265. package/types/tools/block-tool.d.ts +20 -0
  266. package/types/utils/popover/popover-item.d.ts +6 -0
  267. package/bin/blok.mjs +0 -10
  268. package/dist/cli.mjs +0 -37
  269. package/src/tools/code/language-picker.ts +0 -241
@@ -111,6 +111,12 @@ export class Header implements BlockTool {
111
111
  */
112
112
  private readOnly: boolean;
113
113
 
114
+ /**
115
+ * Cleanup function for the placeholder, returned by setupPlaceholder().
116
+ * Stored so we can tear down the placeholder when entering read-only mode.
117
+ */
118
+ private placeholderCleanup: (() => void) | null = null;
119
+
114
120
  /**
115
121
  * Tool's settings passed from Editor
116
122
  */
@@ -302,6 +308,45 @@ export class Header implements BlockTool {
302
308
  this._element.removeEventListener('keydown', this.handleKeyDown);
303
309
  }
304
310
 
311
+ /**
312
+ * Toggle read-only mode in-place without re-rendering the DOM element.
313
+ * Manages contentEditable, keydown listener (for toggle headings),
314
+ * placeholder setup/teardown, and body placeholder click handler.
315
+ *
316
+ * @param state - true to enter read-only mode, false to exit
317
+ */
318
+ public setReadOnly(state: boolean): void {
319
+ if (!this._element) {
320
+ return;
321
+ }
322
+
323
+ this.readOnly = state;
324
+
325
+ if (state) {
326
+ this._element.contentEditable = 'false';
327
+
328
+ if (this._data.isToggleable) {
329
+ this._element.removeEventListener('keydown', this.handleKeyDown);
330
+ }
331
+
332
+ if (this.placeholderCleanup) {
333
+ this.placeholderCleanup();
334
+ this.placeholderCleanup = null;
335
+ }
336
+ } else {
337
+ this._element.contentEditable = 'true';
338
+
339
+ if (this._data.isToggleable) {
340
+ this._element.addEventListener('keydown', this.handleKeyDown);
341
+ }
342
+
343
+ const translatedName = this.api.i18n.t(this.currentLevel.nameKey);
344
+ const placeholderText = this.resolvePlaceholderText(translatedName);
345
+
346
+ this.placeholderCleanup = setupPlaceholder(this._element, placeholderText);
347
+ }
348
+ }
349
+
305
350
  /**
306
351
  * Expand the toggle heading (no-op if not toggleable or already expanded).
307
352
  * Can be called externally via block.call('expand').
@@ -679,7 +724,7 @@ export class Header implements BlockTool {
679
724
  const placeholderText = this.resolvePlaceholderText(translatedName);
680
725
 
681
726
  if (!this.readOnly) {
682
- setupPlaceholder(tag, placeholderText);
727
+ this.placeholderCleanup = setupPlaceholder(tag, placeholderText);
683
728
  } else {
684
729
  tag.setAttribute('data-placeholder', placeholderText);
685
730
  }
@@ -750,6 +795,7 @@ export class Header implements BlockTool {
750
795
  // pl-8 (32px) matches the heading's left padding so children align with the title text start.
751
796
  childContainer.className = 'pl-8';
752
797
  childContainer.setAttribute(TOGGLE_ATTR.toggleChildren, '');
798
+ childContainer.setAttribute(DATA_ATTR.nestedBlocks, '');
753
799
  // Block DOM mutations inside the children container from triggering the header tool's
754
800
  // didMutated → syncBlockDataToYjs path (same rationale as the toggle list tool).
755
801
  childContainer.setAttribute('data-blok-mutation-free', 'true');
@@ -111,7 +111,9 @@ export const buildListItem = (context: DOMBuilderContext): BuildResult => {
111
111
  // Extract element references for the result
112
112
  const markerElement = itemContent.querySelector<HTMLElement>('[data-list-marker]');
113
113
  const checkboxElement = itemContent.querySelector<HTMLInputElement>('input[type="checkbox"]');
114
- const contentElement = itemContent.querySelector<HTMLElement>('[contenteditable]');
114
+ const contentElement = data.style === 'checklist'
115
+ ? itemContent.querySelector<HTMLElement>(`[data-blok-testid="${LIST_TEST_IDS.checklistContent}"]`)
116
+ : itemContent.querySelector<HTMLElement>(`[data-blok-testid="${LIST_TEST_IDS.contentContainer}"]`);
115
117
 
116
118
  return {
117
119
  wrapper,
@@ -52,6 +52,8 @@ export class ListItem implements BlockTool {
52
52
  private depthValidator: ListDepthValidator;
53
53
  private markerCalculator: ListMarkerCalculator;
54
54
  private markerManager: OrderedMarkerManager | null;
55
+ private placeholderCleanup: (() => void) | null = null;
56
+ private boundHandleKeyDown: ((event: KeyboardEvent) => void) | null = null;
55
57
 
56
58
  private blockId?: string;
57
59
 
@@ -120,16 +122,24 @@ export class ListItem implements BlockTool {
120
122
  if (this.readOnly) {
121
123
  return;
122
124
  }
123
- setupPlaceholder(element, this.placeholder);
125
+ this.placeholderCleanup = setupPlaceholder(element, this.placeholder);
124
126
  }
125
127
 
126
128
  public render(): HTMLElement {
129
+ if (this._element) {
130
+ return this._element;
131
+ }
132
+
127
133
  const blockIndex = this.blockId
128
134
  ? this.api.blocks.getBlockIndex(this.blockId) ?? this.api.blocks.getCurrentBlockIndex()
129
135
  : this.api.blocks.getCurrentBlockIndex();
130
136
  const depth = this._data.depth ?? 0;
131
137
  const markerDepth = this.markerCalculator.getVisualDepth(blockIndex, depth);
132
138
 
139
+ if (!this.boundHandleKeyDown) {
140
+ this.boundHandleKeyDown = this.handleKeyDown.bind(this);
141
+ }
142
+
133
143
  this._element = renderListItem({
134
144
  data: this._data,
135
145
  readOnly: this.readOnly,
@@ -145,12 +155,54 @@ export class ListItem implements BlockTool {
145
155
  content.classList.toggle('opacity-60', checked);
146
156
  }
147
157
  },
148
- keydownHandler: this.readOnly ? undefined : this.handleKeyDown.bind(this),
158
+ keydownHandler: this.readOnly ? undefined : this.boundHandleKeyDown,
149
159
  });
150
160
 
151
161
  return this._element;
152
162
  }
153
163
 
164
+ public setReadOnly(state: boolean): void {
165
+ if (!this._element) {
166
+ return;
167
+ }
168
+
169
+ this.readOnly = state;
170
+
171
+ const content = this.getContentElement();
172
+
173
+ // Toggle contentEditable on content container
174
+ if (content) {
175
+ content.contentEditable = state ? 'false' : 'true';
176
+ }
177
+
178
+ // Toggle checkbox disabled state for checklists
179
+ const checkbox = this._element.querySelector<HTMLInputElement>('input[type="checkbox"]');
180
+
181
+ if (checkbox) {
182
+ checkbox.disabled = state;
183
+ }
184
+
185
+ // Toggle keydown handler and placeholder
186
+ if (state) {
187
+ if (this.boundHandleKeyDown) {
188
+ this._element.removeEventListener('keydown', this.boundHandleKeyDown);
189
+ }
190
+
191
+ if (this.placeholderCleanup) {
192
+ this.placeholderCleanup();
193
+ this.placeholderCleanup = null;
194
+ }
195
+ } else {
196
+ if (this.boundHandleKeyDown) {
197
+ this._element.addEventListener('keydown', this.boundHandleKeyDown);
198
+ }
199
+
200
+ if (content) {
201
+ this.placeholderCleanup = setupPlaceholder(content, this.placeholder);
202
+ }
203
+ }
204
+ }
205
+
154
206
  public rendered(): void {
155
207
  this.updateMarkersAfterPositionChange();
156
208
  }
@@ -408,7 +460,7 @@ export class ListItem implements BlockTool {
408
460
  content.classList.toggle('opacity-60', checked);
409
461
  }
410
462
  },
411
- keydownHandler: this.readOnly ? undefined : this.handleKeyDown.bind(this),
463
+ keydownHandler: this.readOnly ? undefined : this.boundHandleKeyDown ?? undefined,
412
464
  });
413
465
 
414
466
  if (newElement) {
@@ -19,8 +19,8 @@ export const getContentElement = (
19
19
  if (!element) return null;
20
20
 
21
21
  if (style === 'checklist') {
22
- const contentEditable = element.querySelector('[contenteditable]');
23
- return contentEditable instanceof HTMLElement ? contentEditable : null;
22
+ const checklistContent = element.querySelector('[data-blok-testid="list-checklist-content"]');
23
+ return checklistContent instanceof HTMLElement ? checklistContent : null;
24
24
  }
25
25
 
26
26
  const contentContainer = element.querySelector('[data-blok-testid="list-content-container"]');
@@ -0,0 +1,25 @@
1
+ import { DATA_ATTR } from '../components/constants/data-attributes';
2
+
3
+ /**
4
+ * Mount child block holders into a container, skipping children that are
5
+ * already in place or claimed by another nested-blocks container.
6
+ *
7
+ * Used by toggle, header, and callout tools to reconcile child holders
8
+ * during the `rendered()` lifecycle hook.
9
+ */
10
+ export const mountChildBlocks = (
11
+ container: HTMLElement,
12
+ children: { holder: HTMLElement }[],
13
+ ): void => {
14
+ for (const child of children) {
15
+ if (child.holder.parentElement === container) {
16
+ continue;
17
+ }
18
+
19
+ if (child.holder.closest(`[${DATA_ATTR.nestedBlocks}]`)) {
20
+ continue;
21
+ }
22
+
23
+ container.appendChild(child.holder);
24
+ }
25
+ };
@@ -19,7 +19,7 @@ import type {
19
19
  import { DATA_ATTR } from '../../components/constants';
20
20
  import { IconText } from '../../components/icons';
21
21
  import { stripFakeBackgroundElements } from '../../components/utils';
22
- import { PLACEHOLDER_EMPTY_EDITOR_CLASSES, PLACEHOLDER_FOCUS_ONLY_CLASSES, setupPlaceholder } from '../../components/utils/placeholder';
22
+ import { isContentEmpty, PLACEHOLDER_EMPTY_EDITOR_CLASSES, PLACEHOLDER_FOCUS_ONLY_CLASSES, setupPlaceholder } from '../../components/utils/placeholder';
23
23
  import { twMerge } from '../../components/utils/tw';
24
24
 
25
25
  /**
@@ -117,6 +117,11 @@ export class Paragraph implements BlockTool {
117
117
  */
118
118
  private readOnly: boolean;
119
119
 
120
+ /**
121
+ * Cleanup function for placeholder behavior, returned by setupPlaceholder
122
+ */
123
+ private placeholderCleanup: (() => void) | null = null;
124
+
120
125
  /**
121
126
  * Placeholder for Paragraph Tool
122
127
  */
@@ -157,9 +162,7 @@ export class Paragraph implements BlockTool {
157
162
  this.api = api;
158
163
  this.readOnly = readOnly;
159
164
 
160
- if (!this.readOnly) {
161
- this.onKeyUp = this.onKeyUp.bind(this);
162
- }
165
+ this.onKeyUp = this.onKeyUp.bind(this);
163
166
 
164
167
  this._placeholder = config?.placeholder ?? Paragraph.DEFAULT_PLACEHOLDER;
165
168
  this._data = data ?? { text: '' };
@@ -263,7 +266,7 @@ export class Paragraph implements BlockTool {
263
266
  if (!this.readOnly) {
264
267
  div.contentEditable = 'true';
265
268
  div.addEventListener('keyup', this.onKeyUp);
266
- setupPlaceholder(div, this.api.i18n.t(this._placeholder), 'data-blok-placeholder-active');
269
+ this.placeholderCleanup = setupPlaceholder(div, this.api.i18n.t(this._placeholder), 'data-blok-placeholder-active');
267
270
  }
268
271
 
269
272
  return div;
@@ -275,11 +278,49 @@ export class Paragraph implements BlockTool {
275
278
  * @returns HTMLDivElement
276
279
  */
277
280
  public render(): HTMLDivElement {
278
- this._element = this.drawView();
281
+ if (!this._element) {
282
+ this._element = this.drawView();
283
+ }
279
284
 
280
285
  return this._element;
281
286
  }
282
287
 
288
+ /**
289
+ * Toggle read-only mode in-place without re-rendering the DOM element.
290
+ * Manages contentEditable, keyup listener, placeholder, and empty-content <br>.
291
+ *
292
+ * @param state - true to enter read-only mode, false to exit
293
+ */
294
+ public setReadOnly(state: boolean): void {
295
+ if (!this._element) {
296
+ return;
297
+ }
298
+
299
+ this.readOnly = state;
300
+
301
+ if (state) {
302
+ this._element.contentEditable = 'false';
303
+ this._element.removeEventListener('keyup', this.onKeyUp);
304
+
305
+ if (this.placeholderCleanup) {
306
+ this.placeholderCleanup();
307
+ this.placeholderCleanup = null;
308
+ }
309
+
310
+ if (isContentEmpty(this._element)) {
311
+ this._element.innerHTML = '<br>';
312
+ }
313
+ } else {
314
+ this._element.contentEditable = 'true';
315
+ this._element.addEventListener('keyup', this.onKeyUp);
316
+ this.placeholderCleanup = setupPlaceholder(this._element, this.api.i18n.t(this._placeholder), 'data-blok-placeholder-active');
317
+
318
+ if (this._element.innerHTML === '<br>') {
319
+ this._element.innerHTML = '';
320
+ }
321
+ }
322
+ }
323
+
283
324
  /**
284
325
  * Method that specified how to merge two Text blocks.
285
326
  * Called by Editor by backspace at the beginning of the Block
@@ -13,7 +13,7 @@ import type { MenuConfig } from '../../../types/tools/menu-config';
13
13
  import { DATA_ATTR } from '../../components/constants';
14
14
  import { IconQuote } from '../../components/icons';
15
15
  import { stripFakeBackgroundElements } from '../../components/utils';
16
- import { PLACEHOLDER_FOCUS_ONLY_CLASSES, setupPlaceholder } from '../../components/utils/placeholder';
16
+ import { isContentEmpty, PLACEHOLDER_FOCUS_ONLY_CLASSES, setupPlaceholder } from '../../components/utils/placeholder';
17
17
  import { twMerge } from '../../components/utils/tw';
18
18
 
19
19
  export interface QuoteData extends BlockToolData {
@@ -40,6 +40,7 @@ const LARGE_CLASS = 'text-[1.2em]';
40
40
  export class Quote implements BlockTool {
41
41
  private api: API;
42
42
  private readOnly: boolean;
43
+ private placeholderCleanup: (() => void) | null = null;
43
44
  private _data: QuoteData;
44
45
  private _element: HTMLQuoteElement | null = null;
45
46
 
@@ -51,9 +52,7 @@ export class Quote implements BlockTool {
51
52
  size: data?.size ?? 'default',
52
53
  };
53
54
 
54
- if (!this.readOnly) {
55
- this.onKeyUp = this.onKeyUp.bind(this);
56
- }
55
+ this.onKeyUp = this.onKeyUp.bind(this);
57
56
  }
58
57
 
59
58
  public onKeyUp(e: KeyboardEvent): void {
@@ -70,7 +69,7 @@ export class Quote implements BlockTool {
70
69
  }
71
70
  }
72
71
 
73
- public render(): HTMLQuoteElement {
72
+ private drawView(): HTMLQuoteElement {
74
73
  const el = document.createElement('blockquote');
75
74
 
76
75
  el.className = twMerge(
@@ -91,14 +90,50 @@ export class Quote implements BlockTool {
91
90
  if (!this.readOnly) {
92
91
  el.contentEditable = 'true';
93
92
  el.addEventListener('keyup', this.onKeyUp);
94
- setupPlaceholder(el, this.api.i18n.t(DEFAULT_PLACEHOLDER), 'data-blok-placeholder-active');
93
+ this.placeholderCleanup = setupPlaceholder(el, this.api.i18n.t(DEFAULT_PLACEHOLDER), 'data-blok-placeholder-active');
95
94
  }
96
95
 
97
- this._element = el;
98
-
99
96
  return el;
100
97
  }
101
98
 
99
+ public render(): HTMLQuoteElement {
100
+ if (!this._element) {
101
+ this._element = this.drawView();
102
+ }
103
+
104
+ return this._element;
105
+ }
106
+
107
+ public setReadOnly(state: boolean): void {
108
+ if (!this._element) {
109
+ return;
110
+ }
111
+
112
+ this.readOnly = state;
113
+
114
+ if (state) {
115
+ this._element.contentEditable = 'false';
116
+ this._element.removeEventListener('keyup', this.onKeyUp);
117
+
118
+ if (this.placeholderCleanup) {
119
+ this.placeholderCleanup();
120
+ this.placeholderCleanup = null;
121
+ }
122
+
123
+ if (isContentEmpty(this._element)) {
124
+ this._element.innerHTML = '<br>';
125
+ }
126
+ } else {
127
+ this._element.contentEditable = 'true';
128
+ this._element.addEventListener('keyup', this.onKeyUp);
129
+ this.placeholderCleanup = setupPlaceholder(this._element, this.api.i18n.t(DEFAULT_PLACEHOLDER), 'data-blok-placeholder-active');
130
+
131
+ if (this._element.innerHTML === '<br>') {
132
+ this._element.innerHTML = '';
133
+ }
134
+ }
135
+ }
136
+
102
137
  public save(blockContent: HTMLQuoteElement): QuoteData {
103
138
  return {
104
139
  text: stripFakeBackgroundElements(blockContent.innerHTML),
@@ -73,6 +73,16 @@ export class Stub implements BlockTool {
73
73
  return this.savedData;
74
74
  }
75
75
 
76
+ /**
77
+ * Toggle read-only mode in-place.
78
+ * Stub has no interactive elements, so this is intentionally a no-op.
79
+ *
80
+ * @param _state - read-only state (unused)
81
+ */
82
+ public setReadOnly(_state: boolean): void {
83
+ // no-op: stub blocks have no editable content
84
+ }
85
+
76
86
  /**
77
87
  * Create Tool html markup
78
88
  * @returns {HTMLElement}