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