@weasel-js/core 1.0.3 → 1.0.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +147 -0
- package/dist/{chunk-U45SODC2.js → chunk-4Z6J4IVH.js} +43 -27
- package/dist/chunk-4Z6J4IVH.js.map +1 -0
- package/dist/{chunk-SMCZRSYB.js → chunk-AYGSXNY3.js} +460 -212
- package/dist/chunk-AYGSXNY3.js.map +1 -0
- package/dist/{chunk-3KGMJMOS.js → chunk-CSMF654J.js} +3 -3
- package/dist/{chunk-3KGMJMOS.js.map → chunk-CSMF654J.js.map} +1 -1
- package/dist/{chunk-TR3HZN34.js → chunk-J3YC3GVF.js} +5 -4
- package/dist/chunk-J3YC3GVF.js.map +1 -0
- package/dist/{chunk-3JYFAQIB.js → chunk-J7LUY47N.js} +3 -3
- package/dist/{chunk-3JYFAQIB.js.map → chunk-J7LUY47N.js.map} +1 -1
- package/dist/index.d.ts +8 -38
- package/dist/index.js +5 -5
- package/dist/insert.js +1 -1
- package/dist/move.js +3 -3
- package/dist/move.js.map +1 -1
- package/dist/{registry-CxnkXbG8.d.ts → registry-QRg8KiNM.d.ts} +1 -1
- package/dist/renderer.d.ts +29 -13
- package/dist/renderer.js +5 -5
- package/dist/resize.js +2 -2
- package/dist/routing.d.ts +1 -1
- package/dist/routing.js +1 -1
- package/package.json +6 -6
- package/dist/chunk-SMCZRSYB.js.map +0 -1
- package/dist/chunk-TR3HZN34.js.map +0 -1
- package/dist/chunk-U45SODC2.js.map +0 -1
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { ActionDisabledReason, useOptionalDepRegistry, DepRegistryProvider, useActionsRegistry, ActionsProvider, useDepRegistry, reportRouteConflicts, buildDepsFromRequires, useDepSource, actionBindings } from './chunk-
|
|
2
|
-
import { scratchKey, createTransformOp, snap, getScratch, createReparentOp, setScratch } from './chunk-
|
|
3
|
-
import { fixedCornerOf, DEFAULT_RESIZE_BEHAVIORS, CORNER_ANCHORS, cornerPoint } from './chunk-
|
|
4
|
-
import { AUTO_POSE_DESCRIPTOR, RECT_POSE_DESCRIPTOR, resolveUnit, pathPoseDescriptor, polygonFromPoints, starPath, regularPolygonPath, linePath, ellipsePath, rectPath, strokeHitTest, withinPxRadius, boundsOfPath, PATH_M, PATH_L, PATH_Z, PATH_Q, PATH_C, DEFAULT_FLATTEN_TOLERANCE, flattenQuadratic, flattenCubic, PathBuilder, pointInPath, transformPath, translatePath, pxExtent, remapRotatedLeaf, withinPxBox, flattenCubicWithArcLen, flattenQuadraticWithArcLen, PATH_CMD_LENGTHS, pointToGridCell } from './chunk-
|
|
1
|
+
import { ActionDisabledReason, useOptionalDepRegistry, DepRegistryProvider, useActionsRegistry, ActionsProvider, useDepRegistry, reportRouteConflicts, buildDepsFromRequires, useDepSource, actionBindings } from './chunk-J3YC3GVF.js';
|
|
2
|
+
import { scratchKey, createTransformOp, snap, getScratch, createReparentOp, setScratch } from './chunk-CSMF654J.js';
|
|
3
|
+
import { fixedCornerOf, DEFAULT_RESIZE_BEHAVIORS, CORNER_ANCHORS, cornerPoint } from './chunk-J7LUY47N.js';
|
|
4
|
+
import { AUTO_POSE_DESCRIPTOR, RECT_POSE_DESCRIPTOR, resolveUnit, pathPoseDescriptor, polygonFromPoints, starPath, regularPolygonPath, linePath, ellipsePath, rectPath, strokeHitTest, withinPxRadius, boundsOfPath, PATH_M, PATH_L, PATH_Z, PATH_Q, PATH_C, DEFAULT_FLATTEN_TOLERANCE, flattenQuadratic, flattenCubic, PathBuilder, pointInPath, transformPath, translatePath, pxExtent, remapRotatedLeaf, withinPxBox, flattenCubicWithArcLen, flattenQuadraticWithArcLen, PATH_CMD_LENGTHS, pointToGridCell } from './chunk-4Z6J4IVH.js';
|
|
5
5
|
import { dispatchApplyBatch, dlog, dwarn, usePointerContext, PointerContextProvider, applyOpsTo, extractWeaselClipboardFromSvg, parseWeaselClipboardText, materializePaste, WEASEL_CLIPBOARD_MIME, WEASEL_CLIPBOARD_MIME_WEB, sniffWeaselClipboardText } from './chunk-JOSUVS6C.js';
|
|
6
6
|
import { createSetSelectionOp } from './chunk-BHVYVFGV.js';
|
|
7
7
|
import { registerOpFactory, createDeleteOp, createInsertOp, rebuildOp } from './chunk-GVCNT7UH.js';
|
|
@@ -10,7 +10,7 @@ import { createContext, createElement, forwardRef, useMemo, useRef, useState, us
|
|
|
10
10
|
import { subscribeGlyphReady, DEFAULT_BAKE_BUDGET, TEXT_VERT_SRC, TEXT_FRAG_SRC, TEXT_SDF_UNIFORMS, TEXT_SDF_ATTRIBUTES, TEXT_FRAG_R8_SRC, markAllFontsNotUploaded, resetBakeBudget, glyphGeneration, syncDynamicPageTexture, ensureFontTexture, dynamicPageTextureId, textureCacheKey, resolveFontVariant, resolveGlyphFallback, glyphOutline } from '@weasel-js/font';
|
|
11
11
|
export { canQueryLocalFonts, canQueryLocalFonts as canQueryLocalFonts2, enableLocalFontOutlines, enableLocalFontOutlines as enableLocalFontOutlines2, hasFontOutlines, hasFontOutlines as hasFontOutlines2, isCanvasFont, isCanvasFont as isCanvasFont2, listFontOutlines, listFontOutlines as listFontOutlines2, outlineStatus, outlineStatus as outlineStatus2, registerCanvasFont, registerCanvasFont as registerCanvasFont2, registerFont, registerFont as registerFont2, registerFontOutlines, registerFontOutlines as registerFontOutlines2, subscribeGlyphReady, subscribeGlyphReady as subscribeGlyphReady2, unregisterCanvasFont, unregisterCanvasFont as unregisterCanvasFont2, unregisterFontOutlines, unregisterFontOutlines as unregisterFontOutlines2 } from '@weasel-js/font';
|
|
12
12
|
import earcut from 'earcut';
|
|
13
|
-
import { applyToPoint, rotateAboutPoint, boxToBox, pointInPolygon, segmentsCross } from '@weasel-js/geom';
|
|
13
|
+
import { applyToPoint, rotateAboutPoint, boxToBox, pointInPolygon, segmentsCross, pointSegmentDist2 } from '@weasel-js/geom';
|
|
14
14
|
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
15
15
|
import polygonClipping from 'polygon-clipping';
|
|
16
16
|
import { matchSpec, RESERVED_ID_PREFIXES, RESERVED_ID_NAMES, parseTargetSpec, mimeMatchesGlob } from '@weasel-js/gestures';
|
|
@@ -19,7 +19,7 @@ import { createHistory } from '@weasel-js/history';
|
|
|
19
19
|
export * from '@weasel-js/history';
|
|
20
20
|
|
|
21
21
|
// src/version.ts
|
|
22
|
-
var VERSION = "1.0.
|
|
22
|
+
var VERSION = "1.0.4" ;
|
|
23
23
|
|
|
24
24
|
// src/features/grid/roundToCell.ts
|
|
25
25
|
function roundToCell(value, cellSize) {
|
|
@@ -524,13 +524,20 @@ var GLTextureCache = class {
|
|
|
524
524
|
}
|
|
525
525
|
gl;
|
|
526
526
|
map = /* @__PURE__ */ new Map();
|
|
527
|
+
wraps = /* @__PURE__ */ new Map();
|
|
527
528
|
has(id) {
|
|
528
529
|
return this.map.has(id);
|
|
529
530
|
}
|
|
530
|
-
/** Uploads once per id
|
|
531
|
-
*
|
|
531
|
+
/** Uploads the pixels once per id. `wrap` is re-applied whenever it differs
|
|
532
|
+
* from what the id was last uploaded under: the same registered image can
|
|
533
|
+
* be a clamped shader texture in one draw and a repeating pattern tile in
|
|
534
|
+
* the next, and first-upload-wins gave the second one the first one's mode. */
|
|
532
535
|
upload(id, source, wrap = "clamp") {
|
|
533
|
-
|
|
536
|
+
const cached = this.map.get(id);
|
|
537
|
+
if (cached) {
|
|
538
|
+
if (this.wraps.get(id) !== wrap) this.applyWrap(id, cached, wrap);
|
|
539
|
+
return id;
|
|
540
|
+
}
|
|
534
541
|
const gl = this.gl;
|
|
535
542
|
const tex = gl.createTexture();
|
|
536
543
|
if (!tex) throw new Error(`GLTextureCache: createTexture failed for id="${id}"`);
|
|
@@ -543,8 +550,18 @@ var GLTextureCache = class {
|
|
|
543
550
|
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, wrapMode);
|
|
544
551
|
gl.bindTexture(gl.TEXTURE_2D, null);
|
|
545
552
|
this.map.set(id, tex);
|
|
553
|
+
this.wraps.set(id, wrap);
|
|
546
554
|
return id;
|
|
547
555
|
}
|
|
556
|
+
applyWrap(id, tex, wrap) {
|
|
557
|
+
const gl = this.gl;
|
|
558
|
+
const mode = wrap === "repeat" ? gl.REPEAT : gl.CLAMP_TO_EDGE;
|
|
559
|
+
gl.bindTexture(gl.TEXTURE_2D, tex);
|
|
560
|
+
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, mode);
|
|
561
|
+
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, mode);
|
|
562
|
+
gl.bindTexture(gl.TEXTURE_2D, null);
|
|
563
|
+
this.wraps.set(id, wrap);
|
|
564
|
+
}
|
|
548
565
|
/** Create a single-channel R8 texture from raw bytes (full upload).
|
|
549
566
|
* No-op if `id` already exists. Same LINEAR/CLAMP params as `upload`;
|
|
550
567
|
* UNPACK_ALIGNMENT dropped to 1 for non-4-aligned row widths. */
|
|
@@ -563,6 +580,7 @@ var GLTextureCache = class {
|
|
|
563
580
|
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
|
|
564
581
|
gl.bindTexture(gl.TEXTURE_2D, null);
|
|
565
582
|
this.map.set(id, tex);
|
|
583
|
+
this.wraps.set(id, "clamp");
|
|
566
584
|
}
|
|
567
585
|
/** Patch a rect of an existing R8 texture with tightly-packed w×h bytes. */
|
|
568
586
|
subImageR8(id, x, y, w, h, data) {
|
|
@@ -594,6 +612,7 @@ var GLTextureCache = class {
|
|
|
594
612
|
gl.deleteTexture(tex);
|
|
595
613
|
}
|
|
596
614
|
this.map.clear();
|
|
615
|
+
this.wraps.clear();
|
|
597
616
|
}
|
|
598
617
|
};
|
|
599
618
|
|
|
@@ -1282,6 +1301,13 @@ var GroupState = class {
|
|
|
1282
1301
|
this.alphaStack.push(nextAlpha);
|
|
1283
1302
|
this.colorMatrixStack.push(nextCM);
|
|
1284
1303
|
}
|
|
1304
|
+
/** Drop every pushed frame, leaving the root. A frame that throws part-way
|
|
1305
|
+
* down the tree never pops, and the next frame would draw under leftovers. */
|
|
1306
|
+
reset() {
|
|
1307
|
+
this.transformStack.length = 1;
|
|
1308
|
+
this.alphaStack.length = 1;
|
|
1309
|
+
this.colorMatrixStack.length = 1;
|
|
1310
|
+
}
|
|
1285
1311
|
pop() {
|
|
1286
1312
|
if (this.transformStack.length <= 1) {
|
|
1287
1313
|
throw new Error("GroupState.pop: cannot pop root frame");
|
|
@@ -1935,16 +1961,28 @@ function verticalAlignOffset(align, boxHeight, textHeight) {
|
|
|
1935
1961
|
|
|
1936
1962
|
// src/features/paths/pathFromD.ts
|
|
1937
1963
|
var NUM_RE = /[+-]?(?:\d*\.\d+|\d+\.?)(?:[eE][+-]?\d+)?/g;
|
|
1964
|
+
var NUM_RE_AT = /[+-]?(?:\d*\.\d+|\d+\.?)(?:[eE][+-]?\d+)?/y;
|
|
1965
|
+
function isCommandLetter(d, j) {
|
|
1966
|
+
const c = d[j];
|
|
1967
|
+
if (!/[A-Za-z]/.test(c)) return false;
|
|
1968
|
+
if (c !== "e" && c !== "E") return true;
|
|
1969
|
+
if (!/[\d.]/.test(d[j - 1] ?? "")) return true;
|
|
1970
|
+
const k = d[j + 1] === "+" || d[j + 1] === "-" ? j + 2 : j + 1;
|
|
1971
|
+
return !/\d/.test(d[k] ?? "");
|
|
1972
|
+
}
|
|
1938
1973
|
function tokenize(d) {
|
|
1939
1974
|
const out = [];
|
|
1940
1975
|
let i = 0;
|
|
1941
1976
|
while (i < d.length) {
|
|
1942
|
-
|
|
1943
|
-
if (/[A-Za-z]/.test(ch)) {
|
|
1977
|
+
if (isCommandLetter(d, i)) {
|
|
1944
1978
|
let j = i + 1;
|
|
1945
|
-
while (j < d.length &&
|
|
1979
|
+
while (j < d.length && !isCommandLetter(d, j)) j++;
|
|
1946
1980
|
const argSlice = d.slice(i + 1, j);
|
|
1947
|
-
|
|
1981
|
+
const cmd = d[i];
|
|
1982
|
+
out.push({
|
|
1983
|
+
cmd,
|
|
1984
|
+
args: cmd === "A" || cmd === "a" ? readArcArgs(argSlice) : readNumbers(argSlice)
|
|
1985
|
+
});
|
|
1948
1986
|
i = j;
|
|
1949
1987
|
} else {
|
|
1950
1988
|
i++;
|
|
@@ -1962,6 +2000,30 @@ function readNumbers(s) {
|
|
|
1962
2000
|
}
|
|
1963
2001
|
return out;
|
|
1964
2002
|
}
|
|
2003
|
+
function readArcArgs(s) {
|
|
2004
|
+
const out = [];
|
|
2005
|
+
let i = 0;
|
|
2006
|
+
while (i < s.length) {
|
|
2007
|
+
const c = s[i];
|
|
2008
|
+
if (c === "," || c === " " || c === " " || c === "\n" || c === "\r") {
|
|
2009
|
+
i++;
|
|
2010
|
+
continue;
|
|
2011
|
+
}
|
|
2012
|
+
const slot = out.length % 7;
|
|
2013
|
+
if (slot === 3 || slot === 4) {
|
|
2014
|
+
if (c !== "0" && c !== "1") return out;
|
|
2015
|
+
out.push(c === "1" ? 1 : 0);
|
|
2016
|
+
i++;
|
|
2017
|
+
continue;
|
|
2018
|
+
}
|
|
2019
|
+
NUM_RE_AT.lastIndex = i;
|
|
2020
|
+
const m = NUM_RE_AT.exec(s);
|
|
2021
|
+
if (!m) return out;
|
|
2022
|
+
out.push(Number(m[0]));
|
|
2023
|
+
i = NUM_RE_AT.lastIndex;
|
|
2024
|
+
}
|
|
2025
|
+
return out;
|
|
2026
|
+
}
|
|
1965
2027
|
var ARG_COUNTS = {
|
|
1966
2028
|
M: 2,
|
|
1967
2029
|
L: 2,
|
|
@@ -2879,42 +2941,42 @@ var MAX_VERTICES_PER_BATCH = 32768;
|
|
|
2879
2941
|
var FLOATS_PER_VERTEX = 6;
|
|
2880
2942
|
var INITIAL_VERTICES = 256;
|
|
2881
2943
|
var INITIAL_INDICES = 384;
|
|
2944
|
+
var SOLID_RING_SIZE = 64;
|
|
2945
|
+
var SOLID_RING_SLOT_VERTICES = 1024;
|
|
2946
|
+
var SOLID_RING_SLOT_INDICES = 3072;
|
|
2947
|
+
var SOLID_LARGE_RING_SIZE = 4;
|
|
2948
|
+
function doubledTo(from, need) {
|
|
2949
|
+
let capacity = from;
|
|
2950
|
+
while (capacity < need) capacity *= 2;
|
|
2951
|
+
return capacity;
|
|
2952
|
+
}
|
|
2882
2953
|
var SolidBatch = class {
|
|
2883
2954
|
gl;
|
|
2884
|
-
|
|
2885
|
-
|
|
2886
|
-
|
|
2955
|
+
aPos;
|
|
2956
|
+
aColor;
|
|
2957
|
+
/** Cycled per flush, and created on first use so a renderer that flushes
|
|
2958
|
+
* rarely allocates as few slots as it flushes. */
|
|
2959
|
+
ring = new Array(SOLID_RING_SIZE).fill(void 0);
|
|
2960
|
+
next = 0;
|
|
2961
|
+
/** The same, for flushes past a slot's capacity; these sets grow to fit. */
|
|
2962
|
+
largeRing = new Array(SOLID_LARGE_RING_SIZE).fill(void 0);
|
|
2963
|
+
nextLarge = 0;
|
|
2887
2964
|
verts = new Float32Array(INITIAL_VERTICES * FLOATS_PER_VERTEX);
|
|
2888
2965
|
idx = new Uint32Array(INITIAL_INDICES);
|
|
2889
2966
|
nVerts = 0;
|
|
2890
2967
|
nIdx = 0;
|
|
2891
|
-
/**
|
|
2892
|
-
|
|
2893
|
-
|
|
2968
|
+
/** Whether the staged run is rects alone, so its indices are the canonical
|
|
2969
|
+
* quad pattern and a slot already holding that pattern needs no upload. */
|
|
2970
|
+
pureRects = true;
|
|
2894
2971
|
constructor(gl, prog) {
|
|
2895
2972
|
const aPos = prog.attribute("a_position");
|
|
2896
2973
|
const aColor = prog.attribute("a_vertexColor");
|
|
2897
2974
|
if (aPos === void 0 || aColor === void 0) {
|
|
2898
2975
|
throw new Error("SolidBatch: vertex-color program is missing a_position / a_vertexColor");
|
|
2899
2976
|
}
|
|
2900
|
-
const vao = gl.createVertexArray();
|
|
2901
|
-
const vbo = gl.createBuffer();
|
|
2902
|
-
const ibo = gl.createBuffer();
|
|
2903
|
-
if (!vao || !vbo || !ibo) throw new Error("SolidBatch: failed to create GL objects");
|
|
2904
2977
|
this.gl = gl;
|
|
2905
|
-
this.
|
|
2906
|
-
this.
|
|
2907
|
-
this.ibo = ibo;
|
|
2908
|
-
const stride = FLOATS_PER_VERTEX * 4;
|
|
2909
|
-
gl.bindVertexArray(vao);
|
|
2910
|
-
gl.bindBuffer(gl.ARRAY_BUFFER, vbo);
|
|
2911
|
-
gl.enableVertexAttribArray(aPos);
|
|
2912
|
-
gl.vertexAttribPointer(aPos, 2, gl.FLOAT, false, stride, 0);
|
|
2913
|
-
gl.enableVertexAttribArray(aColor);
|
|
2914
|
-
gl.vertexAttribPointer(aColor, 4, gl.FLOAT, false, stride, 8);
|
|
2915
|
-
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, ibo);
|
|
2916
|
-
gl.bindVertexArray(null);
|
|
2917
|
-
this.growGpu(INITIAL_VERTICES, INITIAL_INDICES);
|
|
2978
|
+
this.aPos = aPos;
|
|
2979
|
+
this.aColor = aColor;
|
|
2918
2980
|
}
|
|
2919
2981
|
get length() {
|
|
2920
2982
|
return this.nIdx;
|
|
@@ -2984,6 +3046,7 @@ var SolidBatch = class {
|
|
|
2984
3046
|
const srcIdx = mesh.indices;
|
|
2985
3047
|
const n = src.length >> 1;
|
|
2986
3048
|
this.reserve(n, srcIdx.length);
|
|
3049
|
+
this.pureRects = false;
|
|
2987
3050
|
const v = this.verts;
|
|
2988
3051
|
let i = this.nVerts * FLOATS_PER_VERTEX;
|
|
2989
3052
|
const ma = m[0], mb = m[1], mc = m[3], md = m[4], mtx = m[6], mty = m[7];
|
|
@@ -3004,67 +3067,109 @@ var SolidBatch = class {
|
|
|
3004
3067
|
this.nVerts += n;
|
|
3005
3068
|
this.nIdx += srcIdx.length;
|
|
3006
3069
|
}
|
|
3007
|
-
/** Upload the staged geometry and bind
|
|
3008
|
-
* count for the caller's `drawElements`. */
|
|
3070
|
+
/** Upload the staged geometry into the next set of buffers and bind its VAO.
|
|
3071
|
+
* Returns the index count for the caller's `drawElements`. */
|
|
3009
3072
|
uploadAndBind() {
|
|
3010
3073
|
const gl = this.gl;
|
|
3011
|
-
|
|
3012
|
-
|
|
3013
|
-
|
|
3014
|
-
gl.bindVertexArray(this.vao);
|
|
3015
|
-
gl.bindBuffer(gl.ARRAY_BUFFER, this.vbo);
|
|
3074
|
+
const set = this.nVerts <= SOLID_RING_SLOT_VERTICES && this.nIdx <= SOLID_RING_SLOT_INDICES ? this.nextRingSlot() : this.nextLargeSlot();
|
|
3075
|
+
gl.bindVertexArray(set.vao);
|
|
3076
|
+
gl.bindBuffer(gl.ARRAY_BUFFER, set.vbo);
|
|
3016
3077
|
gl.bufferSubData(gl.ARRAY_BUFFER, 0, this.verts, 0, this.nVerts * FLOATS_PER_VERTEX);
|
|
3017
|
-
|
|
3078
|
+
const rects = this.pureRects ? this.nVerts >> 2 : -1;
|
|
3079
|
+
if (rects < 0 || rects !== set.indexRects) {
|
|
3080
|
+
gl.bufferSubData(gl.ELEMENT_ARRAY_BUFFER, 0, this.idx, 0, this.nIdx);
|
|
3081
|
+
set.indexRects = rects;
|
|
3082
|
+
}
|
|
3018
3083
|
return this.nIdx;
|
|
3019
3084
|
}
|
|
3020
3085
|
reset() {
|
|
3021
3086
|
this.nVerts = 0;
|
|
3022
3087
|
this.nIdx = 0;
|
|
3088
|
+
this.pureRects = true;
|
|
3023
3089
|
}
|
|
3024
3090
|
dispose() {
|
|
3025
|
-
const
|
|
3026
|
-
|
|
3027
|
-
|
|
3028
|
-
|
|
3091
|
+
for (const set of [...this.ring, ...this.largeRing]) {
|
|
3092
|
+
if (set) this.deleteSet(set);
|
|
3093
|
+
}
|
|
3094
|
+
this.ring.fill(void 0);
|
|
3095
|
+
this.largeRing.fill(void 0);
|
|
3029
3096
|
}
|
|
3030
3097
|
/** Grow the CPU arrays so `vertices` / `indices` more fit. */
|
|
3031
3098
|
reserve(vertices, indices) {
|
|
3032
3099
|
const needVerts = (this.nVerts + vertices) * FLOATS_PER_VERTEX;
|
|
3033
3100
|
if (needVerts > this.verts.length) {
|
|
3034
|
-
|
|
3035
|
-
while (len < needVerts) len *= 2;
|
|
3036
|
-
const grown = new Float32Array(len);
|
|
3101
|
+
const grown = new Float32Array(doubledTo(this.verts.length, needVerts));
|
|
3037
3102
|
grown.set(this.verts);
|
|
3038
3103
|
this.verts = grown;
|
|
3039
3104
|
}
|
|
3040
3105
|
const needIdx = this.nIdx + indices;
|
|
3041
3106
|
if (needIdx > this.idx.length) {
|
|
3042
|
-
|
|
3043
|
-
while (len < needIdx) len *= 2;
|
|
3044
|
-
const grown = new Uint32Array(len);
|
|
3107
|
+
const grown = new Uint32Array(doubledTo(this.idx.length, needIdx));
|
|
3045
3108
|
grown.set(this.idx);
|
|
3046
3109
|
this.idx = grown;
|
|
3047
3110
|
}
|
|
3048
3111
|
}
|
|
3049
|
-
|
|
3050
|
-
|
|
3112
|
+
nextRingSlot() {
|
|
3113
|
+
const slot = this.next;
|
|
3114
|
+
this.next = (slot + 1) % SOLID_RING_SIZE;
|
|
3115
|
+
const existing = this.ring[slot];
|
|
3116
|
+
if (existing) return existing;
|
|
3117
|
+
const set = this.createSet(SOLID_RING_SLOT_VERTICES, SOLID_RING_SLOT_INDICES);
|
|
3118
|
+
this.ring[slot] = set;
|
|
3119
|
+
return set;
|
|
3120
|
+
}
|
|
3121
|
+
nextLargeSlot() {
|
|
3051
3122
|
const gl = this.gl;
|
|
3052
|
-
|
|
3053
|
-
|
|
3054
|
-
|
|
3055
|
-
|
|
3056
|
-
|
|
3057
|
-
|
|
3058
|
-
|
|
3059
|
-
|
|
3060
|
-
|
|
3061
|
-
|
|
3062
|
-
|
|
3063
|
-
|
|
3064
|
-
|
|
3123
|
+
const slot = this.nextLarge;
|
|
3124
|
+
this.nextLarge = (slot + 1) % SOLID_LARGE_RING_SIZE;
|
|
3125
|
+
let set = this.largeRing[slot];
|
|
3126
|
+
if (!set) {
|
|
3127
|
+
set = this.createSet(
|
|
3128
|
+
doubledTo(SOLID_RING_SLOT_VERTICES, this.nVerts),
|
|
3129
|
+
doubledTo(SOLID_RING_SLOT_INDICES, this.nIdx)
|
|
3130
|
+
);
|
|
3131
|
+
this.largeRing[slot] = set;
|
|
3132
|
+
return set;
|
|
3133
|
+
}
|
|
3134
|
+
if (this.nVerts > set.vertexCapacity) {
|
|
3135
|
+
set.vertexCapacity = doubledTo(set.vertexCapacity, this.nVerts);
|
|
3136
|
+
gl.bindBuffer(gl.ARRAY_BUFFER, set.vbo);
|
|
3137
|
+
gl.bufferData(gl.ARRAY_BUFFER, set.vertexCapacity * FLOATS_PER_VERTEX * 4, gl.DYNAMIC_DRAW);
|
|
3138
|
+
}
|
|
3139
|
+
if (this.nIdx > set.indexCapacity) {
|
|
3140
|
+
set.indexCapacity = doubledTo(set.indexCapacity, this.nIdx);
|
|
3141
|
+
gl.bindVertexArray(set.vao);
|
|
3142
|
+
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, set.ibo);
|
|
3143
|
+
gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, set.indexCapacity * 4, gl.DYNAMIC_DRAW);
|
|
3065
3144
|
gl.bindVertexArray(null);
|
|
3066
|
-
|
|
3145
|
+
set.indexRects = -1;
|
|
3067
3146
|
}
|
|
3147
|
+
return set;
|
|
3148
|
+
}
|
|
3149
|
+
createSet(vertices, indices) {
|
|
3150
|
+
const gl = this.gl;
|
|
3151
|
+
const vao = gl.createVertexArray();
|
|
3152
|
+
const vbo = gl.createBuffer();
|
|
3153
|
+
const ibo = gl.createBuffer();
|
|
3154
|
+
if (!vao || !vbo || !ibo) throw new Error("SolidBatch: failed to create GL objects");
|
|
3155
|
+
const stride = FLOATS_PER_VERTEX * 4;
|
|
3156
|
+
gl.bindVertexArray(vao);
|
|
3157
|
+
gl.bindBuffer(gl.ARRAY_BUFFER, vbo);
|
|
3158
|
+
gl.bufferData(gl.ARRAY_BUFFER, vertices * stride, gl.DYNAMIC_DRAW);
|
|
3159
|
+
gl.enableVertexAttribArray(this.aPos);
|
|
3160
|
+
gl.vertexAttribPointer(this.aPos, 2, gl.FLOAT, false, stride, 0);
|
|
3161
|
+
gl.enableVertexAttribArray(this.aColor);
|
|
3162
|
+
gl.vertexAttribPointer(this.aColor, 4, gl.FLOAT, false, stride, 8);
|
|
3163
|
+
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, ibo);
|
|
3164
|
+
gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, indices * 4, gl.DYNAMIC_DRAW);
|
|
3165
|
+
gl.bindVertexArray(null);
|
|
3166
|
+
return { vao, vbo, ibo, vertexCapacity: vertices, indexCapacity: indices, indexRects: -1 };
|
|
3167
|
+
}
|
|
3168
|
+
deleteSet(set) {
|
|
3169
|
+
const gl = this.gl;
|
|
3170
|
+
gl.deleteBuffer(set.vbo);
|
|
3171
|
+
gl.deleteBuffer(set.ibo);
|
|
3172
|
+
gl.deleteVertexArray(set.vao);
|
|
3068
3173
|
}
|
|
3069
3174
|
};
|
|
3070
3175
|
|
|
@@ -3089,6 +3194,25 @@ function sameValues(prev, next) {
|
|
|
3089
3194
|
for (let i = 0; i < prev.length; i++) if (prev[i] !== next[i]) return false;
|
|
3090
3195
|
return true;
|
|
3091
3196
|
}
|
|
3197
|
+
function setColorUniform(ctx, prog, r, g, b, a) {
|
|
3198
|
+
const loc = prog.uniform("u_color");
|
|
3199
|
+
if (loc === void 0) return;
|
|
3200
|
+
const uploaded = uploadedFor(ctx, prog);
|
|
3201
|
+
const prev = uploaded.color;
|
|
3202
|
+
if (prev !== void 0 && prev[0] === r && prev[1] === g && prev[2] === b && prev[3] === a) {
|
|
3203
|
+
return;
|
|
3204
|
+
}
|
|
3205
|
+
ctx.gl.uniform4f(loc, r, g, b, a);
|
|
3206
|
+
uploaded.color = [r, g, b, a];
|
|
3207
|
+
}
|
|
3208
|
+
function setAlphaUniform(ctx, prog, alpha) {
|
|
3209
|
+
const loc = prog.uniform("u_alpha");
|
|
3210
|
+
if (loc === void 0) return;
|
|
3211
|
+
const uploaded = uploadedFor(ctx, prog);
|
|
3212
|
+
if (uploaded.alpha === alpha) return;
|
|
3213
|
+
ctx.gl.uniform1f(loc, alpha);
|
|
3214
|
+
uploaded.alpha = alpha;
|
|
3215
|
+
}
|
|
3092
3216
|
var BATCH_MODEL = mat3.identity();
|
|
3093
3217
|
function projFor(ctx) {
|
|
3094
3218
|
let proj = FRAME_PROJ.get(ctx);
|
|
@@ -3381,8 +3505,8 @@ function flushSolids(ctx) {
|
|
|
3381
3505
|
gl.useProgram(prog.handle);
|
|
3382
3506
|
const indexCount = batch.uploadAndBind();
|
|
3383
3507
|
setProjAndModel(ctx, prog, BATCH_MODEL);
|
|
3384
|
-
|
|
3385
|
-
|
|
3508
|
+
setColorUniform(ctx, prog, 1, 1, 1, 1);
|
|
3509
|
+
setAlphaUniform(ctx, prog, staged.alpha);
|
|
3386
3510
|
setColorMatrixUniforms(ctx, prog, staged.colorMatrix);
|
|
3387
3511
|
applyClipTest(ctx, staged.clipDepth);
|
|
3388
3512
|
gl.drawElements(gl.TRIANGLES, indexCount, gl.UNSIGNED_INT, 0);
|
|
@@ -3447,10 +3571,9 @@ function setProjAndModel(ctx, prog, model = ctx.state.transform) {
|
|
|
3447
3571
|
}
|
|
3448
3572
|
}
|
|
3449
3573
|
function setSolidPaintUniforms(ctx, prog, color, opacity) {
|
|
3450
|
-
const gl = ctx.gl;
|
|
3451
3574
|
const [r, g, b, a] = resolveColor(color);
|
|
3452
|
-
|
|
3453
|
-
|
|
3575
|
+
setColorUniform(ctx, prog, r, g, b, a * (opacity ?? 1));
|
|
3576
|
+
setAlphaUniform(ctx, prog, ctx.state.alpha);
|
|
3454
3577
|
}
|
|
3455
3578
|
function drawPathFillByKind(ctx, fill, handle) {
|
|
3456
3579
|
const kind = fill.fill ?? "solid";
|
|
@@ -3496,7 +3619,7 @@ function drawPathFillPattern(ctx, fill, handle) {
|
|
|
3496
3619
|
ctx.textureCache.bind(tex.id, 0);
|
|
3497
3620
|
gl.uniform1i(ctx.patternFill.uniform("u_sampler"), 0);
|
|
3498
3621
|
gl.uniform1f(ctx.patternFill.uniform("u_opacity"), fill.opacity ?? 1);
|
|
3499
|
-
|
|
3622
|
+
setAlphaUniform(ctx, ctx.patternFill, ctx.state.alpha);
|
|
3500
3623
|
applyClipTest(ctx);
|
|
3501
3624
|
gl.drawElements(gl.TRIANGLES, handle.indexCount, gl.UNSIGNED_INT, 0);
|
|
3502
3625
|
gl.bindVertexArray(null);
|
|
@@ -3520,7 +3643,7 @@ function drawPathFillGradient(ctx, fill, handle) {
|
|
|
3520
3643
|
gl.uniformMatrix3fv(ctx.gradFill.uniform("u_worldInv"), false, gradientSpaceInverse(ctx, fill.units));
|
|
3521
3644
|
ctx.gradRampCache.bind(key, 0);
|
|
3522
3645
|
gl.uniform1i(ctx.gradFill.uniform("u_ramp"), 0);
|
|
3523
|
-
|
|
3646
|
+
setAlphaUniform(ctx, ctx.gradFill, ctx.state.alpha);
|
|
3524
3647
|
gl.uniform1f(ctx.gradFill.uniform("u_opacity"), fill.opacity ?? 1);
|
|
3525
3648
|
if (fill.fill === "linear-gradient") {
|
|
3526
3649
|
gl.uniform1i(ctx.gradFill.uniform("u_gradKind"), 0);
|
|
@@ -3670,6 +3793,7 @@ function drawPathStrokeUnclipped(ctx, cmd) {
|
|
|
3670
3793
|
gl.enableVertexAttribArray(aVColorLoc);
|
|
3671
3794
|
gl.vertexAttribPointer(aVColorLoc, 4, gl.FLOAT, false, 0, 0);
|
|
3672
3795
|
}
|
|
3796
|
+
applyClipTest(ctx);
|
|
3673
3797
|
gl.drawElements(gl.TRIANGLES, handle.indexCount, gl.UNSIGNED_INT, 0);
|
|
3674
3798
|
gl.bindVertexArray(null);
|
|
3675
3799
|
gl.deleteBuffer(colorVbo);
|
|
@@ -3785,7 +3909,7 @@ function drawText(ctx, cmd) {
|
|
|
3785
3909
|
preparedPrograms.add(prog);
|
|
3786
3910
|
setProjAndModel(ctx, prog);
|
|
3787
3911
|
setColorMatrixUniforms(ctx, prog);
|
|
3788
|
-
|
|
3912
|
+
setAlphaUniform(ctx, prog, ctx.state.alpha);
|
|
3789
3913
|
}
|
|
3790
3914
|
drawTextGroup(ctx, group, prog, dx, dy);
|
|
3791
3915
|
}
|
|
@@ -3903,8 +4027,8 @@ function drawTextDecorations(ctx, decorations, dx, dy) {
|
|
|
3903
4027
|
if (!ibo) throw new Error("drawTextDecorations: createBuffer (IBO) returned null");
|
|
3904
4028
|
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, ibo);
|
|
3905
4029
|
gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, indices, gl.DYNAMIC_DRAW);
|
|
3906
|
-
|
|
3907
|
-
|
|
4030
|
+
setColorUniform(ctx, prog, rgba[0], rgba[1], rgba[2], rgba[3]);
|
|
4031
|
+
setAlphaUniform(ctx, prog, ctx.state.alpha);
|
|
3908
4032
|
gl.drawElements(gl.TRIANGLES, indices.length, gl.UNSIGNED_INT, 0);
|
|
3909
4033
|
gl.bindVertexArray(null);
|
|
3910
4034
|
gl.deleteVertexArray(vao);
|
|
@@ -3988,7 +4112,7 @@ function drawTextGroup(ctx, group, prog, dx, dy) {
|
|
|
3988
4112
|
if ("color" in group.fill) {
|
|
3989
4113
|
[r, g, b, a] = resolveColor(group.fill.color);
|
|
3990
4114
|
}
|
|
3991
|
-
|
|
4115
|
+
setColorUniform(ctx, prog, r, g, b, a);
|
|
3992
4116
|
const synthBoldAmount = group.synthetic.bold ? 0.08 : 0;
|
|
3993
4117
|
const uSynthBold = prog.uniform("u_synthBold");
|
|
3994
4118
|
if (uSynthBold !== void 0) gl.uniform1f(uSynthBold, synthBoldAmount);
|
|
@@ -4092,7 +4216,7 @@ function drawImage(ctx, cmd) {
|
|
|
4092
4216
|
);
|
|
4093
4217
|
gl.uniform1i(prog.uniform("u_sampler"), 0);
|
|
4094
4218
|
gl.uniform1f(prog.uniform("u_opacity"), cmd.opacity ?? 1);
|
|
4095
|
-
|
|
4219
|
+
setAlphaUniform(ctx, prog, ctx.state.alpha);
|
|
4096
4220
|
applyClipTest(ctx);
|
|
4097
4221
|
gl.drawElements(gl.TRIANGLES, 6, gl.UNSIGNED_INT, 0);
|
|
4098
4222
|
gl.bindVertexArray(null);
|
|
@@ -4321,6 +4445,8 @@ var WeaselRenderer = class {
|
|
|
4321
4445
|
const program = new ShaderProgram(this.gl, vertSrc, fragSrc);
|
|
4322
4446
|
program.lookupUniforms([...CUSTOM_KIT_UNIFORMS, ...extractUniformNames(fragSrc)]);
|
|
4323
4447
|
program.lookupAttributes(CUSTOM_ATTRIBUTES);
|
|
4448
|
+
const previous = this.programRegistry.get(handle.id);
|
|
4449
|
+
if (previous) this.gl.deleteProgram(previous.handle);
|
|
4324
4450
|
this.programRegistry.set(handle.id, program);
|
|
4325
4451
|
}
|
|
4326
4452
|
applyViewport() {
|
|
@@ -4419,7 +4545,7 @@ var WeaselRenderer = class {
|
|
|
4419
4545
|
}
|
|
4420
4546
|
this.meshCache.freeTransient();
|
|
4421
4547
|
this.meshCache.drainPendingDeletes();
|
|
4422
|
-
for (const prog of [this.pathFill, this.pathFillVColor, this.textSdf, this.textSdfR8, this.imageFill, this.gradFill]) {
|
|
4548
|
+
for (const prog of [this.pathFill, this.pathFillVColor, this.textSdf, this.textSdfR8, this.imageFill, this.gradFill, this.patternFill]) {
|
|
4423
4549
|
gl.deleteProgram(prog.handle);
|
|
4424
4550
|
}
|
|
4425
4551
|
for (const prog of this.programRegistry.values()) {
|
|
@@ -4446,6 +4572,7 @@ var WeaselRenderer = class {
|
|
|
4446
4572
|
const gl = this.gl;
|
|
4447
4573
|
this.meshCache.drainPendingDeletes();
|
|
4448
4574
|
resetBakeBudget(this.bakeBudget);
|
|
4575
|
+
this.groupState.reset();
|
|
4449
4576
|
gl.stencilMask(255);
|
|
4450
4577
|
gl.clear(gl.COLOR_BUFFER_BIT | gl.STENCIL_BUFFER_BIT);
|
|
4451
4578
|
const ctx = {
|
|
@@ -5202,9 +5329,15 @@ function beginPointerDrag(payload, source, startX, startY, ghostFn) {
|
|
|
5202
5329
|
function onUp(e) {
|
|
5203
5330
|
if (!activeDrag) return;
|
|
5204
5331
|
const zone = findZone(e.clientX, e.clientY, payload.kind);
|
|
5332
|
+
const dropped = activeDrag.payload;
|
|
5205
5333
|
activeDrag.lastZone?.onOver?.(false);
|
|
5206
|
-
|
|
5207
|
-
|
|
5334
|
+
try {
|
|
5335
|
+
if (zone) zone.onDrop(dropped, e.clientX, e.clientY);
|
|
5336
|
+
} catch (err) {
|
|
5337
|
+
console.error("weasel pointerDrag: drop zone onDrop threw", err);
|
|
5338
|
+
} finally {
|
|
5339
|
+
cleanup();
|
|
5340
|
+
}
|
|
5208
5341
|
}
|
|
5209
5342
|
function onCancel() {
|
|
5210
5343
|
activeDrag?.lastZone?.onOver?.(false);
|
|
@@ -5225,6 +5358,10 @@ var DRAG_THRESHOLD_PX_SQ = 25;
|
|
|
5225
5358
|
function useDragHandle(getPayload, options) {
|
|
5226
5359
|
const optsRef = useRef(options);
|
|
5227
5360
|
optsRef.current = options;
|
|
5361
|
+
const pendingTeardownRef = useRef(null);
|
|
5362
|
+
useEffect(() => () => {
|
|
5363
|
+
pendingTeardownRef.current?.();
|
|
5364
|
+
}, []);
|
|
5228
5365
|
const onPointerDown = useCallback((e) => {
|
|
5229
5366
|
if (e.pointerType === "mouse" && e.button !== 0) return;
|
|
5230
5367
|
const target = e.currentTarget;
|
|
@@ -5260,10 +5397,12 @@ function useDragHandle(getPayload, options) {
|
|
|
5260
5397
|
document.removeEventListener("pointermove", onMove);
|
|
5261
5398
|
document.removeEventListener("pointerup", onEnd);
|
|
5262
5399
|
document.removeEventListener("pointercancel", onEnd);
|
|
5400
|
+
pendingTeardownRef.current = null;
|
|
5263
5401
|
}
|
|
5264
5402
|
document.addEventListener("pointermove", onMove);
|
|
5265
5403
|
document.addEventListener("pointerup", onEnd);
|
|
5266
5404
|
document.addEventListener("pointercancel", onEnd);
|
|
5405
|
+
pendingTeardownRef.current = cleanup;
|
|
5267
5406
|
}, [getPayload]);
|
|
5268
5407
|
return { onPointerDown, style: { touchAction: "none" } };
|
|
5269
5408
|
}
|
|
@@ -9102,7 +9241,7 @@ var reorderBackwardAction = {
|
|
|
9102
9241
|
}
|
|
9103
9242
|
],
|
|
9104
9243
|
eligible: { capability: "edits-page" },
|
|
9105
|
-
requires: ["selection", "scene"],
|
|
9244
|
+
requires: ["selection", "scene", "applyOps"],
|
|
9106
9245
|
invoker: {
|
|
9107
9246
|
timing: "immediate",
|
|
9108
9247
|
run: (deps, params) => {
|
|
@@ -9269,6 +9408,7 @@ function makeAlignAction(edge) {
|
|
|
9269
9408
|
icon: ICON_FOR[edge],
|
|
9270
9409
|
group: "align",
|
|
9271
9410
|
eligible: { capability: "transforms-selection" },
|
|
9411
|
+
requires: ["selection", "scene"],
|
|
9272
9412
|
// No default keybindings — six edges/centers don't fit a clean default
|
|
9273
9413
|
// chord set. Wire bindings explicitly via the actions registry override map.
|
|
9274
9414
|
invoker: {
|
|
@@ -9280,7 +9420,14 @@ function makeAlignAction(edge) {
|
|
|
9280
9420
|
alignSelection(selection, scene, edge);
|
|
9281
9421
|
}
|
|
9282
9422
|
},
|
|
9283
|
-
|
|
9423
|
+
// Deps-aware, matching `alignSelection`'s own `ids.length < 2` guard: a
|
|
9424
|
+
// constant disabled reason greys the entry out forever (see
|
|
9425
|
+
// `requiresSelection`).
|
|
9426
|
+
enabled: (deps) => {
|
|
9427
|
+
const selection = deps?.selection;
|
|
9428
|
+
const count = selection?.get().length ?? 0;
|
|
9429
|
+
return count >= 2 ? true : ActionDisabledReason.SelectionRequired;
|
|
9430
|
+
}
|
|
9284
9431
|
};
|
|
9285
9432
|
}
|
|
9286
9433
|
var alignLeftAction = makeAlignAction("left");
|
|
@@ -9361,6 +9508,7 @@ function makeDistributeAction(axis) {
|
|
|
9361
9508
|
icon: ICON_FOR2[axis],
|
|
9362
9509
|
group: "distribute",
|
|
9363
9510
|
eligible: { capability: "transforms-selection" },
|
|
9511
|
+
requires: ["selection", "scene"],
|
|
9364
9512
|
// No default keybindings. Wire bindings explicitly via the actions registry.
|
|
9365
9513
|
invoker: {
|
|
9366
9514
|
timing: "immediate",
|
|
@@ -9371,7 +9519,14 @@ function makeDistributeAction(axis) {
|
|
|
9371
9519
|
distributeSelection(selection, scene, axis);
|
|
9372
9520
|
}
|
|
9373
9521
|
},
|
|
9374
|
-
|
|
9522
|
+
// Deps-aware, matching `distributeSelection`'s own `ids.length < 3` guard:
|
|
9523
|
+
// a constant disabled reason greys the entry out forever (see
|
|
9524
|
+
// `requiresSelection`).
|
|
9525
|
+
enabled: (deps) => {
|
|
9526
|
+
const selection = deps?.selection;
|
|
9527
|
+
const count = selection?.get().length ?? 0;
|
|
9528
|
+
return count >= 3 ? true : ActionDisabledReason.SelectionRequired;
|
|
9529
|
+
}
|
|
9375
9530
|
};
|
|
9376
9531
|
}
|
|
9377
9532
|
var distributeHorizontalAction = makeDistributeAction("x");
|
|
@@ -9455,7 +9610,91 @@ function pathToMultiPolygon(path, opts = {}) {
|
|
|
9455
9610
|
}
|
|
9456
9611
|
finalizeCurrent();
|
|
9457
9612
|
if (rings.length === 0) return [];
|
|
9458
|
-
return rings.
|
|
9613
|
+
return groupRings(rings, path.fillRule);
|
|
9614
|
+
}
|
|
9615
|
+
function ringSignedArea(ring) {
|
|
9616
|
+
let a = 0;
|
|
9617
|
+
for (let i = 0, n = ring.length - 1; i < n; i++) {
|
|
9618
|
+
a += ring[i][0] * ring[i + 1][1] - ring[i + 1][0] * ring[i][1];
|
|
9619
|
+
}
|
|
9620
|
+
return a * 0.5;
|
|
9621
|
+
}
|
|
9622
|
+
function ringBox(ring) {
|
|
9623
|
+
let minX = Infinity, minY = Infinity, maxX = -Infinity, maxY = -Infinity;
|
|
9624
|
+
for (const [x, y] of ring) {
|
|
9625
|
+
if (x < minX) minX = x;
|
|
9626
|
+
if (x > maxX) maxX = x;
|
|
9627
|
+
if (y < minY) minY = y;
|
|
9628
|
+
if (y > maxY) maxY = y;
|
|
9629
|
+
}
|
|
9630
|
+
return [minX, minY, maxX, maxY];
|
|
9631
|
+
}
|
|
9632
|
+
function pointInRing(ring, px, py) {
|
|
9633
|
+
let inside = false;
|
|
9634
|
+
for (let i = 0, n = ring.length - 1; i < n; i++) {
|
|
9635
|
+
const [ax, ay] = ring[i];
|
|
9636
|
+
const [bx, by] = ring[i + 1];
|
|
9637
|
+
if (ay > py !== by > py && px < (bx - ax) * (py - ay) / (by - ay) + ax) {
|
|
9638
|
+
inside = !inside;
|
|
9639
|
+
}
|
|
9640
|
+
}
|
|
9641
|
+
return inside;
|
|
9642
|
+
}
|
|
9643
|
+
function ringContains(outer, outerBox, inner, innerBox) {
|
|
9644
|
+
if (innerBox[0] < outerBox[0] || innerBox[1] < outerBox[1] || innerBox[2] > outerBox[2] || innerBox[3] > outerBox[3]) return false;
|
|
9645
|
+
const n = inner.length - 1;
|
|
9646
|
+
let votes = 0;
|
|
9647
|
+
for (const k of [0, Math.floor(n / 3), Math.floor(2 * n / 3)]) {
|
|
9648
|
+
if (pointInRing(outer, inner[k][0], inner[k][1])) votes++;
|
|
9649
|
+
}
|
|
9650
|
+
return votes >= 2;
|
|
9651
|
+
}
|
|
9652
|
+
function groupRings(rings, fillRule) {
|
|
9653
|
+
const n = rings.length;
|
|
9654
|
+
if (n === 1) return [[rings[0]]];
|
|
9655
|
+
const boxes = rings.map(ringBox);
|
|
9656
|
+
const orient = rings.map((r) => ringSignedArea(r) >= 0 ? 1 : -1);
|
|
9657
|
+
const parent = new Array(n).fill(-1);
|
|
9658
|
+
const children = rings.map(() => []);
|
|
9659
|
+
for (let i = 0; i < n; i++) {
|
|
9660
|
+
let best = -1;
|
|
9661
|
+
let bestArea = Infinity;
|
|
9662
|
+
for (let j = 0; j < n; j++) {
|
|
9663
|
+
if (i === j) continue;
|
|
9664
|
+
if (!ringContains(rings[j], boxes[j], rings[i], boxes[i])) continue;
|
|
9665
|
+
const area = (boxes[j][2] - boxes[j][0]) * (boxes[j][3] - boxes[j][1]);
|
|
9666
|
+
if (area < bestArea) {
|
|
9667
|
+
bestArea = area;
|
|
9668
|
+
best = j;
|
|
9669
|
+
}
|
|
9670
|
+
}
|
|
9671
|
+
parent[i] = best;
|
|
9672
|
+
}
|
|
9673
|
+
for (let i = 0; i < n; i++) if (parent[i] >= 0) children[parent[i]].push(i);
|
|
9674
|
+
const filled = new Array(n);
|
|
9675
|
+
for (let i = 0; i < n; i++) {
|
|
9676
|
+
let depth = 0;
|
|
9677
|
+
let winding = 0;
|
|
9678
|
+
for (let a = i; a >= 0; a = parent[a]) {
|
|
9679
|
+
winding += orient[a];
|
|
9680
|
+
if (a !== i) depth++;
|
|
9681
|
+
}
|
|
9682
|
+
filled[i] = fillRule === "evenodd" ? depth % 2 === 0 : winding !== 0;
|
|
9683
|
+
}
|
|
9684
|
+
const out = [];
|
|
9685
|
+
for (let i = 0; i < n; i++) {
|
|
9686
|
+
if (!filled[i]) continue;
|
|
9687
|
+
if (parent[i] >= 0 && filled[parent[i]]) continue;
|
|
9688
|
+
const polygon = [rings[i]];
|
|
9689
|
+
const queue = [...children[i]];
|
|
9690
|
+
while (queue.length > 0) {
|
|
9691
|
+
const c = queue.pop();
|
|
9692
|
+
if (filled[c]) queue.push(...children[c]);
|
|
9693
|
+
else polygon.push(rings[c]);
|
|
9694
|
+
}
|
|
9695
|
+
out.push(polygon);
|
|
9696
|
+
}
|
|
9697
|
+
return out;
|
|
9459
9698
|
}
|
|
9460
9699
|
function multiPolygonToPath(mp) {
|
|
9461
9700
|
let nCmds = 0;
|
|
@@ -9772,6 +10011,7 @@ function makePathfinderAction(op) {
|
|
|
9772
10011
|
icon: ICON_FOR3[op],
|
|
9773
10012
|
group: "pathfinder",
|
|
9774
10013
|
eligible: { capability: "creates-shapes" },
|
|
10014
|
+
requires: ["selection", "booleansAdapter"],
|
|
9775
10015
|
// No default keybindings — there's no industry-standard chord set for
|
|
9776
10016
|
// boolean ops. Wire bindings explicitly via the actions registry override map.
|
|
9777
10017
|
invoker: {
|
|
@@ -12169,10 +12409,11 @@ function createDispatcher(opts) {
|
|
|
12169
12409
|
uiOngoingByAction.set(actionId, gestureId);
|
|
12170
12410
|
notify2();
|
|
12171
12411
|
let ended = false;
|
|
12412
|
+
const live = () => !ended && inFlightHandles.get(gestureId) === handle;
|
|
12172
12413
|
return {
|
|
12173
12414
|
gestureId,
|
|
12174
12415
|
update(nextParams) {
|
|
12175
|
-
if (
|
|
12416
|
+
if (!live()) return;
|
|
12176
12417
|
if (!handle.onMove) return;
|
|
12177
12418
|
try {
|
|
12178
12419
|
handle.onMove(buildUiInvocationCtx(deps, nextParams));
|
|
@@ -12182,7 +12423,10 @@ function createDispatcher(opts) {
|
|
|
12182
12423
|
notify2();
|
|
12183
12424
|
},
|
|
12184
12425
|
end(reason) {
|
|
12185
|
-
if (
|
|
12426
|
+
if (!live()) {
|
|
12427
|
+
ended = true;
|
|
12428
|
+
return;
|
|
12429
|
+
}
|
|
12186
12430
|
ended = true;
|
|
12187
12431
|
if (handle.onEnd) {
|
|
12188
12432
|
try {
|
|
@@ -13509,6 +13753,7 @@ function useTools(opts) {
|
|
|
13509
13753
|
);
|
|
13510
13754
|
const active = contributions.focused;
|
|
13511
13755
|
const getActiveOverlays = contributions.overlays;
|
|
13756
|
+
const registryKey = Object.keys(slotted.registry).sort().join("|") + "#" + slotted.ambient.map((t) => t.id).join("|");
|
|
13512
13757
|
return useMemo(
|
|
13513
13758
|
() => ({
|
|
13514
13759
|
active,
|
|
@@ -13521,7 +13766,7 @@ function useTools(opts) {
|
|
|
13521
13766
|
has,
|
|
13522
13767
|
getActiveOverlays
|
|
13523
13768
|
}),
|
|
13524
|
-
[active, setActive, hotkeyEngaged, engageHotkey, disengageHotkey, has, getActiveOverlays]
|
|
13769
|
+
[active, setActive, hotkeyEngaged, engageHotkey, disengageHotkey, has, getActiveOverlays, registryKey]
|
|
13525
13770
|
);
|
|
13526
13771
|
}
|
|
13527
13772
|
|
|
@@ -15128,8 +15373,17 @@ function composeAffordanceLayer(id, label, affordances) {
|
|
|
15128
15373
|
// `buildAffordanceAt` share one implementation rather than two that can
|
|
15129
15374
|
// drift. This wrapper lifts the region's declared cursor and claim onto
|
|
15130
15375
|
// the binding, the way `buildAffordanceAt` lifts them onto `AffordanceHit`.
|
|
15131
|
-
hitTest: (wx, wy,
|
|
15132
|
-
const
|
|
15376
|
+
hitTest: (wx, wy, data, view, _dims, isVisible) => {
|
|
15377
|
+
const state = asChromeState(data);
|
|
15378
|
+
if (!state) return null;
|
|
15379
|
+
const hit = hitAffordanceRegions(
|
|
15380
|
+
affordances,
|
|
15381
|
+
wx,
|
|
15382
|
+
wy,
|
|
15383
|
+
state,
|
|
15384
|
+
view,
|
|
15385
|
+
isVisible ?? asIsVisible(data) ?? void 0
|
|
15386
|
+
);
|
|
15133
15387
|
if (!hit) return null;
|
|
15134
15388
|
const { cursor, strength, claimedKinds } = hit.region;
|
|
15135
15389
|
return {
|
|
@@ -15489,16 +15743,6 @@ function useRotateTool(adapter, options) {
|
|
|
15489
15743
|
[overlay, handleHitRadius, rotationHandleDistance]
|
|
15490
15744
|
);
|
|
15491
15745
|
}
|
|
15492
|
-
|
|
15493
|
-
// src/tools/builtin/hitExistingGate.ts
|
|
15494
|
-
function applyHitExistingGate(ctx, hitExisting) {
|
|
15495
|
-
if (!hitExisting) return false;
|
|
15496
|
-
const hit = hitExisting({ x: ctx.worldX, y: ctx.worldY });
|
|
15497
|
-
if (!hit) return false;
|
|
15498
|
-
const ids = Array.isArray(hit) ? hit : [hit];
|
|
15499
|
-
ctx.selection.set(ids);
|
|
15500
|
-
return true;
|
|
15501
|
-
}
|
|
15502
15746
|
function useHandTool(opts = {}) {
|
|
15503
15747
|
const inertia = opts.inertia === false ? false : opts.inertia;
|
|
15504
15748
|
const axis = opts.axis ?? "both";
|
|
@@ -15750,6 +15994,10 @@ function usePenTool(options) {
|
|
|
15750
15994
|
onEnd: (endCtx, reason) => {
|
|
15751
15995
|
const se = s();
|
|
15752
15996
|
if (reason === "cancel") {
|
|
15997
|
+
if (se.current && se.draggingHandleAt === se.current.anchors.length - 1) {
|
|
15998
|
+
se.current.anchors.pop();
|
|
15999
|
+
if (se.current.anchors.length === 0) se.current = null;
|
|
16000
|
+
}
|
|
15753
16001
|
se.draggingHandleAt = null;
|
|
15754
16002
|
forceRenderRef.current();
|
|
15755
16003
|
return;
|
|
@@ -17541,7 +17789,6 @@ function CanvasInner(props, ref) {
|
|
|
17541
17789
|
shaders,
|
|
17542
17790
|
previewIdsExtra,
|
|
17543
17791
|
previewPoseExtra,
|
|
17544
|
-
previewBoundsExtra,
|
|
17545
17792
|
gestureSource,
|
|
17546
17793
|
viewport,
|
|
17547
17794
|
backgroundFill,
|
|
@@ -17567,6 +17814,7 @@ function CanvasInner(props, ref) {
|
|
|
17567
17814
|
debugSinkRefForCtx.current = debugSink;
|
|
17568
17815
|
const adapter = adapterProp;
|
|
17569
17816
|
const canvasRef = useRef(null);
|
|
17817
|
+
const helpersForLayersRef = useRef(null);
|
|
17570
17818
|
const dimsRef = useRef({ width, height });
|
|
17571
17819
|
dimsRef.current = { width, height };
|
|
17572
17820
|
const getIsVisibleRef = useRef(getIsVisible);
|
|
@@ -17589,7 +17837,7 @@ function CanvasInner(props, ref) {
|
|
|
17589
17837
|
const isVisible = getIsVisibleRef.current?.() ?? alwaysVisible;
|
|
17590
17838
|
for (const layer of layers2) {
|
|
17591
17839
|
if (!layer.hitTest) continue;
|
|
17592
|
-
const hit = layer.hitTest(worldX, worldY,
|
|
17840
|
+
const hit = layer.hitTest(worldX, worldY, helpersForLayersRef.current, view, dims, isVisible);
|
|
17593
17841
|
if (hit) return { layerId: layer.id, hit };
|
|
17594
17842
|
}
|
|
17595
17843
|
return null;
|
|
@@ -17744,8 +17992,8 @@ function CanvasInner(props, ref) {
|
|
|
17744
17992
|
};
|
|
17745
17993
|
const selectedIdsForWiring = effectiveSelection.current;
|
|
17746
17994
|
const multiActive2 = selectedIdsForWiring.length > 1;
|
|
17747
|
-
const previewExtraRef = useRef({ previewPoseExtra
|
|
17748
|
-
previewExtraRef.current = { previewPoseExtra
|
|
17995
|
+
const previewExtraRef = useRef({ previewPoseExtra });
|
|
17996
|
+
previewExtraRef.current = { previewPoseExtra };
|
|
17749
17997
|
const effectiveBoundsOf = useMemo(() => {
|
|
17750
17998
|
return boundsOf2 ?? baseBoundsOf;
|
|
17751
17999
|
}, [boundsOf2, baseBoundsOf]);
|
|
@@ -17764,10 +18012,6 @@ function CanvasInner(props, ref) {
|
|
|
17764
18012
|
if (p != null) return geometry.getBounds(p);
|
|
17765
18013
|
}
|
|
17766
18014
|
const extras = previewExtraRef.current;
|
|
17767
|
-
if (extras.previewBoundsExtra) {
|
|
17768
|
-
const b = extras.previewBoundsExtra(id);
|
|
17769
|
-
if (b) return b;
|
|
17770
|
-
}
|
|
17771
18015
|
if (extras.previewPoseExtra) {
|
|
17772
18016
|
const p = extras.previewPoseExtra(id);
|
|
17773
18017
|
if (p != null) return geometry.getBounds(p);
|
|
@@ -17808,10 +18052,6 @@ function CanvasInner(props, ref) {
|
|
|
17808
18052
|
const p = firstPreviewPose(tools, id);
|
|
17809
18053
|
if (p != null) return geometry.getBounds(p);
|
|
17810
18054
|
}
|
|
17811
|
-
if (previewBoundsExtra) {
|
|
17812
|
-
const b = previewBoundsExtra(id);
|
|
17813
|
-
if (b) return b;
|
|
17814
|
-
}
|
|
17815
18055
|
if (previewPoseExtra) {
|
|
17816
18056
|
const p = previewPoseExtra(id);
|
|
17817
18057
|
if (p != null) return geometry.getBounds(p);
|
|
@@ -17847,6 +18087,7 @@ function CanvasInner(props, ref) {
|
|
|
17847
18087
|
getDebug: () => debugSink,
|
|
17848
18088
|
getIsVisible: () => getIsVisibleRef.current?.() ?? alwaysVisible
|
|
17849
18089
|
};
|
|
18090
|
+
helpersForLayersRef.current = helpersForLayers;
|
|
17850
18091
|
if (helpersRef) helpersRef.current = helpersForLayers;
|
|
17851
18092
|
const pointerDownRef = useRef(false);
|
|
17852
18093
|
const handlePointerDown = (e) => {
|
|
@@ -18028,6 +18269,11 @@ function CanvasInner(props, ref) {
|
|
|
18028
18269
|
);
|
|
18029
18270
|
renderer.render(commands, viewToMat3(effectiveView));
|
|
18030
18271
|
}, [layersWithDebug, width, height, effectiveView, debugSink, redrawNonce, dprProp]);
|
|
18272
|
+
useEffect(() => () => {
|
|
18273
|
+
glRendererRef.current?.dispose();
|
|
18274
|
+
glRendererRef.current = null;
|
|
18275
|
+
lastResizeRef.current = null;
|
|
18276
|
+
}, []);
|
|
18031
18277
|
const shaderIdKey = shaders?.map((h) => h.id).join("|") ?? "";
|
|
18032
18278
|
useEffect(() => {
|
|
18033
18279
|
const renderer = glRendererRef.current;
|
|
@@ -19492,6 +19738,89 @@ function poseContainsRotated(pose, wx, wy, tolerance) {
|
|
|
19492
19738
|
}
|
|
19493
19739
|
return poseContains(pose, wx, wy, tolerance);
|
|
19494
19740
|
}
|
|
19741
|
+
function hiddenLayerIds(layers) {
|
|
19742
|
+
const out = /* @__PURE__ */ new Set();
|
|
19743
|
+
for (const layer of layers ?? []) {
|
|
19744
|
+
if (layer.visible === false) out.add(layer.id);
|
|
19745
|
+
}
|
|
19746
|
+
return out;
|
|
19747
|
+
}
|
|
19748
|
+
function hitTestArea(scene, bounds) {
|
|
19749
|
+
const { x, y, width: w, height: h } = bounds;
|
|
19750
|
+
const area = [x, y, x + w, y, x + w, y + h, x, y + h];
|
|
19751
|
+
return hitTestAreaPolygon(scene, area, { x, y, width: w, height: h }, true);
|
|
19752
|
+
}
|
|
19753
|
+
function hitTestAreaPolygon(scene, area, areaBounds, areaIsRect = false) {
|
|
19754
|
+
const ab = areaBounds ?? boundsOf(area);
|
|
19755
|
+
if (!ab) return [];
|
|
19756
|
+
const hits = [];
|
|
19757
|
+
const hidden = hiddenLayerIds(scene.layers);
|
|
19758
|
+
const order = scene.renderOrderNodes();
|
|
19759
|
+
for (let i = 0; i < order.length; i++) {
|
|
19760
|
+
const node = order[i];
|
|
19761
|
+
if (node.kind === "container") continue;
|
|
19762
|
+
if (hidden.size > 0 && hidden.has(node.layer)) continue;
|
|
19763
|
+
const pose = node.pose;
|
|
19764
|
+
const silhouette = pose !== null && typeof pose === "object" && pose.kind === "polygon";
|
|
19765
|
+
const b = silhouette ? nodeMemo(node, "aabb", pose, () => aabbOfPose(pose)) : aabbOfPose(pose);
|
|
19766
|
+
if (!Number.isFinite(b.x) || !Number.isFinite(b.y) || !Number.isFinite(b.width) || !Number.isFinite(b.height)) {
|
|
19767
|
+
continue;
|
|
19768
|
+
}
|
|
19769
|
+
if (b.x >= ab.x + ab.width || b.x + b.width <= ab.x || b.y >= ab.y + ab.height || b.y + b.height <= ab.y) {
|
|
19770
|
+
continue;
|
|
19771
|
+
}
|
|
19772
|
+
if (areaIsRect && b.x >= ab.x && b.y >= ab.y && b.x + b.width <= ab.x + ab.width && b.y + b.height <= ab.y + ab.height) {
|
|
19773
|
+
hits.push(node.id);
|
|
19774
|
+
continue;
|
|
19775
|
+
}
|
|
19776
|
+
if (silhouette) {
|
|
19777
|
+
if (silhouetteOverlapsArea(pose.coords, area)) {
|
|
19778
|
+
hits.push(node.id);
|
|
19779
|
+
}
|
|
19780
|
+
continue;
|
|
19781
|
+
}
|
|
19782
|
+
const drawn = findShapeSilhouette(node, pose);
|
|
19783
|
+
if (drawn?.kind === "polygon") {
|
|
19784
|
+
if (silhouetteOverlapsArea(drawn.coords, area)) hits.push(node.id);
|
|
19785
|
+
continue;
|
|
19786
|
+
}
|
|
19787
|
+
hits.push(node.id);
|
|
19788
|
+
}
|
|
19789
|
+
return hits;
|
|
19790
|
+
}
|
|
19791
|
+
function silhouetteOverlapsArea(sil, area) {
|
|
19792
|
+
const ns = sil.length >> 1;
|
|
19793
|
+
const na = area.length >> 1;
|
|
19794
|
+
if (ns < 1 || na < 3) return false;
|
|
19795
|
+
for (let i = 0; i < ns; i++) {
|
|
19796
|
+
if (pointInPolygon(area, sil[i * 2], sil[i * 2 + 1])) return true;
|
|
19797
|
+
}
|
|
19798
|
+
for (let i = 0; i < na; i++) {
|
|
19799
|
+
if (pointInPolygon(sil, area[i * 2], area[i * 2 + 1])) return true;
|
|
19800
|
+
}
|
|
19801
|
+
for (let i = 0, j = ns - 1; i < ns; j = i++) {
|
|
19802
|
+
const ax = sil[j * 2], ay = sil[j * 2 + 1];
|
|
19803
|
+
const bx = sil[i * 2], by = sil[i * 2 + 1];
|
|
19804
|
+
for (let k = 0, l = na - 1; k < na; l = k++) {
|
|
19805
|
+
const cx = area[l * 2], cy = area[l * 2 + 1];
|
|
19806
|
+
const dx = area[k * 2], dy = area[k * 2 + 1];
|
|
19807
|
+
if (segmentsCross(ax, ay, bx, by, cx, cy, dx, dy)) return true;
|
|
19808
|
+
}
|
|
19809
|
+
}
|
|
19810
|
+
return false;
|
|
19811
|
+
}
|
|
19812
|
+
function boundsOf(coords) {
|
|
19813
|
+
if (coords.length < 2) return null;
|
|
19814
|
+
let minX = Infinity, minY = Infinity, maxX = -Infinity, maxY = -Infinity;
|
|
19815
|
+
for (let i = 0; i + 1 < coords.length; i += 2) {
|
|
19816
|
+
const x = coords[i], y = coords[i + 1];
|
|
19817
|
+
if (x < minX) minX = x;
|
|
19818
|
+
if (y < minY) minY = y;
|
|
19819
|
+
if (x > maxX) maxX = x;
|
|
19820
|
+
if (y > maxY) maxY = y;
|
|
19821
|
+
}
|
|
19822
|
+
return { x: minX, y: minY, width: maxX - minX, height: maxY - minY };
|
|
19823
|
+
}
|
|
19495
19824
|
|
|
19496
19825
|
// src/canvas/SceneCanvas/useSceneSelectTool.ts
|
|
19497
19826
|
var DEFAULT_PICK_TOLERANCE_PX = 4;
|
|
@@ -19591,7 +19920,9 @@ function useSceneSelectTool(args) {
|
|
|
19591
19920
|
}
|
|
19592
19921
|
const tolerance = pickTolerancePx / meanScale(getView?.()?.scale ?? { x: 1, y: 1 });
|
|
19593
19922
|
const out = [];
|
|
19923
|
+
const hidden = hiddenLayerIds(scene.layers);
|
|
19594
19924
|
for (const n of scene.renderOrderNodes()) {
|
|
19925
|
+
if (hidden.size > 0 && hidden.has(n.layer)) continue;
|
|
19595
19926
|
if (!poseContainsRotated(n.pose, wx, wy, tolerance)) continue;
|
|
19596
19927
|
if (shapePicking && !shapeCoversPoint(n, n.pose, wx, wy, { tolerance })) continue;
|
|
19597
19928
|
out.push(n.id);
|
|
@@ -20494,8 +20825,10 @@ function createPathAnchorAffordances(getAnchorState, opts = {}) {
|
|
|
20494
20825
|
const anchors = {
|
|
20495
20826
|
id: PATH_ANCHOR_CHROME_ID,
|
|
20496
20827
|
regions(state) {
|
|
20828
|
+
const editingId = getAnchorState()?.editingId ?? null;
|
|
20497
20829
|
const out = [];
|
|
20498
20830
|
for (const { id, path } of editablePaths(state)) {
|
|
20831
|
+
if (editingId !== null && id !== editingId) continue;
|
|
20499
20832
|
for (const a of enumerateAnchors(path)) {
|
|
20500
20833
|
out.push(point(
|
|
20501
20834
|
`${id}:anchor:${a.anchorIndex}`,
|
|
@@ -20758,80 +21091,6 @@ function DepRegistryProviderIfRoot({ children }) {
|
|
|
20758
21091
|
if (parent) return /* @__PURE__ */ jsx(Fragment, { children });
|
|
20759
21092
|
return /* @__PURE__ */ jsx(DepRegistryProvider, { children });
|
|
20760
21093
|
}
|
|
20761
|
-
function hitTestArea(scene, bounds) {
|
|
20762
|
-
const { x, y, width: w, height: h } = bounds;
|
|
20763
|
-
const area = [x, y, x + w, y, x + w, y + h, x, y + h];
|
|
20764
|
-
return hitTestAreaPolygon(scene, area, { x, y, width: w, height: h }, true);
|
|
20765
|
-
}
|
|
20766
|
-
function hitTestAreaPolygon(scene, area, areaBounds, areaIsRect = false) {
|
|
20767
|
-
const ab = areaBounds ?? boundsOf(area);
|
|
20768
|
-
if (!ab) return [];
|
|
20769
|
-
const hits = [];
|
|
20770
|
-
const order = scene.renderOrderNodes();
|
|
20771
|
-
for (let i = 0; i < order.length; i++) {
|
|
20772
|
-
const node = order[i];
|
|
20773
|
-
if (node.kind === "container") continue;
|
|
20774
|
-
const pose = node.pose;
|
|
20775
|
-
const silhouette = pose !== null && typeof pose === "object" && pose.kind === "polygon";
|
|
20776
|
-
const b = silhouette ? nodeMemo(node, "aabb", pose, () => aabbOfPose(pose)) : aabbOfPose(pose);
|
|
20777
|
-
if (!Number.isFinite(b.x) || !Number.isFinite(b.y) || !Number.isFinite(b.width) || !Number.isFinite(b.height)) {
|
|
20778
|
-
continue;
|
|
20779
|
-
}
|
|
20780
|
-
if (b.x >= ab.x + ab.width || b.x + b.width <= ab.x || b.y >= ab.y + ab.height || b.y + b.height <= ab.y) {
|
|
20781
|
-
continue;
|
|
20782
|
-
}
|
|
20783
|
-
if (areaIsRect && b.x >= ab.x && b.y >= ab.y && b.x + b.width <= ab.x + ab.width && b.y + b.height <= ab.y + ab.height) {
|
|
20784
|
-
hits.push(node.id);
|
|
20785
|
-
continue;
|
|
20786
|
-
}
|
|
20787
|
-
if (silhouette) {
|
|
20788
|
-
if (silhouetteOverlapsArea(pose.coords, area)) {
|
|
20789
|
-
hits.push(node.id);
|
|
20790
|
-
}
|
|
20791
|
-
continue;
|
|
20792
|
-
}
|
|
20793
|
-
const drawn = findShapeSilhouette(node, pose);
|
|
20794
|
-
if (drawn?.kind === "polygon") {
|
|
20795
|
-
if (silhouetteOverlapsArea(drawn.coords, area)) hits.push(node.id);
|
|
20796
|
-
continue;
|
|
20797
|
-
}
|
|
20798
|
-
hits.push(node.id);
|
|
20799
|
-
}
|
|
20800
|
-
return hits;
|
|
20801
|
-
}
|
|
20802
|
-
function silhouetteOverlapsArea(sil, area) {
|
|
20803
|
-
const ns = sil.length >> 1;
|
|
20804
|
-
const na = area.length >> 1;
|
|
20805
|
-
if (ns < 1 || na < 3) return false;
|
|
20806
|
-
for (let i = 0; i < ns; i++) {
|
|
20807
|
-
if (pointInPolygon(area, sil[i * 2], sil[i * 2 + 1])) return true;
|
|
20808
|
-
}
|
|
20809
|
-
for (let i = 0; i < na; i++) {
|
|
20810
|
-
if (pointInPolygon(sil, area[i * 2], area[i * 2 + 1])) return true;
|
|
20811
|
-
}
|
|
20812
|
-
for (let i = 0, j = ns - 1; i < ns; j = i++) {
|
|
20813
|
-
const ax = sil[j * 2], ay = sil[j * 2 + 1];
|
|
20814
|
-
const bx = sil[i * 2], by = sil[i * 2 + 1];
|
|
20815
|
-
for (let k = 0, l = na - 1; k < na; l = k++) {
|
|
20816
|
-
const cx = area[l * 2], cy = area[l * 2 + 1];
|
|
20817
|
-
const dx = area[k * 2], dy = area[k * 2 + 1];
|
|
20818
|
-
if (segmentsCross(ax, ay, bx, by, cx, cy, dx, dy)) return true;
|
|
20819
|
-
}
|
|
20820
|
-
}
|
|
20821
|
-
return false;
|
|
20822
|
-
}
|
|
20823
|
-
function boundsOf(coords) {
|
|
20824
|
-
if (coords.length < 2) return null;
|
|
20825
|
-
let minX = Infinity, minY = Infinity, maxX = -Infinity, maxY = -Infinity;
|
|
20826
|
-
for (let i = 0; i + 1 < coords.length; i += 2) {
|
|
20827
|
-
const x = coords[i], y = coords[i + 1];
|
|
20828
|
-
if (x < minX) minX = x;
|
|
20829
|
-
if (y < minY) minY = y;
|
|
20830
|
-
if (x > maxX) maxX = x;
|
|
20831
|
-
if (y > maxY) maxY = y;
|
|
20832
|
-
}
|
|
20833
|
-
return { x: minX, y: minY, width: maxX - minX, height: maxY - minY };
|
|
20834
|
-
}
|
|
20835
21094
|
function useViewDepSource(currentViewRef, onViewChange, recenter, hostSize) {
|
|
20836
21095
|
const viewApiRef = useRef({
|
|
20837
21096
|
get: () => currentViewRef.current,
|
|
@@ -21634,6 +21893,7 @@ function useActionsPropResolver(actions) {
|
|
|
21634
21893
|
}
|
|
21635
21894
|
if (!prop) return;
|
|
21636
21895
|
const unregisters = [];
|
|
21896
|
+
const restores = [];
|
|
21637
21897
|
const warnedIds = /* @__PURE__ */ new Set();
|
|
21638
21898
|
for (const [slotId, entry] of Object.entries(prop)) {
|
|
21639
21899
|
if (entry === null) {
|
|
@@ -21661,10 +21921,14 @@ function useActionsPropResolver(actions) {
|
|
|
21661
21921
|
}
|
|
21662
21922
|
const { id: _drop, ...rest } = entry;
|
|
21663
21923
|
const merged = { ...existing, ...rest };
|
|
21924
|
+
restores.push(() => {
|
|
21925
|
+
reg.register(existing);
|
|
21926
|
+
});
|
|
21664
21927
|
unregisters.push(reg.register(merged));
|
|
21665
21928
|
}
|
|
21666
21929
|
return () => {
|
|
21667
21930
|
for (const u of unregisters) u();
|
|
21931
|
+
for (const r of restores) r();
|
|
21668
21932
|
};
|
|
21669
21933
|
}, [reg, actions]);
|
|
21670
21934
|
}
|
|
@@ -24894,23 +25158,7 @@ function nestedHitTester(adapter, opts) {
|
|
|
24894
25158
|
};
|
|
24895
25159
|
return { pickOutermost, pickBest };
|
|
24896
25160
|
}
|
|
24897
|
-
|
|
24898
|
-
// src/features/paths/pathDistance.ts
|
|
24899
25161
|
var BEZIER_SAMPLES = 16;
|
|
24900
|
-
function pointSegDist2(px, py, ax, ay, bx, by) {
|
|
24901
|
-
const dx = bx - ax, dy = by - ay;
|
|
24902
|
-
const len2 = dx * dx + dy * dy;
|
|
24903
|
-
if (len2 === 0) {
|
|
24904
|
-
const ex2 = px - ax, ey2 = py - ay;
|
|
24905
|
-
return ex2 * ex2 + ey2 * ey2;
|
|
24906
|
-
}
|
|
24907
|
-
let t = ((px - ax) * dx + (py - ay) * dy) / len2;
|
|
24908
|
-
if (t < 0) t = 0;
|
|
24909
|
-
else if (t > 1) t = 1;
|
|
24910
|
-
const cx = ax + dx * t, cy = ay + dy * t;
|
|
24911
|
-
const ex = px - cx, ey = py - cy;
|
|
24912
|
-
return ex * ex + ey * ey;
|
|
24913
|
-
}
|
|
24914
25162
|
function pointCubicDist2(px, py, x0, y0, x1, y1, x2, y2, x3, y3) {
|
|
24915
25163
|
let prevX = x0, prevY = y0;
|
|
24916
25164
|
let best = Infinity;
|
|
@@ -24919,7 +25167,7 @@ function pointCubicDist2(px, py, x0, y0, x1, y1, x2, y2, x3, y3) {
|
|
|
24919
25167
|
const u = 1 - t;
|
|
24920
25168
|
const sx = u * u * u * x0 + 3 * u * u * t * x1 + 3 * u * t * t * x2 + t * t * t * x3;
|
|
24921
25169
|
const sy = u * u * u * y0 + 3 * u * u * t * y1 + 3 * u * t * t * y2 + t * t * t * y3;
|
|
24922
|
-
const d2 =
|
|
25170
|
+
const d2 = pointSegmentDist2(px, py, prevX, prevY, sx, sy);
|
|
24923
25171
|
if (d2 < best) best = d2;
|
|
24924
25172
|
prevX = sx;
|
|
24925
25173
|
prevY = sy;
|
|
@@ -24956,7 +25204,7 @@ function polygonPathDistance(path, px, py) {
|
|
|
24956
25204
|
ci += 2;
|
|
24957
25205
|
} else if (cmd === PATH_L) {
|
|
24958
25206
|
const x = coords[ci], y = coords[ci + 1];
|
|
24959
|
-
const d2 =
|
|
25207
|
+
const d2 = pointSegmentDist2(px, py, curX, curY, x, y);
|
|
24960
25208
|
if (d2 < best) best = d2;
|
|
24961
25209
|
curX = x;
|
|
24962
25210
|
curY = y;
|
|
@@ -24983,7 +25231,7 @@ function polygonPathDistance(path, px, py) {
|
|
|
24983
25231
|
curY = y;
|
|
24984
25232
|
ci += 4;
|
|
24985
25233
|
} else if (cmd === PATH_Z) {
|
|
24986
|
-
const d2 =
|
|
25234
|
+
const d2 = pointSegmentDist2(px, py, curX, curY, startX, startY);
|
|
24987
25235
|
if (d2 < best) best = d2;
|
|
24988
25236
|
curX = startX;
|
|
24989
25237
|
curY = startY;
|
|
@@ -28338,6 +28586,6 @@ function mergeContributions(...bundles) {
|
|
|
28338
28586
|
return out;
|
|
28339
28587
|
}
|
|
28340
28588
|
|
|
28341
|
-
export { ALWAYS, ANCHOR_HIT_BASE_PX, ActionsProviderIfRoot, ActiveToolContextProvider, ActiveToolContextProviderIfRoot, BUNDLE_TOOLS, COARSE_TARGET_SCALE, CURVE_REPS, ColorOverrideRegistry, CropIcon, CursorCoordsHud, DEFAULT_ALPHA_DECAY, DEFAULT_ALPHA_MIN, DEFAULT_DEBUG_STROKES, DEFAULT_DEBUG_THEME, DEFAULT_DEVICE_PROFILE, DEFAULT_FILL_COLOR, DEFAULT_HANDLE_SIZE2 as DEFAULT_HANDLE_SIZE, DEFAULT_PALETTE, DEFAULT_ROTATION_HANDLE_DISTANCE, DEFAULT_STROKE_COLOR, DEFAULT_TEXT_STYLE, DEFAULT_VELOCITY_DECAY, DepRegistryProviderIfRoot, DeviceProfileProvider, DivideIcon, EASINGS, EllipseIcon, ExcludeIcon, EyedropperIcon, FALLBACK_FIT_VIEW, GHOST_STROKE, HANDLE_BASE_PX, HandIcon, IDENTITY_COLOR_MATRIX, IDENTITY_POSE_COMPOSITION, IntersectIcon, KIT_SHAPE_KINDS, LassoIcon, LineIcon, MIXED, MOVE_ANCHORS, MinimapCanvas, NEVER, OUTLINE_MIN_SCREEN_PX, PATH_ANCHOR_CHROME_ID, PenIcon, PencilIcon, PickHud, PointerProviderIfRoot, PolygonIcon, RECT_ALIGN_PROJECTION, ROTATION_HANDLE_BASE_PX, RectIcon, SPRING_PRESETS, SceneCanvas, SceneViewCanvas, SelectIcon, SelectionContextProvider, SelectionContextProviderIfRoot, ShaderCompileError, StarIcon, SubtractIcon, TextIcon, UnionIcon, UnknownIcon, VERSION, WeaselProvider, WeaselRenderer, aabbCenter, actionIs, alignDeltaFor, alignInsertBehavior, alignMoveBehavior, alignResizeBehavior, alignedStrokeRect, always, and, animateLifecycle, animateOnSetPose, annulusSemiAxes, applyBooleanOp,
|
|
28342
|
-
//# sourceMappingURL=chunk-
|
|
28343
|
-
//# sourceMappingURL=chunk-
|
|
28589
|
+
export { ALWAYS, ANCHOR_HIT_BASE_PX, ActionsProviderIfRoot, ActiveToolContextProvider, ActiveToolContextProviderIfRoot, BUNDLE_TOOLS, COARSE_TARGET_SCALE, CURVE_REPS, ColorOverrideRegistry, CropIcon, CursorCoordsHud, DEFAULT_ALPHA_DECAY, DEFAULT_ALPHA_MIN, DEFAULT_DEBUG_STROKES, DEFAULT_DEBUG_THEME, DEFAULT_DEVICE_PROFILE, DEFAULT_FILL_COLOR, DEFAULT_HANDLE_SIZE2 as DEFAULT_HANDLE_SIZE, DEFAULT_PALETTE, DEFAULT_ROTATION_HANDLE_DISTANCE, DEFAULT_STROKE_COLOR, DEFAULT_TEXT_STYLE, DEFAULT_VELOCITY_DECAY, DepRegistryProviderIfRoot, DeviceProfileProvider, DivideIcon, EASINGS, EllipseIcon, ExcludeIcon, EyedropperIcon, FALLBACK_FIT_VIEW, GHOST_STROKE, HANDLE_BASE_PX, HandIcon, IDENTITY_COLOR_MATRIX, IDENTITY_POSE_COMPOSITION, IntersectIcon, KIT_SHAPE_KINDS, LassoIcon, LineIcon, MIXED, MOVE_ANCHORS, MinimapCanvas, NEVER, OUTLINE_MIN_SCREEN_PX, PATH_ANCHOR_CHROME_ID, PenIcon, PencilIcon, PickHud, PointerProviderIfRoot, PolygonIcon, RECT_ALIGN_PROJECTION, ROTATION_HANDLE_BASE_PX, RectIcon, SPRING_PRESETS, SceneCanvas, SceneViewCanvas, SelectIcon, SelectionContextProvider, SelectionContextProviderIfRoot, ShaderCompileError, StarIcon, SubtractIcon, TextIcon, UnionIcon, UnknownIcon, VERSION, WeaselProvider, WeaselRenderer, aabbCenter, actionIs, alignDeltaFor, alignInsertBehavior, alignMoveBehavior, alignResizeBehavior, alignedStrokeRect, always, and, animateLifecycle, animateOnSetPose, annulusSemiAxes, applyBooleanOp, applyStyleToRange, areaSelectAction, arrayAdapter, asNodeId, bezierCubic, bezierQuadratic, buildChromeCtx, buildGradientRamp, buildRuleCtx, buildSceneViewCommands, canBringForward, canHover, canSendBackward, capabilityAll, capabilityIn, capabilityIs, capabilityNot, caretIndexAt, cellAt, charOffsetToDomPosition, clampView, clearSelectionAction, clientToCanvas, clipboardCopyAction, clipboardCutAction, cloneAction, coarsePointer, composeAffordanceLayer, composePath, composeRectPose, composeSelectionPose, composeWorldPose, computeFitView2 as computeFitView, computeIndicatorCommand, computeWheelAction, cond, constrainTo45, containedThenNearest, countPathAnchors, createCellHighlightLayer, createChildrenLayer, createCornerResizeAffordance, createDebugOverlayLayer, createDebugSink, createDispatcher, createGridLayer, createGuidesLayer, createHistory2 as createHistory, createMarkdownRenderer, createMoveToIndexOp, createNodeProperties, createNodeRouting, createParallaxLayer, createPathAnchorAffordances, createPathEditingOverlayLayer, createPathLayer, createPenPreviewLayer, createReorderOp, createRotationAffordance, createScene, createSelectionHandlesLayer, createSelectionOutlineLayer, createSelectionOverlayLayer, createSetDataOp, createSetLayerOp, createSetPathOp, createSetTextOp, createTextLayer, createViewportLayer, cycleVertexColors, decomposePath, decomposeRectPose, defaultCommitAdapter, defaultDrawOne, defaultLabelTextRenderer, defaultNodeProperties, defaultNodeRouting, defaultVisibilityRules, defineTool, defineViewportTool, deriveAlignmentGuides, deriveParallaxView, describeRule, domPositionToCharOffset, domToRuns, drawLayers, easeIn, easeInBack, easeInBounce, easeInCirc, easeInCubic, easeInElastic, easeInExpo, easeInOut, easeInOutBack, easeInOutBounce, easeInOutCirc, easeInOutCubic, easeInOutElastic, easeInOutExpo, easeInOutQuad, easeInOutQuart, easeInOutQuint, easeInOutSine, easeInQuad, easeInQuart, easeInQuint, easeInSine, easeOut, easeOutBack, easeOutBounce, easeOutCirc, easeOutCubic2 as easeOutCubic, easeOutElastic, easeOutExpo, easeOutQuad, easeOutQuart, easeOutQuint, easeOutSine, editAnchorsAction, enterTextEditAction, enumerateAnchors, evaluate, fillInPoseFrame, fillToBoundsFrame, findNodeShape, findShapeInk, findShapeSilhouette, fitTextPose, fitToBounds, fitViewToBounds, fitZoom, focused, fontString, forEachCoalesced, freeform, gateLayer, gesturing, getAlpha01, getImageBitmap, getNodeShapes, getStylusData, gradientForBounds, gradientGeometry, hexToRgba, hitAffordanceRegions, hitAnchor, hitRotationHandle, hovering, hoveringSelected, imageStatus, inferredNodeProperties, inferredNodeRouting, insertAction, isEditableTarget2 as isEditableTarget, isPatternSpec, lassoSelectAction, layoutMarkdown, lerpColorArray, lerpOklab, lerpOklch, linear, liveScope, makeViewportZoomAction, markdownToRuns, mat3, matchAlignment, matchesKeyBinding, meanScale, measureText, measureTextBounds, measuredWidth, mergeAlphaFromPrev, mergeContributions, modeIn, modeIs, modeNot, modifierHeld, momentum, moveAction, multiActive, nearest, nearestWithin, nestedHitTester, never, nodeHasFlag, none, normalizeHex, not, nurbs, oklabToOklch, oklabToSrgbU8, oklchToOklab, openFilePicker, or, parseColor, parseColorToRgba255, parseDebugFlags, pathContainsPoint, pathContainsPolygon, pathContainsRect, pathDistanceToPoint, pathDivide, pathExclude, pathFromD, pathInPoseFrame, pathInWorld, pathIntersect, pathIntersectsPolygon, pathIntersectsRect, pathOriginProjection, pathSubtract, pathToAnchors, pathUnion, pickTopMostHit, pinchZoomAction, planPixelRender, pointInRotatedRect, pointInTextPose, poseRotationOf, pressureToWidth, rainbowVertexColors, rebaseLocalPose, rectCorners, registerContentHandler, registerNodeShape, registerProgram, renderLabel, renderSceneToCanvas, renderSceneToPixels, resizeAction, resolveColor, resolveDeviceProfile, resolveFillPattern, resolvePatternSpec, resolveRuns, resolveTextStyle, resolveVisibility, rgbaToHex, rotateAction, rotateAroundAABBCenter, rotatePathAround, rotatePoint, rotatedRectCorners, rotationDegreesUnit, rotationHandle, roundToCell, runsToDom, runsToMarkdown, runsToPlainText, sampleGradientStops, sceneFromJSON, sceneNodeClientRect, sceneToAdapter, scopeBindings, screenToWorld, selectFromLasso, selectionAtLeast, selectionEmpty, selectionIs, setFlagOverRange, shapeCoversPoint, sliceAction, snapPoint, solidVertexColors, specificity, spiro, splitPathByLine, splitSubpaths, springPose, springVertexColors, srgbU8ToOklab, staggerVertexColors, startThresholdDrag, styleAtRange, subscribeImageReady, tessellate, tessellateStroke, textCommand, textLineBoxes, tileGrid, toHex8, toRuns, translatePoseViaDescriptor, translateRectPose, tweenPose, tweenVertexColors, unionBounds, unionBoundsPath, useActiveToolContext, useAlign, useAnimator, useArrayAdapter, useAutoCenter, useBooleans, useBooleansAdapter, useCanvasFocus, useCanvasSize, useDecayLoop, useDeviceProfile, useDistribute, useDragGesture, useDragHandle, useDragRadial, useDragRect, useDropZone, useEllipseTool, useEyedropperTool, useGestureDispatcher, useGridCellHover, useGuides, useHandTool, useHandleDrag, useHoverTracking, useImageTool, useKeybindings, useLassoTool, useLineTool, useOptionalActiveToolContext, usePenTool, usePencilTool, usePinchGesture, usePinchZoomTool, usePointerStylus, usePolygonTool, usePublishSelection, useRectTool, useResizePolicy, useRotateTool, useScene, useSceneAdapter, useSceneTextEdit, useSelectTool, useSelection, useSelectionContext, useSimulation, useSliceDep, useStandardActions, useStarTool, useTextEdit, useTextTool, useTools, useVelocityTracker, useViewAnimation, useViewTween, useZoom, verticalAlignOffset, viewToMat3, viewToTransform, viewportDragPanAction, viewportZoomAction, viewportsAt, when, withAlpha01, withCoord, withGradientKind, worldEditToStorage, worldPoseLookup, worldToScreen, zoomAt, zoomAtLeast };
|
|
28590
|
+
//# sourceMappingURL=chunk-AYGSXNY3.js.map
|
|
28591
|
+
//# sourceMappingURL=chunk-AYGSXNY3.js.map
|