UNPKG

@selfcommunity/react-ui

Version:

React UI Components to integrate a Community created with SelfCommunity Platform.

142 lines (141 loc) • 6.67 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); const tslib_1 = require("tslib"); const jsx_runtime_1 = require("react/jsx-runtime"); const link_1 = require("@lexical/link"); const LexicalComposerContext_1 = require("@lexical/react/LexicalComposerContext"); const utils_1 = require("@lexical/utils"); const lexical_1 = require("lexical"); const react_1 = require("react"); const editor_1 = require("../../../utils/editor"); const utils_2 = require("@selfcommunity/utils"); const styles_1 = require("@mui/material/styles"); const material_1 = require("@mui/material"); const Icon_1 = tslib_1.__importDefault(require("@mui/material/Icon")); const constants_1 = require("../constants"); const classes = { root: `${constants_1.PREFIX}-floating-link-plugin-root` }; const Root = (0, styles_1.styled)(material_1.Popper, { name: constants_1.PREFIX, slot: 'FloatingLinkPluginRoot' })(() => ({})); function FloatingLinkPlugin({ editor, isLink, setIsLink }) { const [anchorEl, setAnchorEl] = (0, react_1.useState)(null); const [linkUrl, setLinkUrl] = (0, react_1.useState)(''); const [hideForUrl, setHideForUrl] = (0, react_1.useState)(null); const [lastSelection, setLastSelection] = (0, react_1.useState)(null); const updateLinkEditor = (0, react_1.useCallback)(() => { var _a; const selection = (0, lexical_1.$getSelection)(); if ((0, lexical_1.$isRangeSelection)(selection)) { const node = (0, editor_1.getSelectedNode)(selection); const parent = node.getParent(); if ((0, link_1.$isLinkNode)(parent)) { setLinkUrl(parent.getURL()); } else if ((0, link_1.$isLinkNode)(node)) { setLinkUrl(node.getURL()); } else { setLinkUrl(''); } } const nativeSelection = window.getSelection(); const activeElement = document.activeElement; const rootElement = editor.getRootElement(); if (selection !== null && nativeSelection !== null && rootElement !== null && rootElement.contains(nativeSelection.anchorNode) && editor.isEditable()) { setAnchorEl((_a = nativeSelection.focusNode) === null || _a === void 0 ? void 0 : _a.parentElement); setLastSelection(selection); } else if (!activeElement) { setAnchorEl(null); setLastSelection(null); setLinkUrl(''); } return true; }, [editor]); (0, react_1.useEffect)(() => { if (linkUrl != hideForUrl) { setHideForUrl(null); } }, [linkUrl]); (0, react_1.useEffect)(() => { return (0, utils_1.mergeRegister)(editor.registerUpdateListener(({ editorState }) => { editorState.read(() => { updateLinkEditor(); }); }), editor.registerCommand(lexical_1.SELECTION_CHANGE_COMMAND, () => { updateLinkEditor(); return true; }, lexical_1.COMMAND_PRIORITY_LOW), editor.registerCommand(lexical_1.KEY_ESCAPE_COMMAND, () => { if (isLink) { setIsLink(false); return true; } return false; }, lexical_1.COMMAND_PRIORITY_HIGH)); }, [editor, updateLinkEditor, setIsLink, isLink]); (0, react_1.useEffect)(() => { editor.getEditorState().read(() => { updateLinkEditor(); }); }, [editor, updateLinkEditor]); const handleLinkSubmission = () => { if (lastSelection !== null) { if (linkUrl !== '') { setHideForUrl(linkUrl); editor.dispatchCommand(link_1.TOGGLE_LINK_COMMAND, (0, utils_2.isValidUrl)(linkUrl) ? linkUrl : 'https://'); } } }; if (!isLink || linkUrl === hideForUrl) { return null; } return ((0, jsx_runtime_1.jsx)(Root, Object.assign({ className: classes.root, open: Boolean(anchorEl), anchorEl: anchorEl, placement: "right" }, { children: (0, jsx_runtime_1.jsx)(material_1.Paper, { children: (0, jsx_runtime_1.jsx)(material_1.TextField, { size: "small", value: linkUrl, variant: "outlined", onChange: (event) => { setLinkUrl(event.target.value); }, InputProps: { endAdornment: ((0, jsx_runtime_1.jsxs)(material_1.InputAdornment, Object.assign({ position: "end" }, { children: [(0, jsx_runtime_1.jsx)(material_1.IconButton, Object.assign({ size: "small", tabIndex: 0, onClick: () => { setIsLink(false); } }, { children: (0, jsx_runtime_1.jsx)(Icon_1.default, { children: "close" }) })), (0, jsx_runtime_1.jsx)(material_1.IconButton, Object.assign({ size: "small", tabIndex: 1, onClick: handleLinkSubmission }, { children: (0, jsx_runtime_1.jsx)(Icon_1.default, { children: "check" }) }))] }))) } }) }) }))); } function useFloatingLinkEditorToolbar(editor) { const [activeEditor, setActiveEditor] = (0, react_1.useState)(editor); const [isLink, setIsLink] = (0, react_1.useState)(false); const updateToolbar = (0, react_1.useCallback)(() => { const selection = (0, lexical_1.$getSelection)(); if ((0, lexical_1.$isRangeSelection)(selection)) { const node = (0, editor_1.getSelectedNode)(selection); const linkParent = (0, utils_1.$findMatchingParent)(node, link_1.$isLinkNode); const autoLinkParent = (0, utils_1.$findMatchingParent)(node, link_1.$isAutoLinkNode); // We don't want this menu to open for auto links. if (linkParent != null && autoLinkParent == null) { setIsLink(true); } else { setIsLink(false); } } }, []); (0, react_1.useEffect)(() => { return (0, utils_1.mergeRegister)(editor.registerUpdateListener(({ editorState }) => { editorState.read(() => { updateToolbar(); }); }), editor.registerCommand(lexical_1.SELECTION_CHANGE_COMMAND, (_payload, newEditor) => { updateToolbar(); setActiveEditor(newEditor); return false; }, lexical_1.COMMAND_PRIORITY_CRITICAL)); }, [editor, updateToolbar]); return (0, jsx_runtime_1.jsx)(FloatingLinkPlugin, { editor: activeEditor, isLink: isLink, setIsLink: setIsLink }); } exports.default = () => { const [editor] = (0, LexicalComposerContext_1.useLexicalComposerContext)(); return useFloatingLinkEditorToolbar(editor); };