PluginProbe
Gutenberg / 24.1.0
Gutenberg v24.1.0
24.1.0 24.0.0 23.9.1 23.9.0 23.8.0 23.7.2 23.7.1 23.7.0 23.6.1 23.6.2 23.6.0 23.5.3 23.5.2 23.5.1 23.5.0 23.4.0 23.3.2 23.3.1 23.3.0 23.2.0 23.2.1 23.2.2 23.1.1 23.1.0 23.0.1 All 404 releases
gutenberg / build / scripts / rich-text / index.js

index.js in Gutenberg 24.1.0, at build/scripts/rich-text/index.js

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