@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
|
@@ -56,6 +56,7 @@ export class TableRowColDrag {
|
|
|
56
56
|
|
|
57
57
|
private boundDocPointerMove: (e: PointerEvent) => void;
|
|
58
58
|
private boundDocPointerUp: (e: PointerEvent) => void;
|
|
59
|
+
private boundDocPointerCancel: () => void;
|
|
59
60
|
|
|
60
61
|
/** Resolves when drag ends — set by beginTracking, consumed by caller */
|
|
61
62
|
private resolveTracking: ((wasDrag: boolean) => void) | null = null;
|
|
@@ -67,6 +68,7 @@ export class TableRowColDrag {
|
|
|
67
68
|
|
|
68
69
|
this.boundDocPointerMove = this.handleDocPointerMove.bind(this);
|
|
69
70
|
this.boundDocPointerUp = this.handleDocPointerUp.bind(this);
|
|
71
|
+
this.boundDocPointerCancel = this.handleDocPointerCancel.bind(this);
|
|
70
72
|
}
|
|
71
73
|
|
|
72
74
|
/**
|
|
@@ -87,6 +89,7 @@ export class TableRowColDrag {
|
|
|
87
89
|
|
|
88
90
|
document.addEventListener('pointermove', this.boundDocPointerMove);
|
|
89
91
|
document.addEventListener('pointerup', this.boundDocPointerUp);
|
|
92
|
+
document.addEventListener('pointercancel', this.boundDocPointerCancel);
|
|
90
93
|
|
|
91
94
|
return new Promise<boolean>(resolve => {
|
|
92
95
|
this.resolveTracking = resolve;
|
|
@@ -113,6 +116,7 @@ export class TableRowColDrag {
|
|
|
113
116
|
|
|
114
117
|
document.removeEventListener('pointermove', this.boundDocPointerMove);
|
|
115
118
|
document.removeEventListener('pointerup', this.boundDocPointerUp);
|
|
119
|
+
document.removeEventListener('pointercancel', this.boundDocPointerCancel);
|
|
116
120
|
|
|
117
121
|
this.onDragStateChange?.(false, null);
|
|
118
122
|
this.isDragging = false;
|
|
@@ -139,6 +143,7 @@ export class TableRowColDrag {
|
|
|
139
143
|
private handleDocPointerUp(e: PointerEvent): void {
|
|
140
144
|
document.removeEventListener('pointermove', this.boundDocPointerMove);
|
|
141
145
|
document.removeEventListener('pointerup', this.boundDocPointerUp);
|
|
146
|
+
document.removeEventListener('pointercancel', this.boundDocPointerCancel);
|
|
142
147
|
|
|
143
148
|
if (this.isDragging) {
|
|
144
149
|
this.finishDrag(e);
|
|
@@ -150,6 +155,15 @@ export class TableRowColDrag {
|
|
|
150
155
|
this.cleanup();
|
|
151
156
|
}
|
|
152
157
|
|
|
158
|
+
/**
|
|
159
|
+
* Handle pointercancel — browser aborted the pointer (touch gesture, system dialog, etc.).
|
|
160
|
+
* Cleans up without applying the move (treats as abort).
|
|
161
|
+
*/
|
|
162
|
+
private handleDocPointerCancel(): void {
|
|
163
|
+
this.resolveTracking?.(this.isDragging);
|
|
164
|
+
this.cleanup();
|
|
165
|
+
}
|
|
166
|
+
|
|
153
167
|
private startDrag(): void {
|
|
154
168
|
this.grid.style.userSelect = 'none';
|
|
155
169
|
document.body.style.cursor = 'grabbing';
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Scroll haze overlays for the Table tool.
|
|
3
|
+
*
|
|
4
|
+
* Adds gradient overlays on the left/right edges of the table wrapper
|
|
5
|
+
* to indicate that the table content is horizontally scrollable.
|
|
6
|
+
* Uses a passive scroll event listener with rAF throttling.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
const HAZE_ATTR = 'data-blok-table-haze';
|
|
10
|
+
const HAZE_VISIBLE_ATTR = 'data-blok-table-haze-visible';
|
|
11
|
+
|
|
12
|
+
/** Minimum scrollLeft delta to consider "scrolled" (avoids sub-pixel flicker). */
|
|
13
|
+
const SCROLL_THRESHOLD = 1;
|
|
14
|
+
|
|
15
|
+
const HAZE_CLASSES = [
|
|
16
|
+
'absolute',
|
|
17
|
+
'top-0',
|
|
18
|
+
'bottom-0',
|
|
19
|
+
'w-12',
|
|
20
|
+
'pointer-events-none',
|
|
21
|
+
'opacity-0',
|
|
22
|
+
'transition-opacity',
|
|
23
|
+
'duration-150',
|
|
24
|
+
'z-1',
|
|
25
|
+
];
|
|
26
|
+
|
|
27
|
+
const LEFT_HAZE_CLASSES = [
|
|
28
|
+
'left-0',
|
|
29
|
+
'bg-linear-to-r',
|
|
30
|
+
'from-white/80',
|
|
31
|
+
'to-transparent',
|
|
32
|
+
];
|
|
33
|
+
|
|
34
|
+
const RIGHT_HAZE_CLASSES = [
|
|
35
|
+
'right-5',
|
|
36
|
+
'bg-linear-to-l',
|
|
37
|
+
'from-white/80',
|
|
38
|
+
'to-transparent',
|
|
39
|
+
];
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Manages left/right gradient haze overlays that indicate
|
|
43
|
+
* the table can be scrolled horizontally.
|
|
44
|
+
*/
|
|
45
|
+
export class TableScrollHaze {
|
|
46
|
+
private leftHaze: HTMLDivElement | null = null;
|
|
47
|
+
private rightHaze: HTMLDivElement | null = null;
|
|
48
|
+
private scrollContainer: HTMLElement | null = null;
|
|
49
|
+
private boundOnScroll: (() => void) | null = null;
|
|
50
|
+
private ticking = false;
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Create haze overlay elements and attach the scroll listener.
|
|
54
|
+
*
|
|
55
|
+
* @param wrapper - The table wrapper element (position: relative)
|
|
56
|
+
* @param scrollContainer - The scroll container with overflow-x: auto
|
|
57
|
+
*/
|
|
58
|
+
public init(wrapper: HTMLElement, scrollContainer: HTMLElement): void {
|
|
59
|
+
this.scrollContainer = scrollContainer;
|
|
60
|
+
|
|
61
|
+
this.leftHaze = this.createHazeElement('left');
|
|
62
|
+
this.rightHaze = this.createHazeElement('right');
|
|
63
|
+
|
|
64
|
+
wrapper.appendChild(this.leftHaze);
|
|
65
|
+
wrapper.appendChild(this.rightHaze);
|
|
66
|
+
|
|
67
|
+
this.boundOnScroll = (): void => {
|
|
68
|
+
if (!this.ticking) {
|
|
69
|
+
requestAnimationFrame(() => {
|
|
70
|
+
this.syncVisibility();
|
|
71
|
+
this.ticking = false;
|
|
72
|
+
});
|
|
73
|
+
this.ticking = true;
|
|
74
|
+
}
|
|
75
|
+
};
|
|
76
|
+
|
|
77
|
+
scrollContainer.addEventListener('scroll', this.boundOnScroll, { passive: true });
|
|
78
|
+
|
|
79
|
+
this.syncVisibility();
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Recalculate haze visibility (e.g. after column resize or add/delete).
|
|
84
|
+
*/
|
|
85
|
+
public update(): void {
|
|
86
|
+
this.syncVisibility();
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* Remove overlay elements and detach the scroll listener.
|
|
91
|
+
*/
|
|
92
|
+
public destroy(): void {
|
|
93
|
+
if (this.boundOnScroll && this.scrollContainer) {
|
|
94
|
+
this.scrollContainer.removeEventListener('scroll', this.boundOnScroll);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
this.leftHaze?.remove();
|
|
98
|
+
this.rightHaze?.remove();
|
|
99
|
+
|
|
100
|
+
this.leftHaze = null;
|
|
101
|
+
this.rightHaze = null;
|
|
102
|
+
this.scrollContainer = null;
|
|
103
|
+
this.boundOnScroll = null;
|
|
104
|
+
this.ticking = false;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
private createHazeElement(side: 'left' | 'right'): HTMLDivElement {
|
|
108
|
+
const el = document.createElement('div');
|
|
109
|
+
|
|
110
|
+
el.setAttribute(HAZE_ATTR, side);
|
|
111
|
+
el.setAttribute('aria-hidden', 'true');
|
|
112
|
+
el.classList.add(...HAZE_CLASSES, ...(side === 'left' ? LEFT_HAZE_CLASSES : RIGHT_HAZE_CLASSES));
|
|
113
|
+
|
|
114
|
+
return el;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
private syncVisibility(): void {
|
|
118
|
+
const sc = this.scrollContainer;
|
|
119
|
+
|
|
120
|
+
if (!sc) {
|
|
121
|
+
return;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
const { overflowX } = getComputedStyle(sc);
|
|
125
|
+
const canScroll = overflowX === 'auto' || overflowX === 'scroll';
|
|
126
|
+
|
|
127
|
+
if (!canScroll) {
|
|
128
|
+
this.setVisible(this.leftHaze, false);
|
|
129
|
+
this.setVisible(this.rightHaze, false);
|
|
130
|
+
|
|
131
|
+
return;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
const { scrollLeft, scrollWidth, clientWidth } = sc;
|
|
135
|
+
const maxScroll = scrollWidth - clientWidth;
|
|
136
|
+
|
|
137
|
+
this.setVisible(this.leftHaze, scrollLeft > SCROLL_THRESHOLD);
|
|
138
|
+
this.setVisible(this.rightHaze, maxScroll > SCROLL_THRESHOLD && scrollLeft < maxScroll - SCROLL_THRESHOLD);
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
private setVisible(el: HTMLElement | null, visible: boolean): void {
|
|
142
|
+
if (!el) {
|
|
143
|
+
return;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
if (visible) {
|
|
147
|
+
el.setAttribute(HAZE_VISIBLE_ATTR, '');
|
|
148
|
+
} else {
|
|
149
|
+
el.removeAttribute(HAZE_VISIBLE_ATTR);
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
}
|
package/src/tools/table/types.ts
CHANGED
|
@@ -4,7 +4,7 @@ import type { BlockToolData } from '../../../types';
|
|
|
4
4
|
* Cell content always contains block IDs.
|
|
5
5
|
* Every cell in the table is represented as an array of block references.
|
|
6
6
|
*/
|
|
7
|
-
export type CellContent = { blocks: string[] };
|
|
7
|
+
export type CellContent = { blocks: string[]; color?: string; textColor?: string; text?: string };
|
|
8
8
|
|
|
9
9
|
/**
|
|
10
10
|
* Legacy cell content type for migration from string-based cells.
|
|
@@ -53,4 +53,25 @@ export interface TableConfig {
|
|
|
53
53
|
withHeadings?: boolean;
|
|
54
54
|
/** Whether to start stretched */
|
|
55
55
|
stretched?: boolean;
|
|
56
|
+
/** Additional tool names to restrict from being inserted into table cells */
|
|
57
|
+
restrictedTools?: string[];
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Block data within a clipboard cell (no IDs — those are assigned on paste).
|
|
62
|
+
*/
|
|
63
|
+
export interface ClipboardBlockData {
|
|
64
|
+
tool: string;
|
|
65
|
+
data: Record<string, unknown>;
|
|
66
|
+
tunes?: Record<string, unknown>;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Clipboard payload for copied table cells.
|
|
71
|
+
* Stored as JSON in a data attribute on the HTML table element.
|
|
72
|
+
*/
|
|
73
|
+
export interface TableCellsClipboard {
|
|
74
|
+
rows: number;
|
|
75
|
+
cols: number;
|
|
76
|
+
cells: Array<Array<{ blocks: ClipboardBlockData[]; color?: string; textColor?: string }>>;
|
|
56
77
|
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import type { TableEventBroker, BlockLifecycleEvent } from '../ownership/table-event-broker';
|
|
2
|
+
import type { TableOwnershipRegistry } from '../ownership/table-ownership-registry';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Adapter that bridges the ownership-based event broker into the existing
|
|
6
|
+
* TableCellBlocks event handling.
|
|
7
|
+
*
|
|
8
|
+
* In shadow mode, this adapter subscribes the table to the broker and
|
|
9
|
+
* forwards routed events to the table's handler. It does NOT replace the
|
|
10
|
+
* existing global event listener — both paths run in parallel for validation.
|
|
11
|
+
*
|
|
12
|
+
* After cutover (Task 7), this adapter becomes the sole event path.
|
|
13
|
+
*/
|
|
14
|
+
export class TableCellBlocksAdapter {
|
|
15
|
+
private readonly tableId: string;
|
|
16
|
+
private readonly broker: TableEventBroker;
|
|
17
|
+
private readonly registry: TableOwnershipRegistry;
|
|
18
|
+
private readonly onEvent: (blockId: string, event: BlockLifecycleEvent) => void;
|
|
19
|
+
|
|
20
|
+
constructor(options: {
|
|
21
|
+
tableId: string;
|
|
22
|
+
broker: TableEventBroker;
|
|
23
|
+
registry: TableOwnershipRegistry;
|
|
24
|
+
onEvent: (blockId: string, event: BlockLifecycleEvent) => void;
|
|
25
|
+
}) {
|
|
26
|
+
this.tableId = options.tableId;
|
|
27
|
+
this.broker = options.broker;
|
|
28
|
+
this.registry = options.registry;
|
|
29
|
+
this.onEvent = options.onEvent;
|
|
30
|
+
|
|
31
|
+
this.broker.subscribe(this.tableId, this.handleBrokerEvent);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Destroy the adapter — unsubscribe from the broker.
|
|
36
|
+
*/
|
|
37
|
+
destroy(): void {
|
|
38
|
+
this.broker.unsubscribe(this.tableId);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Handler for events routed through the broker.
|
|
43
|
+
*/
|
|
44
|
+
private handleBrokerEvent = (blockId: string, event: BlockLifecycleEvent): void => {
|
|
45
|
+
this.onEvent(blockId, event);
|
|
46
|
+
};
|
|
47
|
+
}
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Toggle Block Operations - Block-related operations for ToggleItem.
|
|
3
|
+
*
|
|
4
|
+
* Extracted from ToggleItem to reduce file size.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { stripFakeBackgroundElements } from '../../components/utils';
|
|
8
|
+
|
|
9
|
+
import type { ToggleItemData } from './types';
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Parse HTML string into a DocumentFragment.
|
|
13
|
+
*
|
|
14
|
+
* @param html - HTML string to parse
|
|
15
|
+
* @returns DocumentFragment with parsed nodes
|
|
16
|
+
*/
|
|
17
|
+
export const parseHTML = (html: string): DocumentFragment => {
|
|
18
|
+
const wrapper = document.createElement('div');
|
|
19
|
+
wrapper.innerHTML = html.trim();
|
|
20
|
+
|
|
21
|
+
const fragment = document.createDocumentFragment();
|
|
22
|
+
fragment.append(...Array.from(wrapper.childNodes));
|
|
23
|
+
|
|
24
|
+
return fragment;
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Save the toggle item data.
|
|
29
|
+
*
|
|
30
|
+
* @param data - Current toggle item data
|
|
31
|
+
* @param element - The toggle wrapper element (or null)
|
|
32
|
+
* @param getContentElement - Function to get the content element
|
|
33
|
+
* @returns The saved toggle item data
|
|
34
|
+
*/
|
|
35
|
+
export const saveToggleItem = (
|
|
36
|
+
data: ToggleItemData,
|
|
37
|
+
element: HTMLElement | null,
|
|
38
|
+
getContentElement: () => HTMLElement | null
|
|
39
|
+
): ToggleItemData => {
|
|
40
|
+
if (!element) return data;
|
|
41
|
+
|
|
42
|
+
const contentEl = getContentElement();
|
|
43
|
+
const text = contentEl ? stripFakeBackgroundElements(contentEl.innerHTML) : data.text;
|
|
44
|
+
|
|
45
|
+
return { text };
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Context for merge operations
|
|
50
|
+
*/
|
|
51
|
+
export interface MergeContext {
|
|
52
|
+
data: ToggleItemData;
|
|
53
|
+
getContentElement: () => HTMLElement | null;
|
|
54
|
+
parseHTML: (html: string) => DocumentFragment;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Merge incoming data into toggle item.
|
|
59
|
+
*
|
|
60
|
+
* @param context - The merge context
|
|
61
|
+
* @param incomingData - The incoming data to merge
|
|
62
|
+
*/
|
|
63
|
+
export const mergeToggleItemData = (
|
|
64
|
+
context: MergeContext,
|
|
65
|
+
incomingData: ToggleItemData
|
|
66
|
+
): void => {
|
|
67
|
+
const { data, getContentElement } = context;
|
|
68
|
+
|
|
69
|
+
data.text += incomingData.text;
|
|
70
|
+
|
|
71
|
+
const contentEl = getContentElement();
|
|
72
|
+
|
|
73
|
+
if (contentEl && incomingData.text) {
|
|
74
|
+
const fragment = context.parseHTML(incomingData.text);
|
|
75
|
+
|
|
76
|
+
contentEl.appendChild(fragment);
|
|
77
|
+
contentEl.normalize();
|
|
78
|
+
}
|
|
79
|
+
};
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Set data on the toggle item (for undo/redo).
|
|
83
|
+
*
|
|
84
|
+
* @param currentData - The current toggle item data
|
|
85
|
+
* @param newData - The new data to apply
|
|
86
|
+
* @param getContentElement - Function to get the content element
|
|
87
|
+
* @returns Object with the updated data and whether the update was in-place
|
|
88
|
+
*/
|
|
89
|
+
export const setToggleItemData = (
|
|
90
|
+
currentData: ToggleItemData,
|
|
91
|
+
newData: ToggleItemData,
|
|
92
|
+
getContentElement: () => HTMLElement | null
|
|
93
|
+
): { newData: ToggleItemData; inPlace: boolean } => {
|
|
94
|
+
const contentEl = getContentElement();
|
|
95
|
+
|
|
96
|
+
if (!contentEl) {
|
|
97
|
+
return { newData: currentData, inPlace: false };
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
const updatedData: ToggleItemData = {
|
|
101
|
+
...currentData,
|
|
102
|
+
...newData,
|
|
103
|
+
};
|
|
104
|
+
|
|
105
|
+
if (typeof newData.text === 'string') {
|
|
106
|
+
contentEl.innerHTML = newData.text;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
return { newData: updatedData, inPlace: true };
|
|
110
|
+
};
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Constants for the Toggle tool
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Tool name used when registering this tool with Blok
|
|
7
|
+
*/
|
|
8
|
+
export const TOOL_NAME = 'toggle';
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Placeholder translation key
|
|
12
|
+
*/
|
|
13
|
+
export const PLACEHOLDER_KEY = 'tools.toggle.placeholder';
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Base styles for toggle wrapper
|
|
17
|
+
*
|
|
18
|
+
* Matches paragraph spacing: py-[3px] from blok-block + mt-[2px] mb-px
|
|
19
|
+
*/
|
|
20
|
+
export const BASE_STYLES = 'outline-hidden py-[3px] mt-[2px] mb-px';
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Styles for toggle content area
|
|
24
|
+
*/
|
|
25
|
+
export const CONTENT_STYLES = 'outline-hidden pl-0.5 leading-[1.6em] flex-1 min-w-0';
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Styles for toggle wrapper (arrow + content layout)
|
|
29
|
+
*/
|
|
30
|
+
export const TOGGLE_WRAPPER_STYLES = 'flex items-start';
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Styles for the toggle arrow button
|
|
34
|
+
*/
|
|
35
|
+
export const ARROW_STYLES = 'flex-shrink-0 w-6 h-6 flex items-center justify-center cursor-pointer select-none rounded hover:bg-black/5 transition-all duration-200 ease-in-out mt-px';
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* SVG icon for the toggle arrow
|
|
39
|
+
*/
|
|
40
|
+
export const ARROW_ICON = '<svg width="12" height="12" viewBox="0 0 12 12" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M4.5 2.5L8.5 6L4.5 9.5" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/></svg>';
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Data attributes specific to the toggle tool
|
|
44
|
+
*/
|
|
45
|
+
export const TOGGLE_ATTR = {
|
|
46
|
+
toggleOpen: 'data-blok-toggle-open',
|
|
47
|
+
toggleArrow: 'data-blok-toggle-arrow',
|
|
48
|
+
toggleContent: 'data-blok-toggle-content',
|
|
49
|
+
} as const;
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* DOM Builder - Pure functions for DOM creation.
|
|
3
|
+
*
|
|
4
|
+
* These functions are extracted from ToggleItem for testability.
|
|
5
|
+
* They create DOM elements without side effects.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { DATA_ATTR } from '../../components/constants';
|
|
9
|
+
import { twMerge } from '../../components/utils/tw';
|
|
10
|
+
|
|
11
|
+
import {
|
|
12
|
+
ARROW_ICON,
|
|
13
|
+
ARROW_STYLES,
|
|
14
|
+
BASE_STYLES,
|
|
15
|
+
CONTENT_STYLES,
|
|
16
|
+
TOGGLE_ATTR,
|
|
17
|
+
TOGGLE_WRAPPER_STYLES,
|
|
18
|
+
TOOL_NAME,
|
|
19
|
+
} from './constants';
|
|
20
|
+
import type { ToggleItemData } from './types';
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Context object for DOM building operations
|
|
24
|
+
*/
|
|
25
|
+
export interface ToggleDOMBuilderContext {
|
|
26
|
+
/** The toggle item data */
|
|
27
|
+
data: ToggleItemData;
|
|
28
|
+
/** Whether the editor is in read-only mode */
|
|
29
|
+
readOnly: boolean;
|
|
30
|
+
/** Whether the toggle is open (expanded) */
|
|
31
|
+
isOpen: boolean;
|
|
32
|
+
/** Optional keydown event handler */
|
|
33
|
+
keydownHandler: ((event: KeyboardEvent) => void) | null;
|
|
34
|
+
/** Callback when the arrow is clicked */
|
|
35
|
+
onArrowClick: () => void;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Result of building a toggle item element
|
|
40
|
+
*/
|
|
41
|
+
export interface ToggleBuildResult {
|
|
42
|
+
/** The wrapper element */
|
|
43
|
+
wrapper: HTMLElement;
|
|
44
|
+
/** The arrow element for expanding/collapsing */
|
|
45
|
+
arrowElement: HTMLElement;
|
|
46
|
+
/** The content element for text input */
|
|
47
|
+
contentElement: HTMLElement;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Build the complete toggle item DOM structure.
|
|
52
|
+
*
|
|
53
|
+
* @param context - The builder context
|
|
54
|
+
* @returns Object containing the created elements
|
|
55
|
+
*/
|
|
56
|
+
export const buildToggleItem = (context: ToggleDOMBuilderContext): ToggleBuildResult => {
|
|
57
|
+
const { data, readOnly, isOpen, keydownHandler, onArrowClick } = context;
|
|
58
|
+
|
|
59
|
+
const wrapper = document.createElement('div');
|
|
60
|
+
wrapper.className = twMerge(BASE_STYLES, TOGGLE_WRAPPER_STYLES);
|
|
61
|
+
wrapper.setAttribute(DATA_ATTR.tool, TOOL_NAME);
|
|
62
|
+
wrapper.setAttribute(TOGGLE_ATTR.toggleOpen, String(isOpen));
|
|
63
|
+
|
|
64
|
+
const arrowElement = buildArrow(isOpen, onArrowClick);
|
|
65
|
+
const contentElement = buildContent(data, readOnly, keydownHandler);
|
|
66
|
+
|
|
67
|
+
wrapper.appendChild(arrowElement);
|
|
68
|
+
wrapper.appendChild(contentElement);
|
|
69
|
+
|
|
70
|
+
return { wrapper, arrowElement, contentElement };
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Build the arrow element for toggling open/closed state.
|
|
75
|
+
*
|
|
76
|
+
* @param isOpen - Whether the toggle is currently open
|
|
77
|
+
* @param onArrowClick - Callback when arrow is clicked
|
|
78
|
+
* @returns The arrow element
|
|
79
|
+
*/
|
|
80
|
+
const buildArrow = (isOpen: boolean, onArrowClick: () => void): HTMLElement => {
|
|
81
|
+
const arrow = document.createElement('div');
|
|
82
|
+
arrow.className = ARROW_STYLES;
|
|
83
|
+
arrow.setAttribute(TOGGLE_ATTR.toggleArrow, '');
|
|
84
|
+
arrow.setAttribute('role', 'button');
|
|
85
|
+
arrow.setAttribute('tabindex', '-1');
|
|
86
|
+
arrow.setAttribute('aria-label', 'Toggle');
|
|
87
|
+
arrow.innerHTML = ARROW_ICON;
|
|
88
|
+
|
|
89
|
+
if (isOpen) {
|
|
90
|
+
arrow.style.transform = 'rotate(90deg)';
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
arrow.addEventListener('click', (event: MouseEvent) => {
|
|
94
|
+
event.stopPropagation();
|
|
95
|
+
onArrowClick();
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
return arrow;
|
|
99
|
+
};
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* Build the content element for text input.
|
|
103
|
+
*
|
|
104
|
+
* @param data - The toggle item data
|
|
105
|
+
* @param readOnly - Whether the editor is read-only
|
|
106
|
+
* @param keydownHandler - Optional keydown event handler
|
|
107
|
+
* @returns The content element
|
|
108
|
+
*/
|
|
109
|
+
const buildContent = (
|
|
110
|
+
data: ToggleItemData,
|
|
111
|
+
readOnly: boolean,
|
|
112
|
+
keydownHandler: ((event: KeyboardEvent) => void) | null
|
|
113
|
+
): HTMLElement => {
|
|
114
|
+
const content = document.createElement('div');
|
|
115
|
+
content.className = CONTENT_STYLES;
|
|
116
|
+
content.setAttribute(TOGGLE_ATTR.toggleContent, '');
|
|
117
|
+
content.contentEditable = readOnly ? 'false' : 'true';
|
|
118
|
+
content.innerHTML = data.text;
|
|
119
|
+
|
|
120
|
+
if (keydownHandler) {
|
|
121
|
+
content.addEventListener('keydown', keydownHandler);
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
return content;
|
|
125
|
+
};
|