Compare commits
4
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e5db4ce2dc | ||
|
|
cd61f5964c | ||
|
|
ad14721cb5 | ||
|
|
d45dc931ee |
@@ -20,7 +20,7 @@ exportToCanvas({<br/>
|
|||||||
getDimensions,<br/>
|
getDimensions,<br/>
|
||||||
files,<br/>
|
files,<br/>
|
||||||
exportPadding?: number;<br/>
|
exportPadding?: number;<br/>
|
||||||
}: <a href="https://github.com/excalidraw/excalidraw/blob/master/packages/utils/export.ts#L24">ExportOpts</a>
|
}: <a href="https://github.com/excalidraw/excalidraw/blob/master/packages/excalidraw/packages/utils.ts#L21">ExportOpts</a>
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
| Name | Type | Default | Description |
|
| Name | Type | Default | Description |
|
||||||
|
|||||||
+2
-2
@@ -40,7 +40,7 @@ import type {
|
|||||||
} from "@excalidraw/excalidraw/dist/excalidraw/element/types";
|
} from "@excalidraw/excalidraw/dist/excalidraw/element/types";
|
||||||
import type { ImportedLibraryData } from "@excalidraw/excalidraw/dist/excalidraw/data/types";
|
import type { ImportedLibraryData } from "@excalidraw/excalidraw/dist/excalidraw/data/types";
|
||||||
|
|
||||||
import "./ExampleApp.scss";
|
import "./App.scss";
|
||||||
|
|
||||||
type Comment = {
|
type Comment = {
|
||||||
x: number;
|
x: number;
|
||||||
@@ -73,7 +73,7 @@ export interface AppProps {
|
|||||||
excalidrawLib: typeof TExcalidraw;
|
excalidrawLib: typeof TExcalidraw;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function ExampleApp({
|
export default function App({
|
||||||
appTitle,
|
appTitle,
|
||||||
useCustom,
|
useCustom,
|
||||||
customArgs,
|
customArgs,
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
"use client";
|
"use client";
|
||||||
import * as excalidrawLib from "@excalidraw/excalidraw";
|
import * as excalidrawLib from "@excalidraw/excalidraw";
|
||||||
import { Excalidraw } from "@excalidraw/excalidraw";
|
import { Excalidraw } from "@excalidraw/excalidraw";
|
||||||
import App from "../../components/ExampleApp";
|
import App from "../../components/App";
|
||||||
|
|
||||||
import "@excalidraw/excalidraw/index.css";
|
import "@excalidraw/excalidraw/index.css";
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import App from "../components/ExampleApp";
|
import App from "../components/App";
|
||||||
import React, { StrictMode } from "react";
|
import React, { StrictMode } from "react";
|
||||||
import { createRoot } from "react-dom/client";
|
import { createRoot } from "react-dom/client";
|
||||||
|
|
||||||
|
|||||||
+1
-13
@@ -126,8 +126,6 @@ import DebugCanvas, {
|
|||||||
loadSavedDebugState,
|
loadSavedDebugState,
|
||||||
} from "./components/DebugCanvas";
|
} from "./components/DebugCanvas";
|
||||||
import { AIComponents } from "./components/AI";
|
import { AIComponents } from "./components/AI";
|
||||||
import type { SaveWarningRef } from "./components/SaveWarning";
|
|
||||||
import { SaveWarning } from "./components/SaveWarning";
|
|
||||||
|
|
||||||
polyfill();
|
polyfill();
|
||||||
|
|
||||||
@@ -333,8 +331,6 @@ const ExcalidrawWrapper = () => {
|
|||||||
|
|
||||||
const [langCode, setLangCode] = useAppLangCode();
|
const [langCode, setLangCode] = useAppLangCode();
|
||||||
|
|
||||||
const activityRef = useRef<SaveWarningRef | null>(null);
|
|
||||||
|
|
||||||
// initial state
|
// initial state
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
@@ -619,8 +615,6 @@ const ExcalidrawWrapper = () => {
|
|||||||
collabAPI.syncElements(elements);
|
collabAPI.syncElements(elements);
|
||||||
}
|
}
|
||||||
|
|
||||||
activityRef.current?.activity();
|
|
||||||
|
|
||||||
// this check is redundant, but since this is a hot path, it's best
|
// this check is redundant, but since this is a hot path, it's best
|
||||||
// not to evaludate the nested expression every time
|
// not to evaludate the nested expression every time
|
||||||
if (!LocalData.isSavePaused()) {
|
if (!LocalData.isSavePaused()) {
|
||||||
@@ -655,12 +649,7 @@ const ExcalidrawWrapper = () => {
|
|||||||
|
|
||||||
// Render the debug scene if the debug canvas is available
|
// Render the debug scene if the debug canvas is available
|
||||||
if (debugCanvasRef.current && excalidrawAPI) {
|
if (debugCanvasRef.current && excalidrawAPI) {
|
||||||
debugRenderer(
|
debugRenderer(debugCanvasRef.current, appState, window.devicePixelRatio);
|
||||||
debugCanvasRef.current,
|
|
||||||
appState,
|
|
||||||
window.devicePixelRatio,
|
|
||||||
() => forceRefresh((prev) => !prev),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -862,7 +851,6 @@ const ExcalidrawWrapper = () => {
|
|||||||
setTheme={(theme) => setAppTheme(theme)}
|
setTheme={(theme) => setAppTheme(theme)}
|
||||||
refresh={() => forceRefresh((prev) => !prev)}
|
refresh={() => forceRefresh((prev) => !prev)}
|
||||||
/>
|
/>
|
||||||
<SaveWarning ref={activityRef} />
|
|
||||||
<AppWelcomeScreen
|
<AppWelcomeScreen
|
||||||
onCollabDialogOpen={onCollabDialogOpen}
|
onCollabDialogOpen={onCollabDialogOpen}
|
||||||
isCollabEnabled={!isCollabDisabled}
|
isCollabEnabled={!isCollabDisabled}
|
||||||
|
|||||||
@@ -68,17 +68,12 @@ const _debugRenderer = (
|
|||||||
canvas: HTMLCanvasElement,
|
canvas: HTMLCanvasElement,
|
||||||
appState: AppState,
|
appState: AppState,
|
||||||
scale: number,
|
scale: number,
|
||||||
refresh: () => void,
|
|
||||||
) => {
|
) => {
|
||||||
const [normalizedWidth, normalizedHeight] = getNormalizedCanvasDimensions(
|
const [normalizedWidth, normalizedHeight] = getNormalizedCanvasDimensions(
|
||||||
canvas,
|
canvas,
|
||||||
scale,
|
scale,
|
||||||
);
|
);
|
||||||
|
|
||||||
if (appState.height !== canvas.height || appState.width !== canvas.width) {
|
|
||||||
refresh();
|
|
||||||
}
|
|
||||||
|
|
||||||
const context = bootstrapCanvas({
|
const context = bootstrapCanvas({
|
||||||
canvas,
|
canvas,
|
||||||
scale,
|
scale,
|
||||||
@@ -143,13 +138,8 @@ export const saveDebugState = (debug: { enabled: boolean }) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const debugRenderer = throttleRAF(
|
export const debugRenderer = throttleRAF(
|
||||||
(
|
(canvas: HTMLCanvasElement, appState: AppState, scale: number) => {
|
||||||
canvas: HTMLCanvasElement,
|
_debugRenderer(canvas, appState, scale);
|
||||||
appState: AppState,
|
|
||||||
scale: number,
|
|
||||||
refresh: () => void,
|
|
||||||
) => {
|
|
||||||
_debugRenderer(canvas, appState, scale, refresh);
|
|
||||||
},
|
},
|
||||||
{ trailing: true },
|
{ trailing: true },
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1,40 +0,0 @@
|
|||||||
import { forwardRef, useImperativeHandle, useRef } from "react";
|
|
||||||
import { t } from "../../packages/excalidraw/i18n";
|
|
||||||
import { getShortcutKey } from "../../packages/excalidraw/utils";
|
|
||||||
|
|
||||||
export type SaveWarningRef = {
|
|
||||||
activity: () => Promise<void>;
|
|
||||||
};
|
|
||||||
|
|
||||||
export const SaveWarning = forwardRef<SaveWarningRef, {}>((props, ref) => {
|
|
||||||
const dialogRef = useRef<HTMLDivElement | null>(null);
|
|
||||||
const timerRef = useRef<NodeJS.Timeout | null>(null);
|
|
||||||
|
|
||||||
useImperativeHandle(ref, () => ({
|
|
||||||
/**
|
|
||||||
* Call this API method via the ref to hide warning message
|
|
||||||
* and start an idle timer again.
|
|
||||||
*/
|
|
||||||
activity: async () => {
|
|
||||||
if (timerRef.current != null) {
|
|
||||||
clearTimeout(timerRef.current);
|
|
||||||
dialogRef.current?.classList.remove("animate");
|
|
||||||
}
|
|
||||||
|
|
||||||
timerRef.current = setTimeout(() => {
|
|
||||||
timerRef.current = null;
|
|
||||||
dialogRef.current?.classList.add("animate");
|
|
||||||
}, 5000);
|
|
||||||
},
|
|
||||||
}));
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div ref={dialogRef} className="alert-save">
|
|
||||||
<div className="dialog">
|
|
||||||
{t("alerts.saveYourContent", {
|
|
||||||
shortcut: getShortcutKey("CtrlOrCmd + S"),
|
|
||||||
})}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
});
|
|
||||||
@@ -20,10 +20,6 @@ import {
|
|||||||
get,
|
get,
|
||||||
} from "idb-keyval";
|
} from "idb-keyval";
|
||||||
import { clearAppStateForLocalStorage } from "../../packages/excalidraw/appState";
|
import { clearAppStateForLocalStorage } from "../../packages/excalidraw/appState";
|
||||||
import {
|
|
||||||
CANVAS_SEARCH_TAB,
|
|
||||||
DEFAULT_SIDEBAR,
|
|
||||||
} from "../../packages/excalidraw/constants";
|
|
||||||
import type { LibraryPersistedData } from "../../packages/excalidraw/data/library";
|
import type { LibraryPersistedData } from "../../packages/excalidraw/data/library";
|
||||||
import type { ImportedDataState } from "../../packages/excalidraw/data/types";
|
import type { ImportedDataState } from "../../packages/excalidraw/data/types";
|
||||||
import { clearElementsForLocalStorage } from "../../packages/excalidraw/element";
|
import { clearElementsForLocalStorage } from "../../packages/excalidraw/element";
|
||||||
@@ -70,22 +66,13 @@ const saveDataStateToLocalStorage = (
|
|||||||
appState: AppState,
|
appState: AppState,
|
||||||
) => {
|
) => {
|
||||||
try {
|
try {
|
||||||
const _appState = clearAppStateForLocalStorage(appState);
|
|
||||||
|
|
||||||
if (
|
|
||||||
_appState.openSidebar?.name === DEFAULT_SIDEBAR.name &&
|
|
||||||
_appState.openSidebar.tab === CANVAS_SEARCH_TAB
|
|
||||||
) {
|
|
||||||
_appState.openSidebar = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
localStorage.setItem(
|
localStorage.setItem(
|
||||||
STORAGE_KEYS.LOCAL_STORAGE_ELEMENTS,
|
STORAGE_KEYS.LOCAL_STORAGE_ELEMENTS,
|
||||||
JSON.stringify(clearElementsForLocalStorage(elements)),
|
JSON.stringify(clearElementsForLocalStorage(elements)),
|
||||||
);
|
);
|
||||||
localStorage.setItem(
|
localStorage.setItem(
|
||||||
STORAGE_KEYS.LOCAL_STORAGE_APP_STATE,
|
STORAGE_KEYS.LOCAL_STORAGE_APP_STATE,
|
||||||
JSON.stringify(_appState),
|
JSON.stringify(clearAppStateForLocalStorage(appState)),
|
||||||
);
|
);
|
||||||
updateBrowserStateVersion(STORAGE_KEYS.VERSION_DATA_STATE);
|
updateBrowserStateVersion(STORAGE_KEYS.VERSION_DATA_STATE);
|
||||||
} catch (error: any) {
|
} catch (error: any) {
|
||||||
|
|||||||
@@ -18,43 +18,6 @@
|
|||||||
margin-inline-start: auto;
|
margin-inline-start: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
.alert-save {
|
|
||||||
position: absolute;
|
|
||||||
z-index: 10;
|
|
||||||
left: 0;
|
|
||||||
right: 0;
|
|
||||||
bottom: 10vh;
|
|
||||||
margin-inline: auto;
|
|
||||||
width: fit-content;
|
|
||||||
|
|
||||||
opacity: 0;
|
|
||||||
transition: all 0s;
|
|
||||||
|
|
||||||
&.animate {
|
|
||||||
opacity: 1;
|
|
||||||
transition: all 0.2s ease-in;
|
|
||||||
}
|
|
||||||
|
|
||||||
.dialog {
|
|
||||||
margin-inline: 10px;
|
|
||||||
padding: 1rem;
|
|
||||||
padding-inline: 1.25rem;
|
|
||||||
|
|
||||||
resize: none;
|
|
||||||
white-space: pre-wrap;
|
|
||||||
box-sizing: border-box;
|
|
||||||
|
|
||||||
background-color: var(--color-warning);
|
|
||||||
border-radius: var(--border-radius-md);
|
|
||||||
border: 1px solid var(--dialog-border-color);
|
|
||||||
|
|
||||||
font-size: 0.875rem;
|
|
||||||
text-align: center;
|
|
||||||
line-height: 1.5;
|
|
||||||
color: var(--color-text-warning);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.encrypted-icon {
|
.encrypted-icon {
|
||||||
border-radius: var(--space-factor);
|
border-radius: var(--space-factor);
|
||||||
color: var(--color-primary);
|
color: var(--color-primary);
|
||||||
|
|||||||
+1
-1
@@ -36,7 +36,7 @@
|
|||||||
"prettier": "2.6.2",
|
"prettier": "2.6.2",
|
||||||
"rewire": "6.0.0",
|
"rewire": "6.0.0",
|
||||||
"typescript": "4.9.4",
|
"typescript": "4.9.4",
|
||||||
"vite": "5.0.12",
|
"vite": "5.4.2",
|
||||||
"vite-plugin-checker": "0.7.2",
|
"vite-plugin-checker": "0.7.2",
|
||||||
"vite-plugin-ejs": "1.7.0",
|
"vite-plugin-ejs": "1.7.0",
|
||||||
"vite-plugin-pwa": "0.17.4",
|
"vite-plugin-pwa": "0.17.4",
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ import { CODES, KEYS } from "../keys";
|
|||||||
import { getNormalizedZoom } from "../scene";
|
import { getNormalizedZoom } from "../scene";
|
||||||
import { centerScrollOn } from "../scene/scroll";
|
import { centerScrollOn } from "../scene/scroll";
|
||||||
import { getStateForZoom } from "../scene/zoom";
|
import { getStateForZoom } from "../scene/zoom";
|
||||||
import type { AppState, Offsets } from "../types";
|
import type { AppState } from "../types";
|
||||||
import { getShortcutKey, updateActiveTool } from "../utils";
|
import { getShortcutKey, updateActiveTool } from "../utils";
|
||||||
import { register } from "./register";
|
import { register } from "./register";
|
||||||
import { Tooltip } from "../components/Tooltip";
|
import { Tooltip } from "../components/Tooltip";
|
||||||
@@ -38,7 +38,7 @@ import { DEFAULT_CANVAS_BACKGROUND_PICKS } from "../colors";
|
|||||||
import type { SceneBounds } from "../element/bounds";
|
import type { SceneBounds } from "../element/bounds";
|
||||||
import { setCursor } from "../cursor";
|
import { setCursor } from "../cursor";
|
||||||
import { StoreAction } from "../store";
|
import { StoreAction } from "../store";
|
||||||
import { clamp, roundToStep } from "../../math";
|
import { clamp } from "../../math";
|
||||||
|
|
||||||
export const actionChangeViewBackgroundColor = register({
|
export const actionChangeViewBackgroundColor = register({
|
||||||
name: "changeViewBackgroundColor",
|
name: "changeViewBackgroundColor",
|
||||||
@@ -259,85 +259,89 @@ const zoomValueToFitBoundsOnViewport = (
|
|||||||
const adjustedZoomValue =
|
const adjustedZoomValue =
|
||||||
smallestZoomValue * clamp(viewportZoomFactor, 0.1, 1);
|
smallestZoomValue * clamp(viewportZoomFactor, 0.1, 1);
|
||||||
|
|
||||||
return Math.min(adjustedZoomValue, 1);
|
const zoomAdjustedToSteps =
|
||||||
|
Math.floor(adjustedZoomValue / ZOOM_STEP) * ZOOM_STEP;
|
||||||
|
|
||||||
|
return getNormalizedZoom(Math.min(zoomAdjustedToSteps, 1));
|
||||||
};
|
};
|
||||||
|
|
||||||
export const zoomToFitBounds = ({
|
export const zoomToFitBounds = ({
|
||||||
bounds,
|
bounds,
|
||||||
appState,
|
appState,
|
||||||
canvasOffsets,
|
|
||||||
fitToViewport = false,
|
fitToViewport = false,
|
||||||
viewportZoomFactor = 1,
|
viewportZoomFactor = 1,
|
||||||
minZoom = -Infinity,
|
|
||||||
maxZoom = Infinity,
|
|
||||||
}: {
|
}: {
|
||||||
bounds: SceneBounds;
|
bounds: SceneBounds;
|
||||||
canvasOffsets?: Offsets;
|
|
||||||
appState: Readonly<AppState>;
|
appState: Readonly<AppState>;
|
||||||
/** whether to fit content to viewport (beyond >100%) */
|
/** whether to fit content to viewport (beyond >100%) */
|
||||||
fitToViewport: boolean;
|
fitToViewport: boolean;
|
||||||
/** zoom content to cover X of the viewport, when fitToViewport=true */
|
/** zoom content to cover X of the viewport, when fitToViewport=true */
|
||||||
viewportZoomFactor?: number;
|
viewportZoomFactor?: number;
|
||||||
minZoom?: number;
|
|
||||||
maxZoom?: number;
|
|
||||||
}) => {
|
}) => {
|
||||||
viewportZoomFactor = clamp(viewportZoomFactor, MIN_ZOOM, MAX_ZOOM);
|
|
||||||
|
|
||||||
const [x1, y1, x2, y2] = bounds;
|
const [x1, y1, x2, y2] = bounds;
|
||||||
const centerX = (x1 + x2) / 2;
|
const centerX = (x1 + x2) / 2;
|
||||||
const centerY = (y1 + y2) / 2;
|
const centerY = (y1 + y2) / 2;
|
||||||
|
|
||||||
const canvasOffsetLeft = canvasOffsets?.left ?? 0;
|
let newZoomValue;
|
||||||
const canvasOffsetTop = canvasOffsets?.top ?? 0;
|
let scrollX;
|
||||||
const canvasOffsetRight = canvasOffsets?.right ?? 0;
|
let scrollY;
|
||||||
const canvasOffsetBottom = canvasOffsets?.bottom ?? 0;
|
|
||||||
|
|
||||||
const effectiveCanvasWidth =
|
|
||||||
appState.width - canvasOffsetLeft - canvasOffsetRight;
|
|
||||||
const effectiveCanvasHeight =
|
|
||||||
appState.height - canvasOffsetTop - canvasOffsetBottom;
|
|
||||||
|
|
||||||
let adjustedZoomValue;
|
|
||||||
|
|
||||||
if (fitToViewport) {
|
if (fitToViewport) {
|
||||||
const commonBoundsWidth = x2 - x1;
|
const commonBoundsWidth = x2 - x1;
|
||||||
const commonBoundsHeight = y2 - y1;
|
const commonBoundsHeight = y2 - y1;
|
||||||
|
|
||||||
adjustedZoomValue =
|
newZoomValue =
|
||||||
Math.min(
|
Math.min(
|
||||||
effectiveCanvasWidth / commonBoundsWidth,
|
appState.width / commonBoundsWidth,
|
||||||
effectiveCanvasHeight / commonBoundsHeight,
|
appState.height / commonBoundsHeight,
|
||||||
) * viewportZoomFactor;
|
) * clamp(viewportZoomFactor, 0.1, 1);
|
||||||
|
|
||||||
|
newZoomValue = getNormalizedZoom(newZoomValue);
|
||||||
|
|
||||||
|
let appStateWidth = appState.width;
|
||||||
|
|
||||||
|
if (appState.openSidebar) {
|
||||||
|
const sidebarDOMElem = document.querySelector(
|
||||||
|
".sidebar",
|
||||||
|
) as HTMLElement | null;
|
||||||
|
const sidebarWidth = sidebarDOMElem?.offsetWidth ?? 0;
|
||||||
|
const isRTL = document.documentElement.getAttribute("dir") === "rtl";
|
||||||
|
|
||||||
|
appStateWidth = !isRTL
|
||||||
|
? appState.width - sidebarWidth
|
||||||
|
: appState.width + sidebarWidth;
|
||||||
|
}
|
||||||
|
|
||||||
|
scrollX = (appStateWidth / 2) * (1 / newZoomValue) - centerX;
|
||||||
|
scrollY = (appState.height / 2) * (1 / newZoomValue) - centerY;
|
||||||
} else {
|
} else {
|
||||||
adjustedZoomValue = zoomValueToFitBoundsOnViewport(
|
newZoomValue = zoomValueToFitBoundsOnViewport(
|
||||||
bounds,
|
bounds,
|
||||||
{
|
{
|
||||||
width: effectiveCanvasWidth,
|
width: appState.width,
|
||||||
height: effectiveCanvasHeight,
|
height: appState.height,
|
||||||
},
|
},
|
||||||
viewportZoomFactor,
|
viewportZoomFactor,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const centerScroll = centerScrollOn({
|
||||||
|
scenePoint: { x: centerX, y: centerY },
|
||||||
|
viewportDimensions: {
|
||||||
|
width: appState.width,
|
||||||
|
height: appState.height,
|
||||||
|
},
|
||||||
|
zoom: { value: newZoomValue },
|
||||||
|
});
|
||||||
|
|
||||||
|
scrollX = centerScroll.scrollX;
|
||||||
|
scrollY = centerScroll.scrollY;
|
||||||
}
|
}
|
||||||
|
|
||||||
const newZoomValue = getNormalizedZoom(
|
|
||||||
clamp(roundToStep(adjustedZoomValue, ZOOM_STEP, "floor"), minZoom, maxZoom),
|
|
||||||
);
|
|
||||||
|
|
||||||
const centerScroll = centerScrollOn({
|
|
||||||
scenePoint: { x: centerX, y: centerY },
|
|
||||||
viewportDimensions: {
|
|
||||||
width: appState.width,
|
|
||||||
height: appState.height,
|
|
||||||
},
|
|
||||||
offsets: canvasOffsets,
|
|
||||||
zoom: { value: newZoomValue },
|
|
||||||
});
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
appState: {
|
appState: {
|
||||||
...appState,
|
...appState,
|
||||||
scrollX: centerScroll.scrollX,
|
scrollX,
|
||||||
scrollY: centerScroll.scrollY,
|
scrollY,
|
||||||
zoom: { value: newZoomValue },
|
zoom: { value: newZoomValue },
|
||||||
},
|
},
|
||||||
storeAction: StoreAction.NONE,
|
storeAction: StoreAction.NONE,
|
||||||
@@ -345,34 +349,25 @@ export const zoomToFitBounds = ({
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const zoomToFit = ({
|
export const zoomToFit = ({
|
||||||
canvasOffsets,
|
|
||||||
targetElements,
|
targetElements,
|
||||||
appState,
|
appState,
|
||||||
fitToViewport,
|
fitToViewport,
|
||||||
viewportZoomFactor,
|
viewportZoomFactor,
|
||||||
minZoom,
|
|
||||||
maxZoom,
|
|
||||||
}: {
|
}: {
|
||||||
canvasOffsets?: Offsets;
|
|
||||||
targetElements: readonly ExcalidrawElement[];
|
targetElements: readonly ExcalidrawElement[];
|
||||||
appState: Readonly<AppState>;
|
appState: Readonly<AppState>;
|
||||||
/** whether to fit content to viewport (beyond >100%) */
|
/** whether to fit content to viewport (beyond >100%) */
|
||||||
fitToViewport: boolean;
|
fitToViewport: boolean;
|
||||||
/** zoom content to cover X of the viewport, when fitToViewport=true */
|
/** zoom content to cover X of the viewport, when fitToViewport=true */
|
||||||
viewportZoomFactor?: number;
|
viewportZoomFactor?: number;
|
||||||
minZoom?: number;
|
|
||||||
maxZoom?: number;
|
|
||||||
}) => {
|
}) => {
|
||||||
const commonBounds = getCommonBounds(getNonDeletedElements(targetElements));
|
const commonBounds = getCommonBounds(getNonDeletedElements(targetElements));
|
||||||
|
|
||||||
return zoomToFitBounds({
|
return zoomToFitBounds({
|
||||||
canvasOffsets,
|
|
||||||
bounds: commonBounds,
|
bounds: commonBounds,
|
||||||
appState,
|
appState,
|
||||||
fitToViewport,
|
fitToViewport,
|
||||||
viewportZoomFactor,
|
viewportZoomFactor,
|
||||||
minZoom,
|
|
||||||
maxZoom,
|
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -393,7 +388,6 @@ export const actionZoomToFitSelectionInViewport = register({
|
|||||||
userToFollow: null,
|
userToFollow: null,
|
||||||
},
|
},
|
||||||
fitToViewport: false,
|
fitToViewport: false,
|
||||||
canvasOffsets: app.getEditorUIOffsets(),
|
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
// NOTE shift-2 should have been assigned actionZoomToFitSelection.
|
// NOTE shift-2 should have been assigned actionZoomToFitSelection.
|
||||||
@@ -419,7 +413,7 @@ export const actionZoomToFitSelection = register({
|
|||||||
userToFollow: null,
|
userToFollow: null,
|
||||||
},
|
},
|
||||||
fitToViewport: true,
|
fitToViewport: true,
|
||||||
canvasOffsets: app.getEditorUIOffsets(),
|
viewportZoomFactor: 0.7,
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
// NOTE this action should use shift-2 per figma, alas
|
// NOTE this action should use shift-2 per figma, alas
|
||||||
@@ -436,7 +430,7 @@ export const actionZoomToFit = register({
|
|||||||
icon: zoomAreaIcon,
|
icon: zoomAreaIcon,
|
||||||
viewMode: true,
|
viewMode: true,
|
||||||
trackEvent: { category: "canvas" },
|
trackEvent: { category: "canvas" },
|
||||||
perform: (elements, appState, _, app) =>
|
perform: (elements, appState) =>
|
||||||
zoomToFit({
|
zoomToFit({
|
||||||
targetElements: elements,
|
targetElements: elements,
|
||||||
appState: {
|
appState: {
|
||||||
@@ -444,7 +438,6 @@ export const actionZoomToFit = register({
|
|||||||
userToFollow: null,
|
userToFollow: null,
|
||||||
},
|
},
|
||||||
fitToViewport: false,
|
fitToViewport: false,
|
||||||
canvasOffsets: app.getEditorUIOffsets(),
|
|
||||||
}),
|
}),
|
||||||
keyTest: (event) =>
|
keyTest: (event) =>
|
||||||
event.code === CODES.ONE &&
|
event.code === CODES.ONE &&
|
||||||
|
|||||||
@@ -217,7 +217,6 @@ export const actionFinalize = register({
|
|||||||
onClick={updateData}
|
onClick={updateData}
|
||||||
visible={appState.multiElement != null}
|
visible={appState.multiElement != null}
|
||||||
size={data?.size || "medium"}
|
size={data?.size || "medium"}
|
||||||
style={{ pointerEvents: "all" }}
|
|
||||||
/>
|
/>
|
||||||
),
|
),
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,211 +0,0 @@
|
|||||||
import React from "react";
|
|
||||||
import { Excalidraw } from "../index";
|
|
||||||
import { render } from "../tests/test-utils";
|
|
||||||
import { API } from "../tests/helpers/api";
|
|
||||||
import { point } from "../../math";
|
|
||||||
import { actionFlipHorizontal, actionFlipVertical } from "./actionFlip";
|
|
||||||
|
|
||||||
const { h } = window;
|
|
||||||
|
|
||||||
describe("flipping re-centers selection", () => {
|
|
||||||
it("elbow arrow touches group selection side yet it remains in place after multiple moves", async () => {
|
|
||||||
const elements = [
|
|
||||||
API.createElement({
|
|
||||||
type: "rectangle",
|
|
||||||
id: "rec1",
|
|
||||||
x: 100,
|
|
||||||
y: 100,
|
|
||||||
width: 100,
|
|
||||||
height: 100,
|
|
||||||
boundElements: [{ id: "arr", type: "arrow" }],
|
|
||||||
}),
|
|
||||||
API.createElement({
|
|
||||||
type: "rectangle",
|
|
||||||
id: "rec2",
|
|
||||||
x: 220,
|
|
||||||
y: 250,
|
|
||||||
width: 100,
|
|
||||||
height: 100,
|
|
||||||
boundElements: [{ id: "arr", type: "arrow" }],
|
|
||||||
}),
|
|
||||||
API.createElement({
|
|
||||||
type: "arrow",
|
|
||||||
id: "arr",
|
|
||||||
x: 149.9,
|
|
||||||
y: 95,
|
|
||||||
width: 156,
|
|
||||||
height: 239.9,
|
|
||||||
startBinding: {
|
|
||||||
elementId: "rec1",
|
|
||||||
focus: 0,
|
|
||||||
gap: 5,
|
|
||||||
fixedPoint: [0.49, -0.05],
|
|
||||||
},
|
|
||||||
endBinding: {
|
|
||||||
elementId: "rec2",
|
|
||||||
focus: 0,
|
|
||||||
gap: 5,
|
|
||||||
fixedPoint: [-0.05, 0.49],
|
|
||||||
},
|
|
||||||
startArrowhead: null,
|
|
||||||
endArrowhead: "arrow",
|
|
||||||
points: [
|
|
||||||
point(0, 0),
|
|
||||||
point(0, -35),
|
|
||||||
point(-90.9, -35),
|
|
||||||
point(-90.9, 204.9),
|
|
||||||
point(65.1, 204.9),
|
|
||||||
],
|
|
||||||
elbowed: true,
|
|
||||||
}),
|
|
||||||
];
|
|
||||||
await render(<Excalidraw initialData={{ elements }} />);
|
|
||||||
|
|
||||||
API.setSelectedElements(elements);
|
|
||||||
|
|
||||||
expect(Object.keys(h.state.selectedElementIds).length).toBe(3);
|
|
||||||
|
|
||||||
API.executeAction(actionFlipHorizontal);
|
|
||||||
API.executeAction(actionFlipHorizontal);
|
|
||||||
API.executeAction(actionFlipHorizontal);
|
|
||||||
API.executeAction(actionFlipHorizontal);
|
|
||||||
|
|
||||||
const rec1 = h.elements.find((el) => el.id === "rec1");
|
|
||||||
expect(rec1?.x).toBeCloseTo(100);
|
|
||||||
expect(rec1?.y).toBeCloseTo(100);
|
|
||||||
|
|
||||||
const rec2 = h.elements.find((el) => el.id === "rec2");
|
|
||||||
expect(rec2?.x).toBeCloseTo(220);
|
|
||||||
expect(rec2?.y).toBeCloseTo(250);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe("flipping arrowheads", () => {
|
|
||||||
beforeEach(async () => {
|
|
||||||
await render(<Excalidraw />);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("flipping bound arrow should flip arrowheads only", () => {
|
|
||||||
const rect = API.createElement({
|
|
||||||
type: "rectangle",
|
|
||||||
boundElements: [{ type: "arrow", id: "arrow1" }],
|
|
||||||
});
|
|
||||||
const arrow = API.createElement({
|
|
||||||
type: "arrow",
|
|
||||||
id: "arrow1",
|
|
||||||
startArrowhead: "arrow",
|
|
||||||
endArrowhead: null,
|
|
||||||
endBinding: {
|
|
||||||
elementId: rect.id,
|
|
||||||
focus: 0.5,
|
|
||||||
gap: 5,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
API.setElements([rect, arrow]);
|
|
||||||
API.setSelectedElements([arrow]);
|
|
||||||
|
|
||||||
expect(API.getElement(arrow).startArrowhead).toBe("arrow");
|
|
||||||
expect(API.getElement(arrow).endArrowhead).toBe(null);
|
|
||||||
|
|
||||||
API.executeAction(actionFlipHorizontal);
|
|
||||||
expect(API.getElement(arrow).startArrowhead).toBe(null);
|
|
||||||
expect(API.getElement(arrow).endArrowhead).toBe("arrow");
|
|
||||||
|
|
||||||
API.executeAction(actionFlipHorizontal);
|
|
||||||
expect(API.getElement(arrow).startArrowhead).toBe("arrow");
|
|
||||||
expect(API.getElement(arrow).endArrowhead).toBe(null);
|
|
||||||
|
|
||||||
API.executeAction(actionFlipVertical);
|
|
||||||
expect(API.getElement(arrow).startArrowhead).toBe(null);
|
|
||||||
expect(API.getElement(arrow).endArrowhead).toBe("arrow");
|
|
||||||
});
|
|
||||||
|
|
||||||
it("flipping bound arrow should flip arrowheads only 2", () => {
|
|
||||||
const rect = API.createElement({
|
|
||||||
type: "rectangle",
|
|
||||||
boundElements: [{ type: "arrow", id: "arrow1" }],
|
|
||||||
});
|
|
||||||
const rect2 = API.createElement({
|
|
||||||
type: "rectangle",
|
|
||||||
boundElements: [{ type: "arrow", id: "arrow1" }],
|
|
||||||
});
|
|
||||||
const arrow = API.createElement({
|
|
||||||
type: "arrow",
|
|
||||||
id: "arrow1",
|
|
||||||
startArrowhead: "arrow",
|
|
||||||
endArrowhead: "circle",
|
|
||||||
startBinding: {
|
|
||||||
elementId: rect.id,
|
|
||||||
focus: 0.5,
|
|
||||||
gap: 5,
|
|
||||||
},
|
|
||||||
endBinding: {
|
|
||||||
elementId: rect2.id,
|
|
||||||
focus: 0.5,
|
|
||||||
gap: 5,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
API.setElements([rect, rect2, arrow]);
|
|
||||||
API.setSelectedElements([arrow]);
|
|
||||||
|
|
||||||
expect(API.getElement(arrow).startArrowhead).toBe("arrow");
|
|
||||||
expect(API.getElement(arrow).endArrowhead).toBe("circle");
|
|
||||||
|
|
||||||
API.executeAction(actionFlipHorizontal);
|
|
||||||
expect(API.getElement(arrow).startArrowhead).toBe("circle");
|
|
||||||
expect(API.getElement(arrow).endArrowhead).toBe("arrow");
|
|
||||||
|
|
||||||
API.executeAction(actionFlipVertical);
|
|
||||||
expect(API.getElement(arrow).startArrowhead).toBe("arrow");
|
|
||||||
expect(API.getElement(arrow).endArrowhead).toBe("circle");
|
|
||||||
});
|
|
||||||
|
|
||||||
it("flipping unbound arrow shouldn't flip arrowheads", () => {
|
|
||||||
const arrow = API.createElement({
|
|
||||||
type: "arrow",
|
|
||||||
id: "arrow1",
|
|
||||||
startArrowhead: "arrow",
|
|
||||||
endArrowhead: "circle",
|
|
||||||
});
|
|
||||||
|
|
||||||
API.setElements([arrow]);
|
|
||||||
API.setSelectedElements([arrow]);
|
|
||||||
|
|
||||||
expect(API.getElement(arrow).startArrowhead).toBe("arrow");
|
|
||||||
expect(API.getElement(arrow).endArrowhead).toBe("circle");
|
|
||||||
|
|
||||||
API.executeAction(actionFlipHorizontal);
|
|
||||||
expect(API.getElement(arrow).startArrowhead).toBe("arrow");
|
|
||||||
expect(API.getElement(arrow).endArrowhead).toBe("circle");
|
|
||||||
});
|
|
||||||
|
|
||||||
it("flipping bound arrow shouldn't flip arrowheads if selected alongside non-arrow eleemnt", () => {
|
|
||||||
const rect = API.createElement({
|
|
||||||
type: "rectangle",
|
|
||||||
boundElements: [{ type: "arrow", id: "arrow1" }],
|
|
||||||
});
|
|
||||||
const arrow = API.createElement({
|
|
||||||
type: "arrow",
|
|
||||||
id: "arrow1",
|
|
||||||
startArrowhead: "arrow",
|
|
||||||
endArrowhead: null,
|
|
||||||
endBinding: {
|
|
||||||
elementId: rect.id,
|
|
||||||
focus: 0.5,
|
|
||||||
gap: 5,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
API.setElements([rect, arrow]);
|
|
||||||
API.setSelectedElements([rect, arrow]);
|
|
||||||
|
|
||||||
expect(API.getElement(arrow).startArrowhead).toBe("arrow");
|
|
||||||
expect(API.getElement(arrow).endArrowhead).toBe(null);
|
|
||||||
|
|
||||||
API.executeAction(actionFlipHorizontal);
|
|
||||||
expect(API.getElement(arrow).startArrowhead).toBe("arrow");
|
|
||||||
expect(API.getElement(arrow).endArrowhead).toBe(null);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@@ -2,8 +2,6 @@ import { register } from "./register";
|
|||||||
import { getSelectedElements } from "../scene";
|
import { getSelectedElements } from "../scene";
|
||||||
import { getNonDeletedElements } from "../element";
|
import { getNonDeletedElements } from "../element";
|
||||||
import type {
|
import type {
|
||||||
ExcalidrawArrowElement,
|
|
||||||
ExcalidrawElbowArrowElement,
|
|
||||||
ExcalidrawElement,
|
ExcalidrawElement,
|
||||||
NonDeleted,
|
NonDeleted,
|
||||||
NonDeletedSceneElementsMap,
|
NonDeletedSceneElementsMap,
|
||||||
@@ -20,13 +18,7 @@ import {
|
|||||||
import { updateFrameMembershipOfSelectedElements } from "../frame";
|
import { updateFrameMembershipOfSelectedElements } from "../frame";
|
||||||
import { flipHorizontal, flipVertical } from "../components/icons";
|
import { flipHorizontal, flipVertical } from "../components/icons";
|
||||||
import { StoreAction } from "../store";
|
import { StoreAction } from "../store";
|
||||||
import {
|
import { isLinearElement } from "../element/typeChecks";
|
||||||
isArrowElement,
|
|
||||||
isElbowArrow,
|
|
||||||
isLinearElement,
|
|
||||||
} from "../element/typeChecks";
|
|
||||||
import { mutateElbowArrow } from "../element/routing";
|
|
||||||
import { mutateElement, newElementWith } from "../element/mutateElement";
|
|
||||||
|
|
||||||
export const actionFlipHorizontal = register({
|
export const actionFlipHorizontal = register({
|
||||||
name: "flipHorizontal",
|
name: "flipHorizontal",
|
||||||
@@ -117,23 +109,7 @@ const flipElements = (
|
|||||||
flipDirection: "horizontal" | "vertical",
|
flipDirection: "horizontal" | "vertical",
|
||||||
app: AppClassProperties,
|
app: AppClassProperties,
|
||||||
): ExcalidrawElement[] => {
|
): ExcalidrawElement[] => {
|
||||||
if (
|
const { minX, minY, maxX, maxY } = getCommonBoundingBox(selectedElements);
|
||||||
selectedElements.every(
|
|
||||||
(element) =>
|
|
||||||
isArrowElement(element) && (element.startBinding || element.endBinding),
|
|
||||||
)
|
|
||||||
) {
|
|
||||||
return selectedElements.map((element) => {
|
|
||||||
const _element = element as ExcalidrawArrowElement;
|
|
||||||
return newElementWith(_element, {
|
|
||||||
startArrowhead: _element.endArrowhead,
|
|
||||||
endArrowhead: _element.startArrowhead,
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
const { minX, minY, maxX, maxY, midX, midY } =
|
|
||||||
getCommonBoundingBox(selectedElements);
|
|
||||||
|
|
||||||
resizeMultipleElements(
|
resizeMultipleElements(
|
||||||
elementsMap,
|
elementsMap,
|
||||||
@@ -155,48 +131,5 @@ const flipElements = (
|
|||||||
[],
|
[],
|
||||||
);
|
);
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
|
||||||
// flipping arrow elements (and potentially other) makes the selection group
|
|
||||||
// "move" across the canvas because of how arrows can bump against the "wall"
|
|
||||||
// of the selection, so we need to center the group back to the original
|
|
||||||
// position so that repeated flips don't accumulate the offset
|
|
||||||
|
|
||||||
const { elbowArrows, otherElements } = selectedElements.reduce(
|
|
||||||
(
|
|
||||||
acc: {
|
|
||||||
elbowArrows: ExcalidrawElbowArrowElement[];
|
|
||||||
otherElements: ExcalidrawElement[];
|
|
||||||
},
|
|
||||||
element,
|
|
||||||
) =>
|
|
||||||
isElbowArrow(element)
|
|
||||||
? { ...acc, elbowArrows: acc.elbowArrows.concat(element) }
|
|
||||||
: { ...acc, otherElements: acc.otherElements.concat(element) },
|
|
||||||
{ elbowArrows: [], otherElements: [] },
|
|
||||||
);
|
|
||||||
|
|
||||||
const { midX: newMidX, midY: newMidY } =
|
|
||||||
getCommonBoundingBox(selectedElements);
|
|
||||||
const [diffX, diffY] = [midX - newMidX, midY - newMidY];
|
|
||||||
otherElements.forEach((element) =>
|
|
||||||
mutateElement(element, {
|
|
||||||
x: element.x + diffX,
|
|
||||||
y: element.y + diffY,
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
elbowArrows.forEach((element) =>
|
|
||||||
mutateElbowArrow(
|
|
||||||
element,
|
|
||||||
elementsMap,
|
|
||||||
element.points,
|
|
||||||
undefined,
|
|
||||||
undefined,
|
|
||||||
{
|
|
||||||
informMutation: false,
|
|
||||||
},
|
|
||||||
),
|
|
||||||
);
|
|
||||||
// ---------------------------------------------------------------------------
|
|
||||||
|
|
||||||
return selectedElements;
|
return selectedElements;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1685,6 +1685,19 @@ export const actionChangeArrowType = register({
|
|||||||
: {}),
|
: {}),
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
} else {
|
||||||
|
mutateElement(
|
||||||
|
newElement,
|
||||||
|
{
|
||||||
|
startBinding: newElement.startBinding
|
||||||
|
? { ...newElement.startBinding, fixedPoint: null }
|
||||||
|
: null,
|
||||||
|
endBinding: newElement.endBinding
|
||||||
|
? { ...newElement.endBinding, fixedPoint: null }
|
||||||
|
: null,
|
||||||
|
},
|
||||||
|
false,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return newElement;
|
return newElement;
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import { register } from "./register";
|
|||||||
import type { AppState } from "../types";
|
import type { AppState } from "../types";
|
||||||
import { searchIcon } from "../components/icons";
|
import { searchIcon } from "../components/icons";
|
||||||
import { StoreAction } from "../store";
|
import { StoreAction } from "../store";
|
||||||
import { CANVAS_SEARCH_TAB, CLASSES, DEFAULT_SIDEBAR } from "../constants";
|
import { CLASSES, SEARCH_SIDEBAR } from "../constants";
|
||||||
|
|
||||||
export const actionToggleSearchMenu = register({
|
export const actionToggleSearchMenu = register({
|
||||||
name: "searchMenu",
|
name: "searchMenu",
|
||||||
@@ -17,10 +17,7 @@ export const actionToggleSearchMenu = register({
|
|||||||
predicate: (appState) => appState.gridModeEnabled,
|
predicate: (appState) => appState.gridModeEnabled,
|
||||||
},
|
},
|
||||||
perform(elements, appState, _, app) {
|
perform(elements, appState, _, app) {
|
||||||
if (
|
if (appState.openSidebar?.name === SEARCH_SIDEBAR.name) {
|
||||||
appState.openSidebar?.name === DEFAULT_SIDEBAR.name &&
|
|
||||||
appState.openSidebar.tab === CANVAS_SEARCH_TAB
|
|
||||||
) {
|
|
||||||
const searchInput =
|
const searchInput =
|
||||||
app.excalidrawContainerValue.container?.querySelector<HTMLInputElement>(
|
app.excalidrawContainerValue.container?.querySelector<HTMLInputElement>(
|
||||||
`.${CLASSES.SEARCH_MENU_INPUT_WRAPPER} input`,
|
`.${CLASSES.SEARCH_MENU_INPUT_WRAPPER} input`,
|
||||||
@@ -34,14 +31,13 @@ export const actionToggleSearchMenu = register({
|
|||||||
}
|
}
|
||||||
|
|
||||||
searchInput?.focus();
|
searchInput?.focus();
|
||||||
searchInput?.select();
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
appState: {
|
appState: {
|
||||||
...appState,
|
...appState,
|
||||||
openSidebar: { name: DEFAULT_SIDEBAR.name, tab: CANVAS_SEARCH_TAB },
|
openSidebar: { name: SEARCH_SIDEBAR.name },
|
||||||
openDialog: null,
|
openDialog: null,
|
||||||
},
|
},
|
||||||
storeAction: StoreAction.NONE,
|
storeAction: StoreAction.NONE,
|
||||||
|
|||||||
@@ -185,7 +185,6 @@ import type {
|
|||||||
MagicGenerationData,
|
MagicGenerationData,
|
||||||
ExcalidrawNonSelectionElement,
|
ExcalidrawNonSelectionElement,
|
||||||
ExcalidrawArrowElement,
|
ExcalidrawArrowElement,
|
||||||
NonDeletedSceneElementsMap,
|
|
||||||
} from "../element/types";
|
} from "../element/types";
|
||||||
import { getCenter, getDistance } from "../gesture";
|
import { getCenter, getDistance } from "../gesture";
|
||||||
import {
|
import {
|
||||||
@@ -260,7 +259,6 @@ import type {
|
|||||||
ElementsPendingErasure,
|
ElementsPendingErasure,
|
||||||
GenerateDiagramToCode,
|
GenerateDiagramToCode,
|
||||||
NullableGridSize,
|
NullableGridSize,
|
||||||
Offsets,
|
|
||||||
} from "../types";
|
} from "../types";
|
||||||
import {
|
import {
|
||||||
debounce,
|
debounce,
|
||||||
@@ -288,7 +286,6 @@ import {
|
|||||||
getDateTime,
|
getDateTime,
|
||||||
isShallowEqual,
|
isShallowEqual,
|
||||||
arrayToMap,
|
arrayToMap,
|
||||||
toBrandedType,
|
|
||||||
} from "../utils";
|
} from "../utils";
|
||||||
import {
|
import {
|
||||||
createSrcDoc,
|
createSrcDoc,
|
||||||
@@ -437,7 +434,7 @@ import { actionTextAutoResize } from "../actions/actionTextAutoResize";
|
|||||||
import { getVisibleSceneBounds } from "../element/bounds";
|
import { getVisibleSceneBounds } from "../element/bounds";
|
||||||
import { isMaybeMermaidDefinition } from "../mermaid";
|
import { isMaybeMermaidDefinition } from "../mermaid";
|
||||||
import NewElementCanvas from "./canvases/NewElementCanvas";
|
import NewElementCanvas from "./canvases/NewElementCanvas";
|
||||||
import { mutateElbowArrow, updateElbowArrow } from "../element/routing";
|
import { mutateElbowArrow } from "../element/routing";
|
||||||
import {
|
import {
|
||||||
FlowChartCreator,
|
FlowChartCreator,
|
||||||
FlowChartNavigator,
|
FlowChartNavigator,
|
||||||
@@ -2370,10 +2367,9 @@ class App extends React.Component<AppProps, AppState> {
|
|||||||
return false;
|
return false;
|
||||||
};
|
};
|
||||||
|
|
||||||
private clearImageShapeCache(filesMap?: BinaryFiles) {
|
private clearImageShapeCache() {
|
||||||
const files = filesMap ?? this.files;
|
|
||||||
this.scene.getNonDeletedElements().forEach((element) => {
|
this.scene.getNonDeletedElements().forEach((element) => {
|
||||||
if (isInitializedImageElement(element) && files[element.fileId]) {
|
if (isInitializedImageElement(element) && this.files[element.fileId]) {
|
||||||
this.imageCache.delete(element.fileId);
|
this.imageCache.delete(element.fileId);
|
||||||
ShapeCache.delete(element);
|
ShapeCache.delete(element);
|
||||||
}
|
}
|
||||||
@@ -3111,45 +3107,7 @@ class App extends React.Component<AppProps, AppState> {
|
|||||||
retainSeed?: boolean;
|
retainSeed?: boolean;
|
||||||
fitToContent?: boolean;
|
fitToContent?: boolean;
|
||||||
}) => {
|
}) => {
|
||||||
let elements = opts.elements.map((el, _, elements) => {
|
const elements = restoreElements(opts.elements, null, undefined);
|
||||||
if (isElbowArrow(el)) {
|
|
||||||
const startEndElements = [
|
|
||||||
el.startBinding &&
|
|
||||||
elements.find((l) => l.id === el.startBinding?.elementId),
|
|
||||||
el.endBinding &&
|
|
||||||
elements.find((l) => l.id === el.endBinding?.elementId),
|
|
||||||
];
|
|
||||||
const startBinding = startEndElements[0] ? el.startBinding : null;
|
|
||||||
const endBinding = startEndElements[1] ? el.endBinding : null;
|
|
||||||
return {
|
|
||||||
...el,
|
|
||||||
...updateElbowArrow(
|
|
||||||
{
|
|
||||||
...el,
|
|
||||||
startBinding,
|
|
||||||
endBinding,
|
|
||||||
},
|
|
||||||
toBrandedType<NonDeletedSceneElementsMap>(
|
|
||||||
new Map(
|
|
||||||
startEndElements
|
|
||||||
.filter((x) => x != null)
|
|
||||||
.map(
|
|
||||||
(el) =>
|
|
||||||
[el!.id, el] as [
|
|
||||||
string,
|
|
||||||
Ordered<NonDeletedExcalidrawElement>,
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
[el.points[0], el.points[el.points.length - 1]],
|
|
||||||
),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
return el;
|
|
||||||
});
|
|
||||||
elements = restoreElements(elements, null, undefined);
|
|
||||||
const [minX, minY, maxX, maxY] = getCommonBounds(elements);
|
const [minX, minY, maxX, maxY] = getCommonBounds(elements);
|
||||||
|
|
||||||
const elementsCenterX = distance(minX, maxX) / 2;
|
const elementsCenterX = distance(minX, maxX) / 2;
|
||||||
@@ -3273,7 +3231,6 @@ class App extends React.Component<AppProps, AppState> {
|
|||||||
if (opts.fitToContent) {
|
if (opts.fitToContent) {
|
||||||
this.scrollToContent(newElements, {
|
this.scrollToContent(newElements, {
|
||||||
fitToContent: true,
|
fitToContent: true,
|
||||||
canvasOffsets: this.getEditorUIOffsets(),
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -3586,7 +3543,7 @@ class App extends React.Component<AppProps, AppState> {
|
|||||||
target:
|
target:
|
||||||
| ExcalidrawElement
|
| ExcalidrawElement
|
||||||
| readonly ExcalidrawElement[] = this.scene.getNonDeletedElements(),
|
| readonly ExcalidrawElement[] = this.scene.getNonDeletedElements(),
|
||||||
opts?: (
|
opts?:
|
||||||
| {
|
| {
|
||||||
fitToContent?: boolean;
|
fitToContent?: boolean;
|
||||||
fitToViewport?: never;
|
fitToViewport?: never;
|
||||||
@@ -3603,12 +3560,7 @@ class App extends React.Component<AppProps, AppState> {
|
|||||||
viewportZoomFactor?: number;
|
viewportZoomFactor?: number;
|
||||||
animate?: boolean;
|
animate?: boolean;
|
||||||
duration?: number;
|
duration?: number;
|
||||||
}
|
},
|
||||||
) & {
|
|
||||||
minZoom?: number;
|
|
||||||
maxZoom?: number;
|
|
||||||
canvasOffsets?: Offsets;
|
|
||||||
},
|
|
||||||
) => {
|
) => {
|
||||||
this.cancelInProgressAnimation?.();
|
this.cancelInProgressAnimation?.();
|
||||||
|
|
||||||
@@ -3621,13 +3573,10 @@ class App extends React.Component<AppProps, AppState> {
|
|||||||
|
|
||||||
if (opts?.fitToContent || opts?.fitToViewport) {
|
if (opts?.fitToContent || opts?.fitToViewport) {
|
||||||
const { appState } = zoomToFit({
|
const { appState } = zoomToFit({
|
||||||
canvasOffsets: opts.canvasOffsets,
|
|
||||||
targetElements,
|
targetElements,
|
||||||
appState: this.state,
|
appState: this.state,
|
||||||
fitToViewport: !!opts?.fitToViewport,
|
fitToViewport: !!opts?.fitToViewport,
|
||||||
viewportZoomFactor: opts?.viewportZoomFactor,
|
viewportZoomFactor: opts?.viewportZoomFactor,
|
||||||
minZoom: opts?.minZoom,
|
|
||||||
maxZoom: opts?.maxZoom,
|
|
||||||
});
|
});
|
||||||
zoom = appState.zoom;
|
zoom = appState.zoom;
|
||||||
scrollX = appState.scrollX;
|
scrollX = appState.scrollX;
|
||||||
@@ -3741,7 +3690,7 @@ class App extends React.Component<AppProps, AppState> {
|
|||||||
|
|
||||||
this.files = { ...this.files, ...Object.fromEntries(filesMap) };
|
this.files = { ...this.files, ...Object.fromEntries(filesMap) };
|
||||||
|
|
||||||
this.clearImageShapeCache(Object.fromEntries(filesMap));
|
this.clearImageShapeCache();
|
||||||
this.scene.triggerUpdate();
|
this.scene.triggerUpdate();
|
||||||
|
|
||||||
this.addNewImagesToImageCache();
|
this.addNewImagesToImageCache();
|
||||||
@@ -3855,42 +3804,40 @@ class App extends React.Component<AppProps, AppState> {
|
|||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
public getEditorUIOffsets = (): Offsets => {
|
public getEditorUIOffsets = (): {
|
||||||
|
top: number;
|
||||||
|
right: number;
|
||||||
|
bottom: number;
|
||||||
|
left: number;
|
||||||
|
} => {
|
||||||
const toolbarBottom =
|
const toolbarBottom =
|
||||||
this.excalidrawContainerRef?.current
|
this.excalidrawContainerRef?.current
|
||||||
?.querySelector(".App-toolbar")
|
?.querySelector(".App-toolbar")
|
||||||
?.getBoundingClientRect()?.bottom ?? 0;
|
?.getBoundingClientRect()?.bottom ?? 0;
|
||||||
const sidebarRect = this.excalidrawContainerRef?.current
|
const sidebarWidth = Math.max(
|
||||||
?.querySelector(".sidebar")
|
this.excalidrawContainerRef?.current
|
||||||
?.getBoundingClientRect();
|
?.querySelector(".default-sidebar")
|
||||||
const propertiesPanelRect = this.excalidrawContainerRef?.current
|
?.getBoundingClientRect()?.width ?? 0,
|
||||||
?.querySelector(".App-menu__left")
|
);
|
||||||
?.getBoundingClientRect();
|
const propertiesPanelWidth = Math.max(
|
||||||
|
this.excalidrawContainerRef?.current
|
||||||
const PADDING = 16;
|
?.querySelector(".App-menu__left")
|
||||||
|
?.getBoundingClientRect()?.width ?? 0,
|
||||||
|
0,
|
||||||
|
);
|
||||||
|
|
||||||
return getLanguage().rtl
|
return getLanguage().rtl
|
||||||
? {
|
? {
|
||||||
top: toolbarBottom + PADDING,
|
top: toolbarBottom,
|
||||||
right:
|
right: propertiesPanelWidth,
|
||||||
Math.max(
|
bottom: 0,
|
||||||
this.state.width -
|
left: sidebarWidth,
|
||||||
(propertiesPanelRect?.left ?? this.state.width),
|
|
||||||
0,
|
|
||||||
) + PADDING,
|
|
||||||
bottom: PADDING,
|
|
||||||
left: Math.max(sidebarRect?.right ?? 0, 0) + PADDING,
|
|
||||||
}
|
}
|
||||||
: {
|
: {
|
||||||
top: toolbarBottom + PADDING,
|
top: toolbarBottom,
|
||||||
right: Math.max(
|
right: sidebarWidth,
|
||||||
this.state.width -
|
bottom: 0,
|
||||||
(sidebarRect?.left ?? this.state.width) +
|
left: propertiesPanelWidth,
|
||||||
PADDING,
|
|
||||||
0,
|
|
||||||
),
|
|
||||||
bottom: PADDING,
|
|
||||||
left: Math.max(propertiesPanelRect?.right ?? 0, 0) + PADDING,
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -3975,7 +3922,7 @@ class App extends React.Component<AppProps, AppState> {
|
|||||||
animate: true,
|
animate: true,
|
||||||
duration: 300,
|
duration: 300,
|
||||||
fitToContent: true,
|
fitToContent: true,
|
||||||
canvasOffsets: this.getEditorUIOffsets(),
|
viewportZoomFactor: 0.8,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -4031,7 +3978,6 @@ class App extends React.Component<AppProps, AppState> {
|
|||||||
this.scrollToContent(nextNode, {
|
this.scrollToContent(nextNode, {
|
||||||
animate: true,
|
animate: true,
|
||||||
duration: 300,
|
duration: 300,
|
||||||
canvasOffsets: this.getEditorUIOffsets(),
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -4464,7 +4410,6 @@ class App extends React.Component<AppProps, AppState> {
|
|||||||
this.scrollToContent(firstNode, {
|
this.scrollToContent(firstNode, {
|
||||||
animate: true,
|
animate: true,
|
||||||
duration: 300,
|
duration: 300,
|
||||||
canvasOffsets: this.getEditorUIOffsets(),
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,9 +1,5 @@
|
|||||||
import clsx from "clsx";
|
import clsx from "clsx";
|
||||||
import {
|
import { DEFAULT_SIDEBAR, LIBRARY_SIDEBAR_TAB } from "../constants";
|
||||||
CANVAS_SEARCH_TAB,
|
|
||||||
DEFAULT_SIDEBAR,
|
|
||||||
LIBRARY_SIDEBAR_TAB,
|
|
||||||
} from "../constants";
|
|
||||||
import { useTunnels } from "../context/tunnels";
|
import { useTunnels } from "../context/tunnels";
|
||||||
import { useUIAppState } from "../context/ui-appState";
|
import { useUIAppState } from "../context/ui-appState";
|
||||||
import type { MarkOptional, Merge } from "../utility-types";
|
import type { MarkOptional, Merge } from "../utility-types";
|
||||||
@@ -14,8 +10,7 @@ import { LibraryMenu } from "./LibraryMenu";
|
|||||||
import type { SidebarProps, SidebarTriggerProps } from "./Sidebar/common";
|
import type { SidebarProps, SidebarTriggerProps } from "./Sidebar/common";
|
||||||
import { Sidebar } from "./Sidebar/Sidebar";
|
import { Sidebar } from "./Sidebar/Sidebar";
|
||||||
import "../components/dropdownMenu/DropdownMenu.scss";
|
import "../components/dropdownMenu/DropdownMenu.scss";
|
||||||
import { SearchMenu } from "./SearchMenu";
|
import { t } from "../i18n";
|
||||||
import { LibraryIcon, searchIcon } from "./icons";
|
|
||||||
|
|
||||||
const DefaultSidebarTrigger = withInternalFallback(
|
const DefaultSidebarTrigger = withInternalFallback(
|
||||||
"DefaultSidebarTrigger",
|
"DefaultSidebarTrigger",
|
||||||
@@ -37,11 +32,14 @@ const DefaultSidebarTrigger = withInternalFallback(
|
|||||||
);
|
);
|
||||||
DefaultSidebarTrigger.displayName = "DefaultSidebarTrigger";
|
DefaultSidebarTrigger.displayName = "DefaultSidebarTrigger";
|
||||||
|
|
||||||
const DefaultTabTriggers = ({ children }: { children: React.ReactNode }) => {
|
const DefaultTabTriggers = ({
|
||||||
|
children,
|
||||||
|
...rest
|
||||||
|
}: { children: React.ReactNode } & React.HTMLAttributes<HTMLDivElement>) => {
|
||||||
const { DefaultSidebarTabTriggersTunnel } = useTunnels();
|
const { DefaultSidebarTabTriggersTunnel } = useTunnels();
|
||||||
return (
|
return (
|
||||||
<DefaultSidebarTabTriggersTunnel.In>
|
<DefaultSidebarTabTriggersTunnel.In>
|
||||||
{children}
|
<Sidebar.TabTriggers {...rest}>{children}</Sidebar.TabTriggers>
|
||||||
</DefaultSidebarTabTriggersTunnel.In>
|
</DefaultSidebarTabTriggersTunnel.In>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
@@ -68,21 +66,16 @@ export const DefaultSidebar = Object.assign(
|
|||||||
|
|
||||||
const { DefaultSidebarTabTriggersTunnel } = useTunnels();
|
const { DefaultSidebarTabTriggersTunnel } = useTunnels();
|
||||||
|
|
||||||
const isForceDocked = appState.openSidebar?.tab === CANVAS_SEARCH_TAB;
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Sidebar
|
<Sidebar
|
||||||
{...rest}
|
{...rest}
|
||||||
name="default"
|
name={"default"}
|
||||||
key="default"
|
|
||||||
className={clsx("default-sidebar", className)}
|
className={clsx("default-sidebar", className)}
|
||||||
docked={
|
docked={docked ?? appState.defaultSidebarDockedPreference}
|
||||||
isForceDocked || (docked ?? appState.defaultSidebarDockedPreference)
|
|
||||||
}
|
|
||||||
onDock={
|
onDock={
|
||||||
// `onDock=false` disables docking.
|
// `onDock=false` disables docking.
|
||||||
// if `docked` passed, but no onDock passed, disable manual docking.
|
// if `docked` passed, but no onDock passed, disable manual docking.
|
||||||
isForceDocked || onDock === false || (!onDock && docked != null)
|
onDock === false || (!onDock && docked != null)
|
||||||
? undefined
|
? undefined
|
||||||
: // compose to allow the host app to listen on default behavior
|
: // compose to allow the host app to listen on default behavior
|
||||||
composeEventHandlers(onDock, (docked) => {
|
composeEventHandlers(onDock, (docked) => {
|
||||||
@@ -92,22 +85,26 @@ export const DefaultSidebar = Object.assign(
|
|||||||
>
|
>
|
||||||
<Sidebar.Tabs>
|
<Sidebar.Tabs>
|
||||||
<Sidebar.Header>
|
<Sidebar.Header>
|
||||||
<Sidebar.TabTriggers>
|
{rest.__fallback && (
|
||||||
<Sidebar.TabTrigger tab={CANVAS_SEARCH_TAB}>
|
<div
|
||||||
{searchIcon}
|
style={{
|
||||||
</Sidebar.TabTrigger>
|
color: "var(--color-primary)",
|
||||||
<Sidebar.TabTrigger tab={LIBRARY_SIDEBAR_TAB}>
|
fontSize: "1.2em",
|
||||||
{LibraryIcon}
|
fontWeight: "bold",
|
||||||
</Sidebar.TabTrigger>
|
textOverflow: "ellipsis",
|
||||||
<DefaultSidebarTabTriggersTunnel.Out />
|
overflow: "hidden",
|
||||||
</Sidebar.TabTriggers>
|
whiteSpace: "nowrap",
|
||||||
|
paddingRight: "1em",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{t("toolBar.library")}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
<DefaultSidebarTabTriggersTunnel.Out />
|
||||||
</Sidebar.Header>
|
</Sidebar.Header>
|
||||||
<Sidebar.Tab tab={LIBRARY_SIDEBAR_TAB}>
|
<Sidebar.Tab tab={LIBRARY_SIDEBAR_TAB}>
|
||||||
<LibraryMenu />
|
<LibraryMenu />
|
||||||
</Sidebar.Tab>
|
</Sidebar.Tab>
|
||||||
<Sidebar.Tab tab={CANVAS_SEARCH_TAB}>
|
|
||||||
<SearchMenu />
|
|
||||||
</Sidebar.Tab>
|
|
||||||
{children}
|
{children}
|
||||||
</Sidebar.Tabs>
|
</Sidebar.Tabs>
|
||||||
</Sidebar>
|
</Sidebar>
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ import { isEraserActive } from "../appState";
|
|||||||
import "./HintViewer.scss";
|
import "./HintViewer.scss";
|
||||||
import { isNodeInFlowchart } from "../element/flowchart";
|
import { isNodeInFlowchart } from "../element/flowchart";
|
||||||
import { isGridModeEnabled } from "../snapping";
|
import { isGridModeEnabled } from "../snapping";
|
||||||
import { CANVAS_SEARCH_TAB, DEFAULT_SIDEBAR } from "../constants";
|
import { SEARCH_SIDEBAR } from "../constants";
|
||||||
|
|
||||||
interface HintViewerProps {
|
interface HintViewerProps {
|
||||||
appState: UIAppState;
|
appState: UIAppState;
|
||||||
@@ -32,8 +32,7 @@ const getHints = ({
|
|||||||
const multiMode = appState.multiElement !== null;
|
const multiMode = appState.multiElement !== null;
|
||||||
|
|
||||||
if (
|
if (
|
||||||
appState.openSidebar?.name === DEFAULT_SIDEBAR.name &&
|
appState.openSidebar?.name === SEARCH_SIDEBAR.name &&
|
||||||
appState.openSidebar.tab === CANVAS_SEARCH_TAB &&
|
|
||||||
appState.searchMatches?.length
|
appState.searchMatches?.length
|
||||||
) {
|
) {
|
||||||
return t("hints.dismissSearch");
|
return t("hints.dismissSearch");
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import {
|
|||||||
CLASSES,
|
CLASSES,
|
||||||
DEFAULT_SIDEBAR,
|
DEFAULT_SIDEBAR,
|
||||||
LIBRARY_SIDEBAR_WIDTH,
|
LIBRARY_SIDEBAR_WIDTH,
|
||||||
|
SEARCH_SIDEBAR,
|
||||||
TOOL_TYPE,
|
TOOL_TYPE,
|
||||||
} from "../constants";
|
} from "../constants";
|
||||||
import { showSelectedShapeActions } from "../element";
|
import { showSelectedShapeActions } from "../element";
|
||||||
@@ -53,6 +54,9 @@ import { LibraryIcon } from "./icons";
|
|||||||
import { UIAppStateContext } from "../context/ui-appState";
|
import { UIAppStateContext } from "../context/ui-appState";
|
||||||
import { DefaultSidebar } from "./DefaultSidebar";
|
import { DefaultSidebar } from "./DefaultSidebar";
|
||||||
import { EyeDropper, activeEyeDropperAtom } from "./EyeDropper";
|
import { EyeDropper, activeEyeDropperAtom } from "./EyeDropper";
|
||||||
|
|
||||||
|
import "./LayerUI.scss";
|
||||||
|
import "./Toolbar.scss";
|
||||||
import { mutateElement } from "../element/mutateElement";
|
import { mutateElement } from "../element/mutateElement";
|
||||||
import { ShapeCache } from "../scene/ShapeCache";
|
import { ShapeCache } from "../scene/ShapeCache";
|
||||||
import Scene from "../scene/Scene";
|
import Scene from "../scene/Scene";
|
||||||
@@ -60,9 +64,7 @@ import { LaserPointerButton } from "./LaserPointerButton";
|
|||||||
import { TTDDialog } from "./TTDDialog/TTDDialog";
|
import { TTDDialog } from "./TTDDialog/TTDDialog";
|
||||||
import { Stats } from "./Stats";
|
import { Stats } from "./Stats";
|
||||||
import { actionToggleStats } from "../actions";
|
import { actionToggleStats } from "../actions";
|
||||||
|
import { SearchSidebar } from "./SearchSidebar";
|
||||||
import "./LayerUI.scss";
|
|
||||||
import "./Toolbar.scss";
|
|
||||||
|
|
||||||
interface LayerUIProps {
|
interface LayerUIProps {
|
||||||
actionManager: ActionManager;
|
actionManager: ActionManager;
|
||||||
@@ -363,16 +365,21 @@ const LayerUI = ({
|
|||||||
|
|
||||||
const renderSidebars = () => {
|
const renderSidebars = () => {
|
||||||
return (
|
return (
|
||||||
<DefaultSidebar
|
<>
|
||||||
__fallback
|
{appState.openSidebar?.name === SEARCH_SIDEBAR.name && (
|
||||||
onDock={(docked) => {
|
<SearchSidebar />
|
||||||
trackEvent(
|
)}
|
||||||
"sidebar",
|
<DefaultSidebar
|
||||||
`toggleDock (${docked ? "dock" : "undock"})`,
|
__fallback
|
||||||
`(${device.editor.isMobile ? "mobile" : "desktop"})`,
|
onDock={(docked) => {
|
||||||
);
|
trackEvent(
|
||||||
}}
|
"sidebar",
|
||||||
/>
|
`toggleDock (${docked ? "dock" : "undock"})`,
|
||||||
|
`(${device.editor.isMobile ? "mobile" : "desktop"})`,
|
||||||
|
);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -20,19 +20,18 @@ import { CLASSES, EVENT } from "../constants";
|
|||||||
import { useStable } from "../hooks/useStable";
|
import { useStable } from "../hooks/useStable";
|
||||||
|
|
||||||
import "./SearchMenu.scss";
|
import "./SearchMenu.scss";
|
||||||
import { round } from "../../math";
|
|
||||||
|
|
||||||
const searchQueryAtom = atom<string>("");
|
const searchKeywordAtom = atom<string>("");
|
||||||
export const searchItemInFocusAtom = atom<number | null>(null);
|
export const searchItemInFocusAtom = atom<number | null>(null);
|
||||||
|
|
||||||
const SEARCH_DEBOUNCE = 350;
|
const SEARCH_DEBOUNCE = 350;
|
||||||
|
|
||||||
type SearchMatchItem = {
|
type SearchMatchItem = {
|
||||||
textElement: ExcalidrawTextElement;
|
textElement: ExcalidrawTextElement;
|
||||||
searchQuery: SearchQuery;
|
keyword: string;
|
||||||
index: number;
|
index: number;
|
||||||
preview: {
|
preview: {
|
||||||
indexInSearchQuery: number;
|
indexInKeyword: number;
|
||||||
previewText: string;
|
previewText: string;
|
||||||
moreBefore: boolean;
|
moreBefore: boolean;
|
||||||
moreAfter: boolean;
|
moreAfter: boolean;
|
||||||
@@ -50,25 +49,19 @@ type SearchMatches = {
|
|||||||
items: SearchMatchItem[];
|
items: SearchMatchItem[];
|
||||||
};
|
};
|
||||||
|
|
||||||
type SearchQuery = string & { _brand: "SearchQuery" };
|
|
||||||
|
|
||||||
export const SearchMenu = () => {
|
export const SearchMenu = () => {
|
||||||
const app = useApp();
|
const app = useApp();
|
||||||
const setAppState = useExcalidrawSetAppState();
|
const setAppState = useExcalidrawSetAppState();
|
||||||
|
|
||||||
const searchInputRef = useRef<HTMLInputElement>(null);
|
const searchInputRef = useRef<HTMLInputElement>(null);
|
||||||
|
|
||||||
const [inputValue, setInputValue] = useAtom(searchQueryAtom, jotaiScope);
|
const [keyword, setKeyword] = useAtom(searchKeywordAtom, jotaiScope);
|
||||||
const searchQuery = inputValue.trim() as SearchQuery;
|
|
||||||
|
|
||||||
const [isSearching, setIsSearching] = useState(false);
|
|
||||||
|
|
||||||
const [searchMatches, setSearchMatches] = useState<SearchMatches>({
|
const [searchMatches, setSearchMatches] = useState<SearchMatches>({
|
||||||
nonce: null,
|
nonce: null,
|
||||||
items: [],
|
items: [],
|
||||||
});
|
});
|
||||||
const searchedQueryRef = useRef<SearchQuery | null>(null);
|
const searchedKeywordRef = useRef<string | null>();
|
||||||
const lastSceneNonceRef = useRef<number | undefined>(undefined);
|
const lastSceneNonceRef = useRef<number | undefined>();
|
||||||
|
|
||||||
const [focusIndex, setFocusIndex] = useAtom(
|
const [focusIndex, setFocusIndex] = useAtom(
|
||||||
searchItemInFocusAtom,
|
searchItemInFocusAtom,
|
||||||
@@ -77,20 +70,19 @@ export const SearchMenu = () => {
|
|||||||
const elementsMap = app.scene.getNonDeletedElementsMap();
|
const elementsMap = app.scene.getNonDeletedElementsMap();
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (isSearching) {
|
const trimmedKeyword = keyword.trim();
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (
|
if (
|
||||||
searchQuery !== searchedQueryRef.current ||
|
trimmedKeyword !== searchedKeywordRef.current ||
|
||||||
app.scene.getSceneNonce() !== lastSceneNonceRef.current
|
app.scene.getSceneNonce() !== lastSceneNonceRef.current
|
||||||
) {
|
) {
|
||||||
searchedQueryRef.current = null;
|
searchedKeywordRef.current = null;
|
||||||
handleSearch(searchQuery, app, (matchItems, index) => {
|
handleSearch(trimmedKeyword, app, (matchItems, index) => {
|
||||||
setSearchMatches({
|
setSearchMatches({
|
||||||
nonce: randomInteger(),
|
nonce: randomInteger(),
|
||||||
items: matchItems,
|
items: matchItems,
|
||||||
});
|
});
|
||||||
searchedQueryRef.current = searchQuery;
|
setFocusIndex(index);
|
||||||
|
searchedKeywordRef.current = trimmedKeyword;
|
||||||
lastSceneNonceRef.current = app.scene.getSceneNonce();
|
lastSceneNonceRef.current = app.scene.getSceneNonce();
|
||||||
setAppState({
|
setAppState({
|
||||||
searchMatches: matchItems.map((searchMatch) => ({
|
searchMatches: matchItems.map((searchMatch) => ({
|
||||||
@@ -102,8 +94,7 @@ export const SearchMenu = () => {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
}, [
|
}, [
|
||||||
isSearching,
|
keyword,
|
||||||
searchQuery,
|
|
||||||
elementsMap,
|
elementsMap,
|
||||||
app,
|
app,
|
||||||
setAppState,
|
setAppState,
|
||||||
@@ -137,42 +128,23 @@ export const SearchMenu = () => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
setAppState((state) => {
|
|
||||||
return {
|
|
||||||
searchMatches: state.searchMatches.map((match, index) => {
|
|
||||||
if (index === focusIndex) {
|
|
||||||
return { ...match, focus: true };
|
|
||||||
}
|
|
||||||
return { ...match, focus: false };
|
|
||||||
}),
|
|
||||||
};
|
|
||||||
});
|
|
||||||
}, [focusIndex, setAppState]);
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (searchMatches.items.length > 0 && focusIndex !== null) {
|
if (searchMatches.items.length > 0 && focusIndex !== null) {
|
||||||
const match = searchMatches.items[focusIndex];
|
const match = searchMatches.items[focusIndex];
|
||||||
|
|
||||||
if (match) {
|
if (match) {
|
||||||
const zoomValue = app.state.zoom.value;
|
|
||||||
|
|
||||||
const matchAsElement = newTextElement({
|
const matchAsElement = newTextElement({
|
||||||
text: match.searchQuery,
|
text: match.keyword,
|
||||||
x: match.textElement.x + (match.matchedLines[0]?.offsetX ?? 0),
|
x: match.textElement.x + (match.matchedLines[0]?.offsetX ?? 0),
|
||||||
y: match.textElement.y + (match.matchedLines[0]?.offsetY ?? 0),
|
y: match.textElement.y + (match.matchedLines[0]?.offsetY ?? 0),
|
||||||
width: match.matchedLines[0]?.width,
|
width: match.matchedLines[0]?.width,
|
||||||
height: match.matchedLines[0]?.height,
|
height: match.matchedLines[0]?.height,
|
||||||
fontSize: match.textElement.fontSize,
|
|
||||||
fontFamily: match.textElement.fontFamily,
|
|
||||||
});
|
});
|
||||||
|
|
||||||
const FONT_SIZE_LEGIBILITY_THRESHOLD = 14;
|
const isTinyText =
|
||||||
|
app.state.zoom.value *
|
||||||
const fontSize = match.textElement.fontSize;
|
searchMatches.items[focusIndex].textElement.fontSize <
|
||||||
const isTextTiny =
|
16;
|
||||||
fontSize * zoomValue < FONT_SIZE_LEGIBILITY_THRESHOLD;
|
|
||||||
|
|
||||||
if (
|
if (
|
||||||
!isElementCompletelyInViewport(
|
!isElementCompletelyInViewport(
|
||||||
[matchAsElement],
|
[matchAsElement],
|
||||||
@@ -188,44 +160,45 @@ export const SearchMenu = () => {
|
|||||||
app.scene.getNonDeletedElementsMap(),
|
app.scene.getNonDeletedElementsMap(),
|
||||||
app.getEditorUIOffsets(),
|
app.getEditorUIOffsets(),
|
||||||
) ||
|
) ||
|
||||||
isTextTiny
|
isTinyText
|
||||||
) {
|
) {
|
||||||
let zoomOptions: Parameters<AppClassProperties["scrollToContent"]>[1];
|
|
||||||
|
|
||||||
if (isTextTiny) {
|
|
||||||
if (fontSize >= FONT_SIZE_LEGIBILITY_THRESHOLD) {
|
|
||||||
zoomOptions = { fitToContent: true };
|
|
||||||
} else {
|
|
||||||
zoomOptions = {
|
|
||||||
fitToViewport: true,
|
|
||||||
// calculate zoom level to make the fontSize ~equal to FONT_SIZE_THRESHOLD, rounded to nearest 10%
|
|
||||||
maxZoom: round(FONT_SIZE_LEGIBILITY_THRESHOLD / fontSize, 1),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
zoomOptions = { fitToContent: true };
|
|
||||||
}
|
|
||||||
|
|
||||||
app.scrollToContent(matchAsElement, {
|
app.scrollToContent(matchAsElement, {
|
||||||
|
fitToContent: true,
|
||||||
animate: true,
|
animate: true,
|
||||||
duration: 300,
|
duration: 300,
|
||||||
...zoomOptions,
|
|
||||||
canvasOffsets: app.getEditorUIOffsets(),
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const nextMatches = searchMatches.items.map((match, index) => {
|
||||||
|
if (index === focusIndex) {
|
||||||
|
return {
|
||||||
|
id: match.textElement.id,
|
||||||
|
focus: true,
|
||||||
|
matchedLines: match.matchedLines,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
id: match.textElement.id,
|
||||||
|
focus: false,
|
||||||
|
matchedLines: match.matchedLines,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
setAppState({
|
||||||
|
searchMatches: nextMatches,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, [focusIndex, searchMatches, app]);
|
}, [app, focusIndex, searchMatches, setAppState]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
return () => {
|
return () => {
|
||||||
setFocusIndex(null);
|
setFocusIndex(null);
|
||||||
searchedQueryRef.current = null;
|
searchedKeywordRef.current = null;
|
||||||
lastSceneNonceRef.current = undefined;
|
lastSceneNonceRef.current = undefined;
|
||||||
setAppState({
|
setAppState({
|
||||||
searchMatches: [],
|
searchMatches: [],
|
||||||
});
|
});
|
||||||
setIsSearching(false);
|
|
||||||
};
|
};
|
||||||
}, [setAppState, setFocusIndex]);
|
}, [setAppState, setFocusIndex]);
|
||||||
|
|
||||||
@@ -308,32 +281,12 @@ export const SearchMenu = () => {
|
|||||||
<div className="layer-ui__search-header">
|
<div className="layer-ui__search-header">
|
||||||
<TextField
|
<TextField
|
||||||
className={CLASSES.SEARCH_MENU_INPUT_WRAPPER}
|
className={CLASSES.SEARCH_MENU_INPUT_WRAPPER}
|
||||||
value={inputValue}
|
value={keyword}
|
||||||
ref={searchInputRef}
|
ref={searchInputRef}
|
||||||
placeholder={t("search.placeholder")}
|
placeholder={t("search.placeholder")}
|
||||||
icon={searchIcon}
|
icon={searchIcon}
|
||||||
onChange={(value) => {
|
onChange={(value) => {
|
||||||
setInputValue(value);
|
setKeyword(value);
|
||||||
setIsSearching(true);
|
|
||||||
const searchQuery = value.trim() as SearchQuery;
|
|
||||||
handleSearch(searchQuery, app, (matchItems, index) => {
|
|
||||||
setSearchMatches({
|
|
||||||
nonce: randomInteger(),
|
|
||||||
items: matchItems,
|
|
||||||
});
|
|
||||||
setFocusIndex(index);
|
|
||||||
searchedQueryRef.current = searchQuery;
|
|
||||||
lastSceneNonceRef.current = app.scene.getSceneNonce();
|
|
||||||
setAppState({
|
|
||||||
searchMatches: matchItems.map((searchMatch) => ({
|
|
||||||
id: searchMatch.textElement.id,
|
|
||||||
focus: false,
|
|
||||||
matchedLines: searchMatch.matchedLines,
|
|
||||||
})),
|
|
||||||
});
|
|
||||||
|
|
||||||
setIsSearching(false);
|
|
||||||
});
|
|
||||||
}}
|
}}
|
||||||
selectOnRender
|
selectOnRender
|
||||||
/>
|
/>
|
||||||
@@ -371,8 +324,8 @@ export const SearchMenu = () => {
|
|||||||
)}
|
)}
|
||||||
|
|
||||||
{searchMatches.items.length === 0 &&
|
{searchMatches.items.length === 0 &&
|
||||||
searchQuery &&
|
keyword &&
|
||||||
searchedQueryRef.current && (
|
searchedKeywordRef.current && (
|
||||||
<div style={{ margin: "1rem auto" }}>{t("search.noMatch")}</div>
|
<div style={{ margin: "1rem auto" }}>{t("search.noMatch")}</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
@@ -381,7 +334,7 @@ export const SearchMenu = () => {
|
|||||||
matches={searchMatches}
|
matches={searchMatches}
|
||||||
onItemClick={setFocusIndex}
|
onItemClick={setFocusIndex}
|
||||||
focusIndex={focusIndex}
|
focusIndex={focusIndex}
|
||||||
searchQuery={searchQuery}
|
trimmedKeyword={keyword.trim()}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
@@ -389,19 +342,19 @@ export const SearchMenu = () => {
|
|||||||
|
|
||||||
const ListItem = (props: {
|
const ListItem = (props: {
|
||||||
preview: SearchMatchItem["preview"];
|
preview: SearchMatchItem["preview"];
|
||||||
searchQuery: SearchQuery;
|
trimmedKeyword: string;
|
||||||
highlighted: boolean;
|
highlighted: boolean;
|
||||||
onClick?: () => void;
|
onClick?: () => void;
|
||||||
}) => {
|
}) => {
|
||||||
const preview = [
|
const preview = [
|
||||||
props.preview.moreBefore ? "..." : "",
|
props.preview.moreBefore ? "..." : "",
|
||||||
props.preview.previewText.slice(0, props.preview.indexInSearchQuery),
|
props.preview.previewText.slice(0, props.preview.indexInKeyword),
|
||||||
props.preview.previewText.slice(
|
props.preview.previewText.slice(
|
||||||
props.preview.indexInSearchQuery,
|
props.preview.indexInKeyword,
|
||||||
props.preview.indexInSearchQuery + props.searchQuery.length,
|
props.preview.indexInKeyword + props.trimmedKeyword.length,
|
||||||
),
|
),
|
||||||
props.preview.previewText.slice(
|
props.preview.previewText.slice(
|
||||||
props.preview.indexInSearchQuery + props.searchQuery.length,
|
props.preview.indexInKeyword + props.trimmedKeyword.length,
|
||||||
),
|
),
|
||||||
props.preview.moreAfter ? "..." : "",
|
props.preview.moreAfter ? "..." : "",
|
||||||
];
|
];
|
||||||
@@ -432,7 +385,7 @@ interface MatchListProps {
|
|||||||
matches: SearchMatches;
|
matches: SearchMatches;
|
||||||
onItemClick: (index: number) => void;
|
onItemClick: (index: number) => void;
|
||||||
focusIndex: number | null;
|
focusIndex: number | null;
|
||||||
searchQuery: SearchQuery;
|
trimmedKeyword: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
const MatchListBase = (props: MatchListProps) => {
|
const MatchListBase = (props: MatchListProps) => {
|
||||||
@@ -441,7 +394,7 @@ const MatchListBase = (props: MatchListProps) => {
|
|||||||
{props.matches.items.map((searchMatch, index) => (
|
{props.matches.items.map((searchMatch, index) => (
|
||||||
<ListItem
|
<ListItem
|
||||||
key={searchMatch.textElement.id + searchMatch.index}
|
key={searchMatch.textElement.id + searchMatch.index}
|
||||||
searchQuery={props.searchQuery}
|
trimmedKeyword={props.trimmedKeyword}
|
||||||
preview={searchMatch.preview}
|
preview={searchMatch.preview}
|
||||||
highlighted={index === props.focusIndex}
|
highlighted={index === props.focusIndex}
|
||||||
onClick={() => props.onItemClick(index)}
|
onClick={() => props.onItemClick(index)}
|
||||||
@@ -460,27 +413,24 @@ const areEqual = (prevProps: MatchListProps, nextProps: MatchListProps) => {
|
|||||||
|
|
||||||
const MatchList = memo(MatchListBase, areEqual);
|
const MatchList = memo(MatchListBase, areEqual);
|
||||||
|
|
||||||
const getMatchPreview = (
|
const getMatchPreview = (text: string, index: number, keyword: string) => {
|
||||||
text: string,
|
|
||||||
index: number,
|
|
||||||
searchQuery: SearchQuery,
|
|
||||||
) => {
|
|
||||||
const WORDS_BEFORE = 2;
|
const WORDS_BEFORE = 2;
|
||||||
const WORDS_AFTER = 5;
|
const WORDS_AFTER = 5;
|
||||||
|
|
||||||
const substrBeforeQuery = text.slice(0, index);
|
const substrBeforeKeyword = text.slice(0, index);
|
||||||
const wordsBeforeQuery = substrBeforeQuery.split(/\s+/);
|
const wordsBeforeKeyword = substrBeforeKeyword.split(/\s+/);
|
||||||
// text = "small", query = "mall", not complete before
|
// text = "small", keyword = "mall", not complete before
|
||||||
// text = "small", query = "smal", complete before
|
// text = "small", keyword = "smal", complete before
|
||||||
const isQueryCompleteBefore = substrBeforeQuery.endsWith(" ");
|
const isKeywordCompleteBefore = substrBeforeKeyword.endsWith(" ");
|
||||||
const startWordIndex =
|
const startWordIndex =
|
||||||
wordsBeforeQuery.length -
|
wordsBeforeKeyword.length -
|
||||||
WORDS_BEFORE -
|
WORDS_BEFORE -
|
||||||
1 -
|
1 -
|
||||||
(isQueryCompleteBefore ? 0 : 1);
|
(isKeywordCompleteBefore ? 0 : 1);
|
||||||
let wordsBeforeAsString =
|
let wordsBeforeAsString =
|
||||||
wordsBeforeQuery.slice(startWordIndex <= 0 ? 0 : startWordIndex).join(" ") +
|
wordsBeforeKeyword
|
||||||
(isQueryCompleteBefore ? " " : "");
|
.slice(startWordIndex <= 0 ? 0 : startWordIndex)
|
||||||
|
.join(" ") + (isKeywordCompleteBefore ? " " : "");
|
||||||
|
|
||||||
const MAX_ALLOWED_CHARS = 20;
|
const MAX_ALLOWED_CHARS = 20;
|
||||||
|
|
||||||
@@ -489,21 +439,21 @@ const getMatchPreview = (
|
|||||||
? wordsBeforeAsString.slice(-MAX_ALLOWED_CHARS)
|
? wordsBeforeAsString.slice(-MAX_ALLOWED_CHARS)
|
||||||
: wordsBeforeAsString;
|
: wordsBeforeAsString;
|
||||||
|
|
||||||
const substrAfterQuery = text.slice(index + searchQuery.length);
|
const substrAfterKeyword = text.slice(index + keyword.length);
|
||||||
const wordsAfter = substrAfterQuery.split(/\s+/);
|
const wordsAfter = substrAfterKeyword.split(/\s+/);
|
||||||
// text = "small", query = "mall", complete after
|
// text = "small", keyword = "mall", complete after
|
||||||
// text = "small", query = "smal", not complete after
|
// text = "small", keyword = "smal", not complete after
|
||||||
const isQueryCompleteAfter = !substrAfterQuery.startsWith(" ");
|
const isKeywordCompleteAfter = !substrAfterKeyword.startsWith(" ");
|
||||||
const numberOfWordsToTake = isQueryCompleteAfter
|
const numberOfWordsToTake = isKeywordCompleteAfter
|
||||||
? WORDS_AFTER + 1
|
? WORDS_AFTER + 1
|
||||||
: WORDS_AFTER;
|
: WORDS_AFTER;
|
||||||
const wordsAfterAsString =
|
const wordsAfterAsString =
|
||||||
(isQueryCompleteAfter ? "" : " ") +
|
(isKeywordCompleteAfter ? "" : " ") +
|
||||||
wordsAfter.slice(0, numberOfWordsToTake).join(" ");
|
wordsAfter.slice(0, numberOfWordsToTake).join(" ");
|
||||||
|
|
||||||
return {
|
return {
|
||||||
indexInSearchQuery: wordsBeforeAsString.length,
|
indexInKeyword: wordsBeforeAsString.length,
|
||||||
previewText: wordsBeforeAsString + searchQuery + wordsAfterAsString,
|
previewText: wordsBeforeAsString + keyword + wordsAfterAsString,
|
||||||
moreBefore: startWordIndex > 0,
|
moreBefore: startWordIndex > 0,
|
||||||
moreAfter: wordsAfter.length > numberOfWordsToTake,
|
moreAfter: wordsAfter.length > numberOfWordsToTake,
|
||||||
};
|
};
|
||||||
@@ -546,7 +496,7 @@ const normalizeWrappedText = (
|
|||||||
|
|
||||||
const getMatchedLines = (
|
const getMatchedLines = (
|
||||||
textElement: ExcalidrawTextElement,
|
textElement: ExcalidrawTextElement,
|
||||||
searchQuery: SearchQuery,
|
keyword: string,
|
||||||
index: number,
|
index: number,
|
||||||
) => {
|
) => {
|
||||||
const normalizedText = normalizeWrappedText(
|
const normalizedText = normalizeWrappedText(
|
||||||
@@ -577,9 +527,9 @@ const getMatchedLines = (
|
|||||||
}
|
}
|
||||||
|
|
||||||
let startIndex = index;
|
let startIndex = index;
|
||||||
let remainingQuery = textElement.originalText.slice(
|
let remainingKeyword = textElement.originalText.slice(
|
||||||
index,
|
index,
|
||||||
index + searchQuery.length,
|
index + keyword.length,
|
||||||
);
|
);
|
||||||
const matchedLines: {
|
const matchedLines: {
|
||||||
offsetX: number;
|
offsetX: number;
|
||||||
@@ -589,7 +539,7 @@ const getMatchedLines = (
|
|||||||
}[] = [];
|
}[] = [];
|
||||||
|
|
||||||
for (const lineIndexRange of lineIndexRanges) {
|
for (const lineIndexRange of lineIndexRanges) {
|
||||||
if (remainingQuery === "") {
|
if (remainingKeyword === "") {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -603,8 +553,8 @@ const getMatchedLines = (
|
|||||||
startIndex - lineIndexRange.startIndex,
|
startIndex - lineIndexRange.startIndex,
|
||||||
);
|
);
|
||||||
|
|
||||||
const matchedWord = remainingQuery.slice(0, matchCapacity);
|
const matchedWord = remainingKeyword.slice(0, matchCapacity);
|
||||||
remainingQuery = remainingQuery.slice(matchCapacity);
|
remainingKeyword = remainingKeyword.slice(matchCapacity);
|
||||||
|
|
||||||
const offset = measureText(
|
const offset = measureText(
|
||||||
textToStart,
|
textToStart,
|
||||||
@@ -663,11 +613,11 @@ const escapeSpecialCharacters = (string: string) => {
|
|||||||
|
|
||||||
const handleSearch = debounce(
|
const handleSearch = debounce(
|
||||||
(
|
(
|
||||||
searchQuery: SearchQuery,
|
keyword: string,
|
||||||
app: AppClassProperties,
|
app: AppClassProperties,
|
||||||
cb: (matchItems: SearchMatchItem[], focusIndex: number | null) => void,
|
cb: (matchItems: SearchMatchItem[], focusIndex: number | null) => void,
|
||||||
) => {
|
) => {
|
||||||
if (!searchQuery || searchQuery === "") {
|
if (!keyword || keyword === "") {
|
||||||
cb([], null);
|
cb([], null);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -681,20 +631,20 @@ const handleSearch = debounce(
|
|||||||
|
|
||||||
const matchItems: SearchMatchItem[] = [];
|
const matchItems: SearchMatchItem[] = [];
|
||||||
|
|
||||||
const regex = new RegExp(escapeSpecialCharacters(searchQuery), "gi");
|
const regex = new RegExp(escapeSpecialCharacters(keyword), "gi");
|
||||||
|
|
||||||
for (const textEl of texts) {
|
for (const textEl of texts) {
|
||||||
let match = null;
|
let match = null;
|
||||||
const text = textEl.originalText;
|
const text = textEl.originalText;
|
||||||
|
|
||||||
while ((match = regex.exec(text)) !== null) {
|
while ((match = regex.exec(text)) !== null) {
|
||||||
const preview = getMatchPreview(text, match.index, searchQuery);
|
const preview = getMatchPreview(text, match.index, keyword);
|
||||||
const matchedLines = getMatchedLines(textEl, searchQuery, match.index);
|
const matchedLines = getMatchedLines(textEl, keyword, match.index);
|
||||||
|
|
||||||
if (matchedLines.length > 0) {
|
if (matchedLines.length > 0) {
|
||||||
matchItems.push({
|
matchItems.push({
|
||||||
textElement: textEl,
|
textElement: textEl,
|
||||||
searchQuery,
|
keyword,
|
||||||
preview,
|
preview,
|
||||||
index: match.index,
|
index: match.index,
|
||||||
matchedLines,
|
matchedLines,
|
||||||
|
|||||||
@@ -0,0 +1,29 @@
|
|||||||
|
import { SEARCH_SIDEBAR } from "../constants";
|
||||||
|
import { t } from "../i18n";
|
||||||
|
import { SearchMenu } from "./SearchMenu";
|
||||||
|
import { Sidebar } from "./Sidebar/Sidebar";
|
||||||
|
|
||||||
|
export const SearchSidebar = () => {
|
||||||
|
return (
|
||||||
|
<Sidebar name={SEARCH_SIDEBAR.name} docked>
|
||||||
|
<Sidebar.Tabs>
|
||||||
|
<Sidebar.Header>
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
color: "var(--color-primary)",
|
||||||
|
fontSize: "1.2em",
|
||||||
|
fontWeight: "bold",
|
||||||
|
textOverflow: "ellipsis",
|
||||||
|
overflow: "hidden",
|
||||||
|
whiteSpace: "nowrap",
|
||||||
|
paddingRight: "1em",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{t("search.title")}
|
||||||
|
</div>
|
||||||
|
</Sidebar.Header>
|
||||||
|
<SearchMenu />
|
||||||
|
</Sidebar.Tabs>
|
||||||
|
</Sidebar>
|
||||||
|
);
|
||||||
|
};
|
||||||
@@ -377,13 +377,16 @@ export const DEFAULT_ELEMENT_PROPS: {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const LIBRARY_SIDEBAR_TAB = "library";
|
export const LIBRARY_SIDEBAR_TAB = "library";
|
||||||
export const CANVAS_SEARCH_TAB = "search";
|
|
||||||
|
|
||||||
export const DEFAULT_SIDEBAR = {
|
export const DEFAULT_SIDEBAR = {
|
||||||
name: "default",
|
name: "default",
|
||||||
defaultTab: LIBRARY_SIDEBAR_TAB,
|
defaultTab: LIBRARY_SIDEBAR_TAB,
|
||||||
} as const;
|
} as const;
|
||||||
|
|
||||||
|
export const SEARCH_SIDEBAR = {
|
||||||
|
name: "search",
|
||||||
|
};
|
||||||
|
|
||||||
export const LIBRARY_DISABLED_TYPES = new Set([
|
export const LIBRARY_DISABLED_TYPES = new Set([
|
||||||
"iframe",
|
"iframe",
|
||||||
"embeddable",
|
"embeddable",
|
||||||
|
|||||||
@@ -57,15 +57,6 @@ export const base64ToString = async (base64: string, isByteString = false) => {
|
|||||||
: byteStringToString(window.atob(base64));
|
: byteStringToString(window.atob(base64));
|
||||||
};
|
};
|
||||||
|
|
||||||
export const base64ToArrayBuffer = (base64: string): ArrayBuffer => {
|
|
||||||
if (typeof Buffer !== "undefined") {
|
|
||||||
// Node.js environment
|
|
||||||
return Buffer.from(base64, "base64").buffer;
|
|
||||||
}
|
|
||||||
// Browser environment
|
|
||||||
return byteStringToArrayBuffer(atob(base64));
|
|
||||||
};
|
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
// text encoding
|
// text encoding
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
|
|||||||
@@ -5,7 +5,6 @@ import type {
|
|||||||
ExcalidrawLinearElement,
|
ExcalidrawLinearElement,
|
||||||
ExcalidrawSelectionElement,
|
ExcalidrawSelectionElement,
|
||||||
ExcalidrawTextElement,
|
ExcalidrawTextElement,
|
||||||
FixedPointBinding,
|
|
||||||
FontFamilyValues,
|
FontFamilyValues,
|
||||||
OrderedExcalidrawElement,
|
OrderedExcalidrawElement,
|
||||||
PointBinding,
|
PointBinding,
|
||||||
@@ -22,7 +21,6 @@ import {
|
|||||||
import {
|
import {
|
||||||
isArrowElement,
|
isArrowElement,
|
||||||
isElbowArrow,
|
isElbowArrow,
|
||||||
isFixedPointBinding,
|
|
||||||
isLinearElement,
|
isLinearElement,
|
||||||
isTextElement,
|
isTextElement,
|
||||||
isUsingAdaptiveRadius,
|
isUsingAdaptiveRadius,
|
||||||
@@ -103,8 +101,8 @@ const getFontFamilyByName = (fontFamilyName: string): FontFamilyValues => {
|
|||||||
|
|
||||||
const repairBinding = (
|
const repairBinding = (
|
||||||
element: ExcalidrawLinearElement,
|
element: ExcalidrawLinearElement,
|
||||||
binding: PointBinding | FixedPointBinding | null,
|
binding: PointBinding | null,
|
||||||
): PointBinding | FixedPointBinding | null => {
|
): PointBinding | null => {
|
||||||
if (!binding) {
|
if (!binding) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@@ -112,11 +110,9 @@ const repairBinding = (
|
|||||||
return {
|
return {
|
||||||
...binding,
|
...binding,
|
||||||
focus: binding.focus || 0,
|
focus: binding.focus || 0,
|
||||||
...(isElbowArrow(element) && isFixedPointBinding(binding)
|
fixedPoint: isElbowArrow(element)
|
||||||
? {
|
? normalizeFixedPoint(binding.fixedPoint ?? [0, 0])
|
||||||
fixedPoint: normalizeFixedPoint(binding.fixedPoint ?? [0, 0]),
|
: null,
|
||||||
}
|
|
||||||
: {}),
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -39,7 +39,6 @@ import {
|
|||||||
isBindingElement,
|
isBindingElement,
|
||||||
isBoundToContainer,
|
isBoundToContainer,
|
||||||
isElbowArrow,
|
isElbowArrow,
|
||||||
isFixedPointBinding,
|
|
||||||
isFrameLikeElement,
|
isFrameLikeElement,
|
||||||
isLinearElement,
|
isLinearElement,
|
||||||
isRectangularElement,
|
isRectangularElement,
|
||||||
@@ -798,7 +797,7 @@ export const bindPointToSnapToElementOutline = (
|
|||||||
isVertical
|
isVertical
|
||||||
? Math.abs(p[1] - i[1]) < 0.1
|
? Math.abs(p[1] - i[1]) < 0.1
|
||||||
: Math.abs(p[0] - i[0]) < 0.1,
|
: Math.abs(p[0] - i[0]) < 0.1,
|
||||||
)[0] ?? p;
|
)[0] ?? point;
|
||||||
}
|
}
|
||||||
|
|
||||||
return p;
|
return p;
|
||||||
@@ -1014,7 +1013,7 @@ const updateBoundPoint = (
|
|||||||
const direction = startOrEnd === "startBinding" ? -1 : 1;
|
const direction = startOrEnd === "startBinding" ? -1 : 1;
|
||||||
const edgePointIndex = direction === -1 ? 0 : linearElement.points.length - 1;
|
const edgePointIndex = direction === -1 ? 0 : linearElement.points.length - 1;
|
||||||
|
|
||||||
if (isElbowArrow(linearElement) && isFixedPointBinding(binding)) {
|
if (isElbowArrow(linearElement)) {
|
||||||
const fixedPoint =
|
const fixedPoint =
|
||||||
normalizeFixedPoint(binding.fixedPoint) ??
|
normalizeFixedPoint(binding.fixedPoint) ??
|
||||||
calculateFixedPointForElbowArrowBinding(
|
calculateFixedPointForElbowArrowBinding(
|
||||||
|
|||||||
@@ -35,6 +35,7 @@ export const dragSelectedElements = (
|
|||||||
) => {
|
) => {
|
||||||
if (
|
if (
|
||||||
_selectedElements.length === 1 &&
|
_selectedElements.length === 1 &&
|
||||||
|
isArrowElement(_selectedElements[0]) &&
|
||||||
isElbowArrow(_selectedElements[0]) &&
|
isElbowArrow(_selectedElements[0]) &&
|
||||||
(_selectedElements[0].startBinding || _selectedElements[0].endBinding)
|
(_selectedElements[0].startBinding || _selectedElements[0].endBinding)
|
||||||
) {
|
) {
|
||||||
@@ -42,7 +43,13 @@ export const dragSelectedElements = (
|
|||||||
}
|
}
|
||||||
|
|
||||||
const selectedElements = _selectedElements.filter(
|
const selectedElements = _selectedElements.filter(
|
||||||
(el) => !(isElbowArrow(el) && el.startBinding && el.endBinding),
|
(el) =>
|
||||||
|
!(
|
||||||
|
isArrowElement(el) &&
|
||||||
|
isElbowArrow(el) &&
|
||||||
|
el.startBinding &&
|
||||||
|
el.endBinding
|
||||||
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
// we do not want a frame and its elements to be selected at the same time
|
// we do not want a frame and its elements to be selected at the same time
|
||||||
|
|||||||
@@ -102,7 +102,6 @@ export class LinearElementEditor {
|
|||||||
public readonly endBindingElement: ExcalidrawBindableElement | null | "keep";
|
public readonly endBindingElement: ExcalidrawBindableElement | null | "keep";
|
||||||
public readonly hoverPointIndex: number;
|
public readonly hoverPointIndex: number;
|
||||||
public readonly segmentMidPointHoveredCoords: GlobalPoint | null;
|
public readonly segmentMidPointHoveredCoords: GlobalPoint | null;
|
||||||
public readonly elbowed: boolean;
|
|
||||||
|
|
||||||
constructor(element: NonDeleted<ExcalidrawLinearElement>) {
|
constructor(element: NonDeleted<ExcalidrawLinearElement>) {
|
||||||
this.elementId = element.id as string & {
|
this.elementId = element.id as string & {
|
||||||
@@ -132,7 +131,6 @@ export class LinearElementEditor {
|
|||||||
};
|
};
|
||||||
this.hoverPointIndex = -1;
|
this.hoverPointIndex = -1;
|
||||||
this.segmentMidPointHoveredCoords = null;
|
this.segmentMidPointHoveredCoords = null;
|
||||||
this.elbowed = isElbowArrow(element) && element.elbowed;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
@@ -1479,9 +1477,7 @@ export class LinearElementEditor {
|
|||||||
nextPoints,
|
nextPoints,
|
||||||
vector(offsetX, offsetY),
|
vector(offsetX, offsetY),
|
||||||
bindings,
|
bindings,
|
||||||
{
|
options,
|
||||||
isDragging: options?.isDragging,
|
|
||||||
},
|
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
const nextCoords = getElementPointsCoords(element, nextPoints);
|
const nextCoords = getElementPointsCoords(element, nextPoints);
|
||||||
|
|||||||
@@ -223,6 +223,7 @@ export const newTextElement = (
|
|||||||
verticalAlign?: VerticalAlign;
|
verticalAlign?: VerticalAlign;
|
||||||
containerId?: ExcalidrawTextContainer["id"] | null;
|
containerId?: ExcalidrawTextContainer["id"] | null;
|
||||||
lineHeight?: ExcalidrawTextElement["lineHeight"];
|
lineHeight?: ExcalidrawTextElement["lineHeight"];
|
||||||
|
strokeWidth?: ExcalidrawTextElement["strokeWidth"];
|
||||||
autoResize?: ExcalidrawTextElement["autoResize"];
|
autoResize?: ExcalidrawTextElement["autoResize"];
|
||||||
} & ElementConstructorOpts,
|
} & ElementConstructorOpts,
|
||||||
): NonDeleted<ExcalidrawTextElement> => {
|
): NonDeleted<ExcalidrawTextElement> => {
|
||||||
|
|||||||
@@ -9,7 +9,6 @@ import type {
|
|||||||
ExcalidrawTextElementWithContainer,
|
ExcalidrawTextElementWithContainer,
|
||||||
ExcalidrawImageElement,
|
ExcalidrawImageElement,
|
||||||
ElementsMap,
|
ElementsMap,
|
||||||
ExcalidrawArrowElement,
|
|
||||||
NonDeletedSceneElementsMap,
|
NonDeletedSceneElementsMap,
|
||||||
SceneElementsMap,
|
SceneElementsMap,
|
||||||
} from "./types";
|
} from "./types";
|
||||||
@@ -910,8 +909,6 @@ export const resizeMultipleElements = (
|
|||||||
fontSize?: ExcalidrawTextElement["fontSize"];
|
fontSize?: ExcalidrawTextElement["fontSize"];
|
||||||
scale?: ExcalidrawImageElement["scale"];
|
scale?: ExcalidrawImageElement["scale"];
|
||||||
boundTextFontSize?: ExcalidrawTextElement["fontSize"];
|
boundTextFontSize?: ExcalidrawTextElement["fontSize"];
|
||||||
startBinding?: ExcalidrawArrowElement["startBinding"];
|
|
||||||
endBinding?: ExcalidrawArrowElement["endBinding"];
|
|
||||||
};
|
};
|
||||||
}[] = [];
|
}[] = [];
|
||||||
|
|
||||||
@@ -996,6 +993,19 @@ export const resizeMultipleElements = (
|
|||||||
|
|
||||||
mutateElement(element, update, false);
|
mutateElement(element, update, false);
|
||||||
|
|
||||||
|
if (isArrowElement(element) && isElbowArrow(element)) {
|
||||||
|
mutateElbowArrow(
|
||||||
|
element,
|
||||||
|
elementsMap,
|
||||||
|
element.points,
|
||||||
|
undefined,
|
||||||
|
undefined,
|
||||||
|
{
|
||||||
|
informMutation: false,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
updateBoundElements(element, elementsMap, {
|
updateBoundElements(element, elementsMap, {
|
||||||
simultaneouslyUpdated: elementsToUpdate,
|
simultaneouslyUpdated: elementsToUpdate,
|
||||||
oldSize: { width: oldWidth, height: oldHeight },
|
oldSize: { width: oldWidth, height: oldHeight },
|
||||||
@@ -1049,7 +1059,7 @@ const rotateMultipleElements = (
|
|||||||
(centerAngle + origAngle - element.angle) as Radians,
|
(centerAngle + origAngle - element.angle) as Radians,
|
||||||
);
|
);
|
||||||
|
|
||||||
if (isElbowArrow(element)) {
|
if (isArrowElement(element) && isElbowArrow(element)) {
|
||||||
const points = getArrowLocalFixedPoints(element, elementsMap);
|
const points = getArrowLocalFixedPoints(element, elementsMap);
|
||||||
mutateElbowArrow(element, elementsMap, points);
|
mutateElbowArrow(element, elementsMap, points);
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -94,16 +94,7 @@ describe("elbow arrow routing", () => {
|
|||||||
|
|
||||||
describe("elbow arrow ui", () => {
|
describe("elbow arrow ui", () => {
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
localStorage.clear();
|
|
||||||
await render(<Excalidraw handleKeyboardGlobally={true} />);
|
await render(<Excalidraw handleKeyboardGlobally={true} />);
|
||||||
|
|
||||||
fireEvent.contextMenu(GlobalTestState.interactiveCanvas, {
|
|
||||||
button: 2,
|
|
||||||
clientX: 1,
|
|
||||||
clientY: 1,
|
|
||||||
});
|
|
||||||
const contextMenu = UI.queryContextMenu();
|
|
||||||
fireEvent.click(queryByTestId(contextMenu!, "stats")!);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it("can follow bound shapes", async () => {
|
it("can follow bound shapes", async () => {
|
||||||
@@ -139,8 +130,8 @@ describe("elbow arrow ui", () => {
|
|||||||
expect(arrow.elbowed).toBe(true);
|
expect(arrow.elbowed).toBe(true);
|
||||||
expect(arrow.points).toEqual([
|
expect(arrow.points).toEqual([
|
||||||
[0, 0],
|
[0, 0],
|
||||||
[45, 0],
|
[35, 0],
|
||||||
[45, 200],
|
[35, 200],
|
||||||
[90, 200],
|
[90, 200],
|
||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
@@ -172,6 +163,14 @@ describe("elbow arrow ui", () => {
|
|||||||
h.state,
|
h.state,
|
||||||
)[0] as ExcalidrawArrowElement;
|
)[0] as ExcalidrawArrowElement;
|
||||||
|
|
||||||
|
fireEvent.contextMenu(GlobalTestState.interactiveCanvas, {
|
||||||
|
button: 2,
|
||||||
|
clientX: 1,
|
||||||
|
clientY: 1,
|
||||||
|
});
|
||||||
|
const contextMenu = UI.queryContextMenu();
|
||||||
|
fireEvent.click(queryByTestId(contextMenu!, "stats")!);
|
||||||
|
|
||||||
mouse.click(51, 51);
|
mouse.click(51, 51);
|
||||||
|
|
||||||
const inputAngle = UI.queryStatsProperty("A")?.querySelector(
|
const inputAngle = UI.queryStatsProperty("A")?.querySelector(
|
||||||
@@ -183,8 +182,8 @@ describe("elbow arrow ui", () => {
|
|||||||
[0, 0],
|
[0, 0],
|
||||||
[35, 0],
|
[35, 0],
|
||||||
[35, 90],
|
[35, 90],
|
||||||
[35, 90], // Note that coordinates are rounded above!
|
[25, 90],
|
||||||
[35, 165],
|
[25, 165],
|
||||||
[103, 165],
|
[103, 165],
|
||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -36,11 +36,11 @@ import {
|
|||||||
HEADING_UP,
|
HEADING_UP,
|
||||||
vectorToHeading,
|
vectorToHeading,
|
||||||
} from "./heading";
|
} from "./heading";
|
||||||
import type { ElementUpdate } from "./mutateElement";
|
|
||||||
import { mutateElement } from "./mutateElement";
|
import { mutateElement } from "./mutateElement";
|
||||||
import { isBindableElement, isRectanguloidElement } from "./typeChecks";
|
import { isBindableElement, isRectanguloidElement } from "./typeChecks";
|
||||||
import type {
|
import type {
|
||||||
ExcalidrawElbowArrowElement,
|
ExcalidrawElbowArrowElement,
|
||||||
|
FixedPointBinding,
|
||||||
NonDeletedSceneElementsMap,
|
NonDeletedSceneElementsMap,
|
||||||
SceneElementsMap,
|
SceneElementsMap,
|
||||||
} from "./types";
|
} from "./types";
|
||||||
@@ -72,48 +72,16 @@ export const mutateElbowArrow = (
|
|||||||
elementsMap: NonDeletedSceneElementsMap | SceneElementsMap,
|
elementsMap: NonDeletedSceneElementsMap | SceneElementsMap,
|
||||||
nextPoints: readonly LocalPoint[],
|
nextPoints: readonly LocalPoint[],
|
||||||
offset?: Vector,
|
offset?: Vector,
|
||||||
otherUpdates?: Omit<
|
otherUpdates?: {
|
||||||
ElementUpdate<ExcalidrawElbowArrowElement>,
|
startBinding?: FixedPointBinding | null;
|
||||||
"angle" | "x" | "y" | "width" | "height" | "elbowed" | "points"
|
endBinding?: FixedPointBinding | null;
|
||||||
>,
|
|
||||||
options?: {
|
|
||||||
isDragging?: boolean;
|
|
||||||
informMutation?: boolean;
|
|
||||||
},
|
},
|
||||||
) => {
|
|
||||||
const update = updateElbowArrow(
|
|
||||||
arrow,
|
|
||||||
elementsMap,
|
|
||||||
nextPoints,
|
|
||||||
offset,
|
|
||||||
options,
|
|
||||||
);
|
|
||||||
if (update) {
|
|
||||||
mutateElement(
|
|
||||||
arrow,
|
|
||||||
{
|
|
||||||
...otherUpdates,
|
|
||||||
...update,
|
|
||||||
angle: 0 as Radians,
|
|
||||||
},
|
|
||||||
options?.informMutation,
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
console.error("Elbow arrow cannot find a route");
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
export const updateElbowArrow = (
|
|
||||||
arrow: ExcalidrawElbowArrowElement,
|
|
||||||
elementsMap: NonDeletedSceneElementsMap | SceneElementsMap,
|
|
||||||
nextPoints: readonly LocalPoint[],
|
|
||||||
offset?: Vector,
|
|
||||||
options?: {
|
options?: {
|
||||||
isDragging?: boolean;
|
isDragging?: boolean;
|
||||||
disableBinding?: boolean;
|
disableBinding?: boolean;
|
||||||
informMutation?: boolean;
|
informMutation?: boolean;
|
||||||
},
|
},
|
||||||
): ElementUpdate<ExcalidrawElbowArrowElement> | null => {
|
) => {
|
||||||
const origStartGlobalPoint: GlobalPoint = pointTranslate(
|
const origStartGlobalPoint: GlobalPoint = pointTranslate(
|
||||||
pointTranslate<LocalPoint, GlobalPoint>(
|
pointTranslate<LocalPoint, GlobalPoint>(
|
||||||
nextPoints[0],
|
nextPoints[0],
|
||||||
@@ -267,8 +235,6 @@ export const updateElbowArrow = (
|
|||||||
BASE_PADDING,
|
BASE_PADDING,
|
||||||
),
|
),
|
||||||
boundsOverlap,
|
boundsOverlap,
|
||||||
hoveredStartElement && aabbForElement(hoveredStartElement),
|
|
||||||
hoveredEndElement && aabbForElement(hoveredEndElement),
|
|
||||||
);
|
);
|
||||||
const startDonglePosition = getDonglePosition(
|
const startDonglePosition = getDonglePosition(
|
||||||
dynamicAABBs[0],
|
dynamicAABBs[0],
|
||||||
@@ -329,10 +295,18 @@ export const updateElbowArrow = (
|
|||||||
startDongle && points.unshift(startGlobalPoint);
|
startDongle && points.unshift(startGlobalPoint);
|
||||||
endDongle && points.push(endGlobalPoint);
|
endDongle && points.push(endGlobalPoint);
|
||||||
|
|
||||||
return normalizedArrowElementUpdate(simplifyElbowArrowPoints(points), 0, 0);
|
mutateElement(
|
||||||
|
arrow,
|
||||||
|
{
|
||||||
|
...otherUpdates,
|
||||||
|
...normalizedArrowElementUpdate(simplifyElbowArrowPoints(points), 0, 0),
|
||||||
|
angle: 0 as Radians,
|
||||||
|
},
|
||||||
|
options?.informMutation,
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
console.error("Elbow arrow cannot find a route");
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const offsetFromHeading = (
|
const offsetFromHeading = (
|
||||||
@@ -501,11 +475,7 @@ const generateDynamicAABBs = (
|
|||||||
startDifference?: [number, number, number, number],
|
startDifference?: [number, number, number, number],
|
||||||
endDifference?: [number, number, number, number],
|
endDifference?: [number, number, number, number],
|
||||||
disableSideHack?: boolean,
|
disableSideHack?: boolean,
|
||||||
startElementBounds?: Bounds | null,
|
|
||||||
endElementBounds?: Bounds | null,
|
|
||||||
): Bounds[] => {
|
): Bounds[] => {
|
||||||
const startEl = startElementBounds ?? a;
|
|
||||||
const endEl = endElementBounds ?? b;
|
|
||||||
const [startUp, startRight, startDown, startLeft] = startDifference ?? [
|
const [startUp, startRight, startDown, startLeft] = startDifference ?? [
|
||||||
0, 0, 0, 0,
|
0, 0, 0, 0,
|
||||||
];
|
];
|
||||||
@@ -514,29 +484,29 @@ const generateDynamicAABBs = (
|
|||||||
const first = [
|
const first = [
|
||||||
a[0] > b[2]
|
a[0] > b[2]
|
||||||
? a[1] > b[3] || a[3] < b[1]
|
? a[1] > b[3] || a[3] < b[1]
|
||||||
? Math.min((startEl[0] + endEl[2]) / 2, a[0] - startLeft)
|
? Math.min((a[0] + b[2]) / 2, a[0] - startLeft)
|
||||||
: (startEl[0] + endEl[2]) / 2
|
: (a[0] + b[2]) / 2
|
||||||
: a[0] > b[0]
|
: a[0] > b[0]
|
||||||
? a[0] - startLeft
|
? a[0] - startLeft
|
||||||
: common[0] - startLeft,
|
: common[0] - startLeft,
|
||||||
a[1] > b[3]
|
a[1] > b[3]
|
||||||
? a[0] > b[2] || a[2] < b[0]
|
? a[0] > b[2] || a[2] < b[0]
|
||||||
? Math.min((startEl[1] + endEl[3]) / 2, a[1] - startUp)
|
? Math.min((a[1] + b[3]) / 2, a[1] - startUp)
|
||||||
: (startEl[1] + endEl[3]) / 2
|
: (a[1] + b[3]) / 2
|
||||||
: a[1] > b[1]
|
: a[1] > b[1]
|
||||||
? a[1] - startUp
|
? a[1] - startUp
|
||||||
: common[1] - startUp,
|
: common[1] - startUp,
|
||||||
a[2] < b[0]
|
a[2] < b[0]
|
||||||
? a[1] > b[3] || a[3] < b[1]
|
? a[1] > b[3] || a[3] < b[1]
|
||||||
? Math.max((startEl[2] + endEl[0]) / 2, a[2] + startRight)
|
? Math.max((a[2] + b[0]) / 2, a[2] + startRight)
|
||||||
: (startEl[2] + endEl[0]) / 2
|
: (a[2] + b[0]) / 2
|
||||||
: a[2] < b[2]
|
: a[2] < b[2]
|
||||||
? a[2] + startRight
|
? a[2] + startRight
|
||||||
: common[2] + startRight,
|
: common[2] + startRight,
|
||||||
a[3] < b[1]
|
a[3] < b[1]
|
||||||
? a[0] > b[2] || a[2] < b[0]
|
? a[0] > b[2] || a[2] < b[0]
|
||||||
? Math.max((startEl[3] + endEl[1]) / 2, a[3] + startDown)
|
? Math.max((a[3] + b[1]) / 2, a[3] + startDown)
|
||||||
: (startEl[3] + endEl[1]) / 2
|
: (a[3] + b[1]) / 2
|
||||||
: a[3] < b[3]
|
: a[3] < b[3]
|
||||||
? a[3] + startDown
|
? a[3] + startDown
|
||||||
: common[3] + startDown,
|
: common[3] + startDown,
|
||||||
@@ -544,29 +514,29 @@ const generateDynamicAABBs = (
|
|||||||
const second = [
|
const second = [
|
||||||
b[0] > a[2]
|
b[0] > a[2]
|
||||||
? b[1] > a[3] || b[3] < a[1]
|
? b[1] > a[3] || b[3] < a[1]
|
||||||
? Math.min((endEl[0] + startEl[2]) / 2, b[0] - endLeft)
|
? Math.min((b[0] + a[2]) / 2, b[0] - endLeft)
|
||||||
: (endEl[0] + startEl[2]) / 2
|
: (b[0] + a[2]) / 2
|
||||||
: b[0] > a[0]
|
: b[0] > a[0]
|
||||||
? b[0] - endLeft
|
? b[0] - endLeft
|
||||||
: common[0] - endLeft,
|
: common[0] - endLeft,
|
||||||
b[1] > a[3]
|
b[1] > a[3]
|
||||||
? b[0] > a[2] || b[2] < a[0]
|
? b[0] > a[2] || b[2] < a[0]
|
||||||
? Math.min((endEl[1] + startEl[3]) / 2, b[1] - endUp)
|
? Math.min((b[1] + a[3]) / 2, b[1] - endUp)
|
||||||
: (endEl[1] + startEl[3]) / 2
|
: (b[1] + a[3]) / 2
|
||||||
: b[1] > a[1]
|
: b[1] > a[1]
|
||||||
? b[1] - endUp
|
? b[1] - endUp
|
||||||
: common[1] - endUp,
|
: common[1] - endUp,
|
||||||
b[2] < a[0]
|
b[2] < a[0]
|
||||||
? b[1] > a[3] || b[3] < a[1]
|
? b[1] > a[3] || b[3] < a[1]
|
||||||
? Math.max((endEl[2] + startEl[0]) / 2, b[2] + endRight)
|
? Math.max((b[2] + a[0]) / 2, b[2] + endRight)
|
||||||
: (endEl[2] + startEl[0]) / 2
|
: (b[2] + a[0]) / 2
|
||||||
: b[2] < a[2]
|
: b[2] < a[2]
|
||||||
? b[2] + endRight
|
? b[2] + endRight
|
||||||
: common[2] + endRight,
|
: common[2] + endRight,
|
||||||
b[3] < a[1]
|
b[3] < a[1]
|
||||||
? b[0] > a[2] || b[2] < a[0]
|
? b[0] > a[2] || b[2] < a[0]
|
||||||
? Math.max((endEl[3] + startEl[1]) / 2, b[3] + endDown)
|
? Math.max((b[3] + a[1]) / 2, b[3] + endDown)
|
||||||
: (endEl[3] + startEl[1]) / 2
|
: (b[3] + a[1]) / 2
|
||||||
: b[3] < a[3]
|
: b[3] < a[3]
|
||||||
? b[3] + endDown
|
? b[3] + endDown
|
||||||
: common[3] + endDown,
|
: common[3] + endDown,
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import type { ElementsMap, ExcalidrawElement } from "./types";
|
|||||||
import { mutateElement } from "./mutateElement";
|
import { mutateElement } from "./mutateElement";
|
||||||
import { isFreeDrawElement, isLinearElement } from "./typeChecks";
|
import { isFreeDrawElement, isLinearElement } from "./typeChecks";
|
||||||
import { SHIFT_LOCKING_ANGLE } from "../constants";
|
import { SHIFT_LOCKING_ANGLE } from "../constants";
|
||||||
import type { AppState, Offsets, Zoom } from "../types";
|
import type { AppState, Zoom } from "../types";
|
||||||
import { getCommonBounds, getElementBounds } from "./bounds";
|
import { getCommonBounds, getElementBounds } from "./bounds";
|
||||||
import { viewportCoordsToSceneCoords } from "../utils";
|
import { viewportCoordsToSceneCoords } from "../utils";
|
||||||
|
|
||||||
@@ -67,7 +67,12 @@ export const isElementCompletelyInViewport = (
|
|||||||
scrollY: number;
|
scrollY: number;
|
||||||
},
|
},
|
||||||
elementsMap: ElementsMap,
|
elementsMap: ElementsMap,
|
||||||
padding?: Offsets,
|
padding?: Partial<{
|
||||||
|
top: number;
|
||||||
|
right: number;
|
||||||
|
bottom: number;
|
||||||
|
left: number;
|
||||||
|
}>,
|
||||||
) => {
|
) => {
|
||||||
const [x1, y1, x2, y2] = getCommonBounds(elements, elementsMap); // scene coordinates
|
const [x1, y1, x2, y2] = getCommonBounds(elements, elementsMap); // scene coordinates
|
||||||
const topLeftSceneCoords = viewportCoordsToSceneCoords(
|
const topLeftSceneCoords = viewportCoordsToSceneCoords(
|
||||||
|
|||||||
@@ -247,7 +247,7 @@ export const textWysiwyg = ({
|
|||||||
|
|
||||||
// adding left and right padding buffer, so that browser does not cut the glyphs (does not work in Safari)
|
// adding left and right padding buffer, so that browser does not cut the glyphs (does not work in Safari)
|
||||||
const padding = !isSafari
|
const padding = !isSafari
|
||||||
? Math.ceil(updatedTextElement.fontSize / appState.zoom.value / 2)
|
? Math.ceil(updatedTextElement.fontSize / 2)
|
||||||
: 0;
|
: 0;
|
||||||
|
|
||||||
// Make sure text editor height doesn't go beyond viewport
|
// Make sure text editor height doesn't go beyond viewport
|
||||||
|
|||||||
@@ -320,12 +320,9 @@ export const getDefaultRoundnessTypeForElement = (
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const isFixedPointBinding = (
|
export const isFixedPointBinding = (
|
||||||
binding: PointBinding | FixedPointBinding,
|
binding: PointBinding,
|
||||||
): binding is FixedPointBinding => {
|
): binding is FixedPointBinding => {
|
||||||
return (
|
return binding.fixedPoint != null;
|
||||||
Object.hasOwn(binding, "fixedPoint") &&
|
|
||||||
(binding as FixedPointBinding).fixedPoint != null
|
|
||||||
);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// TODO: Move this to @excalidraw/math
|
// TODO: Move this to @excalidraw/math
|
||||||
|
|||||||
@@ -193,7 +193,6 @@ export type ExcalidrawElement =
|
|||||||
| ExcalidrawGenericElement
|
| ExcalidrawGenericElement
|
||||||
| ExcalidrawTextElement
|
| ExcalidrawTextElement
|
||||||
| ExcalidrawLinearElement
|
| ExcalidrawLinearElement
|
||||||
| ExcalidrawArrowElement
|
|
||||||
| ExcalidrawFreeDrawElement
|
| ExcalidrawFreeDrawElement
|
||||||
| ExcalidrawImageElement
|
| ExcalidrawImageElement
|
||||||
| ExcalidrawFrameElement
|
| ExcalidrawFrameElement
|
||||||
@@ -269,19 +268,15 @@ export type PointBinding = {
|
|||||||
elementId: ExcalidrawBindableElement["id"];
|
elementId: ExcalidrawBindableElement["id"];
|
||||||
focus: number;
|
focus: number;
|
||||||
gap: number;
|
gap: number;
|
||||||
|
// Represents the fixed point binding information in form of a vertical and
|
||||||
|
// horizontal ratio (i.e. a percentage value in the 0.0-1.0 range). This ratio
|
||||||
|
// gives the user selected fixed point by multiplying the bound element width
|
||||||
|
// with fixedPoint[0] and the bound element height with fixedPoint[1] to get the
|
||||||
|
// bound element-local point coordinate.
|
||||||
|
fixedPoint: FixedPoint | null;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type FixedPointBinding = Merge<
|
export type FixedPointBinding = Merge<PointBinding, { fixedPoint: FixedPoint }>;
|
||||||
PointBinding,
|
|
||||||
{
|
|
||||||
// Represents the fixed point binding information in form of a vertical and
|
|
||||||
// horizontal ratio (i.e. a percentage value in the 0.0-1.0 range). This ratio
|
|
||||||
// gives the user selected fixed point by multiplying the bound element width
|
|
||||||
// with fixedPoint[0] and the bound element height with fixedPoint[1] to get the
|
|
||||||
// bound element-local point coordinate.
|
|
||||||
fixedPoint: FixedPoint;
|
|
||||||
}
|
|
||||||
>;
|
|
||||||
|
|
||||||
export type Arrowhead =
|
export type Arrowhead =
|
||||||
| "arrow"
|
| "arrow"
|
||||||
|
|||||||
@@ -1,8 +1,4 @@
|
|||||||
import {
|
import { stringToBase64, toByteString } from "../data/encode";
|
||||||
base64ToArrayBuffer,
|
|
||||||
stringToBase64,
|
|
||||||
toByteString,
|
|
||||||
} from "../data/encode";
|
|
||||||
import { LOCAL_FONT_PROTOCOL } from "./metadata";
|
import { LOCAL_FONT_PROTOCOL } from "./metadata";
|
||||||
import loadWoff2 from "./wasm/woff2.loader";
|
import loadWoff2 from "./wasm/woff2.loader";
|
||||||
import loadHbSubset from "./wasm/hb-subset.loader";
|
import loadHbSubset from "./wasm/hb-subset.loader";
|
||||||
@@ -53,7 +49,10 @@ export class ExcalidrawFont implements Font {
|
|||||||
|
|
||||||
// it's dataurl (server), the font is inlined as base64, no need to fetch
|
// it's dataurl (server), the font is inlined as base64, no need to fetch
|
||||||
if (url.protocol === "data:") {
|
if (url.protocol === "data:") {
|
||||||
const arrayBuffer = base64ToArrayBuffer(url.toString().split(",")[1]);
|
const arrayBuffer = Buffer.from(
|
||||||
|
url.toString().split(",")[1],
|
||||||
|
"base64",
|
||||||
|
).buffer;
|
||||||
|
|
||||||
const base64 = await ExcalidrawFont.subsetGlyphsByCodePoints(
|
const base64 = await ExcalidrawFont.subsetGlyphsByCodePoints(
|
||||||
arrayBuffer,
|
arrayBuffer,
|
||||||
|
|||||||
@@ -167,7 +167,7 @@
|
|||||||
"noMatch": "No matches found...",
|
"noMatch": "No matches found...",
|
||||||
"singleResult": "result",
|
"singleResult": "result",
|
||||||
"multipleResults": "results",
|
"multipleResults": "results",
|
||||||
"placeholder": "Find text on canvas..."
|
"placeholder": "Find text..."
|
||||||
},
|
},
|
||||||
"buttons": {
|
"buttons": {
|
||||||
"clearReset": "Reset the canvas",
|
"clearReset": "Reset the canvas",
|
||||||
@@ -230,8 +230,7 @@
|
|||||||
"resetLibrary": "This will clear your library. Are you sure?",
|
"resetLibrary": "This will clear your library. Are you sure?",
|
||||||
"removeItemsFromsLibrary": "Delete {{count}} item(s) from library?",
|
"removeItemsFromsLibrary": "Delete {{count}} item(s) from library?",
|
||||||
"invalidEncryptionKey": "Encryption key must be of 22 characters. Live collaboration is disabled.",
|
"invalidEncryptionKey": "Encryption key must be of 22 characters. Live collaboration is disabled.",
|
||||||
"collabOfflineWarning": "No internet connection available.\nYour changes will not be saved!",
|
"collabOfflineWarning": "No internet connection available.\nYour changes will not be saved!"
|
||||||
"saveYourContent": "Don't forget to save your content ({{shortcut}})!"
|
|
||||||
},
|
},
|
||||||
"errors": {
|
"errors": {
|
||||||
"unsupportedFileType": "Unsupported file type.",
|
"unsupportedFileType": "Unsupported file type.",
|
||||||
|
|||||||
@@ -52,6 +52,7 @@ import {
|
|||||||
} from "./helpers";
|
} from "./helpers";
|
||||||
import oc from "open-color";
|
import oc from "open-color";
|
||||||
import {
|
import {
|
||||||
|
isArrowElement,
|
||||||
isElbowArrow,
|
isElbowArrow,
|
||||||
isFrameLikeElement,
|
isFrameLikeElement,
|
||||||
isLinearElement,
|
isLinearElement,
|
||||||
@@ -806,6 +807,7 @@ const _renderInteractiveScene = ({
|
|||||||
// Elbow arrow elements cannot be selected when bound on either end
|
// Elbow arrow elements cannot be selected when bound on either end
|
||||||
(
|
(
|
||||||
isSingleLinearElementSelected &&
|
isSingleLinearElementSelected &&
|
||||||
|
isArrowElement(element) &&
|
||||||
isElbowArrow(element) &&
|
isElbowArrow(element) &&
|
||||||
(element.startBinding || element.endBinding)
|
(element.startBinding || element.endBinding)
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -421,7 +421,6 @@ const renderElementToSvg = (
|
|||||||
image.setAttribute("width", "100%");
|
image.setAttribute("width", "100%");
|
||||||
image.setAttribute("height", "100%");
|
image.setAttribute("height", "100%");
|
||||||
image.setAttribute("href", fileData.dataURL);
|
image.setAttribute("href", fileData.dataURL);
|
||||||
image.setAttribute("preserveAspectRatio", "none");
|
|
||||||
|
|
||||||
symbol.appendChild(image);
|
symbol.appendChild(image);
|
||||||
|
|
||||||
|
|||||||
@@ -185,11 +185,6 @@ export const exportToCanvas = async (
|
|||||||
exportingFrame ?? null,
|
exportingFrame ?? null,
|
||||||
appState.frameRendering ?? null,
|
appState.frameRendering ?? null,
|
||||||
);
|
);
|
||||||
// for canvas export, don't clip if exporting a specific frame as it would
|
|
||||||
// clip the corners of the content
|
|
||||||
if (exportingFrame) {
|
|
||||||
frameRendering.clip = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
const elementsForRender = prepareElementsForRender({
|
const elementsForRender = prepareElementsForRender({
|
||||||
elements,
|
elements,
|
||||||
@@ -356,11 +351,6 @@ export const exportToSvg = async (
|
|||||||
}) rotate(${frame.angle} ${cx} ${cy})"
|
}) rotate(${frame.angle} ${cx} ${cy})"
|
||||||
width="${frame.width}"
|
width="${frame.width}"
|
||||||
height="${frame.height}"
|
height="${frame.height}"
|
||||||
${
|
|
||||||
exportingFrame
|
|
||||||
? ""
|
|
||||||
: `rx=${FRAME_STYLE.radius} ry=${FRAME_STYLE.radius}`
|
|
||||||
}
|
|
||||||
>
|
>
|
||||||
</rect>
|
</rect>
|
||||||
</clipPath>`;
|
</clipPath>`;
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import type { AppState, Offsets, PointerCoords, Zoom } from "../types";
|
import type { AppState, PointerCoords, Zoom } from "../types";
|
||||||
import type { ExcalidrawElement } from "../element/types";
|
import type { ExcalidrawElement } from "../element/types";
|
||||||
import {
|
import {
|
||||||
getCommonBounds,
|
getCommonBounds,
|
||||||
@@ -31,28 +31,14 @@ export const centerScrollOn = ({
|
|||||||
scenePoint,
|
scenePoint,
|
||||||
viewportDimensions,
|
viewportDimensions,
|
||||||
zoom,
|
zoom,
|
||||||
offsets,
|
|
||||||
}: {
|
}: {
|
||||||
scenePoint: PointerCoords;
|
scenePoint: PointerCoords;
|
||||||
viewportDimensions: { height: number; width: number };
|
viewportDimensions: { height: number; width: number };
|
||||||
zoom: Zoom;
|
zoom: Zoom;
|
||||||
offsets?: Offsets;
|
|
||||||
}) => {
|
}) => {
|
||||||
let scrollX =
|
|
||||||
(viewportDimensions.width - (offsets?.right ?? 0)) / 2 / zoom.value -
|
|
||||||
scenePoint.x;
|
|
||||||
|
|
||||||
scrollX += (offsets?.left ?? 0) / 2 / zoom.value;
|
|
||||||
|
|
||||||
let scrollY =
|
|
||||||
(viewportDimensions.height - (offsets?.bottom ?? 0)) / 2 / zoom.value -
|
|
||||||
scenePoint.y;
|
|
||||||
|
|
||||||
scrollY += (offsets?.top ?? 0) / 2 / zoom.value;
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
scrollX,
|
scrollX: viewportDimensions.width / 2 / zoom.value - scenePoint.x,
|
||||||
scrollY,
|
scrollY: viewportDimensions.height / 2 / zoom.value - scenePoint.y,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
@@ -8430,7 +8430,6 @@ exports[`regression tests > key 5 selects arrow tool > [end of test] appState 1`
|
|||||||
"selectedElementsAreBeingDragged": false,
|
"selectedElementsAreBeingDragged": false,
|
||||||
"selectedGroupIds": {},
|
"selectedGroupIds": {},
|
||||||
"selectedLinearElement": LinearElementEditor {
|
"selectedLinearElement": LinearElementEditor {
|
||||||
"elbowed": false,
|
|
||||||
"elementId": "id0",
|
"elementId": "id0",
|
||||||
"endBindingElement": "keep",
|
"endBindingElement": "keep",
|
||||||
"hoverPointIndex": -1,
|
"hoverPointIndex": -1,
|
||||||
@@ -8650,7 +8649,6 @@ exports[`regression tests > key 6 selects line tool > [end of test] appState 1`]
|
|||||||
"selectedElementsAreBeingDragged": false,
|
"selectedElementsAreBeingDragged": false,
|
||||||
"selectedGroupIds": {},
|
"selectedGroupIds": {},
|
||||||
"selectedLinearElement": LinearElementEditor {
|
"selectedLinearElement": LinearElementEditor {
|
||||||
"elbowed": false,
|
|
||||||
"elementId": "id0",
|
"elementId": "id0",
|
||||||
"endBindingElement": "keep",
|
"endBindingElement": "keep",
|
||||||
"hoverPointIndex": -1,
|
"hoverPointIndex": -1,
|
||||||
@@ -9060,7 +9058,6 @@ exports[`regression tests > key a selects arrow tool > [end of test] appState 1`
|
|||||||
"selectedElementsAreBeingDragged": false,
|
"selectedElementsAreBeingDragged": false,
|
||||||
"selectedGroupIds": {},
|
"selectedGroupIds": {},
|
||||||
"selectedLinearElement": LinearElementEditor {
|
"selectedLinearElement": LinearElementEditor {
|
||||||
"elbowed": false,
|
|
||||||
"elementId": "id0",
|
"elementId": "id0",
|
||||||
"endBindingElement": "keep",
|
"endBindingElement": "keep",
|
||||||
"hoverPointIndex": -1,
|
"hoverPointIndex": -1,
|
||||||
@@ -9457,7 +9454,6 @@ exports[`regression tests > key l selects line tool > [end of test] appState 1`]
|
|||||||
"selectedElementsAreBeingDragged": false,
|
"selectedElementsAreBeingDragged": false,
|
||||||
"selectedGroupIds": {},
|
"selectedGroupIds": {},
|
||||||
"selectedLinearElement": LinearElementEditor {
|
"selectedLinearElement": LinearElementEditor {
|
||||||
"elbowed": false,
|
|
||||||
"elementId": "id0",
|
"elementId": "id0",
|
||||||
"endBindingElement": "keep",
|
"endBindingElement": "keep",
|
||||||
"hoverPointIndex": -1,
|
"hoverPointIndex": -1,
|
||||||
|
|||||||
@@ -9,8 +9,6 @@ import type {
|
|||||||
ExcalidrawFrameElement,
|
ExcalidrawFrameElement,
|
||||||
ExcalidrawElementType,
|
ExcalidrawElementType,
|
||||||
ExcalidrawMagicFrameElement,
|
ExcalidrawMagicFrameElement,
|
||||||
ExcalidrawElbowArrowElement,
|
|
||||||
ExcalidrawArrowElement,
|
|
||||||
} from "../../element/types";
|
} from "../../element/types";
|
||||||
import { newElement, newTextElement, newLinearElement } from "../../element";
|
import { newElement, newTextElement, newLinearElement } from "../../element";
|
||||||
import { DEFAULT_VERTICAL_ALIGN, ROUNDNESS } from "../../constants";
|
import { DEFAULT_VERTICAL_ALIGN, ROUNDNESS } from "../../constants";
|
||||||
@@ -129,10 +127,6 @@ export class API {
|
|||||||
expect(API.getSelectedElements().length).toBe(0);
|
expect(API.getSelectedElements().length).toBe(0);
|
||||||
};
|
};
|
||||||
|
|
||||||
static getElement = <T extends ExcalidrawElement>(element: T): T => {
|
|
||||||
return h.app.scene.getElementsMapIncludingDeleted().get(element.id) as T || element;
|
|
||||||
}
|
|
||||||
|
|
||||||
static createElement = <
|
static createElement = <
|
||||||
T extends Exclude<ExcalidrawElementType, "selection"> = "rectangle",
|
T extends Exclude<ExcalidrawElementType, "selection"> = "rectangle",
|
||||||
>({
|
>({
|
||||||
@@ -185,16 +179,10 @@ export class API {
|
|||||||
scale?: T extends "image" ? ExcalidrawImageElement["scale"] : never;
|
scale?: T extends "image" ? ExcalidrawImageElement["scale"] : never;
|
||||||
status?: T extends "image" ? ExcalidrawImageElement["status"] : never;
|
status?: T extends "image" ? ExcalidrawImageElement["status"] : never;
|
||||||
startBinding?: T extends "arrow"
|
startBinding?: T extends "arrow"
|
||||||
? ExcalidrawArrowElement["startBinding"] | ExcalidrawElbowArrowElement["startBinding"]
|
? ExcalidrawLinearElement["startBinding"]
|
||||||
: never;
|
: never;
|
||||||
endBinding?: T extends "arrow"
|
endBinding?: T extends "arrow"
|
||||||
? ExcalidrawArrowElement["endBinding"] | ExcalidrawElbowArrowElement["endBinding"]
|
? ExcalidrawLinearElement["endBinding"]
|
||||||
: never;
|
|
||||||
startArrowhead?: T extends "arrow"
|
|
||||||
? ExcalidrawArrowElement["startArrowhead"] | ExcalidrawElbowArrowElement["startArrowhead"]
|
|
||||||
: never;
|
|
||||||
endArrowhead?: T extends "arrow"
|
|
||||||
? ExcalidrawArrowElement["endArrowhead"] | ExcalidrawElbowArrowElement["endArrowhead"]
|
|
||||||
: never;
|
: never;
|
||||||
elbowed?: boolean;
|
elbowed?: boolean;
|
||||||
}): T extends "arrow" | "line"
|
}): T extends "arrow" | "line"
|
||||||
@@ -352,8 +340,6 @@ export class API {
|
|||||||
if (element.type === "arrow") {
|
if (element.type === "arrow") {
|
||||||
element.startBinding = rest.startBinding ?? null;
|
element.startBinding = rest.startBinding ?? null;
|
||||||
element.endBinding = rest.endBinding ?? null;
|
element.endBinding = rest.endBinding ?? null;
|
||||||
element.startArrowhead = rest.startArrowhead ?? null;
|
|
||||||
element.endArrowhead = rest.endArrowhead ?? null;
|
|
||||||
}
|
}
|
||||||
if (id) {
|
if (id) {
|
||||||
element.id = id;
|
element.id = id;
|
||||||
|
|||||||
@@ -31,7 +31,6 @@ import type {
|
|||||||
ExcalidrawGenericElement,
|
ExcalidrawGenericElement,
|
||||||
ExcalidrawLinearElement,
|
ExcalidrawLinearElement,
|
||||||
ExcalidrawTextElement,
|
ExcalidrawTextElement,
|
||||||
FixedPointBinding,
|
|
||||||
FractionalIndex,
|
FractionalIndex,
|
||||||
SceneElementsMap,
|
SceneElementsMap,
|
||||||
} from "../element/types";
|
} from "../element/types";
|
||||||
@@ -2050,13 +2049,13 @@ describe("history", () => {
|
|||||||
focus: -0.001587301587301948,
|
focus: -0.001587301587301948,
|
||||||
gap: 5,
|
gap: 5,
|
||||||
fixedPoint: [1.0318471337579618, 0.49920634920634904],
|
fixedPoint: [1.0318471337579618, 0.49920634920634904],
|
||||||
} as FixedPointBinding,
|
},
|
||||||
endBinding: {
|
endBinding: {
|
||||||
elementId: "u2JGnnmoJ0VATV4vCNJE5",
|
elementId: "u2JGnnmoJ0VATV4vCNJE5",
|
||||||
focus: -0.0016129032258049847,
|
focus: -0.0016129032258049847,
|
||||||
gap: 3.537079145500037,
|
gap: 3.537079145500037,
|
||||||
fixedPoint: [0.4991935483870975, -0.03875193720914723],
|
fixedPoint: [0.4991935483870975, -0.03875193720914723],
|
||||||
} as FixedPointBinding,
|
},
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
storeAction: StoreAction.CAPTURE,
|
storeAction: StoreAction.CAPTURE,
|
||||||
@@ -4456,7 +4455,7 @@ describe("history", () => {
|
|||||||
elements: [
|
elements: [
|
||||||
h.elements[0],
|
h.elements[0],
|
||||||
newElementWith(h.elements[1], { boundElements: [] }),
|
newElementWith(h.elements[1], { boundElements: [] }),
|
||||||
newElementWith(h.elements[2] as ExcalidrawElbowArrowElement, {
|
newElementWith(h.elements[2] as ExcalidrawLinearElement, {
|
||||||
endBinding: {
|
endBinding: {
|
||||||
elementId: remoteContainer.id,
|
elementId: remoteContainer.id,
|
||||||
gap: 1,
|
gap: 1,
|
||||||
@@ -4656,7 +4655,7 @@ describe("history", () => {
|
|||||||
// Simulate remote update
|
// Simulate remote update
|
||||||
API.updateScene({
|
API.updateScene({
|
||||||
elements: [
|
elements: [
|
||||||
newElementWith(h.elements[0] as ExcalidrawElbowArrowElement, {
|
newElementWith(h.elements[0] as ExcalidrawLinearElement, {
|
||||||
startBinding: {
|
startBinding: {
|
||||||
elementId: rect1.id,
|
elementId: rect1.id,
|
||||||
gap: 1,
|
gap: 1,
|
||||||
|
|||||||
@@ -4,7 +4,6 @@ import { render } from "./test-utils";
|
|||||||
import { reseed } from "../random";
|
import { reseed } from "../random";
|
||||||
import { UI, Keyboard, Pointer } from "./helpers/ui";
|
import { UI, Keyboard, Pointer } from "./helpers/ui";
|
||||||
import type {
|
import type {
|
||||||
ExcalidrawElbowArrowElement,
|
|
||||||
ExcalidrawFreeDrawElement,
|
ExcalidrawFreeDrawElement,
|
||||||
ExcalidrawLinearElement,
|
ExcalidrawLinearElement,
|
||||||
} from "../element/types";
|
} from "../element/types";
|
||||||
@@ -334,62 +333,6 @@ describe("arrow element", () => {
|
|||||||
expect(label.angle).toBeCloseTo(0);
|
expect(label.angle).toBeCloseTo(0);
|
||||||
expect(label.fontSize).toEqual(20);
|
expect(label.fontSize).toEqual(20);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("flips the fixed point binding on negative resize for single bindable", () => {
|
|
||||||
const rectangle = UI.createElement("rectangle", {
|
|
||||||
x: -100,
|
|
||||||
y: -75,
|
|
||||||
width: 95,
|
|
||||||
height: 100,
|
|
||||||
});
|
|
||||||
UI.clickTool("arrow");
|
|
||||||
UI.clickOnTestId("elbow-arrow");
|
|
||||||
mouse.reset();
|
|
||||||
mouse.moveTo(-5, 0);
|
|
||||||
mouse.click();
|
|
||||||
mouse.moveTo(120, 200);
|
|
||||||
mouse.click();
|
|
||||||
|
|
||||||
const arrow = h.scene.getSelectedElements(
|
|
||||||
h.state,
|
|
||||||
)[0] as ExcalidrawElbowArrowElement;
|
|
||||||
|
|
||||||
expect(arrow.startBinding?.fixedPoint?.[0]).toBeCloseTo(1.05);
|
|
||||||
expect(arrow.startBinding?.fixedPoint?.[1]).toBeCloseTo(0.75);
|
|
||||||
|
|
||||||
UI.resize(rectangle, "se", [-200, -150]);
|
|
||||||
|
|
||||||
expect(arrow.startBinding?.fixedPoint?.[0]).toBeCloseTo(1.05);
|
|
||||||
expect(arrow.startBinding?.fixedPoint?.[1]).toBeCloseTo(0.75);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("flips the fixed point binding on negative resize for group selection", () => {
|
|
||||||
const rectangle = UI.createElement("rectangle", {
|
|
||||||
x: -100,
|
|
||||||
y: -75,
|
|
||||||
width: 95,
|
|
||||||
height: 100,
|
|
||||||
});
|
|
||||||
UI.clickTool("arrow");
|
|
||||||
UI.clickOnTestId("elbow-arrow");
|
|
||||||
mouse.reset();
|
|
||||||
mouse.moveTo(-5, 0);
|
|
||||||
mouse.click();
|
|
||||||
mouse.moveTo(120, 200);
|
|
||||||
mouse.click();
|
|
||||||
|
|
||||||
const arrow = h.scene.getSelectedElements(
|
|
||||||
h.state,
|
|
||||||
)[0] as ExcalidrawElbowArrowElement;
|
|
||||||
|
|
||||||
expect(arrow.startBinding?.fixedPoint?.[0]).toBeCloseTo(1.05);
|
|
||||||
expect(arrow.startBinding?.fixedPoint?.[1]).toBeCloseTo(0.75);
|
|
||||||
|
|
||||||
UI.resize([rectangle, arrow], "nw", [300, 350]);
|
|
||||||
|
|
||||||
expect(arrow.startBinding?.fixedPoint?.[0]).toBeCloseTo(-0.144, 2);
|
|
||||||
expect(arrow.startBinding?.fixedPoint?.[1]).toBeCloseTo(0.25);
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("text element", () => {
|
describe("text element", () => {
|
||||||
@@ -885,6 +828,7 @@ describe("multiple selection", () => {
|
|||||||
expect(leftBoundArrow.endBinding?.elementId).toBe(
|
expect(leftBoundArrow.endBinding?.elementId).toBe(
|
||||||
leftArrowBinding.elementId,
|
leftArrowBinding.elementId,
|
||||||
);
|
);
|
||||||
|
expect(leftBoundArrow.endBinding?.fixedPoint).toBeNull();
|
||||||
expect(leftBoundArrow.endBinding?.focus).toBe(leftArrowBinding.focus);
|
expect(leftBoundArrow.endBinding?.focus).toBe(leftArrowBinding.focus);
|
||||||
|
|
||||||
expect(rightBoundArrow.x).toBeCloseTo(210);
|
expect(rightBoundArrow.x).toBeCloseTo(210);
|
||||||
@@ -899,6 +843,7 @@ describe("multiple selection", () => {
|
|||||||
expect(rightBoundArrow.endBinding?.elementId).toBe(
|
expect(rightBoundArrow.endBinding?.elementId).toBe(
|
||||||
rightArrowBinding.elementId,
|
rightArrowBinding.elementId,
|
||||||
);
|
);
|
||||||
|
expect(rightBoundArrow.endBinding?.fixedPoint).toBeNull();
|
||||||
expect(rightBoundArrow.endBinding?.focus).toBe(rightArrowBinding.focus);
|
expect(rightBoundArrow.endBinding?.focus).toBe(rightArrowBinding.focus);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
import { act, render, waitFor } from "./test-utils";
|
import { act, render, waitFor } from "./test-utils";
|
||||||
import { Excalidraw } from "../index";
|
import { Excalidraw } from "../index";
|
||||||
import { CANVAS_SEARCH_TAB, CLASSES, DEFAULT_SIDEBAR } from "../constants";
|
import { CLASSES, SEARCH_SIDEBAR } from "../constants";
|
||||||
import { Keyboard } from "./helpers/ui";
|
import { Keyboard } from "./helpers/ui";
|
||||||
import { KEYS } from "../keys";
|
import { KEYS } from "../keys";
|
||||||
import { updateTextEditor } from "./queries/dom";
|
import { updateTextEditor } from "./queries/dom";
|
||||||
@@ -34,8 +34,7 @@ describe("search", () => {
|
|||||||
Keyboard.keyPress(KEYS.F);
|
Keyboard.keyPress(KEYS.F);
|
||||||
});
|
});
|
||||||
expect(h.app.state.openSidebar).not.toBeNull();
|
expect(h.app.state.openSidebar).not.toBeNull();
|
||||||
expect(h.app.state.openSidebar?.name).toBe(DEFAULT_SIDEBAR.name);
|
expect(h.app.state.openSidebar?.name).toBe(SEARCH_SIDEBAR.name);
|
||||||
expect(h.app.state.openSidebar?.tab).toBe(CANVAS_SEARCH_TAB);
|
|
||||||
|
|
||||||
const searchInput = await querySearchInput();
|
const searchInput = await querySearchInput();
|
||||||
expect(searchInput.matches(":focus")).toBe(true);
|
expect(searchInput.matches(":focus")).toBe(true);
|
||||||
@@ -79,8 +78,7 @@ describe("search", () => {
|
|||||||
Keyboard.keyPress(KEYS.F);
|
Keyboard.keyPress(KEYS.F);
|
||||||
});
|
});
|
||||||
expect(h.app.state.openSidebar).not.toBeNull();
|
expect(h.app.state.openSidebar).not.toBeNull();
|
||||||
expect(h.app.state.openSidebar?.name).toBe(DEFAULT_SIDEBAR.name);
|
expect(h.app.state.openSidebar?.name).toBe(SEARCH_SIDEBAR.name);
|
||||||
expect(h.app.state.openSidebar?.tab).toBe(CANVAS_SEARCH_TAB);
|
|
||||||
|
|
||||||
const searchInput = await querySearchInput();
|
const searchInput = await querySearchInput();
|
||||||
|
|
||||||
@@ -124,8 +122,7 @@ describe("search", () => {
|
|||||||
Keyboard.keyPress(KEYS.F);
|
Keyboard.keyPress(KEYS.F);
|
||||||
});
|
});
|
||||||
expect(h.app.state.openSidebar).not.toBeNull();
|
expect(h.app.state.openSidebar).not.toBeNull();
|
||||||
expect(h.app.state.openSidebar?.name).toBe(DEFAULT_SIDEBAR.name);
|
expect(h.app.state.openSidebar?.name).toBe(SEARCH_SIDEBAR.name);
|
||||||
expect(h.app.state.openSidebar?.tab).toBe(CANVAS_SEARCH_TAB);
|
|
||||||
|
|
||||||
const searchInput = await querySearchInput();
|
const searchInput = await querySearchInput();
|
||||||
|
|
||||||
|
|||||||
@@ -851,10 +851,3 @@ export type GenerateDiagramToCode = (props: {
|
|||||||
frame: ExcalidrawMagicFrameElement;
|
frame: ExcalidrawMagicFrameElement;
|
||||||
children: readonly ExcalidrawElement[];
|
children: readonly ExcalidrawElement[];
|
||||||
}) => MaybePromise<{ html: string }>;
|
}) => MaybePromise<{ html: string }>;
|
||||||
|
|
||||||
export type Offsets = Partial<{
|
|
||||||
top: number;
|
|
||||||
right: number;
|
|
||||||
bottom: number;
|
|
||||||
left: number;
|
|
||||||
}>;
|
|
||||||
|
|||||||
@@ -110,8 +110,8 @@ export const debugDrawBoundingBox = (
|
|||||||
export const debugDrawBounds = (
|
export const debugDrawBounds = (
|
||||||
box: Bounds | Bounds[],
|
box: Bounds | Bounds[],
|
||||||
opts?: {
|
opts?: {
|
||||||
color?: string;
|
color: string;
|
||||||
permanent?: boolean;
|
permanent: boolean;
|
||||||
},
|
},
|
||||||
) => {
|
) => {
|
||||||
(isBounds(box) ? [box] : box).forEach((bbox) =>
|
(isBounds(box) ? [box] : box).forEach((bbox) =>
|
||||||
@@ -136,7 +136,7 @@ export const debugDrawBounds = (
|
|||||||
],
|
],
|
||||||
{
|
{
|
||||||
color: opts?.color ?? "green",
|
color: opts?.color ?? "green",
|
||||||
permanent: !!opts?.permanent,
|
permanent: opts?.permanent,
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|||||||
+5
-18
@@ -1,27 +1,14 @@
|
|||||||
export const PRECISION = 10e-5;
|
export const PRECISION = 10e-5;
|
||||||
|
|
||||||
export const clamp = (value: number, min: number, max: number) => {
|
export function clamp(value: number, min: number, max: number) {
|
||||||
return Math.min(Math.max(value, min), max);
|
return Math.min(Math.max(value, min), max);
|
||||||
};
|
}
|
||||||
|
|
||||||
export const round = (
|
export function round(value: number, precision: number) {
|
||||||
value: number,
|
|
||||||
precision: number,
|
|
||||||
func: "round" | "floor" | "ceil" = "round",
|
|
||||||
) => {
|
|
||||||
const multiplier = Math.pow(10, precision);
|
const multiplier = Math.pow(10, precision);
|
||||||
|
|
||||||
return Math[func]((value + Number.EPSILON) * multiplier) / multiplier;
|
return Math.round((value + Number.EPSILON) * multiplier) / multiplier;
|
||||||
};
|
}
|
||||||
|
|
||||||
export const roundToStep = (
|
|
||||||
value: number,
|
|
||||||
step: number,
|
|
||||||
func: "round" | "floor" | "ceil" = "round",
|
|
||||||
): number => {
|
|
||||||
const factor = 1 / step;
|
|
||||||
return Math[func](value * factor) / factor;
|
|
||||||
};
|
|
||||||
|
|
||||||
export const average = (a: number, b: number) => (a + b) / 2;
|
export const average = (a: number, b: number) => (a + b) / 2;
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -8,7 +8,7 @@ export default defineConfig({
|
|||||||
// Since hooks are running in stack in v2, which means all hooks run serially whereas
|
// Since hooks are running in stack in v2, which means all hooks run serially whereas
|
||||||
// we need to run them in parallel
|
// we need to run them in parallel
|
||||||
sequence: {
|
sequence: {
|
||||||
hooks: "parallel",
|
hooks: 'parallel',
|
||||||
},
|
},
|
||||||
setupFiles: ["./setupTests.ts"],
|
setupFiles: ["./setupTests.ts"],
|
||||||
globals: true,
|
globals: true,
|
||||||
|
|||||||
@@ -1519,6 +1519,11 @@
|
|||||||
resolved "https://registry.yarnpkg.com/@esbuild/aix-ppc64/-/aix-ppc64-0.20.2.tgz#a70f4ac11c6a1dfc18b8bbb13284155d933b9537"
|
resolved "https://registry.yarnpkg.com/@esbuild/aix-ppc64/-/aix-ppc64-0.20.2.tgz#a70f4ac11c6a1dfc18b8bbb13284155d933b9537"
|
||||||
integrity sha512-D+EBOJHXdNZcLJRBkhENNG8Wji2kgc9AZ9KiPr1JuZjsNtyHzrsfLRrY0tk2H2aoFu6RANO1y1iPPUCDYWkb5g==
|
integrity sha512-D+EBOJHXdNZcLJRBkhENNG8Wji2kgc9AZ9KiPr1JuZjsNtyHzrsfLRrY0tk2H2aoFu6RANO1y1iPPUCDYWkb5g==
|
||||||
|
|
||||||
|
"@esbuild/aix-ppc64@0.21.5":
|
||||||
|
version "0.21.5"
|
||||||
|
resolved "https://registry.yarnpkg.com/@esbuild/aix-ppc64/-/aix-ppc64-0.21.5.tgz#c7184a326533fcdf1b8ee0733e21c713b975575f"
|
||||||
|
integrity sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==
|
||||||
|
|
||||||
"@esbuild/android-arm64@0.19.10":
|
"@esbuild/android-arm64@0.19.10":
|
||||||
version "0.19.10"
|
version "0.19.10"
|
||||||
resolved "https://registry.yarnpkg.com/@esbuild/android-arm64/-/android-arm64-0.19.10.tgz#ef31015416dd79398082409b77aaaa2ade4d531a"
|
resolved "https://registry.yarnpkg.com/@esbuild/android-arm64/-/android-arm64-0.19.10.tgz#ef31015416dd79398082409b77aaaa2ade4d531a"
|
||||||
@@ -1534,6 +1539,11 @@
|
|||||||
resolved "https://registry.yarnpkg.com/@esbuild/android-arm64/-/android-arm64-0.20.2.tgz#db1c9202a5bc92ea04c7b6840f1bbe09ebf9e6b9"
|
resolved "https://registry.yarnpkg.com/@esbuild/android-arm64/-/android-arm64-0.20.2.tgz#db1c9202a5bc92ea04c7b6840f1bbe09ebf9e6b9"
|
||||||
integrity sha512-mRzjLacRtl/tWU0SvD8lUEwb61yP9cqQo6noDZP/O8VkwafSYwZ4yWy24kan8jE/IMERpYncRt2dw438LP3Xmg==
|
integrity sha512-mRzjLacRtl/tWU0SvD8lUEwb61yP9cqQo6noDZP/O8VkwafSYwZ4yWy24kan8jE/IMERpYncRt2dw438LP3Xmg==
|
||||||
|
|
||||||
|
"@esbuild/android-arm64@0.21.5":
|
||||||
|
version "0.21.5"
|
||||||
|
resolved "https://registry.yarnpkg.com/@esbuild/android-arm64/-/android-arm64-0.21.5.tgz#09d9b4357780da9ea3a7dfb833a1f1ff439b4052"
|
||||||
|
integrity sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A==
|
||||||
|
|
||||||
"@esbuild/android-arm@0.19.10":
|
"@esbuild/android-arm@0.19.10":
|
||||||
version "0.19.10"
|
version "0.19.10"
|
||||||
resolved "https://registry.yarnpkg.com/@esbuild/android-arm/-/android-arm-0.19.10.tgz#1c23c7e75473aae9fb323be5d9db225142f47f52"
|
resolved "https://registry.yarnpkg.com/@esbuild/android-arm/-/android-arm-0.19.10.tgz#1c23c7e75473aae9fb323be5d9db225142f47f52"
|
||||||
@@ -1549,6 +1559,11 @@
|
|||||||
resolved "https://registry.yarnpkg.com/@esbuild/android-arm/-/android-arm-0.20.2.tgz#3b488c49aee9d491c2c8f98a909b785870d6e995"
|
resolved "https://registry.yarnpkg.com/@esbuild/android-arm/-/android-arm-0.20.2.tgz#3b488c49aee9d491c2c8f98a909b785870d6e995"
|
||||||
integrity sha512-t98Ra6pw2VaDhqNWO2Oph2LXbz/EJcnLmKLGBJwEwXX/JAN83Fym1rU8l0JUWK6HkIbWONCSSatf4sf2NBRx/w==
|
integrity sha512-t98Ra6pw2VaDhqNWO2Oph2LXbz/EJcnLmKLGBJwEwXX/JAN83Fym1rU8l0JUWK6HkIbWONCSSatf4sf2NBRx/w==
|
||||||
|
|
||||||
|
"@esbuild/android-arm@0.21.5":
|
||||||
|
version "0.21.5"
|
||||||
|
resolved "https://registry.yarnpkg.com/@esbuild/android-arm/-/android-arm-0.21.5.tgz#9b04384fb771926dfa6d7ad04324ecb2ab9b2e28"
|
||||||
|
integrity sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg==
|
||||||
|
|
||||||
"@esbuild/android-x64@0.19.10":
|
"@esbuild/android-x64@0.19.10":
|
||||||
version "0.19.10"
|
version "0.19.10"
|
||||||
resolved "https://registry.yarnpkg.com/@esbuild/android-x64/-/android-x64-0.19.10.tgz#df6a4e6d6eb8da5595cfce16d4e3f6bc24464707"
|
resolved "https://registry.yarnpkg.com/@esbuild/android-x64/-/android-x64-0.19.10.tgz#df6a4e6d6eb8da5595cfce16d4e3f6bc24464707"
|
||||||
@@ -1564,6 +1579,11 @@
|
|||||||
resolved "https://registry.yarnpkg.com/@esbuild/android-x64/-/android-x64-0.20.2.tgz#3b1628029e5576249d2b2d766696e50768449f98"
|
resolved "https://registry.yarnpkg.com/@esbuild/android-x64/-/android-x64-0.20.2.tgz#3b1628029e5576249d2b2d766696e50768449f98"
|
||||||
integrity sha512-btzExgV+/lMGDDa194CcUQm53ncxzeBrWJcncOBxuC6ndBkKxnHdFJn86mCIgTELsooUmwUm9FkhSp5HYu00Rg==
|
integrity sha512-btzExgV+/lMGDDa194CcUQm53ncxzeBrWJcncOBxuC6ndBkKxnHdFJn86mCIgTELsooUmwUm9FkhSp5HYu00Rg==
|
||||||
|
|
||||||
|
"@esbuild/android-x64@0.21.5":
|
||||||
|
version "0.21.5"
|
||||||
|
resolved "https://registry.yarnpkg.com/@esbuild/android-x64/-/android-x64-0.21.5.tgz#29918ec2db754cedcb6c1b04de8cd6547af6461e"
|
||||||
|
integrity sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA==
|
||||||
|
|
||||||
"@esbuild/darwin-arm64@0.19.10":
|
"@esbuild/darwin-arm64@0.19.10":
|
||||||
version "0.19.10"
|
version "0.19.10"
|
||||||
resolved "https://registry.yarnpkg.com/@esbuild/darwin-arm64/-/darwin-arm64-0.19.10.tgz#8462a55db07c1b2fad61c8244ce04469ef1043be"
|
resolved "https://registry.yarnpkg.com/@esbuild/darwin-arm64/-/darwin-arm64-0.19.10.tgz#8462a55db07c1b2fad61c8244ce04469ef1043be"
|
||||||
@@ -1579,6 +1599,11 @@
|
|||||||
resolved "https://registry.yarnpkg.com/@esbuild/darwin-arm64/-/darwin-arm64-0.20.2.tgz#6e8517a045ddd86ae30c6608c8475ebc0c4000bb"
|
resolved "https://registry.yarnpkg.com/@esbuild/darwin-arm64/-/darwin-arm64-0.20.2.tgz#6e8517a045ddd86ae30c6608c8475ebc0c4000bb"
|
||||||
integrity sha512-4J6IRT+10J3aJH3l1yzEg9y3wkTDgDk7TSDFX+wKFiWjqWp/iCfLIYzGyasx9l0SAFPT1HwSCR+0w/h1ES/MjA==
|
integrity sha512-4J6IRT+10J3aJH3l1yzEg9y3wkTDgDk7TSDFX+wKFiWjqWp/iCfLIYzGyasx9l0SAFPT1HwSCR+0w/h1ES/MjA==
|
||||||
|
|
||||||
|
"@esbuild/darwin-arm64@0.21.5":
|
||||||
|
version "0.21.5"
|
||||||
|
resolved "https://registry.yarnpkg.com/@esbuild/darwin-arm64/-/darwin-arm64-0.21.5.tgz#e495b539660e51690f3928af50a76fb0a6ccff2a"
|
||||||
|
integrity sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ==
|
||||||
|
|
||||||
"@esbuild/darwin-x64@0.19.10":
|
"@esbuild/darwin-x64@0.19.10":
|
||||||
version "0.19.10"
|
version "0.19.10"
|
||||||
resolved "https://registry.yarnpkg.com/@esbuild/darwin-x64/-/darwin-x64-0.19.10.tgz#d1de20bfd41bb75b955ba86a6b1004539e8218c1"
|
resolved "https://registry.yarnpkg.com/@esbuild/darwin-x64/-/darwin-x64-0.19.10.tgz#d1de20bfd41bb75b955ba86a6b1004539e8218c1"
|
||||||
@@ -1594,6 +1619,11 @@
|
|||||||
resolved "https://registry.yarnpkg.com/@esbuild/darwin-x64/-/darwin-x64-0.20.2.tgz#90ed098e1f9dd8a9381695b207e1cff45540a0d0"
|
resolved "https://registry.yarnpkg.com/@esbuild/darwin-x64/-/darwin-x64-0.20.2.tgz#90ed098e1f9dd8a9381695b207e1cff45540a0d0"
|
||||||
integrity sha512-tBcXp9KNphnNH0dfhv8KYkZhjc+H3XBkF5DKtswJblV7KlT9EI2+jeA8DgBjp908WEuYll6pF+UStUCfEpdysA==
|
integrity sha512-tBcXp9KNphnNH0dfhv8KYkZhjc+H3XBkF5DKtswJblV7KlT9EI2+jeA8DgBjp908WEuYll6pF+UStUCfEpdysA==
|
||||||
|
|
||||||
|
"@esbuild/darwin-x64@0.21.5":
|
||||||
|
version "0.21.5"
|
||||||
|
resolved "https://registry.yarnpkg.com/@esbuild/darwin-x64/-/darwin-x64-0.21.5.tgz#c13838fa57372839abdddc91d71542ceea2e1e22"
|
||||||
|
integrity sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw==
|
||||||
|
|
||||||
"@esbuild/freebsd-arm64@0.19.10":
|
"@esbuild/freebsd-arm64@0.19.10":
|
||||||
version "0.19.10"
|
version "0.19.10"
|
||||||
resolved "https://registry.yarnpkg.com/@esbuild/freebsd-arm64/-/freebsd-arm64-0.19.10.tgz#16904879e34c53a2e039d1284695d2db3e664d57"
|
resolved "https://registry.yarnpkg.com/@esbuild/freebsd-arm64/-/freebsd-arm64-0.19.10.tgz#16904879e34c53a2e039d1284695d2db3e664d57"
|
||||||
@@ -1609,6 +1639,11 @@
|
|||||||
resolved "https://registry.yarnpkg.com/@esbuild/freebsd-arm64/-/freebsd-arm64-0.20.2.tgz#d71502d1ee89a1130327e890364666c760a2a911"
|
resolved "https://registry.yarnpkg.com/@esbuild/freebsd-arm64/-/freebsd-arm64-0.20.2.tgz#d71502d1ee89a1130327e890364666c760a2a911"
|
||||||
integrity sha512-d3qI41G4SuLiCGCFGUrKsSeTXyWG6yem1KcGZVS+3FYlYhtNoNgYrWcvkOoaqMhwXSMrZRl69ArHsGJ9mYdbbw==
|
integrity sha512-d3qI41G4SuLiCGCFGUrKsSeTXyWG6yem1KcGZVS+3FYlYhtNoNgYrWcvkOoaqMhwXSMrZRl69ArHsGJ9mYdbbw==
|
||||||
|
|
||||||
|
"@esbuild/freebsd-arm64@0.21.5":
|
||||||
|
version "0.21.5"
|
||||||
|
resolved "https://registry.yarnpkg.com/@esbuild/freebsd-arm64/-/freebsd-arm64-0.21.5.tgz#646b989aa20bf89fd071dd5dbfad69a3542e550e"
|
||||||
|
integrity sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g==
|
||||||
|
|
||||||
"@esbuild/freebsd-x64@0.19.10":
|
"@esbuild/freebsd-x64@0.19.10":
|
||||||
version "0.19.10"
|
version "0.19.10"
|
||||||
resolved "https://registry.yarnpkg.com/@esbuild/freebsd-x64/-/freebsd-x64-0.19.10.tgz#8ad9e5ca9786ca3f1ef1411bfd10b08dcd9d4cef"
|
resolved "https://registry.yarnpkg.com/@esbuild/freebsd-x64/-/freebsd-x64-0.19.10.tgz#8ad9e5ca9786ca3f1ef1411bfd10b08dcd9d4cef"
|
||||||
@@ -1624,6 +1659,11 @@
|
|||||||
resolved "https://registry.yarnpkg.com/@esbuild/freebsd-x64/-/freebsd-x64-0.20.2.tgz#aa5ea58d9c1dd9af688b8b6f63ef0d3d60cea53c"
|
resolved "https://registry.yarnpkg.com/@esbuild/freebsd-x64/-/freebsd-x64-0.20.2.tgz#aa5ea58d9c1dd9af688b8b6f63ef0d3d60cea53c"
|
||||||
integrity sha512-d+DipyvHRuqEeM5zDivKV1KuXn9WeRX6vqSqIDgwIfPQtwMP4jaDsQsDncjTDDsExT4lR/91OLjRo8bmC1e+Cw==
|
integrity sha512-d+DipyvHRuqEeM5zDivKV1KuXn9WeRX6vqSqIDgwIfPQtwMP4jaDsQsDncjTDDsExT4lR/91OLjRo8bmC1e+Cw==
|
||||||
|
|
||||||
|
"@esbuild/freebsd-x64@0.21.5":
|
||||||
|
version "0.21.5"
|
||||||
|
resolved "https://registry.yarnpkg.com/@esbuild/freebsd-x64/-/freebsd-x64-0.21.5.tgz#aa615cfc80af954d3458906e38ca22c18cf5c261"
|
||||||
|
integrity sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ==
|
||||||
|
|
||||||
"@esbuild/linux-arm64@0.19.10":
|
"@esbuild/linux-arm64@0.19.10":
|
||||||
version "0.19.10"
|
version "0.19.10"
|
||||||
resolved "https://registry.yarnpkg.com/@esbuild/linux-arm64/-/linux-arm64-0.19.10.tgz#d82cf2c590faece82d28bbf1cfbe36f22ae25bd2"
|
resolved "https://registry.yarnpkg.com/@esbuild/linux-arm64/-/linux-arm64-0.19.10.tgz#d82cf2c590faece82d28bbf1cfbe36f22ae25bd2"
|
||||||
@@ -1639,6 +1679,11 @@
|
|||||||
resolved "https://registry.yarnpkg.com/@esbuild/linux-arm64/-/linux-arm64-0.20.2.tgz#055b63725df678379b0f6db9d0fa85463755b2e5"
|
resolved "https://registry.yarnpkg.com/@esbuild/linux-arm64/-/linux-arm64-0.20.2.tgz#055b63725df678379b0f6db9d0fa85463755b2e5"
|
||||||
integrity sha512-9pb6rBjGvTFNira2FLIWqDk/uaf42sSyLE8j1rnUpuzsODBq7FvpwHYZxQ/It/8b+QOS1RYfqgGFNLRI+qlq2A==
|
integrity sha512-9pb6rBjGvTFNira2FLIWqDk/uaf42sSyLE8j1rnUpuzsODBq7FvpwHYZxQ/It/8b+QOS1RYfqgGFNLRI+qlq2A==
|
||||||
|
|
||||||
|
"@esbuild/linux-arm64@0.21.5":
|
||||||
|
version "0.21.5"
|
||||||
|
resolved "https://registry.yarnpkg.com/@esbuild/linux-arm64/-/linux-arm64-0.21.5.tgz#70ac6fa14f5cb7e1f7f887bcffb680ad09922b5b"
|
||||||
|
integrity sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q==
|
||||||
|
|
||||||
"@esbuild/linux-arm@0.19.10":
|
"@esbuild/linux-arm@0.19.10":
|
||||||
version "0.19.10"
|
version "0.19.10"
|
||||||
resolved "https://registry.yarnpkg.com/@esbuild/linux-arm/-/linux-arm-0.19.10.tgz#477b8e7c7bcd34369717b04dd9ee6972c84f4029"
|
resolved "https://registry.yarnpkg.com/@esbuild/linux-arm/-/linux-arm-0.19.10.tgz#477b8e7c7bcd34369717b04dd9ee6972c84f4029"
|
||||||
@@ -1654,6 +1699,11 @@
|
|||||||
resolved "https://registry.yarnpkg.com/@esbuild/linux-arm/-/linux-arm-0.20.2.tgz#76b3b98cb1f87936fbc37f073efabad49dcd889c"
|
resolved "https://registry.yarnpkg.com/@esbuild/linux-arm/-/linux-arm-0.20.2.tgz#76b3b98cb1f87936fbc37f073efabad49dcd889c"
|
||||||
integrity sha512-VhLPeR8HTMPccbuWWcEUD1Az68TqaTYyj6nfE4QByZIQEQVWBB8vup8PpR7y1QHL3CpcF6xd5WVBU/+SBEvGTg==
|
integrity sha512-VhLPeR8HTMPccbuWWcEUD1Az68TqaTYyj6nfE4QByZIQEQVWBB8vup8PpR7y1QHL3CpcF6xd5WVBU/+SBEvGTg==
|
||||||
|
|
||||||
|
"@esbuild/linux-arm@0.21.5":
|
||||||
|
version "0.21.5"
|
||||||
|
resolved "https://registry.yarnpkg.com/@esbuild/linux-arm/-/linux-arm-0.21.5.tgz#fc6fd11a8aca56c1f6f3894f2bea0479f8f626b9"
|
||||||
|
integrity sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA==
|
||||||
|
|
||||||
"@esbuild/linux-ia32@0.19.10":
|
"@esbuild/linux-ia32@0.19.10":
|
||||||
version "0.19.10"
|
version "0.19.10"
|
||||||
resolved "https://registry.yarnpkg.com/@esbuild/linux-ia32/-/linux-ia32-0.19.10.tgz#d55ff822cf5b0252a57112f86857ff23be6cab0e"
|
resolved "https://registry.yarnpkg.com/@esbuild/linux-ia32/-/linux-ia32-0.19.10.tgz#d55ff822cf5b0252a57112f86857ff23be6cab0e"
|
||||||
@@ -1669,6 +1719,11 @@
|
|||||||
resolved "https://registry.yarnpkg.com/@esbuild/linux-ia32/-/linux-ia32-0.20.2.tgz#c0e5e787c285264e5dfc7a79f04b8b4eefdad7fa"
|
resolved "https://registry.yarnpkg.com/@esbuild/linux-ia32/-/linux-ia32-0.20.2.tgz#c0e5e787c285264e5dfc7a79f04b8b4eefdad7fa"
|
||||||
integrity sha512-o10utieEkNPFDZFQm9CoP7Tvb33UutoJqg3qKf1PWVeeJhJw0Q347PxMvBgVVFgouYLGIhFYG0UGdBumROyiig==
|
integrity sha512-o10utieEkNPFDZFQm9CoP7Tvb33UutoJqg3qKf1PWVeeJhJw0Q347PxMvBgVVFgouYLGIhFYG0UGdBumROyiig==
|
||||||
|
|
||||||
|
"@esbuild/linux-ia32@0.21.5":
|
||||||
|
version "0.21.5"
|
||||||
|
resolved "https://registry.yarnpkg.com/@esbuild/linux-ia32/-/linux-ia32-0.21.5.tgz#3271f53b3f93e3d093d518d1649d6d68d346ede2"
|
||||||
|
integrity sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg==
|
||||||
|
|
||||||
"@esbuild/linux-loong64@0.19.10":
|
"@esbuild/linux-loong64@0.19.10":
|
||||||
version "0.19.10"
|
version "0.19.10"
|
||||||
resolved "https://registry.yarnpkg.com/@esbuild/linux-loong64/-/linux-loong64-0.19.10.tgz#a9ad057d7e48d6c9f62ff50f6f208e331c4543c7"
|
resolved "https://registry.yarnpkg.com/@esbuild/linux-loong64/-/linux-loong64-0.19.10.tgz#a9ad057d7e48d6c9f62ff50f6f208e331c4543c7"
|
||||||
@@ -1684,6 +1739,11 @@
|
|||||||
resolved "https://registry.yarnpkg.com/@esbuild/linux-loong64/-/linux-loong64-0.20.2.tgz#a6184e62bd7cdc63e0c0448b83801001653219c5"
|
resolved "https://registry.yarnpkg.com/@esbuild/linux-loong64/-/linux-loong64-0.20.2.tgz#a6184e62bd7cdc63e0c0448b83801001653219c5"
|
||||||
integrity sha512-PR7sp6R/UC4CFVomVINKJ80pMFlfDfMQMYynX7t1tNTeivQ6XdX5r2XovMmha/VjR1YN/HgHWsVcTRIMkymrgQ==
|
integrity sha512-PR7sp6R/UC4CFVomVINKJ80pMFlfDfMQMYynX7t1tNTeivQ6XdX5r2XovMmha/VjR1YN/HgHWsVcTRIMkymrgQ==
|
||||||
|
|
||||||
|
"@esbuild/linux-loong64@0.21.5":
|
||||||
|
version "0.21.5"
|
||||||
|
resolved "https://registry.yarnpkg.com/@esbuild/linux-loong64/-/linux-loong64-0.21.5.tgz#ed62e04238c57026aea831c5a130b73c0f9f26df"
|
||||||
|
integrity sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg==
|
||||||
|
|
||||||
"@esbuild/linux-mips64el@0.19.10":
|
"@esbuild/linux-mips64el@0.19.10":
|
||||||
version "0.19.10"
|
version "0.19.10"
|
||||||
resolved "https://registry.yarnpkg.com/@esbuild/linux-mips64el/-/linux-mips64el-0.19.10.tgz#b011a96924773d60ebab396fbd7a08de66668179"
|
resolved "https://registry.yarnpkg.com/@esbuild/linux-mips64el/-/linux-mips64el-0.19.10.tgz#b011a96924773d60ebab396fbd7a08de66668179"
|
||||||
@@ -1699,6 +1759,11 @@
|
|||||||
resolved "https://registry.yarnpkg.com/@esbuild/linux-mips64el/-/linux-mips64el-0.20.2.tgz#d08e39ce86f45ef8fc88549d29c62b8acf5649aa"
|
resolved "https://registry.yarnpkg.com/@esbuild/linux-mips64el/-/linux-mips64el-0.20.2.tgz#d08e39ce86f45ef8fc88549d29c62b8acf5649aa"
|
||||||
integrity sha512-4BlTqeutE/KnOiTG5Y6Sb/Hw6hsBOZapOVF6njAESHInhlQAghVVZL1ZpIctBOoTFbQyGW+LsVYZ8lSSB3wkjA==
|
integrity sha512-4BlTqeutE/KnOiTG5Y6Sb/Hw6hsBOZapOVF6njAESHInhlQAghVVZL1ZpIctBOoTFbQyGW+LsVYZ8lSSB3wkjA==
|
||||||
|
|
||||||
|
"@esbuild/linux-mips64el@0.21.5":
|
||||||
|
version "0.21.5"
|
||||||
|
resolved "https://registry.yarnpkg.com/@esbuild/linux-mips64el/-/linux-mips64el-0.21.5.tgz#e79b8eb48bf3b106fadec1ac8240fb97b4e64cbe"
|
||||||
|
integrity sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg==
|
||||||
|
|
||||||
"@esbuild/linux-ppc64@0.19.10":
|
"@esbuild/linux-ppc64@0.19.10":
|
||||||
version "0.19.10"
|
version "0.19.10"
|
||||||
resolved "https://registry.yarnpkg.com/@esbuild/linux-ppc64/-/linux-ppc64-0.19.10.tgz#5d8b59929c029811e473f2544790ea11d588d4dd"
|
resolved "https://registry.yarnpkg.com/@esbuild/linux-ppc64/-/linux-ppc64-0.19.10.tgz#5d8b59929c029811e473f2544790ea11d588d4dd"
|
||||||
@@ -1714,6 +1779,11 @@
|
|||||||
resolved "https://registry.yarnpkg.com/@esbuild/linux-ppc64/-/linux-ppc64-0.20.2.tgz#8d252f0b7756ffd6d1cbde5ea67ff8fd20437f20"
|
resolved "https://registry.yarnpkg.com/@esbuild/linux-ppc64/-/linux-ppc64-0.20.2.tgz#8d252f0b7756ffd6d1cbde5ea67ff8fd20437f20"
|
||||||
integrity sha512-rD3KsaDprDcfajSKdn25ooz5J5/fWBylaaXkuotBDGnMnDP1Uv5DLAN/45qfnf3JDYyJv/ytGHQaziHUdyzaAg==
|
integrity sha512-rD3KsaDprDcfajSKdn25ooz5J5/fWBylaaXkuotBDGnMnDP1Uv5DLAN/45qfnf3JDYyJv/ytGHQaziHUdyzaAg==
|
||||||
|
|
||||||
|
"@esbuild/linux-ppc64@0.21.5":
|
||||||
|
version "0.21.5"
|
||||||
|
resolved "https://registry.yarnpkg.com/@esbuild/linux-ppc64/-/linux-ppc64-0.21.5.tgz#5f2203860a143b9919d383ef7573521fb154c3e4"
|
||||||
|
integrity sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w==
|
||||||
|
|
||||||
"@esbuild/linux-riscv64@0.19.10":
|
"@esbuild/linux-riscv64@0.19.10":
|
||||||
version "0.19.10"
|
version "0.19.10"
|
||||||
resolved "https://registry.yarnpkg.com/@esbuild/linux-riscv64/-/linux-riscv64-0.19.10.tgz#292b06978375b271bd8bc0a554e0822957508d22"
|
resolved "https://registry.yarnpkg.com/@esbuild/linux-riscv64/-/linux-riscv64-0.19.10.tgz#292b06978375b271bd8bc0a554e0822957508d22"
|
||||||
@@ -1729,6 +1799,11 @@
|
|||||||
resolved "https://registry.yarnpkg.com/@esbuild/linux-riscv64/-/linux-riscv64-0.20.2.tgz#19f6dcdb14409dae607f66ca1181dd4e9db81300"
|
resolved "https://registry.yarnpkg.com/@esbuild/linux-riscv64/-/linux-riscv64-0.20.2.tgz#19f6dcdb14409dae607f66ca1181dd4e9db81300"
|
||||||
integrity sha512-snwmBKacKmwTMmhLlz/3aH1Q9T8v45bKYGE3j26TsaOVtjIag4wLfWSiZykXzXuE1kbCE+zJRmwp+ZbIHinnVg==
|
integrity sha512-snwmBKacKmwTMmhLlz/3aH1Q9T8v45bKYGE3j26TsaOVtjIag4wLfWSiZykXzXuE1kbCE+zJRmwp+ZbIHinnVg==
|
||||||
|
|
||||||
|
"@esbuild/linux-riscv64@0.21.5":
|
||||||
|
version "0.21.5"
|
||||||
|
resolved "https://registry.yarnpkg.com/@esbuild/linux-riscv64/-/linux-riscv64-0.21.5.tgz#07bcafd99322d5af62f618cb9e6a9b7f4bb825dc"
|
||||||
|
integrity sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA==
|
||||||
|
|
||||||
"@esbuild/linux-s390x@0.19.10":
|
"@esbuild/linux-s390x@0.19.10":
|
||||||
version "0.19.10"
|
version "0.19.10"
|
||||||
resolved "https://registry.yarnpkg.com/@esbuild/linux-s390x/-/linux-s390x-0.19.10.tgz#d30af63530f8d4fa96930374c9dd0d62bf59e069"
|
resolved "https://registry.yarnpkg.com/@esbuild/linux-s390x/-/linux-s390x-0.19.10.tgz#d30af63530f8d4fa96930374c9dd0d62bf59e069"
|
||||||
@@ -1744,6 +1819,11 @@
|
|||||||
resolved "https://registry.yarnpkg.com/@esbuild/linux-s390x/-/linux-s390x-0.20.2.tgz#3c830c90f1a5d7dd1473d5595ea4ebb920988685"
|
resolved "https://registry.yarnpkg.com/@esbuild/linux-s390x/-/linux-s390x-0.20.2.tgz#3c830c90f1a5d7dd1473d5595ea4ebb920988685"
|
||||||
integrity sha512-wcWISOobRWNm3cezm5HOZcYz1sKoHLd8VL1dl309DiixxVFoFe/o8HnwuIwn6sXre88Nwj+VwZUvJf4AFxkyrQ==
|
integrity sha512-wcWISOobRWNm3cezm5HOZcYz1sKoHLd8VL1dl309DiixxVFoFe/o8HnwuIwn6sXre88Nwj+VwZUvJf4AFxkyrQ==
|
||||||
|
|
||||||
|
"@esbuild/linux-s390x@0.21.5":
|
||||||
|
version "0.21.5"
|
||||||
|
resolved "https://registry.yarnpkg.com/@esbuild/linux-s390x/-/linux-s390x-0.21.5.tgz#b7ccf686751d6a3e44b8627ababc8be3ef62d8de"
|
||||||
|
integrity sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A==
|
||||||
|
|
||||||
"@esbuild/linux-x64@0.19.10":
|
"@esbuild/linux-x64@0.19.10":
|
||||||
version "0.19.10"
|
version "0.19.10"
|
||||||
resolved "https://registry.yarnpkg.com/@esbuild/linux-x64/-/linux-x64-0.19.10.tgz#898c72eeb74d9f2fb43acf316125b475548b75ce"
|
resolved "https://registry.yarnpkg.com/@esbuild/linux-x64/-/linux-x64-0.19.10.tgz#898c72eeb74d9f2fb43acf316125b475548b75ce"
|
||||||
@@ -1759,6 +1839,11 @@
|
|||||||
resolved "https://registry.yarnpkg.com/@esbuild/linux-x64/-/linux-x64-0.20.2.tgz#86eca35203afc0d9de0694c64ec0ab0a378f6fff"
|
resolved "https://registry.yarnpkg.com/@esbuild/linux-x64/-/linux-x64-0.20.2.tgz#86eca35203afc0d9de0694c64ec0ab0a378f6fff"
|
||||||
integrity sha512-1MdwI6OOTsfQfek8sLwgyjOXAu+wKhLEoaOLTjbijk6E2WONYpH9ZU2mNtR+lZ2B4uwr+usqGuVfFT9tMtGvGw==
|
integrity sha512-1MdwI6OOTsfQfek8sLwgyjOXAu+wKhLEoaOLTjbijk6E2WONYpH9ZU2mNtR+lZ2B4uwr+usqGuVfFT9tMtGvGw==
|
||||||
|
|
||||||
|
"@esbuild/linux-x64@0.21.5":
|
||||||
|
version "0.21.5"
|
||||||
|
resolved "https://registry.yarnpkg.com/@esbuild/linux-x64/-/linux-x64-0.21.5.tgz#6d8f0c768e070e64309af8004bb94e68ab2bb3b0"
|
||||||
|
integrity sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ==
|
||||||
|
|
||||||
"@esbuild/netbsd-x64@0.19.10":
|
"@esbuild/netbsd-x64@0.19.10":
|
||||||
version "0.19.10"
|
version "0.19.10"
|
||||||
resolved "https://registry.yarnpkg.com/@esbuild/netbsd-x64/-/netbsd-x64-0.19.10.tgz#fd473a5ae261b43eab6dad4dbd5a3155906e6c91"
|
resolved "https://registry.yarnpkg.com/@esbuild/netbsd-x64/-/netbsd-x64-0.19.10.tgz#fd473a5ae261b43eab6dad4dbd5a3155906e6c91"
|
||||||
@@ -1774,6 +1859,11 @@
|
|||||||
resolved "https://registry.yarnpkg.com/@esbuild/netbsd-x64/-/netbsd-x64-0.20.2.tgz#e771c8eb0e0f6e1877ffd4220036b98aed5915e6"
|
resolved "https://registry.yarnpkg.com/@esbuild/netbsd-x64/-/netbsd-x64-0.20.2.tgz#e771c8eb0e0f6e1877ffd4220036b98aed5915e6"
|
||||||
integrity sha512-K8/DhBxcVQkzYc43yJXDSyjlFeHQJBiowJ0uVL6Tor3jGQfSGHNNJcWxNbOI8v5k82prYqzPuwkzHt3J1T1iZQ==
|
integrity sha512-K8/DhBxcVQkzYc43yJXDSyjlFeHQJBiowJ0uVL6Tor3jGQfSGHNNJcWxNbOI8v5k82prYqzPuwkzHt3J1T1iZQ==
|
||||||
|
|
||||||
|
"@esbuild/netbsd-x64@0.21.5":
|
||||||
|
version "0.21.5"
|
||||||
|
resolved "https://registry.yarnpkg.com/@esbuild/netbsd-x64/-/netbsd-x64-0.21.5.tgz#bbe430f60d378ecb88decb219c602667387a6047"
|
||||||
|
integrity sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg==
|
||||||
|
|
||||||
"@esbuild/openbsd-x64@0.19.10":
|
"@esbuild/openbsd-x64@0.19.10":
|
||||||
version "0.19.10"
|
version "0.19.10"
|
||||||
resolved "https://registry.yarnpkg.com/@esbuild/openbsd-x64/-/openbsd-x64-0.19.10.tgz#96eb8992e526717b5272321eaad3e21f3a608e46"
|
resolved "https://registry.yarnpkg.com/@esbuild/openbsd-x64/-/openbsd-x64-0.19.10.tgz#96eb8992e526717b5272321eaad3e21f3a608e46"
|
||||||
@@ -1789,6 +1879,11 @@
|
|||||||
resolved "https://registry.yarnpkg.com/@esbuild/openbsd-x64/-/openbsd-x64-0.20.2.tgz#9a795ae4b4e37e674f0f4d716f3e226dd7c39baf"
|
resolved "https://registry.yarnpkg.com/@esbuild/openbsd-x64/-/openbsd-x64-0.20.2.tgz#9a795ae4b4e37e674f0f4d716f3e226dd7c39baf"
|
||||||
integrity sha512-eMpKlV0SThJmmJgiVyN9jTPJ2VBPquf6Kt/nAoo6DgHAoN57K15ZghiHaMvqjCye/uU4X5u3YSMgVBI1h3vKrQ==
|
integrity sha512-eMpKlV0SThJmmJgiVyN9jTPJ2VBPquf6Kt/nAoo6DgHAoN57K15ZghiHaMvqjCye/uU4X5u3YSMgVBI1h3vKrQ==
|
||||||
|
|
||||||
|
"@esbuild/openbsd-x64@0.21.5":
|
||||||
|
version "0.21.5"
|
||||||
|
resolved "https://registry.yarnpkg.com/@esbuild/openbsd-x64/-/openbsd-x64-0.21.5.tgz#99d1cf2937279560d2104821f5ccce220cb2af70"
|
||||||
|
integrity sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow==
|
||||||
|
|
||||||
"@esbuild/sunos-x64@0.19.10":
|
"@esbuild/sunos-x64@0.19.10":
|
||||||
version "0.19.10"
|
version "0.19.10"
|
||||||
resolved "https://registry.yarnpkg.com/@esbuild/sunos-x64/-/sunos-x64-0.19.10.tgz#c16ee1c167f903eaaa6acf7372bee42d5a89c9bc"
|
resolved "https://registry.yarnpkg.com/@esbuild/sunos-x64/-/sunos-x64-0.19.10.tgz#c16ee1c167f903eaaa6acf7372bee42d5a89c9bc"
|
||||||
@@ -1804,6 +1899,11 @@
|
|||||||
resolved "https://registry.yarnpkg.com/@esbuild/sunos-x64/-/sunos-x64-0.20.2.tgz#7df23b61a497b8ac189def6e25a95673caedb03f"
|
resolved "https://registry.yarnpkg.com/@esbuild/sunos-x64/-/sunos-x64-0.20.2.tgz#7df23b61a497b8ac189def6e25a95673caedb03f"
|
||||||
integrity sha512-2UyFtRC6cXLyejf/YEld4Hajo7UHILetzE1vsRcGL3earZEW77JxrFjH4Ez2qaTiEfMgAXxfAZCm1fvM/G/o8w==
|
integrity sha512-2UyFtRC6cXLyejf/YEld4Hajo7UHILetzE1vsRcGL3earZEW77JxrFjH4Ez2qaTiEfMgAXxfAZCm1fvM/G/o8w==
|
||||||
|
|
||||||
|
"@esbuild/sunos-x64@0.21.5":
|
||||||
|
version "0.21.5"
|
||||||
|
resolved "https://registry.yarnpkg.com/@esbuild/sunos-x64/-/sunos-x64-0.21.5.tgz#08741512c10d529566baba837b4fe052c8f3487b"
|
||||||
|
integrity sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg==
|
||||||
|
|
||||||
"@esbuild/win32-arm64@0.19.10":
|
"@esbuild/win32-arm64@0.19.10":
|
||||||
version "0.19.10"
|
version "0.19.10"
|
||||||
resolved "https://registry.yarnpkg.com/@esbuild/win32-arm64/-/win32-arm64-0.19.10.tgz#7e417d1971dbc7e469b4eceb6a5d1d667b5e3dcc"
|
resolved "https://registry.yarnpkg.com/@esbuild/win32-arm64/-/win32-arm64-0.19.10.tgz#7e417d1971dbc7e469b4eceb6a5d1d667b5e3dcc"
|
||||||
@@ -1819,6 +1919,11 @@
|
|||||||
resolved "https://registry.yarnpkg.com/@esbuild/win32-arm64/-/win32-arm64-0.20.2.tgz#f1ae5abf9ca052ae11c1bc806fb4c0f519bacf90"
|
resolved "https://registry.yarnpkg.com/@esbuild/win32-arm64/-/win32-arm64-0.20.2.tgz#f1ae5abf9ca052ae11c1bc806fb4c0f519bacf90"
|
||||||
integrity sha512-GRibxoawM9ZCnDxnP3usoUDO9vUkpAxIIZ6GQI+IlVmr5kP3zUq+l17xELTHMWTWzjxa2guPNyrpq1GWmPvcGQ==
|
integrity sha512-GRibxoawM9ZCnDxnP3usoUDO9vUkpAxIIZ6GQI+IlVmr5kP3zUq+l17xELTHMWTWzjxa2guPNyrpq1GWmPvcGQ==
|
||||||
|
|
||||||
|
"@esbuild/win32-arm64@0.21.5":
|
||||||
|
version "0.21.5"
|
||||||
|
resolved "https://registry.yarnpkg.com/@esbuild/win32-arm64/-/win32-arm64-0.21.5.tgz#675b7385398411240735016144ab2e99a60fc75d"
|
||||||
|
integrity sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A==
|
||||||
|
|
||||||
"@esbuild/win32-ia32@0.19.10":
|
"@esbuild/win32-ia32@0.19.10":
|
||||||
version "0.19.10"
|
version "0.19.10"
|
||||||
resolved "https://registry.yarnpkg.com/@esbuild/win32-ia32/-/win32-ia32-0.19.10.tgz#2b52dfec6cd061ecb36171c13bae554888b439e5"
|
resolved "https://registry.yarnpkg.com/@esbuild/win32-ia32/-/win32-ia32-0.19.10.tgz#2b52dfec6cd061ecb36171c13bae554888b439e5"
|
||||||
@@ -1834,6 +1939,11 @@
|
|||||||
resolved "https://registry.yarnpkg.com/@esbuild/win32-ia32/-/win32-ia32-0.20.2.tgz#241fe62c34d8e8461cd708277813e1d0ba55ce23"
|
resolved "https://registry.yarnpkg.com/@esbuild/win32-ia32/-/win32-ia32-0.20.2.tgz#241fe62c34d8e8461cd708277813e1d0ba55ce23"
|
||||||
integrity sha512-HfLOfn9YWmkSKRQqovpnITazdtquEW8/SoHW7pWpuEeguaZI4QnCRW6b+oZTztdBnZOS2hqJ6im/D5cPzBTTlQ==
|
integrity sha512-HfLOfn9YWmkSKRQqovpnITazdtquEW8/SoHW7pWpuEeguaZI4QnCRW6b+oZTztdBnZOS2hqJ6im/D5cPzBTTlQ==
|
||||||
|
|
||||||
|
"@esbuild/win32-ia32@0.21.5":
|
||||||
|
version "0.21.5"
|
||||||
|
resolved "https://registry.yarnpkg.com/@esbuild/win32-ia32/-/win32-ia32-0.21.5.tgz#1bfc3ce98aa6ca9a0969e4d2af72144c59c1193b"
|
||||||
|
integrity sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA==
|
||||||
|
|
||||||
"@esbuild/win32-x64@0.19.10":
|
"@esbuild/win32-x64@0.19.10":
|
||||||
version "0.19.10"
|
version "0.19.10"
|
||||||
resolved "https://registry.yarnpkg.com/@esbuild/win32-x64/-/win32-x64-0.19.10.tgz#bd123a74f243d2f3a1f046447bb9b363ee25d072"
|
resolved "https://registry.yarnpkg.com/@esbuild/win32-x64/-/win32-x64-0.19.10.tgz#bd123a74f243d2f3a1f046447bb9b363ee25d072"
|
||||||
@@ -1849,6 +1959,11 @@
|
|||||||
resolved "https://registry.yarnpkg.com/@esbuild/win32-x64/-/win32-x64-0.20.2.tgz#9c907b21e30a52db959ba4f80bb01a0cc403d5cc"
|
resolved "https://registry.yarnpkg.com/@esbuild/win32-x64/-/win32-x64-0.20.2.tgz#9c907b21e30a52db959ba4f80bb01a0cc403d5cc"
|
||||||
integrity sha512-N49X4lJX27+l9jbLKSqZ6bKNjzQvHaT8IIFUy+YIqmXQdjYCToGWwOItDrfby14c78aDd5NHQl29xingXfCdLQ==
|
integrity sha512-N49X4lJX27+l9jbLKSqZ6bKNjzQvHaT8IIFUy+YIqmXQdjYCToGWwOItDrfby14c78aDd5NHQl29xingXfCdLQ==
|
||||||
|
|
||||||
|
"@esbuild/win32-x64@0.21.5":
|
||||||
|
version "0.21.5"
|
||||||
|
resolved "https://registry.yarnpkg.com/@esbuild/win32-x64/-/win32-x64-0.21.5.tgz#acad351d582d157bb145535db2a6ff53dd514b5c"
|
||||||
|
integrity sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw==
|
||||||
|
|
||||||
"@eslint-community/eslint-utils@^4.2.0":
|
"@eslint-community/eslint-utils@^4.2.0":
|
||||||
version "4.4.0"
|
version "4.4.0"
|
||||||
resolved "https://registry.yarnpkg.com/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz#a23514e8fb9af1269d5f7788aa556798d61c6b59"
|
resolved "https://registry.yarnpkg.com/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz#a23514e8fb9af1269d5f7788aa556798d61c6b59"
|
||||||
@@ -2741,81 +2856,161 @@
|
|||||||
resolved "https://registry.yarnpkg.com/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.18.0.tgz#bbd0e616b2078cd2d68afc9824d1fadb2f2ffd27"
|
resolved "https://registry.yarnpkg.com/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.18.0.tgz#bbd0e616b2078cd2d68afc9824d1fadb2f2ffd27"
|
||||||
integrity sha512-Tya6xypR10giZV1XzxmH5wr25VcZSncG0pZIjfePT0OVBvqNEurzValetGNarVrGiq66EBVAFn15iYX4w6FKgQ==
|
integrity sha512-Tya6xypR10giZV1XzxmH5wr25VcZSncG0pZIjfePT0OVBvqNEurzValetGNarVrGiq66EBVAFn15iYX4w6FKgQ==
|
||||||
|
|
||||||
|
"@rollup/rollup-android-arm-eabi@4.21.2":
|
||||||
|
version "4.21.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.21.2.tgz#0412834dc423d1ff7be4cb1fc13a86a0cd262c11"
|
||||||
|
integrity sha512-fSuPrt0ZO8uXeS+xP3b+yYTCBUd05MoSp2N/MFOgjhhUhMmchXlpTQrTpI8T+YAwAQuK7MafsCOxW7VrPMrJcg==
|
||||||
|
|
||||||
"@rollup/rollup-android-arm64@4.18.0":
|
"@rollup/rollup-android-arm64@4.18.0":
|
||||||
version "4.18.0"
|
version "4.18.0"
|
||||||
resolved "https://registry.yarnpkg.com/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.18.0.tgz#97255ef6384c5f73f4800c0de91f5f6518e21203"
|
resolved "https://registry.yarnpkg.com/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.18.0.tgz#97255ef6384c5f73f4800c0de91f5f6518e21203"
|
||||||
integrity sha512-avCea0RAP03lTsDhEyfy+hpfr85KfyTctMADqHVhLAF3MlIkq83CP8UfAHUssgXTYd+6er6PaAhx/QGv4L1EiA==
|
integrity sha512-avCea0RAP03lTsDhEyfy+hpfr85KfyTctMADqHVhLAF3MlIkq83CP8UfAHUssgXTYd+6er6PaAhx/QGv4L1EiA==
|
||||||
|
|
||||||
|
"@rollup/rollup-android-arm64@4.21.2":
|
||||||
|
version "4.21.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.21.2.tgz#baf1a014b13654f3b9e835388df9caf8c35389cb"
|
||||||
|
integrity sha512-xGU5ZQmPlsjQS6tzTTGwMsnKUtu0WVbl0hYpTPauvbRAnmIvpInhJtgjj3mcuJpEiuUw4v1s4BimkdfDWlh7gA==
|
||||||
|
|
||||||
"@rollup/rollup-darwin-arm64@4.18.0":
|
"@rollup/rollup-darwin-arm64@4.18.0":
|
||||||
version "4.18.0"
|
version "4.18.0"
|
||||||
resolved "https://registry.yarnpkg.com/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.18.0.tgz#b6dd74e117510dfe94541646067b0545b42ff096"
|
resolved "https://registry.yarnpkg.com/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.18.0.tgz#b6dd74e117510dfe94541646067b0545b42ff096"
|
||||||
integrity sha512-IWfdwU7KDSm07Ty0PuA/W2JYoZ4iTj3TUQjkVsO/6U+4I1jN5lcR71ZEvRh52sDOERdnNhhHU57UITXz5jC1/w==
|
integrity sha512-IWfdwU7KDSm07Ty0PuA/W2JYoZ4iTj3TUQjkVsO/6U+4I1jN5lcR71ZEvRh52sDOERdnNhhHU57UITXz5jC1/w==
|
||||||
|
|
||||||
|
"@rollup/rollup-darwin-arm64@4.21.2":
|
||||||
|
version "4.21.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.21.2.tgz#0a2c364e775acdf1172fe3327662eec7c46e55b1"
|
||||||
|
integrity sha512-99AhQ3/ZMxU7jw34Sq8brzXqWH/bMnf7ZVhvLk9QU2cOepbQSVTns6qoErJmSiAvU3InRqC2RRZ5ovh1KN0d0Q==
|
||||||
|
|
||||||
"@rollup/rollup-darwin-x64@4.18.0":
|
"@rollup/rollup-darwin-x64@4.18.0":
|
||||||
version "4.18.0"
|
version "4.18.0"
|
||||||
resolved "https://registry.yarnpkg.com/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.18.0.tgz#e07d76de1cec987673e7f3d48ccb8e106d42c05c"
|
resolved "https://registry.yarnpkg.com/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.18.0.tgz#e07d76de1cec987673e7f3d48ccb8e106d42c05c"
|
||||||
integrity sha512-n2LMsUz7Ynu7DoQrSQkBf8iNrjOGyPLrdSg802vk6XT3FtsgX6JbE8IHRvposskFm9SNxzkLYGSq9QdpLYpRNA==
|
integrity sha512-n2LMsUz7Ynu7DoQrSQkBf8iNrjOGyPLrdSg802vk6XT3FtsgX6JbE8IHRvposskFm9SNxzkLYGSq9QdpLYpRNA==
|
||||||
|
|
||||||
|
"@rollup/rollup-darwin-x64@4.21.2":
|
||||||
|
version "4.21.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.21.2.tgz#a972db75890dfab8df0da228c28993220a468c42"
|
||||||
|
integrity sha512-ZbRaUvw2iN/y37x6dY50D8m2BnDbBjlnMPotDi/qITMJ4sIxNY33HArjikDyakhSv0+ybdUxhWxE6kTI4oX26w==
|
||||||
|
|
||||||
"@rollup/rollup-linux-arm-gnueabihf@4.18.0":
|
"@rollup/rollup-linux-arm-gnueabihf@4.18.0":
|
||||||
version "4.18.0"
|
version "4.18.0"
|
||||||
resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.18.0.tgz#9f1a6d218b560c9d75185af4b8bb42f9f24736b8"
|
resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.18.0.tgz#9f1a6d218b560c9d75185af4b8bb42f9f24736b8"
|
||||||
integrity sha512-C/zbRYRXFjWvz9Z4haRxcTdnkPt1BtCkz+7RtBSuNmKzMzp3ZxdM28Mpccn6pt28/UWUCTXa+b0Mx1k3g6NOMA==
|
integrity sha512-C/zbRYRXFjWvz9Z4haRxcTdnkPt1BtCkz+7RtBSuNmKzMzp3ZxdM28Mpccn6pt28/UWUCTXa+b0Mx1k3g6NOMA==
|
||||||
|
|
||||||
|
"@rollup/rollup-linux-arm-gnueabihf@4.21.2":
|
||||||
|
version "4.21.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.21.2.tgz#1609d0630ef61109dd19a278353e5176d92e30a1"
|
||||||
|
integrity sha512-ztRJJMiE8nnU1YFcdbd9BcH6bGWG1z+jP+IPW2oDUAPxPjo9dverIOyXz76m6IPA6udEL12reYeLojzW2cYL7w==
|
||||||
|
|
||||||
"@rollup/rollup-linux-arm-musleabihf@4.18.0":
|
"@rollup/rollup-linux-arm-musleabihf@4.18.0":
|
||||||
version "4.18.0"
|
version "4.18.0"
|
||||||
resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.18.0.tgz#53618b92e6ffb642c7b620e6e528446511330549"
|
resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.18.0.tgz#53618b92e6ffb642c7b620e6e528446511330549"
|
||||||
integrity sha512-l3m9ewPgjQSXrUMHg93vt0hYCGnrMOcUpTz6FLtbwljo2HluS4zTXFy2571YQbisTnfTKPZ01u/ukJdQTLGh9A==
|
integrity sha512-l3m9ewPgjQSXrUMHg93vt0hYCGnrMOcUpTz6FLtbwljo2HluS4zTXFy2571YQbisTnfTKPZ01u/ukJdQTLGh9A==
|
||||||
|
|
||||||
|
"@rollup/rollup-linux-arm-musleabihf@4.21.2":
|
||||||
|
version "4.21.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.21.2.tgz#3c1dca5f160aa2e79e4b20ff6395eab21804f266"
|
||||||
|
integrity sha512-flOcGHDZajGKYpLV0JNc0VFH361M7rnV1ee+NTeC/BQQ1/0pllYcFmxpagltANYt8FYf9+kL6RSk80Ziwyhr7w==
|
||||||
|
|
||||||
"@rollup/rollup-linux-arm64-gnu@4.18.0":
|
"@rollup/rollup-linux-arm64-gnu@4.18.0":
|
||||||
version "4.18.0"
|
version "4.18.0"
|
||||||
resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.18.0.tgz#99a7ba5e719d4f053761a698f7b52291cefba577"
|
resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.18.0.tgz#99a7ba5e719d4f053761a698f7b52291cefba577"
|
||||||
integrity sha512-rJ5D47d8WD7J+7STKdCUAgmQk49xuFrRi9pZkWoRD1UeSMakbcepWXPF8ycChBoAqs1pb2wzvbY6Q33WmN2ftw==
|
integrity sha512-rJ5D47d8WD7J+7STKdCUAgmQk49xuFrRi9pZkWoRD1UeSMakbcepWXPF8ycChBoAqs1pb2wzvbY6Q33WmN2ftw==
|
||||||
|
|
||||||
|
"@rollup/rollup-linux-arm64-gnu@4.21.2":
|
||||||
|
version "4.21.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.21.2.tgz#c2fe376e8b04eafb52a286668a8df7c761470ac7"
|
||||||
|
integrity sha512-69CF19Kp3TdMopyteO/LJbWufOzqqXzkrv4L2sP8kfMaAQ6iwky7NoXTp7bD6/irKgknDKM0P9E/1l5XxVQAhw==
|
||||||
|
|
||||||
"@rollup/rollup-linux-arm64-musl@4.18.0":
|
"@rollup/rollup-linux-arm64-musl@4.18.0":
|
||||||
version "4.18.0"
|
version "4.18.0"
|
||||||
resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.18.0.tgz#f53db99a45d9bc00ce94db8a35efa7c3c144a58c"
|
resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.18.0.tgz#f53db99a45d9bc00ce94db8a35efa7c3c144a58c"
|
||||||
integrity sha512-be6Yx37b24ZwxQ+wOQXXLZqpq4jTckJhtGlWGZs68TgdKXJgw54lUUoFYrg6Zs/kjzAQwEwYbp8JxZVzZLRepQ==
|
integrity sha512-be6Yx37b24ZwxQ+wOQXXLZqpq4jTckJhtGlWGZs68TgdKXJgw54lUUoFYrg6Zs/kjzAQwEwYbp8JxZVzZLRepQ==
|
||||||
|
|
||||||
|
"@rollup/rollup-linux-arm64-musl@4.21.2":
|
||||||
|
version "4.21.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.21.2.tgz#e62a4235f01e0f66dbba587c087ca6db8008ec80"
|
||||||
|
integrity sha512-48pD/fJkTiHAZTnZwR0VzHrao70/4MlzJrq0ZsILjLW/Ab/1XlVUStYyGt7tdyIiVSlGZbnliqmult/QGA2O2w==
|
||||||
|
|
||||||
"@rollup/rollup-linux-powerpc64le-gnu@4.18.0":
|
"@rollup/rollup-linux-powerpc64le-gnu@4.18.0":
|
||||||
version "4.18.0"
|
version "4.18.0"
|
||||||
resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.18.0.tgz#cbb0837408fe081ce3435cf3730e090febafc9bf"
|
resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.18.0.tgz#cbb0837408fe081ce3435cf3730e090febafc9bf"
|
||||||
integrity sha512-hNVMQK+qrA9Todu9+wqrXOHxFiD5YmdEi3paj6vP02Kx1hjd2LLYR2eaN7DsEshg09+9uzWi2W18MJDlG0cxJA==
|
integrity sha512-hNVMQK+qrA9Todu9+wqrXOHxFiD5YmdEi3paj6vP02Kx1hjd2LLYR2eaN7DsEshg09+9uzWi2W18MJDlG0cxJA==
|
||||||
|
|
||||||
|
"@rollup/rollup-linux-powerpc64le-gnu@4.21.2":
|
||||||
|
version "4.21.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.21.2.tgz#24b3457e75ee9ae5b1c198bd39eea53222a74e54"
|
||||||
|
integrity sha512-cZdyuInj0ofc7mAQpKcPR2a2iu4YM4FQfuUzCVA2u4HI95lCwzjoPtdWjdpDKyHxI0UO82bLDoOaLfpZ/wviyQ==
|
||||||
|
|
||||||
"@rollup/rollup-linux-riscv64-gnu@4.18.0":
|
"@rollup/rollup-linux-riscv64-gnu@4.18.0":
|
||||||
version "4.18.0"
|
version "4.18.0"
|
||||||
resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.18.0.tgz#8ed09c1d1262ada4c38d791a28ae0fea28b80cc9"
|
resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.18.0.tgz#8ed09c1d1262ada4c38d791a28ae0fea28b80cc9"
|
||||||
integrity sha512-ROCM7i+m1NfdrsmvwSzoxp9HFtmKGHEqu5NNDiZWQtXLA8S5HBCkVvKAxJ8U+CVctHwV2Gb5VUaK7UAkzhDjlg==
|
integrity sha512-ROCM7i+m1NfdrsmvwSzoxp9HFtmKGHEqu5NNDiZWQtXLA8S5HBCkVvKAxJ8U+CVctHwV2Gb5VUaK7UAkzhDjlg==
|
||||||
|
|
||||||
|
"@rollup/rollup-linux-riscv64-gnu@4.21.2":
|
||||||
|
version "4.21.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.21.2.tgz#38edfba9620fe2ca8116c97e02bd9f2d606bde09"
|
||||||
|
integrity sha512-RL56JMT6NwQ0lXIQmMIWr1SW28z4E4pOhRRNqwWZeXpRlykRIlEpSWdsgNWJbYBEWD84eocjSGDu/XxbYeCmwg==
|
||||||
|
|
||||||
"@rollup/rollup-linux-s390x-gnu@4.18.0":
|
"@rollup/rollup-linux-s390x-gnu@4.18.0":
|
||||||
version "4.18.0"
|
version "4.18.0"
|
||||||
resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.18.0.tgz#938138d3c8e0c96f022252a28441dcfb17afd7ec"
|
resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.18.0.tgz#938138d3c8e0c96f022252a28441dcfb17afd7ec"
|
||||||
integrity sha512-0UyyRHyDN42QL+NbqevXIIUnKA47A+45WyasO+y2bGJ1mhQrfrtXUpTxCOrfxCR4esV3/RLYyucGVPiUsO8xjg==
|
integrity sha512-0UyyRHyDN42QL+NbqevXIIUnKA47A+45WyasO+y2bGJ1mhQrfrtXUpTxCOrfxCR4esV3/RLYyucGVPiUsO8xjg==
|
||||||
|
|
||||||
|
"@rollup/rollup-linux-s390x-gnu@4.21.2":
|
||||||
|
version "4.21.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.21.2.tgz#a3bfb8bc5f1e802f8c76cff4a4be2e9f9ac36a18"
|
||||||
|
integrity sha512-PMxkrWS9z38bCr3rWvDFVGD6sFeZJw4iQlhrup7ReGmfn7Oukrr/zweLhYX6v2/8J6Cep9IEA/SmjXjCmSbrMQ==
|
||||||
|
|
||||||
"@rollup/rollup-linux-x64-gnu@4.18.0":
|
"@rollup/rollup-linux-x64-gnu@4.18.0":
|
||||||
version "4.18.0"
|
version "4.18.0"
|
||||||
resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.18.0.tgz#1a7481137a54740bee1ded4ae5752450f155d942"
|
resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.18.0.tgz#1a7481137a54740bee1ded4ae5752450f155d942"
|
||||||
integrity sha512-xuglR2rBVHA5UsI8h8UbX4VJ470PtGCf5Vpswh7p2ukaqBGFTnsfzxUBetoWBWymHMxbIG0Cmx7Y9qDZzr648w==
|
integrity sha512-xuglR2rBVHA5UsI8h8UbX4VJ470PtGCf5Vpswh7p2ukaqBGFTnsfzxUBetoWBWymHMxbIG0Cmx7Y9qDZzr648w==
|
||||||
|
|
||||||
|
"@rollup/rollup-linux-x64-gnu@4.21.2":
|
||||||
|
version "4.21.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.21.2.tgz#0dadf34be9199fcdda44b5985a086326344f30ad"
|
||||||
|
integrity sha512-B90tYAUoLhU22olrafY3JQCFLnT3NglazdwkHyxNDYF/zAxJt5fJUB/yBoWFoIQ7SQj+KLe3iL4BhOMa9fzgpw==
|
||||||
|
|
||||||
"@rollup/rollup-linux-x64-musl@4.18.0":
|
"@rollup/rollup-linux-x64-musl@4.18.0":
|
||||||
version "4.18.0"
|
version "4.18.0"
|
||||||
resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.18.0.tgz#f1186afc601ac4f4fc25fac4ca15ecbee3a1874d"
|
resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.18.0.tgz#f1186afc601ac4f4fc25fac4ca15ecbee3a1874d"
|
||||||
integrity sha512-LKaqQL9osY/ir2geuLVvRRs+utWUNilzdE90TpyoX0eNqPzWjRm14oMEE+YLve4k/NAqCdPkGYDaDF5Sw+xBfg==
|
integrity sha512-LKaqQL9osY/ir2geuLVvRRs+utWUNilzdE90TpyoX0eNqPzWjRm14oMEE+YLve4k/NAqCdPkGYDaDF5Sw+xBfg==
|
||||||
|
|
||||||
|
"@rollup/rollup-linux-x64-musl@4.21.2":
|
||||||
|
version "4.21.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.21.2.tgz#7b7deddce240400eb87f2406a445061b4fed99a8"
|
||||||
|
integrity sha512-7twFizNXudESmC9oneLGIUmoHiiLppz/Xs5uJQ4ShvE6234K0VB1/aJYU3f/4g7PhssLGKBVCC37uRkkOi8wjg==
|
||||||
|
|
||||||
"@rollup/rollup-win32-arm64-msvc@4.18.0":
|
"@rollup/rollup-win32-arm64-msvc@4.18.0":
|
||||||
version "4.18.0"
|
version "4.18.0"
|
||||||
resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.18.0.tgz#ed6603e93636a96203c6915be4117245c1bd2daf"
|
resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.18.0.tgz#ed6603e93636a96203c6915be4117245c1bd2daf"
|
||||||
integrity sha512-7J6TkZQFGo9qBKH0pk2cEVSRhJbL6MtfWxth7Y5YmZs57Pi+4x6c2dStAUvaQkHQLnEQv1jzBUW43GvZW8OFqA==
|
integrity sha512-7J6TkZQFGo9qBKH0pk2cEVSRhJbL6MtfWxth7Y5YmZs57Pi+4x6c2dStAUvaQkHQLnEQv1jzBUW43GvZW8OFqA==
|
||||||
|
|
||||||
|
"@rollup/rollup-win32-arm64-msvc@4.21.2":
|
||||||
|
version "4.21.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.21.2.tgz#a0ca0c5149c2cfb26fab32e6ba3f16996fbdb504"
|
||||||
|
integrity sha512-9rRero0E7qTeYf6+rFh3AErTNU1VCQg2mn7CQcI44vNUWM9Ze7MSRS/9RFuSsox+vstRt97+x3sOhEey024FRQ==
|
||||||
|
|
||||||
"@rollup/rollup-win32-ia32-msvc@4.18.0":
|
"@rollup/rollup-win32-ia32-msvc@4.18.0":
|
||||||
version "4.18.0"
|
version "4.18.0"
|
||||||
resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.18.0.tgz#14e0b404b1c25ebe6157a15edb9c46959ba74c54"
|
resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.18.0.tgz#14e0b404b1c25ebe6157a15edb9c46959ba74c54"
|
||||||
integrity sha512-Txjh+IxBPbkUB9+SXZMpv+b/vnTEtFyfWZgJ6iyCmt2tdx0OF5WhFowLmnh8ENGNpfUlUZkdI//4IEmhwPieNg==
|
integrity sha512-Txjh+IxBPbkUB9+SXZMpv+b/vnTEtFyfWZgJ6iyCmt2tdx0OF5WhFowLmnh8ENGNpfUlUZkdI//4IEmhwPieNg==
|
||||||
|
|
||||||
|
"@rollup/rollup-win32-ia32-msvc@4.21.2":
|
||||||
|
version "4.21.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.21.2.tgz#aae2886beec3024203dbb5569db3a137bc385f8e"
|
||||||
|
integrity sha512-5rA4vjlqgrpbFVVHX3qkrCo/fZTj1q0Xxpg+Z7yIo3J2AilW7t2+n6Q8Jrx+4MrYpAnjttTYF8rr7bP46BPzRw==
|
||||||
|
|
||||||
"@rollup/rollup-win32-x64-msvc@4.18.0":
|
"@rollup/rollup-win32-x64-msvc@4.18.0":
|
||||||
version "4.18.0"
|
version "4.18.0"
|
||||||
resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.18.0.tgz#5d694d345ce36b6ecf657349e03eb87297e68da4"
|
resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.18.0.tgz#5d694d345ce36b6ecf657349e03eb87297e68da4"
|
||||||
integrity sha512-UOo5FdvOL0+eIVTgS4tIdbW+TtnBLWg1YBCcU2KWM7nuNwRz9bksDX1bekJJCpu25N1DVWaCwnT39dVQxzqS8g==
|
integrity sha512-UOo5FdvOL0+eIVTgS4tIdbW+TtnBLWg1YBCcU2KWM7nuNwRz9bksDX1bekJJCpu25N1DVWaCwnT39dVQxzqS8g==
|
||||||
|
|
||||||
|
"@rollup/rollup-win32-x64-msvc@4.21.2":
|
||||||
|
version "4.21.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.21.2.tgz#e4291e3c1bc637083f87936c333cdbcad22af63b"
|
||||||
|
integrity sha512-6UUxd0+SKomjdzuAcp+HAmxw1FlGBnl1v2yEPSabtx4lBfdXHDVsW7+lQkgz9cNFJGY3AWR7+V8P5BqkD9L9nA==
|
||||||
|
|
||||||
"@rushstack/eslint-patch@^1.1.0":
|
"@rushstack/eslint-patch@^1.1.0":
|
||||||
version "1.10.3"
|
version "1.10.3"
|
||||||
resolved "https://registry.yarnpkg.com/@rushstack/eslint-patch/-/eslint-patch-1.10.3.tgz#391d528054f758f81e53210f1a1eebcf1a8b1d20"
|
resolved "https://registry.yarnpkg.com/@rushstack/eslint-patch/-/eslint-patch-1.10.3.tgz#391d528054f758f81e53210f1a1eebcf1a8b1d20"
|
||||||
@@ -5804,6 +5999,35 @@ esbuild@^0.20.1:
|
|||||||
"@esbuild/win32-ia32" "0.20.2"
|
"@esbuild/win32-ia32" "0.20.2"
|
||||||
"@esbuild/win32-x64" "0.20.2"
|
"@esbuild/win32-x64" "0.20.2"
|
||||||
|
|
||||||
|
esbuild@^0.21.3:
|
||||||
|
version "0.21.5"
|
||||||
|
resolved "https://registry.yarnpkg.com/esbuild/-/esbuild-0.21.5.tgz#9ca301b120922959b766360d8ac830da0d02997d"
|
||||||
|
integrity sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==
|
||||||
|
optionalDependencies:
|
||||||
|
"@esbuild/aix-ppc64" "0.21.5"
|
||||||
|
"@esbuild/android-arm" "0.21.5"
|
||||||
|
"@esbuild/android-arm64" "0.21.5"
|
||||||
|
"@esbuild/android-x64" "0.21.5"
|
||||||
|
"@esbuild/darwin-arm64" "0.21.5"
|
||||||
|
"@esbuild/darwin-x64" "0.21.5"
|
||||||
|
"@esbuild/freebsd-arm64" "0.21.5"
|
||||||
|
"@esbuild/freebsd-x64" "0.21.5"
|
||||||
|
"@esbuild/linux-arm" "0.21.5"
|
||||||
|
"@esbuild/linux-arm64" "0.21.5"
|
||||||
|
"@esbuild/linux-ia32" "0.21.5"
|
||||||
|
"@esbuild/linux-loong64" "0.21.5"
|
||||||
|
"@esbuild/linux-mips64el" "0.21.5"
|
||||||
|
"@esbuild/linux-ppc64" "0.21.5"
|
||||||
|
"@esbuild/linux-riscv64" "0.21.5"
|
||||||
|
"@esbuild/linux-s390x" "0.21.5"
|
||||||
|
"@esbuild/linux-x64" "0.21.5"
|
||||||
|
"@esbuild/netbsd-x64" "0.21.5"
|
||||||
|
"@esbuild/openbsd-x64" "0.21.5"
|
||||||
|
"@esbuild/sunos-x64" "0.21.5"
|
||||||
|
"@esbuild/win32-arm64" "0.21.5"
|
||||||
|
"@esbuild/win32-ia32" "0.21.5"
|
||||||
|
"@esbuild/win32-x64" "0.21.5"
|
||||||
|
|
||||||
escalade@^3.1.1, escalade@^3.1.2:
|
escalade@^3.1.1, escalade@^3.1.2:
|
||||||
version "3.1.2"
|
version "3.1.2"
|
||||||
resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.2.tgz#54076e9ab29ea5bf3d8f1ed62acffbb88272df27"
|
resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.2.tgz#54076e9ab29ea5bf3d8f1ed62acffbb88272df27"
|
||||||
@@ -8767,6 +8991,15 @@ postcss@^8.4.32, postcss@^8.4.38, postcss@^8.4.7:
|
|||||||
picocolors "^1.0.0"
|
picocolors "^1.0.0"
|
||||||
source-map-js "^1.2.0"
|
source-map-js "^1.2.0"
|
||||||
|
|
||||||
|
postcss@^8.4.41:
|
||||||
|
version "8.4.43"
|
||||||
|
resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.43.tgz#a5ddf22f4cc38e64c6ae030182b43e539d316419"
|
||||||
|
integrity sha512-gJAQVYbh5R3gYm33FijzCZj7CHyQ3hWMgJMprLUlIYqCwTeZhBQ19wp0e9mA25BUbEvY5+EXuuaAjqQsrBxQBQ==
|
||||||
|
dependencies:
|
||||||
|
nanoid "^3.3.7"
|
||||||
|
picocolors "^1.0.1"
|
||||||
|
source-map-js "^1.2.0"
|
||||||
|
|
||||||
prelude-ls@^1.2.1:
|
prelude-ls@^1.2.1:
|
||||||
version "1.2.1"
|
version "1.2.1"
|
||||||
resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.2.1.tgz#debc6489d7a6e6b0e7611888cec880337d316396"
|
resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.2.1.tgz#debc6489d7a6e6b0e7611888cec880337d316396"
|
||||||
@@ -9242,6 +9475,31 @@ rollup@^4.13.0, rollup@^4.2.0:
|
|||||||
"@rollup/rollup-win32-x64-msvc" "4.18.0"
|
"@rollup/rollup-win32-x64-msvc" "4.18.0"
|
||||||
fsevents "~2.3.2"
|
fsevents "~2.3.2"
|
||||||
|
|
||||||
|
rollup@^4.20.0:
|
||||||
|
version "4.21.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/rollup/-/rollup-4.21.2.tgz#f41f277a448d6264e923dd1ea179f0a926aaf9b7"
|
||||||
|
integrity sha512-e3TapAgYf9xjdLvKQCkQTnbTKd4a6jwlpQSJJFokHGaX2IVjoEqkIIhiQfqsi0cdwlOD+tQGuOd5AJkc5RngBw==
|
||||||
|
dependencies:
|
||||||
|
"@types/estree" "1.0.5"
|
||||||
|
optionalDependencies:
|
||||||
|
"@rollup/rollup-android-arm-eabi" "4.21.2"
|
||||||
|
"@rollup/rollup-android-arm64" "4.21.2"
|
||||||
|
"@rollup/rollup-darwin-arm64" "4.21.2"
|
||||||
|
"@rollup/rollup-darwin-x64" "4.21.2"
|
||||||
|
"@rollup/rollup-linux-arm-gnueabihf" "4.21.2"
|
||||||
|
"@rollup/rollup-linux-arm-musleabihf" "4.21.2"
|
||||||
|
"@rollup/rollup-linux-arm64-gnu" "4.21.2"
|
||||||
|
"@rollup/rollup-linux-arm64-musl" "4.21.2"
|
||||||
|
"@rollup/rollup-linux-powerpc64le-gnu" "4.21.2"
|
||||||
|
"@rollup/rollup-linux-riscv64-gnu" "4.21.2"
|
||||||
|
"@rollup/rollup-linux-s390x-gnu" "4.21.2"
|
||||||
|
"@rollup/rollup-linux-x64-gnu" "4.21.2"
|
||||||
|
"@rollup/rollup-linux-x64-musl" "4.21.2"
|
||||||
|
"@rollup/rollup-win32-arm64-msvc" "4.21.2"
|
||||||
|
"@rollup/rollup-win32-ia32-msvc" "4.21.2"
|
||||||
|
"@rollup/rollup-win32-x64-msvc" "4.21.2"
|
||||||
|
fsevents "~2.3.2"
|
||||||
|
|
||||||
roughjs@4.6.4:
|
roughjs@4.6.4:
|
||||||
version "4.6.4"
|
version "4.6.4"
|
||||||
resolved "https://registry.yarnpkg.com/roughjs/-/roughjs-4.6.4.tgz#b6f39b44645854a6e0a4a28b078368701eb7f939"
|
resolved "https://registry.yarnpkg.com/roughjs/-/roughjs-4.6.4.tgz#b6f39b44645854a6e0a4a28b078368701eb7f939"
|
||||||
@@ -9667,7 +9925,7 @@ string-natural-compare@^3.0.1:
|
|||||||
resolved "https://registry.yarnpkg.com/string-natural-compare/-/string-natural-compare-3.0.1.tgz#7a42d58474454963759e8e8b7ae63d71c1e7fdf4"
|
resolved "https://registry.yarnpkg.com/string-natural-compare/-/string-natural-compare-3.0.1.tgz#7a42d58474454963759e8e8b7ae63d71c1e7fdf4"
|
||||||
integrity sha512-n3sPwynL1nwKi3WJ6AIsClwBMa0zTi54fn2oLU6ndfTSIO05xaznjSf15PcBZU6FNWbmN5Q6cxT4V5hGvB4taw==
|
integrity sha512-n3sPwynL1nwKi3WJ6AIsClwBMa0zTi54fn2oLU6ndfTSIO05xaznjSf15PcBZU6FNWbmN5Q6cxT4V5hGvB4taw==
|
||||||
|
|
||||||
"string-width-cjs@npm:string-width@^4.2.0":
|
"string-width-cjs@npm:string-width@^4.2.0", string-width@^4.2.3:
|
||||||
version "4.2.3"
|
version "4.2.3"
|
||||||
resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010"
|
resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010"
|
||||||
integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==
|
integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==
|
||||||
@@ -9685,15 +9943,6 @@ string-width@^4.1.0, string-width@^4.2.0:
|
|||||||
is-fullwidth-code-point "^3.0.0"
|
is-fullwidth-code-point "^3.0.0"
|
||||||
strip-ansi "^6.0.0"
|
strip-ansi "^6.0.0"
|
||||||
|
|
||||||
string-width@^4.2.3:
|
|
||||||
version "4.2.3"
|
|
||||||
resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010"
|
|
||||||
integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==
|
|
||||||
dependencies:
|
|
||||||
emoji-regex "^8.0.0"
|
|
||||||
is-fullwidth-code-point "^3.0.0"
|
|
||||||
strip-ansi "^6.0.1"
|
|
||||||
|
|
||||||
string-width@^5.0.0, string-width@^5.0.1, string-width@^5.1.2:
|
string-width@^5.0.0, string-width@^5.0.1, string-width@^5.1.2:
|
||||||
version "5.1.2"
|
version "5.1.2"
|
||||||
resolved "https://registry.yarnpkg.com/string-width/-/string-width-5.1.2.tgz#14f8daec6d81e7221d2a357e668cab73bdbca794"
|
resolved "https://registry.yarnpkg.com/string-width/-/string-width-5.1.2.tgz#14f8daec6d81e7221d2a357e668cab73bdbca794"
|
||||||
@@ -9765,14 +10014,7 @@ stringify-object@^3.3.0:
|
|||||||
is-obj "^1.0.1"
|
is-obj "^1.0.1"
|
||||||
is-regexp "^1.0.0"
|
is-regexp "^1.0.0"
|
||||||
|
|
||||||
"strip-ansi-cjs@npm:strip-ansi@^6.0.1":
|
"strip-ansi-cjs@npm:strip-ansi@^6.0.1", strip-ansi@6.0.1, strip-ansi@^3.0.0, strip-ansi@^6.0.0, strip-ansi@^6.0.1, strip-ansi@^7.0.1:
|
||||||
version "6.0.1"
|
|
||||||
resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9"
|
|
||||||
integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==
|
|
||||||
dependencies:
|
|
||||||
ansi-regex "^5.0.1"
|
|
||||||
|
|
||||||
strip-ansi@6.0.1, strip-ansi@^3.0.0, strip-ansi@^6.0.0, strip-ansi@^6.0.1, strip-ansi@^7.0.1:
|
|
||||||
version "6.0.1"
|
version "6.0.1"
|
||||||
resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9"
|
resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9"
|
||||||
integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==
|
integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==
|
||||||
@@ -10453,6 +10695,17 @@ vite@5.0.12:
|
|||||||
optionalDependencies:
|
optionalDependencies:
|
||||||
fsevents "~2.3.3"
|
fsevents "~2.3.3"
|
||||||
|
|
||||||
|
vite@5.4.2:
|
||||||
|
version "5.4.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/vite/-/vite-5.4.2.tgz#8acb6ec4bfab823cdfc1cb2d6c53ed311bc4e47e"
|
||||||
|
integrity sha512-dDrQTRHp5C1fTFzcSaMxjk6vdpKvT+2/mIdE07Gw2ykehT49O0z/VHS3zZ8iV/Gh8BJJKHWOe5RjaNrW5xf/GA==
|
||||||
|
dependencies:
|
||||||
|
esbuild "^0.21.3"
|
||||||
|
postcss "^8.4.41"
|
||||||
|
rollup "^4.20.0"
|
||||||
|
optionalDependencies:
|
||||||
|
fsevents "~2.3.3"
|
||||||
|
|
||||||
vite@^5.0.0:
|
vite@^5.0.0:
|
||||||
version "5.2.11"
|
version "5.2.11"
|
||||||
resolved "https://registry.yarnpkg.com/vite/-/vite-5.2.11.tgz#726ec05555431735853417c3c0bfb36003ca0cbd"
|
resolved "https://registry.yarnpkg.com/vite/-/vite-5.2.11.tgz#726ec05555431735853417c3c0bfb36003ca0cbd"
|
||||||
@@ -11009,7 +11262,7 @@ workbox-window@7.1.0, workbox-window@^7.0.0:
|
|||||||
"@types/trusted-types" "^2.0.2"
|
"@types/trusted-types" "^2.0.2"
|
||||||
workbox-core "7.1.0"
|
workbox-core "7.1.0"
|
||||||
|
|
||||||
"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0":
|
"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0", wrap-ansi@^7.0.0:
|
||||||
version "7.0.0"
|
version "7.0.0"
|
||||||
resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43"
|
resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43"
|
||||||
integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==
|
integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==
|
||||||
@@ -11027,15 +11280,6 @@ wrap-ansi@^6.2.0:
|
|||||||
string-width "^4.1.0"
|
string-width "^4.1.0"
|
||||||
strip-ansi "^6.0.0"
|
strip-ansi "^6.0.0"
|
||||||
|
|
||||||
wrap-ansi@^7.0.0:
|
|
||||||
version "7.0.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43"
|
|
||||||
integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==
|
|
||||||
dependencies:
|
|
||||||
ansi-styles "^4.0.0"
|
|
||||||
string-width "^4.1.0"
|
|
||||||
strip-ansi "^6.0.0"
|
|
||||||
|
|
||||||
wrap-ansi@^8.1.0:
|
wrap-ansi@^8.1.0:
|
||||||
version "8.1.0"
|
version "8.1.0"
|
||||||
resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-8.1.0.tgz#56dc22368ee570face1b49819975d9b9a5ead214"
|
resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-8.1.0.tgz#56dc22368ee570face1b49819975d9b9a5ead214"
|
||||||
|
|||||||
Reference in New Issue
Block a user