PluginProbe
Gutenberg / 23.5.3
Gutenberg v23.5.3
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.5.3, at build/scripts/rich-text/index.js

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