| [ Index ] |
PHP Cross Reference of WordPress Trunk (Updated Daily) |
[Summary view] [Print] [Text view]
1 (function() { 2 "use strict"; 3 var wp; 4 (wp ||= {}).richText = (() => { 5 var __create = Object.create; 6 var __defProp = Object.defineProperty; 7 var __getOwnPropDesc = Object.getOwnPropertyDescriptor; 8 var __getOwnPropNames = Object.getOwnPropertyNames; 9 var __getProtoOf = Object.getPrototypeOf; 10 var __hasOwnProp = Object.prototype.hasOwnProperty; 11 var __commonJS = (cb, mod) => function __require() { 12 return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports; 13 }; 14 var __export = (target, all) => { 15 for (var name in all) 16 __defProp(target, name, { get: all[name], enumerable: true }); 17 }; 18 var __copyProps = (to, from, except, desc) => { 19 if (from && typeof from === "object" || typeof from === "function") { 20 for (let key of __getOwnPropNames(from)) 21 if (!__hasOwnProp.call(to, key) && key !== except) 22 __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); 23 } 24 return to; 25 }; 26 var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps( 27 // If the importer is in node compatibility mode or this is not an ESM 28 // file that has been converted to a CommonJS file using a Babel- 29 // compatible transform (i.e. "__esModule" has not been set), then set 30 // "default" to the CommonJS "module.exports" for node compatibility. 31 isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target, 32 mod 33 )); 34 var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); 35 36 // package-external:@wordpress/data 37 var require_data = __commonJS({ 38 "package-external:@wordpress/data"(exports, module) { 39 module.exports = window.wp.data; 40 } 41 }); 42 43 // package-external:@wordpress/escape-html 44 var require_escape_html = __commonJS({ 45 "package-external:@wordpress/escape-html"(exports, module) { 46 module.exports = window.wp.escapeHtml; 47 } 48 }); 49 50 // package-external:@wordpress/a11y 51 var require_a11y = __commonJS({ 52 "package-external:@wordpress/a11y"(exports, module) { 53 module.exports = window.wp.a11y; 54 } 55 }); 56 57 // package-external:@wordpress/i18n 58 var require_i18n = __commonJS({ 59 "package-external:@wordpress/i18n"(exports, module) { 60 module.exports = window.wp.i18n; 61 } 62 }); 63 64 // package-external:@wordpress/private-apis 65 var require_private_apis = __commonJS({ 66 "package-external:@wordpress/private-apis"(exports, module) { 67 module.exports = window.wp.privateApis; 68 } 69 }); 70 71 // package-external:@wordpress/element 72 var require_element = __commonJS({ 73 "package-external:@wordpress/element"(exports, module) { 74 module.exports = window.wp.element; 75 } 76 }); 77 78 // package-external:@wordpress/compose 79 var require_compose = __commonJS({ 80 "package-external:@wordpress/compose"(exports, module) { 81 module.exports = window.wp.compose; 82 } 83 }); 84 85 // package-external:@wordpress/deprecated 86 var require_deprecated = __commonJS({ 87 "package-external:@wordpress/deprecated"(exports, module) { 88 module.exports = window.wp.deprecated; 89 } 90 }); 91 92 // package-external:@wordpress/keycodes 93 var require_keycodes = __commonJS({ 94 "package-external:@wordpress/keycodes"(exports, module) { 95 module.exports = window.wp.keycodes; 96 } 97 }); 98 99 // package-external:@wordpress/dom 100 var require_dom = __commonJS({ 101 "package-external:@wordpress/dom"(exports, module) { 102 module.exports = window.wp.dom; 103 } 104 }); 105 106 // packages/rich-text/build-module/index.mjs 107 var index_exports = {}; 108 __export(index_exports, { 109 RichTextData: () => RichTextData, 110 __experimentalRichText: () => __experimentalRichText, 111 __unstableCreateElement: () => createElement, 112 __unstableToDom: () => toDom, 113 __unstableUseRichText: () => useDeprecatedRichText, 114 applyFormat: () => applyFormat, 115 concat: () => concat, 116 create: () => create, 117 getActiveFormat: () => getActiveFormat, 118 getActiveFormats: () => getActiveFormats, 119 getActiveObject: () => getActiveObject, 120 getTextContent: () => getTextContent, 121 insert: () => insert, 122 insertObject: () => insertObject, 123 isCollapsed: () => isCollapsed, 124 isEmpty: () => isEmpty, 125 join: () => join, 126 privateApis: () => privateApis, 127 registerFormatType: () => registerFormatType, 128 remove: () => remove2, 129 removeFormat: () => removeFormat, 130 replace: () => replace2, 131 slice: () => slice, 132 split: () => split, 133 store: () => store, 134 toHTMLString: () => toHTMLString, 135 toggleFormat: () => toggleFormat, 136 unregisterFormatType: () => unregisterFormatType, 137 useAnchor: () => useAnchor, 138 useAnchorRef: () => useAnchorRef 139 }); 140 141 // packages/rich-text/build-module/store/index.mjs 142 var import_data3 = __toESM(require_data(), 1); 143 144 // packages/rich-text/build-module/store/reducer.mjs 145 var import_data = __toESM(require_data(), 1); 146 function formatTypes(state = {}, action) { 147 switch (action.type) { 148 case "ADD_FORMAT_TYPES": 149 return { 150 ...state, 151 // Key format types by their name. 152 ...action.formatTypes.reduce( 153 (newFormatTypes, type) => ({ 154 ...newFormatTypes, 155 [type.name]: type 156 }), 157 {} 158 ) 159 }; 160 case "REMOVE_FORMAT_TYPES": 161 return Object.fromEntries( 162 Object.entries(state).filter( 163 ([key]) => !action.names.includes(key) 164 ) 165 ); 166 } 167 return state; 168 } 169 var reducer_default = (0, import_data.combineReducers)({ formatTypes }); 170 171 // packages/rich-text/build-module/store/selectors.mjs 172 var selectors_exports = {}; 173 __export(selectors_exports, { 174 getFormatType: () => getFormatType, 175 getFormatTypeForBareElement: () => getFormatTypeForBareElement, 176 getFormatTypeForClassName: () => getFormatTypeForClassName, 177 getFormatTypes: () => getFormatTypes 178 }); 179 var import_data2 = __toESM(require_data(), 1); 180 var getFormatTypes = (0, import_data2.createSelector)( 181 (state) => Object.values(state.formatTypes), 182 (state) => [state.formatTypes] 183 ); 184 function getFormatType(state, name) { 185 return state.formatTypes[name]; 186 } 187 function getFormatTypeForBareElement(state, bareElementTagName) { 188 const formatTypes2 = getFormatTypes(state); 189 return formatTypes2.find(({ className, tagName }) => { 190 return className === null && bareElementTagName === tagName; 191 }) || formatTypes2.find(({ className, tagName }) => { 192 return className === null && "*" === tagName; 193 }); 194 } 195 function getFormatTypeForClassName(state, elementClassName) { 196 return getFormatTypes(state).find(({ className }) => { 197 if (className === null) { 198 return false; 199 } 200 return ` $elementClassName} `.indexOf(` $className} `) >= 0; 201 }); 202 } 203 204 // packages/rich-text/build-module/store/actions.mjs 205 var actions_exports = {}; 206 __export(actions_exports, { 207 addFormatTypes: () => addFormatTypes, 208 removeFormatTypes: () => removeFormatTypes 209 }); 210 function addFormatTypes(formatTypes2) { 211 return { 212 type: "ADD_FORMAT_TYPES", 213 formatTypes: Array.isArray(formatTypes2) ? formatTypes2 : [formatTypes2] 214 }; 215 } 216 function removeFormatTypes(names) { 217 return { 218 type: "REMOVE_FORMAT_TYPES", 219 names: Array.isArray(names) ? names : [names] 220 }; 221 } 222 223 // packages/rich-text/build-module/store/index.mjs 224 var STORE_NAME = "core/rich-text"; 225 var store = (0, import_data3.createReduxStore)(STORE_NAME, { 226 reducer: reducer_default, 227 selectors: selectors_exports, 228 actions: actions_exports 229 }); 230 (0, import_data3.register)(store); 231 232 // packages/rich-text/build-module/is-format-equal.mjs 233 function isFormatEqual(format1, format2) { 234 if (format1 === format2) { 235 return true; 236 } 237 if (!format1 || !format2) { 238 return false; 239 } 240 if (format1.type !== format2.type) { 241 return false; 242 } 243 let attributes1 = format1.attributes; 244 let attributes2 = format2.attributes; 245 if (format1.unregisteredAttributes || format2.unregisteredAttributes) { 246 attributes1 = { ...attributes1, ...format1.unregisteredAttributes }; 247 attributes2 = { ...attributes2, ...format2.unregisteredAttributes }; 248 } 249 if (attributes1 === attributes2) { 250 return true; 251 } 252 if (!attributes1 || !attributes2) { 253 return false; 254 } 255 const keys1 = Object.keys(attributes1); 256 const keys2 = Object.keys(attributes2); 257 if (keys1.length !== keys2.length) { 258 return false; 259 } 260 const length = keys1.length; 261 for (let i2 = 0; i2 < length; i2++) { 262 const name = keys1[i2]; 263 if (attributes1[name] !== attributes2[name]) { 264 return false; 265 } 266 } 267 return true; 268 } 269 270 // packages/rich-text/build-module/normalise-formats.mjs 271 function normaliseFormats(value) { 272 const newFormats = value.formats.slice(); 273 newFormats.forEach((formatsAtIndex, index) => { 274 const formatsAtPreviousIndex = newFormats[index - 1]; 275 if (formatsAtPreviousIndex) { 276 const newFormatsAtIndex = formatsAtIndex.slice(); 277 newFormatsAtIndex.forEach((format, formatIndex) => { 278 const previousFormat = formatsAtPreviousIndex[formatIndex]; 279 if (isFormatEqual(format, previousFormat)) { 280 newFormatsAtIndex[formatIndex] = previousFormat; 281 } 282 }); 283 newFormats[index] = newFormatsAtIndex; 284 } 285 }); 286 return { 287 ...value, 288 formats: newFormats 289 }; 290 } 291 292 // packages/rich-text/build-module/apply-format.mjs 293 function replace(array, index, value) { 294 array = array.slice(); 295 array[index] = value; 296 return array; 297 } 298 function applyFormat(value, format, startIndex = value.start, endIndex = value.end) { 299 const { formats, activeFormats } = value; 300 const newFormats = formats.slice(); 301 if (startIndex === endIndex) { 302 const startFormat = newFormats[startIndex]?.find( 303 ({ type }) => type === format.type 304 ); 305 if (startFormat) { 306 const index = newFormats[startIndex].indexOf(startFormat); 307 while (newFormats[startIndex] && newFormats[startIndex][index] === startFormat) { 308 newFormats[startIndex] = replace( 309 newFormats[startIndex], 310 index, 311 format 312 ); 313 startIndex--; 314 } 315 endIndex++; 316 while (newFormats[endIndex] && newFormats[endIndex][index] === startFormat) { 317 newFormats[endIndex] = replace( 318 newFormats[endIndex], 319 index, 320 format 321 ); 322 endIndex++; 323 } 324 } 325 } else { 326 let position = Infinity; 327 for (let index = startIndex; index < endIndex; index++) { 328 if (newFormats[index]) { 329 newFormats[index] = newFormats[index].filter( 330 ({ type }) => type !== format.type 331 ); 332 const length = newFormats[index].length; 333 if (length < position) { 334 position = length; 335 } 336 } else { 337 newFormats[index] = []; 338 position = 0; 339 } 340 } 341 for (let index = startIndex; index < endIndex; index++) { 342 newFormats[index].splice(position, 0, format); 343 } 344 } 345 return normaliseFormats({ 346 ...value, 347 formats: newFormats, 348 // Always revise active formats. This serves as a placeholder for new 349 // inputs with the format so new input appears with the format applied, 350 // and ensures a format of the same type uses the latest values. 351 activeFormats: [ 352 ...activeFormats?.filter( 353 ({ type }) => type !== format.type 354 ) || [], 355 format 356 ] 357 }); 358 } 359 360 // packages/rich-text/build-module/create.mjs 361 var import_data5 = __toESM(require_data(), 1); 362 363 // packages/rich-text/build-module/create-element.mjs 364 function createElement({ implementation }, html) { 365 if (!createElement.body) { 366 createElement.body = implementation.createHTMLDocument("").body; 367 } 368 createElement.body.innerHTML = html; 369 return createElement.body; 370 } 371 372 // packages/rich-text/build-module/special-characters.mjs 373 var OBJECT_REPLACEMENT_CHARACTER = "\uFFFC"; 374 var ZWNBSP = "\uFEFF"; 375 376 // packages/rich-text/build-module/to-html-string.mjs 377 var import_escape_html = __toESM(require_escape_html(), 1); 378 379 // packages/rich-text/build-module/get-active-formats.mjs 380 function getActiveFormats(value, EMPTY_ACTIVE_FORMATS3 = []) { 381 const { formats, start, end, activeFormats } = value; 382 if (start === void 0) { 383 return EMPTY_ACTIVE_FORMATS3; 384 } 385 if (start === end) { 386 if (activeFormats) { 387 return activeFormats; 388 } 389 const formatsBefore = formats[start - 1] || EMPTY_ACTIVE_FORMATS3; 390 const formatsAfter = formats[start] || EMPTY_ACTIVE_FORMATS3; 391 if (formatsBefore.length < formatsAfter.length) { 392 return formatsBefore; 393 } 394 return formatsAfter; 395 } 396 if (!formats[start]) { 397 return EMPTY_ACTIVE_FORMATS3; 398 } 399 const selectedFormats = formats.slice(start, end); 400 const _activeFormats = [...selectedFormats[0]]; 401 let i2 = selectedFormats.length; 402 while (i2--) { 403 const formatsAtIndex = selectedFormats[i2]; 404 if (!formatsAtIndex) { 405 return EMPTY_ACTIVE_FORMATS3; 406 } 407 let ii = _activeFormats.length; 408 while (ii--) { 409 const format = _activeFormats[ii]; 410 if (!formatsAtIndex.find( 411 (_format) => isFormatEqual(format, _format) 412 )) { 413 _activeFormats.splice(ii, 1); 414 } 415 } 416 if (_activeFormats.length === 0) { 417 return EMPTY_ACTIVE_FORMATS3; 418 } 419 } 420 return _activeFormats || EMPTY_ACTIVE_FORMATS3; 421 } 422 423 // packages/rich-text/build-module/get-format-type.mjs 424 var import_data4 = __toESM(require_data(), 1); 425 function getFormatType2(name) { 426 return (0, import_data4.select)(store).getFormatType(name); 427 } 428 429 // packages/rich-text/build-module/to-tree.mjs 430 function restoreOnAttributes(attributes, isEditableTree) { 431 if (isEditableTree) { 432 return attributes; 433 } 434 const newAttributes = {}; 435 for (const key in attributes) { 436 let newKey = key; 437 if (key.startsWith("data-disable-rich-text-")) { 438 newKey = key.slice("data-disable-rich-text-".length); 439 } 440 newAttributes[newKey] = attributes[key]; 441 } 442 return newAttributes; 443 } 444 function fromFormat({ 445 type, 446 tagName, 447 attributes, 448 unregisteredAttributes, 449 object, 450 boundaryClass, 451 isEditableTree 452 }) { 453 const formatType = getFormatType2(type); 454 let elementAttributes = {}; 455 if (boundaryClass && isEditableTree) { 456 elementAttributes["data-rich-text-format-boundary"] = "true"; 457 } 458 if (!formatType) { 459 if (attributes) { 460 elementAttributes = { ...attributes, ...elementAttributes }; 461 } 462 return { 463 type, 464 attributes: restoreOnAttributes( 465 elementAttributes, 466 isEditableTree 467 ), 468 object 469 }; 470 } 471 elementAttributes = { ...unregisteredAttributes, ...elementAttributes }; 472 for (const name in attributes) { 473 const key = formatType.attributes ? formatType.attributes[name] : false; 474 if (key) { 475 elementAttributes[key] = attributes[name]; 476 } else { 477 elementAttributes[name] = attributes[name]; 478 } 479 } 480 if (formatType.className) { 481 if (elementAttributes.class) { 482 elementAttributes.class = `$formatType.className} $elementAttributes.class}`; 483 } else { 484 elementAttributes.class = formatType.className; 485 } 486 } 487 return { 488 type: tagName || formatType.tagName, 489 object: formatType.object, 490 attributes: restoreOnAttributes(elementAttributes, isEditableTree) 491 }; 492 } 493 function isEqualUntil(a2, b2, index) { 494 do { 495 if (a2[index] !== b2[index]) { 496 return false; 497 } 498 } while (index--); 499 return true; 500 } 501 function toTree({ 502 value, 503 preserveWhiteSpace, 504 createEmpty: createEmpty2, 505 append: append3, 506 getLastChild: getLastChild3, 507 getParent: getParent3, 508 isText: isText3, 509 getText: getText3, 510 remove: remove4, 511 appendText: appendText3, 512 onStartIndex, 513 onEndIndex, 514 isEditableTree, 515 placeholder 516 }) { 517 const { formats, replacements, text, start, end } = value; 518 const formatsLength = formats.length + 1; 519 const tree = createEmpty2(); 520 const activeFormats = getActiveFormats(value); 521 const deepestActiveFormat = activeFormats[activeFormats.length - 1]; 522 let lastCharacterFormats; 523 let lastCharacter; 524 append3(tree, ""); 525 for (let i2 = 0; i2 < formatsLength; i2++) { 526 const character = text.charAt(i2); 527 const shouldInsertPadding = isEditableTree && // Pad the line if the line is empty. 528 (!lastCharacter || // Pad the line if the previous character is a line break, otherwise 529 // the line break won't be visible. 530 lastCharacter === "\n"); 531 const characterFormats = formats[i2]; 532 let pointer = getLastChild3(tree); 533 if (characterFormats) { 534 characterFormats.forEach((format, formatIndex) => { 535 if (pointer && lastCharacterFormats && // Reuse the last element if all formats remain the same. 536 isEqualUntil( 537 characterFormats, 538 lastCharacterFormats, 539 formatIndex 540 )) { 541 pointer = getLastChild3(pointer); 542 return; 543 } 544 const { type, tagName, attributes, unregisteredAttributes } = format; 545 const boundaryClass = isEditableTree && format === deepestActiveFormat; 546 const parent = getParent3(pointer); 547 const newNode = append3( 548 parent, 549 fromFormat({ 550 type, 551 tagName, 552 attributes, 553 unregisteredAttributes, 554 boundaryClass, 555 isEditableTree 556 }) 557 ); 558 if (isText3(pointer) && getText3(pointer).length === 0) { 559 remove4(pointer); 560 } 561 pointer = append3(newNode, ""); 562 }); 563 } 564 if (i2 === 0) { 565 if (onStartIndex && start === 0) { 566 onStartIndex(tree, pointer); 567 } 568 if (onEndIndex && end === 0) { 569 onEndIndex(tree, pointer); 570 } 571 } 572 if (character === OBJECT_REPLACEMENT_CHARACTER) { 573 const replacement = replacements[i2]; 574 if (!replacement) { 575 continue; 576 } 577 const { type, attributes, innerHTML } = replacement; 578 const formatType = getFormatType2(type); 579 if (isEditableTree && type === "#comment") { 580 pointer = append3(getParent3(pointer), { 581 type: "span", 582 attributes: { 583 contenteditable: "false", 584 "data-rich-text-comment": attributes["data-rich-text-comment"] 585 } 586 }); 587 append3( 588 append3(pointer, { type: "span" }), 589 attributes["data-rich-text-comment"].trim() 590 ); 591 } else if (!isEditableTree && type === "script") { 592 pointer = append3( 593 getParent3(pointer), 594 fromFormat({ 595 type: "script", 596 isEditableTree 597 }) 598 ); 599 append3(pointer, { 600 html: decodeURIComponent( 601 attributes["data-rich-text-script"] 602 ) 603 }); 604 } else if (formatType?.contentEditable === false) { 605 if (innerHTML || isEditableTree) { 606 pointer = getParent3(pointer); 607 if (isEditableTree) { 608 const attrs = { 609 contenteditable: "false", 610 "data-rich-text-bogus": true 611 }; 612 if (start === i2 && end === i2 + 1) { 613 attrs["data-rich-text-format-boundary"] = true; 614 } 615 pointer = append3(pointer, { 616 type: "span", 617 attributes: attrs 618 }); 619 if (isEditableTree && i2 + 1 === text.length) { 620 append3(getParent3(pointer), ZWNBSP); 621 } 622 } 623 pointer = append3( 624 pointer, 625 fromFormat({ 626 ...replacement, 627 isEditableTree 628 }) 629 ); 630 if (innerHTML) { 631 append3(pointer, { 632 html: innerHTML 633 }); 634 } 635 } 636 } else { 637 pointer = append3( 638 getParent3(pointer), 639 fromFormat({ 640 ...replacement, 641 object: true, 642 isEditableTree 643 }) 644 ); 645 } 646 pointer = append3(getParent3(pointer), ""); 647 } else if (!preserveWhiteSpace && character === "\n") { 648 pointer = append3(getParent3(pointer), { 649 type: "br", 650 attributes: isEditableTree ? { 651 "data-rich-text-line-break": "true" 652 } : void 0, 653 object: true 654 }); 655 pointer = append3(getParent3(pointer), ""); 656 } else if (!isText3(pointer)) { 657 pointer = append3(getParent3(pointer), character); 658 } else { 659 appendText3(pointer, character); 660 } 661 if (onStartIndex && start === i2 + 1) { 662 onStartIndex(tree, pointer); 663 } 664 if (onEndIndex && end === i2 + 1) { 665 onEndIndex(tree, pointer); 666 } 667 if (shouldInsertPadding && i2 === text.length) { 668 append3(getParent3(pointer), ZWNBSP); 669 if (placeholder && text.length === 0) { 670 append3(getParent3(pointer), { 671 type: "span", 672 attributes: { 673 "data-rich-text-placeholder": placeholder, 674 // Necessary to prevent the placeholder from catching 675 // selection and being editable. 676 style: "pointer-events:none;user-select:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;" 677 } 678 }); 679 } 680 } 681 lastCharacterFormats = characterFormats; 682 lastCharacter = character; 683 } 684 return tree; 685 } 686 687 // packages/rich-text/build-module/to-html-string.mjs 688 function toHTMLString({ value, preserveWhiteSpace }) { 689 const tree = toTree({ 690 value, 691 preserveWhiteSpace, 692 createEmpty, 693 append, 694 getLastChild, 695 getParent, 696 isText, 697 getText, 698 remove, 699 appendText 700 }); 701 return createChildrenHTML(tree.children); 702 } 703 function createEmpty() { 704 return {}; 705 } 706 function getLastChild({ children }) { 707 return children && children[children.length - 1]; 708 } 709 function append(parent, object) { 710 if (typeof object === "string") { 711 object = { text: object }; 712 } 713 object.parent = parent; 714 parent.children = parent.children || []; 715 parent.children.push(object); 716 return object; 717 } 718 function appendText(object, text) { 719 object.text += text; 720 } 721 function getParent({ parent }) { 722 return parent; 723 } 724 function isText({ text }) { 725 return typeof text === "string"; 726 } 727 function getText({ text }) { 728 return text; 729 } 730 function remove(object) { 731 const index = object.parent.children.indexOf(object); 732 if (index !== -1) { 733 object.parent.children.splice(index, 1); 734 } 735 return object; 736 } 737 function createElementHTML({ type, attributes, object, children }) { 738 if (type === "#comment") { 739 return `<!--$attributes["data-rich-text-comment"]}-->`; 740 } 741 let attributeString = ""; 742 for (const key in attributes) { 743 if (!(0, import_escape_html.isValidAttributeName)(key)) { 744 continue; 745 } 746 attributeString += ` $key}="${(0, import_escape_html.escapeAttribute)( 747 attributes[key] 748 )}"`; 749 } 750 if (object) { 751 return `<$type}$attributeString}>`; 752 } 753 return `<$type}$attributeString}>$createChildrenHTML( 754 children 755 )}</$type}>`; 756 } 757 function createChildrenHTML(children = []) { 758 return children.map((child) => { 759 if (child.html !== void 0) { 760 return child.html; 761 } 762 return child.text === void 0 ? createElementHTML(child) : (0, import_escape_html.escapeEditableHTML)(child.text); 763 }).join(""); 764 } 765 766 // packages/rich-text/build-module/get-text-content.mjs 767 function getTextContent({ text }) { 768 return text.replace(OBJECT_REPLACEMENT_CHARACTER, ""); 769 } 770 771 // packages/rich-text/build-module/create.mjs 772 function createEmptyValue() { 773 return { 774 formats: [], 775 replacements: [], 776 text: "" 777 }; 778 } 779 function toFormat({ tagName, attributes }) { 780 let formatType; 781 if (attributes && attributes.class) { 782 formatType = (0, import_data5.select)(store).getFormatTypeForClassName( 783 attributes.class 784 ); 785 if (formatType) { 786 attributes.class = ` $attributes.class} `.replace(` $formatType.className} `, " ").trim(); 787 if (!attributes.class) { 788 delete attributes.class; 789 } 790 } 791 } 792 if (!formatType) { 793 formatType = (0, import_data5.select)(store).getFormatTypeForBareElement(tagName); 794 } 795 if (!formatType) { 796 return attributes ? { type: tagName, attributes } : { type: tagName }; 797 } 798 if (formatType.__experimentalCreatePrepareEditableTree && !formatType.__experimentalCreateOnChangeEditableValue) { 799 return null; 800 } 801 if (!attributes) { 802 return { formatType, type: formatType.name, tagName }; 803 } 804 const registeredAttributes = {}; 805 const unregisteredAttributes = {}; 806 const _attributes = { ...attributes }; 807 for (const key in formatType.attributes) { 808 const name = formatType.attributes[key]; 809 registeredAttributes[key] = _attributes[name]; 810 delete _attributes[name]; 811 if (typeof registeredAttributes[key] === "undefined") { 812 delete registeredAttributes[key]; 813 } 814 } 815 for (const name in _attributes) { 816 unregisteredAttributes[name] = attributes[name]; 817 } 818 if (formatType.contentEditable === false) { 819 delete unregisteredAttributes.contenteditable; 820 } 821 const format = { 822 formatType, 823 type: formatType.name, 824 tagName 825 }; 826 if (Object.keys(registeredAttributes).length) { 827 format.attributes = registeredAttributes; 828 } 829 if (Object.keys(unregisteredAttributes).length) { 830 format.unregisteredAttributes = unregisteredAttributes; 831 } 832 return format; 833 } 834 var RichTextData = class _RichTextData { 835 #value; 836 static empty() { 837 return new _RichTextData(); 838 } 839 static fromPlainText(text) { 840 return new _RichTextData(create({ text })); 841 } 842 static fromHTMLString(html) { 843 return new _RichTextData(create({ html })); 844 } 845 /** 846 * Create a RichTextData instance from an HTML element. 847 * 848 * @param {HTMLElement} htmlElement The HTML element to create the instance from. 849 * @param {{preserveWhiteSpace?: boolean}} options Options. 850 * @return {RichTextData} The RichTextData instance. 851 */ 852 static fromHTMLElement(htmlElement, options = {}) { 853 const { preserveWhiteSpace = false } = options; 854 const element = preserveWhiteSpace ? htmlElement : collapseWhiteSpace(htmlElement); 855 const richTextData = new _RichTextData(create({ element })); 856 Object.defineProperty(richTextData, "originalHTML", { 857 value: htmlElement.innerHTML 858 }); 859 return richTextData; 860 } 861 constructor(init = createEmptyValue()) { 862 this.#value = init; 863 } 864 toPlainText() { 865 return getTextContent(this.#value); 866 } 867 // We could expose `toHTMLElement` at some point as well, but we'd only use 868 // it internally. 869 /** 870 * Convert the rich text value to an HTML string. 871 * 872 * @param {{preserveWhiteSpace?: boolean}} options Options. 873 * @return {string} The HTML string. 874 */ 875 toHTMLString({ preserveWhiteSpace } = {}) { 876 return this.originalHTML || toHTMLString({ value: this.#value, preserveWhiteSpace }); 877 } 878 valueOf() { 879 return this.toHTMLString(); 880 } 881 toString() { 882 return this.toHTMLString(); 883 } 884 toJSON() { 885 return this.toHTMLString(); 886 } 887 get length() { 888 return this.text.length; 889 } 890 get formats() { 891 return this.#value.formats; 892 } 893 get replacements() { 894 return this.#value.replacements; 895 } 896 get text() { 897 return this.#value.text; 898 } 899 }; 900 for (const name of Object.getOwnPropertyNames(String.prototype)) { 901 if (RichTextData.prototype.hasOwnProperty(name)) { 902 continue; 903 } 904 Object.defineProperty(RichTextData.prototype, name, { 905 value(...args) { 906 return this.toHTMLString()[name](...args); 907 } 908 }); 909 } 910 function create({ 911 element, 912 text, 913 html, 914 range, 915 __unstableIsEditableTree: isEditableTree 916 } = {}) { 917 if (html instanceof RichTextData) { 918 return { 919 text: html.text, 920 formats: html.formats, 921 replacements: html.replacements 922 }; 923 } 924 if (typeof text === "string" && text.length > 0) { 925 return { 926 formats: Array(text.length), 927 replacements: Array(text.length), 928 text 929 }; 930 } 931 if (typeof html === "string" && html.length > 0) { 932 element = createElement(document, html); 933 } 934 if (typeof element !== "object") { 935 return createEmptyValue(); 936 } 937 return createFromElement({ 938 element, 939 range, 940 isEditableTree 941 }); 942 } 943 function accumulateSelection(accumulator, node, range, value) { 944 if (!range) { 945 return; 946 } 947 const { parentNode } = node; 948 const { startContainer, startOffset, endContainer, endOffset } = range; 949 const currentLength = accumulator.text.length; 950 if (value.start !== void 0) { 951 accumulator.start = currentLength + value.start; 952 } else if (node === startContainer && node.nodeType === node.TEXT_NODE) { 953 accumulator.start = currentLength + startOffset; 954 } else if (parentNode === startContainer && node === startContainer.childNodes[startOffset]) { 955 accumulator.start = currentLength; 956 } else if (parentNode === startContainer && node === startContainer.childNodes[startOffset - 1]) { 957 accumulator.start = currentLength + value.text.length; 958 } else if (node === startContainer) { 959 accumulator.start = currentLength; 960 } 961 if (value.end !== void 0) { 962 accumulator.end = currentLength + value.end; 963 } else if (node === endContainer && node.nodeType === node.TEXT_NODE) { 964 accumulator.end = currentLength + endOffset; 965 } else if (parentNode === endContainer && node === endContainer.childNodes[endOffset - 1]) { 966 accumulator.end = currentLength + value.text.length; 967 } else if (parentNode === endContainer && node === endContainer.childNodes[endOffset]) { 968 accumulator.end = currentLength; 969 } else if (node === endContainer) { 970 accumulator.end = currentLength + endOffset; 971 } 972 } 973 function filterRange(node, range, filter) { 974 if (!range) { 975 return; 976 } 977 const { startContainer, endContainer } = range; 978 let { startOffset, endOffset } = range; 979 if (node === startContainer) { 980 startOffset = filter(node.nodeValue.slice(0, startOffset)).length; 981 } 982 if (node === endContainer) { 983 endOffset = filter(node.nodeValue.slice(0, endOffset)).length; 984 } 985 return { startContainer, startOffset, endContainer, endOffset }; 986 } 987 function collapseWhiteSpace(element, isRoot = true, hasPrecedingSpace = false, hasTrailingSpace = false) { 988 const clone = element.cloneNode(true); 989 clone.normalize(); 990 Array.from(clone.childNodes).forEach((node, i2, nodes) => { 991 if (node.nodeType === node.TEXT_NODE) { 992 let newNodeValue = node.nodeValue; 993 if (/[\n\t\r\f]/.test(newNodeValue)) { 994 newNodeValue = newNodeValue.replace(/[\n\t\r\f]+/g, " "); 995 } 996 if (newNodeValue.indexOf(" ") !== -1) { 997 newNodeValue = newNodeValue.replace(/ {2,}/g, " "); 998 } 999 if (i2 === 0 && newNodeValue.startsWith(" ") && (isRoot || hasPrecedingSpace)) { 1000 newNodeValue = newNodeValue.slice(1); 1001 } 1002 if (i2 === nodes.length - 1 && newNodeValue.endsWith(" ") && (isRoot || hasTrailingSpace)) { 1003 newNodeValue = newNodeValue.slice(0, -1); 1004 } 1005 node.nodeValue = newNodeValue; 1006 } else if (node.nodeType === node.ELEMENT_NODE) { 1007 const { previousSibling, nextSibling } = node; 1008 const prevHasSpace = previousSibling?.textContent.endsWith(" "); 1009 const nextHasSpace = nextSibling?.textContent.startsWith(" "); 1010 node.replaceWith( 1011 collapseWhiteSpace( 1012 node, 1013 false, 1014 previousSibling ? prevHasSpace : isRoot || hasPrecedingSpace, 1015 nextSibling ? nextHasSpace : isRoot || hasTrailingSpace 1016 ) 1017 ); 1018 } 1019 }); 1020 return clone; 1021 } 1022 var CARRIAGE_RETURN = "\r"; 1023 function removeReservedCharacters(string) { 1024 return string.replace( 1025 new RegExp( 1026 `[$ZWNBSP}$OBJECT_REPLACEMENT_CHARACTER}$CARRIAGE_RETURN}]`, 1027 "gu" 1028 ), 1029 "" 1030 ); 1031 } 1032 function createFromElement({ element, range, isEditableTree }) { 1033 const accumulator = createEmptyValue(); 1034 if (!element) { 1035 return accumulator; 1036 } 1037 if (!element.hasChildNodes()) { 1038 accumulateSelection(accumulator, element, range, createEmptyValue()); 1039 return accumulator; 1040 } 1041 const length = element.childNodes.length; 1042 for (let index = 0; index < length; index++) { 1043 const node = element.childNodes[index]; 1044 const tagName = node.nodeName.toLowerCase(); 1045 if (node.nodeType === node.TEXT_NODE) { 1046 const text = removeReservedCharacters(node.nodeValue); 1047 range = filterRange(node, range, removeReservedCharacters); 1048 accumulateSelection(accumulator, node, range, { text }); 1049 accumulator.formats.length += text.length; 1050 accumulator.replacements.length += text.length; 1051 accumulator.text += text; 1052 continue; 1053 } 1054 if (node.nodeType === node.COMMENT_NODE || node.nodeType === node.ELEMENT_NODE && node.tagName === "SPAN" && node.hasAttribute("data-rich-text-comment")) { 1055 const value2 = { 1056 formats: [,], 1057 replacements: [ 1058 { 1059 type: "#comment", 1060 attributes: { 1061 "data-rich-text-comment": node.nodeType === node.COMMENT_NODE ? node.nodeValue : node.getAttribute( 1062 "data-rich-text-comment" 1063 ) 1064 } 1065 } 1066 ], 1067 text: OBJECT_REPLACEMENT_CHARACTER 1068 }; 1069 accumulateSelection(accumulator, node, range, value2); 1070 mergePair(accumulator, value2); 1071 continue; 1072 } 1073 if (node.nodeType !== node.ELEMENT_NODE) { 1074 continue; 1075 } 1076 if (isEditableTree && // Ignore any line breaks that are not inserted by us. 1077 tagName === "br" && !node.getAttribute("data-rich-text-line-break")) { 1078 accumulateSelection(accumulator, node, range, createEmptyValue()); 1079 continue; 1080 } 1081 if (tagName === "script") { 1082 const value2 = { 1083 formats: [,], 1084 replacements: [ 1085 { 1086 type: tagName, 1087 attributes: { 1088 "data-rich-text-script": node.getAttribute("data-rich-text-script") || encodeURIComponent(node.innerHTML) 1089 } 1090 } 1091 ], 1092 text: OBJECT_REPLACEMENT_CHARACTER 1093 }; 1094 accumulateSelection(accumulator, node, range, value2); 1095 mergePair(accumulator, value2); 1096 continue; 1097 } 1098 if (tagName === "br") { 1099 accumulateSelection(accumulator, node, range, createEmptyValue()); 1100 mergePair(accumulator, create({ text: "\n" })); 1101 continue; 1102 } 1103 const format = toFormat({ 1104 tagName, 1105 attributes: getAttributes({ element: node }) 1106 }); 1107 if (format?.formatType?.contentEditable === false) { 1108 delete format.formatType; 1109 accumulateSelection(accumulator, node, range, createEmptyValue()); 1110 mergePair(accumulator, { 1111 formats: [,], 1112 replacements: [ 1113 { 1114 ...format, 1115 innerHTML: node.innerHTML 1116 } 1117 ], 1118 text: OBJECT_REPLACEMENT_CHARACTER 1119 }); 1120 continue; 1121 } 1122 if (format) { 1123 delete format.formatType; 1124 } 1125 const value = createFromElement({ 1126 element: node, 1127 range, 1128 isEditableTree 1129 }); 1130 accumulateSelection(accumulator, node, range, value); 1131 if (!format || node.getAttribute("data-rich-text-placeholder") || node.getAttribute("data-rich-text-bogus")) { 1132 mergePair(accumulator, value); 1133 } else if (value.text.length === 0) { 1134 if (format.attributes) { 1135 mergePair(accumulator, { 1136 formats: [,], 1137 replacements: [format], 1138 text: OBJECT_REPLACEMENT_CHARACTER 1139 }); 1140 } 1141 } else { 1142 let mergeFormats2 = function(formats) { 1143 if (mergeFormats2.formats === formats) { 1144 return mergeFormats2.newFormats; 1145 } 1146 const newFormats = formats ? [format, ...formats] : [format]; 1147 mergeFormats2.formats = formats; 1148 mergeFormats2.newFormats = newFormats; 1149 return newFormats; 1150 }; 1151 var mergeFormats = mergeFormats2; 1152 mergeFormats2.newFormats = [format]; 1153 mergePair(accumulator, { 1154 ...value, 1155 formats: Array.from(value.formats, mergeFormats2) 1156 }); 1157 } 1158 } 1159 return accumulator; 1160 } 1161 function getAttributes({ element }) { 1162 if (!element.hasAttributes()) { 1163 return; 1164 } 1165 const length = element.attributes.length; 1166 let accumulator; 1167 for (let i2 = 0; i2 < length; i2++) { 1168 const { name, value } = element.attributes[i2]; 1169 if (name.indexOf("data-rich-text-") === 0) { 1170 continue; 1171 } 1172 const safeName = /^on/i.test(name) ? "data-disable-rich-text-" + name : name; 1173 accumulator = accumulator || {}; 1174 accumulator[safeName] = value; 1175 } 1176 return accumulator; 1177 } 1178 1179 // packages/rich-text/build-module/concat.mjs 1180 function mergePair(a2, b2) { 1181 a2.formats = a2.formats.concat(b2.formats); 1182 a2.replacements = a2.replacements.concat(b2.replacements); 1183 a2.text += b2.text; 1184 return a2; 1185 } 1186 function concat(...values) { 1187 return normaliseFormats(values.reduce(mergePair, create())); 1188 } 1189 1190 // packages/rich-text/build-module/get-active-format.mjs 1191 function getActiveFormat(value, formatType) { 1192 return getActiveFormats(value).find( 1193 ({ type }) => type === formatType 1194 ); 1195 } 1196 1197 // packages/rich-text/build-module/get-active-object.mjs 1198 function getActiveObject({ start, end, replacements, text }) { 1199 if (start + 1 !== end || text[start] !== OBJECT_REPLACEMENT_CHARACTER) { 1200 return; 1201 } 1202 return replacements[start]; 1203 } 1204 1205 // packages/rich-text/build-module/is-collapsed.mjs 1206 function isCollapsed({ 1207 start, 1208 end 1209 }) { 1210 if (start === void 0 || end === void 0) { 1211 return; 1212 } 1213 return start === end; 1214 } 1215 1216 // packages/rich-text/build-module/is-empty.mjs 1217 function isEmpty({ text }) { 1218 return text.length === 0; 1219 } 1220 1221 // packages/rich-text/build-module/join.mjs 1222 function join(values, separator = "") { 1223 if (typeof separator === "string") { 1224 separator = create({ text: separator }); 1225 } 1226 return normaliseFormats( 1227 values.reduce((accumulator, { formats, replacements, text }) => ({ 1228 formats: accumulator.formats.concat(separator.formats, formats), 1229 replacements: accumulator.replacements.concat( 1230 separator.replacements, 1231 replacements 1232 ), 1233 text: accumulator.text + separator.text + text 1234 })) 1235 ); 1236 } 1237 1238 // packages/rich-text/build-module/register-format-type.mjs 1239 var import_data6 = __toESM(require_data(), 1); 1240 function registerFormatType(name, settings) { 1241 settings = { 1242 name, 1243 ...settings 1244 }; 1245 if (typeof settings.name !== "string") { 1246 window.console.error("Format names must be strings."); 1247 return; 1248 } 1249 if (!/^[a-z][a-z0-9-]*\/[a-z][a-z0-9-]*$/.test(settings.name)) { 1250 window.console.error( 1251 "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" 1252 ); 1253 return; 1254 } 1255 if ((0, import_data6.select)(store).getFormatType(settings.name)) { 1256 window.console.error( 1257 'Format "' + settings.name + '" is already registered.' 1258 ); 1259 return; 1260 } 1261 if (typeof settings.tagName !== "string" || settings.tagName === "") { 1262 window.console.error("Format tag names must be a string."); 1263 return; 1264 } 1265 if ((typeof settings.className !== "string" || settings.className === "") && settings.className !== null) { 1266 window.console.error( 1267 "Format class names must be a string, or null to handle bare elements." 1268 ); 1269 return; 1270 } 1271 if (!/^[_a-zA-Z]+[a-zA-Z0-9_-]*$/.test(settings.className)) { 1272 window.console.error( 1273 "A class name must begin with a letter, followed by any number of hyphens, underscores, letters, or numbers." 1274 ); 1275 return; 1276 } 1277 if (settings.className === null) { 1278 const formatTypeForBareElement = (0, import_data6.select)( 1279 store 1280 ).getFormatTypeForBareElement(settings.tagName); 1281 if (formatTypeForBareElement && formatTypeForBareElement.name !== "core/unknown") { 1282 window.console.error( 1283 `Format "$formatTypeForBareElement.name}" is already registered to handle bare tag name "$settings.tagName}".` 1284 ); 1285 return; 1286 } 1287 } else { 1288 const formatTypeForClassName = (0, import_data6.select)( 1289 store 1290 ).getFormatTypeForClassName(settings.className); 1291 if (formatTypeForClassName) { 1292 window.console.error( 1293 `Format "$formatTypeForClassName.name}" is already registered to handle class name "$settings.className}".` 1294 ); 1295 return; 1296 } 1297 } 1298 if (!("title" in settings) || settings.title === "") { 1299 window.console.error( 1300 'The format "' + settings.name + '" must have a title.' 1301 ); 1302 return; 1303 } 1304 if ("keywords" in settings && settings.keywords.length > 3) { 1305 window.console.error( 1306 'The format "' + settings.name + '" can have a maximum of 3 keywords.' 1307 ); 1308 return; 1309 } 1310 if (typeof settings.title !== "string") { 1311 window.console.error("Format titles must be strings."); 1312 return; 1313 } 1314 (0, import_data6.dispatch)(store).addFormatTypes(settings); 1315 return settings; 1316 } 1317 1318 // packages/rich-text/build-module/remove-format.mjs 1319 function removeFormat(value, formatType, startIndex = value.start, endIndex = value.end) { 1320 const { formats, activeFormats } = value; 1321 const newFormats = formats.slice(); 1322 if (startIndex === endIndex) { 1323 const format = newFormats[startIndex]?.find( 1324 ({ type }) => type === formatType 1325 ); 1326 if (format) { 1327 while (newFormats[startIndex]?.find( 1328 (newFormat) => newFormat === format 1329 )) { 1330 filterFormats(newFormats, startIndex, formatType); 1331 startIndex--; 1332 } 1333 endIndex++; 1334 while (newFormats[endIndex]?.find( 1335 (newFormat) => newFormat === format 1336 )) { 1337 filterFormats(newFormats, endIndex, formatType); 1338 endIndex++; 1339 } 1340 } 1341 } else { 1342 for (let i2 = startIndex; i2 < endIndex; i2++) { 1343 if (newFormats[i2]) { 1344 filterFormats(newFormats, i2, formatType); 1345 } 1346 } 1347 } 1348 return normaliseFormats({ 1349 ...value, 1350 formats: newFormats, 1351 activeFormats: activeFormats?.filter(({ type }) => type !== formatType) || [] 1352 }); 1353 } 1354 function filterFormats(formats, index, formatType) { 1355 const newFormats = formats[index].filter( 1356 ({ type }) => type !== formatType 1357 ); 1358 if (newFormats.length) { 1359 formats[index] = newFormats; 1360 } else { 1361 delete formats[index]; 1362 } 1363 } 1364 1365 // packages/rich-text/build-module/insert.mjs 1366 function insert(value, valueToInsert, startIndex = value.start, endIndex = value.end) { 1367 const { formats, replacements, text } = value; 1368 if (typeof valueToInsert === "string") { 1369 valueToInsert = create({ text: valueToInsert }); 1370 } 1371 const index = startIndex + valueToInsert.text.length; 1372 return normaliseFormats({ 1373 formats: formats.slice(0, startIndex).concat(valueToInsert.formats, formats.slice(endIndex)), 1374 replacements: replacements.slice(0, startIndex).concat( 1375 valueToInsert.replacements, 1376 replacements.slice(endIndex) 1377 ), 1378 text: text.slice(0, startIndex) + valueToInsert.text + text.slice(endIndex), 1379 start: index, 1380 end: index 1381 }); 1382 } 1383 1384 // packages/rich-text/build-module/remove.mjs 1385 function remove2(value, startIndex, endIndex) { 1386 return insert(value, create(), startIndex, endIndex); 1387 } 1388 1389 // packages/rich-text/build-module/replace.mjs 1390 function replace2({ formats, replacements, text, start, end }, pattern, replacement) { 1391 text = text.replace(pattern, (match, ...rest) => { 1392 const offset = rest[rest.length - 2]; 1393 let newText = replacement; 1394 let newFormats; 1395 let newReplacements; 1396 if (typeof newText === "function") { 1397 newText = replacement(match, ...rest); 1398 } 1399 if (typeof newText === "object") { 1400 newFormats = newText.formats; 1401 newReplacements = newText.replacements; 1402 newText = newText.text; 1403 } else { 1404 newFormats = Array(newText.length); 1405 newReplacements = Array(newText.length); 1406 if (formats[offset]) { 1407 newFormats = newFormats.fill(formats[offset]); 1408 } 1409 } 1410 formats = formats.slice(0, offset).concat(newFormats, formats.slice(offset + match.length)); 1411 replacements = replacements.slice(0, offset).concat( 1412 newReplacements, 1413 replacements.slice(offset + match.length) 1414 ); 1415 if (start) { 1416 start = end = offset + newText.length; 1417 } 1418 return newText; 1419 }); 1420 return normaliseFormats({ formats, replacements, text, start, end }); 1421 } 1422 1423 // packages/rich-text/build-module/insert-object.mjs 1424 function insertObject(value, formatToInsert, startIndex, endIndex) { 1425 const valueToInsert = { 1426 formats: [,], 1427 replacements: [formatToInsert], 1428 text: OBJECT_REPLACEMENT_CHARACTER 1429 }; 1430 return insert(value, valueToInsert, startIndex, endIndex); 1431 } 1432 1433 // packages/rich-text/build-module/slice.mjs 1434 function slice(value, startIndex = value.start, endIndex = value.end) { 1435 const { formats, replacements, text } = value; 1436 if (startIndex === void 0 || endIndex === void 0) { 1437 return { ...value }; 1438 } 1439 return { 1440 formats: formats.slice(startIndex, endIndex), 1441 replacements: replacements.slice(startIndex, endIndex), 1442 text: text.slice(startIndex, endIndex) 1443 }; 1444 } 1445 1446 // packages/rich-text/build-module/split.mjs 1447 function split({ formats, replacements, text, start, end }, string) { 1448 if (typeof string !== "string") { 1449 return splitAtSelection(...arguments); 1450 } 1451 let nextStart = 0; 1452 return text.split(string).map((substring) => { 1453 const startIndex = nextStart; 1454 const value = { 1455 formats: formats.slice(startIndex, startIndex + substring.length), 1456 replacements: replacements.slice( 1457 startIndex, 1458 startIndex + substring.length 1459 ), 1460 text: substring 1461 }; 1462 nextStart += string.length + substring.length; 1463 if (start !== void 0 && end !== void 0) { 1464 if (start >= startIndex && start < nextStart) { 1465 value.start = start - startIndex; 1466 } else if (start < startIndex && end > startIndex) { 1467 value.start = 0; 1468 } 1469 if (end >= startIndex && end < nextStart) { 1470 value.end = end - startIndex; 1471 } else if (start < nextStart && end > nextStart) { 1472 value.end = substring.length; 1473 } 1474 } 1475 return value; 1476 }); 1477 } 1478 function splitAtSelection({ formats, replacements, text, start, end }, startIndex = start, endIndex = end) { 1479 if (start === void 0 || end === void 0) { 1480 return; 1481 } 1482 const before = { 1483 formats: formats.slice(0, startIndex), 1484 replacements: replacements.slice(0, startIndex), 1485 text: text.slice(0, startIndex) 1486 }; 1487 const after = { 1488 formats: formats.slice(endIndex), 1489 replacements: replacements.slice(endIndex), 1490 text: text.slice(endIndex), 1491 start: 0, 1492 end: 0 1493 }; 1494 return [before, after]; 1495 } 1496 1497 // packages/rich-text/build-module/is-range-equal.mjs 1498 function isRangeEqual(a2, b2) { 1499 return a2 === b2 || a2 && b2 && a2.startContainer === b2.startContainer && a2.startOffset === b2.startOffset && a2.endContainer === b2.endContainer && a2.endOffset === b2.endOffset; 1500 } 1501 1502 // packages/rich-text/build-module/to-dom.mjs 1503 var MATHML_NAMESPACE = "http://www.w3.org/1998/Math/MathML"; 1504 function createPathToNode(node, rootNode, path) { 1505 const parentNode = node.parentNode; 1506 let i2 = 0; 1507 while (node = node.previousSibling) { 1508 i2++; 1509 } 1510 path = [i2, ...path]; 1511 if (parentNode !== rootNode) { 1512 path = createPathToNode(parentNode, rootNode, path); 1513 } 1514 return path; 1515 } 1516 function getNodeByPath(node, path) { 1517 path = [...path]; 1518 while (node && path.length > 1) { 1519 node = node.childNodes[path.shift()]; 1520 } 1521 return { 1522 node, 1523 offset: path[0] 1524 }; 1525 } 1526 function append2(element, child) { 1527 if (child.html !== void 0) { 1528 return element.innerHTML += child.html; 1529 } 1530 if (typeof child === "string") { 1531 child = element.ownerDocument.createTextNode(child); 1532 } 1533 const { type, attributes } = child; 1534 if (type) { 1535 if (type === "#comment") { 1536 child = element.ownerDocument.createComment( 1537 attributes["data-rich-text-comment"] 1538 ); 1539 } else { 1540 const parentNamespace = element.namespaceURI; 1541 if (type === "math") { 1542 child = element.ownerDocument.createElementNS( 1543 MATHML_NAMESPACE, 1544 type 1545 ); 1546 } else if (parentNamespace === MATHML_NAMESPACE) { 1547 if (element.tagName === "MTEXT") { 1548 child = element.ownerDocument.createElement(type); 1549 } else { 1550 child = element.ownerDocument.createElementNS( 1551 MATHML_NAMESPACE, 1552 type 1553 ); 1554 } 1555 } else { 1556 child = element.ownerDocument.createElement(type); 1557 } 1558 for (const key in attributes) { 1559 child.setAttribute(key, attributes[key]); 1560 } 1561 } 1562 } 1563 return element.appendChild(child); 1564 } 1565 function appendText2(node, text) { 1566 node.appendData(text); 1567 } 1568 function getLastChild2({ lastChild }) { 1569 return lastChild; 1570 } 1571 function getParent2({ parentNode }) { 1572 return parentNode; 1573 } 1574 function isText2(node) { 1575 return node.nodeType === node.TEXT_NODE; 1576 } 1577 function getText2({ nodeValue }) { 1578 return nodeValue; 1579 } 1580 function remove3(node) { 1581 return node.parentNode.removeChild(node); 1582 } 1583 function toDom({ 1584 value, 1585 prepareEditableTree, 1586 isEditableTree = true, 1587 placeholder, 1588 doc = document 1589 }) { 1590 let startPath = []; 1591 let endPath = []; 1592 if (prepareEditableTree) { 1593 value = { 1594 ...value, 1595 formats: prepareEditableTree(value) 1596 }; 1597 } 1598 const createEmpty2 = () => createElement(doc, ""); 1599 const tree = toTree({ 1600 value, 1601 createEmpty: createEmpty2, 1602 append: append2, 1603 getLastChild: getLastChild2, 1604 getParent: getParent2, 1605 isText: isText2, 1606 getText: getText2, 1607 remove: remove3, 1608 appendText: appendText2, 1609 onStartIndex(body, pointer) { 1610 startPath = createPathToNode(pointer, body, [ 1611 pointer.nodeValue.length 1612 ]); 1613 }, 1614 onEndIndex(body, pointer) { 1615 endPath = createPathToNode(pointer, body, [ 1616 pointer.nodeValue.length 1617 ]); 1618 }, 1619 isEditableTree, 1620 placeholder 1621 }); 1622 return { 1623 body: tree, 1624 selection: { startPath, endPath } 1625 }; 1626 } 1627 function apply({ 1628 value, 1629 current, 1630 prepareEditableTree, 1631 __unstableDomOnly, 1632 placeholder 1633 }) { 1634 const { body, selection } = toDom({ 1635 value, 1636 prepareEditableTree, 1637 placeholder, 1638 doc: current.ownerDocument 1639 }); 1640 applyValue(body, current); 1641 if (value.start !== void 0 && !__unstableDomOnly) { 1642 applySelection(selection, current); 1643 } 1644 } 1645 function applyValue(future, current) { 1646 let i2 = 0; 1647 let futureChild; 1648 while (futureChild = future.firstChild) { 1649 const currentChild = current.childNodes[i2]; 1650 if (!currentChild) { 1651 current.appendChild(futureChild); 1652 } else if (!currentChild.isEqualNode(futureChild)) { 1653 if (currentChild.nodeName !== futureChild.nodeName || currentChild.nodeType === currentChild.TEXT_NODE && currentChild.data !== futureChild.data) { 1654 current.replaceChild(futureChild, currentChild); 1655 } else { 1656 const currentAttributes = currentChild.attributes; 1657 const futureAttributes = futureChild.attributes; 1658 if (currentAttributes) { 1659 let ii = currentAttributes.length; 1660 while (ii--) { 1661 const { name } = currentAttributes[ii]; 1662 if (!futureChild.getAttribute(name)) { 1663 currentChild.removeAttribute(name); 1664 } 1665 } 1666 } 1667 if (futureAttributes) { 1668 for (let ii = 0; ii < futureAttributes.length; ii++) { 1669 const { name, value } = futureAttributes[ii]; 1670 if (currentChild.getAttribute(name) !== value) { 1671 currentChild.setAttribute(name, value); 1672 } 1673 } 1674 } 1675 applyValue(futureChild, currentChild); 1676 future.removeChild(futureChild); 1677 } 1678 } else { 1679 future.removeChild(futureChild); 1680 } 1681 i2++; 1682 } 1683 while (current.childNodes[i2]) { 1684 current.removeChild(current.childNodes[i2]); 1685 } 1686 } 1687 function applySelection({ startPath, endPath }, current) { 1688 const { node: startContainer, offset: startOffset } = getNodeByPath( 1689 current, 1690 startPath 1691 ); 1692 const { node: endContainer, offset: endOffset } = getNodeByPath( 1693 current, 1694 endPath 1695 ); 1696 const { ownerDocument } = current; 1697 const { defaultView } = ownerDocument; 1698 const selection = defaultView.getSelection(); 1699 const range = ownerDocument.createRange(); 1700 range.setStart(startContainer, startOffset); 1701 range.setEnd(endContainer, endOffset); 1702 const { activeElement } = ownerDocument; 1703 if (selection.rangeCount > 0) { 1704 if (isRangeEqual(range, selection.getRangeAt(0))) { 1705 return; 1706 } 1707 selection.removeAllRanges(); 1708 } 1709 selection.addRange(range); 1710 if (activeElement !== ownerDocument.activeElement) { 1711 if (activeElement instanceof defaultView.HTMLElement) { 1712 activeElement.focus(); 1713 } 1714 } 1715 } 1716 1717 // packages/rich-text/build-module/toggle-format.mjs 1718 var import_a11y = __toESM(require_a11y(), 1); 1719 var import_i18n = __toESM(require_i18n(), 1); 1720 function toggleFormat(value, format) { 1721 if (getActiveFormat(value, format.type)) { 1722 if (format.title) { 1723 (0, import_a11y.speak)((0, import_i18n.sprintf)((0, import_i18n.__)("%s removed."), format.title), "assertive"); 1724 } 1725 return removeFormat(value, format.type); 1726 } 1727 if (format.title) { 1728 (0, import_a11y.speak)((0, import_i18n.sprintf)((0, import_i18n.__)("%s applied."), format.title), "assertive"); 1729 } 1730 return applyFormat(value, format); 1731 } 1732 1733 // packages/rich-text/build-module/unregister-format-type.mjs 1734 var import_data7 = __toESM(require_data(), 1); 1735 function unregisterFormatType(name) { 1736 const oldFormat = (0, import_data7.select)(store).getFormatType(name); 1737 if (!oldFormat) { 1738 window.console.error(`Format $name} is not registered.`); 1739 return; 1740 } 1741 (0, import_data7.dispatch)(store).removeFormatTypes(name); 1742 return oldFormat; 1743 } 1744 1745 // packages/rich-text/build-module/lock-unlock.mjs 1746 var import_private_apis = __toESM(require_private_apis(), 1); 1747 var { lock, unlock } = (0, import_private_apis.__dangerousOptInToUnstableAPIsOnlyForCoreModules)( 1748 "I acknowledge private features are not for use in themes or plugins and doing so will break in the next version of WordPress.", 1749 "@wordpress/rich-text" 1750 ); 1751 1752 // packages/rich-text/build-module/hook/index.mjs 1753 var import_element5 = __toESM(require_element(), 1); 1754 var import_compose8 = __toESM(require_compose(), 1); 1755 var import_data9 = __toESM(require_data(), 1); 1756 var import_deprecated = __toESM(require_deprecated(), 1); 1757 1758 // packages/rich-text/build-module/owns-selection.mjs 1759 function ownsSelection(element) { 1760 const { ownerDocument } = element; 1761 const { activeElement } = ownerDocument; 1762 if (activeElement === element) { 1763 return true; 1764 } 1765 if (!activeElement || activeElement.contentEditable !== "true" || element.contentEditable !== "true" || !activeElement.contains(element)) { 1766 return false; 1767 } 1768 const selection = ownerDocument.defaultView.getSelection(); 1769 const { anchorNode, focusNode } = selection; 1770 return !!anchorNode && !!focusNode && element.contains(anchorNode) && element.contains(focusNode); 1771 } 1772 1773 // packages/rich-text/build-module/hook/use-default-style.mjs 1774 var import_element = __toESM(require_element(), 1); 1775 var whiteSpace = "pre-wrap"; 1776 function useDefaultStyle() { 1777 return (0, import_element.useCallback)((element) => { 1778 if (!element) { 1779 return; 1780 } 1781 element.style.whiteSpace = element.style.whiteSpace || whiteSpace; 1782 }, []); 1783 } 1784 1785 // node_modules/colord/index.mjs 1786 var r = { grad: 0.9, turn: 360, rad: 360 / (2 * Math.PI) }; 1787 var t = function(r2) { 1788 return "string" == typeof r2 ? r2.length > 0 : "number" == typeof r2; 1789 }; 1790 var n = function(r2, t2, n2) { 1791 return void 0 === t2 && (t2 = 0), void 0 === n2 && (n2 = Math.pow(10, t2)), Math.round(n2 * r2) / n2 + 0; 1792 }; 1793 var e = function(r2, t2, n2) { 1794 return void 0 === t2 && (t2 = 0), void 0 === n2 && (n2 = 1), r2 > n2 ? n2 : r2 > t2 ? r2 : t2; 1795 }; 1796 var u = function(r2) { 1797 return (r2 = isFinite(r2) ? r2 % 360 : 0) > 0 ? r2 : r2 + 360; 1798 }; 1799 var a = function(r2) { 1800 return { r: e(r2.r, 0, 255), g: e(r2.g, 0, 255), b: e(r2.b, 0, 255), a: e(r2.a) }; 1801 }; 1802 var o = function(r2) { 1803 return { r: n(r2.r), g: n(r2.g), b: n(r2.b), a: n(r2.a, 3) }; 1804 }; 1805 var i = /^#([0-9a-f]{3,8})$/i; 1806 var s = function(r2) { 1807 var t2 = r2.toString(16); 1808 return t2.length < 2 ? "0" + t2 : t2; 1809 }; 1810 var h = function(r2) { 1811 var t2 = r2.r, n2 = r2.g, e2 = r2.b, u2 = r2.a, a2 = Math.max(t2, n2, e2), o2 = a2 - Math.min(t2, n2, e2), i2 = o2 ? a2 === t2 ? (n2 - e2) / o2 : a2 === n2 ? 2 + (e2 - t2) / o2 : 4 + (t2 - n2) / o2 : 0; 1812 return { h: 60 * (i2 < 0 ? i2 + 6 : i2), s: a2 ? o2 / a2 * 100 : 0, v: a2 / 255 * 100, a: u2 }; 1813 }; 1814 var b = function(r2) { 1815 var t2 = r2.h, n2 = r2.s, e2 = r2.v, u2 = r2.a; 1816 t2 = t2 / 360 * 6, n2 /= 100, e2 /= 100; 1817 var a2 = Math.floor(t2), o2 = e2 * (1 - n2), i2 = e2 * (1 - (t2 - a2) * n2), s2 = e2 * (1 - (1 - t2 + a2) * n2), h2 = a2 % 6; 1818 return { r: 255 * [e2, i2, o2, o2, s2, e2][h2], g: 255 * [s2, e2, e2, i2, o2, o2][h2], b: 255 * [o2, o2, s2, e2, e2, i2][h2], a: u2 }; 1819 }; 1820 var g = function(r2) { 1821 return { h: u(r2.h), s: e(r2.s, 0, 100), l: e(r2.l, 0, 100), a: e(r2.a) }; 1822 }; 1823 var d = function(r2) { 1824 return { h: n(r2.h), s: n(r2.s), l: n(r2.l), a: n(r2.a, 3) }; 1825 }; 1826 var f = function(r2) { 1827 return b((n2 = (t2 = r2).s, { h: t2.h, s: (n2 *= ((e2 = t2.l) < 50 ? e2 : 100 - e2) / 100) > 0 ? 2 * n2 / (e2 + n2) * 100 : 0, v: e2 + n2, a: t2.a })); 1828 var t2, n2, e2; 1829 }; 1830 var c = function(r2) { 1831 return { h: (t2 = h(r2)).h, s: (u2 = (200 - (n2 = t2.s)) * (e2 = t2.v) / 100) > 0 && u2 < 200 ? n2 * e2 / 100 / (u2 <= 100 ? u2 : 200 - u2) * 100 : 0, l: u2 / 2, a: t2.a }; 1832 var t2, n2, e2, u2; 1833 }; 1834 var l = /^hsla?\(\s*([+-]?\d*\.?\d+)(deg|rad|grad|turn)?\s*,\s*([+-]?\d*\.?\d+)%\s*,\s*([+-]?\d*\.?\d+)%\s*(?:,\s*([+-]?\d*\.?\d+)(%)?\s*)?\)$/i; 1835 var p = /^hsla?\(\s*([+-]?\d*\.?\d+)(deg|rad|grad|turn)?\s+([+-]?\d*\.?\d+)%\s+([+-]?\d*\.?\d+)%\s*(?:\/\s*([+-]?\d*\.?\d+)(%)?\s*)?\)$/i; 1836 var v = /^rgba?\(\s*([+-]?\d*\.?\d+)(%)?\s*,\s*([+-]?\d*\.?\d+)(%)?\s*,\s*([+-]?\d*\.?\d+)(%)?\s*(?:,\s*([+-]?\d*\.?\d+)(%)?\s*)?\)$/i; 1837 var m = /^rgba?\(\s*([+-]?\d*\.?\d+)(%)?\s+([+-]?\d*\.?\d+)(%)?\s+([+-]?\d*\.?\d+)(%)?\s*(?:\/\s*([+-]?\d*\.?\d+)(%)?\s*)?\)$/i; 1838 var y = { string: [[function(r2) { 1839 var t2 = i.exec(r2); 1840 return t2 ? (r2 = t2[1]).length <= 4 ? { r: parseInt(r2[0] + r2[0], 16), g: parseInt(r2[1] + r2[1], 16), b: parseInt(r2[2] + r2[2], 16), a: 4 === r2.length ? n(parseInt(r2[3] + r2[3], 16) / 255, 2) : 1 } : 6 === r2.length || 8 === r2.length ? { r: parseInt(r2.substr(0, 2), 16), g: parseInt(r2.substr(2, 2), 16), b: parseInt(r2.substr(4, 2), 16), a: 8 === r2.length ? n(parseInt(r2.substr(6, 2), 16) / 255, 2) : 1 } : null : null; 1841 }, "hex"], [function(r2) { 1842 var t2 = v.exec(r2) || m.exec(r2); 1843 return t2 ? t2[2] !== t2[4] || t2[4] !== t2[6] ? null : a({ r: Number(t2[1]) / (t2[2] ? 100 / 255 : 1), g: Number(t2[3]) / (t2[4] ? 100 / 255 : 1), b: Number(t2[5]) / (t2[6] ? 100 / 255 : 1), a: void 0 === t2[7] ? 1 : Number(t2[7]) / (t2[8] ? 100 : 1) }) : null; 1844 }, "rgb"], [function(t2) { 1845 var n2 = l.exec(t2) || p.exec(t2); 1846 if (!n2) return null; 1847 var e2, u2, a2 = g({ h: (e2 = n2[1], u2 = n2[2], void 0 === u2 && (u2 = "deg"), Number(e2) * (r[u2] || 1)), s: Number(n2[3]), l: Number(n2[4]), a: void 0 === n2[5] ? 1 : Number(n2[5]) / (n2[6] ? 100 : 1) }); 1848 return f(a2); 1849 }, "hsl"]], object: [[function(r2) { 1850 var n2 = r2.r, e2 = r2.g, u2 = r2.b, o2 = r2.a, i2 = void 0 === o2 ? 1 : o2; 1851 return t(n2) && t(e2) && t(u2) ? a({ r: Number(n2), g: Number(e2), b: Number(u2), a: Number(i2) }) : null; 1852 }, "rgb"], [function(r2) { 1853 var n2 = r2.h, e2 = r2.s, u2 = r2.l, a2 = r2.a, o2 = void 0 === a2 ? 1 : a2; 1854 if (!t(n2) || !t(e2) || !t(u2)) return null; 1855 var i2 = g({ h: Number(n2), s: Number(e2), l: Number(u2), a: Number(o2) }); 1856 return f(i2); 1857 }, "hsl"], [function(r2) { 1858 var n2 = r2.h, a2 = r2.s, o2 = r2.v, i2 = r2.a, s2 = void 0 === i2 ? 1 : i2; 1859 if (!t(n2) || !t(a2) || !t(o2)) return null; 1860 var h2 = (function(r3) { 1861 return { h: u(r3.h), s: e(r3.s, 0, 100), v: e(r3.v, 0, 100), a: e(r3.a) }; 1862 })({ h: Number(n2), s: Number(a2), v: Number(o2), a: Number(s2) }); 1863 return b(h2); 1864 }, "hsv"]] }; 1865 var N = function(r2, t2) { 1866 for (var n2 = 0; n2 < t2.length; n2++) { 1867 var e2 = t2[n2][0](r2); 1868 if (e2) return [e2, t2[n2][1]]; 1869 } 1870 return [null, void 0]; 1871 }; 1872 var x = function(r2) { 1873 return "string" == typeof r2 ? N(r2.trim(), y.string) : "object" == typeof r2 && null !== r2 ? N(r2, y.object) : [null, void 0]; 1874 }; 1875 var M = function(r2, t2) { 1876 var n2 = c(r2); 1877 return { h: n2.h, s: e(n2.s + 100 * t2, 0, 100), l: n2.l, a: n2.a }; 1878 }; 1879 var H = function(r2) { 1880 return (299 * r2.r + 587 * r2.g + 114 * r2.b) / 1e3 / 255; 1881 }; 1882 var $ = function(r2, t2) { 1883 var n2 = c(r2); 1884 return { h: n2.h, s: n2.s, l: e(n2.l + 100 * t2, 0, 100), a: n2.a }; 1885 }; 1886 var j = (function() { 1887 function r2(r3) { 1888 this.parsed = x(r3)[0], this.rgba = this.parsed || { r: 0, g: 0, b: 0, a: 1 }; 1889 } 1890 return r2.prototype.isValid = function() { 1891 return null !== this.parsed; 1892 }, r2.prototype.brightness = function() { 1893 return n(H(this.rgba), 2); 1894 }, r2.prototype.isDark = function() { 1895 return H(this.rgba) < 0.5; 1896 }, r2.prototype.isLight = function() { 1897 return H(this.rgba) >= 0.5; 1898 }, r2.prototype.toHex = function() { 1899 return r3 = o(this.rgba), t2 = r3.r, e2 = r3.g, u2 = r3.b, i2 = (a2 = r3.a) < 1 ? s(n(255 * a2)) : "", "#" + s(t2) + s(e2) + s(u2) + i2; 1900 var r3, t2, e2, u2, a2, i2; 1901 }, r2.prototype.toRgb = function() { 1902 return o(this.rgba); 1903 }, r2.prototype.toRgbString = function() { 1904 return r3 = o(this.rgba), t2 = r3.r, n2 = r3.g, e2 = r3.b, (u2 = r3.a) < 1 ? "rgba(" + t2 + ", " + n2 + ", " + e2 + ", " + u2 + ")" : "rgb(" + t2 + ", " + n2 + ", " + e2 + ")"; 1905 var r3, t2, n2, e2, u2; 1906 }, r2.prototype.toHsl = function() { 1907 return d(c(this.rgba)); 1908 }, r2.prototype.toHslString = function() { 1909 return r3 = d(c(this.rgba)), t2 = r3.h, n2 = r3.s, e2 = r3.l, (u2 = r3.a) < 1 ? "hsla(" + t2 + ", " + n2 + "%, " + e2 + "%, " + u2 + ")" : "hsl(" + t2 + ", " + n2 + "%, " + e2 + "%)"; 1910 var r3, t2, n2, e2, u2; 1911 }, r2.prototype.toHsv = function() { 1912 return r3 = h(this.rgba), { h: n(r3.h), s: n(r3.s), v: n(r3.v), a: n(r3.a, 3) }; 1913 var r3; 1914 }, r2.prototype.invert = function() { 1915 return w({ r: 255 - (r3 = this.rgba).r, g: 255 - r3.g, b: 255 - r3.b, a: r3.a }); 1916 var r3; 1917 }, r2.prototype.saturate = function(r3) { 1918 return void 0 === r3 && (r3 = 0.1), w(M(this.rgba, r3)); 1919 }, r2.prototype.desaturate = function(r3) { 1920 return void 0 === r3 && (r3 = 0.1), w(M(this.rgba, -r3)); 1921 }, r2.prototype.grayscale = function() { 1922 return w(M(this.rgba, -1)); 1923 }, r2.prototype.lighten = function(r3) { 1924 return void 0 === r3 && (r3 = 0.1), w($(this.rgba, r3)); 1925 }, r2.prototype.darken = function(r3) { 1926 return void 0 === r3 && (r3 = 0.1), w($(this.rgba, -r3)); 1927 }, r2.prototype.rotate = function(r3) { 1928 return void 0 === r3 && (r3 = 15), this.hue(this.hue() + r3); 1929 }, r2.prototype.alpha = function(r3) { 1930 return "number" == typeof r3 ? w({ r: (t2 = this.rgba).r, g: t2.g, b: t2.b, a: r3 }) : n(this.rgba.a, 3); 1931 var t2; 1932 }, r2.prototype.hue = function(r3) { 1933 var t2 = c(this.rgba); 1934 return "number" == typeof r3 ? w({ h: r3, s: t2.s, l: t2.l, a: t2.a }) : n(t2.h); 1935 }, r2.prototype.isEqual = function(r3) { 1936 return this.toHex() === w(r3).toHex(); 1937 }, r2; 1938 })(); 1939 var w = function(r2) { 1940 return r2 instanceof j ? r2 : new j(r2); 1941 }; 1942 1943 // packages/rich-text/build-module/hook/use-boundary-style.mjs 1944 var import_element2 = __toESM(require_element(), 1); 1945 function useBoundaryStyle({ record }) { 1946 const ref = (0, import_element2.useRef)(); 1947 const { activeFormats = [], replacements, start } = record.current; 1948 const activeReplacement = replacements[start]; 1949 (0, import_element2.useEffect)(() => { 1950 if ((!activeFormats || !activeFormats.length) && !activeReplacement) { 1951 return; 1952 } 1953 const boundarySelector = "*[data-rich-text-format-boundary]"; 1954 const element = ref.current.querySelector(boundarySelector); 1955 if (!element) { 1956 return; 1957 } 1958 const { ownerDocument } = element; 1959 const { defaultView } = ownerDocument; 1960 const computedStyle = defaultView.getComputedStyle(element); 1961 const newColor = w(computedStyle.color).alpha(0.2).toRgbString(); 1962 const selector = `.rich-text:focus $boundarySelector}`; 1963 const rule = `background-color: $newColor}`; 1964 const style = `$selector} {$rule}}`; 1965 const globalStyleId = "rich-text-boundary-style"; 1966 let globalStyle = ownerDocument.getElementById(globalStyleId); 1967 if (!globalStyle) { 1968 globalStyle = ownerDocument.createElement("style"); 1969 globalStyle.id = globalStyleId; 1970 ownerDocument.head.appendChild(globalStyle); 1971 } 1972 if (globalStyle.innerHTML !== style) { 1973 globalStyle.innerHTML = style; 1974 } 1975 }, [activeFormats, activeReplacement]); 1976 return ref; 1977 } 1978 1979 // packages/rich-text/build-module/hook/event-listeners/index.mjs 1980 var import_element3 = __toESM(require_element(), 1); 1981 var import_compose7 = __toESM(require_compose(), 1); 1982 1983 // packages/rich-text/build-module/hook/event-listeners/copy-handler.mjs 1984 var import_compose = __toESM(require_compose(), 1); 1985 var { subscribeDelegatedListener } = unlock(import_compose.privateApis); 1986 var copy_handler_default = (props) => (element) => { 1987 function onCopy(event) { 1988 const { record, handleChange } = props.current; 1989 const { ownerDocument } = element; 1990 if ( 1991 // Another handler may have already claimed the clipboard, e.g. 1992 // the block editor copying the whole block when its entire 1993 // text is selected. 1994 event.defaultPrevented || isCollapsed(record.current) || !element.contains(ownerDocument.activeElement) && !ownsSelection(element) 1995 ) { 1996 return; 1997 } 1998 const selectedRecord = slice(record.current); 1999 const plainText = getTextContent(selectedRecord); 2000 const html = toHTMLString({ value: selectedRecord }); 2001 event.clipboardData.setData("text/plain", plainText); 2002 event.clipboardData.setData("text/html", html); 2003 event.clipboardData.setData("rich-text", "true"); 2004 event.preventDefault(); 2005 if (event.type === "cut") { 2006 handleChange(remove2(record.current)); 2007 } 2008 } 2009 const { defaultView } = element.ownerDocument; 2010 const unsubscribeCopy = subscribeDelegatedListener( 2011 defaultView, 2012 "copy", 2013 onCopy 2014 ); 2015 const unsubscribeCut = subscribeDelegatedListener( 2016 defaultView, 2017 "cut", 2018 onCopy 2019 ); 2020 return () => { 2021 unsubscribeCopy(); 2022 unsubscribeCut(); 2023 }; 2024 }; 2025 2026 // packages/rich-text/build-module/hook/event-listeners/select-object.mjs 2027 var import_compose2 = __toESM(require_compose(), 1); 2028 var { subscribeDelegatedListener: subscribeDelegatedListener2 } = unlock(import_compose2.privateApis); 2029 var select_object_default = () => (element) => { 2030 function onClick(event) { 2031 const { target } = event; 2032 if (target === element || target.textContent && target.isContentEditable) { 2033 return; 2034 } 2035 const { ownerDocument } = target; 2036 const { defaultView } = ownerDocument; 2037 const selection = defaultView.getSelection(); 2038 if (selection.containsNode(target)) { 2039 return; 2040 } 2041 const range = ownerDocument.createRange(); 2042 const nodeToSelect = target.isContentEditable ? target : target.closest("[contenteditable]"); 2043 range.selectNode(nodeToSelect); 2044 selection.removeAllRanges(); 2045 selection.addRange(range); 2046 event.preventDefault(); 2047 } 2048 function onFocusIn(event) { 2049 if (event.relatedTarget && !element.contains(event.relatedTarget)) { 2050 onClick(event); 2051 } 2052 } 2053 const unsubscribeClick = subscribeDelegatedListener2( 2054 element, 2055 "click", 2056 onClick 2057 ); 2058 const unsubscribeFocusIn = subscribeDelegatedListener2( 2059 element, 2060 "focusin", 2061 onFocusIn 2062 ); 2063 return () => { 2064 unsubscribeClick(); 2065 unsubscribeFocusIn(); 2066 }; 2067 }; 2068 2069 // packages/rich-text/build-module/hook/event-listeners/format-boundaries.mjs 2070 var import_keycodes = __toESM(require_keycodes(), 1); 2071 2072 // packages/rich-text/build-module/subscribe-owned-listener.mjs 2073 var import_compose3 = __toESM(require_compose(), 1); 2074 var { subscribeDelegatedListener: subscribeDelegatedListener3 } = unlock(import_compose3.privateApis); 2075 var registries = /* @__PURE__ */ new WeakMap(); 2076 function subscribeOwnedListener(element, eventType, callback, capture = false) { 2077 const { ownerDocument } = element; 2078 let byEvent = registries.get(ownerDocument); 2079 if (!byEvent) { 2080 byEvent = /* @__PURE__ */ new Map(); 2081 registries.set(ownerDocument, byEvent); 2082 } 2083 const key = capture ? `$eventType}:capture` : eventType; 2084 let elements = byEvent.get(key); 2085 if (!elements) { 2086 elements = /* @__PURE__ */ new WeakMap(); 2087 byEvent.set(key, elements); 2088 subscribeDelegatedListener3( 2089 ownerDocument, 2090 eventType, 2091 (event) => { 2092 const { defaultView, activeElement } = ownerDocument; 2093 const anchorNode = defaultView?.getSelection()?.anchorNode; 2094 for (let node = anchorNode ?? activeElement; node; node = node.parentNode) { 2095 const callbacks = elements.get(node); 2096 if (callbacks && ownsSelection(node)) { 2097 for (const cb of callbacks) { 2098 cb(event); 2099 } 2100 } 2101 } 2102 }, 2103 capture 2104 ); 2105 } 2106 let set = elements.get(element); 2107 if (!set) { 2108 set = /* @__PURE__ */ new Set(); 2109 elements.set(element, set); 2110 } 2111 set.add(callback); 2112 return () => { 2113 set.delete(callback); 2114 }; 2115 } 2116 2117 // packages/rich-text/build-module/hook/event-listeners/format-boundaries.mjs 2118 var EMPTY_ACTIVE_FORMATS = []; 2119 var format_boundaries_default = (props) => (element) => { 2120 function onKeyDown(event) { 2121 const { keyCode, shiftKey, altKey, metaKey, ctrlKey } = event; 2122 if ( 2123 // Only override left and right keys without modifiers pressed. 2124 shiftKey || altKey || metaKey || ctrlKey || keyCode !== import_keycodes.LEFT && keyCode !== import_keycodes.RIGHT 2125 ) { 2126 return; 2127 } 2128 const { record, applyRecord, forceRender } = props.current; 2129 const { 2130 text, 2131 formats, 2132 start, 2133 end, 2134 activeFormats: currentActiveFormats = [] 2135 } = record.current; 2136 const collapsed = isCollapsed(record.current); 2137 const { defaultView } = element.ownerDocument; 2138 const { direction } = defaultView.getComputedStyle(element); 2139 const reverseKey = direction === "rtl" ? import_keycodes.RIGHT : import_keycodes.LEFT; 2140 const isReverse = event.keyCode === reverseKey; 2141 if (collapsed && currentActiveFormats.length === 0) { 2142 if (start === 0 && isReverse) { 2143 return; 2144 } 2145 if (end === text.length && !isReverse) { 2146 return; 2147 } 2148 } 2149 if (!collapsed) { 2150 return; 2151 } 2152 const formatsBefore = formats[start - 1] || EMPTY_ACTIVE_FORMATS; 2153 const formatsAfter = formats[start] || EMPTY_ACTIVE_FORMATS; 2154 const destination = isReverse ? formatsBefore : formatsAfter; 2155 const isIncreasing = currentActiveFormats.every( 2156 (format, index) => format === destination[index] 2157 ); 2158 let newActiveFormatsLength = currentActiveFormats.length; 2159 if (!isIncreasing) { 2160 newActiveFormatsLength--; 2161 } else if (newActiveFormatsLength < destination.length) { 2162 newActiveFormatsLength++; 2163 } 2164 if (newActiveFormatsLength === currentActiveFormats.length) { 2165 record.current._newActiveFormats = destination; 2166 return; 2167 } 2168 event.preventDefault(); 2169 const origin = isReverse ? formatsAfter : formatsBefore; 2170 const source = isIncreasing ? destination : origin; 2171 const newActiveFormats = source.slice(0, newActiveFormatsLength); 2172 const newValue = { 2173 ...record.current, 2174 activeFormats: newActiveFormats 2175 }; 2176 record.current = newValue; 2177 applyRecord(newValue); 2178 forceRender(); 2179 } 2180 return subscribeOwnedListener(element, "keydown", onKeyDown, true); 2181 }; 2182 2183 // packages/rich-text/build-module/hook/event-listeners/delete.mjs 2184 var import_keycodes2 = __toESM(require_keycodes(), 1); 2185 var delete_default = (props) => (element) => { 2186 function onKeyDown(event) { 2187 const { keyCode } = event; 2188 if (event.defaultPrevented) { 2189 return; 2190 } 2191 if (keyCode !== import_keycodes2.DELETE && keyCode !== import_keycodes2.BACKSPACE) { 2192 return; 2193 } 2194 const { createRecord, handleChange } = props.current; 2195 const currentValue = createRecord(); 2196 const { start, end, text } = currentValue; 2197 if (start === 0 && end !== 0 && end === text.length) { 2198 handleChange(remove2(currentValue)); 2199 event.preventDefault(); 2200 } 2201 } 2202 return subscribeOwnedListener(element, "keydown", onKeyDown); 2203 }; 2204 2205 // packages/rich-text/build-module/hook/event-listeners/input-and-selection.mjs 2206 var import_compose4 = __toESM(require_compose(), 1); 2207 2208 // packages/rich-text/build-module/update-formats.mjs 2209 function updateFormats({ value, start, end, formats }) { 2210 const min = Math.min(start, end); 2211 const max = Math.max(start, end); 2212 const formatsBefore = value.formats[min - 1] || []; 2213 const formatsAfter = value.formats[max] || []; 2214 value.activeFormats = formats.map((format, index) => { 2215 if (formatsBefore[index]) { 2216 if (isFormatEqual(format, formatsBefore[index])) { 2217 return formatsBefore[index]; 2218 } 2219 } else if (formatsAfter[index]) { 2220 if (isFormatEqual(format, formatsAfter[index])) { 2221 return formatsAfter[index]; 2222 } 2223 } 2224 return format; 2225 }); 2226 while (--end >= start) { 2227 if (value.activeFormats.length > 0) { 2228 value.formats[end] = value.activeFormats; 2229 } else { 2230 delete value.formats[end]; 2231 } 2232 } 2233 return value; 2234 } 2235 2236 // packages/rich-text/build-module/hook/event-listeners/input-and-selection.mjs 2237 var { subscribeDelegatedListener: subscribeDelegatedListener4 } = unlock(import_compose4.privateApis); 2238 var INSERTION_INPUT_TYPES_TO_IGNORE = /* @__PURE__ */ new Set([ 2239 "insertParagraph", 2240 "insertOrderedList", 2241 "insertUnorderedList", 2242 "insertHorizontalRule", 2243 "insertLink" 2244 ]); 2245 var EMPTY_ACTIVE_FORMATS2 = []; 2246 var PLACEHOLDER_ATTR_NAME = "data-rich-text-placeholder"; 2247 var input_and_selection_default = (props) => (element) => { 2248 const { ownerDocument } = element; 2249 const { defaultView } = ownerDocument; 2250 let isComposing = false; 2251 function onInput(event) { 2252 if (isComposing) { 2253 return; 2254 } 2255 let inputType; 2256 if (event) { 2257 inputType = event.inputType; 2258 } 2259 const { record, applyRecord, createRecord, handleChange } = props.current; 2260 if (inputType && (inputType.indexOf("format") === 0 || INSERTION_INPUT_TYPES_TO_IGNORE.has(inputType))) { 2261 applyRecord(record.current); 2262 return; 2263 } 2264 const currentValue = createRecord(); 2265 const { start, activeFormats: oldActiveFormats = [] } = record.current; 2266 const clearFormats = !isCollapsed(record.current) && currentValue.start <= start; 2267 const change = updateFormats({ 2268 value: currentValue, 2269 start, 2270 end: currentValue.start, 2271 formats: clearFormats ? [] : oldActiveFormats 2272 }); 2273 handleChange(change); 2274 } 2275 let selectionSnapshot; 2276 function handleSelectionChange() { 2277 const { record, applyRecord, createRecord, onSelectionChange } = props.current; 2278 if (element.contentEditable !== "true") { 2279 return; 2280 } 2281 if (ownerDocument.activeElement !== element && !ownsSelection(element)) { 2282 return; 2283 } 2284 if (isComposing) { 2285 return; 2286 } 2287 const selection = defaultView.getSelection(); 2288 if (selectionSnapshot && selectionSnapshot.anchorNode === selection.anchorNode && selectionSnapshot.anchorOffset === selection.anchorOffset && selectionSnapshot.focusNode === selection.focusNode && selectionSnapshot.focusOffset === selection.focusOffset && selectionSnapshot.processedStart === record.current.start && selectionSnapshot.processedEnd === record.current.end) { 2289 return; 2290 } 2291 const { start, end, text } = createRecord(); 2292 const oldRecord = record.current; 2293 if (text.length === 0) { 2294 applyRecord({ ...oldRecord, start, end }); 2295 } 2296 selectionSnapshot = { 2297 anchorNode: selection.anchorNode, 2298 anchorOffset: selection.anchorOffset, 2299 focusNode: selection.focusNode, 2300 focusOffset: selection.focusOffset, 2301 processedStart: start, 2302 processedEnd: end 2303 }; 2304 if (text !== oldRecord.text) { 2305 onInput(); 2306 return; 2307 } 2308 if (start === oldRecord.start && end === oldRecord.end) { 2309 return; 2310 } 2311 const newValue = { 2312 ...oldRecord, 2313 start, 2314 end, 2315 // _newActiveFormats may be set on arrow key navigation to control 2316 // the right boundary position. If undefined, getActiveFormats will 2317 // give the active formats according to the browser. 2318 activeFormats: oldRecord._newActiveFormats, 2319 _newActiveFormats: void 0 2320 }; 2321 const newActiveFormats = getActiveFormats( 2322 newValue, 2323 EMPTY_ACTIVE_FORMATS2 2324 ); 2325 newValue.activeFormats = newActiveFormats; 2326 record.current = newValue; 2327 applyRecord(newValue, { domOnly: true }); 2328 onSelectionChange(start, end); 2329 } 2330 function onCompositionStart() { 2331 isComposing = true; 2332 element.querySelector(`[$PLACEHOLDER_ATTR_NAME}]`)?.remove(); 2333 } 2334 function onCompositionEnd() { 2335 isComposing = false; 2336 onInput({ inputType: "insertText" }); 2337 } 2338 function onFocus(event) { 2339 if (event.target !== element) { 2340 return; 2341 } 2342 if (element.contentEditable !== "true") { 2343 return; 2344 } 2345 const { record, isSelected, onSelectionChange, applyRecord } = props.current; 2346 if (element.parentElement.closest('[contenteditable="true"]')) { 2347 const selection = defaultView.getSelection(); 2348 if (!selection.anchorNode || !element.contains(selection.anchorNode)) { 2349 if (isSelected && record.current.start !== void 0) { 2350 applyRecord(record.current); 2351 } else { 2352 selection.collapse(element, 0); 2353 } 2354 } 2355 window.queueMicrotask(handleSelectionChange); 2356 return; 2357 } 2358 if (!isSelected) { 2359 const index = void 0; 2360 record.current = { 2361 ...record.current, 2362 start: index, 2363 end: index, 2364 activeFormats: EMPTY_ACTIVE_FORMATS2 2365 }; 2366 selectionSnapshot = void 0; 2367 } else { 2368 applyRecord(record.current); 2369 } 2370 onSelectionChange(record.current.start, record.current.end); 2371 window.queueMicrotask(handleSelectionChange); 2372 } 2373 const unsubscribeInput = subscribeOwnedListener( 2374 element, 2375 "input", 2376 onInput, 2377 true 2378 ); 2379 const unsubscribeCompositionStart = subscribeOwnedListener( 2380 element, 2381 "compositionstart", 2382 onCompositionStart 2383 ); 2384 const unsubscribeCompositionEnd = subscribeOwnedListener( 2385 element, 2386 "compositionend", 2387 onCompositionEnd, 2388 true 2389 ); 2390 const unsubscribeFocus = subscribeDelegatedListener4( 2391 element, 2392 "focusin", 2393 onFocus 2394 ); 2395 const unsubscribeSelectionChange = subscribeOwnedListener( 2396 element, 2397 "selectionchange", 2398 handleSelectionChange 2399 ); 2400 const unsubscribeEnsureSelectionSync = [ 2401 "keydown", 2402 "beforeinput", 2403 "copy", 2404 "cut", 2405 "paste" 2406 ].map( 2407 (eventType) => subscribeOwnedListener( 2408 element, 2409 eventType, 2410 handleSelectionChange, 2411 true 2412 ) 2413 ); 2414 return () => { 2415 unsubscribeInput(); 2416 unsubscribeCompositionStart(); 2417 unsubscribeCompositionEnd(); 2418 unsubscribeFocus(); 2419 unsubscribeSelectionChange(); 2420 unsubscribeEnsureSelectionSync.forEach( 2421 (unsubscribe) => unsubscribe() 2422 ); 2423 }; 2424 }; 2425 2426 // packages/rich-text/build-module/hook/event-listeners/selection-change-compat.mjs 2427 var import_compose5 = __toESM(require_compose(), 1); 2428 var { subscribeDelegatedListener: subscribeDelegatedListener5 } = unlock(import_compose5.privateApis); 2429 var selection_change_compat_default = () => (element) => { 2430 const { ownerDocument } = element; 2431 const { defaultView } = ownerDocument; 2432 const selection = defaultView?.getSelection(); 2433 let range; 2434 function getRange() { 2435 return selection.rangeCount ? selection.getRangeAt(0) : null; 2436 } 2437 function onDown(event) { 2438 const type = event.type === "keydown" ? "keyup" : "pointerup"; 2439 function onCancel() { 2440 ownerDocument.removeEventListener(type, onUp); 2441 ownerDocument.removeEventListener("selectionchange", onCancel); 2442 ownerDocument.removeEventListener("input", onCancel); 2443 } 2444 function onUp() { 2445 onCancel(); 2446 if (isRangeEqual(range, getRange())) { 2447 return; 2448 } 2449 ownerDocument.dispatchEvent(new Event("selectionchange")); 2450 } 2451 ownerDocument.addEventListener(type, onUp); 2452 ownerDocument.addEventListener("selectionchange", onCancel); 2453 ownerDocument.addEventListener("input", onCancel); 2454 range = getRange(); 2455 } 2456 const unsubscribePointerDown = subscribeDelegatedListener5( 2457 element, 2458 "pointerdown", 2459 onDown 2460 ); 2461 const unsubscribeKeyDown = subscribeDelegatedListener5( 2462 element, 2463 "keydown", 2464 onDown 2465 ); 2466 return () => { 2467 unsubscribePointerDown(); 2468 unsubscribeKeyDown(); 2469 }; 2470 }; 2471 2472 // packages/rich-text/build-module/hook/event-listeners/prevent-focus-capture.mjs 2473 var import_compose6 = __toESM(require_compose(), 1); 2474 var { subscribeDelegatedListener: subscribeDelegatedListener6 } = unlock(import_compose6.privateApis); 2475 function preventFocusCapture() { 2476 return (element) => { 2477 const { ownerDocument } = element; 2478 const { defaultView } = ownerDocument; 2479 let value = null; 2480 function onPointerDown(event) { 2481 if (event.defaultPrevented) { 2482 return; 2483 } 2484 if (event.target === element) { 2485 return; 2486 } 2487 if (!event.target.contains(element)) { 2488 return; 2489 } 2490 value = element.getAttribute("contenteditable"); 2491 element.setAttribute("contenteditable", "false"); 2492 defaultView.getSelection().removeAllRanges(); 2493 } 2494 function onPointerUp() { 2495 if (value !== null) { 2496 element.setAttribute("contenteditable", value); 2497 value = null; 2498 } 2499 } 2500 const unsubscribePointerDown = subscribeDelegatedListener6( 2501 defaultView, 2502 "pointerdown", 2503 onPointerDown 2504 ); 2505 const unsubscribePointerUp = subscribeDelegatedListener6( 2506 defaultView, 2507 "pointerup", 2508 onPointerUp 2509 ); 2510 const unsubscribePointerCancel = subscribeDelegatedListener6( 2511 defaultView, 2512 "pointercancel", 2513 onPointerUp 2514 ); 2515 return () => { 2516 unsubscribePointerDown(); 2517 unsubscribePointerUp(); 2518 unsubscribePointerCancel(); 2519 }; 2520 }; 2521 } 2522 2523 // packages/rich-text/build-module/hook/event-listeners/index.mjs 2524 var allEventListeners = [ 2525 input_and_selection_default, 2526 copy_handler_default, 2527 select_object_default, 2528 format_boundaries_default, 2529 delete_default, 2530 selection_change_compat_default, 2531 preventFocusCapture 2532 ]; 2533 function useEventListeners(props) { 2534 const propsRef = (0, import_element3.useRef)(props); 2535 (0, import_element3.useInsertionEffect)(() => { 2536 propsRef.current = props; 2537 }); 2538 const refEffects = (0, import_element3.useMemo)( 2539 () => allEventListeners.map((refEffect) => refEffect(propsRef)), 2540 [propsRef] 2541 ); 2542 return (0, import_compose7.useRefEffect)( 2543 (element) => { 2544 const cleanups = refEffects.map((effect) => effect(element)); 2545 return () => { 2546 cleanups.forEach((cleanup) => cleanup()); 2547 }; 2548 }, 2549 [refEffects] 2550 ); 2551 } 2552 2553 // packages/rich-text/build-module/hook/use-format-types.mjs 2554 var import_element4 = __toESM(require_element(), 1); 2555 var import_data8 = __toESM(require_data(), 1); 2556 function formatTypesSelector(select5) { 2557 return select5(store).getFormatTypes(); 2558 } 2559 var interactiveContentTags = /* @__PURE__ */ new Set([ 2560 "a", 2561 "audio", 2562 "button", 2563 "details", 2564 "embed", 2565 "iframe", 2566 "input", 2567 "label", 2568 "select", 2569 "textarea", 2570 "video" 2571 ]); 2572 function prefixSelectKeys(selected, prefix) { 2573 if (typeof selected !== "object") { 2574 return { [prefix]: selected }; 2575 } 2576 return Object.fromEntries( 2577 Object.entries(selected).map(([key, value]) => [ 2578 `$prefix}.$key}`, 2579 value 2580 ]) 2581 ); 2582 } 2583 function getPrefixedSelectKeys(selected, prefix) { 2584 if (selected[prefix]) { 2585 return selected[prefix]; 2586 } 2587 return Object.keys(selected).filter((key) => key.startsWith(prefix + ".")).reduce((accumulator, key) => { 2588 accumulator[key.slice(prefix.length + 1)] = selected[key]; 2589 return accumulator; 2590 }, {}); 2591 } 2592 function useFormatTypes({ 2593 allowedFormats, 2594 withoutInteractiveFormatting, 2595 __unstableFormatTypeHandlerContext 2596 }) { 2597 const allFormatTypes = (0, import_data8.useSelect)(formatTypesSelector, []); 2598 const formatTypes2 = (0, import_element4.useMemo)(() => { 2599 return allFormatTypes.filter(({ name, interactive, tagName }) => { 2600 if (allowedFormats && !allowedFormats.includes(name)) { 2601 return false; 2602 } 2603 if (withoutInteractiveFormatting && (interactive || interactiveContentTags.has(tagName))) { 2604 return false; 2605 } 2606 return true; 2607 }); 2608 }, [allFormatTypes, allowedFormats, withoutInteractiveFormatting]); 2609 const keyedSelected = (0, import_data8.useSelect)( 2610 (select5) => formatTypes2.reduce((accumulator, type) => { 2611 if (!type.__experimentalGetPropsForEditableTreePreparation || !__unstableFormatTypeHandlerContext) { 2612 return accumulator; 2613 } 2614 return { 2615 ...accumulator, 2616 ...prefixSelectKeys( 2617 type.__experimentalGetPropsForEditableTreePreparation( 2618 select5, 2619 __unstableFormatTypeHandlerContext 2620 ), 2621 type.name 2622 ) 2623 }; 2624 }, {}), 2625 [formatTypes2, __unstableFormatTypeHandlerContext] 2626 ); 2627 const dispatch3 = (0, import_data8.useDispatch)(); 2628 const prepareHandlers = []; 2629 const valueHandlers = []; 2630 const changeHandlers = []; 2631 const dependencies = []; 2632 for (const key in keyedSelected) { 2633 dependencies.push(keyedSelected[key]); 2634 } 2635 formatTypes2.forEach((type) => { 2636 if (type.__experimentalCreatePrepareEditableTree && __unstableFormatTypeHandlerContext) { 2637 const handler = type.__experimentalCreatePrepareEditableTree( 2638 getPrefixedSelectKeys(keyedSelected, type.name), 2639 __unstableFormatTypeHandlerContext 2640 ); 2641 if (type.__experimentalCreateOnChangeEditableValue) { 2642 valueHandlers.push(handler); 2643 } else { 2644 prepareHandlers.push(handler); 2645 } 2646 } 2647 if (type.__experimentalCreateOnChangeEditableValue && __unstableFormatTypeHandlerContext) { 2648 let dispatchers = {}; 2649 if (type.__experimentalGetPropsForEditableTreeChangeHandler) { 2650 dispatchers = type.__experimentalGetPropsForEditableTreeChangeHandler( 2651 dispatch3, 2652 __unstableFormatTypeHandlerContext 2653 ); 2654 } 2655 const selected = getPrefixedSelectKeys(keyedSelected, type.name); 2656 changeHandlers.push( 2657 type.__experimentalCreateOnChangeEditableValue( 2658 { 2659 ...typeof selected === "object" ? selected : {}, 2660 ...dispatchers 2661 }, 2662 __unstableFormatTypeHandlerContext 2663 ) 2664 ); 2665 } 2666 }); 2667 return { 2668 formatTypes: formatTypes2, 2669 prepareHandlers, 2670 valueHandlers, 2671 changeHandlers, 2672 dependencies 2673 }; 2674 } 2675 2676 // packages/rich-text/build-module/hook/index.mjs 2677 function useRichTextBase({ 2678 value = "", 2679 selectionStart, 2680 selectionEnd, 2681 placeholder, 2682 onSelectionChange, 2683 preserveWhiteSpace, 2684 onChange, 2685 __unstableDisableFormats: disableFormats, 2686 __unstableIsSelected: isSelected, 2687 __unstableDependencies = [], 2688 __unstableAfterParse, 2689 __unstableBeforeSerialize, 2690 __unstableAddInvisibleFormats 2691 }) { 2692 const registry = (0, import_data9.useRegistry)(); 2693 const [, forceRender] = (0, import_element5.useReducer)(() => ({})); 2694 const ref = (0, import_element5.useRef)(); 2695 function createRecord() { 2696 const { 2697 ownerDocument: { defaultView } 2698 } = ref.current; 2699 const selection = defaultView.getSelection(); 2700 const range = selection.rangeCount > 0 ? selection.getRangeAt(0) : null; 2701 return create({ 2702 element: ref.current, 2703 range, 2704 __unstableIsEditableTree: true 2705 }); 2706 } 2707 function applyRecord(newRecord, { domOnly } = {}) { 2708 apply({ 2709 value: newRecord, 2710 current: ref.current, 2711 prepareEditableTree: __unstableAddInvisibleFormats, 2712 __unstableDomOnly: domOnly, 2713 placeholder 2714 }); 2715 } 2716 const _valueRef = (0, import_element5.useRef)(value); 2717 const recordRef = (0, import_element5.useRef)(); 2718 function setRecordFromProps() { 2719 const activeFormats = recordRef.current?.activeFormats; 2720 _valueRef.current = value; 2721 recordRef.current = value; 2722 if (!(value instanceof RichTextData)) { 2723 recordRef.current = value ? RichTextData.fromHTMLString(value, { preserveWhiteSpace }) : RichTextData.empty(); 2724 } 2725 recordRef.current = { 2726 text: recordRef.current.text, 2727 formats: recordRef.current.formats, 2728 replacements: recordRef.current.replacements, 2729 activeFormats 2730 }; 2731 if (disableFormats) { 2732 recordRef.current.formats = Array(value.length); 2733 recordRef.current.replacements = Array(value.length); 2734 } 2735 if (__unstableAfterParse) { 2736 recordRef.current.formats = __unstableAfterParse( 2737 recordRef.current 2738 ); 2739 } 2740 recordRef.current.start = selectionStart; 2741 recordRef.current.end = selectionEnd; 2742 } 2743 const hadSelectionUpdateRef = (0, import_element5.useRef)(false); 2744 if (!recordRef.current) { 2745 hadSelectionUpdateRef.current = isSelected; 2746 setRecordFromProps(); 2747 } else if (selectionStart !== recordRef.current.start || selectionEnd !== recordRef.current.end) { 2748 hadSelectionUpdateRef.current = isSelected; 2749 recordRef.current = { 2750 ...recordRef.current, 2751 start: selectionStart, 2752 end: selectionEnd, 2753 activeFormats: void 0 2754 }; 2755 } 2756 function handleChange(newRecord) { 2757 recordRef.current = newRecord; 2758 applyRecord(newRecord); 2759 if (disableFormats) { 2760 _valueRef.current = newRecord.text; 2761 } else { 2762 const newFormats = __unstableBeforeSerialize ? __unstableBeforeSerialize(newRecord) : newRecord.formats; 2763 newRecord = { ...newRecord, formats: newFormats }; 2764 if (typeof value === "string") { 2765 _valueRef.current = toHTMLString({ 2766 value: newRecord, 2767 preserveWhiteSpace 2768 }); 2769 } else { 2770 _valueRef.current = new RichTextData(newRecord); 2771 } 2772 } 2773 const { start, end, formats, text } = recordRef.current; 2774 registry.batch(() => { 2775 onSelectionChange(start, end); 2776 onChange(_valueRef.current, { 2777 __unstableFormats: formats, 2778 __unstableText: text 2779 }); 2780 }); 2781 forceRender(); 2782 } 2783 function applyFromProps() { 2784 const previousValue = _valueRef.current; 2785 setRecordFromProps(); 2786 const contentLengthChanged = previousValue && typeof previousValue === "string" && typeof value === "string" && previousValue.length !== value.length; 2787 const hasFocus = ref.current?.contains(ref.current.ownerDocument.activeElement) || ownsSelection(ref.current); 2788 const skipSelection = contentLengthChanged && !hasFocus; 2789 applyRecord(recordRef.current, { domOnly: skipSelection }); 2790 } 2791 const didMountRef = (0, import_element5.useRef)(false); 2792 (0, import_element5.useLayoutEffect)(() => { 2793 if (didMountRef.current && value !== _valueRef.current) { 2794 applyFromProps(); 2795 forceRender(); 2796 } 2797 }, [value]); 2798 (0, import_element5.useLayoutEffect)(() => { 2799 if (!hadSelectionUpdateRef.current) { 2800 return; 2801 } 2802 if (ref.current.ownerDocument.activeElement !== ref.current && !ownsSelection(ref.current)) { 2803 ref.current.focus(); 2804 } 2805 applyRecord(recordRef.current); 2806 hadSelectionUpdateRef.current = false; 2807 }, [hadSelectionUpdateRef.current]); 2808 const mergedRefs = (0, import_compose8.useMergeRefs)([ 2809 ref, 2810 useDefaultStyle(), 2811 useBoundaryStyle({ record: recordRef }), 2812 useEventListeners({ 2813 record: recordRef, 2814 handleChange, 2815 applyRecord, 2816 createRecord, 2817 isSelected, 2818 onSelectionChange, 2819 forceRender 2820 }), 2821 (0, import_compose8.useRefEffect)(() => { 2822 applyFromProps(); 2823 didMountRef.current = true; 2824 }, [placeholder, ...__unstableDependencies]) 2825 ]); 2826 return { 2827 value: recordRef.current, 2828 // A function to get the most recent value so event handlers in 2829 // useRichText implementations have access to it. For example when 2830 // listening to input events, we internally update the state, but this 2831 // state is not yet available to the input event handler because React 2832 // may re-render asynchronously. 2833 getValue: () => recordRef.current, 2834 onChange: handleChange, 2835 ref: mergedRefs 2836 }; 2837 } 2838 function useRichText({ 2839 allowedFormats, 2840 withoutInteractiveFormatting, 2841 onChange, 2842 __unstableDependencies = [], 2843 __unstableFormatTypeHandlerContext, 2844 ...props 2845 }) { 2846 const { 2847 formatTypes: formatTypes2, 2848 prepareHandlers, 2849 valueHandlers, 2850 changeHandlers, 2851 dependencies 2852 } = useFormatTypes({ 2853 allowedFormats, 2854 withoutInteractiveFormatting, 2855 __unstableFormatTypeHandlerContext 2856 }); 2857 function addEditorOnlyFormats(record) { 2858 return valueHandlers.reduce( 2859 (accumulator, fn) => fn(accumulator, record.text), 2860 record.formats 2861 ); 2862 } 2863 function removeEditorOnlyFormats(record) { 2864 formatTypes2.forEach((formatType) => { 2865 if (formatType.__experimentalCreatePrepareEditableTree) { 2866 record = removeFormat( 2867 record, 2868 formatType.name, 2869 0, 2870 record.text.length 2871 ); 2872 } 2873 }); 2874 return record.formats; 2875 } 2876 function addInvisibleFormats(record) { 2877 return prepareHandlers.reduce( 2878 (accumulator, fn) => fn(accumulator, record.text), 2879 record.formats 2880 ); 2881 } 2882 const result = useRichTextBase({ 2883 ...props, 2884 onChange(value, { __unstableFormats, __unstableText }) { 2885 onChange(value, { __unstableFormats, __unstableText }); 2886 Object.values(changeHandlers).forEach((changeHandler) => { 2887 changeHandler(__unstableFormats, __unstableText); 2888 }); 2889 }, 2890 __unstableDependencies: [...dependencies, ...__unstableDependencies], 2891 __unstableAfterParse: addEditorOnlyFormats, 2892 __unstableBeforeSerialize: removeEditorOnlyFormats, 2893 __unstableAddInvisibleFormats: addInvisibleFormats 2894 }); 2895 return { ...result, formatTypes: formatTypes2 }; 2896 } 2897 function useDeprecatedRichText(props) { 2898 (0, import_deprecated.default)("`__unstableUseRichText` hook", { 2899 since: "7.0" 2900 }); 2901 return useRichTextBase(props); 2902 } 2903 2904 // packages/rich-text/build-module/contexts.mjs 2905 var import_element6 = __toESM(require_element(), 1); 2906 var KeyboardShortcutContext = (0, import_element6.createContext)(); 2907 KeyboardShortcutContext.displayName = "KeyboardShortcutContext"; 2908 var InputEventContext = (0, import_element6.createContext)(); 2909 InputEventContext.displayName = "InputEventContext"; 2910 2911 // packages/rich-text/build-module/keyboard-shortcut.mjs 2912 var import_keycodes3 = __toESM(require_keycodes(), 1); 2913 var import_element7 = __toESM(require_element(), 1); 2914 var import_compose9 = __toESM(require_compose(), 1); 2915 function RichTextShortcut({ character, type, onUse }) { 2916 const keyboardShortcuts = (0, import_element7.useContext)(KeyboardShortcutContext); 2917 const stableOnUse = (0, import_compose9.useEvent)(onUse); 2918 (0, import_element7.useEffect)(() => { 2919 const shortcuts = keyboardShortcuts.current; 2920 function callback(event) { 2921 if (import_keycodes3.isKeyboardEvent[type](event, character)) { 2922 stableOnUse(); 2923 event.preventDefault(); 2924 } 2925 } 2926 shortcuts.add(callback); 2927 return () => { 2928 shortcuts.delete(callback); 2929 }; 2930 }, [character, type, keyboardShortcuts, stableOnUse]); 2931 return null; 2932 } 2933 2934 // packages/rich-text/build-module/input-event.mjs 2935 var import_element8 = __toESM(require_element(), 1); 2936 var import_compose10 = __toESM(require_compose(), 1); 2937 function RichTextInputEvent({ inputType, onInput }) { 2938 const callbacks = (0, import_element8.useContext)(InputEventContext); 2939 const stableOnInput = (0, import_compose10.useEvent)(onInput); 2940 (0, import_element8.useEffect)(() => { 2941 const inputCallbacks = callbacks.current; 2942 function callback(event) { 2943 if (event.inputType === inputType) { 2944 stableOnInput(); 2945 event.preventDefault(); 2946 } 2947 } 2948 inputCallbacks.add(callback); 2949 return () => { 2950 inputCallbacks.delete(callback); 2951 }; 2952 }, [inputType, callbacks, stableOnInput]); 2953 return null; 2954 } 2955 2956 // packages/rich-text/build-module/event-listeners.mjs 2957 var shortcutsListener = (props) => (element) => { 2958 const { keyboardShortcuts } = props.current; 2959 function onKeyDown(event) { 2960 for (const keyboardShortcut of keyboardShortcuts.current) { 2961 keyboardShortcut(event); 2962 } 2963 } 2964 element.addEventListener("keydown", onKeyDown); 2965 return () => { 2966 element.removeEventListener("keydown", onKeyDown); 2967 }; 2968 }; 2969 var inputEventsListener = (props) => (element) => { 2970 const { inputEvents } = props.current; 2971 function onInput(event) { 2972 for (const inputEventHandler of inputEvents.current) { 2973 inputEventHandler(event); 2974 } 2975 } 2976 element.addEventListener("input", onInput); 2977 return () => { 2978 element.removeEventListener("input", onInput); 2979 }; 2980 }; 2981 2982 // packages/rich-text/build-module/private-apis.mjs 2983 var privateApis = {}; 2984 lock(privateApis, { 2985 useRichText, 2986 KeyboardShortcutContext, 2987 InputEventContext, 2988 RichTextShortcut, 2989 RichTextInputEvent, 2990 shortcutsListener, 2991 inputEventsListener, 2992 ownsSelection, 2993 subscribeOwnedListener 2994 }); 2995 2996 // packages/rich-text/build-module/hook/use-anchor-ref.mjs 2997 var import_element9 = __toESM(require_element(), 1); 2998 var import_deprecated2 = __toESM(require_deprecated(), 1); 2999 function useAnchorRef({ ref, value, settings = {} }) { 3000 (0, import_deprecated2.default)("`useAnchorRef` hook", { 3001 since: "6.1", 3002 alternative: "`useAnchor` hook" 3003 }); 3004 const { tagName, className, name } = settings; 3005 const activeFormat = name ? getActiveFormat(value, name) : void 0; 3006 return (0, import_element9.useMemo)(() => { 3007 if (!ref.current) { 3008 return; 3009 } 3010 const { 3011 ownerDocument: { defaultView } 3012 } = ref.current; 3013 const selection = defaultView.getSelection(); 3014 if (!selection.rangeCount) { 3015 return; 3016 } 3017 const range = selection.getRangeAt(0); 3018 if (!activeFormat) { 3019 return range; 3020 } 3021 let element = range.startContainer; 3022 element = element.nextElementSibling || element; 3023 while (element.nodeType !== element.ELEMENT_NODE) { 3024 element = element.parentNode; 3025 } 3026 return element.closest( 3027 tagName + (className ? "." + className : "") 3028 ); 3029 }, [activeFormat, value.start, value.end, tagName, className]); 3030 } 3031 3032 // packages/rich-text/build-module/hook/use-anchor.mjs 3033 var import_compose11 = __toESM(require_compose(), 1); 3034 var import_element10 = __toESM(require_element(), 1); 3035 var import_dom = __toESM(require_dom(), 1); 3036 function getFormatElement(range, editableContentElement, tagName, className) { 3037 let element = range.startContainer; 3038 if (element.nodeType === element.TEXT_NODE && element instanceof window.Text && range.startOffset === element.length && element.nextSibling) { 3039 element = element.nextSibling; 3040 while (element.firstChild) { 3041 element = element.firstChild; 3042 } 3043 } 3044 if (element.nodeType !== element.ELEMENT_NODE) { 3045 if (!element.parentElement) { 3046 return; 3047 } 3048 element = element.parentElement; 3049 } 3050 if (element === editableContentElement) { 3051 return; 3052 } 3053 if (!editableContentElement.contains(element)) { 3054 return; 3055 } 3056 const selector = tagName + (className ? "." + className : ""); 3057 if (!selector) { 3058 return; 3059 } 3060 if (!(element instanceof window.HTMLElement)) { 3061 return; 3062 } 3063 let closestElement = element; 3064 while (closestElement && closestElement !== editableContentElement) { 3065 if (closestElement.matches(selector)) { 3066 return closestElement; 3067 } 3068 closestElement = closestElement.parentElement; 3069 } 3070 return void 0; 3071 } 3072 function createVirtualAnchorElement(range, editableContentElement) { 3073 return { 3074 contextElement: editableContentElement, 3075 getBoundingClientRect() { 3076 if (editableContentElement.contains(range.startContainer)) { 3077 return (0, import_dom.getRectangleFromRange)(range) ?? range.getBoundingClientRect(); 3078 } 3079 return editableContentElement.getBoundingClientRect(); 3080 } 3081 }; 3082 } 3083 function getAnchor(editableContentElement, tagName, className) { 3084 if (!editableContentElement) { 3085 return; 3086 } 3087 const { ownerDocument } = editableContentElement; 3088 const { defaultView } = ownerDocument; 3089 const selection = defaultView?.getSelection(); 3090 if (!selection) { 3091 return; 3092 } 3093 if (!selection.rangeCount) { 3094 return; 3095 } 3096 const range = selection.getRangeAt(0); 3097 if (!range || !range.startContainer) { 3098 return; 3099 } 3100 if (!tagName && !className) { 3101 return createVirtualAnchorElement(range, editableContentElement); 3102 } 3103 return getFormatElement(range, editableContentElement, tagName, className) ?? createVirtualAnchorElement(range, editableContentElement); 3104 } 3105 var DEFAULT_SETTINGS = { 3106 tagName: "", 3107 className: "" 3108 }; 3109 function useAnchor({ 3110 editableContentElement, 3111 settings 3112 }) { 3113 const { tagName, className } = settings ?? DEFAULT_SETTINGS; 3114 const isActive = !!(settings && "isActive" in settings && settings.isActive); 3115 const [anchor, setAnchor] = (0, import_element10.useState)( 3116 () => getAnchor(editableContentElement, tagName, className ?? "") 3117 ); 3118 const wasActive = (0, import_compose11.usePrevious)(isActive); 3119 (0, import_element10.useLayoutEffect)(() => { 3120 if (!editableContentElement) { 3121 return; 3122 } 3123 function callback() { 3124 setAnchor( 3125 getAnchor(editableContentElement, tagName, className ?? "") 3126 ); 3127 } 3128 function attach() { 3129 ownerDocument.addEventListener("selectionchange", callback); 3130 } 3131 function detach() { 3132 ownerDocument.removeEventListener("selectionchange", callback); 3133 } 3134 const { ownerDocument } = editableContentElement; 3135 if (ownsSelection(editableContentElement) || // When a link is created, we need to attach the popover to the newly created anchor. 3136 !wasActive && isActive || // Sometimes we're _removing_ an active anchor, such as the inline color popover. 3137 // When we add the color, it switches from a virtual anchor to a `<mark>` element. 3138 // When we _remove_ the color, it switches from a `<mark>` element to a virtual anchor. 3139 wasActive && !isActive) { 3140 setAnchor( 3141 getAnchor(editableContentElement, tagName, className ?? "") 3142 ); 3143 attach(); 3144 } 3145 editableContentElement.addEventListener("focusin", attach); 3146 editableContentElement.addEventListener("focusout", detach); 3147 return () => { 3148 detach(); 3149 editableContentElement.removeEventListener("focusin", attach); 3150 editableContentElement.removeEventListener("focusout", detach); 3151 }; 3152 }, [editableContentElement, tagName, className, isActive, wasActive]); 3153 return anchor; 3154 } 3155 3156 // packages/rich-text/build-module/index.mjs 3157 function __experimentalRichText() { 3158 } 3159 return __toCommonJS(index_exports); 3160 })(); 3161 (window.wp ||= {}).richText = wp.richText; 3162 })();
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
| Generated : Mon Sep 14 08:20:31 2026 | Cross-referenced by PHPXref |