@weasel-js/core 1.4.2 → 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 +375 -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-KIVJXUYE.js → chunk-WYPSGIYS.js} +1058 -503
- 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 +117 -232
- 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-KIVJXUYE.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
|
}
|
|
@@ -6548,16 +6949,16 @@ function targetSizesPx(targetScale = 1) {
|
|
|
6548
6949
|
}
|
|
6549
6950
|
|
|
6550
6951
|
// src/core/viewport/fitToBounds.ts
|
|
6551
|
-
function fitZoom(availW, availH, contentW, contentH,
|
|
6952
|
+
function fitZoom(availW, availH, contentW, contentH, clamp) {
|
|
6552
6953
|
const raw = Math.min(availW / contentW, availH / contentH);
|
|
6553
|
-
const min =
|
|
6554
|
-
const max =
|
|
6954
|
+
const min = clamp?.min ?? -Infinity;
|
|
6955
|
+
const max = clamp?.max ?? Infinity;
|
|
6555
6956
|
return Math.min(max, Math.max(min, raw));
|
|
6556
6957
|
}
|
|
6557
|
-
function fitToBounds(viewportW, viewportH, contentW, contentH, paddingPx = 0,
|
|
6958
|
+
function fitToBounds(viewportW, viewportH, contentW, contentH, paddingPx = 0, clamp) {
|
|
6558
6959
|
const availW = Math.max(1, viewportW - paddingPx * 2);
|
|
6559
6960
|
const availH = Math.max(1, viewportH - paddingPx * 2);
|
|
6560
|
-
const zoom = fitZoom(availW, availH, contentW, contentH,
|
|
6961
|
+
const zoom = fitZoom(availW, availH, contentW, contentH, clamp);
|
|
6561
6962
|
const contentPxW = contentW * zoom;
|
|
6562
6963
|
const contentPxH = contentH * zoom;
|
|
6563
6964
|
return {
|
|
@@ -6680,128 +7081,6 @@ function sceneNodeClientRect(opts) {
|
|
|
6680
7081
|
height: bounds.height * opts.view.scale.y
|
|
6681
7082
|
};
|
|
6682
7083
|
}
|
|
6683
|
-
var clamp = (z, min, max) => Math.min(max, Math.max(min, z));
|
|
6684
|
-
function isEditableTarget(t) {
|
|
6685
|
-
if (!t) return false;
|
|
6686
|
-
const el = t;
|
|
6687
|
-
if (el.isContentEditable) return true;
|
|
6688
|
-
const tag = (el.tagName ?? "").toUpperCase();
|
|
6689
|
-
return tag === "INPUT" || tag === "TEXTAREA" || tag === "SELECT";
|
|
6690
|
-
}
|
|
6691
|
-
function useZoom(opts) {
|
|
6692
|
-
const min = opts.min ?? DEFAULT_MIN_ZOOM;
|
|
6693
|
-
const max = opts.max ?? DEFAULT_MAX_ZOOM;
|
|
6694
|
-
const wheelStep = opts.wheelStep ?? 1.1;
|
|
6695
|
-
const keyStep = opts.keyStep ?? 1.25;
|
|
6696
|
-
const sources = useMemo(
|
|
6697
|
-
() => ({
|
|
6698
|
-
wheel: opts.sources?.wheel ?? true,
|
|
6699
|
-
keys: opts.sources?.keys ?? true,
|
|
6700
|
-
doubleClick: opts.sources?.doubleClick ?? false,
|
|
6701
|
-
pinch: opts.sources?.pinch ?? true
|
|
6702
|
-
}),
|
|
6703
|
-
[opts.sources?.wheel, opts.sources?.keys, opts.sources?.doubleClick, opts.sources?.pinch]
|
|
6704
|
-
);
|
|
6705
|
-
const applyZoom = useCallback(
|
|
6706
|
-
(nextZoom, focal) => {
|
|
6707
|
-
const oldZoom = opts.zoom;
|
|
6708
|
-
const newZoom = clamp(nextZoom, min, max);
|
|
6709
|
-
const k = newZoom / oldZoom;
|
|
6710
|
-
const newPan = {
|
|
6711
|
-
x: focal.x - (focal.x - opts.pan.x) * k,
|
|
6712
|
-
y: focal.y - (focal.y - opts.pan.y) * k
|
|
6713
|
-
};
|
|
6714
|
-
opts.setZoom(newZoom);
|
|
6715
|
-
opts.setPan(newPan);
|
|
6716
|
-
},
|
|
6717
|
-
[opts, min, max]
|
|
6718
|
-
);
|
|
6719
|
-
const viewportCenter = useCallback(() => {
|
|
6720
|
-
if (!opts.viewport) {
|
|
6721
|
-
throw new Error(
|
|
6722
|
-
"useZoom: viewport option is required for keyboard zoom and zoomTo without focal"
|
|
6723
|
-
);
|
|
6724
|
-
}
|
|
6725
|
-
return { x: opts.viewport.width / 2, y: opts.viewport.height / 2 };
|
|
6726
|
-
}, [opts.viewport]);
|
|
6727
|
-
const zoomTo = useCallback(
|
|
6728
|
-
(level, focal) => {
|
|
6729
|
-
applyZoom(level, focal ?? viewportCenter());
|
|
6730
|
-
},
|
|
6731
|
-
[applyZoom, viewportCenter]
|
|
6732
|
-
);
|
|
6733
|
-
const zoomBy = useCallback(
|
|
6734
|
-
(factor, focal) => {
|
|
6735
|
-
applyZoom(opts.zoom * factor, focal ?? viewportCenter());
|
|
6736
|
-
},
|
|
6737
|
-
[applyZoom, opts.zoom, viewportCenter]
|
|
6738
|
-
);
|
|
6739
|
-
const reset = useCallback(() => {
|
|
6740
|
-
opts.setZoom(1);
|
|
6741
|
-
opts.setPan({ x: 0, y: 0 });
|
|
6742
|
-
}, [opts]);
|
|
6743
|
-
const onWheel = useCallback(
|
|
6744
|
-
(e) => {
|
|
6745
|
-
const evt = e;
|
|
6746
|
-
const isPinch = evt.ctrlKey === true;
|
|
6747
|
-
if (isPinch) {
|
|
6748
|
-
if (!sources.pinch) return;
|
|
6749
|
-
evt.preventDefault?.();
|
|
6750
|
-
} else {
|
|
6751
|
-
if (!sources.wheel) return;
|
|
6752
|
-
if (opts.wheelRequiresModifier && !evt.metaKey) return;
|
|
6753
|
-
}
|
|
6754
|
-
const target = evt.currentTarget;
|
|
6755
|
-
const rect = target?.getBoundingClientRect?.();
|
|
6756
|
-
const focal = {
|
|
6757
|
-
x: evt.clientX - (rect?.left ?? 0),
|
|
6758
|
-
y: evt.clientY - (rect?.top ?? 0)
|
|
6759
|
-
};
|
|
6760
|
-
const factor = evt.deltaY < 0 ? wheelStep : 1 / wheelStep;
|
|
6761
|
-
applyZoom(opts.zoom * factor, focal);
|
|
6762
|
-
},
|
|
6763
|
-
[applyZoom, opts, sources, wheelStep]
|
|
6764
|
-
);
|
|
6765
|
-
const onKeyDown = useCallback(
|
|
6766
|
-
(e) => {
|
|
6767
|
-
if (!sources.keys) return;
|
|
6768
|
-
const evt = e;
|
|
6769
|
-
if (isEditableTarget(evt.target)) return;
|
|
6770
|
-
if (evt.key === "0" && (evt.metaKey || evt.ctrlKey)) {
|
|
6771
|
-
opts.setZoom(1);
|
|
6772
|
-
opts.setPan({ x: 0, y: 0 });
|
|
6773
|
-
return;
|
|
6774
|
-
}
|
|
6775
|
-
let factor = 0;
|
|
6776
|
-
if (evt.key === "+" || evt.key === "=") factor = keyStep;
|
|
6777
|
-
else if (evt.key === "-" || evt.key === "_") factor = 1 / keyStep;
|
|
6778
|
-
if (factor === 0) return;
|
|
6779
|
-
applyZoom(opts.zoom * factor, viewportCenter());
|
|
6780
|
-
},
|
|
6781
|
-
[applyZoom, opts, sources, keyStep, viewportCenter]
|
|
6782
|
-
);
|
|
6783
|
-
const onDoubleClick = useCallback(
|
|
6784
|
-
(e) => {
|
|
6785
|
-
if (!sources.doubleClick) return;
|
|
6786
|
-
const evt = e;
|
|
6787
|
-
if (evt.altKey) {
|
|
6788
|
-
opts.setZoom(1);
|
|
6789
|
-
opts.setPan({ x: 0, y: 0 });
|
|
6790
|
-
return;
|
|
6791
|
-
}
|
|
6792
|
-
const target = evt.currentTarget;
|
|
6793
|
-
const rect = target?.getBoundingClientRect?.();
|
|
6794
|
-
const focal = {
|
|
6795
|
-
x: evt.clientX - (rect?.left ?? 0),
|
|
6796
|
-
y: evt.clientY - (rect?.top ?? 0)
|
|
6797
|
-
};
|
|
6798
|
-
const factor = evt.shiftKey ? 1 / keyStep : keyStep;
|
|
6799
|
-
applyZoom(opts.zoom * factor, focal);
|
|
6800
|
-
},
|
|
6801
|
-
[applyZoom, opts, sources, keyStep]
|
|
6802
|
-
);
|
|
6803
|
-
return { onWheel, onKeyDown, onDoubleClick, zoomTo, zoomBy, reset };
|
|
6804
|
-
}
|
|
6805
7084
|
function computeFitViewport(viewportW, viewportH, contentW, contentH, padRatio = 0.85) {
|
|
6806
7085
|
const zoom = fitZoom(viewportW * padRatio, viewportH * padRatio, contentW, contentH);
|
|
6807
7086
|
const cw = contentW * zoom;
|
|
@@ -6821,7 +7100,7 @@ function useAutoCenter(width, height, contentW, contentH, setZoom, setPan) {
|
|
|
6821
7100
|
}
|
|
6822
7101
|
|
|
6823
7102
|
// src/interactions/keyHelpers.ts
|
|
6824
|
-
function
|
|
7103
|
+
function isEditableTarget(target) {
|
|
6825
7104
|
if (!target || !(target instanceof Element)) return false;
|
|
6826
7105
|
const tag = target.tagName;
|
|
6827
7106
|
if (tag === "INPUT" || tag === "TEXTAREA") return true;
|
|
@@ -6959,7 +7238,10 @@ function moveGestureAdapter(scene) {
|
|
|
6959
7238
|
data: node.data,
|
|
6960
7239
|
id: node.id,
|
|
6961
7240
|
...index !== void 0 ? { index } : {},
|
|
6962
|
-
...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 } : {}
|
|
6963
7245
|
}),
|
|
6964
7246
|
getChildren: (parentId) => parentId === null ? [...scene.roots] : [...scene.childrenOf(asNodeId(parentId))],
|
|
6965
7247
|
setChildOrder: (parentId, ids) => {
|
|
@@ -6984,31 +7266,51 @@ function runLayoutPass(scratch, moveCtx) {
|
|
|
6984
7266
|
if (!layoutDep || !moveCtx.drag) return;
|
|
6985
7267
|
const scene = scratch.scene;
|
|
6986
7268
|
const pc = scratch.pc;
|
|
6987
|
-
const draggedId = scratch.ids[0];
|
|
6988
7269
|
const poseAdapter = scenePoseAdapter(scene);
|
|
6989
|
-
if (!scene.get(draggedId)) return;
|
|
6990
|
-
const sourceContainerId = scene.get(draggedId)?.parent ?? null;
|
|
6991
7270
|
const { dx, dy } = scratch.currentDelta;
|
|
6992
|
-
const
|
|
6993
|
-
const
|
|
6994
|
-
|
|
6995
|
-
|
|
6996
|
-
|
|
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
|
|
6997
7305
|
};
|
|
6998
7306
|
const candidates = [];
|
|
6999
7307
|
const boundsOf2 = scratch.projection?.getBounds ?? AUTO_POSE_DESCRIPTOR.getBounds;
|
|
7000
7308
|
const testInside = (cPose, aabb, layout2) => {
|
|
7001
|
-
if (layout2.contains) return layout2.contains(cPose,
|
|
7002
|
-
return
|
|
7003
|
-
};
|
|
7004
|
-
const draggedArg = {
|
|
7005
|
-
id: draggedId,
|
|
7006
|
-
originPose: startWorld,
|
|
7007
|
-
pose: draggedWorld,
|
|
7008
|
-
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;
|
|
7009
7311
|
};
|
|
7010
7312
|
const consider = (id, zPath) => {
|
|
7011
|
-
if (id
|
|
7313
|
+
if (draggedIds.has(id)) return;
|
|
7012
7314
|
const layout2 = layoutDep.getLayout(id);
|
|
7013
7315
|
if (!layout2) return;
|
|
7014
7316
|
const node = scene.get(id);
|
|
@@ -7016,7 +7318,10 @@ function runLayoutPass(scratch, moveCtx) {
|
|
|
7016
7318
|
const worldPose = composeWorldPose(poseAdapter, id, pc.compose);
|
|
7017
7319
|
const worldAABB = boundsOf2(worldPose);
|
|
7018
7320
|
if (!testInside(worldPose, worldAABB, layout2)) return;
|
|
7019
|
-
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
|
+
}
|
|
7020
7325
|
candidates.push({
|
|
7021
7326
|
id,
|
|
7022
7327
|
bounds: worldAABB,
|
|
@@ -7061,47 +7366,126 @@ function runLayoutPass(scratch, moveCtx) {
|
|
|
7061
7366
|
if (!dest) return;
|
|
7062
7367
|
const layout = dest.layout;
|
|
7063
7368
|
const container = { id: dest.id, bounds: dest.bounds };
|
|
7064
|
-
const
|
|
7369
|
+
const working = scene.childrenOf(dest.id).map((cid) => ({
|
|
7065
7370
|
id: cid,
|
|
7066
7371
|
pose: composeWorldPose(poseAdapter, cid, pc.compose)
|
|
7067
7372
|
}));
|
|
7068
|
-
const
|
|
7069
|
-
|
|
7070
|
-
|
|
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
|
+
}
|
|
7071
7396
|
const reflowIds = /* @__PURE__ */ new Set();
|
|
7072
|
-
for (const [cid, pose] of
|
|
7073
|
-
|
|
7074
|
-
|
|
7075
|
-
|
|
7076
|
-
scratch.previews.set(asNodeId(cid), local);
|
|
7077
|
-
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);
|
|
7078
7401
|
}
|
|
7079
7402
|
const sourceReflow = /* @__PURE__ */ new Map();
|
|
7080
|
-
|
|
7081
|
-
|
|
7082
|
-
|
|
7083
|
-
|
|
7084
|
-
|
|
7085
|
-
|
|
7086
|
-
|
|
7087
|
-
|
|
7088
|
-
|
|
7089
|
-
|
|
7090
|
-
|
|
7091
|
-
|
|
7092
|
-
|
|
7093
|
-
|
|
7094
|
-
|
|
7095
|
-
|
|
7096
|
-
|
|
7097
|
-
|
|
7098
|
-
|
|
7099
|
-
|
|
7100
|
-
|
|
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);
|
|
7101
7467
|
}
|
|
7102
7468
|
}
|
|
7103
7469
|
}
|
|
7104
|
-
|
|
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;
|
|
7105
7489
|
}
|
|
7106
7490
|
function scenePoseAdapter(scene) {
|
|
7107
7491
|
return {
|
|
@@ -7286,7 +7670,7 @@ var moveAction = {
|
|
|
7286
7670
|
scratch.previews.set(id, translatePoseGeneric(ori, dx, dy, scratch.projection));
|
|
7287
7671
|
}
|
|
7288
7672
|
scratch.layoutPass = null;
|
|
7289
|
-
|
|
7673
|
+
runLayoutPass(scratch, moveCtx);
|
|
7290
7674
|
syncPreviewOverrides(scratch);
|
|
7291
7675
|
},
|
|
7292
7676
|
onEnd(endCtx, reason) {
|
|
@@ -7321,25 +7705,17 @@ var moveAction = {
|
|
|
7321
7705
|
scratch.previews.clear();
|
|
7322
7706
|
return;
|
|
7323
7707
|
}
|
|
7324
|
-
if (scratch.layout && scratch.
|
|
7708
|
+
if (scratch.layout && scratch.layoutPass) {
|
|
7325
7709
|
const lp = scratch.layoutPass;
|
|
7326
7710
|
const pc2 = scratch.pc;
|
|
7327
|
-
const draggedId = scratch.ids[0];
|
|
7328
7711
|
const commitAdapter = scenePoseAdapter(scratch.scene);
|
|
7329
|
-
const startWorld = composeWorldPose(commitAdapter, draggedId, pc2.compose);
|
|
7330
|
-
const sourceContainerId = scratch.scene.get(draggedId)?.parent ?? null;
|
|
7331
|
-
const draggedArg = {
|
|
7332
|
-
id: draggedId,
|
|
7333
|
-
originPose: startWorld,
|
|
7334
|
-
pose: { ...startWorld, x: startWorld.x + dx, y: startWorld.y + dy },
|
|
7335
|
-
sourceContainerId
|
|
7336
|
-
};
|
|
7337
7712
|
const destId = lp.container.id;
|
|
7713
|
+
const draggedIds = new Set(scratch.ids.map((id) => id));
|
|
7338
7714
|
const rebaseOpToLocal = (op) => {
|
|
7339
7715
|
if (op.name !== "transform") return op;
|
|
7340
7716
|
const a = op.args;
|
|
7341
7717
|
const curParent = scratch.scene.get(asNodeId(a.id))?.parent ?? null;
|
|
7342
|
-
const toParent = a.id
|
|
7718
|
+
const toParent = draggedIds.has(a.id) ? destId : curParent;
|
|
7343
7719
|
return createTransformOp({
|
|
7344
7720
|
id: a.id,
|
|
7345
7721
|
from: rebaseLocalPose(commitAdapter, a.from, curParent, pc2.compose, pc2.decompose),
|
|
@@ -7348,15 +7724,24 @@ var moveAction = {
|
|
|
7348
7724
|
coalesceKey: a.coalesceKey
|
|
7349
7725
|
});
|
|
7350
7726
|
};
|
|
7351
|
-
const dropOps = lp.layout.commitDrop(lp.container, lp.children, draggedArg, lp.target).map(rebaseOpToLocal);
|
|
7352
7727
|
const reparentOps = [];
|
|
7353
|
-
|
|
7354
|
-
|
|
7355
|
-
|
|
7356
|
-
|
|
7357
|
-
|
|
7358
|
-
|
|
7359
|
-
|
|
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));
|
|
7360
7745
|
}
|
|
7361
7746
|
const reflowOps = [];
|
|
7362
7747
|
for (const [cid, worldPose] of lp.sourceReflow) {
|
|
@@ -7375,38 +7760,82 @@ var moveAction = {
|
|
|
7375
7760
|
scratch.previews.clear();
|
|
7376
7761
|
return;
|
|
7377
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
|
+
}
|
|
7378
7830
|
const resolved = resolveParams(opts?.params);
|
|
7379
7831
|
const reparentMode = resolved?.["reparentOnDrop"] ?? "off";
|
|
7380
7832
|
const dropTarget = reparentMode !== "off" ? resolveDropTarget(endCtx, scratch) : null;
|
|
7381
7833
|
if (dropTarget) {
|
|
7382
7834
|
scratch.scene.batch("Move", () => {
|
|
7383
7835
|
applyReparent(scratch, dropTarget, reparentMode, dx, dy, scratch.pc);
|
|
7384
|
-
});
|
|
7385
|
-
} else {
|
|
7386
|
-
const
|
|
7387
|
-
const ops = [];
|
|
7388
|
-
for (const id of [...scratch.ids, ...scratch.cascadeIds]) {
|
|
7389
|
-
const origin2 = scratch.startPoses.get(id);
|
|
7390
|
-
if (origin2 === void 0) continue;
|
|
7391
|
-
ops.push(createTransformOp({
|
|
7392
|
-
id,
|
|
7393
|
-
from: origin2,
|
|
7394
|
-
to: translatePoseGeneric(origin2, dx, dy, scratch.projection),
|
|
7395
|
-
label: "Move"
|
|
7396
|
-
}));
|
|
7397
|
-
if (scratch.geometryProjection) {
|
|
7398
|
-
const node = scratch.scene.get(id);
|
|
7399
|
-
if (node) {
|
|
7400
|
-
const dataOp = geometryDataOp(
|
|
7401
|
-
scratch.geometryProjection,
|
|
7402
|
-
{ id, data: node.data, pose: origin2 },
|
|
7403
|
-
m,
|
|
7404
|
-
"Move"
|
|
7405
|
-
);
|
|
7406
|
-
if (dataOp) ops.push(dataOp);
|
|
7407
|
-
}
|
|
7408
|
-
}
|
|
7409
|
-
}
|
|
7836
|
+
});
|
|
7837
|
+
} else {
|
|
7838
|
+
const ops = translateCommitOps(scratch, [...scratch.ids, ...scratch.cascadeIds], dx, dy);
|
|
7410
7839
|
if (ops.length > 0) commitOps(ops, "Move");
|
|
7411
7840
|
}
|
|
7412
7841
|
dropPreviewOverrides(scratch);
|
|
@@ -7477,6 +7906,7 @@ function defaultCommitAdapter(scene) {
|
|
|
7477
7906
|
getSelection: () => [...scene.getSelection()],
|
|
7478
7907
|
setSelection: (ids) => scene.setSelection(ids.map(asNodeId)),
|
|
7479
7908
|
getParent: (id) => scene.get(asNodeId(id))?.parent ?? null,
|
|
7909
|
+
getRemovalClosure: (ids) => [...scene.removalClosure(ids.map(asNodeId))],
|
|
7480
7910
|
getChildren: (parentId) => parentId === null ? [...scene.roots] : [...scene.childrenOf(asNodeId(parentId))],
|
|
7481
7911
|
// Re-stamp each slot whose occupant changed. `scene.reorder` mutates the
|
|
7482
7912
|
// live sibling list in place, so re-read it each iteration and skip slots
|
|
@@ -7505,7 +7935,13 @@ function defaultCommitAdapter(scene) {
|
|
|
7505
7935
|
// Sibling-index passthrough: undo of a delete (or a boolean op's
|
|
7506
7936
|
// source removal) re-inserts at the recorded z-order slot instead
|
|
7507
7937
|
// of appending at the end.
|
|
7508
|
-
...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 } : {}
|
|
7509
7945
|
})
|
|
7510
7946
|
};
|
|
7511
7947
|
}
|
|
@@ -8681,15 +9117,40 @@ var viewportDragPanAction = {
|
|
|
8681
9117
|
enabled: () => true
|
|
8682
9118
|
};
|
|
8683
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
|
+
|
|
8684
9146
|
// src/interactions/actions/defaults/viewportZoom.ts
|
|
8685
9147
|
var KEY_STEP = 1.25;
|
|
8686
9148
|
function keyAnchor(view) {
|
|
8687
9149
|
const size = view.hostSize?.();
|
|
8688
9150
|
return size ? { x: size.width / 2, y: size.height / 2 } : { x: 0, y: 0 };
|
|
8689
9151
|
}
|
|
8690
|
-
var WHEEL_STEP = 1.1;
|
|
8691
9152
|
function makeViewportZoomAction(opts = {}) {
|
|
8692
|
-
const
|
|
9153
|
+
const clamp = { min: opts.min ?? DEFAULT_MIN_ZOOM, max: opts.max ?? DEFAULT_MAX_ZOOM };
|
|
8693
9154
|
const wheelSpec = opts.wheel === "plain" ? { kind: "wheel" } : { kind: "wheel", mods: { mod: true } };
|
|
8694
9155
|
const rawAnimate = opts.animate === true ? {} : opts.animate || null;
|
|
8695
9156
|
const { resetMs, ...animateRest } = rawAnimate ?? {};
|
|
@@ -8749,15 +9210,14 @@ function makeViewportZoomAction(opts = {}) {
|
|
|
8749
9210
|
const deltaY = params?.deltaY ?? 0;
|
|
8750
9211
|
const clientX = params?.clientX ?? 0;
|
|
8751
9212
|
const clientY = params?.clientY ?? 0;
|
|
8752
|
-
|
|
8753
|
-
view.set(zoomAt(current, { x: clientX, y: clientY }, factor, clamp2));
|
|
9213
|
+
view.set(wheelZoom(current, { x: clientX, y: clientY }, deltaY, clamp));
|
|
8754
9214
|
break;
|
|
8755
9215
|
}
|
|
8756
9216
|
case "in":
|
|
8757
|
-
stepTo(zoomAt(stepFrom(), keyAnchor(view), KEY_STEP,
|
|
9217
|
+
stepTo(zoomAt(stepFrom(), keyAnchor(view), KEY_STEP, clamp));
|
|
8758
9218
|
break;
|
|
8759
9219
|
case "out":
|
|
8760
|
-
stepTo(zoomAt(stepFrom(), keyAnchor(view), 1 / KEY_STEP,
|
|
9220
|
+
stepTo(zoomAt(stepFrom(), keyAnchor(view), 1 / KEY_STEP, clamp));
|
|
8761
9221
|
break;
|
|
8762
9222
|
case "reset": {
|
|
8763
9223
|
const target = view.recenter ? view.recenter() : { x: 0, y: 0, scale: { x: 1, y: 1 } };
|
|
@@ -8766,7 +9226,7 @@ function makeViewportZoomAction(opts = {}) {
|
|
|
8766
9226
|
}
|
|
8767
9227
|
default:
|
|
8768
9228
|
if (params === void 0) {
|
|
8769
|
-
view.set(zoomAt(current, { x: 0, y: 0 }, KEY_STEP,
|
|
9229
|
+
view.set(zoomAt(current, { x: 0, y: 0 }, KEY_STEP, clamp));
|
|
8770
9230
|
}
|
|
8771
9231
|
break;
|
|
8772
9232
|
}
|
|
@@ -8801,15 +9261,9 @@ var viewportWheelPanAction = {
|
|
|
8801
9261
|
const axis = params?.axis ?? "both";
|
|
8802
9262
|
const deltaX = params?.deltaX ?? 0;
|
|
8803
9263
|
const deltaY = params?.deltaY ?? 0;
|
|
8804
|
-
|
|
8805
|
-
|
|
8806
|
-
|
|
8807
|
-
const dy = swap ? 0 : deltaY / current.scale.y;
|
|
8808
|
-
view.set({
|
|
8809
|
-
...current,
|
|
8810
|
-
x: current.x + (axis === "y" ? 0 : dx),
|
|
8811
|
-
y: current.y + (axis === "x" ? 0 : dy)
|
|
8812
|
-
});
|
|
9264
|
+
view.set(
|
|
9265
|
+
wheelPan(view.get(), { deltaX, deltaY }, { axis, swapAxis: params?.swapAxis === true })
|
|
9266
|
+
);
|
|
8813
9267
|
}
|
|
8814
9268
|
},
|
|
8815
9269
|
enabled: () => true
|
|
@@ -9457,7 +9911,7 @@ var sliceAction = {
|
|
|
9457
9911
|
|
|
9458
9912
|
// src/interactions/actions/defaults/pinchZoom.ts
|
|
9459
9913
|
function makePinchZoomAction(opts = {}) {
|
|
9460
|
-
const
|
|
9914
|
+
const clamp = { min: opts.min ?? DEFAULT_MIN_ZOOM, max: opts.max ?? DEFAULT_MAX_ZOOM };
|
|
9461
9915
|
return {
|
|
9462
9916
|
id: "viewport.pinchZoom",
|
|
9463
9917
|
label: "Pinch Zoom",
|
|
@@ -9485,7 +9939,7 @@ function makePinchZoomAction(opts = {}) {
|
|
|
9485
9939
|
const prev = scratch.centroid;
|
|
9486
9940
|
scratch.centroid = centroid;
|
|
9487
9941
|
const current = scratch.view.get();
|
|
9488
|
-
const zoomed = zoomAt(current, prev, factor,
|
|
9942
|
+
const zoomed = zoomAt(current, prev, factor, clamp);
|
|
9489
9943
|
scratch.view.set({
|
|
9490
9944
|
scale: zoomed.scale,
|
|
9491
9945
|
x: zoomed.x - (centroid.x - prev.x) / zoomed.scale.x,
|
|
@@ -9507,31 +9961,14 @@ function hostIndex(scene, id) {
|
|
|
9507
9961
|
const siblings = node?.parent == null ? scene.roots : scene.childrenOf(node.parent);
|
|
9508
9962
|
return siblings.indexOf(id);
|
|
9509
9963
|
}
|
|
9510
|
-
function coveredByEmitted(scene, id, emitted) {
|
|
9511
|
-
const seen = /* @__PURE__ */ new Set([id]);
|
|
9512
|
-
const stack = [id];
|
|
9513
|
-
while (stack.length > 0) {
|
|
9514
|
-
const node = scene.get(stack.pop());
|
|
9515
|
-
if (!node) continue;
|
|
9516
|
-
const up = node.parent == null ? node.dependsOn ?? [] : [node.parent, ...node.dependsOn ?? []];
|
|
9517
|
-
for (const next of up) {
|
|
9518
|
-
if (seen.has(next)) continue;
|
|
9519
|
-
if (emitted.has(next)) return true;
|
|
9520
|
-
seen.add(next);
|
|
9521
|
-
stack.push(next);
|
|
9522
|
-
}
|
|
9523
|
-
}
|
|
9524
|
-
return false;
|
|
9525
|
-
}
|
|
9526
9964
|
function buildDeleteOps(scene, ids, label) {
|
|
9527
|
-
const
|
|
9965
|
+
const covered = /* @__PURE__ */ new Set();
|
|
9528
9966
|
const ops = [];
|
|
9529
9967
|
for (const id of ids) {
|
|
9530
9968
|
const node = scene.get(id);
|
|
9531
9969
|
if (!node) continue;
|
|
9532
|
-
if (
|
|
9533
|
-
|
|
9534
|
-
emitted.add(id);
|
|
9970
|
+
if (covered.has(id)) continue;
|
|
9971
|
+
for (const taken of scene.removalClosure([id])) covered.add(taken);
|
|
9535
9972
|
ops.push(createDeleteOp({
|
|
9536
9973
|
node,
|
|
9537
9974
|
index: hostIndex(scene, id),
|
|
@@ -9755,7 +10192,10 @@ var selectAllAction = {
|
|
|
9755
10192
|
timing: "immediate",
|
|
9756
10193
|
run: (deps) => {
|
|
9757
10194
|
const scene = deps.scene;
|
|
9758
|
-
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);
|
|
9759
10199
|
if (all.length === 0) return;
|
|
9760
10200
|
deps.selection?.set(all);
|
|
9761
10201
|
}
|
|
@@ -11773,7 +12213,7 @@ var setStrokeOpacityAction = createPaintAction({
|
|
|
11773
12213
|
readParams: (_prev, params) => params?.alpha01 ?? null,
|
|
11774
12214
|
merge: (prev, alpha01) => {
|
|
11775
12215
|
const base = prev ?? strokeOf(DEFAULT_STROKE_COLOR);
|
|
11776
|
-
return { ...base, paint: paintWithAlpha(base.paint, alpha01) };
|
|
12216
|
+
return { ...base, paint: paintWithAlpha(base.paint ?? solid(DEFAULT_STROKE_COLOR), alpha01) };
|
|
11777
12217
|
}
|
|
11778
12218
|
});
|
|
11779
12219
|
|
|
@@ -12243,6 +12683,7 @@ var KIT_STANDARD_DESCRIPTORS = [
|
|
|
12243
12683
|
clipboardCopyAction,
|
|
12244
12684
|
clipboardCutAction
|
|
12245
12685
|
];
|
|
12686
|
+
var KIT_STANDARD_ACTION_IDS = KIT_STANDARD_DESCRIPTORS.map((a) => a.id);
|
|
12246
12687
|
function useStandardActions(opts) {
|
|
12247
12688
|
const optsRef = useRef(opts);
|
|
12248
12689
|
optsRef.current = opts;
|
|
@@ -12275,13 +12716,15 @@ function useStandardActions(opts) {
|
|
|
12275
12716
|
const reg = useActionsRegistry();
|
|
12276
12717
|
const regRef = useRef(reg);
|
|
12277
12718
|
regRef.current = reg;
|
|
12719
|
+
const excludeKey = opts.exclude ? [...opts.exclude].join("\0") : "";
|
|
12278
12720
|
useEffect(() => {
|
|
12279
12721
|
if (!reg || !depReg) return;
|
|
12280
|
-
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));
|
|
12281
12724
|
return () => {
|
|
12282
12725
|
for (const u of unregisters) u();
|
|
12283
12726
|
};
|
|
12284
|
-
}, [reg, depReg]);
|
|
12727
|
+
}, [reg, depReg, excludeKey]);
|
|
12285
12728
|
}
|
|
12286
12729
|
var IDENTITY_EXPAND2 = (ids) => ids;
|
|
12287
12730
|
var EMPTY = Object.freeze([]);
|
|
@@ -13599,9 +14042,18 @@ function useGestureDispatcher(opts) {
|
|
|
13599
14042
|
};
|
|
13600
14043
|
const heldKeys = /* @__PURE__ */ new Set();
|
|
13601
14044
|
const held = /* @__PURE__ */ new Map();
|
|
13602
|
-
const
|
|
13603
|
-
|
|
13604
|
-
|
|
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;
|
|
@@ -13651,7 +14103,7 @@ function useGestureDispatcher(opts) {
|
|
|
13651
14103
|
const DOUBLE_CLICK_MAX_MS = 600;
|
|
13652
14104
|
const DOUBLE_CLICK_MAX_PX = 8;
|
|
13653
14105
|
const onKeyDown = (e) => {
|
|
13654
|
-
if (
|
|
14106
|
+
if (isEditableTarget(e.target)) return;
|
|
13655
14107
|
if (e.repeat && heldKeys.has(e.key)) {
|
|
13656
14108
|
e.preventDefault();
|
|
13657
14109
|
return;
|
|
@@ -13989,10 +14441,12 @@ function useGestureDispatcher(opts) {
|
|
|
13989
14441
|
}
|
|
13990
14442
|
const start = multiTouchStart;
|
|
13991
14443
|
if (start) {
|
|
13992
|
-
const
|
|
13993
|
-
|
|
13994
|
-
|
|
13995
|
-
|
|
14444
|
+
const centroid = toCanvasLocal(
|
|
14445
|
+
computeMultiTouchGeometry([
|
|
14446
|
+
...[...held.values()].map((p) => p.pos),
|
|
14447
|
+
{ x: e.clientX, y: e.clientY }
|
|
14448
|
+
]).centroid
|
|
14449
|
+
);
|
|
13996
14450
|
const dx = centroid.x - start.centroid.x;
|
|
13997
14451
|
const dy = centroid.y - start.centroid.y;
|
|
13998
14452
|
if (Math.hypot(dx, dy) <= TAP_THRESHOLD_PX) {
|
|
@@ -14161,7 +14615,7 @@ function useGestureDispatcher(opts) {
|
|
|
14161
14615
|
});
|
|
14162
14616
|
};
|
|
14163
14617
|
const onPaste = (e) => {
|
|
14164
|
-
if (
|
|
14618
|
+
if (isEditableTarget(e.target)) return;
|
|
14165
14619
|
const cd = e.clipboardData;
|
|
14166
14620
|
if (!cd) return;
|
|
14167
14621
|
const items = itemsFromClipboardData(cd);
|
|
@@ -14222,33 +14676,6 @@ function useGestureDispatcher(opts) {
|
|
|
14222
14676
|
};
|
|
14223
14677
|
}, [enabled, keyboard, canvasRef]);
|
|
14224
14678
|
}
|
|
14225
|
-
|
|
14226
|
-
// src/core/viewport/wheelHandler.ts
|
|
14227
|
-
function computeWheelAction(state, input, bounds = { min: DEFAULT_MIN_ZOOM, max: DEFAULT_MAX_ZOOM }) {
|
|
14228
|
-
if (input.shiftKey) {
|
|
14229
|
-
return {
|
|
14230
|
-
zoom: state.zoom,
|
|
14231
|
-
panX: state.panX - input.deltaY,
|
|
14232
|
-
panY: state.panY
|
|
14233
|
-
};
|
|
14234
|
-
}
|
|
14235
|
-
if (input.metaKey) {
|
|
14236
|
-
return {
|
|
14237
|
-
zoom: state.zoom,
|
|
14238
|
-
panX: state.panX,
|
|
14239
|
-
panY: state.panY - input.deltaY
|
|
14240
|
-
};
|
|
14241
|
-
}
|
|
14242
|
-
const factor = input.deltaY < 0 ? 1.1 : 0.9;
|
|
14243
|
-
const newZoom = Math.min(bounds.max, Math.max(bounds.min, state.zoom * factor));
|
|
14244
|
-
const worldX = (input.mouseX - state.panX) / state.zoom;
|
|
14245
|
-
const worldY = (input.mouseY - state.panY) / state.zoom;
|
|
14246
|
-
return {
|
|
14247
|
-
zoom: newZoom,
|
|
14248
|
-
panX: input.mouseX - worldX * newZoom,
|
|
14249
|
-
panY: input.mouseY - worldY * newZoom
|
|
14250
|
-
};
|
|
14251
|
-
}
|
|
14252
14679
|
function useVelocityTracker() {
|
|
14253
14680
|
return useMemo(() => createVelocityTracker(), []);
|
|
14254
14681
|
}
|
|
@@ -16373,85 +16800,64 @@ function UnknownIcon({ className, size = 20 }) {
|
|
|
16373
16800
|
}
|
|
16374
16801
|
);
|
|
16375
16802
|
}
|
|
16376
|
-
function
|
|
16377
|
-
const flat = new Array(poly2.length * 2);
|
|
16378
|
-
for (let i = 0; i < poly2.length; i++) {
|
|
16379
|
-
flat[i * 2] = poly2[i].x;
|
|
16380
|
-
flat[i * 2 + 1] = poly2[i].y;
|
|
16381
|
-
}
|
|
16382
|
-
return flat;
|
|
16383
|
-
}
|
|
16384
|
-
function polygonContainsRectCenter(poly2, rect) {
|
|
16385
|
-
return pointInPolygon(flattenVerts(poly2), rect.x + rect.width / 2, rect.y + rect.height / 2);
|
|
16386
|
-
}
|
|
16387
|
-
function polygonContainsRect(poly2, rect) {
|
|
16388
|
-
if (poly2.length < 3) return false;
|
|
16389
|
-
const flat = flattenVerts(poly2);
|
|
16390
|
-
if (!pointInPolygon(flat, rect.x, rect.y)) return false;
|
|
16391
|
-
if (!pointInPolygon(flat, rect.x + rect.width, rect.y)) return false;
|
|
16392
|
-
if (!pointInPolygon(flat, rect.x + rect.width, rect.y + rect.height)) return false;
|
|
16393
|
-
if (!pointInPolygon(flat, rect.x, rect.y + rect.height)) return false;
|
|
16394
|
-
return !anyPolyEdgeCrossesRect(poly2, rect);
|
|
16395
|
-
}
|
|
16396
|
-
function polygonIntersectsRect(poly2, rect) {
|
|
16397
|
-
if (poly2.length < 3) return false;
|
|
16398
|
-
const ab = polygonAabb(poly2);
|
|
16399
|
-
if (ab.x + ab.width < rect.x || ab.x > rect.x + rect.width) return false;
|
|
16400
|
-
if (ab.y + ab.height < rect.y || ab.y > rect.y + rect.height) return false;
|
|
16401
|
-
for (const v of poly2) {
|
|
16402
|
-
if (v.x >= rect.x && v.x <= rect.x + rect.width && v.y >= rect.y && v.y <= rect.y + rect.height) return true;
|
|
16403
|
-
}
|
|
16404
|
-
const flat = flattenVerts(poly2);
|
|
16405
|
-
if (pointInPolygon(flat, rect.x, rect.y)) return true;
|
|
16406
|
-
if (pointInPolygon(flat, rect.x + rect.width, rect.y)) return true;
|
|
16407
|
-
if (pointInPolygon(flat, rect.x + rect.width, rect.y + rect.height)) return true;
|
|
16408
|
-
if (pointInPolygon(flat, rect.x, rect.y + rect.height)) return true;
|
|
16409
|
-
return anyPolyEdgeCrossesRect(poly2, rect);
|
|
16410
|
-
}
|
|
16411
|
-
function polygonAabb(poly2) {
|
|
16412
|
-
let minX = Infinity, minY = Infinity, maxX = -Infinity, maxY = -Infinity;
|
|
16413
|
-
for (const v of poly2) {
|
|
16414
|
-
if (v.x < minX) minX = v.x;
|
|
16415
|
-
if (v.y < minY) minY = v.y;
|
|
16416
|
-
if (v.x > maxX) maxX = v.x;
|
|
16417
|
-
if (v.y > maxY) maxY = v.y;
|
|
16418
|
-
}
|
|
16419
|
-
return { x: minX, y: minY, width: maxX - minX, height: maxY - minY };
|
|
16420
|
-
}
|
|
16421
|
-
function anyPolyEdgeCrossesRect(poly2, rect) {
|
|
16422
|
-
const r0x = rect.x, r0y = rect.y;
|
|
16423
|
-
const r1x = rect.x + rect.width, r1y = rect.y;
|
|
16424
|
-
const r2x = rect.x + rect.width, r2y = rect.y + rect.height;
|
|
16425
|
-
const r3x = rect.x, r3y = rect.y + rect.height;
|
|
16426
|
-
for (let i = 0, j = poly2.length - 1; i < poly2.length; j = i++) {
|
|
16427
|
-
const a = poly2[j], b = poly2[i];
|
|
16428
|
-
if (segmentsCross(a.x, a.y, b.x, b.y, r0x, r0y, r1x, r1y)) return true;
|
|
16429
|
-
if (segmentsCross(a.x, a.y, b.x, b.y, r1x, r1y, r2x, r2y)) return true;
|
|
16430
|
-
if (segmentsCross(a.x, a.y, b.x, b.y, r2x, r2y, r3x, r3y)) return true;
|
|
16431
|
-
if (segmentsCross(a.x, a.y, b.x, b.y, r3x, r3y, r0x, r0y)) return true;
|
|
16432
|
-
}
|
|
16433
|
-
return false;
|
|
16434
|
-
}
|
|
16435
|
-
|
|
16436
|
-
// src/features/paths/pathHitTest.ts
|
|
16437
|
-
function extractVertices(path) {
|
|
16803
|
+
function closedSubpaths(path, tolerance) {
|
|
16438
16804
|
const { commands, coords } = path;
|
|
16439
|
-
const
|
|
16805
|
+
const out = [];
|
|
16806
|
+
let sub2 = [];
|
|
16807
|
+
let subStartX = 0, subStartY = 0;
|
|
16808
|
+
let curX = 0, curY = 0;
|
|
16440
16809
|
let ci = 0;
|
|
16441
16810
|
for (let i = 0; i < commands.length; i++) {
|
|
16442
16811
|
const cmd = commands[i];
|
|
16443
|
-
|
|
16444
|
-
|
|
16445
|
-
|
|
16446
|
-
|
|
16447
|
-
|
|
16448
|
-
|
|
16449
|
-
|
|
16450
|
-
|
|
16451
|
-
|
|
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}`);
|
|
16452
16858
|
}
|
|
16453
16859
|
}
|
|
16454
|
-
return
|
|
16860
|
+
return out;
|
|
16455
16861
|
}
|
|
16456
16862
|
function rectToVerts(r) {
|
|
16457
16863
|
return [
|
|
@@ -16461,7 +16867,7 @@ function rectToVerts(r) {
|
|
|
16461
16867
|
{ x: r.x, y: r.y + r.height }
|
|
16462
16868
|
];
|
|
16463
16869
|
}
|
|
16464
|
-
function
|
|
16870
|
+
function flattenVerts(poly2) {
|
|
16465
16871
|
const flat = new Array(poly2.length * 2);
|
|
16466
16872
|
for (let i = 0; i < poly2.length; i++) {
|
|
16467
16873
|
flat[i * 2] = poly2[i].x;
|
|
@@ -16469,15 +16875,10 @@ function flattenVerts2(poly2) {
|
|
|
16469
16875
|
}
|
|
16470
16876
|
return flat;
|
|
16471
16877
|
}
|
|
16472
|
-
function polygonContainsPolygon(outer, inner) {
|
|
16473
|
-
if (inner.length === 0) return false;
|
|
16474
|
-
const flatOuter = flattenVerts2(outer);
|
|
16475
|
-
return inner.every((p) => pointInPolygon(flatOuter, p.x, p.y));
|
|
16476
|
-
}
|
|
16477
16878
|
function polygonsIntersect(a, b) {
|
|
16478
16879
|
if (a.length === 0 || b.length === 0) return false;
|
|
16479
|
-
if (pointInPolygon(
|
|
16480
|
-
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;
|
|
16481
16882
|
for (let i = 0; i < a.length; i++) {
|
|
16482
16883
|
const a0 = a[i], a1 = a[(i + 1) % a.length];
|
|
16483
16884
|
for (let j = 0; j < b.length; j++) {
|
|
@@ -16487,35 +16888,105 @@ function polygonsIntersect(a, b) {
|
|
|
16487
16888
|
}
|
|
16488
16889
|
return false;
|
|
16489
16890
|
}
|
|
16490
|
-
function
|
|
16491
|
-
|
|
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);
|
|
16492
16937
|
}
|
|
16493
|
-
function
|
|
16938
|
+
function pathContainsPoint(path, x, y, opts = {}) {
|
|
16939
|
+
return pointInPath(path, x, y, opts);
|
|
16940
|
+
}
|
|
16941
|
+
function pathContainsRect(path, rect, opts = {}) {
|
|
16494
16942
|
if (path.kind === "rect") {
|
|
16495
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;
|
|
16496
16944
|
}
|
|
16497
|
-
|
|
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);
|
|
16498
16951
|
}
|
|
16499
|
-
function pathIntersectsRect(path, rect) {
|
|
16952
|
+
function pathIntersectsRect(path, rect, opts = {}) {
|
|
16500
16953
|
if (path.kind === "rect") {
|
|
16501
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;
|
|
16502
16955
|
}
|
|
16503
|
-
|
|
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);
|
|
16504
16963
|
}
|
|
16505
|
-
function pathContainsPolygon(path, polygon) {
|
|
16964
|
+
function pathContainsPolygon(path, polygon, opts = {}) {
|
|
16506
16965
|
if (polygon.length === 0) return false;
|
|
16507
16966
|
if (path.kind === "rect") {
|
|
16508
16967
|
return polygon.every(
|
|
16509
16968
|
(p) => p.x >= path.x && p.x <= path.x + path.width && p.y >= path.y && p.y <= path.y + path.height
|
|
16510
16969
|
);
|
|
16511
16970
|
}
|
|
16512
|
-
|
|
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);
|
|
16513
16977
|
}
|
|
16514
|
-
function pathIntersectsPolygon(path, polygon) {
|
|
16978
|
+
function pathIntersectsPolygon(path, polygon, opts = {}) {
|
|
16979
|
+
if (polygon.length === 0) return false;
|
|
16515
16980
|
if (path.kind === "rect") {
|
|
16516
16981
|
return polygonsIntersect(rectToVerts(path), polygon);
|
|
16517
16982
|
}
|
|
16518
|
-
|
|
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);
|
|
16519
16990
|
}
|
|
16520
16991
|
|
|
16521
16992
|
// src/features/paths/markerSites.ts
|
|
@@ -16908,10 +17379,11 @@ var TEXT_PAINTER = {
|
|
|
16908
17379
|
if (boxes.length === 0) return null;
|
|
16909
17380
|
return rectsToPath(boxes);
|
|
16910
17381
|
},
|
|
16911
|
-
// `filled` is unconditional
|
|
16912
|
-
//
|
|
16913
|
-
//
|
|
16914
|
-
//
|
|
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.
|
|
16915
17387
|
ink: (node, _pose, ctx) => {
|
|
16916
17388
|
const d = node.data;
|
|
16917
17389
|
return { filled: true, ...inkReach(resolveNodeStroke(d.stroke), ctx?.scale) };
|
|
@@ -16947,7 +17419,7 @@ function resolveNodeFill(fill, fallback) {
|
|
|
16947
17419
|
return fill === void 0 ? fallback : fill;
|
|
16948
17420
|
}
|
|
16949
17421
|
function resolveNodeStroke(stroke) {
|
|
16950
|
-
if (stroke
|
|
17422
|
+
if (stroke?.paint == null) return null;
|
|
16951
17423
|
return stroke;
|
|
16952
17424
|
}
|
|
16953
17425
|
function strokeInPoseFrame(stroke, box) {
|
|
@@ -18069,6 +18541,7 @@ function worldOf(region, xf, view) {
|
|
|
18069
18541
|
}
|
|
18070
18542
|
|
|
18071
18543
|
// src/affordances/rotationHandle.ts
|
|
18544
|
+
var isAnnulusForm = (paint) => "fill" in paint || "stroke" in paint || "insetPx" in paint;
|
|
18072
18545
|
var DEFAULT_PAINT = {
|
|
18073
18546
|
fill: { fill: "solid", color: "rgba(26, 19, 13, 0.12)" },
|
|
18074
18547
|
insetPx: 10
|
|
@@ -18077,7 +18550,7 @@ function createRotationAffordance(opts = {}) {
|
|
|
18077
18550
|
const { bandPx = 24, paint = DEFAULT_PAINT, cursor } = opts;
|
|
18078
18551
|
const annulusPaint = (() => {
|
|
18079
18552
|
if (!paint) return null;
|
|
18080
|
-
if (
|
|
18553
|
+
if (!isAnnulusForm(paint)) {
|
|
18081
18554
|
return { kind: "annulus", stroke: paint };
|
|
18082
18555
|
}
|
|
18083
18556
|
return {
|
|
@@ -18273,29 +18746,6 @@ function useTextTool() {
|
|
|
18273
18746
|
[]
|
|
18274
18747
|
);
|
|
18275
18748
|
}
|
|
18276
|
-
function usePinchZoomTool(canvasRef, getView, setView, opts = {}) {
|
|
18277
|
-
const getViewRef = useRef(getView);
|
|
18278
|
-
getViewRef.current = getView;
|
|
18279
|
-
const setViewRef = useRef(setView);
|
|
18280
|
-
setViewRef.current = setView;
|
|
18281
|
-
const { min = DEFAULT_MIN_ZOOM, max = DEFAULT_MAX_ZOOM, enabled = true } = opts;
|
|
18282
|
-
const resolveTargetRef = useRef(opts.resolveTarget);
|
|
18283
|
-
resolveTargetRef.current = opts.resolveTarget;
|
|
18284
|
-
usePinchGesture(canvasRef, (clientAnchor, scaleFactor) => {
|
|
18285
|
-
const el = canvasRef.current;
|
|
18286
|
-
if (!el) return;
|
|
18287
|
-
const target = resolveTargetRef.current?.(clientAnchor.x, clientAnchor.y) ?? null;
|
|
18288
|
-
let anchor;
|
|
18289
|
-
if (target) {
|
|
18290
|
-
anchor = { x: clientAnchor.x - target.origin.left, y: clientAnchor.y - target.origin.top };
|
|
18291
|
-
} else {
|
|
18292
|
-
const [cx, cy] = clientToCanvas(el, clientAnchor.x, clientAnchor.y);
|
|
18293
|
-
anchor = { x: cx, y: cy };
|
|
18294
|
-
}
|
|
18295
|
-
const newView = zoomAt(target?.view ?? getViewRef.current(), anchor, scaleFactor, { min, max });
|
|
18296
|
-
(target ? target.setView : setViewRef.current)(newView);
|
|
18297
|
-
}, enabled);
|
|
18298
|
-
}
|
|
18299
18749
|
|
|
18300
18750
|
// src/util/constrainTo45.ts
|
|
18301
18751
|
function constrainTo45(dx, dy) {
|
|
@@ -20611,7 +21061,6 @@ function CanvasInner(props, ref) {
|
|
|
20611
21061
|
previewIdsExtra,
|
|
20612
21062
|
previewPoseExtra,
|
|
20613
21063
|
gestureSource,
|
|
20614
|
-
viewport,
|
|
20615
21064
|
backgroundFill,
|
|
20616
21065
|
cursorCoordsHud,
|
|
20617
21066
|
pickHud,
|
|
@@ -20620,7 +21069,8 @@ function CanvasInner(props, ref) {
|
|
|
20620
21069
|
decorationLayer,
|
|
20621
21070
|
getIsVisible,
|
|
20622
21071
|
layerVisibility,
|
|
20623
|
-
layerOrder
|
|
21072
|
+
layerOrder,
|
|
21073
|
+
layerGroups
|
|
20624
21074
|
} = props;
|
|
20625
21075
|
const resolvedDebugConfig = useMemo(() => {
|
|
20626
21076
|
if (debugProp === false) return null;
|
|
@@ -20773,25 +21223,7 @@ function CanvasInner(props, ref) {
|
|
|
20773
21223
|
const glRendererRef = useRef(null);
|
|
20774
21224
|
const layerCacheRef = useRef(/* @__PURE__ */ new Map());
|
|
20775
21225
|
const lastResizeRef = useRef(null);
|
|
20776
|
-
const pinchConfig = viewport?.pinchZoom === true ? {} : viewport?.pinchZoom || null;
|
|
20777
21226
|
const viewRegistry = useOptionalViewRegistry();
|
|
20778
|
-
const viewRegistryRef = useRef(viewRegistry);
|
|
20779
|
-
viewRegistryRef.current = viewRegistry;
|
|
20780
|
-
const resolvePinchTarget = useCallback((clientX, clientY) => {
|
|
20781
|
-
const reg = viewRegistryRef.current;
|
|
20782
|
-
if (!reg) return null;
|
|
20783
|
-
const target = reg.resolver.at(null, clientX, clientY);
|
|
20784
|
-
if (target.id === null) return null;
|
|
20785
|
-
const api = reg.list().find((r) => r.id === target.id)?.target.deps?.().view;
|
|
20786
|
-
if (!api) return null;
|
|
20787
|
-
return { view: api.get(), setView: api.set, origin: target.origin };
|
|
20788
|
-
}, []);
|
|
20789
|
-
usePinchZoomTool(
|
|
20790
|
-
canvasRef,
|
|
20791
|
-
getView,
|
|
20792
|
-
setView,
|
|
20793
|
-
{ ...pinchConfig ?? {}, enabled: pinchConfig !== null, resolveTarget: resolvePinchTarget }
|
|
20794
|
-
);
|
|
20795
21227
|
const noopAdapter = useMemo(
|
|
20796
21228
|
() => ({
|
|
20797
21229
|
getPose: () => ({}),
|
|
@@ -20883,6 +21315,7 @@ function CanvasInner(props, ref) {
|
|
|
20883
21315
|
const selectedIdsForWiring = effectiveSelection.current;
|
|
20884
21316
|
const {
|
|
20885
21317
|
helpers: viewHelpers,
|
|
21318
|
+
chromeState: viewChromeState,
|
|
20886
21319
|
effectiveBoundsOf,
|
|
20887
21320
|
previewExtraRef
|
|
20888
21321
|
} = useViewHelpers({
|
|
@@ -21051,6 +21484,7 @@ function CanvasInner(props, ref) {
|
|
|
21051
21484
|
dpr: dprProp,
|
|
21052
21485
|
layerVisibility,
|
|
21053
21486
|
layerOrder,
|
|
21487
|
+
layerGroups,
|
|
21054
21488
|
shaders
|
|
21055
21489
|
});
|
|
21056
21490
|
paintInputsRef.current = {
|
|
@@ -21061,6 +21495,7 @@ function CanvasInner(props, ref) {
|
|
|
21061
21495
|
dpr: dprProp,
|
|
21062
21496
|
layerVisibility,
|
|
21063
21497
|
layerOrder,
|
|
21498
|
+
layerGroups,
|
|
21064
21499
|
shaders
|
|
21065
21500
|
};
|
|
21066
21501
|
const paint = useCallback(() => {
|
|
@@ -21075,6 +21510,7 @@ function CanvasInner(props, ref) {
|
|
|
21075
21510
|
dpr: dprIn,
|
|
21076
21511
|
layerVisibility: vis,
|
|
21077
21512
|
layerOrder: order,
|
|
21513
|
+
layerGroups: groups,
|
|
21078
21514
|
shaders: paintShaders
|
|
21079
21515
|
} = paintInputsRef.current;
|
|
21080
21516
|
sink?.beginFrame();
|
|
@@ -21125,7 +21561,9 @@ function CanvasInner(props, ref) {
|
|
|
21125
21561
|
order,
|
|
21126
21562
|
view,
|
|
21127
21563
|
{ width: w, height: h },
|
|
21128
|
-
layerCacheRef.current
|
|
21564
|
+
layerCacheRef.current,
|
|
21565
|
+
void 0,
|
|
21566
|
+
groups
|
|
21129
21567
|
);
|
|
21130
21568
|
renderer.render(commands, viewToMat3(view));
|
|
21131
21569
|
paintedVersionRef.current = contentVersionRef.current?.() ?? 0;
|
|
@@ -21143,8 +21581,11 @@ function CanvasInner(props, ref) {
|
|
|
21143
21581
|
dprProp,
|
|
21144
21582
|
layerVisibility,
|
|
21145
21583
|
layerOrder,
|
|
21584
|
+
layerGroups,
|
|
21146
21585
|
shaderIdKey,
|
|
21147
21586
|
syncPaint,
|
|
21587
|
+
viewChromeState,
|
|
21588
|
+
getIsVisible,
|
|
21148
21589
|
requestRedraw
|
|
21149
21590
|
]);
|
|
21150
21591
|
useEffect(() => {
|
|
@@ -21355,6 +21796,14 @@ function createDependentsIndex() {
|
|
|
21355
21796
|
// src/core/scene/scene.ts
|
|
21356
21797
|
var defaultIdCounter = 0;
|
|
21357
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
|
+
}
|
|
21358
21807
|
function createScene(options) {
|
|
21359
21808
|
if (!options.systemLayers || options.systemLayers.length === 0) {
|
|
21360
21809
|
throw new Error("useScene: systemLayers must declare at least one layer");
|
|
@@ -21578,6 +22027,28 @@ function createScene(options) {
|
|
|
21578
22027
|
state.nodes.get(id).derivePath = spec.derivePath;
|
|
21579
22028
|
if (cacheForRedo) pendingDerivePathPatches.set(id, spec.derivePath);
|
|
21580
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
|
+
}
|
|
21581
22052
|
function registerKitOp(kind, handler) {
|
|
21582
22053
|
registered.set(kind, handler);
|
|
21583
22054
|
}
|
|
@@ -21635,8 +22106,10 @@ function createScene(options) {
|
|
|
21635
22106
|
}
|
|
21636
22107
|
},
|
|
21637
22108
|
revert: (p) => {
|
|
22109
|
+
const keys = new Map((p.fnKeys ?? []).map((k) => [k.id, k]));
|
|
21638
22110
|
for (const n of p.nodes) {
|
|
21639
22111
|
const clone = n.kind === "container" ? { ...n, children: [...n.children] } : { ...n };
|
|
22112
|
+
restoreNodeFunctions(clone, keys.get(n.id));
|
|
21640
22113
|
state.nodes.set(n.id, clone);
|
|
21641
22114
|
dependents.add(n.id, clone.dependsOn ?? []);
|
|
21642
22115
|
}
|
|
@@ -21974,6 +22447,9 @@ function createScene(options) {
|
|
|
21974
22447
|
remove(id) {
|
|
21975
22448
|
scene.removeMany([id]);
|
|
21976
22449
|
},
|
|
22450
|
+
removalClosure(rootIds) {
|
|
22451
|
+
return removalClosure(rootIds).ids;
|
|
22452
|
+
},
|
|
21977
22453
|
removeMany(rootIds) {
|
|
21978
22454
|
if (rootIds.length === 0) return;
|
|
21979
22455
|
const { ids, removing } = removalClosure(rootIds);
|
|
@@ -21983,7 +22459,20 @@ function createScene(options) {
|
|
|
21983
22459
|
});
|
|
21984
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);
|
|
21985
22461
|
for (const nid of ids) overrides.clear(nid);
|
|
21986
|
-
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
|
+
};
|
|
21987
22476
|
executeAndLog("kit:remove", payload, "remove");
|
|
21988
22477
|
},
|
|
21989
22478
|
update(id, patch) {
|
|
@@ -22280,6 +22769,10 @@ function createScene(options) {
|
|
|
22280
22769
|
const layer = { id: l.id };
|
|
22281
22770
|
if (l.visible === false) layer.visible = false;
|
|
22282
22771
|
if (l.locked === true) layer.locked = true;
|
|
22772
|
+
if (l.kind === "user") {
|
|
22773
|
+
layer.kind = "user";
|
|
22774
|
+
layer.name = l.name;
|
|
22775
|
+
}
|
|
22283
22776
|
return layer;
|
|
22284
22777
|
});
|
|
22285
22778
|
return { version: 1, systemLayers, nodes };
|
|
@@ -22297,12 +22790,7 @@ function createScene(options) {
|
|
|
22297
22790
|
if (state.layerIndex.has(spec.id)) {
|
|
22298
22791
|
throw new Error(`Scene.loadState: duplicate system layer id "${spec.id}"`);
|
|
22299
22792
|
}
|
|
22300
|
-
state.layers.push(
|
|
22301
|
-
kind: "system",
|
|
22302
|
-
id: spec.id,
|
|
22303
|
-
visible: spec.visible ?? true,
|
|
22304
|
-
locked: spec.locked ?? false
|
|
22305
|
-
});
|
|
22793
|
+
state.layers.push(layerFromSerialized(spec));
|
|
22306
22794
|
state.layerIndex.set(spec.id, i);
|
|
22307
22795
|
}
|
|
22308
22796
|
history.clear();
|
|
@@ -22402,16 +22890,16 @@ function sceneSelectionStore(scene) {
|
|
|
22402
22890
|
}
|
|
22403
22891
|
function sceneFromJSON(json, options) {
|
|
22404
22892
|
const registry2 = options.registry ?? {};
|
|
22405
|
-
const
|
|
22406
|
-
|
|
22407
|
-
systemLayers: json.systemLayers,
|
|
22408
|
-
initial,
|
|
22893
|
+
const scene = createScene({
|
|
22894
|
+
systemLayers: json.systemLayers.map((l) => ({ id: l.id })),
|
|
22409
22895
|
registry: registry2,
|
|
22410
22896
|
...options.historyLimit !== void 0 ? { historyLimit: options.historyLimit } : {},
|
|
22411
22897
|
...options.coalesceWindowMs !== void 0 ? { coalesceWindowMs: options.coalesceWindowMs } : {},
|
|
22412
22898
|
...options.generateId !== void 0 ? { generateId: options.generateId } : {},
|
|
22413
22899
|
...options.ops !== void 0 ? { ops: options.ops } : {}
|
|
22414
22900
|
});
|
|
22901
|
+
scene.loadState(json);
|
|
22902
|
+
return scene;
|
|
22415
22903
|
}
|
|
22416
22904
|
var SelectionContext = createContext(null);
|
|
22417
22905
|
function SelectionContextProvider({ children }) {
|
|
@@ -23154,7 +23642,7 @@ function CanvasView(props) {
|
|
|
23154
23642
|
}
|
|
23155
23643
|
function ActionsProviderIfRoot({ children }) {
|
|
23156
23644
|
const parent = useActionsRegistry();
|
|
23157
|
-
if (parent) return /* @__PURE__ */ jsx(
|
|
23645
|
+
if (parent) return /* @__PURE__ */ jsx(ActionsScope, { children });
|
|
23158
23646
|
return /* @__PURE__ */ jsx(ActionsProvider, { children });
|
|
23159
23647
|
}
|
|
23160
23648
|
function useToolActions(tools) {
|
|
@@ -23221,6 +23709,65 @@ function PointerPublisher({
|
|
|
23221
23709
|
}, [ctx, canvasRef, registry2]);
|
|
23222
23710
|
return null;
|
|
23223
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
|
+
}
|
|
23224
23771
|
function isPathLike(p) {
|
|
23225
23772
|
if (!p || typeof p !== "object") return false;
|
|
23226
23773
|
const k = p.kind;
|
|
@@ -23402,12 +23949,19 @@ function sceneToAdapter(scene, options = {}) {
|
|
|
23402
23949
|
id: node.id,
|
|
23403
23950
|
...index !== void 0 ? { index } : {},
|
|
23404
23951
|
...node.parent !== null ? { parent: node.parent } : {},
|
|
23405
|
-
...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 } : {}
|
|
23406
23957
|
});
|
|
23407
23958
|
},
|
|
23408
23959
|
removeNode(id) {
|
|
23409
23960
|
scene.remove(asNodeId(id));
|
|
23410
23961
|
},
|
|
23962
|
+
getRemovalClosure(ids) {
|
|
23963
|
+
return [...scene.removalClosure(ids.map(asNodeId))];
|
|
23964
|
+
},
|
|
23411
23965
|
// AreaSelectAdapter surface — included unconditionally so plain
|
|
23412
23966
|
// `useSelectTool(sceneToAdapter(scene, { selection }))` Just Works for the
|
|
23413
23967
|
// marquee gesture. `applyOps` (above) dispatches transiently when called
|
|
@@ -25333,17 +25887,18 @@ function useActionsPropResolver(actions) {
|
|
|
25333
25887
|
useEffect(() => {
|
|
25334
25888
|
if (!reg) return;
|
|
25335
25889
|
const prop = actionsRef.current;
|
|
25890
|
+
const unregisters = [];
|
|
25336
25891
|
if (prop === null) {
|
|
25337
|
-
const
|
|
25338
|
-
|
|
25339
|
-
|
|
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
|
+
};
|
|
25340
25896
|
}
|
|
25341
25897
|
if (!prop) return;
|
|
25342
|
-
const unregisters = [];
|
|
25343
25898
|
const warnedIds = /* @__PURE__ */ new Set();
|
|
25344
25899
|
for (const [slotId, entry] of Object.entries(prop)) {
|
|
25345
25900
|
if (entry === null) {
|
|
25346
|
-
reg.
|
|
25901
|
+
unregisters.push(reg.mute(slotId));
|
|
25347
25902
|
continue;
|
|
25348
25903
|
}
|
|
25349
25904
|
const isFull = (e) => typeof e.id === "string" && typeof e.label === "string" && !!e.invoker;
|
|
@@ -25400,7 +25955,7 @@ function useViewportActions(args) {
|
|
|
25400
25955
|
r.register(makePinchZoomAction(typeof pinchZoom === "object" ? pinchZoom : {}))
|
|
25401
25956
|
);
|
|
25402
25957
|
} else {
|
|
25403
|
-
r.
|
|
25958
|
+
unregisters.push(r.mute("viewport.pinchZoom"));
|
|
25404
25959
|
}
|
|
25405
25960
|
return () => {
|
|
25406
25961
|
for (const u of unregisters) u();
|
|
@@ -28291,7 +28846,7 @@ function applyOverlayStyle(el, style) {
|
|
|
28291
28846
|
el.style.border = "0";
|
|
28292
28847
|
el.style.outline = "none";
|
|
28293
28848
|
el.style.background = "transparent";
|
|
28294
|
-
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";
|
|
28295
28850
|
el.style.caretColor = style.caretColor;
|
|
28296
28851
|
el.style.font = fontString(style);
|
|
28297
28852
|
el.style.lineHeight = String(style.lineHeight);
|
|
@@ -31259,6 +31814,6 @@ function mergeContributions(...bundles) {
|
|
|
31259
31814
|
return out;
|
|
31260
31815
|
}
|
|
31261
31816
|
|
|
31262
|
-
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,
|
|
31263
|
-
//# sourceMappingURL=chunk-
|
|
31264
|
-
//# 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
|