@jackuait/blok 0.6.0-beta.4 → 0.6.0-beta.5
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-DK-97ZTf.mjs → blok-XA2L0_-K.mjs} +1216 -1178
- package/dist/chunks/{i18next-loader-CRollibS.mjs → i18next-loader-Ci2zhA-n.mjs} +1 -1
- package/dist/chunks/{index-jgHmMDND.mjs → index-R38OiQ_d.mjs} +1 -1
- package/dist/chunks/{inline-tool-convert-BIwvipPw.mjs → inline-tool-convert-e3PyuxB6.mjs} +88 -73
- package/dist/chunks/{messages-C5b7hr_E.mjs → messages-1fC8IMyX.mjs} +16 -2
- package/dist/{messages-BPqWKx5Z.mjs → chunks/messages-49thXXGz.mjs} +16 -2
- 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-D00OjS2n.mjs → chunks/messages-B9fe4dQJ.mjs} +15 -1
- 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/chunks/{messages-CQj2JU2j.mjs → messages-BGxiFoZf.mjs} +15 -1
- package/dist/{messages-B5puUm7R.mjs → chunks/messages-BL0tXcDf.mjs} +15 -1
- package/dist/{messages-CyDU5lz9.mjs → chunks/messages-BMv4xwIr.mjs} +16 -2
- package/dist/chunks/{messages-CkFT2gle.mjs → messages-BNe6LuHW.mjs} +14 -0
- 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/{messages-Cyi2AMmz.mjs → chunks/messages-Bfiw5w_W.mjs} +16 -2
- 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-BiExzWJv.mjs → messages-C99mq906.mjs} +15 -1
- package/dist/chunks/{messages-BrJHUxQL.mjs → messages-CJdUsQ-c.mjs} +15 -1
- package/dist/{messages-CrsJ1TEJ.mjs → chunks/messages-CLhcMlTc.mjs} +15 -1
- package/dist/{messages-CnvW8Slp.mjs → chunks/messages-CMkNSDTo.mjs} +17 -3
- 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/{messages-DOlC_Tty.mjs → chunks/messages-DChXyvh2.mjs} +15 -1
- 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-BlpqL8vG.mjs → chunks/messages-DjvaFRqx.mjs} +16 -2
- 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-CySyfkMU.mjs → messages-DsVNtdgM.mjs} +15 -1
- package/dist/chunks/{messages-DnbbyJT3.mjs → messages-Dz9L52ol.mjs} +16 -2
- package/dist/chunks/{messages-Cu08aLS3.mjs → messages-EL5ARzmK.mjs} +16 -2
- 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-GC2PhgV3.mjs → messages-QtoE8uEv.mjs} +15 -1
- package/dist/chunks/{messages-2_xedlYw.mjs → messages-R3hUSvr3.mjs} +15 -1
- package/dist/chunks/{messages-zS1AXZ0y.mjs → messages-UX4gkere.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/{messages-BeUhMpsr.mjs → chunks/messages-wp_1b1hD.mjs} +15 -1
- package/dist/full.mjs +2 -2
- package/dist/locales.mjs +102 -88
- package/dist/{messages-C5b7hr_E.mjs → messages-1fC8IMyX.mjs} +16 -2
- package/dist/{chunks/messages-BPqWKx5Z.mjs → messages-49thXXGz.mjs} +16 -2
- 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-D00OjS2n.mjs → messages-B9fe4dQJ.mjs} +15 -1
- 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/{messages-CQj2JU2j.mjs → messages-BGxiFoZf.mjs} +15 -1
- package/dist/{chunks/messages-B5puUm7R.mjs → messages-BL0tXcDf.mjs} +15 -1
- package/dist/{chunks/messages-CyDU5lz9.mjs → messages-BMv4xwIr.mjs} +16 -2
- package/dist/{messages-CkFT2gle.mjs → messages-BNe6LuHW.mjs} +14 -0
- 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/{chunks/messages-Cyi2AMmz.mjs → messages-Bfiw5w_W.mjs} +16 -2
- 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-BiExzWJv.mjs → messages-C99mq906.mjs} +15 -1
- package/dist/{messages-BrJHUxQL.mjs → messages-CJdUsQ-c.mjs} +15 -1
- package/dist/{chunks/messages-CrsJ1TEJ.mjs → messages-CLhcMlTc.mjs} +15 -1
- package/dist/{chunks/messages-CnvW8Slp.mjs → messages-CMkNSDTo.mjs} +17 -3
- 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/{chunks/messages-DOlC_Tty.mjs → messages-DChXyvh2.mjs} +15 -1
- 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-BlpqL8vG.mjs → messages-DjvaFRqx.mjs} +16 -2
- 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-CySyfkMU.mjs → messages-DsVNtdgM.mjs} +15 -1
- package/dist/{messages-DnbbyJT3.mjs → messages-Dz9L52ol.mjs} +16 -2
- package/dist/{messages-Cu08aLS3.mjs → messages-EL5ARzmK.mjs} +16 -2
- 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-GC2PhgV3.mjs → messages-QtoE8uEv.mjs} +15 -1
- package/dist/{messages-2_xedlYw.mjs → messages-R3hUSvr3.mjs} +15 -1
- package/dist/{messages-zS1AXZ0y.mjs → messages-UX4gkere.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/{chunks/messages-BeUhMpsr.mjs → messages-wp_1b1hD.mjs} +15 -1
- package/dist/tools.mjs +854 -719
- package/package.json +5 -9
- 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 +15 -1
- 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 +14 -0
- 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 +15 -1
- 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 +16 -2
- 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 +15 -1
- package/src/components/i18n/locales/ms/messages.json +16 -2
- package/src/components/i18n/locales/my/messages.json +16 -2
- package/src/components/i18n/locales/ne/messages.json +15 -1
- 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 +15 -1
- 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 +16 -2
- package/src/components/i18n/locales/te/messages.json +15 -1
- package/src/components/i18n/locales/th/messages.json +15 -1
- 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 +16 -2
- 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/blockEvents/composers/markdownShortcuts.ts +12 -1
- 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/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 +67 -70
- package/src/tools/table/table-add-controls.ts +25 -7
- package/src/tools/table/table-cell-blocks.ts +62 -0
- 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/types/utils/popover/popover.d.ts +7 -0
package/src/tools/table/index.ts
CHANGED
|
@@ -18,7 +18,7 @@ import { TableGrid } from './table-core';
|
|
|
18
18
|
import {
|
|
19
19
|
applyPixelWidths,
|
|
20
20
|
computeHalfAvgWidth,
|
|
21
|
-
|
|
21
|
+
computeInitialColWidth,
|
|
22
22
|
deleteColumnWithBlockCleanup,
|
|
23
23
|
deleteRowWithBlockCleanup,
|
|
24
24
|
enableScrollOverflow,
|
|
@@ -30,14 +30,14 @@ import {
|
|
|
30
30
|
normalizeTableData,
|
|
31
31
|
populateNewCells,
|
|
32
32
|
readPixelWidths,
|
|
33
|
-
redistributePercentWidths,
|
|
34
33
|
SCROLL_OVERFLOW_CLASSES,
|
|
35
34
|
setupKeyboardNavigation,
|
|
36
|
-
syncColWidthsAfterMove,
|
|
37
35
|
updateHeadingColumnStyles,
|
|
38
36
|
updateHeadingStyles,
|
|
39
37
|
} from './table-operations';
|
|
40
38
|
import { TableResize } from './table-resize';
|
|
39
|
+
import { executeRowColAction } from './table-row-col-action-handler';
|
|
40
|
+
import type { PendingHighlight } from './table-row-col-action-handler';
|
|
41
41
|
import { TableRowColControls } from './table-row-col-controls';
|
|
42
42
|
import type { RowColAction } from './table-row-col-controls';
|
|
43
43
|
import type { TableData, TableConfig } from './types';
|
|
@@ -71,7 +71,7 @@ export class Table implements BlockTool {
|
|
|
71
71
|
private cellSelection: TableCellSelection | null = null;
|
|
72
72
|
private element: HTMLDivElement | null = null;
|
|
73
73
|
private blockId: string | undefined;
|
|
74
|
-
private pendingHighlight:
|
|
74
|
+
private pendingHighlight: PendingHighlight | null = null;
|
|
75
75
|
|
|
76
76
|
constructor({ data, config, api, readOnly, block }: BlockToolConstructorOptions<TableData, TableConfig>) {
|
|
77
77
|
this.api = api;
|
|
@@ -178,6 +178,14 @@ export class Table implements BlockTool {
|
|
|
178
178
|
|
|
179
179
|
this.data.content = this.cellBlocks?.initializeCells(this.data.content) ?? this.data.content;
|
|
180
180
|
|
|
181
|
+
if (this.data.initialColWidth === undefined) {
|
|
182
|
+
const widths = this.data.colWidths ?? readPixelWidths(gridEl);
|
|
183
|
+
|
|
184
|
+
this.data.initialColWidth = widths.length > 0
|
|
185
|
+
? computeInitialColWidth(widths)
|
|
186
|
+
: undefined;
|
|
187
|
+
}
|
|
188
|
+
|
|
181
189
|
this.initResize(gridEl);
|
|
182
190
|
this.initAddControls(gridEl);
|
|
183
191
|
this.initRowColControls(gridEl);
|
|
@@ -197,6 +205,7 @@ export class Table implements BlockTool {
|
|
|
197
205
|
stretched: this.data.stretched,
|
|
198
206
|
content,
|
|
199
207
|
...(colWidths ? { colWidths } : {}),
|
|
208
|
+
...(this.data.initialColWidth !== undefined ? { initialColWidth: this.data.initialColWidth } : {}),
|
|
200
209
|
};
|
|
201
210
|
}
|
|
202
211
|
|
|
@@ -252,6 +261,8 @@ export class Table implements BlockTool {
|
|
|
252
261
|
}
|
|
253
262
|
|
|
254
263
|
public destroy(): void {
|
|
264
|
+
this.cellBlocks?.deleteAllBlocks();
|
|
265
|
+
|
|
255
266
|
this.resize?.destroy();
|
|
256
267
|
this.resize = null;
|
|
257
268
|
this.addControls?.destroy();
|
|
@@ -296,9 +307,12 @@ export class Table implements BlockTool {
|
|
|
296
307
|
return;
|
|
297
308
|
}
|
|
298
309
|
|
|
310
|
+
const dragState = { addedCols: 0 };
|
|
311
|
+
|
|
299
312
|
this.addControls = new TableAddControls({
|
|
300
313
|
wrapper: this.element,
|
|
301
314
|
grid: gridEl,
|
|
315
|
+
i18n: this.api.i18n,
|
|
302
316
|
onAddRow: () => {
|
|
303
317
|
this.grid.addRow(gridEl);
|
|
304
318
|
populateNewCells(gridEl, this.cellBlocks);
|
|
@@ -310,10 +324,12 @@ export class Table implements BlockTool {
|
|
|
310
324
|
},
|
|
311
325
|
onAddColumn: () => {
|
|
312
326
|
const colWidths = this.data.colWidths ?? readPixelWidths(gridEl);
|
|
313
|
-
const
|
|
327
|
+
const halfWidth = this.data.initialColWidth !== undefined
|
|
328
|
+
? Math.round((this.data.initialColWidth / 2) * 100) / 100
|
|
329
|
+
: computeHalfAvgWidth(colWidths);
|
|
314
330
|
|
|
315
|
-
this.grid.addColumn(gridEl, undefined, colWidths);
|
|
316
|
-
this.data.colWidths = [...colWidths,
|
|
331
|
+
this.grid.addColumn(gridEl, undefined, colWidths, halfWidth);
|
|
332
|
+
this.data.colWidths = [...colWidths, halfWidth];
|
|
317
333
|
populateNewCells(gridEl, this.cellBlocks);
|
|
318
334
|
updateHeadingColumnStyles(this.element, this.data.withHeadingColumn);
|
|
319
335
|
this.initResize(gridEl);
|
|
@@ -342,14 +358,22 @@ export class Table implements BlockTool {
|
|
|
342
358
|
},
|
|
343
359
|
onDragAddCol: () => {
|
|
344
360
|
const colWidths = this.data.colWidths ?? readPixelWidths(gridEl);
|
|
345
|
-
const
|
|
361
|
+
const halfWidth = this.data.initialColWidth !== undefined
|
|
362
|
+
? Math.round((this.data.initialColWidth / 2) * 100) / 100
|
|
363
|
+
: computeHalfAvgWidth(colWidths);
|
|
346
364
|
|
|
347
|
-
this.grid.addColumn(gridEl, undefined, colWidths);
|
|
348
|
-
this.data.colWidths = [...colWidths,
|
|
365
|
+
this.grid.addColumn(gridEl, undefined, colWidths, halfWidth);
|
|
366
|
+
this.data.colWidths = [...colWidths, halfWidth];
|
|
349
367
|
applyPixelWidths(gridEl, this.data.colWidths);
|
|
350
368
|
populateNewCells(gridEl, this.cellBlocks);
|
|
351
369
|
updateHeadingColumnStyles(this.element, this.data.withHeadingColumn);
|
|
352
370
|
this.initResize(gridEl);
|
|
371
|
+
|
|
372
|
+
dragState.addedCols++;
|
|
373
|
+
|
|
374
|
+
if (this.element) {
|
|
375
|
+
this.element.scrollLeft = this.element.scrollWidth;
|
|
376
|
+
}
|
|
353
377
|
},
|
|
354
378
|
onDragRemoveCol: () => {
|
|
355
379
|
const colCount = this.grid.getColumnCount(gridEl);
|
|
@@ -365,6 +389,8 @@ export class Table implements BlockTool {
|
|
|
365
389
|
}
|
|
366
390
|
|
|
367
391
|
this.initResize(gridEl);
|
|
392
|
+
|
|
393
|
+
dragState.addedCols--;
|
|
368
394
|
},
|
|
369
395
|
onDragEnd: () => {
|
|
370
396
|
this.initResize(gridEl);
|
|
@@ -372,8 +398,10 @@ export class Table implements BlockTool {
|
|
|
372
398
|
this.rowColControls?.refresh();
|
|
373
399
|
|
|
374
400
|
if (this.element) {
|
|
375
|
-
this.element.scrollLeft = 0;
|
|
401
|
+
this.element.scrollLeft = dragState.addedCols > 0 ? this.element.scrollWidth : 0;
|
|
376
402
|
}
|
|
403
|
+
|
|
404
|
+
dragState.addedCols = 0;
|
|
377
405
|
},
|
|
378
406
|
});
|
|
379
407
|
}
|
|
@@ -391,6 +419,7 @@ export class Table implements BlockTool {
|
|
|
391
419
|
getRowCount: () => this.grid.getRowCount(gridEl),
|
|
392
420
|
isHeadingRow: () => this.data.withHeadings,
|
|
393
421
|
isHeadingColumn: () => this.data.withHeadingColumn,
|
|
422
|
+
i18n: this.api.i18n,
|
|
394
423
|
onAction: (action: RowColAction) => this.handleRowColAction(gridEl, action),
|
|
395
424
|
onDragStateChange: (isDragging: boolean) => {
|
|
396
425
|
if (this.resize) {
|
|
@@ -434,72 +463,37 @@ export class Table implements BlockTool {
|
|
|
434
463
|
}
|
|
435
464
|
|
|
436
465
|
private handleRowColAction(gridEl: HTMLElement, action: RowColAction): void {
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
break;
|
|
443
|
-
case 'insert-row-below':
|
|
444
|
-
this.grid.addRow(gridEl, action.index + 1);
|
|
445
|
-
populateNewCells(gridEl, this.cellBlocks);
|
|
446
|
-
this.pendingHighlight = { type: 'row', index: action.index + 1 };
|
|
447
|
-
break;
|
|
448
|
-
case 'insert-col-left':
|
|
449
|
-
this.data.colWidths = computeInsertColumnWidths(gridEl, action.index, this.data, this.grid);
|
|
450
|
-
populateNewCells(gridEl, this.cellBlocks);
|
|
451
|
-
this.pendingHighlight = { type: 'col', index: action.index };
|
|
452
|
-
break;
|
|
453
|
-
case 'insert-col-right':
|
|
454
|
-
this.data.colWidths = computeInsertColumnWidths(gridEl, action.index + 1, this.data, this.grid);
|
|
455
|
-
populateNewCells(gridEl, this.cellBlocks);
|
|
456
|
-
this.pendingHighlight = { type: 'col', index: action.index + 1 };
|
|
457
|
-
break;
|
|
458
|
-
case 'move-row':
|
|
459
|
-
this.grid.moveRow(gridEl, action.fromIndex, action.toIndex);
|
|
460
|
-
break;
|
|
461
|
-
case 'move-col':
|
|
462
|
-
this.grid.moveColumn(gridEl, action.fromIndex, action.toIndex);
|
|
463
|
-
this.data.colWidths = syncColWidthsAfterMove(this.data.colWidths, action.fromIndex, action.toIndex);
|
|
464
|
-
break;
|
|
465
|
-
case 'delete-row': {
|
|
466
|
-
deleteRowWithBlockCleanup(gridEl, action.index, this.grid, this.cellBlocks);
|
|
467
|
-
const newRowCount = this.grid.getRowCount(gridEl);
|
|
468
|
-
const neighborRow = action.index < newRowCount ? action.index : action.index - 1;
|
|
469
|
-
|
|
470
|
-
this.pendingHighlight = { type: 'row', index: neighborRow };
|
|
471
|
-
break;
|
|
472
|
-
}
|
|
473
|
-
case 'delete-col': {
|
|
474
|
-
this.data.colWidths = deleteColumnWithBlockCleanup(gridEl, action.index, this.data.colWidths, this.grid, this.cellBlocks);
|
|
475
|
-
|
|
476
|
-
if (this.data.colWidths) {
|
|
477
|
-
applyPixelWidths(gridEl, this.data.colWidths);
|
|
478
|
-
} else {
|
|
479
|
-
redistributePercentWidths(gridEl);
|
|
480
|
-
}
|
|
481
|
-
|
|
482
|
-
const newColCount = this.grid.getColumnCount(gridEl);
|
|
483
|
-
const neighborCol = action.index < newColCount ? action.index : action.index - 1;
|
|
466
|
+
const result = executeRowColAction(
|
|
467
|
+
gridEl,
|
|
468
|
+
action,
|
|
469
|
+
{ grid: this.grid, data: this.data, cellBlocks: this.cellBlocks },
|
|
470
|
+
);
|
|
484
471
|
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
this.data.withHeadings = !this.data.withHeadings;
|
|
490
|
-
this.pendingHighlight = { type: 'row', index: 0 };
|
|
491
|
-
break;
|
|
492
|
-
case 'toggle-heading-column':
|
|
493
|
-
this.data.withHeadingColumn = !this.data.withHeadingColumn;
|
|
494
|
-
this.pendingHighlight = { type: 'col', index: 0 };
|
|
495
|
-
break;
|
|
496
|
-
}
|
|
472
|
+
this.data.colWidths = result.colWidths;
|
|
473
|
+
this.data.withHeadings = result.withHeadings;
|
|
474
|
+
this.data.withHeadingColumn = result.withHeadingColumn;
|
|
475
|
+
this.pendingHighlight = result.pendingHighlight;
|
|
497
476
|
|
|
498
477
|
updateHeadingStyles(this.element, this.data.withHeadings);
|
|
499
478
|
updateHeadingColumnStyles(this.element, this.data.withHeadingColumn);
|
|
500
479
|
this.initResize(gridEl);
|
|
501
480
|
this.addControls?.syncRowButtonWidth();
|
|
502
481
|
this.rowColControls?.refresh();
|
|
482
|
+
|
|
483
|
+
if (!result.moveSelection) {
|
|
484
|
+
return;
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
// After move operations, select the moved row/column to show where it landed
|
|
488
|
+
const { type: moveType, index: moveIndex } = result.moveSelection;
|
|
489
|
+
|
|
490
|
+
if (moveType === 'row') {
|
|
491
|
+
this.cellSelection?.selectRow(moveIndex);
|
|
492
|
+
} else {
|
|
493
|
+
this.cellSelection?.selectColumn(moveIndex);
|
|
494
|
+
}
|
|
495
|
+
|
|
496
|
+
this.rowColControls?.setActiveGrip(moveType, moveIndex);
|
|
503
497
|
}
|
|
504
498
|
|
|
505
499
|
private initResize(gridEl: HTMLElement): void {
|
|
@@ -547,6 +541,7 @@ export class Table implements BlockTool {
|
|
|
547
541
|
this.cellSelection = new TableCellSelection({
|
|
548
542
|
grid: gridEl,
|
|
549
543
|
rectangleSelection, // Pass reference
|
|
544
|
+
i18n: this.api.i18n,
|
|
550
545
|
onSelectionActiveChange: (hasSelection) => {
|
|
551
546
|
if (this.resize) {
|
|
552
547
|
this.resize.enabled = !hasSelection;
|
|
@@ -567,3 +562,5 @@ export class Table implements BlockTool {
|
|
|
567
562
|
});
|
|
568
563
|
}
|
|
569
564
|
}
|
|
565
|
+
|
|
566
|
+
export { isInsideTableCell, isRestrictedInTableCell, convertToParagraph } from './table-restrictions';
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { I18n } from '../../../types/api';
|
|
1
2
|
import { IconPlus } from '../../components/icons';
|
|
2
3
|
import { createTooltipContent } from '../../components/modules/toolbar/tooltip';
|
|
3
4
|
import { hide as hideTooltip, onHover } from '../../components/utils/tooltip';
|
|
@@ -46,6 +47,7 @@ interface DragState {
|
|
|
46
47
|
interface TableAddControlsOptions {
|
|
47
48
|
wrapper: HTMLElement;
|
|
48
49
|
grid: HTMLElement;
|
|
50
|
+
i18n: I18n;
|
|
49
51
|
onAddRow: () => void;
|
|
50
52
|
onAddColumn: () => void;
|
|
51
53
|
onDragStart: () => void;
|
|
@@ -64,6 +66,7 @@ interface TableAddControlsOptions {
|
|
|
64
66
|
export class TableAddControls {
|
|
65
67
|
private wrapper: HTMLElement;
|
|
66
68
|
private grid: HTMLElement;
|
|
69
|
+
private i18n: I18n;
|
|
67
70
|
private addRowBtn: HTMLElement;
|
|
68
71
|
private addColBtn: HTMLElement;
|
|
69
72
|
private rowHideTimeout: ReturnType<typeof setTimeout> | null = null;
|
|
@@ -90,6 +93,7 @@ export class TableAddControls {
|
|
|
90
93
|
constructor(options: TableAddControlsOptions) {
|
|
91
94
|
this.wrapper = options.wrapper;
|
|
92
95
|
this.grid = options.grid;
|
|
96
|
+
this.i18n = options.i18n;
|
|
93
97
|
|
|
94
98
|
this.boundAddRowClick = options.onAddRow;
|
|
95
99
|
this.boundAddColClick = options.onAddColumn;
|
|
@@ -151,10 +155,15 @@ export class TableAddControls {
|
|
|
151
155
|
* Disables pointer events and hover effects during cell selection.
|
|
152
156
|
*/
|
|
153
157
|
public setInteractive(interactive: boolean): void {
|
|
154
|
-
|
|
158
|
+
if (!interactive) {
|
|
159
|
+
this.addRowBtn.style.pointerEvents = 'none';
|
|
160
|
+
this.addColBtn.style.pointerEvents = 'none';
|
|
155
161
|
|
|
156
|
-
|
|
157
|
-
|
|
162
|
+
return;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
this.addRowBtn.style.pointerEvents = this.rowVisible ? '' : 'none';
|
|
166
|
+
this.addColBtn.style.pointerEvents = this.colVisible ? '' : 'none';
|
|
158
167
|
}
|
|
159
168
|
|
|
160
169
|
public destroy(): void {
|
|
@@ -314,6 +323,7 @@ export class TableAddControls {
|
|
|
314
323
|
|
|
315
324
|
if (!this.rowVisible) {
|
|
316
325
|
this.addRowBtn.style.opacity = '1';
|
|
326
|
+
this.addRowBtn.style.pointerEvents = '';
|
|
317
327
|
this.rowVisible = true;
|
|
318
328
|
}
|
|
319
329
|
}
|
|
@@ -323,6 +333,7 @@ export class TableAddControls {
|
|
|
323
333
|
|
|
324
334
|
if (!this.colVisible) {
|
|
325
335
|
this.addColBtn.style.opacity = '1';
|
|
336
|
+
this.addColBtn.style.pointerEvents = '';
|
|
326
337
|
this.colVisible = true;
|
|
327
338
|
}
|
|
328
339
|
}
|
|
@@ -334,6 +345,7 @@ export class TableAddControls {
|
|
|
334
345
|
|
|
335
346
|
this.rowHideTimeout = setTimeout(() => {
|
|
336
347
|
this.addRowBtn.style.opacity = '0';
|
|
348
|
+
this.addRowBtn.style.pointerEvents = 'none';
|
|
337
349
|
this.rowVisible = false;
|
|
338
350
|
this.rowHideTimeout = null;
|
|
339
351
|
}, HIDE_DELAY_MS);
|
|
@@ -346,6 +358,7 @@ export class TableAddControls {
|
|
|
346
358
|
|
|
347
359
|
this.colHideTimeout = setTimeout(() => {
|
|
348
360
|
this.addColBtn.style.opacity = '0';
|
|
361
|
+
this.addColBtn.style.pointerEvents = 'none';
|
|
349
362
|
this.colVisible = false;
|
|
350
363
|
this.colHideTimeout = null;
|
|
351
364
|
}, HIDE_DELAY_MS);
|
|
@@ -372,6 +385,10 @@ export class TableAddControls {
|
|
|
372
385
|
btn.setAttribute(ADD_ROW_ATTR, '');
|
|
373
386
|
btn.setAttribute('contenteditable', 'false');
|
|
374
387
|
btn.style.opacity = '0';
|
|
388
|
+
btn.style.pointerEvents = 'none';
|
|
389
|
+
btn.style.position = 'absolute';
|
|
390
|
+
btn.style.left = '0';
|
|
391
|
+
btn.style.bottom = '-36px';
|
|
375
392
|
btn.style.boxSizing = 'content-box';
|
|
376
393
|
btn.style.width = '100%';
|
|
377
394
|
btn.style.height = '32px';
|
|
@@ -388,8 +405,8 @@ export class TableAddControls {
|
|
|
388
405
|
btn.appendChild(visual);
|
|
389
406
|
|
|
390
407
|
onHover(btn, createTooltipContent([
|
|
391
|
-
'
|
|
392
|
-
'
|
|
408
|
+
this.i18n.t('tools.table.clickToAddRow'),
|
|
409
|
+
this.i18n.t('tools.table.dragToAddRemoveRows'),
|
|
393
410
|
]), { placement: 'bottom', marginTop: -16 });
|
|
394
411
|
|
|
395
412
|
return btn;
|
|
@@ -402,6 +419,7 @@ export class TableAddControls {
|
|
|
402
419
|
btn.setAttribute(ADD_COL_ATTR, '');
|
|
403
420
|
btn.setAttribute('contenteditable', 'false');
|
|
404
421
|
btn.style.opacity = '0';
|
|
422
|
+
btn.style.pointerEvents = 'none';
|
|
405
423
|
btn.style.position = 'absolute';
|
|
406
424
|
btn.style.right = '-36px';
|
|
407
425
|
btn.style.top = '0px';
|
|
@@ -418,8 +436,8 @@ export class TableAddControls {
|
|
|
418
436
|
btn.appendChild(visual);
|
|
419
437
|
|
|
420
438
|
onHover(btn, createTooltipContent([
|
|
421
|
-
'
|
|
422
|
-
'
|
|
439
|
+
this.i18n.t('tools.table.clickToAddColumn'),
|
|
440
|
+
this.i18n.t('tools.table.dragToAddRemoveColumns'),
|
|
423
441
|
]), { placement: 'bottom' });
|
|
424
442
|
|
|
425
443
|
return btn;
|
|
@@ -71,6 +71,7 @@ export class TableCellBlocks {
|
|
|
71
71
|
this.onNavigateToCell = options.onNavigateToCell;
|
|
72
72
|
|
|
73
73
|
this.api.events.on('block changed', this.handleBlockMutation);
|
|
74
|
+
this.gridElement.addEventListener('click', this.handleCellBlankSpaceClick);
|
|
74
75
|
}
|
|
75
76
|
|
|
76
77
|
/**
|
|
@@ -575,10 +576,71 @@ export class TableCellBlocks {
|
|
|
575
576
|
});
|
|
576
577
|
}
|
|
577
578
|
|
|
579
|
+
/**
|
|
580
|
+
* Delete all blocks managed by this table from the BlockManager.
|
|
581
|
+
* Called before the table block itself is removed to prevent orphaned cell blocks.
|
|
582
|
+
*/
|
|
583
|
+
public deleteAllBlocks(): void {
|
|
584
|
+
const allCells = this.gridElement.querySelectorAll(`[${CELL_ATTR}]`);
|
|
585
|
+
const blockIds = this.getBlockIdsFromCells(allCells);
|
|
586
|
+
|
|
587
|
+
this.deleteBlocks(blockIds);
|
|
588
|
+
}
|
|
589
|
+
|
|
590
|
+
/**
|
|
591
|
+
* Handle clicks on blank cell space.
|
|
592
|
+
* When a click lands on the cell or blocks container (not on block content),
|
|
593
|
+
* set the caret to the end of the last block in that cell.
|
|
594
|
+
*/
|
|
595
|
+
private handleCellBlankSpaceClick = (event: Event): void => {
|
|
596
|
+
const target = event.target as HTMLElement | null;
|
|
597
|
+
|
|
598
|
+
if (!target) {
|
|
599
|
+
return;
|
|
600
|
+
}
|
|
601
|
+
|
|
602
|
+
const isCell = target.hasAttribute(CELL_ATTR);
|
|
603
|
+
const isBlocksContainer = target.hasAttribute(CELL_BLOCKS_ATTR);
|
|
604
|
+
|
|
605
|
+
if (!isCell && !isBlocksContainer) {
|
|
606
|
+
return;
|
|
607
|
+
}
|
|
608
|
+
|
|
609
|
+
const cell = isCell ? target : target.closest<HTMLElement>(`[${CELL_ATTR}]`);
|
|
610
|
+
|
|
611
|
+
if (!cell) {
|
|
612
|
+
return;
|
|
613
|
+
}
|
|
614
|
+
|
|
615
|
+
const container = isCell
|
|
616
|
+
? cell.querySelector<HTMLElement>(`[${CELL_BLOCKS_ATTR}]`)
|
|
617
|
+
: target;
|
|
618
|
+
|
|
619
|
+
if (!container) {
|
|
620
|
+
return;
|
|
621
|
+
}
|
|
622
|
+
|
|
623
|
+
const blockHolders = container.querySelectorAll('[data-blok-id]');
|
|
624
|
+
const lastHolder = blockHolders[blockHolders.length - 1];
|
|
625
|
+
|
|
626
|
+
if (!lastHolder) {
|
|
627
|
+
return;
|
|
628
|
+
}
|
|
629
|
+
|
|
630
|
+
const blockId = lastHolder.getAttribute('data-blok-id');
|
|
631
|
+
|
|
632
|
+
if (!blockId) {
|
|
633
|
+
return;
|
|
634
|
+
}
|
|
635
|
+
|
|
636
|
+
this.api.caret.setToBlock(blockId, 'end');
|
|
637
|
+
};
|
|
638
|
+
|
|
578
639
|
/**
|
|
579
640
|
* Clean up event listeners
|
|
580
641
|
*/
|
|
581
642
|
destroy(): void {
|
|
643
|
+
this.gridElement.removeEventListener('click', this.handleCellBlankSpaceClick);
|
|
582
644
|
this.api.events.off('block changed', this.handleBlockMutation);
|
|
583
645
|
this._activeCellWithBlocks = null;
|
|
584
646
|
this.cellsPendingCheck.clear();
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { I18n } from '../../../types/api';
|
|
1
2
|
import { IconCross } from '../../components/icons';
|
|
2
3
|
import { PopoverDesktop } from '../../components/utils/popover';
|
|
3
4
|
import { twMerge } from '../../components/utils/tw';
|
|
@@ -56,6 +57,7 @@ interface CellSelectionOptions {
|
|
|
56
57
|
rectangleSelection?: { cancelActiveSelection: () => void };
|
|
57
58
|
onSelectionActiveChange?: (hasSelection: boolean) => void;
|
|
58
59
|
onClearContent?: (cells: HTMLElement[]) => void;
|
|
60
|
+
i18n: I18n;
|
|
59
61
|
}
|
|
60
62
|
|
|
61
63
|
export class TableCellSelection {
|
|
@@ -63,6 +65,7 @@ export class TableCellSelection {
|
|
|
63
65
|
private rectangleSelection?: { cancelActiveSelection: () => void };
|
|
64
66
|
private onSelectionActiveChange: ((hasSelection: boolean) => void) | undefined;
|
|
65
67
|
private onClearContent: ((cells: HTMLElement[]) => void) | undefined;
|
|
68
|
+
private i18n: I18n;
|
|
66
69
|
private anchorCell: CellCoord | null = null;
|
|
67
70
|
private extentCell: CellCoord | null = null;
|
|
68
71
|
private isSelecting = false;
|
|
@@ -77,12 +80,14 @@ export class TableCellSelection {
|
|
|
77
80
|
private boundPointerUp: () => void;
|
|
78
81
|
private boundClearSelection: (e: PointerEvent) => void;
|
|
79
82
|
private boundCancelRectangle: (e: MouseEvent) => void;
|
|
83
|
+
private boundKeyDown: (e: KeyboardEvent) => void;
|
|
80
84
|
|
|
81
85
|
constructor(options: CellSelectionOptions) {
|
|
82
86
|
this.grid = options.grid;
|
|
83
87
|
this.rectangleSelection = options.rectangleSelection;
|
|
84
88
|
this.onSelectionActiveChange = options.onSelectionActiveChange;
|
|
85
89
|
this.onClearContent = options.onClearContent;
|
|
90
|
+
this.i18n = options.i18n;
|
|
86
91
|
this.grid.style.position = 'relative';
|
|
87
92
|
|
|
88
93
|
this.boundPointerDown = this.handlePointerDown.bind(this);
|
|
@@ -90,8 +95,10 @@ export class TableCellSelection {
|
|
|
90
95
|
this.boundPointerUp = this.handlePointerUp.bind(this);
|
|
91
96
|
this.boundClearSelection = this.handleClearSelection.bind(this);
|
|
92
97
|
this.boundCancelRectangle = this.handleCancelRectangle.bind(this);
|
|
98
|
+
this.boundKeyDown = this.handleKeyDown.bind(this);
|
|
93
99
|
|
|
94
100
|
this.grid.addEventListener('pointerdown', this.boundPointerDown);
|
|
101
|
+
document.addEventListener('keydown', this.boundKeyDown);
|
|
95
102
|
}
|
|
96
103
|
|
|
97
104
|
public destroy(): void {
|
|
@@ -102,6 +109,7 @@ export class TableCellSelection {
|
|
|
102
109
|
document.removeEventListener('pointerup', this.boundPointerUp);
|
|
103
110
|
document.removeEventListener('pointerdown', this.boundClearSelection);
|
|
104
111
|
document.removeEventListener('mousemove', this.boundCancelRectangle, true);
|
|
112
|
+
document.removeEventListener('keydown', this.boundKeyDown);
|
|
105
113
|
}
|
|
106
114
|
|
|
107
115
|
/**
|
|
@@ -276,6 +284,25 @@ export class TableCellSelection {
|
|
|
276
284
|
this.clearSelection();
|
|
277
285
|
}
|
|
278
286
|
|
|
287
|
+
private handleKeyDown(e: KeyboardEvent): void {
|
|
288
|
+
// Only trigger when selection is active
|
|
289
|
+
if (!this.hasSelection) {
|
|
290
|
+
return;
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
// Check for Delete or Backspace
|
|
294
|
+
if (e.key !== 'Delete' && e.key !== 'Backspace') {
|
|
295
|
+
return;
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
// Prevent default behavior
|
|
299
|
+
e.preventDefault();
|
|
300
|
+
|
|
301
|
+
// Clear content and dismiss selection
|
|
302
|
+
this.onClearContent?.([...this.selectedCells]);
|
|
303
|
+
this.clearSelection();
|
|
304
|
+
}
|
|
305
|
+
|
|
279
306
|
private clearSelection(): void {
|
|
280
307
|
const hadSelection = this.hasSelection;
|
|
281
308
|
|
|
@@ -348,26 +375,10 @@ export class TableCellSelection {
|
|
|
348
375
|
const rows = this.grid.querySelectorAll(`[${ROW_ATTR}]`);
|
|
349
376
|
|
|
350
377
|
// Mark selected cells
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
continue;
|
|
356
|
-
}
|
|
357
|
-
|
|
358
|
-
const cells = row.querySelectorAll(`[${CELL_ATTR}]`);
|
|
359
|
-
|
|
360
|
-
for (let c = minCol; c <= maxCol; c++) {
|
|
361
|
-
const cell = cells[c] as HTMLElement | undefined;
|
|
362
|
-
|
|
363
|
-
if (!cell) {
|
|
364
|
-
continue;
|
|
365
|
-
}
|
|
366
|
-
|
|
367
|
-
cell.setAttribute(SELECTED_ATTR, '');
|
|
368
|
-
this.selectedCells.push(cell);
|
|
369
|
-
}
|
|
370
|
-
}
|
|
378
|
+
this.selectedCells = this.collectCellsInRange(rows, minRow, maxRow, minCol, maxCol);
|
|
379
|
+
this.selectedCells.forEach(cell => {
|
|
380
|
+
cell.setAttribute(SELECTED_ATTR, '');
|
|
381
|
+
});
|
|
371
382
|
|
|
372
383
|
// Calculate overlay position from bounding rects of corner cells
|
|
373
384
|
const firstCell = rows[minRow]?.querySelectorAll(`[${CELL_ATTR}]`)[minCol] as HTMLElement | undefined;
|
|
@@ -388,16 +399,14 @@ export class TableCellSelection {
|
|
|
388
399
|
const borderTop = parseFloat(gridStyle.borderTopWidth) || 0;
|
|
389
400
|
const borderLeft = parseFloat(gridStyle.borderLeftWidth) || 0;
|
|
390
401
|
|
|
391
|
-
let top = firstRect.top - gridRect.top - borderTop;
|
|
392
|
-
let left = firstRect.left - gridRect.left - borderLeft;
|
|
393
402
|
const width = lastRect.right - firstRect.left + 1;
|
|
394
403
|
const height = lastRect.bottom - firstRect.top + 1;
|
|
395
404
|
|
|
396
405
|
// Extend overlay 1px outward to cover adjacent borders:
|
|
397
406
|
// grid border-top/border-left at row 0/col 0, or the previous
|
|
398
407
|
// row's border-bottom / previous column's border-right otherwise.
|
|
399
|
-
top
|
|
400
|
-
left
|
|
408
|
+
const top = firstRect.top - gridRect.top - borderTop - 1;
|
|
409
|
+
const left = firstRect.left - gridRect.left - borderLeft - 1;
|
|
401
410
|
|
|
402
411
|
// Create overlay once, reuse on subsequent paints
|
|
403
412
|
if (!this.overlay) {
|
|
@@ -476,7 +485,7 @@ export class TableCellSelection {
|
|
|
476
485
|
const items: PopoverItemParams[] = [
|
|
477
486
|
{
|
|
478
487
|
icon: IconCross,
|
|
479
|
-
title: '
|
|
488
|
+
title: this.i18n.t('tools.table.clearSelection'),
|
|
480
489
|
closeOnActivate: true,
|
|
481
490
|
onActivate: (): void => {
|
|
482
491
|
this.onClearContent?.([...this.selectedCells]);
|
|
@@ -592,27 +601,8 @@ export class TableCellSelection {
|
|
|
592
601
|
return;
|
|
593
602
|
}
|
|
594
603
|
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
if (e.clientY < gridRect.top) {
|
|
599
|
-
row = 0;
|
|
600
|
-
} else if (e.clientY > gridRect.bottom) {
|
|
601
|
-
row = rowCount - 1;
|
|
602
|
-
} else {
|
|
603
|
-
row = this.extentCell?.row ?? this.anchorCell.row;
|
|
604
|
-
}
|
|
605
|
-
|
|
606
|
-
// Clamp col
|
|
607
|
-
let col: number;
|
|
608
|
-
|
|
609
|
-
if (e.clientX < gridRect.left) {
|
|
610
|
-
col = 0;
|
|
611
|
-
} else if (e.clientX > gridRect.right) {
|
|
612
|
-
col = colCount - 1;
|
|
613
|
-
} else {
|
|
614
|
-
col = this.extentCell?.col ?? this.anchorCell.col;
|
|
615
|
-
}
|
|
604
|
+
const row = this.clampAxis(e.clientY, gridRect.top, gridRect.bottom, rowCount, this.extentCell?.row ?? this.anchorCell.row);
|
|
605
|
+
const col = this.clampAxis(e.clientX, gridRect.left, gridRect.right, colCount, this.extentCell?.col ?? this.anchorCell.col);
|
|
616
606
|
|
|
617
607
|
const clamped = { row, col };
|
|
618
608
|
|
|
@@ -621,4 +611,38 @@ export class TableCellSelection {
|
|
|
621
611
|
this.paintSelection();
|
|
622
612
|
}
|
|
623
613
|
}
|
|
614
|
+
|
|
615
|
+
private collectCellsInRange(
|
|
616
|
+
rows: NodeListOf<Element>,
|
|
617
|
+
minRow: number,
|
|
618
|
+
maxRow: number,
|
|
619
|
+
minCol: number,
|
|
620
|
+
maxCol: number,
|
|
621
|
+
): HTMLElement[] {
|
|
622
|
+
return Array.from(rows)
|
|
623
|
+
.slice(minRow, maxRow + 1)
|
|
624
|
+
.flatMap(row => {
|
|
625
|
+
const cells = row.querySelectorAll(`[${CELL_ATTR}]`);
|
|
626
|
+
|
|
627
|
+
return Array.from(cells)
|
|
628
|
+
.slice(minCol, maxCol + 1)
|
|
629
|
+
.filter((cell): cell is HTMLElement => cell instanceof HTMLElement);
|
|
630
|
+
});
|
|
631
|
+
}
|
|
632
|
+
|
|
633
|
+
/**
|
|
634
|
+
* Clamp a pointer coordinate to an axis range, returning the edge index
|
|
635
|
+
* when outside or the fallback when inside.
|
|
636
|
+
*/
|
|
637
|
+
private clampAxis(pointer: number, min: number, max: number, count: number, fallback: number): number {
|
|
638
|
+
if (pointer < min) {
|
|
639
|
+
return 0;
|
|
640
|
+
}
|
|
641
|
+
|
|
642
|
+
if (pointer > max) {
|
|
643
|
+
return count - 1;
|
|
644
|
+
}
|
|
645
|
+
|
|
646
|
+
return fallback;
|
|
647
|
+
}
|
|
624
648
|
}
|