{
+ const newValue = (event.target as HTMLDivElement).innerHTML;
+ onContentChange(newValue);
+ }}
+ {...props}
+ />
+ );
+};
diff --git a/packages/react-components/react-components/stories/ContentEditableTags/data.ts b/packages/react-components/react-components/stories/ContentEditableTags/data.ts
new file mode 100644
index 0000000000000..7e3bae7308ceb
--- /dev/null
+++ b/packages/react-components/react-components/stories/ContentEditableTags/data.ts
@@ -0,0 +1,72 @@
+export const people = [
+ 'Alex Manning',
+ 'Adam Dalton',
+ 'Albert Kidd',
+ 'Bob Hartmann',
+ 'Bill Whitman',
+ 'Brian White',
+ 'Charlie Donohue',
+ 'Carl Mccaffrey',
+ 'Chase Roberts',
+ 'Donald Lee',
+ 'David Lloyd',
+ 'Daniel Williams',
+ 'Esther Chiu',
+ 'Estelle Lapin',
+ 'Emily Dupres',
+ 'Franz Kramer',
+ 'Francis Goth',
+ 'Fanny Chantal',
+ 'Geoff Wilson',
+ 'George Michaels',
+ 'Gale Benson',
+ 'Harry Wilkes',
+ 'Hannibal Troy',
+ 'Hector Gonzales',
+ 'Indira Singh',
+ 'Ian Elba',
+ 'Isaac Bend',
+ 'Jamie Doyle',
+ 'James Reilly',
+ 'Jude Ryan',
+ 'Karl Olafsson',
+ 'Kai Mitsuko',
+ 'Katherine Decker',
+ 'Leonard Dihlmann',
+ 'Lukas Stanek',
+ 'Leah Faber ',
+ 'Max Mustermann',
+ 'Malcom Middleton',
+ 'Morgan Stanley',
+ 'Nils Stanek',
+ 'Natalia Susek',
+ 'Noel Walsh',
+ 'Otto Liebermann',
+ 'Owen Wilson',
+ 'Olivia Wright',
+ 'Peter Murphy',
+ 'Paige Hart',
+ 'Patrik Flaherty',
+ 'Rob Mccaffrey',
+ 'Robin Fitzpatrick',
+ 'Ruby Yu',
+ 'Simon Baker',
+ 'Sebastian Kant',
+ 'Sarah Cortez',
+ 'Tony McGuire',
+ 'Thomas Smyth',
+ 'Tania Lackner',
+ 'Ulla Thamm',
+ 'Umi Safin',
+ 'Una Bentley',
+ 'Victor Schmidt',
+ 'Victoria Bennet',
+ 'Valentin Lungo',
+ 'Xavier Lacalle',
+ 'Yves Deley',
+ 'Yasmin Targa',
+ 'Yvette Davidson',
+ 'Zachary Stephenson',
+ 'Zander Goi',
+ 'Zack Bonnet',
+];
diff --git a/packages/react-components/react-components/stories/ContentEditableTags/index.stories.tsx b/packages/react-components/react-components/stories/ContentEditableTags/index.stories.tsx
new file mode 100644
index 0000000000000..932817e64856d
--- /dev/null
+++ b/packages/react-components/react-components/stories/ContentEditableTags/index.stories.tsx
@@ -0,0 +1,6 @@
+export { SelectionManipulationPicker } from './SelectionManipulationPicker.stories';
+export { LexicalPicker } from './LexicalPicker.stories';
+
+export default {
+ title: 'Concepts/Developer/Accessibility/ContentEditableTags',
+};
diff --git a/packages/react-components/react-components/stories/ContentEditableTags/utils/constants.ts b/packages/react-components/react-components/stories/ContentEditableTags/utils/constants.ts
new file mode 100644
index 0000000000000..6edc5fefa7d92
--- /dev/null
+++ b/packages/react-components/react-components/stories/ContentEditableTags/utils/constants.ts
@@ -0,0 +1 @@
+export const ACTIVEDESCENDANT_ATTRIBUTE = 'data-activedescendant';
diff --git a/packages/react-components/react-components/stories/ContentEditableTags/utils/stories.tsx b/packages/react-components/react-components/stories/ContentEditableTags/utils/stories.tsx
new file mode 100644
index 0000000000000..62912329ad45f
--- /dev/null
+++ b/packages/react-components/react-components/stories/ContentEditableTags/utils/stories.tsx
@@ -0,0 +1,48 @@
+import * as React from 'react';
+import { useFluent } from '@fluentui/react-components';
+
+const APP_TITLE = 'Content editable tags';
+const APP_TITLE_SEPARATOR = ' | ';
+
+interface FullscreenLinkProps {
+ parent: string;
+ story: string;
+ content: string;
+}
+
+// https://storybook.js.org/addons/@storybook/addon-links does not allow opening a story in new tab
+// so this is a naive attempt for opening a story in full screen
+export const FullscreenLink = (props: FullscreenLinkProps) => (
+
+ {props.content}
+
+);
+
+export const TagsListLink: React.FC = props => (
+
+ {props.children}
+
+);
+
+export const BackLink = () =>
Go back to main menu;
+
+export const Prototype: React.FC<{ pageTitle: string }> = ({ pageTitle, children }) => {
+ const { targetDocument } = useFluent();
+
+ React.useEffect(() => {
+ if (targetDocument) {
+ targetDocument.title = pageTitle + APP_TITLE_SEPARATOR + APP_TITLE;
+ }
+ }, [targetDocument, pageTitle]);
+
+ return (
+ <>
+
+
+ {children}
+ >
+ );
+};
diff --git a/packages/react-components/react-components/stories/ContentEditableTags/utils/types.ts b/packages/react-components/react-components/stories/ContentEditableTags/utils/types.ts
new file mode 100644
index 0000000000000..f9bb5b40d06df
--- /dev/null
+++ b/packages/react-components/react-components/stories/ContentEditableTags/utils/types.ts
@@ -0,0 +1,15 @@
+import * as React from 'react';
+
+export interface ActiveDescendantImperativeRef {
+ first: () => void;
+ next: () => void;
+ prev: () => void;
+ blur: () => void;
+ active: () => string | undefined;
+ focus: (id: string) => void;
+}
+
+export interface ActiveDescendantOptions {
+ matchOption: (el: HTMLElement) => boolean;
+ imperativeRef?: React.RefObject
;
+}
diff --git a/packages/react-components/react-components/stories/ContentEditableTags/utils/useActiveDescendant.ts b/packages/react-components/react-components/stories/ContentEditableTags/utils/useActiveDescendant.ts
new file mode 100644
index 0000000000000..dcc82c665454a
--- /dev/null
+++ b/packages/react-components/react-components/stories/ContentEditableTags/utils/useActiveDescendant.ts
@@ -0,0 +1,138 @@
+import * as React from 'react';
+import { useOptionWalker } from './useOptionWalker';
+import type { ActiveDescendantOptions } from './types';
+import { ACTIVEDESCENDANT_ATTRIBUTE } from './constants';
+
+export function useActiveDescendant(
+ options: ActiveDescendantOptions,
+) {
+ const { imperativeRef, matchOption } = options;
+ const activeParentRef = React.useRef(null);
+ const { listboxRef, optionWalker } = useOptionWalker({ matchOption });
+ const getActiveDescendant = () => {
+ return listboxRef.current?.querySelector(`[${ACTIVEDESCENDANT_ATTRIBUTE}]`);
+ };
+
+ const scrollActiveIntoView = (active: HTMLElement) => {
+ if (!listboxRef.current) {
+ return;
+ }
+
+ if (listboxRef.current.offsetHeight >= listboxRef.current.scrollHeight) {
+ return;
+ }
+
+ const { offsetHeight, offsetTop } = active;
+ const { offsetHeight: parentOffsetHeight, scrollTop } = listboxRef.current;
+
+ const isAbove = offsetTop < scrollTop;
+ const isBelow = offsetTop + offsetHeight > scrollTop + parentOffsetHeight;
+
+ const buffer = 2;
+
+ if (isAbove) {
+ listboxRef.current.scrollTo(0, offsetTop - buffer);
+ }
+
+ if (isBelow) {
+ listboxRef.current.scrollTo(0, offsetTop - parentOffsetHeight + offsetHeight + buffer);
+ }
+ };
+
+ const setActiveDescendant = (nextActive: HTMLElement | undefined) => {
+ const active = getActiveDescendant();
+ if (active) {
+ active.removeAttribute(ACTIVEDESCENDANT_ATTRIBUTE);
+ }
+
+ if (nextActive) {
+ nextActive.setAttribute(ACTIVEDESCENDANT_ATTRIBUTE, '');
+ scrollActiveIntoView(nextActive);
+ activeParentRef.current?.setAttribute('aria-activedescendant', nextActive.id);
+ } else {
+ activeParentRef.current?.removeAttribute('aria-activedescendant');
+ }
+ };
+
+ React.useImperativeHandle(imperativeRef, () => ({
+ first: () => {
+ if (!listboxRef.current || !activeParentRef.current) {
+ return;
+ }
+
+ optionWalker.setCurrent(listboxRef.current);
+ const first = optionWalker.first();
+ if (first) {
+ setActiveDescendant(first);
+ }
+ },
+ next: () => {
+ if (!listboxRef.current || !activeParentRef.current) {
+ return;
+ }
+
+ const active = getActiveDescendant();
+ if (!active) {
+ return;
+ }
+
+ optionWalker.setCurrent(active);
+ const next = optionWalker.next();
+ if (next) {
+ setActiveDescendant(next);
+ }
+ },
+ prev: () => {
+ if (!listboxRef.current || !activeParentRef.current) {
+ return;
+ }
+
+ const active = getActiveDescendant();
+ if (!active) {
+ return;
+ }
+
+ optionWalker.setCurrent(active);
+ if (!matchOption(active)) {
+ optionWalker.prev();
+ }
+
+ const next = optionWalker.prev();
+
+ if (next && next !== listboxRef.current) {
+ setActiveDescendant(next);
+ }
+ },
+ blur: () => {
+ if (!activeParentRef.current) {
+ return;
+ }
+
+ setActiveDescendant(undefined);
+ },
+ active: () => {
+ if (listboxRef.current) {
+ return getActiveDescendant()?.id;
+ }
+ },
+
+ focus: (id: string) => {
+ if (!listboxRef.current) {
+ return;
+ }
+
+ optionWalker.setCurrent(listboxRef.current);
+ let cur = optionWalker.next();
+
+ while (cur && cur.id !== id) {
+ cur = optionWalker.next();
+ }
+
+ if (cur) {
+ setActiveDescendant(cur);
+ }
+ },
+ }));
+
+ return { listboxRef, activeParentRef };
+}
diff --git a/packages/react-components/react-components/stories/ContentEditableTags/utils/useCaretManipulation.ts b/packages/react-components/react-components/stories/ContentEditableTags/utils/useCaretManipulation.ts
new file mode 100644
index 0000000000000..8e80dd5d64b48
--- /dev/null
+++ b/packages/react-components/react-components/stories/ContentEditableTags/utils/useCaretManipulation.ts
@@ -0,0 +1,129 @@
+import { useFluent } from '@fluentui/react-components';
+
+export const useCaretManipulation = () => {
+ const { targetDocument } = useFluent();
+
+ const getRange = (element: HTMLElement | null) => {
+ const win = targetDocument?.defaultView;
+ if (!win || element === null) {
+ return null;
+ }
+ const selection = win.getSelection();
+ if (!selection || selection.rangeCount === 0) {
+ return null;
+ }
+ const range = selection.getRangeAt(0);
+ return range;
+ };
+
+ const overrideLeftArrow = (element: HTMLElement | null) => {
+ const range = getRange(element);
+ if (range === null) {
+ return false;
+ }
+ const startContainer = range.startContainer;
+ const startOffset = range.startOffset;
+ const startParent = startContainer.parentNode as HTMLElement;
+ if (startParent?.classList.contains('pickedItem') && startOffset !== 0) {
+ // alert(range.startOffset);
+ // alert(range.endContainer.tkextContent);
+ range.setStart(startContainer, 0);
+ range.setEnd(range.endContainer, 0);
+ return true;
+ }
+ return false;
+ };
+
+ const overrideRightArrow = (element: HTMLElement | null) => {
+ const range = getRange(element);
+ if (range === null) {
+ return false;
+ }
+ const endContainer = range.endContainer;
+ const startOffset = range.startOffset;
+ const endOffset = range.endOffset;
+ const endParent = endContainer.parentNode as HTMLElement;
+ const endContainerRange = range.cloneRange();
+ endContainerRange.selectNodeContents(endContainer);
+ const endContainerNextSibling = endContainer.nextSibling as HTMLElement;
+ const isTextEndRightBeforeItem =
+ endContainerNextSibling &&
+ endParent?.classList.contains('pickerInput') &&
+ endOffset === endContainerRange.endOffset;
+ if (isTextEndRightBeforeItem) {
+ const endContainerNextSiblingText = endContainerNextSibling.firstChild as ChildNode;
+ const endContainreNextSiblingRange = range.cloneRange();
+ endContainreNextSiblingRange.selectNodeContents(endContainerNextSiblingText);
+ range.setEnd(endContainreNextSiblingRange.endContainer, endContainreNextSiblingRange.endOffset);
+ return true;
+ }
+ const endParentNextSibling = endParent.nextSibling as HTMLElement;
+ const endParentNextSiblingText = endParentNextSibling.firstChild as ChildNode;
+ const isItemEndRightBeforeItem =
+ startOffset === endOffset &&
+ endOffset === endContainerRange.endOffset &&
+ endParent.classList.contains('pickedItem') &&
+ endParentNextSibling.classList.contains('pickedItem');
+ if (isItemEndRightBeforeItem) {
+ const endParentNextSiblingRange = range.cloneRange();
+ endParentNextSiblingRange.selectNodeContents(endParentNextSiblingText);
+ // alert(endParentNextSiblingRange.endOffset);
+ range.setEnd(endParentNextSiblingRange.endContainer, endParentNextSiblingRange.endOffset);
+ return true;
+ }
+ endContainerRange.selectNodeContents(endContainer);
+ const isEndInsideItem = endParent?.classList.contains('pickedItem') && endOffset < endContainerRange.endOffset;
+ if (isEndInsideItem) {
+ range.selectNodeContents(endContainer);
+ return true;
+ }
+ };
+
+ const moveCaretFromItem = (element: HTMLElement | null) => {
+ const range = getRange(element);
+ if (range === null) {
+ return;
+ }
+ const startContainer = range.startContainer;
+ const startOffset = range.startOffset;
+ const startParent = startContainer.parentNode as HTMLElement;
+ // const startContainerRange = range.cloneRange();
+ // startContainerRange.selectNodeContents(startContainer);
+ // const isAtItemEnd = startParent?.classList.contains('pickedItem') && startOffset === startContainerRange.endOffset;
+ const isAtItemStart = startParent?.classList.contains('pickedItem') && startOffset === 0;
+ if (isAtItemStart) {
+ let prevSibling = startParent.previousSibling;
+ if (prevSibling === null || prevSibling.nodeType !== Node.TEXT_NODE) {
+ prevSibling = targetDocument?.createTextNode('X') as Text;
+ startParent.parentNode?.insertBefore(prevSibling, startParent);
+ }
+ const newPosition = prevSibling.toString().length;
+ // range.setStart(prevSibling, newPosition);
+ range.setStart(prevSibling, 0);
+ range.setEnd(prevSibling, newPosition);
+ }
+ };
+
+ const getCaretPosition = (element: HTMLElement) => {
+ const win = targetDocument?.defaultView;
+ if (!win) {
+ return 0;
+ }
+ const sel = win.getSelection();
+ if (!sel || sel.rangeCount === 0) {
+ return 0;
+ }
+ const range = sel.getRangeAt(0);
+ const preCaretRange = range.cloneRange();
+ preCaretRange.selectNodeContents(element);
+ preCaretRange.setEnd(range.endContainer, range.endOffset);
+ const caretOffset = preCaretRange.toString().length;
+ return caretOffset;
+ };
+ return {
+ overrideLeftArrow,
+ overrideRightArrow,
+ moveCaretFromItem,
+ getCaretPosition,
+ };
+};
diff --git a/packages/react-components/react-components/stories/ContentEditableTags/utils/useOptionWalker.ts b/packages/react-components/react-components/stories/ContentEditableTags/utils/useOptionWalker.ts
new file mode 100644
index 0000000000000..7e528ff54746b
--- /dev/null
+++ b/packages/react-components/react-components/stories/ContentEditableTags/utils/useOptionWalker.ts
@@ -0,0 +1,72 @@
+import * as React from 'react';
+import { useFluent_unstable as useFluent } from '@fluentui/react-shared-contexts';
+import { isHTMLElement, useIsomorphicLayoutEffect } from '@fluentui/react-utilities';
+
+interface UseOptionWalkerOptions {
+ matchOption: (el: HTMLElement) => boolean;
+}
+
+export function useOptionWalker(options: UseOptionWalkerOptions) {
+ const { matchOption } = options;
+ const { targetDocument } = useFluent();
+ const treeWalkerRef = React.useRef(null);
+ const listboxRef = React.useRef(null);
+
+ const optionFilter = React.useCallback(
+ (node: Node) => {
+ if (isHTMLElement(node) && matchOption(node)) {
+ return NodeFilter.FILTER_ACCEPT;
+ }
+
+ return NodeFilter.FILTER_SKIP;
+ },
+ [matchOption],
+ );
+
+ useIsomorphicLayoutEffect(() => {
+ if (!targetDocument || !listboxRef.current) {
+ return;
+ }
+
+ treeWalkerRef.current = targetDocument.createTreeWalker(listboxRef.current, NodeFilter.SHOW_ELEMENT, optionFilter);
+ }, [targetDocument, optionFilter]);
+
+ const optionWalker = React.useMemo(
+ () => ({
+ first: () => {
+ if (!treeWalkerRef.current) {
+ return null;
+ }
+
+ return treeWalkerRef.current.firstChild() as HTMLElement | null;
+ },
+ next: () => {
+ if (!treeWalkerRef.current) {
+ return null;
+ }
+
+ return treeWalkerRef.current.nextNode() as HTMLElement | null;
+ },
+ prev: () => {
+ if (!treeWalkerRef.current) {
+ return null;
+ }
+
+ return treeWalkerRef.current.previousNode() as HTMLElement | null;
+ },
+ setCurrent: (el: HTMLElement) => {
+ if (!treeWalkerRef.current) {
+ return;
+ }
+
+ treeWalkerRef.current.currentNode = el;
+ },
+ }),
+ [],
+ );
+
+ return {
+ optionWalker,
+ listboxRef,
+ };
+}
diff --git a/packages/react-components/react-components/stories/ContentEditableTags/utils/utils.ts b/packages/react-components/react-components/stories/ContentEditableTags/utils/utils.ts
new file mode 100644
index 0000000000000..4b91f7400dd33
--- /dev/null
+++ b/packages/react-components/react-components/stories/ContentEditableTags/utils/utils.ts
@@ -0,0 +1,8 @@
+export const isKeyCharacter = event => {
+ const isNumeric = typeof event.which === 'number' && event.which > 0 && event.which !== 8;
+ const isModifier = event.key.length > 1 || event.ctrlKey || event.metaKey || event.altKey;
+ if (isNumeric && !isModifier) {
+ return true;
+ }
+ return false;
+};
diff --git a/yarn.lock b/yarn.lock
index b127c1f3db60f..deeb0863b8af4 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -2416,6 +2416,207 @@
resolved "https://registry.yarnpkg.com/@leichtgewicht/ip-codec/-/ip-codec-2.0.4.tgz#b2ac626d6cb9c8718ab459166d4bb405b8ffa78b"
integrity sha512-Hcv+nVC0kZnQ3tD9GVu5xSMR4VVYOteQIr/hwFPVEvPdlXqgGEuRjiheChHgdM+JyqdgNcmzZOX/tnl0JOiI7A==
+"@lexical/clipboard@0.15.0":
+ version "0.15.0"
+ resolved "https://registry.yarnpkg.com/@lexical/clipboard/-/clipboard-0.15.0.tgz#1a8bf8dde44f65658182b5573bfe3cf57bcad585"
+ integrity sha512-binCltK7KiURQJFogvueYfmDNEKynN/lmZrCLFp2xBjEIajqw4WtOVLJZ33engdqNlvj0JqrxrWxbKG+yvUwrg==
+ dependencies:
+ "@lexical/html" "0.15.0"
+ "@lexical/list" "0.15.0"
+ "@lexical/selection" "0.15.0"
+ "@lexical/utils" "0.15.0"
+ lexical "0.15.0"
+
+"@lexical/code@0.15.0":
+ version "0.15.0"
+ resolved "https://registry.yarnpkg.com/@lexical/code/-/code-0.15.0.tgz#aee697f652528455c3782aa1d029f068e4314e58"
+ integrity sha512-n185gjinGhz/M4BW1ayNPYAEgwW4T/NEFl2Wey/O+07W3zvh9k9ai7RjWd0c8Qzqc4DLlqvibvWPebWObQHA4w==
+ dependencies:
+ "@lexical/utils" "0.15.0"
+ lexical "0.15.0"
+ prismjs "^1.27.0"
+
+"@lexical/devtools-core@0.15.0":
+ version "0.15.0"
+ resolved "https://registry.yarnpkg.com/@lexical/devtools-core/-/devtools-core-0.15.0.tgz#99512a860e07c88f3d9da66458da6878fe890609"
+ integrity sha512-kK/IVEiQyqs2DsY4QRYFaFiKQMpaAukAl8PXmNeGTZ7cfFVsP29E4n0/pjY+oxmiRvxbO1s2i14q58nfuhj4VQ==
+ dependencies:
+ "@lexical/html" "0.15.0"
+ "@lexical/link" "0.15.0"
+ "@lexical/mark" "0.15.0"
+ "@lexical/table" "0.15.0"
+ "@lexical/utils" "0.15.0"
+ lexical "0.15.0"
+
+"@lexical/dragon@0.15.0":
+ version "0.15.0"
+ resolved "https://registry.yarnpkg.com/@lexical/dragon/-/dragon-0.15.0.tgz#d6c4f56c4cec4583460cfc2f32af8425ac21b0d5"
+ integrity sha512-hg2rGmxVJF7wmN6psuKw3EyhcNF7DtOYwUCBpjFZVshzAjsNEBfEnqhiMkSVSlN4+WOfM7LS+B88PTKPcnFGbQ==
+ dependencies:
+ lexical "0.15.0"
+
+"@lexical/hashtag@0.15.0":
+ version "0.15.0"
+ resolved "https://registry.yarnpkg.com/@lexical/hashtag/-/hashtag-0.15.0.tgz#6edc0d6c0fe124baabc8eecbdc768bd6a91fe491"
+ integrity sha512-EP6KKvS6BY/8Vh1MLQYeOcYaxnvrLsUkvXXr+Fg8N477Us54Ju69pPO563mbWt7/bpnL9Sh0fbk82JtxqPWpSg==
+ dependencies:
+ "@lexical/utils" "0.15.0"
+ lexical "0.15.0"
+
+"@lexical/history@0.15.0":
+ version "0.15.0"
+ resolved "https://registry.yarnpkg.com/@lexical/history/-/history-0.15.0.tgz#7d32d09c3ccf153ac212dc653ccf04deb220b5e6"
+ integrity sha512-r+pzR2k/51AL6l8UfXeVe/GWPIeWY1kEOuKx9nsYB9tmAkTF66tTFz33DJIMWBVtAHWN7Dcdv0/yy6q8R6CAUQ==
+ dependencies:
+ "@lexical/utils" "0.15.0"
+ lexical "0.15.0"
+
+"@lexical/html@0.15.0":
+ version "0.15.0"
+ resolved "https://registry.yarnpkg.com/@lexical/html/-/html-0.15.0.tgz#f616b831efafe77c597ca7ddc5bac4ec69de69c9"
+ integrity sha512-x/sfGvibwo8b5Vso4ppqNyS/fVve6Rn+TmvP/0eWOaa0I3aOQ57ulfcK6p/GTe+ZaEi8vW64oZPdi8XDgwSRaA==
+ dependencies:
+ "@lexical/selection" "0.15.0"
+ "@lexical/utils" "0.15.0"
+ lexical "0.15.0"
+
+"@lexical/link@0.15.0":
+ version "0.15.0"
+ resolved "https://registry.yarnpkg.com/@lexical/link/-/link-0.15.0.tgz#601a49cdd91d87fba07828ad2c492e2c4d52b579"
+ integrity sha512-KBV/zWk5FxqZGNcq3IKGBDCcS4t0uteU1osAIG+pefo4waTkOOgibxxEJDop2QR5wtjkYva3Qp0D8ZyJDMMMlw==
+ dependencies:
+ "@lexical/utils" "0.15.0"
+ lexical "0.15.0"
+
+"@lexical/list@0.15.0":
+ version "0.15.0"
+ resolved "https://registry.yarnpkg.com/@lexical/list/-/list-0.15.0.tgz#f1b073f2ca04816b12dda4d6ceef97bb5e286a8c"
+ integrity sha512-JuF4k7uo4rZFOSZGrmkxo1+sUrwTKNBhhJAiCgtM+6TO90jppxzCFNKur81yPzF1+g4GWLC9gbjzKb52QPb6cQ==
+ dependencies:
+ "@lexical/utils" "0.15.0"
+ lexical "0.15.0"
+
+"@lexical/mark@0.15.0":
+ version "0.15.0"
+ resolved "https://registry.yarnpkg.com/@lexical/mark/-/mark-0.15.0.tgz#8eb61379bdf599daea07af50ea2c65163d47fc20"
+ integrity sha512-cdePA98sOJRc4/HHqcOcPBFq4UDwzaFJOK1N1E6XUGcXH1GU8zHtV1ElTgmbsGkyjBRwhR+OqKm9eso1PBOUkg==
+ dependencies:
+ "@lexical/utils" "0.15.0"
+ lexical "0.15.0"
+
+"@lexical/markdown@0.15.0":
+ version "0.15.0"
+ resolved "https://registry.yarnpkg.com/@lexical/markdown/-/markdown-0.15.0.tgz#1e41dcbd03d18092ea57c8dfe6b1219acdadb87d"
+ integrity sha512-wu1EP758l452BovDa7i9ZAeWuFj+YY0bc2mNc08nfZ9GqdGMej1JIguY4CwIROCYVizprL9Ocn0avH1uv9b8fA==
+ dependencies:
+ "@lexical/code" "0.15.0"
+ "@lexical/link" "0.15.0"
+ "@lexical/list" "0.15.0"
+ "@lexical/rich-text" "0.15.0"
+ "@lexical/text" "0.15.0"
+ "@lexical/utils" "0.15.0"
+ lexical "0.15.0"
+
+"@lexical/offset@0.15.0":
+ version "0.15.0"
+ resolved "https://registry.yarnpkg.com/@lexical/offset/-/offset-0.15.0.tgz#f21d78cb70ab2470bb9a0fa9194a403504a4362e"
+ integrity sha512-VO1f3m8+RRdRjuXMtCBhi1COVKRC2LhP8AFYxnFlvbV+Waz9R5xB9pqFFUe4RtyqyTLmOUj6+LtsUFhq+23voQ==
+ dependencies:
+ lexical "0.15.0"
+
+"@lexical/overflow@0.15.0":
+ version "0.15.0"
+ resolved "https://registry.yarnpkg.com/@lexical/overflow/-/overflow-0.15.0.tgz#f3ad45dd7eec2d94d07251bc0a879f8942ae4dea"
+ integrity sha512-9qKVCvh9Oka+bzR3th+UWdTEeMZXYy1ZxWbjSxefRMgQxzCvqSuVioK/065gPbvGga9EfvgLLLBDXZm8ISbJQA==
+ dependencies:
+ lexical "0.15.0"
+
+"@lexical/plain-text@0.15.0":
+ version "0.15.0"
+ resolved "https://registry.yarnpkg.com/@lexical/plain-text/-/plain-text-0.15.0.tgz#3d5b1d929e7d65698c6886224794664f52fe3952"
+ integrity sha512-yeK466mXb4xaCCJouGzEHQs59fScHxF8Asq0azNyJmkhQWYrU7WdckHf2xj8ItZFFPyj7lvwKRDYnoy4HQD7Mg==
+ dependencies:
+ "@lexical/clipboard" "0.15.0"
+ "@lexical/selection" "0.15.0"
+ "@lexical/utils" "0.15.0"
+ lexical "0.15.0"
+
+"@lexical/react@^0.15.0":
+ version "0.15.0"
+ resolved "https://registry.yarnpkg.com/@lexical/react/-/react-0.15.0.tgz#b1f469239e77b4ac2e917cab3d5d13bb6f433efa"
+ integrity sha512-TWDp/F9cKwjGreLzIdHKlPUeTn275rR6j1VXrBffNwC5ovxWcKLVRg502eY5xvRQH3lkKQpFgIFbJW4KTvhFsQ==
+ dependencies:
+ "@lexical/clipboard" "0.15.0"
+ "@lexical/code" "0.15.0"
+ "@lexical/devtools-core" "0.15.0"
+ "@lexical/dragon" "0.15.0"
+ "@lexical/hashtag" "0.15.0"
+ "@lexical/history" "0.15.0"
+ "@lexical/link" "0.15.0"
+ "@lexical/list" "0.15.0"
+ "@lexical/mark" "0.15.0"
+ "@lexical/markdown" "0.15.0"
+ "@lexical/overflow" "0.15.0"
+ "@lexical/plain-text" "0.15.0"
+ "@lexical/rich-text" "0.15.0"
+ "@lexical/selection" "0.15.0"
+ "@lexical/table" "0.15.0"
+ "@lexical/text" "0.15.0"
+ "@lexical/utils" "0.15.0"
+ "@lexical/yjs" "0.15.0"
+ lexical "0.15.0"
+ react-error-boundary "^3.1.4"
+
+"@lexical/rich-text@0.15.0":
+ version "0.15.0"
+ resolved "https://registry.yarnpkg.com/@lexical/rich-text/-/rich-text-0.15.0.tgz#b587f9ffe853800227d1c22841ae6ac3a71bb675"
+ integrity sha512-76tXh/eeEOHl91HpFEXCc/tUiLrsa9RcSyvCzRZahk5zqYvQPXma/AUfRzuSMf2kLwDEoauKAVqNFQcbPhqwpQ==
+ dependencies:
+ "@lexical/clipboard" "0.15.0"
+ "@lexical/selection" "0.15.0"
+ "@lexical/utils" "0.15.0"
+ lexical "0.15.0"
+
+"@lexical/selection@0.15.0":
+ version "0.15.0"
+ resolved "https://registry.yarnpkg.com/@lexical/selection/-/selection-0.15.0.tgz#e8675e701b8a66af35e20cbe945d7b99941341cd"
+ integrity sha512-S+AQC6eJiQYSa5zOPuecN85prCT0Bcb8miOdJaE17Zh+vgdUH5gk9I0tEBeG5T7tkSpq6lFiEqs2FZSfaHflbQ==
+ dependencies:
+ lexical "0.15.0"
+
+"@lexical/table@0.15.0":
+ version "0.15.0"
+ resolved "https://registry.yarnpkg.com/@lexical/table/-/table-0.15.0.tgz#7b44863a42fc0ff193c2d3da4065217e4e63df2b"
+ integrity sha512-3IRBg8IoIHetqKozRQbJQ2aPyG0ziXZ+lc8TOIAGs6METW/wxntaV+rTNrODanKAgvk2iJTIyfFkYjsqS9+VFg==
+ dependencies:
+ "@lexical/utils" "0.15.0"
+ lexical "0.15.0"
+
+"@lexical/text@0.15.0":
+ version "0.15.0"
+ resolved "https://registry.yarnpkg.com/@lexical/text/-/text-0.15.0.tgz#091f86150eeb6bef02bf6440a6c626c977344adf"
+ integrity sha512-WsAkAt9T1RH1iDrVuWeoRUeMCOAWar5oSFtnQ4m9vhT/zuf5b8efK87GiqCH00ZAn4DGzOuAfyXlMFqBVCQdkQ==
+ dependencies:
+ lexical "0.15.0"
+
+"@lexical/utils@0.15.0":
+ version "0.15.0"
+ resolved "https://registry.yarnpkg.com/@lexical/utils/-/utils-0.15.0.tgz#bc92b5dd1f3805dfe89479ff13508d8ad498d52e"
+ integrity sha512-/6954LDmTcVFgexhy5WOZDa4TxNQOEZNrf8z7TRAFiAQkihcME/GRoq1en5cbXoVNF8jv5AvNyyc7x0MByRJ6A==
+ dependencies:
+ "@lexical/list" "0.15.0"
+ "@lexical/selection" "0.15.0"
+ "@lexical/table" "0.15.0"
+ lexical "0.15.0"
+
+"@lexical/yjs@0.15.0":
+ version "0.15.0"
+ resolved "https://registry.yarnpkg.com/@lexical/yjs/-/yjs-0.15.0.tgz#b3a5b75e6df68980763c5a88f5093ee0fc35f3c7"
+ integrity sha512-Rf4AIu620Cq90li6GU58gkzlGRdntHP4ZeZrbJ3ToW7vEEnkW6Wl9/HhO647GG4OL5w46M0iWvx1b1b8xjYT1w==
+ dependencies:
+ "@lexical/offset" "0.15.0"
+ lexical "0.15.0"
+
"@linaria/babel-preset@^3.0.0-beta.22", "@linaria/babel-preset@^3.0.0-beta.24":
version "3.0.0-beta.24"
resolved "https://registry.yarnpkg.com/@linaria/babel-preset/-/babel-preset-3.0.0-beta.24.tgz#921b396afc37ebb5df84b8a02d37a56ea49cb54b"
@@ -16345,6 +16546,11 @@ levn@^0.4.1:
prelude-ls "^1.2.1"
type-check "~0.4.0"
+lexical@0.15.0, lexical@^0.15.0:
+ version "0.15.0"
+ resolved "https://registry.yarnpkg.com/lexical/-/lexical-0.15.0.tgz#1c471d7e4ad7140830bbb4cd244c4e65cfce3794"
+ integrity sha512-/7HrPAmtgsc1F+qpv5bFwoQZ6CbH/w3mPPL2AW5P75/QYrqKz4bhvJrc2jozIX0GxtuT/YUYT7w+1sZMtUWbOg==
+
li@^1.3.0:
version "1.3.0"
resolved "https://registry.yarnpkg.com/li/-/li-1.3.0.tgz#22c59bcaefaa9a8ef359cf759784e4bf106aea1b"
@@ -19317,7 +19523,12 @@ prettyjson@^1.2.1:
colors "1.4.0"
minimist "^1.2.0"
-prismjs@^1.16.0, prismjs@^1.8.4, prismjs@~1.16.0:
+prismjs@^1.16.0, prismjs@^1.27.0, prismjs@^1.8.4:
+ version "1.29.0"
+ resolved "https://registry.yarnpkg.com/prismjs/-/prismjs-1.29.0.tgz#f113555a8fa9b57c35e637bba27509dcf802dd12"
+ integrity sha512-Kx/1w86q/epKcmte75LNrEoT+lX8pBpavuAbvJWRXar7Hz8jrtF+e3vY751p0R8H9HdArwaCTNDDzHg/ScJK1Q==
+
+prismjs@~1.16.0:
version "1.16.0"
resolved "https://registry.yarnpkg.com/prismjs/-/prismjs-1.16.0.tgz#406eb2c8aacb0f5f0f1167930cb83835d10a4308"
integrity sha512-OA4MKxjFZHSvZcisLGe14THYsug/nF6O1f0pAJc0KN0wTyAcLqmsbE+lTGKSpyh+9pEW57+k6pg2AfYR+coyHA==
@@ -19787,10 +19998,10 @@ react-element-to-jsx-string@^14.0.2, react-element-to-jsx-string@^14.3.4:
is-plain-object "5.0.0"
react-is "17.0.2"
-react-error-boundary@^3.1.0:
- version "3.1.0"
- resolved "https://registry.yarnpkg.com/react-error-boundary/-/react-error-boundary-3.1.0.tgz#9487443df2f9ba1db90d8ab52351814907ea4af3"
- integrity sha512-lmPrdi5SLRJR+AeJkqdkGlW/CRkAUvZnETahK58J4xb5wpbfDngasEGu+w0T1iXEhVrYBJZeW+c4V1hILCnMWQ==
+react-error-boundary@^3.1.0, react-error-boundary@^3.1.4:
+ version "3.1.4"
+ resolved "https://registry.yarnpkg.com/react-error-boundary/-/react-error-boundary-3.1.4.tgz#255db92b23197108757a888b01e5b729919abde0"
+ integrity sha512-uM9uPzZJTF6wRQORmSrvOIgt4lJ9MC1sNgEOj2XGsDTRE4kmpWxg7ENK9EWNKJRMAOY9z0MuF4yIfl6gp4sotA==
dependencies:
"@babel/runtime" "^7.12.5"