@lobehub/editor
Version:
A powerful and extensible rich text editor built on Meta's Lexical framework, providing a modern editing experience with React integration.
177 lines (173 loc) • 8.79 kB
JavaScript
function _slicedToArray(arr, i) { return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _unsupportedIterableToArray(arr, i) || _nonIterableRest(); }
function _nonIterableRest() { throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); }
function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); }
function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) arr2[i] = arr[i]; return arr2; }
function _iterableToArrayLimit(r, l) { var t = null == r ? null : "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; if (null != t) { var e, n, i, u, a = [], f = !0, o = !1; try { if (i = (t = t.call(r)).next, 0 === l) { if (Object(t) !== t) return; f = !1; } else for (; !(f = (e = i.call(t)).done) && (a.push(e.value), a.length !== l); f = !0); } catch (r) { o = !0, n = r; } finally { try { if (!f && null != t.return && (u = t.return(), Object(u) !== u)) return; } finally { if (o) throw n; } } return a; } }
function _arrayWithHoles(arr) { if (Array.isArray(arr)) return arr; }
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
*/
import { $getTableCellNodeFromLexicalNode, $getTableNodeFromLexicalNodeOrThrow, $isTableCellNode, $isTableSelection, getTableElement, getTableObserverFromTableElement } from '@lexical/table';
import { mergeRegister } from '@lexical/utils';
import { ActionIcon } from '@lobehub/ui';
import { $getSelection, $isRangeSelection, COMMAND_PRIORITY_CRITICAL, SELECTION_CHANGE_COMMAND, getDOMSelection } from 'lexical';
import { ChevronDown } from 'lucide-react';
import { memo, useCallback, useEffect, useRef, useState } from 'react';
import { useAnchor } from "../../../../editor-kernel/react/useAnchor";
import { cleanPosition, updatePosition } from "../../../../utils/updatePosition";
import ActionMenu from "./ActionMenu";
import { styles } from "./style";
import { jsx as _jsx } from "react/jsx-runtime";
var TableActionMenu = /*#__PURE__*/memo(function (_ref) {
var cellMerge = _ref.cellMerge,
editor = _ref.editor;
var anchorElem = useAnchor();
var menuButtonRef = useRef(null);
var _useState = useState(null),
_useState2 = _slicedToArray(_useState, 2),
tableCellNode = _useState2[0],
setTableMenuCellNode = _useState2[1];
// const [colorPickerModal, showColorPickerModal] = useModal();
var checkTableCellOverflow = useCallback(function (tableCellParentNodeDOM) {
var scrollableContainer = tableCellParentNodeDOM.closest('.PlaygroundEditorTheme__tableScrollableWrapper');
if (scrollableContainer) {
var containerRect = scrollableContainer.getBoundingClientRect();
var cellRect = tableCellParentNodeDOM.getBoundingClientRect();
// Calculate where the action button would be positioned (5px from right edge of cell)
// Also account for the button width and table cell padding (8px)
var actionButtonRight = cellRect.right - 5;
var actionButtonLeft = actionButtonRight - 28; // 20px width + 8px padding
// Only hide if the action button would overflow the container
if (actionButtonRight > containerRect.right || actionButtonLeft < containerRect.left) {
return true;
}
}
return false;
}, []);
var $moveMenu = useCallback(function () {
var menu = menuButtonRef.current;
var selection = $getSelection();
var nativeSelection = getDOMSelection(editor._window);
var activeElement = typeof document !== 'undefined' ? document.activeElement : null;
function disable() {
if (menu) {
menu.classList.remove('table-cell-action-button-container--active');
menu.classList.add('table-cell-action-button-container--inactive');
}
setTableMenuCellNode(null);
}
if (!selection || !menu) {
return disable();
}
var rootElement = editor.getRootElement();
var tableObserver = null;
var tableCellParentNodeDOM = null;
if ($isRangeSelection(selection) && rootElement !== null && nativeSelection !== null && rootElement.contains(nativeSelection.anchorNode)) {
var tableCellNodeFromSelection = $getTableCellNodeFromLexicalNode(selection.anchor.getNode());
if (!tableCellNodeFromSelection) {
return disable();
}
tableCellParentNodeDOM = editor.getElementByKey(tableCellNodeFromSelection.getKey());
if (!tableCellParentNodeDOM || !tableCellNodeFromSelection.isAttached()) {
return disable();
}
if (checkTableCellOverflow(tableCellParentNodeDOM)) {
return disable();
}
var tableNode = $getTableNodeFromLexicalNodeOrThrow(tableCellNodeFromSelection);
var tableElement = getTableElement(tableNode, editor.getElementByKey(tableNode.getKey()));
if (tableElement === null) {
throw new Error('TableActionMenu: Expected to find tableElement in DOM');
}
tableObserver = getTableObserverFromTableElement(tableElement);
setTableMenuCellNode(tableCellNodeFromSelection);
} else if ($isTableSelection(selection)) {
var anchorNode = $getTableCellNodeFromLexicalNode(selection.anchor.getNode());
if (!$isTableCellNode(anchorNode)) {
throw new Error('TableSelection anchorNode must be a TableCellNode');
}
var _tableNode = $getTableNodeFromLexicalNodeOrThrow(anchorNode);
var _tableElement = getTableElement(_tableNode, editor.getElementByKey(_tableNode.getKey()));
if (_tableElement === null) {
throw new Error('TableActionMenu: Expected to find tableElement in DOM');
}
tableObserver = getTableObserverFromTableElement(_tableElement);
tableCellParentNodeDOM = editor.getElementByKey(anchorNode.getKey());
if (tableCellParentNodeDOM === null) {
return disable();
}
if (checkTableCellOverflow(tableCellParentNodeDOM)) {
return disable();
}
} else if (!activeElement) {
return disable();
}
if (tableObserver === null || tableCellParentNodeDOM === null) {
return disable();
}
var enabled = !tableObserver || !tableObserver.isSelecting;
menu.classList.toggle('table-cell-action-button-container--active', enabled);
menu.classList.toggle('table-cell-action-button-container--inactive', !enabled);
if (enabled) {
updatePosition({
floating: menu,
offset: 0,
placement: 'top-end',
reference: tableCellParentNodeDOM
});
} else {
cleanPosition(menu);
}
}, [editor, anchorElem, checkTableCellOverflow]);
useEffect(function () {
// We call the $moveMenu callback every time the selection changes,
// once up front, and once after each pointerUp
var timeoutId = undefined;
var callback = function callback() {
timeoutId = undefined;
editor.getEditorState().read($moveMenu);
};
var delayedCallback = function delayedCallback() {
if (timeoutId === undefined) {
timeoutId = setTimeout(callback, 0);
}
return false;
};
return mergeRegister(editor.registerUpdateListener(delayedCallback), editor.registerCommand(SELECTION_CHANGE_COMMAND, delayedCallback, COMMAND_PRIORITY_CRITICAL), editor.registerRootListener(function (rootElement, prevRootElement) {
if (prevRootElement) {
prevRootElement.removeEventListener('pointerup', delayedCallback);
}
if (rootElement) {
rootElement.addEventListener('pointerup', delayedCallback);
delayedCallback();
}
}), function () {
return clearTimeout(timeoutId);
});
});
var prevTableCellDOM = useRef(tableCellNode);
useEffect(function () {
prevTableCellDOM.current = tableCellNode;
}, [prevTableCellDOM, tableCellNode]);
return /*#__PURE__*/_jsx("div", {
className: styles.root,
ref: menuButtonRef,
children: tableCellNode && /*#__PURE__*/_jsx(ActionMenu, {
cellMerge: cellMerge,
editor: editor,
tableCellNode: tableCellNode,
children: /*#__PURE__*/_jsx(ActionIcon, {
className: styles.actionIcon,
glass: true,
icon: ChevronDown,
size: 12,
variant: 'filled'
})
})
});
});
export default TableActionMenu;