@jackuait/blok 0.6.0-beta.9 → 0.7.0-beta.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/blok.mjs +2 -2
- package/dist/chunks/{blok-Bn6Q_o8h.mjs → blok-ob9Fwr1L.mjs} +3414 -2975
- package/dist/chunks/i18next-B47TKgbU.mjs +1303 -0
- package/dist/chunks/{i18next-loader-DjR4d8M7.mjs → i18next-loader-Bu3vFvye.mjs} +2 -2
- package/dist/chunks/{index-oe38cp86.mjs → index-CZmRzRIX.mjs} +12 -12
- package/dist/chunks/{inline-tool-convert-SRTkyaZn.mjs → inline-tool-convert-CvFW2iie.mjs} +1579 -961
- 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 +30 -27
- 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 +3537 -1710
- 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/constants/data-attributes.ts +7 -0
- 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 +61 -7
- 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/composers/markdownShortcuts.ts +54 -2
- package/src/components/modules/blockEvents/constants.ts +12 -0
- 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 +27 -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 +3 -3
- package/src/components/utils/popover/components/popover-item/popover-item-default/popover-item-default.ts +15 -12
- package/src/components/utils/popover/components/search-input/search-input.const.ts +2 -2
- package/src/components/utils/popover/popover-abstract.ts +30 -5
- 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 +3 -3
- package/src/components/utils/sanitizer.ts +24 -3
- package/src/components/utils/tw.ts +17 -5
- package/src/full.ts +4 -0
- package/src/stories/Header.stories.ts +106 -0
- package/src/stories/MarkerColors.stories.ts +730 -0
- package/src/stories/Placeholder.stories.ts +7 -2
- package/src/stories/Popover.stories.ts +1 -3
- package/src/stories/Table.stories.ts +1662 -0
- package/src/stories/helpers.ts +2 -0
- package/src/styles/main.css +217 -39
- package/src/tools/header/index.ts +204 -26
- package/src/tools/index.ts +5 -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/tools/toggle/block-operations.ts +110 -0
- package/src/tools/toggle/constants.ts +49 -0
- package/src/tools/toggle/dom-builder.ts +125 -0
- package/src/tools/toggle/index.ts +280 -0
- package/src/tools/toggle/toggle-keyboard.ts +139 -0
- package/src/tools/toggle/toggle-lifecycle.ts +80 -0
- package/src/tools/toggle/toggle-shortcuts.ts +107 -0
- package/src/tools/toggle/types.ts +21 -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/full.d.ts +2 -0
- package/types/tools/table.d.ts +2 -0
- package/types/tools-entry.d.ts +2 -1
- package/dist/chunks/i18next-CugVlwWp.mjs +0 -1292
- package/src/tools/table/data-normalizer.ts +0 -32
|
@@ -44,12 +44,15 @@ export const createRangeTextWalker = (range: Range): TreeWalker => {
|
|
|
44
44
|
* Find first ancestor element matching the predicate
|
|
45
45
|
* @param node - The node to start searching from
|
|
46
46
|
* @param predicate - Function to test elements
|
|
47
|
+
* @param boundary - Optional node that stops the upward traversal.
|
|
48
|
+
* When reached, the search returns null instead of continuing.
|
|
47
49
|
*/
|
|
48
50
|
export const findFormattingAncestor = (
|
|
49
51
|
node: Node | null,
|
|
50
|
-
predicate: (element: Element) => boolean
|
|
52
|
+
predicate: (element: Element) => boolean,
|
|
53
|
+
boundary?: Node
|
|
51
54
|
): HTMLElement | null => {
|
|
52
|
-
if (!node) {
|
|
55
|
+
if (!node || node === boundary) {
|
|
53
56
|
return null;
|
|
54
57
|
}
|
|
55
58
|
|
|
@@ -57,7 +60,7 @@ export const findFormattingAncestor = (
|
|
|
57
60
|
return node as HTMLElement;
|
|
58
61
|
}
|
|
59
62
|
|
|
60
|
-
return findFormattingAncestor(node.parentNode, predicate);
|
|
63
|
+
return findFormattingAncestor(node.parentNode, predicate, boundary);
|
|
61
64
|
};
|
|
62
65
|
|
|
63
66
|
/**
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { findFormattingAncestor } from './formatting-range-utils';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Check if an element is a <mark> tag
|
|
5
|
+
* @param element - The element to check
|
|
6
|
+
*/
|
|
7
|
+
export const isMarkTag = (element: Element): boolean => {
|
|
8
|
+
return element.tagName === 'MARK';
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Find closest <mark> ancestor from a node
|
|
13
|
+
* @param node - The node to start searching from
|
|
14
|
+
*/
|
|
15
|
+
export const findMarkElement = (node: Node | null): HTMLElement | null => {
|
|
16
|
+
return findFormattingAncestor(node, isMarkTag);
|
|
17
|
+
};
|
|
@@ -20,7 +20,12 @@ export class BlocksAPI extends Module {
|
|
|
20
20
|
* @returns {Blocks}
|
|
21
21
|
*/
|
|
22
22
|
public get methods(): Blocks {
|
|
23
|
+
const blocksAPI = this;
|
|
24
|
+
|
|
23
25
|
return {
|
|
26
|
+
get isSyncingFromYjs(): boolean {
|
|
27
|
+
return blocksAPI.Blok.BlockManager.isSyncingFromYjs;
|
|
28
|
+
},
|
|
24
29
|
clear: (): Promise<void> => this.clear(),
|
|
25
30
|
render: (data: OutputData): Promise<void> => this.render(data),
|
|
26
31
|
renderFromHTML: (data: string): Promise<void> => this.renderFromHTML(data),
|
|
@@ -41,6 +46,7 @@ export class BlocksAPI extends Module {
|
|
|
41
46
|
setBlockParent: (blockId: string, parentId: string | null): void => this.setBlockParent(blockId, parentId),
|
|
42
47
|
stopBlockMutationWatching: (index: number): void => this.stopBlockMutationWatching(index),
|
|
43
48
|
splitBlock: this.splitBlock,
|
|
49
|
+
transact: (fn: () => void): void => this.transact(fn),
|
|
44
50
|
};
|
|
45
51
|
}
|
|
46
52
|
|
|
@@ -168,12 +174,12 @@ export class BlocksAPI extends Module {
|
|
|
168
174
|
}
|
|
169
175
|
|
|
170
176
|
/**
|
|
171
|
-
*
|
|
172
|
-
*
|
|
177
|
+
* Note: default-block insertion when the store is empty is handled
|
|
178
|
+
* synchronously by removeBlock(block, addLastBlock=true).
|
|
179
|
+
* A redundant async check here would race with clear()/render()
|
|
180
|
+
* and could insert a spurious paragraph after the store has been
|
|
181
|
+
* repopulated by Renderer.
|
|
173
182
|
*/
|
|
174
|
-
if (this.Blok.BlockManager.blocks.length === 0) {
|
|
175
|
-
this.Blok.BlockManager.insert();
|
|
176
|
-
}
|
|
177
183
|
|
|
178
184
|
/**
|
|
179
185
|
* After Block deletion currentBlock is updated
|
|
@@ -207,9 +213,14 @@ export class BlocksAPI extends Module {
|
|
|
207
213
|
* So we need to disable modifications observer temporarily
|
|
208
214
|
*/
|
|
209
215
|
this.Blok.ModificationsObserver.disable();
|
|
216
|
+
this.Blok.Renderer.markRenderStart();
|
|
210
217
|
|
|
211
|
-
|
|
212
|
-
|
|
218
|
+
try {
|
|
219
|
+
await this.Blok.BlockManager.clear();
|
|
220
|
+
await this.Blok.Renderer.render(data.blocks);
|
|
221
|
+
} finally {
|
|
222
|
+
this.Blok.Renderer.markRenderEnd();
|
|
223
|
+
}
|
|
213
224
|
|
|
214
225
|
this.Blok.ModificationsObserver.enable();
|
|
215
226
|
}
|
|
@@ -220,9 +231,15 @@ export class BlocksAPI extends Module {
|
|
|
220
231
|
* @returns {Promise<void>}
|
|
221
232
|
*/
|
|
222
233
|
public async renderFromHTML(data: string): Promise<void> {
|
|
223
|
-
|
|
234
|
+
this.Blok.Renderer.markRenderStart();
|
|
235
|
+
|
|
236
|
+
try {
|
|
237
|
+
await this.Blok.BlockManager.clear();
|
|
224
238
|
|
|
225
|
-
|
|
239
|
+
return this.Blok.Paste.processText(data, true);
|
|
240
|
+
} finally {
|
|
241
|
+
this.Blok.Renderer.markRenderEnd();
|
|
242
|
+
}
|
|
226
243
|
}
|
|
227
244
|
|
|
228
245
|
/**
|
|
@@ -446,6 +463,14 @@ export class BlocksAPI extends Module {
|
|
|
446
463
|
return new BlockAPI(newBlock);
|
|
447
464
|
};
|
|
448
465
|
|
|
466
|
+
/**
|
|
467
|
+
* Execute a function within a transaction, grouping all block operations
|
|
468
|
+
* into a single undo entry.
|
|
469
|
+
*/
|
|
470
|
+
private transact(fn: () => void): void {
|
|
471
|
+
this.Blok.BlockManager.transactForTool(fn);
|
|
472
|
+
}
|
|
473
|
+
|
|
449
474
|
/**
|
|
450
475
|
* Validated block index and throws an error if it's invalid
|
|
451
476
|
* @param index - index to validate
|
|
@@ -43,6 +43,33 @@ export class KeyboardNavigation extends BlockEventComposer {
|
|
|
43
43
|
return ui.isRtl ?? false;
|
|
44
44
|
}
|
|
45
45
|
|
|
46
|
+
/**
|
|
47
|
+
* Check if the current block is inside a table cell.
|
|
48
|
+
* Used to prevent closing the toolbar when the user navigates
|
|
49
|
+
* within a table — closing it makes the toolbar permanently
|
|
50
|
+
* disappear because the hover controller deduplicates by block id
|
|
51
|
+
* and all cells resolve to the same parent table block.
|
|
52
|
+
*/
|
|
53
|
+
private get isCurrentBlockInsideTableCell(): boolean {
|
|
54
|
+
const currentBlock = this.Blok.BlockManager.currentBlock;
|
|
55
|
+
|
|
56
|
+
return Boolean(currentBlock?.holder?.closest('[data-blok-table-cell-blocks]'));
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Fully close the toolbar if the current block is NOT inside a table cell.
|
|
61
|
+
* Used for destructive operations (Backspace, Delete, merge) where the
|
|
62
|
+
* toolbar should be dismissed — unlike arrow navigation where
|
|
63
|
+
* hideBlockActions() is preferred to allow reopening.
|
|
64
|
+
*/
|
|
65
|
+
private closeToolbarIfNotInTableCell(): void {
|
|
66
|
+
if (this.isCurrentBlockInsideTableCell) {
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
this.Blok.Toolbar.close();
|
|
71
|
+
}
|
|
72
|
+
|
|
46
73
|
/**
|
|
47
74
|
* Tab pressed inside a Block.
|
|
48
75
|
* @param event - keydown event
|
|
@@ -105,17 +132,31 @@ export class KeyboardNavigation extends BlockEventComposer {
|
|
|
105
132
|
return;
|
|
106
133
|
}
|
|
107
134
|
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
this.Blok.
|
|
135
|
+
/**
|
|
136
|
+
* Capture caret position before block creation so undo can restore it.
|
|
137
|
+
* Must run before stopCapturing/block insertion since the keyboard capture
|
|
138
|
+
* handler fires AFTER handleEnter (document capture runs before redactor capture).
|
|
139
|
+
*/
|
|
140
|
+
this.Blok.YjsManager.markCaretBeforeChange();
|
|
114
141
|
|
|
115
142
|
/**
|
|
116
|
-
*
|
|
143
|
+
* Use transactForTool to keep the entire Enter operation in a single undo entry:
|
|
144
|
+
* 1. Calls stopCapturing() to separate from previous typing
|
|
145
|
+
* 2. Suppresses stopCapturing during block creation + caret movement
|
|
146
|
+
* (prevents currentBlockIndex setter from splitting the undo entry
|
|
147
|
+
* before async table cell content sync completes)
|
|
148
|
+
* 3. Calls stopCapturing() in rAF after all async syncs complete
|
|
117
149
|
*/
|
|
118
|
-
this.Blok.
|
|
150
|
+
this.Blok.BlockManager.transactForTool(() => {
|
|
151
|
+
const blockToFocus = this.createBlockOnEnter(currentBlock);
|
|
152
|
+
|
|
153
|
+
this.Blok.Caret.setToBlock(blockToFocus);
|
|
154
|
+
|
|
155
|
+
/**
|
|
156
|
+
* Show Toolbar
|
|
157
|
+
*/
|
|
158
|
+
this.Blok.Toolbar.moveAndOpen(blockToFocus);
|
|
159
|
+
});
|
|
119
160
|
|
|
120
161
|
event.preventDefault();
|
|
121
162
|
}
|
|
@@ -132,27 +173,18 @@ export class KeyboardNavigation extends BlockEventComposer {
|
|
|
132
173
|
*/
|
|
133
174
|
private createBlockOnEnter(currentBlock: Block): Block {
|
|
134
175
|
// Case 1: Caret at start - insert block above
|
|
135
|
-
if (currentBlock.currentInput !== undefined && isCaretAtStartOfInput(currentBlock.currentInput) && !currentBlock.hasMedia) {
|
|
176
|
+
if (currentBlock.currentInput !== undefined && isCaretAtStartOfInput(currentBlock.currentInput) && !currentBlock.hasMedia && (currentBlock.parentId === null || !currentBlock.isEmpty)) {
|
|
136
177
|
this.Blok.BlockManager.insertDefaultBlockAtIndex(this.Blok.BlockManager.currentBlockIndex);
|
|
137
178
|
|
|
138
|
-
// Force new undo group so typing in the new block is separate from block creation
|
|
139
|
-
this.Blok.YjsManager.stopCapturing();
|
|
140
|
-
|
|
141
179
|
return currentBlock;
|
|
142
180
|
}
|
|
143
181
|
|
|
144
182
|
// Case 2: Caret at end - insert block below
|
|
145
183
|
if (currentBlock.currentInput && isCaretAtEndOfInput(currentBlock.currentInput)) {
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
// Force new undo group so typing in the new block is separate from block creation
|
|
149
|
-
this.Blok.YjsManager.stopCapturing();
|
|
150
|
-
|
|
151
|
-
return newBlock;
|
|
184
|
+
return this.Blok.BlockManager.insertDefaultBlockAtIndex(this.Blok.BlockManager.currentBlockIndex + 1);
|
|
152
185
|
}
|
|
153
186
|
|
|
154
187
|
// Case 3: Caret in middle - split block
|
|
155
|
-
// Note: split() uses transact() internally, so it's already atomic - no stopCapturing needed
|
|
156
188
|
return this.Blok.BlockManager.split();
|
|
157
189
|
}
|
|
158
190
|
|
|
@@ -186,7 +218,8 @@ export class KeyboardNavigation extends BlockEventComposer {
|
|
|
186
218
|
* All the cases below have custom behaviour, so we don't need a native one
|
|
187
219
|
*/
|
|
188
220
|
event.preventDefault();
|
|
189
|
-
|
|
221
|
+
|
|
222
|
+
this.closeToolbarIfNotInTableCell();
|
|
190
223
|
|
|
191
224
|
const isFirstInputFocused = currentBlock.currentInput === currentBlock.firstInput;
|
|
192
225
|
|
|
@@ -273,7 +306,8 @@ export class KeyboardNavigation extends BlockEventComposer {
|
|
|
273
306
|
* All the cases below have custom behaviour, so we don't need a native one
|
|
274
307
|
*/
|
|
275
308
|
event.preventDefault();
|
|
276
|
-
|
|
309
|
+
|
|
310
|
+
this.closeToolbarIfNotInTableCell();
|
|
277
311
|
|
|
278
312
|
const isLastInputFocused = currentBlock.currentInput === currentBlock.lastInput;
|
|
279
313
|
|
|
@@ -316,7 +350,7 @@ export class KeyboardNavigation extends BlockEventComposer {
|
|
|
316
350
|
const newCurrentBlock = BlockManager.currentBlock;
|
|
317
351
|
|
|
318
352
|
newCurrentBlock && Caret.setToBlock(newCurrentBlock, Caret.positions.START);
|
|
319
|
-
this.
|
|
353
|
+
this.closeToolbarIfNotInTableCell();
|
|
320
354
|
|
|
321
355
|
return;
|
|
322
356
|
}
|
|
@@ -340,7 +374,7 @@ export class KeyboardNavigation extends BlockEventComposer {
|
|
|
340
374
|
* @param blockToMerge - what Block we want to merge
|
|
341
375
|
*/
|
|
342
376
|
private mergeBlocks(targetBlock: Block, blockToMerge: Block): void {
|
|
343
|
-
const { BlockManager
|
|
377
|
+
const { BlockManager } = this.Blok;
|
|
344
378
|
|
|
345
379
|
if (targetBlock.lastInput === undefined) {
|
|
346
380
|
return;
|
|
@@ -351,7 +385,7 @@ export class KeyboardNavigation extends BlockEventComposer {
|
|
|
351
385
|
BlockManager
|
|
352
386
|
.mergeBlocks(targetBlock, blockToMerge)
|
|
353
387
|
.then(() => {
|
|
354
|
-
|
|
388
|
+
this.closeToolbarIfNotInTableCell();
|
|
355
389
|
})
|
|
356
390
|
.catch(() => {
|
|
357
391
|
// Error handling for mergeBlocks
|
|
@@ -391,9 +425,10 @@ export class KeyboardNavigation extends BlockEventComposer {
|
|
|
391
425
|
/**
|
|
392
426
|
* Close Toolbar when user moves cursor, but keep toolbars open if the user
|
|
393
427
|
* is extending selection with the Shift key so inline interactions remain available.
|
|
428
|
+
* Skip closing when inside a table cell — the toolbar belongs to the parent
|
|
429
|
+
* table block and the hover controller won't re-emit BlockHovered for it.
|
|
394
430
|
*/
|
|
395
|
-
if (!event.shiftKey) {
|
|
396
|
-
this.Blok.Toolbar.close();
|
|
431
|
+
if (!event.shiftKey && !this.isCurrentBlockInsideTableCell) {
|
|
397
432
|
this.Blok.InlineToolbar.close();
|
|
398
433
|
}
|
|
399
434
|
|
|
@@ -477,6 +512,11 @@ export class KeyboardNavigation extends BlockEventComposer {
|
|
|
477
512
|
*/
|
|
478
513
|
event.preventDefault();
|
|
479
514
|
|
|
515
|
+
/**
|
|
516
|
+
* Reopen the toolbar at the new block position after navigation
|
|
517
|
+
*/
|
|
518
|
+
this.Blok.Toolbar.moveAndOpen(this.Blok.BlockManager.currentBlock);
|
|
519
|
+
|
|
480
520
|
return;
|
|
481
521
|
}
|
|
482
522
|
|
|
@@ -526,15 +566,16 @@ export class KeyboardNavigation extends BlockEventComposer {
|
|
|
526
566
|
return;
|
|
527
567
|
}
|
|
528
568
|
|
|
529
|
-
if (toolbarOpened) {
|
|
569
|
+
if (toolbarOpened && !this.isCurrentBlockInsideTableCell) {
|
|
530
570
|
this.Blok.UI.closeAllToolbars();
|
|
531
571
|
}
|
|
532
572
|
|
|
533
573
|
/**
|
|
534
574
|
* Close Toolbar when user moves cursor, but preserve it for Shift-based selection changes.
|
|
575
|
+
* Skip closing when inside a table cell — the toolbar belongs to the parent
|
|
576
|
+
* table block and the hover controller won't re-emit BlockHovered for it.
|
|
535
577
|
*/
|
|
536
|
-
if (!event.shiftKey) {
|
|
537
|
-
this.Blok.Toolbar.close();
|
|
578
|
+
if (!event.shiftKey && !this.isCurrentBlockInsideTableCell) {
|
|
538
579
|
this.Blok.InlineToolbar.close();
|
|
539
580
|
}
|
|
540
581
|
|
|
@@ -605,6 +646,11 @@ export class KeyboardNavigation extends BlockEventComposer {
|
|
|
605
646
|
*/
|
|
606
647
|
event.preventDefault();
|
|
607
648
|
|
|
649
|
+
/**
|
|
650
|
+
* Reopen the toolbar at the new block position after navigation
|
|
651
|
+
*/
|
|
652
|
+
this.Blok.Toolbar.moveAndOpen(this.Blok.BlockManager.currentBlock);
|
|
653
|
+
|
|
608
654
|
return;
|
|
609
655
|
}
|
|
610
656
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { Block } from '../../../block';
|
|
2
|
-
import { HEADER_PATTERN, CHECKLIST_PATTERN, UNORDERED_LIST_PATTERN, ORDERED_LIST_PATTERN, HEADER_TOOL_NAME, LIST_TOOL_NAME } from '../constants';
|
|
2
|
+
import { HEADER_PATTERN, CHECKLIST_PATTERN, UNORDERED_LIST_PATTERN, ORDERED_LIST_PATTERN, TOGGLE_PATTERN, HEADER_TOOL_NAME, LIST_TOOL_NAME, TOGGLE_TOOL_NAME } from '../constants';
|
|
3
3
|
|
|
4
4
|
import { BlockEventComposer } from './__base';
|
|
5
5
|
|
|
@@ -26,8 +26,9 @@ export class MarkdownShortcuts extends BlockEventComposer {
|
|
|
26
26
|
|
|
27
27
|
const handledList = this.handleListShortcut();
|
|
28
28
|
const handledHeader = this.handleHeaderShortcut();
|
|
29
|
+
const handledToggle = this.handleToggleShortcut();
|
|
29
30
|
|
|
30
|
-
return handledList || handledHeader;
|
|
31
|
+
return handledList || handledHeader || handledToggle;
|
|
31
32
|
}
|
|
32
33
|
|
|
33
34
|
/**
|
|
@@ -207,6 +208,57 @@ export class MarkdownShortcuts extends BlockEventComposer {
|
|
|
207
208
|
return true;
|
|
208
209
|
}
|
|
209
210
|
|
|
211
|
+
/**
|
|
212
|
+
* Check if current block matches a toggle shortcut pattern ("> ") and convert it.
|
|
213
|
+
*/
|
|
214
|
+
private handleToggleShortcut(): boolean {
|
|
215
|
+
const { BlockManager, Tools } = this.Blok;
|
|
216
|
+
const currentBlock = BlockManager.currentBlock;
|
|
217
|
+
|
|
218
|
+
if (!currentBlock) {
|
|
219
|
+
return false;
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
if (!currentBlock.tool.isDefault) {
|
|
223
|
+
return false;
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
const toggleTool = Tools.blockTools.get(TOGGLE_TOOL_NAME);
|
|
227
|
+
|
|
228
|
+
if (!toggleTool) {
|
|
229
|
+
return false;
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
const currentInput = currentBlock.currentInput;
|
|
233
|
+
|
|
234
|
+
if (!currentInput) {
|
|
235
|
+
return false;
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
const textContent = currentInput.textContent || '';
|
|
239
|
+
const match = TOGGLE_PATTERN.exec(textContent);
|
|
240
|
+
|
|
241
|
+
if (!match) {
|
|
242
|
+
return false;
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
this.Blok.YjsManager.stopCapturing();
|
|
246
|
+
|
|
247
|
+
const shortcutLength = 2; // "> "
|
|
248
|
+
const remainingHtml = this.extractRemainingHtml(currentInput, shortcutLength);
|
|
249
|
+
const caretOffset = this.getCaretOffset(currentInput) - shortcutLength;
|
|
250
|
+
|
|
251
|
+
const newBlock = BlockManager.replace(currentBlock, TOGGLE_TOOL_NAME, {
|
|
252
|
+
text: remainingHtml,
|
|
253
|
+
});
|
|
254
|
+
|
|
255
|
+
this.setCaretAfterConversion(newBlock, caretOffset);
|
|
256
|
+
|
|
257
|
+
this.Blok.YjsManager.stopCapturing();
|
|
258
|
+
|
|
259
|
+
return true;
|
|
260
|
+
}
|
|
261
|
+
|
|
210
262
|
/**
|
|
211
263
|
* Match default header shortcuts like "# ", "## ", etc.
|
|
212
264
|
*/
|
|
@@ -63,3 +63,15 @@ export const ORDERED_LIST_PATTERN = /^(\d+)[.)]\s([\s\S]*)$/;
|
|
|
63
63
|
* Captures remaining content after the shortcut in group 2
|
|
64
64
|
*/
|
|
65
65
|
export const HEADER_PATTERN = /^(#{1,6})\s([\s\S]*)$/;
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Tool name for toggle blocks.
|
|
69
|
+
*/
|
|
70
|
+
export const TOGGLE_TOOL_NAME = 'toggle';
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Regex pattern for detecting toggle shortcuts.
|
|
74
|
+
* Matches ">" followed by a space at the start of text.
|
|
75
|
+
* Captures remaining content after the shortcut in group 1.
|
|
76
|
+
*/
|
|
77
|
+
export const TOGGLE_PATTERN = /^>\s([\s\S]*)$/;
|
|
@@ -228,16 +228,13 @@ export class BlockEvents extends Module {
|
|
|
228
228
|
}
|
|
229
229
|
|
|
230
230
|
/**
|
|
231
|
-
* When user
|
|
232
|
-
*
|
|
233
|
-
* - clear block highlighting
|
|
231
|
+
* When user types something, clear block highlighting.
|
|
232
|
+
* The toolbar stays visible — it should persist during typing.
|
|
234
233
|
*/
|
|
235
234
|
if (!isPrintableKeyEvent(event)) {
|
|
236
235
|
return;
|
|
237
236
|
}
|
|
238
237
|
|
|
239
|
-
this.Blok.Toolbar.close();
|
|
240
|
-
|
|
241
238
|
/**
|
|
242
239
|
* Allow to use shortcuts with selected blocks
|
|
243
240
|
* @type {boolean}
|
|
@@ -305,6 +302,17 @@ export class BlockEvents extends Module {
|
|
|
305
302
|
return;
|
|
306
303
|
}
|
|
307
304
|
|
|
305
|
+
/**
|
|
306
|
+
* Eagerly update currentBlock from the event target.
|
|
307
|
+
* The debounced selectionchange handler (180ms) may not have fired yet
|
|
308
|
+
* if '/' was typed quickly after clicking into a different block (e.g. a table cell).
|
|
309
|
+
* Without this, currentBlockIndex is stale and the toolbox checks
|
|
310
|
+
* the wrong block for table-cell containment, failing to hide restricted tools.
|
|
311
|
+
*/
|
|
312
|
+
if (event.target instanceof Node) {
|
|
313
|
+
this.Blok.BlockManager.setCurrentBlockByChildNode(event.target);
|
|
314
|
+
}
|
|
315
|
+
|
|
308
316
|
const currentBlock = this.Blok.BlockManager.currentBlock;
|
|
309
317
|
const canOpenToolbox = currentBlock?.isEmpty;
|
|
310
318
|
|
|
@@ -143,6 +143,14 @@ export class BlockManager extends Module {
|
|
|
143
143
|
return this.repository.isBlokEmpty();
|
|
144
144
|
}
|
|
145
145
|
|
|
146
|
+
/**
|
|
147
|
+
* Returns true when a Yjs sync operation (undo/redo) is in progress.
|
|
148
|
+
* Used by the Blocks API to expose sync state to tools.
|
|
149
|
+
*/
|
|
150
|
+
public get isSyncingFromYjs(): boolean {
|
|
151
|
+
return this.yjsSync.isSyncingFromYjs;
|
|
152
|
+
}
|
|
153
|
+
|
|
146
154
|
/**
|
|
147
155
|
* Index of current working block
|
|
148
156
|
* @type {number}
|
|
@@ -186,6 +194,12 @@ export class BlockManager extends Module {
|
|
|
186
194
|
*/
|
|
187
195
|
private yjsSync!: BlockYjsSync;
|
|
188
196
|
|
|
197
|
+
/**
|
|
198
|
+
* Set of parent block IDs awaiting deferred Yjs sync.
|
|
199
|
+
* Batched via queueMicrotask to avoid multiple syncs during batch operations.
|
|
200
|
+
*/
|
|
201
|
+
private parentsSyncScheduled = new Set<string>();
|
|
202
|
+
|
|
189
203
|
/**
|
|
190
204
|
* Operations handler for state changes
|
|
191
205
|
*/
|
|
@@ -261,8 +275,12 @@ export class BlockManager extends Module {
|
|
|
261
275
|
this.bindBlockEvents.bind(this)
|
|
262
276
|
);
|
|
263
277
|
|
|
264
|
-
// Initialize hierarchy
|
|
265
|
-
this.hierarchy = new BlockHierarchy(this.repository)
|
|
278
|
+
// Initialize hierarchy with callback to sync parent data to Yjs
|
|
279
|
+
this.hierarchy = new BlockHierarchy(this.repository, (parentId) => {
|
|
280
|
+
if (!this.yjsSync.isSyncingFromYjs) {
|
|
281
|
+
this.scheduleParentSync(parentId);
|
|
282
|
+
}
|
|
283
|
+
});
|
|
266
284
|
|
|
267
285
|
// Initialize operations first (before yjsSync) to allow circular dependency resolution
|
|
268
286
|
this.operations = new BlockOperations(
|
|
@@ -637,6 +655,30 @@ export class BlockManager extends Module {
|
|
|
637
655
|
return result;
|
|
638
656
|
}
|
|
639
657
|
|
|
658
|
+
/**
|
|
659
|
+
* Execute a function with stopCapturing suppressed.
|
|
660
|
+
* All block operations within fn are kept in the same undo group.
|
|
661
|
+
* Used by tools that perform multi-step structural operations
|
|
662
|
+
* (e.g., table add row = multiple block inserts).
|
|
663
|
+
*/
|
|
664
|
+
public transactForTool(fn: () => void): void {
|
|
665
|
+
this.Blok.YjsManager.stopCapturing();
|
|
666
|
+
|
|
667
|
+
const prevSuppress = this.operations.suppressStopCapturing;
|
|
668
|
+
|
|
669
|
+
this.operations.suppressStopCapturing = true;
|
|
670
|
+
|
|
671
|
+
try {
|
|
672
|
+
fn();
|
|
673
|
+
} finally {
|
|
674
|
+
this.operations.suppressStopCapturing = prevSuppress;
|
|
675
|
+
|
|
676
|
+
requestAnimationFrame(() => {
|
|
677
|
+
this.Blok.YjsManager.stopCapturing();
|
|
678
|
+
});
|
|
679
|
+
}
|
|
680
|
+
}
|
|
681
|
+
|
|
640
682
|
/**
|
|
641
683
|
* Splits a block by updating the current block's data and inserting a new block.
|
|
642
684
|
* Both operations are grouped into a single undo entry.
|
|
@@ -682,6 +724,16 @@ export class BlockManager extends Module {
|
|
|
682
724
|
return this.repository.getBlockById(id);
|
|
683
725
|
}
|
|
684
726
|
|
|
727
|
+
/**
|
|
728
|
+
* Walks up the parentId chain and returns the top-level (root) block.
|
|
729
|
+
* If the block has no parent, returns it as-is.
|
|
730
|
+
* @param block - the block to resolve
|
|
731
|
+
* @returns {Block} the root ancestor block
|
|
732
|
+
*/
|
|
733
|
+
public resolveToRootBlock(block: Block): Block {
|
|
734
|
+
return this.repository.resolveToRootBlock(block);
|
|
735
|
+
}
|
|
736
|
+
|
|
685
737
|
/**
|
|
686
738
|
* Returns the depth (nesting level) of a block in the hierarchy.
|
|
687
739
|
* @param block - the block to get depth for
|
|
@@ -928,6 +980,33 @@ export class BlockManager extends Module {
|
|
|
928
980
|
return block;
|
|
929
981
|
}
|
|
930
982
|
|
|
983
|
+
/**
|
|
984
|
+
* Schedule a deferred sync of a parent block's data to Yjs.
|
|
985
|
+
* Uses queueMicrotask to batch multiple parent changes (e.g. when initializing
|
|
986
|
+
* all cells in a new table row) into a single flush.
|
|
987
|
+
*/
|
|
988
|
+
private scheduleParentSync(parentId: string): void {
|
|
989
|
+
if (this.parentsSyncScheduled.size === 0) {
|
|
990
|
+
queueMicrotask(() => this.flushParentSyncs());
|
|
991
|
+
}
|
|
992
|
+
this.parentsSyncScheduled.add(parentId);
|
|
993
|
+
}
|
|
994
|
+
|
|
995
|
+
/**
|
|
996
|
+
* Flush all scheduled parent syncs to Yjs.
|
|
997
|
+
* Called from the microtask scheduled by scheduleParentSync.
|
|
998
|
+
*/
|
|
999
|
+
private flushParentSyncs(): void {
|
|
1000
|
+
for (const parentId of this.parentsSyncScheduled) {
|
|
1001
|
+
const parent = this.repository.getBlockById(parentId);
|
|
1002
|
+
|
|
1003
|
+
if (parent !== undefined) {
|
|
1004
|
+
void this.syncBlockDataToYjs(parent);
|
|
1005
|
+
}
|
|
1006
|
+
}
|
|
1007
|
+
this.parentsSyncScheduled.clear();
|
|
1008
|
+
}
|
|
1009
|
+
|
|
931
1010
|
/**
|
|
932
1011
|
* Sync block data to Yjs after DOM mutation
|
|
933
1012
|
*/
|
|
@@ -12,12 +12,15 @@ import type { BlockRepository } from './repository';
|
|
|
12
12
|
*/
|
|
13
13
|
export class BlockHierarchy {
|
|
14
14
|
private readonly repository: BlockRepository;
|
|
15
|
+
private readonly onParentChanged?: (parentId: string) => void;
|
|
15
16
|
|
|
16
17
|
/**
|
|
17
18
|
* @param repository - BlockRepository for looking up blocks by id
|
|
19
|
+
* @param onParentChanged - optional callback invoked after a block is assigned a non-null parent
|
|
18
20
|
*/
|
|
19
|
-
constructor(repository: BlockRepository) {
|
|
21
|
+
constructor(repository: BlockRepository, onParentChanged?: (parentId: string) => void) {
|
|
20
22
|
this.repository = repository;
|
|
23
|
+
this.onParentChanged = onParentChanged;
|
|
21
24
|
}
|
|
22
25
|
|
|
23
26
|
/**
|
|
@@ -73,6 +76,11 @@ export class BlockHierarchy {
|
|
|
73
76
|
|
|
74
77
|
// Update visual indentation
|
|
75
78
|
this.updateBlockIndentation(block);
|
|
79
|
+
|
|
80
|
+
// Notify listener so parent data can be synced (e.g. to Yjs)
|
|
81
|
+
if (newParentId !== null && this.onParentChanged !== undefined) {
|
|
82
|
+
this.onParentChanged(newParentId);
|
|
83
|
+
}
|
|
76
84
|
}
|
|
77
85
|
|
|
78
86
|
/**
|
|
@@ -80,9 +88,19 @@ export class BlockHierarchy {
|
|
|
80
88
|
* @param block - the block to update indentation for
|
|
81
89
|
*/
|
|
82
90
|
public updateBlockIndentation(block: Block): void {
|
|
91
|
+
const { holder } = block;
|
|
92
|
+
|
|
93
|
+
// Blocks inside table cells should not receive visual indentation.
|
|
94
|
+
// The parent-child relationship is semantic (data tracking), not visual.
|
|
95
|
+
if (holder.closest('[data-blok-table-cell-blocks]')) {
|
|
96
|
+
holder.style.marginLeft = '';
|
|
97
|
+
holder.setAttribute('data-blok-depth', '0');
|
|
98
|
+
|
|
99
|
+
return;
|
|
100
|
+
}
|
|
101
|
+
|
|
83
102
|
const depth = this.getBlockDepth(block);
|
|
84
103
|
const indentationPx = depth * 24; // 24px per level
|
|
85
|
-
const { holder } = block;
|
|
86
104
|
|
|
87
105
|
holder.style.marginLeft = indentationPx > 0 ? `${indentationPx}px` : '';
|
|
88
106
|
holder.setAttribute('data-blok-depth', depth.toString());
|