PluginProbe
Gutenberg / 23.4.0
Gutenberg v23.4.0
23.9.1 23.9.0 23.8.0 23.7.2 23.7.1 23.7.0 23.6.1 23.6.2 23.6.0 23.5.3 23.5.2 23.5.1 23.5.0 23.4.0 23.3.2 23.3.1 23.3.0 23.2.0 23.2.1 23.2.2 23.1.1 23.1.0 23.0.1 12.6.0 7.4.0 All 402 releases
gutenberg / build / scripts / rich-text / index.js

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

2,981 lines 99.1 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_compose9 = __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_compose8 = __toESM(require_compose(), 1);
1957
1958 // packages/rich-text/build-module/hook/event-listeners/copy-handler.mjs
1959 var import_compose = __toESM(require_compose(), 1);
1960 var { subscribeDelegatedListener } = unlock(import_compose.privateApis);
1961 var copy_handler_default = (props) => (element) => {
1962 function onCopy(event) {
1963 const { record } = props.current;
1964 const { ownerDocument } = element;
1965 if (isCollapsed(record.current) || !element.contains(ownerDocument.activeElement)) {
1966 return;
1967 }
1968 const selectedRecord = slice(record.current);
1969 const plainText = getTextContent(selectedRecord);
1970 const html = toHTMLString({ value: selectedRecord });
1971 event.clipboardData.setData("text/plain", plainText);
1972 event.clipboardData.setData("text/html", html);
1973 event.clipboardData.setData("rich-text", "true");
1974 event.preventDefault();
1975 if (event.type === "cut") {
1976 ownerDocument.execCommand("delete");
1977 }
1978 }
1979 const { defaultView } = element.ownerDocument;
1980 const unsubscribeCopy = subscribeDelegatedListener(
1981 defaultView,
1982 "copy",
1983 onCopy
1984 );
1985 const unsubscribeCut = subscribeDelegatedListener(
1986 defaultView,
1987 "cut",
1988 onCopy
1989 );
1990 return () => {
1991 unsubscribeCopy();
1992 unsubscribeCut();
1993 };
1994 };
1995
1996 // packages/rich-text/build-module/hook/event-listeners/select-object.mjs
1997 var import_compose2 = __toESM(require_compose(), 1);
1998 var { subscribeDelegatedListener: subscribeDelegatedListener2 } = unlock(import_compose2.privateApis);
1999 var select_object_default = () => (element) => {
2000 function onClick(event) {
2001 const { target } = event;
2002 if (target === element || target.textContent && target.isContentEditable) {
2003 return;
2004 }
2005 const { ownerDocument } = target;
2006 const { defaultView } = ownerDocument;
2007 const selection = defaultView.getSelection();
2008 if (selection.containsNode(target)) {
2009 return;
2010 }
2011 const range = ownerDocument.createRange();
2012 const nodeToSelect = target.isContentEditable ? target : target.closest("[contenteditable]");
2013 range.selectNode(nodeToSelect);
2014 selection.removeAllRanges();
2015 selection.addRange(range);
2016 event.preventDefault();
2017 }
2018 function onFocusIn(event) {
2019 if (event.relatedTarget && !element.contains(event.relatedTarget) && event.relatedTarget.tagName === "A") {
2020 onClick(event);
2021 }
2022 }
2023 const unsubscribeClick = subscribeDelegatedListener2(
2024 element,
2025 "click",
2026 onClick
2027 );
2028 const unsubscribeFocusIn = subscribeDelegatedListener2(
2029 element,
2030 "focusin",
2031 onFocusIn
2032 );
2033 return () => {
2034 unsubscribeClick();
2035 unsubscribeFocusIn();
2036 };
2037 };
2038
2039 // packages/rich-text/build-module/hook/event-listeners/format-boundaries.mjs
2040 var import_keycodes = __toESM(require_keycodes(), 1);
2041 var import_compose3 = __toESM(require_compose(), 1);
2042 var { subscribeDelegatedListener: subscribeDelegatedListener3 } = unlock(import_compose3.privateApis);
2043 var EMPTY_ACTIVE_FORMATS = [];
2044 var format_boundaries_default = (props) => (element) => {
2045 function onKeyDown(event) {
2046 const { keyCode, shiftKey, altKey, metaKey, ctrlKey } = event;
2047 if (
2048 // Only override left and right keys without modifiers pressed.
2049 shiftKey || altKey || metaKey || ctrlKey || keyCode !== import_keycodes.LEFT && keyCode !== import_keycodes.RIGHT
2050 ) {
2051 return;
2052 }
2053 const { record, applyRecord, forceRender } = props.current;
2054 const {
2055 text,
2056 formats,
2057 start,
2058 end,
2059 activeFormats: currentActiveFormats = []
2060 } = record.current;
2061 const collapsed = isCollapsed(record.current);
2062 const { defaultView } = element.ownerDocument;
2063 const { direction } = defaultView.getComputedStyle(element);
2064 const reverseKey = direction === "rtl" ? import_keycodes.RIGHT : import_keycodes.LEFT;
2065 const isReverse = event.keyCode === reverseKey;
2066 if (collapsed && currentActiveFormats.length === 0) {
2067 if (start === 0 && isReverse) {
2068 return;
2069 }
2070 if (end === text.length && !isReverse) {
2071 return;
2072 }
2073 }
2074 if (!collapsed) {
2075 return;
2076 }
2077 const formatsBefore = formats[start - 1] || EMPTY_ACTIVE_FORMATS;
2078 const formatsAfter = formats[start] || EMPTY_ACTIVE_FORMATS;
2079 const destination = isReverse ? formatsBefore : formatsAfter;
2080 const isIncreasing = currentActiveFormats.every(
2081 (format, index) => format === destination[index]
2082 );
2083 let newActiveFormatsLength = currentActiveFormats.length;
2084 if (!isIncreasing) {
2085 newActiveFormatsLength--;
2086 } else if (newActiveFormatsLength < destination.length) {
2087 newActiveFormatsLength++;
2088 }
2089 if (newActiveFormatsLength === currentActiveFormats.length) {
2090 record.current._newActiveFormats = destination;
2091 return;
2092 }
2093 event.preventDefault();
2094 const origin = isReverse ? formatsAfter : formatsBefore;
2095 const source = isIncreasing ? destination : origin;
2096 const newActiveFormats = source.slice(0, newActiveFormatsLength);
2097 const newValue = {
2098 ...record.current,
2099 activeFormats: newActiveFormats
2100 };
2101 record.current = newValue;
2102 applyRecord(newValue);
2103 forceRender();
2104 }
2105 return subscribeDelegatedListener3(element, "keydown", onKeyDown, true);
2106 };
2107
2108 // packages/rich-text/build-module/hook/event-listeners/delete.mjs
2109 var import_keycodes2 = __toESM(require_keycodes(), 1);
2110 var import_compose4 = __toESM(require_compose(), 1);
2111 var { subscribeDelegatedListener: subscribeDelegatedListener4 } = unlock(import_compose4.privateApis);
2112 var delete_default = (props) => (element) => {
2113 function onKeyDown(event) {
2114 const { keyCode } = event;
2115 if (event.defaultPrevented) {
2116 return;
2117 }
2118 if (keyCode !== import_keycodes2.DELETE && keyCode !== import_keycodes2.BACKSPACE) {
2119 return;
2120 }
2121 const { createRecord, handleChange } = props.current;
2122 const currentValue = createRecord();
2123 const { start, end, text } = currentValue;
2124 if (start === 0 && end !== 0 && end === text.length) {
2125 handleChange(remove2(currentValue));
2126 event.preventDefault();
2127 }
2128 }
2129 return subscribeDelegatedListener4(element, "keydown", onKeyDown);
2130 };
2131
2132 // packages/rich-text/build-module/hook/event-listeners/input-and-selection.mjs
2133 var import_compose5 = __toESM(require_compose(), 1);
2134
2135 // packages/rich-text/build-module/update-formats.mjs
2136 function updateFormats({ value, start, end, formats }) {
2137 const min = Math.min(start, end);
2138 const max = Math.max(start, end);
2139 const formatsBefore = value.formats[min - 1] || [];
2140 const formatsAfter = value.formats[max] || [];
2141 value.activeFormats = formats.map((format, index) => {
2142 if (formatsBefore[index]) {
2143 if (isFormatEqual(format, formatsBefore[index])) {
2144 return formatsBefore[index];
2145 }
2146 } else if (formatsAfter[index]) {
2147 if (isFormatEqual(format, formatsAfter[index])) {
2148 return formatsAfter[index];
2149 }
2150 }
2151 return format;
2152 });
2153 while (--end >= start) {
2154 if (value.activeFormats.length > 0) {
2155 value.formats[end] = value.activeFormats;
2156 } else {
2157 delete value.formats[end];
2158 }
2159 }
2160 return value;
2161 }
2162
2163 // packages/rich-text/build-module/hook/event-listeners/input-and-selection.mjs
2164 var { subscribeDelegatedListener: subscribeDelegatedListener5 } = unlock(import_compose5.privateApis);
2165 var INSERTION_INPUT_TYPES_TO_IGNORE = /* @__PURE__ */ new Set([
2166 "insertParagraph",
2167 "insertOrderedList",
2168 "insertUnorderedList",
2169 "insertHorizontalRule",
2170 "insertLink"
2171 ]);
2172 var EMPTY_ACTIVE_FORMATS2 = [];
2173 var PLACEHOLDER_ATTR_NAME = "data-rich-text-placeholder";
2174 function fixPlaceholderSelection(defaultView) {
2175 const selection = defaultView.getSelection();
2176 const { anchorNode, anchorOffset } = selection;
2177 if (anchorNode.nodeType !== anchorNode.ELEMENT_NODE) {
2178 return;
2179 }
2180 const targetNode = anchorNode.childNodes[anchorOffset];
2181 if (!targetNode || targetNode.nodeType !== targetNode.ELEMENT_NODE || !targetNode.hasAttribute(PLACEHOLDER_ATTR_NAME)) {
2182 return;
2183 }
2184 selection.collapseToStart();
2185 }
2186 var input_and_selection_default = (props) => (element) => {
2187 const { ownerDocument } = element;
2188 const { defaultView } = ownerDocument;
2189 let isComposing = false;
2190 function onInput(event) {
2191 if (isComposing) {
2192 return;
2193 }
2194 let inputType;
2195 if (event) {
2196 inputType = event.inputType;
2197 }
2198 const { record, applyRecord, createRecord, handleChange } = props.current;
2199 if (inputType && (inputType.indexOf("format") === 0 || INSERTION_INPUT_TYPES_TO_IGNORE.has(inputType))) {
2200 applyRecord(record.current);
2201 return;
2202 }
2203 const currentValue = createRecord();
2204 const { start, activeFormats: oldActiveFormats = [] } = record.current;
2205 const clearFormats = !isCollapsed(record.current) && currentValue.start <= start;
2206 const change = updateFormats({
2207 value: currentValue,
2208 start,
2209 end: currentValue.start,
2210 formats: clearFormats ? [] : oldActiveFormats
2211 });
2212 handleChange(change);
2213 }
2214 function handleSelectionChange() {
2215 const { record, applyRecord, createRecord, onSelectionChange } = props.current;
2216 if (element.contentEditable !== "true") {
2217 return;
2218 }
2219 if (ownerDocument.activeElement !== element) {
2220 ownerDocument.removeEventListener(
2221 "selectionchange",
2222 handleSelectionChange
2223 );
2224 return;
2225 }
2226 if (isComposing) {
2227 return;
2228 }
2229 const { start, end, text } = createRecord();
2230 const oldRecord = record.current;
2231 if (text !== oldRecord.text) {
2232 onInput();
2233 return;
2234 }
2235 if (start === oldRecord.start && end === oldRecord.end) {
2236 if (oldRecord.text.length === 0 && start === 0) {
2237 fixPlaceholderSelection(defaultView);
2238 }
2239 return;
2240 }
2241 const newValue = {
2242 ...oldRecord,
2243 start,
2244 end,
2245 // _newActiveFormats may be set on arrow key navigation to control
2246 // the right boundary position. If undefined, getActiveFormats will
2247 // give the active formats according to the browser.
2248 activeFormats: oldRecord._newActiveFormats,
2249 _newActiveFormats: void 0
2250 };
2251 const newActiveFormats = getActiveFormats(
2252 newValue,
2253 EMPTY_ACTIVE_FORMATS2
2254 );
2255 newValue.activeFormats = newActiveFormats;
2256 record.current = newValue;
2257 applyRecord(newValue, { domOnly: true });
2258 onSelectionChange(start, end);
2259 }
2260 function onCompositionStart() {
2261 isComposing = true;
2262 ownerDocument.removeEventListener(
2263 "selectionchange",
2264 handleSelectionChange
2265 );
2266 element.querySelector(`[${PLACEHOLDER_ATTR_NAME}]`)?.remove();
2267 }
2268 function onCompositionEnd() {
2269 isComposing = false;
2270 onInput({ inputType: "insertText" });
2271 ownerDocument.addEventListener(
2272 "selectionchange",
2273 handleSelectionChange
2274 );
2275 }
2276 function onFocus(event) {
2277 if (event.target !== element) {
2278 return;
2279 }
2280 if (element.contentEditable !== "true") {
2281 return;
2282 }
2283 const { record, isSelected, onSelectionChange, applyRecord } = props.current;
2284 if (element.parentElement.closest('[contenteditable="true"]')) {
2285 return;
2286 }
2287 if (!isSelected) {
2288 const index = void 0;
2289 record.current = {
2290 ...record.current,
2291 start: index,
2292 end: index,
2293 activeFormats: EMPTY_ACTIVE_FORMATS2
2294 };
2295 } else {
2296 applyRecord(record.current, { domOnly: true });
2297 }
2298 onSelectionChange(record.current.start, record.current.end);
2299 window.queueMicrotask(handleSelectionChange);
2300 ownerDocument.addEventListener(
2301 "selectionchange",
2302 handleSelectionChange
2303 );
2304 }
2305 const unsubscribeInput = subscribeDelegatedListener5(
2306 element,
2307 "input",
2308 onInput,
2309 true
2310 );
2311 const unsubscribeCompositionStart = subscribeDelegatedListener5(
2312 element,
2313 "compositionstart",
2314 onCompositionStart
2315 );
2316 const unsubscribeCompositionEnd = subscribeDelegatedListener5(
2317 element,
2318 "compositionend",
2319 onCompositionEnd,
2320 true
2321 );
2322 const unsubscribeFocus = subscribeDelegatedListener5(
2323 element,
2324 "focusin",
2325 onFocus
2326 );
2327 return () => {
2328 unsubscribeInput();
2329 unsubscribeCompositionStart();
2330 unsubscribeCompositionEnd();
2331 unsubscribeFocus();
2332 };
2333 };
2334
2335 // packages/rich-text/build-module/hook/event-listeners/selection-change-compat.mjs
2336 var import_compose6 = __toESM(require_compose(), 1);
2337 var { subscribeDelegatedListener: subscribeDelegatedListener6 } = unlock(import_compose6.privateApis);
2338 var selection_change_compat_default = () => (element) => {
2339 const { ownerDocument } = element;
2340 const { defaultView } = ownerDocument;
2341 const selection = defaultView?.getSelection();
2342 let range;
2343 function getRange() {
2344 return selection.rangeCount ? selection.getRangeAt(0) : null;
2345 }
2346 function onDown(event) {
2347 const type = event.type === "keydown" ? "keyup" : "pointerup";
2348 function onCancel() {
2349 ownerDocument.removeEventListener(type, onUp);
2350 ownerDocument.removeEventListener("selectionchange", onCancel);
2351 ownerDocument.removeEventListener("input", onCancel);
2352 }
2353 function onUp() {
2354 onCancel();
2355 if (isRangeEqual(range, getRange())) {
2356 return;
2357 }
2358 ownerDocument.dispatchEvent(new Event("selectionchange"));
2359 }
2360 ownerDocument.addEventListener(type, onUp);
2361 ownerDocument.addEventListener("selectionchange", onCancel);
2362 ownerDocument.addEventListener("input", onCancel);
2363 range = getRange();
2364 }
2365 const unsubscribePointerDown = subscribeDelegatedListener6(
2366 element,
2367 "pointerdown",
2368 onDown
2369 );
2370 const unsubscribeKeyDown = subscribeDelegatedListener6(
2371 element,
2372 "keydown",
2373 onDown
2374 );
2375 return () => {
2376 unsubscribePointerDown();
2377 unsubscribeKeyDown();
2378 };
2379 };
2380
2381 // packages/rich-text/build-module/hook/event-listeners/prevent-focus-capture.mjs
2382 var import_compose7 = __toESM(require_compose(), 1);
2383 var { subscribeDelegatedListener: subscribeDelegatedListener7 } = unlock(import_compose7.privateApis);
2384 function preventFocusCapture() {
2385 return (element) => {
2386 const { ownerDocument } = element;
2387 const { defaultView } = ownerDocument;
2388 let value = null;
2389 function onPointerDown(event) {
2390 if (event.defaultPrevented) {
2391 return;
2392 }
2393 if (event.target === element) {
2394 return;
2395 }
2396 if (!event.target.contains(element)) {
2397 return;
2398 }
2399 value = element.getAttribute("contenteditable");
2400 element.setAttribute("contenteditable", "false");
2401 defaultView.getSelection().removeAllRanges();
2402 }
2403 function onPointerUp() {
2404 if (value !== null) {
2405 element.setAttribute("contenteditable", value);
2406 value = null;
2407 }
2408 }
2409 const unsubscribePointerDown = subscribeDelegatedListener7(
2410 defaultView,
2411 "pointerdown",
2412 onPointerDown
2413 );
2414 const unsubscribePointerUp = subscribeDelegatedListener7(
2415 defaultView,
2416 "pointerup",
2417 onPointerUp
2418 );
2419 return () => {
2420 unsubscribePointerDown();
2421 unsubscribePointerUp();
2422 };
2423 };
2424 }
2425
2426 // packages/rich-text/build-module/hook/event-listeners/index.mjs
2427 var allEventListeners = [
2428 copy_handler_default,
2429 select_object_default,
2430 format_boundaries_default,
2431 delete_default,
2432 input_and_selection_default,
2433 selection_change_compat_default,
2434 preventFocusCapture
2435 ];
2436 function useEventListeners(props) {
2437 const propsRef = (0, import_element3.useRef)(props);
2438 (0, import_element3.useInsertionEffect)(() => {
2439 propsRef.current = props;
2440 });
2441 const refEffects = (0, import_element3.useMemo)(
2442 () => allEventListeners.map((refEffect) => refEffect(propsRef)),
2443 [propsRef]
2444 );
2445 return (0, import_compose8.useRefEffect)(
2446 (element) => {
2447 const cleanups = refEffects.map((effect) => effect(element));
2448 return () => {
2449 cleanups.forEach((cleanup) => cleanup());
2450 };
2451 },
2452 [refEffects]
2453 );
2454 }
2455
2456 // packages/rich-text/build-module/hook/use-format-types.mjs
2457 var import_element4 = __toESM(require_element(), 1);
2458 var import_data8 = __toESM(require_data(), 1);
2459 function formatTypesSelector(select5) {
2460 return select5(store).getFormatTypes();
2461 }
2462 var interactiveContentTags = /* @__PURE__ */ new Set([
2463 "a",
2464 "audio",
2465 "button",
2466 "details",
2467 "embed",
2468 "iframe",
2469 "input",
2470 "label",
2471 "select",
2472 "textarea",
2473 "video"
2474 ]);
2475 function prefixSelectKeys(selected, prefix) {
2476 if (typeof selected !== "object") {
2477 return { [prefix]: selected };
2478 }
2479 return Object.fromEntries(
2480 Object.entries(selected).map(([key, value]) => [
2481 `${prefix}.${key}`,
2482 value
2483 ])
2484 );
2485 }
2486 function getPrefixedSelectKeys(selected, prefix) {
2487 if (selected[prefix]) {
2488 return selected[prefix];
2489 }
2490 return Object.keys(selected).filter((key) => key.startsWith(prefix + ".")).reduce((accumulator, key) => {
2491 accumulator[key.slice(prefix.length + 1)] = selected[key];
2492 return accumulator;
2493 }, {});
2494 }
2495 function useFormatTypes({
2496 allowedFormats,
2497 withoutInteractiveFormatting,
2498 __unstableFormatTypeHandlerContext
2499 }) {
2500 const allFormatTypes = (0, import_data8.useSelect)(formatTypesSelector, []);
2501 const formatTypes2 = (0, import_element4.useMemo)(() => {
2502 return allFormatTypes.filter(({ name, interactive, tagName }) => {
2503 if (allowedFormats && !allowedFormats.includes(name)) {
2504 return false;
2505 }
2506 if (withoutInteractiveFormatting && (interactive || interactiveContentTags.has(tagName))) {
2507 return false;
2508 }
2509 return true;
2510 });
2511 }, [allFormatTypes, allowedFormats, withoutInteractiveFormatting]);
2512 const keyedSelected = (0, import_data8.useSelect)(
2513 (select5) => formatTypes2.reduce((accumulator, type) => {
2514 if (!type.__experimentalGetPropsForEditableTreePreparation || !__unstableFormatTypeHandlerContext) {
2515 return accumulator;
2516 }
2517 return {
2518 ...accumulator,
2519 ...prefixSelectKeys(
2520 type.__experimentalGetPropsForEditableTreePreparation(
2521 select5,
2522 __unstableFormatTypeHandlerContext
2523 ),
2524 type.name
2525 )
2526 };
2527 }, {}),
2528 [formatTypes2, __unstableFormatTypeHandlerContext]
2529 );
2530 const dispatch3 = (0, import_data8.useDispatch)();
2531 const prepareHandlers = [];
2532 const valueHandlers = [];
2533 const changeHandlers = [];
2534 const dependencies = [];
2535 for (const key in keyedSelected) {
2536 dependencies.push(keyedSelected[key]);
2537 }
2538 formatTypes2.forEach((type) => {
2539 if (type.__experimentalCreatePrepareEditableTree && __unstableFormatTypeHandlerContext) {
2540 const handler = type.__experimentalCreatePrepareEditableTree(
2541 getPrefixedSelectKeys(keyedSelected, type.name),
2542 __unstableFormatTypeHandlerContext
2543 );
2544 if (type.__experimentalCreateOnChangeEditableValue) {
2545 valueHandlers.push(handler);
2546 } else {
2547 prepareHandlers.push(handler);
2548 }
2549 }
2550 if (type.__experimentalCreateOnChangeEditableValue && __unstableFormatTypeHandlerContext) {
2551 let dispatchers = {};
2552 if (type.__experimentalGetPropsForEditableTreeChangeHandler) {
2553 dispatchers = type.__experimentalGetPropsForEditableTreeChangeHandler(
2554 dispatch3,
2555 __unstableFormatTypeHandlerContext
2556 );
2557 }
2558 const selected = getPrefixedSelectKeys(keyedSelected, type.name);
2559 changeHandlers.push(
2560 type.__experimentalCreateOnChangeEditableValue(
2561 {
2562 ...typeof selected === "object" ? selected : {},
2563 ...dispatchers
2564 },
2565 __unstableFormatTypeHandlerContext
2566 )
2567 );
2568 }
2569 });
2570 return {
2571 formatTypes: formatTypes2,
2572 prepareHandlers,
2573 valueHandlers,
2574 changeHandlers,
2575 dependencies
2576 };
2577 }
2578
2579 // packages/rich-text/build-module/hook/index.mjs
2580 function useRichTextBase({
2581 value = "",
2582 selectionStart,
2583 selectionEnd,
2584 placeholder,
2585 onSelectionChange,
2586 preserveWhiteSpace,
2587 onChange,
2588 __unstableDisableFormats: disableFormats,
2589 __unstableIsSelected: isSelected,
2590 __unstableDependencies = [],
2591 __unstableAfterParse,
2592 __unstableBeforeSerialize,
2593 __unstableAddInvisibleFormats
2594 }) {
2595 const registry = (0, import_data9.useRegistry)();
2596 const [, forceRender] = (0, import_element5.useReducer)(() => ({}));
2597 const ref = (0, import_element5.useRef)();
2598 function createRecord() {
2599 const {
2600 ownerDocument: { defaultView }
2601 } = ref.current;
2602 const selection = defaultView.getSelection();
2603 const range = selection.rangeCount > 0 ? selection.getRangeAt(0) : null;
2604 return create({
2605 element: ref.current,
2606 range,
2607 __unstableIsEditableTree: true
2608 });
2609 }
2610 function applyRecord(newRecord, { domOnly } = {}) {
2611 apply({
2612 value: newRecord,
2613 current: ref.current,
2614 prepareEditableTree: __unstableAddInvisibleFormats,
2615 __unstableDomOnly: domOnly,
2616 placeholder
2617 });
2618 }
2619 const _valueRef = (0, import_element5.useRef)(value);
2620 const recordRef = (0, import_element5.useRef)();
2621 function setRecordFromProps() {
2622 const activeFormats = recordRef.current?.activeFormats;
2623 _valueRef.current = value;
2624 recordRef.current = value;
2625 if (!(value instanceof RichTextData)) {
2626 recordRef.current = value ? RichTextData.fromHTMLString(value, { preserveWhiteSpace }) : RichTextData.empty();
2627 }
2628 recordRef.current = {
2629 text: recordRef.current.text,
2630 formats: recordRef.current.formats,
2631 replacements: recordRef.current.replacements,
2632 activeFormats
2633 };
2634 if (disableFormats) {
2635 recordRef.current.formats = Array(value.length);
2636 recordRef.current.replacements = Array(value.length);
2637 }
2638 if (__unstableAfterParse) {
2639 recordRef.current.formats = __unstableAfterParse(
2640 recordRef.current
2641 );
2642 }
2643 recordRef.current.start = selectionStart;
2644 recordRef.current.end = selectionEnd;
2645 }
2646 const hadSelectionUpdateRef = (0, import_element5.useRef)(false);
2647 if (!recordRef.current) {
2648 hadSelectionUpdateRef.current = isSelected;
2649 setRecordFromProps();
2650 } else if (selectionStart !== recordRef.current.start || selectionEnd !== recordRef.current.end) {
2651 hadSelectionUpdateRef.current = isSelected;
2652 recordRef.current = {
2653 ...recordRef.current,
2654 start: selectionStart,
2655 end: selectionEnd,
2656 activeFormats: void 0
2657 };
2658 }
2659 function handleChange(newRecord) {
2660 recordRef.current = newRecord;
2661 applyRecord(newRecord);
2662 if (disableFormats) {
2663 _valueRef.current = newRecord.text;
2664 } else {
2665 const newFormats = __unstableBeforeSerialize ? __unstableBeforeSerialize(newRecord) : newRecord.formats;
2666 newRecord = { ...newRecord, formats: newFormats };
2667 if (typeof value === "string") {
2668 _valueRef.current = toHTMLString({
2669 value: newRecord,
2670 preserveWhiteSpace
2671 });
2672 } else {
2673 _valueRef.current = new RichTextData(newRecord);
2674 }
2675 }
2676 const { start, end, formats, text } = recordRef.current;
2677 registry.batch(() => {
2678 onSelectionChange(start, end);
2679 onChange(_valueRef.current, {
2680 __unstableFormats: formats,
2681 __unstableText: text
2682 });
2683 });
2684 forceRender();
2685 }
2686 function applyFromProps() {
2687 const previousValue = _valueRef.current;
2688 setRecordFromProps();
2689 const contentLengthChanged = previousValue && typeof previousValue === "string" && typeof value === "string" && previousValue.length !== value.length;
2690 const hasFocus = ref.current?.contains(
2691 ref.current.ownerDocument.activeElement
2692 );
2693 const skipSelection = contentLengthChanged && !hasFocus;
2694 applyRecord(recordRef.current, { domOnly: skipSelection });
2695 }
2696 const didMountRef = (0, import_element5.useRef)(false);
2697 (0, import_element5.useLayoutEffect)(() => {
2698 if (didMountRef.current && value !== _valueRef.current) {
2699 applyFromProps();
2700 forceRender();
2701 }
2702 }, [value]);
2703 (0, import_element5.useLayoutEffect)(() => {
2704 if (!hadSelectionUpdateRef.current) {
2705 return;
2706 }
2707 if (ref.current.ownerDocument.activeElement !== ref.current) {
2708 ref.current.focus();
2709 }
2710 applyRecord(recordRef.current);
2711 hadSelectionUpdateRef.current = false;
2712 }, [hadSelectionUpdateRef.current]);
2713 const mergedRefs = (0, import_compose9.useMergeRefs)([
2714 ref,
2715 useDefaultStyle(),
2716 useBoundaryStyle({ record: recordRef }),
2717 useEventListeners({
2718 record: recordRef,
2719 handleChange,
2720 applyRecord,
2721 createRecord,
2722 isSelected,
2723 onSelectionChange,
2724 forceRender
2725 }),
2726 (0, import_compose9.useRefEffect)(() => {
2727 applyFromProps();
2728 didMountRef.current = true;
2729 }, [placeholder, ...__unstableDependencies])
2730 ]);
2731 return {
2732 value: recordRef.current,
2733 // A function to get the most recent value so event handlers in
2734 // useRichText implementations have access to it. For example when
2735 // listening to input events, we internally update the state, but this
2736 // state is not yet available to the input event handler because React
2737 // may re-render asynchronously.
2738 getValue: () => recordRef.current,
2739 onChange: handleChange,
2740 ref: mergedRefs
2741 };
2742 }
2743 function useRichText({
2744 allowedFormats,
2745 withoutInteractiveFormatting,
2746 onChange,
2747 __unstableDependencies = [],
2748 __unstableFormatTypeHandlerContext,
2749 ...props
2750 }) {
2751 const {
2752 formatTypes: formatTypes2,
2753 prepareHandlers,
2754 valueHandlers,
2755 changeHandlers,
2756 dependencies
2757 } = useFormatTypes({
2758 allowedFormats,
2759 withoutInteractiveFormatting,
2760 __unstableFormatTypeHandlerContext
2761 });
2762 function addEditorOnlyFormats(record) {
2763 return valueHandlers.reduce(
2764 (accumulator, fn) => fn(accumulator, record.text),
2765 record.formats
2766 );
2767 }
2768 function removeEditorOnlyFormats(record) {
2769 formatTypes2.forEach((formatType) => {
2770 if (formatType.__experimentalCreatePrepareEditableTree) {
2771 record = removeFormat(
2772 record,
2773 formatType.name,
2774 0,
2775 record.text.length
2776 );
2777 }
2778 });
2779 return record.formats;
2780 }
2781 function addInvisibleFormats(record) {
2782 return prepareHandlers.reduce(
2783 (accumulator, fn) => fn(accumulator, record.text),
2784 record.formats
2785 );
2786 }
2787 const result = useRichTextBase({
2788 ...props,
2789 onChange(value, { __unstableFormats, __unstableText }) {
2790 onChange(value, { __unstableFormats, __unstableText });
2791 Object.values(changeHandlers).forEach((changeHandler) => {
2792 changeHandler(__unstableFormats, __unstableText);
2793 });
2794 },
2795 __unstableDependencies: [...dependencies, ...__unstableDependencies],
2796 __unstableAfterParse: addEditorOnlyFormats,
2797 __unstableBeforeSerialize: removeEditorOnlyFormats,
2798 __unstableAddInvisibleFormats: addInvisibleFormats
2799 });
2800 return { ...result, formatTypes: formatTypes2 };
2801 }
2802 function useDeprecatedRichText(props) {
2803 (0, import_deprecated.default)("`__unstableUseRichText` hook", {
2804 since: "7.0"
2805 });
2806 return useRichTextBase(props);
2807 }
2808
2809 // packages/rich-text/build-module/private-apis.mjs
2810 var privateApis = {};
2811 lock(privateApis, {
2812 useRichText
2813 });
2814
2815 // packages/rich-text/build-module/hook/use-anchor-ref.mjs
2816 var import_element6 = __toESM(require_element(), 1);
2817 var import_deprecated2 = __toESM(require_deprecated(), 1);
2818 function useAnchorRef({ ref, value, settings = {} }) {
2819 (0, import_deprecated2.default)("`useAnchorRef` hook", {
2820 since: "6.1",
2821 alternative: "`useAnchor` hook"
2822 });
2823 const { tagName, className, name } = settings;
2824 const activeFormat = name ? getActiveFormat(value, name) : void 0;
2825 return (0, import_element6.useMemo)(() => {
2826 if (!ref.current) {
2827 return;
2828 }
2829 const {
2830 ownerDocument: { defaultView }
2831 } = ref.current;
2832 const selection = defaultView.getSelection();
2833 if (!selection.rangeCount) {
2834 return;
2835 }
2836 const range = selection.getRangeAt(0);
2837 if (!activeFormat) {
2838 return range;
2839 }
2840 let element = range.startContainer;
2841 element = element.nextElementSibling || element;
2842 while (element.nodeType !== element.ELEMENT_NODE) {
2843 element = element.parentNode;
2844 }
2845 return element.closest(
2846 tagName + (className ? "." + className : "")
2847 );
2848 }, [activeFormat, value.start, value.end, tagName, className]);
2849 }
2850
2851 // packages/rich-text/build-module/hook/use-anchor.mjs
2852 var import_compose10 = __toESM(require_compose(), 1);
2853 var import_element7 = __toESM(require_element(), 1);
2854 var import_dom = __toESM(require_dom(), 1);
2855 function getFormatElement(range, editableContentElement, tagName, className) {
2856 let element = range.startContainer;
2857 if (element.nodeType === element.TEXT_NODE && element instanceof window.Text && range.startOffset === element.length && element.nextSibling) {
2858 element = element.nextSibling;
2859 while (element.firstChild) {
2860 element = element.firstChild;
2861 }
2862 }
2863 if (element.nodeType !== element.ELEMENT_NODE) {
2864 if (!element.parentElement) {
2865 return;
2866 }
2867 element = element.parentElement;
2868 }
2869 if (element === editableContentElement) {
2870 return;
2871 }
2872 if (!editableContentElement.contains(element)) {
2873 return;
2874 }
2875 const selector = tagName + (className ? "." + className : "");
2876 if (!selector) {
2877 return;
2878 }
2879 if (!(element instanceof window.HTMLElement)) {
2880 return;
2881 }
2882 let closestElement = element;
2883 while (closestElement && closestElement !== editableContentElement) {
2884 if (closestElement.matches(selector)) {
2885 return closestElement;
2886 }
2887 closestElement = closestElement.parentElement;
2888 }
2889 return void 0;
2890 }
2891 function createVirtualAnchorElement(range, editableContentElement) {
2892 return {
2893 contextElement: editableContentElement,
2894 getBoundingClientRect() {
2895 if (editableContentElement.contains(range.startContainer)) {
2896 return (0, import_dom.getRectangleFromRange)(range) ?? range.getBoundingClientRect();
2897 }
2898 return editableContentElement.getBoundingClientRect();
2899 }
2900 };
2901 }
2902 function getAnchor(editableContentElement, tagName, className) {
2903 if (!editableContentElement) {
2904 return;
2905 }
2906 const { ownerDocument } = editableContentElement;
2907 const { defaultView } = ownerDocument;
2908 const selection = defaultView?.getSelection();
2909 if (!selection) {
2910 return;
2911 }
2912 if (!selection.rangeCount) {
2913 return;
2914 }
2915 const range = selection.getRangeAt(0);
2916 if (!range || !range.startContainer) {
2917 return;
2918 }
2919 if (!tagName && !className) {
2920 return createVirtualAnchorElement(range, editableContentElement);
2921 }
2922 return getFormatElement(range, editableContentElement, tagName, className) ?? createVirtualAnchorElement(range, editableContentElement);
2923 }
2924 var DEFAULT_SETTINGS = {
2925 tagName: "",
2926 className: ""
2927 };
2928 function useAnchor({
2929 editableContentElement,
2930 settings
2931 }) {
2932 const { tagName, className } = settings ?? DEFAULT_SETTINGS;
2933 const isActive = !!(settings && "isActive" in settings && settings.isActive);
2934 const [anchor, setAnchor] = (0, import_element7.useState)(
2935 () => getAnchor(editableContentElement, tagName, className ?? "")
2936 );
2937 const wasActive = (0, import_compose10.usePrevious)(isActive);
2938 (0, import_element7.useLayoutEffect)(() => {
2939 if (!editableContentElement) {
2940 return;
2941 }
2942 function callback() {
2943 setAnchor(
2944 getAnchor(editableContentElement, tagName, className ?? "")
2945 );
2946 }
2947 function attach() {
2948 ownerDocument.addEventListener("selectionchange", callback);
2949 }
2950 function detach() {
2951 ownerDocument.removeEventListener("selectionchange", callback);
2952 }
2953 const { ownerDocument } = editableContentElement;
2954 if (editableContentElement === ownerDocument.activeElement || // When a link is created, we need to attach the popover to the newly created anchor.
2955 !wasActive && isActive || // Sometimes we're _removing_ an active anchor, such as the inline color popover.
2956 // When we add the color, it switches from a virtual anchor to a `<mark>` element.
2957 // When we _remove_ the color, it switches from a `<mark>` element to a virtual anchor.
2958 wasActive && !isActive) {
2959 setAnchor(
2960 getAnchor(editableContentElement, tagName, className ?? "")
2961 );
2962 attach();
2963 }
2964 editableContentElement.addEventListener("focusin", attach);
2965 editableContentElement.addEventListener("focusout", detach);
2966 return () => {
2967 detach();
2968 editableContentElement.removeEventListener("focusin", attach);
2969 editableContentElement.removeEventListener("focusout", detach);
2970 };
2971 }, [editableContentElement, tagName, className, isActive, wasActive]);
2972 return anchor;
2973 }
2974
2975 // packages/rich-text/build-module/index.mjs
2976 function __experimentalRichText() {
2977 }
2978 return __toCommonJS(index_exports);
2979 })();
2980 //# sourceMappingURL=index.js.map
2981