UNPKG

@slesaad/veda-content-editor

Version:

VEDA Content Editor - A React-based MDX editor component

1,367 lines (1,305 loc) 4.63 MB
'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