@weasel-js/core 1.4.0-pre.1 → 1.4.1
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 +484 -0
- package/README.md +22 -18
- package/dist/{DrawCommand-b-z1bCT-.d.ts → DrawCommand-Ch8W63oQ.d.ts} +34 -2
- package/dist/{chunk-FUQWXDG3.js → chunk-NU7D64RL.js} +996 -413
- package/dist/chunk-NU7D64RL.js.map +1 -0
- package/dist/{chunk-H6E6KPTU.js → chunk-TORKRNFY.js} +21 -11
- package/dist/chunk-TORKRNFY.js.map +1 -0
- package/dist/index.d.ts +268 -90
- package/dist/index.js +2 -2
- package/dist/{registry-sBLZYWI1.d.ts → registry-BwY_DxJM.d.ts} +81 -21
- package/dist/renderer.d.ts +3 -3
- package/dist/renderer.js +2 -2
- package/dist/routing.d.ts +3 -2
- package/dist/routing.js +1 -1
- package/dist/{stroke-B_BxktoE.d.ts → stroke-Dq8nL4A2.d.ts} +66 -1
- package/package.json +9 -9
- package/dist/chunk-FUQWXDG3.js.map +0 -1
- package/dist/chunk-H6E6KPTU.js.map +0 -1
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { ActionDisabledReason, useOptionalDepRegistry, DepRegistryProvider, useActionsRegistry, ActionsProvider, useDepRegistry, reportRouteConflicts, buildDepsFromRequires, useDepSource, actionBindings } from './chunk-
|
|
1
|
+
import { ActionDisabledReason, useOptionalDepRegistry, DepRegistryProvider, useActionsRegistry, ActionsProvider, useDepRegistry, reportRouteConflicts, buildDepsFromRequires, useDepSource, actionBindings } from './chunk-TORKRNFY.js';
|
|
2
2
|
import { scratchKey, createTransformOp, snap, getScratch, createReparentOp, setScratch } from './chunk-Y5KS66G7.js';
|
|
3
3
|
import { fixedCornerOf, DEFAULT_RESIZE_BEHAVIORS, CORNER_ANCHORS, cornerPoint } from './chunk-BLJNRMKB.js';
|
|
4
4
|
import { AUTO_POSE_DESCRIPTOR, resolveUnit, polylineFromPoints, starPath, regularPolygonPath, linePath, ellipsePath, rectPath, polygonFromPoints, PATH_M, PATH_L, PATH_Z, RECT_POSE_DESCRIPTOR, pathPoseDescriptor, withinPxRadius, boundsOfPath, PATH_Q, PATH_C, DEFAULT_FLATTEN_TOLERANCE, flattenQuadratic, flattenCubic, PathBuilder, pointInPath, strokeHitTest, transformPath, translatePath, pxExtent, remapRotatedLeaf, withinPxBox, flattenCubicWithArcLen, flattenQuadraticWithArcLen, PATH_CMD_LENGTHS, pointToGridCell } from './chunk-SBFC6J3C.js';
|
|
@@ -6,7 +6,7 @@ import { dispatchApplyBatch, dlog, dwarn, usePointerContext, PointerContextProvi
|
|
|
6
6
|
import { createSetSelectionOp } from './chunk-ZB7UYJVG.js';
|
|
7
7
|
import { registerOpFactory, createDeleteOp, createInsertOp, rebuildOp } from './chunk-2KKYDDDD.js';
|
|
8
8
|
import { getTexture, chunks, dots, crosshatch, hatch } from './chunk-BJN5ZRIJ.js';
|
|
9
|
-
import { createContext, createElement, forwardRef, useMemo, useRef, useCallback, useState, useImperativeHandle, useSyncExternalStore,
|
|
9
|
+
import { createContext, createElement, forwardRef, useMemo, useRef, useCallback, useState, useEffect, useImperativeHandle, useSyncExternalStore, useLayoutEffect, useContext, useId, useReducer } from 'react';
|
|
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, syncDynamicPageTexture, ensureFontTexture, dynamicPageTextureId, textureCacheKey } 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 { resolveTextStyle, resolveAlign, resolveRuns, cachedLayoutRuns, verticalAlignOffset, runsToPlainText, toRuns, fontString, textLineBoxes } from '@weasel-js/text';
|
|
@@ -19,12 +19,13 @@ import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
|
19
19
|
import polygonClipping from 'polygon-clipping';
|
|
20
20
|
import { matchSpec, RESERVED_ID_PREFIXES, RESERVED_ID_NAMES, parseTargetSpec, mimeMatchesGlob } from '@weasel-js/gestures';
|
|
21
21
|
import { NORMAL, IMPLICIT_TAGS } from '@weasel-js/modes';
|
|
22
|
-
import { cursorFor } from '@weasel-js/cursor';
|
|
22
|
+
import { GLYPHS, cursorWorldSize, cursorPaintOps, chromeLineWidthScale, cursorPaintMatrix, resolveCursorTier, cursorFor, resolveCursor } from '@weasel-js/cursor';
|
|
23
|
+
export { bakeCursor, cursorFor, resolveCursor, resolveCursorTier } from '@weasel-js/cursor';
|
|
23
24
|
import { createHistory } from '@weasel-js/history';
|
|
24
25
|
export * from '@weasel-js/history';
|
|
25
26
|
|
|
26
27
|
// src/version.ts
|
|
27
|
-
var VERSION = "1.4.
|
|
28
|
+
var VERSION = "1.4.1" ;
|
|
28
29
|
|
|
29
30
|
// src/features/grid/roundToCell.ts
|
|
30
31
|
function roundToCell(value, cellSize) {
|
|
@@ -257,6 +258,44 @@ void main() {
|
|
|
257
258
|
}
|
|
258
259
|
`
|
|
259
260
|
);
|
|
261
|
+
var IMAGE_VOPACITY_VERT_SRC = (
|
|
262
|
+
/* glsl */
|
|
263
|
+
`#version 300 es
|
|
264
|
+
in vec2 a_position;
|
|
265
|
+
in vec2 a_uv;
|
|
266
|
+
in float a_opacity;
|
|
267
|
+
uniform mat3 u_proj;
|
|
268
|
+
uniform mat3 u_model;
|
|
269
|
+
out vec2 v_uv;
|
|
270
|
+
out float v_opacity;
|
|
271
|
+
void main() {
|
|
272
|
+
vec3 screen = u_model * vec3(a_position, 1.0);
|
|
273
|
+
vec3 clip = u_proj * vec3(screen.xy, 1.0);
|
|
274
|
+
gl_Position = vec4(clip.xy, 0.0, 1.0);
|
|
275
|
+
v_uv = a_uv;
|
|
276
|
+
v_opacity = a_opacity;
|
|
277
|
+
}
|
|
278
|
+
`
|
|
279
|
+
);
|
|
280
|
+
var IMAGE_VOPACITY_FRAG_SRC = (
|
|
281
|
+
/* glsl */
|
|
282
|
+
`#version 300 es
|
|
283
|
+
precision highp float;
|
|
284
|
+
in vec2 v_uv;
|
|
285
|
+
in float v_opacity;
|
|
286
|
+
uniform sampler2D u_sampler;
|
|
287
|
+
uniform float u_alpha;
|
|
288
|
+
uniform mat4 u_colorMatrix;
|
|
289
|
+
uniform vec4 u_colorBias;
|
|
290
|
+
out vec4 outColor;
|
|
291
|
+
void main() {
|
|
292
|
+
vec4 texel = texture(u_sampler, v_uv);
|
|
293
|
+
vec4 mapped = clamp(u_colorMatrix * texel + u_colorBias, 0.0, 1.0);
|
|
294
|
+
float a = mapped.a * v_opacity * u_alpha;
|
|
295
|
+
outColor = vec4(mapped.rgb * a, a);
|
|
296
|
+
}
|
|
297
|
+
`
|
|
298
|
+
);
|
|
260
299
|
var IMAGE_FILL_UNIFORMS = [
|
|
261
300
|
"u_proj",
|
|
262
301
|
"u_model",
|
|
@@ -267,6 +306,15 @@ var IMAGE_FILL_UNIFORMS = [
|
|
|
267
306
|
"u_colorBias"
|
|
268
307
|
];
|
|
269
308
|
var IMAGE_FILL_ATTRIBUTES = ["a_position", "a_uv"];
|
|
309
|
+
var IMAGE_VOPACITY_UNIFORMS = [
|
|
310
|
+
"u_proj",
|
|
311
|
+
"u_model",
|
|
312
|
+
"u_sampler",
|
|
313
|
+
"u_alpha",
|
|
314
|
+
"u_colorMatrix",
|
|
315
|
+
"u_colorBias"
|
|
316
|
+
];
|
|
317
|
+
var IMAGE_VOPACITY_ATTRIBUTES = ["a_position", "a_uv", "a_opacity"];
|
|
270
318
|
|
|
271
319
|
// src/renderer/shaders/gradFill.ts
|
|
272
320
|
var GRAD_VERT_SRC = (
|
|
@@ -1516,6 +1564,9 @@ function _resetPaintKindsForTests() {
|
|
|
1516
1564
|
seedBuiltins();
|
|
1517
1565
|
bumpNodeMemoGeneration();
|
|
1518
1566
|
}
|
|
1567
|
+
|
|
1568
|
+
// src/renderer/DrawCommand.ts
|
|
1569
|
+
var SPRITE_STRIDE = 9;
|
|
1519
1570
|
function tessellate(path, opts = {}) {
|
|
1520
1571
|
if (path.kind === "rect") return tessellateRect(path);
|
|
1521
1572
|
return tessellatePolygon(path, opts);
|
|
@@ -3240,6 +3291,210 @@ var SolidBatch = class {
|
|
|
3240
3291
|
}
|
|
3241
3292
|
};
|
|
3242
3293
|
|
|
3294
|
+
// src/renderer/imageBatch.ts
|
|
3295
|
+
var MAX_IMAGE_VERTICES_PER_BATCH = 32768;
|
|
3296
|
+
var FLOATS_PER_VERTEX2 = 5;
|
|
3297
|
+
var INITIAL_QUADS = 64;
|
|
3298
|
+
var TIERS = [
|
|
3299
|
+
{ quads: 1, slots: 64 },
|
|
3300
|
+
{ quads: 16, slots: 64 },
|
|
3301
|
+
{ quads: 256, slots: 16 }
|
|
3302
|
+
];
|
|
3303
|
+
TIERS[0].slots;
|
|
3304
|
+
var IMAGE_LARGE_RING_SIZE = 4;
|
|
3305
|
+
function doubledTo2(from, need) {
|
|
3306
|
+
let capacity = from;
|
|
3307
|
+
while (capacity < need) capacity *= 2;
|
|
3308
|
+
return capacity;
|
|
3309
|
+
}
|
|
3310
|
+
function quadIndices(quads) {
|
|
3311
|
+
const out = new Uint32Array(quads * 6);
|
|
3312
|
+
for (let q = 0; q < quads; q++) {
|
|
3313
|
+
const b = q * 4;
|
|
3314
|
+
const j = q * 6;
|
|
3315
|
+
out[j] = b;
|
|
3316
|
+
out[j + 1] = b + 1;
|
|
3317
|
+
out[j + 2] = b + 2;
|
|
3318
|
+
out[j + 3] = b;
|
|
3319
|
+
out[j + 4] = b + 2;
|
|
3320
|
+
out[j + 5] = b + 3;
|
|
3321
|
+
}
|
|
3322
|
+
return out;
|
|
3323
|
+
}
|
|
3324
|
+
var ImageBatch = class {
|
|
3325
|
+
gl;
|
|
3326
|
+
aPos;
|
|
3327
|
+
aUv;
|
|
3328
|
+
aOpacity;
|
|
3329
|
+
/** One ring per tier, cycled per flush. Slots are created on first use, so a
|
|
3330
|
+
* renderer that flushes rarely allocates as few as it flushes. */
|
|
3331
|
+
rings = TIERS.map((t) => new Array(t.slots).fill(void 0));
|
|
3332
|
+
nextInRing = TIERS.map(() => 0);
|
|
3333
|
+
/** For flushes past the largest tier; these sets grow to fit. */
|
|
3334
|
+
largeRing = new Array(IMAGE_LARGE_RING_SIZE).fill(void 0);
|
|
3335
|
+
nextLarge = 0;
|
|
3336
|
+
verts = new Float32Array(INITIAL_QUADS * 4 * FLOATS_PER_VERTEX2);
|
|
3337
|
+
nQuads = 0;
|
|
3338
|
+
constructor(gl, prog) {
|
|
3339
|
+
const aPos = prog.attribute("a_position");
|
|
3340
|
+
const aUv = prog.attribute("a_uv");
|
|
3341
|
+
const aOpacity = prog.attribute("a_opacity");
|
|
3342
|
+
if (aPos === void 0 || aUv === void 0 || aOpacity === void 0) {
|
|
3343
|
+
throw new Error(
|
|
3344
|
+
"ImageBatch: vertex-opacity program is missing a_position / a_uv / a_opacity"
|
|
3345
|
+
);
|
|
3346
|
+
}
|
|
3347
|
+
this.gl = gl;
|
|
3348
|
+
this.aPos = aPos;
|
|
3349
|
+
this.aUv = aUv;
|
|
3350
|
+
this.aOpacity = aOpacity;
|
|
3351
|
+
}
|
|
3352
|
+
/** Indices staged — what a caller passes to `drawElements`. */
|
|
3353
|
+
get length() {
|
|
3354
|
+
return this.nQuads * 6;
|
|
3355
|
+
}
|
|
3356
|
+
get quads() {
|
|
3357
|
+
return this.nQuads;
|
|
3358
|
+
}
|
|
3359
|
+
/** Whether staging one more quad would put the run past the per-flush cap. */
|
|
3360
|
+
wouldOverflow() {
|
|
3361
|
+
return (this.nQuads + 1) * 4 > MAX_IMAGE_VERTICES_PER_BATCH;
|
|
3362
|
+
}
|
|
3363
|
+
/**
|
|
3364
|
+
* Append one image quad: the destination rect `(x, y, w, h)` mapped through
|
|
3365
|
+
* `m`, sampling `(u0, v0)`-`(u1, v1)`, every corner carrying `opacity`.
|
|
3366
|
+
*
|
|
3367
|
+
* An affine maps a rect to a parallelogram, so two triangles still cover it
|
|
3368
|
+
* and the batch draws at `u_model` identity. Corners wind top-left,
|
|
3369
|
+
* top-right, bottom-right, bottom-left, with UVs following — the flips a
|
|
3370
|
+
* command asks for are already in the `u`/`v` the caller passes.
|
|
3371
|
+
*/
|
|
3372
|
+
pushQuad(x, y, w, h, m, u0, v0, u1, v1, opacity) {
|
|
3373
|
+
this.reserve();
|
|
3374
|
+
const v = this.verts;
|
|
3375
|
+
let i = this.nQuads * 4 * FLOATS_PER_VERTEX2;
|
|
3376
|
+
const ma = m[0], mb = m[1], mc = m[3], md = m[4], mtx = m[6], mty = m[7];
|
|
3377
|
+
const x1 = x + w;
|
|
3378
|
+
const y1 = y + h;
|
|
3379
|
+
const ax = ma * x + mc * y + mtx, ay = mb * x + md * y + mty;
|
|
3380
|
+
const bx = ma * x1 + mc * y + mtx, by = mb * x1 + md * y + mty;
|
|
3381
|
+
const cx = ma * x1 + mc * y1 + mtx, cy = mb * x1 + md * y1 + mty;
|
|
3382
|
+
const dx = ma * x + mc * y1 + mtx, dy = mb * x + md * y1 + mty;
|
|
3383
|
+
v[i++] = ax;
|
|
3384
|
+
v[i++] = ay;
|
|
3385
|
+
v[i++] = u0;
|
|
3386
|
+
v[i++] = v0;
|
|
3387
|
+
v[i++] = opacity;
|
|
3388
|
+
v[i++] = bx;
|
|
3389
|
+
v[i++] = by;
|
|
3390
|
+
v[i++] = u1;
|
|
3391
|
+
v[i++] = v0;
|
|
3392
|
+
v[i++] = opacity;
|
|
3393
|
+
v[i++] = cx;
|
|
3394
|
+
v[i++] = cy;
|
|
3395
|
+
v[i++] = u1;
|
|
3396
|
+
v[i++] = v1;
|
|
3397
|
+
v[i++] = opacity;
|
|
3398
|
+
v[i++] = dx;
|
|
3399
|
+
v[i++] = dy;
|
|
3400
|
+
v[i++] = u0;
|
|
3401
|
+
v[i++] = v1;
|
|
3402
|
+
v[i++] = opacity;
|
|
3403
|
+
this.nQuads += 1;
|
|
3404
|
+
}
|
|
3405
|
+
/** Upload the staged geometry into the next set of buffers and bind its VAO.
|
|
3406
|
+
* Returns the index count for the caller's `drawElements`. */
|
|
3407
|
+
uploadAndBind() {
|
|
3408
|
+
const gl = this.gl;
|
|
3409
|
+
const tier = TIERS.findIndex((t) => this.nQuads <= t.quads);
|
|
3410
|
+
const set = tier < 0 ? this.nextLargeSlot() : this.nextRingSlot(tier);
|
|
3411
|
+
gl.bindVertexArray(set.vao);
|
|
3412
|
+
gl.bindBuffer(gl.ARRAY_BUFFER, set.vbo);
|
|
3413
|
+
gl.bufferSubData(gl.ARRAY_BUFFER, 0, this.verts, 0, this.nQuads * 4 * FLOATS_PER_VERTEX2);
|
|
3414
|
+
return this.nQuads * 6;
|
|
3415
|
+
}
|
|
3416
|
+
reset() {
|
|
3417
|
+
this.nQuads = 0;
|
|
3418
|
+
}
|
|
3419
|
+
dispose() {
|
|
3420
|
+
for (const set of [...this.rings.flat(), ...this.largeRing]) {
|
|
3421
|
+
if (set) this.deleteSet(set);
|
|
3422
|
+
}
|
|
3423
|
+
for (const ring of this.rings) ring.fill(void 0);
|
|
3424
|
+
this.largeRing.fill(void 0);
|
|
3425
|
+
}
|
|
3426
|
+
/** Grow the CPU arrays so one more quad fits. */
|
|
3427
|
+
reserve() {
|
|
3428
|
+
const need = (this.nQuads + 1) * 4 * FLOATS_PER_VERTEX2;
|
|
3429
|
+
if (need <= this.verts.length) return;
|
|
3430
|
+
const grown = new Float32Array(doubledTo2(this.verts.length, need));
|
|
3431
|
+
grown.set(this.verts);
|
|
3432
|
+
this.verts = grown;
|
|
3433
|
+
}
|
|
3434
|
+
nextRingSlot(tier) {
|
|
3435
|
+
const ring = this.rings[tier];
|
|
3436
|
+
const slot = this.nextInRing[tier];
|
|
3437
|
+
this.nextInRing[tier] = (slot + 1) % ring.length;
|
|
3438
|
+
const existing = ring[slot];
|
|
3439
|
+
if (existing) return existing;
|
|
3440
|
+
const set = this.createSet(TIERS[tier].quads);
|
|
3441
|
+
ring[slot] = set;
|
|
3442
|
+
return set;
|
|
3443
|
+
}
|
|
3444
|
+
nextLargeSlot() {
|
|
3445
|
+
const gl = this.gl;
|
|
3446
|
+
const slot = this.nextLarge;
|
|
3447
|
+
this.nextLarge = (slot + 1) % IMAGE_LARGE_RING_SIZE;
|
|
3448
|
+
let set = this.largeRing[slot];
|
|
3449
|
+
if (!set) {
|
|
3450
|
+
set = this.createSet(doubledTo2(TIERS[TIERS.length - 1].quads, this.nQuads));
|
|
3451
|
+
this.largeRing[slot] = set;
|
|
3452
|
+
return set;
|
|
3453
|
+
}
|
|
3454
|
+
if (this.nQuads > set.quadCapacity) {
|
|
3455
|
+
set.quadCapacity = doubledTo2(set.quadCapacity, this.nQuads);
|
|
3456
|
+
gl.bindVertexArray(set.vao);
|
|
3457
|
+
gl.bindBuffer(gl.ARRAY_BUFFER, set.vbo);
|
|
3458
|
+
gl.bufferData(
|
|
3459
|
+
gl.ARRAY_BUFFER,
|
|
3460
|
+
set.quadCapacity * 4 * FLOATS_PER_VERTEX2 * 4,
|
|
3461
|
+
gl.DYNAMIC_DRAW
|
|
3462
|
+
);
|
|
3463
|
+
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, set.ibo);
|
|
3464
|
+
gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, quadIndices(set.quadCapacity), gl.STATIC_DRAW);
|
|
3465
|
+
gl.bindVertexArray(null);
|
|
3466
|
+
}
|
|
3467
|
+
return set;
|
|
3468
|
+
}
|
|
3469
|
+
createSet(quads) {
|
|
3470
|
+
const gl = this.gl;
|
|
3471
|
+
const vao = gl.createVertexArray();
|
|
3472
|
+
const vbo = gl.createBuffer();
|
|
3473
|
+
const ibo = gl.createBuffer();
|
|
3474
|
+
if (!vao || !vbo || !ibo) throw new Error("ImageBatch: failed to create GL objects");
|
|
3475
|
+
const stride = FLOATS_PER_VERTEX2 * 4;
|
|
3476
|
+
gl.bindVertexArray(vao);
|
|
3477
|
+
gl.bindBuffer(gl.ARRAY_BUFFER, vbo);
|
|
3478
|
+
gl.bufferData(gl.ARRAY_BUFFER, quads * 4 * stride, gl.DYNAMIC_DRAW);
|
|
3479
|
+
gl.enableVertexAttribArray(this.aPos);
|
|
3480
|
+
gl.vertexAttribPointer(this.aPos, 2, gl.FLOAT, false, stride, 0);
|
|
3481
|
+
gl.enableVertexAttribArray(this.aUv);
|
|
3482
|
+
gl.vertexAttribPointer(this.aUv, 2, gl.FLOAT, false, stride, 8);
|
|
3483
|
+
gl.enableVertexAttribArray(this.aOpacity);
|
|
3484
|
+
gl.vertexAttribPointer(this.aOpacity, 1, gl.FLOAT, false, stride, 16);
|
|
3485
|
+
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, ibo);
|
|
3486
|
+
gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, quadIndices(quads), gl.STATIC_DRAW);
|
|
3487
|
+
gl.bindVertexArray(null);
|
|
3488
|
+
return { vao, vbo, ibo, quadCapacity: quads };
|
|
3489
|
+
}
|
|
3490
|
+
deleteSet(set) {
|
|
3491
|
+
const gl = this.gl;
|
|
3492
|
+
gl.deleteBuffer(set.vbo);
|
|
3493
|
+
gl.deleteBuffer(set.ibo);
|
|
3494
|
+
gl.deleteVertexArray(set.vao);
|
|
3495
|
+
}
|
|
3496
|
+
};
|
|
3497
|
+
|
|
3243
3498
|
// src/renderer/draw.ts
|
|
3244
3499
|
var FRAME_UPLOADS = /* @__PURE__ */ new WeakMap();
|
|
3245
3500
|
var FRAME_PROJ = /* @__PURE__ */ new WeakMap();
|
|
@@ -3334,13 +3589,14 @@ function dispatch(ctx, cmd) {
|
|
|
3334
3589
|
case "path":
|
|
3335
3590
|
return drawPath(ctx, cmd);
|
|
3336
3591
|
case "text":
|
|
3337
|
-
|
|
3592
|
+
flushBatches(ctx);
|
|
3338
3593
|
return drawText(ctx, cmd);
|
|
3339
3594
|
case "image":
|
|
3340
|
-
flushSolids(ctx);
|
|
3341
3595
|
return drawImage(ctx, cmd);
|
|
3596
|
+
case "sprites":
|
|
3597
|
+
return drawSprites(ctx, cmd);
|
|
3342
3598
|
case "shader":
|
|
3343
|
-
|
|
3599
|
+
flushBatches(ctx);
|
|
3344
3600
|
return drawShader(ctx, cmd);
|
|
3345
3601
|
}
|
|
3346
3602
|
}
|
|
@@ -3517,6 +3773,7 @@ function canBatchMesh(mesh) {
|
|
|
3517
3773
|
return !mesh.requiresStencil && mesh.vertices.length >> 1 <= MAX_BATCHED_MESH_VERTICES;
|
|
3518
3774
|
}
|
|
3519
3775
|
function stageSolid(ctx, vertices) {
|
|
3776
|
+
flushImages(ctx);
|
|
3520
3777
|
if (ctx.solidState !== void 0 && !stagedStateIsLive(ctx, ctx.solidState)) flushSolids(ctx);
|
|
3521
3778
|
if (ctx.solidBatch.wouldOverflow(vertices)) flushSolids(ctx);
|
|
3522
3779
|
if (ctx.solidState === void 0) {
|
|
@@ -3560,7 +3817,7 @@ function tryStageSolid(ctx, mesh, paint) {
|
|
|
3560
3817
|
pushMesh(ctx, mesh, paint);
|
|
3561
3818
|
return true;
|
|
3562
3819
|
}
|
|
3563
|
-
|
|
3820
|
+
flushBatches(ctx);
|
|
3564
3821
|
return false;
|
|
3565
3822
|
}
|
|
3566
3823
|
function flushSolids(ctx) {
|
|
@@ -3581,6 +3838,56 @@ function flushSolids(ctx) {
|
|
|
3581
3838
|
batch.reset();
|
|
3582
3839
|
ctx.solidState = void 0;
|
|
3583
3840
|
}
|
|
3841
|
+
function stagedImageStateIsLive(ctx, staged, image, sampling) {
|
|
3842
|
+
if (staged.image !== image) return false;
|
|
3843
|
+
if (staged.sampling !== sampling) return false;
|
|
3844
|
+
if (staged.clipDepth !== ctx.clipDepth) return false;
|
|
3845
|
+
const colorMatrix = ctx.state.colorMatrix;
|
|
3846
|
+
return staged.colorMatrix === colorMatrix || sameValues(staged.colorMatrix, colorMatrix);
|
|
3847
|
+
}
|
|
3848
|
+
function stageImage(ctx, image, sampling) {
|
|
3849
|
+
flushSolids(ctx);
|
|
3850
|
+
if (ctx.imageState !== void 0 && !stagedImageStateIsLive(ctx, ctx.imageState, image, sampling)) {
|
|
3851
|
+
flushImages(ctx);
|
|
3852
|
+
}
|
|
3853
|
+
if (ctx.imageBatch.wouldOverflow()) flushImages(ctx);
|
|
3854
|
+
if (ctx.imageState === void 0) {
|
|
3855
|
+
ctx.imageState = {
|
|
3856
|
+
image,
|
|
3857
|
+
sampling,
|
|
3858
|
+
colorMatrix: ctx.state.colorMatrix,
|
|
3859
|
+
clipDepth: ctx.clipDepth
|
|
3860
|
+
};
|
|
3861
|
+
}
|
|
3862
|
+
}
|
|
3863
|
+
function flushImages(ctx) {
|
|
3864
|
+
const batch = ctx.imageBatch;
|
|
3865
|
+
const staged = ctx.imageState;
|
|
3866
|
+
if (batch.length === 0 || staged === void 0) return;
|
|
3867
|
+
const gl = ctx.gl;
|
|
3868
|
+
const prog = ctx.imageFillVOpacity;
|
|
3869
|
+
gl.useProgram(prog.handle);
|
|
3870
|
+
const indexCount = batch.uploadAndBind();
|
|
3871
|
+
setProjAndModel(ctx, prog, BATCH_MODEL);
|
|
3872
|
+
setAlphaUniform(ctx, prog, 1);
|
|
3873
|
+
setColorMatrixUniforms(ctx, prog, staged.colorMatrix);
|
|
3874
|
+
ctx.imageCache.bind(staged.image, 0);
|
|
3875
|
+
gl.texParameteri(
|
|
3876
|
+
gl.TEXTURE_2D,
|
|
3877
|
+
gl.TEXTURE_MAG_FILTER,
|
|
3878
|
+
staged.sampling === "nearest" ? gl.NEAREST : gl.LINEAR
|
|
3879
|
+
);
|
|
3880
|
+
gl.uniform1i(prog.uniform("u_sampler"), 0);
|
|
3881
|
+
applyClipTest(ctx, staged.clipDepth);
|
|
3882
|
+
gl.drawElements(gl.TRIANGLES, indexCount, gl.UNSIGNED_INT, 0);
|
|
3883
|
+
gl.bindVertexArray(null);
|
|
3884
|
+
batch.reset();
|
|
3885
|
+
ctx.imageState = void 0;
|
|
3886
|
+
}
|
|
3887
|
+
function flushBatches(ctx) {
|
|
3888
|
+
flushSolids(ctx);
|
|
3889
|
+
flushImages(ctx);
|
|
3890
|
+
}
|
|
3584
3891
|
function expandAnchorColors(perAnchor, handle) {
|
|
3585
3892
|
const aA = handle.anchorA;
|
|
3586
3893
|
const aB = handle.anchorB;
|
|
@@ -3784,7 +4091,7 @@ function rasterizePathToStencil(ctx, path) {
|
|
|
3784
4091
|
gl.bindVertexArray(null);
|
|
3785
4092
|
}
|
|
3786
4093
|
function pushClip(ctx, path, newDepth) {
|
|
3787
|
-
|
|
4094
|
+
flushBatches(ctx);
|
|
3788
4095
|
const gl = ctx.gl;
|
|
3789
4096
|
const ancestors = ancestorMask(newDepth - 1);
|
|
3790
4097
|
const newBit = 1 << newDepth;
|
|
@@ -3799,7 +4106,7 @@ function pushClip(ctx, path, newDepth) {
|
|
|
3799
4106
|
gl.stencilMask(255);
|
|
3800
4107
|
}
|
|
3801
4108
|
function popClip(ctx, path, oldDepth) {
|
|
3802
|
-
|
|
4109
|
+
flushBatches(ctx);
|
|
3803
4110
|
const gl = ctx.gl;
|
|
3804
4111
|
gl.enable(gl.STENCIL_TEST);
|
|
3805
4112
|
const oldBit = 1 << oldDepth + 1;
|
|
@@ -3846,7 +4153,7 @@ function drawPathStroke(ctx, rawCmd) {
|
|
|
3846
4153
|
const stroke = cmd.stroke;
|
|
3847
4154
|
const align = stroke.align ?? "center";
|
|
3848
4155
|
if (cmd.path.kind === "polygon" && align !== "center") {
|
|
3849
|
-
|
|
4156
|
+
flushBatches(ctx);
|
|
3850
4157
|
drawPathStrokeStenciled(ctx, cmd, align);
|
|
3851
4158
|
return;
|
|
3852
4159
|
}
|
|
@@ -4194,45 +4501,6 @@ function drawTextGroup(ctx, group, prog, dx, dy) {
|
|
|
4194
4501
|
gl.drawElements(gl.TRIANGLES, group.quads.length * 6, gl.UNSIGNED_INT, 0);
|
|
4195
4502
|
gl.bindVertexArray(null);
|
|
4196
4503
|
}
|
|
4197
|
-
var IMAGE_QUAD_RING_SIZE = 64;
|
|
4198
|
-
var IMAGE_QUAD_RINGS = /* @__PURE__ */ new WeakMap();
|
|
4199
|
-
var IMAGE_QUAD_INDICES = new Uint32Array([0, 1, 2, 1, 3, 2]);
|
|
4200
|
-
var IMAGE_QUAD_STRIDE = 16;
|
|
4201
|
-
function imageQuadRing(gl, prog) {
|
|
4202
|
-
const existing = IMAGE_QUAD_RINGS.get(prog);
|
|
4203
|
-
if (existing) return existing;
|
|
4204
|
-
const aPosLoc = prog.attribute("a_position");
|
|
4205
|
-
const aUvLoc = prog.attribute("a_uv");
|
|
4206
|
-
const ibo = gl.createBuffer();
|
|
4207
|
-
if (!ibo) throw new Error("drawImage: createBuffer (IBO) returned null");
|
|
4208
|
-
const vaos = [];
|
|
4209
|
-
const vbos = [];
|
|
4210
|
-
for (let slot = 0; slot < IMAGE_QUAD_RING_SIZE; slot++) {
|
|
4211
|
-
const vao = gl.createVertexArray();
|
|
4212
|
-
const vbo = gl.createBuffer();
|
|
4213
|
-
if (!vao) throw new Error("drawImage: createVertexArray returned null");
|
|
4214
|
-
if (!vbo) throw new Error("drawImage: createBuffer returned null");
|
|
4215
|
-
gl.bindVertexArray(vao);
|
|
4216
|
-
gl.bindBuffer(gl.ARRAY_BUFFER, vbo);
|
|
4217
|
-
gl.bufferData(gl.ARRAY_BUFFER, 4 * IMAGE_QUAD_STRIDE, gl.DYNAMIC_DRAW);
|
|
4218
|
-
if (aPosLoc !== void 0) {
|
|
4219
|
-
gl.enableVertexAttribArray(aPosLoc);
|
|
4220
|
-
gl.vertexAttribPointer(aPosLoc, 2, gl.FLOAT, false, IMAGE_QUAD_STRIDE, 0);
|
|
4221
|
-
}
|
|
4222
|
-
if (aUvLoc !== void 0) {
|
|
4223
|
-
gl.enableVertexAttribArray(aUvLoc);
|
|
4224
|
-
gl.vertexAttribPointer(aUvLoc, 2, gl.FLOAT, false, IMAGE_QUAD_STRIDE, 8);
|
|
4225
|
-
}
|
|
4226
|
-
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, ibo);
|
|
4227
|
-
if (slot === 0) gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, IMAGE_QUAD_INDICES, gl.STATIC_DRAW);
|
|
4228
|
-
gl.bindVertexArray(null);
|
|
4229
|
-
vaos.push(vao);
|
|
4230
|
-
vbos.push(vbo);
|
|
4231
|
-
}
|
|
4232
|
-
const ring = { vaos, vbos, ibo, next: 0 };
|
|
4233
|
-
IMAGE_QUAD_RINGS.set(prog, ring);
|
|
4234
|
-
return ring;
|
|
4235
|
-
}
|
|
4236
4504
|
var TEXT_QUAD_RING_SIZE = 64;
|
|
4237
4505
|
var TEXT_QUAD_RINGS = /* @__PURE__ */ new WeakMap();
|
|
4238
4506
|
function grownTo(need) {
|
|
@@ -4310,22 +4578,9 @@ function disposeTextQuads(gl, prog) {
|
|
|
4310
4578
|
gl.deleteBuffer(ring.ibo);
|
|
4311
4579
|
TEXT_QUAD_RINGS.delete(prog);
|
|
4312
4580
|
}
|
|
4313
|
-
function disposeImageQuads(gl, prog) {
|
|
4314
|
-
const ring = IMAGE_QUAD_RINGS.get(prog);
|
|
4315
|
-
if (!ring) return;
|
|
4316
|
-
for (const vao of ring.vaos) gl.deleteVertexArray(vao);
|
|
4317
|
-
for (const vbo of ring.vbos) gl.deleteBuffer(vbo);
|
|
4318
|
-
gl.deleteBuffer(ring.ibo);
|
|
4319
|
-
IMAGE_QUAD_RINGS.delete(prog);
|
|
4320
|
-
}
|
|
4321
|
-
var IMAGE_QUAD_VERTICES = new Float32Array(16);
|
|
4322
4581
|
function drawImage(ctx, cmd) {
|
|
4323
4582
|
ctx.imageCache.upload(cmd.image, cmd.image);
|
|
4324
|
-
|
|
4325
|
-
const prog = ctx.imageFill;
|
|
4326
|
-
gl.useProgram(prog.handle);
|
|
4327
|
-
const x0 = cmd.x, y0 = cmd.y;
|
|
4328
|
-
const x1 = cmd.x + cmd.w, y1 = cmd.y + cmd.h;
|
|
4583
|
+
stageImage(ctx, cmd.image, cmd.sampling ?? "linear");
|
|
4329
4584
|
const src = cmd.source;
|
|
4330
4585
|
let u0 = 0, v0 = 0, u1 = 1, v1 = 1;
|
|
4331
4586
|
if (src) {
|
|
@@ -4345,43 +4600,50 @@ function drawImage(ctx, cmd) {
|
|
|
4345
4600
|
v0 = v1;
|
|
4346
4601
|
v1 = t;
|
|
4347
4602
|
}
|
|
4348
|
-
|
|
4349
|
-
|
|
4350
|
-
|
|
4351
|
-
|
|
4352
|
-
|
|
4353
|
-
|
|
4354
|
-
|
|
4355
|
-
|
|
4356
|
-
|
|
4357
|
-
|
|
4358
|
-
|
|
4359
|
-
v[10] = u0;
|
|
4360
|
-
v[11] = v1;
|
|
4361
|
-
v[12] = x1;
|
|
4362
|
-
v[13] = y1;
|
|
4363
|
-
v[14] = u1;
|
|
4364
|
-
v[15] = v1;
|
|
4365
|
-
const ring = imageQuadRing(gl, prog);
|
|
4366
|
-
const slot = ring.next;
|
|
4367
|
-
ring.next = (slot + 1) % IMAGE_QUAD_RING_SIZE;
|
|
4368
|
-
gl.bindVertexArray(ring.vaos[slot]);
|
|
4369
|
-
gl.bindBuffer(gl.ARRAY_BUFFER, ring.vbos[slot]);
|
|
4370
|
-
gl.bufferSubData(gl.ARRAY_BUFFER, 0, v);
|
|
4371
|
-
setProjAndModel(ctx, prog);
|
|
4372
|
-
setColorMatrixUniforms(ctx, prog);
|
|
4373
|
-
ctx.imageCache.bind(cmd.image, 0);
|
|
4374
|
-
gl.texParameteri(
|
|
4375
|
-
gl.TEXTURE_2D,
|
|
4376
|
-
gl.TEXTURE_MAG_FILTER,
|
|
4377
|
-
cmd.sampling === "nearest" ? gl.NEAREST : gl.LINEAR
|
|
4603
|
+
ctx.imageBatch.pushQuad(
|
|
4604
|
+
cmd.x,
|
|
4605
|
+
cmd.y,
|
|
4606
|
+
cmd.w,
|
|
4607
|
+
cmd.h,
|
|
4608
|
+
ctx.state.transform,
|
|
4609
|
+
u0,
|
|
4610
|
+
v0,
|
|
4611
|
+
u1,
|
|
4612
|
+
v1,
|
|
4613
|
+
(cmd.opacity ?? 1) * ctx.state.alpha
|
|
4378
4614
|
);
|
|
4379
|
-
|
|
4380
|
-
|
|
4381
|
-
|
|
4382
|
-
|
|
4383
|
-
|
|
4384
|
-
|
|
4615
|
+
}
|
|
4616
|
+
function drawSprites(ctx, cmd) {
|
|
4617
|
+
const data = cmd.sprites;
|
|
4618
|
+
const count = Math.floor(data.length / SPRITE_STRIDE);
|
|
4619
|
+
if (count === 0) return;
|
|
4620
|
+
ctx.imageCache.upload(cmd.image, cmd.image);
|
|
4621
|
+
const sampling = cmd.sampling ?? "linear";
|
|
4622
|
+
stageImage(ctx, cmd.image, sampling);
|
|
4623
|
+
const batch = ctx.imageBatch;
|
|
4624
|
+
const m = ctx.state.transform;
|
|
4625
|
+
const groupAlpha = ctx.state.alpha;
|
|
4626
|
+
const tw = cmd.image.width;
|
|
4627
|
+
const th = cmd.image.height;
|
|
4628
|
+
for (let s = 0, i = 0; s < count; s++, i += SPRITE_STRIDE) {
|
|
4629
|
+
if (batch.wouldOverflow()) {
|
|
4630
|
+
flushImages(ctx);
|
|
4631
|
+
stageImage(ctx, cmd.image, sampling);
|
|
4632
|
+
}
|
|
4633
|
+
const sx = data[i + 4], sy = data[i + 5], sw = data[i + 6], sh = data[i + 7];
|
|
4634
|
+
batch.pushQuad(
|
|
4635
|
+
data[i],
|
|
4636
|
+
data[i + 1],
|
|
4637
|
+
data[i + 2],
|
|
4638
|
+
data[i + 3],
|
|
4639
|
+
m,
|
|
4640
|
+
sx / tw,
|
|
4641
|
+
sy / th,
|
|
4642
|
+
(sx + sw) / tw,
|
|
4643
|
+
(sy + sh) / th,
|
|
4644
|
+
data[i + 8] * groupAlpha
|
|
4645
|
+
);
|
|
4646
|
+
}
|
|
4385
4647
|
}
|
|
4386
4648
|
|
|
4387
4649
|
// src/renderer/shaders/customPrelude.ts
|
|
@@ -4484,6 +4746,7 @@ var WeaselRenderer = class {
|
|
|
4484
4746
|
textSdf;
|
|
4485
4747
|
textSdfR8;
|
|
4486
4748
|
imageFill;
|
|
4749
|
+
imageFillVOpacity;
|
|
4487
4750
|
gradFill;
|
|
4488
4751
|
patternFill;
|
|
4489
4752
|
meshCache;
|
|
@@ -4494,6 +4757,7 @@ var WeaselRenderer = class {
|
|
|
4494
4757
|
quadVbo = null;
|
|
4495
4758
|
quadIbo = null;
|
|
4496
4759
|
solidBatch;
|
|
4760
|
+
imageBatch;
|
|
4497
4761
|
groupState = new GroupState();
|
|
4498
4762
|
widthCss;
|
|
4499
4763
|
heightCss;
|
|
@@ -4558,6 +4822,13 @@ var WeaselRenderer = class {
|
|
|
4558
4822
|
this.imageFill = new ShaderProgram(this.gl, IMAGE_VERT_SRC, IMAGE_FRAG_SRC);
|
|
4559
4823
|
this.imageFill.lookupUniforms(IMAGE_FILL_UNIFORMS);
|
|
4560
4824
|
this.imageFill.lookupAttributes(IMAGE_FILL_ATTRIBUTES);
|
|
4825
|
+
this.imageFillVOpacity = new ShaderProgram(
|
|
4826
|
+
this.gl,
|
|
4827
|
+
IMAGE_VOPACITY_VERT_SRC,
|
|
4828
|
+
IMAGE_VOPACITY_FRAG_SRC
|
|
4829
|
+
);
|
|
4830
|
+
this.imageFillVOpacity.lookupUniforms(IMAGE_VOPACITY_UNIFORMS);
|
|
4831
|
+
this.imageFillVOpacity.lookupAttributes(IMAGE_VOPACITY_ATTRIBUTES);
|
|
4561
4832
|
this.gradFill = new ShaderProgram(this.gl, GRAD_VERT_SRC, GRAD_FRAG_SRC);
|
|
4562
4833
|
this.gradFill.lookupUniforms(GRAD_FILL_UNIFORMS);
|
|
4563
4834
|
this.gradFill.lookupAttributes(GRAD_FILL_ATTRIBUTES);
|
|
@@ -4572,6 +4843,7 @@ var WeaselRenderer = class {
|
|
|
4572
4843
|
this.gradRampCache = new GradientRampCache(this.gl);
|
|
4573
4844
|
this.uploadQuadGeometry();
|
|
4574
4845
|
this.solidBatch = new SolidBatch(this.gl, this.pathFillVColor);
|
|
4846
|
+
this.imageBatch = new ImageBatch(this.gl, this.imageFillVOpacity);
|
|
4575
4847
|
}
|
|
4576
4848
|
uploadQuadGeometry() {
|
|
4577
4849
|
const gl = this.gl;
|
|
@@ -4695,6 +4967,13 @@ var WeaselRenderer = class {
|
|
|
4695
4967
|
this.imageFill = new ShaderProgram(this.gl, IMAGE_VERT_SRC, IMAGE_FRAG_SRC);
|
|
4696
4968
|
this.imageFill.lookupUniforms(IMAGE_FILL_UNIFORMS);
|
|
4697
4969
|
this.imageFill.lookupAttributes(IMAGE_FILL_ATTRIBUTES);
|
|
4970
|
+
this.imageFillVOpacity = new ShaderProgram(
|
|
4971
|
+
this.gl,
|
|
4972
|
+
IMAGE_VOPACITY_VERT_SRC,
|
|
4973
|
+
IMAGE_VOPACITY_FRAG_SRC
|
|
4974
|
+
);
|
|
4975
|
+
this.imageFillVOpacity.lookupUniforms(IMAGE_VOPACITY_UNIFORMS);
|
|
4976
|
+
this.imageFillVOpacity.lookupAttributes(IMAGE_VOPACITY_ATTRIBUTES);
|
|
4698
4977
|
this.gradFill = new ShaderProgram(this.gl, GRAD_VERT_SRC, GRAD_FRAG_SRC);
|
|
4699
4978
|
this.gradFill.lookupUniforms(GRAD_FILL_UNIFORMS);
|
|
4700
4979
|
this.gradFill.lookupAttributes(GRAD_FILL_ATTRIBUTES);
|
|
@@ -4710,6 +4989,7 @@ var WeaselRenderer = class {
|
|
|
4710
4989
|
markAllFontsNotUploaded();
|
|
4711
4990
|
this.uploadQuadGeometry();
|
|
4712
4991
|
this.solidBatch = new SolidBatch(this.gl, this.pathFillVColor);
|
|
4992
|
+
this.imageBatch = new ImageBatch(this.gl, this.imageFillVOpacity);
|
|
4713
4993
|
for (const id of this.programRegistry.keys()) {
|
|
4714
4994
|
const src = getProgramSource(id);
|
|
4715
4995
|
if (!src) continue;
|
|
@@ -4758,7 +5038,7 @@ var WeaselRenderer = class {
|
|
|
4758
5038
|
}
|
|
4759
5039
|
this.meshCache.freeTransient();
|
|
4760
5040
|
this.meshCache.drainPendingDeletes();
|
|
4761
|
-
for (const prog of [this.pathFill, this.pathFillVColor, this.textSdf, this.textSdfR8, this.imageFill, this.gradFill, this.patternFill]) {
|
|
5041
|
+
for (const prog of [this.pathFill, this.pathFillVColor, this.textSdf, this.textSdfR8, this.imageFill, this.imageFillVOpacity, this.gradFill, this.patternFill]) {
|
|
4762
5042
|
gl.deleteProgram(prog.handle);
|
|
4763
5043
|
}
|
|
4764
5044
|
for (const prog of this.programRegistry.values()) {
|
|
@@ -4769,9 +5049,9 @@ var WeaselRenderer = class {
|
|
|
4769
5049
|
this.gradRampCache.free();
|
|
4770
5050
|
if (this.quadVbo) gl.deleteBuffer(this.quadVbo);
|
|
4771
5051
|
if (this.quadIbo) gl.deleteBuffer(this.quadIbo);
|
|
4772
|
-
disposeImageQuads(gl, this.imageFill);
|
|
4773
5052
|
for (const prog of [this.textSdf, this.textSdfR8, this.pathFill]) disposeTextQuads(gl, prog);
|
|
4774
5053
|
this.solidBatch.dispose();
|
|
5054
|
+
this.imageBatch.dispose();
|
|
4775
5055
|
}
|
|
4776
5056
|
/**
|
|
4777
5057
|
* Draw one frame.
|
|
@@ -4800,6 +5080,7 @@ var WeaselRenderer = class {
|
|
|
4800
5080
|
textSdf: this.textSdf,
|
|
4801
5081
|
textSdfR8: this.textSdfR8,
|
|
4802
5082
|
imageFill: this.imageFill,
|
|
5083
|
+
imageFillVOpacity: this.imageFillVOpacity,
|
|
4803
5084
|
gradFill: this.gradFill,
|
|
4804
5085
|
patternFill: this.patternFill,
|
|
4805
5086
|
meshCache: this.meshCache,
|
|
@@ -4811,6 +5092,7 @@ var WeaselRenderer = class {
|
|
|
4811
5092
|
quadVbo: this.quadVbo,
|
|
4812
5093
|
quadIbo: this.quadIbo,
|
|
4813
5094
|
solidBatch: this.solidBatch,
|
|
5095
|
+
imageBatch: this.imageBatch,
|
|
4814
5096
|
state: this.groupState,
|
|
4815
5097
|
widthCss: this.widthCss,
|
|
4816
5098
|
heightCss: this.heightCss,
|
|
@@ -4820,7 +5102,7 @@ var WeaselRenderer = class {
|
|
|
4820
5102
|
viewMatrix: viewMatrix2
|
|
4821
5103
|
};
|
|
4822
5104
|
for (const cmd of commands) dispatch(ctx, cmd);
|
|
4823
|
-
|
|
5105
|
+
flushBatches(ctx);
|
|
4824
5106
|
this.meshCache.freeTransient();
|
|
4825
5107
|
}
|
|
4826
5108
|
resize(dims) {
|
|
@@ -4854,6 +5136,10 @@ var WeaselRenderer = class {
|
|
|
4854
5136
|
return this.solidBatch;
|
|
4855
5137
|
}
|
|
4856
5138
|
/** @internal */
|
|
5139
|
+
_imageBatch() {
|
|
5140
|
+
return this.imageBatch;
|
|
5141
|
+
}
|
|
5142
|
+
/** @internal */
|
|
4857
5143
|
_textSdf() {
|
|
4858
5144
|
return this.textSdf;
|
|
4859
5145
|
}
|
|
@@ -4866,6 +5152,10 @@ var WeaselRenderer = class {
|
|
|
4866
5152
|
return this.imageFill;
|
|
4867
5153
|
}
|
|
4868
5154
|
/** @internal */
|
|
5155
|
+
_imageFillVOpacity() {
|
|
5156
|
+
return this.imageFillVOpacity;
|
|
5157
|
+
}
|
|
5158
|
+
/** @internal */
|
|
4869
5159
|
_gradFill() {
|
|
4870
5160
|
return this.gradFill;
|
|
4871
5161
|
}
|
|
@@ -5914,6 +6204,86 @@ function clientToCanvasRect(rect, clientX, clientY) {
|
|
|
5914
6204
|
return [clientX - rect.left, clientY - rect.top];
|
|
5915
6205
|
}
|
|
5916
6206
|
|
|
6207
|
+
// src/interactions/gestures/pointerSession/recovery.ts
|
|
6208
|
+
var LOST_CAPTURE_EVENT = "lostpointercapture";
|
|
6209
|
+
function reportsButtons(down) {
|
|
6210
|
+
return !!down.buttons;
|
|
6211
|
+
}
|
|
6212
|
+
function isMissedRelease(move) {
|
|
6213
|
+
return move.buttons === 0;
|
|
6214
|
+
}
|
|
6215
|
+
|
|
6216
|
+
// src/interactions/gestures/pointerSession/pointerSession.ts
|
|
6217
|
+
function openPointerSession(origin, down, cb, opts = {}) {
|
|
6218
|
+
const pointerId = down.pointerId;
|
|
6219
|
+
const doc = origin.ownerDocument ?? document;
|
|
6220
|
+
const buttonsReported = reportsButtons(down);
|
|
6221
|
+
let active = true;
|
|
6222
|
+
const teardown = () => {
|
|
6223
|
+
active = false;
|
|
6224
|
+
doc.removeEventListener("pointermove", onMove, true);
|
|
6225
|
+
doc.removeEventListener("pointerup", onUp, true);
|
|
6226
|
+
doc.removeEventListener("pointercancel", onPointerCancel, true);
|
|
6227
|
+
doc.removeEventListener("pointerdown", onRepress, true);
|
|
6228
|
+
origin.removeEventListener(LOST_CAPTURE_EVENT, onLostCapture);
|
|
6229
|
+
if (opts.capture !== false) {
|
|
6230
|
+
try {
|
|
6231
|
+
origin.releasePointerCapture?.(pointerId);
|
|
6232
|
+
} catch {
|
|
6233
|
+
}
|
|
6234
|
+
}
|
|
6235
|
+
};
|
|
6236
|
+
const mine = (e) => e.pointerId === pointerId;
|
|
6237
|
+
const end = (e) => {
|
|
6238
|
+
if (!active) return;
|
|
6239
|
+
teardown();
|
|
6240
|
+
cb.onEnd?.(e);
|
|
6241
|
+
};
|
|
6242
|
+
const abort = (reason) => {
|
|
6243
|
+
if (!active) return;
|
|
6244
|
+
teardown();
|
|
6245
|
+
cb.onCancel?.(reason);
|
|
6246
|
+
};
|
|
6247
|
+
function onMove(e) {
|
|
6248
|
+
if (!active || !mine(e)) return;
|
|
6249
|
+
if (buttonsReported && isMissedRelease(e)) {
|
|
6250
|
+
end(e);
|
|
6251
|
+
return;
|
|
6252
|
+
}
|
|
6253
|
+
cb.onMove?.(e);
|
|
6254
|
+
}
|
|
6255
|
+
function onUp(e) {
|
|
6256
|
+
if (mine(e)) end(e);
|
|
6257
|
+
}
|
|
6258
|
+
function onPointerCancel(e) {
|
|
6259
|
+
if (mine(e)) abort("pointercancel");
|
|
6260
|
+
}
|
|
6261
|
+
function onRepress(e) {
|
|
6262
|
+
if (mine(e)) abort("superseded");
|
|
6263
|
+
}
|
|
6264
|
+
function onLostCapture(e) {
|
|
6265
|
+
if (e.pointerId === pointerId) abort("lostcapture");
|
|
6266
|
+
}
|
|
6267
|
+
if (opts.capture !== false) {
|
|
6268
|
+
try {
|
|
6269
|
+
origin.setPointerCapture?.(pointerId);
|
|
6270
|
+
} catch {
|
|
6271
|
+
}
|
|
6272
|
+
}
|
|
6273
|
+
doc.addEventListener("pointermove", onMove, true);
|
|
6274
|
+
doc.addEventListener("pointerup", onUp, true);
|
|
6275
|
+
doc.addEventListener("pointercancel", onPointerCancel, true);
|
|
6276
|
+
doc.addEventListener("pointerdown", onRepress, true);
|
|
6277
|
+
origin.addEventListener(LOST_CAPTURE_EVENT, onLostCapture);
|
|
6278
|
+
return {
|
|
6279
|
+
pointerId,
|
|
6280
|
+
get active() {
|
|
6281
|
+
return active;
|
|
6282
|
+
},
|
|
6283
|
+
cancel: () => abort("aborted")
|
|
6284
|
+
};
|
|
6285
|
+
}
|
|
6286
|
+
|
|
5917
6287
|
// src/interactions/gestures/handleDrag/handleDrag.ts
|
|
5918
6288
|
function defaultRectEl(target) {
|
|
5919
6289
|
if (target instanceof SVGElement && target.ownerSVGElement) {
|
|
@@ -5922,10 +6292,15 @@ function defaultRectEl(target) {
|
|
|
5922
6292
|
return target;
|
|
5923
6293
|
}
|
|
5924
6294
|
function useHandleDrag(opts) {
|
|
5925
|
-
const { onMove, onStart, onEnd, getRect } = opts;
|
|
6295
|
+
const { onMove, onStart, onEnd, onCancel, getRect } = opts;
|
|
6296
|
+
const live = useRef(null);
|
|
6297
|
+
useEffect(() => () => {
|
|
6298
|
+
live.current?.cancel();
|
|
6299
|
+
}, []);
|
|
5926
6300
|
const onPointerDown = useCallback(
|
|
5927
6301
|
(e) => {
|
|
5928
6302
|
e.preventDefault();
|
|
6303
|
+
live.current?.cancel();
|
|
5929
6304
|
const target = e.currentTarget;
|
|
5930
6305
|
const rectEl = getRect ? getRect(target) : defaultRectEl(target);
|
|
5931
6306
|
const rect = rectEl.getBoundingClientRect();
|
|
@@ -5933,26 +6308,24 @@ function useHandleDrag(opts) {
|
|
|
5933
6308
|
const [x, y] = clientToCanvasRect(rect, clientX, clientY);
|
|
5934
6309
|
return { x, y };
|
|
5935
6310
|
};
|
|
5936
|
-
|
|
5937
|
-
|
|
5938
|
-
|
|
5939
|
-
|
|
5940
|
-
|
|
5941
|
-
|
|
5942
|
-
|
|
5943
|
-
|
|
5944
|
-
|
|
5945
|
-
|
|
5946
|
-
|
|
5947
|
-
|
|
6311
|
+
let moved = false;
|
|
6312
|
+
live.current = openPointerSession(target, e, {
|
|
6313
|
+
onMove: (ev) => {
|
|
6314
|
+
moved = true;
|
|
6315
|
+
onMove(localOf(ev.clientX, ev.clientY), ev);
|
|
6316
|
+
},
|
|
6317
|
+
onEnd: (ev) => {
|
|
6318
|
+
live.current = null;
|
|
6319
|
+
onEnd?.({ point: localOf(ev.clientX, ev.clientY), moved, event: ev });
|
|
6320
|
+
},
|
|
6321
|
+
onCancel: (reason) => {
|
|
6322
|
+
live.current = null;
|
|
6323
|
+
onCancel?.(reason);
|
|
5948
6324
|
}
|
|
5949
|
-
|
|
5950
|
-
|
|
5951
|
-
target.addEventListener("pointermove", move);
|
|
5952
|
-
target.addEventListener("pointerup", end);
|
|
5953
|
-
target.addEventListener("pointercancel", end);
|
|
6325
|
+
});
|
|
6326
|
+
onStart?.(localOf(e.clientX, e.clientY), e);
|
|
5954
6327
|
},
|
|
5955
|
-
[onMove, onStart, onEnd, getRect]
|
|
6328
|
+
[onMove, onStart, onEnd, onCancel, getRect]
|
|
5956
6329
|
);
|
|
5957
6330
|
return { onPointerDown };
|
|
5958
6331
|
}
|
|
@@ -6008,57 +6381,53 @@ function positionGhost(el, x, y) {
|
|
|
6008
6381
|
el.style.transform = `translate(${x - el.offsetWidth / 2}px, ${y - el.offsetHeight / 2}px) scale(0.92)`;
|
|
6009
6382
|
}
|
|
6010
6383
|
function beginPointerDrag(payload, source, startX, startY, ghostFn) {
|
|
6011
|
-
if (activeDrag) return;
|
|
6384
|
+
if (activeDrag) return null;
|
|
6012
6385
|
const ghost = ghostFn(source, payload);
|
|
6013
6386
|
document.body.appendChild(ghost);
|
|
6014
6387
|
positionGhost(ghost, startX, startY);
|
|
6015
6388
|
activeDrag = { payload, ghost, lastZone: null };
|
|
6016
|
-
|
|
6017
|
-
if (!activeDrag) return;
|
|
6018
|
-
positionGhost(activeDrag.ghost, e.clientX, e.clientY);
|
|
6019
|
-
const zone = findZone(e.clientX, e.clientY, payload.kind);
|
|
6020
|
-
if (zone !== activeDrag.lastZone) {
|
|
6021
|
-
activeDrag.lastZone?.onOver?.(false);
|
|
6022
|
-
zone?.onOver?.(true);
|
|
6023
|
-
activeDrag.lastZone = zone;
|
|
6024
|
-
}
|
|
6025
|
-
zone?.onMove?.(payload, e.clientX, e.clientY);
|
|
6026
|
-
}
|
|
6027
|
-
function onUp(e) {
|
|
6028
|
-
if (!activeDrag) return;
|
|
6029
|
-
const zone = findZone(e.clientX, e.clientY, payload.kind);
|
|
6030
|
-
const dropped = activeDrag.payload;
|
|
6031
|
-
activeDrag.lastZone?.onOver?.(false);
|
|
6032
|
-
try {
|
|
6033
|
-
if (zone) zone.onDrop(dropped, e.clientX, e.clientY);
|
|
6034
|
-
} catch (err) {
|
|
6035
|
-
console.error("weasel pointerDrag: drop zone onDrop threw", err);
|
|
6036
|
-
} finally {
|
|
6037
|
-
cleanup();
|
|
6038
|
-
}
|
|
6039
|
-
}
|
|
6040
|
-
function onCancel() {
|
|
6041
|
-
activeDrag?.lastZone?.onOver?.(false);
|
|
6042
|
-
cleanup();
|
|
6043
|
-
}
|
|
6044
|
-
function cleanup() {
|
|
6389
|
+
const teardown = () => {
|
|
6045
6390
|
activeDrag?.ghost.remove();
|
|
6046
6391
|
activeDrag = null;
|
|
6047
|
-
|
|
6048
|
-
|
|
6049
|
-
|
|
6050
|
-
|
|
6051
|
-
|
|
6052
|
-
|
|
6053
|
-
|
|
6392
|
+
};
|
|
6393
|
+
return {
|
|
6394
|
+
move(e) {
|
|
6395
|
+
if (!activeDrag) return;
|
|
6396
|
+
positionGhost(activeDrag.ghost, e.clientX, e.clientY);
|
|
6397
|
+
const zone = findZone(e.clientX, e.clientY, payload.kind);
|
|
6398
|
+
if (zone !== activeDrag.lastZone) {
|
|
6399
|
+
activeDrag.lastZone?.onOver?.(false);
|
|
6400
|
+
zone?.onOver?.(true);
|
|
6401
|
+
activeDrag.lastZone = zone;
|
|
6402
|
+
}
|
|
6403
|
+
zone?.onMove?.(payload, e.clientX, e.clientY);
|
|
6404
|
+
},
|
|
6405
|
+
drop(e) {
|
|
6406
|
+
if (!activeDrag) return;
|
|
6407
|
+
const zone = findZone(e.clientX, e.clientY, payload.kind);
|
|
6408
|
+
const dropped = activeDrag.payload;
|
|
6409
|
+
activeDrag.lastZone?.onOver?.(false);
|
|
6410
|
+
try {
|
|
6411
|
+
if (zone) zone.onDrop(dropped, e.clientX, e.clientY);
|
|
6412
|
+
} catch (err) {
|
|
6413
|
+
console.error("weasel pointerDrag: drop zone onDrop threw", err);
|
|
6414
|
+
} finally {
|
|
6415
|
+
teardown();
|
|
6416
|
+
}
|
|
6417
|
+
},
|
|
6418
|
+
cancel() {
|
|
6419
|
+
activeDrag?.lastZone?.onOver?.(false);
|
|
6420
|
+
teardown();
|
|
6421
|
+
}
|
|
6422
|
+
};
|
|
6054
6423
|
}
|
|
6055
6424
|
var DRAG_THRESHOLD_PX_SQ = 25;
|
|
6056
6425
|
function useDragHandle(getPayload, options) {
|
|
6057
6426
|
const optsRef = useRef(options);
|
|
6058
6427
|
optsRef.current = options;
|
|
6059
|
-
const
|
|
6428
|
+
const live = useRef(null);
|
|
6060
6429
|
useEffect(() => () => {
|
|
6061
|
-
|
|
6430
|
+
live.current?.cancel();
|
|
6062
6431
|
}, []);
|
|
6063
6432
|
const onPointerDown = useCallback((e) => {
|
|
6064
6433
|
if (e.pointerType === "mouse" && e.button !== 0) return;
|
|
@@ -6066,41 +6435,46 @@ function useDragHandle(getPayload, options) {
|
|
|
6066
6435
|
if (e.target instanceof HTMLElement && e.target.closest("input, button, select, textarea")) return;
|
|
6067
6436
|
const startX = e.clientX;
|
|
6068
6437
|
const startY = e.clientY;
|
|
6069
|
-
let
|
|
6070
|
-
|
|
6071
|
-
|
|
6072
|
-
|
|
6073
|
-
|
|
6074
|
-
|
|
6075
|
-
|
|
6076
|
-
const payload = getPayload();
|
|
6077
|
-
cleanup();
|
|
6078
|
-
if (payload) {
|
|
6079
|
-
target.addEventListener(
|
|
6080
|
-
"click",
|
|
6081
|
-
(ce) => {
|
|
6082
|
-
ce.stopPropagation();
|
|
6083
|
-
ce.preventDefault();
|
|
6084
|
-
},
|
|
6085
|
-
{ capture: true, once: true }
|
|
6086
|
-
);
|
|
6087
|
-
beginPointerDrag(payload, target, ev.clientX, ev.clientY, optsRef.current?.createGhost ?? defaultGhost);
|
|
6438
|
+
let ghost = null;
|
|
6439
|
+
let past = false;
|
|
6440
|
+
live.current = openPointerSession(target, e, {
|
|
6441
|
+
onMove: (ev) => {
|
|
6442
|
+
if (ghost) {
|
|
6443
|
+
ghost.move(ev);
|
|
6444
|
+
return;
|
|
6088
6445
|
}
|
|
6446
|
+
if (past) return;
|
|
6447
|
+
const dx = ev.clientX - startX;
|
|
6448
|
+
const dy = ev.clientY - startY;
|
|
6449
|
+
if (dx * dx + dy * dy <= DRAG_THRESHOLD_PX_SQ) return;
|
|
6450
|
+
past = true;
|
|
6451
|
+
const payload = getPayload();
|
|
6452
|
+
if (!payload) return;
|
|
6453
|
+
target.addEventListener(
|
|
6454
|
+
"click",
|
|
6455
|
+
(ce) => {
|
|
6456
|
+
ce.stopPropagation();
|
|
6457
|
+
ce.preventDefault();
|
|
6458
|
+
},
|
|
6459
|
+
{ capture: true, once: true }
|
|
6460
|
+
);
|
|
6461
|
+
ghost = beginPointerDrag(
|
|
6462
|
+
payload,
|
|
6463
|
+
target,
|
|
6464
|
+
ev.clientX,
|
|
6465
|
+
ev.clientY,
|
|
6466
|
+
optsRef.current?.createGhost ?? defaultGhost
|
|
6467
|
+
);
|
|
6468
|
+
},
|
|
6469
|
+
onEnd: (ev) => {
|
|
6470
|
+
live.current = null;
|
|
6471
|
+
ghost?.drop(ev);
|
|
6472
|
+
},
|
|
6473
|
+
onCancel: () => {
|
|
6474
|
+
live.current = null;
|
|
6475
|
+
ghost?.cancel();
|
|
6089
6476
|
}
|
|
6090
|
-
}
|
|
6091
|
-
function onEnd() {
|
|
6092
|
-
cleanup();
|
|
6093
|
-
}
|
|
6094
|
-
function cleanup() {
|
|
6095
|
-
document.removeEventListener("pointermove", onMove);
|
|
6096
|
-
document.removeEventListener("pointerup", onEnd);
|
|
6097
|
-
document.removeEventListener("pointercancel", onEnd);
|
|
6098
|
-
pendingTeardownRef.current = null;
|
|
6099
|
-
}
|
|
6100
|
-
document.addEventListener("pointermove", onMove);
|
|
6101
|
-
document.addEventListener("pointerup", onEnd);
|
|
6102
|
-
document.addEventListener("pointercancel", onEnd);
|
|
6103
|
-
pendingTeardownRef.current = cleanup;
|
|
6477
|
+
}, { capture: false });
|
|
6104
6478
|
}, [getPayload]);
|
|
6105
6479
|
return { onPointerDown, style: { touchAction: "none" } };
|
|
6106
6480
|
}
|
|
@@ -6127,47 +6501,34 @@ function startThresholdDrag(e, opts) {
|
|
|
6127
6501
|
const startX = e.clientX;
|
|
6128
6502
|
const startY = e.clientY;
|
|
6129
6503
|
const threshold = opts.threshold ?? 4;
|
|
6130
|
-
const target = e.currentTarget;
|
|
6131
|
-
target.setPointerCapture(e.pointerId);
|
|
6132
6504
|
let activated = false;
|
|
6133
|
-
|
|
6505
|
+
const maybeActivate = (ev) => {
|
|
6134
6506
|
if (activated) return;
|
|
6135
6507
|
const dx = ev.clientX - startX;
|
|
6136
6508
|
const dy = ev.clientY - startY;
|
|
6137
6509
|
if (dx * dx + dy * dy < threshold * threshold) return;
|
|
6138
6510
|
activated = true;
|
|
6139
6511
|
opts.onActivate?.(ev);
|
|
6140
|
-
}
|
|
6141
|
-
|
|
6142
|
-
|
|
6143
|
-
|
|
6144
|
-
|
|
6145
|
-
|
|
6146
|
-
|
|
6147
|
-
|
|
6148
|
-
|
|
6149
|
-
|
|
6150
|
-
|
|
6151
|
-
function onUp(ev) {
|
|
6152
|
-
cleanup();
|
|
6153
|
-
try {
|
|
6154
|
-
target.releasePointerCapture(ev.pointerId);
|
|
6155
|
-
} catch {
|
|
6156
|
-
}
|
|
6157
|
-
if (!activated) {
|
|
6512
|
+
};
|
|
6513
|
+
const session = openPointerSession(e.currentTarget, e, {
|
|
6514
|
+
onMove: (ev) => {
|
|
6515
|
+
maybeActivate(ev);
|
|
6516
|
+
if (activated) opts.onMove(ev);
|
|
6517
|
+
},
|
|
6518
|
+
onEnd: (ev) => {
|
|
6519
|
+
if (activated) opts.onCommit(ev);
|
|
6520
|
+
else opts.onCancel?.();
|
|
6521
|
+
},
|
|
6522
|
+
onCancel: () => {
|
|
6158
6523
|
opts.onCancel?.();
|
|
6159
|
-
return;
|
|
6160
6524
|
}
|
|
6161
|
-
|
|
6162
|
-
|
|
6163
|
-
|
|
6164
|
-
|
|
6165
|
-
|
|
6166
|
-
|
|
6167
|
-
|
|
6168
|
-
document.addEventListener("pointerup", onUp);
|
|
6169
|
-
document.addEventListener("pointercancel", onCancel);
|
|
6170
|
-
return { isDragging: () => activated };
|
|
6525
|
+
});
|
|
6526
|
+
return {
|
|
6527
|
+
isDragging: () => activated,
|
|
6528
|
+
cancel: () => {
|
|
6529
|
+
session.cancel();
|
|
6530
|
+
}
|
|
6531
|
+
};
|
|
6171
6532
|
}
|
|
6172
6533
|
|
|
6173
6534
|
// src/core/device/targets.ts
|
|
@@ -6732,8 +7093,8 @@ function runLayoutPass(scratch, moveCtx) {
|
|
|
6732
7093
|
for (const [cid, pose] of srcLayout.childPoses(srcContainer, srcChildren)) {
|
|
6733
7094
|
const cur = composeWorldPose(poseAdapter, cid, pc.compose);
|
|
6734
7095
|
const next = pose;
|
|
6735
|
-
const
|
|
6736
|
-
if (
|
|
7096
|
+
const same2 = cur.x === next.x && cur.y === next.y && cur.width === next.width && cur.height === next.height;
|
|
7097
|
+
if (same2) continue;
|
|
6737
7098
|
sourceReflow.set(cid, pose);
|
|
6738
7099
|
const parent = scene.get(asNodeId(cid))?.parent ?? null;
|
|
6739
7100
|
scratch.previews.set(asNodeId(cid), rebaseLocalPose(poseAdapter, pose, parent, pc.compose, pc.decompose));
|
|
@@ -8126,6 +8487,11 @@ var cloneAction = {
|
|
|
8126
8487
|
id: "clone",
|
|
8127
8488
|
label: "Clone",
|
|
8128
8489
|
defaultBinding: { kind: "drag" },
|
|
8490
|
+
// The platform's duplicate cursor, and the whole reason this field is
|
|
8491
|
+
// modifier-aware: the select tool binds clone behind `mods: { alt: true }`,
|
|
8492
|
+
// so the pump predicts it — and shows this — only while Alt is down.
|
|
8493
|
+
cursor: "copy",
|
|
8494
|
+
activeCursor: "copy",
|
|
8129
8495
|
eligible: { capability: ["edits-page", "creates-selection"] },
|
|
8130
8496
|
requires: ["selection", "scene", "applyOps"],
|
|
8131
8497
|
invoker: {
|
|
@@ -8211,6 +8577,30 @@ var cloneAction = {
|
|
|
8211
8577
|
enabled: () => true
|
|
8212
8578
|
};
|
|
8213
8579
|
|
|
8580
|
+
// src/core/viewport/createVelocityTracker.ts
|
|
8581
|
+
function createVelocityTracker() {
|
|
8582
|
+
let samples = [];
|
|
8583
|
+
return {
|
|
8584
|
+
record(dx, dy, t) {
|
|
8585
|
+
samples.push({ dx, dy, t });
|
|
8586
|
+
const cutoff = t - 100;
|
|
8587
|
+
samples = samples.filter((s) => s.t >= cutoff);
|
|
8588
|
+
},
|
|
8589
|
+
getVelocity() {
|
|
8590
|
+
const s = samples;
|
|
8591
|
+
if (s.length < 2) return { vx: 0, vy: 0 };
|
|
8592
|
+
const dt = s[s.length - 1].t - s[0].t;
|
|
8593
|
+
if (dt === 0) return { vx: 0, vy: 0 };
|
|
8594
|
+
const totalDx = s.slice(1).reduce((acc, p) => acc + p.dx, 0);
|
|
8595
|
+
const totalDy = s.slice(1).reduce((acc, p) => acc + p.dy, 0);
|
|
8596
|
+
return { vx: totalDx / dt, vy: totalDy / dt };
|
|
8597
|
+
},
|
|
8598
|
+
reset() {
|
|
8599
|
+
samples = [];
|
|
8600
|
+
}
|
|
8601
|
+
};
|
|
8602
|
+
}
|
|
8603
|
+
|
|
8214
8604
|
// src/interactions/actions/defaults/viewportDragPan.ts
|
|
8215
8605
|
var viewportDragPanAction = {
|
|
8216
8606
|
id: "viewport.dragPan",
|
|
@@ -8229,17 +8619,37 @@ var viewportDragPanAction = {
|
|
|
8229
8619
|
requires: ["view"],
|
|
8230
8620
|
invoker: {
|
|
8231
8621
|
timing: "ongoing",
|
|
8232
|
-
start(ctx) {
|
|
8622
|
+
start(ctx, opts) {
|
|
8233
8623
|
const view = ctx.deps.view;
|
|
8234
8624
|
if (!view) return {};
|
|
8235
8625
|
const startView = view.get();
|
|
8236
|
-
const
|
|
8626
|
+
const params = resolveParams(opts?.params) ?? {};
|
|
8627
|
+
const inertia = params.inertia === false ? void 0 : params.inertia;
|
|
8628
|
+
const scratch = {
|
|
8629
|
+
startView,
|
|
8630
|
+
view,
|
|
8631
|
+
axis: params.axis ?? "both",
|
|
8632
|
+
inertia,
|
|
8633
|
+
// Only track when a coast could actually happen, so the common
|
|
8634
|
+
// no-inertia drag does no per-move work.
|
|
8635
|
+
tracker: inertia && view.decay ? createVelocityTracker() : void 0,
|
|
8636
|
+
lastScreen: { x: 0, y: 0 }
|
|
8637
|
+
};
|
|
8237
8638
|
return {
|
|
8238
8639
|
kind: "pan",
|
|
8239
8640
|
onMove(moveCtx) {
|
|
8240
8641
|
if (!moveCtx.drag) return;
|
|
8241
8642
|
const screen = moveCtx.drag.screenDelta ?? moveCtx.drag.delta;
|
|
8242
|
-
const
|
|
8643
|
+
const screenDx = scratch.axis === "y" ? 0 : screen.x;
|
|
8644
|
+
const screenDy = scratch.axis === "x" ? 0 : screen.y;
|
|
8645
|
+
if (scratch.tracker) {
|
|
8646
|
+
scratch.tracker.record(
|
|
8647
|
+
screenDx - scratch.lastScreen.x,
|
|
8648
|
+
screenDy - scratch.lastScreen.y,
|
|
8649
|
+
performance.now()
|
|
8650
|
+
);
|
|
8651
|
+
scratch.lastScreen = { x: screenDx, y: screenDy };
|
|
8652
|
+
}
|
|
8243
8653
|
const sv = scratch.startView;
|
|
8244
8654
|
scratch.view.set({
|
|
8245
8655
|
...sv,
|
|
@@ -8247,7 +8657,24 @@ var viewportDragPanAction = {
|
|
|
8247
8657
|
y: sv.y - screenDy / sv.scale.y
|
|
8248
8658
|
});
|
|
8249
8659
|
},
|
|
8250
|
-
onEnd() {
|
|
8660
|
+
onEnd(_endCtx, reason) {
|
|
8661
|
+
const { tracker, inertia: inertia2, view: v } = scratch;
|
|
8662
|
+
if (reason === "cancel" || !tracker || !inertia2 || !v.decay) return;
|
|
8663
|
+
const { vx, vy } = tracker.getVelocity();
|
|
8664
|
+
const scale2 = scratch.startView.scale;
|
|
8665
|
+
v.decay({
|
|
8666
|
+
// Screen px/ms → world units/ms, matching the onMove conversion.
|
|
8667
|
+
velocity: { vx: -vx / scale2.x, vy: -vy / scale2.y },
|
|
8668
|
+
friction: inertia2.friction,
|
|
8669
|
+
minSpeed: inertia2.minSpeed,
|
|
8670
|
+
boundary: inertia2.boundary,
|
|
8671
|
+
viewBounds: inertia2.bounds,
|
|
8672
|
+
initialPosition: { x: v.get().x, y: v.get().y },
|
|
8673
|
+
onTick: (dx, dy) => {
|
|
8674
|
+
const cur = v.get();
|
|
8675
|
+
v.set({ ...cur, x: cur.x + dx, y: cur.y + dy });
|
|
8676
|
+
}
|
|
8677
|
+
});
|
|
8251
8678
|
}
|
|
8252
8679
|
};
|
|
8253
8680
|
}
|
|
@@ -8351,6 +8778,54 @@ function makeViewportZoomAction(opts = {}) {
|
|
|
8351
8778
|
}
|
|
8352
8779
|
var viewportZoomAction = makeViewportZoomAction();
|
|
8353
8780
|
|
|
8781
|
+
// src/interactions/actions/defaults/viewportWheelPan.ts
|
|
8782
|
+
var viewportWheelPanAction = {
|
|
8783
|
+
id: "viewport.wheelPan",
|
|
8784
|
+
label: "Pan (wheel)",
|
|
8785
|
+
group: "viewport",
|
|
8786
|
+
/**
|
|
8787
|
+
* Plain wheel → pan; Shift+wheel → horizontal pan (axis swap).
|
|
8788
|
+
* Cmd+wheel is claimed by `viewportZoomAction`. The matcher's strict
|
|
8789
|
+
* modifier check keeps the bindings exclusive: omitting `mods` forbids
|
|
8790
|
+
* any modifier, and `mods: { shift: true }` forbids the others.
|
|
8791
|
+
*/
|
|
8792
|
+
defaultBinding: [
|
|
8793
|
+
{ spec: { kind: "wheel" }, opts: {} },
|
|
8794
|
+
{ spec: { kind: "wheel", mods: { shift: true } }, opts: { params: { swapAxis: true } } }
|
|
8795
|
+
],
|
|
8796
|
+
requires: ["view"],
|
|
8797
|
+
invoker: {
|
|
8798
|
+
timing: "immediate",
|
|
8799
|
+
run(deps, params) {
|
|
8800
|
+
const view = deps.view;
|
|
8801
|
+
if (!view) return;
|
|
8802
|
+
const axis = params?.axis ?? "both";
|
|
8803
|
+
const deltaX = params?.deltaX ?? 0;
|
|
8804
|
+
const deltaY = params?.deltaY ?? 0;
|
|
8805
|
+
const current = view.get();
|
|
8806
|
+
const swap = params?.swapAxis === true;
|
|
8807
|
+
const dx = swap ? (deltaX !== 0 ? deltaX : deltaY) / current.scale.x : deltaX / current.scale.x;
|
|
8808
|
+
const dy = swap ? 0 : deltaY / current.scale.y;
|
|
8809
|
+
view.set({
|
|
8810
|
+
...current,
|
|
8811
|
+
x: current.x + (axis === "y" ? 0 : dx),
|
|
8812
|
+
y: current.y + (axis === "x" ? 0 : dy)
|
|
8813
|
+
});
|
|
8814
|
+
}
|
|
8815
|
+
},
|
|
8816
|
+
enabled: () => true
|
|
8817
|
+
};
|
|
8818
|
+
function makeViewportWheelPanAction(opts = {}) {
|
|
8819
|
+
const axis = opts.axis ?? "both";
|
|
8820
|
+
return {
|
|
8821
|
+
...viewportWheelPanAction,
|
|
8822
|
+
defaultBinding: [
|
|
8823
|
+
{ spec: { kind: "wheel" }, opts: { params: { axis } } },
|
|
8824
|
+
{ spec: { kind: "wheel", mods: { shift: true } }, opts: { params: { swapAxis: true, axis } } }
|
|
8825
|
+
]
|
|
8826
|
+
};
|
|
8827
|
+
}
|
|
8828
|
+
|
|
8354
8829
|
// src/interactions/dispatcher/predicates.ts
|
|
8355
8830
|
function bodyPredicate(fn) {
|
|
8356
8831
|
return Object.assign(fn, { readsAffordance: false });
|
|
@@ -12286,8 +12761,6 @@ function useHoverTracking(args) {
|
|
|
12286
12761
|
}, [canvasRef, enabled]);
|
|
12287
12762
|
return () => hoverRef.current;
|
|
12288
12763
|
}
|
|
12289
|
-
|
|
12290
|
-
// src/interactions/dispatcher/dispatcher.ts
|
|
12291
12764
|
function pointerGestureId(pointerId) {
|
|
12292
12765
|
return `pointer-${pointerId ?? "mouse"}`;
|
|
12293
12766
|
}
|
|
@@ -12792,7 +13265,7 @@ function createDispatcher(opts) {
|
|
|
12792
13265
|
}
|
|
12793
13266
|
function inFlightCursor() {
|
|
12794
13267
|
for (const action of inFlightActions.values()) {
|
|
12795
|
-
const cursor = action.activeCursor ?? action.cursor;
|
|
13268
|
+
const cursor = resolveCursor(action.activeCursor ?? action.cursor);
|
|
12796
13269
|
if (cursor) return cursor;
|
|
12797
13270
|
}
|
|
12798
13271
|
return null;
|
|
@@ -12975,8 +13448,6 @@ function itemsFromClipboardData(cd) {
|
|
|
12975
13448
|
}
|
|
12976
13449
|
return out;
|
|
12977
13450
|
}
|
|
12978
|
-
|
|
12979
|
-
// src/interactions/dispatcher/useGestureDispatcher.tsx
|
|
12980
13451
|
var DROPOVER_CLASS = "weasel-dropover";
|
|
12981
13452
|
function stylusOf(e) {
|
|
12982
13453
|
return {
|
|
@@ -13018,7 +13489,7 @@ function computeMultiTouchGeometry(positions) {
|
|
|
13018
13489
|
return { centroid, spread };
|
|
13019
13490
|
}
|
|
13020
13491
|
function useGestureDispatcher(opts) {
|
|
13021
|
-
const { canvasRef, actions, toolsById, enabled = true, keyboard = true, affordanceAt, classifyTarget, dispatcher: dispatcherOpt, clientToWorld: clientToWorld2, requestRedraw, getRuleCtx, onDoubleClick, views } = opts;
|
|
13492
|
+
const { canvasRef, actions, toolsById, enabled = true, keyboard = true, affordanceAt, classifyTarget, dispatcher: dispatcherOpt, clientToWorld: clientToWorld2, requestRedraw, paintedCursor, getRuleCtx, onDoubleClick, views } = opts;
|
|
13022
13493
|
const onDoubleClickRef = useRef(onDoubleClick);
|
|
13023
13494
|
onDoubleClickRef.current = onDoubleClick;
|
|
13024
13495
|
const activeTool = useActiveToolContext();
|
|
@@ -13067,6 +13538,8 @@ function useGestureDispatcher(opts) {
|
|
|
13067
13538
|
];
|
|
13068
13539
|
const requestRedrawRef = useRef(requestRedraw);
|
|
13069
13540
|
requestRedrawRef.current = requestRedraw;
|
|
13541
|
+
const paintedCursorRef = useRef(paintedCursor);
|
|
13542
|
+
paintedCursorRef.current = paintedCursor;
|
|
13070
13543
|
const lastClickRef = useRef(null);
|
|
13071
13544
|
const prevActiveRef = useRef(activeTool.active);
|
|
13072
13545
|
useEffect(() => {
|
|
@@ -13127,6 +13600,7 @@ function useGestureDispatcher(opts) {
|
|
|
13127
13600
|
};
|
|
13128
13601
|
const heldKeys = /* @__PURE__ */ new Set();
|
|
13129
13602
|
const activePointers = /* @__PURE__ */ new Set();
|
|
13603
|
+
const buttonsReportedFor = /* @__PURE__ */ new Set();
|
|
13130
13604
|
const pointerPositions = /* @__PURE__ */ new Map();
|
|
13131
13605
|
let multiTouchStart = null;
|
|
13132
13606
|
const TAP_THRESHOLD_PX = 8;
|
|
@@ -13269,8 +13743,10 @@ function useGestureDispatcher(opts) {
|
|
|
13269
13743
|
};
|
|
13270
13744
|
const onPointerDown = (e) => {
|
|
13271
13745
|
if ((e.button ?? 0) !== 0) return;
|
|
13746
|
+
if (activePointers.has(e.pointerId)) onPointerUp(e);
|
|
13272
13747
|
routeDown(e.pointerId, e.clientX, e.clientY);
|
|
13273
13748
|
activePointers.add(e.pointerId);
|
|
13749
|
+
if (reportsButtons(e)) buttonsReportedFor.add(e.pointerId);
|
|
13274
13750
|
pointerPositions.set(e.pointerId, { x: e.clientX, y: e.clientY });
|
|
13275
13751
|
try {
|
|
13276
13752
|
canvas?.setPointerCapture?.(e.pointerId);
|
|
@@ -13349,6 +13825,10 @@ function useGestureDispatcher(opts) {
|
|
|
13349
13825
|
}
|
|
13350
13826
|
};
|
|
13351
13827
|
const onPointerMove = (e) => {
|
|
13828
|
+
if (activePointers.has(e.pointerId) && buttonsReportedFor.has(e.pointerId) && isMissedRelease(e)) {
|
|
13829
|
+
onPointerUp(e);
|
|
13830
|
+
return;
|
|
13831
|
+
}
|
|
13352
13832
|
routeAt(e.pointerId, e.clientX, e.clientY);
|
|
13353
13833
|
if (activePointers.has(e.pointerId)) {
|
|
13354
13834
|
pointerPositions.set(e.pointerId, { x: e.clientX, y: e.clientY });
|
|
@@ -13406,20 +13886,39 @@ function useGestureDispatcher(opts) {
|
|
|
13406
13886
|
let lastHover = null;
|
|
13407
13887
|
let cursorOverridden = false;
|
|
13408
13888
|
const clearHoverCursor = () => {
|
|
13889
|
+
paintedCursorRef.current?.()?.setOverride(null);
|
|
13409
13890
|
if (cursorOverridden && canvas) {
|
|
13410
13891
|
canvas.style.cursor = "";
|
|
13411
13892
|
cursorOverridden = false;
|
|
13412
13893
|
}
|
|
13413
13894
|
};
|
|
13414
|
-
const applyHoverCursor = (
|
|
13415
|
-
|
|
13416
|
-
|
|
13417
|
-
|
|
13418
|
-
|
|
13895
|
+
const applyHoverCursor = (spec) => {
|
|
13896
|
+
const tier = spec === null ? null : resolveCursorTier(spec);
|
|
13897
|
+
if (!tier || !canvas) {
|
|
13898
|
+
clearHoverCursor();
|
|
13899
|
+
return;
|
|
13900
|
+
}
|
|
13901
|
+
const painted = tier.kind === "painted" ? tier : null;
|
|
13902
|
+
paintedCursorRef.current?.()?.setOverride(painted);
|
|
13903
|
+
const cursor = tier.kind === "css" ? tier.css : "none";
|
|
13904
|
+
if (!cursor) {
|
|
13419
13905
|
clearHoverCursor();
|
|
13906
|
+
return;
|
|
13420
13907
|
}
|
|
13908
|
+
canvas.style.cursor = cursor;
|
|
13909
|
+
cursorOverridden = true;
|
|
13421
13910
|
};
|
|
13911
|
+
function pushPaintedPointer() {
|
|
13912
|
+
const painted = paintedCursorRef.current?.();
|
|
13913
|
+
if (!painted?.active() || !canvas || !lastHover) return;
|
|
13914
|
+
const r = canvas.getBoundingClientRect();
|
|
13915
|
+
painted.setPointer(lastHover.clientX - r.left, lastHover.clientY - r.top);
|
|
13916
|
+
}
|
|
13422
13917
|
function refreshHoverCursor() {
|
|
13918
|
+
resolveHoverCursor();
|
|
13919
|
+
pushPaintedPointer();
|
|
13920
|
+
}
|
|
13921
|
+
function resolveHoverCursor() {
|
|
13423
13922
|
if (!canvas || !lastHover) return;
|
|
13424
13923
|
if (activePointers.size > 0 || dispatcherNow().inFlight().size > 0) {
|
|
13425
13924
|
applyHoverCursor(dispatcherNow().inFlightCursor());
|
|
@@ -13471,6 +13970,7 @@ function useGestureDispatcher(opts) {
|
|
|
13471
13970
|
};
|
|
13472
13971
|
const onHoverPointerLeave = () => {
|
|
13473
13972
|
lastHover = null;
|
|
13973
|
+
paintedCursorRef.current?.()?.clearPointer();
|
|
13474
13974
|
clearHoverCursor();
|
|
13475
13975
|
};
|
|
13476
13976
|
const onPointerUp = (e) => {
|
|
@@ -13478,6 +13978,7 @@ function useGestureDispatcher(opts) {
|
|
|
13478
13978
|
cancelLongPress(e.pointerId);
|
|
13479
13979
|
const prevSize = activePointers.size;
|
|
13480
13980
|
activePointers.delete(e.pointerId);
|
|
13981
|
+
buttonsReportedFor.delete(e.pointerId);
|
|
13481
13982
|
pointerPositions.delete(e.pointerId);
|
|
13482
13983
|
const staysUnderThreshold = bufferedDown.delete(e.pointerId);
|
|
13483
13984
|
if (prevSize >= 2 && activePointers.size < 2) {
|
|
@@ -13585,6 +14086,7 @@ function useGestureDispatcher(opts) {
|
|
|
13585
14086
|
routeAt(e.pointerId, e.clientX, e.clientY);
|
|
13586
14087
|
cancelLongPress(e.pointerId);
|
|
13587
14088
|
activePointers.delete(e.pointerId);
|
|
14089
|
+
buttonsReportedFor.delete(e.pointerId);
|
|
13588
14090
|
pointerPositions.delete(e.pointerId);
|
|
13589
14091
|
lastPointerDown.delete(e.pointerId);
|
|
13590
14092
|
bufferedDown.delete(e.pointerId);
|
|
@@ -13600,6 +14102,11 @@ function useGestureDispatcher(opts) {
|
|
|
13600
14102
|
dispatch2(ev);
|
|
13601
14103
|
routeRelease(e.pointerId);
|
|
13602
14104
|
};
|
|
14105
|
+
const onLostCapture = (e) => {
|
|
14106
|
+
const pe = e;
|
|
14107
|
+
if (!activePointers.has(pe.pointerId)) return;
|
|
14108
|
+
onPointerCancel(pe);
|
|
14109
|
+
};
|
|
13603
14110
|
const onContextMenu = (e) => {
|
|
13604
14111
|
e.preventDefault();
|
|
13605
14112
|
routeAt(null, e.clientX, e.clientY);
|
|
@@ -13689,6 +14196,7 @@ function useGestureDispatcher(opts) {
|
|
|
13689
14196
|
canvas?.addEventListener("pointermove", onPointerMove);
|
|
13690
14197
|
canvas?.addEventListener("pointerup", onPointerUp);
|
|
13691
14198
|
canvas?.addEventListener("pointercancel", onPointerCancel);
|
|
14199
|
+
canvas?.addEventListener(LOST_CAPTURE_EVENT, onLostCapture);
|
|
13692
14200
|
canvas?.addEventListener("contextmenu", onContextMenu);
|
|
13693
14201
|
canvas?.addEventListener("dragenter", onDragOver);
|
|
13694
14202
|
canvas?.addEventListener("dragover", onDragOver);
|
|
@@ -13709,6 +14217,7 @@ function useGestureDispatcher(opts) {
|
|
|
13709
14217
|
canvas?.removeEventListener("pointermove", onPointerMove);
|
|
13710
14218
|
canvas?.removeEventListener("pointerup", onPointerUp);
|
|
13711
14219
|
canvas?.removeEventListener("pointercancel", onPointerCancel);
|
|
14220
|
+
canvas?.removeEventListener(LOST_CAPTURE_EVENT, onLostCapture);
|
|
13712
14221
|
canvas?.removeEventListener("contextmenu", onContextMenu);
|
|
13713
14222
|
canvas?.removeEventListener("dragenter", onDragOver);
|
|
13714
14223
|
canvas?.removeEventListener("dragover", onDragOver);
|
|
@@ -13751,26 +14260,7 @@ function computeWheelAction(state, input, bounds = { min: DEFAULT_MIN_ZOOM, max:
|
|
|
13751
14260
|
};
|
|
13752
14261
|
}
|
|
13753
14262
|
function useVelocityTracker() {
|
|
13754
|
-
|
|
13755
|
-
return useMemo(() => ({
|
|
13756
|
-
record(dx, dy, t) {
|
|
13757
|
-
samplesRef.current.push({ dx, dy, t });
|
|
13758
|
-
const cutoff = t - 100;
|
|
13759
|
-
samplesRef.current = samplesRef.current.filter((s) => s.t >= cutoff);
|
|
13760
|
-
},
|
|
13761
|
-
getVelocity() {
|
|
13762
|
-
const s = samplesRef.current;
|
|
13763
|
-
if (s.length < 2) return { vx: 0, vy: 0 };
|
|
13764
|
-
const dt = s[s.length - 1].t - s[0].t;
|
|
13765
|
-
if (dt === 0) return { vx: 0, vy: 0 };
|
|
13766
|
-
const totalDx = s.slice(1).reduce((acc, p) => acc + p.dx, 0);
|
|
13767
|
-
const totalDy = s.slice(1).reduce((acc, p) => acc + p.dy, 0);
|
|
13768
|
-
return { vx: totalDx / dt, vy: totalDy / dt };
|
|
13769
|
-
},
|
|
13770
|
-
reset() {
|
|
13771
|
-
samplesRef.current = [];
|
|
13772
|
-
}
|
|
13773
|
-
}), []);
|
|
14263
|
+
return useMemo(() => createVelocityTracker(), []);
|
|
13774
14264
|
}
|
|
13775
14265
|
var SPRING_DAMPING = 0.5;
|
|
13776
14266
|
function useDecayLoop() {
|
|
@@ -15200,7 +15690,7 @@ function validateId(id, kind) {
|
|
|
15200
15690
|
}
|
|
15201
15691
|
function defineTool(def) {
|
|
15202
15692
|
validateId(def.id, "tool");
|
|
15203
|
-
const
|
|
15693
|
+
const resolveCursor3 = (ctx) => {
|
|
15204
15694
|
if (def.cursor == null) return "";
|
|
15205
15695
|
return typeof def.cursor === "function" ? def.cursor(ctx) : def.cursor;
|
|
15206
15696
|
};
|
|
@@ -15218,7 +15708,7 @@ function defineTool(def) {
|
|
|
15218
15708
|
onActivate: def.onActivate,
|
|
15219
15709
|
onDeactivate: def.onDeactivate,
|
|
15220
15710
|
initScratch: def.initScratch ?? (() => null),
|
|
15221
|
-
cursor:
|
|
15711
|
+
cursor: resolveCursor3,
|
|
15222
15712
|
bindings: def.bindings,
|
|
15223
15713
|
overlay: def.overlay,
|
|
15224
15714
|
overlayPosition: def.overlayPosition
|
|
@@ -17288,6 +17778,9 @@ function transformOf(state, targetId) {
|
|
|
17288
17778
|
identity: false
|
|
17289
17779
|
};
|
|
17290
17780
|
}
|
|
17781
|
+
function angleOf(xf) {
|
|
17782
|
+
return xf.identity ? 0 : Math.atan2(xf.sin, xf.cos);
|
|
17783
|
+
}
|
|
17291
17784
|
function localToWorld(xf, lx, ly) {
|
|
17292
17785
|
if (xf.identity) return { x: lx, y: ly };
|
|
17293
17786
|
const dx = lx - xf.cx;
|
|
@@ -17591,11 +18084,7 @@ var DEFAULT_PAINT = {
|
|
|
17591
18084
|
insetPx: 10
|
|
17592
18085
|
};
|
|
17593
18086
|
function createRotationAffordance(opts = {}) {
|
|
17594
|
-
const {
|
|
17595
|
-
bandPx = 24,
|
|
17596
|
-
paint = DEFAULT_PAINT,
|
|
17597
|
-
cursor = "grab"
|
|
17598
|
-
} = opts;
|
|
18087
|
+
const { bandPx = 24, paint = DEFAULT_PAINT, cursor } = opts;
|
|
17599
18088
|
const annulusPaint = (() => {
|
|
17600
18089
|
if (!paint) return null;
|
|
17601
18090
|
if ("paint" in paint) {
|
|
@@ -17633,7 +18122,14 @@ function createRotationAffordance(opts = {}) {
|
|
|
17633
18122
|
},
|
|
17634
18123
|
...annulusPaint ? { paint: annulusPaint } : {},
|
|
17635
18124
|
hitKind: "rotate-handle",
|
|
17636
|
-
|
|
18125
|
+
// Turned with the target, so the arc follows the selection it rotates.
|
|
18126
|
+
// Resolved per region rather than defaulted in the option list because
|
|
18127
|
+
// the angle is only known once a target is picked.
|
|
18128
|
+
cursor: cursor ?? {
|
|
18129
|
+
glyph: "rotate",
|
|
18130
|
+
angle: angleOf(transformOf(state, target.id)),
|
|
18131
|
+
fallback: "grab"
|
|
18132
|
+
},
|
|
17637
18133
|
bind: () => ({
|
|
17638
18134
|
initialScratch: {
|
|
17639
18135
|
targetId: target.id,
|
|
@@ -17732,7 +18228,9 @@ function useRotateTool(adapter, options) {
|
|
|
17732
18228
|
[overlay]
|
|
17733
18229
|
);
|
|
17734
18230
|
}
|
|
17735
|
-
function useHandTool(
|
|
18231
|
+
function useHandTool(opts = {}) {
|
|
18232
|
+
const optsRef = useRef(opts);
|
|
18233
|
+
optsRef.current = opts;
|
|
17736
18234
|
return useMemo(
|
|
17737
18235
|
() => Object.assign(defineViewportTool({
|
|
17738
18236
|
id: "hand",
|
|
@@ -17750,7 +18248,16 @@ function useHandTool(_opts = {}) {
|
|
|
17750
18248
|
// viewportDragPanAction, which also owns the grabbing cursor
|
|
17751
18249
|
// (`Action.activeCursor`) the tool used to declare as an `engaged`
|
|
17752
18250
|
// phase entry.
|
|
17753
|
-
bindings: [{
|
|
18251
|
+
bindings: [{
|
|
18252
|
+
spec: { kind: "drag" },
|
|
18253
|
+
actionId: "viewport.dragPan",
|
|
18254
|
+
opts: {
|
|
18255
|
+
params: () => ({
|
|
18256
|
+
axis: optsRef.current.axis ?? "both",
|
|
18257
|
+
inertia: optsRef.current.inertia
|
|
18258
|
+
})
|
|
18259
|
+
}
|
|
18260
|
+
}]
|
|
17754
18261
|
}),
|
|
17755
18262
|
[]
|
|
17756
18263
|
);
|
|
@@ -18116,7 +18623,7 @@ function useRectTool() {
|
|
|
18116
18623
|
id: "rect",
|
|
18117
18624
|
capabilities: ["creates-shapes"],
|
|
18118
18625
|
hookName: "useRectTool",
|
|
18119
|
-
cursor: "crosshair",
|
|
18626
|
+
cursor: cursorFor("crosshairRect", { fallback: "crosshair" }),
|
|
18120
18627
|
presentation: {
|
|
18121
18628
|
label: "Rectangle",
|
|
18122
18629
|
icon: createElement(RectIcon),
|
|
@@ -18142,7 +18649,7 @@ function useEllipseTool() {
|
|
|
18142
18649
|
id: "ellipse",
|
|
18143
18650
|
capabilities: ["creates-shapes"],
|
|
18144
18651
|
hookName: "useEllipseTool",
|
|
18145
|
-
cursor: "crosshair",
|
|
18652
|
+
cursor: cursorFor("crosshairEllipse", { fallback: "crosshair" }),
|
|
18146
18653
|
presentation: {
|
|
18147
18654
|
label: "Ellipse",
|
|
18148
18655
|
group: "shape",
|
|
@@ -18250,7 +18757,7 @@ function useLineTool() {
|
|
|
18250
18757
|
id: "line",
|
|
18251
18758
|
capabilities: ["creates-shapes"],
|
|
18252
18759
|
hookName: "useLineTool",
|
|
18253
|
-
cursor: "crosshair",
|
|
18760
|
+
cursor: cursorFor("crosshairLine", { fallback: "crosshair" }),
|
|
18254
18761
|
presentation: {
|
|
18255
18762
|
label: "Line",
|
|
18256
18763
|
group: "shape",
|
|
@@ -18365,7 +18872,7 @@ function usePolygonTool(options = {}) {
|
|
|
18365
18872
|
id: "polygon",
|
|
18366
18873
|
capabilities: ["creates-shapes"],
|
|
18367
18874
|
hookName: "usePolygonTool",
|
|
18368
|
-
cursor: "crosshair",
|
|
18875
|
+
cursor: cursorFor("crosshairPolygon", { fallback: "crosshair" }),
|
|
18369
18876
|
// Registered by <ToolActionsMounter>, inside the ActionsProvider —
|
|
18370
18877
|
// see `ToolDef.actions` for why the hook can't register it itself.
|
|
18371
18878
|
actions: [adjustSidesAction],
|
|
@@ -18465,7 +18972,7 @@ function useStarTool(options = {}) {
|
|
|
18465
18972
|
id: "star",
|
|
18466
18973
|
capabilities: ["creates-shapes"],
|
|
18467
18974
|
hookName: "useStarTool",
|
|
18468
|
-
cursor: "crosshair",
|
|
18975
|
+
cursor: cursorFor("crosshairStar", { fallback: "crosshair" }),
|
|
18469
18976
|
// Registered by <ToolActionsMounter>, inside the ActionsProvider —
|
|
18470
18977
|
// see `ToolDef.actions` for why the hook can't register it itself.
|
|
18471
18978
|
actions: [adjustPointsAction],
|
|
@@ -19121,24 +19628,25 @@ function projectBounds(b, view) {
|
|
|
19121
19628
|
const [sx, sy] = worldToScreen(b.x, b.y, t);
|
|
19122
19629
|
return { ...b, x: sx, y: sy, width: b.width * view.scale.x, height: b.height * view.scale.y };
|
|
19123
19630
|
}
|
|
19631
|
+
function leavesOf(id, getChildren, isContainer) {
|
|
19632
|
+
if (!isContainer(id)) return [id];
|
|
19633
|
+
const out = [];
|
|
19634
|
+
const visit = (nid) => {
|
|
19635
|
+
const kids = getChildren(nid);
|
|
19636
|
+
if (kids.length === 0) {
|
|
19637
|
+
if (!isContainer(nid)) out.push(nid);
|
|
19638
|
+
return;
|
|
19639
|
+
}
|
|
19640
|
+
for (const k of kids) visit(k);
|
|
19641
|
+
};
|
|
19642
|
+
visit(id);
|
|
19643
|
+
return out;
|
|
19644
|
+
}
|
|
19124
19645
|
function composeSelectionPose(opts) {
|
|
19125
19646
|
const { moveOverlay, resizeOverlay, getStoredPose, getChildren, isContainer } = opts;
|
|
19126
19647
|
const getBounds = opts.getBounds ?? ((pose) => pose);
|
|
19127
19648
|
const fromBounds = opts.fromBounds ?? ((bounds) => bounds);
|
|
19128
|
-
const
|
|
19129
|
-
if (!getChildren || !isContainer || !isContainer(id)) return [id];
|
|
19130
|
-
const out = [];
|
|
19131
|
-
const visit = (nid) => {
|
|
19132
|
-
const kids = getChildren(nid);
|
|
19133
|
-
if (kids.length === 0) {
|
|
19134
|
-
if (!isContainer(nid)) out.push(nid);
|
|
19135
|
-
return;
|
|
19136
|
-
}
|
|
19137
|
-
for (const k of kids) visit(k);
|
|
19138
|
-
};
|
|
19139
|
-
visit(id);
|
|
19140
|
-
return out;
|
|
19141
|
-
};
|
|
19649
|
+
const selectionLeaves = (id) => getChildren && isContainer ? leavesOf(id, getChildren, isContainer) : [id];
|
|
19142
19650
|
const resolveLeaf = (id) => {
|
|
19143
19651
|
const moved = moveOverlay?.poses.get(id);
|
|
19144
19652
|
if (moved !== void 0) return moved;
|
|
@@ -19147,7 +19655,7 @@ function composeSelectionPose(opts) {
|
|
|
19147
19655
|
};
|
|
19148
19656
|
return (id) => {
|
|
19149
19657
|
if (isContainer?.(id)) {
|
|
19150
|
-
const leaves =
|
|
19658
|
+
const leaves = selectionLeaves(id);
|
|
19151
19659
|
if (leaves.length === 0) return null;
|
|
19152
19660
|
const containerResizeLeafPoses = resizeOverlay && resizeOverlay.id === id ? resizeOverlay.leafPoses : void 0;
|
|
19153
19661
|
const leafBounds = [];
|
|
@@ -19178,26 +19686,12 @@ function makeContainerAwareBoundsResolver(getPose, getBounds, getChildren, isCon
|
|
|
19178
19686
|
return p === null ? null : getBounds(p);
|
|
19179
19687
|
};
|
|
19180
19688
|
}
|
|
19181
|
-
const leavesOf = (id) => {
|
|
19182
|
-
if (!isContainer(id)) return [id];
|
|
19183
|
-
const out = [];
|
|
19184
|
-
const visit = (nid) => {
|
|
19185
|
-
const kids = getChildren(nid);
|
|
19186
|
-
if (kids.length === 0) {
|
|
19187
|
-
if (!isContainer(nid)) out.push(nid);
|
|
19188
|
-
return;
|
|
19189
|
-
}
|
|
19190
|
-
for (const k of kids) visit(k);
|
|
19191
|
-
};
|
|
19192
|
-
visit(id);
|
|
19193
|
-
return out;
|
|
19194
|
-
};
|
|
19195
19689
|
return (id) => {
|
|
19196
19690
|
if (!isContainer(id)) {
|
|
19197
19691
|
const p = getPose(id);
|
|
19198
19692
|
return p === null ? null : getBounds(p);
|
|
19199
19693
|
}
|
|
19200
|
-
const leaves = leavesOf(id);
|
|
19694
|
+
const leaves = leavesOf(id, getChildren, isContainer);
|
|
19201
19695
|
if (leaves.length === 0) return null;
|
|
19202
19696
|
const leafBounds = [];
|
|
19203
19697
|
for (const leafId of leaves) {
|
|
@@ -19592,6 +20086,113 @@ function buildSceneTree(adapter, drawOne, view, forLayer, derivedPathOf) {
|
|
|
19592
20086
|
}
|
|
19593
20087
|
return out;
|
|
19594
20088
|
}
|
|
20089
|
+
|
|
20090
|
+
// src/features/cursor/paintedCursorState.ts
|
|
20091
|
+
function same(a, b) {
|
|
20092
|
+
if (a === b) return true;
|
|
20093
|
+
if (!a || !b) return false;
|
|
20094
|
+
return a.glyph === b.glyph && a.angle === b.angle && a.size === b.size && a.worldRadius === b.worldRadius;
|
|
20095
|
+
}
|
|
20096
|
+
function createPaintedCursorState() {
|
|
20097
|
+
let base = null;
|
|
20098
|
+
let override = null;
|
|
20099
|
+
let at = null;
|
|
20100
|
+
const subs = /* @__PURE__ */ new Set();
|
|
20101
|
+
const notify2 = () => {
|
|
20102
|
+
for (const fn of subs) fn();
|
|
20103
|
+
};
|
|
20104
|
+
return {
|
|
20105
|
+
setBase(cursor) {
|
|
20106
|
+
if (same(base, cursor)) return;
|
|
20107
|
+
base = cursor;
|
|
20108
|
+
notify2();
|
|
20109
|
+
},
|
|
20110
|
+
setOverride(cursor) {
|
|
20111
|
+
if (same(override, cursor)) return;
|
|
20112
|
+
override = cursor;
|
|
20113
|
+
notify2();
|
|
20114
|
+
},
|
|
20115
|
+
setPointer(x, y) {
|
|
20116
|
+
if (at && at.x === x && at.y === y) return;
|
|
20117
|
+
at = { x, y };
|
|
20118
|
+
if (override ?? base) notify2();
|
|
20119
|
+
},
|
|
20120
|
+
clearPointer() {
|
|
20121
|
+
if (at === null) return;
|
|
20122
|
+
at = null;
|
|
20123
|
+
notify2();
|
|
20124
|
+
},
|
|
20125
|
+
active() {
|
|
20126
|
+
return (override ?? base) !== null;
|
|
20127
|
+
},
|
|
20128
|
+
current() {
|
|
20129
|
+
const cursor = override ?? base;
|
|
20130
|
+
if (!cursor || !at) return null;
|
|
20131
|
+
return { cursor, at };
|
|
20132
|
+
},
|
|
20133
|
+
subscribe(fn) {
|
|
20134
|
+
subs.add(fn);
|
|
20135
|
+
return () => {
|
|
20136
|
+
subs.delete(fn);
|
|
20137
|
+
};
|
|
20138
|
+
}
|
|
20139
|
+
};
|
|
20140
|
+
}
|
|
20141
|
+
var PAINTED_CURSOR_LAYER_ID = "painted-cursor";
|
|
20142
|
+
var pathCache = /* @__PURE__ */ new Map();
|
|
20143
|
+
function pathFor(d) {
|
|
20144
|
+
let p = pathCache.get(d);
|
|
20145
|
+
if (p === void 0) {
|
|
20146
|
+
p = pathFromD(d);
|
|
20147
|
+
pathCache.set(d, p);
|
|
20148
|
+
}
|
|
20149
|
+
return p;
|
|
20150
|
+
}
|
|
20151
|
+
function commandFor2(op) {
|
|
20152
|
+
return {
|
|
20153
|
+
kind: "path",
|
|
20154
|
+
path: pathFor(op.d),
|
|
20155
|
+
...op.fill !== void 0 ? { fill: { color: op.fill } } : {},
|
|
20156
|
+
...op.stroke !== void 0 ? {
|
|
20157
|
+
stroke: {
|
|
20158
|
+
paint: { color: op.stroke.color },
|
|
20159
|
+
width: op.stroke.width,
|
|
20160
|
+
cap: "round",
|
|
20161
|
+
join: "round"
|
|
20162
|
+
}
|
|
20163
|
+
} : {}
|
|
20164
|
+
};
|
|
20165
|
+
}
|
|
20166
|
+
function createPaintedCursorLayer(state) {
|
|
20167
|
+
return {
|
|
20168
|
+
id: PAINTED_CURSOR_LAYER_ID,
|
|
20169
|
+
label: "Painted cursor",
|
|
20170
|
+
space: "screen",
|
|
20171
|
+
draw: (_data, view) => {
|
|
20172
|
+
const frame = state.current();
|
|
20173
|
+
if (!frame) return [];
|
|
20174
|
+
const { cursor, at } = frame;
|
|
20175
|
+
const glyph = GLYPHS[cursor.glyph];
|
|
20176
|
+
if (!glyph) return [];
|
|
20177
|
+
const scale2 = (view.scale.x + view.scale.y) / 2;
|
|
20178
|
+
const worldSized = cursor.worldRadius !== void 0;
|
|
20179
|
+
const size = worldSized ? cursorWorldSize(glyph, cursor.worldRadius, scale2) : cursor.size ?? 24;
|
|
20180
|
+
if (!(size > 0) || !Number.isFinite(size)) return [];
|
|
20181
|
+
const ops = cursorPaintOps(
|
|
20182
|
+
glyph,
|
|
20183
|
+
worldSized ? { lineWidthScale: chromeLineWidthScale(glyph, size) } : {}
|
|
20184
|
+
);
|
|
20185
|
+
const [a, b, c, d, e, f] = cursorPaintMatrix(glyph, {
|
|
20186
|
+
size,
|
|
20187
|
+
angle: cursor.angle,
|
|
20188
|
+
at
|
|
20189
|
+
});
|
|
20190
|
+
const transform = new Float32Array([a, b, 0, c, d, 0, e, f, 1]);
|
|
20191
|
+
const children = ops.map(commandFor2);
|
|
20192
|
+
return [{ kind: "group", transform, children }];
|
|
20193
|
+
}
|
|
20194
|
+
};
|
|
20195
|
+
}
|
|
19595
20196
|
function mat3ToRenderMatrix(m) {
|
|
19596
20197
|
return new Float32Array([m[0], m[1], 0, m[2], m[3], 0, m[4], m[5], 1]);
|
|
19597
20198
|
}
|
|
@@ -19972,11 +20573,11 @@ function resolveToolsCursor(tools, ctxBase) {
|
|
|
19972
20573
|
const id = tools.hotkeyEngaged ?? tools.active;
|
|
19973
20574
|
const tool = tools.registry[id];
|
|
19974
20575
|
if (!tool?.cursor) return void 0;
|
|
19975
|
-
if (typeof tool.cursor
|
|
20576
|
+
if (typeof tool.cursor !== "function") return resolveCursorTier(tool.cursor);
|
|
19976
20577
|
if (!ctxBase) return void 0;
|
|
19977
20578
|
try {
|
|
19978
20579
|
const base = ctxBase();
|
|
19979
|
-
return tool.cursor({ ...base, scratch: null });
|
|
20580
|
+
return resolveCursorTier(tool.cursor({ ...base, scratch: null }));
|
|
19980
20581
|
} catch {
|
|
19981
20582
|
return void 0;
|
|
19982
20583
|
}
|
|
@@ -20141,6 +20742,14 @@ function CanvasInner(props, ref) {
|
|
|
20141
20742
|
viewSubsRef.current.delete(fn);
|
|
20142
20743
|
};
|
|
20143
20744
|
}, []);
|
|
20745
|
+
const paintedCursor = useMemo(() => createPaintedCursorState(), []);
|
|
20746
|
+
const paintedCursorLayer = useMemo(
|
|
20747
|
+
() => createPaintedCursorLayer(paintedCursor),
|
|
20748
|
+
[paintedCursor]
|
|
20749
|
+
);
|
|
20750
|
+
useEffect(() => paintedCursor.subscribe(() => {
|
|
20751
|
+
requestRedraw();
|
|
20752
|
+
}), [paintedCursor, requestRedraw]);
|
|
20144
20753
|
useImperativeHandle(ref, () => ({
|
|
20145
20754
|
// Named rather than read off `canvasRef` so the handle rebuilds when a
|
|
20146
20755
|
// detached surface's input element arrives, which is a render later.
|
|
@@ -20153,7 +20762,8 @@ function CanvasInner(props, ref) {
|
|
|
20153
20762
|
getView,
|
|
20154
20763
|
setView,
|
|
20155
20764
|
subscribeView,
|
|
20156
|
-
getPaintedVersion
|
|
20765
|
+
getPaintedVersion,
|
|
20766
|
+
paintedCursor
|
|
20157
20767
|
}), [
|
|
20158
20768
|
canvasRef,
|
|
20159
20769
|
ownCanvasRef,
|
|
@@ -20167,7 +20777,8 @@ function CanvasInner(props, ref) {
|
|
|
20167
20777
|
getView,
|
|
20168
20778
|
setView,
|
|
20169
20779
|
subscribeView,
|
|
20170
|
-
getPaintedVersion
|
|
20780
|
+
getPaintedVersion,
|
|
20781
|
+
paintedCursor
|
|
20171
20782
|
]);
|
|
20172
20783
|
const glRendererRef = useRef(null);
|
|
20173
20784
|
const layerCacheRef = useRef(/* @__PURE__ */ new Map());
|
|
@@ -20247,7 +20858,7 @@ function CanvasInner(props, ref) {
|
|
|
20247
20858
|
return {
|
|
20248
20859
|
worldX,
|
|
20249
20860
|
worldY,
|
|
20250
|
-
modifiers: m ? { alt: m.alt, shift: m.shift, meta: m.meta, ctrl: m.ctrl
|
|
20861
|
+
modifiers: m ? { alt: m.alt, shift: m.shift, meta: m.meta, ctrl: m.ctrl } : { alt: false, shift: false, meta: false, ctrl: false },
|
|
20251
20862
|
selection: effectiveSelectionRefForCtx.current,
|
|
20252
20863
|
adapter: effectiveAdapterRefForCtx.current,
|
|
20253
20864
|
applyOps: (ops, label) => {
|
|
@@ -20431,8 +21042,16 @@ function CanvasInner(props, ref) {
|
|
|
20431
21042
|
const layersWithDebug = useMemo(() => {
|
|
20432
21043
|
const withViews = viewRegistry ? [...layers, ...viewRegistry.list().map((r) => r.layer)] : layers;
|
|
20433
21044
|
const base = debugSink && resolvedDebugConfig ? [...withViews, createDebugOverlayLayer({ sink: debugSink, config: resolvedDebugConfig })] : withViews;
|
|
20434
|
-
return [...base, ...extrasRef.current];
|
|
20435
|
-
}, [
|
|
21045
|
+
return [...base, ...extrasRef.current, paintedCursorLayer];
|
|
21046
|
+
}, [
|
|
21047
|
+
layers,
|
|
21048
|
+
debugSink,
|
|
21049
|
+
resolvedDebugConfig,
|
|
21050
|
+
extrasVersion,
|
|
21051
|
+
viewRegistry,
|
|
21052
|
+
viewRegistryVersion,
|
|
21053
|
+
paintedCursorLayer
|
|
21054
|
+
]);
|
|
20436
21055
|
const shaderIdKey = shaders?.map((h) => h.id).join("|") ?? "";
|
|
20437
21056
|
const paintInputsRef = useRef({
|
|
20438
21057
|
layers: layersWithDebug,
|
|
@@ -20554,8 +21173,14 @@ function CanvasInner(props, ref) {
|
|
|
20554
21173
|
if (!renderer) return;
|
|
20555
21174
|
registerShadersOnRenderer(renderer, shaders);
|
|
20556
21175
|
}, [shaderIdKey]);
|
|
20557
|
-
const
|
|
21176
|
+
const toolsCursorTier = tools ? resolveToolsCursor(tools, toolsCtxBase) : void 0;
|
|
21177
|
+
const toolsCursor = toolsCursorTier === void 0 ? void 0 : toolsCursorTier.kind === "css" ? toolsCursorTier.css : "none";
|
|
20558
21178
|
const effectiveStyle = toolsCursor ? { ...style, cursor: toolsCursor } : style;
|
|
21179
|
+
const toolsPainted = toolsCursorTier?.kind === "painted" ? toolsCursorTier : null;
|
|
21180
|
+
const toolsPaintedKey = toolsPainted ? `${toolsPainted.glyph}|${toolsPainted.angle}|${toolsPainted.size}|${toolsPainted.worldRadius}` : "";
|
|
21181
|
+
useEffect(() => {
|
|
21182
|
+
paintedCursor.setBase(toolsPainted);
|
|
21183
|
+
}, [paintedCursor, toolsPaintedKey]);
|
|
20559
21184
|
const layersForMoveRef = useRef(layersWithDebug);
|
|
20560
21185
|
layersForMoveRef.current = layersWithDebug;
|
|
20561
21186
|
useEffect(() => {
|
|
@@ -21894,10 +22519,16 @@ function createCornerResizeAffordance(opts = {}) {
|
|
|
21894
22519
|
hitKind: c.kind,
|
|
21895
22520
|
// Diagonal by fixed-corner parity: a matched-axis anchor (min-min /
|
|
21896
22521
|
// max-max fixed) means the dragged corner sits on the ↘ diagonal;
|
|
21897
|
-
// mixed axes sit on the ↗ diagonal.
|
|
21898
|
-
//
|
|
21899
|
-
//
|
|
21900
|
-
|
|
22522
|
+
// mixed axes sit on the ↗ diagonal. The glyph is horizontal at angle
|
|
22523
|
+
// 0, so the diagonal is a half-quarter-turn either way, plus the
|
|
22524
|
+
// target's own rotation. The keyword is the fallback rather than the
|
|
22525
|
+
// answer: CSS has four of them, which cannot express a target
|
|
22526
|
+
// rotated to anything but a multiple of 45°.
|
|
22527
|
+
cursor: {
|
|
22528
|
+
glyph: "resize",
|
|
22529
|
+
angle: (c.anchor.x === c.anchor.y ? Math.PI / 4 : -Math.PI / 4) + angleOf(xf),
|
|
22530
|
+
fallback: c.anchor.x === c.anchor.y ? "nwse-resize" : "nesw-resize"
|
|
22531
|
+
},
|
|
21901
22532
|
bind: () => ({
|
|
21902
22533
|
initialScratch: {
|
|
21903
22534
|
anchor: c.anchor,
|
|
@@ -23930,10 +24561,10 @@ function boundsOf(coords) {
|
|
|
23930
24561
|
}
|
|
23931
24562
|
return { x: minX, y: minY, width: maxX - minX, height: maxY - minY };
|
|
23932
24563
|
}
|
|
23933
|
-
function useViewDepSource(currentViewRef, onViewChange, recenter, hostSize, animation) {
|
|
23934
|
-
const wiring = useRef({ currentViewRef, onViewChange, recenter, hostSize, animation });
|
|
23935
|
-
wiring.current = { currentViewRef, onViewChange, recenter, hostSize, animation };
|
|
23936
|
-
const shape = `${recenter ? "r" : ""}${hostSize ? "h" : ""}${animation ? "a" : ""}`;
|
|
24564
|
+
function useViewDepSource(currentViewRef, onViewChange, recenter, hostSize, animation, decay) {
|
|
24565
|
+
const wiring = useRef({ currentViewRef, onViewChange, recenter, hostSize, animation, decay });
|
|
24566
|
+
wiring.current = { currentViewRef, onViewChange, recenter, hostSize, animation, decay };
|
|
24567
|
+
const shape = `${recenter ? "r" : ""}${hostSize ? "h" : ""}${animation ? "a" : ""}${decay ? "d" : ""}`;
|
|
23937
24568
|
const shapeRef = useRef(null);
|
|
23938
24569
|
const viewApiRef = useRef(null);
|
|
23939
24570
|
if (viewApiRef.current === null || shapeRef.current !== shape) {
|
|
@@ -23952,6 +24583,10 @@ function useViewDepSource(currentViewRef, onViewChange, recenter, hostSize, anim
|
|
|
23952
24583
|
animate: (to, opts) => wiring.current.animation.animate(to, opts),
|
|
23953
24584
|
stopAnimation: () => wiring.current.animation.stop(),
|
|
23954
24585
|
animationTarget: () => wiring.current.animation.target()
|
|
24586
|
+
} : {},
|
|
24587
|
+
...decay ? {
|
|
24588
|
+
decay: (config) => wiring.current.decay.start(config),
|
|
24589
|
+
stopDecay: () => wiring.current.decay.cancel()
|
|
23955
24590
|
} : {}
|
|
23956
24591
|
};
|
|
23957
24592
|
}
|
|
@@ -24715,7 +25350,6 @@ function useActionsPropResolver(actions) {
|
|
|
24715
25350
|
}
|
|
24716
25351
|
if (!prop) return;
|
|
24717
25352
|
const unregisters = [];
|
|
24718
|
-
const restores = [];
|
|
24719
25353
|
const warnedIds = /* @__PURE__ */ new Set();
|
|
24720
25354
|
for (const [slotId, entry] of Object.entries(prop)) {
|
|
24721
25355
|
if (entry === null) {
|
|
@@ -24743,64 +25377,30 @@ function useActionsPropResolver(actions) {
|
|
|
24743
25377
|
}
|
|
24744
25378
|
const { id: _drop, ...rest } = entry;
|
|
24745
25379
|
const merged = { ...existing, ...rest };
|
|
24746
|
-
restores.push(() => {
|
|
24747
|
-
reg.register(existing);
|
|
24748
|
-
});
|
|
24749
25380
|
unregisters.push(reg.register(merged));
|
|
24750
25381
|
}
|
|
24751
25382
|
return () => {
|
|
24752
25383
|
for (const u of unregisters) u();
|
|
24753
|
-
for (const r of restores) r();
|
|
24754
25384
|
};
|
|
24755
25385
|
}, [reg, actions]);
|
|
24756
25386
|
}
|
|
24757
|
-
|
|
24758
|
-
// src/interactions/actions/defaults/viewportWheelPan.ts
|
|
24759
|
-
var viewportWheelPanAction = {
|
|
24760
|
-
id: "viewport.wheelPan",
|
|
24761
|
-
label: "Pan (wheel)",
|
|
24762
|
-
group: "viewport",
|
|
24763
|
-
/**
|
|
24764
|
-
* Plain wheel → pan; Shift+wheel → horizontal pan (axis swap).
|
|
24765
|
-
* Cmd+wheel is claimed by `viewportZoomAction`. The matcher's strict
|
|
24766
|
-
* modifier check keeps the bindings exclusive: omitting `mods` forbids
|
|
24767
|
-
* any modifier, and `mods: { shift: true }` forbids the others.
|
|
24768
|
-
*/
|
|
24769
|
-
defaultBinding: [
|
|
24770
|
-
{ spec: { kind: "wheel" }, opts: {} },
|
|
24771
|
-
{ spec: { kind: "wheel", mods: { shift: true } }, opts: { params: { swapAxis: true } } }
|
|
24772
|
-
],
|
|
24773
|
-
requires: ["view"],
|
|
24774
|
-
invoker: {
|
|
24775
|
-
timing: "immediate",
|
|
24776
|
-
run(deps, params) {
|
|
24777
|
-
const view = deps.view;
|
|
24778
|
-
if (!view) return;
|
|
24779
|
-
const deltaX = params?.deltaX ?? 0;
|
|
24780
|
-
const deltaY = params?.deltaY ?? 0;
|
|
24781
|
-
const current = view.get();
|
|
24782
|
-
const swap = params?.swapAxis === true;
|
|
24783
|
-
const dx = swap ? (deltaX !== 0 ? deltaX : deltaY) / current.scale.x : deltaX / current.scale.x;
|
|
24784
|
-
const dy = swap ? 0 : deltaY / current.scale.y;
|
|
24785
|
-
view.set({ ...current, x: current.x + dx, y: current.y + dy });
|
|
24786
|
-
}
|
|
24787
|
-
},
|
|
24788
|
-
enabled: () => true
|
|
24789
|
-
};
|
|
24790
|
-
|
|
24791
|
-
// src/canvas/SceneCanvas/useViewportActions.ts
|
|
24792
25387
|
function useViewportActions(args) {
|
|
24793
25388
|
const { pan, zoom, pinchZoom } = args;
|
|
24794
25389
|
const reg = useActionsRegistry();
|
|
24795
25390
|
const regRef = useRef(reg);
|
|
24796
25391
|
regRef.current = reg;
|
|
25392
|
+
const panKey = typeof pan === "object" ? JSON.stringify(pan) : String(pan);
|
|
24797
25393
|
const zoomKey = typeof zoom === "object" ? JSON.stringify(zoom) : String(zoom);
|
|
24798
25394
|
const pinchKey = typeof pinchZoom === "object" ? JSON.stringify(pinchZoom) : String(pinchZoom);
|
|
24799
25395
|
useEffect(() => {
|
|
24800
25396
|
const r = regRef.current;
|
|
24801
25397
|
if (!r) return;
|
|
24802
25398
|
const unregisters = [];
|
|
24803
|
-
if (pan)
|
|
25399
|
+
if (pan) {
|
|
25400
|
+
unregisters.push(
|
|
25401
|
+
r.register(makeViewportWheelPanAction(typeof pan === "object" ? pan : {}))
|
|
25402
|
+
);
|
|
25403
|
+
}
|
|
24804
25404
|
if (zoom) {
|
|
24805
25405
|
const zoomAction = typeof zoom === "object" ? makeViewportZoomAction(zoom) : makeViewportZoomAction();
|
|
24806
25406
|
unregisters.push(r.register(zoomAction));
|
|
@@ -24815,7 +25415,7 @@ function useViewportActions(args) {
|
|
|
24815
25415
|
return () => {
|
|
24816
25416
|
for (const u of unregisters) u();
|
|
24817
25417
|
};
|
|
24818
|
-
}, [
|
|
25418
|
+
}, [panKey, zoomKey, pinchKey]);
|
|
24819
25419
|
}
|
|
24820
25420
|
|
|
24821
25421
|
// src/core/scene/NodeRouting.ts
|
|
@@ -25250,13 +25850,13 @@ function SceneCanvasInner(props, ref) {
|
|
|
25250
25850
|
const viewportRegistered = !!viewport;
|
|
25251
25851
|
const inertiaEnabled = !!viewport?.inertia;
|
|
25252
25852
|
const inertiaObj = typeof viewport?.inertia === "object" ? viewport.inertia : void 0;
|
|
25253
|
-
const handToolInertia = inertiaEnabled
|
|
25254
|
-
friction: inertiaObj
|
|
25255
|
-
minSpeed: inertiaObj
|
|
25256
|
-
boundary: inertiaObj
|
|
25257
|
-
bounds: inertiaObj
|
|
25853
|
+
const handToolInertia = inertiaEnabled ? {
|
|
25854
|
+
friction: inertiaObj?.friction,
|
|
25855
|
+
minSpeed: inertiaObj?.minSpeed,
|
|
25856
|
+
boundary: inertiaObj?.boundary,
|
|
25857
|
+
bounds: inertiaObj?.bounds
|
|
25258
25858
|
} : void 0;
|
|
25259
|
-
const handTool = useHandTool(handToolInertia ? { } : {});
|
|
25859
|
+
const handTool = useHandTool(handToolInertia ? { inertia: handToolInertia } : {});
|
|
25260
25860
|
const viewportAmbient = [];
|
|
25261
25861
|
const baseRequestedTools = defaultTools ?? (toolBundle ? BUNDLE_TOOLS[toolBundle] : null) ?? (viewportRegistered ? ["select", "rotate", "hand"] : ["select", "rotate"]);
|
|
25262
25862
|
const KNOWN_BUILTIN_IDS = /* @__PURE__ */ new Set([
|
|
@@ -25709,7 +26309,7 @@ function SceneCanvasInner(props, ref) {
|
|
|
25709
26309
|
dispatcher,
|
|
25710
26310
|
getActionRef,
|
|
25711
26311
|
pickEvery: internalPickEvery,
|
|
25712
|
-
viewportPanEnabled: viewport?.pan
|
|
26312
|
+
viewportPanEnabled: viewport?.pan ?? true,
|
|
25713
26313
|
viewportZoom: resolvedViewportZoom,
|
|
25714
26314
|
viewportPinchZoom: viewport?.pinchZoom ?? true,
|
|
25715
26315
|
viewportRecenter: viewport?.recenter,
|
|
@@ -25920,6 +26520,10 @@ function GestureDispatcherMounter({
|
|
|
25920
26520
|
const requestRedraw = useCallback(() => {
|
|
25921
26521
|
canvasApiRef?.current?.requestRedraw?.();
|
|
25922
26522
|
}, [canvasApiRef]);
|
|
26523
|
+
const paintedCursor = useCallback(
|
|
26524
|
+
() => canvasApiRef?.current?.paintedCursor,
|
|
26525
|
+
[canvasApiRef]
|
|
26526
|
+
);
|
|
25923
26527
|
const views = useMemo(() => {
|
|
25924
26528
|
if (!viewRegistry) return void 0;
|
|
25925
26529
|
return {
|
|
@@ -25938,6 +26542,7 @@ function GestureDispatcherMounter({
|
|
|
25938
26542
|
dispatcher,
|
|
25939
26543
|
clientToWorld: clientToWorld2,
|
|
25940
26544
|
requestRedraw,
|
|
26545
|
+
paintedCursor,
|
|
25941
26546
|
getRuleCtx,
|
|
25942
26547
|
onDoubleClick,
|
|
25943
26548
|
...views ? { views } : {}
|
|
@@ -25995,6 +26600,7 @@ function StandardActionsRegistrar({
|
|
|
25995
26600
|
getActionRef.current = null;
|
|
25996
26601
|
};
|
|
25997
26602
|
}, [registry2, getActionRef]);
|
|
26603
|
+
const decayLoop = useDecayLoop();
|
|
25998
26604
|
const view = useViewDepSource(
|
|
25999
26605
|
currentViewRef,
|
|
26000
26606
|
onViewChange,
|
|
@@ -26003,7 +26609,8 @@ function StandardActionsRegistrar({
|
|
|
26003
26609
|
const el = canvasRef.current;
|
|
26004
26610
|
return el ? { width: el.clientWidth, height: el.clientHeight } : null;
|
|
26005
26611
|
},
|
|
26006
|
-
viewAnimation
|
|
26612
|
+
viewAnimation,
|
|
26613
|
+
decayLoop
|
|
26007
26614
|
);
|
|
26008
26615
|
const sceneAsHistory = scene;
|
|
26009
26616
|
useStandardActions({ selection, scene, view, history: sceneAsHistory });
|
|
@@ -26463,8 +27070,7 @@ function MinimapCanvasInner(props) {
|
|
|
26463
27070
|
}, [mainView, mainViewDims, indicatorStyle]);
|
|
26464
27071
|
const extraCommands = useMemo(() => [indicatorCmd], [indicatorCmd]);
|
|
26465
27072
|
const localCanvasRef = useRef(null);
|
|
26466
|
-
const
|
|
26467
|
-
const capturedPointerIdRef = useRef(null);
|
|
27073
|
+
const sessionRef = useRef(null);
|
|
26468
27074
|
const mainViewRef = useRef(mainView);
|
|
26469
27075
|
const mainViewDimsRef = useRef(mainViewDims);
|
|
26470
27076
|
const onMainViewChangeRef = useRef(onMainViewChange);
|
|
@@ -26493,36 +27099,18 @@ function MinimapCanvasInner(props) {
|
|
|
26493
27099
|
}, []);
|
|
26494
27100
|
const handlePointerDown = useCallback((ev) => {
|
|
26495
27101
|
const canvas = localCanvasRef.current;
|
|
26496
|
-
if (!canvas) return;
|
|
27102
|
+
if (!canvas || sessionRef.current) return;
|
|
26497
27103
|
if (ev.pointerType === "mouse" && ev.button !== 0) return;
|
|
26498
|
-
|
|
26499
|
-
|
|
26500
|
-
}
|
|
26501
|
-
|
|
26502
|
-
|
|
26503
|
-
|
|
26504
|
-
|
|
26505
|
-
|
|
26506
|
-
const handlePointerMove = useCallback((ev) => {
|
|
26507
|
-
if (!dragActiveRef.current) return;
|
|
26508
|
-
if (capturedPointerIdRef.current !== null && ev.pointerId !== capturedPointerIdRef.current) {
|
|
26509
|
-
return;
|
|
26510
|
-
}
|
|
27104
|
+
const done = () => {
|
|
27105
|
+
sessionRef.current = null;
|
|
27106
|
+
};
|
|
27107
|
+
sessionRef.current = openPointerSession(canvas, ev, {
|
|
27108
|
+
onMove: recenterFromPointer,
|
|
27109
|
+
onEnd: done,
|
|
27110
|
+
onCancel: done
|
|
27111
|
+
});
|
|
26511
27112
|
recenterFromPointer(ev);
|
|
26512
27113
|
}, [recenterFromPointer]);
|
|
26513
|
-
const releaseCapture = useCallback((ev) => {
|
|
26514
|
-
const canvas = localCanvasRef.current;
|
|
26515
|
-
if (canvas) {
|
|
26516
|
-
try {
|
|
26517
|
-
if (canvas.hasPointerCapture?.(ev.pointerId)) {
|
|
26518
|
-
canvas.releasePointerCapture(ev.pointerId);
|
|
26519
|
-
}
|
|
26520
|
-
} catch {
|
|
26521
|
-
}
|
|
26522
|
-
}
|
|
26523
|
-
dragActiveRef.current = false;
|
|
26524
|
-
capturedPointerIdRef.current = null;
|
|
26525
|
-
}, []);
|
|
26526
27114
|
const setCanvasRef = useCallback((el) => {
|
|
26527
27115
|
localCanvasRef.current = el;
|
|
26528
27116
|
if (typeof canvasRef === "function") {
|
|
@@ -26535,16 +27123,11 @@ function MinimapCanvasInner(props) {
|
|
|
26535
27123
|
const canvas = localCanvasRef.current;
|
|
26536
27124
|
if (!canvas) return;
|
|
26537
27125
|
canvas.addEventListener("pointerdown", handlePointerDown);
|
|
26538
|
-
canvas.addEventListener("pointermove", handlePointerMove);
|
|
26539
|
-
canvas.addEventListener("pointerup", releaseCapture);
|
|
26540
|
-
canvas.addEventListener("pointercancel", releaseCapture);
|
|
26541
27126
|
return () => {
|
|
26542
27127
|
canvas.removeEventListener("pointerdown", handlePointerDown);
|
|
26543
|
-
|
|
26544
|
-
canvas.removeEventListener("pointerup", releaseCapture);
|
|
26545
|
-
canvas.removeEventListener("pointercancel", releaseCapture);
|
|
27128
|
+
sessionRef.current?.cancel();
|
|
26546
27129
|
};
|
|
26547
|
-
}, [handlePointerDown
|
|
27130
|
+
}, [handlePointerDown]);
|
|
26548
27131
|
return /* @__PURE__ */ jsx(
|
|
26549
27132
|
SceneViewCanvas,
|
|
26550
27133
|
{
|
|
@@ -30684,6 +31267,6 @@ function mergeContributions(...bundles) {
|
|
|
30684
31267
|
return out;
|
|
30685
31268
|
}
|
|
30686
31269
|
|
|
30687
|
-
export { ALWAYS, ANCHOR_HIT_BASE_PX, ActionsProviderIfRoot, ActiveToolContextProvider, ActiveToolContextProviderIfRoot, ArrowIcon, BUILTIN_MARKERS, BUNDLE_TOOLS, COARSE_TARGET_SCALE, CURVE_REPS, CanvasView, 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_MAX_ZOOM, DEFAULT_MIN_ZOOM, DEFAULT_PALETTE, DEFAULT_ROTATION_HANDLE_DISTANCE, DEFAULT_SHAPE_FILL, DEFAULT_STROKE_COLOR, DEFAULT_VELOCITY_DECAY, DepRegistryProviderIfRoot, DeviceProfileProvider, DivideIcon, EASINGS, EllipseIcon, ExcludeIcon, EyedropperIcon, FALLBACK_FIT_VIEW, GHOST_STROKE, HANDLE_BASE_PX, HandIcon, IDENTITY_COLOR_MATRIX, IDENTITY_JOINT, IDENTITY_POSE_COMPOSITION, ImageIcon, 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, TOOL_PREF_KINDS, TextIcon, UnionIcon, UnknownIcon, VERSION, VIEW_ANIMATION_KEY, WeaselProvider, WeaselRenderer, _resetMarkersForTests, _resetPaintKindsForTests, aabbCenter, actionIs, actionShortcuts, alignDeltaFor, alignInsertBehavior, alignMoveBehavior, alignResizeBehavior, always, and, animateLifecycle, animateOnSetPose, annulusSemiAxes, applyBooleanOp, applyStyleToRange, areaSelectAction, arrayAdapter, asNodeId, asPaint, axisAlignedBounds, bezierCubic, bezierQuadratic, blendPoses, 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, computeFitView, computeFitViewport, computeIndicatorCommand, computeWheelAction, cond, constrainTo45, containedThenNearest, countPathAnchors, createCellHighlightLayer, createChildrenLayer, createCornerResizeAffordance, createDebugOverlayLayer, createDebugSink, createDispatcher, createGridLayer, createGuidesLayer, createHistory2 as createHistory, createMoveToIndexOp, createNodeProperties, createNodeRouting, createParallaxLayer, createPathAnchorAffordances, createPathEditingOverlayLayer, createPathLayer, createPenPreviewLayer, createReorderOp, createRotationAffordance, createScene, createSelectionHandlesLayer, createSelectionOutlineLayer, createSelectionOverlayLayer, createSetDataOp, createSetLayerOp, createSetPathOp, createSetTextOp, createTextLayer, createViewResolver, createViewportLayer, cubicBezierEasing, cycleVertexColors, decomposePath, decomposeRectPose, defaultCommitAdapter, defaultDrawOne, defaultLabelTextRenderer, defaultNodeProperties, defaultNodeRouting, defaultVisibilityRules, defineTool, defineViewportTool, deriveAlignmentGuides, deriveParallaxView, describeRule, domPositionToCharOffset, domToRuns, drawLayers, drawOneLayer, 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, easeOutCubic, easeOutElastic, easeOutExpo, easeOutQuad, easeOutQuart, easeOutQuint, easeOutSine, editAnchorsAction, enterTextEditAction, enumerateAnchors, evaluate, fillInPoseFrame, fillToBoundsFrame, findNodeShape, findShapeInk, findShapeSilhouette, fitTextPose, fitToBounds, fitViewToBounds, fitZoom, focused, forEachCoalesced, frameRect, freeform, gateLayer, gesturing, getAlpha01, getImageBitmap, getMarker, getNodeShapes, getPaintKind, getStylusData, gradientForBounds, gradientGeometry, hexToRgba, hitAffordanceRegions, hitAnchor, hitRotationHandle, hostAnchorCss, hostAnchorRect, hovering, hoveringSelected, imageStatus, inferredNodeProperties, inferredNodeRouting, insertAction, interpolateView, isBuiltinToolPref, isEditableTarget2 as isEditableTarget, isGradientFill, isLayerPainted, isLayerVisible, isPatternSpec, keySpecShortcut, lassoSelectAction, lerpColorArray, lerpOklab, lerpOklch, linear, listMarkers, listPaintKinds, liveScope, makePinchZoomAction, makeViewportZoomAction, markerDrawCommands, markerInset, markerKeyOf, markerSites, mat3, matchAlignment, matchesKeyBinding, meanScale, mergeAlphaFromPrev, mergeContributions, modeIn, modeIs, modeNot, modifierHeld, momentum, moveAction, multiActive, nearest, nearestWithin, nestedHitTester, never, nodeHasFlag, none, normalizeHex, not, nurbs, oklabToOklch, oklabToSrgbU8, oklchToOklab, openFilePicker, or, paintAlpha, paintKindOf, paintWithAlpha, paintWithColor, 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, registerMarker, registerNodeShape, registerPaintKind, registerProgram, renderLabel, renderSceneToCanvas, renderSceneToPixels, resizeAction, resolveColor, resolveDeviceProfile, resolveEasing, resolveFillPattern, resolveMarkerSize, resolveParams, resolvePatternSpec, resolveSkeleton, resolveStrokeWidth, resolveVisibility, rgbaToHex, rotateAction, rotateAroundAABBCenter, rotatePathAround, rotatePoint, rotatedRectCorners, rotationDegreesUnit, rotationHandle, roundToCell, runsToDom, sampleGradientStops, sampleTrack, sceneFromJSON, sceneNodeClientRect, sceneSelectionStore, sceneToAdapter, scopeBindings, screenToWorld, selectFromLasso, selectionAtLeast, selectionEmpty, selectionIs, setFlagOverRange, shapeCoversPoint, sliceAction, snapPoint, solid, solidVertexColors, specificity, spiro, splitPathByLine, splitSubpaths, springPose, springVertexColors, srgbU8ToOklab, staggerVertexColors, startThresholdDrag, strokeInsets, strokeOf, strokeWith, styleAtRange, subscribeImageReady, tessellate, tessellateStroke, textCommand, textCommandFromRuns, tileGrid, toHex8, translatePoseViaDescriptor, translateRectPose, trimPolyline, tweenPose, tweenVertexColors, unionAABB, 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, useHostAnchor, useHoverTracking, useImageTool, useKeybindings, useLassoTool, useLineTool, useNodeOverlayFrame, 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, useVisibleRaf, useZoom, viewToMat3, viewToTransform, viewportDragPanAction, viewportZoomAction, viewportsAt, visualBoundsViaDescriptor, when, withAlpha01, withCoord, withGradientKind, worldEditToStorage, worldPoseLookup, worldToScreen, zoomAt, zoomAtLeast };
|
|
30688
|
-
//# sourceMappingURL=chunk-
|
|
30689
|
-
//# sourceMappingURL=chunk-
|
|
31270
|
+
export { ALWAYS, ANCHOR_HIT_BASE_PX, ActionsProviderIfRoot, ActiveToolContextProvider, ActiveToolContextProviderIfRoot, ArrowIcon, BUILTIN_MARKERS, BUNDLE_TOOLS, COARSE_TARGET_SCALE, CURVE_REPS, CanvasView, 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_MAX_ZOOM, DEFAULT_MIN_ZOOM, DEFAULT_PALETTE, DEFAULT_ROTATION_HANDLE_DISTANCE, DEFAULT_SHAPE_FILL, DEFAULT_STROKE_COLOR, DEFAULT_VELOCITY_DECAY, DepRegistryProviderIfRoot, DeviceProfileProvider, DivideIcon, EASINGS, EllipseIcon, ExcludeIcon, EyedropperIcon, FALLBACK_FIT_VIEW, GHOST_STROKE, HANDLE_BASE_PX, HandIcon, IDENTITY_COLOR_MATRIX, IDENTITY_JOINT, IDENTITY_POSE_COMPOSITION, ImageIcon, IntersectIcon, KIT_SHAPE_KINDS, LassoIcon, LineIcon, MIXED, MOVE_ANCHORS, MinimapCanvas, NEVER, OUTLINE_MIN_SCREEN_PX, PAINTED_CURSOR_LAYER_ID, PATH_ANCHOR_CHROME_ID, PenIcon, PencilIcon, PickHud, PointerProviderIfRoot, PolygonIcon, RECT_ALIGN_PROJECTION, ROTATION_HANDLE_BASE_PX, RectIcon, SPRING_PRESETS, SPRITE_STRIDE, SceneCanvas, SceneViewCanvas, SelectIcon, SelectionContextProvider, SelectionContextProviderIfRoot, ShaderCompileError, StarIcon, SubtractIcon, TOOL_PREF_KINDS, TextIcon, UnionIcon, UnknownIcon, VERSION, VIEW_ANIMATION_KEY, WeaselProvider, WeaselRenderer, _resetMarkersForTests, _resetPaintKindsForTests, aabbCenter, actionIs, actionShortcuts, alignDeltaFor, alignInsertBehavior, alignMoveBehavior, alignResizeBehavior, always, and, animateLifecycle, animateOnSetPose, annulusSemiAxes, applyBooleanOp, applyStyleToRange, areaSelectAction, arrayAdapter, asNodeId, asPaint, axisAlignedBounds, bezierCubic, bezierQuadratic, blendPoses, 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, computeFitView, computeFitViewport, computeIndicatorCommand, computeWheelAction, cond, constrainTo45, containedThenNearest, countPathAnchors, createCellHighlightLayer, createChildrenLayer, createCornerResizeAffordance, createDebugOverlayLayer, createDebugSink, createDispatcher, createGridLayer, createGuidesLayer, createHistory2 as createHistory, createMoveToIndexOp, createNodeProperties, createNodeRouting, createPaintedCursorLayer, createPaintedCursorState, createParallaxLayer, createPathAnchorAffordances, createPathEditingOverlayLayer, createPathLayer, createPenPreviewLayer, createReorderOp, createRotationAffordance, createScene, createSelectionHandlesLayer, createSelectionOutlineLayer, createSelectionOverlayLayer, createSetDataOp, createSetLayerOp, createSetPathOp, createSetTextOp, createTextLayer, createVelocityTracker, createViewResolver, createViewportLayer, cubicBezierEasing, cycleVertexColors, decomposePath, decomposeRectPose, defaultCommitAdapter, defaultDrawOne, defaultLabelTextRenderer, defaultNodeProperties, defaultNodeRouting, defaultVisibilityRules, defineTool, defineViewportTool, deriveAlignmentGuides, deriveParallaxView, describeRule, domPositionToCharOffset, domToRuns, drawLayers, drawOneLayer, 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, easeOutCubic, easeOutElastic, easeOutExpo, easeOutQuad, easeOutQuart, easeOutQuint, easeOutSine, editAnchorsAction, enterTextEditAction, enumerateAnchors, evaluate, fillInPoseFrame, fillToBoundsFrame, findNodeShape, findShapeInk, findShapeSilhouette, fitTextPose, fitToBounds, fitViewToBounds, fitZoom, focused, forEachCoalesced, frameRect, freeform, gateLayer, gesturing, getAlpha01, getImageBitmap, getMarker, getNodeShapes, getPaintKind, getStylusData, gradientForBounds, gradientGeometry, hexToRgba, hitAffordanceRegions, hitAnchor, hitRotationHandle, hostAnchorCss, hostAnchorRect, hovering, hoveringSelected, imageStatus, inferredNodeProperties, inferredNodeRouting, insertAction, interpolateView, isBuiltinToolPref, isEditableTarget2 as isEditableTarget, isGradientFill, isLayerPainted, isLayerVisible, isPatternSpec, keySpecShortcut, lassoSelectAction, lerpColorArray, lerpOklab, lerpOklch, linear, listMarkers, listPaintKinds, liveScope, makePinchZoomAction, makeViewportWheelPanAction, makeViewportZoomAction, markerDrawCommands, markerInset, markerKeyOf, markerSites, mat3, matchAlignment, matchesKeyBinding, meanScale, mergeAlphaFromPrev, mergeContributions, modeIn, modeIs, modeNot, modifierHeld, momentum, moveAction, multiActive, nearest, nearestWithin, nestedHitTester, never, nodeHasFlag, none, normalizeHex, not, nurbs, oklabToOklch, oklabToSrgbU8, oklchToOklab, openFilePicker, openPointerSession, or, paintAlpha, paintKindOf, paintWithAlpha, paintWithColor, 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, registerMarker, registerNodeShape, registerPaintKind, registerProgram, renderLabel, renderSceneToCanvas, renderSceneToPixels, resizeAction, resolveColor, resolveDeviceProfile, resolveEasing, resolveFillPattern, resolveMarkerSize, resolveParams, resolvePatternSpec, resolveSkeleton, resolveStrokeWidth, resolveVisibility, rgbaToHex, rotateAction, rotateAroundAABBCenter, rotatePathAround, rotatePoint, rotatedRectCorners, rotationDegreesUnit, rotationHandle, roundToCell, runsToDom, sampleGradientStops, sampleTrack, sceneFromJSON, sceneNodeClientRect, sceneSelectionStore, sceneToAdapter, scopeBindings, screenToWorld, selectFromLasso, selectionAtLeast, selectionEmpty, selectionIs, setFlagOverRange, shapeCoversPoint, sliceAction, snapPoint, solid, solidVertexColors, specificity, spiro, splitPathByLine, splitSubpaths, springPose, springVertexColors, srgbU8ToOklab, staggerVertexColors, startThresholdDrag, strokeInsets, strokeOf, strokeWith, styleAtRange, subscribeImageReady, tessellate, tessellateStroke, textCommand, textCommandFromRuns, tileGrid, toHex8, translatePoseViaDescriptor, translateRectPose, trimPolyline, tweenPose, tweenVertexColors, unionAABB, 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, useHostAnchor, useHoverTracking, useImageTool, useKeybindings, useLassoTool, useLineTool, useNodeOverlayFrame, 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, useVisibleRaf, useZoom, viewToMat3, viewToTransform, viewportDragPanAction, viewportWheelPanAction, viewportZoomAction, viewportsAt, visualBoundsViaDescriptor, when, withAlpha01, withCoord, withGradientKind, worldEditToStorage, worldPoseLookup, worldToScreen, zoomAt, zoomAtLeast };
|
|
31271
|
+
//# sourceMappingURL=chunk-NU7D64RL.js.map
|
|
31272
|
+
//# sourceMappingURL=chunk-NU7D64RL.js.map
|