@atlaskit/editor-plugin-table 2.5.4 → 2.6.0
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 +16 -0
- package/dist/cjs/plugins/table/nodeviews/TableContainer.js +6 -2
- package/dist/cjs/plugins/table/nodeviews/TableResizer.js +49 -18
- package/dist/cjs/plugins/table/pm-plugins/sticky-headers/nodeviews/tableRow.js +0 -20
- package/dist/cjs/version.json +1 -1
- package/dist/es2019/plugins/table/nodeviews/TableContainer.js +6 -2
- package/dist/es2019/plugins/table/nodeviews/TableResizer.js +48 -19
- package/dist/es2019/plugins/table/pm-plugins/sticky-headers/nodeviews/tableRow.js +0 -14
- package/dist/es2019/version.json +1 -1
- package/dist/esm/plugins/table/nodeviews/TableContainer.js +6 -2
- package/dist/esm/plugins/table/nodeviews/TableResizer.js +50 -19
- package/dist/esm/plugins/table/pm-plugins/sticky-headers/nodeviews/tableRow.js +0 -20
- package/dist/esm/version.json +1 -1
- package/dist/types/plugins/table/nodeviews/TableResizer.d.ts +4 -1
- package/dist/types-ts4.5/plugins/table/nodeviews/TableResizer.d.ts +4 -1
- package/package.json +3 -3
- package/src/__tests__/unit/nodeviews/TableContainer.tsx +74 -11
- package/src/__tests__/visual-regression/sticky-header.ts +2 -1
- package/src/plugins/table/nodeviews/TableContainer.tsx +11 -4
- package/src/plugins/table/nodeviews/TableResizer.tsx +94 -31
- package/src/plugins/table/pm-plugins/sticky-headers/nodeviews/tableRow.ts +0 -26
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,21 @@
|
|
|
1
1
|
# @atlaskit/editor-plugin-table
|
|
2
2
|
|
|
3
|
+
## 2.6.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- [`0ae6f70038a`](https://bitbucket.org/atlassian/atlassian-frontend/commits/0ae6f70038a) - [ED-17635] Add analytics event for table width resizing
|
|
8
|
+
|
|
9
|
+
### Patch Changes
|
|
10
|
+
|
|
11
|
+
- Updated dependencies
|
|
12
|
+
|
|
13
|
+
## 2.5.5
|
|
14
|
+
|
|
15
|
+
### Patch Changes
|
|
16
|
+
|
|
17
|
+
- [`d55db921de3`](https://bitbucket.org/atlassian/atlassian-frontend/commits/d55db921de3) - improve performance when adding a new column in table
|
|
18
|
+
|
|
3
19
|
## 2.5.4
|
|
4
20
|
|
|
5
21
|
### Patch Changes
|
|
@@ -71,8 +71,11 @@ var ResizableTableContainer = function ResizableTableContainer(_ref2) {
|
|
|
71
71
|
guidelines: guidelines
|
|
72
72
|
})) !== null && _pluginInjectionApi$d !== void 0 ? _pluginInjectionApi$d : false;
|
|
73
73
|
}, [pluginInjectionApi, editorView]);
|
|
74
|
+
var attachAnalyticsEvent = (0, _react.useCallback)(function (payload) {
|
|
75
|
+
var _pluginInjectionApi$d5;
|
|
76
|
+
return pluginInjectionApi === null || pluginInjectionApi === void 0 ? void 0 : (_pluginInjectionApi$d5 = pluginInjectionApi.dependencies) === null || _pluginInjectionApi$d5 === void 0 ? void 0 : _pluginInjectionApi$d5.analytics.actions.attachAnalyticsEvent(payload);
|
|
77
|
+
}, [pluginInjectionApi]);
|
|
74
78
|
var tableWidth = (0, _nodeWidth.getTableContainerWidth)(node);
|
|
75
|
-
|
|
76
79
|
// 76 is currently an accepted padding value considering the spacing for resizer handle
|
|
77
80
|
var responsiveContainerWidth = containerWidth - 76;
|
|
78
81
|
var width = Math.min(tableWidth, responsiveContainerWidth);
|
|
@@ -93,7 +96,8 @@ var ResizableTableContainer = function ResizableTableContainer(_ref2) {
|
|
|
93
96
|
getPos: getPos,
|
|
94
97
|
node: node,
|
|
95
98
|
tableRef: tableRef,
|
|
96
|
-
displayGuideline: displayGuideline
|
|
99
|
+
displayGuideline: displayGuideline,
|
|
100
|
+
attachAnalyticsEvent: attachAnalyticsEvent
|
|
97
101
|
}, /*#__PURE__*/_react.default.createElement(InnerContainer, {
|
|
98
102
|
className: className,
|
|
99
103
|
node: node
|
|
@@ -10,11 +10,14 @@ var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/de
|
|
|
10
10
|
var _slicedToArray2 = _interopRequireDefault(require("@babel/runtime/helpers/slicedToArray"));
|
|
11
11
|
var _react = _interopRequireWildcard(require("react"));
|
|
12
12
|
var _rafSchd = _interopRequireDefault(require("raf-schd"));
|
|
13
|
+
var _analytics = require("@atlaskit/editor-common/analytics");
|
|
13
14
|
var _guideline = require("@atlaskit/editor-common/guideline");
|
|
14
15
|
var _resizer = require("@atlaskit/editor-common/resizer");
|
|
16
|
+
var _editorTables = require("@atlaskit/editor-tables");
|
|
15
17
|
var _utils = require("../pm-plugins/table-resizing/utils");
|
|
16
18
|
var _tableWidth = require("../pm-plugins/table-width");
|
|
17
19
|
var _consts = require("../ui/consts");
|
|
20
|
+
var _utils2 = require("../utils");
|
|
18
21
|
var _guidelines = require("../utils/guidelines");
|
|
19
22
|
var _snapping = require("../utils/snapping");
|
|
20
23
|
function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function _getRequireWildcardCache(nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); }
|
|
@@ -25,6 +28,23 @@ var handles = {
|
|
|
25
28
|
right: true
|
|
26
29
|
};
|
|
27
30
|
var tableHandleMarginTop = 11;
|
|
31
|
+
var generateResizedPayload = function generateResizedPayload(props) {
|
|
32
|
+
var _props$originalNode$a;
|
|
33
|
+
var tableMap = _editorTables.TableMap.get(props.resizedNode);
|
|
34
|
+
return {
|
|
35
|
+
action: _analytics.TABLE_ACTION.RESIZED,
|
|
36
|
+
actionSubject: _analytics.ACTION_SUBJECT.TABLE,
|
|
37
|
+
eventType: _analytics.EVENT_TYPE.TRACK,
|
|
38
|
+
attributes: {
|
|
39
|
+
newWidth: props.resizedNode.attrs.width,
|
|
40
|
+
prevWidth: (_props$originalNode$a = props.originalNode.attrs.width) !== null && _props$originalNode$a !== void 0 ? _props$originalNode$a : null,
|
|
41
|
+
nodeSize: props.resizedNode.nodeSize,
|
|
42
|
+
totalTableWidth: (0, _utils.hasTableBeenResized)(props.resizedNode) ? (0, _utils2.getTableWidth)(props.resizedNode) : null,
|
|
43
|
+
totalRowCount: tableMap.height,
|
|
44
|
+
totalColumnCount: tableMap.width
|
|
45
|
+
}
|
|
46
|
+
};
|
|
47
|
+
};
|
|
28
48
|
var TableResizer = function TableResizer(_ref) {
|
|
29
49
|
var children = _ref.children,
|
|
30
50
|
width = _ref.width,
|
|
@@ -34,7 +54,8 @@ var TableResizer = function TableResizer(_ref) {
|
|
|
34
54
|
getPos = _ref.getPos,
|
|
35
55
|
node = _ref.node,
|
|
36
56
|
tableRef = _ref.tableRef,
|
|
37
|
-
displayGuideline = _ref.displayGuideline
|
|
57
|
+
displayGuideline = _ref.displayGuideline,
|
|
58
|
+
attachAnalyticsEvent = _ref.attachAnalyticsEvent;
|
|
38
59
|
var currentColumnCount = (0, _utils.getColgroupChildrenLength)(node);
|
|
39
60
|
var minColumnWidth = currentColumnCount <= 3 ? currentColumnCount * _utils.COLUMN_MIN_WIDTH : 3 * _utils.COLUMN_MIN_WIDTH;
|
|
40
61
|
var tableHeight = tableRef === null || tableRef === void 0 ? void 0 : tableRef.clientHeight;
|
|
@@ -88,6 +109,7 @@ var TableResizer = function TableResizer(_ref) {
|
|
|
88
109
|
resizing: false
|
|
89
110
|
});
|
|
90
111
|
if (typeof pos === 'number') {
|
|
112
|
+
var _attachAnalyticsEvent;
|
|
91
113
|
tr = tr.setNodeMarkup(pos, undefined, _objectSpread(_objectSpread({}, node.attrs), {}, {
|
|
92
114
|
width: newWidth
|
|
93
115
|
}));
|
|
@@ -98,6 +120,11 @@ var TableResizer = function TableResizer(_ref) {
|
|
|
98
120
|
start: pos + 1,
|
|
99
121
|
parentWidth: newWidth
|
|
100
122
|
}, editorView.domAtPos.bind(editorView))(tr);
|
|
123
|
+
var scaledNode = tr.doc.nodeAt(pos);
|
|
124
|
+
(_attachAnalyticsEvent = attachAnalyticsEvent(generateResizedPayload({
|
|
125
|
+
originalNode: node,
|
|
126
|
+
resizedNode: scaledNode
|
|
127
|
+
}))) === null || _attachAnalyticsEvent === void 0 ? void 0 : _attachAnalyticsEvent(tr);
|
|
101
128
|
}
|
|
102
129
|
dispatch(tr);
|
|
103
130
|
|
|
@@ -105,7 +132,26 @@ var TableResizer = function TableResizer(_ref) {
|
|
|
105
132
|
displayGuideline([]);
|
|
106
133
|
updateWidth(newWidth);
|
|
107
134
|
return newWidth;
|
|
108
|
-
}, [updateWidth, editorView, getPos, node, tableRef, displayGuideline]);
|
|
135
|
+
}, [updateWidth, editorView, getPos, node, tableRef, displayGuideline, attachAnalyticsEvent]);
|
|
136
|
+
var handleResize = (0, _react.useCallback)(function (originalState, delta) {
|
|
137
|
+
var newWidth = originalState.width + delta.width;
|
|
138
|
+
var pos = getPos();
|
|
139
|
+
if (typeof pos !== 'number') {
|
|
140
|
+
return;
|
|
141
|
+
}
|
|
142
|
+
(0, _utils.previewScaleTable)(tableRef, {
|
|
143
|
+
node: node,
|
|
144
|
+
prevNode: node,
|
|
145
|
+
start: pos + 1,
|
|
146
|
+
parentWidth: newWidth
|
|
147
|
+
}, editorView.domAtPos.bind(editorView));
|
|
148
|
+
updateActiveGuidelines((0, _snapping.findClosestSnap)(newWidth, _guidelines.defaultGuidelineWidths, _guidelines.defaultGuidelines, _consts.TABLE_HIGHLIGHT_GAP));
|
|
149
|
+
updateWidth(newWidth);
|
|
150
|
+
return newWidth;
|
|
151
|
+
}, [editorView, getPos, node, tableRef, updateWidth, updateActiveGuidelines]);
|
|
152
|
+
var scheduleResize = (0, _react.useMemo)(function () {
|
|
153
|
+
return (0, _rafSchd.default)(handleResize);
|
|
154
|
+
}, [handleResize]);
|
|
109
155
|
return /*#__PURE__*/_react.default.createElement(_resizer.ResizerNext, {
|
|
110
156
|
enable: handles,
|
|
111
157
|
width: width,
|
|
@@ -113,22 +159,7 @@ var TableResizer = function TableResizer(_ref) {
|
|
|
113
159
|
handleHeightSize: handleHeightSize,
|
|
114
160
|
handleMarginTop: tableHandleMarginTop,
|
|
115
161
|
handleResizeStart: handleResizeStart,
|
|
116
|
-
handleResize:
|
|
117
|
-
var newWidth = originalState.width + delta.width;
|
|
118
|
-
var pos = getPos();
|
|
119
|
-
if (typeof pos !== 'number') {
|
|
120
|
-
return;
|
|
121
|
-
}
|
|
122
|
-
(0, _utils.previewScaleTable)(tableRef, {
|
|
123
|
-
node: node,
|
|
124
|
-
prevNode: node,
|
|
125
|
-
start: pos + 1,
|
|
126
|
-
parentWidth: newWidth
|
|
127
|
-
}, editorView.domAtPos.bind(editorView));
|
|
128
|
-
updateActiveGuidelines((0, _snapping.findClosestSnap)(newWidth, _guidelines.defaultGuidelineWidths, _guidelines.defaultGuidelines, _consts.TABLE_HIGHLIGHT_GAP));
|
|
129
|
-
updateWidth(newWidth);
|
|
130
|
-
return newWidth;
|
|
131
|
-
}),
|
|
162
|
+
handleResize: scheduleResize,
|
|
132
163
|
handleResizeStop: handleResizeStop,
|
|
133
164
|
resizeRatio: 2,
|
|
134
165
|
minWidth: minColumnWidth,
|
|
@@ -32,22 +32,6 @@ var anyChildCellMergedAcrossRow = function anyChildCellMergedAcrossRow(node) {
|
|
|
32
32
|
});
|
|
33
33
|
};
|
|
34
34
|
|
|
35
|
-
/**
|
|
36
|
-
* Compare two table row nodes and return true if the two table rows have a
|
|
37
|
-
* different number of table cells or if table cell row spans are different
|
|
38
|
-
*/
|
|
39
|
-
var rowHasDifferentMergedCells = function rowHasDifferentMergedCells(prevNode, incomingNode) {
|
|
40
|
-
var incomingNodeChildrenRowSpan = (0, _utils.mapChildren)(prevNode, function (child) {
|
|
41
|
-
return child.attrs.rowspan || 0;
|
|
42
|
-
});
|
|
43
|
-
var currentNodeChildrenRowSpan = (0, _utils.mapChildren)(incomingNode, function (child) {
|
|
44
|
-
return child.attrs.rowspan || 0;
|
|
45
|
-
});
|
|
46
|
-
return incomingNodeChildrenRowSpan.length !== currentNodeChildrenRowSpan.length || currentNodeChildrenRowSpan.some(function (child, index) {
|
|
47
|
-
return child !== incomingNodeChildrenRowSpan[index];
|
|
48
|
-
});
|
|
49
|
-
};
|
|
50
|
-
|
|
51
35
|
/**
|
|
52
36
|
* Check if a given node is a header row with this definition:
|
|
53
37
|
* - all children are tableHeader cells
|
|
@@ -512,10 +496,6 @@ var TableRowNodeView = /*#__PURE__*/function () {
|
|
|
512
496
|
return false; // re-create nodeview
|
|
513
497
|
}
|
|
514
498
|
|
|
515
|
-
if (rowHasDifferentMergedCells(this.node, node)) {
|
|
516
|
-
return false;
|
|
517
|
-
}
|
|
518
|
-
|
|
519
499
|
// node is different but no need to re-create nodeview
|
|
520
500
|
this.node = node;
|
|
521
501
|
|
package/dist/cjs/version.json
CHANGED
|
@@ -62,8 +62,11 @@ export const ResizableTableContainer = ({
|
|
|
62
62
|
guidelines
|
|
63
63
|
})) !== null && _pluginInjectionApi$d !== void 0 ? _pluginInjectionApi$d : false;
|
|
64
64
|
}, [pluginInjectionApi, editorView]);
|
|
65
|
+
const attachAnalyticsEvent = useCallback(payload => {
|
|
66
|
+
var _pluginInjectionApi$d5;
|
|
67
|
+
return pluginInjectionApi === null || pluginInjectionApi === void 0 ? void 0 : (_pluginInjectionApi$d5 = pluginInjectionApi.dependencies) === null || _pluginInjectionApi$d5 === void 0 ? void 0 : _pluginInjectionApi$d5.analytics.actions.attachAnalyticsEvent(payload);
|
|
68
|
+
}, [pluginInjectionApi]);
|
|
65
69
|
const tableWidth = getTableContainerWidth(node);
|
|
66
|
-
|
|
67
70
|
// 76 is currently an accepted padding value considering the spacing for resizer handle
|
|
68
71
|
const responsiveContainerWidth = containerWidth - 76;
|
|
69
72
|
const width = Math.min(tableWidth, responsiveContainerWidth);
|
|
@@ -84,7 +87,8 @@ export const ResizableTableContainer = ({
|
|
|
84
87
|
getPos: getPos,
|
|
85
88
|
node: node,
|
|
86
89
|
tableRef: tableRef,
|
|
87
|
-
displayGuideline: displayGuideline
|
|
90
|
+
displayGuideline: displayGuideline,
|
|
91
|
+
attachAnalyticsEvent: attachAnalyticsEvent
|
|
88
92
|
}, /*#__PURE__*/React.createElement(InnerContainer, {
|
|
89
93
|
className: className,
|
|
90
94
|
node: node
|
|
@@ -1,16 +1,36 @@
|
|
|
1
1
|
import React, { useCallback, useMemo, useRef, useState } from 'react';
|
|
2
2
|
import rafSchd from 'raf-schd';
|
|
3
|
+
import { ACTION_SUBJECT, EVENT_TYPE, TABLE_ACTION } from '@atlaskit/editor-common/analytics';
|
|
3
4
|
import { getGuidelinesWithHighlights } from '@atlaskit/editor-common/guideline';
|
|
4
5
|
import { ResizerNext } from '@atlaskit/editor-common/resizer';
|
|
5
|
-
import {
|
|
6
|
+
import { TableMap } from '@atlaskit/editor-tables';
|
|
7
|
+
import { COLUMN_MIN_WIDTH, getColgroupChildrenLength, hasTableBeenResized, previewScaleTable, scaleTable } from '../pm-plugins/table-resizing/utils';
|
|
6
8
|
import { pluginKey as tableWidthPluginKey } from '../pm-plugins/table-width';
|
|
7
9
|
import { TABLE_HIGHLIGHT_GAP, TABLE_SNAP_GAP } from '../ui/consts';
|
|
10
|
+
import { getTableWidth } from '../utils';
|
|
8
11
|
import { defaultGuidelines, defaultGuidelineWidths } from '../utils/guidelines';
|
|
9
12
|
import { findClosestSnap } from '../utils/snapping';
|
|
10
13
|
const handles = {
|
|
11
14
|
right: true
|
|
12
15
|
};
|
|
13
16
|
const tableHandleMarginTop = 11;
|
|
17
|
+
const generateResizedPayload = props => {
|
|
18
|
+
var _props$originalNode$a;
|
|
19
|
+
const tableMap = TableMap.get(props.resizedNode);
|
|
20
|
+
return {
|
|
21
|
+
action: TABLE_ACTION.RESIZED,
|
|
22
|
+
actionSubject: ACTION_SUBJECT.TABLE,
|
|
23
|
+
eventType: EVENT_TYPE.TRACK,
|
|
24
|
+
attributes: {
|
|
25
|
+
newWidth: props.resizedNode.attrs.width,
|
|
26
|
+
prevWidth: (_props$originalNode$a = props.originalNode.attrs.width) !== null && _props$originalNode$a !== void 0 ? _props$originalNode$a : null,
|
|
27
|
+
nodeSize: props.resizedNode.nodeSize,
|
|
28
|
+
totalTableWidth: hasTableBeenResized(props.resizedNode) ? getTableWidth(props.resizedNode) : null,
|
|
29
|
+
totalRowCount: tableMap.height,
|
|
30
|
+
totalColumnCount: tableMap.width
|
|
31
|
+
}
|
|
32
|
+
};
|
|
33
|
+
};
|
|
14
34
|
export const TableResizer = ({
|
|
15
35
|
children,
|
|
16
36
|
width,
|
|
@@ -20,7 +40,8 @@ export const TableResizer = ({
|
|
|
20
40
|
getPos,
|
|
21
41
|
node,
|
|
22
42
|
tableRef,
|
|
23
|
-
displayGuideline
|
|
43
|
+
displayGuideline,
|
|
44
|
+
attachAnalyticsEvent
|
|
24
45
|
}) => {
|
|
25
46
|
const currentColumnCount = getColgroupChildrenLength(node);
|
|
26
47
|
const minColumnWidth = currentColumnCount <= 3 ? currentColumnCount * COLUMN_MIN_WIDTH : 3 * COLUMN_MIN_WIDTH;
|
|
@@ -77,6 +98,7 @@ export const TableResizer = ({
|
|
|
77
98
|
resizing: false
|
|
78
99
|
});
|
|
79
100
|
if (typeof pos === 'number') {
|
|
101
|
+
var _attachAnalyticsEvent;
|
|
80
102
|
tr = tr.setNodeMarkup(pos, undefined, {
|
|
81
103
|
...node.attrs,
|
|
82
104
|
width: newWidth
|
|
@@ -88,6 +110,11 @@ export const TableResizer = ({
|
|
|
88
110
|
start: pos + 1,
|
|
89
111
|
parentWidth: newWidth
|
|
90
112
|
}, editorView.domAtPos.bind(editorView))(tr);
|
|
113
|
+
const scaledNode = tr.doc.nodeAt(pos);
|
|
114
|
+
(_attachAnalyticsEvent = attachAnalyticsEvent(generateResizedPayload({
|
|
115
|
+
originalNode: node,
|
|
116
|
+
resizedNode: scaledNode
|
|
117
|
+
}))) === null || _attachAnalyticsEvent === void 0 ? void 0 : _attachAnalyticsEvent(tr);
|
|
91
118
|
}
|
|
92
119
|
dispatch(tr);
|
|
93
120
|
|
|
@@ -95,7 +122,24 @@ export const TableResizer = ({
|
|
|
95
122
|
displayGuideline([]);
|
|
96
123
|
updateWidth(newWidth);
|
|
97
124
|
return newWidth;
|
|
98
|
-
}, [updateWidth, editorView, getPos, node, tableRef, displayGuideline]);
|
|
125
|
+
}, [updateWidth, editorView, getPos, node, tableRef, displayGuideline, attachAnalyticsEvent]);
|
|
126
|
+
const handleResize = useCallback((originalState, delta) => {
|
|
127
|
+
const newWidth = originalState.width + delta.width;
|
|
128
|
+
const pos = getPos();
|
|
129
|
+
if (typeof pos !== 'number') {
|
|
130
|
+
return;
|
|
131
|
+
}
|
|
132
|
+
previewScaleTable(tableRef, {
|
|
133
|
+
node,
|
|
134
|
+
prevNode: node,
|
|
135
|
+
start: pos + 1,
|
|
136
|
+
parentWidth: newWidth
|
|
137
|
+
}, editorView.domAtPos.bind(editorView));
|
|
138
|
+
updateActiveGuidelines(findClosestSnap(newWidth, defaultGuidelineWidths, defaultGuidelines, TABLE_HIGHLIGHT_GAP));
|
|
139
|
+
updateWidth(newWidth);
|
|
140
|
+
return newWidth;
|
|
141
|
+
}, [editorView, getPos, node, tableRef, updateWidth, updateActiveGuidelines]);
|
|
142
|
+
const scheduleResize = useMemo(() => rafSchd(handleResize), [handleResize]);
|
|
99
143
|
return /*#__PURE__*/React.createElement(ResizerNext, {
|
|
100
144
|
enable: handles,
|
|
101
145
|
width: width,
|
|
@@ -103,22 +147,7 @@ export const TableResizer = ({
|
|
|
103
147
|
handleHeightSize: handleHeightSize,
|
|
104
148
|
handleMarginTop: tableHandleMarginTop,
|
|
105
149
|
handleResizeStart: handleResizeStart,
|
|
106
|
-
handleResize:
|
|
107
|
-
const newWidth = originalState.width + delta.width;
|
|
108
|
-
const pos = getPos();
|
|
109
|
-
if (typeof pos !== 'number') {
|
|
110
|
-
return;
|
|
111
|
-
}
|
|
112
|
-
previewScaleTable(tableRef, {
|
|
113
|
-
node,
|
|
114
|
-
prevNode: node,
|
|
115
|
-
start: pos + 1,
|
|
116
|
-
parentWidth: newWidth
|
|
117
|
-
}, editorView.domAtPos.bind(editorView));
|
|
118
|
-
updateActiveGuidelines(findClosestSnap(newWidth, defaultGuidelineWidths, defaultGuidelines, TABLE_HIGHLIGHT_GAP));
|
|
119
|
-
updateWidth(newWidth);
|
|
120
|
-
return newWidth;
|
|
121
|
-
}),
|
|
150
|
+
handleResize: scheduleResize,
|
|
122
151
|
handleResizeStop: handleResizeStop,
|
|
123
152
|
resizeRatio: 2,
|
|
124
153
|
minWidth: minColumnWidth,
|
|
@@ -18,16 +18,6 @@ const HEADER_ROW_SCROLL_THROTTLE_TIMEOUT = 200;
|
|
|
18
18
|
const HEADER_ROW_SCROLL_RESET_DEBOUNCE_TIMEOUT = 400;
|
|
19
19
|
const anyChildCellMergedAcrossRow = node => mapChildren(node, child => child.attrs.rowspan || 0).some(rowspan => rowspan > 1);
|
|
20
20
|
|
|
21
|
-
/**
|
|
22
|
-
* Compare two table row nodes and return true if the two table rows have a
|
|
23
|
-
* different number of table cells or if table cell row spans are different
|
|
24
|
-
*/
|
|
25
|
-
const rowHasDifferentMergedCells = (prevNode, incomingNode) => {
|
|
26
|
-
const incomingNodeChildrenRowSpan = mapChildren(prevNode, child => child.attrs.rowspan || 0);
|
|
27
|
-
const currentNodeChildrenRowSpan = mapChildren(incomingNode, child => child.attrs.rowspan || 0);
|
|
28
|
-
return incomingNodeChildrenRowSpan.length !== currentNodeChildrenRowSpan.length || currentNodeChildrenRowSpan.some((child, index) => child !== incomingNodeChildrenRowSpan[index]);
|
|
29
|
-
};
|
|
30
|
-
|
|
31
21
|
/**
|
|
32
22
|
* Check if a given node is a header row with this definition:
|
|
33
23
|
* - all children are tableHeader cells
|
|
@@ -477,10 +467,6 @@ export class TableRowNodeView {
|
|
|
477
467
|
return false; // re-create nodeview
|
|
478
468
|
}
|
|
479
469
|
|
|
480
|
-
if (rowHasDifferentMergedCells(this.node, node)) {
|
|
481
|
-
return false;
|
|
482
|
-
}
|
|
483
|
-
|
|
484
470
|
// node is different but no need to re-create nodeview
|
|
485
471
|
this.node = node;
|
|
486
472
|
|
package/dist/es2019/version.json
CHANGED
|
@@ -60,8 +60,11 @@ export var ResizableTableContainer = function ResizableTableContainer(_ref2) {
|
|
|
60
60
|
guidelines: guidelines
|
|
61
61
|
})) !== null && _pluginInjectionApi$d !== void 0 ? _pluginInjectionApi$d : false;
|
|
62
62
|
}, [pluginInjectionApi, editorView]);
|
|
63
|
+
var attachAnalyticsEvent = useCallback(function (payload) {
|
|
64
|
+
var _pluginInjectionApi$d5;
|
|
65
|
+
return pluginInjectionApi === null || pluginInjectionApi === void 0 ? void 0 : (_pluginInjectionApi$d5 = pluginInjectionApi.dependencies) === null || _pluginInjectionApi$d5 === void 0 ? void 0 : _pluginInjectionApi$d5.analytics.actions.attachAnalyticsEvent(payload);
|
|
66
|
+
}, [pluginInjectionApi]);
|
|
63
67
|
var tableWidth = getTableContainerWidth(node);
|
|
64
|
-
|
|
65
68
|
// 76 is currently an accepted padding value considering the spacing for resizer handle
|
|
66
69
|
var responsiveContainerWidth = containerWidth - 76;
|
|
67
70
|
var width = Math.min(tableWidth, responsiveContainerWidth);
|
|
@@ -82,7 +85,8 @@ export var ResizableTableContainer = function ResizableTableContainer(_ref2) {
|
|
|
82
85
|
getPos: getPos,
|
|
83
86
|
node: node,
|
|
84
87
|
tableRef: tableRef,
|
|
85
|
-
displayGuideline: displayGuideline
|
|
88
|
+
displayGuideline: displayGuideline,
|
|
89
|
+
attachAnalyticsEvent: attachAnalyticsEvent
|
|
86
90
|
}, /*#__PURE__*/React.createElement(InnerContainer, {
|
|
87
91
|
className: className,
|
|
88
92
|
node: node
|
|
@@ -4,17 +4,37 @@ function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (O
|
|
|
4
4
|
function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = null != arguments[i] ? arguments[i] : {}; i % 2 ? ownKeys(Object(source), !0).forEach(function (key) { _defineProperty(target, key, source[key]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } return target; }
|
|
5
5
|
import React, { useCallback, useMemo, useRef, useState } from 'react';
|
|
6
6
|
import rafSchd from 'raf-schd';
|
|
7
|
+
import { ACTION_SUBJECT, EVENT_TYPE, TABLE_ACTION } from '@atlaskit/editor-common/analytics';
|
|
7
8
|
import { getGuidelinesWithHighlights } from '@atlaskit/editor-common/guideline';
|
|
8
9
|
import { ResizerNext } from '@atlaskit/editor-common/resizer';
|
|
9
|
-
import {
|
|
10
|
+
import { TableMap } from '@atlaskit/editor-tables';
|
|
11
|
+
import { COLUMN_MIN_WIDTH, getColgroupChildrenLength, hasTableBeenResized, previewScaleTable, scaleTable } from '../pm-plugins/table-resizing/utils';
|
|
10
12
|
import { pluginKey as tableWidthPluginKey } from '../pm-plugins/table-width';
|
|
11
13
|
import { TABLE_HIGHLIGHT_GAP, TABLE_SNAP_GAP } from '../ui/consts';
|
|
14
|
+
import { getTableWidth } from '../utils';
|
|
12
15
|
import { defaultGuidelines, defaultGuidelineWidths } from '../utils/guidelines';
|
|
13
16
|
import { findClosestSnap } from '../utils/snapping';
|
|
14
17
|
var handles = {
|
|
15
18
|
right: true
|
|
16
19
|
};
|
|
17
20
|
var tableHandleMarginTop = 11;
|
|
21
|
+
var generateResizedPayload = function generateResizedPayload(props) {
|
|
22
|
+
var _props$originalNode$a;
|
|
23
|
+
var tableMap = TableMap.get(props.resizedNode);
|
|
24
|
+
return {
|
|
25
|
+
action: TABLE_ACTION.RESIZED,
|
|
26
|
+
actionSubject: ACTION_SUBJECT.TABLE,
|
|
27
|
+
eventType: EVENT_TYPE.TRACK,
|
|
28
|
+
attributes: {
|
|
29
|
+
newWidth: props.resizedNode.attrs.width,
|
|
30
|
+
prevWidth: (_props$originalNode$a = props.originalNode.attrs.width) !== null && _props$originalNode$a !== void 0 ? _props$originalNode$a : null,
|
|
31
|
+
nodeSize: props.resizedNode.nodeSize,
|
|
32
|
+
totalTableWidth: hasTableBeenResized(props.resizedNode) ? getTableWidth(props.resizedNode) : null,
|
|
33
|
+
totalRowCount: tableMap.height,
|
|
34
|
+
totalColumnCount: tableMap.width
|
|
35
|
+
}
|
|
36
|
+
};
|
|
37
|
+
};
|
|
18
38
|
export var TableResizer = function TableResizer(_ref) {
|
|
19
39
|
var children = _ref.children,
|
|
20
40
|
width = _ref.width,
|
|
@@ -24,7 +44,8 @@ export var TableResizer = function TableResizer(_ref) {
|
|
|
24
44
|
getPos = _ref.getPos,
|
|
25
45
|
node = _ref.node,
|
|
26
46
|
tableRef = _ref.tableRef,
|
|
27
|
-
displayGuideline = _ref.displayGuideline
|
|
47
|
+
displayGuideline = _ref.displayGuideline,
|
|
48
|
+
attachAnalyticsEvent = _ref.attachAnalyticsEvent;
|
|
28
49
|
var currentColumnCount = getColgroupChildrenLength(node);
|
|
29
50
|
var minColumnWidth = currentColumnCount <= 3 ? currentColumnCount * COLUMN_MIN_WIDTH : 3 * COLUMN_MIN_WIDTH;
|
|
30
51
|
var tableHeight = tableRef === null || tableRef === void 0 ? void 0 : tableRef.clientHeight;
|
|
@@ -78,6 +99,7 @@ export var TableResizer = function TableResizer(_ref) {
|
|
|
78
99
|
resizing: false
|
|
79
100
|
});
|
|
80
101
|
if (typeof pos === 'number') {
|
|
102
|
+
var _attachAnalyticsEvent;
|
|
81
103
|
tr = tr.setNodeMarkup(pos, undefined, _objectSpread(_objectSpread({}, node.attrs), {}, {
|
|
82
104
|
width: newWidth
|
|
83
105
|
}));
|
|
@@ -88,6 +110,11 @@ export var TableResizer = function TableResizer(_ref) {
|
|
|
88
110
|
start: pos + 1,
|
|
89
111
|
parentWidth: newWidth
|
|
90
112
|
}, editorView.domAtPos.bind(editorView))(tr);
|
|
113
|
+
var scaledNode = tr.doc.nodeAt(pos);
|
|
114
|
+
(_attachAnalyticsEvent = attachAnalyticsEvent(generateResizedPayload({
|
|
115
|
+
originalNode: node,
|
|
116
|
+
resizedNode: scaledNode
|
|
117
|
+
}))) === null || _attachAnalyticsEvent === void 0 ? void 0 : _attachAnalyticsEvent(tr);
|
|
91
118
|
}
|
|
92
119
|
dispatch(tr);
|
|
93
120
|
|
|
@@ -95,7 +122,26 @@ export var TableResizer = function TableResizer(_ref) {
|
|
|
95
122
|
displayGuideline([]);
|
|
96
123
|
updateWidth(newWidth);
|
|
97
124
|
return newWidth;
|
|
98
|
-
}, [updateWidth, editorView, getPos, node, tableRef, displayGuideline]);
|
|
125
|
+
}, [updateWidth, editorView, getPos, node, tableRef, displayGuideline, attachAnalyticsEvent]);
|
|
126
|
+
var handleResize = useCallback(function (originalState, delta) {
|
|
127
|
+
var newWidth = originalState.width + delta.width;
|
|
128
|
+
var pos = getPos();
|
|
129
|
+
if (typeof pos !== 'number') {
|
|
130
|
+
return;
|
|
131
|
+
}
|
|
132
|
+
previewScaleTable(tableRef, {
|
|
133
|
+
node: node,
|
|
134
|
+
prevNode: node,
|
|
135
|
+
start: pos + 1,
|
|
136
|
+
parentWidth: newWidth
|
|
137
|
+
}, editorView.domAtPos.bind(editorView));
|
|
138
|
+
updateActiveGuidelines(findClosestSnap(newWidth, defaultGuidelineWidths, defaultGuidelines, TABLE_HIGHLIGHT_GAP));
|
|
139
|
+
updateWidth(newWidth);
|
|
140
|
+
return newWidth;
|
|
141
|
+
}, [editorView, getPos, node, tableRef, updateWidth, updateActiveGuidelines]);
|
|
142
|
+
var scheduleResize = useMemo(function () {
|
|
143
|
+
return rafSchd(handleResize);
|
|
144
|
+
}, [handleResize]);
|
|
99
145
|
return /*#__PURE__*/React.createElement(ResizerNext, {
|
|
100
146
|
enable: handles,
|
|
101
147
|
width: width,
|
|
@@ -103,22 +149,7 @@ export var TableResizer = function TableResizer(_ref) {
|
|
|
103
149
|
handleHeightSize: handleHeightSize,
|
|
104
150
|
handleMarginTop: tableHandleMarginTop,
|
|
105
151
|
handleResizeStart: handleResizeStart,
|
|
106
|
-
handleResize:
|
|
107
|
-
var newWidth = originalState.width + delta.width;
|
|
108
|
-
var pos = getPos();
|
|
109
|
-
if (typeof pos !== 'number') {
|
|
110
|
-
return;
|
|
111
|
-
}
|
|
112
|
-
previewScaleTable(tableRef, {
|
|
113
|
-
node: node,
|
|
114
|
-
prevNode: node,
|
|
115
|
-
start: pos + 1,
|
|
116
|
-
parentWidth: newWidth
|
|
117
|
-
}, editorView.domAtPos.bind(editorView));
|
|
118
|
-
updateActiveGuidelines(findClosestSnap(newWidth, defaultGuidelineWidths, defaultGuidelines, TABLE_HIGHLIGHT_GAP));
|
|
119
|
-
updateWidth(newWidth);
|
|
120
|
-
return newWidth;
|
|
121
|
-
}),
|
|
152
|
+
handleResize: scheduleResize,
|
|
122
153
|
handleResizeStop: handleResizeStop,
|
|
123
154
|
resizeRatio: 2,
|
|
124
155
|
minWidth: minColumnWidth,
|
|
@@ -26,22 +26,6 @@ var anyChildCellMergedAcrossRow = function anyChildCellMergedAcrossRow(node) {
|
|
|
26
26
|
});
|
|
27
27
|
};
|
|
28
28
|
|
|
29
|
-
/**
|
|
30
|
-
* Compare two table row nodes and return true if the two table rows have a
|
|
31
|
-
* different number of table cells or if table cell row spans are different
|
|
32
|
-
*/
|
|
33
|
-
var rowHasDifferentMergedCells = function rowHasDifferentMergedCells(prevNode, incomingNode) {
|
|
34
|
-
var incomingNodeChildrenRowSpan = mapChildren(prevNode, function (child) {
|
|
35
|
-
return child.attrs.rowspan || 0;
|
|
36
|
-
});
|
|
37
|
-
var currentNodeChildrenRowSpan = mapChildren(incomingNode, function (child) {
|
|
38
|
-
return child.attrs.rowspan || 0;
|
|
39
|
-
});
|
|
40
|
-
return incomingNodeChildrenRowSpan.length !== currentNodeChildrenRowSpan.length || currentNodeChildrenRowSpan.some(function (child, index) {
|
|
41
|
-
return child !== incomingNodeChildrenRowSpan[index];
|
|
42
|
-
});
|
|
43
|
-
};
|
|
44
|
-
|
|
45
29
|
/**
|
|
46
30
|
* Check if a given node is a header row with this definition:
|
|
47
31
|
* - all children are tableHeader cells
|
|
@@ -505,10 +489,6 @@ export var TableRowNodeView = /*#__PURE__*/function () {
|
|
|
505
489
|
return false; // re-create nodeview
|
|
506
490
|
}
|
|
507
491
|
|
|
508
|
-
if (rowHasDifferentMergedCells(this.node, node)) {
|
|
509
|
-
return false;
|
|
510
|
-
}
|
|
511
|
-
|
|
512
492
|
// node is different but no need to re-create nodeview
|
|
513
493
|
this.node = node;
|
|
514
494
|
|
package/dist/esm/version.json
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { PropsWithChildren } from 'react';
|
|
2
2
|
import { Node as PMNode } from 'prosemirror-model';
|
|
3
|
+
import { Transaction } from 'prosemirror-state';
|
|
3
4
|
import { EditorView } from 'prosemirror-view';
|
|
5
|
+
import { TableEventPayload } from '@atlaskit/editor-common/analytics';
|
|
4
6
|
import type { GuidelineConfig } from '@atlaskit/editor-plugin-guideline';
|
|
5
7
|
interface TableResizerProps {
|
|
6
8
|
width: number;
|
|
@@ -11,6 +13,7 @@ interface TableResizerProps {
|
|
|
11
13
|
node: PMNode;
|
|
12
14
|
tableRef: HTMLTableElement;
|
|
13
15
|
displayGuideline: (guideline: GuidelineConfig[]) => boolean;
|
|
16
|
+
attachAnalyticsEvent: (payload: TableEventPayload) => ((tr: Transaction) => boolean) | undefined;
|
|
14
17
|
}
|
|
15
|
-
export declare const TableResizer: ({ children, width, maxWidth, updateWidth, editorView, getPos, node, tableRef, displayGuideline, }: PropsWithChildren<TableResizerProps>) => JSX.Element;
|
|
18
|
+
export declare const TableResizer: ({ children, width, maxWidth, updateWidth, editorView, getPos, node, tableRef, displayGuideline, attachAnalyticsEvent, }: PropsWithChildren<TableResizerProps>) => JSX.Element;
|
|
16
19
|
export {};
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { PropsWithChildren } from 'react';
|
|
2
2
|
import { Node as PMNode } from 'prosemirror-model';
|
|
3
|
+
import { Transaction } from 'prosemirror-state';
|
|
3
4
|
import { EditorView } from 'prosemirror-view';
|
|
5
|
+
import { TableEventPayload } from '@atlaskit/editor-common/analytics';
|
|
4
6
|
import type { GuidelineConfig } from '@atlaskit/editor-plugin-guideline';
|
|
5
7
|
interface TableResizerProps {
|
|
6
8
|
width: number;
|
|
@@ -11,6 +13,7 @@ interface TableResizerProps {
|
|
|
11
13
|
node: PMNode;
|
|
12
14
|
tableRef: HTMLTableElement;
|
|
13
15
|
displayGuideline: (guideline: GuidelineConfig[]) => boolean;
|
|
16
|
+
attachAnalyticsEvent: (payload: TableEventPayload) => ((tr: Transaction) => boolean) | undefined;
|
|
14
17
|
}
|
|
15
|
-
export declare const TableResizer: ({ children, width, maxWidth, updateWidth, editorView, getPos, node, tableRef, displayGuideline, }: PropsWithChildren<TableResizerProps>) => JSX.Element;
|
|
18
|
+
export declare const TableResizer: ({ children, width, maxWidth, updateWidth, editorView, getPos, node, tableRef, displayGuideline, attachAnalyticsEvent, }: PropsWithChildren<TableResizerProps>) => JSX.Element;
|
|
16
19
|
export {};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@atlaskit/editor-plugin-table",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.6.0",
|
|
4
4
|
"description": "Table plugin for the @atlaskit/editor",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"registry": "https://registry.npmjs.org/"
|
|
@@ -27,8 +27,8 @@
|
|
|
27
27
|
"releaseModel": "continuous"
|
|
28
28
|
},
|
|
29
29
|
"dependencies": {
|
|
30
|
-
"@atlaskit/adf-schema": "^26.
|
|
31
|
-
"@atlaskit/editor-common": "^74.
|
|
30
|
+
"@atlaskit/adf-schema": "^26.3.0",
|
|
31
|
+
"@atlaskit/editor-common": "^74.27.0",
|
|
32
32
|
"@atlaskit/editor-palette": "1.5.1",
|
|
33
33
|
"@atlaskit/editor-plugin-analytics": "^0.1.0",
|
|
34
34
|
"@atlaskit/editor-plugin-content-insertion": "^0.0.6",
|
|
@@ -1,8 +1,13 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
|
|
3
|
-
import { render } from '@testing-library/react';
|
|
3
|
+
import { fireEvent, render } from '@testing-library/react';
|
|
4
4
|
|
|
5
5
|
import { TableAttributes } from '@atlaskit/adf-schema';
|
|
6
|
+
import {
|
|
7
|
+
ACTION_SUBJECT,
|
|
8
|
+
EVENT_TYPE,
|
|
9
|
+
TABLE_ACTION,
|
|
10
|
+
} from '@atlaskit/editor-common/analytics';
|
|
6
11
|
import { akEditorWideLayoutWidth } from '@atlaskit/editor-shared-styles';
|
|
7
12
|
import { findTable } from '@atlaskit/editor-tables/utils';
|
|
8
13
|
import { createEditorFactory } from '@atlaskit/editor-test-helpers/create-editor';
|
|
@@ -43,12 +48,12 @@ describe('table -> nodeviews -> TableContainer.tsx', () => {
|
|
|
43
48
|
});
|
|
44
49
|
};
|
|
45
50
|
const createNode = (attrs?: TableAttributes) => {
|
|
46
|
-
const { editorView
|
|
47
|
-
doc(
|
|
51
|
+
const { editorView } = editor(
|
|
52
|
+
doc(table(attrs)(tr(td()(p('{<>}text')), tdEmpty, tdEmpty))),
|
|
48
53
|
);
|
|
49
|
-
const resolvedTable = findTable(
|
|
54
|
+
const resolvedTable = findTable(editorView.state.selection);
|
|
50
55
|
|
|
51
|
-
return resolvedTable!.node;
|
|
56
|
+
return { editorView, node: resolvedTable!.node };
|
|
52
57
|
};
|
|
53
58
|
|
|
54
59
|
describe('show correct container for FF and options', () => {
|
|
@@ -56,7 +61,7 @@ describe('table -> nodeviews -> TableContainer.tsx', () => {
|
|
|
56
61
|
isTableResizingEnabled: boolean,
|
|
57
62
|
isBreakoutEnabled: boolean = true,
|
|
58
63
|
) => {
|
|
59
|
-
const node = createNode();
|
|
64
|
+
const { node, editorView } = createNode();
|
|
60
65
|
|
|
61
66
|
const { container } = render(
|
|
62
67
|
<TableContainer
|
|
@@ -68,7 +73,7 @@ describe('table -> nodeviews -> TableContainer.tsx', () => {
|
|
|
68
73
|
isTableResizingEnabled={isTableResizingEnabled}
|
|
69
74
|
isBreakoutEnabled={isBreakoutEnabled}
|
|
70
75
|
className={''}
|
|
71
|
-
editorView={
|
|
76
|
+
editorView={editorView}
|
|
72
77
|
getPos={() => 1}
|
|
73
78
|
tableRef={{} as any}
|
|
74
79
|
isNested={false}
|
|
@@ -94,7 +99,7 @@ describe('table -> nodeviews -> TableContainer.tsx', () => {
|
|
|
94
99
|
isTableResizingEnabled: boolean,
|
|
95
100
|
isBreakoutEnabled: boolean = true,
|
|
96
101
|
) => {
|
|
97
|
-
const node = createNode();
|
|
102
|
+
const { node, editorView } = createNode();
|
|
98
103
|
|
|
99
104
|
const { container } = render(
|
|
100
105
|
<TableContainer
|
|
@@ -106,7 +111,7 @@ describe('table -> nodeviews -> TableContainer.tsx', () => {
|
|
|
106
111
|
isTableResizingEnabled={isTableResizingEnabled}
|
|
107
112
|
isBreakoutEnabled={isBreakoutEnabled}
|
|
108
113
|
className={''}
|
|
109
|
-
editorView={
|
|
114
|
+
editorView={editorView}
|
|
110
115
|
getPos={() => 1}
|
|
111
116
|
tableRef={{} as any}
|
|
112
117
|
isNested={true}
|
|
@@ -129,7 +134,7 @@ describe('table -> nodeviews -> TableContainer.tsx', () => {
|
|
|
129
134
|
|
|
130
135
|
describe('sets width and margin correctly for resizable container', () => {
|
|
131
136
|
const buildContainer = (attrs: TableAttributes) => {
|
|
132
|
-
const node = createNode(attrs);
|
|
137
|
+
const { node, editorView } = createNode(attrs);
|
|
133
138
|
|
|
134
139
|
const { container } = render(
|
|
135
140
|
<ResizableTableContainer
|
|
@@ -137,7 +142,7 @@ describe('table -> nodeviews -> TableContainer.tsx', () => {
|
|
|
137
142
|
lineLength={720}
|
|
138
143
|
node={node}
|
|
139
144
|
className={''}
|
|
140
|
-
editorView={
|
|
145
|
+
editorView={editorView}
|
|
141
146
|
getPos={() => 1}
|
|
142
147
|
tableRef={{} as any}
|
|
143
148
|
/>,
|
|
@@ -154,4 +159,62 @@ describe('table -> nodeviews -> TableContainer.tsx', () => {
|
|
|
154
159
|
expect(style.marginLeft).toBe('-120px');
|
|
155
160
|
});
|
|
156
161
|
});
|
|
162
|
+
|
|
163
|
+
describe('analytics', () => {
|
|
164
|
+
const buildContainer = (attrs: TableAttributes) => {
|
|
165
|
+
const { node, editorView } = createNode(attrs);
|
|
166
|
+
const analyticsMock = jest.fn();
|
|
167
|
+
|
|
168
|
+
const { container } = render(
|
|
169
|
+
<ResizableTableContainer
|
|
170
|
+
containerWidth={1800}
|
|
171
|
+
lineLength={720}
|
|
172
|
+
node={node}
|
|
173
|
+
className={''}
|
|
174
|
+
editorView={editorView}
|
|
175
|
+
getPos={() => 0}
|
|
176
|
+
tableRef={
|
|
177
|
+
{
|
|
178
|
+
querySelector: () => null,
|
|
179
|
+
insertBefore: () => {},
|
|
180
|
+
style: {},
|
|
181
|
+
} as any
|
|
182
|
+
}
|
|
183
|
+
pluginInjectionApi={
|
|
184
|
+
{
|
|
185
|
+
dependencies: {
|
|
186
|
+
analytics: { actions: { attachAnalyticsEvent: analyticsMock } },
|
|
187
|
+
},
|
|
188
|
+
} as any
|
|
189
|
+
}
|
|
190
|
+
/>,
|
|
191
|
+
);
|
|
192
|
+
|
|
193
|
+
return { container, analyticsMock };
|
|
194
|
+
};
|
|
195
|
+
|
|
196
|
+
test('fires when resizing is finished', async () => {
|
|
197
|
+
const { container, analyticsMock } = buildContainer({ layout: 'wide' });
|
|
198
|
+
|
|
199
|
+
fireEvent.mouseDown(container.querySelector('.resizer-handle-right')!);
|
|
200
|
+
fireEvent.mouseMove(container.querySelector('.resizer-handle-right')!);
|
|
201
|
+
fireEvent.mouseMove(container.querySelector('.resizer-handle-right')!);
|
|
202
|
+
fireEvent.mouseMove(container.querySelector('.resizer-handle-right')!);
|
|
203
|
+
fireEvent.mouseUp(container.querySelector('.resizer-handle-right')!);
|
|
204
|
+
|
|
205
|
+
expect(analyticsMock).toHaveBeenLastCalledWith({
|
|
206
|
+
action: TABLE_ACTION.RESIZED,
|
|
207
|
+
actionSubject: ACTION_SUBJECT.TABLE,
|
|
208
|
+
eventType: EVENT_TYPE.TRACK,
|
|
209
|
+
attributes: {
|
|
210
|
+
width: undefined, // Can't get the events right to trigger re-resizeable
|
|
211
|
+
prevWidth: null,
|
|
212
|
+
nodeSize: 20,
|
|
213
|
+
totalTableWidth: null,
|
|
214
|
+
totalRowCount: 1,
|
|
215
|
+
totalColumnCount: 3,
|
|
216
|
+
},
|
|
217
|
+
});
|
|
218
|
+
});
|
|
219
|
+
});
|
|
157
220
|
});
|
|
@@ -39,7 +39,8 @@ describe('Snapshot Test: Table', () => {
|
|
|
39
39
|
});
|
|
40
40
|
|
|
41
41
|
describe('sticky header', () => {
|
|
42
|
-
|
|
42
|
+
// FIXME: This test was automatically skipped due to failure on 26/07/2023: https://product-fabric.atlassian.net/browse/ED-19223
|
|
43
|
+
it.skip('should align with table cell when active', async () => {
|
|
43
44
|
await initEditor(page, stickyHeaderWithHorizontalScroll);
|
|
44
45
|
|
|
45
46
|
await clickFirstCell(page, true);
|
|
@@ -9,6 +9,7 @@ import classNames from 'classnames';
|
|
|
9
9
|
import { Node as PMNode } from 'prosemirror-model';
|
|
10
10
|
import { EditorView } from 'prosemirror-view';
|
|
11
11
|
|
|
12
|
+
import { TableEventPayload } from '@atlaskit/editor-common/analytics';
|
|
12
13
|
import { getTableContainerWidth } from '@atlaskit/editor-common/node-width';
|
|
13
14
|
import { calcTableWidth } from '@atlaskit/editor-common/styles';
|
|
14
15
|
import { EditorContainerWidth } from '@atlaskit/editor-common/types';
|
|
@@ -115,15 +116,20 @@ export const ResizableTableContainer = ({
|
|
|
115
116
|
[pluginInjectionApi, editorView],
|
|
116
117
|
);
|
|
117
118
|
|
|
118
|
-
const
|
|
119
|
+
const attachAnalyticsEvent = useCallback(
|
|
120
|
+
(payload: TableEventPayload) => {
|
|
121
|
+
return pluginInjectionApi?.dependencies?.analytics.actions.attachAnalyticsEvent(
|
|
122
|
+
payload,
|
|
123
|
+
);
|
|
124
|
+
},
|
|
125
|
+
[pluginInjectionApi],
|
|
126
|
+
);
|
|
119
127
|
|
|
128
|
+
const tableWidth = getTableContainerWidth(node);
|
|
120
129
|
// 76 is currently an accepted padding value considering the spacing for resizer handle
|
|
121
130
|
const responsiveContainerWidth = containerWidth - 76;
|
|
122
|
-
|
|
123
131
|
const width = Math.min(tableWidth, responsiveContainerWidth);
|
|
124
|
-
|
|
125
132
|
marginLeftRef.current = getMarginLeft(lineLength, width);
|
|
126
|
-
|
|
127
133
|
const maxResizerWidth = Math.min(responsiveContainerWidth, TABLE_MAX_WIDTH);
|
|
128
134
|
|
|
129
135
|
return (
|
|
@@ -141,6 +147,7 @@ export const ResizableTableContainer = ({
|
|
|
141
147
|
node={node}
|
|
142
148
|
tableRef={tableRef}
|
|
143
149
|
displayGuideline={displayGuideline}
|
|
150
|
+
attachAnalyticsEvent={attachAnalyticsEvent}
|
|
144
151
|
>
|
|
145
152
|
<InnerContainer className={className} node={node}>
|
|
146
153
|
{children}
|
|
@@ -7,9 +7,16 @@ import React, {
|
|
|
7
7
|
} from 'react';
|
|
8
8
|
|
|
9
9
|
import { Node as PMNode } from 'prosemirror-model';
|
|
10
|
+
import { Transaction } from 'prosemirror-state';
|
|
10
11
|
import { EditorView } from 'prosemirror-view';
|
|
11
12
|
import rafSchd from 'raf-schd';
|
|
12
13
|
|
|
14
|
+
import {
|
|
15
|
+
ACTION_SUBJECT,
|
|
16
|
+
EVENT_TYPE,
|
|
17
|
+
TABLE_ACTION,
|
|
18
|
+
TableEventPayload,
|
|
19
|
+
} from '@atlaskit/editor-common/analytics';
|
|
13
20
|
import { getGuidelinesWithHighlights } from '@atlaskit/editor-common/guideline';
|
|
14
21
|
import {
|
|
15
22
|
HandleHeightSizeType,
|
|
@@ -17,15 +24,18 @@ import {
|
|
|
17
24
|
ResizerNext,
|
|
18
25
|
} from '@atlaskit/editor-common/resizer';
|
|
19
26
|
import type { GuidelineConfig } from '@atlaskit/editor-plugin-guideline';
|
|
27
|
+
import { TableMap } from '@atlaskit/editor-tables';
|
|
20
28
|
|
|
21
29
|
import {
|
|
22
30
|
COLUMN_MIN_WIDTH,
|
|
23
31
|
getColgroupChildrenLength,
|
|
32
|
+
hasTableBeenResized,
|
|
24
33
|
previewScaleTable,
|
|
25
34
|
scaleTable,
|
|
26
35
|
} from '../pm-plugins/table-resizing/utils';
|
|
27
36
|
import { pluginKey as tableWidthPluginKey } from '../pm-plugins/table-width';
|
|
28
37
|
import { TABLE_HIGHLIGHT_GAP, TABLE_SNAP_GAP } from '../ui/consts';
|
|
38
|
+
import { getTableWidth } from '../utils';
|
|
29
39
|
import { defaultGuidelines, defaultGuidelineWidths } from '../utils/guidelines';
|
|
30
40
|
import { findClosestSnap } from '../utils/snapping';
|
|
31
41
|
|
|
@@ -38,11 +48,37 @@ interface TableResizerProps {
|
|
|
38
48
|
node: PMNode;
|
|
39
49
|
tableRef: HTMLTableElement;
|
|
40
50
|
displayGuideline: (guideline: GuidelineConfig[]) => boolean;
|
|
51
|
+
attachAnalyticsEvent: (
|
|
52
|
+
payload: TableEventPayload,
|
|
53
|
+
) => ((tr: Transaction) => boolean) | undefined;
|
|
41
54
|
}
|
|
42
55
|
|
|
43
56
|
const handles = { right: true };
|
|
44
57
|
const tableHandleMarginTop = 11;
|
|
45
58
|
|
|
59
|
+
const generateResizedPayload = (props: {
|
|
60
|
+
originalNode: PMNode;
|
|
61
|
+
resizedNode: PMNode;
|
|
62
|
+
}): TableEventPayload => {
|
|
63
|
+
const tableMap = TableMap.get(props.resizedNode);
|
|
64
|
+
|
|
65
|
+
return {
|
|
66
|
+
action: TABLE_ACTION.RESIZED,
|
|
67
|
+
actionSubject: ACTION_SUBJECT.TABLE,
|
|
68
|
+
eventType: EVENT_TYPE.TRACK,
|
|
69
|
+
attributes: {
|
|
70
|
+
newWidth: props.resizedNode.attrs.width,
|
|
71
|
+
prevWidth: props.originalNode.attrs.width ?? null,
|
|
72
|
+
nodeSize: props.resizedNode.nodeSize,
|
|
73
|
+
totalTableWidth: hasTableBeenResized(props.resizedNode)
|
|
74
|
+
? getTableWidth(props.resizedNode)
|
|
75
|
+
: null,
|
|
76
|
+
totalRowCount: tableMap.height,
|
|
77
|
+
totalColumnCount: tableMap.width,
|
|
78
|
+
},
|
|
79
|
+
};
|
|
80
|
+
};
|
|
81
|
+
|
|
46
82
|
export const TableResizer = ({
|
|
47
83
|
children,
|
|
48
84
|
width,
|
|
@@ -53,6 +89,7 @@ export const TableResizer = ({
|
|
|
53
89
|
node,
|
|
54
90
|
tableRef,
|
|
55
91
|
displayGuideline,
|
|
92
|
+
attachAnalyticsEvent,
|
|
56
93
|
}: PropsWithChildren<TableResizerProps>) => {
|
|
57
94
|
const currentColumnCount = getColgroupChildrenLength(node);
|
|
58
95
|
const minColumnWidth =
|
|
@@ -111,6 +148,7 @@ export const TableResizer = ({
|
|
|
111
148
|
dispatch,
|
|
112
149
|
state: { tr },
|
|
113
150
|
} = editorView;
|
|
151
|
+
|
|
114
152
|
dispatch(tr.setMeta(tableWidthPluginKey, { resizing: true }));
|
|
115
153
|
|
|
116
154
|
setSnappingEnabled(displayGuideline(defaultGuidelines));
|
|
@@ -142,19 +180,73 @@ export const TableResizer = ({
|
|
|
142
180
|
},
|
|
143
181
|
editorView.domAtPos.bind(editorView),
|
|
144
182
|
)(tr);
|
|
183
|
+
|
|
184
|
+
const scaledNode = tr.doc.nodeAt(pos)!;
|
|
185
|
+
|
|
186
|
+
attachAnalyticsEvent(
|
|
187
|
+
generateResizedPayload({
|
|
188
|
+
originalNode: node,
|
|
189
|
+
resizedNode: scaledNode,
|
|
190
|
+
}),
|
|
191
|
+
)?.(tr);
|
|
145
192
|
}
|
|
146
193
|
|
|
147
194
|
dispatch(tr);
|
|
148
195
|
|
|
149
196
|
// Hide guidelines when resizing stops
|
|
150
197
|
displayGuideline([]);
|
|
198
|
+
updateWidth(newWidth);
|
|
199
|
+
|
|
200
|
+
return newWidth;
|
|
201
|
+
},
|
|
202
|
+
[
|
|
203
|
+
updateWidth,
|
|
204
|
+
editorView,
|
|
205
|
+
getPos,
|
|
206
|
+
node,
|
|
207
|
+
tableRef,
|
|
208
|
+
displayGuideline,
|
|
209
|
+
attachAnalyticsEvent,
|
|
210
|
+
],
|
|
211
|
+
);
|
|
212
|
+
|
|
213
|
+
const handleResize = useCallback(
|
|
214
|
+
(originalState, delta) => {
|
|
215
|
+
const newWidth = originalState.width + delta.width;
|
|
216
|
+
const pos = getPos();
|
|
217
|
+
if (typeof pos !== 'number') {
|
|
218
|
+
return;
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
previewScaleTable(
|
|
222
|
+
tableRef,
|
|
223
|
+
{
|
|
224
|
+
node,
|
|
225
|
+
prevNode: node,
|
|
226
|
+
start: pos + 1,
|
|
227
|
+
parentWidth: newWidth,
|
|
228
|
+
},
|
|
229
|
+
editorView.domAtPos.bind(editorView),
|
|
230
|
+
);
|
|
231
|
+
|
|
232
|
+
updateActiveGuidelines(
|
|
233
|
+
findClosestSnap(
|
|
234
|
+
newWidth,
|
|
235
|
+
defaultGuidelineWidths,
|
|
236
|
+
defaultGuidelines,
|
|
237
|
+
TABLE_HIGHLIGHT_GAP,
|
|
238
|
+
),
|
|
239
|
+
);
|
|
151
240
|
|
|
152
241
|
updateWidth(newWidth);
|
|
242
|
+
|
|
153
243
|
return newWidth;
|
|
154
244
|
},
|
|
155
|
-
[
|
|
245
|
+
[editorView, getPos, node, tableRef, updateWidth, updateActiveGuidelines],
|
|
156
246
|
);
|
|
157
247
|
|
|
248
|
+
const scheduleResize = useMemo(() => rafSchd(handleResize), [handleResize]);
|
|
249
|
+
|
|
158
250
|
return (
|
|
159
251
|
<ResizerNext
|
|
160
252
|
enable={handles}
|
|
@@ -163,36 +255,7 @@ export const TableResizer = ({
|
|
|
163
255
|
handleHeightSize={handleHeightSize}
|
|
164
256
|
handleMarginTop={tableHandleMarginTop}
|
|
165
257
|
handleResizeStart={handleResizeStart}
|
|
166
|
-
handleResize={
|
|
167
|
-
const newWidth = originalState.width + delta.width;
|
|
168
|
-
const pos = getPos();
|
|
169
|
-
if (typeof pos !== 'number') {
|
|
170
|
-
return;
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
previewScaleTable(
|
|
174
|
-
tableRef,
|
|
175
|
-
{
|
|
176
|
-
node,
|
|
177
|
-
prevNode: node,
|
|
178
|
-
start: pos + 1,
|
|
179
|
-
parentWidth: newWidth,
|
|
180
|
-
},
|
|
181
|
-
editorView.domAtPos.bind(editorView),
|
|
182
|
-
);
|
|
183
|
-
|
|
184
|
-
updateActiveGuidelines(
|
|
185
|
-
findClosestSnap(
|
|
186
|
-
newWidth,
|
|
187
|
-
defaultGuidelineWidths,
|
|
188
|
-
defaultGuidelines,
|
|
189
|
-
TABLE_HIGHLIGHT_GAP,
|
|
190
|
-
),
|
|
191
|
-
);
|
|
192
|
-
|
|
193
|
-
updateWidth(newWidth);
|
|
194
|
-
return newWidth;
|
|
195
|
-
})}
|
|
258
|
+
handleResize={scheduleResize}
|
|
196
259
|
handleResizeStop={handleResizeStop}
|
|
197
260
|
resizeRatio={2}
|
|
198
261
|
minWidth={minColumnWidth}
|
|
@@ -40,28 +40,6 @@ const anyChildCellMergedAcrossRow = (node: PmNode) =>
|
|
|
40
40
|
(rowspan) => rowspan > 1,
|
|
41
41
|
);
|
|
42
42
|
|
|
43
|
-
/**
|
|
44
|
-
* Compare two table row nodes and return true if the two table rows have a
|
|
45
|
-
* different number of table cells or if table cell row spans are different
|
|
46
|
-
*/
|
|
47
|
-
const rowHasDifferentMergedCells = (prevNode: PmNode, incomingNode: PmNode) => {
|
|
48
|
-
const incomingNodeChildrenRowSpan = mapChildren(
|
|
49
|
-
prevNode,
|
|
50
|
-
(child) => child.attrs.rowspan || 0,
|
|
51
|
-
);
|
|
52
|
-
const currentNodeChildrenRowSpan = mapChildren(
|
|
53
|
-
incomingNode,
|
|
54
|
-
(child) => child.attrs.rowspan || 0,
|
|
55
|
-
);
|
|
56
|
-
|
|
57
|
-
return (
|
|
58
|
-
incomingNodeChildrenRowSpan.length !== currentNodeChildrenRowSpan.length ||
|
|
59
|
-
currentNodeChildrenRowSpan.some(
|
|
60
|
-
(child, index) => child !== incomingNodeChildrenRowSpan[index],
|
|
61
|
-
)
|
|
62
|
-
);
|
|
63
|
-
};
|
|
64
|
-
|
|
65
43
|
/**
|
|
66
44
|
* Check if a given node is a header row with this definition:
|
|
67
45
|
* - all children are tableHeader cells
|
|
@@ -429,10 +407,6 @@ export class TableRowNodeView implements NodeView {
|
|
|
429
407
|
return false; // re-create nodeview
|
|
430
408
|
}
|
|
431
409
|
|
|
432
|
-
if (rowHasDifferentMergedCells(this.node, node)) {
|
|
433
|
-
return false;
|
|
434
|
-
}
|
|
435
|
-
|
|
436
410
|
// node is different but no need to re-create nodeview
|
|
437
411
|
this.node = node;
|
|
438
412
|
|