@weasel-js/core 0.8.0 → 1.0.0
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 +413 -0
- package/dist/{DrawCommand-BKJ5JPkC.d.ts → DrawCommand-DCmiNkBj.d.ts} +14 -169
- package/dist/{chunk-GLZLSPGJ.js → chunk-6SHZHXXR.js} +46 -9
- package/dist/chunk-6SHZHXXR.js.map +1 -0
- package/dist/{chunk-DLV5F4NY.js → chunk-D2C6K6FO.js} +915 -547
- package/dist/chunk-D2C6K6FO.js.map +1 -0
- package/dist/chunk-DCIU3SRK.js +505 -0
- package/dist/chunk-DCIU3SRK.js.map +1 -0
- package/dist/chunk-IO5Z75X4.js +167 -0
- package/dist/chunk-IO5Z75X4.js.map +1 -0
- package/dist/{chunk-BPRHGTLQ.js → chunk-UB6A6L77.js} +3 -3
- package/dist/{chunk-BPRHGTLQ.js.map → chunk-UB6A6L77.js.map} +1 -1
- package/dist/{chunk-CMBE45MT.js → chunk-Z3KNFTTS.js} +6 -6
- package/dist/chunk-Z3KNFTTS.js.map +1 -0
- package/dist/{index-Clf_koyR.d.ts → index-ChM3ZJ2v.d.ts} +103 -90
- package/dist/index.d.ts +313 -32
- package/dist/index.js +6 -6
- package/dist/insert.js +5 -5
- package/dist/insert.js.map +1 -1
- package/dist/move.js +2 -2
- package/dist/paint-types-CnLIzqq1.d.ts +261 -0
- package/dist/patterns-builtin.d.ts +57 -2
- package/dist/patterns-builtin.js +1 -97
- package/dist/patterns-builtin.js.map +1 -1
- package/dist/renderer.d.ts +24 -7
- package/dist/renderer.js +6 -6
- package/dist/resize.js +2 -2
- package/dist/routing.d.ts +4 -4
- package/dist/routing.js +1 -1
- package/dist/{viewToMat3-DFMdZvVl.d.ts → viewToMat3-BvaWCN99.d.ts} +1 -1
- package/package.json +6 -6
- package/dist/chunk-6DAUIMTO.js +0 -233
- package/dist/chunk-6DAUIMTO.js.map +0 -1
- package/dist/chunk-CMBE45MT.js.map +0 -1
- package/dist/chunk-DLV5F4NY.js.map +0 -1
- package/dist/chunk-GLZLSPGJ.js.map +0 -1
- package/dist/chunk-Y52N27PF.js +0 -39
- package/dist/chunk-Y52N27PF.js.map +0 -1
- package/dist/registerTexture-BzHTLhD9.d.ts +0 -25
|
@@ -1,17 +1,17 @@
|
|
|
1
|
-
import { defineViewportTool,
|
|
2
|
-
import { scratchKey, createTransformOp, snap, getScratch, createReparentOp, setScratch } from './chunk-
|
|
3
|
-
import { fixedCornerOf, DEFAULT_RESIZE_BEHAVIORS, CORNER_ANCHORS, cornerPoint } from './chunk-
|
|
4
|
-
import { AUTO_POSE_DESCRIPTOR, RECT_POSE_DESCRIPTOR, resolveUnit,
|
|
1
|
+
import { ActionDisabledReason, defineViewportTool, useOptionalDepRegistry, DepRegistryProvider, useActionsRegistry, ActionsProvider, useDepRegistry, defineTool, reportRouteConflicts, buildDepsFromRequires, useDepSource, actionBindings } from './chunk-DCIU3SRK.js';
|
|
2
|
+
import { scratchKey, createTransformOp, snap, getScratch, createReparentOp, setScratch } from './chunk-UB6A6L77.js';
|
|
3
|
+
import { fixedCornerOf, DEFAULT_RESIZE_BEHAVIORS, CORNER_ANCHORS, cornerPoint } from './chunk-Z3KNFTTS.js';
|
|
4
|
+
import { AUTO_POSE_DESCRIPTOR, RECT_POSE_DESCRIPTOR, resolveUnit, pathPoseDescriptor, polygonFromPoints, starPath, regularPolygonPath, linePath, ellipsePath, rectPath, strokeHitTest, withinPxRadius, boundsOfPath, PATH_M, PATH_L, PATH_Z, PATH_Q, PATH_C, DEFAULT_FLATTEN_TOLERANCE, flattenQuadratic, flattenCubic, PathBuilder, pointInPath, transformPath, translatePath, pxExtent, remapRotatedLeaf, withinPxBox, flattenCubicWithArcLen, flattenQuadraticWithArcLen, PATH_CMD_LENGTHS, pointToGridCell } from './chunk-6SHZHXXR.js';
|
|
5
5
|
import { dispatchApplyBatch, dlog, dwarn, usePointerContext, PointerContextProvider, applyOpsTo, extractWeaselClipboardFromSvg, parseWeaselClipboardText, materializePaste, WEASEL_CLIPBOARD_MIME, WEASEL_CLIPBOARD_MIME_WEB, sniffWeaselClipboardText } from './chunk-775XXAHR.js';
|
|
6
6
|
import { createSetSelectionOp } from './chunk-BHVYVFGV.js';
|
|
7
7
|
import { registerOpFactory, createDeleteOp, createInsertOp, rebuildOp } from './chunk-GVCNT7UH.js';
|
|
8
|
-
import { getTexture } from './chunk-
|
|
8
|
+
import { getTexture, chunks, dots, crosshatch, hatch } from './chunk-IO5Z75X4.js';
|
|
9
9
|
import { createContext, createElement, forwardRef, useMemo, useRef, useState, useCallback, useImperativeHandle, useEffect, useSyncExternalStore, useContext, useReducer, useLayoutEffect } 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, glyphGeneration, syncDynamicPageTexture, ensureFontTexture, dynamicPageTextureId, textureCacheKey, resolveFontVariant, resolveGlyphFallback, glyphOutline } from '@weasel-js/font';
|
|
11
11
|
export { canQueryLocalFonts, canQueryLocalFonts as canQueryLocalFonts2, enableLocalFontOutlines, enableLocalFontOutlines as enableLocalFontOutlines2, hasFontOutlines, hasFontOutlines as hasFontOutlines2, isCanvasFont, isCanvasFont as isCanvasFont2, listFontOutlines, listFontOutlines as listFontOutlines2, outlineStatus, outlineStatus as outlineStatus2, registerCanvasFont, registerCanvasFont as registerCanvasFont2, registerFont, registerFont as registerFont2, registerFontOutlines, registerFontOutlines as registerFontOutlines2, subscribeGlyphReady, subscribeGlyphReady as subscribeGlyphReady2, unregisterCanvasFont, unregisterCanvasFont as unregisterCanvasFont2, unregisterFontOutlines, unregisterFontOutlines as unregisterFontOutlines2 } from '@weasel-js/font';
|
|
12
12
|
import earcut from 'earcut';
|
|
13
|
-
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
14
13
|
import { applyToPoint, rotateAboutPoint, boxToBox, pointInPolygon, segmentsCross } from '@weasel-js/geom';
|
|
14
|
+
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
15
15
|
import polygonClipping from 'polygon-clipping';
|
|
16
16
|
import { matchSpec, mimeMatchesGlob } from '@weasel-js/gestures';
|
|
17
17
|
import { NORMAL, IMPLICIT_TAGS } from '@weasel-js/modes';
|
|
@@ -19,7 +19,7 @@ import { createHistory } from '@weasel-js/history';
|
|
|
19
19
|
export * from '@weasel-js/history';
|
|
20
20
|
|
|
21
21
|
// src/version.ts
|
|
22
|
-
var VERSION = "0.
|
|
22
|
+
var VERSION = "1.0.0" ;
|
|
23
23
|
|
|
24
24
|
// src/features/grid/roundToCell.ts
|
|
25
25
|
function roundToCell(value, cellSize) {
|
|
@@ -333,6 +333,60 @@ var GRAD_FILL_UNIFORMS = [
|
|
|
333
333
|
];
|
|
334
334
|
var GRAD_FILL_ATTRIBUTES = ["a_position"];
|
|
335
335
|
|
|
336
|
+
// src/renderer/shaders/patternFill.ts
|
|
337
|
+
var PATTERN_VERT_SRC = (
|
|
338
|
+
/* glsl */
|
|
339
|
+
`#version 300 es
|
|
340
|
+
in vec2 a_position;
|
|
341
|
+
uniform mat3 u_proj;
|
|
342
|
+
uniform mat3 u_model;
|
|
343
|
+
uniform mat3 u_worldInv;
|
|
344
|
+
out vec2 v_world;
|
|
345
|
+
void main() {
|
|
346
|
+
vec3 screen = u_model * vec3(a_position, 1.0);
|
|
347
|
+
vec3 clip = u_proj * vec3(screen.xy, 1.0);
|
|
348
|
+
gl_Position = vec4(clip.xy, 0.0, 1.0);
|
|
349
|
+
vec3 world = u_worldInv * vec3(screen.xy, 1.0);
|
|
350
|
+
v_world = world.xy;
|
|
351
|
+
}
|
|
352
|
+
`
|
|
353
|
+
);
|
|
354
|
+
var PATTERN_FRAG_SRC = (
|
|
355
|
+
/* glsl */
|
|
356
|
+
`#version 300 es
|
|
357
|
+
precision highp float;
|
|
358
|
+
in vec2 v_world;
|
|
359
|
+
uniform sampler2D u_sampler;
|
|
360
|
+
uniform vec2 u_tileOrigin;
|
|
361
|
+
uniform vec2 u_tileSize;
|
|
362
|
+
uniform float u_opacity;
|
|
363
|
+
uniform float u_alpha;
|
|
364
|
+
uniform mat4 u_colorMatrix;
|
|
365
|
+
uniform vec4 u_colorBias;
|
|
366
|
+
out vec4 outColor;
|
|
367
|
+
void main() {
|
|
368
|
+
vec2 uv = (v_world - u_tileOrigin) / max(u_tileSize, vec2(0.0001));
|
|
369
|
+
vec4 texel = texture(u_sampler, uv);
|
|
370
|
+
vec4 mapped = clamp(u_colorMatrix * texel + u_colorBias, 0.0, 1.0);
|
|
371
|
+
float a = mapped.a * u_opacity * u_alpha;
|
|
372
|
+
outColor = vec4(mapped.rgb * a, a);
|
|
373
|
+
}
|
|
374
|
+
`
|
|
375
|
+
);
|
|
376
|
+
var PATTERN_FILL_UNIFORMS = [
|
|
377
|
+
"u_proj",
|
|
378
|
+
"u_model",
|
|
379
|
+
"u_worldInv",
|
|
380
|
+
"u_sampler",
|
|
381
|
+
"u_tileOrigin",
|
|
382
|
+
"u_tileSize",
|
|
383
|
+
"u_opacity",
|
|
384
|
+
"u_alpha",
|
|
385
|
+
"u_colorMatrix",
|
|
386
|
+
"u_colorBias"
|
|
387
|
+
];
|
|
388
|
+
var PATTERN_FILL_ATTRIBUTES = ["a_position"];
|
|
389
|
+
|
|
336
390
|
// src/renderer/cache/GLMeshCache.ts
|
|
337
391
|
var GLMeshCache = class {
|
|
338
392
|
constructor(gl, aPositionLoc) {
|
|
@@ -458,17 +512,20 @@ var GLTextureCache = class {
|
|
|
458
512
|
has(id) {
|
|
459
513
|
return this.map.has(id);
|
|
460
514
|
}
|
|
461
|
-
|
|
515
|
+
/** Uploads once per id; `wrap` therefore applies on first upload only.
|
|
516
|
+
* An id is either a pattern tile or a shader texture, never both. */
|
|
517
|
+
upload(id, source, wrap = "clamp") {
|
|
462
518
|
if (this.map.has(id)) return id;
|
|
463
519
|
const gl = this.gl;
|
|
464
520
|
const tex = gl.createTexture();
|
|
465
521
|
if (!tex) throw new Error(`GLTextureCache: createTexture failed for id="${id}"`);
|
|
522
|
+
const wrapMode = wrap === "repeat" ? gl.REPEAT : gl.CLAMP_TO_EDGE;
|
|
466
523
|
gl.bindTexture(gl.TEXTURE_2D, tex);
|
|
467
524
|
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, source);
|
|
468
525
|
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
|
|
469
526
|
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
|
|
470
|
-
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S,
|
|
471
|
-
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T,
|
|
527
|
+
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, wrapMode);
|
|
528
|
+
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, wrapMode);
|
|
472
529
|
gl.bindTexture(gl.TEXTURE_2D, null);
|
|
473
530
|
this.map.set(id, tex);
|
|
474
531
|
return id;
|
|
@@ -1100,6 +1157,18 @@ function scale(m, sx, sy) {
|
|
|
1100
1157
|
const s = create(sx, 0, 0, sy, 0, 0);
|
|
1101
1158
|
return multiply(m, s);
|
|
1102
1159
|
}
|
|
1160
|
+
function invert(m) {
|
|
1161
|
+
const a = m[0], b = m[1];
|
|
1162
|
+
const c = m[3], d = m[4];
|
|
1163
|
+
const tx = m[6], ty = m[7];
|
|
1164
|
+
const det = a * d - b * c;
|
|
1165
|
+
if (det === 0 || !Number.isFinite(det)) return identity();
|
|
1166
|
+
const ia = d / det;
|
|
1167
|
+
const ib = -b / det;
|
|
1168
|
+
const ic = -c / det;
|
|
1169
|
+
const id = a / det;
|
|
1170
|
+
return create(ia, ib, ic, id, -(ia * tx + ic * ty), -(ib * tx + id * ty));
|
|
1171
|
+
}
|
|
1103
1172
|
function apply(m, x, y) {
|
|
1104
1173
|
const a = m[0], b = m[1];
|
|
1105
1174
|
const c = m[3], d = m[4];
|
|
@@ -1127,6 +1196,7 @@ var mat3 = {
|
|
|
1127
1196
|
multiply,
|
|
1128
1197
|
translate,
|
|
1129
1198
|
scale,
|
|
1199
|
+
invert,
|
|
1130
1200
|
apply,
|
|
1131
1201
|
screenToClip
|
|
1132
1202
|
};
|
|
@@ -3048,28 +3118,42 @@ function drawPathFillPattern(ctx, fill, handle) {
|
|
|
3048
3118
|
if (isDev3) console.warn(`weasel: pattern TextureHandle "${tex.id}" not registered`);
|
|
3049
3119
|
return;
|
|
3050
3120
|
}
|
|
3051
|
-
ctx.textureCache.upload(tex.id, entry.source);
|
|
3121
|
+
ctx.textureCache.upload(tex.id, entry.source, "repeat");
|
|
3052
3122
|
const gl = ctx.gl;
|
|
3053
|
-
gl.useProgram(ctx.
|
|
3123
|
+
gl.useProgram(ctx.patternFill.handle);
|
|
3054
3124
|
gl.bindVertexArray(handle.vao);
|
|
3055
|
-
setProjAndModel(ctx, ctx.
|
|
3056
|
-
setColorMatrixUniforms(ctx, ctx.
|
|
3125
|
+
setProjAndModel(ctx, ctx.patternFill);
|
|
3126
|
+
setColorMatrixUniforms(ctx, ctx.patternFill);
|
|
3127
|
+
gl.uniformMatrix3fv(ctx.patternFill.uniform("u_worldInv"), false, gradientSpaceInverse(ctx, fill.units));
|
|
3128
|
+
const [tw, th] = textureSize(entry.source);
|
|
3129
|
+
const origin = fill.origin ?? { x: 0, y: 0 };
|
|
3130
|
+
gl.uniform2f(ctx.patternFill.uniform("u_tileOrigin"), origin.x, origin.y);
|
|
3131
|
+
gl.uniform2f(ctx.patternFill.uniform("u_tileSize"), tw, th);
|
|
3057
3132
|
ctx.textureCache.bind(tex.id, 0);
|
|
3058
|
-
gl.uniform1i(ctx.
|
|
3059
|
-
gl.uniform1f(ctx.
|
|
3060
|
-
gl.uniform1f(ctx.
|
|
3133
|
+
gl.uniform1i(ctx.patternFill.uniform("u_sampler"), 0);
|
|
3134
|
+
gl.uniform1f(ctx.patternFill.uniform("u_opacity"), fill.opacity ?? 1);
|
|
3135
|
+
gl.uniform1f(ctx.patternFill.uniform("u_alpha"), ctx.state.alpha);
|
|
3061
3136
|
applyClipTest(ctx);
|
|
3062
3137
|
gl.drawElements(gl.TRIANGLES, handle.indexCount, gl.UNSIGNED_INT, 0);
|
|
3063
3138
|
gl.bindVertexArray(null);
|
|
3064
3139
|
}
|
|
3140
|
+
function textureSize(source) {
|
|
3141
|
+
const w = "naturalWidth" in source ? source.naturalWidth : source.width;
|
|
3142
|
+
const h = "naturalHeight" in source ? source.naturalHeight : source.height;
|
|
3143
|
+
return [w || 1, h || 1];
|
|
3144
|
+
}
|
|
3145
|
+
function gradientSpaceInverse(ctx, units) {
|
|
3146
|
+
if (units === "local") return mat3.invert(ctx.state.transform);
|
|
3147
|
+
if (units === "world" && ctx.viewMatrix) return mat3.invert(ctx.viewMatrix);
|
|
3148
|
+
return mat3.identity();
|
|
3149
|
+
}
|
|
3065
3150
|
function drawPathFillGradient(ctx, fill, handle) {
|
|
3066
3151
|
const gl = ctx.gl;
|
|
3067
3152
|
const key = ctx.gradRampCache.upload(fill.stops);
|
|
3068
3153
|
gl.useProgram(ctx.gradFill.handle);
|
|
3069
3154
|
gl.bindVertexArray(handle.vao);
|
|
3070
3155
|
setProjAndModel(ctx, ctx.gradFill);
|
|
3071
|
-
|
|
3072
|
-
gl.uniformMatrix3fv(ctx.gradFill.uniform("u_worldInv"), false, identity3);
|
|
3156
|
+
gl.uniformMatrix3fv(ctx.gradFill.uniform("u_worldInv"), false, gradientSpaceInverse(ctx, fill.units));
|
|
3073
3157
|
ctx.gradRampCache.bind(key, 0);
|
|
3074
3158
|
gl.uniform1i(ctx.gradFill.uniform("u_ramp"), 0);
|
|
3075
3159
|
gl.uniform1f(ctx.gradFill.uniform("u_alpha"), ctx.state.alpha);
|
|
@@ -3589,6 +3673,11 @@ function drawImage(ctx, cmd) {
|
|
|
3589
3673
|
setProjAndModel(ctx, ctx.imageFill);
|
|
3590
3674
|
setColorMatrixUniforms(ctx, ctx.imageFill);
|
|
3591
3675
|
ctx.imageCache.bind(cmd.image, 0);
|
|
3676
|
+
gl.texParameteri(
|
|
3677
|
+
gl.TEXTURE_2D,
|
|
3678
|
+
gl.TEXTURE_MAG_FILTER,
|
|
3679
|
+
cmd.sampling === "nearest" ? gl.NEAREST : gl.LINEAR
|
|
3680
|
+
);
|
|
3592
3681
|
gl.uniform1i(ctx.imageFill.uniform("u_sampler"), 0);
|
|
3593
3682
|
gl.uniform1f(ctx.imageFill.uniform("u_opacity"), cmd.opacity ?? 1);
|
|
3594
3683
|
gl.uniform1f(ctx.imageFill.uniform("u_alpha"), ctx.state.alpha);
|
|
@@ -3689,6 +3778,7 @@ var WeaselRenderer = class {
|
|
|
3689
3778
|
textSdfR8;
|
|
3690
3779
|
imageFill;
|
|
3691
3780
|
gradFill;
|
|
3781
|
+
patternFill;
|
|
3692
3782
|
meshCache;
|
|
3693
3783
|
textureCache;
|
|
3694
3784
|
imageCache;
|
|
@@ -3764,6 +3854,9 @@ var WeaselRenderer = class {
|
|
|
3764
3854
|
this.gradFill = new ShaderProgram(this.gl, GRAD_VERT_SRC, GRAD_FRAG_SRC);
|
|
3765
3855
|
this.gradFill.lookupUniforms(GRAD_FILL_UNIFORMS);
|
|
3766
3856
|
this.gradFill.lookupAttributes(GRAD_FILL_ATTRIBUTES);
|
|
3857
|
+
this.patternFill = new ShaderProgram(this.gl, PATTERN_VERT_SRC, PATTERN_FRAG_SRC);
|
|
3858
|
+
this.patternFill.lookupUniforms(PATTERN_FILL_UNIFORMS);
|
|
3859
|
+
this.patternFill.lookupAttributes(PATTERN_FILL_ATTRIBUTES);
|
|
3767
3860
|
const aPos = this.pathFill.attribute("a_position");
|
|
3768
3861
|
if (aPos === void 0) throw new Error("WeaselRenderer: a_position not found in path-fill shader");
|
|
3769
3862
|
this.meshCache = new GLMeshCache(this.gl, aPos);
|
|
@@ -3872,6 +3965,9 @@ var WeaselRenderer = class {
|
|
|
3872
3965
|
this.gradFill = new ShaderProgram(this.gl, GRAD_VERT_SRC, GRAD_FRAG_SRC);
|
|
3873
3966
|
this.gradFill.lookupUniforms(GRAD_FILL_UNIFORMS);
|
|
3874
3967
|
this.gradFill.lookupAttributes(GRAD_FILL_ATTRIBUTES);
|
|
3968
|
+
this.patternFill = new ShaderProgram(this.gl, PATTERN_VERT_SRC, PATTERN_FRAG_SRC);
|
|
3969
|
+
this.patternFill.lookupUniforms(PATTERN_FILL_UNIFORMS);
|
|
3970
|
+
this.patternFill.lookupAttributes(PATTERN_FILL_ATTRIBUTES);
|
|
3875
3971
|
const aPos = this.pathFill.attribute("a_position");
|
|
3876
3972
|
if (aPos === void 0) throw new Error("a_position missing after restore");
|
|
3877
3973
|
this.meshCache = new GLMeshCache(this.gl, aPos);
|
|
@@ -3944,7 +4040,15 @@ var WeaselRenderer = class {
|
|
|
3944
4040
|
if (this.rectIbo) gl.deleteBuffer(this.rectIbo);
|
|
3945
4041
|
if (this.rectVao) gl.deleteVertexArray(this.rectVao);
|
|
3946
4042
|
}
|
|
3947
|
-
|
|
4043
|
+
/**
|
|
4044
|
+
* Draw one frame.
|
|
4045
|
+
*
|
|
4046
|
+
* `viewMatrix` is the frame's world→screen transform. It is only consulted
|
|
4047
|
+
* by `units: 'world'` gradients, which fall back to screen space without
|
|
4048
|
+
* it — every other command carries its own transform in the stream, so
|
|
4049
|
+
* callers with no view concept can keep calling `render(commands)`.
|
|
4050
|
+
*/
|
|
4051
|
+
render(commands, viewMatrix) {
|
|
3948
4052
|
if (this.contextLost || this.disposed) return;
|
|
3949
4053
|
const gl = this.gl;
|
|
3950
4054
|
this.meshCache.drainPendingDeletes();
|
|
@@ -3959,6 +4063,7 @@ var WeaselRenderer = class {
|
|
|
3959
4063
|
textSdfR8: this.textSdfR8,
|
|
3960
4064
|
imageFill: this.imageFill,
|
|
3961
4065
|
gradFill: this.gradFill,
|
|
4066
|
+
patternFill: this.patternFill,
|
|
3962
4067
|
meshCache: this.meshCache,
|
|
3963
4068
|
textureCache: this.textureCache,
|
|
3964
4069
|
imageCache: this.imageCache,
|
|
@@ -3973,7 +4078,8 @@ var WeaselRenderer = class {
|
|
|
3973
4078
|
heightCss: this.heightCss,
|
|
3974
4079
|
clipDepth: 0,
|
|
3975
4080
|
flattenTolerance: this.flattenTolerance,
|
|
3976
|
-
textOutlineMinScreenSize: this.textOutlineMinScreenSize
|
|
4081
|
+
textOutlineMinScreenSize: this.textOutlineMinScreenSize,
|
|
4082
|
+
viewMatrix
|
|
3977
4083
|
};
|
|
3978
4084
|
for (const cmd of commands) dispatch(ctx, cmd);
|
|
3979
4085
|
this.meshCache.freeTransient();
|
|
@@ -4021,6 +4127,10 @@ var WeaselRenderer = class {
|
|
|
4021
4127
|
return this.gradFill;
|
|
4022
4128
|
}
|
|
4023
4129
|
/** @internal */
|
|
4130
|
+
_patternFill() {
|
|
4131
|
+
return this.patternFill;
|
|
4132
|
+
}
|
|
4133
|
+
/** @internal */
|
|
4024
4134
|
_meshCache() {
|
|
4025
4135
|
return this.meshCache;
|
|
4026
4136
|
}
|
|
@@ -4086,6 +4196,11 @@ function alignedStrokeRect(rect, align, width = 1) {
|
|
|
4086
4196
|
};
|
|
4087
4197
|
}
|
|
4088
4198
|
|
|
4199
|
+
// src/core/viewport/meanScale.ts
|
|
4200
|
+
function meanScale(s) {
|
|
4201
|
+
return Math.sqrt(s.x * s.y);
|
|
4202
|
+
}
|
|
4203
|
+
|
|
4089
4204
|
// src/features/grid/layer.ts
|
|
4090
4205
|
var DEFAULT_LINE = {
|
|
4091
4206
|
paint: { fill: "solid", color: "rgba(255, 255, 255, 0.08)" },
|
|
@@ -5224,254 +5339,6 @@ function matchesKeyBinding(e, b) {
|
|
|
5224
5339
|
}
|
|
5225
5340
|
return true;
|
|
5226
5341
|
}
|
|
5227
|
-
var DepRegistryContext = createContext(null);
|
|
5228
|
-
function DepRegistryProvider({ children }) {
|
|
5229
|
-
const sourcesRef = useRef(/* @__PURE__ */ new Map());
|
|
5230
|
-
const registry2 = useMemo(() => ({
|
|
5231
|
-
register: (name, source) => {
|
|
5232
|
-
sourcesRef.current.set(name, source);
|
|
5233
|
-
return () => {
|
|
5234
|
-
sourcesRef.current.delete(name);
|
|
5235
|
-
};
|
|
5236
|
-
},
|
|
5237
|
-
get: (name) => sourcesRef.current.get(name)?.()
|
|
5238
|
-
}), []);
|
|
5239
|
-
return /* @__PURE__ */ jsx(DepRegistryContext.Provider, { value: registry2, children });
|
|
5240
|
-
}
|
|
5241
|
-
function useDepRegistry() {
|
|
5242
|
-
const r = useContext(DepRegistryContext);
|
|
5243
|
-
if (r === null) {
|
|
5244
|
-
throw new Error("useDepRegistry: no DepRegistryProvider in scope. Wrap your tree with <DepRegistryProvider> (typically inside <SceneCanvas>).");
|
|
5245
|
-
}
|
|
5246
|
-
return r;
|
|
5247
|
-
}
|
|
5248
|
-
function useOptionalDepRegistry() {
|
|
5249
|
-
return useContext(DepRegistryContext);
|
|
5250
|
-
}
|
|
5251
|
-
function useDepSource(name, source) {
|
|
5252
|
-
const registry2 = useDepRegistry();
|
|
5253
|
-
const sourceRef = useRef(source);
|
|
5254
|
-
sourceRef.current = source;
|
|
5255
|
-
useEffect(() => {
|
|
5256
|
-
return registry2.register(name, () => sourceRef.current());
|
|
5257
|
-
}, [name, registry2]);
|
|
5258
|
-
}
|
|
5259
|
-
|
|
5260
|
-
// src/interactions/actions/buildDeps.ts
|
|
5261
|
-
var DEV = (() => {
|
|
5262
|
-
try {
|
|
5263
|
-
return Boolean(import.meta.env?.DEV);
|
|
5264
|
-
} catch {
|
|
5265
|
-
return false;
|
|
5266
|
-
}
|
|
5267
|
-
})();
|
|
5268
|
-
function buildDepsFromRequires(action, depRegistry) {
|
|
5269
|
-
const requires = action.requires ?? [];
|
|
5270
|
-
const entries = requires.map((name) => [name, depRegistry.get(name)]);
|
|
5271
|
-
const deps = Object.fromEntries(entries);
|
|
5272
|
-
if (DEV) {
|
|
5273
|
-
const declared = new Set(requires);
|
|
5274
|
-
return new Proxy(deps, {
|
|
5275
|
-
get(target, prop, receiver) {
|
|
5276
|
-
if (typeof prop === "string" && !declared.has(prop) && prop !== "then") {
|
|
5277
|
-
const message = `[weasel:dispatcher] action "${action.id}" read deps.${prop} but did not declare it in \`requires\`. Add \`requires: [...'${prop}']\` to the descriptor or the dep will be undefined at runtime.`;
|
|
5278
|
-
console.warn(message);
|
|
5279
|
-
throw new Error(message);
|
|
5280
|
-
}
|
|
5281
|
-
return Reflect.get(target, prop, receiver);
|
|
5282
|
-
}
|
|
5283
|
-
});
|
|
5284
|
-
}
|
|
5285
|
-
return deps;
|
|
5286
|
-
}
|
|
5287
|
-
var ActionDisabledReason = {
|
|
5288
|
-
SelectionRequired: "selection-required",
|
|
5289
|
-
SceneEmpty: "scene-empty",
|
|
5290
|
-
NotApplicable: "not-applicable",
|
|
5291
|
-
/** Sentinel: the predicate threw. Surfaced by `evaluateEnabled`'s catch. */
|
|
5292
|
-
PredicateThrew: "predicate-threw"
|
|
5293
|
-
};
|
|
5294
|
-
var enabledSlowWarned = /* @__PURE__ */ new Set();
|
|
5295
|
-
var enabledThrewWarned = /* @__PURE__ */ new Set();
|
|
5296
|
-
var ENABLED_BUDGET_MS = 4;
|
|
5297
|
-
function evaluateEnabled(action, deps) {
|
|
5298
|
-
if (!action.enabled) return { enabled: true };
|
|
5299
|
-
const isDev3 = typeof process !== "undefined" ? process.env.NODE_ENV !== "production" : true;
|
|
5300
|
-
const now = typeof performance !== "undefined" && typeof performance.now === "function" ? () => performance.now() : () => Date.now();
|
|
5301
|
-
const start = isDev3 ? now() : 0;
|
|
5302
|
-
try {
|
|
5303
|
-
const result = action.enabled(deps);
|
|
5304
|
-
if (isDev3) {
|
|
5305
|
-
const elapsed = now() - start;
|
|
5306
|
-
if (elapsed > ENABLED_BUDGET_MS && !enabledSlowWarned.has(action.id)) {
|
|
5307
|
-
enabledSlowWarned.add(action.id);
|
|
5308
|
-
console.warn(
|
|
5309
|
-
`weasel actions: enabled() for action "${action.id}" took ${elapsed.toFixed(2)}ms (budget ${ENABLED_BUDGET_MS}ms). The predicate must be pure and fast \u2014 see Action.enabled JSDoc.`
|
|
5310
|
-
);
|
|
5311
|
-
}
|
|
5312
|
-
}
|
|
5313
|
-
if (result === true) return { enabled: true };
|
|
5314
|
-
return { enabled: false, reason: result };
|
|
5315
|
-
} catch (e) {
|
|
5316
|
-
if (isDev3 && !enabledThrewWarned.has(action.id)) {
|
|
5317
|
-
enabledThrewWarned.add(action.id);
|
|
5318
|
-
console.warn(
|
|
5319
|
-
`weasel actions: enabled() for action "${action.id}" threw; treating as disabled. The predicate must not throw \u2014 see Action.enabled JSDoc.`,
|
|
5320
|
-
e
|
|
5321
|
-
);
|
|
5322
|
-
}
|
|
5323
|
-
return { enabled: false, reason: ActionDisabledReason.PredicateThrew };
|
|
5324
|
-
}
|
|
5325
|
-
}
|
|
5326
|
-
function validateActionId(id) {
|
|
5327
|
-
if (id.length === 0) {
|
|
5328
|
-
throw new Error(`weasel: action id may not be empty`);
|
|
5329
|
-
}
|
|
5330
|
-
if (RESERVED_ID_PREFIXES.has(id[0])) {
|
|
5331
|
-
throw new Error(
|
|
5332
|
-
`weasel: action id "${id}" starts with reserved sigil "${id[0]}" (reserved set: ${[...RESERVED_ID_PREFIXES].join(" ")})`
|
|
5333
|
-
);
|
|
5334
|
-
}
|
|
5335
|
-
if (RESERVED_ID_NAMES.has(id)) {
|
|
5336
|
-
throw new Error(
|
|
5337
|
-
`weasel: action id "${id}" collides with a reserved phase keyword (reserved: ${[...RESERVED_ID_NAMES].join(", ")})`
|
|
5338
|
-
);
|
|
5339
|
-
}
|
|
5340
|
-
}
|
|
5341
|
-
function validateActionDefaultBinding(action) {
|
|
5342
|
-
const gs = action.defaultBinding;
|
|
5343
|
-
if (!gs) return;
|
|
5344
|
-
const entries = Array.isArray(gs) ? gs : [gs];
|
|
5345
|
-
for (const entry of entries) {
|
|
5346
|
-
const spec = "kind" in entry ? entry : entry.spec;
|
|
5347
|
-
const phase = spec.phase;
|
|
5348
|
-
if (phase === void 0) continue;
|
|
5349
|
-
const atoms = Array.isArray(phase) ? phase : [{ channel: "&", phase }];
|
|
5350
|
-
for (const atom of atoms) {
|
|
5351
|
-
if (atom.channel === "&") {
|
|
5352
|
-
throw new Error(
|
|
5353
|
-
`weasel: action "${action.id}" defaultBinding uses '&' channel which has no owning tool to resolve to. Use a named tool channel (e.g. '[rect:engaged]') or '*' instead, or move this binding to the tool's own Tool.bindings.`
|
|
5354
|
-
);
|
|
5355
|
-
}
|
|
5356
|
-
}
|
|
5357
|
-
}
|
|
5358
|
-
}
|
|
5359
|
-
var ActionsContext = createContext(null);
|
|
5360
|
-
function ActionsProvider({ children }) {
|
|
5361
|
-
const actionsRef = useRef(/* @__PURE__ */ new Map());
|
|
5362
|
-
const versionRef = useRef(0);
|
|
5363
|
-
const cachedRef = useRef([]);
|
|
5364
|
-
const cachedVerRef = useRef(-1);
|
|
5365
|
-
const listenersRef = useRef(/* @__PURE__ */ new Set());
|
|
5366
|
-
const depReg = useOptionalDepRegistry();
|
|
5367
|
-
const depRegRef = useRef(depReg);
|
|
5368
|
-
depRegRef.current = depReg;
|
|
5369
|
-
const wiredDepRegRef = useRef(null);
|
|
5370
|
-
const dispatcherRef = useRef(null);
|
|
5371
|
-
const registry2 = useMemo(() => {
|
|
5372
|
-
const snapshot = () => {
|
|
5373
|
-
const v = versionRef.current;
|
|
5374
|
-
if (cachedVerRef.current === v) return cachedRef.current;
|
|
5375
|
-
const out = Object.freeze(Array.from(actionsRef.current.values()));
|
|
5376
|
-
cachedRef.current = out;
|
|
5377
|
-
cachedVerRef.current = v;
|
|
5378
|
-
return out;
|
|
5379
|
-
};
|
|
5380
|
-
const notify2 = () => {
|
|
5381
|
-
for (const l of listenersRef.current) {
|
|
5382
|
-
try {
|
|
5383
|
-
l();
|
|
5384
|
-
} catch (err) {
|
|
5385
|
-
console.error("weasel ActionsRegistry: subscriber threw", err);
|
|
5386
|
-
}
|
|
5387
|
-
}
|
|
5388
|
-
};
|
|
5389
|
-
return {
|
|
5390
|
-
register: (action) => {
|
|
5391
|
-
validateActionId(action.id);
|
|
5392
|
-
validateActionDefaultBinding(action);
|
|
5393
|
-
actionsRef.current.set(action.id, action);
|
|
5394
|
-
versionRef.current++;
|
|
5395
|
-
notify2();
|
|
5396
|
-
return () => {
|
|
5397
|
-
const cur = actionsRef.current.get(action.id);
|
|
5398
|
-
if (cur === action) {
|
|
5399
|
-
actionsRef.current.delete(action.id);
|
|
5400
|
-
versionRef.current++;
|
|
5401
|
-
notify2();
|
|
5402
|
-
}
|
|
5403
|
-
};
|
|
5404
|
-
},
|
|
5405
|
-
unregister: (id) => {
|
|
5406
|
-
if (actionsRef.current.delete(id)) {
|
|
5407
|
-
versionRef.current++;
|
|
5408
|
-
notify2();
|
|
5409
|
-
}
|
|
5410
|
-
},
|
|
5411
|
-
list: () => snapshot(),
|
|
5412
|
-
trigger: (id, params) => {
|
|
5413
|
-
const a = actionsRef.current.get(id);
|
|
5414
|
-
if (!a) return false;
|
|
5415
|
-
try {
|
|
5416
|
-
if (a.invoker && a.invoker.timing === "immediate") {
|
|
5417
|
-
const r = wiredDepRegRef.current ?? depRegRef.current;
|
|
5418
|
-
const deps = !r ? {} : a.requires ? buildDepsFromRequires(a, r) : {
|
|
5419
|
-
selection: r.get("selection"),
|
|
5420
|
-
scene: r.get("scene"),
|
|
5421
|
-
history: r.get("history"),
|
|
5422
|
-
view: r.get("view"),
|
|
5423
|
-
pointer: r.get("pointer"),
|
|
5424
|
-
activeTool: r.get("activeTool"),
|
|
5425
|
-
booleansAdapter: r.get("booleansAdapter")
|
|
5426
|
-
};
|
|
5427
|
-
a.invoker.run(deps, params);
|
|
5428
|
-
}
|
|
5429
|
-
} catch (err) {
|
|
5430
|
-
console.error(`weasel ActionsRegistry: action "${id}" threw`, err);
|
|
5431
|
-
}
|
|
5432
|
-
return true;
|
|
5433
|
-
},
|
|
5434
|
-
subscribe: (listener) => {
|
|
5435
|
-
listenersRef.current.add(listener);
|
|
5436
|
-
return () => {
|
|
5437
|
-
listenersRef.current.delete(listener);
|
|
5438
|
-
};
|
|
5439
|
-
},
|
|
5440
|
-
setDispatcher: (d) => {
|
|
5441
|
-
dispatcherRef.current = d;
|
|
5442
|
-
},
|
|
5443
|
-
setDepRegistry: (r) => {
|
|
5444
|
-
wiredDepRegRef.current = r;
|
|
5445
|
-
},
|
|
5446
|
-
begin: (id, params) => {
|
|
5447
|
-
const disp = dispatcherRef.current;
|
|
5448
|
-
if (!disp) return null;
|
|
5449
|
-
const r = wiredDepRegRef.current ?? depRegRef.current;
|
|
5450
|
-
const deps = r ? {
|
|
5451
|
-
selection: r.get("selection"),
|
|
5452
|
-
scene: r.get("scene"),
|
|
5453
|
-
history: r.get("history"),
|
|
5454
|
-
view: r.get("view"),
|
|
5455
|
-
pointer: r.get("pointer"),
|
|
5456
|
-
activeTool: r.get("activeTool"),
|
|
5457
|
-
booleansAdapter: r.get("booleansAdapter")
|
|
5458
|
-
} : {};
|
|
5459
|
-
return disp.beginUiOngoing(id, deps, params);
|
|
5460
|
-
}
|
|
5461
|
-
};
|
|
5462
|
-
}, []);
|
|
5463
|
-
return /* @__PURE__ */ jsx(ActionsContext.Provider, { value: registry2, children });
|
|
5464
|
-
}
|
|
5465
|
-
function useActionsRegistry() {
|
|
5466
|
-
return useContext(ActionsContext);
|
|
5467
|
-
}
|
|
5468
|
-
function useAction(action) {
|
|
5469
|
-
const reg = useActionsRegistry();
|
|
5470
|
-
useEffect(() => {
|
|
5471
|
-
if (!reg) return;
|
|
5472
|
-
return reg.register(action);
|
|
5473
|
-
}, [reg, action]);
|
|
5474
|
-
}
|
|
5475
5342
|
|
|
5476
5343
|
// src/interactions/actions/invoker.ts
|
|
5477
5344
|
function resolveParams(params) {
|
|
@@ -6044,6 +5911,62 @@ var moveAction = {
|
|
|
6044
5911
|
enabled: () => true
|
|
6045
5912
|
};
|
|
6046
5913
|
|
|
5914
|
+
// src/features/paths/poseRotation.ts
|
|
5915
|
+
function poseRotationOf(pose) {
|
|
5916
|
+
const p = pose;
|
|
5917
|
+
if (p.rotation && p.x != null && p.y != null && p.width != null && p.height != null) {
|
|
5918
|
+
return { cx: p.x + p.width / 2, cy: p.y + p.height / 2, rotation: p.rotation };
|
|
5919
|
+
}
|
|
5920
|
+
return null;
|
|
5921
|
+
}
|
|
5922
|
+
function rotatePathAround(path, cx, cy, rotation) {
|
|
5923
|
+
if (path.kind === "rect") {
|
|
5924
|
+
return rotateRectCorners(path.x, path.y, path.width, path.height, cx, cy, rotation);
|
|
5925
|
+
}
|
|
5926
|
+
return rotatePolygon(path, cx, cy, rotation);
|
|
5927
|
+
}
|
|
5928
|
+
function rotatePolygon(path, cx, cy, rotation) {
|
|
5929
|
+
const cos = Math.cos(rotation);
|
|
5930
|
+
const sin = Math.sin(rotation);
|
|
5931
|
+
const { commands, coords } = path;
|
|
5932
|
+
const next = new Float32Array(coords.length);
|
|
5933
|
+
let ci = 0;
|
|
5934
|
+
for (let i = 0; i < commands.length; i++) {
|
|
5935
|
+
const len = COORD_COUNT[commands[i]];
|
|
5936
|
+
for (let k = 0; k < len; k += 2) {
|
|
5937
|
+
const dx = coords[ci + k] - cx;
|
|
5938
|
+
const dy = coords[ci + k + 1] - cy;
|
|
5939
|
+
next[ci + k] = cx + dx * cos - dy * sin;
|
|
5940
|
+
next[ci + k + 1] = cy + dx * sin + dy * cos;
|
|
5941
|
+
}
|
|
5942
|
+
ci += len;
|
|
5943
|
+
}
|
|
5944
|
+
return { kind: "polygon", commands: path.commands, coords: next, fillRule: path.fillRule };
|
|
5945
|
+
}
|
|
5946
|
+
function rotateRectCorners(x, y, w, h, cx, cy, rotation) {
|
|
5947
|
+
const cos = Math.cos(rotation);
|
|
5948
|
+
const sin = Math.sin(rotation);
|
|
5949
|
+
const rotate = (px, py) => {
|
|
5950
|
+
const dx = px - cx;
|
|
5951
|
+
const dy = py - cy;
|
|
5952
|
+
return [cx + dx * cos - dy * sin, cy + dx * sin + dy * cos];
|
|
5953
|
+
};
|
|
5954
|
+
const [x0, y0] = rotate(x, y);
|
|
5955
|
+
const [x1, y1] = rotate(x + w, y);
|
|
5956
|
+
const [x2, y2] = rotate(x + w, y + h);
|
|
5957
|
+
const [x3, y3] = rotate(x, y + h);
|
|
5958
|
+
const commands = new Uint8Array([PATH_M, PATH_L, PATH_L, PATH_L, PATH_Z]);
|
|
5959
|
+
const coords = new Float32Array([x0, y0, x1, y1, x2, y2, x3, y3]);
|
|
5960
|
+
return { kind: "polygon", commands, coords, fillRule: "nonzero" };
|
|
5961
|
+
}
|
|
5962
|
+
var COORD_COUNT = {
|
|
5963
|
+
[PATH_M]: 2,
|
|
5964
|
+
[PATH_L]: 2,
|
|
5965
|
+
[PATH_C]: 6,
|
|
5966
|
+
[PATH_Q]: 4,
|
|
5967
|
+
[PATH_Z]: 0
|
|
5968
|
+
};
|
|
5969
|
+
|
|
6047
5970
|
// src/interactions/actions/rotate/geometry.ts
|
|
6048
5971
|
function aabbCenter(bounds) {
|
|
6049
5972
|
return { x: bounds.x + bounds.width / 2, y: bounds.y + bounds.height / 2 };
|
|
@@ -6360,6 +6283,13 @@ var resizeAction = {
|
|
|
6360
6283
|
const computePose = (id) => {
|
|
6361
6284
|
const sp = scratch.startPoses.get(id);
|
|
6362
6285
|
if (sp === void 0) return void 0;
|
|
6286
|
+
if (isGroupPath && poseRotationOf(sp) !== null) {
|
|
6287
|
+
return remapRotatedLeaf(
|
|
6288
|
+
sp,
|
|
6289
|
+
scratch.originBounds,
|
|
6290
|
+
proposedBounds
|
|
6291
|
+
);
|
|
6292
|
+
}
|
|
6363
6293
|
return scratch.geometry.remapBounds(sp, scratch.originBounds, proposedBounds);
|
|
6364
6294
|
};
|
|
6365
6295
|
scratch.previews.clear();
|
|
@@ -7217,7 +7147,13 @@ function makeViewportZoomAction(opts = {}) {
|
|
|
7217
7147
|
var viewportZoomAction = makeViewportZoomAction();
|
|
7218
7148
|
|
|
7219
7149
|
// src/interactions/dispatcher/predicates.ts
|
|
7220
|
-
|
|
7150
|
+
function bodyPredicate(fn) {
|
|
7151
|
+
return Object.assign(fn, { readsAffordance: false });
|
|
7152
|
+
}
|
|
7153
|
+
var isBody = bodyPredicate((_target, bodyTarget) => bodyTarget === "selected-body" || bodyTarget === "unselected-body");
|
|
7154
|
+
bodyPredicate((_target, bodyTarget) => bodyTarget === "selected-body");
|
|
7155
|
+
bodyPredicate((_target, bodyTarget) => bodyTarget === "unselected-body");
|
|
7156
|
+
bodyPredicate((_target, bodyTarget) => bodyTarget === "empty");
|
|
7221
7157
|
function kindOf(target) {
|
|
7222
7158
|
if (typeof target !== "object" || target === null) return void 0;
|
|
7223
7159
|
const k = target.kind;
|
|
@@ -7258,17 +7194,17 @@ function splitCubicAtT(p0, p1, p2, p3, t) {
|
|
|
7258
7194
|
function fitCubicThroughDeletion(prev, next) {
|
|
7259
7195
|
const dx = next.x - prev.x;
|
|
7260
7196
|
const dy = next.y - prev.y;
|
|
7261
|
-
const
|
|
7197
|
+
const dist3 = Math.sqrt(dx * dx + dy * dy);
|
|
7262
7198
|
const c1DirX = prev.outHandle ? prev.outHandle.x - prev.x : dx;
|
|
7263
7199
|
const c1DirY = prev.outHandle ? prev.outHandle.y - prev.y : dy;
|
|
7264
|
-
const c1 = controlOnSide(prev, c1DirX, c1DirY,
|
|
7200
|
+
const c1 = controlOnSide(prev, c1DirX, c1DirY, dist3, 1 / 3);
|
|
7265
7201
|
const c2DirX = next.inHandle ? next.inHandle.x - next.x : -dx;
|
|
7266
7202
|
const c2DirY = next.inHandle ? next.inHandle.y - next.y : -dy;
|
|
7267
|
-
const c2 = controlOnSide(next, c2DirX, c2DirY,
|
|
7203
|
+
const c2 = controlOnSide(next, c2DirX, c2DirY, dist3, 1 / 3);
|
|
7268
7204
|
return { c1, c2 };
|
|
7269
7205
|
}
|
|
7270
|
-
function controlOnSide(anchor, dirX, dirY,
|
|
7271
|
-
const targetDist =
|
|
7206
|
+
function controlOnSide(anchor, dirX, dirY, dist3, fraction) {
|
|
7207
|
+
const targetDist = dist3 * fraction;
|
|
7272
7208
|
const len = Math.hypot(dirX, dirY) || 1;
|
|
7273
7209
|
const ux = dirX / len, uy = dirY / len;
|
|
7274
7210
|
return { x: anchor.x + ux * targetDist, y: anchor.y + uy * targetDist };
|
|
@@ -7539,64 +7475,6 @@ function anchorsInRect(set, rect) {
|
|
|
7539
7475
|
}
|
|
7540
7476
|
return hits;
|
|
7541
7477
|
}
|
|
7542
|
-
|
|
7543
|
-
// src/features/paths/poseRotation.ts
|
|
7544
|
-
function poseRotationOf(pose) {
|
|
7545
|
-
const p = pose;
|
|
7546
|
-
if (p.rotation && p.x != null && p.y != null && p.width != null && p.height != null) {
|
|
7547
|
-
return { cx: p.x + p.width / 2, cy: p.y + p.height / 2, rotation: p.rotation };
|
|
7548
|
-
}
|
|
7549
|
-
return null;
|
|
7550
|
-
}
|
|
7551
|
-
function rotatePathAround(path, cx, cy, rotation) {
|
|
7552
|
-
if (path.kind === "rect") {
|
|
7553
|
-
return rotateRectCorners(path.x, path.y, path.width, path.height, cx, cy, rotation);
|
|
7554
|
-
}
|
|
7555
|
-
return rotatePolygon(path, cx, cy, rotation);
|
|
7556
|
-
}
|
|
7557
|
-
function rotatePolygon(path, cx, cy, rotation) {
|
|
7558
|
-
const cos = Math.cos(rotation);
|
|
7559
|
-
const sin = Math.sin(rotation);
|
|
7560
|
-
const { commands, coords } = path;
|
|
7561
|
-
const next = new Float32Array(coords.length);
|
|
7562
|
-
let ci = 0;
|
|
7563
|
-
for (let i = 0; i < commands.length; i++) {
|
|
7564
|
-
const len = COORD_COUNT[commands[i]];
|
|
7565
|
-
for (let k = 0; k < len; k += 2) {
|
|
7566
|
-
const dx = coords[ci + k] - cx;
|
|
7567
|
-
const dy = coords[ci + k + 1] - cy;
|
|
7568
|
-
next[ci + k] = cx + dx * cos - dy * sin;
|
|
7569
|
-
next[ci + k + 1] = cy + dx * sin + dy * cos;
|
|
7570
|
-
}
|
|
7571
|
-
ci += len;
|
|
7572
|
-
}
|
|
7573
|
-
return { kind: "polygon", commands: path.commands, coords: next, fillRule: path.fillRule };
|
|
7574
|
-
}
|
|
7575
|
-
function rotateRectCorners(x, y, w, h, cx, cy, rotation) {
|
|
7576
|
-
const cos = Math.cos(rotation);
|
|
7577
|
-
const sin = Math.sin(rotation);
|
|
7578
|
-
const rotate = (px, py) => {
|
|
7579
|
-
const dx = px - cx;
|
|
7580
|
-
const dy = py - cy;
|
|
7581
|
-
return [cx + dx * cos - dy * sin, cy + dx * sin + dy * cos];
|
|
7582
|
-
};
|
|
7583
|
-
const [x0, y0] = rotate(x, y);
|
|
7584
|
-
const [x1, y1] = rotate(x + w, y);
|
|
7585
|
-
const [x2, y2] = rotate(x + w, y + h);
|
|
7586
|
-
const [x3, y3] = rotate(x, y + h);
|
|
7587
|
-
const commands = new Uint8Array([PATH_M, PATH_L, PATH_L, PATH_L, PATH_Z]);
|
|
7588
|
-
const coords = new Float32Array([x0, y0, x1, y1, x2, y2, x3, y3]);
|
|
7589
|
-
return { kind: "polygon", commands, coords, fillRule: "nonzero" };
|
|
7590
|
-
}
|
|
7591
|
-
var COORD_COUNT = {
|
|
7592
|
-
[PATH_M]: 2,
|
|
7593
|
-
[PATH_L]: 2,
|
|
7594
|
-
[PATH_C]: 6,
|
|
7595
|
-
[PATH_Q]: 4,
|
|
7596
|
-
[PATH_Z]: 0
|
|
7597
|
-
};
|
|
7598
|
-
|
|
7599
|
-
// src/features/paths/pathInWorld.ts
|
|
7600
7478
|
function pathInPoseFrame(path, pose) {
|
|
7601
7479
|
if (path.kind === "rect") {
|
|
7602
7480
|
if (path.x === pose.x && path.y === pose.y && path.width === pose.width && path.height === pose.height) return path;
|
|
@@ -9281,7 +9159,7 @@ var LABEL = {
|
|
|
9281
9159
|
divide: "Divide",
|
|
9282
9160
|
crop: "Crop"
|
|
9283
9161
|
};
|
|
9284
|
-
function
|
|
9162
|
+
function isEmpty2(p) {
|
|
9285
9163
|
return p.commands.length === 0;
|
|
9286
9164
|
}
|
|
9287
9165
|
function applyBooleanOp(adapter, op) {
|
|
@@ -9319,7 +9197,7 @@ function applyBooleanOp(adapter, op) {
|
|
|
9319
9197
|
break;
|
|
9320
9198
|
}
|
|
9321
9199
|
}
|
|
9322
|
-
results = results.filter((p) => !
|
|
9200
|
+
results = results.filter((p) => !isEmpty2(p));
|
|
9323
9201
|
if (results.length === 0) return { kind: "noop", reason: "empty-result" };
|
|
9324
9202
|
const topmostId = entries[entries.length - 1].id;
|
|
9325
9203
|
const topAnchor = adapter.getZOrder?.(topmostId);
|
|
@@ -9870,14 +9748,24 @@ var DEFAULT_PALETTE = [
|
|
|
9870
9748
|
var GHOST_STROKE = DEFAULT_PALETTE[0];
|
|
9871
9749
|
|
|
9872
9750
|
// src/interactions/actions/defaults/setFill.ts
|
|
9751
|
+
function resolveFill(scratch, prev) {
|
|
9752
|
+
if (scratch.currentPaint) return scratch.currentPaint;
|
|
9753
|
+
const prevColor = typeof prev?.fill === "string" ? prev.fill : DEFAULT_FILL_COLOR;
|
|
9754
|
+
return mergeAlphaFromPrev(scratch.currentColor, prevColor);
|
|
9755
|
+
}
|
|
9873
9756
|
function refreshPreviews(scratch) {
|
|
9874
9757
|
scratch.previews.clear();
|
|
9875
9758
|
for (const id of scratch.ids) {
|
|
9876
9759
|
const prev = scratch.startData.get(id);
|
|
9877
|
-
|
|
9878
|
-
scratch.previews.set(id, { ...prev ?? {}, fill: next });
|
|
9760
|
+
scratch.previews.set(id, { ...prev ?? {}, fill: resolveFill(scratch, prev) });
|
|
9879
9761
|
}
|
|
9880
9762
|
}
|
|
9763
|
+
function readParams(params) {
|
|
9764
|
+
return {
|
|
9765
|
+
color: params?.color,
|
|
9766
|
+
paint: params?.paint
|
|
9767
|
+
};
|
|
9768
|
+
}
|
|
9881
9769
|
var setFillAction = {
|
|
9882
9770
|
id: "setFill",
|
|
9883
9771
|
label: "Set fill",
|
|
@@ -9892,9 +9780,10 @@ var setFillAction = {
|
|
|
9892
9780
|
if (!selection || !scene) return {};
|
|
9893
9781
|
const ids = selection.get();
|
|
9894
9782
|
if (ids.length === 0) return {};
|
|
9895
|
-
const
|
|
9896
|
-
const
|
|
9897
|
-
const
|
|
9783
|
+
const fromCtx = readParams(ctx.params);
|
|
9784
|
+
const fromOpts = readParams(opts?.params);
|
|
9785
|
+
const initialPaint = fromCtx.paint ?? fromOpts.paint;
|
|
9786
|
+
const initialColor = fromCtx.color ?? fromOpts.color ?? DEFAULT_STROKE_COLOR;
|
|
9898
9787
|
const startData = /* @__PURE__ */ new Map();
|
|
9899
9788
|
for (const id of ids) {
|
|
9900
9789
|
const node = scene.get(id);
|
|
@@ -9905,15 +9794,20 @@ var setFillAction = {
|
|
|
9905
9794
|
scene,
|
|
9906
9795
|
startData,
|
|
9907
9796
|
currentColor: initialColor,
|
|
9797
|
+
currentPaint: initialPaint,
|
|
9908
9798
|
previews: /* @__PURE__ */ new Map(),
|
|
9909
9799
|
applyOps
|
|
9910
9800
|
};
|
|
9911
9801
|
refreshPreviews(scratch);
|
|
9912
9802
|
return {
|
|
9913
9803
|
onMove(moveCtx) {
|
|
9914
|
-
const
|
|
9915
|
-
if (
|
|
9916
|
-
scratch.
|
|
9804
|
+
const { color, paint } = readParams(moveCtx.params);
|
|
9805
|
+
if (color === void 0 && paint === void 0) return;
|
|
9806
|
+
if (paint !== void 0) scratch.currentPaint = paint;
|
|
9807
|
+
if (color !== void 0) {
|
|
9808
|
+
scratch.currentColor = color;
|
|
9809
|
+
if (paint === void 0) scratch.currentPaint = void 0;
|
|
9810
|
+
}
|
|
9917
9811
|
refreshPreviews(scratch);
|
|
9918
9812
|
},
|
|
9919
9813
|
onEnd(_endCtx, reason) {
|
|
@@ -9923,8 +9817,7 @@ var setFillAction = {
|
|
|
9923
9817
|
}
|
|
9924
9818
|
const ops = [];
|
|
9925
9819
|
for (const id of scratch.ids) {
|
|
9926
|
-
const
|
|
9927
|
-
const merged = mergeAlphaFromPrev(scratch.currentColor, prev?.fill ?? DEFAULT_FILL_COLOR);
|
|
9820
|
+
const merged = resolveFill(scratch, scratch.startData.get(id));
|
|
9928
9821
|
const nodeNow = scratch.scene.get(id);
|
|
9929
9822
|
if (!nodeNow) continue;
|
|
9930
9823
|
const from = { ...nodeNow.data };
|
|
@@ -10818,6 +10711,54 @@ function targetRank(target) {
|
|
|
10818
10711
|
if (target.startsWith("affordance:")) return 2;
|
|
10819
10712
|
return 1;
|
|
10820
10713
|
}
|
|
10714
|
+
function targetConsultsAffordance(specTarget) {
|
|
10715
|
+
if (specTarget === void 0) return false;
|
|
10716
|
+
if (typeof specTarget === "object" && specTarget !== null && "kindOf" in specTarget) {
|
|
10717
|
+
const kindOf2 = specTarget.kindOf;
|
|
10718
|
+
return kindOf2?.readsAffordance !== false;
|
|
10719
|
+
}
|
|
10720
|
+
return typeof specTarget === "string" && specTarget.startsWith("affordance:");
|
|
10721
|
+
}
|
|
10722
|
+
function specTargetOf(spec) {
|
|
10723
|
+
return "target" in spec ? spec.target : void 0;
|
|
10724
|
+
}
|
|
10725
|
+
function claimOf(e) {
|
|
10726
|
+
return "affordance" in e ? e.affordance : void 0;
|
|
10727
|
+
}
|
|
10728
|
+
function claimGestureOf(e) {
|
|
10729
|
+
switch (e.kind) {
|
|
10730
|
+
case "pointerdown":
|
|
10731
|
+
case "click":
|
|
10732
|
+
return "pointer";
|
|
10733
|
+
case "doubleclick":
|
|
10734
|
+
return "doubleClick";
|
|
10735
|
+
case "contextmenu":
|
|
10736
|
+
return "contextMenu";
|
|
10737
|
+
case "longpress":
|
|
10738
|
+
return "longPress";
|
|
10739
|
+
case "wheel":
|
|
10740
|
+
return "wheel";
|
|
10741
|
+
default:
|
|
10742
|
+
return null;
|
|
10743
|
+
}
|
|
10744
|
+
}
|
|
10745
|
+
function isExclusiveClaim(e) {
|
|
10746
|
+
const claim = claimOf(e);
|
|
10747
|
+
if (claim?.strength !== "exclusive") return false;
|
|
10748
|
+
const gesture = claimGestureOf(e);
|
|
10749
|
+
if (gesture === null) return false;
|
|
10750
|
+
return claim.claimedKinds === void 0 || claim.claimedKinds.includes(gesture);
|
|
10751
|
+
}
|
|
10752
|
+
var warnedDeadClaims = /* @__PURE__ */ new Set();
|
|
10753
|
+
function reportDeadClaim(owner, warn) {
|
|
10754
|
+
if (process.env.NODE_ENV === "production") return;
|
|
10755
|
+
const key = String(owner);
|
|
10756
|
+
if (warnedDeadClaims.has(key)) return;
|
|
10757
|
+
warnedDeadClaims.add(key);
|
|
10758
|
+
warn(
|
|
10759
|
+
`[weasel] exclusive claim by "${key}" matched no binding: no \`affordance:\` or \`kindOf\` target resolved against it, so the press was dropped.`
|
|
10760
|
+
);
|
|
10761
|
+
}
|
|
10821
10762
|
function specificity(spec) {
|
|
10822
10763
|
const t = targetRank("target" in spec ? spec.target : void 0);
|
|
10823
10764
|
const mods = "mods" in spec ? spec.mods : void 0;
|
|
@@ -10834,12 +10775,14 @@ function compareSpecificity(a, b) {
|
|
|
10834
10775
|
}
|
|
10835
10776
|
return 0;
|
|
10836
10777
|
}
|
|
10837
|
-
function matchSorted(e, bindings, isMac, engagedChannels) {
|
|
10778
|
+
function matchSorted(e, bindings, isMac, engagedChannels, warn = (m) => console.warn(m)) {
|
|
10838
10779
|
const out = [];
|
|
10839
10780
|
const engaged = engagedChannels ?? EMPTY_ENGAGED;
|
|
10781
|
+
const exclusive = isExclusiveClaim(e);
|
|
10782
|
+
const pool = exclusive ? bindings.filter((sb) => targetConsultsAffordance(specTargetOf(sb.binding.spec))) : bindings;
|
|
10840
10783
|
for (const scope of SCOPE_PRIORITY) {
|
|
10841
10784
|
const scopeMatches = [];
|
|
10842
|
-
for (const sb of
|
|
10785
|
+
for (const sb of pool) {
|
|
10843
10786
|
if (sb.scope !== scope) continue;
|
|
10844
10787
|
const phaseCtx = { selfChannel: sb.ownerToolId, engagedChannels: engaged };
|
|
10845
10788
|
if (matchSpec(e, sb.binding.spec, isMac, phaseCtx)) {
|
|
@@ -10849,10 +10792,37 @@ function matchSorted(e, bindings, isMac, engagedChannels) {
|
|
|
10849
10792
|
scopeMatches.sort((a, b) => compareSpecificity(a.binding.spec, b.binding.spec));
|
|
10850
10793
|
out.push(...scopeMatches);
|
|
10851
10794
|
}
|
|
10795
|
+
if (exclusive && out.length === 0 && bindings.length > 0) {
|
|
10796
|
+
reportDeadClaim(claimOf(e)?.owner, warn);
|
|
10797
|
+
}
|
|
10852
10798
|
return out;
|
|
10853
10799
|
}
|
|
10854
10800
|
var EMPTY_ENGAGED = /* @__PURE__ */ new Set();
|
|
10855
10801
|
|
|
10802
|
+
// src/contributions/eligibility.ts
|
|
10803
|
+
function liveScope(id, eligibility, state) {
|
|
10804
|
+
const tags = eligibility.capabilities;
|
|
10805
|
+
if (tags && tags.length > 0 && state.allows && !state.allows(tags)) return null;
|
|
10806
|
+
if (state.engagedIds?.has(id)) return "hotkey";
|
|
10807
|
+
if (eligibility.offhand && state.heldTriggers.has(eligibility.offhand)) return "hotkey";
|
|
10808
|
+
if (eligibility.focus && state.focusedId === id) return "active";
|
|
10809
|
+
if (eligibility.always || eligibility.claimed) return "ambient";
|
|
10810
|
+
return null;
|
|
10811
|
+
}
|
|
10812
|
+
|
|
10813
|
+
// src/contributions/assemble.ts
|
|
10814
|
+
function scopeBindings(entries, state) {
|
|
10815
|
+
const out = [];
|
|
10816
|
+
for (const entry of entries) {
|
|
10817
|
+
const scope = liveScope(entry.id, entry.eligibility ?? {}, state);
|
|
10818
|
+
if (scope === null) continue;
|
|
10819
|
+
for (const binding of entry.bindings ?? []) {
|
|
10820
|
+
out.push({ binding, scope, ownerToolId: entry.id });
|
|
10821
|
+
}
|
|
10822
|
+
}
|
|
10823
|
+
return out;
|
|
10824
|
+
}
|
|
10825
|
+
|
|
10856
10826
|
// src/features/chrome-caps/rule.ts
|
|
10857
10827
|
var ALWAYS = { all: [] };
|
|
10858
10828
|
var NEVER = { any: [] };
|
|
@@ -11157,7 +11127,7 @@ function useHoverTracking(args) {
|
|
|
11157
11127
|
function pointerGestureId(pointerId) {
|
|
11158
11128
|
return `pointer-${pointerId ?? "mouse"}`;
|
|
11159
11129
|
}
|
|
11160
|
-
var
|
|
11130
|
+
var DEV = (() => {
|
|
11161
11131
|
try {
|
|
11162
11132
|
return Boolean(import.meta.env?.DEV);
|
|
11163
11133
|
} catch {
|
|
@@ -11165,9 +11135,9 @@ var DEV2 = (() => {
|
|
|
11165
11135
|
}
|
|
11166
11136
|
})();
|
|
11167
11137
|
var TRACE_LIMIT = 200;
|
|
11168
|
-
var traceLog =
|
|
11138
|
+
var traceLog = DEV && typeof window !== "undefined" ? window.__weaselDispatchLog__ ??= [] : [];
|
|
11169
11139
|
function recordTrace(entry) {
|
|
11170
|
-
if (!
|
|
11140
|
+
if (!DEV) return;
|
|
11171
11141
|
traceLog.push(entry);
|
|
11172
11142
|
if (traceLog.length > TRACE_LIMIT) traceLog.shift();
|
|
11173
11143
|
}
|
|
@@ -11198,6 +11168,7 @@ function filterEligible(matches, actionLookup, ruleCtx) {
|
|
|
11198
11168
|
return isEligible(action, ruleCtx);
|
|
11199
11169
|
});
|
|
11200
11170
|
}
|
|
11171
|
+
var EMPTY_TRIGGERS = /* @__PURE__ */ new Set();
|
|
11201
11172
|
var EMPTY_ENGAGED2 = /* @__PURE__ */ new Set();
|
|
11202
11173
|
function modifiersOf(e) {
|
|
11203
11174
|
return { alt: e.altKey, ctrl: e.ctrlKey, meta: e.metaKey, shift: e.shiftKey };
|
|
@@ -11305,34 +11276,23 @@ function createDispatcher(opts) {
|
|
|
11305
11276
|
return `ongoing-${event.kind}`;
|
|
11306
11277
|
}
|
|
11307
11278
|
function assembleScopedBindings(ctx) {
|
|
11308
|
-
const
|
|
11309
|
-
for (const
|
|
11310
|
-
const tool = ctx.toolsById.get(
|
|
11311
|
-
|
|
11312
|
-
|
|
11313
|
-
|
|
11314
|
-
|
|
11315
|
-
|
|
11316
|
-
|
|
11317
|
-
|
|
11318
|
-
|
|
11319
|
-
|
|
11320
|
-
|
|
11321
|
-
for (const binding of tool?.bindings ?? []) {
|
|
11322
|
-
result.push({ binding, scope: "ambient", ownerToolId: toolId });
|
|
11323
|
-
}
|
|
11324
|
-
}
|
|
11279
|
+
const ordered = [];
|
|
11280
|
+
for (const id of ctx.hotkeyStack) {
|
|
11281
|
+
const tool = ctx.toolsById.get(id);
|
|
11282
|
+
if (tool && !ordered.includes(tool)) ordered.push(tool);
|
|
11283
|
+
}
|
|
11284
|
+
for (const tool of ctx.toolsById.values()) {
|
|
11285
|
+
if (!ordered.includes(tool)) ordered.push(tool);
|
|
11286
|
+
}
|
|
11287
|
+
const result = scopeBindings(ordered, {
|
|
11288
|
+
focusedId: ctx.activeToolId,
|
|
11289
|
+
heldTriggers: EMPTY_TRIGGERS,
|
|
11290
|
+
engagedIds: new Set(ctx.hotkeyStack)
|
|
11291
|
+
});
|
|
11325
11292
|
for (const action of ctx.actions.list()) {
|
|
11326
|
-
const
|
|
11327
|
-
|
|
11328
|
-
|
|
11329
|
-
for (const entry of raw) {
|
|
11330
|
-
const isBoundObj = !("kind" in entry);
|
|
11331
|
-
const spec = isBoundObj ? entry.spec : entry;
|
|
11332
|
-
const opts2 = isBoundObj ? entry.opts : void 0;
|
|
11333
|
-
const defaultBinding = { spec, actionId: action.id, ...opts2 !== void 0 ? { opts: opts2 } : {} };
|
|
11334
|
-
const targetScope = action.scope === "hotkey" ? "hotkey" : "ambient";
|
|
11335
|
-
result.push({ binding: defaultBinding, scope: targetScope, ownerToolId: null });
|
|
11293
|
+
const targetScope = action.scope === "hotkey" ? "hotkey" : "ambient";
|
|
11294
|
+
for (const binding of actionBindings(action)) {
|
|
11295
|
+
result.push({ binding, scope: targetScope, ownerToolId: null });
|
|
11336
11296
|
}
|
|
11337
11297
|
}
|
|
11338
11298
|
return result;
|
|
@@ -11487,15 +11447,26 @@ function createDispatcher(opts) {
|
|
|
11487
11447
|
deltaY: event.deltaY,
|
|
11488
11448
|
clientX: event.clientX,
|
|
11489
11449
|
clientY: event.clientY,
|
|
11450
|
+
affordance: event.affordance,
|
|
11490
11451
|
...resolved
|
|
11491
11452
|
};
|
|
11492
11453
|
} else if (event.kind === "click" || event.kind === "doubleclick") {
|
|
11493
11454
|
params = {
|
|
11494
11455
|
worldX: event.worldX,
|
|
11495
11456
|
worldY: event.worldY,
|
|
11457
|
+
affordance: event.affordance,
|
|
11496
11458
|
// Press point as well as release point — an action that places
|
|
11497
11459
|
// geometry at the click wants the former. See `ClickEvent`.
|
|
11498
|
-
...event.kind === "click" ? { pressX: event.pressX, pressY: event.pressY
|
|
11460
|
+
...event.kind === "click" ? { pressX: event.pressX, pressY: event.pressY } : {},
|
|
11461
|
+
mods: modifiersOf(event),
|
|
11462
|
+
...resolved
|
|
11463
|
+
};
|
|
11464
|
+
} else if (event.kind === "contextmenu" || event.kind === "longpress") {
|
|
11465
|
+
params = {
|
|
11466
|
+
worldX: event.kind === "contextmenu" ? event.worldX : event.x,
|
|
11467
|
+
worldY: event.kind === "contextmenu" ? event.worldY : event.y,
|
|
11468
|
+
affordance: event.affordance,
|
|
11469
|
+
bodyTarget: event.bodyTarget,
|
|
11499
11470
|
mods: modifiersOf(event),
|
|
11500
11471
|
...resolved
|
|
11501
11472
|
};
|
|
@@ -11867,7 +11838,7 @@ function computeMultiTouchGeometry(positions) {
|
|
|
11867
11838
|
return { centroid, spread };
|
|
11868
11839
|
}
|
|
11869
11840
|
function useGestureDispatcher(opts) {
|
|
11870
|
-
const { canvasRef, actions, toolsById,
|
|
11841
|
+
const { canvasRef, actions, toolsById, enabled = true, keyboard = true, affordanceAt, classifyTarget, dispatcher: dispatcherOpt, clientToWorld: clientToWorld2, requestRedraw, getRuleCtx, onDoubleClick } = opts;
|
|
11871
11842
|
const onDoubleClickRef = useRef(onDoubleClick);
|
|
11872
11843
|
onDoubleClickRef.current = onDoubleClick;
|
|
11873
11844
|
const activeTool = useActiveToolContext();
|
|
@@ -11882,7 +11853,6 @@ function useGestureDispatcher(opts) {
|
|
|
11882
11853
|
activeToolId: activeTool.active,
|
|
11883
11854
|
hotkeyStack: activeTool.hotkeyStack,
|
|
11884
11855
|
toolsById,
|
|
11885
|
-
ambientToolIds,
|
|
11886
11856
|
isMac: IS_MAC,
|
|
11887
11857
|
getRuleCtx
|
|
11888
11858
|
});
|
|
@@ -11892,7 +11862,6 @@ function useGestureDispatcher(opts) {
|
|
|
11892
11862
|
activeToolId: activeTool.active,
|
|
11893
11863
|
hotkeyStack: activeTool.hotkeyStack,
|
|
11894
11864
|
toolsById,
|
|
11895
|
-
ambientToolIds,
|
|
11896
11865
|
isMac: IS_MAC,
|
|
11897
11866
|
getRuleCtx
|
|
11898
11867
|
};
|
|
@@ -11970,6 +11939,7 @@ function useGestureDispatcher(opts) {
|
|
|
11970
11939
|
ctrlKey: down.ctrlKey,
|
|
11971
11940
|
metaKey: down.metaKey,
|
|
11972
11941
|
shiftKey: down.shiftKey,
|
|
11942
|
+
...down.affordance !== void 0 ? { affordance: down.affordance } : {},
|
|
11973
11943
|
...down.bodyTarget !== void 0 ? { bodyTarget: down.bodyTarget } : {},
|
|
11974
11944
|
...down.bodyKind !== void 0 ? { bodyKind: down.bodyKind } : {}
|
|
11975
11945
|
};
|
|
@@ -11979,11 +11949,15 @@ function useGestureDispatcher(opts) {
|
|
|
11979
11949
|
y: down.worldY,
|
|
11980
11950
|
clientX: down.clientX,
|
|
11981
11951
|
clientY: down.clientY,
|
|
11982
|
-
...down.affordance !== void 0 ? { affordance: down.affordance } : {},
|
|
11983
11952
|
...shared
|
|
11984
11953
|
});
|
|
11985
11954
|
if (result === "unhandled") {
|
|
11986
|
-
dispatch2({
|
|
11955
|
+
dispatch2({
|
|
11956
|
+
kind: "contextmenu",
|
|
11957
|
+
worldX: down.worldX,
|
|
11958
|
+
worldY: down.worldY,
|
|
11959
|
+
...shared
|
|
11960
|
+
});
|
|
11987
11961
|
}
|
|
11988
11962
|
};
|
|
11989
11963
|
const DOUBLE_CLICK_MAX_MS = 600;
|
|
@@ -12038,6 +12012,9 @@ function useGestureDispatcher(opts) {
|
|
|
12038
12012
|
const onWheel = (e) => {
|
|
12039
12013
|
const rect = canvas?.getBoundingClientRect();
|
|
12040
12014
|
const [localX, localY] = rect ? clientToCanvasRect(rect, e.clientX, e.clientY) : [e.clientX, e.clientY];
|
|
12015
|
+
const screenPoint = { x: e.clientX, y: e.clientY };
|
|
12016
|
+
const affordance = affordanceAtRef.current?.(screenPoint) ?? void 0;
|
|
12017
|
+
const body = classifyTargetRef.current?.(screenPoint);
|
|
12041
12018
|
const ev = {
|
|
12042
12019
|
kind: "wheel",
|
|
12043
12020
|
altKey: e.altKey,
|
|
@@ -12047,7 +12024,10 @@ function useGestureDispatcher(opts) {
|
|
|
12047
12024
|
deltaX: e.deltaX,
|
|
12048
12025
|
deltaY: e.deltaY,
|
|
12049
12026
|
clientX: localX,
|
|
12050
|
-
clientY: localY
|
|
12027
|
+
clientY: localY,
|
|
12028
|
+
...affordance !== void 0 ? { affordance } : {},
|
|
12029
|
+
...body?.body !== void 0 ? { bodyTarget: body.body } : {},
|
|
12030
|
+
...body?.kind !== void 0 ? { bodyKind: body.kind } : {}
|
|
12051
12031
|
};
|
|
12052
12032
|
const result = dispatch2(ev);
|
|
12053
12033
|
if (result === "handled") {
|
|
@@ -12341,6 +12321,7 @@ function useGestureDispatcher(opts) {
|
|
|
12341
12321
|
shiftKey: e.shiftKey,
|
|
12342
12322
|
worldX: wClick.x,
|
|
12343
12323
|
worldY: wClick.y,
|
|
12324
|
+
...down.affordance !== void 0 ? { affordance: down.affordance } : {},
|
|
12344
12325
|
...down.bodyTarget !== void 0 ? { bodyTarget: down.bodyTarget } : {},
|
|
12345
12326
|
...down.bodyKind !== void 0 ? { bodyKind: down.bodyKind } : {}
|
|
12346
12327
|
};
|
|
@@ -12382,8 +12363,10 @@ function useGestureDispatcher(opts) {
|
|
|
12382
12363
|
};
|
|
12383
12364
|
const onContextMenu = (e) => {
|
|
12384
12365
|
e.preventDefault();
|
|
12385
|
-
const
|
|
12386
|
-
const
|
|
12366
|
+
const screenPoint = { x: e.clientX, y: e.clientY };
|
|
12367
|
+
const affordance = affordanceAtRef.current?.(screenPoint) ?? void 0;
|
|
12368
|
+
const menuBody = classifyTargetRef.current?.(screenPoint);
|
|
12369
|
+
const w = toWorld(e.clientX, e.clientY);
|
|
12387
12370
|
const ev = {
|
|
12388
12371
|
kind: "contextmenu",
|
|
12389
12372
|
target: e.target,
|
|
@@ -12391,6 +12374,9 @@ function useGestureDispatcher(opts) {
|
|
|
12391
12374
|
ctrlKey: e.ctrlKey,
|
|
12392
12375
|
metaKey: e.metaKey,
|
|
12393
12376
|
shiftKey: e.shiftKey,
|
|
12377
|
+
worldX: w.x,
|
|
12378
|
+
worldY: w.y,
|
|
12379
|
+
...affordance !== void 0 ? { affordance } : {},
|
|
12394
12380
|
...menuBody?.body !== void 0 ? { bodyTarget: menuBody.body } : {},
|
|
12395
12381
|
...menuBody?.kind !== void 0 ? { bodyKind: menuBody.kind } : {}
|
|
12396
12382
|
};
|
|
@@ -12790,47 +12776,209 @@ function useViewAnimation(setView) {
|
|
|
12790
12776
|
);
|
|
12791
12777
|
return { animateTo, animateToBounds, cancel };
|
|
12792
12778
|
}
|
|
12793
|
-
|
|
12794
|
-
|
|
12795
|
-
|
|
12779
|
+
|
|
12780
|
+
// src/interactions/actions/defaults/toolOffhand.ts
|
|
12781
|
+
var TOOL_OFFHAND_ID = "tool.offhand";
|
|
12782
|
+
function offhandKeyFor(trigger) {
|
|
12783
|
+
switch (trigger) {
|
|
12784
|
+
case "space":
|
|
12785
|
+
return " ";
|
|
12786
|
+
case "alt":
|
|
12787
|
+
return "Alt";
|
|
12788
|
+
case "ctrl":
|
|
12789
|
+
return "Control";
|
|
12790
|
+
case "meta":
|
|
12791
|
+
return "Meta";
|
|
12792
|
+
case "shift":
|
|
12793
|
+
return "Shift";
|
|
12796
12794
|
}
|
|
12795
|
+
}
|
|
12796
|
+
function buildToolOffhandBindings(specs) {
|
|
12797
|
+
return specs.map(({ toolId, key }) => ({
|
|
12798
|
+
spec: { kind: "key-held", key },
|
|
12799
|
+
opts: { params: { toolId } }
|
|
12800
|
+
}));
|
|
12801
|
+
}
|
|
12802
|
+
function makeToolOffhandAction(bindings) {
|
|
12803
|
+
return {
|
|
12804
|
+
id: TOOL_OFFHAND_ID,
|
|
12805
|
+
label: "Engage tool (offhand)",
|
|
12806
|
+
defaultBinding: bindings,
|
|
12807
|
+
scope: "hotkey",
|
|
12808
|
+
invoker: {
|
|
12809
|
+
timing: "ongoing",
|
|
12810
|
+
start: (ctx, opts) => {
|
|
12811
|
+
const activeTool = ctx.deps.activeTool;
|
|
12812
|
+
const toolId = resolveParams(opts?.params)?.toolId;
|
|
12813
|
+
if (!activeTool || !toolId) return {};
|
|
12814
|
+
activeTool.pushHotkey(toolId);
|
|
12815
|
+
return {
|
|
12816
|
+
onEnd: () => {
|
|
12817
|
+
activeTool.popHotkey();
|
|
12818
|
+
}
|
|
12819
|
+
};
|
|
12820
|
+
}
|
|
12821
|
+
},
|
|
12822
|
+
requires: ["activeTool"]
|
|
12823
|
+
};
|
|
12824
|
+
}
|
|
12825
|
+
|
|
12826
|
+
// src/contributions/useContributions.ts
|
|
12827
|
+
var NO_TRIGGERS = /* @__PURE__ */ new Set();
|
|
12828
|
+
function useContributions(opts) {
|
|
12797
12829
|
const ctx = useActiveToolContext();
|
|
12830
|
+
const actionsRegistry = useActionsRegistry();
|
|
12798
12831
|
const hasInitializedRef = useRef(false);
|
|
12799
12832
|
const isFirstRender = !hasInitializedRef.current;
|
|
12800
12833
|
const needsFirstMountSyncRef = useRef(false);
|
|
12801
12834
|
if (isFirstRender) {
|
|
12802
12835
|
hasInitializedRef.current = true;
|
|
12803
|
-
needsFirstMountSyncRef.current = ctx.active === "select" && opts.
|
|
12836
|
+
needsFirstMountSyncRef.current = ctx.active === "select" && opts.focused !== "select";
|
|
12804
12837
|
}
|
|
12805
12838
|
useEffect(() => {
|
|
12806
12839
|
if (!needsFirstMountSyncRef.current) return;
|
|
12807
12840
|
needsFirstMountSyncRef.current = false;
|
|
12808
|
-
ctx.setActive(opts.
|
|
12841
|
+
ctx.setActive(opts.focused);
|
|
12842
|
+
}, []);
|
|
12843
|
+
const focused2 = isFirstRender && ctx.active === "select" && opts.focused !== "select" ? opts.focused : ctx.active;
|
|
12844
|
+
const entriesRef = useRef(opts.entries);
|
|
12845
|
+
entriesRef.current = opts.entries;
|
|
12846
|
+
const focusedRef = useRef(focused2);
|
|
12847
|
+
focusedRef.current = focused2;
|
|
12848
|
+
const engagedRef = useRef(ctx.hotkeyStack);
|
|
12849
|
+
engagedRef.current = ctx.hotkeyStack;
|
|
12850
|
+
const setFocused = useCallback((id) => {
|
|
12851
|
+
ctx.setActive(id);
|
|
12852
|
+
}, [ctx]);
|
|
12853
|
+
const snapshot = useCallback(() => {
|
|
12854
|
+
const engaged = engagedRef.current;
|
|
12855
|
+
const engagedIds = new Set(engaged);
|
|
12856
|
+
const ordered = [];
|
|
12857
|
+
for (const id of engaged) {
|
|
12858
|
+
const entry = entriesRef.current.find((e) => e.id === id);
|
|
12859
|
+
if (entry && !ordered.includes(entry)) ordered.push(entry);
|
|
12860
|
+
}
|
|
12861
|
+
for (const entry of entriesRef.current) {
|
|
12862
|
+
if (!ordered.includes(entry)) ordered.push(entry);
|
|
12863
|
+
}
|
|
12864
|
+
return {
|
|
12865
|
+
ordered,
|
|
12866
|
+
state: { focusedId: focusedRef.current, heldTriggers: NO_TRIGGERS, engagedIds }
|
|
12867
|
+
};
|
|
12809
12868
|
}, []);
|
|
12810
|
-
const
|
|
12811
|
-
|
|
12812
|
-
|
|
12813
|
-
|
|
12814
|
-
|
|
12815
|
-
|
|
12816
|
-
|
|
12817
|
-
|
|
12818
|
-
|
|
12869
|
+
const scopedBindings = useCallback(() => {
|
|
12870
|
+
const { ordered, state } = snapshot();
|
|
12871
|
+
return scopeBindings(ordered, state);
|
|
12872
|
+
}, [snapshot]);
|
|
12873
|
+
const overlays = useCallback(() => {
|
|
12874
|
+
const { ordered, state } = snapshot();
|
|
12875
|
+
const active = [];
|
|
12876
|
+
const hotkey = [];
|
|
12877
|
+
const ambient = [];
|
|
12878
|
+
for (const entry of ordered) {
|
|
12879
|
+
if (!entry.overlay) continue;
|
|
12880
|
+
const scope = liveScope(entry.id, entry.eligibility ?? {}, state);
|
|
12881
|
+
if (scope === "active") active.push(entry.overlay);
|
|
12882
|
+
else if (scope === "hotkey") hotkey.push(entry.overlay);
|
|
12883
|
+
else if (scope === "ambient") ambient.push(entry.overlay);
|
|
12884
|
+
}
|
|
12885
|
+
return [...active, ...hotkey, ...ambient];
|
|
12886
|
+
}, [snapshot]);
|
|
12887
|
+
const offhandSig = opts.entries.map((e) => e.eligibility?.offhand ? `${e.id}:${e.eligibility.offhand}` : "").filter(Boolean).join(",");
|
|
12888
|
+
useEffect(() => {
|
|
12889
|
+
if (!actionsRegistry || offhandSig === "") return;
|
|
12890
|
+
const specs = offhandSig.split(",").map((entry) => {
|
|
12891
|
+
const [toolId, trigger] = entry.split(":");
|
|
12892
|
+
return { toolId, key: offhandKeyFor(trigger) };
|
|
12893
|
+
});
|
|
12894
|
+
return actionsRegistry.register(makeToolOffhandAction(buildToolOffhandBindings(specs)));
|
|
12895
|
+
}, [actionsRegistry, offhandSig]);
|
|
12896
|
+
const lastConflictSigRef = useRef(null);
|
|
12897
|
+
const entrySig = opts.entries.map((e) => e.id).join(",");
|
|
12898
|
+
useEffect(() => {
|
|
12899
|
+
if (process.env.NODE_ENV === "production") return;
|
|
12900
|
+
if (lastConflictSigRef.current === entrySig) return;
|
|
12901
|
+
lastConflictSigRef.current = entrySig;
|
|
12902
|
+
const registry2 = [];
|
|
12903
|
+
const ambient = [];
|
|
12904
|
+
for (const entry of entriesRef.current) {
|
|
12905
|
+
(entry.eligibility?.focus ? registry2 : ambient).push(entry);
|
|
12906
|
+
}
|
|
12907
|
+
reportRouteConflicts({
|
|
12908
|
+
registry: registry2,
|
|
12909
|
+
ambient,
|
|
12910
|
+
actions: actionsRegistry?.list() ?? []
|
|
12911
|
+
});
|
|
12912
|
+
}, [entrySig, actionsRegistry]);
|
|
12913
|
+
return useMemo(
|
|
12914
|
+
() => ({
|
|
12915
|
+
entries: entriesRef.current,
|
|
12916
|
+
focused: focused2,
|
|
12917
|
+
setFocused,
|
|
12918
|
+
scopedBindings,
|
|
12919
|
+
overlays
|
|
12920
|
+
}),
|
|
12921
|
+
[focused2, setFocused, scopedBindings, overlays]
|
|
12922
|
+
);
|
|
12923
|
+
}
|
|
12924
|
+
|
|
12925
|
+
// src/tools/useTools.ts
|
|
12926
|
+
function declareSlot(tool, slot) {
|
|
12927
|
+
const hotkey = tool.def?.hotkey;
|
|
12928
|
+
const eligibility = {
|
|
12929
|
+
...tool.eligibility,
|
|
12930
|
+
[slot]: true,
|
|
12931
|
+
...hotkey ? { offhand: hotkey } : {}
|
|
12932
|
+
};
|
|
12933
|
+
return sameEligibility(tool.eligibility, eligibility) ? tool : { ...tool, eligibility };
|
|
12934
|
+
}
|
|
12935
|
+
function sameEligibility(a, b) {
|
|
12936
|
+
if (!a) return false;
|
|
12937
|
+
const keys = /* @__PURE__ */ new Set([...Object.keys(a), ...Object.keys(b)]);
|
|
12938
|
+
for (const key of keys) if (a[key] !== b[key]) return false;
|
|
12939
|
+
return true;
|
|
12940
|
+
}
|
|
12941
|
+
function useTools(opts) {
|
|
12942
|
+
if (!(opts.active in opts.registry)) {
|
|
12943
|
+
throw new Error(`useTools: active "${opts.active}" not in registry`);
|
|
12944
|
+
}
|
|
12945
|
+
const ctx = useActiveToolContext();
|
|
12946
|
+
const slotted = useMemo(() => {
|
|
12947
|
+
const registry2 = {};
|
|
12948
|
+
for (const [id, tool] of Object.entries(opts.registry)) {
|
|
12949
|
+
registry2[id] = declareSlot(tool, "focus");
|
|
12950
|
+
}
|
|
12951
|
+
const ambient = (opts.ambient ?? []).map((t) => declareSlot(t, "always"));
|
|
12952
|
+
const byId = /* @__PURE__ */ new Map();
|
|
12953
|
+
for (const tool of [...Object.values(registry2), ...ambient]) {
|
|
12954
|
+
const prior = byId.get(tool.id);
|
|
12955
|
+
if (prior) byId.set(tool.id, { ...tool, eligibility: { ...prior.eligibility, ...tool.eligibility } });
|
|
12956
|
+
else byId.set(tool.id, tool);
|
|
12957
|
+
}
|
|
12958
|
+
return { registry: registry2, ambient, entries: [...byId.values()] };
|
|
12959
|
+
}, [opts.registry, opts.ambient]);
|
|
12960
|
+
const contributions = useContributions({ entries: slotted.entries, focused: opts.active });
|
|
12961
|
+
const hotkeyEngaged = ctx.hotkeyStack.at(-1) ?? null;
|
|
12962
|
+
const slottedRef = useRef(slotted);
|
|
12963
|
+
slottedRef.current = slotted;
|
|
12964
|
+
const activeRef = useRef(contributions.focused);
|
|
12965
|
+
activeRef.current = contributions.focused;
|
|
12819
12966
|
const hotkeyRef = useRef(hotkeyEngaged);
|
|
12820
12967
|
hotkeyRef.current = hotkeyEngaged;
|
|
12968
|
+
const setFocused = contributions.setFocused;
|
|
12821
12969
|
const setActive = useCallback(
|
|
12822
12970
|
(id) => {
|
|
12823
|
-
if (!(id in
|
|
12971
|
+
if (!(id in slottedRef.current.registry)) {
|
|
12824
12972
|
throw new Error(`setActive: "${id}" not in registry`);
|
|
12825
12973
|
}
|
|
12826
12974
|
dlog("tools", "active:", activeRef.current, "\u2192", id);
|
|
12827
|
-
|
|
12975
|
+
setFocused(id);
|
|
12828
12976
|
},
|
|
12829
|
-
[
|
|
12977
|
+
[setFocused]
|
|
12830
12978
|
);
|
|
12831
12979
|
const engageHotkey = useCallback(
|
|
12832
12980
|
(id) => {
|
|
12833
|
-
if (!(id in
|
|
12981
|
+
if (!(id in slottedRef.current.registry)) {
|
|
12834
12982
|
throw new Error(`engageHotkey: "${id}" not in registry`);
|
|
12835
12983
|
}
|
|
12836
12984
|
dlog("tools", "hotkey engaged:", id);
|
|
@@ -12842,32 +12990,12 @@ function useTools(opts) {
|
|
|
12842
12990
|
if (hotkeyRef.current) dlog("tools", "hotkey disengaged:", hotkeyRef.current);
|
|
12843
12991
|
ctx.popHotkey();
|
|
12844
12992
|
}, [ctx]);
|
|
12845
|
-
const lastConflictSigRef = useRef(null);
|
|
12846
|
-
const toolSetSig = Object.keys(opts.registry).join(",") + "|" + (opts.ambient ?? []).map((t) => t.id).join(",");
|
|
12847
|
-
useEffect(() => {
|
|
12848
|
-
if (process.env.NODE_ENV === "production") return;
|
|
12849
|
-
if (lastConflictSigRef.current === toolSetSig) return;
|
|
12850
|
-
lastConflictSigRef.current = toolSetSig;
|
|
12851
|
-
reportRouteConflicts({
|
|
12852
|
-
registry: registryRef.current,
|
|
12853
|
-
ambient: ambientRef.current
|
|
12854
|
-
});
|
|
12855
|
-
}, [toolSetSig]);
|
|
12856
12993
|
const has = useCallback(
|
|
12857
|
-
(id) => id in
|
|
12994
|
+
(id) => id in slottedRef.current.registry || slottedRef.current.ambient.some((t) => t.id === id),
|
|
12858
12995
|
[]
|
|
12859
12996
|
);
|
|
12860
|
-
const
|
|
12861
|
-
|
|
12862
|
-
const activeTool = registryRef.current[activeRef.current];
|
|
12863
|
-
if (activeTool?.overlay) out.push(activeTool.overlay);
|
|
12864
|
-
const mod = hotkeyRef.current ? registryRef.current[hotkeyRef.current] : null;
|
|
12865
|
-
if (mod?.overlay) out.push(mod.overlay);
|
|
12866
|
-
for (const t of ambientRef.current) {
|
|
12867
|
-
if (t.overlay) out.push(t.overlay);
|
|
12868
|
-
}
|
|
12869
|
-
return out;
|
|
12870
|
-
}, []);
|
|
12997
|
+
const active = contributions.focused;
|
|
12998
|
+
const getActiveOverlays = contributions.overlays;
|
|
12871
12999
|
return useMemo(
|
|
12872
13000
|
() => ({
|
|
12873
13001
|
active,
|
|
@@ -12875,8 +13003,8 @@ function useTools(opts) {
|
|
|
12875
13003
|
hotkeyEngaged,
|
|
12876
13004
|
engageHotkey,
|
|
12877
13005
|
disengageHotkey,
|
|
12878
|
-
ambient:
|
|
12879
|
-
registry:
|
|
13006
|
+
ambient: slottedRef.current.ambient,
|
|
13007
|
+
registry: slottedRef.current.registry,
|
|
12880
13008
|
has,
|
|
12881
13009
|
getActiveOverlays
|
|
12882
13010
|
}),
|
|
@@ -12884,38 +13012,6 @@ function useTools(opts) {
|
|
|
12884
13012
|
);
|
|
12885
13013
|
}
|
|
12886
13014
|
|
|
12887
|
-
// src/interactions/actions/defaults/toolOffhand.ts
|
|
12888
|
-
var TOOL_OFFHAND_ID = "tool.offhand";
|
|
12889
|
-
function buildToolOffhandBindings(specs) {
|
|
12890
|
-
return specs.map(({ toolId, key }) => ({
|
|
12891
|
-
spec: { kind: "key-held", key },
|
|
12892
|
-
opts: { params: { toolId } }
|
|
12893
|
-
}));
|
|
12894
|
-
}
|
|
12895
|
-
function makeToolOffhandAction(bindings) {
|
|
12896
|
-
return {
|
|
12897
|
-
id: TOOL_OFFHAND_ID,
|
|
12898
|
-
label: "Engage tool (offhand)",
|
|
12899
|
-
defaultBinding: bindings,
|
|
12900
|
-
scope: "hotkey",
|
|
12901
|
-
invoker: {
|
|
12902
|
-
timing: "ongoing",
|
|
12903
|
-
start: (ctx, opts) => {
|
|
12904
|
-
const activeTool = ctx.deps.activeTool;
|
|
12905
|
-
const toolId = resolveParams(opts?.params)?.toolId;
|
|
12906
|
-
if (!activeTool || !toolId) return {};
|
|
12907
|
-
activeTool.pushHotkey(toolId);
|
|
12908
|
-
return {
|
|
12909
|
-
onEnd: () => {
|
|
12910
|
-
activeTool.popHotkey();
|
|
12911
|
-
}
|
|
12912
|
-
};
|
|
12913
|
-
}
|
|
12914
|
-
},
|
|
12915
|
-
requires: ["activeTool"]
|
|
12916
|
-
};
|
|
12917
|
-
}
|
|
12918
|
-
|
|
12919
13015
|
// src/interactions/actions/defaults/toolActivate.ts
|
|
12920
13016
|
var TOOL_ACTIVATE_ID = "tool.activate";
|
|
12921
13017
|
function buildToolActivateBindings(specs) {
|
|
@@ -12992,9 +13088,6 @@ var BUILTIN_SELECT_KEYS = {
|
|
|
12992
13088
|
hand: { key: "H" },
|
|
12993
13089
|
pen: { key: "P" }
|
|
12994
13090
|
};
|
|
12995
|
-
var BUILTIN_OFFHAND_ACTIONS = {
|
|
12996
|
-
hand: " "
|
|
12997
|
-
};
|
|
12998
13091
|
function useKeybindings(tools, options = {}) {
|
|
12999
13092
|
const toolsRef = useRef(tools);
|
|
13000
13093
|
toolsRef.current = tools;
|
|
@@ -13002,19 +13095,6 @@ function useKeybindings(tools, options = {}) {
|
|
|
13002
13095
|
optionsRef.current = options;
|
|
13003
13096
|
const initialActiveRef = useRef(tools.active);
|
|
13004
13097
|
const registry2 = useActionsRegistry();
|
|
13005
|
-
useEffect(() => {
|
|
13006
|
-
if (optionsRef.current.disable) return;
|
|
13007
|
-
if (!registry2) return;
|
|
13008
|
-
const specs = [];
|
|
13009
|
-
for (const [toolId, key] of Object.entries(BUILTIN_OFFHAND_ACTIONS)) {
|
|
13010
|
-
if (toolsRef.current.has(toolId)) {
|
|
13011
|
-
specs.push({ toolId, key });
|
|
13012
|
-
}
|
|
13013
|
-
}
|
|
13014
|
-
if (specs.length === 0) return;
|
|
13015
|
-
const bindings = buildToolOffhandBindings(specs);
|
|
13016
|
-
return registry2.register(makeToolOffhandAction(bindings));
|
|
13017
|
-
}, [registry2, tools]);
|
|
13018
13098
|
useEffect(() => {
|
|
13019
13099
|
if (optionsRef.current.disable) return;
|
|
13020
13100
|
if (!registry2) return;
|
|
@@ -13576,8 +13656,108 @@ function textLineBoxes(pose, opts = {}) {
|
|
|
13576
13656
|
return out;
|
|
13577
13657
|
}
|
|
13578
13658
|
|
|
13579
|
-
// src/
|
|
13659
|
+
// src/core/fillInPoseFrame.ts
|
|
13660
|
+
function fillInPoseFrame(fill, box) {
|
|
13661
|
+
if (isBoundsPattern(fill)) {
|
|
13662
|
+
const o = fill.origin ?? { x: 0, y: 0 };
|
|
13663
|
+
return { ...fill, origin: { x: box.x + o.x, y: box.y + o.y }, units: "local" };
|
|
13664
|
+
}
|
|
13665
|
+
if (!isBoundsGradient(fill)) return fill;
|
|
13666
|
+
const toBox = (p) => ({
|
|
13667
|
+
x: box.x + p.x * box.width,
|
|
13668
|
+
y: box.y + p.y * box.height
|
|
13669
|
+
});
|
|
13670
|
+
if (fill.fill === "linear-gradient") {
|
|
13671
|
+
return { ...fill, from: toBox(fill.from), to: toBox(fill.to), units: "local" };
|
|
13672
|
+
}
|
|
13673
|
+
if (fill.fill === "radial-gradient") {
|
|
13674
|
+
const scale2 = Math.hypot(box.width, box.height) / Math.SQRT2;
|
|
13675
|
+
return { ...fill, center: toBox(fill.center), radius: fill.radius * scale2, units: "local" };
|
|
13676
|
+
}
|
|
13677
|
+
return { ...fill, center: toBox(fill.center), units: "local" };
|
|
13678
|
+
}
|
|
13679
|
+
function fillToBoundsFrame(fill, box) {
|
|
13680
|
+
if (fill.fill === "pattern") {
|
|
13681
|
+
const o = fill.origin ?? { x: 0, y: 0 };
|
|
13682
|
+
return { ...fill, origin: { x: o.x - box.x, y: o.y - box.y }, units: "bounds" };
|
|
13683
|
+
}
|
|
13684
|
+
const isGradient = fill.fill === "linear-gradient" || fill.fill === "radial-gradient" || fill.fill === "conic-gradient";
|
|
13685
|
+
if (!isGradient) return fill;
|
|
13686
|
+
if (box.width === 0 || box.height === 0) return fill;
|
|
13687
|
+
const fromBox = (p) => ({
|
|
13688
|
+
x: (p.x - box.x) / box.width,
|
|
13689
|
+
y: (p.y - box.y) / box.height
|
|
13690
|
+
});
|
|
13691
|
+
if (fill.fill === "linear-gradient") {
|
|
13692
|
+
return { ...fill, from: fromBox(fill.from), to: fromBox(fill.to), units: "bounds" };
|
|
13693
|
+
}
|
|
13694
|
+
if (fill.fill === "radial-gradient") {
|
|
13695
|
+
const scale2 = Math.hypot(box.width, box.height) / Math.SQRT2;
|
|
13696
|
+
return { ...fill, center: fromBox(fill.center), radius: fill.radius / scale2, units: "bounds" };
|
|
13697
|
+
}
|
|
13698
|
+
return { ...fill, center: fromBox(fill.center), units: "bounds" };
|
|
13699
|
+
}
|
|
13700
|
+
function isBoundsPattern(fill) {
|
|
13701
|
+
return fill.fill === "pattern" && fill.units === "bounds";
|
|
13702
|
+
}
|
|
13703
|
+
function isBoundsGradient(fill) {
|
|
13704
|
+
if (fill === void 0) return false;
|
|
13705
|
+
const kind = fill.fill;
|
|
13706
|
+
if (kind !== "linear-gradient" && kind !== "radial-gradient" && kind !== "conic-gradient") {
|
|
13707
|
+
return false;
|
|
13708
|
+
}
|
|
13709
|
+
return fill.units === "bounds";
|
|
13710
|
+
}
|
|
13711
|
+
|
|
13712
|
+
// src/features/patterns/resolveSpec.ts
|
|
13580
13713
|
var cache5 = /* @__PURE__ */ new Map();
|
|
13714
|
+
function specKey(spec) {
|
|
13715
|
+
const keys = Object.keys(spec).sort();
|
|
13716
|
+
const bag = spec;
|
|
13717
|
+
return keys.map((k) => `${k}=${String(bag[k])}`).join("&");
|
|
13718
|
+
}
|
|
13719
|
+
function resolvePatternSpec(spec) {
|
|
13720
|
+
const key = specKey(spec);
|
|
13721
|
+
const hit = cache5.get(key);
|
|
13722
|
+
if (hit !== void 0) return hit;
|
|
13723
|
+
const built = buildTile(spec);
|
|
13724
|
+
cache5.set(key, built);
|
|
13725
|
+
return built;
|
|
13726
|
+
}
|
|
13727
|
+
function buildTile(spec) {
|
|
13728
|
+
const { color, size } = spec;
|
|
13729
|
+
switch (spec.tile) {
|
|
13730
|
+
case "hatch":
|
|
13731
|
+
return hatch({ color, size, lineWidth: spec.lineWidth });
|
|
13732
|
+
case "crosshatch":
|
|
13733
|
+
return crosshatch({ color, size, lineWidth: spec.lineWidth });
|
|
13734
|
+
case "dots":
|
|
13735
|
+
return dots({ color, size, radius: spec.radius });
|
|
13736
|
+
case "chunks":
|
|
13737
|
+
return chunks({
|
|
13738
|
+
color,
|
|
13739
|
+
size,
|
|
13740
|
+
bg: spec.bg,
|
|
13741
|
+
density: spec.density,
|
|
13742
|
+
chunkSize: spec.chunkSize,
|
|
13743
|
+
seed: spec.seed
|
|
13744
|
+
});
|
|
13745
|
+
default:
|
|
13746
|
+
return null;
|
|
13747
|
+
}
|
|
13748
|
+
}
|
|
13749
|
+
function isPatternSpec(payload) {
|
|
13750
|
+
return "tile" in payload;
|
|
13751
|
+
}
|
|
13752
|
+
function resolveFillPattern(fill) {
|
|
13753
|
+
if (fill.fill !== "pattern") return fill;
|
|
13754
|
+
if (!isPatternSpec(fill.pattern)) return fill;
|
|
13755
|
+
const handle = resolvePatternSpec(fill.pattern);
|
|
13756
|
+
return handle ? { ...fill, pattern: handle } : null;
|
|
13757
|
+
}
|
|
13758
|
+
|
|
13759
|
+
// src/features/images/imageCache.ts
|
|
13760
|
+
var cache6 = /* @__PURE__ */ new Map();
|
|
13581
13761
|
var subscribers = /* @__PURE__ */ new Set();
|
|
13582
13762
|
var defaultLoader = async (src) => {
|
|
13583
13763
|
if (typeof Image === "undefined" || typeof createImageBitmap === "undefined") {
|
|
@@ -13595,28 +13775,28 @@ function notify() {
|
|
|
13595
13775
|
}
|
|
13596
13776
|
function startLoad(src) {
|
|
13597
13777
|
const entry = { status: "loading" };
|
|
13598
|
-
|
|
13778
|
+
cache6.set(src, entry);
|
|
13599
13779
|
loader(src).then(
|
|
13600
13780
|
(bitmap) => {
|
|
13601
|
-
if (
|
|
13602
|
-
|
|
13781
|
+
if (cache6.get(src) !== entry) return;
|
|
13782
|
+
cache6.set(src, { status: "ready", bitmap });
|
|
13603
13783
|
notify();
|
|
13604
13784
|
},
|
|
13605
13785
|
() => {
|
|
13606
|
-
if (
|
|
13607
|
-
|
|
13786
|
+
if (cache6.get(src) !== entry) return;
|
|
13787
|
+
cache6.set(src, { status: "error" });
|
|
13608
13788
|
notify();
|
|
13609
13789
|
}
|
|
13610
13790
|
);
|
|
13611
13791
|
}
|
|
13612
13792
|
function getImageBitmap(src) {
|
|
13613
|
-
const entry =
|
|
13793
|
+
const entry = cache6.get(src);
|
|
13614
13794
|
if (entry) return entry.bitmap;
|
|
13615
13795
|
startLoad(src);
|
|
13616
13796
|
return void 0;
|
|
13617
13797
|
}
|
|
13618
13798
|
function imageStatus(src) {
|
|
13619
|
-
return
|
|
13799
|
+
return cache6.get(src)?.status ?? "idle";
|
|
13620
13800
|
}
|
|
13621
13801
|
function subscribeImageReady(cb) {
|
|
13622
13802
|
subscribers.add(cb);
|
|
@@ -13801,6 +13981,17 @@ function rectsToPath(rects) {
|
|
|
13801
13981
|
}
|
|
13802
13982
|
return { kind: "polygon", commands, coords, fillRule: "nonzero" };
|
|
13803
13983
|
}
|
|
13984
|
+
function isFillStyle(v) {
|
|
13985
|
+
return typeof v === "object" && v !== null;
|
|
13986
|
+
}
|
|
13987
|
+
function resolveNodeFill(fill, color, hasStroke, fallback) {
|
|
13988
|
+
if (isFillStyle(fill)) return fill;
|
|
13989
|
+
const c = fill ?? color;
|
|
13990
|
+
if (c === "none") return null;
|
|
13991
|
+
if (c !== void 0) return { color: c };
|
|
13992
|
+
if (hasStroke && fallback === null) return null;
|
|
13993
|
+
return fallback === null ? null : { color: fallback };
|
|
13994
|
+
}
|
|
13804
13995
|
var PATH_PAINTER = {
|
|
13805
13996
|
id: "kit:path",
|
|
13806
13997
|
matches: (node) => {
|
|
@@ -13814,12 +14005,12 @@ var PATH_PAINTER = {
|
|
|
13814
14005
|
const d = node.data;
|
|
13815
14006
|
const projected = pathInPoseFrame(d.path, pose);
|
|
13816
14007
|
const hasStroke = !!d.stroke && d.stroke !== "none" && (d.strokeWidth ?? 0) > 0;
|
|
13817
|
-
const
|
|
13818
|
-
const
|
|
14008
|
+
const declared = resolveNodeFill(d.fill, d.color, hasStroke, hasStroke ? null : "#888");
|
|
14009
|
+
const fill = declared && resolveFillPattern(fillInPoseFrame(declared, pose));
|
|
13819
14010
|
const cmd = {
|
|
13820
14011
|
kind: "path",
|
|
13821
14012
|
path: projected,
|
|
13822
|
-
...
|
|
14013
|
+
...fill ? { fill } : {},
|
|
13823
14014
|
...hasStroke ? { stroke: { paint: { color: d.stroke }, width: d.strokeWidth ?? 1 } } : {}
|
|
13824
14015
|
};
|
|
13825
14016
|
return [cmd];
|
|
@@ -13835,9 +14026,8 @@ var PATH_PAINTER = {
|
|
|
13835
14026
|
ink: (node) => {
|
|
13836
14027
|
const d = node.data;
|
|
13837
14028
|
const hasStroke = !!d.stroke && d.stroke !== "none" && (d.strokeWidth ?? 0) > 0;
|
|
13838
|
-
const fillColor = d.fill ?? d.color;
|
|
13839
14029
|
return {
|
|
13840
|
-
filled:
|
|
14030
|
+
filled: resolveNodeFill(d.fill, d.color, hasStroke, hasStroke ? null : "#888") !== null,
|
|
13841
14031
|
strokeWidth: hasStroke ? d.strokeWidth ?? 1 : 0
|
|
13842
14032
|
};
|
|
13843
14033
|
}
|
|
@@ -13854,10 +14044,12 @@ var SHAPE_PAINTER = {
|
|
|
13854
14044
|
paint: (node, pose) => nodeMemo(node, PAINT_SLOT, pose, () => {
|
|
13855
14045
|
const d = node.data;
|
|
13856
14046
|
const path = pathForShape(d, pose);
|
|
14047
|
+
const declaredFill = resolveNodeFill(d.fill, d.color, false, "#888");
|
|
14048
|
+
const shapeFill = declaredFill && resolveFillPattern(fillInPoseFrame(declaredFill, pose));
|
|
13857
14049
|
return [{
|
|
13858
14050
|
kind: "path",
|
|
13859
14051
|
path,
|
|
13860
|
-
|
|
14052
|
+
...shapeFill ? { fill: shapeFill } : {},
|
|
13861
14053
|
...d.stroke && (d.strokeWidth ?? 0) > 0 ? { stroke: { paint: { color: d.stroke }, width: d.strokeWidth ?? 1 } } : {}
|
|
13862
14054
|
}];
|
|
13863
14055
|
}),
|
|
@@ -14258,11 +14450,8 @@ function useSelectTool(adapter, options) {
|
|
|
14258
14450
|
...moveOpts
|
|
14259
14451
|
},
|
|
14260
14452
|
{ spec: { kind: "drag", target: "empty" }, actionId: "areaSelect" },
|
|
14261
|
-
//
|
|
14262
|
-
//
|
|
14263
|
-
// widget that happens to float over empty canvas isn't a click on
|
|
14264
|
-
// empty canvas, and declining in the SPEC lets the chrome's owner
|
|
14265
|
-
// have the click instead of it being consumed here.
|
|
14453
|
+
// resize/rotate bind only drag (no click), so a click on either handle
|
|
14454
|
+
// (body genuinely empty) would hit target:'empty' and wrongly clear selection.
|
|
14266
14455
|
{
|
|
14267
14456
|
spec: {
|
|
14268
14457
|
kind: "click",
|
|
@@ -14348,17 +14537,17 @@ function worldToLocal(xf, wx, wy) {
|
|
|
14348
14537
|
function annulusSemiAxes(shape, view) {
|
|
14349
14538
|
const bandPx = shape.minBandPx ?? 0;
|
|
14350
14539
|
if (bandPx === 0) return { rx: shape.rx, ry: shape.ry };
|
|
14351
|
-
const band = bandPx
|
|
14540
|
+
const band = pxExtent(bandPx, view.scale);
|
|
14352
14541
|
return {
|
|
14353
|
-
rx: Math.max(shape.rx, shape.innerWidth / 2 + band),
|
|
14354
|
-
ry: Math.max(shape.ry, shape.innerHeight / 2 + band)
|
|
14542
|
+
rx: Math.max(shape.rx, shape.innerWidth / 2 + band.x),
|
|
14543
|
+
ry: Math.max(shape.ry, shape.innerHeight / 2 + band.y)
|
|
14355
14544
|
};
|
|
14356
14545
|
}
|
|
14357
14546
|
function hitRegion(region, wx, wy, xf, view) {
|
|
14358
14547
|
const local = worldToLocal(xf, wx, wy);
|
|
14359
14548
|
if (region.shape.kind === "point") {
|
|
14360
|
-
const
|
|
14361
|
-
return
|
|
14549
|
+
const anchor = localToWorld(xf, region.shape.x, region.shape.y);
|
|
14550
|
+
return withinPxBox(anchor.x - wx, anchor.y - wy, region.shape.hitRadiusPx, view.scale);
|
|
14362
14551
|
}
|
|
14363
14552
|
if (region.shape.kind === "annulus") {
|
|
14364
14553
|
const s = region.shape;
|
|
@@ -14424,14 +14613,13 @@ function asIsVisible(data) {
|
|
|
14424
14613
|
function recordRegionHitbox(debug, affordanceId, region, xf, view) {
|
|
14425
14614
|
if (region.shape.kind === "point") {
|
|
14426
14615
|
const w2 = localToWorld(xf, region.shape.x, region.shape.y);
|
|
14427
|
-
const
|
|
14616
|
+
const e = pxExtent(region.shape.hitRadiusPx, view.scale);
|
|
14428
14617
|
debug.recordHitbox(affordanceId, "handle", {
|
|
14429
14618
|
kind: "rect",
|
|
14430
|
-
x: w2.x -
|
|
14431
|
-
y: w2.y -
|
|
14432
|
-
width:
|
|
14433
|
-
height:
|
|
14434
|
-
...xf.identity ? {} : { rotation: Math.atan2(xf.sin, xf.cos) }
|
|
14619
|
+
x: w2.x - e.x,
|
|
14620
|
+
y: w2.y - e.y,
|
|
14621
|
+
width: e.x * 2,
|
|
14622
|
+
height: e.y * 2
|
|
14435
14623
|
});
|
|
14436
14624
|
return;
|
|
14437
14625
|
}
|
|
@@ -14490,7 +14678,7 @@ function paintRegion(region, xf, view, state, viewT, out) {
|
|
|
14490
14678
|
if (paint.kind === "annulus") {
|
|
14491
14679
|
if (region.shape.kind !== "annulus") return;
|
|
14492
14680
|
const s = region.shape;
|
|
14493
|
-
const insetLocal = (paint.insetPx ?? 0
|
|
14681
|
+
const insetLocal = pxExtent(paint.insetPx ?? 0, view.scale);
|
|
14494
14682
|
const cmd = annulusCommand(s, annulusSemiAxes(s, view), insetLocal, xf, viewT, paint.fill, paint.stroke);
|
|
14495
14683
|
if (cmd) out.push(cmd);
|
|
14496
14684
|
return;
|
|
@@ -14507,13 +14695,13 @@ function paintRegion(region, xf, view, state, viewT, out) {
|
|
|
14507
14695
|
}
|
|
14508
14696
|
}
|
|
14509
14697
|
function annulusCommand(shape, semiAxes, insetLocal, xf, viewT, fill, stroke) {
|
|
14510
|
-
const rx = semiAxes.rx - insetLocal;
|
|
14511
|
-
const ry = semiAxes.ry - insetLocal;
|
|
14698
|
+
const rx = semiAxes.rx - insetLocal.x;
|
|
14699
|
+
const ry = semiAxes.ry - insetLocal.y;
|
|
14512
14700
|
if (rx <= 0 || ry <= 0) return null;
|
|
14513
14701
|
const cx = shape.cx;
|
|
14514
14702
|
const cy = shape.cy;
|
|
14515
|
-
const rectHW = shape.innerWidth / 2 + insetLocal;
|
|
14516
|
-
const rectHH = shape.innerHeight / 2 + insetLocal;
|
|
14703
|
+
const rectHW = shape.innerWidth / 2 + insetLocal.x;
|
|
14704
|
+
const rectHH = shape.innerHeight / 2 + insetLocal.y;
|
|
14517
14705
|
const haveTopBottom = rectHH < ry;
|
|
14518
14706
|
const haveLeftRight = rectHW < rx;
|
|
14519
14707
|
if (!haveTopBottom && !haveLeftRight) return null;
|
|
@@ -14774,6 +14962,7 @@ function useHandTool(opts = {}) {
|
|
|
14774
14962
|
() => Object.assign(defineViewportTool({
|
|
14775
14963
|
id: "hand",
|
|
14776
14964
|
capabilities: ["navigation"],
|
|
14965
|
+
hotkey: "space",
|
|
14777
14966
|
hookName: "useHandTool",
|
|
14778
14967
|
presentation: {
|
|
14779
14968
|
label: "Hand",
|
|
@@ -14898,10 +15087,6 @@ function mirrorHandle(anchor, out) {
|
|
|
14898
15087
|
if (!out || anchor.altBroken) return void 0;
|
|
14899
15088
|
return { x: 2 * anchor.x - out.x, y: 2 * anchor.y - out.y };
|
|
14900
15089
|
}
|
|
14901
|
-
function dist2(ax, ay, bx, by) {
|
|
14902
|
-
const dx = ax - bx, dy = ay - by;
|
|
14903
|
-
return Math.hypot(dx, dy);
|
|
14904
|
-
}
|
|
14905
15090
|
function usePenTool(options) {
|
|
14906
15091
|
const { wrapPath, adapter, autoSelect = true, autoCommitOnClose = true, closeHitRadius = 8, snapPoint: snapPoint2 } = options;
|
|
14907
15092
|
const scratchRef = useRef(null);
|
|
@@ -14925,11 +15110,14 @@ function usePenTool(options) {
|
|
|
14925
15110
|
const fn = optsRef.current.snapPoint;
|
|
14926
15111
|
return fn ? fn({ x, y }) : { x, y };
|
|
14927
15112
|
}, []);
|
|
14928
|
-
const
|
|
14929
|
-
|
|
14930
|
-
|
|
14931
|
-
|
|
14932
|
-
|
|
15113
|
+
const withinCloseRadius = useCallback(
|
|
15114
|
+
(deps, ax, ay, wx, wy) => {
|
|
15115
|
+
const view = deps.view?.get();
|
|
15116
|
+
const scale2 = view?.scale ?? { x: 1, y: 1 };
|
|
15117
|
+
return withinPxRadius(ax - wx, ay - wy, optsRef.current.closeHitRadius, scale2);
|
|
15118
|
+
},
|
|
15119
|
+
[]
|
|
15120
|
+
);
|
|
14933
15121
|
const actions = useMemo(() => {
|
|
14934
15122
|
const s = () => scratchRef.current;
|
|
14935
15123
|
return [
|
|
@@ -14945,10 +15133,9 @@ function usePenTool(options) {
|
|
|
14945
15133
|
if (p?.pressX === void 0 || p.pressY === void 0) return;
|
|
14946
15134
|
const { x: wx, y: wy } = snap2(p.pressX, p.pressY);
|
|
14947
15135
|
const scratch = s();
|
|
14948
|
-
const radius = closeRadius(deps);
|
|
14949
15136
|
if (scratch.current && scratch.current.anchors.length >= 3) {
|
|
14950
15137
|
const first = scratch.current.anchors[0];
|
|
14951
|
-
if (
|
|
15138
|
+
if (withinCloseRadius(deps, first.x, first.y, wx, wy)) {
|
|
14952
15139
|
scratch.current.closed = true;
|
|
14953
15140
|
scratch.finishedSubpaths.push(scratch.current);
|
|
14954
15141
|
scratch.current = null;
|
|
@@ -15067,7 +15254,7 @@ function usePenTool(options) {
|
|
|
15067
15254
|
}
|
|
15068
15255
|
}
|
|
15069
15256
|
];
|
|
15070
|
-
}, [commit, snap2,
|
|
15257
|
+
}, [commit, snap2, withinCloseRadius]);
|
|
15071
15258
|
return useMemo(() => {
|
|
15072
15259
|
return defineTool({
|
|
15073
15260
|
id: "pen",
|
|
@@ -16844,8 +17031,8 @@ function CanvasInner(props, ref) {
|
|
|
16844
17031
|
const isVisible = getIsVisibleRef.current?.() ?? alwaysVisible;
|
|
16845
17032
|
for (const layer of layers2) {
|
|
16846
17033
|
if (!layer.hitTest) continue;
|
|
16847
|
-
const
|
|
16848
|
-
if (
|
|
17034
|
+
const hit = layer.hitTest(worldX, worldY, void 0, view, dims, isVisible);
|
|
17035
|
+
if (hit) return { layerId: layer.id, hit };
|
|
16849
17036
|
}
|
|
16850
17037
|
return null;
|
|
16851
17038
|
}, []);
|
|
@@ -17281,7 +17468,7 @@ function CanvasInner(props, ref) {
|
|
|
17281
17468
|
effectiveView,
|
|
17282
17469
|
{ width, height }
|
|
17283
17470
|
);
|
|
17284
|
-
renderer.render(commands);
|
|
17471
|
+
renderer.render(commands, viewToMat3(effectiveView));
|
|
17285
17472
|
}, [layersWithDebug, width, height, effectiveView, debugSink, redrawNonce, dprProp]);
|
|
17286
17473
|
const shaderIdKey = shaders?.map((h) => h.id).join("|") ?? "";
|
|
17287
17474
|
useEffect(() => {
|
|
@@ -19721,6 +19908,8 @@ function toAffordanceHit(hit) {
|
|
|
19721
19908
|
const scratch = hit.binding.initialScratch ?? {};
|
|
19722
19909
|
return {
|
|
19723
19910
|
kind: hit.region.hitKind ?? `${hit.affordanceId}:${hit.regionId}`,
|
|
19911
|
+
owner: hit.affordanceId,
|
|
19912
|
+
strength: "shared",
|
|
19724
19913
|
...scratch.targetId !== void 0 ? { targetIds: [scratch.targetId] } : {},
|
|
19725
19914
|
...scratch.anchor !== void 0 ? { anchor: scratch.anchor } : {},
|
|
19726
19915
|
...scratch.fixedPoint !== void 0 ? { fixedPoint: scratch.fixedPoint } : {},
|
|
@@ -20249,7 +20438,7 @@ function chordLengthParam(samples) {
|
|
|
20249
20438
|
ts[0] = 0;
|
|
20250
20439
|
let total = 0;
|
|
20251
20440
|
for (let i = 1; i < n; i++) {
|
|
20252
|
-
total +=
|
|
20441
|
+
total += dist2(samples[i - 1], samples[i]);
|
|
20253
20442
|
ts[i] = total;
|
|
20254
20443
|
}
|
|
20255
20444
|
if (total === 0) return null;
|
|
@@ -20282,13 +20471,13 @@ function solveLS(samples, ts, a, e, tStart, tEnd) {
|
|
|
20282
20471
|
let alpha1;
|
|
20283
20472
|
let alpha2;
|
|
20284
20473
|
if (Math.abs(det) < 1e-12) {
|
|
20285
|
-
const chord =
|
|
20474
|
+
const chord = dist2(a, e);
|
|
20286
20475
|
alpha1 = alpha2 = chord / 3;
|
|
20287
20476
|
} else {
|
|
20288
20477
|
alpha1 = (c22 * x1 - c12 * x2) / det;
|
|
20289
20478
|
alpha2 = (c11 * x2 - c12 * x1) / det;
|
|
20290
20479
|
if (alpha1 < 1e-6 || alpha2 < 1e-6) {
|
|
20291
|
-
const chord =
|
|
20480
|
+
const chord = dist2(a, e);
|
|
20292
20481
|
alpha1 = alpha2 = chord / 3;
|
|
20293
20482
|
}
|
|
20294
20483
|
}
|
|
@@ -20324,7 +20513,7 @@ function newtonRefineT(p, t, p0, p1, p2, p3) {
|
|
|
20324
20513
|
function sub(a, b) {
|
|
20325
20514
|
return { x: a.x - b.x, y: a.y - b.y };
|
|
20326
20515
|
}
|
|
20327
|
-
function
|
|
20516
|
+
function dist2(a, b) {
|
|
20328
20517
|
return Math.hypot(a.x - b.x, a.y - b.y);
|
|
20329
20518
|
}
|
|
20330
20519
|
function unit(v) {
|
|
@@ -21334,7 +21523,7 @@ function SceneCanvasInner(props, ref) {
|
|
|
21334
21523
|
const getMode = getActiveModeRef.current;
|
|
21335
21524
|
if (!getMode) return true;
|
|
21336
21525
|
const registry2 = toolsForEligibilityRef.current?.registry;
|
|
21337
|
-
const caps = registry2?.[toolId]?.capabilities ?? [];
|
|
21526
|
+
const caps = registry2?.[toolId]?.eligibility.capabilities ?? [];
|
|
21338
21527
|
if (caps.length === 0) return false;
|
|
21339
21528
|
const allowed = getMode().allowedCapabilities;
|
|
21340
21529
|
for (const c of caps) if (allowed.has(c)) return true;
|
|
@@ -21808,10 +21997,6 @@ function GestureDispatcherMounter({
|
|
|
21808
21997
|
for (const tool of tools.ambient) m.set(tool.id, tool);
|
|
21809
21998
|
return m;
|
|
21810
21999
|
}, [tools.registry, tools.ambient]);
|
|
21811
|
-
const ambientToolIds = useMemo(
|
|
21812
|
-
() => tools.ambient.map((t) => t.id),
|
|
21813
|
-
[tools.ambient]
|
|
21814
|
-
);
|
|
21815
22000
|
const boundsOfRef = useRef(boundsOf2);
|
|
21816
22001
|
boundsOfRef.current = boundsOf2;
|
|
21817
22002
|
const pickEveryRef = useRef(pickEvery);
|
|
@@ -21923,9 +22108,14 @@ function GestureDispatcherMounter({
|
|
|
21923
22108
|
const worldPoint = clientToWorld2(screenPoint.x, screenPoint.y);
|
|
21924
22109
|
const extra = canvasApiRef?.current?.hitTestExtras?.(worldPoint.x, worldPoint.y);
|
|
21925
22110
|
if (extra) {
|
|
22111
|
+
const claim = extra.hit;
|
|
21926
22112
|
return {
|
|
21927
22113
|
kind: `layer:${extra.layerId}`,
|
|
21928
|
-
|
|
22114
|
+
owner: extra.layerId,
|
|
22115
|
+
strength: claim.strength ?? "shared",
|
|
22116
|
+
...claim.claimedKinds !== void 0 ? { claimedKinds: claim.claimedKinds } : {},
|
|
22117
|
+
...claim.cursor !== void 0 ? { cursor: claim.cursor } : {},
|
|
22118
|
+
...claim.initialScratch !== void 0 ? { payload: claim.initialScratch } : {}
|
|
21929
22119
|
};
|
|
21930
22120
|
}
|
|
21931
22121
|
return affordanceAt ? affordanceAt(worldPoint) : null;
|
|
@@ -21945,7 +22135,6 @@ function GestureDispatcherMounter({
|
|
|
21945
22135
|
canvasRef,
|
|
21946
22136
|
actions: registry2,
|
|
21947
22137
|
toolsById,
|
|
21948
|
-
ambientToolIds,
|
|
21949
22138
|
enabled,
|
|
21950
22139
|
keyboard,
|
|
21951
22140
|
affordanceAt: wrappedAffordanceAt,
|
|
@@ -22203,7 +22392,7 @@ function renderSceneToCanvas(args) {
|
|
|
22203
22392
|
entry.dpr = dpr;
|
|
22204
22393
|
}
|
|
22205
22394
|
const commands = buildSceneViewCommands(scene, view, drawOne, extraCommands);
|
|
22206
|
-
entry.renderer.render(commands);
|
|
22395
|
+
entry.renderer.render(commands, viewToMat3(view));
|
|
22207
22396
|
}
|
|
22208
22397
|
function SceneViewCanvasInner(props) {
|
|
22209
22398
|
const { scene, view, width, height, drawOne, extraCommands, className, canvasRef } = props;
|
|
@@ -22543,7 +22732,7 @@ function renderSceneToPixels(args) {
|
|
|
22543
22732
|
bakeBudget: Infinity
|
|
22544
22733
|
});
|
|
22545
22734
|
try {
|
|
22546
|
-
renderer.render(plan.commands);
|
|
22735
|
+
renderer.render(plan.commands, viewToMat3(plan.view));
|
|
22547
22736
|
if (typeof gl.isContextLost === "function" && gl.isContextLost()) {
|
|
22548
22737
|
throw new Error("renderSceneToPixels: WebGL2 context was lost during render");
|
|
22549
22738
|
}
|
|
@@ -23267,6 +23456,64 @@ function applyStyleToRange(runs, start, end, patch) {
|
|
|
23267
23456
|
return coalesceRuns(out);
|
|
23268
23457
|
}
|
|
23269
23458
|
|
|
23459
|
+
// src/features/text/runs/flagRange.ts
|
|
23460
|
+
function nodeHasFlag(style, key) {
|
|
23461
|
+
switch (key) {
|
|
23462
|
+
case "bold":
|
|
23463
|
+
return isBoldWeight(style.fontWeight);
|
|
23464
|
+
case "italic":
|
|
23465
|
+
return style.fontStyle === "italic";
|
|
23466
|
+
case "underline":
|
|
23467
|
+
return style.underline === true;
|
|
23468
|
+
case "strikethrough":
|
|
23469
|
+
return style.strikethrough === true;
|
|
23470
|
+
}
|
|
23471
|
+
}
|
|
23472
|
+
function isBoldWeight(w) {
|
|
23473
|
+
if (w === void 0) return false;
|
|
23474
|
+
if (typeof w === "number") return w >= 600;
|
|
23475
|
+
return w === "bold" || w === "bolder";
|
|
23476
|
+
}
|
|
23477
|
+
function weightIsExpressibleAsRunBold(w) {
|
|
23478
|
+
return w === 700 || w === "bold";
|
|
23479
|
+
}
|
|
23480
|
+
function clearNodeFlag(style, key) {
|
|
23481
|
+
const next = { ...style };
|
|
23482
|
+
switch (key) {
|
|
23483
|
+
case "bold":
|
|
23484
|
+
next.fontWeight = 400;
|
|
23485
|
+
break;
|
|
23486
|
+
case "italic":
|
|
23487
|
+
next.fontStyle = "normal";
|
|
23488
|
+
break;
|
|
23489
|
+
case "underline":
|
|
23490
|
+
delete next.underline;
|
|
23491
|
+
break;
|
|
23492
|
+
case "strikethrough":
|
|
23493
|
+
delete next.strikethrough;
|
|
23494
|
+
break;
|
|
23495
|
+
}
|
|
23496
|
+
return next;
|
|
23497
|
+
}
|
|
23498
|
+
function setFlagOverRange(runs, style, start, end, key, value) {
|
|
23499
|
+
if (value || !nodeHasFlag(style, key)) {
|
|
23500
|
+
return {
|
|
23501
|
+
runs: applyStyleToRange(runs, start, end, { [key]: value }),
|
|
23502
|
+
style,
|
|
23503
|
+
applied: true
|
|
23504
|
+
};
|
|
23505
|
+
}
|
|
23506
|
+
if (key === "bold" && !weightIsExpressibleAsRunBold(style.fontWeight)) {
|
|
23507
|
+
return { runs: [...runs], style, applied: false };
|
|
23508
|
+
}
|
|
23509
|
+
const total = runs.reduce((n, r) => n + r.text.length, 0);
|
|
23510
|
+
const lo = Math.max(0, start);
|
|
23511
|
+
const hi = Math.min(total, end);
|
|
23512
|
+
let next = applyStyleToRange(runs, 0, total, { [key]: true });
|
|
23513
|
+
if (lo < hi) next = applyStyleToRange(next, lo, hi, { [key]: false });
|
|
23514
|
+
return { runs: next, style: clearNodeFlag(style, key), applied: true };
|
|
23515
|
+
}
|
|
23516
|
+
|
|
23270
23517
|
// src/features/text/useTextEdit.ts
|
|
23271
23518
|
var FLAG_SHORTCUTS = [
|
|
23272
23519
|
{ key: "b", shift: false, flag: "bold" },
|
|
@@ -23428,7 +23675,21 @@ function useTextEdit(opts) {
|
|
|
23428
23675
|
togglePending(flag);
|
|
23429
23676
|
return;
|
|
23430
23677
|
}
|
|
23431
|
-
|
|
23678
|
+
if (editingId === null) return;
|
|
23679
|
+
const runs = domToRuns(overlay);
|
|
23680
|
+
const nodeStyle = optsRef.current.getStyle(editingId) ?? {};
|
|
23681
|
+
const setStyle = optsRef.current.setStyle;
|
|
23682
|
+
const current = styleAtRange(runs, range2.start, range2.end)[flag];
|
|
23683
|
+
const unsetting = current === true;
|
|
23684
|
+
if (unsetting && setStyle && nodeHasFlag(nodeStyle, flag)) {
|
|
23685
|
+
const r = setFlagOverRange(runs, nodeStyle, range2.start, range2.end, flag, false);
|
|
23686
|
+
if (!r.applied) return;
|
|
23687
|
+
setStyle(editingId, r.style);
|
|
23688
|
+
writeRunsPreservingSelection(overlay, r.runs, range2.start, range2.end);
|
|
23689
|
+
syncSelection();
|
|
23690
|
+
return;
|
|
23691
|
+
}
|
|
23692
|
+
const next = toggleFlagInRange(runs, range2.start, range2.end, flag);
|
|
23432
23693
|
writeRunsPreservingSelection(overlay, next, range2.start, range2.end);
|
|
23433
23694
|
syncSelection();
|
|
23434
23695
|
}
|
|
@@ -23706,6 +23967,95 @@ function useSceneTextEdit(scene, container, options = {}) {
|
|
|
23706
23967
|
return { ...edit, onDoubleClick };
|
|
23707
23968
|
}
|
|
23708
23969
|
|
|
23970
|
+
// src/core/gradient.ts
|
|
23971
|
+
function sampleGradientStops(stops, t) {
|
|
23972
|
+
if (stops.length === 0) return "rgba(0,0,0,0)";
|
|
23973
|
+
const sorted = [...stops].sort((a, b) => a.offset - b.offset);
|
|
23974
|
+
if (sorted.length === 1) return sorted[0].color;
|
|
23975
|
+
const first = sorted[0];
|
|
23976
|
+
const last = sorted[sorted.length - 1];
|
|
23977
|
+
if (t <= first.offset) return first.color;
|
|
23978
|
+
if (t >= last.offset) return last.color;
|
|
23979
|
+
for (let i = 0; i < sorted.length - 1; i++) {
|
|
23980
|
+
const lo = sorted[i];
|
|
23981
|
+
const hi = sorted[i + 1];
|
|
23982
|
+
if (t < lo.offset || t > hi.offset) continue;
|
|
23983
|
+
const span = hi.offset - lo.offset;
|
|
23984
|
+
if (span <= 0) return hi.color;
|
|
23985
|
+
return lerpColor(lo.color, hi.color, (t - lo.offset) / span);
|
|
23986
|
+
}
|
|
23987
|
+
return last.color;
|
|
23988
|
+
}
|
|
23989
|
+
function lerpColor(a, b, t) {
|
|
23990
|
+
const [ar, ag, ab, aa] = hexToRgba(a);
|
|
23991
|
+
const [br, bg, bb, ba] = hexToRgba(b);
|
|
23992
|
+
return rgbaToHex([
|
|
23993
|
+
ar + (br - ar) * t,
|
|
23994
|
+
ag + (bg - ag) * t,
|
|
23995
|
+
ab + (bb - ab) * t,
|
|
23996
|
+
aa + (ba - aa) * t
|
|
23997
|
+
]);
|
|
23998
|
+
}
|
|
23999
|
+
function withGradientKind(fill, kind) {
|
|
24000
|
+
if (fill.fill === kind) return fill;
|
|
24001
|
+
const common = { stops: fill.stops, units: fill.units, opacity: fill.opacity };
|
|
24002
|
+
const { center, radius, angle } = gradientGeometry(fill);
|
|
24003
|
+
if (kind === "linear-gradient") {
|
|
24004
|
+
const dx = Math.cos(angle) * radius;
|
|
24005
|
+
const dy = Math.sin(angle) * radius;
|
|
24006
|
+
return {
|
|
24007
|
+
fill: "linear-gradient",
|
|
24008
|
+
from: { x: center.x - dx, y: center.y - dy },
|
|
24009
|
+
to: { x: center.x + dx, y: center.y + dy },
|
|
24010
|
+
...common
|
|
24011
|
+
};
|
|
24012
|
+
}
|
|
24013
|
+
if (kind === "radial-gradient") {
|
|
24014
|
+
return { fill: "radial-gradient", center, radius, ...common };
|
|
24015
|
+
}
|
|
24016
|
+
return { fill: "conic-gradient", center, angle, ...common };
|
|
24017
|
+
}
|
|
24018
|
+
function gradientGeometry(fill) {
|
|
24019
|
+
if (fill.fill === "linear-gradient") {
|
|
24020
|
+
const dx = fill.to.x - fill.from.x;
|
|
24021
|
+
const dy = fill.to.y - fill.from.y;
|
|
24022
|
+
return {
|
|
24023
|
+
center: { x: (fill.from.x + fill.to.x) / 2, y: (fill.from.y + fill.to.y) / 2 },
|
|
24024
|
+
radius: Math.hypot(dx, dy) / 2,
|
|
24025
|
+
angle: Math.atan2(dy, dx)
|
|
24026
|
+
};
|
|
24027
|
+
}
|
|
24028
|
+
if (fill.fill === "radial-gradient") {
|
|
24029
|
+
return { center: fill.center, radius: fill.radius, angle: 0 };
|
|
24030
|
+
}
|
|
24031
|
+
return { center: fill.center, radius: conicArmRadius(fill.units), angle: fill.angle };
|
|
24032
|
+
}
|
|
24033
|
+
function conicArmRadius(units) {
|
|
24034
|
+
return units === "bounds" ? 0.5 : 50;
|
|
24035
|
+
}
|
|
24036
|
+
function gradientForBounds(kind, bounds, stops, units) {
|
|
24037
|
+
const center = { x: bounds.x + bounds.width / 2, y: bounds.y + bounds.height / 2 };
|
|
24038
|
+
if (kind === "linear-gradient") {
|
|
24039
|
+
return {
|
|
24040
|
+
fill: "linear-gradient",
|
|
24041
|
+
from: { x: bounds.x, y: center.y },
|
|
24042
|
+
to: { x: bounds.x + bounds.width, y: center.y },
|
|
24043
|
+
stops,
|
|
24044
|
+
units
|
|
24045
|
+
};
|
|
24046
|
+
}
|
|
24047
|
+
if (kind === "radial-gradient") {
|
|
24048
|
+
return {
|
|
24049
|
+
fill: "radial-gradient",
|
|
24050
|
+
center,
|
|
24051
|
+
radius: Math.max(bounds.width, bounds.height) / 2,
|
|
24052
|
+
stops,
|
|
24053
|
+
units
|
|
24054
|
+
};
|
|
24055
|
+
}
|
|
24056
|
+
return { fill: "conic-gradient", center, angle: 0, stops, units };
|
|
24057
|
+
}
|
|
24058
|
+
|
|
23709
24059
|
// src/core/ops/setText.ts
|
|
23710
24060
|
function createSetTextOp(args) {
|
|
23711
24061
|
const { id, from, to, label, coalesceKey = `setText:${id}` } = args;
|
|
@@ -25040,8 +25390,8 @@ function bestAxis(b, axis, anchors, candidates, worldTolerance) {
|
|
|
25040
25390
|
return { delta: bestGuide ? bestDelta : 0, guide: bestGuide };
|
|
25041
25391
|
}
|
|
25042
25392
|
function matchAlignment(bounds, candidates, worldTolerance, anchors) {
|
|
25043
|
-
const x = bestAxis(bounds, "x", anchors.x, candidates, worldTolerance);
|
|
25044
|
-
const y = bestAxis(bounds, "y", anchors.y, candidates, worldTolerance);
|
|
25393
|
+
const x = bestAxis(bounds, "x", anchors.x, candidates, worldTolerance.x);
|
|
25394
|
+
const y = bestAxis(bounds, "y", anchors.y, candidates, worldTolerance.y);
|
|
25045
25395
|
return { dx: x.delta, dy: y.delta, activeX: x.guide, activeY: y.guide };
|
|
25046
25396
|
}
|
|
25047
25397
|
|
|
@@ -25049,7 +25399,7 @@ function matchAlignment(bounds, candidates, worldTolerance, anchors) {
|
|
|
25049
25399
|
var activeList = (m) => [m.activeX, m.activeY].filter((g) => g !== null);
|
|
25050
25400
|
function worldTol(base) {
|
|
25051
25401
|
const t = base.tolerance ?? 6;
|
|
25052
|
-
return base.getView ? t
|
|
25402
|
+
return base.getView ? pxExtent(t, base.getView().scale) : { x: t, y: t };
|
|
25053
25403
|
}
|
|
25054
25404
|
function alignMoveBehavior(args) {
|
|
25055
25405
|
const proj = args.projection ?? RECT_ALIGN_PROJECTION;
|
|
@@ -27270,6 +27620,24 @@ function snapPoint(opts) {
|
|
|
27270
27620
|
};
|
|
27271
27621
|
}
|
|
27272
27622
|
|
|
27273
|
-
|
|
27274
|
-
|
|
27275
|
-
|
|
27623
|
+
// src/contributions/merge.ts
|
|
27624
|
+
function mergeContributions(...bundles) {
|
|
27625
|
+
const out = [];
|
|
27626
|
+
const seen = /* @__PURE__ */ new Set();
|
|
27627
|
+
for (const bundle of bundles) {
|
|
27628
|
+
for (const entry of bundle) {
|
|
27629
|
+
if (seen.has(entry.id)) {
|
|
27630
|
+
throw new Error(
|
|
27631
|
+
`mergeContributions: duplicate contribution id "${entry.id}". Two bundles registered the same id; rename one or merge them by hand.`
|
|
27632
|
+
);
|
|
27633
|
+
}
|
|
27634
|
+
seen.add(entry.id);
|
|
27635
|
+
out.push(entry);
|
|
27636
|
+
}
|
|
27637
|
+
}
|
|
27638
|
+
return out;
|
|
27639
|
+
}
|
|
27640
|
+
|
|
27641
|
+
export { ALWAYS, ANCHOR_HIT_BASE_PX, ActionsProviderIfRoot, ActiveToolContextProvider, ActiveToolContextProviderIfRoot, BUNDLE_TOOLS, COARSE_TARGET_SCALE, CURVE_REPS, ColorOverrideRegistry, CropIcon, CursorCoordsHud, DEFAULT_ALPHA_DECAY, DEFAULT_ALPHA_MIN, DEFAULT_DEBUG_THEME, DEFAULT_DEVICE_PROFILE, DEFAULT_FILL_COLOR, DEFAULT_HANDLE_SIZE2 as DEFAULT_HANDLE_SIZE, DEFAULT_PALETTE, DEFAULT_ROTATION_HANDLE_DISTANCE, DEFAULT_STROKE_COLOR, DEFAULT_TEXT_STYLE, DEFAULT_VELOCITY_DECAY, DepRegistryProviderIfRoot, DeviceProfileProvider, DivideIcon, EASINGS, EllipseIcon, ExcludeIcon, EyedropperIcon, FALLBACK_FIT_VIEW, GHOST_STROKE, HANDLE_BASE_PX, HandIcon, IDENTITY_COLOR_MATRIX, IDENTITY_POSE_COMPOSITION, IntersectIcon, KIT_SHAPE_KINDS, LassoIcon, LineIcon, MIXED, MOVE_ANCHORS, MinimapCanvas, NEVER, OUTLINE_MIN_SCREEN_PX, PATH_ANCHOR_CHROME_ID, PenIcon, PencilIcon, PickHud, PointerProviderIfRoot, PolygonIcon, RECT_ALIGN_PROJECTION, ROTATION_HANDLE_BASE_PX, RectIcon, SPRING_PRESETS, SceneCanvas, SceneViewCanvas, SelectIcon, SelectionContextProvider, SelectionContextProviderIfRoot, ShaderCompileError, StarIcon, SubtractIcon, TextIcon, UnionIcon, UnknownIcon, VERSION, WeaselProvider, WeaselRenderer, aabbCenter, actionIs, alignDeltaFor, alignInsertBehavior, alignMoveBehavior, alignResizeBehavior, alignedStrokeRect, always, and, animateLifecycle, animateOnSetPose, annulusSemiAxes, applyBooleanOp, applyHitExistingGate, applyStyleToRange, areaSelectAction, arrayAdapter, asNodeId, bezierCubic, bezierQuadratic, buildChromeCtx, buildGradientRamp, buildRuleCtx, buildSceneViewCommands, canBringForward, canHover, canSendBackward, capabilityAll, capabilityIn, capabilityIs, capabilityNot, caretIndexAt, cellAt, charOffsetToDomPosition, clampView, clearSelectionAction, clientToCanvas, clipboardCopyAction, clipboardCutAction, cloneAction, coarsePointer, composeAffordanceLayer, composePath, composeRectPose, composeSelectionPose, composeWorldPose, computeFitView2 as computeFitView, computeIndicatorCommand, computeWheelAction, cond, constrainTo45, containedThenNearest, countPathAnchors, createCellHighlightLayer, createChildrenLayer, createCornerResizeAffordance, createDebugOverlayLayer, createDebugSink, createDispatcher, createGridLayer, createGuidesLayer, createHistory2 as createHistory, createMarkdownRenderer, createMoveToIndexOp, createNodeProperties, createNodeRouting, createParallaxLayer, createPathAnchorAffordances, createPathEditingOverlayLayer, createPathLayer, createPenPreviewLayer, createReorderOp, createRotationAffordance, createScene, createSelectionHandlesLayer, createSelectionOutlineLayer, createSelectionOverlayLayer, createSetDataOp, createSetLayerOp, createSetPathOp, createSetTextOp, createTextLayer, createViewportLayer, cycleVertexColors, decomposePath, decomposeRectPose, defaultCommitAdapter, defaultDrawOne, defaultLabelTextRenderer, defaultNodeProperties, defaultNodeRouting, defaultVisibilityRules, deriveAlignmentGuides, deriveParallaxView, describeRule, domPositionToCharOffset, domToRuns, drawLayers, easeIn, easeInBack, easeInBounce, easeInCirc, easeInCubic, easeInElastic, easeInExpo, easeInOut, easeInOutBack, easeInOutBounce, easeInOutCirc, easeInOutCubic, easeInOutElastic, easeInOutExpo, easeInOutQuad, easeInOutQuart, easeInOutQuint, easeInOutSine, easeInQuad, easeInQuart, easeInQuint, easeInSine, easeOut, easeOutBack, easeOutBounce, easeOutCirc, easeOutCubic2 as easeOutCubic, easeOutElastic, easeOutExpo, easeOutQuad, easeOutQuart, easeOutQuint, easeOutSine, editAnchorsAction, enterTextEditAction, enumerateAnchors, evaluate, fillInPoseFrame, fillToBoundsFrame, findNodeShape, findShapeInk, findShapeSilhouette, fitTextPose, fitToBounds, fitViewToBounds, fitZoom, focused, fontString, forEachCoalesced, freeform, gateLayer, gesturing, getAlpha01, getImageBitmap, getNodeShapes, getStylusData, gradientForBounds, gradientGeometry, hexToRgba, hitAffordanceRegions, hitAnchor, hitRotationHandle, hovering, hoveringSelected, imageStatus, inferredNodeProperties, inferredNodeRouting, insertAction, isEditableTarget2 as isEditableTarget, isPatternSpec, lassoSelectAction, layoutMarkdown, lerpColorArray, lerpOklab, lerpOklch, linear, liveScope, makeViewportZoomAction, markdownToRuns, mat3, matchAlignment, matchesKeyBinding, meanScale, measureText, measureTextBounds, measuredWidth, mergeAlphaFromPrev, mergeContributions, modeIn, modeIs, modeNot, modifierHeld, momentum, moveAction, multiActive, nearest, nearestWithin, nestedHitTester, never, nodeHasFlag, none, normalizeHex, not, nurbs, oklabToOklch, oklabToSrgbU8, oklchToOklab, openFilePicker, or, parseColor, parseColorToRgba255, parseDebugFlags, pathContainsPoint, pathContainsPolygon, pathContainsRect, pathDistanceToPoint, pathDivide, pathExclude, pathFromD, pathInPoseFrame, pathInWorld, pathIntersect, pathIntersectsPolygon, pathIntersectsRect, pathOriginProjection, pathSubtract, pathToAnchors, pathUnion, pickTopMostHit, pinchZoomAction, planPixelRender, pointInRotatedRect, pointInTextPose, poseRotationOf, pressureToWidth, rainbowVertexColors, rebaseLocalPose, rectCorners, registerContentHandler, registerNodeShape, registerProgram, renderLabel, renderSceneToCanvas, renderSceneToPixels, resizeAction, resolveColor, resolveDeviceProfile, resolveFillPattern, resolvePatternSpec, resolveRuns, resolveTextStyle, resolveVisibility, rgbaToHex, rotateAction, rotateAroundAABBCenter, rotatePathAround, rotatePoint, rotatedRectCorners, rotationDegreesUnit, rotationHandle, roundToCell, runsToDom, runsToMarkdown, runsToPlainText, sampleGradientStops, sceneFromJSON, sceneNodeClientRect, sceneToAdapter, scopeBindings, screenToWorld, selectFromLasso, selectionAtLeast, selectionEmpty, selectionIs, setFlagOverRange, shapeCoversPoint, sliceAction, snapPoint, solidVertexColors, specificity, spiro, splitPathByLine, splitSubpaths, springPose, springVertexColors, srgbU8ToOklab, staggerVertexColors, startThresholdDrag, styleAtRange, subscribeImageReady, tessellate, tessellateStroke, textCommand, textLineBoxes, tileGrid, toHex8, toRuns, translatePoseViaDescriptor, translateRectPose, tweenPose, tweenVertexColors, unionBounds, unionBoundsPath, useActiveToolContext, useAlign, useAnimator, useArrayAdapter, useAutoCenter, useBooleans, useBooleansAdapter, useCanvasFocus, useCanvasSize, useDecayLoop, useDeviceProfile, useDistribute, useDragGesture, useDragHandle, useDragRadial, useDragRect, useDropZone, useEllipseTool, useEyedropperTool, useGestureDispatcher, useGridCellHover, useGuides, useHandTool, useHandleDrag, useHoverTracking, useImageTool, useKeybindings, useLassoTool, useLineTool, useOptionalActiveToolContext, usePenTool, usePencilTool, usePinchGesture, usePinchZoomTool, usePointerStylus, usePolygonTool, usePublishSelection, useRectTool, useResizePolicy, useRotateTool, useScene, useSceneAdapter, useSceneTextEdit, useSelectTool, useSelection, useSelectionContext, useSimulation, useSliceDep, useStandardActions, useStarTool, useTextEdit, useTextTool, useTools, useVelocityTracker, useViewAnimation, useViewTween, useZoom, verticalAlignOffset, viewToMat3, viewToTransform, viewportDragPanAction, viewportZoomAction, when, withAlpha01, withCoord, withGradientKind, worldEditToStorage, worldPoseLookup, worldToScreen, zoomAt, zoomAtLeast };
|
|
27642
|
+
//# sourceMappingURL=chunk-D2C6K6FO.js.map
|
|
27643
|
+
//# sourceMappingURL=chunk-D2C6K6FO.js.map
|