Merge remote-tracking branch 'origin/master' into zsviczian-stickynote

This commit is contained in:
zsviczian
2025-11-01 09:37:17 +00:00
113 changed files with 3743 additions and 1371 deletions

View File

@@ -5,17 +5,18 @@ export class BinaryHeap<T> {
sinkDown(idx: number) {
const node = this.content[idx];
const nodeScore = this.scoreFunction(node);
while (idx > 0) {
const parentN = ((idx + 1) >> 1) - 1;
const parent = this.content[parentN];
if (this.scoreFunction(node) < this.scoreFunction(parent)) {
this.content[parentN] = node;
if (nodeScore < this.scoreFunction(parent)) {
this.content[idx] = parent;
idx = parentN; // TODO: Optimize
} else {
break;
}
}
this.content[idx] = node;
}
bubbleUp(idx: number) {
@@ -24,35 +25,39 @@ export class BinaryHeap<T> {
const score = this.scoreFunction(node);
while (true) {
const child2N = (idx + 1) << 1;
const child1N = child2N - 1;
let swap = null;
let child1Score = 0;
const child1N = ((idx + 1) << 1) - 1;
const child2N = child1N + 1;
let smallestIdx = idx;
let smallestScore = score;
// Check left child
if (child1N < length) {
const child1 = this.content[child1N];
child1Score = this.scoreFunction(child1);
if (child1Score < score) {
swap = child1N;
const child1Score = this.scoreFunction(this.content[child1N]);
if (child1Score < smallestScore) {
smallestIdx = child1N;
smallestScore = child1Score;
}
}
// Check right child
if (child2N < length) {
const child2 = this.content[child2N];
const child2Score = this.scoreFunction(child2);
if (child2Score < (swap === null ? score : child1Score)) {
swap = child2N;
const child2Score = this.scoreFunction(this.content[child2N]);
if (child2Score < smallestScore) {
smallestIdx = child2N;
}
}
if (swap !== null) {
this.content[idx] = this.content[swap];
this.content[swap] = node;
idx = swap; // TODO: Optimize
} else {
if (smallestIdx === idx) {
break;
}
// Move the smaller child up, continue finding position for node
this.content[idx] = this.content[smallestIdx];
idx = smallestIdx;
}
// Place node in its final position
this.content[idx] = node;
}
push(node: T) {

View File

@@ -125,6 +125,7 @@ export const ENV = {
};
export const CLASSES = {
SIDEBAR: "sidebar",
SHAPE_ACTIONS_MENU: "App-menu__left",
ZOOM_ACTIONS: "zoom-actions",
SEARCH_MENU_INPUT_WRAPPER: "layer-ui__search-inputWrapper",
@@ -266,7 +267,10 @@ export const STRING_MIME_TYPES = {
json: "application/json",
// excalidraw data
excalidraw: "application/vnd.excalidraw+json",
// LEGACY: fully-qualified library JSON data
excalidrawlib: "application/vnd.excalidrawlib+json",
// list of excalidraw library item ids
excalidrawlibIds: "application/vnd.excalidrawlib.ids+json",
} as const;
export const MIME_TYPES = {
@@ -351,6 +355,9 @@ export const DEFAULT_UI_OPTIONS: AppProps["UIOptions"] = {
// mobile: up to 699px
export const MQ_MAX_MOBILE = 599;
export const MQ_MAX_WIDTH_LANDSCAPE = 1000;
export const MQ_MAX_HEIGHT_LANDSCAPE = 500;
// tablets
export const MQ_MIN_TABLET = MQ_MAX_MOBILE + 1; // lower bound (excludes phones)
export const MQ_MAX_TABLET = 1400; // upper bound (excludes laptops/desktops)
@@ -541,3 +548,8 @@ export enum UserIdleState {
export const LINE_POLYGON_POINT_MERGE_DISTANCE = 20;
export const DOUBLE_TAP_POSITION_THRESHOLD = 35;
// glass background for mobile action buttons
export const MOBILE_ACTION_BUTTON_BG = {
background: "var(--mobile-action-button-bg)",
} as const;

View File

@@ -20,7 +20,6 @@ import {
ENV,
FONT_FAMILY,
getFontFamilyFallbacks,
isDarwin,
isAndroid,
isIOS,
WINDOWS_EMOJI_FALLBACK_FONT,
@@ -93,7 +92,8 @@ export const isWritableElement = (
(target instanceof HTMLInputElement &&
(target.type === "text" ||
target.type === "number" ||
target.type === "password"));
target.type === "password" ||
target.type === "search"));
export const getFontFamilyString = ({
fontFamily,
@@ -121,6 +121,11 @@ export const getFontString = ({
return `${fontSize}px ${getFontFamilyString({ fontFamily })}` as FontString;
};
/** executes callback in the frame that's after the current one */
export const nextAnimationFrame = async (cb: () => any) => {
requestAnimationFrame(() => requestAnimationFrame(cb));
};
export const debounce = <T extends any[]>(
fn: (...args: T) => void,
timeout: number,
@@ -420,19 +425,6 @@ export const allowFullScreen = () =>
export const exitFullScreen = () => document.exitFullscreen();
export const getShortcutKey = (shortcut: string): string => {
shortcut = shortcut
.replace(/\bAlt\b/i, "Alt")
.replace(/\bShift\b/i, "Shift")
.replace(/\b(Enter|Return)\b/i, "Enter");
if (isDarwin) {
return shortcut
.replace(/\bCtrlOrCmd\b/gi, "Cmd")
.replace(/\bAlt\b/i, "Option");
}
return shortcut.replace(/\bCtrlOrCmd\b/gi, "Ctrl");
};
export const viewportCoordsToSceneCoords = (
{ clientX, clientY }: { clientX: number; clientY: number },
{