@jackuait/blok 0.10.0-beta.6 → 0.10.0-beta.7

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 (409) hide show
  1. package/codemod/migrate-editorjs-to-blok.js +0 -2
  2. package/codemod/test.js +0 -6
  3. package/dist/blok.mjs +2 -2
  4. package/dist/chunks/_basePickBy-BHRNO12X.mjs +410 -0
  5. package/dist/chunks/_baseUniq-DtFPDBML.mjs +1045 -0
  6. package/dist/chunks/_getTag-ozrhqxk_.mjs +26 -0
  7. package/dist/chunks/arc-BEqJP9HX.mjs +80 -0
  8. package/dist/chunks/architecture-YZFGNWBL-Bcu-90pi.mjs +3 -0
  9. package/dist/chunks/architectureDiagram-Q4EWVU46-BMno5LCn.mjs +4066 -0
  10. package/dist/chunks/array-Cyf-61SV.mjs +6 -0
  11. package/dist/chunks/blockDiagram-DXYQGD6D-DlP_cPth.mjs +3259 -0
  12. package/dist/chunks/{blok-BdlR_lX6.mjs → blok-CiLRmoHI.mjs} +850 -855
  13. package/dist/chunks/c4Diagram-AHTNJAMY-BbVV8EXj.mjs +2956 -0
  14. package/dist/chunks/channel-DPcniO2B.mjs +5 -0
  15. package/dist/chunks/chunk-2KRD3SAO-CazES4VS.mjs +20 -0
  16. package/dist/chunks/chunk-336JU56O-heO72r_k.mjs +49 -0
  17. package/dist/chunks/chunk-426QAEUC-CmCcml1z.mjs +13 -0
  18. package/dist/chunks/chunk-4BX2VUAB-B10DxOza.mjs +19 -0
  19. package/dist/chunks/chunk-4TB4RGXK-B0snhZOU.mjs +3250 -0
  20. package/dist/chunks/chunk-55IACEB6-CGkn5ABd.mjs +8 -0
  21. package/dist/chunks/chunk-5FUZZQ4R-USdumo_u.mjs +3786 -0
  22. package/dist/chunks/chunk-5PVQY5BW-CxUGVzQL.mjs +1692 -0
  23. package/dist/chunks/chunk-67CJDMHE-Bvw55oRa.mjs +20 -0
  24. package/dist/chunks/chunk-7N4EOEYR-Bs2qDy88.mjs +29 -0
  25. package/dist/chunks/chunk-AA7GKIK3-Bss0LgrN.mjs +24 -0
  26. package/dist/chunks/chunk-BSJP7CBP-CpUW7gi5.mjs +83 -0
  27. package/dist/chunks/chunk-CIAEETIT-DlRbLLf3.mjs +20 -0
  28. package/dist/chunks/{chunk-Byubey_H.mjs → chunk-D6kmoKXy.mjs} +5 -5
  29. package/dist/chunks/chunk-EDXVE4YY-DEcX4XWm.mjs +26 -0
  30. package/dist/chunks/chunk-ENJZ2VHE-B4THRZkR.mjs +566 -0
  31. package/dist/chunks/chunk-FMBD7UC4-CF6BKEiV.mjs +5 -0
  32. package/dist/chunks/chunk-FOC6F5B3--xuza7Yn.mjs +20 -0
  33. package/dist/chunks/chunk-ICPOFSXX-BMja8cuy.mjs +3290 -0
  34. package/dist/chunks/chunk-K5T4RW27-CHEqGHFS.mjs +16370 -0
  35. package/dist/chunks/chunk-KGLVRYIC-DHYYpR8v.mjs +20 -0
  36. package/dist/chunks/chunk-LIHQZDEY-AvbOvyLE.mjs +55 -0
  37. package/dist/chunks/chunk-ORNJ4GCN-38fbR5OS.mjs +25 -0
  38. package/dist/chunks/chunk-OYMX7WX6-BiqlATPA.mjs +2038 -0
  39. package/dist/chunks/chunk-QZHKN3VN-DitZIvj8.mjs +12 -0
  40. package/dist/chunks/chunk-U2HBQHQK-DJytnHmZ.mjs +1875 -0
  41. package/dist/chunks/chunk-X2U36JSP-DlOifw1K.mjs +68 -0
  42. package/dist/chunks/chunk-XPW4576I-s4fsi4XO.mjs +1146 -0
  43. package/dist/chunks/chunk-YZCP3GAM-Ch258bXC.mjs +60 -0
  44. package/dist/chunks/chunk-ZZ45TVLE-DWziaKxP.mjs +33 -0
  45. package/dist/chunks/classDiagram-6PBFFD2Q-BOkAe08u.mjs +30 -0
  46. package/dist/chunks/classDiagram-v2-HSJHXN6E-DeKatSvh.mjs +30 -0
  47. package/dist/chunks/clone-CJCz7VRp.mjs +8 -0
  48. package/dist/chunks/{constants-Cp8O0UfP.mjs → constants-DFS8l39Y.mjs} +49 -50
  49. package/dist/chunks/cose-bilkent-S5V4N54A-CzLGVqvr.mjs +2246 -0
  50. package/dist/chunks/cytoscape.esm-D0iglm-M.mjs +18108 -0
  51. package/dist/chunks/dagre-KV5264BT-XbHSjleO.mjs +298 -0
  52. package/dist/chunks/dagre-XY8CZ1sg.mjs +1536 -0
  53. package/dist/chunks/defaultLocale-DFhS1600.mjs +201 -0
  54. package/dist/chunks/diagram-5BDNPKRD-CM7c3UTI.mjs +112 -0
  55. package/dist/chunks/diagram-G4DWMVQ6-Bhg4ps6b.mjs +546 -0
  56. package/dist/chunks/diagram-MMDJMWI5-C-UCVaxB.mjs +234 -0
  57. package/dist/chunks/diagram-TYMM5635-BOHSujSD.mjs +144 -0
  58. package/dist/chunks/dist-DHsXIYdd.mjs +59 -0
  59. package/dist/chunks/erDiagram-SMLLAGMA-CwKxXFMB.mjs +1712 -0
  60. package/dist/chunks/flowDiagram-DWJPFMVM-rQJKfyuO.mjs +4175 -0
  61. package/dist/chunks/ganttDiagram-T4ZO3ILL-DfaZirLX.mjs +3083 -0
  62. package/dist/chunks/gitGraph-7Q5UKJZL-BKG8cHGz.mjs +3 -0
  63. package/dist/chunks/gitGraphDiagram-UUTBAWPF-CRa-ymsI.mjs +792 -0
  64. package/dist/chunks/graphlib-CuDElSdG.mjs +223 -0
  65. package/dist/chunks/{i18next-loader-oDO9ZKUV.mjs → i18next-loader-CasQQb5s.mjs} +2 -2
  66. package/dist/chunks/info-OMHHGYJF-FKqYyUn9.mjs +3 -0
  67. package/dist/chunks/infoDiagram-42DDH7IO-CvyJU2nE.mjs +29 -0
  68. package/dist/chunks/init-JlKGZtuT.mjs +15 -0
  69. package/dist/chunks/ishikawaDiagram-UXIWVN3A-CIpbw1BK.mjs +719 -0
  70. package/dist/chunks/journeyDiagram-VCZTEJTY-H96UcUK9.mjs +885 -0
  71. package/dist/chunks/kanban-definition-6JOO6SKY-BYZT3srA.mjs +980 -0
  72. package/dist/chunks/{katex-NjLaA6AJ.mjs → katex-JyOgX6MW.mjs} +1 -1
  73. package/dist/chunks/{lightweight-i18n-DTySD6f6.mjs → lightweight-i18n-Cvv8CWh4.mjs} +13 -0
  74. package/dist/chunks/line-B9xUUA7k.mjs +34 -0
  75. package/dist/chunks/linear-Dj-1yA_B.mjs +289 -0
  76. package/dist/chunks/mermaid-parser.core-D6OPAUtM.mjs +57 -0
  77. package/dist/chunks/mermaid.core-BPN9ZHKQ.mjs +989 -0
  78. package/dist/{messages-B4lhNMKm2.mjs → chunks/messages--YKhFEDE.mjs} +28 -3
  79. package/dist/chunks/{messages-CF_PfacZ.mjs → messages-0Uwu1AMJ2.mjs} +26 -1
  80. package/dist/{messages-Bug6Du35.mjs → chunks/messages-1__0Ph4Q.mjs} +26 -1
  81. package/dist/chunks/{messages-CnQydQJd2.mjs → messages-4sm9Pb0C.mjs} +26 -1
  82. package/dist/chunks/{messages-BDXl53cy2.mjs → messages-4uxjtzKW.mjs} +26 -1
  83. package/dist/{messages-DQN1y6E9.mjs → chunks/messages-B-SwLgkQ.mjs} +28 -3
  84. package/dist/chunks/{messages-BlcRm2I3.mjs → messages-B1ylBxXQ.mjs} +26 -1
  85. package/dist/{messages-12_eyAo-.mjs → chunks/messages-B5m3dhKc.mjs} +26 -1
  86. package/dist/chunks/{messages-D8-N0FmU.mjs → messages-B6n2zDtv.mjs} +27 -2
  87. package/dist/chunks/{messages-BMq9k_lI.mjs → messages-BC9w4zAT.mjs} +26 -1
  88. package/dist/{messages-CsiGzUSP2.mjs → chunks/messages-BOj-7N3p.mjs} +26 -1
  89. package/dist/chunks/{messages-CvlMT1e62.mjs → messages-BRYHTS18.mjs} +26 -1
  90. package/dist/{messages-hrSlVSHp.mjs → chunks/messages-BSBbVjor.mjs} +33 -8
  91. package/dist/{messages-uCsQjz7M.mjs → chunks/messages-BUUkmUGc.mjs} +26 -1
  92. package/dist/chunks/{messages-DopbvJlg.mjs → messages-Bb3YEV2P.mjs} +31 -6
  93. package/dist/{messages-KqWQKmIu2.mjs → chunks/messages-Be_6YLzJ.mjs} +27 -2
  94. package/dist/chunks/{messages-BXn9Vzbx2.mjs → messages-BevRhv5d.mjs} +26 -1
  95. package/dist/chunks/{messages-DQ5ng0_t2.mjs → messages-Bhqr7Im2.mjs} +26 -1
  96. package/dist/{messages-B3Yhiycb2.mjs → chunks/messages-BpJFjSKa.mjs} +27 -2
  97. package/dist/chunks/{messages-BaoJwsEZ.mjs → messages-BqYlq_Bn.mjs} +26 -1
  98. package/dist/chunks/{messages-vN4T4r67.mjs → messages-BtAwCUfD.mjs} +26 -1
  99. package/dist/{messages-Cb3wXGnc.mjs → chunks/messages-Bthbp65G.mjs} +27 -2
  100. package/dist/{messages-x353UCBI.mjs → chunks/messages-BvHMZ8Pi2.mjs} +26 -1
  101. package/dist/{messages-BOE2mzCj2.mjs → chunks/messages-Bw1BE9jW.mjs} +26 -1
  102. package/dist/chunks/{messages-C5aCWL7B.mjs → messages-Bx6Wt285.mjs} +26 -1
  103. package/dist/{messages-C8f1I5EQ2.mjs → chunks/messages-BzslJRYv.mjs} +27 -2
  104. package/dist/chunks/{messages-CZ5Sbf8U.mjs → messages-C02M0Tpw.mjs} +26 -1
  105. package/dist/chunks/{messages-DN-194c32.mjs → messages-C1u3E9qg.mjs} +26 -1
  106. package/dist/chunks/{messages-DdmWzF5M.mjs → messages-C68WgSKk.mjs} +27 -2
  107. package/dist/chunks/{messages-Dgng6KN8.mjs → messages-C8w8JCP0.mjs} +28 -3
  108. package/dist/chunks/{messages-B5fKJXd6.mjs → messages-CFOZdSk4.mjs} +26 -1
  109. package/dist/chunks/{messages-5ArOv8cj.mjs → messages-CGOY79lr.mjs} +26 -1
  110. package/dist/{messages-mipkPgwQ2.mjs → chunks/messages-CGaSMZPu.mjs} +26 -1
  111. package/dist/{messages-Dq_v7slw2.mjs → chunks/messages-CJJgQ0BH.mjs} +26 -1
  112. package/dist/chunks/{messages-DUGEqDEG.mjs → messages-CTD6rtQj2.mjs} +26 -1
  113. package/dist/{messages-DIKCwGog.mjs → chunks/messages-CZymJML9.mjs} +30 -5
  114. package/dist/chunks/{messages-CcyIKgGU.mjs → messages-CfeFJbiv.mjs} +30 -5
  115. package/dist/chunks/{messages-BXSXk3oS2.mjs → messages-Cgatzu_z.mjs} +28 -3
  116. package/dist/{messages-CBPiFbEf2.mjs → chunks/messages-Ch2zBI602.mjs} +26 -1
  117. package/dist/chunks/{messages-yszqJukE.mjs → messages-CiAHsUfO.mjs} +26 -1
  118. package/dist/chunks/{messages-bmwto4UV.mjs → messages-Cuzq-tNW.mjs} +26 -1
  119. package/dist/{messages-JK9Okzsy2.mjs → chunks/messages-Cw4qiMwb.mjs} +26 -1
  120. package/dist/chunks/{messages-DSO2U-ul.mjs → messages-Cyh-mz40.mjs} +26 -1
  121. package/dist/{messages-DbZsJAff.mjs → chunks/messages-D-I2QO8H.mjs} +26 -1
  122. package/dist/chunks/{messages-BhcYsC_M2.mjs → messages-D0D2gruy.mjs} +26 -1
  123. package/dist/{messages-X80Nh0ib.mjs → chunks/messages-D1BKxfLD.mjs} +27 -2
  124. package/dist/chunks/{messages-CjVPwkVy.mjs → messages-D4eDs6R_.mjs} +26 -1
  125. package/dist/{messages-C5Uufygq.mjs → chunks/messages-D9Xr-hES.mjs} +26 -1
  126. package/dist/{messages-DkvQ-6HC2.mjs → chunks/messages-D9eJPHia.mjs} +28 -3
  127. package/dist/chunks/{messages-DRv4g-IA.mjs → messages-DBFWSzKY2.mjs} +26 -1
  128. package/dist/chunks/{messages-SSDr5fGF2.mjs → messages-DC0wu2S7.mjs} +26 -1
  129. package/dist/{messages-Bdk4ocMI.mjs → chunks/messages-DF9o19rG.mjs} +26 -1
  130. package/dist/chunks/{messages-DVKifYlq.mjs → messages-DFS_n986.mjs} +49 -24
  131. package/dist/{messages-CvvbLyTy2.mjs → chunks/messages-DGS4H30T.mjs} +26 -1
  132. package/dist/{messages-PvMdmlxI.mjs → chunks/messages-DKjddpzJ.mjs} +28 -3
  133. package/dist/chunks/{messages-DGD6BiGd.mjs → messages-DMvTdUXC.mjs} +28 -3
  134. package/dist/{messages-CD8K1g_t2.mjs → chunks/messages-DQUX-QYI2.mjs} +26 -1
  135. package/dist/chunks/{messages-CqgEz7C5.mjs → messages-DUigq8FO2.mjs} +26 -1
  136. package/dist/chunks/{messages-ByAqzAhB.mjs → messages-DY0FJdpH.mjs} +26 -1
  137. package/dist/{messages-DACg1XAu.mjs → chunks/messages-DfVXiqt-2.mjs} +26 -1
  138. package/dist/{messages-BYQ769S5.mjs → chunks/messages-DgZc9TJw.mjs} +26 -1
  139. package/dist/{messages-Dj79y02X.mjs → chunks/messages-QD4BCUDP.mjs} +26 -1
  140. package/dist/{messages-BeI2HORe2.mjs → chunks/messages-USmweex9.mjs} +26 -1
  141. package/dist/{messages-CEEzfqMO2.mjs → chunks/messages-a1JTi0Qm.mjs} +29 -4
  142. package/dist/chunks/{messages-Dz3UhEco2.mjs → messages-jcgCHPRn.mjs} +26 -1
  143. package/dist/{messages--cUQf9JX.mjs → chunks/messages-tnnqHpbd.mjs} +27 -2
  144. package/dist/chunks/{messages-DZwCufSb.mjs → messages-vzWKPLJO.mjs} +26 -1
  145. package/dist/chunks/{micromark-extension-math-CCEGWpdz.mjs → micromark-extension-math-Cz_ZZ_0Y.mjs} +1 -1
  146. package/dist/chunks/mindmap-definition-QFDTVHPH-BswFuNN6.mjs +1013 -0
  147. package/dist/chunks/ordinal-D1_lEgAO.mjs +65 -0
  148. package/dist/chunks/packet-4T2RLAQJ-DTUW2U0C.mjs +3 -0
  149. package/dist/chunks/path-6nYPAvNb.mjs +85 -0
  150. package/dist/chunks/pie-ZZUOXDRM-D-umqvEM.mjs +3 -0
  151. package/dist/chunks/pieDiagram-DEJITSTG-1WJgvK1w.mjs +179 -0
  152. package/dist/chunks/quadrantDiagram-34T5L4WZ-B_YH8QGl.mjs +1960 -0
  153. package/dist/chunks/radar-PYXPWWZC-DkQelf08.mjs +3 -0
  154. package/dist/chunks/requirementDiagram-MS252O5E-DRl0YJRI.mjs +2224 -0
  155. package/dist/chunks/rough.esm-CSWJruu5.mjs +1353 -0
  156. package/dist/chunks/sankeyDiagram-XADWPNL6-B-8IrknH.mjs +909 -0
  157. package/dist/chunks/sequenceDiagram-FGHM5R23-DTLb8qmO.mjs +4181 -0
  158. package/dist/chunks/src-CRgEHLPW.mjs +2149 -0
  159. package/dist/chunks/stateDiagram-FHFEXIEX-B0JFjLFy.mjs +218 -0
  160. package/dist/chunks/stateDiagram-v2-QKLJ7IA2-Co9CUU_z.mjs +28 -0
  161. package/dist/chunks/timeline-definition-GMOUNBTQ-CS9KTh-Q.mjs +1084 -0
  162. package/dist/chunks/{tools-DGOsJbHH.mjs → tools-CSYsrnud.mjs} +2116 -1268
  163. package/dist/chunks/treeView-SZITEDCU-DOOoyNP9.mjs +3 -0
  164. package/dist/chunks/treemap-W4RFUUIX-CsOoUA-u.mjs +3 -0
  165. package/dist/chunks/vennDiagram-DHZGUBPP-0BNu5Wna.mjs +1876 -0
  166. package/dist/chunks/wardley-RL74JXVD-CCzZcmEk.mjs +3 -0
  167. package/dist/chunks/wardleyDiagram-NUSXRM2D-Ca9XByNH.mjs +594 -0
  168. package/dist/chunks/xychartDiagram-5P7HB3ND-C8AyKUAE.mjs +2017 -0
  169. package/dist/cli.mjs +1 -1
  170. package/dist/full.mjs +3 -3
  171. package/dist/locales.mjs +80 -67
  172. package/dist/markdown.mjs +2 -2
  173. package/dist/{chunks/messages-9l49jauY.mjs → messages-5jvKxQNu2.mjs} +26 -1
  174. package/dist/{messages-CkySRhtd2.mjs → messages-7QD-X6XT2.mjs} +26 -1
  175. package/dist/{chunks/messages-Btr121zI2.mjs → messages-96iaAUds2.mjs} +27 -2
  176. package/dist/{chunks/messages-BAP2OAQk.mjs → messages-B19o-Teb.mjs} +28 -3
  177. package/dist/{messages-DJU4YLij.mjs → messages-B1ZUQagA.mjs} +26 -1
  178. package/dist/{messages-Dg2CDXZi2.mjs → messages-B7ieAJBd2.mjs} +26 -1
  179. package/dist/{messages-CByBLxWk.mjs → messages-BECMxmfX.mjs} +26 -1
  180. package/dist/{messages-CwCEcbWG.mjs → messages-BIHc0KHY.mjs} +27 -2
  181. package/dist/{messages-D8WvwU42.mjs → messages-BIoeoik5.mjs} +26 -1
  182. package/dist/{messages-D38h5XlF.mjs → messages-BJeGJksD.mjs} +26 -1
  183. package/dist/{messages-Cd23UgLV2.mjs → messages-BRZX964b2.mjs} +27 -2
  184. package/dist/{chunks/messages-B9N__q552.mjs → messages-BTQPpoM42.mjs} +29 -4
  185. package/dist/{messages-CUzBNjnc.mjs → messages-BYNcD6uR.mjs} +26 -1
  186. package/dist/{messages-DjWfVYHS2.mjs → messages-BYmmMDrN2.mjs} +26 -1
  187. package/dist/{chunks/messages-DkTxBa1V.mjs → messages-BbYq1pk-.mjs} +26 -1
  188. package/dist/{chunks/messages-BHhbHLoq.mjs → messages-BiUGXvYr2.mjs} +26 -1
  189. package/dist/{messages-So3SHdIc2.mjs → messages-BiiongNz2.mjs} +26 -1
  190. package/dist/{chunks/messages-BxBID_0B.mjs → messages-Bm0Feca1.mjs} +30 -5
  191. package/dist/{messages-C2veeQpU.mjs → messages-BmAn22OX.mjs} +26 -1
  192. package/dist/{messages-KbYSpNrE.mjs → messages-Bq3F2Tp_.mjs} +26 -1
  193. package/dist/{chunks/messages-Dux1S0-D2.mjs → messages-BsycN_JI2.mjs} +26 -1
  194. package/dist/{messages-DRU_IgoW.mjs → messages-BwHs4cm1.mjs} +30 -5
  195. package/dist/{messages-Cv-DKlZd.mjs → messages-CJTy6JZt.mjs} +26 -1
  196. package/dist/{chunks/messages-D7n_wJK7.mjs → messages-CR_L_UtK.mjs} +26 -1
  197. package/dist/{messages-DnhEzmXJ2.mjs → messages-CSUHBs4c2.mjs} +26 -1
  198. package/dist/{messages-C_HmWyXc2.mjs → messages-CWIXvnDf2.mjs} +26 -1
  199. package/dist/{messages-KSxF8eib.mjs → messages-CcF4y-E4.mjs} +26 -1
  200. package/dist/{chunks/messages-CL3mCbi6.mjs → messages-Ce6KVEbT.mjs} +27 -2
  201. package/dist/{chunks/messages-C-jA6Rf7.mjs → messages-Ci0KqX-J.mjs} +33 -8
  202. package/dist/{chunks/messages-DMyRdafk2.mjs → messages-CjbnogEC.mjs} +26 -1
  203. package/dist/{chunks/messages-BlO_37l_.mjs → messages-CmB406HW.mjs} +28 -3
  204. package/dist/{messages-Cho2VTAX.mjs → messages-CqXtJTpU.mjs} +26 -1
  205. package/dist/{messages-CWEL1WDy2.mjs → messages-D0aw5_0k2.mjs} +28 -3
  206. package/dist/{messages-CgEDVri-2.mjs → messages-D8FQWulF2.mjs} +26 -1
  207. package/dist/{chunks/messages-B5aAzExz.mjs → messages-DBiVgUs2.mjs} +27 -2
  208. package/dist/{chunks/messages-DYizZHT2.mjs → messages-DIJlIqlQ2.mjs} +26 -1
  209. package/dist/{messages-BPL7riv-.mjs → messages-DLX_iBDJ.mjs} +26 -1
  210. package/dist/{messages-vptt-pVF.mjs → messages-DLlc9QPw.mjs} +26 -1
  211. package/dist/{chunks/messages-876bKyUj2.mjs → messages-DMr62KiO2.mjs} +26 -1
  212. package/dist/{chunks/messages-CgedvWCf.mjs → messages-DPA-mMWC2.mjs} +27 -2
  213. package/dist/{messages-vcoib5Ga.mjs → messages-DTh9a8mR.mjs} +26 -1
  214. package/dist/{chunks/messages-DgEGJECT.mjs → messages-DY4IqlhY.mjs} +26 -1
  215. package/dist/{chunks/messages-CdzF0Hvl.mjs → messages-DYTTu0O12.mjs} +26 -1
  216. package/dist/{messages-rbox5gSb2.mjs → messages-DbySKTKt2.mjs} +28 -3
  217. package/dist/{chunks/messages-BGCQCeWd.mjs → messages-Ddnj2iTG2.mjs} +26 -1
  218. package/dist/{chunks/messages-CNEJxD8q2.mjs → messages-DkLU_rWm.mjs} +26 -1
  219. package/dist/{chunks/messages-FYl9woii2.mjs → messages-Dl3Sv6Rq2.mjs} +27 -2
  220. package/dist/{messages-Clsh86WQ.mjs → messages-Dl5Y2-Ia.mjs} +49 -24
  221. package/dist/{chunks/messages-CKRJDX0K2.mjs → messages-DnG0ef8t2.mjs} +28 -3
  222. package/dist/{chunks/messages-CyxDkx8a.mjs → messages-DnGJD4TL.mjs} +26 -1
  223. package/dist/{chunks/messages-DnJHflSh.mjs → messages-Dnp9N6RU2.mjs} +26 -1
  224. package/dist/{chunks/messages-Jps5Tc77.mjs → messages-Dvn35ksS.mjs} +26 -1
  225. package/dist/{messages-ChTWmxS8.mjs → messages-Dw__BcTj.mjs} +26 -1
  226. package/dist/{messages-D7juvhHp.mjs → messages-Dy-Y_nEI.mjs} +26 -1
  227. package/dist/{messages-CNNcKuGH.mjs → messages-E_ZuzGDt.mjs} +26 -1
  228. package/dist/{chunks/messages-DJO0ERQT.mjs → messages-F2xRoY1w.mjs} +26 -1
  229. package/dist/{messages-DqJTZbwt.mjs → messages-Smt4GBbj.mjs} +31 -6
  230. package/dist/{chunks/messages-D8dKkyII2.mjs → messages-aMXpHt5X2.mjs} +26 -1
  231. package/dist/{chunks/messages-DWD0ry9x.mjs → messages-aWZH50vu2.mjs} +28 -3
  232. package/dist/{chunks/messages-BbfLRqLh2.mjs → messages-dv19AkyJ.mjs} +26 -1
  233. package/dist/{chunks/messages-Dw2rmKMi2.mjs → messages-hWwSRF-2.mjs} +26 -1
  234. package/dist/{messages-En8LDjUB.mjs → messages-j7o5rT9s.mjs} +26 -1
  235. package/dist/{chunks/messages-NJsvFwJj.mjs → messages-nUVjeh7K.mjs} +27 -2
  236. package/dist/{messages-Cg1CF4pw.mjs → messages-nlhESX9t.mjs} +26 -1
  237. package/dist/{messages-CSl0Wla62.mjs → messages-rk-A1Wa42.mjs} +28 -3
  238. package/dist/{messages-nOe1gJYu.mjs → messages-xh2eOLvs.mjs} +26 -1
  239. package/dist/{messages-B_sKqaeK.mjs → messages-ynAe7ewZ.mjs} +26 -1
  240. package/dist/react.mjs +2 -2
  241. package/dist/tools.mjs +2 -2
  242. package/dist/vendor.LICENSE.txt +3254 -297
  243. package/package.json +7 -2
  244. package/src/components/constants/data-attributes.ts +0 -2
  245. package/src/components/i18n/locales/am/messages.json +26 -1
  246. package/src/components/i18n/locales/ar/messages.json +26 -1
  247. package/src/components/i18n/locales/az/messages.json +26 -1
  248. package/src/components/i18n/locales/bg/messages.json +26 -1
  249. package/src/components/i18n/locales/bn/messages.json +26 -1
  250. package/src/components/i18n/locales/bs/messages.json +28 -3
  251. package/src/components/i18n/locales/cs/messages.json +30 -5
  252. package/src/components/i18n/locales/da/messages.json +33 -8
  253. package/src/components/i18n/locales/de/messages.json +31 -6
  254. package/src/components/i18n/locales/dv/messages.json +26 -1
  255. package/src/components/i18n/locales/el/messages.json +26 -1
  256. package/src/components/i18n/locales/en/messages.json +13 -0
  257. package/src/components/i18n/locales/es/messages.json +27 -2
  258. package/src/components/i18n/locales/et/messages.json +30 -5
  259. package/src/components/i18n/locales/fa/messages.json +26 -1
  260. package/src/components/i18n/locales/fi/messages.json +26 -1
  261. package/src/components/i18n/locales/fil/messages.json +49 -24
  262. package/src/components/i18n/locales/fr/messages.json +27 -2
  263. package/src/components/i18n/locales/gu/messages.json +26 -1
  264. package/src/components/i18n/locales/he/messages.json +26 -1
  265. package/src/components/i18n/locales/hi/messages.json +26 -1
  266. package/src/components/i18n/locales/hr/messages.json +28 -3
  267. package/src/components/i18n/locales/hu/messages.json +27 -2
  268. package/src/components/i18n/locales/hy/messages.json +26 -1
  269. package/src/components/i18n/locales/id/messages.json +26 -1
  270. package/src/components/i18n/locales/it/messages.json +27 -2
  271. package/src/components/i18n/locales/ja/messages.json +26 -1
  272. package/src/components/i18n/locales/ka/messages.json +26 -1
  273. package/src/components/i18n/locales/km/messages.json +26 -1
  274. package/src/components/i18n/locales/kn/messages.json +26 -1
  275. package/src/components/i18n/locales/ko/messages.json +26 -1
  276. package/src/components/i18n/locales/ku/messages.json +26 -1
  277. package/src/components/i18n/locales/lo/messages.json +26 -1
  278. package/src/components/i18n/locales/lt/messages.json +26 -1
  279. package/src/components/i18n/locales/lv/messages.json +26 -1
  280. package/src/components/i18n/locales/mk/messages.json +26 -1
  281. package/src/components/i18n/locales/ml/messages.json +26 -1
  282. package/src/components/i18n/locales/mn/messages.json +26 -1
  283. package/src/components/i18n/locales/mr/messages.json +26 -1
  284. package/src/components/i18n/locales/ms/messages.json +28 -3
  285. package/src/components/i18n/locales/my/messages.json +26 -1
  286. package/src/components/i18n/locales/ne/messages.json +26 -1
  287. package/src/components/i18n/locales/nl/messages.json +28 -3
  288. package/src/components/i18n/locales/no/messages.json +29 -4
  289. package/src/components/i18n/locales/pa/messages.json +26 -1
  290. package/src/components/i18n/locales/pl/messages.json +27 -2
  291. package/src/components/i18n/locales/ps/messages.json +26 -1
  292. package/src/components/i18n/locales/pt/messages.json +27 -2
  293. package/src/components/i18n/locales/ro/messages.json +27 -2
  294. package/src/components/i18n/locales/ru/messages.json +26 -1
  295. package/src/components/i18n/locales/sd/messages.json +26 -1
  296. package/src/components/i18n/locales/si/messages.json +26 -1
  297. package/src/components/i18n/locales/sk/messages.json +28 -3
  298. package/src/components/i18n/locales/sl/messages.json +28 -3
  299. package/src/components/i18n/locales/sq/messages.json +27 -2
  300. package/src/components/i18n/locales/sr/messages.json +26 -1
  301. package/src/components/i18n/locales/sv/messages.json +28 -3
  302. package/src/components/i18n/locales/sw/messages.json +26 -1
  303. package/src/components/i18n/locales/ta/messages.json +26 -1
  304. package/src/components/i18n/locales/te/messages.json +26 -1
  305. package/src/components/i18n/locales/th/messages.json +26 -1
  306. package/src/components/i18n/locales/tr/messages.json +26 -1
  307. package/src/components/i18n/locales/ug/messages.json +26 -1
  308. package/src/components/i18n/locales/uk/messages.json +26 -1
  309. package/src/components/i18n/locales/ur/messages.json +26 -1
  310. package/src/components/i18n/locales/vi/messages.json +26 -1
  311. package/src/components/i18n/locales/yi/messages.json +26 -1
  312. package/src/components/i18n/locales/zh/messages.json +26 -1
  313. package/src/components/icons/index.ts +38 -0
  314. package/src/components/modules/ui.ts +0 -13
  315. package/src/stories/EditorModes.stories.ts +0 -60
  316. package/src/styles/main.css +39 -1
  317. package/src/tools/callout/emoji-picker/index.ts +3 -2
  318. package/src/tools/code/code-keyboard.ts +16 -9
  319. package/src/tools/code/constants.ts +26 -3
  320. package/src/tools/code/dom-builder.ts +40 -5
  321. package/src/tools/code/highlight-applier.ts +229 -0
  322. package/src/tools/code/index.ts +141 -1
  323. package/src/tools/code/mermaid-loader.ts +45 -0
  324. package/src/tools/code/shiki-loader.ts +135 -0
  325. package/src/tools/table/core/table-commands.ts +16 -0
  326. package/src/tools/table/core/table-controller.ts +29 -0
  327. package/src/tools/table/core/table-events.ts +17 -0
  328. package/src/tools/table/index.ts +194 -11
  329. package/src/tools/table/table-cell-blocks.ts +9 -6
  330. package/src/tools/table/table-cell-clipboard.ts +6 -1
  331. package/src/tools/table/table-cell-placement-picker.ts +133 -0
  332. package/src/tools/table/table-cell-selection.ts +174 -19
  333. package/src/tools/table/table-core.ts +321 -113
  334. package/src/tools/table/table-map.ts +279 -0
  335. package/src/tools/table/table-model.ts +901 -1
  336. package/src/tools/table/table-operations.ts +78 -44
  337. package/src/tools/table/table-resize.ts +19 -17
  338. package/src/tools/table/table-row-col-drag.ts +24 -10
  339. package/src/tools/table/types.ts +24 -2
  340. package/types/data-attributes.d.ts +0 -1
  341. package/types/tools/code.d.ts +2 -0
  342. /package/dist/chunks/{am-CS-JjQ0N.mjs → am-rVzV1W41.mjs} +0 -0
  343. /package/dist/chunks/{ar-Dt4XzR5U.mjs → ar-C710lkoH.mjs} +0 -0
  344. /package/dist/chunks/{az-CaDTXby8.mjs → az-BOp1pgua.mjs} +0 -0
  345. /package/dist/chunks/{bg-D1pLog-R.mjs → bg-CL9p09ZD.mjs} +0 -0
  346. /package/dist/chunks/{bn-Db_ae60m.mjs → bn-CNmSeyAy.mjs} +0 -0
  347. /package/dist/chunks/{bs-DJTg1R9e.mjs → bs-BRzMGqzk.mjs} +0 -0
  348. /package/dist/chunks/{cs-_Gc21gSL.mjs → cs-BYPBLmnF.mjs} +0 -0
  349. /package/dist/chunks/{da-xDB8uhCd.mjs → da-CBC_LR1c.mjs} +0 -0
  350. /package/dist/chunks/{de-B6gVjh1Z.mjs → de-DxRFMoAj.mjs} +0 -0
  351. /package/dist/chunks/{el-ClbRSnOs.mjs → el-Bk6YbySf.mjs} +0 -0
  352. /package/dist/chunks/{es-CuY9rnLK.mjs → es-DpT3FCMR.mjs} +0 -0
  353. /package/dist/chunks/{et-BLu5lDVc.mjs → et-DE9Dr_g9.mjs} +0 -0
  354. /package/dist/chunks/{fa-P3gnrZH8.mjs → fa-Banj1QUE.mjs} +0 -0
  355. /package/dist/chunks/{fi-B8PVHLjq.mjs → fi-DfN3M5ER.mjs} +0 -0
  356. /package/dist/chunks/{fil-B9JII5iF.mjs → fil-DbCsRS1d.mjs} +0 -0
  357. /package/dist/chunks/{fr-BWLDZdcc.mjs → fr-D1clKhgt.mjs} +0 -0
  358. /package/dist/chunks/{gu-BH3R_s4c.mjs → gu-1CsZyRwT.mjs} +0 -0
  359. /package/dist/chunks/{he-CCmeCVR_.mjs → he-qQdnL6eK.mjs} +0 -0
  360. /package/dist/chunks/{hi-BBav00DN.mjs → hi-DxM0Nff1.mjs} +0 -0
  361. /package/dist/chunks/{hr-B5ZX0r9G.mjs → hr-Onldyi-u.mjs} +0 -0
  362. /package/dist/chunks/{hu-1jgDa3YU.mjs → hu-CAn3pBuY.mjs} +0 -0
  363. /package/dist/chunks/{hy-LX4Kp2PE.mjs → hy-D43q7NxE.mjs} +0 -0
  364. /package/dist/chunks/{i18next-KNC_XV5x.mjs → i18next-BBGW2sDE.mjs} +0 -0
  365. /package/dist/chunks/{id-CcG40D1H.mjs → id-Xrw5Dd0Y.mjs} +0 -0
  366. /package/dist/chunks/{it-Cb8_K72W.mjs → it-CA9ZDMSc.mjs} +0 -0
  367. /package/dist/chunks/{ja-ipCH91mv.mjs → ja-D0J6WRFh.mjs} +0 -0
  368. /package/dist/chunks/{ka-BRvREIgq.mjs → ka-BZL7xDuY.mjs} +0 -0
  369. /package/dist/chunks/{km-BJwVw7Fg.mjs → km-BimgQZVU.mjs} +0 -0
  370. /package/dist/chunks/{kn-BPgUazCC.mjs → kn-C2n2cPHK.mjs} +0 -0
  371. /package/dist/chunks/{ko-CQLzxe7k.mjs → ko-n4Cn93D3.mjs} +0 -0
  372. /package/dist/chunks/{ku-BHhHu8Iz.mjs → ku-BYZCgT44.mjs} +0 -0
  373. /package/dist/chunks/{lo-DsTgYblY.mjs → lo-DVXiAE4N.mjs} +0 -0
  374. /package/dist/chunks/{lt-CDzHJm71.mjs → lt-B9KlQFnY.mjs} +0 -0
  375. /package/dist/chunks/{lv-MLLIAnIX.mjs → lv-BINeOdyx.mjs} +0 -0
  376. /package/dist/chunks/{mdast-util-math-yS0EygZV.mjs → mdast-util-math-CHYUxOHk.mjs} +0 -0
  377. /package/dist/chunks/{mk-DQdmUquZ.mjs → mk-_-QrPrLN.mjs} +0 -0
  378. /package/dist/chunks/{ml-DqehZnra.mjs → ml-KvJSC1KT.mjs} +0 -0
  379. /package/dist/chunks/{mn-4cFkKFjW.mjs → mn-CjFjWnRG.mjs} +0 -0
  380. /package/dist/chunks/{mr-DWiztOP4.mjs → mr-DqAZ7FRX.mjs} +0 -0
  381. /package/dist/chunks/{ms-BSz-iSnc.mjs → ms-BZcV4UG_.mjs} +0 -0
  382. /package/dist/chunks/{my-DbtbM1MW.mjs → my-97SC9jYN.mjs} +0 -0
  383. /package/dist/chunks/{ne-CqALWw_f.mjs → ne-Bs-M2TyF.mjs} +0 -0
  384. /package/dist/chunks/{nl-D_ra6RvH.mjs → nl-2ZwQilo-.mjs} +0 -0
  385. /package/dist/chunks/{no-Cg_kz_jl.mjs → no-fOQTpFq1.mjs} +0 -0
  386. /package/dist/chunks/{notifier-BOwxj_Ok.mjs → notifier-B1zCi9G1.mjs} +0 -0
  387. /package/dist/chunks/{pa-NLAsNqwY.mjs → pa-DLOqkMi0.mjs} +0 -0
  388. /package/dist/chunks/{pl-NHKp4YDg.mjs → pl-FYs9QrXU.mjs} +0 -0
  389. /package/dist/chunks/{ps-D1zEqNeg.mjs → ps-CTXe6pSe.mjs} +0 -0
  390. /package/dist/chunks/{pt-DBtqbUEB.mjs → pt-B1X4x7d1.mjs} +0 -0
  391. /package/dist/chunks/{ro-lqr63ai5.mjs → ro-Bf7S2FaR.mjs} +0 -0
  392. /package/dist/chunks/{ru-BycNnDyN.mjs → ru-B8lqnu_j.mjs} +0 -0
  393. /package/dist/chunks/{sd-DpHpIN9Z.mjs → sd-CHRYJm2r.mjs} +0 -0
  394. /package/dist/chunks/{si-BwiwaC7N.mjs → si-CI0Hs6vH.mjs} +0 -0
  395. /package/dist/chunks/{sk-CqRHT2Gp.mjs → sk-Bdvq1Kb_.mjs} +0 -0
  396. /package/dist/chunks/{sl-DA348uQ_.mjs → sl-B_qiFTV5.mjs} +0 -0
  397. /package/dist/chunks/{sq-D7JNgve1.mjs → sq-E0j1hysP.mjs} +0 -0
  398. /package/dist/chunks/{sr-D8RK6Kwp.mjs → sr-VPpVNTZw.mjs} +0 -0
  399. /package/dist/chunks/{sv-dwgT67ZG.mjs → sv-gKmDSR3d.mjs} +0 -0
  400. /package/dist/chunks/{sw-ZRRJnkem.mjs → sw-zeFLiO23.mjs} +0 -0
  401. /package/dist/chunks/{ta-5x4L5Krl.mjs → ta-Ci-j89hR.mjs} +0 -0
  402. /package/dist/chunks/{te-BZpEimwA.mjs → te-qyMI0M7a.mjs} +0 -0
  403. /package/dist/chunks/{th-Bhr-33kv.mjs → th-DPxHtpdb.mjs} +0 -0
  404. /package/dist/chunks/{tr-6tSNKGNB.mjs → tr-CRV6GS-G.mjs} +0 -0
  405. /package/dist/chunks/{ug-_e-jvr2b.mjs → ug-DW0YFpo5.mjs} +0 -0
  406. /package/dist/chunks/{uk-DooSc2Ja.mjs → uk-ssteuphK.mjs} +0 -0
  407. /package/dist/chunks/{ur-rb-krkIO.mjs → ur-qhY3-jY7.mjs} +0 -0
  408. /package/dist/chunks/{vi-CQkLn2AQ.mjs → vi-CHriMMC8.mjs} +0 -0
  409. /package/dist/chunks/{zh-CXQ40Q2_.mjs → zh-BJktawVN.mjs} +0 -0
@@ -1,6 +1,18 @@
1
- import type { CellContent, LegacyCellContent, TableData } from './types';
1
+ import type { CellContent, CellPlacement, LegacyCellContent, TableData } from './types';
2
2
  import { isCellWithBlocks } from './types';
3
3
 
4
+ export interface SelectionRect {
5
+ minRow: number;
6
+ maxRow: number;
7
+ minCol: number;
8
+ maxCol: number;
9
+ }
10
+
11
+ export interface MergeResult {
12
+ /** Block IDs that were moved from absorbed cells into the origin cell. */
13
+ blocksToRelocate: string[];
14
+ }
15
+
4
16
  /**
5
17
  * Validate that a string is a safe CSS color value.
6
18
  *
@@ -120,6 +132,22 @@ export class TableModel {
120
132
  cell.textColor = c.textColor;
121
133
  }
122
134
 
135
+ if (c.placement !== undefined) {
136
+ cell.placement = c.placement;
137
+ }
138
+
139
+ if (c.colspan !== undefined && c.colspan > 1) {
140
+ cell.colspan = c.colspan;
141
+ }
142
+
143
+ if (c.rowspan !== undefined && c.rowspan > 1) {
144
+ cell.rowspan = c.rowspan;
145
+ }
146
+
147
+ if (c.mergedInto !== undefined) {
148
+ cell.mergedInto = [...c.mergedInto];
149
+ }
150
+
123
151
  return cell;
124
152
  })
125
153
  ),
@@ -269,6 +297,25 @@ export class TableModel {
269
297
  return this.contentGrid[row][col].textColor;
270
298
  }
271
299
 
300
+ setCellPlacement(row: number, col: number, placement: CellPlacement | undefined): void {
301
+ if (!this.isInBounds(row, col)) {
302
+ return;
303
+ }
304
+ if (placement === undefined) {
305
+ delete this.contentGrid[row][col].placement;
306
+ } else {
307
+ this.contentGrid[row][col].placement = placement;
308
+ }
309
+ }
310
+
311
+ getCellPlacement(row: number, col: number): CellPlacement | undefined {
312
+ if (!this.isInBounds(row, col)) {
313
+ return undefined;
314
+ }
315
+
316
+ return this.contentGrid[row][col].placement;
317
+ }
318
+
272
319
  // ─── Row operations ─────────────────────────────────────────────
273
320
 
274
321
  /**
@@ -283,6 +330,8 @@ export class TableModel {
283
330
  const newRow: CellContent[] = Array.from({ length: colCount }, () => ({ blocks: [] }));
284
331
 
285
332
  this.contentGrid.splice(clampedIndex, 0, newRow);
333
+ this.shiftMergedIntoRows(clampedIndex, 1);
334
+ this.expandSpansForInsertedRow(clampedIndex);
286
335
  this.rebuildBlockCellMap();
287
336
 
288
337
  return {
@@ -300,6 +349,8 @@ export class TableModel {
300
349
  return { type: 'delete-row', index, blocksToDelete: [] };
301
350
  }
302
351
 
352
+ this.contractSpansForDeletedRow(index);
353
+
303
354
  const blocksToDelete = this.collectBlocksInRow(index);
304
355
 
305
356
  this.contentGrid.splice(index, 1);
@@ -308,6 +359,7 @@ export class TableModel {
308
359
  this.blockCellMap.delete(id);
309
360
  }
310
361
 
362
+ this.shiftMergedIntoRows(index, -1);
311
363
  this.rebuildBlockCellMap();
312
364
 
313
365
  return { type: 'delete-row', index, blocksToDelete };
@@ -321,9 +373,14 @@ export class TableModel {
321
373
  return { type: 'move-row', index: from, toIndex: to };
322
374
  }
323
375
 
376
+ if (this.isRowInvolvedInMerge(from)) {
377
+ return { type: 'move-row', index: from, toIndex: to };
378
+ }
379
+
324
380
  const [moved] = this.contentGrid.splice(from, 1);
325
381
 
326
382
  this.contentGrid.splice(to, 0, moved);
383
+ this.rebuildMergedIntoRowCoordinates(from, to);
327
384
  this.rebuildBlockCellMap();
328
385
 
329
386
  return { type: 'move-row', index: from, toIndex: to };
@@ -356,6 +413,8 @@ export class TableModel {
356
413
  this.colWidthsValue.splice(clampedIndex, 0, insertWidth);
357
414
  }
358
415
 
416
+ this.shiftMergedIntoCols(clampedIndex, 1);
417
+ this.expandSpansForInsertedCol(clampedIndex);
359
418
  this.rebuildBlockCellMap();
360
419
 
361
420
  return {
@@ -373,6 +432,8 @@ export class TableModel {
373
432
  return { type: 'delete-column', index, blocksToDelete: [] };
374
433
  }
375
434
 
435
+ this.contractSpansForDeletedCol(index);
436
+
376
437
  const blocksToDelete = this.collectBlocksInColumn(index);
377
438
 
378
439
  for (const row of this.contentGrid) {
@@ -391,6 +452,7 @@ export class TableModel {
391
452
  this.colWidthsValue = undefined;
392
453
  }
393
454
 
455
+ this.shiftMergedIntoCols(index, -1);
394
456
  this.rebuildBlockCellMap();
395
457
 
396
458
  return { type: 'delete-column', index, blocksToDelete };
@@ -404,6 +466,10 @@ export class TableModel {
404
466
  return { type: 'move-column', index: from, toIndex: to };
405
467
  }
406
468
 
469
+ if (this.isColInvolvedInMerge(from)) {
470
+ return { type: 'move-column', index: from, toIndex: to };
471
+ }
472
+
407
473
  for (const row of this.contentGrid) {
408
474
  const [moved] = row.splice(from, 1);
409
475
 
@@ -416,6 +482,7 @@ export class TableModel {
416
482
  this.colWidthsValue.splice(to, 0, movedWidth);
417
483
  }
418
484
 
485
+ this.rebuildMergedIntoColCoordinates(from, to);
419
486
  this.rebuildBlockCellMap();
420
487
 
421
488
  return { type: 'move-column', index: from, toIndex: to };
@@ -438,6 +505,247 @@ export class TableModel {
438
505
  this.rebuildBlockCellMap();
439
506
  }
440
507
 
508
+ // ─── Merge / Split ──────────────────────────────────────────────
509
+
510
+ /**
511
+ * Check whether the given rectangle of cells can be merged.
512
+ * Returns true when the selection contains at least 2 grid positions,
513
+ * is fully in-bounds, and no existing merged cell partially overlaps
514
+ * the selection boundary.
515
+ */
516
+ canMergeCells(rect: SelectionRect): boolean {
517
+ const { minRow, maxRow, minCol, maxCol } = rect;
518
+
519
+ // Must span at least 2 cells
520
+ if (minRow === maxRow && minCol === maxCol) {
521
+ return false;
522
+ }
523
+
524
+ // Bounds check
525
+ if (minRow < 0 || maxRow >= this.rows || minCol < 0 || maxCol >= this.cols) {
526
+ return false;
527
+ }
528
+
529
+ // Check that no merged cell partially overlaps the selection boundary.
530
+ // A merged cell is allowed if it's fully inside the selection.
531
+ return this.contentGrid.slice(minRow, maxRow + 1).every((row, ri) => {
532
+ const r = minRow + ri;
533
+
534
+ return row.slice(minCol, maxCol + 1).every((cell, ci) => {
535
+ const c = minCol + ci;
536
+
537
+ // Check origin cells whose span extends beyond the selection
538
+ const colspan = cell.colspan ?? 1;
539
+ const rowspan = cell.rowspan ?? 1;
540
+
541
+ if (colspan > 1 || rowspan > 1) {
542
+ if (r + rowspan - 1 > maxRow || c + colspan - 1 > maxCol) {
543
+ return false;
544
+ }
545
+ }
546
+
547
+ // Check spanned cells whose origin is outside the selection
548
+ if (cell.mergedInto !== undefined) {
549
+ const [originRow, originCol] = cell.mergedInto;
550
+
551
+ if (originRow < minRow || originCol < minCol) {
552
+ return false;
553
+ }
554
+ }
555
+
556
+ return true;
557
+ });
558
+ });
559
+ }
560
+
561
+ /**
562
+ * Merge cells in the given rectangle. The top-left cell becomes the
563
+ * origin with colspan/rowspan set. All other cells in the rectangle
564
+ * become spanned (mergedInto pointing to origin, blocks emptied).
565
+ *
566
+ * Blocks from absorbed cells are concatenated into the origin cell
567
+ * in row-major order.
568
+ */
569
+ mergeCells(rect: SelectionRect): MergeResult {
570
+ const { minRow, maxRow, minCol, maxCol } = rect;
571
+ const result: MergeResult = { blocksToRelocate: [] };
572
+
573
+ if (!this.canMergeCells(rect)) {
574
+ return result;
575
+ }
576
+
577
+ const origin = this.contentGrid[minRow][minCol];
578
+
579
+ // First, if any cell in the selection is itself an origin of a merge,
580
+ // split it so we work with flat cells
581
+ this.contentGrid.slice(minRow, maxRow + 1).forEach((row, ri) => {
582
+ const r = minRow + ri;
583
+
584
+ row.slice(minCol, maxCol + 1).forEach((cell, ci) => {
585
+ const c = minCol + ci;
586
+
587
+ if (r === minRow && c === minCol) {
588
+ return;
589
+ }
590
+
591
+ if ((cell.colspan ?? 1) > 1 || (cell.rowspan ?? 1) > 1) {
592
+ this.splitCellInternal(r, c);
593
+ }
594
+ });
595
+ });
596
+
597
+ // Also split the origin if it was previously merged
598
+ if ((origin.colspan ?? 1) > 1 || (origin.rowspan ?? 1) > 1) {
599
+ this.splitCellInternal(minRow, minCol);
600
+ }
601
+
602
+ // Collect blocks from all cells in row-major order and move to origin
603
+ const collectedBlocks: string[] = [];
604
+
605
+ this.contentGrid.slice(minRow, maxRow + 1).forEach((_row, ri) => {
606
+ const r = minRow + ri;
607
+
608
+ this.contentGrid[r].slice(minCol, maxCol + 1).forEach((_cell, ci) => {
609
+ const c = minCol + ci;
610
+ const gridCell = this.contentGrid[r][c];
611
+
612
+ for (const blockId of gridCell.blocks) {
613
+ collectedBlocks.push(blockId);
614
+
615
+ if (r !== minRow || c !== minCol) {
616
+ result.blocksToRelocate.push(blockId);
617
+ }
618
+ }
619
+
620
+ // Clear non-origin cells
621
+ if (r !== minRow || c !== minCol) {
622
+ gridCell.blocks = [];
623
+ gridCell.mergedInto = [minRow, minCol];
624
+ delete gridCell.colspan;
625
+ delete gridCell.rowspan;
626
+ }
627
+ });
628
+ });
629
+
630
+ // Set origin cell
631
+ origin.blocks = collectedBlocks;
632
+ origin.colspan = maxCol - minCol + 1;
633
+ origin.rowspan = maxRow - minRow + 1;
634
+ delete origin.mergedInto;
635
+ // Reset placement to default (top-left) on merge
636
+ delete origin.placement;
637
+
638
+ // Normalize: remove colspan/rowspan if 1
639
+ if (origin.colspan === 1) {
640
+ delete origin.colspan;
641
+ }
642
+
643
+ if (origin.rowspan === 1) {
644
+ delete origin.rowspan;
645
+ }
646
+
647
+ this.rebuildBlockCellMap();
648
+
649
+ return result;
650
+ }
651
+
652
+ /**
653
+ * Split a merged cell at (row, col) back into individual cells.
654
+ * All content stays in the origin cell; freed cells become empty.
655
+ * No-op if the cell is not a merge origin.
656
+ */
657
+ splitCell(row: number, col: number): void {
658
+ if (!this.isInBounds(row, col)) {
659
+ return;
660
+ }
661
+
662
+ const cell = this.contentGrid[row][col];
663
+
664
+ if ((cell.colspan ?? 1) <= 1 && (cell.rowspan ?? 1) <= 1) {
665
+ return;
666
+ }
667
+
668
+ this.splitCellInternal(row, col);
669
+ this.rebuildBlockCellMap();
670
+ }
671
+
672
+ /**
673
+ * Returns true if the cell at (row, col) is the origin of a merge
674
+ * (has colspan > 1 or rowspan > 1).
675
+ */
676
+ isMergedCell(row: number, col: number): boolean {
677
+ if (!this.isInBounds(row, col)) {
678
+ return false;
679
+ }
680
+
681
+ const cell = this.contentGrid[row][col];
682
+
683
+ return (cell.colspan ?? 1) > 1 || (cell.rowspan ?? 1) > 1;
684
+ }
685
+
686
+ /**
687
+ * Returns true if the cell at (row, col) is covered by another cell's merge
688
+ * (has mergedInto set).
689
+ */
690
+ isSpannedCell(row: number, col: number): boolean {
691
+ if (!this.isInBounds(row, col)) {
692
+ return false;
693
+ }
694
+
695
+ return this.contentGrid[row][col].mergedInto !== undefined;
696
+ }
697
+
698
+ /**
699
+ * Get the colspan and rowspan of the cell at (row, col).
700
+ * Returns {colspan: 1, rowspan: 1} for regular/spanned cells.
701
+ */
702
+ getCellSpan(row: number, col: number): { colspan: number; rowspan: number } {
703
+ if (!this.isInBounds(row, col)) {
704
+ return { colspan: 1, rowspan: 1 };
705
+ }
706
+
707
+ const cell = this.contentGrid[row][col];
708
+
709
+ return {
710
+ colspan: cell.colspan ?? 1,
711
+ rowspan: cell.rowspan ?? 1,
712
+ };
713
+ }
714
+
715
+ /**
716
+ * Internal split that doesn't rebuild the block cell map.
717
+ * Used by mergeCells to flatten existing merges before re-merging.
718
+ */
719
+ private splitCellInternal(row: number, col: number): void {
720
+ const cell = this.contentGrid[row][col];
721
+ const colspan = cell.colspan ?? 1;
722
+ const rowspan = cell.rowspan ?? 1;
723
+
724
+ // Clear spanned cells
725
+ this.contentGrid.slice(row, Math.min(row + rowspan, this.rows)).forEach((_gridRow, ri) => {
726
+ const r = row + ri;
727
+
728
+ this.contentGrid[r].slice(col, Math.min(col + colspan, this.cols)).forEach((_spanned, ci) => {
729
+ const c = col + ci;
730
+
731
+ if (r === row && c === col) {
732
+ return;
733
+ }
734
+
735
+ const spanned = this.contentGrid[r][c];
736
+
737
+ delete spanned.mergedInto;
738
+ spanned.blocks = [];
739
+ delete spanned.placement;
740
+ });
741
+ });
742
+
743
+ // Reset origin
744
+ delete cell.colspan;
745
+ delete cell.rowspan;
746
+ delete cell.placement;
747
+ }
748
+
441
749
  // ─── Metadata setters ──────────────────────────────────────────
442
750
 
443
751
  setWithHeadings(value: boolean): void {
@@ -526,6 +834,90 @@ export class TableModel {
526
834
  });
527
835
  });
528
836
 
837
+ // Invariant 5: merge spans in bounds
838
+ this.contentGrid.forEach((row, r) => {
839
+ row.forEach((cell, c) => {
840
+ const colspan = cell.colspan ?? 1;
841
+ const rowspan = cell.rowspan ?? 1;
842
+
843
+ if (colspan > 1 || rowspan > 1) {
844
+ if (r + rowspan > this.contentGrid.length || c + colspan > (this.contentGrid[0]?.length ?? 0)) {
845
+ throw new Error(
846
+ `Invariant violation: origin [${r},${c}] span extends beyond grid bounds (colspan=${colspan}, rowspan=${rowspan}, rows=${this.contentGrid.length}, cols=${this.contentGrid[0]?.length ?? 0})`
847
+ );
848
+ }
849
+ }
850
+ });
851
+ });
852
+
853
+ // Invariant 6: mergedInto references are valid
854
+ this.contentGrid.forEach((row, r) => {
855
+ row.forEach((cell, c) => {
856
+ if (cell.mergedInto === undefined) {
857
+ return;
858
+ }
859
+
860
+ const [originRow, originCol] = cell.mergedInto;
861
+
862
+ // Must be in bounds
863
+ if (originRow < 0 || originRow >= this.contentGrid.length ||
864
+ originCol < 0 || originCol >= (this.contentGrid[0]?.length ?? 0)) {
865
+ throw new Error(
866
+ `Invariant violation: mergedInto at [${r},${c}] points to out-of-bounds [${originRow},${originCol}]`
867
+ );
868
+ }
869
+
870
+ // Must point to a merge origin
871
+ const origin = this.contentGrid[originRow][originCol];
872
+ const oColspan = origin.colspan ?? 1;
873
+ const oRowspan = origin.rowspan ?? 1;
874
+
875
+ if (oColspan <= 1 && oRowspan <= 1) {
876
+ throw new Error(
877
+ `Invariant violation: mergedInto at [${r},${c}] points to [${originRow},${originCol}] which is not a merge origin`
878
+ );
879
+ }
880
+
881
+ // Must be within the origin's span
882
+ if (r < originRow || r >= originRow + oRowspan ||
883
+ c < originCol || c >= originCol + oColspan) {
884
+ throw new Error(
885
+ `Invariant violation: mergedInto at [${r},${c}] is outside the span of origin [${originRow},${originCol}] (colspan=${oColspan}, rowspan=${oRowspan})`
886
+ );
887
+ }
888
+ });
889
+ });
890
+
891
+ // Invariant 7: every cell within an origin's span has mergedInto (except the origin itself)
892
+ this.contentGrid.forEach((row, r) => {
893
+ row.forEach((cell, c) => {
894
+ const colspan = cell.colspan ?? 1;
895
+ const rowspan = cell.rowspan ?? 1;
896
+
897
+ if (colspan <= 1 && rowspan <= 1) {
898
+ return;
899
+ }
900
+
901
+ this.contentGrid.slice(r, r + rowspan).forEach((spanRow, dri) => {
902
+ const dr = r + dri;
903
+
904
+ spanRow.slice(c, c + colspan).forEach((spanned, dci) => {
905
+ const dc = c + dci;
906
+
907
+ if (dr === r && dc === c) {
908
+ return;
909
+ }
910
+
911
+ if (!spanned?.mergedInto) {
912
+ throw new Error(
913
+ `Invariant violation: cell [${dr},${dc}] is within span of origin [${r},${c}] but has no mergedInto`
914
+ );
915
+ }
916
+ });
917
+ });
918
+ });
919
+ });
920
+
529
921
  // Check map doesn't have extra entries
530
922
  if (this.blockCellMap.size !== seenBlocks.size) {
531
923
  throw new Error(
@@ -534,6 +926,498 @@ export class TableModel {
534
926
  }
535
927
  }
536
928
 
929
+ // ─── Merge-aware structural helpers ─────────────────────────────
930
+
931
+ /**
932
+ * Shift mergedInto row coordinates for all cells where mergedInto[0] >= startRow.
933
+ * Called after inserting (delta=1) or deleting (delta=-1) a row.
934
+ */
935
+ private shiftMergedIntoRows(startRow: number, delta: number): void {
936
+ this.contentGrid.forEach((_row, r) => {
937
+ this.contentGrid[r].forEach((_cell, c) => {
938
+ const gridCell = this.contentGrid[r][c];
939
+
940
+ if (gridCell.mergedInto !== undefined && gridCell.mergedInto[0] >= startRow) {
941
+ gridCell.mergedInto = [gridCell.mergedInto[0] + delta, gridCell.mergedInto[1]];
942
+ }
943
+ });
944
+ });
945
+ }
946
+
947
+ /**
948
+ * Shift mergedInto col coordinates for all cells where mergedInto[1] >= startCol.
949
+ * Called after inserting (delta=1) or deleting (delta=-1) a column.
950
+ */
951
+ private shiftMergedIntoCols(startCol: number, delta: number): void {
952
+ this.contentGrid.forEach((_row, r) => {
953
+ this.contentGrid[r].forEach((_cell, c) => {
954
+ const gridCell = this.contentGrid[r][c];
955
+
956
+ if (gridCell.mergedInto !== undefined && gridCell.mergedInto[1] >= startCol) {
957
+ gridCell.mergedInto = [gridCell.mergedInto[0], gridCell.mergedInto[1] + delta];
958
+ }
959
+ });
960
+ });
961
+ }
962
+
963
+ /**
964
+ * After inserting a row at insertedRow, find origin cells above whose rowspan
965
+ * crosses the insertion point, increment their rowspan, and mark new cells as covered.
966
+ */
967
+ private expandSpansForInsertedRow(insertedRow: number): void {
968
+ this.contentGrid.forEach((_row, r) => {
969
+ this.contentGrid[r].forEach((_cell, c) => {
970
+ const gridCell = this.contentGrid[r][c];
971
+ const rowspan = gridCell.rowspan ?? 1;
972
+ const colspan = gridCell.colspan ?? 1;
973
+
974
+ if (rowspan <= 1 && colspan <= 1) {
975
+ return;
976
+ }
977
+
978
+ if (r >= insertedRow || r + rowspan <= insertedRow) {
979
+ return;
980
+ }
981
+
982
+ // Increment rowspan to absorb the new row
983
+ gridCell.rowspan = rowspan + 1;
984
+
985
+ // Mark the new row's cells within the colspan as covered
986
+ this.markInsertedRowCells(insertedRow, r, c, colspan);
987
+ });
988
+ });
989
+ }
990
+
991
+ private markInsertedRowCells(insertedRow: number, originRow: number, originCol: number, colspan: number): void {
992
+ this.contentGrid[insertedRow].slice(originCol, originCol + colspan).forEach((_newCell, ci) => {
993
+ const dc = originCol + ci;
994
+
995
+ if (dc === originCol && originRow === insertedRow) {
996
+ return;
997
+ }
998
+ const gridCell = this.contentGrid[insertedRow][dc];
999
+
1000
+ gridCell.mergedInto = [originRow, originCol];
1001
+ gridCell.blocks = [];
1002
+ });
1003
+ }
1004
+
1005
+ /**
1006
+ * After inserting a column at insertedCol, find origin cells to the left whose colspan
1007
+ * crosses the insertion point, increment their colspan, and mark new cells as covered.
1008
+ */
1009
+ private expandSpansForInsertedCol(insertedCol: number): void {
1010
+ this.contentGrid.forEach((_row, r) => {
1011
+ this.contentGrid[r].forEach((_cell, c) => {
1012
+ const gridCell = this.contentGrid[r][c];
1013
+ const rowspan = gridCell.rowspan ?? 1;
1014
+ const colspan = gridCell.colspan ?? 1;
1015
+
1016
+ if (rowspan <= 1 && colspan <= 1) {
1017
+ return;
1018
+ }
1019
+
1020
+ if (c >= insertedCol || c + colspan <= insertedCol) {
1021
+ return;
1022
+ }
1023
+
1024
+ gridCell.colspan = colspan + 1;
1025
+
1026
+ // Mark the new column's cells within the rowspan as covered
1027
+ this.markInsertedColCells(insertedCol, r, c, rowspan);
1028
+ });
1029
+ });
1030
+ }
1031
+
1032
+ private markInsertedColCells(insertedCol: number, originRow: number, originCol: number, rowspan: number): void {
1033
+ this.contentGrid.slice(originRow, originRow + rowspan).forEach((_gridRow, ri) => {
1034
+ const dr = originRow + ri;
1035
+
1036
+ if (dr === originRow && insertedCol === originCol) {
1037
+ return;
1038
+ }
1039
+ const gridCell = this.contentGrid[dr][insertedCol];
1040
+
1041
+ gridCell.mergedInto = [originRow, originCol];
1042
+ gridCell.blocks = [];
1043
+ });
1044
+ }
1045
+
1046
+ /**
1047
+ * Before deleting a row, handle merge origins and covered cells in that row.
1048
+ * - If a cell is a merge origin with rowspan > 1: transfer to the row below.
1049
+ * - If a cell has mergedInto pointing to a different row: decrement origin's rowspan.
1050
+ */
1051
+ private contractSpansForDeletedRow(rowIndex: number): void {
1052
+ const row = this.contentGrid[rowIndex];
1053
+
1054
+ row.forEach((_cell, c) => {
1055
+ const gridCell = this.contentGrid[rowIndex][c];
1056
+
1057
+ if ((gridCell.colspan ?? 1) > 1 || (gridCell.rowspan ?? 1) > 1) {
1058
+ this.handleOriginInDeletedRow(rowIndex, c);
1059
+ } else if (gridCell.mergedInto !== undefined) {
1060
+ this.handleCoveredInDeletedRow(rowIndex, c);
1061
+ }
1062
+ });
1063
+ }
1064
+
1065
+ private handleOriginInDeletedRow(rowIndex: number, c: number): void {
1066
+ const cell = this.contentGrid[rowIndex][c];
1067
+ const rowspan = cell.rowspan ?? 1;
1068
+ const colspan = cell.colspan ?? 1;
1069
+
1070
+ if (rowspan <= 1) {
1071
+ return;
1072
+ }
1073
+
1074
+ const newRowspan = rowspan - 1;
1075
+ const nextRow = rowIndex + 1;
1076
+
1077
+ if (nextRow < this.contentGrid.length) {
1078
+ this.transferOriginToNextRow(rowIndex, c, nextRow, rowspan, colspan, newRowspan);
1079
+ }
1080
+
1081
+ delete cell.colspan;
1082
+ delete cell.rowspan;
1083
+ }
1084
+
1085
+ private transferOriginToNextRow(
1086
+ rowIndex: number, c: number, nextRow: number,
1087
+ rowspan: number, colspan: number, newRowspan: number
1088
+ ): void {
1089
+ const cell = this.contentGrid[rowIndex][c];
1090
+ const newOrigin = this.contentGrid[nextRow][c];
1091
+
1092
+ newOrigin.blocks = [...cell.blocks];
1093
+ cell.blocks = [];
1094
+
1095
+ delete newOrigin.mergedInto;
1096
+
1097
+ if (newRowspan === 1 && colspan === 1) {
1098
+ delete newOrigin.colspan;
1099
+ delete newOrigin.rowspan;
1100
+ this.clearMergedIntoRefs(nextRow, rowIndex + rowspan, c, c + colspan, rowIndex, c, nextRow, c, undefined);
1101
+
1102
+ return;
1103
+ }
1104
+
1105
+ if (newRowspan > 1) {
1106
+ newOrigin.rowspan = newRowspan;
1107
+ } else {
1108
+ delete newOrigin.rowspan;
1109
+ }
1110
+ if (colspan > 1) {
1111
+ newOrigin.colspan = colspan;
1112
+ } else {
1113
+ delete newOrigin.colspan;
1114
+ }
1115
+ this.clearMergedIntoRefs(nextRow, rowIndex + rowspan, c, c + colspan, rowIndex, c, nextRow, c, [nextRow, c]);
1116
+ }
1117
+
1118
+ private handleCoveredInDeletedRow(rowIndex: number, c: number): void {
1119
+ const cell = this.contentGrid[rowIndex][c];
1120
+ const [originRow, originCol] = cell.mergedInto as [number, number];
1121
+
1122
+ if (originRow === rowIndex) {
1123
+ return;
1124
+ }
1125
+
1126
+ const origin = this.contentGrid[originRow]?.[originCol];
1127
+
1128
+ if (!origin) {
1129
+ return;
1130
+ }
1131
+
1132
+ const oRowspan = origin.rowspan ?? 1;
1133
+ const oColspan = origin.colspan ?? 1;
1134
+ const newRowspan = oRowspan - 1;
1135
+
1136
+ if (newRowspan === 1 && oColspan === 1) {
1137
+ delete origin.colspan;
1138
+ delete origin.rowspan;
1139
+
1140
+ this.clearMergedIntoRefsForDissolve(originRow, originRow + oRowspan, originCol, originCol + oColspan, originRow, originCol, rowIndex);
1141
+ } else {
1142
+ if (newRowspan > 1) {
1143
+ origin.rowspan = newRowspan;
1144
+ } else {
1145
+ delete origin.rowspan;
1146
+ }
1147
+ }
1148
+ }
1149
+
1150
+ private clearMergedIntoRefs(
1151
+ startRow: number, endRow: number, startCol: number, endCol: number,
1152
+ oldOriginRow: number, oldOriginCol: number,
1153
+ skipRow: number, skipCol: number,
1154
+ newRef: [number, number] | undefined
1155
+ ): void {
1156
+ this.contentGrid.slice(startRow, endRow).forEach((_gridRow, ri) => {
1157
+ const dr = startRow + ri;
1158
+
1159
+ this.contentGrid[dr].slice(startCol, endCol).forEach((_spanned, ci) => {
1160
+ const dc = startCol + ci;
1161
+
1162
+ if (dr === skipRow && dc === skipCol) {
1163
+ return;
1164
+ }
1165
+
1166
+ const spanned = this.contentGrid[dr]?.[dc];
1167
+
1168
+ if (spanned?.mergedInto?.[0] === oldOriginRow && spanned?.mergedInto?.[1] === oldOriginCol) {
1169
+ if (newRef === undefined) {
1170
+ delete spanned.mergedInto;
1171
+ } else {
1172
+ spanned.mergedInto = newRef;
1173
+ }
1174
+ }
1175
+ });
1176
+ });
1177
+ }
1178
+
1179
+ private clearMergedIntoRefsForDissolve(
1180
+ startRow: number, endRow: number, startCol: number, endCol: number,
1181
+ skipOriginRow: number, skipOriginCol: number, deletedRow: number
1182
+ ): void {
1183
+ this.contentGrid.slice(startRow, endRow).forEach((_gridRow, ri) => {
1184
+ const dr = startRow + ri;
1185
+
1186
+ if (dr === deletedRow) {
1187
+ return;
1188
+ }
1189
+
1190
+ this.contentGrid[dr].slice(startCol, endCol).forEach((_spanned, ci) => {
1191
+ const dc = startCol + ci;
1192
+
1193
+ if (dr === skipOriginRow && dc === skipOriginCol) {
1194
+ return;
1195
+ }
1196
+
1197
+ const spanned = this.contentGrid[dr]?.[dc];
1198
+
1199
+ if (spanned?.mergedInto) {
1200
+ delete spanned.mergedInto;
1201
+ }
1202
+ });
1203
+ });
1204
+ }
1205
+
1206
+ /**
1207
+ * Before deleting a column, handle merge origins and covered cells in that column.
1208
+ * Symmetric to contractSpansForDeletedRow.
1209
+ */
1210
+ private contractSpansForDeletedCol(colIndex: number): void {
1211
+ this.contentGrid.forEach((_row, r) => {
1212
+ const gridCell = this.contentGrid[r][colIndex];
1213
+
1214
+ if ((gridCell.colspan ?? 1) > 1 || (gridCell.rowspan ?? 1) > 1) {
1215
+ this.handleOriginInDeletedCol(colIndex, r);
1216
+ } else if (gridCell.mergedInto !== undefined) {
1217
+ this.handleCoveredInDeletedCol(colIndex, r);
1218
+ }
1219
+ });
1220
+ }
1221
+
1222
+ private handleOriginInDeletedCol(colIndex: number, r: number): void {
1223
+ const cell = this.contentGrid[r][colIndex];
1224
+ const rowspan = cell.rowspan ?? 1;
1225
+ const colspan = cell.colspan ?? 1;
1226
+
1227
+ if (colspan <= 1) {
1228
+ return;
1229
+ }
1230
+
1231
+ const newColspan = colspan - 1;
1232
+ const nextCol = colIndex + 1;
1233
+
1234
+ if (nextCol < (this.contentGrid[r]?.length ?? 0)) {
1235
+ this.transferOriginToNextCol(colIndex, r, nextCol, rowspan, colspan, newColspan);
1236
+ }
1237
+
1238
+ delete cell.colspan;
1239
+ delete cell.rowspan;
1240
+ }
1241
+
1242
+ private transferOriginToNextCol(
1243
+ colIndex: number, r: number, nextCol: number,
1244
+ rowspan: number, colspan: number, newColspan: number
1245
+ ): void {
1246
+ const cell = this.contentGrid[r][colIndex];
1247
+ const newOrigin = this.contentGrid[r][nextCol];
1248
+
1249
+ newOrigin.blocks = [...cell.blocks];
1250
+ cell.blocks = [];
1251
+ delete newOrigin.mergedInto;
1252
+
1253
+ if (newColspan === 1 && rowspan === 1) {
1254
+ delete newOrigin.colspan;
1255
+ delete newOrigin.rowspan;
1256
+ this.clearMergedIntoRefs(r, r + rowspan, nextCol, colIndex + colspan, r, colIndex, r, nextCol, undefined);
1257
+
1258
+ return;
1259
+ }
1260
+
1261
+ if (newColspan > 1) {
1262
+ newOrigin.colspan = newColspan;
1263
+ } else {
1264
+ delete newOrigin.colspan;
1265
+ }
1266
+ if (rowspan > 1) {
1267
+ newOrigin.rowspan = rowspan;
1268
+ } else {
1269
+ delete newOrigin.rowspan;
1270
+ }
1271
+ this.clearMergedIntoRefs(r, r + rowspan, nextCol, colIndex + colspan, r, colIndex, r, nextCol, [r, nextCol]);
1272
+ }
1273
+
1274
+ private handleCoveredInDeletedCol(colIndex: number, r: number): void {
1275
+ const cell = this.contentGrid[r][colIndex];
1276
+ const [originRow, originCol] = cell.mergedInto as [number, number];
1277
+
1278
+ if (originCol === colIndex) {
1279
+ return;
1280
+ }
1281
+
1282
+ const origin = this.contentGrid[originRow]?.[originCol];
1283
+
1284
+ if (!origin) {
1285
+ return;
1286
+ }
1287
+
1288
+ const oColspan = origin.colspan ?? 1;
1289
+ const oRowspan = origin.rowspan ?? 1;
1290
+ const newColspan = oColspan - 1;
1291
+
1292
+ if (newColspan === 1 && oRowspan === 1) {
1293
+ delete origin.colspan;
1294
+ delete origin.rowspan;
1295
+
1296
+ this.clearMergedIntoRefsForDissolveCol(originRow, originRow + oRowspan, originCol, originCol + oColspan, originRow, originCol, colIndex);
1297
+ } else {
1298
+ if (newColspan > 1) {
1299
+ origin.colspan = newColspan;
1300
+ } else {
1301
+ delete origin.colspan;
1302
+ }
1303
+ }
1304
+ }
1305
+
1306
+ private clearMergedIntoRefsForDissolveCol(
1307
+ startRow: number, endRow: number, startCol: number, endCol: number,
1308
+ skipOriginRow: number, skipOriginCol: number, deletedCol: number
1309
+ ): void {
1310
+ this.contentGrid.slice(startRow, endRow).forEach((_gridRow, ri) => {
1311
+ const dr = startRow + ri;
1312
+
1313
+ this.contentGrid[dr].slice(startCol, endCol).forEach((_spanned, ci) => {
1314
+ const dc = startCol + ci;
1315
+
1316
+ if (dr === skipOriginRow && dc === skipOriginCol) {
1317
+ return;
1318
+ }
1319
+
1320
+ if (dc === deletedCol) {
1321
+ return;
1322
+ }
1323
+
1324
+ const spanned = this.contentGrid[dr]?.[dc];
1325
+
1326
+ if (spanned?.mergedInto) {
1327
+ delete spanned.mergedInto;
1328
+ }
1329
+ });
1330
+ });
1331
+ }
1332
+
1333
+ /**
1334
+ * Check if any cell in a row is involved in a merge that extends beyond the row.
1335
+ */
1336
+ private isRowInvolvedInMerge(rowIndex: number): boolean {
1337
+ const row = this.contentGrid[rowIndex];
1338
+
1339
+ return row.some(cell => {
1340
+ // Origin with rowspan > 1 means it extends to other rows
1341
+ if ((cell.rowspan ?? 1) > 1) {
1342
+ return true;
1343
+ }
1344
+
1345
+ // Covered by a merge from a different row
1346
+ return cell.mergedInto !== undefined && cell.mergedInto[0] !== rowIndex;
1347
+ });
1348
+ }
1349
+
1350
+ /**
1351
+ * Check if any cell in a column is involved in a merge that extends beyond the column.
1352
+ */
1353
+ private isColInvolvedInMerge(colIndex: number): boolean {
1354
+ return this.contentGrid.some(row => {
1355
+ const cell = row[colIndex];
1356
+
1357
+ // Origin with colspan > 1 means it extends to other columns
1358
+ if ((cell.colspan ?? 1) > 1) {
1359
+ return true;
1360
+ }
1361
+
1362
+ // Covered by a merge from a different column
1363
+ return cell.mergedInto !== undefined && cell.mergedInto[1] !== colIndex;
1364
+ });
1365
+ }
1366
+
1367
+ /**
1368
+ * After a row move (splice from, splice to), rebuild mergedInto row coordinates
1369
+ * by computing the index remapping.
1370
+ */
1371
+ private rebuildMergedIntoRowCoordinates(from: number, to: number): void {
1372
+ const rowCount = this.contentGrid.length;
1373
+ const mapping = this.buildMoveMapping(rowCount, from, to);
1374
+
1375
+ this.contentGrid.forEach((_row, r) => {
1376
+ this.contentGrid[r].forEach((_cell, c) => {
1377
+ const gridCell = this.contentGrid[r][c];
1378
+
1379
+ if (gridCell.mergedInto !== undefined) {
1380
+ const oldOriginRow = gridCell.mergedInto[0];
1381
+
1382
+ gridCell.mergedInto = [mapping[oldOriginRow], gridCell.mergedInto[1]];
1383
+ }
1384
+ });
1385
+ });
1386
+ }
1387
+
1388
+ /**
1389
+ * After a column move (splice from, splice to), rebuild mergedInto col coordinates
1390
+ * by computing the index remapping.
1391
+ */
1392
+ private rebuildMergedIntoColCoordinates(from: number, to: number): void {
1393
+ const colCount = this.cols;
1394
+ const mapping = this.buildMoveMapping(colCount, from, to);
1395
+
1396
+ this.contentGrid.forEach((_row, r) => {
1397
+ this.contentGrid[r].forEach((_cell, c) => {
1398
+ const gridCell = this.contentGrid[r][c];
1399
+
1400
+ if (gridCell.mergedInto !== undefined) {
1401
+ const oldOriginCol = gridCell.mergedInto[1];
1402
+
1403
+ gridCell.mergedInto = [gridCell.mergedInto[0], mapping[oldOriginCol]];
1404
+ }
1405
+ });
1406
+ });
1407
+ }
1408
+
1409
+ private buildMoveMapping(count: number, from: number, to: number): number[] {
1410
+ return Array.from({ length: count }, (_, oldIdx) => {
1411
+ if (oldIdx === from) {
1412
+ return to;
1413
+ }
1414
+
1415
+ const afterRemove = oldIdx > from ? oldIdx - 1 : oldIdx;
1416
+
1417
+ return afterRemove >= to ? afterRemove + 1 : afterRemove;
1418
+ });
1419
+ }
1420
+
537
1421
  // ─── Private helpers ────────────────────────────────────────────
538
1422
 
539
1423
  /**
@@ -564,6 +1448,22 @@ export class TableModel {
564
1448
  normalized.textColor = cell.textColor;
565
1449
  }
566
1450
 
1451
+ if (cell.placement !== undefined) {
1452
+ normalized.placement = cell.placement;
1453
+ }
1454
+
1455
+ if (cell.colspan !== undefined && cell.colspan > 1) {
1456
+ normalized.colspan = cell.colspan;
1457
+ }
1458
+
1459
+ if (cell.rowspan !== undefined && cell.rowspan > 1) {
1460
+ normalized.rowspan = cell.rowspan;
1461
+ }
1462
+
1463
+ if (cell.mergedInto !== undefined) {
1464
+ normalized.mergedInto = [...cell.mergedInto];
1465
+ }
1466
+
567
1467
  return normalized;
568
1468
  }
569
1469