@jackuait/blok 0.10.3 → 0.10.5
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-3wc3aInM.mjs → blok-DSP5zC_s.mjs} +2374 -2159
- package/dist/chunks/{constants-Bp622jic.mjs → constants-B0Tns0mh.mjs} +318 -227
- package/dist/chunks/{i18next-loader-CDnSPae_.mjs → i18next-loader-D_v0EmDP.mjs} +1 -1
- package/dist/chunks/{lightweight-i18n-DZmo8dAI.mjs → lightweight-i18n-DTYoSr_o.mjs} +21 -0
- package/dist/{messages-bkGniiaz.mjs → chunks/messages--X-ZzYSb.mjs} +24 -3
- package/dist/chunks/{messages-DrfRYiM32.mjs → messages--tSqMtkx2.mjs} +24 -3
- package/dist/chunks/{messages-CW35K1pq.mjs → messages-3w1e16T2.mjs} +25 -4
- package/dist/chunks/{messages-BHMiK51R.mjs → messages-B5BaA6AV.mjs} +24 -3
- package/dist/{messages-DKHbt-7l2.mjs → chunks/messages-B5ZVSxG4.mjs} +25 -4
- package/dist/chunks/{messages-kGmxkeFH.mjs → messages-B9PUHq4t.mjs} +24 -3
- package/dist/chunks/{messages-BlxwW7M6.mjs → messages-BAxCMQgm.mjs} +24 -3
- package/dist/chunks/{messages-BRAoJpOu.mjs → messages-BDhWRN6Y.mjs} +25 -4
- package/dist/{messages-CdEASHDp2.mjs → chunks/messages-BGpx2ecP2.mjs} +24 -3
- package/dist/{messages-C6ONf71u2.mjs → chunks/messages-BHUQs6402.mjs} +24 -3
- package/dist/{messages-BrOWqNCu2.mjs → chunks/messages-BIXCvkbG.mjs} +24 -3
- package/dist/chunks/{messages-DMoERagV2.mjs → messages-BKeL1zk-2.mjs} +24 -3
- package/dist/chunks/{messages-DjvaiALg2.mjs → messages-Bedied602.mjs} +24 -3
- package/dist/chunks/{messages-oMc7qugU2.mjs → messages-Bg8uBETk2.mjs} +24 -3
- package/dist/{messages-CRNogopy2.mjs → chunks/messages-Blg1X6YL.mjs} +24 -3
- package/dist/chunks/{messages-euM2m3wQ.mjs → messages-BmDMK9Dg.mjs} +24 -3
- package/dist/{messages-D3rwCtKn.mjs → chunks/messages-BmDw1fZF2.mjs} +24 -3
- package/dist/{messages-qfvXgPpu2.mjs → chunks/messages-BqKIunt0.mjs} +24 -3
- package/dist/chunks/{messages-BfAcUavP.mjs → messages-BszGK0ox.mjs} +26 -5
- package/dist/{messages-BckDk9aq2.mjs → chunks/messages-Buwm8xrX2.mjs} +24 -3
- package/dist/chunks/{messages-CC_noR8y.mjs → messages-BvoElEE_.mjs} +24 -3
- package/dist/chunks/{messages-zt6zdYWh.mjs → messages-ByHXyVi6.mjs} +23 -2
- package/dist/chunks/{messages-DBMaLL8b2.mjs → messages-C9HPruJj2.mjs} +24 -3
- package/dist/{messages-DQORja0D.mjs → chunks/messages-CDtmVcBc.mjs} +26 -5
- package/dist/chunks/{messages-wl8YrvGG.mjs → messages-CEWKcK-Q.mjs} +23 -2
- package/dist/chunks/{messages-CZSlfnkO2.mjs → messages-CRLvJfNU2.mjs} +22 -1
- package/dist/chunks/{messages-BRoa9tGl.mjs → messages-CXjSY5Fy.mjs} +24 -3
- package/dist/{messages-BesJaI6A.mjs → chunks/messages-CdWS0hvw.mjs} +29 -8
- package/dist/{messages-JNrYldAa2.mjs → chunks/messages-Cic0Y1z6.mjs} +24 -3
- package/dist/chunks/{messages-CTCe595D2.mjs → messages-CmGixnBb2.mjs} +24 -3
- package/dist/chunks/{messages-JSQjKQ8I.mjs → messages-CrCalcxK.mjs} +24 -3
- package/dist/chunks/{messages-DUr9WAkD.mjs → messages-D3wlt9eE.mjs} +22 -1
- package/dist/{messages-CdduYw-q.mjs → chunks/messages-D5NWb-B9.mjs} +23 -2
- package/dist/chunks/{messages-CRF7nNrO.mjs → messages-D5lY22F4.mjs} +24 -3
- package/dist/{messages-_PLyRfVw.mjs → chunks/messages-DGYjioKM.mjs} +26 -5
- package/dist/{messages-Che99vKP.mjs → chunks/messages-DIH2U0ZD.mjs} +24 -3
- package/dist/chunks/{messages-BJ-vT1SU2.mjs → messages-DIUegdwv2.mjs} +24 -3
- package/dist/chunks/{messages-BgM91Lxm2.mjs → messages-DKZHsfXy2.mjs} +25 -4
- package/dist/chunks/{messages-1_6UkKLS.mjs → messages-DKjUcEfs.mjs} +24 -3
- package/dist/{messages-C1vc5584.mjs → chunks/messages-DOPK-Xif2.mjs} +24 -3
- package/dist/chunks/{messages-DB_-5Xln.mjs → messages-DSMFg80t.mjs} +25 -4
- package/dist/{messages-A96tMxeU.mjs → chunks/messages-DT6eM0I22.mjs} +22 -1
- package/dist/chunks/{messages-DUeiPraX.mjs → messages-DZTQIS9F.mjs} +24 -3
- package/dist/{messages-apA6BStA.mjs → chunks/messages-DalLfJNC.mjs} +24 -3
- package/dist/chunks/{messages-QilfinOn2.mjs → messages-DggaAu362.mjs} +24 -3
- package/dist/chunks/{messages-CxxyR4vY.mjs → messages-DgoJDjHm.mjs} +24 -3
- package/dist/chunks/{messages-ElIGUi0O2.mjs → messages-DhgEjOjw2.mjs} +25 -4
- package/dist/chunks/{messages-sDdNf8O9.mjs → messages-Dk-d3mmM.mjs} +22 -1
- package/dist/{messages-BE_z-zrb.mjs → chunks/messages-DlTG06-j.mjs} +25 -4
- package/dist/chunks/{messages-C0IFfhnp.mjs → messages-Dle6Hv30.mjs} +22 -1
- package/dist/{messages-DBhvm8NK.mjs → chunks/messages-DoD9yWMu2.mjs} +22 -1
- package/dist/{messages-D0lLw9KM.mjs → chunks/messages-DpnhbDoK2.mjs} +24 -3
- package/dist/{messages-DODrhcop.mjs → chunks/messages-DqGv-lj6.mjs} +24 -3
- package/dist/{messages-CZbcxlZt2.mjs → chunks/messages-DslnYTHU2.mjs} +24 -3
- package/dist/chunks/{messages-Du2BffA7.mjs → messages-IjEU7XAq.mjs} +24 -3
- package/dist/chunks/{messages-BK8Cp2d0.mjs → messages-JRjsu_bC.mjs} +24 -3
- package/dist/chunks/{messages-CszmHAvQ.mjs → messages-PkO_43Eb.mjs} +24 -3
- package/dist/chunks/{messages-CQBo3lmL2.mjs → messages-W2zpf0Mu2.mjs} +24 -3
- package/dist/{messages-Do7Xjy0n.mjs → chunks/messages-adEATsLK.mjs} +23 -2
- package/dist/{messages-E8NjqzWq2.mjs → chunks/messages-b8XGiuAa2.mjs} +23 -2
- package/dist/{messages-CisR4PNV.mjs → chunks/messages-bteFpBer.mjs} +24 -3
- package/dist/chunks/{messages-DVr1sqfI2.mjs → messages-cR48x2Aq2.mjs} +24 -3
- package/dist/chunks/{messages-4Ck88DYZ2.mjs → messages-f-YBthdd2.mjs} +24 -3
- package/dist/{messages-Xc0KUbYl.mjs → chunks/messages-fUpUvsRN.mjs} +25 -4
- package/dist/{messages-Be_2RHZD.mjs → chunks/messages-gNK1EolD.mjs} +25 -4
- package/dist/{messages-DfFZ6Yj5.mjs → chunks/messages-vqR3RAU4.mjs} +24 -3
- package/dist/{messages-BbJ7ZXY8.mjs → chunks/messages-wSX_4fK1.mjs} +24 -3
- package/dist/chunks/{tools-BC1jRfoS.mjs → tools-KZmhOKEo.mjs} +3407 -1299
- package/dist/full.mjs +10 -10
- package/dist/locales.mjs +88 -67
- package/dist/{chunks/messages-D22e9h7V2.mjs → messages--zgIPYtb.mjs} +22 -1
- package/dist/{chunks/messages-EDMC5ukV.mjs → messages-4jULpVvw.mjs} +24 -3
- package/dist/{messages-DK6dA0O2.mjs → messages-AbwSlRf_.mjs} +26 -5
- package/dist/{messages-Ddq3Ce3E2.mjs → messages-B-dl7Pwb2.mjs} +25 -4
- package/dist/{chunks/messages-BAlZjPcl.mjs → messages-B3rCRhb1.mjs} +24 -3
- package/dist/{chunks/messages-DSrdy9Nw2.mjs → messages-B73L8nKc2.mjs} +24 -3
- package/dist/{messages-ClGvlFcH2.mjs → messages-BAjsD2Vm2.mjs} +24 -3
- package/dist/{chunks/messages-BbEW9bQz.mjs → messages-BBodSb5B2.mjs} +24 -3
- package/dist/{messages-DopaMHC42.mjs → messages-BTpn6H9x2.mjs} +22 -1
- package/dist/{messages-D0005ti32.mjs → messages-BWb0GjTj2.mjs} +24 -3
- package/dist/{messages-Q5sQeVap2.mjs → messages-BbCgnri12.mjs} +24 -3
- package/dist/{chunks/messages-BeGZqQwz.mjs → messages-Bfon_Y3q.mjs} +25 -4
- package/dist/{messages-CTTmWn4Y2.mjs → messages-BhOtow9J2.mjs} +24 -3
- package/dist/{messages-98nQiC7t2.mjs → messages-BoB7m0uu2.mjs} +25 -4
- package/dist/{messages-CT-Kdas6.mjs → messages-BsOZPjeg.mjs} +24 -3
- package/dist/{messages-D6VIFnSW.mjs → messages-BuzKUYPV.mjs} +24 -3
- package/dist/{chunks/messages-DEBy3nuJ2.mjs → messages-BzOKMdMQ.mjs} +22 -1
- package/dist/{messages-DOGbHYv-2.mjs → messages-C2H3PeQW2.mjs} +24 -3
- package/dist/{chunks/messages-DxHh0O8j2.mjs → messages-C5KNzSTk.mjs} +24 -3
- package/dist/{chunks/messages-eFd4YYzt.mjs → messages-CIDYjE6l.mjs} +24 -3
- package/dist/{messages-Dqu4aX9s.mjs → messages-CJmyF5ye.mjs} +23 -2
- package/dist/{messages-qbKjjvgd2.mjs → messages-CTwiYb2a2.mjs} +22 -1
- package/dist/{chunks/messages-CPBN4zWc.mjs → messages-CUHoJaDO.mjs} +24 -3
- package/dist/{messages-D05jqBIa2.mjs → messages-CVeuqUjQ2.mjs} +24 -3
- package/dist/{chunks/messages-BMD37y3q2.mjs → messages-CW75b4sz.mjs} +24 -3
- package/dist/{chunks/messages-CD_MnBln.mjs → messages-CXd7YeWV.mjs} +24 -3
- package/dist/{messages-DVL0KZE5.mjs → messages-CjlYkunD.mjs} +24 -3
- package/dist/{chunks/messages-BKN3YVIj.mjs → messages-CrGx64yd.mjs} +25 -4
- package/dist/{messages-BK_LsgY4.mjs → messages-Ct0jbgHd.mjs} +24 -3
- package/dist/{messages-BmH2cQHQ.mjs → messages-CtKrCYD1.mjs} +24 -3
- package/dist/{messages-neGD3WGq.mjs → messages-Cu2eLjfJ.mjs} +24 -3
- package/dist/{messages-Brd5R-da2.mjs → messages-CvwQ-fK_2.mjs} +24 -3
- package/dist/{messages-uwK7ktqk.mjs → messages-Cy6UYN9b.mjs} +22 -1
- package/dist/{chunks/messages-ChK7v1PV.mjs → messages-D01vnfA9.mjs} +24 -3
- package/dist/{messages-DpwMKDV0.mjs → messages-D0BAV45W.mjs} +24 -3
- package/dist/{messages-LMaR2_bE.mjs → messages-D5LGpdga.mjs} +24 -3
- package/dist/{messages-BcVB3osF.mjs → messages-DATK4ftv.mjs} +25 -4
- package/dist/{chunks/messages-Bz0-KNEB.mjs → messages-DEl77Urv2.mjs} +25 -4
- package/dist/{messages-DSmxJWju2.mjs → messages-DHNjM2nv2.mjs} +22 -1
- package/dist/{messages-DYuD5-rO.mjs → messages-DMW8b_sO.mjs} +24 -3
- package/dist/{chunks/messages-DPzHD51Y.mjs → messages-DNmgANKr.mjs} +23 -2
- package/dist/{chunks/messages-C1S9ztpF.mjs → messages-DQaa3cEM.mjs} +25 -4
- package/dist/{chunks/messages-a07QVz8U.mjs → messages-DSlD4bV9.mjs} +24 -3
- package/dist/{messages-DM4Gjc9h.mjs → messages-DTzbkXFt.mjs} +24 -3
- package/dist/{messages-LYJbLq_F.mjs → messages-DbZihxtV.mjs} +24 -3
- package/dist/{messages-C_Qn9SbQ.mjs → messages-DeE8fyKQ.mjs} +24 -3
- package/dist/{chunks/messages-Q7-4ZJLB2.mjs → messages-Dg-TpO2S2.mjs} +24 -3
- package/dist/{messages-BiTMwiKH.mjs → messages-DgP82LzF.mjs} +23 -2
- package/dist/{chunks/messages-QMOmwcZb.mjs → messages-Dh3Vt7WC.mjs} +23 -2
- package/dist/{messages-C0GSBBCo2.mjs → messages-DiVVyZD22.mjs} +25 -4
- package/dist/{chunks/messages-BONyZroH.mjs → messages-DpRnGjoe.mjs} +26 -5
- package/dist/{chunks/messages-8Ld7P_9j2.mjs → messages-DqZmrFaa2.mjs} +24 -3
- package/dist/{chunks/messages-CxiURE2X.mjs → messages-Dra9Fz5Q.mjs} +26 -5
- package/dist/{chunks/messages-Clku7Cf-2.mjs → messages-DuPBRgEF2.mjs} +23 -2
- package/dist/{messages-53w0fPZS2.mjs → messages-DuxEyAY-2.mjs} +25 -4
- package/dist/{chunks/messages-D7dx_6k8.mjs → messages-FmJD6lHR2.mjs} +24 -3
- package/dist/{chunks/messages-DTN1XGll.mjs → messages-ONielGl92.mjs} +24 -3
- package/dist/{chunks/messages-CIfUm1Oa.mjs → messages-RzgUqCGb2.mjs} +24 -3
- package/dist/{messages-DpJGbx3q.mjs → messages-U22AKGKs.mjs} +24 -3
- package/dist/{messages-2ZWBTerL.mjs → messages-XufeeRfO.mjs} +24 -3
- package/dist/{messages-CnuH-BZK2.mjs → messages-fprUm7SO2.mjs} +24 -3
- package/dist/{messages-C7lJg8fy2.mjs → messages-gFNdz3Tn2.mjs} +24 -3
- package/dist/{chunks/messages-C15z2r5U.mjs → messages-h_n5GBm6.mjs} +29 -8
- package/dist/{chunks/messages-CvANwuht2.mjs → messages-oOogIpsL2.mjs} +24 -3
- package/dist/{chunks/messages-DtoId_bw2.mjs → messages-otwg3KcK.mjs} +24 -3
- package/dist/{messages-D81w6AmW.mjs → messages-rDDoBMWb.mjs} +24 -3
- package/dist/{messages-Dnd5YSWv.mjs → messages-trQPxZIu.mjs} +24 -3
- package/dist/react.mjs +2 -2
- package/dist/tools.mjs +3 -3
- package/dist/vendor.LICENSE.txt +135 -0
- package/package.json +2 -1
- package/src/blok.ts +103 -0
- package/src/components/block/index.ts +21 -2
- package/src/components/block-tunes/block-tune-copy-link.ts +82 -0
- package/src/components/i18n/locales/am/messages.json +24 -3
- package/src/components/i18n/locales/ar/messages.json +24 -3
- package/src/components/i18n/locales/az/messages.json +24 -3
- package/src/components/i18n/locales/bg/messages.json +23 -2
- package/src/components/i18n/locales/bn/messages.json +24 -3
- package/src/components/i18n/locales/bs/messages.json +26 -5
- package/src/components/i18n/locales/cs/messages.json +25 -4
- package/src/components/i18n/locales/da/messages.json +25 -4
- package/src/components/i18n/locales/de/messages.json +24 -3
- package/src/components/i18n/locales/dv/messages.json +24 -3
- package/src/components/i18n/locales/el/messages.json +24 -3
- package/src/components/i18n/locales/en/messages.json +21 -0
- package/src/components/i18n/locales/es/messages.json +25 -4
- package/src/components/i18n/locales/et/messages.json +23 -2
- package/src/components/i18n/locales/fa/messages.json +24 -3
- package/src/components/i18n/locales/fi/messages.json +24 -3
- package/src/components/i18n/locales/fil/messages.json +29 -8
- package/src/components/i18n/locales/fr/messages.json +24 -3
- package/src/components/i18n/locales/gu/messages.json +24 -3
- package/src/components/i18n/locales/he/messages.json +24 -3
- package/src/components/i18n/locales/hi/messages.json +24 -3
- package/src/components/i18n/locales/hr/messages.json +26 -5
- package/src/components/i18n/locales/hu/messages.json +25 -4
- package/src/components/i18n/locales/hy/messages.json +24 -3
- package/src/components/i18n/locales/id/messages.json +23 -2
- package/src/components/i18n/locales/it/messages.json +26 -5
- package/src/components/i18n/locales/ja/messages.json +24 -3
- package/src/components/i18n/locales/ka/messages.json +24 -3
- package/src/components/i18n/locales/km/messages.json +22 -1
- package/src/components/i18n/locales/kn/messages.json +24 -3
- package/src/components/i18n/locales/ko/messages.json +24 -3
- package/src/components/i18n/locales/ku/messages.json +24 -3
- package/src/components/i18n/locales/lo/messages.json +22 -1
- package/src/components/i18n/locales/lt/messages.json +24 -3
- package/src/components/i18n/locales/lv/messages.json +24 -3
- package/src/components/i18n/locales/mk/messages.json +24 -3
- package/src/components/i18n/locales/ml/messages.json +24 -3
- package/src/components/i18n/locales/mn/messages.json +24 -3
- package/src/components/i18n/locales/mr/messages.json +24 -3
- package/src/components/i18n/locales/ms/messages.json +22 -1
- package/src/components/i18n/locales/my/messages.json +24 -3
- package/src/components/i18n/locales/ne/messages.json +24 -3
- package/src/components/i18n/locales/nl/messages.json +24 -3
- package/src/components/i18n/locales/no/messages.json +25 -4
- package/src/components/i18n/locales/pa/messages.json +24 -3
- package/src/components/i18n/locales/pl/messages.json +25 -4
- package/src/components/i18n/locales/ps/messages.json +24 -3
- package/src/components/i18n/locales/pt/messages.json +24 -3
- package/src/components/i18n/locales/ro/messages.json +24 -3
- package/src/components/i18n/locales/ru/messages.json +23 -2
- package/src/components/i18n/locales/sd/messages.json +24 -3
- package/src/components/i18n/locales/si/messages.json +24 -3
- package/src/components/i18n/locales/sk/messages.json +25 -4
- package/src/components/i18n/locales/sl/messages.json +25 -4
- package/src/components/i18n/locales/sq/messages.json +25 -4
- package/src/components/i18n/locales/sr/messages.json +24 -3
- package/src/components/i18n/locales/sv/messages.json +24 -3
- package/src/components/i18n/locales/sw/messages.json +22 -1
- package/src/components/i18n/locales/ta/messages.json +24 -3
- package/src/components/i18n/locales/te/messages.json +24 -3
- package/src/components/i18n/locales/th/messages.json +22 -1
- package/src/components/i18n/locales/tr/messages.json +24 -3
- package/src/components/i18n/locales/ug/messages.json +24 -3
- package/src/components/i18n/locales/uk/messages.json +23 -2
- package/src/components/i18n/locales/ur/messages.json +24 -3
- package/src/components/i18n/locales/vi/messages.json +22 -1
- package/src/components/i18n/locales/yi/messages.json +24 -3
- package/src/components/i18n/locales/zh/messages.json +24 -3
- package/src/components/icons/index.ts +65 -0
- package/src/components/inline-tools/inline-tool-bold.ts +10 -0
- package/src/components/inline-tools/inline-tool-code.ts +35 -1
- package/src/components/inline-tools/inline-tool-italic.ts +37 -1
- package/src/components/inline-tools/inline-tool-strikethrough.ts +35 -1
- package/src/components/inline-tools/inline-tool-underline.ts +35 -1
- package/src/components/inline-tools/services/bold-normalization-pass.ts +2 -4
- package/src/components/inline-tools/utils/formatting-range-utils.ts +83 -0
- package/src/components/modules/api/tools.ts +19 -0
- package/src/components/modules/blockEvents/composers/keyboardNavigation.ts +7 -1
- package/src/components/modules/blockManager/blockManager.ts +22 -0
- package/src/components/modules/blockManager/event-binder.ts +12 -1
- package/src/components/modules/blockManager/factory.ts +4 -0
- package/src/components/modules/blockManager/types.ts +4 -0
- package/src/components/modules/blockManager/yjs-sync.ts +16 -2
- package/src/components/modules/paste/google-docs-preprocessor.ts +49 -3
- package/src/components/modules/paste/handlers/table-cells-handler.ts +12 -2
- package/src/components/modules/paste/index.ts +8 -4
- package/src/components/modules/paste/types.ts +2 -0
- package/src/components/modules/renderer.ts +22 -2
- package/src/components/modules/saver.ts +19 -1
- package/src/components/modules/themeManager.ts +3 -1
- package/src/components/modules/toolbar/blockSettings.ts +51 -1
- package/src/components/modules/toolbar/inline/index.ts +0 -3
- package/src/components/modules/tools.ts +5 -0
- package/src/components/modules/ui.ts +1 -0
- package/src/components/modules/uiControllers/controllers/keyboard.ts +79 -0
- package/src/components/modules/uiControllers/controllers/selection.ts +14 -2
- package/src/components/modules/yjs/document-store.ts +22 -0
- package/src/components/modules/yjs/index.ts +10 -0
- package/src/components/modules/yjs/serializer.ts +20 -0
- package/src/components/ui/toolbox.ts +0 -1
- package/src/components/utils/id-generator.ts +11 -0
- package/src/components/utils/key-icon.ts +187 -0
- package/src/components/utils/popover/components/hint/hint.ts +3 -1
- package/src/components/utils/popover/components/popover-item/popover-item-default/popover-item-default.ts +18 -5
- package/src/components/utils/popover/popover-abstract.ts +45 -0
- package/src/components/utils/popover/popover-desktop.ts +1 -0
- package/src/components/utils/popover/popover-position.ts +4 -2
- package/src/components/utils/popover/popover.const.ts +2 -0
- package/src/components/utils.ts +1 -0
- package/src/styles/main.css +1272 -0
- package/src/tools/code/index.ts +4 -0
- package/src/tools/database/database-backend-sync.ts +132 -0
- package/src/tools/database/database-board-view.ts +410 -0
- package/src/tools/database/database-card-drag.ts +306 -0
- package/src/tools/database/database-card-drawer.ts +546 -0
- package/src/tools/database/database-column-controls.ts +141 -0
- package/src/tools/database/database-column-drag.ts +262 -0
- package/src/tools/database/database-keyboard.ts +35 -0
- package/src/tools/database/database-list-row-drag.ts +245 -0
- package/src/tools/database/database-list-view.ts +333 -0
- package/src/tools/database/database-model.ts +214 -0
- package/src/tools/database/database-property-type-popover.ts +108 -0
- package/src/tools/database/database-tab-bar.ts +558 -0
- package/src/tools/database/database-view-popover.ts +129 -0
- package/src/tools/database/database-view-renderer.ts +25 -0
- package/src/tools/database/database-view.ts +269 -0
- package/src/tools/database/index.ts +1223 -0
- package/src/tools/database/types.ts +168 -0
- package/src/tools/database-row/index.ts +74 -0
- package/src/tools/index.ts +4 -0
- package/types/api/tools.d.ts +18 -0
- package/types/configs/blok-config.d.ts +27 -0
- package/types/data-formats/output-data.d.ts +13 -0
- package/types/index.d.ts +17 -0
- package/types/tools/database.d.ts +152 -0
- package/types/tools-entry.d.ts +7 -4
- package/types/utils/popover/popover.d.ts +6 -0
|
@@ -18,13 +18,15 @@
|
|
|
18
18
|
"toolNames.numberedList": "נומעריקע ליסטע",
|
|
19
19
|
"toolNames.todoList": "צו-טאָן ליסטע",
|
|
20
20
|
"toolNames.toggleList": "אויפֿקלאַפּ ליסטע",
|
|
21
|
+
"toolNames.board": "טאָוול",
|
|
22
|
+
"toolNames.database": "דאַטאַבאַנק",
|
|
21
23
|
"tools.link.addLink": "צולייגן לינק",
|
|
22
24
|
"tools.link.invalidLink": "אומגילטיקער לינק",
|
|
23
25
|
"tools.marker.textColor": "טעקסט",
|
|
24
26
|
"tools.marker.background": "הינטערגרונט",
|
|
25
27
|
"tools.marker.default": "שטאַנדאַרד",
|
|
26
|
-
"tools.colorPicker.defaultSwatchLabel": "{
|
|
27
|
-
"tools.colorPicker.colorSwatchLabel": "{
|
|
28
|
+
"tools.colorPicker.defaultSwatchLabel": "{mode} {default}",
|
|
29
|
+
"tools.colorPicker.colorSwatchLabel": "{mode} {color}",
|
|
28
30
|
"tools.colorPicker.color.gray": "גרוי",
|
|
29
31
|
"tools.colorPicker.color.brown": "ברוין",
|
|
30
32
|
"tools.colorPicker.color.orange": "אָראַנזש",
|
|
@@ -71,6 +73,9 @@
|
|
|
71
73
|
"tools.table.clickToAddColumn": "קליק צו צולייגן אַ נײַע שפּאַלט",
|
|
72
74
|
"tools.table.dragToAddRemoveColumns": "שלעפּ צו צולייגן אָדער אויסמעקן שפּאַלטן",
|
|
73
75
|
"blockSettings.delete": "אויסמעקן",
|
|
76
|
+
"blockSettings.copyLink": "קאָפּירן לינק צום בלאָק",
|
|
77
|
+
"blockSettings.lastEdited": "לעצט רעדאַקטירט",
|
|
78
|
+
"blockSettings.lastEditedBy": "לעצט רעדאַקטירט דורך {name}",
|
|
74
79
|
"a11y.dragHandle": "שלעפּ צו באַוועגן בלאָק אָדער קליק פֿאַר מעניו",
|
|
75
80
|
"a11y.dragHandleRole": "שלעפּ האַנטל",
|
|
76
81
|
"a11y.dragStarted": "שלעפּט בלאָק",
|
|
@@ -143,6 +148,22 @@
|
|
|
143
148
|
"tools.callout.emojiCategoryObjects": "זאַכן",
|
|
144
149
|
"tools.callout.emojiCategorySymbols": "סימבאָלן",
|
|
145
150
|
"tools.callout.emojiCategoryFlags": "פֿאָנען",
|
|
151
|
+
"tools.database.addCard": "צוגעבן קאַרטל",
|
|
152
|
+
"tools.database.newPage": "נייע בלאט",
|
|
153
|
+
"tools.database.addColumn": "צוגעבן שפּאַלט",
|
|
154
|
+
"tools.database.cardTitlePlaceholder": "ליידיק בלאַט",
|
|
155
|
+
"tools.database.columnTitlePlaceholder": "שפּאַלט",
|
|
156
|
+
"tools.database.deleteCard": "אויסמעקן קאַרטל",
|
|
157
|
+
"tools.database.editCardTitle": "רעדאַקטירן טיטל",
|
|
158
|
+
"tools.database.cardMenuLabel": "קאַרטל אָפּציעס",
|
|
159
|
+
"tools.database.deleteColumn": "אויסמעקן שפּאַלט",
|
|
160
|
+
"tools.database.emptyColumn": "קיין קארטן",
|
|
161
|
+
"tools.database.rowTitlePlaceholder": "ליידיק בלאַט",
|
|
162
|
+
"tools.database.addRow": "צוגעבן שורה",
|
|
163
|
+
"tools.database.newRow": "נייע שורה",
|
|
164
|
+
"tools.database.openRow": "עפֿענען שורה",
|
|
165
|
+
"tools.database.deleteRow": "אויסמעקן שורה",
|
|
166
|
+
"tools.database.renameColumn": "באַנענען שפּאַלט",
|
|
146
167
|
"tools.callout.color": "קאָליר",
|
|
147
168
|
"tools.callout.colorDefault": "שטאַנדאַרד",
|
|
148
169
|
"tools.callout.colorGray": "גרוי",
|
|
@@ -184,5 +205,5 @@
|
|
|
184
205
|
"searchTerms.code": "קאָד",
|
|
185
206
|
"searchTerms.snippet": "שניצל",
|
|
186
207
|
"searchTerms.program": "פּראָגראַם",
|
|
187
|
-
"searchTerms.pre": "
|
|
208
|
+
"searchTerms.pre": "פֿאָרמאַטירט"
|
|
188
209
|
}
|
|
@@ -18,13 +18,15 @@
|
|
|
18
18
|
"toolNames.numberedList": "有序列表",
|
|
19
19
|
"toolNames.todoList": "清单",
|
|
20
20
|
"toolNames.toggleList": "折叠列表",
|
|
21
|
+
"toolNames.board": "看板",
|
|
22
|
+
"toolNames.database": "数据库",
|
|
21
23
|
"tools.link.addLink": "添加链接",
|
|
22
24
|
"tools.link.invalidLink": "链接无效",
|
|
23
25
|
"tools.marker.textColor": "文字",
|
|
24
26
|
"tools.marker.background": "背景",
|
|
25
27
|
"tools.marker.default": "默认",
|
|
26
|
-
"tools.colorPicker.defaultSwatchLabel": "{
|
|
27
|
-
"tools.colorPicker.colorSwatchLabel": "{
|
|
28
|
+
"tools.colorPicker.defaultSwatchLabel": "{mode} {default}",
|
|
29
|
+
"tools.colorPicker.colorSwatchLabel": "{mode} {color}",
|
|
28
30
|
"tools.colorPicker.color.gray": "灰色",
|
|
29
31
|
"tools.colorPicker.color.brown": "棕色",
|
|
30
32
|
"tools.colorPicker.color.orange": "橙色",
|
|
@@ -53,6 +55,9 @@
|
|
|
53
55
|
"tools.toggle.ariaLabelCollapse": "折叠",
|
|
54
56
|
"tools.toggle.ariaLabelExpand": "展开",
|
|
55
57
|
"blockSettings.delete": "删除",
|
|
58
|
+
"blockSettings.copyLink": "复制块链接",
|
|
59
|
+
"blockSettings.lastEdited": "上次编辑",
|
|
60
|
+
"blockSettings.lastEditedBy": "{name} 上次编辑",
|
|
56
61
|
"a11y.dragHandle": "拖动移动或点击打开菜单",
|
|
57
62
|
"a11y.dragHandleRole": "拖动控件",
|
|
58
63
|
"a11y.dragStarted": "正在拖动内容块",
|
|
@@ -143,6 +148,22 @@
|
|
|
143
148
|
"tools.callout.emojiCategoryObjects": "物品",
|
|
144
149
|
"tools.callout.emojiCategorySymbols": "符号",
|
|
145
150
|
"tools.callout.emojiCategoryFlags": "旗帜",
|
|
151
|
+
"tools.database.addCard": "添加卡片",
|
|
152
|
+
"tools.database.newPage": "新页面",
|
|
153
|
+
"tools.database.addColumn": "添加列",
|
|
154
|
+
"tools.database.cardTitlePlaceholder": "空白页面",
|
|
155
|
+
"tools.database.columnTitlePlaceholder": "列",
|
|
156
|
+
"tools.database.deleteCard": "删除卡片",
|
|
157
|
+
"tools.database.editCardTitle": "编辑标题",
|
|
158
|
+
"tools.database.cardMenuLabel": "卡片选项",
|
|
159
|
+
"tools.database.deleteColumn": "删除列",
|
|
160
|
+
"tools.database.emptyColumn": "没有卡片",
|
|
161
|
+
"tools.database.rowTitlePlaceholder": "空白页面",
|
|
162
|
+
"tools.database.addRow": "添加行",
|
|
163
|
+
"tools.database.newRow": "新行",
|
|
164
|
+
"tools.database.openRow": "打开行",
|
|
165
|
+
"tools.database.deleteRow": "删除行",
|
|
166
|
+
"tools.database.renameColumn": "重命名列",
|
|
146
167
|
"tools.callout.color": "颜色",
|
|
147
168
|
"tools.callout.colorDefault": "默认",
|
|
148
169
|
"tools.callout.colorGray": "灰色",
|
|
@@ -184,5 +205,5 @@
|
|
|
184
205
|
"searchTerms.code": "代码",
|
|
185
206
|
"searchTerms.snippet": "片段",
|
|
186
207
|
"searchTerms.program": "程序",
|
|
187
|
-
"searchTerms.pre": "
|
|
208
|
+
"searchTerms.pre": "预格式化"
|
|
188
209
|
}
|
|
@@ -399,6 +399,13 @@ export const IconCopy = `
|
|
|
399
399
|
</svg>
|
|
400
400
|
`;
|
|
401
401
|
|
|
402
|
+
// Pencil/Rename icon
|
|
403
|
+
export const IconPencil = `
|
|
404
|
+
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
405
|
+
<path d="M12.5 5.5l2 2M4.5 13.5l8-8 2 2-8 8H4.5v-2z" stroke="currentColor" stroke-width="1.25" stroke-linecap="round" stroke-linejoin="round"/>
|
|
406
|
+
</svg>
|
|
407
|
+
`;
|
|
408
|
+
|
|
402
409
|
// Trash/Delete icon
|
|
403
410
|
export const IconTrash = `
|
|
404
411
|
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
@@ -409,6 +416,15 @@ export const IconTrash = `
|
|
|
409
416
|
</svg>
|
|
410
417
|
`;
|
|
411
418
|
|
|
419
|
+
// Horizontal dots / more options icon
|
|
420
|
+
export const IconDotsHorizontal = `
|
|
421
|
+
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
422
|
+
<circle cx="5" cy="10" r="1.25" fill="currentColor"/>
|
|
423
|
+
<circle cx="10" cy="10" r="1.25" fill="currentColor"/>
|
|
424
|
+
<circle cx="15" cy="10" r="1.25" fill="currentColor"/>
|
|
425
|
+
</svg>
|
|
426
|
+
`;
|
|
427
|
+
|
|
412
428
|
// Toggle Heading 1 icon (H1 with toggle arrow)
|
|
413
429
|
export const IconToggleH1 = `
|
|
414
430
|
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
@@ -592,6 +608,55 @@ export const IconEmojiFlag = `
|
|
|
592
608
|
</svg>
|
|
593
609
|
`;
|
|
594
610
|
|
|
611
|
+
export const IconDatabase = `
|
|
612
|
+
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
613
|
+
<ellipse cx="10" cy="5.5" rx="6" ry="2.5" stroke="currentColor" stroke-width="1.25"/>
|
|
614
|
+
<path d="M4 5.5v4c0 1.38 2.69 2.5 6 2.5s6-1.12 6-2.5v-4" stroke="currentColor" stroke-width="1.25"/>
|
|
615
|
+
<path d="M4 9.5v4c0 1.38 2.69 2.5 6 2.5s6-1.12 6-2.5v-4" stroke="currentColor" stroke-width="1.25"/>
|
|
616
|
+
</svg>
|
|
617
|
+
`;
|
|
618
|
+
|
|
619
|
+
export const IconBoard = `
|
|
620
|
+
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
621
|
+
<rect x="3" y="4" width="14" height="12" rx="1.5" stroke="currentColor" stroke-width="1.25"/>
|
|
622
|
+
<path d="M7.5 4v12M12.5 4v12" stroke="currentColor" stroke-width="1.25"/>
|
|
623
|
+
<rect x="4.5" y="6" width="1.5" height="2" rx="0.5" fill="currentColor"/>
|
|
624
|
+
<rect x="4.5" y="9" width="1.5" height="2" rx="0.5" fill="currentColor"/>
|
|
625
|
+
<rect x="9" y="6" width="1.5" height="2" rx="0.5" fill="currentColor"/>
|
|
626
|
+
<rect x="14" y="6" width="1.5" height="2" rx="0.5" fill="currentColor"/>
|
|
627
|
+
</svg>
|
|
628
|
+
`;
|
|
629
|
+
|
|
630
|
+
export const IconGallery = `
|
|
631
|
+
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
632
|
+
<rect x="3" y="4" width="6" height="5" rx="1" stroke="currentColor" stroke-width="1.25"/>
|
|
633
|
+
<rect x="11" y="4" width="6" height="5" rx="1" stroke="currentColor" stroke-width="1.25"/>
|
|
634
|
+
<rect x="3" y="11" width="6" height="5" rx="1" stroke="currentColor" stroke-width="1.25"/>
|
|
635
|
+
<rect x="11" y="11" width="6" height="5" rx="1" stroke="currentColor" stroke-width="1.25"/>
|
|
636
|
+
</svg>
|
|
637
|
+
`;
|
|
638
|
+
|
|
639
|
+
export const IconList = `
|
|
640
|
+
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
641
|
+
<circle cx="4.5" cy="6.5" r="1" fill="currentColor"/>
|
|
642
|
+
<circle cx="4.5" cy="10" r="1" fill="currentColor"/>
|
|
643
|
+
<circle cx="4.5" cy="13.5" r="1" fill="currentColor"/>
|
|
644
|
+
<path d="M7.5 6.5h9M7.5 10h9M7.5 13.5h9" stroke="currentColor" stroke-width="1.25" stroke-linecap="round"/>
|
|
645
|
+
</svg>
|
|
646
|
+
`;
|
|
647
|
+
|
|
648
|
+
// Calendar icon (date property type)
|
|
649
|
+
export const IconCalendar = `
|
|
650
|
+
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
651
|
+
<rect x="3" y="4.5" width="14" height="12" rx="1.5" stroke="currentColor" stroke-width="1.25"/>
|
|
652
|
+
<path d="M3 8.5h14" stroke="currentColor" stroke-width="1.25" stroke-linecap="round"/>
|
|
653
|
+
<path d="M7 3v3M13 3v3" stroke="currentColor" stroke-width="1.25" stroke-linecap="round"/>
|
|
654
|
+
<circle cx="7" cy="12" r="1" fill="currentColor"/>
|
|
655
|
+
<circle cx="10" cy="12" r="1" fill="currentColor"/>
|
|
656
|
+
<circle cx="13" cy="12" r="1" fill="currentColor"/>
|
|
657
|
+
</svg>
|
|
658
|
+
`;
|
|
659
|
+
|
|
595
660
|
// Merge cells icon (two cells merging into one)
|
|
596
661
|
export const IconMergeCells = `
|
|
597
662
|
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
@@ -16,6 +16,7 @@ import {
|
|
|
16
16
|
import {
|
|
17
17
|
isRangeFormatted,
|
|
18
18
|
collectFormattingAncestors,
|
|
19
|
+
extendRangeToTrailingWhitespace,
|
|
19
20
|
} from './utils/formatting-range-utils';
|
|
20
21
|
|
|
21
22
|
/**
|
|
@@ -212,6 +213,7 @@ export class BoldInlineTool implements InlineTool {
|
|
|
212
213
|
* @param range - The Range object containing the selection to wrap
|
|
213
214
|
*/
|
|
214
215
|
private wrapWithBold(range: Range): void {
|
|
216
|
+
extendRangeToTrailingWhitespace(range);
|
|
215
217
|
const html = this.getRangeHtmlWithoutBold(range);
|
|
216
218
|
const insertedRange = this.replaceRangeWithHtml(range, `<strong>${html}</strong>`);
|
|
217
219
|
const selection = window.getSelection();
|
|
@@ -308,8 +310,16 @@ export class BoldInlineTool implements InlineTool {
|
|
|
308
310
|
BoldNormalizationPass.normalizeAroundSelection(selection);
|
|
309
311
|
|
|
310
312
|
boldAncestors.forEach((element) => {
|
|
313
|
+
if (!element.isConnected) {
|
|
314
|
+
return;
|
|
315
|
+
}
|
|
316
|
+
|
|
311
317
|
if (isElementEmpty(element)) {
|
|
312
318
|
element.remove();
|
|
319
|
+
} else if (element.textContent.trim().length === 0) {
|
|
320
|
+
// Element contains only whitespace — unwrap it to preserve the whitespace
|
|
321
|
+
// as plain text while removing the bold formatting
|
|
322
|
+
this.unwrapElement(element);
|
|
313
323
|
}
|
|
314
324
|
});
|
|
315
325
|
|
|
@@ -6,6 +6,7 @@ import {
|
|
|
6
6
|
isRangeFormatted,
|
|
7
7
|
findFormattingAncestor,
|
|
8
8
|
collectFormattingAncestors,
|
|
9
|
+
extendRangeToTrailingWhitespace,
|
|
9
10
|
} from './utils/formatting-range-utils';
|
|
10
11
|
|
|
11
12
|
/**
|
|
@@ -168,13 +169,46 @@ export class CodeInlineTool implements InlineTool {
|
|
|
168
169
|
* @param range - The Range object containing the selection to wrap
|
|
169
170
|
*/
|
|
170
171
|
private wrapWithCode(range: Range): void {
|
|
172
|
+
extendRangeToTrailingWhitespace(range);
|
|
171
173
|
const html = this.getRangeHtmlWithoutCode(range);
|
|
172
174
|
const insertedRange = this.replaceRangeWithHtml(range, `<code>${html}</code>`);
|
|
173
175
|
const selection = window.getSelection();
|
|
174
176
|
|
|
175
177
|
if (selection && insertedRange) {
|
|
178
|
+
const wrappedElement = insertedRange.startContainer.childNodes[insertedRange.startOffset] as HTMLElement | undefined;
|
|
179
|
+
const newRange = document.createRange();
|
|
180
|
+
|
|
181
|
+
if (wrappedElement) {
|
|
182
|
+
this.normalizeNbspInElement(wrappedElement);
|
|
183
|
+
newRange.selectNodeContents(wrappedElement);
|
|
184
|
+
} else {
|
|
185
|
+
newRange.setStart(insertedRange.startContainer, insertedRange.startOffset);
|
|
186
|
+
newRange.setEnd(insertedRange.endContainer, insertedRange.endOffset);
|
|
187
|
+
}
|
|
188
|
+
|
|
176
189
|
selection.removeAllRanges();
|
|
177
|
-
selection.addRange(
|
|
190
|
+
selection.addRange(newRange);
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
/**
|
|
195
|
+
* Replace non-breaking spaces (\u00A0) with regular spaces in all text nodes of an element
|
|
196
|
+
* @param element - The element to normalize
|
|
197
|
+
*/
|
|
198
|
+
private normalizeNbspInElement(element: HTMLElement): void {
|
|
199
|
+
const walker = document.createTreeWalker(element, NodeFilter.SHOW_TEXT);
|
|
200
|
+
|
|
201
|
+
while (true) {
|
|
202
|
+
const node = walker.nextNode();
|
|
203
|
+
|
|
204
|
+
if (node === null) {
|
|
205
|
+
break;
|
|
206
|
+
}
|
|
207
|
+
if (!node.textContent?.includes('\u00A0')) {
|
|
208
|
+
continue;
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
node.textContent = node.textContent.replace(/\u00A0/g, ' ');
|
|
178
212
|
}
|
|
179
213
|
}
|
|
180
214
|
|
|
@@ -7,6 +7,7 @@ import {
|
|
|
7
7
|
findFormattingAncestor,
|
|
8
8
|
hasFormattingAncestor,
|
|
9
9
|
collectFormattingAncestors,
|
|
10
|
+
extendRangeToTrailingWhitespace,
|
|
10
11
|
} from './utils/formatting-range-utils';
|
|
11
12
|
|
|
12
13
|
/**
|
|
@@ -172,13 +173,48 @@ export class ItalicInlineTool implements InlineTool {
|
|
|
172
173
|
* @param range - The Range object containing the selection to wrap
|
|
173
174
|
*/
|
|
174
175
|
private wrapWithItalic(range: Range): void {
|
|
176
|
+
extendRangeToTrailingWhitespace(range);
|
|
175
177
|
const html = this.getRangeHtmlWithoutItalic(range);
|
|
176
178
|
const insertedRange = this.replaceRangeWithHtml(range, `<i>${html}</i>`);
|
|
177
179
|
const selection = window.getSelection();
|
|
178
180
|
|
|
179
181
|
if (selection && insertedRange) {
|
|
182
|
+
const wrappedElement = insertedRange.startContainer.childNodes[insertedRange.startOffset] as HTMLElement | undefined;
|
|
183
|
+
const newRange = document.createRange();
|
|
184
|
+
|
|
185
|
+
if (wrappedElement) {
|
|
186
|
+
this.normalizeNbspInElement(wrappedElement);
|
|
187
|
+
newRange.selectNodeContents(wrappedElement);
|
|
188
|
+
} else {
|
|
189
|
+
newRange.setStart(insertedRange.startContainer, insertedRange.startOffset);
|
|
190
|
+
newRange.setEnd(insertedRange.endContainer, insertedRange.endOffset);
|
|
191
|
+
}
|
|
192
|
+
|
|
180
193
|
selection.removeAllRanges();
|
|
181
|
-
selection.addRange(
|
|
194
|
+
selection.addRange(newRange);
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
/**
|
|
199
|
+
* Replace non-breaking spaces (\u00A0) with regular spaces in all text nodes of an element.
|
|
200
|
+
* The browser's contenteditable engine will re-insert nbsp where needed for rendering
|
|
201
|
+
* (e.g. trailing spaces, consecutive spaces) on the next input event.
|
|
202
|
+
* @param element - The element to normalize
|
|
203
|
+
*/
|
|
204
|
+
private normalizeNbspInElement(element: HTMLElement): void {
|
|
205
|
+
const walker = document.createTreeWalker(element, NodeFilter.SHOW_TEXT);
|
|
206
|
+
|
|
207
|
+
while (true) {
|
|
208
|
+
const node = walker.nextNode();
|
|
209
|
+
|
|
210
|
+
if (node === null) {
|
|
211
|
+
break;
|
|
212
|
+
}
|
|
213
|
+
if (!node.textContent?.includes('\u00A0')) {
|
|
214
|
+
continue;
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
node.textContent = node.textContent.replace(/\u00A0/g, ' ');
|
|
182
218
|
}
|
|
183
219
|
}
|
|
184
220
|
|
|
@@ -7,6 +7,7 @@ import {
|
|
|
7
7
|
findFormattingAncestor,
|
|
8
8
|
hasFormattingAncestor,
|
|
9
9
|
collectFormattingAncestors,
|
|
10
|
+
extendRangeToTrailingWhitespace,
|
|
10
11
|
} from './utils/formatting-range-utils';
|
|
11
12
|
|
|
12
13
|
/**
|
|
@@ -169,13 +170,46 @@ export class StrikethroughInlineTool implements InlineTool {
|
|
|
169
170
|
* @param range - The Range object containing the selection to wrap
|
|
170
171
|
*/
|
|
171
172
|
private wrapWithStrikethrough(range: Range): void {
|
|
173
|
+
extendRangeToTrailingWhitespace(range);
|
|
172
174
|
const html = this.getRangeHtmlWithoutStrikethrough(range);
|
|
173
175
|
const insertedRange = this.replaceRangeWithHtml(range, `<s>${html}</s>`);
|
|
174
176
|
const selection = window.getSelection();
|
|
175
177
|
|
|
176
178
|
if (selection && insertedRange) {
|
|
179
|
+
const wrappedElement = insertedRange.startContainer.childNodes[insertedRange.startOffset] as HTMLElement | undefined;
|
|
180
|
+
const newRange = document.createRange();
|
|
181
|
+
|
|
182
|
+
if (wrappedElement) {
|
|
183
|
+
this.normalizeNbspInElement(wrappedElement);
|
|
184
|
+
newRange.selectNodeContents(wrappedElement);
|
|
185
|
+
} else {
|
|
186
|
+
newRange.setStart(insertedRange.startContainer, insertedRange.startOffset);
|
|
187
|
+
newRange.setEnd(insertedRange.endContainer, insertedRange.endOffset);
|
|
188
|
+
}
|
|
189
|
+
|
|
177
190
|
selection.removeAllRanges();
|
|
178
|
-
selection.addRange(
|
|
191
|
+
selection.addRange(newRange);
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
/**
|
|
196
|
+
* Replace non-breaking spaces (\u00A0) with regular spaces in all text nodes of an element
|
|
197
|
+
* @param element - The element to normalize
|
|
198
|
+
*/
|
|
199
|
+
private normalizeNbspInElement(element: HTMLElement): void {
|
|
200
|
+
const walker = document.createTreeWalker(element, NodeFilter.SHOW_TEXT);
|
|
201
|
+
|
|
202
|
+
while (true) {
|
|
203
|
+
const node = walker.nextNode();
|
|
204
|
+
|
|
205
|
+
if (node === null) {
|
|
206
|
+
break;
|
|
207
|
+
}
|
|
208
|
+
if (!node.textContent?.includes('\u00A0')) {
|
|
209
|
+
continue;
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
node.textContent = node.textContent.replace(/\u00A0/g, ' ');
|
|
179
213
|
}
|
|
180
214
|
}
|
|
181
215
|
|
|
@@ -7,6 +7,7 @@ import {
|
|
|
7
7
|
findFormattingAncestor,
|
|
8
8
|
hasFormattingAncestor,
|
|
9
9
|
collectFormattingAncestors,
|
|
10
|
+
extendRangeToTrailingWhitespace,
|
|
10
11
|
} from './utils/formatting-range-utils';
|
|
11
12
|
|
|
12
13
|
/**
|
|
@@ -169,13 +170,46 @@ export class UnderlineInlineTool implements InlineTool {
|
|
|
169
170
|
* @param range - The Range object containing the selection to wrap
|
|
170
171
|
*/
|
|
171
172
|
private wrapWithUnderline(range: Range): void {
|
|
173
|
+
extendRangeToTrailingWhitespace(range);
|
|
172
174
|
const html = this.getRangeHtmlWithoutUnderline(range);
|
|
173
175
|
const insertedRange = this.replaceRangeWithHtml(range, `<u>${html}</u>`);
|
|
174
176
|
const selection = window.getSelection();
|
|
175
177
|
|
|
176
178
|
if (selection && insertedRange) {
|
|
179
|
+
const wrappedElement = insertedRange.startContainer.childNodes[insertedRange.startOffset] as HTMLElement | undefined;
|
|
180
|
+
const newRange = document.createRange();
|
|
181
|
+
|
|
182
|
+
if (wrappedElement) {
|
|
183
|
+
this.normalizeNbspInElement(wrappedElement);
|
|
184
|
+
newRange.selectNodeContents(wrappedElement);
|
|
185
|
+
} else {
|
|
186
|
+
newRange.setStart(insertedRange.startContainer, insertedRange.startOffset);
|
|
187
|
+
newRange.setEnd(insertedRange.endContainer, insertedRange.endOffset);
|
|
188
|
+
}
|
|
189
|
+
|
|
177
190
|
selection.removeAllRanges();
|
|
178
|
-
selection.addRange(
|
|
191
|
+
selection.addRange(newRange);
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
/**
|
|
196
|
+
* Replace non-breaking spaces (\u00A0) with regular spaces in all text nodes of an element
|
|
197
|
+
* @param element - The element to normalize
|
|
198
|
+
*/
|
|
199
|
+
private normalizeNbspInElement(element: HTMLElement): void {
|
|
200
|
+
const walker = document.createTreeWalker(element, NodeFilter.SHOW_TEXT);
|
|
201
|
+
|
|
202
|
+
while (true) {
|
|
203
|
+
const node = walker.nextNode();
|
|
204
|
+
|
|
205
|
+
if (node === null) {
|
|
206
|
+
break;
|
|
207
|
+
}
|
|
208
|
+
if (!node.textContent?.includes('\u00A0')) {
|
|
209
|
+
continue;
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
node.textContent = node.textContent.replace(/\u00A0/g, ' ');
|
|
179
213
|
}
|
|
180
214
|
}
|
|
181
215
|
|
|
@@ -201,7 +201,7 @@ export class BoldNormalizationPass {
|
|
|
201
201
|
}
|
|
202
202
|
|
|
203
203
|
/**
|
|
204
|
-
* Replace non-breaking spaces with regular spaces in a text node
|
|
204
|
+
* Replace non-breaking spaces with regular spaces in a text node.
|
|
205
205
|
* @param textNode - The text node to process
|
|
206
206
|
*/
|
|
207
207
|
private replaceNbspInTextNode(textNode: Text): void {
|
|
@@ -211,10 +211,8 @@ export class BoldNormalizationPass {
|
|
|
211
211
|
return;
|
|
212
212
|
}
|
|
213
213
|
|
|
214
|
-
const normalizedText = text.replace(/\u00A0/g, ' ');
|
|
215
|
-
|
|
216
214
|
// eslint-disable-next-line no-param-reassign
|
|
217
|
-
textNode.textContent =
|
|
215
|
+
textNode.textContent = text.replace(/\u00A0/g, ' ');
|
|
218
216
|
}
|
|
219
217
|
|
|
220
218
|
/**
|
|
@@ -132,6 +132,89 @@ export const isRangeFormatted = (
|
|
|
132
132
|
return textNodes.every((textNode) => hasFormattingAncestor(textNode, predicate));
|
|
133
133
|
};
|
|
134
134
|
|
|
135
|
+
/**
|
|
136
|
+
* Walk down the `lastChild` chain of `node` and return the deepest last
|
|
137
|
+
* descendant that is a text node, or `null` if none exists.
|
|
138
|
+
*/
|
|
139
|
+
const findDeepestLastTextNode = (node: Node): Text | null => {
|
|
140
|
+
const last = node.lastChild;
|
|
141
|
+
|
|
142
|
+
if (last === null) {
|
|
143
|
+
return node.nodeType === Node.TEXT_NODE ? (node as Text) : null;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
return findDeepestLastTextNode(last);
|
|
147
|
+
};
|
|
148
|
+
|
|
149
|
+
/**
|
|
150
|
+
* Extend the range to include any trailing whitespace characters that browsers
|
|
151
|
+
* exclude from selections (e.g. Ctrl+A on loaded text stops before trailing spaces).
|
|
152
|
+
*
|
|
153
|
+
* When text is loaded via innerHTML (e.g. `"hello "`), browsers keep trailing
|
|
154
|
+
* regular spaces (char 32) as-is in the text node, but Ctrl+A / selectAll
|
|
155
|
+
* in Chromium and WebKit places the range end *before* those trailing spaces.
|
|
156
|
+
* This means `range.cloneContents()` omits them, so formatting operations
|
|
157
|
+
* (bold, italic, etc.) silently drop any trailing whitespace.
|
|
158
|
+
*
|
|
159
|
+
* By contrast, text typed by the user is stored internally with a non-breaking
|
|
160
|
+
* space (`\u00A0`) which is always included in the selection.
|
|
161
|
+
*
|
|
162
|
+
* This function mutates the range in place to cover those excluded trailing
|
|
163
|
+
* spaces, so downstream formatting can include them.
|
|
164
|
+
*
|
|
165
|
+
* Two browser behaviours are handled:
|
|
166
|
+
* 1. `endContainer` is a text node — the range ends mid-text, so check whether
|
|
167
|
+
* the remaining characters are all whitespace and extend if so.
|
|
168
|
+
* 2. `endContainer` is an element node — Ctrl+A / selectAll in Chromium and
|
|
169
|
+
* WebKit places the range end on the element itself with `endOffset` equal
|
|
170
|
+
* to the child count (i.e. after all children). In this case the last child
|
|
171
|
+
* text node may still have trailing whitespace that was excluded; walk to
|
|
172
|
+
* the deepest last text node and extend the range to its end if it ends with
|
|
173
|
+
* only whitespace after the current offset (or fully consists of whitespace).
|
|
174
|
+
*
|
|
175
|
+
* @param range - The range to extend (mutated in place)
|
|
176
|
+
*/
|
|
177
|
+
export const extendRangeToTrailingWhitespace = (range: Range): void => {
|
|
178
|
+
const endContainer = range.endContainer;
|
|
179
|
+
|
|
180
|
+
if (endContainer.nodeType === Node.TEXT_NODE) {
|
|
181
|
+
const text = endContainer.textContent ?? '';
|
|
182
|
+
const endOffset = range.endOffset;
|
|
183
|
+
|
|
184
|
+
if (endOffset >= text.length) {
|
|
185
|
+
return;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
// Check whether all characters between endOffset and end of text node are whitespace
|
|
189
|
+
const trailingSlice = text.slice(endOffset);
|
|
190
|
+
|
|
191
|
+
if (trailingSlice.length > 0 && trailingSlice.trim().length === 0) {
|
|
192
|
+
range.setEnd(endContainer, text.length);
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
return;
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
// endContainer is an element node (the common case for Ctrl+A on loaded content).
|
|
199
|
+
// Walk to the deepest last text node within it to find any trailing whitespace.
|
|
200
|
+
const lastTextNode = findDeepestLastTextNode(endContainer);
|
|
201
|
+
|
|
202
|
+
if (lastTextNode === null) {
|
|
203
|
+
return;
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
const text = lastTextNode.textContent ?? '';
|
|
207
|
+
|
|
208
|
+
if (text.length === 0) {
|
|
209
|
+
return;
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
// Extend range if the text ends with one or more whitespace characters.
|
|
213
|
+
if (/\s+$/.test(text)) {
|
|
214
|
+
range.setEnd(lastTextNode, text.length);
|
|
215
|
+
}
|
|
216
|
+
};
|
|
217
|
+
|
|
135
218
|
/**
|
|
136
219
|
* Collect all unique formatting ancestors within a range
|
|
137
220
|
* @param range - The range to search within
|
|
@@ -11,6 +11,25 @@ export class ToolsAPI extends Module {
|
|
|
11
11
|
public get methods(): ToolsAPIInterface {
|
|
12
12
|
return {
|
|
13
13
|
getBlockTools: () => Array.from(this.Blok.Tools.blockTools.values()),
|
|
14
|
+
getToolsConfig: () => {
|
|
15
|
+
const result: ReturnType<ToolsAPIInterface['getToolsConfig']> = {
|
|
16
|
+
tools: this.config.tools,
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
if (this.config.inlineToolbar !== undefined) {
|
|
20
|
+
result.inlineToolbar = this.config.inlineToolbar;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
if (this.config.tunes !== undefined) {
|
|
24
|
+
result.tunes = this.config.tunes;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
if (this.config.theme !== undefined) {
|
|
28
|
+
result.theme = this.config.theme;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
return result;
|
|
32
|
+
},
|
|
14
33
|
};
|
|
15
34
|
}
|
|
16
35
|
}
|
|
@@ -94,7 +94,13 @@ export class KeyboardNavigation extends BlockEventComposer {
|
|
|
94
94
|
const isNavigated = event.shiftKey ? Caret.navigatePrevious(true) : Caret.navigateNext(true);
|
|
95
95
|
|
|
96
96
|
/**
|
|
97
|
-
*
|
|
97
|
+
* Prevent default Tab behaviour only when navigation occurred within the
|
|
98
|
+
* editor. When navigateNext/navigatePrevious returns false (no next/prev
|
|
99
|
+
* block), allow the browser default so focus can leave the editor to
|
|
100
|
+
* external elements (e.g. inputs after the editor).
|
|
101
|
+
*
|
|
102
|
+
* Nested editors (e.g. database card drawer) are safe because the table
|
|
103
|
+
* cell guard above returns early, and those editors handle Tab themselves.
|
|
98
104
|
*/
|
|
99
105
|
if (isNavigated) {
|
|
100
106
|
event.preventDefault();
|
|
@@ -300,6 +300,17 @@ export class BlockManager extends Module {
|
|
|
300
300
|
eventsDispatcher: this.eventsDispatcher,
|
|
301
301
|
getBlockIndex: (block) => this.repository.getBlockIndex(block),
|
|
302
302
|
onBlockMutated: this.blockDidMutated.bind(this),
|
|
303
|
+
shouldHandleEvent: (event: Event) => {
|
|
304
|
+
const target = event.target;
|
|
305
|
+
|
|
306
|
+
if (target instanceof Element) {
|
|
307
|
+
const closestEditor = target.closest('[data-blok-testid="blok-editor"]');
|
|
308
|
+
|
|
309
|
+
return closestEditor === null || closestEditor === this.Blok.UI.nodes.wrapper;
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
return true;
|
|
313
|
+
},
|
|
303
314
|
});
|
|
304
315
|
|
|
305
316
|
// Initialize factory
|
|
@@ -438,6 +449,8 @@ export class BlockManager extends Module {
|
|
|
438
449
|
parentId?: string;
|
|
439
450
|
contentIds?: string[];
|
|
440
451
|
bindEventsImmediately?: boolean;
|
|
452
|
+
lastEditedAt?: number;
|
|
453
|
+
lastEditedBy?: string | null;
|
|
441
454
|
}): Block {
|
|
442
455
|
return this.factory.composeBlock(options);
|
|
443
456
|
}
|
|
@@ -1086,6 +1099,11 @@ export class BlockManager extends Module {
|
|
|
1086
1099
|
// Also skip if a pointer drag is active — the browser can mutate contenteditable DOM across
|
|
1087
1100
|
// cell boundaries during a drag, and we must not write that corrupted state to Yjs.
|
|
1088
1101
|
if (mutationType === BlockChangedMutationType && !this.yjsSync.isSyncingFromYjs && !this._isPointerDragActive) {
|
|
1102
|
+
// eslint-disable-next-line no-param-reassign
|
|
1103
|
+
block.lastEditedAt = Date.now();
|
|
1104
|
+
// eslint-disable-next-line no-param-reassign
|
|
1105
|
+
block.lastEditedBy = this.config.user?.name ?? null;
|
|
1106
|
+
|
|
1089
1107
|
void this.syncBlockDataToYjs(block);
|
|
1090
1108
|
}
|
|
1091
1109
|
|
|
@@ -1140,5 +1158,9 @@ export class BlockManager extends Module {
|
|
|
1140
1158
|
for (const [key, value] of Object.entries(savedData.data)) {
|
|
1141
1159
|
this.Blok.YjsManager.updateBlockData(block.id, key, value);
|
|
1142
1160
|
}
|
|
1161
|
+
|
|
1162
|
+
if (block.lastEditedAt !== undefined) {
|
|
1163
|
+
this.Blok.YjsManager.updateBlockMetadata(block.id, block.lastEditedAt, block.lastEditedBy);
|
|
1164
|
+
}
|
|
1143
1165
|
}
|
|
1144
1166
|
}
|