@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
|
@@ -0,0 +1,247 @@
|
|
|
1
|
+
import { show as showTooltip, hide as hideTooltip } from '../../components/utils/tooltip';
|
|
2
|
+
|
|
3
|
+
const CORNER_DRAG_ATTR = 'data-blok-table-corner-drag';
|
|
4
|
+
|
|
5
|
+
export interface TableCornerDragOptions {
|
|
6
|
+
wrapper: HTMLElement;
|
|
7
|
+
gridEl: HTMLElement;
|
|
8
|
+
onAddRow: () => void;
|
|
9
|
+
onAddColumn: () => void;
|
|
10
|
+
onRemoveLastRow: () => void;
|
|
11
|
+
onRemoveLastColumn: () => void;
|
|
12
|
+
onDragStart: () => void;
|
|
13
|
+
onDragEnd: () => void;
|
|
14
|
+
getTableSize: () => { rows: number; cols: number };
|
|
15
|
+
canRemoveLastRow: () => boolean;
|
|
16
|
+
canRemoveLastColumn: () => boolean;
|
|
17
|
+
onClickAdd?: () => void;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
const DRAG_THRESHOLD = 5;
|
|
21
|
+
|
|
22
|
+
interface DragState {
|
|
23
|
+
startX: number;
|
|
24
|
+
startY: number;
|
|
25
|
+
unitWidth: number;
|
|
26
|
+
unitHeight: number;
|
|
27
|
+
addedRows: number;
|
|
28
|
+
addedCols: number;
|
|
29
|
+
pointerId: number;
|
|
30
|
+
didDrag: boolean;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export class TableCornerDrag {
|
|
34
|
+
private wrapper: HTMLElement;
|
|
35
|
+
private gridEl: HTMLElement;
|
|
36
|
+
private hitZone: HTMLElement;
|
|
37
|
+
private getTableSize: () => { rows: number; cols: number };
|
|
38
|
+
private onAddRow: () => void;
|
|
39
|
+
private onAddColumn: () => void;
|
|
40
|
+
private onRemoveLastRow: () => void;
|
|
41
|
+
private onRemoveLastColumn: () => void;
|
|
42
|
+
private onDragStart: () => void;
|
|
43
|
+
private onDragEnd: () => void;
|
|
44
|
+
private canRemoveLastRow: () => boolean;
|
|
45
|
+
private canRemoveLastColumn: () => boolean;
|
|
46
|
+
private onClickAdd: (() => void) | null;
|
|
47
|
+
private dragState: DragState | null = null;
|
|
48
|
+
private readonly boundMouseEnter: () => void;
|
|
49
|
+
private readonly boundMouseLeave: () => void;
|
|
50
|
+
private readonly boundPointerDown: (e: PointerEvent) => void;
|
|
51
|
+
private readonly boundPointerMove: (e: PointerEvent) => void;
|
|
52
|
+
private readonly boundPointerUp: (e: PointerEvent) => void;
|
|
53
|
+
|
|
54
|
+
constructor(options: TableCornerDragOptions) {
|
|
55
|
+
this.wrapper = options.wrapper;
|
|
56
|
+
this.gridEl = options.gridEl;
|
|
57
|
+
this.getTableSize = options.getTableSize;
|
|
58
|
+
this.onAddRow = options.onAddRow;
|
|
59
|
+
this.onAddColumn = options.onAddColumn;
|
|
60
|
+
this.onRemoveLastRow = options.onRemoveLastRow;
|
|
61
|
+
this.onRemoveLastColumn = options.onRemoveLastColumn;
|
|
62
|
+
this.onDragStart = options.onDragStart;
|
|
63
|
+
this.onDragEnd = options.onDragEnd;
|
|
64
|
+
this.canRemoveLastRow = options.canRemoveLastRow;
|
|
65
|
+
this.canRemoveLastColumn = options.canRemoveLastColumn;
|
|
66
|
+
this.onClickAdd = options.onClickAdd ?? null;
|
|
67
|
+
|
|
68
|
+
this.hitZone = document.createElement('div');
|
|
69
|
+
this.hitZone.setAttribute(CORNER_DRAG_ATTR, '');
|
|
70
|
+
this.hitZone.setAttribute('contenteditable', 'false');
|
|
71
|
+
this.hitZone.style.position = 'absolute';
|
|
72
|
+
this.hitZone.style.width = '36px';
|
|
73
|
+
this.hitZone.style.height = '36px';
|
|
74
|
+
this.hitZone.style.cursor = 'nwse-resize';
|
|
75
|
+
this.hitZone.style.zIndex = '2';
|
|
76
|
+
this.hitZone.style.pointerEvents = 'auto';
|
|
77
|
+
this.hitZone.style.bottom = '-36px';
|
|
78
|
+
this.hitZone.style.right = '-16px';
|
|
79
|
+
|
|
80
|
+
this.boundMouseEnter = this.handleMouseEnter.bind(this);
|
|
81
|
+
this.boundMouseLeave = this.handleMouseLeave.bind(this);
|
|
82
|
+
this.boundPointerDown = this.handlePointerDown.bind(this);
|
|
83
|
+
this.boundPointerMove = this.handlePointerMove.bind(this);
|
|
84
|
+
this.boundPointerUp = this.handlePointerUp.bind(this);
|
|
85
|
+
|
|
86
|
+
this.hitZone.addEventListener('mouseenter', this.boundMouseEnter);
|
|
87
|
+
this.hitZone.addEventListener('mouseleave', this.boundMouseLeave);
|
|
88
|
+
this.hitZone.addEventListener('pointerdown', this.boundPointerDown);
|
|
89
|
+
|
|
90
|
+
this.wrapper.appendChild(this.hitZone);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
private updateTooltip(): void {
|
|
94
|
+
const size = this.getTableSize();
|
|
95
|
+
|
|
96
|
+
showTooltip(this.hitZone, `${size.cols}\u00D7${size.rows}`, { placement: 'bottom' });
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
private handleMouseEnter(): void {
|
|
100
|
+
this.updateTooltip();
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
private handleMouseLeave(): void {
|
|
104
|
+
if (this.dragState !== null) {
|
|
105
|
+
return;
|
|
106
|
+
}
|
|
107
|
+
hideTooltip();
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
private measureUnitHeight(): number {
|
|
111
|
+
const rows = this.gridEl.querySelectorAll('[data-blok-table-row]');
|
|
112
|
+
const lastRow = rows[rows.length - 1] as HTMLElement | undefined;
|
|
113
|
+
|
|
114
|
+
return lastRow?.offsetHeight || 30;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
private measureUnitWidth(): number {
|
|
118
|
+
const firstRow = this.gridEl.querySelector('[data-blok-table-row]');
|
|
119
|
+
|
|
120
|
+
if (!firstRow) {
|
|
121
|
+
return 100;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
const cells = firstRow.querySelectorAll('[data-blok-table-cell]');
|
|
125
|
+
const lastCell = cells[cells.length - 1] as HTMLElement | undefined;
|
|
126
|
+
|
|
127
|
+
return lastCell?.offsetWidth || 100;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
private handlePointerDown(e: PointerEvent): void {
|
|
131
|
+
this.dragState = {
|
|
132
|
+
startX: e.clientX,
|
|
133
|
+
startY: e.clientY,
|
|
134
|
+
unitWidth: this.measureUnitWidth(),
|
|
135
|
+
unitHeight: this.measureUnitHeight(),
|
|
136
|
+
addedRows: 0,
|
|
137
|
+
addedCols: 0,
|
|
138
|
+
pointerId: e.pointerId,
|
|
139
|
+
didDrag: false,
|
|
140
|
+
};
|
|
141
|
+
|
|
142
|
+
this.updateTooltip();
|
|
143
|
+
|
|
144
|
+
this.hitZone.setPointerCapture(e.pointerId);
|
|
145
|
+
this.hitZone.addEventListener('pointermove', this.boundPointerMove);
|
|
146
|
+
this.hitZone.addEventListener('pointerup', this.boundPointerUp);
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
private handlePointerMove(e: PointerEvent): void {
|
|
150
|
+
if (this.dragState === null) {
|
|
151
|
+
return;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
const dx = e.clientX - this.dragState.startX;
|
|
155
|
+
const dy = e.clientY - this.dragState.startY;
|
|
156
|
+
|
|
157
|
+
if (!this.dragState.didDrag) {
|
|
158
|
+
const distance = Math.sqrt(dx * dx + dy * dy);
|
|
159
|
+
|
|
160
|
+
if (distance < DRAG_THRESHOLD) {
|
|
161
|
+
return;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
this.dragState.didDrag = true;
|
|
165
|
+
document.body.style.cursor = 'nwse-resize';
|
|
166
|
+
document.body.style.userSelect = 'none';
|
|
167
|
+
this.onDragStart();
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
const { unitHeight, unitWidth } = this.dragState;
|
|
171
|
+
|
|
172
|
+
const targetRows = Math.trunc(dy / unitHeight);
|
|
173
|
+
const targetCols = Math.trunc(dx / unitWidth);
|
|
174
|
+
|
|
175
|
+
while (this.dragState.addedRows < targetRows) {
|
|
176
|
+
this.onAddRow();
|
|
177
|
+
this.dragState.addedRows++;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
while (this.dragState.addedRows > targetRows && this.canRemoveLastRow()) {
|
|
181
|
+
this.onRemoveLastRow();
|
|
182
|
+
this.dragState.addedRows--;
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
while (this.dragState.addedCols < targetCols) {
|
|
186
|
+
this.onAddColumn();
|
|
187
|
+
this.dragState.addedCols++;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
while (this.dragState.addedCols > targetCols && this.canRemoveLastColumn()) {
|
|
191
|
+
this.onRemoveLastColumn();
|
|
192
|
+
this.dragState.addedCols--;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
this.updateTooltip();
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
private handlePointerUp(_e: PointerEvent): void {
|
|
199
|
+
if (this.dragState === null) {
|
|
200
|
+
return;
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
const { didDrag, pointerId } = this.dragState;
|
|
204
|
+
|
|
205
|
+
this.dragState = null;
|
|
206
|
+
hideTooltip();
|
|
207
|
+
this.hitZone.releasePointerCapture(pointerId);
|
|
208
|
+
this.hitZone.removeEventListener('pointermove', this.boundPointerMove);
|
|
209
|
+
this.hitZone.removeEventListener('pointerup', this.boundPointerUp);
|
|
210
|
+
|
|
211
|
+
if (!didDrag) {
|
|
212
|
+
if (this.onClickAdd) {
|
|
213
|
+
this.onClickAdd();
|
|
214
|
+
} else {
|
|
215
|
+
this.onAddRow();
|
|
216
|
+
this.onAddColumn();
|
|
217
|
+
}
|
|
218
|
+
} else {
|
|
219
|
+
document.body.style.cursor = '';
|
|
220
|
+
document.body.style.userSelect = '';
|
|
221
|
+
this.onDragEnd();
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
public setDisplay(visible: boolean): void {
|
|
226
|
+
this.hitZone.style.display = visible ? '' : 'none';
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
public setInteractive(interactive: boolean): void {
|
|
230
|
+
this.hitZone.style.pointerEvents = interactive ? 'auto' : 'none';
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
public destroy(): void {
|
|
234
|
+
this.hitZone.removeEventListener('mouseenter', this.boundMouseEnter);
|
|
235
|
+
this.hitZone.removeEventListener('mouseleave', this.boundMouseLeave);
|
|
236
|
+
this.hitZone.removeEventListener('pointerdown', this.boundPointerDown);
|
|
237
|
+
this.hitZone.removeEventListener('pointermove', this.boundPointerMove);
|
|
238
|
+
this.hitZone.removeEventListener('pointerup', this.boundPointerUp);
|
|
239
|
+
if (this.dragState?.didDrag) {
|
|
240
|
+
document.body.style.cursor = '';
|
|
241
|
+
document.body.style.userSelect = '';
|
|
242
|
+
}
|
|
243
|
+
this.dragState = null;
|
|
244
|
+
hideTooltip();
|
|
245
|
+
this.hitZone.remove();
|
|
246
|
+
}
|
|
247
|
+
}
|
|
@@ -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 type { TableCellBlocks } from './table-cell-blocks';
|
|
4
5
|
import { CELL_BLOCKS_ATTR } from './table-cell-blocks';
|
|
@@ -288,16 +289,28 @@ export const mountCellBlocksReadOnly = (
|
|
|
288
289
|
|
|
289
290
|
if (!isCellWithBlocks(cellContent)) {
|
|
290
291
|
// Read-only render path must not mutate block state.
|
|
291
|
-
//
|
|
292
|
-
//
|
|
293
|
-
|
|
292
|
+
// Wrap in a div with leading-[1.5] so the line-height matches paragraph
|
|
293
|
+
// blocks used in edit mode (where legacy strings are converted to real
|
|
294
|
+
// paragraph blocks with that line-height). Without this wrapper, the
|
|
295
|
+
// text inherits the cell's leading-none, producing shorter cells.
|
|
296
|
+
const wrapper = document.createElement('div');
|
|
297
|
+
|
|
298
|
+
wrapper.className = 'leading-[1.5]';
|
|
299
|
+
wrapper.innerHTML = cellContent;
|
|
300
|
+
container.replaceChildren(wrapper);
|
|
294
301
|
|
|
295
302
|
return;
|
|
296
303
|
}
|
|
297
304
|
|
|
298
|
-
//
|
|
299
|
-
|
|
300
|
-
|
|
305
|
+
// Clear the container before (re-)mounting block holders.
|
|
306
|
+
// This covers two cases:
|
|
307
|
+
// 1. Legacy text was previously rendered and needs to be replaced with blocks.
|
|
308
|
+
// 2. Block holders are already mounted (e.g. from edit mode before a
|
|
309
|
+
// setReadOnly toggle) — without clearing, the clone-guard below would
|
|
310
|
+
// duplicate every holder because it detects them inside a
|
|
311
|
+
// [data-blok-nested-blocks] container and appends a cloneNode(true).
|
|
312
|
+
if (hasExistingBlocks || (container.textContent ?? '').length > 0) {
|
|
313
|
+
container.replaceChildren();
|
|
301
314
|
}
|
|
302
315
|
|
|
303
316
|
for (const blockId of cellContent.blocks) {
|
|
@@ -313,12 +326,20 @@ export const mountCellBlocksReadOnly = (
|
|
|
313
326
|
continue;
|
|
314
327
|
}
|
|
315
328
|
|
|
329
|
+
// Skip blocks that don't belong to this table.
|
|
330
|
+
// Corrupted data may contain cross-table references; mounting them
|
|
331
|
+
// would steal (or clone) DOM nodes from the other table.
|
|
332
|
+
if (block.parentId !== _tableBlockId) {
|
|
333
|
+
continue;
|
|
334
|
+
}
|
|
335
|
+
|
|
316
336
|
// Guard: if the block holder is already inside another table cell's
|
|
317
|
-
// blocks container,
|
|
318
|
-
//
|
|
319
|
-
//
|
|
320
|
-
//
|
|
321
|
-
if (block.holder.closest(`[${
|
|
337
|
+
// blocks container, clone its visual content instead of moving (stealing)
|
|
338
|
+
// the DOM node. This can happen when corrupted data references the same
|
|
339
|
+
// block in multiple tables. In read-only mode a deep clone is safe
|
|
340
|
+
// because the content is non-interactive.
|
|
341
|
+
if (block.holder.closest(`[${DATA_ATTR.nestedBlocks}]`)) {
|
|
342
|
+
container.appendChild(block.holder.cloneNode(true));
|
|
322
343
|
continue;
|
|
323
344
|
}
|
|
324
345
|
|
|
@@ -374,8 +395,8 @@ export const normalizeTableData = (
|
|
|
374
395
|
export const setupKeyboardNavigation = (
|
|
375
396
|
gridEl: HTMLElement,
|
|
376
397
|
cellBlocks: TableCellBlocks | null,
|
|
377
|
-
): void => {
|
|
378
|
-
|
|
398
|
+
): (() => void) => {
|
|
399
|
+
const handler = (event: KeyboardEvent): void => {
|
|
379
400
|
const target = event.target as HTMLElement;
|
|
380
401
|
const cell = target.closest<HTMLElement>(`[${CELL_ATTR}]`);
|
|
381
402
|
|
|
@@ -388,7 +409,13 @@ export const setupKeyboardNavigation = (
|
|
|
388
409
|
if (position) {
|
|
389
410
|
cellBlocks?.handleKeyDown(event, position);
|
|
390
411
|
}
|
|
391
|
-
}
|
|
412
|
+
};
|
|
413
|
+
|
|
414
|
+
gridEl.addEventListener('keydown', handler);
|
|
415
|
+
|
|
416
|
+
return () => {
|
|
417
|
+
gridEl.removeEventListener('keydown', handler);
|
|
418
|
+
};
|
|
392
419
|
};
|
|
393
420
|
|
|
394
421
|
export const SCROLL_OVERFLOW_CLASSES = ['overflow-x-auto', 'overflow-y-hidden'];
|
|
@@ -88,6 +88,7 @@ export const buildToggleItem = (context: ToggleDOMBuilderContext): ToggleBuildRe
|
|
|
88
88
|
const childContainerElement = document.createElement('div');
|
|
89
89
|
childContainerElement.className = TOGGLE_CHILDREN_STYLES;
|
|
90
90
|
childContainerElement.setAttribute(TOGGLE_ATTR.toggleChildren, '');
|
|
91
|
+
childContainerElement.setAttribute(DATA_ATTR.nestedBlocks, '');
|
|
91
92
|
// Block DOM mutations inside the children container from triggering the toggle tool's
|
|
92
93
|
// didMutated → syncBlockDataToYjs path. Child block insertions/removals are tracked
|
|
93
94
|
// via the block hierarchy (parentId / contentIds) and must not create spurious Yjs
|
|
@@ -229,6 +229,31 @@ export class ToggleItem implements BlockTool {
|
|
|
229
229
|
this.setOpenState(false);
|
|
230
230
|
}
|
|
231
231
|
|
|
232
|
+
public setReadOnly(state: boolean): void {
|
|
233
|
+
if (!this._element) {
|
|
234
|
+
return;
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
const wasReadOnly = this.readOnly;
|
|
238
|
+
|
|
239
|
+
this.readOnly = state;
|
|
240
|
+
|
|
241
|
+
// Toggle contentEditable on the content element
|
|
242
|
+
if (this._contentElement) {
|
|
243
|
+
this._contentElement.contentEditable = state ? 'false' : 'true';
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
// Manage block changed event subscription
|
|
247
|
+
if (state && !wasReadOnly) {
|
|
248
|
+
this.api.events.off('block changed', this.handleBlockChanged);
|
|
249
|
+
} else if (!state && wasReadOnly) {
|
|
250
|
+
this.api.events.on('block changed', this.handleBlockChanged);
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
// Update body placeholder visibility (hidden in read-only mode)
|
|
254
|
+
this.updateBodyPlaceholderVisibility();
|
|
255
|
+
}
|
|
256
|
+
|
|
232
257
|
public removed(): void {
|
|
233
258
|
this.api.events.off('block changed', this.handleBlockChanged);
|
|
234
259
|
}
|
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
|
|
7
7
|
import type { API } from '../../../types';
|
|
8
8
|
|
|
9
|
+
import { mountChildBlocks } from '../nested-blocks';
|
|
9
10
|
import { setupPlaceholder } from '../../components/utils/placeholder';
|
|
10
11
|
|
|
11
12
|
import { TOGGLE_ATTR } from './constants';
|
|
@@ -94,11 +95,11 @@ export const updateChildrenVisibility = (
|
|
|
94
95
|
arrowElement.focus();
|
|
95
96
|
}
|
|
96
97
|
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
}
|
|
98
|
+
if (childContainer) {
|
|
99
|
+
mountChildBlocks(childContainer, children);
|
|
100
|
+
}
|
|
101
101
|
|
|
102
|
+
for (const child of children) {
|
|
102
103
|
if (isOpen) {
|
|
103
104
|
child.holder.classList.remove('hidden');
|
|
104
105
|
} else {
|
|
@@ -35,6 +35,12 @@ interface BlockToolAdapter extends BaseToolAdapter<ToolType.Block, BlockTool>{
|
|
|
35
35
|
*/
|
|
36
36
|
isReadOnlySupported: boolean;
|
|
37
37
|
|
|
38
|
+
/**
|
|
39
|
+
* Returns true if the Tool's prototype has a setReadOnly method,
|
|
40
|
+
* enabling the in-place read-only toggle path (no save/clear/render cycle).
|
|
41
|
+
*/
|
|
42
|
+
supportsInPlaceReadOnly: boolean;
|
|
43
|
+
|
|
38
44
|
/**
|
|
39
45
|
* Returns true if Tool supports linebreaks
|
|
40
46
|
*/
|
|
@@ -87,6 +87,26 @@ export interface BlockTool extends BaseTool {
|
|
|
87
87
|
* @returns Object with left offset in pixels, or undefined if no offset should be applied
|
|
88
88
|
*/
|
|
89
89
|
getContentOffset?(hoveredElement: Element): { left: number } | undefined;
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Returns the element that the toolbar should vertically center on.
|
|
93
|
+
* Used by tools whose editable area is deeply nested below non-editable UI
|
|
94
|
+
* (e.g., a header bar), where the default contenteditable-descendant search
|
|
95
|
+
* would position the toolbar too far down inside the block.
|
|
96
|
+
*
|
|
97
|
+
* Return undefined to use the default positioning logic.
|
|
98
|
+
*/
|
|
99
|
+
getToolbarAnchorElement?(): HTMLElement | undefined;
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* Called when read-only mode is toggled without re-rendering the block.
|
|
103
|
+
* Implementations should update the DOM in place: toggle contentEditable,
|
|
104
|
+
* bind/unbind event listeners, show/hide interactive elements, etc.
|
|
105
|
+
*
|
|
106
|
+
* Optional — tools without this method trigger a full save/clear/render
|
|
107
|
+
* fallback when read-only mode is toggled.
|
|
108
|
+
*/
|
|
109
|
+
setReadOnly?(state: boolean): void;
|
|
90
110
|
}
|
|
91
111
|
|
|
92
112
|
/**
|
|
@@ -151,6 +151,12 @@ export interface PopoverItemDefaultBaseParams {
|
|
|
151
151
|
*/
|
|
152
152
|
icon?: string;
|
|
153
153
|
|
|
154
|
+
/**
|
|
155
|
+
* Icon to be displayed on the trailing (right) side of the item.
|
|
156
|
+
* Rendered without a box background, suitable for indicators like a checkmark.
|
|
157
|
+
*/
|
|
158
|
+
trailingIcon?: string;
|
|
159
|
+
|
|
154
160
|
/**
|
|
155
161
|
* Additional displayed text
|
|
156
162
|
*/
|
package/bin/blok.mjs
DELETED
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
import { readFileSync } from 'node:fs';
|
|
4
|
-
import { run } from '../dist/cli.mjs';
|
|
5
|
-
|
|
6
|
-
const version = process.env.npm_package_version
|
|
7
|
-
|| JSON.parse(readFileSync(new URL('../package.json', import.meta.url), 'utf-8')).version;
|
|
8
|
-
const args = process.argv.slice(2);
|
|
9
|
-
|
|
10
|
-
run(args, version);
|
package/dist/cli.mjs
DELETED
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
import * as e from "node:fs";
|
|
2
|
-
//#region src/cli/commands/migrationContent.ts
|
|
3
|
-
var t = "# Migrating from EditorJS to Blok\n\nThis guide covers the breaking changes when migrating from EditorJS to Blok.\n\n## Table of Contents\n\n- [Core Changes](#core-changes)\n- [Data Attributes](#data-attributes)\n- [CSS Classes](#css-classes)\n- [Bundled Tools](#bundled-tools)\n - [Tool Configuration](#tool-configuration)\n - [Lifecycle Hooks](#lifecycle-hooks)\n - [Delimiter → Divider](#delimiter--divider)\n- [Configuration Defaults](#configuration-defaults)\n- [New API Methods](#new-api-methods)\n- [DOM Selectors](#dom-selectors)\n- [E2E Test Selectors](#e2e-test-selectors)\n\n---\n\n## Core Changes\n\n### Class Name\n\n```diff\n- import EditorJS from '@editorjs/editorjs';\n+ import Blok from '@jackuait/blok';\n\n- const editor = new EditorJS({ ... });\n+ const editor = new Blok({ ... });\n```\n\n### Default Holder\n\nThe default holder ID changed from `editorjs` to `blok`:\n\n```diff\n- <div id=\"editorjs\"></div>\n+ <div id=\"blok\"></div>\n```\n\nOr specify explicitly:\n\n```javascript\nconst editor = new Blok({\n holder: 'my-editor', // works the same as before\n});\n```\n\n### TypeScript Types\n\n```diff\n- import type { EditorConfig, OutputData } from '@editorjs/editorjs';\n+ import type { BlokConfig, OutputData } from '@jackuait/blok';\n```\n\n---\n\n## Data Attributes\n\nBlok uses `data-blok-*` attributes instead of EditorJS's mixed naming conventions.\n\n| EditorJS | Blok |\n|----------|------|\n| `data-id` | `data-blok-id` |\n| `data-item-name` | `data-blok-item-name` |\n| `data-empty` | `data-blok-empty` |\n| `.ce-block--selected` (class) | `data-blok-selected=\"true\"` |\n| — | `data-blok-component` (tool name) |\n| — | `data-blok-interface` (element type) |\n| — | `data-blok-testid` (testing) |\n| — | `data-blok-opened` (toolbar state) |\n| — | `data-blok-placeholder` |\n| — | `data-blok-stretched` |\n| — | `data-blok-focused` |\n| — | `data-blok-popover-opened` |\n| — | `data-blok-tool` (tool name on rendered element) |\n| — | `data-blok-dragging` (block being dragged) |\n| — | `data-blok-hidden` (hidden state) |\n| — | `data-blok-rtl` (RTL mode) |\n| — | `data-blok-drag-handle` (drag handle element) |\n| — | `data-blok-overlay` (selection overlay) |\n| — | `data-blok-overlay-rectangle` (selection rectangle) |\n\n### Querying Blocks\n\n```diff\n- document.querySelector('[data-id=\"abc123\"]');\n+ document.querySelector('[data-blok-id=\"abc123\"]');\n\n- document.querySelector('[data-item-name=\"bold\"]');\n+ document.querySelector('[data-blok-item-name=\"bold\"]');\n```\n\n---\n\n## CSS Classes\n\nBlok replaces BEM class names with data attributes for selection.\n\n### Editor Wrapper\n\n| EditorJS | Blok |\n|----------|------|\n| `.codex-editor` | `[data-blok-editor]` |\n| `.codex-editor__redactor` | `[data-blok-redactor]` |\n| `.codex-editor--rtl` | `[data-blok-rtl=\"true\"]` |\n\n### Block Elements\n\n| EditorJS | Blok |\n|----------|------|\n| `.ce-block` | `[data-blok-element]` |\n| `.ce-block--selected` | `[data-blok-selected=\"true\"]` |\n| `.ce-block--stretched` | `[data-blok-stretched=\"true\"]` |\n| `.ce-block--focused` | `[data-blok-focused=\"true\"]` |\n| `.ce-block__content` | `[data-blok-element-content]` |\n\n### Toolbar\n\n| EditorJS | Blok |\n|----------|------|\n| `.ce-toolbar` | `[data-blok-toolbar]` |\n| `.ce-toolbar__plus` | `[data-blok-testid=\"plus-button\"]` |\n| `.ce-toolbar__settings-btn` | `[data-blok-settings-toggler]` |\n| `.ce-toolbar__actions` | `[data-blok-testid=\"toolbar-actions\"]` |\n| `.ce-toolbox` | `[data-blok-toolbox]` |\n| `.ce-toolbox--opened` | `[data-blok-toolbox][data-blok-opened=\"true\"]` |\n\n### Inline Toolbar\n\n| EditorJS | Blok |\n|----------|------|\n| `.ce-inline-toolbar` | `[data-blok-testid=\"inline-toolbar\"]` |\n| `.ce-inline-tool` | `[data-blok-testid=\"inline-tool\"]` |\n| `.ce-inline-tool--link` | `[data-blok-testid=\"inline-tool-link\"]` |\n| `.ce-inline-tool--bold` | `[data-blok-testid=\"inline-tool-bold\"]` |\n| `.ce-inline-tool--italic` | `[data-blok-testid=\"inline-tool-italic\"]` |\n\n### Popover\n\n| EditorJS | Blok |\n|----------|------|\n| `.ce-popover` | `[data-blok-popover]` |\n| `.ce-popover--opened` | `[data-blok-popover][data-blok-opened=\"true\"]` |\n| `.ce-popover__container` | `[data-blok-popover-container]` |\n| `.ce-popover-item` | `[data-blok-testid=\"popover-item\"]` |\n| `.ce-popover-item--focused` | `[data-blok-focused=\"true\"]` |\n| `.ce-popover-item--confirmation` | `[data-blok-confirmation=\"true\"]` |\n| `.ce-popover-item__icon` | `[data-blok-testid=\"popover-item-icon\"]` |\n| `.ce-popover-item__icon--tool` | `[data-blok-testid=\"popover-item-icon-tool\"]` |\n\n### Tool-Specific Classes\n\n| EditorJS | Blok |\n|----------|------|\n| `.ce-paragraph` | `[data-blok-tool=\"paragraph\"]` |\n| `.ce-header` | `[data-blok-tool=\"header\"]` |\n\n### Conversion Toolbar & Settings\n\n| EditorJS | Blok |\n|----------|------|\n| `.ce-conversion-toolbar` | `[data-blok-testid=\"conversion-toolbar\"]` |\n| `.ce-conversion-tool` | `[data-blok-testid=\"conversion-tool\"]` |\n| `.ce-settings` | `[data-blok-testid=\"block-settings\"]` |\n| `.ce-tune` | `[data-blok-testid=\"block-tune\"]` |\n\n### Other Elements\n\n| EditorJS | Blok |\n|----------|------|\n| `.ce-stub` | `[data-blok-stub]` |\n| `.ce-drag-handle` | `[data-blok-drag-handle]` |\n| `.ce-ragged-right` | `[data-blok-ragged-right=\"true\"]` |\n\n### CDX List Classes\n\n| EditorJS | Blok |\n|----------|------|\n| `.cdx-list` | `[data-blok-list]` |\n| `.cdx-list__item` | `[data-blok-list-item]` |\n| `.cdx-list--ordered` | `[data-blok-list=\"ordered\"]` |\n| `.cdx-list--unordered` | `[data-blok-list=\"unordered\"]` |\n\n### CDX Utility Classes\n\n| EditorJS | Blok |\n|----------|------|\n| `.cdx-button` | `[data-blok-button]` |\n| `.cdx-input` | `[data-blok-input]` |\n| `.cdx-loader` | `[data-blok-loader]` |\n| `.cdx-search-field` | `[data-blok-search-field]` |\n\n---\n\n## Bundled Tools\n\nBlok includes Header and Paragraph tools. No external packages needed:\n\n```diff\n- import Header from '@editorjs/header';\n- import Paragraph from '@editorjs/paragraph';\n\n+ import Blok from '@jackuait/blok';\n\nconst editor = new Blok({\n tools: {\n- header: Header,\n- paragraph: Paragraph,\n+ header: Blok.Header,\n+ paragraph: Blok.Paragraph, // optional, it's the default\n },\n});\n```\n\n### Tool Configuration\n\nBoth bundled tools accept configuration options:\n\n#### HeaderConfig\n\n```typescript\nimport type { HeaderConfig } from '@jackuait/blok';\n\nconst editor = new Blok({\n tools: {\n header: {\n class: Blok.Header,\n config: {\n placeholder: 'Enter a heading',\n levels: [2, 3, 4], // Restrict to H2-H4 only\n defaultLevel: 2, // Default to H2\n } as HeaderConfig,\n },\n },\n});\n```\n\n| Option | Type | Default | Description |\n|--------|------|---------|-------------|\n| `placeholder` | `string` | `''` | Placeholder text for empty header |\n| `levels` | `number[]` | `[1,2,3,4,5,6]` | Available heading levels (1-6) |\n| `defaultLevel` | `number` | `2` | Default heading level |\n\n#### ParagraphConfig\n\n```typescript\nimport type { ParagraphConfig } from '@jackuait/blok';\n\nconst editor = new Blok({\n tools: {\n paragraph: {\n class: Blok.Paragraph,\n config: {\n placeholder: 'Start typing...',\n preserveBlank: true,\n } as ParagraphConfig,\n },\n },\n});\n```\n\n| Option | Type | Default | Description |\n|--------|------|---------|-------------|\n| `placeholder` | `string` | `''` | Placeholder text for empty paragraph |\n| `preserveBlank` | `boolean` | `false` | Keep empty paragraphs when saving |\n\n### Delimiter → Divider\n\nEditor.js's `@editorjs/delimiter` is replaced by Blok's built-in `divider` tool:\n\n```diff\n- import Delimiter from '@editorjs/delimiter';\n\nconst editor = new Blok({\n tools: {\n- delimiter: Delimiter,\n+ divider: Blok.Divider,\n },\n});\n```\n\n**Saved data migration:** The block type name changed from `\"delimiter\"` to `\"divider\"`. The data format is identical (empty `{}`):\n\n```diff\n {\n- \"type\": \"delimiter\",\n+ \"type\": \"divider\",\n \"data\": {}\n }\n```\n\n> **Note:** Blok automatically recognizes `\"delimiter\"` blocks and renders them as dividers, so existing articles work without data migration. However, renaming the type in your database is recommended for consistency.\n\n---\n\n## Configuration Defaults\n\n| Option | EditorJS | Blok |\n|--------|----------|------|\n| `holder` | `\"editorjs\"` | `\"blok\"` |\n| `defaultBlock` | `\"paragraph\"` | `\"paragraph\"` |\n\n---\n\n## New API Methods\n\nBlok exposes shorthand methods directly on the instance:\n\n```javascript\nconst editor = new Blok({ ... });\n\n// Shorthand methods\nawait editor.save(); // Same as editor.saver.save()\neditor.clear(); // Same as editor.blocks.clear()\nawait editor.render(data);// Same as editor.blocks.render(data)\neditor.focus(); // Same as editor.caret.focus()\n\n// Event methods\neditor.on('change', handler); // Same as editor.events.on()\neditor.off('change', handler); // Same as editor.events.off()\neditor.emit('custom', data); // Same as editor.events.emit()\n```\n\n---\n\n## DOM Selectors\n\nBlok uses consistent `data-blok-interface` attributes for major UI components:\n\n```javascript\n// Find the editor wrapper\nconst editorWrapper = document.querySelector('[data-blok-interface=\"blok\"]');\n\n// Find inline toolbar\nconst inlineToolbar = document.querySelector('[data-blok-interface=\"inline-toolbar\"]');\n\n// Find tooltip\nconst tooltip = document.querySelector('[data-blok-interface=\"tooltip\"]');\n```\n\nThese selectors are stable and recommended for programmatic access to Blok's UI components.\n\n### Key Changes\n\n1. **Prefix custom classes** with `blok-` instead of `ce-` or `cdx-`\n2. **Use `data-blok-*`** attributes instead of `data-*`\n\n---\n\n## E2E Test Selectors\n\nUpdate your test selectors to use Blok's `data-blok-testid` attributes:\n\n| EditorJS | Blok |\n|----------|------|\n| `[data-cy=editorjs]` | `[data-blok-testid=\"blok-editor\"]` |\n| `.ce-block` | `[data-blok-element]` |\n| `.ce-block__content` | `[data-blok-element-content]` |\n| `.ce-toolbar` | `[data-blok-toolbar]` |\n| `.ce-toolbar__plus` | `[data-blok-testid=\"plus-button\"]` |\n| `.ce-toolbar__settings-btn` | `[data-blok-settings-toggler]` |\n| `.ce-toolbar__actions` | `[data-blok-testid=\"toolbar-actions\"]` |\n| `.ce-toolbox` | `[data-blok-toolbox]` |\n| `.ce-inline-toolbar` | `[data-blok-testid=\"inline-toolbar\"]` |\n| `.ce-popover` | `[data-blok-popover]` |\n| `.ce-popover-item` | `[data-blok-testid=\"popover-item\"]` |\n| `[data-item-name=\"...\"]` | `[data-blok-item-name=\"...\"]` |\n\n### Playwright Example\n\n```diff\n// EditorJS\n- await page.locator('[data-cy=editorjs] .ce-block').click();\n- await page.locator('.ce-toolbar__settings-btn').click();\n- await page.locator('[data-item-name=\"delete\"]').click();\n\n// Blok\n+ await page.locator('[data-blok-element]').click();\n+ await page.locator('[data-blok-settings-toggler]').click();\n+ await page.locator('[data-blok-item-name=\"delete\"]').click();\n```\n\n### Additional Test Selectors\n\n| Element | Selector |\n|---------|----------|\n| Block tunes popover | `[data-blok-testid=\"block-tunes-popover\"]` |\n| Popover search input | `[data-blok-testid=\"popover-search-input\"]` |\n| Popover item title | `[data-blok-testid=\"popover-item-title\"]` |\n| Popover overlay | `[data-blok-testid=\"popover-overlay\"]` |\n| Inline tool input | `[data-blok-testid=\"inline-tool-input\"]` |\n| Tooltip | `[data-blok-testid=\"tooltip\"]` |\n| Redactor | `[data-blok-testid=\"redactor\"]` |\n| Toolbox | `[data-blok-testid=\"toolbox\"]` |\n| Toolbox popover | `[data-blok-testid=\"toolbox-popover\"]` |\n| Selection overlay | `[data-blok-testid=\"overlay\"]` |\n| Selection rectangle | `[data-blok-testid=\"overlay-rectangle\"]` |\n\n---\n\n### State Selectors\n\n| State | Selector |\n|-------|----------|\n| Toolbar opened | `[data-blok-opened=\"true\"]` |\n| Block selected | `[data-blok-selected=\"true\"]` |\n| Popover opened | `[data-blok-popover-opened=\"true\"]` |\n| Item focused | `[data-blok-focused=\"true\"]` |\n| Item disabled | `[data-blok-disabled=\"true\"]` |\n| Nested popover | `[data-blok-nested=\"true\"]` |\n| Toolbox opened | `[data-blok-toolbox-opened=\"true\"]` |\n| Block dragging | `[data-blok-dragging=\"true\"]` |\n| Element hidden | `[data-blok-hidden=\"true\"]` |\n| RTL mode | `[data-blok-rtl=\"true\"]` |\n\n---\n\n## Quick Checklist\n\n- [ ] Replace `new EditorJS` with `new Blok`\n- [ ] Update imports from `@editorjs/*` to `@jackuait/blok`\n- [ ] Change holder from `editorjs` to `blok` (or specify explicitly)\n- [ ] Use bundled tools: `Blok.Header`, `Blok.Paragraph`\n- [ ] Replace `@editorjs/delimiter` with built-in `Blok.Divider`\n- [ ] Update `EditorConfig` type to `BlokConfig`\n- [ ] Replace `data-id` with `data-blok-id` in queries\n- [ ] Replace `data-item-name` with `data-blok-item-name`\n- [ ] Replace `.ce-*` selectors with `[data-blok-*]` attributes\n- [ ] Replace `.cdx-*` selectors with `[data-blok-*]` attributes\n- [ ] Update E2E test selectors\n", n = (e) => [
|
|
4
|
-
"# Blok Migration Guide (for LLM-assisted migration)",
|
|
5
|
-
"",
|
|
6
|
-
"> This document contains everything needed to migrate a project from EditorJS to Blok.",
|
|
7
|
-
"> Apply these changes systematically to the user's codebase.",
|
|
8
|
-
`> Current Blok version: ${e}`,
|
|
9
|
-
"",
|
|
10
|
-
"---",
|
|
11
|
-
""
|
|
12
|
-
].join("\n") + t, r = (t, n) => {
|
|
13
|
-
n ? (e.writeFileSync(n, t, "utf-8"), process.stderr.write(`Written to ${n}\n`)) : process.stdout.write(t);
|
|
14
|
-
}, i = "Usage: blok [options]\n\nOptions:\n --migration Output the EditorJS to Blok migration guide (LLM-friendly)\n --output <file> Write output to a file instead of stdout\n --help Show this help message\n\nExamples:\n npx @jackuait/blok --migration\n npx @jackuait/blok --migration | pbcopy\n npx @jackuait/blok --migration --output migration-guide.md\n", a = (e) => {
|
|
15
|
-
if (e.includes("--help")) return { command: "help" };
|
|
16
|
-
if (e.includes("--migration")) {
|
|
17
|
-
let t = e.indexOf("--output");
|
|
18
|
-
return {
|
|
19
|
-
command: "migration",
|
|
20
|
-
output: t === -1 ? void 0 : e[t + 1]
|
|
21
|
-
};
|
|
22
|
-
}
|
|
23
|
-
return { command: null };
|
|
24
|
-
}, o = (e, t) => {
|
|
25
|
-
let { command: o, output: s } = a(e);
|
|
26
|
-
switch (o) {
|
|
27
|
-
case "migration":
|
|
28
|
-
r(n(t), s);
|
|
29
|
-
break;
|
|
30
|
-
case "help":
|
|
31
|
-
case null:
|
|
32
|
-
process.stdout.write(i);
|
|
33
|
-
break;
|
|
34
|
-
}
|
|
35
|
-
};
|
|
36
|
-
//#endregion
|
|
37
|
-
export { o as run };
|