'use strict';

Object.defineProperty(exports, '__esModule', { value: true });

const index = require('./index-58ea899e.js');
const globalSlimmerRegistry = require('./global-slimmer-registry-b3bce7e0.js');
const componentUsageRuntimeMetrics = require('./component-usage-runtime-metrics-4572c5b7.js');
const component = require('./component-1e352960.js');
const internalIconManager = require('./internal-icon-manager-c989189a.js');
const trashCan = require('./trash-can-46a5e19a.js');
const domNodeSubjectObserverFactory = require('./dom-node-subject-observer-factory-ba6a95f3.js');
const vegaEventId = require('./vega-event-id-d9994eb3.js');
const codeBlock = require('./code-block-0ec03cd3.js');
const ui = require('./ui-3727d685.js');
const changeManager = require('./change-manager-a297e4d2.js');
const vegaInternalEventId = require('./vega-internal-event-id-87014e4f.js');
const eventEmitSlimmer = require('./event-emit-slimmer-8ba00d00.js');
const object = require('./object-b53e9416.js');
const translationSlimmer = require('./translation-slimmer-3cd7d3b2.js');
const componentValueHistoryControllerSlimmer_abstract = require('./component-value-history-controller-slimmer.abstract-b243e1e3.js');
const autoRunWhenReRenderTaskQueueSlimmer_abstract = require('./auto-run-when-re-render-task-queue-slimmer.abstract-5734634d.js');
const timer = require('./timer-5f33058b.js');
const childNodesEventPreventSlimmer = require('./child-nodes-event-prevent-slimmer-f3979a03.js');
const componentGlobalStyleSlimmer = require('./component-global-style-slimmer-93c5fb50.js');
require('./icon-manager-c12c6ea9.js');
require('./create-public-api-runtime-metrics-slimmer-9cb09fb2.js');
require('./dynamic-slimmer-f31fdfd7.js');
require('./misc-3d30df91.js');
require('./observer-f49483e8.js');
require('./string-39438062.js');
require('./type-guard-2e97fc56.js');
require('./breakpoints-ebde4837.js');
require('./ui-32120990.js');
require('./typography-4560e7f1.js');
require('./internal-translation-controller-8360a89c.js');
require('./static-subject-title-5829a298.js');
require('./dark-mode-style-controller-bd765afb.js');
require('./tinycolor-polyfill-502efaa8.js');
require('./vega-nonce-manager-df69d3ed.js');
require('./try-get-document-c0ebd39a.js');
require('./index-592b4052.js');
require('./internal-vega-event-manager-7e0d966d.js');
require('./range-a6c15539.js');
require('./keyboard-manager-slimmer-3824781d.js');
require('./keyboard-manager-d3cc662c.js');
require('./synchronize-task-queue-1ee80e94.js');
require('./vega-env-manager-23b8b23c.js');
require('./feature-flag-controller-9129ef52.js');
require('./index-f054eb5d.js');

var __decorate$c = (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 code block editor renderer class.
 */
class VegaCodeBlockRenderer extends globalSlimmerRegistry.VegaSlimmer {
  constructor() {
    super(...arguments);
    this.languageDropdownProps = {
      searchable: false,
    };
    this.languageOptions = Object.keys(codeBlock.CodeLanguage).map((key) => {
      return { id: codeBlock.CodeLanguage[key], displayName: key };
    });
    /**
     * Handle the code language update.
     *
     * @param {HTMLVegaInputSelectElement} node - The language select element.
     */
    this.handleLanguageChange = (node) => {
      domNodeSubjectObserverFactory.DomNodeSubjectObserverFactory.addUniqueObserverToNode(node, vegaEventId.VegaChange, (payload) => {
        var _a;
        this.valueController.updateValue((_a = this.value) === null || _a === void 0 ? void 0 : _a.code, payload.detail);
      });
    };
    /**
     * Handle the code language update.
     *
     * @param {HTMLVegaButtonCircleElement} node - The delete button.
     */
    this.handleDeleteClick = (node) => {
      domNodeSubjectObserverFactory.DomNodeSubjectObserverFactory.addUniqueObserverToNode(node, vegaEventId.VegaClick, () => {
        const event = this.removeEventEmitter.emit();
        if (!event.defaultPrevented) {
          this.host.remove();
        }
      });
    };
  }
  /**
   * Get the toolbar container element ref.
   *
   * @returns {HTMLDivElement} - The div element.
   */
  getToolbarContainerRef() {
    return this.toolbarContainerRef;
  }
  /**
   * Render the code block editor toolbar element or copy element.
   *
   * @returns {HTMLElement} - The code block operate action button.
   */
  render() {
    return (index.h(index.Fragment, null,
      index.h("div", { part: "editor-toolbar", contenteditable: false, class: {
          'editor-toolbar': !this.readOnly,
          'copy-button-container': this.showCopyButton && this.readOnly,
        }, ref: (node) => (this.toolbarContainerRef = node) },
        this.renderEditorToolbar(),
        this.copyButtonRenderer.render()),
      this.contentRenderer.render()));
  }
  /**
   * Render a language select and delete button.
   *
   * @returns {Nullable<HTMLElement>} The editor toolbar container element.
   */
  renderEditorToolbar() {
    var _a, _b;
    if (!this.readOnly) {
      return (index.h(index.Fragment, null,
        index.h("vega-input-select", { source: this.languageOptions, value: (_b = (_a = this.value) === null || _a === void 0 ? void 0 : _a.language) !== null && _b !== void 0 ? _b : '', disabled: this.disabled, placeholder: this.translationSlimmer.t('Select Language'), size: "small", vegaDropdownProps: this.languageDropdownProps, exportparts: "select-container, selected-box, placeholder, toggle-icon-container, toggle-icon", ref: this.handleLanguageChange }),
        index.h("vega-button-circle", { key: "delete-button", disabled: this.disabled, label: this.translationSlimmer.t('Delete Code'), icon: internalIconManager.VegaInternalIconManager.getIconKey('trash-can'), iconColor: "text-secondary", variant: "icon-only", size: "extra-small", ref: this.handleDeleteClick })));
    }
  }
}
(() => {
  internalIconManager.VegaInternalIconManager.register({
    'trash-can': trashCan.trashCan,
  });
})();
__decorate$c([
  globalSlimmerRegistry.MapToComponentField()
], VegaCodeBlockRenderer.prototype, "readOnly", void 0);
__decorate$c([
  globalSlimmerRegistry.MapToComponentField()
], VegaCodeBlockRenderer.prototype, "host", void 0);
__decorate$c([
  globalSlimmerRegistry.MapToComponentField()
], VegaCodeBlockRenderer.prototype, "disabled", void 0);
__decorate$c([
  globalSlimmerRegistry.MapToComponentField()
], VegaCodeBlockRenderer.prototype, "showCopyButton", void 0);
__decorate$c([
  globalSlimmerRegistry.MapToComponentField()
], VegaCodeBlockRenderer.prototype, "value", void 0);
__decorate$c([
  globalSlimmerRegistry.MapToComponentField()
], VegaCodeBlockRenderer.prototype, "contentRenderer", void 0);
__decorate$c([
  globalSlimmerRegistry.MapToComponentField()
], VegaCodeBlockRenderer.prototype, "valueController", void 0);
__decorate$c([
  globalSlimmerRegistry.MapToComponentField()
], VegaCodeBlockRenderer.prototype, "removeEventEmitter", void 0);
__decorate$c([
  globalSlimmerRegistry.MapToComponentField()
], VegaCodeBlockRenderer.prototype, "translationSlimmer", void 0);
__decorate$c([
  globalSlimmerRegistry.MapToComponentField()
], VegaCodeBlockRenderer.prototype, "copyButtonRenderer", void 0);

var __decorate$b = (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 code block content renderer class.
 */
class VegaCodeBlockContentRenderer extends globalSlimmerRegistry.VegaSlimmer {
  constructor() {
    super(...arguments);
    /**
     * The code input area focus.
     */
    this.handleFocus = () => {
      if (!this.readOnly && !this.disabled) {
        this.host.classList.add('focus');
      }
    };
    /**
     * The code input area blur.
     */
    this.handleBlur = () => {
      this.host.classList.remove('focus');
      changeManager.ChangeManager.notify(domNodeSubjectObserverFactory.domNodeSubjectFactory.getSubject(this.host, vegaInternalEventId.VegaInternalCodeBlockBlur), null);
    };
  }
  /**
   * Get the editable root element.
   *
   * @returns {HTMLElement} - The root element.
   */
  getCodeContentContainerRef() {
    return this.codeContentContainerRef;
  }
  /**
   * Add focus and blur event listener.
   */
  registerEventListener() {
    if (this.codeContentContainerRef) {
      this.codeContentContainerRef.addEventListener('focusin', this.handleFocus);
      this.codeContentContainerRef.addEventListener('focusout', this.handleBlur);
    }
  }
  /**
   * Remove the event listener.
   */
  unregisterEventListener() {
    if (this.codeContentContainerRef) {
      this.codeContentContainerRef.removeEventListener('focusin', this.handleFocus);
      this.codeContentContainerRef.removeEventListener('focusout', this.handleBlur);
    }
  }
  /**
   * Render the code content.
   *
   * @returns {HTMLElement} - The code element.
   */
  render() {
    var _a;
    const codeNodes = this.contentParseController.parseCode();
    const language = ((_a = this.value) === null || _a === void 0 ? void 0 : _a.language) || '';
    return (index.h(index.Fragment, null,
      index.h("style", null, this.getLineNumberStyleVariable(codeNodes)),
      index.h("code", { role: "textbox", tabIndex: 0, spellcheck: false, ref: (node) => (this.codeContentContainerRef = node), contenteditable: this.readOnly || this.disabled ? false : true, "data-language": language, innerHTML: codeNodes
          .map((codeNode) => this.renderCodeNode(codeNode))
          .join('') })));
  }
  /**
   * Render the code node the html element.
   *
   * @param {CodeNodeType} codeNode - The code node object.
   * @returns {string} - The html element.
   */
  renderCodeNode(codeNode) {
    const { key, className, mark, text } = codeNode;
    return `<span key='${key}' class='${className}' data-mark='${mark}' data-index='${key}'>${text}</span>`;
  }
  /**
   * Dynamic calculate line number element width and update the margin and padding variable.
   *
   * @param {CodeNodeType[]} codeNodes - The code node array.
   * @returns {string} - The style content.
   */
  getLineNumberStyleVariable(codeNodes) {
    const lineCountArray = codeNodes.filter((item) => {
      return item.text === '\n';
    });
    const singleTextLength = 10;
    const gap = 16;
    const space = (lineCountArray.length + 1).toString().length * singleTextLength;
    return `code{--v-code-line-number-width:${space}px;--v-code-line-number-ml:-${space + gap}px;--v-code-block-pl:${space + gap}px}`;
  }
}
__decorate$b([
  globalSlimmerRegistry.MapToComponentField()
], VegaCodeBlockContentRenderer.prototype, "host", void 0);
__decorate$b([
  globalSlimmerRegistry.MapToComponentField()
], VegaCodeBlockContentRenderer.prototype, "readOnly", void 0);
__decorate$b([
  globalSlimmerRegistry.MapToComponentField()
], VegaCodeBlockContentRenderer.prototype, "disabled", void 0);
__decorate$b([
  globalSlimmerRegistry.MapToComponentField()
], VegaCodeBlockContentRenderer.prototype, "value", void 0);
__decorate$b([
  globalSlimmerRegistry.MapToComponentField()
], VegaCodeBlockContentRenderer.prototype, "contentParseController", void 0);
__decorate$b([
  globalSlimmerRegistry.MapToComponentMethod('componentDidLoad')
], VegaCodeBlockContentRenderer.prototype, "registerEventListener", null);
__decorate$b([
  globalSlimmerRegistry.MapToComponentMethod('disconnectedCallback')
], VegaCodeBlockContentRenderer.prototype, "unregisterEventListener", null);

var __decorate$a = (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 component value controller.
 */
class VegaCodeBlockValueController extends globalSlimmerRegistry.VegaSlimmer {
  /**
   * Update the component value if code content or code language update.
   *
   * @param {string} code - The new code content.
   * @param {string} language - The new code language.
   * @param {CodeBlockHistoryState} codeBlockHistoryState - Update the history or not.
   */
  updateValue(code, language, codeBlockHistoryState) {
    if (!this.value || this.value.code !== code || this.value.language !== language) {
      this.value = {
        language: language,
        code,
      };
      this.changeEventEmitter.emit(this.value);
      if (codeBlockHistoryState && codeBlockHistoryState.recordHistory) {
        this.historyController.registerHistory({
          value: this.value,
          offset: codeBlockHistoryState.offset,
        });
      }
    }
  }
  /**
   * Set a default value if the value is not defined.
   */
  initialValue() {
    if (!this.value) {
      this.value = { code: '', language: 'plainText' };
    }
  }
}
__decorate$a([
  globalSlimmerRegistry.MapToComponentField({ writable: true })
], VegaCodeBlockValueController.prototype, "value", void 0);
__decorate$a([
  globalSlimmerRegistry.MapToComponentField()
], VegaCodeBlockValueController.prototype, "changeEventEmitter", void 0);
__decorate$a([
  globalSlimmerRegistry.MapToComponentField()
], VegaCodeBlockValueController.prototype, "historyController", void 0);
__decorate$a([
  globalSlimmerRegistry.MapToComponentMethod('connectedCallback')
], VegaCodeBlockValueController.prototype, "initialValue", null);

var __decorate$9 = (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;
};
/**
 * Parse the code content to different tokens.
 */
class CodeContentParseController extends globalSlimmerRegistry.VegaSlimmer {
  constructor() {
    super(...arguments);
    this.codeNodes = [];
  }
  /**
   * Get the current rendering code node array.
   *
   * @returns {CodeNodeType[]} - The code node array.
   */
  getCurrentCodeNodes() {
    return this.codeNodes;
  }
  /**
   * Split the code content to code node array. The default parse used if the language is not defined.
   *
   * @returns {CodeNodeType[]} - The code node array.
   */
  parseCode() {
    const parsers = [
      this.prismCodeHighlightParser,
      this.defaultCodeHighlightParser,
    ];
    let result = [];
    for (const parser of parsers) {
      if (parser.canParse()) {
        result = parser.parse();
        break;
      }
    }
    this.codeNodes = result;
    return result;
  }
}
__decorate$9([
  globalSlimmerRegistry.MapToComponentField()
], CodeContentParseController.prototype, "prismCodeHighlightParser", void 0);
__decorate$9([
  globalSlimmerRegistry.MapToComponentField()
], CodeContentParseController.prototype, "defaultCodeHighlightParser", void 0);

/**
 * The code block component range class.
 */
class CodeBlockRange {
  /**
   * Initial the code block range.
   *
   * @param {HTMLElement} codeContainerRef - The code content container ref.
   */
  constructor(codeContainerRef) {
    // The cursor position.
    this.contentOffset = 0;
    // The range selected text, the value will be empty if the range is collapsed.
    this.selectedText = '';
    this.codeContainerRef = codeContainerRef;
  }
  /**
   * Update the code block range when the focus node changed or focus node content changed.
   *
   * @param {Node} startContainer - The focus node instance.
   * @param {number} startOffset - The focus offset.
   * @param {CodeNodeType[]} currentNodes - The current code node array.
   * @param {string} [selectedText] - The range selected text.
   * @returns {CodeBlockRange} - The new code block range instance.
   */
  updateRange(startContainer, startOffset, currentNodes, selectedText = '') {
    const range = new CodeBlockRange(this.codeContainerRef);
    range.selectedText = selectedText;
    range.contentOffset = range.getContentOffset(startContainer, startOffset, currentNodes);
    return range;
  }
  /**
   * Update the cursor position when insert text or delete text...
   *
   * @param {number} newContentOffset - New value for content offset.
   * @returns {number} - The new content offset.
   */
  updateContentOffset(newContentOffset) {
    this.contentOffset = Math.max(0, newContentOffset);
    this.selectedText = '';
    return this.contentOffset;
  }
  /**
   * Create a native range from the current code block range.
   *
   * @param {CodeNodeType[]} nextCodeNodes - The code block node array.
   * @returns {Nullable<Range>} - The range instance.
   */
  createNativeRange(nextCodeNodes) {
    const { nodeIndex, offset } = this.getFocusNodeState(nextCodeNodes, this.contentOffset);
    const range = new Range();
    const focusNode = this.codeContainerRef.querySelector(`span[data-index="${nodeIndex}"]`);
    if (focusNode) {
      const startOffset = Math.min(focusNode.firstChild.textContent.length, offset);
      range.setStart(focusNode.firstChild, startOffset);
      range.setEnd(focusNode.firstChild, startOffset);
      return range;
    }
  }
  /**
   * Calculate the cursor position.
   *
   * @param {Node} startContainer - The cursor node.
   * @param {number} startOffset - The cursor offset.
   * @param {CodeNodeType[]} currentNodes - The code block node array.
   * @returns {number} - A number value.
   */
  getContentOffset(startContainer, startOffset, currentNodes) {
    let startSpan = startContainer.nodeType === Node.TEXT_NODE
      ? startContainer.parentElement
      : startContainer;
    if (startSpan.nodeName === 'CODE' && startSpan.childNodes && startSpan.childNodes.length) {
      startSpan = startSpan.childNodes[Math.min(startOffset, startSpan.childNodes.length - 1)];
      startOffset = 0;
    }
    if (startSpan && startSpan.hasAttribute('data-index')) {
      const index = Number(startSpan.dataset.index);
      let beforeText = '';
      for (let i = 0; i < index; i++) {
        beforeText += currentNodes[i].text;
      }
      return beforeText.length + startOffset;
    }
    return 0;
  }
  /**
   * Get the next focus node of the code block node array.
   *
   * @param {CodeNodeType[]} codeNodes - The current code block array.
   * @param {number} contentOffset - The cursor position.
   * @returns {FocusNodeStateType} - The object contains next focus node index and offset.
   */
  getFocusNodeState(codeNodes, contentOffset) {
    const content = this.getCodeContent(codeNodes);
    const result = { nodeIndex: 0, offset: 0 };
    if (!content || contentOffset >= content.length) {
      result.nodeIndex = codeNodes.length - 1;
      result.offset = codeNodes[result.nodeIndex].text.length;
    }
    else {
      let text = '';
      for (let i = 0; i < codeNodes.length; i++) {
        text += codeNodes[i].text;
        if (text.length >= contentOffset) {
          result.offset = Math.max(0, codeNodes[i].text.length - (text.length - contentOffset));
          result.nodeIndex = i;
          break;
        }
      }
    }
    // The cursor position is incorrect in firefox when cursor node is line break node.
    if (codeNodes[result.nodeIndex].text === '\n' &&
      result.offset > 0 &&
      codeNodes[result.nodeIndex + 1]) {
      result.nodeIndex += 1;
      result.offset = 0;
    }
    return result;
  }
  /**
   * Get all code content from the code block node array.
   *
   * @param {CodeNodeType[]} codeNodes - The code block node array.
   * @returns {string} - The code content.
   */
  getCodeContent(codeNodes) {
    return codeNodes.map((codeNode) => codeNode.text).join('');
  }
}

var __decorate$8 = (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 class used to control the code block input cursor.
 */
class VegaCodeBlockSelectionController extends autoRunWhenReRenderTaskQueueSlimmer_abstract.AutoRunWhenReRenderTaskQueueSlimmer {
  constructor() {
    super(1);
    this.handleSelectionWithDebounce = timer.debounce(this.handleSelectionChange, VegaCodeBlockSelectionController.SELECTION_CHANGE_DEBOUNCE_TIME, this);
    /**
     * 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 selection = this.getSelection();
      const range = this.codeBlockRange.createNativeRange(this.contentParseController.getCurrentCodeNodes());
      if (selection && range) {
        selection.removeAllRanges();
        selection.addRange(range);
      }
    };
  }
  /**
   * Get current range instance.
   *
   * @returns {Nullable<CodeBlockRange>} - The range instance or null.
   */
  getCurrentRange() {
    return this.codeBlockRange;
  }
  /**
   * Update the text content offset, push the update native range task to a queue.
   *
   * @param {number} contentOffset - The next content offset.
   * @param {boolean} [immediatelyRun] - Run the task immediately or not.
   */
  setNextCodeBlockRange(contentOffset, immediatelyRun = false) {
    this.codeBlockRange.updateContentOffset(contentOffset);
    super.enqueueTheTaskIntoQueue(immediatelyRun);
  }
  /**
   * Component lifecycle
   */
  addSelectionChangeEventListener() {
    this.codeBlockRange = new CodeBlockRange(this.contentRenderer.getCodeContentContainerRef());
    // eslint-disable-next-line no-restricted-globals
    document.addEventListener('selectionchange', this.handleSelectionWithDebounce);
  }
  /**
   * Component lifecycle
   */
  removeSelectionChangeEventListener() {
    // eslint-disable-next-line no-restricted-globals
    document.removeEventListener('selectionchange', this.handleSelectionWithDebounce);
  }
  /**
   * Get the code block selected range
   *
   * @returns {Selection} A [Selection](https://developer.mozilla.org/en-US/docs/Web/API/Selection) object
   */
  getSelection() {
    return componentValueHistoryControllerSlimmer_abstract.ShadowSelectionPolyfill.getSelection(this.host.shadowRoot);
  }
  /**
   * Notify the code content selection change event.
   */
  handleSelectionChange() {
    const selection = this.getSelection();
    if (selection && selection.rangeCount > 0) {
      this.syncCodeRangeByNativeRange();
      changeManager.ChangeManager.notify(domNodeSubjectObserverFactory.domNodeSubjectFactory.getSubject(this.host, vegaInternalEventId.VegaInternalCodeBlockSelectionChange), { detail: true });
    }
    else {
      changeManager.ChangeManager.notify(domNodeSubjectObserverFactory.domNodeSubjectFactory.getSubject(this.host, vegaInternalEventId.VegaInternalCodeBlockSelectionChange), { detail: false });
    }
  }
  /**
   * Sync the code block range to make sure the code block range content offset is up to date after user click or selected text.
   */
  syncCodeRangeByNativeRange() {
    const selection = this.getSelection();
    if (this.isCodeBlockActive() &&
      this.autoRunTaskQueue.queue.length === 0 &&
      !this.insertCompositionTextController.isComposing()) {
      const range = selection.getRangeAt(0);
      const { startContainer, startOffset } = range;
      this.codeBlockRange = this.codeBlockRange.updateRange(startContainer, startOffset, this.contentParseController.getCurrentCodeNodes(), range.toString());
    }
  }
  /**
   * This method is used to determine if the code block is currently focused or active.
   * In firefox and safari, the selection change event will trigger when the code block is not active, because the shadow selection polyfill will always return the selection of the code block.
   *
   * @returns {boolean} - Returns true if the code block is active, otherwise false.
   */
  isCodeBlockActive() {
    return this.host && this.host.classList.contains('focus');
  }
}
// Must make sure the debounce time will not greater than the RTE selection range debounce time.
VegaCodeBlockSelectionController.SELECTION_CHANGE_DEBOUNCE_TIME = Math.min(componentValueHistoryControllerSlimmer_abstract.SelectionController.SELECTION_CHANGE_DEBOUNCE_TIME, 40);
__decorate$8([
  globalSlimmerRegistry.MapToComponentField()
], VegaCodeBlockSelectionController.prototype, "host", void 0);
__decorate$8([
  globalSlimmerRegistry.MapToComponentField()
], VegaCodeBlockSelectionController.prototype, "contentRenderer", void 0);
__decorate$8([
  globalSlimmerRegistry.MapToComponentField()
], VegaCodeBlockSelectionController.prototype, "contentParseController", void 0);
__decorate$8([
  globalSlimmerRegistry.MapToComponentField()
], VegaCodeBlockSelectionController.prototype, "insertCompositionTextController", void 0);
__decorate$8([
  globalSlimmerRegistry.MapToComponentMethod('componentDidLoad')
], VegaCodeBlockSelectionController.prototype, "addSelectionChangeEventListener", null);
__decorate$8([
  globalSlimmerRegistry.MapToComponentMethod('disconnectedCallback')
], VegaCodeBlockSelectionController.prototype, "removeSelectionChangeEventListener", null);

/**
 * The abstract class used to control the code block input paste action.
 */
class CodeInputPaste extends globalSlimmerRegistry.VegaSlimmer {
  /**
   * Delete the selected text from a string.
   *
   * @param {string} oldValue - The original string value.
   * @param {number} contentStartOffset - The start index for deletion.
   * @param {number} length - The length of text to delete.
   * @returns {string} The content after deletion.
   */
  deleteSelectedText(oldValue, contentStartOffset, length) {
    if (length >= oldValue.length) {
      oldValue = '';
    }
    else {
      oldValue = oldValue.slice(0, contentStartOffset) + oldValue.slice(contentStartOffset + length);
    }
    return oldValue;
  }
  /**
   * Collect the code nodes content from the code nodes array.
   *
   * @param {CodeNodeType[]} codeNodes - The code nodes array.
   * @returns {string} The concatenated content of code nodes.
   */
  getCodeNodesContent(codeNodes) {
    return codeNodes.map((codeNode) => codeNode.text).join('');
  }
  /**
   * Stop event propagation.
   *
   * @param {Event} e - The event object.
   */
  stopEventPropagation(e) {
    if (e && typeof e.stopPropagation === 'function') {
      e.stopPropagation();
    }
  }
  /**
   * Re-calculate the next offset and content after insert or delete operation.
   *
   * @param {CodeBlockRange} range - The current code block range.
   * @param {string} content - The current code content.
   * @param {string} newlyAddedContent - The new content to be inserted.
   * @returns {NextOffsetAndContentResult} The next offset and updated content.
   */
  reCalculateRangeAndContent(range, content, newlyAddedContent) {
    let nextOffset = range.contentOffset;
    let updatedContent = content;
    if (range) {
      if (range.selectedText.length) {
        updatedContent = this.deleteSelectedText(updatedContent, range.contentOffset, range.selectedText.length);
      }
      updatedContent =
        updatedContent.slice(0, range.contentOffset) +
          newlyAddedContent +
          updatedContent.slice(range.contentOffset);
      nextOffset = range.contentOffset + newlyAddedContent.length;
    }
    return { nextOffset, updatedContent };
  }
}

var __decorate$7 = (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 class used to control the code block modify content action.
 */
class CodeBlockInputController extends CodeInputPaste {
  constructor() {
    super(...arguments);
    /**
     * Stop the input event bubbles and update the code value.
     *
     * @param {InputEvent} e - The input event object.
     */
    this.handleInputEvent = (e) => {
      this.stopEventPropagation(e);
      this.updateCodeContent();
    };
    /**
     * Prevent paste the file into code block. Prevent to delete the last space.
     *
     * @param {InputEvent} e - The input event object.
     */
    this.handleBeforeInput = (e) => {
      e.stopPropagation();
      const inputType = e.inputType;
      switch (inputType) {
        case 'deleteContentBackward':
          if (!this.value || !this.value.code || this.value.code === '') {
            e.preventDefault();
          }
          else {
            this.handleDeleteAction(e);
          }
          return;
        case 'historyUndo':
        case 'historyRedo':
          e.preventDefault();
          return;
      }
      this.updateCodeBlockRange(e);
    };
  }
  /**
   * Stop `beforeinput` and `input` event bubbles to parent element.
   */
  registerInputEvent() {
    const codeContentContainerRef = this.contentRenderer.getCodeContentContainerRef();
    if (codeContentContainerRef) {
      codeContentContainerRef.addEventListener('beforeinput', this.handleBeforeInput);
      codeContentContainerRef.addEventListener('input', this.handleInputEvent);
    }
  }
  /**
   * Remove the event listener.
   */
  unregisterEventListener() {
    const codeContentContainerRef = this.contentRenderer.getCodeContentContainerRef();
    if (codeContentContainerRef) {
      codeContentContainerRef.removeEventListener('beforeinput', this.handleBeforeInput);
      codeContentContainerRef.removeEventListener('input', this.handleInputEvent);
    }
  }
  /**
   * Modify the component code content when user press delete key.
   *
   * @param {InputEvent} e - The input event object.
   */
  handleDeleteAction(e) {
    const range = this.selectionController.getCurrentRange();
    if (range) {
      e.preventDefault();
      const contentStartOffset = range.contentOffset;
      const currentNodes = this.contentParseController.getCurrentCodeNodes();
      let content = this.getCodeNodesContent(currentNodes);
      let nextOffset = contentStartOffset;
      // In low version firefox, the selected text could not delete when press delete key, so we handle the action manually.
      if (range.selectedText.length) {
        content = this.deleteSelectedText(content, contentStartOffset, range.selectedText.length);
      }
      else if (contentStartOffset > 0) {
        content = content.slice(0, contentStartOffset - 1) + content.slice(contentStartOffset);
        nextOffset -= 1;
      }
      this.selectionController.setNextCodeBlockRange(nextOffset);
      this.valueController.updateValue(content, this.value.language, {
        recordHistory: true,
        offset: nextOffset,
      });
    }
  }
  /**
   * Update the code block range base on input data.
   *
   * @param {InputEvent} e - The input event object.
   */
  updateCodeBlockRange(e) {
    const range = this.selectionController.getCurrentRange();
    if (!this.insertCompositionTextController.isComposing() && range) {
      this.selectionController.setNextCodeBlockRange(range.contentOffset + this.getInsertDataLength(e));
    }
  }
  /**
   * Calculates the length of the inserted data based on the input event type.
   *
   * @param {InputEvent} e - The input event object.
   * @returns {number} - The length of the inserted data.
   */
  getInsertDataLength(e) {
    const { data, inputType } = e;
    switch (inputType) {
      case 'insertText':
        return data.length; // For insert text, we return the length of the inserted text.
      case 'insertParagraph':
      case 'insertLineBreak':
        return 1;
      default:
        return 0; // For other input types, we return 0.
    }
  }
  /**
   * Update the code content after user modify action.
   */
  updateCodeContent() {
    var _a;
    if (!this.insertCompositionTextController.isComposing()) {
      const codeContentContainerRef = this.contentRenderer.getCodeContentContainerRef();
      let newText = codeContentContainerRef.innerText;
      if (this.isInsertLineBreakInLowVersionFirefox(newText)) {
        newText = newText + '\n';
      }
      this.valueController.updateValue(newText, (_a = this.value) === null || _a === void 0 ? void 0 : _a.language, {
        recordHistory: true,
        offset: this.selectionController.getCurrentRange().contentOffset,
      });
    }
  }
  /**
   * Check if the new content update by insert line break in low version Firefox.
   *
   * @param {string} newText - The new text content.
   * @returns {boolean} - Boolean value.
   */
  isInsertLineBreakInLowVersionFirefox(newText) {
    var _a;
    const oldValue = ((_a = this.value) === null || _a === void 0 ? void 0 : _a.code) || '';
    if (!oldValue.endsWith('\n') && newText === oldValue + '\n') {
      return true;
    }
    return false;
  }
}
__decorate$7([
  globalSlimmerRegistry.MapToComponentField()
], CodeBlockInputController.prototype, "selectionController", void 0);
__decorate$7([
  globalSlimmerRegistry.MapToComponentField()
], CodeBlockInputController.prototype, "contentRenderer", void 0);
__decorate$7([
  globalSlimmerRegistry.MapToComponentField()
], CodeBlockInputController.prototype, "valueController", void 0);
__decorate$7([
  globalSlimmerRegistry.MapToComponentField()
], CodeBlockInputController.prototype, "contentParseController", void 0);
__decorate$7([
  globalSlimmerRegistry.MapToComponentField()
], CodeBlockInputController.prototype, "insertCompositionTextController", void 0);
__decorate$7([
  globalSlimmerRegistry.MapToComponentField()
], CodeBlockInputController.prototype, "value", void 0);
__decorate$7([
  globalSlimmerRegistry.MapToComponentMethod('componentDidLoad')
], CodeBlockInputController.prototype, "registerInputEvent", null);
__decorate$7([
  globalSlimmerRegistry.MapToComponentMethod('disconnectedCallback')
], CodeBlockInputController.prototype, "unregisterEventListener", null);

var __decorate$6 = (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;
};
/**
 * Control the component focus state.
 */
class VegaCodeBlockFocusController extends globalSlimmerRegistry.VegaSlimmer {
  /**
   * Focus the code block and update the selection range offset to end.
   */
  focusAndUpdateSelection() {
    if (!this.disabled && !this.readOnly) {
      const codeContentContainerRef = this.contentRenderer.getCodeContentContainerRef();
      if (codeContentContainerRef) {
        codeContentContainerRef.focus();
        const offset = this.value && this.value.code && this.value.code !== ' ' ? this.value.code.length : 0;
        this.selectionController.setNextCodeBlockRange(offset, true);
      }
    }
  }
  /**
   * Remove the focus class when component disabled or readonly.
   */
  removeFocusAfterDisabled() {
    if (this.disabled || this.readOnly) {
      this.host.classList.remove('focus');
    }
  }
}
__decorate$6([
  globalSlimmerRegistry.MapToComponentField()
], VegaCodeBlockFocusController.prototype, "host", void 0);
__decorate$6([
  globalSlimmerRegistry.MapToComponentField()
], VegaCodeBlockFocusController.prototype, "value", void 0);
__decorate$6([
  globalSlimmerRegistry.MapToComponentField()
], VegaCodeBlockFocusController.prototype, "readOnly", void 0);
__decorate$6([
  globalSlimmerRegistry.MapToComponentField()
], VegaCodeBlockFocusController.prototype, "disabled", void 0);
__decorate$6([
  globalSlimmerRegistry.MapToComponentField()
], VegaCodeBlockFocusController.prototype, "contentRenderer", void 0);
__decorate$6([
  globalSlimmerRegistry.MapToComponentField()
], VegaCodeBlockFocusController.prototype, "selectionController", void 0);
__decorate$6([
  globalSlimmerRegistry.MapToComponentMethod('doFocus')
], VegaCodeBlockFocusController.prototype, "focusAndUpdateSelection", null);
__decorate$6([
  globalSlimmerRegistry.MapToComponentMethod('watchEditableChange')
], VegaCodeBlockFocusController.prototype, "removeFocusAfterDisabled", null);

const copy = {
  icon: `<svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" viewBox="0 0 12 12"><g clip-path="url(#clip0_70002_574)"><path fill="currentColor" d="M11.7794 1.65539L10.3439 0.219844C10.2044 0.0790078 10.0122 0 9.81303 0H5.97865C5.15014 0 4.47865 0.671719 4.47865 1.5L4.47911 7.5C4.49975 8.32969 5.1724 9 5.99975 9H10.4997C11.3247 9 11.9997 8.325 11.9997 7.5V2.18555C11.9997 1.9868 11.9201 1.79602 11.7794 1.65539ZM10.8747 7.5C10.8747 7.70709 10.7068 7.875 10.4997 7.875H5.97865C5.77151 7.875 5.60365 7.70709 5.60365 7.5V1.50305C5.60365 1.29595 5.77156 1.12805 5.97865 1.12805H8.97865L8.99975 2.25C8.99975 2.66414 9.33561 3 9.74975 3H10.8537V7.5H10.8747ZM6.37475 10.5C6.37475 10.7071 6.20684 10.875 5.99975 10.875H1.47865C1.27151 10.875 1.10365 10.7071 1.10365 10.5L1.12428 4.50234C1.12428 4.29525 1.29218 4.12734 1.49928 4.12734H3.74975V3H1.49951C0.670996 3 -0.000488281 3.67148 -0.000488281 4.5L-0.000258594 10.5C-0.000207031 11.3273 0.671465 12 1.49975 12H5.99975C6.82475 12 7.49975 11.325 7.49975 10.5V9.75H6.39584L6.37475 10.5Z"/></g><defs><clipPath id="clip0_70002_574"><rect width="12" height="12" fill="currentColor"/></clipPath></defs></svg>`,
};

var __decorate$5 = (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;
};
class VegaCodeBlockCopyButtonRenderer extends globalSlimmerRegistry.VegaSlimmer {
  constructor() {
    super(...arguments);
    /**
     * Copy the code.
     *
     * @param {HTMLVegaButtonCircleElement} node - The copy button.
     */
    this.handleCopyClick = (node) => {
      domNodeSubjectObserverFactory.DomNodeSubjectObserverFactory.addUniqueObserverToNode(node, vegaEventId.VegaClick, async () => {
        var _a;
        const content = ((_a = this.value) === null || _a === void 0 ? void 0 : _a.code) || '';
        if (content && globalThis.navigator && globalThis.navigator.clipboard) {
          clearTimeout(this.updateLabelTimer);
          await globalThis.navigator.clipboard.writeText(content);
          const oldTooltip = node.label;
          node.label = this.translationSlimmer.t('Copied');
          this.updateLabelTimer = setTimeout(() => {
            if (node) {
              node.label = oldTooltip;
            }
          }, VegaCodeBlockCopyButtonRenderer.RESET_TOOLTIP_TIME);
        }
      });
    };
  }
  /**
   * Render a copy button.
   *
   * @returns {Nullable<HTMLElement>} The button element.
   */
  render() {
    if (this.showCopyButton && this.readOnly) {
      return (index.h("vega-button-circle", { key: "copy-button", label: this.translationSlimmer.t('Copy Code'), class: "copy-code-button", icon: internalIconManager.VegaInternalIconManager.getIconKey('copy'), iconColor: "text-secondary", variant: "icon-only", size: "extra-small", ref: this.handleCopyClick }));
    }
  }
}
(() => {
  internalIconManager.VegaInternalIconManager.register({
    copy: copy,
  });
})();
VegaCodeBlockCopyButtonRenderer.RESET_TOOLTIP_TIME = 1000;
__decorate$5([
  globalSlimmerRegistry.MapToComponentField()
], VegaCodeBlockCopyButtonRenderer.prototype, "value", void 0);
__decorate$5([
  globalSlimmerRegistry.MapToComponentField()
], VegaCodeBlockCopyButtonRenderer.prototype, "readOnly", void 0);
__decorate$5([
  globalSlimmerRegistry.MapToComponentField()
], VegaCodeBlockCopyButtonRenderer.prototype, "showCopyButton", void 0);
__decorate$5([
  globalSlimmerRegistry.MapToComponentField()
], VegaCodeBlockCopyButtonRenderer.prototype, "translationSlimmer", void 0);

/**
 * Unique placeholder used to mark greedy-matched regions so they are not
 * re-tokenized by later grammar rules.  The surrounding curly-brace pairs
 * make an accidental collision with real source code extremely unlikely.
 */
const GREEDY_PLACEHOLDER = '\x00GREEDY_PLACEHOLDER\x00';
/**
 * Core tokenizer that converts source code into syntax tokens based on a grammar definition.
 * This is a local replacement for Prism tokenize.
 *
 * The tokenizer works by:
 * 1. Pre-processing greedy patterns to claim their matched regions first
 * 2. Iterating through all grammar rules in order
 * 3. Finding regex matches in the source text
 * 4. Splitting the text into matched (typed) and unmatched (plain) segments
 * 5. Recursively tokenizing nested content when an `inside` grammar is specified
 *
 * @param {string} code - The source code string to tokenize.
 * @param {Grammar} grammar - The grammar rules to apply for tokenization.
 * @returns {(string | SyntaxToken)[]} An array of plain strings and syntax tokens.
 */
function tokenize(code, grammar) {
  if (!code || !grammar) {
    return [code];
  }
  const tokens = [code];
  matchGrammar(tokens, grammar);
  return tokens;
}
/**
 * Apply grammar rules to tokenize string entries in the token list.
 * Greedy patterns are applied first: their matched regions are replaced with
 * opaque placeholder tokens so that subsequent (non-greedy) rules cannot
 * match inside those regions.  After all rules have run the placeholders are
 * restored to the original matched text.
 *
 * @param {(string | SyntaxToken)[]} tokens - The current token list to process in-place.
 * @param {Grammar} grammar - The grammar rules to apply.
 */
function matchGrammar(tokens, grammar) {
  const greedyEntries = [];
  const nonGreedyEntries = [];
  for (const tokenType of Object.keys(grammar)) {
    const grammarEntry = grammar[tokenType];
    const patterns = Array.isArray(grammarEntry) ? grammarEntry : [grammarEntry];
    for (const patternDef of patterns) {
      if (patternDef.greedy) {
        greedyEntries.push({ tokenType, patternDef });
      }
      else {
        nonGreedyEntries.push({ tokenType, patternDef });
      }
    }
  }
  // --- Phase 1: Apply greedy patterns first --------------------------------
  // Greedy patterns claim regions of the source text exclusively.
  // We replace matched regions with a placeholder string of equal length so
  // that character offsets remain stable.  Each greedy match is recorded so
  // we can later restore the original text inside the token.
  if (greedyEntries.length > 0) {
    applyGreedyPatterns(tokens, greedyEntries);
  }
  // --- Phase 2: Apply remaining non-greedy patterns ------------------------
  for (const { tokenType, patternDef } of nonGreedyEntries) {
    applyPattern(tokens, tokenType, patternDef);
  }
}
/**
 * Process all greedy patterns against the current token list.
 *
 * For every plain-string entry in the list the function builds a *mask* string
 * of the same length.  Greedy matches are recorded and their corresponding
 * character ranges in the mask are overwritten with a placeholder character so
 * that later greedy patterns (and all non-greedy patterns) will never match
 * inside an already-claimed region.
 *
 * After all greedy patterns have been collected the affected string entries are
 * rebuilt by splicing in SyntaxToken objects for each greedy match.
 *
 * @param {(string | SyntaxToken)[]} tokens - The token list to process in-place.
 * @param {{ tokenType: string; patternDef: GrammarPattern }[]} greedyEntries - Greedy patterns to apply.
 */
function applyGreedyPatterns(tokens, greedyEntries) {
  for (let i = 0; i < tokens.length; i++) {
    const token = tokens[i];
    /* istanbul ignore next -- defensive: greedy phase only sees strings from initial tokenize() call */
    if (typeof token !== 'string') {
      continue;
    }
    // Build the full text by concatenating all consecutive string segments
    // so greedy regex can match across them — but for simplicity we operate
    // per-segment, which matches prismjs behavior for the patterns we use.
    const originalText = token;
    // Mask tracks which characters have been claimed.  A GREEDY_PLACEHOLDER
    // character at position j means that character is already part of a greedy match.
    let mask = originalText;
    const matches = [];
    for (const { tokenType, patternDef } of greedyEntries) {
      const { pattern, lookbehind, inside } = patternDef;
      const regex = new RegExp(pattern.source, pattern.flags.replace(/g/g, '') + 'g');
      let execResult;
      while ((execResult = regex.exec(mask)) !== null) {
        let matchIndex = execResult.index;
        let match = execResult[0];
        /* istanbul ignore next -- defensive: prevents infinite loop on zero-length regex matches */
        if (match.length === 0) {
          regex.lastIndex++;
          continue;
        }
        // If matched text contains a placeholder char it overlaps a
        // previously claimed region — skip it.
        /* istanbul ignore next -- defensive: prevents re-tokenizing already-claimed greedy regions */
        if (match.indexOf(GREEDY_PLACEHOLDER) !== -1) {
          continue;
        }
        if (lookbehind && execResult[1]) {
          const lookbehindLength = execResult[1].length;
          matchIndex += lookbehindLength;
          match = match.slice(lookbehindLength);
        }
        // Record the match and blank out the region in the mask.
        const matchEnd = matchIndex + match.length;
        matches.push({
          tokenType,
          matchStart: matchIndex,
          matchEnd,
          matchText: originalText.slice(matchIndex, matchEnd),
          inside,
        });
        // Replace matched region in the mask with placeholder so later
        // patterns cannot match inside it.
        mask =
          mask.slice(0, matchIndex) +
            GREEDY_PLACEHOLDER.repeat(match.length).slice(0, match.length) +
            mask.slice(matchEnd);
      }
    }
    if (matches.length === 0) {
      continue;
    }
    // Sort matches by start position for deterministic splicing.
    matches.sort((a, b) => a.matchStart - b.matchStart);
    // Build replacement array.
    const replacement = [];
    let lastIndex = 0;
    for (const m of matches) {
      if (m.matchStart > lastIndex) {
        replacement.push(originalText.slice(lastIndex, m.matchStart));
      }
      let content = m.matchText;
      if (m.inside) {
        const nested = tokenize(m.matchText, m.inside);
        content = nested.length === 1 ? nested[0] : nested;
      }
      replacement.push({ type: m.tokenType, content });
      lastIndex = m.matchEnd;
    }
    if (lastIndex < originalText.length) {
      replacement.push(originalText.slice(lastIndex));
    }
    tokens.splice(i, 1, ...replacement);
    i += replacement.length - 1;
  }
}
/**
 * Apply a single pattern definition across all string entries in the token list.
 * For each string entry, finds ALL matches of the pattern and splits the string
 * into alternating unmatched/matched segments in one pass.
 *
 * @param {(string | SyntaxToken)[]} tokens - The token list to process.
 * @param {string} tokenType - The token type name for matched content.
 * @param {GrammarPattern} patternDef - The pattern definition to apply.
 */
function applyPattern(tokens, tokenType, patternDef) {
  for (let i = 0; i < tokens.length; i++) {
    const token = tokens[i];
    // Only process string tokens, skip already-tokenized entries
    if (typeof token !== 'string') {
      continue;
    }
    const replacement = tokenizeStringByPattern(token, tokenType, patternDef);
    // Only splice if matches were found (replacement differs from original)
    if (replacement.length === 1 && typeof replacement[0] === 'string') {
      continue;
    }
    tokens.splice(i, 1, ...replacement);
    // Skip past the entire replacement — all matches in this string are handled
    i += replacement.length - 1;
  }
}
/**
 * Find all matches of a pattern within a string and return the split result
 * as an array of alternating plain strings and syntax tokens.
 *
 * @param {string} text - The string to tokenize.
 * @param {string} tokenType - The token type name for matched content.
 * @param {GrammarPattern} patternDef - The pattern definition to apply.
 * @returns {(string | SyntaxToken)[]} The tokenized result.
 */
function tokenizeStringByPattern(text, tokenType, patternDef) {
  const { pattern, lookbehind, inside } = patternDef;
  const regex = new RegExp(pattern.source, pattern.flags.replace(/g/g, '') + 'g');
  const result = [];
  let lastIndex = 0;
  let execResult;
  while ((execResult = regex.exec(text)) !== null) {
    let matchIndex = execResult.index;
    let match = execResult[0];
    // Prevent zero-length match infinite loops
    if (match.length === 0) {
      regex.lastIndex++;
      continue;
    }
    // Handle lookbehind: adjust match position and content
    if (lookbehind && execResult[1]) {
      const lookbehindLength = execResult[1].length;
      matchIndex += lookbehindLength;
      match = match.slice(lookbehindLength);
    }
    // Add unmatched text before this match
    if (matchIndex > lastIndex) {
      result.push(text.slice(lastIndex, matchIndex));
    }
    // Process nested grammar if specified
    let content = match;
    if (inside) {
      const nestedTokens = tokenize(match, inside);
      content = nestedTokens.length === 1 ? nestedTokens[0] : nestedTokens;
    }
    result.push({ type: tokenType, content });
    lastIndex = matchIndex + match.length;
  }
  // Add remaining unmatched text
  if (lastIndex < text.length) {
    result.push(text.slice(lastIndex));
  }
  /* istanbul ignore next -- defensive: tokenizeStringByPattern always has remainder text */
  if (result.length === 0) {
    return [text];
  }
  return result;
}

/**
 * Grammar definition for CSS syntax highlighting.
 * Handles selectors, properties, values, at-rules, comments, strings, and other CSS constructs.
 */
const cssGrammar = {
  comment: {
    pattern: /\/\*[\s\S]*?\*\//,
    greedy: true,
  },
  string: {
    pattern: /("|')(?:\\[\s\S]|(?!\1)[^\\\n\r])*\1/,
    greedy: true,
  },
  atrule: [
    {
      pattern: /@[\w-](?:[^;{\s]|\s+(?![\s{]))*(?:;|(?=\s*\{))/,
      inside: {
        'rule': { pattern: /^@[\w-]+/ },
        'selector-function-argument': {
          pattern: /(\bselector\s*\(\s*(?![\s)]))(?:[^()\s]|\s+(?![\s)])|\((?:[^()]|\([^()]*\))*\))+(?=\s*\))/,
          lookbehind: true,
        },
        'keyword': {
          pattern: /(^|[^\w-])(?:and|not|only|or)(?![\w-])/,
          lookbehind: true,
        },
        'punctuation': { pattern: /[;:(){}]/ },
      },
    },
  ],
  url: {
    pattern: /\burl\((?:("|')(?:\\[\s\S]|(?!\1)[^\\\n\r])*\1|(?:[^\\\r\n()"']|\\[\s\S])*)\)/i,
    greedy: true,
    inside: {
      function: { pattern: /^url/i },
      punctuation: { pattern: /^\(|\)$/ },
      string: {
        pattern: /^("|')[\s\S]+(?=\1$)/,
        lookbehind: true,
      },
    },
  },
  selector: {
    pattern: /(?=\S)[^@;{}()]?(?:[^@;{}()\s]|\s+(?![\s{])|\((?:[^()]|\([^()]*\))*\))*(?=\s*\{)/,
    inside: {
      'pseudo-element': { pattern: /(?:::)[\w-]+/ },
      'pseudo-class': { pattern: /(?::)[\w-]+/ },
      'class': { pattern: /\.[\w-]+/ },
      'id': { pattern: /#[\w-]+/ },
      'attribute': {
        pattern: /\[(?:[^[\]"']|("|')(?:\\[\s\S]|(?!\1)[^\\\n\r])*\1)*\]/,
        greedy: true,
        inside: {
          'punctuation': { pattern: /^\[|\]$/ },
          'attr-name': { pattern: /^(\s*)(?:(?!\s)[-\w\u00B7\u00C0-\u024F])+/i, lookbehind: true },
          'attr-value': [{ pattern: /(=\s*)(?:"[^"]*"|'[^']*'|[^\s'"=]+)/, lookbehind: true }],
          'operator': { pattern: /[|~*^$]?=/ },
        },
      },
    },
  },
  property: {
    pattern: /(?!\s)[-_a-z\u00B7\u00C0-\u024F][-\w\u00B7\u00C0-\u024F]*(?=\s*:)/i,
  },
  important: {
    pattern: /!important\b/i,
  },
  function: {
    pattern: /(^|[^-a-z0-9])[-a-z0-9]+(?=\()/i,
    lookbehind: true,
  },
  number: {
    pattern: /(^|[^\w.-])-?(?:\d+(?:\.\d+)?|\.\d+)(?:e[+-]?\d+)?/i,
    lookbehind: true,
  },
  unit: {
    pattern: /(\b\d+)(?:%|[a-z]+)/,
    lookbehind: true,
  },
  punctuation: {
    pattern: /[(){};:,]/,
  },
  operator: {
    pattern: /[+\-*/=><~^|]+/,
  },
};

/**
 * Grammar definition for HTML/Markup syntax highlighting.
 * Handles tags, attributes, comments, doctypes, CDATA, entities, and embedded content.
 */
const markupGrammar = {
  comment: {
    pattern: /<!--(?:(?!<!--)[\s\S])*?-->/,
    greedy: true,
  },
  prolog: {
    pattern: /<\?[\s\S]+?\?>/,
    greedy: true,
  },
  doctype: {
    pattern: /<!DOCTYPE(?:[^>"']|"[^"]*"|'[^']*')+(?:>|$)/i,
    greedy: true,
    inside: {
      'internal-subset': {
        pattern: /(^[^[]*\[)[\s\S]+(?=\]>$)/,
        lookbehind: true,
        greedy: true,
      },
      'punctuation': { pattern: /^<!|>$|[[\]]/ },
      'doctype-tag': { pattern: /^DOCTYPE/i },
      'name': { pattern: /[^\s<>'"/]+/ },
      'string': {
        pattern: /("|')[\s\S]*?\1/,
        greedy: true,
      },
    },
  },
  cdata: {
    pattern: /<!\[CDATA\[[\s\S]*?\]\]>/i,
    greedy: true,
  },
  tag: {
    pattern: /<\/?(?!\d)[^\s>/=$<%]+(?:\s(?:\s*[^\s>/=]+(?:\s*=\s*(?:"[^"]*"|'[^']*'|[^\s'">=]+(?=[\s>]))|(?=[\s/>])))+)?\s*\/?>/,
    greedy: true,
    inside: {
      'tag': {
        pattern: /^<\/?[^\s>/]+/,
        inside: {
          punctuation: { pattern: /^<\/?/ },
          namespace: { pattern: /^[^\s>/:]+:/ },
        },
      },
      'special-attr': [],
      'attr-value': {
        pattern: /=\s*(?:"[^"]*"|'[^']*'|[^\s'">=]+)/,
        inside: {
          punctuation: [{ pattern: /^=/ }, { pattern: /^(\s*)["']|["']$/, lookbehind: true }],
        },
      },
      'punctuation': { pattern: /\/?>/ },
      'attr-name': {
        pattern: /[^\s>/]+/,
        inside: {
          namespace: { pattern: /^[^\s>/:]+:/ },
        },
      },
    },
  },
  entity: [
    {
      pattern: /&[\da-z]{1,8};/i,
    },
    {
      pattern: /&#x?[\da-f]{1,8};/i,
    },
  ],
};

/**
 * Grammar definition for JavaScript syntax highlighting.
 * Handles keywords, operators, strings, template literals, numbers,
 * regex literals, comments, functions, classes, and other JS constructs.
 */
const javascriptGrammar = {
  'comment': [
    {
      pattern: /(^|[^\\])\/\*[\s\S]*?(?:\*\/|$)/,
      lookbehind: true,
      greedy: true,
    },
    {
      pattern: /(^|[^\\:])\/\/.*/,
      lookbehind: true,
      greedy: true,
    },
  ],
  'string': [
    {
      pattern: /(["'])(?:\\[\s\S]|(?!\1)[^\\\r\n])*\1/,
      greedy: true,
    },
  ],
  'template-string': {
    pattern: /`(?:\\[\s\S]|[^\\`])*`/,
    greedy: true,
    inside: {
      'template-punctuation': {
        pattern: /^`|`$/,
      },
      'interpolation': {
        pattern: /\$\{(?:[^{}]|\{(?:[^{}]|\{[^{}]*\})*\})*\}/,
        inside: {
          'interpolation-punctuation': {
            pattern: /^\$\{|\}$/,
          },
        },
      },
      'string': {
        pattern: /[\s\S]+/,
      },
    },
  },
  'regex': {
    pattern: 
    // eslint-disable-next-line no-useless-escape
    /((?:^|[^$\w\xA0-\uFFFF."'\])\s]|\b(?:return|yield))\s*)\/(?:\[(?:[^\]\\\r\n]|\\.)*\]|\\.|[^/\\\[\r\n])+\/[dgimyus]{0,7}(?=(?:\s|\/\*(?:[^*]|\*(?!\/))*\*\/)*(?:$|[.\r\n,;:})\]]|\/\/))/,
    lookbehind: true,
    greedy: true,
    inside: {
      'regex-source': {
        pattern: /^(\/)[\s\S]+(?=\/[a-z]*$)/,
        lookbehind: true,
      },
      'regex-delimiter': {
        pattern: /^\/|\/$/,
      },
      'regex-flags': {
        pattern: /^[a-z]+$/,
      },
    },
  },
  'class-name': [
    {
      pattern: /(\b(?:class|extends|implements|instanceof|interface|new)\s+)[\w.\\]+/,
      lookbehind: true,
      inside: {
        punctuation: { pattern: /[.\\]/ },
      },
    },
  ],
  'keyword': [
    {
      pattern: /\b(?:as|async|await|break|case|catch|class|const|continue|debugger|default|delete|do|else|enum|export|extends|finally|for|from|function|get|if|implements|import|in|instanceof|interface|let|new|null|of|package|private|protected|public|return|set|static|super|switch|this|throw|try|typeof|undefined|var|void|while|with|yield)\b/,
    },
  ],
  'boolean': {
    pattern: /\b(?:false|true)\b/,
  },
  'number': {
    pattern: /\b(?:(?:0[xX][\dA-Fa-f](?:_[\dA-Fa-f])*|0[bB][01](?:_[01])*|0[oO][0-7](?:_[0-7])*)n?|(?:\d(?:_\d)*\.?\d*|\.\d+)(?:[Ee][+-]?\d(?:_\d)*)?n?|NaN|Infinity)\b/,
  },
  'function': {
    pattern: /#?(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*(?=\s*(?:\.\s*(?:apply|bind|call)\s*)?\()/,
  },
  'operator': {
    pattern: /--|\+\+|\*\*=?|=>|&&=?|\|\|=?|[!=]==|<<=?|>>>?=?|[-+*/%|&^!=<>]=?|\.{3}|\?\?=?|\?\.?|[~:]/,
  },
  'punctuation': {
    pattern: /[{}[\];(),.:]/,
  },
  'constant': {
    pattern: /\b[A-Z](?:[A-Z_]|\dx)*\b/,
  },
};

var __rest = (undefined && undefined.__rest) || function (s, e) {
  var t = {};
  for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
    t[p] = s[p];
  if (s != null && typeof Object.getOwnPropertySymbols === "function")
    for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
      if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
        t[p[i]] = s[p[i]];
    }
  return t;
};
/**
 * Grammar definition for TypeScript syntax highlighting.
 * Extends JavaScript grammar with TypeScript-specific constructs such as
 * type annotations, generics, interfaces, enums, decorators, and access modifiers.
 *
 * Note: We destructure `keyword`, `function`, `operator`, and `punctuation` out
 * of the JS grammar and re-add them in the correct order. This ensures:
 * - `builtin` is matched before `keyword` (both contain words like void, null, etc.)
 * - `function` is matched before `operator` and `punctuation` (the function
 *   pattern uses a lookahead for `(` which must still be an unmatched string)
 */
const { 
// eslint-disable-next-line @typescript-eslint/no-unused-vars
keyword: _jsKeyword, function: jsFunction, 
// eslint-disable-next-line @typescript-eslint/no-unused-vars
operator: _jsOperator, punctuation: jsPunctuation } = javascriptGrammar, jsGrammarBase = __rest(javascriptGrammar, ["keyword", "function", "operator", "punctuation"]);
const typescriptGrammar = Object.assign(Object.assign({}, jsGrammarBase), { 'class-name': [
    {
      pattern: /(\b(?:class|extends|implements|instanceof|interface|new|type)\s+)(?!keyof\b)(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*(?:\s*<(?:[^<>]|<(?:[^<>]|<[^<>]*>)*>)*>)?/,
      lookbehind: true,
      greedy: true,
      inside: {
        punctuation: { pattern: /[<>.,]/ },
      },
    },
  ], 'builtin': {
    pattern: /\b(?:Array|Boolean|Date|Function|Map|Number|Object|Promise|RegExp|Set|String|WeakMap|WeakSet|bigint|boolean|never|null|number|string|symbol|undefined|unknown|void)\b/,
  }, 'keyword': [
    {
      pattern: /\b(?:abstract|as|asserts|async|await|break|case|catch|class|const|constructor|continue|debugger|declare|default|delete|do|else|enum|export|extends|finally|for|from|function|get|if|implements|import|in|infer|instanceof|interface|is|keyof|let|module|namespace|new|null|of|package|private|protected|public|readonly|return|require|set|static|super|switch|this|throw|try|type|typeof|undefined|var|void|while|with|yield)\b/,
    },
  ], 'function': jsFunction, 'generic-function': {
    pattern: /#?(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*\s*<(?:[^<>]|<(?:[^<>]|<[^<>]*>)*>)*>(?=\s*\()/,
    greedy: true,
    inside: {
      function: {
        pattern: /^#?(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*/,
      },
      generic: {
        pattern: /<[\s\S]+/,
        inside: {
          punctuation: { pattern: /[<>(),.]/ },
          keyword: { pattern: /\b(?:extends|infer|keyof)\b/ },
          builtin: {
            pattern: /\b(?:boolean|never|null|number|string|symbol|undefined|unknown|void)\b/,
          },
        },
      },
    },
  }, 'operator': {
    pattern: /--|\+\+|\*\*=?|=>|&&=?|\|\|=?|[!=]==|<<=?|>>>?=?|[-+*/%|&^!=<>]=?|\.{3}|\?\?=?|\?\.?|[~:]|!(?=\s*[^=])/,
  }, 'punctuation': jsPunctuation });

/**
 * Grammar definition for JSX syntax highlighting.
 * Extends JavaScript grammar with JSX tag syntax for React components,
 * including self-closing tags, expressions in braces, and embedded markup attributes.
 */
const jsxGrammar = Object.assign(Object.assign({ 
  // Tag must come before JS spread so operator pattern doesn't consume < and >
  tag: {
    pattern: /<\/?(?:[\w.:-]+(?:\s+(?:[\w.:$-]+(?:=(?:"(?:\\[\s\S]|[^\\"])*"|'(?:\\[\s\S]|[^\\'])*'|\{(?:\{(?:\{[^{}]*\}|[^{}])*\}|[^{}])+\}))?|\{\.{3}[a-z_$][\w$]*(?:\.[\w$]+)*\}))*\s*\/?)?>/i,
    greedy: true,
    inside: {
      'tag': {
        pattern: /^<\/?[^\s>/]*/,
        inside: {
          punctuation: { pattern: /^<\/?/ },
          namespace: { pattern: /^[^\s>/:]+:/ },
        },
      },
      'attr-value': {
        pattern: /=\s*(?:"[^"]*"|'[^']*'|\{(?:\{(?:\{[^{}]*\}|[^{}])*\}|[^{}])+\})/,
        inside: {
          punctuation: [{ pattern: /^=/ }, { pattern: /^(\s*)["'{]|[}"']$/, lookbehind: true }],
          script: {
            pattern: /[\s\S]+/,
            inside: javascriptGrammar,
          },
        },
      },
      'spread': {
        pattern: /\{\.{3}[a-z_$][\w$]*(?:\.[\w$]+)*\}/,
        inside: {
          'punctuation': { pattern: /^\{\.{3}|\}$/ },
          'attr-name': { pattern: /[\s\S]+/ },
        },
      },
      'attr-name': {
        pattern: /[^\s>/]+/,
        inside: {
          namespace: { pattern: /^[^\s>/:]+:/ },
        },
      },
      'punctuation': { pattern: /\/?>/ },
    },
  } }, javascriptGrammar), { entity: markupGrammar.entity });

/**
 * Grammar definition for TSX (TypeScript + JSX) syntax highlighting.
 * Merges TypeScript and JSX grammars, supporting both type annotations
 * and JSX tag syntax in the same file.
 */
const tsxGrammar = Object.assign(Object.assign({ 
  // Tag must come before TS spread so operator pattern doesn't consume < and >
  tag: jsxGrammar['tag'] }, typescriptGrammar), { entity: jsxGrammar['entity'] });

/**
 * A registry that maps language identifiers to their grammar definitions.
 * Supports common aliases (e.g., 'html' -> markup, 'js' -> javascript).
 *
 * The registry provides grammars for:
 * - CSS
 * - HTML / Markup
 * - JavaScript (JS)
 * - TypeScript (TS)
 * - JSX
 * - TSX
 * - C / C-like (falls back to JavaScript grammar for basic C-family highlighting)
 */
const languageRegistry = {
  css: cssGrammar,
  html: markupGrammar,
  markup: markupGrammar,
  javascript: javascriptGrammar,
  js: javascriptGrammar,
  typescript: typescriptGrammar,
  ts: typescriptGrammar,
  jsx: jsxGrammar,
  tsx: tsxGrammar,
  c: javascriptGrammar,
  clike: javascriptGrammar,
};
/**
 * Retrieve the grammar for a given language identifier.
 *
 * @param {string} language - The language identifier (e.g., 'js', 'css', 'html', 'ts', 'jsx', 'tsx').
 * @returns {Grammar | undefined} The grammar definition, or undefined if the language is not registered.
 */
function getLanguageGrammar(language) {
  return languageRegistry[language];
}

var __decorate$4 = (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;
};
const presetLanguages = Object.values(codeBlock.CodeLanguage);
/**
 * Processing the code content into different types of nodes.
 */
class CodeHighlightParser extends globalSlimmerRegistry.VegaSlimmer {
  /**
   * Split the HTML tag to avoid the content render to a html element.
   *
   * @example <div> -> ['<', 'div', '>']
   * @param {string} text - The code content.
   * @returns {string[]} - The code content array.
   */
  splitTag(text) {
    if (!this.hasSpecialCharacter(text) || text.length < 2) {
      return [text];
    }
    else {
      const result = [];
      const textArray = text.split('');
      let nextIndex = 0;
      textArray.forEach((item) => {
        if (item === '<' || item === '>' || item === '/') {
          result.push(item);
          nextIndex = result.length;
        }
        else {
          result[nextIndex] = result[nextIndex] ? result[nextIndex] + item : item;
        }
      });
      return result;
    }
  }
  /**
   * Check the current language is a preset language and the language is not plain text.
   *
   * @param {Nullable<string>} language - The input language.
   * @returns {boolean} - The boolean result.
   */
  isHighlightLanguage(language) {
    return language !== 'plainText' && presetLanguages.includes(language);
  }
  /**
   * Mark the line number class for the first node of each line.
   *
   * @param {CodeNodeType[]} codeNodes - The code nodes array.
   * @returns {CodeNodeType[]} - The code node array with line number tag.
   */
  markLineNumberNodes(codeNodes) {
    if (codeNodes.length === 0) {
      codeNodes.push({ text: '\n', key: '0', className: '' });
    }
    let lineNumber = 0;
    return codeNodes.map((node, index) => {
      let className = node.className;
      if (index === 0 || codeNodes[index - 1].text === '\n') {
        lineNumber++;
        className = `v-code-line-number ${node.className}`;
      }
      return {
        text: node.text,
        key: `${index}`,
        className,
        mark: `${lineNumber}`,
      };
    });
  }
  /**
   * Check the text has special character.
   *
   * @param {string} text - The test text.
   * @returns {boolean} - Return true is the text has <, > , /.
   */
  hasSpecialCharacter(text) {
    return /[<|>|\\/]/.test(text);
  }
}
__decorate$4([
  globalSlimmerRegistry.MapToComponentField()
], CodeHighlightParser.prototype, "value", void 0);

/**
 * Use the local syntax highlight tokenizer to highlight the code content.
 */
class PrismCodeHighlightParseController extends CodeHighlightParser {
  /**
   * Return true when the content and language are defined.
   *
   * @returns {boolean} - Boolean value.
   */
  canParse() {
    const { code, language } = this.value || { code: '' };
    return code && language && this.isHighlightLanguage(language);
  }
  /**
   * Use tokenizer to parse the string code into an array of nodes with different keywords.
   *
   * @returns {CodeNodeType[]} - The object contains content and highlight type.
   */
  parse() {
    const { code, language } = this.value;
    let result = [];
    const parseLanguage = getLanguageGrammar(language);
    const tokens = tokenize(code, parseLanguage);
    result = this.getHighlightNodes(tokens);
    return this.markLineNumberNodes(result);
  }
  /**
   * Parse the plugin parse result to a usable array.
   *
   * @param {(string | CodeHighlightToken)[]} tokens - The plugin parse result.
   * @param {string} [type] - The keywords. Such as variable, function-name, attr-name...
   * @returns {CodeNodeType[]} - The code node array.
   */
  getHighlightNodes(tokens, type) {
    const nodes = [];
    for (const token of tokens) {
      if (typeof token === 'string') {
        const partials = token.split(/(\n|\t)/);
        const partialsLength = partials.length;
        for (let i = 0; i < partialsLength; i++) {
          const part = partials[i];
          if (part) {
            const textArray = this.splitTag(part);
            nodes.push(...textArray.map((text) => this.createCodeNode(text, type)));
          }
        }
      }
      else {
        const { content } = token;
        if (typeof content === 'string') {
          nodes.push(...this.getHighlightNodes([content], token.type));
        }
        else if (Array.isArray(content)) {
          nodes.push(...this.getHighlightNodes(content, token.type));
        }
      }
    }
    return nodes;
  }
  /**
   * Create a CodeNodeType type object by the code content and highlight type.
   *
   * @param {string} text - The code content.
   * @param {string} highlightType - The highlight type.
   * @returns {CodeNodeType} - The code node object.
   */
  createCodeNode(text, highlightType) {
    return {
      text,
      key: '',
      className: `token ${highlightType || ''}`,
      mark: '',
    };
  }
}

/**
 * Plain text parse logic.
 */
class DefaultCodeHighlightParseController extends CodeHighlightParser {
  /**
   * Default parser will handle if others not catch.
   *
   * @returns {boolean} True value.
   */
  canParse() {
    const { code, language } = this.value || { code: '' };
    return !code || !language || language === 'plainText' || !this.isHighlightLanguage(language);
  }
  /**
   * The default parse will split the html tag and create the line number.
   *
   * @returns {CodeNodeType[]} - The code node array.
   */
  parse() {
    var _a, _b;
    const code = (_b = (_a = this.value) === null || _a === void 0 ? void 0 : _a.code) !== null && _b !== void 0 ? _b : '';
    const nodes = code.split(/(\n)/);
    let result = [];
    nodes.forEach((item) => {
      if (item) {
        const textArray = this.splitTag(item);
        result.push(...textArray.map((text) => ({ text, key: '', className: '' })));
      }
    });
    result = this.markLineNumberNodes(result);
    return result;
  }
}

const codeColorVariableCss = ":root{--code-orange:#cd3e00;--code-green:#007e7e;--code-purple:#6851f5;--code-gray:#67727e;--code-neutral:rgb(15, 36, 51);--code-neutral-8:rgba(15, 36, 51, 0.8);--code-neutral-7:rgba(15, 36, 51, 0.7)}.dark{--code-orange:#ff9571;--code-green:#73e6dc;--code-purple:#c7bdff;--code-gray:#8b959f;--code-neutral:rgb(252, 252, 252);--code-neutral-8:rgba(252, 252, 252, 0.8);--code-neutral-7:rgba(252, 252, 252, 0.7)}";

var __decorate$3 = (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 class used to control the code block insert composition text action.
 */
class InsertCompositionTextController extends globalSlimmerRegistry.VegaSlimmer {
  constructor() {
    super(...arguments);
    this.insertCompositionTextEndFlag = true;
    /**
     * An event handler function that is triggered when the composition of text input starts. In this case,
     *  it sets the `insertCompositionTextEndFlag` property of the `UserInputController` class to `false`.
     *
     * @param {CompositionEvent} e The composition event instance
     */
    this.handleCompositionStart = (e) => {
      this.insertCompositionTextEndFlag = false;
      this.stopEventPropagation(e);
    };
    /**
     * An event handler function that is triggered when the composition of text input ends. In this case,
     *  it sets the `insertCompositionTextEndFlag` property of the `UserInputController` class to `true`.
     *
     * @param {CompositionEvent} e The composition event instance
     */
    this.handleCompositionEnd = (e) => {
      var _a;
      this.insertCompositionTextEndFlag = true;
      this.stopEventPropagation(e);
      const range = this.selectionController.getCurrentRange();
      if (range) {
        this.selectionController.setNextCodeBlockRange(range.contentOffset + e.data.length);
      }
      const newContent = this.contentRenderer.getCodeContentContainerRef().innerText;
      this.valueController.updateValue(newContent, (_a = this.value) === null || _a === void 0 ? void 0 : _a.language);
    };
  }
  /**
   * The method is to get the composition text insert end or not.
   *
   * @returns {boolean} The false is mean that insert composition text process is end.
   */
  isComposing() {
    return !this.insertCompositionTextEndFlag;
  }
  /**
   * Stop `beforeinput` and `input` event bubbles to parent element.
   */
  registerInputEvent() {
    const codeContentContainerRef = this.contentRenderer.getCodeContentContainerRef();
    if (codeContentContainerRef) {
      codeContentContainerRef.addEventListener('compositionstart', this.handleCompositionStart);
      codeContentContainerRef.addEventListener('compositionend', this.handleCompositionEnd);
    }
  }
  /**
   * Remove the event listener.
   */
  unregisterEventListener() {
    const codeContentContainerRef = this.contentRenderer.getCodeContentContainerRef();
    if (codeContentContainerRef) {
      codeContentContainerRef.removeEventListener('compositionstart', this.handleCompositionStart);
      codeContentContainerRef.removeEventListener('compositionend', this.handleCompositionEnd);
    }
  }
  /**
   * Stop the event bubbles.
   *
   * @param {Event} e - The event object.
   */
  stopEventPropagation(e) {
    e.stopPropagation();
  }
}
__decorate$3([
  globalSlimmerRegistry.MapToComponentField()
], InsertCompositionTextController.prototype, "selectionController", void 0);
__decorate$3([
  globalSlimmerRegistry.MapToComponentField()
], InsertCompositionTextController.prototype, "contentRenderer", void 0);
__decorate$3([
  globalSlimmerRegistry.MapToComponentField()
], InsertCompositionTextController.prototype, "valueController", void 0);
__decorate$3([
  globalSlimmerRegistry.MapToComponentField()
], InsertCompositionTextController.prototype, "contentParseController", void 0);
__decorate$3([
  globalSlimmerRegistry.MapToComponentField()
], InsertCompositionTextController.prototype, "value", void 0);
__decorate$3([
  globalSlimmerRegistry.MapToComponentMethod('componentDidLoad')
], InsertCompositionTextController.prototype, "registerInputEvent", null);
__decorate$3([
  globalSlimmerRegistry.MapToComponentMethod('disconnectedCallback')
], InsertCompositionTextController.prototype, "unregisterEventListener", null);

var __decorate$2 = (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 class used to control the code block history.
 * It extends the ComponentValueHistoryControllerSlimmer to manage the history of code block states.
 */
class VegaCodeBlockHistoryController extends componentValueHistoryControllerSlimmer_abstract.ComponentValueHistoryControllerSlimmer {
  constructor() {
    super(...arguments);
    /**
     * Get the effective target elements for the code block history.
     *
     * @returns {HTMLElement[]} - An array of effective target elements.
     */
    this.getEffectiveTargets = () => {
      return [this.contentRenderer.getCodeContentContainerRef()];
    };
  }
  /**
   * Invoke the method to back up the current code block state.
   */
  async undo() {
    if (this.undoStack.length > 1) {
      const clonedState = this.undoStack.pop();
      this.redoStack.push(clonedState);
      const prev = this.undoStack[this.undoStack.length - 1];
      if (prev) {
        await this.restoreState(prev);
      }
    }
  }
  /**
   * Invoke the redo action to restore the last undone state.
   */
  async redo() {
    const clonedState = this.redoStack.pop();
    this.undoStack.push(clonedState);
    await this.restoreState(clonedState);
  }
  /**
   * Set the initial state of the code block history when the component is loaded.
   */
  initialHistory() {
    this.registerHistory({
      value: this.value,
      offset: this.value.code.length,
    }, true);
  }
  /**
   * Get the ineffective target elements for the code block history.
   *
   * @returns { HTMLElement[]} - An empty array, as there are no ineffective targets for the code block.
   */
  getIneffectiveTargets() {
    return [];
  }
  /**
   * Restore the state of the code block from the given state.
   *
   * @param {CodeBlockState} state - The state to restore.
   */
  async restoreState(state) {
    const { value, offset } = state;
    this.selectionController.setNextCodeBlockRange(offset);
    this.valueController.updateValue(value.code, value.language);
  }
}
__decorate$2([
  globalSlimmerRegistry.MapToComponentField()
], VegaCodeBlockHistoryController.prototype, "contentRenderer", void 0);
__decorate$2([
  globalSlimmerRegistry.MapToComponentField()
], VegaCodeBlockHistoryController.prototype, "value", void 0);
__decorate$2([
  globalSlimmerRegistry.MapToComponentField()
], VegaCodeBlockHistoryController.prototype, "valueController", void 0);
__decorate$2([
  globalSlimmerRegistry.MapToComponentField()
], VegaCodeBlockHistoryController.prototype, "selectionController", void 0);
__decorate$2([
  globalSlimmerRegistry.MapToComponentMethod('componentDidLoad')
], VegaCodeBlockHistoryController.prototype, "initialHistory", null);

var __decorate$1 = (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;
};
/**
 * Controller for handling paste events in VegaCodeBlock.
 * Handles insertion, selection, and content update logic for pasted code.
 */
class CodeBlockPasteController extends CodeInputPaste {
  constructor() {
    super(...arguments);
    /**
     * Handle the paste event.
     *
     * @param {ClipboardEvent} e - The clipboard event object.
     * @returns {void}
     */
    this.handlePasteEvent = (e) => {
      var _a, _b;
      e.preventDefault();
      this.stopEventPropagation(e);
      const pasteData = e.clipboardData;
      if ((_a = pasteData === null || pasteData === void 0 ? void 0 : pasteData.files) === null || _a === void 0 ? void 0 : _a.length) {
        // Prevent paste if the clipboard contains files.
        return;
      }
      const pastedContent = (_b = pasteData === null || pasteData === void 0 ? void 0 : pasteData.getData('text/plain')) !== null && _b !== void 0 ? _b : '';
      if (!pastedContent) {
        return;
      }
      this.updateCodeBlockRangeAndContent(pastedContent);
    };
  }
  /**
   *  Register paste event listener on component load.
   */
  registerInputEvent() {
    const codeContentContainerRef = this.contentRenderer.getCodeContentContainerRef();
    if (codeContentContainerRef) {
      codeContentContainerRef.addEventListener('paste', this.handlePasteEvent);
    }
  }
  /**
   * Remove the event listener.
   */
  unregisterEventListener() {
    const codeContentContainerRef = this.contentRenderer.getCodeContentContainerRef();
    if (codeContentContainerRef) {
      codeContentContainerRef.removeEventListener('paste', this.handlePasteEvent);
    }
  }
  /**
   * Update the code block range based on pasted data.
   *
   * @param {string} pastedContent - The content that has been pasted.
   * @returns {void}
   */
  updateCodeBlockRangeAndContent(pastedContent) {
    const { nextOffset: updatedOffset, updatedContent } = this.getLatestRangeAndContent(pastedContent);
    this.selectionController.setNextCodeBlockRange(updatedOffset);
    this.valueController.updateValue(updatedContent, this.value.language, {
      recordHistory: true,
      offset: this.selectionController.getCurrentRange().contentOffset,
    });
  }
  /**
   * Get the latest range and content after paste operation.
   *
   * @param {string} pastedContent - The content that has been pasted.
   * @returns {NextOffsetAndContentResult}} The next offset and updated content.
   */
  getLatestRangeAndContent(pastedContent) {
    const range = this.selectionController.getCurrentRange();
    const currentNodes = this.contentParseController.getCurrentCodeNodes();
    const content = this.getCodeNodesContent(currentNodes);
    return this.reCalculateRangeAndContent(range, content, pastedContent);
  }
}
__decorate$1([
  globalSlimmerRegistry.MapToComponentField()
], CodeBlockPasteController.prototype, "host", void 0);
__decorate$1([
  globalSlimmerRegistry.MapToComponentField()
], CodeBlockPasteController.prototype, "valueController", void 0);
__decorate$1([
  globalSlimmerRegistry.MapToComponentField()
], CodeBlockPasteController.prototype, "contentRenderer", void 0);
__decorate$1([
  globalSlimmerRegistry.MapToComponentField()
], CodeBlockPasteController.prototype, "value", void 0);
__decorate$1([
  globalSlimmerRegistry.MapToComponentField()
], CodeBlockPasteController.prototype, "selectionController", void 0);
__decorate$1([
  globalSlimmerRegistry.MapToComponentField()
], CodeBlockPasteController.prototype, "contentParseController", void 0);
__decorate$1([
  globalSlimmerRegistry.MapToComponentField()
], CodeBlockPasteController.prototype, "inputController", void 0);
__decorate$1([
  globalSlimmerRegistry.MapToComponentMethod('componentDidLoad')
], CodeBlockPasteController.prototype, "registerInputEvent", null);
__decorate$1([
  globalSlimmerRegistry.MapToComponentMethod('disconnectedCallback')
], CodeBlockPasteController.prototype, "unregisterEventListener", null);

const vegaCodeBlockCss = ":host{display:block;border-radius:2px;background-color:rgba(var(--v-bg-secondary, 245, 247, 247, 1));padding-left:12px;padding-right:12px;padding-top:12px;padding-bottom:12px}:host code{display:block;box-sizing:border-box;color:rgba(var(--v-text-primary, 32, 54, 69, 1));text-align:left;font-family:\"Roboto Mono\";font-weight:400;line-height:22px;font-size:16px;white-space:pre-wrap;min-height:22px;tab-size:2px;word-break:break-word}:host code:focus-visible{outline:none}:host .editor-toolbar{display:flex;flex-direction:row;justify-content:space-between;align-items:center;padding-bottom:12px;border:1px solid rgba(var(--v-border-divider-secondary, 199, 217, 229, 1));border-top-width:0px;border-left-width:0px;border-right-width:0px;margin-bottom:12px;user-select:none}:host .editor-toolbar vega-input-select{width:auto;min-width:161px}:host(.show-line-number) code .v-code-line-number::before{content:attr(data-mark);width:var(--v-code-line-number-width);margin-left:var(--v-code-line-number-ml);padding-right:16px;text-align:right;user-select:none;font-style:normal;word-break:keep-all;color:rgba(var(--v-text-secondary, 107, 116, 125, 1));display:inline-block}:host(.show-line-number) code{padding-left:var(--v-code-block-pl)}:host::part(select-container){padding-top:0px;padding-bottom:0px;padding-left:8px;padding-right:8px;border-radius:4px}:host::part(selected-box),:host::part(placeholder){font-size:14px;user-select:none}:host::part(toggle-icon-container){width:12px;height:12px;line-height:12px}:host::part(toggle-icon){width:12px;height:12px}:host(.readonly) .copy-button-container{position:relative}:host(.readonly) .copy-button-container .copy-code-button{position:absolute;top:0px;right:0px}:host(.disabled:not(.highlight)) code{color:rgba(var(--v-text-input-disabled, 107, 116, 125, 1))}:host(.disabled.highlight){opacity:0.5}:host(.focus:not(.disabled,.readonly)){outline:2px solid rgba(var(--v-border-color-action, 19, 98, 226, 1));outline-offset:2px}:host(.highlight) code{color:var(--code-neutral)}code .comment,code .prolog,code .doctype,code .cdata{color:var(--code-gray);font-style:italic}code .namespace{color:var(--code-neutral-7)}code .string,code .attr-value,code .builtin{color:var(--code-green)}code .punctuation,code .operator,code .attr-equals{color:var(--code-gray)}code .entity,code .url,code .symbol,code .number,code .boolean,code .variable,code .constant,code .property,code .regex,code .inserted{color:var(--code-neutral-8)}code .atrule,code .function,code .attr-name{color:var(--code-orange)}code .deleted{color:var(--code-neutral)}code .function-variable{color:#ff0000}code .tag,code .selector,code .keyword{color:var(--code-purple)}";

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;
};
const VegaCodeBlock = class {
  constructor(hostRef) {
    index.registerInstance(this, hostRef);
    this.vegaChange = index.createEvent(this, "vegaChange", 7);
    this.change = index.createEvent(this, "change", 7);
    this.vegaRemove = index.createEvent(this, "vegaRemove", 7);
    this.remove = index.createEvent(this, "remove", 7);
    this.globalSlimmers = {};
    //TODO: The global style should be removed after the code color change to the color token.
    this.componentGlobalStyleSlimmer = new componentGlobalStyleSlimmer.ComponentGlobalStyleSlimmer(codeColorVariableCss);
    this.translationSlimmer = new translationSlimmer.TranslationSlimmer();
    this.vegaComponentUsageRuntimeMetricsSlimmer = new componentUsageRuntimeMetrics.VegaComponentUsageRuntimeMetricsSlimmer();
    this.codeBlockRenderer = new VegaCodeBlockRenderer();
    this.contentRenderer = new VegaCodeBlockContentRenderer();
    this.copyButtonRenderer = new VegaCodeBlockCopyButtonRenderer();
    this.valueController = new VegaCodeBlockValueController();
    this.contentParseController = new CodeContentParseController();
    this.prismCodeHighlightParser = new PrismCodeHighlightParseController();
    this.defaultCodeHighlightParser = new DefaultCodeHighlightParseController();
    this.selectionController = new VegaCodeBlockSelectionController();
    this.inputController = new CodeBlockInputController();
    this.insertCompositionTextController = new InsertCompositionTextController();
    this.focusController = new VegaCodeBlockFocusController();
    this.historyController = new VegaCodeBlockHistoryController();
    this.changeEventEmitter = eventEmitSlimmer.createEventEmitSlimmer(VegaCodeBlock, vegaEventId.VegaChange);
    this.removeEventEmitter = eventEmitSlimmer.createEventEmitSlimmer(VegaCodeBlock, vegaEventId.VegaRemove);
    this.codeBlockPasteController = new CodeBlockPasteController();
    this.eventPreventSlimmer = new childNodesEventPreventSlimmer.ChildNodesEventPreventSlimmer([vegaEventId.VegaChange], () => this.codeBlockRenderer.getToolbarContainerRef());
    /**
     * Specifies whether the code block editor is in read-only mode.
     *
     * @vegaVersion 2.50.0
     */
    this.readOnly = false;
    /**
     * Specifies whether the code block editor is disabled.
     *
     * @vegaVersion 2.50.0
     */
    this.disabled = false;
    /**
     * Specifies whether to display the copy button in the code block.
     *
     * @vegaVersion 2.50.0
     */
    this.showCopyButton = true;
    /**
     * Specifies whether to display the code line number in the code block.
     *
     * @vegaVersion 2.50.0
     */
    this.showLineNumber = true;
  }
  watchEditableChange() {
  }
  /**
   * Check the props value to avoid unnecessary updates.
   *
   * @param {unknown} newValue - The new props value.
   * @param {unknown} oldValue - The old props value.
   * @param {string} name - The property name.
   * @returns {boolean} Return false to skip the current update flow.
   */
  componentShouldUpdate(newValue, oldValue, name) {
    if (name === 'value' && object.deepEqual(newValue, oldValue)) {
      return false;
    }
    return true;
  }
  /**
   * Invoke this method to focus the current code block.
   *
   * @vegaVersion 2.50.0
   */
  async doFocus() {
  }
  render() {
    const classNames = ui.arrayToClassString([
      this.readOnly ? 'readonly' : '',
      this.disabled ? 'disabled' : '',
      this.showLineNumber ? 'show-line-number' : '',
      this.prismCodeHighlightParser.canParse() ? 'highlight' : '',
    ]);
    return component.sanitizeVegaComponent(index.h(index.Host, { contenteditable: false, class: classNames }, this.codeBlockRenderer.render()), this.host);
  }
  get host() { return index.getElement(this); }
  static get watchers() { return {
    "readOnly": ["watchEditableChange"],
    "disabled": ["watchEditableChange"]
  }; }
};
__decorate([
  componentUsageRuntimeMetrics.InjectVegaGlobalSlimmer()
], VegaCodeBlock.prototype, "globalSlimmers", void 0);
__decorate([
  globalSlimmerRegistry.InjectVegaSlimmer()
], VegaCodeBlock.prototype, "componentGlobalStyleSlimmer", void 0);
__decorate([
  globalSlimmerRegistry.InjectVegaSlimmer()
], VegaCodeBlock.prototype, "translationSlimmer", void 0);
__decorate([
  globalSlimmerRegistry.InjectVegaSlimmer()
], VegaCodeBlock.prototype, "vegaComponentUsageRuntimeMetricsSlimmer", void 0);
__decorate([
  globalSlimmerRegistry.InjectVegaSlimmer()
], VegaCodeBlock.prototype, "codeBlockRenderer", void 0);
__decorate([
  globalSlimmerRegistry.InjectVegaSlimmer()
], VegaCodeBlock.prototype, "contentRenderer", void 0);
__decorate([
  globalSlimmerRegistry.InjectVegaSlimmer()
], VegaCodeBlock.prototype, "copyButtonRenderer", void 0);
__decorate([
  globalSlimmerRegistry.InjectVegaSlimmer()
], VegaCodeBlock.prototype, "valueController", void 0);
__decorate([
  globalSlimmerRegistry.InjectVegaSlimmer()
], VegaCodeBlock.prototype, "contentParseController", void 0);
__decorate([
  globalSlimmerRegistry.InjectVegaSlimmer()
], VegaCodeBlock.prototype, "prismCodeHighlightParser", void 0);
__decorate([
  globalSlimmerRegistry.InjectVegaSlimmer()
], VegaCodeBlock.prototype, "defaultCodeHighlightParser", void 0);
__decorate([
  globalSlimmerRegistry.InjectVegaSlimmer()
], VegaCodeBlock.prototype, "selectionController", void 0);
__decorate([
  globalSlimmerRegistry.InjectVegaSlimmer()
], VegaCodeBlock.prototype, "inputController", void 0);
__decorate([
  globalSlimmerRegistry.InjectVegaSlimmer()
], VegaCodeBlock.prototype, "insertCompositionTextController", void 0);
__decorate([
  globalSlimmerRegistry.InjectVegaSlimmer()
], VegaCodeBlock.prototype, "focusController", void 0);
__decorate([
  globalSlimmerRegistry.InjectVegaSlimmer()
], VegaCodeBlock.prototype, "historyController", void 0);
__decorate([
  globalSlimmerRegistry.InjectVegaSlimmer()
], VegaCodeBlock.prototype, "changeEventEmitter", void 0);
__decorate([
  globalSlimmerRegistry.InjectVegaSlimmer()
], VegaCodeBlock.prototype, "removeEventEmitter", void 0);
__decorate([
  globalSlimmerRegistry.InjectVegaSlimmer()
], VegaCodeBlock.prototype, "codeBlockPasteController", void 0);
__decorate([
  globalSlimmerRegistry.InjectVegaSlimmer()
], VegaCodeBlock.prototype, "eventPreventSlimmer", void 0);
VegaCodeBlock.style = vegaCodeBlockCss;

exports.vega_code_block = VegaCodeBlock;
