Fixing common package

This commit is contained in:
Marcel Mraz 2025-03-17 13:57:03 +01:00
parent aa873234ad
commit 44d8a6b4fe
No known key found for this signature in database
GPG key ID: 4EBD6E62DC830CD2
22 changed files with 182 additions and 88 deletions

13
packages/common/global.d.ts vendored Normal file
View file

@ -0,0 +1,13 @@
interface Window {
EXCALIDRAW_EXPORT_SOURCE: string;
}
interface ImportMetaEnv {
MODE: string;
DEV: string;
PROD: string;
}
interface ImportMeta {
readonly env: ImportMetaEnv;
}

7
packages/common/index.ts Normal file
View file

@ -0,0 +1,7 @@
export * from "./src/colors";
export * from "./src/constants";
export * from "./src/keys";
export * from "./src/points";
export * from "./src/random";
export * from "./src/url";
export * from "./src/utils";

View file

@ -48,8 +48,13 @@
]
},
"dependencies": {
"es6-promise-pool": "2.5.0",
"nanoid": "3.3.3",
"open-color": "1.9.1",
"roughjs": "4.6.4"
},
"devDependencies": {
"typescript": "4.9.4"
},
"bugs": "https://github.com/excalidraw/excalidraw/issues",
"repository": "https://github.com/excalidraw/excalidraw",

View file

@ -1,6 +1,6 @@
import oc from "open-color";
import type { Merge } from "./utility-types";
import type { Merge } from "@excalidraw/excalidraw/utility-types";
// FIXME can't put to utils.ts rn because of circular dependency
const pick = <R extends Record<string, any>, K extends readonly (keyof R)[]>(

View file

@ -1,7 +1,10 @@
import { COLOR_PALETTE } from "./colors";
import type {
ExcalidrawElement,
FontFamilyValues,
} from "@excalidraw/element/types";
import type { AppProps, AppState } from "@excalidraw/excalidraw/types";
import type { ExcalidrawElement, FontFamilyValues } from "./element/types";
import type { AppProps, AppState } from "./types";
import { COLOR_PALETTE } from "./colors";
export const isDarwin = /Mac|iPod|iPhone|iPad/.test(navigator.platform);
export const isWindows = /^Win/.test(navigator.platform);

View file

@ -1,6 +1,6 @@
import { isDarwin } from "./constants";
import type { ValueOf } from "@excalidraw/excalidraw/utility-types";
import type { ValueOf } from "../excalidraw/utility-types";
import { isDarwin } from "./constants";
export const CODES = {
EQUAL: "Equal",

View file

@ -0,0 +1,50 @@
import Pool from "es6-promise-pool";
// extending the missing types
// relying on the [Index, T] to keep a correct order
type TPromisePool<T, Index = number> = Pool<[Index, T][]> & {
addEventListener: (
type: "fulfilled",
listener: (event: { data: { result: [Index, T] } }) => void,
) => (event: { data: { result: [Index, T] } }) => void;
removeEventListener: (
type: "fulfilled",
listener: (event: { data: { result: [Index, T] } }) => void,
) => void;
};
export class PromisePool<T> {
private readonly pool: TPromisePool<T>;
private readonly entries: Record<number, T> = {};
constructor(
source: IterableIterator<Promise<void | readonly [number, T]>>,
concurrency: number,
) {
this.pool = new Pool(
source as unknown as () => void | PromiseLike<[number, T][]>,
concurrency,
) as TPromisePool<T>;
}
public all() {
const listener = (event: { data: { result: void | [number, T] } }) => {
if (event.data.result) {
// by default pool does not return the results, so we are gathering them manually
// with the correct call order (represented by the index in the tuple)
const [index, value] = event.data.result;
this.entries[index] = value;
}
};
this.pool.addEventListener("fulfilled", listener);
return this.pool.start().then(() => {
setTimeout(() => {
this.pool.removeEventListener("fulfilled", listener);
});
return Object.values(this.entries);
});
}
}

View file

@ -1,6 +1,28 @@
import Pool from "es6-promise-pool";
import { average } from "@excalidraw/math";
import type {
ExcalidrawBindableElement,
ExcalidrawElement,
FontFamilyValues,
FontString,
GroupId,
NonDeletedExcalidrawElement,
} from "@excalidraw/element/types";
import type {
ActiveTool,
AppState,
NullableGridSize,
ToolType,
UnsubscribeCallback,
Zoom,
} from "@excalidraw/excalidraw/types";
import type {
MaybePromise,
ResolutionType,
} from "@excalidraw/excalidraw/utility-types";
import { COLOR_PALETTE } from "./colors";
import {
DEFAULT_VERSION,
@ -11,19 +33,6 @@ import {
} from "./constants";
import type { EVENT } from "./constants";
import type {
ExcalidrawBindableElement,
FontFamilyValues,
FontString,
} from "./element/types";
import type {
ActiveTool,
AppState,
ToolType,
UnsubscribeCallback,
Zoom,
} from "./types";
import type { MaybePromise, ResolutionType } from "./utility-types";
let mockDateTime: string | null = null;
@ -1186,54 +1195,6 @@ export const safelyParseJSON = (json: string): Record<string, any> | null => {
return null;
}
};
// extending the missing types
// relying on the [Index, T] to keep a correct order
type TPromisePool<T, Index = number> = Pool<[Index, T][]> & {
addEventListener: (
type: "fulfilled",
listener: (event: { data: { result: [Index, T] } }) => void,
) => (event: { data: { result: [Index, T] } }) => void;
removeEventListener: (
type: "fulfilled",
listener: (event: { data: { result: [Index, T] } }) => void,
) => void;
};
export class PromisePool<T> {
private readonly pool: TPromisePool<T>;
private readonly entries: Record<number, T> = {};
constructor(
source: IterableIterator<Promise<void | readonly [number, T]>>,
concurrency: number,
) {
this.pool = new Pool(
source as unknown as () => void | PromiseLike<[number, T][]>,
concurrency,
) as TPromisePool<T>;
}
public all() {
const listener = (event: { data: { result: void | [number, T] } }) => {
if (event.data.result) {
// by default pool does not return the results, so we are gathering them manually
// with the correct call order (represented by the index in the tuple)
const [index, value] = event.data.result;
this.entries[index] = value;
}
};
this.pool.addEventListener("fulfilled", listener);
return this.pool.start().then(() => {
setTimeout(() => {
this.pool.removeEventListener("fulfilled", listener);
});
return Object.values(this.entries);
});
}
}
/**
* use when you need to render unsafe string as HTML attribute, but MAKE SURE
@ -1246,8 +1207,7 @@ export const escapeDoubleQuotes = (str: string) => {
export const castArray = <T>(value: T | T[]): T[] =>
Array.isArray(value) ? value : [value];
// TODO_SEP: perhaps could be refactored away?
// TODO_SEP: perhaps could be refactored away
// TODO: Rounding this point causes some shake when free drawing
export const getGridPoint = (

View file

@ -1,4 +1,4 @@
import { KEYS, matchKey } from "./keys";
import { KEYS, matchKey } from "../src/keys";
describe("key matcher", async () => {
it("should not match unexpected key", async () => {

View file

@ -1,4 +1,4 @@
import { normalizeLink } from "./url";
import { normalizeLink } from "../src/url";
describe("normalizeLink", () => {
// NOTE not an extensive XSS test suite, just to check if we're not

56
packages/common/yarn.lock Normal file
View file

@ -0,0 +1,56 @@
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
# yarn lockfile v1
es6-promise-pool@2.5.0:
version "2.5.0"
resolved "https://registry.yarnpkg.com/es6-promise-pool/-/es6-promise-pool-2.5.0.tgz#147c612b36b47f105027f9d2bf54a598a99d9ccb"
integrity sha512-VHErXfzR/6r/+yyzPKeBvO0lgjfC5cbDCQWjWwMZWSb6YU39TGIl51OUmCfWCq4ylMdJSB8zkz2vIuIeIxXApA==
hachure-fill@^0.5.2:
version "0.5.2"
resolved "https://registry.yarnpkg.com/hachure-fill/-/hachure-fill-0.5.2.tgz#d19bc4cc8750a5962b47fb1300557a85fcf934cc"
integrity sha512-3GKBOn+m2LX9iq+JC1064cSFprJY4jL1jCXTcpnfER5HYE2l/4EfWSGzkPa/ZDBmYI0ZOEj5VHV/eKnPGkHuOg==
nanoid@3.3.3:
version "3.3.3"
resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.3.tgz#fd8e8b7aa761fe807dba2d1b98fb7241bb724a25"
integrity sha512-p1sjXuopFs0xg+fPASzQ28agW1oHD7xDsd9Xkf3T15H3c/cifrFHVwrh74PdoklAPi+i7MdRsE47vm2r6JoB+w==
open-color@1.9.1:
version "1.9.1"
resolved "https://registry.yarnpkg.com/open-color/-/open-color-1.9.1.tgz#a6e6328f60eff7aa60e3e8fcfa50f53ff3eece35"
integrity sha512-vCseG/EQ6/RcvxhUcGJiHViOgrtz4x0XbZepXvKik66TMGkvbmjeJrKFyBEx6daG5rNyyd14zYXhz0hZVwQFOw==
path-data-parser@0.1.0, path-data-parser@^0.1.0:
version "0.1.0"
resolved "https://registry.yarnpkg.com/path-data-parser/-/path-data-parser-0.1.0.tgz#8f5ba5cc70fc7becb3dcefaea08e2659aba60b8c"
integrity sha512-NOnmBpt5Y2RWbuv0LMzsayp3lVylAHLPUTut412ZA3l+C4uw4ZVkQbjShYCQ8TCpUMdPapr4YjUqLYD6v68j+w==
points-on-curve@0.2.0, points-on-curve@^0.2.0:
version "0.2.0"
resolved "https://registry.yarnpkg.com/points-on-curve/-/points-on-curve-0.2.0.tgz#7dbb98c43791859434284761330fa893cb81b4d1"
integrity sha512-0mYKnYYe9ZcqMCWhUjItv/oHjvgEsfKvnUTg8sAtnHr3GVy7rGkXCb6d5cSyqrWqL4k81b9CPg3urd+T7aop3A==
points-on-path@^0.2.1:
version "0.2.1"
resolved "https://registry.yarnpkg.com/points-on-path/-/points-on-path-0.2.1.tgz#553202b5424c53bed37135b318858eacff85dd52"
integrity sha512-25ClnWWuw7JbWZcgqY/gJ4FQWadKxGWk+3kR/7kD0tCaDtPPMj7oHu2ToLaVhfpnHrZzYby2w6tUA0eOIuUg8g==
dependencies:
path-data-parser "0.1.0"
points-on-curve "0.2.0"
roughjs@4.6.4:
version "4.6.4"
resolved "https://registry.yarnpkg.com/roughjs/-/roughjs-4.6.4.tgz#b6f39b44645854a6e0a4a28b078368701eb7f939"
integrity sha512-s6EZ0BntezkFYMf/9mGn7M8XGIoaav9QQBCnJROWB3brUWQ683Q2LbRD/hq0Z3bAJ/9NVpU/5LpiTWvQMyLDhw==
dependencies:
hachure-fill "^0.5.2"
path-data-parser "^0.1.0"
points-on-curve "^0.2.0"
points-on-path "^0.2.1"
typescript@4.9.4:
version "4.9.4"
resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.9.4.tgz#a2a3d2756c079abda241d75f149df9d561091e78"
integrity sha512-Uz+dTXYzxXXbsFpM86Wh3dKCxrQqUcVMxwU54orwlJjOpO3ao8L7j5lH+dWfTwgCwIuM9GQ2kvVotzYJMXTBZg==