@jackuait/blok 0.6.0-beta.13 → 0.6.0-beta.14
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-DzeTRJ_i.mjs → blok-Cl30YOLl.mjs} +1398 -1132
- package/dist/chunks/{i18next-loader-CgW4H90H.mjs → i18next-loader-DbTDlMux.mjs} +1 -1
- package/dist/chunks/{index-BWKk7PIS.mjs → index-DJmaYswj.mjs} +1 -1
- package/dist/chunks/{inline-tool-convert-DrSwadw_.mjs → inline-tool-convert-MjSaP8r7.mjs} +161 -145
- package/dist/{messages-B1Aww8q7.mjs → chunks/messages-1mYyrppy.mjs} +1 -0
- package/dist/chunks/{messages-DnIhyAJk.mjs → messages-4gHfbcDp.mjs} +1 -0
- package/dist/{messages-CQwpzUFp.mjs → chunks/messages-6xYv-U8A.mjs} +1 -0
- package/dist/chunks/{messages-CMkNSDTo.mjs → messages-7jqF79FO.mjs} +1 -0
- package/dist/chunks/{messages-BSbjsyHY.mjs → messages-B3EUuA7o.mjs} +1 -0
- package/dist/{messages-LPVfA-8K.mjs → chunks/messages-B6srtRn7.mjs} +1 -0
- package/dist/chunks/{messages-DJDG55Vq.mjs → messages-B85OIs0E.mjs} +1 -0
- package/dist/{messages-_ErNTNhk.mjs → chunks/messages-BCYBBG_u.mjs} +1 -0
- package/dist/{messages-CZygwLwM.mjs → chunks/messages-BDLNPiaW.mjs} +1 -0
- package/dist/{messages-C2htQ_3F.mjs → chunks/messages-BKpNd1Zb.mjs} +1 -0
- package/dist/chunks/{messages-CnwibSvh.mjs → messages-BLFUid_o.mjs} +1 -0
- package/dist/{messages-CVw84KdI.mjs → chunks/messages-BNPTVKnc.mjs} +1 -0
- package/dist/{messages-BMv4xwIr.mjs → chunks/messages-BQPXSkri.mjs} +1 -0
- package/dist/{messages-Dz9L52ol.mjs → chunks/messages-BQu6VNDq.mjs} +1 -0
- package/dist/{messages-DprmQg6V.mjs → chunks/messages-BRodFKUo.mjs} +1 -0
- package/dist/{messages-CznZadDf.mjs → chunks/messages-BWIikA8H.mjs} +1 -0
- package/dist/{messages-CqWJcCbY.mjs → chunks/messages-BXQvMilx.mjs} +1 -0
- package/dist/chunks/{messages-Z9nEU2xK.mjs → messages-BZ92luiw.mjs} +1 -0
- package/dist/chunks/{messages-BC86qLvI.mjs → messages-Bg0Phlcj.mjs} +1 -0
- package/dist/chunks/{messages-DnXLrlHh.mjs → messages-Bh6RBIu5.mjs} +1 -0
- package/dist/chunks/{messages-DhLKYm2j.mjs → messages-BnFHdIpg.mjs} +1 -0
- package/dist/{messages-BU2nlrLK.mjs → chunks/messages-Bq82EVsw.mjs} +1 -0
- package/dist/chunks/{messages-Diu6jAaR.mjs → messages-BxbcTiHh.mjs} +1 -0
- package/dist/{messages-BoJc_p1r.mjs → chunks/messages-ByO6bSV2.mjs} +1 -0
- package/dist/chunks/{messages-BrPFGbM-.mjs → messages-ByUNPiQ4.mjs} +1 -0
- package/dist/chunks/{messages-BB5z9Uba.mjs → messages-Byw0EHyf.mjs} +1 -0
- package/dist/chunks/{messages-D1Hv8XGo.mjs → messages-C-aP90zq.mjs} +1 -0
- package/dist/chunks/{messages-DBRw-7Zc.mjs → messages-C2f44jci.mjs} +1 -0
- package/dist/chunks/{messages-CJdUsQ-c.mjs → messages-CKYoAmm9.mjs} +1 -0
- package/dist/chunks/{messages-CvGLfqmV.mjs → messages-CSQJrJ_N.mjs} +1 -0
- package/dist/chunks/{messages-1fC8IMyX.mjs → messages-CX_o4Cgc.mjs} +1 -0
- package/dist/chunks/{messages-BdeLo0N9.mjs → messages-C_tfXllT.mjs} +1 -0
- package/dist/chunks/{messages-DBn76jVV.mjs → messages-Cj6TZ_By.mjs} +1 -0
- package/dist/{messages-CLhcMlTc.mjs → chunks/messages-CjdYkfzj.mjs} +1 -0
- package/dist/{messages-7W4d0DwD.mjs → chunks/messages-CmvWFWR6.mjs} +1 -0
- package/dist/{messages-CzTufCHu.mjs → chunks/messages-CnV-kxh6.mjs} +1 -0
- package/dist/chunks/{messages-BMXCuEKO.mjs → messages-CpuDfpdi.mjs} +1 -0
- package/dist/chunks/{messages-DT4dP5uK.mjs → messages-Cspe1oXk.mjs} +1 -0
- package/dist/{messages-D-ZtY5v0.mjs → chunks/messages-D2_d-Jt4.mjs} +1 -0
- package/dist/{messages-BELRf6DU.mjs → chunks/messages-DADSbW8l.mjs} +1 -0
- package/dist/chunks/{messages-O5tQus_0.mjs → messages-DHSeTQ4S.mjs} +1 -0
- package/dist/{messages-BFG6Wlgy.mjs → chunks/messages-DKeO2RsW.mjs} +1 -0
- package/dist/chunks/{messages-9SihnaXQ.mjs → messages-DLdlX_dY.mjs} +1 -0
- package/dist/chunks/{messages-BL0tXcDf.mjs → messages-DVxlJ4DU.mjs} +1 -0
- package/dist/chunks/{messages-CY8_RyFE.mjs → messages-DWSxENRk.mjs} +1 -0
- package/dist/{messages-Q7AO_FLv.mjs → chunks/messages-D_bVNZ12.mjs} +1 -0
- package/dist/chunks/{messages-BYyy6Wqf.mjs → messages-DdzjVwmG.mjs} +1 -0
- package/dist/chunks/{messages-DLfR5bMd.mjs → messages-DhyBKTi0.mjs} +1 -0
- package/dist/chunks/{messages-DvFLX36Q.mjs → messages-DlC9jDXa.mjs} +1 -0
- package/dist/chunks/{messages-D5C3J9qr.mjs → messages-DmBGk8ed.mjs} +1 -0
- package/dist/chunks/{messages-R3hUSvr3.mjs → messages-Dm_VqpU6.mjs} +1 -0
- package/dist/chunks/{messages-w7v1GNaE.mjs → messages-Dn9hI_ER.mjs} +1 -0
- package/dist/{messages-uKX8WBaD.mjs → chunks/messages-Dssp4AXT.mjs} +1 -0
- package/dist/chunks/{messages-Xq8UmkVs.mjs → messages-DzCc0JgS.mjs} +1 -0
- package/dist/chunks/{messages-JELdtT6E.mjs → messages-N6THNxo0.mjs} +1 -0
- package/dist/chunks/{messages-DqM1LFg5.mjs → messages-OctOxF2l.mjs} +1 -0
- package/dist/chunks/{messages-_ncGrKHh.mjs → messages-QT3JA95K.mjs} +1 -0
- package/dist/{messages-C9eaarcK.mjs → chunks/messages-QqWK83BF.mjs} +1 -0
- package/dist/chunks/{messages-BogRq8lt.mjs → messages-RsGaDzbb.mjs} +1 -0
- package/dist/chunks/{messages-Dzwxv9v1.mjs → messages-c7YlI6Wm.mjs} +1 -0
- package/dist/{messages-D5iv1Kox.mjs → chunks/messages-lZ8aF-4r.mjs} +1 -0
- package/dist/chunks/{messages-7QoX8DkW.mjs → messages-uGDrchjb.mjs} +1 -0
- package/dist/chunks/{messages-CKI54h6O.mjs → messages-xc2yNvog.mjs} +1 -0
- package/dist/{messages-Bmu_S7GM.mjs → chunks/messages-y5Q-ymIx.mjs} +1 -0
- package/dist/{messages-BWF-zUpY.mjs → chunks/messages-yJnyedAd.mjs} +1 -0
- package/dist/{messages-kep5wtm4.mjs → chunks/messages-yQ_4upHh.mjs} +1 -0
- package/dist/chunks/{messages-C99mq906.mjs → messages-ysbWD56Q.mjs} +1 -0
- package/dist/full.mjs +2 -2
- package/dist/locales.mjs +68 -67
- package/dist/{chunks/messages-B1Aww8q7.mjs → messages-1mYyrppy.mjs} +1 -0
- package/dist/{messages-DnIhyAJk.mjs → messages-4gHfbcDp.mjs} +1 -0
- package/dist/{chunks/messages-CQwpzUFp.mjs → messages-6xYv-U8A.mjs} +1 -0
- package/dist/{messages-CMkNSDTo.mjs → messages-7jqF79FO.mjs} +1 -0
- package/dist/{messages-BSbjsyHY.mjs → messages-B3EUuA7o.mjs} +1 -0
- package/dist/{chunks/messages-LPVfA-8K.mjs → messages-B6srtRn7.mjs} +1 -0
- package/dist/{messages-DJDG55Vq.mjs → messages-B85OIs0E.mjs} +1 -0
- package/dist/{chunks/messages-_ErNTNhk.mjs → messages-BCYBBG_u.mjs} +1 -0
- package/dist/{chunks/messages-CZygwLwM.mjs → messages-BDLNPiaW.mjs} +1 -0
- package/dist/{chunks/messages-C2htQ_3F.mjs → messages-BKpNd1Zb.mjs} +1 -0
- package/dist/{messages-CnwibSvh.mjs → messages-BLFUid_o.mjs} +1 -0
- package/dist/{chunks/messages-CVw84KdI.mjs → messages-BNPTVKnc.mjs} +1 -0
- package/dist/{chunks/messages-BMv4xwIr.mjs → messages-BQPXSkri.mjs} +1 -0
- package/dist/{chunks/messages-Dz9L52ol.mjs → messages-BQu6VNDq.mjs} +1 -0
- package/dist/{chunks/messages-DprmQg6V.mjs → messages-BRodFKUo.mjs} +1 -0
- package/dist/{chunks/messages-CznZadDf.mjs → messages-BWIikA8H.mjs} +1 -0
- package/dist/{chunks/messages-CqWJcCbY.mjs → messages-BXQvMilx.mjs} +1 -0
- package/dist/{messages-Z9nEU2xK.mjs → messages-BZ92luiw.mjs} +1 -0
- package/dist/{messages-BC86qLvI.mjs → messages-Bg0Phlcj.mjs} +1 -0
- package/dist/{messages-DnXLrlHh.mjs → messages-Bh6RBIu5.mjs} +1 -0
- package/dist/{messages-DhLKYm2j.mjs → messages-BnFHdIpg.mjs} +1 -0
- package/dist/{chunks/messages-BU2nlrLK.mjs → messages-Bq82EVsw.mjs} +1 -0
- package/dist/{messages-Diu6jAaR.mjs → messages-BxbcTiHh.mjs} +1 -0
- package/dist/{chunks/messages-BoJc_p1r.mjs → messages-ByO6bSV2.mjs} +1 -0
- package/dist/{messages-BrPFGbM-.mjs → messages-ByUNPiQ4.mjs} +1 -0
- package/dist/{messages-BB5z9Uba.mjs → messages-Byw0EHyf.mjs} +1 -0
- package/dist/{messages-D1Hv8XGo.mjs → messages-C-aP90zq.mjs} +1 -0
- package/dist/{messages-DBRw-7Zc.mjs → messages-C2f44jci.mjs} +1 -0
- package/dist/{messages-CJdUsQ-c.mjs → messages-CKYoAmm9.mjs} +1 -0
- package/dist/{messages-CvGLfqmV.mjs → messages-CSQJrJ_N.mjs} +1 -0
- package/dist/{messages-1fC8IMyX.mjs → messages-CX_o4Cgc.mjs} +1 -0
- package/dist/{messages-BdeLo0N9.mjs → messages-C_tfXllT.mjs} +1 -0
- package/dist/{messages-DBn76jVV.mjs → messages-Cj6TZ_By.mjs} +1 -0
- package/dist/{chunks/messages-CLhcMlTc.mjs → messages-CjdYkfzj.mjs} +1 -0
- package/dist/{chunks/messages-7W4d0DwD.mjs → messages-CmvWFWR6.mjs} +1 -0
- package/dist/{chunks/messages-CzTufCHu.mjs → messages-CnV-kxh6.mjs} +1 -0
- package/dist/{messages-BMXCuEKO.mjs → messages-CpuDfpdi.mjs} +1 -0
- package/dist/{messages-DT4dP5uK.mjs → messages-Cspe1oXk.mjs} +1 -0
- package/dist/{chunks/messages-D-ZtY5v0.mjs → messages-D2_d-Jt4.mjs} +1 -0
- package/dist/{chunks/messages-BELRf6DU.mjs → messages-DADSbW8l.mjs} +1 -0
- package/dist/{messages-O5tQus_0.mjs → messages-DHSeTQ4S.mjs} +1 -0
- package/dist/{chunks/messages-BFG6Wlgy.mjs → messages-DKeO2RsW.mjs} +1 -0
- package/dist/{messages-9SihnaXQ.mjs → messages-DLdlX_dY.mjs} +1 -0
- package/dist/{messages-BL0tXcDf.mjs → messages-DVxlJ4DU.mjs} +1 -0
- package/dist/{messages-CY8_RyFE.mjs → messages-DWSxENRk.mjs} +1 -0
- package/dist/{chunks/messages-Q7AO_FLv.mjs → messages-D_bVNZ12.mjs} +1 -0
- package/dist/{messages-BYyy6Wqf.mjs → messages-DdzjVwmG.mjs} +1 -0
- package/dist/{messages-DLfR5bMd.mjs → messages-DhyBKTi0.mjs} +1 -0
- package/dist/{messages-DvFLX36Q.mjs → messages-DlC9jDXa.mjs} +1 -0
- package/dist/{messages-D5C3J9qr.mjs → messages-DmBGk8ed.mjs} +1 -0
- package/dist/{messages-R3hUSvr3.mjs → messages-Dm_VqpU6.mjs} +1 -0
- package/dist/{messages-w7v1GNaE.mjs → messages-Dn9hI_ER.mjs} +1 -0
- package/dist/{chunks/messages-uKX8WBaD.mjs → messages-Dssp4AXT.mjs} +1 -0
- package/dist/{messages-Xq8UmkVs.mjs → messages-DzCc0JgS.mjs} +1 -0
- package/dist/{messages-JELdtT6E.mjs → messages-N6THNxo0.mjs} +1 -0
- package/dist/{messages-DqM1LFg5.mjs → messages-OctOxF2l.mjs} +1 -0
- package/dist/{messages-_ncGrKHh.mjs → messages-QT3JA95K.mjs} +1 -0
- package/dist/{chunks/messages-C9eaarcK.mjs → messages-QqWK83BF.mjs} +1 -0
- package/dist/{messages-BogRq8lt.mjs → messages-RsGaDzbb.mjs} +1 -0
- package/dist/{messages-Dzwxv9v1.mjs → messages-c7YlI6Wm.mjs} +1 -0
- package/dist/{chunks/messages-D5iv1Kox.mjs → messages-lZ8aF-4r.mjs} +1 -0
- package/dist/{messages-7QoX8DkW.mjs → messages-uGDrchjb.mjs} +1 -0
- package/dist/{messages-CKI54h6O.mjs → messages-xc2yNvog.mjs} +1 -0
- package/dist/{chunks/messages-Bmu_S7GM.mjs → messages-y5Q-ymIx.mjs} +1 -0
- package/dist/{chunks/messages-BWF-zUpY.mjs → messages-yJnyedAd.mjs} +1 -0
- package/dist/{chunks/messages-kep5wtm4.mjs → messages-yQ_4upHh.mjs} +1 -0
- package/dist/{messages-C99mq906.mjs → messages-ysbWD56Q.mjs} +1 -0
- package/dist/tools.mjs +887 -701
- package/package.json +2 -1
- package/src/components/block/style-manager.ts +5 -1
- package/src/components/blocks.ts +109 -9
- package/src/components/i18n/locales/am/messages.json +1 -0
- package/src/components/i18n/locales/ar/messages.json +1 -0
- package/src/components/i18n/locales/az/messages.json +1 -0
- package/src/components/i18n/locales/bg/messages.json +1 -0
- package/src/components/i18n/locales/bn/messages.json +1 -0
- package/src/components/i18n/locales/bs/messages.json +1 -0
- package/src/components/i18n/locales/cs/messages.json +1 -0
- package/src/components/i18n/locales/da/messages.json +1 -0
- package/src/components/i18n/locales/de/messages.json +1 -0
- package/src/components/i18n/locales/dv/messages.json +1 -0
- package/src/components/i18n/locales/el/messages.json +1 -0
- package/src/components/i18n/locales/en/messages.json +1 -0
- package/src/components/i18n/locales/es/messages.json +1 -0
- package/src/components/i18n/locales/et/messages.json +1 -0
- package/src/components/i18n/locales/fa/messages.json +1 -0
- package/src/components/i18n/locales/fi/messages.json +1 -0
- package/src/components/i18n/locales/fil/messages.json +1 -0
- package/src/components/i18n/locales/fr/messages.json +1 -0
- package/src/components/i18n/locales/gu/messages.json +1 -0
- package/src/components/i18n/locales/he/messages.json +1 -0
- package/src/components/i18n/locales/hi/messages.json +1 -0
- package/src/components/i18n/locales/hr/messages.json +1 -0
- package/src/components/i18n/locales/hu/messages.json +1 -0
- package/src/components/i18n/locales/hy/messages.json +1 -0
- package/src/components/i18n/locales/id/messages.json +1 -0
- package/src/components/i18n/locales/it/messages.json +1 -0
- package/src/components/i18n/locales/ja/messages.json +1 -0
- package/src/components/i18n/locales/ka/messages.json +1 -0
- package/src/components/i18n/locales/km/messages.json +1 -0
- package/src/components/i18n/locales/kn/messages.json +1 -0
- package/src/components/i18n/locales/ko/messages.json +1 -0
- package/src/components/i18n/locales/ku/messages.json +1 -0
- package/src/components/i18n/locales/lo/messages.json +1 -0
- package/src/components/i18n/locales/lt/messages.json +1 -0
- package/src/components/i18n/locales/lv/messages.json +1 -0
- package/src/components/i18n/locales/mk/messages.json +1 -0
- package/src/components/i18n/locales/ml/messages.json +1 -0
- package/src/components/i18n/locales/mn/messages.json +1 -0
- package/src/components/i18n/locales/mr/messages.json +1 -0
- package/src/components/i18n/locales/ms/messages.json +1 -0
- package/src/components/i18n/locales/my/messages.json +1 -0
- package/src/components/i18n/locales/ne/messages.json +1 -0
- package/src/components/i18n/locales/nl/messages.json +1 -0
- package/src/components/i18n/locales/no/messages.json +1 -0
- package/src/components/i18n/locales/pa/messages.json +1 -0
- package/src/components/i18n/locales/pl/messages.json +1 -0
- package/src/components/i18n/locales/ps/messages.json +1 -0
- package/src/components/i18n/locales/pt/messages.json +1 -0
- package/src/components/i18n/locales/ro/messages.json +1 -0
- package/src/components/i18n/locales/ru/messages.json +1 -0
- package/src/components/i18n/locales/sd/messages.json +1 -0
- package/src/components/i18n/locales/si/messages.json +1 -0
- package/src/components/i18n/locales/sk/messages.json +1 -0
- package/src/components/i18n/locales/sl/messages.json +1 -0
- package/src/components/i18n/locales/sq/messages.json +1 -0
- package/src/components/i18n/locales/sr/messages.json +1 -0
- package/src/components/i18n/locales/sv/messages.json +1 -0
- package/src/components/i18n/locales/sw/messages.json +1 -0
- package/src/components/i18n/locales/ta/messages.json +1 -0
- package/src/components/i18n/locales/te/messages.json +1 -0
- package/src/components/i18n/locales/th/messages.json +1 -0
- package/src/components/i18n/locales/tr/messages.json +1 -0
- package/src/components/i18n/locales/ug/messages.json +1 -0
- package/src/components/i18n/locales/uk/messages.json +1 -0
- package/src/components/i18n/locales/ur/messages.json +1 -0
- package/src/components/i18n/locales/vi/messages.json +1 -0
- package/src/components/i18n/locales/yi/messages.json +1 -0
- package/src/components/i18n/locales/zh/messages.json +1 -0
- package/src/components/icons/index.ts +8 -0
- package/src/components/modules/blockEvents/composers/keyboardNavigation.ts +51 -10
- package/src/components/modules/blockEvents/index.ts +2 -5
- package/src/components/modules/blockManager/blockManager.ts +10 -0
- package/src/components/modules/blockManager/operations.ts +11 -0
- package/src/components/modules/blockManager/repository.ts +22 -0
- package/src/components/modules/blockManager/yjs-sync.ts +148 -31
- package/src/components/modules/crossBlockSelection.ts +11 -3
- package/src/components/modules/drag/preview/DragPreview.ts +8 -0
- package/src/components/modules/drag/target/DropTargetDetector.ts +100 -11
- package/src/components/modules/paste/handlers/base.ts +3 -4
- package/src/components/modules/paste/index.ts +1 -1
- package/src/components/modules/rectangleSelection.ts +5 -2
- package/src/components/modules/toolbar/blockSettings.ts +52 -44
- package/src/components/modules/toolbar/index.ts +27 -7
- package/src/components/modules/toolbar/inline/index.ts +1 -1
- 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 +4 -2
- package/src/components/modules/yjs/types.ts +8 -6
- package/src/components/utils/popover/components/popover-item/popover-item-default/popover-item-default.ts +6 -4
- package/src/components/utils/popover/popover-desktop.ts +12 -0
- package/src/stories/Popover.stories.ts +0 -2
- package/src/styles/main.css +9 -1
- package/src/tools/list/caret-manager.ts +28 -10
- package/src/tools/table/index.ts +180 -37
- package/src/tools/table/table-add-controls.ts +51 -14
- package/src/tools/table/table-cell-blocks.ts +41 -2
- package/src/tools/table/table-cell-selection.ts +27 -1
- package/src/tools/table/table-operations.ts +12 -15
- package/src/tools/table/table-row-col-controls.ts +69 -6
- package/src/tools/table/table-scroll-haze.ts +152 -0
package/src/tools/table/index.ts
CHANGED
|
@@ -47,6 +47,7 @@ import type { PendingHighlight } from './table-row-col-action-handler';
|
|
|
47
47
|
import { TableRowColControls } from './table-row-col-controls';
|
|
48
48
|
import type { RowColAction } from './table-row-col-controls';
|
|
49
49
|
import { registerAdditionalRestrictedTools } from './table-restrictions';
|
|
50
|
+
import { TableScrollHaze } from './table-scroll-haze';
|
|
50
51
|
import type { ClipboardBlockData, LegacyCellContent, TableCellsClipboard, TableData, TableConfig } from './types';
|
|
51
52
|
|
|
52
53
|
const DEFAULT_ROWS = 3;
|
|
@@ -59,6 +60,12 @@ const WRAPPER_CLASSES = [
|
|
|
59
60
|
|
|
60
61
|
const WRAPPER_EDIT_CLASSES = [
|
|
61
62
|
'relative',
|
|
63
|
+
'after:content-[""]',
|
|
64
|
+
'after:absolute',
|
|
65
|
+
'after:-bottom-10',
|
|
66
|
+
'after:left-0',
|
|
67
|
+
'after:right-0',
|
|
68
|
+
'after:h-10',
|
|
62
69
|
];
|
|
63
70
|
|
|
64
71
|
/**
|
|
@@ -77,7 +84,11 @@ export class Table implements BlockTool {
|
|
|
77
84
|
private rowColControls: TableRowColControls | null = null;
|
|
78
85
|
private cellBlocks: TableCellBlocks | null = null;
|
|
79
86
|
private cellSelection: TableCellSelection | null = null;
|
|
87
|
+
private scrollHaze: TableScrollHaze | null = null;
|
|
80
88
|
private element: HTMLDivElement | null = null;
|
|
89
|
+
private gridElement: HTMLElement | null = null;
|
|
90
|
+
private scrollContainer: HTMLDivElement | null = null;
|
|
91
|
+
private gripOverlay: HTMLDivElement | null = null;
|
|
81
92
|
private blockId: string | undefined;
|
|
82
93
|
private pendingHighlight: PendingHighlight | null = null;
|
|
83
94
|
private isNewTable = false;
|
|
@@ -145,16 +156,19 @@ export class Table implements BlockTool {
|
|
|
145
156
|
* Execute a structural operation within a Yjs transaction.
|
|
146
157
|
* Combines the structural op lock (event deferral) with Yjs undo grouping.
|
|
147
158
|
* Used for interactive operations that should be a single undo entry.
|
|
159
|
+
*
|
|
160
|
+
* @param fn - The structural operation to execute
|
|
161
|
+
* @param discard - If true, discard deferred events (forwarded to runStructuralOp)
|
|
148
162
|
*/
|
|
149
|
-
private runTransactedStructuralOp<T>(fn: () => T): T {
|
|
163
|
+
private runTransactedStructuralOp<T>(fn: () => T, discard = false): T {
|
|
150
164
|
if (!this.api.blocks.transact) {
|
|
151
|
-
return this.runStructuralOp(fn);
|
|
165
|
+
return this.runStructuralOp(fn, discard);
|
|
152
166
|
}
|
|
153
167
|
|
|
154
168
|
const ref = { current: undefined as T | undefined };
|
|
155
169
|
|
|
156
170
|
this.api.blocks.transact(() => {
|
|
157
|
-
ref.current = this.runStructuralOp(fn);
|
|
171
|
+
ref.current = this.runStructuralOp(fn, discard);
|
|
158
172
|
});
|
|
159
173
|
|
|
160
174
|
return ref.current as T;
|
|
@@ -174,6 +188,8 @@ export class Table implements BlockTool {
|
|
|
174
188
|
this.rowColControls = null;
|
|
175
189
|
this.cellSelection?.destroy();
|
|
176
190
|
this.cellSelection = null;
|
|
191
|
+
this.scrollHaze?.destroy();
|
|
192
|
+
this.scrollHaze = null;
|
|
177
193
|
}
|
|
178
194
|
|
|
179
195
|
/**
|
|
@@ -187,6 +203,7 @@ export class Table implements BlockTool {
|
|
|
187
203
|
this.initRowColControls(gridEl);
|
|
188
204
|
this.initCellSelection(gridEl);
|
|
189
205
|
this.initGridPasteListener(gridEl);
|
|
206
|
+
this.initScrollHaze();
|
|
190
207
|
}
|
|
191
208
|
|
|
192
209
|
public static get toolbox(): ToolboxConfig {
|
|
@@ -224,10 +241,35 @@ export class Table implements BlockTool {
|
|
|
224
241
|
};
|
|
225
242
|
}
|
|
226
243
|
|
|
244
|
+
/**
|
|
245
|
+
* Ensure a scroll container exists between the wrapper and the grid.
|
|
246
|
+
* Creates one on demand (e.g. when the first resize converts percent → pixel mode).
|
|
247
|
+
*/
|
|
248
|
+
private ensureScrollContainer(): HTMLDivElement {
|
|
249
|
+
if (this.scrollContainer) {
|
|
250
|
+
return this.scrollContainer;
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
const sc = document.createElement('div');
|
|
254
|
+
|
|
255
|
+
sc.setAttribute('data-blok-table-scroll', '');
|
|
256
|
+
|
|
257
|
+
const grid = this.gridElement;
|
|
258
|
+
|
|
259
|
+
if (grid && this.element) {
|
|
260
|
+
this.element.insertBefore(sc, grid);
|
|
261
|
+
sc.appendChild(grid);
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
this.scrollContainer = sc;
|
|
265
|
+
|
|
266
|
+
return sc;
|
|
267
|
+
}
|
|
268
|
+
|
|
227
269
|
public render(): HTMLDivElement {
|
|
228
270
|
const wrapper = document.createElement('div');
|
|
229
271
|
|
|
230
|
-
wrapper.className = twMerge(WRAPPER_CLASSES, !this.readOnly && WRAPPER_EDIT_CLASSES
|
|
272
|
+
wrapper.className = twMerge(WRAPPER_CLASSES, !this.readOnly && WRAPPER_EDIT_CLASSES);
|
|
231
273
|
wrapper.setAttribute(DATA_ATTR.tool, 'table');
|
|
232
274
|
|
|
233
275
|
if (this.readOnly) {
|
|
@@ -249,15 +291,45 @@ export class Table implements BlockTool {
|
|
|
249
291
|
applyPixelWidths(gridEl, this.model.colWidths);
|
|
250
292
|
}
|
|
251
293
|
|
|
252
|
-
|
|
294
|
+
this.gridElement = gridEl;
|
|
295
|
+
|
|
296
|
+
if (this.model.colWidths || !this.readOnly) {
|
|
297
|
+
const sc = document.createElement('div');
|
|
298
|
+
|
|
299
|
+
sc.setAttribute('data-blok-table-scroll', '');
|
|
300
|
+
|
|
301
|
+
const overflowClasses = this.model.colWidths ? SCROLL_OVERFLOW_CLASSES : [];
|
|
302
|
+
|
|
303
|
+
sc.classList.add(...overflowClasses);
|
|
304
|
+
|
|
305
|
+
sc.appendChild(gridEl);
|
|
306
|
+
wrapper.appendChild(sc);
|
|
307
|
+
this.scrollContainer = sc;
|
|
308
|
+
} else {
|
|
309
|
+
wrapper.appendChild(gridEl);
|
|
310
|
+
this.scrollContainer = null;
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
if (!this.readOnly) {
|
|
314
|
+
const overlay = document.createElement('div');
|
|
315
|
+
|
|
316
|
+
overlay.setAttribute('data-blok-table-grip-overlay', '');
|
|
317
|
+
overlay.style.position = 'absolute';
|
|
318
|
+
overlay.style.inset = '0';
|
|
319
|
+
overlay.style.pointerEvents = 'none';
|
|
320
|
+
overlay.style.zIndex = '3';
|
|
321
|
+
wrapper.appendChild(overlay);
|
|
322
|
+
this.gripOverlay = overlay;
|
|
323
|
+
}
|
|
324
|
+
|
|
253
325
|
this.element = wrapper;
|
|
254
326
|
|
|
255
327
|
if (this.model.withHeadings) {
|
|
256
|
-
updateHeadingStyles(this.
|
|
328
|
+
updateHeadingStyles(this.gridElement, this.model.withHeadings);
|
|
257
329
|
}
|
|
258
330
|
|
|
259
331
|
if (this.model.withHeadingColumn) {
|
|
260
|
-
updateHeadingColumnStyles(this.
|
|
332
|
+
updateHeadingColumnStyles(this.gridElement, this.model.withHeadingColumn);
|
|
261
333
|
}
|
|
262
334
|
|
|
263
335
|
if (!this.readOnly) {
|
|
@@ -273,7 +345,7 @@ export class Table implements BlockTool {
|
|
|
273
345
|
return;
|
|
274
346
|
}
|
|
275
347
|
|
|
276
|
-
const gridEl = this.
|
|
348
|
+
const gridEl = this.gridElement;
|
|
277
349
|
|
|
278
350
|
if (!gridEl) {
|
|
279
351
|
return;
|
|
@@ -286,11 +358,12 @@ export class Table implements BlockTool {
|
|
|
286
358
|
if (this.readOnly) {
|
|
287
359
|
mountCellBlocksReadOnly(gridEl, content, this.api, this.blockId ?? '');
|
|
288
360
|
this.initReadOnlyCellSelection(gridEl);
|
|
361
|
+
this.initScrollHaze();
|
|
289
362
|
|
|
290
363
|
return;
|
|
291
364
|
}
|
|
292
365
|
|
|
293
|
-
this.
|
|
366
|
+
this.runTransactedStructuralOp(() => {
|
|
294
367
|
const initializedContent = this.cellBlocks?.initializeCells(content) ?? content;
|
|
295
368
|
|
|
296
369
|
// When a new table is created with empty content, the DOM grid already has
|
|
@@ -390,7 +463,7 @@ export class Table implements BlockTool {
|
|
|
390
463
|
|
|
391
464
|
oldElement.parentNode.replaceChild(newElement, oldElement);
|
|
392
465
|
|
|
393
|
-
const gridEl = this.
|
|
466
|
+
const gridEl = this.gridElement;
|
|
394
467
|
|
|
395
468
|
if (this.readOnly || !gridEl) {
|
|
396
469
|
return;
|
|
@@ -412,10 +485,29 @@ export class Table implements BlockTool {
|
|
|
412
485
|
return;
|
|
413
486
|
}
|
|
414
487
|
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
488
|
+
// When undoing reverts content to empty, the grid has default dimensions
|
|
489
|
+
// but initializeCells([]) mounted zero blocks. Pre-populate the model
|
|
490
|
+
// with empty cell entries so populateNewCells can place blocks correctly.
|
|
491
|
+
if (this.api.blocks.isSyncingFromYjs && setDataContent.length === 0 && gridEl) {
|
|
492
|
+
const emptyGridContent = Array.from(gridEl.querySelectorAll(`[${ROW_ATTR}]`), (row) => {
|
|
493
|
+
const cellCount = row.querySelectorAll(`[${CELL_ATTR}]`).length;
|
|
494
|
+
|
|
495
|
+
return Array.from({ length: cellCount }, () => ({ blocks: [] as string[] }));
|
|
496
|
+
});
|
|
497
|
+
|
|
498
|
+
this.model.replaceAll({
|
|
499
|
+
...this.model.snapshot(),
|
|
500
|
+
content: emptyGridContent,
|
|
501
|
+
});
|
|
502
|
+
|
|
503
|
+
populateNewCells(gridEl, this.cellBlocks);
|
|
504
|
+
} else {
|
|
505
|
+
this.model.replaceAll({
|
|
506
|
+
...this.model.snapshot(),
|
|
507
|
+
content: setDataContent,
|
|
508
|
+
});
|
|
509
|
+
}
|
|
510
|
+
|
|
419
511
|
this.initialContent = null;
|
|
420
512
|
}, true);
|
|
421
513
|
|
|
@@ -469,7 +561,7 @@ export class Table implements BlockTool {
|
|
|
469
561
|
|
|
470
562
|
oldElement.parentNode.replaceChild(newElement, oldElement);
|
|
471
563
|
|
|
472
|
-
const gridEl = this.
|
|
564
|
+
const gridEl = this.gridElement;
|
|
473
565
|
|
|
474
566
|
if (!this.readOnly && gridEl) {
|
|
475
567
|
this.runStructuralOp(() => {
|
|
@@ -501,11 +593,13 @@ export class Table implements BlockTool {
|
|
|
501
593
|
this.teardownSubsystems();
|
|
502
594
|
this.cellBlocks?.destroy();
|
|
503
595
|
this.cellBlocks = null;
|
|
596
|
+
this.gridElement = null;
|
|
597
|
+
this.scrollContainer = null;
|
|
504
598
|
this.element = null;
|
|
505
599
|
}
|
|
506
600
|
|
|
507
601
|
public deleteRowWithCleanup(rowIndex: number): void {
|
|
508
|
-
const gridEl = this.
|
|
602
|
+
const gridEl = this.gridElement;
|
|
509
603
|
|
|
510
604
|
if (!gridEl) {
|
|
511
605
|
return;
|
|
@@ -520,7 +614,7 @@ export class Table implements BlockTool {
|
|
|
520
614
|
}
|
|
521
615
|
|
|
522
616
|
public deleteColumnWithCleanup(colIndex: number): void {
|
|
523
|
-
const gridEl = this.
|
|
617
|
+
const gridEl = this.gridElement;
|
|
524
618
|
|
|
525
619
|
if (!gridEl) {
|
|
526
620
|
return;
|
|
@@ -570,8 +664,8 @@ export class Table implements BlockTool {
|
|
|
570
664
|
this.grid.addRow(gridEl);
|
|
571
665
|
this.model.addRow();
|
|
572
666
|
populateNewCells(gridEl, this.cellBlocks);
|
|
573
|
-
updateHeadingStyles(this.
|
|
574
|
-
updateHeadingColumnStyles(this.
|
|
667
|
+
updateHeadingStyles(this.gridElement, this.model.withHeadings);
|
|
668
|
+
updateHeadingColumnStyles(this.gridElement, this.model.withHeadingColumn);
|
|
575
669
|
this.initResize(gridEl);
|
|
576
670
|
this.addControls?.syncRowButtonWidth();
|
|
577
671
|
this.rowColControls?.refresh();
|
|
@@ -588,10 +682,14 @@ export class Table implements BlockTool {
|
|
|
588
682
|
this.model.addColumn(undefined, halfWidth);
|
|
589
683
|
this.model.setColWidths([...colWidths, halfWidth]);
|
|
590
684
|
populateNewCells(gridEl, this.cellBlocks);
|
|
591
|
-
updateHeadingColumnStyles(this.
|
|
685
|
+
updateHeadingColumnStyles(this.gridElement, this.model.withHeadingColumn);
|
|
592
686
|
this.initResize(gridEl);
|
|
593
687
|
this.addControls?.syncRowButtonWidth();
|
|
594
688
|
this.rowColControls?.refresh();
|
|
689
|
+
|
|
690
|
+
if (this.scrollContainer) {
|
|
691
|
+
this.scrollContainer.scrollLeft = this.scrollContainer.scrollWidth;
|
|
692
|
+
}
|
|
595
693
|
});
|
|
596
694
|
},
|
|
597
695
|
onDragStart: () => {
|
|
@@ -606,8 +704,8 @@ export class Table implements BlockTool {
|
|
|
606
704
|
this.grid.addRow(gridEl);
|
|
607
705
|
this.model.addRow();
|
|
608
706
|
populateNewCells(gridEl, this.cellBlocks);
|
|
609
|
-
updateHeadingStyles(this.
|
|
610
|
-
updateHeadingColumnStyles(this.
|
|
707
|
+
updateHeadingStyles(this.gridElement, this.model.withHeadings);
|
|
708
|
+
updateHeadingColumnStyles(this.gridElement, this.model.withHeadingColumn);
|
|
611
709
|
});
|
|
612
710
|
},
|
|
613
711
|
onDragRemoveRow: () => {
|
|
@@ -636,13 +734,13 @@ export class Table implements BlockTool {
|
|
|
636
734
|
this.model.setColWidths(newWidths);
|
|
637
735
|
applyPixelWidths(gridEl, newWidths);
|
|
638
736
|
populateNewCells(gridEl, this.cellBlocks);
|
|
639
|
-
updateHeadingColumnStyles(this.
|
|
737
|
+
updateHeadingColumnStyles(this.gridElement, this.model.withHeadingColumn);
|
|
640
738
|
this.initResize(gridEl);
|
|
641
739
|
|
|
642
740
|
dragState.addedCols++;
|
|
643
741
|
|
|
644
|
-
if (this.
|
|
645
|
-
this.
|
|
742
|
+
if (this.scrollContainer) {
|
|
743
|
+
this.scrollContainer.scrollLeft = this.scrollContainer.scrollWidth;
|
|
646
744
|
}
|
|
647
745
|
});
|
|
648
746
|
},
|
|
@@ -677,8 +775,8 @@ export class Table implements BlockTool {
|
|
|
677
775
|
this.addControls?.syncRowButtonWidth();
|
|
678
776
|
this.rowColControls?.refresh();
|
|
679
777
|
|
|
680
|
-
if (this.
|
|
681
|
-
this.
|
|
778
|
+
if (this.scrollContainer) {
|
|
779
|
+
this.scrollContainer.scrollLeft = dragState.addedCols > 0 ? this.scrollContainer.scrollWidth : 0;
|
|
682
780
|
}
|
|
683
781
|
|
|
684
782
|
dragState.addedCols = 0;
|
|
@@ -695,6 +793,8 @@ export class Table implements BlockTool {
|
|
|
695
793
|
|
|
696
794
|
this.rowColControls = new TableRowColControls({
|
|
697
795
|
grid: gridEl,
|
|
796
|
+
overlay: this.gripOverlay ?? undefined,
|
|
797
|
+
scrollContainer: this.scrollContainer ?? undefined,
|
|
698
798
|
getColumnCount: () => this.grid.getColumnCount(gridEl),
|
|
699
799
|
getRowCount: () => this.grid.getRowCount(gridEl),
|
|
700
800
|
isHeadingRow: () => this.model.withHeadings,
|
|
@@ -748,7 +848,7 @@ export class Table implements BlockTool {
|
|
|
748
848
|
const generationAtStart = this.setDataGeneration;
|
|
749
849
|
|
|
750
850
|
this.runTransactedStructuralOp(() => {
|
|
751
|
-
if (generationAtStart !== this.setDataGeneration || this.
|
|
851
|
+
if (generationAtStart !== this.setDataGeneration || this.gridElement !== gridEl) {
|
|
752
852
|
return;
|
|
753
853
|
}
|
|
754
854
|
|
|
@@ -779,7 +879,7 @@ export class Table implements BlockTool {
|
|
|
779
879
|
},
|
|
780
880
|
);
|
|
781
881
|
|
|
782
|
-
if (generationAtStart !== this.setDataGeneration || this.
|
|
882
|
+
if (generationAtStart !== this.setDataGeneration || this.gridElement !== gridEl) {
|
|
783
883
|
return;
|
|
784
884
|
}
|
|
785
885
|
|
|
@@ -788,8 +888,8 @@ export class Table implements BlockTool {
|
|
|
788
888
|
this.model.setWithHeadingColumn(result.withHeadingColumn);
|
|
789
889
|
this.pendingHighlight = result.pendingHighlight;
|
|
790
890
|
|
|
791
|
-
updateHeadingStyles(this.
|
|
792
|
-
updateHeadingColumnStyles(this.
|
|
891
|
+
updateHeadingStyles(this.gridElement, this.model.withHeadings);
|
|
892
|
+
updateHeadingColumnStyles(this.gridElement, this.model.withHeadingColumn);
|
|
793
893
|
this.initResize(gridEl);
|
|
794
894
|
this.addControls?.syncRowButtonWidth();
|
|
795
895
|
this.rowColControls?.refresh();
|
|
@@ -851,7 +951,7 @@ export class Table implements BlockTool {
|
|
|
851
951
|
const widths = this.model.colWidths ?? readPixelWidths(gridEl);
|
|
852
952
|
|
|
853
953
|
if (!isPercentMode) {
|
|
854
|
-
enableScrollOverflow(this.
|
|
954
|
+
enableScrollOverflow(this.ensureScrollContainer());
|
|
855
955
|
}
|
|
856
956
|
|
|
857
957
|
this.resize = new TableResize(
|
|
@@ -859,14 +959,17 @@ export class Table implements BlockTool {
|
|
|
859
959
|
widths,
|
|
860
960
|
(newWidths: number[]) => {
|
|
861
961
|
this.model.setColWidths(newWidths);
|
|
862
|
-
enableScrollOverflow(this.
|
|
962
|
+
enableScrollOverflow(this.ensureScrollContainer());
|
|
863
963
|
this.rowColControls?.positionGrips();
|
|
964
|
+
this.addControls?.syncRowButtonWidth();
|
|
965
|
+
this.scrollHaze?.update();
|
|
864
966
|
},
|
|
865
967
|
() => {
|
|
866
968
|
this.rowColControls?.hideAllGrips();
|
|
867
969
|
},
|
|
868
970
|
() => {
|
|
869
971
|
this.addControls?.syncRowButtonWidth();
|
|
972
|
+
this.scrollHaze?.update();
|
|
870
973
|
},
|
|
871
974
|
isPercentMode,
|
|
872
975
|
);
|
|
@@ -895,10 +998,32 @@ export class Table implements BlockTool {
|
|
|
895
998
|
clipboardData.setData('text/plain', buildClipboardPlainText(payload));
|
|
896
999
|
}
|
|
897
1000
|
|
|
1001
|
+
private handleCellCopyViaButton(cells: HTMLElement[]): void {
|
|
1002
|
+
const entries = this.collectCellBlockData(cells);
|
|
1003
|
+
|
|
1004
|
+
if (entries.length === 0) {
|
|
1005
|
+
return;
|
|
1006
|
+
}
|
|
1007
|
+
|
|
1008
|
+
const payload = serializeCellsToClipboard(entries);
|
|
1009
|
+
const html = buildClipboardHtml(payload);
|
|
1010
|
+
const plainText = buildClipboardPlainText(payload);
|
|
1011
|
+
|
|
1012
|
+
const htmlBlob = new Blob([html], { type: 'text/html' });
|
|
1013
|
+
const textBlob = new Blob([plainText], { type: 'text/plain' });
|
|
1014
|
+
|
|
1015
|
+
void navigator.clipboard.write([
|
|
1016
|
+
new ClipboardItem({
|
|
1017
|
+
'text/html': htmlBlob,
|
|
1018
|
+
'text/plain': textBlob,
|
|
1019
|
+
}),
|
|
1020
|
+
]);
|
|
1021
|
+
}
|
|
1022
|
+
|
|
898
1023
|
private collectCellBlockData(
|
|
899
1024
|
cells: HTMLElement[],
|
|
900
1025
|
): Array<{ row: number; col: number; blocks: ClipboardBlockData[] }> {
|
|
901
|
-
const gridEl = this.
|
|
1026
|
+
const gridEl = this.gridElement;
|
|
902
1027
|
|
|
903
1028
|
if (!gridEl) {
|
|
904
1029
|
return [];
|
|
@@ -976,6 +1101,7 @@ export class Table implements BlockTool {
|
|
|
976
1101
|
grid: gridEl,
|
|
977
1102
|
rectangleSelection, // Pass reference
|
|
978
1103
|
i18n: this.api.i18n,
|
|
1104
|
+
isPopoverOpen: () => this.rowColControls?.isPopoverOpen ?? false,
|
|
979
1105
|
onSelectionActiveChange: (hasSelection) => {
|
|
980
1106
|
if (this.resize) {
|
|
981
1107
|
this.resize.enabled = !hasSelection;
|
|
@@ -999,6 +1125,9 @@ export class Table implements BlockTool {
|
|
|
999
1125
|
onCut: (cells, clipboardData) => {
|
|
1000
1126
|
this.handleCellCopy(cells, clipboardData);
|
|
1001
1127
|
},
|
|
1128
|
+
onCopyViaButton: (cells) => {
|
|
1129
|
+
this.handleCellCopyViaButton(cells);
|
|
1130
|
+
},
|
|
1002
1131
|
});
|
|
1003
1132
|
}
|
|
1004
1133
|
|
|
@@ -1014,9 +1143,23 @@ export class Table implements BlockTool {
|
|
|
1014
1143
|
onCopy: (cells, clipboardData) => {
|
|
1015
1144
|
this.handleCellCopy(cells, clipboardData);
|
|
1016
1145
|
},
|
|
1146
|
+
onCopyViaButton: (cells) => {
|
|
1147
|
+
this.handleCellCopyViaButton(cells);
|
|
1148
|
+
},
|
|
1017
1149
|
});
|
|
1018
1150
|
}
|
|
1019
1151
|
|
|
1152
|
+
private initScrollHaze(): void {
|
|
1153
|
+
this.scrollHaze?.destroy();
|
|
1154
|
+
|
|
1155
|
+
if (!this.element || !this.scrollContainer) {
|
|
1156
|
+
return;
|
|
1157
|
+
}
|
|
1158
|
+
|
|
1159
|
+
this.scrollHaze = new TableScrollHaze();
|
|
1160
|
+
this.scrollHaze.init(this.element, this.scrollContainer);
|
|
1161
|
+
}
|
|
1162
|
+
|
|
1020
1163
|
private initGridPasteListener(gridEl: HTMLElement): void {
|
|
1021
1164
|
gridEl.addEventListener('paste', (e: ClipboardEvent) => {
|
|
1022
1165
|
this.handleGridPaste(e, gridEl);
|
|
@@ -1150,8 +1293,8 @@ export class Table implements BlockTool {
|
|
|
1150
1293
|
this.grid.addRow(gridEl);
|
|
1151
1294
|
this.model.addRow();
|
|
1152
1295
|
populateNewCells(gridEl, this.cellBlocks);
|
|
1153
|
-
updateHeadingStyles(this.
|
|
1154
|
-
updateHeadingColumnStyles(this.
|
|
1296
|
+
updateHeadingStyles(this.gridElement, this.model.withHeadings);
|
|
1297
|
+
updateHeadingColumnStyles(this.gridElement, this.model.withHeadingColumn);
|
|
1155
1298
|
});
|
|
1156
1299
|
|
|
1157
1300
|
// Auto-expand columns
|
|
@@ -1165,7 +1308,7 @@ export class Table implements BlockTool {
|
|
|
1165
1308
|
this.model.addColumn(undefined, halfWidth);
|
|
1166
1309
|
this.model.setColWidths([...colWidths, halfWidth]);
|
|
1167
1310
|
populateNewCells(gridEl, this.cellBlocks);
|
|
1168
|
-
updateHeadingColumnStyles(this.
|
|
1311
|
+
updateHeadingColumnStyles(this.gridElement, this.model.withHeadingColumn);
|
|
1169
1312
|
});
|
|
1170
1313
|
}
|
|
1171
1314
|
|
|
@@ -121,7 +121,7 @@ export class TableAddControls {
|
|
|
121
121
|
this.addColBtn = this.createAddColumnButton();
|
|
122
122
|
|
|
123
123
|
this.wrapper.appendChild(this.addRowBtn);
|
|
124
|
-
this.
|
|
124
|
+
this.wrapper.appendChild(this.addColBtn);
|
|
125
125
|
this.syncRowButtonWidth();
|
|
126
126
|
|
|
127
127
|
this.wrapper.addEventListener('mousemove', this.boundMouseMove);
|
|
@@ -133,17 +133,51 @@ export class TableAddControls {
|
|
|
133
133
|
}
|
|
134
134
|
|
|
135
135
|
/**
|
|
136
|
-
* Match the add-row button width to the grid
|
|
137
|
-
*
|
|
138
|
-
*
|
|
139
|
-
*
|
|
136
|
+
* Match the add-row button width and horizontal position to the grid.
|
|
137
|
+
*
|
|
138
|
+
* Pixel mode (colWidths set): clamp to the scroll container's visible
|
|
139
|
+
* width so the button never overflows the table boundary.
|
|
140
|
+
*
|
|
141
|
+
* Percent mode (no colWidths): clear `width` and use `left`/`right`
|
|
142
|
+
* constraints so the browser auto-sizes the button to the wrapper's
|
|
143
|
+
* content area, avoiding the wrapper's right padding.
|
|
140
144
|
*/
|
|
141
145
|
public syncRowButtonWidth(): void {
|
|
142
146
|
const gridWidth = this.grid.style.width;
|
|
143
147
|
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
148
|
+
if (gridWidth && gridWidth.endsWith('px')) {
|
|
149
|
+
const numericWidth = parseFloat(gridWidth);
|
|
150
|
+
const scrollContainer = this.grid.parentElement;
|
|
151
|
+
const isInsideScrollContainer = scrollContainer !== null && scrollContainer !== this.wrapper;
|
|
152
|
+
|
|
153
|
+
/**
|
|
154
|
+
* When a scroll container exists and the grid overflows it,
|
|
155
|
+
* clamp to the visible width so the button stays within bounds.
|
|
156
|
+
* Guard clientWidth > 0 for pre-layout / jsdom environments.
|
|
157
|
+
*/
|
|
158
|
+
const visibleWidth = isInsideScrollContainer && scrollContainer.clientWidth > 0
|
|
159
|
+
? Math.min(numericWidth, scrollContainer.clientWidth)
|
|
160
|
+
: numericWidth;
|
|
161
|
+
|
|
162
|
+
this.addRowBtn.style.width = `${visibleWidth}px`;
|
|
163
|
+
this.addRowBtn.style.right = '';
|
|
164
|
+
this.addRowBtn.style.left = '0px';
|
|
165
|
+
this.addRowBtn.style.transform = '';
|
|
166
|
+
|
|
167
|
+
this.addColBtn.style.left = `${visibleWidth}px`;
|
|
168
|
+
this.addColBtn.style.right = '';
|
|
169
|
+
} else {
|
|
170
|
+
this.addRowBtn.style.width = '';
|
|
171
|
+
this.addRowBtn.style.left = '0px';
|
|
172
|
+
this.addRowBtn.style.transform = '';
|
|
173
|
+
|
|
174
|
+
const paddingRight = parseFloat(getComputedStyle(this.wrapper).paddingRight) || 0;
|
|
175
|
+
|
|
176
|
+
this.addRowBtn.style.right = `${paddingRight}px`;
|
|
177
|
+
|
|
178
|
+
this.addColBtn.style.left = '';
|
|
179
|
+
this.addColBtn.style.right = '-16px';
|
|
180
|
+
}
|
|
147
181
|
}
|
|
148
182
|
|
|
149
183
|
/**
|
|
@@ -338,8 +372,14 @@ export class TableAddControls {
|
|
|
338
372
|
|
|
339
373
|
private handleMouseMove(e: MouseEvent): void {
|
|
340
374
|
const gridRect = this.grid.getBoundingClientRect();
|
|
375
|
+
const scrollContainer = this.grid.parentElement;
|
|
376
|
+
const isInsideScrollContainer = scrollContainer !== null && scrollContainer !== this.wrapper;
|
|
377
|
+
const visibleRight = isInsideScrollContainer
|
|
378
|
+
? Math.min(gridRect.right, scrollContainer.getBoundingClientRect().right)
|
|
379
|
+
: gridRect.right;
|
|
380
|
+
|
|
341
381
|
const distFromBottom = Math.abs(e.clientY - gridRect.bottom);
|
|
342
|
-
const distFromRight = Math.abs(e.clientX -
|
|
382
|
+
const distFromRight = Math.abs(e.clientX - visibleRight);
|
|
343
383
|
|
|
344
384
|
if (distFromBottom <= PROXIMITY_PX) {
|
|
345
385
|
this.showRow();
|
|
@@ -430,11 +470,8 @@ export class TableAddControls {
|
|
|
430
470
|
btn.style.position = 'absolute';
|
|
431
471
|
btn.style.left = '0';
|
|
432
472
|
btn.style.bottom = '-36px';
|
|
433
|
-
btn.style.
|
|
434
|
-
btn.style.width = '100%';
|
|
473
|
+
btn.style.zIndex = '1';
|
|
435
474
|
btn.style.height = '32px';
|
|
436
|
-
btn.style.padding = '4px 8px 0';
|
|
437
|
-
btn.style.marginLeft = '-8px';
|
|
438
475
|
|
|
439
476
|
const visual = document.createElement('div');
|
|
440
477
|
|
|
@@ -462,7 +499,7 @@ export class TableAddControls {
|
|
|
462
499
|
btn.style.opacity = '0';
|
|
463
500
|
btn.style.pointerEvents = 'none';
|
|
464
501
|
btn.style.position = 'absolute';
|
|
465
|
-
btn.style.right = '-
|
|
502
|
+
btn.style.right = '-16px';
|
|
466
503
|
btn.style.top = '0px';
|
|
467
504
|
btn.style.bottom = '0px';
|
|
468
505
|
btn.style.width = '32px';
|
|
@@ -384,6 +384,12 @@ export class TableCellBlocks {
|
|
|
384
384
|
return;
|
|
385
385
|
}
|
|
386
386
|
|
|
387
|
+
// Guard against circular DOM: never append the table block's own holder
|
|
388
|
+
// into one of its descendant cell containers.
|
|
389
|
+
if (block.holder.contains(container)) {
|
|
390
|
+
return;
|
|
391
|
+
}
|
|
392
|
+
|
|
387
393
|
container.appendChild(block.holder);
|
|
388
394
|
this.api.blocks.setBlockParent(blockId, this.tableBlockId);
|
|
389
395
|
this.stripPlaceholders(container);
|
|
@@ -477,6 +483,13 @@ export class TableCellBlocks {
|
|
|
477
483
|
return;
|
|
478
484
|
}
|
|
479
485
|
|
|
486
|
+
// Never claim the table block itself as a cell content block.
|
|
487
|
+
// This can happen when rendered() creates cell blocks synchronously,
|
|
488
|
+
// polluting currentBlockIndex before the table's own block-added fires.
|
|
489
|
+
if (detail.target.id === this.tableBlockId) {
|
|
490
|
+
return;
|
|
491
|
+
}
|
|
492
|
+
|
|
480
493
|
const blockIndex = detail.index;
|
|
481
494
|
|
|
482
495
|
if (blockIndex === undefined) {
|
|
@@ -526,9 +539,35 @@ export class TableCellBlocks {
|
|
|
526
539
|
}
|
|
527
540
|
|
|
528
541
|
// Only claim blocks whose holder is inside this table's grid.
|
|
529
|
-
// Blocks placed outside the grid (e.g., via
|
|
530
|
-
//
|
|
542
|
+
// Blocks placed outside the grid (e.g., via undo/restore or API inserts)
|
|
543
|
+
// should not be pulled into a cell by adjacency alone.
|
|
544
|
+
//
|
|
545
|
+
// However, blocks created while the editor's focus is inside this table
|
|
546
|
+
// (e.g., via Enter key or paste in a cell) land outside the grid because
|
|
547
|
+
// insertToDOM walks up from cell blocks to the table holder level.
|
|
548
|
+
// For those, check that the current block at the time of insertion belongs
|
|
549
|
+
// to this table — indicating the user was editing inside a cell.
|
|
531
550
|
if (!this.gridElement.contains(holder)) {
|
|
551
|
+
const currentIndex = this.api.blocks.getCurrentBlockIndex();
|
|
552
|
+
const currentBlock = currentIndex >= 0
|
|
553
|
+
? this.api.blocks.getBlockByIndex(currentIndex)
|
|
554
|
+
: null;
|
|
555
|
+
const currentBlockInOurTable = currentBlock !== null
|
|
556
|
+
&& currentBlock !== undefined
|
|
557
|
+
&& this.getOwnedCellForBlock(currentBlock.id) !== null;
|
|
558
|
+
|
|
559
|
+
if (!currentBlockInOurTable) {
|
|
560
|
+
return;
|
|
561
|
+
}
|
|
562
|
+
|
|
563
|
+
const cell = this.findCellForNewBlock(blockIndex);
|
|
564
|
+
|
|
565
|
+
if (cell) {
|
|
566
|
+
this.claimBlockForCell(cell, detail.target.id);
|
|
567
|
+
this.syncBlockToModel(cell, detail.target.id);
|
|
568
|
+
this.cellsPendingCheck.delete(cell);
|
|
569
|
+
}
|
|
570
|
+
|
|
532
571
|
return;
|
|
533
572
|
}
|
|
534
573
|
|