@weasel-js/core 1.4.1 → 1.4.3
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 +428 -0
- package/dist/{DrawCommand-Ch8W63oQ.d.ts → DrawCommand-CD-ug3d9.d.ts} +45 -1
- package/dist/{stroke-Dq8nL4A2.d.ts → builtins-CtGORLCG.d.ts} +51 -2
- package/dist/{chunk-2KKYDDDD.js → chunk-4RJP2N2L.js} +43 -21
- package/dist/chunk-4RJP2N2L.js.map +1 -0
- package/dist/{chunk-MXFSHJOM.js → chunk-D4AAWR64.js} +4 -4
- package/dist/{chunk-MXFSHJOM.js.map → chunk-D4AAWR64.js.map} +1 -1
- package/dist/{chunk-ZB7UYJVG.js → chunk-DOBSZOPR.js} +3 -3
- package/dist/{chunk-ZB7UYJVG.js.map → chunk-DOBSZOPR.js.map} +1 -1
- package/dist/{chunk-TORKRNFY.js → chunk-LEURURX3.js} +68 -5
- package/dist/chunk-LEURURX3.js.map +1 -0
- package/dist/{chunk-Y5KS66G7.js → chunk-ORZNKVXM.js} +3 -3
- package/dist/{chunk-Y5KS66G7.js.map → chunk-ORZNKVXM.js.map} +1 -1
- package/dist/{chunk-67KE7SDP.js → chunk-T3UQ3F6R.js} +4 -4
- package/dist/{chunk-67KE7SDP.js.map → chunk-T3UQ3F6R.js.map} +1 -1
- package/dist/{chunk-NU7D64RL.js → chunk-WYPSGIYS.js} +1142 -595
- package/dist/chunk-WYPSGIYS.js.map +1 -0
- package/dist/clipboard.d.ts +2 -2
- package/dist/clipboard.js +3 -3
- package/dist/clone.d.ts +2 -2
- package/dist/clone.js +3 -3
- package/dist/{geometry-Dtt_k6Dq.d.ts → geometry-CHR36Ub_.d.ts} +3 -3
- package/dist/{grid-nnXU4VjN.d.ts → grid-Bw8cSde-.d.ts} +1 -1
- package/dist/index.d.ts +128 -237
- package/dist/index.js +7 -7
- package/dist/insert.d.ts +3 -3
- package/dist/move.d.ts +4 -4
- package/dist/move.js +2 -2
- package/dist/{options-CdFl510T.d.ts → options-DYfUlZxk.d.ts} +1 -1
- package/dist/{pointSnapToGrid-Dmthv94u.d.ts → pointSnapToGrid-D1bRdq-j.d.ts} +2 -2
- package/dist/{registry-BwY_DxJM.d.ts → registry-DnoTWGED.d.ts} +98 -8
- package/dist/renderer.d.ts +32 -4
- package/dist/renderer.js +7 -7
- package/dist/resize.d.ts +4 -4
- package/dist/routing.d.ts +6 -6
- package/dist/routing.js +1 -1
- package/dist/{types-miXHGrZM.d.ts → types-BJqsTlXl.d.ts} +1 -1
- package/dist/{types-XBcDEp3Y.d.ts → types-CoVTbo_y.d.ts} +9 -0
- package/dist/{types-DIQAisSG.d.ts → types-H7o6MaPo.d.ts} +20 -1
- package/package.json +9 -9
- package/dist/chunk-2KKYDDDD.js.map +0 -1
- package/dist/chunk-NU7D64RL.js.map +0 -1
- package/dist/chunk-TORKRNFY.js.map +0 -1
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import { ActionDisabledReason, useOptionalDepRegistry, DepRegistryProvider, useActionsRegistry, ActionsProvider, useDepRegistry, reportRouteConflicts, buildDepsFromRequires, useDepSource, actionBindings } from './chunk-
|
|
2
|
-
import { scratchKey, createTransformOp, snap, getScratch,
|
|
1
|
+
import { ActionDisabledReason, useOptionalDepRegistry, DepRegistryProvider, useActionsRegistry, ActionsScope, ActionsProvider, useDepRegistry, reportRouteConflicts, buildDepsFromRequires, useDepSource, actionBindings } from './chunk-LEURURX3.js';
|
|
2
|
+
import { scratchKey, createReparentOp, createTransformOp, snap, getScratch, setScratch } from './chunk-ORZNKVXM.js';
|
|
3
3
|
import { fixedCornerOf, DEFAULT_RESIZE_BEHAVIORS, CORNER_ANCHORS, cornerPoint } from './chunk-BLJNRMKB.js';
|
|
4
|
-
import { AUTO_POSE_DESCRIPTOR, resolveUnit, polylineFromPoints, starPath, regularPolygonPath, linePath, ellipsePath, rectPath, polygonFromPoints,
|
|
5
|
-
import { dispatchApplyBatch, dlog, dwarn, usePointerContext, PointerContextProvider,
|
|
6
|
-
import { createSetSelectionOp } from './chunk-
|
|
7
|
-
import { registerOpFactory,
|
|
4
|
+
import { AUTO_POSE_DESCRIPTOR, remapRotatedLeaf, PATH_Z, PATH_Q, PATH_C, PATH_L, PATH_M, resolveUnit, polylineFromPoints, starPath, regularPolygonPath, linePath, ellipsePath, rectPath, polygonFromPoints, RECT_POSE_DESCRIPTOR, PathBuilder, pathPoseDescriptor, withinPxRadius, boundsOfPath, DEFAULT_FLATTEN_TOLERANCE, flattenQuadratic, flattenCubic, pointInPath, strokeHitTest, transformPath, translatePath, pxExtent, withinPxBox, flattenCubicWithArcLen, flattenQuadraticWithArcLen, PATH_CMD_LENGTHS, pointToGridCell } from './chunk-SBFC6J3C.js';
|
|
5
|
+
import { dispatchApplyBatch, dlog, dwarn, usePointerContext, PointerContextProvider, extractWeaselClipboardFromSvg, parseWeaselClipboardText, materializePaste, WEASEL_CLIPBOARD_MIME, WEASEL_CLIPBOARD_MIME_WEB, sniffWeaselClipboardText, applyOpsTo } from './chunk-T3UQ3F6R.js';
|
|
6
|
+
import { createSetSelectionOp } from './chunk-DOBSZOPR.js';
|
|
7
|
+
import { registerOpFactory, createInsertOp, createDeleteOp, rebuildOp } from './chunk-4RJP2N2L.js';
|
|
8
8
|
import { getTexture, chunks, dots, crosshatch, hatch } from './chunk-BJN5ZRIJ.js';
|
|
9
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';
|
|
@@ -14,10 +14,10 @@ export { DEFAULT_TEXT_STYLE, MARKDOWN_RUN_GRAMMAR, SCRIPT_METRICS, cachedLayoutR
|
|
|
14
14
|
import earcut from 'earcut';
|
|
15
15
|
import { dashForStrokeStyle, strokeDashStyleOf, alignedStrokeRect } from '@weasel-js/paint';
|
|
16
16
|
export { STROKE_DASH_RATIOS, alignedStrokeRect, dashForStrokeStyle, strokeDashStyleOf } from '@weasel-js/paint';
|
|
17
|
-
import { clampRectWithin, applyToPoint, rotateAboutPoint,
|
|
17
|
+
import { boxToBox, clampRectWithin, applyToPoint, rotateAboutPoint, pointInPolygon, segmentsCross, forEachSegment, pathCommandCoordCount, multiply as multiply$1, invert as invert$1, pointSegmentDist2 } from '@weasel-js/geom';
|
|
18
18
|
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
19
19
|
import polygonClipping from 'polygon-clipping';
|
|
20
|
-
import { matchSpec, RESERVED_ID_PREFIXES, RESERVED_ID_NAMES, parseTargetSpec
|
|
20
|
+
import { mimeMatchesGlob, matchSpec, RESERVED_ID_PREFIXES, RESERVED_ID_NAMES, parseTargetSpec } from '@weasel-js/gestures';
|
|
21
21
|
import { NORMAL, IMPLICIT_TAGS } from '@weasel-js/modes';
|
|
22
22
|
import { GLYPHS, cursorWorldSize, cursorPaintOps, chromeLineWidthScale, cursorPaintMatrix, resolveCursorTier, cursorFor, resolveCursor } from '@weasel-js/cursor';
|
|
23
23
|
export { bakeCursor, cursorFor, resolveCursor, resolveCursorTier } from '@weasel-js/cursor';
|
|
@@ -25,7 +25,7 @@ import { createHistory } from '@weasel-js/history';
|
|
|
25
25
|
export * from '@weasel-js/history';
|
|
26
26
|
|
|
27
27
|
// src/version.ts
|
|
28
|
-
var VERSION = "1.4.
|
|
28
|
+
var VERSION = "1.4.3" ;
|
|
29
29
|
|
|
30
30
|
// src/features/grid/roundToCell.ts
|
|
31
31
|
function roundToCell(value, cellSize) {
|
|
@@ -1431,6 +1431,28 @@ var GroupState = class {
|
|
|
1431
1431
|
this.alphaStack.push(nextAlpha);
|
|
1432
1432
|
this.colorMatrixStack.push(nextCM);
|
|
1433
1433
|
}
|
|
1434
|
+
/**
|
|
1435
|
+
* Push a frame whose children paint into a surface of their own.
|
|
1436
|
+
*
|
|
1437
|
+
* The transform still accumulates — the children draw where they would have
|
|
1438
|
+
* drawn. Alpha and colour do not: they describe how the finished surface
|
|
1439
|
+
* joins the frame, and applying them on the way in as well would fade the
|
|
1440
|
+
* pixels an effect is about to read, then fade them again on the way out.
|
|
1441
|
+
*
|
|
1442
|
+
* Returns the pair the caller must apply at composite time — what `push`
|
|
1443
|
+
* would have left on the stack — so the composition rules live here and not
|
|
1444
|
+
* in the dispatcher.
|
|
1445
|
+
*/
|
|
1446
|
+
pushIsolated(frame) {
|
|
1447
|
+
this.push(frame);
|
|
1448
|
+
const composited = { alpha: this.alpha, colorMatrix: this.colorMatrix };
|
|
1449
|
+
this.pop();
|
|
1450
|
+
const current = this.transform;
|
|
1451
|
+
this.transformStack.push(frame.transform ? mat3.multiply(current, frame.transform) : current);
|
|
1452
|
+
this.alphaStack.push(1);
|
|
1453
|
+
this.colorMatrixStack.push(IDENTITY_COLOR_MATRIX);
|
|
1454
|
+
return composited;
|
|
1455
|
+
}
|
|
1434
1456
|
/** Drop every pushed frame, leaving the root. A frame that throws part-way
|
|
1435
1457
|
* down the tree never pops, and the next frame would draw under leftovers. */
|
|
1436
1458
|
reset() {
|
|
@@ -3495,6 +3517,63 @@ var ImageBatch = class {
|
|
|
3495
3517
|
}
|
|
3496
3518
|
};
|
|
3497
3519
|
|
|
3520
|
+
// src/renderer/shaders/registerProgram.ts
|
|
3521
|
+
var registry = /* @__PURE__ */ new Map();
|
|
3522
|
+
function getProgramSource(id) {
|
|
3523
|
+
return registry.get(id) ?? null;
|
|
3524
|
+
}
|
|
3525
|
+
var isDev = () => typeof process !== "undefined" ? process.env.NODE_ENV !== "production" : true;
|
|
3526
|
+
function registerProgram(id, vert, frag) {
|
|
3527
|
+
if (registry.has(id) && !isDev()) {
|
|
3528
|
+
throw new Error(`weasel registerProgram: duplicate program id "${id}". In production, re-registration is not allowed. Pass a unique id or call in dev mode.`);
|
|
3529
|
+
}
|
|
3530
|
+
registry.set(id, { vert, frag });
|
|
3531
|
+
return { id };
|
|
3532
|
+
}
|
|
3533
|
+
|
|
3534
|
+
// src/renderer/effects/effectPrelude.ts
|
|
3535
|
+
var EFFECT_VERT_SRC = (
|
|
3536
|
+
/* glsl */
|
|
3537
|
+
`#version 300 es
|
|
3538
|
+
in vec2 a_position;
|
|
3539
|
+
in vec2 a_uv;
|
|
3540
|
+
out vec2 v_uv;
|
|
3541
|
+
|
|
3542
|
+
void main() {
|
|
3543
|
+
v_uv = a_uv;
|
|
3544
|
+
gl_Position = vec4(a_position, 0.0, 1.0);
|
|
3545
|
+
}
|
|
3546
|
+
`
|
|
3547
|
+
);
|
|
3548
|
+
var EFFECT_KIT_UNIFORMS = ["u_source", "u_resolution", "u_texel"];
|
|
3549
|
+
var COMPOSITE_FRAG_SRC = (
|
|
3550
|
+
/* glsl */
|
|
3551
|
+
`#version 300 es
|
|
3552
|
+
precision highp float;
|
|
3553
|
+
in vec2 v_uv;
|
|
3554
|
+
uniform sampler2D u_source;
|
|
3555
|
+
uniform float u_alpha;
|
|
3556
|
+
uniform mat4 u_colorMatrix;
|
|
3557
|
+
uniform vec4 u_colorBias;
|
|
3558
|
+
out vec4 outColor;
|
|
3559
|
+
|
|
3560
|
+
void main() {
|
|
3561
|
+
vec4 src = texture(u_source, v_uv);
|
|
3562
|
+
// Undo premultiplication before the colour matrix, which is defined on
|
|
3563
|
+
// straight alpha, then put it back for the blend.
|
|
3564
|
+
float a = src.a;
|
|
3565
|
+
vec3 rgb = a > 0.0 ? src.rgb / a : vec3(0.0);
|
|
3566
|
+
vec4 c = u_colorMatrix * vec4(rgb, a) + u_colorBias;
|
|
3567
|
+
c.a *= u_alpha;
|
|
3568
|
+
outColor = vec4(clamp(c.rgb, 0.0, 1.0) * c.a, c.a);
|
|
3569
|
+
}
|
|
3570
|
+
`
|
|
3571
|
+
);
|
|
3572
|
+
|
|
3573
|
+
// src/renderer/effects/composite.ts
|
|
3574
|
+
var COMPOSITE_PROGRAM_ID = "weasel:effect-composite";
|
|
3575
|
+
registerProgram(COMPOSITE_PROGRAM_ID, EFFECT_VERT_SRC, COMPOSITE_FRAG_SRC);
|
|
3576
|
+
|
|
3498
3577
|
// src/renderer/draw.ts
|
|
3499
3578
|
var FRAME_UPLOADS = /* @__PURE__ */ new WeakMap();
|
|
3500
3579
|
var FRAME_PROJ = /* @__PURE__ */ new WeakMap();
|
|
@@ -3711,7 +3790,118 @@ function drawShader(ctx, cmd) {
|
|
|
3711
3790
|
gl.bindBuffer(gl.ARRAY_BUFFER, null);
|
|
3712
3791
|
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, null);
|
|
3713
3792
|
}
|
|
3793
|
+
function drawGroupWithEffects(ctx, cmd, targets, width, height) {
|
|
3794
|
+
const gl = ctx.gl;
|
|
3795
|
+
flushBatches(ctx);
|
|
3796
|
+
const parentTarget = ctx.renderTarget ?? null;
|
|
3797
|
+
const parentClipDepth = ctx.clipDepth;
|
|
3798
|
+
const scissorWasOn = gl.isEnabled(gl.SCISSOR_TEST);
|
|
3799
|
+
let front = targets.acquire(width, height);
|
|
3800
|
+
const composited = ctx.state.pushIsolated({ transform: cmd.transform });
|
|
3801
|
+
ctx.clipDepth = 0;
|
|
3802
|
+
gl.bindFramebuffer(gl.FRAMEBUFFER, front.fbo);
|
|
3803
|
+
ctx.renderTarget = front;
|
|
3804
|
+
gl.viewport(0, 0, width, height);
|
|
3805
|
+
gl.disable(gl.SCISSOR_TEST);
|
|
3806
|
+
gl.stencilMask(255);
|
|
3807
|
+
gl.clear(gl.COLOR_BUFFER_BIT | gl.STENCIL_BUFFER_BIT);
|
|
3808
|
+
for (const child of cmd.children) dispatch(ctx, child);
|
|
3809
|
+
flushBatches(ctx);
|
|
3810
|
+
gl.disable(gl.BLEND);
|
|
3811
|
+
for (const effect of cmd.effects) {
|
|
3812
|
+
const program = ctx.ensureProgram?.(effect.program.id) ?? null;
|
|
3813
|
+
if (!program) {
|
|
3814
|
+
warnOnceUniform(effect.program.id, "(program)");
|
|
3815
|
+
continue;
|
|
3816
|
+
}
|
|
3817
|
+
const back = targets.acquire(width, height);
|
|
3818
|
+
gl.bindFramebuffer(gl.FRAMEBUFFER, back.fbo);
|
|
3819
|
+
gl.viewport(0, 0, width, height);
|
|
3820
|
+
gl.clear(gl.COLOR_BUFFER_BIT);
|
|
3821
|
+
drawFullscreenQuad(
|
|
3822
|
+
ctx,
|
|
3823
|
+
program,
|
|
3824
|
+
front.texture,
|
|
3825
|
+
width,
|
|
3826
|
+
height,
|
|
3827
|
+
effect.uniforms,
|
|
3828
|
+
void 0,
|
|
3829
|
+
effect.program.id
|
|
3830
|
+
);
|
|
3831
|
+
targets.release(front);
|
|
3832
|
+
front = back;
|
|
3833
|
+
}
|
|
3834
|
+
gl.enable(gl.BLEND);
|
|
3835
|
+
ctx.state.pop();
|
|
3836
|
+
ctx.clipDepth = parentClipDepth;
|
|
3837
|
+
ctx.renderTarget = parentTarget;
|
|
3838
|
+
gl.bindFramebuffer(gl.FRAMEBUFFER, parentTarget ? parentTarget.fbo : null);
|
|
3839
|
+
if (parentTarget) {
|
|
3840
|
+
gl.viewport(0, 0, width, height);
|
|
3841
|
+
} else {
|
|
3842
|
+
ctx.restoreTargetRect?.();
|
|
3843
|
+
if (scissorWasOn) gl.enable(gl.SCISSOR_TEST);
|
|
3844
|
+
}
|
|
3845
|
+
const composite = ctx.ensureProgram?.(COMPOSITE_PROGRAM_ID) ?? null;
|
|
3846
|
+
if (composite) {
|
|
3847
|
+
applyClipTest(ctx);
|
|
3848
|
+
drawFullscreenQuad(ctx, composite, front.texture, width, height, void 0, {
|
|
3849
|
+
alpha: composited.alpha,
|
|
3850
|
+
colorMatrix: composited.colorMatrix
|
|
3851
|
+
});
|
|
3852
|
+
}
|
|
3853
|
+
targets.release(front);
|
|
3854
|
+
}
|
|
3855
|
+
function drawFullscreenQuad(ctx, program, texture, width, height, uniforms, composite, programId) {
|
|
3856
|
+
const gl = ctx.gl;
|
|
3857
|
+
gl.useProgram(program.handle);
|
|
3858
|
+
const aPos = program.attribute("a_position");
|
|
3859
|
+
const aUv = program.attribute("a_uv");
|
|
3860
|
+
gl.bindBuffer(gl.ARRAY_BUFFER, ctx.quadVbo);
|
|
3861
|
+
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, ctx.quadIbo);
|
|
3862
|
+
if (aPos !== void 0 && aPos >= 0) {
|
|
3863
|
+
gl.enableVertexAttribArray(aPos);
|
|
3864
|
+
gl.vertexAttribPointer(aPos, 2, gl.FLOAT, false, 16, 0);
|
|
3865
|
+
}
|
|
3866
|
+
if (aUv !== void 0 && aUv >= 0) {
|
|
3867
|
+
gl.enableVertexAttribArray(aUv);
|
|
3868
|
+
gl.vertexAttribPointer(aUv, 2, gl.FLOAT, false, 16, 8);
|
|
3869
|
+
}
|
|
3870
|
+
gl.activeTexture(gl.TEXTURE0);
|
|
3871
|
+
gl.bindTexture(gl.TEXTURE_2D, texture);
|
|
3872
|
+
const source = program.uniform("u_source");
|
|
3873
|
+
if (source !== void 0) gl.uniform1i(source, 0);
|
|
3874
|
+
const resolution = program.uniform("u_resolution");
|
|
3875
|
+
if (resolution !== void 0) gl.uniform2f(resolution, width, height);
|
|
3876
|
+
const texel = program.uniform("u_texel");
|
|
3877
|
+
if (texel !== void 0) gl.uniform2f(texel, 1 / width, 1 / height);
|
|
3878
|
+
if (composite) {
|
|
3879
|
+
const alpha = program.uniform("u_alpha");
|
|
3880
|
+
if (alpha !== void 0) gl.uniform1f(alpha, composite.alpha);
|
|
3881
|
+
setColorMatrixUniforms(ctx, program, composite.colorMatrix);
|
|
3882
|
+
}
|
|
3883
|
+
if (uniforms) {
|
|
3884
|
+
const nextTexUnit = { value: 1 };
|
|
3885
|
+
for (const [name, value] of Object.entries(uniforms)) {
|
|
3886
|
+
const loc = program.uniform(name);
|
|
3887
|
+
if (loc === void 0) {
|
|
3888
|
+
warnOnceUniform(programId ?? "effect", name);
|
|
3889
|
+
continue;
|
|
3890
|
+
}
|
|
3891
|
+
setUniform(gl, loc, value, ctx.textureCache, nextTexUnit);
|
|
3892
|
+
}
|
|
3893
|
+
}
|
|
3894
|
+
gl.drawElements(gl.TRIANGLES, 6, gl.UNSIGNED_SHORT, 0);
|
|
3895
|
+
if (aPos !== void 0 && aPos >= 0) gl.disableVertexAttribArray(aPos);
|
|
3896
|
+
if (aUv !== void 0 && aUv >= 0) gl.disableVertexAttribArray(aUv);
|
|
3897
|
+
gl.bindBuffer(gl.ARRAY_BUFFER, null);
|
|
3898
|
+
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, null);
|
|
3899
|
+
}
|
|
3714
3900
|
function drawGroup(ctx, cmd) {
|
|
3901
|
+
if (cmd.effects && cmd.effects.length > 0 && ctx.effectTargets && ctx.deviceWidth && ctx.deviceHeight) {
|
|
3902
|
+
drawGroupWithEffects(ctx, cmd, ctx.effectTargets, ctx.deviceWidth, ctx.deviceHeight);
|
|
3903
|
+
return;
|
|
3904
|
+
}
|
|
3715
3905
|
ctx.state.push({
|
|
3716
3906
|
transform: cmd.transform,
|
|
3717
3907
|
alpha: cmd.alpha,
|
|
@@ -3737,7 +3927,7 @@ function drawGroup(ctx, cmd) {
|
|
|
3737
3927
|
}
|
|
3738
3928
|
function drawPath(ctx, cmd) {
|
|
3739
3929
|
if (cmd.fill) drawPathFill(ctx, cmd);
|
|
3740
|
-
if (cmd.stroke) drawPathStroke(ctx, cmd);
|
|
3930
|
+
if (cmd.stroke?.paint) drawPathStroke(ctx, cmd);
|
|
3741
3931
|
}
|
|
3742
3932
|
function drawPathFill(ctx, cmd) {
|
|
3743
3933
|
const fill = cmd.fill;
|
|
@@ -4329,12 +4519,16 @@ function drawText(ctx, cmd) {
|
|
|
4329
4519
|
}
|
|
4330
4520
|
var SYNTHETIC_ITALIC_RADIANS = 0.2094;
|
|
4331
4521
|
function drawTextOutlineGroup(ctx, group, dx, dy) {
|
|
4332
|
-
const
|
|
4333
|
-
if (
|
|
4334
|
-
|
|
4522
|
+
const fill = group.fill;
|
|
4523
|
+
if (fill !== null) {
|
|
4524
|
+
const mesh = outlineGroupMesh(group, dx, dy);
|
|
4525
|
+
if (mesh) drawPathFillByKind(ctx, fill, ctx.meshCache.uploadTransient(mesh));
|
|
4526
|
+
}
|
|
4527
|
+
const strokePaint = group.stroke?.paint;
|
|
4528
|
+
if (!strokePaint) return;
|
|
4335
4529
|
const ribbon = outlineGroupStrokeMesh(group, dx, dy, mat3.meanScaleOf(ctx.state.transform));
|
|
4336
4530
|
if (ribbon) {
|
|
4337
|
-
drawPathFillByKind(ctx,
|
|
4531
|
+
drawPathFillByKind(ctx, strokePaint, ctx.meshCache.uploadTransient(ribbon));
|
|
4338
4532
|
}
|
|
4339
4533
|
}
|
|
4340
4534
|
function outlineGroupMesh(group, dx, dy) {
|
|
@@ -4485,7 +4679,7 @@ function drawTextGroup(ctx, group, prog, dx, dy) {
|
|
|
4485
4679
|
ensureQuadIndices(gl, ring, group.quads.length);
|
|
4486
4680
|
bindTextQuadSlot(gl, ring, vertices.subarray(0, floats));
|
|
4487
4681
|
let r = 0, g = 0, b = 0, a = 1;
|
|
4488
|
-
if ("color" in group.fill) {
|
|
4682
|
+
if (group.fill !== null && "color" in group.fill) {
|
|
4489
4683
|
[r, g, b, a] = resolveColor(group.fill.color);
|
|
4490
4684
|
}
|
|
4491
4685
|
setColorUniform(ctx, prog, r, g, b, a);
|
|
@@ -4699,19 +4893,79 @@ var QUAD_VERTICES = new Float32Array([
|
|
|
4699
4893
|
]);
|
|
4700
4894
|
var QUAD_INDICES = new Uint16Array([0, 1, 2, 0, 2, 3]);
|
|
4701
4895
|
|
|
4702
|
-
// src/renderer/
|
|
4703
|
-
var
|
|
4704
|
-
|
|
4705
|
-
|
|
4706
|
-
|
|
4707
|
-
|
|
4708
|
-
|
|
4709
|
-
|
|
4710
|
-
|
|
4896
|
+
// src/renderer/effects/EffectTargets.ts
|
|
4897
|
+
var EffectTargets = class {
|
|
4898
|
+
gl;
|
|
4899
|
+
all = [];
|
|
4900
|
+
free = [];
|
|
4901
|
+
width = 0;
|
|
4902
|
+
height = 0;
|
|
4903
|
+
constructor(gl) {
|
|
4904
|
+
this.gl = gl;
|
|
4711
4905
|
}
|
|
4712
|
-
|
|
4713
|
-
|
|
4714
|
-
|
|
4906
|
+
/** True once anything has been allocated — what a test asks instead of
|
|
4907
|
+
* reaching for the private arrays. */
|
|
4908
|
+
get allocated() {
|
|
4909
|
+
return this.all.length > 0;
|
|
4910
|
+
}
|
|
4911
|
+
/**
|
|
4912
|
+
* Borrow a target sized `width` × `height` device pixels. A size change
|
|
4913
|
+
* drops every pooled buffer rather than resizing in place: a borrowed one
|
|
4914
|
+
* cannot be resized under its holder, and a resize is not a per-frame event.
|
|
4915
|
+
*/
|
|
4916
|
+
acquire(width, height) {
|
|
4917
|
+
if (width !== this.width || height !== this.height) {
|
|
4918
|
+
this.free = [];
|
|
4919
|
+
this.releaseAll();
|
|
4920
|
+
this.width = width;
|
|
4921
|
+
this.height = height;
|
|
4922
|
+
}
|
|
4923
|
+
const pooled = this.free.pop();
|
|
4924
|
+
if (pooled) return pooled;
|
|
4925
|
+
const made = this.create(width, height);
|
|
4926
|
+
this.all.push(made);
|
|
4927
|
+
return made;
|
|
4928
|
+
}
|
|
4929
|
+
/** Hand one back. Order does not matter — every target is interchangeable. */
|
|
4930
|
+
release(target) {
|
|
4931
|
+
this.free.push(target);
|
|
4932
|
+
}
|
|
4933
|
+
/** Drop every buffer. Called on dispose and on context loss, where the
|
|
4934
|
+
* handles are already invalid and only the bookkeeping has to go. */
|
|
4935
|
+
releaseAll() {
|
|
4936
|
+
const gl = this.gl;
|
|
4937
|
+
for (const t of this.all) {
|
|
4938
|
+
gl.deleteFramebuffer(t.fbo);
|
|
4939
|
+
gl.deleteTexture(t.texture);
|
|
4940
|
+
gl.deleteRenderbuffer(t.stencil);
|
|
4941
|
+
}
|
|
4942
|
+
this.all.length = 0;
|
|
4943
|
+
this.free = [];
|
|
4944
|
+
this.width = 0;
|
|
4945
|
+
this.height = 0;
|
|
4946
|
+
}
|
|
4947
|
+
create(width, height) {
|
|
4948
|
+
const gl = this.gl;
|
|
4949
|
+
const texture = gl.createTexture();
|
|
4950
|
+
gl.bindTexture(gl.TEXTURE_2D, texture);
|
|
4951
|
+
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA8, width, height, 0, gl.RGBA, gl.UNSIGNED_BYTE, null);
|
|
4952
|
+
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
|
|
4953
|
+
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
|
|
4954
|
+
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
|
|
4955
|
+
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
|
|
4956
|
+
gl.bindTexture(gl.TEXTURE_2D, null);
|
|
4957
|
+
const stencil = gl.createRenderbuffer();
|
|
4958
|
+
gl.bindRenderbuffer(gl.RENDERBUFFER, stencil);
|
|
4959
|
+
gl.renderbufferStorage(gl.RENDERBUFFER, gl.DEPTH24_STENCIL8, width, height);
|
|
4960
|
+
gl.bindRenderbuffer(gl.RENDERBUFFER, null);
|
|
4961
|
+
const fbo = gl.createFramebuffer();
|
|
4962
|
+
gl.bindFramebuffer(gl.FRAMEBUFFER, fbo);
|
|
4963
|
+
gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, texture, 0);
|
|
4964
|
+
gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.DEPTH_STENCIL_ATTACHMENT, gl.RENDERBUFFER, stencil);
|
|
4965
|
+
gl.bindFramebuffer(gl.FRAMEBUFFER, null);
|
|
4966
|
+
return { fbo, texture, stencil };
|
|
4967
|
+
}
|
|
4968
|
+
};
|
|
4715
4969
|
|
|
4716
4970
|
// src/renderer/WeaselRenderer.ts
|
|
4717
4971
|
var UNIFORM_QUALIFIER = /^(?:lowp|mediump|highp|precise|invariant|centroid|flat|smooth|noperspective)$/;
|
|
@@ -4764,6 +5018,9 @@ var WeaselRenderer = class {
|
|
|
4764
5018
|
dpr;
|
|
4765
5019
|
canvas = null;
|
|
4766
5020
|
target = null;
|
|
5021
|
+
/** Offscreen buffers for group effects. Allocates nothing until a group
|
|
5022
|
+
* with effects asks, so a canvas without them pays no memory. */
|
|
5023
|
+
effectTargets;
|
|
4767
5024
|
imageMinification;
|
|
4768
5025
|
flattenTolerance;
|
|
4769
5026
|
bakeBudget;
|
|
@@ -4781,6 +5038,7 @@ var WeaselRenderer = class {
|
|
|
4781
5038
|
const gl = opts.gl ?? opts.canvas.getContext("webgl2", { stencil: true });
|
|
4782
5039
|
if (!gl) throw new Error("WeaselRenderer: WebGL2 not available");
|
|
4783
5040
|
this.gl = gl;
|
|
5041
|
+
this.effectTargets = new EffectTargets(this.gl);
|
|
4784
5042
|
const attrs = typeof this.gl.getContextAttributes === "function" ? this.gl.getContextAttributes() : null;
|
|
4785
5043
|
if (attrs && attrs.stencil === false) {
|
|
4786
5044
|
throw new Error(
|
|
@@ -4952,6 +5210,7 @@ var WeaselRenderer = class {
|
|
|
4952
5210
|
this.contextLost = false;
|
|
4953
5211
|
this.applyGlState();
|
|
4954
5212
|
this.applyTarget();
|
|
5213
|
+
this.effectTargets.releaseAll();
|
|
4955
5214
|
this.pathFill = new ShaderProgram(this.gl, VERT_SRC, FRAG_SRC);
|
|
4956
5215
|
this.pathFill.lookupUniforms(PATH_FILL_UNIFORMS);
|
|
4957
5216
|
this.pathFill.lookupAttributes(PATH_FILL_ATTRIBUTES);
|
|
@@ -5052,6 +5311,7 @@ var WeaselRenderer = class {
|
|
|
5052
5311
|
for (const prog of [this.textSdf, this.textSdfR8, this.pathFill]) disposeTextQuads(gl, prog);
|
|
5053
5312
|
this.solidBatch.dispose();
|
|
5054
5313
|
this.imageBatch.dispose();
|
|
5314
|
+
this.effectTargets.releaseAll();
|
|
5055
5315
|
}
|
|
5056
5316
|
/**
|
|
5057
5317
|
* Draw one frame.
|
|
@@ -5099,7 +5359,12 @@ var WeaselRenderer = class {
|
|
|
5099
5359
|
clipDepth: 0,
|
|
5100
5360
|
flattenTolerance: this.flattenTolerance,
|
|
5101
5361
|
textOutlineMinScreenSize: this.textOutlineMinScreenSize,
|
|
5102
|
-
viewMatrix: viewMatrix2
|
|
5362
|
+
viewMatrix: viewMatrix2,
|
|
5363
|
+
effectTargets: this.effectTargets,
|
|
5364
|
+
renderTarget: null,
|
|
5365
|
+
deviceWidth: Math.round(this.widthCss * this.dpr),
|
|
5366
|
+
deviceHeight: Math.round(this.heightCss * this.dpr),
|
|
5367
|
+
restoreTargetRect: () => this.applyTarget()
|
|
5103
5368
|
};
|
|
5104
5369
|
for (const cmd of commands) dispatch(ctx, cmd);
|
|
5105
5370
|
flushBatches(ctx);
|
|
@@ -5231,6 +5496,71 @@ function viewToMat3(view) {
|
|
|
5231
5496
|
]);
|
|
5232
5497
|
}
|
|
5233
5498
|
|
|
5499
|
+
// src/renderer/effects/types.ts
|
|
5500
|
+
function registerEffect(id, frag) {
|
|
5501
|
+
return registerProgram(id, EFFECT_VERT_SRC, frag);
|
|
5502
|
+
}
|
|
5503
|
+
|
|
5504
|
+
// src/renderer/effects/builtins.ts
|
|
5505
|
+
var BLUR_FRAG = (
|
|
5506
|
+
/* glsl */
|
|
5507
|
+
`#version 300 es
|
|
5508
|
+
precision highp float;
|
|
5509
|
+
in vec2 v_uv;
|
|
5510
|
+
uniform sampler2D u_source;
|
|
5511
|
+
uniform vec2 u_texel;
|
|
5512
|
+
uniform vec2 u_direction;
|
|
5513
|
+
uniform float u_radius;
|
|
5514
|
+
out vec4 outColor;
|
|
5515
|
+
|
|
5516
|
+
void main() {
|
|
5517
|
+
// Nine taps on a Gaussian, spread across the requested radius. The weights
|
|
5518
|
+
// are a normalized binomial row, so a radius of 0 collapses to a copy.
|
|
5519
|
+
const float W[5] = float[5](0.2270270, 0.1945946, 0.1216216, 0.0540541, 0.0162162);
|
|
5520
|
+
vec2 step = u_direction * u_texel * (u_radius / 4.0);
|
|
5521
|
+
vec4 sum = texture(u_source, v_uv) * W[0];
|
|
5522
|
+
for (int i = 1; i < 5; i++) {
|
|
5523
|
+
vec2 off = step * float(i);
|
|
5524
|
+
sum += texture(u_source, v_uv + off) * W[i];
|
|
5525
|
+
sum += texture(u_source, v_uv - off) * W[i];
|
|
5526
|
+
}
|
|
5527
|
+
outColor = sum;
|
|
5528
|
+
}
|
|
5529
|
+
`
|
|
5530
|
+
);
|
|
5531
|
+
var VIGNETTE_FRAG = (
|
|
5532
|
+
/* glsl */
|
|
5533
|
+
`#version 300 es
|
|
5534
|
+
precision highp float;
|
|
5535
|
+
in vec2 v_uv;
|
|
5536
|
+
uniform sampler2D u_source;
|
|
5537
|
+
uniform float u_amount;
|
|
5538
|
+
uniform float u_feather;
|
|
5539
|
+
out vec4 outColor;
|
|
5540
|
+
|
|
5541
|
+
void main() {
|
|
5542
|
+
vec4 src = texture(u_source, v_uv);
|
|
5543
|
+
float d = distance(v_uv, vec2(0.5)) * 1.41421356;
|
|
5544
|
+
float shade = 1.0 - u_amount * smoothstep(1.0 - u_feather, 1.0, d);
|
|
5545
|
+
// Premultiplied in, premultiplied out: scaling all four channels darkens
|
|
5546
|
+
// toward transparent black, which is what a vignette over a transparent
|
|
5547
|
+
// canvas should do.
|
|
5548
|
+
outColor = src * shade;
|
|
5549
|
+
}
|
|
5550
|
+
`
|
|
5551
|
+
);
|
|
5552
|
+
var BLUR = registerEffect("weasel:blur", BLUR_FRAG);
|
|
5553
|
+
var VIGNETTE = registerEffect("weasel:vignette", VIGNETTE_FRAG);
|
|
5554
|
+
function blur({ radius }) {
|
|
5555
|
+
return [
|
|
5556
|
+
{ program: BLUR, uniforms: { u_direction: [1, 0], u_radius: radius } },
|
|
5557
|
+
{ program: BLUR, uniforms: { u_direction: [0, 1], u_radius: radius } }
|
|
5558
|
+
];
|
|
5559
|
+
}
|
|
5560
|
+
function vignette({ amount, feather = 0.6 }) {
|
|
5561
|
+
return [{ program: VIGNETTE, uniforms: { u_amount: amount, u_feather: feather } }];
|
|
5562
|
+
}
|
|
5563
|
+
|
|
5234
5564
|
// src/core/viewport/meanScale.ts
|
|
5235
5565
|
function meanScale(s) {
|
|
5236
5566
|
return Math.sqrt(s.x * s.y);
|
|
@@ -5348,7 +5678,13 @@ function createCellHighlightLayer(opts) {
|
|
|
5348
5678
|
|
|
5349
5679
|
// src/core/layers/render.ts
|
|
5350
5680
|
var IDENTITY_VIEW = { x: 0, y: 0, scale: { x: 1, y: 1 } };
|
|
5351
|
-
function
|
|
5681
|
+
function reportLayerFailure({ layerId, error }) {
|
|
5682
|
+
console.error(
|
|
5683
|
+
`[weasel] layer "${layerId}" threw while drawing; it painted nothing this frame.`,
|
|
5684
|
+
error
|
|
5685
|
+
);
|
|
5686
|
+
}
|
|
5687
|
+
function drawLayers(layers, data, visibility, order, view, dims, cache7, onLayerError = reportLayerFailure, groups) {
|
|
5352
5688
|
const layerById = new Map(layers.map((l) => [l.id, l]));
|
|
5353
5689
|
const sequence = order ? order.map((id) => layerById.get(id)).filter((l) => l !== void 0) : layers;
|
|
5354
5690
|
const v = view ?? IDENTITY_VIEW;
|
|
@@ -5358,12 +5694,67 @@ function drawLayers(layers, data, visibility, order, view, dims, cache7) {
|
|
|
5358
5694
|
if (!layerById.has(id)) cache7.delete(id);
|
|
5359
5695
|
}
|
|
5360
5696
|
}
|
|
5697
|
+
const groupOf = groupMembership(groups);
|
|
5698
|
+
const bracketed = /* @__PURE__ */ new Set();
|
|
5699
|
+
let run = null;
|
|
5700
|
+
const closeRun = () => {
|
|
5701
|
+
if (!run) return;
|
|
5702
|
+
for (const c of wrapGroup(run.group, run.children, v, dims)) out.push(c);
|
|
5703
|
+
run = null;
|
|
5704
|
+
};
|
|
5361
5705
|
for (const layer of sequence) {
|
|
5362
5706
|
if (!isLayerVisible(layer, visibility)) continue;
|
|
5363
|
-
|
|
5707
|
+
const cmds = drawOneLayer(layer, data, v, dims, cache7, onLayerError);
|
|
5708
|
+
if (cmds.length === 0) continue;
|
|
5709
|
+
const group = groupOf?.get(layer.id);
|
|
5710
|
+
if (run && run.group !== group) closeRun();
|
|
5711
|
+
if (!group) {
|
|
5712
|
+
for (const c of cmds) out.push(c);
|
|
5713
|
+
continue;
|
|
5714
|
+
}
|
|
5715
|
+
if (!run) {
|
|
5716
|
+
if (bracketed.has(group)) {
|
|
5717
|
+
console.warn(
|
|
5718
|
+
`[weasel] layer group "${group.id}" is not one run \u2014 another layer is drawn between its members, so it composites as more than one pass over more than one buffer. Move its members together in the layer order.`
|
|
5719
|
+
);
|
|
5720
|
+
}
|
|
5721
|
+
bracketed.add(group);
|
|
5722
|
+
run = { group, children: [] };
|
|
5723
|
+
}
|
|
5724
|
+
for (const c of cmds) run.children.push(c);
|
|
5364
5725
|
}
|
|
5726
|
+
closeRun();
|
|
5365
5727
|
return out;
|
|
5366
5728
|
}
|
|
5729
|
+
function groupMembership(groups) {
|
|
5730
|
+
if (!groups || groups.length === 0) return null;
|
|
5731
|
+
const byLayer = /* @__PURE__ */ new Map();
|
|
5732
|
+
for (const group of groups) {
|
|
5733
|
+
for (const id of group.layers) {
|
|
5734
|
+
const claimed = byLayer.get(id);
|
|
5735
|
+
if (claimed) {
|
|
5736
|
+
console.warn(
|
|
5737
|
+
`[weasel] layer "${id}" is claimed by layer groups "${claimed.id}" and "${group.id}"; it stays in "${claimed.id}".`
|
|
5738
|
+
);
|
|
5739
|
+
continue;
|
|
5740
|
+
}
|
|
5741
|
+
byLayer.set(id, group);
|
|
5742
|
+
}
|
|
5743
|
+
}
|
|
5744
|
+
return byLayer;
|
|
5745
|
+
}
|
|
5746
|
+
function wrapGroup(group, children, view, dims) {
|
|
5747
|
+
const declared = typeof group.effects === "function" ? group.effects(view, dims) : group.effects;
|
|
5748
|
+
const effects = declared && declared.length > 0 ? declared : void 0;
|
|
5749
|
+
if (!effects && group.alpha === void 0 && group.colorMatrix === void 0) return children;
|
|
5750
|
+
return [{
|
|
5751
|
+
kind: "group",
|
|
5752
|
+
...effects ? { effects } : {},
|
|
5753
|
+
...group.alpha !== void 0 ? { alpha: group.alpha } : {},
|
|
5754
|
+
...group.colorMatrix !== void 0 ? { colorMatrix: group.colorMatrix } : {},
|
|
5755
|
+
children
|
|
5756
|
+
}];
|
|
5757
|
+
}
|
|
5367
5758
|
function isLayerVisible(layer, visibility) {
|
|
5368
5759
|
if (layer.alwaysOn) return true;
|
|
5369
5760
|
if (layer.id in visibility) return visibility[layer.id];
|
|
@@ -5373,11 +5764,21 @@ function isLayerPainted(layer, visibility, order) {
|
|
|
5373
5764
|
if (order && !order.includes(layer.id)) return false;
|
|
5374
5765
|
return isLayerVisible(layer, visibility);
|
|
5375
5766
|
}
|
|
5376
|
-
function drawOneLayer(layer, data, view, dims, cache7) {
|
|
5377
|
-
|
|
5767
|
+
function drawOneLayer(layer, data, view, dims, cache7, onLayerError = reportLayerFailure) {
|
|
5768
|
+
let cmds;
|
|
5769
|
+
try {
|
|
5770
|
+
cmds = layerCommands(layer, data, view, dims, cache7);
|
|
5771
|
+
} catch (error) {
|
|
5772
|
+
cache7?.delete(layer.id);
|
|
5773
|
+
onLayerError({ layerId: layer.id, error });
|
|
5774
|
+
return [];
|
|
5775
|
+
}
|
|
5378
5776
|
if (cmds.length === 0) return [];
|
|
5379
|
-
|
|
5380
|
-
|
|
5777
|
+
const effects = layer.effects && layer.effects.length > 0 ? layer.effects : void 0;
|
|
5778
|
+
if ((layer.space ?? "world") === "screen") {
|
|
5779
|
+
return effects ? [{ kind: "group", effects, children: cmds }] : cmds;
|
|
5780
|
+
}
|
|
5781
|
+
return [{ kind: "group", transform: viewToMat3(view), ...effects ? { effects } : {}, children: cmds }];
|
|
5381
5782
|
}
|
|
5382
5783
|
function layerCommands(layer, data, view, dims, cache7) {
|
|
5383
5784
|
if (!cache7 || !layer.deps) return layer.draw(data, view, dims);
|
|
@@ -5535,7 +5936,7 @@ function createParallaxLayer(opts) {
|
|
|
5535
5936
|
space: "screen",
|
|
5536
5937
|
draw: (data, outer, dims) => {
|
|
5537
5938
|
const inner = deriveParallaxView(getOuterView?.() ?? outer, { pan, zoom, anchor });
|
|
5538
|
-
return source.flatMap((layer) => layer
|
|
5939
|
+
return source.flatMap((layer) => drawOneLayer(layer, data, inner, dims));
|
|
5539
5940
|
}
|
|
5540
5941
|
};
|
|
5541
5942
|
}
|
|
@@ -6204,7 +6605,7 @@ function clientToCanvasRect(rect, clientX, clientY) {
|
|
|
6204
6605
|
return [clientX - rect.left, clientY - rect.top];
|
|
6205
6606
|
}
|
|
6206
6607
|
|
|
6207
|
-
// src/interactions/gestures/pointerSession/
|
|
6608
|
+
// src/interactions/gestures/pointerSession/pointerSession.ts
|
|
6208
6609
|
var LOST_CAPTURE_EVENT = "lostpointercapture";
|
|
6209
6610
|
function reportsButtons(down) {
|
|
6210
6611
|
return !!down.buttons;
|
|
@@ -6212,8 +6613,6 @@ function reportsButtons(down) {
|
|
|
6212
6613
|
function isMissedRelease(move) {
|
|
6213
6614
|
return move.buttons === 0;
|
|
6214
6615
|
}
|
|
6215
|
-
|
|
6216
|
-
// src/interactions/gestures/pointerSession/pointerSession.ts
|
|
6217
6616
|
function openPointerSession(origin, down, cb, opts = {}) {
|
|
6218
6617
|
const pointerId = down.pointerId;
|
|
6219
6618
|
const doc = origin.ownerDocument ?? document;
|
|
@@ -6262,7 +6661,8 @@ function openPointerSession(origin, down, cb, opts = {}) {
|
|
|
6262
6661
|
if (mine(e)) abort("superseded");
|
|
6263
6662
|
}
|
|
6264
6663
|
function onLostCapture(e) {
|
|
6265
|
-
if (e.pointerId
|
|
6664
|
+
if (e.pointerId !== pointerId) return;
|
|
6665
|
+
if (!origin.isConnected) abort("lostcapture");
|
|
6266
6666
|
}
|
|
6267
6667
|
if (opts.capture !== false) {
|
|
6268
6668
|
try {
|
|
@@ -6510,14 +6910,14 @@ function startThresholdDrag(e, opts) {
|
|
|
6510
6910
|
activated = true;
|
|
6511
6911
|
opts.onActivate?.(ev);
|
|
6512
6912
|
};
|
|
6513
|
-
const session = openPointerSession(e.currentTarget, e, {
|
|
6913
|
+
const session = openPointerSession(opts.origin ?? e.currentTarget, e, {
|
|
6514
6914
|
onMove: (ev) => {
|
|
6515
6915
|
maybeActivate(ev);
|
|
6516
6916
|
if (activated) opts.onMove(ev);
|
|
6517
6917
|
},
|
|
6518
6918
|
onEnd: (ev) => {
|
|
6519
6919
|
if (activated) opts.onCommit(ev);
|
|
6520
|
-
else opts.
|
|
6920
|
+
else opts.onClick?.(ev);
|
|
6521
6921
|
},
|
|
6522
6922
|
onCancel: () => {
|
|
6523
6923
|
opts.onCancel?.();
|
|
@@ -6549,16 +6949,16 @@ function targetSizesPx(targetScale = 1) {
|
|
|
6549
6949
|
}
|
|
6550
6950
|
|
|
6551
6951
|
// src/core/viewport/fitToBounds.ts
|
|
6552
|
-
function fitZoom(availW, availH, contentW, contentH,
|
|
6952
|
+
function fitZoom(availW, availH, contentW, contentH, clamp) {
|
|
6553
6953
|
const raw = Math.min(availW / contentW, availH / contentH);
|
|
6554
|
-
const min =
|
|
6555
|
-
const max =
|
|
6954
|
+
const min = clamp?.min ?? -Infinity;
|
|
6955
|
+
const max = clamp?.max ?? Infinity;
|
|
6556
6956
|
return Math.min(max, Math.max(min, raw));
|
|
6557
6957
|
}
|
|
6558
|
-
function fitToBounds(viewportW, viewportH, contentW, contentH, paddingPx = 0,
|
|
6958
|
+
function fitToBounds(viewportW, viewportH, contentW, contentH, paddingPx = 0, clamp) {
|
|
6559
6959
|
const availW = Math.max(1, viewportW - paddingPx * 2);
|
|
6560
6960
|
const availH = Math.max(1, viewportH - paddingPx * 2);
|
|
6561
|
-
const zoom = fitZoom(availW, availH, contentW, contentH,
|
|
6961
|
+
const zoom = fitZoom(availW, availH, contentW, contentH, clamp);
|
|
6562
6962
|
const contentPxW = contentW * zoom;
|
|
6563
6963
|
const contentPxH = contentH * zoom;
|
|
6564
6964
|
return {
|
|
@@ -6681,128 +7081,6 @@ function sceneNodeClientRect(opts) {
|
|
|
6681
7081
|
height: bounds.height * opts.view.scale.y
|
|
6682
7082
|
};
|
|
6683
7083
|
}
|
|
6684
|
-
var clamp = (z, min, max) => Math.min(max, Math.max(min, z));
|
|
6685
|
-
function isEditableTarget(t) {
|
|
6686
|
-
if (!t) return false;
|
|
6687
|
-
const el = t;
|
|
6688
|
-
if (el.isContentEditable) return true;
|
|
6689
|
-
const tag = (el.tagName ?? "").toUpperCase();
|
|
6690
|
-
return tag === "INPUT" || tag === "TEXTAREA" || tag === "SELECT";
|
|
6691
|
-
}
|
|
6692
|
-
function useZoom(opts) {
|
|
6693
|
-
const min = opts.min ?? DEFAULT_MIN_ZOOM;
|
|
6694
|
-
const max = opts.max ?? DEFAULT_MAX_ZOOM;
|
|
6695
|
-
const wheelStep = opts.wheelStep ?? 1.1;
|
|
6696
|
-
const keyStep = opts.keyStep ?? 1.25;
|
|
6697
|
-
const sources = useMemo(
|
|
6698
|
-
() => ({
|
|
6699
|
-
wheel: opts.sources?.wheel ?? true,
|
|
6700
|
-
keys: opts.sources?.keys ?? true,
|
|
6701
|
-
doubleClick: opts.sources?.doubleClick ?? false,
|
|
6702
|
-
pinch: opts.sources?.pinch ?? true
|
|
6703
|
-
}),
|
|
6704
|
-
[opts.sources?.wheel, opts.sources?.keys, opts.sources?.doubleClick, opts.sources?.pinch]
|
|
6705
|
-
);
|
|
6706
|
-
const applyZoom = useCallback(
|
|
6707
|
-
(nextZoom, focal) => {
|
|
6708
|
-
const oldZoom = opts.zoom;
|
|
6709
|
-
const newZoom = clamp(nextZoom, min, max);
|
|
6710
|
-
const k = newZoom / oldZoom;
|
|
6711
|
-
const newPan = {
|
|
6712
|
-
x: focal.x - (focal.x - opts.pan.x) * k,
|
|
6713
|
-
y: focal.y - (focal.y - opts.pan.y) * k
|
|
6714
|
-
};
|
|
6715
|
-
opts.setZoom(newZoom);
|
|
6716
|
-
opts.setPan(newPan);
|
|
6717
|
-
},
|
|
6718
|
-
[opts, min, max]
|
|
6719
|
-
);
|
|
6720
|
-
const viewportCenter = useCallback(() => {
|
|
6721
|
-
if (!opts.viewport) {
|
|
6722
|
-
throw new Error(
|
|
6723
|
-
"useZoom: viewport option is required for keyboard zoom and zoomTo without focal"
|
|
6724
|
-
);
|
|
6725
|
-
}
|
|
6726
|
-
return { x: opts.viewport.width / 2, y: opts.viewport.height / 2 };
|
|
6727
|
-
}, [opts.viewport]);
|
|
6728
|
-
const zoomTo = useCallback(
|
|
6729
|
-
(level, focal) => {
|
|
6730
|
-
applyZoom(level, focal ?? viewportCenter());
|
|
6731
|
-
},
|
|
6732
|
-
[applyZoom, viewportCenter]
|
|
6733
|
-
);
|
|
6734
|
-
const zoomBy = useCallback(
|
|
6735
|
-
(factor, focal) => {
|
|
6736
|
-
applyZoom(opts.zoom * factor, focal ?? viewportCenter());
|
|
6737
|
-
},
|
|
6738
|
-
[applyZoom, opts.zoom, viewportCenter]
|
|
6739
|
-
);
|
|
6740
|
-
const reset = useCallback(() => {
|
|
6741
|
-
opts.setZoom(1);
|
|
6742
|
-
opts.setPan({ x: 0, y: 0 });
|
|
6743
|
-
}, [opts]);
|
|
6744
|
-
const onWheel = useCallback(
|
|
6745
|
-
(e) => {
|
|
6746
|
-
const evt = e;
|
|
6747
|
-
const isPinch = evt.ctrlKey === true;
|
|
6748
|
-
if (isPinch) {
|
|
6749
|
-
if (!sources.pinch) return;
|
|
6750
|
-
evt.preventDefault?.();
|
|
6751
|
-
} else {
|
|
6752
|
-
if (!sources.wheel) return;
|
|
6753
|
-
if (opts.wheelRequiresModifier && !evt.metaKey) return;
|
|
6754
|
-
}
|
|
6755
|
-
const target = evt.currentTarget;
|
|
6756
|
-
const rect = target?.getBoundingClientRect?.();
|
|
6757
|
-
const focal = {
|
|
6758
|
-
x: evt.clientX - (rect?.left ?? 0),
|
|
6759
|
-
y: evt.clientY - (rect?.top ?? 0)
|
|
6760
|
-
};
|
|
6761
|
-
const factor = evt.deltaY < 0 ? wheelStep : 1 / wheelStep;
|
|
6762
|
-
applyZoom(opts.zoom * factor, focal);
|
|
6763
|
-
},
|
|
6764
|
-
[applyZoom, opts, sources, wheelStep]
|
|
6765
|
-
);
|
|
6766
|
-
const onKeyDown = useCallback(
|
|
6767
|
-
(e) => {
|
|
6768
|
-
if (!sources.keys) return;
|
|
6769
|
-
const evt = e;
|
|
6770
|
-
if (isEditableTarget(evt.target)) return;
|
|
6771
|
-
if (evt.key === "0" && (evt.metaKey || evt.ctrlKey)) {
|
|
6772
|
-
opts.setZoom(1);
|
|
6773
|
-
opts.setPan({ x: 0, y: 0 });
|
|
6774
|
-
return;
|
|
6775
|
-
}
|
|
6776
|
-
let factor = 0;
|
|
6777
|
-
if (evt.key === "+" || evt.key === "=") factor = keyStep;
|
|
6778
|
-
else if (evt.key === "-" || evt.key === "_") factor = 1 / keyStep;
|
|
6779
|
-
if (factor === 0) return;
|
|
6780
|
-
applyZoom(opts.zoom * factor, viewportCenter());
|
|
6781
|
-
},
|
|
6782
|
-
[applyZoom, opts, sources, keyStep, viewportCenter]
|
|
6783
|
-
);
|
|
6784
|
-
const onDoubleClick = useCallback(
|
|
6785
|
-
(e) => {
|
|
6786
|
-
if (!sources.doubleClick) return;
|
|
6787
|
-
const evt = e;
|
|
6788
|
-
if (evt.altKey) {
|
|
6789
|
-
opts.setZoom(1);
|
|
6790
|
-
opts.setPan({ x: 0, y: 0 });
|
|
6791
|
-
return;
|
|
6792
|
-
}
|
|
6793
|
-
const target = evt.currentTarget;
|
|
6794
|
-
const rect = target?.getBoundingClientRect?.();
|
|
6795
|
-
const focal = {
|
|
6796
|
-
x: evt.clientX - (rect?.left ?? 0),
|
|
6797
|
-
y: evt.clientY - (rect?.top ?? 0)
|
|
6798
|
-
};
|
|
6799
|
-
const factor = evt.shiftKey ? 1 / keyStep : keyStep;
|
|
6800
|
-
applyZoom(opts.zoom * factor, focal);
|
|
6801
|
-
},
|
|
6802
|
-
[applyZoom, opts, sources, keyStep]
|
|
6803
|
-
);
|
|
6804
|
-
return { onWheel, onKeyDown, onDoubleClick, zoomTo, zoomBy, reset };
|
|
6805
|
-
}
|
|
6806
7084
|
function computeFitViewport(viewportW, viewportH, contentW, contentH, padRatio = 0.85) {
|
|
6807
7085
|
const zoom = fitZoom(viewportW * padRatio, viewportH * padRatio, contentW, contentH);
|
|
6808
7086
|
const cw = contentW * zoom;
|
|
@@ -6822,7 +7100,7 @@ function useAutoCenter(width, height, contentW, contentH, setZoom, setPan) {
|
|
|
6822
7100
|
}
|
|
6823
7101
|
|
|
6824
7102
|
// src/interactions/keyHelpers.ts
|
|
6825
|
-
function
|
|
7103
|
+
function isEditableTarget(target) {
|
|
6826
7104
|
if (!target || !(target instanceof Element)) return false;
|
|
6827
7105
|
const tag = target.tagName;
|
|
6828
7106
|
if (tag === "INPUT" || tag === "TEXTAREA") return true;
|
|
@@ -6960,7 +7238,10 @@ function moveGestureAdapter(scene) {
|
|
|
6960
7238
|
data: node.data,
|
|
6961
7239
|
id: node.id,
|
|
6962
7240
|
...index !== void 0 ? { index } : {},
|
|
6963
|
-
...node.parent !== null ? { parent: node.parent } : {}
|
|
7241
|
+
...node.parent !== null ? { parent: node.parent } : {},
|
|
7242
|
+
...node.dependsOn !== void 0 ? { dependsOn: node.dependsOn } : {},
|
|
7243
|
+
...node.derivePath !== void 0 ? { derivePath: node.derivePath } : {},
|
|
7244
|
+
...node.kind === "container" && node.clipFromPose !== void 0 ? { clipFromPose: node.clipFromPose } : {}
|
|
6964
7245
|
}),
|
|
6965
7246
|
getChildren: (parentId) => parentId === null ? [...scene.roots] : [...scene.childrenOf(asNodeId(parentId))],
|
|
6966
7247
|
setChildOrder: (parentId, ids) => {
|
|
@@ -6985,31 +7266,51 @@ function runLayoutPass(scratch, moveCtx) {
|
|
|
6985
7266
|
if (!layoutDep || !moveCtx.drag) return;
|
|
6986
7267
|
const scene = scratch.scene;
|
|
6987
7268
|
const pc = scratch.pc;
|
|
6988
|
-
const draggedId = scratch.ids[0];
|
|
6989
7269
|
const poseAdapter = scenePoseAdapter(scene);
|
|
6990
|
-
if (!scene.get(draggedId)) return;
|
|
6991
|
-
const sourceContainerId = scene.get(draggedId)?.parent ?? null;
|
|
6992
7270
|
const { dx, dy } = scratch.currentDelta;
|
|
6993
|
-
const
|
|
6994
|
-
const
|
|
6995
|
-
|
|
6996
|
-
|
|
6997
|
-
|
|
7271
|
+
const dragged = [];
|
|
7272
|
+
for (const id of scratch.ids) {
|
|
7273
|
+
const node = scene.get(id);
|
|
7274
|
+
if (!node) continue;
|
|
7275
|
+
const startWorld = composeWorldPose(poseAdapter, id, pc.compose);
|
|
7276
|
+
const world = { ...startWorld, x: startWorld.x + dx, y: startWorld.y + dy };
|
|
7277
|
+
dragged.push({
|
|
7278
|
+
id,
|
|
7279
|
+
arg: {
|
|
7280
|
+
id,
|
|
7281
|
+
originPose: startWorld,
|
|
7282
|
+
pose: world,
|
|
7283
|
+
sourceContainerId: node.parent ?? null
|
|
7284
|
+
},
|
|
7285
|
+
center: { x: world.x + (world.width ?? 0) / 2, y: world.y + (world.height ?? 0) / 2 }
|
|
7286
|
+
});
|
|
7287
|
+
}
|
|
7288
|
+
if (dragged.length === 0) return;
|
|
7289
|
+
const draggedIds = new Set(dragged.map((d) => d.id));
|
|
7290
|
+
let minX = Infinity;
|
|
7291
|
+
let minY = Infinity;
|
|
7292
|
+
let maxX = -Infinity;
|
|
7293
|
+
let maxY = -Infinity;
|
|
7294
|
+
for (const d of dragged) {
|
|
7295
|
+
const p = d.arg.pose;
|
|
7296
|
+
minX = Math.min(minX, p.x);
|
|
7297
|
+
minY = Math.min(minY, p.y);
|
|
7298
|
+
maxX = Math.max(maxX, p.x + (p.width ?? 0));
|
|
7299
|
+
maxY = Math.max(maxY, p.y + (p.height ?? 0));
|
|
7300
|
+
}
|
|
7301
|
+
const selectionCenter = { x: (minX + maxX) / 2, y: (minY + maxY) / 2 };
|
|
7302
|
+
const probeOffset = {
|
|
7303
|
+
x: moveCtx.drag.current.x - selectionCenter.x,
|
|
7304
|
+
y: moveCtx.drag.current.y - selectionCenter.y
|
|
6998
7305
|
};
|
|
6999
7306
|
const candidates = [];
|
|
7000
7307
|
const boundsOf2 = scratch.projection?.getBounds ?? AUTO_POSE_DESCRIPTOR.getBounds;
|
|
7001
7308
|
const testInside = (cPose, aabb, layout2) => {
|
|
7002
|
-
if (layout2.contains) return layout2.contains(cPose,
|
|
7003
|
-
return
|
|
7004
|
-
};
|
|
7005
|
-
const draggedArg = {
|
|
7006
|
-
id: draggedId,
|
|
7007
|
-
originPose: startWorld,
|
|
7008
|
-
pose: draggedWorld,
|
|
7009
|
-
sourceContainerId
|
|
7309
|
+
if (layout2.contains) return layout2.contains(cPose, selectionCenter);
|
|
7310
|
+
return selectionCenter.x >= aabb.x && selectionCenter.x < aabb.x + aabb.width && selectionCenter.y >= aabb.y && selectionCenter.y < aabb.y + aabb.height;
|
|
7010
7311
|
};
|
|
7011
7312
|
const consider = (id, zPath) => {
|
|
7012
|
-
if (id
|
|
7313
|
+
if (draggedIds.has(id)) return;
|
|
7013
7314
|
const layout2 = layoutDep.getLayout(id);
|
|
7014
7315
|
if (!layout2) return;
|
|
7015
7316
|
const node = scene.get(id);
|
|
@@ -7017,7 +7318,10 @@ function runLayoutPass(scratch, moveCtx) {
|
|
|
7017
7318
|
const worldPose = composeWorldPose(poseAdapter, id, pc.compose);
|
|
7018
7319
|
const worldAABB = boundsOf2(worldPose);
|
|
7019
7320
|
if (!testInside(worldPose, worldAABB, layout2)) return;
|
|
7020
|
-
if (layout2.acceptsDrop
|
|
7321
|
+
if (layout2.acceptsDrop) {
|
|
7322
|
+
const arg = { id, bounds: worldAABB };
|
|
7323
|
+
for (const d of dragged) if (!layout2.acceptsDrop(arg, d.arg)) return;
|
|
7324
|
+
}
|
|
7021
7325
|
candidates.push({
|
|
7022
7326
|
id,
|
|
7023
7327
|
bounds: worldAABB,
|
|
@@ -7062,47 +7366,126 @@ function runLayoutPass(scratch, moveCtx) {
|
|
|
7062
7366
|
if (!dest) return;
|
|
7063
7367
|
const layout = dest.layout;
|
|
7064
7368
|
const container = { id: dest.id, bounds: dest.bounds };
|
|
7065
|
-
const
|
|
7369
|
+
const working = scene.childrenOf(dest.id).map((cid) => ({
|
|
7066
7370
|
id: cid,
|
|
7067
7371
|
pose: composeWorldPose(poseAdapter, cid, pc.compose)
|
|
7068
7372
|
}));
|
|
7069
|
-
const
|
|
7070
|
-
|
|
7071
|
-
|
|
7373
|
+
const setWorking = (id, pose) => {
|
|
7374
|
+
const at = working.findIndex((c) => c.id === id);
|
|
7375
|
+
if (at >= 0) working[at] = { id, pose };
|
|
7376
|
+
else working.push({ id, pose });
|
|
7377
|
+
};
|
|
7378
|
+
const placements = [];
|
|
7379
|
+
const destReflow = /* @__PURE__ */ new Map();
|
|
7380
|
+
for (const d of dragged) {
|
|
7381
|
+
const children = working.map((c) => ({ ...c }));
|
|
7382
|
+
const targets = layout.getDropTargets(container, children, d.arg);
|
|
7383
|
+
const target = layout.snap.pickTarget(targets, {
|
|
7384
|
+
x: d.center.x + probeOffset.x,
|
|
7385
|
+
y: d.center.y + probeOffset.y
|
|
7386
|
+
});
|
|
7387
|
+
if (!target) return;
|
|
7388
|
+
placements.push({ dragged: d.arg, children, target });
|
|
7389
|
+
const poses = layout.reflowPoses(container, children, d.arg, target);
|
|
7390
|
+
for (const [cid, pose] of poses) {
|
|
7391
|
+
setWorking(cid, pose);
|
|
7392
|
+
if (!draggedIds.has(asNodeId(cid))) destReflow.set(asNodeId(cid), pose);
|
|
7393
|
+
}
|
|
7394
|
+
setWorking(d.arg.id, poses.get(d.arg.id) ?? target.pose);
|
|
7395
|
+
}
|
|
7072
7396
|
const reflowIds = /* @__PURE__ */ new Set();
|
|
7073
|
-
for (const [cid, pose] of
|
|
7074
|
-
|
|
7075
|
-
|
|
7076
|
-
|
|
7077
|
-
scratch.previews.set(asNodeId(cid), local);
|
|
7078
|
-
reflowIds.add(asNodeId(cid));
|
|
7397
|
+
for (const [cid, pose] of destReflow) {
|
|
7398
|
+
const parent = scene.get(cid)?.parent ?? null;
|
|
7399
|
+
scratch.previews.set(cid, rebaseLocalPose(poseAdapter, pose, parent, pc.compose, pc.decompose));
|
|
7400
|
+
reflowIds.add(cid);
|
|
7079
7401
|
}
|
|
7080
7402
|
const sourceReflow = /* @__PURE__ */ new Map();
|
|
7081
|
-
|
|
7082
|
-
|
|
7083
|
-
|
|
7084
|
-
|
|
7085
|
-
|
|
7086
|
-
|
|
7087
|
-
|
|
7088
|
-
|
|
7089
|
-
|
|
7090
|
-
|
|
7091
|
-
|
|
7092
|
-
|
|
7093
|
-
|
|
7094
|
-
|
|
7095
|
-
|
|
7096
|
-
|
|
7097
|
-
|
|
7098
|
-
|
|
7099
|
-
|
|
7100
|
-
|
|
7101
|
-
|
|
7403
|
+
for (const [srcId, leaving] of groupBySourceContainer(dragged.map((d) => ({
|
|
7404
|
+
id: d.id,
|
|
7405
|
+
sourceContainerId: d.arg.sourceContainerId
|
|
7406
|
+
})), container.id)) {
|
|
7407
|
+
const srcLayout = layoutDep.getLayout(srcId);
|
|
7408
|
+
const srcNode = scene.get(asNodeId(srcId));
|
|
7409
|
+
if (!srcLayout || !srcNode) continue;
|
|
7410
|
+
const srcContainer = {
|
|
7411
|
+
id: srcId,
|
|
7412
|
+
bounds: composeWorldPose(poseAdapter, srcId, pc.compose)
|
|
7413
|
+
};
|
|
7414
|
+
const srcChildren = scene.childrenOf(asNodeId(srcId)).filter((cid) => !leaving.has(cid)).map((cid) => ({
|
|
7415
|
+
id: cid,
|
|
7416
|
+
pose: composeWorldPose(poseAdapter, cid, pc.compose)
|
|
7417
|
+
}));
|
|
7418
|
+
for (const [cid, pose] of srcLayout.childPoses(srcContainer, srcChildren)) {
|
|
7419
|
+
const cur = composeWorldPose(poseAdapter, cid, pc.compose);
|
|
7420
|
+
const next = pose;
|
|
7421
|
+
const same2 = cur.x === next.x && cur.y === next.y && cur.width === next.width && cur.height === next.height;
|
|
7422
|
+
if (same2) continue;
|
|
7423
|
+
sourceReflow.set(cid, pose);
|
|
7424
|
+
const parent = scene.get(asNodeId(cid))?.parent ?? null;
|
|
7425
|
+
scratch.previews.set(asNodeId(cid), rebaseLocalPose(poseAdapter, pose, parent, pc.compose, pc.decompose));
|
|
7426
|
+
reflowIds.add(asNodeId(cid));
|
|
7427
|
+
}
|
|
7428
|
+
}
|
|
7429
|
+
scratch.layoutPass = { layout, container, placements, sourceReflow, reflowIds };
|
|
7430
|
+
}
|
|
7431
|
+
function groupBySourceContainer(dragged, exclude) {
|
|
7432
|
+
const out = /* @__PURE__ */ new Map();
|
|
7433
|
+
for (const d of dragged) {
|
|
7434
|
+
const src = d.sourceContainerId;
|
|
7435
|
+
if (!src || src === exclude) continue;
|
|
7436
|
+
let set = out.get(src);
|
|
7437
|
+
if (!set) {
|
|
7438
|
+
set = /* @__PURE__ */ new Set();
|
|
7439
|
+
out.set(src, set);
|
|
7440
|
+
}
|
|
7441
|
+
set.add(d.id);
|
|
7442
|
+
}
|
|
7443
|
+
return out;
|
|
7444
|
+
}
|
|
7445
|
+
function translateCommitOps(scratch, ids, dx, dy) {
|
|
7446
|
+
const m = [1, 0, 0, 1, dx, dy];
|
|
7447
|
+
const ops = [];
|
|
7448
|
+
for (const id of ids) {
|
|
7449
|
+
const origin = scratch.startPoses.get(id);
|
|
7450
|
+
if (origin === void 0) continue;
|
|
7451
|
+
ops.push(createTransformOp({
|
|
7452
|
+
id,
|
|
7453
|
+
from: origin,
|
|
7454
|
+
to: translatePoseGeneric(origin, dx, dy, scratch.projection),
|
|
7455
|
+
label: "Move"
|
|
7456
|
+
}));
|
|
7457
|
+
if (scratch.geometryProjection) {
|
|
7458
|
+
const node = scratch.scene.get(id);
|
|
7459
|
+
if (node) {
|
|
7460
|
+
const dataOp = geometryDataOp(
|
|
7461
|
+
scratch.geometryProjection,
|
|
7462
|
+
{ id, data: node.data, pose: origin },
|
|
7463
|
+
m,
|
|
7464
|
+
"Move"
|
|
7465
|
+
);
|
|
7466
|
+
if (dataOp) ops.push(dataOp);
|
|
7102
7467
|
}
|
|
7103
7468
|
}
|
|
7104
7469
|
}
|
|
7105
|
-
|
|
7470
|
+
return ops;
|
|
7471
|
+
}
|
|
7472
|
+
function unreleasedIds(scratch, released) {
|
|
7473
|
+
const selected = new Set(scratch.ids);
|
|
7474
|
+
const out = scratch.ids.filter((id) => !released.has(id));
|
|
7475
|
+
for (const id of scratch.cascadeIds) {
|
|
7476
|
+
let cur = scratch.scene.get(id)?.parent ?? null;
|
|
7477
|
+
let claimed = false;
|
|
7478
|
+
while (cur) {
|
|
7479
|
+
if (released.has(cur)) {
|
|
7480
|
+
claimed = true;
|
|
7481
|
+
break;
|
|
7482
|
+
}
|
|
7483
|
+
if (selected.has(cur)) break;
|
|
7484
|
+
cur = scratch.scene.get(cur)?.parent ?? null;
|
|
7485
|
+
}
|
|
7486
|
+
if (!claimed) out.push(id);
|
|
7487
|
+
}
|
|
7488
|
+
return out;
|
|
7106
7489
|
}
|
|
7107
7490
|
function scenePoseAdapter(scene) {
|
|
7108
7491
|
return {
|
|
@@ -7287,7 +7670,7 @@ var moveAction = {
|
|
|
7287
7670
|
scratch.previews.set(id, translatePoseGeneric(ori, dx, dy, scratch.projection));
|
|
7288
7671
|
}
|
|
7289
7672
|
scratch.layoutPass = null;
|
|
7290
|
-
|
|
7673
|
+
runLayoutPass(scratch, moveCtx);
|
|
7291
7674
|
syncPreviewOverrides(scratch);
|
|
7292
7675
|
},
|
|
7293
7676
|
onEnd(endCtx, reason) {
|
|
@@ -7322,25 +7705,17 @@ var moveAction = {
|
|
|
7322
7705
|
scratch.previews.clear();
|
|
7323
7706
|
return;
|
|
7324
7707
|
}
|
|
7325
|
-
if (scratch.layout && scratch.
|
|
7708
|
+
if (scratch.layout && scratch.layoutPass) {
|
|
7326
7709
|
const lp = scratch.layoutPass;
|
|
7327
7710
|
const pc2 = scratch.pc;
|
|
7328
|
-
const draggedId = scratch.ids[0];
|
|
7329
7711
|
const commitAdapter = scenePoseAdapter(scratch.scene);
|
|
7330
|
-
const startWorld = composeWorldPose(commitAdapter, draggedId, pc2.compose);
|
|
7331
|
-
const sourceContainerId = scratch.scene.get(draggedId)?.parent ?? null;
|
|
7332
|
-
const draggedArg = {
|
|
7333
|
-
id: draggedId,
|
|
7334
|
-
originPose: startWorld,
|
|
7335
|
-
pose: { ...startWorld, x: startWorld.x + dx, y: startWorld.y + dy },
|
|
7336
|
-
sourceContainerId
|
|
7337
|
-
};
|
|
7338
7712
|
const destId = lp.container.id;
|
|
7713
|
+
const draggedIds = new Set(scratch.ids.map((id) => id));
|
|
7339
7714
|
const rebaseOpToLocal = (op) => {
|
|
7340
7715
|
if (op.name !== "transform") return op;
|
|
7341
7716
|
const a = op.args;
|
|
7342
7717
|
const curParent = scratch.scene.get(asNodeId(a.id))?.parent ?? null;
|
|
7343
|
-
const toParent = a.id
|
|
7718
|
+
const toParent = draggedIds.has(a.id) ? destId : curParent;
|
|
7344
7719
|
return createTransformOp({
|
|
7345
7720
|
id: a.id,
|
|
7346
7721
|
from: rebaseLocalPose(commitAdapter, a.from, curParent, pc2.compose, pc2.decompose),
|
|
@@ -7349,15 +7724,24 @@ var moveAction = {
|
|
|
7349
7724
|
coalesceKey: a.coalesceKey
|
|
7350
7725
|
});
|
|
7351
7726
|
};
|
|
7352
|
-
const dropOps = lp.layout.commitDrop(lp.container, lp.children, draggedArg, lp.target).map(rebaseOpToLocal);
|
|
7353
7727
|
const reparentOps = [];
|
|
7354
|
-
|
|
7355
|
-
|
|
7356
|
-
|
|
7357
|
-
|
|
7358
|
-
|
|
7359
|
-
|
|
7360
|
-
|
|
7728
|
+
const dropOps = [];
|
|
7729
|
+
for (const placement of lp.placements) {
|
|
7730
|
+
if (placement.dragged.sourceContainerId !== destId) {
|
|
7731
|
+
reparentOps.push(createReparentOp({
|
|
7732
|
+
id: placement.dragged.id,
|
|
7733
|
+
fromParentId: placement.dragged.sourceContainerId,
|
|
7734
|
+
toParentId: destId,
|
|
7735
|
+
label: "Reparent"
|
|
7736
|
+
}));
|
|
7737
|
+
}
|
|
7738
|
+
const ops2 = lp.layout.commitDrop(
|
|
7739
|
+
lp.container,
|
|
7740
|
+
placement.children,
|
|
7741
|
+
placement.dragged,
|
|
7742
|
+
placement.target
|
|
7743
|
+
);
|
|
7744
|
+
for (const op of ops2) dropOps.push(rebaseOpToLocal(op));
|
|
7361
7745
|
}
|
|
7362
7746
|
const reflowOps = [];
|
|
7363
7747
|
for (const [cid, worldPose] of lp.sourceReflow) {
|
|
@@ -7376,6 +7760,73 @@ var moveAction = {
|
|
|
7376
7760
|
scratch.previews.clear();
|
|
7377
7761
|
return;
|
|
7378
7762
|
}
|
|
7763
|
+
const released = /* @__PURE__ */ new Set();
|
|
7764
|
+
const releasedOps = [];
|
|
7765
|
+
if (scratch.layout && !scratch.layoutPass) {
|
|
7766
|
+
const pc2 = scratch.pc;
|
|
7767
|
+
const commitAdapter = scenePoseAdapter(scratch.scene);
|
|
7768
|
+
const boundsOf2 = scratch.projection?.getBounds ?? AUTO_POSE_DESCRIPTOR.getBounds;
|
|
7769
|
+
const rebaseReleased = (op) => {
|
|
7770
|
+
if (op.name !== "transform") return op;
|
|
7771
|
+
const a = op.args;
|
|
7772
|
+
const parent = scratch.scene.get(asNodeId(a.id))?.parent ?? null;
|
|
7773
|
+
return createTransformOp({
|
|
7774
|
+
id: a.id,
|
|
7775
|
+
from: rebaseLocalPose(commitAdapter, a.from, parent, pc2.compose, pc2.decompose),
|
|
7776
|
+
to: rebaseLocalPose(commitAdapter, a.to, parent, pc2.compose, pc2.decompose),
|
|
7777
|
+
label: a.label,
|
|
7778
|
+
coalesceKey: a.coalesceKey
|
|
7779
|
+
});
|
|
7780
|
+
};
|
|
7781
|
+
const sources = groupBySourceContainer(
|
|
7782
|
+
scratch.ids.map((id) => ({
|
|
7783
|
+
id,
|
|
7784
|
+
sourceContainerId: scratch.scene.get(id)?.parent ?? null
|
|
7785
|
+
})),
|
|
7786
|
+
null
|
|
7787
|
+
);
|
|
7788
|
+
for (const [srcId, leaving] of sources) {
|
|
7789
|
+
const srcLayout = scratch.layout.getLayout(srcId);
|
|
7790
|
+
if (!srcLayout?.releaseDrop) continue;
|
|
7791
|
+
const srcContainer = {
|
|
7792
|
+
id: srcId,
|
|
7793
|
+
bounds: boundsOf2(
|
|
7794
|
+
composeWorldPose(commitAdapter, srcId, pc2.compose)
|
|
7795
|
+
)
|
|
7796
|
+
};
|
|
7797
|
+
let srcChildren = scratch.scene.childrenOf(asNodeId(srcId)).filter((cid) => !leaving.has(cid)).map((cid) => ({
|
|
7798
|
+
id: cid,
|
|
7799
|
+
pose: composeWorldPose(commitAdapter, cid, pc2.compose)
|
|
7800
|
+
}));
|
|
7801
|
+
for (const id of leaving) {
|
|
7802
|
+
const startWorld = composeWorldPose(commitAdapter, id, pc2.compose);
|
|
7803
|
+
const ops = srcLayout.releaseDrop(srcContainer, srcChildren, {
|
|
7804
|
+
id,
|
|
7805
|
+
originPose: startWorld,
|
|
7806
|
+
pose: { ...startWorld, x: startWorld.x + dx, y: startWorld.y + dy },
|
|
7807
|
+
sourceContainerId: srcId
|
|
7808
|
+
});
|
|
7809
|
+
if (ops === null) continue;
|
|
7810
|
+
released.add(id);
|
|
7811
|
+
let landed = startWorld;
|
|
7812
|
+
for (const op of ops) {
|
|
7813
|
+
const a = op.args;
|
|
7814
|
+
if (op.name === "transform" && a.id === id) landed = a.to;
|
|
7815
|
+
releasedOps.push(rebaseReleased(op));
|
|
7816
|
+
}
|
|
7817
|
+
srcChildren = [...srcChildren, { id, pose: landed }];
|
|
7818
|
+
}
|
|
7819
|
+
}
|
|
7820
|
+
}
|
|
7821
|
+
if (released.size > 0) {
|
|
7822
|
+
const ops = [
|
|
7823
|
+
...releasedOps,
|
|
7824
|
+
...translateCommitOps(scratch, unreleasedIds(scratch, released), dx, dy)
|
|
7825
|
+
];
|
|
7826
|
+
if (ops.length > 0) commitOps(ops, ops[0].label ?? "Move");
|
|
7827
|
+
scratch.previews.clear();
|
|
7828
|
+
return;
|
|
7829
|
+
}
|
|
7379
7830
|
const resolved = resolveParams(opts?.params);
|
|
7380
7831
|
const reparentMode = resolved?.["reparentOnDrop"] ?? "off";
|
|
7381
7832
|
const dropTarget = reparentMode !== "off" ? resolveDropTarget(endCtx, scratch) : null;
|
|
@@ -7384,30 +7835,7 @@ var moveAction = {
|
|
|
7384
7835
|
applyReparent(scratch, dropTarget, reparentMode, dx, dy, scratch.pc);
|
|
7385
7836
|
});
|
|
7386
7837
|
} else {
|
|
7387
|
-
const
|
|
7388
|
-
const ops = [];
|
|
7389
|
-
for (const id of [...scratch.ids, ...scratch.cascadeIds]) {
|
|
7390
|
-
const origin2 = scratch.startPoses.get(id);
|
|
7391
|
-
if (origin2 === void 0) continue;
|
|
7392
|
-
ops.push(createTransformOp({
|
|
7393
|
-
id,
|
|
7394
|
-
from: origin2,
|
|
7395
|
-
to: translatePoseGeneric(origin2, dx, dy, scratch.projection),
|
|
7396
|
-
label: "Move"
|
|
7397
|
-
}));
|
|
7398
|
-
if (scratch.geometryProjection) {
|
|
7399
|
-
const node = scratch.scene.get(id);
|
|
7400
|
-
if (node) {
|
|
7401
|
-
const dataOp = geometryDataOp(
|
|
7402
|
-
scratch.geometryProjection,
|
|
7403
|
-
{ id, data: node.data, pose: origin2 },
|
|
7404
|
-
m,
|
|
7405
|
-
"Move"
|
|
7406
|
-
);
|
|
7407
|
-
if (dataOp) ops.push(dataOp);
|
|
7408
|
-
}
|
|
7409
|
-
}
|
|
7410
|
-
}
|
|
7838
|
+
const ops = translateCommitOps(scratch, [...scratch.ids, ...scratch.cascadeIds], dx, dy);
|
|
7411
7839
|
if (ops.length > 0) commitOps(ops, "Move");
|
|
7412
7840
|
}
|
|
7413
7841
|
dropPreviewOverrides(scratch);
|
|
@@ -7478,6 +7906,7 @@ function defaultCommitAdapter(scene) {
|
|
|
7478
7906
|
getSelection: () => [...scene.getSelection()],
|
|
7479
7907
|
setSelection: (ids) => scene.setSelection(ids.map(asNodeId)),
|
|
7480
7908
|
getParent: (id) => scene.get(asNodeId(id))?.parent ?? null,
|
|
7909
|
+
getRemovalClosure: (ids) => [...scene.removalClosure(ids.map(asNodeId))],
|
|
7481
7910
|
getChildren: (parentId) => parentId === null ? [...scene.roots] : [...scene.childrenOf(asNodeId(parentId))],
|
|
7482
7911
|
// Re-stamp each slot whose occupant changed. `scene.reorder` mutates the
|
|
7483
7912
|
// live sibling list in place, so re-read it each iteration and skip slots
|
|
@@ -7506,7 +7935,13 @@ function defaultCommitAdapter(scene) {
|
|
|
7506
7935
|
// Sibling-index passthrough: undo of a delete (or a boolean op's
|
|
7507
7936
|
// source removal) re-inserts at the recorded z-order slot instead
|
|
7508
7937
|
// of appending at the end.
|
|
7509
|
-
...index !== void 0 ? { index } : {}
|
|
7938
|
+
...index !== void 0 ? { index } : {},
|
|
7939
|
+
// The function-valued fields travel with the node, or undo of a delete
|
|
7940
|
+
// brings an edge back as a static path that never follows its endpoints
|
|
7941
|
+
// again, and a clipped container back with nothing clipped.
|
|
7942
|
+
...node.dependsOn !== void 0 ? { dependsOn: node.dependsOn } : {},
|
|
7943
|
+
...node.derivePath !== void 0 ? { derivePath: node.derivePath } : {},
|
|
7944
|
+
...node.kind === "container" && node.clipFromPose !== void 0 ? { clipFromPose: node.clipFromPose } : {}
|
|
7510
7945
|
})
|
|
7511
7946
|
};
|
|
7512
7947
|
}
|
|
@@ -8682,15 +9117,40 @@ var viewportDragPanAction = {
|
|
|
8682
9117
|
enabled: () => true
|
|
8683
9118
|
};
|
|
8684
9119
|
|
|
9120
|
+
// src/core/viewport/wheelHandler.ts
|
|
9121
|
+
var WHEEL_ZOOM_STEP = 1.1;
|
|
9122
|
+
function wheelZoomFactor(deltaY) {
|
|
9123
|
+
return Math.pow(WHEEL_ZOOM_STEP, -deltaY / 100);
|
|
9124
|
+
}
|
|
9125
|
+
function wheelZoom(view, anchor, deltaY, clamp) {
|
|
9126
|
+
return zoomAt(view, anchor, wheelZoomFactor(deltaY), clamp);
|
|
9127
|
+
}
|
|
9128
|
+
function wheelPan(view, delta3, opts = {}) {
|
|
9129
|
+
const axis = opts.axis ?? "both";
|
|
9130
|
+
const swapped = opts.swapAxis === true;
|
|
9131
|
+
const screenX = swapped ? delta3.deltaX !== 0 ? delta3.deltaX : delta3.deltaY : delta3.deltaX;
|
|
9132
|
+
const screenY = swapped ? 0 : delta3.deltaY;
|
|
9133
|
+
return {
|
|
9134
|
+
scale: view.scale,
|
|
9135
|
+
x: view.x + (axis === "y" ? 0 : screenX / view.scale.x),
|
|
9136
|
+
y: view.y + (axis === "x" ? 0 : screenY / view.scale.y)
|
|
9137
|
+
};
|
|
9138
|
+
}
|
|
9139
|
+
function computeWheelAction(view, input, clamp, opts = {}) {
|
|
9140
|
+
if (input.ctrlKey || input.metaKey) {
|
|
9141
|
+
return wheelZoom(view, { x: input.x, y: input.y }, input.deltaY, clamp);
|
|
9142
|
+
}
|
|
9143
|
+
return wheelPan(view, input, { axis: opts.axis, swapAxis: input.shiftKey === true });
|
|
9144
|
+
}
|
|
9145
|
+
|
|
8685
9146
|
// src/interactions/actions/defaults/viewportZoom.ts
|
|
8686
9147
|
var KEY_STEP = 1.25;
|
|
8687
9148
|
function keyAnchor(view) {
|
|
8688
9149
|
const size = view.hostSize?.();
|
|
8689
9150
|
return size ? { x: size.width / 2, y: size.height / 2 } : { x: 0, y: 0 };
|
|
8690
9151
|
}
|
|
8691
|
-
var WHEEL_STEP = 1.1;
|
|
8692
9152
|
function makeViewportZoomAction(opts = {}) {
|
|
8693
|
-
const
|
|
9153
|
+
const clamp = { min: opts.min ?? DEFAULT_MIN_ZOOM, max: opts.max ?? DEFAULT_MAX_ZOOM };
|
|
8694
9154
|
const wheelSpec = opts.wheel === "plain" ? { kind: "wheel" } : { kind: "wheel", mods: { mod: true } };
|
|
8695
9155
|
const rawAnimate = opts.animate === true ? {} : opts.animate || null;
|
|
8696
9156
|
const { resetMs, ...animateRest } = rawAnimate ?? {};
|
|
@@ -8750,15 +9210,14 @@ function makeViewportZoomAction(opts = {}) {
|
|
|
8750
9210
|
const deltaY = params?.deltaY ?? 0;
|
|
8751
9211
|
const clientX = params?.clientX ?? 0;
|
|
8752
9212
|
const clientY = params?.clientY ?? 0;
|
|
8753
|
-
|
|
8754
|
-
view.set(zoomAt(current, { x: clientX, y: clientY }, factor, clamp2));
|
|
9213
|
+
view.set(wheelZoom(current, { x: clientX, y: clientY }, deltaY, clamp));
|
|
8755
9214
|
break;
|
|
8756
9215
|
}
|
|
8757
9216
|
case "in":
|
|
8758
|
-
stepTo(zoomAt(stepFrom(), keyAnchor(view), KEY_STEP,
|
|
9217
|
+
stepTo(zoomAt(stepFrom(), keyAnchor(view), KEY_STEP, clamp));
|
|
8759
9218
|
break;
|
|
8760
9219
|
case "out":
|
|
8761
|
-
stepTo(zoomAt(stepFrom(), keyAnchor(view), 1 / KEY_STEP,
|
|
9220
|
+
stepTo(zoomAt(stepFrom(), keyAnchor(view), 1 / KEY_STEP, clamp));
|
|
8762
9221
|
break;
|
|
8763
9222
|
case "reset": {
|
|
8764
9223
|
const target = view.recenter ? view.recenter() : { x: 0, y: 0, scale: { x: 1, y: 1 } };
|
|
@@ -8767,7 +9226,7 @@ function makeViewportZoomAction(opts = {}) {
|
|
|
8767
9226
|
}
|
|
8768
9227
|
default:
|
|
8769
9228
|
if (params === void 0) {
|
|
8770
|
-
view.set(zoomAt(current, { x: 0, y: 0 }, KEY_STEP,
|
|
9229
|
+
view.set(zoomAt(current, { x: 0, y: 0 }, KEY_STEP, clamp));
|
|
8771
9230
|
}
|
|
8772
9231
|
break;
|
|
8773
9232
|
}
|
|
@@ -8802,15 +9261,9 @@ var viewportWheelPanAction = {
|
|
|
8802
9261
|
const axis = params?.axis ?? "both";
|
|
8803
9262
|
const deltaX = params?.deltaX ?? 0;
|
|
8804
9263
|
const deltaY = params?.deltaY ?? 0;
|
|
8805
|
-
|
|
8806
|
-
|
|
8807
|
-
|
|
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
|
-
});
|
|
9264
|
+
view.set(
|
|
9265
|
+
wheelPan(view.get(), { deltaX, deltaY }, { axis, swapAxis: params?.swapAxis === true })
|
|
9266
|
+
);
|
|
8814
9267
|
}
|
|
8815
9268
|
},
|
|
8816
9269
|
enabled: () => true
|
|
@@ -9458,7 +9911,7 @@ var sliceAction = {
|
|
|
9458
9911
|
|
|
9459
9912
|
// src/interactions/actions/defaults/pinchZoom.ts
|
|
9460
9913
|
function makePinchZoomAction(opts = {}) {
|
|
9461
|
-
const
|
|
9914
|
+
const clamp = { min: opts.min ?? DEFAULT_MIN_ZOOM, max: opts.max ?? DEFAULT_MAX_ZOOM };
|
|
9462
9915
|
return {
|
|
9463
9916
|
id: "viewport.pinchZoom",
|
|
9464
9917
|
label: "Pinch Zoom",
|
|
@@ -9486,7 +9939,7 @@ function makePinchZoomAction(opts = {}) {
|
|
|
9486
9939
|
const prev = scratch.centroid;
|
|
9487
9940
|
scratch.centroid = centroid;
|
|
9488
9941
|
const current = scratch.view.get();
|
|
9489
|
-
const zoomed = zoomAt(current, prev, factor,
|
|
9942
|
+
const zoomed = zoomAt(current, prev, factor, clamp);
|
|
9490
9943
|
scratch.view.set({
|
|
9491
9944
|
scale: zoomed.scale,
|
|
9492
9945
|
x: zoomed.x - (centroid.x - prev.x) / zoomed.scale.x,
|
|
@@ -9508,31 +9961,14 @@ function hostIndex(scene, id) {
|
|
|
9508
9961
|
const siblings = node?.parent == null ? scene.roots : scene.childrenOf(node.parent);
|
|
9509
9962
|
return siblings.indexOf(id);
|
|
9510
9963
|
}
|
|
9511
|
-
function coveredByEmitted(scene, id, emitted) {
|
|
9512
|
-
const seen = /* @__PURE__ */ new Set([id]);
|
|
9513
|
-
const stack = [id];
|
|
9514
|
-
while (stack.length > 0) {
|
|
9515
|
-
const node = scene.get(stack.pop());
|
|
9516
|
-
if (!node) continue;
|
|
9517
|
-
const up = node.parent == null ? node.dependsOn ?? [] : [node.parent, ...node.dependsOn ?? []];
|
|
9518
|
-
for (const next of up) {
|
|
9519
|
-
if (seen.has(next)) continue;
|
|
9520
|
-
if (emitted.has(next)) return true;
|
|
9521
|
-
seen.add(next);
|
|
9522
|
-
stack.push(next);
|
|
9523
|
-
}
|
|
9524
|
-
}
|
|
9525
|
-
return false;
|
|
9526
|
-
}
|
|
9527
9964
|
function buildDeleteOps(scene, ids, label) {
|
|
9528
|
-
const
|
|
9965
|
+
const covered = /* @__PURE__ */ new Set();
|
|
9529
9966
|
const ops = [];
|
|
9530
9967
|
for (const id of ids) {
|
|
9531
9968
|
const node = scene.get(id);
|
|
9532
9969
|
if (!node) continue;
|
|
9533
|
-
if (
|
|
9534
|
-
|
|
9535
|
-
emitted.add(id);
|
|
9970
|
+
if (covered.has(id)) continue;
|
|
9971
|
+
for (const taken of scene.removalClosure([id])) covered.add(taken);
|
|
9536
9972
|
ops.push(createDeleteOp({
|
|
9537
9973
|
node,
|
|
9538
9974
|
index: hostIndex(scene, id),
|
|
@@ -9756,7 +10192,10 @@ var selectAllAction = {
|
|
|
9756
10192
|
timing: "immediate",
|
|
9757
10193
|
run: (deps) => {
|
|
9758
10194
|
const scene = deps.scene;
|
|
9759
|
-
const
|
|
10195
|
+
const hidden = new Set(
|
|
10196
|
+
(scene?.layers ?? []).filter((l) => !l.visible).map((l) => l.id)
|
|
10197
|
+
);
|
|
10198
|
+
const all = hidden.size === 0 || !scene?.renderOrderNodes ? scene?.renderOrder ? [...scene.renderOrder()] : [] : scene.renderOrderNodes().filter((n) => !hidden.has(n.layer)).map((n) => n.id);
|
|
9760
10199
|
if (all.length === 0) return;
|
|
9761
10200
|
deps.selection?.set(all);
|
|
9762
10201
|
}
|
|
@@ -11774,7 +12213,7 @@ var setStrokeOpacityAction = createPaintAction({
|
|
|
11774
12213
|
readParams: (_prev, params) => params?.alpha01 ?? null,
|
|
11775
12214
|
merge: (prev, alpha01) => {
|
|
11776
12215
|
const base = prev ?? strokeOf(DEFAULT_STROKE_COLOR);
|
|
11777
|
-
return { ...base, paint: paintWithAlpha(base.paint, alpha01) };
|
|
12216
|
+
return { ...base, paint: paintWithAlpha(base.paint ?? solid(DEFAULT_STROKE_COLOR), alpha01) };
|
|
11778
12217
|
}
|
|
11779
12218
|
});
|
|
11780
12219
|
|
|
@@ -12244,6 +12683,7 @@ var KIT_STANDARD_DESCRIPTORS = [
|
|
|
12244
12683
|
clipboardCopyAction,
|
|
12245
12684
|
clipboardCutAction
|
|
12246
12685
|
];
|
|
12686
|
+
var KIT_STANDARD_ACTION_IDS = KIT_STANDARD_DESCRIPTORS.map((a) => a.id);
|
|
12247
12687
|
function useStandardActions(opts) {
|
|
12248
12688
|
const optsRef = useRef(opts);
|
|
12249
12689
|
optsRef.current = opts;
|
|
@@ -12276,13 +12716,15 @@ function useStandardActions(opts) {
|
|
|
12276
12716
|
const reg = useActionsRegistry();
|
|
12277
12717
|
const regRef = useRef(reg);
|
|
12278
12718
|
regRef.current = reg;
|
|
12719
|
+
const excludeKey = opts.exclude ? [...opts.exclude].join("\0") : "";
|
|
12279
12720
|
useEffect(() => {
|
|
12280
12721
|
if (!reg || !depReg) return;
|
|
12281
|
-
const
|
|
12722
|
+
const excluded = new Set(excludeKey ? excludeKey.split("\0") : []);
|
|
12723
|
+
const unregisters = KIT_STANDARD_DESCRIPTORS.filter((a) => !excluded.has(a.id)).map((a) => reg.register(a));
|
|
12282
12724
|
return () => {
|
|
12283
12725
|
for (const u of unregisters) u();
|
|
12284
12726
|
};
|
|
12285
|
-
}, [reg, depReg]);
|
|
12727
|
+
}, [reg, depReg, excludeKey]);
|
|
12286
12728
|
}
|
|
12287
12729
|
var IDENTITY_EXPAND2 = (ids) => ids;
|
|
12288
12730
|
var EMPTY = Object.freeze([]);
|
|
@@ -13472,7 +13914,7 @@ function withViewDeps(base, overlay) {
|
|
|
13472
13914
|
};
|
|
13473
13915
|
}
|
|
13474
13916
|
function computeMultiTouchGeometry(positions) {
|
|
13475
|
-
const pts = [...positions
|
|
13917
|
+
const pts = [...positions];
|
|
13476
13918
|
if (pts.length < 2) {
|
|
13477
13919
|
return { centroid: { x: 0, y: 0 }, spread: 0 };
|
|
13478
13920
|
}
|
|
@@ -13599,14 +14041,22 @@ function useGestureDispatcher(opts) {
|
|
|
13599
14041
|
return result;
|
|
13600
14042
|
};
|
|
13601
14043
|
const heldKeys = /* @__PURE__ */ new Set();
|
|
13602
|
-
const
|
|
13603
|
-
const
|
|
13604
|
-
|
|
14044
|
+
const held = /* @__PURE__ */ new Map();
|
|
14045
|
+
const toCanvasLocal = (p) => {
|
|
14046
|
+
const rect = canvas?.getBoundingClientRect();
|
|
14047
|
+
if (!rect) return p;
|
|
14048
|
+
const [x, y] = clientToCanvasRect(rect, p.x, p.y);
|
|
14049
|
+
return { x, y };
|
|
14050
|
+
};
|
|
14051
|
+
const heldGeometry = () => {
|
|
14052
|
+
const { centroid, spread } = computeMultiTouchGeometry(
|
|
14053
|
+
[...held.values()].map((p) => p.pos)
|
|
14054
|
+
);
|
|
14055
|
+
return { centroid: toCanvasLocal(centroid), spread };
|
|
14056
|
+
};
|
|
13605
14057
|
let multiTouchStart = null;
|
|
13606
14058
|
const TAP_THRESHOLD_PX = 8;
|
|
13607
14059
|
const DRAG_THRESHOLD_PX = 4;
|
|
13608
|
-
const bufferedDown = /* @__PURE__ */ new Map();
|
|
13609
|
-
const lastPointerDown = /* @__PURE__ */ new Map();
|
|
13610
14060
|
const LONG_PRESS_MS = 500;
|
|
13611
14061
|
const longPressTimers = /* @__PURE__ */ new Map();
|
|
13612
14062
|
const cancelLongPress = (pointerId) => {
|
|
@@ -13621,7 +14071,7 @@ function useGestureDispatcher(opts) {
|
|
|
13621
14071
|
longPressTimers.clear();
|
|
13622
14072
|
};
|
|
13623
14073
|
const fireLongPress = (pointerId) => {
|
|
13624
|
-
const down =
|
|
14074
|
+
const down = held.get(pointerId)?.down;
|
|
13625
14075
|
if (!down) return;
|
|
13626
14076
|
const shared = {
|
|
13627
14077
|
target: down.target,
|
|
@@ -13653,7 +14103,7 @@ function useGestureDispatcher(opts) {
|
|
|
13653
14103
|
const DOUBLE_CLICK_MAX_MS = 600;
|
|
13654
14104
|
const DOUBLE_CLICK_MAX_PX = 8;
|
|
13655
14105
|
const onKeyDown = (e) => {
|
|
13656
|
-
if (
|
|
14106
|
+
if (isEditableTarget(e.target)) return;
|
|
13657
14107
|
if (e.repeat && heldKeys.has(e.key)) {
|
|
13658
14108
|
e.preventDefault();
|
|
13659
14109
|
return;
|
|
@@ -13743,15 +14193,8 @@ function useGestureDispatcher(opts) {
|
|
|
13743
14193
|
};
|
|
13744
14194
|
const onPointerDown = (e) => {
|
|
13745
14195
|
if ((e.button ?? 0) !== 0) return;
|
|
13746
|
-
if (
|
|
14196
|
+
if (!canvas) return;
|
|
13747
14197
|
routeDown(e.pointerId, e.clientX, e.clientY);
|
|
13748
|
-
activePointers.add(e.pointerId);
|
|
13749
|
-
if (reportsButtons(e)) buttonsReportedFor.add(e.pointerId);
|
|
13750
|
-
pointerPositions.set(e.pointerId, { x: e.clientX, y: e.clientY });
|
|
13751
|
-
try {
|
|
13752
|
-
canvas?.setPointerCapture?.(e.pointerId);
|
|
13753
|
-
} catch {
|
|
13754
|
-
}
|
|
13755
14198
|
const worldPoint = { x: e.clientX, y: e.clientY };
|
|
13756
14199
|
const affordance = target().affordanceAt?.(worldPoint) ?? void 0;
|
|
13757
14200
|
const body = target().classifyTarget?.(worldPoint);
|
|
@@ -13773,25 +14216,37 @@ function useGestureDispatcher(opts) {
|
|
|
13773
14216
|
...stylusOf(e),
|
|
13774
14217
|
...affordance !== void 0 ? { affordance } : {},
|
|
13775
14218
|
...bodyTarget !== void 0 ? { bodyTarget } : {},
|
|
13776
|
-
...bodyKind !== void 0 ? { bodyKind } : {}
|
|
13777
|
-
};
|
|
13778
|
-
|
|
13779
|
-
|
|
13780
|
-
|
|
13781
|
-
|
|
13782
|
-
|
|
13783
|
-
|
|
13784
|
-
|
|
13785
|
-
|
|
13786
|
-
|
|
13787
|
-
|
|
13788
|
-
|
|
13789
|
-
|
|
13790
|
-
|
|
13791
|
-
|
|
13792
|
-
|
|
14219
|
+
...bodyKind !== void 0 ? { bodyKind } : {}
|
|
14220
|
+
};
|
|
14221
|
+
held.set(e.pointerId, {
|
|
14222
|
+
session: openPointerSession(canvas, e, {
|
|
14223
|
+
onMove: onPointerMove,
|
|
14224
|
+
onEnd: onPointerUp,
|
|
14225
|
+
onCancel: () => {
|
|
14226
|
+
onPointerCancel(e.pointerId);
|
|
14227
|
+
}
|
|
14228
|
+
}),
|
|
14229
|
+
pos: { x: e.clientX, y: e.clientY },
|
|
14230
|
+
// Deferred until the first past-threshold pointermove: a bare
|
|
14231
|
+
// press-and-release should fire `click`, not start a drag action.
|
|
14232
|
+
buffered: { ev, clientX: e.clientX, clientY: e.clientY },
|
|
14233
|
+
down: {
|
|
14234
|
+
target: e.target,
|
|
14235
|
+
clientX: e.clientX,
|
|
14236
|
+
clientY: e.clientY,
|
|
14237
|
+
worldX: w.x,
|
|
14238
|
+
worldY: w.y,
|
|
14239
|
+
affordance,
|
|
14240
|
+
bodyTarget,
|
|
14241
|
+
bodyKind,
|
|
14242
|
+
altKey: e.altKey,
|
|
14243
|
+
ctrlKey: e.ctrlKey,
|
|
14244
|
+
metaKey: e.metaKey,
|
|
14245
|
+
shiftKey: e.shiftKey
|
|
14246
|
+
}
|
|
13793
14247
|
});
|
|
13794
|
-
|
|
14248
|
+
dispatch2({ ...ev, stage: "press" });
|
|
14249
|
+
if ((e.pointerType === "touch" || e.pointerType === "pen") && held.size === 1) {
|
|
13795
14250
|
cancelLongPress(e.pointerId);
|
|
13796
14251
|
longPressTimers.set(
|
|
13797
14252
|
e.pointerId,
|
|
@@ -13802,18 +14257,18 @@ function useGestureDispatcher(opts) {
|
|
|
13802
14257
|
}, LONG_PRESS_MS)
|
|
13803
14258
|
);
|
|
13804
14259
|
}
|
|
13805
|
-
if (
|
|
14260
|
+
if (held.size >= 2) {
|
|
13806
14261
|
cancelAllLongPress();
|
|
13807
|
-
for (const
|
|
13808
|
-
const { centroid, spread } =
|
|
14262
|
+
for (const p of held.values()) p.buffered = null;
|
|
14263
|
+
const { centroid, spread } = heldGeometry();
|
|
13809
14264
|
if (!multiTouchStart) {
|
|
13810
|
-
multiTouchStart = { fingers:
|
|
14265
|
+
multiTouchStart = { fingers: held.size, centroid: { ...centroid } };
|
|
13811
14266
|
} else {
|
|
13812
|
-
multiTouchStart.fingers =
|
|
14267
|
+
multiTouchStart.fingers = held.size;
|
|
13813
14268
|
}
|
|
13814
14269
|
const mt = {
|
|
13815
14270
|
kind: "multitouch",
|
|
13816
|
-
fingers:
|
|
14271
|
+
fingers: held.size,
|
|
13817
14272
|
altKey: e.altKey,
|
|
13818
14273
|
ctrlKey: e.ctrlKey,
|
|
13819
14274
|
metaKey: e.metaKey,
|
|
@@ -13825,30 +14280,25 @@ function useGestureDispatcher(opts) {
|
|
|
13825
14280
|
}
|
|
13826
14281
|
};
|
|
13827
14282
|
const onPointerMove = (e) => {
|
|
13828
|
-
if (activePointers.has(e.pointerId) && buttonsReportedFor.has(e.pointerId) && isMissedRelease(e)) {
|
|
13829
|
-
onPointerUp(e);
|
|
13830
|
-
return;
|
|
13831
|
-
}
|
|
13832
14283
|
routeAt(e.pointerId, e.clientX, e.clientY);
|
|
13833
|
-
|
|
13834
|
-
|
|
13835
|
-
|
|
13836
|
-
|
|
13837
|
-
if (buffered) {
|
|
14284
|
+
const rec = held.get(e.pointerId);
|
|
14285
|
+
if (rec) rec.pos = { x: e.clientX, y: e.clientY };
|
|
14286
|
+
const buffered = rec?.buffered;
|
|
14287
|
+
if (rec && buffered) {
|
|
13838
14288
|
const dx = e.clientX - buffered.clientX;
|
|
13839
14289
|
const dy = e.clientY - buffered.clientY;
|
|
13840
14290
|
if (Math.hypot(dx, dy) >= DRAG_THRESHOLD_PX) {
|
|
13841
|
-
|
|
14291
|
+
rec.buffered = null;
|
|
13842
14292
|
cancelLongPress(e.pointerId);
|
|
13843
14293
|
dispatch2(buffered.ev);
|
|
13844
14294
|
}
|
|
13845
14295
|
}
|
|
13846
|
-
const mtGestureId = `multitouch-${
|
|
13847
|
-
if (
|
|
13848
|
-
const { centroid, spread } =
|
|
14296
|
+
const mtGestureId = `multitouch-${held.size}`;
|
|
14297
|
+
if (held.size >= 2 && dispatcherNow().inFlight().has(mtGestureId)) {
|
|
14298
|
+
const { centroid, spread } = heldGeometry();
|
|
13849
14299
|
const mtEv = {
|
|
13850
14300
|
kind: "multitouch",
|
|
13851
|
-
fingers:
|
|
14301
|
+
fingers: held.size,
|
|
13852
14302
|
altKey: e.altKey,
|
|
13853
14303
|
ctrlKey: e.ctrlKey,
|
|
13854
14304
|
metaKey: e.metaKey,
|
|
@@ -13920,7 +14370,7 @@ function useGestureDispatcher(opts) {
|
|
|
13920
14370
|
}
|
|
13921
14371
|
function resolveHoverCursor() {
|
|
13922
14372
|
if (!canvas || !lastHover) return;
|
|
13923
|
-
if (
|
|
14373
|
+
if (held.size > 0 || dispatcherNow().inFlight().size > 0) {
|
|
13924
14374
|
applyHoverCursor(dispatcherNow().inFlightCursor());
|
|
13925
14375
|
return;
|
|
13926
14376
|
}
|
|
@@ -13968,6 +14418,10 @@ function useGestureDispatcher(opts) {
|
|
|
13968
14418
|
if (!disposed) refreshHoverCursor();
|
|
13969
14419
|
}, 0);
|
|
13970
14420
|
};
|
|
14421
|
+
const onHoverMove = (e) => {
|
|
14422
|
+
if (held.has(e.pointerId)) return;
|
|
14423
|
+
onPointerMove(e);
|
|
14424
|
+
};
|
|
13971
14425
|
const onHoverPointerLeave = () => {
|
|
13972
14426
|
lastHover = null;
|
|
13973
14427
|
paintedCursorRef.current?.()?.clearPointer();
|
|
@@ -13976,21 +14430,23 @@ function useGestureDispatcher(opts) {
|
|
|
13976
14430
|
const onPointerUp = (e) => {
|
|
13977
14431
|
routeAt(e.pointerId, e.clientX, e.clientY);
|
|
13978
14432
|
cancelLongPress(e.pointerId);
|
|
13979
|
-
const prevSize =
|
|
13980
|
-
|
|
13981
|
-
|
|
13982
|
-
|
|
13983
|
-
|
|
13984
|
-
if (prevSize >= 2 && activePointers.size < 2) {
|
|
14433
|
+
const prevSize = held.size;
|
|
14434
|
+
const rec = held.get(e.pointerId);
|
|
14435
|
+
held.delete(e.pointerId);
|
|
14436
|
+
const staysUnderThreshold = rec?.buffered != null;
|
|
14437
|
+
if (prevSize >= 2 && held.size < 2) {
|
|
13985
14438
|
const mtGestureId = `multitouch-${prevSize}`;
|
|
13986
14439
|
if (dispatcherNow().inFlight().has(mtGestureId)) {
|
|
13987
14440
|
dispatcherNow().cancelAll("commit");
|
|
13988
14441
|
}
|
|
13989
14442
|
const start = multiTouchStart;
|
|
13990
14443
|
if (start) {
|
|
13991
|
-
const
|
|
13992
|
-
|
|
13993
|
-
|
|
14444
|
+
const centroid = toCanvasLocal(
|
|
14445
|
+
computeMultiTouchGeometry([
|
|
14446
|
+
...[...held.values()].map((p) => p.pos),
|
|
14447
|
+
{ x: e.clientX, y: e.clientY }
|
|
14448
|
+
]).centroid
|
|
14449
|
+
);
|
|
13994
14450
|
const dx = centroid.x - start.centroid.x;
|
|
13995
14451
|
const dy = centroid.y - start.centroid.y;
|
|
13996
14452
|
if (Math.hypot(dx, dy) <= TAP_THRESHOLD_PX) {
|
|
@@ -14007,8 +14463,7 @@ function useGestureDispatcher(opts) {
|
|
|
14007
14463
|
multiTouchStart = null;
|
|
14008
14464
|
}
|
|
14009
14465
|
}
|
|
14010
|
-
const
|
|
14011
|
-
const movedDuringDrag = downForClick ? downForClick.clientX !== e.clientX || downForClick.clientY !== e.clientY : true;
|
|
14466
|
+
const movedDuringDrag = rec ? rec.down.clientX !== e.clientX || rec.down.clientY !== e.clientY : true;
|
|
14012
14467
|
const hadDragInFlight = dispatcherNow().inFlight().has(pointerGestureId(e.pointerId)) && movedDuringDrag;
|
|
14013
14468
|
const wUp = toWorld2(e.clientX, e.clientY);
|
|
14014
14469
|
const ev = {
|
|
@@ -14024,8 +14479,7 @@ function useGestureDispatcher(opts) {
|
|
|
14024
14479
|
shiftKey: e.shiftKey
|
|
14025
14480
|
};
|
|
14026
14481
|
dispatch2(ev);
|
|
14027
|
-
const down =
|
|
14028
|
-
lastPointerDown.delete(e.pointerId);
|
|
14482
|
+
const down = rec?.down;
|
|
14029
14483
|
if (!hadDragInFlight && staysUnderThreshold && down) {
|
|
14030
14484
|
const wClick = toWorld2(e.clientX, e.clientY);
|
|
14031
14485
|
const clickEv = {
|
|
@@ -14082,30 +14536,24 @@ function useGestureDispatcher(opts) {
|
|
|
14082
14536
|
if (!disposed) refreshHoverCursor();
|
|
14083
14537
|
}, 0);
|
|
14084
14538
|
};
|
|
14085
|
-
const onPointerCancel = (
|
|
14086
|
-
|
|
14087
|
-
|
|
14088
|
-
|
|
14089
|
-
|
|
14090
|
-
|
|
14091
|
-
|
|
14092
|
-
bufferedDown.delete(e.pointerId);
|
|
14539
|
+
const onPointerCancel = (pointerId) => {
|
|
14540
|
+
if (disposed) return;
|
|
14541
|
+
const rec = held.get(pointerId);
|
|
14542
|
+
if (!rec) return;
|
|
14543
|
+
held.delete(pointerId);
|
|
14544
|
+
routeAt(pointerId, rec.pos.x, rec.pos.y);
|
|
14545
|
+
cancelLongPress(pointerId);
|
|
14093
14546
|
multiTouchStart = null;
|
|
14094
14547
|
const ev = {
|
|
14095
14548
|
kind: "pointercancel",
|
|
14096
|
-
pointerId
|
|
14097
|
-
altKey:
|
|
14098
|
-
ctrlKey:
|
|
14099
|
-
metaKey:
|
|
14100
|
-
shiftKey:
|
|
14549
|
+
pointerId,
|
|
14550
|
+
altKey: rec.down.altKey,
|
|
14551
|
+
ctrlKey: rec.down.ctrlKey,
|
|
14552
|
+
metaKey: rec.down.metaKey,
|
|
14553
|
+
shiftKey: rec.down.shiftKey
|
|
14101
14554
|
};
|
|
14102
14555
|
dispatch2(ev);
|
|
14103
|
-
routeRelease(
|
|
14104
|
-
};
|
|
14105
|
-
const onLostCapture = (e) => {
|
|
14106
|
-
const pe = e;
|
|
14107
|
-
if (!activePointers.has(pe.pointerId)) return;
|
|
14108
|
-
onPointerCancel(pe);
|
|
14556
|
+
routeRelease(pointerId);
|
|
14109
14557
|
};
|
|
14110
14558
|
const onContextMenu = (e) => {
|
|
14111
14559
|
e.preventDefault();
|
|
@@ -14167,7 +14615,7 @@ function useGestureDispatcher(opts) {
|
|
|
14167
14615
|
});
|
|
14168
14616
|
};
|
|
14169
14617
|
const onPaste = (e) => {
|
|
14170
|
-
if (
|
|
14618
|
+
if (isEditableTarget(e.target)) return;
|
|
14171
14619
|
const cd = e.clipboardData;
|
|
14172
14620
|
if (!cd) return;
|
|
14173
14621
|
const items = itemsFromClipboardData(cd);
|
|
@@ -14193,10 +14641,7 @@ function useGestureDispatcher(opts) {
|
|
|
14193
14641
|
canvas?.addEventListener("pointerleave", onHoverPointerLeave);
|
|
14194
14642
|
canvas?.addEventListener("wheel", onWheel, { passive: false });
|
|
14195
14643
|
canvas?.addEventListener("pointerdown", onPointerDown);
|
|
14196
|
-
canvas?.addEventListener("pointermove",
|
|
14197
|
-
canvas?.addEventListener("pointerup", onPointerUp);
|
|
14198
|
-
canvas?.addEventListener("pointercancel", onPointerCancel);
|
|
14199
|
-
canvas?.addEventListener(LOST_CAPTURE_EVENT, onLostCapture);
|
|
14644
|
+
canvas?.addEventListener("pointermove", onHoverMove);
|
|
14200
14645
|
canvas?.addEventListener("contextmenu", onContextMenu);
|
|
14201
14646
|
canvas?.addEventListener("dragenter", onDragOver);
|
|
14202
14647
|
canvas?.addEventListener("dragover", onDragOver);
|
|
@@ -14214,10 +14659,7 @@ function useGestureDispatcher(opts) {
|
|
|
14214
14659
|
canvas?.removeEventListener("pointerleave", onHoverPointerLeave);
|
|
14215
14660
|
canvas?.removeEventListener("wheel", onWheel);
|
|
14216
14661
|
canvas?.removeEventListener("pointerdown", onPointerDown);
|
|
14217
|
-
canvas?.removeEventListener("pointermove",
|
|
14218
|
-
canvas?.removeEventListener("pointerup", onPointerUp);
|
|
14219
|
-
canvas?.removeEventListener("pointercancel", onPointerCancel);
|
|
14220
|
-
canvas?.removeEventListener(LOST_CAPTURE_EVENT, onLostCapture);
|
|
14662
|
+
canvas?.removeEventListener("pointermove", onHoverMove);
|
|
14221
14663
|
canvas?.removeEventListener("contextmenu", onContextMenu);
|
|
14222
14664
|
canvas?.removeEventListener("dragenter", onDragOver);
|
|
14223
14665
|
canvas?.removeEventListener("dragover", onDragOver);
|
|
@@ -14228,37 +14670,12 @@ function useGestureDispatcher(opts) {
|
|
|
14228
14670
|
clearHoverCursor();
|
|
14229
14671
|
cancelAllLongPress();
|
|
14230
14672
|
disposed = true;
|
|
14673
|
+
for (const p of held.values()) p.session.cancel();
|
|
14674
|
+
held.clear();
|
|
14231
14675
|
for (const d of allDispatchers()) d.cancelAll("cancel");
|
|
14232
14676
|
};
|
|
14233
14677
|
}, [enabled, keyboard, canvasRef]);
|
|
14234
14678
|
}
|
|
14235
|
-
|
|
14236
|
-
// src/core/viewport/wheelHandler.ts
|
|
14237
|
-
function computeWheelAction(state, input, bounds = { min: DEFAULT_MIN_ZOOM, max: DEFAULT_MAX_ZOOM }) {
|
|
14238
|
-
if (input.shiftKey) {
|
|
14239
|
-
return {
|
|
14240
|
-
zoom: state.zoom,
|
|
14241
|
-
panX: state.panX - input.deltaY,
|
|
14242
|
-
panY: state.panY
|
|
14243
|
-
};
|
|
14244
|
-
}
|
|
14245
|
-
if (input.metaKey) {
|
|
14246
|
-
return {
|
|
14247
|
-
zoom: state.zoom,
|
|
14248
|
-
panX: state.panX,
|
|
14249
|
-
panY: state.panY - input.deltaY
|
|
14250
|
-
};
|
|
14251
|
-
}
|
|
14252
|
-
const factor = input.deltaY < 0 ? 1.1 : 0.9;
|
|
14253
|
-
const newZoom = Math.min(bounds.max, Math.max(bounds.min, state.zoom * factor));
|
|
14254
|
-
const worldX = (input.mouseX - state.panX) / state.zoom;
|
|
14255
|
-
const worldY = (input.mouseY - state.panY) / state.zoom;
|
|
14256
|
-
return {
|
|
14257
|
-
zoom: newZoom,
|
|
14258
|
-
panX: input.mouseX - worldX * newZoom,
|
|
14259
|
-
panY: input.mouseY - worldY * newZoom
|
|
14260
|
-
};
|
|
14261
|
-
}
|
|
14262
14679
|
function useVelocityTracker() {
|
|
14263
14680
|
return useMemo(() => createVelocityTracker(), []);
|
|
14264
14681
|
}
|
|
@@ -16383,85 +16800,64 @@ function UnknownIcon({ className, size = 20 }) {
|
|
|
16383
16800
|
}
|
|
16384
16801
|
);
|
|
16385
16802
|
}
|
|
16386
|
-
function
|
|
16387
|
-
const flat = new Array(poly2.length * 2);
|
|
16388
|
-
for (let i = 0; i < poly2.length; i++) {
|
|
16389
|
-
flat[i * 2] = poly2[i].x;
|
|
16390
|
-
flat[i * 2 + 1] = poly2[i].y;
|
|
16391
|
-
}
|
|
16392
|
-
return flat;
|
|
16393
|
-
}
|
|
16394
|
-
function polygonContainsRectCenter(poly2, rect) {
|
|
16395
|
-
return pointInPolygon(flattenVerts(poly2), rect.x + rect.width / 2, rect.y + rect.height / 2);
|
|
16396
|
-
}
|
|
16397
|
-
function polygonContainsRect(poly2, rect) {
|
|
16398
|
-
if (poly2.length < 3) return false;
|
|
16399
|
-
const flat = flattenVerts(poly2);
|
|
16400
|
-
if (!pointInPolygon(flat, rect.x, rect.y)) return false;
|
|
16401
|
-
if (!pointInPolygon(flat, rect.x + rect.width, rect.y)) return false;
|
|
16402
|
-
if (!pointInPolygon(flat, rect.x + rect.width, rect.y + rect.height)) return false;
|
|
16403
|
-
if (!pointInPolygon(flat, rect.x, rect.y + rect.height)) return false;
|
|
16404
|
-
return !anyPolyEdgeCrossesRect(poly2, rect);
|
|
16405
|
-
}
|
|
16406
|
-
function polygonIntersectsRect(poly2, rect) {
|
|
16407
|
-
if (poly2.length < 3) return false;
|
|
16408
|
-
const ab = polygonAabb(poly2);
|
|
16409
|
-
if (ab.x + ab.width < rect.x || ab.x > rect.x + rect.width) return false;
|
|
16410
|
-
if (ab.y + ab.height < rect.y || ab.y > rect.y + rect.height) return false;
|
|
16411
|
-
for (const v of poly2) {
|
|
16412
|
-
if (v.x >= rect.x && v.x <= rect.x + rect.width && v.y >= rect.y && v.y <= rect.y + rect.height) return true;
|
|
16413
|
-
}
|
|
16414
|
-
const flat = flattenVerts(poly2);
|
|
16415
|
-
if (pointInPolygon(flat, rect.x, rect.y)) return true;
|
|
16416
|
-
if (pointInPolygon(flat, rect.x + rect.width, rect.y)) return true;
|
|
16417
|
-
if (pointInPolygon(flat, rect.x + rect.width, rect.y + rect.height)) return true;
|
|
16418
|
-
if (pointInPolygon(flat, rect.x, rect.y + rect.height)) return true;
|
|
16419
|
-
return anyPolyEdgeCrossesRect(poly2, rect);
|
|
16420
|
-
}
|
|
16421
|
-
function polygonAabb(poly2) {
|
|
16422
|
-
let minX = Infinity, minY = Infinity, maxX = -Infinity, maxY = -Infinity;
|
|
16423
|
-
for (const v of poly2) {
|
|
16424
|
-
if (v.x < minX) minX = v.x;
|
|
16425
|
-
if (v.y < minY) minY = v.y;
|
|
16426
|
-
if (v.x > maxX) maxX = v.x;
|
|
16427
|
-
if (v.y > maxY) maxY = v.y;
|
|
16428
|
-
}
|
|
16429
|
-
return { x: minX, y: minY, width: maxX - minX, height: maxY - minY };
|
|
16430
|
-
}
|
|
16431
|
-
function anyPolyEdgeCrossesRect(poly2, rect) {
|
|
16432
|
-
const r0x = rect.x, r0y = rect.y;
|
|
16433
|
-
const r1x = rect.x + rect.width, r1y = rect.y;
|
|
16434
|
-
const r2x = rect.x + rect.width, r2y = rect.y + rect.height;
|
|
16435
|
-
const r3x = rect.x, r3y = rect.y + rect.height;
|
|
16436
|
-
for (let i = 0, j = poly2.length - 1; i < poly2.length; j = i++) {
|
|
16437
|
-
const a = poly2[j], b = poly2[i];
|
|
16438
|
-
if (segmentsCross(a.x, a.y, b.x, b.y, r0x, r0y, r1x, r1y)) return true;
|
|
16439
|
-
if (segmentsCross(a.x, a.y, b.x, b.y, r1x, r1y, r2x, r2y)) return true;
|
|
16440
|
-
if (segmentsCross(a.x, a.y, b.x, b.y, r2x, r2y, r3x, r3y)) return true;
|
|
16441
|
-
if (segmentsCross(a.x, a.y, b.x, b.y, r3x, r3y, r0x, r0y)) return true;
|
|
16442
|
-
}
|
|
16443
|
-
return false;
|
|
16444
|
-
}
|
|
16445
|
-
|
|
16446
|
-
// src/features/paths/pathHitTest.ts
|
|
16447
|
-
function extractVertices(path) {
|
|
16803
|
+
function closedSubpaths(path, tolerance) {
|
|
16448
16804
|
const { commands, coords } = path;
|
|
16449
|
-
const
|
|
16805
|
+
const out = [];
|
|
16806
|
+
let sub2 = [];
|
|
16807
|
+
let subStartX = 0, subStartY = 0;
|
|
16808
|
+
let curX = 0, curY = 0;
|
|
16450
16809
|
let ci = 0;
|
|
16451
16810
|
for (let i = 0; i < commands.length; i++) {
|
|
16452
16811
|
const cmd = commands[i];
|
|
16453
|
-
|
|
16454
|
-
|
|
16455
|
-
|
|
16456
|
-
|
|
16457
|
-
|
|
16458
|
-
|
|
16459
|
-
|
|
16460
|
-
|
|
16461
|
-
|
|
16812
|
+
switch (cmd) {
|
|
16813
|
+
case PATH_M: {
|
|
16814
|
+
sub2 = [];
|
|
16815
|
+
subStartX = coords[ci];
|
|
16816
|
+
subStartY = coords[ci + 1];
|
|
16817
|
+
curX = subStartX;
|
|
16818
|
+
curY = subStartY;
|
|
16819
|
+
sub2.push(curX, curY);
|
|
16820
|
+
ci += 2;
|
|
16821
|
+
break;
|
|
16822
|
+
}
|
|
16823
|
+
case PATH_L: {
|
|
16824
|
+
curX = coords[ci];
|
|
16825
|
+
curY = coords[ci + 1];
|
|
16826
|
+
sub2.push(curX, curY);
|
|
16827
|
+
ci += 2;
|
|
16828
|
+
break;
|
|
16829
|
+
}
|
|
16830
|
+
case PATH_C: {
|
|
16831
|
+
const x1 = coords[ci], y1 = coords[ci + 1];
|
|
16832
|
+
const x2 = coords[ci + 2], y2 = coords[ci + 3];
|
|
16833
|
+
const x3 = coords[ci + 4], y3 = coords[ci + 5];
|
|
16834
|
+
flattenCubic(curX, curY, x1, y1, x2, y2, x3, y3, tolerance, sub2);
|
|
16835
|
+
curX = x3;
|
|
16836
|
+
curY = y3;
|
|
16837
|
+
ci += 6;
|
|
16838
|
+
break;
|
|
16839
|
+
}
|
|
16840
|
+
case PATH_Q: {
|
|
16841
|
+
const x1 = coords[ci], y1 = coords[ci + 1];
|
|
16842
|
+
const x2 = coords[ci + 2], y2 = coords[ci + 3];
|
|
16843
|
+
flattenQuadratic(curX, curY, x1, y1, x2, y2, tolerance, sub2);
|
|
16844
|
+
curX = x2;
|
|
16845
|
+
curY = y2;
|
|
16846
|
+
ci += 4;
|
|
16847
|
+
break;
|
|
16848
|
+
}
|
|
16849
|
+
case PATH_Z: {
|
|
16850
|
+
if (sub2.length >= 6) out.push(sub2);
|
|
16851
|
+
sub2 = [];
|
|
16852
|
+
curX = subStartX;
|
|
16853
|
+
curY = subStartY;
|
|
16854
|
+
break;
|
|
16855
|
+
}
|
|
16856
|
+
default:
|
|
16857
|
+
throw new Error(`pathHitTest: unknown command ${cmd}`);
|
|
16462
16858
|
}
|
|
16463
16859
|
}
|
|
16464
|
-
return
|
|
16860
|
+
return out;
|
|
16465
16861
|
}
|
|
16466
16862
|
function rectToVerts(r) {
|
|
16467
16863
|
return [
|
|
@@ -16471,7 +16867,7 @@ function rectToVerts(r) {
|
|
|
16471
16867
|
{ x: r.x, y: r.y + r.height }
|
|
16472
16868
|
];
|
|
16473
16869
|
}
|
|
16474
|
-
function
|
|
16870
|
+
function flattenVerts(poly2) {
|
|
16475
16871
|
const flat = new Array(poly2.length * 2);
|
|
16476
16872
|
for (let i = 0; i < poly2.length; i++) {
|
|
16477
16873
|
flat[i * 2] = poly2[i].x;
|
|
@@ -16479,15 +16875,10 @@ function flattenVerts2(poly2) {
|
|
|
16479
16875
|
}
|
|
16480
16876
|
return flat;
|
|
16481
16877
|
}
|
|
16482
|
-
function polygonContainsPolygon(outer, inner) {
|
|
16483
|
-
if (inner.length === 0) return false;
|
|
16484
|
-
const flatOuter = flattenVerts2(outer);
|
|
16485
|
-
return inner.every((p) => pointInPolygon(flatOuter, p.x, p.y));
|
|
16486
|
-
}
|
|
16487
16878
|
function polygonsIntersect(a, b) {
|
|
16488
16879
|
if (a.length === 0 || b.length === 0) return false;
|
|
16489
|
-
if (pointInPolygon(
|
|
16490
|
-
if (pointInPolygon(
|
|
16880
|
+
if (pointInPolygon(flattenVerts(a), b[0].x, b[0].y)) return true;
|
|
16881
|
+
if (pointInPolygon(flattenVerts(b), a[0].x, a[0].y)) return true;
|
|
16491
16882
|
for (let i = 0; i < a.length; i++) {
|
|
16492
16883
|
const a0 = a[i], a1 = a[(i + 1) % a.length];
|
|
16493
16884
|
for (let j = 0; j < b.length; j++) {
|
|
@@ -16497,35 +16888,105 @@ function polygonsIntersect(a, b) {
|
|
|
16497
16888
|
}
|
|
16498
16889
|
return false;
|
|
16499
16890
|
}
|
|
16500
|
-
function
|
|
16501
|
-
|
|
16891
|
+
function anyEdge(subpaths, visit) {
|
|
16892
|
+
for (const sub2 of subpaths) {
|
|
16893
|
+
const n = sub2.length;
|
|
16894
|
+
for (let i = 0; i < n; i += 2) {
|
|
16895
|
+
const j = (i + 2) % n;
|
|
16896
|
+
if (visit(sub2[i], sub2[i + 1], sub2[j], sub2[j + 1])) return true;
|
|
16897
|
+
}
|
|
16898
|
+
}
|
|
16899
|
+
return false;
|
|
16900
|
+
}
|
|
16901
|
+
function anyEdgeCrossesRect(subpaths, r) {
|
|
16902
|
+
const x0 = r.x, y0 = r.y, x1 = r.x + r.width, y1 = r.y + r.height;
|
|
16903
|
+
return anyEdge(
|
|
16904
|
+
subpaths,
|
|
16905
|
+
(ax, ay, bx, by) => segmentsCross(ax, ay, bx, by, x0, y0, x1, y0) || segmentsCross(ax, ay, bx, by, x1, y0, x1, y1) || segmentsCross(ax, ay, bx, by, x1, y1, x0, y1) || segmentsCross(ax, ay, bx, by, x0, y1, x0, y0)
|
|
16906
|
+
);
|
|
16907
|
+
}
|
|
16908
|
+
function anyEdgeCrossesPolygon(subpaths, poly2) {
|
|
16909
|
+
if (poly2.length === 0) return false;
|
|
16910
|
+
return anyEdge(subpaths, (ax, ay, bx, by) => {
|
|
16911
|
+
for (let i = 0; i < poly2.length; i++) {
|
|
16912
|
+
const p0 = poly2[i], p1 = poly2[(i + 1) % poly2.length];
|
|
16913
|
+
if (segmentsCross(ax, ay, bx, by, p0.x, p0.y, p1.x, p1.y)) return true;
|
|
16914
|
+
}
|
|
16915
|
+
return false;
|
|
16916
|
+
});
|
|
16917
|
+
}
|
|
16918
|
+
function anyVertexInRect(subpaths, r) {
|
|
16919
|
+
for (const sub2 of subpaths) {
|
|
16920
|
+
for (let i = 0; i < sub2.length; i += 2) {
|
|
16921
|
+
const x = sub2[i], y = sub2[i + 1];
|
|
16922
|
+
if (x >= r.x && x <= r.x + r.width && y >= r.y && y <= r.y + r.height) return true;
|
|
16923
|
+
}
|
|
16924
|
+
}
|
|
16925
|
+
return false;
|
|
16926
|
+
}
|
|
16927
|
+
function anyVertexInPolygon(subpaths, flatPoly) {
|
|
16928
|
+
for (const sub2 of subpaths) {
|
|
16929
|
+
for (let i = 0; i < sub2.length; i += 2) {
|
|
16930
|
+
if (pointInPolygon(flatPoly, sub2[i], sub2[i + 1])) return true;
|
|
16931
|
+
}
|
|
16932
|
+
}
|
|
16933
|
+
return false;
|
|
16934
|
+
}
|
|
16935
|
+
function subpathsOf(path, opts) {
|
|
16936
|
+
return closedSubpaths(path, opts.tolerance ?? DEFAULT_FLATTEN_TOLERANCE);
|
|
16937
|
+
}
|
|
16938
|
+
function pathContainsPoint(path, x, y, opts = {}) {
|
|
16939
|
+
return pointInPath(path, x, y, opts);
|
|
16502
16940
|
}
|
|
16503
|
-
function pathContainsRect(path, rect) {
|
|
16941
|
+
function pathContainsRect(path, rect, opts = {}) {
|
|
16504
16942
|
if (path.kind === "rect") {
|
|
16505
16943
|
return rect.x >= path.x && rect.y >= path.y && rect.x + rect.width <= path.x + path.width && rect.y + rect.height <= path.y + path.height;
|
|
16506
16944
|
}
|
|
16507
|
-
|
|
16945
|
+
const subpaths = subpathsOf(path, opts);
|
|
16946
|
+
if (subpaths.length === 0) return false;
|
|
16947
|
+
for (const c of rectToVerts(rect)) {
|
|
16948
|
+
if (!pointInPath(path, c.x, c.y, opts)) return false;
|
|
16949
|
+
}
|
|
16950
|
+
return !anyVertexInRect(subpaths, rect) && !anyEdgeCrossesRect(subpaths, rect);
|
|
16508
16951
|
}
|
|
16509
|
-
function pathIntersectsRect(path, rect) {
|
|
16952
|
+
function pathIntersectsRect(path, rect, opts = {}) {
|
|
16510
16953
|
if (path.kind === "rect") {
|
|
16511
16954
|
return rect.x < path.x + path.width && rect.x + rect.width > path.x && rect.y < path.y + path.height && rect.y + rect.height > path.y;
|
|
16512
16955
|
}
|
|
16513
|
-
|
|
16956
|
+
const subpaths = subpathsOf(path, opts);
|
|
16957
|
+
if (subpaths.length === 0) return false;
|
|
16958
|
+
for (const c of rectToVerts(rect)) {
|
|
16959
|
+
if (pointInPath(path, c.x, c.y, opts)) return true;
|
|
16960
|
+
}
|
|
16961
|
+
if (anyVertexInRect(subpaths, rect)) return true;
|
|
16962
|
+
return anyEdgeCrossesRect(subpaths, rect);
|
|
16514
16963
|
}
|
|
16515
|
-
function pathContainsPolygon(path, polygon) {
|
|
16964
|
+
function pathContainsPolygon(path, polygon, opts = {}) {
|
|
16516
16965
|
if (polygon.length === 0) return false;
|
|
16517
16966
|
if (path.kind === "rect") {
|
|
16518
16967
|
return polygon.every(
|
|
16519
16968
|
(p) => p.x >= path.x && p.x <= path.x + path.width && p.y >= path.y && p.y <= path.y + path.height
|
|
16520
16969
|
);
|
|
16521
16970
|
}
|
|
16522
|
-
|
|
16971
|
+
const subpaths = subpathsOf(path, opts);
|
|
16972
|
+
if (subpaths.length === 0) return false;
|
|
16973
|
+
for (const p of polygon) {
|
|
16974
|
+
if (!pointInPath(path, p.x, p.y, opts)) return false;
|
|
16975
|
+
}
|
|
16976
|
+
return !anyVertexInPolygon(subpaths, flattenVerts(polygon)) && !anyEdgeCrossesPolygon(subpaths, polygon);
|
|
16523
16977
|
}
|
|
16524
|
-
function pathIntersectsPolygon(path, polygon) {
|
|
16978
|
+
function pathIntersectsPolygon(path, polygon, opts = {}) {
|
|
16979
|
+
if (polygon.length === 0) return false;
|
|
16525
16980
|
if (path.kind === "rect") {
|
|
16526
16981
|
return polygonsIntersect(rectToVerts(path), polygon);
|
|
16527
16982
|
}
|
|
16528
|
-
|
|
16983
|
+
const subpaths = subpathsOf(path, opts);
|
|
16984
|
+
if (subpaths.length === 0) return false;
|
|
16985
|
+
for (const p of polygon) {
|
|
16986
|
+
if (pointInPath(path, p.x, p.y, opts)) return true;
|
|
16987
|
+
}
|
|
16988
|
+
if (anyVertexInPolygon(subpaths, flattenVerts(polygon))) return true;
|
|
16989
|
+
return anyEdgeCrossesPolygon(subpaths, polygon);
|
|
16529
16990
|
}
|
|
16530
16991
|
|
|
16531
16992
|
// src/features/paths/markerSites.ts
|
|
@@ -16918,10 +17379,11 @@ var TEXT_PAINTER = {
|
|
|
16918
17379
|
if (boxes.length === 0) return null;
|
|
16919
17380
|
return rectsToPath(boxes);
|
|
16920
17381
|
},
|
|
16921
|
-
// `filled` is unconditional
|
|
16922
|
-
//
|
|
16923
|
-
//
|
|
16924
|
-
//
|
|
17382
|
+
// `filled` is unconditional, `data.fill: null` included: the silhouette
|
|
17383
|
+
// above is line boxes, not glyph ink, so reporting outline-only text as
|
|
17384
|
+
// unfilled would leave it grabbable within a stroke width of a box edge and
|
|
17385
|
+
// nowhere near the letters. The reach still matters — a heavily outlined
|
|
17386
|
+
// glyph was unpickable across the width of its own outline.
|
|
16925
17387
|
ink: (node, _pose, ctx) => {
|
|
16926
17388
|
const d = node.data;
|
|
16927
17389
|
return { filled: true, ...inkReach(resolveNodeStroke(d.stroke), ctx?.scale) };
|
|
@@ -16957,7 +17419,7 @@ function resolveNodeFill(fill, fallback) {
|
|
|
16957
17419
|
return fill === void 0 ? fallback : fill;
|
|
16958
17420
|
}
|
|
16959
17421
|
function resolveNodeStroke(stroke) {
|
|
16960
|
-
if (stroke
|
|
17422
|
+
if (stroke?.paint == null) return null;
|
|
16961
17423
|
return stroke;
|
|
16962
17424
|
}
|
|
16963
17425
|
function strokeInPoseFrame(stroke, box) {
|
|
@@ -18079,6 +18541,7 @@ function worldOf(region, xf, view) {
|
|
|
18079
18541
|
}
|
|
18080
18542
|
|
|
18081
18543
|
// src/affordances/rotationHandle.ts
|
|
18544
|
+
var isAnnulusForm = (paint) => "fill" in paint || "stroke" in paint || "insetPx" in paint;
|
|
18082
18545
|
var DEFAULT_PAINT = {
|
|
18083
18546
|
fill: { fill: "solid", color: "rgba(26, 19, 13, 0.12)" },
|
|
18084
18547
|
insetPx: 10
|
|
@@ -18087,7 +18550,7 @@ function createRotationAffordance(opts = {}) {
|
|
|
18087
18550
|
const { bandPx = 24, paint = DEFAULT_PAINT, cursor } = opts;
|
|
18088
18551
|
const annulusPaint = (() => {
|
|
18089
18552
|
if (!paint) return null;
|
|
18090
|
-
if (
|
|
18553
|
+
if (!isAnnulusForm(paint)) {
|
|
18091
18554
|
return { kind: "annulus", stroke: paint };
|
|
18092
18555
|
}
|
|
18093
18556
|
return {
|
|
@@ -18283,29 +18746,6 @@ function useTextTool() {
|
|
|
18283
18746
|
[]
|
|
18284
18747
|
);
|
|
18285
18748
|
}
|
|
18286
|
-
function usePinchZoomTool(canvasRef, getView, setView, opts = {}) {
|
|
18287
|
-
const getViewRef = useRef(getView);
|
|
18288
|
-
getViewRef.current = getView;
|
|
18289
|
-
const setViewRef = useRef(setView);
|
|
18290
|
-
setViewRef.current = setView;
|
|
18291
|
-
const { min = DEFAULT_MIN_ZOOM, max = DEFAULT_MAX_ZOOM, enabled = true } = opts;
|
|
18292
|
-
const resolveTargetRef = useRef(opts.resolveTarget);
|
|
18293
|
-
resolveTargetRef.current = opts.resolveTarget;
|
|
18294
|
-
usePinchGesture(canvasRef, (clientAnchor, scaleFactor) => {
|
|
18295
|
-
const el = canvasRef.current;
|
|
18296
|
-
if (!el) return;
|
|
18297
|
-
const target = resolveTargetRef.current?.(clientAnchor.x, clientAnchor.y) ?? null;
|
|
18298
|
-
let anchor;
|
|
18299
|
-
if (target) {
|
|
18300
|
-
anchor = { x: clientAnchor.x - target.origin.left, y: clientAnchor.y - target.origin.top };
|
|
18301
|
-
} else {
|
|
18302
|
-
const [cx, cy] = clientToCanvas(el, clientAnchor.x, clientAnchor.y);
|
|
18303
|
-
anchor = { x: cx, y: cy };
|
|
18304
|
-
}
|
|
18305
|
-
const newView = zoomAt(target?.view ?? getViewRef.current(), anchor, scaleFactor, { min, max });
|
|
18306
|
-
(target ? target.setView : setViewRef.current)(newView);
|
|
18307
|
-
}, enabled);
|
|
18308
|
-
}
|
|
18309
18749
|
|
|
18310
18750
|
// src/util/constrainTo45.ts
|
|
18311
18751
|
function constrainTo45(dx, dy) {
|
|
@@ -20621,7 +21061,6 @@ function CanvasInner(props, ref) {
|
|
|
20621
21061
|
previewIdsExtra,
|
|
20622
21062
|
previewPoseExtra,
|
|
20623
21063
|
gestureSource,
|
|
20624
|
-
viewport,
|
|
20625
21064
|
backgroundFill,
|
|
20626
21065
|
cursorCoordsHud,
|
|
20627
21066
|
pickHud,
|
|
@@ -20630,7 +21069,8 @@ function CanvasInner(props, ref) {
|
|
|
20630
21069
|
decorationLayer,
|
|
20631
21070
|
getIsVisible,
|
|
20632
21071
|
layerVisibility,
|
|
20633
|
-
layerOrder
|
|
21072
|
+
layerOrder,
|
|
21073
|
+
layerGroups
|
|
20634
21074
|
} = props;
|
|
20635
21075
|
const resolvedDebugConfig = useMemo(() => {
|
|
20636
21076
|
if (debugProp === false) return null;
|
|
@@ -20783,25 +21223,7 @@ function CanvasInner(props, ref) {
|
|
|
20783
21223
|
const glRendererRef = useRef(null);
|
|
20784
21224
|
const layerCacheRef = useRef(/* @__PURE__ */ new Map());
|
|
20785
21225
|
const lastResizeRef = useRef(null);
|
|
20786
|
-
const pinchConfig = viewport?.pinchZoom === true ? {} : viewport?.pinchZoom || null;
|
|
20787
21226
|
const viewRegistry = useOptionalViewRegistry();
|
|
20788
|
-
const viewRegistryRef = useRef(viewRegistry);
|
|
20789
|
-
viewRegistryRef.current = viewRegistry;
|
|
20790
|
-
const resolvePinchTarget = useCallback((clientX, clientY) => {
|
|
20791
|
-
const reg = viewRegistryRef.current;
|
|
20792
|
-
if (!reg) return null;
|
|
20793
|
-
const target = reg.resolver.at(null, clientX, clientY);
|
|
20794
|
-
if (target.id === null) return null;
|
|
20795
|
-
const api = reg.list().find((r) => r.id === target.id)?.target.deps?.().view;
|
|
20796
|
-
if (!api) return null;
|
|
20797
|
-
return { view: api.get(), setView: api.set, origin: target.origin };
|
|
20798
|
-
}, []);
|
|
20799
|
-
usePinchZoomTool(
|
|
20800
|
-
canvasRef,
|
|
20801
|
-
getView,
|
|
20802
|
-
setView,
|
|
20803
|
-
{ ...pinchConfig ?? {}, enabled: pinchConfig !== null, resolveTarget: resolvePinchTarget }
|
|
20804
|
-
);
|
|
20805
21227
|
const noopAdapter = useMemo(
|
|
20806
21228
|
() => ({
|
|
20807
21229
|
getPose: () => ({}),
|
|
@@ -20893,6 +21315,7 @@ function CanvasInner(props, ref) {
|
|
|
20893
21315
|
const selectedIdsForWiring = effectiveSelection.current;
|
|
20894
21316
|
const {
|
|
20895
21317
|
helpers: viewHelpers,
|
|
21318
|
+
chromeState: viewChromeState,
|
|
20896
21319
|
effectiveBoundsOf,
|
|
20897
21320
|
previewExtraRef
|
|
20898
21321
|
} = useViewHelpers({
|
|
@@ -21061,6 +21484,7 @@ function CanvasInner(props, ref) {
|
|
|
21061
21484
|
dpr: dprProp,
|
|
21062
21485
|
layerVisibility,
|
|
21063
21486
|
layerOrder,
|
|
21487
|
+
layerGroups,
|
|
21064
21488
|
shaders
|
|
21065
21489
|
});
|
|
21066
21490
|
paintInputsRef.current = {
|
|
@@ -21071,6 +21495,7 @@ function CanvasInner(props, ref) {
|
|
|
21071
21495
|
dpr: dprProp,
|
|
21072
21496
|
layerVisibility,
|
|
21073
21497
|
layerOrder,
|
|
21498
|
+
layerGroups,
|
|
21074
21499
|
shaders
|
|
21075
21500
|
};
|
|
21076
21501
|
const paint = useCallback(() => {
|
|
@@ -21085,6 +21510,7 @@ function CanvasInner(props, ref) {
|
|
|
21085
21510
|
dpr: dprIn,
|
|
21086
21511
|
layerVisibility: vis,
|
|
21087
21512
|
layerOrder: order,
|
|
21513
|
+
layerGroups: groups,
|
|
21088
21514
|
shaders: paintShaders
|
|
21089
21515
|
} = paintInputsRef.current;
|
|
21090
21516
|
sink?.beginFrame();
|
|
@@ -21135,7 +21561,9 @@ function CanvasInner(props, ref) {
|
|
|
21135
21561
|
order,
|
|
21136
21562
|
view,
|
|
21137
21563
|
{ width: w, height: h },
|
|
21138
|
-
layerCacheRef.current
|
|
21564
|
+
layerCacheRef.current,
|
|
21565
|
+
void 0,
|
|
21566
|
+
groups
|
|
21139
21567
|
);
|
|
21140
21568
|
renderer.render(commands, viewToMat3(view));
|
|
21141
21569
|
paintedVersionRef.current = contentVersionRef.current?.() ?? 0;
|
|
@@ -21153,8 +21581,11 @@ function CanvasInner(props, ref) {
|
|
|
21153
21581
|
dprProp,
|
|
21154
21582
|
layerVisibility,
|
|
21155
21583
|
layerOrder,
|
|
21584
|
+
layerGroups,
|
|
21156
21585
|
shaderIdKey,
|
|
21157
21586
|
syncPaint,
|
|
21587
|
+
viewChromeState,
|
|
21588
|
+
getIsVisible,
|
|
21158
21589
|
requestRedraw
|
|
21159
21590
|
]);
|
|
21160
21591
|
useEffect(() => {
|
|
@@ -21365,6 +21796,14 @@ function createDependentsIndex() {
|
|
|
21365
21796
|
// src/core/scene/scene.ts
|
|
21366
21797
|
var defaultIdCounter = 0;
|
|
21367
21798
|
var defaultGenerateId = () => asNodeId(`n${(defaultIdCounter++).toString(36)}-${Math.random().toString(36).slice(2, 8)}`);
|
|
21799
|
+
function layerFromSerialized(spec) {
|
|
21800
|
+
const base = {
|
|
21801
|
+
id: spec.id,
|
|
21802
|
+
visible: spec.visible ?? true,
|
|
21803
|
+
locked: spec.locked ?? false
|
|
21804
|
+
};
|
|
21805
|
+
return spec.kind === "user" ? { ...base, kind: "user", name: spec.name ?? spec.id } : { ...base, kind: "system" };
|
|
21806
|
+
}
|
|
21368
21807
|
function createScene(options) {
|
|
21369
21808
|
if (!options.systemLayers || options.systemLayers.length === 0) {
|
|
21370
21809
|
throw new Error("useScene: systemLayers must declare at least one layer");
|
|
@@ -21588,6 +22027,28 @@ function createScene(options) {
|
|
|
21588
22027
|
state.nodes.get(id).derivePath = spec.derivePath;
|
|
21589
22028
|
if (cacheForRedo) pendingDerivePathPatches.set(id, spec.derivePath);
|
|
21590
22029
|
}
|
|
22030
|
+
function restoreNodeFunctions(node, keys) {
|
|
22031
|
+
if (!keys) return;
|
|
22032
|
+
if (node.derivePath === void 0 && keys.derivePathKey !== void 0) {
|
|
22033
|
+
const fn = registry2.derivePath?.[keys.derivePathKey];
|
|
22034
|
+
if (fn) {
|
|
22035
|
+
node.derivePath = fn;
|
|
22036
|
+
pendingDerivePathPatches.set(node.id, fn);
|
|
22037
|
+
} else {
|
|
22038
|
+
dwarn("scene", `kit:remove: derivePathKey "${keys.derivePathKey}" not in this scene's registry \u2014 node "${node.id}" restored without derived geometry. Register a function with this key in the registry option to restore it.`);
|
|
22039
|
+
}
|
|
22040
|
+
}
|
|
22041
|
+
if (node.kind !== "container" || keys.clipKey === void 0) return;
|
|
22042
|
+
const container = node;
|
|
22043
|
+
if (container.clipFromPose !== void 0) return;
|
|
22044
|
+
const clip = registry2.clipFromPose?.[keys.clipKey];
|
|
22045
|
+
if (clip) {
|
|
22046
|
+
container.clipFromPose = clip;
|
|
22047
|
+
pendingClipPatches.set(node.id, clip);
|
|
22048
|
+
} else {
|
|
22049
|
+
dwarn("scene", `kit:remove: clipKey "${keys.clipKey}" not in this scene's registry \u2014 container "${node.id}" restored without clip. Register a function with this key in the registry option to restore the clip.`);
|
|
22050
|
+
}
|
|
22051
|
+
}
|
|
21591
22052
|
function registerKitOp(kind, handler) {
|
|
21592
22053
|
registered.set(kind, handler);
|
|
21593
22054
|
}
|
|
@@ -21645,8 +22106,10 @@ function createScene(options) {
|
|
|
21645
22106
|
}
|
|
21646
22107
|
},
|
|
21647
22108
|
revert: (p) => {
|
|
22109
|
+
const keys = new Map((p.fnKeys ?? []).map((k) => [k.id, k]));
|
|
21648
22110
|
for (const n of p.nodes) {
|
|
21649
22111
|
const clone = n.kind === "container" ? { ...n, children: [...n.children] } : { ...n };
|
|
22112
|
+
restoreNodeFunctions(clone, keys.get(n.id));
|
|
21650
22113
|
state.nodes.set(n.id, clone);
|
|
21651
22114
|
dependents.add(n.id, clone.dependsOn ?? []);
|
|
21652
22115
|
}
|
|
@@ -21984,6 +22447,9 @@ function createScene(options) {
|
|
|
21984
22447
|
remove(id) {
|
|
21985
22448
|
scene.removeMany([id]);
|
|
21986
22449
|
},
|
|
22450
|
+
removalClosure(rootIds) {
|
|
22451
|
+
return removalClosure(rootIds).ids;
|
|
22452
|
+
},
|
|
21987
22453
|
removeMany(rootIds) {
|
|
21988
22454
|
if (rootIds.length === 0) return;
|
|
21989
22455
|
const { ids, removing } = removalClosure(rootIds);
|
|
@@ -21993,7 +22459,20 @@ function createScene(options) {
|
|
|
21993
22459
|
});
|
|
21994
22460
|
const detached = snapshot.filter((n) => n.parent === null || !removing.has(n.parent)).map((n) => ({ id: n.id, parent: n.parent, index: siblingsOf(n.parent).indexOf(n.id) })).sort((l, r) => l.index - r.index);
|
|
21995
22461
|
for (const nid of ids) overrides.clear(nid);
|
|
21996
|
-
const
|
|
22462
|
+
const fnKeys = snapshot.flatMap((n) => {
|
|
22463
|
+
const derivePathKey = n.derivePath !== void 0 ? reverseDerivePath.get(n.derivePath) : void 0;
|
|
22464
|
+
const clipKey = n.kind === "container" && n.clipFromPose !== void 0 ? reverseClipFromPose.get(n.clipFromPose) : void 0;
|
|
22465
|
+
return derivePathKey === void 0 && clipKey === void 0 ? [] : [{
|
|
22466
|
+
id: n.id,
|
|
22467
|
+
...derivePathKey !== void 0 ? { derivePathKey } : {},
|
|
22468
|
+
...clipKey !== void 0 ? { clipKey } : {}
|
|
22469
|
+
}];
|
|
22470
|
+
});
|
|
22471
|
+
const payload = {
|
|
22472
|
+
nodes: snapshot,
|
|
22473
|
+
detached,
|
|
22474
|
+
...fnKeys.length > 0 ? { fnKeys } : {}
|
|
22475
|
+
};
|
|
21997
22476
|
executeAndLog("kit:remove", payload, "remove");
|
|
21998
22477
|
},
|
|
21999
22478
|
update(id, patch) {
|
|
@@ -22290,6 +22769,10 @@ function createScene(options) {
|
|
|
22290
22769
|
const layer = { id: l.id };
|
|
22291
22770
|
if (l.visible === false) layer.visible = false;
|
|
22292
22771
|
if (l.locked === true) layer.locked = true;
|
|
22772
|
+
if (l.kind === "user") {
|
|
22773
|
+
layer.kind = "user";
|
|
22774
|
+
layer.name = l.name;
|
|
22775
|
+
}
|
|
22293
22776
|
return layer;
|
|
22294
22777
|
});
|
|
22295
22778
|
return { version: 1, systemLayers, nodes };
|
|
@@ -22307,12 +22790,7 @@ function createScene(options) {
|
|
|
22307
22790
|
if (state.layerIndex.has(spec.id)) {
|
|
22308
22791
|
throw new Error(`Scene.loadState: duplicate system layer id "${spec.id}"`);
|
|
22309
22792
|
}
|
|
22310
|
-
state.layers.push(
|
|
22311
|
-
kind: "system",
|
|
22312
|
-
id: spec.id,
|
|
22313
|
-
visible: spec.visible ?? true,
|
|
22314
|
-
locked: spec.locked ?? false
|
|
22315
|
-
});
|
|
22793
|
+
state.layers.push(layerFromSerialized(spec));
|
|
22316
22794
|
state.layerIndex.set(spec.id, i);
|
|
22317
22795
|
}
|
|
22318
22796
|
history.clear();
|
|
@@ -22412,16 +22890,16 @@ function sceneSelectionStore(scene) {
|
|
|
22412
22890
|
}
|
|
22413
22891
|
function sceneFromJSON(json, options) {
|
|
22414
22892
|
const registry2 = options.registry ?? {};
|
|
22415
|
-
const
|
|
22416
|
-
|
|
22417
|
-
systemLayers: json.systemLayers,
|
|
22418
|
-
initial,
|
|
22893
|
+
const scene = createScene({
|
|
22894
|
+
systemLayers: json.systemLayers.map((l) => ({ id: l.id })),
|
|
22419
22895
|
registry: registry2,
|
|
22420
22896
|
...options.historyLimit !== void 0 ? { historyLimit: options.historyLimit } : {},
|
|
22421
22897
|
...options.coalesceWindowMs !== void 0 ? { coalesceWindowMs: options.coalesceWindowMs } : {},
|
|
22422
22898
|
...options.generateId !== void 0 ? { generateId: options.generateId } : {},
|
|
22423
22899
|
...options.ops !== void 0 ? { ops: options.ops } : {}
|
|
22424
22900
|
});
|
|
22901
|
+
scene.loadState(json);
|
|
22902
|
+
return scene;
|
|
22425
22903
|
}
|
|
22426
22904
|
var SelectionContext = createContext(null);
|
|
22427
22905
|
function SelectionContextProvider({ children }) {
|
|
@@ -23164,7 +23642,7 @@ function CanvasView(props) {
|
|
|
23164
23642
|
}
|
|
23165
23643
|
function ActionsProviderIfRoot({ children }) {
|
|
23166
23644
|
const parent = useActionsRegistry();
|
|
23167
|
-
if (parent) return /* @__PURE__ */ jsx(
|
|
23645
|
+
if (parent) return /* @__PURE__ */ jsx(ActionsScope, { children });
|
|
23168
23646
|
return /* @__PURE__ */ jsx(ActionsProvider, { children });
|
|
23169
23647
|
}
|
|
23170
23648
|
function useToolActions(tools) {
|
|
@@ -23231,6 +23709,65 @@ function PointerPublisher({
|
|
|
23231
23709
|
}, [ctx, canvasRef, registry2]);
|
|
23232
23710
|
return null;
|
|
23233
23711
|
}
|
|
23712
|
+
function flattenVerts2(poly2) {
|
|
23713
|
+
const flat = new Array(poly2.length * 2);
|
|
23714
|
+
for (let i = 0; i < poly2.length; i++) {
|
|
23715
|
+
flat[i * 2] = poly2[i].x;
|
|
23716
|
+
flat[i * 2 + 1] = poly2[i].y;
|
|
23717
|
+
}
|
|
23718
|
+
return flat;
|
|
23719
|
+
}
|
|
23720
|
+
function polygonContainsRectCenter(poly2, rect) {
|
|
23721
|
+
return pointInPolygon(flattenVerts2(poly2), rect.x + rect.width / 2, rect.y + rect.height / 2);
|
|
23722
|
+
}
|
|
23723
|
+
function polygonContainsRect(poly2, rect) {
|
|
23724
|
+
if (poly2.length < 3) return false;
|
|
23725
|
+
const flat = flattenVerts2(poly2);
|
|
23726
|
+
if (!pointInPolygon(flat, rect.x, rect.y)) return false;
|
|
23727
|
+
if (!pointInPolygon(flat, rect.x + rect.width, rect.y)) return false;
|
|
23728
|
+
if (!pointInPolygon(flat, rect.x + rect.width, rect.y + rect.height)) return false;
|
|
23729
|
+
if (!pointInPolygon(flat, rect.x, rect.y + rect.height)) return false;
|
|
23730
|
+
return !anyPolyEdgeCrossesRect(poly2, rect);
|
|
23731
|
+
}
|
|
23732
|
+
function polygonIntersectsRect(poly2, rect) {
|
|
23733
|
+
if (poly2.length < 3) return false;
|
|
23734
|
+
const ab = polygonAabb(poly2);
|
|
23735
|
+
if (ab.x + ab.width < rect.x || ab.x > rect.x + rect.width) return false;
|
|
23736
|
+
if (ab.y + ab.height < rect.y || ab.y > rect.y + rect.height) return false;
|
|
23737
|
+
for (const v of poly2) {
|
|
23738
|
+
if (v.x >= rect.x && v.x <= rect.x + rect.width && v.y >= rect.y && v.y <= rect.y + rect.height) return true;
|
|
23739
|
+
}
|
|
23740
|
+
const flat = flattenVerts2(poly2);
|
|
23741
|
+
if (pointInPolygon(flat, rect.x, rect.y)) return true;
|
|
23742
|
+
if (pointInPolygon(flat, rect.x + rect.width, rect.y)) return true;
|
|
23743
|
+
if (pointInPolygon(flat, rect.x + rect.width, rect.y + rect.height)) return true;
|
|
23744
|
+
if (pointInPolygon(flat, rect.x, rect.y + rect.height)) return true;
|
|
23745
|
+
return anyPolyEdgeCrossesRect(poly2, rect);
|
|
23746
|
+
}
|
|
23747
|
+
function polygonAabb(poly2) {
|
|
23748
|
+
let minX = Infinity, minY = Infinity, maxX = -Infinity, maxY = -Infinity;
|
|
23749
|
+
for (const v of poly2) {
|
|
23750
|
+
if (v.x < minX) minX = v.x;
|
|
23751
|
+
if (v.y < minY) minY = v.y;
|
|
23752
|
+
if (v.x > maxX) maxX = v.x;
|
|
23753
|
+
if (v.y > maxY) maxY = v.y;
|
|
23754
|
+
}
|
|
23755
|
+
return { x: minX, y: minY, width: maxX - minX, height: maxY - minY };
|
|
23756
|
+
}
|
|
23757
|
+
function anyPolyEdgeCrossesRect(poly2, rect) {
|
|
23758
|
+
const r0x = rect.x, r0y = rect.y;
|
|
23759
|
+
const r1x = rect.x + rect.width, r1y = rect.y;
|
|
23760
|
+
const r2x = rect.x + rect.width, r2y = rect.y + rect.height;
|
|
23761
|
+
const r3x = rect.x, r3y = rect.y + rect.height;
|
|
23762
|
+
for (let i = 0, j = poly2.length - 1; i < poly2.length; j = i++) {
|
|
23763
|
+
const a = poly2[j], b = poly2[i];
|
|
23764
|
+
if (segmentsCross(a.x, a.y, b.x, b.y, r0x, r0y, r1x, r1y)) return true;
|
|
23765
|
+
if (segmentsCross(a.x, a.y, b.x, b.y, r1x, r1y, r2x, r2y)) return true;
|
|
23766
|
+
if (segmentsCross(a.x, a.y, b.x, b.y, r2x, r2y, r3x, r3y)) return true;
|
|
23767
|
+
if (segmentsCross(a.x, a.y, b.x, b.y, r3x, r3y, r0x, r0y)) return true;
|
|
23768
|
+
}
|
|
23769
|
+
return false;
|
|
23770
|
+
}
|
|
23234
23771
|
function isPathLike(p) {
|
|
23235
23772
|
if (!p || typeof p !== "object") return false;
|
|
23236
23773
|
const k = p.kind;
|
|
@@ -23412,12 +23949,19 @@ function sceneToAdapter(scene, options = {}) {
|
|
|
23412
23949
|
id: node.id,
|
|
23413
23950
|
...index !== void 0 ? { index } : {},
|
|
23414
23951
|
...node.parent !== null ? { parent: node.parent } : {},
|
|
23415
|
-
...node.kind === "container" && node.clipFromPose ? { clipFromPose: node.clipFromPose } : {}
|
|
23952
|
+
...node.kind === "container" && node.clipFromPose ? { clipFromPose: node.clipFromPose } : {},
|
|
23953
|
+
// Derivation travels with the node, or undo of a delete brings an
|
|
23954
|
+
// edge back as a static path that never follows its endpoints again.
|
|
23955
|
+
...node.dependsOn !== void 0 ? { dependsOn: node.dependsOn } : {},
|
|
23956
|
+
...node.derivePath !== void 0 ? { derivePath: node.derivePath } : {}
|
|
23416
23957
|
});
|
|
23417
23958
|
},
|
|
23418
23959
|
removeNode(id) {
|
|
23419
23960
|
scene.remove(asNodeId(id));
|
|
23420
23961
|
},
|
|
23962
|
+
getRemovalClosure(ids) {
|
|
23963
|
+
return [...scene.removalClosure(ids.map(asNodeId))];
|
|
23964
|
+
},
|
|
23421
23965
|
// AreaSelectAdapter surface — included unconditionally so plain
|
|
23422
23966
|
// `useSelectTool(sceneToAdapter(scene, { selection }))` Just Works for the
|
|
23423
23967
|
// marquee gesture. `applyOps` (above) dispatches transiently when called
|
|
@@ -25343,17 +25887,18 @@ function useActionsPropResolver(actions) {
|
|
|
25343
25887
|
useEffect(() => {
|
|
25344
25888
|
if (!reg) return;
|
|
25345
25889
|
const prop = actionsRef.current;
|
|
25890
|
+
const unregisters = [];
|
|
25346
25891
|
if (prop === null) {
|
|
25347
|
-
const
|
|
25348
|
-
|
|
25349
|
-
|
|
25892
|
+
for (const id of reg.list().map((a) => a.id)) unregisters.push(reg.mute(id));
|
|
25893
|
+
return () => {
|
|
25894
|
+
for (const u of unregisters) u();
|
|
25895
|
+
};
|
|
25350
25896
|
}
|
|
25351
25897
|
if (!prop) return;
|
|
25352
|
-
const unregisters = [];
|
|
25353
25898
|
const warnedIds = /* @__PURE__ */ new Set();
|
|
25354
25899
|
for (const [slotId, entry] of Object.entries(prop)) {
|
|
25355
25900
|
if (entry === null) {
|
|
25356
|
-
reg.
|
|
25901
|
+
unregisters.push(reg.mute(slotId));
|
|
25357
25902
|
continue;
|
|
25358
25903
|
}
|
|
25359
25904
|
const isFull = (e) => typeof e.id === "string" && typeof e.label === "string" && !!e.invoker;
|
|
@@ -25410,7 +25955,7 @@ function useViewportActions(args) {
|
|
|
25410
25955
|
r.register(makePinchZoomAction(typeof pinchZoom === "object" ? pinchZoom : {}))
|
|
25411
25956
|
);
|
|
25412
25957
|
} else {
|
|
25413
|
-
r.
|
|
25958
|
+
unregisters.push(r.mute("viewport.pinchZoom"));
|
|
25414
25959
|
}
|
|
25415
25960
|
return () => {
|
|
25416
25961
|
for (const u of unregisters) u();
|
|
@@ -25639,7 +26184,6 @@ function SceneCanvasInner(props, ref) {
|
|
|
25639
26184
|
() => isSerialized(sceneInput) ? sceneFromJSON(sceneInput, {}) : null
|
|
25640
26185
|
);
|
|
25641
26186
|
const scene = bakedScene ?? sceneInput;
|
|
25642
|
-
useSyncExternalStore(scene.subscribe, scene.getVersion, scene.getVersion);
|
|
25643
26187
|
const { view: viewProp, onViewChange: onViewChangeProp, defaultView, ...restProps } = rest;
|
|
25644
26188
|
const internalCanvasRef = useRef(null);
|
|
25645
26189
|
const canvasApiRef = useRef(null);
|
|
@@ -25670,6 +26214,9 @@ function SceneCanvasInner(props, ref) {
|
|
|
25670
26214
|
useEffect(() => scene.overrides.subscribe(() => {
|
|
25671
26215
|
canvasApiRef.current?.requestRedraw?.();
|
|
25672
26216
|
}), [scene]);
|
|
26217
|
+
useEffect(() => scene.subscribe(() => {
|
|
26218
|
+
canvasApiRef.current?.requestRedraw?.();
|
|
26219
|
+
}), [scene]);
|
|
25673
26220
|
const currentViewRef = useRef(
|
|
25674
26221
|
viewProp ?? defaultView ?? { x: 0, y: 0, scale: { x: 1, y: 1 } }
|
|
25675
26222
|
);
|
|
@@ -28299,7 +28846,7 @@ function applyOverlayStyle(el, style) {
|
|
|
28299
28846
|
el.style.border = "0";
|
|
28300
28847
|
el.style.outline = "none";
|
|
28301
28848
|
el.style.background = "transparent";
|
|
28302
|
-
el.style.color = "color" in style.fill ? style.fill.color : "#000";
|
|
28849
|
+
el.style.color = style.fill !== null && "color" in style.fill ? style.fill.color : "#000";
|
|
28303
28850
|
el.style.caretColor = style.caretColor;
|
|
28304
28851
|
el.style.font = fontString(style);
|
|
28305
28852
|
el.style.lineHeight = String(style.lineHeight);
|
|
@@ -31267,6 +31814,6 @@ function mergeContributions(...bundles) {
|
|
|
31267
31814
|
return out;
|
|
31268
31815
|
}
|
|
31269
31816
|
|
|
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,
|
|
31271
|
-
//# sourceMappingURL=chunk-
|
|
31272
|
-
//# sourceMappingURL=chunk-
|
|
31817
|
+
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, EFFECT_KIT_UNIFORMS, EFFECT_VERT_SRC, 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, KIT_STANDARD_ACTION_IDS, 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, WHEEL_ZOOM_STEP, 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, blur, 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, 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, registerEffect, 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, usePointerStylus, usePolygonTool, usePublishSelection, useRectTool, useResizePolicy, useRotateTool, useScene, useSceneAdapter, useSceneTextEdit, useSelectTool, useSelection, useSelectionContext, useSimulation, useSliceDep, useStandardActions, useStarTool, useTextEdit, useTextTool, useTools, useVelocityTracker, useViewAnimation, useVisibleRaf, viewToMat3, viewToTransform, viewportDragPanAction, viewportWheelPanAction, viewportZoomAction, viewportsAt, vignette, visualBoundsViaDescriptor, wheelPan, wheelZoom, wheelZoomFactor, when, withAlpha01, withCoord, withGradientKind, worldEditToStorage, worldPoseLookup, worldToScreen, zoomAt, zoomAtLeast };
|
|
31818
|
+
//# sourceMappingURL=chunk-WYPSGIYS.js.map
|
|
31819
|
+
//# sourceMappingURL=chunk-WYPSGIYS.js.map
|