@atlaskit/editor-plugin-table
Version:
Table plugin for the @atlaskit/editor
155 lines (151 loc) • 8.41 kB
JavaScript
;
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;