PluginProbe
Gutenberg / 23.2.2
Gutenberg v23.2.2
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 12.6.0 7.4.0 All 402 releases
gutenberg / build / scripts / rich-text / index.js

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

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