@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.
- package/dist/blok.mjs +2 -2
- package/dist/chunks/{blok-DDu252IK.mjs → blok-u_68bnlk.mjs} +1617 -1562
- package/dist/chunks/{constants-DMW9a31I.mjs → constants-VDhCUk4c.mjs} +56 -48
- package/dist/chunks/{i18next-loader-CwsYu0n6.mjs → i18next-loader-CDnSPae_.mjs} +1 -1
- package/dist/chunks/{lightweight-i18n-Cvv8CWh4.mjs → lightweight-i18n-DZmo8dAI.mjs} +1 -0
- package/dist/chunks/{messages-DG-4DPmP.mjs → messages-1_6UkKLS.mjs} +1 -0
- package/dist/{messages-CqXtJTpU.mjs → chunks/messages-4Ck88DYZ2.mjs} +1 -0
- package/dist/chunks/{messages-DGL1ySqb2.mjs → messages-8Ld7P_9j2.mjs} +1 -0
- package/dist/{messages-DLX_iBDJ.mjs → chunks/messages-BAlZjPcl.mjs} +1 -0
- package/dist/chunks/{messages-p1mbe__S.mjs → messages-BHMiK51R.mjs} +1 -0
- package/dist/chunks/{messages-Cdf0W9H02.mjs → messages-BJ-vT1SU2.mjs} +1 -0
- package/dist/{messages-Smt4GBbj.mjs → chunks/messages-BK8Cp2d0.mjs} +1 -0
- package/dist/{messages-Ci0KqX-J.mjs → chunks/messages-BKN3YVIj.mjs} +1 -0
- package/dist/chunks/{messages-BXM80fdr2.mjs → messages-BMD37y3q2.mjs} +1 -0
- package/dist/{messages-B19o-Teb.mjs → chunks/messages-BONyZroH.mjs} +1 -0
- package/dist/{messages-BwHs4cm1.mjs → chunks/messages-BRAoJpOu.mjs} +1 -0
- package/dist/{messages-DY4IqlhY.mjs → chunks/messages-BRoa9tGl.mjs} +1 -0
- package/dist/chunks/{messages-RInp1ytX.mjs → messages-BbEW9bQz.mjs} +1 -0
- package/dist/{messages-BIHc0KHY.mjs → chunks/messages-BeGZqQwz.mjs} +1 -0
- package/dist/{messages-CmB406HW.mjs → chunks/messages-BfAcUavP.mjs} +1 -0
- package/dist/chunks/{messages-Cu-Wevxs2.mjs → messages-BgM91Lxm2.mjs} +1 -0
- package/dist/{messages-BYNcD6uR.mjs → chunks/messages-BlxwW7M6.mjs} +1 -0
- package/dist/chunks/{messages-rCd0Rrw6.mjs → messages-Bz0-KNEB.mjs} +1 -0
- package/dist/{messages-7QD-X6XT2.mjs → chunks/messages-C0IFfhnp.mjs} +1 -0
- package/dist/{messages-Dl5Y2-Ia.mjs → chunks/messages-C15z2r5U.mjs} +1 -0
- package/dist/chunks/{messages-MxpWO1db.mjs → messages-C1S9ztpF.mjs} +1 -0
- package/dist/chunks/{messages-8IHf7ZP3.mjs → messages-CC_noR8y.mjs} +1 -0
- package/dist/chunks/{messages-COO5xmcA.mjs → messages-CD_MnBln.mjs} +1 -0
- package/dist/chunks/{messages-BYlSMRkd.mjs → messages-CIfUm1Oa.mjs} +1 -0
- package/dist/{messages-BbYq1pk-.mjs → chunks/messages-CPBN4zWc.mjs} +1 -0
- package/dist/{messages-DPA-mMWC2.mjs → chunks/messages-CQBo3lmL2.mjs} +1 -0
- package/dist/{messages-DnGJD4TL.mjs → chunks/messages-CRF7nNrO.mjs} +1 -0
- package/dist/{messages-D8FQWulF2.mjs → chunks/messages-CTCe595D2.mjs} +1 -0
- package/dist/{messages-BRZX964b2.mjs → chunks/messages-CW35K1pq.mjs} +1 -0
- package/dist/{messages-DnG0ef8t2.mjs → chunks/messages-CZSlfnkO2.mjs} +1 -0
- package/dist/chunks/{messages-iS34FHFB.mjs → messages-ChK7v1PV.mjs} +1 -0
- package/dist/{messages-BiUGXvYr2.mjs → chunks/messages-Clku7Cf-2.mjs} +1 -0
- package/dist/{messages-DIJlIqlQ2.mjs → chunks/messages-CszmHAvQ.mjs} +1 -0
- package/dist/chunks/{messages-DWu1r4gc2.mjs → messages-CvANwuht2.mjs} +1 -0
- package/dist/{messages-nUVjeh7K.mjs → chunks/messages-CxiURE2X.mjs} +1 -0
- package/dist/chunks/{messages-A_MkXDlG.mjs → messages-CxxyR4vY.mjs} +1 -0
- package/dist/{messages-ynAe7ewZ.mjs → chunks/messages-D22e9h7V2.mjs} +1 -0
- package/dist/{messages-DYTTu0O12.mjs → chunks/messages-D7dx_6k8.mjs} +1 -0
- package/dist/chunks/{messages-BA8Iv99Y2.mjs → messages-DBMaLL8b2.mjs} +1 -0
- package/dist/{messages-DbySKTKt2.mjs → chunks/messages-DB_-5Xln.mjs} +1 -0
- package/dist/{messages-CcF4y-E4.mjs → chunks/messages-DEBy3nuJ2.mjs} +1 -0
- package/dist/chunks/{messages-NEqrrYvE2.mjs → messages-DMoERagV2.mjs} +1 -0
- package/dist/chunks/{messages-Bxvi1ebN.mjs → messages-DPzHD51Y.mjs} +1 -0
- package/dist/chunks/{messages-jfVpL9c-2.mjs → messages-DSrdy9Nw2.mjs} +1 -0
- package/dist/chunks/{messages-Cmf6NhSC.mjs → messages-DTN1XGll.mjs} +1 -0
- package/dist/{messages-5jvKxQNu2.mjs → chunks/messages-DUeiPraX.mjs} +1 -0
- package/dist/chunks/{messages-G416eyjY.mjs → messages-DUr9WAkD.mjs} +1 -0
- package/dist/chunks/{messages-Ck81cQkn2.mjs → messages-DVr1sqfI2.mjs} +1 -0
- package/dist/{messages-BYmmMDrN2.mjs → chunks/messages-DjvaiALg2.mjs} +1 -0
- package/dist/chunks/{messages-D55HRx5O2.mjs → messages-DrfRYiM32.mjs} +1 -0
- package/dist/chunks/{messages-B2N4fUi72.mjs → messages-DtoId_bw2.mjs} +1 -0
- package/dist/{messages-Bq3F2Tp_.mjs → chunks/messages-Du2BffA7.mjs} +1 -0
- package/dist/{messages-CjbnogEC.mjs → chunks/messages-DxHh0O8j2.mjs} +1 -0
- package/dist/{messages-BECMxmfX.mjs → chunks/messages-EDMC5ukV.mjs} +1 -0
- package/dist/{messages-BTQPpoM42.mjs → chunks/messages-ElIGUi0O2.mjs} +1 -0
- package/dist/chunks/{messages-BhzzNkN-.mjs → messages-JSQjKQ8I.mjs} +1 -0
- package/dist/{messages-CWIXvnDf2.mjs → chunks/messages-Q7-4ZJLB2.mjs} +1 -0
- package/dist/chunks/{messages-DOuS1Qge.mjs → messages-QMOmwcZb.mjs} +1 -0
- package/dist/{messages-hWwSRF-2.mjs → chunks/messages-QilfinOn2.mjs} +1 -0
- package/dist/{messages-BmAn22OX.mjs → chunks/messages-a07QVz8U.mjs} +1 -0
- package/dist/chunks/{messages-BYxLFj7y.mjs → messages-eFd4YYzt.mjs} +1 -0
- package/dist/chunks/{messages-BSghd0ez.mjs → messages-euM2m3wQ.mjs} +1 -0
- package/dist/chunks/{messages-BVjoM7P0.mjs → messages-kGmxkeFH.mjs} +1 -0
- package/dist/{messages-DMr62KiO2.mjs → chunks/messages-oMc7qugU2.mjs} +1 -0
- package/dist/chunks/{messages-DzTk8bJ5.mjs → messages-sDdNf8O9.mjs} +1 -0
- package/dist/{messages-Bm0Feca1.mjs → chunks/messages-wl8YrvGG.mjs} +1 -0
- package/dist/chunks/{messages-BAsb5CgZ.mjs → messages-zt6zdYWh.mjs} +1 -0
- package/dist/chunks/{tools-XmzH2rgQ.mjs → tools-1ZFajlGN.mjs} +1619 -1307
- package/dist/full.mjs +3 -3
- package/dist/locales.mjs +68 -67
- package/dist/{messages-F2xRoY1w.mjs → messages-2ZWBTerL.mjs} +1 -0
- package/dist/{messages-Dl3Sv6Rq2.mjs → messages-53w0fPZS2.mjs} +1 -0
- package/dist/{chunks/messages-BDZA10kl2.mjs → messages-98nQiC7t2.mjs} +1 -0
- package/dist/{chunks/messages-JyvWu4rf2.mjs → messages-A96tMxeU.mjs} +1 -0
- package/dist/{messages-Ce6KVEbT.mjs → messages-BE_z-zrb.mjs} +1 -0
- package/dist/{chunks/messages-CSJ_zb3a2.mjs → messages-BK_LsgY4.mjs} +1 -0
- package/dist/{messages-CJTy6JZt.mjs → messages-BbJ7ZXY8.mjs} +1 -0
- package/dist/{chunks/messages-DMVXnAYj.mjs → messages-BcVB3osF.mjs} +1 -0
- package/dist/{chunks/messages-CSL-6xfb2.mjs → messages-BckDk9aq2.mjs} +1 -0
- package/dist/{chunks/messages-C0HvoMPb.mjs → messages-Be_2RHZD.mjs} +1 -0
- package/dist/{chunks/messages-Dr0Ekmbz.mjs → messages-BesJaI6A.mjs} +1 -0
- package/dist/{chunks/messages-D3zojZ94.mjs → messages-BiTMwiKH.mjs} +1 -0
- package/dist/{messages-B1ZUQagA.mjs → messages-BmH2cQHQ.mjs} +1 -0
- package/dist/{chunks/messages-Bfnq1xv4.mjs → messages-BrOWqNCu2.mjs} +1 -0
- package/dist/{messages-Dnp9N6RU2.mjs → messages-Brd5R-da2.mjs} +1 -0
- package/dist/{chunks/messages-DJoNVjqP.mjs → messages-C0GSBBCo2.mjs} +1 -0
- package/dist/{messages-Dw__BcTj.mjs → messages-C1vc5584.mjs} +1 -0
- package/dist/{messages-aMXpHt5X2.mjs → messages-C6ONf71u2.mjs} +1 -0
- package/dist/{chunks/messages-BeFqtIrc2.mjs → messages-C7lJg8fy2.mjs} +1 -0
- package/dist/{messages-CSUHBs4c2.mjs → messages-CRNogopy2.mjs} +1 -0
- package/dist/{messages-DLlc9QPw.mjs → messages-CT-Kdas6.mjs} +1 -0
- package/dist/{chunks/messages-DlLXpgWM2.mjs → messages-CTTmWn4Y2.mjs} +1 -0
- package/dist/{messages-D0aw5_0k2.mjs → messages-CZbcxlZt2.mjs} +1 -0
- package/dist/{chunks/messages-Bp8qin1R.mjs → messages-C_Qn9SbQ.mjs} +1 -0
- package/dist/{messages-96iaAUds2.mjs → messages-CdEASHDp2.mjs} +1 -0
- package/dist/{messages-Dy-Y_nEI.mjs → messages-CdduYw-q.mjs} +1 -0
- package/dist/{chunks/messages-Je5YvxiY.mjs → messages-Che99vKP.mjs} +1 -0
- package/dist/{messages-nlhESX9t.mjs → messages-CisR4PNV.mjs} +1 -0
- package/dist/{chunks/messages-BE6lHKwf.mjs → messages-ClGvlFcH2.mjs} +1 -0
- package/dist/{chunks/messages-FWfsxpBz.mjs → messages-CnuH-BZK2.mjs} +1 -0
- package/dist/{chunks/messages-aZcy0JQq2.mjs → messages-D0005ti32.mjs} +1 -0
- package/dist/{messages-B7ieAJBd2.mjs → messages-D05jqBIa2.mjs} +1 -0
- package/dist/{messages-DTh9a8mR.mjs → messages-D0lLw9KM.mjs} +1 -0
- package/dist/{chunks/messages-ihCjSFJI2.mjs → messages-D3rwCtKn.mjs} +1 -0
- package/dist/{chunks/messages-xuqyb6Ff2.mjs → messages-D6VIFnSW.mjs} +1 -0
- package/dist/{chunks/messages-KdawW5Na.mjs → messages-D81w6AmW.mjs} +1 -0
- package/dist/{chunks/messages-BUVhHx0q2.mjs → messages-DBhvm8NK.mjs} +1 -0
- package/dist/{chunks/messages-C7VGpihw.mjs → messages-DK6dA0O2.mjs} +1 -0
- package/dist/{messages-rk-A1Wa42.mjs → messages-DKHbt-7l2.mjs} +1 -0
- package/dist/{messages-BIoeoik5.mjs → messages-DM4Gjc9h.mjs} +1 -0
- package/dist/{chunks/messages-B9kmbUWV.mjs → messages-DODrhcop.mjs} +1 -0
- package/dist/{messages-BsycN_JI2.mjs → messages-DOGbHYv-2.mjs} +1 -0
- package/dist/{chunks/messages-BQYvBqm2.mjs → messages-DQORja0D.mjs} +1 -0
- package/dist/{chunks/messages-CVdpweyf2.mjs → messages-DSmxJWju2.mjs} +1 -0
- package/dist/{messages-CR_L_UtK.mjs → messages-DVL0KZE5.mjs} +1 -0
- package/dist/{chunks/messages-Cs81Z_Bh.mjs → messages-DYuD5-rO.mjs} +1 -0
- package/dist/{chunks/messages-CKBhDGI3.mjs → messages-Ddq3Ce3E2.mjs} +1 -0
- package/dist/{messages-xh2eOLvs.mjs → messages-DfFZ6Yj5.mjs} +1 -0
- package/dist/{chunks/messages-C6Mpiacw.mjs → messages-Dnd5YSWv.mjs} +1 -0
- package/dist/{messages-BJeGJksD.mjs → messages-Do7Xjy0n.mjs} +1 -0
- package/dist/{chunks/messages-C3aX3q0H.mjs → messages-DopaMHC42.mjs} +1 -0
- package/dist/{messages-dv19AkyJ.mjs → messages-DpJGbx3q.mjs} +1 -0
- package/dist/{messages-DBiVgUs2.mjs → messages-DpwMKDV0.mjs} +1 -0
- package/dist/{messages-j7o5rT9s.mjs → messages-Dqu4aX9s.mjs} +1 -0
- package/dist/{chunks/messages-BjadX8jR2.mjs → messages-E8NjqzWq2.mjs} +1 -0
- package/dist/{messages-aWZH50vu2.mjs → messages-JNrYldAa2.mjs} +1 -0
- package/dist/{chunks/messages-B4UMuyjT.mjs → messages-LMaR2_bE.mjs} +1 -0
- package/dist/{messages-E_ZuzGDt.mjs → messages-LYJbLq_F.mjs} +1 -0
- package/dist/{chunks/messages-D9N2MvQx2.mjs → messages-Q5sQeVap2.mjs} +1 -0
- package/dist/{chunks/messages-Bphq_Bt3.mjs → messages-Xc0KUbYl.mjs} +1 -0
- package/dist/{chunks/messages-DlonA3wa.mjs → messages-_PLyRfVw.mjs} +1 -0
- package/dist/{chunks/messages-TRUuyiFB.mjs → messages-apA6BStA.mjs} +1 -0
- package/dist/{chunks/messages-B0vPBsWq.mjs → messages-bkGniiaz.mjs} +1 -0
- package/dist/{messages-DkLU_rWm.mjs → messages-neGD3WGq.mjs} +1 -0
- package/dist/{messages-Ddnj2iTG2.mjs → messages-qbKjjvgd2.mjs} +1 -0
- package/dist/{messages-BiiongNz2.mjs → messages-qfvXgPpu2.mjs} +1 -0
- package/dist/{messages-Dvn35ksS.mjs → messages-uwK7ktqk.mjs} +1 -0
- package/dist/react.mjs +2 -2
- package/dist/tools.mjs +2 -2
- package/package.json +3 -5
- package/src/cli/commands/convert-gdocs/index.ts +26 -0
- package/src/cli/commands/convert-html/block-builder.ts +392 -0
- package/src/cli/commands/convert-html/id-generator.ts +11 -0
- package/src/cli/commands/convert-html/index.ts +23 -0
- package/src/cli/commands/convert-html/preprocessor.ts +422 -0
- package/src/cli/commands/convert-html/sanitizer.ts +93 -0
- package/src/cli/commands/convert-html/types.ts +15 -0
- package/src/cli/index.ts +56 -5
- package/src/components/block/index.ts +58 -10
- package/src/components/constants/data-attributes.ts +10 -0
- package/src/components/i18n/locales/am/messages.json +1 -0
- package/src/components/i18n/locales/ar/messages.json +1 -0
- package/src/components/i18n/locales/az/messages.json +1 -0
- package/src/components/i18n/locales/bg/messages.json +1 -0
- package/src/components/i18n/locales/bn/messages.json +1 -0
- package/src/components/i18n/locales/bs/messages.json +1 -0
- package/src/components/i18n/locales/cs/messages.json +1 -0
- package/src/components/i18n/locales/da/messages.json +1 -0
- package/src/components/i18n/locales/de/messages.json +1 -0
- package/src/components/i18n/locales/dv/messages.json +1 -0
- package/src/components/i18n/locales/el/messages.json +1 -0
- package/src/components/i18n/locales/en/messages.json +1 -0
- package/src/components/i18n/locales/es/messages.json +1 -0
- package/src/components/i18n/locales/et/messages.json +1 -0
- package/src/components/i18n/locales/fa/messages.json +1 -0
- package/src/components/i18n/locales/fi/messages.json +1 -0
- package/src/components/i18n/locales/fil/messages.json +1 -0
- package/src/components/i18n/locales/fr/messages.json +1 -0
- package/src/components/i18n/locales/gu/messages.json +1 -0
- package/src/components/i18n/locales/he/messages.json +1 -0
- package/src/components/i18n/locales/hi/messages.json +1 -0
- package/src/components/i18n/locales/hr/messages.json +1 -0
- package/src/components/i18n/locales/hu/messages.json +1 -0
- package/src/components/i18n/locales/hy/messages.json +1 -0
- package/src/components/i18n/locales/id/messages.json +1 -0
- package/src/components/i18n/locales/it/messages.json +1 -0
- package/src/components/i18n/locales/ja/messages.json +1 -0
- package/src/components/i18n/locales/ka/messages.json +1 -0
- package/src/components/i18n/locales/km/messages.json +1 -0
- package/src/components/i18n/locales/kn/messages.json +1 -0
- package/src/components/i18n/locales/ko/messages.json +1 -0
- package/src/components/i18n/locales/ku/messages.json +1 -0
- package/src/components/i18n/locales/lo/messages.json +1 -0
- package/src/components/i18n/locales/lt/messages.json +1 -0
- package/src/components/i18n/locales/lv/messages.json +1 -0
- package/src/components/i18n/locales/mk/messages.json +1 -0
- package/src/components/i18n/locales/ml/messages.json +1 -0
- package/src/components/i18n/locales/mn/messages.json +1 -0
- package/src/components/i18n/locales/mr/messages.json +1 -0
- package/src/components/i18n/locales/ms/messages.json +1 -0
- package/src/components/i18n/locales/my/messages.json +1 -0
- package/src/components/i18n/locales/ne/messages.json +1 -0
- package/src/components/i18n/locales/nl/messages.json +1 -0
- package/src/components/i18n/locales/no/messages.json +1 -0
- package/src/components/i18n/locales/pa/messages.json +1 -0
- package/src/components/i18n/locales/pl/messages.json +1 -0
- package/src/components/i18n/locales/ps/messages.json +1 -0
- package/src/components/i18n/locales/pt/messages.json +1 -0
- package/src/components/i18n/locales/ro/messages.json +1 -0
- package/src/components/i18n/locales/ru/messages.json +1 -0
- package/src/components/i18n/locales/sd/messages.json +1 -0
- package/src/components/i18n/locales/si/messages.json +1 -0
- package/src/components/i18n/locales/sk/messages.json +1 -0
- package/src/components/i18n/locales/sl/messages.json +1 -0
- package/src/components/i18n/locales/sq/messages.json +1 -0
- package/src/components/i18n/locales/sr/messages.json +1 -0
- package/src/components/i18n/locales/sv/messages.json +1 -0
- package/src/components/i18n/locales/sw/messages.json +1 -0
- package/src/components/i18n/locales/ta/messages.json +1 -0
- package/src/components/i18n/locales/te/messages.json +1 -0
- package/src/components/i18n/locales/th/messages.json +1 -0
- package/src/components/i18n/locales/tr/messages.json +1 -0
- package/src/components/i18n/locales/ug/messages.json +1 -0
- package/src/components/i18n/locales/uk/messages.json +1 -0
- package/src/components/i18n/locales/ur/messages.json +1 -0
- package/src/components/i18n/locales/vi/messages.json +1 -0
- package/src/components/i18n/locales/yi/messages.json +1 -0
- package/src/components/i18n/locales/zh/messages.json +1 -0
- package/src/components/icons/index.ts +29 -18
- package/src/components/modules/blockEvents/composers/keyboardNavigation.ts +18 -0
- package/src/components/modules/blockManager/hierarchy.ts +4 -1
- package/src/components/modules/readonly.ts +46 -0
- package/src/components/modules/rectangleSelection.ts +25 -5
- package/src/components/modules/toolbar/index.ts +96 -19
- package/src/components/modules/toolbar/positioning.ts +11 -2
- package/src/components/modules/toolbar/styles.ts +0 -2
- package/src/components/modules/uiControllers/controllers/blockHover.ts +44 -1
- package/src/components/tools/block.ts +10 -0
- package/src/components/utils/placeholder.ts +9 -2
- package/src/components/utils/popover/components/popover-item/popover-item-default/popover-item-default.ts +11 -0
- package/src/components/utils/popover/popover-abstract.ts +7 -0
- package/src/styles/main.css +16 -0
- package/src/tools/callout/constants.ts +2 -1
- package/src/tools/callout/dom-builder.ts +13 -1
- package/src/tools/callout/index.ts +21 -7
- package/src/tools/code/constants.ts +28 -8
- package/src/tools/code/dom-builder.ts +133 -64
- package/src/tools/code/index.ts +280 -91
- package/src/tools/code/language-detector.ts +118 -0
- package/src/tools/divider/index.ts +5 -0
- package/src/tools/header/index.ts +47 -1
- package/src/tools/list/dom-builder.ts +3 -1
- package/src/tools/list/index.ts +55 -3
- package/src/tools/list/list-helpers.ts +2 -2
- package/src/tools/nested-blocks.ts +25 -0
- package/src/tools/paragraph/index.ts +47 -6
- package/src/tools/quote/index.ts +43 -8
- package/src/tools/stub/index.ts +10 -0
- package/src/tools/table/index.ts +238 -6
- package/src/tools/table/table-add-controls.ts +37 -5
- package/src/tools/table/table-cell-blocks.ts +57 -18
- package/src/tools/table/table-core.ts +2 -0
- package/src/tools/table/table-corner-drag.ts +247 -0
- package/src/tools/table/table-operations.ts +41 -14
- package/src/tools/toggle/dom-builder.ts +1 -0
- package/src/tools/toggle/index.ts +25 -0
- package/src/tools/toggle/toggle-lifecycle.ts +5 -4
- package/src/types-internal/jsdom.d.ts +9 -0
- package/types/tools/adapters/block-tool-adapter.d.ts +6 -0
- package/types/tools/block-tool.d.ts +20 -0
- package/types/utils/popover/popover-item.d.ts +6 -0
- package/bin/blok.mjs +0 -10
- package/dist/cli.mjs +0 -37
- package/src/tools/code/language-picker.ts +0 -241
package/src/tools/table/index.ts
CHANGED
|
@@ -54,8 +54,10 @@ import type { PendingHighlight } from './table-row-col-action-handler';
|
|
|
54
54
|
import { TableRowColControls } from './table-row-col-controls';
|
|
55
55
|
import type { RowColAction } from './table-row-col-controls';
|
|
56
56
|
import { registerAdditionalRestrictedTools } from './table-restrictions';
|
|
57
|
+
import { TableCornerDrag } from './table-corner-drag';
|
|
57
58
|
import { TableScrollHaze } from './table-scroll-haze';
|
|
58
59
|
import type { CellPlacement, ClipboardBlockData, LegacyCellContent, TableCellsClipboard, TableData, TableConfig } from './types';
|
|
60
|
+
import { isCellWithBlocks } from './types';
|
|
59
61
|
|
|
60
62
|
const DEFAULT_ROWS = 3;
|
|
61
63
|
const DEFAULT_COLS = 3;
|
|
@@ -93,6 +95,7 @@ export class Table implements BlockTool {
|
|
|
93
95
|
private rowColControls: TableRowColControls | null = null;
|
|
94
96
|
private cellBlocks: TableCellBlocks | null = null;
|
|
95
97
|
private cellSelection: TableCellSelection | null = null;
|
|
98
|
+
private cornerDrag: TableCornerDrag | null = null;
|
|
96
99
|
private scrollHaze: TableScrollHaze | null = null;
|
|
97
100
|
private element: HTMLDivElement | null = null;
|
|
98
101
|
private gridElement: HTMLElement | null = null;
|
|
@@ -102,6 +105,8 @@ export class Table implements BlockTool {
|
|
|
102
105
|
private pendingHighlight: PendingHighlight | null = null;
|
|
103
106
|
private isNewTable = false;
|
|
104
107
|
private unregisterRestrictedTools: (() => void) | null = null;
|
|
108
|
+
private gridPasteCleanup: (() => void) | null = null;
|
|
109
|
+
private keyboardNavCleanup: (() => void) | null = null;
|
|
105
110
|
|
|
106
111
|
/**
|
|
107
112
|
* Generation counter for setData calls.
|
|
@@ -193,12 +198,18 @@ export class Table implements BlockTool {
|
|
|
193
198
|
this.resize = null;
|
|
194
199
|
this.addControls?.destroy();
|
|
195
200
|
this.addControls = null;
|
|
201
|
+
this.cornerDrag?.destroy();
|
|
202
|
+
this.cornerDrag = null;
|
|
196
203
|
this.rowColControls?.destroy();
|
|
197
204
|
this.rowColControls = null;
|
|
198
205
|
this.cellSelection?.destroy();
|
|
199
206
|
this.cellSelection = null;
|
|
200
207
|
this.scrollHaze?.destroy();
|
|
201
208
|
this.scrollHaze = null;
|
|
209
|
+
this.gridPasteCleanup?.();
|
|
210
|
+
this.gridPasteCleanup = null;
|
|
211
|
+
this.keyboardNavCleanup?.();
|
|
212
|
+
this.keyboardNavCleanup = null;
|
|
202
213
|
}
|
|
203
214
|
|
|
204
215
|
/**
|
|
@@ -256,6 +267,8 @@ export class Table implements BlockTool {
|
|
|
256
267
|
newTbody: Element,
|
|
257
268
|
blockHolders: Map<string, HTMLElement>
|
|
258
269
|
): void {
|
|
270
|
+
const mounted = new Set<string>();
|
|
271
|
+
|
|
259
272
|
content.forEach((rowData, r) => {
|
|
260
273
|
rowData.forEach((cellContent, c) => {
|
|
261
274
|
if (typeof cellContent === 'string') {
|
|
@@ -283,8 +296,9 @@ export class Table implements BlockTool {
|
|
|
283
296
|
cellContent.blocks.forEach(blockId => {
|
|
284
297
|
const holder = blockHolders.get(blockId);
|
|
285
298
|
|
|
286
|
-
if (holder) {
|
|
299
|
+
if (holder && !mounted.has(blockId)) {
|
|
287
300
|
container.appendChild(holder);
|
|
301
|
+
mounted.add(blockId);
|
|
288
302
|
}
|
|
289
303
|
});
|
|
290
304
|
});
|
|
@@ -323,6 +337,7 @@ export class Table implements BlockTool {
|
|
|
323
337
|
private initSubsystems(gridEl: HTMLElement): void {
|
|
324
338
|
this.initResize(gridEl);
|
|
325
339
|
this.initAddControls(gridEl);
|
|
340
|
+
this.initCornerDrag(gridEl);
|
|
326
341
|
this.initRowColControls(gridEl);
|
|
327
342
|
this.initCellSelection(gridEl);
|
|
328
343
|
this.initGridPasteListener(gridEl);
|
|
@@ -482,7 +497,7 @@ export class Table implements BlockTool {
|
|
|
482
497
|
|
|
483
498
|
if (!this.readOnly) {
|
|
484
499
|
this.initCellBlocks(gridEl);
|
|
485
|
-
setupKeyboardNavigation(gridEl, this.cellBlocks);
|
|
500
|
+
this.keyboardNavCleanup = setupKeyboardNavigation(gridEl, this.cellBlocks);
|
|
486
501
|
}
|
|
487
502
|
|
|
488
503
|
return wrapper;
|
|
@@ -558,6 +573,64 @@ export class Table implements BlockTool {
|
|
|
558
573
|
}
|
|
559
574
|
}
|
|
560
575
|
|
|
576
|
+
/**
|
|
577
|
+
* Toggle read-only mode in place without re-rendering.
|
|
578
|
+
* Entering readonly tears down all interactive subsystems and cell blocks;
|
|
579
|
+
* exiting readonly recreates them.
|
|
580
|
+
*/
|
|
581
|
+
public setReadOnly(state: boolean): void {
|
|
582
|
+
const wrapper = this.element;
|
|
583
|
+
const gridEl = this.gridElement;
|
|
584
|
+
|
|
585
|
+
if (!wrapper || !gridEl) {
|
|
586
|
+
return;
|
|
587
|
+
}
|
|
588
|
+
|
|
589
|
+
this.readOnly = state;
|
|
590
|
+
|
|
591
|
+
if (state) {
|
|
592
|
+
// Entering readonly: tear down interactive subsystems
|
|
593
|
+
this.teardownSubsystems();
|
|
594
|
+
this.cellBlocks?.destroy();
|
|
595
|
+
this.cellBlocks = null;
|
|
596
|
+
|
|
597
|
+
// Remove grip overlay
|
|
598
|
+
if (this.gripOverlay) {
|
|
599
|
+
this.gripOverlay.remove();
|
|
600
|
+
this.gripOverlay = null;
|
|
601
|
+
}
|
|
602
|
+
|
|
603
|
+
// Update wrapper classes and attributes
|
|
604
|
+
WRAPPER_EDIT_CLASSES.forEach(cls => wrapper.classList.remove(cls));
|
|
605
|
+
wrapper.setAttribute('data-blok-table-readonly', '');
|
|
606
|
+
|
|
607
|
+
// Mount cell content as non-interactive
|
|
608
|
+
const snap = this.model.snapshot();
|
|
609
|
+
|
|
610
|
+
mountCellBlocksReadOnly(gridEl, snap.content, this.api, this.blockId ?? '');
|
|
611
|
+
} else {
|
|
612
|
+
// Exiting readonly: restore interactive subsystems
|
|
613
|
+
wrapper.removeAttribute('data-blok-table-readonly');
|
|
614
|
+
WRAPPER_EDIT_CLASSES.forEach(cls => wrapper.classList.add(cls));
|
|
615
|
+
|
|
616
|
+
// Create grip overlay
|
|
617
|
+
const overlay = document.createElement('div');
|
|
618
|
+
|
|
619
|
+
overlay.setAttribute('data-blok-table-grip-overlay', '');
|
|
620
|
+
overlay.style.position = 'absolute';
|
|
621
|
+
overlay.style.inset = '0';
|
|
622
|
+
overlay.style.pointerEvents = 'none';
|
|
623
|
+
overlay.style.zIndex = '3';
|
|
624
|
+
wrapper.appendChild(overlay);
|
|
625
|
+
this.gripOverlay = overlay;
|
|
626
|
+
|
|
627
|
+
// Initialize cell blocks and subsystems
|
|
628
|
+
this.initCellBlocks(gridEl);
|
|
629
|
+
this.keyboardNavCleanup = setupKeyboardNavigation(gridEl, this.cellBlocks);
|
|
630
|
+
this.initSubsystems(gridEl);
|
|
631
|
+
}
|
|
632
|
+
}
|
|
633
|
+
|
|
561
634
|
/**
|
|
562
635
|
* Remove blocks that claim this table as parent but are not referenced in any cell.
|
|
563
636
|
*
|
|
@@ -595,7 +668,28 @@ export class Table implements BlockTool {
|
|
|
595
668
|
}
|
|
596
669
|
|
|
597
670
|
public save(_blockContent: HTMLElement): TableData {
|
|
598
|
-
|
|
671
|
+
const data = this.model.snapshot();
|
|
672
|
+
|
|
673
|
+
// Filter out block IDs that don't belong to this table.
|
|
674
|
+
// Corrupted data may contain cross-table references; persisting them
|
|
675
|
+
// causes DOM node stealing and data loss on subsequent renders.
|
|
676
|
+
data.content = data.content.map(row =>
|
|
677
|
+
row.map(cell => {
|
|
678
|
+
if (!isCellWithBlocks(cell)) {
|
|
679
|
+
return cell;
|
|
680
|
+
}
|
|
681
|
+
|
|
682
|
+
const filtered = cell.blocks.filter(blockId => {
|
|
683
|
+
const block = this.api.blocks.getById?.(blockId);
|
|
684
|
+
|
|
685
|
+
return !block || block.parentId === this.blockId;
|
|
686
|
+
});
|
|
687
|
+
|
|
688
|
+
return { ...cell, blocks: filtered };
|
|
689
|
+
})
|
|
690
|
+
);
|
|
691
|
+
|
|
692
|
+
return data;
|
|
599
693
|
}
|
|
600
694
|
|
|
601
695
|
public validate(savedData: TableData): boolean {
|
|
@@ -900,6 +994,10 @@ export class Table implements BlockTool {
|
|
|
900
994
|
wrapper: this.element,
|
|
901
995
|
grid: gridEl,
|
|
902
996
|
i18n: this.api.i18n,
|
|
997
|
+
getTableSize: () => ({
|
|
998
|
+
rows: this.model.rows,
|
|
999
|
+
cols: this.model.cols,
|
|
1000
|
+
}),
|
|
903
1001
|
getNewColumnWidth: () => {
|
|
904
1002
|
const colWidths = this.model.colWidths ?? readPixelWidths(gridEl);
|
|
905
1003
|
|
|
@@ -1040,6 +1138,131 @@ export class Table implements BlockTool {
|
|
|
1040
1138
|
}
|
|
1041
1139
|
}
|
|
1042
1140
|
|
|
1141
|
+
private initCornerDrag(gridEl: HTMLElement): void {
|
|
1142
|
+
this.cornerDrag?.destroy();
|
|
1143
|
+
|
|
1144
|
+
if (!this.element) {
|
|
1145
|
+
return;
|
|
1146
|
+
}
|
|
1147
|
+
|
|
1148
|
+
this.cornerDrag = new TableCornerDrag({
|
|
1149
|
+
wrapper: this.element,
|
|
1150
|
+
gridEl,
|
|
1151
|
+
onAddRow: () => {
|
|
1152
|
+
this.runStructuralOp(() => {
|
|
1153
|
+
this.grid.addRow(gridEl);
|
|
1154
|
+
this.model.addRow();
|
|
1155
|
+
populateNewCells(gridEl, this.cellBlocks);
|
|
1156
|
+
updateHeadingStyles(this.gridElement, this.model.withHeadings);
|
|
1157
|
+
updateHeadingColumnStyles(this.gridElement, this.model.withHeadingColumn);
|
|
1158
|
+
});
|
|
1159
|
+
},
|
|
1160
|
+
onAddColumn: () => {
|
|
1161
|
+
this.runStructuralOp(() => {
|
|
1162
|
+
const colWidths = this.model.colWidths ?? readPixelWidths(gridEl);
|
|
1163
|
+
const halfWidth = this.model.initialColWidth !== undefined
|
|
1164
|
+
? Math.round((this.model.initialColWidth / 2) * 100) / 100
|
|
1165
|
+
: computeHalfAvgWidth(colWidths);
|
|
1166
|
+
const newWidths = [...colWidths, halfWidth];
|
|
1167
|
+
|
|
1168
|
+
this.grid.addColumn(gridEl, undefined, colWidths, halfWidth);
|
|
1169
|
+
this.model.addColumn(undefined, halfWidth);
|
|
1170
|
+
this.model.setColWidths(newWidths);
|
|
1171
|
+
applyPixelWidths(gridEl, newWidths);
|
|
1172
|
+
enableScrollOverflow(this.ensureScrollContainer());
|
|
1173
|
+
populateNewCells(gridEl, this.cellBlocks);
|
|
1174
|
+
updateHeadingColumnStyles(this.gridElement, this.model.withHeadingColumn);
|
|
1175
|
+
});
|
|
1176
|
+
},
|
|
1177
|
+
onRemoveLastRow: () => {
|
|
1178
|
+
this.runStructuralOp(() => {
|
|
1179
|
+
const rowCount = this.grid.getRowCount(gridEl);
|
|
1180
|
+
|
|
1181
|
+
if (rowCount <= 1) {
|
|
1182
|
+
return;
|
|
1183
|
+
}
|
|
1184
|
+
|
|
1185
|
+
const { blocksToDelete } = this.model.deleteRow(rowCount - 1);
|
|
1186
|
+
|
|
1187
|
+
this.cellBlocks?.deleteBlocks(blocksToDelete);
|
|
1188
|
+
this.grid.deleteRow(gridEl, rowCount - 1);
|
|
1189
|
+
});
|
|
1190
|
+
},
|
|
1191
|
+
onRemoveLastColumn: () => {
|
|
1192
|
+
this.runStructuralOp(() => {
|
|
1193
|
+
const colCount = this.grid.getColumnCount(gridEl);
|
|
1194
|
+
|
|
1195
|
+
if (colCount <= 1) {
|
|
1196
|
+
return;
|
|
1197
|
+
}
|
|
1198
|
+
|
|
1199
|
+
const { blocksToDelete } = this.model.deleteColumn(colCount - 1);
|
|
1200
|
+
|
|
1201
|
+
this.cellBlocks?.deleteBlocks(blocksToDelete);
|
|
1202
|
+
this.grid.deleteColumn(gridEl, colCount - 1);
|
|
1203
|
+
|
|
1204
|
+
const updatedWidths = this.model.colWidths;
|
|
1205
|
+
|
|
1206
|
+
if (updatedWidths) {
|
|
1207
|
+
applyPixelWidths(gridEl, updatedWidths);
|
|
1208
|
+
}
|
|
1209
|
+
});
|
|
1210
|
+
},
|
|
1211
|
+
onDragStart: () => {
|
|
1212
|
+
if (this.resize) {
|
|
1213
|
+
this.resize.enabled = false;
|
|
1214
|
+
}
|
|
1215
|
+
this.rowColControls?.hideAllGrips();
|
|
1216
|
+
this.rowColControls?.setGripsDisplay(false);
|
|
1217
|
+
this.addControls?.setDisplay(false);
|
|
1218
|
+
},
|
|
1219
|
+
onDragEnd: () => {
|
|
1220
|
+
this.initResize(gridEl);
|
|
1221
|
+
this.rowColControls?.refresh();
|
|
1222
|
+
this.addControls?.setDisplay(true);
|
|
1223
|
+
this.addControls?.syncRowButtonWidth();
|
|
1224
|
+
},
|
|
1225
|
+
getTableSize: () => {
|
|
1226
|
+
return { rows: this.model.rows, cols: this.model.cols };
|
|
1227
|
+
},
|
|
1228
|
+
canRemoveLastRow: () => {
|
|
1229
|
+
return this.model.rows > 1 && isRowEmpty(gridEl, this.model.rows - 1);
|
|
1230
|
+
},
|
|
1231
|
+
canRemoveLastColumn: () => {
|
|
1232
|
+
return this.model.cols > 1 && isColumnEmpty(gridEl, this.model.cols - 1);
|
|
1233
|
+
},
|
|
1234
|
+
onClickAdd: () => {
|
|
1235
|
+
this.runTransactedStructuralOp(() => {
|
|
1236
|
+
// Add row
|
|
1237
|
+
this.grid.addRow(gridEl);
|
|
1238
|
+
this.model.addRow();
|
|
1239
|
+
populateNewCells(gridEl, this.cellBlocks);
|
|
1240
|
+
updateHeadingStyles(this.gridElement, this.model.withHeadings);
|
|
1241
|
+
updateHeadingColumnStyles(this.gridElement, this.model.withHeadingColumn);
|
|
1242
|
+
|
|
1243
|
+
// Add column
|
|
1244
|
+
const colWidths = this.model.colWidths ?? readPixelWidths(gridEl);
|
|
1245
|
+
const halfWidth = this.model.initialColWidth !== undefined
|
|
1246
|
+
? Math.round((this.model.initialColWidth / 2) * 100) / 100
|
|
1247
|
+
: computeHalfAvgWidth(colWidths);
|
|
1248
|
+
const newWidths = [...colWidths, halfWidth];
|
|
1249
|
+
|
|
1250
|
+
this.grid.addColumn(gridEl, undefined, colWidths, halfWidth);
|
|
1251
|
+
this.model.addColumn(undefined, halfWidth);
|
|
1252
|
+
this.model.setColWidths(newWidths);
|
|
1253
|
+
applyPixelWidths(gridEl, newWidths);
|
|
1254
|
+
populateNewCells(gridEl, this.cellBlocks);
|
|
1255
|
+
updateHeadingColumnStyles(this.gridElement, this.model.withHeadingColumn);
|
|
1256
|
+
|
|
1257
|
+
// Refresh subsystems
|
|
1258
|
+
this.initResize(gridEl);
|
|
1259
|
+
this.rowColControls?.refresh();
|
|
1260
|
+
this.addControls?.syncRowButtonWidth();
|
|
1261
|
+
});
|
|
1262
|
+
},
|
|
1263
|
+
});
|
|
1264
|
+
}
|
|
1265
|
+
|
|
1043
1266
|
private initRowColControls(gridEl: HTMLElement): void {
|
|
1044
1267
|
this.rowColControls?.destroy();
|
|
1045
1268
|
|
|
@@ -1063,6 +1286,7 @@ export class Table implements BlockTool {
|
|
|
1063
1286
|
}
|
|
1064
1287
|
|
|
1065
1288
|
this.addControls?.setDisplay(!isDragging);
|
|
1289
|
+
this.cornerDrag?.setDisplay(!isDragging);
|
|
1066
1290
|
|
|
1067
1291
|
if (isDragging) {
|
|
1068
1292
|
this.api.toolbar.close({ setExplicitlyClosed: false });
|
|
@@ -1442,6 +1666,7 @@ export class Table implements BlockTool {
|
|
|
1442
1666
|
}
|
|
1443
1667
|
|
|
1444
1668
|
this.addControls?.setInteractive(!hasSelection);
|
|
1669
|
+
this.cornerDrag?.setInteractive(!hasSelection);
|
|
1445
1670
|
this.rowColControls?.setGripsDisplay(!hasSelection);
|
|
1446
1671
|
},
|
|
1447
1672
|
onSelectionRangeChange: () => {
|
|
@@ -1531,9 +1756,14 @@ export class Table implements BlockTool {
|
|
|
1531
1756
|
}
|
|
1532
1757
|
|
|
1533
1758
|
private initGridPasteListener(gridEl: HTMLElement): void {
|
|
1534
|
-
|
|
1759
|
+
const handler = (e: ClipboardEvent): void => {
|
|
1535
1760
|
this.handleGridPaste(e, gridEl);
|
|
1536
|
-
}
|
|
1761
|
+
};
|
|
1762
|
+
|
|
1763
|
+
gridEl.addEventListener('paste', handler);
|
|
1764
|
+
this.gridPasteCleanup = () => {
|
|
1765
|
+
gridEl.removeEventListener('paste', handler);
|
|
1766
|
+
};
|
|
1537
1767
|
}
|
|
1538
1768
|
|
|
1539
1769
|
private handleGridPaste(e: ClipboardEvent, gridEl: HTMLElement): void {
|
|
@@ -1633,7 +1863,9 @@ export class Table implements BlockTool {
|
|
|
1633
1863
|
|
|
1634
1864
|
const range = selection.getRangeAt(0);
|
|
1635
1865
|
|
|
1636
|
-
range.
|
|
1866
|
+
if (!range.collapsed) {
|
|
1867
|
+
range.deleteContents();
|
|
1868
|
+
}
|
|
1637
1869
|
|
|
1638
1870
|
const fragment = document.createDocumentFragment();
|
|
1639
1871
|
const wrapper = document.createElement('div');
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { I18n } from '../../../types/api';
|
|
2
2
|
import { IconPlus } from '../../components/icons';
|
|
3
3
|
import { createTooltipContent } from '../../components/modules/toolbar/tooltip';
|
|
4
|
-
import { hide as hideTooltip, onHover } from '../../components/utils/tooltip';
|
|
4
|
+
import { hide as hideTooltip, onHover, show as showTooltip } from '../../components/utils/tooltip';
|
|
5
5
|
import { twMerge } from '../../components/utils/tw';
|
|
6
6
|
|
|
7
7
|
const ADD_ROW_ATTR = 'data-blok-table-add-row';
|
|
@@ -29,7 +29,7 @@ const VISUAL_CLASSES = [
|
|
|
29
29
|
'justify-center',
|
|
30
30
|
'border',
|
|
31
31
|
'border-gray-300',
|
|
32
|
-
'rounded-
|
|
32
|
+
'rounded-sm',
|
|
33
33
|
'group-hover/add:bg-gray-50',
|
|
34
34
|
];
|
|
35
35
|
|
|
@@ -56,6 +56,7 @@ interface TableAddControlsOptions {
|
|
|
56
56
|
onDragAddCol: () => void;
|
|
57
57
|
onDragRemoveCol: () => void;
|
|
58
58
|
onDragEnd: () => void;
|
|
59
|
+
getTableSize: () => { rows: number; cols: number };
|
|
59
60
|
/** Returns the pixel width of a newly added column, used as the drag unit size. */
|
|
60
61
|
getNewColumnWidth?: () => number;
|
|
61
62
|
}
|
|
@@ -94,6 +95,7 @@ export class TableAddControls {
|
|
|
94
95
|
private boundPointerCancel: (e: PointerEvent) => void;
|
|
95
96
|
private boundRowPointerDown: (e: PointerEvent) => void;
|
|
96
97
|
private boundColPointerDown: (e: PointerEvent) => void;
|
|
98
|
+
private getTableSize: () => { rows: number; cols: number };
|
|
97
99
|
private getNewColumnWidth: (() => number) | undefined;
|
|
98
100
|
private scrollContainer: HTMLElement | null = null;
|
|
99
101
|
private boundScrollHandler: (() => void) | null = null;
|
|
@@ -112,6 +114,7 @@ export class TableAddControls {
|
|
|
112
114
|
this.onDragAddCol = options.onDragAddCol;
|
|
113
115
|
this.onDragRemoveCol = options.onDragRemoveCol;
|
|
114
116
|
this.onDragEnd = options.onDragEnd;
|
|
117
|
+
this.getTableSize = options.getTableSize;
|
|
115
118
|
this.getNewColumnWidth = options.getNewColumnWidth;
|
|
116
119
|
this.boundMouseMove = this.handleMouseMove.bind(this);
|
|
117
120
|
this.boundDocumentMouseMove = this.handleDocumentMouseMove.bind(this);
|
|
@@ -324,6 +327,20 @@ export class TableAddControls {
|
|
|
324
327
|
this.addColBtn.remove();
|
|
325
328
|
}
|
|
326
329
|
|
|
330
|
+
private showDimensionTooltip(): void {
|
|
331
|
+
if (!this.dragState) {
|
|
332
|
+
return;
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
const size = this.getTableSize();
|
|
336
|
+
const target = this.dragState.axis === 'row' ? this.addRowBtn : this.addColBtn;
|
|
337
|
+
const opts = this.dragState.axis === 'row'
|
|
338
|
+
? { placement: 'bottom' as const, marginTop: -16 }
|
|
339
|
+
: { placement: 'bottom' as const };
|
|
340
|
+
|
|
341
|
+
showTooltip(target, `${size.cols}\u00D7${size.rows}`, opts);
|
|
342
|
+
}
|
|
343
|
+
|
|
327
344
|
private handlePointerDown(axis: 'row' | 'col', e: PointerEvent): void {
|
|
328
345
|
e.preventDefault();
|
|
329
346
|
|
|
@@ -380,8 +397,18 @@ export class TableAddControls {
|
|
|
380
397
|
if (Math.abs(delta) > DRAG_THRESHOLD && !this.dragState.didDrag) {
|
|
381
398
|
this.dragState.didDrag = true;
|
|
382
399
|
document.body.style.cursor = axis === 'row' ? 'row-resize' : 'col-resize';
|
|
383
|
-
|
|
400
|
+
this.showDimensionTooltip();
|
|
384
401
|
this.onDragStart();
|
|
402
|
+
|
|
403
|
+
return;
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
if (this.dragState.didDrag) {
|
|
407
|
+
this.showDimensionTooltip();
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
if (this.dragState.didDrag) {
|
|
411
|
+
this.showDimensionTooltip();
|
|
385
412
|
}
|
|
386
413
|
}
|
|
387
414
|
|
|
@@ -400,6 +427,7 @@ export class TableAddControls {
|
|
|
400
427
|
target.removeEventListener('pointercancel', this.boundPointerCancel);
|
|
401
428
|
|
|
402
429
|
document.body.style.cursor = '';
|
|
430
|
+
hideTooltip();
|
|
403
431
|
this.dragState = null;
|
|
404
432
|
|
|
405
433
|
if (!didDrag) {
|
|
@@ -431,6 +459,7 @@ export class TableAddControls {
|
|
|
431
459
|
target.removeEventListener('pointercancel', this.boundPointerCancel);
|
|
432
460
|
|
|
433
461
|
document.body.style.cursor = '';
|
|
462
|
+
hideTooltip();
|
|
434
463
|
this.dragState = null;
|
|
435
464
|
|
|
436
465
|
if (didDrag) {
|
|
@@ -495,8 +524,8 @@ export class TableAddControls {
|
|
|
495
524
|
* Document-level mousemove handler.
|
|
496
525
|
* Catches mouse movements outside the wrapper (e.g. in the ::after
|
|
497
526
|
* pseudo-element zone below the grid, which has pointer-events-none).
|
|
498
|
-
*
|
|
499
|
-
*
|
|
527
|
+
* Delegates to handleMouseMove when the cursor is within the proximity
|
|
528
|
+
* zone around the grid; schedules hiding when the cursor is far away.
|
|
500
529
|
*/
|
|
501
530
|
private handleDocumentMouseMove(e: MouseEvent): void {
|
|
502
531
|
if (this.wrapper.contains(e.target as Node)) {
|
|
@@ -513,6 +542,9 @@ export class TableAddControls {
|
|
|
513
542
|
|
|
514
543
|
if (nearGrid) {
|
|
515
544
|
this.handleMouseMove(e);
|
|
545
|
+
} else {
|
|
546
|
+
this.scheduleHideRow();
|
|
547
|
+
this.scheduleHideCol();
|
|
516
548
|
}
|
|
517
549
|
}
|
|
518
550
|
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { API } from '../../../types';
|
|
2
|
+
import { DATA_ATTR } from '../../components/constants/data-attributes';
|
|
2
3
|
|
|
3
4
|
import { CELL_ATTR, ROW_ATTR, CELL_COL_ATTR } from './table-core';
|
|
4
5
|
import type { TableModel } from './table-model';
|
|
@@ -7,15 +8,6 @@ import { isCellWithBlocks } from './types';
|
|
|
7
8
|
|
|
8
9
|
export const CELL_BLOCKS_ATTR = 'data-blok-table-cell-blocks';
|
|
9
10
|
|
|
10
|
-
/**
|
|
11
|
-
* Check if an element is inside a block-based table cell
|
|
12
|
-
*/
|
|
13
|
-
export const isInCellBlock = (element: HTMLElement): boolean => {
|
|
14
|
-
const cellBlocksContainer = element.closest(`[${CELL_BLOCKS_ATTR}]`);
|
|
15
|
-
|
|
16
|
-
return cellBlocksContainer !== null;
|
|
17
|
-
};
|
|
18
|
-
|
|
19
11
|
/**
|
|
20
12
|
* Get the cell element that contains the given element
|
|
21
13
|
*/
|
|
@@ -390,9 +382,9 @@ export class TableCellBlocks {
|
|
|
390
382
|
const referencedBlockIds = isCellWithBlocks(cellContent) && cellContent.blocks.length > 0
|
|
391
383
|
? [...cellContent.blocks]
|
|
392
384
|
: null;
|
|
393
|
-
const mountedIds = referencedBlockIds
|
|
385
|
+
const { mountedIds, replacements } = referencedBlockIds
|
|
394
386
|
? this.mountBlocksInCell(container, referencedBlockIds)
|
|
395
|
-
: [];
|
|
387
|
+
: { mountedIds: [] as string[], replacements: new Map<string, string>() };
|
|
396
388
|
|
|
397
389
|
const cellColorProps: Pick<CellContent, 'color' | 'textColor'> = {};
|
|
398
390
|
|
|
@@ -406,7 +398,12 @@ export class TableCellBlocks {
|
|
|
406
398
|
}
|
|
407
399
|
|
|
408
400
|
if (mountedIds.length > 0) {
|
|
409
|
-
|
|
401
|
+
const baseIds = referencedBlockIds ?? mountedIds;
|
|
402
|
+
const blockIds = replacements.size > 0
|
|
403
|
+
? baseIds.map(id => replacements.get(id) ?? id)
|
|
404
|
+
: baseIds;
|
|
405
|
+
|
|
406
|
+
normalizedRow.push({ blocks: blockIds, ...cellColorProps });
|
|
410
407
|
} else {
|
|
411
408
|
const text = typeof cellContent === 'string'
|
|
412
409
|
? cellContent
|
|
@@ -455,10 +452,15 @@ export class TableCellBlocks {
|
|
|
455
452
|
|
|
456
453
|
/**
|
|
457
454
|
* Mount existing blocks into a cell container by their IDs.
|
|
458
|
-
* Returns the IDs of blocks that were successfully mounted
|
|
455
|
+
* Returns the IDs of blocks that were successfully mounted and a map of
|
|
456
|
+
* original→duplicate IDs for blocks that were already in another cell.
|
|
459
457
|
*/
|
|
460
|
-
private mountBlocksInCell(
|
|
458
|
+
private mountBlocksInCell(
|
|
459
|
+
container: HTMLElement,
|
|
460
|
+
blockIds: string[]
|
|
461
|
+
): { mountedIds: string[]; replacements: Map<string, string> } {
|
|
461
462
|
const mountedIds: string[] = [];
|
|
463
|
+
const replacements = new Map<string, string>();
|
|
462
464
|
|
|
463
465
|
for (const blockId of blockIds) {
|
|
464
466
|
const index = this.api.blocks.getBlockIndex(blockId);
|
|
@@ -473,11 +475,30 @@ export class TableCellBlocks {
|
|
|
473
475
|
continue;
|
|
474
476
|
}
|
|
475
477
|
|
|
478
|
+
// Guard: if the block is already mounted in another nested container
|
|
479
|
+
// (table cell, toggle, callout, header), create a duplicate with the
|
|
480
|
+
// same tool name and data rather than stealing the DOM node.
|
|
481
|
+
if (block.holder.closest(`[${DATA_ATTR.nestedBlocks}]`)) {
|
|
482
|
+
const duplicate = this.api.blocks.insert(
|
|
483
|
+
block.name,
|
|
484
|
+
block.preservedData,
|
|
485
|
+
{},
|
|
486
|
+
this.api.blocks.getBlocksCount(),
|
|
487
|
+
false
|
|
488
|
+
);
|
|
489
|
+
|
|
490
|
+
container.appendChild(duplicate.holder);
|
|
491
|
+
this.api.blocks.setBlockParent(duplicate.id, this.tableBlockId);
|
|
492
|
+
mountedIds.push(duplicate.id);
|
|
493
|
+
replacements.set(blockId, duplicate.id);
|
|
494
|
+
continue;
|
|
495
|
+
}
|
|
496
|
+
|
|
476
497
|
container.appendChild(block.holder);
|
|
477
498
|
this.api.blocks.setBlockParent(blockId, this.tableBlockId);
|
|
478
499
|
mountedIds.push(blockId);
|
|
479
500
|
}
|
|
480
|
-
return mountedIds;
|
|
501
|
+
return { mountedIds, replacements };
|
|
481
502
|
}
|
|
482
503
|
|
|
483
504
|
/**
|
|
@@ -508,6 +529,12 @@ export class TableCellBlocks {
|
|
|
508
529
|
return;
|
|
509
530
|
}
|
|
510
531
|
|
|
532
|
+
// Guard: skip blocks already mounted in another nested container.
|
|
533
|
+
// Without this, insertBefore would steal the DOM node from the other container.
|
|
534
|
+
if (block.holder.closest(`[${DATA_ATTR.nestedBlocks}]`)) {
|
|
535
|
+
return;
|
|
536
|
+
}
|
|
537
|
+
|
|
511
538
|
// Insert at the correct DOM position based on the flat array order,
|
|
512
539
|
// so that pressing Enter on a non-last paragraph inserts the new block
|
|
513
540
|
// right after the current one instead of always at the end of the cell.
|
|
@@ -1026,7 +1053,11 @@ export class TableCellBlocks {
|
|
|
1026
1053
|
}
|
|
1027
1054
|
|
|
1028
1055
|
/**
|
|
1029
|
-
* Delete blocks by their IDs (in reverse index order to avoid shifting issues)
|
|
1056
|
+
* Delete blocks by their IDs (in reverse index order to avoid shifting issues).
|
|
1057
|
+
* Preserves scroll position because api.blocks.delete() is async — its internal
|
|
1058
|
+
* `await` defers Caret.setToBlock() to microtasks that run AFTER this method returns,
|
|
1059
|
+
* causing unwanted page jumps via element.focus() and window.scrollBy().
|
|
1060
|
+
* We use Promise.all().then() to schedule the scroll restore after all those microtasks.
|
|
1030
1061
|
*/
|
|
1031
1062
|
public deleteBlocks(blockIds: string[]): void {
|
|
1032
1063
|
const blockIndices = blockIds
|
|
@@ -1034,8 +1065,16 @@ export class TableCellBlocks {
|
|
|
1034
1065
|
.filter((index): index is number => index !== undefined)
|
|
1035
1066
|
.sort((a, b) => b - a);
|
|
1036
1067
|
|
|
1037
|
-
|
|
1038
|
-
|
|
1068
|
+
const savedScrollY = window.scrollY;
|
|
1069
|
+
|
|
1070
|
+
const deletePromises = blockIndices.map(index => {
|
|
1071
|
+
return this.api.blocks.delete(index);
|
|
1072
|
+
});
|
|
1073
|
+
|
|
1074
|
+
void Promise.all(deletePromises).then(() => {
|
|
1075
|
+
if (window.scrollY !== savedScrollY) {
|
|
1076
|
+
window.scrollTo(0, savedScrollY);
|
|
1077
|
+
}
|
|
1039
1078
|
});
|
|
1040
1079
|
}
|
|
1041
1080
|
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { twMerge } from '../../components/utils/tw';
|
|
2
|
+
import { DATA_ATTR } from '../../components/constants/data-attributes';
|
|
2
3
|
|
|
3
4
|
import { CELL_BLOCKS_ATTR } from './table-cell-blocks';
|
|
4
5
|
import type { TableModel } from './table-model';
|
|
@@ -631,6 +632,7 @@ export class TableGrid {
|
|
|
631
632
|
const blocksContainer = document.createElement('div');
|
|
632
633
|
|
|
633
634
|
blocksContainer.setAttribute(CELL_BLOCKS_ATTR, '');
|
|
635
|
+
blocksContainer.setAttribute(DATA_ATTR.nestedBlocks, '');
|
|
634
636
|
blocksContainer.style.display = 'flex';
|
|
635
637
|
blocksContainer.style.flexDirection = 'column';
|
|
636
638
|
blocksContainer.style.minHeight = '100%';
|