[ Index ]

PHP Cross Reference of WordPress Trunk (Updated Daily)

Search

title

Body

[close]

/wp-includes/js/dist/ -> rich-text.js (source)

   1  /******/ (() => { // webpackBootstrap
   2  /******/     "use strict";
   3  /******/     // The require scope
   4  /******/     var __webpack_require__ = {};
   5  /******/     
   6  /************************************************************************/
   7  /******/     /* webpack/runtime/compat get default export */
   8  /******/     (() => {
   9  /******/         // getDefaultExport function for compatibility with non-harmony modules
  10  /******/         __webpack_require__.n = (module) => {
  11  /******/             var getter = module && module.__esModule ?
  12  /******/                 () => (module['default']) :
  13  /******/                 () => (module);
  14  /******/             __webpack_require__.d(getter, { a: getter });
  15  /******/             return getter;
  16  /******/         };
  17  /******/     })();
  18  /******/     
  19  /******/     /* webpack/runtime/define property getters */
  20  /******/     (() => {
  21  /******/         // define getter functions for harmony exports
  22  /******/         __webpack_require__.d = (exports, definition) => {
  23  /******/             for(var key in definition) {
  24  /******/                 if(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) {
  25  /******/                     Object.defineProperty(exports, key, { enumerable: true, get: definition[key] });
  26  /******/                 }
  27  /******/             }
  28  /******/         };
  29  /******/     })();
  30  /******/     
  31  /******/     /* webpack/runtime/hasOwnProperty shorthand */
  32  /******/     (() => {
  33  /******/         __webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop))
  34  /******/     })();
  35  /******/     
  36  /******/     /* webpack/runtime/make namespace object */
  37  /******/     (() => {
  38  /******/         // define __esModule on exports
  39  /******/         __webpack_require__.r = (exports) => {
  40  /******/             if(typeof Symbol !== 'undefined' && Symbol.toStringTag) {
  41  /******/                 Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
  42  /******/             }
  43  /******/             Object.defineProperty(exports, '__esModule', { value: true });
  44  /******/         };
  45  /******/     })();
  46  /******/     
  47  /************************************************************************/
  48  var __webpack_exports__ = {};
  49  // ESM COMPAT FLAG
  50  __webpack_require__.r(__webpack_exports__);
  51  
  52  // EXPORTS
  53  __webpack_require__.d(__webpack_exports__, {
  54    RichTextData: () => (/* reexport */ RichTextData),
  55    __experimentalRichText: () => (/* reexport */ __experimentalRichText),
  56    __unstableCreateElement: () => (/* reexport */ createElement),
  57    __unstableToDom: () => (/* reexport */ toDom),
  58    __unstableUseRichText: () => (/* reexport */ useRichText),
  59    applyFormat: () => (/* reexport */ applyFormat),
  60    concat: () => (/* reexport */ concat),
  61    create: () => (/* reexport */ create),
  62    getActiveFormat: () => (/* reexport */ getActiveFormat),
  63    getActiveFormats: () => (/* reexport */ getActiveFormats),
  64    getActiveObject: () => (/* reexport */ getActiveObject),
  65    getTextContent: () => (/* reexport */ getTextContent),
  66    insert: () => (/* reexport */ insert),
  67    insertObject: () => (/* reexport */ insertObject),
  68    isCollapsed: () => (/* reexport */ isCollapsed),
  69    isEmpty: () => (/* reexport */ isEmpty),
  70    join: () => (/* reexport */ join),
  71    registerFormatType: () => (/* reexport */ registerFormatType),
  72    remove: () => (/* reexport */ remove_remove),
  73    removeFormat: () => (/* reexport */ removeFormat),
  74    replace: () => (/* reexport */ replace_replace),
  75    slice: () => (/* reexport */ slice),
  76    split: () => (/* reexport */ split),
  77    store: () => (/* reexport */ store),
  78    toHTMLString: () => (/* reexport */ toHTMLString),
  79    toggleFormat: () => (/* reexport */ toggleFormat),
  80    unregisterFormatType: () => (/* reexport */ unregisterFormatType),
  81    useAnchor: () => (/* reexport */ useAnchor),
  82    useAnchorRef: () => (/* reexport */ useAnchorRef)
  83  });
  84  
  85  // NAMESPACE OBJECT: ./node_modules/@wordpress/rich-text/build-module/store/selectors.js
  86  var selectors_namespaceObject = {};
  87  __webpack_require__.r(selectors_namespaceObject);
  88  __webpack_require__.d(selectors_namespaceObject, {
  89    getFormatType: () => (getFormatType),
  90    getFormatTypeForBareElement: () => (getFormatTypeForBareElement),
  91    getFormatTypeForClassName: () => (getFormatTypeForClassName),
  92    getFormatTypes: () => (getFormatTypes)
  93  });
  94  
  95  // NAMESPACE OBJECT: ./node_modules/@wordpress/rich-text/build-module/store/actions.js
  96  var actions_namespaceObject = {};
  97  __webpack_require__.r(actions_namespaceObject);
  98  __webpack_require__.d(actions_namespaceObject, {
  99    addFormatTypes: () => (addFormatTypes),
 100    removeFormatTypes: () => (removeFormatTypes)
 101  });
 102  
 103  ;// CONCATENATED MODULE: external ["wp","data"]
 104  const external_wp_data_namespaceObject = window["wp"]["data"];
 105  ;// CONCATENATED MODULE: ./node_modules/@wordpress/rich-text/build-module/store/reducer.js
 106  /**
 107   * WordPress dependencies
 108   */
 109  
 110  
 111  /**
 112   * Reducer managing the format types
 113   *
 114   * @param {Object} state  Current state.
 115   * @param {Object} action Dispatched action.
 116   *
 117   * @return {Object} Updated state.
 118   */
 119  function formatTypes(state = {}, action) {
 120    switch (action.type) {
 121      case 'ADD_FORMAT_TYPES':
 122        return {
 123          ...state,
 124          // Key format types by their name.
 125          ...action.formatTypes.reduce((newFormatTypes, type) => ({
 126            ...newFormatTypes,
 127            [type.name]: type
 128          }), {})
 129        };
 130      case 'REMOVE_FORMAT_TYPES':
 131        return Object.fromEntries(Object.entries(state).filter(([key]) => !action.names.includes(key)));
 132    }
 133    return state;
 134  }
 135  /* harmony default export */ const reducer = ((0,external_wp_data_namespaceObject.combineReducers)({
 136    formatTypes
 137  }));
 138  
 139  ;// CONCATENATED MODULE: ./node_modules/@wordpress/rich-text/build-module/store/selectors.js
 140  /**
 141   * WordPress dependencies
 142   */
 143  
 144  
 145  /**
 146   * Returns all the available format types.
 147   *
 148   * @param {Object} state Data state.
 149   *
 150   * @example
 151   * ```js
 152   * import { __, sprintf } from '@wordpress/i18n';
 153   * import { store as richTextStore } from '@wordpress/rich-text';
 154   * import { useSelect } from '@wordpress/data';
 155   *
 156   * const ExampleComponent = () => {
 157   *    const { getFormatTypes } = useSelect(
 158   *        ( select ) => select( richTextStore ),
 159   *        []
 160   *    );
 161   *
 162   *    const availableFormats = getFormatTypes();
 163   *
 164   *    return availableFormats ? (
 165   *        <ul>
 166   *            { availableFormats?.map( ( format ) => (
 167   *                <li>{ format.name }</li>
 168   *           ) ) }
 169   *        </ul>
 170   *    ) : (
 171   *        __( 'No Formats available' )
 172   *    );
 173   * };
 174   * ```
 175   *
 176   * @return {Array} Format types.
 177   */
 178  const getFormatTypes = (0,external_wp_data_namespaceObject.createSelector)(state => Object.values(state.formatTypes), state => [state.formatTypes]);
 179  
 180  /**
 181   * Returns a format type by name.
 182   *
 183   * @param {Object} state Data state.
 184   * @param {string} name  Format type name.
 185   *
 186   * @example
 187   * ```js
 188   * import { __, sprintf } from '@wordpress/i18n';
 189   * import { store as richTextStore } from '@wordpress/rich-text';
 190   * import { useSelect } from '@wordpress/data';
 191   *
 192   * const ExampleComponent = () => {
 193   *    const { getFormatType } = useSelect(
 194   *        ( select ) => select( richTextStore ),
 195   *        []
 196   *    );
 197   *
 198   *    const boldFormat = getFormatType( 'core/bold' );
 199   *
 200   *    return boldFormat ? (
 201   *        <ul>
 202   *            { Object.entries( boldFormat )?.map( ( [ key, value ] ) => (
 203   *                <li>
 204   *                    { key } : { value }
 205   *                </li>
 206   *           ) ) }
 207   *       </ul>
 208   *    ) : (
 209   *        __( 'Not Found' )
 210   *    ;
 211   * };
 212   * ```
 213   *
 214   * @return {Object?} Format type.
 215   */
 216  function getFormatType(state, name) {
 217    return state.formatTypes[name];
 218  }
 219  
 220  /**
 221   * Gets the format type, if any, that can handle a bare element (without a
 222   * data-format-type attribute), given the tag name of this element.
 223   *
 224   * @param {Object} state              Data state.
 225   * @param {string} bareElementTagName The tag name of the element to find a
 226   *                                    format type for.
 227   *
 228   * @example
 229   * ```js
 230   * import { __, sprintf } from '@wordpress/i18n';
 231   * import { store as richTextStore } from '@wordpress/rich-text';
 232   * import { useSelect } from '@wordpress/data';
 233   *
 234   * const ExampleComponent = () => {
 235   *    const { getFormatTypeForBareElement } = useSelect(
 236   *        ( select ) => select( richTextStore ),
 237   *        []
 238   *    );
 239   *
 240   *    const format = getFormatTypeForBareElement( 'strong' );
 241   *
 242   *    return format && <p>{ sprintf( __( 'Format name: %s' ), format.name ) }</p>;
 243   * }
 244   * ```
 245   *
 246   * @return {?Object} Format type.
 247   */
 248  function getFormatTypeForBareElement(state, bareElementTagName) {
 249    const formatTypes = getFormatTypes(state);
 250    return formatTypes.find(({
 251      className,
 252      tagName
 253    }) => {
 254      return className === null && bareElementTagName === tagName;
 255    }) || formatTypes.find(({
 256      className,
 257      tagName
 258    }) => {
 259      return className === null && '*' === tagName;
 260    });
 261  }
 262  
 263  /**
 264   * Gets the format type, if any, that can handle an element, given its classes.
 265   *
 266   * @param {Object} state            Data state.
 267   * @param {string} elementClassName The classes of the element to find a format
 268   *                                  type for.
 269   *
 270   * @example
 271   * ```js
 272   * import { __, sprintf } from '@wordpress/i18n';
 273   * import { store as richTextStore } from '@wordpress/rich-text';
 274   * import { useSelect } from '@wordpress/data';
 275   *
 276   * const ExampleComponent = () => {
 277   *    const { getFormatTypeForClassName } = useSelect(
 278   *        ( select ) => select( richTextStore ),
 279   *        []
 280   *    );
 281   *
 282   *    const format = getFormatTypeForClassName( 'has-inline-color' );
 283   *
 284   *    return format && <p>{ sprintf( __( 'Format name: %s' ), format.name ) }</p>;
 285   * };
 286   * ```
 287   *
 288   * @return {?Object} Format type.
 289   */
 290  function getFormatTypeForClassName(state, elementClassName) {
 291    return getFormatTypes(state).find(({
 292      className
 293    }) => {
 294      if (className === null) {
 295        return false;
 296      }
 297      return ` $elementClassName} `.indexOf(` $className} `) >= 0;
 298    });
 299  }
 300  
 301  ;// CONCATENATED MODULE: ./node_modules/@wordpress/rich-text/build-module/store/actions.js
 302  /**
 303   * Returns an action object used in signalling that format types have been
 304   * added.
 305   * Ignored from documentation as registerFormatType should be used instead from @wordpress/rich-text
 306   *
 307   * @ignore
 308   *
 309   * @param {Array|Object} formatTypes Format types received.
 310   *
 311   * @return {Object} Action object.
 312   */
 313  function addFormatTypes(formatTypes) {
 314    return {
 315      type: 'ADD_FORMAT_TYPES',
 316      formatTypes: Array.isArray(formatTypes) ? formatTypes : [formatTypes]
 317    };
 318  }
 319  
 320  /**
 321   * Returns an action object used to remove a registered format type.
 322   *
 323   * Ignored from documentation as unregisterFormatType should be used instead from @wordpress/rich-text
 324   *
 325   * @ignore
 326   *
 327   * @param {string|Array} names Format name.
 328   *
 329   * @return {Object} Action object.
 330   */
 331  function removeFormatTypes(names) {
 332    return {
 333      type: 'REMOVE_FORMAT_TYPES',
 334      names: Array.isArray(names) ? names : [names]
 335    };
 336  }
 337  
 338  ;// CONCATENATED MODULE: ./node_modules/@wordpress/rich-text/build-module/store/index.js
 339  /**
 340   * WordPress dependencies
 341   */
 342  
 343  
 344  /**
 345   * Internal dependencies
 346   */
 347  
 348  
 349  
 350  const STORE_NAME = 'core/rich-text';
 351  
 352  /**
 353   * Store definition for the rich-text namespace.
 354   *
 355   * @see https://github.com/WordPress/gutenberg/blob/HEAD/packages/data/README.md#createReduxStore
 356   *
 357   * @type {Object}
 358   */
 359  const store = (0,external_wp_data_namespaceObject.createReduxStore)(STORE_NAME, {
 360    reducer: reducer,
 361    selectors: selectors_namespaceObject,
 362    actions: actions_namespaceObject
 363  });
 364  (0,external_wp_data_namespaceObject.register)(store);
 365  
 366  ;// CONCATENATED MODULE: ./node_modules/@wordpress/rich-text/build-module/is-format-equal.js
 367  /** @typedef {import('./types').RichTextFormat} RichTextFormat */
 368  
 369  /**
 370   * Optimised equality check for format objects.
 371   *
 372   * @param {?RichTextFormat} format1 Format to compare.
 373   * @param {?RichTextFormat} format2 Format to compare.
 374   *
 375   * @return {boolean} True if formats are equal, false if not.
 376   */
 377  function isFormatEqual(format1, format2) {
 378    // Both not defined.
 379    if (format1 === format2) {
 380      return true;
 381    }
 382  
 383    // Either not defined.
 384    if (!format1 || !format2) {
 385      return false;
 386    }
 387    if (format1.type !== format2.type) {
 388      return false;
 389    }
 390    const attributes1 = format1.attributes;
 391    const attributes2 = format2.attributes;
 392  
 393    // Both not defined.
 394    if (attributes1 === attributes2) {
 395      return true;
 396    }
 397  
 398    // Either not defined.
 399    if (!attributes1 || !attributes2) {
 400      return false;
 401    }
 402    const keys1 = Object.keys(attributes1);
 403    const keys2 = Object.keys(attributes2);
 404    if (keys1.length !== keys2.length) {
 405      return false;
 406    }
 407    const length = keys1.length;
 408  
 409    // Optimise for speed.
 410    for (let i = 0; i < length; i++) {
 411      const name = keys1[i];
 412      if (attributes1[name] !== attributes2[name]) {
 413        return false;
 414      }
 415    }
 416    return true;
 417  }
 418  
 419  ;// CONCATENATED MODULE: ./node_modules/@wordpress/rich-text/build-module/normalise-formats.js
 420  /**
 421   * Internal dependencies
 422   */
 423  
 424  
 425  
 426  /** @typedef {import('./types').RichTextValue} RichTextValue */
 427  
 428  /**
 429   * Normalises formats: ensures subsequent adjacent equal formats have the same
 430   * reference.
 431   *
 432   * @param {RichTextValue} value Value to normalise formats of.
 433   *
 434   * @return {RichTextValue} New value with normalised formats.
 435   */
 436  function normaliseFormats(value) {
 437    const newFormats = value.formats.slice();
 438    newFormats.forEach((formatsAtIndex, index) => {
 439      const formatsAtPreviousIndex = newFormats[index - 1];
 440      if (formatsAtPreviousIndex) {
 441        const newFormatsAtIndex = formatsAtIndex.slice();
 442        newFormatsAtIndex.forEach((format, formatIndex) => {
 443          const previousFormat = formatsAtPreviousIndex[formatIndex];
 444          if (isFormatEqual(format, previousFormat)) {
 445            newFormatsAtIndex[formatIndex] = previousFormat;
 446          }
 447        });
 448        newFormats[index] = newFormatsAtIndex;
 449      }
 450    });
 451    return {
 452      ...value,
 453      formats: newFormats
 454    };
 455  }
 456  
 457  ;// CONCATENATED MODULE: ./node_modules/@wordpress/rich-text/build-module/apply-format.js
 458  /**
 459   * Internal dependencies
 460   */
 461  
 462  
 463  
 464  /** @typedef {import('./types').RichTextValue} RichTextValue */
 465  /** @typedef {import('./types').RichTextFormat} RichTextFormat */
 466  
 467  function replace(array, index, value) {
 468    array = array.slice();
 469    array[index] = value;
 470    return array;
 471  }
 472  
 473  /**
 474   * Apply a format object to a Rich Text value from the given `startIndex` to the
 475   * given `endIndex`. Indices are retrieved from the selection if none are
 476   * provided.
 477   *
 478   * @param {RichTextValue}  value        Value to modify.
 479   * @param {RichTextFormat} format       Format to apply.
 480   * @param {number}         [startIndex] Start index.
 481   * @param {number}         [endIndex]   End index.
 482   *
 483   * @return {RichTextValue} A new value with the format applied.
 484   */
 485  function applyFormat(value, format, startIndex = value.start, endIndex = value.end) {
 486    const {
 487      formats,
 488      activeFormats
 489    } = value;
 490    const newFormats = formats.slice();
 491  
 492    // The selection is collapsed.
 493    if (startIndex === endIndex) {
 494      const startFormat = newFormats[startIndex]?.find(({
 495        type
 496      }) => type === format.type);
 497  
 498      // If the caret is at a format of the same type, expand start and end to
 499      // the edges of the format. This is useful to apply new attributes.
 500      if (startFormat) {
 501        const index = newFormats[startIndex].indexOf(startFormat);
 502        while (newFormats[startIndex] && newFormats[startIndex][index] === startFormat) {
 503          newFormats[startIndex] = replace(newFormats[startIndex], index, format);
 504          startIndex--;
 505        }
 506        endIndex++;
 507        while (newFormats[endIndex] && newFormats[endIndex][index] === startFormat) {
 508          newFormats[endIndex] = replace(newFormats[endIndex], index, format);
 509          endIndex++;
 510        }
 511      }
 512    } else {
 513      // Determine the highest position the new format can be inserted at.
 514      let position = +Infinity;
 515      for (let index = startIndex; index < endIndex; index++) {
 516        if (newFormats[index]) {
 517          newFormats[index] = newFormats[index].filter(({
 518            type
 519          }) => type !== format.type);
 520          const length = newFormats[index].length;
 521          if (length < position) {
 522            position = length;
 523          }
 524        } else {
 525          newFormats[index] = [];
 526          position = 0;
 527        }
 528      }
 529      for (let index = startIndex; index < endIndex; index++) {
 530        newFormats[index].splice(position, 0, format);
 531      }
 532    }
 533    return normaliseFormats({
 534      ...value,
 535      formats: newFormats,
 536      // Always revise active formats. This serves as a placeholder for new
 537      // inputs with the format so new input appears with the format applied,
 538      // and ensures a format of the same type uses the latest values.
 539      activeFormats: [...(activeFormats?.filter(({
 540        type
 541      }) => type !== format.type) || []), format]
 542    });
 543  }
 544  
 545  ;// CONCATENATED MODULE: ./node_modules/@wordpress/rich-text/build-module/create-element.js
 546  /**
 547   * Parse the given HTML into a body element.
 548   *
 549   * Note: The current implementation will return a shared reference, reset on
 550   * each call to `createElement`. Therefore, you should not hold a reference to
 551   * the value to operate upon asynchronously, as it may have unexpected results.
 552   *
 553   * @param {HTMLDocument} document The HTML document to use to parse.
 554   * @param {string}       html     The HTML to parse.
 555   *
 556   * @return {HTMLBodyElement} Body element with parsed HTML.
 557   */
 558  function createElement({
 559    implementation
 560  }, html) {
 561    // Because `createHTMLDocument` is an expensive operation, and with this
 562    // function being internal to `rich-text` (full control in avoiding a risk
 563    // of asynchronous operations on the shared reference), a single document
 564    // is reused and reset for each call to the function.
 565    if (!createElement.body) {
 566      createElement.body = implementation.createHTMLDocument('').body;
 567    }
 568    createElement.body.innerHTML = html;
 569    return createElement.body;
 570  }
 571  
 572  ;// CONCATENATED MODULE: ./node_modules/@wordpress/rich-text/build-module/special-characters.js
 573  /**
 574   * Object replacement character, used as a placeholder for objects.
 575   */
 576  const OBJECT_REPLACEMENT_CHARACTER = '\ufffc';
 577  
 578  /**
 579   * Zero width non-breaking space, used as padding in the editable DOM tree when
 580   * it is empty otherwise.
 581   */
 582  const ZWNBSP = '\ufeff';
 583  
 584  ;// CONCATENATED MODULE: external ["wp","escapeHtml"]
 585  const external_wp_escapeHtml_namespaceObject = window["wp"]["escapeHtml"];
 586  ;// CONCATENATED MODULE: ./node_modules/@wordpress/rich-text/build-module/get-active-formats.js
 587  /** @typedef {import('./types').RichTextValue} RichTextValue */
 588  /** @typedef {import('./types').RichTextFormatList} RichTextFormatList */
 589  
 590  /**
 591   * Internal dependencies
 592   */
 593  
 594  
 595  /**
 596   * Gets the all format objects at the start of the selection.
 597   *
 598   * @param {RichTextValue} value                Value to inspect.
 599   * @param {Array}         EMPTY_ACTIVE_FORMATS Array to return if there are no
 600   *                                             active formats.
 601   *
 602   * @return {RichTextFormatList} Active format objects.
 603   */
 604  function getActiveFormats(value, EMPTY_ACTIVE_FORMATS = []) {
 605    const {
 606      formats,
 607      start,
 608      end,
 609      activeFormats
 610    } = value;
 611    if (start === undefined) {
 612      return EMPTY_ACTIVE_FORMATS;
 613    }
 614    if (start === end) {
 615      // For a collapsed caret, it is possible to override the active formats.
 616      if (activeFormats) {
 617        return activeFormats;
 618      }
 619      const formatsBefore = formats[start - 1] || EMPTY_ACTIVE_FORMATS;
 620      const formatsAfter = formats[start] || EMPTY_ACTIVE_FORMATS;
 621  
 622      // By default, select the lowest amount of formats possible (which means
 623      // the caret is positioned outside the format boundary). The user can
 624      // then use arrow keys to define `activeFormats`.
 625      if (formatsBefore.length < formatsAfter.length) {
 626        return formatsBefore;
 627      }
 628      return formatsAfter;
 629    }
 630  
 631    // If there's no formats at the start index, there are not active formats.
 632    if (!formats[start]) {
 633      return EMPTY_ACTIVE_FORMATS;
 634    }
 635    const selectedFormats = formats.slice(start, end);
 636  
 637    // Clone the formats so we're not mutating the live value.
 638    const _activeFormats = [...selectedFormats[0]];
 639    let i = selectedFormats.length;
 640  
 641    // For performance reasons, start from the end where it's much quicker to
 642    // realise that there are no active formats.
 643    while (i--) {
 644      const formatsAtIndex = selectedFormats[i];
 645  
 646      // If we run into any index without formats, we're sure that there's no
 647      // active formats.
 648      if (!formatsAtIndex) {
 649        return EMPTY_ACTIVE_FORMATS;
 650      }
 651      let ii = _activeFormats.length;
 652  
 653      // Loop over the active formats and remove any that are not present at
 654      // the current index.
 655      while (ii--) {
 656        const format = _activeFormats[ii];
 657        if (!formatsAtIndex.find(_format => isFormatEqual(format, _format))) {
 658          _activeFormats.splice(ii, 1);
 659        }
 660      }
 661  
 662      // If there are no active formats, we can stop.
 663      if (_activeFormats.length === 0) {
 664        return EMPTY_ACTIVE_FORMATS;
 665      }
 666    }
 667    return _activeFormats || EMPTY_ACTIVE_FORMATS;
 668  }
 669  
 670  ;// CONCATENATED MODULE: ./node_modules/@wordpress/rich-text/build-module/get-format-type.js
 671  /**
 672   * WordPress dependencies
 673   */
 674  
 675  /**
 676   * Internal dependencies
 677   */
 678  
 679  
 680  /** @typedef {import('./register-format-type').RichTextFormatType} RichTextFormatType */
 681  
 682  /**
 683   * Returns a registered format type.
 684   *
 685   * @param {string} name Format name.
 686   *
 687   * @return {RichTextFormatType|undefined} Format type.
 688   */
 689  function get_format_type_getFormatType(name) {
 690    return (0,external_wp_data_namespaceObject.select)(store).getFormatType(name);
 691  }
 692  
 693  ;// CONCATENATED MODULE: ./node_modules/@wordpress/rich-text/build-module/to-tree.js
 694  /**
 695   * Internal dependencies
 696   */
 697  
 698  
 699  
 700  
 701  function restoreOnAttributes(attributes, isEditableTree) {
 702    if (isEditableTree) {
 703      return attributes;
 704    }
 705    const newAttributes = {};
 706    for (const key in attributes) {
 707      let newKey = key;
 708      if (key.startsWith('data-disable-rich-text-')) {
 709        newKey = key.slice('data-disable-rich-text-'.length);
 710      }
 711      newAttributes[newKey] = attributes[key];
 712    }
 713    return newAttributes;
 714  }
 715  
 716  /**
 717   * Converts a format object to information that can be used to create an element
 718   * from (type, attributes and object).
 719   *
 720   * @param {Object}  $1                        Named parameters.
 721   * @param {string}  $1.type                   The format type.
 722   * @param {string}  $1.tagName                The tag name.
 723   * @param {Object}  $1.attributes             The format attributes.
 724   * @param {Object}  $1.unregisteredAttributes The unregistered format
 725   *                                            attributes.
 726   * @param {boolean} $1.object                 Whether or not it is an object
 727   *                                            format.
 728   * @param {boolean} $1.boundaryClass          Whether or not to apply a boundary
 729   *                                            class.
 730   * @param {boolean} $1.isEditableTree
 731   *
 732   * @return {Object} Information to be used for element creation.
 733   */
 734  function fromFormat({
 735    type,
 736    tagName,
 737    attributes,
 738    unregisteredAttributes,
 739    object,
 740    boundaryClass,
 741    isEditableTree
 742  }) {
 743    const formatType = get_format_type_getFormatType(type);
 744    let elementAttributes = {};
 745    if (boundaryClass && isEditableTree) {
 746      elementAttributes['data-rich-text-format-boundary'] = 'true';
 747    }
 748    if (!formatType) {
 749      if (attributes) {
 750        elementAttributes = {
 751          ...attributes,
 752          ...elementAttributes
 753        };
 754      }
 755      return {
 756        type,
 757        attributes: restoreOnAttributes(elementAttributes, isEditableTree),
 758        object
 759      };
 760    }
 761    elementAttributes = {
 762      ...unregisteredAttributes,
 763      ...elementAttributes
 764    };
 765    for (const name in attributes) {
 766      const key = formatType.attributes ? formatType.attributes[name] : false;
 767      if (key) {
 768        elementAttributes[key] = attributes[name];
 769      } else {
 770        elementAttributes[name] = attributes[name];
 771      }
 772    }
 773    if (formatType.className) {
 774      if (elementAttributes.class) {
 775        elementAttributes.class = `$formatType.className} $elementAttributes.class}`;
 776      } else {
 777        elementAttributes.class = formatType.className;
 778      }
 779    }
 780  
 781    // When a format is declared as non editable, make it non editable in the
 782    // editor.
 783    if (isEditableTree && formatType.contentEditable === false) {
 784      elementAttributes.contenteditable = 'false';
 785    }
 786    return {
 787      type: tagName || formatType.tagName,
 788      object: formatType.object,
 789      attributes: restoreOnAttributes(elementAttributes, isEditableTree)
 790    };
 791  }
 792  
 793  /**
 794   * Checks if both arrays of formats up until a certain index are equal.
 795   *
 796   * @param {Array}  a     Array of formats to compare.
 797   * @param {Array}  b     Array of formats to compare.
 798   * @param {number} index Index to check until.
 799   */
 800  function isEqualUntil(a, b, index) {
 801    do {
 802      if (a[index] !== b[index]) {
 803        return false;
 804      }
 805    } while (index--);
 806    return true;
 807  }
 808  function toTree({
 809    value,
 810    preserveWhiteSpace,
 811    createEmpty,
 812    append,
 813    getLastChild,
 814    getParent,
 815    isText,
 816    getText,
 817    remove,
 818    appendText,
 819    onStartIndex,
 820    onEndIndex,
 821    isEditableTree,
 822    placeholder
 823  }) {
 824    const {
 825      formats,
 826      replacements,
 827      text,
 828      start,
 829      end
 830    } = value;
 831    const formatsLength = formats.length + 1;
 832    const tree = createEmpty();
 833    const activeFormats = getActiveFormats(value);
 834    const deepestActiveFormat = activeFormats[activeFormats.length - 1];
 835    let lastCharacterFormats;
 836    let lastCharacter;
 837    append(tree, '');
 838    for (let i = 0; i < formatsLength; i++) {
 839      const character = text.charAt(i);
 840      const shouldInsertPadding = isEditableTree && (
 841      // Pad the line if the line is empty.
 842      !lastCharacter ||
 843      // Pad the line if the previous character is a line break, otherwise
 844      // the line break won't be visible.
 845      lastCharacter === '\n');
 846      const characterFormats = formats[i];
 847      let pointer = getLastChild(tree);
 848      if (characterFormats) {
 849        characterFormats.forEach((format, formatIndex) => {
 850          if (pointer && lastCharacterFormats &&
 851          // Reuse the last element if all formats remain the same.
 852          isEqualUntil(characterFormats, lastCharacterFormats, formatIndex)) {
 853            pointer = getLastChild(pointer);
 854            return;
 855          }
 856          const {
 857            type,
 858            tagName,
 859            attributes,
 860            unregisteredAttributes
 861          } = format;
 862          const boundaryClass = isEditableTree && format === deepestActiveFormat;
 863          const parent = getParent(pointer);
 864          const newNode = append(parent, fromFormat({
 865            type,
 866            tagName,
 867            attributes,
 868            unregisteredAttributes,
 869            boundaryClass,
 870            isEditableTree
 871          }));
 872          if (isText(pointer) && getText(pointer).length === 0) {
 873            remove(pointer);
 874          }
 875          pointer = append(newNode, '');
 876        });
 877      }
 878  
 879      // If there is selection at 0, handle it before characters are inserted.
 880      if (i === 0) {
 881        if (onStartIndex && start === 0) {
 882          onStartIndex(tree, pointer);
 883        }
 884        if (onEndIndex && end === 0) {
 885          onEndIndex(tree, pointer);
 886        }
 887      }
 888      if (character === OBJECT_REPLACEMENT_CHARACTER) {
 889        const replacement = replacements[i];
 890        if (!replacement) {
 891          continue;
 892        }
 893        const {
 894          type,
 895          attributes,
 896          innerHTML
 897        } = replacement;
 898        const formatType = get_format_type_getFormatType(type);
 899        if (!isEditableTree && type === 'script') {
 900          pointer = append(getParent(pointer), fromFormat({
 901            type: 'script',
 902            isEditableTree
 903          }));
 904          append(pointer, {
 905            html: decodeURIComponent(attributes['data-rich-text-script'])
 906          });
 907        } else if (formatType?.contentEditable === false) {
 908          // For non editable formats, render the stored inner HTML.
 909          pointer = append(getParent(pointer), fromFormat({
 910            ...replacement,
 911            isEditableTree,
 912            boundaryClass: start === i && end === i + 1
 913          }));
 914          if (innerHTML) {
 915            append(pointer, {
 916              html: innerHTML
 917            });
 918          }
 919        } else {
 920          pointer = append(getParent(pointer), fromFormat({
 921            ...replacement,
 922            object: true,
 923            isEditableTree
 924          }));
 925        }
 926        // Ensure pointer is text node.
 927        pointer = append(getParent(pointer), '');
 928      } else if (!preserveWhiteSpace && character === '\n') {
 929        pointer = append(getParent(pointer), {
 930          type: 'br',
 931          attributes: isEditableTree ? {
 932            'data-rich-text-line-break': 'true'
 933          } : undefined,
 934          object: true
 935        });
 936        // Ensure pointer is text node.
 937        pointer = append(getParent(pointer), '');
 938      } else if (!isText(pointer)) {
 939        pointer = append(getParent(pointer), character);
 940      } else {
 941        appendText(pointer, character);
 942      }
 943      if (onStartIndex && start === i + 1) {
 944        onStartIndex(tree, pointer);
 945      }
 946      if (onEndIndex && end === i + 1) {
 947        onEndIndex(tree, pointer);
 948      }
 949      if (shouldInsertPadding && i === text.length) {
 950        append(getParent(pointer), ZWNBSP);
 951  
 952        // We CANNOT use CSS to add a placeholder with pseudo elements on
 953        // the main block wrappers because that could clash with theme CSS.
 954        if (placeholder && text.length === 0) {
 955          append(getParent(pointer), {
 956            type: 'span',
 957            attributes: {
 958              'data-rich-text-placeholder': placeholder,
 959              // Necessary to prevent the placeholder from catching
 960              // selection and being editable.
 961              style: 'pointer-events:none;user-select:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;'
 962            }
 963          });
 964        }
 965      }
 966      lastCharacterFormats = characterFormats;
 967      lastCharacter = character;
 968    }
 969    return tree;
 970  }
 971  
 972  ;// CONCATENATED MODULE: ./node_modules/@wordpress/rich-text/build-module/to-html-string.js
 973  /**
 974   * WordPress dependencies
 975   */
 976  
 977  
 978  
 979  /**
 980   * Internal dependencies
 981   */
 982  
 983  
 984  
 985  /** @typedef {import('./types').RichTextValue} RichTextValue */
 986  
 987  /**
 988   * Create an HTML string from a Rich Text value.
 989   *
 990   * @param {Object}        $1                      Named argements.
 991   * @param {RichTextValue} $1.value                Rich text value.
 992   * @param {boolean}       [$1.preserveWhiteSpace] Preserves newlines if true.
 993   *
 994   * @return {string} HTML string.
 995   */
 996  function toHTMLString({
 997    value,
 998    preserveWhiteSpace
 999  }) {
1000    const tree = toTree({
1001      value,
1002      preserveWhiteSpace,
1003      createEmpty,
1004      append,
1005      getLastChild,
1006      getParent,
1007      isText,
1008      getText,
1009      remove,
1010      appendText
1011    });
1012    return createChildrenHTML(tree.children);
1013  }
1014  function createEmpty() {
1015    return {};
1016  }
1017  function getLastChild({
1018    children
1019  }) {
1020    return children && children[children.length - 1];
1021  }
1022  function append(parent, object) {
1023    if (typeof object === 'string') {
1024      object = {
1025        text: object
1026      };
1027    }
1028    object.parent = parent;
1029    parent.children = parent.children || [];
1030    parent.children.push(object);
1031    return object;
1032  }
1033  function appendText(object, text) {
1034    object.text += text;
1035  }
1036  function getParent({
1037    parent
1038  }) {
1039    return parent;
1040  }
1041  function isText({
1042    text
1043  }) {
1044    return typeof text === 'string';
1045  }
1046  function getText({
1047    text
1048  }) {
1049    return text;
1050  }
1051  function remove(object) {
1052    const index = object.parent.children.indexOf(object);
1053    if (index !== -1) {
1054      object.parent.children.splice(index, 1);
1055    }
1056    return object;
1057  }
1058  function createElementHTML({
1059    type,
1060    attributes,
1061    object,
1062    children
1063  }) {
1064    let attributeString = '';
1065    for (const key in attributes) {
1066      if (!(0,external_wp_escapeHtml_namespaceObject.isValidAttributeName)(key)) {
1067        continue;
1068      }
1069      attributeString += ` $key}="${(0,external_wp_escapeHtml_namespaceObject.escapeAttribute)(attributes[key])}"`;
1070    }
1071    if (object) {
1072      return `<$type}$attributeString}>`;
1073    }
1074    return `<$type}$attributeString}>$createChildrenHTML(children)}</$type}>`;
1075  }
1076  function createChildrenHTML(children = []) {
1077    return children.map(child => {
1078      if (child.html !== undefined) {
1079        return child.html;
1080      }
1081      return child.text === undefined ? createElementHTML(child) : (0,external_wp_escapeHtml_namespaceObject.escapeEditableHTML)(child.text);
1082    }).join('');
1083  }
1084  
1085  ;// CONCATENATED MODULE: ./node_modules/@wordpress/rich-text/build-module/get-text-content.js
1086  /**
1087   * Internal dependencies
1088   */
1089  
1090  
1091  /** @typedef {import('./types').RichTextValue} RichTextValue */
1092  
1093  /**
1094   * Get the textual content of a Rich Text value. This is similar to
1095   * `Element.textContent`.
1096   *
1097   * @param {RichTextValue} value Value to use.
1098   *
1099   * @return {string} The text content.
1100   */
1101  function getTextContent({
1102    text
1103  }) {
1104    return text.replace(OBJECT_REPLACEMENT_CHARACTER, '');
1105  }
1106  
1107  ;// CONCATENATED MODULE: ./node_modules/@wordpress/rich-text/build-module/create.js
1108  /**
1109   * WordPress dependencies
1110   */
1111  
1112  
1113  /**
1114   * Internal dependencies
1115   */
1116  
1117  
1118  
1119  
1120  
1121  
1122  
1123  /** @typedef {import('./types').RichTextValue} RichTextValue */
1124  
1125  function createEmptyValue() {
1126    return {
1127      formats: [],
1128      replacements: [],
1129      text: ''
1130    };
1131  }
1132  function toFormat({
1133    tagName,
1134    attributes
1135  }) {
1136    let formatType;
1137    if (attributes && attributes.class) {
1138      formatType = (0,external_wp_data_namespaceObject.select)(store).getFormatTypeForClassName(attributes.class);
1139      if (formatType) {
1140        // Preserve any additional classes.
1141        attributes.class = ` $attributes.class} `.replace(` $formatType.className} `, ' ').trim();
1142        if (!attributes.class) {
1143          delete attributes.class;
1144        }
1145      }
1146    }
1147    if (!formatType) {
1148      formatType = (0,external_wp_data_namespaceObject.select)(store).getFormatTypeForBareElement(tagName);
1149    }
1150    if (!formatType) {
1151      return attributes ? {
1152        type: tagName,
1153        attributes
1154      } : {
1155        type: tagName
1156      };
1157    }
1158    if (formatType.__experimentalCreatePrepareEditableTree && !formatType.__experimentalCreateOnChangeEditableValue) {
1159      return null;
1160    }
1161    if (!attributes) {
1162      return {
1163        formatType,
1164        type: formatType.name,
1165        tagName
1166      };
1167    }
1168    const registeredAttributes = {};
1169    const unregisteredAttributes = {};
1170    const _attributes = {
1171      ...attributes
1172    };
1173    for (const key in formatType.attributes) {
1174      const name = formatType.attributes[key];
1175      registeredAttributes[key] = _attributes[name];
1176  
1177      // delete the attribute and what's left is considered
1178      // to be unregistered.
1179      delete _attributes[name];
1180      if (typeof registeredAttributes[key] === 'undefined') {
1181        delete registeredAttributes[key];
1182      }
1183    }
1184    for (const name in _attributes) {
1185      unregisteredAttributes[name] = attributes[name];
1186    }
1187    if (formatType.contentEditable === false) {
1188      delete unregisteredAttributes.contenteditable;
1189    }
1190    return {
1191      formatType,
1192      type: formatType.name,
1193      tagName,
1194      attributes: registeredAttributes,
1195      unregisteredAttributes
1196    };
1197  }
1198  
1199  /**
1200   * The RichTextData class is used to instantiate a wrapper around rich text
1201   * values, with methods that can be used to transform or manipulate the data.
1202   *
1203   * - Create an empty instance: `new RichTextData()`.
1204   * - Create one from an HTML string: `RichTextData.fromHTMLString(
1205   *   '<em>hello</em>' )`.
1206   * - Create one from a wrapper HTMLElement: `RichTextData.fromHTMLElement(
1207   *   document.querySelector( 'p' ) )`.
1208   * - Create one from plain text: `RichTextData.fromPlainText( '1\n2' )`.
1209   * - Create one from a rich text value: `new RichTextData( { text: '...',
1210   *   formats: [ ... ] } )`.
1211   *
1212   * @todo Add methods to manipulate the data, such as applyFormat, slice etc.
1213   */
1214  class RichTextData {
1215    #value;
1216    static empty() {
1217      return new RichTextData();
1218    }
1219    static fromPlainText(text) {
1220      return new RichTextData(create({
1221        text
1222      }));
1223    }
1224    static fromHTMLString(html) {
1225      return new RichTextData(create({
1226        html
1227      }));
1228    }
1229    static fromHTMLElement(htmlElement, options = {}) {
1230      const {
1231        preserveWhiteSpace = false
1232      } = options;
1233      const element = preserveWhiteSpace ? htmlElement : collapseWhiteSpace(htmlElement);
1234      const richTextData = new RichTextData(create({
1235        element
1236      }));
1237      Object.defineProperty(richTextData, 'originalHTML', {
1238        value: htmlElement.innerHTML
1239      });
1240      return richTextData;
1241    }
1242    constructor(init = createEmptyValue()) {
1243      this.#value = init;
1244    }
1245    toPlainText() {
1246      return getTextContent(this.#value);
1247    }
1248    // We could expose `toHTMLElement` at some point as well, but we'd only use
1249    // it internally.
1250    toHTMLString({
1251      preserveWhiteSpace
1252    } = {}) {
1253      return this.originalHTML || toHTMLString({
1254        value: this.#value,
1255        preserveWhiteSpace
1256      });
1257    }
1258    valueOf() {
1259      return this.toHTMLString();
1260    }
1261    toString() {
1262      return this.toHTMLString();
1263    }
1264    toJSON() {
1265      return this.toHTMLString();
1266    }
1267    get length() {
1268      return this.text.length;
1269    }
1270    get formats() {
1271      return this.#value.formats;
1272    }
1273    get replacements() {
1274      return this.#value.replacements;
1275    }
1276    get text() {
1277      return this.#value.text;
1278    }
1279  }
1280  for (const name of Object.getOwnPropertyNames(String.prototype)) {
1281    if (RichTextData.prototype.hasOwnProperty(name)) {
1282      continue;
1283    }
1284    Object.defineProperty(RichTextData.prototype, name, {
1285      value(...args) {
1286        // Should we convert back to RichTextData?
1287        return this.toHTMLString()[name](...args);
1288      }
1289    });
1290  }
1291  
1292  /**
1293   * Create a RichText value from an `Element` tree (DOM), an HTML string or a
1294   * plain text string, with optionally a `Range` object to set the selection. If
1295   * called without any input, an empty value will be created. The optional
1296   * functions can be used to filter out content.
1297   *
1298   * A value will have the following shape, which you are strongly encouraged not
1299   * to modify without the use of helper functions:
1300   *
1301   * ```js
1302   * {
1303   *   text: string,
1304   *   formats: Array,
1305   *   replacements: Array,
1306   *   ?start: number,
1307   *   ?end: number,
1308   * }
1309   * ```
1310   *
1311   * As you can see, text and formatting are separated. `text` holds the text,
1312   * including any replacement characters for objects and lines. `formats`,
1313   * `objects` and `lines` are all sparse arrays of the same length as `text`. It
1314   * holds information about the formatting at the relevant text indices. Finally
1315   * `start` and `end` state which text indices are selected. They are only
1316   * provided if a `Range` was given.
1317   *
1318   * @param {Object}  [$1]                          Optional named arguments.
1319   * @param {Element} [$1.element]                  Element to create value from.
1320   * @param {string}  [$1.text]                     Text to create value from.
1321   * @param {string}  [$1.html]                     HTML to create value from.
1322   * @param {Range}   [$1.range]                    Range to create value from.
1323   * @param {boolean} [$1.__unstableIsEditableTree]
1324   * @return {RichTextValue} A rich text value.
1325   */
1326  function create({
1327    element,
1328    text,
1329    html,
1330    range,
1331    __unstableIsEditableTree: isEditableTree
1332  } = {}) {
1333    if (html instanceof RichTextData) {
1334      return {
1335        text: html.text,
1336        formats: html.formats,
1337        replacements: html.replacements
1338      };
1339    }
1340    if (typeof text === 'string' && text.length > 0) {
1341      return {
1342        formats: Array(text.length),
1343        replacements: Array(text.length),
1344        text
1345      };
1346    }
1347    if (typeof html === 'string' && html.length > 0) {
1348      // It does not matter which document this is, we're just using it to
1349      // parse.
1350      element = createElement(document, html);
1351    }
1352    if (typeof element !== 'object') {
1353      return createEmptyValue();
1354    }
1355    return createFromElement({
1356      element,
1357      range,
1358      isEditableTree
1359    });
1360  }
1361  
1362  /**
1363   * Helper to accumulate the value's selection start and end from the current
1364   * node and range.
1365   *
1366   * @param {Object} accumulator Object to accumulate into.
1367   * @param {Node}   node        Node to create value with.
1368   * @param {Range}  range       Range to create value with.
1369   * @param {Object} value       Value that is being accumulated.
1370   */
1371  function accumulateSelection(accumulator, node, range, value) {
1372    if (!range) {
1373      return;
1374    }
1375    const {
1376      parentNode
1377    } = node;
1378    const {
1379      startContainer,
1380      startOffset,
1381      endContainer,
1382      endOffset
1383    } = range;
1384    const currentLength = accumulator.text.length;
1385  
1386    // Selection can be extracted from value.
1387    if (value.start !== undefined) {
1388      accumulator.start = currentLength + value.start;
1389      // Range indicates that the current node has selection.
1390    } else if (node === startContainer && node.nodeType === node.TEXT_NODE) {
1391      accumulator.start = currentLength + startOffset;
1392      // Range indicates that the current node is selected.
1393    } else if (parentNode === startContainer && node === startContainer.childNodes[startOffset]) {
1394      accumulator.start = currentLength;
1395      // Range indicates that the selection is after the current node.
1396    } else if (parentNode === startContainer && node === startContainer.childNodes[startOffset - 1]) {
1397      accumulator.start = currentLength + value.text.length;
1398      // Fallback if no child inside handled the selection.
1399    } else if (node === startContainer) {
1400      accumulator.start = currentLength;
1401    }
1402  
1403    // Selection can be extracted from value.
1404    if (value.end !== undefined) {
1405      accumulator.end = currentLength + value.end;
1406      // Range indicates that the current node has selection.
1407    } else if (node === endContainer && node.nodeType === node.TEXT_NODE) {
1408      accumulator.end = currentLength + endOffset;
1409      // Range indicates that the current node is selected.
1410    } else if (parentNode === endContainer && node === endContainer.childNodes[endOffset - 1]) {
1411      accumulator.end = currentLength + value.text.length;
1412      // Range indicates that the selection is before the current node.
1413    } else if (parentNode === endContainer && node === endContainer.childNodes[endOffset]) {
1414      accumulator.end = currentLength;
1415      // Fallback if no child inside handled the selection.
1416    } else if (node === endContainer) {
1417      accumulator.end = currentLength + endOffset;
1418    }
1419  }
1420  
1421  /**
1422   * Adjusts the start and end offsets from a range based on a text filter.
1423   *
1424   * @param {Node}     node   Node of which the text should be filtered.
1425   * @param {Range}    range  The range to filter.
1426   * @param {Function} filter Function to use to filter the text.
1427   *
1428   * @return {Object|void} Object containing range properties.
1429   */
1430  function filterRange(node, range, filter) {
1431    if (!range) {
1432      return;
1433    }
1434    const {
1435      startContainer,
1436      endContainer
1437    } = range;
1438    let {
1439      startOffset,
1440      endOffset
1441    } = range;
1442    if (node === startContainer) {
1443      startOffset = filter(node.nodeValue.slice(0, startOffset)).length;
1444    }
1445    if (node === endContainer) {
1446      endOffset = filter(node.nodeValue.slice(0, endOffset)).length;
1447    }
1448    return {
1449      startContainer,
1450      startOffset,
1451      endContainer,
1452      endOffset
1453    };
1454  }
1455  
1456  /**
1457   * Collapse any whitespace used for HTML formatting to one space character,
1458   * because it will also be displayed as such by the browser.
1459   *
1460   * We need to strip it from the content because we use white-space: pre-wrap for
1461   * displaying editable rich text. Without using white-space: pre-wrap, the
1462   * browser will litter the content with non breaking spaces, among other issues.
1463   * See packages/rich-text/src/component/use-default-style.js.
1464   *
1465   * @see
1466   * https://developer.mozilla.org/en-US/docs/Web/CSS/white-space-collapse#collapsing_of_white_space
1467   *
1468   * @param {HTMLElement} element
1469   * @param {boolean}     isRoot
1470   *
1471   * @return {HTMLElement} New element with collapsed whitespace.
1472   */
1473  function collapseWhiteSpace(element, isRoot = true) {
1474    const clone = element.cloneNode(true);
1475    clone.normalize();
1476    Array.from(clone.childNodes).forEach((node, i, nodes) => {
1477      if (node.nodeType === node.TEXT_NODE) {
1478        let newNodeValue = node.nodeValue;
1479        if (/[\n\t\r\f]/.test(newNodeValue)) {
1480          newNodeValue = newNodeValue.replace(/[\n\t\r\f]+/g, ' ');
1481        }
1482        if (newNodeValue.indexOf('  ') !== -1) {
1483          newNodeValue = newNodeValue.replace(/ {2,}/g, ' ');
1484        }
1485        if (i === 0 && newNodeValue.startsWith(' ')) {
1486          newNodeValue = newNodeValue.slice(1);
1487        } else if (isRoot && i === nodes.length - 1 && newNodeValue.endsWith(' ')) {
1488          newNodeValue = newNodeValue.slice(0, -1);
1489        }
1490        node.nodeValue = newNodeValue;
1491      } else if (node.nodeType === node.ELEMENT_NODE) {
1492        collapseWhiteSpace(node, false);
1493      }
1494    });
1495    return clone;
1496  }
1497  
1498  /**
1499   * We need to normalise line breaks to `\n` so they are consistent across
1500   * platforms and serialised properly. Not removing \r would cause it to
1501   * linger and result in double line breaks when whitespace is preserved.
1502   */
1503  const CARRIAGE_RETURN = '\r';
1504  
1505  /**
1506   * Removes reserved characters used by rich-text (zero width non breaking spaces
1507   * added by `toTree` and object replacement characters).
1508   *
1509   * @param {string} string
1510   */
1511  function removeReservedCharacters(string) {
1512    // with the global flag, note that we should create a new regex each time OR
1513    // reset lastIndex state.
1514    return string.replace(new RegExp(`[$ZWNBSP}$OBJECT_REPLACEMENT_CHARACTER}$CARRIAGE_RETURN}]`, 'gu'), '');
1515  }
1516  
1517  /**
1518   * Creates a Rich Text value from a DOM element and range.
1519   *
1520   * @param {Object}  $1                  Named argements.
1521   * @param {Element} [$1.element]        Element to create value from.
1522   * @param {Range}   [$1.range]          Range to create value from.
1523   * @param {boolean} [$1.isEditableTree]
1524   *
1525   * @return {RichTextValue} A rich text value.
1526   */
1527  function createFromElement({
1528    element,
1529    range,
1530    isEditableTree
1531  }) {
1532    const accumulator = createEmptyValue();
1533    if (!element) {
1534      return accumulator;
1535    }
1536    if (!element.hasChildNodes()) {
1537      accumulateSelection(accumulator, element, range, createEmptyValue());
1538      return accumulator;
1539    }
1540    const length = element.childNodes.length;
1541  
1542    // Optimise for speed.
1543    for (let index = 0; index < length; index++) {
1544      const node = element.childNodes[index];
1545      const tagName = node.nodeName.toLowerCase();
1546      if (node.nodeType === node.TEXT_NODE) {
1547        const text = removeReservedCharacters(node.nodeValue);
1548        range = filterRange(node, range, removeReservedCharacters);
1549        accumulateSelection(accumulator, node, range, {
1550          text
1551        });
1552        // Create a sparse array of the same length as `text`, in which
1553        // formats can be added.
1554        accumulator.formats.length += text.length;
1555        accumulator.replacements.length += text.length;
1556        accumulator.text += text;
1557        continue;
1558      }
1559      if (node.nodeType !== node.ELEMENT_NODE) {
1560        continue;
1561      }
1562      if (isEditableTree &&
1563      // Ignore any line breaks that are not inserted by us.
1564      tagName === 'br' && !node.getAttribute('data-rich-text-line-break')) {
1565        accumulateSelection(accumulator, node, range, createEmptyValue());
1566        continue;
1567      }
1568      if (tagName === 'script') {
1569        const value = {
1570          formats: [,],
1571          replacements: [{
1572            type: tagName,
1573            attributes: {
1574              'data-rich-text-script': node.getAttribute('data-rich-text-script') || encodeURIComponent(node.innerHTML)
1575            }
1576          }],
1577          text: OBJECT_REPLACEMENT_CHARACTER
1578        };
1579        accumulateSelection(accumulator, node, range, value);
1580        mergePair(accumulator, value);
1581        continue;
1582      }
1583      if (tagName === 'br') {
1584        accumulateSelection(accumulator, node, range, createEmptyValue());
1585        mergePair(accumulator, create({
1586          text: '\n'
1587        }));
1588        continue;
1589      }
1590      const format = toFormat({
1591        tagName,
1592        attributes: getAttributes({
1593          element: node
1594        })
1595      });
1596  
1597      // When a format type is declared as not editable, replace it with an
1598      // object replacement character and preserve the inner HTML.
1599      if (format?.formatType?.contentEditable === false) {
1600        delete format.formatType;
1601        accumulateSelection(accumulator, node, range, createEmptyValue());
1602        mergePair(accumulator, {
1603          formats: [,],
1604          replacements: [{
1605            ...format,
1606            innerHTML: node.innerHTML
1607          }],
1608          text: OBJECT_REPLACEMENT_CHARACTER
1609        });
1610        continue;
1611      }
1612      if (format) {
1613        delete format.formatType;
1614      }
1615      const value = createFromElement({
1616        element: node,
1617        range,
1618        isEditableTree
1619      });
1620      accumulateSelection(accumulator, node, range, value);
1621  
1622      // Ignore any placeholders, but keep their content since the browser
1623      // might insert text inside them when the editable element is flex.
1624      if (!format || node.getAttribute('data-rich-text-placeholder')) {
1625        mergePair(accumulator, value);
1626      } else if (value.text.length === 0) {
1627        if (format.attributes) {
1628          mergePair(accumulator, {
1629            formats: [,],
1630            replacements: [format],
1631            text: OBJECT_REPLACEMENT_CHARACTER
1632          });
1633        }
1634      } else {
1635        // Indices should share a reference to the same formats array.
1636        // Only create a new reference if `formats` changes.
1637        function mergeFormats(formats) {
1638          if (mergeFormats.formats === formats) {
1639            return mergeFormats.newFormats;
1640          }
1641          const newFormats = formats ? [format, ...formats] : [format];
1642          mergeFormats.formats = formats;
1643          mergeFormats.newFormats = newFormats;
1644          return newFormats;
1645        }
1646  
1647        // Since the formats parameter can be `undefined`, preset
1648        // `mergeFormats` with a new reference.
1649        mergeFormats.newFormats = [format];
1650        mergePair(accumulator, {
1651          ...value,
1652          formats: Array.from(value.formats, mergeFormats)
1653        });
1654      }
1655    }
1656    return accumulator;
1657  }
1658  
1659  /**
1660   * Gets the attributes of an element in object shape.
1661   *
1662   * @param {Object}  $1         Named argements.
1663   * @param {Element} $1.element Element to get attributes from.
1664   *
1665   * @return {Object|void} Attribute object or `undefined` if the element has no
1666   *                       attributes.
1667   */
1668  function getAttributes({
1669    element
1670  }) {
1671    if (!element.hasAttributes()) {
1672      return;
1673    }
1674    const length = element.attributes.length;
1675    let accumulator;
1676  
1677    // Optimise for speed.
1678    for (let i = 0; i < length; i++) {
1679      const {
1680        name,
1681        value
1682      } = element.attributes[i];
1683      if (name.indexOf('data-rich-text-') === 0) {
1684        continue;
1685      }
1686      const safeName = /^on/i.test(name) ? 'data-disable-rich-text-' + name : name;
1687      accumulator = accumulator || {};
1688      accumulator[safeName] = value;
1689    }
1690    return accumulator;
1691  }
1692  
1693  ;// CONCATENATED MODULE: ./node_modules/@wordpress/rich-text/build-module/concat.js
1694  /**
1695   * Internal dependencies
1696   */
1697  
1698  
1699  
1700  
1701  /** @typedef {import('./types').RichTextValue} RichTextValue */
1702  
1703  /**
1704   * Concats a pair of rich text values. Not that this mutates `a` and does NOT
1705   * normalise formats!
1706   *
1707   * @param {Object} a Value to mutate.
1708   * @param {Object} b Value to add read from.
1709   *
1710   * @return {Object} `a`, mutated.
1711   */
1712  function mergePair(a, b) {
1713    a.formats = a.formats.concat(b.formats);
1714    a.replacements = a.replacements.concat(b.replacements);
1715    a.text += b.text;
1716    return a;
1717  }
1718  
1719  /**
1720   * Combine all Rich Text values into one. This is similar to
1721   * `String.prototype.concat`.
1722   *
1723   * @param {...RichTextValue} values Objects to combine.
1724   *
1725   * @return {RichTextValue} A new value combining all given records.
1726   */
1727  function concat(...values) {
1728    return normaliseFormats(values.reduce(mergePair, create()));
1729  }
1730  
1731  ;// CONCATENATED MODULE: ./node_modules/@wordpress/rich-text/build-module/get-active-format.js
1732  /**
1733   * Internal dependencies
1734   */
1735  
1736  
1737  /** @typedef {import('./types').RichTextValue} RichTextValue */
1738  /** @typedef {import('./types').RichTextFormat} RichTextFormat */
1739  
1740  /**
1741   * Gets the format object by type at the start of the selection. This can be
1742   * used to get e.g. the URL of a link format at the current selection, but also
1743   * to check if a format is active at the selection. Returns undefined if there
1744   * is no format at the selection.
1745   *
1746   * @param {RichTextValue} value      Value to inspect.
1747   * @param {string}        formatType Format type to look for.
1748   *
1749   * @return {RichTextFormat|undefined} Active format object of the specified
1750   *                                    type, or undefined.
1751   */
1752  function getActiveFormat(value, formatType) {
1753    return getActiveFormats(value).find(({
1754      type
1755    }) => type === formatType);
1756  }
1757  
1758  ;// CONCATENATED MODULE: ./node_modules/@wordpress/rich-text/build-module/get-active-object.js
1759  /**
1760   * Internal dependencies
1761   */
1762  
1763  
1764  
1765  /** @typedef {import('./types').RichTextValue} RichTextValue */
1766  /** @typedef {import('./types').RichTextFormat} RichTextFormat */
1767  
1768  /**
1769   * Gets the active object, if there is any.
1770   *
1771   * @param {RichTextValue} value Value to inspect.
1772   *
1773   * @return {RichTextFormat|void} Active object, or undefined.
1774   */
1775  function getActiveObject({
1776    start,
1777    end,
1778    replacements,
1779    text
1780  }) {
1781    if (start + 1 !== end || text[start] !== OBJECT_REPLACEMENT_CHARACTER) {
1782      return;
1783    }
1784    return replacements[start];
1785  }
1786  
1787  ;// CONCATENATED MODULE: ./node_modules/@wordpress/rich-text/build-module/is-collapsed.js
1788  /**
1789   * Internal dependencies
1790   */
1791  
1792  /**
1793   * Check if the selection of a Rich Text value is collapsed or not. Collapsed
1794   * means that no characters are selected, but there is a caret present. If there
1795   * is no selection, `undefined` will be returned. This is similar to
1796   * `window.getSelection().isCollapsed()`.
1797   *
1798   * @param props       The rich text value to check.
1799   * @param props.start
1800   * @param props.end
1801   * @return True if the selection is collapsed, false if not, undefined if there is no selection.
1802   */
1803  function isCollapsed({
1804    start,
1805    end
1806  }) {
1807    if (start === undefined || end === undefined) {
1808      return;
1809    }
1810    return start === end;
1811  }
1812  
1813  ;// CONCATENATED MODULE: ./node_modules/@wordpress/rich-text/build-module/is-empty.js
1814  /** @typedef {import('./types').RichTextValue} RichTextValue */
1815  
1816  /**
1817   * Check if a Rich Text value is Empty, meaning it contains no text or any
1818   * objects (such as images).
1819   *
1820   * @param {RichTextValue} value Value to use.
1821   *
1822   * @return {boolean} True if the value is empty, false if not.
1823   */
1824  function isEmpty({
1825    text
1826  }) {
1827    return text.length === 0;
1828  }
1829  
1830  ;// CONCATENATED MODULE: ./node_modules/@wordpress/rich-text/build-module/join.js
1831  /**
1832   * Internal dependencies
1833   */
1834  
1835  
1836  
1837  
1838  /** @typedef {import('./types').RichTextValue} RichTextValue */
1839  
1840  /**
1841   * Combine an array of Rich Text values into one, optionally separated by
1842   * `separator`, which can be a Rich Text value, HTML string, or plain text
1843   * string. This is similar to `Array.prototype.join`.
1844   *
1845   * @param {Array<RichTextValue>} values      An array of values to join.
1846   * @param {string|RichTextValue} [separator] Separator string or value.
1847   *
1848   * @return {RichTextValue} A new combined value.
1849   */
1850  function join(values, separator = '') {
1851    if (typeof separator === 'string') {
1852      separator = create({
1853        text: separator
1854      });
1855    }
1856    return normaliseFormats(values.reduce((accumlator, {
1857      formats,
1858      replacements,
1859      text
1860    }) => ({
1861      formats: accumlator.formats.concat(separator.formats, formats),
1862      replacements: accumlator.replacements.concat(separator.replacements, replacements),
1863      text: accumlator.text + separator.text + text
1864    })));
1865  }
1866  
1867  ;// CONCATENATED MODULE: ./node_modules/@wordpress/rich-text/build-module/register-format-type.js
1868  /**
1869   * WordPress dependencies
1870   */
1871  
1872  /**
1873   * Internal dependencies
1874   */
1875  
1876  /**
1877   * @typedef {Object} WPFormat
1878   *
1879   * @property {string}        name        A string identifying the format. Must be
1880   *                                       unique across all registered formats.
1881   * @property {string}        tagName     The HTML tag this format will wrap the
1882   *                                       selection with.
1883   * @property {boolean}       interactive Whether format makes content interactive or not.
1884   * @property {string | null} [className] A class to match the format.
1885   * @property {string}        title       Name of the format.
1886   * @property {Function}      edit        Should return a component for the user to
1887   *                                       interact with the new registered format.
1888   */
1889  
1890  /**
1891   * Registers a new format provided a unique name and an object defining its
1892   * behavior.
1893   *
1894   * @param {string}   name     Format name.
1895   * @param {WPFormat} settings Format settings.
1896   *
1897   * @return {WPFormat|undefined} The format, if it has been successfully
1898   *                              registered; otherwise `undefined`.
1899   */
1900  function registerFormatType(name, settings) {
1901    settings = {
1902      name,
1903      ...settings
1904    };
1905    if (typeof settings.name !== 'string') {
1906      window.console.error('Format names must be strings.');
1907      return;
1908    }
1909    if (!/^[a-z][a-z0-9-]*\/[a-z][a-z0-9-]*$/.test(settings.name)) {
1910      window.console.error('Format names must contain a namespace prefix, include only lowercase alphanumeric characters or dashes, and start with a letter. Example: my-plugin/my-custom-format');
1911      return;
1912    }
1913    if ((0,external_wp_data_namespaceObject.select)(store).getFormatType(settings.name)) {
1914      window.console.error('Format "' + settings.name + '" is already registered.');
1915      return;
1916    }
1917    if (typeof settings.tagName !== 'string' || settings.tagName === '') {
1918      window.console.error('Format tag names must be a string.');
1919      return;
1920    }
1921    if ((typeof settings.className !== 'string' || settings.className === '') && settings.className !== null) {
1922      window.console.error('Format class names must be a string, or null to handle bare elements.');
1923      return;
1924    }
1925    if (!/^[_a-zA-Z]+[a-zA-Z0-9_-]*$/.test(settings.className)) {
1926      window.console.error('A class name must begin with a letter, followed by any number of hyphens, underscores, letters, or numbers.');
1927      return;
1928    }
1929    if (settings.className === null) {
1930      const formatTypeForBareElement = (0,external_wp_data_namespaceObject.select)(store).getFormatTypeForBareElement(settings.tagName);
1931      if (formatTypeForBareElement && formatTypeForBareElement.name !== 'core/unknown') {
1932        window.console.error(`Format "$formatTypeForBareElement.name}" is already registered to handle bare tag name "$settings.tagName}".`);
1933        return;
1934      }
1935    } else {
1936      const formatTypeForClassName = (0,external_wp_data_namespaceObject.select)(store).getFormatTypeForClassName(settings.className);
1937      if (formatTypeForClassName) {
1938        window.console.error(`Format "$formatTypeForClassName.name}" is already registered to handle class name "$settings.className}".`);
1939        return;
1940      }
1941    }
1942    if (!('title' in settings) || settings.title === '') {
1943      window.console.error('The format "' + settings.name + '" must have a title.');
1944      return;
1945    }
1946    if ('keywords' in settings && settings.keywords.length > 3) {
1947      window.console.error('The format "' + settings.name + '" can have a maximum of 3 keywords.');
1948      return;
1949    }
1950    if (typeof settings.title !== 'string') {
1951      window.console.error('Format titles must be strings.');
1952      return;
1953    }
1954    (0,external_wp_data_namespaceObject.dispatch)(store).addFormatTypes(settings);
1955    return settings;
1956  }
1957  
1958  ;// CONCATENATED MODULE: ./node_modules/@wordpress/rich-text/build-module/remove-format.js
1959  /**
1960   * Internal dependencies
1961   */
1962  
1963  
1964  
1965  /** @typedef {import('./types').RichTextValue} RichTextValue */
1966  
1967  /**
1968   * Remove any format object from a Rich Text value by type from the given
1969   * `startIndex` to the given `endIndex`. Indices are retrieved from the
1970   * selection if none are provided.
1971   *
1972   * @param {RichTextValue} value        Value to modify.
1973   * @param {string}        formatType   Format type to remove.
1974   * @param {number}        [startIndex] Start index.
1975   * @param {number}        [endIndex]   End index.
1976   *
1977   * @return {RichTextValue} A new value with the format applied.
1978   */
1979  function removeFormat(value, formatType, startIndex = value.start, endIndex = value.end) {
1980    const {
1981      formats,
1982      activeFormats
1983    } = value;
1984    const newFormats = formats.slice();
1985  
1986    // If the selection is collapsed, expand start and end to the edges of the
1987    // format.
1988    if (startIndex === endIndex) {
1989      const format = newFormats[startIndex]?.find(({
1990        type
1991      }) => type === formatType);
1992      if (format) {
1993        while (newFormats[startIndex]?.find(newFormat => newFormat === format)) {
1994          filterFormats(newFormats, startIndex, formatType);
1995          startIndex--;
1996        }
1997        endIndex++;
1998        while (newFormats[endIndex]?.find(newFormat => newFormat === format)) {
1999          filterFormats(newFormats, endIndex, formatType);
2000          endIndex++;
2001        }
2002      }
2003    } else {
2004      for (let i = startIndex; i < endIndex; i++) {
2005        if (newFormats[i]) {
2006          filterFormats(newFormats, i, formatType);
2007        }
2008      }
2009    }
2010    return normaliseFormats({
2011      ...value,
2012      formats: newFormats,
2013      activeFormats: activeFormats?.filter(({
2014        type
2015      }) => type !== formatType) || []
2016    });
2017  }
2018  function filterFormats(formats, index, formatType) {
2019    const newFormats = formats[index].filter(({
2020      type
2021    }) => type !== formatType);
2022    if (newFormats.length) {
2023      formats[index] = newFormats;
2024    } else {
2025      delete formats[index];
2026    }
2027  }
2028  
2029  ;// CONCATENATED MODULE: ./node_modules/@wordpress/rich-text/build-module/insert.js
2030  /**
2031   * Internal dependencies
2032   */
2033  
2034  
2035  
2036  
2037  /** @typedef {import('./types').RichTextValue} RichTextValue */
2038  
2039  /**
2040   * Insert a Rich Text value, an HTML string, or a plain text string, into a
2041   * Rich Text value at the given `startIndex`. Any content between `startIndex`
2042   * and `endIndex` will be removed. Indices are retrieved from the selection if
2043   * none are provided.
2044   *
2045   * @param {RichTextValue}        value         Value to modify.
2046   * @param {RichTextValue|string} valueToInsert Value to insert.
2047   * @param {number}               [startIndex]  Start index.
2048   * @param {number}               [endIndex]    End index.
2049   *
2050   * @return {RichTextValue} A new value with the value inserted.
2051   */
2052  function insert(value, valueToInsert, startIndex = value.start, endIndex = value.end) {
2053    const {
2054      formats,
2055      replacements,
2056      text
2057    } = value;
2058    if (typeof valueToInsert === 'string') {
2059      valueToInsert = create({
2060        text: valueToInsert
2061      });
2062    }
2063    const index = startIndex + valueToInsert.text.length;
2064    return normaliseFormats({
2065      formats: formats.slice(0, startIndex).concat(valueToInsert.formats, formats.slice(endIndex)),
2066      replacements: replacements.slice(0, startIndex).concat(valueToInsert.replacements, replacements.slice(endIndex)),
2067      text: text.slice(0, startIndex) + valueToInsert.text + text.slice(endIndex),
2068      start: index,
2069      end: index
2070    });
2071  }
2072  
2073  ;// CONCATENATED MODULE: ./node_modules/@wordpress/rich-text/build-module/remove.js
2074  /**
2075   * Internal dependencies
2076   */
2077  
2078  
2079  
2080  
2081  /** @typedef {import('./types').RichTextValue} RichTextValue */
2082  
2083  /**
2084   * Remove content from a Rich Text value between the given `startIndex` and
2085   * `endIndex`. Indices are retrieved from the selection if none are provided.
2086   *
2087   * @param {RichTextValue} value        Value to modify.
2088   * @param {number}        [startIndex] Start index.
2089   * @param {number}        [endIndex]   End index.
2090   *
2091   * @return {RichTextValue} A new value with the content removed.
2092   */
2093  function remove_remove(value, startIndex, endIndex) {
2094    return insert(value, create(), startIndex, endIndex);
2095  }
2096  
2097  ;// CONCATENATED MODULE: ./node_modules/@wordpress/rich-text/build-module/replace.js
2098  /**
2099   * Internal dependencies
2100   */
2101  
2102  
2103  
2104  /** @typedef {import('./types').RichTextValue} RichTextValue */
2105  
2106  /**
2107   * Search a Rich Text value and replace the match(es) with `replacement`. This
2108   * is similar to `String.prototype.replace`.
2109   *
2110   * @param {RichTextValue}   value       The value to modify.
2111   * @param {RegExp|string}   pattern     A RegExp object or literal. Can also be
2112   *                                      a string. It is treated as a verbatim
2113   *                                      string and is not interpreted as a
2114   *                                      regular expression. Only the first
2115   *                                      occurrence will be replaced.
2116   * @param {Function|string} replacement The match or matches are replaced with
2117   *                                      the specified or the value returned by
2118   *                                      the specified function.
2119   *
2120   * @return {RichTextValue} A new value with replacements applied.
2121   */
2122  function replace_replace({
2123    formats,
2124    replacements,
2125    text,
2126    start,
2127    end
2128  }, pattern, replacement) {
2129    text = text.replace(pattern, (match, ...rest) => {
2130      const offset = rest[rest.length - 2];
2131      let newText = replacement;
2132      let newFormats;
2133      let newReplacements;
2134      if (typeof newText === 'function') {
2135        newText = replacement(match, ...rest);
2136      }
2137      if (typeof newText === 'object') {
2138        newFormats = newText.formats;
2139        newReplacements = newText.replacements;
2140        newText = newText.text;
2141      } else {
2142        newFormats = Array(newText.length);
2143        newReplacements = Array(newText.length);
2144        if (formats[offset]) {
2145          newFormats = newFormats.fill(formats[offset]);
2146        }
2147      }
2148      formats = formats.slice(0, offset).concat(newFormats, formats.slice(offset + match.length));
2149      replacements = replacements.slice(0, offset).concat(newReplacements, replacements.slice(offset + match.length));
2150      if (start) {
2151        start = end = offset + newText.length;
2152      }
2153      return newText;
2154    });
2155    return normaliseFormats({
2156      formats,
2157      replacements,
2158      text,
2159      start,
2160      end
2161    });
2162  }
2163  
2164  ;// CONCATENATED MODULE: ./node_modules/@wordpress/rich-text/build-module/insert-object.js
2165  /**
2166   * Internal dependencies
2167   */
2168  
2169  
2170  
2171  
2172  /** @typedef {import('./types').RichTextValue} RichTextValue */
2173  /** @typedef {import('./types').RichTextFormat} RichTextFormat */
2174  
2175  /**
2176   * Insert a format as an object into a Rich Text value at the given
2177   * `startIndex`. Any content between `startIndex` and `endIndex` will be
2178   * removed. Indices are retrieved from the selection if none are provided.
2179   *
2180   * @param {RichTextValue}  value          Value to modify.
2181   * @param {RichTextFormat} formatToInsert Format to insert as object.
2182   * @param {number}         [startIndex]   Start index.
2183   * @param {number}         [endIndex]     End index.
2184   *
2185   * @return {RichTextValue} A new value with the object inserted.
2186   */
2187  function insertObject(value, formatToInsert, startIndex, endIndex) {
2188    const valueToInsert = {
2189      formats: [,],
2190      replacements: [formatToInsert],
2191      text: OBJECT_REPLACEMENT_CHARACTER
2192    };
2193    return insert(value, valueToInsert, startIndex, endIndex);
2194  }
2195  
2196  ;// CONCATENATED MODULE: ./node_modules/@wordpress/rich-text/build-module/slice.js
2197  /** @typedef {import('./types').RichTextValue} RichTextValue */
2198  
2199  /**
2200   * Slice a Rich Text value from `startIndex` to `endIndex`. Indices are
2201   * retrieved from the selection if none are provided. This is similar to
2202   * `String.prototype.slice`.
2203   *
2204   * @param {RichTextValue} value        Value to modify.
2205   * @param {number}        [startIndex] Start index.
2206   * @param {number}        [endIndex]   End index.
2207   *
2208   * @return {RichTextValue} A new extracted value.
2209   */
2210  function slice(value, startIndex = value.start, endIndex = value.end) {
2211    const {
2212      formats,
2213      replacements,
2214      text
2215    } = value;
2216    if (startIndex === undefined || endIndex === undefined) {
2217      return {
2218        ...value
2219      };
2220    }
2221    return {
2222      formats: formats.slice(startIndex, endIndex),
2223      replacements: replacements.slice(startIndex, endIndex),
2224      text: text.slice(startIndex, endIndex)
2225    };
2226  }
2227  
2228  ;// CONCATENATED MODULE: ./node_modules/@wordpress/rich-text/build-module/split.js
2229  /**
2230   * Internal dependencies
2231   */
2232  
2233  /** @typedef {import('./types').RichTextValue} RichTextValue */
2234  
2235  /**
2236   * Split a Rich Text value in two at the given `startIndex` and `endIndex`, or
2237   * split at the given separator. This is similar to `String.prototype.split`.
2238   * Indices are retrieved from the selection if none are provided.
2239   *
2240   * @param {RichTextValue} value
2241   * @param {number|string} [string] Start index, or string at which to split.
2242   *
2243   * @return {Array<RichTextValue>|undefined} An array of new values.
2244   */
2245  function split({
2246    formats,
2247    replacements,
2248    text,
2249    start,
2250    end
2251  }, string) {
2252    if (typeof string !== 'string') {
2253      return splitAtSelection(...arguments);
2254    }
2255    let nextStart = 0;
2256    return text.split(string).map(substring => {
2257      const startIndex = nextStart;
2258      const value = {
2259        formats: formats.slice(startIndex, startIndex + substring.length),
2260        replacements: replacements.slice(startIndex, startIndex + substring.length),
2261        text: substring
2262      };
2263      nextStart += string.length + substring.length;
2264      if (start !== undefined && end !== undefined) {
2265        if (start >= startIndex && start < nextStart) {
2266          value.start = start - startIndex;
2267        } else if (start < startIndex && end > startIndex) {
2268          value.start = 0;
2269        }
2270        if (end >= startIndex && end < nextStart) {
2271          value.end = end - startIndex;
2272        } else if (start < nextStart && end > nextStart) {
2273          value.end = substring.length;
2274        }
2275      }
2276      return value;
2277    });
2278  }
2279  function splitAtSelection({
2280    formats,
2281    replacements,
2282    text,
2283    start,
2284    end
2285  }, startIndex = start, endIndex = end) {
2286    if (start === undefined || end === undefined) {
2287      return;
2288    }
2289    const before = {
2290      formats: formats.slice(0, startIndex),
2291      replacements: replacements.slice(0, startIndex),
2292      text: text.slice(0, startIndex)
2293    };
2294    const after = {
2295      formats: formats.slice(endIndex),
2296      replacements: replacements.slice(endIndex),
2297      text: text.slice(endIndex),
2298      start: 0,
2299      end: 0
2300    };
2301    return [before, after];
2302  }
2303  
2304  ;// CONCATENATED MODULE: ./node_modules/@wordpress/rich-text/build-module/is-range-equal.js
2305  /**
2306   * Returns true if two ranges are equal, or false otherwise. Ranges are
2307   * considered equal if their start and end occur in the same container and
2308   * offset.
2309   *
2310   * @param {Range|null} a First range object to test.
2311   * @param {Range|null} b First range object to test.
2312   *
2313   * @return {boolean} Whether the two ranges are equal.
2314   */
2315  function isRangeEqual(a, b) {
2316    return a === b || a && b && a.startContainer === b.startContainer && a.startOffset === b.startOffset && a.endContainer === b.endContainer && a.endOffset === b.endOffset;
2317  }
2318  
2319  ;// CONCATENATED MODULE: ./node_modules/@wordpress/rich-text/build-module/to-dom.js
2320  /**
2321   * Internal dependencies
2322   */
2323  
2324  
2325  
2326  
2327  
2328  /** @typedef {import('./types').RichTextValue} RichTextValue */
2329  
2330  /**
2331   * Creates a path as an array of indices from the given root node to the given
2332   * node.
2333   *
2334   * @param {Node}        node     Node to find the path of.
2335   * @param {HTMLElement} rootNode Root node to find the path from.
2336   * @param {Array}       path     Initial path to build on.
2337   *
2338   * @return {Array} The path from the root node to the node.
2339   */
2340  function createPathToNode(node, rootNode, path) {
2341    const parentNode = node.parentNode;
2342    let i = 0;
2343    while (node = node.previousSibling) {
2344      i++;
2345    }
2346    path = [i, ...path];
2347    if (parentNode !== rootNode) {
2348      path = createPathToNode(parentNode, rootNode, path);
2349    }
2350    return path;
2351  }
2352  
2353  /**
2354   * Gets a node given a path (array of indices) from the given node.
2355   *
2356   * @param {HTMLElement} node Root node to find the wanted node in.
2357   * @param {Array}       path Path (indices) to the wanted node.
2358   *
2359   * @return {Object} Object with the found node and the remaining offset (if any).
2360   */
2361  function getNodeByPath(node, path) {
2362    path = [...path];
2363    while (node && path.length > 1) {
2364      node = node.childNodes[path.shift()];
2365    }
2366    return {
2367      node,
2368      offset: path[0]
2369    };
2370  }
2371  function to_dom_append(element, child) {
2372    if (child.html !== undefined) {
2373      return element.innerHTML += child.html;
2374    }
2375    if (typeof child === 'string') {
2376      child = element.ownerDocument.createTextNode(child);
2377    }
2378    const {
2379      type,
2380      attributes
2381    } = child;
2382    if (type) {
2383      child = element.ownerDocument.createElement(type);
2384      for (const key in attributes) {
2385        child.setAttribute(key, attributes[key]);
2386      }
2387    }
2388    return element.appendChild(child);
2389  }
2390  function to_dom_appendText(node, text) {
2391    node.appendData(text);
2392  }
2393  function to_dom_getLastChild({
2394    lastChild
2395  }) {
2396    return lastChild;
2397  }
2398  function to_dom_getParent({
2399    parentNode
2400  }) {
2401    return parentNode;
2402  }
2403  function to_dom_isText(node) {
2404    return node.nodeType === node.TEXT_NODE;
2405  }
2406  function to_dom_getText({
2407    nodeValue
2408  }) {
2409    return nodeValue;
2410  }
2411  function to_dom_remove(node) {
2412    return node.parentNode.removeChild(node);
2413  }
2414  function toDom({
2415    value,
2416    prepareEditableTree,
2417    isEditableTree = true,
2418    placeholder,
2419    doc = document
2420  }) {
2421    let startPath = [];
2422    let endPath = [];
2423    if (prepareEditableTree) {
2424      value = {
2425        ...value,
2426        formats: prepareEditableTree(value)
2427      };
2428    }
2429  
2430    /**
2431     * Returns a new instance of a DOM tree upon which RichText operations can be
2432     * applied.
2433     *
2434     * Note: The current implementation will return a shared reference, reset on
2435     * each call to `createEmpty`. Therefore, you should not hold a reference to
2436     * the value to operate upon asynchronously, as it may have unexpected results.
2437     *
2438     * @return {Object} RichText tree.
2439     */
2440    const createEmpty = () => createElement(doc, '');
2441    const tree = toTree({
2442      value,
2443      createEmpty,
2444      append: to_dom_append,
2445      getLastChild: to_dom_getLastChild,
2446      getParent: to_dom_getParent,
2447      isText: to_dom_isText,
2448      getText: to_dom_getText,
2449      remove: to_dom_remove,
2450      appendText: to_dom_appendText,
2451      onStartIndex(body, pointer) {
2452        startPath = createPathToNode(pointer, body, [pointer.nodeValue.length]);
2453      },
2454      onEndIndex(body, pointer) {
2455        endPath = createPathToNode(pointer, body, [pointer.nodeValue.length]);
2456      },
2457      isEditableTree,
2458      placeholder
2459    });
2460    return {
2461      body: tree,
2462      selection: {
2463        startPath,
2464        endPath
2465      }
2466    };
2467  }
2468  
2469  /**
2470   * Create an `Element` tree from a Rich Text value and applies the difference to
2471   * the `Element` tree contained by `current`.
2472   *
2473   * @param {Object}        $1                       Named arguments.
2474   * @param {RichTextValue} $1.value                 Value to apply.
2475   * @param {HTMLElement}   $1.current               The live root node to apply the element tree to.
2476   * @param {Function}      [$1.prepareEditableTree] Function to filter editorable formats.
2477   * @param {boolean}       [$1.__unstableDomOnly]   Only apply elements, no selection.
2478   * @param {string}        [$1.placeholder]         Placeholder text.
2479   */
2480  function apply({
2481    value,
2482    current,
2483    prepareEditableTree,
2484    __unstableDomOnly,
2485    placeholder
2486  }) {
2487    // Construct a new element tree in memory.
2488    const {
2489      body,
2490      selection
2491    } = toDom({
2492      value,
2493      prepareEditableTree,
2494      placeholder,
2495      doc: current.ownerDocument
2496    });
2497    applyValue(body, current);
2498    if (value.start !== undefined && !__unstableDomOnly) {
2499      applySelection(selection, current);
2500    }
2501  }
2502  function applyValue(future, current) {
2503    let i = 0;
2504    let futureChild;
2505    while (futureChild = future.firstChild) {
2506      const currentChild = current.childNodes[i];
2507      if (!currentChild) {
2508        current.appendChild(futureChild);
2509      } else if (!currentChild.isEqualNode(futureChild)) {
2510        if (currentChild.nodeName !== futureChild.nodeName || currentChild.nodeType === currentChild.TEXT_NODE && currentChild.data !== futureChild.data) {
2511          current.replaceChild(futureChild, currentChild);
2512        } else {
2513          const currentAttributes = currentChild.attributes;
2514          const futureAttributes = futureChild.attributes;
2515          if (currentAttributes) {
2516            let ii = currentAttributes.length;
2517  
2518            // Reverse loop because `removeAttribute` on `currentChild`
2519            // changes `currentAttributes`.
2520            while (ii--) {
2521              const {
2522                name
2523              } = currentAttributes[ii];
2524              if (!futureChild.getAttribute(name)) {
2525                currentChild.removeAttribute(name);
2526              }
2527            }
2528          }
2529          if (futureAttributes) {
2530            for (let ii = 0; ii < futureAttributes.length; ii++) {
2531              const {
2532                name,
2533                value
2534              } = futureAttributes[ii];
2535              if (currentChild.getAttribute(name) !== value) {
2536                currentChild.setAttribute(name, value);
2537              }
2538            }
2539          }
2540          applyValue(futureChild, currentChild);
2541          future.removeChild(futureChild);
2542        }
2543      } else {
2544        future.removeChild(futureChild);
2545      }
2546      i++;
2547    }
2548    while (current.childNodes[i]) {
2549      current.removeChild(current.childNodes[i]);
2550    }
2551  }
2552  function applySelection({
2553    startPath,
2554    endPath
2555  }, current) {
2556    const {
2557      node: startContainer,
2558      offset: startOffset
2559    } = getNodeByPath(current, startPath);
2560    const {
2561      node: endContainer,
2562      offset: endOffset
2563    } = getNodeByPath(current, endPath);
2564    const {
2565      ownerDocument
2566    } = current;
2567    const {
2568      defaultView
2569    } = ownerDocument;
2570    const selection = defaultView.getSelection();
2571    const range = ownerDocument.createRange();
2572    range.setStart(startContainer, startOffset);
2573    range.setEnd(endContainer, endOffset);
2574    const {
2575      activeElement
2576    } = ownerDocument;
2577    if (selection.rangeCount > 0) {
2578      // If the to be added range and the live range are the same, there's no
2579      // need to remove the live range and add the equivalent range.
2580      if (isRangeEqual(range, selection.getRangeAt(0))) {
2581        return;
2582      }
2583      selection.removeAllRanges();
2584    }
2585    selection.addRange(range);
2586  
2587    // This function is not intended to cause a shift in focus. Since the above
2588    // selection manipulations may shift focus, ensure that focus is restored to
2589    // its previous state.
2590    if (activeElement !== ownerDocument.activeElement) {
2591      // The `instanceof` checks protect against edge cases where the focused
2592      // element is not of the interface HTMLElement (does not have a `focus`
2593      // or `blur` property).
2594      //
2595      // See: https://github.com/Microsoft/TypeScript/issues/5901#issuecomment-431649653
2596      if (activeElement instanceof defaultView.HTMLElement) {
2597        activeElement.focus();
2598      }
2599    }
2600  }
2601  
2602  ;// CONCATENATED MODULE: external ["wp","a11y"]
2603  const external_wp_a11y_namespaceObject = window["wp"]["a11y"];
2604  ;// CONCATENATED MODULE: external ["wp","i18n"]
2605  const external_wp_i18n_namespaceObject = window["wp"]["i18n"];
2606  ;// CONCATENATED MODULE: ./node_modules/@wordpress/rich-text/build-module/toggle-format.js
2607  /**
2608   * WordPress dependencies
2609   */
2610  
2611  
2612  
2613  
2614  /**
2615   * Internal dependencies
2616   */
2617  
2618  
2619  
2620  
2621  
2622  /** @typedef {import('./types').RichTextValue} RichTextValue */
2623  /** @typedef {import('./types').RichTextFormat} RichTextFormat */
2624  
2625  /**
2626   * Toggles a format object to a Rich Text value at the current selection.
2627   *
2628   * @param {RichTextValue}  value  Value to modify.
2629   * @param {RichTextFormat} format Format to apply or remove.
2630   *
2631   * @return {RichTextValue} A new value with the format applied or removed.
2632   */
2633  function toggleFormat(value, format) {
2634    if (getActiveFormat(value, format.type)) {
2635      // For screen readers, will announce if formatting control is disabled.
2636      if (format.title) {
2637        // translators: %s: title of the formatting control
2638        (0,external_wp_a11y_namespaceObject.speak)((0,external_wp_i18n_namespaceObject.sprintf)((0,external_wp_i18n_namespaceObject.__)('%s removed.'), format.title), 'assertive');
2639      }
2640      return removeFormat(value, format.type);
2641    }
2642    // For screen readers, will announce if formatting control is enabled.
2643    if (format.title) {
2644      // translators: %s: title of the formatting control
2645      (0,external_wp_a11y_namespaceObject.speak)((0,external_wp_i18n_namespaceObject.sprintf)((0,external_wp_i18n_namespaceObject.__)('%s applied.'), format.title), 'assertive');
2646    }
2647    return applyFormat(value, format);
2648  }
2649  
2650  ;// CONCATENATED MODULE: ./node_modules/@wordpress/rich-text/build-module/unregister-format-type.js
2651  /**
2652   * WordPress dependencies
2653   */
2654  
2655  
2656  /**
2657   * Internal dependencies
2658   */
2659  
2660  
2661  /** @typedef {import('./register-format-type').WPFormat} WPFormat */
2662  
2663  /**
2664   * Unregisters a format.
2665   *
2666   * @param {string} name Format name.
2667   *
2668   * @return {WPFormat|undefined} The previous format value, if it has
2669   *                                        been successfully unregistered;
2670   *                                        otherwise `undefined`.
2671   */
2672  function unregisterFormatType(name) {
2673    const oldFormat = (0,external_wp_data_namespaceObject.select)(store).getFormatType(name);
2674    if (!oldFormat) {
2675      window.console.error(`Format $name} is not registered.`);
2676      return;
2677    }
2678    (0,external_wp_data_namespaceObject.dispatch)(store).removeFormatTypes(name);
2679    return oldFormat;
2680  }
2681  
2682  ;// CONCATENATED MODULE: external ["wp","element"]
2683  const external_wp_element_namespaceObject = window["wp"]["element"];
2684  ;// CONCATENATED MODULE: external ["wp","deprecated"]
2685  const external_wp_deprecated_namespaceObject = window["wp"]["deprecated"];
2686  var external_wp_deprecated_default = /*#__PURE__*/__webpack_require__.n(external_wp_deprecated_namespaceObject);
2687  ;// CONCATENATED MODULE: ./node_modules/@wordpress/rich-text/build-module/component/use-anchor-ref.js
2688  /**
2689   * WordPress dependencies
2690   */
2691  
2692  
2693  
2694  /**
2695   * Internal dependencies
2696   */
2697  
2698  
2699  /**
2700   * @template T
2701   * @typedef {import('@wordpress/element').RefObject<T>} RefObject<T>
2702   */
2703  /** @typedef {import('../register-format-type').WPFormat} WPFormat */
2704  /** @typedef {import('../types').RichTextValue} RichTextValue */
2705  
2706  /**
2707   * This hook, to be used in a format type's Edit component, returns the active
2708   * element that is formatted, or the selection range if no format is active.
2709   * The returned value is meant to be used for positioning UI, e.g. by passing it
2710   * to the `Popover` component.
2711   *
2712   * @param {Object}                 $1          Named parameters.
2713   * @param {RefObject<HTMLElement>} $1.ref      React ref of the element
2714   *                                             containing  the editable content.
2715   * @param {RichTextValue}          $1.value    Value to check for selection.
2716   * @param {WPFormat}               $1.settings The format type's settings.
2717   *
2718   * @return {Element|Range} The active element or selection range.
2719   */
2720  function useAnchorRef({
2721    ref,
2722    value,
2723    settings = {}
2724  }) {
2725    external_wp_deprecated_default()('`useAnchorRef` hook', {
2726      since: '6.1',
2727      alternative: '`useAnchor` hook'
2728    });
2729    const {
2730      tagName,
2731      className,
2732      name
2733    } = settings;
2734    const activeFormat = name ? getActiveFormat(value, name) : undefined;
2735    return (0,external_wp_element_namespaceObject.useMemo)(() => {
2736      if (!ref.current) {
2737        return;
2738      }
2739      const {
2740        ownerDocument: {
2741          defaultView
2742        }
2743      } = ref.current;
2744      const selection = defaultView.getSelection();
2745      if (!selection.rangeCount) {
2746        return;
2747      }
2748      const range = selection.getRangeAt(0);
2749      if (!activeFormat) {
2750        return range;
2751      }
2752      let element = range.startContainer;
2753  
2754      // If the caret is right before the element, select the next element.
2755      element = element.nextElementSibling || element;
2756      while (element.nodeType !== element.ELEMENT_NODE) {
2757        element = element.parentNode;
2758      }
2759      return element.closest(tagName + (className ? '.' + className : ''));
2760    }, [activeFormat, value.start, value.end, tagName, className]);
2761  }
2762  
2763  ;// CONCATENATED MODULE: external ["wp","compose"]
2764  const external_wp_compose_namespaceObject = window["wp"]["compose"];
2765  ;// CONCATENATED MODULE: ./node_modules/@wordpress/rich-text/build-module/component/use-anchor.js
2766  /**
2767   * WordPress dependencies
2768   */
2769  
2770  
2771  
2772  /** @typedef {import('../register-format-type').WPFormat} WPFormat */
2773  /** @typedef {import('../types').RichTextValue} RichTextValue */
2774  
2775  /**
2776   * Given a range and a format tag name and class name, returns the closest
2777   * format element.
2778   *
2779   * @param {Range}       range                  The Range to check.
2780   * @param {HTMLElement} editableContentElement The editable wrapper.
2781   * @param {string}      tagName                The tag name of the format element.
2782   * @param {string}      className              The class name of the format element.
2783   *
2784   * @return {HTMLElement|undefined} The format element, if found.
2785   */
2786  function getFormatElement(range, editableContentElement, tagName, className) {
2787    let element = range.startContainer;
2788  
2789    // Even if the active format is defined, the actualy DOM range's start
2790    // container may be outside of the format's DOM element:
2791    // `a‸<strong>b</strong>` (DOM) while visually it's `a<strong>‸b</strong>`.
2792    // So at a given selection index, start with the deepest format DOM element.
2793    if (element.nodeType === element.TEXT_NODE && range.startOffset === element.length && element.nextSibling) {
2794      element = element.nextSibling;
2795      while (element.firstChild) {
2796        element = element.firstChild;
2797      }
2798    }
2799    if (element.nodeType !== element.ELEMENT_NODE) {
2800      element = element.parentElement;
2801    }
2802    if (!element) {
2803      return;
2804    }
2805    if (element === editableContentElement) {
2806      return;
2807    }
2808    if (!editableContentElement.contains(element)) {
2809      return;
2810    }
2811    const selector = tagName + (className ? '.' + className : '');
2812  
2813    // .closest( selector ), but with a boundary. Check if the element matches
2814    // the selector. If it doesn't match, try the parent element if it's not the
2815    // editable wrapper. We don't want to try to match ancestors of the editable
2816    // wrapper, which is what .closest( selector ) would do. When the element is
2817    // the editable wrapper (which is most likely the case because most text is
2818    // unformatted), this never runs.
2819    while (element !== editableContentElement) {
2820      if (element.matches(selector)) {
2821        return element;
2822      }
2823      element = element.parentElement;
2824    }
2825  }
2826  
2827  /**
2828   * @typedef {Object} VirtualAnchorElement
2829   * @property {() => DOMRect} getBoundingClientRect A function returning a DOMRect
2830   * @property {HTMLElement}   contextElement        The actual DOM element
2831   */
2832  
2833  /**
2834   * Creates a virtual anchor element for a range.
2835   *
2836   * @param {Range}       range                  The range to create a virtual anchor element for.
2837   * @param {HTMLElement} editableContentElement The editable wrapper.
2838   *
2839   * @return {VirtualAnchorElement} The virtual anchor element.
2840   */
2841  function createVirtualAnchorElement(range, editableContentElement) {
2842    return {
2843      contextElement: editableContentElement,
2844      getBoundingClientRect() {
2845        return editableContentElement.contains(range.startContainer) ? range.getBoundingClientRect() : editableContentElement.getBoundingClientRect();
2846      }
2847    };
2848  }
2849  
2850  /**
2851   * Get the anchor: a format element if there is a matching one based on the
2852   * tagName and className or a range otherwise.
2853   *
2854   * @param {HTMLElement} editableContentElement The editable wrapper.
2855   * @param {string}      tagName                The tag name of the format
2856   *                                             element.
2857   * @param {string}      className              The class name of the format
2858   *                                             element.
2859   *
2860   * @return {HTMLElement|VirtualAnchorElement|undefined} The anchor.
2861   */
2862  function getAnchor(editableContentElement, tagName, className) {
2863    if (!editableContentElement) {
2864      return;
2865    }
2866    const {
2867      ownerDocument
2868    } = editableContentElement;
2869    const {
2870      defaultView
2871    } = ownerDocument;
2872    const selection = defaultView.getSelection();
2873    if (!selection) {
2874      return;
2875    }
2876    if (!selection.rangeCount) {
2877      return;
2878    }
2879    const range = selection.getRangeAt(0);
2880    if (!range || !range.startContainer) {
2881      return;
2882    }
2883    const formatElement = getFormatElement(range, editableContentElement, tagName, className);
2884    if (formatElement) {
2885      return formatElement;
2886    }
2887    return createVirtualAnchorElement(range, editableContentElement);
2888  }
2889  
2890  /**
2891   * This hook, to be used in a format type's Edit component, returns the active
2892   * element that is formatted, or a virtual element for the selection range if
2893   * no format is active. The returned value is meant to be used for positioning
2894   * UI, e.g. by passing it to the `Popover` component via the `anchor` prop.
2895   *
2896   * @param {Object}           $1                        Named parameters.
2897   * @param {HTMLElement|null} $1.editableContentElement The element containing
2898   *                                                     the editable content.
2899   * @param {WPFormat=}        $1.settings               The format type's settings.
2900   * @return {Element|VirtualAnchorElement|undefined|null} The active element or selection range.
2901   */
2902  function useAnchor({
2903    editableContentElement,
2904    settings = {}
2905  }) {
2906    const {
2907      tagName,
2908      className,
2909      isActive
2910    } = settings;
2911    const [anchor, setAnchor] = (0,external_wp_element_namespaceObject.useState)(() => getAnchor(editableContentElement, tagName, className));
2912    const wasActive = (0,external_wp_compose_namespaceObject.usePrevious)(isActive);
2913    (0,external_wp_element_namespaceObject.useLayoutEffect)(() => {
2914      if (!editableContentElement) {
2915        return;
2916      }
2917      function callback() {
2918        setAnchor(getAnchor(editableContentElement, tagName, className));
2919      }
2920      function attach() {
2921        ownerDocument.addEventListener('selectionchange', callback);
2922      }
2923      function detach() {
2924        ownerDocument.removeEventListener('selectionchange', callback);
2925      }
2926      const {
2927        ownerDocument
2928      } = editableContentElement;
2929      if (editableContentElement === ownerDocument.activeElement ||
2930      // When a link is created, we need to attach the popover to the newly created anchor.
2931      !wasActive && isActive ||
2932      // Sometimes we're _removing_ an active anchor, such as the inline color popover.
2933      // When we add the color, it switches from a virtual anchor to a `<mark>` element.
2934      // When we _remove_ the color, it switches from a `<mark>` element to a virtual anchor.
2935      wasActive && !isActive) {
2936        setAnchor(getAnchor(editableContentElement, tagName, className));
2937        attach();
2938      }
2939      editableContentElement.addEventListener('focusin', attach);
2940      editableContentElement.addEventListener('focusout', detach);
2941      return () => {
2942        detach();
2943        editableContentElement.removeEventListener('focusin', attach);
2944        editableContentElement.removeEventListener('focusout', detach);
2945      };
2946    }, [editableContentElement, tagName, className, isActive, wasActive]);
2947    return anchor;
2948  }
2949  
2950  ;// CONCATENATED MODULE: ./node_modules/@wordpress/rich-text/build-module/component/use-default-style.js
2951  /**
2952   * WordPress dependencies
2953   */
2954  
2955  
2956  /**
2957   * In HTML, leading and trailing spaces are not visible, and multiple spaces
2958   * elsewhere are visually reduced to one space. This rule prevents spaces from
2959   * collapsing so all space is visible in the editor and can be removed. It also
2960   * prevents some browsers from inserting non-breaking spaces at the end of a
2961   * line to prevent the space from visually disappearing. Sometimes these non
2962   * breaking spaces can linger in the editor causing unwanted non breaking spaces
2963   * in between words. If also prevent Firefox from inserting a trailing `br` node
2964   * to visualise any trailing space, causing the element to be saved.
2965   *
2966   * > Authors are encouraged to set the 'white-space' property on editing hosts
2967   * > and on markup that was originally created through these editing mechanisms
2968   * > to the value 'pre-wrap'. Default HTML whitespace handling is not well
2969   * > suited to WYSIWYG editing, and line wrapping will not work correctly in
2970   * > some corner cases if 'white-space' is left at its default value.
2971   *
2972   * https://html.spec.whatwg.org/multipage/interaction.html#best-practices-for-in-page-editors
2973   *
2974   * @type {string}
2975   */
2976  const whiteSpace = 'pre-wrap';
2977  
2978  /**
2979   * A minimum width of 1px will prevent the rich text container from collapsing
2980   * to 0 width and hiding the caret. This is useful for inline containers.
2981   */
2982  const minWidth = '1px';
2983  function useDefaultStyle() {
2984    return (0,external_wp_element_namespaceObject.useCallback)(element => {
2985      if (!element) {
2986        return;
2987      }
2988      element.style.whiteSpace = whiteSpace;
2989      element.style.minWidth = minWidth;
2990    }, []);
2991  }
2992  
2993  ;// CONCATENATED MODULE: ./node_modules/@wordpress/rich-text/build-module/component/use-boundary-style.js
2994  /**
2995   * WordPress dependencies
2996   */
2997  
2998  
2999  /*
3000   * Calculates and renders the format boundary style when the active formats
3001   * change.
3002   */
3003  function useBoundaryStyle({
3004    record
3005  }) {
3006    const ref = (0,external_wp_element_namespaceObject.useRef)();
3007    const {
3008      activeFormats = [],
3009      replacements,
3010      start
3011    } = record.current;
3012    const activeReplacement = replacements[start];
3013    (0,external_wp_element_namespaceObject.useEffect)(() => {
3014      // There's no need to recalculate the boundary styles if no formats are
3015      // active, because no boundary styles will be visible.
3016      if ((!activeFormats || !activeFormats.length) && !activeReplacement) {
3017        return;
3018      }
3019      const boundarySelector = '*[data-rich-text-format-boundary]';
3020      const element = ref.current.querySelector(boundarySelector);
3021      if (!element) {
3022        return;
3023      }
3024      const {
3025        ownerDocument
3026      } = element;
3027      const {
3028        defaultView
3029      } = ownerDocument;
3030      const computedStyle = defaultView.getComputedStyle(element);
3031      const newColor = computedStyle.color.replace(')', ', 0.2)').replace('rgb', 'rgba');
3032      const selector = `.rich-text:focus $boundarySelector}`;
3033      const rule = `background-color: $newColor}`;
3034      const style = `$selector} {$rule}}`;
3035      const globalStyleId = 'rich-text-boundary-style';
3036      let globalStyle = ownerDocument.getElementById(globalStyleId);
3037      if (!globalStyle) {
3038        globalStyle = ownerDocument.createElement('style');
3039        globalStyle.id = globalStyleId;
3040        ownerDocument.head.appendChild(globalStyle);
3041      }
3042      if (globalStyle.innerHTML !== style) {
3043        globalStyle.innerHTML = style;
3044      }
3045    }, [activeFormats, activeReplacement]);
3046    return ref;
3047  }
3048  
3049  ;// CONCATENATED MODULE: ./node_modules/@wordpress/rich-text/build-module/component/event-listeners/copy-handler.js
3050  /**
3051   * Internal dependencies
3052   */
3053  
3054  
3055  
3056  
3057  /* harmony default export */ const copy_handler = (props => element => {
3058    function onCopy(event) {
3059      const {
3060        record
3061      } = props.current;
3062      const {
3063        ownerDocument
3064      } = element;
3065      if (isCollapsed(record.current) || !element.contains(ownerDocument.activeElement)) {
3066        return;
3067      }
3068      const selectedRecord = slice(record.current);
3069      const plainText = getTextContent(selectedRecord);
3070      const html = toHTMLString({
3071        value: selectedRecord
3072      });
3073      event.clipboardData.setData('text/plain', plainText);
3074      event.clipboardData.setData('text/html', html);
3075      event.clipboardData.setData('rich-text', 'true');
3076      event.preventDefault();
3077      if (event.type === 'cut') {
3078        ownerDocument.execCommand('delete');
3079      }
3080    }
3081    const {
3082      defaultView
3083    } = element.ownerDocument;
3084    defaultView.addEventListener('copy', onCopy);
3085    defaultView.addEventListener('cut', onCopy);
3086    return () => {
3087      defaultView.removeEventListener('copy', onCopy);
3088      defaultView.removeEventListener('cut', onCopy);
3089    };
3090  });
3091  
3092  ;// CONCATENATED MODULE: ./node_modules/@wordpress/rich-text/build-module/component/event-listeners/select-object.js
3093  /* harmony default export */ const select_object = (() => element => {
3094    function onClick(event) {
3095      const {
3096        target
3097      } = event;
3098  
3099      // If the child element has no text content, it must be an object.
3100      if (target === element || target.textContent && target.isContentEditable) {
3101        return;
3102      }
3103      const {
3104        ownerDocument
3105      } = target;
3106      const {
3107        defaultView
3108      } = ownerDocument;
3109      const selection = defaultView.getSelection();
3110  
3111      // If it's already selected, do nothing and let default behavior happen.
3112      // This means it's "click-through".
3113      if (selection.containsNode(target)) {
3114        return;
3115      }
3116      const range = ownerDocument.createRange();
3117      // If the target is within a non editable element, select the non
3118      // editable element.
3119      const nodeToSelect = target.isContentEditable ? target : target.closest('[contenteditable]');
3120      range.selectNode(nodeToSelect);
3121      selection.removeAllRanges();
3122      selection.addRange(range);
3123      event.preventDefault();
3124    }
3125    function onFocusIn(event) {
3126      // When there is incoming focus from a link, select the object.
3127      if (event.relatedTarget && !element.contains(event.relatedTarget) && event.relatedTarget.tagName === 'A') {
3128        onClick(event);
3129      }
3130    }
3131    element.addEventListener('click', onClick);
3132    element.addEventListener('focusin', onFocusIn);
3133    return () => {
3134      element.removeEventListener('click', onClick);
3135      element.removeEventListener('focusin', onFocusIn);
3136    };
3137  });
3138  
3139  ;// CONCATENATED MODULE: external ["wp","keycodes"]
3140  const external_wp_keycodes_namespaceObject = window["wp"]["keycodes"];
3141  ;// CONCATENATED MODULE: ./node_modules/@wordpress/rich-text/build-module/component/event-listeners/format-boundaries.js
3142  /**
3143   * WordPress dependencies
3144   */
3145  
3146  
3147  /**
3148   * Internal dependencies
3149   */
3150  
3151  const EMPTY_ACTIVE_FORMATS = [];
3152  /* harmony default export */ const format_boundaries = (props => element => {
3153    function onKeyDown(event) {
3154      const {
3155        keyCode,
3156        shiftKey,
3157        altKey,
3158        metaKey,
3159        ctrlKey
3160      } = event;
3161      if (
3162      // Only override left and right keys without modifiers pressed.
3163      shiftKey || altKey || metaKey || ctrlKey || keyCode !== external_wp_keycodes_namespaceObject.LEFT && keyCode !== external_wp_keycodes_namespaceObject.RIGHT) {
3164        return;
3165      }
3166      const {
3167        record,
3168        applyRecord,
3169        forceRender
3170      } = props.current;
3171      const {
3172        text,
3173        formats,
3174        start,
3175        end,
3176        activeFormats: currentActiveFormats = []
3177      } = record.current;
3178      const collapsed = isCollapsed(record.current);
3179      const {
3180        ownerDocument
3181      } = element;
3182      const {
3183        defaultView
3184      } = ownerDocument;
3185      // To do: ideally, we should look at visual position instead.
3186      const {
3187        direction
3188      } = defaultView.getComputedStyle(element);
3189      const reverseKey = direction === 'rtl' ? external_wp_keycodes_namespaceObject.RIGHT : external_wp_keycodes_namespaceObject.LEFT;
3190      const isReverse = event.keyCode === reverseKey;
3191  
3192      // If the selection is collapsed and at the very start, do nothing if
3193      // navigating backward.
3194      // If the selection is collapsed and at the very end, do nothing if
3195      // navigating forward.
3196      if (collapsed && currentActiveFormats.length === 0) {
3197        if (start === 0 && isReverse) {
3198          return;
3199        }
3200        if (end === text.length && !isReverse) {
3201          return;
3202        }
3203      }
3204  
3205      // If the selection is not collapsed, let the browser handle collapsing
3206      // the selection for now. Later we could expand this logic to set
3207      // boundary positions if needed.
3208      if (!collapsed) {
3209        return;
3210      }
3211      const formatsBefore = formats[start - 1] || EMPTY_ACTIVE_FORMATS;
3212      const formatsAfter = formats[start] || EMPTY_ACTIVE_FORMATS;
3213      const destination = isReverse ? formatsBefore : formatsAfter;
3214      const isIncreasing = currentActiveFormats.every((format, index) => format === destination[index]);
3215      let newActiveFormatsLength = currentActiveFormats.length;
3216      if (!isIncreasing) {
3217        newActiveFormatsLength--;
3218      } else if (newActiveFormatsLength < destination.length) {
3219        newActiveFormatsLength++;
3220      }
3221      if (newActiveFormatsLength === currentActiveFormats.length) {
3222        record.current._newActiveFormats = destination;
3223        return;
3224      }
3225      event.preventDefault();
3226      const origin = isReverse ? formatsAfter : formatsBefore;
3227      const source = isIncreasing ? destination : origin;
3228      const newActiveFormats = source.slice(0, newActiveFormatsLength);
3229      const newValue = {
3230        ...record.current,
3231        activeFormats: newActiveFormats
3232      };
3233      record.current = newValue;
3234      applyRecord(newValue);
3235      forceRender();
3236    }
3237    element.addEventListener('keydown', onKeyDown);
3238    return () => {
3239      element.removeEventListener('keydown', onKeyDown);
3240    };
3241  });
3242  
3243  ;// CONCATENATED MODULE: ./node_modules/@wordpress/rich-text/build-module/component/event-listeners/delete.js
3244  /**
3245   * WordPress dependencies
3246   */
3247  
3248  
3249  /**
3250   * Internal dependencies
3251   */
3252  
3253  /* harmony default export */ const event_listeners_delete = (props => element => {
3254    function onKeyDown(event) {
3255      const {
3256        keyCode
3257      } = event;
3258      const {
3259        createRecord,
3260        handleChange
3261      } = props.current;
3262      if (event.defaultPrevented) {
3263        return;
3264      }
3265      if (keyCode !== external_wp_keycodes_namespaceObject.DELETE && keyCode !== external_wp_keycodes_namespaceObject.BACKSPACE) {
3266        return;
3267      }
3268      const currentValue = createRecord();
3269      const {
3270        start,
3271        end,
3272        text
3273      } = currentValue;
3274  
3275      // Always handle full content deletion ourselves.
3276      if (start === 0 && end !== 0 && end === text.length) {
3277        handleChange(remove_remove(currentValue));
3278        event.preventDefault();
3279      }
3280    }
3281    element.addEventListener('keydown', onKeyDown);
3282    return () => {
3283      element.removeEventListener('keydown', onKeyDown);
3284    };
3285  });
3286  
3287  ;// CONCATENATED MODULE: ./node_modules/@wordpress/rich-text/build-module/update-formats.js
3288  /**
3289   * Internal dependencies
3290   */
3291  
3292  
3293  
3294  /** @typedef {import('./types').RichTextValue} RichTextValue */
3295  
3296  /**
3297   * Efficiently updates all the formats from `start` (including) until `end`
3298   * (excluding) with the active formats. Mutates `value`.
3299   *
3300   * @param {Object}        $1         Named paramentes.
3301   * @param {RichTextValue} $1.value   Value te update.
3302   * @param {number}        $1.start   Index to update from.
3303   * @param {number}        $1.end     Index to update until.
3304   * @param {Array}         $1.formats Replacement formats.
3305   *
3306   * @return {RichTextValue} Mutated value.
3307   */
3308  function updateFormats({
3309    value,
3310    start,
3311    end,
3312    formats
3313  }) {
3314    // Start and end may be switched in case of delete.
3315    const min = Math.min(start, end);
3316    const max = Math.max(start, end);
3317    const formatsBefore = value.formats[min - 1] || [];
3318    const formatsAfter = value.formats[max] || [];
3319  
3320    // First, fix the references. If any format right before or after are
3321    // equal, the replacement format should use the same reference.
3322    value.activeFormats = formats.map((format, index) => {
3323      if (formatsBefore[index]) {
3324        if (isFormatEqual(format, formatsBefore[index])) {
3325          return formatsBefore[index];
3326        }
3327      } else if (formatsAfter[index]) {
3328        if (isFormatEqual(format, formatsAfter[index])) {
3329          return formatsAfter[index];
3330        }
3331      }
3332      return format;
3333    });
3334    while (--end >= start) {
3335      if (value.activeFormats.length > 0) {
3336        value.formats[end] = value.activeFormats;
3337      } else {
3338        delete value.formats[end];
3339      }
3340    }
3341    return value;
3342  }
3343  
3344  ;// CONCATENATED MODULE: ./node_modules/@wordpress/rich-text/build-module/component/event-listeners/input-and-selection.js
3345  /**
3346   * Internal dependencies
3347   */
3348  
3349  
3350  
3351  /**
3352   * All inserting input types that would insert HTML into the DOM.
3353   *
3354   * @see https://www.w3.org/TR/input-events-2/#interface-InputEvent-Attributes
3355   *
3356   * @type {Set}
3357   */
3358  const INSERTION_INPUT_TYPES_TO_IGNORE = new Set(['insertParagraph', 'insertOrderedList', 'insertUnorderedList', 'insertHorizontalRule', 'insertLink']);
3359  const input_and_selection_EMPTY_ACTIVE_FORMATS = [];
3360  const PLACEHOLDER_ATTR_NAME = 'data-rich-text-placeholder';
3361  
3362  /**
3363   * If the selection is set on the placeholder element, collapse the selection to
3364   * the start (before the placeholder).
3365   *
3366   * @param {Window} defaultView
3367   */
3368  function fixPlaceholderSelection(defaultView) {
3369    const selection = defaultView.getSelection();
3370    const {
3371      anchorNode,
3372      anchorOffset
3373    } = selection;
3374    if (anchorNode.nodeType !== anchorNode.ELEMENT_NODE) {
3375      return;
3376    }
3377    const targetNode = anchorNode.childNodes[anchorOffset];
3378    if (!targetNode || targetNode.nodeType !== targetNode.ELEMENT_NODE || !targetNode.hasAttribute(PLACEHOLDER_ATTR_NAME)) {
3379      return;
3380    }
3381    selection.collapseToStart();
3382  }
3383  /* harmony default export */ const input_and_selection = (props => element => {
3384    const {
3385      ownerDocument
3386    } = element;
3387    const {
3388      defaultView
3389    } = ownerDocument;
3390    let isComposing = false;
3391    function onInput(event) {
3392      // Do not trigger a change if characters are being composed. Browsers
3393      // will usually emit a final `input` event when the characters are
3394      // composed. As of December 2019, Safari doesn't support
3395      // nativeEvent.isComposing.
3396      if (isComposing) {
3397        return;
3398      }
3399      let inputType;
3400      if (event) {
3401        inputType = event.inputType;
3402      }
3403      const {
3404        record,
3405        applyRecord,
3406        createRecord,
3407        handleChange
3408      } = props.current;
3409  
3410      // The browser formatted something or tried to insert HTML. Overwrite
3411      // it. It will be handled later by the format library if needed.
3412      if (inputType && (inputType.indexOf('format') === 0 || INSERTION_INPUT_TYPES_TO_IGNORE.has(inputType))) {
3413        applyRecord(record.current);
3414        return;
3415      }
3416      const currentValue = createRecord();
3417      const {
3418        start,
3419        activeFormats: oldActiveFormats = []
3420      } = record.current;
3421  
3422      // Update the formats between the last and new caret position.
3423      const change = updateFormats({
3424        value: currentValue,
3425        start,
3426        end: currentValue.start,
3427        formats: oldActiveFormats
3428      });
3429      handleChange(change);
3430    }
3431  
3432    /**
3433     * Syncs the selection to local state. A callback for the `selectionchange`
3434     * event.
3435     */
3436    function handleSelectionChange() {
3437      const {
3438        record,
3439        applyRecord,
3440        createRecord,
3441        onSelectionChange
3442      } = props.current;
3443  
3444      // Check if the implementor disabled editing. `contentEditable` does
3445      // disable input, but not text selection, so we must ignore selection
3446      // changes.
3447      if (element.contentEditable !== 'true') {
3448        return;
3449      }
3450  
3451      // Ensure the active element is the rich text element.
3452      if (ownerDocument.activeElement !== element) {
3453        // If it is not, we can stop listening for selection changes. We
3454        // resume listening when the element is focused.
3455        ownerDocument.removeEventListener('selectionchange', handleSelectionChange);
3456        return;
3457      }
3458  
3459      // In case of a keyboard event, ignore selection changes during
3460      // composition.
3461      if (isComposing) {
3462        return;
3463      }
3464      const {
3465        start,
3466        end,
3467        text
3468      } = createRecord();
3469      const oldRecord = record.current;
3470  
3471      // Fallback mechanism for IE11, which doesn't support the input event.
3472      // Any input results in a selection change.
3473      if (text !== oldRecord.text) {
3474        onInput();
3475        return;
3476      }
3477      if (start === oldRecord.start && end === oldRecord.end) {
3478        // Sometimes the browser may set the selection on the placeholder
3479        // element, in which case the caret is not visible. We need to set
3480        // the caret before the placeholder if that's the case.
3481        if (oldRecord.text.length === 0 && start === 0) {
3482          fixPlaceholderSelection(defaultView);
3483        }
3484        return;
3485      }
3486      const newValue = {
3487        ...oldRecord,
3488        start,
3489        end,
3490        // _newActiveFormats may be set on arrow key navigation to control
3491        // the right boundary position. If undefined, getActiveFormats will
3492        // give the active formats according to the browser.
3493        activeFormats: oldRecord._newActiveFormats,
3494        _newActiveFormats: undefined
3495      };
3496      const newActiveFormats = getActiveFormats(newValue, input_and_selection_EMPTY_ACTIVE_FORMATS);
3497  
3498      // Update the value with the new active formats.
3499      newValue.activeFormats = newActiveFormats;
3500  
3501      // It is important that the internal value is updated first,
3502      // otherwise the value will be wrong on render!
3503      record.current = newValue;
3504      applyRecord(newValue, {
3505        domOnly: true
3506      });
3507      onSelectionChange(start, end);
3508    }
3509    function onCompositionStart() {
3510      isComposing = true;
3511      // Do not update the selection when characters are being composed as
3512      // this rerenders the component and might destroy internal browser
3513      // editing state.
3514      ownerDocument.removeEventListener('selectionchange', handleSelectionChange);
3515      // Remove the placeholder. Since the rich text value doesn't update
3516      // during composition, the placeholder doesn't get removed. There's no
3517      // need to re-add it, when the value is updated on compositionend it
3518      // will be re-added when the value is empty.
3519      element.querySelector(`[$PLACEHOLDER_ATTR_NAME}]`)?.remove();
3520    }
3521    function onCompositionEnd() {
3522      isComposing = false;
3523      // Ensure the value is up-to-date for browsers that don't emit a final
3524      // input event after composition.
3525      onInput({
3526        inputType: 'insertText'
3527      });
3528      // Tracking selection changes can be resumed.
3529      ownerDocument.addEventListener('selectionchange', handleSelectionChange);
3530    }
3531    function onFocus() {
3532      const {
3533        record,
3534        isSelected,
3535        onSelectionChange,
3536        applyRecord
3537      } = props.current;
3538  
3539      // When the whole editor is editable, let writing flow handle
3540      // selection.
3541      if (element.parentElement.closest('[contenteditable="true"]')) {
3542        return;
3543      }
3544      if (!isSelected) {
3545        // We know for certain that on focus, the old selection is invalid.
3546        // It will be recalculated on the next mouseup, keyup, or touchend
3547        // event.
3548        const index = undefined;
3549        record.current = {
3550          ...record.current,
3551          start: index,
3552          end: index,
3553          activeFormats: input_and_selection_EMPTY_ACTIVE_FORMATS
3554        };
3555      } else {
3556        applyRecord(record.current, {
3557          domOnly: true
3558        });
3559      }
3560      onSelectionChange(record.current.start, record.current.end);
3561  
3562      // There is no selection change event when the element is focused, so
3563      // we need to manually trigger it. The selection is also not available
3564      // yet in this call stack.
3565      window.queueMicrotask(handleSelectionChange);
3566      ownerDocument.addEventListener('selectionchange', handleSelectionChange);
3567    }
3568    element.addEventListener('input', onInput);
3569    element.addEventListener('compositionstart', onCompositionStart);
3570    element.addEventListener('compositionend', onCompositionEnd);
3571    element.addEventListener('focus', onFocus);
3572    return () => {
3573      element.removeEventListener('input', onInput);
3574      element.removeEventListener('compositionstart', onCompositionStart);
3575      element.removeEventListener('compositionend', onCompositionEnd);
3576      element.removeEventListener('focus', onFocus);
3577    };
3578  });
3579  
3580  ;// CONCATENATED MODULE: ./node_modules/@wordpress/rich-text/build-module/component/event-listeners/selection-change-compat.js
3581  /**
3582   * Internal dependencies
3583   */
3584  
3585  
3586  /**
3587   * Sometimes some browsers are not firing a `selectionchange` event when
3588   * changing the selection by mouse or keyboard. This hook makes sure that, if we
3589   * detect no `selectionchange` or `input` event between the up and down events,
3590   * we fire a `selectionchange` event.
3591   */
3592  /* harmony default export */ const selection_change_compat = (() => element => {
3593    const {
3594      ownerDocument
3595    } = element;
3596    const {
3597      defaultView
3598    } = ownerDocument;
3599    const selection = defaultView?.getSelection();
3600    let range;
3601    function getRange() {
3602      return selection.rangeCount ? selection.getRangeAt(0) : null;
3603    }
3604    function onDown(event) {
3605      const type = event.type === 'keydown' ? 'keyup' : 'pointerup';
3606      function onCancel() {
3607        ownerDocument.removeEventListener(type, onUp);
3608        ownerDocument.removeEventListener('selectionchange', onCancel);
3609        ownerDocument.removeEventListener('input', onCancel);
3610      }
3611      function onUp() {
3612        onCancel();
3613        if (isRangeEqual(range, getRange())) {
3614          return;
3615        }
3616        ownerDocument.dispatchEvent(new Event('selectionchange'));
3617      }
3618      ownerDocument.addEventListener(type, onUp);
3619      ownerDocument.addEventListener('selectionchange', onCancel);
3620      ownerDocument.addEventListener('input', onCancel);
3621      range = getRange();
3622    }
3623    element.addEventListener('pointerdown', onDown);
3624    element.addEventListener('keydown', onDown);
3625    return () => {
3626      element.removeEventListener('pointerdown', onDown);
3627      element.removeEventListener('keydown', onDown);
3628    };
3629  });
3630  
3631  ;// CONCATENATED MODULE: ./node_modules/@wordpress/rich-text/build-module/component/event-listeners/index.js
3632  /**
3633   * WordPress dependencies
3634   */
3635  
3636  
3637  
3638  /**
3639   * Internal dependencies
3640   */
3641  
3642  
3643  
3644  
3645  
3646  
3647  const allEventListeners = [copy_handler, select_object, format_boundaries, event_listeners_delete, input_and_selection, selection_change_compat];
3648  function useEventListeners(props) {
3649    const propsRef = (0,external_wp_element_namespaceObject.useRef)(props);
3650    propsRef.current = props;
3651    const refEffects = (0,external_wp_element_namespaceObject.useMemo)(() => allEventListeners.map(refEffect => refEffect(propsRef)), [propsRef]);
3652    return (0,external_wp_compose_namespaceObject.useRefEffect)(element => {
3653      const cleanups = refEffects.map(effect => effect(element));
3654      return () => {
3655        cleanups.forEach(cleanup => cleanup());
3656      };
3657    }, [refEffects]);
3658  }
3659  
3660  ;// CONCATENATED MODULE: ./node_modules/@wordpress/rich-text/build-module/component/index.js
3661  /**
3662   * WordPress dependencies
3663   */
3664  
3665  
3666  
3667  
3668  /**
3669   * Internal dependencies
3670   */
3671  
3672  
3673  
3674  
3675  
3676  
3677  function useRichText({
3678    value = '',
3679    selectionStart,
3680    selectionEnd,
3681    placeholder,
3682    onSelectionChange,
3683    preserveWhiteSpace,
3684    onChange,
3685    __unstableDisableFormats: disableFormats,
3686    __unstableIsSelected: isSelected,
3687    __unstableDependencies = [],
3688    __unstableAfterParse,
3689    __unstableBeforeSerialize,
3690    __unstableAddInvisibleFormats
3691  }) {
3692    const registry = (0,external_wp_data_namespaceObject.useRegistry)();
3693    const [, forceRender] = (0,external_wp_element_namespaceObject.useReducer)(() => ({}));
3694    const ref = (0,external_wp_element_namespaceObject.useRef)();
3695    function createRecord() {
3696      const {
3697        ownerDocument: {
3698          defaultView
3699        }
3700      } = ref.current;
3701      const selection = defaultView.getSelection();
3702      const range = selection.rangeCount > 0 ? selection.getRangeAt(0) : null;
3703      return create({
3704        element: ref.current,
3705        range,
3706        __unstableIsEditableTree: true
3707      });
3708    }
3709    function applyRecord(newRecord, {
3710      domOnly
3711    } = {}) {
3712      apply({
3713        value: newRecord,
3714        current: ref.current,
3715        prepareEditableTree: __unstableAddInvisibleFormats,
3716        __unstableDomOnly: domOnly,
3717        placeholder
3718      });
3719    }
3720  
3721    // Internal values are updated synchronously, unlike props and state.
3722    const _valueRef = (0,external_wp_element_namespaceObject.useRef)(value);
3723    const recordRef = (0,external_wp_element_namespaceObject.useRef)();
3724    function setRecordFromProps() {
3725      _valueRef.current = value;
3726      recordRef.current = value;
3727      if (!(value instanceof RichTextData)) {
3728        recordRef.current = value ? RichTextData.fromHTMLString(value, {
3729          preserveWhiteSpace
3730        }) : RichTextData.empty();
3731      }
3732      // To do: make rich text internally work with RichTextData.
3733      recordRef.current = {
3734        text: recordRef.current.text,
3735        formats: recordRef.current.formats,
3736        replacements: recordRef.current.replacements
3737      };
3738      if (disableFormats) {
3739        recordRef.current.formats = Array(value.length);
3740        recordRef.current.replacements = Array(value.length);
3741      }
3742      if (__unstableAfterParse) {
3743        recordRef.current.formats = __unstableAfterParse(recordRef.current);
3744      }
3745      recordRef.current.start = selectionStart;
3746      recordRef.current.end = selectionEnd;
3747    }
3748    const hadSelectionUpdateRef = (0,external_wp_element_namespaceObject.useRef)(false);
3749    if (!recordRef.current) {
3750      hadSelectionUpdateRef.current = isSelected;
3751      setRecordFromProps();
3752    } else if (selectionStart !== recordRef.current.start || selectionEnd !== recordRef.current.end) {
3753      hadSelectionUpdateRef.current = isSelected;
3754      recordRef.current = {
3755        ...recordRef.current,
3756        start: selectionStart,
3757        end: selectionEnd,
3758        activeFormats: undefined
3759      };
3760    }
3761  
3762    /**
3763     * Sync the value to global state. The node tree and selection will also be
3764     * updated if differences are found.
3765     *
3766     * @param {Object} newRecord The record to sync and apply.
3767     */
3768    function handleChange(newRecord) {
3769      recordRef.current = newRecord;
3770      applyRecord(newRecord);
3771      if (disableFormats) {
3772        _valueRef.current = newRecord.text;
3773      } else {
3774        const newFormats = __unstableBeforeSerialize ? __unstableBeforeSerialize(newRecord) : newRecord.formats;
3775        newRecord = {
3776          ...newRecord,
3777          formats: newFormats
3778        };
3779        if (typeof value === 'string') {
3780          _valueRef.current = toHTMLString({
3781            value: newRecord,
3782            preserveWhiteSpace
3783          });
3784        } else {
3785          _valueRef.current = new RichTextData(newRecord);
3786        }
3787      }
3788      const {
3789        start,
3790        end,
3791        formats,
3792        text
3793      } = recordRef.current;
3794  
3795      // Selection must be updated first, so it is recorded in history when
3796      // the content change happens.
3797      // We batch both calls to only attempt to rerender once.
3798      registry.batch(() => {
3799        onSelectionChange(start, end);
3800        onChange(_valueRef.current, {
3801          __unstableFormats: formats,
3802          __unstableText: text
3803        });
3804      });
3805      forceRender();
3806    }
3807    function applyFromProps() {
3808      setRecordFromProps();
3809      applyRecord(recordRef.current);
3810    }
3811    const didMountRef = (0,external_wp_element_namespaceObject.useRef)(false);
3812  
3813    // Value updates must happen synchonously to avoid overwriting newer values.
3814    (0,external_wp_element_namespaceObject.useLayoutEffect)(() => {
3815      if (didMountRef.current && value !== _valueRef.current) {
3816        applyFromProps();
3817        forceRender();
3818      }
3819    }, [value]);
3820  
3821    // Value updates must happen synchonously to avoid overwriting newer values.
3822    (0,external_wp_element_namespaceObject.useLayoutEffect)(() => {
3823      if (!hadSelectionUpdateRef.current) {
3824        return;
3825      }
3826      if (ref.current.ownerDocument.activeElement !== ref.current) {
3827        ref.current.focus();
3828      }
3829      applyRecord(recordRef.current);
3830      hadSelectionUpdateRef.current = false;
3831    }, [hadSelectionUpdateRef.current]);
3832    const mergedRefs = (0,external_wp_compose_namespaceObject.useMergeRefs)([ref, useDefaultStyle(), useBoundaryStyle({
3833      record: recordRef
3834    }), useEventListeners({
3835      record: recordRef,
3836      handleChange,
3837      applyRecord,
3838      createRecord,
3839      isSelected,
3840      onSelectionChange,
3841      forceRender
3842    }), (0,external_wp_compose_namespaceObject.useRefEffect)(() => {
3843      applyFromProps();
3844      didMountRef.current = true;
3845    }, [placeholder, ...__unstableDependencies])]);
3846    return {
3847      value: recordRef.current,
3848      // A function to get the most recent value so event handlers in
3849      // useRichText implementations have access to it. For example when
3850      // listening to input events, we internally update the state, but this
3851      // state is not yet available to the input event handler because React
3852      // may re-render asynchronously.
3853      getValue: () => recordRef.current,
3854      onChange: handleChange,
3855      ref: mergedRefs
3856    };
3857  }
3858  function __experimentalRichText() {}
3859  
3860  ;// CONCATENATED MODULE: ./node_modules/@wordpress/rich-text/build-module/index.js
3861  
3862  
3863  
3864  
3865  
3866  
3867  
3868  
3869  
3870  
3871  
3872  
3873  
3874  
3875  
3876  
3877  
3878  
3879  
3880  
3881  
3882  
3883  
3884  
3885  
3886  
3887  
3888  
3889  /**
3890   * An object which represents a formatted string. See main `@wordpress/rich-text`
3891   * documentation for more information.
3892   */
3893  
3894  (window.wp = window.wp || {}).richText = __webpack_exports__;
3895  /******/ })()
3896  ;


Generated : Sat Nov 23 08:20:01 2024 Cross-referenced by PHPXref