@jackuait/blok 0.13.2 → 0.14.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 (397) hide show
  1. package/dist/blok.cjs +1 -1
  2. package/dist/blok.iife.js +30 -30
  3. package/dist/blok.mjs +2 -2
  4. package/dist/chunks/blok-DbYIZS7_.cjs +17 -0
  5. package/dist/chunks/{blok-Du6vYONn.mjs → blok-DuYqYpF7.mjs} +2738 -2322
  6. package/dist/chunks/{constants-DUuYY64n.mjs → constants-DMVxzgHf.mjs} +390 -299
  7. package/dist/chunks/constants-DPty7Dc7.cjs +457 -0
  8. package/dist/chunks/{i18next-loader-GIrBCFrC.mjs → i18next-loader-BEWWek8j.mjs} +1 -1
  9. package/dist/chunks/{i18next-loader-DC1uN-wc.cjs → i18next-loader-BRLYf-CW.cjs} +1 -1
  10. package/dist/chunks/{lightweight-i18n-DF9Pupws.mjs → lightweight-i18n-GbzxWVgl.mjs} +9 -0
  11. package/dist/chunks/lightweight-i18n-lNYVKCfj.cjs +1 -0
  12. package/dist/chunks/messages-085GG-gT.cjs +1 -0
  13. package/dist/{messages-3j4yi-DF.mjs → chunks/messages-46QopBh4.mjs} +9 -0
  14. package/dist/chunks/messages-5kQujjf1.cjs +1 -0
  15. package/dist/chunks/{messages-CTWXEx_o.mjs → messages-6r3Lrqpf.mjs} +9 -0
  16. package/dist/chunks/messages-8vjbwhvK.cjs +1 -0
  17. package/dist/chunks/messages-ACbZDExx.cjs +1 -0
  18. package/dist/chunks/messages-B05XREvI.cjs +1 -0
  19. package/dist/chunks/{messages-CQg2_vmm.mjs → messages-B0y97-C9.mjs} +9 -0
  20. package/dist/chunks/{messages-ZHNvKiIX.mjs → messages-B26pkAIj.mjs} +9 -0
  21. package/dist/chunks/messages-B2J7kDKI.cjs +1 -0
  22. package/dist/chunks/messages-B3jMjjFG.cjs +1 -0
  23. package/dist/chunks/messages-B4_c-uS0.cjs +1 -0
  24. package/dist/chunks/messages-B6zoVYEd.cjs +1 -0
  25. package/dist/chunks/{messages-DI9Ifrgt.mjs → messages-B73uch0z.mjs} +9 -0
  26. package/dist/chunks/{messages-AgmrT2Id.mjs → messages-B74xK8Ux.mjs} +9 -0
  27. package/dist/chunks/messages-B7efcz_S2.cjs +1 -0
  28. package/dist/chunks/{messages-sqdfYuVj2.mjs → messages-B9u3UJRu2.mjs} +9 -0
  29. package/dist/chunks/messages-BB9huoLU.cjs +1 -0
  30. package/dist/{messages-Cx7sqvx02.mjs → chunks/messages-BEzCtzW3.mjs} +9 -0
  31. package/dist/chunks/messages-BGQdk2zV2.cjs +1 -0
  32. package/dist/chunks/messages-BGmUrVtN2.cjs +1 -0
  33. package/dist/chunks/messages-BH-3FR4b2.cjs +1 -0
  34. package/dist/chunks/{messages-BZ4d5yNH.mjs → messages-BHqAQF6C.mjs} +9 -0
  35. package/dist/{messages-DzkZ434Z.mjs → chunks/messages-BI_-Ub99.mjs} +9 -0
  36. package/dist/chunks/messages-BNa6_BYq2.cjs +1 -0
  37. package/dist/chunks/{messages-BvupGuDw2.mjs → messages-BOMNOs8T2.mjs} +9 -0
  38. package/dist/chunks/{messages-fSeXd6-z.mjs → messages-BPYPnKHy.mjs} +9 -0
  39. package/dist/{messages-B3PWaMcw.mjs → chunks/messages-BQmUOeft.mjs} +9 -0
  40. package/dist/chunks/messages-BRfutnCs.cjs +1 -0
  41. package/dist/chunks/messages-BT_0dgL1.cjs +1 -0
  42. package/dist/chunks/{messages-BWGqOZ9J.mjs → messages-BWSXW4jk.mjs} +9 -0
  43. package/dist/chunks/messages-BWpKvkND2.cjs +1 -0
  44. package/dist/chunks/messages-BY6gCAsA2.cjs +1 -0
  45. package/dist/{messages-BDwU9rYR2.mjs → chunks/messages-BbfZo0kw2.mjs} +9 -0
  46. package/dist/{messages-gQ5PFa2t2.mjs → chunks/messages-BfqzgRP72.mjs} +9 -0
  47. package/dist/chunks/messages-Bk2Xs7_v.cjs +1 -0
  48. package/dist/{messages-CmN2OfuB.mjs → chunks/messages-BmkavfpK.mjs} +9 -0
  49. package/dist/chunks/{messages-B1k4DgVe.mjs → messages-BmzMikmq.mjs} +9 -0
  50. package/dist/chunks/messages-BniEGAW32.cjs +1 -0
  51. package/dist/chunks/{messages-BP77P9ER.mjs → messages-BplwYBhA.mjs} +9 -0
  52. package/dist/chunks/{messages-B1xgsCNQ.cjs → messages-BqJ-xe8R.cjs} +1 -1
  53. package/dist/chunks/messages-Bry43U_U.cjs +1 -0
  54. package/dist/{messages-DFfhoDWZ2.mjs → chunks/messages-BuzGjYKw.mjs} +9 -0
  55. package/dist/chunks/messages-ByT63R7v2.cjs +1 -0
  56. package/dist/{messages-C_gdsU952.mjs → chunks/messages-C0S7KViA2.mjs} +9 -0
  57. package/dist/chunks/{messages-DzY53I67.mjs → messages-C0Tt7Odx.mjs} +9 -0
  58. package/dist/{messages-B8Tq9Txy.mjs → chunks/messages-C3A1iLjY.mjs} +9 -0
  59. package/dist/chunks/{messages-B6You-RA.mjs → messages-C3gh1rpr.mjs} +9 -0
  60. package/dist/chunks/{messages-CXxz5HYQ.mjs → messages-C7JE4SUS.mjs} +9 -0
  61. package/dist/chunks/messages-C9IWDnCh2.cjs +1 -0
  62. package/dist/chunks/messages-CBc3S61g2.cjs +1 -0
  63. package/dist/chunks/{messages-DefZ3ihx.mjs → messages-CHpkDOiI.mjs} +9 -0
  64. package/dist/{messages-BcD7xtJA.mjs → chunks/messages-CImQCp-z2.mjs} +9 -0
  65. package/dist/chunks/messages-CJ--z80t2.cjs +1 -0
  66. package/dist/chunks/messages-CNH8YFuv.cjs +1 -0
  67. package/dist/chunks/{messages-bjSJwsXK2.mjs → messages-CQ2KWTbV2.mjs} +9 -0
  68. package/dist/{messages-C8RMjnBe.mjs → chunks/messages-CWAukiLC.mjs} +9 -0
  69. package/dist/{messages-B3oFjWq3.mjs → chunks/messages-C_BUhMkZ.mjs} +9 -0
  70. package/dist/chunks/{messages-BvuEffoe.mjs → messages-CcBT1o1B.mjs} +9 -0
  71. package/dist/chunks/messages-CdqejEof.cjs +1 -0
  72. package/dist/chunks/messages-Chdejshy2.cjs +1 -0
  73. package/dist/{messages-D-rvoUSJ.mjs → chunks/messages-CijMg_B_.mjs} +9 -0
  74. package/dist/{messages-JKXCsFKZ.mjs → chunks/messages-Ciz80Z2u2.mjs} +9 -0
  75. package/dist/{messages-Dq2WEsEu.mjs → chunks/messages-CjuGKMoT.mjs} +9 -0
  76. package/dist/chunks/{messages-BxKobpJ22.mjs → messages-ClOfUECP2.mjs} +9 -0
  77. package/dist/chunks/messages-CrF-Q_ML.cjs +1 -0
  78. package/dist/chunks/messages-Cww_rBCM.cjs +1 -0
  79. package/dist/chunks/messages-CxPVYl2H2.cjs +1 -0
  80. package/dist/chunks/{messages-BA2sVGrR2.mjs → messages-Cyiqo_dk2.mjs} +9 -0
  81. package/dist/{messages-D788KtGe.mjs → chunks/messages-D-u_SWhb.mjs} +9 -0
  82. package/dist/chunks/messages-D0H-D5FQ2.cjs +1 -0
  83. package/dist/chunks/messages-D195RH3A.cjs +1 -0
  84. package/dist/chunks/{messages-Dd4nzvLj2.mjs → messages-D5-DG-_u2.mjs} +9 -0
  85. package/dist/chunks/messages-D6kDQgDP2.cjs +1 -0
  86. package/dist/{messages-CAGQtm7T.mjs → chunks/messages-D8-hiQgf.mjs} +9 -0
  87. package/dist/{messages-ftPYsH6d2.mjs → chunks/messages-D8nb9CKr2.mjs} +9 -0
  88. package/dist/{messages-DPqFBtJR.mjs → chunks/messages-DAd5yWtH2.mjs} +9 -0
  89. package/dist/chunks/messages-DAdsFLpE.cjs +1 -0
  90. package/dist/chunks/messages-DCUsbiUQ.cjs +1 -0
  91. package/dist/{messages-AycxTjmw.mjs → chunks/messages-DCVZaAT9.mjs} +9 -0
  92. package/dist/chunks/messages-DHXttezt2.cjs +1 -0
  93. package/dist/chunks/messages-DIgxCixa.cjs +1 -0
  94. package/dist/chunks/messages-DJ0Wr-Bt2.cjs +1 -0
  95. package/dist/chunks/messages-DJBdlmxR.cjs +1 -0
  96. package/dist/chunks/{messages-5AxgjKgf2.mjs → messages-DJm-uLwr2.mjs} +9 -0
  97. package/dist/chunks/{messages-BVarbXYD2.mjs → messages-DKF4qWhw2.mjs} +9 -0
  98. package/dist/chunks/messages-DLAWSVlE.cjs +1 -0
  99. package/dist/{messages-Bj03XD-02.mjs → chunks/messages-DLI8m6z_2.mjs} +9 -0
  100. package/dist/{messages-CTzO11jz.mjs → chunks/messages-DNiWBVQr.mjs} +9 -0
  101. package/dist/chunks/messages-DNsgR3ZH.cjs +1 -0
  102. package/dist/{messages-CgaGkQi32.mjs → chunks/messages-DPI5-TrO2.mjs} +9 -0
  103. package/dist/chunks/{messages-CyCl8la6.mjs → messages-DQ1z_srP.mjs} +9 -0
  104. package/dist/chunks/{messages-C4bHKGnB2.mjs → messages-DSxYO-_j2.mjs} +9 -0
  105. package/dist/chunks/messages-DTrrEqf02.cjs +1 -0
  106. package/dist/chunks/{messages-D7YPlNAK.mjs → messages-DYLfoakZ.mjs} +9 -0
  107. package/dist/chunks/messages-DZCWq8nI2.cjs +1 -0
  108. package/dist/{messages-PQVh93mt.mjs → chunks/messages-D_JT9POv.mjs} +9 -0
  109. package/dist/chunks/{messages-Uc3Uc2862.mjs → messages-DaTniq4w2.mjs} +9 -0
  110. package/dist/{messages-DiL61awK.mjs → chunks/messages-De2tXe0o.mjs} +9 -0
  111. package/dist/chunks/{messages-l5xHQb_m.mjs → messages-DiwyN3uU.mjs} +9 -0
  112. package/dist/chunks/messages-DkQGwmom.cjs +1 -0
  113. package/dist/chunks/{messages-B6t1xShv.mjs → messages-Dl-C7Pdf.mjs} +9 -0
  114. package/dist/chunks/{messages-bSVgJ1cu.mjs → messages-DlDyYt5x.mjs} +9 -0
  115. package/dist/chunks/messages-Dmhwr_Ow2.cjs +1 -0
  116. package/dist/chunks/messages-DrQQ1Hky.cjs +1 -0
  117. package/dist/chunks/messages-DtQ_pCWn.cjs +1 -0
  118. package/dist/{messages-uy3FE24_2.mjs → chunks/messages-Du-inLpi2.mjs} +9 -0
  119. package/dist/{messages-DqXJJPx9.mjs → chunks/messages-Duu9LiF32.mjs} +9 -0
  120. package/dist/chunks/messages-DxCc14pu2.cjs +1 -0
  121. package/dist/chunks/{messages-DNqFlfOd.mjs → messages-Dz3cVqxu.mjs} +9 -0
  122. package/dist/chunks/messages-EJkYSgsP.cjs +1 -0
  123. package/dist/chunks/messages-F3QeKduK.cjs +1 -0
  124. package/dist/chunks/messages-HfCZ1oPV.cjs +1 -0
  125. package/dist/chunks/{messages-BVZONUH9.mjs → messages-Ji3WDjrp.mjs} +9 -0
  126. package/dist/chunks/messages-MTnjMh07.cjs +1 -0
  127. package/dist/{messages-DL7JAwpC.mjs → chunks/messages-NU3n_1t9.mjs} +9 -0
  128. package/dist/chunks/messages-NpCBoXqi.cjs +1 -0
  129. package/dist/chunks/messages-PMZIH3mH.cjs +1 -0
  130. package/dist/{messages-7fwJIrld2.mjs → chunks/messages-TFu4tdzc2.mjs} +9 -0
  131. package/dist/{messages-BSHFypGE2.mjs → chunks/messages-Ti4ZdnqM2.mjs} +9 -0
  132. package/dist/chunks/messages-UOTfsDv3.cjs +1 -0
  133. package/dist/chunks/messages-WDBEGpNu.cjs +1 -0
  134. package/dist/chunks/messages-Zg6PFQ87.cjs +1 -0
  135. package/dist/chunks/messages-bdVhFVzt2.cjs +1 -0
  136. package/dist/chunks/messages-dnnjc_oR2.cjs +1 -0
  137. package/dist/{messages-BmWP4vpV2.mjs → chunks/messages-fI_5bRwV2.mjs} +9 -0
  138. package/dist/{messages-CIjSE2_O2.mjs → chunks/messages-g80Luov_2.mjs} +9 -0
  139. package/dist/chunks/messages-hlzAtKI5.cjs +1 -0
  140. package/dist/chunks/messages-kuh4lSUE2.cjs +1 -0
  141. package/dist/chunks/messages-m20Eebmt2.cjs +1 -0
  142. package/dist/chunks/messages-o1__8Rul.cjs +1 -0
  143. package/dist/chunks/messages-pBYvH88_.cjs +1 -0
  144. package/dist/chunks/{messages-CMRjQYxi2.mjs → messages-u1hpTCvK2.mjs} +9 -0
  145. package/dist/chunks/{messages-BoCUgrkI.mjs → messages-vq5ZvFTF.mjs} +9 -0
  146. package/dist/chunks/tools-BuCT1-J0.cjs +116 -0
  147. package/dist/chunks/{tools-Tt-NXbRZ.mjs → tools-BwY9bTlg.mjs} +1599 -1460
  148. package/dist/full.cjs +1 -1
  149. package/dist/full.mjs +13 -13
  150. package/dist/locales.mjs +76 -67
  151. package/dist/{chunks/messages-DHdoaaFq2.mjs → messages-2hSOMnir2.mjs} +9 -0
  152. package/dist/{chunks/messages-DlcI-0Sy.mjs → messages-3VCxXECx.mjs} +9 -0
  153. package/dist/{messages-CxX23Jsk2.mjs → messages-8xGEIh_m2.mjs} +9 -0
  154. package/dist/{chunks/messages-DmErSGPk2.mjs → messages-B-QcHnuI2.mjs} +9 -0
  155. package/dist/{messages-BKCuCTFM.mjs → messages-B8zoeMf9.mjs} +9 -0
  156. package/dist/{chunks/messages-BmdkDNYv.mjs → messages-B9CF0GcE.mjs} +9 -0
  157. package/dist/{messages-1ufJbdRv2.mjs → messages-B9W0pRCr2.mjs} +9 -0
  158. package/dist/{messages-DQik3_xv2.mjs → messages-BFM2ljkf2.mjs} +9 -0
  159. package/dist/{chunks/messages-BNxTGhHu.mjs → messages-BLm4FSbz2.mjs} +9 -0
  160. package/dist/{chunks/messages-GHsufIGi2.mjs → messages-BLpeYPKv2.mjs} +9 -0
  161. package/dist/{messages-D_WzyzUt.mjs → messages-BM73sjxy.mjs} +9 -0
  162. package/dist/{messages-CX8egsiA2.mjs → messages-BOpqKi6Y2.mjs} +9 -0
  163. package/dist/{chunks/messages-eyGOcbhV.mjs → messages-BUGdUeTK.mjs} +9 -0
  164. package/dist/{chunks/messages-DhZwMl9x2.mjs → messages-BZm7MzSJ2.mjs} +9 -0
  165. package/dist/{messages-C31VIrlL.mjs → messages-BtBhP1sv.mjs} +9 -0
  166. package/dist/{messages-D1Fjr4OK2.mjs → messages-BthFu3bN2.mjs} +9 -0
  167. package/dist/{chunks/messages-COMdnGQV2.mjs → messages-BurjwjCQ2.mjs} +9 -0
  168. package/dist/{messages-DTkd9ND8.mjs → messages-ByIHkus-.mjs} +9 -0
  169. package/dist/{messages-C9GFRcVj.mjs → messages-ByVKFMH3.mjs} +9 -0
  170. package/dist/{chunks/messages-B5CFhyI8.mjs → messages-C6FDRqcf.mjs} +9 -0
  171. package/dist/{chunks/messages-OSIAf0Wk2.mjs → messages-C9dJ_N542.mjs} +9 -0
  172. package/dist/{messages-CRR1VRO6.mjs → messages-CCw8aJgW.mjs} +9 -0
  173. package/dist/{chunks/messages-AtUsRyWK2.mjs → messages-CO3NEwf22.mjs} +9 -0
  174. package/dist/{chunks/messages-CcboYTP8.mjs → messages-CPB2xkpC.mjs} +9 -0
  175. package/dist/{messages-CITYhXUz.mjs → messages-CPDsEORY.mjs} +9 -0
  176. package/dist/{chunks/messages-B2zrJyAc2.mjs → messages-CYyPOGy7.mjs} +9 -0
  177. package/dist/{chunks/messages-C03LZxma.mjs → messages-CZAODRjY.mjs} +9 -0
  178. package/dist/{messages-Duk7VVeY.mjs → messages-C_rns7Ku.mjs} +9 -0
  179. package/dist/{chunks/messages-CdWXgq_r.mjs → messages-CaUUIQvU.mjs} +9 -0
  180. package/dist/{messages-Cp0fjsey.mjs → messages-Cc-A7Vip.mjs} +9 -0
  181. package/dist/{chunks/messages-B7KbtBAE.mjs → messages-Ccf81JsG.mjs} +9 -0
  182. package/dist/{chunks/messages-rEsI_fAk.mjs → messages-CerTDuSC.mjs} +9 -0
  183. package/dist/{messages-BkTBwYet.mjs → messages-CgmDwRRE.mjs} +9 -0
  184. package/dist/{chunks/messages-DsyO86r3.mjs → messages-Cn3PWtLp.mjs} +9 -0
  185. package/dist/{chunks/messages-CWTFEPbA2.mjs → messages-Cu1rTEkB.mjs} +9 -0
  186. package/dist/{messages-oIa8wahx.mjs → messages-CxEHfUNH.mjs} +9 -0
  187. package/dist/{messages-C_mN4lx0.mjs → messages-D1B41i8X.mjs} +9 -0
  188. package/dist/{messages-NVepzgE3.mjs → messages-D6954zcl.mjs} +9 -0
  189. package/dist/{messages-C2TRJroV2.mjs → messages-DBwWssfL2.mjs} +9 -0
  190. package/dist/{messages-Cdgz3urh.mjs → messages-DFHRMYke.mjs} +9 -0
  191. package/dist/{messages-DXCyNanc2.mjs → messages-DJVrq0Xa2.mjs} +9 -0
  192. package/dist/{chunks/messages-OYoN_rp1.mjs → messages-DMJz28kt.mjs} +9 -0
  193. package/dist/{chunks/messages-B_U10evN2.mjs → messages-DOnOpXFJ2.mjs} +9 -0
  194. package/dist/{messages-5USazVPA2.mjs → messages-DR1Tf-Kj2.mjs} +9 -0
  195. package/dist/{chunks/messages-C4sIqArW2.mjs → messages-DSUXwuzH2.mjs} +9 -0
  196. package/dist/{chunks/messages-DGHTTk1S2.mjs → messages-DTNO7tw1.mjs} +9 -0
  197. package/dist/{messages-Ddz6eH0-2.mjs → messages-DWBtyom42.mjs} +9 -0
  198. package/dist/{messages-DKsyrVp5.mjs → messages-DZQALZIU.mjs} +9 -0
  199. package/dist/{chunks/messages-V8K7-1l2.mjs → messages-D_i86vbQ.mjs} +9 -0
  200. package/dist/{chunks/messages-BmiN0JGP2.mjs → messages-Da1VKvvf2.mjs} +9 -0
  201. package/dist/{messages-D5qgCWmB2.mjs → messages-Ddimgqvp2.mjs} +9 -0
  202. package/dist/{chunks/messages-MPF8o3EP.mjs → messages-DdmXBLUC.mjs} +9 -0
  203. package/dist/{messages-D4U4wkYM.mjs → messages-Devcsnrv.mjs} +9 -0
  204. package/dist/{chunks/messages-DiGsu5XN.mjs → messages-DhS-j4Hp.mjs} +9 -0
  205. package/dist/{messages-BGzpwNrz.mjs → messages-DrRVvVPI.mjs} +9 -0
  206. package/dist/{chunks/messages-Z9mDYT3w.mjs → messages-Ds4gQbVR2.mjs} +9 -0
  207. package/dist/{chunks/messages-vQ5kblO8.mjs → messages-DxkB7LL6.mjs} +9 -0
  208. package/dist/{chunks/messages-LTkIIrSe2.mjs → messages-GgHHrLBU2.mjs} +9 -0
  209. package/dist/{messages-CntTlSE22.mjs → messages-IycPaZe22.mjs} +9 -0
  210. package/dist/{messages-BtDz-sw92.mjs → messages-ST8f_nDx2.mjs} +9 -0
  211. package/dist/{messages-CgVEHCQ-.mjs → messages-SV8lf6F0.mjs} +9 -0
  212. package/dist/{messages-Bt4TLGth.mjs → messages-lVrQmsky.mjs} +9 -0
  213. package/dist/{messages-rpO1POP02.mjs → messages-lcoIGSX82.mjs} +9 -0
  214. package/dist/{chunks/messages-BuYnNUtU2.mjs → messages-mqRVfUUq.mjs} +9 -0
  215. package/dist/{chunks/messages-C24IC_eR.mjs → messages-qWFvoPY1.mjs} +9 -0
  216. package/dist/{messages-CacRpQpm.mjs → messages-yte1QPX5.mjs} +9 -0
  217. package/dist/{messages-DNlrcG5Z.mjs → messages-zyiti_A8.mjs} +9 -0
  218. package/dist/react.cjs +1 -1
  219. package/dist/react.mjs +1 -1
  220. package/dist/tools.cjs +1 -1
  221. package/dist/tools.mjs +3 -3
  222. package/package.json +1 -1
  223. package/src/components/blocks.ts +30 -7
  224. package/src/components/i18n/locales/am/messages.json +9 -0
  225. package/src/components/i18n/locales/ar/messages.json +9 -0
  226. package/src/components/i18n/locales/az/messages.json +9 -0
  227. package/src/components/i18n/locales/bg/messages.json +9 -0
  228. package/src/components/i18n/locales/bn/messages.json +9 -0
  229. package/src/components/i18n/locales/bs/messages.json +9 -0
  230. package/src/components/i18n/locales/cs/messages.json +9 -0
  231. package/src/components/i18n/locales/da/messages.json +9 -0
  232. package/src/components/i18n/locales/de/messages.json +9 -0
  233. package/src/components/i18n/locales/dv/messages.json +9 -0
  234. package/src/components/i18n/locales/el/messages.json +9 -0
  235. package/src/components/i18n/locales/en/messages.json +9 -0
  236. package/src/components/i18n/locales/es/messages.json +9 -0
  237. package/src/components/i18n/locales/et/messages.json +9 -0
  238. package/src/components/i18n/locales/fa/messages.json +9 -0
  239. package/src/components/i18n/locales/fi/messages.json +9 -0
  240. package/src/components/i18n/locales/fil/messages.json +9 -0
  241. package/src/components/i18n/locales/fr/messages.json +9 -0
  242. package/src/components/i18n/locales/gu/messages.json +9 -0
  243. package/src/components/i18n/locales/he/messages.json +9 -0
  244. package/src/components/i18n/locales/hi/messages.json +9 -0
  245. package/src/components/i18n/locales/hr/messages.json +9 -0
  246. package/src/components/i18n/locales/hu/messages.json +9 -0
  247. package/src/components/i18n/locales/hy/messages.json +9 -0
  248. package/src/components/i18n/locales/id/messages.json +9 -0
  249. package/src/components/i18n/locales/it/messages.json +9 -0
  250. package/src/components/i18n/locales/ja/messages.json +9 -0
  251. package/src/components/i18n/locales/ka/messages.json +9 -0
  252. package/src/components/i18n/locales/km/messages.json +9 -0
  253. package/src/components/i18n/locales/kn/messages.json +9 -0
  254. package/src/components/i18n/locales/ko/messages.json +9 -0
  255. package/src/components/i18n/locales/ku/messages.json +9 -0
  256. package/src/components/i18n/locales/lo/messages.json +9 -0
  257. package/src/components/i18n/locales/lt/messages.json +9 -0
  258. package/src/components/i18n/locales/lv/messages.json +9 -0
  259. package/src/components/i18n/locales/mk/messages.json +9 -0
  260. package/src/components/i18n/locales/ml/messages.json +9 -0
  261. package/src/components/i18n/locales/mn/messages.json +9 -0
  262. package/src/components/i18n/locales/mr/messages.json +9 -0
  263. package/src/components/i18n/locales/ms/messages.json +9 -0
  264. package/src/components/i18n/locales/my/messages.json +9 -0
  265. package/src/components/i18n/locales/ne/messages.json +9 -0
  266. package/src/components/i18n/locales/nl/messages.json +9 -0
  267. package/src/components/i18n/locales/no/messages.json +9 -0
  268. package/src/components/i18n/locales/pa/messages.json +9 -0
  269. package/src/components/i18n/locales/pl/messages.json +9 -0
  270. package/src/components/i18n/locales/ps/messages.json +9 -0
  271. package/src/components/i18n/locales/pt/messages.json +9 -0
  272. package/src/components/i18n/locales/ro/messages.json +9 -0
  273. package/src/components/i18n/locales/ru/messages.json +9 -0
  274. package/src/components/i18n/locales/sd/messages.json +9 -0
  275. package/src/components/i18n/locales/si/messages.json +9 -0
  276. package/src/components/i18n/locales/sk/messages.json +9 -0
  277. package/src/components/i18n/locales/sl/messages.json +9 -0
  278. package/src/components/i18n/locales/sq/messages.json +9 -0
  279. package/src/components/i18n/locales/sr/messages.json +9 -0
  280. package/src/components/i18n/locales/sv/messages.json +9 -0
  281. package/src/components/i18n/locales/sw/messages.json +9 -0
  282. package/src/components/i18n/locales/ta/messages.json +9 -0
  283. package/src/components/i18n/locales/te/messages.json +9 -0
  284. package/src/components/i18n/locales/th/messages.json +9 -0
  285. package/src/components/i18n/locales/tr/messages.json +9 -0
  286. package/src/components/i18n/locales/ug/messages.json +9 -0
  287. package/src/components/i18n/locales/uk/messages.json +9 -0
  288. package/src/components/i18n/locales/ur/messages.json +9 -0
  289. package/src/components/i18n/locales/vi/messages.json +9 -0
  290. package/src/components/i18n/locales/yi/messages.json +9 -0
  291. package/src/components/i18n/locales/zh/messages.json +9 -0
  292. package/src/components/icons/index.ts +24 -0
  293. package/src/components/modules/blockEvents/composers/keyboardNavigation.ts +67 -6
  294. package/src/components/modules/blockManager/hierarchy.ts +150 -8
  295. package/src/components/modules/blockManager/operations.ts +207 -8
  296. package/src/components/modules/blockManager/yjs-sync.ts +36 -1
  297. package/src/components/modules/caret.ts +205 -31
  298. package/src/components/modules/drag/DragController.ts +219 -2
  299. package/src/components/modules/drag/a11y/DragA11y.ts +9 -1
  300. package/src/components/modules/drag/state/DragStateMachine.ts +1 -1
  301. package/src/components/modules/drag/target/DropTargetDetector.ts +513 -3
  302. package/src/components/modules/drag/utils/drag.constants.ts +9 -0
  303. package/src/components/modules/toolbar/blockSettings.ts +75 -5
  304. package/src/components/modules/toolbar/index.ts +12 -1
  305. package/src/components/modules/tools.ts +57 -1
  306. package/src/components/modules/uiControllers/controllers/blockHover.ts +24 -2
  307. package/src/components/modules/uiControllers/controllers/selection.ts +50 -0
  308. package/src/components/utils/blocks.ts +21 -7
  309. package/src/styles/colors.css +3 -0
  310. package/src/styles/columns.css +105 -0
  311. package/src/styles/main.css +48 -3
  312. package/src/styles/popover-animation.css +8 -0
  313. package/src/tools/column/index.ts +189 -0
  314. package/src/tools/column/types.ts +26 -0
  315. package/src/tools/column-drop.ts +273 -0
  316. package/src/tools/column-list/index.ts +142 -0
  317. package/src/tools/column-list/types.ts +17 -0
  318. package/src/tools/columns/index.ts +21 -0
  319. package/src/tools/columns-shared.ts +343 -0
  320. package/src/tools/divider/index.ts +1 -0
  321. package/src/tools/index.ts +5 -0
  322. package/src/tools/nested-blocks.ts +23 -2
  323. package/src/tools/table/table-restrictions.ts +1 -1
  324. package/types/tools/column-list.d.ts +15 -0
  325. package/types/tools/column.d.ts +13 -0
  326. package/types/tools/tool.d.ts +12 -0
  327. package/types/tools-entry.d.ts +15 -0
  328. package/dist/chunks/blok-Xu27QC2G.cjs +0 -17
  329. package/dist/chunks/constants-DDTVRO2H.cjs +0 -457
  330. package/dist/chunks/lightweight-i18n-Bbl1cNYK.cjs +0 -1
  331. package/dist/chunks/messages-1qYt6EhZ2.cjs +0 -1
  332. package/dist/chunks/messages-2fxvN3Nb.cjs +0 -1
  333. package/dist/chunks/messages-B1Vs2HmR.cjs +0 -1
  334. package/dist/chunks/messages-B780gS332.cjs +0 -1
  335. package/dist/chunks/messages-B7T5Notn.cjs +0 -1
  336. package/dist/chunks/messages-BE9aZQ1Q.cjs +0 -1
  337. package/dist/chunks/messages-BIQpTYfm.cjs +0 -1
  338. package/dist/chunks/messages-BIRvUJ0t.cjs +0 -1
  339. package/dist/chunks/messages-BIodfkjv.cjs +0 -1
  340. package/dist/chunks/messages-BL-zBcuM.cjs +0 -1
  341. package/dist/chunks/messages-BQr0zpmu2.cjs +0 -1
  342. package/dist/chunks/messages-BTHi6rVW2.cjs +0 -1
  343. package/dist/chunks/messages-BZOAdcmO2.cjs +0 -1
  344. package/dist/chunks/messages-BbsGeVs_2.cjs +0 -1
  345. package/dist/chunks/messages-Bc1NYJVS.cjs +0 -1
  346. package/dist/chunks/messages-BdORNG8X.cjs +0 -1
  347. package/dist/chunks/messages-Bg2kheTv.cjs +0 -1
  348. package/dist/chunks/messages-Bj1eQtQw.cjs +0 -1
  349. package/dist/chunks/messages-BkJJCHNK.cjs +0 -1
  350. package/dist/chunks/messages-BkdGQfIX.cjs +0 -1
  351. package/dist/chunks/messages-BkgsB-cj2.cjs +0 -1
  352. package/dist/chunks/messages-Bn0vGFEP.cjs +0 -1
  353. package/dist/chunks/messages-BoIUXwWe.cjs +0 -1
  354. package/dist/chunks/messages-BpDEh8rW.cjs +0 -1
  355. package/dist/chunks/messages-BwknPZJ8.cjs +0 -1
  356. package/dist/chunks/messages-ByicRCge2.cjs +0 -1
  357. package/dist/chunks/messages-C2oBmyTn.cjs +0 -1
  358. package/dist/chunks/messages-C9wBMmxr2.cjs +0 -1
  359. package/dist/chunks/messages-CDK5-8vW.cjs +0 -1
  360. package/dist/chunks/messages-CKHbPcfh.cjs +0 -1
  361. package/dist/chunks/messages-CNFfwTfw.cjs +0 -1
  362. package/dist/chunks/messages-CNiuofck2.cjs +0 -1
  363. package/dist/chunks/messages-CWszAGkF.cjs +0 -1
  364. package/dist/chunks/messages-CWzQNagc2.cjs +0 -1
  365. package/dist/chunks/messages-CYf1gv722.cjs +0 -1
  366. package/dist/chunks/messages-CfcCwbQo.cjs +0 -1
  367. package/dist/chunks/messages-CkvqOnAR.cjs +0 -1
  368. package/dist/chunks/messages-Cnrug7nz2.cjs +0 -1
  369. package/dist/chunks/messages-Cr51zCHy.cjs +0 -1
  370. package/dist/chunks/messages-CsLvvl2F2.cjs +0 -1
  371. package/dist/chunks/messages-CuO-Rx4g.cjs +0 -1
  372. package/dist/chunks/messages-Cv4I3k1W2.cjs +0 -1
  373. package/dist/chunks/messages-CwHRv6g8.cjs +0 -1
  374. package/dist/chunks/messages-CzXnHfGb2.cjs +0 -1
  375. package/dist/chunks/messages-D2QxLx1a.cjs +0 -1
  376. package/dist/chunks/messages-D4LUPpX_.cjs +0 -1
  377. package/dist/chunks/messages-DJFL-bxd2.cjs +0 -1
  378. package/dist/chunks/messages-DLEeNpMi2.cjs +0 -1
  379. package/dist/chunks/messages-DTNU_cq0.cjs +0 -1
  380. package/dist/chunks/messages-DVKsYqpJ.cjs +0 -1
  381. package/dist/chunks/messages-DXlfz-nC.cjs +0 -1
  382. package/dist/chunks/messages-DbA_Zja3.cjs +0 -1
  383. package/dist/chunks/messages-Dc2TTEx_2.cjs +0 -1
  384. package/dist/chunks/messages-DeDMMmRC.cjs +0 -1
  385. package/dist/chunks/messages-DlQNXqzr.cjs +0 -1
  386. package/dist/chunks/messages-DqMqZLcn.cjs +0 -1
  387. package/dist/chunks/messages-DqqDuEE22.cjs +0 -1
  388. package/dist/chunks/messages-DzppdmWe.cjs +0 -1
  389. package/dist/chunks/messages-HzLF-BQL2.cjs +0 -1
  390. package/dist/chunks/messages-Jb9n97oP2.cjs +0 -1
  391. package/dist/chunks/messages-K_vSdSoF2.cjs +0 -1
  392. package/dist/chunks/messages-Nh7wrRdm.cjs +0 -1
  393. package/dist/chunks/messages-QHS-Ydg_.cjs +0 -1
  394. package/dist/chunks/messages-SpiG5vT-2.cjs +0 -1
  395. package/dist/chunks/messages-XFaJzdhP2.cjs +0 -1
  396. package/dist/chunks/messages-y03BGg692.cjs +0 -1
  397. package/dist/chunks/tools-DOuVjow8.cjs +0 -116
@@ -1197,7 +1197,18 @@ export class Toolbar extends Module<ToolbarNodes> {
1197
1197
  const currentBlock = this.Blok.BlockManager.currentBlock;
1198
1198
 
1199
1199
  if (currentBlock && currentBlock.inputs.length > 0) {
1200
- this.Blok.Caret.setToBlock(currentBlock, this.Blok.Caret.positions.END);
1200
+ // If a freshly inserted tool already placed the caret inside its own
1201
+ // subtree (e.g. a column_list focusing its FIRST column), keep it.
1202
+ // Restore focus only when it has actually fallen outside the block —
1203
+ // to document.body on non-keyboard close paths — which is what this
1204
+ // branch defends against. Restoring to END would otherwise jump a
1205
+ // multi-input container like columns to its LAST input.
1206
+ const active = document.activeElement;
1207
+ const focusAlreadyInBlock = active instanceof Node && currentBlock.holder.contains(active);
1208
+
1209
+ if (!focusAlreadyInBlock) {
1210
+ this.Blok.Caret.setToBlock(currentBlock, this.Blok.Caret.positions.END);
1211
+ }
1201
1212
  }
1202
1213
  });
1203
1214
 
@@ -148,7 +148,9 @@ export class Tools extends Module {
148
148
  */
149
149
  const userTools = this.config.tools ?? {};
150
150
 
151
- this.config.tools = deepMerge({}, this.internalTools, userTools);
151
+ this.config.tools = this.expandToolGroups(
152
+ deepMerge({}, this.internalTools, userTools)
153
+ );
152
154
 
153
155
  this.validateTools();
154
156
 
@@ -284,6 +286,60 @@ export class Tools extends Module {
284
286
  };
285
287
  }
286
288
 
289
+ /**
290
+ * Expand any registered tool "group" into the real block tools it provides.
291
+ *
292
+ * A tool class may expose a static `provides` map of `{ blockType: ToolClass }`.
293
+ * Registering such a class under any key (e.g. `columns: Columns`) registers
294
+ * the provided block tools (`column_list`, `column`) instead, and drops the
295
+ * group handle key — no block ever has the handle's type. Settings on the
296
+ * group entry forward to each provided sub-tool.
297
+ *
298
+ * Explicit entries always win over group-provided entries regardless of order.
299
+ * If two groups provide the same block type, the first-registered group wins.
300
+ */
301
+ private expandToolGroups(
302
+ tools: Record<string, ToolConstructable | ToolSettings>
303
+ ): Record<string, ToolConstructable | ToolSettings> {
304
+ const out: Record<string, ToolConstructable | ToolSettings> = {};
305
+
306
+ for (const name in tools) {
307
+ if (!Object.prototype.hasOwnProperty.call(tools, name)) {
308
+ continue;
309
+ }
310
+
311
+ const entry = tools[name];
312
+ const toolClass = isObject(entry) ? (entry as ToolSettings).class : entry;
313
+ const provides = (toolClass as { provides?: Record<string, ToolConstructable> } | undefined)?.provides;
314
+
315
+ if (!provides) {
316
+ out[name] = entry;
317
+ continue;
318
+ }
319
+
320
+ const groupSettings: Record<string, unknown> = isObject(entry)
321
+ ? Object.fromEntries(
322
+ // never forward the class ref or the internal-tool flag to sub-tools
323
+ Object.entries(entry).filter(([key]) => key !== 'class' && key !== 'isInternal')
324
+ )
325
+ : {};
326
+
327
+ const hasGroupSettings = Object.keys(groupSettings).length > 0;
328
+
329
+ Object.entries(provides).forEach(([blockType, providedClass]) => {
330
+ // Never clobber an entry already present — explicit registration wins.
331
+ if (blockType in out) {
332
+ return;
333
+ }
334
+
335
+ out[blockType] = hasGroupSettings ? { class: providedClass, ...groupSettings } : providedClass;
336
+ });
337
+ // The group handle key (`name`) is intentionally dropped: not a block type.
338
+ }
339
+
340
+ return out;
341
+ }
342
+
287
343
  /**
288
344
  * Tool prepare method success callback
289
345
  * @param {object} data - append tool to available list
@@ -137,6 +137,15 @@ export class BlockHoverController extends Controller {
137
137
  return;
138
138
  }
139
139
 
140
+ /**
141
+ * Columns are structural containers, not selectable blocks. Skip the
142
+ * event so neither the column nor its column_list ever gets a toolbar —
143
+ * only the blocks inside a column are selectable (Notion-style).
144
+ */
145
+ if (BlockHoverController.isColumnContainer(block)) {
146
+ return;
147
+ }
148
+
140
149
  /**
141
150
  * For multi-block selection, still emit 'block-hovered' event so toolbar can follow the hovered block.
142
151
  * The toolbar module will handle the logic of whether to move or not.
@@ -189,6 +198,17 @@ export class BlockHoverController extends Controller {
189
198
  });
190
199
  }
191
200
 
201
+ /**
202
+ * Columns are structural containers, not independent blocks: neither a
203
+ * `column` nor its `column_list` may own a drag handle, settings menu, or
204
+ * "convert to" option. Only the blocks inside a column are selectable.
205
+ * @param block - a hovered or candidate block
206
+ * @returns true when the block is a column layout container
207
+ */
208
+ private static isColumnContainer(block: Block): boolean {
209
+ return block.name === 'column' || block.name === 'column_list';
210
+ }
211
+
192
212
  /**
193
213
  * Emits a BlockHovered event for the nearest block, but only if the cursor
194
214
  * is within the extended hover zone (HOVER_ZONE_SIZE px from content edges).
@@ -198,7 +218,8 @@ export class BlockHoverController extends Controller {
198
218
  private emitNearestBlockHoveredInZone(clientX: number, clientY: number): void {
199
219
  const blocks = this.Blok.BlockManager.blocks;
200
220
  const topLevelBlocks = blocks.filter(block =>
201
- block.holder.closest('[data-blok-table-cell-blocks], [data-blok-toggle-children]') === null
221
+ !BlockHoverController.isColumnContainer(block)
222
+ && block.holder.closest('[data-blok-table-cell-blocks], [data-blok-toggle-children]') === null
202
223
  );
203
224
 
204
225
  if (topLevelBlocks.length === 0) {
@@ -246,7 +267,8 @@ export class BlockHoverController extends Controller {
246
267
  * This matches the direct-hit path which also resolves nested blocks to their parent.
247
268
  */
248
269
  const topLevelBlocks = blocks.filter(block =>
249
- block.holder.closest('[data-blok-table-cell-blocks], [data-blok-toggle-children]') === null
270
+ !BlockHoverController.isColumnContainer(block)
271
+ && block.holder.closest('[data-blok-table-cell-blocks], [data-blok-toggle-children]') === null
250
272
  );
251
273
 
252
274
  if (topLevelBlocks.length === 0) {
@@ -33,11 +33,51 @@ export class SelectionController extends Controller {
33
33
  this.wrapperElement = element;
34
34
  }
35
35
 
36
+ /**
37
+ * Whether a pointer is currently pressed (an in-progress drag selection).
38
+ * While true, the inline toolbar is kept hidden so it doesn't pop up mid-drag;
39
+ * it appears the moment the pointer is released.
40
+ */
41
+ private isPointerDown = false;
42
+
43
+ /**
44
+ * Remember that a drag may be starting so the inline toolbar stays hidden
45
+ * until the pointer is released.
46
+ */
47
+ private handlePointerDown = (): void => {
48
+ this.isPointerDown = true;
49
+ };
50
+
51
+ /**
52
+ * Show the inline toolbar the moment a pointer drag-selection is released.
53
+ *
54
+ * While the pointer is down the debounced selectionchange handler suppresses
55
+ * the toolbar (see handleSelectionChange), so it never flickers mid-drag.
56
+ * Clearing the flag and running the handler synchronously here makes the
57
+ * toolbar appear instantly on release.
58
+ */
59
+ private handlePointerUp = (): void => {
60
+ this.isPointerDown = false;
61
+ this.handleSelectionChange();
62
+ };
63
+
64
+ /**
65
+ * A cancelled pointer interaction (e.g. the gesture is taken over by the
66
+ * browser) never fires pointerup, so clear the flag to avoid stranding the
67
+ * toolbar in a permanently-suppressed state.
68
+ */
69
+ private handlePointerCancel = (): void => {
70
+ this.isPointerDown = false;
71
+ };
72
+
36
73
  /**
37
74
  * Enable selection change listeners
38
75
  */
39
76
  public override enable(): void {
40
77
  this.listeners.on(document, 'selectionchange', this.selectionChangeDebounced);
78
+ this.listeners.on(document, 'pointerdown', this.handlePointerDown);
79
+ this.listeners.on(document, 'pointerup', this.handlePointerUp);
80
+ this.listeners.on(document, 'pointercancel', this.handlePointerCancel);
41
81
  }
42
82
 
43
83
  /**
@@ -137,6 +177,16 @@ export class SelectionController extends Controller {
137
177
  this.Blok.BlockManager.setCurrentBlockByChildNode(focusedElement);
138
178
  }
139
179
 
180
+ /**
181
+ * While the pointer is held down the user is still dragging out the
182
+ * selection. Keep the toolbar hidden until they release (handlePointerUp),
183
+ * so it appears in one motion at the final selection rather than popping up
184
+ * mid-drag.
185
+ */
186
+ if (this.isPointerDown) {
187
+ return;
188
+ }
189
+
140
190
  void this.Blok.InlineToolbar.tryToShow(true);
141
191
  }
142
192
 
@@ -191,20 +191,34 @@ export const getConvertibleToolsForBlocks = async (blocks: BlockAPI[], allBlockT
191
191
  }
192
192
 
193
193
  /**
194
- * Check that all blocks have export conversion config
194
+ * Only the "roots" of the selection constrain the conversion targets:
195
+ *
196
+ * - A block nested under another selected block rides with its container
197
+ * (e.g. the contents of a selected column_list) and must NOT be converted
198
+ * on its own — so it's ignored here.
199
+ * - A block whose tool has no «export» rule (e.g. container blocks like
200
+ * column_list/column) cannot convert and is left untouched — ignored too,
201
+ * NOT used to suppress every target for the whole selection.
195
202
  */
196
- for (const block of blocks) {
203
+ const selectedIds = new Set(blocks.map((block) => block.id));
204
+ const convertibleBlocks = blocks.filter((block) => {
205
+ if (block.parentId !== null && selectedIds.has(block.parentId)) {
206
+ return false;
207
+ }
208
+
197
209
  const blockTool = allBlockTools.find((tool) => tool.name === block.name);
198
210
 
199
- if (blockTool !== undefined && !isToolConvertable(blockTool, 'export')) {
200
- return [];
201
- }
211
+ return blockTool === undefined || isToolConvertable(blockTool, 'export');
212
+ });
213
+
214
+ if (convertibleBlocks.length === 0) {
215
+ return [];
202
216
  }
203
217
 
204
218
  /**
205
- * Get the set of tool names that all blocks currently use
219
+ * Get the set of tool names that the convertible blocks currently use
206
220
  */
207
- const blockToolNames = new Set(blocks.map((block) => block.name));
221
+ const blockToolNames = new Set(convertibleBlocks.map((block) => block.name));
208
222
 
209
223
  /**
210
224
  * Filter tools that have import conversion config and valid toolbox
@@ -241,6 +241,9 @@
241
241
  /* Small UI surfaces that can't reach a var via Tailwind arbitrary syntax. */
242
242
  --blok-button-focus-bg-hover: #fbfcfe;
243
243
  --blok-dnd-drop-indicator-bg: #d4e3fc;
244
+ /* Drop-line geometry shared by the horizontal (top/bottom) and vertical
245
+ (left/right) indicators so both bars render identically. */
246
+ --blok-dnd-drop-indicator-thickness: 6px;
244
247
 
245
248
  /* Direct-usage surface tokens extracted in B1.6. Light-theme values match
246
249
  the dark overrides below; they are rarely applied outside the dark theme. */
@@ -0,0 +1,105 @@
1
+ /*
2
+ * Columns layout tool — responsive stacking.
3
+ *
4
+ * The flex children of a column_list are the block-holder wrappers
5
+ * ([data-blok-element]), not the [data-blok-column] elements the Column tool
6
+ * renders. Target the holders directly so flex-wrap forces vertical stacking
7
+ * on narrow viewports and restores side-by-side distribution above the
8
+ * project's mobile breakpoint (651px, matching the `not-mobile` variant).
9
+ */
10
+ [data-blok-columns] > [data-blok-element] {
11
+ flex-basis: 100%;
12
+ flex-shrink: 0;
13
+ }
14
+
15
+ @media (min-width: 651px) {
16
+ [data-blok-columns] > [data-blok-element] {
17
+ flex-basis: 0;
18
+ flex-shrink: 1;
19
+ }
20
+ }
21
+
22
+ /*
23
+ * New-column entry animation (Notion-style): a freshly added column slides in by
24
+ * growing its flex share from 0 while fading in, so the existing columns reflow
25
+ * to make room. The trigger attribute is set on the column holder when the
26
+ * column is created and stripped on animationend — see playColumnEnterAnimation.
27
+ */
28
+ @keyframes blok-column-enter {
29
+ from {
30
+ flex-grow: 0;
31
+ opacity: 0;
32
+ }
33
+
34
+ to {
35
+ flex-grow: 1;
36
+ opacity: 1;
37
+ }
38
+ }
39
+
40
+ [data-blok-columns] > [data-blok-element][data-blok-column-enter] {
41
+ animation: blok-column-enter 200ms ease-out;
42
+ }
43
+
44
+ @media (prefers-reduced-motion: reduce) {
45
+ [data-blok-columns] > [data-blok-element][data-blok-column-enter] {
46
+ animation: none;
47
+ }
48
+ }
49
+
50
+ /*
51
+ * Resize separator — a fixed-width flex item that forms the gutter between two
52
+ * columns. The visible bar is hidden until the gutter is hovered or dragged,
53
+ * matching Notion. The bar is wider than its hit feel via the full-width
54
+ * col-resize cursor zone.
55
+ */
56
+ [data-blok-column-resizer] {
57
+ flex: 0 0 1.5rem;
58
+ align-self: stretch;
59
+ position: relative;
60
+ cursor: col-resize;
61
+ touch-action: none;
62
+ }
63
+
64
+ [data-blok-column-resizer]::before {
65
+ content: '';
66
+ position: absolute;
67
+ inset-block: 0.25rem;
68
+ left: 50%;
69
+ width: 3px;
70
+ border-radius: 9999px;
71
+ /* Theme-aware so the handle stays visible on both light and dark surfaces. */
72
+ background-color: var(--blok-border-strong);
73
+ transform: translateX(-50%);
74
+ opacity: 0;
75
+ transition: opacity 120ms ease, background-color 120ms ease;
76
+ }
77
+
78
+ [data-blok-column-resizer]:hover::before,
79
+ [data-blok-column-resizer][data-dragging]::before {
80
+ opacity: 1;
81
+ }
82
+
83
+ /* Accent the handle while actively dragging for clear feedback. */
84
+ [data-blok-column-resizer][data-dragging]::before {
85
+ background-color: var(--blok-active-icon);
86
+ }
87
+
88
+ /*
89
+ * While a block is being dragged, suppress the gutter handle entirely. Otherwise
90
+ * the cursor passing over a separator triggers :hover and reveals the gray handle
91
+ * bar right next to the blue drop indicator — reading as two drop targets in the
92
+ * gutter. Higher specificity than the :hover rule (three attributes), so it wins
93
+ * without !important. A real resize drag sets [data-dragging] on the resizer, not
94
+ * data-blok-dragging on the interface, so this never hides the active resize.
95
+ */
96
+ [data-blok-interface][data-blok-dragging="true"] [data-blok-column-resizer]::before {
97
+ opacity: 0;
98
+ }
99
+
100
+ /* Columns stack vertically below the breakpoint, so the gutter handle hides. */
101
+ @media (max-width: 650px) {
102
+ [data-blok-column-resizer] {
103
+ display: none;
104
+ }
105
+ }
@@ -170,11 +170,29 @@
170
170
  @apply relative;
171
171
  }
172
172
 
173
+ /*
174
+ * Shared drop-line look for every orientation. The bar is a rounded rule whose
175
+ * colour and thickness come from the design tokens, so the horizontal
176
+ * (top/bottom) and vertical (left/right) indicators are visually identical;
177
+ * each orientation rule below only sets which axis the thickness applies to and
178
+ * where the bar is pinned.
179
+ */
173
180
  [data-drop-indicator]::before {
174
- @apply content-[''] absolute h-1.5 rounded-xs pointer-events-none z-10;
181
+ @apply content-[''] absolute rounded-xs pointer-events-none z-10;
175
182
  background-color: var(--blok-dnd-drop-indicator-bg);
176
- left: calc(var(--drop-indicator-depth, 0) * var(--blok-space-3));
177
- right: 0;
183
+ }
184
+
185
+ /*
186
+ * Horizontal drop indicator: a rule across the top or bottom edge of the block.
187
+ */
188
+ [data-drop-indicator="top"]::before,
189
+ [data-drop-indicator="bottom"]::before {
190
+ height: var(--blok-dnd-drop-indicator-thickness);
191
+ /* Confine the line to the content box: the holder spans the editor gutters,
192
+ * so the side offsets pull the line in to the visible content width. The
193
+ * depth indent (list nesting) is added on top of the content-left offset. */
194
+ left: calc(var(--drop-indicator-side-left, 0px) + var(--drop-indicator-depth, 0) * var(--blok-space-3));
195
+ right: var(--drop-indicator-side-right, 0px);
178
196
  }
179
197
 
180
198
  [data-drop-indicator="bottom"]::before {
@@ -187,6 +205,32 @@
187
205
  transform: translateY(-50%);
188
206
  }
189
207
 
208
+ /*
209
+ * Vertical drop indicator: a bar on the left or right edge of the holder,
210
+ * signalling a column-layout drop. Same look as the horizontal rule, only the
211
+ * thickness applies to the width and the bar is pinned to a side edge.
212
+ */
213
+ [data-drop-indicator="left"]::before,
214
+ [data-drop-indicator="right"]::before {
215
+ width: var(--blok-dnd-drop-indicator-thickness);
216
+ /* Span the full column-row height when the target sits in a column_list: the
217
+ * controller sets these to the row's top/bottom offset (negative, so the bar
218
+ * grows past the single block). Default 0/0 → the bar matches the block. */
219
+ top: var(--drop-indicator-side-top, 0);
220
+ bottom: var(--drop-indicator-side-bottom, 0);
221
+ }
222
+
223
+ [data-drop-indicator="left"]::before {
224
+ /* Pull the bar out into the gutter so it sits clear of the content edge. */
225
+ left: calc(var(--drop-indicator-side-left, 0px) - var(--blok-space-2));
226
+ transform: translateX(-50%);
227
+ }
228
+
229
+ [data-drop-indicator="right"]::before {
230
+ right: calc(var(--drop-indicator-side-right, 0px) - var(--blok-space-2));
231
+ transform: translateX(50%);
232
+ }
233
+
190
234
  /* Spring-loaded: flash selection highlight on toggle after it auto-expands */
191
235
  [data-blok-spring-loaded] [data-blok-element-content] {
192
236
  animation: spring-loaded-flash 700ms ease-out forwards;
@@ -296,6 +340,7 @@
296
340
  @import './emoji-picker.css';
297
341
  @import './database.css';
298
342
  @import './image.css';
343
+ @import './columns.css';
299
344
 
300
345
  /*
301
346
  Image tool — selectors audited by unit tests (no backdrop-filter regression,
@@ -26,6 +26,14 @@
26
26
  transform: scale(0.98);
27
27
  }
28
28
 
29
+ /* Inline toolbar appears instantly — no entrance animation.
30
+ Direct child only, so nested inline popovers keep their animation. */
31
+ [data-blok-popover-inline] > [data-blok-popover-container],
32
+ [data-blok-popover-inline]:not([data-blok-popover-opened='true']) > [data-blok-popover-container] {
33
+ transition: none;
34
+ transform: none;
35
+ }
36
+
29
37
  @media (prefers-reduced-motion: reduce) {
30
38
  [data-blok-popover-container] {
31
39
  transition: none;
@@ -0,0 +1,189 @@
1
+ import type {
2
+ API,
3
+ BlockTool,
4
+ BlockToolConstructorOptions,
5
+ } from '../../../types';
6
+ import { COLUMN_ATTR, unwrapColumnListIfCollapsed } from '../columns-shared';
7
+ import { mountChildBlocks } from '../nested-blocks';
8
+ import { DATA_ATTR } from '../../components/constants/data-attributes';
9
+ import { twMerge } from '../../components/utils/tw';
10
+ import type { ColumnData } from './types';
11
+
12
+ /**
13
+ * Column block — a single vertical column inside a column_list.
14
+ * Hosts arbitrary user blocks as nested children and seeds an empty
15
+ * paragraph when created so it is never empty.
16
+ */
17
+ export class Column implements BlockTool {
18
+ private readonly api: API;
19
+ private _data: ColumnData;
20
+ private readonly blockId: string;
21
+ private readonly block: BlockToolConstructorOptions<ColumnData>['block'];
22
+ private childContainer: HTMLElement | null = null;
23
+ // Latched once the column has ever held content (mounted children or a seed).
24
+ // Distinguishes a fresh empty column (first render → seed) from one emptied
25
+ // later by a drag-out (re-render → self-delete).
26
+ private populated = false;
27
+
28
+ constructor({ data, api, block }: BlockToolConstructorOptions<ColumnData>) {
29
+ this.api = api;
30
+ this._data = { ...data };
31
+ this.blockId = block.id;
32
+ this.block = block;
33
+ }
34
+
35
+ public render(): HTMLElement {
36
+ const wrapper = document.createElement('div');
37
+
38
+ // `break-words` lets long unbreakable words reflow so a column can be
39
+ // resized arbitrarily thin instead of being held open at its min-content
40
+ // width. overflow-wrap is inherited, so descendant text picks it up.
41
+ wrapper.className = twMerge('flex', 'flex-col', 'min-w-0', 'break-words');
42
+ wrapper.setAttribute(COLUMN_ATTR, '');
43
+
44
+ const childContainer = document.createElement('div');
45
+
46
+ childContainer.setAttribute(DATA_ATTR.nestedBlocks, '');
47
+ wrapper.appendChild(childContainer);
48
+
49
+ this.childContainer = childContainer;
50
+
51
+ return wrapper;
52
+ }
53
+
54
+ public rendered(): void {
55
+ if (this.childContainer === null) {
56
+ return;
57
+ }
58
+
59
+ // The flex item is the block holder, not the rendered wrapper, and the
60
+ // holder only exists once the block is composed (post-render). Grow it so
61
+ // sibling columns split the row evenly; widthRatio biases the split.
62
+ this.block.holder.style.flexGrow = String(this._data.widthRatio ?? 1);
63
+ // A flex item defaults to min-width:auto (its min-content), which would
64
+ // floor the column at the width of its widest content. Allow it to shrink
65
+ // freely so the resizer has no min-width restriction.
66
+ this.block.holder.style.minWidth = '0';
67
+
68
+ const children = this.api.blocks.getChildren(this.blockId);
69
+
70
+ if (children.length > 0) {
71
+ this.populated = true;
72
+ mountChildBlocks(this.childContainer, children);
73
+
74
+ return;
75
+ }
76
+
77
+ // Empty AFTER having held content: the column's last block was dragged out,
78
+ // which re-fires rendered(). A column is pure layout, never standalone — so
79
+ // it removes itself rather than lingering as a dead, uninteractable box.
80
+ if (this.populated) {
81
+ this.deleteSelf();
82
+
83
+ return;
84
+ }
85
+
86
+ // Empty on the FIRST render. noSeed is a one-shot creation hint: a column-list
87
+ // wrap / add-column fills the column explicitly right afterwards, so suppress
88
+ // the seed this once and let the follow-up render mount the moved-in blocks.
89
+ if (this._data.noSeed === true) {
90
+ this._data.noSeed = false;
91
+
92
+ return;
93
+ }
94
+
95
+ // A fresh, unseeded column (e.g. a slash-menu preset): seed it so it is
96
+ // never empty.
97
+ this.seedParagraph();
98
+ this.populated = true;
99
+ }
100
+
101
+ /**
102
+ * Remove this now-childless column from its column_list. Deferred to a
103
+ * microtask because rendered() runs inside the drop's affected-parents loop;
104
+ * an index-based delete fired synchronously would splice the flat array
105
+ * mid-iteration. Re-check emptiness at fire time so a column refilled before
106
+ * the microtask runs is spared. Deleting the column triggers its own removed()
107
+ * hook, which unwraps the column_list if this leaves a single survivor.
108
+ */
109
+ private deleteSelf(): void {
110
+ queueMicrotask(() => {
111
+ if (this.api.blocks.getChildren(this.blockId).length > 0) {
112
+ return;
113
+ }
114
+
115
+ const index = this.api.blocks.getBlockIndex(this.blockId);
116
+
117
+ if (index !== undefined) {
118
+ void this.api.blocks.delete(index);
119
+ }
120
+ });
121
+ }
122
+
123
+ /**
124
+ * Seed the empty column with a paragraph. The first seeded column of a freshly
125
+ * created column_list claims the caret; siblings carry noFocus so the
126
+ * asynchronous last column never steals it (see {@link ColumnData}).
127
+ */
128
+ private seedParagraph(): void {
129
+ const blockIndex = this.api.blocks.getBlockIndex(this.blockId);
130
+
131
+ if (blockIndex === undefined || this.childContainer === null) {
132
+ return;
133
+ }
134
+
135
+ const paragraph = this.api.blocks.insertInsideParent(this.blockId, blockIndex + 1);
136
+
137
+ this.childContainer.appendChild(paragraph.holder);
138
+
139
+ if (this._data.noFocus !== true) {
140
+ this.api.caret.setToBlock(paragraph.id, 'start');
141
+ }
142
+ }
143
+
144
+ public save(): ColumnData {
145
+ // The resizer mutates the holder's flex-grow live, so the holder is the
146
+ // source of truth once rendered. Fall back to the seeded data before the
147
+ // holder exists. An even-split grow of 1 is the default — omit it.
148
+ const liveGrow = this.block.holder?.style.flexGrow;
149
+ const ratio = liveGrow !== undefined && liveGrow !== ''
150
+ ? Number(liveGrow)
151
+ : this._data.widthRatio;
152
+
153
+ return ratio !== undefined && ratio !== 1
154
+ ? { widthRatio: ratio }
155
+ : {};
156
+ }
157
+
158
+ public validate(_data: ColumnData): boolean {
159
+ return true;
160
+ }
161
+
162
+ public removed(): void {
163
+ // removed() runs INSIDE blocksStore.remove, BEFORE this block is spliced
164
+ // out of the flat array. The unwrap below issues index-based deletes
165
+ // (deleteById) of the surviving column + the column_list; running them now
166
+ // would splice the array mid-removal, shifting indices so the outer splice
167
+ // hits the wrong slot — the storm that drops innocent blocks when an empty
168
+ // column collapses. Defer to a microtask so the triggering removal finishes
169
+ // its splice first and every nested delete runs on a stable array.
170
+ //
171
+ // Read the LIVE parent id (off the block) at fire time, not the id captured
172
+ // at construction: a column detached to root before deletion must skip.
173
+ queueMicrotask(() => {
174
+ const parentId = this.block.parentId;
175
+
176
+ if (parentId !== null) {
177
+ // Pass blockId as excludeId so a not-yet-spliced self is excluded from
178
+ // the surviving-column count.
179
+ void unwrapColumnListIfCollapsed(this.api, parentId, this.blockId);
180
+ }
181
+ });
182
+ }
183
+
184
+ public static get isReadOnlySupported(): boolean {
185
+ return true;
186
+ }
187
+ }
188
+
189
+ export type { ColumnData };
@@ -0,0 +1,26 @@
1
+ import type { BlockToolData } from '../../../types';
2
+
3
+ export interface ColumnData extends BlockToolData {
4
+ /**
5
+ * Width of this column relative to its siblings, applied as flex-grow.
6
+ * Omitted means equal width (flex-grow: 1). Set by the resize sub-project.
7
+ */
8
+ widthRatio?: number;
9
+
10
+ /**
11
+ * Transient flag set when a column is created programmatically (e.g. by a
12
+ * drag-beside drop) and will be populated by reparenting existing blocks.
13
+ * Suppresses the empty-paragraph seed in rendered(). Never persisted — not
14
+ * returned from save().
15
+ */
16
+ noSeed?: boolean;
17
+
18
+ /**
19
+ * Transient flag: seed the empty paragraph but do NOT move the caret into it.
20
+ * Columns render asynchronously, so when a column_list seeds several columns
21
+ * the LAST one's self-focus would otherwise win the race. Setting this on
22
+ * every column except the first lets only the first column claim the caret.
23
+ * Never persisted — not returned from save().
24
+ */
25
+ noFocus?: boolean;
26
+ }