@slesaad/veda-content-editor
Version:
VEDA Content Editor - A React-based MDX editor component
1,367 lines (1,305 loc) • 4.63 MB
JavaScript
'use strict';
var require$$1 = require('react/jsx-runtime');
var React__default = require('react');
var vedaUi = require('@teamimpact/veda-ui');
var reactRouterDom = require('react-router-dom');
var themeProvider = require('@devseed-ui/theme-provider');
var ReactDOM = require('react-dom');
var reactUswds = require('@trussworks/react-uswds');
var require$$0$1 = require('react/jsx-dev-runtime');
var require$$0$2 = require('os');
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
function _interopNamespace(e) {
if (e && e.__esModule) return e;
var n = Object.create(null);
if (e) {
Object.keys(e).forEach(function (k) {
if (k !== 'default') {
var d = Object.getOwnPropertyDescriptor(e, k);
Object.defineProperty(n, k, d.get ? d : {
enumerable: true,
get: function () { return e[k]; }
});
}
});
}
n.default = e;
return Object.freeze(n);
}
var require$$1__default = /*#__PURE__*/_interopDefault(require$$1);
var React__default__namespace = /*#__PURE__*/_interopNamespace(React__default);
var ReactDOM__namespace = /*#__PURE__*/_interopNamespace(ReactDOM);
var require$$0__default = /*#__PURE__*/_interopDefault(require$$0$1);
var require$$0__default$1 = /*#__PURE__*/_interopDefault(require$$0$2);
const DataContext = React__default.createContext({});
// @TODO: Decided how to handle function as mapLabel from VEDA UI
// https://github.com/NASA-IMPACT/veda-ui/issues/1377
function updateMapLabels(data) {
return data.map((dataset) => {
if (dataset.metadata && dataset.metadata.layers) {
dataset.metadata.layers.forEach((layer) => {
if (layer.mapLabel && typeof layer.mapLabel === 'string') {
// Instead of eval, we'll keep it as a string
// The consuming code should handle the function creation if needed
// This is safer and avoids eval() security issues
console.warn('mapLabel as string functions are not automatically evaluated for security reasons');
}
if (layer.compare && layer.compare.mapLabel && typeof layer.compare.mapLabel === 'string') {
console.warn('compare.mapLabel as string functions are not automatically evaluated for security reasons');
}
});
}
return dataset;
});
}
function DataProvider({ initialDatasets = undefined, children, }) {
const [datasets, setDatasets] = React__default.useState(updateMapLabels(initialDatasets));
const value = {
datasets,
setDatasets,
};
return (require$$1.jsx(DataContext.Provider, { value: value, children: require$$1.jsx(vedaUi.ReactQueryProvider, { children: children }) }));
}
function VedaUIConfigProvider({ children }) {
const VedaUIProviderComponent = vedaUi.VedaUIProvider;
return (require$$1.jsx(VedaUIProviderComponent, { config: {
envMapboxToken: process.env.NEXT_PUBLIC_MAPBOX_TOKEN ?? '',
envApiStacEndpoint: process.env.NEXT_PUBLIC_API_STAC_ENDPOINT ?? '',
envApiRasterEndpoint: process.env.NEXT_PUBLIC_API_RASTER_ENDPOINT ?? '',
navigation: {
LinkComponent: reactRouterDom.Link,
linkProps: {
pathAttributeKeyName: 'href',
},
},
}, children: children }));
}
// Values here should be manually synced until we consolidate all the styles to USWDS
// Be mindful that these values are used more for VEDA UI component, not for instance
// Use this page to look up the value: https://designsystem.digital.gov/design-tokens/color/system-tokens/
const VEDA_OVERRIDE_THEME = {
zIndices: {
hide: -1,
docked: 10,
sticky: 900,
dropdown: 1550,
overlay: 1300,
modal: 1400,
popover: 1500,
skipLink: 1600,
toast: 1700,
tooltip: 1800,
},
color: {
base: '#2c3e50',
primary: '#d83933',
link: '#6f3331',
danger: '#FC3D21',
infographicA: '#fcab10',
infographicB: '#f4442e',
infographicC: '#b62b6e',
infographicD: '#2ca58d',
infographicE: '#2276ac',
},
type: {
base: {
leadSize: '1.25rem',
extrabold: '800',
line: 'inherit',
// Increments to the type.base.size for each media breakpoint.
sizeIncrement: {
small: '0rem',
medium: '0rem',
large: '0.25rem',
xlarge: '0.25rem',
},
},
heading: {
settings: '"wdth" 100, "wght" 700',
},
},
layout: {
min: '384px',
max: '1440px',
glspMultiplier: {
xsmall: 1,
small: 1,
medium: 1.5,
large: 2,
xlarge: 2,
},
},
};
function DevseedUIThemeProvider({ children, }) {
return (require$$1.jsx(vedaUi.DevseedUiThemeProvider, { theme: themeProvider.createUITheme(VEDA_OVERRIDE_THEME), children: children }));
}
function Providers({ datasets, children }) {
return (require$$1.jsx(DevseedUIThemeProvider, { children: require$$1.jsx(VedaUIConfigProvider, { children: datasets ? (require$$1.jsx(DataProvider, { initialDatasets: datasets, children: children })) : (children) }) }));
}
/**
* 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.
*
*/
/**
* 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.
*
*/
const LexicalComposerContext$3 = /*#__PURE__*/React__default.createContext(null);
function createLexicalComposerContext$3(parent, theme) {
let parentContext = null;
if (parent != null) {
parentContext = parent[1];
}
function getTheme() {
if (theme != null) {
return theme;
}
return parentContext != null ? parentContext.getTheme() : null;
}
return {
getTheme
};
}
function useLexicalComposerContext$3() {
const composerContext = React__default.useContext(LexicalComposerContext$3);
if (composerContext == null) {
{
throw Error(`LexicalComposerContext.useLexicalComposerContext: cannot find a LexicalComposerContext`);
}
}
return composerContext;
}
var modDev$w = /*#__PURE__*/Object.freeze({
__proto__: null,
LexicalComposerContext: LexicalComposerContext$3,
createLexicalComposerContext: createLexicalComposerContext$3,
useLexicalComposerContext: useLexicalComposerContext$3
});
/**
* 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.
*
*/
function r$3(e){return e&&e.__esModule&&Object.prototype.hasOwnProperty.call(e,"default")?e.default:e}var t$5=r$3((function(e){const n=new URLSearchParams;n.append("code",e);for(let e=1;e<arguments.length;e++)n.append("v",arguments[e]);throw Error(`Minified Lexical error #${e}; visit https://lexical.dev/docs/error?${n} for the full message or use the non-minified dev environment for full errors and additional helpful warnings.`)}));const l$4=React__default.createContext(null);function o$7(e,n){let r=null;return null!=e&&(r=e[1]),{getTheme:function(){return null!=n?n:null!=r?r.getTheme():null}}}function u$6(){const e=React__default.useContext(l$4);return null==e&&t$5(8),e}
var modProd$w = /*#__PURE__*/Object.freeze({
__proto__: null,
LexicalComposerContext: l$4,
createLexicalComposerContext: o$7,
useLexicalComposerContext: u$6
});
/**
* 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.
*
*/
const mod$w = process.env.NODE_ENV === 'development' ? modDev$w : modProd$w;
const LexicalComposerContext$2 = mod$w.LexicalComposerContext;
const createLexicalComposerContext$2 = mod$w.createLexicalComposerContext;
const useLexicalComposerContext$2 = mod$w.useLexicalComposerContext;
/**
* 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.
*
*/
/**
* 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.
*
*/
function createCommand$2(type) {
return {
type
} ;
}
const SELECTION_CHANGE_COMMAND$2 = createCommand$2('SELECTION_CHANGE_COMMAND');
const SELECTION_INSERT_CLIPBOARD_NODES_COMMAND$2 = createCommand$2('SELECTION_INSERT_CLIPBOARD_NODES_COMMAND');
const CLICK_COMMAND$2 = createCommand$2('CLICK_COMMAND');
const DELETE_CHARACTER_COMMAND$2 = createCommand$2('DELETE_CHARACTER_COMMAND');
const INSERT_LINE_BREAK_COMMAND$2 = createCommand$2('INSERT_LINE_BREAK_COMMAND');
const INSERT_PARAGRAPH_COMMAND$2 = createCommand$2('INSERT_PARAGRAPH_COMMAND');
const CONTROLLED_TEXT_INSERTION_COMMAND$2 = createCommand$2('CONTROLLED_TEXT_INSERTION_COMMAND');
const PASTE_COMMAND$2 = createCommand$2('PASTE_COMMAND');
const REMOVE_TEXT_COMMAND$2 = createCommand$2('REMOVE_TEXT_COMMAND');
const DELETE_WORD_COMMAND$2 = createCommand$2('DELETE_WORD_COMMAND');
const DELETE_LINE_COMMAND$2 = createCommand$2('DELETE_LINE_COMMAND');
const FORMAT_TEXT_COMMAND$2 = createCommand$2('FORMAT_TEXT_COMMAND');
const UNDO_COMMAND$2 = createCommand$2('UNDO_COMMAND');
const REDO_COMMAND$2 = createCommand$2('REDO_COMMAND');
const KEY_DOWN_COMMAND$2 = createCommand$2('KEYDOWN_COMMAND');
const KEY_ARROW_RIGHT_COMMAND$2 = createCommand$2('KEY_ARROW_RIGHT_COMMAND');
const MOVE_TO_END$2 = createCommand$2('MOVE_TO_END');
const KEY_ARROW_LEFT_COMMAND$2 = createCommand$2('KEY_ARROW_LEFT_COMMAND');
const MOVE_TO_START$2 = createCommand$2('MOVE_TO_START');
const KEY_ARROW_UP_COMMAND$2 = createCommand$2('KEY_ARROW_UP_COMMAND');
const KEY_ARROW_DOWN_COMMAND$2 = createCommand$2('KEY_ARROW_DOWN_COMMAND');
const KEY_ENTER_COMMAND$2 = createCommand$2('KEY_ENTER_COMMAND');
const KEY_SPACE_COMMAND$2 = createCommand$2('KEY_SPACE_COMMAND');
const KEY_BACKSPACE_COMMAND$2 = createCommand$2('KEY_BACKSPACE_COMMAND');
const KEY_ESCAPE_COMMAND$2 = createCommand$2('KEY_ESCAPE_COMMAND');
const KEY_DELETE_COMMAND$2 = createCommand$2('KEY_DELETE_COMMAND');
const KEY_TAB_COMMAND$2 = createCommand$2('KEY_TAB_COMMAND');
const INSERT_TAB_COMMAND$2 = createCommand$2('INSERT_TAB_COMMAND');
const INDENT_CONTENT_COMMAND$2 = createCommand$2('INDENT_CONTENT_COMMAND');
const OUTDENT_CONTENT_COMMAND$2 = createCommand$2('OUTDENT_CONTENT_COMMAND');
const DROP_COMMAND$2 = createCommand$2('DROP_COMMAND');
const FORMAT_ELEMENT_COMMAND$2 = createCommand$2('FORMAT_ELEMENT_COMMAND');
const DRAGSTART_COMMAND$2 = createCommand$2('DRAGSTART_COMMAND');
const DRAGOVER_COMMAND$2 = createCommand$2('DRAGOVER_COMMAND');
const DRAGEND_COMMAND$1 = createCommand$2('DRAGEND_COMMAND');
const COPY_COMMAND$2 = createCommand$2('COPY_COMMAND');
const CUT_COMMAND$2 = createCommand$2('CUT_COMMAND');
const SELECT_ALL_COMMAND$2 = createCommand$2('SELECT_ALL_COMMAND');
const CLEAR_EDITOR_COMMAND$2 = createCommand$2('CLEAR_EDITOR_COMMAND');
const CLEAR_HISTORY_COMMAND$2 = createCommand$2('CLEAR_HISTORY_COMMAND');
const CAN_REDO_COMMAND$2 = createCommand$2('CAN_REDO_COMMAND');
const CAN_UNDO_COMMAND$2 = createCommand$2('CAN_UNDO_COMMAND');
const FOCUS_COMMAND$2 = createCommand$2('FOCUS_COMMAND');
const BLUR_COMMAND$2 = createCommand$2('BLUR_COMMAND');
const KEY_MODIFIER_COMMAND$2 = createCommand$2('KEY_MODIFIER_COMMAND');
/**
* 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.
*
*/
const CAN_USE_DOM$8 = typeof window !== 'undefined' && typeof window.document !== 'undefined' && typeof window.document.createElement !== 'undefined';
/**
* 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.
*
*/
const documentMode$3 = CAN_USE_DOM$8 && 'documentMode' in document ? document.documentMode : null;
const IS_APPLE$4 = CAN_USE_DOM$8 && /Mac|iPod|iPhone|iPad/.test(navigator.platform);
const IS_FIREFOX$3 = CAN_USE_DOM$8 && /^(?!.*Seamonkey)(?=.*Firefox).*/i.test(navigator.userAgent);
const CAN_USE_BEFORE_INPUT$4 = CAN_USE_DOM$8 && 'InputEvent' in window && !documentMode$3 ? 'getTargetRanges' in new window.InputEvent('input') : false;
const IS_SAFARI$4 = CAN_USE_DOM$8 && /Version\/[\d.]+.*Safari/.test(navigator.userAgent);
const IS_IOS$4 = CAN_USE_DOM$8 && /iPad|iPhone|iPod/.test(navigator.userAgent) && !window.MSStream;
const IS_ANDROID$3 = CAN_USE_DOM$8 && /Android/.test(navigator.userAgent);
// Keep these in case we need to use them in the future.
// export const IS_WINDOWS: boolean = CAN_USE_DOM && /Win/.test(navigator.platform);
const IS_CHROME$4 = CAN_USE_DOM$8 && /^(?=.*Chrome).*/i.test(navigator.userAgent);
// export const canUseTextInputEvent: boolean = CAN_USE_DOM && 'TextEvent' in window && !documentMode;
const IS_ANDROID_CHROME$3 = CAN_USE_DOM$8 && IS_ANDROID$3 && IS_CHROME$4;
const IS_APPLE_WEBKIT$4 = CAN_USE_DOM$8 && /AppleWebKit\/[\d.]+/.test(navigator.userAgent) && !IS_CHROME$4;
/**
* 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.
*
*/
// DOM
const DOM_ELEMENT_TYPE$1 = 1;
const DOM_TEXT_TYPE$1 = 3;
const DOM_DOCUMENT_TYPE$1 = 9;
const DOM_DOCUMENT_FRAGMENT_TYPE$1 = 11;
// Reconciling
const NO_DIRTY_NODES$1 = 0;
const HAS_DIRTY_NODES$1 = 1;
const FULL_RECONCILE$1 = 2;
// Text node modes
const IS_NORMAL$1 = 0;
const IS_TOKEN$1 = 1;
const IS_SEGMENTED$1 = 2;
// IS_INERT = 3
// Text node formatting
const IS_BOLD$2 = 1;
const IS_ITALIC$2 = 1 << 1;
const IS_STRIKETHROUGH$2 = 1 << 2;
const IS_UNDERLINE$2 = 1 << 3;
const IS_CODE$2 = 1 << 4;
const IS_SUBSCRIPT$2 = 1 << 5;
const IS_SUPERSCRIPT$2 = 1 << 6;
const IS_HIGHLIGHT$1 = 1 << 7;
const IS_LOWERCASE$1 = 1 << 8;
const IS_UPPERCASE$1 = 1 << 9;
const IS_CAPITALIZE$1 = 1 << 10;
const IS_ALL_FORMATTING$1 = IS_BOLD$2 | IS_ITALIC$2 | IS_STRIKETHROUGH$2 | IS_UNDERLINE$2 | IS_CODE$2 | IS_SUBSCRIPT$2 | IS_SUPERSCRIPT$2 | IS_HIGHLIGHT$1 | IS_LOWERCASE$1 | IS_UPPERCASE$1 | IS_CAPITALIZE$1;
// Text node details
const IS_DIRECTIONLESS$1 = 1;
const IS_UNMERGEABLE$1 = 1 << 1;
// Element node formatting
const IS_ALIGN_LEFT$1 = 1;
const IS_ALIGN_CENTER$1 = 2;
const IS_ALIGN_RIGHT$1 = 3;
const IS_ALIGN_JUSTIFY$1 = 4;
const IS_ALIGN_START$1 = 5;
const IS_ALIGN_END$1 = 6;
// Reconciliation
const NON_BREAKING_SPACE$1 = '\u00A0';
const ZERO_WIDTH_SPACE$1 = '\u200b';
// For iOS/Safari we use a non breaking space, otherwise the cursor appears
// overlapping the composed text.
const COMPOSITION_SUFFIX$1 = IS_SAFARI$4 || IS_IOS$4 || IS_APPLE_WEBKIT$4 ? NON_BREAKING_SPACE$1 : ZERO_WIDTH_SPACE$1;
const DOUBLE_LINE_BREAK$1 = '\n\n';
// For FF, we need to use a non-breaking space, or it gets composition
// in a stuck state.
const COMPOSITION_START_CHAR$1 = IS_FIREFOX$3 ? NON_BREAKING_SPACE$1 : COMPOSITION_SUFFIX$1;
const RTL$1 = '\u0591-\u07FF\uFB1D-\uFDFD\uFE70-\uFEFC';
const LTR$1 = 'A-Za-z\u00C0-\u00D6\u00D8-\u00F6' + '\u00F8-\u02B8\u0300-\u0590\u0800-\u1FFF\u200E\u2C00-\uFB1C' + '\uFE00-\uFE6F\uFEFD-\uFFFF';
// eslint-disable-next-line no-misleading-character-class
const RTL_REGEX$1 = new RegExp('^[^' + LTR$1 + ']*[' + RTL$1 + ']');
// eslint-disable-next-line no-misleading-character-class
const LTR_REGEX$1 = new RegExp('^[^' + RTL$1 + ']*[' + LTR$1 + ']');
const TEXT_TYPE_TO_FORMAT$1 = {
bold: IS_BOLD$2,
capitalize: IS_CAPITALIZE$1,
code: IS_CODE$2,
highlight: IS_HIGHLIGHT$1,
italic: IS_ITALIC$2,
lowercase: IS_LOWERCASE$1,
strikethrough: IS_STRIKETHROUGH$2,
subscript: IS_SUBSCRIPT$2,
superscript: IS_SUPERSCRIPT$2,
underline: IS_UNDERLINE$2,
uppercase: IS_UPPERCASE$1
};
const DETAIL_TYPE_TO_DETAIL$1 = {
directionless: IS_DIRECTIONLESS$1,
unmergeable: IS_UNMERGEABLE$1
};
const ELEMENT_TYPE_TO_FORMAT$1 = {
center: IS_ALIGN_CENTER$1,
end: IS_ALIGN_END$1,
justify: IS_ALIGN_JUSTIFY$1,
left: IS_ALIGN_LEFT$1,
right: IS_ALIGN_RIGHT$1,
start: IS_ALIGN_START$1
};
const ELEMENT_FORMAT_TO_TYPE$1 = {
[IS_ALIGN_CENTER$1]: 'center',
[IS_ALIGN_END$1]: 'end',
[IS_ALIGN_JUSTIFY$1]: 'justify',
[IS_ALIGN_LEFT$1]: 'left',
[IS_ALIGN_RIGHT$1]: 'right',
[IS_ALIGN_START$1]: 'start'
};
const TEXT_MODE_TO_TYPE$1 = {
normal: IS_NORMAL$1,
segmented: IS_SEGMENTED$1,
token: IS_TOKEN$1
};
const TEXT_TYPE_TO_MODE$1 = {
[IS_NORMAL$1]: 'normal',
[IS_SEGMENTED$1]: 'segmented',
[IS_TOKEN$1]: 'token'
};
/**
* 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.
*
*/
function normalizeClassNames$3(...classNames) {
const rval = [];
for (const className of classNames) {
if (className && typeof className === 'string') {
for (const [s] of className.matchAll(/\S+/g)) {
rval.push(s);
}
}
}
return rval;
}
/**
* 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.
*
*/
// The time between a text entry event and the mutation observer firing.
const TEXT_MUTATION_VARIANCE$1 = 100;
let isProcessingMutations$1 = false;
let lastTextEntryTimeStamp$1 = 0;
function getIsProcessingMutations$1() {
return isProcessingMutations$1;
}
function updateTimeStamp$1(event) {
lastTextEntryTimeStamp$1 = event.timeStamp;
}
function initTextEntryListener$1(editor) {
if (lastTextEntryTimeStamp$1 === 0) {
getWindow$2(editor).addEventListener('textInput', updateTimeStamp$1, true);
}
}
function isManagedLineBreak$1(dom, target, editor) {
const isBR = dom.nodeName === 'BR';
const lexicalLineBreak = target.__lexicalLineBreak;
return lexicalLineBreak && (dom === lexicalLineBreak || isBR && dom.previousSibling === lexicalLineBreak) || isBR && getNodeKeyFromDOMNode$1(dom, editor) !== undefined;
}
function getLastSelection$1(editor) {
return editor.getEditorState().read(() => {
const selection = $getSelection$3();
return selection !== null ? selection.clone() : null;
});
}
function $handleTextMutation$1(target, node, editor) {
const domSelection = getDOMSelection$3(editor._window);
let anchorOffset = null;
let focusOffset = null;
if (domSelection !== null && domSelection.anchorNode === target) {
anchorOffset = domSelection.anchorOffset;
focusOffset = domSelection.focusOffset;
}
const text = target.nodeValue;
if (text !== null) {
$updateTextNodeFromDOMContent$1(node, text, anchorOffset, focusOffset, false);
}
}
function shouldUpdateTextNodeFromMutation$1(selection, targetDOM, targetNode) {
if ($isRangeSelection$2(selection)) {
const anchorNode = selection.anchor.getNode();
if (anchorNode.is(targetNode) && selection.format !== anchorNode.getFormat()) {
return false;
}
}
return isDOMTextNode$1(targetDOM) && targetNode.isAttached();
}
function $getNearestManagedNodePairFromDOMNode$1(startingDOM, editor, editorState, rootElement) {
for (let dom = startingDOM; dom && !isDOMUnmanaged$1(dom); dom = getParentElement$1(dom)) {
const key = getNodeKeyFromDOMNode$1(dom, editor);
if (key !== undefined) {
const node = $getNodeByKey$2(key, editorState);
if (node) {
// All decorator nodes are unmanaged
return $isDecoratorNode$2(node) || !isHTMLElement$5(dom) ? undefined : [dom, node];
}
} else if (dom === rootElement) {
return [rootElement, internalGetRoot$1(editorState)];
}
}
}
function $flushMutations$1(editor, mutations, observer) {
isProcessingMutations$1 = true;
const shouldFlushTextMutations = performance.now() - lastTextEntryTimeStamp$1 > TEXT_MUTATION_VARIANCE$1;
try {
updateEditor$1(editor, () => {
const selection = $getSelection$3() || getLastSelection$1(editor);
const badDOMTargets = new Map();
const rootElement = editor.getRootElement();
// We use the current editor state, as that reflects what is
// actually "on screen".
const currentEditorState = editor._editorState;
const blockCursorElement = editor._blockCursorElement;
let shouldRevertSelection = false;
let possibleTextForFirefoxPaste = '';
for (let i = 0; i < mutations.length; i++) {
const mutation = mutations[i];
const type = mutation.type;
const targetDOM = mutation.target;
const pair = $getNearestManagedNodePairFromDOMNode$1(targetDOM, editor, currentEditorState, rootElement);
if (!pair) {
continue;
}
const [nodeDOM, targetNode] = pair;
if (type === 'characterData') {
// Text mutations are deferred and passed to mutation listeners to be
// processed outside of the Lexical engine.
if (shouldFlushTextMutations && $isTextNode$2(targetNode) && isDOMTextNode$1(targetDOM) && shouldUpdateTextNodeFromMutation$1(selection, targetDOM, targetNode)) {
$handleTextMutation$1(targetDOM, targetNode, editor);
}
} else if (type === 'childList') {
shouldRevertSelection = true;
// We attempt to "undo" any changes that have occurred outside
// of Lexical. We want Lexical's editor state to be source of truth.
// To the user, these will look like no-ops.
const addedDOMs = mutation.addedNodes;
for (let s = 0; s < addedDOMs.length; s++) {
const addedDOM = addedDOMs[s];
const node = $getNodeFromDOMNode$1(addedDOM);
const parentDOM = addedDOM.parentNode;
if (parentDOM != null && addedDOM !== blockCursorElement && node === null && !isManagedLineBreak$1(addedDOM, parentDOM, editor)) {
if (IS_FIREFOX$3) {
const possibleText = (isHTMLElement$5(addedDOM) ? addedDOM.innerText : null) || addedDOM.nodeValue;
if (possibleText) {
possibleTextForFirefoxPaste += possibleText;
}
}
parentDOM.removeChild(addedDOM);
}
}
const removedDOMs = mutation.removedNodes;
const removedDOMsLength = removedDOMs.length;
if (removedDOMsLength > 0) {
let unremovedBRs = 0;
for (let s = 0; s < removedDOMsLength; s++) {
const removedDOM = removedDOMs[s];
if (isManagedLineBreak$1(removedDOM, targetDOM, editor) || blockCursorElement === removedDOM) {
targetDOM.appendChild(removedDOM);
unremovedBRs++;
}
}
if (removedDOMsLength !== unremovedBRs) {
badDOMTargets.set(nodeDOM, targetNode);
}
}
}
}
// Now we process each of the unique target nodes, attempting
// to restore their contents back to the source of truth, which
// is Lexical's "current" editor state. This is basically like
// an internal revert on the DOM.
if (badDOMTargets.size > 0) {
for (const [nodeDOM, targetNode] of badDOMTargets) {
targetNode.reconcileObservedMutation(nodeDOM, editor);
}
}
// Capture all the mutations made during this function. This
// also prevents us having to process them on the next cycle
// of onMutation, as these mutations were made by us.
const records = observer.takeRecords();
// Check for any random auto-added <br> elements, and remove them.
// These get added by the browser when we undo the above mutations
// and this can lead to a broken UI.
if (records.length > 0) {
for (let i = 0; i < records.length; i++) {
const record = records[i];
const addedNodes = record.addedNodes;
const target = record.target;
for (let s = 0; s < addedNodes.length; s++) {
const addedDOM = addedNodes[s];
const parentDOM = addedDOM.parentNode;
if (parentDOM != null && addedDOM.nodeName === 'BR' && !isManagedLineBreak$1(addedDOM, target, editor)) {
parentDOM.removeChild(addedDOM);
}
}
}
// Clear any of those removal mutations
observer.takeRecords();
}
if (selection !== null) {
if (shouldRevertSelection) {
selection.dirty = true;
$setSelection$2(selection);
}
if (IS_FIREFOX$3 && isFirefoxClipboardEvents$1(editor)) {
selection.insertRawText(possibleTextForFirefoxPaste);
}
}
});
} finally {
isProcessingMutations$1 = false;
}
}
function $flushRootMutations(editor) {
const observer = editor._observer;
if (observer !== null) {
const mutations = observer.takeRecords();
$flushMutations$1(editor, mutations, observer);
}
}
function initMutationObserver$1(editor) {
initTextEntryListener$1(editor);
editor._observer = new MutationObserver((mutations, observer) => {
$flushMutations$1(editor, mutations, observer);
});
}
/**
* 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.
*
*/
function $canSimpleTextNodesBeMerged$1(node1, node2) {
const node1Mode = node1.__mode;
const node1Format = node1.__format;
const node1Style = node1.__style;
const node2Mode = node2.__mode;
const node2Format = node2.__format;
const node2Style = node2.__style;
return (node1Mode === null || node1Mode === node2Mode) && (node1Format === null || node1Format === node2Format) && (node1Style === null || node1Style === node2Style);
}
function $mergeTextNodes$1(node1, node2) {
const writableNode1 = node1.mergeWithSibling(node2);
const normalizedNodes = getActiveEditor$1()._normalizedNodes;
normalizedNodes.add(node1.__key);
normalizedNodes.add(node2.__key);
return writableNode1;
}
function $normalizeTextNode$1(textNode) {
let node = textNode;
if (node.__text === '' && node.isSimpleText() && !node.isUnmergeable()) {
node.remove();
return;
}
// Backward
let previousNode;
while ((previousNode = node.getPreviousSibling()) !== null && $isTextNode$2(previousNode) && previousNode.isSimpleText() && !previousNode.isUnmergeable()) {
if (previousNode.__text === '') {
previousNode.remove();
} else if ($canSimpleTextNodesBeMerged$1(previousNode, node)) {
node = $mergeTextNodes$1(previousNode, node);
break;
} else {
break;
}
}
// Forward
let nextNode;
while ((nextNode = node.getNextSibling()) !== null && $isTextNode$2(nextNode) && nextNode.isSimpleText() && !nextNode.isUnmergeable()) {
if (nextNode.__text === '') {
nextNode.remove();
} else if ($canSimpleTextNodesBeMerged$1(node, nextNode)) {
node = $mergeTextNodes$1(node, nextNode);
break;
} else {
break;
}
}
}
function $normalizeSelection$1(selection) {
$normalizePoint$1(selection.anchor);
$normalizePoint$1(selection.focus);
return selection;
}
function $normalizePoint$1(point) {
while (point.type === 'element') {
const node = point.getNode();
const offset = point.offset;
let nextNode;
let nextOffsetAtEnd;
if (offset === node.getChildrenSize()) {
nextNode = node.getChildAtIndex(offset - 1);
nextOffsetAtEnd = true;
} else {
nextNode = node.getChildAtIndex(offset);
nextOffsetAtEnd = false;
}
if ($isTextNode$2(nextNode)) {
point.set(nextNode.__key, nextOffsetAtEnd ? nextNode.getTextContentSize() : 0, 'text');
break;
} else if (!$isElementNode$2(nextNode)) {
break;
}
point.set(nextNode.__key, nextOffsetAtEnd ? nextNode.getChildrenSize() : 0, 'element');
}
}
/**
* 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.
*
*/
let keyCounter$1 = 1;
function resetRandomKey$1() {
keyCounter$1 = 1;
}
function generateRandomKey$1() {
return '' + keyCounter$1++;
}
function getRegisteredNodeOrThrow$1(editor, nodeType) {
const registeredNode = editor._nodes.get(nodeType);
if (registeredNode === undefined) {
{
throw Error(`registeredNode: Type ${nodeType} not found`);
}
}
return registeredNode;
}
const scheduleMicroTask$1 = typeof queueMicrotask === 'function' ? queueMicrotask : fn => {
// No window prefix intended (#1400)
Promise.resolve().then(fn);
};
function $isSelectionCapturedInDecorator$1(node) {
return $isDecoratorNode$2($getNearestNodeFromDOMNode$2(node));
}
function isSelectionCapturedInDecoratorInput$2(anchorDOM) {
const activeElement = document.activeElement;
if (!isHTMLElement$5(activeElement)) {
return false;
}
const nodeName = activeElement.nodeName;
return $isDecoratorNode$2($getNearestNodeFromDOMNode$2(anchorDOM)) && (nodeName === 'INPUT' || nodeName === 'TEXTAREA' || activeElement.contentEditable === 'true' && getEditorPropertyFromDOMNode$1(activeElement) == null);
}
function isSelectionWithinEditor$2(editor, anchorDOM, focusDOM) {
const rootElement = editor.getRootElement();
try {
return rootElement !== null && rootElement.contains(anchorDOM) && rootElement.contains(focusDOM) &&
// Ignore if selection is within nested editor
anchorDOM !== null && !isSelectionCapturedInDecoratorInput$2(anchorDOM) && getNearestEditorFromDOMNode$2(anchorDOM) === editor;
} catch (error) {
return false;
}
}
/**
* @returns true if the given argument is a LexicalEditor instance from this build of Lexical
*/
function isLexicalEditor$1(editor) {
// Check instanceof to prevent issues with multiple embedded Lexical installations
return editor instanceof LexicalEditor$1;
}
function getNearestEditorFromDOMNode$2(node) {
let currentNode = node;
while (currentNode != null) {
const editor = getEditorPropertyFromDOMNode$1(currentNode);
if (isLexicalEditor$1(editor)) {
return editor;
}
currentNode = getParentElement$1(currentNode);
}
return null;
}
/** @internal */
function getEditorPropertyFromDOMNode$1(node) {
// @ts-expect-error: internal field
return node ? node.__lexicalEditor : null;
}
function getTextDirection$1(text) {
if (RTL_REGEX$1.test(text)) {
return 'rtl';
}
if (LTR_REGEX$1.test(text)) {
return 'ltr';
}
return null;
}
function $isTokenOrSegmented$2(node) {
return node.isToken() || node.isSegmented();
}
/**
* @param node - The element being tested
* @returns Returns true if node is an DOM Text node, false otherwise.
*/
function isDOMTextNode$1(node) {
return isDOMNode$2(node) && node.nodeType === DOM_TEXT_TYPE$1;
}
/**
* @param node - The element being tested
* @returns Returns true if node is an DOM Document node, false otherwise.
*/
function isDOMDocumentNode$1(node) {
return isDOMNode$2(node) && node.nodeType === DOM_DOCUMENT_TYPE$1;
}
function getDOMTextNode$3(element) {
let node = element;
while (node != null) {
if (isDOMTextNode$1(node)) {
return node;
}
node = node.firstChild;
}
return null;
}
function toggleTextFormatType$1(format, type, alignWithFormat) {
const activeFormat = TEXT_TYPE_TO_FORMAT$1[type];
if (alignWithFormat !== null && (format & activeFormat) === (alignWithFormat & activeFormat)) {
return format;
}
let newFormat = format ^ activeFormat;
if (type === 'subscript') {
newFormat &= ~TEXT_TYPE_TO_FORMAT$1.superscript;
} else if (type === 'superscript') {
newFormat &= ~TEXT_TYPE_TO_FORMAT$1.subscript;
} else if (type === 'lowercase') {
newFormat &= ~TEXT_TYPE_TO_FORMAT$1.uppercase;
newFormat &= ~TEXT_TYPE_TO_FORMAT$1.capitalize;
} else if (type === 'uppercase') {
newFormat &= ~TEXT_TYPE_TO_FORMAT$1.lowercase;
newFormat &= ~TEXT_TYPE_TO_FORMAT$1.capitalize;
} else if (type === 'capitalize') {
newFormat &= ~TEXT_TYPE_TO_FORMAT$1.lowercase;
newFormat &= ~TEXT_TYPE_TO_FORMAT$1.uppercase;
}
return newFormat;
}
function $isLeafNode$2(node) {
return $isTextNode$2(node) || $isLineBreakNode$2(node) || $isDecoratorNode$2(node);
}
function $setNodeKey$1(node, existingKey) {
if (existingKey != null) {
{
errorOnNodeKeyConstructorMismatch$1(node, existingKey);
}
node.__key = existingKey;
return;
}
errorOnReadOnly$1();
errorOnInfiniteTransforms$1();
const editor = getActiveEditor$1();
const editorState = getActiveEditorState$1();
const key = generateRandomKey$1();
editorState._nodeMap.set(key, node);
// TODO Split this function into leaf/element
if ($isElementNode$2(node)) {
editor._dirtyElements.set(key, true);
} else {
editor._dirtyLeaves.add(key);
}
editor._cloneNotNeeded.add(key);
editor._dirtyType = HAS_DIRTY_NODES$1;
node.__key = key;
}
function errorOnNodeKeyConstructorMismatch$1(node, existingKey) {
const editorState = internalGetActiveEditorState$1();
if (!editorState) {
// tests expect to be able to do this kind of clone without an active editor state
return;
}
const existingNode = editorState._nodeMap.get(existingKey);
if (existingNode && existingNode.constructor !== node.constructor) {
// Lifted condition to if statement because the inverted logic is a bit confusing
if (node.constructor.name !== existingNode.constructor.name) {
{
throw Error(`Lexical node with constructor ${node.constructor.name} attempted to re-use key from node in active editor state with constructor ${existingNode.constructor.name}. Keys must not be re-used when the type is changed.`);
}
} else {
{
throw Error(`Lexical node with constructor ${node.constructor.name} attempted to re-use key from node in active editor state with different constructor with the same name (possibly due to invalid Hot Module Replacement). Keys must not be re-used when the type is changed.`);
}
}
}
}
function internalMarkParentElementsAsDirty$1(parentKey, nodeMap, dirtyElements) {
let nextParentKey = parentKey;
while (nextParentKey !== null) {
if (dirtyElements.has(nextParentKey)) {
return;
}
const node = nodeMap.get(nextParentKey);
if (node === undefined) {
break;
}
dirtyElements.set(nextParentKey, false);
nextParentKey = node.__parent;
}
}
// TODO #6031 this function or their callers have to adjust selection (i.e. insertBefore)
function removeFromParent$1(node) {
const oldParent = node.getParent();
if (oldParent !== null) {
const writableNode = node.getWritable();
const writableParent = oldParent.getWritable();
const prevSibling = node.getPreviousSibling();
const nextSibling = node.getNextSibling();
// TODO: this function duplicates a bunch of operations, can be simplified.
if (prevSibling === null) {
if (nextSibling !== null) {
const writableNextSibling = nextSibling.getWritable();
writableParent.__first = nextSibling.__key;
writableNextSibling.__prev = null;
} else {
writableParent.__first = null;
}
} else {
const writablePrevSibling = prevSibling.getWritable();
if (nextSibling !== null) {
const writableNextSibling = nextSibling.getWritable();
writableNextSibling.__prev = writablePrevSibling.__key;
writablePrevSibling.__next = writableNextSibling.__key;
} else {
writablePrevSibling.__next = null;
}
writableNode.__prev = null;
}
if (nextSibling === null) {
if (prevSibling !== null) {
const writablePrevSibling = prevSibling.getWritable();
writableParent.__last = prevSibling.__key;
writablePrevSibling.__next = null;
} else {
writableParent.__last = null;
}
} else {
const writableNextSibling = nextSibling.getWritable();
if (prevSibling !== null) {
const writablePrevSibling = prevSibling.getWritable();
writablePrevSibling.__next = writableNextSibling.__key;
writableNextSibling.__prev = writablePrevSibling.__key;
} else {
writableNextSibling.__prev = null;
}
writableNode.__next = null;
}
writableParent.__size--;
writableNode.__parent = null;
}
}
// Never use this function directly! It will break
// the cloning heuristic. Instead use node.getWritable().
function internalMarkNodeAsDirty$1(node) {
errorOnInfiniteTransforms$1();
const latest = node.getLatest();
const parent = latest.__parent;
const editorState = getActiveEditorState$1();
const editor = getActiveEditor$1();
const nodeMap = editorState._nodeMap;
const dirtyElements = editor._dirtyElements;
if (parent !== null) {
internalMarkParentElementsAsDirty$1(parent, nodeMap, dirtyElements);
}
const key = latest.__key;
editor._dirtyType = HAS_DIRTY_NODES$1;
if ($isElementNode$2(node)) {
dirtyElements.set(key, true);
} else {
// TODO split internally MarkNodeAsDirty into two dedicated Element/leave functions
editor._dirtyLeaves.add(key);
}
}
function internalMarkSiblingsAsDirty$1(node) {
const previousNode = node.getPreviousSibling();
const nextNode = node.getNextSibling();
if (previousNode !== null) {
internalMarkNodeAsDirty$1(previousNode);
}
if (nextNode !== null) {
internalMarkNodeAsDirty$1(nextNode);
}
}
function $setCompositionKey$1(compositionKey) {
errorOnReadOnly$1();
const editor = getActiveEditor$1();
const previousCompositionKey = editor._compositionKey;
if (compositionKey !== previousCompositionKey) {
editor._compositionKey = compositionKey;
if (previousCompositionKey !== null) {
const node = $getNodeByKey$2(previousCompositionKey);
if (node !== null) {
node.getWritable();
}
}
if (compositionKey !== null) {
const node = $getNodeByKey$2(compositionKey);
if (node !== null) {
node.getWritable();
}
}
}
}
function $getCompositionKey$1() {
if (isCurrentlyReadOnlyMode$1()) {
return null;
}
const editor = getActiveEditor$1();
return editor._compositionKey;
}
function $getNodeByKey$2(key, _editorState) {
const editorState = _editorState || getActiveEditorState$1();
const node = editorState._nodeMap.get(key);
if (node === undefined) {
return null;
}
return node;
}
function $getNodeFromDOMNode$1(dom, editorState) {
const editor = getActiveEditor$1();
const key = getNodeKeyFromDOMNode$1(dom, editor);
if (key !== undefined) {
return $getNodeByKey$2(key, editorState);
}
return null;
}
function setNodeKeyOnDOMNode$1(dom, editor, key) {
const prop = `__lexicalKey_${editor._key}`;
dom[prop] = key;
}
function getNodeKeyFromDOMNode$1(dom, editor) {
const prop = `__lexicalKey_${editor._key}`;
return dom[prop];
}
function $getNearestNodeFromDOMNode$2(startingDOM, editorState) {
let dom = startingDOM;
while (dom != null) {
const node = $getNodeFromDOMNode$1(dom, editorState);
if (node !== null) {
return node;
}
dom = getParentElement$1(dom);
}
return null;
}
function cloneDecorators$1(editor) {
const currentDecorators = editor._decorators;
const pendingDecorators = Object.assign({}, currentDecorators);
editor._pendingDecorators = pendingDecorators;
return pendingDecorators;
}
function getEditorStateTextContent$1(editorState) {
return editorState.read(() => $getRoot$3().getTextContent());
}
function markNodesWithTypesAsDirty$1(editor, types) {
// We only need to mark nodes dirty if they were in the previous state.
// If they aren't, then they are by definition dirty already.
const cachedMap = getCachedTypeToNodeMap$1(editor.getEditorState());
const dirtyNodeMaps = [];
for (const type of types) {
const nodeMap = cachedMap.get(type);
if (nodeMap) {
// By construction these are non-empty
dirtyNodeMaps.push(nodeMap);
}
}
// Nothing to mark dirty, no update necessary
if (dirtyNodeMaps.length === 0) {
return;
}
editor.update(() => {
for (const nodeMap of dirtyNodeMaps) {
for (const nodeKey of nodeMap.keys()) {
// We are only concerned with nodes that are still in the latest NodeMap,
// if they no longer exist then markDirty would raise an exception
const latest = $getNodeByKey$2(nodeKey);
if (latest) {
latest.markDirty();
}
}
}
}, editor._pendingEditorState === null ? {
tag: 'history-merge'
} : undefined);
}
function $getRoot$3() {
return internalGetRoot$1(getActiveEditorState$1());
}
function internalGetRoot$1(editorState) {
return editorState._nodeMap.get('root');
}
function $setSelection$2(selection) {
errorOnReadOnly$1();
const editorState = getActiveEditorState$1();
if (selection !== null) {
{
if (Object.isFrozen(selection)) {
{
throw Error(`$setSelection called on frozen selection object. Ensure selection is cloned before passing in.`);
}
}
}
selection.dirty = true;
selection.setCachedNodes(null);
}
editorState._selection = selection;
}
function $flushMutations$2() {
errorOnReadOnly$1();
const editor = getActiveEditor$1();
$flushRootMutations(editor);
}
function $getNodeFromDOM$1(dom) {
const editor = getActiveEditor$1();
const nodeKey = getNodeKeyFromDOMTree$1(dom, editor);
if (nodeKey === null) {
const rootElement = editor.getRootElement();
if (dom === rootElement) {
return $getNodeByKey$2('root');
}
return null;
}
return $getNodeByKey$2(nodeKey);
}
function getTextNodeOffset$1(node, moveSelectionToEnd) {
return moveSelectionToEnd ? node.getTextContentSize() : 0;
}
function getNodeKeyFromDOMTree$1(
// Note that node here refers to a DOM Node, not an Lexical Node
dom, editor) {
let node = dom;
while (node != null) {
const key = getNodeKeyFromDOMNode$1(node, editor);
if (key !== undefined) {
return key;
}
node = getParentElement$1(node);
}
return null;
}
function doesContainGrapheme(str) {
return /[\uD800-\uDBFF][\uDC00-\uDFFF]/g.test(str);
}
function getEditorsToPropagate$1(editor) {
const editorsToPropagate = [];
let currentEditor = editor;
while (currentEditor !== null) {
editorsToPropagate.push(currentEditor);
currentEditor = currentEditor._parentEditor;
}
return editorsToPropagate;
}
function createUID$1() {
return Math.random().toString(36).replace(/[^a-z]+/g, '').substr(0, 5);
}
function getAnchorTextFromDOM$1(anchorNode) {
return isDOMTextNode$1(anchorNode) ? anchorNode.nodeValue : null;
}
function $updateSelectedTextFromDOM$1(isCompositionEnd, editor, data) {
// Update the text content with the latest composition text
const domSelection = getDOMSelection$3(editor._window);
if (domSelection === null) {
return;
}
const anchorNode = domSelection.anchorNode;
let {
anchorOffset,
focusOffset
} = domSelection;
if (anchorNode !== null) {
let textContent = getAnchorTextFromDOM$1(anchorNode);
const node = $getNearestNodeFromDOMNode$2(anchorNode);
if (textContent !== null && $isTextNode$2(node)) {
// Data is intentionally truthy, as we check for boolean, null and empty string.
if (textContent === COMPOSITION_SUFFIX$1 && data) {
const offset = data.length;
textContent = data;
anchorOffset = offset;
focusOffset = offset;
}
if (textContent !== null) {
$updateTextNodeFromDOMContent$1(node, textContent, anchorOffset, focusOffset, isCompositionEnd);
}
}
}
}
function $updateTextNodeFromDOMContent$1(textNode, textContent, anchorOffset, focusOffset, compositionEnd) {
let node = textNode;
if (node.isAttached() && (compositionEnd || !node.isDirty())) {
const isComposing = node.isComposing();
let normalizedTextContent = textContent;
if ((isComposing || compositionEnd) && textContent[textContent.length - 1] === COMPOSITION_SUFFIX$1) {
normalizedTextContent = textContent.slice(0, -1);
}
const prevTextContent = node.getTextContent();
if (compositionEnd || normalizedTextContent !== prevTextContent) {
if (normalizedTextContent === '') {
$setCompositionKey$1(null);
if (!IS_SAFARI$4 && !IS_IOS$4 && !IS_APPLE_WEBKIT$4) {
// For composition (mainly Android), we have to remove the node on a later update
const editor = getActiveEditor$1();
setTimeout(() => {
editor.update(() => {
if (node.isAttached()) {
node.remove();
}
});
}, 20);
} else {
node.remove();
}
return;
}
const parent = node.getParent();
const prevSelection = $getPreviousSelection$2();
const prevTextContentSize = node.getTextContentSize();
const compositionKey = $getCompositionKey$1();
const nodeKey = node.getKey();
if (node.isToken() || compositionKey !== null && nodeKey === compositionKey && !isComposing ||
// Check if character was added at the start or boundaries when not insertable, and we need
// to clear this input from occurring as that action wasn't permitted.
$isRangeSelection$2(prevSelection) && (parent !== null && !parent.canInsertTextBefore() && prevSelection.anchor.offset === 0 || prevSelection.anchor.key === textNode.__key && prevSelection.anchor.offset === 0 && !node.canInsertTextBefore() && !isComposing || prevSelection.focus.key === textNode.__key && prevSelection.focus.offset === prevTextContentSize && !node.canInsertTextAfter() && !isComposing)) {
node.markDirty();
return;
}
const selection = $getSelection$3();
if (!$isRangeSelection$2(selection) || anchorOffset === null || focusOffset === null) {
node.setTextContent(normalizedTextContent);
return;
}
selection.setTextNodeRange(node, anchorOffset, node, focusOffset);
if (node.isSegmented()) {
const originalTextContent = node.getTextContent();
const replacement = $createTextNode$2(originalTextContent);
node.replace(replacement);
node = replacement;
}
node.setTextContent(normalizedTextContent);
}
}
}
function $previousSiblingDoesNotAcceptText$1(node) {
const previousSibling = node.getPreviousSibling();
return ($isTextNode$2(previousSibling) || $isElementNode$2(previousSibling) && previousSibling.isInline()) && !previousSibling.canInsertTextAfter();
}
// This function is connected to $shouldPreventDefaultAndInsertText and determines whether the
// TextNode boundaries are writable or we should use the previous/next sibling instead. For example,
// in the case of a LinkNode, boundaries are not writable.
function $shouldInsertTextAfterOrBeforeTextNode$1(selection, node) {
if (node.isSegmented()) {
return true;
}
if (!selection.isCollapsed()) {
return false;
}
const offset = selection.anchor.offset;
const parent = node.getParentOrThrow();
const isToken = node.isToken();
if (offset === 0) {
return !node.canInsertTextBefore() || !parent.canInsertTextBefore() && !node.isComposing() || isToken || $previousSiblingDoesNotAcceptText$1(node);
} else if (offset === node.getTextContentSize()) {
return !node.canInsertTextAfter() || !parent.canInsertTextAfter() && !node.isComposing() || isToken;
} else {
return false;
}
}
function isTab$1(key, altKey, ctrlKey, metaKey) {
return key === 'Tab' && !altKey && !ctrlKey && !metaKey;
}
function isBold$1(key, altKey, metaKey, ctrlKey) {
return key.toLowerCase() === 'b' && !altKey && controlOrMeta$1(metaKey, ctrlKey);
}
function isItalic$1(key, altKey, metaKey, ctrlKey) {
return key.toLowerCase() === 'i' && !altKey && controlOrMeta$1(metaKey, ctrlKey);
}
function isUnderline$1(key, altKey, metaKey, ctrlKey) {
return key.toLowerCase() === 'u' && !altKey && controlOrMeta$1(metaKey, ctrlKey);
}
function isParagraph$1(key, shiftKey) {
return isReturn(key) && !shiftKey;
}
function isLineBreak$1(key, shiftKey) {
return isReturn(key) && shiftKey;
}
// Inserts a new line after the selection
function isOpenLineBreak$1(key, ctrlKey) {
// 79 = KeyO
return IS_APPLE$4 && ctrlKey && key.toLowerCase() === 'o';
}
function isDeleteWordBackward$1(key, altKey, ctrlKey) {
return isBackspace$1(key) && (IS_APPLE$4 ? altKey : ctrlKey);
}
function isDeleteWordForward$1(key, altKey, ctrlKey) {
return isDelete$1(key) && (IS_APPLE$4 ? altKey : ctrlKey);
}
function isDeleteLineBackward$1(key, metaKey) {
return IS_APPLE$4 && metaKey && isBackspace$1(key);
}
function isDeleteLineForward$1(key, metaKey) {
return IS_APPLE$4 && metaKey && isDelete$1(key);
}
function isDeleteBackward$1(key, altKey, metaKey, ctrlKey) {
if (IS_APPLE$4) {
if (altKey || metaKey) {
return false;
}
return isBackspace$1(key) || key.toLowerCase() === 'h' && ctrlKey;
}
if (ctrlKey || altKey || metaKey) {
return false;
}
return isBackspace$1(key);
}
function isDeleteForward$1(key, ctrlKey, shiftKey, altKey, metaKey) {
if (IS_APPLE$4) {
if (shiftKey || altKey || metaKey) {
return false;
}
return isDelete$1(key) || ke