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

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

3,133 lines 104.6 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_compose8 = __toESM(require_compose(), 1);
1754 var import_data9 = __toESM(require_data(), 1);
1755 var import_deprecated = __toESM(require_deprecated(), 1);
1756
1757 // packages/rich-text/build-module/owns-selection.mjs
1758 function ownsSelection(element) {
1759 const { ownerDocument } = element;
1760 const { activeElement } = ownerDocument;
1761 if (activeElement === element) {
1762 return true;
1763 }
1764 if (!activeElement || !activeElement.isContentEditable || !element.isContentEditable || !activeElement.contains(element)) {
1765 return false;
1766 }
1767 const selection = ownerDocument.defaultView.getSelection();
1768 const { anchorNode, focusNode } = selection;
1769 return !!anchorNode && !!focusNode && element.contains(anchorNode) && element.contains(focusNode);
1770 }
1771
1772 // packages/rich-text/build-module/hook/use-default-style.mjs
1773 var import_element = __toESM(require_element(), 1);
1774 var whiteSpace = "pre-wrap";
1775 function useDefaultStyle() {
1776 return (0, import_element.useCallback)((element) => {
1777 if (!element) {
1778 return;
1779 }
1780 element.style.whiteSpace = element.style.whiteSpace || whiteSpace;
1781 }, []);
1782 }
1783
1784 // node_modules/colord/index.mjs
1785 var r = { grad: 0.9, turn: 360, rad: 360 / (2 * Math.PI) };
1786 var t = function(r2) {
1787 return "string" == typeof r2 ? r2.length > 0 : "number" == typeof r2;
1788 };
1789 var n = function(r2, t2, n2) {
1790 return void 0 === t2 && (t2 = 0), void 0 === n2 && (n2 = Math.pow(10, t2)), Math.round(n2 * r2) / n2 + 0;
1791 };
1792 var e = function(r2, t2, n2) {
1793 return void 0 === t2 && (t2 = 0), void 0 === n2 && (n2 = 1), r2 > n2 ? n2 : r2 > t2 ? r2 : t2;
1794 };
1795 var u = function(r2) {
1796 return (r2 = isFinite(r2) ? r2 % 360 : 0) > 0 ? r2 : r2 + 360;
1797 };
1798 var a = function(r2) {
1799 return { r: e(r2.r, 0, 255), g: e(r2.g, 0, 255), b: e(r2.b, 0, 255), a: e(r2.a) };
1800 };
1801 var o = function(r2) {
1802 return { r: n(r2.r), g: n(r2.g), b: n(r2.b), a: n(r2.a, 3) };
1803 };
1804 var i = /^#([0-9a-f]{3,8})$/i;
1805 var s = function(r2) {
1806 var t2 = r2.toString(16);
1807 return t2.length < 2 ? "0" + t2 : t2;
1808 };
1809 var h = function(r2) {
1810 var t2 = r2.r, n2 = r2.g, e2 = r2.b, u2 = r2.a, a2 = Math.max(t2, n2, e2), o2 = a2 - Math.min(t2, n2, e2), i2 = o2 ? a2 === t2 ? (n2 - e2) / o2 : a2 === n2 ? 2 + (e2 - t2) / o2 : 4 + (t2 - n2) / o2 : 0;
1811 return { h: 60 * (i2 < 0 ? i2 + 6 : i2), s: a2 ? o2 / a2 * 100 : 0, v: a2 / 255 * 100, a: u2 };
1812 };
1813 var b = function(r2) {
1814 var t2 = r2.h, n2 = r2.s, e2 = r2.v, u2 = r2.a;
1815 t2 = t2 / 360 * 6, n2 /= 100, e2 /= 100;
1816 var a2 = Math.floor(t2), o2 = e2 * (1 - n2), i2 = e2 * (1 - (t2 - a2) * n2), s2 = e2 * (1 - (1 - t2 + a2) * n2), h2 = a2 % 6;
1817 return { r: 255 * [e2, i2, o2, o2, s2, e2][h2], g: 255 * [s2, e2, e2, i2, o2, o2][h2], b: 255 * [o2, o2, s2, e2, e2, i2][h2], a: u2 };
1818 };
1819 var g = function(r2) {
1820 return { h: u(r2.h), s: e(r2.s, 0, 100), l: e(r2.l, 0, 100), a: e(r2.a) };
1821 };
1822 var d = function(r2) {
1823 return { h: n(r2.h), s: n(r2.s), l: n(r2.l), a: n(r2.a, 3) };
1824 };
1825 var f = function(r2) {
1826 return b((n2 = (t2 = r2).s, { h: t2.h, s: (n2 *= ((e2 = t2.l) < 50 ? e2 : 100 - e2) / 100) > 0 ? 2 * n2 / (e2 + n2) * 100 : 0, v: e2 + n2, a: t2.a }));
1827 var t2, n2, e2;
1828 };
1829 var c = function(r2) {
1830 return { h: (t2 = h(r2)).h, s: (u2 = (200 - (n2 = t2.s)) * (e2 = t2.v) / 100) > 0 && u2 < 200 ? n2 * e2 / 100 / (u2 <= 100 ? u2 : 200 - u2) * 100 : 0, l: u2 / 2, a: t2.a };
1831 var t2, n2, e2, u2;
1832 };
1833 var l = /^hsla?\(\s*([+-]?\d*\.?\d+)(deg|rad|grad|turn)?\s*,\s*([+-]?\d*\.?\d+)%\s*,\s*([+-]?\d*\.?\d+)%\s*(?:,\s*([+-]?\d*\.?\d+)(%)?\s*)?\)$/i;
1834 var p = /^hsla?\(\s*([+-]?\d*\.?\d+)(deg|rad|grad|turn)?\s+([+-]?\d*\.?\d+)%\s+([+-]?\d*\.?\d+)%\s*(?:\/\s*([+-]?\d*\.?\d+)(%)?\s*)?\)$/i;
1835 var v = /^rgba?\(\s*([+-]?\d*\.?\d+)(%)?\s*,\s*([+-]?\d*\.?\d+)(%)?\s*,\s*([+-]?\d*\.?\d+)(%)?\s*(?:,\s*([+-]?\d*\.?\d+)(%)?\s*)?\)$/i;
1836 var m = /^rgba?\(\s*([+-]?\d*\.?\d+)(%)?\s+([+-]?\d*\.?\d+)(%)?\s+([+-]?\d*\.?\d+)(%)?\s*(?:\/\s*([+-]?\d*\.?\d+)(%)?\s*)?\)$/i;
1837 var y = { string: [[function(r2) {
1838 var t2 = i.exec(r2);
1839 return t2 ? (r2 = t2[1]).length <= 4 ? { r: parseInt(r2[0] + r2[0], 16), g: parseInt(r2[1] + r2[1], 16), b: parseInt(r2[2] + r2[2], 16), a: 4 === r2.length ? n(parseInt(r2[3] + r2[3], 16) / 255, 2) : 1 } : 6 === r2.length || 8 === r2.length ? { r: parseInt(r2.substr(0, 2), 16), g: parseInt(r2.substr(2, 2), 16), b: parseInt(r2.substr(4, 2), 16), a: 8 === r2.length ? n(parseInt(r2.substr(6, 2), 16) / 255, 2) : 1 } : null : null;
1840 }, "hex"], [function(r2) {
1841 var t2 = v.exec(r2) || m.exec(r2);
1842 return t2 ? t2[2] !== t2[4] || t2[4] !== t2[6] ? null : a({ r: Number(t2[1]) / (t2[2] ? 100 / 255 : 1), g: Number(t2[3]) / (t2[4] ? 100 / 255 : 1), b: Number(t2[5]) / (t2[6] ? 100 / 255 : 1), a: void 0 === t2[7] ? 1 : Number(t2[7]) / (t2[8] ? 100 : 1) }) : null;
1843 }, "rgb"], [function(t2) {
1844 var n2 = l.exec(t2) || p.exec(t2);
1845 if (!n2) return null;
1846 var e2, u2, a2 = g({ h: (e2 = n2[1], u2 = n2[2], void 0 === u2 && (u2 = "deg"), Number(e2) * (r[u2] || 1)), s: Number(n2[3]), l: Number(n2[4]), a: void 0 === n2[5] ? 1 : Number(n2[5]) / (n2[6] ? 100 : 1) });
1847 return f(a2);
1848 }, "hsl"]], object: [[function(r2) {
1849 var n2 = r2.r, e2 = r2.g, u2 = r2.b, o2 = r2.a, i2 = void 0 === o2 ? 1 : o2;
1850 return t(n2) && t(e2) && t(u2) ? a({ r: Number(n2), g: Number(e2), b: Number(u2), a: Number(i2) }) : null;
1851 }, "rgb"], [function(r2) {
1852 var n2 = r2.h, e2 = r2.s, u2 = r2.l, a2 = r2.a, o2 = void 0 === a2 ? 1 : a2;
1853 if (!t(n2) || !t(e2) || !t(u2)) return null;
1854 var i2 = g({ h: Number(n2), s: Number(e2), l: Number(u2), a: Number(o2) });
1855 return f(i2);
1856 }, "hsl"], [function(r2) {
1857 var n2 = r2.h, a2 = r2.s, o2 = r2.v, i2 = r2.a, s2 = void 0 === i2 ? 1 : i2;
1858 if (!t(n2) || !t(a2) || !t(o2)) return null;
1859 var h2 = (function(r3) {
1860 return { h: u(r3.h), s: e(r3.s, 0, 100), v: e(r3.v, 0, 100), a: e(r3.a) };
1861 })({ h: Number(n2), s: Number(a2), v: Number(o2), a: Number(s2) });
1862 return b(h2);
1863 }, "hsv"]] };
1864 var N = function(r2, t2) {
1865 for (var n2 = 0; n2 < t2.length; n2++) {
1866 var e2 = t2[n2][0](r2);
1867 if (e2) return [e2, t2[n2][1]];
1868 }
1869 return [null, void 0];
1870 };
1871 var x = function(r2) {
1872 return "string" == typeof r2 ? N(r2.trim(), y.string) : "object" == typeof r2 && null !== r2 ? N(r2, y.object) : [null, void 0];
1873 };
1874 var M = function(r2, t2) {
1875 var n2 = c(r2);
1876 return { h: n2.h, s: e(n2.s + 100 * t2, 0, 100), l: n2.l, a: n2.a };
1877 };
1878 var H = function(r2) {
1879 return (299 * r2.r + 587 * r2.g + 114 * r2.b) / 1e3 / 255;
1880 };
1881 var $ = function(r2, t2) {
1882 var n2 = c(r2);
1883 return { h: n2.h, s: n2.s, l: e(n2.l + 100 * t2, 0, 100), a: n2.a };
1884 };
1885 var j = (function() {
1886 function r2(r3) {
1887 this.parsed = x(r3)[0], this.rgba = this.parsed || { r: 0, g: 0, b: 0, a: 1 };
1888 }
1889 return r2.prototype.isValid = function() {
1890 return null !== this.parsed;
1891 }, r2.prototype.brightness = function() {
1892 return n(H(this.rgba), 2);
1893 }, r2.prototype.isDark = function() {
1894 return H(this.rgba) < 0.5;
1895 }, r2.prototype.isLight = function() {
1896 return H(this.rgba) >= 0.5;
1897 }, r2.prototype.toHex = function() {
1898 return r3 = o(this.rgba), t2 = r3.r, e2 = r3.g, u2 = r3.b, i2 = (a2 = r3.a) < 1 ? s(n(255 * a2)) : "", "#" + s(t2) + s(e2) + s(u2) + i2;
1899 var r3, t2, e2, u2, a2, i2;
1900 }, r2.prototype.toRgb = function() {
1901 return o(this.rgba);
1902 }, r2.prototype.toRgbString = function() {
1903 return r3 = o(this.rgba), t2 = r3.r, n2 = r3.g, e2 = r3.b, (u2 = r3.a) < 1 ? "rgba(" + t2 + ", " + n2 + ", " + e2 + ", " + u2 + ")" : "rgb(" + t2 + ", " + n2 + ", " + e2 + ")";
1904 var r3, t2, n2, e2, u2;
1905 }, r2.prototype.toHsl = function() {
1906 return d(c(this.rgba));
1907 }, r2.prototype.toHslString = function() {
1908 return r3 = d(c(this.rgba)), t2 = r3.h, n2 = r3.s, e2 = r3.l, (u2 = r3.a) < 1 ? "hsla(" + t2 + ", " + n2 + "%, " + e2 + "%, " + u2 + ")" : "hsl(" + t2 + ", " + n2 + "%, " + e2 + "%)";
1909 var r3, t2, n2, e2, u2;
1910 }, r2.prototype.toHsv = function() {
1911 return r3 = h(this.rgba), { h: n(r3.h), s: n(r3.s), v: n(r3.v), a: n(r3.a, 3) };
1912 var r3;
1913 }, r2.prototype.invert = function() {
1914 return w({ r: 255 - (r3 = this.rgba).r, g: 255 - r3.g, b: 255 - r3.b, a: r3.a });
1915 var r3;
1916 }, r2.prototype.saturate = function(r3) {
1917 return void 0 === r3 && (r3 = 0.1), w(M(this.rgba, r3));
1918 }, r2.prototype.desaturate = function(r3) {
1919 return void 0 === r3 && (r3 = 0.1), w(M(this.rgba, -r3));
1920 }, r2.prototype.grayscale = function() {
1921 return w(M(this.rgba, -1));
1922 }, r2.prototype.lighten = function(r3) {
1923 return void 0 === r3 && (r3 = 0.1), w($(this.rgba, r3));
1924 }, r2.prototype.darken = function(r3) {
1925 return void 0 === r3 && (r3 = 0.1), w($(this.rgba, -r3));
1926 }, r2.prototype.rotate = function(r3) {
1927 return void 0 === r3 && (r3 = 15), this.hue(this.hue() + r3);
1928 }, r2.prototype.alpha = function(r3) {
1929 return "number" == typeof r3 ? w({ r: (t2 = this.rgba).r, g: t2.g, b: t2.b, a: r3 }) : n(this.rgba.a, 3);
1930 var t2;
1931 }, r2.prototype.hue = function(r3) {
1932 var t2 = c(this.rgba);
1933 return "number" == typeof r3 ? w({ h: r3, s: t2.s, l: t2.l, a: t2.a }) : n(t2.h);
1934 }, r2.prototype.isEqual = function(r3) {
1935 return this.toHex() === w(r3).toHex();
1936 }, r2;
1937 })();
1938 var w = function(r2) {
1939 return r2 instanceof j ? r2 : new j(r2);
1940 };
1941
1942 // packages/rich-text/build-module/hook/use-boundary-style.mjs
1943 var import_element2 = __toESM(require_element(), 1);
1944 function useBoundaryStyle({ record }) {
1945 const ref = (0, import_element2.useRef)();
1946 const { activeFormats = [], replacements, start } = record.current;
1947 const activeReplacement = replacements[start];
1948 (0, import_element2.useEffect)(() => {
1949 if ((!activeFormats || !activeFormats.length) && !activeReplacement) {
1950 return;
1951 }
1952 const boundarySelector = "*[data-rich-text-format-boundary]";
1953 const element = ref.current.querySelector(boundarySelector);
1954 if (!element) {
1955 return;
1956 }
1957 const { ownerDocument } = element;
1958 const { defaultView } = ownerDocument;
1959 const computedStyle = defaultView.getComputedStyle(element);
1960 const newColor = w(computedStyle.color).alpha(0.2).toRgbString();
1961 const selector = `.rich-text:focus ${boundarySelector}`;
1962 const rule = `background-color: ${newColor}`;
1963 const style = `${selector} {${rule}}`;
1964 const globalStyleId = "rich-text-boundary-style";
1965 let globalStyle = ownerDocument.getElementById(globalStyleId);
1966 if (!globalStyle) {
1967 globalStyle = ownerDocument.createElement("style");
1968 globalStyle.id = globalStyleId;
1969 ownerDocument.head.appendChild(globalStyle);
1970 }
1971 if (globalStyle.innerHTML !== style) {
1972 globalStyle.innerHTML = style;
1973 }
1974 }, [activeFormats, activeReplacement]);
1975 return ref;
1976 }
1977
1978 // packages/rich-text/build-module/hook/event-listeners/index.mjs
1979 var import_element3 = __toESM(require_element(), 1);
1980 var import_compose7 = __toESM(require_compose(), 1);
1981
1982 // packages/rich-text/build-module/hook/event-listeners/copy-handler.mjs
1983 var import_compose = __toESM(require_compose(), 1);
1984 var { subscribeDelegatedListener } = unlock(import_compose.privateApis);
1985 var copy_handler_default = (props) => (element) => {
1986 function onCopy(event) {
1987 const { record, handleChange } = props.current;
1988 const { ownerDocument } = element;
1989 if (isCollapsed(record.current) || !element.contains(ownerDocument.activeElement) && !ownsSelection(element)) {
1990 return;
1991 }
1992 const selectedRecord = slice(record.current);
1993 const plainText = getTextContent(selectedRecord);
1994 const html = toHTMLString({ value: selectedRecord });
1995 event.clipboardData.setData("text/plain", plainText);
1996 event.clipboardData.setData("text/html", html);
1997 event.clipboardData.setData("rich-text", "true");
1998 event.preventDefault();
1999 if (event.type === "cut") {
2000 handleChange(remove2(record.current));
2001 }
2002 }
2003 const { defaultView } = element.ownerDocument;
2004 const unsubscribeCopy = subscribeDelegatedListener(
2005 defaultView,
2006 "copy",
2007 onCopy
2008 );
2009 const unsubscribeCut = subscribeDelegatedListener(
2010 defaultView,
2011 "cut",
2012 onCopy
2013 );
2014 return () => {
2015 unsubscribeCopy();
2016 unsubscribeCut();
2017 };
2018 };
2019
2020 // packages/rich-text/build-module/hook/event-listeners/select-object.mjs
2021 var import_compose2 = __toESM(require_compose(), 1);
2022 var { subscribeDelegatedListener: subscribeDelegatedListener2 } = unlock(import_compose2.privateApis);
2023 var select_object_default = () => (element) => {
2024 function onClick(event) {
2025 const { target } = event;
2026 if (target === element || target.textContent && target.isContentEditable) {
2027 return;
2028 }
2029 const { ownerDocument } = target;
2030 const { defaultView } = ownerDocument;
2031 const selection = defaultView.getSelection();
2032 if (selection.containsNode(target)) {
2033 return;
2034 }
2035 const range = ownerDocument.createRange();
2036 const nodeToSelect = target.isContentEditable ? target : target.closest("[contenteditable]");
2037 range.selectNode(nodeToSelect);
2038 selection.removeAllRanges();
2039 selection.addRange(range);
2040 event.preventDefault();
2041 }
2042 function onFocusIn(event) {
2043 if (event.relatedTarget && !element.contains(event.relatedTarget)) {
2044 onClick(event);
2045 }
2046 }
2047 const unsubscribeClick = subscribeDelegatedListener2(
2048 element,
2049 "click",
2050 onClick
2051 );
2052 const unsubscribeFocusIn = subscribeDelegatedListener2(
2053 element,
2054 "focusin",
2055 onFocusIn
2056 );
2057 return () => {
2058 unsubscribeClick();
2059 unsubscribeFocusIn();
2060 };
2061 };
2062
2063 // packages/rich-text/build-module/hook/event-listeners/format-boundaries.mjs
2064 var import_keycodes = __toESM(require_keycodes(), 1);
2065
2066 // packages/rich-text/build-module/subscribe-owned-listener.mjs
2067 var import_compose3 = __toESM(require_compose(), 1);
2068 var { subscribeDelegatedListener: subscribeDelegatedListener3 } = unlock(import_compose3.privateApis);
2069 function subscribeOwnedListener(element, eventType, callback, capture = false) {
2070 return subscribeDelegatedListener3(
2071 element.ownerDocument,
2072 eventType,
2073 (event) => {
2074 if (!element.contains(event.target) && !ownsSelection(element)) {
2075 return;
2076 }
2077 callback(event);
2078 },
2079 capture
2080 );
2081 }
2082
2083 // packages/rich-text/build-module/hook/event-listeners/format-boundaries.mjs
2084 var EMPTY_ACTIVE_FORMATS = [];
2085 var format_boundaries_default = (props) => (element) => {
2086 function onKeyDown(event) {
2087 const { keyCode, shiftKey, altKey, metaKey, ctrlKey } = event;
2088 if (
2089 // Only override left and right keys without modifiers pressed.
2090 shiftKey || altKey || metaKey || ctrlKey || keyCode !== import_keycodes.LEFT && keyCode !== import_keycodes.RIGHT
2091 ) {
2092 return;
2093 }
2094 const { record, applyRecord, forceRender } = props.current;
2095 const {
2096 text,
2097 formats,
2098 start,
2099 end,
2100 activeFormats: currentActiveFormats = []
2101 } = record.current;
2102 const collapsed = isCollapsed(record.current);
2103 const { defaultView } = element.ownerDocument;
2104 const { direction } = defaultView.getComputedStyle(element);
2105 const reverseKey = direction === "rtl" ? import_keycodes.RIGHT : import_keycodes.LEFT;
2106 const isReverse = event.keyCode === reverseKey;
2107 if (collapsed && currentActiveFormats.length === 0) {
2108 if (start === 0 && isReverse) {
2109 return;
2110 }
2111 if (end === text.length && !isReverse) {
2112 return;
2113 }
2114 }
2115 if (!collapsed) {
2116 return;
2117 }
2118 const formatsBefore = formats[start - 1] || EMPTY_ACTIVE_FORMATS;
2119 const formatsAfter = formats[start] || EMPTY_ACTIVE_FORMATS;
2120 const destination = isReverse ? formatsBefore : formatsAfter;
2121 const isIncreasing = currentActiveFormats.every(
2122 (format, index) => format === destination[index]
2123 );
2124 let newActiveFormatsLength = currentActiveFormats.length;
2125 if (!isIncreasing) {
2126 newActiveFormatsLength--;
2127 } else if (newActiveFormatsLength < destination.length) {
2128 newActiveFormatsLength++;
2129 }
2130 if (newActiveFormatsLength === currentActiveFormats.length) {
2131 record.current._newActiveFormats = destination;
2132 return;
2133 }
2134 event.preventDefault();
2135 const origin = isReverse ? formatsAfter : formatsBefore;
2136 const source = isIncreasing ? destination : origin;
2137 const newActiveFormats = source.slice(0, newActiveFormatsLength);
2138 const newValue = {
2139 ...record.current,
2140 activeFormats: newActiveFormats
2141 };
2142 record.current = newValue;
2143 applyRecord(newValue);
2144 forceRender();
2145 }
2146 return subscribeOwnedListener(element, "keydown", onKeyDown, true);
2147 };
2148
2149 // packages/rich-text/build-module/hook/event-listeners/delete.mjs
2150 var import_keycodes2 = __toESM(require_keycodes(), 1);
2151 var delete_default = (props) => (element) => {
2152 function onKeyDown(event) {
2153 const { keyCode } = event;
2154 if (event.defaultPrevented) {
2155 return;
2156 }
2157 if (keyCode !== import_keycodes2.DELETE && keyCode !== import_keycodes2.BACKSPACE) {
2158 return;
2159 }
2160 const { createRecord, handleChange } = props.current;
2161 const currentValue = createRecord();
2162 const { start, end, text } = currentValue;
2163 if (start === 0 && end !== 0 && end === text.length) {
2164 handleChange(remove2(currentValue));
2165 event.preventDefault();
2166 }
2167 }
2168 return subscribeOwnedListener(element, "keydown", onKeyDown);
2169 };
2170
2171 // packages/rich-text/build-module/hook/event-listeners/input-and-selection.mjs
2172 var import_compose4 = __toESM(require_compose(), 1);
2173
2174 // packages/rich-text/build-module/update-formats.mjs
2175 function updateFormats({ value, start, end, formats }) {
2176 const min = Math.min(start, end);
2177 const max = Math.max(start, end);
2178 const formatsBefore = value.formats[min - 1] || [];
2179 const formatsAfter = value.formats[max] || [];
2180 value.activeFormats = formats.map((format, index) => {
2181 if (formatsBefore[index]) {
2182 if (isFormatEqual(format, formatsBefore[index])) {
2183 return formatsBefore[index];
2184 }
2185 } else if (formatsAfter[index]) {
2186 if (isFormatEqual(format, formatsAfter[index])) {
2187 return formatsAfter[index];
2188 }
2189 }
2190 return format;
2191 });
2192 while (--end >= start) {
2193 if (value.activeFormats.length > 0) {
2194 value.formats[end] = value.activeFormats;
2195 } else {
2196 delete value.formats[end];
2197 }
2198 }
2199 return value;
2200 }
2201
2202 // packages/rich-text/build-module/hook/event-listeners/input-and-selection.mjs
2203 var { subscribeDelegatedListener: subscribeDelegatedListener4 } = unlock(import_compose4.privateApis);
2204 var INSERTION_INPUT_TYPES_TO_IGNORE = /* @__PURE__ */ new Set([
2205 "insertParagraph",
2206 "insertOrderedList",
2207 "insertUnorderedList",
2208 "insertHorizontalRule",
2209 "insertLink"
2210 ]);
2211 var EMPTY_ACTIVE_FORMATS2 = [];
2212 var PLACEHOLDER_ATTR_NAME = "data-rich-text-placeholder";
2213 function fixPlaceholderSelection(defaultView) {
2214 const selection = defaultView.getSelection();
2215 const { anchorNode, anchorOffset } = selection;
2216 if (anchorNode.nodeType !== anchorNode.ELEMENT_NODE) {
2217 return;
2218 }
2219 const targetNode = anchorNode.childNodes[anchorOffset];
2220 if (!targetNode || targetNode.nodeType !== targetNode.ELEMENT_NODE || !targetNode.hasAttribute(PLACEHOLDER_ATTR_NAME)) {
2221 return;
2222 }
2223 selection.collapseToStart();
2224 }
2225 var input_and_selection_default = (props) => (element) => {
2226 const { ownerDocument } = element;
2227 const { defaultView } = ownerDocument;
2228 let isComposing = false;
2229 function onInput(event) {
2230 if (isComposing) {
2231 return;
2232 }
2233 let inputType;
2234 if (event) {
2235 inputType = event.inputType;
2236 }
2237 const { record, applyRecord, createRecord, handleChange } = props.current;
2238 if (inputType && (inputType.indexOf("format") === 0 || INSERTION_INPUT_TYPES_TO_IGNORE.has(inputType))) {
2239 applyRecord(record.current);
2240 return;
2241 }
2242 const currentValue = createRecord();
2243 const { start, activeFormats: oldActiveFormats = [] } = record.current;
2244 const clearFormats = !isCollapsed(record.current) && currentValue.start <= start;
2245 const change = updateFormats({
2246 value: currentValue,
2247 start,
2248 end: currentValue.start,
2249 formats: clearFormats ? [] : oldActiveFormats
2250 });
2251 handleChange(change);
2252 }
2253 let selectionSnapshot;
2254 function handleSelectionChange() {
2255 const { record, applyRecord, createRecord, onSelectionChange } = props.current;
2256 if (element.contentEditable !== "true") {
2257 return;
2258 }
2259 if (ownerDocument.activeElement !== element && !ownsSelection(element)) {
2260 return;
2261 }
2262 if (isComposing) {
2263 return;
2264 }
2265 const selection = defaultView.getSelection();
2266 if (selectionSnapshot && selectionSnapshot.anchorNode === selection.anchorNode && selectionSnapshot.anchorOffset === selection.anchorOffset && selectionSnapshot.focusNode === selection.focusNode && selectionSnapshot.focusOffset === selection.focusOffset && selectionSnapshot.processedStart === record.current.start && selectionSnapshot.processedEnd === record.current.end) {
2267 return;
2268 }
2269 const { start, end, text } = createRecord();
2270 const oldRecord = record.current;
2271 selectionSnapshot = {
2272 anchorNode: selection.anchorNode,
2273 anchorOffset: selection.anchorOffset,
2274 focusNode: selection.focusNode,
2275 focusOffset: selection.focusOffset,
2276 processedStart: start,
2277 processedEnd: end
2278 };
2279 if (text !== oldRecord.text) {
2280 onInput();
2281 return;
2282 }
2283 if (start === oldRecord.start && end === oldRecord.end) {
2284 if (oldRecord.text.length === 0 && start === 0) {
2285 fixPlaceholderSelection(defaultView);
2286 }
2287 return;
2288 }
2289 const newValue = {
2290 ...oldRecord,
2291 start,
2292 end,
2293 // _newActiveFormats may be set on arrow key navigation to control
2294 // the right boundary position. If undefined, getActiveFormats will
2295 // give the active formats according to the browser.
2296 activeFormats: oldRecord._newActiveFormats,
2297 _newActiveFormats: void 0
2298 };
2299 const newActiveFormats = getActiveFormats(
2300 newValue,
2301 EMPTY_ACTIVE_FORMATS2
2302 );
2303 newValue.activeFormats = newActiveFormats;
2304 record.current = newValue;
2305 applyRecord(newValue, { domOnly: true });
2306 onSelectionChange(start, end);
2307 }
2308 function onCompositionStart() {
2309 isComposing = true;
2310 element.querySelector(`[${PLACEHOLDER_ATTR_NAME}]`)?.remove();
2311 }
2312 function onCompositionEnd() {
2313 isComposing = false;
2314 onInput({ inputType: "insertText" });
2315 }
2316 function onFocus(event) {
2317 if (event.target !== element) {
2318 return;
2319 }
2320 if (element.contentEditable !== "true") {
2321 return;
2322 }
2323 const { record, isSelected, onSelectionChange, applyRecord } = props.current;
2324 if (element.parentElement.closest('[contenteditable="true"]')) {
2325 const selection = defaultView.getSelection();
2326 if (!selection.anchorNode || !element.contains(selection.anchorNode)) {
2327 if (isSelected && record.current.start !== void 0) {
2328 applyRecord(record.current);
2329 } else {
2330 selection.collapse(element, 0);
2331 }
2332 }
2333 return;
2334 }
2335 if (!isSelected) {
2336 const index = void 0;
2337 record.current = {
2338 ...record.current,
2339 start: index,
2340 end: index,
2341 activeFormats: EMPTY_ACTIVE_FORMATS2
2342 };
2343 selectionSnapshot = void 0;
2344 } else {
2345 applyRecord(record.current);
2346 }
2347 onSelectionChange(record.current.start, record.current.end);
2348 window.queueMicrotask(handleSelectionChange);
2349 }
2350 const unsubscribeInput = subscribeOwnedListener(
2351 element,
2352 "input",
2353 onInput,
2354 true
2355 );
2356 const unsubscribeCompositionStart = subscribeOwnedListener(
2357 element,
2358 "compositionstart",
2359 onCompositionStart
2360 );
2361 const unsubscribeCompositionEnd = subscribeOwnedListener(
2362 element,
2363 "compositionend",
2364 onCompositionEnd,
2365 true
2366 );
2367 const unsubscribeFocus = subscribeDelegatedListener4(
2368 element,
2369 "focusin",
2370 onFocus
2371 );
2372 const unsubscribeSelectionChange = subscribeDelegatedListener4(
2373 ownerDocument,
2374 "selectionchange",
2375 handleSelectionChange
2376 );
2377 const unsubscribeEnsureSelectionSync = [
2378 "keydown",
2379 "beforeinput",
2380 "copy",
2381 "cut",
2382 "paste"
2383 ].map(
2384 (eventType) => subscribeDelegatedListener4(
2385 ownerDocument,
2386 eventType,
2387 handleSelectionChange,
2388 true
2389 )
2390 );
2391 return () => {
2392 unsubscribeInput();
2393 unsubscribeCompositionStart();
2394 unsubscribeCompositionEnd();
2395 unsubscribeFocus();
2396 unsubscribeSelectionChange();
2397 unsubscribeEnsureSelectionSync.forEach(
2398 (unsubscribe) => unsubscribe()
2399 );
2400 };
2401 };
2402
2403 // packages/rich-text/build-module/hook/event-listeners/selection-change-compat.mjs
2404 var import_compose5 = __toESM(require_compose(), 1);
2405 var { subscribeDelegatedListener: subscribeDelegatedListener5 } = unlock(import_compose5.privateApis);
2406 var selection_change_compat_default = () => (element) => {
2407 const { ownerDocument } = element;
2408 const { defaultView } = ownerDocument;
2409 const selection = defaultView?.getSelection();
2410 let range;
2411 function getRange() {
2412 return selection.rangeCount ? selection.getRangeAt(0) : null;
2413 }
2414 function onDown(event) {
2415 const type = event.type === "keydown" ? "keyup" : "pointerup";
2416 function onCancel() {
2417 ownerDocument.removeEventListener(type, onUp);
2418 ownerDocument.removeEventListener("selectionchange", onCancel);
2419 ownerDocument.removeEventListener("input", onCancel);
2420 }
2421 function onUp() {
2422 onCancel();
2423 if (isRangeEqual(range, getRange())) {
2424 return;
2425 }
2426 ownerDocument.dispatchEvent(new Event("selectionchange"));
2427 }
2428 ownerDocument.addEventListener(type, onUp);
2429 ownerDocument.addEventListener("selectionchange", onCancel);
2430 ownerDocument.addEventListener("input", onCancel);
2431 range = getRange();
2432 }
2433 const unsubscribePointerDown = subscribeDelegatedListener5(
2434 element,
2435 "pointerdown",
2436 onDown
2437 );
2438 const unsubscribeKeyDown = subscribeDelegatedListener5(
2439 element,
2440 "keydown",
2441 onDown
2442 );
2443 return () => {
2444 unsubscribePointerDown();
2445 unsubscribeKeyDown();
2446 };
2447 };
2448
2449 // packages/rich-text/build-module/hook/event-listeners/prevent-focus-capture.mjs
2450 var import_compose6 = __toESM(require_compose(), 1);
2451 var { subscribeDelegatedListener: subscribeDelegatedListener6 } = unlock(import_compose6.privateApis);
2452 function preventFocusCapture() {
2453 return (element) => {
2454 const { ownerDocument } = element;
2455 const { defaultView } = ownerDocument;
2456 let value = null;
2457 function onPointerDown(event) {
2458 if (event.defaultPrevented) {
2459 return;
2460 }
2461 if (event.target === element) {
2462 return;
2463 }
2464 if (!event.target.contains(element)) {
2465 return;
2466 }
2467 value = element.getAttribute("contenteditable");
2468 element.setAttribute("contenteditable", "false");
2469 defaultView.getSelection().removeAllRanges();
2470 }
2471 function onPointerUp() {
2472 if (value !== null) {
2473 element.setAttribute("contenteditable", value);
2474 value = null;
2475 }
2476 }
2477 const unsubscribePointerDown = subscribeDelegatedListener6(
2478 defaultView,
2479 "pointerdown",
2480 onPointerDown
2481 );
2482 const unsubscribePointerUp = subscribeDelegatedListener6(
2483 defaultView,
2484 "pointerup",
2485 onPointerUp
2486 );
2487 return () => {
2488 unsubscribePointerDown();
2489 unsubscribePointerUp();
2490 };
2491 };
2492 }
2493
2494 // packages/rich-text/build-module/hook/event-listeners/index.mjs
2495 var allEventListeners = [
2496 input_and_selection_default,
2497 copy_handler_default,
2498 select_object_default,
2499 format_boundaries_default,
2500 delete_default,
2501 selection_change_compat_default,
2502 preventFocusCapture
2503 ];
2504 function useEventListeners(props) {
2505 const propsRef = (0, import_element3.useRef)(props);
2506 (0, import_element3.useInsertionEffect)(() => {
2507 propsRef.current = props;
2508 });
2509 const refEffects = (0, import_element3.useMemo)(
2510 () => allEventListeners.map((refEffect) => refEffect(propsRef)),
2511 [propsRef]
2512 );
2513 return (0, import_compose7.useRefEffect)(
2514 (element) => {
2515 const cleanups = refEffects.map((effect) => effect(element));
2516 return () => {
2517 cleanups.forEach((cleanup) => cleanup());
2518 };
2519 },
2520 [refEffects]
2521 );
2522 }
2523
2524 // packages/rich-text/build-module/hook/use-format-types.mjs
2525 var import_element4 = __toESM(require_element(), 1);
2526 var import_data8 = __toESM(require_data(), 1);
2527 function formatTypesSelector(select5) {
2528 return select5(store).getFormatTypes();
2529 }
2530 var interactiveContentTags = /* @__PURE__ */ new Set([
2531 "a",
2532 "audio",
2533 "button",
2534 "details",
2535 "embed",
2536 "iframe",
2537 "input",
2538 "label",
2539 "select",
2540 "textarea",
2541 "video"
2542 ]);
2543 function prefixSelectKeys(selected, prefix) {
2544 if (typeof selected !== "object") {
2545 return { [prefix]: selected };
2546 }
2547 return Object.fromEntries(
2548 Object.entries(selected).map(([key, value]) => [
2549 `${prefix}.${key}`,
2550 value
2551 ])
2552 );
2553 }
2554 function getPrefixedSelectKeys(selected, prefix) {
2555 if (selected[prefix]) {
2556 return selected[prefix];
2557 }
2558 return Object.keys(selected).filter((key) => key.startsWith(prefix + ".")).reduce((accumulator, key) => {
2559 accumulator[key.slice(prefix.length + 1)] = selected[key];
2560 return accumulator;
2561 }, {});
2562 }
2563 function useFormatTypes({
2564 allowedFormats,
2565 withoutInteractiveFormatting,
2566 __unstableFormatTypeHandlerContext
2567 }) {
2568 const allFormatTypes = (0, import_data8.useSelect)(formatTypesSelector, []);
2569 const formatTypes2 = (0, import_element4.useMemo)(() => {
2570 return allFormatTypes.filter(({ name, interactive, tagName }) => {
2571 if (allowedFormats && !allowedFormats.includes(name)) {
2572 return false;
2573 }
2574 if (withoutInteractiveFormatting && (interactive || interactiveContentTags.has(tagName))) {
2575 return false;
2576 }
2577 return true;
2578 });
2579 }, [allFormatTypes, allowedFormats, withoutInteractiveFormatting]);
2580 const keyedSelected = (0, import_data8.useSelect)(
2581 (select5) => formatTypes2.reduce((accumulator, type) => {
2582 if (!type.__experimentalGetPropsForEditableTreePreparation || !__unstableFormatTypeHandlerContext) {
2583 return accumulator;
2584 }
2585 return {
2586 ...accumulator,
2587 ...prefixSelectKeys(
2588 type.__experimentalGetPropsForEditableTreePreparation(
2589 select5,
2590 __unstableFormatTypeHandlerContext
2591 ),
2592 type.name
2593 )
2594 };
2595 }, {}),
2596 [formatTypes2, __unstableFormatTypeHandlerContext]
2597 );
2598 const dispatch3 = (0, import_data8.useDispatch)();
2599 const prepareHandlers = [];
2600 const valueHandlers = [];
2601 const changeHandlers = [];
2602 const dependencies = [];
2603 for (const key in keyedSelected) {
2604 dependencies.push(keyedSelected[key]);
2605 }
2606 formatTypes2.forEach((type) => {
2607 if (type.__experimentalCreatePrepareEditableTree && __unstableFormatTypeHandlerContext) {
2608 const handler = type.__experimentalCreatePrepareEditableTree(
2609 getPrefixedSelectKeys(keyedSelected, type.name),
2610 __unstableFormatTypeHandlerContext
2611 );
2612 if (type.__experimentalCreateOnChangeEditableValue) {
2613 valueHandlers.push(handler);
2614 } else {
2615 prepareHandlers.push(handler);
2616 }
2617 }
2618 if (type.__experimentalCreateOnChangeEditableValue && __unstableFormatTypeHandlerContext) {
2619 let dispatchers = {};
2620 if (type.__experimentalGetPropsForEditableTreeChangeHandler) {
2621 dispatchers = type.__experimentalGetPropsForEditableTreeChangeHandler(
2622 dispatch3,
2623 __unstableFormatTypeHandlerContext
2624 );
2625 }
2626 const selected = getPrefixedSelectKeys(keyedSelected, type.name);
2627 changeHandlers.push(
2628 type.__experimentalCreateOnChangeEditableValue(
2629 {
2630 ...typeof selected === "object" ? selected : {},
2631 ...dispatchers
2632 },
2633 __unstableFormatTypeHandlerContext
2634 )
2635 );
2636 }
2637 });
2638 return {
2639 formatTypes: formatTypes2,
2640 prepareHandlers,
2641 valueHandlers,
2642 changeHandlers,
2643 dependencies
2644 };
2645 }
2646
2647 // packages/rich-text/build-module/hook/index.mjs
2648 function useRichTextBase({
2649 value = "",
2650 selectionStart,
2651 selectionEnd,
2652 placeholder,
2653 onSelectionChange,
2654 preserveWhiteSpace,
2655 onChange,
2656 __unstableDisableFormats: disableFormats,
2657 __unstableIsSelected: isSelected,
2658 __unstableDependencies = [],
2659 __unstableAfterParse,
2660 __unstableBeforeSerialize,
2661 __unstableAddInvisibleFormats
2662 }) {
2663 const registry = (0, import_data9.useRegistry)();
2664 const [, forceRender] = (0, import_element5.useReducer)(() => ({}));
2665 const ref = (0, import_element5.useRef)();
2666 function createRecord() {
2667 const {
2668 ownerDocument: { defaultView }
2669 } = ref.current;
2670 const selection = defaultView.getSelection();
2671 const range = selection.rangeCount > 0 ? selection.getRangeAt(0) : null;
2672 return create({
2673 element: ref.current,
2674 range,
2675 __unstableIsEditableTree: true
2676 });
2677 }
2678 function applyRecord(newRecord, { domOnly } = {}) {
2679 apply({
2680 value: newRecord,
2681 current: ref.current,
2682 prepareEditableTree: __unstableAddInvisibleFormats,
2683 __unstableDomOnly: domOnly,
2684 placeholder
2685 });
2686 }
2687 const _valueRef = (0, import_element5.useRef)(value);
2688 const recordRef = (0, import_element5.useRef)();
2689 function setRecordFromProps() {
2690 const activeFormats = recordRef.current?.activeFormats;
2691 _valueRef.current = value;
2692 recordRef.current = value;
2693 if (!(value instanceof RichTextData)) {
2694 recordRef.current = value ? RichTextData.fromHTMLString(value, { preserveWhiteSpace }) : RichTextData.empty();
2695 }
2696 recordRef.current = {
2697 text: recordRef.current.text,
2698 formats: recordRef.current.formats,
2699 replacements: recordRef.current.replacements,
2700 activeFormats
2701 };
2702 if (disableFormats) {
2703 recordRef.current.formats = Array(value.length);
2704 recordRef.current.replacements = Array(value.length);
2705 }
2706 if (__unstableAfterParse) {
2707 recordRef.current.formats = __unstableAfterParse(
2708 recordRef.current
2709 );
2710 }
2711 recordRef.current.start = selectionStart;
2712 recordRef.current.end = selectionEnd;
2713 }
2714 const hadSelectionUpdateRef = (0, import_element5.useRef)(false);
2715 if (!recordRef.current) {
2716 hadSelectionUpdateRef.current = isSelected;
2717 setRecordFromProps();
2718 } else if (selectionStart !== recordRef.current.start || selectionEnd !== recordRef.current.end) {
2719 hadSelectionUpdateRef.current = isSelected;
2720 recordRef.current = {
2721 ...recordRef.current,
2722 start: selectionStart,
2723 end: selectionEnd,
2724 activeFormats: void 0
2725 };
2726 }
2727 function handleChange(newRecord) {
2728 recordRef.current = newRecord;
2729 applyRecord(newRecord);
2730 if (disableFormats) {
2731 _valueRef.current = newRecord.text;
2732 } else {
2733 const newFormats = __unstableBeforeSerialize ? __unstableBeforeSerialize(newRecord) : newRecord.formats;
2734 newRecord = { ...newRecord, formats: newFormats };
2735 if (typeof value === "string") {
2736 _valueRef.current = toHTMLString({
2737 value: newRecord,
2738 preserveWhiteSpace
2739 });
2740 } else {
2741 _valueRef.current = new RichTextData(newRecord);
2742 }
2743 }
2744 const { start, end, formats, text } = recordRef.current;
2745 registry.batch(() => {
2746 onSelectionChange(start, end);
2747 onChange(_valueRef.current, {
2748 __unstableFormats: formats,
2749 __unstableText: text
2750 });
2751 });
2752 forceRender();
2753 }
2754 function applyFromProps() {
2755 const previousValue = _valueRef.current;
2756 setRecordFromProps();
2757 const contentLengthChanged = previousValue && typeof previousValue === "string" && typeof value === "string" && previousValue.length !== value.length;
2758 const hasFocus = ref.current?.contains(ref.current.ownerDocument.activeElement) || ownsSelection(ref.current);
2759 const skipSelection = contentLengthChanged && !hasFocus;
2760 applyRecord(recordRef.current, { domOnly: skipSelection });
2761 }
2762 const didMountRef = (0, import_element5.useRef)(false);
2763 (0, import_element5.useLayoutEffect)(() => {
2764 if (didMountRef.current && value !== _valueRef.current) {
2765 applyFromProps();
2766 forceRender();
2767 }
2768 }, [value]);
2769 (0, import_element5.useLayoutEffect)(() => {
2770 if (!hadSelectionUpdateRef.current) {
2771 return;
2772 }
2773 if (ref.current.ownerDocument.activeElement !== ref.current && !ownsSelection(ref.current)) {
2774 ref.current.focus();
2775 }
2776 applyRecord(recordRef.current);
2777 hadSelectionUpdateRef.current = false;
2778 }, [hadSelectionUpdateRef.current]);
2779 const mergedRefs = (0, import_compose8.useMergeRefs)([
2780 ref,
2781 useDefaultStyle(),
2782 useBoundaryStyle({ record: recordRef }),
2783 useEventListeners({
2784 record: recordRef,
2785 handleChange,
2786 applyRecord,
2787 createRecord,
2788 isSelected,
2789 onSelectionChange,
2790 forceRender
2791 }),
2792 (0, import_compose8.useRefEffect)(() => {
2793 applyFromProps();
2794 didMountRef.current = true;
2795 }, [placeholder, ...__unstableDependencies])
2796 ]);
2797 return {
2798 value: recordRef.current,
2799 // A function to get the most recent value so event handlers in
2800 // useRichText implementations have access to it. For example when
2801 // listening to input events, we internally update the state, but this
2802 // state is not yet available to the input event handler because React
2803 // may re-render asynchronously.
2804 getValue: () => recordRef.current,
2805 onChange: handleChange,
2806 ref: mergedRefs
2807 };
2808 }
2809 function useRichText({
2810 allowedFormats,
2811 withoutInteractiveFormatting,
2812 onChange,
2813 __unstableDependencies = [],
2814 __unstableFormatTypeHandlerContext,
2815 ...props
2816 }) {
2817 const {
2818 formatTypes: formatTypes2,
2819 prepareHandlers,
2820 valueHandlers,
2821 changeHandlers,
2822 dependencies
2823 } = useFormatTypes({
2824 allowedFormats,
2825 withoutInteractiveFormatting,
2826 __unstableFormatTypeHandlerContext
2827 });
2828 function addEditorOnlyFormats(record) {
2829 return valueHandlers.reduce(
2830 (accumulator, fn) => fn(accumulator, record.text),
2831 record.formats
2832 );
2833 }
2834 function removeEditorOnlyFormats(record) {
2835 formatTypes2.forEach((formatType) => {
2836 if (formatType.__experimentalCreatePrepareEditableTree) {
2837 record = removeFormat(
2838 record,
2839 formatType.name,
2840 0,
2841 record.text.length
2842 );
2843 }
2844 });
2845 return record.formats;
2846 }
2847 function addInvisibleFormats(record) {
2848 return prepareHandlers.reduce(
2849 (accumulator, fn) => fn(accumulator, record.text),
2850 record.formats
2851 );
2852 }
2853 const result = useRichTextBase({
2854 ...props,
2855 onChange(value, { __unstableFormats, __unstableText }) {
2856 onChange(value, { __unstableFormats, __unstableText });
2857 Object.values(changeHandlers).forEach((changeHandler) => {
2858 changeHandler(__unstableFormats, __unstableText);
2859 });
2860 },
2861 __unstableDependencies: [...dependencies, ...__unstableDependencies],
2862 __unstableAfterParse: addEditorOnlyFormats,
2863 __unstableBeforeSerialize: removeEditorOnlyFormats,
2864 __unstableAddInvisibleFormats: addInvisibleFormats
2865 });
2866 return { ...result, formatTypes: formatTypes2 };
2867 }
2868 function useDeprecatedRichText(props) {
2869 (0, import_deprecated.default)("`__unstableUseRichText` hook", {
2870 since: "7.0"
2871 });
2872 return useRichTextBase(props);
2873 }
2874
2875 // packages/rich-text/build-module/contexts.mjs
2876 var import_element6 = __toESM(require_element(), 1);
2877 var KeyboardShortcutContext = (0, import_element6.createContext)();
2878 KeyboardShortcutContext.displayName = "KeyboardShortcutContext";
2879 var InputEventContext = (0, import_element6.createContext)();
2880 InputEventContext.displayName = "InputEventContext";
2881
2882 // packages/rich-text/build-module/keyboard-shortcut.mjs
2883 var import_keycodes3 = __toESM(require_keycodes(), 1);
2884 var import_element7 = __toESM(require_element(), 1);
2885 var import_compose9 = __toESM(require_compose(), 1);
2886 function RichTextShortcut({ character, type, onUse }) {
2887 const keyboardShortcuts = (0, import_element7.useContext)(KeyboardShortcutContext);
2888 const stableOnUse = (0, import_compose9.useEvent)(onUse);
2889 (0, import_element7.useEffect)(() => {
2890 const shortcuts = keyboardShortcuts.current;
2891 function callback(event) {
2892 if (import_keycodes3.isKeyboardEvent[type](event, character)) {
2893 stableOnUse();
2894 event.preventDefault();
2895 }
2896 }
2897 shortcuts.add(callback);
2898 return () => {
2899 shortcuts.delete(callback);
2900 };
2901 }, [character, type, keyboardShortcuts, stableOnUse]);
2902 return null;
2903 }
2904
2905 // packages/rich-text/build-module/input-event.mjs
2906 var import_element8 = __toESM(require_element(), 1);
2907 var import_compose10 = __toESM(require_compose(), 1);
2908 function RichTextInputEvent({ inputType, onInput }) {
2909 const callbacks = (0, import_element8.useContext)(InputEventContext);
2910 const stableOnInput = (0, import_compose10.useEvent)(onInput);
2911 (0, import_element8.useEffect)(() => {
2912 const inputCallbacks = callbacks.current;
2913 function callback(event) {
2914 if (event.inputType === inputType) {
2915 stableOnInput();
2916 event.preventDefault();
2917 }
2918 }
2919 inputCallbacks.add(callback);
2920 return () => {
2921 inputCallbacks.delete(callback);
2922 };
2923 }, [inputType, callbacks, stableOnInput]);
2924 return null;
2925 }
2926
2927 // packages/rich-text/build-module/event-listeners.mjs
2928 var shortcutsListener = (props) => (element) => {
2929 const { keyboardShortcuts } = props.current;
2930 function onKeyDown(event) {
2931 for (const keyboardShortcut of keyboardShortcuts.current) {
2932 keyboardShortcut(event);
2933 }
2934 }
2935 element.addEventListener("keydown", onKeyDown);
2936 return () => {
2937 element.removeEventListener("keydown", onKeyDown);
2938 };
2939 };
2940 var inputEventsListener = (props) => (element) => {
2941 const { inputEvents } = props.current;
2942 function onInput(event) {
2943 for (const inputEventHandler of inputEvents.current) {
2944 inputEventHandler(event);
2945 }
2946 }
2947 element.addEventListener("input", onInput);
2948 return () => {
2949 element.removeEventListener("input", onInput);
2950 };
2951 };
2952
2953 // packages/rich-text/build-module/private-apis.mjs
2954 var privateApis = {};
2955 lock(privateApis, {
2956 useRichText,
2957 KeyboardShortcutContext,
2958 InputEventContext,
2959 RichTextShortcut,
2960 RichTextInputEvent,
2961 shortcutsListener,
2962 inputEventsListener,
2963 ownsSelection,
2964 subscribeOwnedListener
2965 });
2966
2967 // packages/rich-text/build-module/hook/use-anchor-ref.mjs
2968 var import_element9 = __toESM(require_element(), 1);
2969 var import_deprecated2 = __toESM(require_deprecated(), 1);
2970 function useAnchorRef({ ref, value, settings = {} }) {
2971 (0, import_deprecated2.default)("`useAnchorRef` hook", {
2972 since: "6.1",
2973 alternative: "`useAnchor` hook"
2974 });
2975 const { tagName, className, name } = settings;
2976 const activeFormat = name ? getActiveFormat(value, name) : void 0;
2977 return (0, import_element9.useMemo)(() => {
2978 if (!ref.current) {
2979 return;
2980 }
2981 const {
2982 ownerDocument: { defaultView }
2983 } = ref.current;
2984 const selection = defaultView.getSelection();
2985 if (!selection.rangeCount) {
2986 return;
2987 }
2988 const range = selection.getRangeAt(0);
2989 if (!activeFormat) {
2990 return range;
2991 }
2992 let element = range.startContainer;
2993 element = element.nextElementSibling || element;
2994 while (element.nodeType !== element.ELEMENT_NODE) {
2995 element = element.parentNode;
2996 }
2997 return element.closest(
2998 tagName + (className ? "." + className : "")
2999 );
3000 }, [activeFormat, value.start, value.end, tagName, className]);
3001 }
3002
3003 // packages/rich-text/build-module/hook/use-anchor.mjs
3004 var import_compose11 = __toESM(require_compose(), 1);
3005 var import_element10 = __toESM(require_element(), 1);
3006 var import_dom = __toESM(require_dom(), 1);
3007 function getFormatElement(range, editableContentElement, tagName, className) {
3008 let element = range.startContainer;
3009 if (element.nodeType === element.TEXT_NODE && element instanceof window.Text && range.startOffset === element.length && element.nextSibling) {
3010 element = element.nextSibling;
3011 while (element.firstChild) {
3012 element = element.firstChild;
3013 }
3014 }
3015 if (element.nodeType !== element.ELEMENT_NODE) {
3016 if (!element.parentElement) {
3017 return;
3018 }
3019 element = element.parentElement;
3020 }
3021 if (element === editableContentElement) {
3022 return;
3023 }
3024 if (!editableContentElement.contains(element)) {
3025 return;
3026 }
3027 const selector = tagName + (className ? "." + className : "");
3028 if (!selector) {
3029 return;
3030 }
3031 if (!(element instanceof window.HTMLElement)) {
3032 return;
3033 }
3034 let closestElement = element;
3035 while (closestElement && closestElement !== editableContentElement) {
3036 if (closestElement.matches(selector)) {
3037 return closestElement;
3038 }
3039 closestElement = closestElement.parentElement;
3040 }
3041 return void 0;
3042 }
3043 function createVirtualAnchorElement(range, editableContentElement) {
3044 return {
3045 contextElement: editableContentElement,
3046 getBoundingClientRect() {
3047 if (editableContentElement.contains(range.startContainer)) {
3048 return (0, import_dom.getRectangleFromRange)(range) ?? range.getBoundingClientRect();
3049 }
3050 return editableContentElement.getBoundingClientRect();
3051 }
3052 };
3053 }
3054 function getAnchor(editableContentElement, tagName, className) {
3055 if (!editableContentElement) {
3056 return;
3057 }
3058 const { ownerDocument } = editableContentElement;
3059 const { defaultView } = ownerDocument;
3060 const selection = defaultView?.getSelection();
3061 if (!selection) {
3062 return;
3063 }
3064 if (!selection.rangeCount) {
3065 return;
3066 }
3067 const range = selection.getRangeAt(0);
3068 if (!range || !range.startContainer) {
3069 return;
3070 }
3071 if (!tagName && !className) {
3072 return createVirtualAnchorElement(range, editableContentElement);
3073 }
3074 return getFormatElement(range, editableContentElement, tagName, className) ?? createVirtualAnchorElement(range, editableContentElement);
3075 }
3076 var DEFAULT_SETTINGS = {
3077 tagName: "",
3078 className: ""
3079 };
3080 function useAnchor({
3081 editableContentElement,
3082 settings
3083 }) {
3084 const { tagName, className } = settings ?? DEFAULT_SETTINGS;
3085 const isActive = !!(settings && "isActive" in settings && settings.isActive);
3086 const [anchor, setAnchor] = (0, import_element10.useState)(
3087 () => getAnchor(editableContentElement, tagName, className ?? "")
3088 );
3089 const wasActive = (0, import_compose11.usePrevious)(isActive);
3090 (0, import_element10.useLayoutEffect)(() => {
3091 if (!editableContentElement) {
3092 return;
3093 }
3094 function callback() {
3095 setAnchor(
3096 getAnchor(editableContentElement, tagName, className ?? "")
3097 );
3098 }
3099 function attach() {
3100 ownerDocument.addEventListener("selectionchange", callback);
3101 }
3102 function detach() {
3103 ownerDocument.removeEventListener("selectionchange", callback);
3104 }
3105 const { ownerDocument } = editableContentElement;
3106 if (ownsSelection(editableContentElement) || // When a link is created, we need to attach the popover to the newly created anchor.
3107 !wasActive && isActive || // Sometimes we're _removing_ an active anchor, such as the inline color popover.
3108 // When we add the color, it switches from a virtual anchor to a `<mark>` element.
3109 // When we _remove_ the color, it switches from a `<mark>` element to a virtual anchor.
3110 wasActive && !isActive) {
3111 setAnchor(
3112 getAnchor(editableContentElement, tagName, className ?? "")
3113 );
3114 attach();
3115 }
3116 editableContentElement.addEventListener("focusin", attach);
3117 editableContentElement.addEventListener("focusout", detach);
3118 return () => {
3119 detach();
3120 editableContentElement.removeEventListener("focusin", attach);
3121 editableContentElement.removeEventListener("focusout", detach);
3122 };
3123 }, [editableContentElement, tagName, className, isActive, wasActive]);
3124 return anchor;
3125 }
3126
3127 // packages/rich-text/build-module/index.mjs
3128 function __experimentalRichText() {
3129 }
3130 return __toCommonJS(index_exports);
3131 })();
3132 //# sourceMappingURL=index.js.map
3133