mirror of
https://github.com/excalidraw/excalidraw.git
synced 2025-12-05 03:55:06 +01:00
Compare commits
7 Commits
release
...
feat/bette
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a9f57f0fc1 | ||
|
|
4a67c3e9b7 | ||
|
|
fdb8aaf44e | ||
|
|
6f4081e371 | ||
|
|
d080833f4d | ||
|
|
451bcac0b7 | ||
|
|
06f01e11f8 |
18
README.md
18
README.md
@@ -23,23 +23,17 @@
|
||||
<br />
|
||||
<p align="center">
|
||||
<a href="https://github.com/excalidraw/excalidraw/blob/master/LICENSE">
|
||||
<img alt="Excalidraw is released under the MIT license." src="https://img.shields.io/badge/license-MIT-blue.svg" />
|
||||
</a>
|
||||
<img alt="Excalidraw is released under the MIT license." src="https://img.shields.io/badge/license-MIT-blue.svg" /></a>
|
||||
<a href="https://www.npmjs.com/package/@excalidraw/excalidraw">
|
||||
<img alt="npm downloads/month" src="https://img.shields.io/npm/dm/@excalidraw/excalidraw" />
|
||||
</a>
|
||||
<img alt="npm downloads/month" src="https://img.shields.io/npm/dm/@excalidraw/excalidraw" /></a>
|
||||
<a href="https://docs.excalidraw.com/docs/introduction/contributing">
|
||||
<img alt="PRs welcome!" src="https://img.shields.io/badge/PRs-welcome-brightgreen.svg?style=flat" />
|
||||
</a>
|
||||
<img alt="PRs welcome!" src="https://img.shields.io/badge/PRs-welcome-brightgreen.svg?style=flat" /></a>
|
||||
<a href="https://discord.gg/UexuTaE">
|
||||
<img alt="Chat on Discord" src="https://img.shields.io/discord/723672430744174682?color=738ad6&label=Chat%20on%20Discord&logo=discord&logoColor=ffffff&widge=false"/>
|
||||
</a>
|
||||
<img alt="Chat on Discord" src="https://img.shields.io/discord/723672430744174682?color=738ad6&label=Chat%20on%20Discord&logo=discord&logoColor=ffffff&widge=false"/></a>
|
||||
<a href="https://deepwiki.com/excalidraw/excalidraw">
|
||||
<img alt="Ask DeepWiki" src="https://deepwiki.com/badge.svg" />
|
||||
</a>
|
||||
<img alt="Ask DeepWiki" src="https://deepwiki.com/badge.svg" /></a>
|
||||
<a href="https://twitter.com/excalidraw">
|
||||
<img alt="Follow Excalidraw on Twitter" src="https://img.shields.io/twitter/follow/excalidraw.svg?label=follow+@excalidraw&style=social&logo=twitter"/>
|
||||
</a>
|
||||
<img alt="Follow Excalidraw on Twitter" src="https://img.shields.io/twitter/follow/excalidraw.svg?label=follow+@excalidraw&style=social&logo=twitter"/></a>
|
||||
</p>
|
||||
|
||||
<div align="center">
|
||||
|
||||
@@ -441,7 +441,7 @@ class Collab extends PureComponent<CollabProps, CollabState> {
|
||||
};
|
||||
|
||||
private decryptPayload = async (
|
||||
iv: Uint8Array,
|
||||
iv: Uint8Array<ArrayBuffer>,
|
||||
encryptedData: ArrayBuffer,
|
||||
decryptionKey: string,
|
||||
): Promise<ValueOf<SocketUpdateDataSource>> => {
|
||||
@@ -562,7 +562,7 @@ class Collab extends PureComponent<CollabProps, CollabState> {
|
||||
// All socket listeners are moving to Portal
|
||||
this.portal.socket.on(
|
||||
"client-broadcast",
|
||||
async (encryptedData: ArrayBuffer, iv: Uint8Array) => {
|
||||
async (encryptedData: ArrayBuffer, iv: Uint8Array<ArrayBuffer>) => {
|
||||
if (!this.portal.roomKey) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -105,8 +105,8 @@ const decryptElements = async (
|
||||
data: FirebaseStoredScene,
|
||||
roomKey: string,
|
||||
): Promise<readonly ExcalidrawElement[]> => {
|
||||
const ciphertext = data.ciphertext.toUint8Array();
|
||||
const iv = data.iv.toUint8Array();
|
||||
const ciphertext = data.ciphertext.toUint8Array() as Uint8Array<ArrayBuffer>;
|
||||
const iv = data.iv.toUint8Array() as Uint8Array<ArrayBuffer>;
|
||||
|
||||
const decrypted = await decryptData(iv, ciphertext, roomKey);
|
||||
const decodedData = new TextDecoder("utf-8").decode(
|
||||
|
||||
@@ -34,7 +34,7 @@
|
||||
"prettier": "2.6.2",
|
||||
"rewire": "6.0.0",
|
||||
"rimraf": "^5.0.0",
|
||||
"typescript": "4.9.4",
|
||||
"typescript": "5.9.3",
|
||||
"vite": "5.0.12",
|
||||
"vite-plugin-checker": "0.7.2",
|
||||
"vite-plugin-ejs": "1.7.0",
|
||||
|
||||
255
packages/element/src/freedraw.ts
Normal file
255
packages/element/src/freedraw.ts
Normal file
@@ -0,0 +1,255 @@
|
||||
import {
|
||||
type GlobalPoint,
|
||||
type LineSegment,
|
||||
lineSegment,
|
||||
lineSegmentIntersectionPoints,
|
||||
type LocalPoint,
|
||||
pointDistanceSq,
|
||||
pointFrom,
|
||||
pointFromVector,
|
||||
vectorAntiNormal,
|
||||
vectorFromPoint,
|
||||
vectorNormal,
|
||||
vectorNormalize,
|
||||
vectorScale,
|
||||
} from "@excalidraw/math";
|
||||
import { debugDrawLine } from "@excalidraw/common";
|
||||
|
||||
import { type ExcalidrawFreeDrawElement } from "./types";
|
||||
|
||||
const offset = (
|
||||
x: number,
|
||||
y: number,
|
||||
pressure: number,
|
||||
direction: "left" | "right",
|
||||
origin: LocalPoint,
|
||||
) => {
|
||||
const p = pointFrom<LocalPoint>(x, y);
|
||||
const v = vectorNormalize(vectorFromPoint(p, origin));
|
||||
const normal = direction === "left" ? vectorNormal(v) : vectorAntiNormal(v);
|
||||
const scaled = vectorScale(normal, pressure / 2);
|
||||
|
||||
return pointFromVector(scaled, origin);
|
||||
};
|
||||
|
||||
function generateSegments(
|
||||
input:
|
||||
| readonly [x: number, y: number, pressure: number][]
|
||||
| readonly [x: number, y: number][],
|
||||
element: ExcalidrawFreeDrawElement,
|
||||
pressureMultiplier: number = 1,
|
||||
minimumPressure: number = 1,
|
||||
): LineSegment<LocalPoint>[] {
|
||||
if (input.length < 3) {
|
||||
return [];
|
||||
}
|
||||
|
||||
let idx = 0;
|
||||
const segments = Array(input.length * 4 - 4);
|
||||
|
||||
segments[idx++] = lineSegment(
|
||||
offset(
|
||||
input[1][0],
|
||||
input[1][1],
|
||||
Math.max((input[1][2] ?? 5) * pressureMultiplier, minimumPressure),
|
||||
"left",
|
||||
pointFrom<LocalPoint>(input[0][0], input[0][1]),
|
||||
),
|
||||
offset(
|
||||
input[0][0],
|
||||
input[0][1],
|
||||
Math.max((input[1][2] ?? 5) * pressureMultiplier, minimumPressure),
|
||||
"right",
|
||||
pointFrom<LocalPoint>(input[1][0], input[1][1]),
|
||||
),
|
||||
);
|
||||
|
||||
for (let i = 2; i < input.length; i++) {
|
||||
const a = segments[idx - 1][1];
|
||||
const b = offset(
|
||||
input[i][0],
|
||||
input[i][1],
|
||||
Math.max((input[1][2] ?? 5) * pressureMultiplier, minimumPressure),
|
||||
"left",
|
||||
pointFrom<LocalPoint>(input[i - 1][0], input[i - 1][1]),
|
||||
);
|
||||
const c = offset(
|
||||
input[i - 1][0],
|
||||
input[i - 1][1],
|
||||
Math.max((input[1][2] ?? 5) * pressureMultiplier, minimumPressure),
|
||||
"right",
|
||||
pointFrom<LocalPoint>(input[i][0], input[i][1]),
|
||||
);
|
||||
|
||||
segments[idx++] = lineSegment(a, b); // Bridge segment
|
||||
segments[idx++] = lineSegment(b, c); // Main segment
|
||||
}
|
||||
|
||||
// Turnaround segments
|
||||
const prev = segments[idx - 1][1];
|
||||
segments[idx++] = lineSegment(
|
||||
prev,
|
||||
pointFrom<LocalPoint>(
|
||||
input[input.length - 1][0],
|
||||
input[input.length - 1][1],
|
||||
),
|
||||
);
|
||||
segments[idx++] = lineSegment(
|
||||
pointFrom<LocalPoint>(
|
||||
input[input.length - 1][0],
|
||||
input[input.length - 1][1],
|
||||
),
|
||||
offset(
|
||||
input[input.length - 2][0],
|
||||
input[input.length - 2][1],
|
||||
Math.max((input[1][2] ?? 5) * pressureMultiplier, minimumPressure),
|
||||
"left",
|
||||
pointFrom<LocalPoint>(
|
||||
input[input.length - 1][0],
|
||||
input[input.length - 1][1],
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
for (let i = input.length - 2; i > 0; i--) {
|
||||
const a = segments[idx - 1][1];
|
||||
const b = offset(
|
||||
input[i + 1][0],
|
||||
input[i + 1][1],
|
||||
Math.max((input[1][2] ?? 5) * pressureMultiplier, minimumPressure),
|
||||
"right",
|
||||
pointFrom<LocalPoint>(input[i][0], input[i][1]),
|
||||
);
|
||||
const c = offset(
|
||||
input[i - 1][0],
|
||||
input[i - 1][1],
|
||||
Math.max((input[1][2] ?? 5) * pressureMultiplier, minimumPressure),
|
||||
"left",
|
||||
pointFrom<LocalPoint>(input[i][0], input[i][1]),
|
||||
);
|
||||
|
||||
segments[idx++] = lineSegment(a, b); // Main segment
|
||||
segments[idx++] = lineSegment(b, c); // Bridge segment
|
||||
}
|
||||
|
||||
const last = segments[idx - 1][1];
|
||||
segments[idx++] = lineSegment(
|
||||
last,
|
||||
offset(
|
||||
input[1][0],
|
||||
input[1][1],
|
||||
Math.max((input[1][2] ?? 5) * pressureMultiplier, minimumPressure),
|
||||
"right",
|
||||
pointFrom<LocalPoint>(input[0][0], input[0][1]),
|
||||
),
|
||||
);
|
||||
|
||||
// Closing cap
|
||||
segments[idx++] = lineSegment(
|
||||
segments[idx - 2][1],
|
||||
pointFrom<LocalPoint>(input[0][0], input[0][1]),
|
||||
);
|
||||
segments[idx++] = lineSegment(
|
||||
pointFrom<LocalPoint>(input[0][0], input[0][1]),
|
||||
segments[0][0],
|
||||
);
|
||||
|
||||
return segments;
|
||||
}
|
||||
|
||||
export function getStroke(
|
||||
input:
|
||||
| readonly [x: number, y: number, pressure: number][]
|
||||
| readonly [x: number, y: number][],
|
||||
options: any,
|
||||
element: ExcalidrawFreeDrawElement,
|
||||
): LocalPoint[] {
|
||||
const segments: (LineSegment<LocalPoint> | undefined)[] = generateSegments(
|
||||
input,
|
||||
element,
|
||||
);
|
||||
|
||||
const MIN_DIST_SQ = 0.2 ** 2;
|
||||
for (let j = 0; j < segments.length; j++) {
|
||||
for (let i = j + 1; i < segments.length; i++) {
|
||||
const a = segments[j];
|
||||
const b = segments[i];
|
||||
if (!a || !b) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const intersection = lineSegmentIntersectionPoints(a, b);
|
||||
|
||||
if (
|
||||
intersection &&
|
||||
pointDistanceSq(a[0], intersection) > MIN_DIST_SQ &&
|
||||
pointDistanceSq(a[1], intersection) > MIN_DIST_SQ &&
|
||||
i === j + 2
|
||||
) {
|
||||
a[1] = intersection;
|
||||
segments[j + 1] = undefined;
|
||||
b[0] = intersection;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
debugSegments(
|
||||
segments.filter((s): s is LineSegment<LocalPoint> => !!s),
|
||||
input,
|
||||
element,
|
||||
);
|
||||
|
||||
return [
|
||||
...(segments[0] ? [segments[0][0]] : []),
|
||||
...segments
|
||||
.filter((s): s is LineSegment<LocalPoint> => !!s)
|
||||
.map((s) => s[1]),
|
||||
];
|
||||
}
|
||||
|
||||
function debugSegments(
|
||||
segments: LineSegment<LocalPoint>[],
|
||||
input: readonly [number, number, number][] | readonly [number, number][],
|
||||
element: ExcalidrawFreeDrawElement,
|
||||
): void {
|
||||
const colors = [
|
||||
"#FF0000",
|
||||
"#00FF00",
|
||||
"#0000FF",
|
||||
// "#FFFF00",
|
||||
// "#00FFFF",
|
||||
// "#FF00FF",
|
||||
// "#C0C0C0",
|
||||
// "#800000",
|
||||
// "#808000",
|
||||
// "#008000",
|
||||
// "#800080",
|
||||
// "#008080",
|
||||
// "#000080",
|
||||
];
|
||||
segments.forEach((s, i) => {
|
||||
debugDrawLine(
|
||||
lineSegment(
|
||||
pointFrom<GlobalPoint>(element.x + s[0][0], element.y + s[0][1]),
|
||||
pointFrom<GlobalPoint>(element.x + s[1][0], element.y + s[1][1]),
|
||||
),
|
||||
{ color: colors[i % colors.length], permanent: true },
|
||||
);
|
||||
});
|
||||
input.forEach((p, i) => {
|
||||
if (i === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
debugDrawLine(
|
||||
lineSegment(
|
||||
pointFrom<GlobalPoint>(
|
||||
element.x + input[i - 1][0],
|
||||
element.y + input[i - 1][1],
|
||||
),
|
||||
pointFrom<GlobalPoint>(element.x + p[0], element.y + p[1]),
|
||||
),
|
||||
{ color: "#000000", permanent: true },
|
||||
);
|
||||
});
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
import rough from "roughjs/bin/rough";
|
||||
import { getStroke } from "perfect-freehand";
|
||||
//import { getStroke } from "perfect-freehand";
|
||||
|
||||
import {
|
||||
type GlobalPoint,
|
||||
@@ -63,8 +63,8 @@ import {
|
||||
} from "./typeChecks";
|
||||
import { getContainingFrame } from "./frame";
|
||||
import { getCornerRadius } from "./utils";
|
||||
|
||||
import { ShapeCache } from "./shape";
|
||||
import { getStroke } from "./freedraw";
|
||||
|
||||
import type {
|
||||
ExcalidrawElement,
|
||||
@@ -1102,10 +1102,10 @@ export function getFreedrawOutlineAsSegments(
|
||||
export function getFreedrawOutlinePoints(element: ExcalidrawFreeDrawElement) {
|
||||
// If input points are empty (should they ever be?) return a dot
|
||||
const inputPoints = element.simulatePressure
|
||||
? element.points
|
||||
: element.points.length
|
||||
? element.points.map(([x, y], i) => [x, y, element.pressures[i]])
|
||||
: [[0, 0, 0.5]];
|
||||
? (element.points as readonly [number, number][])
|
||||
: ((element.points.length
|
||||
? element.points.map(([x, y], i) => [x, y, element.pressures[i]])
|
||||
: [[0, 0, 0.5]]) as [number, number, number][]);
|
||||
|
||||
// Consider changing the options for simulated pressure vs real pressure
|
||||
const options: StrokeOptions = {
|
||||
@@ -1118,7 +1118,16 @@ export function getFreedrawOutlinePoints(element: ExcalidrawFreeDrawElement) {
|
||||
last: true,
|
||||
};
|
||||
|
||||
return getStroke(inputPoints as number[][], options) as [number, number][];
|
||||
// return getStroke(
|
||||
// [
|
||||
// [0, 0],
|
||||
// [30, -30],
|
||||
// [60, -30],
|
||||
// ],
|
||||
// options,
|
||||
// element,
|
||||
// );
|
||||
return getStroke(inputPoints, options, element) as [number, number][];
|
||||
}
|
||||
|
||||
function med(A: number[], B: number[]) {
|
||||
|
||||
@@ -11463,7 +11463,14 @@ class App extends React.Component<AppProps, AppState> {
|
||||
): void => {
|
||||
const selectionElement = this.state.selectionElement;
|
||||
const pointerCoords = pointerDownState.lastCoords;
|
||||
if (selectionElement && this.state.activeTool.type !== "eraser") {
|
||||
const selectedElements = this.scene.getSelectedElements(this.state);
|
||||
const onlyBindingElementSelected =
|
||||
selectedElements?.length === 1 && isBindingElement(selectedElements[0]);
|
||||
if (
|
||||
selectionElement &&
|
||||
this.state.activeTool.type !== "eraser" &&
|
||||
!onlyBindingElementSelected
|
||||
) {
|
||||
dragNewElement({
|
||||
newElement: selectionElement,
|
||||
elementType: this.state.activeTool.type,
|
||||
@@ -11527,25 +11534,27 @@ class App extends React.Component<AppProps, AppState> {
|
||||
snapLines,
|
||||
});
|
||||
|
||||
dragNewElement({
|
||||
newElement,
|
||||
elementType: this.state.activeTool.type,
|
||||
originX: pointerDownState.originInGrid.x,
|
||||
originY: pointerDownState.originInGrid.y,
|
||||
x: gridX,
|
||||
y: gridY,
|
||||
width: distance(pointerDownState.originInGrid.x, gridX),
|
||||
height: distance(pointerDownState.originInGrid.y, gridY),
|
||||
shouldMaintainAspectRatio: isImageElement(newElement)
|
||||
? !shouldMaintainAspectRatio(event)
|
||||
: shouldMaintainAspectRatio(event),
|
||||
shouldResizeFromCenter: shouldResizeFromCenter(event),
|
||||
zoom: this.state.zoom.value,
|
||||
scene: this.scene,
|
||||
widthAspectRatio: aspectRatio,
|
||||
originOffset: this.state.originSnapOffset,
|
||||
informMutation,
|
||||
});
|
||||
if (!isBindingElement(newElement)) {
|
||||
dragNewElement({
|
||||
newElement,
|
||||
elementType: this.state.activeTool.type,
|
||||
originX: pointerDownState.originInGrid.x,
|
||||
originY: pointerDownState.originInGrid.y,
|
||||
x: gridX,
|
||||
y: gridY,
|
||||
width: distance(pointerDownState.originInGrid.x, gridX),
|
||||
height: distance(pointerDownState.originInGrid.y, gridY),
|
||||
shouldMaintainAspectRatio: isImageElement(newElement)
|
||||
? !shouldMaintainAspectRatio(event)
|
||||
: shouldMaintainAspectRatio(event),
|
||||
shouldResizeFromCenter: shouldResizeFromCenter(event),
|
||||
zoom: this.state.zoom.value,
|
||||
scene: this.scene,
|
||||
widthAspectRatio: aspectRatio,
|
||||
originOffset: this.state.originSnapOffset,
|
||||
informMutation,
|
||||
});
|
||||
}
|
||||
|
||||
this.setState({
|
||||
newElement,
|
||||
|
||||
@@ -222,7 +222,7 @@ function dataView(
|
||||
*
|
||||
* @param buffers each buffer (chunk) must be at most 2^32 bits large (~4GB)
|
||||
*/
|
||||
const concatBuffers = (...buffers: Uint8Array[]) => {
|
||||
const concatBuffers = (...buffers: Uint8Array[]): Uint8Array<ArrayBuffer> => {
|
||||
const bufferView = new Uint8Array(
|
||||
VERSION_DATAVIEW_BYTES +
|
||||
NEXT_CHUNK_SIZE_DATAVIEW_BYTES * buffers.length +
|
||||
@@ -295,12 +295,12 @@ const splitBuffers = (concatenatedBuffer: Uint8Array) => {
|
||||
|
||||
/** @private */
|
||||
const _encryptAndCompress = async (
|
||||
data: Uint8Array | string,
|
||||
data: Uint8Array<ArrayBuffer> | string,
|
||||
encryptionKey: string,
|
||||
) => {
|
||||
const { encryptedBuffer, iv } = await encryptData(
|
||||
encryptionKey,
|
||||
deflate(data),
|
||||
deflate(data) as Uint8Array<ArrayBuffer>,
|
||||
);
|
||||
|
||||
return { iv, buffer: new Uint8Array(encryptedBuffer) };
|
||||
@@ -330,7 +330,7 @@ export const compressData = async <T extends Record<string, any> = never>(
|
||||
: {
|
||||
metadata: T;
|
||||
}),
|
||||
): Promise<Uint8Array> => {
|
||||
): Promise<Uint8Array<ArrayBuffer>> => {
|
||||
const fileInfo: FileEncodingInfo = {
|
||||
version: 2,
|
||||
compression: "pako@1",
|
||||
@@ -355,8 +355,8 @@ export const compressData = async <T extends Record<string, any> = never>(
|
||||
|
||||
/** @private */
|
||||
const _decryptAndDecompress = async (
|
||||
iv: Uint8Array,
|
||||
decryptedBuffer: Uint8Array,
|
||||
iv: Uint8Array<ArrayBuffer>,
|
||||
decryptedBuffer: Uint8Array<ArrayBuffer>,
|
||||
decryptionKey: string,
|
||||
isCompressed: boolean,
|
||||
) => {
|
||||
|
||||
@@ -4,7 +4,7 @@ import { blobToArrayBuffer } from "./blob";
|
||||
|
||||
export const IV_LENGTH_BYTES = 12;
|
||||
|
||||
export const createIV = () => {
|
||||
export const createIV = (): Uint8Array<ArrayBuffer> => {
|
||||
const arr = new Uint8Array(IV_LENGTH_BYTES);
|
||||
return window.crypto.getRandomValues(arr);
|
||||
};
|
||||
@@ -49,12 +49,12 @@ export const getCryptoKey = (key: string, usage: KeyUsage) =>
|
||||
|
||||
export const encryptData = async (
|
||||
key: string | CryptoKey,
|
||||
data: Uint8Array | ArrayBuffer | Blob | File | string,
|
||||
): Promise<{ encryptedBuffer: ArrayBuffer; iv: Uint8Array }> => {
|
||||
data: Uint8Array<ArrayBuffer> | ArrayBuffer | Blob | File | string,
|
||||
): Promise<{ encryptedBuffer: ArrayBuffer; iv: Uint8Array<ArrayBuffer> }> => {
|
||||
const importedKey =
|
||||
typeof key === "string" ? await getCryptoKey(key, "encrypt") : key;
|
||||
const iv = createIV();
|
||||
const buffer: ArrayBuffer | Uint8Array =
|
||||
const buffer: ArrayBuffer | Uint8Array<ArrayBuffer> =
|
||||
typeof data === "string"
|
||||
? new TextEncoder().encode(data)
|
||||
: data instanceof Uint8Array
|
||||
@@ -71,15 +71,15 @@ export const encryptData = async (
|
||||
iv,
|
||||
},
|
||||
importedKey,
|
||||
buffer as ArrayBuffer | Uint8Array,
|
||||
buffer,
|
||||
);
|
||||
|
||||
return { encryptedBuffer, iv };
|
||||
};
|
||||
|
||||
export const decryptData = async (
|
||||
iv: Uint8Array,
|
||||
encrypted: Uint8Array | ArrayBuffer,
|
||||
iv: Uint8Array<ArrayBuffer>,
|
||||
encrypted: Uint8Array<ArrayBuffer> | ArrayBuffer,
|
||||
privateKey: string,
|
||||
): Promise<ArrayBuffer> => {
|
||||
const key = await getCryptoKey(privateKey, "decrypt");
|
||||
|
||||
2
packages/excalidraw/global.d.ts
vendored
2
packages/excalidraw/global.d.ts
vendored
@@ -42,7 +42,7 @@ declare module "png-chunk-text" {
|
||||
function decode(data: Uint8Array): { keyword: string; text: string };
|
||||
}
|
||||
declare module "png-chunks-encode" {
|
||||
function encode(chunks: TEXtChunk[]): Uint8Array;
|
||||
function encode(chunks: TEXtChunk[]): Uint8Array<ArrayBuffer>;
|
||||
export = encode;
|
||||
}
|
||||
declare module "png-chunks-extract" {
|
||||
|
||||
@@ -18,7 +18,7 @@ export function useOutsideClick<T extends HTMLElement>(
|
||||
* Returning `undefined` will fallback to the default behavior.
|
||||
*/
|
||||
isInside?: (
|
||||
event: Event & { target: HTMLElement },
|
||||
event: Event & { target: T },
|
||||
/** the element of the passed ref */
|
||||
container: T,
|
||||
) => boolean | undefined,
|
||||
|
||||
@@ -133,6 +133,6 @@
|
||||
"fonteditor-core": "2.4.1",
|
||||
"harfbuzzjs": "0.3.6",
|
||||
"jest-diff": "29.7.0",
|
||||
"typescript": "4.9.4"
|
||||
"typescript": "5.9.3"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,7 +20,7 @@ const load = (): Promise<{
|
||||
subset: (
|
||||
fontBuffer: ArrayBuffer,
|
||||
codePoints: ReadonlySet<number>,
|
||||
) => Uint8Array;
|
||||
) => Uint8Array<ArrayBuffer>;
|
||||
}> => {
|
||||
return new Promise(async (resolve, reject) => {
|
||||
try {
|
||||
|
||||
@@ -18,7 +18,7 @@ type Vector = any;
|
||||
let loadedWasm: ReturnType<typeof load> | null = null;
|
||||
|
||||
// re-map from internal vector into byte array
|
||||
function convertFromVecToUint8Array(vector: Vector): Uint8Array {
|
||||
function convertFromVecToUint8Array(vector: Vector): Uint8Array<ArrayBuffer> {
|
||||
const arr = [];
|
||||
for (let i = 0, l = vector.size(); i < l; i++) {
|
||||
arr.push(vector.get(i));
|
||||
@@ -29,8 +29,8 @@ function convertFromVecToUint8Array(vector: Vector): Uint8Array {
|
||||
|
||||
// TODO: consider adding support for fetching the wasm from an URL (external CDN, data URL, etc.)
|
||||
const load = (): Promise<{
|
||||
compress: (buffer: ArrayBuffer) => Uint8Array;
|
||||
decompress: (buffer: ArrayBuffer) => Uint8Array;
|
||||
compress: (buffer: ArrayBuffer) => Uint8Array<ArrayBuffer>;
|
||||
decompress: (buffer: ArrayBuffer) => Uint8Array<ArrayBuffer>;
|
||||
}> => {
|
||||
return new Promise((resolve, reject) => {
|
||||
try {
|
||||
|
||||
@@ -464,7 +464,7 @@ export class API {
|
||||
static readFile = async <T extends "utf8" | null>(
|
||||
filepath: string,
|
||||
encoding?: T,
|
||||
): Promise<T extends "utf8" ? string : Buffer> => {
|
||||
): Promise<T extends "utf8" ? string : ArrayBuffer> => {
|
||||
filepath = path.isAbsolute(filepath)
|
||||
? filepath
|
||||
: path.resolve(path.join(__dirname, "../", filepath));
|
||||
|
||||
@@ -158,3 +158,8 @@ export const vectorNormalize = (v: Vector): Vector => {
|
||||
* Calculate the right-hand normal of the vector.
|
||||
*/
|
||||
export const vectorNormal = (v: Vector): Vector => vector(v[1], -v[0]);
|
||||
|
||||
/**
|
||||
* Calculate the left-hand normal of the vector.
|
||||
*/
|
||||
export const vectorAntiNormal = (v: Vector): Vector => vector(-v[1], v[0]);
|
||||
|
||||
@@ -62,7 +62,7 @@
|
||||
"devDependencies": {
|
||||
"cross-env": "7.0.3",
|
||||
"fonteditor-core": "2.4.0",
|
||||
"typescript": "4.9.4",
|
||||
"typescript": "5.9.3",
|
||||
"wawoff2": "2.0.1",
|
||||
"which": "4.0.0"
|
||||
},
|
||||
|
||||
@@ -9290,10 +9290,10 @@ typed-array-length@^1.0.7:
|
||||
possible-typed-array-names "^1.0.0"
|
||||
reflect.getprototypeof "^1.0.6"
|
||||
|
||||
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==
|
||||
typescript@5.9.3:
|
||||
version "5.9.3"
|
||||
resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.9.3.tgz#5b4f59e15310ab17a216f5d6cf53ee476ede670f"
|
||||
integrity sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==
|
||||
|
||||
typescript@^5:
|
||||
version "5.8.2"
|
||||
|
||||
Reference in New Issue
Block a user