phx-react
Version:
PHX REACT
165 lines • 7.36 kB
JavaScript
"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