@jackuait/blok 0.7.0-beta.1 → 0.7.0-beta.2
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 +20 -4
- package/dist/blok.mjs +2 -2
- package/dist/chunks/{blok-ob9Fwr1L.mjs → blok-D9Rs29Wo.mjs} +1620 -1441
- package/dist/chunks/{inline-tool-convert-CvFW2iie.mjs → constants-DmNIR3I8.mjs} +316 -297
- package/dist/chunks/{i18next-loader-Bu3vFvye.mjs → i18next-loader-C2-jYpLi.mjs} +1 -1
- package/dist/chunks/index-D7V1g7Oq.mjs +130 -0
- package/dist/chunks/{messages-D2NOpHn9.mjs → messages-0Pxnqd4N.mjs} +7 -0
- package/dist/chunks/{messages-GSByFygY.mjs → messages-0ZXYUq7S.mjs} +7 -0
- package/dist/{messages-BUl_Rcnj.mjs → chunks/messages-2OD2uUDS.mjs} +9 -2
- package/dist/{messages-CgTq3QhU.mjs → chunks/messages-7cEMfYzh.mjs} +7 -0
- package/dist/{messages-DlJbPF2T.mjs → chunks/messages-8mwfda1Q.mjs} +7 -0
- package/dist/{messages-D9ndgBnU.mjs → chunks/messages-B-FqWsBM.mjs} +7 -0
- package/dist/{messages-B217znr-.mjs → chunks/messages-B1jzqWiQ.mjs} +7 -0
- package/dist/{messages-BcpCubnC.mjs → chunks/messages-B5wk4Ezz.mjs} +7 -0
- package/dist/chunks/{messages-DRXWF0PV.mjs → messages-BAZ5Ld8x.mjs} +7 -0
- package/dist/{messages-CRJ_mchV.mjs → chunks/messages-BBhGp198.mjs} +7 -0
- package/dist/chunks/{messages-yHcs38yI.mjs → messages-BC9IjIb7.mjs} +7 -0
- package/dist/chunks/{messages-Cr94GzbX.mjs → messages-BFEmpeV-.mjs} +7 -0
- package/dist/chunks/{messages-ucTVgS5G.mjs → messages-BGqzTZy0.mjs} +7 -0
- package/dist/{messages-begYOTgC.mjs → chunks/messages-BICs1abK.mjs} +7 -0
- package/dist/chunks/{messages-DVQvl8Qj.mjs → messages-BJX6rOnd.mjs} +7 -0
- package/dist/chunks/{messages-Chb7k3Rg.mjs → messages-BL2bXRhN.mjs} +7 -0
- package/dist/{messages-Phkd7XmE.mjs → chunks/messages-BMs5qdlH.mjs} +7 -0
- package/dist/chunks/{messages-Cjjo7yHR.mjs → messages-BRsjUNwB.mjs} +7 -0
- package/dist/chunks/{messages-D4qqwVgQ.mjs → messages-BSqV8OUR.mjs} +7 -0
- package/dist/chunks/{messages-DviiFSv2.mjs → messages-BTqu3DfG.mjs} +7 -0
- package/dist/chunks/{messages-0AbcLMLm.mjs → messages-BXnDEsur.mjs} +7 -0
- package/dist/{messages-CmR9ftc_.mjs → chunks/messages-BYcre4-6.mjs} +7 -0
- package/dist/{messages-wmi-iFkH.mjs → chunks/messages-BZ9LRJf-.mjs} +7 -0
- package/dist/chunks/{messages-D00x4S8o.mjs → messages-BgypBy7y.mjs} +7 -0
- package/dist/{messages-96kNZDll.mjs → chunks/messages-BsuGf70G.mjs} +7 -0
- package/dist/chunks/{messages-v3GipbFl.mjs → messages-BwaoF4lQ.mjs} +7 -0
- package/dist/{messages-DDTQgImT.mjs → chunks/messages-C1l8_7-y.mjs} +7 -0
- package/dist/{messages-B1FZ8lxU.mjs → chunks/messages-C5NA_r9v.mjs} +7 -0
- package/dist/{messages-Cs8zmZ3L.mjs → chunks/messages-C6zgZ5pA.mjs} +7 -0
- package/dist/chunks/{messages-ZjUAIWb1.mjs → messages-CAo5ghFI.mjs} +7 -0
- package/dist/{messages-D5S1Dnpm.mjs → chunks/messages-CH9qlJ9I.mjs} +7 -0
- package/dist/{messages-D7u2bmP2.mjs → chunks/messages-CI0HqAeS.mjs} +7 -0
- package/dist/{messages-DH_jBeED.mjs → chunks/messages-CJJtms9k.mjs} +7 -0
- package/dist/{messages-CDBLbUOQ.mjs → chunks/messages-CM2hJqk6.mjs} +7 -0
- package/dist/chunks/{messages-8IPXkrDl.mjs → messages-CRMiDPIQ.mjs} +7 -0
- package/dist/chunks/{messages-Dzzn6XoD.mjs → messages-CWsZuBj1.mjs} +7 -0
- package/dist/chunks/{messages-CW4c4cRk.mjs → messages-C_gLHo6A.mjs} +7 -0
- package/dist/{messages-CH4hrauY.mjs → chunks/messages-Cbu-NUDn.mjs} +7 -0
- package/dist/{messages-RonBBCnh.mjs → chunks/messages-Cjb_MCeh.mjs} +7 -0
- package/dist/chunks/{messages-BJ6zrz2j.mjs → messages-ClXYO9Wn.mjs} +7 -0
- package/dist/chunks/{messages-CrCYPCk3.mjs → messages-CsH20vhP.mjs} +7 -0
- package/dist/{messages-CzK0LEhb.mjs → chunks/messages-CsjAGhzA.mjs} +7 -0
- package/dist/chunks/{messages-BZlmVRwn.mjs → messages-Cx7VKFOE.mjs} +7 -0
- package/dist/chunks/{messages-0E0AkrNu.mjs → messages-D3JeBwxo.mjs} +7 -0
- package/dist/chunks/{messages-D85FqxgY.mjs → messages-D541fieJ.mjs} +7 -0
- package/dist/{messages-4v4MuVEc.mjs → chunks/messages-D7XPdglc.mjs} +7 -0
- package/dist/{messages-BC8IN4Bf.mjs → chunks/messages-DBhylfvt.mjs} +7 -0
- package/dist/chunks/{messages-B8WNljW3.mjs → messages-DCA120lW.mjs} +7 -0
- package/dist/chunks/{messages-Cr49Nt3U.mjs → messages-DCf_xZMN.mjs} +7 -0
- package/dist/chunks/{messages-VDriF5Qy.mjs → messages-DDwXKCpe.mjs} +7 -0
- package/dist/{messages-b1EdvUm0.mjs → chunks/messages-DNKDlxcy.mjs} +7 -0
- package/dist/{messages-L_kl2Qvh.mjs → chunks/messages-DPvEjrGK.mjs} +7 -0
- package/dist/chunks/{messages-62v-CLC-.mjs → messages-DQ-AkNxA.mjs} +7 -0
- package/dist/chunks/{messages-DdK-nFGm.mjs → messages-DVuvkNap.mjs} +7 -0
- package/dist/{messages-DnVlmiNT.mjs → chunks/messages-DaglyqUT.mjs} +7 -0
- package/dist/{messages-Bm-E4iRC.mjs → chunks/messages-Di0bAfwA.mjs} +7 -0
- package/dist/{messages-D1mn7Zd5.mjs → chunks/messages-DuLct0Yr.mjs} +7 -0
- package/dist/{messages-8DeO60Oo.mjs → chunks/messages-DzEYYhZh.mjs} +7 -0
- package/dist/chunks/{messages-CfiyT2Wi.mjs → messages-DznNGAB2.mjs} +7 -0
- package/dist/chunks/{messages-DXktiao_.mjs → messages-DzoIzyu8.mjs} +7 -0
- package/dist/{messages-C_4otP7U.mjs → chunks/messages-QYOGmket.mjs} +7 -0
- package/dist/chunks/{messages-nefz1S71.mjs → messages-cEjGDAgI.mjs} +7 -0
- package/dist/chunks/{messages-jrncnb-H.mjs → messages-ddhvrdpE.mjs} +7 -0
- package/dist/chunks/{messages-DzqM3Fel.mjs → messages-mwfNK5nZ.mjs} +7 -0
- package/dist/chunks/{messages-Cl6ayUaq.mjs → messages-nG_vNDte.mjs} +7 -0
- package/dist/{messages-C4jL-90N.mjs → chunks/messages-tDq3Owh7.mjs} +7 -0
- package/dist/{messages-BI43k_BD.mjs → chunks/messages-x6VJVZKx.mjs} +7 -0
- package/dist/full.mjs +2 -2
- package/dist/locales.mjs +87 -80
- package/dist/{messages-D2NOpHn9.mjs → messages-0Pxnqd4N.mjs} +7 -0
- package/dist/{messages-GSByFygY.mjs → messages-0ZXYUq7S.mjs} +7 -0
- package/dist/{chunks/messages-BUl_Rcnj.mjs → messages-2OD2uUDS.mjs} +9 -2
- package/dist/{chunks/messages-CgTq3QhU.mjs → messages-7cEMfYzh.mjs} +7 -0
- package/dist/{chunks/messages-DlJbPF2T.mjs → messages-8mwfda1Q.mjs} +7 -0
- package/dist/{chunks/messages-D9ndgBnU.mjs → messages-B-FqWsBM.mjs} +7 -0
- package/dist/{chunks/messages-B217znr-.mjs → messages-B1jzqWiQ.mjs} +7 -0
- package/dist/{chunks/messages-BcpCubnC.mjs → messages-B5wk4Ezz.mjs} +7 -0
- package/dist/{messages-DRXWF0PV.mjs → messages-BAZ5Ld8x.mjs} +7 -0
- package/dist/{chunks/messages-CRJ_mchV.mjs → messages-BBhGp198.mjs} +7 -0
- package/dist/{messages-yHcs38yI.mjs → messages-BC9IjIb7.mjs} +7 -0
- package/dist/{messages-Cr94GzbX.mjs → messages-BFEmpeV-.mjs} +7 -0
- package/dist/{messages-ucTVgS5G.mjs → messages-BGqzTZy0.mjs} +7 -0
- package/dist/{chunks/messages-begYOTgC.mjs → messages-BICs1abK.mjs} +7 -0
- package/dist/{messages-DVQvl8Qj.mjs → messages-BJX6rOnd.mjs} +7 -0
- package/dist/{messages-Chb7k3Rg.mjs → messages-BL2bXRhN.mjs} +7 -0
- package/dist/{chunks/messages-Phkd7XmE.mjs → messages-BMs5qdlH.mjs} +7 -0
- package/dist/{messages-Cjjo7yHR.mjs → messages-BRsjUNwB.mjs} +7 -0
- package/dist/{messages-D4qqwVgQ.mjs → messages-BSqV8OUR.mjs} +7 -0
- package/dist/{messages-DviiFSv2.mjs → messages-BTqu3DfG.mjs} +7 -0
- package/dist/{messages-0AbcLMLm.mjs → messages-BXnDEsur.mjs} +7 -0
- package/dist/{chunks/messages-CmR9ftc_.mjs → messages-BYcre4-6.mjs} +7 -0
- package/dist/{chunks/messages-wmi-iFkH.mjs → messages-BZ9LRJf-.mjs} +7 -0
- package/dist/{messages-D00x4S8o.mjs → messages-BgypBy7y.mjs} +7 -0
- package/dist/{chunks/messages-96kNZDll.mjs → messages-BsuGf70G.mjs} +7 -0
- package/dist/{messages-v3GipbFl.mjs → messages-BwaoF4lQ.mjs} +7 -0
- package/dist/{chunks/messages-DDTQgImT.mjs → messages-C1l8_7-y.mjs} +7 -0
- package/dist/{chunks/messages-B1FZ8lxU.mjs → messages-C5NA_r9v.mjs} +7 -0
- package/dist/{chunks/messages-Cs8zmZ3L.mjs → messages-C6zgZ5pA.mjs} +7 -0
- package/dist/{messages-ZjUAIWb1.mjs → messages-CAo5ghFI.mjs} +7 -0
- package/dist/{chunks/messages-D5S1Dnpm.mjs → messages-CH9qlJ9I.mjs} +7 -0
- package/dist/{chunks/messages-D7u2bmP2.mjs → messages-CI0HqAeS.mjs} +7 -0
- package/dist/{chunks/messages-DH_jBeED.mjs → messages-CJJtms9k.mjs} +7 -0
- package/dist/{chunks/messages-CDBLbUOQ.mjs → messages-CM2hJqk6.mjs} +7 -0
- package/dist/{messages-8IPXkrDl.mjs → messages-CRMiDPIQ.mjs} +7 -0
- package/dist/{messages-Dzzn6XoD.mjs → messages-CWsZuBj1.mjs} +7 -0
- package/dist/{messages-CW4c4cRk.mjs → messages-C_gLHo6A.mjs} +7 -0
- package/dist/{chunks/messages-CH4hrauY.mjs → messages-Cbu-NUDn.mjs} +7 -0
- package/dist/{chunks/messages-RonBBCnh.mjs → messages-Cjb_MCeh.mjs} +7 -0
- package/dist/{messages-BJ6zrz2j.mjs → messages-ClXYO9Wn.mjs} +7 -0
- package/dist/{messages-CrCYPCk3.mjs → messages-CsH20vhP.mjs} +7 -0
- package/dist/{chunks/messages-CzK0LEhb.mjs → messages-CsjAGhzA.mjs} +7 -0
- package/dist/{messages-BZlmVRwn.mjs → messages-Cx7VKFOE.mjs} +7 -0
- package/dist/{messages-0E0AkrNu.mjs → messages-D3JeBwxo.mjs} +7 -0
- package/dist/{messages-D85FqxgY.mjs → messages-D541fieJ.mjs} +7 -0
- package/dist/{chunks/messages-4v4MuVEc.mjs → messages-D7XPdglc.mjs} +7 -0
- package/dist/{chunks/messages-BC8IN4Bf.mjs → messages-DBhylfvt.mjs} +7 -0
- package/dist/{messages-B8WNljW3.mjs → messages-DCA120lW.mjs} +7 -0
- package/dist/{messages-Cr49Nt3U.mjs → messages-DCf_xZMN.mjs} +7 -0
- package/dist/{messages-VDriF5Qy.mjs → messages-DDwXKCpe.mjs} +7 -0
- package/dist/{chunks/messages-b1EdvUm0.mjs → messages-DNKDlxcy.mjs} +7 -0
- package/dist/{chunks/messages-L_kl2Qvh.mjs → messages-DPvEjrGK.mjs} +7 -0
- package/dist/{messages-62v-CLC-.mjs → messages-DQ-AkNxA.mjs} +7 -0
- package/dist/{messages-DdK-nFGm.mjs → messages-DVuvkNap.mjs} +7 -0
- package/dist/{chunks/messages-DnVlmiNT.mjs → messages-DaglyqUT.mjs} +7 -0
- package/dist/{chunks/messages-Bm-E4iRC.mjs → messages-Di0bAfwA.mjs} +7 -0
- package/dist/{chunks/messages-D1mn7Zd5.mjs → messages-DuLct0Yr.mjs} +7 -0
- package/dist/{chunks/messages-8DeO60Oo.mjs → messages-DzEYYhZh.mjs} +7 -0
- package/dist/{messages-CfiyT2Wi.mjs → messages-DznNGAB2.mjs} +7 -0
- package/dist/{messages-DXktiao_.mjs → messages-DzoIzyu8.mjs} +7 -0
- package/dist/{chunks/messages-C_4otP7U.mjs → messages-QYOGmket.mjs} +7 -0
- package/dist/{messages-nefz1S71.mjs → messages-cEjGDAgI.mjs} +7 -0
- package/dist/{messages-jrncnb-H.mjs → messages-ddhvrdpE.mjs} +7 -0
- package/dist/{messages-DzqM3Fel.mjs → messages-mwfNK5nZ.mjs} +7 -0
- package/dist/{messages-Cl6ayUaq.mjs → messages-nG_vNDte.mjs} +7 -0
- package/dist/{chunks/messages-C4jL-90N.mjs → messages-tDq3Owh7.mjs} +7 -0
- package/dist/{chunks/messages-BI43k_BD.mjs → messages-x6VJVZKx.mjs} +7 -0
- package/dist/tools.mjs +442 -337
- package/package.json +1 -1
- package/src/components/i18n/locales/am/messages.json +7 -0
- package/src/components/i18n/locales/ar/messages.json +7 -0
- package/src/components/i18n/locales/az/messages.json +7 -0
- package/src/components/i18n/locales/bg/messages.json +7 -0
- package/src/components/i18n/locales/bn/messages.json +7 -0
- package/src/components/i18n/locales/bs/messages.json +7 -0
- package/src/components/i18n/locales/cs/messages.json +7 -0
- package/src/components/i18n/locales/da/messages.json +7 -0
- package/src/components/i18n/locales/de/messages.json +7 -0
- package/src/components/i18n/locales/dv/messages.json +7 -0
- package/src/components/i18n/locales/el/messages.json +7 -0
- package/src/components/i18n/locales/en/messages.json +7 -0
- package/src/components/i18n/locales/es/messages.json +7 -0
- package/src/components/i18n/locales/et/messages.json +7 -0
- package/src/components/i18n/locales/fa/messages.json +7 -0
- package/src/components/i18n/locales/fi/messages.json +7 -0
- package/src/components/i18n/locales/fil/messages.json +7 -0
- package/src/components/i18n/locales/fr/messages.json +7 -0
- package/src/components/i18n/locales/gu/messages.json +7 -0
- package/src/components/i18n/locales/he/messages.json +7 -0
- package/src/components/i18n/locales/hi/messages.json +7 -0
- package/src/components/i18n/locales/hr/messages.json +7 -0
- package/src/components/i18n/locales/hu/messages.json +7 -0
- package/src/components/i18n/locales/hy/messages.json +7 -0
- package/src/components/i18n/locales/id/messages.json +7 -0
- package/src/components/i18n/locales/it/messages.json +7 -0
- package/src/components/i18n/locales/ja/messages.json +7 -0
- package/src/components/i18n/locales/ka/messages.json +7 -0
- package/src/components/i18n/locales/km/messages.json +7 -0
- package/src/components/i18n/locales/kn/messages.json +7 -0
- package/src/components/i18n/locales/ko/messages.json +7 -0
- package/src/components/i18n/locales/ku/messages.json +7 -0
- package/src/components/i18n/locales/lo/messages.json +7 -0
- package/src/components/i18n/locales/lt/messages.json +7 -0
- package/src/components/i18n/locales/lv/messages.json +7 -0
- package/src/components/i18n/locales/mk/messages.json +7 -0
- package/src/components/i18n/locales/ml/messages.json +7 -0
- package/src/components/i18n/locales/mn/messages.json +7 -0
- package/src/components/i18n/locales/mr/messages.json +7 -0
- package/src/components/i18n/locales/ms/messages.json +7 -0
- package/src/components/i18n/locales/my/messages.json +7 -0
- package/src/components/i18n/locales/ne/messages.json +7 -0
- package/src/components/i18n/locales/nl/messages.json +7 -0
- package/src/components/i18n/locales/no/messages.json +7 -0
- package/src/components/i18n/locales/pa/messages.json +7 -0
- package/src/components/i18n/locales/pl/messages.json +7 -0
- package/src/components/i18n/locales/ps/messages.json +7 -0
- package/src/components/i18n/locales/pt/messages.json +7 -0
- package/src/components/i18n/locales/ro/messages.json +7 -0
- package/src/components/i18n/locales/ru/messages.json +7 -0
- package/src/components/i18n/locales/sd/messages.json +7 -0
- package/src/components/i18n/locales/si/messages.json +7 -0
- package/src/components/i18n/locales/sk/messages.json +7 -0
- package/src/components/i18n/locales/sl/messages.json +7 -0
- package/src/components/i18n/locales/sq/messages.json +7 -0
- package/src/components/i18n/locales/sr/messages.json +7 -0
- package/src/components/i18n/locales/sv/messages.json +7 -0
- package/src/components/i18n/locales/sw/messages.json +7 -0
- package/src/components/i18n/locales/ta/messages.json +7 -0
- package/src/components/i18n/locales/te/messages.json +7 -0
- package/src/components/i18n/locales/th/messages.json +7 -0
- package/src/components/i18n/locales/tr/messages.json +7 -0
- package/src/components/i18n/locales/ug/messages.json +7 -0
- package/src/components/i18n/locales/uk/messages.json +7 -0
- package/src/components/i18n/locales/ur/messages.json +7 -0
- package/src/components/i18n/locales/vi/messages.json +7 -0
- package/src/components/i18n/locales/yi/messages.json +7 -0
- package/src/components/i18n/locales/zh/messages.json +7 -0
- package/src/components/modules/blockEvents/composers/keyboardNavigation.ts +44 -2
- package/src/components/modules/blockEvents/index.ts +1 -3
- package/src/components/modules/blockManager/blockManager.ts +16 -0
- package/src/components/modules/blockManager/operations.ts +106 -9
- package/src/components/modules/blockSelection.ts +2 -0
- package/src/components/modules/caret.ts +49 -4
- package/src/components/modules/drag/DragController.ts +34 -2
- package/src/components/modules/paste/handlers/blok-data-handler.ts +50 -3
- package/src/components/modules/toolbar/index.ts +11 -16
- package/src/components/modules/ui.ts +12 -0
- package/src/components/ui/toolbox.ts +19 -3
- package/src/components/utils/notifier/draw.ts +116 -14
- package/src/components/utils/notifier/index.ts +31 -4
- package/src/components/utils/popover/components/popover-item/popover-item-default/popover-item-default.const.ts +2 -2
- package/src/components/utils/popover/components/popover-item/popover-item-default/popover-item-default.ts +6 -7
- package/src/components/utils/popover/components/popover-item/popover-item-separator/popover-item-separator.const.ts +2 -2
- package/src/components/utils/popover/popover-abstract.ts +2 -0
- package/src/components/utils/popover/popover-desktop.ts +39 -2
- package/src/styles/main.css +46 -0
- package/src/tools/header/index.ts +124 -21
- package/src/tools/table/index.ts +2 -3
- package/src/tools/table/table-add-controls.ts +29 -1
- package/src/tools/table/table-cell-blocks.ts +93 -0
- package/src/tools/toggle/constants.ts +2 -2
- package/src/tools/toggle/dom-builder.ts +31 -4
- package/src/tools/toggle/index.ts +26 -4
- package/src/tools/toggle/toggle-keyboard.ts +19 -2
- package/src/tools/toggle/toggle-lifecycle.ts +1 -0
- package/src/tools/toggle/toggle-shortcuts.ts +14 -8
- package/types/utils/popover/popover.d.ts +8 -0
- package/dist/chunks/index-CZmRzRIX.mjs +0 -78
|
@@ -391,9 +391,11 @@ export abstract class PopoverAbstract<Nodes extends PopoverNodes = PopoverNodes>
|
|
|
391
391
|
protected toggleNothingFoundMessage(isDisplayed: boolean): void {
|
|
392
392
|
if (isDisplayed) {
|
|
393
393
|
this.nodes.nothingFoundMessage.classList.remove('hidden');
|
|
394
|
+
this.nodes.nothingFoundMessage.classList.add('animate-[fade-in_150ms_ease_forwards]');
|
|
394
395
|
this.nodes.nothingFoundMessage.setAttribute(DATA_ATTR.nothingFoundDisplayed, 'true');
|
|
395
396
|
} else {
|
|
396
397
|
this.nodes.nothingFoundMessage.classList.add('hidden');
|
|
398
|
+
this.nodes.nothingFoundMessage.classList.remove('animate-[fade-in_150ms_ease_forwards]');
|
|
397
399
|
this.nodes.nothingFoundMessage.removeAttribute(DATA_ATTR.nothingFoundDisplayed);
|
|
398
400
|
}
|
|
399
401
|
}
|
|
@@ -60,6 +60,12 @@ export class PopoverDesktop extends PopoverAbstract {
|
|
|
60
60
|
*/
|
|
61
61
|
private trigger: HTMLElement | undefined;
|
|
62
62
|
|
|
63
|
+
/**
|
|
64
|
+
* Optional element whose left edge is used for horizontal positioning
|
|
65
|
+
* instead of the trigger's left edge.
|
|
66
|
+
*/
|
|
67
|
+
private leftAlignElement: HTMLElement | undefined;
|
|
68
|
+
|
|
63
69
|
/**
|
|
64
70
|
* Popover size cache
|
|
65
71
|
*/
|
|
@@ -78,6 +84,10 @@ export class PopoverDesktop extends PopoverAbstract {
|
|
|
78
84
|
this.trigger = params.trigger;
|
|
79
85
|
}
|
|
80
86
|
|
|
87
|
+
if (params.leftAlignElement) {
|
|
88
|
+
this.leftAlignElement = params.leftAlignElement;
|
|
89
|
+
}
|
|
90
|
+
|
|
81
91
|
if (params.nestingLevel !== undefined) {
|
|
82
92
|
this.nestingLevel = params.nestingLevel;
|
|
83
93
|
}
|
|
@@ -191,7 +201,13 @@ export class PopoverDesktop extends PopoverAbstract {
|
|
|
191
201
|
this.nodes.popover.style.setProperty(CSSVariables.PopoverLeft, '0px');
|
|
192
202
|
}
|
|
193
203
|
|
|
194
|
-
|
|
204
|
+
const measuredSize = this.size;
|
|
205
|
+
|
|
206
|
+
this.nodes.popover.style.setProperty(CSSVariables.PopoverHeight, measuredSize.height + 'px');
|
|
207
|
+
|
|
208
|
+
if (this.params.width === undefined || this.params.width === 'auto') {
|
|
209
|
+
this.nodes.popover.style.setProperty('--width', measuredSize.width + 'px');
|
|
210
|
+
}
|
|
195
211
|
|
|
196
212
|
if (!this.trigger && !this.shouldOpenBottom) {
|
|
197
213
|
this.setOpenTop(true);
|
|
@@ -270,7 +286,7 @@ export class PopoverDesktop extends PopoverAbstract {
|
|
|
270
286
|
(rect.top - offset - popoverRect.height > window.scrollY);
|
|
271
287
|
const top = shouldFlipTop ? rect.top - offset - popoverRect.height + window.scrollY : initialTop;
|
|
272
288
|
|
|
273
|
-
const initialLeft = rect.left + window.scrollX;
|
|
289
|
+
const initialLeft = (this.leftAlignElement?.getBoundingClientRect().left ?? rect.left) + window.scrollX;
|
|
274
290
|
const shouldFlipLeft = initialLeft + popoverRect.width > windowWidth + window.scrollX;
|
|
275
291
|
const left = shouldFlipLeft ? Math.max(0, rect.right - popoverRect.width + window.scrollX) : initialLeft;
|
|
276
292
|
|
|
@@ -695,6 +711,18 @@ export class PopoverDesktop extends PopoverAbstract {
|
|
|
695
711
|
// Cast data.items to PopoverItemDefault[] since we know that's what filterItems passes
|
|
696
712
|
const matchingItems = data.items as unknown as PopoverItemDefault[];
|
|
697
713
|
|
|
714
|
+
/**
|
|
715
|
+
* When nothing is found, disable transitions so items hide instantly.
|
|
716
|
+
* The "Nothing found" message fade-in provides the visual transition;
|
|
717
|
+
* animating the last items' collapse simultaneously causes a jarring
|
|
718
|
+
* height bounce in the popover container.
|
|
719
|
+
*/
|
|
720
|
+
if (isNothingFound) {
|
|
721
|
+
this.items.forEach(item => {
|
|
722
|
+
item.getElement()?.style.setProperty('transition-duration', '0s');
|
|
723
|
+
});
|
|
724
|
+
}
|
|
725
|
+
|
|
698
726
|
this.items
|
|
699
727
|
.forEach((item) => {
|
|
700
728
|
const isDefaultItem = item instanceof PopoverItemDefault;
|
|
@@ -705,6 +733,15 @@ export class PopoverDesktop extends PopoverAbstract {
|
|
|
705
733
|
|
|
706
734
|
item.toggleHidden(isHidden);
|
|
707
735
|
});
|
|
736
|
+
|
|
737
|
+
if (isNothingFound) {
|
|
738
|
+
// Force reflow so the instant hide takes effect, then restore transitions
|
|
739
|
+
this.nodes.popoverContainer.offsetHeight;
|
|
740
|
+
this.items.forEach(item => {
|
|
741
|
+
item.getElement()?.style.removeProperty('transition-duration');
|
|
742
|
+
});
|
|
743
|
+
}
|
|
744
|
+
|
|
708
745
|
this.toggleNothingFoundMessage(isNothingFound);
|
|
709
746
|
|
|
710
747
|
/** List of elements available for keyboard navigation considering search query applied */
|
package/src/styles/main.css
CHANGED
|
@@ -108,6 +108,9 @@
|
|
|
108
108
|
--animate-wobble: wobble 400ms;
|
|
109
109
|
--animate-rotation: rotation 1.2s infinite linear;
|
|
110
110
|
--animate-notify-bounce-in: notifyBounceIn 600ms 1;
|
|
111
|
+
--animate-notify-slide-in: notifySlideIn 400ms cubic-bezier(0.16, 1, 0.3, 1) both;
|
|
112
|
+
--animate-notify-slide-out: notifySlideOut 250ms cubic-bezier(0.4, 0, 1, 1) both;
|
|
113
|
+
--animate-notify-progress: notifyProgress linear forwards;
|
|
111
114
|
|
|
112
115
|
/* Keyframes */
|
|
113
116
|
@keyframes fade-in {
|
|
@@ -166,6 +169,22 @@
|
|
|
166
169
|
70% { transform: scale(0.9); }
|
|
167
170
|
100% { transform: scale(1); }
|
|
168
171
|
}
|
|
172
|
+
|
|
173
|
+
@keyframes notifySlideIn {
|
|
174
|
+
0% { opacity: 0; transform: translateY(16px); }
|
|
175
|
+
70% { opacity: 1; transform: translateY(-2px); }
|
|
176
|
+
100% { opacity: 1; transform: translateY(0); }
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
@keyframes notifySlideOut {
|
|
180
|
+
0% { opacity: 1; transform: translateY(0); }
|
|
181
|
+
100% { opacity: 0; transform: translateY(8px); }
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
@keyframes notifyProgress {
|
|
185
|
+
0% { width: 100%; }
|
|
186
|
+
100% { width: 0%; }
|
|
187
|
+
}
|
|
169
188
|
}
|
|
170
189
|
|
|
171
190
|
/*
|
|
@@ -308,6 +327,19 @@
|
|
|
308
327
|
@apply p-0 m-0 min-h-[1.6em];
|
|
309
328
|
}
|
|
310
329
|
|
|
330
|
+
/**
|
|
331
|
+
* Exclude bare 'color' from transition-property inside table cells.
|
|
332
|
+
* StyleManager applies transition-colors (which includes 'color') for smooth
|
|
333
|
+
* selection-state changes, but inside table cells inherited text-color changes
|
|
334
|
+
* trigger a 150ms flash from black → target. Keep all other transition
|
|
335
|
+
* properties so background-color selection highlighting still animates.
|
|
336
|
+
*/
|
|
337
|
+
[data-blok-table-cell] [data-blok-element-content] {
|
|
338
|
+
transition-property: background-color, border-color, outline-color,
|
|
339
|
+
text-decoration-color, fill, stroke, --tw-gradient-from,
|
|
340
|
+
--tw-gradient-via, --tw-gradient-to;
|
|
341
|
+
}
|
|
342
|
+
|
|
311
343
|
/**
|
|
312
344
|
* Table heading styles
|
|
313
345
|
* Applied to first row (heading row) and first column (heading column) cells
|
|
@@ -324,3 +356,17 @@
|
|
|
324
356
|
[data-blok-table-haze][data-blok-table-haze-visible] {
|
|
325
357
|
@apply opacity-100;
|
|
326
358
|
}
|
|
359
|
+
|
|
360
|
+
/**
|
|
361
|
+
* Slash search input appearance
|
|
362
|
+
* When the user types "/" to open the toolbox, the contenteditable
|
|
363
|
+
* transforms to look like a search input with a placeholder.
|
|
364
|
+
*/
|
|
365
|
+
[data-blok-slash-search] {
|
|
366
|
+
@apply bg-[#F8F8F8] rounded-lg transition-colors duration-150 max-w-[240px];
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
[data-blok-slash-search]::after {
|
|
370
|
+
content: attr(data-blok-slash-search);
|
|
371
|
+
@apply text-gray-text font-medium text-base pointer-events-none;
|
|
372
|
+
}
|
|
@@ -23,7 +23,8 @@ import { IconH1, IconH2, IconH3, IconH4, IconH5, IconH6, IconHeading, IconToggle
|
|
|
23
23
|
import { PLACEHOLDER_CLASSES, setupPlaceholder } from '../../components/utils/placeholder';
|
|
24
24
|
import { translateToolTitle } from '../../components/utils/tools';
|
|
25
25
|
import { twMerge } from '../../components/utils/tw';
|
|
26
|
-
import { ARROW_ICON,
|
|
26
|
+
import { ARROW_ICON, TOGGLE_ATTR, TOGGLE_WRAPPER_STYLES } from '../toggle/constants';
|
|
27
|
+
import { buildArrow } from '../toggle/dom-builder';
|
|
27
28
|
import { updateArrowState, updateChildrenVisibility } from '../toggle/toggle-lifecycle';
|
|
28
29
|
|
|
29
30
|
/**
|
|
@@ -216,6 +217,22 @@ export class Header implements BlockTool {
|
|
|
216
217
|
normalized.isToggleable = true;
|
|
217
218
|
}
|
|
218
219
|
|
|
220
|
+
/**
|
|
221
|
+
* Sanitize text to remove any previously saved arrow HTML (backwards compatibility)
|
|
222
|
+
*/
|
|
223
|
+
if (normalized.text) {
|
|
224
|
+
const temp = document.createElement('div');
|
|
225
|
+
|
|
226
|
+
temp.innerHTML = normalized.text;
|
|
227
|
+
|
|
228
|
+
const arrowEl = temp.querySelector(`[${TOGGLE_ATTR.toggleArrow}]`);
|
|
229
|
+
|
|
230
|
+
if (arrowEl) {
|
|
231
|
+
arrowEl.remove();
|
|
232
|
+
normalized.text = temp.innerHTML;
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
|
|
219
236
|
return normalized;
|
|
220
237
|
}
|
|
221
238
|
|
|
@@ -238,6 +255,42 @@ export class Header implements BlockTool {
|
|
|
238
255
|
}
|
|
239
256
|
}
|
|
240
257
|
|
|
258
|
+
/**
|
|
259
|
+
* Expand the toggle heading (no-op if not toggleable or already expanded).
|
|
260
|
+
* Can be called externally via block.call('expand').
|
|
261
|
+
*/
|
|
262
|
+
public expand(): void {
|
|
263
|
+
if (!this._data.isToggleable || this._isOpen) {
|
|
264
|
+
return;
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
this._isOpen = true;
|
|
268
|
+
|
|
269
|
+
if (this._arrowElement && this._element) {
|
|
270
|
+
updateArrowState(this._arrowElement, this._element, this._isOpen);
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
this.updateChildrenVisibility();
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
/**
|
|
277
|
+
* Collapse the toggle heading (no-op if not toggleable or already collapsed).
|
|
278
|
+
* Can be called externally via block.call('collapse').
|
|
279
|
+
*/
|
|
280
|
+
public collapse(): void {
|
|
281
|
+
if (!this._data.isToggleable || !this._isOpen) {
|
|
282
|
+
return;
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
this._isOpen = false;
|
|
286
|
+
|
|
287
|
+
if (this._arrowElement && this._element) {
|
|
288
|
+
updateArrowState(this._arrowElement, this._element, this._isOpen);
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
this.updateChildrenVisibility();
|
|
292
|
+
}
|
|
293
|
+
|
|
241
294
|
/**
|
|
242
295
|
* Returns header block tunes config
|
|
243
296
|
*
|
|
@@ -357,7 +410,34 @@ export class Header implements BlockTool {
|
|
|
357
410
|
* @param data - saved data to merge with current block
|
|
358
411
|
*/
|
|
359
412
|
public merge(data: HeaderData): void {
|
|
360
|
-
|
|
413
|
+
/**
|
|
414
|
+
* Strip any arrow HTML from incoming data to prevent injection of toggle markup
|
|
415
|
+
*/
|
|
416
|
+
const tempDiv = document.createElement('div');
|
|
417
|
+
tempDiv.innerHTML = data.text;
|
|
418
|
+
const arrowInData = tempDiv.querySelector(`[${TOGGLE_ATTR.toggleArrow}]`);
|
|
419
|
+
|
|
420
|
+
if (arrowInData) {
|
|
421
|
+
arrowInData.remove();
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
const cleanText = tempDiv.innerHTML;
|
|
425
|
+
|
|
426
|
+
/**
|
|
427
|
+
* Strip arrow from current element, append text, then re-add arrow.
|
|
428
|
+
* This ensures text is appended to the content, not interleaved with toggle markup.
|
|
429
|
+
*/
|
|
430
|
+
const arrowEl = this._element.querySelector(`[${TOGGLE_ATTR.toggleArrow}]`);
|
|
431
|
+
|
|
432
|
+
if (arrowEl) {
|
|
433
|
+
arrowEl.remove();
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
this._element.insertAdjacentHTML('beforeend', cleanText);
|
|
437
|
+
|
|
438
|
+
if (arrowEl && this._data.isToggleable) {
|
|
439
|
+
this._element.prepend(arrowEl);
|
|
440
|
+
}
|
|
361
441
|
}
|
|
362
442
|
|
|
363
443
|
/**
|
|
@@ -378,11 +458,27 @@ export class Header implements BlockTool {
|
|
|
378
458
|
* @returns saved data
|
|
379
459
|
*/
|
|
380
460
|
public save(toolsContent: HTMLHeadingElement): HeaderData {
|
|
461
|
+
/**
|
|
462
|
+
* Strip arrow element before reading innerHTML to avoid saving toggle markup
|
|
463
|
+
*/
|
|
464
|
+
const arrowEl = toolsContent.querySelector(`[${TOGGLE_ATTR.toggleArrow}]`);
|
|
465
|
+
|
|
466
|
+
if (arrowEl) {
|
|
467
|
+
arrowEl.remove();
|
|
468
|
+
}
|
|
469
|
+
|
|
381
470
|
const data: HeaderData = {
|
|
382
471
|
text: toolsContent.innerHTML,
|
|
383
472
|
level: this.currentLevel.number,
|
|
384
473
|
};
|
|
385
474
|
|
|
475
|
+
/**
|
|
476
|
+
* Re-add arrow after reading so the DOM is not mutated
|
|
477
|
+
*/
|
|
478
|
+
if (arrowEl && this._data.isToggleable) {
|
|
479
|
+
toolsContent.prepend(arrowEl);
|
|
480
|
+
}
|
|
481
|
+
|
|
386
482
|
if (this._data.isToggleable === true) {
|
|
387
483
|
data.isToggleable = true;
|
|
388
484
|
}
|
|
@@ -426,7 +522,24 @@ export class Header implements BlockTool {
|
|
|
426
522
|
* @returns Current data
|
|
427
523
|
*/
|
|
428
524
|
public get data(): HeaderData {
|
|
525
|
+
/**
|
|
526
|
+
* Strip arrow element before reading innerHTML to avoid capturing toggle markup
|
|
527
|
+
*/
|
|
528
|
+
const arrowEl = this._element.querySelector(`[${TOGGLE_ATTR.toggleArrow}]`);
|
|
529
|
+
|
|
530
|
+
if (arrowEl) {
|
|
531
|
+
arrowEl.remove();
|
|
532
|
+
}
|
|
533
|
+
|
|
429
534
|
this._data.text = this._element.innerHTML;
|
|
535
|
+
|
|
536
|
+
/**
|
|
537
|
+
* Re-add arrow after reading so the DOM is not mutated
|
|
538
|
+
*/
|
|
539
|
+
if (arrowEl && this._data.isToggleable) {
|
|
540
|
+
this._element.prepend(arrowEl);
|
|
541
|
+
}
|
|
542
|
+
|
|
430
543
|
this._data.level = this.currentLevel.number;
|
|
431
544
|
|
|
432
545
|
return this._data;
|
|
@@ -568,25 +681,7 @@ export class Header implements BlockTool {
|
|
|
568
681
|
* @returns The arrow element
|
|
569
682
|
*/
|
|
570
683
|
private buildArrow(): HTMLElement {
|
|
571
|
-
|
|
572
|
-
arrow.className = ARROW_STYLES;
|
|
573
|
-
arrow.setAttribute(TOGGLE_ATTR.toggleArrow, '');
|
|
574
|
-
arrow.setAttribute('role', 'button');
|
|
575
|
-
arrow.setAttribute('tabindex', '-1');
|
|
576
|
-
arrow.setAttribute('aria-label', 'Expand');
|
|
577
|
-
arrow.contentEditable = 'false';
|
|
578
|
-
arrow.innerHTML = ARROW_ICON;
|
|
579
|
-
|
|
580
|
-
if (this._isOpen) {
|
|
581
|
-
arrow.style.transform = 'rotate(90deg)';
|
|
582
|
-
}
|
|
583
|
-
|
|
584
|
-
arrow.addEventListener('click', (event: MouseEvent) => {
|
|
585
|
-
event.stopPropagation();
|
|
586
|
-
this.toggleOpen();
|
|
587
|
-
});
|
|
588
|
-
|
|
589
|
-
return arrow;
|
|
684
|
+
return buildArrow(this._isOpen, () => this.toggleOpen(), { contentEditableFalse: true });
|
|
590
685
|
}
|
|
591
686
|
|
|
592
687
|
/**
|
|
@@ -596,6 +691,14 @@ export class Header implements BlockTool {
|
|
|
596
691
|
private toggleIsToggleable(): void {
|
|
597
692
|
const wasToggleable = this._data.isToggleable === true;
|
|
598
693
|
|
|
694
|
+
/**
|
|
695
|
+
* If disabling toggle, ensure children are visible before removing toggle state
|
|
696
|
+
*/
|
|
697
|
+
if (wasToggleable) {
|
|
698
|
+
updateChildrenVisibility(this.api, this.blockId ?? '', true);
|
|
699
|
+
this._isOpen = false;
|
|
700
|
+
}
|
|
701
|
+
|
|
599
702
|
this.data = {
|
|
600
703
|
level: this._data.level,
|
|
601
704
|
text: this._data.text,
|
package/src/tools/table/index.ts
CHANGED
|
@@ -71,6 +71,7 @@ const WRAPPER_EDIT_CLASSES = [
|
|
|
71
71
|
'after:left-0',
|
|
72
72
|
'after:right-0',
|
|
73
73
|
'after:h-10',
|
|
74
|
+
'after:pointer-events-none',
|
|
74
75
|
];
|
|
75
76
|
|
|
76
77
|
/**
|
|
@@ -405,9 +406,7 @@ export class Table implements BlockTool {
|
|
|
405
406
|
applyCellColors(gridEl, this.model.snapshot().content);
|
|
406
407
|
|
|
407
408
|
if (this.isNewTable) {
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
firstEditable?.focus();
|
|
409
|
+
this.cellSelection?.selectRange({ minRow: 0, maxRow: 0, minCol: 0, maxCol: 0 });
|
|
411
410
|
}
|
|
412
411
|
}
|
|
413
412
|
|
|
@@ -79,6 +79,7 @@ export class TableAddControls {
|
|
|
79
79
|
private dragState: DragState | null = null;
|
|
80
80
|
|
|
81
81
|
private boundMouseMove: (e: MouseEvent) => void;
|
|
82
|
+
private boundDocumentMouseMove: (e: MouseEvent) => void;
|
|
82
83
|
private boundMouseLeave: () => void;
|
|
83
84
|
private boundAddRowClick: () => void;
|
|
84
85
|
private boundAddColClick: () => void;
|
|
@@ -110,6 +111,7 @@ export class TableAddControls {
|
|
|
110
111
|
this.onDragEnd = options.onDragEnd;
|
|
111
112
|
this.getNewColumnWidth = options.getNewColumnWidth;
|
|
112
113
|
this.boundMouseMove = this.handleMouseMove.bind(this);
|
|
114
|
+
this.boundDocumentMouseMove = this.handleDocumentMouseMove.bind(this);
|
|
113
115
|
this.boundMouseLeave = this.handleMouseLeave.bind(this);
|
|
114
116
|
this.boundPointerMove = this.handlePointerMove.bind(this);
|
|
115
117
|
this.boundPointerUp = this.handlePointerUp.bind(this);
|
|
@@ -126,10 +128,10 @@ export class TableAddControls {
|
|
|
126
128
|
|
|
127
129
|
this.wrapper.addEventListener('mousemove', this.boundMouseMove);
|
|
128
130
|
this.wrapper.addEventListener('mouseleave', this.boundMouseLeave);
|
|
131
|
+
document.addEventListener('mousemove', this.boundDocumentMouseMove);
|
|
129
132
|
|
|
130
133
|
this.addRowBtn.addEventListener('pointerdown', this.boundRowPointerDown);
|
|
131
134
|
this.addColBtn.addEventListener('pointerdown', this.boundColPointerDown);
|
|
132
|
-
|
|
133
135
|
}
|
|
134
136
|
|
|
135
137
|
/**
|
|
@@ -212,6 +214,7 @@ export class TableAddControls {
|
|
|
212
214
|
public destroy(): void {
|
|
213
215
|
this.wrapper.removeEventListener('mousemove', this.boundMouseMove);
|
|
214
216
|
this.wrapper.removeEventListener('mouseleave', this.boundMouseLeave);
|
|
217
|
+
document.removeEventListener('mousemove', this.boundDocumentMouseMove);
|
|
215
218
|
this.addRowBtn.removeEventListener('pointerdown', this.boundRowPointerDown);
|
|
216
219
|
this.addColBtn.removeEventListener('pointerdown', this.boundColPointerDown);
|
|
217
220
|
|
|
@@ -399,6 +402,31 @@ export class TableAddControls {
|
|
|
399
402
|
this.scheduleHideCol();
|
|
400
403
|
}
|
|
401
404
|
|
|
405
|
+
/**
|
|
406
|
+
* Document-level mousemove handler.
|
|
407
|
+
* Catches mouse movements outside the wrapper (e.g. in the ::after
|
|
408
|
+
* pseudo-element zone below the grid, which has pointer-events-none).
|
|
409
|
+
* Only delegates to handleMouseMove when the cursor is within the
|
|
410
|
+
* proximity zone around the grid to avoid unnecessary work.
|
|
411
|
+
*/
|
|
412
|
+
private handleDocumentMouseMove(e: MouseEvent): void {
|
|
413
|
+
if (this.wrapper.contains(e.target as Node)) {
|
|
414
|
+
return;
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
const gridRect = this.grid.getBoundingClientRect();
|
|
418
|
+
const margin = PROXIMITY_PX;
|
|
419
|
+
const nearGrid =
|
|
420
|
+
e.clientX >= gridRect.left - margin &&
|
|
421
|
+
e.clientX <= gridRect.right + margin &&
|
|
422
|
+
e.clientY >= gridRect.top - margin &&
|
|
423
|
+
e.clientY <= gridRect.bottom + margin;
|
|
424
|
+
|
|
425
|
+
if (nearGrid) {
|
|
426
|
+
this.handleMouseMove(e);
|
|
427
|
+
}
|
|
428
|
+
}
|
|
429
|
+
|
|
402
430
|
private showRow(): void {
|
|
403
431
|
this.clearRowTimeout();
|
|
404
432
|
|
|
@@ -86,6 +86,9 @@ export class TableCellBlocks {
|
|
|
86
86
|
/** Events deferred during structural operations, replayed or discarded afterward. */
|
|
87
87
|
private deferredEvents: Array<unknown> = [];
|
|
88
88
|
|
|
89
|
+
/** When true, handleBlockMutation skips claiming so exitTableForward's new block stays outside the grid. */
|
|
90
|
+
private isExitingTable = false;
|
|
91
|
+
|
|
89
92
|
constructor(options: TableCellBlocksOptions) {
|
|
90
93
|
this.api = options.api;
|
|
91
94
|
this.gridElement = options.gridElement;
|
|
@@ -140,6 +143,12 @@ export class TableCellBlocks {
|
|
|
140
143
|
|
|
141
144
|
return;
|
|
142
145
|
}
|
|
146
|
+
|
|
147
|
+
// ArrowDown at last row -> exit table
|
|
148
|
+
if (event.key === 'ArrowDown' && position.row === this.getRowCount() - 1) {
|
|
149
|
+
event.preventDefault();
|
|
150
|
+
this.exitTableForward();
|
|
151
|
+
}
|
|
143
152
|
}
|
|
144
153
|
|
|
145
154
|
/**
|
|
@@ -161,7 +170,12 @@ export class TableCellBlocks {
|
|
|
161
170
|
|
|
162
171
|
if (nextRow < this.getRowCount()) {
|
|
163
172
|
this.navigateToCell({ row: nextRow, col: 0 });
|
|
173
|
+
|
|
174
|
+
return;
|
|
164
175
|
}
|
|
176
|
+
|
|
177
|
+
// At the very last cell — exit the table by focusing or creating a block below
|
|
178
|
+
this.exitTableForward();
|
|
165
179
|
}
|
|
166
180
|
|
|
167
181
|
/**
|
|
@@ -182,7 +196,82 @@ export class TableCellBlocks {
|
|
|
182
196
|
|
|
183
197
|
if (prevRow >= 0) {
|
|
184
198
|
this.navigateToCell({ row: prevRow, col: this.getColumnCount() - 1 }, true);
|
|
199
|
+
|
|
200
|
+
return;
|
|
185
201
|
}
|
|
202
|
+
|
|
203
|
+
// At the very first cell — exit the table by focusing the block above
|
|
204
|
+
this.exitTableBackward();
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
/**
|
|
208
|
+
* Exit the table by focusing the first block after it, or creating one if none exists.
|
|
209
|
+
*/
|
|
210
|
+
private exitTableForward(): void {
|
|
211
|
+
const tableIndex = this.api.blocks.getBlockIndex(this.tableBlockId);
|
|
212
|
+
|
|
213
|
+
if (tableIndex === undefined) {
|
|
214
|
+
return;
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
const blockAfterTable = this.findFirstBlockAfterTable(tableIndex);
|
|
218
|
+
|
|
219
|
+
if (blockAfterTable !== null) {
|
|
220
|
+
this.api.caret.setToBlock(blockAfterTable.id, 'start');
|
|
221
|
+
|
|
222
|
+
return;
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
/**
|
|
226
|
+
* No block after the table — create a new default block.
|
|
227
|
+
* Set isExitingTable so handleBlockMutation does not claim the new block
|
|
228
|
+
* into a cell (the block-added event fires synchronously during insert).
|
|
229
|
+
*/
|
|
230
|
+
this.isExitingTable = true;
|
|
231
|
+
|
|
232
|
+
try {
|
|
233
|
+
const totalBlocks = this.api.blocks.getBlocksCount();
|
|
234
|
+
const newBlock = this.api.blocks.insert(undefined, {}, {}, totalBlocks, true);
|
|
235
|
+
|
|
236
|
+
this.api.caret.setToBlock(newBlock.id, 'start');
|
|
237
|
+
} finally {
|
|
238
|
+
this.isExitingTable = false;
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
/**
|
|
243
|
+
* Exit the table backward by focusing the block before the table.
|
|
244
|
+
* If no block exists before the table, do nothing.
|
|
245
|
+
*/
|
|
246
|
+
private exitTableBackward(): void {
|
|
247
|
+
const tableIndex = this.api.blocks.getBlockIndex(this.tableBlockId);
|
|
248
|
+
|
|
249
|
+
if (tableIndex === undefined || tableIndex === 0) {
|
|
250
|
+
return;
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
// The block immediately before the table in the flat array
|
|
254
|
+
const blockBefore = this.api.blocks.getBlockByIndex(tableIndex - 1);
|
|
255
|
+
|
|
256
|
+
if (blockBefore) {
|
|
257
|
+
this.api.caret.setToBlock(blockBefore.id, 'end');
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
/**
|
|
262
|
+
* Scan the flat block array starting after the table block, skipping all blocks
|
|
263
|
+
* whose holder is inside the table grid, and return the first non-child block.
|
|
264
|
+
* Returns null if no such block exists.
|
|
265
|
+
*/
|
|
266
|
+
private findFirstBlockAfterTable(tableIndex: number): { id: string } | null {
|
|
267
|
+
const totalBlocks = this.api.blocks.getBlocksCount();
|
|
268
|
+
const candidates = Array.from({ length: totalBlocks - tableIndex - 1 }, (_, offset) =>
|
|
269
|
+
this.api.blocks.getBlockByIndex(tableIndex + 1 + offset)
|
|
270
|
+
);
|
|
271
|
+
|
|
272
|
+
return candidates.find(block =>
|
|
273
|
+
block !== null && block !== undefined && !this.gridElement.contains(block.holder)
|
|
274
|
+
) ?? null;
|
|
186
275
|
}
|
|
187
276
|
|
|
188
277
|
/**
|
|
@@ -481,6 +570,10 @@ export class TableCellBlocks {
|
|
|
481
570
|
return;
|
|
482
571
|
}
|
|
483
572
|
|
|
573
|
+
if (this.isExitingTable) {
|
|
574
|
+
return;
|
|
575
|
+
}
|
|
576
|
+
|
|
484
577
|
if (!this.isBlockMutationEvent(data)) {
|
|
485
578
|
return;
|
|
486
579
|
}
|
|
@@ -32,12 +32,12 @@ export const TOGGLE_WRAPPER_STYLES = 'flex items-start';
|
|
|
32
32
|
/**
|
|
33
33
|
* Styles for the toggle arrow button
|
|
34
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';
|
|
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 focus-visible:ring-2 focus-visible:ring-blue-500 focus-visible:outline-none';
|
|
36
36
|
|
|
37
37
|
/**
|
|
38
38
|
* SVG icon for the toggle arrow
|
|
39
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>';
|
|
40
|
+
export const ARROW_ICON = '<svg aria-hidden="true" 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
41
|
|
|
42
42
|
/**
|
|
43
43
|
* Data attributes specific to the toggle tool
|
|
@@ -70,20 +70,39 @@ export const buildToggleItem = (context: ToggleDOMBuilderContext): ToggleBuildRe
|
|
|
70
70
|
return { wrapper, arrowElement, contentElement };
|
|
71
71
|
};
|
|
72
72
|
|
|
73
|
+
/**
|
|
74
|
+
* Options for building arrow element
|
|
75
|
+
*/
|
|
76
|
+
export interface BuildArrowOptions {
|
|
77
|
+
/** Set contentEditable="false" on the arrow (used by Header to prevent caret entering arrow) */
|
|
78
|
+
contentEditableFalse?: boolean;
|
|
79
|
+
}
|
|
80
|
+
|
|
73
81
|
/**
|
|
74
82
|
* Build the arrow element for toggling open/closed state.
|
|
75
83
|
*
|
|
76
84
|
* @param isOpen - Whether the toggle is currently open
|
|
77
85
|
* @param onArrowClick - Callback when arrow is clicked
|
|
86
|
+
* @param options - Optional configuration
|
|
78
87
|
* @returns The arrow element
|
|
79
88
|
*/
|
|
80
|
-
const buildArrow = (
|
|
81
|
-
|
|
89
|
+
export const buildArrow = (
|
|
90
|
+
isOpen: boolean,
|
|
91
|
+
onArrowClick: () => void,
|
|
92
|
+
options: BuildArrowOptions = {}
|
|
93
|
+
): HTMLElement => {
|
|
94
|
+
const arrow = document.createElement('span');
|
|
82
95
|
arrow.className = ARROW_STYLES;
|
|
83
96
|
arrow.setAttribute(TOGGLE_ATTR.toggleArrow, '');
|
|
84
97
|
arrow.setAttribute('role', 'button');
|
|
85
|
-
arrow.setAttribute('tabindex', '
|
|
86
|
-
arrow.setAttribute('aria-label', '
|
|
98
|
+
arrow.setAttribute('tabindex', '0');
|
|
99
|
+
arrow.setAttribute('aria-label', isOpen ? 'Collapse' : 'Expand');
|
|
100
|
+
arrow.setAttribute('aria-expanded', String(isOpen));
|
|
101
|
+
|
|
102
|
+
if (options.contentEditableFalse === true) {
|
|
103
|
+
arrow.contentEditable = 'false';
|
|
104
|
+
}
|
|
105
|
+
|
|
87
106
|
arrow.innerHTML = ARROW_ICON;
|
|
88
107
|
|
|
89
108
|
if (isOpen) {
|
|
@@ -95,6 +114,14 @@ const buildArrow = (isOpen: boolean, onArrowClick: () => void): HTMLElement => {
|
|
|
95
114
|
onArrowClick();
|
|
96
115
|
});
|
|
97
116
|
|
|
117
|
+
arrow.addEventListener('keydown', (event: KeyboardEvent) => {
|
|
118
|
+
if (event.key === 'Enter' || event.key === ' ') {
|
|
119
|
+
event.preventDefault();
|
|
120
|
+
event.stopPropagation();
|
|
121
|
+
onArrowClick();
|
|
122
|
+
}
|
|
123
|
+
});
|
|
124
|
+
|
|
98
125
|
return arrow;
|
|
99
126
|
};
|
|
100
127
|
|