UNPKG

phx-react

Version:

PHX REACT

165 lines • 7.36 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.default = PreserveFontSizeOnEnterPlugin; const LexicalComposerContext_1 = require("@lexical/react/LexicalComposerContext"); const lexical_1 = require("lexical"); const list_1 = require("@lexical/list"); const selection_1 = require("@lexical/selection"); const react_1 = require("react"); /** * Extracts font size from a CSS style string. * @param style CSS style text to parse. * @returns Font size value, or an empty string when absent. */ function getFontSizeFromStyle(style) { var _a; return ((_a = (0, selection_1.getStyleObjectFromCSS)(style)) === null || _a === void 0 ? void 0 : _a['font-size']) || ''; } /** * Gets the font size that should be preserved for a collapsed selection. * @returns Font size value, or an empty string when no font size is available. */ function getCollapsedSelectionFontSize() { const selection = (0, lexical_1.$getSelection)(); if (!(0, lexical_1.$isRangeSelection)(selection) || !selection.isCollapsed()) { return ''; } const selectionFontSize = (0, selection_1.$getSelectionStyleValueForProperty)(selection, 'font-size', ''); if (selectionFontSize) { return selectionFontSize; } const anchor = selection.anchor; const anchorNode = anchor.getNode(); if ((0, lexical_1.$isTextNode)(anchorNode)) { return getFontSizeFromStyle(anchorNode.getStyle()); } if ((0, lexical_1.$isElementNode)(anchorNode)) { const previousNode = anchor.offset > 0 ? anchorNode.getChildAtIndex(anchor.offset - 1) : null; const nextNode = anchorNode.getChildAtIndex(anchor.offset); if ((0, lexical_1.$isTextNode)(previousNode)) { return getFontSizeFromStyle(previousNode.getStyle()); } if ((0, lexical_1.$isTextNode)(nextNode)) { return getFontSizeFromStyle(nextNode.getStyle()); } } return ''; } /** * Checks whether the current selection is inside an empty list item. * @returns True when the collapsed selection is in an empty list item. */ function isSelectionInEmptyListItem() { const selection = (0, lexical_1.$getSelection)(); if (!(0, lexical_1.$isRangeSelection)(selection) || !selection.isCollapsed()) { return false; } const anchorNode = selection.anchor.getNode(); if ((0, list_1.$isListItemNode)(anchorNode) && anchorNode.getChildrenSize() === 0) { return true; } if (!(0, lexical_1.$isTextNode)(anchorNode)) { return false; } const parent = anchorNode.getParent(); return ((0, list_1.$isListItemNode)(parent) && parent.getChildren().every((node) => (0, lexical_1.$isTextNode)(node) && node.getTextContent().trim() === '')); } /** * Syncs the inserted block and collapsed selection to a font size after Lexical handles list exit. * @param editor Active Lexical editor. * @param fontSize Font size that should drive the next caret height. */ function syncListExitFontSize(editor, fontSize) { const applyFontSize = () => { editor.update(() => { const selection = (0, lexical_1.$getSelection)(); if (!(0, lexical_1.$isRangeSelection)(selection) || !selection.isCollapsed()) { return; } const anchorNode = selection.anchor.getNode(); const targetNode = (0, lexical_1.$isElementNode)(anchorNode) ? anchorNode : (0, lexical_1.$isTextNode)(anchorNode) ? anchorNode.getTopLevelElement() : null; if (!(0, lexical_1.$isElementNode)(targetNode)) { return; } const targetNodeKey = targetNode.getKey(); const blockStyles = (0, selection_1.getStyleObjectFromCSS)(targetNode.getStyle()); const fontSizeStyle = (0, selection_1.getCSSFromStyleObject)({ 'font-size': fontSize }); targetNode.setStyle((0, selection_1.getCSSFromStyleObject)({ ...blockStyles, 'font-size': fontSize, })); targetNode.setTextStyle(fontSizeStyle); (0, selection_1.$patchStyleText)(selection, { 'font-size': fontSize, }); const applyFontSizeToElement = () => { const targetElement = editor.getElementByKey(targetNodeKey); targetElement === null || targetElement === void 0 ? void 0 : targetElement.style.setProperty('font-size', fontSize); }; if (typeof queueMicrotask === 'function') { queueMicrotask(applyFontSizeToElement); } requestAnimationFrame(applyFontSizeToElement); }); }; if (typeof queueMicrotask === 'function') { queueMicrotask(applyFontSize); } else { setTimeout(applyFontSize); } } /** * Preserves font size when inserting a paragraph with Enter. * @returns Null because the plugin renders no UI. */ function PreserveFontSizeOnEnterPlugin() { const [editor] = (0, LexicalComposerContext_1.useLexicalComposerContext)(); (0, react_1.useEffect)(() => { return editor.registerCommand(lexical_1.INSERT_PARAGRAPH_COMMAND, () => { const selection = (0, lexical_1.$getSelection)(); const fontSize = getCollapsedSelectionFontSize(); if (!(0, lexical_1.$isRangeSelection)(selection) || !selection.isCollapsed() || !fontSize) { return false; } if (isSelectionInEmptyListItem()) { syncListExitFontSize(editor, fontSize); return false; } const insertedBlock = selection.insertParagraph(); if ((0, lexical_1.$isElementNode)(insertedBlock)) { const insertedBlockKey = insertedBlock.getKey(); const blockStyles = (0, selection_1.getStyleObjectFromCSS)(insertedBlock.getStyle()); const fontSizeStyle = (0, selection_1.getCSSFromStyleObject)({ 'font-size': fontSize }); insertedBlock.setStyle((0, selection_1.getCSSFromStyleObject)({ ...blockStyles, 'font-size': fontSize, })); insertedBlock.setTextStyle(fontSizeStyle); insertedBlock.selectStart(); const applyFontSizeToInsertedElement = () => { const insertedElement = editor.getElementByKey(insertedBlockKey); insertedElement === null || insertedElement === void 0 ? void 0 : insertedElement.style.setProperty('font-size', fontSize); }; if (typeof queueMicrotask === 'function') { queueMicrotask(applyFontSizeToInsertedElement); } requestAnimationFrame(applyFontSizeToInsertedElement); } const nextSelection = (0, lexical_1.$getSelection)(); if ((0, lexical_1.$isRangeSelection)(nextSelection) && nextSelection.isCollapsed()) { (0, selection_1.$patchStyleText)(nextSelection, { 'font-size': fontSize, }); } return true; }, lexical_1.COMMAND_PRIORITY_CRITICAL); }, [editor]); return null; } //# sourceMappingURL=index.js.map