mirror of
https://github.com/excalidraw/excalidraw.git
synced 2025-11-01 19:34:38 +01:00
Compare commits
15 Commits
aakansha-p
...
kb/auto-sa
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2bf886c941 | ||
|
|
6215256787 | ||
|
|
35d195e891 | ||
|
|
9d3d7f3500 | ||
|
|
0b32757085 | ||
|
|
6442a45bd4 | ||
|
|
d7a015cb3a | ||
|
|
f68404fbed | ||
|
|
01f5914a82 | ||
|
|
5e1e16c150 | ||
|
|
14537cbaba | ||
|
|
92ac11c49d | ||
|
|
90d68b3e0b | ||
|
|
006aad052d | ||
|
|
98a7707e26 |
18
package.json
18
package.json
@@ -19,18 +19,18 @@
|
||||
]
|
||||
},
|
||||
"dependencies": {
|
||||
"@sentry/browser": "6.2.5",
|
||||
"@sentry/integrations": "6.2.5",
|
||||
"@sentry/browser": "6.2.2",
|
||||
"@sentry/integrations": "6.2.1",
|
||||
"@testing-library/jest-dom": "5.11.10",
|
||||
"@testing-library/react": "11.2.6",
|
||||
"@testing-library/react": "11.2.5",
|
||||
"@types/jest": "26.0.22",
|
||||
"@types/react": "17.0.3",
|
||||
"@types/react-dom": "17.0.3",
|
||||
"@types/react-dom": "17.0.2",
|
||||
"@types/socket.io-client": "1.4.36",
|
||||
"browser-fs-access": "0.16.4",
|
||||
"browser-fs-access": "0.16.2",
|
||||
"clsx": "1.1.1",
|
||||
"firebase": "8.3.2",
|
||||
"i18next-browser-languagedetector": "6.1.0",
|
||||
"firebase": "8.2.10",
|
||||
"i18next-browser-languagedetector": "6.0.1",
|
||||
"lodash.throttle": "4.1.1",
|
||||
"nanoid": "3.1.22",
|
||||
"open-color": "1.8.0",
|
||||
@@ -46,7 +46,7 @@
|
||||
"roughjs": "4.3.1",
|
||||
"sass": "1.32.8",
|
||||
"socket.io-client": "2.3.1",
|
||||
"typescript": "4.2.4"
|
||||
"typescript": "4.2.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@excalidraw/eslint-config": "1.0.0",
|
||||
@@ -56,7 +56,7 @@
|
||||
"@types/resize-observer-browser": "0.1.5",
|
||||
"eslint-config-prettier": "8.1.0",
|
||||
"eslint-plugin-prettier": "3.3.1",
|
||||
"firebase-tools": "9.9.0",
|
||||
"firebase-tools": "9.6.1",
|
||||
"husky": "4.3.8",
|
||||
"jest-canvas-mock": "2.3.1",
|
||||
"lint-staged": "10.5.4",
|
||||
|
||||
@@ -8,7 +8,7 @@ import { getCommonBounds, getNonDeletedElements } from "../element";
|
||||
import { newElementWith } from "../element/mutateElement";
|
||||
import { ExcalidrawElement } from "../element/types";
|
||||
import { t } from "../i18n";
|
||||
import { useIsMobile } from "../components/App";
|
||||
import { useIsMobile } from "../is-mobile";
|
||||
import { CODES, KEYS } from "../keys";
|
||||
import { getNormalizedZoom, getSelectedElements } from "../scene";
|
||||
import { centerScrollOn } from "../scene/scroll";
|
||||
|
||||
@@ -8,7 +8,7 @@ import { Tooltip } from "../components/Tooltip";
|
||||
import { DarkModeToggle, Appearence } from "../components/DarkModeToggle";
|
||||
import { loadFromJSON, saveAsJSON } from "../data";
|
||||
import { t } from "../i18n";
|
||||
import { useIsMobile } from "../components/App";
|
||||
import { useIsMobile } from "../is-mobile";
|
||||
import { KEYS } from "../keys";
|
||||
import { register } from "./register";
|
||||
import { supported } from "browser-fs-access";
|
||||
@@ -238,3 +238,37 @@ export const actionExportWithDarkMode = register({
|
||||
</div>
|
||||
),
|
||||
});
|
||||
|
||||
export const actionToggleAutosave = register({
|
||||
name: "toggleAutosave",
|
||||
perform(elements, appState) {
|
||||
trackEvent("toggle", "autosave");
|
||||
return {
|
||||
appState: {
|
||||
...appState,
|
||||
autosave: !appState.autosave,
|
||||
},
|
||||
commitToHistory: false,
|
||||
};
|
||||
},
|
||||
PanelComponent: ({ appState, updateData }) =>
|
||||
supported && appState.fileHandle ? (
|
||||
<label style={{ display: "flex" }}>
|
||||
<input
|
||||
type="checkbox"
|
||||
checked={appState.autosave}
|
||||
onChange={(event) => updateData(event.target.checked)}
|
||||
/>{" "}
|
||||
{t("labels.toggleAutosave")}
|
||||
<Tooltip
|
||||
label={t("labels.toggleAutosave_details")}
|
||||
position="above"
|
||||
long={true}
|
||||
>
|
||||
<div className="TooltipIcon">{questionCircle}</div>
|
||||
</Tooltip>
|
||||
</label>
|
||||
) : (
|
||||
<></>
|
||||
),
|
||||
});
|
||||
|
||||
@@ -33,6 +33,7 @@ export { actionFinalize } from "./actionFinalize";
|
||||
export {
|
||||
actionChangeProjectName,
|
||||
actionChangeExportBackground,
|
||||
actionToggleAutosave,
|
||||
actionSaveScene,
|
||||
actionSaveAsScene,
|
||||
actionLoadScene,
|
||||
|
||||
@@ -51,6 +51,7 @@ export type ActionName =
|
||||
| "changeOpacity"
|
||||
| "changeFontSize"
|
||||
| "toggleCanvasMenu"
|
||||
| "toggleAutosave"
|
||||
| "toggleEditMenu"
|
||||
| "undo"
|
||||
| "redo"
|
||||
|
||||
@@ -13,6 +13,7 @@ export const getDefaultAppState = (): Omit<
|
||||
"offsetTop" | "offsetLeft" | "width" | "height"
|
||||
> => {
|
||||
return {
|
||||
autosave: false,
|
||||
theme: "light",
|
||||
collaborators: new Map(),
|
||||
currentChartType: "bar",
|
||||
@@ -90,6 +91,7 @@ const APP_STATE_STORAGE_CONF = (<
|
||||
>(
|
||||
config: { [K in keyof T]: K extends keyof AppState ? T[K] : never },
|
||||
) => config)({
|
||||
autosave: { browser: true, export: false },
|
||||
theme: { browser: true, export: false },
|
||||
collaborators: { browser: false, export: false },
|
||||
currentChartType: { browser: true, export: false },
|
||||
|
||||
@@ -14,13 +14,6 @@ type ElementsClipboard = {
|
||||
elements: ExcalidrawElement[];
|
||||
};
|
||||
|
||||
export interface ClipboardData {
|
||||
spreadsheet?: Spreadsheet;
|
||||
elements?: readonly ExcalidrawElement[];
|
||||
text?: string;
|
||||
errorMessage?: string;
|
||||
}
|
||||
|
||||
let CLIPBOARD = "";
|
||||
let PREFER_APP_CLIPBOARD = false;
|
||||
|
||||
@@ -117,7 +110,12 @@ const getSystemClipboard = async (
|
||||
*/
|
||||
export const parseClipboard = async (
|
||||
event: ClipboardEvent | null,
|
||||
): Promise<ClipboardData> => {
|
||||
): Promise<{
|
||||
spreadsheet?: Spreadsheet;
|
||||
elements?: readonly ExcalidrawElement[];
|
||||
text?: string;
|
||||
errorMessage?: string;
|
||||
}> => {
|
||||
const systemClipboard = await getSystemClipboard(event);
|
||||
|
||||
// if system clipboard empty, couldn't be resolved, or contains previously
|
||||
|
||||
@@ -3,7 +3,7 @@ import { ActionManager } from "../actions/manager";
|
||||
import { getNonDeletedElements } from "../element";
|
||||
import { ExcalidrawElement } from "../element/types";
|
||||
import { t } from "../i18n";
|
||||
import { useIsMobile } from "../components/App";
|
||||
import { useIsMobile } from "../is-mobile";
|
||||
import {
|
||||
canChangeSharpness,
|
||||
canHaveArrowheads,
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { Point, simplify } from "points-on-curve";
|
||||
import React, { useContext } from "react";
|
||||
import React from "react";
|
||||
import { RoughCanvas } from "roughjs/bin/canvas";
|
||||
import rough from "roughjs/bin/rough";
|
||||
import clsx from "clsx";
|
||||
@@ -46,7 +46,6 @@ import {
|
||||
CURSOR_TYPE,
|
||||
DEFAULT_UI_OPTIONS,
|
||||
DEFAULT_VERTICAL_ALIGN,
|
||||
DETECT_POSITION_CHANGE_INTERVAL,
|
||||
DRAGGING_THRESHOLD,
|
||||
ELEMENT_SHIFT_TRANSLATE_AMOUNT,
|
||||
ELEMENT_TRANSLATE_AMOUNT,
|
||||
@@ -55,11 +54,9 @@ import {
|
||||
GRID_SIZE,
|
||||
LINE_CONFIRM_THRESHOLD,
|
||||
MIME_TYPES,
|
||||
MQ_MAX_HEIGHT_LANDSCAPE,
|
||||
MQ_MAX_WIDTH_LANDSCAPE,
|
||||
MQ_MAX_WIDTH_PORTRAIT,
|
||||
POINTER_BUTTON,
|
||||
SCROLL_TIMEOUT,
|
||||
AUTO_SAVE_TIMEOUT,
|
||||
TAP_TWICE_TIMEOUT,
|
||||
TEXT_TO_CENTER_SNAP_THRESHOLD,
|
||||
TOUCH_CTX_MENU_TIMEOUT,
|
||||
@@ -68,7 +65,7 @@ import {
|
||||
ZOOM_STEP,
|
||||
} from "../constants";
|
||||
import { loadFromBlob } from "../data";
|
||||
import { isValidLibrary } from "../data/json";
|
||||
import { saveAsJSON, isValidLibrary } from "../data/json";
|
||||
import { Library } from "../data/library";
|
||||
import { restore } from "../data/restore";
|
||||
import {
|
||||
@@ -169,7 +166,6 @@ import { AppProps, AppState, Gesture, GestureEvent, SceneData } from "../types";
|
||||
import {
|
||||
debounce,
|
||||
distance,
|
||||
getNearestScrollableContainer,
|
||||
isInputLike,
|
||||
isToolIcon,
|
||||
isWritableElement,
|
||||
@@ -183,15 +179,13 @@ import {
|
||||
viewportCoordsToSceneCoords,
|
||||
withBatchedUpdates,
|
||||
} from "../utils";
|
||||
import { isMobile } from "../is-mobile";
|
||||
import ContextMenu, { ContextMenuOption } from "./ContextMenu";
|
||||
import LayerUI from "./LayerUI";
|
||||
import { Stats } from "./Stats";
|
||||
import { Toast } from "./Toast";
|
||||
import { actionToggleViewMode } from "../actions/actionToggleViewMode";
|
||||
|
||||
export const IsMobileContext = React.createContext(false);
|
||||
export const useIsMobile = () => useContext(IsMobileContext);
|
||||
|
||||
const { history } = createHistory();
|
||||
|
||||
let didTapTwice: boolean = false;
|
||||
@@ -293,9 +287,6 @@ class App extends React.Component<AppProps, AppState> {
|
||||
rc: RoughCanvas | null = null;
|
||||
unmounted: boolean = false;
|
||||
actionManager: ActionManager;
|
||||
isMobile = false;
|
||||
detachIsMobileMqHandler?: () => void;
|
||||
|
||||
private excalidrawContainerRef = React.createRef<HTMLDivElement>();
|
||||
|
||||
public static defaultProps: Partial<AppProps> = {
|
||||
@@ -305,9 +296,6 @@ class App extends React.Component<AppProps, AppState> {
|
||||
|
||||
private scene: Scene;
|
||||
private resizeObserver: ResizeObserver | undefined;
|
||||
private nearestScrollableContainer: HTMLElement | Document | undefined;
|
||||
private detectPositionIntervalId: NodeJS.Timeout | undefined;
|
||||
|
||||
constructor(props: AppProps) {
|
||||
super(props);
|
||||
const defaultAppState = getDefaultAppState();
|
||||
@@ -450,64 +438,60 @@ class App extends React.Component<AppProps, AppState> {
|
||||
<div
|
||||
className={clsx("excalidraw", {
|
||||
"excalidraw--view-mode": viewModeEnabled,
|
||||
"excalidraw--mobile": this.isMobile,
|
||||
})}
|
||||
ref={this.excalidrawContainerRef}
|
||||
onDrop={this.handleAppOnDrop}
|
||||
>
|
||||
<IsMobileContext.Provider value={this.isMobile}>
|
||||
<LayerUI
|
||||
canvas={this.canvas}
|
||||
<LayerUI
|
||||
canvas={this.canvas}
|
||||
appState={this.state}
|
||||
setAppState={this.setAppState}
|
||||
actionManager={this.actionManager}
|
||||
elements={this.scene.getElements()}
|
||||
onCollabButtonClick={onCollabButtonClick}
|
||||
onLockToggle={this.toggleLock}
|
||||
onInsertElements={(elements) =>
|
||||
this.addElementsFromPasteOrLibrary(
|
||||
elements,
|
||||
DEFAULT_PASTE_X,
|
||||
DEFAULT_PASTE_Y,
|
||||
)
|
||||
}
|
||||
zenModeEnabled={zenModeEnabled}
|
||||
toggleZenMode={this.toggleZenMode}
|
||||
langCode={getLanguage().code}
|
||||
isCollaborating={this.props.isCollaborating || false}
|
||||
onExportToBackend={onExportToBackend}
|
||||
renderCustomFooter={renderFooter}
|
||||
viewModeEnabled={viewModeEnabled}
|
||||
showExitZenModeBtn={
|
||||
typeof this.props?.zenModeEnabled === "undefined" && zenModeEnabled
|
||||
}
|
||||
showThemeBtn={
|
||||
typeof this.props?.theme === "undefined" &&
|
||||
this.props.UIOptions.canvasActions.theme
|
||||
}
|
||||
libraryReturnUrl={this.props.libraryReturnUrl}
|
||||
UIOptions={this.props.UIOptions}
|
||||
/>
|
||||
<div className="excalidraw-textEditorContainer" />
|
||||
<div className="excalidraw-contextMenuContainer" />
|
||||
{this.state.showStats && (
|
||||
<Stats
|
||||
appState={this.state}
|
||||
setAppState={this.setAppState}
|
||||
actionManager={this.actionManager}
|
||||
elements={this.scene.getElements()}
|
||||
onCollabButtonClick={onCollabButtonClick}
|
||||
onLockToggle={this.toggleLock}
|
||||
onInsertElements={(elements) =>
|
||||
this.addElementsFromPasteOrLibrary(
|
||||
elements,
|
||||
DEFAULT_PASTE_X,
|
||||
DEFAULT_PASTE_Y,
|
||||
)
|
||||
}
|
||||
zenModeEnabled={zenModeEnabled}
|
||||
toggleZenMode={this.toggleZenMode}
|
||||
langCode={getLanguage().code}
|
||||
isCollaborating={this.props.isCollaborating || false}
|
||||
onExportToBackend={onExportToBackend}
|
||||
renderCustomFooter={renderFooter}
|
||||
viewModeEnabled={viewModeEnabled}
|
||||
showExitZenModeBtn={
|
||||
typeof this.props?.zenModeEnabled === "undefined" &&
|
||||
zenModeEnabled
|
||||
}
|
||||
showThemeBtn={
|
||||
typeof this.props?.theme === "undefined" &&
|
||||
this.props.UIOptions.canvasActions.theme
|
||||
}
|
||||
libraryReturnUrl={this.props.libraryReturnUrl}
|
||||
UIOptions={this.props.UIOptions}
|
||||
onClose={this.toggleStats}
|
||||
renderCustomStats={renderCustomStats}
|
||||
/>
|
||||
<div className="excalidraw-textEditorContainer" />
|
||||
<div className="excalidraw-contextMenuContainer" />
|
||||
{this.state.showStats && (
|
||||
<Stats
|
||||
appState={this.state}
|
||||
setAppState={this.setAppState}
|
||||
elements={this.scene.getElements()}
|
||||
onClose={this.toggleStats}
|
||||
renderCustomStats={renderCustomStats}
|
||||
/>
|
||||
)}
|
||||
{this.state.toastMessage !== null && (
|
||||
<Toast
|
||||
message={this.state.toastMessage}
|
||||
clearToast={this.clearToast}
|
||||
/>
|
||||
)}
|
||||
<main>{this.renderCanvas()}</main>
|
||||
</IsMobileContext.Provider>
|
||||
)}
|
||||
{this.state.toastMessage !== null && (
|
||||
<Toast
|
||||
message={this.state.toastMessage}
|
||||
clearToast={this.clearToast}
|
||||
/>
|
||||
)}
|
||||
<main>{this.renderCanvas()}</main>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -791,38 +775,12 @@ class App extends React.Component<AppProps, AppState> {
|
||||
this.scene.addCallback(this.onSceneUpdated);
|
||||
this.addEventListeners();
|
||||
|
||||
if (this.props.detectPosition) {
|
||||
this.detectPositionIntervalId = setInterval(
|
||||
this.updateOffsetsIfChanged,
|
||||
DETECT_POSITION_CHANGE_INTERVAL,
|
||||
);
|
||||
}
|
||||
|
||||
if ("ResizeObserver" in window && this.excalidrawContainerRef?.current) {
|
||||
this.resizeObserver = new ResizeObserver(() => {
|
||||
// compute isMobile state
|
||||
// ---------------------------------------------------------------------
|
||||
const {
|
||||
width,
|
||||
height,
|
||||
} = this.excalidrawContainerRef.current!.getBoundingClientRect();
|
||||
this.isMobile =
|
||||
width < MQ_MAX_WIDTH_PORTRAIT ||
|
||||
(height < MQ_MAX_HEIGHT_LANDSCAPE && width < MQ_MAX_WIDTH_LANDSCAPE);
|
||||
// refresh offsets
|
||||
// ---------------------------------------------------------------------
|
||||
this.updateDOMRect();
|
||||
});
|
||||
this.resizeObserver?.observe(this.excalidrawContainerRef.current);
|
||||
} else if (window.matchMedia) {
|
||||
const mediaQuery = window.matchMedia(
|
||||
`(max-width: ${MQ_MAX_WIDTH_PORTRAIT}px), (max-height: ${MQ_MAX_HEIGHT_LANDSCAPE}px) and (max-width: ${MQ_MAX_WIDTH_LANDSCAPE}px)`,
|
||||
);
|
||||
const handler = () => (this.isMobile = mediaQuery.matches);
|
||||
mediaQuery.addListener(handler);
|
||||
this.detachIsMobileMqHandler = () => mediaQuery.removeListener(handler);
|
||||
}
|
||||
|
||||
const searchParams = new URLSearchParams(window.location.search.slice(1));
|
||||
|
||||
if (searchParams.has("web-share-target")) {
|
||||
@@ -839,9 +797,6 @@ class App extends React.Component<AppProps, AppState> {
|
||||
this.removeEventListeners();
|
||||
this.scene.destroy();
|
||||
clearTimeout(touchTimeout);
|
||||
if (this.detectPositionIntervalId) {
|
||||
clearInterval(this.detectPositionIntervalId);
|
||||
}
|
||||
touchTimeout = 0;
|
||||
}
|
||||
|
||||
@@ -856,10 +811,6 @@ class App extends React.Component<AppProps, AppState> {
|
||||
document.removeEventListener(EVENT.COPY, this.onCopy);
|
||||
document.removeEventListener(EVENT.PASTE, this.pasteFromClipboard);
|
||||
document.removeEventListener(EVENT.CUT, this.onCut);
|
||||
this.nearestScrollableContainer?.removeEventListener(
|
||||
EVENT.SCROLL,
|
||||
this.onScroll,
|
||||
);
|
||||
|
||||
document.removeEventListener(EVENT.KEYDOWN, this.onKeyDown, false);
|
||||
document.removeEventListener(
|
||||
@@ -889,8 +840,6 @@ class App extends React.Component<AppProps, AppState> {
|
||||
this.onGestureEnd as any,
|
||||
false,
|
||||
);
|
||||
|
||||
this.detachIsMobileMqHandler?.();
|
||||
}
|
||||
|
||||
private addEventListeners() {
|
||||
@@ -926,15 +875,8 @@ class App extends React.Component<AppProps, AppState> {
|
||||
|
||||
document.addEventListener(EVENT.PASTE, this.pasteFromClipboard);
|
||||
document.addEventListener(EVENT.CUT, this.onCut);
|
||||
if (this.props.detectScroll) {
|
||||
this.nearestScrollableContainer = getNearestScrollableContainer(
|
||||
this.excalidrawContainerRef.current!,
|
||||
);
|
||||
this.nearestScrollableContainer.addEventListener(
|
||||
EVENT.SCROLL,
|
||||
this.onScroll,
|
||||
);
|
||||
}
|
||||
document.addEventListener(EVENT.SCROLL, this.onScroll);
|
||||
|
||||
window.addEventListener(EVENT.RESIZE, this.onResize, false);
|
||||
window.addEventListener(EVENT.UNLOAD, this.onUnload, false);
|
||||
window.addEventListener(EVENT.BLUR, this.onBlur, false);
|
||||
@@ -982,6 +924,13 @@ class App extends React.Component<AppProps, AppState> {
|
||||
.querySelector(".excalidraw")
|
||||
?.classList.toggle("theme--dark", this.state.theme === "dark");
|
||||
|
||||
if (this.state.autosave && this.state.fileHandle && supported) {
|
||||
this.autosaveLocalSceneDebounced(
|
||||
this.scene.getElementsIncludingDeleted(),
|
||||
this.state,
|
||||
);
|
||||
}
|
||||
|
||||
if (
|
||||
this.state.editingLinearElement &&
|
||||
!this.state.selectedElementIds[this.state.editingLinearElement.elementId]
|
||||
@@ -1075,7 +1024,7 @@ class App extends React.Component<AppProps, AppState> {
|
||||
},
|
||||
{
|
||||
renderOptimizations: true,
|
||||
renderScrollbars: !this.isMobile,
|
||||
renderScrollbars: !isMobile(),
|
||||
},
|
||||
);
|
||||
if (scrollBars) {
|
||||
@@ -1104,7 +1053,7 @@ class App extends React.Component<AppProps, AppState> {
|
||||
}
|
||||
}
|
||||
|
||||
private updateOffsetsIfChanged = () => {
|
||||
private onScroll = debounce(() => {
|
||||
const { offsetTop, offsetLeft } = this.getCanvasOffsets();
|
||||
this.setState((state) => {
|
||||
if (state.offsetLeft === offsetLeft && state.offsetTop === offsetTop) {
|
||||
@@ -1112,9 +1061,38 @@ class App extends React.Component<AppProps, AppState> {
|
||||
}
|
||||
return { offsetTop, offsetLeft };
|
||||
});
|
||||
};
|
||||
}, SCROLL_TIMEOUT);
|
||||
|
||||
private onScroll = debounce(this.updateOffsetsIfChanged, SCROLL_TIMEOUT);
|
||||
private autosaveLocalSceneDebounced = debounce(
|
||||
async (elements: readonly ExcalidrawElement[], state: AppState) => {
|
||||
if (this.state.autosave && this.state.fileHandle && supported) {
|
||||
try {
|
||||
await saveAsJSON(
|
||||
elements,
|
||||
state,
|
||||
// only if fileHandle valid
|
||||
true,
|
||||
);
|
||||
} catch (error) {
|
||||
this.setState({
|
||||
autosave: false,
|
||||
toastMessage:
|
||||
error.name === "NotAllowedError"
|
||||
? t("toast.autosaveFailed_notAllowed")
|
||||
: error.name === "NotFoundError"
|
||||
? t("toast.autosaveFailed_notFound")
|
||||
: t("toast.autosaveFailed"),
|
||||
});
|
||||
|
||||
// shouldn't happen, so let's log it
|
||||
if (!["NotAllowedError", "NotFoundError"].includes(error.name)) {
|
||||
console.error(error);
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
AUTO_SAVE_TIMEOUT,
|
||||
);
|
||||
|
||||
// Copy/paste
|
||||
|
||||
@@ -1216,11 +1194,6 @@ class App extends React.Component<AppProps, AppState> {
|
||||
return;
|
||||
}
|
||||
const data = await parseClipboard(event);
|
||||
if (this.props.onPaste) {
|
||||
if (await this.props.onPaste(data, event)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (data.errorMessage) {
|
||||
this.setState({ errorMessage: data.errorMessage });
|
||||
} else if (data.spreadsheet) {
|
||||
@@ -3877,6 +3850,8 @@ class App extends React.Component<AppProps, AppState> {
|
||||
|
||||
const separator = "separator";
|
||||
|
||||
const _isMobile = isMobile();
|
||||
|
||||
const elements = this.scene.getElements();
|
||||
|
||||
const options: ContextMenuOption[] = [];
|
||||
@@ -3913,7 +3888,7 @@ class App extends React.Component<AppProps, AppState> {
|
||||
|
||||
ContextMenu.push({
|
||||
options: [
|
||||
this.isMobile &&
|
||||
_isMobile &&
|
||||
navigator.clipboard && {
|
||||
name: "paste",
|
||||
perform: (elements, appStates) => {
|
||||
@@ -3924,7 +3899,7 @@ class App extends React.Component<AppProps, AppState> {
|
||||
},
|
||||
contextItemLabel: "labels.paste",
|
||||
},
|
||||
this.isMobile && navigator.clipboard && separator,
|
||||
_isMobile && navigator.clipboard && separator,
|
||||
probablySupportsClipboardBlob &&
|
||||
elements.length > 0 &&
|
||||
actionCopyAsPng,
|
||||
@@ -3967,9 +3942,9 @@ class App extends React.Component<AppProps, AppState> {
|
||||
|
||||
ContextMenu.push({
|
||||
options: [
|
||||
this.isMobile && actionCut,
|
||||
this.isMobile && navigator.clipboard && actionCopy,
|
||||
this.isMobile &&
|
||||
_isMobile && actionCut,
|
||||
_isMobile && navigator.clipboard && actionCopy,
|
||||
_isMobile &&
|
||||
navigator.clipboard && {
|
||||
name: "paste",
|
||||
perform: (elements, appStates) => {
|
||||
@@ -3980,7 +3955,7 @@ class App extends React.Component<AppProps, AppState> {
|
||||
},
|
||||
contextItemLabel: "labels.paste",
|
||||
},
|
||||
this.isMobile && separator,
|
||||
_isMobile && separator,
|
||||
...options,
|
||||
separator,
|
||||
actionCopyStyles,
|
||||
|
||||
@@ -2,7 +2,7 @@ import React from "react";
|
||||
import clsx from "clsx";
|
||||
import { ToolButton } from "./ToolButton";
|
||||
import { t } from "../i18n";
|
||||
import { useIsMobile } from "../components/App";
|
||||
import { useIsMobile } from "../is-mobile";
|
||||
import { users } from "./icons";
|
||||
|
||||
import "./CollabButton.scss";
|
||||
|
||||
@@ -218,7 +218,7 @@
|
||||
left: 2px;
|
||||
}
|
||||
|
||||
@include isMobile {
|
||||
@media #{$is-mobile-query} {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -76,7 +76,7 @@
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
@include isMobile {
|
||||
@media #{$is-mobile-query} {
|
||||
.context-menu-option {
|
||||
display: block;
|
||||
|
||||
|
||||
@@ -31,7 +31,7 @@
|
||||
padding: 0 16px 16px;
|
||||
}
|
||||
|
||||
@include isMobile {
|
||||
@media #{$is-mobile-query} {
|
||||
.Dialog {
|
||||
--metric: calc(var(--space-factor) * 4);
|
||||
--inset-left: #{"max(var(--metric), var(--sal))"};
|
||||
|
||||
@@ -2,7 +2,7 @@ import clsx from "clsx";
|
||||
import React, { useEffect } from "react";
|
||||
import { useCallbackRefState } from "../hooks/useCallbackRefState";
|
||||
import { t } from "../i18n";
|
||||
import { useIsMobile } from "../components/App";
|
||||
import { useIsMobile } from "../is-mobile";
|
||||
import { KEYS } from "../keys";
|
||||
import "./Dialog.scss";
|
||||
import { back, close } from "./icons";
|
||||
|
||||
@@ -55,7 +55,7 @@
|
||||
}
|
||||
}
|
||||
|
||||
@include isMobile {
|
||||
@media #{$is-mobile-query} {
|
||||
.ExportDialog {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
@@ -6,7 +6,7 @@ import { canvasToBlob } from "../data/blob";
|
||||
import { NonDeletedExcalidrawElement } from "../element/types";
|
||||
import { CanvasError } from "../errors";
|
||||
import { t } from "../i18n";
|
||||
import { useIsMobile } from "../components/App";
|
||||
import { useIsMobile } from "../is-mobile";
|
||||
import { getSelectedElements, isSomeElementSelected } from "../scene";
|
||||
import { exportToCanvas, getExportSize } from "../scene/export";
|
||||
import { AppState } from "../types";
|
||||
@@ -202,6 +202,7 @@ const ExportModal = ({
|
||||
})}
|
||||
</Stack.Row>
|
||||
</div>
|
||||
{actionManager.renderAction("toggleAutosave")}
|
||||
{actionManager.renderAction("changeExportBackground")}
|
||||
{someElementIsSelected && (
|
||||
<div>
|
||||
|
||||
@@ -19,7 +19,7 @@ $wide-viewport-width: 1000px;
|
||||
color: $oc-gray-6;
|
||||
font-size: 0.8rem;
|
||||
|
||||
@include isMobile {
|
||||
@media #{$is-mobile-query} {
|
||||
position: static;
|
||||
padding-right: 2em;
|
||||
}
|
||||
|
||||
@@ -111,7 +111,7 @@
|
||||
:root[dir="rtl"] & {
|
||||
left: 2px;
|
||||
}
|
||||
@include isMobile {
|
||||
@media #{$is-mobile-query} {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@ import { Library } from "../data/library";
|
||||
import { isTextElement, showSelectedShapeActions } from "../element";
|
||||
import { NonDeletedExcalidrawElement } from "../element/types";
|
||||
import { Language, t } from "../i18n";
|
||||
import { useIsMobile } from "../components/App";
|
||||
import { useIsMobile } from "../is-mobile";
|
||||
import { calculateScrollCenter, getSelectedElements } from "../scene";
|
||||
import { ExportType } from "../scene/types";
|
||||
import {
|
||||
|
||||
@@ -4,7 +4,7 @@ import React, { useEffect, useRef, useState } from "react";
|
||||
import { close } from "../components/icons";
|
||||
import { MIME_TYPES } from "../constants";
|
||||
import { t } from "../i18n";
|
||||
import { useIsMobile } from "../components/App";
|
||||
import { useIsMobile } from "../is-mobile";
|
||||
import { exportToSvg } from "../scene/export";
|
||||
import { LibraryItem } from "../types";
|
||||
import "./LibraryUnit.scss";
|
||||
|
||||
@@ -52,7 +52,7 @@
|
||||
border-radius: 6px;
|
||||
box-sizing: border-box;
|
||||
|
||||
@include isMobile {
|
||||
@media #{$is-mobile-query} {
|
||||
max-width: 100%;
|
||||
border: 0;
|
||||
border-radius: 0;
|
||||
@@ -82,7 +82,7 @@
|
||||
}
|
||||
}
|
||||
|
||||
@include isMobile {
|
||||
@media #{$is-mobile-query} {
|
||||
.Modal {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
import "./Modal.scss";
|
||||
|
||||
import React, { useState, useLayoutEffect, useRef } from "react";
|
||||
import React, { useState, useLayoutEffect } from "react";
|
||||
import { createPortal } from "react-dom";
|
||||
import clsx from "clsx";
|
||||
import { KEYS } from "../keys";
|
||||
import { useIsMobile } from "../components/App";
|
||||
|
||||
export const Modal = (props: {
|
||||
className?: string;
|
||||
@@ -49,16 +48,6 @@ export const Modal = (props: {
|
||||
const useBodyRoot = () => {
|
||||
const [div, setDiv] = useState<HTMLDivElement | null>(null);
|
||||
|
||||
const isMobile = useIsMobile();
|
||||
const isMobileRef = useRef(isMobile);
|
||||
isMobileRef.current = isMobile;
|
||||
|
||||
useLayoutEffect(() => {
|
||||
if (div) {
|
||||
div.classList.toggle("excalidraw--mobile", isMobile);
|
||||
}
|
||||
}, [div, isMobile]);
|
||||
|
||||
useLayoutEffect(() => {
|
||||
const isDarkTheme = !!document
|
||||
.querySelector(".excalidraw")
|
||||
@@ -66,7 +55,6 @@ const useBodyRoot = () => {
|
||||
const div = document.createElement("div");
|
||||
|
||||
div.classList.add("excalidraw", "excalidraw-modal-container");
|
||||
div.classList.toggle("excalidraw--mobile", isMobileRef.current);
|
||||
|
||||
if (isDarkTheme) {
|
||||
div.classList.add("theme--dark");
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
.excalidraw {
|
||||
.PasteChartDialog {
|
||||
@include isMobile {
|
||||
@media #{$is-mobile-query} {
|
||||
.Island {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
@@ -13,7 +13,7 @@
|
||||
align-items: center;
|
||||
justify-content: space-around;
|
||||
flex-wrap: wrap;
|
||||
@include isMobile {
|
||||
@media #{$is-mobile-query} {
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@ import React from "react";
|
||||
import { getCommonBounds } from "../element/bounds";
|
||||
import { NonDeletedExcalidrawElement } from "../element/types";
|
||||
import { t } from "../i18n";
|
||||
import { useIsMobile } from "../components/App";
|
||||
import { useIsMobile } from "../is-mobile";
|
||||
import { getTargetElements } from "../scene";
|
||||
import { AppState, ExcalidrawProps } from "../types";
|
||||
import { close } from "./icons";
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
cursor: default;
|
||||
left: 50%;
|
||||
margin-left: -150px;
|
||||
padding: 4px 0;
|
||||
padding: 8px;
|
||||
position: absolute;
|
||||
text-align: center;
|
||||
width: 300px;
|
||||
|
||||
@@ -193,7 +193,7 @@
|
||||
margin-left: 5px;
|
||||
margin-top: 1px;
|
||||
|
||||
@include isMobile {
|
||||
@media #{$is-mobile-query} {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -101,8 +101,9 @@ export const TOUCH_CTX_MENU_TIMEOUT = 500;
|
||||
export const TITLE_TIMEOUT = 10000;
|
||||
export const TOAST_TIMEOUT = 5000;
|
||||
export const VERSION_TIMEOUT = 30000;
|
||||
export const AUTO_SAVE_TIMEOUT = 500;
|
||||
export const SCROLL_TIMEOUT = 100;
|
||||
export const DETECT_POSITION_CHANGE_INTERVAL = 500;
|
||||
|
||||
export const ZOOM_STEP = 0.1;
|
||||
|
||||
// Report a user inactive after IDLE_THRESHOLD milliseconds
|
||||
@@ -137,7 +138,3 @@ export const DEFAULT_UI_OPTIONS: AppProps["UIOptions"] = {
|
||||
theme: true,
|
||||
},
|
||||
};
|
||||
|
||||
export const MQ_MAX_WIDTH_PORTRAIT = 730;
|
||||
export const MQ_MAX_WIDTH_LANDSCAPE = 1000;
|
||||
export const MQ_MAX_HEIGHT_LANDSCAPE = 500;
|
||||
|
||||
@@ -480,7 +480,7 @@
|
||||
}
|
||||
}
|
||||
|
||||
@include isMobile {
|
||||
@media #{$is-mobile-query} {
|
||||
aside {
|
||||
display: none;
|
||||
}
|
||||
|
||||
@@ -1,13 +1,10 @@
|
||||
@import "open-color/open-color.scss";
|
||||
|
||||
@mixin isMobile() {
|
||||
@at-root .excalidraw--mobile#{&} {
|
||||
@content;
|
||||
}
|
||||
}
|
||||
|
||||
// keep up to date with is-mobile.tsx
|
||||
$is-mobile-query: "(max-width: 600px), (max-height: 500px) and (max-width: 1000px)";
|
||||
$theme-filter: "invert(93%) hue-rotate(180deg)";
|
||||
|
||||
:export {
|
||||
isMobileQuery: unquote($is-mobile-query);
|
||||
themeFilter: unquote($theme-filter);
|
||||
}
|
||||
|
||||
@@ -27,6 +27,7 @@ export const serializeAsJSON = (
|
||||
export const saveAsJSON = async (
|
||||
elements: readonly ExcalidrawElement[],
|
||||
appState: AppState,
|
||||
onlyIfFileHandleValid = false,
|
||||
) => {
|
||||
const serialized = serializeAsJSON(elements, appState);
|
||||
const blob = new Blob([serialized], {
|
||||
@@ -41,6 +42,7 @@ export const saveAsJSON = async (
|
||||
extensions: [".excalidraw"],
|
||||
},
|
||||
appState.fileHandle,
|
||||
onlyIfFileHandleValid,
|
||||
);
|
||||
return { fileHandle };
|
||||
};
|
||||
|
||||
@@ -32,13 +32,13 @@
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
@include isMobile {
|
||||
@media #{$is-mobile-query} {
|
||||
flex-direction: column;
|
||||
align-items: stretch;
|
||||
}
|
||||
}
|
||||
|
||||
@include isMobile {
|
||||
@media #{$is-mobile-query} {
|
||||
.RoomDialog-usernameLabel {
|
||||
font-weight: bold;
|
||||
}
|
||||
@@ -51,7 +51,7 @@
|
||||
min-width: 0;
|
||||
flex: 1 1 auto;
|
||||
margin-inline-start: 1em;
|
||||
@include isMobile {
|
||||
@media #{$is-mobile-query} {
|
||||
margin-top: 0.5em;
|
||||
margin-inline-start: 0;
|
||||
}
|
||||
|
||||
@@ -324,7 +324,6 @@ const ExcalidrawWrapper = () => {
|
||||
renderFooter={renderFooter}
|
||||
langCode={langCode}
|
||||
renderCustomStats={renderCustomStats}
|
||||
detectScroll={false}
|
||||
/>
|
||||
{excalidrawAPI && <CollabWrapper excalidrawAPI={excalidrawAPI} />}
|
||||
{errorMessage && (
|
||||
|
||||
37
src/is-mobile.tsx
Normal file
37
src/is-mobile.tsx
Normal file
@@ -0,0 +1,37 @@
|
||||
import React, { useState, useEffect, useRef, useContext } from "react";
|
||||
import variables from "./css/variables.module.scss";
|
||||
|
||||
const context = React.createContext(false);
|
||||
|
||||
const getIsMobileMatcher = () => {
|
||||
return window.matchMedia
|
||||
? window.matchMedia(variables.isMobileQuery)
|
||||
: (({
|
||||
matches: false,
|
||||
addListener: () => {},
|
||||
removeListener: () => {},
|
||||
} as any) as MediaQueryList);
|
||||
};
|
||||
|
||||
export const IsMobileProvider = ({
|
||||
children,
|
||||
}: {
|
||||
children: React.ReactNode;
|
||||
}) => {
|
||||
const query = useRef<MediaQueryList>();
|
||||
if (!query.current) {
|
||||
query.current = getIsMobileMatcher();
|
||||
}
|
||||
const [isMobile, setMobile] = useState(query.current.matches);
|
||||
|
||||
useEffect(() => {
|
||||
const handler = () => setMobile(query.current!.matches);
|
||||
query.current!.addListener(handler);
|
||||
return () => query.current!.removeListener(handler);
|
||||
}, []);
|
||||
|
||||
return <context.Provider value={isMobile}>{children}</context.Provider>;
|
||||
};
|
||||
|
||||
export const isMobile = () => getIsMobileMatcher().matches;
|
||||
export const useIsMobile = () => useContext(context);
|
||||
@@ -78,6 +78,8 @@
|
||||
"ungroup": "Ungroup selection",
|
||||
"collaborators": "Collaborators",
|
||||
"showGrid": "Show grid",
|
||||
"toggleAutosave": "Autosave to current file",
|
||||
"toggleAutosave_details": "Automatically save changes when working on an existing file.",
|
||||
"addToLibrary": "Add to library",
|
||||
"removeFromLibrary": "Remove from library",
|
||||
"libraryLoadingMessage": "Loading library…",
|
||||
@@ -249,6 +251,9 @@
|
||||
"width": "Width"
|
||||
},
|
||||
"toast": {
|
||||
"autosaveFailed_notAllowed": "Autosave was disabled.",
|
||||
"autosaveFailed_notFound": "Autosave failed.\nIt seems the file no longer exists.",
|
||||
"autosaveFailed": "Autosave failed.",
|
||||
"copyStyles": "Copied styles.",
|
||||
"copyToClipboard": "Copied to clipboard.",
|
||||
"copyToClipboardAsPng": "Copied {{exportSelection}} to clipboard as PNG\n({{exportColorScheme}})",
|
||||
|
||||
@@ -11,20 +11,6 @@ The change should be grouped under one of the below section and must contain PR
|
||||
Please add the latest change on the top under the correct section.
|
||||
-->
|
||||
|
||||
## Unreleased
|
||||
|
||||
## Excalidraw API
|
||||
|
||||
- Support detecting position of the component and recompute offsets when the position changes [#3428](https://github.com/excalidraw/excalidraw/pull/3428). Disabled by default. You can enable this by setting [`detectPosition`](https://github.com/excalidraw/excalidraw/blob/master/src/packages/excalidraw/README.md#detectPosition) to `true`.
|
||||
- Recompute offsets on `scroll` of the nearest scrollable container [#3408](https://github.com/excalidraw/excalidraw/pull/3408). This can be disabled by setting [`detectScroll`](https://github.com/excalidraw/excalidraw/blob/master/src/packages/excalidraw/README.md#detectScroll) to `false`.
|
||||
- Add `onPaste` prop to handle custom clipboard behaviours [#3420](https://github.com/excalidraw/excalidraw/pull/3420).
|
||||
|
||||
## Excalidraw Library
|
||||
|
||||
### Features
|
||||
|
||||
- App now breaks into mobile view using the component dimensions, not viewport dimensions. This fixes a case where the app would break sooner than necessary when the component's size is smaller than viewport [#3414](https://github.com/excalidraw/excalidraw/pull/3414).
|
||||
|
||||
## 0.6.0 (2021-04-04)
|
||||
|
||||
## Excalidraw API
|
||||
|
||||
@@ -364,9 +364,6 @@ To view the full example visit :point_down:
|
||||
| [`theme`](#theme) | `light` or `dark` | | The theme of the Excalidraw component |
|
||||
| [`name`](#name) | string | | Name of the drawing |
|
||||
| [`UIOptions`](#UIOptions) | <pre>{ canvasActions: <a href="https://github.com/excalidraw/excalidraw/blob/master/src/types.ts#L208"> CanvasActions<a/> }</pre> | [DEFAULT UI OPTIONS](https://github.com/excalidraw/excalidraw/blob/master/src/constants.ts#L129) | To customise UI options. Currently we support customising [`canvas actions`](#canvasActions) |
|
||||
| [`onPaste`](#onPaste) | <pre>(data: <a href="https://github.com/excalidraw/excalidraw/blob/master/src/clipboard.ts#L17">ClipboardData</a>, event: ClipboardEvent | null) => boolean</pre> | | Callback to be triggered if passed when the something is pasted in to the scene |
|
||||
| [`detectScroll`](#detectScroll) | boolean | true | Indicates whether to recompute the offsets when nearest ancestor is scrolled. |
|
||||
| [`detectPosition`](#detectPosition) | boolean | false | Indicates whether to recompute the offsets when position of the Excalidraw component is updated. |
|
||||
|
||||
### Dimensions of Excalidraw
|
||||
|
||||
@@ -442,8 +439,8 @@ You can pass a `ref` when you want to access some excalidraw APIs. We expose the
|
||||
| getAppState | <pre> () => <a href="https://github.com/excalidraw/excalidraw/blob/master/src/types.ts#L37">AppState</a></pre> | Returns current appState |
|
||||
| history | `{ clear: () => void }` | This is the history API. `history.clear()` will clear the history |
|
||||
| setScrollToContent | <pre> (<a href="https://github.com/excalidraw/excalidraw/blob/master/src/element/types.ts#L78">ExcalidrawElement[]</a>) => void </pre> | Scroll to the nearest element to center |
|
||||
| [`refresh`](#refresh) | `() => void` | Recomputes the offsets for the Excalidraw component. |
|
||||
| [`importLibrary`](#importlibrary) | `(url: string, token?: string) => void` | Imports library from given URL. |
|
||||
| refresh | `() => void` | Updates the offsets for the Excalidraw component so that the coordinates are computed correctly (for example the cursor position). You don't have to call this when the position is changed on page scroll or when the excalidraw container resizes (we handle that ourselves). For any other cases if the position of excalidraw is updated (example due to scroll on parent container and not page scroll) you should call this API. |
|
||||
| [importLibrary](#importlibrary) | `(url: string, token?: string) => void` | Imports library from given URL |
|
||||
| setToastMessage | `(message: string) => void` | This API can be used to show the toast with custom message. |
|
||||
|
||||
#### `readyPromise`
|
||||
@@ -531,7 +528,7 @@ This prop controls Excalidraw's theme. When supplied, the value takes precedence
|
||||
|
||||
This prop sets the name of the drawing which will be used when exporting the drawing. When supplied, the value takes precedence over `intialData.appState.name`, the `name` will be fully controlled by host app and the users won't be able to edit from within Excalidraw.
|
||||
|
||||
#### `UIOptions`
|
||||
### `UIOptions`
|
||||
|
||||
This prop can be used to customise UI of Excalidraw. Currently we support customising only [`canvasActions`](#canvasActions). It accepts the below parameters
|
||||
|
||||
@@ -539,7 +536,7 @@ This prop can be used to customise UI of Excalidraw. Currently we support custom
|
||||
{ canvasActions: <a href="https://github.com/excalidraw/excalidraw/blob/master/src/types.ts#L208"> CanvasActions<a/> }
|
||||
</pre>
|
||||
|
||||
##### canvasActions
|
||||
#### canvasActions
|
||||
|
||||
| Attribute | Type | Default | Description |
|
||||
| --- | --- | --- | --- |
|
||||
@@ -551,26 +548,10 @@ This prop can be used to customise UI of Excalidraw. Currently we support custom
|
||||
| `saveScene` | boolean | true | Implies whether to show `Save button` |
|
||||
| `theme` | boolean | true | Implies whether to show `Theme toggle` |
|
||||
|
||||
#### `onPaste`
|
||||
|
||||
This callback is triggered if passed when something is pasted into the scene. You can use this callback in case you want to do something additional when the paste event occurs.
|
||||
|
||||
<pre>
|
||||
(data: <a href="https://github.com/excalidraw/excalidraw/blob/master/src/clipboard.ts#L17">ClipboardData</a>, event: ClipboardEvent | null) => boolean
|
||||
</pre>
|
||||
|
||||
This callback must return a `boolean` value or a [promise](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/Promise) which resolves to a boolean value.
|
||||
|
||||
In case you want to prevent the excalidraw paste action you must return `true`, it will stop the native excalidraw clipboard management flow (nothing will be pasted into the scene).
|
||||
|
||||
### Does it support collaboration ?
|
||||
|
||||
No Excalidraw package doesn't come with collaboration, since this would have different implementations on the consumer so we expose the API's which you can use to communicate with Excalidraw as mentioned above. If you are interested in understanding how Excalidraw does it you can check it [here](https://github.com/excalidraw/excalidraw/blob/master/src/excalidraw-app/index.tsx).
|
||||
|
||||
### refresh
|
||||
|
||||
Recomputes the offsets for the Excalidraw component so that the coordinates are computed correctly (for example the cursor position). You don't have to call this when the position is changed due to scrolling on the nearest scrollable parent or when the excalidraw container resizes (we handle that ourselves). For any other cases if the position of excalidraw is updated (for example due to multiple scrolls or add / removal of elements in flex container) you can enable [`detectPosition`](#detectposition) or handle it manually by calling this API.
|
||||
|
||||
### importLibrary
|
||||
|
||||
Imports library from given URL. You should call this on `hashchange`, passing the `addLibrary` value if you detect it as shown below. Optionally pass a CSRF `token` to skip prompting during installation (retrievable via `token` key from the url coming from [https://libraries.excalidraw.com](https://libraries.excalidraw.com/)).
|
||||
@@ -593,18 +574,6 @@ useEffect(() => {
|
||||
|
||||
Try out the [Demo](#Demo) to see it in action.
|
||||
|
||||
### detectScroll
|
||||
|
||||
Indicates whether Excalidraw should listen for `scroll` event on the nearest scrollable container in the DOM tree and recompute the coordinates (e.g. to correctly handle the cursor) when the component's position changes. You can disable this when you either know this doesn't affect your app or you want to take care of it yourself (calling the [`refresh()`](#refresh) method).
|
||||
|
||||
### detectPosition
|
||||
|
||||
Indicates whether the coordinates should be recomputed (e.g. to correctly handle the cursor) when the component's position changes. This is disabled by default.
|
||||
|
||||
Resizing and handling nearest scrollable parent ([detectScroll](#detectScroll)) is already handled so if there is any other case where position gets updated is where you will want to enable this prop (eg multiple scroll containers, or position updating due to addition/removal of elements in flex container).
|
||||
|
||||
You might want to disable [detectScroll](#detectScroll) when you enable this prop.
|
||||
|
||||
### Extra API's
|
||||
|
||||
#### `getSceneVersion`
|
||||
|
||||
@@ -8,6 +8,7 @@ import "../../css/app.scss";
|
||||
import "../../css/styles.scss";
|
||||
|
||||
import { ExcalidrawAPIRefValue, ExcalidrawProps } from "../../types";
|
||||
import { IsMobileProvider } from "../../is-mobile";
|
||||
import { defaultLang } from "../../i18n";
|
||||
import { DEFAULT_UI_OPTIONS } from "../../constants";
|
||||
|
||||
@@ -29,9 +30,6 @@ const Excalidraw = (props: ExcalidrawProps) => {
|
||||
theme,
|
||||
name,
|
||||
renderCustomStats,
|
||||
onPaste,
|
||||
detectScroll = true,
|
||||
detectPosition = false,
|
||||
} = props;
|
||||
|
||||
const canvasActions = props.UIOptions?.canvasActions;
|
||||
@@ -63,28 +61,27 @@ const Excalidraw = (props: ExcalidrawProps) => {
|
||||
|
||||
return (
|
||||
<InitializeApp langCode={langCode}>
|
||||
<App
|
||||
onChange={onChange}
|
||||
initialData={initialData}
|
||||
excalidrawRef={excalidrawRef}
|
||||
onCollabButtonClick={onCollabButtonClick}
|
||||
isCollaborating={isCollaborating}
|
||||
onPointerUpdate={onPointerUpdate}
|
||||
onExportToBackend={onExportToBackend}
|
||||
renderFooter={renderFooter}
|
||||
langCode={langCode}
|
||||
viewModeEnabled={viewModeEnabled}
|
||||
zenModeEnabled={zenModeEnabled}
|
||||
gridModeEnabled={gridModeEnabled}
|
||||
libraryReturnUrl={libraryReturnUrl}
|
||||
theme={theme}
|
||||
name={name}
|
||||
renderCustomStats={renderCustomStats}
|
||||
UIOptions={UIOptions}
|
||||
onPaste={onPaste}
|
||||
detectScroll={detectScroll}
|
||||
detectPosition={detectPosition}
|
||||
/>
|
||||
<IsMobileProvider>
|
||||
<App
|
||||
onChange={onChange}
|
||||
initialData={initialData}
|
||||
excalidrawRef={excalidrawRef}
|
||||
onCollabButtonClick={onCollabButtonClick}
|
||||
isCollaborating={isCollaborating}
|
||||
onPointerUpdate={onPointerUpdate}
|
||||
onExportToBackend={onExportToBackend}
|
||||
renderFooter={renderFooter}
|
||||
langCode={langCode}
|
||||
viewModeEnabled={viewModeEnabled}
|
||||
zenModeEnabled={zenModeEnabled}
|
||||
gridModeEnabled={gridModeEnabled}
|
||||
libraryReturnUrl={libraryReturnUrl}
|
||||
theme={theme}
|
||||
name={name}
|
||||
renderCustomStats={renderCustomStats}
|
||||
UIOptions={UIOptions}
|
||||
/>
|
||||
</IsMobileProvider>
|
||||
</InitializeApp>
|
||||
);
|
||||
};
|
||||
@@ -106,6 +103,11 @@ const areEqual = (
|
||||
);
|
||||
};
|
||||
|
||||
Excalidraw.defaultProps = {
|
||||
lanCode: defaultLang.code,
|
||||
UIOptions: DEFAULT_UI_OPTIONS,
|
||||
};
|
||||
|
||||
const forwardedRefComp = forwardRef<
|
||||
ExcalidrawAPIRefValue,
|
||||
PublicExcalidrawProps
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
exports[`given element A and group of elements B and given both are selected when user clicks on B, on pointer up only elements from B should be selected: [end of test] appState 1`] = `
|
||||
Object {
|
||||
"autosave": false,
|
||||
"collaborators": Map {},
|
||||
"currentChartType": "bar",
|
||||
"currentItemBackgroundColor": "transparent",
|
||||
@@ -463,6 +464,7 @@ exports[`given element A and group of elements B and given both are selected whe
|
||||
|
||||
exports[`given element A and group of elements B and given both are selected when user shift-clicks on B, on pointer up only element A should be selected: [end of test] appState 1`] = `
|
||||
Object {
|
||||
"autosave": false,
|
||||
"collaborators": Map {},
|
||||
"currentChartType": "bar",
|
||||
"currentItemBackgroundColor": "transparent",
|
||||
@@ -930,6 +932,7 @@ exports[`given element A and group of elements B and given both are selected whe
|
||||
|
||||
exports[`regression tests Cmd/Ctrl-click exclusively select element under pointer: [end of test] appState 1`] = `
|
||||
Object {
|
||||
"autosave": false,
|
||||
"collaborators": Map {},
|
||||
"currentChartType": "bar",
|
||||
"currentItemBackgroundColor": "transparent",
|
||||
@@ -1706,6 +1709,7 @@ exports[`regression tests Cmd/Ctrl-click exclusively select element under pointe
|
||||
|
||||
exports[`regression tests Drags selected element when hitting only bounding box and keeps element selected: [end of test] appState 1`] = `
|
||||
Object {
|
||||
"autosave": false,
|
||||
"collaborators": Map {},
|
||||
"currentChartType": "bar",
|
||||
"currentItemBackgroundColor": "transparent",
|
||||
@@ -1910,6 +1914,7 @@ exports[`regression tests Drags selected element when hitting only bounding box
|
||||
|
||||
exports[`regression tests adjusts z order when grouping: [end of test] appState 1`] = `
|
||||
Object {
|
||||
"autosave": false,
|
||||
"collaborators": Map {},
|
||||
"currentChartType": "bar",
|
||||
"currentItemBackgroundColor": "transparent",
|
||||
@@ -2368,6 +2373,7 @@ exports[`regression tests adjusts z order when grouping: [end of test] number of
|
||||
|
||||
exports[`regression tests alt-drag duplicates an element: [end of test] appState 1`] = `
|
||||
Object {
|
||||
"autosave": false,
|
||||
"collaborators": Map {},
|
||||
"currentChartType": "bar",
|
||||
"currentItemBackgroundColor": "transparent",
|
||||
@@ -2621,6 +2627,7 @@ exports[`regression tests alt-drag duplicates an element: [end of test] number o
|
||||
|
||||
exports[`regression tests arrow keys: [end of test] appState 1`] = `
|
||||
Object {
|
||||
"autosave": false,
|
||||
"collaborators": Map {},
|
||||
"currentChartType": "bar",
|
||||
"currentItemBackgroundColor": "transparent",
|
||||
@@ -2785,6 +2792,7 @@ exports[`regression tests arrow keys: [end of test] number of renders 1`] = `20`
|
||||
|
||||
exports[`regression tests can drag element that covers another element, while another elem is selected: [end of test] appState 1`] = `
|
||||
Object {
|
||||
"autosave": false,
|
||||
"collaborators": Map {},
|
||||
"currentChartType": "bar",
|
||||
"currentItemBackgroundColor": "transparent",
|
||||
@@ -3262,6 +3270,7 @@ exports[`regression tests can drag element that covers another element, while an
|
||||
|
||||
exports[`regression tests change the properties of a shape: [end of test] appState 1`] = `
|
||||
Object {
|
||||
"autosave": false,
|
||||
"collaborators": Map {},
|
||||
"currentChartType": "bar",
|
||||
"currentItemBackgroundColor": "#fa5252",
|
||||
@@ -3498,6 +3507,7 @@ exports[`regression tests change the properties of a shape: [end of test] number
|
||||
|
||||
exports[`regression tests click on an element and drag it: [dragged] appState 1`] = `
|
||||
Object {
|
||||
"autosave": false,
|
||||
"collaborators": Map {},
|
||||
"currentChartType": "bar",
|
||||
"currentItemBackgroundColor": "transparent",
|
||||
@@ -3702,6 +3712,7 @@ exports[`regression tests click on an element and drag it: [dragged] number of r
|
||||
|
||||
exports[`regression tests click on an element and drag it: [end of test] appState 1`] = `
|
||||
Object {
|
||||
"autosave": false,
|
||||
"collaborators": Map {},
|
||||
"currentChartType": "bar",
|
||||
"currentItemBackgroundColor": "transparent",
|
||||
@@ -3946,6 +3957,7 @@ exports[`regression tests click on an element and drag it: [end of test] number
|
||||
|
||||
exports[`regression tests click to select a shape: [end of test] appState 1`] = `
|
||||
Object {
|
||||
"autosave": false,
|
||||
"collaborators": Map {},
|
||||
"currentChartType": "bar",
|
||||
"currentItemBackgroundColor": "transparent",
|
||||
@@ -4198,6 +4210,7 @@ exports[`regression tests click to select a shape: [end of test] number of rende
|
||||
|
||||
exports[`regression tests click-drag to select a group: [end of test] appState 1`] = `
|
||||
Object {
|
||||
"autosave": false,
|
||||
"collaborators": Map {},
|
||||
"currentChartType": "bar",
|
||||
"currentItemBackgroundColor": "transparent",
|
||||
@@ -4559,6 +4572,7 @@ exports[`regression tests click-drag to select a group: [end of test] number of
|
||||
|
||||
exports[`regression tests deselects group of selected elements on pointer down when pointer doesn't hit any element: [end of test] appState 1`] = `
|
||||
Object {
|
||||
"autosave": false,
|
||||
"collaborators": Map {},
|
||||
"currentChartType": "bar",
|
||||
"currentItemBackgroundColor": "transparent",
|
||||
@@ -4854,6 +4868,7 @@ exports[`regression tests deselects group of selected elements on pointer down w
|
||||
|
||||
exports[`regression tests deselects group of selected elements on pointer up when pointer hits common bounding box without hitting any element: [end of test] appState 1`] = `
|
||||
Object {
|
||||
"autosave": false,
|
||||
"collaborators": Map {},
|
||||
"currentChartType": "bar",
|
||||
"currentItemBackgroundColor": "transparent",
|
||||
@@ -5161,6 +5176,7 @@ exports[`regression tests deselects group of selected elements on pointer up whe
|
||||
|
||||
exports[`regression tests deselects selected element on pointer down when pointer doesn't hit any element: [end of test] appState 1`] = `
|
||||
Object {
|
||||
"autosave": false,
|
||||
"collaborators": Map {},
|
||||
"currentChartType": "bar",
|
||||
"currentItemBackgroundColor": "transparent",
|
||||
@@ -5369,6 +5385,7 @@ exports[`regression tests deselects selected element on pointer down when pointe
|
||||
|
||||
exports[`regression tests deselects selected element, on pointer up, when click hits element bounding box but doesn't hit the element: [end of test] appState 1`] = `
|
||||
Object {
|
||||
"autosave": false,
|
||||
"collaborators": Map {},
|
||||
"currentChartType": "bar",
|
||||
"currentItemBackgroundColor": "transparent",
|
||||
@@ -5555,6 +5572,7 @@ exports[`regression tests deselects selected element, on pointer up, when click
|
||||
|
||||
exports[`regression tests double click to edit a group: [end of test] appState 1`] = `
|
||||
Object {
|
||||
"autosave": false,
|
||||
"collaborators": Map {},
|
||||
"currentChartType": "bar",
|
||||
"currentItemBackgroundColor": "transparent",
|
||||
@@ -6008,6 +6026,7 @@ exports[`regression tests double click to edit a group: [end of test] number of
|
||||
|
||||
exports[`regression tests drags selected elements from point inside common bounding box that doesn't hit any element and keeps elements selected after dragging: [end of test] appState 1`] = `
|
||||
Object {
|
||||
"autosave": false,
|
||||
"collaborators": Map {},
|
||||
"currentChartType": "bar",
|
||||
"currentItemBackgroundColor": "transparent",
|
||||
@@ -6326,6 +6345,7 @@ exports[`regression tests drags selected elements from point inside common bound
|
||||
|
||||
exports[`regression tests draw every type of shape: [end of test] appState 1`] = `
|
||||
Object {
|
||||
"autosave": false,
|
||||
"collaborators": Map {},
|
||||
"currentChartType": "bar",
|
||||
"currentItemBackgroundColor": "transparent",
|
||||
@@ -8360,6 +8380,7 @@ exports[`regression tests draw every type of shape: [end of test] number of rend
|
||||
|
||||
exports[`regression tests given a group of selected elements with an element that is not selected inside the group common bounding box when element that is not selected is clicked should switch selection to not selected element on pointer up: [end of test] appState 1`] = `
|
||||
Object {
|
||||
"autosave": false,
|
||||
"collaborators": Map {},
|
||||
"currentChartType": "bar",
|
||||
"currentItemBackgroundColor": "transparent",
|
||||
@@ -8722,6 +8743,7 @@ exports[`regression tests given a group of selected elements with an element tha
|
||||
|
||||
exports[`regression tests given a selected element A and a not selected element B with higher z-index than A and given B partialy overlaps A when there's a shift-click on the overlapped section B is added to the selection: [end of test] appState 1`] = `
|
||||
Object {
|
||||
"autosave": false,
|
||||
"collaborators": Map {},
|
||||
"currentChartType": "bar",
|
||||
"currentItemBackgroundColor": "#fa5252",
|
||||
@@ -8977,6 +8999,7 @@ exports[`regression tests given a selected element A and a not selected element
|
||||
|
||||
exports[`regression tests given selected element A with lower z-index than unselected element B and given B is partially over A when clicking intersection between A and B B should be selected on pointer up: [end of test] appState 1`] = `
|
||||
Object {
|
||||
"autosave": false,
|
||||
"collaborators": Map {},
|
||||
"currentChartType": "bar",
|
||||
"currentItemBackgroundColor": "#fa5252",
|
||||
@@ -9230,6 +9253,7 @@ exports[`regression tests given selected element A with lower z-index than unsel
|
||||
|
||||
exports[`regression tests given selected element A with lower z-index than unselected element B and given B is partially over A when dragging on intersection between A and B A should be dragged and keep being selected: [end of test] appState 1`] = `
|
||||
Object {
|
||||
"autosave": false,
|
||||
"collaborators": Map {},
|
||||
"currentChartType": "bar",
|
||||
"currentItemBackgroundColor": "#fa5252",
|
||||
@@ -9545,6 +9569,7 @@ exports[`regression tests given selected element A with lower z-index than unsel
|
||||
|
||||
exports[`regression tests key 2 selects rectangle tool: [end of test] appState 1`] = `
|
||||
Object {
|
||||
"autosave": false,
|
||||
"collaborators": Map {},
|
||||
"currentChartType": "bar",
|
||||
"currentItemBackgroundColor": "transparent",
|
||||
@@ -9709,6 +9734,7 @@ exports[`regression tests key 2 selects rectangle tool: [end of test] number of
|
||||
|
||||
exports[`regression tests key 3 selects diamond tool: [end of test] appState 1`] = `
|
||||
Object {
|
||||
"autosave": false,
|
||||
"collaborators": Map {},
|
||||
"currentChartType": "bar",
|
||||
"currentItemBackgroundColor": "transparent",
|
||||
@@ -9873,6 +9899,7 @@ exports[`regression tests key 3 selects diamond tool: [end of test] number of re
|
||||
|
||||
exports[`regression tests key 4 selects ellipse tool: [end of test] appState 1`] = `
|
||||
Object {
|
||||
"autosave": false,
|
||||
"collaborators": Map {},
|
||||
"currentChartType": "bar",
|
||||
"currentItemBackgroundColor": "transparent",
|
||||
@@ -10037,6 +10064,7 @@ exports[`regression tests key 4 selects ellipse tool: [end of test] number of re
|
||||
|
||||
exports[`regression tests key 5 selects arrow tool: [end of test] appState 1`] = `
|
||||
Object {
|
||||
"autosave": false,
|
||||
"collaborators": Map {},
|
||||
"currentChartType": "bar",
|
||||
"currentItemBackgroundColor": "transparent",
|
||||
@@ -10231,6 +10259,7 @@ exports[`regression tests key 5 selects arrow tool: [end of test] number of rend
|
||||
|
||||
exports[`regression tests key 6 selects line tool: [end of test] appState 1`] = `
|
||||
Object {
|
||||
"autosave": false,
|
||||
"collaborators": Map {},
|
||||
"currentChartType": "bar",
|
||||
"currentItemBackgroundColor": "transparent",
|
||||
@@ -10425,6 +10454,7 @@ exports[`regression tests key 6 selects line tool: [end of test] number of rende
|
||||
|
||||
exports[`regression tests key 7 selects draw tool: [end of test] appState 1`] = `
|
||||
Object {
|
||||
"autosave": false,
|
||||
"collaborators": Map {},
|
||||
"currentChartType": "bar",
|
||||
"currentItemBackgroundColor": "transparent",
|
||||
@@ -10619,6 +10649,7 @@ exports[`regression tests key 7 selects draw tool: [end of test] number of rende
|
||||
|
||||
exports[`regression tests key a selects arrow tool: [end of test] appState 1`] = `
|
||||
Object {
|
||||
"autosave": false,
|
||||
"collaborators": Map {},
|
||||
"currentChartType": "bar",
|
||||
"currentItemBackgroundColor": "transparent",
|
||||
@@ -10813,6 +10844,7 @@ exports[`regression tests key a selects arrow tool: [end of test] number of rend
|
||||
|
||||
exports[`regression tests key d selects diamond tool: [end of test] appState 1`] = `
|
||||
Object {
|
||||
"autosave": false,
|
||||
"collaborators": Map {},
|
||||
"currentChartType": "bar",
|
||||
"currentItemBackgroundColor": "transparent",
|
||||
@@ -10977,6 +11009,7 @@ exports[`regression tests key d selects diamond tool: [end of test] number of re
|
||||
|
||||
exports[`regression tests key e selects ellipse tool: [end of test] appState 1`] = `
|
||||
Object {
|
||||
"autosave": false,
|
||||
"collaborators": Map {},
|
||||
"currentChartType": "bar",
|
||||
"currentItemBackgroundColor": "transparent",
|
||||
@@ -11141,6 +11174,7 @@ exports[`regression tests key e selects ellipse tool: [end of test] number of re
|
||||
|
||||
exports[`regression tests key l selects line tool: [end of test] appState 1`] = `
|
||||
Object {
|
||||
"autosave": false,
|
||||
"collaborators": Map {},
|
||||
"currentChartType": "bar",
|
||||
"currentItemBackgroundColor": "transparent",
|
||||
@@ -11335,6 +11369,7 @@ exports[`regression tests key l selects line tool: [end of test] number of rende
|
||||
|
||||
exports[`regression tests key r selects rectangle tool: [end of test] appState 1`] = `
|
||||
Object {
|
||||
"autosave": false,
|
||||
"collaborators": Map {},
|
||||
"currentChartType": "bar",
|
||||
"currentItemBackgroundColor": "transparent",
|
||||
@@ -11499,6 +11534,7 @@ exports[`regression tests key r selects rectangle tool: [end of test] number of
|
||||
|
||||
exports[`regression tests key x selects draw tool: [end of test] appState 1`] = `
|
||||
Object {
|
||||
"autosave": false,
|
||||
"collaborators": Map {},
|
||||
"currentChartType": "bar",
|
||||
"currentItemBackgroundColor": "transparent",
|
||||
@@ -11693,6 +11729,7 @@ exports[`regression tests key x selects draw tool: [end of test] number of rende
|
||||
|
||||
exports[`regression tests make a group and duplicate it: [end of test] appState 1`] = `
|
||||
Object {
|
||||
"autosave": false,
|
||||
"collaborators": Map {},
|
||||
"currentChartType": "bar",
|
||||
"currentItemBackgroundColor": "transparent",
|
||||
@@ -12409,6 +12446,7 @@ exports[`regression tests make a group and duplicate it: [end of test] number of
|
||||
|
||||
exports[`regression tests noop interaction after undo shouldn't create history entry: [end of test] appState 1`] = `
|
||||
Object {
|
||||
"autosave": false,
|
||||
"collaborators": Map {},
|
||||
"currentChartType": "bar",
|
||||
"currentItemBackgroundColor": "transparent",
|
||||
@@ -12662,6 +12700,7 @@ exports[`regression tests noop interaction after undo shouldn't create history e
|
||||
|
||||
exports[`regression tests pinch-to-zoom works: [end of test] appState 1`] = `
|
||||
Object {
|
||||
"autosave": false,
|
||||
"collaborators": Map {},
|
||||
"currentChartType": "bar",
|
||||
"currentItemBackgroundColor": "transparent",
|
||||
@@ -12764,6 +12803,7 @@ exports[`regression tests pinch-to-zoom works: [end of test] number of renders 1
|
||||
|
||||
exports[`regression tests rerenders UI on language change: [end of test] appState 1`] = `
|
||||
Object {
|
||||
"autosave": false,
|
||||
"collaborators": Map {},
|
||||
"currentChartType": "bar",
|
||||
"currentItemBackgroundColor": "transparent",
|
||||
@@ -12864,6 +12904,7 @@ exports[`regression tests rerenders UI on language change: [end of test] number
|
||||
|
||||
exports[`regression tests shift click on selected element should deselect it on pointer up: [end of test] appState 1`] = `
|
||||
Object {
|
||||
"autosave": false,
|
||||
"collaborators": Map {},
|
||||
"currentChartType": "bar",
|
||||
"currentItemBackgroundColor": "transparent",
|
||||
@@ -13031,6 +13072,7 @@ exports[`regression tests shift click on selected element should deselect it on
|
||||
|
||||
exports[`regression tests shift-click to multiselect, then drag: [end of test] appState 1`] = `
|
||||
Object {
|
||||
"autosave": false,
|
||||
"collaborators": Map {},
|
||||
"currentChartType": "bar",
|
||||
"currentItemBackgroundColor": "transparent",
|
||||
@@ -13352,6 +13394,7 @@ exports[`regression tests shift-click to multiselect, then drag: [end of test] n
|
||||
|
||||
exports[`regression tests should show fill icons when element has non transparent background: [end of test] appState 1`] = `
|
||||
Object {
|
||||
"autosave": false,
|
||||
"collaborators": Map {},
|
||||
"currentChartType": "bar",
|
||||
"currentItemBackgroundColor": "#fa5252",
|
||||
@@ -13555,6 +13598,7 @@ exports[`regression tests should show fill icons when element has non transparen
|
||||
|
||||
exports[`regression tests single-clicking on a subgroup of a selected group should not alter selection: [end of test] appState 1`] = `
|
||||
Object {
|
||||
"autosave": false,
|
||||
"collaborators": Map {},
|
||||
"currentChartType": "bar",
|
||||
"currentItemBackgroundColor": "transparent",
|
||||
@@ -14376,6 +14420,7 @@ exports[`regression tests single-clicking on a subgroup of a selected group shou
|
||||
|
||||
exports[`regression tests spacebar + drag scrolls the canvas: [end of test] appState 1`] = `
|
||||
Object {
|
||||
"autosave": false,
|
||||
"collaborators": Map {},
|
||||
"currentChartType": "bar",
|
||||
"currentItemBackgroundColor": "transparent",
|
||||
@@ -14476,6 +14521,7 @@ exports[`regression tests spacebar + drag scrolls the canvas: [end of test] numb
|
||||
|
||||
exports[`regression tests supports nested groups: [end of test] appState 1`] = `
|
||||
Object {
|
||||
"autosave": false,
|
||||
"collaborators": Map {},
|
||||
"currentChartType": "bar",
|
||||
"currentItemBackgroundColor": "transparent",
|
||||
@@ -15208,6 +15254,7 @@ exports[`regression tests supports nested groups: [end of test] number of render
|
||||
|
||||
exports[`regression tests switches from group of selected elements to another element on pointer down: [end of test] appState 1`] = `
|
||||
Object {
|
||||
"autosave": false,
|
||||
"collaborators": Map {},
|
||||
"currentChartType": "bar",
|
||||
"currentItemBackgroundColor": "transparent",
|
||||
@@ -15613,6 +15660,7 @@ exports[`regression tests switches from group of selected elements to another el
|
||||
|
||||
exports[`regression tests switches selected element on pointer down: [end of test] appState 1`] = `
|
||||
Object {
|
||||
"autosave": false,
|
||||
"collaborators": Map {},
|
||||
"currentChartType": "bar",
|
||||
"currentItemBackgroundColor": "transparent",
|
||||
@@ -15908,6 +15956,7 @@ exports[`regression tests switches selected element on pointer down: [end of tes
|
||||
|
||||
exports[`regression tests two-finger scroll works: [end of test] appState 1`] = `
|
||||
Object {
|
||||
"autosave": false,
|
||||
"collaborators": Map {},
|
||||
"currentChartType": "bar",
|
||||
"currentItemBackgroundColor": "transparent",
|
||||
@@ -16010,6 +16059,7 @@ exports[`regression tests two-finger scroll works: [end of test] number of rende
|
||||
|
||||
exports[`regression tests undo/redo drawing an element: [end of test] appState 1`] = `
|
||||
Object {
|
||||
"autosave": false,
|
||||
"collaborators": Map {},
|
||||
"currentChartType": "bar",
|
||||
"currentItemBackgroundColor": "transparent",
|
||||
@@ -16508,6 +16558,7 @@ exports[`regression tests undo/redo drawing an element: [end of test] number of
|
||||
|
||||
exports[`regression tests updates fontSize & fontFamily appState: [end of test] appState 1`] = `
|
||||
Object {
|
||||
"autosave": false,
|
||||
"collaborators": Map {},
|
||||
"currentChartType": "bar",
|
||||
"currentItemBackgroundColor": "transparent",
|
||||
@@ -16608,6 +16659,7 @@ exports[`regression tests updates fontSize & fontFamily appState: [end of test]
|
||||
|
||||
exports[`regression tests zoom hotkeys: [end of test] appState 1`] = `
|
||||
Object {
|
||||
"autosave": false,
|
||||
"collaborators": Map {},
|
||||
"currentChartType": "bar",
|
||||
"currentItemBackgroundColor": "transparent",
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
exports[`exportToSvg with default arguments 1`] = `
|
||||
Object {
|
||||
"autosave": false,
|
||||
"collaborators": Map {},
|
||||
"currentChartType": "bar",
|
||||
"currentItemBackgroundColor": "transparent",
|
||||
|
||||
10
src/types.ts
10
src/types.ts
@@ -20,7 +20,6 @@ import { ExcalidrawImperativeAPI } from "./components/App";
|
||||
import type { ResolvablePromise } from "./utils";
|
||||
import { Spreadsheet } from "./charts";
|
||||
import { Language } from "./i18n";
|
||||
import { ClipboardData } from "./clipboard";
|
||||
|
||||
export type Point = Readonly<RoughPoint>;
|
||||
|
||||
@@ -40,6 +39,7 @@ export type Collaborator = {
|
||||
};
|
||||
|
||||
export type AppState = {
|
||||
autosave: boolean;
|
||||
isLoading: boolean;
|
||||
errorMessage: string | null;
|
||||
draggingElement: NonDeletedExcalidrawElement | null;
|
||||
@@ -178,10 +178,6 @@ export interface ExcalidrawProps {
|
||||
appState: AppState,
|
||||
canvas: HTMLCanvasElement | null,
|
||||
) => void;
|
||||
onPaste?: (
|
||||
data: ClipboardData,
|
||||
event: ClipboardEvent | null,
|
||||
) => Promise<boolean> | boolean;
|
||||
renderFooter?: (isMobile: boolean) => JSX.Element;
|
||||
langCode?: Language["code"];
|
||||
viewModeEnabled?: boolean;
|
||||
@@ -195,8 +191,6 @@ export interface ExcalidrawProps {
|
||||
appState: AppState,
|
||||
) => JSX.Element;
|
||||
UIOptions?: UIOptions;
|
||||
detectScroll?: boolean;
|
||||
detectPosition?: boolean;
|
||||
}
|
||||
|
||||
export type SceneData = {
|
||||
@@ -230,6 +224,4 @@ export type AppProps = ExcalidrawProps & {
|
||||
UIOptions: {
|
||||
canvasActions: Required<CanvasActions>;
|
||||
};
|
||||
detectScroll: boolean;
|
||||
detectPosition: boolean;
|
||||
};
|
||||
|
||||
21
src/utils.ts
21
src/utils.ts
@@ -406,24 +406,3 @@ export const supportsEmoji = () => {
|
||||
ctx.fillText("😀", 0, 0);
|
||||
return ctx.getImageData(offset, offset, 1, 1).data[0] !== 0;
|
||||
};
|
||||
|
||||
export const getNearestScrollableContainer = (
|
||||
element: HTMLElement,
|
||||
): HTMLElement | Document => {
|
||||
let parent = element.parentElement;
|
||||
while (parent) {
|
||||
if (parent === document.body) {
|
||||
return document;
|
||||
}
|
||||
const { overflowY } = window.getComputedStyle(parent);
|
||||
const hasScrollableContent = parent.scrollHeight > parent.clientHeight;
|
||||
if (
|
||||
hasScrollableContent &&
|
||||
(overflowY === "auto" || overflowY === "scroll")
|
||||
) {
|
||||
return parent;
|
||||
}
|
||||
parent = parent.parentElement;
|
||||
}
|
||||
return document;
|
||||
};
|
||||
|
||||
397
yarn.lock
397
yarn.lock
@@ -1088,33 +1088,31 @@
|
||||
version "0.4.0"
|
||||
resolved "https://registry.npmjs.org/@firebase/analytics-types/-/analytics-types-0.4.0.tgz"
|
||||
|
||||
"@firebase/analytics@0.6.7":
|
||||
version "0.6.7"
|
||||
resolved "https://registry.yarnpkg.com/@firebase/analytics/-/analytics-0.6.7.tgz#9c6d3fc478555829e43ecd7fb4dd4884ad1b9c7d"
|
||||
integrity sha512-ObnFDewIqiamvU7UKDx+0jfLrD3LyqEIsXZdjnGQhY/xc10HFH0jp23lOzb39CWf/399X+xMMJ3Uj51VyHwbJQ==
|
||||
"@firebase/analytics@0.6.4":
|
||||
version "0.6.4"
|
||||
resolved "https://registry.npmjs.org/@firebase/analytics/-/analytics-0.6.4.tgz"
|
||||
dependencies:
|
||||
"@firebase/analytics-types" "0.4.0"
|
||||
"@firebase/component" "0.3.1"
|
||||
"@firebase/installations" "0.4.23"
|
||||
"@firebase/component" "0.2.0"
|
||||
"@firebase/installations" "0.4.20"
|
||||
"@firebase/logger" "0.2.6"
|
||||
"@firebase/util" "0.4.1"
|
||||
tslib "^2.1.0"
|
||||
"@firebase/util" "0.3.4"
|
||||
tslib "^1.11.1"
|
||||
|
||||
"@firebase/app-types@0.6.1":
|
||||
version "0.6.1"
|
||||
resolved "https://registry.npmjs.org/@firebase/app-types/-/app-types-0.6.1.tgz"
|
||||
|
||||
"@firebase/app@0.6.18":
|
||||
version "0.6.18"
|
||||
resolved "https://registry.yarnpkg.com/@firebase/app/-/app-0.6.18.tgz#68df65fee9929d5ace7a25fcd522888c0858bb2b"
|
||||
integrity sha512-eBThPc4QGHy/FC+oHZsnp4Qk6oksYTZ10B4jXaVH1lCS5eUSKvV1TIzAtpkPzMp2huS/qBz411r1tkQUv5vKcw==
|
||||
"@firebase/app@0.6.15":
|
||||
version "0.6.15"
|
||||
resolved "https://registry.npmjs.org/@firebase/app/-/app-0.6.15.tgz"
|
||||
dependencies:
|
||||
"@firebase/app-types" "0.6.1"
|
||||
"@firebase/component" "0.3.1"
|
||||
"@firebase/component" "0.2.0"
|
||||
"@firebase/logger" "0.2.6"
|
||||
"@firebase/util" "0.4.1"
|
||||
"@firebase/util" "0.3.4"
|
||||
dom-storage "2.1.0"
|
||||
tslib "^2.1.0"
|
||||
tslib "^1.11.1"
|
||||
xmlhttprequest "1.8.0"
|
||||
|
||||
"@firebase/auth-interop-types@0.1.5":
|
||||
@@ -1131,13 +1129,12 @@
|
||||
dependencies:
|
||||
"@firebase/auth-types" "0.10.2"
|
||||
|
||||
"@firebase/component@0.3.1":
|
||||
version "0.3.1"
|
||||
resolved "https://registry.yarnpkg.com/@firebase/component/-/component-0.3.1.tgz#91e32bd4426ad10f6bbe86b178780e8715171986"
|
||||
integrity sha512-8ACaB772bWwZRE47aVEYzld+jlDPgvHnLZoiVtG6BzygonVnKzwXo0wK6wcRzCbx4kun7G/gXYM0gUMkqvKtRA==
|
||||
"@firebase/component@0.2.0":
|
||||
version "0.2.0"
|
||||
resolved "https://registry.npmjs.org/@firebase/component/-/component-0.2.0.tgz"
|
||||
dependencies:
|
||||
"@firebase/util" "0.4.1"
|
||||
tslib "^2.1.0"
|
||||
"@firebase/util" "0.3.4"
|
||||
tslib "^1.11.1"
|
||||
|
||||
"@firebase/database-types@0.7.0":
|
||||
version "0.7.0"
|
||||
@@ -1145,68 +1142,63 @@
|
||||
dependencies:
|
||||
"@firebase/app-types" "0.6.1"
|
||||
|
||||
"@firebase/database@0.9.7":
|
||||
version "0.9.7"
|
||||
resolved "https://registry.yarnpkg.com/@firebase/database/-/database-0.9.7.tgz#42a03c18cd705e95ad2c8fcc739616eecb8e1dfa"
|
||||
integrity sha512-JUm6CnUxFRuyWvzTAzv/Mo/KYwLtUezpNGa4AzbhbdS8t3ewprc/7ARFErpv95cIM5MgiiPcLOC5F+mLDmrQwA==
|
||||
"@firebase/database@0.9.4":
|
||||
version "0.9.4"
|
||||
resolved "https://registry.npmjs.org/@firebase/database/-/database-0.9.4.tgz"
|
||||
dependencies:
|
||||
"@firebase/auth-interop-types" "0.1.5"
|
||||
"@firebase/component" "0.3.1"
|
||||
"@firebase/component" "0.2.0"
|
||||
"@firebase/database-types" "0.7.0"
|
||||
"@firebase/logger" "0.2.6"
|
||||
"@firebase/util" "0.4.1"
|
||||
"@firebase/util" "0.3.4"
|
||||
faye-websocket "0.11.3"
|
||||
tslib "^2.1.0"
|
||||
tslib "^1.11.1"
|
||||
|
||||
"@firebase/firestore-types@2.2.0":
|
||||
version "2.2.0"
|
||||
resolved "https://registry.yarnpkg.com/@firebase/firestore-types/-/firestore-types-2.2.0.tgz#9a3f3f2906232c3b4a726d988a6ef077f35f9093"
|
||||
integrity sha512-5kZZtQ32FIRJP1029dw+ZVNRCclKOErHv1+Xn0pw/5Fq3dxroA/ZyFHqDu+uV52AyWHhNLjCqX43ibm4YqOzRw==
|
||||
"@firebase/firestore-types@2.1.0":
|
||||
version "2.1.0"
|
||||
resolved "https://registry.npmjs.org/@firebase/firestore-types/-/firestore-types-2.1.0.tgz"
|
||||
|
||||
"@firebase/firestore@2.2.2":
|
||||
version "2.2.2"
|
||||
resolved "https://registry.yarnpkg.com/@firebase/firestore/-/firestore-2.2.2.tgz#7f4fb103600c983d762748f658d7bead20827584"
|
||||
integrity sha512-tFB0gRZcYQ8y9WBO5cSCij8pspF4vv2NdUkG8qWKG9cx2ccXnjo3qiQWRkoLuJGPaicCOGt11c08KvNSy/zfDA==
|
||||
"@firebase/firestore@2.1.7":
|
||||
version "2.1.7"
|
||||
resolved "https://registry.npmjs.org/@firebase/firestore/-/firestore-2.1.7.tgz"
|
||||
dependencies:
|
||||
"@firebase/component" "0.3.1"
|
||||
"@firebase/firestore-types" "2.2.0"
|
||||
"@firebase/component" "0.2.0"
|
||||
"@firebase/firestore-types" "2.1.0"
|
||||
"@firebase/logger" "0.2.6"
|
||||
"@firebase/util" "0.4.1"
|
||||
"@firebase/util" "0.3.4"
|
||||
"@firebase/webchannel-wrapper" "0.4.1"
|
||||
"@grpc/grpc-js" "^1.0.0"
|
||||
"@grpc/proto-loader" "^0.5.0"
|
||||
node-fetch "2.6.1"
|
||||
tslib "^2.1.0"
|
||||
tslib "^1.11.1"
|
||||
|
||||
"@firebase/functions-types@0.4.0":
|
||||
version "0.4.0"
|
||||
resolved "https://registry.npmjs.org/@firebase/functions-types/-/functions-types-0.4.0.tgz"
|
||||
|
||||
"@firebase/functions@0.6.5":
|
||||
version "0.6.5"
|
||||
resolved "https://registry.yarnpkg.com/@firebase/functions/-/functions-0.6.5.tgz#2302dff2ffe4257a61ab1b810166284d8d63906d"
|
||||
integrity sha512-8T/BKscHJhzQ7cM9Kn2Hcs8mkA1Zypzvo4b0mue7hRm6W/vzDMsgTiAUk7j7H1HEEf1Saw58h2tlQBg2rdDHPQ==
|
||||
"@firebase/functions@0.6.2":
|
||||
version "0.6.2"
|
||||
resolved "https://registry.npmjs.org/@firebase/functions/-/functions-0.6.2.tgz"
|
||||
dependencies:
|
||||
"@firebase/component" "0.3.1"
|
||||
"@firebase/component" "0.2.0"
|
||||
"@firebase/functions-types" "0.4.0"
|
||||
"@firebase/messaging-types" "0.5.0"
|
||||
node-fetch "2.6.1"
|
||||
tslib "^2.1.0"
|
||||
tslib "^1.11.1"
|
||||
|
||||
"@firebase/installations-types@0.3.4":
|
||||
version "0.3.4"
|
||||
resolved "https://registry.npmjs.org/@firebase/installations-types/-/installations-types-0.3.4.tgz"
|
||||
|
||||
"@firebase/installations@0.4.23":
|
||||
version "0.4.23"
|
||||
resolved "https://registry.yarnpkg.com/@firebase/installations/-/installations-0.4.23.tgz#e1013f52d6b8cc1ce2faebb0e2474a5fee33e0de"
|
||||
integrity sha512-vULPhK0DbDcXL0utJ8Td8+x5ArpUjSbCarz5ttR+u3Xsn1sEC6EX2Tlmua6csqNnBU/VpMo1bopWOvCVyX9jYA==
|
||||
"@firebase/installations@0.4.20":
|
||||
version "0.4.20"
|
||||
resolved "https://registry.npmjs.org/@firebase/installations/-/installations-0.4.20.tgz"
|
||||
dependencies:
|
||||
"@firebase/component" "0.3.1"
|
||||
"@firebase/component" "0.2.0"
|
||||
"@firebase/installations-types" "0.3.4"
|
||||
"@firebase/util" "0.4.1"
|
||||
"@firebase/util" "0.3.4"
|
||||
idb "3.0.2"
|
||||
tslib "^2.1.0"
|
||||
tslib "^1.11.1"
|
||||
|
||||
"@firebase/logger@0.2.6":
|
||||
version "0.2.6"
|
||||
@@ -1216,33 +1208,31 @@
|
||||
version "0.5.0"
|
||||
resolved "https://registry.npmjs.org/@firebase/messaging-types/-/messaging-types-0.5.0.tgz"
|
||||
|
||||
"@firebase/messaging@0.7.7":
|
||||
version "0.7.7"
|
||||
resolved "https://registry.yarnpkg.com/@firebase/messaging/-/messaging-0.7.7.tgz#ef9e1258f05dd80981b8a1b170352efe28936d0b"
|
||||
integrity sha512-osS61riot7Kg3YPuQWGqxOHos+IXOrTvTdchFOU/HVxenwmXteOpepEeNC3PZvudnYSKoI/w6voo5+E5yUyftw==
|
||||
"@firebase/messaging@0.7.4":
|
||||
version "0.7.4"
|
||||
resolved "https://registry.npmjs.org/@firebase/messaging/-/messaging-0.7.4.tgz"
|
||||
dependencies:
|
||||
"@firebase/component" "0.3.1"
|
||||
"@firebase/installations" "0.4.23"
|
||||
"@firebase/component" "0.2.0"
|
||||
"@firebase/installations" "0.4.20"
|
||||
"@firebase/messaging-types" "0.5.0"
|
||||
"@firebase/util" "0.4.1"
|
||||
"@firebase/util" "0.3.4"
|
||||
idb "3.0.2"
|
||||
tslib "^2.1.0"
|
||||
tslib "^1.11.1"
|
||||
|
||||
"@firebase/performance-types@0.0.13":
|
||||
version "0.0.13"
|
||||
resolved "https://registry.npmjs.org/@firebase/performance-types/-/performance-types-0.0.13.tgz"
|
||||
|
||||
"@firebase/performance@0.4.9":
|
||||
version "0.4.9"
|
||||
resolved "https://registry.yarnpkg.com/@firebase/performance/-/performance-0.4.9.tgz#f25306b81c9887a223b100ac308454c8f6036a46"
|
||||
integrity sha512-2BozmCAbvL4iFZwHE+9xSrdl3sJeF1/l8X2Ci4n8n+vwZjQbhq5pHPSZXLVT78i23V3XM14eS4SUJVqNL/QkRw==
|
||||
"@firebase/performance@0.4.6":
|
||||
version "0.4.6"
|
||||
resolved "https://registry.npmjs.org/@firebase/performance/-/performance-0.4.6.tgz"
|
||||
dependencies:
|
||||
"@firebase/component" "0.3.1"
|
||||
"@firebase/installations" "0.4.23"
|
||||
"@firebase/component" "0.2.0"
|
||||
"@firebase/installations" "0.4.20"
|
||||
"@firebase/logger" "0.2.6"
|
||||
"@firebase/performance-types" "0.0.13"
|
||||
"@firebase/util" "0.4.1"
|
||||
tslib "^2.1.0"
|
||||
"@firebase/util" "0.3.4"
|
||||
tslib "^1.11.1"
|
||||
|
||||
"@firebase/polyfill@0.3.36":
|
||||
version "0.3.36"
|
||||
@@ -1256,38 +1246,35 @@
|
||||
version "0.1.9"
|
||||
resolved "https://registry.npmjs.org/@firebase/remote-config-types/-/remote-config-types-0.1.9.tgz"
|
||||
|
||||
"@firebase/remote-config@0.1.34":
|
||||
version "0.1.34"
|
||||
resolved "https://registry.yarnpkg.com/@firebase/remote-config/-/remote-config-0.1.34.tgz#3156dd2d3e94ae047aff206f0933cb529505f965"
|
||||
integrity sha512-4dXdRjwuTH8lckmF8bPYCq0P/fM3NLV9QAF98Anft7f/0ZZNAucyQpvlK8KP7IRBZcllXq1Rla4THCNFtrLLOA==
|
||||
"@firebase/remote-config@0.1.31":
|
||||
version "0.1.31"
|
||||
resolved "https://registry.npmjs.org/@firebase/remote-config/-/remote-config-0.1.31.tgz"
|
||||
dependencies:
|
||||
"@firebase/component" "0.3.1"
|
||||
"@firebase/installations" "0.4.23"
|
||||
"@firebase/component" "0.2.0"
|
||||
"@firebase/installations" "0.4.20"
|
||||
"@firebase/logger" "0.2.6"
|
||||
"@firebase/remote-config-types" "0.1.9"
|
||||
"@firebase/util" "0.4.1"
|
||||
tslib "^2.1.0"
|
||||
"@firebase/util" "0.3.4"
|
||||
tslib "^1.11.1"
|
||||
|
||||
"@firebase/storage-types@0.3.13":
|
||||
version "0.3.13"
|
||||
resolved "https://registry.npmjs.org/@firebase/storage-types/-/storage-types-0.3.13.tgz"
|
||||
|
||||
"@firebase/storage@0.4.6":
|
||||
version "0.4.6"
|
||||
resolved "https://registry.yarnpkg.com/@firebase/storage/-/storage-0.4.6.tgz#485b6297a0863a8455e2c1d3b162509c215ea9a5"
|
||||
integrity sha512-nXhLuPKGJlty2whW56T5/Kpr/3O+cKSB5YcCcRKUO8eBu/1VvIswPgipWFaIpgZ3hkXJqaNzYLYpTdIf1UPWrQ==
|
||||
"@firebase/storage@0.4.3":
|
||||
version "0.4.3"
|
||||
resolved "https://registry.npmjs.org/@firebase/storage/-/storage-0.4.3.tgz"
|
||||
dependencies:
|
||||
"@firebase/component" "0.3.1"
|
||||
"@firebase/component" "0.2.0"
|
||||
"@firebase/storage-types" "0.3.13"
|
||||
"@firebase/util" "0.4.1"
|
||||
tslib "^2.1.0"
|
||||
"@firebase/util" "0.3.4"
|
||||
tslib "^1.11.1"
|
||||
|
||||
"@firebase/util@0.4.1":
|
||||
version "0.4.1"
|
||||
resolved "https://registry.yarnpkg.com/@firebase/util/-/util-0.4.1.tgz#fe76cf0238901dc5455b341cf02e298e7bf68df4"
|
||||
integrity sha512-XhYCOwq4AH+YeQBEnDQvigz50WiiBU4LnJh2+//VMt4J2Ybsk0eTgUHNngUzXsmp80EJrwal3ItODg55q1ajWg==
|
||||
"@firebase/util@0.3.4":
|
||||
version "0.3.4"
|
||||
resolved "https://registry.npmjs.org/@firebase/util/-/util-0.3.4.tgz"
|
||||
dependencies:
|
||||
tslib "^2.1.0"
|
||||
tslib "^1.11.1"
|
||||
|
||||
"@firebase/webchannel-wrapper@0.4.1":
|
||||
version "0.4.1"
|
||||
@@ -1695,66 +1682,70 @@
|
||||
estree-walker "^1.0.1"
|
||||
picomatch "^2.2.2"
|
||||
|
||||
"@sentry/browser@6.2.5":
|
||||
version "6.2.5"
|
||||
resolved "https://registry.yarnpkg.com/@sentry/browser/-/browser-6.2.5.tgz#35e259e16521d26f348a06b31eb495e0033111d6"
|
||||
integrity sha512-nlvaE+D7oaj4MxoY9ikw+krQDOjftnDYJQnOwOraXPk7KYM6YwmkakLuE+x/AkaH3FQVTQF330VAa9d6SWETlA==
|
||||
"@sentry/browser@6.2.2":
|
||||
version "6.2.2"
|
||||
resolved "https://registry.npmjs.org/@sentry/browser/-/browser-6.2.2.tgz"
|
||||
dependencies:
|
||||
"@sentry/core" "6.2.5"
|
||||
"@sentry/types" "6.2.5"
|
||||
"@sentry/utils" "6.2.5"
|
||||
"@sentry/core" "6.2.2"
|
||||
"@sentry/types" "6.2.2"
|
||||
"@sentry/utils" "6.2.2"
|
||||
tslib "^1.9.3"
|
||||
|
||||
"@sentry/core@6.2.5":
|
||||
version "6.2.5"
|
||||
resolved "https://registry.yarnpkg.com/@sentry/core/-/core-6.2.5.tgz#e75093f8598becc0a4a0be927f32f7ac49e8588f"
|
||||
integrity sha512-I+AkgIFO6sDUoHQticP6I27TT3L+i6TUS03in3IEtpBcSeP2jyhlxI8l/wdA7gsBqUPdQ4GHOOaNgtFIcr8qag==
|
||||
"@sentry/core@6.2.2":
|
||||
version "6.2.2"
|
||||
resolved "https://registry.npmjs.org/@sentry/core/-/core-6.2.2.tgz"
|
||||
dependencies:
|
||||
"@sentry/hub" "6.2.5"
|
||||
"@sentry/minimal" "6.2.5"
|
||||
"@sentry/types" "6.2.5"
|
||||
"@sentry/utils" "6.2.5"
|
||||
"@sentry/hub" "6.2.2"
|
||||
"@sentry/minimal" "6.2.2"
|
||||
"@sentry/types" "6.2.2"
|
||||
"@sentry/utils" "6.2.2"
|
||||
tslib "^1.9.3"
|
||||
|
||||
"@sentry/hub@6.2.5":
|
||||
version "6.2.5"
|
||||
resolved "https://registry.yarnpkg.com/@sentry/hub/-/hub-6.2.5.tgz#324cae0c90d736cd1032e94104bf3f18becec4d6"
|
||||
integrity sha512-YlEFdEhcfqpl2HC+/dWXBsBJEljyMzFS7LRRjCk8QANcOdp9PhwQjwebUB4/ulOBjHPP2WZk7fBBd/IKDasTUg==
|
||||
"@sentry/hub@6.2.2":
|
||||
version "6.2.2"
|
||||
resolved "https://registry.npmjs.org/@sentry/hub/-/hub-6.2.2.tgz"
|
||||
dependencies:
|
||||
"@sentry/types" "6.2.5"
|
||||
"@sentry/utils" "6.2.5"
|
||||
"@sentry/types" "6.2.2"
|
||||
"@sentry/utils" "6.2.2"
|
||||
tslib "^1.9.3"
|
||||
|
||||
"@sentry/integrations@6.2.5":
|
||||
version "6.2.5"
|
||||
resolved "https://registry.yarnpkg.com/@sentry/integrations/-/integrations-6.2.5.tgz#37cac11b486779707d62751da36aaaefbb44951a"
|
||||
integrity sha512-4LOgO8lSeGaRV4w1Y03YWtTqrZdm56ciD7k0GLhv+PcFLpiu0exsS1XSs/9vET5LB5GtIgBTeJNNbxVFvvmv8g==
|
||||
"@sentry/integrations@6.2.1":
|
||||
version "6.2.1"
|
||||
resolved "https://registry.npmjs.org/@sentry/integrations/-/integrations-6.2.1.tgz"
|
||||
dependencies:
|
||||
"@sentry/types" "6.2.5"
|
||||
"@sentry/utils" "6.2.5"
|
||||
"@sentry/types" "6.2.1"
|
||||
"@sentry/utils" "6.2.1"
|
||||
localforage "^1.8.1"
|
||||
tslib "^1.9.3"
|
||||
|
||||
"@sentry/minimal@6.2.5":
|
||||
version "6.2.5"
|
||||
resolved "https://registry.yarnpkg.com/@sentry/minimal/-/minimal-6.2.5.tgz#3e963e868bfa68e97581403521fd4e09a8965b02"
|
||||
integrity sha512-RKP4Qx3p7Cv0oX1cPKAkNVFYM7p2k1t32cNk1+rrVQS4hwlJ7Eg6m6fsqsO+85jd6Ne/FnyYsfo9cDD3ImTlWQ==
|
||||
"@sentry/minimal@6.2.2":
|
||||
version "6.2.2"
|
||||
resolved "https://registry.npmjs.org/@sentry/minimal/-/minimal-6.2.2.tgz"
|
||||
dependencies:
|
||||
"@sentry/hub" "6.2.5"
|
||||
"@sentry/types" "6.2.5"
|
||||
"@sentry/hub" "6.2.2"
|
||||
"@sentry/types" "6.2.2"
|
||||
tslib "^1.9.3"
|
||||
|
||||
"@sentry/types@6.2.5":
|
||||
version "6.2.5"
|
||||
resolved "https://registry.yarnpkg.com/@sentry/types/-/types-6.2.5.tgz#34b75285b149e0b9bc5fd54fcc2c445d978c7f2e"
|
||||
integrity sha512-1Sux6CLYrV9bETMsGP/HuLFLouwKoX93CWzG8BjMueW+Di0OGxZphYjXrGuDs8xO8bAKEVGCHgVQdcB2jevS0w==
|
||||
"@sentry/types@6.2.1":
|
||||
version "6.2.1"
|
||||
resolved "https://registry.npmjs.org/@sentry/types/-/types-6.2.1.tgz"
|
||||
|
||||
"@sentry/utils@6.2.5":
|
||||
version "6.2.5"
|
||||
resolved "https://registry.yarnpkg.com/@sentry/utils/-/utils-6.2.5.tgz#be90d056b09ed1216097d7a29e3e81ba39238e1b"
|
||||
integrity sha512-fJoLUZHrd5MPylV1dT4qL74yNFDl1Ur/dab+pKNSyvnHPnbZ/LRM7aJ8VaRY/A7ZdpRowU+E14e/Yeem2c6gtQ==
|
||||
"@sentry/types@6.2.2":
|
||||
version "6.2.2"
|
||||
resolved "https://registry.npmjs.org/@sentry/types/-/types-6.2.2.tgz"
|
||||
|
||||
"@sentry/utils@6.2.1":
|
||||
version "6.2.1"
|
||||
resolved "https://registry.npmjs.org/@sentry/utils/-/utils-6.2.1.tgz"
|
||||
dependencies:
|
||||
"@sentry/types" "6.2.5"
|
||||
"@sentry/types" "6.2.1"
|
||||
tslib "^1.9.3"
|
||||
|
||||
"@sentry/utils@6.2.2":
|
||||
version "6.2.2"
|
||||
resolved "https://registry.npmjs.org/@sentry/utils/-/utils-6.2.2.tgz"
|
||||
dependencies:
|
||||
"@sentry/types" "6.2.2"
|
||||
tslib "^1.9.3"
|
||||
|
||||
"@sindresorhus/is@^0.14.0":
|
||||
@@ -1901,10 +1892,9 @@
|
||||
lodash "^4.17.15"
|
||||
redent "^3.0.0"
|
||||
|
||||
"@testing-library/react@11.2.6":
|
||||
version "11.2.6"
|
||||
resolved "https://registry.yarnpkg.com/@testing-library/react/-/react-11.2.6.tgz#586a23adc63615985d85be0c903f374dab19200b"
|
||||
integrity sha512-TXMCg0jT8xmuU8BkKMtp8l7Z50Ykew5WNX8UoIKTaLFwKkP2+1YDhOLA2Ga3wY4x29jyntk7EWfum0kjlYiSjQ==
|
||||
"@testing-library/react@11.2.5":
|
||||
version "11.2.5"
|
||||
resolved "https://registry.npmjs.org/@testing-library/react/-/react-11.2.5.tgz"
|
||||
dependencies:
|
||||
"@babel/runtime" "^7.12.5"
|
||||
"@testing-library/dom" "^7.28.1"
|
||||
@@ -2075,10 +2065,9 @@
|
||||
version "1.5.4"
|
||||
resolved "https://registry.npmjs.org/@types/q/-/q-1.5.4.tgz"
|
||||
|
||||
"@types/react-dom@17.0.3":
|
||||
version "17.0.3"
|
||||
resolved "https://registry.yarnpkg.com/@types/react-dom/-/react-dom-17.0.3.tgz#7fdf37b8af9d6d40127137865bb3fff8871d7ee1"
|
||||
integrity sha512-4NnJbCeWE+8YBzupn/YrJxZ8VnjcJq5iR1laqQ1vkpQgBiA7bwk0Rp24fxsdNinzJY2U+HHS4dJJDPdoMjdJ7w==
|
||||
"@types/react-dom@17.0.2":
|
||||
version "17.0.2"
|
||||
resolved "https://registry.npmjs.org/@types/react-dom/-/react-dom-17.0.2.tgz"
|
||||
dependencies:
|
||||
"@types/react" "*"
|
||||
|
||||
@@ -3027,7 +3016,7 @@ base64-arraybuffer@0.1.4:
|
||||
version "0.1.4"
|
||||
resolved "https://registry.npmjs.org/base64-arraybuffer/-/base64-arraybuffer-0.1.4.tgz"
|
||||
|
||||
base64-js@^1.0.2, base64-js@^1.3.0, base64-js@^1.3.1:
|
||||
base64-js@^1.0.2, base64-js@^1.2.3, base64-js@^1.3.0, base64-js@^1.3.1:
|
||||
version "1.5.1"
|
||||
resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a"
|
||||
|
||||
@@ -3216,10 +3205,10 @@ brorand@^1.0.1, brorand@^1.1.0:
|
||||
version "1.1.0"
|
||||
resolved "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz"
|
||||
|
||||
browser-fs-access@0.16.4:
|
||||
version "0.16.4"
|
||||
resolved "https://registry.yarnpkg.com/browser-fs-access/-/browser-fs-access-0.16.4.tgz#5dbb85671b1199d74581db98d2975c2fc3a5c708"
|
||||
integrity sha512-c1A9Y3pHJTKPYFjwL5SXX3MZ0BQcK7He7l0csclr80SEADIFOUHUM5oJBdg49XUdlLmIFiWiE3tbr/5KcD5TsQ==
|
||||
browser-fs-access@0.16.2:
|
||||
version "0.16.2"
|
||||
resolved "https://registry.yarnpkg.com/browser-fs-access/-/browser-fs-access-0.16.2.tgz#0707e4b7ae237625b0a513f1ba79080fb33298a6"
|
||||
integrity sha512-wuboS/Vmm85dYIvaY/oIVboNFr3YI1bV+PF19t6gtDUcjaXN7yyroJ/oKdkXJZp6UeQPdWP/tgKGmFbQkfVrYA==
|
||||
|
||||
browser-process-hrtime@^1.0.0:
|
||||
version "1.0.0"
|
||||
@@ -4022,14 +4011,6 @@ core-util-is@1.0.2, core-util-is@~1.0.0:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz"
|
||||
|
||||
cors@^2.8.5:
|
||||
version "2.8.5"
|
||||
resolved "https://registry.yarnpkg.com/cors/-/cors-2.8.5.tgz#eac11da51592dd86b9f06f6e7ac293b3df875d29"
|
||||
integrity sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==
|
||||
dependencies:
|
||||
object-assign "^4"
|
||||
vary "^1"
|
||||
|
||||
cosmiconfig@^5.0.0:
|
||||
version "5.2.1"
|
||||
resolved "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-5.2.1.tgz"
|
||||
@@ -5330,7 +5311,7 @@ exegesis-express@^2.0.0:
|
||||
dependencies:
|
||||
exegesis "^2.0.0"
|
||||
|
||||
exegesis@^2.0.0, exegesis@^2.5.6:
|
||||
exegesis@^2.0.0:
|
||||
version "2.5.6"
|
||||
resolved "https://registry.npmjs.org/exegesis/-/exegesis-2.5.6.tgz"
|
||||
dependencies:
|
||||
@@ -5654,10 +5635,9 @@ find-versions@^4.0.0:
|
||||
dependencies:
|
||||
semver-regex "^3.1.2"
|
||||
|
||||
firebase-tools@9.9.0:
|
||||
version "9.9.0"
|
||||
resolved "https://registry.yarnpkg.com/firebase-tools/-/firebase-tools-9.9.0.tgz#acb64d3a7a8f5dac0b1855783a067aabad8d5743"
|
||||
integrity sha512-LM4HaLHg/UYJ1CB3VEzneRWk+BMJXH/9Id+v9nYeNzYFPRTxAxfWez2Etd2c+kFreLhCoMtSC4yx44zorqdkSA==
|
||||
firebase-tools@9.6.1:
|
||||
version "9.6.1"
|
||||
resolved "https://registry.npmjs.org/firebase-tools/-/firebase-tools-9.6.1.tgz"
|
||||
dependencies:
|
||||
"@google-cloud/pubsub" "^2.7.0"
|
||||
"@types/archiver" "^5.1.0"
|
||||
@@ -5671,12 +5651,10 @@ firebase-tools@9.9.0:
|
||||
cli-table "^0.3.1"
|
||||
commander "^4.0.1"
|
||||
configstore "^5.0.1"
|
||||
cors "^2.8.5"
|
||||
cross-env "^5.1.3"
|
||||
cross-spawn "^7.0.1"
|
||||
csv-streamify "^3.0.4"
|
||||
dotenv "^6.1.0"
|
||||
exegesis "^2.5.6"
|
||||
exegesis-express "^2.0.0"
|
||||
exit-code "^1.0.2"
|
||||
express "^4.16.4"
|
||||
@@ -5686,7 +5664,8 @@ firebase-tools@9.9.0:
|
||||
google-auth-library "^6.1.3"
|
||||
inquirer "~6.3.1"
|
||||
js-yaml "^3.13.1"
|
||||
jsonwebtoken "^8.5.1"
|
||||
jsonschema "^1.0.2"
|
||||
jsonwebtoken "^8.2.1"
|
||||
leven "^3.1.0"
|
||||
lodash "^4.17.19"
|
||||
marked "^0.7.0"
|
||||
@@ -5696,6 +5675,7 @@ firebase-tools@9.9.0:
|
||||
node-fetch "^2.6.1"
|
||||
open "^6.3.0"
|
||||
ora "^3.4.0"
|
||||
plist "^3.0.1"
|
||||
portfinder "^1.0.23"
|
||||
progress "^2.0.3"
|
||||
proxy-agent "^4.0.0"
|
||||
@@ -5713,28 +5693,26 @@ firebase-tools@9.9.0:
|
||||
update-notifier "^4.1.0"
|
||||
uuid "^3.0.0"
|
||||
winston "^3.0.0"
|
||||
winston-transport "^4.4.0"
|
||||
ws "^7.2.3"
|
||||
|
||||
firebase@8.3.2:
|
||||
version "8.3.2"
|
||||
resolved "https://registry.yarnpkg.com/firebase/-/firebase-8.3.2.tgz#f647770472ede31e4411ce5ffdc2ab84796fe4dd"
|
||||
integrity sha512-qGKASp6lXcV8NriHz/3wdltyLUjHOVkON6TQ1syGjW0sS5q/yTl9LK4O83hDLwG+UeRVRhLOaVa3jaLG4o3gnw==
|
||||
firebase@8.2.10:
|
||||
version "8.2.10"
|
||||
resolved "https://registry.npmjs.org/firebase/-/firebase-8.2.10.tgz"
|
||||
dependencies:
|
||||
"@firebase/analytics" "0.6.7"
|
||||
"@firebase/app" "0.6.18"
|
||||
"@firebase/analytics" "0.6.4"
|
||||
"@firebase/app" "0.6.15"
|
||||
"@firebase/app-types" "0.6.1"
|
||||
"@firebase/auth" "0.16.4"
|
||||
"@firebase/database" "0.9.7"
|
||||
"@firebase/firestore" "2.2.2"
|
||||
"@firebase/functions" "0.6.5"
|
||||
"@firebase/installations" "0.4.23"
|
||||
"@firebase/messaging" "0.7.7"
|
||||
"@firebase/performance" "0.4.9"
|
||||
"@firebase/database" "0.9.4"
|
||||
"@firebase/firestore" "2.1.7"
|
||||
"@firebase/functions" "0.6.2"
|
||||
"@firebase/installations" "0.4.20"
|
||||
"@firebase/messaging" "0.7.4"
|
||||
"@firebase/performance" "0.4.6"
|
||||
"@firebase/polyfill" "0.3.36"
|
||||
"@firebase/remote-config" "0.1.34"
|
||||
"@firebase/storage" "0.4.6"
|
||||
"@firebase/util" "0.4.1"
|
||||
"@firebase/remote-config" "0.1.31"
|
||||
"@firebase/storage" "0.4.3"
|
||||
"@firebase/util" "0.3.4"
|
||||
|
||||
flat-arguments@^1.0.0:
|
||||
version "1.0.2"
|
||||
@@ -6512,10 +6490,9 @@ husky@4.3.8:
|
||||
slash "^3.0.0"
|
||||
which-pm-runs "^1.0.0"
|
||||
|
||||
i18next-browser-languagedetector@6.1.0:
|
||||
version "6.1.0"
|
||||
resolved "https://registry.yarnpkg.com/i18next-browser-languagedetector/-/i18next-browser-languagedetector-6.1.0.tgz#83d3a920d5f300424aa37bd4c0a09c267844de71"
|
||||
integrity sha512-NXbr/qPqkg6VyUwPrzmVOAafqIk1zdjzhYVxZWoSi338XEGmuOeroEglLdR8nJUJcf5BfOSHva80tqCPwXFTFQ==
|
||||
i18next-browser-languagedetector@6.0.1:
|
||||
version "6.0.1"
|
||||
resolved "https://registry.npmjs.org/i18next-browser-languagedetector/-/i18next-browser-languagedetector-6.0.1.tgz"
|
||||
dependencies:
|
||||
"@babel/runtime" "^7.5.5"
|
||||
|
||||
@@ -7690,10 +7667,13 @@ jsonparse@^1.2.0:
|
||||
version "1.3.1"
|
||||
resolved "https://registry.npmjs.org/jsonparse/-/jsonparse-1.3.1.tgz"
|
||||
|
||||
jsonwebtoken@^8.5.1:
|
||||
jsonschema@^1.0.2:
|
||||
version "1.4.0"
|
||||
resolved "https://registry.npmjs.org/jsonschema/-/jsonschema-1.4.0.tgz"
|
||||
|
||||
jsonwebtoken@^8.2.1:
|
||||
version "8.5.1"
|
||||
resolved "https://registry.yarnpkg.com/jsonwebtoken/-/jsonwebtoken-8.5.1.tgz#00e71e0b8df54c2121a1f26137df2280673bcc0d"
|
||||
integrity sha512-XjwVfRS6jTMsqYs0EsuJ4LGxXV14zQybNd4L2r0UvbVnSF9Af8x7p5MzbJ90Ioz/9TI41/hTCvznF/loiSzn8w==
|
||||
resolved "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-8.5.1.tgz"
|
||||
dependencies:
|
||||
jws "^3.2.2"
|
||||
lodash.includes "^4.3.0"
|
||||
@@ -8769,7 +8749,7 @@ oauth-sign@~0.9.0:
|
||||
version "0.9.0"
|
||||
resolved "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz"
|
||||
|
||||
object-assign@^4, object-assign@^4.0.1, object-assign@^4.1.0, object-assign@^4.1.1:
|
||||
object-assign@^4.0.1, object-assign@^4.1.0, object-assign@^4.1.1:
|
||||
version "4.1.1"
|
||||
resolved "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz"
|
||||
|
||||
@@ -9314,6 +9294,14 @@ please-upgrade-node@^3.2.0:
|
||||
dependencies:
|
||||
semver-compare "^1.0.0"
|
||||
|
||||
plist@^3.0.1:
|
||||
version "3.0.1"
|
||||
resolved "https://registry.npmjs.org/plist/-/plist-3.0.1.tgz"
|
||||
dependencies:
|
||||
base64-js "^1.2.3"
|
||||
xmlbuilder "^9.0.7"
|
||||
xmldom "0.1.x"
|
||||
|
||||
png-chunk-text@1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.npmjs.org/png-chunk-text/-/png-chunk-text-1.0.0.tgz"
|
||||
@@ -10787,15 +10775,15 @@ rgba-regex@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.npmjs.org/rgba-regex/-/rgba-regex-1.0.0.tgz"
|
||||
|
||||
rimraf@2, rimraf@^2.2.8, rimraf@^2.5.4, rimraf@^2.6.3:
|
||||
version "2.7.1"
|
||||
resolved "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz"
|
||||
rimraf@2, rimraf@2.6.3, rimraf@^2.5.4, rimraf@^2.6.3:
|
||||
version "2.6.3"
|
||||
resolved "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz"
|
||||
dependencies:
|
||||
glob "^7.1.3"
|
||||
|
||||
rimraf@2.6.3:
|
||||
version "2.6.3"
|
||||
resolved "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz"
|
||||
rimraf@^2.2.8:
|
||||
version "2.7.1"
|
||||
resolved "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz"
|
||||
dependencies:
|
||||
glob "^7.1.3"
|
||||
|
||||
@@ -11022,7 +11010,13 @@ semver@^6.0.0, semver@^6.1.1, semver@^6.1.2, semver@^6.2.0, semver@^6.3.0:
|
||||
version "6.3.0"
|
||||
resolved "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz"
|
||||
|
||||
semver@^7.0.0, semver@^7.1.3, semver@^7.2.1, semver@^7.3.2:
|
||||
semver@^7.0.0, semver@^7.1.3:
|
||||
version "7.3.4"
|
||||
resolved "https://registry.npmjs.org/semver/-/semver-7.3.4.tgz"
|
||||
dependencies:
|
||||
lru-cache "^6.0.0"
|
||||
|
||||
semver@^7.2.1, semver@^7.3.2:
|
||||
version "7.3.5"
|
||||
resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.5.tgz#0b621c879348d8998e4b0e4be94b3f12e6018ef7"
|
||||
dependencies:
|
||||
@@ -12053,11 +12047,11 @@ tsconfig-paths@^3.9.0:
|
||||
minimist "^1.2.0"
|
||||
strip-bom "^3.0.0"
|
||||
|
||||
tslib@^1.8.1, tslib@^1.9.0, tslib@^1.9.3:
|
||||
tslib@^1.11.1, tslib@^1.8.1, tslib@^1.9.0, tslib@^1.9.3:
|
||||
version "1.14.1"
|
||||
resolved "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz"
|
||||
|
||||
tslib@^2.0.0, tslib@^2.0.1, tslib@^2.0.3, tslib@^2.1.0:
|
||||
tslib@^2.0.0, tslib@^2.0.1, tslib@^2.0.3:
|
||||
version "2.1.0"
|
||||
resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.1.0.tgz#da60860f1c2ecaa5703ab7d39bc05b6bf988b97a"
|
||||
|
||||
@@ -12157,10 +12151,9 @@ typedarray@^0.0.6:
|
||||
version "0.0.6"
|
||||
resolved "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz"
|
||||
|
||||
typescript@4.2.4:
|
||||
version "4.2.4"
|
||||
resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.2.4.tgz#8610b59747de028fda898a8aef0e103f156d0961"
|
||||
integrity sha512-V+evlYHZnQkaz8TRBuxTA92yZBPotr5H+WhQ7bD3hZUndx5tGOa1fuCgeSjxAzM1RiN5IzvadIXTVefuuwZCRg==
|
||||
typescript@4.2.3:
|
||||
version "4.2.3"
|
||||
resolved "https://registry.npmjs.org/typescript/-/typescript-4.2.3.tgz"
|
||||
|
||||
unbox-primitive@^1.0.0:
|
||||
version "1.0.1"
|
||||
@@ -12416,7 +12409,7 @@ validate-npm-package-license@^3.0.1:
|
||||
spdx-correct "^3.0.0"
|
||||
spdx-expression-parse "^3.0.0"
|
||||
|
||||
vary@^1, vary@~1.1.2:
|
||||
vary@~1.1.2:
|
||||
version "1.1.2"
|
||||
resolved "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz"
|
||||
|
||||
@@ -12910,10 +12903,18 @@ xml-name-validator@^3.0.0:
|
||||
version "3.0.0"
|
||||
resolved "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-3.0.0.tgz"
|
||||
|
||||
xmlbuilder@^9.0.7:
|
||||
version "9.0.7"
|
||||
resolved "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-9.0.7.tgz"
|
||||
|
||||
xmlchars@^2.2.0:
|
||||
version "2.2.0"
|
||||
resolved "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz"
|
||||
|
||||
xmldom@0.1.x:
|
||||
version "0.1.31"
|
||||
resolved "https://registry.npmjs.org/xmldom/-/xmldom-0.1.31.tgz"
|
||||
|
||||
xmlhttprequest-ssl@~1.5.4:
|
||||
version "1.5.5"
|
||||
resolved "https://registry.npmjs.org/xmlhttprequest-ssl/-/xmlhttprequest-ssl-1.5.5.tgz"
|
||||
|
||||
Reference in New Issue
Block a user