@jackuait/blok 0.6.0-beta.9 → 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-Bn6Q_o8h.mjs → blok-BAh1rvUC.mjs} +3410 -2927
- package/dist/chunks/i18next-B47TKgbU.mjs +1303 -0
- package/dist/chunks/{i18next-loader-DjR4d8M7.mjs → i18next-loader-CHtGO6IK.mjs} +2 -2
- package/dist/chunks/{index-oe38cp86.mjs → index-DBWWKrDe.mjs} +12 -12
- package/dist/chunks/{inline-tool-convert-SRTkyaZn.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 +3190 -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 +9 -5
- 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
|
@@ -19,10 +19,10 @@ import { announce } from '../../utils/announcer';
|
|
|
19
19
|
import { convertStringToBlockData, isBlockConvertable } from '../../utils/blocks';
|
|
20
20
|
import type { EventsDispatcher } from '../../utils/events';
|
|
21
21
|
import { sanitizeBlocks, clean, composeSanitizerConfig } from '../../utils/sanitizer';
|
|
22
|
+
import { isInsideTableCell, isRestrictedInTableCell } from '../../../tools/table/table-restrictions';
|
|
22
23
|
import type { Caret } from '../caret';
|
|
23
24
|
import type { I18n } from '../i18n';
|
|
24
25
|
import type { YjsManager } from '../yjs';
|
|
25
|
-
|
|
26
26
|
import type { BlockFactory } from './factory';
|
|
27
27
|
import type { BlockHierarchy } from './hierarchy';
|
|
28
28
|
import type { BlockRepository } from './repository';
|
|
@@ -191,6 +191,7 @@ export class BlockOperations {
|
|
|
191
191
|
replace = false,
|
|
192
192
|
tunes,
|
|
193
193
|
skipYjsSync = false,
|
|
194
|
+
appendToWorkingArea = false,
|
|
194
195
|
} = options;
|
|
195
196
|
|
|
196
197
|
const targetIndex = index ?? this.currentBlockIndex + (replace ? 0 : 1);
|
|
@@ -204,15 +205,33 @@ export class BlockOperations {
|
|
|
204
205
|
this.repository.getBlockByIndex(targetIndex)?.unwatchBlockMutations();
|
|
205
206
|
}
|
|
206
207
|
|
|
207
|
-
const
|
|
208
|
+
const resolvedToolName = (() => {
|
|
209
|
+
const name = tool ?? this.dependencies.config.defaultBlock;
|
|
208
210
|
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
211
|
+
if (name === undefined) {
|
|
212
|
+
throw new Error('Could not insert Block. Tool name is not specified.');
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
// Demote restricted tools to paragraph when inserting inside a table cell.
|
|
216
|
+
// For replace: check the block being replaced (new block takes its DOM position).
|
|
217
|
+
// For insert: check the predecessor block (new block is placed after it in the DOM).
|
|
218
|
+
// Using the block AT targetIndex for non-replace inserts is wrong because that
|
|
219
|
+
// block may be a child paragraph inside a table cell that gets displaced, while
|
|
220
|
+
// the new block actually lands at the top level.
|
|
221
|
+
const neighborBlock = replace
|
|
222
|
+
? this.repository.getBlockByIndex(targetIndex)
|
|
223
|
+
: (this.repository.getBlockByIndex(targetIndex - 1) ?? this.repository.getBlockByIndex(targetIndex));
|
|
224
|
+
|
|
225
|
+
if (neighborBlock !== undefined && isInsideTableCell(neighborBlock) && isRestrictedInTableCell(name)) {
|
|
226
|
+
return this.dependencies.config.defaultBlock ?? 'paragraph';
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
return name;
|
|
230
|
+
})();
|
|
212
231
|
|
|
213
232
|
// Bind events immediately for user-created blocks so mutations are tracked right away
|
|
214
233
|
const block = this.factory.composeBlock({
|
|
215
|
-
tool:
|
|
234
|
+
tool: resolvedToolName,
|
|
216
235
|
bindEventsImmediately: true,
|
|
217
236
|
...(id !== undefined && { id }),
|
|
218
237
|
...(data !== undefined && { data }),
|
|
@@ -235,7 +254,7 @@ export class BlockOperations {
|
|
|
235
254
|
});
|
|
236
255
|
}
|
|
237
256
|
|
|
238
|
-
blocksStore.insert(targetIndex, block, replace);
|
|
257
|
+
blocksStore.insert(targetIndex, block, replace, appendToWorkingArea);
|
|
239
258
|
|
|
240
259
|
/**
|
|
241
260
|
* Force call of didMutated event on Block insertion
|
|
@@ -245,9 +264,11 @@ export class BlockOperations {
|
|
|
245
264
|
});
|
|
246
265
|
|
|
247
266
|
/**
|
|
248
|
-
* Sync to Yjs data layer (unless caller is handling sync separately
|
|
267
|
+
* Sync to Yjs data layer (unless caller is handling sync separately,
|
|
268
|
+
* or we're inside an atomic operation like paste where all Yjs sync
|
|
269
|
+
* is deferred until the operation completes)
|
|
249
270
|
*/
|
|
250
|
-
if (!skipYjsSync) {
|
|
271
|
+
if (!skipYjsSync && !this.yjsSync.isSyncingFromYjs) {
|
|
251
272
|
this.dependencies.YjsManager.addBlock({
|
|
252
273
|
id: block.id,
|
|
253
274
|
type: block.name,
|
|
@@ -298,7 +319,7 @@ export class BlockOperations {
|
|
|
298
319
|
public insertAtEnd(blocksStore: BlocksStore): Block {
|
|
299
320
|
this.currentBlockIndexValue = this.repository.length - 1;
|
|
300
321
|
|
|
301
|
-
return this.insert({}, blocksStore);
|
|
322
|
+
return this.insert({ appendToWorkingArea: true }, blocksStore);
|
|
302
323
|
}
|
|
303
324
|
|
|
304
325
|
/**
|
|
@@ -319,6 +340,15 @@ export class BlockOperations {
|
|
|
319
340
|
throw new Error('Can\'t find a Block to remove');
|
|
320
341
|
}
|
|
321
342
|
|
|
343
|
+
// Clean up parent's contentIds before removing the block
|
|
344
|
+
const parentBlock = block.parentId !== null
|
|
345
|
+
? this.repository.getBlockById(block.parentId)
|
|
346
|
+
: undefined;
|
|
347
|
+
|
|
348
|
+
if (parentBlock !== undefined) {
|
|
349
|
+
parentBlock.contentIds = parentBlock.contentIds.filter(id => id !== block.id);
|
|
350
|
+
}
|
|
351
|
+
|
|
322
352
|
blocksStore.remove(index);
|
|
323
353
|
|
|
324
354
|
/**
|
|
@@ -467,6 +497,17 @@ export class BlockOperations {
|
|
|
467
497
|
return;
|
|
468
498
|
}
|
|
469
499
|
|
|
500
|
+
// Check if the move would place a restricted tool inside a table cell
|
|
501
|
+
const movingBlock = this.repository.getBlockByIndex(fromIndex);
|
|
502
|
+
const neighborBlock = this.repository.getBlockByIndex(toIndex);
|
|
503
|
+
|
|
504
|
+
if (movingBlock !== undefined && neighborBlock !== undefined &&
|
|
505
|
+
isInsideTableCell(neighborBlock) && isRestrictedInTableCell(movingBlock.name)) {
|
|
506
|
+
log(`Warning during 'move' call: '${movingBlock.name}' is restricted in table cells.`, 'warn');
|
|
507
|
+
|
|
508
|
+
return;
|
|
509
|
+
}
|
|
510
|
+
|
|
470
511
|
// Suppress stopCapturing to keep DOM + Yjs move as single undo entry
|
|
471
512
|
this.suppressStopCapturing = true;
|
|
472
513
|
try {
|
|
@@ -765,33 +806,27 @@ export class BlockOperations {
|
|
|
765
806
|
replace = false,
|
|
766
807
|
blocksStore: BlocksStore
|
|
767
808
|
): Promise<Block> {
|
|
768
|
-
// Insert block without syncing to Yjs yet
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
809
|
+
// Insert block without syncing to Yjs yet.
|
|
810
|
+
// Wrap in atomic operation so that child blocks created during rendered()
|
|
811
|
+
// (e.g., table cell paragraph blocks) also skip Yjs sync.
|
|
812
|
+
const block = this.yjsSync.withAtomicOperation(() => {
|
|
813
|
+
return this.insert({
|
|
814
|
+
tool: toolName,
|
|
815
|
+
replace,
|
|
816
|
+
skipYjsSync: true,
|
|
817
|
+
}, blocksStore);
|
|
818
|
+
});
|
|
819
|
+
|
|
820
|
+
// Wait for the block to be fully rendered before calling onPaste,
|
|
821
|
+
// because onPaste may change the tool's root element and needs
|
|
822
|
+
// mutation watchers to be bound first.
|
|
823
|
+
await block.ready;
|
|
774
824
|
|
|
775
|
-
//
|
|
825
|
+
// Call onPaste within atomic operation so child blocks created
|
|
826
|
+
// during cell initialization also skip Yjs sync.
|
|
776
827
|
this.yjsSync.withAtomicOperation(() => {
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
* because onPaste could change tool's root element, and we need to do that after block.watchBlockMutations() bound
|
|
780
|
-
* to detect tool root element change
|
|
781
|
-
* @todo make this.insert() awaitable and remove requestIdleCallback
|
|
782
|
-
*/
|
|
783
|
-
return void block.ready.then(() => {
|
|
784
|
-
block.call(BlockToolAPI.ON_PASTE, pasteEvent as unknown as Record<string, unknown>);
|
|
785
|
-
|
|
786
|
-
/**
|
|
787
|
-
* onPaste might cause the tool to replace its root element (e.g., Header changing level).
|
|
788
|
-
* Since mutation observers are set up asynchronously via requestIdleCallback,
|
|
789
|
-
* we need to manually refresh the tool element reference here.
|
|
790
|
-
*/
|
|
791
|
-
block.refreshToolRootElement();
|
|
792
|
-
}).catch((e) => {
|
|
793
|
-
log(`${toolName}: onPaste callback call is failed`, 'error', e);
|
|
794
|
-
});
|
|
828
|
+
block.call(BlockToolAPI.ON_PASTE, pasteEvent as unknown as Record<string, unknown>);
|
|
829
|
+
block.refreshToolRootElement();
|
|
795
830
|
});
|
|
796
831
|
|
|
797
832
|
// Sync final state to Yjs as single operation
|
|
@@ -201,6 +201,28 @@ export class BlockRepository {
|
|
|
201
201
|
return previousBlocks.find((block) => !!block.inputs.length);
|
|
202
202
|
}
|
|
203
203
|
|
|
204
|
+
/**
|
|
205
|
+
* Walks up the parentId chain and returns the top-level (root) block.
|
|
206
|
+
* If the block has no parent, returns it as-is.
|
|
207
|
+
* Used by selection modules to treat hierarchical blocks (e.g. table cells)
|
|
208
|
+
* as a single unit rather than selecting child blocks individually.
|
|
209
|
+
* @param block - the block to resolve
|
|
210
|
+
* @returns {Block} the root ancestor block
|
|
211
|
+
*/
|
|
212
|
+
public resolveToRootBlock(block: Block): Block {
|
|
213
|
+
if (block.parentId === null) {
|
|
214
|
+
return block;
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
const parent = this.getBlockById(block.parentId);
|
|
218
|
+
|
|
219
|
+
if (parent === undefined) {
|
|
220
|
+
return block;
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
return this.resolveToRootBlock(parent);
|
|
224
|
+
}
|
|
225
|
+
|
|
204
226
|
/**
|
|
205
227
|
* Get block at a specific index from the blocks store nodes array
|
|
206
228
|
* @param index - the index
|
|
@@ -48,6 +48,8 @@ export interface InsertBlockOptions {
|
|
|
48
48
|
tunes?: { [name: string]: BlockTuneData };
|
|
49
49
|
/** Skip syncing to Yjs (caller handles sync separately) */
|
|
50
50
|
skipYjsSync?: boolean;
|
|
51
|
+
/** When true, append block to workingArea instead of positioning relative to adjacent blocks */
|
|
52
|
+
appendToWorkingArea?: boolean;
|
|
51
53
|
}
|
|
52
54
|
|
|
53
55
|
/**
|
|
@@ -105,7 +107,7 @@ export interface ConvertBlockOptions {
|
|
|
105
107
|
*/
|
|
106
108
|
export type BlocksStore = Blocks & {
|
|
107
109
|
[index: number]: Block | undefined;
|
|
108
|
-
insert(index: number, block: Block, replace?: boolean): void;
|
|
110
|
+
insert(index: number, block: Block, replace?: boolean, appendToWorkingArea?: boolean): void;
|
|
109
111
|
remove(index: number): void;
|
|
110
112
|
move(toIndex: number, fromIndex: number, skipDOM?: boolean): void;
|
|
111
113
|
};
|
|
@@ -112,21 +112,43 @@ export class BlockYjsSync {
|
|
|
112
112
|
* @param fn - Function to execute
|
|
113
113
|
* @param options - Options for controlling the atomic operation behavior
|
|
114
114
|
*/
|
|
115
|
-
|
|
115
|
+
/**
|
|
116
|
+
* Begin an atomic operation by incrementing sync count and suppressing stop capturing.
|
|
117
|
+
*
|
|
118
|
+
* @returns cleanup function to call when operation completes
|
|
119
|
+
*/
|
|
120
|
+
private beginAtomicOperation(): () => void {
|
|
116
121
|
this.yjsSyncCount++;
|
|
117
122
|
const operations = this.dependencies.operations;
|
|
118
|
-
const shouldExtend = options?.extendThroughRAF === true;
|
|
119
123
|
|
|
120
124
|
if (operations) {
|
|
121
125
|
operations.suppressStopCapturing = true;
|
|
122
126
|
}
|
|
123
127
|
|
|
124
|
-
|
|
128
|
+
return (): void => {
|
|
125
129
|
this.yjsSyncCount--;
|
|
126
130
|
if (operations && this.yjsSyncCount === 0) {
|
|
127
131
|
operations.suppressStopCapturing = false;
|
|
128
132
|
}
|
|
129
133
|
};
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* End an atomic operation, optionally deferring cleanup through RAF.
|
|
138
|
+
*
|
|
139
|
+
* @param cleanup - function to call to decrement sync count
|
|
140
|
+
* @param extendThroughRAF - if true, defer cleanup until after next animation frame
|
|
141
|
+
*/
|
|
142
|
+
private endAtomicOperation(cleanup: () => void, extendThroughRAF: boolean): void {
|
|
143
|
+
if (extendThroughRAF) {
|
|
144
|
+
requestAnimationFrame(cleanup);
|
|
145
|
+
} else {
|
|
146
|
+
cleanup();
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
public withAtomicOperation<T>(fn: () => T, options?: { extendThroughRAF?: boolean }): T {
|
|
151
|
+
const cleanup = this.beginAtomicOperation();
|
|
130
152
|
|
|
131
153
|
try {
|
|
132
154
|
const result = fn();
|
|
@@ -134,16 +156,34 @@ export class BlockYjsSync {
|
|
|
134
156
|
// If extendThroughRAF is true, delay decrementing yjsSyncCount until after requestAnimationFrame callbacks
|
|
135
157
|
// This ensures that DOM updates scheduled by rendered() hooks don't trigger
|
|
136
158
|
// block data sync to Yjs, which would create new undo entries and clear the redo stack
|
|
137
|
-
|
|
138
|
-
requestAnimationFrame(decrementSyncCount);
|
|
139
|
-
} else {
|
|
140
|
-
decrementSyncCount();
|
|
141
|
-
}
|
|
159
|
+
this.endAtomicOperation(cleanup, options?.extendThroughRAF === true);
|
|
142
160
|
|
|
143
161
|
return result;
|
|
144
162
|
} catch (error) {
|
|
145
|
-
|
|
146
|
-
|
|
163
|
+
cleanup();
|
|
164
|
+
throw error;
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
/**
|
|
169
|
+
* Async version of withAtomicOperation for operations that return promises.
|
|
170
|
+
* Keeps yjsSyncCount elevated until the async work completes, then optionally
|
|
171
|
+
* extends through RAF to cover deferred DOM callbacks.
|
|
172
|
+
*
|
|
173
|
+
* @param fn - Async function to execute
|
|
174
|
+
* @param options - Options for controlling the atomic operation behavior
|
|
175
|
+
*/
|
|
176
|
+
public async withAtomicOperationAsync(
|
|
177
|
+
fn: () => Promise<void>,
|
|
178
|
+
options?: { extendThroughRAF?: boolean }
|
|
179
|
+
): Promise<void> {
|
|
180
|
+
const cleanup = this.beginAtomicOperation();
|
|
181
|
+
|
|
182
|
+
try {
|
|
183
|
+
await fn();
|
|
184
|
+
this.endAtomicOperation(cleanup, options?.extendThroughRAF === true);
|
|
185
|
+
} catch (error) {
|
|
186
|
+
cleanup();
|
|
147
187
|
throw error;
|
|
148
188
|
}
|
|
149
189
|
}
|
|
@@ -165,25 +205,28 @@ export class BlockYjsSync {
|
|
|
165
205
|
* @param event - the block change event from YjsManager
|
|
166
206
|
*/
|
|
167
207
|
private syncBlockFromYjs(event: BlockChangeEvent): void {
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
if (changeType === 'update') {
|
|
171
|
-
this.handleYjsUpdate(blockId);
|
|
208
|
+
if (event.type === 'update') {
|
|
209
|
+
this.handleYjsUpdate(event.blockId);
|
|
172
210
|
return;
|
|
173
211
|
}
|
|
174
212
|
|
|
175
|
-
if (
|
|
213
|
+
if (event.type === 'move') {
|
|
176
214
|
this.handleYjsMove();
|
|
177
215
|
return;
|
|
178
216
|
}
|
|
179
217
|
|
|
180
|
-
if (
|
|
181
|
-
this.handleYjsAdd(blockId);
|
|
218
|
+
if (event.type === 'add') {
|
|
219
|
+
this.handleYjsAdd(event.blockId);
|
|
220
|
+
return;
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
if (event.type === 'batch-add') {
|
|
224
|
+
this.handleYjsBatchAdd(event.blockIds);
|
|
182
225
|
return;
|
|
183
226
|
}
|
|
184
227
|
|
|
185
|
-
if (
|
|
186
|
-
this.handleYjsRemove(blockId);
|
|
228
|
+
if (event.type === 'remove') {
|
|
229
|
+
this.handleYjsRemove(event.blockId);
|
|
187
230
|
}
|
|
188
231
|
}
|
|
189
232
|
|
|
@@ -221,19 +264,32 @@ export class BlockYjsSync {
|
|
|
221
264
|
bindEventsImmediately: true,
|
|
222
265
|
});
|
|
223
266
|
|
|
224
|
-
//
|
|
225
|
-
|
|
226
|
-
|
|
267
|
+
// Use atomic operation with RAF extension to prevent DOM mutation observers
|
|
268
|
+
// from syncing back to Yjs after block replacement
|
|
269
|
+
this.withAtomicOperation(() => {
|
|
227
270
|
this.handlers.replaceBlock(blockIndex, newBlock);
|
|
228
|
-
}
|
|
229
|
-
this.yjsSyncCount--;
|
|
230
|
-
}
|
|
271
|
+
}, { extendThroughRAF: true });
|
|
231
272
|
} else {
|
|
232
|
-
//
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
273
|
+
// Update data in-place; if tool can't handle it, recreate the block.
|
|
274
|
+
// Use async atomic operation with RAF extension to keep isSyncingFromYjs
|
|
275
|
+
// true through the entire setData lifecycle + one RAF frame, preventing
|
|
276
|
+
// DOM mutation observers from writing back to Yjs and clearing the redo stack.
|
|
277
|
+
void this.withAtomicOperationAsync(async () => {
|
|
278
|
+
const success = await block.setData(data);
|
|
279
|
+
|
|
280
|
+
if (!success) {
|
|
281
|
+
const blockIndex = this.handlers.getBlockIndex(block);
|
|
282
|
+
const newBlock = this.factory.composeBlock({
|
|
283
|
+
id: block.id,
|
|
284
|
+
tool: block.name,
|
|
285
|
+
data,
|
|
286
|
+
tunes: block.preservedTunes,
|
|
287
|
+
bindEventsImmediately: true,
|
|
288
|
+
});
|
|
289
|
+
|
|
290
|
+
this.handlers.replaceBlock(blockIndex, newBlock);
|
|
291
|
+
}
|
|
292
|
+
}, { extendThroughRAF: true });
|
|
237
293
|
}
|
|
238
294
|
}
|
|
239
295
|
|
|
@@ -290,6 +346,80 @@ export class BlockYjsSync {
|
|
|
290
346
|
}, { extendThroughRAF: true });
|
|
291
347
|
}
|
|
292
348
|
|
|
349
|
+
/**
|
|
350
|
+
* Handle batch block add from Yjs (undo/redo).
|
|
351
|
+
*
|
|
352
|
+
* When multiple blocks are restored at once (e.g. a table + its cell
|
|
353
|
+
* paragraphs), we use a two-pass approach:
|
|
354
|
+
* 1. Create ALL blocks and insert them into the blocks array (no DOM).
|
|
355
|
+
* 2. Activate each block (DOM insert + RENDERED lifecycle hook).
|
|
356
|
+
*
|
|
357
|
+
* This ensures that when a parent tool's `rendered()` hook fires (pass 2),
|
|
358
|
+
* child blocks already exist in BlockManager, so helpers like
|
|
359
|
+
* `mountBlocksInCell()` can find them by ID.
|
|
360
|
+
*/
|
|
361
|
+
private handleYjsBatchAdd(blockIds: string[]): void {
|
|
362
|
+
const yjsBlocks = this.dependencies.YjsManager.toJSON();
|
|
363
|
+
|
|
364
|
+
// Collect blocks to create — skip any that already exist
|
|
365
|
+
const toCreate: Array<{ blockId: string; toolName: string; data: Record<string, unknown>; parentId: string | undefined; targetIndex: number }> = [];
|
|
366
|
+
|
|
367
|
+
for (const blockId of blockIds) {
|
|
368
|
+
if (this.repository.getBlockById(blockId) !== undefined) {
|
|
369
|
+
continue;
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
const yblock = this.dependencies.YjsManager.getBlockById(blockId);
|
|
373
|
+
|
|
374
|
+
if (yblock === undefined) {
|
|
375
|
+
continue;
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
const toolName = yblock.get('type') as string;
|
|
379
|
+
const data = this.dependencies.YjsManager.yMapToObject(yblock.get('data') as YMap<unknown>);
|
|
380
|
+
const parentId = yblock.get('parentId') as string | undefined;
|
|
381
|
+
const targetIndex = yjsBlocks.findIndex((b) => b.id === blockId);
|
|
382
|
+
|
|
383
|
+
if (targetIndex === -1) {
|
|
384
|
+
continue;
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
toCreate.push({ blockId, toolName, data, parentId: parentId ?? undefined, targetIndex });
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
if (toCreate.length === 0) {
|
|
391
|
+
return;
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
this.withAtomicOperation(() => {
|
|
395
|
+
// Pass 1 — create blocks and add to array (no DOM, no RENDERED)
|
|
396
|
+
const created: Array<{ block: Block; targetIndex: number; parentId: string | undefined }> = [];
|
|
397
|
+
|
|
398
|
+
for (const entry of toCreate) {
|
|
399
|
+
const block = this.factory.composeBlock({
|
|
400
|
+
id: entry.blockId,
|
|
401
|
+
tool: entry.toolName,
|
|
402
|
+
data: entry.data,
|
|
403
|
+
parentId: entry.parentId,
|
|
404
|
+
bindEventsImmediately: true,
|
|
405
|
+
});
|
|
406
|
+
|
|
407
|
+
this.blocksStore.addToArray(entry.targetIndex, block);
|
|
408
|
+
created.push({ block, targetIndex: entry.targetIndex, parentId: entry.parentId });
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
// Pass 2 — activate blocks (DOM insert + RENDERED), then emit events
|
|
412
|
+
for (const { block, targetIndex, parentId } of created) {
|
|
413
|
+
this.blocksStore.activateBlock(block);
|
|
414
|
+
this.handlers.onBlockAdded(block, targetIndex);
|
|
415
|
+
|
|
416
|
+
if (parentId !== undefined) {
|
|
417
|
+
this.handlers.updateIndentation(block);
|
|
418
|
+
}
|
|
419
|
+
}
|
|
420
|
+
}, { extendThroughRAF: true });
|
|
421
|
+
}
|
|
422
|
+
|
|
293
423
|
/**
|
|
294
424
|
* Handle block remove from Yjs (undo/redo - removing a previously added block)
|
|
295
425
|
*/
|
|
@@ -306,17 +436,21 @@ export class BlockYjsSync {
|
|
|
306
436
|
return;
|
|
307
437
|
}
|
|
308
438
|
|
|
309
|
-
//
|
|
310
|
-
//
|
|
311
|
-
this.
|
|
439
|
+
// Keep Yjs sync state active for the full remove lifecycle so listeners
|
|
440
|
+
// and block.destroy handlers can detect undo/redo-originated removals.
|
|
441
|
+
this.withAtomicOperation(() => {
|
|
442
|
+
// Emit block-removed event BEFORE removal so listeners can inspect
|
|
443
|
+
// the block's DOM position (e.g., which table cell it's in)
|
|
444
|
+
this.handlers.onBlockRemoved(block, index);
|
|
312
445
|
|
|
313
|
-
|
|
314
|
-
|
|
446
|
+
// Remove from DOM
|
|
447
|
+
this.blocksStore.remove(index);
|
|
315
448
|
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
449
|
+
// If all blocks removed, insert a default block
|
|
450
|
+
if (this.blocksStore.length === 0) {
|
|
451
|
+
this.handlers.insertDefaultBlock(true);
|
|
452
|
+
}
|
|
453
|
+
});
|
|
320
454
|
}
|
|
321
455
|
|
|
322
456
|
/**
|
|
@@ -269,13 +269,21 @@ export class CrossBlockSelection extends Module {
|
|
|
269
269
|
return;
|
|
270
270
|
}
|
|
271
271
|
|
|
272
|
-
const
|
|
273
|
-
const
|
|
272
|
+
const rawRelatedBlock = BlockManager.getBlockByChildNode(mouseEvent.relatedTarget as Node) || this.lastSelectedBlock;
|
|
273
|
+
const rawTargetBlock = BlockManager.getBlockByChildNode(mouseEvent.target as Node);
|
|
274
274
|
|
|
275
|
-
if (!
|
|
275
|
+
if (!rawRelatedBlock || !rawTargetBlock) {
|
|
276
276
|
return;
|
|
277
277
|
}
|
|
278
278
|
|
|
279
|
+
/**
|
|
280
|
+
* Resolve child blocks (e.g. paragraphs inside table cells) to their root parent.
|
|
281
|
+
* Without this, dragging across a table would select individual cell blocks
|
|
282
|
+
* from the flat blocks array instead of treating the table as a single unit.
|
|
283
|
+
*/
|
|
284
|
+
const relatedBlock = BlockManager.resolveToRootBlock(rawRelatedBlock);
|
|
285
|
+
const targetBlock = BlockManager.resolveToRootBlock(rawTargetBlock);
|
|
286
|
+
|
|
279
287
|
if (targetBlock === relatedBlock) {
|
|
280
288
|
return;
|
|
281
289
|
}
|
|
@@ -23,11 +23,19 @@ export class DragPreview {
|
|
|
23
23
|
// Reset styles on clone
|
|
24
24
|
clone.className = twMerge(PREVIEW_STYLES.content, isStretched ? 'max-w-none' : '');
|
|
25
25
|
|
|
26
|
+
// Set explicit width on clone so percentage-based children (e.g. table cells)
|
|
27
|
+
// have a sizing reference inside the position:fixed preview container
|
|
28
|
+
const computedWidth = contentElement.getBoundingClientRect().width;
|
|
29
|
+
|
|
30
|
+
if (computedWidth > 0) {
|
|
31
|
+
clone.style.width = `${computedWidth}px`;
|
|
32
|
+
}
|
|
33
|
+
|
|
26
34
|
// Reset margin on the tool's rendered element (first child) to prevent offset
|
|
27
35
|
const toolElement = clone.firstElementChild as HTMLElement | null;
|
|
28
36
|
|
|
29
37
|
if (toolElement) {
|
|
30
|
-
toolElement.className = twMerge(toolElement.className, '
|
|
38
|
+
toolElement.className = twMerge(toolElement.className, 'm-0!');
|
|
31
39
|
}
|
|
32
40
|
|
|
33
41
|
preview.appendChild(clone);
|
|
@@ -100,7 +108,7 @@ export class DragPreview {
|
|
|
100
108
|
const toolElement = clone.firstElementChild as HTMLElement | null;
|
|
101
109
|
|
|
102
110
|
if (toolElement) {
|
|
103
|
-
toolElement.className = twMerge(toolElement.className, '
|
|
111
|
+
toolElement.className = twMerge(toolElement.className, 'm-0!');
|
|
104
112
|
}
|
|
105
113
|
|
|
106
114
|
// Position with cumulative offset
|