@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
@@ -162,6 +162,7 @@ var e = {
162
162
  "tools.quote.largeSize": "Suuri",
163
163
  "tools.code.codeTab": "Koodi",
164
164
  "tools.code.previewTab": "Esikatselu",
165
+ "tools.code.sideBySide": "Vierekkäin",
165
166
  "tools.table.placement": "Sijainti",
166
167
  "tools.table.placementTopLeft": "Ylhäällä vasemmalla",
167
168
  "tools.table.placementTopCenter": "Ylhäällä keskellä",
@@ -162,6 +162,7 @@ var e = {
162
162
  "tools.quote.largeSize": "Голям",
163
163
  "tools.code.codeTab": "Код",
164
164
  "tools.code.previewTab": "Преглед",
165
+ "tools.code.sideBySide": "Един до друг",
165
166
  "tools.table.placement": "Подравняване",
166
167
  "tools.table.placementTopLeft": "Горе вляво",
167
168
  "tools.table.placementTopCenter": "Горе в центъра",
@@ -162,6 +162,7 @@ var e = {
162
162
  "tools.quote.largeSize": "Kubwa",
163
163
  "tools.code.codeTab": "Msimbo",
164
164
  "tools.code.previewTab": "Hakiki",
165
+ "tools.code.sideBySide": "Kando kwa kando",
165
166
  "tools.table.placement": "Uwekaji",
166
167
  "tools.table.placementTopLeft": "Juu kushoto",
167
168
  "tools.table.placementTopCenter": "Juu katikati",
@@ -162,6 +162,7 @@ var e = {
162
162
  "tools.quote.largeSize": "വലുത്",
163
163
  "tools.code.codeTab": "കോഡ്",
164
164
  "tools.code.previewTab": "പ്രിവ്യൂ",
165
+ "tools.code.sideBySide": "അരികിലരികെ",
165
166
  "tools.table.placement": "സ്ഥാനം",
166
167
  "tools.table.placementTopLeft": "മുകളിൽ ഇടത്",
167
168
  "tools.table.placementTopCenter": "മുകളിൽ മധ്യത്തിൽ",
@@ -162,6 +162,7 @@ var e = {
162
162
  "tools.quote.largeSize": "Grand",
163
163
  "tools.code.codeTab": "Code",
164
164
  "tools.code.previewTab": "Aperçu",
165
+ "tools.code.sideBySide": "Côte à côte",
165
166
  "tools.table.placement": "Position",
166
167
  "tools.table.placementTopLeft": "Haut gauche",
167
168
  "tools.table.placementTopCenter": "Haut centre",
@@ -162,6 +162,7 @@ var e = {
162
162
  "tools.quote.largeSize": "Besar",
163
163
  "tools.code.codeTab": "Kode",
164
164
  "tools.code.previewTab": "Pratinjau",
165
+ "tools.code.sideBySide": "Berdampingan",
165
166
  "tools.table.placement": "Penempatan",
166
167
  "tools.table.placementTopLeft": "Kiri Atas",
167
168
  "tools.table.placementTopCenter": "Tengah Atas",
@@ -162,6 +162,7 @@ var e = {
162
162
  "tools.quote.largeSize": "Большой",
163
163
  "tools.code.codeTab": "Код",
164
164
  "tools.code.previewTab": "Предпросмотр",
165
+ "tools.code.sideBySide": "Бок о бок",
165
166
  "tools.table.placement": "Расположение",
166
167
  "tools.table.placementTopLeft": "Сверху слева",
167
168
  "tools.table.placementTopCenter": "Сверху по центру",
@@ -162,6 +162,7 @@ var e = {
162
162
  "tools.quote.largeSize": "Stor",
163
163
  "tools.code.codeTab": "Kod",
164
164
  "tools.code.previewTab": "Förhandsgranskning",
165
+ "tools.code.sideBySide": "Sida vid sida",
165
166
  "tools.table.placement": "Placering",
166
167
  "tools.table.placementTopLeft": "Uppe till vänster",
167
168
  "tools.table.placementTopCenter": "Uppe i mitten",
@@ -162,6 +162,7 @@ var e = {
162
162
  "tools.quote.largeSize": "Groß",
163
163
  "tools.code.codeTab": "Code",
164
164
  "tools.code.previewTab": "Vorschau",
165
+ "tools.code.sideBySide": "Nebeneinander",
165
166
  "tools.table.placement": "Position",
166
167
  "tools.table.placementTopLeft": "Oben links",
167
168
  "tools.table.placementTopCenter": "Oben zentriert",
@@ -162,6 +162,7 @@ var e = {
162
162
  "tools.quote.largeSize": "Didelis",
163
163
  "tools.code.codeTab": "Kodas",
164
164
  "tools.code.previewTab": "Peržiūra",
165
+ "tools.code.sideBySide": "Šalia",
165
166
  "tools.table.placement": "Padėtis",
166
167
  "tools.table.placementTopLeft": "Viršuje kairėje",
167
168
  "tools.table.placementTopCenter": "Viršuje centre",
@@ -162,6 +162,7 @@ var e = {
162
162
  "tools.quote.largeSize": "အကြီး",
163
163
  "tools.code.codeTab": "ကုဒ်",
164
164
  "tools.code.previewTab": "ကြိုတင်ကြည့်ရှုမှု",
165
+ "tools.code.sideBySide": "ဘေးချင်းကပ်",
165
166
  "tools.table.placement": "တည်နေရာ",
166
167
  "tools.table.placementTopLeft": "အပေါ် ဘယ်",
167
168
  "tools.table.placementTopCenter": "အပေါ် အလယ်",
@@ -162,6 +162,7 @@ var e = {
162
162
  "tools.quote.largeSize": "Stor",
163
163
  "tools.code.codeTab": "Kode",
164
164
  "tools.code.previewTab": "Forhåndsvisning",
165
+ "tools.code.sideBySide": "Side om side",
165
166
  "tools.table.placement": "Placering",
166
167
  "tools.table.placementTopLeft": "Øverst til venstre",
167
168
  "tools.table.placementTopCenter": "Øverst centreret",
@@ -162,6 +162,7 @@ var e = {
162
162
  "tools.quote.largeSize": "Veliko",
163
163
  "tools.code.codeTab": "Kod",
164
164
  "tools.code.previewTab": "Pregled",
165
+ "tools.code.sideBySide": "Usporedno",
165
166
  "tools.table.placement": "Položaj",
166
167
  "tools.table.placementTopLeft": "Gore lijevo",
167
168
  "tools.table.placementTopCenter": "Gore u sredini",
@@ -162,6 +162,7 @@ var e = {
162
162
  "tools.quote.largeSize": "बड़ा",
163
163
  "tools.code.codeTab": "कोड",
164
164
  "tools.code.previewTab": "पूर्वावलोकन",
165
+ "tools.code.sideBySide": "साथ-साथ",
165
166
  "tools.table.placement": "स्थिति",
166
167
  "tools.table.placementTopLeft": "ऊपर बाएं",
167
168
  "tools.table.placementTopCenter": "ऊपर बीच में",
@@ -162,6 +162,7 @@ var e = {
162
162
  "tools.quote.largeSize": "Böyük",
163
163
  "tools.code.codeTab": "Kod",
164
164
  "tools.code.previewTab": "Önizləmə",
165
+ "tools.code.sideBySide": "Yan-yana",
165
166
  "tools.table.placement": "Yerləşmə",
166
167
  "tools.table.placementTopLeft": "Yuxarı sol",
167
168
  "tools.table.placementTopCenter": "Yuxarı orta",
@@ -162,6 +162,7 @@ var e = {
162
162
  "tools.quote.largeSize": "Голем",
163
163
  "tools.code.codeTab": "Код",
164
164
  "tools.code.previewTab": "Преглед",
165
+ "tools.code.sideBySide": "Една до друга",
165
166
  "tools.table.placement": "Позиција",
166
167
  "tools.table.placementTopLeft": "Горе лево",
167
168
  "tools.table.placementTopCenter": "Горе во средина",
@@ -162,6 +162,7 @@ var e = {
162
162
  "tools.quote.largeSize": "ใหญ่",
163
163
  "tools.code.codeTab": "โค้ด",
164
164
  "tools.code.previewTab": "ตัวอย่าง",
165
+ "tools.code.sideBySide": "เคียงข้างกัน",
165
166
  "tools.table.placement": "ตำแหน่ง",
166
167
  "tools.table.placementTopLeft": "บนซ้าย",
167
168
  "tools.table.placementTopCenter": "บนกลาง",
@@ -162,6 +162,7 @@ var e = {
162
162
  "tools.quote.largeSize": "பெரிய",
163
163
  "tools.code.codeTab": "குறியீடு",
164
164
  "tools.code.previewTab": "முன்னோட்டம்",
165
+ "tools.code.sideBySide": "பக்கவாட்டில்",
165
166
  "tools.table.placement": "இட அமைப்பு",
166
167
  "tools.table.placementTopLeft": "மேல் இடது",
167
168
  "tools.table.placementTopCenter": "மேல் நடு",
@@ -162,6 +162,7 @@ var e = {
162
162
  "tools.quote.largeSize": "Lớn",
163
163
  "tools.code.codeTab": "Mã",
164
164
  "tools.code.previewTab": "Xem trước",
165
+ "tools.code.sideBySide": "Song song",
165
166
  "tools.table.placement": "Vị trí",
166
167
  "tools.table.placementTopLeft": "Trên trái",
167
168
  "tools.table.placementTopCenter": "Trên giữa",
package/dist/react.mjs CHANGED
@@ -1,5 +1,5 @@
1
- import { t as e } from "./chunks/blok-DDu252IK.mjs";
2
- import "./chunks/constants-DMW9a31I.mjs";
1
+ import { t as e } from "./chunks/blok-u_68bnlk.mjs";
2
+ import "./chunks/constants-VDhCUk4c.mjs";
3
3
  import { t } from "./chunks/objectSpread2-CWwMYL_U.mjs";
4
4
  import { t as n } from "./chunks/objectWithoutProperties-D0XxKB4n.mjs";
5
5
  import { forwardRef as r, useEffect as i, useMemo as a, useRef as o, useState as s } from "react";
package/dist/tools.mjs CHANGED
@@ -1,3 +1,3 @@
1
- import { m as e } from "./chunks/constants-DMW9a31I.mjs";
2
- import { _ as t, a as n, c as r, d as i, f as a, g as o, h as s, i as c, l, m as u, n as d, o as f, p, r as m, s as h, t as g, u as _, v } from "./chunks/tools-XmzH2rgQ.mjs";
1
+ import { m as e } from "./chunks/constants-VDhCUk4c.mjs";
2
+ import { _ as t, a as n, c as r, d as i, f as a, g as o, h as s, i as c, l, m as u, n as d, o as f, p, r as m, s as h, t as g, u as _, v } from "./chunks/tools-1ZFajlGN.mjs";
3
3
  export { l as Bold, p as Callout, _ as Code, e as Convert, a as Divider, t as Header, m as InlineCode, r as Italic, h as Link, o as List, f as Marker, v as Paragraph, i as Quote, c as Strikethrough, s as Table, u as Toggle, n as Underline, g as defaultBlockTools, d as defaultInlineTools };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jackuait/blok",
3
- "version": "0.10.0-beta.9",
3
+ "version": "0.10.1",
4
4
  "description": "Blok — headless, highly extensible rich text editor built for developers who need to implement a block-based editing experience (similar to Notion) without building it from scratch",
5
5
  "module": "dist/blok.mjs",
6
6
  "types": "./types/index.d.ts",
@@ -50,15 +50,13 @@
50
50
  }
51
51
  },
52
52
  "bin": {
53
- "blok": "./bin/blok.mjs",
54
53
  "migrate-from-editorjs": "./codemod/migrate-editorjs-to-blok.js"
55
54
  },
56
55
  "files": [
57
56
  "dist",
58
57
  "types",
59
58
  "src",
60
- "codemod",
61
- "bin"
59
+ "codemod"
62
60
  ],
63
61
  "publishConfig": {
64
62
  "access": "public"
@@ -83,7 +81,7 @@
83
81
  "scripts": {
84
82
  "serve": "vite --no-open",
85
83
  "serve:docs": "cd docs && vite --port 8080",
86
- "build": "vite build --mode production && node scripts/build-locales.mjs && node scripts/build-cli.mjs",
84
+ "build": "vite build --mode production && node scripts/build-locales.mjs",
87
85
  "build:cli": "node scripts/build-cli.mjs",
88
86
  "build:test": "vite build --mode test && node scripts/build-locales.mjs test && node scripts/build-react-vendor.mjs",
89
87
  "lint": "sh -c 'eslint .; ESLINT_EXIT=$?; tsc --noEmit; TSC_EXIT=$?; if [ $ESLINT_EXIT -ne 0 ] || [ $TSC_EXIT -ne 0 ]; then exit 1; fi'",
@@ -0,0 +1,26 @@
1
+ import { preprocessGoogleDocsHtml } from '../../../components/modules/paste/google-docs-preprocessor';
2
+ import { preprocess } from '../convert-html/preprocessor';
3
+ import { sanitize } from '../convert-html/sanitizer';
4
+ import { buildBlocks } from '../convert-html/block-builder';
5
+ import type { OutputData } from '../convert-html/types';
6
+
7
+ declare const __CLI_VERSION__: string;
8
+
9
+ /**
10
+ * Convert Google Docs HTML to Blok JSON.
11
+ * Runs: Google Docs preprocess -> general preprocess -> sanitize -> build blocks -> serialize.
12
+ */
13
+ export function convertGdocs(html: string): string {
14
+ const preprocessed = preprocessGoogleDocsHtml(html);
15
+
16
+ const dom = new DOMParser().parseFromString(preprocessed, 'text/html');
17
+ const wrapper = dom.body;
18
+
19
+ preprocess(wrapper);
20
+ sanitize(wrapper);
21
+
22
+ const blocks = buildBlocks(wrapper);
23
+ const output: OutputData = { version: typeof __CLI_VERSION__ !== 'undefined' ? __CLI_VERSION__ : 'dev', blocks };
24
+
25
+ return JSON.stringify(output);
26
+ }
@@ -0,0 +1,392 @@
1
+ import { createIdGenerator } from './id-generator';
2
+ import { mapToNearestPresetName } from '../../../components/utils/color-mapping';
3
+ import type { OutputBlockData } from './types';
4
+
5
+ /**
6
+ * Walk the wrapper's top-level children and convert each block-level HTML
7
+ * element into one or more Blok JSON blocks.
8
+ */
9
+ export function buildBlocks(wrapper: HTMLElement): OutputBlockData[] {
10
+ const nextId = createIdGenerator();
11
+ const blocks: OutputBlockData[] = [];
12
+
13
+ for (const node of Array.from(wrapper.childNodes)) {
14
+ convertNode(node, blocks, nextId);
15
+ }
16
+
17
+ return blocks;
18
+ }
19
+
20
+ // ---------------------------------------------------------------------------
21
+ // Converters
22
+ // ---------------------------------------------------------------------------
23
+
24
+ function convertNode(
25
+ node: Node,
26
+ blocks: OutputBlockData[],
27
+ nextId: (prefix: string) => string
28
+ ): void {
29
+ if (node.nodeType === Node.TEXT_NODE) {
30
+ const text = node.textContent?.trim() ?? '';
31
+
32
+ if (text) {
33
+ blocks.push({ id: nextId('paragraph'), type: 'paragraph', data: { text } });
34
+ }
35
+
36
+ return;
37
+ }
38
+
39
+ if (node.nodeType !== Node.ELEMENT_NODE) {
40
+ return;
41
+ }
42
+
43
+ const el = node as HTMLElement;
44
+ const tag = el.tagName;
45
+
46
+ if (tag === 'P') {
47
+ blocks.push({ id: nextId('paragraph'), type: 'paragraph', data: { text: el.innerHTML } });
48
+
49
+ return;
50
+ }
51
+
52
+ if (/^H[1-6]$/.test(tag)) {
53
+ const level = Number(tag[1]);
54
+
55
+ blocks.push({ id: nextId('header'), type: 'header', data: { text: el.innerHTML, level } });
56
+
57
+ return;
58
+ }
59
+
60
+ if (tag === 'BLOCKQUOTE') {
61
+ blocks.push({
62
+ id: nextId('quote'),
63
+ type: 'quote',
64
+ data: { text: el.innerHTML, size: 'default' },
65
+ });
66
+
67
+ return;
68
+ }
69
+
70
+ if (tag === 'PRE') {
71
+ blocks.push({
72
+ id: nextId('code'),
73
+ type: 'code',
74
+ data: { code: el.textContent ?? '', language: 'plain-text' },
75
+ });
76
+
77
+ return;
78
+ }
79
+
80
+ if (tag === 'HR') {
81
+ blocks.push({ id: nextId('divider'), type: 'divider', data: {} });
82
+
83
+ return;
84
+ }
85
+
86
+ if (tag === 'IMG') {
87
+ const src = el.getAttribute('src') ?? '';
88
+ const width = parseIntFromStyle(el, 'width');
89
+
90
+ blocks.push({
91
+ id: nextId('image'),
92
+ type: 'image',
93
+ data: { url: src },
94
+ stretched: null,
95
+ key: null,
96
+ width,
97
+ });
98
+
99
+ return;
100
+ }
101
+
102
+ if (tag === 'DETAILS') {
103
+ const summary = el.querySelector('summary');
104
+ const text = summary ? summary.innerHTML : el.innerHTML;
105
+
106
+ blocks.push({ id: nextId('toggle'), type: 'toggle', data: { text } });
107
+
108
+ return;
109
+ }
110
+
111
+ if (tag === 'UL' || tag === 'OL') {
112
+ flattenList(el, tag === 'OL' ? 'ordered' : 'unordered', 0, blocks, nextId);
113
+
114
+ return;
115
+ }
116
+
117
+ if (tag === 'TABLE') {
118
+ convertTable(el, blocks, nextId);
119
+
120
+ return;
121
+ }
122
+
123
+ if (tag === 'ASIDE') {
124
+ convertCallout(el, blocks, nextId);
125
+
126
+ return;
127
+ }
128
+
129
+ // Unknown block element: extract innerHTML as paragraph
130
+ blocks.push({
131
+ id: nextId('paragraph'),
132
+ type: 'paragraph',
133
+ data: { text: el.innerHTML },
134
+ });
135
+ }
136
+
137
+ // ---------------------------------------------------------------------------
138
+ // List flattening
139
+ // ---------------------------------------------------------------------------
140
+
141
+ function flattenList(
142
+ listEl: HTMLElement,
143
+ style: 'ordered' | 'unordered',
144
+ depth: number,
145
+ blocks: OutputBlockData[],
146
+ nextId: (prefix: string) => string
147
+ ): void {
148
+ const startAttr = listEl.getAttribute('start');
149
+ const startValue = startAttr ? Number(startAttr) : null;
150
+ const listItems = Array.from(listEl.children).filter((child) => child.tagName === 'LI');
151
+
152
+ for (const [index, child] of listItems.entries()) {
153
+ // Clone the li so we can remove nested lists without mutating DOM
154
+ const clone = child.cloneNode(true) as HTMLElement;
155
+ const nestedLists: HTMLElement[] = [];
156
+
157
+ for (const nested of Array.from(clone.querySelectorAll('ul, ol'))) {
158
+ nestedLists.push(nested.cloneNode(true) as HTMLElement);
159
+ nested.remove();
160
+ }
161
+
162
+ const text = clone.innerHTML.trim();
163
+
164
+ // Use aria-level if present (1-based → 0-based), otherwise use nesting depth
165
+ const ariaLevel = (child as HTMLElement).getAttribute('aria-level');
166
+ const itemDepth = ariaLevel
167
+ ? Math.max(0, parseInt(ariaLevel, 10) - 1)
168
+ : depth;
169
+
170
+ blocks.push({
171
+ id: nextId('list'),
172
+ type: 'list',
173
+ data: {
174
+ text,
175
+ style,
176
+ depth: itemDepth === 0 ? null : itemDepth,
177
+ checked: null,
178
+ start: index === 0 && startValue !== null ? startValue : null,
179
+ },
180
+ });
181
+
182
+ // Recursively process nested lists
183
+ for (const nested of nestedLists) {
184
+ const nestedStyle = nested.tagName === 'OL' ? 'ordered' : 'unordered';
185
+
186
+ flattenList(nested, nestedStyle, depth + 1, blocks, nextId);
187
+ }
188
+ }
189
+ }
190
+
191
+ // ---------------------------------------------------------------------------
192
+ // Table conversion
193
+ // ---------------------------------------------------------------------------
194
+
195
+ function convertTable(
196
+ tableEl: HTMLElement,
197
+ blocks: OutputBlockData[],
198
+ nextId: (prefix: string) => string
199
+ ): void {
200
+ const tableId = nextId('table');
201
+ const rows = Array.from(tableEl.querySelectorAll('tr'));
202
+ const content: Record<string, unknown>[][] = [];
203
+
204
+ for (const row of rows) {
205
+ const cells = Array.from(row.querySelectorAll('td, th'));
206
+ const rowData = cells.map((cell) => convertTableCell(cell as HTMLElement, tableId, blocks, nextId));
207
+
208
+ content.push(rowData);
209
+ }
210
+
211
+ // Parse column widths and headings from first row cells
212
+ const firstRowCells = rows[0] ? Array.from(rows[0].querySelectorAll('td, th')) : [];
213
+ const withHeadings = firstRowCells.some((c) => c.tagName === 'TH');
214
+ const colWidths = firstRowCells.map((cell) => {
215
+ const width = parseCssProperty(cell as HTMLElement, 'width');
216
+
217
+ if (width) {
218
+ const px = parseInt(width, 10);
219
+
220
+ return isNaN(px) ? null : px;
221
+ }
222
+
223
+ return null;
224
+ });
225
+ const hasWidths = colWidths.some((w) => w !== null);
226
+
227
+ // Insert table block before its child paragraph blocks
228
+ const tableBlock: OutputBlockData = {
229
+ id: tableId,
230
+ type: 'table',
231
+ data: {
232
+ withHeadings,
233
+ withHeadingColumn: false,
234
+ content,
235
+ ...(hasWidths ? { colWidths } : {}),
236
+ },
237
+ };
238
+
239
+ // Find first child block index to insert table before its children
240
+ const firstChildIdx = blocks.findIndex((b) => b.parent === tableId);
241
+
242
+ if (firstChildIdx >= 0) {
243
+ blocks.splice(firstChildIdx, 0, tableBlock);
244
+ } else {
245
+ blocks.push(tableBlock);
246
+ }
247
+ }
248
+
249
+ // ---------------------------------------------------------------------------
250
+ // Callout conversion
251
+ // ---------------------------------------------------------------------------
252
+
253
+ function convertCallout(
254
+ asideEl: HTMLElement,
255
+ blocks: OutputBlockData[],
256
+ nextId: (prefix: string) => string
257
+ ): void {
258
+ const calloutId = nextId('callout');
259
+ const bgColor = parseCssProperty(asideEl, 'background-color');
260
+ const backgroundColor = bgColor ? mapToNearestPresetName(bgColor, 'bg') : null;
261
+
262
+ const childIds: string[] = [];
263
+
264
+ for (const child of Array.from(asideEl.childNodes)) {
265
+ const childId = convertCalloutChild(child, calloutId, blocks, nextId);
266
+
267
+ if (childId) {
268
+ childIds.push(childId);
269
+ }
270
+ }
271
+
272
+ // Insert callout block before its children
273
+ const firstChildIdx = blocks.findIndex((b) => b.parent === calloutId);
274
+
275
+ const calloutBlock: OutputBlockData = {
276
+ id: calloutId,
277
+ type: 'callout',
278
+ data: {
279
+ emoji: '\u{1F4A1}',
280
+ backgroundColor: backgroundColor ?? 'gray',
281
+ },
282
+ content: childIds,
283
+ };
284
+
285
+ if (firstChildIdx >= 0) {
286
+ blocks.splice(firstChildIdx, 0, calloutBlock);
287
+ } else {
288
+ blocks.push(calloutBlock);
289
+ }
290
+ }
291
+
292
+ // ---------------------------------------------------------------------------
293
+ // Helpers
294
+ // ---------------------------------------------------------------------------
295
+
296
+ function convertTableCell(
297
+ cellEl: HTMLElement,
298
+ tableId: string,
299
+ blocks: OutputBlockData[],
300
+ nextId: (prefix: string) => string
301
+ ): Record<string, unknown> {
302
+ const cellText = cellEl.innerHTML.trim();
303
+
304
+ if (!cellText) {
305
+ return { blocks: [], color: null, textColor: null };
306
+ }
307
+
308
+ const childId = nextId('paragraph');
309
+
310
+ blocks.push({
311
+ id: childId,
312
+ type: 'paragraph',
313
+ parent: tableId,
314
+ data: { text: cellText },
315
+ });
316
+
317
+ const bgColor = parseCssProperty(cellEl, 'background-color');
318
+ const textColor = parseCssProperty(cellEl, 'color');
319
+
320
+ return {
321
+ blocks: [childId],
322
+ color: bgColor ? mapToNearestPresetName(bgColor, 'bg') : null,
323
+ textColor: textColor ? mapToNearestPresetName(textColor, 'text') : null,
324
+ };
325
+ }
326
+
327
+ function convertCalloutChild(
328
+ child: ChildNode,
329
+ calloutId: string,
330
+ blocks: OutputBlockData[],
331
+ nextId: (prefix: string) => string
332
+ ): string | null {
333
+ if (child.nodeType === Node.ELEMENT_NODE) {
334
+ const childEl = child as HTMLElement;
335
+ const childId = nextId('paragraph');
336
+
337
+ blocks.push({
338
+ id: childId,
339
+ type: 'paragraph',
340
+ parent: calloutId,
341
+ data: { text: childEl.innerHTML },
342
+ });
343
+
344
+ return childId;
345
+ }
346
+
347
+ if (child.nodeType === Node.TEXT_NODE) {
348
+ const text = child.textContent?.trim() ?? '';
349
+
350
+ if (!text) {
351
+ return null;
352
+ }
353
+
354
+ const childId = nextId('paragraph');
355
+
356
+ blocks.push({
357
+ id: childId,
358
+ type: 'paragraph',
359
+ parent: calloutId,
360
+ data: { text },
361
+ });
362
+
363
+ return childId;
364
+ }
365
+
366
+ return null;
367
+ }
368
+
369
+ function parseIntFromStyle(el: HTMLElement, property: string): number | null {
370
+ const value = parseCssProperty(el, property);
371
+
372
+ if (!value) {
373
+ return null;
374
+ }
375
+
376
+ const parsed = parseInt(value, 10);
377
+
378
+ return isNaN(parsed) ? null : parsed;
379
+ }
380
+
381
+ function parseCssProperty(el: HTMLElement, property: string): string | null {
382
+ const style = el.getAttribute('style');
383
+
384
+ if (!style) {
385
+ return null;
386
+ }
387
+
388
+ const regex = new RegExp(`(?<![\\-a-z])${property}\\s*:\\s*([^;]+)`);
389
+ const match = regex.exec(style);
390
+
391
+ return match ? match[1].trim() : null;
392
+ }
@@ -0,0 +1,11 @@
1
+ export function createIdGenerator(): (prefix: string) => string {
2
+ const counters = new Map<string, number>();
3
+
4
+ return (prefix: string): string => {
5
+ const count = (counters.get(prefix) ?? 0) + 1;
6
+
7
+ counters.set(prefix, count);
8
+
9
+ return `${prefix}-${count}`;
10
+ };
11
+ }