@atlaskit/editor-plugin-table 5.4.11 → 5.4.13
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/CHANGELOG.md +15 -0
- package/dist/cjs/plugins/table/event-handlers.js +10 -4
- package/dist/cjs/plugins/table/toolbar.js +3 -6
- package/dist/cjs/plugins/table/ui/ColumnResizeWidget/index.js +3 -6
- package/dist/cjs/plugins/table/ui/DragHandle/index.js +12 -6
- package/dist/cjs/plugins/table/ui/DragPreview/index.js +2 -0
- package/dist/cjs/plugins/table/ui/FloatingContextualButton/index.js +7 -10
- package/dist/cjs/plugins/table/ui/FloatingContextualMenu/ContextualMenu.js +10 -11
- package/dist/cjs/plugins/table/ui/FloatingContextualMenu/index.js +3 -6
- package/dist/cjs/plugins/table/ui/FloatingDragMenu/DragMenu.js +4 -7
- package/dist/cjs/plugins/table/ui/TableFloatingColumnControls/index.js +1 -4
- package/dist/cjs/plugins/table/utils/column-controls.js +63 -1
- package/dist/cjs/plugins/table/utils/index.js +12 -0
- package/dist/es2019/plugins/table/event-handlers.js +11 -5
- package/dist/es2019/plugins/table/toolbar.js +3 -5
- package/dist/es2019/plugins/table/ui/ColumnResizeWidget/index.js +3 -5
- package/dist/es2019/plugins/table/ui/DragHandle/index.js +11 -4
- package/dist/es2019/plugins/table/ui/DragPreview/index.js +2 -0
- package/dist/es2019/plugins/table/ui/FloatingContextualButton/index.js +7 -9
- package/dist/es2019/plugins/table/ui/FloatingContextualMenu/ContextualMenu.js +9 -11
- package/dist/es2019/plugins/table/ui/FloatingContextualMenu/index.js +3 -5
- package/dist/es2019/plugins/table/ui/FloatingDragMenu/DragMenu.js +4 -6
- package/dist/es2019/plugins/table/ui/TableFloatingColumnControls/index.js +1 -4
- package/dist/es2019/plugins/table/utils/column-controls.js +62 -0
- package/dist/es2019/plugins/table/utils/index.js +1 -1
- package/dist/esm/plugins/table/event-handlers.js +11 -5
- package/dist/esm/plugins/table/toolbar.js +3 -5
- package/dist/esm/plugins/table/ui/ColumnResizeWidget/index.js +3 -5
- package/dist/esm/plugins/table/ui/DragHandle/index.js +11 -5
- package/dist/esm/plugins/table/ui/DragPreview/index.js +2 -0
- package/dist/esm/plugins/table/ui/FloatingContextualButton/index.js +7 -9
- package/dist/esm/plugins/table/ui/FloatingContextualMenu/ContextualMenu.js +9 -11
- package/dist/esm/plugins/table/ui/FloatingContextualMenu/index.js +3 -5
- package/dist/esm/plugins/table/ui/FloatingDragMenu/DragMenu.js +4 -6
- package/dist/esm/plugins/table/ui/TableFloatingColumnControls/index.js +1 -4
- package/dist/esm/plugins/table/utils/column-controls.js +62 -0
- package/dist/esm/plugins/table/utils/index.js +1 -1
- package/dist/types/plugins/table/utils/column-controls.d.ts +3 -0
- package/dist/types/plugins/table/utils/index.d.ts +1 -1
- package/dist/types-ts4.5/plugins/table/utils/column-controls.d.ts +3 -0
- package/dist/types-ts4.5/plugins/table/utils/index.d.ts +1 -1
- package/package.json +4 -4
- package/src/__tests__/unit/utils/column-controls.ts +145 -1
- package/src/plugins/table/event-handlers.ts +22 -4
- package/src/plugins/table/ui/DragHandle/index.tsx +30 -21
- package/src/plugins/table/ui/TableFloatingColumnControls/index.tsx +1 -5
- package/src/plugins/table/utils/column-controls.ts +81 -0
- package/src/plugins/table/utils/index.ts +2 -0
- package/src/__tests__/integration/block-node-selection.ts +0 -165
|
@@ -1,6 +1,4 @@
|
|
|
1
1
|
import _toConsumableArray from "@babel/runtime/helpers/toConsumableArray";
|
|
2
|
-
/** @jsx jsx */
|
|
3
|
-
import { jsx } from '@emotion/react';
|
|
4
2
|
import { ArrowKeyNavigationType, DropdownMenu } from '@atlaskit/editor-common/ui-menu';
|
|
5
3
|
import { shortcutStyle } from '@atlaskit/editor-shared-styles/shortcut';
|
|
6
4
|
import { TableMap } from '@atlaskit/editor-tables/table-map';
|
|
@@ -31,15 +29,15 @@ var convertToDropdownItems = function convertToDropdownItems(dragMenuConfig) {
|
|
|
31
29
|
name: item.id
|
|
32
30
|
},
|
|
33
31
|
isDisabled: item.disabled,
|
|
34
|
-
elemBefore: item.icon ?
|
|
32
|
+
elemBefore: item.icon ? /*#__PURE__*/React.createElement("div", {
|
|
35
33
|
style: {
|
|
36
34
|
marginRight: "var(--ds-space-negative-075, -6px)",
|
|
37
35
|
display: 'flex'
|
|
38
36
|
}
|
|
39
|
-
},
|
|
37
|
+
}, /*#__PURE__*/React.createElement(item.icon, {
|
|
40
38
|
label: item.title
|
|
41
39
|
})) : undefined,
|
|
42
|
-
elemAfter: item.keymap ?
|
|
40
|
+
elemAfter: item.keymap ? /*#__PURE__*/React.createElement("div", {
|
|
43
41
|
css: shortcutStyle
|
|
44
42
|
}, item.keymap) : undefined
|
|
45
43
|
});
|
|
@@ -131,7 +129,7 @@ export var DragMenu = function DragMenu(_ref) {
|
|
|
131
129
|
if (!menuItems) {
|
|
132
130
|
return null;
|
|
133
131
|
}
|
|
134
|
-
return
|
|
132
|
+
return /*#__PURE__*/React.createElement(DropdownMenu, {
|
|
135
133
|
mountTo: mountPoint
|
|
136
134
|
//This needs be removed when the a11y is completely handled
|
|
137
135
|
//Disabling key navigation now as it works only partially
|
|
@@ -89,14 +89,11 @@ export var TableFloatingColumnControls = function TableFloatingColumnControls(_r
|
|
|
89
89
|
}
|
|
90
90
|
return [0];
|
|
91
91
|
}, [tableRef, tableRect.height]);
|
|
92
|
-
if (!tableRef) {
|
|
92
|
+
if (!tableRef || !tableActive) {
|
|
93
93
|
return null;
|
|
94
94
|
}
|
|
95
95
|
var colWidths = getColumnsWidths(editorView);
|
|
96
96
|
var stickyTop = stickyHeader && stickyHeader.sticky && hasHeaderRow ? stickyHeader.top : undefined;
|
|
97
|
-
if (!tableActive) {
|
|
98
|
-
return null;
|
|
99
|
-
}
|
|
100
97
|
return /*#__PURE__*/React.createElement("div", {
|
|
101
98
|
className: ClassName.DRAG_COLUMN_CONTROLS_WRAPPER,
|
|
102
99
|
"data-testid": "table-floating-column-controls-wrapper"
|
|
@@ -182,4 +182,66 @@ export var colWidthsForRow = function colWidthsForRow(tr) {
|
|
|
182
182
|
return pctWidths.map(function (pct) {
|
|
183
183
|
return "".concat(pct, "%");
|
|
184
184
|
}).join(' ');
|
|
185
|
+
};
|
|
186
|
+
export var convertHTMLCellIndexToColumnIndex = function convertHTMLCellIndexToColumnIndex(htmlColIndex, htmlRowIndex, tableMap) {
|
|
187
|
+
// Same numbers (positions) in tableMap.map array mean that there are merged cells.
|
|
188
|
+
// Cells can be merged across columns. So we need to check if the cell on the left and current cell have the same value.
|
|
189
|
+
// Cells can be merged acroll rows. So we need to check if the cell above has the same value as current cell.
|
|
190
|
+
// When cell has the same value as the cell above it or the cell to the left of it, html cellIndex won't count it a separete column.
|
|
191
|
+
var width = tableMap.width;
|
|
192
|
+
var map = tableMap.map;
|
|
193
|
+
var htmlColCount = 0;
|
|
194
|
+
if (htmlRowIndex === 0) {
|
|
195
|
+
for (var colIndex = 0; colIndex < width; colIndex++) {
|
|
196
|
+
if (colIndex === 0 || map[colIndex] !== map[colIndex - 1]) {
|
|
197
|
+
htmlColCount++;
|
|
198
|
+
}
|
|
199
|
+
if (htmlColCount - 1 === htmlColIndex) {
|
|
200
|
+
return colIndex;
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
} else {
|
|
204
|
+
for (var _colIndex = 0; _colIndex < width; _colIndex++) {
|
|
205
|
+
var currentCellMapIndex = htmlRowIndex * width + _colIndex;
|
|
206
|
+
var cellAboveMapIndex = (htmlRowIndex - 1) * width + _colIndex;
|
|
207
|
+
if (_colIndex > 0) {
|
|
208
|
+
if (map[currentCellMapIndex] !== map[currentCellMapIndex - 1] && map[currentCellMapIndex] !== map[cellAboveMapIndex]) {
|
|
209
|
+
htmlColCount++;
|
|
210
|
+
}
|
|
211
|
+
} else {
|
|
212
|
+
if (map[currentCellMapIndex] !== map[cellAboveMapIndex]) {
|
|
213
|
+
htmlColCount++;
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
if (htmlColCount - 1 === htmlColIndex) {
|
|
217
|
+
return _colIndex;
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
return 0;
|
|
222
|
+
};
|
|
223
|
+
|
|
224
|
+
// When first row has merged cells, our converted column index needs to be mapped.
|
|
225
|
+
export var getColumnIndexMappedToColumnIndexInFirstRow = function getColumnIndexMappedToColumnIndexInFirstRow(convertedColIndex, htmlRowIndex, tableMap) {
|
|
226
|
+
var width = tableMap.width;
|
|
227
|
+
var map = tableMap.map;
|
|
228
|
+
var mapColIndexToFistRowColIndex = [];
|
|
229
|
+
var htmlColCounFirstRow = 0;
|
|
230
|
+
var colSpan = 0;
|
|
231
|
+
if (htmlRowIndex === 0) {
|
|
232
|
+
return convertedColIndex;
|
|
233
|
+
}
|
|
234
|
+
for (var colIndex = 0; colIndex < width; colIndex++) {
|
|
235
|
+
if (colIndex === 0 || map[colIndex] !== map[colIndex - 1]) {
|
|
236
|
+
if (colSpan > 0) {
|
|
237
|
+
htmlColCounFirstRow += colSpan;
|
|
238
|
+
colSpan = 0;
|
|
239
|
+
}
|
|
240
|
+
htmlColCounFirstRow++;
|
|
241
|
+
} else if (map[colIndex] === map[colIndex - 1]) {
|
|
242
|
+
colSpan++;
|
|
243
|
+
}
|
|
244
|
+
mapColIndexToFistRowColIndex[colIndex] = htmlColCounFirstRow - 1;
|
|
245
|
+
}
|
|
246
|
+
return mapColIndexToFistRowColIndex[convertedColIndex];
|
|
185
247
|
};
|
|
@@ -3,7 +3,7 @@ export { findControlsHoverDecoration, createControlsHoverDecoration, createColum
|
|
|
3
3
|
export { isIsolating, containsHeaderColumn, containsHeaderRow, checkIfHeaderColumnEnabled, checkIfHeaderRowEnabled, checkIfNumberColumnEnabled, isLayoutSupported, getTableWidth, tablesHaveDifferentColumnWidths, tablesHaveDifferentNoOfColumns, isTableNested, anyChildCellMergedAcrossRow, supportedHeaderRow } from './nodes';
|
|
4
4
|
export { unwrapContentFromTable, removeTableFromFirstChild, removeTableFromLastChild, transformSliceToRemoveOpenTable, transformSliceToCorrectEmptyTableCells, transformSliceToFixHardBreakProblemOnCopyFromCell } from './paste';
|
|
5
5
|
export { isCell, isCornerButton, isInsertRowButton, isColumnControlsDecorations, isTableControlsButton, isTableContainerOrWrapper, isRowControlsButton, isDragRowControlsButton, isDragColumnFloatingInsertDot, isDragRowFloatingInsertDot, isDragCornerButton, getColumnOrRowIndex, getMousePositionHorizontalRelativeByElement, getMousePositionVerticalRelativeByElement, updateResizeHandles, isResizeHandleDecoration, hasResizeHandler } from './dom';
|
|
6
|
-
export { getColumnsWidths, isColumnDeleteButtonVisible, getColumnDeleteButtonParams, getColumnClassNames } from './column-controls';
|
|
6
|
+
export { convertHTMLCellIndexToColumnIndex, getColumnsWidths, isColumnDeleteButtonVisible, getColumnDeleteButtonParams, getColumnClassNames, getColumnIndexMappedToColumnIndexInFirstRow } from './column-controls';
|
|
7
7
|
export { getRowHeights, isRowDeleteButtonVisible, getRowDeleteButtonParams, getRowsParams, getRowClassNames, copyPreviousRow } from './row-controls';
|
|
8
8
|
export { getSelectedTableInfo, getSelectedCellInfo } from './analytics';
|
|
9
9
|
export { getMergedCellsPositions } from './table';
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { Selection } from '@atlaskit/editor-prosemirror/state';
|
|
2
2
|
import type { EditorView } from '@atlaskit/editor-prosemirror/view';
|
|
3
|
+
import { TableMap } from '@atlaskit/editor-tables/table-map';
|
|
3
4
|
export declare const getColumnsWidths: (view: EditorView) => Array<number | undefined>;
|
|
4
5
|
export declare const isColumnDeleteButtonVisible: (selection: Selection) => boolean;
|
|
5
6
|
export declare const getColumnDeleteButtonParams: (columnsWidths: Array<number | undefined>, selection: Selection) => {
|
|
@@ -8,3 +9,5 @@ export declare const getColumnDeleteButtonParams: (columnsWidths: Array<number |
|
|
|
8
9
|
} | null;
|
|
9
10
|
export declare const getColumnClassNames: (index: number, selection: Selection, hoveredColumns?: number[], isInDanger?: boolean, isResizing?: boolean) => string;
|
|
10
11
|
export declare const colWidthsForRow: (tr: HTMLTableRowElement) => string;
|
|
12
|
+
export declare const convertHTMLCellIndexToColumnIndex: (htmlColIndex: number, htmlRowIndex: number, tableMap: TableMap) => number;
|
|
13
|
+
export declare const getColumnIndexMappedToColumnIndexInFirstRow: (convertedColIndex: number, htmlRowIndex: number, tableMap: TableMap) => number;
|
|
@@ -3,7 +3,7 @@ export { findControlsHoverDecoration, createControlsHoverDecoration, createColum
|
|
|
3
3
|
export { isIsolating, containsHeaderColumn, containsHeaderRow, checkIfHeaderColumnEnabled, checkIfHeaderRowEnabled, checkIfNumberColumnEnabled, isLayoutSupported, getTableWidth, tablesHaveDifferentColumnWidths, tablesHaveDifferentNoOfColumns, isTableNested, anyChildCellMergedAcrossRow, supportedHeaderRow, } from './nodes';
|
|
4
4
|
export { unwrapContentFromTable, removeTableFromFirstChild, removeTableFromLastChild, transformSliceToRemoveOpenTable, transformSliceToCorrectEmptyTableCells, transformSliceToFixHardBreakProblemOnCopyFromCell, } from './paste';
|
|
5
5
|
export { isCell, isCornerButton, isInsertRowButton, isColumnControlsDecorations, isTableControlsButton, isTableContainerOrWrapper, isRowControlsButton, isDragRowControlsButton, isDragColumnFloatingInsertDot, isDragRowFloatingInsertDot, isDragCornerButton, getColumnOrRowIndex, getMousePositionHorizontalRelativeByElement, getMousePositionVerticalRelativeByElement, updateResizeHandles, isResizeHandleDecoration, hasResizeHandler, } from './dom';
|
|
6
|
-
export { getColumnsWidths, isColumnDeleteButtonVisible, getColumnDeleteButtonParams, getColumnClassNames, } from './column-controls';
|
|
6
|
+
export { convertHTMLCellIndexToColumnIndex, getColumnsWidths, isColumnDeleteButtonVisible, getColumnDeleteButtonParams, getColumnClassNames, getColumnIndexMappedToColumnIndexInFirstRow, } from './column-controls';
|
|
7
7
|
export { getRowHeights, isRowDeleteButtonVisible, getRowDeleteButtonParams, getRowsParams, getRowClassNames, copyPreviousRow, } from './row-controls';
|
|
8
8
|
export type { RowParams } from './row-controls';
|
|
9
9
|
export { getSelectedTableInfo, getSelectedCellInfo } from './analytics';
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { Selection } from '@atlaskit/editor-prosemirror/state';
|
|
2
2
|
import type { EditorView } from '@atlaskit/editor-prosemirror/view';
|
|
3
|
+
import { TableMap } from '@atlaskit/editor-tables/table-map';
|
|
3
4
|
export declare const getColumnsWidths: (view: EditorView) => Array<number | undefined>;
|
|
4
5
|
export declare const isColumnDeleteButtonVisible: (selection: Selection) => boolean;
|
|
5
6
|
export declare const getColumnDeleteButtonParams: (columnsWidths: Array<number | undefined>, selection: Selection) => {
|
|
@@ -8,3 +9,5 @@ export declare const getColumnDeleteButtonParams: (columnsWidths: Array<number |
|
|
|
8
9
|
} | null;
|
|
9
10
|
export declare const getColumnClassNames: (index: number, selection: Selection, hoveredColumns?: number[], isInDanger?: boolean, isResizing?: boolean) => string;
|
|
10
11
|
export declare const colWidthsForRow: (tr: HTMLTableRowElement) => string;
|
|
12
|
+
export declare const convertHTMLCellIndexToColumnIndex: (htmlColIndex: number, htmlRowIndex: number, tableMap: TableMap) => number;
|
|
13
|
+
export declare const getColumnIndexMappedToColumnIndexInFirstRow: (convertedColIndex: number, htmlRowIndex: number, tableMap: TableMap) => number;
|
|
@@ -3,7 +3,7 @@ export { findControlsHoverDecoration, createControlsHoverDecoration, createColum
|
|
|
3
3
|
export { isIsolating, containsHeaderColumn, containsHeaderRow, checkIfHeaderColumnEnabled, checkIfHeaderRowEnabled, checkIfNumberColumnEnabled, isLayoutSupported, getTableWidth, tablesHaveDifferentColumnWidths, tablesHaveDifferentNoOfColumns, isTableNested, anyChildCellMergedAcrossRow, supportedHeaderRow, } from './nodes';
|
|
4
4
|
export { unwrapContentFromTable, removeTableFromFirstChild, removeTableFromLastChild, transformSliceToRemoveOpenTable, transformSliceToCorrectEmptyTableCells, transformSliceToFixHardBreakProblemOnCopyFromCell, } from './paste';
|
|
5
5
|
export { isCell, isCornerButton, isInsertRowButton, isColumnControlsDecorations, isTableControlsButton, isTableContainerOrWrapper, isRowControlsButton, isDragRowControlsButton, isDragColumnFloatingInsertDot, isDragRowFloatingInsertDot, isDragCornerButton, getColumnOrRowIndex, getMousePositionHorizontalRelativeByElement, getMousePositionVerticalRelativeByElement, updateResizeHandles, isResizeHandleDecoration, hasResizeHandler, } from './dom';
|
|
6
|
-
export { getColumnsWidths, isColumnDeleteButtonVisible, getColumnDeleteButtonParams, getColumnClassNames, } from './column-controls';
|
|
6
|
+
export { convertHTMLCellIndexToColumnIndex, getColumnsWidths, isColumnDeleteButtonVisible, getColumnDeleteButtonParams, getColumnClassNames, getColumnIndexMappedToColumnIndexInFirstRow, } from './column-controls';
|
|
7
7
|
export { getRowHeights, isRowDeleteButtonVisible, getRowDeleteButtonParams, getRowsParams, getRowClassNames, copyPreviousRow, } from './row-controls';
|
|
8
8
|
export type { RowParams } from './row-controls';
|
|
9
9
|
export { getSelectedTableInfo, getSelectedCellInfo } from './analytics';
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@atlaskit/editor-plugin-table",
|
|
3
|
-
"version": "5.4.
|
|
3
|
+
"version": "5.4.13",
|
|
4
4
|
"description": "Table plugin for the @atlaskit/editor",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"registry": "https://registry.npmjs.org/"
|
|
@@ -27,9 +27,9 @@
|
|
|
27
27
|
"releaseModel": "continuous"
|
|
28
28
|
},
|
|
29
29
|
"dependencies": {
|
|
30
|
-
"@atlaskit/adf-schema": "^
|
|
31
|
-
"@atlaskit/custom-steps": "^0.0.
|
|
32
|
-
"@atlaskit/editor-common": "^76.
|
|
30
|
+
"@atlaskit/adf-schema": "^35.0.0",
|
|
31
|
+
"@atlaskit/custom-steps": "^0.0.6",
|
|
32
|
+
"@atlaskit/editor-common": "^76.25.0",
|
|
33
33
|
"@atlaskit/editor-palette": "1.5.2",
|
|
34
34
|
"@atlaskit/editor-plugin-analytics": "^0.3.0",
|
|
35
35
|
"@atlaskit/editor-plugin-content-insertion": "^0.1.0",
|
|
@@ -1,4 +1,10 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import type { TableMap } from '@atlaskit/editor-tables';
|
|
2
|
+
|
|
3
|
+
import {
|
|
4
|
+
colWidthsForRow,
|
|
5
|
+
convertHTMLCellIndexToColumnIndex,
|
|
6
|
+
getColumnIndexMappedToColumnIndexInFirstRow,
|
|
7
|
+
} from '../../../plugins/table/utils/column-controls';
|
|
2
8
|
|
|
3
9
|
const createRow = (colCount: number, childType = 'td') => {
|
|
4
10
|
const tr = document.createElement('tr');
|
|
@@ -59,3 +65,141 @@ describe('table utilities', () => {
|
|
|
59
65
|
});
|
|
60
66
|
});
|
|
61
67
|
});
|
|
68
|
+
|
|
69
|
+
describe('table utilities - convertHTMLCellIndexToColumnIndex', () => {
|
|
70
|
+
/*
|
|
71
|
+
Table looks like this:
|
|
72
|
+
___ _______ ___ ___ ___
|
|
73
|
+
|___| |_A_|___|___|
|
|
74
|
+
|___| |___| |___|
|
|
75
|
+
|___|_______|_B_| |___|
|
|
76
|
+
|___|___|___|___| |___|
|
|
77
|
+
|___________|___|___|___|
|
|
78
|
+
|___________|___|_C_|___|
|
|
79
|
+
|___________|___|___|___|
|
|
80
|
+
|___|___|___|_D_|___|___|
|
|
81
|
+
|___|___|_E_____________|
|
|
82
|
+
*/
|
|
83
|
+
const tableMap = {
|
|
84
|
+
width: 6,
|
|
85
|
+
height: 9,
|
|
86
|
+
map: [
|
|
87
|
+
1, 5, 5, 9, 13, 17, 23, 5, 5, 27, 31, 35, 41, 5, 5, 45, 31, 49, 55, 59,
|
|
88
|
+
63, 67, 31, 71, 77, 77, 77, 81, 31, 85, 91, 91, 91, 95, 99, 103, 109, 109,
|
|
89
|
+
109, 113, 117, 121, 127, 131, 135, 139, 143, 147, 153, 157, 161, 161, 161,
|
|
90
|
+
161,
|
|
91
|
+
],
|
|
92
|
+
} as TableMap;
|
|
93
|
+
|
|
94
|
+
const testCases = [
|
|
95
|
+
[
|
|
96
|
+
'case A: when hovered cell is in the first row and first row has merged cells',
|
|
97
|
+
2, // htmlColIndex
|
|
98
|
+
0, // htmlRowIndex
|
|
99
|
+
3, // expected
|
|
100
|
+
],
|
|
101
|
+
[
|
|
102
|
+
'case B: when hoverd cell is not in the first row, but the row has merged cells',
|
|
103
|
+
1,
|
|
104
|
+
2,
|
|
105
|
+
3,
|
|
106
|
+
],
|
|
107
|
+
[
|
|
108
|
+
'case C: when a cell that is in the row above and to the left of current cell is merged',
|
|
109
|
+
3,
|
|
110
|
+
5,
|
|
111
|
+
5,
|
|
112
|
+
],
|
|
113
|
+
[
|
|
114
|
+
'case D: when first row has merged cell and hovered cell is below merged area',
|
|
115
|
+
2,
|
|
116
|
+
7,
|
|
117
|
+
2,
|
|
118
|
+
],
|
|
119
|
+
[
|
|
120
|
+
'case E: when first row has merged cell and hovered cell is below merged area and is part of merged area',
|
|
121
|
+
2,
|
|
122
|
+
8,
|
|
123
|
+
2,
|
|
124
|
+
],
|
|
125
|
+
];
|
|
126
|
+
|
|
127
|
+
describe('should convert cellIndex into colIndex correctly', () => {
|
|
128
|
+
test.each(testCases)(
|
|
129
|
+
'%s',
|
|
130
|
+
(message, htmlColIndex, htmlRowIndex, expected) => {
|
|
131
|
+
expect(
|
|
132
|
+
convertHTMLCellIndexToColumnIndex(
|
|
133
|
+
htmlColIndex as number,
|
|
134
|
+
htmlRowIndex as number,
|
|
135
|
+
tableMap,
|
|
136
|
+
),
|
|
137
|
+
).toEqual(expected);
|
|
138
|
+
},
|
|
139
|
+
);
|
|
140
|
+
});
|
|
141
|
+
});
|
|
142
|
+
|
|
143
|
+
describe('tableUtilities - getColumnIndexMappedToColumnIndexInFirstRow', () => {
|
|
144
|
+
/*
|
|
145
|
+
Table used for this tests looks like this:
|
|
146
|
+
___ _______ ___ ___ ___ ___ ___ ___________ ___
|
|
147
|
+
|___|_______|___|___|___|___|___|___________|_D_|
|
|
148
|
+
|___|_A_|_B_|___|___|___|___|___|___|_E_|___|___|
|
|
149
|
+
|___|___|_______|___|_____C_|___|___|___|___|___|
|
|
150
|
+
|___|___|___|___|___|___|___|___|___|___|___|___|
|
|
151
|
+
*/
|
|
152
|
+
|
|
153
|
+
const tableMap = {
|
|
154
|
+
width: 12,
|
|
155
|
+
height: 4,
|
|
156
|
+
map: [
|
|
157
|
+
1, 5, 5, 9, 13, 17, 21, 25, 29, 29, 29, 33, 39, 43, 47, 51, 55, 59, 63,
|
|
158
|
+
67, 71, 75, 79, 83, 89, 93, 97, 97, 101, 105, 105, 109, 113, 117, 121,
|
|
159
|
+
125, 131, 135, 139, 143, 147, 151, 155, 159, 163, 167, 171, 175,
|
|
160
|
+
],
|
|
161
|
+
} as TableMap;
|
|
162
|
+
|
|
163
|
+
const testCases = [
|
|
164
|
+
[
|
|
165
|
+
'case A: mouse is on a cell located below merged area of the first row closer to its start',
|
|
166
|
+
2, // convertedColIndex
|
|
167
|
+
1, // htmlRowIndex
|
|
168
|
+
1, // expected
|
|
169
|
+
],
|
|
170
|
+
[
|
|
171
|
+
'case B: mouse is on a cell located below merged area of the first row close to its end',
|
|
172
|
+
1,
|
|
173
|
+
1,
|
|
174
|
+
1,
|
|
175
|
+
],
|
|
176
|
+
[
|
|
177
|
+
'case E: mouse is on a cell located below merged area of the first row in the middle of the merged area',
|
|
178
|
+
9,
|
|
179
|
+
1,
|
|
180
|
+
8,
|
|
181
|
+
],
|
|
182
|
+
['case C: mouse is on a merged cell located below the first row', 5, 2, 5],
|
|
183
|
+
[
|
|
184
|
+
'case D: mouse is on a cell in the first row that is next to a merged cell',
|
|
185
|
+
11,
|
|
186
|
+
1,
|
|
187
|
+
11,
|
|
188
|
+
],
|
|
189
|
+
];
|
|
190
|
+
|
|
191
|
+
describe('should adapt converted colIndex when first row has merged cells', () => {
|
|
192
|
+
test.each(testCases)(
|
|
193
|
+
'%s',
|
|
194
|
+
(message, convertedColIndex, htmlRowIndex, expected) => {
|
|
195
|
+
expect(
|
|
196
|
+
getColumnIndexMappedToColumnIndexInFirstRow(
|
|
197
|
+
convertedColIndex as number,
|
|
198
|
+
htmlRowIndex as number,
|
|
199
|
+
tableMap,
|
|
200
|
+
),
|
|
201
|
+
).toEqual(expected);
|
|
202
|
+
},
|
|
203
|
+
);
|
|
204
|
+
});
|
|
205
|
+
});
|
|
@@ -48,6 +48,8 @@ import { deleteColumns, deleteRows } from './transforms';
|
|
|
48
48
|
import type { ElementContentRects } from './types';
|
|
49
49
|
import { RESIZE_HANDLE_AREA_DECORATION_GAP } from './types';
|
|
50
50
|
import {
|
|
51
|
+
convertHTMLCellIndexToColumnIndex,
|
|
52
|
+
getColumnIndexMappedToColumnIndexInFirstRow,
|
|
51
53
|
getColumnOrRowIndex,
|
|
52
54
|
getMousePositionHorizontalRelativeByElement,
|
|
53
55
|
getMousePositionVerticalRelativeByElement,
|
|
@@ -552,24 +554,40 @@ const trackCellLocation = (view: EditorView, mouseEvent: Event) => {
|
|
|
552
554
|
return;
|
|
553
555
|
}
|
|
554
556
|
|
|
555
|
-
const
|
|
557
|
+
const htmlColIndex = maybeTableCell.cellIndex;
|
|
556
558
|
const rowElement = closestElement(
|
|
557
559
|
target as HTMLElement,
|
|
558
560
|
'tr',
|
|
559
561
|
) as HTMLTableRowElement;
|
|
560
|
-
const
|
|
562
|
+
const htmlRowIndex = rowElement && rowElement.rowIndex;
|
|
561
563
|
|
|
562
564
|
const colHeight = tableRef.offsetHeight;
|
|
563
565
|
const colWidth = maybeTableCell.offsetWidth;
|
|
564
566
|
|
|
567
|
+
const tableMap = tableNode && TableMap.get(tableNode);
|
|
568
|
+
let colIndex = htmlColIndex;
|
|
569
|
+
if (tableMap) {
|
|
570
|
+
const convertedColIndex = convertHTMLCellIndexToColumnIndex(
|
|
571
|
+
htmlColIndex,
|
|
572
|
+
htmlRowIndex,
|
|
573
|
+
tableMap,
|
|
574
|
+
);
|
|
575
|
+
|
|
576
|
+
colIndex = getColumnIndexMappedToColumnIndexInFirstRow(
|
|
577
|
+
convertedColIndex,
|
|
578
|
+
htmlRowIndex,
|
|
579
|
+
tableMap,
|
|
580
|
+
);
|
|
581
|
+
}
|
|
582
|
+
|
|
565
583
|
if (
|
|
566
584
|
hoveredCell.colIndex !== colIndex ||
|
|
567
|
-
hoveredCell.rowIndex !==
|
|
585
|
+
hoveredCell.rowIndex !== htmlRowIndex ||
|
|
568
586
|
hoveredCell.colWidth !== colWidth ||
|
|
569
587
|
hoveredCell.colHeight !== colHeight
|
|
570
588
|
) {
|
|
571
589
|
hoverCell(
|
|
572
|
-
|
|
590
|
+
htmlRowIndex,
|
|
573
591
|
colIndex,
|
|
574
592
|
colWidth,
|
|
575
593
|
colHeight,
|
|
@@ -134,26 +134,35 @@ export const DragHandle = ({
|
|
|
134
134
|
]);
|
|
135
135
|
|
|
136
136
|
return (
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
137
|
+
<>
|
|
138
|
+
<button
|
|
139
|
+
className={classnames(
|
|
140
|
+
ClassName.DRAG_HANDLE_BUTTON_CONTAINER,
|
|
141
|
+
ClassName.CONTROLS_BUTTON,
|
|
142
|
+
appearance,
|
|
143
|
+
{
|
|
144
|
+
[ClassName.DRAG_HANDLE_DISABLED]:
|
|
145
|
+
isDragAndDropEnabled && hasMergedCells,
|
|
146
|
+
},
|
|
147
|
+
)}
|
|
148
|
+
ref={dragHandleDivRef}
|
|
149
|
+
style={{
|
|
150
|
+
transform: direction === 'column' ? 'none' : 'rotate(90deg)',
|
|
151
|
+
pointerEvents: 'auto',
|
|
152
|
+
}}
|
|
153
|
+
data-testid="table-floating-column-controls-drag-handle"
|
|
154
|
+
onMouseOver={onMouseOver}
|
|
155
|
+
onMouseOut={onMouseOut}
|
|
156
|
+
onMouseUp={(e) => {
|
|
157
|
+
// return focus to editor so copying table selections whilst still works, i cannot call e.preventDefault in a mousemove event as this stops dragstart events from firing
|
|
158
|
+
// -> this is bad for a11y but is the current standard new copy/paste keyboard shortcuts should be introduced instead
|
|
159
|
+
editorView.focus();
|
|
160
|
+
onMouseUp && onMouseUp(e);
|
|
161
|
+
}}
|
|
162
|
+
onClick={onClick}
|
|
163
|
+
>
|
|
164
|
+
<HandleIconComponent {...handleIconProps} />
|
|
165
|
+
</button>
|
|
157
166
|
{previewContainer &&
|
|
158
167
|
previewWidth !== undefined &&
|
|
159
168
|
previewHeight !== undefined &&
|
|
@@ -165,6 +174,6 @@ export const DragHandle = ({
|
|
|
165
174
|
/>,
|
|
166
175
|
previewContainer,
|
|
167
176
|
)}
|
|
168
|
-
|
|
177
|
+
</>
|
|
169
178
|
);
|
|
170
179
|
};
|
|
@@ -108,7 +108,7 @@ export const TableFloatingColumnControls: React.FC<Props> = ({
|
|
|
108
108
|
return [0];
|
|
109
109
|
}, [tableRef, tableRect.height]);
|
|
110
110
|
|
|
111
|
-
if (!tableRef) {
|
|
111
|
+
if (!tableRef || !tableActive) {
|
|
112
112
|
return null;
|
|
113
113
|
}
|
|
114
114
|
|
|
@@ -119,10 +119,6 @@ export const TableFloatingColumnControls: React.FC<Props> = ({
|
|
|
119
119
|
? stickyHeader.top
|
|
120
120
|
: undefined;
|
|
121
121
|
|
|
122
|
-
if (!tableActive) {
|
|
123
|
-
return null;
|
|
124
|
-
}
|
|
125
|
-
|
|
126
122
|
return (
|
|
127
123
|
<div
|
|
128
124
|
className={ClassName.DRAG_COLUMN_CONTROLS_WRAPPER}
|
|
@@ -217,3 +217,84 @@ export const colWidthsForRow = (tr: HTMLTableRowElement) => {
|
|
|
217
217
|
|
|
218
218
|
return pctWidths.map((pct) => `${pct}%`).join(' ');
|
|
219
219
|
};
|
|
220
|
+
|
|
221
|
+
export const convertHTMLCellIndexToColumnIndex = (
|
|
222
|
+
htmlColIndex: number,
|
|
223
|
+
htmlRowIndex: number,
|
|
224
|
+
tableMap: TableMap,
|
|
225
|
+
): number => {
|
|
226
|
+
// Same numbers (positions) in tableMap.map array mean that there are merged cells.
|
|
227
|
+
// Cells can be merged across columns. So we need to check if the cell on the left and current cell have the same value.
|
|
228
|
+
// Cells can be merged acroll rows. So we need to check if the cell above has the same value as current cell.
|
|
229
|
+
// When cell has the same value as the cell above it or the cell to the left of it, html cellIndex won't count it a separete column.
|
|
230
|
+
const width = tableMap.width;
|
|
231
|
+
const map = tableMap.map;
|
|
232
|
+
let htmlColCount = 0;
|
|
233
|
+
|
|
234
|
+
if (htmlRowIndex === 0) {
|
|
235
|
+
for (let colIndex = 0; colIndex < width; colIndex++) {
|
|
236
|
+
if (colIndex === 0 || map[colIndex] !== map[colIndex - 1]) {
|
|
237
|
+
htmlColCount++;
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
if (htmlColCount - 1 === htmlColIndex) {
|
|
241
|
+
return colIndex;
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
} else {
|
|
245
|
+
for (let colIndex = 0; colIndex < width; colIndex++) {
|
|
246
|
+
const currentCellMapIndex = htmlRowIndex * width + colIndex;
|
|
247
|
+
const cellAboveMapIndex = (htmlRowIndex - 1) * width + colIndex;
|
|
248
|
+
if (colIndex > 0) {
|
|
249
|
+
if (
|
|
250
|
+
map[currentCellMapIndex] !== map[currentCellMapIndex - 1] &&
|
|
251
|
+
map[currentCellMapIndex] !== map[cellAboveMapIndex]
|
|
252
|
+
) {
|
|
253
|
+
htmlColCount++;
|
|
254
|
+
}
|
|
255
|
+
} else {
|
|
256
|
+
if (map[currentCellMapIndex] !== map[cellAboveMapIndex]) {
|
|
257
|
+
htmlColCount++;
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
if (htmlColCount - 1 === htmlColIndex) {
|
|
262
|
+
return colIndex;
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
return 0;
|
|
268
|
+
};
|
|
269
|
+
|
|
270
|
+
// When first row has merged cells, our converted column index needs to be mapped.
|
|
271
|
+
export const getColumnIndexMappedToColumnIndexInFirstRow = (
|
|
272
|
+
convertedColIndex: number,
|
|
273
|
+
htmlRowIndex: number,
|
|
274
|
+
tableMap: TableMap,
|
|
275
|
+
): number => {
|
|
276
|
+
const width = tableMap.width;
|
|
277
|
+
const map = tableMap.map;
|
|
278
|
+
const mapColIndexToFistRowColIndex = [];
|
|
279
|
+
let htmlColCounFirstRow = 0;
|
|
280
|
+
let colSpan = 0;
|
|
281
|
+
|
|
282
|
+
if (htmlRowIndex === 0) {
|
|
283
|
+
return convertedColIndex;
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
for (let colIndex = 0; colIndex < width; colIndex++) {
|
|
287
|
+
if (colIndex === 0 || map[colIndex] !== map[colIndex - 1]) {
|
|
288
|
+
if (colSpan > 0) {
|
|
289
|
+
htmlColCounFirstRow += colSpan;
|
|
290
|
+
colSpan = 0;
|
|
291
|
+
}
|
|
292
|
+
htmlColCounFirstRow++;
|
|
293
|
+
} else if (map[colIndex] === map[colIndex - 1]) {
|
|
294
|
+
colSpan++;
|
|
295
|
+
}
|
|
296
|
+
mapColIndexToFistRowColIndex[colIndex] = htmlColCounFirstRow - 1;
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
return mapColIndexToFistRowColIndex[convertedColIndex];
|
|
300
|
+
};
|
|
@@ -59,10 +59,12 @@ export {
|
|
|
59
59
|
hasResizeHandler,
|
|
60
60
|
} from './dom';
|
|
61
61
|
export {
|
|
62
|
+
convertHTMLCellIndexToColumnIndex,
|
|
62
63
|
getColumnsWidths,
|
|
63
64
|
isColumnDeleteButtonVisible,
|
|
64
65
|
getColumnDeleteButtonParams,
|
|
65
66
|
getColumnClassNames,
|
|
67
|
+
getColumnIndexMappedToColumnIndexInFirstRow,
|
|
66
68
|
} from './column-controls';
|
|
67
69
|
export {
|
|
68
70
|
getRowHeights,
|