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