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