@wistia/rich-text-editor 0.0.0 → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +28 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +31 -16
- package/dist/index.js.map +1 -1
- package/package.json +5 -5
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
# @wistia/rich-text-editor
|
|
2
|
+
|
|
3
|
+
## 0.1.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- [#4515](https://github.com/wistia/vhs/pull/4515) [`0ce53d6`](https://github.com/wistia/vhs/commit/0ce53d6f838e6d9623c3b1013acf73deb5cbcd11) Thanks [@okize](https://github.com/okize)! - Add `@wistia/rich-text-editor`. It is the `RichTextEditor` from `@wistia/vhs` in its own package, without the vhs theme or Formik.
|
|
8
|
+
|
|
9
|
+
- Works in a native form or a `FormField` from `@wistia/ui`. With `name`, it adds a hidden input that holds the content as HTML.
|
|
10
|
+
- `defaultValue` takes an HTML string or editor nodes.
|
|
11
|
+
- The `id` and `aria-*` props go to the text area. A `<label for>` names the editor, and the toolbar buttons have readable names.
|
|
12
|
+
- A disabled editor keeps its textbox role and sets `aria-disabled`.
|
|
13
|
+
- `useExternalValue` is optional. It defaults to `false`.
|
|
14
|
+
- The Image button no longer changes the current line into a `<span>`, and it accepts `.jpeg`, `.webp`, `.avif`, and `.svg` URLs.
|
|
15
|
+
- Backspace or Delete on a selected image no longer removes the character before it.
|
|
16
|
+
- CSS custom properties (`--rte-*`) change the colors, corners, and font.
|
|
17
|
+
|
|
18
|
+
### Patch Changes
|
|
19
|
+
|
|
20
|
+
- [#4516](https://github.com/wistia/vhs/pull/4516) [`95b1c86`](https://github.com/wistia/vhs/commit/95b1c86172ba20c3d95b4dc982ddb0050144ad69) Thanks [@okize](https://github.com/okize)! - Fix editor bugs.
|
|
21
|
+
|
|
22
|
+
- An HTML element that starts with a space or a comment keeps its content. Before, `<li>\n<p>Agenda</p>\n</li>` loaded as an empty line.
|
|
23
|
+
- The space between two words with different formats stays. Before, `<strong>bold</strong> <em>italic</em>` loaded as "bolditalic".
|
|
24
|
+
- Text outside a block keeps all its parts and formats. Before, `plain <strong>bold</strong> text` loaded as "plain".
|
|
25
|
+
- With `useExternalValue`, the editor shows a new `value` that starts with a list, a link, an image, or an empty line.
|
|
26
|
+
- The Link button no longer adds a `link` property to the text in the link.
|
|
27
|
+
- The Image button shows a message when the URL is not an image.
|
|
28
|
+
- The editor shows an outline while the text area has focus. `--rte-focus-color` changes its color.
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","names":[],"sources":["../src/components/RichTextEditor/types.ts","../src/components/RichTextEditor/utilities/rteFormatTypes.ts","../src/components/RichTextEditor/RichTextEditor.tsx","../src/components/RichTextEditor/serializers.ts"],"mappings":";;;;;;KAIY;EACV,aAAa;EACb,WAAW;EACX;EACA;;KAGU,aAAa,oBAAoB;KAEjC;EACV,aAAa;EACb;EACA;EACA;EACA,SAAS;EACT,WAAW;EACX;EACA;EACA;EACA;EACA;;;;qBCxBW;WACF;WACA;WACA;WACA;WACA;WACA;WACA;WACA;WACA;WACA;WACA;;;;KCyDC,sBAAsB;;;;EAIhC;;;;EAIA;;;;EAIA;;;;;EAKA,eAAe;;;;EAIf;;;;EAIA,+BAA+B;;;;EAI/B;;;;EAIA;;;;;EAKA;;;;EAIA,WAAW,OAAO;;;;EAIlB,aAAa,OAAO;;;;EAIpB;;;;EAIA,QAAQ;;;;EAIR;;;;;EAKA,QAAQ;;qBAgBG,gBAAgB,GAAG;;;qBCXnB,qBAAsB,OAAO;
|
|
1
|
+
{"version":3,"file":"index.d.ts","names":[],"sources":["../src/components/RichTextEditor/types.ts","../src/components/RichTextEditor/utilities/rteFormatTypes.ts","../src/components/RichTextEditor/RichTextEditor.tsx","../src/components/RichTextEditor/serializers.ts"],"mappings":";;;;;;KAIY;EACV,aAAa;EACb,WAAW;EACX;EACA;;KAGU,aAAa,oBAAoB;KAEjC;EACV,aAAa;EACb;EACA;EACA;EACA,SAAS;EACT,WAAW;EACX;EACA;EACA;EACA;EACA;;;;qBCxBW;WACF;WACA;WACA;WACA;WACA;WACA;WACA;WACA;WACA;WACA;WACA;;;;KCyDC,sBAAsB;;;;EAIhC;;;;EAIA;;;;EAIA;;;;;EAKA,eAAe;;;;EAIf;;;;EAIA,+BAA+B;;;;EAI/B;;;;EAIA;;;;;EAKA;;;;EAIA,WAAW,OAAO;;;;EAIlB,aAAa,OAAO;;;;EAIpB;;;;EAIA,QAAQ;;;;EAIR;;;;;EAKA,QAAQ;;qBAgBG,gBAAgB,GAAG;;;qBCXnB,qBAAsB,OAAO;qBA6Q7B,qBACX,wBACE,gCAAgC"}
|
package/dist/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
|
|
2
2
|
/*
|
|
3
|
-
* @license @wistia/rich-text-editor v0.
|
|
3
|
+
* @license @wistia/rich-text-editor v0.1.0
|
|
4
4
|
*
|
|
5
5
|
* Copyright (c) 2021-2026, Wistia, Inc. and its affiliates.
|
|
6
6
|
*
|
|
@@ -881,24 +881,42 @@ const TEXT_TAGS = {
|
|
|
881
881
|
};
|
|
882
882
|
const isTextNode = (el) => el.nodeType === 3;
|
|
883
883
|
const isElement = (el) => el.nodeType === 1;
|
|
884
|
-
const
|
|
884
|
+
const isCodeBlock = (element) => element.nodeName === "CODE";
|
|
885
|
+
const isInlineCodeBlock = (element, elementChildren) => isCodeBlock(element) && isNotNil(elementChildren[0]) && !/\n/.test(elementChildren[0]);
|
|
886
|
+
const getCodeChildren = (el) => [...el.childNodes].map((node) => {
|
|
887
|
+
if (isTextNode(node)) return node.textContent;
|
|
888
|
+
return node instanceof globalThis.Element ? node.outerHTML : void 0;
|
|
889
|
+
});
|
|
890
|
+
const isBlockElement = (el) => isElement(el) && el.nodeName in ELEMENT_TAGS && el.nodeName !== "A" && !(isCodeBlock(el) && isInlineCodeBlock(el, getCodeChildren(el)));
|
|
885
891
|
const isTextFormatElement = (el) => el.nodeName in TEXT_TAGS || el.nodeName === "A";
|
|
886
|
-
const
|
|
887
|
-
const
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
892
|
+
const isBlockNeighbor = (node) => isNotNil(node) && isBlockElement(node);
|
|
893
|
+
const isComment = (node) => node.nodeType === 8;
|
|
894
|
+
const isSpaceOnlyText = (node) => isTextNode(node) && node.nodeValue?.trim() === "";
|
|
895
|
+
const contentPastSkipped = {
|
|
896
|
+
previousSibling: /* @__PURE__ */ new WeakMap(),
|
|
897
|
+
nextSibling: /* @__PURE__ */ new WeakMap()
|
|
898
|
+
};
|
|
899
|
+
const nearestContent = (node, direction) => {
|
|
900
|
+
const saved = contentPastSkipped[direction];
|
|
901
|
+
const skipped = [];
|
|
902
|
+
let sibling = node[direction];
|
|
903
|
+
while (isNotNil(sibling) && (isComment(sibling) || isSpaceOnlyText(sibling))) {
|
|
904
|
+
if (saved.has(sibling)) {
|
|
905
|
+
sibling = saved.get(sibling) ?? null;
|
|
906
|
+
break;
|
|
907
|
+
}
|
|
908
|
+
skipped.push(sibling);
|
|
909
|
+
sibling = sibling[direction];
|
|
910
|
+
}
|
|
911
|
+
for (const skippedNode of skipped) saved.set(skippedNode, sibling);
|
|
912
|
+
return sibling;
|
|
893
913
|
};
|
|
894
914
|
const isWordSpace = (el) => {
|
|
895
915
|
const parent = el.parentNode;
|
|
896
916
|
if (isNil(parent)) return false;
|
|
897
917
|
if (parent.childNodes.length === 1) return isTextFormatElement(parent);
|
|
898
|
-
return !
|
|
918
|
+
return !isBlockNeighbor(nearestContent(el, "previousSibling")) && !isBlockNeighbor(nearestContent(el, "nextSibling"));
|
|
899
919
|
};
|
|
900
|
-
const isCodeBlock = (element) => element.nodeName === "CODE";
|
|
901
|
-
const isInlineCodeBlock = (element, elementChildren) => isCodeBlock(element) && isNotNil(elementChildren[0]) && !/\n/.test(elementChildren[0]);
|
|
902
920
|
const shouldCreateBlock = (el, children) => !isInlineCodeBlock(el, children) && isNotNil(ELEMENT_TAGS[el.nodeName]);
|
|
903
921
|
const shouldCreateText = (el, children) => isInlineCodeBlock(el, children) || isNotNil(TEXT_TAGS[el.nodeName]);
|
|
904
922
|
const htmlChildIsEmptyText = (child) => isNotNil(child) && !isString(child) && child.text?.trim() === "";
|
|
@@ -920,10 +938,7 @@ const createEditorTextElements = (children, el) => {
|
|
|
920
938
|
const blockWithOnlyTextChildren = (el) => el.nodeName === "BLOCKQUOTE" || el.nodeName === "OL" || el.nodeName === "UL";
|
|
921
939
|
const getNodeChildren = (el, mapper) => {
|
|
922
940
|
let children = [];
|
|
923
|
-
if (isCodeBlock(el)) children =
|
|
924
|
-
if (isTextNode(node)) return node.textContent;
|
|
925
|
-
return node instanceof globalThis.Element ? node.outerHTML : void 0;
|
|
926
|
-
});
|
|
941
|
+
if (isCodeBlock(el)) children = getCodeChildren(el);
|
|
927
942
|
else if (blockWithOnlyTextChildren(el)) children = [...el.childNodes].filter((node) => isTextNode(node) || isTextFormatElement(node) || node.textContent?.trim() !== "").flatMap((node) => mapper(node));
|
|
928
943
|
else children = [...el.childNodes].flatMap((node) => mapper(node));
|
|
929
944
|
return children;
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":["Image","iconsManifest","emptyTextNode","SlateEditor","Element","jsx","ElementToRender"],"sources":["../src/components/Icon/iconMap.ts","../src/components/Icon/icons/BlockQuote.tsx","../src/components/Icon/icons/Bold.tsx","../src/components/Icon/icons/BulletedList.tsx","../src/components/Icon/icons/Heading.tsx","../src/components/Icon/icons/HeadingTwo.tsx","../src/components/Icon/icons/Image.tsx","../src/components/Icon/icons/Italic.tsx","../src/components/Icon/icons/Link.tsx","../src/components/Icon/icons/NumberedList.tsx","../src/components/Icon/icons/Strikethrough.tsx","../src/components/Icon/icons/Underline.tsx","../src/components/Icon/icons/index.ts","../src/components/Icon/Icon.tsx","../src/components/RichTextEditor/ToolbarButton.tsx","../src/helpers/isUrl/isUrl.ts","../src/components/RichTextEditor/utilities/withImagesPlugin.ts","../src/components/RichTextEditor/utilities/withLinksPlugin.ts","../src/components/RichTextEditor/utilities/handleListEscape.ts","../src/components/RichTextEditor/utilities/rteFormatTypes.ts","../src/components/RichTextEditor/utilities/toggle.ts","../src/components/RichTextEditor/EditorButtons.tsx","../src/components/RichTextEditor/Element.tsx","../src/components/RichTextEditor/Leaf.tsx","../src/helpers/escapeHtml/escapeHtml.ts","../src/components/RichTextEditor/serializers.ts","../src/components/RichTextEditor/useLabelFor.ts","../src/components/RichTextEditor/utilities/useExternalValueSync.ts","../src/components/RichTextEditor/RichTextEditor.tsx"],"sourcesContent":["export const iconMap = {\n 'block-quote': 'BlockQuote',\n bold: 'Bold',\n 'bulleted-list': 'BulletedList',\n heading: 'Heading',\n 'heading-two': 'HeadingTwo',\n image: 'Image',\n italic: 'Italic',\n link: 'Link',\n 'numbered-list': 'NumberedList',\n strikethrough: 'Strikethrough',\n underline: 'Underline',\n};\n","import type { JSX, SVGProps } from 'react';\n\nexport const BlockQuote = (props: SVGProps<SVGSVGElement>): JSX.Element => (\n <svg {...props}>\n <path\n d=\"M4.2125 11.0375C4.35417 11.1792 4.53333 11.25 4.75 11.25H19.25C19.4667 11.25 19.6458 11.1792 19.7875 11.0375C19.9292 10.8958 20 10.7167 20 10.5C20 10.2833 19.9292 10.1042 19.7875 9.9625C19.6458 9.82083 19.4667 9.75 19.25 9.75H4.75C4.53333 9.75 4.35417 9.82083 4.2125 9.9625C4.07083 10.1042 4 10.2833 4 10.5C4 10.7167 4.07083 10.8958 4.2125 11.0375ZM4.2125 14.0375C4.35417 14.1792 4.53333 14.25 4.75 14.25H12.975C13.1917 14.25 13.3708 14.1792 13.5125 14.0375C13.6542 13.8958 13.725 13.7167 13.725 13.5C13.725 13.2833 13.6542 13.1042 13.5125 12.9625C13.3708 12.8208 13.1917 12.75 12.975 12.75H4.75C4.53333 12.75 4.35417 12.8208 4.2125 12.9625C4.07083 13.1042 4 13.2833 4 13.5C4 13.7167 4.07083 13.8958 4.2125 14.0375ZM1.5 10C1.22386 10 1 10.2239 1 10.5V14C1 14.2761 1.22386 14.5 1.5 14.5C1.77614 14.5 2 14.2761 2 14V10.5C2 10.2239 1.77614 10 1.5 10Z\"\n fill=\"currentColor\"\n />\n </svg>\n);\n","import type { JSX, SVGProps } from 'react';\n\nexport const Bold = (props: SVGProps<SVGSVGElement>): JSX.Element => (\n <svg {...props}>\n <path\n d=\"M16.9995 11.7C18.354 10.743 19.302 9.17101 19.302 7.71451C19.302 4.48501 16.86 1.99951 13.722 1.99951H4.998V22.0005H14.823C17.7375 22.0005 19.998 19.5705 19.998 16.5855C19.998 14.415 18.798 12.5565 16.998 11.7H16.9995ZM9.186 5.57101H13.371C14.5305 5.57101 15.465 6.52801 15.465 7.71451C15.465 8.89951 14.5305 9.85651 13.3725 9.85651H9.186V5.57101ZM14.07 18.429H9.186V14.1435H14.07C15.228 14.1435 16.1625 15.1005 16.1625 16.2855C16.1625 17.4705 15.228 18.429 14.07 18.429V18.429Z\"\n fill=\"currentColor\"\n />\n </svg>\n);\n","import type { JSX, SVGProps } from 'react';\n\nexport const BulletedList = (props: SVGProps<SVGSVGElement>): JSX.Element => (\n <svg {...props}>\n <path\n d=\"M4.0005 10.5C3.1695 10.5 2.5005 11.1705 2.5005 12C2.5005 12.8295 3.1695 13.5 4.0005 13.5C4.83 13.5 5.5005 12.8295 5.5005 12C5.5005 11.1705 4.83 10.5 4.0005 10.5ZM4.0005 4.5C3.1695 4.5 2.5005 5.1705 2.5005 6C2.5005 6.8295 3.1695 7.5 4.0005 7.5C4.83 7.5 5.5005 6.8295 5.5005 6C5.5005 5.1705 4.83 4.5 4.0005 4.5ZM4.0005 16.5C3.1695 16.5 2.5005 17.1795 2.5005 18C2.5005 18.8205 3.18 19.5 4.0005 19.5C4.8195 19.5 5.5005 18.8205 5.5005 18C5.5005 17.1795 4.83 16.5 4.0005 16.5ZM7.0005 19.0005H21V16.9995H7.0005V19.0005ZM7.0005 13.0005H21V10.9995H7.0005V13.0005ZM7.0005 4.9995V7.0005H21V4.9995H7.0005Z\"\n fill=\"currentColor\"\n />\n </svg>\n);\n","import type { JSX, SVGProps } from 'react';\n\nexport const Heading = (props: SVGProps<SVGSVGElement>): JSX.Element => (\n <svg {...props}>\n <path\n d=\"M7.9995 3V6.7995H14.154V22.0005H17.8455V6.7995H24V3H7.9995ZM0 12.9H3.666V22.0005H7.335V12.9H11.001V9H0V12.9Z\"\n fill=\"currentColor\"\n />\n </svg>\n);\n","import type { JSX, SVGProps } from 'react';\n\nexport const HeadingTwo = (props: SVGProps<SVGSVGElement>): JSX.Element => (\n <svg {...props}>\n <path\n d=\"M3 17V7H4.5V11.25H9V7H10.5V17H9V12.75H4.5V17H3ZM13.5 17V12.75C13.5 12.3333 13.6458 11.9792 13.9375 11.6875C14.2292 11.3958 14.5833 11.25 15 11.25H19.5V8.5H13.5V7H19.5C19.9167 7 20.2708 7.14583 20.5625 7.4375C20.8542 7.72917 21 8.08333 21 8.5V11.25C21 11.6667 20.8542 12.0208 20.5625 12.3125C20.2708 12.6042 19.9167 12.75 19.5 12.75H15V15.5H21V17H13.5Z\"\n fill=\"currentColor\"\n />\n </svg>\n);\n","import type { JSX, SVGProps } from 'react';\n\nexport const Image = (props: SVGProps<SVGSVGElement>): JSX.Element => (\n <svg {...props}>\n <path\n d=\"M21 19.0005V4.9995C21 3.9 20.1 3 19.0005 3H4.9995C3.9 3 3 3.9 3 4.9995V19.0005C3 20.1 3.9 21 4.9995 21H19.0005C20.1 21 21 20.1 21 19.0005ZM8.5005 13.5L10.9995 16.5105L14.5005 12L19.0005 18H4.9995L8.5005 13.5Z\"\n fill=\"currentColor\"\n />\n </svg>\n);\n","import type { JSX, SVGProps } from 'react';\n\nexport const Italic = (props: SVGProps<SVGSVGElement>): JSX.Element => (\n <svg {...props}>\n <path\n d=\"M8.8335 1.99951V6.28501H12.0555L7.0695 17.715H3V22.0005H14.667V17.715H11.4435L16.431 6.28501H20.5005V1.99951H8.8335Z\"\n fill=\"currentColor\"\n />\n </svg>\n);\n","import type { JSX, SVGProps } from 'react';\n\nexport const Link = (props: SVGProps<SVGSVGElement>): JSX.Element => (\n <svg {...props}>\n <path\n d=\"M2.28 12C2.28 9.948 3.948 8.28 6 8.28H10.8V6H6C2.688 6 0 8.688 0 12C0 15.312 2.688 18 6 18H10.8V15.72H6C3.948 15.72 2.28 14.052 2.28 12ZM7.2 13.2H16.8V10.8H7.2V13.2ZM18 6H13.2V8.28H18C20.052 8.28 21.72 9.948 21.72 12C21.72 14.052 20.052 15.72 18 15.72H13.2V18H18C21.312 18 24 15.312 24 12C24 8.688 21.312 6 18 6Z\"\n fill=\"currentColor\"\n />\n </svg>\n);\n","import type { JSX, SVGProps } from 'react';\n\nexport const NumberedList = (props: SVGProps<SVGSVGElement>): JSX.Element => (\n <svg {...props}>\n <path\n d=\"M3.425 20C3.30833 20 3.20833 19.9583 3.125 19.875C3.04167 19.7917 3 19.6917 3 19.575C3 19.4583 3.04167 19.3583 3.125 19.275C3.20833 19.1917 3.30833 19.15 3.425 19.15H5.1V18.5H4.475C4.35833 18.5 4.25833 18.4583 4.175 18.375C4.09167 18.2917 4.05 18.1917 4.05 18.075C4.05 17.9583 4.09167 17.8583 4.175 17.775C4.25833 17.6917 4.35833 17.65 4.475 17.65H5.1V17H3.425C3.30833 17 3.20833 16.9583 3.125 16.875C3.04167 16.7917 3 16.6917 3 16.575C3 16.4583 3.04167 16.3583 3.125 16.275C3.20833 16.1917 3.30833 16.15 3.425 16.15H5.525C5.64167 16.15 5.74167 16.1917 5.825 16.275C5.90833 16.3583 5.95 16.4583 5.95 16.575V19.575C5.95 19.6917 5.90833 19.7917 5.825 19.875C5.74167 19.9583 5.64167 20 5.525 20H3.425ZM4.475 7.9C4.35833 7.9 4.25833 7.85833 4.175 7.775C4.09167 7.69167 4.05 7.59167 4.05 7.475V4.85H3.425C3.30833 4.85 3.20833 4.80833 3.125 4.725C3.04167 4.64167 3 4.54167 3 4.425C3 4.30833 3.04167 4.20833 3.125 4.125C3.20833 4.04167 3.30833 4 3.425 4H4.475C4.59167 4 4.69167 4.04167 4.775 4.125C4.85833 4.20833 4.9 4.30833 4.9 4.425V7.475C4.9 7.59167 4.85833 7.69167 4.775 7.775C4.69167 7.85833 4.59167 7.9 4.475 7.9V7.9ZM3.425 13.925C3.30833 13.925 3.20833 13.8833 3.125 13.8C3.04167 13.7167 3 13.6167 3 13.5V13.275C3 13.2583 3.03333 13.1667 3.1 13L4.875 10.925H3.425C3.30833 10.925 3.20833 10.8833 3.125 10.8C3.04167 10.7167 3 10.6167 3 10.5C3 10.3833 3.04167 10.2833 3.125 10.2C3.20833 10.1167 3.30833 10.075 3.425 10.075H5.525C5.64167 10.075 5.74167 10.1167 5.825 10.2C5.90833 10.2833 5.95 10.3833 5.95 10.5V10.725C5.95 10.7417 5.91667 10.8333 5.85 11L4.05 13.075H5.525C5.64167 13.075 5.74167 13.1167 5.825 13.2C5.90833 13.2833 5.95 13.3833 5.95 13.5C5.95 13.6167 5.90833 13.7167 5.825 13.8C5.74167 13.8833 5.64167 13.925 5.525 13.925H3.425ZM8.975 18.775C8.75833 18.775 8.57917 18.7042 8.4375 18.5625C8.29583 18.4208 8.225 18.2417 8.225 18.025C8.225 17.8083 8.29583 17.6292 8.4375 17.4875C8.57917 17.3458 8.75833 17.275 8.975 17.275H20.25C20.4667 17.275 20.6458 17.3458 20.7875 17.4875C20.9292 17.6292 21 17.8083 21 18.025C21 18.2417 20.9292 18.4208 20.7875 18.5625C20.6458 18.7042 20.4667 18.775 20.25 18.775H8.975ZM8.975 12.7C8.75833 12.7 8.57917 12.6292 8.4375 12.4875C8.29583 12.3458 8.225 12.1667 8.225 11.95C8.225 11.7333 8.29583 11.5542 8.4375 11.4125C8.57917 11.2708 8.75833 11.2 8.975 11.2H20.25C20.4667 11.2 20.6458 11.2708 20.7875 11.4125C20.9292 11.5542 21 11.7333 21 11.95C21 12.1667 20.9292 12.3458 20.7875 12.4875C20.6458 12.6292 20.4667 12.7 20.25 12.7H8.975ZM8.975 6.625C8.75833 6.625 8.57917 6.55417 8.4375 6.4125C8.29583 6.27083 8.225 6.09167 8.225 5.875C8.225 5.65833 8.29583 5.47917 8.4375 5.3375C8.57917 5.19583 8.75833 5.125 8.975 5.125H20.25C20.4667 5.125 20.6458 5.19583 20.7875 5.3375C20.9292 5.47917 21 5.65833 21 5.875C21 6.09167 20.9292 6.27083 20.7875 6.4125C20.6458 6.55417 20.4667 6.625 20.25 6.625H8.975Z\"\n fill=\"currentColor\"\n />\n </svg>\n);\n","import type { JSX, SVGProps } from 'react';\n\nexport const Strikethrough = (props: SVGProps<SVGSVGElement>): JSX.Element => (\n <svg {...props}>\n <path\n d=\"M2 13.75V12.25H22V13.75H2ZM10.75 10.75V6.5H5V4H19V6.5H13.25V10.75H10.75ZM10.75 20V15.25H13.25V20H10.75Z\"\n fill=\"currentColor\"\n />\n </svg>\n);\n","import type { JSX, SVGProps } from 'react';\n\nexport const Underline = (props: SVGProps<SVGSVGElement>): JSX.Element => (\n <svg {...props}>\n <path\n d=\"M5 21V19.5H19V21H5ZM12 17C10.3167 17 8.89583 16.425 7.7375 15.275C6.57917 14.125 6 12.7167 6 11.05V3H8V11.1C8 12.2 8.38333 13.125 9.15 13.875C9.91667 14.625 10.8667 15 12 15C13.1333 15 14.0833 14.625 14.85 13.875C15.6167 13.125 16 12.2 16 11.1V3H18V11.05C18 12.7167 17.4208 14.125 16.2625 15.275C15.1042 16.425 13.6833 17 12 17Z\"\n fill=\"currentColor\"\n />\n </svg>\n);\n","export { BlockQuote } from './BlockQuote';\nexport { Bold } from './Bold';\nexport { BulletedList } from './BulletedList';\nexport { Heading } from './Heading';\nexport { HeadingTwo } from './HeadingTwo';\nexport { Image } from './Image';\nexport { Italic } from './Italic';\nexport { Link } from './Link';\nexport { NumberedList } from './NumberedList';\nexport { Strikethrough } from './Strikethrough';\nexport { Underline } from './Underline';\n","import type { FC } from 'react';\nimport { isNil } from '@wistia/type-guards';\nimport { iconMap } from './iconMap';\n// oxlint-disable-next-line barrel-files/avoid-namespace-import -- needed to enumerate icon exports\nimport * as iconsManifest from './icons';\n\n// size in pixels\nconst iconSizeMap = {\n sm: '12',\n md: '16',\n lg: '24',\n xl: '32',\n xxl: '48',\n};\n\nexport type IconProps = {\n /**\n * Color (as hex) of the Icon\n */\n color?: string;\n /**\n * The size of the icon to display\n */\n size?: keyof typeof iconSizeMap;\n /**\n * @ignore\n */\n style?: Record<string, unknown>;\n /**\n * Determines which icon to display\n */\n type: keyof typeof iconMap;\n};\n\nexport const Icon: FC<IconProps> = ({\n color = 'currentColor',\n size = 'lg',\n style,\n type,\n ...otherProps\n}) => {\n if (isNil(type)) {\n throw new Error('An Icon component requires a `type` prop to be provided');\n }\n\n if (isNil(iconMap[type])) {\n throw new Error(`Type \"${type}\" does not exist, please update type prop in Icon component.`);\n }\n\n if (isNil(iconSizeMap[size])) {\n throw new Error(`Size \"${size}\" does not exist, please update size prop in Icon component.`);\n }\n\n // oxlint-disable-next-line import/namespace -- dynamic lookup by icon name; key is type-checked via keyof typeof iconsManifest\n const IconElement = iconsManifest[iconMap[type] as keyof typeof iconsManifest];\n\n // so we do not have to add this to each individual Icon but still allow overrides\n const defaultStyle = { verticalAlign: 'middle', ...style };\n\n return (\n <IconElement\n aria-hidden=\"true\"\n color={color}\n height={`${iconSizeMap[size]}px`}\n role=\"presentation\"\n style={defaultStyle}\n viewBox=\"0 0 24 24\"\n width={`${iconSizeMap[size]}px`}\n xmlns=\"http://www.w3.org/2000/svg\"\n {...otherProps}\n />\n );\n};\n\nIcon.displayName = 'Icon';\n","import type { ComponentPropsWithoutRef, JSX, ReactNode } from 'react';\nimport { styled } from 'styled-components';\n\n// Matches the vhs IconButton (size \"md\", dark style) the toolbar used before the package split.\n// Round by default because every VMA root renders vhs with `wistiaTheme`, whose buttons are round.\nconst StyledToolbarButton = styled.button<{ $isActive: boolean }>`\n --rte-toolbar-button-color: ${({ $isActive }) =>\n $isActive ? 'var(--rte-accent-color, #2949e5)' : 'var(--rte-icon-color, #62626c)'};\n\n align-items: center;\n appearance: none;\n background-color: transparent;\n background-image: none;\n border: none;\n border-radius: var(--rte-toolbar-button-radius, 1000px);\n box-shadow: none;\n color: var(--rte-toolbar-button-color);\n cursor: pointer;\n display: inline-flex;\n font: inherit;\n height: 24px;\n justify-content: center;\n line-height: 1;\n padding: 0;\n transition: all 110ms;\n vertical-align: middle;\n width: 24px;\n\n svg {\n height: 16px;\n width: 16px;\n }\n\n &::-moz-focus-inner {\n border: 0;\n padding: 0;\n }\n\n &:focus-visible {\n outline: thin dotted #999999;\n }\n\n &:hover,\n &:focus-visible {\n background-color: color-mix(in srgb, var(--rte-toolbar-button-color) 20%, transparent);\n }\n\n &:active {\n background-color: color-mix(in srgb, var(--rte-toolbar-button-color) 40%, transparent);\n }\n\n &:disabled {\n background-color: transparent;\n color: color-mix(in srgb, var(--rte-toolbar-button-color) 50%, transparent);\n cursor: not-allowed;\n }\n`;\n\nexport type ToolbarButtonProps = Omit<\n ComponentPropsWithoutRef<'button'>,\n 'aria-label' | 'children' | 'type'\n> & {\n /**\n * Icon shown inside the button\n */\n icon: ReactNode;\n /**\n * Shows the button in the accent color\n */\n isActive: boolean;\n /**\n * Accessible name of the button\n */\n label: string;\n};\n\nexport const ToolbarButton = ({\n icon,\n isActive,\n label,\n ...props\n}: ToolbarButtonProps): JSX.Element => (\n <StyledToolbarButton\n {...props}\n $isActive={isActive}\n aria-label={label}\n type=\"button\"\n >\n {icon}\n </StyledToolbarButton>\n);\n","import { isString } from '@wistia/type-guards';\n\n/**\n * Loosely validates a URL string\n *\n * @param {*} str - a string to validate - could be an unknown type\n * @return {boolean} - whether string appears to be a url\n */\nexport const isUrl = (str: unknown): boolean => {\n // A URL must match #1 and then at least one of #2/#3\n // Use two levels of REs to avoid ReDoS\n // https://levelup.gitconnected.com/the-regular-expression-denial-of-service-redos-cheat-sheet-a78d0ed7d865\n const protocolAndDomain = /^(?:\\w+:)?\\/\\/(\\S+)$/;\n const localhostDomain = /^localhost[:?\\d]*(?:[^:?\\d]\\S*)?$/;\n const nonLocalhostDomain = /^[^\\s.]+\\.\\S{2,}$/;\n\n if (!isString(str)) {\n return false;\n }\n\n const match = protocolAndDomain.exec(str);\n\n if (!match) {\n return false;\n }\n\n // part of the string that is not the protocol\n const remaining = match[1];\n\n if (remaining === undefined || !remaining) {\n return false;\n }\n\n return localhostDomain.test(remaining) || nonLocalhostDomain.test(remaining);\n};\n","import type { Node, Editor } from 'slate';\nimport { isNotUndefined, isNotNil } from '@wistia/type-guards';\nimport { Transforms, Element, Text } from 'slate';\nimport { isUrl } from '../../../helpers/isUrl';\n\n// All Element nodes must contain at least one Text descendant.\n// If an element node does not contain any children,\n// an empty text node will be added as its only child.\n// Read more at https://docs.slatejs.org/concepts/10-normalizing\nconst emptyTextNode = { text: '' };\n// a URL counts as an image when it contains one of these anywhere, so query strings like `?fm=jpg` work\nconst imageExtensions = ['jpg', 'jpeg', 'png', 'gif', 'webp', 'avif', 'svg', 'tiff', 'bmp', 'dcm'];\n\nconst isImageUrl = (url: string) => {\n if (!isUrl(url)) {\n return false;\n }\n const hasImageExtension = imageExtensions.find((event) => url.includes(event));\n return isNotUndefined(hasImageExtension) && Boolean(hasImageExtension);\n};\n\n// returns false, and changes nothing, when the URL is not an image\nexport const insertImage = (editor: Editor, url: string): boolean => {\n if (!isImageUrl(url)) {\n return false;\n }\n\n const image = { type: 'image', url, children: [emptyTextNode] };\n Transforms.insertNodes(editor, image);\n return true;\n};\n\nexport const withImages = (editor: Editor): Editor => {\n const { normalizeNode, isVoid } = editor;\n editor.isVoid = (element: Element) => (element.type === 'image' ? true : isVoid(element));\n\n editor.normalizeNode = ([node, path]: [Node, number[]]) => {\n if (Element.isElement(node) && node.type === 'image' && node.url !== undefined) {\n const paragraph = {\n type: 'paragraph',\n children: [emptyTextNode],\n };\n\n const pathIndex = isNotUndefined(path[0]) ? path[0] + 1 : 1;\n Transforms.insertNodes(editor, paragraph, { at: [pathIndex] });\n Transforms.move(editor);\n }\n if (\n Element.isElement(node) &&\n node.type === 'image' &&\n node.url === undefined &&\n isNotUndefined(node.children) &&\n isNotUndefined(node.children[0]) &&\n isNotUndefined(node.children[0].text) &&\n node.children[0].text.trim() !== ''\n ) {\n Transforms.setNodes(\n editor,\n { type: 'span' },\n {\n match: (matchNode: Node) =>\n Element.isElement(matchNode) &&\n matchNode.type === 'image' &&\n matchNode.url === undefined &&\n isNotUndefined(matchNode.children) &&\n Text.isText(matchNode.children[0]) &&\n isNotNil(matchNode.children[0].text) &&\n matchNode.children[0].text.trim() !== '',\n split: true,\n at: path,\n mode: 'highest',\n },\n );\n }\n normalizeNode([node, path]);\n };\n\n return editor;\n};\n","import type { CustomEditor } from '../types';\nimport { isNonEmptyString } from '@wistia/type-guards';\nimport { Transforms, Element, Node, Editor, Range, Path } from 'slate';\nimport { isUrl } from '../../../helpers/isUrl';\n\nconst isHashUrl = (urlString: string) => {\n const urlPattern = /^#.+$/i;\n return urlPattern.test(urlString);\n};\n\nconst isLinkActive = (editor: Editor) => {\n const [link] = Editor.nodes(editor, {\n match: (node: Node) => Element.isElement(node) && node.type === 'link',\n });\n return Boolean(link);\n};\n\nconst unwrapLink = (editor: Editor) => {\n Transforms.unwrapNodes(editor, {\n match: (node: Node) => Element.isElement(node) && node.type === 'link',\n });\n};\n\nconst wrapLink = (editor: Editor, url: string) => {\n if (isLinkActive(editor)) {\n unwrapLink(editor);\n }\n\n const { selection } = editor;\n const isCollapsed = selection && Range.isCollapsed(selection);\n const link = {\n type: 'link',\n url,\n children: isCollapsed === true ? [{ text: url }] : [],\n };\n\n if (isCollapsed === true) {\n Transforms.insertNodes(editor, link);\n } else {\n Transforms.wrapNodes(editor, link, { split: true });\n Transforms.collapse(editor, { edge: 'end' });\n }\n};\n\nexport const withLinks = (editor: CustomEditor): CustomEditor => {\n const { insertData, insertText, isInline, normalizeNode } = editor;\n\n editor.isInline = (element: Element) => (element.type === 'link' ? true : isInline(element));\n\n editor.insertText = (text: string) => {\n if (text && isUrl(text)) {\n wrapLink(editor, text);\n } else {\n insertText(text);\n }\n };\n\n editor.insertData = (data: DataTransfer) => {\n const text = data.getData('text/plain');\n\n if (text && isUrl(text)) {\n wrapLink(editor, text);\n } else {\n insertData(data);\n }\n };\n\n editor.normalizeNode = ([node, path]: [Node, Path]) => {\n if (Element.isElement(node) && node.type === 'link' && Node.string(node) === '') {\n Transforms.unwrapNodes(editor, { at: path });\n Transforms.select(editor, Path.next(path));\n }\n normalizeNode([node, path]);\n };\n\n return editor;\n};\n\nexport const insertLink = (editor: Editor): void => {\n if (isLinkActive(editor)) {\n unwrapLink(editor);\n } else {\n // oxlint-disable-next-line no-alert\n const url = prompt('Enter the URL of the link:');\n\n if (!isNonEmptyString(url)) {\n return;\n }\n\n const urlHasSpaces = url.includes(' ');\n if (urlHasSpaces) {\n // oxlint-disable-next-line no-alert\n alert('The URL provided had spaces. Try again without spaces.');\n return;\n }\n\n if (!isUrl(url) && !isHashUrl(url)) {\n // oxlint-disable-next-line no-alert\n alert(\n 'The URL provided looks invalid. Try again. Make sure to include the protocol (ex. https://) in the URL.',\n );\n return;\n }\n\n if (editor.selection) {\n wrapLink(editor, url);\n }\n }\n};\n","import type { EditorInterface, Descendant, Node } from 'slate';\nimport type { NodeLeafObject } from '../types';\nimport { Transforms, Range, Editor, Element } from 'slate';\n\n// Allowing non-null assertions in this file for sake of TS conversion.\n/* oxlint-disable @typescript-eslint/no-non-null-assertion */\nconst OverriddenEditor: EditorInterface & { isBlock: typeof Editor.isBlock } = {\n ...Editor,\n isBlock: Editor.isBlock,\n};\n\n// All Element nodes must contain at least one Text descendant.\n// If an element node does not contain any children,\n// an empty text node will be added as its only child.\n// Read more at https://docs.slatejs.org/concepts/10-normalizing\nconst newLine = {\n type: 'paragraph',\n children: [\n {\n text: '',\n marks: [],\n },\n ],\n};\n\nconst isLastChildBlankText = (listChildren: Descendant[] | NodeLeafObject[]): boolean => {\n if (listChildren.length === 1) {\n // @ts-expect-error - Text does exist on some sub-types of nodes.\n return (listChildren.at(-1)?.text as string | null)?.trim() === '';\n }\n // Links need to be handled differently because they're surrounded by empty text by SlateJS design here.\n const link = listChildren.find((el) => el.type === 'link');\n return link?.children![0]?.text?.trim() === '';\n};\n\nexport const handleListEscape = (editor: Editor): void => {\n const { selection } = editor;\n const textIsNotSelected = selection && Range.isCollapsed(selection);\n const selectedElement = editor.children[selection!.anchor.path[0]!]!;\n const isList =\n selectedElement.type === 'bulleted-list' || selectedElement.type === 'numbered-list';\n const blockAbove = OverriddenEditor.above(editor, {\n match: (node: Node) => Element.isElement(node) && OverriddenEditor.isBlock(editor, node),\n })!;\n if ((textIsNotSelected ?? false) && isList && isLastChildBlankText(blockAbove[0].children!)) {\n Transforms.removeNodes(editor, { hanging: true });\n Transforms.insertNodes(editor, newLine);\n Transforms.unwrapNodes(editor, {\n // @ts-expect-error - type does exist on some sub-types of nodes.\n match: ({ type }: { type?: string }) => type === 'bulleted-list' || type === 'numbered-list',\n all: true,\n split: true,\n });\n }\n};\n","export const rteFormatTypes: {\n readonly BOLD: 'BOLD';\n readonly ITALIC: 'ITALIC';\n readonly UNDERLINE: 'UNDERLINE';\n readonly STRIKETHROUGH: 'STRIKETHROUGH';\n readonly HEADING_1: 'HEADING_1';\n readonly HEADING_2: 'HEADING_2';\n readonly BLOCKQUOTE: 'BLOCKQUOTE';\n readonly NUMBERED_LIST: 'NUMBERED_LIST';\n readonly BULLETED_LIST: 'BULLETED_LIST';\n readonly LINK: 'LINK';\n readonly IMAGE: 'IMAGE';\n} = Object.freeze({\n BOLD: 'BOLD',\n ITALIC: 'ITALIC',\n UNDERLINE: 'UNDERLINE',\n STRIKETHROUGH: 'STRIKETHROUGH',\n HEADING_1: 'HEADING_1',\n HEADING_2: 'HEADING_2',\n BLOCKQUOTE: 'BLOCKQUOTE',\n NUMBERED_LIST: 'NUMBERED_LIST',\n BULLETED_LIST: 'BULLETED_LIST',\n LINK: 'LINK',\n IMAGE: 'IMAGE',\n});\n","import type { Node, Editor } from 'slate';\nimport { isNotNil, isNonEmptyString } from '@wistia/type-guards';\nimport { Element, Transforms, Editor as SlateEditor } from 'slate';\n\nexport const isBlockActive = (editor: Editor, format: string): boolean => {\n const [match] = SlateEditor.nodes(editor, {\n match: (node: Node) => Element.isElement(node) && node.type === format,\n });\n return Boolean(match);\n};\n\nconst LIST_TYPES = new Set(['numbered-list', 'bulleted-list']);\n\nexport const toggleBlock = (editor: Editor, format: string): void => {\n const isActive = isBlockActive(editor, format);\n\n const isList = LIST_TYPES.has(format);\n Transforms.unwrapNodes(editor, {\n match: (node: Node) =>\n Element.isElement(node) && isNotNil(node.type) && LIST_TYPES.has(node.type),\n split: true,\n });\n const formatting = isList ? 'list-item' : format;\n\n Transforms.setNodes(editor, {\n type: isActive ? 'paragraph' : formatting,\n });\n\n if (!isActive && isList) {\n const block = { type: format, children: [] };\n Transforms.wrapNodes(editor, block);\n }\n};\n\nexport const isMarkActive = (editor: Editor, format: string): boolean => {\n const valueMarks = SlateEditor.marks(editor);\n return isNonEmptyString(valueMarks && Object.keys(valueMarks).find((mark) => mark === format));\n};\n\nexport const toggleMark = (editor: Editor, format: string): void => {\n const isActive = isMarkActive(editor, format);\n\n if (isActive) {\n SlateEditor.removeMark(editor, format);\n } else {\n SlateEditor.addMark(editor, format, true);\n }\n};\n","import type { MouseEvent, JSX } from 'react';\nimport type { Editor } from 'slate';\nimport type { iconMap } from '../Icon/iconMap';\nimport { isNonEmptyString } from '@wistia/type-guards';\nimport { Node } from 'slate';\nimport { useSlate } from 'slate-react';\nimport { styled } from 'styled-components';\nimport { Icon } from '../Icon';\nimport { ToolbarButton } from './ToolbarButton';\nimport {\n rteFormatTypes,\n insertImage,\n insertLink,\n isBlockActive,\n toggleBlock,\n isMarkActive,\n toggleMark,\n} from './utilities';\n\nconst ButtonContainer = styled.div`\n background: var(--rte-background, #ffffff);\n border-bottom: 1px solid var(--rte-border-color, #c4c4c8);\n display: flex;\n gap: 8px;\n padding: 8px 0;\n position: sticky;\n top: 0;\n\n /* needs a stacking context to stay above RTE content */\n z-index: 1;\n`;\n\ntype EditorButtonProps = {\n /**\n * `block` and `mark` buttons toggle their format. An `insert` button only runs `onCustomClick`.\n */\n buttonType: 'block' | 'insert' | 'mark';\n disabled: boolean;\n format: string;\n icon: keyof typeof iconMap;\n /**\n * Accessible name of the button\n */\n label: string;\n /**\n * Runs after the click toggles the format. A button with this callback is an action, not a toggle,\n * so it does not get `aria-pressed`.\n */\n onCustomClick?: (event: MouseEvent) => unknown;\n};\n\nconst EditorButton = ({\n buttonType,\n disabled,\n format,\n icon,\n label,\n onCustomClick,\n}: EditorButtonProps) => {\n const editor = useSlate();\n const isActive =\n buttonType === 'mark' ? isMarkActive(editor, format) : isBlockActive(editor, format);\n const handleClick = (event: MouseEvent) => {\n event.preventDefault();\n if (buttonType === 'block') {\n toggleBlock(editor, format);\n } else if (buttonType === 'mark') {\n toggleMark(editor, format);\n }\n if (onCustomClick) {\n onCustomClick(event);\n }\n };\n\n return (\n <ToolbarButton\n aria-pressed={onCustomClick ? undefined : isActive}\n disabled={disabled}\n icon={<Icon type={icon} />}\n isActive={isActive}\n label={label}\n onClick={handleClick}\n />\n );\n};\n\ntype FormatButtonConfig = Pick<EditorButtonProps, 'buttonType' | 'format' | 'icon' | 'label'> & {\n enabledFormat: keyof typeof rteFormatTypes;\n};\n\n// in toolbar order; the link and image buttons always come last\nconst FORMAT_BUTTONS: FormatButtonConfig[] = [\n { enabledFormat: 'BOLD', buttonType: 'mark', format: 'bold', icon: 'bold', label: 'Bold' },\n {\n enabledFormat: 'ITALIC',\n buttonType: 'mark',\n format: 'italic',\n icon: 'italic',\n label: 'Italic',\n },\n {\n enabledFormat: 'HEADING_1',\n buttonType: 'block',\n format: 'heading-one',\n icon: 'heading',\n label: 'Heading 1',\n },\n {\n enabledFormat: 'HEADING_2',\n buttonType: 'block',\n format: 'heading-two',\n icon: 'heading-two',\n label: 'Heading 2',\n },\n {\n enabledFormat: 'BULLETED_LIST',\n buttonType: 'block',\n format: 'bulleted-list',\n icon: 'bulleted-list',\n label: 'Bulleted list',\n },\n {\n enabledFormat: 'NUMBERED_LIST',\n buttonType: 'block',\n format: 'numbered-list',\n icon: 'numbered-list',\n label: 'Numbered list',\n },\n {\n enabledFormat: 'BLOCKQUOTE',\n buttonType: 'block',\n format: 'blockquote',\n icon: 'block-quote',\n label: 'Block quote',\n },\n {\n enabledFormat: 'UNDERLINE',\n buttonType: 'mark',\n format: 'underline',\n icon: 'underline',\n label: 'Underline',\n },\n {\n enabledFormat: 'STRIKETHROUGH',\n buttonType: 'mark',\n format: 'strikethrough',\n icon: 'strikethrough',\n label: 'Strikethrough',\n },\n];\n\nconst getSelectedText = (editor: Editor): string => {\n if (!editor.selection) {\n return '';\n }\n const nodeFragment = Node.fragment(editor, editor.selection);\n if (!nodeFragment[0]) {\n return '';\n }\n return Node.string(nodeFragment[0]);\n};\n\nconst noTextSelected = (editor: Editor) => {\n const userSelection = getSelectedText(editor);\n return userSelection.trim() === '';\n};\n\nexport type EditorButtonsProps = {\n disabled: boolean;\n enabledFormats: (keyof typeof rteFormatTypes)[];\n};\n\nexport const EditorButtons = ({ enabledFormats, disabled }: EditorButtonsProps): JSX.Element => {\n const editor = useSlate();\n return (\n <ButtonContainer>\n {FORMAT_BUTTONS.filter(({ enabledFormat }) => enabledFormats.includes(enabledFormat)).map(\n ({ enabledFormat, ...buttonProps }) => (\n <EditorButton\n key={enabledFormat}\n {...buttonProps}\n disabled={disabled}\n />\n ),\n )}\n {enabledFormats.includes(rteFormatTypes.LINK) && (\n <EditorButton\n // a link is an element, not a text format, so the button shows active inside a link\n buttonType=\"insert\"\n disabled={disabled || noTextSelected(editor)}\n format=\"link\"\n icon=\"link\"\n label=\"Link\"\n onCustomClick={() => {\n insertLink(editor);\n }}\n />\n )}\n {enabledFormats.includes(rteFormatTypes.IMAGE) && (\n <EditorButton\n buttonType=\"insert\"\n disabled={disabled}\n format=\"image\"\n icon=\"image\"\n label=\"Image\"\n onCustomClick={() => {\n // oxlint-disable-next-line no-alert\n const promptUserForImageUrl = prompt('Enter the URL of the image:');\n if (!isNonEmptyString(promptUserForImageUrl)) {\n return;\n }\n if (!insertImage(editor, promptUserForImageUrl)) {\n // oxlint-disable-next-line no-alert\n alert(\n 'The URL provided is not an image. Try again. Make sure to include the protocol (ex. https://) and a file type such as .png or .jpg in the URL.',\n );\n }\n }}\n />\n )}\n </ButtonContainer>\n );\n};\n","import type { JSX } from 'react';\nimport type { RenderElementProps } from 'slate-react';\nimport { useSelected, useFocused } from 'slate-react';\nimport { styled, css } from 'styled-components';\n\nconst Wrapper = styled.span`\n display: inline-block;\n user-select: none;\n`;\n\ntype ImageProps = {\n $isHighlighted: boolean;\n};\nconst Image = styled.img<ImageProps>`\n box-shadow: ${({ $isHighlighted }) =>\n $isHighlighted ? '0 0 0 3px var(--rte-accent-color, #2949e5)' : 'none'};\n max-height: 10em;\n max-width: 100%;\n user-select: none;\n`;\n\nconst listStyle = css`\n padding: 0 24px;\n\n li {\n font-size: 14px;\n font-style: normal;\n font-weight: 400;\n margin: 8px 0;\n }\n`;\n\nconst EditorOrderedList = styled.ol`\n ${listStyle}\n`;\n\nconst EditorUnorderedList = styled.ul`\n ${listStyle}\n`;\n\nconst headerStyle = css`\n font-weight: 500;\n`;\n\nconst EditorHeading1 = styled.h1`\n ${headerStyle}\n font-size: 18px;\n`;\n\nconst EditorHeading2 = styled.h2`\n ${headerStyle}\n font-size: 16px;\n`;\n\nconst EditorHeading3 = styled.h3`\n ${headerStyle}\n font-size: 14px;\n`;\n\nconst EditorParagraph = styled.p`\n font-weight: 400;\n`;\n\nconst EditorLink = styled.a`\n color: var(--rte-accent-color, #2949e5);\n font-weight: 300;\n`;\n\nconst EditorSpan = styled.span`\n font-weight: 400;\n`;\n\nexport const Element = ({ attributes, children, element }: RenderElementProps): JSX.Element => {\n const selected = useSelected();\n const focused = useFocused();\n\n switch (element.type) {\n case 'span':\n return <EditorSpan {...attributes}>{children}</EditorSpan>;\n case 'blockquote':\n return <blockquote {...attributes}>{children}</blockquote>;\n case 'bulleted-list':\n return <EditorUnorderedList {...attributes}>{children}</EditorUnorderedList>;\n case 'heading-one':\n return <EditorHeading1 {...attributes}>{children}</EditorHeading1>;\n case 'heading-two':\n return <EditorHeading2 {...attributes}>{children}</EditorHeading2>;\n // We render h4-h6 as h3s in the editor UI per Design request\n // (Though we preserve the original headers \"under the hood\" in the HTML).\n case 'heading-three':\n case 'heading-four':\n case 'heading-five':\n case 'heading-six':\n return <EditorHeading3 {...attributes}>{children}</EditorHeading3>;\n case 'list-item':\n return <li {...attributes}>{children}</li>;\n case 'numbered-list':\n return <EditorOrderedList {...attributes}>{children}</EditorOrderedList>;\n case 'image':\n return (\n <Wrapper {...attributes}>\n <Wrapper contentEditable={false}>\n <Image\n alt=\"\"\n contentEditable={false}\n $isHighlighted={selected && focused}\n src={element.url}\n />\n </Wrapper>\n {children}\n </Wrapper>\n );\n case 'link':\n return (\n <EditorLink\n {...attributes}\n href={element.url}\n rel=\"noopener noreferrer\"\n target=\"_blank\"\n >\n {children}\n </EditorLink>\n );\n case 'code':\n return <code {...attributes}>{children}</code>;\n case undefined:\n default:\n return <EditorParagraph {...attributes}>{children}</EditorParagraph>;\n }\n};\n","import type { JSX } from 'react';\nimport type { RenderLeafProps } from 'slate-react';\nimport { isNotNil } from '@wistia/type-guards';\n\nexport const Leaf = ({ attributes, children, leaf }: RenderLeafProps): JSX.Element => {\n // Slate-React allows for children to be any type.\n // oxlint-disable-next-line @typescript-eslint/no-unsafe-assignment\n let kids = children;\n if (isNotNil(leaf.bold)) {\n kids = <strong>{kids}</strong>;\n }\n\n if (isNotNil(leaf.italic)) {\n kids = <em>{kids}</em>;\n }\n\n if (isNotNil(leaf.underline)) {\n kids = <u>{kids}</u>;\n }\n\n if (isNotNil(leaf.strikethrough)) {\n kids = <s>{kids}</s>;\n }\n\n if (isNotNil(leaf.code)) {\n kids = <code>{kids}</code>;\n }\n\n return <span {...attributes}>{kids}</span>;\n};\n","// note: adapted from https://github.com/component/escape-html/blob/master/index.js because that's what we\n// were already using, but we should consider using https://www.npmjs.com/package/@wordpress/escape-html in the future\nconst matchHtmlRegExp = /[\"'&<>]/;\nconst doubleQuoteChar = 34; // \"\nconst ampersandChar = 38; // &\nconst singleQuoteChar = 39; // '\nconst lessThanChar = 60; // <\nconst greaterThanChar = 62; // >\n\n/**\n * Handle special characters by escaping in the provided text string.\n *\n * @param {string} stringToEscape - the string to escape\n * @return {string} - the escaped string\n */\nexport const escapeHtml = (stringToEscape: number | string | null | undefined): string => {\n const str = `${stringToEscape}`;\n const match = matchHtmlRegExp.exec(str);\n\n if (!match) {\n return str;\n }\n\n let escape: string;\n let html = '';\n let index: number;\n let lastIndex = 0;\n\n for (index = match.index; index < str.length; index++) {\n const charCode = str.codePointAt(index);\n if (charCode === doubleQuoteChar) {\n escape = '"';\n } else if (charCode === ampersandChar) {\n escape = '&';\n } else if (charCode === singleQuoteChar) {\n escape = ''';\n } else if (charCode === lessThanChar) {\n escape = '<';\n } else if (charCode === greaterThanChar) {\n escape = '>';\n } else {\n escape = '';\n }\n\n if (escape !== '') {\n if (lastIndex !== index) {\n html += str.slice(lastIndex, index);\n }\n\n lastIndex = index + 1;\n html += escape;\n }\n }\n\n return lastIndex !== index ? html + str.slice(lastIndex, index) : html;\n};\n","import type { Node, Descendant } from 'slate';\nimport type { NodeObject } from './types';\nimport { isNotNil, isNil, isString, isArray } from '@wistia/type-guards';\nimport { Element, Text } from 'slate';\nimport { jsx } from 'slate-hyperscript';\nimport { escapeHtml } from '../../helpers/escapeHtml';\n\n// All Element nodes must contain at least one Text descendant.\n// If an element node does not contain any children,\n// an empty text node will be added as its only child.\n// Read more at https://docs.slatejs.org/concepts/10-normalizing\nconst emptyTextNode = { text: '' };\n\n// Image nodes need blank text by SlateJS design, so we make some exceptions for them\nconst rteIsNonImageNodeType = (node: Descendant): boolean => node.type !== 'image';\n\nconst rteIsInvalidImage = (node: Descendant): boolean =>\n node.type === 'image' && node.url === undefined;\n\nconst rteHasOnlyOneChild = (node: Descendant): boolean =>\n isNotNil(node.children) && node.children.length === 1;\nconst rteIsEmptyTextNode = (node: Descendant): boolean =>\n Text.isText(node) && node.text?.trim() === '';\nconst rteIsOnlyChildWithEmptyText = (node: Descendant): boolean =>\n // We know that node.children[0] exists bcause of rteHasOnlyOneChild\n // oxlint-disable-next-line @typescript-eslint/no-non-null-assertion\n rteHasOnlyOneChild(node) && rteIsEmptyTextNode(node.children![0]!);\n\nconst isValueNull = (value: (string | null)[]): boolean => value.every((val) => isNil(val));\nconst sanitizedValue = (value: (string | null)[]): string | null =>\n isValueNull(value) ? null : value.join('');\n\n// Handles cases in foreign HTML (i.e., in case of import or paste)\n// when links may be wrapped by attr tags like <strong></strong>,\n// which breaks the rules of SlateJS.\n// The code here correctly adds those attrs to the children of the element.\n// Inspired by https://github.com/udecode/slate-plugins/pull/83/files.\nconst addAttrsToChildren = (child: Descendant, attrs: Record<string, unknown>) => {\n const childCopy = child;\n if (childCopy.children) {\n childCopy.children = childCopy.children.map((item) => {\n const itemWithAttrs = addAttrsToChildren(item, attrs);\n return { ...itemWithAttrs, ...attrs };\n });\n }\n return childCopy;\n};\n\n// serialize to HTML\nconst serializeText = (textNode: Text) => {\n const text = escapeHtml(textNode.text);\n const newStringArr = [text];\n if (isNotNil(textNode.bold) && textNode.bold) {\n newStringArr.push('</strong>');\n newStringArr.unshift('<strong>');\n }\n if (isNotNil(textNode.italic) && textNode.italic) {\n newStringArr.push('</em>');\n newStringArr.unshift('<em>');\n }\n if (isNotNil(textNode.underline) && textNode.underline) {\n newStringArr.push('</u>');\n newStringArr.unshift('<u>');\n }\n if (isNotNil(textNode.strikethrough) && textNode.strikethrough) {\n newStringArr.push('</s>');\n newStringArr.unshift('<s>');\n }\n if (isNotNil(textNode.code) && textNode.code) {\n newStringArr.push('</code>');\n newStringArr.unshift('<code>');\n }\n return newStringArr.join('');\n};\n\nconst serializeNode = (node: Descendant): string | null => {\n // if the only thing in the editor is\n // a non-image RTE node with empty text (since image nodes need empty text by SlateJS design)\n // OR if the node is an image but invalid, with an undefined src\n // do not serialize the HTML for it.\n if (\n (rteIsNonImageNodeType(node) && rteIsOnlyChildWithEmptyText(node)) ||\n rteIsInvalidImage(node)\n ) {\n return null;\n }\n\n if (Text.isText(node)) {\n return serializeText(node);\n }\n\n const children = isNotNil(node.children)\n ? node.children.map((node_) => serializeNode(node_)).join('')\n : '';\n\n switch (node.type) {\n case 'span':\n return `<span>${children}</span>`;\n case 'blockquote':\n return `<blockquote>${children}</blockquote>`;\n case 'paragraph':\n return `<p>${children}</p>`;\n case 'heading-one':\n return `<h1>${children}</h1>`;\n case 'heading-two':\n return `<h2>${children}</h2>`;\n // We preserve the original headers \"under the hood\" in the HTML\n // Even though we render h4-h6 as h3s in the editor UI per Design request.\n case 'heading-three':\n return `<h3>${children}</h3>`;\n case 'heading-four':\n return `<h4>${children}</h4>`;\n case 'heading-five':\n return `<h5>${children}</h5>`;\n case 'heading-six':\n return `<h6>${children}</h6>`;\n case 'link':\n return `<a rel=\"noopener noreferrer\" target=\"_blank\" href=\"${escapeHtml(\n node.url,\n )}\">${children}</a>`;\n case 'numbered-list':\n return `<ol>${children}</ol>`;\n case 'bulleted-list':\n return `<ul>${children}</ul>`;\n case 'list-item':\n return `<li>${children}</li>`;\n case 'image':\n return `<img src=\"${escapeHtml(node.url)}\" />`;\n case 'code':\n return `<code>${children}</code>`;\n case undefined:\n default:\n return children;\n }\n};\n\nexport const rteSerializeToHTML = (value: NodeObject[]): string | null => {\n const mappedValue = value.map((node) => serializeNode(node));\n return sanitizedValue(mappedValue);\n};\n\n// deserialize from HTML\nconst ELEMENT_TAGS = {\n SPAN: () => ({ type: 'span' }),\n A: (el: HTMLElement) => ({ type: 'link', url: el.getAttribute('href') }), // oxlint-disable-line id-length\n BLOCKQUOTE: () => ({ type: 'blockquote' }),\n H1: () => ({ type: 'heading-one' }),\n H2: () => ({ type: 'heading-two' }),\n H3: () => ({ type: 'heading-three' }),\n H4: () => ({ type: 'heading-four' }),\n H5: () => ({ type: 'heading-five' }),\n H6: () => ({ type: 'heading-six' }),\n LI: () => ({ type: 'list-item' }),\n OL: () => ({ type: 'numbered-list' }),\n P: () => ({ type: 'paragraph' }), // oxlint-disable-line id-length\n UL: () => ({ type: 'bulleted-list' }),\n IMG: (el: HTMLElement) => ({ type: 'image', url: el.getAttribute('src') }),\n CODE: () => ({ type: 'code' }),\n};\n\n// `B` is omitted here since the HTML 5 specification discourages the use of that tag.\nconst TEXT_TAGS = {\n DEL: () => ({ strikethrough: true }),\n S: () => ({ strikethrough: true }), // oxlint-disable-line id-length\n EM: () => ({ italic: true }),\n I: () => ({ italic: true }), // oxlint-disable-line id-length\n STRONG: () => ({ bold: true }),\n U: () => ({ underline: true }), // oxlint-disable-line id-length\n CODE: () => ({ code: true }),\n};\n\nconst isTextNode = (el: ChildNode | HTMLElement): boolean => el.nodeType === 3;\nconst isElement = (el: ChildNode | HTMLElement) => el.nodeType === 1;\n// Links and inline code sit in a line of text. The other element tags make blocks.\nconst isBlockElement = (el: ChildNode) =>\n isElement(el) && el.nodeName in ELEMENT_TAGS && el.nodeName !== 'A' && el.nodeName !== 'CODE';\nconst isTextFormatElement = (el: ChildNode | ParentNode) =>\n el.nodeName in TEXT_TAGS || el.nodeName === 'A';\n\n// Each parent is checked once, so a long list or paragraph loads in linear time.\n// The parsed HTML does not change while it loads, so a saved answer stays correct.\nconst parentHasBlock = new WeakMap<ParentNode, boolean>();\nconst hasBlockChild = (parent: ParentNode): boolean => {\n const saved = parentHasBlock.get(parent);\n if (isNotNil(saved)) {\n return saved;\n }\n const hasBlock = [...parent.childNodes].some((node) => isBlockElement(node));\n parentHasBlock.set(parent, hasBlock);\n return hasBlock;\n};\n\n// A space-only text node is the space between two words, for example in\n// `<strong>bold</strong> <em>italic</em>`. It means nothing next to a block, for example the line\n// breaks between list items, or as the only content of a block.\nconst isWordSpace = (el: ChildNode): boolean => {\n const parent = el.parentNode;\n if (isNil(parent)) {\n return false;\n }\n if (parent.childNodes.length === 1) {\n return isTextFormatElement(parent);\n }\n return !hasBlockChild(parent);\n};\nconst isCodeBlock = (element: ChildNode | HTMLElement) => element.nodeName === 'CODE';\n// This function catches Code blocks that are \"inline\" as opposed to block.\n// Code blocks are formatted from the markdown with new lines before and after the children, i.e.,\n// <code>\n// I am block content\n// </code>\n// versus <code>I am inline</code\n// which should be treated as text rather than a block.\nconst isInlineCodeBlock = (\n element: ChildNode | HTMLElement,\n elementChildren: (Node | string | null)[],\n): boolean =>\n // @ts-expect-error I don't want to narrow the type too far and miss something that should be matched here.\n isCodeBlock(element) && isNotNil(elementChildren[0]) && !/\\n/.test(elementChildren[0]);\n\nconst shouldCreateBlock = (\n el: ChildNode | HTMLElement,\n children: (Descendant | Node | string | null)[],\n): boolean =>\n !isInlineCodeBlock(el, children) &&\n isNotNil(ELEMENT_TAGS[el.nodeName as keyof typeof ELEMENT_TAGS]);\nconst shouldCreateText = (\n el: ChildNode | HTMLElement,\n children: (Node | string | null)[],\n): boolean =>\n isInlineCodeBlock(el, children) || isNotNil(TEXT_TAGS[el.nodeName as keyof typeof TEXT_TAGS]);\n\nconst htmlChildIsEmptyText = (child: Descendant | string | null | undefined) =>\n isNotNil(child) && !isString(child) && (child as Text).text?.trim() === '';\n\nconst createEditorBlockElements = (\n children: (Descendant | string | null)[],\n el: ChildNode | HTMLElement,\n): Descendant => {\n const { nodeName } = el;\n if (\n nodeName !== 'IMG' &&\n children.length === 1 &&\n !isString(children[0]) &&\n // @ts-expect-error - text is a property on NodeLeafObject.\n isNotNil(children[0].text) &&\n // Casting to Text as I don't want to further narrow the type in case I miss another type where it's valid. RM 2021-03-31\n (children[0] as Text).text?.trim() === ''\n ) {\n return jsx('element', ELEMENT_TAGS.P(), emptyTextNode);\n }\n const attrs = ELEMENT_TAGS[nodeName as keyof typeof ELEMENT_TAGS](el as HTMLElement);\n return jsx('element', attrs, children);\n};\n\nconst createEditorTextElements = (children: (Descendant | string | null)[], el: HTMLElement) => {\n const { nodeName } = el;\n const attrs = TEXT_TAGS[nodeName as keyof typeof TEXT_TAGS]();\n return children.map((child) => {\n if (!isString(child) && isNotNil(child) && isNotNil(child.children)) {\n return addAttrsToChildren(child, attrs);\n }\n // if a child's text node has an empty string\n // return an empty text node in its place without any of the trimmings (italic, strong, etc.)\n if (htmlChildIsEmptyText(child)) {\n return jsx('text', {}, emptyTextNode);\n }\n return jsx('text', attrs, child);\n });\n};\n\nconst blockWithOnlyTextChildren = (el: HTMLElement) =>\n el.nodeName === 'BLOCKQUOTE' || el.nodeName === 'OL' || el.nodeName === 'UL';\n\nconst getNodeChildren = (\n el: ChildNode | HTMLElement,\n mapper: (\n el: ChildNode | HTMLElement,\n ) => (Descendant | string | null)[] | Descendant | string | null,\n): (Descendant | Node | string | null)[] => {\n let children = [];\n if (isCodeBlock(el)) {\n children = [...el.childNodes].map((node) => {\n // This helps us distinguish between code block content that should be treated as HTML vs. as text content\n if (isTextNode(node)) {\n return node.textContent;\n }\n // Only DOM elements have outerHTML; other nodes (e.g. comments) give undefined, as before.\n // `Element` in this file is Slate's, so use the DOM one from globalThis.\n return node instanceof globalThis.Element ? node.outerHTML : undefined;\n });\n } else if (blockWithOnlyTextChildren(el as HTMLElement)) {\n // Blockquotes, as rendered from our markdown, contain paragraphs, as well as blank text leaf nodes as their first and last children.\n // Ordered lists and unordered lists also contain blank text leaf nodes as their first and last children.\n // To avoid stripping those out via \"safeChildren\", and to allow for more sophisticated rendering of internal text nodes -- i.e. of bold/italic.etc. text within a blockquote's internal paragraph --\n // We remove the blank string content here.\n // Text nodes and formats go to `mapper`, which keeps the spaces between words, also `<em> </em>`.\n children = [...el.childNodes]\n .filter(\n (node) => isTextNode(node) || isTextFormatElement(node) || node.textContent?.trim() !== '',\n )\n .flatMap((node) => mapper(node));\n } else {\n children = [...el.childNodes].flatMap((node) => mapper(node));\n }\n\n // TODO revisit this casting by instead being more specific about return types above.\n return children as (Descendant | Node | string | null)[];\n};\n\nconst deserializeHTMLNode = (\n el: ChildNode | HTMLElement,\n): (Descendant | string | null)[] | Descendant | string | null => {\n if (isTextNode(el)) {\n if (el.nodeValue?.trim() === '' && !isWordSpace(el)) {\n return null;\n }\n return el.textContent;\n }\n if (el.nodeName === 'BR') {\n return '\\n';\n }\n if (!isElement(el)) {\n return null;\n }\n\n const children = getNodeChildren(el, deserializeHTMLNode);\n // Only keep valid Descendant objects (with 'text' or 'type' properties), strings, or null values\n const filteredChildren = children.filter(\n (child): child is Descendant | string | null =>\n child === null ||\n typeof child === 'string' ||\n (typeof child === 'object' && ('text' in child || 'type' in child)),\n );\n // This allows us to handle \"empty\" elements, i.e, for those that we've removed text content from.\n // SlateJS blows up if we don't provide at least an empty text node as a child.\n // A removed first child (a comment, or space next to a block) must not remove the others.\n const nonNullChildren = filteredChildren.filter((child) => isNotNil(child));\n const safeChildren = nonNullChildren.length > 0 ? nonNullChildren : [emptyTextNode];\n\n if (el.nodeName === 'BODY') {\n return jsx('fragment', {}, safeChildren);\n }\n\n if (shouldCreateBlock(el, children)) {\n return createEditorBlockElements(safeChildren, el);\n }\n\n if (shouldCreateText(el, safeChildren)) {\n return createEditorTextElements(safeChildren, el as HTMLElement);\n }\n\n return children;\n};\n\nconst isInlineNode = (node: Descendant) =>\n Text.isText(node) || (Element.isElement(node) && node.type === 'link');\n\n// Puts each run of text and links that is not in a block into a paragraph, with its formats.\nconst wrapLooseInlineNodes = (nodes: Descendant[]): Descendant[] => {\n const blocks: Descendant[] = [];\n let paragraph: Descendant[] | undefined;\n for (const node of nodes) {\n if (!isInlineNode(node)) {\n paragraph = undefined;\n blocks.push(node);\n } else if (isNil(paragraph)) {\n paragraph = [node];\n blocks.push({ type: 'paragraph', children: paragraph });\n } else {\n paragraph.push(node);\n }\n }\n return blocks;\n};\n\nexport const rteDeserializeHTML = (\n htmlString: string,\n): (NodeObject | string | null)[] | NodeObject | string | null | undefined => {\n if (!htmlString) {\n return undefined;\n }\n const parsedEl = new DOMParser().parseFromString(htmlString, 'text/html').body;\n const body = deserializeHTMLNode(parsedEl);\n // We need this in order to handle values from a plain text input\n // i.e., values entered into the Description field on the \"Set up your Channel\" form in the Create Channel flow.\n // If we don't do this, we'll get <body>some text</body>, which breaks the editor\n // Since there's no top-level block element wrapping the text.\n const fragment = isArray(body) ? wrapLooseInlineNodes(body as Descendant[]) : body;\n // If the last element added to the editor is NOT a paragraph,\n // Insert a paragraph as the last element\n // So the cursor is always escaped below the last element.\n const lastNodeOfFragment = isArray(fragment) ? fragment.at(-1) : undefined;\n if (\n isArray(fragment) &&\n Element.isElement(lastNodeOfFragment) &&\n lastNodeOfFragment.type !== 'paragraph'\n ) {\n return [...fragment, { type: 'paragraph', children: [{ text: '' }] }];\n }\n return fragment;\n};\n","import type { Editor } from 'slate';\nimport { isNonEmptyString } from '@wistia/type-guards';\nimport { useEffect, useId, useState } from 'react';\nimport { ReactEditor } from 'slate-react';\n\n/**\n * A `<label for>` only names and focuses native form controls, and the editor's text area is a\n * contenteditable `div`. This finds the label that points at `id` and focuses the editor when the\n * label is clicked. When `isName` is true, it also returns the label's id for `aria-labelledby`\n * (it gives the label an id when it has none).\n */\nexport const useLabelFor = (\n editor: Editor,\n id: string | undefined,\n isName: boolean,\n): string | undefined => {\n const generatedLabelId = useId();\n const [labelId, setLabelId] = useState<string>();\n\n useEffect(() => {\n if (!isNonEmptyString(id)) {\n return undefined;\n }\n const { ownerDocument } = ReactEditor.toDOMNode(editor, editor);\n const label = [...ownerDocument.querySelectorAll('label')].find(\n (element) => element.htmlFor === id,\n );\n if (!label) {\n return undefined;\n }\n const focusEditor = () => {\n ReactEditor.focus(editor);\n };\n label.addEventListener('click', focusEditor);\n const addsId = isName && !isNonEmptyString(label.id);\n if (addsId) {\n label.id = generatedLabelId;\n }\n if (isName) {\n setLabelId(label.id);\n }\n\n return () => {\n label.removeEventListener('click', focusEditor);\n if (addsId) {\n label.removeAttribute('id');\n }\n setLabelId(undefined);\n };\n }, [editor, generatedLabelId, id, isName]);\n\n return labelId;\n};\n","import type { Descendant, Editor } from 'slate';\nimport type { NodeElementObject } from '../types';\nimport { isNotNil, isNonEmptyString, isUndefined } from '@wistia/type-guards';\nimport { useCallback, useEffect, useRef } from 'react';\nimport isEqual from 'react-fast-compare';\nimport { Text } from 'slate';\nimport { rteSerializeToHTML } from '../serializers';\n\n// All Element nodes must contain at least one Text descendant.\n// If an element node does not contain any children,\n// an empty text node will be added as its only child.\n// Read more at https://docs.slatejs.org/concepts/10-normalizing\nexport const emptyValue: Descendant[] = [\n {\n type: 'paragraph',\n children: [{ text: '' }],\n },\n];\n\n// How long an emitted editor state stays recognizable as an echo. This needs\n// to outlast any save round trip; a matching value that arrives later than this\n// is treated as a genuine external update.\nconst ECHO_WINDOW_MS = 10_000;\n// Memory backstop for parents that never echo. Far above what a user can type\n// within ECHO_WINDOW_MS, so in practice only the time window evicts states.\nconst MAX_PENDING_ECHOES = 1000;\n\ntype PendingEchoes = Map<string | null, number>;\n\n// Drops states that are too old to be echoes. Map iteration follows insertion\n// order, and states are re-inserted when emitted, so the oldest come first.\nconst prunePendingEchoes = (pending: PendingEchoes, now: number) => {\n for (const [html, emittedAt] of pending) {\n if (now - emittedAt <= ECHO_WINDOW_MS && pending.size <= MAX_PENDING_ECHOES) {\n return;\n }\n pending.delete(html);\n }\n};\n\n// true when any line holds text or an image, also when the first line is empty, a list, or a link\nconst hasContent = (nodes: Descendant[] | undefined): boolean =>\n isNotNil(nodes) &&\n nodes.some((node) =>\n Text.isText(node)\n ? isNonEmptyString(node.text)\n : node.type === 'image' || hasContent(node.children),\n );\n\ntype UseExternalValueSyncArgs = {\n editor: Editor;\n // `undefined` when the editor is uncontrolled (it started from `defaultValue`)\n value: Descendant[] | undefined;\n useExternalValue: boolean;\n onChange?: ((value: NodeElementObject[]) => void) | undefined;\n};\n\n/**\n * Keeps a Slate editor in sync with a controlled `value` prop without clobbering\n * in-progress typing.\n *\n * Controlled parents echo every `onChange` back as `value`. When that echo is\n * delayed (async store, debounced save, slow render), the prop can arrive\n * holding an *older* editor state than the one the user is typing into. The\n * previous implementation treated any mismatch as an external update, reset\n * `editor.children` to the stale value and nulled the selection — dropping\n * characters and sending the caret to the start of the document.\n *\n * Here, every state emitted through `onChange` is remembered for\n * `ECHO_WINDOW_MS`. A `value` that matches one of those states is an echo\n * (current or stale, in any order, any number of times, and even after an\n * external update) and is ignored. Anything else is a genuine external update\n * and is applied, as before.\n *\n * Returns the `onChange` handler to pass to `<Slate>`.\n *\n * This is directly from the Slate.js docs on how to update slate outside of onChange:\n * If you want to update the editor's content in response to events from outside of Slate, you\n * need to change the children property directly. The simplest way is to replace the value of\n * editor.children editor.children = newValue and trigger a re-rendering (e.g. by calling\n * editor.onChange()).\n * More info here: https://docs.slatejs.org/walkthroughs/06-saving-to-a-database\n */\nexport const useExternalValueSync = ({\n editor,\n value,\n useExternalValue,\n onChange,\n}: UseExternalValueSyncArgs) => {\n // The serialized `value` prop we last reconciled. Slate already renders the\n // mount-time value via `initialValue`, so start from it: the mount effect (and\n // any re-render passing a new array with the same content) is then a no-op and\n // cannot wipe text typed before it ran.\n // `undefined` while uncontrolled; `null` is the HTML of an empty editor.\n const lastSeenValueHtml = useRef<string | null | undefined>(\n isUndefined(value) ? undefined : rteSerializeToHTML(value),\n );\n // The `useExternalValue` flag we last reconciled with. Turning it on must\n // re-evaluate a value that was skipped while it was off.\n const lastSeenUseExternalValue = useRef(useExternalValue);\n // Serialized editor states emitted through onChange within the echo window,\n // mapped to when they were last emitted, oldest first. Echoes do not consume\n // them: a state can be echoed more than once (it may have been emitted more\n // than once), and echoes can arrive in any order.\n const pendingEchoes = useRef<PendingEchoes>(new Map());\n\n const handleChange = useCallback(\n (nodes: Descendant[]) => {\n const html = rteSerializeToHTML(nodes);\n const pending = pendingEchoes.current;\n const now = Date.now();\n // Re-insert so the map stays ordered by emit time. Selection-only changes\n // re-emit identical content and only refresh the timestamp.\n pending.delete(html);\n pending.set(html, now);\n prunePendingEchoes(pending, now);\n if (isNotNil(onChange)) {\n onChange(nodes);\n }\n },\n [onChange],\n );\n\n useEffect(() => {\n // An uncontrolled editor keeps its own content. A `value` given later is then new.\n if (isUndefined(value)) {\n lastSeenValueHtml.current = undefined;\n lastSeenUseExternalValue.current = useExternalValue;\n return;\n }\n const valueHtml = rteSerializeToHTML(value);\n if (\n valueHtml === lastSeenValueHtml.current &&\n useExternalValue === lastSeenUseExternalValue.current\n ) {\n return;\n }\n lastSeenValueHtml.current = valueHtml;\n lastSeenUseExternalValue.current = useExternalValue;\n\n // The parent is echoing a state this editor emitted (possibly an older one\n // than the editor now holds, and not necessarily in emit order). The editor\n // is already at or past it.\n const pending = pendingEchoes.current;\n prunePendingEchoes(pending, Date.now());\n if (pending.has(valueHtml)) {\n return;\n }\n\n const isEmptyValue = isEqual(value, emptyValue);\n /** if we have an external value and the text editor is not empty (and therefore valid), we can safely update the editor. */\n if (!(isEmptyValue || (hasContent(value) && useExternalValue))) {\n return;\n }\n if (valueHtml === rteSerializeToHTML(editor.children)) {\n return;\n }\n\n // Emitted states stay recognizable: echoes still in flight from before this\n // update must not be applied over it.\n // oxlint-disable-next-line @eslint-react/immutability -- required by Slate to update content from outside onChange\n editor.children = value;\n editor.selection = null;\n editor.onChange();\n }, [value, editor, useExternalValue]);\n\n return handleChange;\n};\n","import type { AriaAttributes, CSSProperties, FocusEvent, FC } from 'react';\nimport type { Descendant, Editor, Node } from 'slate';\nimport type { RenderLeafProps, RenderElementProps } from 'slate-react';\nimport type { NodeElementObject, NodeObject } from './types';\nimport { isArray, isNil, isNotNil, isString, isUndefined } from '@wistia/type-guards';\nimport { isHotkey } from 'is-hotkey';\nimport { useCallback, useMemo, useState } from 'react';\nimport { createEditor, Transforms, Element, Text } from 'slate';\nimport { withHistory } from 'slate-history';\nimport { Editable, withReact, Slate, ReactEditor } from 'slate-react';\nimport { styled } from 'styled-components';\nimport { EditorButtons } from './EditorButtons';\nimport { Element as ElementToRender } from './Element';\nimport { Leaf } from './Leaf';\nimport { rteDeserializeHTML, rteSerializeToHTML } from './serializers';\nimport { useLabelFor } from './useLabelFor';\nimport {\n rteFormatTypes,\n handleListEscape,\n withLinks,\n withImages,\n toggleMark,\n toggleBlock,\n} from './utilities';\nimport { emptyValue, useExternalValueSync } from './utilities/useExternalValueSync';\n\nconst EditableWrapper = styled(Editable)`\n color: var(--rte-text-color, #37373c);\n outline: none; /* the outer box shows the focus instead */\n`;\n\ntype EditorWrapperProps = {\n $disabled: boolean;\n $height: string | undefined;\n};\n\nconst defaultHeight = '300px';\nconst EditorWrapper = styled.div<EditorWrapperProps>`\n background: var(--rte-background, #ffffff);\n border: 1px solid var(--rte-border-color, #c4c4c8);\n border-radius: var(--rte-border-radius, 4px);\n cursor: ${({ $disabled }) => ($disabled ? 'not-allowed' : 'auto')};\n\n /* UIProvider defines its font as a token, not on body. With no token, the font is inherited\n (VHSProvider sets it on body). */\n font-family: var(--rte-font-family, var(--wui-typography-family-default));\n font-size: 14px;\n font-weight: 500;\n height: ${({ $height }) => $height ?? defaultHeight};\n overflow: auto;\n padding: 0 16px;\n\n &:has(${EditableWrapper}:focus) {\n outline: 2px solid var(--rte-focus-color, var(--rte-accent-color, #2949e5));\n outline-offset: -1px; /* on the border, where the sticky toolbar cannot cover it */\n }\n\n strong {\n font-weight: 700;\n }\n`;\n\nconst HOTKEYS = {\n 'mod+b': 'bold',\n 'mod+i': 'italic',\n 'mod+u': 'underline',\n};\n\nexport type RichTextEditorProps = AriaAttributes & {\n /**\n * Same as `aria-labelledby`. `aria-labelledby` wins when both are set.\n */\n ariaLabelledBy?: string | undefined;\n /**\n * Class name for the outer box (border, toolbar, and text area)\n */\n className?: string | undefined;\n /**\n * Test id for the outer box\n */\n 'data-testid'?: string;\n /**\n * Starting content when `value` is not set: an HTML string or editor nodes.\n * The editor does not read it again after the first render.\n */\n defaultValue?: NodeObject[] | string | undefined;\n /**\n * Determines whether editor is clickable/read-only\n */\n disabled?: boolean;\n /**\n * Formats to enable in editor, restricted to rteFormatTypes\n */\n enabledFormats?: (keyof typeof rteFormatTypes)[];\n /**\n * Custom height of editor\n */\n height?: string | undefined;\n /**\n * Id of the text area. A `<label for>` with this id names the text area and focuses it on click.\n */\n id?: string | undefined;\n /**\n * Adds a hidden input with this name. Its value is the content as HTML, so a native form\n * submission or `FormData` includes it.\n */\n name?: string | undefined;\n /**\n * Function to be called when editor loses focus\n */\n onBlur?: ((value: NodeElementObject[]) => void) | undefined;\n /**\n * Function to be called after editor state update\n */\n onChange?: ((value: NodeElementObject[]) => void) | undefined;\n /**\n * Placeholder text\n */\n placeholder?: string;\n /**\n * Inline styles for the outer box\n */\n style?: CSSProperties | undefined;\n /**\n * Whether to update the editor when the value prop changes\n */\n useExternalValue?: boolean;\n /**\n * Content of the editor. The editor reads it on the first render. After that, it reads it again\n * when it is the empty value (to clear the editor), or when `useExternalValue` is true.\n */\n value?: NodeObject[] | undefined;\n};\n\nconst toNodes = (content: NodeObject[] | string | undefined): Descendant[] | undefined => {\n if (!isString(content)) {\n return content;\n }\n const nodes = rteDeserializeHTML(content);\n // the editor only accepts a list of elements as its value\n return isArray(nodes) && nodes.length > 0 && nodes.every((node) => Element.isElement(node))\n ? nodes\n : undefined;\n};\n\nconst serialize = (nodes: Descendant[]): string => rteSerializeToHTML(nodes) ?? '';\n\nexport const RichTextEditor: FC<RichTextEditorProps> = ({\n 'aria-label': ariaLabel,\n 'aria-labelledby': ariaLabelledByAttribute,\n ariaLabelledBy,\n className,\n 'data-testid': dataTestId = 'rich-text-editor',\n defaultValue,\n disabled = false,\n enabledFormats = Object.values(rteFormatTypes),\n height,\n id,\n name,\n onBlur,\n onChange,\n placeholder = 'Enter some rich text...',\n style,\n useExternalValue = false,\n value,\n ...ariaProps\n}) => {\n const renderElement = useCallback(\n (props: RenderElementProps) => <ElementToRender {...props} />,\n [],\n );\n const renderLeaf = useCallback((props: RenderLeafProps) => <Leaf {...props} />, []);\n const editor: Editor = useMemo(() => {\n const baseEditor = withReact(createEditor());\n return withImages(withLinks(withHistory(baseEditor)));\n }, []);\n // Slate reads its initial value only once, so the first render decides it\n const [initialValue] = useState(() => value ?? toNodes(defaultValue) ?? emptyValue);\n // kept current without `name` too, so a `name` added later submits the content\n const [html, setHtml] = useState(() => serialize(initialValue));\n const labelledBy = ariaLabelledByAttribute ?? ariaLabelledBy;\n const labelId = useLabelFor(editor, id, isNil(ariaLabel) && isNil(labelledBy));\n // Without `defaultValue`, a missing `value` means \"empty\", as it did before `defaultValue` existed.\n const externalValue = value ?? (isUndefined(defaultValue) ? emptyValue : undefined);\n const handleSyncedChange = useExternalValueSync({\n editor,\n value: externalValue,\n useExternalValue,\n onChange,\n });\n\n const handleChange = (nodes: Descendant[]) => {\n setHtml(serialize(nodes));\n handleSyncedChange(nodes);\n };\n\n const handleEditorBlur = (_event: FocusEvent<HTMLDivElement>) => {\n const updatedValue = editor.children;\n\n if (isNotNil(onBlur)) {\n onBlur(updatedValue);\n }\n };\n\n // returns true when it removed an image\n const handleRemoveImageIfSelected = useCallback((): boolean => {\n const { selection } = editor;\n\n if (isNil(selection) || isNil(selection.anchor.path[0])) {\n return false;\n }\n\n const selectedElement = editor.children[selection.anchor.path[0]];\n if (!Element.isElement(selectedElement) || selectedElement.type !== 'image') {\n return false;\n }\n\n toggleBlock(editor, 'image');\n Transforms.removeNodes(editor, { at: selection });\n Transforms.move(editor, { reverse: true });\n const spanElement = editor.children.find(\n (child: Node) => Element.isElement(child) && child.type === 'span',\n );\n if (\n Element.isElement(spanElement) &&\n spanElement.type === 'span' &&\n isNotNil(spanElement.children) &&\n isNotNil(spanElement.children[0]) &&\n isNotNil(spanElement.children[0].text) &&\n spanElement.children[0].text.trim() !== ''\n ) {\n Transforms.setNodes(\n editor,\n { type: 'paragraph' },\n {\n match: (node: Node) =>\n Element.isElement(node) &&\n node.type === 'span' &&\n isNotNil(node.children) &&\n Text.isText(node.children[0]) &&\n isNotNil(node.children[0].text) &&\n node.children[0].text.trim() !== '',\n split: true,\n mode: 'highest',\n },\n );\n }\n return true;\n }, [editor]);\n\n return (\n // oxlint-disable-next-line styled-components-a11y/click-events-have-key-events, styled-components-a11y/no-static-element-interactions\n <EditorWrapper\n $disabled={disabled}\n $height={height}\n className={className}\n data-testid={dataTestId}\n onClick={() => {\n ReactEditor.focus(editor);\n }}\n style={style}\n >\n <Slate\n editor={editor}\n initialValue={initialValue}\n onChange={handleChange}\n >\n <EditorButtons\n disabled={disabled}\n enabledFormats={enabledFormats}\n />\n <EditableWrapper\n {...ariaProps}\n aria-disabled={disabled || ariaProps['aria-disabled']}\n aria-label={ariaLabel}\n aria-labelledby={labelledBy ?? labelId}\n // Slate drops the role while read-only; keep it so a disabled editor still has a name\n aria-multiline={true}\n autoFocus={false}\n data-testid=\"editor-content\"\n id={id}\n onBlur={handleEditorBlur}\n onKeyDown={(event) => {\n Object.keys(HOTKEYS).forEach((hotKey: string) => {\n if (isHotkey(hotKey, event)) {\n event.preventDefault();\n toggleMark(editor, HOTKEYS[hotKey as keyof typeof HOTKEYS]);\n }\n });\n if (event.key === 'Enter' && !event.shiftKey) {\n handleListEscape(editor);\n }\n if (event.key === 'Backspace' || event.key === 'Clear' || event.key === 'Delete') {\n // the image is gone; the browser's own delete would also take the text before it\n if (handleRemoveImageIfSelected()) {\n event.preventDefault();\n }\n }\n }}\n placeholder={placeholder}\n readOnly={disabled}\n renderElement={renderElement}\n renderLeaf={renderLeaf}\n role=\"textbox\"\n spellCheck={true}\n />\n </Slate>\n {isNotNil(name) && (\n <input\n disabled={disabled}\n name={name}\n type=\"hidden\"\n value={html}\n />\n )}\n </EditorWrapper>\n );\n};\n\nRichTextEditor.displayName = 'RichTextEditor';\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","names":["Image","iconsManifest","emptyTextNode","SlateEditor","Element","jsx","ElementToRender"],"sources":["../src/components/Icon/iconMap.ts","../src/components/Icon/icons/BlockQuote.tsx","../src/components/Icon/icons/Bold.tsx","../src/components/Icon/icons/BulletedList.tsx","../src/components/Icon/icons/Heading.tsx","../src/components/Icon/icons/HeadingTwo.tsx","../src/components/Icon/icons/Image.tsx","../src/components/Icon/icons/Italic.tsx","../src/components/Icon/icons/Link.tsx","../src/components/Icon/icons/NumberedList.tsx","../src/components/Icon/icons/Strikethrough.tsx","../src/components/Icon/icons/Underline.tsx","../src/components/Icon/icons/index.ts","../src/components/Icon/Icon.tsx","../src/components/RichTextEditor/ToolbarButton.tsx","../src/helpers/isUrl/isUrl.ts","../src/components/RichTextEditor/utilities/withImagesPlugin.ts","../src/components/RichTextEditor/utilities/withLinksPlugin.ts","../src/components/RichTextEditor/utilities/handleListEscape.ts","../src/components/RichTextEditor/utilities/rteFormatTypes.ts","../src/components/RichTextEditor/utilities/toggle.ts","../src/components/RichTextEditor/EditorButtons.tsx","../src/components/RichTextEditor/Element.tsx","../src/components/RichTextEditor/Leaf.tsx","../src/helpers/escapeHtml/escapeHtml.ts","../src/components/RichTextEditor/serializers.ts","../src/components/RichTextEditor/useLabelFor.ts","../src/components/RichTextEditor/utilities/useExternalValueSync.ts","../src/components/RichTextEditor/RichTextEditor.tsx"],"sourcesContent":["export const iconMap = {\n 'block-quote': 'BlockQuote',\n bold: 'Bold',\n 'bulleted-list': 'BulletedList',\n heading: 'Heading',\n 'heading-two': 'HeadingTwo',\n image: 'Image',\n italic: 'Italic',\n link: 'Link',\n 'numbered-list': 'NumberedList',\n strikethrough: 'Strikethrough',\n underline: 'Underline',\n};\n","import type { JSX, SVGProps } from 'react';\n\nexport const BlockQuote = (props: SVGProps<SVGSVGElement>): JSX.Element => (\n <svg {...props}>\n <path\n d=\"M4.2125 11.0375C4.35417 11.1792 4.53333 11.25 4.75 11.25H19.25C19.4667 11.25 19.6458 11.1792 19.7875 11.0375C19.9292 10.8958 20 10.7167 20 10.5C20 10.2833 19.9292 10.1042 19.7875 9.9625C19.6458 9.82083 19.4667 9.75 19.25 9.75H4.75C4.53333 9.75 4.35417 9.82083 4.2125 9.9625C4.07083 10.1042 4 10.2833 4 10.5C4 10.7167 4.07083 10.8958 4.2125 11.0375ZM4.2125 14.0375C4.35417 14.1792 4.53333 14.25 4.75 14.25H12.975C13.1917 14.25 13.3708 14.1792 13.5125 14.0375C13.6542 13.8958 13.725 13.7167 13.725 13.5C13.725 13.2833 13.6542 13.1042 13.5125 12.9625C13.3708 12.8208 13.1917 12.75 12.975 12.75H4.75C4.53333 12.75 4.35417 12.8208 4.2125 12.9625C4.07083 13.1042 4 13.2833 4 13.5C4 13.7167 4.07083 13.8958 4.2125 14.0375ZM1.5 10C1.22386 10 1 10.2239 1 10.5V14C1 14.2761 1.22386 14.5 1.5 14.5C1.77614 14.5 2 14.2761 2 14V10.5C2 10.2239 1.77614 10 1.5 10Z\"\n fill=\"currentColor\"\n />\n </svg>\n);\n","import type { JSX, SVGProps } from 'react';\n\nexport const Bold = (props: SVGProps<SVGSVGElement>): JSX.Element => (\n <svg {...props}>\n <path\n d=\"M16.9995 11.7C18.354 10.743 19.302 9.17101 19.302 7.71451C19.302 4.48501 16.86 1.99951 13.722 1.99951H4.998V22.0005H14.823C17.7375 22.0005 19.998 19.5705 19.998 16.5855C19.998 14.415 18.798 12.5565 16.998 11.7H16.9995ZM9.186 5.57101H13.371C14.5305 5.57101 15.465 6.52801 15.465 7.71451C15.465 8.89951 14.5305 9.85651 13.3725 9.85651H9.186V5.57101ZM14.07 18.429H9.186V14.1435H14.07C15.228 14.1435 16.1625 15.1005 16.1625 16.2855C16.1625 17.4705 15.228 18.429 14.07 18.429V18.429Z\"\n fill=\"currentColor\"\n />\n </svg>\n);\n","import type { JSX, SVGProps } from 'react';\n\nexport const BulletedList = (props: SVGProps<SVGSVGElement>): JSX.Element => (\n <svg {...props}>\n <path\n d=\"M4.0005 10.5C3.1695 10.5 2.5005 11.1705 2.5005 12C2.5005 12.8295 3.1695 13.5 4.0005 13.5C4.83 13.5 5.5005 12.8295 5.5005 12C5.5005 11.1705 4.83 10.5 4.0005 10.5ZM4.0005 4.5C3.1695 4.5 2.5005 5.1705 2.5005 6C2.5005 6.8295 3.1695 7.5 4.0005 7.5C4.83 7.5 5.5005 6.8295 5.5005 6C5.5005 5.1705 4.83 4.5 4.0005 4.5ZM4.0005 16.5C3.1695 16.5 2.5005 17.1795 2.5005 18C2.5005 18.8205 3.18 19.5 4.0005 19.5C4.8195 19.5 5.5005 18.8205 5.5005 18C5.5005 17.1795 4.83 16.5 4.0005 16.5ZM7.0005 19.0005H21V16.9995H7.0005V19.0005ZM7.0005 13.0005H21V10.9995H7.0005V13.0005ZM7.0005 4.9995V7.0005H21V4.9995H7.0005Z\"\n fill=\"currentColor\"\n />\n </svg>\n);\n","import type { JSX, SVGProps } from 'react';\n\nexport const Heading = (props: SVGProps<SVGSVGElement>): JSX.Element => (\n <svg {...props}>\n <path\n d=\"M7.9995 3V6.7995H14.154V22.0005H17.8455V6.7995H24V3H7.9995ZM0 12.9H3.666V22.0005H7.335V12.9H11.001V9H0V12.9Z\"\n fill=\"currentColor\"\n />\n </svg>\n);\n","import type { JSX, SVGProps } from 'react';\n\nexport const HeadingTwo = (props: SVGProps<SVGSVGElement>): JSX.Element => (\n <svg {...props}>\n <path\n d=\"M3 17V7H4.5V11.25H9V7H10.5V17H9V12.75H4.5V17H3ZM13.5 17V12.75C13.5 12.3333 13.6458 11.9792 13.9375 11.6875C14.2292 11.3958 14.5833 11.25 15 11.25H19.5V8.5H13.5V7H19.5C19.9167 7 20.2708 7.14583 20.5625 7.4375C20.8542 7.72917 21 8.08333 21 8.5V11.25C21 11.6667 20.8542 12.0208 20.5625 12.3125C20.2708 12.6042 19.9167 12.75 19.5 12.75H15V15.5H21V17H13.5Z\"\n fill=\"currentColor\"\n />\n </svg>\n);\n","import type { JSX, SVGProps } from 'react';\n\nexport const Image = (props: SVGProps<SVGSVGElement>): JSX.Element => (\n <svg {...props}>\n <path\n d=\"M21 19.0005V4.9995C21 3.9 20.1 3 19.0005 3H4.9995C3.9 3 3 3.9 3 4.9995V19.0005C3 20.1 3.9 21 4.9995 21H19.0005C20.1 21 21 20.1 21 19.0005ZM8.5005 13.5L10.9995 16.5105L14.5005 12L19.0005 18H4.9995L8.5005 13.5Z\"\n fill=\"currentColor\"\n />\n </svg>\n);\n","import type { JSX, SVGProps } from 'react';\n\nexport const Italic = (props: SVGProps<SVGSVGElement>): JSX.Element => (\n <svg {...props}>\n <path\n d=\"M8.8335 1.99951V6.28501H12.0555L7.0695 17.715H3V22.0005H14.667V17.715H11.4435L16.431 6.28501H20.5005V1.99951H8.8335Z\"\n fill=\"currentColor\"\n />\n </svg>\n);\n","import type { JSX, SVGProps } from 'react';\n\nexport const Link = (props: SVGProps<SVGSVGElement>): JSX.Element => (\n <svg {...props}>\n <path\n d=\"M2.28 12C2.28 9.948 3.948 8.28 6 8.28H10.8V6H6C2.688 6 0 8.688 0 12C0 15.312 2.688 18 6 18H10.8V15.72H6C3.948 15.72 2.28 14.052 2.28 12ZM7.2 13.2H16.8V10.8H7.2V13.2ZM18 6H13.2V8.28H18C20.052 8.28 21.72 9.948 21.72 12C21.72 14.052 20.052 15.72 18 15.72H13.2V18H18C21.312 18 24 15.312 24 12C24 8.688 21.312 6 18 6Z\"\n fill=\"currentColor\"\n />\n </svg>\n);\n","import type { JSX, SVGProps } from 'react';\n\nexport const NumberedList = (props: SVGProps<SVGSVGElement>): JSX.Element => (\n <svg {...props}>\n <path\n d=\"M3.425 20C3.30833 20 3.20833 19.9583 3.125 19.875C3.04167 19.7917 3 19.6917 3 19.575C3 19.4583 3.04167 19.3583 3.125 19.275C3.20833 19.1917 3.30833 19.15 3.425 19.15H5.1V18.5H4.475C4.35833 18.5 4.25833 18.4583 4.175 18.375C4.09167 18.2917 4.05 18.1917 4.05 18.075C4.05 17.9583 4.09167 17.8583 4.175 17.775C4.25833 17.6917 4.35833 17.65 4.475 17.65H5.1V17H3.425C3.30833 17 3.20833 16.9583 3.125 16.875C3.04167 16.7917 3 16.6917 3 16.575C3 16.4583 3.04167 16.3583 3.125 16.275C3.20833 16.1917 3.30833 16.15 3.425 16.15H5.525C5.64167 16.15 5.74167 16.1917 5.825 16.275C5.90833 16.3583 5.95 16.4583 5.95 16.575V19.575C5.95 19.6917 5.90833 19.7917 5.825 19.875C5.74167 19.9583 5.64167 20 5.525 20H3.425ZM4.475 7.9C4.35833 7.9 4.25833 7.85833 4.175 7.775C4.09167 7.69167 4.05 7.59167 4.05 7.475V4.85H3.425C3.30833 4.85 3.20833 4.80833 3.125 4.725C3.04167 4.64167 3 4.54167 3 4.425C3 4.30833 3.04167 4.20833 3.125 4.125C3.20833 4.04167 3.30833 4 3.425 4H4.475C4.59167 4 4.69167 4.04167 4.775 4.125C4.85833 4.20833 4.9 4.30833 4.9 4.425V7.475C4.9 7.59167 4.85833 7.69167 4.775 7.775C4.69167 7.85833 4.59167 7.9 4.475 7.9V7.9ZM3.425 13.925C3.30833 13.925 3.20833 13.8833 3.125 13.8C3.04167 13.7167 3 13.6167 3 13.5V13.275C3 13.2583 3.03333 13.1667 3.1 13L4.875 10.925H3.425C3.30833 10.925 3.20833 10.8833 3.125 10.8C3.04167 10.7167 3 10.6167 3 10.5C3 10.3833 3.04167 10.2833 3.125 10.2C3.20833 10.1167 3.30833 10.075 3.425 10.075H5.525C5.64167 10.075 5.74167 10.1167 5.825 10.2C5.90833 10.2833 5.95 10.3833 5.95 10.5V10.725C5.95 10.7417 5.91667 10.8333 5.85 11L4.05 13.075H5.525C5.64167 13.075 5.74167 13.1167 5.825 13.2C5.90833 13.2833 5.95 13.3833 5.95 13.5C5.95 13.6167 5.90833 13.7167 5.825 13.8C5.74167 13.8833 5.64167 13.925 5.525 13.925H3.425ZM8.975 18.775C8.75833 18.775 8.57917 18.7042 8.4375 18.5625C8.29583 18.4208 8.225 18.2417 8.225 18.025C8.225 17.8083 8.29583 17.6292 8.4375 17.4875C8.57917 17.3458 8.75833 17.275 8.975 17.275H20.25C20.4667 17.275 20.6458 17.3458 20.7875 17.4875C20.9292 17.6292 21 17.8083 21 18.025C21 18.2417 20.9292 18.4208 20.7875 18.5625C20.6458 18.7042 20.4667 18.775 20.25 18.775H8.975ZM8.975 12.7C8.75833 12.7 8.57917 12.6292 8.4375 12.4875C8.29583 12.3458 8.225 12.1667 8.225 11.95C8.225 11.7333 8.29583 11.5542 8.4375 11.4125C8.57917 11.2708 8.75833 11.2 8.975 11.2H20.25C20.4667 11.2 20.6458 11.2708 20.7875 11.4125C20.9292 11.5542 21 11.7333 21 11.95C21 12.1667 20.9292 12.3458 20.7875 12.4875C20.6458 12.6292 20.4667 12.7 20.25 12.7H8.975ZM8.975 6.625C8.75833 6.625 8.57917 6.55417 8.4375 6.4125C8.29583 6.27083 8.225 6.09167 8.225 5.875C8.225 5.65833 8.29583 5.47917 8.4375 5.3375C8.57917 5.19583 8.75833 5.125 8.975 5.125H20.25C20.4667 5.125 20.6458 5.19583 20.7875 5.3375C20.9292 5.47917 21 5.65833 21 5.875C21 6.09167 20.9292 6.27083 20.7875 6.4125C20.6458 6.55417 20.4667 6.625 20.25 6.625H8.975Z\"\n fill=\"currentColor\"\n />\n </svg>\n);\n","import type { JSX, SVGProps } from 'react';\n\nexport const Strikethrough = (props: SVGProps<SVGSVGElement>): JSX.Element => (\n <svg {...props}>\n <path\n d=\"M2 13.75V12.25H22V13.75H2ZM10.75 10.75V6.5H5V4H19V6.5H13.25V10.75H10.75ZM10.75 20V15.25H13.25V20H10.75Z\"\n fill=\"currentColor\"\n />\n </svg>\n);\n","import type { JSX, SVGProps } from 'react';\n\nexport const Underline = (props: SVGProps<SVGSVGElement>): JSX.Element => (\n <svg {...props}>\n <path\n d=\"M5 21V19.5H19V21H5ZM12 17C10.3167 17 8.89583 16.425 7.7375 15.275C6.57917 14.125 6 12.7167 6 11.05V3H8V11.1C8 12.2 8.38333 13.125 9.15 13.875C9.91667 14.625 10.8667 15 12 15C13.1333 15 14.0833 14.625 14.85 13.875C15.6167 13.125 16 12.2 16 11.1V3H18V11.05C18 12.7167 17.4208 14.125 16.2625 15.275C15.1042 16.425 13.6833 17 12 17Z\"\n fill=\"currentColor\"\n />\n </svg>\n);\n","export { BlockQuote } from './BlockQuote';\nexport { Bold } from './Bold';\nexport { BulletedList } from './BulletedList';\nexport { Heading } from './Heading';\nexport { HeadingTwo } from './HeadingTwo';\nexport { Image } from './Image';\nexport { Italic } from './Italic';\nexport { Link } from './Link';\nexport { NumberedList } from './NumberedList';\nexport { Strikethrough } from './Strikethrough';\nexport { Underline } from './Underline';\n","import type { FC } from 'react';\nimport { isNil } from '@wistia/type-guards';\nimport { iconMap } from './iconMap';\n// oxlint-disable-next-line barrel-files/avoid-namespace-import -- needed to enumerate icon exports\nimport * as iconsManifest from './icons';\n\n// size in pixels\nconst iconSizeMap = {\n sm: '12',\n md: '16',\n lg: '24',\n xl: '32',\n xxl: '48',\n};\n\nexport type IconProps = {\n /**\n * Color (as hex) of the Icon\n */\n color?: string;\n /**\n * The size of the icon to display\n */\n size?: keyof typeof iconSizeMap;\n /**\n * @ignore\n */\n style?: Record<string, unknown>;\n /**\n * Determines which icon to display\n */\n type: keyof typeof iconMap;\n};\n\nexport const Icon: FC<IconProps> = ({\n color = 'currentColor',\n size = 'lg',\n style,\n type,\n ...otherProps\n}) => {\n if (isNil(type)) {\n throw new Error('An Icon component requires a `type` prop to be provided');\n }\n\n if (isNil(iconMap[type])) {\n throw new Error(`Type \"${type}\" does not exist, please update type prop in Icon component.`);\n }\n\n if (isNil(iconSizeMap[size])) {\n throw new Error(`Size \"${size}\" does not exist, please update size prop in Icon component.`);\n }\n\n // oxlint-disable-next-line import/namespace -- dynamic lookup by icon name; key is type-checked via keyof typeof iconsManifest\n const IconElement = iconsManifest[iconMap[type] as keyof typeof iconsManifest];\n\n // so we do not have to add this to each individual Icon but still allow overrides\n const defaultStyle = { verticalAlign: 'middle', ...style };\n\n return (\n <IconElement\n aria-hidden=\"true\"\n color={color}\n height={`${iconSizeMap[size]}px`}\n role=\"presentation\"\n style={defaultStyle}\n viewBox=\"0 0 24 24\"\n width={`${iconSizeMap[size]}px`}\n xmlns=\"http://www.w3.org/2000/svg\"\n {...otherProps}\n />\n );\n};\n\nIcon.displayName = 'Icon';\n","import type { ComponentPropsWithoutRef, JSX, ReactNode } from 'react';\nimport { styled } from 'styled-components';\n\n// Matches the vhs IconButton (size \"md\", dark style) the toolbar used before the package split.\n// Round by default because every VMA root renders vhs with `wistiaTheme`, whose buttons are round.\nconst StyledToolbarButton = styled.button<{ $isActive: boolean }>`\n --rte-toolbar-button-color: ${({ $isActive }) =>\n $isActive ? 'var(--rte-accent-color, #2949e5)' : 'var(--rte-icon-color, #62626c)'};\n\n align-items: center;\n appearance: none;\n background-color: transparent;\n background-image: none;\n border: none;\n border-radius: var(--rte-toolbar-button-radius, 1000px);\n box-shadow: none;\n color: var(--rte-toolbar-button-color);\n cursor: pointer;\n display: inline-flex;\n font: inherit;\n height: 24px;\n justify-content: center;\n line-height: 1;\n padding: 0;\n transition: all 110ms;\n vertical-align: middle;\n width: 24px;\n\n svg {\n height: 16px;\n width: 16px;\n }\n\n &::-moz-focus-inner {\n border: 0;\n padding: 0;\n }\n\n &:focus-visible {\n outline: thin dotted #999999;\n }\n\n &:hover,\n &:focus-visible {\n background-color: color-mix(in srgb, var(--rte-toolbar-button-color) 20%, transparent);\n }\n\n &:active {\n background-color: color-mix(in srgb, var(--rte-toolbar-button-color) 40%, transparent);\n }\n\n &:disabled {\n background-color: transparent;\n color: color-mix(in srgb, var(--rte-toolbar-button-color) 50%, transparent);\n cursor: not-allowed;\n }\n`;\n\nexport type ToolbarButtonProps = Omit<\n ComponentPropsWithoutRef<'button'>,\n 'aria-label' | 'children' | 'type'\n> & {\n /**\n * Icon shown inside the button\n */\n icon: ReactNode;\n /**\n * Shows the button in the accent color\n */\n isActive: boolean;\n /**\n * Accessible name of the button\n */\n label: string;\n};\n\nexport const ToolbarButton = ({\n icon,\n isActive,\n label,\n ...props\n}: ToolbarButtonProps): JSX.Element => (\n <StyledToolbarButton\n {...props}\n $isActive={isActive}\n aria-label={label}\n type=\"button\"\n >\n {icon}\n </StyledToolbarButton>\n);\n","import { isString } from '@wistia/type-guards';\n\n/**\n * Loosely validates a URL string\n *\n * @param {*} str - a string to validate - could be an unknown type\n * @return {boolean} - whether string appears to be a url\n */\nexport const isUrl = (str: unknown): boolean => {\n // A URL must match #1 and then at least one of #2/#3\n // Use two levels of REs to avoid ReDoS\n // https://levelup.gitconnected.com/the-regular-expression-denial-of-service-redos-cheat-sheet-a78d0ed7d865\n const protocolAndDomain = /^(?:\\w+:)?\\/\\/(\\S+)$/;\n const localhostDomain = /^localhost[:?\\d]*(?:[^:?\\d]\\S*)?$/;\n const nonLocalhostDomain = /^[^\\s.]+\\.\\S{2,}$/;\n\n if (!isString(str)) {\n return false;\n }\n\n const match = protocolAndDomain.exec(str);\n\n if (!match) {\n return false;\n }\n\n // part of the string that is not the protocol\n const remaining = match[1];\n\n if (remaining === undefined || !remaining) {\n return false;\n }\n\n return localhostDomain.test(remaining) || nonLocalhostDomain.test(remaining);\n};\n","import type { Node, Editor } from 'slate';\nimport { isNotUndefined, isNotNil } from '@wistia/type-guards';\nimport { Transforms, Element, Text } from 'slate';\nimport { isUrl } from '../../../helpers/isUrl';\n\n// All Element nodes must contain at least one Text descendant.\n// If an element node does not contain any children,\n// an empty text node will be added as its only child.\n// Read more at https://docs.slatejs.org/concepts/10-normalizing\nconst emptyTextNode = { text: '' };\n// a URL counts as an image when it contains one of these anywhere, so query strings like `?fm=jpg` work\nconst imageExtensions = ['jpg', 'jpeg', 'png', 'gif', 'webp', 'avif', 'svg', 'tiff', 'bmp', 'dcm'];\n\nconst isImageUrl = (url: string) => {\n if (!isUrl(url)) {\n return false;\n }\n const hasImageExtension = imageExtensions.find((event) => url.includes(event));\n return isNotUndefined(hasImageExtension) && Boolean(hasImageExtension);\n};\n\n// returns false, and changes nothing, when the URL is not an image\nexport const insertImage = (editor: Editor, url: string): boolean => {\n if (!isImageUrl(url)) {\n return false;\n }\n\n const image = { type: 'image', url, children: [emptyTextNode] };\n Transforms.insertNodes(editor, image);\n return true;\n};\n\nexport const withImages = (editor: Editor): Editor => {\n const { normalizeNode, isVoid } = editor;\n editor.isVoid = (element: Element) => (element.type === 'image' ? true : isVoid(element));\n\n editor.normalizeNode = ([node, path]: [Node, number[]]) => {\n if (Element.isElement(node) && node.type === 'image' && node.url !== undefined) {\n const paragraph = {\n type: 'paragraph',\n children: [emptyTextNode],\n };\n\n const pathIndex = isNotUndefined(path[0]) ? path[0] + 1 : 1;\n Transforms.insertNodes(editor, paragraph, { at: [pathIndex] });\n Transforms.move(editor);\n }\n if (\n Element.isElement(node) &&\n node.type === 'image' &&\n node.url === undefined &&\n isNotUndefined(node.children) &&\n isNotUndefined(node.children[0]) &&\n isNotUndefined(node.children[0].text) &&\n node.children[0].text.trim() !== ''\n ) {\n Transforms.setNodes(\n editor,\n { type: 'span' },\n {\n match: (matchNode: Node) =>\n Element.isElement(matchNode) &&\n matchNode.type === 'image' &&\n matchNode.url === undefined &&\n isNotUndefined(matchNode.children) &&\n Text.isText(matchNode.children[0]) &&\n isNotNil(matchNode.children[0].text) &&\n matchNode.children[0].text.trim() !== '',\n split: true,\n at: path,\n mode: 'highest',\n },\n );\n }\n normalizeNode([node, path]);\n };\n\n return editor;\n};\n","import type { CustomEditor } from '../types';\nimport { isNonEmptyString } from '@wistia/type-guards';\nimport { Transforms, Element, Node, Editor, Range, Path } from 'slate';\nimport { isUrl } from '../../../helpers/isUrl';\n\nconst isHashUrl = (urlString: string) => {\n const urlPattern = /^#.+$/i;\n return urlPattern.test(urlString);\n};\n\nconst isLinkActive = (editor: Editor) => {\n const [link] = Editor.nodes(editor, {\n match: (node: Node) => Element.isElement(node) && node.type === 'link',\n });\n return Boolean(link);\n};\n\nconst unwrapLink = (editor: Editor) => {\n Transforms.unwrapNodes(editor, {\n match: (node: Node) => Element.isElement(node) && node.type === 'link',\n });\n};\n\nconst wrapLink = (editor: Editor, url: string) => {\n if (isLinkActive(editor)) {\n unwrapLink(editor);\n }\n\n const { selection } = editor;\n const isCollapsed = selection && Range.isCollapsed(selection);\n const link = {\n type: 'link',\n url,\n children: isCollapsed === true ? [{ text: url }] : [],\n };\n\n if (isCollapsed === true) {\n Transforms.insertNodes(editor, link);\n } else {\n Transforms.wrapNodes(editor, link, { split: true });\n Transforms.collapse(editor, { edge: 'end' });\n }\n};\n\nexport const withLinks = (editor: CustomEditor): CustomEditor => {\n const { insertData, insertText, isInline, normalizeNode } = editor;\n\n editor.isInline = (element: Element) => (element.type === 'link' ? true : isInline(element));\n\n editor.insertText = (text: string) => {\n if (text && isUrl(text)) {\n wrapLink(editor, text);\n } else {\n insertText(text);\n }\n };\n\n editor.insertData = (data: DataTransfer) => {\n const text = data.getData('text/plain');\n\n if (text && isUrl(text)) {\n wrapLink(editor, text);\n } else {\n insertData(data);\n }\n };\n\n editor.normalizeNode = ([node, path]: [Node, Path]) => {\n if (Element.isElement(node) && node.type === 'link' && Node.string(node) === '') {\n Transforms.unwrapNodes(editor, { at: path });\n Transforms.select(editor, Path.next(path));\n }\n normalizeNode([node, path]);\n };\n\n return editor;\n};\n\nexport const insertLink = (editor: Editor): void => {\n if (isLinkActive(editor)) {\n unwrapLink(editor);\n } else {\n // oxlint-disable-next-line no-alert\n const url = prompt('Enter the URL of the link:');\n\n if (!isNonEmptyString(url)) {\n return;\n }\n\n const urlHasSpaces = url.includes(' ');\n if (urlHasSpaces) {\n // oxlint-disable-next-line no-alert\n alert('The URL provided had spaces. Try again without spaces.');\n return;\n }\n\n if (!isUrl(url) && !isHashUrl(url)) {\n // oxlint-disable-next-line no-alert\n alert(\n 'The URL provided looks invalid. Try again. Make sure to include the protocol (ex. https://) in the URL.',\n );\n return;\n }\n\n if (editor.selection) {\n wrapLink(editor, url);\n }\n }\n};\n","import type { EditorInterface, Descendant, Node } from 'slate';\nimport type { NodeLeafObject } from '../types';\nimport { Transforms, Range, Editor, Element } from 'slate';\n\n// Allowing non-null assertions in this file for sake of TS conversion.\n/* oxlint-disable @typescript-eslint/no-non-null-assertion */\nconst OverriddenEditor: EditorInterface & { isBlock: typeof Editor.isBlock } = {\n ...Editor,\n isBlock: Editor.isBlock,\n};\n\n// All Element nodes must contain at least one Text descendant.\n// If an element node does not contain any children,\n// an empty text node will be added as its only child.\n// Read more at https://docs.slatejs.org/concepts/10-normalizing\nconst newLine = {\n type: 'paragraph',\n children: [\n {\n text: '',\n marks: [],\n },\n ],\n};\n\nconst isLastChildBlankText = (listChildren: Descendant[] | NodeLeafObject[]): boolean => {\n if (listChildren.length === 1) {\n // @ts-expect-error - Text does exist on some sub-types of nodes.\n return (listChildren.at(-1)?.text as string | null)?.trim() === '';\n }\n // Links need to be handled differently because they're surrounded by empty text by SlateJS design here.\n const link = listChildren.find((el) => el.type === 'link');\n return link?.children![0]?.text?.trim() === '';\n};\n\nexport const handleListEscape = (editor: Editor): void => {\n const { selection } = editor;\n const textIsNotSelected = selection && Range.isCollapsed(selection);\n const selectedElement = editor.children[selection!.anchor.path[0]!]!;\n const isList =\n selectedElement.type === 'bulleted-list' || selectedElement.type === 'numbered-list';\n const blockAbove = OverriddenEditor.above(editor, {\n match: (node: Node) => Element.isElement(node) && OverriddenEditor.isBlock(editor, node),\n })!;\n if ((textIsNotSelected ?? false) && isList && isLastChildBlankText(blockAbove[0].children!)) {\n Transforms.removeNodes(editor, { hanging: true });\n Transforms.insertNodes(editor, newLine);\n Transforms.unwrapNodes(editor, {\n // @ts-expect-error - type does exist on some sub-types of nodes.\n match: ({ type }: { type?: string }) => type === 'bulleted-list' || type === 'numbered-list',\n all: true,\n split: true,\n });\n }\n};\n","export const rteFormatTypes: {\n readonly BOLD: 'BOLD';\n readonly ITALIC: 'ITALIC';\n readonly UNDERLINE: 'UNDERLINE';\n readonly STRIKETHROUGH: 'STRIKETHROUGH';\n readonly HEADING_1: 'HEADING_1';\n readonly HEADING_2: 'HEADING_2';\n readonly BLOCKQUOTE: 'BLOCKQUOTE';\n readonly NUMBERED_LIST: 'NUMBERED_LIST';\n readonly BULLETED_LIST: 'BULLETED_LIST';\n readonly LINK: 'LINK';\n readonly IMAGE: 'IMAGE';\n} = Object.freeze({\n BOLD: 'BOLD',\n ITALIC: 'ITALIC',\n UNDERLINE: 'UNDERLINE',\n STRIKETHROUGH: 'STRIKETHROUGH',\n HEADING_1: 'HEADING_1',\n HEADING_2: 'HEADING_2',\n BLOCKQUOTE: 'BLOCKQUOTE',\n NUMBERED_LIST: 'NUMBERED_LIST',\n BULLETED_LIST: 'BULLETED_LIST',\n LINK: 'LINK',\n IMAGE: 'IMAGE',\n});\n","import type { Node, Editor } from 'slate';\nimport { isNotNil, isNonEmptyString } from '@wistia/type-guards';\nimport { Element, Transforms, Editor as SlateEditor } from 'slate';\n\nexport const isBlockActive = (editor: Editor, format: string): boolean => {\n const [match] = SlateEditor.nodes(editor, {\n match: (node: Node) => Element.isElement(node) && node.type === format,\n });\n return Boolean(match);\n};\n\nconst LIST_TYPES = new Set(['numbered-list', 'bulleted-list']);\n\nexport const toggleBlock = (editor: Editor, format: string): void => {\n const isActive = isBlockActive(editor, format);\n\n const isList = LIST_TYPES.has(format);\n Transforms.unwrapNodes(editor, {\n match: (node: Node) =>\n Element.isElement(node) && isNotNil(node.type) && LIST_TYPES.has(node.type),\n split: true,\n });\n const formatting = isList ? 'list-item' : format;\n\n Transforms.setNodes(editor, {\n type: isActive ? 'paragraph' : formatting,\n });\n\n if (!isActive && isList) {\n const block = { type: format, children: [] };\n Transforms.wrapNodes(editor, block);\n }\n};\n\nexport const isMarkActive = (editor: Editor, format: string): boolean => {\n const valueMarks = SlateEditor.marks(editor);\n return isNonEmptyString(valueMarks && Object.keys(valueMarks).find((mark) => mark === format));\n};\n\nexport const toggleMark = (editor: Editor, format: string): void => {\n const isActive = isMarkActive(editor, format);\n\n if (isActive) {\n SlateEditor.removeMark(editor, format);\n } else {\n SlateEditor.addMark(editor, format, true);\n }\n};\n","import type { MouseEvent, JSX } from 'react';\nimport type { Editor } from 'slate';\nimport type { iconMap } from '../Icon/iconMap';\nimport { isNonEmptyString } from '@wistia/type-guards';\nimport { Node } from 'slate';\nimport { useSlate } from 'slate-react';\nimport { styled } from 'styled-components';\nimport { Icon } from '../Icon';\nimport { ToolbarButton } from './ToolbarButton';\nimport {\n rteFormatTypes,\n insertImage,\n insertLink,\n isBlockActive,\n toggleBlock,\n isMarkActive,\n toggleMark,\n} from './utilities';\n\nconst ButtonContainer = styled.div`\n background: var(--rte-background, #ffffff);\n border-bottom: 1px solid var(--rte-border-color, #c4c4c8);\n display: flex;\n gap: 8px;\n padding: 8px 0;\n position: sticky;\n top: 0;\n\n /* needs a stacking context to stay above RTE content */\n z-index: 1;\n`;\n\ntype EditorButtonProps = {\n /**\n * `block` and `mark` buttons toggle their format. An `insert` button only runs `onCustomClick`.\n */\n buttonType: 'block' | 'insert' | 'mark';\n disabled: boolean;\n format: string;\n icon: keyof typeof iconMap;\n /**\n * Accessible name of the button\n */\n label: string;\n /**\n * Runs after the click toggles the format. A button with this callback is an action, not a toggle,\n * so it does not get `aria-pressed`.\n */\n onCustomClick?: (event: MouseEvent) => unknown;\n};\n\nconst EditorButton = ({\n buttonType,\n disabled,\n format,\n icon,\n label,\n onCustomClick,\n}: EditorButtonProps) => {\n const editor = useSlate();\n const isActive =\n buttonType === 'mark' ? isMarkActive(editor, format) : isBlockActive(editor, format);\n const handleClick = (event: MouseEvent) => {\n event.preventDefault();\n if (buttonType === 'block') {\n toggleBlock(editor, format);\n } else if (buttonType === 'mark') {\n toggleMark(editor, format);\n }\n if (onCustomClick) {\n onCustomClick(event);\n }\n };\n\n return (\n <ToolbarButton\n aria-pressed={onCustomClick ? undefined : isActive}\n disabled={disabled}\n icon={<Icon type={icon} />}\n isActive={isActive}\n label={label}\n onClick={handleClick}\n />\n );\n};\n\ntype FormatButtonConfig = Pick<EditorButtonProps, 'buttonType' | 'format' | 'icon' | 'label'> & {\n enabledFormat: keyof typeof rteFormatTypes;\n};\n\n// in toolbar order; the link and image buttons always come last\nconst FORMAT_BUTTONS: FormatButtonConfig[] = [\n { enabledFormat: 'BOLD', buttonType: 'mark', format: 'bold', icon: 'bold', label: 'Bold' },\n {\n enabledFormat: 'ITALIC',\n buttonType: 'mark',\n format: 'italic',\n icon: 'italic',\n label: 'Italic',\n },\n {\n enabledFormat: 'HEADING_1',\n buttonType: 'block',\n format: 'heading-one',\n icon: 'heading',\n label: 'Heading 1',\n },\n {\n enabledFormat: 'HEADING_2',\n buttonType: 'block',\n format: 'heading-two',\n icon: 'heading-two',\n label: 'Heading 2',\n },\n {\n enabledFormat: 'BULLETED_LIST',\n buttonType: 'block',\n format: 'bulleted-list',\n icon: 'bulleted-list',\n label: 'Bulleted list',\n },\n {\n enabledFormat: 'NUMBERED_LIST',\n buttonType: 'block',\n format: 'numbered-list',\n icon: 'numbered-list',\n label: 'Numbered list',\n },\n {\n enabledFormat: 'BLOCKQUOTE',\n buttonType: 'block',\n format: 'blockquote',\n icon: 'block-quote',\n label: 'Block quote',\n },\n {\n enabledFormat: 'UNDERLINE',\n buttonType: 'mark',\n format: 'underline',\n icon: 'underline',\n label: 'Underline',\n },\n {\n enabledFormat: 'STRIKETHROUGH',\n buttonType: 'mark',\n format: 'strikethrough',\n icon: 'strikethrough',\n label: 'Strikethrough',\n },\n];\n\nconst getSelectedText = (editor: Editor): string => {\n if (!editor.selection) {\n return '';\n }\n const nodeFragment = Node.fragment(editor, editor.selection);\n if (!nodeFragment[0]) {\n return '';\n }\n return Node.string(nodeFragment[0]);\n};\n\nconst noTextSelected = (editor: Editor) => {\n const userSelection = getSelectedText(editor);\n return userSelection.trim() === '';\n};\n\nexport type EditorButtonsProps = {\n disabled: boolean;\n enabledFormats: (keyof typeof rteFormatTypes)[];\n};\n\nexport const EditorButtons = ({ enabledFormats, disabled }: EditorButtonsProps): JSX.Element => {\n const editor = useSlate();\n return (\n <ButtonContainer>\n {FORMAT_BUTTONS.filter(({ enabledFormat }) => enabledFormats.includes(enabledFormat)).map(\n ({ enabledFormat, ...buttonProps }) => (\n <EditorButton\n key={enabledFormat}\n {...buttonProps}\n disabled={disabled}\n />\n ),\n )}\n {enabledFormats.includes(rteFormatTypes.LINK) && (\n <EditorButton\n // a link is an element, not a text format, so the button shows active inside a link\n buttonType=\"insert\"\n disabled={disabled || noTextSelected(editor)}\n format=\"link\"\n icon=\"link\"\n label=\"Link\"\n onCustomClick={() => {\n insertLink(editor);\n }}\n />\n )}\n {enabledFormats.includes(rteFormatTypes.IMAGE) && (\n <EditorButton\n buttonType=\"insert\"\n disabled={disabled}\n format=\"image\"\n icon=\"image\"\n label=\"Image\"\n onCustomClick={() => {\n // oxlint-disable-next-line no-alert\n const promptUserForImageUrl = prompt('Enter the URL of the image:');\n if (!isNonEmptyString(promptUserForImageUrl)) {\n return;\n }\n if (!insertImage(editor, promptUserForImageUrl)) {\n // oxlint-disable-next-line no-alert\n alert(\n 'The URL provided is not an image. Try again. Make sure to include the protocol (ex. https://) and a file type such as .png or .jpg in the URL.',\n );\n }\n }}\n />\n )}\n </ButtonContainer>\n );\n};\n","import type { JSX } from 'react';\nimport type { RenderElementProps } from 'slate-react';\nimport { useSelected, useFocused } from 'slate-react';\nimport { styled, css } from 'styled-components';\n\nconst Wrapper = styled.span`\n display: inline-block;\n user-select: none;\n`;\n\ntype ImageProps = {\n $isHighlighted: boolean;\n};\nconst Image = styled.img<ImageProps>`\n box-shadow: ${({ $isHighlighted }) =>\n $isHighlighted ? '0 0 0 3px var(--rte-accent-color, #2949e5)' : 'none'};\n max-height: 10em;\n max-width: 100%;\n user-select: none;\n`;\n\nconst listStyle = css`\n padding: 0 24px;\n\n li {\n font-size: 14px;\n font-style: normal;\n font-weight: 400;\n margin: 8px 0;\n }\n`;\n\nconst EditorOrderedList = styled.ol`\n ${listStyle}\n`;\n\nconst EditorUnorderedList = styled.ul`\n ${listStyle}\n`;\n\nconst headerStyle = css`\n font-weight: 500;\n`;\n\nconst EditorHeading1 = styled.h1`\n ${headerStyle}\n font-size: 18px;\n`;\n\nconst EditorHeading2 = styled.h2`\n ${headerStyle}\n font-size: 16px;\n`;\n\nconst EditorHeading3 = styled.h3`\n ${headerStyle}\n font-size: 14px;\n`;\n\nconst EditorParagraph = styled.p`\n font-weight: 400;\n`;\n\nconst EditorLink = styled.a`\n color: var(--rte-accent-color, #2949e5);\n font-weight: 300;\n`;\n\nconst EditorSpan = styled.span`\n font-weight: 400;\n`;\n\nexport const Element = ({ attributes, children, element }: RenderElementProps): JSX.Element => {\n const selected = useSelected();\n const focused = useFocused();\n\n switch (element.type) {\n case 'span':\n return <EditorSpan {...attributes}>{children}</EditorSpan>;\n case 'blockquote':\n return <blockquote {...attributes}>{children}</blockquote>;\n case 'bulleted-list':\n return <EditorUnorderedList {...attributes}>{children}</EditorUnorderedList>;\n case 'heading-one':\n return <EditorHeading1 {...attributes}>{children}</EditorHeading1>;\n case 'heading-two':\n return <EditorHeading2 {...attributes}>{children}</EditorHeading2>;\n // We render h4-h6 as h3s in the editor UI per Design request\n // (Though we preserve the original headers \"under the hood\" in the HTML).\n case 'heading-three':\n case 'heading-four':\n case 'heading-five':\n case 'heading-six':\n return <EditorHeading3 {...attributes}>{children}</EditorHeading3>;\n case 'list-item':\n return <li {...attributes}>{children}</li>;\n case 'numbered-list':\n return <EditorOrderedList {...attributes}>{children}</EditorOrderedList>;\n case 'image':\n return (\n <Wrapper {...attributes}>\n <Wrapper contentEditable={false}>\n <Image\n alt=\"\"\n contentEditable={false}\n $isHighlighted={selected && focused}\n src={element.url}\n />\n </Wrapper>\n {children}\n </Wrapper>\n );\n case 'link':\n return (\n <EditorLink\n {...attributes}\n href={element.url}\n rel=\"noopener noreferrer\"\n target=\"_blank\"\n >\n {children}\n </EditorLink>\n );\n case 'code':\n return <code {...attributes}>{children}</code>;\n case undefined:\n default:\n return <EditorParagraph {...attributes}>{children}</EditorParagraph>;\n }\n};\n","import type { JSX } from 'react';\nimport type { RenderLeafProps } from 'slate-react';\nimport { isNotNil } from '@wistia/type-guards';\n\nexport const Leaf = ({ attributes, children, leaf }: RenderLeafProps): JSX.Element => {\n // Slate-React allows for children to be any type.\n // oxlint-disable-next-line @typescript-eslint/no-unsafe-assignment\n let kids = children;\n if (isNotNil(leaf.bold)) {\n kids = <strong>{kids}</strong>;\n }\n\n if (isNotNil(leaf.italic)) {\n kids = <em>{kids}</em>;\n }\n\n if (isNotNil(leaf.underline)) {\n kids = <u>{kids}</u>;\n }\n\n if (isNotNil(leaf.strikethrough)) {\n kids = <s>{kids}</s>;\n }\n\n if (isNotNil(leaf.code)) {\n kids = <code>{kids}</code>;\n }\n\n return <span {...attributes}>{kids}</span>;\n};\n","// note: adapted from https://github.com/component/escape-html/blob/master/index.js because that's what we\n// were already using, but we should consider using https://www.npmjs.com/package/@wordpress/escape-html in the future\nconst matchHtmlRegExp = /[\"'&<>]/;\nconst doubleQuoteChar = 34; // \"\nconst ampersandChar = 38; // &\nconst singleQuoteChar = 39; // '\nconst lessThanChar = 60; // <\nconst greaterThanChar = 62; // >\n\n/**\n * Handle special characters by escaping in the provided text string.\n *\n * @param {string} stringToEscape - the string to escape\n * @return {string} - the escaped string\n */\nexport const escapeHtml = (stringToEscape: number | string | null | undefined): string => {\n const str = `${stringToEscape}`;\n const match = matchHtmlRegExp.exec(str);\n\n if (!match) {\n return str;\n }\n\n let escape: string;\n let html = '';\n let index: number;\n let lastIndex = 0;\n\n for (index = match.index; index < str.length; index++) {\n const charCode = str.codePointAt(index);\n if (charCode === doubleQuoteChar) {\n escape = '"';\n } else if (charCode === ampersandChar) {\n escape = '&';\n } else if (charCode === singleQuoteChar) {\n escape = ''';\n } else if (charCode === lessThanChar) {\n escape = '<';\n } else if (charCode === greaterThanChar) {\n escape = '>';\n } else {\n escape = '';\n }\n\n if (escape !== '') {\n if (lastIndex !== index) {\n html += str.slice(lastIndex, index);\n }\n\n lastIndex = index + 1;\n html += escape;\n }\n }\n\n return lastIndex !== index ? html + str.slice(lastIndex, index) : html;\n};\n","import type { Node, Descendant } from 'slate';\nimport type { NodeObject } from './types';\nimport { isNotNil, isNil, isString, isArray } from '@wistia/type-guards';\nimport { Element, Text } from 'slate';\nimport { jsx } from 'slate-hyperscript';\nimport { escapeHtml } from '../../helpers/escapeHtml';\n\n// All Element nodes must contain at least one Text descendant.\n// If an element node does not contain any children,\n// an empty text node will be added as its only child.\n// Read more at https://docs.slatejs.org/concepts/10-normalizing\nconst emptyTextNode = { text: '' };\n\n// Image nodes need blank text by SlateJS design, so we make some exceptions for them\nconst rteIsNonImageNodeType = (node: Descendant): boolean => node.type !== 'image';\n\nconst rteIsInvalidImage = (node: Descendant): boolean =>\n node.type === 'image' && node.url === undefined;\n\nconst rteHasOnlyOneChild = (node: Descendant): boolean =>\n isNotNil(node.children) && node.children.length === 1;\nconst rteIsEmptyTextNode = (node: Descendant): boolean =>\n Text.isText(node) && node.text?.trim() === '';\nconst rteIsOnlyChildWithEmptyText = (node: Descendant): boolean =>\n // We know that node.children[0] exists bcause of rteHasOnlyOneChild\n // oxlint-disable-next-line @typescript-eslint/no-non-null-assertion\n rteHasOnlyOneChild(node) && rteIsEmptyTextNode(node.children![0]!);\n\nconst isValueNull = (value: (string | null)[]): boolean => value.every((val) => isNil(val));\nconst sanitizedValue = (value: (string | null)[]): string | null =>\n isValueNull(value) ? null : value.join('');\n\n// Handles cases in foreign HTML (i.e., in case of import or paste)\n// when links may be wrapped by attr tags like <strong></strong>,\n// which breaks the rules of SlateJS.\n// The code here correctly adds those attrs to the children of the element.\n// Inspired by https://github.com/udecode/slate-plugins/pull/83/files.\nconst addAttrsToChildren = (child: Descendant, attrs: Record<string, unknown>) => {\n const childCopy = child;\n if (childCopy.children) {\n childCopy.children = childCopy.children.map((item) => {\n const itemWithAttrs = addAttrsToChildren(item, attrs);\n return { ...itemWithAttrs, ...attrs };\n });\n }\n return childCopy;\n};\n\n// serialize to HTML\nconst serializeText = (textNode: Text) => {\n const text = escapeHtml(textNode.text);\n const newStringArr = [text];\n if (isNotNil(textNode.bold) && textNode.bold) {\n newStringArr.push('</strong>');\n newStringArr.unshift('<strong>');\n }\n if (isNotNil(textNode.italic) && textNode.italic) {\n newStringArr.push('</em>');\n newStringArr.unshift('<em>');\n }\n if (isNotNil(textNode.underline) && textNode.underline) {\n newStringArr.push('</u>');\n newStringArr.unshift('<u>');\n }\n if (isNotNil(textNode.strikethrough) && textNode.strikethrough) {\n newStringArr.push('</s>');\n newStringArr.unshift('<s>');\n }\n if (isNotNil(textNode.code) && textNode.code) {\n newStringArr.push('</code>');\n newStringArr.unshift('<code>');\n }\n return newStringArr.join('');\n};\n\nconst serializeNode = (node: Descendant): string | null => {\n // if the only thing in the editor is\n // a non-image RTE node with empty text (since image nodes need empty text by SlateJS design)\n // OR if the node is an image but invalid, with an undefined src\n // do not serialize the HTML for it.\n if (\n (rteIsNonImageNodeType(node) && rteIsOnlyChildWithEmptyText(node)) ||\n rteIsInvalidImage(node)\n ) {\n return null;\n }\n\n if (Text.isText(node)) {\n return serializeText(node);\n }\n\n const children = isNotNil(node.children)\n ? node.children.map((node_) => serializeNode(node_)).join('')\n : '';\n\n switch (node.type) {\n case 'span':\n return `<span>${children}</span>`;\n case 'blockquote':\n return `<blockquote>${children}</blockquote>`;\n case 'paragraph':\n return `<p>${children}</p>`;\n case 'heading-one':\n return `<h1>${children}</h1>`;\n case 'heading-two':\n return `<h2>${children}</h2>`;\n // We preserve the original headers \"under the hood\" in the HTML\n // Even though we render h4-h6 as h3s in the editor UI per Design request.\n case 'heading-three':\n return `<h3>${children}</h3>`;\n case 'heading-four':\n return `<h4>${children}</h4>`;\n case 'heading-five':\n return `<h5>${children}</h5>`;\n case 'heading-six':\n return `<h6>${children}</h6>`;\n case 'link':\n return `<a rel=\"noopener noreferrer\" target=\"_blank\" href=\"${escapeHtml(\n node.url,\n )}\">${children}</a>`;\n case 'numbered-list':\n return `<ol>${children}</ol>`;\n case 'bulleted-list':\n return `<ul>${children}</ul>`;\n case 'list-item':\n return `<li>${children}</li>`;\n case 'image':\n return `<img src=\"${escapeHtml(node.url)}\" />`;\n case 'code':\n return `<code>${children}</code>`;\n case undefined:\n default:\n return children;\n }\n};\n\nexport const rteSerializeToHTML = (value: NodeObject[]): string | null => {\n const mappedValue = value.map((node) => serializeNode(node));\n return sanitizedValue(mappedValue);\n};\n\n// deserialize from HTML\nconst ELEMENT_TAGS = {\n SPAN: () => ({ type: 'span' }),\n A: (el: HTMLElement) => ({ type: 'link', url: el.getAttribute('href') }), // oxlint-disable-line id-length\n BLOCKQUOTE: () => ({ type: 'blockquote' }),\n H1: () => ({ type: 'heading-one' }),\n H2: () => ({ type: 'heading-two' }),\n H3: () => ({ type: 'heading-three' }),\n H4: () => ({ type: 'heading-four' }),\n H5: () => ({ type: 'heading-five' }),\n H6: () => ({ type: 'heading-six' }),\n LI: () => ({ type: 'list-item' }),\n OL: () => ({ type: 'numbered-list' }),\n P: () => ({ type: 'paragraph' }), // oxlint-disable-line id-length\n UL: () => ({ type: 'bulleted-list' }),\n IMG: (el: HTMLElement) => ({ type: 'image', url: el.getAttribute('src') }),\n CODE: () => ({ type: 'code' }),\n};\n\n// `B` is omitted here since the HTML 5 specification discourages the use of that tag.\nconst TEXT_TAGS = {\n DEL: () => ({ strikethrough: true }),\n S: () => ({ strikethrough: true }), // oxlint-disable-line id-length\n EM: () => ({ italic: true }),\n I: () => ({ italic: true }), // oxlint-disable-line id-length\n STRONG: () => ({ bold: true }),\n U: () => ({ underline: true }), // oxlint-disable-line id-length\n CODE: () => ({ code: true }),\n};\n\nconst isTextNode = (el: ChildNode | HTMLElement): boolean => el.nodeType === 3;\nconst isElement = (el: ChildNode | HTMLElement) => el.nodeType === 1;\nconst isCodeBlock = (element: ChildNode | HTMLElement) => element.nodeName === 'CODE';\n// This function catches Code blocks that are \"inline\" as opposed to block.\n// Code blocks are formatted from the markdown with new lines before and after the children, i.e.,\n// <code>\n// I am block content\n// </code>\n// versus <code>I am inline</code\n// which should be treated as text rather than a block.\nconst isInlineCodeBlock = (\n element: ChildNode | HTMLElement,\n elementChildren: (Node | string | null | undefined)[],\n): boolean =>\n // @ts-expect-error I don't want to narrow the type too far and miss something that should be matched here.\n isCodeBlock(element) && isNotNil(elementChildren[0]) && !/\\n/.test(elementChildren[0]);\nconst getCodeChildren = (el: ChildNode | HTMLElement) =>\n [...el.childNodes].map((node) => {\n // This helps us distinguish between code block content that should be treated as HTML vs. as text content\n if (isTextNode(node)) {\n return node.textContent;\n }\n // Only DOM elements have outerHTML; other nodes (e.g. comments) give undefined, as before.\n // `Element` in this file is Slate's, so use the DOM one from globalThis.\n return node instanceof globalThis.Element ? node.outerHTML : undefined;\n });\n// Links and inline code sit in a line of text. The other element tags, code blocks too, make blocks.\nconst isBlockElement = (el: ChildNode) =>\n isElement(el) &&\n el.nodeName in ELEMENT_TAGS &&\n el.nodeName !== 'A' &&\n !(isCodeBlock(el) && isInlineCodeBlock(el, getCodeChildren(el)));\nconst isTextFormatElement = (el: ChildNode | ParentNode) =>\n el.nodeName in TEXT_TAGS || el.nodeName === 'A';\n\nconst isBlockNeighbor = (node: ChildNode | null): boolean => isNotNil(node) && isBlockElement(node);\nconst isComment = (node: ChildNode) => node.nodeType === 8;\nconst isSpaceOnlyText = (node: ChildNode) => isTextNode(node) && node.nodeValue?.trim() === '';\n// Each skipped node saves the content found past it, so a long run of comments is walked once and\n// loads in linear time. The parsed HTML does not change while it loads, so a saved answer stays\n// correct.\nconst contentPastSkipped = {\n previousSibling: new WeakMap<ChildNode, ChildNode | null>(),\n nextSibling: new WeakMap<ChildNode, ChildNode | null>(),\n};\n// Comments load as nothing, so skip them, and the spaces between them, to find the content beside\n// a space.\nconst nearestContent = (\n node: ChildNode,\n direction: 'previousSibling' | 'nextSibling',\n): ChildNode | null => {\n const saved = contentPastSkipped[direction];\n const skipped: ChildNode[] = [];\n let sibling = node[direction];\n while (isNotNil(sibling) && (isComment(sibling) || isSpaceOnlyText(sibling))) {\n if (saved.has(sibling)) {\n sibling = saved.get(sibling) ?? null;\n break;\n }\n skipped.push(sibling);\n sibling = sibling[direction];\n }\n for (const skippedNode of skipped) {\n saved.set(skippedNode, sibling);\n }\n return sibling;\n};\n\n// A space-only text node is the space between two words, for example in\n// `<strong>bold</strong> <em>italic</em>`. It means nothing next to a block, for example the line\n// breaks between list items, or as the only content of a block.\n// Only the content on each side counts, so words next to a block keep their spaces.\nconst isWordSpace = (el: ChildNode): boolean => {\n const parent = el.parentNode;\n if (isNil(parent)) {\n return false;\n }\n if (parent.childNodes.length === 1) {\n return isTextFormatElement(parent);\n }\n return (\n !isBlockNeighbor(nearestContent(el, 'previousSibling')) &&\n !isBlockNeighbor(nearestContent(el, 'nextSibling'))\n );\n};\n\nconst shouldCreateBlock = (\n el: ChildNode | HTMLElement,\n children: (Descendant | Node | string | null)[],\n): boolean =>\n !isInlineCodeBlock(el, children) &&\n isNotNil(ELEMENT_TAGS[el.nodeName as keyof typeof ELEMENT_TAGS]);\nconst shouldCreateText = (\n el: ChildNode | HTMLElement,\n children: (Node | string | null)[],\n): boolean =>\n isInlineCodeBlock(el, children) || isNotNil(TEXT_TAGS[el.nodeName as keyof typeof TEXT_TAGS]);\n\nconst htmlChildIsEmptyText = (child: Descendant | string | null | undefined) =>\n isNotNil(child) && !isString(child) && (child as Text).text?.trim() === '';\n\nconst createEditorBlockElements = (\n children: (Descendant | string | null)[],\n el: ChildNode | HTMLElement,\n): Descendant => {\n const { nodeName } = el;\n if (\n nodeName !== 'IMG' &&\n children.length === 1 &&\n !isString(children[0]) &&\n // @ts-expect-error - text is a property on NodeLeafObject.\n isNotNil(children[0].text) &&\n // Casting to Text as I don't want to further narrow the type in case I miss another type where it's valid. RM 2021-03-31\n (children[0] as Text).text?.trim() === ''\n ) {\n return jsx('element', ELEMENT_TAGS.P(), emptyTextNode);\n }\n const attrs = ELEMENT_TAGS[nodeName as keyof typeof ELEMENT_TAGS](el as HTMLElement);\n return jsx('element', attrs, children);\n};\n\nconst createEditorTextElements = (children: (Descendant | string | null)[], el: HTMLElement) => {\n const { nodeName } = el;\n const attrs = TEXT_TAGS[nodeName as keyof typeof TEXT_TAGS]();\n return children.map((child) => {\n if (!isString(child) && isNotNil(child) && isNotNil(child.children)) {\n return addAttrsToChildren(child, attrs);\n }\n // if a child's text node has an empty string\n // return an empty text node in its place without any of the trimmings (italic, strong, etc.)\n if (htmlChildIsEmptyText(child)) {\n return jsx('text', {}, emptyTextNode);\n }\n return jsx('text', attrs, child);\n });\n};\n\nconst blockWithOnlyTextChildren = (el: HTMLElement) =>\n el.nodeName === 'BLOCKQUOTE' || el.nodeName === 'OL' || el.nodeName === 'UL';\n\nconst getNodeChildren = (\n el: ChildNode | HTMLElement,\n mapper: (\n el: ChildNode | HTMLElement,\n ) => (Descendant | string | null)[] | Descendant | string | null,\n): (Descendant | Node | string | null)[] => {\n let children = [];\n if (isCodeBlock(el)) {\n children = getCodeChildren(el);\n } else if (blockWithOnlyTextChildren(el as HTMLElement)) {\n // Blockquotes, as rendered from our markdown, contain paragraphs, as well as blank text leaf nodes as their first and last children.\n // Ordered lists and unordered lists also contain blank text leaf nodes as their first and last children.\n // To avoid stripping those out via \"safeChildren\", and to allow for more sophisticated rendering of internal text nodes -- i.e. of bold/italic.etc. text within a blockquote's internal paragraph --\n // We remove the blank string content here.\n // Text nodes and formats go to `mapper`, which keeps the spaces between words, also `<em> </em>`.\n children = [...el.childNodes]\n .filter(\n (node) => isTextNode(node) || isTextFormatElement(node) || node.textContent?.trim() !== '',\n )\n .flatMap((node) => mapper(node));\n } else {\n children = [...el.childNodes].flatMap((node) => mapper(node));\n }\n\n // TODO revisit this casting by instead being more specific about return types above.\n return children as (Descendant | Node | string | null)[];\n};\n\nconst deserializeHTMLNode = (\n el: ChildNode | HTMLElement,\n): (Descendant | string | null)[] | Descendant | string | null => {\n if (isTextNode(el)) {\n if (el.nodeValue?.trim() === '' && !isWordSpace(el)) {\n return null;\n }\n return el.textContent;\n }\n if (el.nodeName === 'BR') {\n return '\\n';\n }\n if (!isElement(el)) {\n return null;\n }\n\n const children = getNodeChildren(el, deserializeHTMLNode);\n // Only keep valid Descendant objects (with 'text' or 'type' properties), strings, or null values\n const filteredChildren = children.filter(\n (child): child is Descendant | string | null =>\n child === null ||\n typeof child === 'string' ||\n (typeof child === 'object' && ('text' in child || 'type' in child)),\n );\n // This allows us to handle \"empty\" elements, i.e, for those that we've removed text content from.\n // SlateJS blows up if we don't provide at least an empty text node as a child.\n // A removed first child (a comment, or space next to a block) must not remove the others.\n const nonNullChildren = filteredChildren.filter((child) => isNotNil(child));\n const safeChildren = nonNullChildren.length > 0 ? nonNullChildren : [emptyTextNode];\n\n if (el.nodeName === 'BODY') {\n return jsx('fragment', {}, safeChildren);\n }\n\n if (shouldCreateBlock(el, children)) {\n return createEditorBlockElements(safeChildren, el);\n }\n\n if (shouldCreateText(el, safeChildren)) {\n return createEditorTextElements(safeChildren, el as HTMLElement);\n }\n\n return children;\n};\n\nconst isInlineNode = (node: Descendant) =>\n Text.isText(node) || (Element.isElement(node) && node.type === 'link');\n\n// Puts each run of text and links that is not in a block into a paragraph, with its formats.\nconst wrapLooseInlineNodes = (nodes: Descendant[]): Descendant[] => {\n const blocks: Descendant[] = [];\n let paragraph: Descendant[] | undefined;\n for (const node of nodes) {\n if (!isInlineNode(node)) {\n paragraph = undefined;\n blocks.push(node);\n } else if (isNil(paragraph)) {\n paragraph = [node];\n blocks.push({ type: 'paragraph', children: paragraph });\n } else {\n paragraph.push(node);\n }\n }\n return blocks;\n};\n\nexport const rteDeserializeHTML = (\n htmlString: string,\n): (NodeObject | string | null)[] | NodeObject | string | null | undefined => {\n if (!htmlString) {\n return undefined;\n }\n const parsedEl = new DOMParser().parseFromString(htmlString, 'text/html').body;\n const body = deserializeHTMLNode(parsedEl);\n // We need this in order to handle values from a plain text input\n // i.e., values entered into the Description field on the \"Set up your Channel\" form in the Create Channel flow.\n // If we don't do this, we'll get <body>some text</body>, which breaks the editor\n // Since there's no top-level block element wrapping the text.\n const fragment = isArray(body) ? wrapLooseInlineNodes(body as Descendant[]) : body;\n // If the last element added to the editor is NOT a paragraph,\n // Insert a paragraph as the last element\n // So the cursor is always escaped below the last element.\n const lastNodeOfFragment = isArray(fragment) ? fragment.at(-1) : undefined;\n if (\n isArray(fragment) &&\n Element.isElement(lastNodeOfFragment) &&\n lastNodeOfFragment.type !== 'paragraph'\n ) {\n return [...fragment, { type: 'paragraph', children: [{ text: '' }] }];\n }\n return fragment;\n};\n","import type { Editor } from 'slate';\nimport { isNonEmptyString } from '@wistia/type-guards';\nimport { useEffect, useId, useState } from 'react';\nimport { ReactEditor } from 'slate-react';\n\n/**\n * A `<label for>` only names and focuses native form controls, and the editor's text area is a\n * contenteditable `div`. This finds the label that points at `id` and focuses the editor when the\n * label is clicked. When `isName` is true, it also returns the label's id for `aria-labelledby`\n * (it gives the label an id when it has none).\n */\nexport const useLabelFor = (\n editor: Editor,\n id: string | undefined,\n isName: boolean,\n): string | undefined => {\n const generatedLabelId = useId();\n const [labelId, setLabelId] = useState<string>();\n\n useEffect(() => {\n if (!isNonEmptyString(id)) {\n return undefined;\n }\n const { ownerDocument } = ReactEditor.toDOMNode(editor, editor);\n const label = [...ownerDocument.querySelectorAll('label')].find(\n (element) => element.htmlFor === id,\n );\n if (!label) {\n return undefined;\n }\n const focusEditor = () => {\n ReactEditor.focus(editor);\n };\n label.addEventListener('click', focusEditor);\n const addsId = isName && !isNonEmptyString(label.id);\n if (addsId) {\n label.id = generatedLabelId;\n }\n if (isName) {\n setLabelId(label.id);\n }\n\n return () => {\n label.removeEventListener('click', focusEditor);\n if (addsId) {\n label.removeAttribute('id');\n }\n setLabelId(undefined);\n };\n }, [editor, generatedLabelId, id, isName]);\n\n return labelId;\n};\n","import type { Descendant, Editor } from 'slate';\nimport type { NodeElementObject } from '../types';\nimport { isNotNil, isNonEmptyString, isUndefined } from '@wistia/type-guards';\nimport { useCallback, useEffect, useRef } from 'react';\nimport isEqual from 'react-fast-compare';\nimport { Text } from 'slate';\nimport { rteSerializeToHTML } from '../serializers';\n\n// All Element nodes must contain at least one Text descendant.\n// If an element node does not contain any children,\n// an empty text node will be added as its only child.\n// Read more at https://docs.slatejs.org/concepts/10-normalizing\nexport const emptyValue: Descendant[] = [\n {\n type: 'paragraph',\n children: [{ text: '' }],\n },\n];\n\n// How long an emitted editor state stays recognizable as an echo. This needs\n// to outlast any save round trip; a matching value that arrives later than this\n// is treated as a genuine external update.\nconst ECHO_WINDOW_MS = 10_000;\n// Memory backstop for parents that never echo. Far above what a user can type\n// within ECHO_WINDOW_MS, so in practice only the time window evicts states.\nconst MAX_PENDING_ECHOES = 1000;\n\ntype PendingEchoes = Map<string | null, number>;\n\n// Drops states that are too old to be echoes. Map iteration follows insertion\n// order, and states are re-inserted when emitted, so the oldest come first.\nconst prunePendingEchoes = (pending: PendingEchoes, now: number) => {\n for (const [html, emittedAt] of pending) {\n if (now - emittedAt <= ECHO_WINDOW_MS && pending.size <= MAX_PENDING_ECHOES) {\n return;\n }\n pending.delete(html);\n }\n};\n\n// true when any line holds text or an image, also when the first line is empty, a list, or a link\nconst hasContent = (nodes: Descendant[] | undefined): boolean =>\n isNotNil(nodes) &&\n nodes.some((node) =>\n Text.isText(node)\n ? isNonEmptyString(node.text)\n : node.type === 'image' || hasContent(node.children),\n );\n\ntype UseExternalValueSyncArgs = {\n editor: Editor;\n // `undefined` when the editor is uncontrolled (it started from `defaultValue`)\n value: Descendant[] | undefined;\n useExternalValue: boolean;\n onChange?: ((value: NodeElementObject[]) => void) | undefined;\n};\n\n/**\n * Keeps a Slate editor in sync with a controlled `value` prop without clobbering\n * in-progress typing.\n *\n * Controlled parents echo every `onChange` back as `value`. When that echo is\n * delayed (async store, debounced save, slow render), the prop can arrive\n * holding an *older* editor state than the one the user is typing into. The\n * previous implementation treated any mismatch as an external update, reset\n * `editor.children` to the stale value and nulled the selection — dropping\n * characters and sending the caret to the start of the document.\n *\n * Here, every state emitted through `onChange` is remembered for\n * `ECHO_WINDOW_MS`. A `value` that matches one of those states is an echo\n * (current or stale, in any order, any number of times, and even after an\n * external update) and is ignored. Anything else is a genuine external update\n * and is applied, as before.\n *\n * Returns the `onChange` handler to pass to `<Slate>`.\n *\n * This is directly from the Slate.js docs on how to update slate outside of onChange:\n * If you want to update the editor's content in response to events from outside of Slate, you\n * need to change the children property directly. The simplest way is to replace the value of\n * editor.children editor.children = newValue and trigger a re-rendering (e.g. by calling\n * editor.onChange()).\n * More info here: https://docs.slatejs.org/walkthroughs/06-saving-to-a-database\n */\nexport const useExternalValueSync = ({\n editor,\n value,\n useExternalValue,\n onChange,\n}: UseExternalValueSyncArgs) => {\n // The serialized `value` prop we last reconciled. Slate already renders the\n // mount-time value via `initialValue`, so start from it: the mount effect (and\n // any re-render passing a new array with the same content) is then a no-op and\n // cannot wipe text typed before it ran.\n // `undefined` while uncontrolled; `null` is the HTML of an empty editor.\n const lastSeenValueHtml = useRef<string | null | undefined>(\n isUndefined(value) ? undefined : rteSerializeToHTML(value),\n );\n // The `useExternalValue` flag we last reconciled with. Turning it on must\n // re-evaluate a value that was skipped while it was off.\n const lastSeenUseExternalValue = useRef(useExternalValue);\n // Serialized editor states emitted through onChange within the echo window,\n // mapped to when they were last emitted, oldest first. Echoes do not consume\n // them: a state can be echoed more than once (it may have been emitted more\n // than once), and echoes can arrive in any order.\n const pendingEchoes = useRef<PendingEchoes>(new Map());\n\n const handleChange = useCallback(\n (nodes: Descendant[]) => {\n const html = rteSerializeToHTML(nodes);\n const pending = pendingEchoes.current;\n const now = Date.now();\n // Re-insert so the map stays ordered by emit time. Selection-only changes\n // re-emit identical content and only refresh the timestamp.\n pending.delete(html);\n pending.set(html, now);\n prunePendingEchoes(pending, now);\n if (isNotNil(onChange)) {\n onChange(nodes);\n }\n },\n [onChange],\n );\n\n useEffect(() => {\n // An uncontrolled editor keeps its own content. A `value` given later is then new.\n if (isUndefined(value)) {\n lastSeenValueHtml.current = undefined;\n lastSeenUseExternalValue.current = useExternalValue;\n return;\n }\n const valueHtml = rteSerializeToHTML(value);\n if (\n valueHtml === lastSeenValueHtml.current &&\n useExternalValue === lastSeenUseExternalValue.current\n ) {\n return;\n }\n lastSeenValueHtml.current = valueHtml;\n lastSeenUseExternalValue.current = useExternalValue;\n\n // The parent is echoing a state this editor emitted (possibly an older one\n // than the editor now holds, and not necessarily in emit order). The editor\n // is already at or past it.\n const pending = pendingEchoes.current;\n prunePendingEchoes(pending, Date.now());\n if (pending.has(valueHtml)) {\n return;\n }\n\n const isEmptyValue = isEqual(value, emptyValue);\n /** if we have an external value and the text editor is not empty (and therefore valid), we can safely update the editor. */\n if (!(isEmptyValue || (hasContent(value) && useExternalValue))) {\n return;\n }\n if (valueHtml === rteSerializeToHTML(editor.children)) {\n return;\n }\n\n // Emitted states stay recognizable: echoes still in flight from before this\n // update must not be applied over it.\n // oxlint-disable-next-line @eslint-react/immutability -- required by Slate to update content from outside onChange\n editor.children = value;\n editor.selection = null;\n editor.onChange();\n }, [value, editor, useExternalValue]);\n\n return handleChange;\n};\n","import type { AriaAttributes, CSSProperties, FocusEvent, FC } from 'react';\nimport type { Descendant, Editor, Node } from 'slate';\nimport type { RenderLeafProps, RenderElementProps } from 'slate-react';\nimport type { NodeElementObject, NodeObject } from './types';\nimport { isArray, isNil, isNotNil, isString, isUndefined } from '@wistia/type-guards';\nimport { isHotkey } from 'is-hotkey';\nimport { useCallback, useMemo, useState } from 'react';\nimport { createEditor, Transforms, Element, Text } from 'slate';\nimport { withHistory } from 'slate-history';\nimport { Editable, withReact, Slate, ReactEditor } from 'slate-react';\nimport { styled } from 'styled-components';\nimport { EditorButtons } from './EditorButtons';\nimport { Element as ElementToRender } from './Element';\nimport { Leaf } from './Leaf';\nimport { rteDeserializeHTML, rteSerializeToHTML } from './serializers';\nimport { useLabelFor } from './useLabelFor';\nimport {\n rteFormatTypes,\n handleListEscape,\n withLinks,\n withImages,\n toggleMark,\n toggleBlock,\n} from './utilities';\nimport { emptyValue, useExternalValueSync } from './utilities/useExternalValueSync';\n\nconst EditableWrapper = styled(Editable)`\n color: var(--rte-text-color, #37373c);\n outline: none; /* the outer box shows the focus instead */\n`;\n\ntype EditorWrapperProps = {\n $disabled: boolean;\n $height: string | undefined;\n};\n\nconst defaultHeight = '300px';\nconst EditorWrapper = styled.div<EditorWrapperProps>`\n background: var(--rte-background, #ffffff);\n border: 1px solid var(--rte-border-color, #c4c4c8);\n border-radius: var(--rte-border-radius, 4px);\n cursor: ${({ $disabled }) => ($disabled ? 'not-allowed' : 'auto')};\n\n /* UIProvider defines its font as a token, not on body. With no token, the font is inherited\n (VHSProvider sets it on body). */\n font-family: var(--rte-font-family, var(--wui-typography-family-default));\n font-size: 14px;\n font-weight: 500;\n height: ${({ $height }) => $height ?? defaultHeight};\n overflow: auto;\n padding: 0 16px;\n\n &:has(${EditableWrapper}:focus) {\n outline: 2px solid var(--rte-focus-color, var(--rte-accent-color, #2949e5));\n outline-offset: -1px; /* on the border, where the sticky toolbar cannot cover it */\n }\n\n strong {\n font-weight: 700;\n }\n`;\n\nconst HOTKEYS = {\n 'mod+b': 'bold',\n 'mod+i': 'italic',\n 'mod+u': 'underline',\n};\n\nexport type RichTextEditorProps = AriaAttributes & {\n /**\n * Same as `aria-labelledby`. `aria-labelledby` wins when both are set.\n */\n ariaLabelledBy?: string | undefined;\n /**\n * Class name for the outer box (border, toolbar, and text area)\n */\n className?: string | undefined;\n /**\n * Test id for the outer box\n */\n 'data-testid'?: string;\n /**\n * Starting content when `value` is not set: an HTML string or editor nodes.\n * The editor does not read it again after the first render.\n */\n defaultValue?: NodeObject[] | string | undefined;\n /**\n * Determines whether editor is clickable/read-only\n */\n disabled?: boolean;\n /**\n * Formats to enable in editor, restricted to rteFormatTypes\n */\n enabledFormats?: (keyof typeof rteFormatTypes)[];\n /**\n * Custom height of editor\n */\n height?: string | undefined;\n /**\n * Id of the text area. A `<label for>` with this id names the text area and focuses it on click.\n */\n id?: string | undefined;\n /**\n * Adds a hidden input with this name. Its value is the content as HTML, so a native form\n * submission or `FormData` includes it.\n */\n name?: string | undefined;\n /**\n * Function to be called when editor loses focus\n */\n onBlur?: ((value: NodeElementObject[]) => void) | undefined;\n /**\n * Function to be called after editor state update\n */\n onChange?: ((value: NodeElementObject[]) => void) | undefined;\n /**\n * Placeholder text\n */\n placeholder?: string;\n /**\n * Inline styles for the outer box\n */\n style?: CSSProperties | undefined;\n /**\n * Whether to update the editor when the value prop changes\n */\n useExternalValue?: boolean;\n /**\n * Content of the editor. The editor reads it on the first render. After that, it reads it again\n * when it is the empty value (to clear the editor), or when `useExternalValue` is true.\n */\n value?: NodeObject[] | undefined;\n};\n\nconst toNodes = (content: NodeObject[] | string | undefined): Descendant[] | undefined => {\n if (!isString(content)) {\n return content;\n }\n const nodes = rteDeserializeHTML(content);\n // the editor only accepts a list of elements as its value\n return isArray(nodes) && nodes.length > 0 && nodes.every((node) => Element.isElement(node))\n ? nodes\n : undefined;\n};\n\nconst serialize = (nodes: Descendant[]): string => rteSerializeToHTML(nodes) ?? '';\n\nexport const RichTextEditor: FC<RichTextEditorProps> = ({\n 'aria-label': ariaLabel,\n 'aria-labelledby': ariaLabelledByAttribute,\n ariaLabelledBy,\n className,\n 'data-testid': dataTestId = 'rich-text-editor',\n defaultValue,\n disabled = false,\n enabledFormats = Object.values(rteFormatTypes),\n height,\n id,\n name,\n onBlur,\n onChange,\n placeholder = 'Enter some rich text...',\n style,\n useExternalValue = false,\n value,\n ...ariaProps\n}) => {\n const renderElement = useCallback(\n (props: RenderElementProps) => <ElementToRender {...props} />,\n [],\n );\n const renderLeaf = useCallback((props: RenderLeafProps) => <Leaf {...props} />, []);\n const editor: Editor = useMemo(() => {\n const baseEditor = withReact(createEditor());\n return withImages(withLinks(withHistory(baseEditor)));\n }, []);\n // Slate reads its initial value only once, so the first render decides it\n const [initialValue] = useState(() => value ?? toNodes(defaultValue) ?? emptyValue);\n // kept current without `name` too, so a `name` added later submits the content\n const [html, setHtml] = useState(() => serialize(initialValue));\n const labelledBy = ariaLabelledByAttribute ?? ariaLabelledBy;\n const labelId = useLabelFor(editor, id, isNil(ariaLabel) && isNil(labelledBy));\n // Without `defaultValue`, a missing `value` means \"empty\", as it did before `defaultValue` existed.\n const externalValue = value ?? (isUndefined(defaultValue) ? emptyValue : undefined);\n const handleSyncedChange = useExternalValueSync({\n editor,\n value: externalValue,\n useExternalValue,\n onChange,\n });\n\n const handleChange = (nodes: Descendant[]) => {\n setHtml(serialize(nodes));\n handleSyncedChange(nodes);\n };\n\n const handleEditorBlur = (_event: FocusEvent<HTMLDivElement>) => {\n const updatedValue = editor.children;\n\n if (isNotNil(onBlur)) {\n onBlur(updatedValue);\n }\n };\n\n // returns true when it removed an image\n const handleRemoveImageIfSelected = useCallback((): boolean => {\n const { selection } = editor;\n\n if (isNil(selection) || isNil(selection.anchor.path[0])) {\n return false;\n }\n\n const selectedElement = editor.children[selection.anchor.path[0]];\n if (!Element.isElement(selectedElement) || selectedElement.type !== 'image') {\n return false;\n }\n\n toggleBlock(editor, 'image');\n Transforms.removeNodes(editor, { at: selection });\n Transforms.move(editor, { reverse: true });\n const spanElement = editor.children.find(\n (child: Node) => Element.isElement(child) && child.type === 'span',\n );\n if (\n Element.isElement(spanElement) &&\n spanElement.type === 'span' &&\n isNotNil(spanElement.children) &&\n isNotNil(spanElement.children[0]) &&\n isNotNil(spanElement.children[0].text) &&\n spanElement.children[0].text.trim() !== ''\n ) {\n Transforms.setNodes(\n editor,\n { type: 'paragraph' },\n {\n match: (node: Node) =>\n Element.isElement(node) &&\n node.type === 'span' &&\n isNotNil(node.children) &&\n Text.isText(node.children[0]) &&\n isNotNil(node.children[0].text) &&\n node.children[0].text.trim() !== '',\n split: true,\n mode: 'highest',\n },\n );\n }\n return true;\n }, [editor]);\n\n return (\n // oxlint-disable-next-line styled-components-a11y/click-events-have-key-events, styled-components-a11y/no-static-element-interactions\n <EditorWrapper\n $disabled={disabled}\n $height={height}\n className={className}\n data-testid={dataTestId}\n onClick={() => {\n ReactEditor.focus(editor);\n }}\n style={style}\n >\n <Slate\n editor={editor}\n initialValue={initialValue}\n onChange={handleChange}\n >\n <EditorButtons\n disabled={disabled}\n enabledFormats={enabledFormats}\n />\n <EditableWrapper\n {...ariaProps}\n aria-disabled={disabled || ariaProps['aria-disabled']}\n aria-label={ariaLabel}\n aria-labelledby={labelledBy ?? labelId}\n // Slate drops the role while read-only; keep it so a disabled editor still has a name\n aria-multiline={true}\n autoFocus={false}\n data-testid=\"editor-content\"\n id={id}\n onBlur={handleEditorBlur}\n onKeyDown={(event) => {\n Object.keys(HOTKEYS).forEach((hotKey: string) => {\n if (isHotkey(hotKey, event)) {\n event.preventDefault();\n toggleMark(editor, HOTKEYS[hotKey as keyof typeof HOTKEYS]);\n }\n });\n if (event.key === 'Enter' && !event.shiftKey) {\n handleListEscape(editor);\n }\n if (event.key === 'Backspace' || event.key === 'Clear' || event.key === 'Delete') {\n // the image is gone; the browser's own delete would also take the text before it\n if (handleRemoveImageIfSelected()) {\n event.preventDefault();\n }\n }\n }}\n placeholder={placeholder}\n readOnly={disabled}\n renderElement={renderElement}\n renderLeaf={renderLeaf}\n role=\"textbox\"\n spellCheck={true}\n />\n </Slate>\n {isNotNil(name) && (\n <input\n disabled={disabled}\n name={name}\n type=\"hidden\"\n value={html}\n />\n )}\n </EditorWrapper>\n );\n};\n\nRichTextEditor.displayName = 'RichTextEditor';\n"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@wistia/rich-text-editor",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.1.0",
|
|
4
4
|
"description": "Slate-based rich text editor for Wistia apps",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"module": "dist/index.js",
|
|
@@ -49,7 +49,7 @@
|
|
|
49
49
|
"slate-react": "^0.142.0"
|
|
50
50
|
},
|
|
51
51
|
"devDependencies": {
|
|
52
|
-
"@repo/config": "
|
|
52
|
+
"@repo/config": "0.0.0",
|
|
53
53
|
"@storybook/addon-a11y": "^10.6.2",
|
|
54
54
|
"@storybook/addon-docs": "^10.6.2",
|
|
55
55
|
"@storybook/react-vite": "^10.6.2",
|
|
@@ -64,8 +64,8 @@
|
|
|
64
64
|
"@typescript/native": "npm:typescript@7.1.0-beta",
|
|
65
65
|
"@vitejs/plugin-react": "^6.1.2",
|
|
66
66
|
"@vitest/coverage-v8": "^5.0.5",
|
|
67
|
-
"@wistia/ui": "
|
|
68
|
-
"@wistia/vhs": "
|
|
67
|
+
"@wistia/ui": "3.1.0",
|
|
68
|
+
"@wistia/vhs": "6.0.5",
|
|
69
69
|
"check-export-map": "^1.3.1",
|
|
70
70
|
"jsdom": "^30.1.3",
|
|
71
71
|
"react": "^19.3.1",
|
|
@@ -87,4 +87,4 @@
|
|
|
87
87
|
"url": "https://github.com/wistia/vhs/issues"
|
|
88
88
|
},
|
|
89
89
|
"homepage": "https://github.com/wistia/vhs#readme"
|
|
90
|
-
}
|
|
90
|
+
}
|