Compare commits
12 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 232412d7bc | |||
| 6a8680f500 | |||
| 3b0aff0ac6 | |||
| 93d0a56bdb | |||
| 0a3675e1b9 | |||
| cf35caaf23 | |||
| 4e3bf7e8d2 | |||
| 4c3544df4a | |||
| 74e82d0d7c | |||
| 9dd2257932 | |||
| 9c0f832a41 | |||
| 6cafb6bb90 |
Generated
+27992
-121
File diff suppressed because it is too large
Load Diff
+5
-1
@@ -60,7 +60,8 @@
|
||||
"lint-staged": "10.5.4",
|
||||
"pepjs": "0.5.3",
|
||||
"prettier": "2.2.1",
|
||||
"rewire": "5.0.0"
|
||||
"rewire": "5.0.0",
|
||||
"worker-loader": "3.0.8"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=12.0.0"
|
||||
@@ -75,6 +76,9 @@
|
||||
"transformIgnorePatterns": [
|
||||
"node_modules/(?!(roughjs|points-on-curve|path-data-parser|points-on-path|browser-fs-access)/)"
|
||||
],
|
||||
"moduleNameMapper": {
|
||||
"^worker-loader!.+": "<rootDir>/src/__mocks__/worker-mock.js"
|
||||
},
|
||||
"resetMocks": false
|
||||
},
|
||||
"name": "excalidraw",
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
module.exports = class {
|
||||
postMessage() {}
|
||||
terminate() {}
|
||||
};
|
||||
@@ -7,6 +7,7 @@ import { register } from "./register";
|
||||
import { allowFullScreen, exitFullScreen, isFullScreen } from "../utils";
|
||||
import { CODES, KEYS } from "../keys";
|
||||
import { HelpIcon } from "../components/HelpIcon";
|
||||
import { MiniMap } from "../components/MiniMap";
|
||||
|
||||
export const actionToggleCanvasMenu = register({
|
||||
name: "toggleCanvasMenu",
|
||||
@@ -84,3 +85,21 @@ export const actionShortcuts = register({
|
||||
),
|
||||
keyTest: (event) => event.key === KEYS.QUESTION_MARK,
|
||||
});
|
||||
|
||||
export const actionMinimap = register({
|
||||
name: "toggleMinimap",
|
||||
perform: (_elements, appState) => {
|
||||
return {
|
||||
appState: {
|
||||
...appState,
|
||||
isMinimapEnabled: !appState.isMinimapEnabled,
|
||||
},
|
||||
commitToHistory: false,
|
||||
};
|
||||
},
|
||||
PanelComponent: ({ appState, elements }) =>
|
||||
appState.isMinimapEnabled ? (
|
||||
<MiniMap appState={appState} elements={elements} />
|
||||
) : null,
|
||||
keyTest: (event) => event.key === KEYS.M,
|
||||
});
|
||||
|
||||
@@ -44,6 +44,7 @@ export {
|
||||
actionToggleEditMenu,
|
||||
actionFullScreen,
|
||||
actionShortcuts,
|
||||
actionMinimap,
|
||||
} from "./actionMenu";
|
||||
|
||||
export { actionGroup, actionUngroup } from "./actionGroup";
|
||||
|
||||
@@ -85,7 +85,8 @@ export type ActionName =
|
||||
| "alignHorizontallyCentered"
|
||||
| "distributeHorizontally"
|
||||
| "distributeVertically"
|
||||
| "viewMode";
|
||||
| "viewMode"
|
||||
| "toggleMinimap";
|
||||
|
||||
export interface Action {
|
||||
name: ActionName;
|
||||
|
||||
+4
-2
@@ -42,7 +42,7 @@ export const getDefaultAppState = (): Omit<
|
||||
exportEmbedScene: false,
|
||||
fileHandle: null,
|
||||
gridSize: null,
|
||||
height: window.innerHeight,
|
||||
height: globalThis.innerHeight,
|
||||
isBindingEnabled: true,
|
||||
isLibraryOpen: false,
|
||||
isLoading: false,
|
||||
@@ -69,10 +69,11 @@ export const getDefaultAppState = (): Omit<
|
||||
suggestedBindings: [],
|
||||
toastMessage: null,
|
||||
viewBackgroundColor: oc.white,
|
||||
width: window.innerWidth,
|
||||
width: globalThis.innerWidth,
|
||||
zenModeEnabled: false,
|
||||
zoom: { value: 1 as NormalizedZoomValue, translation: { x: 0, y: 0 } },
|
||||
viewModeEnabled: false,
|
||||
isMinimapEnabled: false,
|
||||
};
|
||||
};
|
||||
|
||||
@@ -153,6 +154,7 @@ const APP_STATE_STORAGE_CONF = (<
|
||||
zenModeEnabled: { browser: true, export: false },
|
||||
zoom: { browser: true, export: false },
|
||||
viewModeEnabled: { browser: false, export: false },
|
||||
isMinimapEnabled: { browser: true, export: false },
|
||||
});
|
||||
|
||||
const _clearAppStateForStorage = <ExportType extends "export" | "browser">(
|
||||
|
||||
@@ -972,6 +972,7 @@ class App extends React.Component<ExcalidrawProps, AppState> {
|
||||
},
|
||||
{
|
||||
renderOptimizations: true,
|
||||
renderScrollbars: !isMobile(),
|
||||
},
|
||||
);
|
||||
if (scrollBars) {
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
.excalidraw {
|
||||
.CollabButton.is-collaborating {
|
||||
background-color: var(--button-special-active-background-color);
|
||||
background-color: var(--button-special-active-bg-color);
|
||||
|
||||
.ToolIcon__icon svg,
|
||||
.ToolIcon__label {
|
||||
|
||||
@@ -2,9 +2,9 @@
|
||||
|
||||
.excalidraw {
|
||||
.color-picker {
|
||||
background: var(--popup-background-color);
|
||||
border: 0px solid transparentize($oc-white, 0.75);
|
||||
box-shadow: transparentize($oc-black, 0.75) 0px 1px 4px;
|
||||
background: var(--popup-bg-color);
|
||||
border: 0 solid transparentize($oc-white, 0.75);
|
||||
box-shadow: transparentize($oc-black, 0.75) 0 1px 4px;
|
||||
border-radius: 4px;
|
||||
position: absolute;
|
||||
|
||||
@@ -24,11 +24,11 @@
|
||||
}
|
||||
|
||||
.color-picker-triangle {
|
||||
width: 0px;
|
||||
height: 0px;
|
||||
width: 0;
|
||||
height: 0;
|
||||
border-style: solid;
|
||||
border-width: 0px 9px 10px;
|
||||
border-color: transparent transparent var(--popup-background-color);
|
||||
border-width: 0 9px 10px;
|
||||
border-color: transparent transparent var(--popup-bg-color);
|
||||
position: absolute;
|
||||
top: -10px;
|
||||
|
||||
@@ -84,12 +84,12 @@
|
||||
|
||||
.color-picker-transparent {
|
||||
border-radius: 4px;
|
||||
box-shadow: transparentize($oc-black, 0.9) 0px 0px 0px 1px inset;
|
||||
box-shadow: transparentize($oc-black, 0.9) 0 0 0 1px inset;
|
||||
position: absolute;
|
||||
top: 0px;
|
||||
right: 0px;
|
||||
bottom: 0px;
|
||||
left: 0px;
|
||||
top: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
}
|
||||
|
||||
.color-picker-transparent,
|
||||
@@ -104,11 +104,11 @@
|
||||
width: 1.875rem;
|
||||
|
||||
:root[dir="ltr"] & {
|
||||
border-radius: 4px 0px 0px 4px;
|
||||
border-radius: 4px 0 0 4px;
|
||||
}
|
||||
|
||||
:root[dir="rtl"] & {
|
||||
border-radius: 0px 4px 4px 0px;
|
||||
border-radius: 0 4px 4px 0;
|
||||
}
|
||||
|
||||
color: var(--input-label-color);
|
||||
@@ -144,7 +144,7 @@
|
||||
}
|
||||
|
||||
.color-input-container:focus-within .color-picker-hash::after {
|
||||
background: var(--input-background-color);
|
||||
background: var(--input-bg-color);
|
||||
|
||||
:root[dir="ltr"] & {
|
||||
right: -2px;
|
||||
@@ -163,19 +163,19 @@
|
||||
width: 12ch; /* length of `transparent` + 1 */
|
||||
margin: 0;
|
||||
font-size: 1rem;
|
||||
background-color: var(--input-background-color);
|
||||
color: var(--text-color-primary);
|
||||
border: 0px;
|
||||
background-color: var(--input-bg-color);
|
||||
color: var(--text-primary-color);
|
||||
border: 0;
|
||||
outline: none;
|
||||
height: 1.75em;
|
||||
box-shadow: var(--input-border-color) 0px 0px 0px 1px inset;
|
||||
box-shadow: var(--input-border-color) 0 0 0 1px inset;
|
||||
|
||||
:root[dir="ltr"] & {
|
||||
border-radius: 0px 4px 4px 0px;
|
||||
border-radius: 0 4px 4px 0;
|
||||
}
|
||||
|
||||
:root[dir="rtl"] & {
|
||||
border-radius: 4px 0px 0px 4px;
|
||||
border-radius: 4px 0 0 4px;
|
||||
}
|
||||
|
||||
float: left;
|
||||
@@ -228,7 +228,7 @@
|
||||
}
|
||||
|
||||
.color-picker-type-elementBackground .color-picker-keybinding {
|
||||
color: #fff;
|
||||
color: $oc-white;
|
||||
}
|
||||
|
||||
.color-picker-swatch[aria-label="transparent"] .color-picker-keybinding {
|
||||
@@ -241,10 +241,10 @@
|
||||
|
||||
&.Appearance_dark {
|
||||
.color-picker-type-elementBackground .color-picker-keybinding {
|
||||
color: #000;
|
||||
color: $oc-black;
|
||||
}
|
||||
.color-picker-swatch[aria-label="transparent"] .color-picker-keybinding {
|
||||
color: #000;
|
||||
color: $oc-black;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,13 +4,13 @@
|
||||
.context-menu {
|
||||
position: relative;
|
||||
border-radius: 4px;
|
||||
box-shadow: 0px 3px 10px transparentize($oc-black, 0.8);
|
||||
box-shadow: 0 3px 10px transparentize($oc-black, 0.8);
|
||||
padding: 0;
|
||||
list-style: none;
|
||||
user-select: none;
|
||||
margin: -0.25rem 0 0 0.125rem;
|
||||
padding: 0.5rem 0;
|
||||
background-color: var(--popup-secondary-background-color);
|
||||
background-color: var(--popup-secondary-bg-color);
|
||||
border: 1px solid var(--button-gray-3);
|
||||
cursor: default;
|
||||
}
|
||||
@@ -61,12 +61,12 @@
|
||||
}
|
||||
|
||||
.context-menu-option:hover {
|
||||
color: var(--popup-background-color);
|
||||
color: var(--popup-bg-color);
|
||||
background-color: var(--select-highlight-color);
|
||||
|
||||
&.dangerous {
|
||||
.context-menu-option__label {
|
||||
color: var(--popup-background-color);
|
||||
color: var(--popup-bg-color);
|
||||
}
|
||||
background-color: $oc-red-6;
|
||||
}
|
||||
|
||||
@@ -45,7 +45,7 @@
|
||||
position: sticky;
|
||||
top: 0;
|
||||
padding: calc(var(--space-factor) * 2);
|
||||
background: var(--bg-color-island);
|
||||
background: var(--island-bg-color);
|
||||
font-size: 1.25em;
|
||||
|
||||
box-sizing: border-box;
|
||||
|
||||
@@ -101,6 +101,10 @@ const ExportModal = ({
|
||||
shouldAddWatermark,
|
||||
});
|
||||
|
||||
if (canvas instanceof OffscreenCanvas) {
|
||||
return;
|
||||
}
|
||||
|
||||
// if converting to blob fails, there's some problem that will
|
||||
// likely prevent preview and export (e.g. canvas too big)
|
||||
canvasToBlob(canvas)
|
||||
|
||||
@@ -26,7 +26,7 @@ $wide-viewport-width: 1000px;
|
||||
|
||||
> span {
|
||||
padding: 0.2rem 0.4rem;
|
||||
background-color: var(--overlay-background-color);
|
||||
background-color: var(--overlay-bg-color);
|
||||
border-radius: 4px;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,9 +8,9 @@
|
||||
}
|
||||
|
||||
.picker {
|
||||
background: var(--popup-background-color);
|
||||
border: 0px solid transparentize($oc-white, 0.75);
|
||||
box-shadow: transparentize($oc-black, 0.75) 0px 1px 4px;
|
||||
background: var(--popup-bg-color);
|
||||
border: 0 solid transparentize($oc-white, 0.75);
|
||||
box-shadow: transparentize($oc-black, 0.75) 0 1px 4px;
|
||||
border-radius: 4px;
|
||||
position: absolute;
|
||||
}
|
||||
@@ -56,8 +56,8 @@
|
||||
}
|
||||
|
||||
.picker-triangle {
|
||||
width: 0px;
|
||||
height: 0px;
|
||||
width: 0;
|
||||
height: 0;
|
||||
position: relative;
|
||||
top: -10px;
|
||||
:root[dir="ltr"] & {
|
||||
@@ -73,7 +73,7 @@
|
||||
content: "";
|
||||
position: absolute;
|
||||
border-style: solid;
|
||||
border-width: 0px 9px 10px;
|
||||
border-width: 0 9px 10px;
|
||||
border-color: transparent transparent transparentize($oc-black, 0.9);
|
||||
top: -1px;
|
||||
}
|
||||
@@ -82,8 +82,8 @@
|
||||
content: "";
|
||||
position: absolute;
|
||||
border-style: solid;
|
||||
border-width: 0px 9px 10px;
|
||||
border-color: transparent transparent var(--popup-background-color);
|
||||
border-width: 0 9px 10px;
|
||||
border-color: transparent transparent var(--popup-bg-color);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -121,7 +121,7 @@
|
||||
}
|
||||
|
||||
.picker-type-elementBackground .picker-keybinding {
|
||||
color: #fff;
|
||||
color: $oc-white;
|
||||
}
|
||||
|
||||
.picker-swatch[aria-label="transparent"] .picker-keybinding {
|
||||
@@ -134,10 +134,10 @@
|
||||
|
||||
&.Appearance_dark {
|
||||
.picker-type-elementBackground .picker-keybinding {
|
||||
color: #000;
|
||||
color: $oc-black;
|
||||
}
|
||||
.picker-swatch[aria-label="transparent"] .picker-keybinding {
|
||||
color: #000;
|
||||
color: $oc-black;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
.excalidraw {
|
||||
.Island {
|
||||
--padding: 0;
|
||||
background-color: var(--bg-color-island);
|
||||
background-color: var(--island-bg-color);
|
||||
backdrop-filter: saturate(100%) blur(10px);
|
||||
box-shadow: var(--shadow-island);
|
||||
border-radius: 4px;
|
||||
|
||||
@@ -73,7 +73,7 @@
|
||||
&__footer {
|
||||
position: absolute;
|
||||
z-index: 100;
|
||||
bottom: 0px;
|
||||
bottom: 0;
|
||||
|
||||
:root[dir="ltr"] & {
|
||||
right: 0;
|
||||
@@ -94,7 +94,7 @@
|
||||
}
|
||||
|
||||
:root[dir="ltr"] &.transition-right {
|
||||
transform: translate(999px, 0px);
|
||||
transform: translate(999px, 0);
|
||||
}
|
||||
|
||||
:root[dir="rtl"] &.transition-left {
|
||||
|
||||
@@ -602,6 +602,7 @@ const LayerUI = ({
|
||||
>
|
||||
{renderCustomFooter?.(false)}
|
||||
{actionManager.renderAction("toggleShortcuts")}
|
||||
{actionManager.renderAction("toggleMinimap")}
|
||||
</div>
|
||||
<button
|
||||
className={clsx("disable-zen-mode", {
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
.Island.MiniMap {
|
||||
position: absolute;
|
||||
bottom: 50px;
|
||||
right: calc(var(--space-factor) * 4);
|
||||
}
|
||||
@@ -0,0 +1,151 @@
|
||||
import "./MiniMap.scss";
|
||||
|
||||
import React, { useEffect, useRef, useMemo, useState } from "react";
|
||||
import { getCommonBounds, getNonDeletedElements } from "../element";
|
||||
import { ExcalidrawElement } from "../element/types";
|
||||
import { AppState } from "../types";
|
||||
import { distance, viewportCoordsToSceneCoords } from "../utils";
|
||||
import { Island } from "./Island";
|
||||
// eslint-disable-next-line import/no-webpack-loader-syntax
|
||||
import MinimapWorker from "worker-loader!../renderer/minimapWorker";
|
||||
|
||||
const RATIO = 1.2;
|
||||
const MINIMAP_HEIGHT = 150;
|
||||
const MINIMAP_WIDTH = MINIMAP_HEIGHT * RATIO;
|
||||
|
||||
const MinimapViewport = ({
|
||||
elements,
|
||||
appState,
|
||||
}: {
|
||||
elements: readonly ExcalidrawElement[];
|
||||
appState: AppState;
|
||||
}) => {
|
||||
const [minX, minY, maxX, maxY] = useMemo(
|
||||
() => getCommonBounds(getNonDeletedElements(elements)),
|
||||
[elements],
|
||||
);
|
||||
|
||||
const minimapScale = Math.min(
|
||||
MINIMAP_WIDTH / distance(minX, maxX),
|
||||
MINIMAP_HEIGHT / distance(minY, maxY),
|
||||
);
|
||||
|
||||
const leftTop = viewportCoordsToSceneCoords(
|
||||
{ clientX: 0, clientY: 0 },
|
||||
appState,
|
||||
);
|
||||
const rightBot = viewportCoordsToSceneCoords(
|
||||
{ clientX: appState.width, clientY: appState.height },
|
||||
appState,
|
||||
);
|
||||
|
||||
const top = (leftTop.y - minY) * minimapScale;
|
||||
const left = (leftTop.x - minX) * minimapScale;
|
||||
const width = (rightBot.x - leftTop.x) * minimapScale;
|
||||
const height = (rightBot.y - leftTop.y) * minimapScale;
|
||||
|
||||
// Set viewport boundaries
|
||||
const viewportTop = Math.min(Math.max(0, top), MINIMAP_HEIGHT);
|
||||
const viewportLeft = Math.min(Math.max(0, left), MINIMAP_WIDTH);
|
||||
const viewportWidth = Math.min(
|
||||
MINIMAP_WIDTH - viewportLeft,
|
||||
width,
|
||||
width + left,
|
||||
);
|
||||
const viewportHeight = Math.min(
|
||||
MINIMAP_HEIGHT - viewportTop,
|
||||
height,
|
||||
height + top,
|
||||
);
|
||||
|
||||
if (
|
||||
Number.isNaN(viewportTop) ||
|
||||
Number.isNaN(viewportLeft) ||
|
||||
Number.isNaN(viewportWidth) ||
|
||||
Number.isNaN(viewportHeight)
|
||||
) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<div
|
||||
style={{
|
||||
border: "2px solid orange",
|
||||
boxSizing: "border-box",
|
||||
position: "absolute",
|
||||
pointerEvents: "none",
|
||||
top: viewportTop,
|
||||
left: viewportLeft,
|
||||
width: viewportWidth,
|
||||
height: viewportHeight,
|
||||
}}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export function MiniMap({
|
||||
appState,
|
||||
elements,
|
||||
}: {
|
||||
appState: AppState;
|
||||
elements: readonly ExcalidrawElement[];
|
||||
}) {
|
||||
const [minimapWorker] = useState(() => new MinimapWorker());
|
||||
const canvasRef = useRef<HTMLCanvasElement>(null);
|
||||
const elementsRef = useRef(elements);
|
||||
elementsRef.current = elements;
|
||||
const appStateRef = useRef(appState);
|
||||
appStateRef.current = appState;
|
||||
|
||||
useEffect(() => {
|
||||
const canvas = canvasRef.current;
|
||||
if (!canvas) {
|
||||
return;
|
||||
}
|
||||
|
||||
const offscreenCanvas = canvas.transferControlToOffscreen();
|
||||
|
||||
minimapWorker.postMessage({ type: "INIT", canvas: offscreenCanvas }, [
|
||||
offscreenCanvas,
|
||||
]);
|
||||
|
||||
minimapWorker.postMessage({
|
||||
type: "DRAW",
|
||||
elements: elementsRef.current,
|
||||
appState: appStateRef.current,
|
||||
width: MINIMAP_WIDTH,
|
||||
height: MINIMAP_HEIGHT,
|
||||
});
|
||||
|
||||
setInterval(() => {
|
||||
minimapWorker.postMessage({
|
||||
type: "DRAW",
|
||||
elements: elementsRef.current,
|
||||
appState: appStateRef.current,
|
||||
width: MINIMAP_WIDTH,
|
||||
height: MINIMAP_HEIGHT,
|
||||
});
|
||||
}, 1000);
|
||||
|
||||
return () => {
|
||||
minimapWorker.terminate();
|
||||
};
|
||||
}, [minimapWorker]);
|
||||
|
||||
return (
|
||||
<Island padding={1} className="MiniMap">
|
||||
<div
|
||||
style={{
|
||||
width: MINIMAP_WIDTH,
|
||||
height: MINIMAP_HEIGHT,
|
||||
position: "relative",
|
||||
overflow: "hidden",
|
||||
backgroundColor: appState.viewBackgroundColor,
|
||||
}}
|
||||
>
|
||||
<canvas ref={canvasRef} />
|
||||
<MinimapViewport elements={elements} appState={appState} />
|
||||
</div>
|
||||
</Island>
|
||||
);
|
||||
}
|
||||
@@ -44,10 +44,10 @@
|
||||
overflow-y: auto;
|
||||
|
||||
// for modals, reset blurry bg
|
||||
background: var(--bg-color-island);
|
||||
background: var(--island-bg-color);
|
||||
backdrop-filter: none;
|
||||
|
||||
border: 1px solid var(--dialog-border);
|
||||
border: 1px solid var(--dialog-border-color);
|
||||
box-shadow: 0 2px 10px transparentize($oc-black, 0.75);
|
||||
border-radius: 6px;
|
||||
|
||||
|
||||
+42
-40
@@ -1,51 +1,53 @@
|
||||
@import "../css/variables.module";
|
||||
|
||||
.Stats {
|
||||
position: absolute;
|
||||
top: 64px;
|
||||
right: 12px;
|
||||
font-size: 12px;
|
||||
z-index: 999;
|
||||
.excalidraw {
|
||||
.Stats {
|
||||
position: absolute;
|
||||
top: 64px;
|
||||
right: 12px;
|
||||
font-size: 12px;
|
||||
z-index: 999;
|
||||
|
||||
h3 {
|
||||
margin: 0 24px 8px 0;
|
||||
white-space: nowrap;
|
||||
}
|
||||
h3 {
|
||||
margin: 0 24px 8px 0;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.close {
|
||||
float: right;
|
||||
height: 16px;
|
||||
width: 16px;
|
||||
cursor: pointer;
|
||||
svg {
|
||||
.close {
|
||||
float: right;
|
||||
height: 16px;
|
||||
width: 16px;
|
||||
cursor: pointer;
|
||||
svg {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
table {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
th {
|
||||
border-bottom: 1px solid var(--input-border-color);
|
||||
padding: 4px;
|
||||
}
|
||||
tr {
|
||||
td:nth-child(2) {
|
||||
min-width: 24px;
|
||||
text-align: right;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
table {
|
||||
width: 100%;
|
||||
th {
|
||||
border-bottom: 1px solid var(--input-border-color);
|
||||
padding: 4px;
|
||||
}
|
||||
tr {
|
||||
td:nth-child(2) {
|
||||
min-width: 24px;
|
||||
text-align: right;
|
||||
:root[dir="rtl"] & {
|
||||
left: 12px;
|
||||
right: initial;
|
||||
|
||||
h3 {
|
||||
margin: 0 0 8px 24px;
|
||||
}
|
||||
.close {
|
||||
float: left;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
:root[dir="rtl"] & {
|
||||
left: 12px;
|
||||
right: initial;
|
||||
|
||||
h3 {
|
||||
margin: 0 0 8px 24px;
|
||||
}
|
||||
.close {
|
||||
float: left;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,18 +2,18 @@
|
||||
|
||||
.excalidraw {
|
||||
.TextInput {
|
||||
color: var(--text-color-primary);
|
||||
color: var(--text-primary-color);
|
||||
display: inline-block;
|
||||
border: 1.5px solid var(--button-gray-1);
|
||||
line-height: 1;
|
||||
padding: 0.75rem;
|
||||
white-space: nowrap;
|
||||
border-radius: var(--space-factor);
|
||||
background-color: var(--input-background-color);
|
||||
background-color: var(--input-bg-color);
|
||||
|
||||
&:not(:focus) {
|
||||
&:hover {
|
||||
background-color: var(--input-hover-background-color);
|
||||
background-color: var(--input-hover-bg-color);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+12
-12
@@ -8,7 +8,7 @@
|
||||
}
|
||||
|
||||
.excalidraw {
|
||||
color: var(--text-color-primary);
|
||||
color: var(--text-primary-color);
|
||||
display: flex;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
@@ -50,10 +50,10 @@
|
||||
}
|
||||
|
||||
.FixedSideContainer {
|
||||
padding-top: var(--sat, 0px);
|
||||
padding-right: var(--sar, 0px);
|
||||
padding-bottom: var(--sab, 0px);
|
||||
padding-left: var(--sal, 0px);
|
||||
padding-top: var(--sat, 0);
|
||||
padding-right: var(--sar, 0);
|
||||
padding-bottom: var(--sab, 0);
|
||||
padding-left: var(--sal, 0);
|
||||
}
|
||||
|
||||
.panelRow {
|
||||
@@ -71,7 +71,7 @@
|
||||
margin-top: 0.333rem;
|
||||
margin-bottom: 0.333rem;
|
||||
font-size: 0.75rem;
|
||||
color: var(--text-color-primary);
|
||||
color: var(--text-primary-color);
|
||||
font-weight: bold;
|
||||
display: block;
|
||||
}
|
||||
@@ -237,10 +237,10 @@
|
||||
left: 0;
|
||||
right: 0;
|
||||
--bar-padding: calc(4 * var(--space-factor));
|
||||
padding-top: #{"max(var(--bar-padding), var(--sat, 0px))"};
|
||||
padding-right: var(--sar, 0px);
|
||||
padding-bottom: var(--sab, 0px);
|
||||
padding-left: var(--sal, 0px);
|
||||
padding-top: #{"max(var(--bar-padding), var(--sat,0))"};
|
||||
padding-right: var(--sar, 0);
|
||||
padding-bottom: var(--sab, 0);
|
||||
padding-left: var(--sal, 0);
|
||||
z-index: 4;
|
||||
display: flex;
|
||||
align-items: flex-end;
|
||||
@@ -257,7 +257,7 @@
|
||||
pointer-events: initial;
|
||||
|
||||
.panelColumn {
|
||||
padding: 8px 8px 0px 8px;
|
||||
padding: 8px 8px 0 8px;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -460,7 +460,7 @@
|
||||
display: none;
|
||||
}
|
||||
.scroll-back-to-content {
|
||||
bottom: calc(80px + var(--sab, 0px));
|
||||
bottom: calc(80px + var(--sab, 0));
|
||||
z-index: -1;
|
||||
}
|
||||
}
|
||||
|
||||
+42
-42
@@ -1,43 +1,43 @@
|
||||
@import "open-color/open-color.scss";
|
||||
|
||||
:root {
|
||||
--bg-color-island: rgba(255, 255, 255, 0.9);
|
||||
--popup-background-color: #{$oc-white};
|
||||
--space-factor: 0.25rem;
|
||||
--appearance-filter: none;
|
||||
--button-destructive-bg-color: #{$oc-red-1};
|
||||
--button-destructive-color: #{$oc-red-9};
|
||||
--button-gray-1: #{$oc-gray-2};
|
||||
--button-gray-2: #{$oc-gray-4};
|
||||
--button-gray-3: #{$oc-gray-5};
|
||||
--input-border-color: #{$oc-gray-3};
|
||||
--input-background-color: #{$oc-white};
|
||||
--input-hover-background-color: #{$oc-gray-1};
|
||||
--input-label-color: #{$oc-gray-7};
|
||||
--button-special-active-bg-color: #{$oc-green-0};
|
||||
--dialog-border-color: #{$oc-gray-6};
|
||||
--dropdown-icon: url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" width="292.4" height="292.4" viewBox="0 0 292 292"><path d="M287 197L159 69c-4-3-8-5-13-5s-9 2-13 5L5 197c-3 4-5 8-5 13s2 9 5 13c4 4 8 5 13 5h256c5 0 9-1 13-5s5-8 5-13-1-9-5-13z"/></svg>');
|
||||
--focus-highlight-color: #{$oc-blue-2};
|
||||
--icon-fill-color: #{$oc-black};
|
||||
--icon-green-fill-color: #{$oc-green-9};
|
||||
--input-bg-color: #{$oc-white};
|
||||
--input-border-color: #{$oc-gray-3};
|
||||
--input-hover-bg-color: #{$oc-gray-1};
|
||||
--input-label-color: #{$oc-gray-7};
|
||||
--island-bg-color: rgba(255, 255, 255, 0.9);
|
||||
--keybinding-color: #{$oc-gray-5};
|
||||
--sat: env(safe-area-inset-top);
|
||||
--link-color: #{$oc-blue-7};
|
||||
--overlay-bg-color: #{transparentize($oc-white, 0.12)};
|
||||
--popup-bg-color: #{$oc-white};
|
||||
--popup-secondary-bg-color: #{$oc-gray-1};
|
||||
--popup-text-color: #{$oc-black};
|
||||
--popup-text-inverted-color: #{$oc-white};
|
||||
--sab: env(safe-area-inset-bottom);
|
||||
--sal: env(safe-area-inset-left);
|
||||
--sar: env(safe-area-inset-right);
|
||||
--text-color-primary: #{$oc-gray-8};
|
||||
--shadow-island: 0 1px 5px #{transparentize($oc-black, 0.85)};
|
||||
--overlay-background-color: #{transparentize($oc-white, 0.12)};
|
||||
--dropdown-icon: url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" width="292.4" height="292.4" viewBox="0 0 292 292"><path d="M287 197L159 69c-4-3-8-5-13-5s-9 2-13 5L5 197c-3 4-5 8-5 13s2 9 5 13c4 4 8 5 13 5h256c5 0 9-1 13-5s5-8 5-13-1-9-5-13z"/></svg>');
|
||||
--focus-highlight-color: #{$oc-blue-2};
|
||||
--sat: env(safe-area-inset-top);
|
||||
--select-highlight-color: #{$oc-blue-5};
|
||||
--appearance-filter: none;
|
||||
--button-special-active-background-color: #{$oc-green-0};
|
||||
--button-destructive-color: #{$oc-red-9};
|
||||
--button-destructive-background-color: #{$oc-red-1};
|
||||
--popup-secondary-background-color: #{$oc-gray-1};
|
||||
--popup-text-color: #{$oc-black};
|
||||
--popup-text-inverted-color: #{$oc-white};
|
||||
--dialog-border: #{$oc-gray-6};
|
||||
--link-color: #{$oc-blue-7};
|
||||
--shadow-island: 0 1px 5px #{transparentize($oc-black, 0.85)};
|
||||
--space-factor: 0.25rem;
|
||||
--text-primary-color: #{$oc-gray-8};
|
||||
}
|
||||
|
||||
.excalidraw {
|
||||
&.Appearance_dark {
|
||||
background: #000;
|
||||
background: $oc-black;
|
||||
|
||||
&.Appearance_dark-background-none {
|
||||
background: none;
|
||||
@@ -45,31 +45,31 @@
|
||||
}
|
||||
|
||||
&.Appearance_dark {
|
||||
--text-color-primary: #{$oc-gray-4};
|
||||
--bg-color-island: #1e1e1e;
|
||||
--popup-background-color: #2c2c2c;
|
||||
--appearance-filter: invert(93%) hue-rotate(180deg);
|
||||
--button-destructive-bg-color: #5a0000;
|
||||
--button-destructive-color: #{$oc-red-3};
|
||||
--button-gray-1: #363636;
|
||||
--button-gray-2: #272727;
|
||||
--button-gray-3: #222;
|
||||
--input-border-color: #2e2e2e;
|
||||
--input-background-color: #121212;
|
||||
--input-hover-background-color: #181818;
|
||||
--input-label-color: #{$oc-gray-2};
|
||||
--icon-fill-color: #{$oc-gray-4};
|
||||
--icon-green-fill-color: #{$oc-green-4};
|
||||
--keybinding-color: #{$oc-gray-6};
|
||||
--shadow-island: 0 1px 5px #{transparentize($oc-black, 0.7)};
|
||||
--overlay-background-color: rgba(30, 30, 30, 0.88);
|
||||
--button-special-active-bg-color: #204624;
|
||||
--dialog-border-color: #{$oc-gray-9};
|
||||
--dropdown-icon: url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" width="292.4" height="292.4" viewBox="0 0 292 292"><path fill="%23ced4da" d="M287 197L159 69c-4-3-8-5-13-5s-9 2-13 5L5 197c-3 4-5 8-5 13s2 9 5 13c4 4 8 5 13 5h256c5 0 9-1 13-5s5-8 5-13-1-9-5-13z"/></svg>');
|
||||
--focus-highlight-color: #{$oc-blue-6};
|
||||
--select-highlight-color: #{$oc-blue-4};
|
||||
--appearance-filter: invert(93%) hue-rotate(180deg);
|
||||
--button-special-active-background-color: #204624;
|
||||
--button-destructive-color: #{$oc-red-3};
|
||||
--button-destructive-background-color: #5a0000;
|
||||
--popup-secondary-background-color: #222;
|
||||
--icon-fill-color: #{$oc-gray-4};
|
||||
--icon-green-fill-color: #{$oc-green-4};
|
||||
--input-bg-color: #121212;
|
||||
--input-border-color: #2e2e2e;
|
||||
--input-hover-bg-color: #181818;
|
||||
--input-label-color: #{$oc-gray-2};
|
||||
--island-bg-color: #1e1e1e;
|
||||
--keybinding-color: #{$oc-gray-6};
|
||||
--overlay-bg-color: #{transparentize($oc-gray-8, 0.88)};
|
||||
--popup-bg-color: #2c2c2c;
|
||||
--popup-secondary-bg-color: #222;
|
||||
--popup-text-color: #{$oc-gray-4};
|
||||
--popup-text-inverted-color: #2c2c2c;
|
||||
--dialog-border: #{$oc-gray-9};
|
||||
--select-highlight-color: #{$oc-blue-4};
|
||||
--shadow-island: 0 1px 5px #{transparentize($oc-black, 0.7)};
|
||||
--text-primary-color: #{$oc-gray-4};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -73,6 +73,11 @@ export const exportCanvas = async (
|
||||
scale,
|
||||
shouldAddWatermark,
|
||||
});
|
||||
|
||||
if (tempCanvas instanceof OffscreenCanvas) {
|
||||
return;
|
||||
}
|
||||
|
||||
tempCanvas.style.display = "none";
|
||||
document.body.appendChild(tempCanvas);
|
||||
|
||||
|
||||
+1
-1
@@ -141,7 +141,7 @@ export const restoreElements = (
|
||||
}, [] as ExcalidrawElement[]);
|
||||
};
|
||||
|
||||
const restoreAppState = (
|
||||
export const restoreAppState = (
|
||||
appState: ImportedDataState["appState"],
|
||||
localAppState: Partial<AppState> | null,
|
||||
): AppState => {
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
}
|
||||
|
||||
.RoomDialog-link {
|
||||
color: var(--text-color-primary);
|
||||
color: var(--text-primary-color);
|
||||
min-width: 0;
|
||||
flex: 1 1 auto;
|
||||
margin-inline-start: 1em;
|
||||
@@ -45,7 +45,7 @@
|
||||
}
|
||||
|
||||
.RoomDialog-username {
|
||||
background-color: var(--input-background-color);
|
||||
background-color: var(--input-bg-color);
|
||||
border-color: var(--input-border-color);
|
||||
appearance: none;
|
||||
min-width: 0;
|
||||
@@ -67,7 +67,7 @@
|
||||
}
|
||||
|
||||
.Modal .RoomDialog-stopSession {
|
||||
background-color: var(--button-destructive-background-color);
|
||||
background-color: var(--button-destructive-bg-color);
|
||||
|
||||
.ToolIcon__label,
|
||||
.ToolIcon__icon svg {
|
||||
|
||||
Vendored
+11
@@ -88,3 +88,14 @@ interface Blob {
|
||||
handle?: import("browser-fs-acces").FileSystemHandle;
|
||||
name?: string;
|
||||
}
|
||||
|
||||
declare module "worker-loader!*" {
|
||||
// You need to change `Worker`, if you specified a different value for the `workerType` option
|
||||
class WebpackWorker extends Worker {
|
||||
constructor();
|
||||
}
|
||||
|
||||
// Uncomment this if you set the `esModule` option to `false`
|
||||
// export = WebpackWorker;
|
||||
export default WebpackWorker;
|
||||
}
|
||||
|
||||
+5
-2
@@ -1,5 +1,7 @@
|
||||
export const isDarwin = /Mac|iPod|iPhone|iPad/.test(window.navigator.platform);
|
||||
export const isWindows = /^Win/.test(window.navigator.platform);
|
||||
export const isDarwin = /Mac|iPod|iPhone|iPad/.test(
|
||||
globalThis.navigator.platform,
|
||||
);
|
||||
export const isWindows = /^Win/.test(globalThis.navigator.platform);
|
||||
|
||||
export const CODES = {
|
||||
EQUAL: "Equal",
|
||||
@@ -43,6 +45,7 @@ export const KEYS = {
|
||||
D: "d",
|
||||
E: "e",
|
||||
L: "l",
|
||||
M: "m",
|
||||
O: "o",
|
||||
P: "p",
|
||||
Q: "q",
|
||||
|
||||
@@ -12,6 +12,18 @@ 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
|
||||
|
||||
### Features
|
||||
|
||||
- Export [`restore`](https://github.com/excalidraw/excalidraw/blob/master/src/data/restore.ts#L182), [`restoreAppState`](https://github.com/excalidraw/excalidraw/blob/master/src/data/restore.ts#L144) and [`restoreElements`](https://github.com/excalidraw/excalidraw/blob/master/src/data/restore.ts#L128) to host
|
||||
|
||||
### Fixes
|
||||
|
||||
- Show user state only when [userState](https://github.com/excalidraw/excalidraw/blob/master/src/types.ts#L35) is passed on remote pointers during collaboration [#3050](https://github.com/excalidraw/excalidraw/pull/3050)
|
||||
|
||||
## 0.3.1
|
||||
|
||||
## Excalidraw API
|
||||
|
||||
@@ -252,51 +252,6 @@ export default function IndexPage() {
|
||||
| [`zenModeEnabled`](#zenModeEnabled) | boolean | | This implies if the zen mode is enabled |
|
||||
| [`gridModeEnabled`](#gridModeEnabled) | boolean | | This implies if the grid mode is enabled |
|
||||
|
||||
### `Extra API's`
|
||||
|
||||
#### `getSceneVersion`
|
||||
|
||||
**How to use**
|
||||
|
||||
<pre>
|
||||
import { getSceneVersion } from "@excalidraw/excalidraw";
|
||||
getSceneVersion(elements: <a href="https://github.com/excalidraw/excalidraw/blob/master/src/element/types.ts#L78">ExcalidrawElement[]</a>)
|
||||
</pre>
|
||||
|
||||
This function returns the current scene version.
|
||||
|
||||
#### `getSyncableElements`
|
||||
|
||||
**_Signature_**
|
||||
|
||||
<pre>
|
||||
getSyncableElements(elements: <a href="https://github.com/excalidraw/excalidraw/blob/master/src/element/types.ts#L78">ExcalidrawElement[]</a>):<a href="https://github.com/excalidraw/excalidraw/blob/master/src/element/types.ts#L78">ExcalidrawElement[]</a>
|
||||
</pre>
|
||||
|
||||
**How to use**
|
||||
|
||||
```js
|
||||
import { getSyncableElements } from "@excalidraw/excalidraw";
|
||||
```
|
||||
|
||||
This function returns all the deleted elements of the scene.
|
||||
|
||||
### `getElementMap`
|
||||
|
||||
**_Signature_**
|
||||
|
||||
<pre>
|
||||
getElementsMap(elements: <a href="https://github.com/excalidraw/excalidraw/blob/master/src/element/types.ts#L78">ExcalidrawElement[]</a>): {[id: string]: <a href="https://github.com/excalidraw/excalidraw/blob/master/src/element/types.ts#L78">ExcalidrawElement</a>}
|
||||
</pre>
|
||||
|
||||
**How to use**
|
||||
|
||||
```js
|
||||
import { getElementsMap } from "@excalidraw/excalidraw";
|
||||
```
|
||||
|
||||
This function returns an object where each element is mapped to its id.
|
||||
|
||||
#### `width`
|
||||
|
||||
This props defines the `width` of the Excalidraw component. Defaults to `window.innerWidth` if not passed.
|
||||
@@ -451,3 +406,98 @@ This prop indicates whether the app is in `zen mode`. When supplied, the value t
|
||||
#### `gridModeEnabled`
|
||||
|
||||
This prop indicates whether the shows the grid. When supplied, the value takes precedence over `intialData.appState.gridModeEnabled`, the grid will be fully controlled by the host app, and users won't be able to toggle it from within the app.
|
||||
|
||||
### Extra API's
|
||||
|
||||
#### `getSceneVersion`
|
||||
|
||||
**How to use**
|
||||
|
||||
<pre>
|
||||
import { getSceneVersion } from "@excalidraw/excalidraw";
|
||||
getSceneVersion(elements: <a href="https://github.com/excalidraw/excalidraw/blob/master/src/element/types.ts#L78">ExcalidrawElement[]</a>)
|
||||
</pre>
|
||||
|
||||
This function returns the current scene version.
|
||||
|
||||
#### `getSyncableElements`
|
||||
|
||||
**_Signature_**
|
||||
|
||||
<pre>
|
||||
getSyncableElements(elements: <a href="https://github.com/excalidraw/excalidraw/blob/master/src/element/types.ts#L78">ExcalidrawElement[]</a>):<a href="https://github.com/excalidraw/excalidraw/blob/master/src/element/types.ts#L78">ExcalidrawElement[]</a>
|
||||
</pre>
|
||||
|
||||
**How to use**
|
||||
|
||||
```js
|
||||
import { getSyncableElements } from "@excalidraw/excalidraw";
|
||||
```
|
||||
|
||||
This function returns all the deleted elements of the scene.
|
||||
|
||||
#### `getElementMap`
|
||||
|
||||
**_Signature_**
|
||||
|
||||
<pre>
|
||||
getElementsMap(elements: <a href="https://github.com/excalidraw/excalidraw/blob/master/src/element/types.ts#L78">ExcalidrawElement[]</a>): {[id: string]: <a href="https://github.com/excalidraw/excalidraw/blob/master/src/element/types.ts#L78">ExcalidrawElement</a>}
|
||||
</pre>
|
||||
|
||||
**How to use**
|
||||
|
||||
```js
|
||||
import { getElementsMap } from "@excalidraw/excalidraw";
|
||||
```
|
||||
|
||||
This function returns an object where each element is mapped to its id.
|
||||
|
||||
**_The below api's will be available in [next version](https://github.com/excalidraw/excalidraw/blob/master/src/packages/excalidraw/CHANGELOG.md#unreleased)_**
|
||||
|
||||
#### `restoreAppState`
|
||||
|
||||
**_Signature_**
|
||||
|
||||
<pre>
|
||||
restoreAppState(appState: <a href="https://github.com/excalidraw/excalidraw/blob/master/src/data/types.ts#L17">ImportedDataState["appState"]</a>, localAppState: Partial<<a href="https://github.com/excalidraw/excalidraw/blob/master/src/types.ts#L37">AppState</a>> | null): <a href="https://github.com/excalidraw/excalidraw/blob/master/src/types.ts#L37">AppState</a>
|
||||
</pre>
|
||||
|
||||
**_How to use_**
|
||||
|
||||
```js
|
||||
import { restoreAppState } from "@excalidraw/excalidraw";
|
||||
```
|
||||
|
||||
This function will make sure all the keys have appropriate values in [appState](https://github.com/excalidraw/excalidraw/blob/master/src/types.ts#L37) and if any key is missing, it will be set to default value. If you pass `localAppState`, `localAppState` value will be preferred over the `appState` passed in params.
|
||||
|
||||
#### `restoreElements`
|
||||
|
||||
**_Signature_**
|
||||
|
||||
<pre>
|
||||
restoreElements(elements: <a href="https://github.com/excalidraw/excalidraw/blob/master/src/data/types.ts#L16">ImportedDataState["elements"]</a>): <a href="https://github.com/excalidraw/excalidraw/blob/master/src/element/types.ts#L78">ExcalidrawElement[]</a>
|
||||
</pre>
|
||||
|
||||
**_How to use_**
|
||||
|
||||
```js
|
||||
import { restoreElements } from "@excalidraw/excalidraw";
|
||||
```
|
||||
|
||||
This function will make sure all properties of element is correctly set and if any attribute is missing, it will be set to default value.
|
||||
|
||||
#### `restore`
|
||||
|
||||
**_Signature_**
|
||||
|
||||
<pre>
|
||||
restoreElements(data: <a href="https://github.com/excalidraw/excalidraw/blob/master/src/data/types.ts#L12">ImportedDataState</a>): <a href="https://github.com/excalidraw/excalidraw/blob/master/src/data/types.ts#L4">DataState</a>
|
||||
</pre>
|
||||
|
||||
**_How to use_**
|
||||
|
||||
```js
|
||||
import { restore } from "@excalidraw/excalidraw";
|
||||
```
|
||||
|
||||
This function makes sure elements and state is set to appropriate values and set to default value if not present. It is combination of [restoreElements](#restoreElements) and [restoreAppState](#restoreAppState)
|
||||
|
||||
@@ -106,3 +106,4 @@ export {
|
||||
getElementMap,
|
||||
} from "../../element";
|
||||
export { defaultLang, languages } from "../../i18n";
|
||||
export { restore, restoreAppState, restoreElements } from "../../data/restore";
|
||||
|
||||
@@ -48,6 +48,9 @@ export const exportToBlob = (
|
||||
},
|
||||
): Promise<Blob | null> => {
|
||||
const canvas = exportToCanvas(opts);
|
||||
if (canvas instanceof OffscreenCanvas) {
|
||||
return Promise.resolve(null);
|
||||
}
|
||||
|
||||
let { mimeType = "image/png", quality } = opts;
|
||||
|
||||
|
||||
@@ -0,0 +1,48 @@
|
||||
/* eslint-disable no-restricted-globals */
|
||||
|
||||
import { getNonDeletedElements } from "../element";
|
||||
import { ExcalidrawElement } from "../element/types";
|
||||
import { exportToCanvas } from "../scene/export";
|
||||
import { AppState } from "../types";
|
||||
|
||||
const ctx: Worker = self as any;
|
||||
let canvas: OffscreenCanvas;
|
||||
|
||||
ctx.addEventListener("message", (ev) => {
|
||||
if (ev.data.type === "INIT") {
|
||||
canvas = ev.data.canvas;
|
||||
}
|
||||
|
||||
if (ev.data.type === "DRAW") {
|
||||
const { elements, appState, width, height } = ev.data;
|
||||
drawScene(canvas, elements, appState, width, height);
|
||||
}
|
||||
});
|
||||
|
||||
function drawScene(
|
||||
canvas: OffscreenCanvas,
|
||||
elements: readonly ExcalidrawElement[],
|
||||
appState: AppState,
|
||||
minimapWidth: number,
|
||||
minimapHeight: number,
|
||||
) {
|
||||
exportToCanvas(
|
||||
getNonDeletedElements(elements),
|
||||
appState,
|
||||
{
|
||||
exportBackground: true,
|
||||
viewBackgroundColor: appState.viewBackgroundColor,
|
||||
shouldAddWatermark: false,
|
||||
},
|
||||
(width, height) => {
|
||||
const scale = Math.min(minimapWidth / width, minimapHeight / height);
|
||||
canvas.width = width * scale;
|
||||
canvas.height = height * scale;
|
||||
|
||||
return {
|
||||
canvas,
|
||||
scale,
|
||||
};
|
||||
},
|
||||
);
|
||||
}
|
||||
@@ -115,7 +115,7 @@ const generateElementCanvas = (
|
||||
const drawElementOnCanvas = (
|
||||
element: NonDeletedExcalidrawElement,
|
||||
rc: RoughCanvas,
|
||||
context: CanvasRenderingContext2D,
|
||||
context: CanvasRenderingContext2D | OffscreenCanvasRenderingContext2D,
|
||||
) => {
|
||||
context.globalAlpha = element.opacity / 100;
|
||||
switch (element.type) {
|
||||
@@ -136,13 +136,16 @@ const drawElementOnCanvas = (
|
||||
default: {
|
||||
if (isTextElement(element)) {
|
||||
const rtl = isRTL(element.text);
|
||||
const shouldTemporarilyAttach = rtl && !context.canvas.isConnected;
|
||||
if (shouldTemporarilyAttach) {
|
||||
// to correctly render RTL text mixed with LTR, we have to append it
|
||||
// to the DOM
|
||||
document.body.appendChild(context.canvas);
|
||||
let shouldTemporarilyAttach = false;
|
||||
if (!(context instanceof OffscreenCanvasRenderingContext2D)) {
|
||||
shouldTemporarilyAttach = rtl && !context.canvas.isConnected;
|
||||
if (shouldTemporarilyAttach) {
|
||||
// to correctly render RTL text mixed with LTR, we have to append it
|
||||
// to the DOM
|
||||
document.body.appendChild(context.canvas);
|
||||
}
|
||||
context.canvas.setAttribute("dir", rtl ? "rtl" : "ltr");
|
||||
}
|
||||
context.canvas.setAttribute("dir", rtl ? "rtl" : "ltr");
|
||||
const font = context.font;
|
||||
context.font = getFontString(element);
|
||||
const fillStyle = context.fillStyle;
|
||||
@@ -170,7 +173,10 @@ const drawElementOnCanvas = (
|
||||
context.fillStyle = fillStyle;
|
||||
context.font = font;
|
||||
context.textAlign = textAlign;
|
||||
if (shouldTemporarilyAttach) {
|
||||
if (
|
||||
shouldTemporarilyAttach &&
|
||||
!(context instanceof OffscreenCanvasRenderingContext2D)
|
||||
) {
|
||||
context.canvas.remove();
|
||||
}
|
||||
} else {
|
||||
@@ -451,7 +457,7 @@ const generateElementWithCanvas = (
|
||||
const drawElementFromCanvas = (
|
||||
elementWithCanvas: ExcalidrawElementWithCanvas,
|
||||
rc: RoughCanvas,
|
||||
context: CanvasRenderingContext2D,
|
||||
context: CanvasRenderingContext2D | OffscreenCanvasRenderingContext2D,
|
||||
sceneState: SceneState,
|
||||
) => {
|
||||
const element = elementWithCanvas.element;
|
||||
@@ -482,7 +488,7 @@ const drawElementFromCanvas = (
|
||||
export const renderElement = (
|
||||
element: NonDeletedExcalidrawElement,
|
||||
rc: RoughCanvas,
|
||||
context: CanvasRenderingContext2D,
|
||||
context: CanvasRenderingContext2D | OffscreenCanvasRenderingContext2D,
|
||||
renderOptimizations: boolean,
|
||||
sceneState: SceneState,
|
||||
) => {
|
||||
|
||||
+24
-29
@@ -53,7 +53,7 @@ import { UserIdleState } from "../excalidraw-app/collab/types";
|
||||
const hasEmojiSupport = supportsEmoji();
|
||||
|
||||
const strokeRectWithRotation = (
|
||||
context: CanvasRenderingContext2D,
|
||||
context: CanvasRenderingContext2D | OffscreenCanvasRenderingContext2D,
|
||||
x: number,
|
||||
y: number,
|
||||
width: number,
|
||||
@@ -74,7 +74,7 @@ const strokeRectWithRotation = (
|
||||
};
|
||||
|
||||
const strokeDiamondWithRotation = (
|
||||
context: CanvasRenderingContext2D,
|
||||
context: CanvasRenderingContext2D | OffscreenCanvasRenderingContext2D,
|
||||
width: number,
|
||||
height: number,
|
||||
cx: number,
|
||||
@@ -95,7 +95,7 @@ const strokeDiamondWithRotation = (
|
||||
};
|
||||
|
||||
const strokeEllipseWithRotation = (
|
||||
context: CanvasRenderingContext2D,
|
||||
context: CanvasRenderingContext2D | OffscreenCanvasRenderingContext2D,
|
||||
width: number,
|
||||
height: number,
|
||||
cx: number,
|
||||
@@ -108,7 +108,7 @@ const strokeEllipseWithRotation = (
|
||||
};
|
||||
|
||||
const fillCircle = (
|
||||
context: CanvasRenderingContext2D,
|
||||
context: CanvasRenderingContext2D | OffscreenCanvasRenderingContext2D,
|
||||
cx: number,
|
||||
cy: number,
|
||||
radius: number,
|
||||
@@ -120,7 +120,7 @@ const fillCircle = (
|
||||
};
|
||||
|
||||
const strokeGrid = (
|
||||
context: CanvasRenderingContext2D,
|
||||
context: CanvasRenderingContext2D | OffscreenCanvasRenderingContext2D,
|
||||
gridSize: number,
|
||||
offsetX: number,
|
||||
offsetY: number,
|
||||
@@ -143,7 +143,7 @@ const strokeGrid = (
|
||||
};
|
||||
|
||||
const renderLinearPointHandles = (
|
||||
context: CanvasRenderingContext2D,
|
||||
context: CanvasRenderingContext2D | OffscreenCanvasRenderingContext2D,
|
||||
appState: AppState,
|
||||
sceneState: SceneState,
|
||||
element: NonDeleted<ExcalidrawLinearElement>,
|
||||
@@ -182,7 +182,7 @@ export const renderScene = (
|
||||
selectionElement: NonDeletedExcalidrawElement | null,
|
||||
scale: number,
|
||||
rc: RoughCanvas,
|
||||
canvas: HTMLCanvasElement,
|
||||
canvas: HTMLCanvasElement | OffscreenCanvas,
|
||||
sceneState: SceneState,
|
||||
// extra options, currently passed by export helper
|
||||
{
|
||||
@@ -483,25 +483,20 @@ export const renderScene = (
|
||||
context.stroke();
|
||||
|
||||
const username = sceneState.remotePointerUsernames[clientId];
|
||||
let usernameAndIdleState;
|
||||
if (hasEmojiSupport) {
|
||||
usernameAndIdleState = `${username ? `${username} ` : ""}${
|
||||
userState === UserIdleState.AWAY
|
||||
? "⚫️"
|
||||
: userState === UserIdleState.IDLE
|
||||
? "💤"
|
||||
: "🟢"
|
||||
}`;
|
||||
} else {
|
||||
usernameAndIdleState = `${username ? `${username}` : ""}${
|
||||
userState === UserIdleState.AWAY
|
||||
? ` (${UserIdleState.AWAY})`
|
||||
: userState === UserIdleState.IDLE
|
||||
? ` (${UserIdleState.IDLE})`
|
||||
: ""
|
||||
}`;
|
||||
|
||||
let idleState = "";
|
||||
if (userState === UserIdleState.AWAY) {
|
||||
idleState = hasEmojiSupport ? "⚫️" : ` (${UserIdleState.AWAY})`;
|
||||
} else if (userState === UserIdleState.IDLE) {
|
||||
idleState = hasEmojiSupport ? "💤" : ` (${UserIdleState.IDLE})`;
|
||||
} else if (userState === UserIdleState.ACTIVE) {
|
||||
idleState = hasEmojiSupport ? "🟢" : "";
|
||||
}
|
||||
|
||||
const usernameAndIdleState = `${
|
||||
username ? `${username} ` : ""
|
||||
}${idleState}`;
|
||||
|
||||
if (!isOutOfBounds && usernameAndIdleState) {
|
||||
const offsetX = x + width;
|
||||
const offsetY = y + height;
|
||||
@@ -578,7 +573,7 @@ export const renderScene = (
|
||||
};
|
||||
|
||||
const renderTransformHandles = (
|
||||
context: CanvasRenderingContext2D,
|
||||
context: CanvasRenderingContext2D | OffscreenCanvasRenderingContext2D,
|
||||
sceneState: SceneState,
|
||||
transformHandles: TransformHandles,
|
||||
angle: number,
|
||||
@@ -614,7 +609,7 @@ const renderTransformHandles = (
|
||||
};
|
||||
|
||||
const renderSelectionBorder = (
|
||||
context: CanvasRenderingContext2D,
|
||||
context: CanvasRenderingContext2D | OffscreenCanvasRenderingContext2D,
|
||||
sceneState: SceneState,
|
||||
elementProperties: {
|
||||
angle: number;
|
||||
@@ -676,7 +671,7 @@ const renderSelectionBorder = (
|
||||
};
|
||||
|
||||
const renderBindingHighlight = (
|
||||
context: CanvasRenderingContext2D,
|
||||
context: CanvasRenderingContext2D | OffscreenCanvasRenderingContext2D,
|
||||
sceneState: SceneState,
|
||||
suggestedBinding: SuggestedBinding,
|
||||
) => {
|
||||
@@ -698,7 +693,7 @@ const renderBindingHighlight = (
|
||||
};
|
||||
|
||||
const renderBindingHighlightForBindableElement = (
|
||||
context: CanvasRenderingContext2D,
|
||||
context: CanvasRenderingContext2D | OffscreenCanvasRenderingContext2D,
|
||||
element: ExcalidrawBindableElement,
|
||||
) => {
|
||||
const [x1, y1, x2, y2] = getElementAbsoluteCoords(element);
|
||||
@@ -753,7 +748,7 @@ const renderBindingHighlightForBindableElement = (
|
||||
};
|
||||
|
||||
const renderBindingHighlightForSuggestedPointBinding = (
|
||||
context: CanvasRenderingContext2D,
|
||||
context: CanvasRenderingContext2D | OffscreenCanvasRenderingContext2D,
|
||||
suggestedBinding: SuggestedPointBinding,
|
||||
) => {
|
||||
const [element, startOrEnd, bindableElement] = suggestedBinding;
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
* @param {Number} radius The corner radius
|
||||
*/
|
||||
export const roundRect = (
|
||||
context: CanvasRenderingContext2D,
|
||||
context: CanvasRenderingContext2D | OffscreenCanvasRenderingContext2D,
|
||||
x: number,
|
||||
y: number,
|
||||
width: number,
|
||||
|
||||
+5
-2
@@ -32,7 +32,10 @@ export const exportToCanvas = (
|
||||
createCanvas: (
|
||||
width: number,
|
||||
height: number,
|
||||
) => { canvas: HTMLCanvasElement; scale: number } = (width, height) => {
|
||||
) => { canvas: HTMLCanvasElement | OffscreenCanvas; scale: number } = (
|
||||
width,
|
||||
height,
|
||||
) => {
|
||||
const tempCanvas = document.createElement("canvas");
|
||||
tempCanvas.width = width * scale;
|
||||
tempCanvas.height = height * scale;
|
||||
@@ -57,7 +60,7 @@ export const exportToCanvas = (
|
||||
appState,
|
||||
null,
|
||||
newScale,
|
||||
rough.canvas(tempCanvas),
|
||||
rough.canvas((tempCanvas as unknown) as HTMLCanvasElement),
|
||||
tempCanvas,
|
||||
{
|
||||
viewBackgroundColor: exportBackground ? viewBackgroundColor : null,
|
||||
|
||||
@@ -35,6 +35,7 @@ Object {
|
||||
"isBindingEnabled": true,
|
||||
"isLibraryOpen": false,
|
||||
"isLoading": false,
|
||||
"isMinimapEnabled": false,
|
||||
"isResizing": false,
|
||||
"isRotating": false,
|
||||
"lastPointerDownWith": "mouse",
|
||||
@@ -495,6 +496,7 @@ Object {
|
||||
"isBindingEnabled": true,
|
||||
"isLibraryOpen": false,
|
||||
"isLoading": false,
|
||||
"isMinimapEnabled": false,
|
||||
"isResizing": false,
|
||||
"isRotating": false,
|
||||
"lastPointerDownWith": "mouse",
|
||||
@@ -961,6 +963,7 @@ Object {
|
||||
"isBindingEnabled": false,
|
||||
"isLibraryOpen": false,
|
||||
"isLoading": false,
|
||||
"isMinimapEnabled": false,
|
||||
"isResizing": false,
|
||||
"isRotating": false,
|
||||
"lastPointerDownWith": "mouse",
|
||||
@@ -1736,6 +1739,7 @@ Object {
|
||||
"isBindingEnabled": true,
|
||||
"isLibraryOpen": false,
|
||||
"isLoading": false,
|
||||
"isMinimapEnabled": false,
|
||||
"isResizing": false,
|
||||
"isRotating": false,
|
||||
"lastPointerDownWith": "mouse",
|
||||
@@ -1939,6 +1943,7 @@ Object {
|
||||
"isBindingEnabled": true,
|
||||
"isLibraryOpen": false,
|
||||
"isLoading": false,
|
||||
"isMinimapEnabled": false,
|
||||
"isResizing": false,
|
||||
"isRotating": false,
|
||||
"lastPointerDownWith": "mouse",
|
||||
@@ -2396,6 +2401,7 @@ Object {
|
||||
"isBindingEnabled": true,
|
||||
"isLibraryOpen": false,
|
||||
"isLoading": false,
|
||||
"isMinimapEnabled": false,
|
||||
"isResizing": false,
|
||||
"isRotating": false,
|
||||
"lastPointerDownWith": "mouse",
|
||||
@@ -2648,6 +2654,7 @@ Object {
|
||||
"isBindingEnabled": true,
|
||||
"isLibraryOpen": false,
|
||||
"isLoading": false,
|
||||
"isMinimapEnabled": false,
|
||||
"isResizing": false,
|
||||
"isRotating": false,
|
||||
"lastPointerDownWith": "mouse",
|
||||
@@ -2811,6 +2818,7 @@ Object {
|
||||
"isBindingEnabled": true,
|
||||
"isLibraryOpen": false,
|
||||
"isLoading": false,
|
||||
"isMinimapEnabled": false,
|
||||
"isResizing": false,
|
||||
"isRotating": false,
|
||||
"lastPointerDownWith": "mouse",
|
||||
@@ -3287,6 +3295,7 @@ Object {
|
||||
"isBindingEnabled": true,
|
||||
"isLibraryOpen": false,
|
||||
"isLoading": false,
|
||||
"isMinimapEnabled": false,
|
||||
"isResizing": false,
|
||||
"isRotating": false,
|
||||
"lastPointerDownWith": "mouse",
|
||||
@@ -3594,6 +3603,7 @@ Object {
|
||||
"isBindingEnabled": true,
|
||||
"isLibraryOpen": false,
|
||||
"isLoading": false,
|
||||
"isMinimapEnabled": false,
|
||||
"isResizing": false,
|
||||
"isRotating": false,
|
||||
"lastPointerDownWith": "mouse",
|
||||
@@ -3797,6 +3807,7 @@ Object {
|
||||
"isBindingEnabled": true,
|
||||
"isLibraryOpen": false,
|
||||
"isLoading": false,
|
||||
"isMinimapEnabled": false,
|
||||
"isResizing": false,
|
||||
"isRotating": false,
|
||||
"lastPointerDownWith": "mouse",
|
||||
@@ -4040,6 +4051,7 @@ Object {
|
||||
"isBindingEnabled": true,
|
||||
"isLibraryOpen": false,
|
||||
"isLoading": false,
|
||||
"isMinimapEnabled": false,
|
||||
"isResizing": false,
|
||||
"isRotating": false,
|
||||
"lastPointerDownWith": "mouse",
|
||||
@@ -4291,6 +4303,7 @@ Object {
|
||||
"isBindingEnabled": true,
|
||||
"isLibraryOpen": false,
|
||||
"isLoading": false,
|
||||
"isMinimapEnabled": false,
|
||||
"isResizing": false,
|
||||
"isRotating": false,
|
||||
"lastPointerDownWith": "mouse",
|
||||
@@ -4673,6 +4686,7 @@ Object {
|
||||
"isBindingEnabled": true,
|
||||
"isLibraryOpen": false,
|
||||
"isLoading": false,
|
||||
"isMinimapEnabled": false,
|
||||
"isResizing": false,
|
||||
"isRotating": false,
|
||||
"lastPointerDownWith": "mouse",
|
||||
@@ -4967,6 +4981,7 @@ Object {
|
||||
"isBindingEnabled": true,
|
||||
"isLibraryOpen": false,
|
||||
"isLoading": false,
|
||||
"isMinimapEnabled": false,
|
||||
"isResizing": false,
|
||||
"isRotating": false,
|
||||
"lastPointerDownWith": "mouse",
|
||||
@@ -5273,6 +5288,7 @@ Object {
|
||||
"isBindingEnabled": true,
|
||||
"isLibraryOpen": false,
|
||||
"isLoading": false,
|
||||
"isMinimapEnabled": false,
|
||||
"isResizing": false,
|
||||
"isRotating": false,
|
||||
"lastPointerDownWith": "mouse",
|
||||
@@ -5480,6 +5496,7 @@ Object {
|
||||
"isBindingEnabled": true,
|
||||
"isLibraryOpen": false,
|
||||
"isLoading": false,
|
||||
"isMinimapEnabled": false,
|
||||
"isResizing": false,
|
||||
"isRotating": false,
|
||||
"lastPointerDownWith": "mouse",
|
||||
@@ -5643,6 +5660,7 @@ Object {
|
||||
"isBindingEnabled": true,
|
||||
"isLibraryOpen": false,
|
||||
"isLoading": false,
|
||||
"isMinimapEnabled": false,
|
||||
"isResizing": false,
|
||||
"isRotating": false,
|
||||
"lastPointerDownWith": "mouse",
|
||||
@@ -6095,6 +6113,7 @@ Object {
|
||||
"isBindingEnabled": true,
|
||||
"isLibraryOpen": false,
|
||||
"isLoading": false,
|
||||
"isMinimapEnabled": false,
|
||||
"isResizing": false,
|
||||
"isRotating": false,
|
||||
"lastPointerDownWith": "mouse",
|
||||
@@ -6412,6 +6431,7 @@ Object {
|
||||
"isBindingEnabled": true,
|
||||
"isLibraryOpen": false,
|
||||
"isLoading": false,
|
||||
"isMinimapEnabled": false,
|
||||
"isResizing": false,
|
||||
"isRotating": false,
|
||||
"lastPointerDownWith": "mouse",
|
||||
@@ -8445,6 +8465,7 @@ Object {
|
||||
"isBindingEnabled": true,
|
||||
"isLibraryOpen": false,
|
||||
"isLoading": false,
|
||||
"isMinimapEnabled": false,
|
||||
"isResizing": false,
|
||||
"isRotating": false,
|
||||
"lastPointerDownWith": "mouse",
|
||||
@@ -8806,6 +8827,7 @@ Object {
|
||||
"isBindingEnabled": true,
|
||||
"isLibraryOpen": false,
|
||||
"isLoading": false,
|
||||
"isMinimapEnabled": false,
|
||||
"isResizing": false,
|
||||
"isRotating": false,
|
||||
"lastPointerDownWith": "mouse",
|
||||
@@ -9060,6 +9082,7 @@ Object {
|
||||
"isBindingEnabled": true,
|
||||
"isLibraryOpen": false,
|
||||
"isLoading": false,
|
||||
"isMinimapEnabled": false,
|
||||
"isResizing": false,
|
||||
"isRotating": false,
|
||||
"lastPointerDownWith": "mouse",
|
||||
@@ -9312,6 +9335,7 @@ Object {
|
||||
"isBindingEnabled": true,
|
||||
"isLibraryOpen": false,
|
||||
"isLoading": false,
|
||||
"isMinimapEnabled": false,
|
||||
"isResizing": false,
|
||||
"isRotating": false,
|
||||
"lastPointerDownWith": "mouse",
|
||||
@@ -9626,6 +9650,7 @@ Object {
|
||||
"isBindingEnabled": true,
|
||||
"isLibraryOpen": false,
|
||||
"isLoading": false,
|
||||
"isMinimapEnabled": false,
|
||||
"isResizing": false,
|
||||
"isRotating": false,
|
||||
"lastPointerDownWith": "mouse",
|
||||
@@ -9789,6 +9814,7 @@ Object {
|
||||
"isBindingEnabled": true,
|
||||
"isLibraryOpen": false,
|
||||
"isLoading": false,
|
||||
"isMinimapEnabled": false,
|
||||
"isResizing": false,
|
||||
"isRotating": false,
|
||||
"lastPointerDownWith": "mouse",
|
||||
@@ -9952,6 +9978,7 @@ Object {
|
||||
"isBindingEnabled": true,
|
||||
"isLibraryOpen": false,
|
||||
"isLoading": false,
|
||||
"isMinimapEnabled": false,
|
||||
"isResizing": false,
|
||||
"isRotating": false,
|
||||
"lastPointerDownWith": "mouse",
|
||||
@@ -10115,6 +10142,7 @@ Object {
|
||||
"isBindingEnabled": true,
|
||||
"isLibraryOpen": false,
|
||||
"isLoading": false,
|
||||
"isMinimapEnabled": false,
|
||||
"isResizing": false,
|
||||
"isRotating": false,
|
||||
"lastPointerDownWith": "mouse",
|
||||
@@ -10308,6 +10336,7 @@ Object {
|
||||
"isBindingEnabled": true,
|
||||
"isLibraryOpen": false,
|
||||
"isLoading": false,
|
||||
"isMinimapEnabled": false,
|
||||
"isResizing": false,
|
||||
"isRotating": false,
|
||||
"lastPointerDownWith": "mouse",
|
||||
@@ -10501,6 +10530,7 @@ Object {
|
||||
"isBindingEnabled": true,
|
||||
"isLibraryOpen": false,
|
||||
"isLoading": false,
|
||||
"isMinimapEnabled": false,
|
||||
"isResizing": false,
|
||||
"isRotating": false,
|
||||
"lastPointerDownWith": "mouse",
|
||||
@@ -10694,6 +10724,7 @@ Object {
|
||||
"isBindingEnabled": true,
|
||||
"isLibraryOpen": false,
|
||||
"isLoading": false,
|
||||
"isMinimapEnabled": false,
|
||||
"isResizing": false,
|
||||
"isRotating": false,
|
||||
"lastPointerDownWith": "mouse",
|
||||
@@ -10887,6 +10918,7 @@ Object {
|
||||
"isBindingEnabled": true,
|
||||
"isLibraryOpen": false,
|
||||
"isLoading": false,
|
||||
"isMinimapEnabled": false,
|
||||
"isResizing": false,
|
||||
"isRotating": false,
|
||||
"lastPointerDownWith": "mouse",
|
||||
@@ -11050,6 +11082,7 @@ Object {
|
||||
"isBindingEnabled": true,
|
||||
"isLibraryOpen": false,
|
||||
"isLoading": false,
|
||||
"isMinimapEnabled": false,
|
||||
"isResizing": false,
|
||||
"isRotating": false,
|
||||
"lastPointerDownWith": "mouse",
|
||||
@@ -11213,6 +11246,7 @@ Object {
|
||||
"isBindingEnabled": true,
|
||||
"isLibraryOpen": false,
|
||||
"isLoading": false,
|
||||
"isMinimapEnabled": false,
|
||||
"isResizing": false,
|
||||
"isRotating": false,
|
||||
"lastPointerDownWith": "mouse",
|
||||
@@ -11406,6 +11440,7 @@ Object {
|
||||
"isBindingEnabled": true,
|
||||
"isLibraryOpen": false,
|
||||
"isLoading": false,
|
||||
"isMinimapEnabled": false,
|
||||
"isResizing": false,
|
||||
"isRotating": false,
|
||||
"lastPointerDownWith": "mouse",
|
||||
@@ -11569,6 +11604,7 @@ Object {
|
||||
"isBindingEnabled": true,
|
||||
"isLibraryOpen": false,
|
||||
"isLoading": false,
|
||||
"isMinimapEnabled": false,
|
||||
"isResizing": false,
|
||||
"isRotating": false,
|
||||
"lastPointerDownWith": "mouse",
|
||||
@@ -11762,6 +11798,7 @@ Object {
|
||||
"isBindingEnabled": true,
|
||||
"isLibraryOpen": false,
|
||||
"isLoading": false,
|
||||
"isMinimapEnabled": false,
|
||||
"isResizing": false,
|
||||
"isRotating": false,
|
||||
"lastPointerDownWith": "mouse",
|
||||
@@ -12477,6 +12514,7 @@ Object {
|
||||
"isBindingEnabled": true,
|
||||
"isLibraryOpen": false,
|
||||
"isLoading": false,
|
||||
"isMinimapEnabled": false,
|
||||
"isResizing": false,
|
||||
"isRotating": false,
|
||||
"lastPointerDownWith": "mouse",
|
||||
@@ -12729,6 +12767,7 @@ Object {
|
||||
"isBindingEnabled": true,
|
||||
"isLibraryOpen": false,
|
||||
"isLoading": false,
|
||||
"isMinimapEnabled": false,
|
||||
"isResizing": false,
|
||||
"isRotating": false,
|
||||
"lastPointerDownWith": "touch",
|
||||
@@ -12830,6 +12869,7 @@ Object {
|
||||
"isBindingEnabled": true,
|
||||
"isLibraryOpen": false,
|
||||
"isLoading": false,
|
||||
"isMinimapEnabled": false,
|
||||
"isResizing": false,
|
||||
"isRotating": false,
|
||||
"lastPointerDownWith": "mouse",
|
||||
@@ -12929,6 +12969,7 @@ Object {
|
||||
"isBindingEnabled": true,
|
||||
"isLibraryOpen": false,
|
||||
"isLoading": false,
|
||||
"isMinimapEnabled": false,
|
||||
"isResizing": false,
|
||||
"isRotating": false,
|
||||
"lastPointerDownWith": "mouse",
|
||||
@@ -13092,6 +13133,7 @@ Object {
|
||||
"isBindingEnabled": true,
|
||||
"isLibraryOpen": false,
|
||||
"isLoading": false,
|
||||
"isMinimapEnabled": false,
|
||||
"isResizing": false,
|
||||
"isRotating": false,
|
||||
"lastPointerDownWith": "mouse",
|
||||
@@ -13399,6 +13441,7 @@ Object {
|
||||
"isBindingEnabled": true,
|
||||
"isLibraryOpen": false,
|
||||
"isLoading": false,
|
||||
"isMinimapEnabled": false,
|
||||
"isResizing": false,
|
||||
"isRotating": false,
|
||||
"lastPointerDownWith": "mouse",
|
||||
@@ -13706,6 +13749,7 @@ Object {
|
||||
"isBindingEnabled": true,
|
||||
"isLibraryOpen": false,
|
||||
"isLoading": false,
|
||||
"isMinimapEnabled": false,
|
||||
"isResizing": false,
|
||||
"isRotating": false,
|
||||
"lastPointerDownWith": "mouse",
|
||||
@@ -13869,6 +13913,7 @@ Object {
|
||||
"isBindingEnabled": true,
|
||||
"isLibraryOpen": false,
|
||||
"isLoading": false,
|
||||
"isMinimapEnabled": false,
|
||||
"isResizing": false,
|
||||
"isRotating": false,
|
||||
"lastPointerDownWith": "mouse",
|
||||
@@ -14064,6 +14109,7 @@ Object {
|
||||
"isBindingEnabled": true,
|
||||
"isLibraryOpen": false,
|
||||
"isLoading": false,
|
||||
"isMinimapEnabled": false,
|
||||
"isResizing": false,
|
||||
"isRotating": false,
|
||||
"lastPointerDownWith": "mouse",
|
||||
@@ -14312,6 +14358,7 @@ Object {
|
||||
"isBindingEnabled": true,
|
||||
"isLibraryOpen": false,
|
||||
"isLoading": false,
|
||||
"isMinimapEnabled": false,
|
||||
"isResizing": false,
|
||||
"isRotating": false,
|
||||
"lastPointerDownWith": "mouse",
|
||||
@@ -14635,6 +14682,7 @@ Object {
|
||||
"isBindingEnabled": true,
|
||||
"isLibraryOpen": false,
|
||||
"isLoading": false,
|
||||
"isMinimapEnabled": false,
|
||||
"isResizing": false,
|
||||
"isRotating": false,
|
||||
"lastPointerDownWith": "mouse",
|
||||
@@ -15473,6 +15521,7 @@ Object {
|
||||
"isBindingEnabled": true,
|
||||
"isLibraryOpen": false,
|
||||
"isLoading": false,
|
||||
"isMinimapEnabled": false,
|
||||
"isResizing": false,
|
||||
"isRotating": false,
|
||||
"lastPointerDownWith": "mouse",
|
||||
@@ -15780,6 +15829,7 @@ Object {
|
||||
"isBindingEnabled": true,
|
||||
"isLibraryOpen": false,
|
||||
"isLoading": false,
|
||||
"isMinimapEnabled": false,
|
||||
"isResizing": false,
|
||||
"isRotating": false,
|
||||
"lastPointerDownWith": "mouse",
|
||||
@@ -16087,6 +16137,7 @@ Object {
|
||||
"isBindingEnabled": true,
|
||||
"isLibraryOpen": false,
|
||||
"isLoading": false,
|
||||
"isMinimapEnabled": false,
|
||||
"isResizing": false,
|
||||
"isRotating": false,
|
||||
"lastPointerDownWith": "mouse",
|
||||
@@ -16465,6 +16516,7 @@ Object {
|
||||
"isBindingEnabled": true,
|
||||
"isLibraryOpen": false,
|
||||
"isLoading": false,
|
||||
"isMinimapEnabled": false,
|
||||
"isResizing": false,
|
||||
"isRotating": false,
|
||||
"lastPointerDownWith": "mouse",
|
||||
@@ -16631,6 +16683,7 @@ Object {
|
||||
"isBindingEnabled": true,
|
||||
"isLibraryOpen": false,
|
||||
"isLoading": false,
|
||||
"isMinimapEnabled": false,
|
||||
"isResizing": false,
|
||||
"isRotating": false,
|
||||
"lastPointerDownWith": "mouse",
|
||||
@@ -16951,6 +17004,7 @@ Object {
|
||||
"isBindingEnabled": true,
|
||||
"isLibraryOpen": false,
|
||||
"isLoading": false,
|
||||
"isMinimapEnabled": false,
|
||||
"isResizing": false,
|
||||
"isRotating": false,
|
||||
"lastPointerDownWith": "mouse",
|
||||
@@ -17189,6 +17243,7 @@ Object {
|
||||
"isBindingEnabled": true,
|
||||
"isLibraryOpen": false,
|
||||
"isLoading": false,
|
||||
"isMinimapEnabled": false,
|
||||
"isResizing": false,
|
||||
"isRotating": false,
|
||||
"lastPointerDownWith": "mouse",
|
||||
@@ -17443,6 +17498,7 @@ Object {
|
||||
"isBindingEnabled": true,
|
||||
"isLibraryOpen": false,
|
||||
"isLoading": false,
|
||||
"isMinimapEnabled": false,
|
||||
"isResizing": false,
|
||||
"isRotating": false,
|
||||
"lastPointerDownWith": "mouse",
|
||||
@@ -17769,6 +17825,7 @@ Object {
|
||||
"isBindingEnabled": true,
|
||||
"isLibraryOpen": false,
|
||||
"isLoading": false,
|
||||
"isMinimapEnabled": false,
|
||||
"isResizing": false,
|
||||
"isRotating": false,
|
||||
"lastPointerDownWith": "mouse",
|
||||
@@ -17868,6 +17925,7 @@ Object {
|
||||
"isBindingEnabled": true,
|
||||
"isLibraryOpen": false,
|
||||
"isLoading": false,
|
||||
"isMinimapEnabled": false,
|
||||
"isResizing": false,
|
||||
"isRotating": false,
|
||||
"lastPointerDownWith": "mouse",
|
||||
@@ -18031,6 +18089,7 @@ Object {
|
||||
"isBindingEnabled": true,
|
||||
"isLibraryOpen": false,
|
||||
"isLoading": false,
|
||||
"isMinimapEnabled": false,
|
||||
"isResizing": false,
|
||||
"isRotating": false,
|
||||
"lastPointerDownWith": "mouse",
|
||||
@@ -18851,6 +18910,7 @@ Object {
|
||||
"isBindingEnabled": true,
|
||||
"isLibraryOpen": false,
|
||||
"isLoading": false,
|
||||
"isMinimapEnabled": false,
|
||||
"isResizing": false,
|
||||
"isRotating": false,
|
||||
"lastPointerDownWith": "mouse",
|
||||
@@ -18950,6 +19010,7 @@ Object {
|
||||
"isBindingEnabled": true,
|
||||
"isLibraryOpen": false,
|
||||
"isLoading": false,
|
||||
"isMinimapEnabled": false,
|
||||
"isResizing": false,
|
||||
"isRotating": false,
|
||||
"lastPointerDownWith": "mouse",
|
||||
@@ -19703,6 +19764,7 @@ Object {
|
||||
"isBindingEnabled": true,
|
||||
"isLibraryOpen": false,
|
||||
"isLoading": false,
|
||||
"isMinimapEnabled": false,
|
||||
"isResizing": false,
|
||||
"isRotating": false,
|
||||
"lastPointerDownWith": "mouse",
|
||||
@@ -20107,6 +20169,7 @@ Object {
|
||||
"isBindingEnabled": true,
|
||||
"isLibraryOpen": false,
|
||||
"isLoading": false,
|
||||
"isMinimapEnabled": false,
|
||||
"isResizing": false,
|
||||
"isRotating": false,
|
||||
"lastPointerDownWith": "mouse",
|
||||
@@ -20379,6 +20442,7 @@ Object {
|
||||
"isBindingEnabled": true,
|
||||
"isLibraryOpen": false,
|
||||
"isLoading": false,
|
||||
"isMinimapEnabled": false,
|
||||
"isResizing": false,
|
||||
"isRotating": false,
|
||||
"lastPointerDownWith": "touch",
|
||||
@@ -20480,6 +20544,7 @@ Object {
|
||||
"isBindingEnabled": true,
|
||||
"isLibraryOpen": false,
|
||||
"isLoading": false,
|
||||
"isMinimapEnabled": false,
|
||||
"isResizing": false,
|
||||
"isRotating": false,
|
||||
"lastPointerDownWith": "mouse",
|
||||
@@ -20977,6 +21042,7 @@ Object {
|
||||
"isBindingEnabled": true,
|
||||
"isLibraryOpen": false,
|
||||
"isLoading": false,
|
||||
"isMinimapEnabled": false,
|
||||
"isResizing": false,
|
||||
"isRotating": false,
|
||||
"lastPointerDownWith": "mouse",
|
||||
@@ -21076,6 +21142,7 @@ Object {
|
||||
"isBindingEnabled": true,
|
||||
"isLibraryOpen": false,
|
||||
"isLoading": false,
|
||||
"isMinimapEnabled": false,
|
||||
"isResizing": false,
|
||||
"isRotating": false,
|
||||
"lastPointerDownWith": "mouse",
|
||||
|
||||
@@ -117,6 +117,7 @@ export type AppState = {
|
||||
shown: true;
|
||||
data: Spreadsheet;
|
||||
};
|
||||
isMinimapEnabled: boolean;
|
||||
};
|
||||
|
||||
export type NormalizedZoomValue = number & { _brand: "normalizedZoom" };
|
||||
|
||||
@@ -372,6 +372,9 @@ export const getVersion = () => {
|
||||
|
||||
// Adapted from https://github.com/Modernizr/Modernizr/blob/master/feature-detects/emoji.js
|
||||
export const supportsEmoji = () => {
|
||||
if (typeof document === "undefined") {
|
||||
return;
|
||||
}
|
||||
const canvas = document.createElement("canvas");
|
||||
const ctx = canvas.getContext("2d");
|
||||
if (!ctx) {
|
||||
|
||||
Reference in New Issue
Block a user