Compare commits

..

58 Commits

Author SHA1 Message Date
zsviczian
b8ae1d2486 setActiveTool - do not clear selectedElementIds so customData of image can be used & do not render when deferredText is empty 2023-09-26 21:37:13 +02:00
zsviczian
482178b7b6 lint 2023-09-24 19:24:04 +02:00
zsviczian
7da500fe0a store mermaid text in customData of image element 2023-09-24 19:14:49 +02:00
Aakansha Doshi
b1d923db3a use common utils to update and get text editor 2023-09-22 18:59:22 +05:30
Aakansha Doshi
7f6789780d Add tests 2023-09-22 18:55:48 +05:30
Aakansha Doshi
17accffee3 enable test coverage in ui 2023-09-22 18:55:29 +05:30
Aakansha Doshi
e1b0b559f5 better api 2023-09-22 11:22:39 +05:30
Aakansha Doshi
8654958aba use i18n 2023-09-21 18:18:44 +05:30
Aakansha Doshi
7c1889efc0 fix width of shapes toolbar for smaller screen size and also fix regression of mobile menu 2023-09-21 17:45:08 +05:30
Aakansha Doshi
b3e8d6bbf0 upgrade mermaid-to-excalidraw 2023-09-21 12:47:44 +05:30
Aakansha Doshi
26481fbf43 Merge remote-tracking branch 'origin/master' into aakansha-mermaid 2023-09-21 12:34:47 +05:30
Aakansha Doshi
b7a4dfb6ef use stable version of mermaid-to-excalidraw 2023-09-13 21:09:19 +05:30
Aakansha Doshi
8a153b822a Merge remote-tracking branch 'origin/master' into aakansha-mermaid 2023-09-13 21:08:50 +05:30
Aakansha Doshi
57da3768b1 upgrade mermaid-to-excalidraw 2023-09-13 20:12:11 +05:30
Aakansha Doshi
db163ab89c use types from mermaid-to-excalidraw 2023-09-07 13:40:06 +05:30
Aakansha Doshi
3593cf6a14 upgrade mermaid-to-excalidraw to fix firefox issue 2023-09-07 12:02:33 +05:30
Aakansha Doshi
ce6a9986e3 don't pass appState in deps as its not used 2023-09-06 19:43:02 +05:30
Aakansha Doshi
c95369ace8 upgrade mermaid-to-excalidraw 2023-09-06 11:23:07 +05:30
Aakansha Doshi
a8283b27c5 width auto 2023-09-05 11:25:46 +05:30
Aakansha Doshi
3ea7c7ffa0 fix mobile css 2023-09-05 11:01:19 +05:30
Aakansha Doshi
beb2ceaa72 fix: show extra tools dropdown in mobile 2023-09-05 10:32:51 +05:30
Aakansha Doshi
0d49eb3e05 make design responsive 2023-09-04 13:59:47 +05:30
Aakansha Doshi
de0f35454a remove only 2023-09-04 13:22:06 +05:30
Aakansha Doshi
d393a1c048 Merge remote-tracking branch 'origin/master' into aakansha-mermaid 2023-09-04 13:15:24 +05:30
Aakansha Doshi
23fa44cf5e fix tests 2023-09-04 13:09:35 +05:30
Aakansha Doshi
9d22e84fc8 tweak text 2023-09-04 10:42:05 +05:30
Aakansha Doshi
aa6b585b96 defer rendering the preview 2023-09-04 09:05:22 +05:30
Aakansha Doshi
06389f96b9 fix: Update start/end points by 0.5 so bindings don't overlap with start/end bound element coordinates. 2023-09-04 08:49:50 +05:30
dwelle
9b1c88eed9 fix elements insert position and viewport centering 2023-09-01 14:49:26 +02:00
Aakansha Doshi
d070760b2f fix arrow bindings in safari and firefox 2023-08-31 21:05:44 +05:30
Aakansha Doshi
acd6db5304 make opts optional and use 100% zoom when inserting to canvas 2023-08-31 13:34:28 +05:30
Aakansha Doshi
d203794f70 add option to transform viewport to scene coords in transform api 2023-08-31 11:08:10 +05:30
Aakansha Doshi
c8fd157914 tweak 2023-08-30 20:32:56 +05:30
Aakansha Doshi
b47d46699a regenerate ids when needed via programmatic api, this makes sure for mermaid diagrams ids are regenerated 2023-08-30 20:28:13 +05:30
Aakansha Doshi
10a5d18fa2 show a spinner unless mermaid loaded 2023-08-30 14:14:24 +05:30
Aakansha Doshi
b1bd94c377 tweak design to remove scroll bar 2023-08-30 13:57:49 +05:30
Aakansha Doshi
e4e2e044af fix 2023-08-30 13:29:52 +05:30
Aakansha Doshi
d3db48e8f4 add example and docs link 2023-08-30 13:21:32 +05:30
Aakansha Doshi
cef0f15158 design tweaks 2023-08-30 13:02:13 +05:30
Aakansha Doshi
742e4bc017 show mermaid error messgae react way 2023-08-30 08:58:27 +05:30
Aakansha Doshi
a573fbbb5a show error in preview when error 2023-08-29 22:06:45 +05:30
Aakansha Doshi
f696d36e03 reset preview when error 2023-08-29 21:59:46 +05:30
Aakansha Doshi
21a804a4e5 add a note in dialog 2023-08-29 21:36:13 +05:30
Aakansha Doshi
c313a2cf42 add mermaid icon in dropdown 2023-08-29 21:20:08 +05:30
Aakansha Doshi
6b33ba1d04 fix undefined vertex issue 2023-08-29 16:56:57 +05:30
Aakansha Doshi
fe9f89a0fc compute width, height correctly for arrows 2023-08-29 12:49:49 +05:30
Aakansha Doshi
d1266280cb tweak design 2023-08-25 15:44:22 +05:30
Aakansha Doshi
41a0258fe1 load mermaid lazily 2023-08-24 13:43:41 +05:30
Aakansha Doshi
3346c72356 store canvas data in refs 2023-08-24 12:50:03 +05:30
Aakansha Doshi
6518e05cab persist mermaid data to storage 2023-08-24 12:29:33 +05:30
Aakansha Doshi
f85f890b25 set elements as selected when inserted onto canvas 2023-08-23 16:24:37 +05:30
Aakansha Doshi
7b612bec5e center preview 2023-08-23 14:43:27 +05:30
Aakansha Doshi
efdafc8659 fix markdown error by using named export 2023-08-22 21:40:25 +05:30
Aakansha Doshi
554913c58b fix webpack config 2023-08-21 21:31:53 +05:30
Aakansha Doshi
84059086a6 fix 2023-08-21 21:09:42 +05:30
Aakansha Doshi
fec984895e allow mermaid syntax and export in preview 2023-08-21 20:52:01 +05:30
Aakansha Doshi
c5514974b7 create mermaid to excal dialog 2023-08-17 14:12:57 +05:30
Aakansha Doshi
6a04ebc6db feat: integrate mermaidToExcalidraw 2023-08-17 12:24:00 +05:30
31 changed files with 1692 additions and 273 deletions

View File

@@ -131,5 +131,5 @@ export class Debug {
}; };
}; };
} }
//@ts-ignore
window.debug = Debug; window.debug = Debug;

View File

@@ -20,6 +20,7 @@
}, },
"dependencies": { "dependencies": {
"@braintree/sanitize-url": "6.0.2", "@braintree/sanitize-url": "6.0.2",
"@excalidraw/mermaid-to-excalidraw": "0.1.1",
"@excalidraw/random-username": "1.0.0", "@excalidraw/random-username": "1.0.0",
"@radix-ui/react-popover": "1.0.3", "@radix-ui/react-popover": "1.0.3",
"@radix-ui/react-tabs": "1.0.2", "@radix-ui/react-tabs": "1.0.2",
@@ -124,7 +125,7 @@
"test": "yarn test:app", "test": "yarn test:app",
"test:coverage": "vitest --coverage", "test:coverage": "vitest --coverage",
"test:coverage:watch": "vitest --coverage --watch", "test:coverage:watch": "vitest --coverage --watch",
"test:ui": "yarn test --ui", "test:ui": "yarn test --ui --coverage.enabled=true",
"autorelease": "node scripts/autorelease.js", "autorelease": "node scripts/autorelease.js",
"prerelease": "node scripts/prerelease.js", "prerelease": "node scripts/prerelease.js",
"build:preview": "yarn build && vite preview --port 5000", "build:preview": "yarn build && vite preview --port 5000",

View File

@@ -36,7 +36,12 @@ import {
import "./Actions.scss"; import "./Actions.scss";
import DropdownMenu from "./dropdownMenu/DropdownMenu"; import DropdownMenu from "./dropdownMenu/DropdownMenu";
import { EmbedIcon, extraToolsIcon, frameToolIcon } from "./icons"; import {
EmbedIcon,
extraToolsIcon,
frameToolIcon,
mermaidLogoIcon,
} from "./icons";
import { KEYS } from "../keys"; import { KEYS } from "../keys";
export const SelectedShapeActions = ({ export const SelectedShapeActions = ({
@@ -226,7 +231,6 @@ export const ShapesSwitcher = ({
appState: UIAppState; appState: UIAppState;
}) => { }) => {
const [isExtraToolsMenuOpen, setIsExtraToolsMenuOpen] = useState(false); const [isExtraToolsMenuOpen, setIsExtraToolsMenuOpen] = useState(false);
const device = useDevice();
return ( return (
<> <>
{SHAPES.map(({ value, icon, key, numericKey, fillable }, index) => { {SHAPES.map(({ value, icon, key, numericKey, fillable }, index) => {
@@ -282,75 +286,7 @@ export const ShapesSwitcher = ({
); );
})} })}
<div className="App-toolbar__divider" /> <div className="App-toolbar__divider" />
{/* TEMP HACK because dropdown doesn't work well inside mobile toolbar */}
{device.isMobile ? (
<>
<ToolButton
className={clsx("Shape", { fillable: false })}
type="radio"
icon={frameToolIcon}
checked={activeTool.type === "frame"}
name="editor-current-shape"
title={`${capitalizeString(
t("toolBar.frame"),
)}${KEYS.F.toLocaleUpperCase()}`}
keyBindingLabel={KEYS.F.toLocaleUpperCase()}
aria-label={capitalizeString(t("toolBar.frame"))}
aria-keyshortcuts={KEYS.F.toLocaleUpperCase()}
data-testid={`toolbar-frame`}
onPointerDown={({ pointerType }) => {
if (!appState.penDetected && pointerType === "pen") {
setAppState({
penDetected: true,
penMode: true,
});
}
}}
onChange={({ pointerType }) => {
trackEvent("toolbar", "frame", "ui");
const nextActiveTool = updateActiveTool(appState, {
type: "frame",
});
setAppState({
activeTool: nextActiveTool,
multiElement: null,
selectedElementIds: {},
activeEmbeddable: null,
});
}}
/>
<ToolButton
className={clsx("Shape", { fillable: false })}
type="radio"
icon={EmbedIcon}
checked={activeTool.type === "embeddable"}
name="editor-current-shape"
title={capitalizeString(t("toolBar.embeddable"))}
aria-label={capitalizeString(t("toolBar.embeddable"))}
data-testid={`toolbar-embeddable`}
onPointerDown={({ pointerType }) => {
if (!appState.penDetected && pointerType === "pen") {
setAppState({
penDetected: true,
penMode: true,
});
}
}}
onChange={({ pointerType }) => {
trackEvent("toolbar", "embeddable", "ui");
const nextActiveTool = updateActiveTool(appState, {
type: "embeddable",
});
setAppState({
activeTool: nextActiveTool,
multiElement: null,
selectedElementIds: {},
activeEmbeddable: null,
});
}}
/>
</>
) : (
<DropdownMenu open={isExtraToolsMenuOpen}> <DropdownMenu open={isExtraToolsMenuOpen}>
<DropdownMenu.Trigger <DropdownMenu.Trigger
className="App-toolbar__extra-tools-trigger" className="App-toolbar__extra-tools-trigger"
@@ -397,9 +333,23 @@ export const ShapesSwitcher = ({
> >
{t("toolBar.embeddable")} {t("toolBar.embeddable")}
</DropdownMenu.Item> </DropdownMenu.Item>
<DropdownMenu.Item
onSelect={() => {
const nextActiveTool = updateActiveTool(appState, {
type: "mermaid",
});
setAppState({
activeTool: nextActiveTool,
multiElement: null,
});
}}
icon={mermaidLogoIcon}
data-testid="toolbar-embeddable"
>
{t("toolBar.mermaidToExcalidraw")}
</DropdownMenu.Item>
</DropdownMenu.Content> </DropdownMenu.Content>
</DropdownMenu> </DropdownMenu>
)}
</> </>
); );
}; };

View File

@@ -354,6 +354,7 @@ import { isSidebarDockedAtom } from "./Sidebar/Sidebar";
import { StaticCanvas, InteractiveCanvas } from "./canvases"; import { StaticCanvas, InteractiveCanvas } from "./canvases";
import { Renderer } from "../scene/Renderer"; import { Renderer } from "../scene/Renderer";
import { ShapeCache } from "../scene/ShapeCache"; import { ShapeCache } from "../scene/ShapeCache";
import MermaidToExcalidraw from "./MermaidToExcalidraw";
const AppContext = React.createContext<AppClassProperties>(null!); const AppContext = React.createContext<AppClassProperties>(null!);
const AppPropsContext = React.createContext<AppProps>(null!); const AppPropsContext = React.createContext<AppProps>(null!);
@@ -1086,7 +1087,7 @@ class App extends React.Component<AppProps, AppState> {
cursor: CURSOR_TYPE.MOVE, cursor: CURSOR_TYPE.MOVE,
pointerEvents: this.state.viewModeEnabled pointerEvents: this.state.viewModeEnabled
? POINTER_EVENTS.disabled ? POINTER_EVENTS.disabled
: POINTER_EVENTS.enabled, : POINTER_EVENTS.inheritFromUI,
}} }}
onPointerDown={(event) => this.handleCanvasPointerDown(event)} onPointerDown={(event) => this.handleCanvasPointerDown(event)}
onWheel={(event) => this.handleWheel(event)} onWheel={(event) => this.handleWheel(event)}
@@ -1190,7 +1191,15 @@ class App extends React.Component<AppProps, AppState> {
app={this} app={this}
> >
{this.props.children} {this.props.children}
{this.state.activeTool.type === "mermaid" && (
<MermaidToExcalidraw
selectedElements={this.scene.getSelectedElements(
this.state,
)}
/>
)}
</LayerUI> </LayerUI>
<div className="excalidraw-textEditorContainer" /> <div className="excalidraw-textEditorContainer" />
<div className="excalidraw-contextMenuContainer" /> <div className="excalidraw-contextMenuContainer" />
<div className="excalidraw-eye-dropper-container" /> <div className="excalidraw-eye-dropper-container" />
@@ -2253,11 +2262,12 @@ class App extends React.Component<AppProps, AppState> {
}, },
); );
private addElementsFromPasteOrLibrary = (opts: { addElementsFromPasteOrLibrary = (opts: {
elements: readonly ExcalidrawElement[]; elements: readonly ExcalidrawElement[];
files: BinaryFiles | null; files: BinaryFiles | null;
position: { clientX: number; clientY: number } | "cursor" | "center"; position: { clientX: number; clientY: number } | "cursor" | "center";
retainSeed?: boolean; retainSeed?: boolean;
fitToContent?: boolean;
}) => { }) => {
const elements = restoreElements(opts.elements, null, undefined); const elements = restoreElements(opts.elements, null, undefined);
const [minX, minY, maxX, maxY] = getCommonBounds(elements); const [minX, minY, maxX, maxY] = getCommonBounds(elements);
@@ -2362,6 +2372,12 @@ class App extends React.Component<AppProps, AppState> {
}, },
); );
this.setActiveTool({ type: "selection" }); this.setActiveTool({ type: "selection" });
if (opts.fitToContent) {
this.scrollToContent(newElements, {
fitToContent: true,
});
}
}; };
private addTextFromPaste(text: string, isPlainPaste = false) { private addTextFromPaste(text: string, isPlainPaste = false) {
@@ -3092,7 +3108,7 @@ class App extends React.Component<AppProps, AppState> {
} }
}); });
private setActiveTool = ( public setActiveTool = (
tool: tool:
| { | {
type: type:
@@ -3100,7 +3116,8 @@ class App extends React.Component<AppProps, AppState> {
| "eraser" | "eraser"
| "hand" | "hand"
| "frame" | "frame"
| "embeddable"; | "embeddable"
| "mermaid";
} }
| { type: "custom"; customType: string }, | { type: "custom"; customType: string },
) => { ) => {
@@ -3122,7 +3139,12 @@ class App extends React.Component<AppProps, AppState> {
if (nextActiveTool.type !== "selection") { if (nextActiveTool.type !== "selection") {
this.setState({ this.setState({
activeTool: nextActiveTool, activeTool: nextActiveTool,
selectedElementIds: makeNextSelectedElementIds({}, this.state), selectedElementIds: makeNextSelectedElementIds(
nextActiveTool.type === "mermaid"
? this.state.selectedElementIds
: {},
this.state,
),
selectedGroupIds: {}, selectedGroupIds: {},
editingGroupId: null, editingGroupId: null,
activeEmbeddable: null, activeEmbeddable: null,
@@ -4058,6 +4080,7 @@ class App extends React.Component<AppProps, AppState> {
scenePointer.x, scenePointer.x,
scenePointer.y, scenePointer.y,
); );
this.hitLinkElement = this.getElementLinkAtPosition( this.hitLinkElement = this.getElementLinkAtPosition(
scenePointer, scenePointer,
hitElement, hitElement,
@@ -4510,7 +4533,8 @@ class App extends React.Component<AppProps, AppState> {
this.createFrameElementOnPointerDown(pointerDownState); this.createFrameElementOnPointerDown(pointerDownState);
} else if ( } else if (
this.state.activeTool.type !== "eraser" && this.state.activeTool.type !== "eraser" &&
this.state.activeTool.type !== "hand" this.state.activeTool.type !== "hand" &&
this.state.activeTool.type !== "mermaid"
) { ) {
this.createGenericElementOnPointerDown( this.createGenericElementOnPointerDown(
this.state.activeTool.type, this.state.activeTool.type,
@@ -6400,11 +6424,9 @@ class App extends React.Component<AppProps, AppState> {
isInvisiblySmallElement(draggingElement) isInvisiblySmallElement(draggingElement)
) { ) {
// remove invisible element which was added in onPointerDown // remove invisible element which was added in onPointerDown
if (draggingElement.type !== "selection") {
this.scene.replaceAllElements( this.scene.replaceAllElements(
this.scene.getElementsIncludingDeleted().slice(0, -1), this.scene.getElementsIncludingDeleted().slice(0, -1),
); );
}
this.setState({ this.setState({
draggingElement: null, draggingElement: null,
}); });
@@ -7418,6 +7440,30 @@ class App extends React.Component<AppProps, AppState> {
this.setState({ suggestedBindings }); this.setState({ suggestedBindings });
} }
public setSelection(elements: readonly NonDeletedExcalidrawElement[]) {
const selectedElementIds: { [id: string]: true } = {};
const selectedGroupIds: { [id: string]: true } = {};
elements.forEach((ele) => {
if (ele.groupIds.length) {
selectedElementIds[ele.id] = true;
ele.groupIds.forEach((id) => {
selectedGroupIds[id] = true;
});
}
// exclude bound text elements as we don't mark them as selected when
// container is selected unless in group
else if (!isBoundToContainer(ele)) {
selectedElementIds[ele.id] = true;
}
});
this.setState({
previousSelectedElementIds: this.state.selectedElementIds,
selectedElementIds,
selectedGroupIds,
});
}
private clearSelection(hitElement: ExcalidrawElement | null): void { private clearSelection(hitElement: ExcalidrawElement | null): void {
this.setState((prevState) => ({ this.setState((prevState) => ({
selectedElementIds: makeNextSelectedElementIds({}, prevState), selectedElementIds: makeNextSelectedElementIds({}, prevState),

View File

@@ -0,0 +1,82 @@
@import "../css/variables.module";
.excalidraw {
.mermaid-to-excalidraw-wrapper {
display: flex;
width: 100%;
justify-content: space-between;
label {
font-size: 14px;
font-style: normal;
font-weight: 600;
margin-bottom: 4px;
margin-left: 4px;
@media screen and (max-width: 860px) {
margin-top: 4px;
}
}
&-text {
display: flex;
flex-direction: column;
textarea {
width: 20rem;
height: 19rem;
resize: none;
border-radius: 8px;
padding: 1rem;
@media screen and (max-width: 860px) {
width: auto;
height: 10rem;
}
}
}
&-preview-canvas {
display: flex;
align-items: center;
justify-content: center;
padding: 0.85rem;
width: 20rem;
height: 19rem;
background: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAMUlEQVQ4T2NkYGAQYcAP3uCTZhw1gGGYhAGBZIA/nYDCgBDAm9BGDWAAJyRCgLaBCAAgXwixzAS0pgAAAABJRU5ErkJggg==")
left center;
border-radius: 8px;
border: 1px solid #e4e4eb;
@media screen and (max-width: 860px) {
width: auto;
}
}
&-preview-insert.excalidraw-button {
font-family: "Assistant";
font-weight: 600;
height: 2.5rem;
margin-top: 1em;
margin-bottom: 0.3em;
width: 7.5rem;
font-size: 12px;
background-color: var(--color-primary);
&:hover {
background-color: var(--color-primary-darker);
}
&:active {
background-color: var(--color-primary-darkest);
}
color: $oc-white;
@media screen and (max-width: 860px) {
width: 100%;
}
}
@media screen and (max-width: 860px) {
flex-direction: column;
}
}
}

View File

@@ -0,0 +1,273 @@
import { useState, useRef, useEffect, useDeferredValue } from "react";
import { BinaryFiles } from "../types";
import { useApp } from "./App";
import { Button } from "./Button";
import { Dialog } from "./Dialog";
import { DEFAULT_EXPORT_PADDING, DEFAULT_FONT_SIZE } from "../constants";
import {
convertToExcalidrawElements,
exportToCanvas,
} from "../packages/excalidraw/index";
import { NonDeletedExcalidrawElement } from "../element/types";
import { canvasToBlob } from "../data/blob";
import { ArrowRightIcon } from "./icons";
import Spinner from "./Spinner";
import "./MermaidToExcalidraw.scss";
import { MermaidToExcalidrawResult } from "@excalidraw/mermaid-to-excalidraw/dist/interfaces";
import type { MermaidOptions } from "@excalidraw/mermaid-to-excalidraw";
import { t } from "../i18n";
import Trans from "./Trans";
const LOCAL_STORAGE_KEY_MERMAID_TO_EXCALIDRAW = "mermaid-to-excalidraw";
const MERMAID_EXAMPLE =
"flowchart TD\n A[Christmas] -->|Get money| B(Go shopping)\n B --> C{Let me think}\n C -->|One| D[Laptop]\n C -->|Two| E[iPhone]\n C -->|Three| F[test]";
const saveMermaidDataToStorage = (data: string) => {
try {
localStorage.setItem(LOCAL_STORAGE_KEY_MERMAID_TO_EXCALIDRAW, data);
} catch (error: any) {
// Unable to access window.localStorage
console.error(error);
}
};
const importMermaidDataFromStorage = () => {
try {
const data = localStorage.getItem(LOCAL_STORAGE_KEY_MERMAID_TO_EXCALIDRAW);
if (data) {
return data;
}
} catch (error: any) {
// Unable to access localStorage
console.error(error);
}
return null;
};
const ErrorComp = ({ error }: { error: string }) => {
return (
<div
data-testid="mermaid-error"
style={{
color: "red",
fontWeight: 800,
fontSize: "30px",
wordBreak: "break-word",
overflow: "auto",
maxHeight: "100%",
textAlign: "center",
}}
>
Error! <p style={{ fontSize: "18px", fontWeight: "600" }}>{error}</p>
</div>
);
};
const MermaidToExcalidraw = ({
selectedElements,
}: {
selectedElements: readonly NonDeletedExcalidrawElement[];
}) => {
const mermaidToExcalidrawLib = useRef<{
parseMermaidToExcalidraw: (
defination: string,
options: MermaidOptions,
) => Promise<MermaidToExcalidrawResult>;
} | null>(null);
const [text, setText] = useState("");
const deferredText = useDeferredValue(text);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
const canvasRef = useRef<HTMLDivElement>(null);
const data = useRef<{
elements: readonly NonDeletedExcalidrawElement[];
files: BinaryFiles | null;
}>({ elements: [], files: null });
const app = useApp();
const resetPreview = () => {
const canvasNode = canvasRef.current;
if (!canvasNode) {
return;
}
const parent = canvasNode.parentElement;
if (!parent) {
return;
}
parent.style.background = "";
canvasNode.replaceChildren();
};
useEffect(() => {
const loadMermaidToExcalidrawLib = async () => {
mermaidToExcalidrawLib.current = await import(
/* webpackChunkName:"mermaid-to-excalidraw" */ "@excalidraw/mermaid-to-excalidraw"
);
setLoading(false);
};
loadMermaidToExcalidrawLib();
}, []);
useEffect(() => {
if (!loading) {
const selectedMermaidImage = selectedElements.filter(
(el) => el.type === "image" && el.customData?.mermaidText,
)[0];
const data = selectedMermaidImage
? selectedMermaidImage.customData?.mermaidText
: importMermaidDataFromStorage() || MERMAID_EXAMPLE;
setText(data);
}
}, [loading, selectedElements]);
useEffect(() => {
const renderExcalidrawPreview = async () => {
const canvasNode = canvasRef.current;
if (
!canvasNode ||
!mermaidToExcalidrawLib.current ||
deferredText === ""
) {
return;
}
try {
const { elements, files } =
await mermaidToExcalidrawLib.current.parseMermaidToExcalidraw(
deferredText,
{
fontSize: DEFAULT_FONT_SIZE,
},
);
setError(null);
data.current = {
elements: convertToExcalidrawElements(
elements.map((el) => {
if (el.type === "image") {
el.customData = { mermaidText: text };
}
return el;
}),
{
regenerateIds: true,
},
),
files,
};
const parent = canvasNode.parentElement!;
const maxWidth = parent.offsetWidth;
const maxHeight = parent.offsetHeight;
let dimension = Math.max(maxWidth, maxHeight);
dimension = Math.min(dimension, parent.offsetWidth - 10);
dimension = Math.min(dimension, parent.offsetHeight - 10);
const canvas = await exportToCanvas({
elements: data.current.elements,
files: data.current.files,
exportPadding: DEFAULT_EXPORT_PADDING,
maxWidthOrHeight: dimension,
});
// if converting to blob fails, there's some problem that will
// likely prevent preview and export (e.g. canvas too big)
await canvasToBlob(canvas);
parent.style.background = "#fff";
canvasNode.replaceChildren(canvas);
} catch (e: any) {
console.error(e.message);
resetPreview();
if (deferredText) {
setError(e.message);
}
}
};
renderExcalidrawPreview();
}, [deferredText, text]);
const onClose = () => {
app.setActiveTool({ type: "selection" });
saveMermaidDataToStorage(text);
};
const onSelect = () => {
const { elements: newElements, files } = data.current;
app.addElementsFromPasteOrLibrary({
elements: newElements,
files,
position: "center",
fitToContent: true,
});
onClose();
};
return (
<Dialog
className="dialog-mermaid"
onCloseRequest={onClose}
title={
<>
<p style={{ marginBottom: "5px", marginTop: "2px" }}>
{t("mermaid.title")}
</p>
<span
style={{ fontSize: "15px", fontStyle: "italic", fontWeight: 500 }}
>
<Trans
i18nKey="mermaid.description"
flowchartLink={(el) => (
<a href="https://mermaid.js.org/syntax/flowchart.html">{el}</a>
)}
/>
<br />
</span>
</>
}
>
<div className="mermaid-to-excalidraw-wrapper">
<div
className="mermaid-to-excalidraw-wrapper-text"
style={{ display: "flex", flexDirection: "column" }}
>
<label>{t("mermaid.syntax")}</label>
<textarea
style={{
padding: "0.85rem",
borderRadius: "8px",
border: "1px solid #e4e4eb",
whiteSpace: "pre-wrap",
}}
onChange={(event) => setText(event.target.value)}
value={text}
/>
</div>
<div
className="mermaid-to-excalidraw-wrapper-preview"
style={{ display: "flex", flexDirection: "column" }}
>
<label>{t("mermaid.preview")}</label>
<div className="mermaid-to-excalidraw-wrapper-preview-canvas">
{error && <ErrorComp error={error} />}
{loading && <Spinner size="2rem" />}
<div ref={canvasRef} />
</div>
<Button
className="mermaid-to-excalidraw-wrapper-preview-insert"
onSelect={onSelect}
>
{t("mermaid.button")}
<span style={{ paddingLeft: "8px", display: "flex" }}>
{ArrowRightIcon}
</span>
</Button>
</div>
</div>
</Dialog>
);
};
export default MermaidToExcalidraw;

View File

@@ -165,6 +165,15 @@
width: var(--lg-button-size); width: var(--lg-button-size);
height: var(--lg-button-size); height: var(--lg-button-size);
@media screen and (max-width: 450px) {
width: 1.8rem;
height: 1.8rem;
}
@media screen and (max-width: 379px) {
width: 1.5rem;
height: 1.5rem;
}
svg { svg {
width: var(--lg-icon-size); width: var(--lg-icon-size);
height: var(--lg-icon-size); height: var(--lg-icon-size);

View File

@@ -16,6 +16,10 @@
align-self: center; align-self: center;
background-color: var(--default-border-color); background-color: var(--default-border-color);
margin: 0 0.25rem; margin: 0 0.25rem;
@include isMobile {
margin: 0;
}
} }
} }
@@ -34,5 +38,6 @@
margin-top: 0.375rem; margin-top: 0.375rem;
right: 0; right: 0;
min-width: 11.875rem; min-width: 11.875rem;
z-index: 1;
} }
} }

View File

@@ -7,8 +7,6 @@
margin-top: 0.25rem; margin-top: 0.25rem;
&--mobile { &--mobile {
bottom: 55px;
top: auto;
left: 0; left: 0;
width: 100%; width: 100%;
row-gap: 0.75rem; row-gap: 0.75rem;

View File

@@ -1653,3 +1653,37 @@ export const frameToolIcon = createIcon(
</g>, </g>,
tablerIconProps, tablerIconProps,
); );
export const mermaidLogoIcon = createIcon(
<path
fill="black"
d="M407.48,111.18C335.587,108.103 269.573,152.338 245.08,220C220.587,152.338 154.573,108.103 82.68,111.18C80.285,168.229 107.577,222.632 154.74,254.82C178.908,271.419 193.35,298.951 193.27,328.27L193.27,379.13L296.9,379.13L296.9,328.27C296.816,298.953 311.255,271.42 335.42,254.82C382.596,222.644 409.892,168.233 407.48,111.18Z"
/>,
);
export const ArrowRightIcon = createIcon(
<>
<path
d="M4.16602 10H15.8327"
stroke="white"
strokeWidth="1.25"
strokeLinecap="round"
strokeLinejoin="round"
/>
<path
d="M12.5 13.3333L15.8333 10"
stroke="white"
strokeWidth="1.25"
strokeLinecap="round"
strokeLinejoin="round"
/>
<path
d="M12.5 6.66666L15.8333 9.99999"
stroke="white"
strokeWidth="1.25"
strokeLinecap="round"
strokeLinejoin="round"
/>
</>,
{ width: 20, height: 20 },
);

View File

@@ -280,6 +280,11 @@
align-items: center; align-items: center;
justify-content: space-between; justify-content: space-between;
padding: 8px; padding: 8px;
.dropdown-menu--mobile {
bottom: 55px;
top: auto;
}
} }
.App-mobile-menu { .App-mobile-menu {
@@ -591,6 +596,8 @@
background-color: var(--island-bg-color); background-color: var(--island-bg-color);
.ToolIcon__icon { .ToolIcon__icon {
width: 2rem;
height: 2rem;
border-radius: 0; border-radius: 0;
} }
@@ -600,8 +607,8 @@
} }
.App-toolbar--mobile { .App-toolbar--mobile {
overflow-x: auto; overflow: visible;
max-width: 90vw; max-width: 98vw;
.ToolIcon__keybinding { .ToolIcon__keybinding {
display: none; display: none;

View File

@@ -97,12 +97,12 @@ exports[`Test Transform > Test arrow bindings > should bind arrows to existing s
"opacity": 100, "opacity": 100,
"points": [ "points": [
[ [
0, 0.5,
0, 0.5,
], ],
[ [
395, 394.5,
35, 34.5,
], ],
], ],
"roughness": 1, "roughness": 1,
@@ -150,11 +150,11 @@ exports[`Test Transform > Test arrow bindings > should bind arrows to existing s
"opacity": 100, "opacity": 100,
"points": [ "points": [
[ [
0, 0.5,
0, 0,
], ],
[ [
400, 399.5,
0, 0,
], ],
], ],
@@ -317,7 +317,7 @@ exports[`Test Transform > Test arrow bindings > should bind arrows to existing t
"endBinding": { "endBinding": {
"elementId": "text-2", "elementId": "text-2",
"focus": 0, "focus": 0,
"gap": 5, "gap": 205,
}, },
"fillStyle": "hachure", "fillStyle": "hachure",
"frameId": null, "frameId": null,
@@ -331,11 +331,11 @@ exports[`Test Transform > Test arrow bindings > should bind arrows to existing t
"opacity": 100, "opacity": 100,
"points": [ "points": [
[ [
0, 0.5,
0, 0,
], ],
[ [
300, 99.5,
0, 0,
], ],
], ],
@@ -355,7 +355,7 @@ exports[`Test Transform > Test arrow bindings > should bind arrows to existing t
"updated": 1, "updated": 1,
"version": 3, "version": 3,
"versionNonce": Any<Number>, "versionNonce": Any<Number>,
"width": 300, "width": 100,
"x": 255, "x": 255,
"y": 239, "y": 239,
} }
@@ -395,7 +395,7 @@ exports[`Test Transform > Test arrow bindings > should bind arrows to existing t
"versionNonce": Any<Number>, "versionNonce": Any<Number>,
"verticalAlign": "middle", "verticalAlign": "middle",
"width": 130, "width": 130,
"x": 340, "x": 240,
"y": 226.5, "y": 226.5,
} }
`; `;
@@ -428,11 +428,11 @@ exports[`Test Transform > Test arrow bindings > should bind arrows to shapes whe
"opacity": 100, "opacity": 100,
"points": [ "points": [
[ [
0, 0.5,
0, 0,
], ],
[ [
300, 99.5,
0, 0,
], ],
], ],
@@ -452,7 +452,7 @@ exports[`Test Transform > Test arrow bindings > should bind arrows to shapes whe
"updated": 1, "updated": 1,
"version": 3, "version": 3,
"versionNonce": Any<Number>, "versionNonce": Any<Number>,
"width": 300, "width": 100,
"x": 255, "x": 255,
"y": 239, "y": 239,
} }
@@ -492,7 +492,7 @@ exports[`Test Transform > Test arrow bindings > should bind arrows to shapes whe
"versionNonce": Any<Number>, "versionNonce": Any<Number>,
"verticalAlign": "middle", "verticalAlign": "middle",
"width": 130, "width": 130,
"x": 340, "x": 240,
"y": 226.5, "y": 226.5,
} }
`; `;
@@ -562,7 +562,7 @@ exports[`Test Transform > Test arrow bindings > should bind arrows to shapes whe
"version": 2, "version": 2,
"versionNonce": Any<Number>, "versionNonce": Any<Number>,
"width": 100, "width": 100,
"x": 555, "x": 355,
"y": 189, "y": 189,
} }
`; `;
@@ -595,11 +595,11 @@ exports[`Test Transform > Test arrow bindings > should bind arrows to text when
"opacity": 100, "opacity": 100,
"points": [ "points": [
[ [
0, 0.5,
0, 0,
], ],
[ [
300, 99.5,
0, 0,
], ],
], ],
@@ -619,7 +619,7 @@ exports[`Test Transform > Test arrow bindings > should bind arrows to text when
"updated": 1, "updated": 1,
"version": 3, "version": 3,
"versionNonce": Any<Number>, "versionNonce": Any<Number>,
"width": 300, "width": 100,
"x": 255, "x": 255,
"y": 239, "y": 239,
} }
@@ -659,7 +659,7 @@ exports[`Test Transform > Test arrow bindings > should bind arrows to text when
"versionNonce": Any<Number>, "versionNonce": Any<Number>,
"verticalAlign": "middle", "verticalAlign": "middle",
"width": 130, "width": 130,
"x": 340, "x": 240,
"y": 226.5, "y": 226.5,
} }
`; `;
@@ -747,7 +747,7 @@ exports[`Test Transform > Test arrow bindings > should bind arrows to text when
"versionNonce": Any<Number>, "versionNonce": Any<Number>,
"verticalAlign": "top", "verticalAlign": "top",
"width": 100, "width": 100,
"x": 555, "x": 355,
"y": 226.5, "y": 226.5,
} }
`; `;
@@ -801,11 +801,11 @@ exports[`Test Transform > should transform linear elements 1`] = `
"opacity": 100, "opacity": 100,
"points": [ "points": [
[ [
0, 0.5,
0, 0,
], ],
[ [
300, 99.5,
0, 0,
], ],
], ],
@@ -821,7 +821,7 @@ exports[`Test Transform > should transform linear elements 1`] = `
"updated": 1, "updated": 1,
"version": 1, "version": 1,
"versionNonce": Any<Number>, "versionNonce": Any<Number>,
"width": 300, "width": 100,
"x": 100, "x": 100,
"y": 20, "y": 20,
} }
@@ -846,11 +846,11 @@ exports[`Test Transform > should transform linear elements 2`] = `
"opacity": 100, "opacity": 100,
"points": [ "points": [
[ [
0, 0.5,
0, 0,
], ],
[ [
300, 99.5,
0, 0,
], ],
], ],
@@ -866,7 +866,7 @@ exports[`Test Transform > should transform linear elements 2`] = `
"updated": 1, "updated": 1,
"version": 1, "version": 1,
"versionNonce": Any<Number>, "versionNonce": Any<Number>,
"width": 300, "width": 100,
"x": 450, "x": 450,
"y": 20, "y": 20,
} }
@@ -895,7 +895,7 @@ exports[`Test Transform > should transform linear elements 3`] = `
0, 0,
], ],
[ [
300, 100,
0, 0,
], ],
], ],
@@ -911,7 +911,7 @@ exports[`Test Transform > should transform linear elements 3`] = `
"updated": 1, "updated": 1,
"version": 1, "version": 1,
"versionNonce": Any<Number>, "versionNonce": Any<Number>,
"width": 300, "width": 100,
"x": 100, "x": 100,
"y": 60, "y": 60,
} }
@@ -940,7 +940,7 @@ exports[`Test Transform > should transform linear elements 4`] = `
0, 0,
], ],
[ [
300, 100,
0, 0,
], ],
], ],
@@ -956,7 +956,7 @@ exports[`Test Transform > should transform linear elements 4`] = `
"updated": 1, "updated": 1,
"version": 1, "version": 1,
"versionNonce": Any<Number>, "versionNonce": Any<Number>,
"width": 300, "width": 100,
"x": 450, "x": 450,
"y": 60, "y": 60,
} }
@@ -1244,11 +1244,11 @@ exports[`Test Transform > should transform to labelled arrows when label provide
"opacity": 100, "opacity": 100,
"points": [ "points": [
[ [
0, 0.5,
0, 0,
], ],
[ [
300, 99.5,
0, 0,
], ],
], ],
@@ -1264,7 +1264,7 @@ exports[`Test Transform > should transform to labelled arrows when label provide
"updated": 1, "updated": 1,
"version": 1, "version": 1,
"versionNonce": Any<Number>, "versionNonce": Any<Number>,
"width": 300, "width": 100,
"x": 100, "x": 100,
"y": 100, "y": 100,
} }
@@ -1294,11 +1294,11 @@ exports[`Test Transform > should transform to labelled arrows when label provide
"opacity": 100, "opacity": 100,
"points": [ "points": [
[ [
0, 0.5,
0, 0,
], ],
[ [
300, 99.5,
0, 0,
], ],
], ],
@@ -1314,7 +1314,7 @@ exports[`Test Transform > should transform to labelled arrows when label provide
"updated": 1, "updated": 1,
"version": 1, "version": 1,
"versionNonce": Any<Number>, "versionNonce": Any<Number>,
"width": 300, "width": 100,
"x": 100, "x": 100,
"y": 200, "y": 200,
} }
@@ -1344,11 +1344,11 @@ exports[`Test Transform > should transform to labelled arrows when label provide
"opacity": 100, "opacity": 100,
"points": [ "points": [
[ [
0, 0.5,
0, 0,
], ],
[ [
300, 99.5,
0, 0,
], ],
], ],
@@ -1364,7 +1364,7 @@ exports[`Test Transform > should transform to labelled arrows when label provide
"updated": 1, "updated": 1,
"version": 2, "version": 2,
"versionNonce": Any<Number>, "versionNonce": Any<Number>,
"width": 300, "width": 100,
"x": 100, "x": 100,
"y": 300, "y": 300,
} }
@@ -1394,11 +1394,11 @@ exports[`Test Transform > should transform to labelled arrows when label provide
"opacity": 100, "opacity": 100,
"points": [ "points": [
[ [
0, 0.5,
0, 0,
], ],
[ [
300, 99.5,
0, 0,
], ],
], ],
@@ -1414,7 +1414,7 @@ exports[`Test Transform > should transform to labelled arrows when label provide
"updated": 1, "updated": 1,
"version": 2, "version": 2,
"versionNonce": Any<Number>, "versionNonce": Any<Number>,
"width": 300, "width": 100,
"x": 100, "x": 100,
"y": 400, "y": 400,
} }
@@ -1454,7 +1454,7 @@ exports[`Test Transform > should transform to labelled arrows when label provide
"versionNonce": Any<Number>, "versionNonce": Any<Number>,
"verticalAlign": "middle", "verticalAlign": "middle",
"width": 130, "width": 130,
"x": 185, "x": 85,
"y": 87.5, "y": 87.5,
} }
`; `;
@@ -1493,7 +1493,7 @@ exports[`Test Transform > should transform to labelled arrows when label provide
"versionNonce": Any<Number>, "versionNonce": Any<Number>,
"verticalAlign": "middle", "verticalAlign": "middle",
"width": 200, "width": 200,
"x": 150, "x": 50,
"y": 187.5, "y": 187.5,
} }
`; `;
@@ -1533,7 +1533,7 @@ LABELLED ARROW",
"versionNonce": Any<Number>, "versionNonce": Any<Number>,
"verticalAlign": "middle", "verticalAlign": "middle",
"width": 150, "width": 150,
"x": 175, "x": 75,
"y": 275, "y": 275,
} }
`; `;
@@ -1573,7 +1573,7 @@ LABELLED ARROW",
"versionNonce": Any<Number>, "versionNonce": Any<Number>,
"verticalAlign": "middle", "verticalAlign": "middle",
"width": 150, "width": 150,
"x": 175, "x": 75,
"y": 375, "y": 375,
} }
`; `;

View File

@@ -67,6 +67,7 @@ export const AllowedExcalidrawActiveTools: Record<
frame: true, frame: true,
embeddable: true, embeddable: true,
hand: true, hand: true,
mermaid: true,
}; };
export type RestoredDataState = { export type RestoredDataState = {

View File

@@ -321,7 +321,7 @@ describe("Test Transform", () => {
}); });
expect(text).toMatchObject({ expect(text).toMatchObject({
x: 340, x: 240,
y: 226.5, y: 226.5,
type: "text", type: "text",
text: "HELLO WORLD!!", text: "HELLO WORLD!!",
@@ -341,7 +341,7 @@ describe("Test Transform", () => {
}); });
expect(ellipse).toMatchObject({ expect(ellipse).toMatchObject({
x: 555, x: 355,
y: 189, y: 189,
type: "ellipse", type: "ellipse",
boundElements: [ boundElements: [
@@ -386,7 +386,6 @@ describe("Test Transform", () => {
); );
expect(excaldrawElements.length).toBe(4); expect(excaldrawElements.length).toBe(4);
const [arrow, text1, text2, text3] = excaldrawElements; const [arrow, text1, text2, text3] = excaldrawElements;
expect(arrow).toMatchObject({ expect(arrow).toMatchObject({
@@ -406,7 +405,7 @@ describe("Test Transform", () => {
}); });
expect(text1).toMatchObject({ expect(text1).toMatchObject({
x: 340, x: 240,
y: 226.5, y: 226.5,
type: "text", type: "text",
text: "HELLO WORLD!!", text: "HELLO WORLD!!",
@@ -426,7 +425,7 @@ describe("Test Transform", () => {
}); });
expect(text3).toMatchObject({ expect(text3).toMatchObject({
x: 555, x: 355,
y: 226.5, y: 226.5,
type: "text", type: "text",
boundElements: [ boundElements: [
@@ -603,14 +602,14 @@ describe("Test Transform", () => {
); );
expect(excaldrawElements.length).toBe(4); expect(excaldrawElements.length).toBe(4);
const [, , arrow] = excaldrawElements; const [, , arrow, text] = excaldrawElements;
expect(arrow).toMatchObject({ expect(arrow).toMatchObject({
type: "arrow", type: "arrow",
x: 255, x: 255,
y: 239, y: 239,
boundElements: [ boundElements: [
{ {
id: "id46", id: text.id,
type: "text", type: "text",
}, },
], ],
@@ -656,11 +655,11 @@ describe("Test Transform", () => {
expect((arrow as ExcalidrawArrowElement).endBinding).toStrictEqual({ expect((arrow as ExcalidrawArrowElement).endBinding).toStrictEqual({
elementId: "rect-1", elementId: "rect-1",
focus: 0, focus: 0,
gap: 5, gap: 205,
}); });
expect(rect.boundElements).toStrictEqual([ expect(rect.boundElements).toStrictEqual([
{ {
id: "id47", id: arrow.id,
type: "arrow", type: "arrow",
}, },
]); ]);

View File

@@ -39,6 +39,8 @@ import {
} from "../element/types"; } from "../element/types";
import { MarkOptional } from "../utility-types"; import { MarkOptional } from "../utility-types";
import { assertNever, getFontString } from "../utils"; import { assertNever, getFontString } from "../utils";
import { getSizeFromPoints } from "../points";
import { nanoid } from "nanoid";
export type ValidLinearElement = { export type ValidLinearElement = {
type: "arrow" | "line"; type: "arrow" | "line";
@@ -159,7 +161,7 @@ export type ExcalidrawElementSkeleton =
} & Partial<ExcalidrawImageElement>); } & Partial<ExcalidrawImageElement>);
const DEFAULT_LINEAR_ELEMENT_PROPS = { const DEFAULT_LINEAR_ELEMENT_PROPS = {
width: 300, width: 100,
height: 0, height: 0,
}; };
@@ -357,6 +359,48 @@ const bindLinearElementToElement = (
); );
} }
} }
// Update start/end points by 0.5 so bindings don't overlap with start/end bound element coordinates.
const endPointIndex = linearElement.points.length - 1;
const delta = 0.5;
const newPoints = JSON.parse(JSON.stringify(linearElement.points));
// left to right so shift the arrow towards right
if (
linearElement.points[endPointIndex][0] >
linearElement.points[endPointIndex - 1][0]
) {
newPoints[0][0] = delta;
newPoints[endPointIndex][0] -= delta;
}
// right to left so shift the arrow towards left
if (
linearElement.points[endPointIndex][0] <
linearElement.points[endPointIndex - 1][0]
) {
newPoints[0][0] = -delta;
newPoints[endPointIndex][0] += delta;
}
// top to bottom so shift the arrow towards top
if (
linearElement.points[endPointIndex][1] >
linearElement.points[endPointIndex - 1][1]
) {
newPoints[0][1] = delta;
newPoints[endPointIndex][1] -= delta;
}
// bottom to top so shift the arrow towards bottom
if (
linearElement.points[endPointIndex][1] <
linearElement.points[endPointIndex - 1][1]
) {
newPoints[0][1] = -delta;
newPoints[endPointIndex][1] += delta;
}
Object.assign(linearElement, { points: newPoints });
return { return {
linearElement, linearElement,
startBoundElement, startBoundElement,
@@ -367,7 +411,7 @@ const bindLinearElementToElement = (
class ElementStore { class ElementStore {
excalidrawElements = new Map<string, ExcalidrawElement>(); excalidrawElements = new Map<string, ExcalidrawElement>();
add = (ele?: ExcalidrawElement) => { add = (ele?: ExcalidrawElement, originalId?: string) => {
if (!ele) { if (!ele) {
return; return;
} }
@@ -385,6 +429,7 @@ class ElementStore {
export const convertToExcalidrawElements = ( export const convertToExcalidrawElements = (
elements: ExcalidrawElementSkeleton[] | null, elements: ExcalidrawElementSkeleton[] | null,
opts?: { regenerateIds: boolean },
) => { ) => {
if (!elements) { if (!elements) {
return []; return [];
@@ -392,10 +437,16 @@ export const convertToExcalidrawElements = (
const elementStore = new ElementStore(); const elementStore = new ElementStore();
const elementsWithIds = new Map<string, ExcalidrawElementSkeleton>(); const elementsWithIds = new Map<string, ExcalidrawElementSkeleton>();
const oldToNewElementIdMap = new Map<string, string>();
// Create individual elements // Create individual elements
for (const element of elements) { for (const element of elements) {
let excalidrawElement: ExcalidrawElement; let excalidrawElement: ExcalidrawElement;
const originalId = element.id;
if (opts?.regenerateIds) {
Object.assign(element, { id: nanoid() });
}
switch (element.type) { switch (element.type) {
case "rectangle": case "rectangle":
case "ellipse": case "ellipse":
@@ -444,6 +495,11 @@ export const convertToExcalidrawElements = (
], ],
...element, ...element,
}); });
Object.assign(
excalidrawElement,
getSizeFromPoints(excalidrawElement.points),
);
break; break;
} }
case "text": { case "text": {
@@ -499,6 +555,9 @@ export const convertToExcalidrawElements = (
} else { } else {
elementStore.add(excalidrawElement); elementStore.add(excalidrawElement);
elementsWithIds.set(excalidrawElement.id, element); elementsWithIds.set(excalidrawElement.id, element);
if (originalId) {
oldToNewElementIdMap.set(originalId, excalidrawElement.id);
}
} }
} }
@@ -524,6 +583,18 @@ export const convertToExcalidrawElements = (
element.type === "arrow" ? element?.start : undefined; element.type === "arrow" ? element?.start : undefined;
const originalEnd = const originalEnd =
element.type === "arrow" ? element?.end : undefined; element.type === "arrow" ? element?.end : undefined;
if (originalStart && originalStart.id) {
const newStartId = oldToNewElementIdMap.get(originalStart.id);
if (newStartId) {
Object.assign(originalStart, { id: newStartId });
}
}
if (originalEnd && originalEnd.id) {
const newEndId = oldToNewElementIdMap.get(originalEnd.id);
if (newEndId) {
Object.assign(originalEnd, { id: newEndId });
}
}
const { linearElement, startBoundElement, endBoundElement } = const { linearElement, startBoundElement, endBoundElement } =
bindLinearElementToElement( bindLinearElementToElement(
container as ExcalidrawArrowElement, container as ExcalidrawArrowElement,
@@ -539,13 +610,23 @@ export const convertToExcalidrawElements = (
} else { } else {
switch (element.type) { switch (element.type) {
case "arrow": { case "arrow": {
const { start, end } = element;
if (start && start.id) {
const newStartId = oldToNewElementIdMap.get(start.id);
Object.assign(start, { id: newStartId });
}
if (end && end.id) {
const newEndId = oldToNewElementIdMap.get(end.id);
Object.assign(end, { id: newEndId });
}
const { linearElement, startBoundElement, endBoundElement } = const { linearElement, startBoundElement, endBoundElement } =
bindLinearElementToElement( bindLinearElementToElement(
excalidrawElement as ExcalidrawArrowElement, excalidrawElement as ExcalidrawArrowElement,
element.start, start,
element.end, end,
elementStore, elementStore,
); );
elementStore.add(linearElement); elementStore.add(linearElement);
elementStore.add(startBoundElement); elementStore.add(startBoundElement);
elementStore.add(endBoundElement); elementStore.add(endBoundElement);

View File

@@ -7,7 +7,11 @@ import { AppState, PointerDownState } from "../types";
import { getBoundTextElement } from "./textElement"; import { getBoundTextElement } from "./textElement";
import { isSelectedViaGroup } from "../groups"; import { isSelectedViaGroup } from "../groups";
import Scene from "../scene/Scene"; import Scene from "../scene/Scene";
import { isFrameElement } from "./typeChecks"; import {
isArrowElement,
isBoundToContainer,
isFrameElement,
} from "./typeChecks";
export const dragSelectedElements = ( export const dragSelectedElements = (
pointerDownState: PointerDownState, pointerDownState: PointerDownState,
@@ -36,6 +40,7 @@ export const dragSelectedElements = (
if (frames.length > 0) { if (frames.length > 0) {
const elementsInFrames = scene const elementsInFrames = scene
.getNonDeletedElements() .getNonDeletedElements()
.filter((e) => !isBoundToContainer(e))
.filter((e) => e.frameId !== null) .filter((e) => e.frameId !== null)
.filter((e) => frames.includes(e.frameId!)); .filter((e) => frames.includes(e.frameId!));
@@ -54,20 +59,16 @@ export const dragSelectedElements = (
// update coords of bound text only if we're dragging the container directly // update coords of bound text only if we're dragging the container directly
// (we don't drag the group that it's part of) // (we don't drag the group that it's part of)
if ( if (
// Don't update coords of arrow label since we calculate its position during render
!isArrowElement(element) &&
// container isn't part of any group // container isn't part of any group
// (perf optim so we don't check `isSelectedViaGroup()` in every case) // (perf optim so we don't check `isSelectedViaGroup()` in every case)
!element.groupIds.length || (!element.groupIds.length ||
// container is part of a group, but we're dragging the container directly // container is part of a group, but we're dragging the container directly
(appState.editingGroupId && !isSelectedViaGroup(appState, element)) (appState.editingGroupId && !isSelectedViaGroup(appState, element)))
) { ) {
const textElement = getBoundTextElement(element); const textElement = getBoundTextElement(element);
if ( if (textElement) {
textElement &&
// when container is added to a frame, so will its bound text
// so the text is already in `elementsToUpdate` and we should avoid
// updating its coords again
(!textElement.frameId || !frames.includes(textElement.frameId))
) {
updateElementCoords( updateElementCoords(
lockDirection, lockDirection,
distanceX, distanceX,

View File

@@ -1,6 +1,12 @@
import ReactDOM from "react-dom"; import ReactDOM from "react-dom";
import { Excalidraw } from "../packages/excalidraw/index"; import { Excalidraw } from "../packages/excalidraw/index";
import { GlobalTestState, render, screen } from "../tests/test-utils"; import {
GlobalTestState,
getTextEditor,
render,
screen,
updateTextEditor,
} from "../tests/test-utils";
import { Keyboard, Pointer, UI } from "../tests/helpers/ui"; import { Keyboard, Pointer, UI } from "../tests/helpers/ui";
import { CODES, KEYS } from "../keys"; import { CODES, KEYS } from "../keys";
import { import {
@@ -26,16 +32,7 @@ ReactDOM.unmountComponentAtNode(document.getElementById("root")!);
const tab = " "; const tab = " ";
const mouse = new Pointer("mouse"); const mouse = new Pointer("mouse");
const getTextEditor = () => { const textEditorSelector = ".excalidraw-textEditorContainer > textarea";
return document.querySelector(
".excalidraw-textEditorContainer > textarea",
) as HTMLTextAreaElement;
};
const updateTextEditor = (editor: HTMLTextAreaElement, value: string) => {
fireEvent.change(editor, { target: { value } });
editor.dispatchEvent(new Event("input"));
};
describe("textWysiwyg", () => { describe("textWysiwyg", () => {
describe("start text editing", () => { describe("start text editing", () => {
@@ -201,7 +198,7 @@ describe("textWysiwyg", () => {
mouse.clickAt(text.x + 50, text.y + 50); mouse.clickAt(text.x + 50, text.y + 50);
const editor = getTextEditor(); const editor = getTextEditor(textEditorSelector);
expect(editor).not.toBe(null); expect(editor).not.toBe(null);
expect(h.state.editingElement?.id).toBe(text.id); expect(h.state.editingElement?.id).toBe(text.id);
@@ -223,7 +220,7 @@ describe("textWysiwyg", () => {
mouse.doubleClickAt(text.x + 50, text.y + 50); mouse.doubleClickAt(text.x + 50, text.y + 50);
const editor = getTextEditor(); const editor = getTextEditor(textEditorSelector);
expect(editor).not.toBe(null); expect(editor).not.toBe(null);
expect(h.state.editingElement?.id).toBe(text.id); expect(h.state.editingElement?.id).toBe(text.id);
@@ -250,7 +247,7 @@ describe("textWysiwyg", () => {
textElement = UI.createElement("text"); textElement = UI.createElement("text");
mouse.clickOn(textElement); mouse.clickOn(textElement);
textarea = getTextEditor(); textarea = getTextEditor(textEditorSelector);
}); });
afterAll(() => { afterAll(() => {
@@ -460,7 +457,7 @@ describe("textWysiwyg", () => {
UI.clickTool("text"); UI.clickTool("text");
mouse.clickAt(750, 300); mouse.clickAt(750, 300);
textarea = getTextEditor(); textarea = getTextEditor(textEditorSelector);
updateTextEditor( updateTextEditor(
textarea, textarea,
"Excalidraw is an opensource virtual collaborative whiteboard for sketching hand-drawn like diagrams!", "Excalidraw is an opensource virtual collaborative whiteboard for sketching hand-drawn like diagrams!",
@@ -512,7 +509,7 @@ describe("textWysiwyg", () => {
{ id: text.id, type: "text" }, { id: text.id, type: "text" },
]); ]);
mouse.down(); mouse.down();
const editor = getTextEditor(); const editor = getTextEditor(textEditorSelector);
updateTextEditor(editor, "Hello World!"); updateTextEditor(editor, "Hello World!");
@@ -540,7 +537,7 @@ describe("textWysiwyg", () => {
]); ]);
expect(text.angle).toBe(rectangle.angle); expect(text.angle).toBe(rectangle.angle);
mouse.down(); mouse.down();
const editor = getTextEditor(); const editor = getTextEditor(textEditorSelector);
updateTextEditor(editor, "Hello World!"); updateTextEditor(editor, "Hello World!");
@@ -567,7 +564,7 @@ describe("textWysiwyg", () => {
API.setSelectedElements([diamond]); API.setSelectedElements([diamond]);
Keyboard.keyPress(KEYS.ENTER); Keyboard.keyPress(KEYS.ENTER);
const editor = getTextEditor(); const editor = getTextEditor(textEditorSelector);
await new Promise((r) => setTimeout(r, 0)); await new Promise((r) => setTimeout(r, 0));
const value = new Array(1000).fill("1").join("\n"); const value = new Array(1000).fill("1").join("\n");
@@ -602,7 +599,7 @@ describe("textWysiwyg", () => {
expect(text.type).toBe("text"); expect(text.type).toBe("text");
expect(text.containerId).toBe(null); expect(text.containerId).toBe(null);
mouse.down(); mouse.down();
let editor = getTextEditor(); let editor = getTextEditor(textEditorSelector);
await new Promise((r) => setTimeout(r, 0)); await new Promise((r) => setTimeout(r, 0));
editor.blur(); editor.blur();
@@ -617,7 +614,7 @@ describe("textWysiwyg", () => {
expect(text.containerId).toBe(rectangle.id); expect(text.containerId).toBe(rectangle.id);
mouse.down(); mouse.down();
editor = getTextEditor(); editor = getTextEditor(textEditorSelector);
updateTextEditor(editor, "Hello World!"); updateTextEditor(editor, "Hello World!");
await new Promise((r) => setTimeout(r, 0)); await new Promise((r) => setTimeout(r, 0));
@@ -639,7 +636,7 @@ describe("textWysiwyg", () => {
const text = h.elements[1] as ExcalidrawTextElementWithContainer; const text = h.elements[1] as ExcalidrawTextElementWithContainer;
expect(text.type).toBe("text"); expect(text.type).toBe("text");
expect(text.containerId).toBe(rectangle.id); expect(text.containerId).toBe(rectangle.id);
const editor = getTextEditor(); const editor = getTextEditor(textEditorSelector);
await new Promise((r) => setTimeout(r, 0)); await new Promise((r) => setTimeout(r, 0));
@@ -674,7 +671,7 @@ describe("textWysiwyg", () => {
{ id: text.id, type: "text" }, { id: text.id, type: "text" },
]); ]);
mouse.down(); mouse.down();
const editor = getTextEditor(); const editor = getTextEditor(textEditorSelector);
updateTextEditor(editor, "Hello World!"); updateTextEditor(editor, "Hello World!");
await new Promise((r) => setTimeout(r, 0)); await new Promise((r) => setTimeout(r, 0));
@@ -699,7 +696,7 @@ describe("textWysiwyg", () => {
freedraw.y + freedraw.height / 2, freedraw.y + freedraw.height / 2,
); );
const editor = getTextEditor(); const editor = getTextEditor(textEditorSelector);
updateTextEditor(editor, "Hello World!"); updateTextEditor(editor, "Hello World!");
fireEvent.keyDown(editor, { key: KEYS.ESCAPE }); fireEvent.keyDown(editor, { key: KEYS.ESCAPE });
@@ -733,7 +730,7 @@ describe("textWysiwyg", () => {
expect(text.type).toBe("text"); expect(text.type).toBe("text");
expect(text.containerId).toBe(null); expect(text.containerId).toBe(null);
mouse.down(); mouse.down();
const editor = getTextEditor(); const editor = getTextEditor(textEditorSelector);
updateTextEditor(editor, "Hello World!"); updateTextEditor(editor, "Hello World!");
@@ -748,7 +745,7 @@ describe("textWysiwyg", () => {
UI.clickTool("text"); UI.clickTool("text");
mouse.clickAt(20, 30); mouse.clickAt(20, 30);
const editor = getTextEditor(); const editor = getTextEditor(textEditorSelector);
updateTextEditor( updateTextEditor(
editor, editor,
@@ -793,7 +790,7 @@ describe("textWysiwyg", () => {
mouse.down(); mouse.down();
const text = h.elements[1] as ExcalidrawTextElementWithContainer; const text = h.elements[1] as ExcalidrawTextElementWithContainer;
let editor = getTextEditor(); let editor = getTextEditor(textEditorSelector);
await new Promise((r) => setTimeout(r, 0)); await new Promise((r) => setTimeout(r, 0));
updateTextEditor(editor, "Hello World!"); updateTextEditor(editor, "Hello World!");
@@ -806,7 +803,7 @@ describe("textWysiwyg", () => {
rectangle.y + rectangle.height / 2, rectangle.y + rectangle.height / 2,
); );
mouse.down(); mouse.down();
editor = getTextEditor(); editor = getTextEditor(textEditorSelector);
editor.select(); editor.select();
fireEvent.click(screen.getByTitle(/code/i)); fireEvent.click(screen.getByTitle(/code/i));
@@ -839,7 +836,7 @@ describe("textWysiwyg", () => {
Keyboard.keyDown(KEYS.ENTER); Keyboard.keyDown(KEYS.ENTER);
let text = h.elements[1] as ExcalidrawTextElementWithContainer; let text = h.elements[1] as ExcalidrawTextElementWithContainer;
let editor = getTextEditor(); let editor = getTextEditor(textEditorSelector);
updateTextEditor(editor, "Hello World!"); updateTextEditor(editor, "Hello World!");
@@ -860,7 +857,7 @@ describe("textWysiwyg", () => {
mouse.select(rectangle); mouse.select(rectangle);
Keyboard.keyPress(KEYS.ENTER); Keyboard.keyPress(KEYS.ENTER);
editor = getTextEditor(); editor = getTextEditor(textEditorSelector);
updateTextEditor(editor, "Hello"); updateTextEditor(editor, "Hello");
await new Promise((r) => setTimeout(r, 0)); await new Promise((r) => setTimeout(r, 0));
@@ -889,7 +886,7 @@ describe("textWysiwyg", () => {
const text = h.elements[1] as ExcalidrawTextElementWithContainer; const text = h.elements[1] as ExcalidrawTextElementWithContainer;
expect(text.containerId).toBe(rectangle.id); expect(text.containerId).toBe(rectangle.id);
const editor = getTextEditor(); const editor = getTextEditor(textEditorSelector);
await new Promise((r) => setTimeout(r, 0)); await new Promise((r) => setTimeout(r, 0));
@@ -926,7 +923,7 @@ describe("textWysiwyg", () => {
// Bind first text // Bind first text
const text = h.elements[1] as ExcalidrawTextElementWithContainer; const text = h.elements[1] as ExcalidrawTextElementWithContainer;
expect(text.containerId).toBe(rectangle.id); expect(text.containerId).toBe(rectangle.id);
const editor = getTextEditor(); const editor = getTextEditor(textEditorSelector);
await new Promise((r) => setTimeout(r, 0)); await new Promise((r) => setTimeout(r, 0));
updateTextEditor(editor, "Hello World!"); updateTextEditor(editor, "Hello World!");
editor.blur(); editor.blur();
@@ -947,7 +944,7 @@ describe("textWysiwyg", () => {
it("should respect text alignment when resizing", async () => { it("should respect text alignment when resizing", async () => {
Keyboard.keyPress(KEYS.ENTER); Keyboard.keyPress(KEYS.ENTER);
let editor = getTextEditor(); let editor = getTextEditor(textEditorSelector);
await new Promise((r) => setTimeout(r, 0)); await new Promise((r) => setTimeout(r, 0));
updateTextEditor(editor, "Hello"); updateTextEditor(editor, "Hello");
editor.blur(); editor.blur();
@@ -964,7 +961,7 @@ describe("textWysiwyg", () => {
mouse.select(rectangle); mouse.select(rectangle);
Keyboard.keyPress(KEYS.ENTER); Keyboard.keyPress(KEYS.ENTER);
editor = getTextEditor(); editor = getTextEditor(textEditorSelector);
editor.select(); editor.select();
@@ -987,7 +984,7 @@ describe("textWysiwyg", () => {
mouse.select(rectangle); mouse.select(rectangle);
Keyboard.keyPress(KEYS.ENTER); Keyboard.keyPress(KEYS.ENTER);
editor = getTextEditor(); editor = getTextEditor(textEditorSelector);
editor.select(); editor.select();
@@ -1025,7 +1022,7 @@ describe("textWysiwyg", () => {
expect(text.type).toBe("text"); expect(text.type).toBe("text");
expect(text.containerId).toBe(rectangle.id); expect(text.containerId).toBe(rectangle.id);
mouse.down(); mouse.down();
const editor = getTextEditor(); const editor = getTextEditor(textEditorSelector);
updateTextEditor(editor, "Hello World!"); updateTextEditor(editor, "Hello World!");
@@ -1040,7 +1037,7 @@ describe("textWysiwyg", () => {
it("should scale font size correctly when resizing using shift", async () => { it("should scale font size correctly when resizing using shift", async () => {
Keyboard.keyPress(KEYS.ENTER); Keyboard.keyPress(KEYS.ENTER);
const editor = getTextEditor(); const editor = getTextEditor(textEditorSelector);
await new Promise((r) => setTimeout(r, 0)); await new Promise((r) => setTimeout(r, 0));
updateTextEditor(editor, "Hello"); updateTextEditor(editor, "Hello");
editor.blur(); editor.blur();
@@ -1060,7 +1057,7 @@ describe("textWysiwyg", () => {
it("should bind text correctly when container duplicated with alt-drag", async () => { it("should bind text correctly when container duplicated with alt-drag", async () => {
Keyboard.keyPress(KEYS.ENTER); Keyboard.keyPress(KEYS.ENTER);
const editor = getTextEditor(); const editor = getTextEditor(textEditorSelector);
await new Promise((r) => setTimeout(r, 0)); await new Promise((r) => setTimeout(r, 0));
updateTextEditor(editor, "Hello"); updateTextEditor(editor, "Hello");
editor.blur(); editor.blur();
@@ -1092,7 +1089,7 @@ describe("textWysiwyg", () => {
it("undo should work", async () => { it("undo should work", async () => {
Keyboard.keyPress(KEYS.ENTER); Keyboard.keyPress(KEYS.ENTER);
const editor = getTextEditor(); const editor = getTextEditor(textEditorSelector);
await new Promise((r) => setTimeout(r, 0)); await new Promise((r) => setTimeout(r, 0));
updateTextEditor(editor, "Hello"); updateTextEditor(editor, "Hello");
editor.blur(); editor.blur();
@@ -1129,7 +1126,7 @@ describe("textWysiwyg", () => {
it("should not allow bound text with only whitespaces", async () => { it("should not allow bound text with only whitespaces", async () => {
Keyboard.keyPress(KEYS.ENTER); Keyboard.keyPress(KEYS.ENTER);
const editor = getTextEditor(); const editor = getTextEditor(textEditorSelector);
await new Promise((r) => setTimeout(r, 0)); await new Promise((r) => setTimeout(r, 0));
updateTextEditor(editor, " "); updateTextEditor(editor, " ");
@@ -1184,7 +1181,7 @@ describe("textWysiwyg", () => {
it("should reset the container height cache when resizing", async () => { it("should reset the container height cache when resizing", async () => {
Keyboard.keyPress(KEYS.ENTER); Keyboard.keyPress(KEYS.ENTER);
expect(getOriginalContainerHeightFromCache(rectangle.id)).toBe(75); expect(getOriginalContainerHeightFromCache(rectangle.id)).toBe(75);
let editor = getTextEditor(); let editor = getTextEditor(textEditorSelector);
await new Promise((r) => setTimeout(r, 0)); await new Promise((r) => setTimeout(r, 0));
updateTextEditor(editor, "Hello"); updateTextEditor(editor, "Hello");
editor.blur(); editor.blur();
@@ -1196,7 +1193,7 @@ describe("textWysiwyg", () => {
mouse.select(rectangle); mouse.select(rectangle);
Keyboard.keyPress(KEYS.ENTER); Keyboard.keyPress(KEYS.ENTER);
editor = getTextEditor(); editor = getTextEditor(textEditorSelector);
await new Promise((r) => setTimeout(r, 0)); await new Promise((r) => setTimeout(r, 0));
editor.blur(); editor.blur();
@@ -1209,7 +1206,7 @@ describe("textWysiwyg", () => {
Keyboard.keyPress(KEYS.ENTER); Keyboard.keyPress(KEYS.ENTER);
expect(getOriginalContainerHeightFromCache(rectangle.id)).toBe(75); expect(getOriginalContainerHeightFromCache(rectangle.id)).toBe(75);
const editor = getTextEditor(); const editor = getTextEditor(textEditorSelector);
updateTextEditor(editor, "Hello World!"); updateTextEditor(editor, "Hello World!");
editor.blur(); editor.blur();
@@ -1234,7 +1231,7 @@ describe("textWysiwyg", () => {
Keyboard.keyPress(KEYS.ENTER); Keyboard.keyPress(KEYS.ENTER);
expect(getOriginalContainerHeightFromCache(rectangle.id)).toBe(75); expect(getOriginalContainerHeightFromCache(rectangle.id)).toBe(75);
const editor = getTextEditor(); const editor = getTextEditor(textEditorSelector);
updateTextEditor(editor, "Hello World!"); updateTextEditor(editor, "Hello World!");
editor.blur(); editor.blur();
expect( expect(
@@ -1266,12 +1263,12 @@ describe("textWysiwyg", () => {
beforeEach(async () => { beforeEach(async () => {
Keyboard.keyPress(KEYS.ENTER); Keyboard.keyPress(KEYS.ENTER);
editor = getTextEditor(); editor = getTextEditor(textEditorSelector);
updateTextEditor(editor, "Hello"); updateTextEditor(editor, "Hello");
editor.blur(); editor.blur();
mouse.select(rectangle); mouse.select(rectangle);
Keyboard.keyPress(KEYS.ENTER); Keyboard.keyPress(KEYS.ENTER);
editor = getTextEditor(); editor = getTextEditor(textEditorSelector);
editor.select(); editor.select();
}); });
@@ -1382,7 +1379,7 @@ describe("textWysiwyg", () => {
it("should wrap text in a container when wrap text in container triggered from context menu", async () => { it("should wrap text in a container when wrap text in container triggered from context menu", async () => {
UI.clickTool("text"); UI.clickTool("text");
mouse.clickAt(20, 30); mouse.clickAt(20, 30);
const editor = getTextEditor(); const editor = getTextEditor(textEditorSelector);
updateTextEditor( updateTextEditor(
editor, editor,
@@ -1470,7 +1467,7 @@ describe("textWysiwyg", () => {
// Bind first text // Bind first text
let text = h.elements[1] as ExcalidrawTextElementWithContainer; let text = h.elements[1] as ExcalidrawTextElementWithContainer;
expect(text.containerId).toBe(rectangle.id); expect(text.containerId).toBe(rectangle.id);
let editor = getTextEditor(); let editor = getTextEditor(textEditorSelector);
await new Promise((r) => setTimeout(r, 0)); await new Promise((r) => setTimeout(r, 0));
updateTextEditor(editor, "Hello!"); updateTextEditor(editor, "Hello!");
expect( expect(
@@ -1495,7 +1492,7 @@ describe("textWysiwyg", () => {
rectangle.x + rectangle.width / 2, rectangle.x + rectangle.width / 2,
rectangle.y + rectangle.height / 2, rectangle.y + rectangle.height / 2,
); );
editor = getTextEditor(); editor = getTextEditor(textEditorSelector);
await new Promise((r) => setTimeout(r, 0)); await new Promise((r) => setTimeout(r, 0));
updateTextEditor(editor, "Excalidraw"); updateTextEditor(editor, "Excalidraw");
editor.blur(); editor.blur();
@@ -1519,7 +1516,7 @@ describe("textWysiwyg", () => {
mouse.select(arrow); mouse.select(arrow);
Keyboard.keyPress(KEYS.ENTER); Keyboard.keyPress(KEYS.ENTER);
let editor = getTextEditor(); let editor = getTextEditor(textEditorSelector);
await new Promise((r) => setTimeout(r, 0)); await new Promise((r) => setTimeout(r, 0));
updateTextEditor(editor, "Hello"); updateTextEditor(editor, "Hello");
editor.blur(); editor.blur();
@@ -1528,7 +1525,7 @@ describe("textWysiwyg", () => {
mouse.select(arrow); mouse.select(arrow);
Keyboard.keyPress(KEYS.ENTER); Keyboard.keyPress(KEYS.ENTER);
editor = getTextEditor(); editor = getTextEditor(textEditorSelector);
await new Promise((r) => setTimeout(r, 0)); await new Promise((r) => setTimeout(r, 0));
updateTextEditor(editor, "Hello\nworld!"); updateTextEditor(editor, "Hello\nworld!");
editor.blur(); editor.blur();

View File

@@ -236,7 +236,8 @@
"frame": "Frame tool", "frame": "Frame tool",
"embeddable": "Web Embed", "embeddable": "Web Embed",
"hand": "Hand (panning tool)", "hand": "Hand (panning tool)",
"extraTools": "More tools" "extraTools": "More tools",
"mermaidToExcalidraw": "Mermaid to Excalidraw"
}, },
"headings": { "headings": {
"canvasActions": "Canvas actions", "canvasActions": "Canvas actions",
@@ -495,5 +496,12 @@
"description": "Loading external drawing will <bold>replace your existing content</bold>.<br></br>You can back up your drawing first by using one of the options below." "description": "Loading external drawing will <bold>replace your existing content</bold>.<br></br>You can back up your drawing first by using one of the options below."
} }
} }
},
"mermaid": {
"title": "Mermaid to Excalidraw",
"button": "Insert",
"description": "Currently only <flowchartLink>flowcharts</flowchartLink> are supported. The other types will be rendered as image in Excalidraw.",
"syntax": "Mermaid Syntax",
"preview": "Preview"
} }
} }

View File

@@ -11,22 +11,6 @@ The change should be grouped under one of the below section and must contain PR
Please add the latest change on the top under the correct section. Please add the latest change on the top under the correct section.
--> -->
## 0.16.1 (2023-09-21)
## Excalidraw Library
**_This section lists the updates made to the excalidraw library and will not affect the integration._**
### Fixes
- More eye-droper fixes [#7019](https://github.com/excalidraw/excalidraw/pull/7019)
### Refactor
- Move excalidraw-app outside src [#6987](https://github.com/excalidraw/excalidraw/pull/6987)
---
## 0.16.0 (2023-09-19) ## 0.16.0 (2023-09-19)
- Support creating containers, linear elements, text containers, labelled arrows and arrow bindings programatically [#6546](https://github.com/excalidraw/excalidraw/pull/6546) - Support creating containers, linear elements, text containers, labelled arrows and arrow bindings programatically [#6546](https://github.com/excalidraw/excalidraw/pull/6546)

View File

@@ -1,6 +1,6 @@
{ {
"name": "@excalidraw/excalidraw", "name": "@excalidraw/excalidraw",
"version": "0.16.1", "version": "0.16.0",
"main": "main.js", "main": "main.js",
"types": "types/packages/excalidraw/index.d.ts", "types": "types/packages/excalidraw/index.d.ts",
"files": [ "files": [

View File

@@ -41,6 +41,14 @@ module.exports = {
"sass-loader", "sass-loader",
], ],
}, },
// So that type module works with webpack
// https://github.com/webpack/webpack/issues/11467#issuecomment-691873586
{
test: /\.m?js/,
resolve: {
fullySpecified: false,
},
},
{ {
test: /\.(ts|tsx|js|jsx|mjs)$/, test: /\.(ts|tsx|js|jsx|mjs)$/,
exclude: exclude:

View File

@@ -44,6 +44,14 @@ module.exports = {
"sass-loader", "sass-loader",
], ],
}, },
// So that type module works with webpack
// https://github.com/webpack/webpack/issues/11467#issuecomment-691873586
{
test: /\.m?js/,
resolve: {
fullySpecified: false,
},
},
{ {
test: /\.(ts|tsx|js|jsx|mjs)$/, test: /\.(ts|tsx|js|jsx|mjs)$/,
exclude: exclude:

View File

@@ -22,12 +22,5 @@ const polyfill = () => {
configurable: true, configurable: true,
}); });
} }
if (!Element.prototype.replaceChildren) {
Element.prototype.replaceChildren = function (...nodes) {
this.innerHTML = "";
this.append(...nodes);
};
}
}; };
export default polyfill; export default polyfill;

View File

@@ -0,0 +1,178 @@
import {
act,
fireEvent,
getTextEditor,
render,
updateTextEditor,
} from "./test-utils";
import { Excalidraw } from "../packages/excalidraw/index";
import React from "react";
import { expect, vi } from "vitest";
import * as MermaidToExcalidraw from "@excalidraw/mermaid-to-excalidraw";
vi.mock("@excalidraw/mermaid-to-excalidraw", async (importActual) => {
const module = (await importActual()) as any;
return {
__esModule: true,
...module,
};
});
const parseMermaidToExcalidrawSpy = vi.spyOn(
MermaidToExcalidraw,
"parseMermaidToExcalidraw",
);
parseMermaidToExcalidrawSpy.mockImplementation(
async (
definition: string,
options?: MermaidToExcalidraw.MermaidOptions | undefined,
) => {
const firstLine = definition.split("\n")[0];
return new Promise((resolve, reject) => {
if (firstLine === "flowchart TD") {
resolve({
elements: [
{
id: "Start",
type: "rectangle",
groupIds: [],
x: 0,
y: 0,
width: 69.703125,
height: 44,
strokeWidth: 2,
label: {
groupIds: [],
text: "Start",
fontSize: 20,
},
link: null,
},
{
id: "Stop",
type: "rectangle",
groupIds: [],
x: 2.7109375,
y: 94,
width: 64.28125,
height: 44,
strokeWidth: 2,
label: {
groupIds: [],
text: "Stop",
fontSize: 20,
},
link: null,
},
{
id: "Start_Stop",
type: "arrow",
groupIds: [],
x: 34.852,
y: 44,
strokeWidth: 2,
points: [
[0, 0],
[0, 50],
],
roundness: {
type: 2,
},
start: {
id: "Start",
},
end: {
id: "Stop",
},
},
],
});
} else {
reject(new Error("ERROR"));
}
});
},
);
vi.spyOn(React, "useRef").mockReturnValue({
current: {
parseMermaidToExcalidraw: parseMermaidToExcalidrawSpy,
},
});
describe("Test <MermaidToExcalidraw/>", () => {
beforeEach(async () => {
await render(
<Excalidraw
initialData={{
appState: {
activeTool: {
type: "mermaid",
lastActiveTool: null,
locked: false,
customType: null,
},
},
}}
/>,
);
});
it("should open mermaid popup when active tool is mermaid", async () => {
const dialog = document.querySelector(".dialog-mermaid")!;
expect(dialog.outerHTML).toMatchSnapshot();
});
it("should close the popup and set the tool to selection when close button clicked", () => {
const dialog = document.querySelector(".dialog-mermaid")!;
const closeBtn = dialog.querySelector(".Dialog__close")!;
fireEvent.click(closeBtn);
expect(document.querySelector(".dialog-mermaid")).toBe(null);
expect(window.h.state.activeTool).toStrictEqual({
customType: null,
lastActiveTool: null,
locked: false,
type: "selection",
});
});
it("should show error in preview when mermaid library throws error", async () => {
const dialog = document.querySelector(".dialog-mermaid")!;
const selector = ".mermaid-to-excalidraw-wrapper-text textarea";
const editor = getTextEditor(selector);
expect(dialog.querySelector('[data-testid="mermaid-error"]')).toBeNull();
expect(editor.textContent).toMatchInlineSnapshot(`
"flowchart TD
A[Christmas] -->|Get money| B(Go shopping)
B --> C{Let me think}
C -->|One| D[Laptop]
C -->|Two| E[iPhone]
C -->|Three| F[test]"
`);
await act(async () => {
updateTextEditor(editor, "flowchart TD1");
await new Promise((cb) => setTimeout(cb, 0));
});
expect(getTextEditor(selector).textContent).toBe("flowchart TD1");
expect(dialog.querySelector('[data-testid="mermaid-error"]'))
.toMatchInlineSnapshot(`
<div
data-testid="mermaid-error"
style="color: red; font-weight: 800; font-size: 30px; word-break: break-word; overflow: auto; max-height: 100%; text-align: center;"
>
Error!
<p
style="font-size: 18px; font-weight: 600;"
>
ERROR
</p>
</div>
`);
});
});

View File

@@ -0,0 +1,10 @@
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
exports[`Test <MermaidToExcalidraw/> > should open mermaid popup when active tool is mermaid 1`] = `
"<div class=\\"Modal Dialog dialog-mermaid\\" role=\\"dialog\\" aria-modal=\\"true\\" aria-labelledby=\\"dialog-title\\" data-prevent-outside-click=\\"true\\"><div class=\\"Modal__background\\"></div><div class=\\"Modal__content\\" style=\\"--max-width: 800px;\\" tabindex=\\"0\\"><div class=\\"Island\\"><h2 id=\\"test-id-dialog-title\\" class=\\"Dialog__title\\"><span class=\\"Dialog__titleContent\\"><p style=\\"margin-bottom: 5px; margin-top: 2px;\\">Mermaid to Excalidraw</p><span style=\\"font-size: 15px; font-style: italic; font-weight: 500;\\">Currently only <a href=\\"https://mermaid.js.org/syntax/flowchart.html\\">flowcharts</a> are supported. The other types will be rendered as image in Excalidraw.<br></span></span></h2><button class=\\"Dialog__close\\" title=\\"Close\\" aria-label=\\"Close\\"><svg aria-hidden=\\"true\\" focusable=\\"false\\" role=\\"img\\" viewBox=\\"0 0 20 20\\" class=\\"\\" fill=\\"none\\" stroke=\\"currentColor\\" stroke-linecap=\\"round\\" stroke-linejoin=\\"round\\"><g clip-path=\\"url(#a)\\" stroke=\\"currentColor\\" stroke-width=\\"1.25\\" stroke-linecap=\\"round\\" stroke-linejoin=\\"round\\"><path d=\\"M15 5 5 15M5 5l10 10\\"></path></g><defs><clipPath id=\\"a\\"><path fill=\\"#fff\\" d=\\"M0 0h20v20H0z\\"></path></clipPath></defs></svg></button><div class=\\"Dialog__content\\"><div class=\\"mermaid-to-excalidraw-wrapper\\"><div class=\\"mermaid-to-excalidraw-wrapper-text\\" style=\\"display: flex; flex-direction: column;\\"><label>Mermaid Syntax</label><textarea style=\\"padding: 0.85rem; border-radius: 8px; border: 1px solid #e4e4eb; white-space: pre-wrap;\\">flowchart TD
A[Christmas] --&gt;|Get money| B(Go shopping)
B --&gt; C{Let me think}
C --&gt;|One| D[Laptop]
C --&gt;|Two| E[iPhone]
C --&gt;|Three| F[test]</textarea></div><div class=\\"mermaid-to-excalidraw-wrapper-preview\\" style=\\"display: flex; flex-direction: column;\\"><label>Preview</label><div class=\\"mermaid-to-excalidraw-wrapper-preview-canvas\\"><div></div></div><button type=\\"button\\" class=\\"excalidraw-button mermaid-to-excalidraw-wrapper-preview-insert\\">Insert<span style=\\"padding-left: 8px; display: flex;\\"><svg aria-hidden=\\"true\\" focusable=\\"false\\" role=\\"img\\" viewBox=\\"0 0 20 20\\" class=\\"\\"><path d=\\"M4.16602 10H15.8327\\" stroke=\\"white\\" stroke-width=\\"1.25\\" stroke-linecap=\\"round\\" stroke-linejoin=\\"round\\"></path><path d=\\"M12.5 13.3333L15.8333 10\\" stroke=\\"white\\" stroke-width=\\"1.25\\" stroke-linecap=\\"round\\" stroke-linejoin=\\"round\\"></path><path d=\\"M12.5 6.66666L15.8333 9.99999\\" stroke=\\"white\\" stroke-width=\\"1.25\\" stroke-linecap=\\"round\\" stroke-linejoin=\\"round\\"></path></svg></span></button></div></div></div></div></div></div>"
`;

View File

@@ -274,7 +274,7 @@ describe("Test Linear Elements", () => {
// drag line from midpoint // drag line from midpoint
drag(midpoint, [midpoint[0] + delta, midpoint[1] + delta]); drag(midpoint, [midpoint[0] + delta, midpoint[1] + delta]);
expect(renderInteractiveScene).toHaveBeenCalledTimes(14); expect(renderInteractiveScene).toHaveBeenCalledTimes(13);
expect(renderStaticScene).toHaveBeenCalledTimes(6); expect(renderStaticScene).toHaveBeenCalledTimes(6);
expect(line.points.length).toEqual(3); expect(line.points.length).toEqual(3);
@@ -417,7 +417,7 @@ describe("Test Linear Elements", () => {
lastSegmentMidpoint[1] + delta, lastSegmentMidpoint[1] + delta,
]); ]);
expect(renderInteractiveScene).toHaveBeenCalledTimes(21); expect(renderInteractiveScene).toHaveBeenCalledTimes(19);
expect(renderStaticScene).toHaveBeenCalledTimes(9); expect(renderStaticScene).toHaveBeenCalledTimes(9);
expect(line.points.length).toEqual(5); expect(line.points.length).toEqual(5);
@@ -520,7 +520,7 @@ describe("Test Linear Elements", () => {
// delete 3rd point // delete 3rd point
deletePoint(points[2]); deletePoint(points[2]);
expect(line.points.length).toEqual(3); expect(line.points.length).toEqual(3);
expect(renderInteractiveScene).toHaveBeenCalledTimes(21); expect(renderInteractiveScene).toHaveBeenCalledTimes(20);
expect(renderStaticScene).toHaveBeenCalledTimes(9); expect(renderStaticScene).toHaveBeenCalledTimes(9);
const newMidPoints = LinearElementEditor.getEditorMidPoints( const newMidPoints = LinearElementEditor.getEditorMidPoints(
@@ -567,7 +567,7 @@ describe("Test Linear Elements", () => {
lastSegmentMidpoint[0] + delta, lastSegmentMidpoint[0] + delta,
lastSegmentMidpoint[1] + delta, lastSegmentMidpoint[1] + delta,
]); ]);
expect(renderInteractiveScene).toHaveBeenCalledTimes(21); expect(renderInteractiveScene).toHaveBeenCalledTimes(19);
expect(renderStaticScene).toHaveBeenCalledTimes(9); expect(renderStaticScene).toHaveBeenCalledTimes(9);
expect(line.points.length).toEqual(5); expect(line.points.length).toEqual(5);

View File

@@ -265,3 +265,15 @@ expect.extend({
}; };
}, },
}); });
export const updateTextEditor = (
editor: HTMLTextAreaElement,
value: string,
) => {
fireEvent.change(editor, { target: { value } });
editor.dispatchEvent(new Event("input"));
};
export const getTextEditor = (selector: string) => {
return document.querySelector(selector) as HTMLTextAreaElement;
};

View File

@@ -92,7 +92,8 @@ export type LastActiveTool =
| "eraser" | "eraser"
| "hand" | "hand"
| "frame" | "frame"
| "embeddable"; | "embeddable"
| "mermaid";
customType: null; customType: null;
} }
| { | {
@@ -200,7 +201,8 @@ export type AppState = {
| "eraser" | "eraser"
| "hand" | "hand"
| "frame" | "frame"
| "embeddable"; | "embeddable"
| "mermaid";
customType: null; customType: null;
} }
| { | {
@@ -527,6 +529,11 @@ export type AppClassProperties = {
onInsertElements: App["onInsertElements"]; onInsertElements: App["onInsertElements"];
onExportImage: App["onExportImage"]; onExportImage: App["onExportImage"];
lastViewportPosition: App["lastViewportPosition"]; lastViewportPosition: App["lastViewportPosition"];
scrollToContent: App["scrollToContent"];
addFiles: App["addFiles"];
setSelection: App["setSelection"];
addElementsFromPasteOrLibrary: App["addElementsFromPasteOrLibrary"];
setActiveTool: App["setActiveTool"];
}; };
export type PointerDownState = Readonly<{ export type PointerDownState = Readonly<{

View File

@@ -376,7 +376,8 @@ export const updateActiveTool = (
| "eraser" | "eraser"
| "hand" | "hand"
| "frame" | "frame"
| "embeddable"; | "embeddable"
| "mermaid";
} }
| { type: "custom"; customType: string } | { type: "custom"; customType: string }
) & { lastActiveToolBeforeEraser?: LastActiveTool }, ) & { lastActiveToolBeforeEraser?: LastActiveTool },

View File

@@ -6,7 +6,7 @@ export default defineConfig({
globals: true, globals: true,
environment: "jsdom", environment: "jsdom",
coverage: { coverage: {
reporter: ["text", "json-summary", "json"], reporter: ["text", "json-summary", "json", "html"],
lines: 70, lines: 70,
branches: 70, branches: 70,
functions: 68, functions: 68,

730
yarn.lock
View File

@@ -1270,6 +1270,11 @@
resolved "https://registry.yarnpkg.com/@braintree/sanitize-url/-/sanitize-url-6.0.2.tgz#6110f918d273fe2af8ea1c4398a88774bb9fc12f" resolved "https://registry.yarnpkg.com/@braintree/sanitize-url/-/sanitize-url-6.0.2.tgz#6110f918d273fe2af8ea1c4398a88774bb9fc12f"
integrity sha512-Tbsj02wXCbqGmzdnXNk0SOF19ChhRU70BsroIi4Pm6Ehp56in6vch94mfbdQ17DozxkL3BAVjbZ4Qc1a0HFRAg== integrity sha512-Tbsj02wXCbqGmzdnXNk0SOF19ChhRU70BsroIi4Pm6Ehp56in6vch94mfbdQ17DozxkL3BAVjbZ4Qc1a0HFRAg==
"@braintree/sanitize-url@^6.0.2":
version "6.0.4"
resolved "https://registry.yarnpkg.com/@braintree/sanitize-url/-/sanitize-url-6.0.4.tgz#923ca57e173c6b232bbbb07347b1be982f03e783"
integrity sha512-s3jaWicZd0pkP0jf5ysyHUI/RE7MHos6qlToFcGWXVp+ykHOy77OUMrfbgJ9it2C5bow7OIQwYYaHjk9XlBQ2A==
"@esbuild/android-arm64@0.17.19": "@esbuild/android-arm64@0.17.19":
version "0.17.19" version "0.17.19"
resolved "https://registry.yarnpkg.com/@esbuild/android-arm64/-/android-arm64-0.17.19.tgz#bafb75234a5d3d1b690e7c2956a599345e84a2fd" resolved "https://registry.yarnpkg.com/@esbuild/android-arm64/-/android-arm64-0.17.19.tgz#bafb75234a5d3d1b690e7c2956a599345e84a2fd"
@@ -1522,6 +1527,20 @@
resolved "https://registry.yarnpkg.com/@excalidraw/eslint-config/-/eslint-config-1.0.3.tgz#2122ef7413ae77874ae9848ce0f1c6b3f0d8bbbd" resolved "https://registry.yarnpkg.com/@excalidraw/eslint-config/-/eslint-config-1.0.3.tgz#2122ef7413ae77874ae9848ce0f1c6b3f0d8bbbd"
integrity sha512-GemHNF5Z6ga0BWBSX7GJaNBUchLu6RwTcAB84eX1MeckRNhNasAsPCdelDlFalz27iS4RuYEQh0bPE8SRxJgbQ== integrity sha512-GemHNF5Z6ga0BWBSX7GJaNBUchLu6RwTcAB84eX1MeckRNhNasAsPCdelDlFalz27iS4RuYEQh0bPE8SRxJgbQ==
"@excalidraw/markdown-to-text@0.1.2":
version "0.1.2"
resolved "https://registry.yarnpkg.com/@excalidraw/markdown-to-text/-/markdown-to-text-0.1.2.tgz#1703705e7da608cf478f17bfe96fb295f55a23eb"
integrity sha512-1nDXBNAojfi3oSFwJswKREkFm5wrSjqay81QlyRv2pkITG/XYB5v+oChENVBQLcxQwX4IUATWvXM5BcaNhPiIg==
"@excalidraw/mermaid-to-excalidraw@0.1.1":
version "0.1.1"
resolved "https://registry.yarnpkg.com/@excalidraw/mermaid-to-excalidraw/-/mermaid-to-excalidraw-0.1.1.tgz#1992f881b96d1994390333f4f67c22faf84a9a98"
integrity sha512-U/DQVWtznpWtXn1q0m3azBx6Dz/wPYaz6LUu5WJNHxnAmnL/b0O/Yq1q5cwcp5VRQ0B5JgXtS2zJVipIheJ8og==
dependencies:
"@excalidraw/markdown-to-text" "0.1.2"
mermaid "10.2.3"
nanoid "4.0.2"
"@excalidraw/prettier-config@1.0.2": "@excalidraw/prettier-config@1.0.2":
version "1.0.2" version "1.0.2"
resolved "https://registry.yarnpkg.com/@excalidraw/prettier-config/-/prettier-config-1.0.2.tgz#b7c061c99cee2f78b9ca470ea1fbd602683bba65" resolved "https://registry.yarnpkg.com/@excalidraw/prettier-config/-/prettier-config-1.0.2.tgz#b7c061c99cee2f78b9ca470ea1fbd602683bba65"
@@ -2500,6 +2519,13 @@
resolved "https://registry.yarnpkg.com/@types/chai/-/chai-4.3.0.tgz#23509ebc1fa32f1b4d50d6a66c4032d5b8eaabdc" resolved "https://registry.yarnpkg.com/@types/chai/-/chai-4.3.0.tgz#23509ebc1fa32f1b4d50d6a66c4032d5b8eaabdc"
integrity sha512-/ceqdqeRraGolFTcfoXNiqjyQhZzbINDngeoAq9GoHa8PPK1yNzTaxWjA6BFWp5Ua9JpXEMSS4s5i9tS0hOJtw== integrity sha512-/ceqdqeRraGolFTcfoXNiqjyQhZzbINDngeoAq9GoHa8PPK1yNzTaxWjA6BFWp5Ua9JpXEMSS4s5i9tS0hOJtw==
"@types/debug@^4.0.0":
version "4.1.8"
resolved "https://registry.yarnpkg.com/@types/debug/-/debug-4.1.8.tgz#cef723a5d0a90990313faec2d1e22aee5eecb317"
integrity sha512-/vPO1EPOs306Cvhwv7KfVfYvOJqA/S/AXjaHQiJboCZzcNDb+TIJFN9/2C9DZ//ijSKWioNyUxD792QmDJ+HKQ==
dependencies:
"@types/ms" "*"
"@types/estree@0.0.39": "@types/estree@0.0.39":
version "0.0.39" version "0.0.39"
resolved "https://registry.yarnpkg.com/@types/estree/-/estree-0.0.39.tgz#e177e699ee1b8c22d23174caaa7422644389509f" resolved "https://registry.yarnpkg.com/@types/estree/-/estree-0.0.39.tgz#e177e699ee1b8c22d23174caaa7422644389509f"
@@ -2572,6 +2598,18 @@
resolved "https://registry.yarnpkg.com/@types/long/-/long-4.0.2.tgz#b74129719fc8d11c01868010082d483b7545591a" resolved "https://registry.yarnpkg.com/@types/long/-/long-4.0.2.tgz#b74129719fc8d11c01868010082d483b7545591a"
integrity sha512-MqTGEo5bj5t157U6fA/BiDynNkn0YknVdh48CMPkTSpFTVmvao5UQmm7uEF6xBEo7qIMAlY/JSleYaE6VOdpaA== integrity sha512-MqTGEo5bj5t157U6fA/BiDynNkn0YknVdh48CMPkTSpFTVmvao5UQmm7uEF6xBEo7qIMAlY/JSleYaE6VOdpaA==
"@types/mdast@^3.0.0":
version "3.0.12"
resolved "https://registry.yarnpkg.com/@types/mdast/-/mdast-3.0.12.tgz#beeb511b977c875a5b0cc92eab6fcac2f0895514"
integrity sha512-DT+iNIRNX884cx0/Q1ja7NyUPpZuv0KPyL5rGNxm1WC1OtHstl7n4Jb7nk+xacNShQMbczJjt8uFzznpp6kYBg==
dependencies:
"@types/unist" "^2"
"@types/ms@*":
version "0.7.31"
resolved "https://registry.yarnpkg.com/@types/ms/-/ms-0.7.31.tgz#31b7ca6407128a3d2bbc27fe2d21b345397f6197"
integrity sha512-iiUgKzV9AuaEkZqkOLDIvlQiL6ltuZd9tGcW3gwpnX8JbuiuhFlEGmmFXEXkN50Cvq7Os88IY2v0dkDqXYWVgA==
"@types/node@*", "@types/node@>=12.12.47", "@types/node@>=13.7.0": "@types/node@*", "@types/node@>=12.12.47", "@types/node@>=13.7.0":
version "18.15.11" version "18.15.11"
resolved "https://registry.yarnpkg.com/@types/node/-/node-18.15.11.tgz#b3b790f09cb1696cffcec605de025b088fa4225f" resolved "https://registry.yarnpkg.com/@types/node/-/node-18.15.11.tgz#b3b790f09cb1696cffcec605de025b088fa4225f"
@@ -2682,6 +2720,11 @@
resolved "https://registry.yarnpkg.com/@types/trusted-types/-/trusted-types-2.0.3.tgz#a136f83b0758698df454e328759dbd3d44555311" resolved "https://registry.yarnpkg.com/@types/trusted-types/-/trusted-types-2.0.3.tgz#a136f83b0758698df454e328759dbd3d44555311"
integrity sha512-NfQ4gyz38SL8sDNrSixxU2Os1a5xcdFxipAFxYEuLUlvU2uDwS4NUpsImcf1//SlWItCVMMLiylsxbmNMToV/g== integrity sha512-NfQ4gyz38SL8sDNrSixxU2Os1a5xcdFxipAFxYEuLUlvU2uDwS4NUpsImcf1//SlWItCVMMLiylsxbmNMToV/g==
"@types/unist@^2", "@types/unist@^2.0.0":
version "2.0.7"
resolved "https://registry.yarnpkg.com/@types/unist/-/unist-2.0.7.tgz#5b06ad6894b236a1d2bd6b2f07850ca5c59cf4d6"
integrity sha512-cputDpIbFgLUaGQn6Vqg3/YsJwxUwHLO13v3i5ouxT4lat0khip9AEWxtERujXV9wxIB1EyF97BSJFt6vpdI8g==
"@types/yargs-parser@*": "@types/yargs-parser@*":
version "21.0.0" version "21.0.0"
resolved "https://registry.yarnpkg.com/@types/yargs-parser/-/yargs-parser-21.0.0.tgz#0c60e537fa790f5f9472ed2776c2b71ec117351b" resolved "https://registry.yarnpkg.com/@types/yargs-parser/-/yargs-parser-21.0.0.tgz#0c60e537fa790f5f9472ed2776c2b71ec117351b"
@@ -3375,6 +3418,11 @@ chalk@^4.0.0, chalk@^4.0.2, chalk@^4.1.0, chalk@^4.1.1, chalk@^4.1.2:
ansi-styles "^4.1.0" ansi-styles "^4.1.0"
supports-color "^7.1.0" supports-color "^7.1.0"
character-entities@^2.0.0:
version "2.0.2"
resolved "https://registry.yarnpkg.com/character-entities/-/character-entities-2.0.2.tgz#2d09c2e72cd9523076ccb21157dff66ad43fcc22"
integrity sha512-shx7oQ0Awen/BRIdkjkvz54PnEEI/EjwXDSIZp86/KKdbafHh1Df/RYGBhn4hbe2+uKC9FnT5UCEdyPz3ai9hQ==
check-error@^1.0.2: check-error@^1.0.2:
version "1.0.2" version "1.0.2"
resolved "https://registry.yarnpkg.com/check-error/-/check-error-1.0.2.tgz#574d312edd88bb5dd8912e9286dd6c0aed4aac82" resolved "https://registry.yarnpkg.com/check-error/-/check-error-1.0.2.tgz#574d312edd88bb5dd8912e9286dd6c0aed4aac82"
@@ -3478,6 +3526,11 @@ combined-stream@^1.0.8:
dependencies: dependencies:
delayed-stream "~1.0.0" delayed-stream "~1.0.0"
commander@7:
version "7.2.0"
resolved "https://registry.yarnpkg.com/commander/-/commander-7.2.0.tgz#a36cb57d0b501ce108e4d20559a150a391d97ab7"
integrity sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==
commander@^2.20.0: commander@^2.20.0:
version "2.20.3" version "2.20.3"
resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33" resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33"
@@ -3545,6 +3598,20 @@ corser@^2.0.1:
resolved "https://registry.yarnpkg.com/corser/-/corser-2.0.1.tgz#8eda252ecaab5840dcd975ceb90d9370c819ff87" resolved "https://registry.yarnpkg.com/corser/-/corser-2.0.1.tgz#8eda252ecaab5840dcd975ceb90d9370c819ff87"
integrity sha512-utCYNzRSQIZNPIcGZdQc92UVJYAhtGAteCFg0yRaFm8f0P+CPtyGyHXJcGXnffjCybUCEx3FQ2G7U3/o9eIkVQ== integrity sha512-utCYNzRSQIZNPIcGZdQc92UVJYAhtGAteCFg0yRaFm8f0P+CPtyGyHXJcGXnffjCybUCEx3FQ2G7U3/o9eIkVQ==
cose-base@^1.0.0:
version "1.0.3"
resolved "https://registry.yarnpkg.com/cose-base/-/cose-base-1.0.3.tgz#650334b41b869578a543358b80cda7e0abe0a60a"
integrity sha512-s9whTXInMSgAp/NVXVNuVxVKzGH2qck3aQlVHxDCdAEPgtMKwc4Wq6/QKhgdEdgbLSi9rBTAcPoRa6JpiG4ksg==
dependencies:
layout-base "^1.0.0"
cose-base@^2.2.0:
version "2.2.0"
resolved "https://registry.yarnpkg.com/cose-base/-/cose-base-2.2.0.tgz#1c395c35b6e10bb83f9769ca8b817d614add5c01"
integrity sha512-AzlgcsCbUMymkADOJtQm3wO9S3ltPfYOFD5033keQn9NJzIbtnZj+UdBJe7DYml/8TdbtHJW3j58SOnKhWY/5g==
dependencies:
layout-base "^2.0.0"
cosmiconfig@^7.0.0, cosmiconfig@^7.0.1: cosmiconfig@^7.0.0, cosmiconfig@^7.0.1:
version "7.1.0" version "7.1.0"
resolved "https://registry.yarnpkg.com/cosmiconfig/-/cosmiconfig-7.1.0.tgz#1443b9afa596b670082ea46cbd8f6a62b84635f6" resolved "https://registry.yarnpkg.com/cosmiconfig/-/cosmiconfig-7.1.0.tgz#1443b9afa596b670082ea46cbd8f6a62b84635f6"
@@ -3613,6 +3680,280 @@ csstype@^3.0.2:
resolved "https://registry.yarnpkg.com/csstype/-/csstype-3.1.2.tgz#1d4bf9d572f11c14031f0436e1c10bc1f571f50b" resolved "https://registry.yarnpkg.com/csstype/-/csstype-3.1.2.tgz#1d4bf9d572f11c14031f0436e1c10bc1f571f50b"
integrity sha512-I7K1Uu0MBPzaFKg4nI5Q7Vs2t+3gWWW648spaF+Rg7pI9ds18Ugn+lvg4SHczUdKlHI5LWBXyqfS8+DufyBsgQ== integrity sha512-I7K1Uu0MBPzaFKg4nI5Q7Vs2t+3gWWW648spaF+Rg7pI9ds18Ugn+lvg4SHczUdKlHI5LWBXyqfS8+DufyBsgQ==
cytoscape-cose-bilkent@^4.1.0:
version "4.1.0"
resolved "https://registry.yarnpkg.com/cytoscape-cose-bilkent/-/cytoscape-cose-bilkent-4.1.0.tgz#762fa121df9930ffeb51a495d87917c570ac209b"
integrity sha512-wgQlVIUJF13Quxiv5e1gstZ08rnZj2XaLHGoFMYXz7SkNfCDOOteKBE6SYRfA9WxxI/iBc3ajfDoc6hb/MRAHQ==
dependencies:
cose-base "^1.0.0"
cytoscape-fcose@^2.1.0:
version "2.2.0"
resolved "https://registry.yarnpkg.com/cytoscape-fcose/-/cytoscape-fcose-2.2.0.tgz#e4d6f6490df4fab58ae9cea9e5c3ab8d7472f471"
integrity sha512-ki1/VuRIHFCzxWNrsshHYPs6L7TvLu3DL+TyIGEsRcvVERmxokbf5Gdk7mFxZnTdiGtnA4cfSmjZJMviqSuZrQ==
dependencies:
cose-base "^2.2.0"
cytoscape@^3.23.0:
version "3.26.0"
resolved "https://registry.yarnpkg.com/cytoscape/-/cytoscape-3.26.0.tgz#b4c6961445fd51e1fd3cca83c3ffe924d9a8abc9"
integrity sha512-IV+crL+KBcrCnVVUCZW+zRRRFUZQcrtdOPXki+o4CFUWLdAEYvuZLcBSJC9EBK++suamERKzeY7roq2hdovV3w==
dependencies:
heap "^0.2.6"
lodash "^4.17.21"
"d3-array@2 - 3", "d3-array@2.10.0 - 3", "d3-array@2.5.0 - 3", d3-array@3, d3-array@^3.2.0:
version "3.2.4"
resolved "https://registry.yarnpkg.com/d3-array/-/d3-array-3.2.4.tgz#15fec33b237f97ac5d7c986dc77da273a8ed0bb5"
integrity sha512-tdQAmyA18i4J7wprpYq8ClcxZy3SC31QMeByyCFyRt7BVHdREQZ5lpzoe5mFEYZUWe+oq8HBvk9JjpibyEV4Jg==
dependencies:
internmap "1 - 2"
d3-axis@3:
version "3.0.0"
resolved "https://registry.yarnpkg.com/d3-axis/-/d3-axis-3.0.0.tgz#c42a4a13e8131d637b745fc2973824cfeaf93322"
integrity sha512-IH5tgjV4jE/GhHkRV0HiVYPDtvfjHQlQfJHs0usq7M30XcSBvOotpmH1IgkcXsO/5gEQZD43B//fc7SRT5S+xw==
d3-brush@3:
version "3.0.0"
resolved "https://registry.yarnpkg.com/d3-brush/-/d3-brush-3.0.0.tgz#6f767c4ed8dcb79de7ede3e1c0f89e63ef64d31c"
integrity sha512-ALnjWlVYkXsVIGlOsuWH1+3udkYFI48Ljihfnh8FZPF2QS9o+PzGLBslO0PjzVoHLZ2KCVgAM8NVkXPJB2aNnQ==
dependencies:
d3-dispatch "1 - 3"
d3-drag "2 - 3"
d3-interpolate "1 - 3"
d3-selection "3"
d3-transition "3"
d3-chord@3:
version "3.0.1"
resolved "https://registry.yarnpkg.com/d3-chord/-/d3-chord-3.0.1.tgz#d156d61f485fce8327e6abf339cb41d8cbba6966"
integrity sha512-VE5S6TNa+j8msksl7HwjxMHDM2yNK3XCkusIlpX5kwauBfXuyLAtNg9jCp/iHH61tgI4sb6R/EIMWCqEIdjT/g==
dependencies:
d3-path "1 - 3"
"d3-color@1 - 3", d3-color@3:
version "3.1.0"
resolved "https://registry.yarnpkg.com/d3-color/-/d3-color-3.1.0.tgz#395b2833dfac71507f12ac2f7af23bf819de24e2"
integrity sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA==
d3-contour@4:
version "4.0.2"
resolved "https://registry.yarnpkg.com/d3-contour/-/d3-contour-4.0.2.tgz#bb92063bc8c5663acb2422f99c73cbb6c6ae3bcc"
integrity sha512-4EzFTRIikzs47RGmdxbeUvLWtGedDUNkTcmzoeyg4sP/dvCexO47AaQL7VKy/gul85TOxw+IBgA8US2xwbToNA==
dependencies:
d3-array "^3.2.0"
d3-delaunay@6:
version "6.0.4"
resolved "https://registry.yarnpkg.com/d3-delaunay/-/d3-delaunay-6.0.4.tgz#98169038733a0a5babbeda55054f795bb9e4a58b"
integrity sha512-mdjtIZ1XLAM8bm/hx3WwjfHt6Sggek7qH043O8KEjDXN40xi3vx/6pYSVTwLjEgiXQTbvaouWKynLBiUZ6SK6A==
dependencies:
delaunator "5"
"d3-dispatch@1 - 3", d3-dispatch@3:
version "3.0.1"
resolved "https://registry.yarnpkg.com/d3-dispatch/-/d3-dispatch-3.0.1.tgz#5fc75284e9c2375c36c839411a0cf550cbfc4d5e"
integrity sha512-rzUyPU/S7rwUflMyLc1ETDeBj0NRuHKKAcvukozwhshr6g6c5d8zh4c2gQjY2bZ0dXeGLWc1PF174P2tVvKhfg==
"d3-drag@2 - 3", d3-drag@3:
version "3.0.0"
resolved "https://registry.yarnpkg.com/d3-drag/-/d3-drag-3.0.0.tgz#994aae9cd23c719f53b5e10e3a0a6108c69607ba"
integrity sha512-pWbUJLdETVA8lQNJecMxoXfH6x+mO2UQo8rSmZ+QqxcbyA3hfeprFgIT//HW2nlHChWeIIMwS2Fq+gEARkhTkg==
dependencies:
d3-dispatch "1 - 3"
d3-selection "3"
"d3-dsv@1 - 3", d3-dsv@3:
version "3.0.1"
resolved "https://registry.yarnpkg.com/d3-dsv/-/d3-dsv-3.0.1.tgz#c63af978f4d6a0d084a52a673922be2160789b73"
integrity sha512-UG6OvdI5afDIFP9w4G0mNq50dSOsXHJaRE8arAS5o9ApWnIElp8GZw1Dun8vP8OyHOZ/QJUKUJwxiiCCnUwm+Q==
dependencies:
commander "7"
iconv-lite "0.6"
rw "1"
"d3-ease@1 - 3", d3-ease@3:
version "3.0.1"
resolved "https://registry.yarnpkg.com/d3-ease/-/d3-ease-3.0.1.tgz#9658ac38a2140d59d346160f1f6c30fda0bd12f4"
integrity sha512-wR/XK3D3XcLIZwpbvQwQ5fK+8Ykds1ip7A2Txe0yxncXSdq1L9skcG7blcedkOX+ZcgxGAmLX1FrRGbADwzi0w==
d3-fetch@3:
version "3.0.1"
resolved "https://registry.yarnpkg.com/d3-fetch/-/d3-fetch-3.0.1.tgz#83141bff9856a0edb5e38de89cdcfe63d0a60a22"
integrity sha512-kpkQIM20n3oLVBKGg6oHrUchHM3xODkTzjMoj7aWQFq5QEM+R6E4WkzT5+tojDY7yjez8KgCBRoj4aEr99Fdqw==
dependencies:
d3-dsv "1 - 3"
d3-force@3:
version "3.0.0"
resolved "https://registry.yarnpkg.com/d3-force/-/d3-force-3.0.0.tgz#3e2ba1a61e70888fe3d9194e30d6d14eece155c4"
integrity sha512-zxV/SsA+U4yte8051P4ECydjD/S+qeYtnaIyAs9tgHCqfguma/aAQDjo85A9Z6EKhBirHRJHXIgJUlffT4wdLg==
dependencies:
d3-dispatch "1 - 3"
d3-quadtree "1 - 3"
d3-timer "1 - 3"
"d3-format@1 - 3", d3-format@3:
version "3.1.0"
resolved "https://registry.yarnpkg.com/d3-format/-/d3-format-3.1.0.tgz#9260e23a28ea5cb109e93b21a06e24e2ebd55641"
integrity sha512-YyUI6AEuY/Wpt8KWLgZHsIU86atmikuoOmCfommt0LYHiQSPjvX2AcFc38PX0CBpr2RCyZhjex+NS/LPOv6YqA==
d3-geo@3:
version "3.1.0"
resolved "https://registry.yarnpkg.com/d3-geo/-/d3-geo-3.1.0.tgz#74fd54e1f4cebd5185ac2039217a98d39b0a4c0e"
integrity sha512-JEo5HxXDdDYXCaWdwLRt79y7giK8SbhZJbFWXqbRTolCHFI5jRqteLzCsq51NKbUoX0PjBVSohxrx+NoOUujYA==
dependencies:
d3-array "2.5.0 - 3"
d3-hierarchy@3:
version "3.1.2"
resolved "https://registry.yarnpkg.com/d3-hierarchy/-/d3-hierarchy-3.1.2.tgz#b01cd42c1eed3d46db77a5966cf726f8c09160c6"
integrity sha512-FX/9frcub54beBdugHjDCdikxThEqjnR93Qt7PvQTOHxyiNCAlvMrHhclk3cD5VeAaq9fxmfRp+CnWw9rEMBuA==
"d3-interpolate@1 - 3", "d3-interpolate@1.2.0 - 3", d3-interpolate@3:
version "3.0.1"
resolved "https://registry.yarnpkg.com/d3-interpolate/-/d3-interpolate-3.0.1.tgz#3c47aa5b32c5b3dfb56ef3fd4342078a632b400d"
integrity sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g==
dependencies:
d3-color "1 - 3"
"d3-path@1 - 3", d3-path@3, d3-path@^3.1.0:
version "3.1.0"
resolved "https://registry.yarnpkg.com/d3-path/-/d3-path-3.1.0.tgz#22df939032fb5a71ae8b1800d61ddb7851c42526"
integrity sha512-p3KP5HCf/bvjBSSKuXid6Zqijx7wIfNW+J/maPs+iwR35at5JCbLUT0LzF1cnjbCHWhqzQTIN2Jpe8pRebIEFQ==
d3-polygon@3:
version "3.0.1"
resolved "https://registry.yarnpkg.com/d3-polygon/-/d3-polygon-3.0.1.tgz#0b45d3dd1c48a29c8e057e6135693ec80bf16398"
integrity sha512-3vbA7vXYwfe1SYhED++fPUQlWSYTTGmFmQiany/gdbiWgU/iEyQzyymwL9SkJjFFuCS4902BSzewVGsHHmHtXg==
"d3-quadtree@1 - 3", d3-quadtree@3:
version "3.0.1"
resolved "https://registry.yarnpkg.com/d3-quadtree/-/d3-quadtree-3.0.1.tgz#6dca3e8be2b393c9a9d514dabbd80a92deef1a4f"
integrity sha512-04xDrxQTDTCFwP5H6hRhsRcb9xxv2RzkcsygFzmkSIOJy3PeRJP7sNk3VRIbKXcog561P9oU0/rVH6vDROAgUw==
d3-random@3:
version "3.0.1"
resolved "https://registry.yarnpkg.com/d3-random/-/d3-random-3.0.1.tgz#d4926378d333d9c0bfd1e6fa0194d30aebaa20f4"
integrity sha512-FXMe9GfxTxqd5D6jFsQ+DJ8BJS4E/fT5mqqdjovykEB2oFbTMDVdg1MGFxfQW+FBOGoB++k8swBrgwSHT1cUXQ==
d3-scale-chromatic@3:
version "3.0.0"
resolved "https://registry.yarnpkg.com/d3-scale-chromatic/-/d3-scale-chromatic-3.0.0.tgz#15b4ceb8ca2bb0dcb6d1a641ee03d59c3b62376a"
integrity sha512-Lx9thtxAKrO2Pq6OO2Ua474opeziKr279P/TKZsMAhYyNDD3EnCffdbgeSYN5O7m2ByQsxtuP2CSDczNUIZ22g==
dependencies:
d3-color "1 - 3"
d3-interpolate "1 - 3"
d3-scale@4:
version "4.0.2"
resolved "https://registry.yarnpkg.com/d3-scale/-/d3-scale-4.0.2.tgz#82b38e8e8ff7080764f8dcec77bd4be393689396"
integrity sha512-GZW464g1SH7ag3Y7hXjf8RoUuAFIqklOAq3MRl4OaWabTFJY9PN/E1YklhXLh+OQ3fM9yS2nOkCoS+WLZ6kvxQ==
dependencies:
d3-array "2.10.0 - 3"
d3-format "1 - 3"
d3-interpolate "1.2.0 - 3"
d3-time "2.1.1 - 3"
d3-time-format "2 - 4"
"d3-selection@2 - 3", d3-selection@3:
version "3.0.0"
resolved "https://registry.yarnpkg.com/d3-selection/-/d3-selection-3.0.0.tgz#c25338207efa72cc5b9bd1458a1a41901f1e1b31"
integrity sha512-fmTRWbNMmsmWq6xJV8D19U/gw/bwrHfNXxrIN+HfZgnzqTHp9jOmKMhsTUjXOJnZOdZY9Q28y4yebKzqDKlxlQ==
d3-shape@3:
version "3.2.0"
resolved "https://registry.yarnpkg.com/d3-shape/-/d3-shape-3.2.0.tgz#a1a839cbd9ba45f28674c69d7f855bcf91dfc6a5"
integrity sha512-SaLBuwGm3MOViRq2ABk3eLoxwZELpH6zhl3FbAoJ7Vm1gofKx6El1Ib5z23NUEhF9AsGl7y+dzLe5Cw2AArGTA==
dependencies:
d3-path "^3.1.0"
"d3-time-format@2 - 4", d3-time-format@4:
version "4.1.0"
resolved "https://registry.yarnpkg.com/d3-time-format/-/d3-time-format-4.1.0.tgz#7ab5257a5041d11ecb4fe70a5c7d16a195bb408a"
integrity sha512-dJxPBlzC7NugB2PDLwo9Q8JiTR3M3e4/XANkreKSUxF8vvXKqm1Yfq4Q5dl8budlunRVlUUaDUgFt7eA8D6NLg==
dependencies:
d3-time "1 - 3"
"d3-time@1 - 3", "d3-time@2.1.1 - 3", d3-time@3:
version "3.1.0"
resolved "https://registry.yarnpkg.com/d3-time/-/d3-time-3.1.0.tgz#9310db56e992e3c0175e1ef385e545e48a9bb5c7"
integrity sha512-VqKjzBLejbSMT4IgbmVgDjpkYrNWUYJnbCGo874u7MMKIWsILRX+OpX/gTk8MqjpT1A/c6HY2dCA77ZN0lkQ2Q==
dependencies:
d3-array "2 - 3"
"d3-timer@1 - 3", d3-timer@3:
version "3.0.1"
resolved "https://registry.yarnpkg.com/d3-timer/-/d3-timer-3.0.1.tgz#6284d2a2708285b1abb7e201eda4380af35e63b0"
integrity sha512-ndfJ/JxxMd3nw31uyKoY2naivF+r29V+Lc0svZxe1JvvIRmi8hUsrMvdOwgS1o6uBHmiz91geQ0ylPP0aj1VUA==
"d3-transition@2 - 3", d3-transition@3:
version "3.0.1"
resolved "https://registry.yarnpkg.com/d3-transition/-/d3-transition-3.0.1.tgz#6869fdde1448868077fdd5989200cb61b2a1645f"
integrity sha512-ApKvfjsSR6tg06xrL434C0WydLr7JewBB3V+/39RMHsaXTOG0zmt/OAXeng5M5LBm0ojmxJrpomQVZ1aPvBL4w==
dependencies:
d3-color "1 - 3"
d3-dispatch "1 - 3"
d3-ease "1 - 3"
d3-interpolate "1 - 3"
d3-timer "1 - 3"
d3-zoom@3:
version "3.0.0"
resolved "https://registry.yarnpkg.com/d3-zoom/-/d3-zoom-3.0.0.tgz#d13f4165c73217ffeaa54295cd6969b3e7aee8f3"
integrity sha512-b8AmV3kfQaqWAuacbPuNbL6vahnOJflOhexLzMMNLga62+/nh0JzvJ0aO/5a5MVgUFGS7Hu1P9P03o3fJkDCyw==
dependencies:
d3-dispatch "1 - 3"
d3-drag "2 - 3"
d3-interpolate "1 - 3"
d3-selection "2 - 3"
d3-transition "2 - 3"
d3@^7.4.0, d3@^7.8.2:
version "7.8.5"
resolved "https://registry.yarnpkg.com/d3/-/d3-7.8.5.tgz#fde4b760d4486cdb6f0cc8e2cbff318af844635c"
integrity sha512-JgoahDG51ncUfJu6wX/1vWQEqOflgXyl4MaHqlcSruTez7yhaRKR9i8VjjcQGeS2en/jnFivXuaIMnseMMt0XA==
dependencies:
d3-array "3"
d3-axis "3"
d3-brush "3"
d3-chord "3"
d3-color "3"
d3-contour "4"
d3-delaunay "6"
d3-dispatch "3"
d3-drag "3"
d3-dsv "3"
d3-ease "3"
d3-fetch "3"
d3-force "3"
d3-format "3"
d3-geo "3"
d3-hierarchy "3"
d3-interpolate "3"
d3-path "3"
d3-polygon "3"
d3-quadtree "3"
d3-random "3"
d3-scale "4"
d3-scale-chromatic "3"
d3-selection "3"
d3-shape "3"
d3-time "3"
d3-time-format "4"
d3-timer "3"
d3-transition "3"
d3-zoom "3"
dagre-d3-es@7.0.10:
version "7.0.10"
resolved "https://registry.yarnpkg.com/dagre-d3-es/-/dagre-d3-es-7.0.10.tgz#19800d4be674379a3cd8c86a8216a2ac6827cadc"
integrity sha512-qTCQmEhcynucuaZgY5/+ti3X/rnszKZhEQH/ZdWdtP1tA/y3VoHJzcVrO9pjjJCNpigfscAtoUB5ONcd2wNn0A==
dependencies:
d3 "^7.8.2"
lodash-es "^4.17.21"
damerau-levenshtein@^1.0.8: damerau-levenshtein@^1.0.8:
version "1.0.8" version "1.0.8"
resolved "https://registry.yarnpkg.com/damerau-levenshtein/-/damerau-levenshtein-1.0.8.tgz#b43d286ccbd36bc5b2f7ed41caf2d0aba1f8a6e7" resolved "https://registry.yarnpkg.com/damerau-levenshtein/-/damerau-levenshtein-1.0.8.tgz#b43d286ccbd36bc5b2f7ed41caf2d0aba1f8a6e7"
@@ -3627,7 +3968,12 @@ data-urls@^4.0.0:
whatwg-mimetype "^3.0.0" whatwg-mimetype "^3.0.0"
whatwg-url "^12.0.0" whatwg-url "^12.0.0"
debug@4, debug@^4.0.1, debug@^4.1.0, debug@^4.1.1, debug@^4.3.3, debug@^4.3.4: dayjs@^1.11.7:
version "1.11.9"
resolved "https://registry.yarnpkg.com/dayjs/-/dayjs-1.11.9.tgz#9ca491933fadd0a60a2c19f6c237c03517d71d1a"
integrity sha512-QvzAURSbQ0pKdIye2txOzNaHmxtUBXerpY0FJsFXUMKbIZeFm5ht1LS/jFsrncjnmtv8HsG0W2g6c0zUjZWmpA==
debug@4, debug@^4.0.0, debug@^4.0.1, debug@^4.1.0, debug@^4.1.1, debug@^4.3.3, debug@^4.3.4:
version "4.3.4" version "4.3.4"
resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865" resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865"
integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ== integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==
@@ -3653,6 +3999,13 @@ decimal.js@^10.4.3:
resolved "https://registry.yarnpkg.com/decimal.js/-/decimal.js-10.4.3.tgz#1044092884d245d1b7f65725fa4ad4c6f781cc23" resolved "https://registry.yarnpkg.com/decimal.js/-/decimal.js-10.4.3.tgz#1044092884d245d1b7f65725fa4ad4c6f781cc23"
integrity sha512-VBBaLc1MgL5XpzgIP7ny5Z6Nx3UrRkIViUkPUdtl9aya5amy3De1gsUUSB1g3+3sExYNjCAsAznmukyxCb1GRA== integrity sha512-VBBaLc1MgL5XpzgIP7ny5Z6Nx3UrRkIViUkPUdtl9aya5amy3De1gsUUSB1g3+3sExYNjCAsAznmukyxCb1GRA==
decode-named-character-reference@^1.0.0:
version "1.0.2"
resolved "https://registry.yarnpkg.com/decode-named-character-reference/-/decode-named-character-reference-1.0.2.tgz#daabac9690874c394c81e4162a0304b35d824f0e"
integrity sha512-O8x12RzrUF8xyVcY0KJowWsmaJxQbmy0/EtnNtHRpsOcT7dFk5W598coHqBVpmWo1oQQfsCqfCmkZN5DJrZVdg==
dependencies:
character-entities "^2.0.0"
decode-uri-component@^0.2.0: decode-uri-component@^0.2.0:
version "0.2.2" version "0.2.2"
resolved "https://registry.yarnpkg.com/decode-uri-component/-/decode-uri-component-0.2.2.tgz#e69dbe25d37941171dd540e024c444cd5188e1e9" resolved "https://registry.yarnpkg.com/decode-uri-component/-/decode-uri-component-0.2.2.tgz#e69dbe25d37941171dd540e024c444cd5188e1e9"
@@ -3713,11 +4066,23 @@ define-properties@^1.1.3, define-properties@^1.1.4:
has-property-descriptors "^1.0.0" has-property-descriptors "^1.0.0"
object-keys "^1.1.1" object-keys "^1.1.1"
delaunator@5:
version "5.0.0"
resolved "https://registry.yarnpkg.com/delaunator/-/delaunator-5.0.0.tgz#60f052b28bd91c9b4566850ebf7756efe821d81b"
integrity sha512-AyLvtyJdbv/U1GkiS6gUUzclRoAY4Gs75qkMygJJhU75LW4DNuSF2RMzpxs9jw9Oz1BobHjTdkG3zdP55VxAqw==
dependencies:
robust-predicates "^3.0.0"
delayed-stream@~1.0.0: delayed-stream@~1.0.0:
version "1.0.0" version "1.0.0"
resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619"
integrity sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ== integrity sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==
dequal@^2.0.0:
version "2.0.3"
resolved "https://registry.yarnpkg.com/dequal/-/dequal-2.0.3.tgz#2644214f1997d39ed0ee0ece72335490a7ac67be"
integrity sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==
detect-node-es@^1.1.0: detect-node-es@^1.1.0:
version "1.1.0" version "1.1.0"
resolved "https://registry.yarnpkg.com/detect-node-es/-/detect-node-es-1.1.0.tgz#163acdf643330caa0b4cd7c21e7ee7755d6fa493" resolved "https://registry.yarnpkg.com/detect-node-es/-/detect-node-es-1.1.0.tgz#163acdf643330caa0b4cd7c21e7ee7755d6fa493"
@@ -3733,6 +4098,11 @@ diff-sequences@^29.4.3:
resolved "https://registry.yarnpkg.com/diff-sequences/-/diff-sequences-29.4.3.tgz#9314bc1fabe09267ffeca9cbafc457d8499a13f2" resolved "https://registry.yarnpkg.com/diff-sequences/-/diff-sequences-29.4.3.tgz#9314bc1fabe09267ffeca9cbafc457d8499a13f2"
integrity sha512-ofrBgwpPhCD85kMKtE9RYFFq6OC1A89oW2vvgWZNCwxrUpRUILopY7lsYyMDSjc8g6U6aiO0Qubg6r4Wgt5ZnA== integrity sha512-ofrBgwpPhCD85kMKtE9RYFFq6OC1A89oW2vvgWZNCwxrUpRUILopY7lsYyMDSjc8g6U6aiO0Qubg6r4Wgt5ZnA==
diff@^5.0.0:
version "5.1.0"
resolved "https://registry.yarnpkg.com/diff/-/diff-5.1.0.tgz#bc52d298c5ea8df9194800224445ed43ffc87e40"
integrity sha512-D+mk+qE8VC/PAUrlAU34N+VfXev0ghe5ywmpqrawphmVZc1bEfn56uo9qpyGp1p4xpzOHkSW4ztBd6L7Xx4ACw==
dir-glob@^3.0.1: dir-glob@^3.0.1:
version "3.0.1" version "3.0.1"
resolved "https://registry.yarnpkg.com/dir-glob/-/dir-glob-3.0.1.tgz#56dbf73d992a4a93ba1584f4534063fd2e41717f" resolved "https://registry.yarnpkg.com/dir-glob/-/dir-glob-3.0.1.tgz#56dbf73d992a4a93ba1584f4534063fd2e41717f"
@@ -3778,6 +4148,11 @@ domexception@^4.0.0:
dependencies: dependencies:
webidl-conversions "^7.0.0" webidl-conversions "^7.0.0"
dompurify@3.0.3:
version "3.0.3"
resolved "https://registry.yarnpkg.com/dompurify/-/dompurify-3.0.3.tgz#4b115d15a091ddc96f232bcef668550a2f6f1430"
integrity sha512-axQ9zieHLnAnHh0sfAamKYiqXMJAVwu+LM/alQ7WDagoWessyWvMSFyW65CqF3owufNu8HBcE4cM2Vflu7YWcQ==
dotenv@16.0.1: dotenv@16.0.1:
version "16.0.1" version "16.0.1"
resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-16.0.1.tgz#8f8f9d94876c35dac989876a5d3a82a267fdce1d" resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-16.0.1.tgz#8f8f9d94876c35dac989876a5d3a82a267fdce1d"
@@ -3800,6 +4175,11 @@ electron-to-chromium@^1.4.284:
resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.359.tgz#5c4d13cb08032469fcd6bd36457915caa211356b" resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.359.tgz#5c4d13cb08032469fcd6bd36457915caa211356b"
integrity sha512-OoVcngKCIuNXtZnsYoqlCvr0Cf3NIPzDIgwUfI9bdTFjXCrr79lI0kwQstLPZ7WhCezLlGksZk/BFAzoXC7GDw== integrity sha512-OoVcngKCIuNXtZnsYoqlCvr0Cf3NIPzDIgwUfI9bdTFjXCrr79lI0kwQstLPZ7WhCezLlGksZk/BFAzoXC7GDw==
elkjs@^0.8.2:
version "0.8.2"
resolved "https://registry.yarnpkg.com/elkjs/-/elkjs-0.8.2.tgz#c37763c5a3e24e042e318455e0147c912a7c248e"
integrity sha512-L6uRgvZTH+4OF5NE/MBbzQx/WYpru1xCBE9respNj6qznEewGUIfhzmm7horWWxbNO2M0WckQypGctR8lH79xQ==
emoji-regex@^8.0.0: emoji-regex@^8.0.0:
version "8.0.0" version "8.0.0"
resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37" resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37"
@@ -4691,6 +5071,11 @@ he@^1.2.0:
resolved "https://registry.yarnpkg.com/he/-/he-1.2.0.tgz#84ae65fa7eafb165fddb61566ae14baf05664f0f" resolved "https://registry.yarnpkg.com/he/-/he-1.2.0.tgz#84ae65fa7eafb165fddb61566ae14baf05664f0f"
integrity sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw== integrity sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==
heap@^0.2.6:
version "0.2.7"
resolved "https://registry.yarnpkg.com/heap/-/heap-0.2.7.tgz#1e6adf711d3f27ce35a81fe3b7bd576c2260a8fc"
integrity sha512-2bsegYkkHO+h/9MGbn6KWcE45cHZgPANo5LXF7EvWdT0yT2EguSVO1nDgU5c8+ZOPwp2vMNa7YFsJhVcDR9Sdg==
html-encoding-sniffer@^3.0.0: html-encoding-sniffer@^3.0.0:
version "3.0.0" version "3.0.0"
resolved "https://registry.yarnpkg.com/html-encoding-sniffer/-/html-encoding-sniffer-3.0.0.tgz#2cb1a8cf0db52414776e5b2a7a04d5dd98158de9" resolved "https://registry.yarnpkg.com/html-encoding-sniffer/-/html-encoding-sniffer-3.0.0.tgz#2cb1a8cf0db52414776e5b2a7a04d5dd98158de9"
@@ -4770,7 +5155,7 @@ i18next-browser-languagedetector@6.1.4:
dependencies: dependencies:
"@babel/runtime" "^7.14.6" "@babel/runtime" "^7.14.6"
iconv-lite@0.6.3: iconv-lite@0.6, iconv-lite@0.6.3:
version "0.6.3" version "0.6.3"
resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.6.3.tgz#a52f80bf38da1952eb5c681790719871a1a72501" resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.6.3.tgz#a52f80bf38da1952eb5c681790719871a1a72501"
integrity sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw== integrity sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==
@@ -4866,6 +5251,11 @@ internal-slot@^1.0.3, internal-slot@^1.0.4, internal-slot@^1.0.5:
has "^1.0.3" has "^1.0.3"
side-channel "^1.0.4" side-channel "^1.0.4"
"internmap@1 - 2":
version "2.0.3"
resolved "https://registry.yarnpkg.com/internmap/-/internmap-2.0.3.tgz#6685f23755e43c524e251d29cbc97248e3061009"
integrity sha512-5Hh7Y1wQbvY5ooGgPbDaL5iYLAPzMTUrjMulskHLH6wnv/A+1q5rgEaiuqEjB+oxGXIVZs1FF+R/KPN3ZSQYYg==
invariant@^2.2.4: invariant@^2.2.4:
version "2.2.4" version "2.2.4"
resolved "https://registry.yarnpkg.com/invariant/-/invariant-2.2.4.tgz#610f3c92c9359ce1db616e538008d23ff35158e6" resolved "https://registry.yarnpkg.com/invariant/-/invariant-2.2.4.tgz#610f3c92c9359ce1db616e538008d23ff35158e6"
@@ -5338,6 +5728,16 @@ jsonpointer@^5.0.0:
array-includes "^3.1.5" array-includes "^3.1.5"
object.assign "^4.1.3" object.assign "^4.1.3"
khroma@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/khroma/-/khroma-2.0.0.tgz#7577de98aed9f36c7a474c4d453d94c0d6c6588b"
integrity sha512-2J8rDNlQWbtiNYThZRvmMv5yt44ZakX+Tz5ZIp/mN1pt4snn+m030Va5Z4v8xA0cQFDXBwO/8i42xL4QPsVk3g==
kleur@^4.0.3:
version "4.1.5"
resolved "https://registry.yarnpkg.com/kleur/-/kleur-4.1.5.tgz#95106101795f7050c6c650f350c683febddb1780"
integrity sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ==
language-subtag-registry@~0.3.2: language-subtag-registry@~0.3.2:
version "0.3.22" version "0.3.22"
resolved "https://registry.yarnpkg.com/language-subtag-registry/-/language-subtag-registry-0.3.22.tgz#2e1500861b2e457eba7e7ae86877cbd08fa1fd1d" resolved "https://registry.yarnpkg.com/language-subtag-registry/-/language-subtag-registry-0.3.22.tgz#2e1500861b2e457eba7e7ae86877cbd08fa1fd1d"
@@ -5350,6 +5750,16 @@ language-tags@=1.0.5:
dependencies: dependencies:
language-subtag-registry "~0.3.2" language-subtag-registry "~0.3.2"
layout-base@^1.0.0:
version "1.0.2"
resolved "https://registry.yarnpkg.com/layout-base/-/layout-base-1.0.2.tgz#1291e296883c322a9dd4c5dd82063721b53e26e2"
integrity sha512-8h2oVEZNktL4BH2JCOI90iD1yXwL6iNW7KcCKT2QZgQJR2vbqDsldCTPRU9NifTCqHZci57XvQQ15YTu+sTYPg==
layout-base@^2.0.0:
version "2.0.1"
resolved "https://registry.yarnpkg.com/layout-base/-/layout-base-2.0.1.tgz#d0337913586c90f9c2c075292069f5c2da5dd285"
integrity sha512-dp3s92+uNI1hWIpPGH3jK2kxE2lMjdXdr+DH8ynZHpd6PUlH6x6cbuXnoMmiNumznqaNO31xu9e79F0uuZ0JFg==
leven@^3.1.0: leven@^3.1.0:
version "3.1.0" version "3.1.0"
resolved "https://registry.yarnpkg.com/leven/-/leven-3.1.0.tgz#77891de834064cccba82ae7842bb6b14a13ed7f2" resolved "https://registry.yarnpkg.com/leven/-/leven-3.1.0.tgz#77891de834064cccba82ae7842bb6b14a13ed7f2"
@@ -5426,6 +5836,11 @@ localforage@^1.8.1:
dependencies: dependencies:
lie "3.1.1" lie "3.1.1"
lodash-es@^4.17.21:
version "4.17.21"
resolved "https://registry.yarnpkg.com/lodash-es/-/lodash-es-4.17.21.tgz#43e626c46e6591b7750beb2b50117390c609e3ee"
integrity sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==
lodash.camelcase@^4.3.0: lodash.camelcase@^4.3.0:
version "4.3.0" version "4.3.0"
resolved "https://registry.yarnpkg.com/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz#b28aa6288a2b9fc651035c7711f65ab6190331a6" resolved "https://registry.yarnpkg.com/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz#b28aa6288a2b9fc651035c7711f65ab6190331a6"
@@ -5547,6 +5962,31 @@ make-dir@^4.0.0:
dependencies: dependencies:
semver "^7.5.3" semver "^7.5.3"
mdast-util-from-markdown@^1.3.0:
version "1.3.1"
resolved "https://registry.yarnpkg.com/mdast-util-from-markdown/-/mdast-util-from-markdown-1.3.1.tgz#9421a5a247f10d31d2faed2a30df5ec89ceafcf0"
integrity sha512-4xTO/M8c82qBcnQc1tgpNtubGUW/Y1tBQ1B0i5CtSoelOLKFYlElIr3bvgREYYO5iRqbMY1YuqZng0GVOI8Qww==
dependencies:
"@types/mdast" "^3.0.0"
"@types/unist" "^2.0.0"
decode-named-character-reference "^1.0.0"
mdast-util-to-string "^3.1.0"
micromark "^3.0.0"
micromark-util-decode-numeric-character-reference "^1.0.0"
micromark-util-decode-string "^1.0.0"
micromark-util-normalize-identifier "^1.0.0"
micromark-util-symbol "^1.0.0"
micromark-util-types "^1.0.0"
unist-util-stringify-position "^3.0.0"
uvu "^0.5.0"
mdast-util-to-string@^3.1.0:
version "3.2.0"
resolved "https://registry.yarnpkg.com/mdast-util-to-string/-/mdast-util-to-string-3.2.0.tgz#66f7bb6324756741c5f47a53557f0cbf16b6f789"
integrity sha512-V4Zn/ncyN1QNSqSBxTrMOLpjr+IKdHl2v3KVLoWmDPscP4r9GcCi71gjgvUV1SFSKh92AjAG4peFuBl2/YgCJg==
dependencies:
"@types/mdast" "^3.0.0"
merge-stream@^2.0.0: merge-stream@^2.0.0:
version "2.0.0" version "2.0.0"
resolved "https://registry.yarnpkg.com/merge-stream/-/merge-stream-2.0.0.tgz#52823629a14dd00c9770fb6ad47dc6310f2c1f60" resolved "https://registry.yarnpkg.com/merge-stream/-/merge-stream-2.0.0.tgz#52823629a14dd00c9770fb6ad47dc6310f2c1f60"
@@ -5557,6 +5997,223 @@ merge2@^1.3.0, merge2@^1.4.1:
resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.4.1.tgz#4368892f885e907455a6fd7dc55c0c9d404990ae" resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.4.1.tgz#4368892f885e907455a6fd7dc55c0c9d404990ae"
integrity sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg== integrity sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==
mermaid@10.2.3:
version "10.2.3"
resolved "https://registry.yarnpkg.com/mermaid/-/mermaid-10.2.3.tgz#789d3b582c5da8c69aa4a7c0e2b826562c8c8b12"
integrity sha512-cMVE5s9PlQvOwfORkyVpr5beMsLdInrycAosdr+tpZ0WFjG4RJ/bUHST7aTgHNJbujHkdBRAm+N50P3puQOfPw==
dependencies:
"@braintree/sanitize-url" "^6.0.2"
cytoscape "^3.23.0"
cytoscape-cose-bilkent "^4.1.0"
cytoscape-fcose "^2.1.0"
d3 "^7.4.0"
dagre-d3-es "7.0.10"
dayjs "^1.11.7"
dompurify "3.0.3"
elkjs "^0.8.2"
khroma "^2.0.0"
lodash-es "^4.17.21"
mdast-util-from-markdown "^1.3.0"
non-layered-tidy-tree-layout "^2.0.2"
stylis "^4.1.3"
ts-dedent "^2.2.0"
uuid "^9.0.0"
web-worker "^1.2.0"
micromark-core-commonmark@^1.0.1:
version "1.1.0"
resolved "https://registry.yarnpkg.com/micromark-core-commonmark/-/micromark-core-commonmark-1.1.0.tgz#1386628df59946b2d39fb2edfd10f3e8e0a75bb8"
integrity sha512-BgHO1aRbolh2hcrzL2d1La37V0Aoz73ymF8rAcKnohLy93titmv62E0gP8Hrx9PKcKrqCZ1BbLGbP3bEhoXYlw==
dependencies:
decode-named-character-reference "^1.0.0"
micromark-factory-destination "^1.0.0"
micromark-factory-label "^1.0.0"
micromark-factory-space "^1.0.0"
micromark-factory-title "^1.0.0"
micromark-factory-whitespace "^1.0.0"
micromark-util-character "^1.0.0"
micromark-util-chunked "^1.0.0"
micromark-util-classify-character "^1.0.0"
micromark-util-html-tag-name "^1.0.0"
micromark-util-normalize-identifier "^1.0.0"
micromark-util-resolve-all "^1.0.0"
micromark-util-subtokenize "^1.0.0"
micromark-util-symbol "^1.0.0"
micromark-util-types "^1.0.1"
uvu "^0.5.0"
micromark-factory-destination@^1.0.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/micromark-factory-destination/-/micromark-factory-destination-1.1.0.tgz#eb815957d83e6d44479b3df640f010edad667b9f"
integrity sha512-XaNDROBgx9SgSChd69pjiGKbV+nfHGDPVYFs5dOoDd7ZnMAE+Cuu91BCpsY8RT2NP9vo/B8pds2VQNCLiu0zhg==
dependencies:
micromark-util-character "^1.0.0"
micromark-util-symbol "^1.0.0"
micromark-util-types "^1.0.0"
micromark-factory-label@^1.0.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/micromark-factory-label/-/micromark-factory-label-1.1.0.tgz#cc95d5478269085cfa2a7282b3de26eb2e2dec68"
integrity sha512-OLtyez4vZo/1NjxGhcpDSbHQ+m0IIGnT8BoPamh+7jVlzLJBH98zzuCoUeMxvM6WsNeh8wx8cKvqLiPHEACn0w==
dependencies:
micromark-util-character "^1.0.0"
micromark-util-symbol "^1.0.0"
micromark-util-types "^1.0.0"
uvu "^0.5.0"
micromark-factory-space@^1.0.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/micromark-factory-space/-/micromark-factory-space-1.1.0.tgz#c8f40b0640a0150751d3345ed885a080b0d15faf"
integrity sha512-cRzEj7c0OL4Mw2v6nwzttyOZe8XY/Z8G0rzmWQZTBi/jjwyw/U4uqKtUORXQrR5bAZZnbTI/feRV/R7hc4jQYQ==
dependencies:
micromark-util-character "^1.0.0"
micromark-util-types "^1.0.0"
micromark-factory-title@^1.0.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/micromark-factory-title/-/micromark-factory-title-1.1.0.tgz#dd0fe951d7a0ac71bdc5ee13e5d1465ad7f50ea1"
integrity sha512-J7n9R3vMmgjDOCY8NPw55jiyaQnH5kBdV2/UXCtZIpnHH3P6nHUKaH7XXEYuWwx/xUJcawa8plLBEjMPU24HzQ==
dependencies:
micromark-factory-space "^1.0.0"
micromark-util-character "^1.0.0"
micromark-util-symbol "^1.0.0"
micromark-util-types "^1.0.0"
micromark-factory-whitespace@^1.0.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/micromark-factory-whitespace/-/micromark-factory-whitespace-1.1.0.tgz#798fb7489f4c8abafa7ca77eed6b5745853c9705"
integrity sha512-v2WlmiymVSp5oMg+1Q0N1Lxmt6pMhIHD457whWM7/GUlEks1hI9xj5w3zbc4uuMKXGisksZk8DzP2UyGbGqNsQ==
dependencies:
micromark-factory-space "^1.0.0"
micromark-util-character "^1.0.0"
micromark-util-symbol "^1.0.0"
micromark-util-types "^1.0.0"
micromark-util-character@^1.0.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/micromark-util-character/-/micromark-util-character-1.2.0.tgz#4fedaa3646db249bc58caeb000eb3549a8ca5dcc"
integrity sha512-lXraTwcX3yH/vMDaFWCQJP1uIszLVebzUa3ZHdrgxr7KEU/9mL4mVgCpGbyhvNLNlauROiNUq7WN5u7ndbY6xg==
dependencies:
micromark-util-symbol "^1.0.0"
micromark-util-types "^1.0.0"
micromark-util-chunked@^1.0.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/micromark-util-chunked/-/micromark-util-chunked-1.1.0.tgz#37a24d33333c8c69a74ba12a14651fd9ea8a368b"
integrity sha512-Ye01HXpkZPNcV6FiyoW2fGZDUw4Yc7vT0E9Sad83+bEDiCJ1uXu0S3mr8WLpsz3HaG3x2q0HM6CTuPdcZcluFQ==
dependencies:
micromark-util-symbol "^1.0.0"
micromark-util-classify-character@^1.0.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/micromark-util-classify-character/-/micromark-util-classify-character-1.1.0.tgz#6a7f8c8838e8a120c8e3c4f2ae97a2bff9190e9d"
integrity sha512-SL0wLxtKSnklKSUplok1WQFoGhUdWYKggKUiqhX+Swala+BtptGCu5iPRc+xvzJ4PXE/hwM3FNXsfEVgoZsWbw==
dependencies:
micromark-util-character "^1.0.0"
micromark-util-symbol "^1.0.0"
micromark-util-types "^1.0.0"
micromark-util-combine-extensions@^1.0.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/micromark-util-combine-extensions/-/micromark-util-combine-extensions-1.1.0.tgz#192e2b3d6567660a85f735e54d8ea6e3952dbe84"
integrity sha512-Q20sp4mfNf9yEqDL50WwuWZHUrCO4fEyeDCnMGmG5Pr0Cz15Uo7KBs6jq+dq0EgX4DPwwrh9m0X+zPV1ypFvUA==
dependencies:
micromark-util-chunked "^1.0.0"
micromark-util-types "^1.0.0"
micromark-util-decode-numeric-character-reference@^1.0.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/micromark-util-decode-numeric-character-reference/-/micromark-util-decode-numeric-character-reference-1.1.0.tgz#b1e6e17009b1f20bc652a521309c5f22c85eb1c6"
integrity sha512-m9V0ExGv0jB1OT21mrWcuf4QhP46pH1KkfWy9ZEezqHKAxkj4mPCy3nIH1rkbdMlChLHX531eOrymlwyZIf2iw==
dependencies:
micromark-util-symbol "^1.0.0"
micromark-util-decode-string@^1.0.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/micromark-util-decode-string/-/micromark-util-decode-string-1.1.0.tgz#dc12b078cba7a3ff690d0203f95b5d5537f2809c"
integrity sha512-YphLGCK8gM1tG1bd54azwyrQRjCFcmgj2S2GoJDNnh4vYtnL38JS8M4gpxzOPNyHdNEpheyWXCTnnTDY3N+NVQ==
dependencies:
decode-named-character-reference "^1.0.0"
micromark-util-character "^1.0.0"
micromark-util-decode-numeric-character-reference "^1.0.0"
micromark-util-symbol "^1.0.0"
micromark-util-encode@^1.0.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/micromark-util-encode/-/micromark-util-encode-1.1.0.tgz#92e4f565fd4ccb19e0dcae1afab9a173bbeb19a5"
integrity sha512-EuEzTWSTAj9PA5GOAs992GzNh2dGQO52UvAbtSOMvXTxv3Criqb6IOzJUBCmEqrrXSblJIJBbFFv6zPxpreiJw==
micromark-util-html-tag-name@^1.0.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/micromark-util-html-tag-name/-/micromark-util-html-tag-name-1.2.0.tgz#48fd7a25826f29d2f71479d3b4e83e94829b3588"
integrity sha512-VTQzcuQgFUD7yYztuQFKXT49KghjtETQ+Wv/zUjGSGBioZnkA4P1XXZPT1FHeJA6RwRXSF47yvJ1tsJdoxwO+Q==
micromark-util-normalize-identifier@^1.0.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/micromark-util-normalize-identifier/-/micromark-util-normalize-identifier-1.1.0.tgz#7a73f824eb9f10d442b4d7f120fecb9b38ebf8b7"
integrity sha512-N+w5vhqrBihhjdpM8+5Xsxy71QWqGn7HYNUvch71iV2PM7+E3uWGox1Qp90loa1ephtCxG2ftRV/Conitc6P2Q==
dependencies:
micromark-util-symbol "^1.0.0"
micromark-util-resolve-all@^1.0.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/micromark-util-resolve-all/-/micromark-util-resolve-all-1.1.0.tgz#4652a591ee8c8fa06714c9b54cd6c8e693671188"
integrity sha512-b/G6BTMSg+bX+xVCshPTPyAu2tmA0E4X98NSR7eIbeC6ycCqCeE7wjfDIgzEbkzdEVJXRtOG4FbEm/uGbCRouA==
dependencies:
micromark-util-types "^1.0.0"
micromark-util-sanitize-uri@^1.0.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/micromark-util-sanitize-uri/-/micromark-util-sanitize-uri-1.2.0.tgz#613f738e4400c6eedbc53590c67b197e30d7f90d"
integrity sha512-QO4GXv0XZfWey4pYFndLUKEAktKkG5kZTdUNaTAkzbuJxn2tNBOr+QtxR2XpWaMhbImT2dPzyLrPXLlPhph34A==
dependencies:
micromark-util-character "^1.0.0"
micromark-util-encode "^1.0.0"
micromark-util-symbol "^1.0.0"
micromark-util-subtokenize@^1.0.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/micromark-util-subtokenize/-/micromark-util-subtokenize-1.1.0.tgz#941c74f93a93eaf687b9054aeb94642b0e92edb1"
integrity sha512-kUQHyzRoxvZO2PuLzMt2P/dwVsTiivCK8icYTeR+3WgbuPqfHgPPy7nFKbeqRivBvn/3N3GBiNC+JRTMSxEC7A==
dependencies:
micromark-util-chunked "^1.0.0"
micromark-util-symbol "^1.0.0"
micromark-util-types "^1.0.0"
uvu "^0.5.0"
micromark-util-symbol@^1.0.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/micromark-util-symbol/-/micromark-util-symbol-1.1.0.tgz#813cd17837bdb912d069a12ebe3a44b6f7063142"
integrity sha512-uEjpEYY6KMs1g7QfJ2eX1SQEV+ZT4rUD3UcF6l57acZvLNK7PBZL+ty82Z1qhK1/yXIY4bdx04FKMgR0g4IAag==
micromark-util-types@^1.0.0, micromark-util-types@^1.0.1:
version "1.1.0"
resolved "https://registry.yarnpkg.com/micromark-util-types/-/micromark-util-types-1.1.0.tgz#e6676a8cae0bb86a2171c498167971886cb7e283"
integrity sha512-ukRBgie8TIAcacscVHSiddHjO4k/q3pnedmzMQ4iwDcK0FtFCohKOlFbaOL/mPgfnPsL3C1ZyxJa4sbWrBl3jg==
micromark@^3.0.0:
version "3.2.0"
resolved "https://registry.yarnpkg.com/micromark/-/micromark-3.2.0.tgz#1af9fef3f995ea1ea4ac9c7e2f19c48fd5c006e9"
integrity sha512-uD66tJj54JLYq0De10AhWycZWGQNUvDI55xPgk2sQM5kn1JYlhbCMTtEeT27+vAhW2FBQxLlOmS3pmA7/2z4aA==
dependencies:
"@types/debug" "^4.0.0"
debug "^4.0.0"
decode-named-character-reference "^1.0.0"
micromark-core-commonmark "^1.0.1"
micromark-factory-space "^1.0.0"
micromark-util-character "^1.0.0"
micromark-util-chunked "^1.0.0"
micromark-util-combine-extensions "^1.0.0"
micromark-util-decode-numeric-character-reference "^1.0.0"
micromark-util-encode "^1.0.0"
micromark-util-normalize-identifier "^1.0.0"
micromark-util-resolve-all "^1.0.0"
micromark-util-sanitize-uri "^1.0.0"
micromark-util-subtokenize "^1.0.0"
micromark-util-symbol "^1.0.0"
micromark-util-types "^1.0.1"
uvu "^0.5.0"
micromatch@^4.0.4: micromatch@^4.0.4:
version "4.0.5" version "4.0.5"
resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.5.tgz#bc8999a7cbbf77cdc89f132f6e467051b49090c6" resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.5.tgz#bc8999a7cbbf77cdc89f132f6e467051b49090c6"
@@ -5635,6 +6292,11 @@ moo-color@^1.0.2:
dependencies: dependencies:
color-name "^1.1.4" color-name "^1.1.4"
mri@^1.1.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/mri/-/mri-1.2.0.tgz#6721480fec2a11a4889861115a48b6cbe7cc8f0b"
integrity sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA==
mrmime@^1.0.0: mrmime@^1.0.0:
version "1.0.1" version "1.0.1"
resolved "https://registry.yarnpkg.com/mrmime/-/mrmime-1.0.1.tgz#5f90c825fad4bdd41dc914eff5d1a8cfdaf24f27" resolved "https://registry.yarnpkg.com/mrmime/-/mrmime-1.0.1.tgz#5f90c825fad4bdd41dc914eff5d1a8cfdaf24f27"
@@ -5668,6 +6330,11 @@ nanoid@3.3.3:
resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.3.tgz#fd8e8b7aa761fe807dba2d1b98fb7241bb724a25" resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.3.tgz#fd8e8b7aa761fe807dba2d1b98fb7241bb724a25"
integrity sha512-p1sjXuopFs0xg+fPASzQ28agW1oHD7xDsd9Xkf3T15H3c/cifrFHVwrh74PdoklAPi+i7MdRsE47vm2r6JoB+w== integrity sha512-p1sjXuopFs0xg+fPASzQ28agW1oHD7xDsd9Xkf3T15H3c/cifrFHVwrh74PdoklAPi+i7MdRsE47vm2r6JoB+w==
nanoid@4.0.2:
version "4.0.2"
resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-4.0.2.tgz#140b3c5003959adbebf521c170f282c5e7f9fb9e"
integrity sha512-7ZtY5KTCNheRGfEFxnedV5zFiORN1+Y1N6zvPTnHQd8ENUvfaDBeuJDZb2bN/oXwXxu3qkTXDzy57W5vAmDTBw==
nanoid@^3.3.6: nanoid@^3.3.6:
version "3.3.6" version "3.3.6"
resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.6.tgz#443380c856d6e9f9824267d960b4236ad583ea4c" resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.6.tgz#443380c856d6e9f9824267d960b4236ad583ea4c"
@@ -5693,6 +6360,11 @@ node-releases@^2.0.8:
resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.10.tgz#c311ebae3b6a148c89b1813fd7c4d3c024ef537f" resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.10.tgz#c311ebae3b6a148c89b1813fd7c4d3c024ef537f"
integrity sha512-5GFldHPXVG/YZmFzJvKK2zDSzPKhEp0+ZR5SVaoSag9fsL5YgHbUHDfnG5494ISANDcK4KwPXAx2xqVEydmd7w== integrity sha512-5GFldHPXVG/YZmFzJvKK2zDSzPKhEp0+ZR5SVaoSag9fsL5YgHbUHDfnG5494ISANDcK4KwPXAx2xqVEydmd7w==
non-layered-tidy-tree-layout@^2.0.2:
version "2.0.2"
resolved "https://registry.yarnpkg.com/non-layered-tidy-tree-layout/-/non-layered-tidy-tree-layout-2.0.2.tgz#57d35d13c356643fc296a55fb11ac15e74da7804"
integrity sha512-gkXMxRzUH+PB0ax9dUN0yYF0S25BqeAYqhgMaLUFmpXLEk7Fcu8f4emJuOAY0V8kjDICxROIKsTAKsV/v355xw==
normalize-path@^3.0.0, normalize-path@~3.0.0: normalize-path@^3.0.0, normalize-path@~3.0.0:
version "3.0.0" version "3.0.0"
resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65" resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65"
@@ -6362,6 +7034,11 @@ rimraf@^3.0.2:
dependencies: dependencies:
glob "^7.1.3" glob "^7.1.3"
robust-predicates@^3.0.0:
version "3.0.2"
resolved "https://registry.yarnpkg.com/robust-predicates/-/robust-predicates-3.0.2.tgz#d5b28528c4824d20fc48df1928d41d9efa1ad771"
integrity sha512-IXgzBWvWQwE6PrDI05OvmXUIruQTcoMDzRsOd5CDvHCVLcLHMTSYvOK5Cm46kWqlV3yAbuSpBZdJ5oP5OUoStg==
rollup-plugin-terser@^7.0.0: rollup-plugin-terser@^7.0.0:
version "7.0.2" version "7.0.2"
resolved "https://registry.yarnpkg.com/rollup-plugin-terser/-/rollup-plugin-terser-7.0.2.tgz#e8fbba4869981b2dc35ae7e8a502d5c6c04d324d" resolved "https://registry.yarnpkg.com/rollup-plugin-terser/-/rollup-plugin-terser-7.0.2.tgz#e8fbba4869981b2dc35ae7e8a502d5c6c04d324d"
@@ -6414,6 +7091,11 @@ run-parallel@^1.1.9:
dependencies: dependencies:
queue-microtask "^1.2.2" queue-microtask "^1.2.2"
rw@1:
version "1.3.3"
resolved "https://registry.yarnpkg.com/rw/-/rw-1.3.3.tgz#3f862dfa91ab766b14885ef4d01124bfda074fb4"
integrity sha512-PdhdWy89SiZogBLaw42zdeqtRJ//zFd2PgQavcICDUgJT5oW10QCRKbJ6bg4r0/UY2M6BWd5tkxuGFRvCkgfHQ==
rxjs@^7.5.5: rxjs@^7.5.5:
version "7.8.0" version "7.8.0"
resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-7.8.0.tgz#90a938862a82888ff4c7359811a595e14e1e09a4" resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-7.8.0.tgz#90a938862a82888ff4c7359811a595e14e1e09a4"
@@ -6421,6 +7103,13 @@ rxjs@^7.5.5:
dependencies: dependencies:
tslib "^2.1.0" tslib "^2.1.0"
sade@^1.7.3:
version "1.8.1"
resolved "https://registry.yarnpkg.com/sade/-/sade-1.8.1.tgz#0a78e81d658d394887be57d2a409bf703a3b2701"
integrity sha512-xal3CZX1Xlo/k4ApwCFrHVACi9fBqJ7V+mwhBsuf/1IOKbBy098Fex+Wa/5QMubw09pSZ/u8EY8PWgevJsXp1A==
dependencies:
mri "^1.1.0"
safari-14-idb-fix@^3.0.0: safari-14-idb-fix@^3.0.0:
version "3.0.0" version "3.0.0"
resolved "https://registry.yarnpkg.com/safari-14-idb-fix/-/safari-14-idb-fix-3.0.0.tgz#450fc049b996ec7f3fd9ca2f89d32e0761583440" resolved "https://registry.yarnpkg.com/safari-14-idb-fix/-/safari-14-idb-fix-3.0.0.tgz#450fc049b996ec7f3fd9ca2f89d32e0761583440"
@@ -6799,6 +7488,11 @@ strip-literal@^1.0.1:
dependencies: dependencies:
acorn "^8.8.2" acorn "^8.8.2"
stylis@^4.1.3:
version "4.3.0"
resolved "https://registry.yarnpkg.com/stylis/-/stylis-4.3.0.tgz#abe305a669fc3d8777e10eefcfc73ad861c5588c"
integrity sha512-E87pIogpwUsUwXw7dNyU4QDjdgVMy52m+XEOPEKUn161cCzWjjhPSQhByfd1CcNvrOLnXQ6OnnZDwnJrz/Z4YQ==
supports-color@^5.3.0: supports-color@^5.3.0:
version "5.5.0" version "5.5.0"
resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f" resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f"
@@ -6961,6 +7655,11 @@ tr46@^4.1.1:
dependencies: dependencies:
punycode "^2.3.0" punycode "^2.3.0"
ts-dedent@^2.2.0:
version "2.2.0"
resolved "https://registry.yarnpkg.com/ts-dedent/-/ts-dedent-2.2.0.tgz#39e4bd297cd036292ae2394eb3412be63f563bb5"
integrity sha512-q5W7tVM71e2xjHZTlgfTDoPF/SmqKG5hddq9SzR49CH2hayqRKJtQ4mtRlSxKaJlR/+9rEM+mnBHf7I2/BQcpQ==
tsconfig-paths@^3.14.1: tsconfig-paths@^3.14.1:
version "3.14.2" version "3.14.2"
resolved "https://registry.yarnpkg.com/tsconfig-paths/-/tsconfig-paths-3.14.2.tgz#6e32f1f79412decd261f92d633a9dc1cfa99f088" resolved "https://registry.yarnpkg.com/tsconfig-paths/-/tsconfig-paths-3.14.2.tgz#6e32f1f79412decd261f92d633a9dc1cfa99f088"
@@ -7102,6 +7801,13 @@ unique-string@^2.0.0:
dependencies: dependencies:
crypto-random-string "^2.0.0" crypto-random-string "^2.0.0"
unist-util-stringify-position@^3.0.0:
version "3.0.3"
resolved "https://registry.yarnpkg.com/unist-util-stringify-position/-/unist-util-stringify-position-3.0.3.tgz#03ad3348210c2d930772d64b489580c13a7db39d"
integrity sha512-k5GzIBZ/QatR8N5X2y+drfpWG8IDBzdnVj6OInRNWm1oXrzydiaAT2OQiA8DPRRZyAKb9b6I2a6PxYklZD0gKg==
dependencies:
"@types/unist" "^2.0.0"
universalify@^0.2.0: universalify@^0.2.0:
version "0.2.0" version "0.2.0"
resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.2.0.tgz#6451760566fa857534745ab1dde952d1b1761be0" resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.2.0.tgz#6451760566fa857534745ab1dde952d1b1761be0"
@@ -7170,6 +7876,21 @@ use-sync-external-store@1.2.0:
resolved "https://registry.yarnpkg.com/use-sync-external-store/-/use-sync-external-store-1.2.0.tgz#7dbefd6ef3fe4e767a0cf5d7287aacfb5846928a" resolved "https://registry.yarnpkg.com/use-sync-external-store/-/use-sync-external-store-1.2.0.tgz#7dbefd6ef3fe4e767a0cf5d7287aacfb5846928a"
integrity sha512-eEgnFxGQ1Ife9bzYs6VLi8/4X6CObHMw9Qr9tPY43iKwsPw8xE8+EFsf/2cFZ5S3esXgpWgtSCtLNS41F+sKPA== integrity sha512-eEgnFxGQ1Ife9bzYs6VLi8/4X6CObHMw9Qr9tPY43iKwsPw8xE8+EFsf/2cFZ5S3esXgpWgtSCtLNS41F+sKPA==
uuid@^9.0.0:
version "9.0.0"
resolved "https://registry.yarnpkg.com/uuid/-/uuid-9.0.0.tgz#592f550650024a38ceb0c562f2f6aa435761efb5"
integrity sha512-MXcSTerfPa4uqyzStbRoTgt5XIe3x5+42+q1sDuy3R5MDk66URdLMOZe5aPX/SQd+kuYAh0FdP/pO28IkQyTeg==
uvu@^0.5.0:
version "0.5.6"
resolved "https://registry.yarnpkg.com/uvu/-/uvu-0.5.6.tgz#2754ca20bcb0bb59b64e9985e84d2e81058502df"
integrity sha512-+g8ENReyr8YsOc6fv/NVJs2vFdHBnBNdfE49rshrTzDWOlUx4Gq7KOS2GD8eqhy2j+Ejq29+SbKH8yjkAqXqoA==
dependencies:
dequal "^2.0.0"
diff "^5.0.0"
kleur "^4.0.3"
sade "^1.7.3"
v8-compile-cache@^2.0.3: v8-compile-cache@^2.0.3:
version "2.3.0" version "2.3.0"
resolved "https://registry.yarnpkg.com/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz#2de19618c66dc247dcfb6f99338035d8245a2cee" resolved "https://registry.yarnpkg.com/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz#2de19618c66dc247dcfb6f99338035d8245a2cee"
@@ -7355,6 +8076,11 @@ w3c-xmlserializer@^4.0.0:
dependencies: dependencies:
xml-name-validator "^4.0.0" xml-name-validator "^4.0.0"
web-worker@^1.2.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/web-worker/-/web-worker-1.2.0.tgz#5d85a04a7fbc1e7db58f66595d7a3ac7c9c180da"
integrity sha512-PgF341avzqyx60neE9DD+XS26MMNMoUQRz9NOZwW32nPQrF6p77f1htcnjBSEV8BGMKZ16choqUG4hyI0Hx7mA==
webidl-conversions@^4.0.2: webidl-conversions@^4.0.2:
version "4.0.2" version "4.0.2"
resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-4.0.2.tgz#a855980b1f0b6b359ba1d5d9fb39ae941faa63ad" resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-4.0.2.tgz#a855980b1f0b6b359ba1d5d9fb39ae941faa63ad"