@jackuait/blok 0.6.0-beta.8 → 0.6.0
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-bzxy6Olq.mjs → blok-BAh1rvUC.mjs} +3410 -2927
- package/dist/chunks/i18next-B47TKgbU.mjs +1303 -0
- package/dist/chunks/{i18next-loader-CzL6YHyQ.mjs → i18next-loader-CHtGO6IK.mjs} +2 -2
- package/dist/chunks/{index-DSSrx_Co.mjs → index-DBWWKrDe.mjs} +12 -12
- package/dist/chunks/{inline-tool-convert-D4SXxjDd.mjs → inline-tool-convert-DduRc0fF.mjs} +1467 -951
- package/dist/chunks/{messages-BogRq8lt.mjs → messages-0AbcLMLm.mjs} +6 -0
- package/dist/chunks/{messages-DJDG55Vq.mjs → messages-0E0AkrNu.mjs} +6 -0
- package/dist/{messages-DnXLrlHh.mjs → chunks/messages-4v4MuVEc.mjs} +6 -0
- package/dist/chunks/{messages-DnIhyAJk.mjs → messages-62v-CLC-.mjs} +6 -0
- package/dist/chunks/{messages-Dzwxv9v1.mjs → messages-8DeO60Oo.mjs} +6 -0
- package/dist/chunks/{messages-B1Aww8q7.mjs → messages-8IPXkrDl.mjs} +6 -0
- package/dist/{messages-uKX8WBaD.mjs → chunks/messages-96kNZDll.mjs} +6 -0
- package/dist/chunks/{messages-BL0tXcDf.mjs → messages-B1FZ8lxU.mjs} +6 -0
- package/dist/{messages-DBn76jVV.mjs → chunks/messages-B217znr-.mjs} +8 -2
- package/dist/{messages-DT4dP5uK.mjs → chunks/messages-B8WNljW3.mjs} +6 -0
- package/dist/chunks/{messages-BdeLo0N9.mjs → messages-BC8IN4Bf.mjs} +6 -0
- package/dist/{messages-CZygwLwM.mjs → chunks/messages-BI43k_BD.mjs} +6 -0
- package/dist/{messages-CzTufCHu.mjs → chunks/messages-BJ6zrz2j.mjs} +6 -0
- package/dist/{messages-BoJc_p1r.mjs → chunks/messages-BUl_Rcnj.mjs} +6 -0
- package/dist/chunks/{messages-CnwibSvh.mjs → messages-BZlmVRwn.mjs} +6 -0
- package/dist/{messages-C2htQ_3F.mjs → chunks/messages-BcpCubnC.mjs} +6 -0
- package/dist/{messages-D5C3J9qr.mjs → chunks/messages-Bm-E4iRC.mjs} +6 -0
- package/dist/chunks/{messages-BELRf6DU.mjs → messages-C4jL-90N.mjs} +6 -0
- package/dist/chunks/{messages-1fC8IMyX.mjs → messages-CDBLbUOQ.mjs} +6 -0
- package/dist/chunks/{messages-7QoX8DkW.mjs → messages-CH4hrauY.mjs} +6 -0
- package/dist/{messages-Dz9L52ol.mjs → chunks/messages-CRJ_mchV.mjs} +6 -0
- package/dist/chunks/{messages-JELdtT6E.mjs → messages-CW4c4cRk.mjs} +6 -0
- package/dist/chunks/{messages-CKI54h6O.mjs → messages-C_4otP7U.mjs} +6 -0
- package/dist/{messages-R3hUSvr3.mjs → chunks/messages-CfiyT2Wi.mjs} +6 -0
- package/dist/{messages-CJdUsQ-c.mjs → chunks/messages-CgTq3QhU.mjs} +6 -0
- package/dist/chunks/{messages-D1Hv8XGo.mjs → messages-Chb7k3Rg.mjs} +6 -0
- package/dist/{messages-Q7AO_FLv.mjs → chunks/messages-Cjjo7yHR.mjs} +6 -0
- package/dist/{messages-C99mq906.mjs → chunks/messages-Cl6ayUaq.mjs} +6 -0
- package/dist/chunks/{messages-Diu6jAaR.mjs → messages-CmR9ftc_.mjs} +6 -0
- package/dist/chunks/{messages-LPVfA-8K.mjs → messages-Cr49Nt3U.mjs} +6 -0
- package/dist/chunks/{messages-DqM1LFg5.mjs → messages-Cr94GzbX.mjs} +6 -0
- package/dist/{messages-BWF-zUpY.mjs → chunks/messages-CrCYPCk3.mjs} +6 -0
- package/dist/{messages-D-ZtY5v0.mjs → chunks/messages-Cs8zmZ3L.mjs} +6 -0
- package/dist/{messages-DprmQg6V.mjs → chunks/messages-CzK0LEhb.mjs} +6 -0
- package/dist/chunks/{messages-BSbjsyHY.mjs → messages-D00x4S8o.mjs} +6 -0
- package/dist/chunks/{messages-Xq8UmkVs.mjs → messages-D1mn7Zd5.mjs} +6 -0
- package/dist/chunks/{messages-BC86qLvI.mjs → messages-D2NOpHn9.mjs} +6 -0
- package/dist/{messages-kep5wtm4.mjs → chunks/messages-D4qqwVgQ.mjs} +6 -0
- package/dist/chunks/{messages-7W4d0DwD.mjs → messages-D5S1Dnpm.mjs} +6 -0
- package/dist/{messages-CY8_RyFE.mjs → chunks/messages-D7u2bmP2.mjs} +6 -0
- package/dist/chunks/{messages-BFG6Wlgy.mjs → messages-D85FqxgY.mjs} +6 -0
- package/dist/{messages-DLfR5bMd.mjs → chunks/messages-D9ndgBnU.mjs} +6 -0
- package/dist/{messages-CVw84KdI.mjs → chunks/messages-DDTQgImT.mjs} +6 -0
- package/dist/{messages-_ErNTNhk.mjs → chunks/messages-DH_jBeED.mjs} +6 -0
- package/dist/chunks/{messages-CMkNSDTo.mjs → messages-DRXWF0PV.mjs} +6 -0
- package/dist/chunks/{messages-BYyy6Wqf.mjs → messages-DVQvl8Qj.mjs} +6 -0
- package/dist/chunks/{messages-CznZadDf.mjs → messages-DXktiao_.mjs} +6 -0
- package/dist/chunks/{messages-DhLKYm2j.mjs → messages-DdK-nFGm.mjs} +6 -0
- package/dist/chunks/{messages-BMXCuEKO.mjs → messages-DlJbPF2T.mjs} +6 -0
- package/dist/chunks/{messages-CvGLfqmV.mjs → messages-DnVlmiNT.mjs} +6 -0
- package/dist/{messages-Z9nEU2xK.mjs → chunks/messages-DviiFSv2.mjs} +6 -0
- package/dist/chunks/{messages-BB5z9Uba.mjs → messages-DzqM3Fel.mjs} +6 -0
- package/dist/{messages-w7v1GNaE.mjs → chunks/messages-Dzzn6XoD.mjs} +6 -0
- package/dist/{messages-CqWJcCbY.mjs → chunks/messages-GSByFygY.mjs} +6 -0
- package/dist/chunks/{messages-_ncGrKHh.mjs → messages-L_kl2Qvh.mjs} +6 -0
- package/dist/chunks/{messages-BrPFGbM-.mjs → messages-Phkd7XmE.mjs} +6 -0
- package/dist/{messages-BU2nlrLK.mjs → chunks/messages-RonBBCnh.mjs} +6 -0
- package/dist/{messages-Bmu_S7GM.mjs → chunks/messages-VDriF5Qy.mjs} +6 -0
- package/dist/{messages-CLhcMlTc.mjs → chunks/messages-ZjUAIWb1.mjs} +6 -0
- package/dist/{messages-9SihnaXQ.mjs → chunks/messages-b1EdvUm0.mjs} +6 -0
- package/dist/{messages-DvFLX36Q.mjs → chunks/messages-begYOTgC.mjs} +6 -0
- package/dist/{messages-BMv4xwIr.mjs → chunks/messages-jrncnb-H.mjs} +6 -0
- package/dist/{messages-D5iv1Kox.mjs → chunks/messages-nefz1S71.mjs} +6 -0
- package/dist/{messages-CQwpzUFp.mjs → chunks/messages-ucTVgS5G.mjs} +6 -0
- package/dist/chunks/{messages-DBRw-7Zc.mjs → messages-v3GipbFl.mjs} +6 -0
- package/dist/{messages-C9eaarcK.mjs → chunks/messages-wmi-iFkH.mjs} +6 -0
- package/dist/chunks/{messages-O5tQus_0.mjs → messages-yHcs38yI.mjs} +6 -0
- package/dist/full.mjs +2 -2
- package/dist/locales.mjs +90 -84
- package/dist/{messages-BogRq8lt.mjs → messages-0AbcLMLm.mjs} +6 -0
- package/dist/{messages-DJDG55Vq.mjs → messages-0E0AkrNu.mjs} +6 -0
- package/dist/{chunks/messages-DnXLrlHh.mjs → messages-4v4MuVEc.mjs} +6 -0
- package/dist/{messages-DnIhyAJk.mjs → messages-62v-CLC-.mjs} +6 -0
- package/dist/{messages-Dzwxv9v1.mjs → messages-8DeO60Oo.mjs} +6 -0
- package/dist/{messages-B1Aww8q7.mjs → messages-8IPXkrDl.mjs} +6 -0
- package/dist/{chunks/messages-uKX8WBaD.mjs → messages-96kNZDll.mjs} +6 -0
- package/dist/{messages-BL0tXcDf.mjs → messages-B1FZ8lxU.mjs} +6 -0
- package/dist/{chunks/messages-DBn76jVV.mjs → messages-B217znr-.mjs} +8 -2
- package/dist/{chunks/messages-DT4dP5uK.mjs → messages-B8WNljW3.mjs} +6 -0
- package/dist/{messages-BdeLo0N9.mjs → messages-BC8IN4Bf.mjs} +6 -0
- package/dist/{chunks/messages-CZygwLwM.mjs → messages-BI43k_BD.mjs} +6 -0
- package/dist/{chunks/messages-CzTufCHu.mjs → messages-BJ6zrz2j.mjs} +6 -0
- package/dist/{chunks/messages-BoJc_p1r.mjs → messages-BUl_Rcnj.mjs} +6 -0
- package/dist/{messages-CnwibSvh.mjs → messages-BZlmVRwn.mjs} +6 -0
- package/dist/{chunks/messages-C2htQ_3F.mjs → messages-BcpCubnC.mjs} +6 -0
- package/dist/{chunks/messages-D5C3J9qr.mjs → messages-Bm-E4iRC.mjs} +6 -0
- package/dist/{messages-BELRf6DU.mjs → messages-C4jL-90N.mjs} +6 -0
- package/dist/{messages-1fC8IMyX.mjs → messages-CDBLbUOQ.mjs} +6 -0
- package/dist/{messages-7QoX8DkW.mjs → messages-CH4hrauY.mjs} +6 -0
- package/dist/{chunks/messages-Dz9L52ol.mjs → messages-CRJ_mchV.mjs} +6 -0
- package/dist/{messages-JELdtT6E.mjs → messages-CW4c4cRk.mjs} +6 -0
- package/dist/{messages-CKI54h6O.mjs → messages-C_4otP7U.mjs} +6 -0
- package/dist/{chunks/messages-R3hUSvr3.mjs → messages-CfiyT2Wi.mjs} +6 -0
- package/dist/{chunks/messages-CJdUsQ-c.mjs → messages-CgTq3QhU.mjs} +6 -0
- package/dist/{messages-D1Hv8XGo.mjs → messages-Chb7k3Rg.mjs} +6 -0
- package/dist/{chunks/messages-Q7AO_FLv.mjs → messages-Cjjo7yHR.mjs} +6 -0
- package/dist/{chunks/messages-C99mq906.mjs → messages-Cl6ayUaq.mjs} +6 -0
- package/dist/{messages-Diu6jAaR.mjs → messages-CmR9ftc_.mjs} +6 -0
- package/dist/{messages-LPVfA-8K.mjs → messages-Cr49Nt3U.mjs} +6 -0
- package/dist/{messages-DqM1LFg5.mjs → messages-Cr94GzbX.mjs} +6 -0
- package/dist/{chunks/messages-BWF-zUpY.mjs → messages-CrCYPCk3.mjs} +6 -0
- package/dist/{chunks/messages-D-ZtY5v0.mjs → messages-Cs8zmZ3L.mjs} +6 -0
- package/dist/{chunks/messages-DprmQg6V.mjs → messages-CzK0LEhb.mjs} +6 -0
- package/dist/{messages-BSbjsyHY.mjs → messages-D00x4S8o.mjs} +6 -0
- package/dist/{messages-Xq8UmkVs.mjs → messages-D1mn7Zd5.mjs} +6 -0
- package/dist/{messages-BC86qLvI.mjs → messages-D2NOpHn9.mjs} +6 -0
- package/dist/{chunks/messages-kep5wtm4.mjs → messages-D4qqwVgQ.mjs} +6 -0
- package/dist/{messages-7W4d0DwD.mjs → messages-D5S1Dnpm.mjs} +6 -0
- package/dist/{chunks/messages-CY8_RyFE.mjs → messages-D7u2bmP2.mjs} +6 -0
- package/dist/{messages-BFG6Wlgy.mjs → messages-D85FqxgY.mjs} +6 -0
- package/dist/{chunks/messages-DLfR5bMd.mjs → messages-D9ndgBnU.mjs} +6 -0
- package/dist/{chunks/messages-CVw84KdI.mjs → messages-DDTQgImT.mjs} +6 -0
- package/dist/{chunks/messages-_ErNTNhk.mjs → messages-DH_jBeED.mjs} +6 -0
- package/dist/{messages-CMkNSDTo.mjs → messages-DRXWF0PV.mjs} +6 -0
- package/dist/{messages-BYyy6Wqf.mjs → messages-DVQvl8Qj.mjs} +6 -0
- package/dist/{messages-CznZadDf.mjs → messages-DXktiao_.mjs} +6 -0
- package/dist/{messages-DhLKYm2j.mjs → messages-DdK-nFGm.mjs} +6 -0
- package/dist/{messages-BMXCuEKO.mjs → messages-DlJbPF2T.mjs} +6 -0
- package/dist/{messages-CvGLfqmV.mjs → messages-DnVlmiNT.mjs} +6 -0
- package/dist/{chunks/messages-Z9nEU2xK.mjs → messages-DviiFSv2.mjs} +6 -0
- package/dist/{messages-BB5z9Uba.mjs → messages-DzqM3Fel.mjs} +6 -0
- package/dist/{chunks/messages-w7v1GNaE.mjs → messages-Dzzn6XoD.mjs} +6 -0
- package/dist/{chunks/messages-CqWJcCbY.mjs → messages-GSByFygY.mjs} +6 -0
- package/dist/{messages-_ncGrKHh.mjs → messages-L_kl2Qvh.mjs} +6 -0
- package/dist/{messages-BrPFGbM-.mjs → messages-Phkd7XmE.mjs} +6 -0
- package/dist/{chunks/messages-BU2nlrLK.mjs → messages-RonBBCnh.mjs} +6 -0
- package/dist/{chunks/messages-Bmu_S7GM.mjs → messages-VDriF5Qy.mjs} +6 -0
- package/dist/{chunks/messages-CLhcMlTc.mjs → messages-ZjUAIWb1.mjs} +6 -0
- package/dist/{chunks/messages-9SihnaXQ.mjs → messages-b1EdvUm0.mjs} +6 -0
- package/dist/{chunks/messages-DvFLX36Q.mjs → messages-begYOTgC.mjs} +6 -0
- package/dist/{chunks/messages-BMv4xwIr.mjs → messages-jrncnb-H.mjs} +6 -0
- package/dist/{chunks/messages-D5iv1Kox.mjs → messages-nefz1S71.mjs} +6 -0
- package/dist/{chunks/messages-CQwpzUFp.mjs → messages-ucTVgS5G.mjs} +6 -0
- package/dist/{messages-DBRw-7Zc.mjs → messages-v3GipbFl.mjs} +6 -0
- package/dist/{chunks/messages-C9eaarcK.mjs → messages-wmi-iFkH.mjs} +6 -0
- package/dist/{messages-O5tQus_0.mjs → messages-yHcs38yI.mjs} +6 -0
- package/dist/tools.mjs +3194 -1690
- package/dist/vendor.LICENSE.txt +109 -109
- package/package.json +43 -57
- package/src/blok.ts +12 -0
- package/src/components/__module.ts +21 -0
- package/src/components/block/api.ts +17 -0
- package/src/components/block/style-manager.ts +6 -2
- package/src/components/block/tool-renderer.ts +33 -30
- package/src/components/blocks.ts +132 -15
- package/src/components/i18n/locales/am/messages.json +6 -0
- package/src/components/i18n/locales/ar/messages.json +6 -0
- package/src/components/i18n/locales/az/messages.json +6 -0
- package/src/components/i18n/locales/bg/messages.json +6 -0
- package/src/components/i18n/locales/bn/messages.json +6 -0
- package/src/components/i18n/locales/bs/messages.json +6 -0
- package/src/components/i18n/locales/cs/messages.json +6 -0
- package/src/components/i18n/locales/da/messages.json +6 -0
- package/src/components/i18n/locales/de/messages.json +6 -0
- package/src/components/i18n/locales/dv/messages.json +6 -0
- package/src/components/i18n/locales/el/messages.json +6 -0
- package/src/components/i18n/locales/en/messages.json +6 -0
- package/src/components/i18n/locales/es/messages.json +6 -0
- package/src/components/i18n/locales/et/messages.json +6 -0
- package/src/components/i18n/locales/fa/messages.json +6 -0
- package/src/components/i18n/locales/fi/messages.json +6 -0
- package/src/components/i18n/locales/fil/messages.json +6 -0
- package/src/components/i18n/locales/fr/messages.json +6 -0
- package/src/components/i18n/locales/gu/messages.json +6 -0
- package/src/components/i18n/locales/he/messages.json +6 -0
- package/src/components/i18n/locales/hi/messages.json +6 -0
- package/src/components/i18n/locales/hr/messages.json +6 -0
- package/src/components/i18n/locales/hu/messages.json +6 -0
- package/src/components/i18n/locales/hy/messages.json +6 -0
- package/src/components/i18n/locales/id/messages.json +6 -0
- package/src/components/i18n/locales/it/messages.json +6 -0
- package/src/components/i18n/locales/ja/messages.json +6 -0
- package/src/components/i18n/locales/ka/messages.json +6 -0
- package/src/components/i18n/locales/km/messages.json +6 -0
- package/src/components/i18n/locales/kn/messages.json +6 -0
- package/src/components/i18n/locales/ko/messages.json +6 -0
- package/src/components/i18n/locales/ku/messages.json +6 -0
- package/src/components/i18n/locales/lo/messages.json +6 -0
- package/src/components/i18n/locales/lt/messages.json +6 -0
- package/src/components/i18n/locales/lv/messages.json +6 -0
- package/src/components/i18n/locales/mk/messages.json +6 -0
- package/src/components/i18n/locales/ml/messages.json +6 -0
- package/src/components/i18n/locales/mn/messages.json +6 -0
- package/src/components/i18n/locales/mr/messages.json +6 -0
- package/src/components/i18n/locales/ms/messages.json +6 -0
- package/src/components/i18n/locales/my/messages.json +6 -0
- package/src/components/i18n/locales/ne/messages.json +6 -0
- package/src/components/i18n/locales/nl/messages.json +6 -0
- package/src/components/i18n/locales/no/messages.json +6 -0
- package/src/components/i18n/locales/pa/messages.json +6 -0
- package/src/components/i18n/locales/pl/messages.json +6 -0
- package/src/components/i18n/locales/ps/messages.json +6 -0
- package/src/components/i18n/locales/pt/messages.json +6 -0
- package/src/components/i18n/locales/ro/messages.json +6 -0
- package/src/components/i18n/locales/ru/messages.json +6 -0
- package/src/components/i18n/locales/sd/messages.json +6 -0
- package/src/components/i18n/locales/si/messages.json +6 -0
- package/src/components/i18n/locales/sk/messages.json +6 -0
- package/src/components/i18n/locales/sl/messages.json +6 -0
- package/src/components/i18n/locales/sq/messages.json +6 -0
- package/src/components/i18n/locales/sr/messages.json +6 -0
- package/src/components/i18n/locales/sv/messages.json +6 -0
- package/src/components/i18n/locales/sw/messages.json +6 -0
- package/src/components/i18n/locales/ta/messages.json +6 -0
- package/src/components/i18n/locales/te/messages.json +6 -0
- package/src/components/i18n/locales/th/messages.json +6 -0
- package/src/components/i18n/locales/tr/messages.json +6 -0
- package/src/components/i18n/locales/ug/messages.json +6 -0
- package/src/components/i18n/locales/uk/messages.json +6 -0
- package/src/components/i18n/locales/ur/messages.json +6 -0
- package/src/components/i18n/locales/vi/messages.json +6 -0
- package/src/components/i18n/locales/yi/messages.json +6 -0
- package/src/components/i18n/locales/zh/messages.json +6 -0
- package/src/components/icons/index.ts +17 -0
- package/src/components/inline-tools/inline-tool-link.ts +1 -1
- package/src/components/inline-tools/inline-tool-marker.ts +737 -0
- package/src/components/inline-tools/utils/formatting-range-utils.ts +6 -3
- package/src/components/inline-tools/utils/marker-dom-utils.ts +17 -0
- package/src/components/modules/api/blocks.ts +34 -9
- package/src/components/modules/blockEvents/composers/keyboardNavigation.ts +75 -29
- package/src/components/modules/blockEvents/index.ts +13 -5
- package/src/components/modules/blockManager/blockManager.ts +81 -2
- package/src/components/modules/blockManager/hierarchy.ts +20 -2
- package/src/components/modules/blockManager/operations.ts +70 -35
- package/src/components/modules/blockManager/repository.ts +22 -0
- package/src/components/modules/blockManager/types.ts +3 -1
- package/src/components/modules/blockManager/yjs-sync.ts +173 -39
- package/src/components/modules/blockSelection.ts +3 -0
- package/src/components/modules/crossBlockSelection.ts +11 -3
- package/src/components/modules/drag/preview/DragPreview.ts +10 -2
- package/src/components/modules/drag/target/DropTargetDetector.ts +100 -11
- package/src/components/modules/drag/utils/drag.constants.ts +1 -1
- package/src/components/modules/normalizeInlineImages.ts +263 -0
- package/src/components/modules/paste/google-docs-preprocessor.ts +197 -0
- package/src/components/modules/paste/handlers/base.ts +43 -2
- package/src/components/modules/paste/handlers/html-handler.ts +1 -1
- package/src/components/modules/paste/handlers/index.ts +1 -0
- package/src/components/modules/paste/handlers/table-cells-handler.ts +104 -0
- package/src/components/modules/paste/index.ts +20 -3
- package/src/components/modules/readonly.ts +8 -2
- package/src/components/modules/rectangleSelection.ts +5 -2
- package/src/components/modules/renderer.ts +35 -0
- package/src/components/modules/saver.ts +52 -2
- package/src/components/modules/toolbar/blockSettings.ts +52 -44
- package/src/components/modules/toolbar/index.ts +124 -17
- package/src/components/modules/toolbar/inline/index.ts +4 -4
- package/src/components/modules/toolbar/plus-button.ts +3 -3
- package/src/components/modules/toolbar/settings-toggler.ts +3 -3
- package/src/components/modules/toolbar/styles.ts +7 -7
- package/src/components/modules/ui.ts +6 -6
- package/src/components/modules/uiControllers/controllers/blockHover.ts +16 -2
- package/src/components/modules/uiControllers/handlers/touch.ts +83 -10
- package/src/components/modules/yjs/block-observer.ts +9 -3
- package/src/components/modules/yjs/document-store.ts +10 -7
- package/src/components/modules/yjs/types.ts +8 -6
- package/src/components/modules/yjs/undo-history.ts +90 -11
- package/src/components/selection/fake-background/shadows.ts +1 -1
- package/src/components/shared/color-picker.ts +211 -0
- package/src/components/shared/color-presets.ts +25 -0
- package/src/components/ui/toolbox.ts +19 -11
- package/src/components/utils/color-mapping.ts +241 -0
- package/src/components/utils/notifier/draw.ts +9 -9
- package/src/components/utils/placeholder.ts +24 -8
- package/src/components/utils/popover/components/popover-item/popover-item-default/popover-item-default.const.ts +2 -2
- package/src/components/utils/popover/components/popover-item/popover-item-default/popover-item-default.ts +14 -12
- package/src/components/utils/popover/components/search-input/search-input.const.ts +2 -2
- package/src/components/utils/popover/popover-abstract.ts +27 -3
- package/src/components/utils/popover/popover-desktop.ts +26 -3
- package/src/components/utils/popover/popover-inline.ts +14 -1
- package/src/components/utils/popover/popover-mobile.ts +4 -4
- package/src/components/utils/popover/popover.const.ts +2 -2
- package/src/components/utils/sanitizer.ts +24 -3
- package/src/components/utils/tw.ts +17 -5
- package/src/stories/Header.stories.ts +106 -0
- package/src/stories/MarkerColors.stories.ts +730 -0
- package/src/stories/Popover.stories.ts +1 -3
- package/src/stories/Table.stories.ts +1662 -0
- package/src/styles/main.css +207 -37
- package/src/tools/header/index.ts +1 -1
- package/src/tools/index.ts +3 -1
- package/src/tools/list/caret-manager.ts +28 -10
- package/src/tools/list/constants.ts +2 -2
- package/src/tools/list/dom-builder.ts +3 -3
- package/src/tools/list/static-configs.ts +0 -1
- package/src/tools/paragraph/index.ts +15 -7
- package/src/tools/table/core/table-commands.ts +99 -0
- package/src/tools/table/core/table-controller.ts +231 -0
- package/src/tools/table/core/table-events.ts +102 -0
- package/src/tools/table/index.ts +1070 -174
- package/src/tools/table/ownership/table-event-broker.ts +74 -0
- package/src/tools/table/ownership/table-ownership-registry.ts +126 -0
- package/src/tools/table/table-add-controls.ts +85 -15
- package/src/tools/table/table-cell-blocks.ts +336 -38
- package/src/tools/table/table-cell-clipboard.ts +415 -0
- package/src/tools/table/table-cell-color-picker.ts +34 -0
- package/src/tools/table/table-cell-selection.ts +264 -15
- package/src/tools/table/table-core.ts +3 -42
- package/src/tools/table/table-heading-toggle.ts +2 -2
- package/src/tools/table/table-model.ts +623 -0
- package/src/tools/table/table-operations.ts +59 -78
- package/src/tools/table/table-resize.ts +15 -11
- package/src/tools/table/table-restrictions.ts +69 -3
- package/src/tools/table/table-row-col-action-handler.ts +22 -7
- package/src/tools/table/table-row-col-controls.ts +129 -12
- package/src/tools/table/table-row-col-drag.ts +14 -0
- package/src/tools/table/table-scroll-haze.ts +152 -0
- package/src/tools/table/types.ts +22 -1
- package/src/tools/table/view/table-cell-blocks-adapter.ts +47 -0
- package/src/variants/blok-minimum.ts +13 -0
- package/types/api/block.d.ts +13 -0
- package/types/api/blocks.d.ts +16 -0
- package/types/tools/table.d.ts +2 -0
- package/dist/chunks/i18next-CugVlwWp.mjs +0 -1292
- package/src/tools/table/data-normalizer.ts +0 -32
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
import type { PasteEvent, PasteEventDetail } from '../../../../../types';
|
|
2
2
|
import type { BlokModules } from '../../../../types-internal/blok-modules';
|
|
3
|
+
import { getRestrictedTools } from '../../../../tools/table/table-restrictions';
|
|
4
|
+
import { Dom } from '../../../dom';
|
|
5
|
+
import { clean } from '../../../utils/sanitizer';
|
|
3
6
|
import type { SanitizerConfigBuilder } from '../sanitizer-config';
|
|
4
7
|
import type { ToolRegistry } from '../tool-registry';
|
|
5
8
|
import type { HandlerContext, PasteData } from '../types';
|
|
@@ -65,6 +68,34 @@ export abstract class BasePasteHandler implements PasteHandler {
|
|
|
65
68
|
return isCurrentBlockDefault && currentBlock.isEmpty;
|
|
66
69
|
}
|
|
67
70
|
|
|
71
|
+
/**
|
|
72
|
+
* If we're inside a table cell and any pasted item uses a tool that can't
|
|
73
|
+
* be nested in table cells (e.g. table, header), redirect the insertion
|
|
74
|
+
* point to the parent table block. This prevents new block DOM elements
|
|
75
|
+
* from being placed inside the existing table's grid structure, which
|
|
76
|
+
* would corrupt the table's saved data.
|
|
77
|
+
*/
|
|
78
|
+
private redirectToTableParentIfNeeded(data: PasteData[], BlockManager: BlokModules['BlockManager']): void {
|
|
79
|
+
const currentBlock = BlockManager.currentBlock;
|
|
80
|
+
const isInsideTableCell = currentBlock?.holder?.closest('[data-blok-table-cell-blocks]');
|
|
81
|
+
const restricted = new Set(getRestrictedTools());
|
|
82
|
+
const hasRestrictedTools = data.some(item => restricted.has(item.tool));
|
|
83
|
+
|
|
84
|
+
if (!isInsideTableCell || !hasRestrictedTools || currentBlock === undefined) {
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
const tableBlockHolder = currentBlock.holder
|
|
89
|
+
.closest('[data-blok-tool="table"]')
|
|
90
|
+
?.closest('[data-blok-element]') as HTMLElement | null;
|
|
91
|
+
|
|
92
|
+
if (!tableBlockHolder) {
|
|
93
|
+
return;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
BlockManager.setCurrentBlockByChildNode(tableBlockHolder);
|
|
97
|
+
}
|
|
98
|
+
|
|
68
99
|
/**
|
|
69
100
|
* Insert paste data as blocks.
|
|
70
101
|
*/
|
|
@@ -82,7 +113,19 @@ export abstract class BasePasteHandler implements PasteHandler {
|
|
|
82
113
|
const isMultipleItems = data.length > 1;
|
|
83
114
|
|
|
84
115
|
if (isMultipleItems) {
|
|
116
|
+
this.redirectToTableParentIfNeeded(data, BlockManager);
|
|
117
|
+
|
|
85
118
|
for (const [index, pasteData] of data.entries()) {
|
|
119
|
+
/**
|
|
120
|
+
* Force each pasted block into its own Yjs undo entry so that
|
|
121
|
+
* Ctrl+Z removes them one at a time.
|
|
122
|
+
*
|
|
123
|
+
* paste() wraps insert() in withAtomicOperation() which suppresses
|
|
124
|
+
* the normal stopCapturing() from currentBlockIndexValue changes.
|
|
125
|
+
* Without this, consecutive addBlock() calls within the 500ms
|
|
126
|
+
* captureTimeout get merged into a single undo entry.
|
|
127
|
+
*/
|
|
128
|
+
this.Blok.YjsManager.stopCapturing();
|
|
86
129
|
await this.insertBlock(pasteData, index === 0 && canReplaceCurrentBlock);
|
|
87
130
|
}
|
|
88
131
|
|
|
@@ -129,7 +172,6 @@ export abstract class BasePasteHandler implements PasteHandler {
|
|
|
129
172
|
protected async processSingleBlock(dataToInsert: PasteData, canReplaceCurrentBlock: boolean): Promise<void> {
|
|
130
173
|
const { Caret, BlockManager } = this.Blok;
|
|
131
174
|
const { currentBlock } = BlockManager;
|
|
132
|
-
const { Dom } = await import('../../../dom');
|
|
133
175
|
const $ = Dom;
|
|
134
176
|
|
|
135
177
|
if (
|
|
@@ -159,7 +201,6 @@ export abstract class BasePasteHandler implements PasteHandler {
|
|
|
159
201
|
return;
|
|
160
202
|
}
|
|
161
203
|
|
|
162
|
-
const { clean } = await import('../../../utils/sanitizer');
|
|
163
204
|
const currentToolSanitizeConfig = currentBlock.tool.baseSanitizeConfig;
|
|
164
205
|
|
|
165
206
|
Caret.insertContentAtCaretPosition(
|
|
@@ -107,7 +107,7 @@ export class HtmlHandler extends BasePasteHandler implements PasteHandler {
|
|
|
107
107
|
const toolTags = this.buildToolTags(tool);
|
|
108
108
|
|
|
109
109
|
const structuralSanitizeConfig = this.sanitizerBuilder.getStructuralTagsConfig(content);
|
|
110
|
-
const customConfig =
|
|
110
|
+
const customConfig: SanitizerConfig = { ...structuralSanitizeConfig, ...toolTags, ...tool.baseSanitizeConfig, br: {} };
|
|
111
111
|
const sanitizedContent = this.sanitizeContent(content, customConfig);
|
|
112
112
|
|
|
113
113
|
if (!sanitizedContent) {
|
|
@@ -5,4 +5,5 @@ export { BlokDataHandler } from './blok-data-handler';
|
|
|
5
5
|
export { FilesHandler } from './files-handler';
|
|
6
6
|
export { HtmlHandler } from './html-handler';
|
|
7
7
|
export { PatternHandler } from './pattern-handler';
|
|
8
|
+
export { TableCellsHandler } from './table-cells-handler';
|
|
8
9
|
export { TextHandler } from './text-handler';
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
import type { BlokModules } from '../../../../types-internal/blok-modules';
|
|
2
|
+
import { parseClipboardHtml } from '../../../../tools/table/table-cell-clipboard';
|
|
3
|
+
import type { CellContent, LegacyCellContent } from '../../../../tools/table/types';
|
|
4
|
+
import type { SanitizerConfigBuilder } from '../sanitizer-config';
|
|
5
|
+
import type { ToolRegistry } from '../tool-registry';
|
|
6
|
+
import type { HandlerContext } from '../types';
|
|
7
|
+
|
|
8
|
+
import type { PasteHandler } from './base';
|
|
9
|
+
import { BasePasteHandler } from './base';
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Handles pasting table cell clipboard data outside of a table.
|
|
13
|
+
* Creates a new Table block with the pasted cell content.
|
|
14
|
+
* Priority 90: higher than HTML (40) but lower than BlokData (100).
|
|
15
|
+
*/
|
|
16
|
+
export class TableCellsHandler extends BasePasteHandler implements PasteHandler {
|
|
17
|
+
constructor(
|
|
18
|
+
Blok: BlokModules,
|
|
19
|
+
toolRegistry: ToolRegistry,
|
|
20
|
+
sanitizerBuilder: SanitizerConfigBuilder,
|
|
21
|
+
) {
|
|
22
|
+
super(Blok, toolRegistry, sanitizerBuilder);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
canHandle(data: unknown): number {
|
|
26
|
+
if (typeof data !== 'string') {
|
|
27
|
+
return 0;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
return parseClipboardHtml(data) !== null ? 90 : 0;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
async handle(data: unknown, context: HandlerContext): Promise<boolean> {
|
|
34
|
+
if (typeof data !== 'string') {
|
|
35
|
+
return false;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
const payload = parseClipboardHtml(data);
|
|
39
|
+
|
|
40
|
+
if (!payload) {
|
|
41
|
+
return false;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// If cursor is inside a table cell, let the grid paste listener handle it
|
|
45
|
+
const activeElement = document.activeElement as HTMLElement | null;
|
|
46
|
+
|
|
47
|
+
if (activeElement?.closest('[data-blok-table-cell]')) {
|
|
48
|
+
return false;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
const { BlockManager, Caret } = this.Blok;
|
|
52
|
+
|
|
53
|
+
// Build table content from the clipboard payload.
|
|
54
|
+
// When a cell has color or textColor, use a CellContent object to preserve
|
|
55
|
+
// the colors — the Table tool will create paragraph blocks during its
|
|
56
|
+
// rendered() lifecycle. For cells without colors, store plain text strings
|
|
57
|
+
// which the Table tool migrates to blocks normally.
|
|
58
|
+
const content: LegacyCellContent[][] = payload.cells.map(row =>
|
|
59
|
+
row.map(cell => {
|
|
60
|
+
const text = cell.blocks.length === 0
|
|
61
|
+
? ''
|
|
62
|
+
: cell.blocks
|
|
63
|
+
.map(b => (typeof b.data.text === 'string' ? b.data.text : ''))
|
|
64
|
+
.join(' ');
|
|
65
|
+
|
|
66
|
+
const hasColor = cell.color !== undefined;
|
|
67
|
+
const hasTextColor = cell.textColor !== undefined;
|
|
68
|
+
|
|
69
|
+
if (!hasColor && !hasTextColor) {
|
|
70
|
+
return text;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
const cellContent: CellContent = { blocks: [], text };
|
|
74
|
+
|
|
75
|
+
if (hasColor) {
|
|
76
|
+
cellContent.color = cell.color;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
if (hasTextColor) {
|
|
80
|
+
cellContent.textColor = cell.textColor;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
return cellContent;
|
|
84
|
+
}),
|
|
85
|
+
);
|
|
86
|
+
|
|
87
|
+
const tableData = {
|
|
88
|
+
withHeadings: false,
|
|
89
|
+
withHeadingColumn: false,
|
|
90
|
+
content,
|
|
91
|
+
};
|
|
92
|
+
|
|
93
|
+
const canReplace = context.canReplaceCurrentBlock;
|
|
94
|
+
const block = BlockManager.insert({
|
|
95
|
+
tool: 'table',
|
|
96
|
+
data: tableData,
|
|
97
|
+
replace: canReplace,
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
Caret.setToBlock(block, Caret.positions.END);
|
|
101
|
+
|
|
102
|
+
return true;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
@@ -3,11 +3,13 @@ import { Module } from '../../__module';
|
|
|
3
3
|
import { Dom as dom$ } from '../../dom';
|
|
4
4
|
import { composeSanitizerConfig, clean } from '../../utils/sanitizer';
|
|
5
5
|
|
|
6
|
+
import { preprocessGoogleDocsHtml } from './google-docs-preprocessor';
|
|
6
7
|
import type { PasteHandler } from './handlers/base';
|
|
7
8
|
import { BlokDataHandler } from './handlers/blok-data-handler';
|
|
8
9
|
import { FilesHandler } from './handlers/files-handler';
|
|
9
10
|
import { HtmlHandler } from './handlers/html-handler';
|
|
10
11
|
import { PatternHandler } from './handlers/pattern-handler';
|
|
12
|
+
import { TableCellsHandler } from './handlers/table-cells-handler';
|
|
11
13
|
import { TextHandler } from './handlers/text-handler';
|
|
12
14
|
import { SanitizerConfigBuilder } from './sanitizer-config';
|
|
13
15
|
import { ToolRegistry } from './tool-registry';
|
|
@@ -44,6 +46,7 @@ export class Paste extends Module {
|
|
|
44
46
|
// Initialize handlers in priority order (higher priority first)
|
|
45
47
|
this.handlers = [
|
|
46
48
|
new BlokDataHandler(this.Blok, this.toolRegistry, this.sanitizerBuilder, this.config),
|
|
49
|
+
new TableCellsHandler(this.Blok, this.toolRegistry, this.sanitizerBuilder),
|
|
47
50
|
new FilesHandler(this.Blok, this.toolRegistry, this.sanitizerBuilder),
|
|
48
51
|
new PatternHandler(this.Blok, this.toolRegistry, this.sanitizerBuilder),
|
|
49
52
|
new HtmlHandler(this.Blok, this.toolRegistry, this.sanitizerBuilder),
|
|
@@ -128,7 +131,8 @@ export class Paste extends Module {
|
|
|
128
131
|
const canReplaceCurrentBlock = Boolean(
|
|
129
132
|
currentBlock &&
|
|
130
133
|
currentBlock.tool.isDefault &&
|
|
131
|
-
currentBlock.isEmpty
|
|
134
|
+
currentBlock.isEmpty &&
|
|
135
|
+
!currentBlock.holder?.closest('[data-blok-table-cell-blocks]')
|
|
132
136
|
);
|
|
133
137
|
|
|
134
138
|
const context: HandlerContext = {
|
|
@@ -175,6 +179,10 @@ export class Paste extends Module {
|
|
|
175
179
|
return blokData;
|
|
176
180
|
}
|
|
177
181
|
|
|
182
|
+
if (handler instanceof TableCellsHandler) {
|
|
183
|
+
return rawHtmlData;
|
|
184
|
+
}
|
|
185
|
+
|
|
178
186
|
if (handler instanceof FilesHandler) {
|
|
179
187
|
return dataTransfer;
|
|
180
188
|
}
|
|
@@ -201,7 +209,8 @@ export class Paste extends Module {
|
|
|
201
209
|
{ br: {} }
|
|
202
210
|
);
|
|
203
211
|
|
|
204
|
-
const
|
|
212
|
+
const preprocessed = preprocessGoogleDocsHtml(rawHtmlData);
|
|
213
|
+
const cleanData = clean(preprocessed, customConfig);
|
|
205
214
|
const cleanDataIsHtml = dom$.isHTMLString(cleanData);
|
|
206
215
|
const shouldProcessAsPlain = !cleanData.trim() || (cleanData.trim() === plainData || !cleanDataIsHtml);
|
|
207
216
|
|
|
@@ -267,6 +276,14 @@ export class Paste extends Module {
|
|
|
267
276
|
* Check if Blok should process pasted data and pass data transfer object to handler.
|
|
268
277
|
*/
|
|
269
278
|
private handlePasteEvent = async (event: ClipboardEvent): Promise<void> => {
|
|
279
|
+
/**
|
|
280
|
+
* If the event was already handled (e.g., by the table grid paste listener),
|
|
281
|
+
* skip processing to prevent duplicate content insertion.
|
|
282
|
+
*/
|
|
283
|
+
if (event.defaultPrevented) {
|
|
284
|
+
return;
|
|
285
|
+
}
|
|
286
|
+
|
|
270
287
|
const { BlockManager, Toolbar } = this.Blok;
|
|
271
288
|
|
|
272
289
|
const currentBlock = BlockManager.setCurrentBlockByChildNode(event.target as HTMLElement);
|
|
@@ -288,6 +305,6 @@ export class Paste extends Module {
|
|
|
288
305
|
await this.processDataTransfer(event.clipboardData);
|
|
289
306
|
}
|
|
290
307
|
|
|
291
|
-
Toolbar.
|
|
308
|
+
Toolbar.moveAndOpen();
|
|
292
309
|
};
|
|
293
310
|
}
|
|
@@ -117,8 +117,14 @@ export class ReadOnly extends Module {
|
|
|
117
117
|
return this.readOnlyEnabled;
|
|
118
118
|
}
|
|
119
119
|
|
|
120
|
-
|
|
121
|
-
|
|
120
|
+
this.Blok.Renderer.markRenderStart();
|
|
121
|
+
|
|
122
|
+
try {
|
|
123
|
+
await this.Blok.BlockManager.clear();
|
|
124
|
+
await this.Blok.Renderer.render(savedBlocks.blocks);
|
|
125
|
+
} finally {
|
|
126
|
+
this.Blok.Renderer.markRenderEnd();
|
|
127
|
+
}
|
|
122
128
|
|
|
123
129
|
this.Blok.ModificationsObserver.enable();
|
|
124
130
|
|
|
@@ -611,9 +611,12 @@ export class RectangleSelection extends Module {
|
|
|
611
611
|
};
|
|
612
612
|
}
|
|
613
613
|
const blockInCurrentPos = this.Blok.BlockManager.getBlockByChildNode(elementUnderMouse);
|
|
614
|
+
const rootBlock = blockInCurrentPos !== undefined
|
|
615
|
+
? this.Blok.BlockManager.resolveToRootBlock(blockInCurrentPos)
|
|
616
|
+
: undefined;
|
|
614
617
|
|
|
615
|
-
const index =
|
|
616
|
-
? this.Blok.BlockManager.blocks.findIndex((block) => block.holder ===
|
|
618
|
+
const index = rootBlock !== undefined
|
|
619
|
+
? this.Blok.BlockManager.blocks.findIndex((block) => block.holder === rootBlock.holder)
|
|
617
620
|
: undefined;
|
|
618
621
|
|
|
619
622
|
return {
|
|
@@ -20,6 +20,41 @@ export class Renderer extends Module {
|
|
|
20
20
|
*/
|
|
21
21
|
private detectedInputFormat: DataFormatAnalysis['format'] = 'flat';
|
|
22
22
|
|
|
23
|
+
/**
|
|
24
|
+
* Promise that resolves when an in-progress render operation completes.
|
|
25
|
+
* Used by Saver to wait for render to finish before reading blocks.
|
|
26
|
+
* null when no render is in progress.
|
|
27
|
+
*/
|
|
28
|
+
public pendingRender: Promise<void> | null = null;
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Resolve function for the current pendingRender promise.
|
|
32
|
+
* Called when the render operation is done (in finally block).
|
|
33
|
+
*/
|
|
34
|
+
private resolvePendingRender: (() => void) | null = null;
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Signals that a render operation is starting.
|
|
38
|
+
* Sets pendingRender so that Saver can await it.
|
|
39
|
+
*/
|
|
40
|
+
public markRenderStart(): void {
|
|
41
|
+
this.pendingRender = new Promise<void>((resolve) => {
|
|
42
|
+
this.resolvePendingRender = resolve;
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Signals that a render operation has completed.
|
|
48
|
+
* Resolves pendingRender so that any waiting Saver call can proceed.
|
|
49
|
+
*/
|
|
50
|
+
public markRenderEnd(): void {
|
|
51
|
+
if (this.resolvePendingRender !== null) {
|
|
52
|
+
this.resolvePendingRender();
|
|
53
|
+
this.resolvePendingRender = null;
|
|
54
|
+
}
|
|
55
|
+
this.pendingRender = null;
|
|
56
|
+
}
|
|
57
|
+
|
|
23
58
|
/**
|
|
24
59
|
* Get the detected input format
|
|
25
60
|
*/
|
|
@@ -12,6 +12,7 @@ import type { Block } from '../block';
|
|
|
12
12
|
import { getBlokVersion, isEmpty, isObject, log, logLabeled } from '../utils';
|
|
13
13
|
import { collapseToLegacy, shouldCollapseToLegacy } from '../utils/data-model-transform';
|
|
14
14
|
import { sanitizeBlocks } from '../utils/sanitizer';
|
|
15
|
+
import { normalizeInlineImages } from './normalizeInlineImages';
|
|
15
16
|
|
|
16
17
|
type SaverValidatedData = ValidatedData & {
|
|
17
18
|
tunes?: Record<string, BlockTuneData>;
|
|
@@ -40,10 +41,52 @@ export class Saver extends Module {
|
|
|
40
41
|
private lastSaveError?: unknown;
|
|
41
42
|
|
|
42
43
|
/**
|
|
43
|
-
*
|
|
44
|
+
* Stores the in-flight save promise for deduplication.
|
|
45
|
+
* If a save is already in progress, subsequent calls return the same promise.
|
|
46
|
+
*/
|
|
47
|
+
private pendingSave: Promise<OutputData | undefined> | null = null;
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Composes new chain of Promises to fire them alternatelly.
|
|
51
|
+
* Deduplicates concurrent calls — if a save is already in-flight, returns the same promise.
|
|
44
52
|
* @returns {OutputData | undefined}
|
|
45
53
|
*/
|
|
46
54
|
public async save(): Promise<OutputData | undefined> {
|
|
55
|
+
if (this.isDestroyed) {
|
|
56
|
+
return undefined;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
if (this.pendingSave !== null) {
|
|
60
|
+
return this.pendingSave;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
this.pendingSave = this.doSave();
|
|
64
|
+
|
|
65
|
+
try {
|
|
66
|
+
return await this.pendingSave;
|
|
67
|
+
} finally {
|
|
68
|
+
this.pendingSave = null;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Internal save implementation.
|
|
74
|
+
* Waits for any pending render to complete before reading blocks.
|
|
75
|
+
* @returns {OutputData | undefined}
|
|
76
|
+
*/
|
|
77
|
+
private async doSave(): Promise<OutputData | undefined> {
|
|
78
|
+
// Wait for any in-progress render to complete before reading blocks
|
|
79
|
+
const pendingRender = this.Blok.Renderer?.pendingRender;
|
|
80
|
+
|
|
81
|
+
if (pendingRender !== null && pendingRender !== undefined) {
|
|
82
|
+
await pendingRender;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
// Check again after awaiting — editor may have been destroyed during the wait
|
|
86
|
+
if (this.isDestroyed) {
|
|
87
|
+
return undefined;
|
|
88
|
+
}
|
|
89
|
+
|
|
47
90
|
const { BlockManager, Tools } = this.Blok;
|
|
48
91
|
const blocks = BlockManager.blocks;
|
|
49
92
|
|
|
@@ -75,7 +118,14 @@ export class Saver extends Module {
|
|
|
75
118
|
this.config.sanitizer as SanitizerConfig
|
|
76
119
|
);
|
|
77
120
|
|
|
78
|
-
|
|
121
|
+
const normalizedData = normalizeInlineImages(sanitizedData);
|
|
122
|
+
|
|
123
|
+
// Check destruction one more time after async block.save() operations
|
|
124
|
+
if (this.isDestroyed) {
|
|
125
|
+
return undefined;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
return this.makeOutput(normalizedData);
|
|
79
129
|
} catch (error: unknown) {
|
|
80
130
|
this.lastSaveError = error;
|
|
81
131
|
|
|
@@ -160,61 +160,69 @@ export class BlockSettings extends Module<BlockSettingsNodes> {
|
|
|
160
160
|
* Set isOpening flag BEFORE async operations to prevent toolbar from moving
|
|
161
161
|
* while menu items are being created. This fixes a bug where hovering over a different
|
|
162
162
|
* block during async getTunesItems() causes the toolbar to reposition incorrectly.
|
|
163
|
+
*
|
|
164
|
+
* Wrapped in try/catch to guarantee isOpening is always reset — if any step
|
|
165
|
+
* (getTunes, getTunesItems, PopoverClass constructor) throws, without cleanup
|
|
166
|
+
* the flag stays true and the toolbar permanently stops appearing on hover.
|
|
163
167
|
*/
|
|
164
168
|
this.isOpening = true;
|
|
165
169
|
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
170
|
+
try {
|
|
171
|
+
/**
|
|
172
|
+
* If block settings contains any inputs, focus will be set there,
|
|
173
|
+
* so we need to save current selection to restore it after block settings is closed
|
|
174
|
+
*/
|
|
175
|
+
this.selection.save();
|
|
171
176
|
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
177
|
+
/**
|
|
178
|
+
* Highlight content of a Block we are working with
|
|
179
|
+
* For multiple blocks, they should already be selected
|
|
180
|
+
*/
|
|
181
|
+
if (!hasMultipleBlocksSelected) {
|
|
182
|
+
this.Blok.BlockSelection.selectBlock(block);
|
|
183
|
+
this.Blok.BlockSelection.clearCache();
|
|
184
|
+
}
|
|
180
185
|
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
186
|
+
/** Get tool's settings data - only relevant for single block selection */
|
|
187
|
+
const { toolTunes, commonTunes } = block.getTunes();
|
|
188
|
+
|
|
189
|
+
const PopoverClass = isMobileScreen() ? PopoverMobile : PopoverDesktop;
|
|
190
|
+
const popoverParams: PopoverParams & { flipper?: Flipper } = {
|
|
191
|
+
searchable: false,
|
|
192
|
+
trigger: trigger || this.nodes.wrapper,
|
|
193
|
+
items: await this.getTunesItems(block, commonTunes, toolTunes),
|
|
194
|
+
scopeElement: this.Blok.API.methods.ui.nodes.redactor,
|
|
195
|
+
messages: {
|
|
196
|
+
nothingFound: this.Blok.I18n.t('popover.nothingFound'),
|
|
197
|
+
search: this.Blok.I18n.t('popover.search'),
|
|
198
|
+
},
|
|
199
|
+
};
|
|
195
200
|
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
201
|
+
if (PopoverClass === PopoverDesktop) {
|
|
202
|
+
popoverParams.flipper = this.flipperInstance;
|
|
203
|
+
}
|
|
199
204
|
|
|
200
|
-
|
|
201
|
-
|
|
205
|
+
this.popover = new PopoverClass(popoverParams);
|
|
206
|
+
this.popover.getElement().setAttribute('data-blok-testid', 'block-tunes-popover');
|
|
202
207
|
|
|
203
|
-
|
|
208
|
+
this.popover.on(PopoverEvent.Closed, this.onPopoverClose);
|
|
204
209
|
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
210
|
+
/**
|
|
211
|
+
* Set opened flag AFTER popover is created to prevent race conditions
|
|
212
|
+
* where close() is called during the async getTunesItems() call
|
|
213
|
+
* when opened=true but popover is still null
|
|
214
|
+
*/
|
|
215
|
+
this.opened = true;
|
|
216
|
+
this.isOpening = false;
|
|
212
217
|
|
|
213
|
-
|
|
214
|
-
|
|
218
|
+
/** Tell to subscribers that block settings is opened */
|
|
219
|
+
this.eventsDispatcher.emit(this.events.opened);
|
|
215
220
|
|
|
216
|
-
|
|
217
|
-
|
|
221
|
+
this.popover.show();
|
|
222
|
+
this.attachFlipperKeydownListener(block);
|
|
223
|
+
} catch {
|
|
224
|
+
this.isOpening = false;
|
|
225
|
+
}
|
|
218
226
|
}
|
|
219
227
|
|
|
220
228
|
/**
|