Merge branch 'master' into mrazator/separate-element-into-standalone-package

This commit is contained in:
Marcel Mraz 2025-03-25 10:05:50 +01:00
commit e50f78e9d2
No known key found for this signature in database
GPG key ID: 4EBD6E62DC830CD2
15 changed files with 50 additions and 48 deletions

View file

@ -29,6 +29,7 @@ import {
preventUnload, preventUnload,
resolvablePromise, resolvablePromise,
isRunningInIframe, isRunningInIframe,
isDevEnv,
} from "@excalidraw/common"; } from "@excalidraw/common";
import polyfill from "@excalidraw/excalidraw/polyfill"; import polyfill from "@excalidraw/excalidraw/polyfill";
import { useCallback, useEffect, useRef, useState } from "react"; import { useCallback, useEffect, useRef, useState } from "react";
@ -382,7 +383,7 @@ const ExcalidrawWrapper = () => {
const [, forceRefresh] = useState(false); const [, forceRefresh] = useState(false);
useEffect(() => { useEffect(() => {
if (import.meta.env.DEV) { if (isDevEnv()) {
const debugState = loadSavedDebugState(); const debugState = loadSavedDebugState();
if (debugState.enabled && !window.visualDebug) { if (debugState.enabled && !window.visualDebug) {

View file

@ -6,12 +6,14 @@ import {
reconcileElements, reconcileElements,
} from "@excalidraw/excalidraw"; } from "@excalidraw/excalidraw";
import { ErrorDialog } from "@excalidraw/excalidraw/components/ErrorDialog"; import { ErrorDialog } from "@excalidraw/excalidraw/components/ErrorDialog";
import { APP_NAME, ENV, EVENT } from "@excalidraw/common"; import { APP_NAME, EVENT } from "@excalidraw/common";
import { import {
IDLE_THRESHOLD, IDLE_THRESHOLD,
ACTIVE_THRESHOLD, ACTIVE_THRESHOLD,
UserIdleState, UserIdleState,
assertNever, assertNever,
isDevEnv,
isTestEnv,
preventUnload, preventUnload,
resolvablePromise, resolvablePromise,
throttleRAF, throttleRAF,
@ -239,7 +241,7 @@ class Collab extends PureComponent<CollabProps, CollabState> {
appJotaiStore.set(collabAPIAtom, collabAPI); appJotaiStore.set(collabAPIAtom, collabAPI);
if (import.meta.env.MODE === ENV.TEST || import.meta.env.DEV) { if (isTestEnv() || isDevEnv()) {
window.collab = window.collab || ({} as Window["collab"]); window.collab = window.collab || ({} as Window["collab"]);
Object.defineProperties(window, { Object.defineProperties(window, {
collab: { collab: {
@ -1012,7 +1014,7 @@ declare global {
} }
} }
if (import.meta.env.MODE === ENV.TEST || import.meta.env.DEV) { if (isTestEnv() || isDevEnv()) {
window.collab = window.collab || ({} as Window["collab"]); window.collab = window.collab || ({} as Window["collab"]);
} }

View file

@ -6,6 +6,8 @@ import {
import { MainMenu } from "@excalidraw/excalidraw/index"; import { MainMenu } from "@excalidraw/excalidraw/index";
import React from "react"; import React from "react";
import { isDevEnv } from "@excalidraw/common";
import type { Theme } from "@excalidraw/element/types"; import type { Theme } from "@excalidraw/element/types";
import { LanguageList } from "../app-language/LanguageList"; import { LanguageList } from "../app-language/LanguageList";
@ -57,7 +59,7 @@ export const AppMainMenu: React.FC<{
> >
{isExcalidrawPlusSignedUser ? "Sign in" : "Sign up"} {isExcalidrawPlusSignedUser ? "Sign in" : "Sign up"}
</MainMenu.ItemLink> </MainMenu.ItemLink>
{import.meta.env.DEV && ( {isDevEnv() && (
<MainMenu.Item <MainMenu.Item
icon={eyeIcon} icon={eyeIcon}
onClick={() => { onClick={() => {

View file

@ -17,6 +17,7 @@ import type {
import { COLOR_PALETTE } from "./colors"; import { COLOR_PALETTE } from "./colors";
import { import {
DEFAULT_VERSION, DEFAULT_VERSION,
ENV,
FONT_FAMILY, FONT_FAMILY,
getFontFamilyFallbacks, getFontFamilyFallbacks,
isDarwin, isDarwin,
@ -171,7 +172,7 @@ export const throttleRAF = <T extends any[]>(
}; };
const ret = (...args: T) => { const ret = (...args: T) => {
if (import.meta.env.MODE === "test") { if (isTestEnv()) {
fn(...args); fn(...args);
return; return;
} }
@ -732,9 +733,9 @@ export const arrayToList = <T>(array: readonly T[]): Node<T>[] =>
return acc; return acc;
}, [] as Node<T>[]); }, [] as Node<T>[]);
export const isTestEnv = () => import.meta.env.MODE === "test"; export const isTestEnv = () => import.meta.env.MODE === ENV.TEST;
export const isDevEnv = () => import.meta.env.MODE === "development"; export const isDevEnv = () => import.meta.env.MODE === ENV.DEVELOPMENT;
export const isServerEnv = () => export const isServerEnv = () =>
typeof process !== "undefined" && !!process?.env?.NODE_ENV; typeof process !== "undefined" && !!process?.env?.NODE_ENV;

View file

@ -19,6 +19,7 @@ import {
isAnyTrue, isAnyTrue,
tupleToCoors, tupleToCoors,
getSizeFromPoints, getSizeFromPoints,
isDevEnv,
} from "@excalidraw/common"; } from "@excalidraw/common";
import type { AppState } from "@excalidraw/excalidraw/types"; import type { AppState } from "@excalidraw/excalidraw/types";
@ -254,7 +255,7 @@ const handleSegmentRenormalization = (
); );
} }
import.meta.env.DEV && isDevEnv() &&
invariant( invariant(
validateElbowPoints(nextPoints), validateElbowPoints(nextPoints),
"Invalid elbow points with fixed segments", "Invalid elbow points with fixed segments",

View file

@ -1,4 +1,4 @@
import { ENV } from "@excalidraw/common"; import { isDevEnv, isTestEnv } from "@excalidraw/common";
import { charWidth, getLineWidth } from "./textMeasurements"; import { charWidth, getLineWidth } from "./textMeasurements";
@ -562,7 +562,7 @@ const isSingleCharacter = (maybeSingleCharacter: string) => {
* Invariant for the word wrapping algorithm. * Invariant for the word wrapping algorithm.
*/ */
const satisfiesWordInvariant = (word: string) => { const satisfiesWordInvariant = (word: string) => {
if (import.meta.env.MODE === ENV.TEST || import.meta.env.DEV) { if (isTestEnv() || isDevEnv()) {
if (/\s/.test(word)) { if (/\s/.test(word)) {
throw new Error("Word should not contain any whitespaces!"); throw new Error("Word should not contain any whitespaces!");
} }

View file

@ -1,4 +1,7 @@
// place here categories that you want to track. We want to track just a // place here categories that you want to track. We want to track just a
import { isDevEnv } from "@excalidraw/common";
// small subset of categories at a given time. // small subset of categories at a given time.
const ALLOWED_CATEGORIES_TO_TRACK = new Set(["command_palette", "export"]); const ALLOWED_CATEGORIES_TO_TRACK = new Set(["command_palette", "export"]);
@ -21,7 +24,7 @@ export const trackEvent = (
return; return;
} }
if (import.meta.env.DEV) { if (isDevEnv()) {
// comment out to debug in dev // comment out to debug in dev
return; return;
} }

View file

@ -1,9 +1,10 @@
import { import {
ENV,
arrayToMap, arrayToMap,
arrayToObject, arrayToObject,
assertNever, assertNever,
isDevEnv,
isShallowEqual, isShallowEqual,
isTestEnv,
toBrandedType, toBrandedType,
} from "@excalidraw/common"; } from "@excalidraw/common";
import { import {
@ -527,7 +528,7 @@ export class AppStateChange implements Change<AppState> {
// shouldn't really happen, but just in case // shouldn't really happen, but just in case
console.error(`Couldn't apply appstate change`, e); console.error(`Couldn't apply appstate change`, e);
if (import.meta.env.DEV || import.meta.env.MODE === ENV.TEST) { if (isTestEnv() || isDevEnv()) {
throw e; throw e;
} }
@ -565,7 +566,7 @@ export class AppStateChange implements Change<AppState> {
// if postprocessing fails it does not make sense to bubble up, but let's make sure we know about it // if postprocessing fails it does not make sense to bubble up, but let's make sure we know about it
console.error(`Couldn't postprocess appstate change deltas.`); console.error(`Couldn't postprocess appstate change deltas.`);
if (import.meta.env.DEV || import.meta.env.MODE === ENV.TEST) { if (isTestEnv() || isDevEnv()) {
throw e; throw e;
} }
} finally { } finally {
@ -855,7 +856,7 @@ export class ElementsChange implements Change<SceneElementsMap> {
change = new ElementsChange(added, removed, updated); change = new ElementsChange(added, removed, updated);
} }
if (import.meta.env.DEV || import.meta.env.MODE === ENV.TEST) { if (isTestEnv() || isDevEnv()) {
ElementsChange.validate(change, "added", this.satisfiesAddition); ElementsChange.validate(change, "added", this.satisfiesAddition);
ElementsChange.validate(change, "removed", this.satisfiesRemoval); ElementsChange.validate(change, "removed", this.satisfiesRemoval);
ElementsChange.validate(change, "updated", this.satisfiesUpdate); ElementsChange.validate(change, "updated", this.satisfiesUpdate);
@ -1119,7 +1120,7 @@ export class ElementsChange implements Change<SceneElementsMap> {
} catch (e) { } catch (e) {
console.error(`Couldn't apply elements change`, e); console.error(`Couldn't apply elements change`, e);
if (import.meta.env.DEV || import.meta.env.MODE === ENV.TEST) { if (isTestEnv() || isDevEnv()) {
throw e; throw e;
} }
@ -1150,7 +1151,7 @@ export class ElementsChange implements Change<SceneElementsMap> {
e, e,
); );
if (import.meta.env.DEV || import.meta.env.MODE === ENV.TEST) { if (isTestEnv() || isDevEnv()) {
throw e; throw e;
} }
} finally { } finally {
@ -1564,7 +1565,7 @@ export class ElementsChange implements Change<SceneElementsMap> {
// if postprocessing fails, it does not make sense to bubble up, but let's make sure we know about it // if postprocessing fails, it does not make sense to bubble up, but let's make sure we know about it
console.error(`Couldn't postprocess elements change deltas.`); console.error(`Couldn't postprocess elements change deltas.`);
if (import.meta.env.DEV || import.meta.env.MODE === ENV.TEST) { if (isTestEnv() || isDevEnv()) {
throw e; throw e;
} }
} finally { } finally {

View file

@ -8,6 +8,7 @@ import {
DEFAULT_FONT_SIZE, DEFAULT_FONT_SIZE,
VERTICAL_ALIGN, VERTICAL_ALIGN,
randomId, randomId,
isDevEnv,
} from "@excalidraw/common"; } from "@excalidraw/common";
import { import {
@ -376,7 +377,7 @@ const chartTypeBar = (
y, y,
groupId, groupId,
backgroundColor, backgroundColor,
!!import.meta.env.DEV, isDevEnv(),
), ),
]; ];
}; };
@ -458,7 +459,7 @@ const chartTypeLine = (
y, y,
groupId, groupId,
backgroundColor, backgroundColor,
!!import.meta.env.DEV, isDevEnv(),
), ),
line, line,
...lines, ...lines,

View file

@ -35,7 +35,6 @@ import {
DRAGGING_THRESHOLD, DRAGGING_THRESHOLD,
ELEMENT_SHIFT_TRANSLATE_AMOUNT, ELEMENT_SHIFT_TRANSLATE_AMOUNT,
ELEMENT_TRANSLATE_AMOUNT, ELEMENT_TRANSLATE_AMOUNT,
ENV,
EVENT, EVENT,
FRAME_STYLE, FRAME_STYLE,
IMAGE_MIME_TYPES, IMAGE_MIME_TYPES,
@ -91,6 +90,7 @@ import {
easeToValuesRAF, easeToValuesRAF,
muteFSAbortError, muteFSAbortError,
isTestEnv, isTestEnv,
isDevEnv,
easeOut, easeOut,
updateStable, updateStable,
addEventListener, addEventListener,
@ -403,7 +403,6 @@ import {
} from "../scene"; } from "../scene";
import Scene from "../scene/Scene"; import Scene from "../scene/Scene";
import { getStateForZoom } from "../scene/zoom"; import { getStateForZoom } from "../scene/zoom";
import { import {
dataURLToFile, dataURLToFile,
dataURLToString, dataURLToString,
@ -2493,7 +2492,7 @@ class App extends React.Component<AppProps, AppState> {
this.excalidrawContainerValue.container = this.excalidrawContainerValue.container =
this.excalidrawContainerRef.current; this.excalidrawContainerRef.current;
if (import.meta.env.MODE === ENV.TEST || import.meta.env.DEV) { if (isTestEnv() || isDevEnv()) {
const setState = this.setState.bind(this); const setState = this.setState.bind(this);
Object.defineProperties(window.h, { Object.defineProperties(window.h, {
state: { state: {
@ -11119,7 +11118,7 @@ declare global {
} }
export const createTestHook = () => { export const createTestHook = () => {
if (import.meta.env.MODE === ENV.TEST || import.meta.env.DEV) { if (isTestEnv() || isDevEnv()) {
window.h = window.h || ({} as Window["h"]); window.h = window.h || ({} as Window["h"]);
Object.defineProperties(window.h, { Object.defineProperties(window.h, {

View file

@ -9,7 +9,7 @@ import React, {
useCallback, useCallback,
} from "react"; } from "react";
import { EVENT, KEYS, updateObject } from "@excalidraw/common"; import { EVENT, isDevEnv, KEYS, updateObject } from "@excalidraw/common";
import { useUIAppState } from "../../context/ui-appState"; import { useUIAppState } from "../../context/ui-appState";
import { atom, useSetAtom } from "../../editor-jotai"; import { atom, useSetAtom } from "../../editor-jotai";
@ -51,7 +51,7 @@ export const SidebarInner = forwardRef(
}: SidebarProps & Omit<React.RefAttributes<HTMLDivElement>, "onSelect">, }: SidebarProps & Omit<React.RefAttributes<HTMLDivElement>, "onSelect">,
ref: React.ForwardedRef<HTMLDivElement>, ref: React.ForwardedRef<HTMLDivElement>,
) => { ) => {
if (import.meta.env.DEV && onDock && docked == null) { if (isDevEnv() && onDock && docked == null) {
console.warn( console.warn(
"Sidebar: `docked` must be set when `onDock` is supplied for the sidebar to be user-dockable. To hide this message, either pass `docked` or remove `onDock`", "Sidebar: `docked` must be set when `onDock` is supplied for the sidebar to be user-dockable. To hide this message, either pass `docked` or remove `onDock`",
); );

View file

@ -1,6 +1,6 @@
import throttle from "lodash.throttle"; import throttle from "lodash.throttle";
import { ENV, arrayToMap } from "@excalidraw/common"; import { arrayToMap, isDevEnv, isTestEnv } from "@excalidraw/common";
import { import {
orderByFractionalIndex, orderByFractionalIndex,
@ -49,11 +49,7 @@ const validateIndicesThrottled = throttle(
localElements: readonly OrderedExcalidrawElement[], localElements: readonly OrderedExcalidrawElement[],
remoteElements: readonly RemoteExcalidrawElement[], remoteElements: readonly RemoteExcalidrawElement[],
) => { ) => {
if ( if (isDevEnv() || isTestEnv() || window?.DEBUG_FRACTIONAL_INDICES) {
import.meta.env.DEV ||
import.meta.env.MODE === ENV.TEST ||
window?.DEBUG_FRACTIONAL_INDICES
) {
// create new instances due to the mutation // create new instances due to the mutation
const elements = syncInvalidIndices( const elements = syncInvalidIndices(
orderedElements.map((x) => ({ ...x })), orderedElements.map((x) => ({ ...x })),
@ -61,9 +57,7 @@ const validateIndicesThrottled = throttle(
validateFractionalIndices(elements, { validateFractionalIndices(elements, {
// throw in dev & test only, to remain functional on `DEBUG_FRACTIONAL_INDICES` // throw in dev & test only, to remain functional on `DEBUG_FRACTIONAL_INDICES`
shouldThrow: Boolean( shouldThrow: isTestEnv() || isDevEnv(),
import.meta.env.DEV || import.meta.env.MODE === ENV.TEST,
),
includeBoundTextValidation: true, includeBoundTextValidation: true,
reconciliationContext: { reconciliationContext: {
localElements, localElements,

View file

@ -1,3 +1,5 @@
import { isDevEnv } from "@excalidraw/common";
import type { NestedKeyOf } from "@excalidraw/common/utility-types"; import type { NestedKeyOf } from "@excalidraw/common/utility-types";
import { useAtomValue, editorJotaiStore, atom } from "./editor-jotai"; import { useAtomValue, editorJotaiStore, atom } from "./editor-jotai";
@ -73,7 +75,7 @@ export const languages: Language[] = [
]; ];
const TEST_LANG_CODE = "__test__"; const TEST_LANG_CODE = "__test__";
if (import.meta.env.DEV) { if (isDevEnv()) {
languages.unshift( languages.unshift(
{ code: TEST_LANG_CODE, label: "test language" }, { code: TEST_LANG_CODE, label: "test language" },
{ {

View file

@ -1,10 +1,11 @@
import throttle from "lodash.throttle"; import throttle from "lodash.throttle";
import { import {
ENV,
randomInteger, randomInteger,
arrayToMap, arrayToMap,
toBrandedType, toBrandedType,
isDevEnv,
isTestEnv,
} from "@excalidraw/common"; } from "@excalidraw/common";
import { isNonDeletedElement } from "@excalidraw/element"; import { isNonDeletedElement } from "@excalidraw/element";
import { isFrameLikeElement } from "@excalidraw/element/typeChecks"; import { isFrameLikeElement } from "@excalidraw/element/typeChecks";
@ -62,16 +63,10 @@ const getNonDeletedElements = <T extends ExcalidrawElement>(
const validateIndicesThrottled = throttle( const validateIndicesThrottled = throttle(
(elements: readonly ExcalidrawElement[]) => { (elements: readonly ExcalidrawElement[]) => {
if ( if (isDevEnv() || isTestEnv() || window?.DEBUG_FRACTIONAL_INDICES) {
import.meta.env.DEV ||
import.meta.env.MODE === ENV.TEST ||
window?.DEBUG_FRACTIONAL_INDICES
) {
validateFractionalIndices(elements, { validateFractionalIndices(elements, {
// throw only in dev & test, to remain functional on `DEBUG_FRACTIONAL_INDICES` // throw only in dev & test, to remain functional on `DEBUG_FRACTIONAL_INDICES`
shouldThrow: Boolean( shouldThrow: isDevEnv() || isTestEnv(),
import.meta.env.DEV || import.meta.env.MODE === ENV.TEST,
),
includeBoundTextValidation: true, includeBoundTextValidation: true,
}); });
} }

View file

@ -1,4 +1,4 @@
import { ENV, isShallowEqual } from "@excalidraw/common"; import { isDevEnv, isShallowEqual, isTestEnv } from "@excalidraw/common";
import { deepCopyElement } from "@excalidraw/element/duplicate"; import { deepCopyElement } from "@excalidraw/element/duplicate";
@ -261,7 +261,7 @@ export class Store implements IStore {
const message = `There can be at most three store actions scheduled at the same time, but there are "${this.scheduledActions.size}".`; const message = `There can be at most three store actions scheduled at the same time, but there are "${this.scheduledActions.size}".`;
console.error(message, this.scheduledActions.values()); console.error(message, this.scheduledActions.values());
if (import.meta.env.DEV || import.meta.env.MODE === ENV.TEST) { if (isTestEnv() || isDevEnv()) {
throw new Error(message); throw new Error(message);
} }
} }