@jackuait/blok 0.6.0-beta.4 → 0.6.0-beta.6
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/README.md +16 -169
- package/bin/blok.mjs +10 -0
- package/dist/blok.mjs +2 -2
- package/dist/chunks/{blok-DK-97ZTf.mjs → blok-BOtlKwVO.mjs} +1486 -1354
- package/dist/chunks/{i18next-loader-CRollibS.mjs → i18next-loader-CJNShSyT.mjs} +1 -1
- package/dist/chunks/{index-jgHmMDND.mjs → index-BUAPAChM.mjs} +1 -1
- package/dist/chunks/{inline-tool-convert-BIwvipPw.mjs → inline-tool-convert-UoYdJJic.mjs} +88 -73
- package/dist/chunks/{messages-C5b7hr_E.mjs → messages-1fC8IMyX.mjs} +16 -2
- package/dist/chunks/{messages-CQj2JU2j.mjs → messages-7QoX8DkW.mjs} +23 -9
- package/dist/{messages-LvFKBBPa.mjs → chunks/messages-7W4d0DwD.mjs} +15 -1
- package/dist/{messages-Bn253WWC.mjs → chunks/messages-9SihnaXQ.mjs} +14 -0
- package/dist/{messages-Bf6Y3_GI.mjs → chunks/messages-B1Aww8q7.mjs} +16 -2
- package/dist/{messages-pA5TvcAj.mjs → chunks/messages-BB5z9Uba.mjs} +14 -0
- package/dist/chunks/{messages-wdqp4610.mjs → messages-BC86qLvI.mjs} +17 -3
- package/dist/chunks/{messages-o24dK6CU.mjs → messages-BELRf6DU.mjs} +16 -2
- package/dist/chunks/{messages-CUZ1x1QD.mjs → messages-BFG6Wlgy.mjs} +16 -2
- package/dist/{messages-B5puUm7R.mjs → chunks/messages-BL0tXcDf.mjs} +15 -1
- package/dist/chunks/{messages-zS1AXZ0y.mjs → messages-BMXCuEKO.mjs} +19 -5
- package/dist/{messages-CyDU5lz9.mjs → chunks/messages-BMv4xwIr.mjs} +16 -2
- package/dist/chunks/{messages-BeUhMpsr.mjs → messages-BSbjsyHY.mjs} +25 -11
- package/dist/chunks/{messages-JGsXAReJ.mjs → messages-BU2nlrLK.mjs} +16 -2
- package/dist/chunks/{messages-srxrv8Yh.mjs → messages-BWF-zUpY.mjs} +17 -3
- package/dist/{messages-CXHd9SUK.mjs → chunks/messages-BYyy6Wqf.mjs} +14 -0
- package/dist/chunks/{messages-DOlC_Tty.mjs → messages-BdeLo0N9.mjs} +24 -10
- package/dist/chunks/{messages-B5jGUnOy.mjs → messages-Bmu_S7GM.mjs} +14 -0
- package/dist/chunks/{messages-BmKCChWZ.mjs → messages-BoJc_p1r.mjs} +14 -0
- package/dist/chunks/{messages-CvaqJFN-.mjs → messages-BogRq8lt.mjs} +15 -1
- package/dist/chunks/{messages-NP1myMGI.mjs → messages-BrPFGbM-.mjs} +14 -0
- package/dist/chunks/{messages-D00OjS2n.mjs → messages-C2htQ_3F.mjs} +24 -10
- package/dist/chunks/{messages-BiExzWJv.mjs → messages-C99mq906.mjs} +15 -1
- package/dist/chunks/{messages-CkFT2gle.mjs → messages-C9eaarcK.mjs} +20 -6
- package/dist/chunks/{messages-BrJHUxQL.mjs → messages-CJdUsQ-c.mjs} +15 -1
- package/dist/chunks/messages-CKI54h6O.mjs +62 -0
- package/dist/{messages-CrsJ1TEJ.mjs → chunks/messages-CLhcMlTc.mjs} +15 -1
- package/dist/{messages-CnvW8Slp.mjs → chunks/messages-CMkNSDTo.mjs} +17 -3
- package/dist/{messages-BlpqL8vG.mjs → chunks/messages-CQwpzUFp.mjs} +19 -5
- package/dist/chunks/{messages-Cu08aLS3.mjs → messages-CVw84KdI.mjs} +21 -7
- package/dist/chunks/{messages-B9Oba7sq.mjs → messages-CY8_RyFE.mjs} +15 -1
- package/dist/chunks/{messages-B5hdXZwA.mjs → messages-CZygwLwM.mjs} +15 -1
- package/dist/chunks/{messages-CVeWVKsV.mjs → messages-CnwibSvh.mjs} +14 -0
- package/dist/chunks/{messages-DbVquYKN.mjs → messages-CqWJcCbY.mjs} +14 -0
- package/dist/{messages-Dg92dXZ5.mjs → chunks/messages-CvGLfqmV.mjs} +14 -0
- package/dist/{messages-AHESHJm_.mjs → chunks/messages-CzTufCHu.mjs} +14 -0
- package/dist/chunks/{messages-Cj-t1bdy.mjs → messages-CznZadDf.mjs} +15 -1
- package/dist/chunks/{messages-DMQIHGRj.mjs → messages-D-ZtY5v0.mjs} +14 -0
- package/dist/chunks/{messages-rRSHQDCX.mjs → messages-D1Hv8XGo.mjs} +14 -0
- package/dist/chunks/{messages-0tDXLuyH.mjs → messages-D5C3J9qr.mjs} +15 -1
- package/dist/chunks/{messages-RvMHb2Ht.mjs → messages-D5iv1Kox.mjs} +16 -2
- package/dist/{messages-zSzDzXej.mjs → chunks/messages-DBRw-7Zc.mjs} +16 -2
- package/dist/chunks/{messages-CeCjVKMW.mjs → messages-DBn76jVV.mjs} +16 -2
- package/dist/chunks/{messages-C7I_AVH2.mjs → messages-DJDG55Vq.mjs} +16 -2
- package/dist/{messages-DDLgIPDF.mjs → chunks/messages-DLfR5bMd.mjs} +16 -2
- package/dist/{messages-CbhuIWRJ.mjs → chunks/messages-DT4dP5uK.mjs} +15 -1
- package/dist/chunks/{messages-B66ZSDCJ.mjs → messages-DhLKYm2j.mjs} +15 -1
- package/dist/{messages-BPqWKx5Z.mjs → chunks/messages-Diu6jAaR.mjs} +17 -3
- package/dist/{messages-BA0rcTCY.mjs → chunks/messages-DnIhyAJk.mjs} +18 -4
- package/dist/chunks/{messages-DV6shA9b.mjs → messages-DnXLrlHh.mjs} +14 -0
- package/dist/chunks/{messages-DcKOuncK.mjs → messages-DprmQg6V.mjs} +16 -2
- package/dist/{messages-CJoBtXU6.mjs → chunks/messages-DqM1LFg5.mjs} +14 -0
- package/dist/chunks/{messages-Cyi2AMmz.mjs → messages-DvFLX36Q.mjs} +25 -11
- package/dist/chunks/{messages-DnbbyJT3.mjs → messages-Dz9L52ol.mjs} +16 -2
- package/dist/chunks/{messages-GC2PhgV3.mjs → messages-Dzwxv9v1.mjs} +23 -9
- package/dist/chunks/{messages-Q4kc_ZtL.mjs → messages-JELdtT6E.mjs} +15 -1
- package/dist/{messages-DY94ykcE.mjs → chunks/messages-LPVfA-8K.mjs} +14 -0
- package/dist/{messages-Cr-RJ7YB.mjs → chunks/messages-O5tQus_0.mjs} +14 -0
- package/dist/chunks/{messages-CbMyJSzS.mjs → messages-Q7AO_FLv.mjs} +17 -3
- package/dist/chunks/{messages-2_xedlYw.mjs → messages-R3hUSvr3.mjs} +15 -1
- package/dist/{messages-CUy1vn-b.mjs → chunks/messages-Xq8UmkVs.mjs} +14 -0
- package/dist/chunks/{messages-BBJgd5jG.mjs → messages-Z9nEU2xK.mjs} +16 -2
- package/dist/chunks/{messages-Cm9aLHeX.mjs → messages-_ErNTNhk.mjs} +15 -1
- package/dist/chunks/{messages-JZUhXTuV.mjs → messages-_ncGrKHh.mjs} +16 -2
- package/dist/chunks/{messages-ftMcCEuO.mjs → messages-kep5wtm4.mjs} +15 -1
- package/dist/chunks/{messages-DteYq0rv.mjs → messages-uKX8WBaD.mjs} +16 -2
- package/dist/chunks/{messages-Bdv-IkfG.mjs → messages-w7v1GNaE.mjs} +15 -1
- package/dist/cli.mjs +50 -0
- package/dist/full.mjs +15 -15
- package/dist/locales.mjs +102 -88
- package/dist/{messages-C5b7hr_E.mjs → messages-1fC8IMyX.mjs} +16 -2
- package/dist/{messages-CQj2JU2j.mjs → messages-7QoX8DkW.mjs} +23 -9
- package/dist/{chunks/messages-LvFKBBPa.mjs → messages-7W4d0DwD.mjs} +15 -1
- package/dist/{chunks/messages-Bn253WWC.mjs → messages-9SihnaXQ.mjs} +14 -0
- package/dist/{chunks/messages-Bf6Y3_GI.mjs → messages-B1Aww8q7.mjs} +16 -2
- package/dist/{chunks/messages-pA5TvcAj.mjs → messages-BB5z9Uba.mjs} +14 -0
- package/dist/{messages-wdqp4610.mjs → messages-BC86qLvI.mjs} +17 -3
- package/dist/{messages-o24dK6CU.mjs → messages-BELRf6DU.mjs} +16 -2
- package/dist/{messages-CUZ1x1QD.mjs → messages-BFG6Wlgy.mjs} +16 -2
- package/dist/{chunks/messages-B5puUm7R.mjs → messages-BL0tXcDf.mjs} +15 -1
- package/dist/{messages-zS1AXZ0y.mjs → messages-BMXCuEKO.mjs} +19 -5
- package/dist/{chunks/messages-CyDU5lz9.mjs → messages-BMv4xwIr.mjs} +16 -2
- package/dist/{messages-BeUhMpsr.mjs → messages-BSbjsyHY.mjs} +25 -11
- package/dist/{messages-JGsXAReJ.mjs → messages-BU2nlrLK.mjs} +16 -2
- package/dist/{messages-srxrv8Yh.mjs → messages-BWF-zUpY.mjs} +17 -3
- package/dist/{chunks/messages-CXHd9SUK.mjs → messages-BYyy6Wqf.mjs} +14 -0
- package/dist/{messages-DOlC_Tty.mjs → messages-BdeLo0N9.mjs} +24 -10
- package/dist/{messages-B5jGUnOy.mjs → messages-Bmu_S7GM.mjs} +14 -0
- package/dist/{messages-BmKCChWZ.mjs → messages-BoJc_p1r.mjs} +14 -0
- package/dist/{messages-CvaqJFN-.mjs → messages-BogRq8lt.mjs} +15 -1
- package/dist/{messages-NP1myMGI.mjs → messages-BrPFGbM-.mjs} +14 -0
- package/dist/{messages-D00OjS2n.mjs → messages-C2htQ_3F.mjs} +24 -10
- package/dist/{messages-BiExzWJv.mjs → messages-C99mq906.mjs} +15 -1
- package/dist/{messages-CkFT2gle.mjs → messages-C9eaarcK.mjs} +20 -6
- package/dist/{messages-BrJHUxQL.mjs → messages-CJdUsQ-c.mjs} +15 -1
- package/dist/messages-CKI54h6O.mjs +62 -0
- package/dist/{chunks/messages-CrsJ1TEJ.mjs → messages-CLhcMlTc.mjs} +15 -1
- package/dist/{chunks/messages-CnvW8Slp.mjs → messages-CMkNSDTo.mjs} +17 -3
- package/dist/{chunks/messages-BlpqL8vG.mjs → messages-CQwpzUFp.mjs} +19 -5
- package/dist/{messages-Cu08aLS3.mjs → messages-CVw84KdI.mjs} +21 -7
- package/dist/{messages-B9Oba7sq.mjs → messages-CY8_RyFE.mjs} +15 -1
- package/dist/{messages-B5hdXZwA.mjs → messages-CZygwLwM.mjs} +15 -1
- package/dist/{messages-CVeWVKsV.mjs → messages-CnwibSvh.mjs} +14 -0
- package/dist/{messages-DbVquYKN.mjs → messages-CqWJcCbY.mjs} +14 -0
- package/dist/{chunks/messages-Dg92dXZ5.mjs → messages-CvGLfqmV.mjs} +14 -0
- package/dist/{chunks/messages-AHESHJm_.mjs → messages-CzTufCHu.mjs} +14 -0
- package/dist/{messages-Cj-t1bdy.mjs → messages-CznZadDf.mjs} +15 -1
- package/dist/{messages-DMQIHGRj.mjs → messages-D-ZtY5v0.mjs} +14 -0
- package/dist/{messages-rRSHQDCX.mjs → messages-D1Hv8XGo.mjs} +14 -0
- package/dist/{messages-0tDXLuyH.mjs → messages-D5C3J9qr.mjs} +15 -1
- package/dist/{messages-RvMHb2Ht.mjs → messages-D5iv1Kox.mjs} +16 -2
- package/dist/{chunks/messages-zSzDzXej.mjs → messages-DBRw-7Zc.mjs} +16 -2
- package/dist/{messages-CeCjVKMW.mjs → messages-DBn76jVV.mjs} +16 -2
- package/dist/{messages-C7I_AVH2.mjs → messages-DJDG55Vq.mjs} +16 -2
- package/dist/{chunks/messages-DDLgIPDF.mjs → messages-DLfR5bMd.mjs} +16 -2
- package/dist/{chunks/messages-CbhuIWRJ.mjs → messages-DT4dP5uK.mjs} +15 -1
- package/dist/{messages-B66ZSDCJ.mjs → messages-DhLKYm2j.mjs} +15 -1
- package/dist/{chunks/messages-BPqWKx5Z.mjs → messages-Diu6jAaR.mjs} +17 -3
- package/dist/{chunks/messages-BA0rcTCY.mjs → messages-DnIhyAJk.mjs} +18 -4
- package/dist/{messages-DV6shA9b.mjs → messages-DnXLrlHh.mjs} +14 -0
- package/dist/{messages-DcKOuncK.mjs → messages-DprmQg6V.mjs} +16 -2
- package/dist/{chunks/messages-CJoBtXU6.mjs → messages-DqM1LFg5.mjs} +14 -0
- package/dist/{messages-Cyi2AMmz.mjs → messages-DvFLX36Q.mjs} +25 -11
- package/dist/{messages-DnbbyJT3.mjs → messages-Dz9L52ol.mjs} +16 -2
- package/dist/{messages-GC2PhgV3.mjs → messages-Dzwxv9v1.mjs} +23 -9
- package/dist/{messages-Q4kc_ZtL.mjs → messages-JELdtT6E.mjs} +15 -1
- package/dist/{chunks/messages-DY94ykcE.mjs → messages-LPVfA-8K.mjs} +14 -0
- package/dist/{chunks/messages-Cr-RJ7YB.mjs → messages-O5tQus_0.mjs} +14 -0
- package/dist/{messages-CbMyJSzS.mjs → messages-Q7AO_FLv.mjs} +17 -3
- package/dist/{messages-2_xedlYw.mjs → messages-R3hUSvr3.mjs} +15 -1
- package/dist/{chunks/messages-CUy1vn-b.mjs → messages-Xq8UmkVs.mjs} +14 -0
- package/dist/{messages-BBJgd5jG.mjs → messages-Z9nEU2xK.mjs} +16 -2
- package/dist/{messages-Cm9aLHeX.mjs → messages-_ErNTNhk.mjs} +15 -1
- package/dist/{messages-JZUhXTuV.mjs → messages-_ncGrKHh.mjs} +16 -2
- package/dist/{messages-ftMcCEuO.mjs → messages-kep5wtm4.mjs} +15 -1
- package/dist/{messages-DteYq0rv.mjs → messages-uKX8WBaD.mjs} +16 -2
- package/dist/{messages-Bdv-IkfG.mjs → messages-w7v1GNaE.mjs} +15 -1
- package/dist/tools.mjs +929 -779
- package/dist/vendor.LICENSE.txt +1 -1
- package/package.json +15 -14
- package/src/cli/commands/migration.ts +16 -0
- package/src/cli/commands/migrationContent.ts +6 -0
- package/src/cli/index.ts +47 -0
- package/src/cli/utils/output.ts +10 -0
- package/src/components/i18n/locales/am/messages.json +15 -1
- package/src/components/i18n/locales/ar/messages.json +14 -0
- package/src/components/i18n/locales/az/messages.json +14 -0
- package/src/components/i18n/locales/bg/messages.json +14 -0
- package/src/components/i18n/locales/bn/messages.json +25 -11
- package/src/components/i18n/locales/bs/messages.json +15 -1
- package/src/components/i18n/locales/cs/messages.json +14 -0
- package/src/components/i18n/locales/da/messages.json +14 -0
- package/src/components/i18n/locales/de/messages.json +14 -0
- package/src/components/i18n/locales/dv/messages.json +15 -1
- package/src/components/i18n/locales/el/messages.json +15 -1
- package/src/components/i18n/locales/en/messages.json +14 -0
- package/src/components/i18n/locales/es/messages.json +14 -0
- package/src/components/i18n/locales/et/messages.json +14 -0
- package/src/components/i18n/locales/fa/messages.json +15 -1
- package/src/components/i18n/locales/fi/messages.json +15 -1
- package/src/components/i18n/locales/fil/messages.json +20 -6
- package/src/components/i18n/locales/fr/messages.json +15 -1
- package/src/components/i18n/locales/gu/messages.json +15 -1
- package/src/components/i18n/locales/he/messages.json +14 -0
- package/src/components/i18n/locales/hi/messages.json +23 -9
- package/src/components/i18n/locales/hr/messages.json +14 -0
- package/src/components/i18n/locales/hu/messages.json +14 -0
- package/src/components/i18n/locales/hy/messages.json +16 -2
- package/src/components/i18n/locales/id/messages.json +19 -5
- package/src/components/i18n/locales/it/messages.json +14 -0
- package/src/components/i18n/locales/ja/messages.json +14 -0
- package/src/components/i18n/locales/ka/messages.json +15 -1
- package/src/components/i18n/locales/km/messages.json +16 -2
- package/src/components/i18n/locales/kn/messages.json +16 -2
- package/src/components/i18n/locales/ko/messages.json +14 -0
- package/src/components/i18n/locales/ku/messages.json +16 -2
- package/src/components/i18n/locales/lo/messages.json +15 -1
- package/src/components/i18n/locales/lt/messages.json +15 -1
- package/src/components/i18n/locales/lv/messages.json +15 -1
- package/src/components/i18n/locales/mk/messages.json +16 -2
- package/src/components/i18n/locales/ml/messages.json +16 -2
- package/src/components/i18n/locales/mn/messages.json +16 -2
- package/src/components/i18n/locales/mr/messages.json +24 -10
- package/src/components/i18n/locales/ms/messages.json +17 -3
- package/src/components/i18n/locales/my/messages.json +16 -2
- package/src/components/i18n/locales/ne/messages.json +24 -10
- package/src/components/i18n/locales/nl/messages.json +15 -1
- package/src/components/i18n/locales/no/messages.json +16 -2
- package/src/components/i18n/locales/pa/messages.json +15 -1
- package/src/components/i18n/locales/pl/messages.json +14 -0
- package/src/components/i18n/locales/ps/messages.json +17 -3
- package/src/components/i18n/locales/pt/messages.json +14 -0
- package/src/components/i18n/locales/ro/messages.json +15 -1
- package/src/components/i18n/locales/ru/messages.json +14 -0
- package/src/components/i18n/locales/sd/messages.json +16 -2
- package/src/components/i18n/locales/si/messages.json +23 -9
- package/src/components/i18n/locales/sk/messages.json +15 -1
- package/src/components/i18n/locales/sl/messages.json +16 -2
- package/src/components/i18n/locales/sq/messages.json +16 -2
- package/src/components/i18n/locales/sr/messages.json +16 -2
- package/src/components/i18n/locales/sv/messages.json +16 -2
- package/src/components/i18n/locales/sw/messages.json +16 -2
- package/src/components/i18n/locales/ta/messages.json +21 -7
- package/src/components/i18n/locales/te/messages.json +40 -26
- package/src/components/i18n/locales/th/messages.json +19 -5
- package/src/components/i18n/locales/tr/messages.json +15 -1
- package/src/components/i18n/locales/ug/messages.json +16 -2
- package/src/components/i18n/locales/uk/messages.json +15 -1
- package/src/components/i18n/locales/ur/messages.json +15 -1
- package/src/components/i18n/locales/vi/messages.json +25 -11
- package/src/components/i18n/locales/yi/messages.json +16 -2
- package/src/components/i18n/locales/zh/messages.json +15 -1
- package/src/components/modules/api/blocks.ts +17 -2
- package/src/components/modules/api/history.ts +64 -0
- package/src/components/modules/api/index.ts +1 -0
- package/src/components/modules/api/readonly.ts +11 -1
- package/src/components/modules/blockEvents/composers/markdownShortcuts.ts +12 -1
- package/src/components/modules/blockManager/blockManager.ts +7 -0
- package/src/components/modules/blockManager/yjs-sync.ts +12 -2
- package/src/components/modules/index.ts +3 -0
- package/src/components/modules/readonly.ts +11 -0
- package/src/components/modules/toolbar/index.ts +29 -7
- package/src/components/modules/ui.ts +46 -68
- package/src/components/modules/uiControllers/controllers/blockHover.ts +40 -61
- package/src/components/modules/yjs/index.ts +23 -0
- package/src/components/ui/toolbox.ts +41 -6
- package/src/components/utils/popover/components/popover-item/popover-item-default/popover-item-default.ts +3 -1
- package/src/components/utils/popover/popover-desktop.ts +27 -8
- package/src/tools/table/index.ts +87 -70
- package/src/tools/table/table-add-controls.ts +33 -7
- package/src/tools/table/table-cell-blocks.ts +77 -5
- package/src/tools/table/table-cell-selection.ts +70 -46
- package/src/tools/table/table-core.ts +20 -15
- package/src/tools/table/table-grip-visuals.ts +4 -4
- package/src/tools/table/table-operations.ts +22 -12
- package/src/tools/table/table-restrictions.ts +64 -0
- package/src/tools/table/table-row-col-action-handler.ts +190 -0
- package/src/tools/table/table-row-col-controls.ts +91 -182
- package/src/tools/table/table-row-col-drag.ts +4 -4
- package/src/tools/table/table-row-col-popover.ts +225 -0
- package/src/tools/table/types.ts +2 -0
- package/src/types-internal/blok-modules.d.ts +2 -0
- package/types/api/history.d.ts +33 -0
- package/types/api/index.d.ts +1 -0
- package/types/api/readonly.d.ts +12 -2
- package/types/index.d.ts +3 -0
- package/types/utils/popover/popover.d.ts +7 -0
- package/dist/chunks/messages-CySyfkMU.mjs +0 -48
- package/dist/messages-CySyfkMU.mjs +0 -48
|
@@ -12,9 +12,10 @@ export class ReadOnlyAPI extends Module {
|
|
|
12
12
|
public get methods(): ReadOnly {
|
|
13
13
|
const getIsEnabled = (): boolean => this.isEnabled;
|
|
14
14
|
|
|
15
|
-
|
|
15
|
+
|
|
16
16
|
return {
|
|
17
17
|
toggle: (state): Promise<boolean> => this.toggle(state),
|
|
18
|
+
set: (state): Promise<boolean> => this.set(state),
|
|
18
19
|
get isEnabled(): boolean {
|
|
19
20
|
return getIsEnabled();
|
|
20
21
|
},
|
|
@@ -30,6 +31,15 @@ export class ReadOnlyAPI extends Module {
|
|
|
30
31
|
return this.Blok.ReadOnly.toggle(state);
|
|
31
32
|
}
|
|
32
33
|
|
|
34
|
+
/**
|
|
35
|
+
* Set read-only mode to the specified boolean state
|
|
36
|
+
* @param {boolean} state - read-only state to set
|
|
37
|
+
* @returns {Promise<boolean>} the new read-only state
|
|
38
|
+
*/
|
|
39
|
+
public set(state: boolean): Promise<boolean> {
|
|
40
|
+
return this.Blok.ReadOnly.set(state);
|
|
41
|
+
}
|
|
42
|
+
|
|
33
43
|
/**
|
|
34
44
|
* Returns current read-only state
|
|
35
45
|
*/
|
|
@@ -153,7 +153,18 @@ export class MarkdownShortcuts extends BlockEventComposer {
|
|
|
153
153
|
const { BlockManager, Tools } = this.Blok;
|
|
154
154
|
const currentBlock = BlockManager.currentBlock;
|
|
155
155
|
|
|
156
|
-
if (!currentBlock
|
|
156
|
+
if (!currentBlock) {
|
|
157
|
+
return false;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
// Check if inside table cell
|
|
161
|
+
const isInsideTableCell = currentBlock.holder.closest('[data-blok-table-cell-blocks]') !== null;
|
|
162
|
+
|
|
163
|
+
if (isInsideTableCell) {
|
|
164
|
+
return false; // Don't convert to header
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
if (!currentBlock.tool.isDefault) {
|
|
157
168
|
return false;
|
|
158
169
|
}
|
|
159
170
|
|
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
import type { BlockToolData, OutputBlockData, PasteEvent } from '../../../../types';
|
|
8
8
|
import type { BlockTuneData } from '../../../../types/block-tunes/block-tune-data';
|
|
9
9
|
import type { BlockMutationEventMap, BlockMutationType } from '../../../../types/events/block';
|
|
10
|
+
import { BlockAddedMutationType } from '../../../../types/events/block/BlockAdded';
|
|
10
11
|
import { BlockChangedMutationType } from '../../../../types/events/block/BlockChanged';
|
|
11
12
|
import { BlockRemovedMutationType } from '../../../../types/events/block/BlockRemoved';
|
|
12
13
|
import { Module } from '../../__module';
|
|
@@ -307,6 +308,12 @@ export class BlockManager extends Module {
|
|
|
307
308
|
replaceBlock: (index, newBlock) => {
|
|
308
309
|
this.blocksStore.replace(index, newBlock);
|
|
309
310
|
},
|
|
311
|
+
onBlockRemoved: (block, index) => {
|
|
312
|
+
this.blockDidMutated(BlockRemovedMutationType, block, { index });
|
|
313
|
+
},
|
|
314
|
+
onBlockAdded: (block, index) => {
|
|
315
|
+
this.blockDidMutated(BlockAddedMutationType, block, { index });
|
|
316
|
+
},
|
|
310
317
|
},
|
|
311
318
|
this.blocksStore
|
|
312
319
|
);
|
|
@@ -43,6 +43,10 @@ export interface SyncHandlers {
|
|
|
43
43
|
updateIndentation: (block: Block) => void;
|
|
44
44
|
/** Called to replace a block at a specific index with a new block instance */
|
|
45
45
|
replaceBlock: (index: number, newBlock: Block) => void;
|
|
46
|
+
/** Called when a block is removed during undo/redo (before DOM removal) */
|
|
47
|
+
onBlockRemoved: (block: Block, index: number) => void;
|
|
48
|
+
/** Called when a block is added during undo/redo (after insertion) */
|
|
49
|
+
onBlockAdded: (block: Block, index: number) => void;
|
|
46
50
|
}
|
|
47
51
|
|
|
48
52
|
/**
|
|
@@ -273,10 +277,12 @@ export class BlockYjsSync {
|
|
|
273
277
|
bindEventsImmediately: true,
|
|
274
278
|
});
|
|
275
279
|
|
|
276
|
-
// Insert into blocks store at correct position - caller must handle this
|
|
277
|
-
// This is a limitation - we need the blocksStore.insert method
|
|
278
280
|
this.blocksStore.insert(targetIndex, block);
|
|
279
281
|
|
|
282
|
+
// Emit block-added event so listeners (e.g., TableCellBlocks) can
|
|
283
|
+
// claim the block for the correct cell during undo/redo
|
|
284
|
+
this.handlers.onBlockAdded(block, targetIndex);
|
|
285
|
+
|
|
280
286
|
// Apply indentation if needed
|
|
281
287
|
if (parentId !== undefined) {
|
|
282
288
|
this.handlers.updateIndentation(block);
|
|
@@ -300,6 +306,10 @@ export class BlockYjsSync {
|
|
|
300
306
|
return;
|
|
301
307
|
}
|
|
302
308
|
|
|
309
|
+
// Emit block-removed event BEFORE removal so listeners can inspect
|
|
310
|
+
// the block's DOM position (e.g., which table cell it's in)
|
|
311
|
+
this.handlers.onBlockRemoved(block, index);
|
|
312
|
+
|
|
303
313
|
// Remove from DOM
|
|
304
314
|
this.blocksStore.remove(index);
|
|
305
315
|
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { BlocksAPI } from './api/blocks';
|
|
2
2
|
import { CaretAPI } from './api/caret';
|
|
3
3
|
import { EventsAPI } from './api/events';
|
|
4
|
+
import { HistoryAPI } from './api/history';
|
|
4
5
|
import { I18nAPI } from './api/i18n';
|
|
5
6
|
import { API } from './api/index';
|
|
6
7
|
import { InlineToolbarAPI } from './api/inlineToolbar';
|
|
@@ -44,6 +45,7 @@ export {
|
|
|
44
45
|
BlocksAPI,
|
|
45
46
|
CaretAPI,
|
|
46
47
|
EventsAPI,
|
|
48
|
+
HistoryAPI,
|
|
47
49
|
I18nAPI,
|
|
48
50
|
API,
|
|
49
51
|
InlineToolbarAPI,
|
|
@@ -91,6 +93,7 @@ export const Modules = {
|
|
|
91
93
|
BlocksAPI,
|
|
92
94
|
CaretAPI,
|
|
93
95
|
EventsAPI,
|
|
96
|
+
HistoryAPI,
|
|
94
97
|
I18nAPI,
|
|
95
98
|
API,
|
|
96
99
|
InlineToolbarAPI,
|
|
@@ -125,6 +125,17 @@ export class ReadOnly extends Module {
|
|
|
125
125
|
return this.readOnlyEnabled;
|
|
126
126
|
}
|
|
127
127
|
|
|
128
|
+
/**
|
|
129
|
+
* Set read-only mode to the specified boolean state
|
|
130
|
+
* Unlike toggle(), this method requires a parameter and does not have default toggle behavior
|
|
131
|
+
* Call all Modules `toggleReadOnly` method and re-render Blok
|
|
132
|
+
* @param state - read-only state to set (required)
|
|
133
|
+
* @returns the new read-only state
|
|
134
|
+
*/
|
|
135
|
+
public async set(state: boolean): Promise<boolean> {
|
|
136
|
+
return this.toggle(state);
|
|
137
|
+
}
|
|
138
|
+
|
|
128
139
|
/**
|
|
129
140
|
* Throws an error about tools which don't support read-only mode
|
|
130
141
|
*/
|
|
@@ -320,17 +320,15 @@ export class Toolbar extends Module<ToolbarNodes> {
|
|
|
320
320
|
/**
|
|
321
321
|
* If no one Block selected as a Current
|
|
322
322
|
*/
|
|
323
|
-
const
|
|
323
|
+
const unresolvedBlock = block ?? this.Blok.BlockManager.currentBlock;
|
|
324
324
|
|
|
325
|
-
if (!
|
|
325
|
+
if (!unresolvedBlock) {
|
|
326
326
|
return;
|
|
327
327
|
}
|
|
328
328
|
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
*/
|
|
333
|
-
if (targetBlock.holder.closest('[data-blok-table-cell-blocks]')) {
|
|
329
|
+
const targetBlock = this.resolveTableCellBlock(unresolvedBlock);
|
|
330
|
+
|
|
331
|
+
if (!targetBlock) {
|
|
334
332
|
this.close();
|
|
335
333
|
|
|
336
334
|
return;
|
|
@@ -562,6 +560,30 @@ export class Toolbar extends Module<ToolbarNodes> {
|
|
|
562
560
|
this.explicitlyClosed = false;
|
|
563
561
|
}
|
|
564
562
|
|
|
563
|
+
/**
|
|
564
|
+
* If the block is inside a table cell, resolve to the parent table block.
|
|
565
|
+
* This ensures the toolbar shows for the table when clicking/focusing inside cells.
|
|
566
|
+
* Uses the DOM attribute directly to avoid cross-module dependency on the table tool.
|
|
567
|
+
*
|
|
568
|
+
* @param block - the block to resolve
|
|
569
|
+
* @returns the parent table block if inside a cell, the original block otherwise, or null if resolution fails
|
|
570
|
+
*/
|
|
571
|
+
private resolveTableCellBlock(block: Block): Block | null {
|
|
572
|
+
const cellBlocksContainer = block.holder.closest('[data-blok-table-cell-blocks]');
|
|
573
|
+
|
|
574
|
+
if (!cellBlocksContainer) {
|
|
575
|
+
return block;
|
|
576
|
+
}
|
|
577
|
+
|
|
578
|
+
const tableBlockHolder = cellBlocksContainer.closest('[data-blok-testid="block-wrapper"]');
|
|
579
|
+
|
|
580
|
+
if (!tableBlockHolder) {
|
|
581
|
+
return null;
|
|
582
|
+
}
|
|
583
|
+
|
|
584
|
+
return this.Blok.BlockManager.getBlockByChildNode(tableBlockHolder) ?? null;
|
|
585
|
+
}
|
|
586
|
+
|
|
565
587
|
/**
|
|
566
588
|
* Reset the Toolbar position to prevent DOM height growth, for example after blocks deletion
|
|
567
589
|
*/
|
|
@@ -30,6 +30,7 @@ interface UINodes extends Record<string, unknown> {
|
|
|
30
30
|
holder: HTMLElement;
|
|
31
31
|
wrapper: HTMLElement;
|
|
32
32
|
redactor: HTMLElement;
|
|
33
|
+
bottomZone: HTMLElement;
|
|
33
34
|
}
|
|
34
35
|
|
|
35
36
|
/**
|
|
@@ -191,12 +192,11 @@ export class UI extends Module<UINodes> {
|
|
|
191
192
|
this.selectionController.setWrapperElement(this.nodes.wrapper);
|
|
192
193
|
|
|
193
194
|
/**
|
|
194
|
-
* Block hover controller
|
|
195
|
+
* Block hover controller detects hover over blocks and finds nearest block
|
|
195
196
|
*/
|
|
196
197
|
this.blockHoverController = new BlockHoverController({
|
|
197
198
|
config: this.config,
|
|
198
199
|
eventsDispatcher: this.eventsDispatcher,
|
|
199
|
-
contentRectGetter: () => this.contentRect,
|
|
200
200
|
});
|
|
201
201
|
this.blockHoverController.state = this.Blok;
|
|
202
202
|
|
|
@@ -452,11 +452,15 @@ export class UI extends Module<UINodes> {
|
|
|
452
452
|
}
|
|
453
453
|
|
|
454
454
|
/**
|
|
455
|
-
*
|
|
455
|
+
* Create dedicated bottom zone element
|
|
456
456
|
*/
|
|
457
|
-
this.nodes.
|
|
457
|
+
this.nodes.bottomZone = $.make('div', ['cursor-text']);
|
|
458
|
+
this.nodes.bottomZone.setAttribute('data-blok-bottom-zone', '');
|
|
459
|
+
this.nodes.bottomZone.setAttribute('data-blok-testid', 'bottom-zone');
|
|
460
|
+
this.nodes.bottomZone.style.minHeight = this.config.minHeight + 'px';
|
|
458
461
|
|
|
459
462
|
this.nodes.wrapper.appendChild(this.nodes.redactor);
|
|
463
|
+
this.nodes.wrapper.appendChild(this.nodes.bottomZone);
|
|
460
464
|
this.nodes.holder.appendChild(this.nodes.wrapper);
|
|
461
465
|
|
|
462
466
|
this.bindReadOnlyInsensitiveListeners();
|
|
@@ -541,7 +545,16 @@ export class UI extends Module<UINodes> {
|
|
|
541
545
|
*/
|
|
542
546
|
private bindReadOnlySensitiveListeners(): void {
|
|
543
547
|
/**
|
|
544
|
-
*
|
|
548
|
+
* Bottom zone click handler — creates new block when clicking below last block
|
|
549
|
+
*/
|
|
550
|
+
this.readOnlyMutableListeners.on(this.nodes.bottomZone, 'click', (event: Event) => {
|
|
551
|
+
if (event instanceof MouseEvent) {
|
|
552
|
+
this.bottomZoneClicked(event);
|
|
553
|
+
}
|
|
554
|
+
}, false);
|
|
555
|
+
|
|
556
|
+
/**
|
|
557
|
+
* Redactor click handler for Ctrl+click anchor navigation
|
|
545
558
|
*/
|
|
546
559
|
this.readOnlyMutableListeners.on(this.nodes.redactor, 'click', (event: Event) => {
|
|
547
560
|
if (event instanceof MouseEvent) {
|
|
@@ -610,98 +623,63 @@ export class UI extends Module<UINodes> {
|
|
|
610
623
|
}
|
|
611
624
|
|
|
612
625
|
/**
|
|
613
|
-
*
|
|
614
|
-
*
|
|
615
|
-
* @description
|
|
616
|
-
* - By clicks on the Blok's bottom zone:
|
|
617
|
-
* - if last Block is empty, set a Caret to this
|
|
618
|
-
* - otherwise, add a new empty Block and set a Caret to that
|
|
626
|
+
* Handle click on the bottom zone element below the last block.
|
|
627
|
+
* Creates a new default block if needed, focuses the last block, and opens the toolbar.
|
|
619
628
|
*/
|
|
620
|
-
private
|
|
629
|
+
private bottomZoneClicked(event: MouseEvent): void {
|
|
621
630
|
if (!Selection.isCollapsed) {
|
|
622
631
|
return;
|
|
623
632
|
}
|
|
624
633
|
|
|
625
|
-
|
|
626
|
-
* case when user clicks on anchor element
|
|
627
|
-
* if it is clicked via ctrl key, then we open new window with url
|
|
628
|
-
*/
|
|
629
|
-
const element = event.target as Element;
|
|
630
|
-
const ctrlKey = event.metaKey || event.ctrlKey;
|
|
631
|
-
const shouldOpenAnchorInNewTab = $.isAnchor(element) && ctrlKey;
|
|
634
|
+
const { BlockSelection, BlockManager, Caret, Toolbar } = this.Blok;
|
|
632
635
|
|
|
633
|
-
if (
|
|
634
|
-
|
|
636
|
+
if (BlockSelection.anyBlockSelected) {
|
|
637
|
+
return;
|
|
638
|
+
}
|
|
635
639
|
|
|
640
|
+
if (!BlockManager.lastBlock) {
|
|
636
641
|
return;
|
|
637
642
|
}
|
|
638
643
|
|
|
639
644
|
event.stopImmediatePropagation();
|
|
640
645
|
event.stopPropagation();
|
|
641
646
|
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
647
|
+
/**
|
|
648
|
+
* Insert a default-block at the bottom if:
|
|
649
|
+
* - last-block is not a default-block (Text)
|
|
650
|
+
* - Or, default-block is not empty
|
|
651
|
+
*/
|
|
652
|
+
if (!BlockManager.lastBlock.tool.isDefault || !BlockManager.lastBlock.isEmpty) {
|
|
653
|
+
BlockManager.insertAtEnd();
|
|
646
654
|
}
|
|
647
655
|
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
openTab(validUrl);
|
|
656
|
+
Caret.setToTheLastBlock();
|
|
657
|
+
Toolbar.moveAndOpen(BlockManager.lastBlock);
|
|
651
658
|
}
|
|
652
659
|
|
|
653
660
|
/**
|
|
654
|
-
*
|
|
655
|
-
* - set caret to the last block
|
|
656
|
-
* - or add new empty block
|
|
657
|
-
* @param event - click event
|
|
661
|
+
* Handle Ctrl+click on anchor elements to open in new tab
|
|
658
662
|
*/
|
|
659
|
-
private
|
|
660
|
-
const
|
|
661
|
-
|
|
662
|
-
if (lastBlock === undefined) {
|
|
663
|
-
return;
|
|
664
|
-
}
|
|
665
|
-
|
|
666
|
-
const lastBlockBottomCoord = $.offset(lastBlock.holder).bottom;
|
|
667
|
-
const clickedCoord = event.pageY;
|
|
668
|
-
const { BlockSelection } = this.Blok;
|
|
669
|
-
const isClickedBottom = event.target instanceof Element &&
|
|
670
|
-
event.target.isEqualNode(this.nodes.redactor) &&
|
|
671
|
-
/**
|
|
672
|
-
* If there is cross block selection started, target will be equal to redactor so we need additional check
|
|
673
|
-
*/
|
|
674
|
-
!BlockSelection.anyBlockSelected &&
|
|
675
|
-
|
|
676
|
-
/**
|
|
677
|
-
* Prevent caret jumping (to last block) when clicking between blocks
|
|
678
|
-
*/
|
|
679
|
-
lastBlockBottomCoord < clickedCoord;
|
|
663
|
+
private redactorClicked(event: MouseEvent): void {
|
|
664
|
+
const element = event.target as Element;
|
|
665
|
+
const ctrlKey = event.metaKey || event.ctrlKey;
|
|
680
666
|
|
|
681
|
-
if (!
|
|
667
|
+
if (!$.isAnchor(element) || !ctrlKey) {
|
|
682
668
|
return;
|
|
683
669
|
}
|
|
684
670
|
|
|
685
671
|
event.stopImmediatePropagation();
|
|
686
672
|
event.stopPropagation();
|
|
687
673
|
|
|
688
|
-
const
|
|
674
|
+
const href = element.getAttribute('href');
|
|
689
675
|
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
* - last-block is not a default-block (Text)
|
|
693
|
-
* to prevent unnecessary tree-walking on Tools with many nodes (for ex. Table)
|
|
694
|
-
* - Or, default-block is not empty
|
|
695
|
-
*/
|
|
696
|
-
if (!BlockManager.lastBlock?.tool.isDefault || !BlockManager.lastBlock?.isEmpty) {
|
|
697
|
-
BlockManager.insertAtEnd();
|
|
676
|
+
if (!href) {
|
|
677
|
+
return;
|
|
698
678
|
}
|
|
699
679
|
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
Caret.setToTheLastBlock();
|
|
704
|
-
Toolbar.moveAndOpen(BlockManager.lastBlock);
|
|
680
|
+
const validUrl = getValidUrl(href);
|
|
681
|
+
|
|
682
|
+
openTab(validUrl);
|
|
705
683
|
}
|
|
706
684
|
|
|
707
685
|
/**
|
|
@@ -5,20 +5,15 @@ import { throttle } from '../../../utils';
|
|
|
5
5
|
import { Controller } from './_base';
|
|
6
6
|
|
|
7
7
|
/**
|
|
8
|
-
* BlockHoverController detects when user hovers over blocks
|
|
8
|
+
* BlockHoverController detects when user hovers over blocks or finds nearest block.
|
|
9
9
|
*
|
|
10
10
|
* Responsibilities:
|
|
11
11
|
* - Listen to mousemove events (throttled)
|
|
12
|
-
* - Find block by element hit or
|
|
12
|
+
* - Find block by element hit or nearest by Y distance
|
|
13
13
|
* - Emit BlockHovered events
|
|
14
14
|
* - Track last hovered block to avoid duplicate events
|
|
15
15
|
*/
|
|
16
16
|
export class BlockHoverController extends Controller {
|
|
17
|
-
/**
|
|
18
|
-
* Getter function for content rect
|
|
19
|
-
*/
|
|
20
|
-
private contentRectGetter: () => DOMRect;
|
|
21
|
-
|
|
22
17
|
/**
|
|
23
18
|
* Used to not emit the same block multiple times to the 'block-hovered' event on every mousemove.
|
|
24
19
|
* Stores block ID to ensure consistent comparison regardless of how the block was detected.
|
|
@@ -42,10 +37,8 @@ export class BlockHoverController extends Controller {
|
|
|
42
37
|
constructor(options: {
|
|
43
38
|
config: Controller['config'];
|
|
44
39
|
eventsDispatcher: Controller['eventsDispatcher'];
|
|
45
|
-
contentRectGetter: () => DOMRect;
|
|
46
40
|
}) {
|
|
47
41
|
super(options);
|
|
48
|
-
this.contentRectGetter = options.contentRectGetter;
|
|
49
42
|
}
|
|
50
43
|
|
|
51
44
|
/**
|
|
@@ -83,35 +76,11 @@ export class BlockHoverController extends Controller {
|
|
|
83
76
|
: closestBlockWrapper;
|
|
84
77
|
|
|
85
78
|
/**
|
|
86
|
-
* If no block element found directly,
|
|
79
|
+
* If no block element found directly, find the nearest block by Y distance
|
|
87
80
|
*/
|
|
88
|
-
const zoneBlock = !hoveredBlockElement
|
|
89
|
-
? this.findBlockInHoverZone(event.clientX, event.clientY)
|
|
90
|
-
: null;
|
|
91
|
-
|
|
92
|
-
if (zoneBlock !== null && this.blockHoveredState.lastHoveredBlockId !== zoneBlock.id) {
|
|
93
|
-
/**
|
|
94
|
-
* Emit the event but DON'T set lastHoveredBlockId for hover zone events.
|
|
95
|
-
* This allows the event to be emitted again when the mouse enters the actual block element,
|
|
96
|
-
* which is important for proper toolbar positioning after cross-block selection.
|
|
97
|
-
*/
|
|
98
|
-
this.eventsDispatcher.emit(BlockHovered, {
|
|
99
|
-
block: zoneBlock,
|
|
100
|
-
target: zoneBlock.holder,
|
|
101
|
-
});
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
if (zoneBlock !== null) {
|
|
105
|
-
return;
|
|
106
|
-
}
|
|
107
|
-
|
|
108
81
|
if (!hoveredBlockElement) {
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
* This allows hover events to be emitted again when re-entering a block,
|
|
112
|
-
* which is important after cross-block selection completes.
|
|
113
|
-
*/
|
|
114
|
-
this.blockHoveredState.lastHoveredBlockId = null;
|
|
82
|
+
this.emitNearestBlockHovered(event.clientY);
|
|
83
|
+
|
|
115
84
|
return;
|
|
116
85
|
}
|
|
117
86
|
|
|
@@ -143,9 +112,8 @@ export class BlockHoverController extends Controller {
|
|
|
143
112
|
);
|
|
144
113
|
|
|
145
114
|
/**
|
|
146
|
-
* Listen on document to detect hover
|
|
147
|
-
*
|
|
148
|
-
* We filter events to only process those over the editor or in the hover zone.
|
|
115
|
+
* Listen on document to detect hover anywhere on the page.
|
|
116
|
+
* When cursor is not directly on a block, finds the nearest block by Y distance.
|
|
149
117
|
*/
|
|
150
118
|
this.readOnlyMutableListeners.on(document, 'mousemove', (event: Event) => {
|
|
151
119
|
throttledHandleBlockHovered(event);
|
|
@@ -155,38 +123,49 @@ export class BlockHoverController extends Controller {
|
|
|
155
123
|
}
|
|
156
124
|
|
|
157
125
|
/**
|
|
158
|
-
* Finds
|
|
159
|
-
*
|
|
160
|
-
* allowing the toolbar to follow hover anywhere outside the content area horizontally.
|
|
161
|
-
* @param clientX - Cursor X position
|
|
126
|
+
* Finds and emits a BlockHovered event for the nearest block by Y distance.
|
|
127
|
+
* Deduplicates by lastHoveredBlockId to avoid redundant events.
|
|
162
128
|
* @param clientY - Cursor Y position
|
|
163
|
-
* @returns Block at the vertical position, or null if not in hover zone or no block found
|
|
164
129
|
*/
|
|
165
|
-
private
|
|
166
|
-
const
|
|
130
|
+
private emitNearestBlockHovered(clientY: number): void {
|
|
131
|
+
const nearestBlock = this.findNearestBlock(clientY);
|
|
167
132
|
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
*/
|
|
172
|
-
const isInHoverZone = clientX < contentRect.left || clientX > contentRect.right;
|
|
133
|
+
if (nearestBlock === null || this.blockHoveredState.lastHoveredBlockId === nearestBlock.id) {
|
|
134
|
+
return;
|
|
135
|
+
}
|
|
173
136
|
|
|
174
|
-
|
|
137
|
+
this.blockHoveredState.lastHoveredBlockId = nearestBlock.id;
|
|
138
|
+
|
|
139
|
+
this.eventsDispatcher.emit(BlockHovered, {
|
|
140
|
+
block: nearestBlock,
|
|
141
|
+
target: nearestBlock.holder,
|
|
142
|
+
});
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
/**
|
|
146
|
+
* Finds the nearest block by vertical distance to cursor position.
|
|
147
|
+
* Returns the block whose vertical center is closest to the cursor Y position.
|
|
148
|
+
* If cursor is above all blocks, returns the first block.
|
|
149
|
+
* If cursor is below all blocks, returns the last block.
|
|
150
|
+
* @param clientY - Cursor Y position
|
|
151
|
+
* @returns Nearest block, or null if no blocks exist
|
|
152
|
+
*/
|
|
153
|
+
private findNearestBlock(clientY: number): Block | null {
|
|
154
|
+
const blocks = this.Blok.BlockManager.blocks;
|
|
155
|
+
|
|
156
|
+
if (blocks.length === 0) {
|
|
175
157
|
return null;
|
|
176
158
|
}
|
|
177
159
|
|
|
178
|
-
|
|
179
|
-
* Find block by Y position
|
|
180
|
-
*/
|
|
181
|
-
for (const block of this.Blok.BlockManager.blocks) {
|
|
160
|
+
const result = blocks.reduce<{ block: Block; distance: number }>((nearest, block) => {
|
|
182
161
|
const rect = block.holder.getBoundingClientRect();
|
|
162
|
+
const centerY = (rect.top + rect.bottom) / 2;
|
|
163
|
+
const distance = Math.abs(clientY - centerY);
|
|
183
164
|
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
}
|
|
187
|
-
}
|
|
165
|
+
return distance < nearest.distance ? { block, distance } : nearest;
|
|
166
|
+
}, { block: blocks[0], distance: Infinity });
|
|
188
167
|
|
|
189
|
-
return
|
|
168
|
+
return result.block;
|
|
190
169
|
}
|
|
191
170
|
|
|
192
171
|
/**
|
|
@@ -189,6 +189,29 @@ export class YjsManager extends Module {
|
|
|
189
189
|
this.undoHistory.redo();
|
|
190
190
|
}
|
|
191
191
|
|
|
192
|
+
/**
|
|
193
|
+
* Check if undo is available.
|
|
194
|
+
* @returns true if undo is available
|
|
195
|
+
*/
|
|
196
|
+
public canUndo(): boolean {
|
|
197
|
+
return this.undoHistory.canUndo();
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
/**
|
|
201
|
+
* Check if redo is available.
|
|
202
|
+
* @returns true if redo is available
|
|
203
|
+
*/
|
|
204
|
+
public canRedo(): boolean {
|
|
205
|
+
return this.undoHistory.canRedo();
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
/**
|
|
209
|
+
* Clear all history.
|
|
210
|
+
*/
|
|
211
|
+
public clear(): void {
|
|
212
|
+
this.undoHistory.clear();
|
|
213
|
+
}
|
|
214
|
+
|
|
192
215
|
/**
|
|
193
216
|
* Stop capturing changes into current undo group.
|
|
194
217
|
* Call this to force next change into a new undo entry.
|
|
@@ -1,5 +1,7 @@
|
|
|
1
|
+
import { RESTRICTED_TOOLS } from '../../tools/table/table-restrictions';
|
|
1
2
|
import { Dom } from '../dom';
|
|
2
3
|
import { BlokMobileLayoutToggled } from '../events';
|
|
4
|
+
import { SelectionUtils } from '../selection';
|
|
3
5
|
import type { BlockToolAdapter } from '../tools/block';
|
|
4
6
|
import type { ToolsCollection } from '../tools/collection';
|
|
5
7
|
import { beautifyShortcut, capitalize, isMobileScreen } from '../utils';
|
|
@@ -155,7 +157,7 @@ export class Toolbox extends EventsDispatcher<ToolboxEventMap> {
|
|
|
155
157
|
|
|
156
158
|
/**
|
|
157
159
|
* Whether the toolbox was opened inside a table cell.
|
|
158
|
-
* Used to restore
|
|
160
|
+
* Used to restore restricted tool visibility on close.
|
|
159
161
|
*/
|
|
160
162
|
private isInsideTableCell = false;
|
|
161
163
|
|
|
@@ -273,17 +275,28 @@ export class Toolbox extends EventsDispatcher<ToolboxEventMap> {
|
|
|
273
275
|
const currentBlock = this.api.blocks.getBlockByIndex(currentBlockIndex);
|
|
274
276
|
|
|
275
277
|
/**
|
|
276
|
-
* Hide
|
|
277
|
-
* to prevent nested tables.
|
|
278
|
+
* Hide restricted tools (headers, tables) when the caret is inside a table cell.
|
|
278
279
|
*/
|
|
279
280
|
this.isInsideTableCell = currentBlock !== undefined
|
|
280
281
|
&& currentBlock.holder.closest('[data-blok-table-cell-blocks]') !== null;
|
|
281
282
|
|
|
282
283
|
if (this.isInsideTableCell) {
|
|
283
|
-
this.
|
|
284
|
+
this.toggleRestrictedToolsHidden(true);
|
|
284
285
|
}
|
|
285
286
|
|
|
286
287
|
this.popover?.show();
|
|
288
|
+
|
|
289
|
+
/**
|
|
290
|
+
* When opening toolbox inside a table cell, position it at the caret
|
|
291
|
+
* instead of at the trigger element (which is outside the table).
|
|
292
|
+
* Must be called after show() so the popover is in the DOM.
|
|
293
|
+
*/
|
|
294
|
+
if (this.isInsideTableCell && this.popover instanceof PopoverDesktop) {
|
|
295
|
+
const caretRect = SelectionUtils.rect;
|
|
296
|
+
|
|
297
|
+
this.popover.updatePosition(caretRect);
|
|
298
|
+
}
|
|
299
|
+
|
|
287
300
|
this.opened = true;
|
|
288
301
|
this.emit(ToolboxEvent.Opened);
|
|
289
302
|
this.startListeningToBlockInput();
|
|
@@ -294,7 +307,7 @@ export class Toolbox extends EventsDispatcher<ToolboxEventMap> {
|
|
|
294
307
|
*/
|
|
295
308
|
public close(): void {
|
|
296
309
|
if (this.isInsideTableCell) {
|
|
297
|
-
this.
|
|
310
|
+
this.toggleRestrictedToolsHidden(false);
|
|
298
311
|
this.isInsideTableCell = false;
|
|
299
312
|
}
|
|
300
313
|
|
|
@@ -364,7 +377,7 @@ export class Toolbox extends EventsDispatcher<ToolboxEventMap> {
|
|
|
364
377
|
*/
|
|
365
378
|
private onPopoverClose = (): void => {
|
|
366
379
|
if (this.isInsideTableCell) {
|
|
367
|
-
this.
|
|
380
|
+
this.toggleRestrictedToolsHidden(false);
|
|
368
381
|
this.isInsideTableCell = false;
|
|
369
382
|
}
|
|
370
383
|
|
|
@@ -373,6 +386,28 @@ export class Toolbox extends EventsDispatcher<ToolboxEventMap> {
|
|
|
373
386
|
this.emit(ToolboxEvent.Closed);
|
|
374
387
|
};
|
|
375
388
|
|
|
389
|
+
/**
|
|
390
|
+
* Toggles hidden state for all popover items belonging to restricted tools.
|
|
391
|
+
* Handles tools like header that have multiple entries with custom names (header-1, header-2, etc.)
|
|
392
|
+
* by matching item names that equal or start with a restricted tool name.
|
|
393
|
+
*/
|
|
394
|
+
private toggleRestrictedToolsHidden(isHidden: boolean): void {
|
|
395
|
+
for (const item of this.toolboxItemsToBeDisplayed) {
|
|
396
|
+
if (!('name' in item) || item.name === undefined) {
|
|
397
|
+
continue;
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
const { name } = item;
|
|
401
|
+
const isRestricted = RESTRICTED_TOOLS.some(
|
|
402
|
+
restricted => name === restricted || name.startsWith(`${restricted}-`)
|
|
403
|
+
);
|
|
404
|
+
|
|
405
|
+
if (isRestricted) {
|
|
406
|
+
this.popover?.toggleItemHiddenByName(name, isHidden);
|
|
407
|
+
}
|
|
408
|
+
}
|
|
409
|
+
}
|
|
410
|
+
|
|
376
411
|
/**
|
|
377
412
|
* Returns list of tools that enables the Toolbox (by specifying the 'toolbox' getter)
|
|
378
413
|
*/
|