UNPKG

@atlaskit/editor-plugin-table

Version:

Table plugin for the @atlaskit/editor

155 lines (151 loc) 8.41 kB
"use strict"; var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault"); var _typeof = require("@babel/runtime/helpers/typeof"); Object.defineProperty(exports, "__esModule", { value: true }); exports.default = exports.calcObserverTargetMargin = exports.calcLeftPos = exports.FixedButton = void 0; var _react = _interopRequireWildcard(require("react")); var _rafSchd = _interopRequireDefault(require("raf-schd")); var _reactDom = require("react-dom"); var _editorSharedStyles = require("@atlaskit/editor-shared-styles"); var _types = require("../../types"); var _commonStyles = require("../common-styles"); function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function _interopRequireWildcard(e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != _typeof(e) && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (var _t in e) "default" !== _t && {}.hasOwnProperty.call(e, _t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, _t)) && (i.get || i.set) ? o(f, _t, i) : f[_t] = e[_t]); return f; })(e, t); } var BUTTON_WIDTH = 20; var calcLeftPos = exports.calcLeftPos = function calcLeftPos(_ref) { var buttonWidth = _ref.buttonWidth, cellRectLeft = _ref.cellRectLeft, cellRefWidth = _ref.cellRefWidth, offset = _ref.offset; return cellRectLeft + cellRefWidth - buttonWidth - offset; }; var calcObserverTargetMargin = exports.calcObserverTargetMargin = function calcObserverTargetMargin(tableWrapper, fixedButtonRefCurrent) { var tableWrapperRect = tableWrapper.getBoundingClientRect(); var fixedButtonRect = fixedButtonRefCurrent.getBoundingClientRect(); var scrollLeft = tableWrapper.scrollLeft; return fixedButtonRect.left - tableWrapperRect.left + scrollLeft; }; var FixedButton = exports.FixedButton = function FixedButton(_ref2) { var children = _ref2.children, isContextualMenuOpen = _ref2.isContextualMenuOpen, mountTo = _ref2.mountTo, offset = _ref2.offset, stickyHeader = _ref2.stickyHeader, tableWrapper = _ref2.tableWrapper, targetCellPosition = _ref2.targetCellPosition, targetCellRef = _ref2.targetCellRef; var fixedButtonRef = (0, _react.useRef)(null); var observerTargetRef = (0, _react.useRef)(null); // Using refs here rather than state to prevent heaps of renders on scroll var scrollDataRef = (0, _react.useRef)(0); var leftPosDataRef = (0, _react.useRef)(0); (0, _react.useEffect)(function () { var observerTargetRefCurrent = observerTargetRef.current; var fixedButtonRefCurrent = fixedButtonRef.current; if (fixedButtonRefCurrent && observerTargetRefCurrent) { scrollDataRef.current = tableWrapper.scrollLeft; leftPosDataRef.current = 0; // Hide the button initially in case there's a flash of the button being // outside the table before the Intersection Observer fires fixedButtonRefCurrent.style.visibility = 'hidden'; var margin = calcObserverTargetMargin(tableWrapper, fixedButtonRefCurrent); // Much more simple and predictable to add this margin to the observer target // rather than using it to calculate the rootMargin values observerTargetRefCurrent.style.marginLeft = "".concat(margin, "px"); var observer = new IntersectionObserver(function (entries) { entries.forEach(function (entry) { if (entry.isIntersecting) { fixedButtonRefCurrent.style.visibility = 'visible'; } else { fixedButtonRefCurrent.style.visibility = 'hidden'; } }); }, { root: tableWrapper, rootMargin: "0px ".concat(_commonStyles.insertColumnButtonOffset, "px 0px 0px"), threshold: 1 }); var handleScroll = (0, _rafSchd.default)(function (event) { if (fixedButtonRef.current) { var delta = event.target.scrollLeft - scrollDataRef.current; var style = "translateX(".concat(leftPosDataRef.current - delta, "px)"); fixedButtonRef.current.style.transform = style; scrollDataRef.current = event.target.scrollLeft; leftPosDataRef.current = leftPosDataRef.current - delta; } }); observer.observe(observerTargetRefCurrent); // Ignored via go/ees005 // eslint-disable-next-line @repo/internal/dom-events/no-unsafe-event-listeners tableWrapper.addEventListener('scroll', handleScroll); return function () { // Ignored via go/ees005 // eslint-disable-next-line @repo/internal/dom-events/no-unsafe-event-listeners tableWrapper.removeEventListener('scroll', handleScroll); fixedButtonRefCurrent.style.transform = ''; observer.unobserve(observerTargetRefCurrent); }; } }, [fixedButtonRef, observerTargetRef, tableWrapper, targetCellPosition, targetCellRef, isContextualMenuOpen]); var fixedButtonTop = 0; var containerLeft = (0, _react.useMemo)(function () { var container = targetCellRef.closest('[data-editor-container="true"]'); return (container === null || container === void 0 ? void 0 : container.getBoundingClientRect().left) || 0; }, [targetCellRef]); var left = (0, _react.useMemo)(function () { var targetCellRect = targetCellRef.getBoundingClientRect(); var baseLeft = calcLeftPos({ buttonWidth: BUTTON_WIDTH, cellRectLeft: targetCellRect.left, cellRefWidth: targetCellRef.clientWidth, offset: offset }); return baseLeft - containerLeft; }, [containerLeft, targetCellRef, offset]); // Using a portal here to ensure wrapperRef has the tableWrapper as an // ancestor. This is required to make the Intersection Observer work. return /*#__PURE__*/(0, _reactDom.createPortal)( /*#__PURE__*/ // Using observerTargetRef here for our Intersection Observer. There is issues // getting the observer to work just using the fixedButtonRef, possible due // to using position fixed on this Element, or possibly due to its position // being changed on scroll. _react.default.createElement("div", { ref: observerTargetRef, style: { // eslint-disable-next-line @atlaskit/ui-styling-standard/enforce-style-prop -- Ignored via go/DSP-18766 position: 'absolute', // eslint-disable-next-line @atlaskit/ui-styling-standard/enforce-style-prop -- Ignored via go/DSP-18766 top: "var(--ds-space-0, 0px)", // eslint-disable-next-line @atlaskit/ui-styling-standard/enforce-style-prop -- Ignored via go/DSP-18766 left: "var(--ds-space-0, 0px)", // eslint-disable-next-line @atlaskit/ui-styling-standard/enforce-style-prop -- Ignored via go/DSP-18766 width: "var(--ds-space-250, 20px)", // BUTTON_WIDTH // eslint-disable-next-line @atlaskit/ui-styling-standard/enforce-style-prop -- Ignored via go/DSP-18766 height: "var(--ds-space-250, 20px)" // BUTTON_WIDTH } }, /*#__PURE__*/_react.default.createElement("div", { ref: fixedButtonRef, style: { // eslint-disable-next-line @atlaskit/ui-styling-standard/enforce-style-prop -- Ignored via go/DSP-18766 position: 'fixed', // eslint-disable-next-line @atlaskit/design-system/ensure-design-token-usage/preview top: fixedButtonTop + stickyHeader.padding + offset * 2, // eslint-disable-next-line @atlaskit/ui-styling-standard/enforce-style-prop, @atlaskit/ui-styling-standard/no-imported-style-values -- Ignored via go/DSP-18766 zIndex: _editorSharedStyles.akEditorTableCellOnStickyHeaderZIndex, // eslint-disable-next-line @atlaskit/design-system/ensure-design-token-usage/preview left: left, // eslint-disable-next-line @atlaskit/ui-styling-standard/enforce-style-prop -- Ignored via go/DSP-18766 width: "var(--ds-space-250, 20px)", // BUTTON_WIDTH // eslint-disable-next-line @atlaskit/ui-styling-standard/enforce-style-prop -- Ignored via go/DSP-18766 height: "var(--ds-space-250, 20px)" // BUTTON_WIDTH } // eslint-disable-next-line @atlaskit/ui-styling-standard/no-classname-prop -- Ignored via go/DSP-18766 , className: _types.TableCssClassName.CONTEXTUAL_MENU_BUTTON_FIXED }, children)), mountTo); }; var _default = exports.default = FixedButton;