@atlaskit/editor-plugin-table 1.6.1 → 1.6.3
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 +12 -0
- package/dist/cjs/plugins/table/index.js +2 -1
- package/dist/cjs/plugins/table/pm-plugins/sticky-headers/nodeviews/tableRow.js +3 -1
- package/dist/cjs/plugins/table/types.js +1 -0
- package/dist/cjs/plugins/table/ui/FloatingContextualButton/FixedButton.js +133 -0
- package/dist/cjs/plugins/table/ui/FloatingContextualButton/index.js +73 -128
- package/dist/cjs/version.json +1 -1
- package/dist/es2019/plugins/table/index.js +2 -1
- package/dist/es2019/plugins/table/pm-plugins/sticky-headers/nodeviews/tableRow.js +3 -1
- package/dist/es2019/plugins/table/types.js +1 -0
- package/dist/es2019/plugins/table/ui/FloatingContextualButton/FixedButton.js +120 -0
- package/dist/es2019/plugins/table/ui/FloatingContextualButton/index.js +76 -108
- package/dist/es2019/version.json +1 -1
- package/dist/esm/plugins/table/index.js +2 -1
- package/dist/esm/plugins/table/pm-plugins/sticky-headers/nodeviews/tableRow.js +3 -1
- package/dist/esm/plugins/table/types.js +1 -0
- package/dist/esm/plugins/table/ui/FloatingContextualButton/FixedButton.js +118 -0
- package/dist/esm/plugins/table/ui/FloatingContextualButton/index.js +73 -129
- package/dist/esm/version.json +1 -1
- package/dist/types/plugins/table/types.d.ts +1 -0
- package/dist/types/plugins/table/ui/FloatingContextualButton/FixedButton.d.ts +23 -0
- package/dist/types/plugins/table/ui/FloatingContextualButton/index.d.ts +1 -9
- package/dist/types-ts4.5/plugins/table/types.d.ts +1 -0
- package/dist/types-ts4.5/plugins/table/ui/FloatingContextualButton/FixedButton.d.ts +23 -0
- package/dist/types-ts4.5/plugins/table/ui/FloatingContextualButton/index.d.ts +1 -9
- package/package.json +5 -4
- package/src/__tests__/playwright/__fixtures__/base-adfs.ts +1486 -0
- package/src/__tests__/playwright/extensions.spec.ts +67 -0
- package/src/__tests__/unit/nodeviews/cell.ts +0 -14
- package/src/__tests__/unit/ui/FixedButton.tsx +214 -0
- package/src/plugins/table/index.tsx +1 -0
- package/src/plugins/table/pm-plugins/sticky-headers/nodeviews/tableRow.ts +2 -1
- package/src/plugins/table/types.ts +1 -0
- package/src/plugins/table/ui/FloatingContextualButton/FixedButton.tsx +175 -0
- package/src/plugins/table/ui/FloatingContextualButton/index.tsx +41 -95
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,17 @@
|
|
|
1
1
|
# @atlaskit/editor-plugin-table
|
|
2
2
|
|
|
3
|
+
## 1.6.3
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- [`1202f6f0a82`](https://bitbucket.org/atlassian/atlassian-frontend/commits/1202f6f0a82) - ED-16692: add logic to position FloatingContextualButton correctly when sticky and scrolling
|
|
8
|
+
|
|
9
|
+
## 1.6.2
|
|
10
|
+
|
|
11
|
+
### Patch Changes
|
|
12
|
+
|
|
13
|
+
- Updated dependencies
|
|
14
|
+
|
|
3
15
|
## 1.6.1
|
|
4
16
|
|
|
5
17
|
### Patch Changes
|
|
@@ -261,7 +261,8 @@ var tablesPlugin = function tablesPlugin(options, api) {
|
|
|
261
261
|
dispatchAnalyticsEvent: dispatchAnalyticsEvent,
|
|
262
262
|
isContextualMenuOpen: isContextualMenuOpen,
|
|
263
263
|
layout: layout,
|
|
264
|
-
stickyHeader: stickyHeader
|
|
264
|
+
stickyHeader: stickyHeader,
|
|
265
|
+
tableWrapper: tableWrapperTarget
|
|
265
266
|
}), allowControls && /*#__PURE__*/_react.default.createElement(_FloatingInsertButton.default, {
|
|
266
267
|
tableNode: tableNode,
|
|
267
268
|
tableRef: tableRef,
|
|
@@ -232,7 +232,8 @@ var TableRowNodeView = /*#__PURE__*/function () {
|
|
|
232
232
|
if (_this.stickyRowHeight && _this.stickyRowHeight > window.innerHeight / 2) {
|
|
233
233
|
return;
|
|
234
234
|
}
|
|
235
|
-
var table = tree.table
|
|
235
|
+
var table = tree.table,
|
|
236
|
+
wrapper = tree.wrapper;
|
|
236
237
|
|
|
237
238
|
// ED-16035 Make sure sticky header is only applied to first row
|
|
238
239
|
var tbody = _this.dom.parentElement;
|
|
@@ -253,6 +254,7 @@ var TableRowNodeView = /*#__PURE__*/function () {
|
|
|
253
254
|
}
|
|
254
255
|
_this.dom.style.top = "".concat(domTop, "px");
|
|
255
256
|
(0, _dom.updateStickyMargins)(table);
|
|
257
|
+
_this.dom.scrollLeft = wrapper.scrollLeft;
|
|
256
258
|
_this.emitOn(domTop, _this.colControlsOffset);
|
|
257
259
|
});
|
|
258
260
|
(0, _defineProperty2.default)(this, "makeRowHeaderNotSticky", function (table) {
|
|
@@ -98,6 +98,7 @@ var TableCssClassName = _objectSpread(_objectSpread({}, _styles.TableSharedCssCl
|
|
|
98
98
|
CONTEXTUAL_SUBMENU: "".concat(_adfSchema.tablePrefixSelector, "-contextual-submenu"),
|
|
99
99
|
CONTEXTUAL_MENU_BUTTON_WRAP: "".concat(_adfSchema.tablePrefixSelector, "-contextual-menu-button-wrap"),
|
|
100
100
|
CONTEXTUAL_MENU_BUTTON: "".concat(_adfSchema.tablePrefixSelector, "-contextual-menu-button"),
|
|
101
|
+
CONTEXTUAL_MENU_BUTTON_FIXED: "".concat(_adfSchema.tablePrefixSelector, "-contextual-menu-button-fixed"),
|
|
101
102
|
CONTEXTUAL_MENU_ICON: "".concat(_adfSchema.tablePrefixSelector, "-contextual-submenu-icon"),
|
|
102
103
|
// come from prosemirror-table
|
|
103
104
|
SELECTED_CELL: 'selectedCell',
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
|
|
4
|
+
var _typeof = require("@babel/runtime/helpers/typeof");
|
|
5
|
+
Object.defineProperty(exports, "__esModule", {
|
|
6
|
+
value: true
|
|
7
|
+
});
|
|
8
|
+
exports.default = exports.calcObserverTargetMargin = exports.calcLeftPos = exports.FixedButton = exports.BUTTON_WIDTH = void 0;
|
|
9
|
+
var _react = _interopRequireWildcard(require("react"));
|
|
10
|
+
var _reactDom = require("react-dom");
|
|
11
|
+
var _rafSchd = _interopRequireDefault(require("raf-schd"));
|
|
12
|
+
var _editorSharedStyles = require("@atlaskit/editor-shared-styles");
|
|
13
|
+
var _commonStyles = require("../common-styles");
|
|
14
|
+
var _types = require("../../types");
|
|
15
|
+
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); }
|
|
16
|
+
function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || _typeof(obj) !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
|
|
17
|
+
var BUTTON_WIDTH = 20;
|
|
18
|
+
exports.BUTTON_WIDTH = BUTTON_WIDTH;
|
|
19
|
+
var calcLeftPos = function calcLeftPos(_ref) {
|
|
20
|
+
var buttonWidth = _ref.buttonWidth,
|
|
21
|
+
cellRectLeft = _ref.cellRectLeft,
|
|
22
|
+
cellRefWidth = _ref.cellRefWidth,
|
|
23
|
+
offset = _ref.offset;
|
|
24
|
+
return cellRectLeft + cellRefWidth - buttonWidth - offset;
|
|
25
|
+
};
|
|
26
|
+
exports.calcLeftPos = calcLeftPos;
|
|
27
|
+
var calcObserverTargetMargin = function calcObserverTargetMargin(tableWrapper, fixedButtonRefCurrent) {
|
|
28
|
+
var tableWrapperRect = tableWrapper.getBoundingClientRect();
|
|
29
|
+
var fixedButtonRect = fixedButtonRefCurrent.getBoundingClientRect();
|
|
30
|
+
var scrollLeft = tableWrapper.scrollLeft;
|
|
31
|
+
return fixedButtonRect.left - tableWrapperRect.left + scrollLeft;
|
|
32
|
+
};
|
|
33
|
+
exports.calcObserverTargetMargin = calcObserverTargetMargin;
|
|
34
|
+
var FixedButton = function FixedButton(_ref2) {
|
|
35
|
+
var children = _ref2.children,
|
|
36
|
+
isContextualMenuOpen = _ref2.isContextualMenuOpen,
|
|
37
|
+
mountTo = _ref2.mountTo,
|
|
38
|
+
offset = _ref2.offset,
|
|
39
|
+
stickyHeader = _ref2.stickyHeader,
|
|
40
|
+
tableWrapper = _ref2.tableWrapper,
|
|
41
|
+
targetCellPosition = _ref2.targetCellPosition,
|
|
42
|
+
targetCellRef = _ref2.targetCellRef;
|
|
43
|
+
var fixedButtonRef = (0, _react.useRef)(null);
|
|
44
|
+
var observerTargetRef = (0, _react.useRef)(null);
|
|
45
|
+
|
|
46
|
+
// Using refs here rather than state to prevent heaps of renders on scroll
|
|
47
|
+
var scrollDataRef = (0, _react.useRef)(0);
|
|
48
|
+
var leftPosDataRef = (0, _react.useRef)(0);
|
|
49
|
+
(0, _react.useEffect)(function () {
|
|
50
|
+
var observerTargetRefCurrent = observerTargetRef.current;
|
|
51
|
+
var fixedButtonRefCurrent = fixedButtonRef.current;
|
|
52
|
+
if (fixedButtonRefCurrent && observerTargetRefCurrent) {
|
|
53
|
+
scrollDataRef.current = tableWrapper.scrollLeft;
|
|
54
|
+
leftPosDataRef.current = 0;
|
|
55
|
+
// Hide the button initially in case there's a flash of the button being
|
|
56
|
+
// outside the table before the Intersection Observer fires
|
|
57
|
+
fixedButtonRefCurrent.style.visibility = 'hidden';
|
|
58
|
+
var margin = calcObserverTargetMargin(tableWrapper, fixedButtonRefCurrent);
|
|
59
|
+
|
|
60
|
+
// Much more simple and predictable to add this margin to the observer target
|
|
61
|
+
// rather than using it to calculate the rootMargin values
|
|
62
|
+
observerTargetRefCurrent.style.marginLeft = "".concat(margin, "px");
|
|
63
|
+
var observer = new IntersectionObserver(function (entries) {
|
|
64
|
+
entries.forEach(function (entry) {
|
|
65
|
+
if (entry.isIntersecting) {
|
|
66
|
+
fixedButtonRefCurrent.style.visibility = 'visible';
|
|
67
|
+
} else {
|
|
68
|
+
fixedButtonRefCurrent.style.visibility = 'hidden';
|
|
69
|
+
}
|
|
70
|
+
});
|
|
71
|
+
}, {
|
|
72
|
+
root: tableWrapper,
|
|
73
|
+
rootMargin: "0px ".concat(_commonStyles.insertColumnButtonOffset, "px 0px 0px"),
|
|
74
|
+
threshold: 1
|
|
75
|
+
});
|
|
76
|
+
var handleScroll = (0, _rafSchd.default)(function (event) {
|
|
77
|
+
if (fixedButtonRef.current) {
|
|
78
|
+
var delta = event.target.scrollLeft - scrollDataRef.current;
|
|
79
|
+
var style = "translateX(".concat(leftPosDataRef.current - delta, "px)");
|
|
80
|
+
fixedButtonRef.current.style.transform = style;
|
|
81
|
+
scrollDataRef.current = event.target.scrollLeft;
|
|
82
|
+
leftPosDataRef.current = leftPosDataRef.current - delta;
|
|
83
|
+
}
|
|
84
|
+
});
|
|
85
|
+
observer.observe(observerTargetRefCurrent);
|
|
86
|
+
tableWrapper.addEventListener('scroll', handleScroll);
|
|
87
|
+
return function () {
|
|
88
|
+
tableWrapper.removeEventListener('scroll', handleScroll);
|
|
89
|
+
fixedButtonRefCurrent.style.transform = '';
|
|
90
|
+
observer.unobserve(observerTargetRefCurrent);
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
}, [fixedButtonRef, observerTargetRef, tableWrapper, targetCellPosition, targetCellRef, isContextualMenuOpen]);
|
|
94
|
+
var targetCellRect = targetCellRef.getBoundingClientRect();
|
|
95
|
+
|
|
96
|
+
// Using a portal here to ensure wrapperRef has the tableWrapper as an
|
|
97
|
+
// ancestor. This is required to make the Intersection Observer work.
|
|
98
|
+
return /*#__PURE__*/(0, _reactDom.createPortal)(
|
|
99
|
+
/*#__PURE__*/
|
|
100
|
+
// Using observerTargetRef here for our Intersection Observer. There is issues
|
|
101
|
+
// getting the observer to work just using the fixedButtonRef, possible due
|
|
102
|
+
// to using position fixed on this Element, or possibly due to its position
|
|
103
|
+
// being changed on scroll.
|
|
104
|
+
_react.default.createElement("div", {
|
|
105
|
+
ref: observerTargetRef,
|
|
106
|
+
style: {
|
|
107
|
+
position: 'absolute',
|
|
108
|
+
top: '0px',
|
|
109
|
+
left: '0px',
|
|
110
|
+
width: "".concat(BUTTON_WIDTH, "px"),
|
|
111
|
+
height: "".concat(BUTTON_WIDTH, "px")
|
|
112
|
+
}
|
|
113
|
+
}, /*#__PURE__*/_react.default.createElement("div", {
|
|
114
|
+
ref: fixedButtonRef,
|
|
115
|
+
style: {
|
|
116
|
+
position: 'fixed',
|
|
117
|
+
top: stickyHeader.top + stickyHeader.padding + offset * 2,
|
|
118
|
+
zIndex: _editorSharedStyles.akEditorFloatingPanelZIndex,
|
|
119
|
+
left: calcLeftPos({
|
|
120
|
+
buttonWidth: BUTTON_WIDTH,
|
|
121
|
+
cellRectLeft: targetCellRect.left,
|
|
122
|
+
cellRefWidth: targetCellRef.clientWidth,
|
|
123
|
+
offset: offset
|
|
124
|
+
}),
|
|
125
|
+
width: "".concat(BUTTON_WIDTH, "px"),
|
|
126
|
+
height: "".concat(BUTTON_WIDTH, "px")
|
|
127
|
+
},
|
|
128
|
+
className: _types.TableCssClassName.CONTEXTUAL_MENU_BUTTON_FIXED
|
|
129
|
+
}, children)), mountTo);
|
|
130
|
+
};
|
|
131
|
+
exports.FixedButton = FixedButton;
|
|
132
|
+
var _default = FixedButton;
|
|
133
|
+
exports.default = _default;
|
|
@@ -4,15 +4,7 @@ var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefau
|
|
|
4
4
|
Object.defineProperty(exports, "__esModule", {
|
|
5
5
|
value: true
|
|
6
6
|
});
|
|
7
|
-
exports.FloatingContextualButtonInner = void 0;
|
|
8
7
|
exports.default = _default;
|
|
9
|
-
var _classCallCheck2 = _interopRequireDefault(require("@babel/runtime/helpers/classCallCheck"));
|
|
10
|
-
var _createClass2 = _interopRequireDefault(require("@babel/runtime/helpers/createClass"));
|
|
11
|
-
var _assertThisInitialized2 = _interopRequireDefault(require("@babel/runtime/helpers/assertThisInitialized"));
|
|
12
|
-
var _inherits2 = _interopRequireDefault(require("@babel/runtime/helpers/inherits"));
|
|
13
|
-
var _possibleConstructorReturn2 = _interopRequireDefault(require("@babel/runtime/helpers/possibleConstructorReturn"));
|
|
14
|
-
var _getPrototypeOf2 = _interopRequireDefault(require("@babel/runtime/helpers/getPrototypeOf"));
|
|
15
|
-
var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
|
|
16
8
|
var _react = _interopRequireDefault(require("react"));
|
|
17
9
|
var _react2 = require("@emotion/react");
|
|
18
10
|
var _prosemirrorUtils = require("prosemirror-utils");
|
|
@@ -21,135 +13,88 @@ var _ui = require("@atlaskit/editor-common/ui");
|
|
|
21
13
|
var _editorSharedStyles = require("@atlaskit/editor-shared-styles");
|
|
22
14
|
var _chevronDown = _interopRequireDefault(require("@atlaskit/icon/glyph/chevron-down"));
|
|
23
15
|
var _uiMenu = require("@atlaskit/editor-common/ui-menu");
|
|
24
|
-
var _utils = require("@atlaskit/editor-common/utils");
|
|
25
16
|
var _commands = require("../../commands");
|
|
26
17
|
var _types = require("../../types");
|
|
27
18
|
var _messages = _interopRequireDefault(require("../../ui/messages"));
|
|
19
|
+
var _FixedButton = _interopRequireDefault(require("./FixedButton"));
|
|
28
20
|
var _analytics = require("@atlaskit/editor-common/analytics");
|
|
29
21
|
var _styles = require("./styles");
|
|
30
22
|
var _errorBoundary = require("@atlaskit/editor-common/error-boundary");
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
var
|
|
34
|
-
|
|
35
|
-
var
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
23
|
+
/** @jsx jsx */
|
|
24
|
+
|
|
25
|
+
var BUTTON_OFFSET = 3;
|
|
26
|
+
var FloatingContextualButtonInner = /*#__PURE__*/_react.default.memo(function (props) {
|
|
27
|
+
var editorView = props.editorView,
|
|
28
|
+
isContextualMenuOpen = props.isContextualMenuOpen,
|
|
29
|
+
mountPoint = props.mountPoint,
|
|
30
|
+
scrollableElement = props.scrollableElement,
|
|
31
|
+
stickyHeader = props.stickyHeader,
|
|
32
|
+
tableWrapper = props.tableWrapper,
|
|
33
|
+
targetCellPosition = props.targetCellPosition,
|
|
34
|
+
formatMessage = props.intl.formatMessage; // : Props & WrappedComponentProps
|
|
35
|
+
|
|
36
|
+
var handleClick = function handleClick() {
|
|
37
|
+
var state = editorView.state,
|
|
38
|
+
dispatch = editorView.dispatch;
|
|
39
|
+
// Clicking outside the dropdown handles toggling the menu closed
|
|
40
|
+
// (otherwise these two toggles combat each other).
|
|
41
|
+
// In the event a user clicks the chevron button again
|
|
42
|
+
// That will count as clicking outside the dropdown and
|
|
43
|
+
// will be toggled appropriately
|
|
44
|
+
if (!isContextualMenuOpen) {
|
|
45
|
+
(0, _commands.toggleContextualMenu)()(state, dispatch);
|
|
41
46
|
}
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
// (otherwise these two toggles combat each other).
|
|
49
|
-
// In the event a user clicks the chevron button again
|
|
50
|
-
// That will count as clicking outside the dropdown and
|
|
51
|
-
// will be toggled appropriately
|
|
52
|
-
if (!_this.props.isContextualMenuOpen) {
|
|
53
|
-
(0, _commands.toggleContextualMenu)()(state, dispatch);
|
|
54
|
-
}
|
|
55
|
-
});
|
|
56
|
-
return _this;
|
|
47
|
+
};
|
|
48
|
+
var domAtPos = editorView.domAtPos.bind(editorView);
|
|
49
|
+
var targetCellRef;
|
|
50
|
+
targetCellRef = (0, _prosemirrorUtils.findDomRefAtPos)(targetCellPosition, domAtPos);
|
|
51
|
+
if (!targetCellRef || !(targetCellRef instanceof HTMLElement)) {
|
|
52
|
+
return null;
|
|
57
53
|
}
|
|
58
|
-
(
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
isContextualMenuOpen = _this$props.isContextualMenuOpen,
|
|
67
|
-
formatMessage = _this$props.intl.formatMessage,
|
|
68
|
-
dispatchAnalyticsEvent = _this$props.dispatchAnalyticsEvent; // : Props & WrappedComponentProps
|
|
69
|
-
var domAtPos = editorView.domAtPos.bind(editorView);
|
|
70
|
-
var targetCellRef;
|
|
71
|
-
try {
|
|
72
|
-
targetCellRef = (0, _prosemirrorUtils.findDomRefAtPos)(targetCellPosition, domAtPos);
|
|
73
|
-
} catch (error) {
|
|
74
|
-
// eslint-disable-next-line no-console
|
|
75
|
-
console.warn(error);
|
|
76
|
-
if (dispatchAnalyticsEvent) {
|
|
77
|
-
var payload = {
|
|
78
|
-
action: _analytics.ACTION.ERRORED,
|
|
79
|
-
actionSubject: _analytics.ACTION_SUBJECT.CONTENT_COMPONENT,
|
|
80
|
-
eventType: _analytics.EVENT_TYPE.OPERATIONAL,
|
|
81
|
-
attributes: {
|
|
82
|
-
component: _analytics.CONTENT_COMPONENT.FLOATING_CONTEXTUAL_BUTTON,
|
|
83
|
-
selection: editorView.state.selection.toJSON(),
|
|
84
|
-
position: targetCellPosition,
|
|
85
|
-
docSize: editorView.state.doc.nodeSize,
|
|
86
|
-
error: error instanceof Error ? error.message : String(error)
|
|
87
|
-
},
|
|
88
|
-
nonPrivacySafeAttributes: {
|
|
89
|
-
errorStack: error instanceof Error ? error.stack : undefined
|
|
90
|
-
}
|
|
91
|
-
};
|
|
92
|
-
dispatchAnalyticsEvent(payload);
|
|
93
|
-
}
|
|
94
|
-
}
|
|
95
|
-
if (!targetCellRef || !(targetCellRef instanceof HTMLElement)) {
|
|
96
|
-
return null;
|
|
97
|
-
}
|
|
98
|
-
var tableWrapper = (0, _utils.closestElement)(targetCellRef, ".".concat(_types.TableCssClassName.TABLE_NODE_WRAPPER));
|
|
99
|
-
var labelCellOptions = formatMessage(_messages.default.cellOptions);
|
|
100
|
-
var button = (0, _react2.jsx)("div", {
|
|
101
|
-
css: function css(theme) {
|
|
102
|
-
return [(0, _styles.tableFloatingCellButtonStyles)({
|
|
103
|
-
theme: theme
|
|
104
|
-
}), isContextualMenuOpen && (0, _styles.tableFloatingCellButtonSelectedStyles)({
|
|
105
|
-
theme: theme
|
|
106
|
-
})];
|
|
107
|
-
}
|
|
108
|
-
}, (0, _react2.jsx)(_uiMenu.ToolbarButton, {
|
|
109
|
-
className: _types.TableCssClassName.CONTEXTUAL_MENU_BUTTON,
|
|
110
|
-
selected: isContextualMenuOpen,
|
|
111
|
-
title: labelCellOptions,
|
|
112
|
-
onClick: this.handleClick,
|
|
113
|
-
iconBefore: (0, _react2.jsx)(_chevronDown.default, {
|
|
114
|
-
label: ""
|
|
115
|
-
}),
|
|
116
|
-
"aria-label": labelCellOptions
|
|
117
|
-
}));
|
|
118
|
-
var parentSticky = targetCellRef.parentElement && targetCellRef.parentElement.className.indexOf('sticky') > -1;
|
|
119
|
-
if (this.props.stickyHeader && parentSticky) {
|
|
120
|
-
var pos = targetCellRef.getBoundingClientRect();
|
|
121
|
-
return (0, _react2.jsx)("div", {
|
|
122
|
-
style: {
|
|
123
|
-
position: 'fixed',
|
|
124
|
-
top: this.props.stickyHeader.top + this.props.stickyHeader.padding + 3 + 3,
|
|
125
|
-
zIndex: _editorSharedStyles.akEditorFloatingOverlapPanelZIndex,
|
|
126
|
-
left: pos.left + targetCellRef.clientWidth - 20 - 3
|
|
127
|
-
}
|
|
128
|
-
}, button);
|
|
129
|
-
}
|
|
130
|
-
return (0, _react2.jsx)(_ui.Popup, {
|
|
131
|
-
alignX: "right",
|
|
132
|
-
alignY: "start",
|
|
133
|
-
target: targetCellRef,
|
|
134
|
-
mountTo: tableWrapper || mountPoint,
|
|
135
|
-
boundariesElement: targetCellRef,
|
|
136
|
-
scrollableElement: scrollableElement,
|
|
137
|
-
offset: [3, -3],
|
|
138
|
-
forcePlacement: true,
|
|
139
|
-
allowOutOfBounds: true,
|
|
140
|
-
zIndex: _editorSharedStyles.akEditorSmallZIndex
|
|
141
|
-
}, button);
|
|
142
|
-
}
|
|
143
|
-
}, {
|
|
144
|
-
key: "shouldComponentUpdate",
|
|
145
|
-
value: function shouldComponentUpdate(nextProps) {
|
|
146
|
-
return this.props.tableNode !== nextProps.tableNode || this.props.targetCellPosition !== nextProps.targetCellPosition || this.props.layout !== nextProps.layout || this.props.isContextualMenuOpen !== nextProps.isContextualMenuOpen || this.props.isNumberColumnEnabled !== nextProps.isNumberColumnEnabled || this.props.stickyHeader !== nextProps.stickyHeader;
|
|
54
|
+
var labelCellOptions = formatMessage(_messages.default.cellOptions);
|
|
55
|
+
var button = (0, _react2.jsx)("div", {
|
|
56
|
+
css: function css(theme) {
|
|
57
|
+
return [(0, _styles.tableFloatingCellButtonStyles)({
|
|
58
|
+
theme: theme
|
|
59
|
+
}), isContextualMenuOpen && (0, _styles.tableFloatingCellButtonSelectedStyles)({
|
|
60
|
+
theme: theme
|
|
61
|
+
})];
|
|
147
62
|
}
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
63
|
+
}, (0, _react2.jsx)(_uiMenu.ToolbarButton, {
|
|
64
|
+
className: _types.TableCssClassName.CONTEXTUAL_MENU_BUTTON,
|
|
65
|
+
selected: isContextualMenuOpen,
|
|
66
|
+
title: labelCellOptions,
|
|
67
|
+
onClick: handleClick,
|
|
68
|
+
iconBefore: (0, _react2.jsx)(_chevronDown.default, {
|
|
69
|
+
label: ""
|
|
70
|
+
}),
|
|
71
|
+
"aria-label": labelCellOptions
|
|
72
|
+
}));
|
|
73
|
+
var parentSticky = targetCellRef.parentElement && targetCellRef.parentElement.className.indexOf('sticky') > -1;
|
|
74
|
+
if (stickyHeader && parentSticky && tableWrapper) {
|
|
75
|
+
return (0, _react2.jsx)(_FixedButton.default, {
|
|
76
|
+
offset: BUTTON_OFFSET,
|
|
77
|
+
stickyHeader: stickyHeader,
|
|
78
|
+
tableWrapper: tableWrapper,
|
|
79
|
+
targetCellPosition: targetCellPosition,
|
|
80
|
+
targetCellRef: targetCellRef,
|
|
81
|
+
mountTo: tableWrapper,
|
|
82
|
+
isContextualMenuOpen: isContextualMenuOpen
|
|
83
|
+
}, button);
|
|
84
|
+
}
|
|
85
|
+
return (0, _react2.jsx)(_ui.Popup, {
|
|
86
|
+
alignX: "right",
|
|
87
|
+
alignY: "start",
|
|
88
|
+
target: targetCellRef,
|
|
89
|
+
mountTo: tableWrapper || mountPoint,
|
|
90
|
+
boundariesElement: targetCellRef,
|
|
91
|
+
scrollableElement: scrollableElement,
|
|
92
|
+
offset: [BUTTON_OFFSET, -BUTTON_OFFSET],
|
|
93
|
+
forcePlacement: true,
|
|
94
|
+
allowOutOfBounds: true,
|
|
95
|
+
zIndex: _editorSharedStyles.akEditorSmallZIndex
|
|
96
|
+
}, button);
|
|
97
|
+
});
|
|
153
98
|
var FloatingContextualButton = (0, _reactIntlNext.injectIntl)(FloatingContextualButtonInner);
|
|
154
99
|
function _default(props) {
|
|
155
100
|
return (0, _react2.jsx)(_errorBoundary.ErrorBoundary, {
|
package/dist/cjs/version.json
CHANGED
|
@@ -251,7 +251,8 @@ const tablesPlugin = (options, api) => {
|
|
|
251
251
|
dispatchAnalyticsEvent: dispatchAnalyticsEvent,
|
|
252
252
|
isContextualMenuOpen: isContextualMenuOpen,
|
|
253
253
|
layout: layout,
|
|
254
|
-
stickyHeader: stickyHeader
|
|
254
|
+
stickyHeader: stickyHeader,
|
|
255
|
+
tableWrapper: tableWrapperTarget
|
|
255
256
|
}), allowControls && /*#__PURE__*/React.createElement(FloatingInsertButton, {
|
|
256
257
|
tableNode: tableNode,
|
|
257
258
|
tableRef: tableRef,
|
|
@@ -217,7 +217,8 @@ export class TableRowNodeView {
|
|
|
217
217
|
return;
|
|
218
218
|
}
|
|
219
219
|
const {
|
|
220
|
-
table
|
|
220
|
+
table,
|
|
221
|
+
wrapper
|
|
221
222
|
} = tree;
|
|
222
223
|
|
|
223
224
|
// ED-16035 Make sure sticky header is only applied to first row
|
|
@@ -239,6 +240,7 @@ export class TableRowNodeView {
|
|
|
239
240
|
}
|
|
240
241
|
this.dom.style.top = `${domTop}px`;
|
|
241
242
|
updateTableMargin(table);
|
|
243
|
+
this.dom.scrollLeft = wrapper.scrollLeft;
|
|
242
244
|
this.emitOn(domTop, this.colControlsOffset);
|
|
243
245
|
});
|
|
244
246
|
_defineProperty(this, "makeRowHeaderNotSticky", (table, isEditorDestroyed = false) => {
|
|
@@ -88,6 +88,7 @@ export const TableCssClassName = {
|
|
|
88
88
|
CONTEXTUAL_SUBMENU: `${tablePrefixSelector}-contextual-submenu`,
|
|
89
89
|
CONTEXTUAL_MENU_BUTTON_WRAP: `${tablePrefixSelector}-contextual-menu-button-wrap`,
|
|
90
90
|
CONTEXTUAL_MENU_BUTTON: `${tablePrefixSelector}-contextual-menu-button`,
|
|
91
|
+
CONTEXTUAL_MENU_BUTTON_FIXED: `${tablePrefixSelector}-contextual-menu-button-fixed`,
|
|
91
92
|
CONTEXTUAL_MENU_ICON: `${tablePrefixSelector}-contextual-submenu-icon`,
|
|
92
93
|
// come from prosemirror-table
|
|
93
94
|
SELECTED_CELL: 'selectedCell',
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
import React, { useEffect, useRef } from 'react';
|
|
2
|
+
import { createPortal } from 'react-dom';
|
|
3
|
+
import rafSchedule from 'raf-schd';
|
|
4
|
+
import { akEditorFloatingPanelZIndex } from '@atlaskit/editor-shared-styles';
|
|
5
|
+
import { insertColumnButtonOffset } from '../common-styles';
|
|
6
|
+
import { TableCssClassName as ClassName } from '../../types';
|
|
7
|
+
export const BUTTON_WIDTH = 20;
|
|
8
|
+
export const calcLeftPos = ({
|
|
9
|
+
buttonWidth,
|
|
10
|
+
cellRectLeft,
|
|
11
|
+
cellRefWidth,
|
|
12
|
+
offset
|
|
13
|
+
}) => {
|
|
14
|
+
return cellRectLeft + cellRefWidth - buttonWidth - offset;
|
|
15
|
+
};
|
|
16
|
+
export const calcObserverTargetMargin = (tableWrapper, fixedButtonRefCurrent) => {
|
|
17
|
+
const tableWrapperRect = tableWrapper.getBoundingClientRect();
|
|
18
|
+
const fixedButtonRect = fixedButtonRefCurrent.getBoundingClientRect();
|
|
19
|
+
const scrollLeft = tableWrapper.scrollLeft;
|
|
20
|
+
return fixedButtonRect.left - tableWrapperRect.left + scrollLeft;
|
|
21
|
+
};
|
|
22
|
+
export const FixedButton = ({
|
|
23
|
+
children,
|
|
24
|
+
isContextualMenuOpen,
|
|
25
|
+
mountTo,
|
|
26
|
+
offset,
|
|
27
|
+
stickyHeader,
|
|
28
|
+
tableWrapper,
|
|
29
|
+
targetCellPosition,
|
|
30
|
+
targetCellRef
|
|
31
|
+
}) => {
|
|
32
|
+
const fixedButtonRef = useRef(null);
|
|
33
|
+
const observerTargetRef = useRef(null);
|
|
34
|
+
|
|
35
|
+
// Using refs here rather than state to prevent heaps of renders on scroll
|
|
36
|
+
const scrollDataRef = useRef(0);
|
|
37
|
+
const leftPosDataRef = useRef(0);
|
|
38
|
+
useEffect(() => {
|
|
39
|
+
const observerTargetRefCurrent = observerTargetRef.current;
|
|
40
|
+
const fixedButtonRefCurrent = fixedButtonRef.current;
|
|
41
|
+
if (fixedButtonRefCurrent && observerTargetRefCurrent) {
|
|
42
|
+
scrollDataRef.current = tableWrapper.scrollLeft;
|
|
43
|
+
leftPosDataRef.current = 0;
|
|
44
|
+
// Hide the button initially in case there's a flash of the button being
|
|
45
|
+
// outside the table before the Intersection Observer fires
|
|
46
|
+
fixedButtonRefCurrent.style.visibility = 'hidden';
|
|
47
|
+
const margin = calcObserverTargetMargin(tableWrapper, fixedButtonRefCurrent);
|
|
48
|
+
|
|
49
|
+
// Much more simple and predictable to add this margin to the observer target
|
|
50
|
+
// rather than using it to calculate the rootMargin values
|
|
51
|
+
observerTargetRefCurrent.style.marginLeft = `${margin}px`;
|
|
52
|
+
const observer = new IntersectionObserver(entries => {
|
|
53
|
+
entries.forEach(entry => {
|
|
54
|
+
if (entry.isIntersecting) {
|
|
55
|
+
fixedButtonRefCurrent.style.visibility = 'visible';
|
|
56
|
+
} else {
|
|
57
|
+
fixedButtonRefCurrent.style.visibility = 'hidden';
|
|
58
|
+
}
|
|
59
|
+
});
|
|
60
|
+
}, {
|
|
61
|
+
root: tableWrapper,
|
|
62
|
+
rootMargin: `0px ${insertColumnButtonOffset}px 0px 0px`,
|
|
63
|
+
threshold: 1
|
|
64
|
+
});
|
|
65
|
+
const handleScroll = rafSchedule(event => {
|
|
66
|
+
if (fixedButtonRef.current) {
|
|
67
|
+
const delta = event.target.scrollLeft - scrollDataRef.current;
|
|
68
|
+
const style = `translateX(${leftPosDataRef.current - delta}px)`;
|
|
69
|
+
fixedButtonRef.current.style.transform = style;
|
|
70
|
+
scrollDataRef.current = event.target.scrollLeft;
|
|
71
|
+
leftPosDataRef.current = leftPosDataRef.current - delta;
|
|
72
|
+
}
|
|
73
|
+
});
|
|
74
|
+
observer.observe(observerTargetRefCurrent);
|
|
75
|
+
tableWrapper.addEventListener('scroll', handleScroll);
|
|
76
|
+
return () => {
|
|
77
|
+
tableWrapper.removeEventListener('scroll', handleScroll);
|
|
78
|
+
fixedButtonRefCurrent.style.transform = '';
|
|
79
|
+
observer.unobserve(observerTargetRefCurrent);
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
}, [fixedButtonRef, observerTargetRef, tableWrapper, targetCellPosition, targetCellRef, isContextualMenuOpen]);
|
|
83
|
+
const targetCellRect = targetCellRef.getBoundingClientRect();
|
|
84
|
+
|
|
85
|
+
// Using a portal here to ensure wrapperRef has the tableWrapper as an
|
|
86
|
+
// ancestor. This is required to make the Intersection Observer work.
|
|
87
|
+
return /*#__PURE__*/createPortal(
|
|
88
|
+
/*#__PURE__*/
|
|
89
|
+
// Using observerTargetRef here for our Intersection Observer. There is issues
|
|
90
|
+
// getting the observer to work just using the fixedButtonRef, possible due
|
|
91
|
+
// to using position fixed on this Element, or possibly due to its position
|
|
92
|
+
// being changed on scroll.
|
|
93
|
+
React.createElement("div", {
|
|
94
|
+
ref: observerTargetRef,
|
|
95
|
+
style: {
|
|
96
|
+
position: 'absolute',
|
|
97
|
+
top: '0px',
|
|
98
|
+
left: '0px',
|
|
99
|
+
width: `${BUTTON_WIDTH}px`,
|
|
100
|
+
height: `${BUTTON_WIDTH}px`
|
|
101
|
+
}
|
|
102
|
+
}, /*#__PURE__*/React.createElement("div", {
|
|
103
|
+
ref: fixedButtonRef,
|
|
104
|
+
style: {
|
|
105
|
+
position: 'fixed',
|
|
106
|
+
top: stickyHeader.top + stickyHeader.padding + offset * 2,
|
|
107
|
+
zIndex: akEditorFloatingPanelZIndex,
|
|
108
|
+
left: calcLeftPos({
|
|
109
|
+
buttonWidth: BUTTON_WIDTH,
|
|
110
|
+
cellRectLeft: targetCellRect.left,
|
|
111
|
+
cellRefWidth: targetCellRef.clientWidth,
|
|
112
|
+
offset
|
|
113
|
+
}),
|
|
114
|
+
width: `${BUTTON_WIDTH}px`,
|
|
115
|
+
height: `${BUTTON_WIDTH}px`
|
|
116
|
+
},
|
|
117
|
+
className: ClassName.CONTEXTUAL_MENU_BUTTON_FIXED
|
|
118
|
+
}, children)), mountTo);
|
|
119
|
+
};
|
|
120
|
+
export default FixedButton;
|