@weasel-js/labkit 1.4.0-pre.1 → 1.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/_dts/{CanvasStackContext-LnCfqNBA.d.ts → CanvasStackContext-BIRUVVGH.d.ts} +1 -1
- package/dist/_dts/PrefsForm.d-CgxUequc.d.ts +20 -0
- package/dist/_dts/{frac-C-2c72Ij.d.ts → frac-X7mWgd7y.d.ts} +10 -4
- package/dist/_dts/{index-BDVzvRzQ.d.ts → index-FEa1MudK.d.ts} +8 -2
- package/dist/_dts/{types-DYMaEvM5.d.ts → types-ChVJJHvk.d.ts} +3 -0
- package/dist/_dts/{types-D6s4b7if.d.ts → types-lg4TSCb2.d.ts} +3 -1
- package/dist/_dts/{useTrialState-gmMvZqPc.d.ts → useTrialState-Cdm13fvl.d.ts} +2 -1
- package/dist/_dts/weasel-canvas-FJTFi3ZZ.d.ts +5041 -0
- package/dist/canvas/index.d.ts +16 -16
- package/dist/canvas/index.js +2 -2
- package/dist/chrome/index.d.ts +6 -6
- package/dist/chrome/index.js +5 -5
- package/dist/chunk-2YILQ7Y5.js +33 -0
- package/dist/chunk-2YILQ7Y5.js.map +1 -0
- package/dist/{chunk-TO2FUOKF.js → chunk-53AZ2O2N.js} +16 -13
- package/dist/chunk-53AZ2O2N.js.map +1 -0
- package/dist/{chunk-QB5SM4BM.js → chunk-7TRFMIWX.js} +55 -41
- package/dist/chunk-7TRFMIWX.js.map +1 -0
- package/dist/{chunk-6OEYTYML.js → chunk-BMQWLKOL.js} +15 -15
- package/dist/chunk-BMQWLKOL.js.map +1 -0
- package/dist/{chunk-M75ZU6ZZ.js → chunk-D7QIPGEB.js} +3 -3
- package/dist/{chunk-M75ZU6ZZ.js.map → chunk-D7QIPGEB.js.map} +1 -1
- package/dist/{chunk-L5QJOOLV.js → chunk-DG2IFMLA.js} +1309 -273
- package/dist/chunk-DG2IFMLA.js.map +1 -0
- package/dist/{chunk-LN6JDUGB.js → chunk-HXXTULDN.js} +2 -2
- package/dist/{chunk-LN6JDUGB.js.map → chunk-HXXTULDN.js.map} +1 -1
- package/dist/{chunk-RBGKL7NF.js → chunk-J6SBFZYT.js} +1807 -1814
- package/dist/chunk-J6SBFZYT.js.map +1 -0
- package/dist/{chunk-XJ6N32QP.js → chunk-LJSIUFYD.js} +14 -30
- package/dist/chunk-LJSIUFYD.js.map +1 -0
- package/dist/{chunk-AE5CNVRU.js → chunk-MIT3ISW4.js} +37 -31
- package/dist/chunk-MIT3ISW4.js.map +1 -0
- package/dist/{chunk-HHGVISVZ.js → chunk-MSR7EVS6.js} +7 -5
- package/dist/chunk-MSR7EVS6.js.map +1 -0
- package/dist/{chunk-ESIQNQ6K.js → chunk-OFCBEZMU.js} +12 -6
- package/dist/chunk-OFCBEZMU.js.map +1 -0
- package/dist/{chunk-HMFODCOX.js → chunk-PP7ZWAMV.js} +83 -75
- package/dist/chunk-PP7ZWAMV.js.map +1 -0
- package/dist/{chunk-E2UQVZ44.js → chunk-RLOXQZW3.js} +3 -3
- package/dist/{chunk-E2UQVZ44.js.map → chunk-RLOXQZW3.js.map} +1 -1
- package/dist/controls/index.d.ts +4 -3
- package/dist/controls/index.js +3 -3
- package/dist/dragdrop/index.d.ts +5 -5
- package/dist/dragdrop/index.js +2 -2
- package/dist/index.d.ts +57 -77
- package/dist/index.js +308 -161
- package/dist/index.js.map +1 -1
- package/dist/job/index.js +1 -1
- package/dist/layers/index.d.ts +6 -6
- package/dist/layers/index.js +3 -3
- package/dist/loupe/index.d.ts +7 -13
- package/dist/loupe/index.js +2 -2
- package/dist/passthrough/weasel-canvas.d.ts +3 -343
- package/dist/passthrough/weasel-canvas.js +1 -1
- package/dist/passthrough/weasel-ui.d.ts +141 -2866
- package/dist/passthrough/weasel-ui.js +2 -2
- package/dist/primitives/index.js +4 -4
- package/dist/state/index.d.ts +3 -3
- package/dist/state/index.js +4 -2
- package/dist/state/index.js.map +1 -1
- package/dist/styles.css +74 -5
- package/dist/surface/index.d.ts +17 -2
- package/dist/surface/index.js +3 -2
- package/dist/ui/layers/index.js +2 -2
- package/dist/undo/index.d.ts +6 -5
- package/package.json +8 -8
- package/src/annotations/AnnotationOverlay.tsx +10 -6
- package/src/annotations/Annotations.less +6 -0
- package/src/annotations/Annotations.overlay.test.tsx +113 -0
- package/src/annotations/MarkList.tsx +3 -2
- package/src/canvas/CanvasStack.tsx +8 -13
- package/src/canvas/useOrbit.test.ts +93 -1
- package/src/canvas/useOrbit.ts +41 -34
- package/src/canvas/usePanZoom.test.ts +102 -1
- package/src/canvas/usePanZoom.ts +54 -36
- package/src/config/builder.test.ts +5 -0
- package/src/config/builder.ts +6 -0
- package/src/config/types.ts +1 -0
- package/src/controls/ControlPanel.test.tsx +23 -0
- package/src/controls/ControlPanel.tsx +3 -0
- package/src/job/useJob.ts +1 -1
- package/src/lab/Lab.surface.test.tsx +8 -3
- package/src/lab/LabHeader.test.tsx +12 -0
- package/src/lab/LabHeader.tsx +16 -6
- package/src/lab/Workspace.tsx +1 -1
- package/src/layers/LayerList.test.tsx +72 -1
- package/src/layers/LayerList.tsx +40 -32
- package/src/passthrough/weasel-ui.test.ts +9 -0
- package/src/passthrough/weasel-ui.ts +4 -0
- package/src/primitives/FloatingPanel.test.tsx +82 -0
- package/src/primitives/FloatingPanel.tsx +59 -41
- package/src/primitives/ZoomControl.tsx +2 -0
- package/src/state/store.ts +10 -0
- package/src/state/types.ts +3 -0
- package/src/surface/AGENTS.md +11 -1
- package/src/surface/index.ts +7 -1
- package/src/surface/useSurfaceTile.ts +20 -2
- package/src/surface/useTiledSurface.ts +4 -1
- package/src/theme/Interstellar.stories.tsx +4 -3
- package/src/theme/base.less +39 -1
- package/src/trial/Trial.less +27 -5
- package/src/trial/TrialBody.test.tsx +67 -0
- package/src/trial/TrialBody.tsx +155 -0
- package/src/trial/TrialChrome.tsx +18 -10
- package/src/trial/index.ts +2 -0
- package/dist/_dts/DrawCommand-B3bskUsC.d.ts +0 -564
- package/dist/_dts/PrefsForm-BkUJZx0A.d.ts +0 -204
- package/dist/_dts/fitViewToBounds-dZ2UDB6e.d.ts +0 -21
- package/dist/_dts/shapeKinds-Cx_rxwsa.d.ts +0 -87
- package/dist/_dts/types-C-gh9Ap-.d.ts +0 -695
- package/dist/chunk-6OEYTYML.js.map +0 -1
- package/dist/chunk-AE5CNVRU.js.map +0 -1
- package/dist/chunk-ESIQNQ6K.js.map +0 -1
- package/dist/chunk-HHGVISVZ.js.map +0 -1
- package/dist/chunk-HMFODCOX.js.map +0 -1
- package/dist/chunk-L5QJOOLV.js.map +0 -1
- package/dist/chunk-QB5SM4BM.js.map +0 -1
- package/dist/chunk-RBGKL7NF.js.map +0 -1
- package/dist/chunk-TO2FUOKF.js.map +0 -1
- package/dist/chunk-XJ6N32QP.js.map +0 -1
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import { createContext, createElement, forwardRef, useMemo, useRef, useCallback, useState, useImperativeHandle, useSyncExternalStore,
|
|
1
|
+
import { createContext, createElement, forwardRef, useMemo, useRef, useCallback, useState, useEffect, useImperativeHandle, useSyncExternalStore, useLayoutEffect, useContext, useId, useReducer } from 'react';
|
|
2
2
|
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
3
3
|
import earcut from 'earcut';
|
|
4
4
|
import polygonClipping from 'polygon-clipping';
|
|
5
5
|
|
|
6
|
-
// ../core/dist/chunk-
|
|
6
|
+
// ../core/dist/chunk-TORKRNFY.js
|
|
7
7
|
|
|
8
8
|
// ../gestures/dist/index.js
|
|
9
9
|
var GESTURE_DESCRIPTORS = [
|
|
@@ -287,7 +287,7 @@ function matchSpec(e, spec, isMac, phaseCtx) {
|
|
|
287
287
|
}
|
|
288
288
|
var EMPTY_ENGAGED = /* @__PURE__ */ new Set();
|
|
289
289
|
|
|
290
|
-
// ../core/dist/chunk-
|
|
290
|
+
// ../core/dist/chunk-TORKRNFY.js
|
|
291
291
|
var DepRegistryContext = createContext(null);
|
|
292
292
|
function DepRegistryProvider({ children }) {
|
|
293
293
|
const sourcesRef = useRef(/* @__PURE__ */ new Map());
|
|
@@ -437,6 +437,7 @@ function warnSharedScope() {
|
|
|
437
437
|
var ActionsContext = createContext(null);
|
|
438
438
|
function ActionsProvider({ children }) {
|
|
439
439
|
const actionsRef = useRef(/* @__PURE__ */ new Map());
|
|
440
|
+
const liveAction = (id) => actionsRef.current.get(id)?.at(-1);
|
|
440
441
|
const versionRef = useRef(0);
|
|
441
442
|
const cachedRef = useRef([]);
|
|
442
443
|
const cachedVerRef = useRef(-1);
|
|
@@ -451,7 +452,9 @@ function ActionsProvider({ children }) {
|
|
|
451
452
|
const snapshot = () => {
|
|
452
453
|
const v = versionRef.current;
|
|
453
454
|
if (cachedVerRef.current === v) return cachedRef.current;
|
|
454
|
-
const out = Object.freeze(
|
|
455
|
+
const out = Object.freeze(
|
|
456
|
+
Array.from(actionsRef.current.values(), (stack) => stack[stack.length - 1])
|
|
457
|
+
);
|
|
455
458
|
cachedRef.current = out;
|
|
456
459
|
cachedVerRef.current = v;
|
|
457
460
|
return out;
|
|
@@ -469,16 +472,23 @@ function ActionsProvider({ children }) {
|
|
|
469
472
|
register: (action) => {
|
|
470
473
|
validateActionId(action.id);
|
|
471
474
|
validateActionDefaultBinding(action);
|
|
472
|
-
actionsRef.current.
|
|
475
|
+
const stack = actionsRef.current.get(action.id);
|
|
476
|
+
if (stack) stack.push(action);
|
|
477
|
+
else actionsRef.current.set(action.id, [action]);
|
|
473
478
|
versionRef.current++;
|
|
474
479
|
notify2();
|
|
480
|
+
let released = false;
|
|
475
481
|
return () => {
|
|
482
|
+
if (released) return;
|
|
483
|
+
released = true;
|
|
476
484
|
const cur = actionsRef.current.get(action.id);
|
|
477
|
-
if (cur
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
485
|
+
if (!cur) return;
|
|
486
|
+
const i = cur.lastIndexOf(action);
|
|
487
|
+
if (i === -1) return;
|
|
488
|
+
cur.splice(i, 1);
|
|
489
|
+
if (cur.length === 0) actionsRef.current.delete(action.id);
|
|
490
|
+
versionRef.current++;
|
|
491
|
+
notify2();
|
|
482
492
|
};
|
|
483
493
|
},
|
|
484
494
|
unregister: (id) => {
|
|
@@ -489,7 +499,7 @@ function ActionsProvider({ children }) {
|
|
|
489
499
|
},
|
|
490
500
|
list: () => snapshot(),
|
|
491
501
|
trigger: (id, params) => {
|
|
492
|
-
const a =
|
|
502
|
+
const a = liveAction(id);
|
|
493
503
|
if (!a) return false;
|
|
494
504
|
try {
|
|
495
505
|
if (a.invoker && a.invoker.timing === "immediate") {
|
|
@@ -536,7 +546,7 @@ function ActionsProvider({ children }) {
|
|
|
536
546
|
const disp = dispatcherRef.current;
|
|
537
547
|
if (!disp) return null;
|
|
538
548
|
const r = wiredDepRegRef.current ?? depRegRef.current;
|
|
539
|
-
const a =
|
|
549
|
+
const a = liveAction(id);
|
|
540
550
|
const deps = !r ? {} : a?.requires ? buildDepsFromRequires(a, r) : {
|
|
541
551
|
selection: r.get("selection"),
|
|
542
552
|
scene: r.get("scene"),
|
|
@@ -3845,31 +3855,66 @@ function eligibleContribution(reg, entry) {
|
|
|
3845
3855
|
var CURSOR_INK = "#141418";
|
|
3846
3856
|
var CURSOR_HALO = "#ffffff";
|
|
3847
3857
|
var CURSOR_HALO_WIDTH = 2.6;
|
|
3858
|
+
var CURSOR_ANGLE_STEPS = 16;
|
|
3848
3859
|
var CURSOR_MAX_CSS_PX = 128;
|
|
3849
|
-
function
|
|
3860
|
+
function halo(p, k) {
|
|
3850
3861
|
switch (p.role) {
|
|
3851
3862
|
case "ink":
|
|
3852
3863
|
case "accent":
|
|
3853
|
-
return
|
|
3864
|
+
return { d: p.d, fill: CURSOR_HALO, stroke: { color: CURSOR_HALO, width: CURSOR_HALO_WIDTH * k } };
|
|
3854
3865
|
case "stroke":
|
|
3855
|
-
return
|
|
3866
|
+
return { d: p.d, stroke: { color: CURSOR_HALO, width: (p.width + CURSOR_HALO_WIDTH) * k } };
|
|
3856
3867
|
// A detail IS halo-coloured and sits on top of the ink; it has no halo.
|
|
3857
3868
|
case "detail":
|
|
3858
|
-
return
|
|
3869
|
+
return null;
|
|
3859
3870
|
}
|
|
3860
3871
|
}
|
|
3861
|
-
function
|
|
3872
|
+
function ink(p, k) {
|
|
3862
3873
|
switch (p.role) {
|
|
3863
3874
|
case "ink":
|
|
3864
|
-
return
|
|
3875
|
+
return { d: p.d, fill: CURSOR_INK };
|
|
3865
3876
|
case "stroke":
|
|
3866
|
-
return
|
|
3877
|
+
return { d: p.d, stroke: { color: CURSOR_INK, width: p.width * k } };
|
|
3867
3878
|
case "detail":
|
|
3868
|
-
return
|
|
3879
|
+
return { d: p.d, stroke: { color: CURSOR_HALO, width: p.width * k } };
|
|
3869
3880
|
case "accent":
|
|
3870
|
-
return
|
|
3881
|
+
return { d: p.d, fill: p.fill };
|
|
3871
3882
|
}
|
|
3872
3883
|
}
|
|
3884
|
+
function cursorPaintOps(glyph, opts = {}) {
|
|
3885
|
+
const k = opts.lineWidthScale ?? 1;
|
|
3886
|
+
const out = [];
|
|
3887
|
+
for (const p of glyph.paths) {
|
|
3888
|
+
const h = halo(p, k);
|
|
3889
|
+
if (h) out.push(h);
|
|
3890
|
+
}
|
|
3891
|
+
for (const p of glyph.paths) out.push(ink(p, k));
|
|
3892
|
+
return out;
|
|
3893
|
+
}
|
|
3894
|
+
function cursorPaintMatrix(glyph, placement) {
|
|
3895
|
+
const s = placement.size / glyph.box;
|
|
3896
|
+
const theta = placement.angle ?? 0;
|
|
3897
|
+
const a = s * Math.cos(theta);
|
|
3898
|
+
const b = s * Math.sin(theta);
|
|
3899
|
+
const [hx, hy] = glyph.hotspot;
|
|
3900
|
+
return [a, b, -b, a, placement.at.x - (a * hx - b * hy), placement.at.y - (b * hx + a * hy)];
|
|
3901
|
+
}
|
|
3902
|
+
function cursorWorldSize(glyph, worldRadius, scale2) {
|
|
3903
|
+
const r = glyph.radius ?? glyph.box / 2;
|
|
3904
|
+
return worldRadius * scale2 * glyph.box / r;
|
|
3905
|
+
}
|
|
3906
|
+
function chromeLineWidthScale(glyph, size) {
|
|
3907
|
+
return glyph.box / size;
|
|
3908
|
+
}
|
|
3909
|
+
function quantizeCursorAngle(angle) {
|
|
3910
|
+
const i = Math.round(angle / (Math.PI * 2) * CURSOR_ANGLE_STEPS);
|
|
3911
|
+
return (i % CURSOR_ANGLE_STEPS + CURSOR_ANGLE_STEPS) % CURSOR_ANGLE_STEPS;
|
|
3912
|
+
}
|
|
3913
|
+
function renderOp(op) {
|
|
3914
|
+
const fill = op.fill === void 0 ? "none" : op.fill;
|
|
3915
|
+
const stroke = op.stroke ? ` stroke="${op.stroke.color}" stroke-width="${op.stroke.width}" stroke-linecap="round" stroke-linejoin="round"` : "";
|
|
3916
|
+
return `<path d="${op.d}" fill="${fill}"${stroke}/>`;
|
|
3917
|
+
}
|
|
3873
3918
|
function bakeCursor(glyph, opts = {}) {
|
|
3874
3919
|
const size = opts.size ?? 24;
|
|
3875
3920
|
if (size > CURSOR_MAX_CSS_PX) {
|
|
@@ -3877,10 +3922,18 @@ function bakeCursor(glyph, opts = {}) {
|
|
|
3877
3922
|
`cursor size ${size} exceeds the ${CURSOR_MAX_CSS_PX}px cap: the browser would drop the image and silently fall back. Use the painted tier.`
|
|
3878
3923
|
);
|
|
3879
3924
|
}
|
|
3880
|
-
const
|
|
3925
|
+
const paths = cursorPaintOps(glyph).map(renderOp).join("");
|
|
3926
|
+
const c = glyph.box / 2;
|
|
3927
|
+
const step = quantizeCursorAngle(opts.angle ?? 0);
|
|
3928
|
+
const theta = step / CURSOR_ANGLE_STEPS * Math.PI * 2;
|
|
3929
|
+
const body = step === 0 ? paths : `<g transform="rotate(${step * 360 / CURSOR_ANGLE_STEPS} ${c} ${c})">${paths}</g>`;
|
|
3881
3930
|
const svg = `<svg xmlns="http://www.w3.org/2000/svg" width="${size}" height="${size}" viewBox="0 0 ${glyph.box} ${glyph.box}">${body}</svg>`;
|
|
3882
|
-
const
|
|
3883
|
-
const
|
|
3931
|
+
const dx = glyph.hotspot[0] - c;
|
|
3932
|
+
const dy = glyph.hotspot[1] - c;
|
|
3933
|
+
const cos = Math.cos(theta);
|
|
3934
|
+
const sin = Math.sin(theta);
|
|
3935
|
+
const hx = Math.round((c + cos * dx - sin * dy) / glyph.box * size);
|
|
3936
|
+
const hy = Math.round((c + sin * dx + cos * dy) / glyph.box * size);
|
|
3884
3937
|
const uri = `data:image/svg+xml,${encodeURIComponent(svg)}`;
|
|
3885
3938
|
return `url("${uri}") ${hx} ${hy}, ${opts.fallback ?? "default"}`;
|
|
3886
3939
|
}
|
|
@@ -3937,23 +3990,263 @@ var GLYPHS = {
|
|
|
3937
3990
|
"d": "M 18.2 2.6 A 3.2 3.2 0 1 0 18.2 9 A 3.2 3.2 0 1 0 18.2 2.6 Z"
|
|
3938
3991
|
}
|
|
3939
3992
|
]
|
|
3993
|
+
},
|
|
3994
|
+
"brush": {
|
|
3995
|
+
"box": 24,
|
|
3996
|
+
"hotspot": [
|
|
3997
|
+
12,
|
|
3998
|
+
12
|
|
3999
|
+
],
|
|
4000
|
+
"radius": 9.9,
|
|
4001
|
+
"paths": [
|
|
4002
|
+
{
|
|
4003
|
+
"role": "stroke",
|
|
4004
|
+
"d": "M 12 2.1 A 9.9 9.9 0 1 0 12 21.9 A 9.9 9.9 0 1 0 12 2.1 Z",
|
|
4005
|
+
"width": 1.6
|
|
4006
|
+
}
|
|
4007
|
+
]
|
|
4008
|
+
},
|
|
4009
|
+
"crosshairRect": {
|
|
4010
|
+
"box": 24,
|
|
4011
|
+
"hotspot": [
|
|
4012
|
+
9,
|
|
4013
|
+
9
|
|
4014
|
+
],
|
|
4015
|
+
"paths": [
|
|
4016
|
+
{
|
|
4017
|
+
"role": "stroke",
|
|
4018
|
+
"d": "M 1.6 9 L 6.4 9",
|
|
4019
|
+
"width": 1.6
|
|
4020
|
+
},
|
|
4021
|
+
{
|
|
4022
|
+
"role": "stroke",
|
|
4023
|
+
"d": "M 11.6 9 L 16.4 9",
|
|
4024
|
+
"width": 1.6
|
|
4025
|
+
},
|
|
4026
|
+
{
|
|
4027
|
+
"role": "stroke",
|
|
4028
|
+
"d": "M 9 1.6 L 9 6.4",
|
|
4029
|
+
"width": 1.6
|
|
4030
|
+
},
|
|
4031
|
+
{
|
|
4032
|
+
"role": "stroke",
|
|
4033
|
+
"d": "M 9 11.6 L 9 16.4",
|
|
4034
|
+
"width": 1.6
|
|
4035
|
+
},
|
|
4036
|
+
{
|
|
4037
|
+
"role": "ink",
|
|
4038
|
+
"d": "M 14.2 14.2 L 21 14.2 L 21 21 L 14.2 21 Z"
|
|
4039
|
+
}
|
|
4040
|
+
]
|
|
4041
|
+
},
|
|
4042
|
+
"crosshairEllipse": {
|
|
4043
|
+
"box": 24,
|
|
4044
|
+
"hotspot": [
|
|
4045
|
+
9,
|
|
4046
|
+
9
|
|
4047
|
+
],
|
|
4048
|
+
"paths": [
|
|
4049
|
+
{
|
|
4050
|
+
"role": "stroke",
|
|
4051
|
+
"d": "M 1.6 9 L 6.4 9",
|
|
4052
|
+
"width": 1.6
|
|
4053
|
+
},
|
|
4054
|
+
{
|
|
4055
|
+
"role": "stroke",
|
|
4056
|
+
"d": "M 11.6 9 L 16.4 9",
|
|
4057
|
+
"width": 1.6
|
|
4058
|
+
},
|
|
4059
|
+
{
|
|
4060
|
+
"role": "stroke",
|
|
4061
|
+
"d": "M 9 1.6 L 9 6.4",
|
|
4062
|
+
"width": 1.6
|
|
4063
|
+
},
|
|
4064
|
+
{
|
|
4065
|
+
"role": "stroke",
|
|
4066
|
+
"d": "M 9 11.6 L 9 16.4",
|
|
4067
|
+
"width": 1.6
|
|
4068
|
+
},
|
|
4069
|
+
{
|
|
4070
|
+
"role": "ink",
|
|
4071
|
+
"d": "M 17.6 13.9 A 3.7 3.7 0 1 0 17.6 21.3 A 3.7 3.7 0 1 0 17.6 13.9 Z"
|
|
4072
|
+
}
|
|
4073
|
+
]
|
|
4074
|
+
},
|
|
4075
|
+
"crosshairLine": {
|
|
4076
|
+
"box": 24,
|
|
4077
|
+
"hotspot": [
|
|
4078
|
+
9,
|
|
4079
|
+
9
|
|
4080
|
+
],
|
|
4081
|
+
"paths": [
|
|
4082
|
+
{
|
|
4083
|
+
"role": "stroke",
|
|
4084
|
+
"d": "M 1.6 9 L 6.4 9",
|
|
4085
|
+
"width": 1.6
|
|
4086
|
+
},
|
|
4087
|
+
{
|
|
4088
|
+
"role": "stroke",
|
|
4089
|
+
"d": "M 11.6 9 L 16.4 9",
|
|
4090
|
+
"width": 1.6
|
|
4091
|
+
},
|
|
4092
|
+
{
|
|
4093
|
+
"role": "stroke",
|
|
4094
|
+
"d": "M 9 1.6 L 9 6.4",
|
|
4095
|
+
"width": 1.6
|
|
4096
|
+
},
|
|
4097
|
+
{
|
|
4098
|
+
"role": "stroke",
|
|
4099
|
+
"d": "M 9 11.6 L 9 16.4",
|
|
4100
|
+
"width": 1.6
|
|
4101
|
+
},
|
|
4102
|
+
{
|
|
4103
|
+
"role": "stroke",
|
|
4104
|
+
"d": "M 14.2 21 L 21 14.2",
|
|
4105
|
+
"width": 2.2
|
|
4106
|
+
}
|
|
4107
|
+
]
|
|
4108
|
+
},
|
|
4109
|
+
"crosshairStar": {
|
|
4110
|
+
"box": 24,
|
|
4111
|
+
"hotspot": [
|
|
4112
|
+
9,
|
|
4113
|
+
9
|
|
4114
|
+
],
|
|
4115
|
+
"paths": [
|
|
4116
|
+
{
|
|
4117
|
+
"role": "stroke",
|
|
4118
|
+
"d": "M 1.6 9 L 6.4 9",
|
|
4119
|
+
"width": 1.6
|
|
4120
|
+
},
|
|
4121
|
+
{
|
|
4122
|
+
"role": "stroke",
|
|
4123
|
+
"d": "M 11.6 9 L 16.4 9",
|
|
4124
|
+
"width": 1.6
|
|
4125
|
+
},
|
|
4126
|
+
{
|
|
4127
|
+
"role": "stroke",
|
|
4128
|
+
"d": "M 9 1.6 L 9 6.4",
|
|
4129
|
+
"width": 1.6
|
|
4130
|
+
},
|
|
4131
|
+
{
|
|
4132
|
+
"role": "stroke",
|
|
4133
|
+
"d": "M 9 11.6 L 9 16.4",
|
|
4134
|
+
"width": 1.6
|
|
4135
|
+
},
|
|
4136
|
+
{
|
|
4137
|
+
"role": "ink",
|
|
4138
|
+
"d": "M 17.6 13.4 L 18.72 16.06 L 21.59 16.3 L 19.41 18.19 L 20.07 21 L 17.6 19.5 L 15.13 21 L 15.79 18.19 L 13.61 16.3 L 16.48 16.06 Z"
|
|
4139
|
+
}
|
|
4140
|
+
]
|
|
4141
|
+
},
|
|
4142
|
+
"crosshairPolygon": {
|
|
4143
|
+
"box": 24,
|
|
4144
|
+
"hotspot": [
|
|
4145
|
+
9,
|
|
4146
|
+
9
|
|
4147
|
+
],
|
|
4148
|
+
"paths": [
|
|
4149
|
+
{
|
|
4150
|
+
"role": "stroke",
|
|
4151
|
+
"d": "M 1.6 9 L 6.4 9",
|
|
4152
|
+
"width": 1.6
|
|
4153
|
+
},
|
|
4154
|
+
{
|
|
4155
|
+
"role": "stroke",
|
|
4156
|
+
"d": "M 11.6 9 L 16.4 9",
|
|
4157
|
+
"width": 1.6
|
|
4158
|
+
},
|
|
4159
|
+
{
|
|
4160
|
+
"role": "stroke",
|
|
4161
|
+
"d": "M 9 1.6 L 9 6.4",
|
|
4162
|
+
"width": 1.6
|
|
4163
|
+
},
|
|
4164
|
+
{
|
|
4165
|
+
"role": "stroke",
|
|
4166
|
+
"d": "M 9 11.6 L 9 16.4",
|
|
4167
|
+
"width": 1.6
|
|
4168
|
+
},
|
|
4169
|
+
{
|
|
4170
|
+
"role": "ink",
|
|
4171
|
+
"d": "M 17.6 13.5 L 21.5 16.33 L 20.01 20.92 L 15.19 20.92 L 13.7 16.33 Z"
|
|
4172
|
+
}
|
|
4173
|
+
]
|
|
4174
|
+
},
|
|
4175
|
+
"resize": {
|
|
4176
|
+
"box": 24,
|
|
4177
|
+
"hotspot": [
|
|
4178
|
+
12,
|
|
4179
|
+
12
|
|
4180
|
+
],
|
|
4181
|
+
"paths": [
|
|
4182
|
+
{
|
|
4183
|
+
"role": "ink",
|
|
4184
|
+
"d": "M 2.5 12 L 7 8.8 L 7 10.7 L 17 10.7 L 17 8.8 L 21.5 12 L 17 15.2 L 17 13.3 L 7 13.3 L 7 15.2 Z"
|
|
4185
|
+
}
|
|
4186
|
+
]
|
|
4187
|
+
},
|
|
4188
|
+
"rotate": {
|
|
4189
|
+
"box": 24,
|
|
4190
|
+
"hotspot": [
|
|
4191
|
+
12,
|
|
4192
|
+
12
|
|
4193
|
+
],
|
|
4194
|
+
"paths": [
|
|
4195
|
+
{
|
|
4196
|
+
"role": "stroke",
|
|
4197
|
+
"d": "M 5.8 9.74 A 6.6 6.6 0 0 1 18.2 9.74",
|
|
4198
|
+
"width": 2.8
|
|
4199
|
+
},
|
|
4200
|
+
{
|
|
4201
|
+
"role": "ink",
|
|
4202
|
+
"d": "M 4.22 14.07 L 2.98 8.72 L 8.62 10.77 Z"
|
|
4203
|
+
},
|
|
4204
|
+
{
|
|
4205
|
+
"role": "ink",
|
|
4206
|
+
"d": "M 19.78 14.07 L 15.38 10.77 L 21.02 8.72 Z"
|
|
4207
|
+
}
|
|
4208
|
+
]
|
|
3940
4209
|
}
|
|
3941
4210
|
};
|
|
3942
4211
|
var cache2 = /* @__PURE__ */ new Map();
|
|
3943
4212
|
function cursorFor(name, opts = {}) {
|
|
3944
4213
|
const size = opts.size ?? 24;
|
|
3945
4214
|
const fallback = opts.fallback ?? "default";
|
|
3946
|
-
const
|
|
4215
|
+
const step = quantizeCursorAngle(opts.angle ?? 0);
|
|
4216
|
+
const key = `${name}|${size}|${step}|${fallback}`;
|
|
3947
4217
|
const hit = cache2.get(key);
|
|
3948
4218
|
if (hit !== void 0) return hit;
|
|
3949
4219
|
const glyph = GLYPHS[name];
|
|
3950
4220
|
if (glyph === void 0) {
|
|
3951
4221
|
throw new Error(`unknown cursor glyph: ${String(name)}`);
|
|
3952
4222
|
}
|
|
3953
|
-
const css = bakeCursor(glyph, { size, fallback });
|
|
4223
|
+
const css = bakeCursor(glyph, { size, fallback, angle: opts.angle ?? 0 });
|
|
3954
4224
|
cache2.set(key, css);
|
|
3955
4225
|
return css;
|
|
3956
4226
|
}
|
|
4227
|
+
function resolveCursorTier(spec) {
|
|
4228
|
+
if (typeof spec === "string") return { kind: "css", css: spec };
|
|
4229
|
+
const { glyph, size, worldRadius, angle = 0, fallback } = spec;
|
|
4230
|
+
if (worldRadius !== void 0) {
|
|
4231
|
+
return { kind: "painted", glyph, angle, worldRadius };
|
|
4232
|
+
}
|
|
4233
|
+
if (size !== void 0 && size > CURSOR_MAX_CSS_PX) {
|
|
4234
|
+
return { kind: "painted", glyph, angle, size };
|
|
4235
|
+
}
|
|
4236
|
+
return {
|
|
4237
|
+
kind: "css",
|
|
4238
|
+
css: cursorFor(glyph, {
|
|
4239
|
+
...size !== void 0 ? { size } : {},
|
|
4240
|
+
...fallback !== void 0 ? { fallback } : {},
|
|
4241
|
+
angle
|
|
4242
|
+
})
|
|
4243
|
+
};
|
|
4244
|
+
}
|
|
4245
|
+
function resolveCursor(spec) {
|
|
4246
|
+
if (spec === void 0) return void 0;
|
|
4247
|
+
const r = resolveCursorTier(spec);
|
|
4248
|
+
return r.kind === "css" ? r.css : "none";
|
|
4249
|
+
}
|
|
3957
4250
|
|
|
3958
4251
|
// ../history/dist/index.js
|
|
3959
4252
|
var RESUMERS = /* @__PURE__ */ new WeakMap();
|
|
@@ -4377,7 +4670,7 @@ function serialToEntry(se, custom, logger) {
|
|
|
4377
4670
|
};
|
|
4378
4671
|
}
|
|
4379
4672
|
|
|
4380
|
-
// ../core/dist/chunk-
|
|
4673
|
+
// ../core/dist/chunk-NU7D64RL.js
|
|
4381
4674
|
function worldToScreen(worldX, worldY, view) {
|
|
4382
4675
|
return [view.panX + worldX * view.zoom.x, view.panY + worldY * view.zoom.y];
|
|
4383
4676
|
}
|
|
@@ -4550,6 +4843,44 @@ void main() {
|
|
|
4550
4843
|
}
|
|
4551
4844
|
`
|
|
4552
4845
|
);
|
|
4846
|
+
var IMAGE_VOPACITY_VERT_SRC = (
|
|
4847
|
+
/* glsl */
|
|
4848
|
+
`#version 300 es
|
|
4849
|
+
in vec2 a_position;
|
|
4850
|
+
in vec2 a_uv;
|
|
4851
|
+
in float a_opacity;
|
|
4852
|
+
uniform mat3 u_proj;
|
|
4853
|
+
uniform mat3 u_model;
|
|
4854
|
+
out vec2 v_uv;
|
|
4855
|
+
out float v_opacity;
|
|
4856
|
+
void main() {
|
|
4857
|
+
vec3 screen = u_model * vec3(a_position, 1.0);
|
|
4858
|
+
vec3 clip = u_proj * vec3(screen.xy, 1.0);
|
|
4859
|
+
gl_Position = vec4(clip.xy, 0.0, 1.0);
|
|
4860
|
+
v_uv = a_uv;
|
|
4861
|
+
v_opacity = a_opacity;
|
|
4862
|
+
}
|
|
4863
|
+
`
|
|
4864
|
+
);
|
|
4865
|
+
var IMAGE_VOPACITY_FRAG_SRC = (
|
|
4866
|
+
/* glsl */
|
|
4867
|
+
`#version 300 es
|
|
4868
|
+
precision highp float;
|
|
4869
|
+
in vec2 v_uv;
|
|
4870
|
+
in float v_opacity;
|
|
4871
|
+
uniform sampler2D u_sampler;
|
|
4872
|
+
uniform float u_alpha;
|
|
4873
|
+
uniform mat4 u_colorMatrix;
|
|
4874
|
+
uniform vec4 u_colorBias;
|
|
4875
|
+
out vec4 outColor;
|
|
4876
|
+
void main() {
|
|
4877
|
+
vec4 texel = texture(u_sampler, v_uv);
|
|
4878
|
+
vec4 mapped = clamp(u_colorMatrix * texel + u_colorBias, 0.0, 1.0);
|
|
4879
|
+
float a = mapped.a * v_opacity * u_alpha;
|
|
4880
|
+
outColor = vec4(mapped.rgb * a, a);
|
|
4881
|
+
}
|
|
4882
|
+
`
|
|
4883
|
+
);
|
|
4553
4884
|
var IMAGE_FILL_UNIFORMS = [
|
|
4554
4885
|
"u_proj",
|
|
4555
4886
|
"u_model",
|
|
@@ -4560,6 +4891,15 @@ var IMAGE_FILL_UNIFORMS = [
|
|
|
4560
4891
|
"u_colorBias"
|
|
4561
4892
|
];
|
|
4562
4893
|
var IMAGE_FILL_ATTRIBUTES = ["a_position", "a_uv"];
|
|
4894
|
+
var IMAGE_VOPACITY_UNIFORMS = [
|
|
4895
|
+
"u_proj",
|
|
4896
|
+
"u_model",
|
|
4897
|
+
"u_sampler",
|
|
4898
|
+
"u_alpha",
|
|
4899
|
+
"u_colorMatrix",
|
|
4900
|
+
"u_colorBias"
|
|
4901
|
+
];
|
|
4902
|
+
var IMAGE_VOPACITY_ATTRIBUTES = ["a_position", "a_uv", "a_opacity"];
|
|
4563
4903
|
var GRAD_VERT_SRC = (
|
|
4564
4904
|
/* glsl */
|
|
4565
4905
|
`#version 300 es
|
|
@@ -5680,6 +6020,7 @@ seedBuiltins();
|
|
|
5680
6020
|
function getPaintKind(kind) {
|
|
5681
6021
|
return KINDS.get(kind ?? "solid");
|
|
5682
6022
|
}
|
|
6023
|
+
var SPRITE_STRIDE = 9;
|
|
5683
6024
|
function tessellate(path, opts = {}) {
|
|
5684
6025
|
if (path.kind === "rect") return tessellateRect(path);
|
|
5685
6026
|
return tessellatePolygon(path, opts);
|
|
@@ -7362,6 +7703,208 @@ var SolidBatch = class {
|
|
|
7362
7703
|
gl.deleteVertexArray(set.vao);
|
|
7363
7704
|
}
|
|
7364
7705
|
};
|
|
7706
|
+
var MAX_IMAGE_VERTICES_PER_BATCH = 32768;
|
|
7707
|
+
var FLOATS_PER_VERTEX2 = 5;
|
|
7708
|
+
var INITIAL_QUADS = 64;
|
|
7709
|
+
var TIERS = [
|
|
7710
|
+
{ quads: 1, slots: 64 },
|
|
7711
|
+
{ quads: 16, slots: 64 },
|
|
7712
|
+
{ quads: 256, slots: 16 }
|
|
7713
|
+
];
|
|
7714
|
+
TIERS[0].slots;
|
|
7715
|
+
var IMAGE_LARGE_RING_SIZE = 4;
|
|
7716
|
+
function doubledTo2(from, need) {
|
|
7717
|
+
let capacity = from;
|
|
7718
|
+
while (capacity < need) capacity *= 2;
|
|
7719
|
+
return capacity;
|
|
7720
|
+
}
|
|
7721
|
+
function quadIndices(quads) {
|
|
7722
|
+
const out = new Uint32Array(quads * 6);
|
|
7723
|
+
for (let q = 0; q < quads; q++) {
|
|
7724
|
+
const b = q * 4;
|
|
7725
|
+
const j = q * 6;
|
|
7726
|
+
out[j] = b;
|
|
7727
|
+
out[j + 1] = b + 1;
|
|
7728
|
+
out[j + 2] = b + 2;
|
|
7729
|
+
out[j + 3] = b;
|
|
7730
|
+
out[j + 4] = b + 2;
|
|
7731
|
+
out[j + 5] = b + 3;
|
|
7732
|
+
}
|
|
7733
|
+
return out;
|
|
7734
|
+
}
|
|
7735
|
+
var ImageBatch = class {
|
|
7736
|
+
gl;
|
|
7737
|
+
aPos;
|
|
7738
|
+
aUv;
|
|
7739
|
+
aOpacity;
|
|
7740
|
+
/** One ring per tier, cycled per flush. Slots are created on first use, so a
|
|
7741
|
+
* renderer that flushes rarely allocates as few as it flushes. */
|
|
7742
|
+
rings = TIERS.map((t) => new Array(t.slots).fill(void 0));
|
|
7743
|
+
nextInRing = TIERS.map(() => 0);
|
|
7744
|
+
/** For flushes past the largest tier; these sets grow to fit. */
|
|
7745
|
+
largeRing = new Array(IMAGE_LARGE_RING_SIZE).fill(void 0);
|
|
7746
|
+
nextLarge = 0;
|
|
7747
|
+
verts = new Float32Array(INITIAL_QUADS * 4 * FLOATS_PER_VERTEX2);
|
|
7748
|
+
nQuads = 0;
|
|
7749
|
+
constructor(gl, prog) {
|
|
7750
|
+
const aPos = prog.attribute("a_position");
|
|
7751
|
+
const aUv = prog.attribute("a_uv");
|
|
7752
|
+
const aOpacity = prog.attribute("a_opacity");
|
|
7753
|
+
if (aPos === void 0 || aUv === void 0 || aOpacity === void 0) {
|
|
7754
|
+
throw new Error(
|
|
7755
|
+
"ImageBatch: vertex-opacity program is missing a_position / a_uv / a_opacity"
|
|
7756
|
+
);
|
|
7757
|
+
}
|
|
7758
|
+
this.gl = gl;
|
|
7759
|
+
this.aPos = aPos;
|
|
7760
|
+
this.aUv = aUv;
|
|
7761
|
+
this.aOpacity = aOpacity;
|
|
7762
|
+
}
|
|
7763
|
+
/** Indices staged — what a caller passes to `drawElements`. */
|
|
7764
|
+
get length() {
|
|
7765
|
+
return this.nQuads * 6;
|
|
7766
|
+
}
|
|
7767
|
+
get quads() {
|
|
7768
|
+
return this.nQuads;
|
|
7769
|
+
}
|
|
7770
|
+
/** Whether staging one more quad would put the run past the per-flush cap. */
|
|
7771
|
+
wouldOverflow() {
|
|
7772
|
+
return (this.nQuads + 1) * 4 > MAX_IMAGE_VERTICES_PER_BATCH;
|
|
7773
|
+
}
|
|
7774
|
+
/**
|
|
7775
|
+
* Append one image quad: the destination rect `(x, y, w, h)` mapped through
|
|
7776
|
+
* `m`, sampling `(u0, v0)`-`(u1, v1)`, every corner carrying `opacity`.
|
|
7777
|
+
*
|
|
7778
|
+
* An affine maps a rect to a parallelogram, so two triangles still cover it
|
|
7779
|
+
* and the batch draws at `u_model` identity. Corners wind top-left,
|
|
7780
|
+
* top-right, bottom-right, bottom-left, with UVs following — the flips a
|
|
7781
|
+
* command asks for are already in the `u`/`v` the caller passes.
|
|
7782
|
+
*/
|
|
7783
|
+
pushQuad(x, y, w, h, m, u0, v0, u1, v1, opacity) {
|
|
7784
|
+
this.reserve();
|
|
7785
|
+
const v = this.verts;
|
|
7786
|
+
let i = this.nQuads * 4 * FLOATS_PER_VERTEX2;
|
|
7787
|
+
const ma = m[0], mb = m[1], mc = m[3], md = m[4], mtx = m[6], mty = m[7];
|
|
7788
|
+
const x1 = x + w;
|
|
7789
|
+
const y1 = y + h;
|
|
7790
|
+
const ax = ma * x + mc * y + mtx, ay = mb * x + md * y + mty;
|
|
7791
|
+
const bx = ma * x1 + mc * y + mtx, by = mb * x1 + md * y + mty;
|
|
7792
|
+
const cx = ma * x1 + mc * y1 + mtx, cy = mb * x1 + md * y1 + mty;
|
|
7793
|
+
const dx = ma * x + mc * y1 + mtx, dy = mb * x + md * y1 + mty;
|
|
7794
|
+
v[i++] = ax;
|
|
7795
|
+
v[i++] = ay;
|
|
7796
|
+
v[i++] = u0;
|
|
7797
|
+
v[i++] = v0;
|
|
7798
|
+
v[i++] = opacity;
|
|
7799
|
+
v[i++] = bx;
|
|
7800
|
+
v[i++] = by;
|
|
7801
|
+
v[i++] = u1;
|
|
7802
|
+
v[i++] = v0;
|
|
7803
|
+
v[i++] = opacity;
|
|
7804
|
+
v[i++] = cx;
|
|
7805
|
+
v[i++] = cy;
|
|
7806
|
+
v[i++] = u1;
|
|
7807
|
+
v[i++] = v1;
|
|
7808
|
+
v[i++] = opacity;
|
|
7809
|
+
v[i++] = dx;
|
|
7810
|
+
v[i++] = dy;
|
|
7811
|
+
v[i++] = u0;
|
|
7812
|
+
v[i++] = v1;
|
|
7813
|
+
v[i++] = opacity;
|
|
7814
|
+
this.nQuads += 1;
|
|
7815
|
+
}
|
|
7816
|
+
/** Upload the staged geometry into the next set of buffers and bind its VAO.
|
|
7817
|
+
* Returns the index count for the caller's `drawElements`. */
|
|
7818
|
+
uploadAndBind() {
|
|
7819
|
+
const gl = this.gl;
|
|
7820
|
+
const tier = TIERS.findIndex((t) => this.nQuads <= t.quads);
|
|
7821
|
+
const set = tier < 0 ? this.nextLargeSlot() : this.nextRingSlot(tier);
|
|
7822
|
+
gl.bindVertexArray(set.vao);
|
|
7823
|
+
gl.bindBuffer(gl.ARRAY_BUFFER, set.vbo);
|
|
7824
|
+
gl.bufferSubData(gl.ARRAY_BUFFER, 0, this.verts, 0, this.nQuads * 4 * FLOATS_PER_VERTEX2);
|
|
7825
|
+
return this.nQuads * 6;
|
|
7826
|
+
}
|
|
7827
|
+
reset() {
|
|
7828
|
+
this.nQuads = 0;
|
|
7829
|
+
}
|
|
7830
|
+
dispose() {
|
|
7831
|
+
for (const set of [...this.rings.flat(), ...this.largeRing]) {
|
|
7832
|
+
if (set) this.deleteSet(set);
|
|
7833
|
+
}
|
|
7834
|
+
for (const ring of this.rings) ring.fill(void 0);
|
|
7835
|
+
this.largeRing.fill(void 0);
|
|
7836
|
+
}
|
|
7837
|
+
/** Grow the CPU arrays so one more quad fits. */
|
|
7838
|
+
reserve() {
|
|
7839
|
+
const need = (this.nQuads + 1) * 4 * FLOATS_PER_VERTEX2;
|
|
7840
|
+
if (need <= this.verts.length) return;
|
|
7841
|
+
const grown = new Float32Array(doubledTo2(this.verts.length, need));
|
|
7842
|
+
grown.set(this.verts);
|
|
7843
|
+
this.verts = grown;
|
|
7844
|
+
}
|
|
7845
|
+
nextRingSlot(tier) {
|
|
7846
|
+
const ring = this.rings[tier];
|
|
7847
|
+
const slot = this.nextInRing[tier];
|
|
7848
|
+
this.nextInRing[tier] = (slot + 1) % ring.length;
|
|
7849
|
+
const existing = ring[slot];
|
|
7850
|
+
if (existing) return existing;
|
|
7851
|
+
const set = this.createSet(TIERS[tier].quads);
|
|
7852
|
+
ring[slot] = set;
|
|
7853
|
+
return set;
|
|
7854
|
+
}
|
|
7855
|
+
nextLargeSlot() {
|
|
7856
|
+
const gl = this.gl;
|
|
7857
|
+
const slot = this.nextLarge;
|
|
7858
|
+
this.nextLarge = (slot + 1) % IMAGE_LARGE_RING_SIZE;
|
|
7859
|
+
let set = this.largeRing[slot];
|
|
7860
|
+
if (!set) {
|
|
7861
|
+
set = this.createSet(doubledTo2(TIERS[TIERS.length - 1].quads, this.nQuads));
|
|
7862
|
+
this.largeRing[slot] = set;
|
|
7863
|
+
return set;
|
|
7864
|
+
}
|
|
7865
|
+
if (this.nQuads > set.quadCapacity) {
|
|
7866
|
+
set.quadCapacity = doubledTo2(set.quadCapacity, this.nQuads);
|
|
7867
|
+
gl.bindVertexArray(set.vao);
|
|
7868
|
+
gl.bindBuffer(gl.ARRAY_BUFFER, set.vbo);
|
|
7869
|
+
gl.bufferData(
|
|
7870
|
+
gl.ARRAY_BUFFER,
|
|
7871
|
+
set.quadCapacity * 4 * FLOATS_PER_VERTEX2 * 4,
|
|
7872
|
+
gl.DYNAMIC_DRAW
|
|
7873
|
+
);
|
|
7874
|
+
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, set.ibo);
|
|
7875
|
+
gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, quadIndices(set.quadCapacity), gl.STATIC_DRAW);
|
|
7876
|
+
gl.bindVertexArray(null);
|
|
7877
|
+
}
|
|
7878
|
+
return set;
|
|
7879
|
+
}
|
|
7880
|
+
createSet(quads) {
|
|
7881
|
+
const gl = this.gl;
|
|
7882
|
+
const vao = gl.createVertexArray();
|
|
7883
|
+
const vbo = gl.createBuffer();
|
|
7884
|
+
const ibo = gl.createBuffer();
|
|
7885
|
+
if (!vao || !vbo || !ibo) throw new Error("ImageBatch: failed to create GL objects");
|
|
7886
|
+
const stride = FLOATS_PER_VERTEX2 * 4;
|
|
7887
|
+
gl.bindVertexArray(vao);
|
|
7888
|
+
gl.bindBuffer(gl.ARRAY_BUFFER, vbo);
|
|
7889
|
+
gl.bufferData(gl.ARRAY_BUFFER, quads * 4 * stride, gl.DYNAMIC_DRAW);
|
|
7890
|
+
gl.enableVertexAttribArray(this.aPos);
|
|
7891
|
+
gl.vertexAttribPointer(this.aPos, 2, gl.FLOAT, false, stride, 0);
|
|
7892
|
+
gl.enableVertexAttribArray(this.aUv);
|
|
7893
|
+
gl.vertexAttribPointer(this.aUv, 2, gl.FLOAT, false, stride, 8);
|
|
7894
|
+
gl.enableVertexAttribArray(this.aOpacity);
|
|
7895
|
+
gl.vertexAttribPointer(this.aOpacity, 1, gl.FLOAT, false, stride, 16);
|
|
7896
|
+
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, ibo);
|
|
7897
|
+
gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, quadIndices(quads), gl.STATIC_DRAW);
|
|
7898
|
+
gl.bindVertexArray(null);
|
|
7899
|
+
return { vao, vbo, ibo, quadCapacity: quads };
|
|
7900
|
+
}
|
|
7901
|
+
deleteSet(set) {
|
|
7902
|
+
const gl = this.gl;
|
|
7903
|
+
gl.deleteBuffer(set.vbo);
|
|
7904
|
+
gl.deleteBuffer(set.ibo);
|
|
7905
|
+
gl.deleteVertexArray(set.vao);
|
|
7906
|
+
}
|
|
7907
|
+
};
|
|
7365
7908
|
var FRAME_UPLOADS = /* @__PURE__ */ new WeakMap();
|
|
7366
7909
|
var FRAME_PROJ = /* @__PURE__ */ new WeakMap();
|
|
7367
7910
|
function uploadedFor(ctx, prog) {
|
|
@@ -7455,13 +7998,14 @@ function dispatch(ctx, cmd) {
|
|
|
7455
7998
|
case "path":
|
|
7456
7999
|
return drawPath(ctx, cmd);
|
|
7457
8000
|
case "text":
|
|
7458
|
-
|
|
8001
|
+
flushBatches(ctx);
|
|
7459
8002
|
return drawText(ctx, cmd);
|
|
7460
8003
|
case "image":
|
|
7461
|
-
flushSolids(ctx);
|
|
7462
8004
|
return drawImage(ctx, cmd);
|
|
8005
|
+
case "sprites":
|
|
8006
|
+
return drawSprites(ctx, cmd);
|
|
7463
8007
|
case "shader":
|
|
7464
|
-
|
|
8008
|
+
flushBatches(ctx);
|
|
7465
8009
|
return drawShader(ctx, cmd);
|
|
7466
8010
|
}
|
|
7467
8011
|
}
|
|
@@ -7638,6 +8182,7 @@ function canBatchMesh(mesh) {
|
|
|
7638
8182
|
return !mesh.requiresStencil && mesh.vertices.length >> 1 <= MAX_BATCHED_MESH_VERTICES;
|
|
7639
8183
|
}
|
|
7640
8184
|
function stageSolid(ctx, vertices) {
|
|
8185
|
+
flushImages(ctx);
|
|
7641
8186
|
if (ctx.solidState !== void 0 && !stagedStateIsLive(ctx, ctx.solidState)) flushSolids(ctx);
|
|
7642
8187
|
if (ctx.solidBatch.wouldOverflow(vertices)) flushSolids(ctx);
|
|
7643
8188
|
if (ctx.solidState === void 0) {
|
|
@@ -7681,7 +8226,7 @@ function tryStageSolid(ctx, mesh, paint) {
|
|
|
7681
8226
|
pushMesh(ctx, mesh, paint);
|
|
7682
8227
|
return true;
|
|
7683
8228
|
}
|
|
7684
|
-
|
|
8229
|
+
flushBatches(ctx);
|
|
7685
8230
|
return false;
|
|
7686
8231
|
}
|
|
7687
8232
|
function flushSolids(ctx) {
|
|
@@ -7702,6 +8247,56 @@ function flushSolids(ctx) {
|
|
|
7702
8247
|
batch.reset();
|
|
7703
8248
|
ctx.solidState = void 0;
|
|
7704
8249
|
}
|
|
8250
|
+
function stagedImageStateIsLive(ctx, staged, image, sampling) {
|
|
8251
|
+
if (staged.image !== image) return false;
|
|
8252
|
+
if (staged.sampling !== sampling) return false;
|
|
8253
|
+
if (staged.clipDepth !== ctx.clipDepth) return false;
|
|
8254
|
+
const colorMatrix = ctx.state.colorMatrix;
|
|
8255
|
+
return staged.colorMatrix === colorMatrix || sameValues(staged.colorMatrix, colorMatrix);
|
|
8256
|
+
}
|
|
8257
|
+
function stageImage(ctx, image, sampling) {
|
|
8258
|
+
flushSolids(ctx);
|
|
8259
|
+
if (ctx.imageState !== void 0 && !stagedImageStateIsLive(ctx, ctx.imageState, image, sampling)) {
|
|
8260
|
+
flushImages(ctx);
|
|
8261
|
+
}
|
|
8262
|
+
if (ctx.imageBatch.wouldOverflow()) flushImages(ctx);
|
|
8263
|
+
if (ctx.imageState === void 0) {
|
|
8264
|
+
ctx.imageState = {
|
|
8265
|
+
image,
|
|
8266
|
+
sampling,
|
|
8267
|
+
colorMatrix: ctx.state.colorMatrix,
|
|
8268
|
+
clipDepth: ctx.clipDepth
|
|
8269
|
+
};
|
|
8270
|
+
}
|
|
8271
|
+
}
|
|
8272
|
+
function flushImages(ctx) {
|
|
8273
|
+
const batch = ctx.imageBatch;
|
|
8274
|
+
const staged = ctx.imageState;
|
|
8275
|
+
if (batch.length === 0 || staged === void 0) return;
|
|
8276
|
+
const gl = ctx.gl;
|
|
8277
|
+
const prog = ctx.imageFillVOpacity;
|
|
8278
|
+
gl.useProgram(prog.handle);
|
|
8279
|
+
const indexCount = batch.uploadAndBind();
|
|
8280
|
+
setProjAndModel(ctx, prog, BATCH_MODEL);
|
|
8281
|
+
setAlphaUniform(ctx, prog, 1);
|
|
8282
|
+
setColorMatrixUniforms(ctx, prog, staged.colorMatrix);
|
|
8283
|
+
ctx.imageCache.bind(staged.image, 0);
|
|
8284
|
+
gl.texParameteri(
|
|
8285
|
+
gl.TEXTURE_2D,
|
|
8286
|
+
gl.TEXTURE_MAG_FILTER,
|
|
8287
|
+
staged.sampling === "nearest" ? gl.NEAREST : gl.LINEAR
|
|
8288
|
+
);
|
|
8289
|
+
gl.uniform1i(prog.uniform("u_sampler"), 0);
|
|
8290
|
+
applyClipTest(ctx, staged.clipDepth);
|
|
8291
|
+
gl.drawElements(gl.TRIANGLES, indexCount, gl.UNSIGNED_INT, 0);
|
|
8292
|
+
gl.bindVertexArray(null);
|
|
8293
|
+
batch.reset();
|
|
8294
|
+
ctx.imageState = void 0;
|
|
8295
|
+
}
|
|
8296
|
+
function flushBatches(ctx) {
|
|
8297
|
+
flushSolids(ctx);
|
|
8298
|
+
flushImages(ctx);
|
|
8299
|
+
}
|
|
7705
8300
|
function expandAnchorColors(perAnchor, handle) {
|
|
7706
8301
|
const aA = handle.anchorA;
|
|
7707
8302
|
const aB = handle.anchorB;
|
|
@@ -7905,7 +8500,7 @@ function rasterizePathToStencil(ctx, path) {
|
|
|
7905
8500
|
gl.bindVertexArray(null);
|
|
7906
8501
|
}
|
|
7907
8502
|
function pushClip(ctx, path, newDepth) {
|
|
7908
|
-
|
|
8503
|
+
flushBatches(ctx);
|
|
7909
8504
|
const gl = ctx.gl;
|
|
7910
8505
|
const ancestors = ancestorMask(newDepth - 1);
|
|
7911
8506
|
const newBit = 1 << newDepth;
|
|
@@ -7920,7 +8515,7 @@ function pushClip(ctx, path, newDepth) {
|
|
|
7920
8515
|
gl.stencilMask(255);
|
|
7921
8516
|
}
|
|
7922
8517
|
function popClip(ctx, path, oldDepth) {
|
|
7923
|
-
|
|
8518
|
+
flushBatches(ctx);
|
|
7924
8519
|
const gl = ctx.gl;
|
|
7925
8520
|
gl.enable(gl.STENCIL_TEST);
|
|
7926
8521
|
const oldBit = 1 << oldDepth + 1;
|
|
@@ -7967,7 +8562,7 @@ function drawPathStroke(ctx, rawCmd) {
|
|
|
7967
8562
|
const stroke = cmd.stroke;
|
|
7968
8563
|
const align = stroke.align ?? "center";
|
|
7969
8564
|
if (cmd.path.kind === "polygon" && align !== "center") {
|
|
7970
|
-
|
|
8565
|
+
flushBatches(ctx);
|
|
7971
8566
|
drawPathStrokeStenciled(ctx, cmd, align);
|
|
7972
8567
|
return;
|
|
7973
8568
|
}
|
|
@@ -8315,45 +8910,6 @@ function drawTextGroup(ctx, group, prog, dx, dy) {
|
|
|
8315
8910
|
gl.drawElements(gl.TRIANGLES, group.quads.length * 6, gl.UNSIGNED_INT, 0);
|
|
8316
8911
|
gl.bindVertexArray(null);
|
|
8317
8912
|
}
|
|
8318
|
-
var IMAGE_QUAD_RING_SIZE = 64;
|
|
8319
|
-
var IMAGE_QUAD_RINGS = /* @__PURE__ */ new WeakMap();
|
|
8320
|
-
var IMAGE_QUAD_INDICES = new Uint32Array([0, 1, 2, 1, 3, 2]);
|
|
8321
|
-
var IMAGE_QUAD_STRIDE = 16;
|
|
8322
|
-
function imageQuadRing(gl, prog) {
|
|
8323
|
-
const existing = IMAGE_QUAD_RINGS.get(prog);
|
|
8324
|
-
if (existing) return existing;
|
|
8325
|
-
const aPosLoc = prog.attribute("a_position");
|
|
8326
|
-
const aUvLoc = prog.attribute("a_uv");
|
|
8327
|
-
const ibo = gl.createBuffer();
|
|
8328
|
-
if (!ibo) throw new Error("drawImage: createBuffer (IBO) returned null");
|
|
8329
|
-
const vaos = [];
|
|
8330
|
-
const vbos = [];
|
|
8331
|
-
for (let slot = 0; slot < IMAGE_QUAD_RING_SIZE; slot++) {
|
|
8332
|
-
const vao = gl.createVertexArray();
|
|
8333
|
-
const vbo = gl.createBuffer();
|
|
8334
|
-
if (!vao) throw new Error("drawImage: createVertexArray returned null");
|
|
8335
|
-
if (!vbo) throw new Error("drawImage: createBuffer returned null");
|
|
8336
|
-
gl.bindVertexArray(vao);
|
|
8337
|
-
gl.bindBuffer(gl.ARRAY_BUFFER, vbo);
|
|
8338
|
-
gl.bufferData(gl.ARRAY_BUFFER, 4 * IMAGE_QUAD_STRIDE, gl.DYNAMIC_DRAW);
|
|
8339
|
-
if (aPosLoc !== void 0) {
|
|
8340
|
-
gl.enableVertexAttribArray(aPosLoc);
|
|
8341
|
-
gl.vertexAttribPointer(aPosLoc, 2, gl.FLOAT, false, IMAGE_QUAD_STRIDE, 0);
|
|
8342
|
-
}
|
|
8343
|
-
if (aUvLoc !== void 0) {
|
|
8344
|
-
gl.enableVertexAttribArray(aUvLoc);
|
|
8345
|
-
gl.vertexAttribPointer(aUvLoc, 2, gl.FLOAT, false, IMAGE_QUAD_STRIDE, 8);
|
|
8346
|
-
}
|
|
8347
|
-
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, ibo);
|
|
8348
|
-
if (slot === 0) gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, IMAGE_QUAD_INDICES, gl.STATIC_DRAW);
|
|
8349
|
-
gl.bindVertexArray(null);
|
|
8350
|
-
vaos.push(vao);
|
|
8351
|
-
vbos.push(vbo);
|
|
8352
|
-
}
|
|
8353
|
-
const ring = { vaos, vbos, ibo, next: 0 };
|
|
8354
|
-
IMAGE_QUAD_RINGS.set(prog, ring);
|
|
8355
|
-
return ring;
|
|
8356
|
-
}
|
|
8357
8913
|
var TEXT_QUAD_RING_SIZE = 64;
|
|
8358
8914
|
var TEXT_QUAD_RINGS = /* @__PURE__ */ new WeakMap();
|
|
8359
8915
|
function grownTo(need) {
|
|
@@ -8431,22 +8987,9 @@ function disposeTextQuads(gl, prog) {
|
|
|
8431
8987
|
gl.deleteBuffer(ring.ibo);
|
|
8432
8988
|
TEXT_QUAD_RINGS.delete(prog);
|
|
8433
8989
|
}
|
|
8434
|
-
function disposeImageQuads(gl, prog) {
|
|
8435
|
-
const ring = IMAGE_QUAD_RINGS.get(prog);
|
|
8436
|
-
if (!ring) return;
|
|
8437
|
-
for (const vao of ring.vaos) gl.deleteVertexArray(vao);
|
|
8438
|
-
for (const vbo of ring.vbos) gl.deleteBuffer(vbo);
|
|
8439
|
-
gl.deleteBuffer(ring.ibo);
|
|
8440
|
-
IMAGE_QUAD_RINGS.delete(prog);
|
|
8441
|
-
}
|
|
8442
|
-
var IMAGE_QUAD_VERTICES = new Float32Array(16);
|
|
8443
8990
|
function drawImage(ctx, cmd) {
|
|
8444
8991
|
ctx.imageCache.upload(cmd.image, cmd.image);
|
|
8445
|
-
|
|
8446
|
-
const prog = ctx.imageFill;
|
|
8447
|
-
gl.useProgram(prog.handle);
|
|
8448
|
-
const x0 = cmd.x, y0 = cmd.y;
|
|
8449
|
-
const x1 = cmd.x + cmd.w, y1 = cmd.y + cmd.h;
|
|
8992
|
+
stageImage(ctx, cmd.image, cmd.sampling ?? "linear");
|
|
8450
8993
|
const src = cmd.source;
|
|
8451
8994
|
let u0 = 0, v0 = 0, u1 = 1, v1 = 1;
|
|
8452
8995
|
if (src) {
|
|
@@ -8466,43 +9009,50 @@ function drawImage(ctx, cmd) {
|
|
|
8466
9009
|
v0 = v1;
|
|
8467
9010
|
v1 = t;
|
|
8468
9011
|
}
|
|
8469
|
-
|
|
8470
|
-
|
|
8471
|
-
|
|
8472
|
-
|
|
8473
|
-
|
|
8474
|
-
|
|
8475
|
-
|
|
8476
|
-
|
|
8477
|
-
|
|
8478
|
-
|
|
8479
|
-
|
|
8480
|
-
v[10] = u0;
|
|
8481
|
-
v[11] = v1;
|
|
8482
|
-
v[12] = x1;
|
|
8483
|
-
v[13] = y1;
|
|
8484
|
-
v[14] = u1;
|
|
8485
|
-
v[15] = v1;
|
|
8486
|
-
const ring = imageQuadRing(gl, prog);
|
|
8487
|
-
const slot = ring.next;
|
|
8488
|
-
ring.next = (slot + 1) % IMAGE_QUAD_RING_SIZE;
|
|
8489
|
-
gl.bindVertexArray(ring.vaos[slot]);
|
|
8490
|
-
gl.bindBuffer(gl.ARRAY_BUFFER, ring.vbos[slot]);
|
|
8491
|
-
gl.bufferSubData(gl.ARRAY_BUFFER, 0, v);
|
|
8492
|
-
setProjAndModel(ctx, prog);
|
|
8493
|
-
setColorMatrixUniforms(ctx, prog);
|
|
8494
|
-
ctx.imageCache.bind(cmd.image, 0);
|
|
8495
|
-
gl.texParameteri(
|
|
8496
|
-
gl.TEXTURE_2D,
|
|
8497
|
-
gl.TEXTURE_MAG_FILTER,
|
|
8498
|
-
cmd.sampling === "nearest" ? gl.NEAREST : gl.LINEAR
|
|
9012
|
+
ctx.imageBatch.pushQuad(
|
|
9013
|
+
cmd.x,
|
|
9014
|
+
cmd.y,
|
|
9015
|
+
cmd.w,
|
|
9016
|
+
cmd.h,
|
|
9017
|
+
ctx.state.transform,
|
|
9018
|
+
u0,
|
|
9019
|
+
v0,
|
|
9020
|
+
u1,
|
|
9021
|
+
v1,
|
|
9022
|
+
(cmd.opacity ?? 1) * ctx.state.alpha
|
|
8499
9023
|
);
|
|
8500
|
-
|
|
8501
|
-
|
|
8502
|
-
|
|
8503
|
-
|
|
8504
|
-
|
|
8505
|
-
|
|
9024
|
+
}
|
|
9025
|
+
function drawSprites(ctx, cmd) {
|
|
9026
|
+
const data = cmd.sprites;
|
|
9027
|
+
const count = Math.floor(data.length / SPRITE_STRIDE);
|
|
9028
|
+
if (count === 0) return;
|
|
9029
|
+
ctx.imageCache.upload(cmd.image, cmd.image);
|
|
9030
|
+
const sampling = cmd.sampling ?? "linear";
|
|
9031
|
+
stageImage(ctx, cmd.image, sampling);
|
|
9032
|
+
const batch = ctx.imageBatch;
|
|
9033
|
+
const m = ctx.state.transform;
|
|
9034
|
+
const groupAlpha = ctx.state.alpha;
|
|
9035
|
+
const tw = cmd.image.width;
|
|
9036
|
+
const th = cmd.image.height;
|
|
9037
|
+
for (let s = 0, i = 0; s < count; s++, i += SPRITE_STRIDE) {
|
|
9038
|
+
if (batch.wouldOverflow()) {
|
|
9039
|
+
flushImages(ctx);
|
|
9040
|
+
stageImage(ctx, cmd.image, sampling);
|
|
9041
|
+
}
|
|
9042
|
+
const sx = data[i + 4], sy = data[i + 5], sw = data[i + 6], sh = data[i + 7];
|
|
9043
|
+
batch.pushQuad(
|
|
9044
|
+
data[i],
|
|
9045
|
+
data[i + 1],
|
|
9046
|
+
data[i + 2],
|
|
9047
|
+
data[i + 3],
|
|
9048
|
+
m,
|
|
9049
|
+
sx / tw,
|
|
9050
|
+
sy / th,
|
|
9051
|
+
(sx + sw) / tw,
|
|
9052
|
+
(sy + sh) / th,
|
|
9053
|
+
data[i + 8] * groupAlpha
|
|
9054
|
+
);
|
|
9055
|
+
}
|
|
8506
9056
|
}
|
|
8507
9057
|
var CUSTOM_VERT_SRC = (
|
|
8508
9058
|
/* glsl */
|
|
@@ -8591,6 +9141,7 @@ var WeaselRenderer = class {
|
|
|
8591
9141
|
textSdf;
|
|
8592
9142
|
textSdfR8;
|
|
8593
9143
|
imageFill;
|
|
9144
|
+
imageFillVOpacity;
|
|
8594
9145
|
gradFill;
|
|
8595
9146
|
patternFill;
|
|
8596
9147
|
meshCache;
|
|
@@ -8601,6 +9152,7 @@ var WeaselRenderer = class {
|
|
|
8601
9152
|
quadVbo = null;
|
|
8602
9153
|
quadIbo = null;
|
|
8603
9154
|
solidBatch;
|
|
9155
|
+
imageBatch;
|
|
8604
9156
|
groupState = new GroupState();
|
|
8605
9157
|
widthCss;
|
|
8606
9158
|
heightCss;
|
|
@@ -8665,6 +9217,13 @@ var WeaselRenderer = class {
|
|
|
8665
9217
|
this.imageFill = new ShaderProgram(this.gl, IMAGE_VERT_SRC, IMAGE_FRAG_SRC);
|
|
8666
9218
|
this.imageFill.lookupUniforms(IMAGE_FILL_UNIFORMS);
|
|
8667
9219
|
this.imageFill.lookupAttributes(IMAGE_FILL_ATTRIBUTES);
|
|
9220
|
+
this.imageFillVOpacity = new ShaderProgram(
|
|
9221
|
+
this.gl,
|
|
9222
|
+
IMAGE_VOPACITY_VERT_SRC,
|
|
9223
|
+
IMAGE_VOPACITY_FRAG_SRC
|
|
9224
|
+
);
|
|
9225
|
+
this.imageFillVOpacity.lookupUniforms(IMAGE_VOPACITY_UNIFORMS);
|
|
9226
|
+
this.imageFillVOpacity.lookupAttributes(IMAGE_VOPACITY_ATTRIBUTES);
|
|
8668
9227
|
this.gradFill = new ShaderProgram(this.gl, GRAD_VERT_SRC, GRAD_FRAG_SRC);
|
|
8669
9228
|
this.gradFill.lookupUniforms(GRAD_FILL_UNIFORMS);
|
|
8670
9229
|
this.gradFill.lookupAttributes(GRAD_FILL_ATTRIBUTES);
|
|
@@ -8679,6 +9238,7 @@ var WeaselRenderer = class {
|
|
|
8679
9238
|
this.gradRampCache = new GradientRampCache(this.gl);
|
|
8680
9239
|
this.uploadQuadGeometry();
|
|
8681
9240
|
this.solidBatch = new SolidBatch(this.gl, this.pathFillVColor);
|
|
9241
|
+
this.imageBatch = new ImageBatch(this.gl, this.imageFillVOpacity);
|
|
8682
9242
|
}
|
|
8683
9243
|
uploadQuadGeometry() {
|
|
8684
9244
|
const gl = this.gl;
|
|
@@ -8802,6 +9362,13 @@ var WeaselRenderer = class {
|
|
|
8802
9362
|
this.imageFill = new ShaderProgram(this.gl, IMAGE_VERT_SRC, IMAGE_FRAG_SRC);
|
|
8803
9363
|
this.imageFill.lookupUniforms(IMAGE_FILL_UNIFORMS);
|
|
8804
9364
|
this.imageFill.lookupAttributes(IMAGE_FILL_ATTRIBUTES);
|
|
9365
|
+
this.imageFillVOpacity = new ShaderProgram(
|
|
9366
|
+
this.gl,
|
|
9367
|
+
IMAGE_VOPACITY_VERT_SRC,
|
|
9368
|
+
IMAGE_VOPACITY_FRAG_SRC
|
|
9369
|
+
);
|
|
9370
|
+
this.imageFillVOpacity.lookupUniforms(IMAGE_VOPACITY_UNIFORMS);
|
|
9371
|
+
this.imageFillVOpacity.lookupAttributes(IMAGE_VOPACITY_ATTRIBUTES);
|
|
8805
9372
|
this.gradFill = new ShaderProgram(this.gl, GRAD_VERT_SRC, GRAD_FRAG_SRC);
|
|
8806
9373
|
this.gradFill.lookupUniforms(GRAD_FILL_UNIFORMS);
|
|
8807
9374
|
this.gradFill.lookupAttributes(GRAD_FILL_ATTRIBUTES);
|
|
@@ -8816,6 +9383,7 @@ var WeaselRenderer = class {
|
|
|
8816
9383
|
this.gradRampCache = new GradientRampCache(this.gl);
|
|
8817
9384
|
this.uploadQuadGeometry();
|
|
8818
9385
|
this.solidBatch = new SolidBatch(this.gl, this.pathFillVColor);
|
|
9386
|
+
this.imageBatch = new ImageBatch(this.gl, this.imageFillVOpacity);
|
|
8819
9387
|
for (const id of this.programRegistry.keys()) {
|
|
8820
9388
|
const src = getProgramSource(id);
|
|
8821
9389
|
if (!src) continue;
|
|
@@ -8864,7 +9432,7 @@ var WeaselRenderer = class {
|
|
|
8864
9432
|
}
|
|
8865
9433
|
this.meshCache.freeTransient();
|
|
8866
9434
|
this.meshCache.drainPendingDeletes();
|
|
8867
|
-
for (const prog of [this.pathFill, this.pathFillVColor, this.textSdf, this.textSdfR8, this.imageFill, this.gradFill, this.patternFill]) {
|
|
9435
|
+
for (const prog of [this.pathFill, this.pathFillVColor, this.textSdf, this.textSdfR8, this.imageFill, this.imageFillVOpacity, this.gradFill, this.patternFill]) {
|
|
8868
9436
|
gl.deleteProgram(prog.handle);
|
|
8869
9437
|
}
|
|
8870
9438
|
for (const prog of this.programRegistry.values()) {
|
|
@@ -8875,9 +9443,9 @@ var WeaselRenderer = class {
|
|
|
8875
9443
|
this.gradRampCache.free();
|
|
8876
9444
|
if (this.quadVbo) gl.deleteBuffer(this.quadVbo);
|
|
8877
9445
|
if (this.quadIbo) gl.deleteBuffer(this.quadIbo);
|
|
8878
|
-
disposeImageQuads(gl, this.imageFill);
|
|
8879
9446
|
for (const prog of [this.textSdf, this.textSdfR8, this.pathFill]) disposeTextQuads(gl, prog);
|
|
8880
9447
|
this.solidBatch.dispose();
|
|
9448
|
+
this.imageBatch.dispose();
|
|
8881
9449
|
}
|
|
8882
9450
|
/**
|
|
8883
9451
|
* Draw one frame.
|
|
@@ -8906,6 +9474,7 @@ var WeaselRenderer = class {
|
|
|
8906
9474
|
textSdf: this.textSdf,
|
|
8907
9475
|
textSdfR8: this.textSdfR8,
|
|
8908
9476
|
imageFill: this.imageFill,
|
|
9477
|
+
imageFillVOpacity: this.imageFillVOpacity,
|
|
8909
9478
|
gradFill: this.gradFill,
|
|
8910
9479
|
patternFill: this.patternFill,
|
|
8911
9480
|
meshCache: this.meshCache,
|
|
@@ -8917,6 +9486,7 @@ var WeaselRenderer = class {
|
|
|
8917
9486
|
quadVbo: this.quadVbo,
|
|
8918
9487
|
quadIbo: this.quadIbo,
|
|
8919
9488
|
solidBatch: this.solidBatch,
|
|
9489
|
+
imageBatch: this.imageBatch,
|
|
8920
9490
|
state: this.groupState,
|
|
8921
9491
|
widthCss: this.widthCss,
|
|
8922
9492
|
heightCss: this.heightCss,
|
|
@@ -8926,7 +9496,7 @@ var WeaselRenderer = class {
|
|
|
8926
9496
|
viewMatrix: viewMatrix2
|
|
8927
9497
|
};
|
|
8928
9498
|
for (const cmd of commands) dispatch(ctx, cmd);
|
|
8929
|
-
|
|
9499
|
+
flushBatches(ctx);
|
|
8930
9500
|
this.meshCache.freeTransient();
|
|
8931
9501
|
}
|
|
8932
9502
|
resize(dims) {
|
|
@@ -8960,6 +9530,10 @@ var WeaselRenderer = class {
|
|
|
8960
9530
|
return this.solidBatch;
|
|
8961
9531
|
}
|
|
8962
9532
|
/** @internal */
|
|
9533
|
+
_imageBatch() {
|
|
9534
|
+
return this.imageBatch;
|
|
9535
|
+
}
|
|
9536
|
+
/** @internal */
|
|
8963
9537
|
_textSdf() {
|
|
8964
9538
|
return this.textSdf;
|
|
8965
9539
|
}
|
|
@@ -8972,6 +9546,10 @@ var WeaselRenderer = class {
|
|
|
8972
9546
|
return this.imageFill;
|
|
8973
9547
|
}
|
|
8974
9548
|
/** @internal */
|
|
9549
|
+
_imageFillVOpacity() {
|
|
9550
|
+
return this.imageFillVOpacity;
|
|
9551
|
+
}
|
|
9552
|
+
/** @internal */
|
|
8975
9553
|
_gradFill() {
|
|
8976
9554
|
return this.gradFill;
|
|
8977
9555
|
}
|
|
@@ -9567,6 +10145,82 @@ function clientToCanvas(canvas, clientX, clientY) {
|
|
|
9567
10145
|
function clientToCanvasRect(rect, clientX, clientY) {
|
|
9568
10146
|
return [clientX - rect.left, clientY - rect.top];
|
|
9569
10147
|
}
|
|
10148
|
+
var LOST_CAPTURE_EVENT = "lostpointercapture";
|
|
10149
|
+
function reportsButtons(down) {
|
|
10150
|
+
return !!down.buttons;
|
|
10151
|
+
}
|
|
10152
|
+
function isMissedRelease(move) {
|
|
10153
|
+
return move.buttons === 0;
|
|
10154
|
+
}
|
|
10155
|
+
function openPointerSession(origin, down, cb, opts = {}) {
|
|
10156
|
+
const pointerId = down.pointerId;
|
|
10157
|
+
const doc = origin.ownerDocument ?? document;
|
|
10158
|
+
const buttonsReported = reportsButtons(down);
|
|
10159
|
+
let active = true;
|
|
10160
|
+
const teardown = () => {
|
|
10161
|
+
active = false;
|
|
10162
|
+
doc.removeEventListener("pointermove", onMove, true);
|
|
10163
|
+
doc.removeEventListener("pointerup", onUp, true);
|
|
10164
|
+
doc.removeEventListener("pointercancel", onPointerCancel, true);
|
|
10165
|
+
doc.removeEventListener("pointerdown", onRepress, true);
|
|
10166
|
+
origin.removeEventListener(LOST_CAPTURE_EVENT, onLostCapture);
|
|
10167
|
+
if (opts.capture !== false) {
|
|
10168
|
+
try {
|
|
10169
|
+
origin.releasePointerCapture?.(pointerId);
|
|
10170
|
+
} catch {
|
|
10171
|
+
}
|
|
10172
|
+
}
|
|
10173
|
+
};
|
|
10174
|
+
const mine = (e) => e.pointerId === pointerId;
|
|
10175
|
+
const end = (e) => {
|
|
10176
|
+
if (!active) return;
|
|
10177
|
+
teardown();
|
|
10178
|
+
cb.onEnd?.(e);
|
|
10179
|
+
};
|
|
10180
|
+
const abort = (reason) => {
|
|
10181
|
+
if (!active) return;
|
|
10182
|
+
teardown();
|
|
10183
|
+
cb.onCancel?.(reason);
|
|
10184
|
+
};
|
|
10185
|
+
function onMove(e) {
|
|
10186
|
+
if (!active || !mine(e)) return;
|
|
10187
|
+
if (buttonsReported && isMissedRelease(e)) {
|
|
10188
|
+
end(e);
|
|
10189
|
+
return;
|
|
10190
|
+
}
|
|
10191
|
+
cb.onMove?.(e);
|
|
10192
|
+
}
|
|
10193
|
+
function onUp(e) {
|
|
10194
|
+
if (mine(e)) end(e);
|
|
10195
|
+
}
|
|
10196
|
+
function onPointerCancel(e) {
|
|
10197
|
+
if (mine(e)) abort("pointercancel");
|
|
10198
|
+
}
|
|
10199
|
+
function onRepress(e) {
|
|
10200
|
+
if (mine(e)) abort("superseded");
|
|
10201
|
+
}
|
|
10202
|
+
function onLostCapture(e) {
|
|
10203
|
+
if (e.pointerId === pointerId) abort("lostcapture");
|
|
10204
|
+
}
|
|
10205
|
+
if (opts.capture !== false) {
|
|
10206
|
+
try {
|
|
10207
|
+
origin.setPointerCapture?.(pointerId);
|
|
10208
|
+
} catch {
|
|
10209
|
+
}
|
|
10210
|
+
}
|
|
10211
|
+
doc.addEventListener("pointermove", onMove, true);
|
|
10212
|
+
doc.addEventListener("pointerup", onUp, true);
|
|
10213
|
+
doc.addEventListener("pointercancel", onPointerCancel, true);
|
|
10214
|
+
doc.addEventListener("pointerdown", onRepress, true);
|
|
10215
|
+
origin.addEventListener(LOST_CAPTURE_EVENT, onLostCapture);
|
|
10216
|
+
return {
|
|
10217
|
+
pointerId,
|
|
10218
|
+
get active() {
|
|
10219
|
+
return active;
|
|
10220
|
+
},
|
|
10221
|
+
cancel: () => abort("aborted")
|
|
10222
|
+
};
|
|
10223
|
+
}
|
|
9570
10224
|
var BASE_PX = {
|
|
9571
10225
|
handle: 8,
|
|
9572
10226
|
anchor: 8,
|
|
@@ -9882,8 +10536,8 @@ function runLayoutPass(scratch, moveCtx) {
|
|
|
9882
10536
|
for (const [cid, pose] of srcLayout.childPoses(srcContainer, srcChildren)) {
|
|
9883
10537
|
const cur = composeWorldPose(poseAdapter, cid, pc.compose);
|
|
9884
10538
|
const next = pose;
|
|
9885
|
-
const
|
|
9886
|
-
if (
|
|
10539
|
+
const same2 = cur.x === next.x && cur.y === next.y && cur.width === next.width && cur.height === next.height;
|
|
10540
|
+
if (same2) continue;
|
|
9887
10541
|
sourceReflow.set(cid, pose);
|
|
9888
10542
|
const parent = scene.get(asNodeId(cid))?.parent ?? null;
|
|
9889
10543
|
scratch.previews.set(asNodeId(cid), rebaseLocalPose(poseAdapter, pose, parent, pc.compose, pc.decompose));
|
|
@@ -11237,6 +11891,11 @@ var cloneAction = {
|
|
|
11237
11891
|
id: "clone",
|
|
11238
11892
|
label: "Clone",
|
|
11239
11893
|
defaultBinding: { kind: "drag" },
|
|
11894
|
+
// The platform's duplicate cursor, and the whole reason this field is
|
|
11895
|
+
// modifier-aware: the select tool binds clone behind `mods: { alt: true }`,
|
|
11896
|
+
// so the pump predicts it — and shows this — only while Alt is down.
|
|
11897
|
+
cursor: "copy",
|
|
11898
|
+
activeCursor: "copy",
|
|
11240
11899
|
eligible: { capability: ["edits-page", "creates-selection"] },
|
|
11241
11900
|
requires: ["selection", "scene", "applyOps"],
|
|
11242
11901
|
invoker: {
|
|
@@ -11321,6 +11980,28 @@ var cloneAction = {
|
|
|
11321
11980
|
},
|
|
11322
11981
|
enabled: () => true
|
|
11323
11982
|
};
|
|
11983
|
+
function createVelocityTracker() {
|
|
11984
|
+
let samples = [];
|
|
11985
|
+
return {
|
|
11986
|
+
record(dx, dy, t) {
|
|
11987
|
+
samples.push({ dx, dy, t });
|
|
11988
|
+
const cutoff = t - 100;
|
|
11989
|
+
samples = samples.filter((s) => s.t >= cutoff);
|
|
11990
|
+
},
|
|
11991
|
+
getVelocity() {
|
|
11992
|
+
const s = samples;
|
|
11993
|
+
if (s.length < 2) return { vx: 0, vy: 0 };
|
|
11994
|
+
const dt = s[s.length - 1].t - s[0].t;
|
|
11995
|
+
if (dt === 0) return { vx: 0, vy: 0 };
|
|
11996
|
+
const totalDx = s.slice(1).reduce((acc, p) => acc + p.dx, 0);
|
|
11997
|
+
const totalDy = s.slice(1).reduce((acc, p) => acc + p.dy, 0);
|
|
11998
|
+
return { vx: totalDx / dt, vy: totalDy / dt };
|
|
11999
|
+
},
|
|
12000
|
+
reset() {
|
|
12001
|
+
samples = [];
|
|
12002
|
+
}
|
|
12003
|
+
};
|
|
12004
|
+
}
|
|
11324
12005
|
var viewportDragPanAction = {
|
|
11325
12006
|
id: "viewport.dragPan",
|
|
11326
12007
|
label: "Drag to pan viewport",
|
|
@@ -11338,17 +12019,37 @@ var viewportDragPanAction = {
|
|
|
11338
12019
|
requires: ["view"],
|
|
11339
12020
|
invoker: {
|
|
11340
12021
|
timing: "ongoing",
|
|
11341
|
-
start(ctx) {
|
|
12022
|
+
start(ctx, opts) {
|
|
11342
12023
|
const view = ctx.deps.view;
|
|
11343
12024
|
if (!view) return {};
|
|
11344
12025
|
const startView = view.get();
|
|
11345
|
-
const
|
|
12026
|
+
const params = resolveParams(opts?.params) ?? {};
|
|
12027
|
+
const inertia = params.inertia === false ? void 0 : params.inertia;
|
|
12028
|
+
const scratch = {
|
|
12029
|
+
startView,
|
|
12030
|
+
view,
|
|
12031
|
+
axis: params.axis ?? "both",
|
|
12032
|
+
inertia,
|
|
12033
|
+
// Only track when a coast could actually happen, so the common
|
|
12034
|
+
// no-inertia drag does no per-move work.
|
|
12035
|
+
tracker: inertia && view.decay ? createVelocityTracker() : void 0,
|
|
12036
|
+
lastScreen: { x: 0, y: 0 }
|
|
12037
|
+
};
|
|
11346
12038
|
return {
|
|
11347
12039
|
kind: "pan",
|
|
11348
12040
|
onMove(moveCtx) {
|
|
11349
12041
|
if (!moveCtx.drag) return;
|
|
11350
12042
|
const screen = moveCtx.drag.screenDelta ?? moveCtx.drag.delta;
|
|
11351
|
-
const
|
|
12043
|
+
const screenDx = scratch.axis === "y" ? 0 : screen.x;
|
|
12044
|
+
const screenDy = scratch.axis === "x" ? 0 : screen.y;
|
|
12045
|
+
if (scratch.tracker) {
|
|
12046
|
+
scratch.tracker.record(
|
|
12047
|
+
screenDx - scratch.lastScreen.x,
|
|
12048
|
+
screenDy - scratch.lastScreen.y,
|
|
12049
|
+
performance.now()
|
|
12050
|
+
);
|
|
12051
|
+
scratch.lastScreen = { x: screenDx, y: screenDy };
|
|
12052
|
+
}
|
|
11352
12053
|
const sv = scratch.startView;
|
|
11353
12054
|
scratch.view.set({
|
|
11354
12055
|
...sv,
|
|
@@ -11356,7 +12057,24 @@ var viewportDragPanAction = {
|
|
|
11356
12057
|
y: sv.y - screenDy / sv.scale.y
|
|
11357
12058
|
});
|
|
11358
12059
|
},
|
|
11359
|
-
onEnd() {
|
|
12060
|
+
onEnd(_endCtx, reason) {
|
|
12061
|
+
const { tracker, inertia: inertia2, view: v } = scratch;
|
|
12062
|
+
if (reason === "cancel" || !tracker || !inertia2 || !v.decay) return;
|
|
12063
|
+
const { vx, vy } = tracker.getVelocity();
|
|
12064
|
+
const scale2 = scratch.startView.scale;
|
|
12065
|
+
v.decay({
|
|
12066
|
+
// Screen px/ms → world units/ms, matching the onMove conversion.
|
|
12067
|
+
velocity: { vx: -vx / scale2.x, vy: -vy / scale2.y },
|
|
12068
|
+
friction: inertia2.friction,
|
|
12069
|
+
minSpeed: inertia2.minSpeed,
|
|
12070
|
+
boundary: inertia2.boundary,
|
|
12071
|
+
viewBounds: inertia2.bounds,
|
|
12072
|
+
initialPosition: { x: v.get().x, y: v.get().y },
|
|
12073
|
+
onTick: (dx, dy) => {
|
|
12074
|
+
const cur = v.get();
|
|
12075
|
+
v.set({ ...cur, x: cur.x + dx, y: cur.y + dy });
|
|
12076
|
+
}
|
|
12077
|
+
});
|
|
11360
12078
|
}
|
|
11361
12079
|
};
|
|
11362
12080
|
}
|
|
@@ -11457,6 +12175,52 @@ function makeViewportZoomAction(opts = {}) {
|
|
|
11457
12175
|
};
|
|
11458
12176
|
}
|
|
11459
12177
|
makeViewportZoomAction();
|
|
12178
|
+
var viewportWheelPanAction = {
|
|
12179
|
+
id: "viewport.wheelPan",
|
|
12180
|
+
label: "Pan (wheel)",
|
|
12181
|
+
group: "viewport",
|
|
12182
|
+
/**
|
|
12183
|
+
* Plain wheel → pan; Shift+wheel → horizontal pan (axis swap).
|
|
12184
|
+
* Cmd+wheel is claimed by `viewportZoomAction`. The matcher's strict
|
|
12185
|
+
* modifier check keeps the bindings exclusive: omitting `mods` forbids
|
|
12186
|
+
* any modifier, and `mods: { shift: true }` forbids the others.
|
|
12187
|
+
*/
|
|
12188
|
+
defaultBinding: [
|
|
12189
|
+
{ spec: { kind: "wheel" }, opts: {} },
|
|
12190
|
+
{ spec: { kind: "wheel", mods: { shift: true } }, opts: { params: { swapAxis: true } } }
|
|
12191
|
+
],
|
|
12192
|
+
requires: ["view"],
|
|
12193
|
+
invoker: {
|
|
12194
|
+
timing: "immediate",
|
|
12195
|
+
run(deps, params) {
|
|
12196
|
+
const view = deps.view;
|
|
12197
|
+
if (!view) return;
|
|
12198
|
+
const axis = params?.axis ?? "both";
|
|
12199
|
+
const deltaX = params?.deltaX ?? 0;
|
|
12200
|
+
const deltaY = params?.deltaY ?? 0;
|
|
12201
|
+
const current = view.get();
|
|
12202
|
+
const swap = params?.swapAxis === true;
|
|
12203
|
+
const dx = swap ? (deltaX !== 0 ? deltaX : deltaY) / current.scale.x : deltaX / current.scale.x;
|
|
12204
|
+
const dy = swap ? 0 : deltaY / current.scale.y;
|
|
12205
|
+
view.set({
|
|
12206
|
+
...current,
|
|
12207
|
+
x: current.x + (axis === "y" ? 0 : dx),
|
|
12208
|
+
y: current.y + (axis === "x" ? 0 : dy)
|
|
12209
|
+
});
|
|
12210
|
+
}
|
|
12211
|
+
},
|
|
12212
|
+
enabled: () => true
|
|
12213
|
+
};
|
|
12214
|
+
function makeViewportWheelPanAction(opts = {}) {
|
|
12215
|
+
const axis = opts.axis ?? "both";
|
|
12216
|
+
return {
|
|
12217
|
+
...viewportWheelPanAction,
|
|
12218
|
+
defaultBinding: [
|
|
12219
|
+
{ spec: { kind: "wheel" }, opts: { params: { axis } } },
|
|
12220
|
+
{ spec: { kind: "wheel", mods: { shift: true } }, opts: { params: { swapAxis: true, axis } } }
|
|
12221
|
+
]
|
|
12222
|
+
};
|
|
12223
|
+
}
|
|
11460
12224
|
function bodyPredicate(fn) {
|
|
11461
12225
|
return Object.assign(fn, { readsAffordance: false });
|
|
11462
12226
|
}
|
|
@@ -15627,7 +16391,7 @@ function createDispatcher(opts) {
|
|
|
15627
16391
|
}
|
|
15628
16392
|
function inFlightCursor() {
|
|
15629
16393
|
for (const action of inFlightActions.values()) {
|
|
15630
|
-
const cursor = action.activeCursor ?? action.cursor;
|
|
16394
|
+
const cursor = resolveCursor(action.activeCursor ?? action.cursor);
|
|
15631
16395
|
if (cursor) return cursor;
|
|
15632
16396
|
}
|
|
15633
16397
|
return null;
|
|
@@ -15849,7 +16613,7 @@ function computeMultiTouchGeometry(positions) {
|
|
|
15849
16613
|
return { centroid, spread };
|
|
15850
16614
|
}
|
|
15851
16615
|
function useGestureDispatcher(opts) {
|
|
15852
|
-
const { canvasRef, actions, toolsById, enabled = true, keyboard = true, affordanceAt, classifyTarget, dispatcher: dispatcherOpt, clientToWorld: clientToWorld2, requestRedraw, getRuleCtx, onDoubleClick, views } = opts;
|
|
16616
|
+
const { canvasRef, actions, toolsById, enabled = true, keyboard = true, affordanceAt, classifyTarget, dispatcher: dispatcherOpt, clientToWorld: clientToWorld2, requestRedraw, paintedCursor, getRuleCtx, onDoubleClick, views } = opts;
|
|
15853
16617
|
const onDoubleClickRef = useRef(onDoubleClick);
|
|
15854
16618
|
onDoubleClickRef.current = onDoubleClick;
|
|
15855
16619
|
const activeTool = useActiveToolContext();
|
|
@@ -15898,6 +16662,8 @@ function useGestureDispatcher(opts) {
|
|
|
15898
16662
|
];
|
|
15899
16663
|
const requestRedrawRef = useRef(requestRedraw);
|
|
15900
16664
|
requestRedrawRef.current = requestRedraw;
|
|
16665
|
+
const paintedCursorRef = useRef(paintedCursor);
|
|
16666
|
+
paintedCursorRef.current = paintedCursor;
|
|
15901
16667
|
const lastClickRef = useRef(null);
|
|
15902
16668
|
const prevActiveRef = useRef(activeTool.active);
|
|
15903
16669
|
useEffect(() => {
|
|
@@ -15958,6 +16724,7 @@ function useGestureDispatcher(opts) {
|
|
|
15958
16724
|
};
|
|
15959
16725
|
const heldKeys = /* @__PURE__ */ new Set();
|
|
15960
16726
|
const activePointers = /* @__PURE__ */ new Set();
|
|
16727
|
+
const buttonsReportedFor = /* @__PURE__ */ new Set();
|
|
15961
16728
|
const pointerPositions = /* @__PURE__ */ new Map();
|
|
15962
16729
|
let multiTouchStart = null;
|
|
15963
16730
|
const TAP_THRESHOLD_PX = 8;
|
|
@@ -16100,8 +16867,10 @@ function useGestureDispatcher(opts) {
|
|
|
16100
16867
|
};
|
|
16101
16868
|
const onPointerDown = (e) => {
|
|
16102
16869
|
if ((e.button ?? 0) !== 0) return;
|
|
16870
|
+
if (activePointers.has(e.pointerId)) onPointerUp(e);
|
|
16103
16871
|
routeDown(e.pointerId, e.clientX, e.clientY);
|
|
16104
16872
|
activePointers.add(e.pointerId);
|
|
16873
|
+
if (reportsButtons(e)) buttonsReportedFor.add(e.pointerId);
|
|
16105
16874
|
pointerPositions.set(e.pointerId, { x: e.clientX, y: e.clientY });
|
|
16106
16875
|
try {
|
|
16107
16876
|
canvas?.setPointerCapture?.(e.pointerId);
|
|
@@ -16180,6 +16949,10 @@ function useGestureDispatcher(opts) {
|
|
|
16180
16949
|
}
|
|
16181
16950
|
};
|
|
16182
16951
|
const onPointerMove = (e) => {
|
|
16952
|
+
if (activePointers.has(e.pointerId) && buttonsReportedFor.has(e.pointerId) && isMissedRelease(e)) {
|
|
16953
|
+
onPointerUp(e);
|
|
16954
|
+
return;
|
|
16955
|
+
}
|
|
16183
16956
|
routeAt(e.pointerId, e.clientX, e.clientY);
|
|
16184
16957
|
if (activePointers.has(e.pointerId)) {
|
|
16185
16958
|
pointerPositions.set(e.pointerId, { x: e.clientX, y: e.clientY });
|
|
@@ -16237,20 +17010,39 @@ function useGestureDispatcher(opts) {
|
|
|
16237
17010
|
let lastHover = null;
|
|
16238
17011
|
let cursorOverridden = false;
|
|
16239
17012
|
const clearHoverCursor = () => {
|
|
17013
|
+
paintedCursorRef.current?.()?.setOverride(null);
|
|
16240
17014
|
if (cursorOverridden && canvas) {
|
|
16241
17015
|
canvas.style.cursor = "";
|
|
16242
17016
|
cursorOverridden = false;
|
|
16243
17017
|
}
|
|
16244
17018
|
};
|
|
16245
|
-
const applyHoverCursor = (
|
|
16246
|
-
|
|
16247
|
-
|
|
16248
|
-
|
|
16249
|
-
|
|
17019
|
+
const applyHoverCursor = (spec) => {
|
|
17020
|
+
const tier = spec === null ? null : resolveCursorTier(spec);
|
|
17021
|
+
if (!tier || !canvas) {
|
|
17022
|
+
clearHoverCursor();
|
|
17023
|
+
return;
|
|
17024
|
+
}
|
|
17025
|
+
const painted = tier.kind === "painted" ? tier : null;
|
|
17026
|
+
paintedCursorRef.current?.()?.setOverride(painted);
|
|
17027
|
+
const cursor = tier.kind === "css" ? tier.css : "none";
|
|
17028
|
+
if (!cursor) {
|
|
16250
17029
|
clearHoverCursor();
|
|
17030
|
+
return;
|
|
16251
17031
|
}
|
|
17032
|
+
canvas.style.cursor = cursor;
|
|
17033
|
+
cursorOverridden = true;
|
|
16252
17034
|
};
|
|
17035
|
+
function pushPaintedPointer() {
|
|
17036
|
+
const painted = paintedCursorRef.current?.();
|
|
17037
|
+
if (!painted?.active() || !canvas || !lastHover) return;
|
|
17038
|
+
const r = canvas.getBoundingClientRect();
|
|
17039
|
+
painted.setPointer(lastHover.clientX - r.left, lastHover.clientY - r.top);
|
|
17040
|
+
}
|
|
16253
17041
|
function refreshHoverCursor() {
|
|
17042
|
+
resolveHoverCursor();
|
|
17043
|
+
pushPaintedPointer();
|
|
17044
|
+
}
|
|
17045
|
+
function resolveHoverCursor() {
|
|
16254
17046
|
if (!canvas || !lastHover) return;
|
|
16255
17047
|
if (activePointers.size > 0 || dispatcherNow().inFlight().size > 0) {
|
|
16256
17048
|
applyHoverCursor(dispatcherNow().inFlightCursor());
|
|
@@ -16302,6 +17094,7 @@ function useGestureDispatcher(opts) {
|
|
|
16302
17094
|
};
|
|
16303
17095
|
const onHoverPointerLeave = () => {
|
|
16304
17096
|
lastHover = null;
|
|
17097
|
+
paintedCursorRef.current?.()?.clearPointer();
|
|
16305
17098
|
clearHoverCursor();
|
|
16306
17099
|
};
|
|
16307
17100
|
const onPointerUp = (e) => {
|
|
@@ -16309,6 +17102,7 @@ function useGestureDispatcher(opts) {
|
|
|
16309
17102
|
cancelLongPress(e.pointerId);
|
|
16310
17103
|
const prevSize = activePointers.size;
|
|
16311
17104
|
activePointers.delete(e.pointerId);
|
|
17105
|
+
buttonsReportedFor.delete(e.pointerId);
|
|
16312
17106
|
pointerPositions.delete(e.pointerId);
|
|
16313
17107
|
const staysUnderThreshold = bufferedDown.delete(e.pointerId);
|
|
16314
17108
|
if (prevSize >= 2 && activePointers.size < 2) {
|
|
@@ -16416,6 +17210,7 @@ function useGestureDispatcher(opts) {
|
|
|
16416
17210
|
routeAt(e.pointerId, e.clientX, e.clientY);
|
|
16417
17211
|
cancelLongPress(e.pointerId);
|
|
16418
17212
|
activePointers.delete(e.pointerId);
|
|
17213
|
+
buttonsReportedFor.delete(e.pointerId);
|
|
16419
17214
|
pointerPositions.delete(e.pointerId);
|
|
16420
17215
|
lastPointerDown.delete(e.pointerId);
|
|
16421
17216
|
bufferedDown.delete(e.pointerId);
|
|
@@ -16431,6 +17226,11 @@ function useGestureDispatcher(opts) {
|
|
|
16431
17226
|
dispatch2(ev);
|
|
16432
17227
|
routeRelease(e.pointerId);
|
|
16433
17228
|
};
|
|
17229
|
+
const onLostCapture = (e) => {
|
|
17230
|
+
const pe = e;
|
|
17231
|
+
if (!activePointers.has(pe.pointerId)) return;
|
|
17232
|
+
onPointerCancel(pe);
|
|
17233
|
+
};
|
|
16434
17234
|
const onContextMenu = (e) => {
|
|
16435
17235
|
e.preventDefault();
|
|
16436
17236
|
routeAt(null, e.clientX, e.clientY);
|
|
@@ -16520,6 +17320,7 @@ function useGestureDispatcher(opts) {
|
|
|
16520
17320
|
canvas?.addEventListener("pointermove", onPointerMove);
|
|
16521
17321
|
canvas?.addEventListener("pointerup", onPointerUp);
|
|
16522
17322
|
canvas?.addEventListener("pointercancel", onPointerCancel);
|
|
17323
|
+
canvas?.addEventListener(LOST_CAPTURE_EVENT, onLostCapture);
|
|
16523
17324
|
canvas?.addEventListener("contextmenu", onContextMenu);
|
|
16524
17325
|
canvas?.addEventListener("dragenter", onDragOver);
|
|
16525
17326
|
canvas?.addEventListener("dragover", onDragOver);
|
|
@@ -16540,6 +17341,7 @@ function useGestureDispatcher(opts) {
|
|
|
16540
17341
|
canvas?.removeEventListener("pointermove", onPointerMove);
|
|
16541
17342
|
canvas?.removeEventListener("pointerup", onPointerUp);
|
|
16542
17343
|
canvas?.removeEventListener("pointercancel", onPointerCancel);
|
|
17344
|
+
canvas?.removeEventListener(LOST_CAPTURE_EVENT, onLostCapture);
|
|
16543
17345
|
canvas?.removeEventListener("contextmenu", onContextMenu);
|
|
16544
17346
|
canvas?.removeEventListener("dragenter", onDragOver);
|
|
16545
17347
|
canvas?.removeEventListener("dragover", onDragOver);
|
|
@@ -16554,6 +17356,132 @@ function useGestureDispatcher(opts) {
|
|
|
16554
17356
|
};
|
|
16555
17357
|
}, [enabled, keyboard, canvasRef]);
|
|
16556
17358
|
}
|
|
17359
|
+
var SPRING_DAMPING = 0.5;
|
|
17360
|
+
function useDecayLoop() {
|
|
17361
|
+
const stateRef = useRef(null);
|
|
17362
|
+
const frameLoop = useVisibleRaf(
|
|
17363
|
+
(now) => {
|
|
17364
|
+
tick(now);
|
|
17365
|
+
},
|
|
17366
|
+
{
|
|
17367
|
+
// Coasting does not continue while suspended: dropping `lastTime` makes
|
|
17368
|
+
// the resuming frame seed a fresh interval instead of applying an hour of
|
|
17369
|
+
// friction at once, which would end the decay before it was seen.
|
|
17370
|
+
onResume: useCallback(() => {
|
|
17371
|
+
if (stateRef.current) stateRef.current.lastTime = null;
|
|
17372
|
+
}, [])
|
|
17373
|
+
}
|
|
17374
|
+
);
|
|
17375
|
+
const cancel = useCallback(() => {
|
|
17376
|
+
frameLoop.cancel();
|
|
17377
|
+
stateRef.current = null;
|
|
17378
|
+
}, [frameLoop]);
|
|
17379
|
+
const tick = useCallback((now) => {
|
|
17380
|
+
const s = stateRef.current;
|
|
17381
|
+
if (!s) return;
|
|
17382
|
+
if (s.lastTime === null) {
|
|
17383
|
+
s.lastTime = now;
|
|
17384
|
+
frameLoop.request();
|
|
17385
|
+
return;
|
|
17386
|
+
}
|
|
17387
|
+
const dt = Math.min(now - s.lastTime, 64);
|
|
17388
|
+
s.lastTime = now;
|
|
17389
|
+
const f = Math.pow(s.friction, dt / 16.67);
|
|
17390
|
+
s.vx *= f;
|
|
17391
|
+
s.vy *= f;
|
|
17392
|
+
const speed = Math.sqrt(s.vx * s.vx + s.vy * s.vy);
|
|
17393
|
+
if (speed < s.minSpeed) {
|
|
17394
|
+
stateRef.current = null;
|
|
17395
|
+
frameLoop.cancel();
|
|
17396
|
+
s.onEnd?.();
|
|
17397
|
+
return;
|
|
17398
|
+
}
|
|
17399
|
+
let dx = s.vx * dt;
|
|
17400
|
+
let dy = s.vy * dt;
|
|
17401
|
+
if (s.viewBounds && s.boundary) {
|
|
17402
|
+
const { minX, maxX, minY, maxY } = s.viewBounds;
|
|
17403
|
+
const newX = s.posX + dx;
|
|
17404
|
+
const newY = s.posY + dy;
|
|
17405
|
+
if (s.boundary === "stop") {
|
|
17406
|
+
if (minX !== void 0 && newX < minX) {
|
|
17407
|
+
dx = minX - s.posX;
|
|
17408
|
+
s.vx = 0;
|
|
17409
|
+
} else if (maxX !== void 0 && newX > maxX) {
|
|
17410
|
+
dx = maxX - s.posX;
|
|
17411
|
+
s.vx = 0;
|
|
17412
|
+
}
|
|
17413
|
+
if (minY !== void 0 && newY < minY) {
|
|
17414
|
+
dy = minY - s.posY;
|
|
17415
|
+
s.vy = 0;
|
|
17416
|
+
} else if (maxY !== void 0 && newY > maxY) {
|
|
17417
|
+
dy = maxY - s.posY;
|
|
17418
|
+
s.vy = 0;
|
|
17419
|
+
}
|
|
17420
|
+
} else if (s.boundary === "spring") {
|
|
17421
|
+
if (minX !== void 0 && newX < minX) {
|
|
17422
|
+
dx = minX - s.posX;
|
|
17423
|
+
s.vx = Math.abs(s.vx) * SPRING_DAMPING;
|
|
17424
|
+
} else if (maxX !== void 0 && newX > maxX) {
|
|
17425
|
+
dx = maxX - s.posX;
|
|
17426
|
+
s.vx = -Math.abs(s.vx) * SPRING_DAMPING;
|
|
17427
|
+
}
|
|
17428
|
+
if (minY !== void 0 && newY < minY) {
|
|
17429
|
+
dy = minY - s.posY;
|
|
17430
|
+
s.vy = Math.abs(s.vy) * SPRING_DAMPING;
|
|
17431
|
+
} else if (maxY !== void 0 && newY > maxY) {
|
|
17432
|
+
dy = maxY - s.posY;
|
|
17433
|
+
s.vy = -Math.abs(s.vy) * SPRING_DAMPING;
|
|
17434
|
+
}
|
|
17435
|
+
} else {
|
|
17436
|
+
if (minX !== void 0 && newX < minX) {
|
|
17437
|
+
dx = minX - s.posX;
|
|
17438
|
+
s.vx = Math.abs(s.vx);
|
|
17439
|
+
} else if (maxX !== void 0 && newX > maxX) {
|
|
17440
|
+
dx = maxX - s.posX;
|
|
17441
|
+
s.vx = -Math.abs(s.vx);
|
|
17442
|
+
}
|
|
17443
|
+
if (minY !== void 0 && newY < minY) {
|
|
17444
|
+
dy = minY - s.posY;
|
|
17445
|
+
s.vy = Math.abs(s.vy);
|
|
17446
|
+
} else if (maxY !== void 0 && newY > maxY) {
|
|
17447
|
+
dy = maxY - s.posY;
|
|
17448
|
+
s.vy = -Math.abs(s.vy);
|
|
17449
|
+
}
|
|
17450
|
+
}
|
|
17451
|
+
s.posX += dx;
|
|
17452
|
+
s.posY += dy;
|
|
17453
|
+
}
|
|
17454
|
+
s.onTick(dx, dy);
|
|
17455
|
+
frameLoop.request();
|
|
17456
|
+
}, [frameLoop]);
|
|
17457
|
+
const start = useCallback((config) => {
|
|
17458
|
+
cancel();
|
|
17459
|
+
const { velocity, friction = 0.92, minSpeed = 0.01, viewBounds, boundary, initialPosition, onTick, onEnd } = config;
|
|
17460
|
+
const speed = Math.sqrt(velocity.vx ** 2 + velocity.vy ** 2);
|
|
17461
|
+
if (speed < minSpeed) {
|
|
17462
|
+
onEnd?.();
|
|
17463
|
+
return;
|
|
17464
|
+
}
|
|
17465
|
+
stateRef.current = {
|
|
17466
|
+
vx: velocity.vx,
|
|
17467
|
+
vy: velocity.vy,
|
|
17468
|
+
friction,
|
|
17469
|
+
minSpeed,
|
|
17470
|
+
lastTime: null,
|
|
17471
|
+
posX: initialPosition?.x ?? 0,
|
|
17472
|
+
posY: initialPosition?.y ?? 0,
|
|
17473
|
+
viewBounds,
|
|
17474
|
+
boundary,
|
|
17475
|
+
onTick,
|
|
17476
|
+
onEnd
|
|
17477
|
+
};
|
|
17478
|
+
frameLoop.request();
|
|
17479
|
+
}, [cancel, frameLoop]);
|
|
17480
|
+
useEffect(() => () => {
|
|
17481
|
+
cancel();
|
|
17482
|
+
}, [cancel]);
|
|
17483
|
+
return { start, cancel };
|
|
17484
|
+
}
|
|
16557
17485
|
function dist(a, b) {
|
|
16558
17486
|
return Math.hypot(b.x - a.x, b.y - a.y);
|
|
16559
17487
|
}
|
|
@@ -17811,7 +18739,7 @@ function validateId(id, kind) {
|
|
|
17811
18739
|
}
|
|
17812
18740
|
function defineTool(def) {
|
|
17813
18741
|
validateId(def.id, "tool");
|
|
17814
|
-
const
|
|
18742
|
+
const resolveCursor3 = (ctx) => {
|
|
17815
18743
|
if (def.cursor == null) return "";
|
|
17816
18744
|
return typeof def.cursor === "function" ? def.cursor(ctx) : def.cursor;
|
|
17817
18745
|
};
|
|
@@ -17829,7 +18757,7 @@ function defineTool(def) {
|
|
|
17829
18757
|
onActivate: def.onActivate,
|
|
17830
18758
|
onDeactivate: def.onDeactivate,
|
|
17831
18759
|
initScratch: def.initScratch ?? (() => null),
|
|
17832
|
-
cursor:
|
|
18760
|
+
cursor: resolveCursor3,
|
|
17833
18761
|
bindings: def.bindings,
|
|
17834
18762
|
overlay: def.overlay,
|
|
17835
18763
|
overlayPosition: def.overlayPosition
|
|
@@ -18829,10 +19757,10 @@ function findShapeInk(node, pose, ctx) {
|
|
|
18829
19757
|
function shapeCoversPoint(node, pose, x, y, opts = {}) {
|
|
18830
19758
|
const sil = findShapeSilhouette(node, pose, { derivedPath: opts.derivedPath });
|
|
18831
19759
|
if (sil === null) return true;
|
|
18832
|
-
const
|
|
19760
|
+
const ink2 = findShapeInk(node, pose, { scale: opts.scale }) ?? DEFAULT_INK;
|
|
18833
19761
|
const inside = pathContainsPoint(sil, x, y);
|
|
18834
|
-
if (
|
|
18835
|
-
const reach = (inside ?
|
|
19762
|
+
if (ink2.filled && inside) return true;
|
|
19763
|
+
const reach = (inside ? ink2.inset : ink2.outset) + (opts.tolerance ?? 0);
|
|
18836
19764
|
return reach > 0 && strokeHitTest(sil, x, y, reach);
|
|
18837
19765
|
}
|
|
18838
19766
|
var TEXT_PAINTER = {
|
|
@@ -19731,6 +20659,9 @@ function transformOf(state, targetId) {
|
|
|
19731
20659
|
identity: false
|
|
19732
20660
|
};
|
|
19733
20661
|
}
|
|
20662
|
+
function angleOf(xf) {
|
|
20663
|
+
return xf.identity ? 0 : Math.atan2(xf.sin, xf.cos);
|
|
20664
|
+
}
|
|
19734
20665
|
function localToWorld(xf, lx, ly) {
|
|
19735
20666
|
if (xf.identity) return { x: lx, y: ly };
|
|
19736
20667
|
const dx = lx - xf.cx;
|
|
@@ -20030,11 +20961,7 @@ var DEFAULT_PAINT = {
|
|
|
20030
20961
|
insetPx: 10
|
|
20031
20962
|
};
|
|
20032
20963
|
function createRotationAffordance(opts = {}) {
|
|
20033
|
-
const {
|
|
20034
|
-
bandPx = 24,
|
|
20035
|
-
paint = DEFAULT_PAINT,
|
|
20036
|
-
cursor = "grab"
|
|
20037
|
-
} = opts;
|
|
20964
|
+
const { bandPx = 24, paint = DEFAULT_PAINT, cursor } = opts;
|
|
20038
20965
|
const annulusPaint = (() => {
|
|
20039
20966
|
if (!paint) return null;
|
|
20040
20967
|
if ("paint" in paint) {
|
|
@@ -20072,7 +20999,14 @@ function createRotationAffordance(opts = {}) {
|
|
|
20072
20999
|
},
|
|
20073
21000
|
...annulusPaint ? { paint: annulusPaint } : {},
|
|
20074
21001
|
hitKind: "rotate-handle",
|
|
20075
|
-
|
|
21002
|
+
// Turned with the target, so the arc follows the selection it rotates.
|
|
21003
|
+
// Resolved per region rather than defaulted in the option list because
|
|
21004
|
+
// the angle is only known once a target is picked.
|
|
21005
|
+
cursor: cursor ?? {
|
|
21006
|
+
glyph: "rotate",
|
|
21007
|
+
angle: angleOf(transformOf(state, target.id)),
|
|
21008
|
+
fallback: "grab"
|
|
21009
|
+
},
|
|
20076
21010
|
bind: () => ({
|
|
20077
21011
|
initialScratch: {
|
|
20078
21012
|
targetId: target.id,
|
|
@@ -20169,7 +21103,9 @@ function useRotateTool(adapter, options) {
|
|
|
20169
21103
|
[overlay]
|
|
20170
21104
|
);
|
|
20171
21105
|
}
|
|
20172
|
-
function useHandTool(
|
|
21106
|
+
function useHandTool(opts = {}) {
|
|
21107
|
+
const optsRef = useRef(opts);
|
|
21108
|
+
optsRef.current = opts;
|
|
20173
21109
|
return useMemo(
|
|
20174
21110
|
() => Object.assign(defineViewportTool({
|
|
20175
21111
|
id: "hand",
|
|
@@ -20187,7 +21123,16 @@ function useHandTool(_opts = {}) {
|
|
|
20187
21123
|
// viewportDragPanAction, which also owns the grabbing cursor
|
|
20188
21124
|
// (`Action.activeCursor`) the tool used to declare as an `engaged`
|
|
20189
21125
|
// phase entry.
|
|
20190
|
-
bindings: [{
|
|
21126
|
+
bindings: [{
|
|
21127
|
+
spec: { kind: "drag" },
|
|
21128
|
+
actionId: "viewport.dragPan",
|
|
21129
|
+
opts: {
|
|
21130
|
+
params: () => ({
|
|
21131
|
+
axis: optsRef.current.axis ?? "both",
|
|
21132
|
+
inertia: optsRef.current.inertia
|
|
21133
|
+
})
|
|
21134
|
+
}
|
|
21135
|
+
}]
|
|
20191
21136
|
}),
|
|
20192
21137
|
[]
|
|
20193
21138
|
);
|
|
@@ -20551,7 +21496,7 @@ function useRectTool() {
|
|
|
20551
21496
|
id: "rect",
|
|
20552
21497
|
capabilities: ["creates-shapes"],
|
|
20553
21498
|
hookName: "useRectTool",
|
|
20554
|
-
cursor: "crosshair",
|
|
21499
|
+
cursor: cursorFor("crosshairRect", { fallback: "crosshair" }),
|
|
20555
21500
|
presentation: {
|
|
20556
21501
|
label: "Rectangle",
|
|
20557
21502
|
icon: createElement(RectIcon),
|
|
@@ -20577,7 +21522,7 @@ function useEllipseTool() {
|
|
|
20577
21522
|
id: "ellipse",
|
|
20578
21523
|
capabilities: ["creates-shapes"],
|
|
20579
21524
|
hookName: "useEllipseTool",
|
|
20580
|
-
cursor: "crosshair",
|
|
21525
|
+
cursor: cursorFor("crosshairEllipse", { fallback: "crosshair" }),
|
|
20581
21526
|
presentation: {
|
|
20582
21527
|
label: "Ellipse",
|
|
20583
21528
|
group: "shape",
|
|
@@ -20600,7 +21545,7 @@ function useLineTool() {
|
|
|
20600
21545
|
id: "line",
|
|
20601
21546
|
capabilities: ["creates-shapes"],
|
|
20602
21547
|
hookName: "useLineTool",
|
|
20603
|
-
cursor: "crosshair",
|
|
21548
|
+
cursor: cursorFor("crosshairLine", { fallback: "crosshair" }),
|
|
20604
21549
|
presentation: {
|
|
20605
21550
|
label: "Line",
|
|
20606
21551
|
group: "shape",
|
|
@@ -20711,7 +21656,7 @@ function usePolygonTool(options = {}) {
|
|
|
20711
21656
|
id: "polygon",
|
|
20712
21657
|
capabilities: ["creates-shapes"],
|
|
20713
21658
|
hookName: "usePolygonTool",
|
|
20714
|
-
cursor: "crosshair",
|
|
21659
|
+
cursor: cursorFor("crosshairPolygon", { fallback: "crosshair" }),
|
|
20715
21660
|
// Registered by <ToolActionsMounter>, inside the ActionsProvider —
|
|
20716
21661
|
// see `ToolDef.actions` for why the hook can't register it itself.
|
|
20717
21662
|
actions: [adjustSidesAction],
|
|
@@ -20811,7 +21756,7 @@ function useStarTool(options = {}) {
|
|
|
20811
21756
|
id: "star",
|
|
20812
21757
|
capabilities: ["creates-shapes"],
|
|
20813
21758
|
hookName: "useStarTool",
|
|
20814
|
-
cursor: "crosshair",
|
|
21759
|
+
cursor: cursorFor("crosshairStar", { fallback: "crosshair" }),
|
|
20815
21760
|
// Registered by <ToolActionsMounter>, inside the ActionsProvider —
|
|
20816
21761
|
// see `ToolDef.actions` for why the hook can't register it itself.
|
|
20817
21762
|
actions: [adjustPointsAction],
|
|
@@ -21448,6 +22393,20 @@ function projectBounds(b, view) {
|
|
|
21448
22393
|
const [sx, sy] = worldToScreen(b.x, b.y, t);
|
|
21449
22394
|
return { ...b, x: sx, y: sy, width: b.width * view.scale.x, height: b.height * view.scale.y };
|
|
21450
22395
|
}
|
|
22396
|
+
function leavesOf(id, getChildren, isContainer) {
|
|
22397
|
+
if (!isContainer(id)) return [id];
|
|
22398
|
+
const out = [];
|
|
22399
|
+
const visit = (nid) => {
|
|
22400
|
+
const kids = getChildren(nid);
|
|
22401
|
+
if (kids.length === 0) {
|
|
22402
|
+
if (!isContainer(nid)) out.push(nid);
|
|
22403
|
+
return;
|
|
22404
|
+
}
|
|
22405
|
+
for (const k of kids) visit(k);
|
|
22406
|
+
};
|
|
22407
|
+
visit(id);
|
|
22408
|
+
return out;
|
|
22409
|
+
}
|
|
21451
22410
|
function makeContainerAwareBoundsResolver(getPose, getBounds, getChildren, isContainer) {
|
|
21452
22411
|
if (getChildren === void 0 || isContainer === void 0) {
|
|
21453
22412
|
return (id) => {
|
|
@@ -21455,26 +22414,12 @@ function makeContainerAwareBoundsResolver(getPose, getBounds, getChildren, isCon
|
|
|
21455
22414
|
return p === null ? null : getBounds(p);
|
|
21456
22415
|
};
|
|
21457
22416
|
}
|
|
21458
|
-
const leavesOf = (id) => {
|
|
21459
|
-
if (!isContainer(id)) return [id];
|
|
21460
|
-
const out = [];
|
|
21461
|
-
const visit = (nid) => {
|
|
21462
|
-
const kids = getChildren(nid);
|
|
21463
|
-
if (kids.length === 0) {
|
|
21464
|
-
if (!isContainer(nid)) out.push(nid);
|
|
21465
|
-
return;
|
|
21466
|
-
}
|
|
21467
|
-
for (const k of kids) visit(k);
|
|
21468
|
-
};
|
|
21469
|
-
visit(id);
|
|
21470
|
-
return out;
|
|
21471
|
-
};
|
|
21472
22417
|
return (id) => {
|
|
21473
22418
|
if (!isContainer(id)) {
|
|
21474
22419
|
const p = getPose(id);
|
|
21475
22420
|
return p === null ? null : getBounds(p);
|
|
21476
22421
|
}
|
|
21477
|
-
const leaves = leavesOf(id);
|
|
22422
|
+
const leaves = leavesOf(id, getChildren, isContainer);
|
|
21478
22423
|
if (leaves.length === 0) return null;
|
|
21479
22424
|
const leafBounds = [];
|
|
21480
22425
|
for (const leafId of leaves) {
|
|
@@ -21848,6 +22793,111 @@ function buildSceneTree(adapter, drawOne, view, forLayer, derivedPathOf) {
|
|
|
21848
22793
|
}
|
|
21849
22794
|
return out;
|
|
21850
22795
|
}
|
|
22796
|
+
function same(a, b) {
|
|
22797
|
+
if (a === b) return true;
|
|
22798
|
+
if (!a || !b) return false;
|
|
22799
|
+
return a.glyph === b.glyph && a.angle === b.angle && a.size === b.size && a.worldRadius === b.worldRadius;
|
|
22800
|
+
}
|
|
22801
|
+
function createPaintedCursorState() {
|
|
22802
|
+
let base = null;
|
|
22803
|
+
let override = null;
|
|
22804
|
+
let at = null;
|
|
22805
|
+
const subs = /* @__PURE__ */ new Set();
|
|
22806
|
+
const notify2 = () => {
|
|
22807
|
+
for (const fn of subs) fn();
|
|
22808
|
+
};
|
|
22809
|
+
return {
|
|
22810
|
+
setBase(cursor) {
|
|
22811
|
+
if (same(base, cursor)) return;
|
|
22812
|
+
base = cursor;
|
|
22813
|
+
notify2();
|
|
22814
|
+
},
|
|
22815
|
+
setOverride(cursor) {
|
|
22816
|
+
if (same(override, cursor)) return;
|
|
22817
|
+
override = cursor;
|
|
22818
|
+
notify2();
|
|
22819
|
+
},
|
|
22820
|
+
setPointer(x, y) {
|
|
22821
|
+
if (at && at.x === x && at.y === y) return;
|
|
22822
|
+
at = { x, y };
|
|
22823
|
+
if (override ?? base) notify2();
|
|
22824
|
+
},
|
|
22825
|
+
clearPointer() {
|
|
22826
|
+
if (at === null) return;
|
|
22827
|
+
at = null;
|
|
22828
|
+
notify2();
|
|
22829
|
+
},
|
|
22830
|
+
active() {
|
|
22831
|
+
return (override ?? base) !== null;
|
|
22832
|
+
},
|
|
22833
|
+
current() {
|
|
22834
|
+
const cursor = override ?? base;
|
|
22835
|
+
if (!cursor || !at) return null;
|
|
22836
|
+
return { cursor, at };
|
|
22837
|
+
},
|
|
22838
|
+
subscribe(fn) {
|
|
22839
|
+
subs.add(fn);
|
|
22840
|
+
return () => {
|
|
22841
|
+
subs.delete(fn);
|
|
22842
|
+
};
|
|
22843
|
+
}
|
|
22844
|
+
};
|
|
22845
|
+
}
|
|
22846
|
+
var PAINTED_CURSOR_LAYER_ID = "painted-cursor";
|
|
22847
|
+
var pathCache = /* @__PURE__ */ new Map();
|
|
22848
|
+
function pathFor(d) {
|
|
22849
|
+
let p = pathCache.get(d);
|
|
22850
|
+
if (p === void 0) {
|
|
22851
|
+
p = pathFromD(d);
|
|
22852
|
+
pathCache.set(d, p);
|
|
22853
|
+
}
|
|
22854
|
+
return p;
|
|
22855
|
+
}
|
|
22856
|
+
function commandFor2(op) {
|
|
22857
|
+
return {
|
|
22858
|
+
kind: "path",
|
|
22859
|
+
path: pathFor(op.d),
|
|
22860
|
+
...op.fill !== void 0 ? { fill: { color: op.fill } } : {},
|
|
22861
|
+
...op.stroke !== void 0 ? {
|
|
22862
|
+
stroke: {
|
|
22863
|
+
paint: { color: op.stroke.color },
|
|
22864
|
+
width: op.stroke.width,
|
|
22865
|
+
cap: "round",
|
|
22866
|
+
join: "round"
|
|
22867
|
+
}
|
|
22868
|
+
} : {}
|
|
22869
|
+
};
|
|
22870
|
+
}
|
|
22871
|
+
function createPaintedCursorLayer(state) {
|
|
22872
|
+
return {
|
|
22873
|
+
id: PAINTED_CURSOR_LAYER_ID,
|
|
22874
|
+
label: "Painted cursor",
|
|
22875
|
+
space: "screen",
|
|
22876
|
+
draw: (_data, view) => {
|
|
22877
|
+
const frame = state.current();
|
|
22878
|
+
if (!frame) return [];
|
|
22879
|
+
const { cursor, at } = frame;
|
|
22880
|
+
const glyph = GLYPHS[cursor.glyph];
|
|
22881
|
+
if (!glyph) return [];
|
|
22882
|
+
const scale2 = (view.scale.x + view.scale.y) / 2;
|
|
22883
|
+
const worldSized = cursor.worldRadius !== void 0;
|
|
22884
|
+
const size = worldSized ? cursorWorldSize(glyph, cursor.worldRadius, scale2) : cursor.size ?? 24;
|
|
22885
|
+
if (!(size > 0) || !Number.isFinite(size)) return [];
|
|
22886
|
+
const ops = cursorPaintOps(
|
|
22887
|
+
glyph,
|
|
22888
|
+
worldSized ? { lineWidthScale: chromeLineWidthScale(glyph, size) } : {}
|
|
22889
|
+
);
|
|
22890
|
+
const [a, b, c, d, e, f] = cursorPaintMatrix(glyph, {
|
|
22891
|
+
size,
|
|
22892
|
+
angle: cursor.angle,
|
|
22893
|
+
at
|
|
22894
|
+
});
|
|
22895
|
+
const transform = new Float32Array([a, b, 0, c, d, 0, e, f, 1]);
|
|
22896
|
+
const children = ops.map(commandFor2);
|
|
22897
|
+
return [{ kind: "group", transform, children }];
|
|
22898
|
+
}
|
|
22899
|
+
};
|
|
22900
|
+
}
|
|
21851
22901
|
function mat3ToRenderMatrix(m) {
|
|
21852
22902
|
return new Float32Array([m[0], m[1], 0, m[2], m[3], 0, m[4], m[5], 1]);
|
|
21853
22903
|
}
|
|
@@ -22217,11 +23267,11 @@ function resolveToolsCursor(tools, ctxBase) {
|
|
|
22217
23267
|
const id = tools.hotkeyEngaged ?? tools.active;
|
|
22218
23268
|
const tool = tools.registry[id];
|
|
22219
23269
|
if (!tool?.cursor) return void 0;
|
|
22220
|
-
if (typeof tool.cursor
|
|
23270
|
+
if (typeof tool.cursor !== "function") return resolveCursorTier(tool.cursor);
|
|
22221
23271
|
if (!ctxBase) return void 0;
|
|
22222
23272
|
try {
|
|
22223
23273
|
const base = ctxBase();
|
|
22224
|
-
return tool.cursor({ ...base, scratch: null });
|
|
23274
|
+
return resolveCursorTier(tool.cursor({ ...base, scratch: null }));
|
|
22225
23275
|
} catch {
|
|
22226
23276
|
return void 0;
|
|
22227
23277
|
}
|
|
@@ -22386,6 +23436,14 @@ function CanvasInner(props, ref) {
|
|
|
22386
23436
|
viewSubsRef.current.delete(fn);
|
|
22387
23437
|
};
|
|
22388
23438
|
}, []);
|
|
23439
|
+
const paintedCursor = useMemo(() => createPaintedCursorState(), []);
|
|
23440
|
+
const paintedCursorLayer = useMemo(
|
|
23441
|
+
() => createPaintedCursorLayer(paintedCursor),
|
|
23442
|
+
[paintedCursor]
|
|
23443
|
+
);
|
|
23444
|
+
useEffect(() => paintedCursor.subscribe(() => {
|
|
23445
|
+
requestRedraw();
|
|
23446
|
+
}), [paintedCursor, requestRedraw]);
|
|
22389
23447
|
useImperativeHandle(ref, () => ({
|
|
22390
23448
|
// Named rather than read off `canvasRef` so the handle rebuilds when a
|
|
22391
23449
|
// detached surface's input element arrives, which is a render later.
|
|
@@ -22398,7 +23456,8 @@ function CanvasInner(props, ref) {
|
|
|
22398
23456
|
getView,
|
|
22399
23457
|
setView,
|
|
22400
23458
|
subscribeView,
|
|
22401
|
-
getPaintedVersion
|
|
23459
|
+
getPaintedVersion,
|
|
23460
|
+
paintedCursor
|
|
22402
23461
|
}), [
|
|
22403
23462
|
canvasRef,
|
|
22404
23463
|
ownCanvasRef,
|
|
@@ -22412,7 +23471,8 @@ function CanvasInner(props, ref) {
|
|
|
22412
23471
|
getView,
|
|
22413
23472
|
setView,
|
|
22414
23473
|
subscribeView,
|
|
22415
|
-
getPaintedVersion
|
|
23474
|
+
getPaintedVersion,
|
|
23475
|
+
paintedCursor
|
|
22416
23476
|
]);
|
|
22417
23477
|
const glRendererRef = useRef(null);
|
|
22418
23478
|
const layerCacheRef = useRef(/* @__PURE__ */ new Map());
|
|
@@ -22492,7 +23552,7 @@ function CanvasInner(props, ref) {
|
|
|
22492
23552
|
return {
|
|
22493
23553
|
worldX,
|
|
22494
23554
|
worldY,
|
|
22495
|
-
modifiers: m ? { alt: m.alt, shift: m.shift, meta: m.meta, ctrl: m.ctrl
|
|
23555
|
+
modifiers: m ? { alt: m.alt, shift: m.shift, meta: m.meta, ctrl: m.ctrl } : { alt: false, shift: false, meta: false, ctrl: false },
|
|
22496
23556
|
selection: effectiveSelectionRefForCtx.current,
|
|
22497
23557
|
adapter: effectiveAdapterRefForCtx.current,
|
|
22498
23558
|
applyOps: (ops, label) => {
|
|
@@ -22676,8 +23736,16 @@ function CanvasInner(props, ref) {
|
|
|
22676
23736
|
const layersWithDebug = useMemo(() => {
|
|
22677
23737
|
const withViews = viewRegistry ? [...layers, ...viewRegistry.list().map((r) => r.layer)] : layers;
|
|
22678
23738
|
const base = debugSink && resolvedDebugConfig ? [...withViews, createDebugOverlayLayer({ sink: debugSink, config: resolvedDebugConfig })] : withViews;
|
|
22679
|
-
return [...base, ...extrasRef.current];
|
|
22680
|
-
}, [
|
|
23739
|
+
return [...base, ...extrasRef.current, paintedCursorLayer];
|
|
23740
|
+
}, [
|
|
23741
|
+
layers,
|
|
23742
|
+
debugSink,
|
|
23743
|
+
resolvedDebugConfig,
|
|
23744
|
+
extrasVersion,
|
|
23745
|
+
viewRegistry,
|
|
23746
|
+
viewRegistryVersion,
|
|
23747
|
+
paintedCursorLayer
|
|
23748
|
+
]);
|
|
22681
23749
|
const shaderIdKey = shaders?.map((h) => h.id).join("|") ?? "";
|
|
22682
23750
|
const paintInputsRef = useRef({
|
|
22683
23751
|
layers: layersWithDebug,
|
|
@@ -22799,8 +23867,14 @@ function CanvasInner(props, ref) {
|
|
|
22799
23867
|
if (!renderer) return;
|
|
22800
23868
|
registerShadersOnRenderer(renderer, shaders);
|
|
22801
23869
|
}, [shaderIdKey]);
|
|
22802
|
-
const
|
|
23870
|
+
const toolsCursorTier = tools ? resolveToolsCursor(tools, toolsCtxBase) : void 0;
|
|
23871
|
+
const toolsCursor = toolsCursorTier === void 0 ? void 0 : toolsCursorTier.kind === "css" ? toolsCursorTier.css : "none";
|
|
22803
23872
|
const effectiveStyle = toolsCursor ? { ...style, cursor: toolsCursor } : style;
|
|
23873
|
+
const toolsPainted = toolsCursorTier?.kind === "painted" ? toolsCursorTier : null;
|
|
23874
|
+
const toolsPaintedKey = toolsPainted ? `${toolsPainted.glyph}|${toolsPainted.angle}|${toolsPainted.size}|${toolsPainted.worldRadius}` : "";
|
|
23875
|
+
useEffect(() => {
|
|
23876
|
+
paintedCursor.setBase(toolsPainted);
|
|
23877
|
+
}, [paintedCursor, toolsPaintedKey]);
|
|
22804
23878
|
const layersForMoveRef = useRef(layersWithDebug);
|
|
22805
23879
|
layersForMoveRef.current = layersWithDebug;
|
|
22806
23880
|
useEffect(() => {
|
|
@@ -24120,10 +25194,16 @@ function createCornerResizeAffordance(opts = {}) {
|
|
|
24120
25194
|
hitKind: c.kind,
|
|
24121
25195
|
// Diagonal by fixed-corner parity: a matched-axis anchor (min-min /
|
|
24122
25196
|
// max-max fixed) means the dragged corner sits on the ↘ diagonal;
|
|
24123
|
-
// mixed axes sit on the ↗ diagonal.
|
|
24124
|
-
//
|
|
24125
|
-
//
|
|
24126
|
-
|
|
25197
|
+
// mixed axes sit on the ↗ diagonal. The glyph is horizontal at angle
|
|
25198
|
+
// 0, so the diagonal is a half-quarter-turn either way, plus the
|
|
25199
|
+
// target's own rotation. The keyword is the fallback rather than the
|
|
25200
|
+
// answer: CSS has four of them, which cannot express a target
|
|
25201
|
+
// rotated to anything but a multiple of 45°.
|
|
25202
|
+
cursor: {
|
|
25203
|
+
glyph: "resize",
|
|
25204
|
+
angle: (c.anchor.x === c.anchor.y ? Math.PI / 4 : -Math.PI / 4) + angleOf(xf),
|
|
25205
|
+
fallback: c.anchor.x === c.anchor.y ? "nwse-resize" : "nesw-resize"
|
|
25206
|
+
},
|
|
24127
25207
|
bind: () => ({
|
|
24128
25208
|
initialScratch: {
|
|
24129
25209
|
anchor: c.anchor,
|
|
@@ -26116,10 +27196,10 @@ function boundsOf(coords) {
|
|
|
26116
27196
|
}
|
|
26117
27197
|
return { x: minX, y: minY, width: maxX - minX, height: maxY - minY };
|
|
26118
27198
|
}
|
|
26119
|
-
function useViewDepSource(currentViewRef, onViewChange, recenter, hostSize, animation) {
|
|
26120
|
-
const wiring = useRef({ currentViewRef, onViewChange, recenter, hostSize, animation });
|
|
26121
|
-
wiring.current = { currentViewRef, onViewChange, recenter, hostSize, animation };
|
|
26122
|
-
const shape = `${recenter ? "r" : ""}${hostSize ? "h" : ""}${animation ? "a" : ""}`;
|
|
27199
|
+
function useViewDepSource(currentViewRef, onViewChange, recenter, hostSize, animation, decay) {
|
|
27200
|
+
const wiring = useRef({ currentViewRef, onViewChange, recenter, hostSize, animation, decay });
|
|
27201
|
+
wiring.current = { currentViewRef, onViewChange, recenter, hostSize, animation, decay };
|
|
27202
|
+
const shape = `${recenter ? "r" : ""}${hostSize ? "h" : ""}${animation ? "a" : ""}${decay ? "d" : ""}`;
|
|
26123
27203
|
const shapeRef = useRef(null);
|
|
26124
27204
|
const viewApiRef = useRef(null);
|
|
26125
27205
|
if (viewApiRef.current === null || shapeRef.current !== shape) {
|
|
@@ -26138,6 +27218,10 @@ function useViewDepSource(currentViewRef, onViewChange, recenter, hostSize, anim
|
|
|
26138
27218
|
animate: (to, opts) => wiring.current.animation.animate(to, opts),
|
|
26139
27219
|
stopAnimation: () => wiring.current.animation.stop(),
|
|
26140
27220
|
animationTarget: () => wiring.current.animation.target()
|
|
27221
|
+
} : {},
|
|
27222
|
+
...decay ? {
|
|
27223
|
+
decay: (config) => wiring.current.decay.start(config),
|
|
27224
|
+
stopDecay: () => wiring.current.decay.cancel()
|
|
26141
27225
|
} : {}
|
|
26142
27226
|
};
|
|
26143
27227
|
}
|
|
@@ -26870,7 +27954,6 @@ function useActionsPropResolver(actions) {
|
|
|
26870
27954
|
}
|
|
26871
27955
|
if (!prop) return;
|
|
26872
27956
|
const unregisters = [];
|
|
26873
|
-
const restores = [];
|
|
26874
27957
|
const warnedIds = /* @__PURE__ */ new Set();
|
|
26875
27958
|
for (const [slotId, entry] of Object.entries(prop)) {
|
|
26876
27959
|
if (entry === null) {
|
|
@@ -26898,60 +27981,30 @@ function useActionsPropResolver(actions) {
|
|
|
26898
27981
|
}
|
|
26899
27982
|
const { id: _drop, ...rest } = entry;
|
|
26900
27983
|
const merged = { ...existing, ...rest };
|
|
26901
|
-
restores.push(() => {
|
|
26902
|
-
reg.register(existing);
|
|
26903
|
-
});
|
|
26904
27984
|
unregisters.push(reg.register(merged));
|
|
26905
27985
|
}
|
|
26906
27986
|
return () => {
|
|
26907
27987
|
for (const u of unregisters) u();
|
|
26908
|
-
for (const r of restores) r();
|
|
26909
27988
|
};
|
|
26910
27989
|
}, [reg, actions]);
|
|
26911
27990
|
}
|
|
26912
|
-
var viewportWheelPanAction = {
|
|
26913
|
-
id: "viewport.wheelPan",
|
|
26914
|
-
label: "Pan (wheel)",
|
|
26915
|
-
group: "viewport",
|
|
26916
|
-
/**
|
|
26917
|
-
* Plain wheel → pan; Shift+wheel → horizontal pan (axis swap).
|
|
26918
|
-
* Cmd+wheel is claimed by `viewportZoomAction`. The matcher's strict
|
|
26919
|
-
* modifier check keeps the bindings exclusive: omitting `mods` forbids
|
|
26920
|
-
* any modifier, and `mods: { shift: true }` forbids the others.
|
|
26921
|
-
*/
|
|
26922
|
-
defaultBinding: [
|
|
26923
|
-
{ spec: { kind: "wheel" }, opts: {} },
|
|
26924
|
-
{ spec: { kind: "wheel", mods: { shift: true } }, opts: { params: { swapAxis: true } } }
|
|
26925
|
-
],
|
|
26926
|
-
requires: ["view"],
|
|
26927
|
-
invoker: {
|
|
26928
|
-
timing: "immediate",
|
|
26929
|
-
run(deps, params) {
|
|
26930
|
-
const view = deps.view;
|
|
26931
|
-
if (!view) return;
|
|
26932
|
-
const deltaX = params?.deltaX ?? 0;
|
|
26933
|
-
const deltaY = params?.deltaY ?? 0;
|
|
26934
|
-
const current = view.get();
|
|
26935
|
-
const swap = params?.swapAxis === true;
|
|
26936
|
-
const dx = swap ? (deltaX !== 0 ? deltaX : deltaY) / current.scale.x : deltaX / current.scale.x;
|
|
26937
|
-
const dy = swap ? 0 : deltaY / current.scale.y;
|
|
26938
|
-
view.set({ ...current, x: current.x + dx, y: current.y + dy });
|
|
26939
|
-
}
|
|
26940
|
-
},
|
|
26941
|
-
enabled: () => true
|
|
26942
|
-
};
|
|
26943
27991
|
function useViewportActions(args) {
|
|
26944
27992
|
const { pan, zoom, pinchZoom } = args;
|
|
26945
27993
|
const reg = useActionsRegistry();
|
|
26946
27994
|
const regRef = useRef(reg);
|
|
26947
27995
|
regRef.current = reg;
|
|
27996
|
+
const panKey = typeof pan === "object" ? JSON.stringify(pan) : String(pan);
|
|
26948
27997
|
const zoomKey = typeof zoom === "object" ? JSON.stringify(zoom) : String(zoom);
|
|
26949
27998
|
const pinchKey = typeof pinchZoom === "object" ? JSON.stringify(pinchZoom) : String(pinchZoom);
|
|
26950
27999
|
useEffect(() => {
|
|
26951
28000
|
const r = regRef.current;
|
|
26952
28001
|
if (!r) return;
|
|
26953
28002
|
const unregisters = [];
|
|
26954
|
-
if (pan)
|
|
28003
|
+
if (pan) {
|
|
28004
|
+
unregisters.push(
|
|
28005
|
+
r.register(makeViewportWheelPanAction(typeof pan === "object" ? pan : {}))
|
|
28006
|
+
);
|
|
28007
|
+
}
|
|
26955
28008
|
if (zoom) {
|
|
26956
28009
|
const zoomAction = typeof zoom === "object" ? makeViewportZoomAction(zoom) : makeViewportZoomAction();
|
|
26957
28010
|
unregisters.push(r.register(zoomAction));
|
|
@@ -26966,7 +28019,7 @@ function useViewportActions(args) {
|
|
|
26966
28019
|
return () => {
|
|
26967
28020
|
for (const u of unregisters) u();
|
|
26968
28021
|
};
|
|
26969
|
-
}, [
|
|
28022
|
+
}, [panKey, zoomKey, pinchKey]);
|
|
26970
28023
|
}
|
|
26971
28024
|
function createNodeRouting() {
|
|
26972
28025
|
const entries = [];
|
|
@@ -27390,13 +28443,13 @@ function SceneCanvasInner(props, ref) {
|
|
|
27390
28443
|
const viewportRegistered = !!viewport;
|
|
27391
28444
|
const inertiaEnabled = !!viewport?.inertia;
|
|
27392
28445
|
const inertiaObj = typeof viewport?.inertia === "object" ? viewport.inertia : void 0;
|
|
27393
|
-
const handToolInertia = inertiaEnabled
|
|
27394
|
-
friction: inertiaObj
|
|
27395
|
-
minSpeed: inertiaObj
|
|
27396
|
-
boundary: inertiaObj
|
|
27397
|
-
bounds: inertiaObj
|
|
28446
|
+
const handToolInertia = inertiaEnabled ? {
|
|
28447
|
+
friction: inertiaObj?.friction,
|
|
28448
|
+
minSpeed: inertiaObj?.minSpeed,
|
|
28449
|
+
boundary: inertiaObj?.boundary,
|
|
28450
|
+
bounds: inertiaObj?.bounds
|
|
27398
28451
|
} : void 0;
|
|
27399
|
-
const handTool = useHandTool(handToolInertia ? {} : {});
|
|
28452
|
+
const handTool = useHandTool(handToolInertia ? { inertia: handToolInertia } : {});
|
|
27400
28453
|
const viewportAmbient = [];
|
|
27401
28454
|
const baseRequestedTools = defaultTools ?? (toolBundle ? BUNDLE_TOOLS[toolBundle] : null) ?? (viewportRegistered ? ["select", "rotate", "hand"] : ["select", "rotate"]);
|
|
27402
28455
|
const KNOWN_BUILTIN_IDS = /* @__PURE__ */ new Set([
|
|
@@ -27849,7 +28902,7 @@ function SceneCanvasInner(props, ref) {
|
|
|
27849
28902
|
dispatcher,
|
|
27850
28903
|
getActionRef,
|
|
27851
28904
|
pickEvery: internalPickEvery,
|
|
27852
|
-
viewportPanEnabled: viewport?.pan
|
|
28905
|
+
viewportPanEnabled: viewport?.pan ?? true,
|
|
27853
28906
|
viewportZoom: resolvedViewportZoom,
|
|
27854
28907
|
viewportPinchZoom: viewport?.pinchZoom ?? true,
|
|
27855
28908
|
viewportRecenter: viewport?.recenter,
|
|
@@ -28060,6 +29113,10 @@ function GestureDispatcherMounter({
|
|
|
28060
29113
|
const requestRedraw = useCallback(() => {
|
|
28061
29114
|
canvasApiRef?.current?.requestRedraw?.();
|
|
28062
29115
|
}, [canvasApiRef]);
|
|
29116
|
+
const paintedCursor = useCallback(
|
|
29117
|
+
() => canvasApiRef?.current?.paintedCursor,
|
|
29118
|
+
[canvasApiRef]
|
|
29119
|
+
);
|
|
28063
29120
|
const views = useMemo(() => {
|
|
28064
29121
|
if (!viewRegistry) return void 0;
|
|
28065
29122
|
return {
|
|
@@ -28078,6 +29135,7 @@ function GestureDispatcherMounter({
|
|
|
28078
29135
|
dispatcher,
|
|
28079
29136
|
clientToWorld: clientToWorld2,
|
|
28080
29137
|
requestRedraw,
|
|
29138
|
+
paintedCursor,
|
|
28081
29139
|
getRuleCtx,
|
|
28082
29140
|
onDoubleClick,
|
|
28083
29141
|
...views ? { views } : {}
|
|
@@ -28135,6 +29193,7 @@ function StandardActionsRegistrar({
|
|
|
28135
29193
|
getActionRef.current = null;
|
|
28136
29194
|
};
|
|
28137
29195
|
}, [registry22, getActionRef]);
|
|
29196
|
+
const decayLoop = useDecayLoop();
|
|
28138
29197
|
const view = useViewDepSource(
|
|
28139
29198
|
currentViewRef,
|
|
28140
29199
|
onViewChange,
|
|
@@ -28143,7 +29202,8 @@ function StandardActionsRegistrar({
|
|
|
28143
29202
|
const el = canvasRef.current;
|
|
28144
29203
|
return el ? { width: el.clientWidth, height: el.clientHeight } : null;
|
|
28145
29204
|
},
|
|
28146
|
-
viewAnimation
|
|
29205
|
+
viewAnimation,
|
|
29206
|
+
decayLoop
|
|
28147
29207
|
);
|
|
28148
29208
|
const sceneAsHistory = scene;
|
|
28149
29209
|
useStandardActions({ selection, scene, view, history: sceneAsHistory });
|
|
@@ -28576,8 +29636,7 @@ function MinimapCanvasInner(props) {
|
|
|
28576
29636
|
}, [mainView, mainViewDims, indicatorStyle]);
|
|
28577
29637
|
const extraCommands = useMemo(() => [indicatorCmd], [indicatorCmd]);
|
|
28578
29638
|
const localCanvasRef = useRef(null);
|
|
28579
|
-
const
|
|
28580
|
-
const capturedPointerIdRef = useRef(null);
|
|
29639
|
+
const sessionRef = useRef(null);
|
|
28581
29640
|
const mainViewRef = useRef(mainView);
|
|
28582
29641
|
const mainViewDimsRef = useRef(mainViewDims);
|
|
28583
29642
|
const onMainViewChangeRef = useRef(onMainViewChange);
|
|
@@ -28606,36 +29665,18 @@ function MinimapCanvasInner(props) {
|
|
|
28606
29665
|
}, []);
|
|
28607
29666
|
const handlePointerDown = useCallback((ev) => {
|
|
28608
29667
|
const canvas = localCanvasRef.current;
|
|
28609
|
-
if (!canvas) return;
|
|
29668
|
+
if (!canvas || sessionRef.current) return;
|
|
28610
29669
|
if (ev.pointerType === "mouse" && ev.button !== 0) return;
|
|
28611
|
-
|
|
28612
|
-
|
|
28613
|
-
}
|
|
28614
|
-
|
|
28615
|
-
|
|
28616
|
-
|
|
28617
|
-
|
|
28618
|
-
|
|
28619
|
-
const handlePointerMove = useCallback((ev) => {
|
|
28620
|
-
if (!dragActiveRef.current) return;
|
|
28621
|
-
if (capturedPointerIdRef.current !== null && ev.pointerId !== capturedPointerIdRef.current) {
|
|
28622
|
-
return;
|
|
28623
|
-
}
|
|
29670
|
+
const done = () => {
|
|
29671
|
+
sessionRef.current = null;
|
|
29672
|
+
};
|
|
29673
|
+
sessionRef.current = openPointerSession(canvas, ev, {
|
|
29674
|
+
onMove: recenterFromPointer,
|
|
29675
|
+
onEnd: done,
|
|
29676
|
+
onCancel: done
|
|
29677
|
+
});
|
|
28624
29678
|
recenterFromPointer(ev);
|
|
28625
29679
|
}, [recenterFromPointer]);
|
|
28626
|
-
const releaseCapture = useCallback((ev) => {
|
|
28627
|
-
const canvas = localCanvasRef.current;
|
|
28628
|
-
if (canvas) {
|
|
28629
|
-
try {
|
|
28630
|
-
if (canvas.hasPointerCapture?.(ev.pointerId)) {
|
|
28631
|
-
canvas.releasePointerCapture(ev.pointerId);
|
|
28632
|
-
}
|
|
28633
|
-
} catch {
|
|
28634
|
-
}
|
|
28635
|
-
}
|
|
28636
|
-
dragActiveRef.current = false;
|
|
28637
|
-
capturedPointerIdRef.current = null;
|
|
28638
|
-
}, []);
|
|
28639
29680
|
const setCanvasRef = useCallback((el) => {
|
|
28640
29681
|
localCanvasRef.current = el;
|
|
28641
29682
|
if (typeof canvasRef === "function") {
|
|
@@ -28648,16 +29689,11 @@ function MinimapCanvasInner(props) {
|
|
|
28648
29689
|
const canvas = localCanvasRef.current;
|
|
28649
29690
|
if (!canvas) return;
|
|
28650
29691
|
canvas.addEventListener("pointerdown", handlePointerDown);
|
|
28651
|
-
canvas.addEventListener("pointermove", handlePointerMove);
|
|
28652
|
-
canvas.addEventListener("pointerup", releaseCapture);
|
|
28653
|
-
canvas.addEventListener("pointercancel", releaseCapture);
|
|
28654
29692
|
return () => {
|
|
28655
29693
|
canvas.removeEventListener("pointerdown", handlePointerDown);
|
|
28656
|
-
|
|
28657
|
-
canvas.removeEventListener("pointerup", releaseCapture);
|
|
28658
|
-
canvas.removeEventListener("pointercancel", releaseCapture);
|
|
29694
|
+
sessionRef.current?.cancel();
|
|
28659
29695
|
};
|
|
28660
|
-
}, [handlePointerDown
|
|
29696
|
+
}, [handlePointerDown]);
|
|
28661
29697
|
return /* @__PURE__ */ jsx(
|
|
28662
29698
|
SceneViewCanvas,
|
|
28663
29699
|
{
|
|
@@ -28929,6 +29965,6 @@ function oklchToOklab(L, C, h) {
|
|
|
28929
29965
|
return [L, C * Math.cos(h), C * Math.sin(h)];
|
|
28930
29966
|
}
|
|
28931
29967
|
|
|
28932
|
-
export { ArrowIcon, EllipseIcon, FALLBACK_FIT_VIEW, LineIcon, MinimapCanvas, PATH_C, PATH_L, PATH_M, PATH_Q, PATH_Z, PathBuilder, PencilIcon, RectIcon, SCRIPT_METRICS, SceneCanvas, SceneViewCanvas, SelectIcon, TextIcon, UnknownIcon, WeaselProvider, asNodeId, boundsOfPath, buildSceneViewCommands, computeFitView, computeIndicatorCommand, createScene, eligibleContribution, ellipsePath, evaluateEnabled, getMarker, getPaintKind, isBuiltinToolPref, linePath, markerDrawCommands, oklabToSrgbU8, oklchToOklab, rectPath, renderSceneToCanvas, renderSceneToPixels, resolveStrokeWidth, rgbaToHex, sceneFromJSON, textCommand, tileGeometry, useActionsRegistry, useActiveToolContext, useOptionalDepRegistry, useVisibleRaf };
|
|
28933
|
-
//# sourceMappingURL=chunk-
|
|
28934
|
-
//# sourceMappingURL=chunk-
|
|
29968
|
+
export { ArrowIcon, EllipseIcon, FALLBACK_FIT_VIEW, LineIcon, MinimapCanvas, PATH_C, PATH_L, PATH_M, PATH_Q, PATH_Z, PathBuilder, PencilIcon, RectIcon, SCRIPT_METRICS, SceneCanvas, SceneViewCanvas, SelectIcon, TextIcon, UnknownIcon, WeaselProvider, asNodeId, boundsOfPath, buildSceneViewCommands, computeFitView, computeIndicatorCommand, createScene, eligibleContribution, ellipsePath, evaluateEnabled, getMarker, getPaintKind, isBuiltinToolPref, linePath, markerDrawCommands, oklabToSrgbU8, oklchToOklab, openPointerSession, rectPath, renderSceneToCanvas, renderSceneToPixels, resolveStrokeWidth, rgbaToHex, sceneFromJSON, textCommand, tileGeometry, useActionsRegistry, useActiveToolContext, useOptionalDepRegistry, useVisibleRaf };
|
|
29969
|
+
//# sourceMappingURL=chunk-DG2IFMLA.js.map
|
|
29970
|
+
//# sourceMappingURL=chunk-DG2IFMLA.js.map
|