import { c as MapToComponentField, M as MapToComponentMethod } from './global-slimmer-registry-17c4efd4.js';
import { a9 as RTECodeBlockNode, c as RTETextNode, ac as ZERO_WIDTH_SPACE, af as SelectionChangeAction, k as InternalAnnotationTypeEnum, s as stateEntityRenderingRegistry, d as RTEBlock, i as RTENode, G as RTEDecoratorNode, E as RTECodeBlock } from './code-block-10be3916.js';
import { d as debounce } from './timer-9321173b.js';
import { g as getActiveElement } from './component-7d906393.js';
import { C as ChangeManager } from './change-manager-6a7eb88c.js';
import { d as domNodeSubjectFactory, D as DomNodeSubjectObserverFactory } from './dom-node-subject-observer-factory-aca0116e.js';
import { e as VegaInternalRichTextEditorSelectionRangeChange, c as VegaInternalUpdateRTECursorPosition } from './vega-internal-event-id-db974a0d.js';
import { O as Observer } from './observer-3959f9dd.js';
import { R as RTERange } from './range-f32f9185.js';
import { A as AutoRunWhenReRenderTaskQueueSlimmer } from './auto-run-when-re-render-task-queue-slimmer.abstract-27820d4c.js';
import { i as isHTMLElement } from './ui-b7600a48.js';
import { K as KeyboardManagerSlimmer } from './keyboard-manager-slimmer-3891ee20.js';

let processing = false;
/**
 * Simulate a selection for browsers that don't support shadow selection.
 * Cypress test case added in https://github.com/heartlandpayments/Vega/pull/1561/files#diff-83bdbaaf47fc156ab878099aa1f21b0e8ab92abe5852521299f1fb6efab001c2R300
 */
class ShadowSelection {
  constructor() {
    this.rangeCount = 0;
    this.ranges = [];
  }
  /**
   * Returns a Range object at a specified index.
   *
   * @param {number} index - A specified index.
   * @returns {Range} - A Range object.
   */
  getRangeAt(index) {
    return this.ranges[index];
  }
  /**
   * Adds a Range to ranges array.
   *
   * @param {Range} range - The range of selection.
   */
  addRange(range) {
    this.ranges.push(range);
    this.rangeCount = this.ranges.length;
    if (!processing) {
      const windowSelection = window.getSelection();
      windowSelection.removeAllRanges();
      windowSelection.setBaseAndExtent(range.startContainer, range.startOffset, range.endContainer, range.endOffset);
    }
  }
  /**
   * Clears all ranges.
   */
  removeAllRanges() {
    this.ranges = [];
    this.rangeCount = 0;
  }
}
/**
 * Due to the ShadowRoot.getSelection is not a standard API, we add this polyfill to achieve this function.
 *
 * - On Chromium, calling document.getSelection will not pierce into the Shadow DOM and gives you some unhelpful high-level element.
 *   But it does expose the non-standard getSelection method on the ShadowRoot.
 *
 * - On Firefox, it does not implement ShadowRoot.getSelection,
 *   but document.getSelection will pierce through shadow dom and give you the exact element.
 *
 * - On Safari, Selection.getComposedRanges is supported as of v17. On versions before that,
 *   ShadowRoot.getSelection is not supported and apparently document.getSelection does not pierce the Shadow DOM, meaning you are just out of luck.
 *
 * https://developer.mozilla.org/en-US/docs/Web/API/ShadowRoot#shadowroot.getselection
 * https://stackoverflow.com/a/70523247
 */
class ShadowSelectionPolyfill {
  constructor() {
    this.supportShadowSelection = typeof window.ShadowRoot.prototype['getSelection'] === 'function';
    this.supportBeforeInput = typeof window.InputEvent.prototype.getTargetRanges === 'function';
    this.isFirefox = window.navigator.userAgent.toLowerCase().indexOf('firefox') > 0;
    this.listen();
  }
  /**
   * For Firefox, we directly use document.getSelection()
   * For other browser which not support shadowroot.getSelection, we use this.selection which is built by us.
   * For browser which supported shadowroot.getSelection, we use shadowRoot.getselection().
   *
   * @param {ShadowRoot} shadow - A shadow.
   * @returns {Nullable<Selection>} - The shadow selection.
   */
  getSelection(shadow) {
    if (this.supportShadowSelection) {
      return shadow['getSelection']();
    }
    else {
      return this.isFirefox
        ? this.getFirefoxSelection()
        : this.polyfilledShadowSelection;
    }
  }
  /**
   * Get selection in firefox.
   *
   * Example:
   *
   * <span>span1</span><span>span2</span><span>span3</span>
   *
   * In firefox, while selected `span2`, the range be likely to:
   * range:
   *   startContainer: #text 'span1'
   *   startOffset: 5
   * 	 endContainer: #text 'span3'
   *   endOffset: 0
   * start is end of brefore node and end is start of after node.
   *
   * So we should modify the startContainer and endContainer here.
   *
   * modified range:
   *   startContainer: #text 'span2'
   *   startOffset: 0
   * 	 endContainer: #text 'span2'
   *   endOffset: 5
   *
   * @returns {Selection} - document selection
   */
  getFirefoxSelection() {
    // eslint-disable-next-line no-restricted-globals
    const selection = document.getSelection();
    if (selection.rangeCount > 0) {
      const range = selection.getRangeAt(0);
      const startNode = range.startContainer;
      const endNode = range.endContainer;
      if (startNode !== endNode && startNode.textContent.length === range.startOffset) {
        const nextSibling = startNode.nodeType === Node.TEXT_NODE
          ? startNode.parentNode.nextSibling
          : startNode.nextSibling;
        range.setStart(nextSibling.firstChild, 0);
      }
      if (endNode !== startNode && range.endOffset === 0) {
        const previousSibling = endNode.nodeType === Node.TEXT_NODE
          ? endNode.parentNode.previousSibling
          : endNode.previousSibling;
        range.setEnd(previousSibling.lastChild, previousSibling.lastChild.textContent.length);
      }
    }
    return selection;
  }
  /**
   * Sets up event listeners for `selectionchange` and `beforeinput` events to simulate shadow selection.
   */
  listen() {
    if (this.isFirefox || this.supportShadowSelection || !this.supportBeforeInput)
      return;
    this.polyfilledShadowSelection = new ShadowSelection();
    window.addEventListener('selectionchange', () => {
      if (!processing) {
        processing = true;
        const active = getActiveElement();
        if (active && active.hasAttribute('contenteditable')) {
          // This command will not actually work, it only trigger the `beforeinput` event,
          // the `beforeinput` event will prevented this command work.
          // eslint-disable-next-line no-restricted-globals
          document.execCommand('indent');
        }
        else {
          this.polyfilledShadowSelection.removeAllRanges();
        }
        processing = false;
      }
    }, true);
    window.addEventListener('beforeinput', (event) => {
      if (processing) {
        const ranges = event.getTargetRanges();
        const range = ranges[0];
        const newRange = new Range();
        newRange.setStart(range.startContainer, range.startOffset);
        newRange.setEnd(range.endContainer, range.endOffset);
        this.polyfilledShadowSelection.removeAllRanges();
        this.polyfilledShadowSelection.addRange(newRange);
        event.preventDefault();
        event.stopImmediatePropagation();
      }
    }, true);
  }
}
const ShadowSelectionPolyfill$1 = new ShadowSelectionPolyfill();

/**
 * Represents the state of the selection in the RTE.
 */
class RTESelectionState {
  constructor(range) {
    this.range = range;
  }
  /**
   * Clones the selection state, updating the range nodes based on the provided content.
   *
   * @returns {RTESelectionState} A new instance of RTESelectionState with the updated range.
   */
  clone() {
    const newRange = this.range.clone();
    return new RTESelectionState(newRange);
  }
}

var __decorate = (undefined && undefined.__decorate) || function (decorators, target, key, desc) {
  var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
  if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
  else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
  return c > 3 && r && Object.defineProperty(target, key, r), r;
};
/**
 * The text selection controller
 */
class SelectionController extends AutoRunWhenReRenderTaskQueueSlimmer {
  constructor() {
    super(1);
    this.currentRange = new RTERange();
    this.handleSelectionWithDebounce = debounce(this.handleSelectionChange, SelectionController.SELECTION_CHANGE_DEBOUNCE_TIME, this);
    this.pendingRestoreSelectionNodes = [];
    /**
     * The method invoke after the component re-render.
     */
    this.doTask = async () => {
      // add await Promise.resolve to put the code behind to a micro task
      await Promise.resolve();
      const range = this.currentRange.toNativeRange();
      if (range) {
        this.setSelectionRange(range);
      }
    };
  }
  /**
   * Component lifecycle - [connectedCallback]{@link VegaRichTextEditor.connectedCallback}
   */
  connectedCallback() {
    this.registerSelectionRangeChangeObserver();
  }
  /**
   * Component lifecycle - [disconnectedCallback]{@link VegaRichTextEditor.disconnectedCallback}
   */
  disconnectedCallback() {
    ChangeManager.unregister(domNodeSubjectFactory.getSubject(this.host, VegaInternalRichTextEditorSelectionRangeChange), this.selectionRangeChangeObserver);
    DomNodeSubjectObserverFactory.removeUniqueObserverFromNode(this.host, VegaInternalUpdateRTECursorPosition);
  }
  /**
   * Component lifecycle - [componentDidLoad]{@link VegaRichTextEditor.componentDidLoad}
   */
  componentDidLoad() {
    // eslint-disable-next-line no-restricted-globals
    document.addEventListener('selectionchange', this.handleSelectionWithDebounce);
    this.registerUpdateCaretPositionObserver();
  }
  /**
   * Watches the internal value of the editor
   */
  watchValueUpdate() {
    this.prepareRestoreSelectionState();
    this.restoreSelection();
  }
  /**
   * Get the current RTE selection range
   *
   * @returns {RTERange} - The current RTE selection range
   */
  getCurrentRange() {
    return this.currentRange;
  }
  /**
   * Get the selected rich text node
   *
   * @returns {RTENode[]} Selected rich text nodes
   */
  getSelectedNodes() {
    return Array.from(this.selectionMap.values()).flat();
  }
  /**
   * Set the selected rich text nodes
   *
   * @param {RTENode[]} nodes - The rich text nodes to set as selected
   * @param {RTERangeOptions} [rangeOptions] - The range options to set the selection range
   */
  setSelectedNodes(nodes, rangeOptions) {
    this.clearSelectionMap();
    this.addNodesToSelectionMap(nodes);
    if (rangeOptions) {
      this.currentRange = this.currentRange.updateRTERange(rangeOptions);
    }
  }
  /**
   * Get the selected rich text blocks
   *
   * @returns {RTEBlock[]} Selected rich text blocks
   */
  getSelectedBlocks() {
    return Array.from(this.selectionMap.keys());
  }
  /**
   * Set the selection state
   *
   * @param {RTESelectionState} state - The selection state to set
   */
  setSelectionState(state) {
    this.selectionState = state;
  }
  /**
   * Sets the next selection state with specified start and end nodes, offsets, push the update task to a queue
   *
   * @param {SelectionStateType['startNode']} startNode - The starting node of the selection range. It is a Node object representing the node where the selection range starts.
   * @param {number} startOffset - The `startNode` where the selection range should start. It indicates the position within the `startNode` where the selection should begin.
   * @param {SelectionStateType['endNode']} [endNode] - The ending node of the selection range. If a value is provided for `endNode`, it will be used as the ending node of the selection range.
   * @param {number} [endOffset] - The ending offset within the `endNode` where the selection range should end.
   * @param {boolean} [immediatelyRun] - Should the task run immediately. default is false
   */
  enqueueSelectionRangeFutureState(startNode, startOffset, endNode, endOffset, immediatelyRun = false) {
    if (startNode instanceof RTECodeBlockNode) {
      this.internalCodeBlockSelectionController.enqueueSelectionRangeFutureState(startNode, startOffset, immediatelyRun);
    }
    else {
      endNode = endNode || startNode;
      endOffset = endOffset || endOffset === 0 ? endOffset : startOffset;
      this.currentRange = this.currentRange.updateRTERange({
        startNode,
        endNode,
        startOffset,
        endOffset,
      });
      super.enqueueTheTaskIntoQueue(immediatelyRun);
    }
  }
  /**
   * Set selection with a new range
   *
   * @param {Range} range - The range to set
   */
  setSelectionRange(range) {
    const selection = this.getSelection();
    if (selection) {
      selection.removeAllRanges();
      selection.addRange(range);
      this.saveSelection();
    }
  }
  /**
   * Get the rich text content selected range
   *
   * @returns {Selection} A [Selection](https://developer.mozilla.org/en-US/docs/Web/API/Selection) object
   */
  getSelection() {
    const richTextContentRef = this.vegaRichTextEditorRenderer.getRichTextContentRef();
    return ShadowSelectionPolyfill$1.getSelection(richTextContentRef.shadowRoot);
  }
  /**
   * Save the current selection range detail
   */
  saveSelection() {
    const selection = this.getSelection();
    // The range is out of date if the queue is not empty, or the range is update by the composition text insert, so we should not update the RTERange
    if (selection &&
      selection.rangeCount > 0 &&
      this.autoRunTaskQueue.queue.length === 0 &&
      !this.insertCompositionTextController.isComposing()) {
      const range = selection.getRangeAt(0);
      const { startContainer: startNode, endContainer: endNode, startOffset, endOffset } = range;
      this.currentRange = this.currentRange.updateRTERange({ startNode, endNode, startOffset, endOffset }, range);
    }
  }
  /**
   * Restore the selection to the current selected nodes
   */
  restoreSelection() {
    if (this.selectionState) {
      const { startNode, endNode, startOffset, endOffset } = this.selectionState.range;
      if (startNode instanceof RTETextNode && startNode === endNode && startNode.text.length === 0) {
        this.enqueueSelectionRangeFutureState(startNode, ZERO_WIDTH_SPACE.length);
      }
      else {
        // Don't need update the range if the selected node is a non-editable text node, such as token node.
        if (!(startNode === endNode &&
          startNode instanceof RTETextNode &&
          !startNode.isContentEditable())) {
          this.enqueueSelectionRangeFutureState(startNode, startOffset, endNode, endOffset);
        }
      }
      this.selectionState = null;
    }
  }
  /**
   * Get selected rich text
   */
  handleSelectionChange() {
    if (this.disabled || this.sourceView)
      return;
    // Clear previous selection when handling new selection always
    this.clearSelectionMap();
    const selection = this.getSelection();
    if (!selection || selection.rangeCount === 0)
      return;
    this.saveSelection();
    const range = selection.getRangeAt(0);
    const commonAncestor = range.commonAncestorContainer;
    const selectedNodes = [];
    /**
     * Rich text node filter
     *
     * @todo refactor the function by a handlers chain https://gethired.atlassian.net/browse/VD-7132
     * @param {Node} node - Start node
     */
    const filterNode = (node) => {
      if (!range.intersectsNode(node)) {
        return;
      }
      if (node.nodeType === Node.TEXT_NODE) {
        const currentNode = node.parentElement;
        const nodeEntity = stateEntityRenderingRegistry.getEntityByDOM(currentNode);
        if (nodeEntity instanceof RTENode) {
          selectedNodes.push(nodeEntity);
          return;
        }
      }
      if (isHTMLElement(node)) {
        const entityElement = RTEDecoratorNode.isDecoratorNodeContainerElement(node)
          ? RTEDecoratorNode.getDecoratorNodeElement(node)
          : node;
        const nodeEntity = stateEntityRenderingRegistry.getEntityByDOM(entityElement);
        if (nodeEntity instanceof RTECodeBlock) {
          if (this.internalCodeBlockSelectionController.isCodeBlockSelected(nodeEntity, range)) {
            selectedNodes.push(nodeEntity.children[0]);
          }
          return;
        }
        if (nodeEntity instanceof RTENode) {
          selectedNodes.push(nodeEntity);
          return;
        }
        // If no node is selected, try to get the nearest node from the current range and set the range to it
        if (nodeEntity instanceof RTEBlock && range.collapsed) {
          this.tryToFindTheNearestSelectedNode(range, selectedNodes);
          return;
        }
      }
      node.childNodes.forEach(filterNode);
    };
    filterNode(commonAncestor);
    this.addNodesToSelectionMap(selectedNodes);
    this.getSelectedNodes().forEach((node) => node.apply(new SelectionChangeAction(range)));
  }
  /**
   * Add nodes to the selection map
   *
   * @param {RTENode[]} nodes - The rich text nodes to add
   */
  addNodesToSelectionMap(nodes) {
    nodes.forEach((node) => {
      if (this.selectionMap.has(node.parent)) {
        this.selectionMap.get(node.parent).push(node);
      }
      else {
        this.selectionMap.set(node.parent, [node]);
      }
    });
  }
  /**
   * Clear the selection map.
   * The code node don't need clear here, because the code node will manager the selection state itself. `code-node-renderer.tsx#handleSelectionChange`
   */
  clearSelectionMap() {
    this.getSelectedNodes()
      .filter((node) => node.type !== 'CODE_BLOCK_NODE')
      .forEach((node) => {
      node.annotationMap.delete(InternalAnnotationTypeEnum.SELECTION_RANGE);
    });
    this.selectionMap = new Map();
  }
  /**
   * Check if the selection range change is acceptable
   *
   * @returns {boolean} - Returns a boolean value.
   */
  isAcceptableSelectionRangeChange() {
    return true;
  }
  /**
   * Register the selection range change observer
   */
  registerSelectionRangeChangeObserver() {
    this.selectionRangeChangeObserver = new Observer(this.isAcceptableSelectionRangeChange.bind(this), (payload) => {
      if (!payload.updateDirectly) {
        this.pendingRestoreSelectionNodes.push(payload.node);
      }
      else {
        this.enqueueSelectionRangeFutureState(payload.node, payload.offset);
      }
    });
    ChangeManager.register(domNodeSubjectFactory.getSubject(this.host, VegaInternalRichTextEditorSelectionRangeChange), this.selectionRangeChangeObserver);
  }
  /**
   * Prepare the selection state to restore
   */
  prepareRestoreSelectionState() {
    if (this.pendingRestoreSelectionNodes.length > 0) {
      const startNode = this.pendingRestoreSelectionNodes[0];
      const endNode = this.pendingRestoreSelectionNodes.length > 1
        ? this.pendingRestoreSelectionNodes[this.pendingRestoreSelectionNodes.length - 1]
        : startNode;
      const { startOffset, endOffset, endContainer, startContainer } = this.currentRange;
      const nodesInCurrentRange = startContainer &&
        stateEntityRenderingRegistry.getDOMByEntity(startNode) === startContainer.parentElement &&
        endContainer &&
        stateEntityRenderingRegistry.getDOMByEntity(endNode) === endContainer.parentElement;
      if (nodesInCurrentRange) {
        this.currentRange = this.currentRange.updateRTERange({
          startNode,
          endNode,
          startOffset,
          endOffset,
        });
        this.selectionState = new RTESelectionState(this.currentRange);
      }
      else {
        this.currentRange = this.currentRange.updateRTERange({
          startNode,
          endNode,
          startOffset: 0,
          endOffset: endNode.getRangeEndOffset(),
        });
        this.selectionState = new RTESelectionState(this.currentRange);
      }
      this.pendingRestoreSelectionNodes = [];
    }
  }
  /**
   * Register the update caret position observer.
   */
  registerUpdateCaretPositionObserver() {
    DomNodeSubjectObserverFactory.addUniqueObserverToNode(this.host, VegaInternalUpdateRTECursorPosition, (payload) => {
      const { node, updateDirectly } = payload;
      const offset = typeof payload.offset === 'number' ? payload.offset : node.getRangeEndOffset();
      this.enqueueSelectionRangeFutureState(node, offset, node, offset, updateDirectly);
    });
  }
  /**
   * If no node is selected, try to get the nearest node from the current range and set the range to it
   *
   * @param {Range} range - The current range
   * @param {RTENode[]} selectedNodes - The selected nodes array
   */
  tryToFindTheNearestSelectedNode(range, selectedNodes) {
    const { startContainer, startOffset, collapsed } = range;
    if (selectedNodes.length === 0 && isHTMLElement(startContainer) && collapsed) {
      const entity = stateEntityRenderingRegistry.getEntityByDOM(startContainer);
      if (entity instanceof RTEBlock && entity.children.length >= startOffset) {
        const nearestFocusState = this.detectNearestElement(entity, startOffset);
        if (nearestFocusState) {
          const { startNode, startOffset } = nearestFocusState;
          selectedNodes.push(startNode);
          this.currentRange = this.currentRange.updateRTERange({ startNode, endNode: startNode, startOffset, endOffset: startOffset }, range);
        }
        else {
          this.selectionMap.set(entity, []);
        }
      }
    }
  }
  /**
   * Detects the nearest element in the block at the given offset.
   *
   * @param {RTEBlock} block - The block to search within.
   * @param {number} offset - The offset to search from.
   * @returns {Nullable<FocusNodeRangeState>} - The detected element's range state or null if not found.
   */
  detectNearestElement(block, offset) {
    if (block.children) {
      const currentNode = block.children[offset];
      const prevNode = block.children[offset - 1];
      if (currentNode && currentNode instanceof RTENode) {
        return {
          startNode: currentNode,
          startOffset: 0,
        };
      }
      else if (prevNode && prevNode instanceof RTENode) {
        return {
          startNode: prevNode,
          startOffset: prevNode.getRangeEndOffset(),
        };
      }
    }
  }
}
SelectionController.SELECTION_CHANGE_DEBOUNCE_TIME = 50;
__decorate([
  MapToComponentField()
], SelectionController.prototype, "vegaRichTextEditorRenderer", void 0);
__decorate([
  MapToComponentField({ writable: true })
], SelectionController.prototype, "selectionMap", void 0);
__decorate([
  MapToComponentField()
], SelectionController.prototype, "host", void 0);
__decorate([
  MapToComponentField()
], SelectionController.prototype, "value", void 0);
__decorate([
  MapToComponentField()
], SelectionController.prototype, "disabled", void 0);
__decorate([
  MapToComponentField()
], SelectionController.prototype, "sourceView", void 0);
__decorate([
  MapToComponentField()
], SelectionController.prototype, "valueController", void 0);
__decorate([
  MapToComponentField()
], SelectionController.prototype, "insertCompositionTextController", void 0);
__decorate([
  MapToComponentField()
], SelectionController.prototype, "historyController", void 0);
__decorate([
  MapToComponentField()
], SelectionController.prototype, "internalCodeBlockSelectionController", void 0);
__decorate([
  MapToComponentMethod('connectedCallback')
], SelectionController.prototype, "connectedCallback", null);
__decorate([
  MapToComponentMethod('disconnectedCallback')
], SelectionController.prototype, "disconnectedCallback", null);
__decorate([
  MapToComponentMethod('componentDidLoad')
], SelectionController.prototype, "componentDidLoad", null);
__decorate([
  MapToComponentMethod('watchValueUpdate')
], SelectionController.prototype, "watchValueUpdate", null);

/**
 * An abstract class that manages the history of component values.
 */
class ComponentValueHistoryControllerSlimmer extends KeyboardManagerSlimmer {
  constructor() {
    super(() => this.getKeyboardShortcutOptions.call(this));
    this.redoStack = [];
    this.undoStack = [];
    this.registerHistoryDelay = 300;
    this.registerHistoryDebounced = debounce((state) => {
      this.internalRegisterHistory(state);
    }, this.registerHistoryDelay, this);
  }
  /**
   * Registers history based on the editor state.
   *
   * @typedef T generic type parameter
   * @param {T} editorState - The state to record in history.
   * @param {boolean} [isForce] - If true, the history will be registered immediately without debounce.
   */
  registerHistory(editorState, isForce = false) {
    if (isForce) {
      this.internalRegisterHistory(editorState);
    }
    else {
      this.registerHistoryDebounced(editorState);
    }
  }
  /**
   * Internal function to register history immediately.
   *
   * @typedef T generic type parameter
   * @param {T} state - The state to record in history.
   */
  internalRegisterHistory(state) {
    this.redoStack = []; // clear redo stack when new action happens.
    this.undoStack.push(state);
  }
  /**
   * Returns the keyboard shortcut options for undo/redo functionality.
   *
   * @returns {KeyboardEventListener[]} - An array of keyboard shortcut options.
   */
  getKeyboardShortcutOptions() {
    const baseOption = {
      keyCode: 'KeyZ',
      activeElementInScope: this.getEffectiveTargets(),
      activeElementOutScope: this.getIneffectiveTargets.bind(this),
      eventName: 'keydown',
      modifierPressed: true,
    };
    return [
      Object.assign(Object.assign({}, baseOption), { shiftKey: false, 
        /**
         * Callback function for the undo action.
         *
         * @param {KeyboardEvent} e - The keyboard event triggered by the user.
         */
        callback: (e) => {
          e.preventDefault();
          if (this.undoStack.length > 0) {
            void this.undo();
          }
        } }),
      Object.assign(Object.assign({}, baseOption), { shiftKey: true, 
        /**
         * Callback function for the redo action.
         *
         * @param {KeyboardEvent} e - The keyboard event triggered by the user.
         */
        callback: (e) => {
          e.preventDefault();
          if (this.redoStack.length > 0) {
            void this.redo();
          }
        } }),
    ];
  }
}

export { ComponentValueHistoryControllerSlimmer as C, RTESelectionState as R, ShadowSelectionPolyfill$1 as S, SelectionController as a };
