@weasel-js/labkit 1.0.3 → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +6 -6
- package/dist/_dts/{DrawCommand-uKHt4Vul.d.ts → DrawCommand-BkZztJsW.d.ts} +3 -1
- package/dist/_dts/{index-CFlDPeZh.d.ts → index-iAP6XbH3.d.ts} +17 -7
- package/dist/_dts/{useExperimentState-vrttakTt.d.ts → useTrialState-DYe2vUwN.d.ts} +62 -34
- package/dist/canvas/index.d.ts +1 -1
- package/dist/chunk-3TYUJR7Z.js +488 -0
- package/dist/chunk-3TYUJR7Z.js.map +1 -0
- package/dist/{chunk-N5KTQKQA.js → chunk-C6GJKPUI.js} +835 -770
- package/dist/chunk-C6GJKPUI.js.map +1 -0
- package/dist/{chunk-3WPOGKUP.js → chunk-DJLDIRFN.js} +543 -226
- package/dist/chunk-DJLDIRFN.js.map +1 -0
- package/dist/{chunk-73PXCRCR.js → chunk-NRKWVTVT.js} +6 -6
- package/dist/chunk-NRKWVTVT.js.map +1 -0
- package/dist/dragdrop/index.d.ts +1 -1
- package/dist/index.d.ts +197 -148
- package/dist/index.js +275 -161
- package/dist/index.js.map +1 -1
- package/dist/layers/index.d.ts +2 -2
- package/dist/passthrough/weasel-canvas.d.ts +1 -1
- package/dist/passthrough/weasel-canvas.js +1 -1
- package/dist/passthrough/weasel-ui.d.ts +10 -3
- package/dist/passthrough/weasel-ui.js +2 -2
- package/dist/state/index.d.ts +14 -14
- package/dist/state/index.js +5 -5
- package/dist/state/index.js.map +1 -1
- package/dist/styles.css +179 -14
- package/dist/ui/layers/index.js +3 -3
- package/dist/undo/index.d.ts +1 -1
- package/package.json +2 -1
- package/src/canvas/AGENTS.md +6 -2
- package/src/dragdrop/dragDrop.test.tsx +4 -7
- package/src/index.test.ts +52 -0
- package/src/index.ts +11 -7
- package/src/instrument/SineWave.smoke.test.tsx +1 -1
- package/src/instrument/capabilityDetector.ts +1 -1
- package/src/instrument/types.ts +18 -6
- package/src/lab/Lab.less +16 -0
- package/src/lab/Lab.stories.tsx +5 -5
- package/src/lab/Lab.test.tsx +25 -25
- package/src/lab/Lab.tsx +56 -44
- package/src/lab/LabContext.ts +12 -11
- package/src/lab/LabShell.tsx +1 -1
- package/src/lab/Workspace.less +40 -0
- package/src/lab/{WorkspaceGrid.stories.tsx → Workspace.stories.tsx} +27 -11
- package/src/lab/Workspace.test.tsx +114 -0
- package/src/lab/Workspace.tsx +196 -0
- package/src/lab/index.ts +2 -4
- package/src/layers/AGENTS.md +3 -3
- package/src/primitives/Toolbar.stories.tsx +2 -2
- package/src/state/SingletonExperiment.test.tsx +8 -8
- package/src/state/SingletonExperiment.tsx +9 -9
- package/src/state/context.tsx +12 -12
- package/src/state/document.test.ts +369 -0
- package/src/state/document.ts +194 -0
- package/src/state/helpers.test.ts +74 -46
- package/src/state/helpers.ts +23 -31
- package/src/state/index.ts +16 -8
- package/src/state/store.test.ts +440 -40
- package/src/state/store.ts +166 -90
- package/src/state/types.ts +30 -10
- package/src/state/{useExperimentState.test.tsx → useTrialState.test.tsx} +18 -18
- package/src/state/useTrialState.ts +29 -0
- package/src/styles.less +2 -2
- package/src/test-setup.ts +19 -0
- package/src/theme/base.less +1 -1
- package/src/{workspace → trial}/DefaultSidebar.tsx +3 -3
- package/src/{workspace → trial}/DefaultStatusBar.tsx +5 -4
- package/src/{workspace → trial}/DefaultToolbar.tsx +9 -8
- package/src/trial/Trial.canvas.test.tsx +80 -0
- package/src/{workspace/Workspace.less → trial/Trial.less} +1 -1
- package/src/{workspace/Workspace.stories.tsx → trial/Trial.stories.tsx} +13 -17
- package/src/{workspace/Workspace.test.tsx → trial/Trial.test.tsx} +26 -25
- package/src/{workspace/Workspace.tsx → trial/Trial.tsx} +48 -43
- package/src/{workspace/WorkspaceChrome.tsx → trial/TrialChrome.tsx} +42 -42
- package/src/{workspace → trial}/index.ts +13 -12
- package/src/{workspace → trial}/slotTypes.ts +16 -16
- package/src/{workspace/workspaceOps.test.ts → trial/trialOps.test.ts} +60 -33
- package/src/trial/trialOps.ts +99 -0
- package/src/ui/format.test.ts +33 -0
- package/src/ui/format.ts +11 -0
- package/src/ui/properties/CurveField.tsx +6 -6
- package/src/ui/properties/SpeechBalloonPanels.stories.tsx +3 -3
- package/dist/chunk-3WPOGKUP.js.map +0 -1
- package/dist/chunk-73PXCRCR.js.map +0 -1
- package/dist/chunk-N5KTQKQA.js.map +0 -1
- package/dist/chunk-T7OKNJTY.js +0 -351
- package/dist/chunk-T7OKNJTY.js.map +0 -1
- package/src/lab/WorkspaceGrid.less +0 -8
- package/src/lab/WorkspaceGrid.test.tsx +0 -40
- package/src/lab/WorkspaceGrid.tsx +0 -22
- package/src/lab/gridDims.test.ts +0 -35
- package/src/lab/gridDims.ts +0 -13
- package/src/state/useExperimentState.ts +0 -31
- package/src/workspace/workspaceOps.ts +0 -86
|
@@ -3,7 +3,7 @@ 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-J3YC3GVF.js
|
|
7
7
|
|
|
8
8
|
// ../gestures/dist/index.js
|
|
9
9
|
var GESTURE_DESCRIPTORS = [
|
|
@@ -60,9 +60,8 @@ function formatRoute(r) {
|
|
|
60
60
|
const desc = getGestureDescriptor(r.gesture);
|
|
61
61
|
const phaseStr = `[${r.phases.map(formatPhaseAtom).join(",")}]`;
|
|
62
62
|
let out = `${phaseStr} ${r.gesture}`;
|
|
63
|
-
if (desc.arg) {
|
|
64
|
-
|
|
65
|
-
if (!isDefault) out += `(${r.arg})`;
|
|
63
|
+
if (desc.arg && r.arg !== void 0 && r.arg !== (desc.arg.default ?? "*")) {
|
|
64
|
+
out += `(${r.arg})`;
|
|
66
65
|
}
|
|
67
66
|
if (desc.hasTarget && r.target !== void 0 && r.target !== "*") {
|
|
68
67
|
out += ` => ${r.target}`;
|
|
@@ -288,7 +287,7 @@ function matchSpec(e, spec, isMac, phaseCtx) {
|
|
|
288
287
|
}
|
|
289
288
|
var EMPTY_ENGAGED = /* @__PURE__ */ new Set();
|
|
290
289
|
|
|
291
|
-
// ../core/dist/chunk-
|
|
290
|
+
// ../core/dist/chunk-J3YC3GVF.js
|
|
292
291
|
var DepRegistryContext = createContext(null);
|
|
293
292
|
function DepRegistryProvider({ children }) {
|
|
294
293
|
const sourcesRef = useRef(/* @__PURE__ */ new Map());
|
|
@@ -520,7 +519,8 @@ function ActionsProvider({ children }) {
|
|
|
520
519
|
const disp = dispatcherRef.current;
|
|
521
520
|
if (!disp) return null;
|
|
522
521
|
const r = wiredDepRegRef.current ?? depRegRef.current;
|
|
523
|
-
const
|
|
522
|
+
const a = actionsRef.current.get(id);
|
|
523
|
+
const deps = !r ? {} : a?.requires ? buildDepsFromRequires(a, r) : {
|
|
524
524
|
selection: r.get("selection"),
|
|
525
525
|
scene: r.get("scene"),
|
|
526
526
|
history: r.get("history"),
|
|
@@ -528,7 +528,7 @@ function ActionsProvider({ children }) {
|
|
|
528
528
|
pointer: r.get("pointer"),
|
|
529
529
|
activeTool: r.get("activeTool"),
|
|
530
530
|
booleansAdapter: r.get("booleansAdapter")
|
|
531
|
-
}
|
|
531
|
+
};
|
|
532
532
|
return disp.beginUiOngoing(id, deps, params);
|
|
533
533
|
}
|
|
534
534
|
};
|
|
@@ -699,7 +699,7 @@ function reportRouteConflicts(scopes, warn = (m) => console.warn(m)) {
|
|
|
699
699
|
return conflicts;
|
|
700
700
|
}
|
|
701
701
|
|
|
702
|
-
// ../geom/dist/chunk-
|
|
702
|
+
// ../geom/dist/chunk-KU7FXMOA.js
|
|
703
703
|
function cubicEvalAt(x0, y0, x1, y1, x2, y2, x3, y3, t) {
|
|
704
704
|
const u = 1 - t;
|
|
705
705
|
const a = u * u * u, b = 3 * u * u * t, c = 3 * u * t * t, d = t * t * t;
|
|
@@ -753,6 +753,12 @@ function cubicBounds(x0, y0, x1, y1, x2, y2, x3, y3) {
|
|
|
753
753
|
}
|
|
754
754
|
|
|
755
755
|
// ../geom/dist/index.js
|
|
756
|
+
function dot(ax, ay, bx, by) {
|
|
757
|
+
return ax * bx + ay * by;
|
|
758
|
+
}
|
|
759
|
+
function len2(x, y) {
|
|
760
|
+
return x * x + y * y;
|
|
761
|
+
}
|
|
756
762
|
function sign(n) {
|
|
757
763
|
return n > 0 ? 1 : n < 0 ? -1 : 0;
|
|
758
764
|
}
|
|
@@ -804,6 +810,15 @@ function segmentsCross(ax, ay, bx, by, cx, cy, dx, dy) {
|
|
|
804
810
|
const d4 = sign((bx - ax) * (dy - ay) - (by - ay) * (dx - ax));
|
|
805
811
|
return d1 !== d2 && d3 !== d4;
|
|
806
812
|
}
|
|
813
|
+
function pointSegmentDist2(px, py, ax, ay, bx, by) {
|
|
814
|
+
const vx = bx - ax, vy = by - ay;
|
|
815
|
+
const wx = px - ax, wy = py - ay;
|
|
816
|
+
const vv = len2(vx, vy);
|
|
817
|
+
let t = vv === 0 ? 0 : dot(wx, wy, vx, vy) / vv;
|
|
818
|
+
t = t < 0 ? 0 : t > 1 ? 1 : t;
|
|
819
|
+
const dx = px - (ax + t * vx), dy = py - (ay + t * vy);
|
|
820
|
+
return len2(dx, dy);
|
|
821
|
+
}
|
|
807
822
|
function transformCoords(coords, m) {
|
|
808
823
|
const out = new Float64Array(coords.length);
|
|
809
824
|
const a = m[0], b = m[1], c = m[2], d = m[3], e = m[4], f = m[5];
|
|
@@ -815,7 +830,7 @@ function transformCoords(coords, m) {
|
|
|
815
830
|
return out;
|
|
816
831
|
}
|
|
817
832
|
|
|
818
|
-
// ../core/dist/chunk-
|
|
833
|
+
// ../core/dist/chunk-4Z6J4IVH.js
|
|
819
834
|
function resolveUnit(v, unitSystem) {
|
|
820
835
|
if (typeof v === "number") return v;
|
|
821
836
|
if (!unitSystem) {
|
|
@@ -900,19 +915,36 @@ function boundsOfPath(path) {
|
|
|
900
915
|
return { kind: "rect", x: minX, y: minY, width: maxX - minX, height: maxY - minY };
|
|
901
916
|
}
|
|
902
917
|
var DEFAULT_FLATTEN_TOLERANCE = 0.5;
|
|
918
|
+
var MIN_FLATTEN_TOLERANCE = 1e-6;
|
|
919
|
+
function usableTolerance(tolerance) {
|
|
920
|
+
return tolerance > 0 ? tolerance : MIN_FLATTEN_TOLERANCE;
|
|
921
|
+
}
|
|
922
|
+
function finite6(a, b, c, d, e, f) {
|
|
923
|
+
return Number.isFinite(a) && Number.isFinite(b) && Number.isFinite(c) && Number.isFinite(d) && Number.isFinite(e) && Number.isFinite(f);
|
|
924
|
+
}
|
|
925
|
+
function finite8(a, b, c, d, e, f, g, h) {
|
|
926
|
+
return finite6(a, b, c, d, e, f) && Number.isFinite(g) && Number.isFinite(h);
|
|
927
|
+
}
|
|
903
928
|
function distPointToLine(px, py, ax, ay, bx, by) {
|
|
904
929
|
const dx = bx - ax;
|
|
905
930
|
const dy = by - ay;
|
|
906
|
-
const
|
|
907
|
-
if (
|
|
931
|
+
const len22 = dx * dx + dy * dy;
|
|
932
|
+
if (len22 === 0) {
|
|
908
933
|
const ex = px - ax;
|
|
909
934
|
const ey = py - ay;
|
|
910
935
|
return Math.sqrt(ex * ex + ey * ey);
|
|
911
936
|
}
|
|
912
937
|
const cross = (px - ax) * dy - (py - ay) * dx;
|
|
913
|
-
return Math.abs(cross) / Math.sqrt(
|
|
938
|
+
return Math.abs(cross) / Math.sqrt(len22);
|
|
914
939
|
}
|
|
915
940
|
function flattenCubic2(x0, y0, x1, y1, x2, y2, x3, y3, tolerance, out) {
|
|
941
|
+
if (!finite8(x0, y0, x1, y1, x2, y2, x3, y3)) {
|
|
942
|
+
out.push(x3, y3);
|
|
943
|
+
return;
|
|
944
|
+
}
|
|
945
|
+
flattenCubicRec(x0, y0, x1, y1, x2, y2, x3, y3, usableTolerance(tolerance), out);
|
|
946
|
+
}
|
|
947
|
+
function flattenCubicRec(x0, y0, x1, y1, x2, y2, x3, y3, tolerance, out) {
|
|
916
948
|
const d1 = distPointToLine(x1, y1, x0, y0, x3, y3);
|
|
917
949
|
const d2 = distPointToLine(x2, y2, x0, y0, x3, y3);
|
|
918
950
|
if (Math.max(d1, d2) <= tolerance) {
|
|
@@ -925,10 +957,17 @@ function flattenCubic2(x0, y0, x1, y1, x2, y2, x3, y3, tolerance, out) {
|
|
|
925
957
|
const x012 = (x01 + x12) * 0.5, y012 = (y01 + y12) * 0.5;
|
|
926
958
|
const x123 = (x12 + x23) * 0.5, y123 = (y12 + y23) * 0.5;
|
|
927
959
|
const x0123 = (x012 + x123) * 0.5, y0123 = (y012 + y123) * 0.5;
|
|
928
|
-
|
|
929
|
-
|
|
960
|
+
flattenCubicRec(x0, y0, x01, y01, x012, y012, x0123, y0123, tolerance, out);
|
|
961
|
+
flattenCubicRec(x0123, y0123, x123, y123, x23, y23, x3, y3, tolerance, out);
|
|
930
962
|
}
|
|
931
963
|
function flattenQuadratic(x0, y0, x1, y1, x2, y2, tolerance, out) {
|
|
964
|
+
if (!finite6(x0, y0, x1, y1, x2, y2)) {
|
|
965
|
+
out.push(x2, y2);
|
|
966
|
+
return;
|
|
967
|
+
}
|
|
968
|
+
flattenQuadraticRec(x0, y0, x1, y1, x2, y2, usableTolerance(tolerance), out);
|
|
969
|
+
}
|
|
970
|
+
function flattenQuadraticRec(x0, y0, x1, y1, x2, y2, tolerance, out) {
|
|
932
971
|
const d = distPointToLine(x1, y1, x0, y0, x2, y2);
|
|
933
972
|
if (d <= tolerance) {
|
|
934
973
|
out.push(x2, y2);
|
|
@@ -937,11 +976,16 @@ function flattenQuadratic(x0, y0, x1, y1, x2, y2, tolerance, out) {
|
|
|
937
976
|
const x01 = (x0 + x1) * 0.5, y01 = (y0 + y1) * 0.5;
|
|
938
977
|
const x12 = (x1 + x2) * 0.5, y12 = (y1 + y2) * 0.5;
|
|
939
978
|
const x012 = (x01 + x12) * 0.5, y012 = (y01 + y12) * 0.5;
|
|
940
|
-
|
|
941
|
-
|
|
979
|
+
flattenQuadraticRec(x0, y0, x01, y01, x012, y012, tolerance, out);
|
|
980
|
+
flattenQuadraticRec(x012, y012, x12, y12, x2, y2, tolerance, out);
|
|
942
981
|
}
|
|
943
982
|
function flattenCubicWithArcLen(x0, y0, x1, y1, x2, y2, x3, y3, tolerance, out, arcOut) {
|
|
944
|
-
|
|
983
|
+
if (!finite8(x0, y0, x1, y1, x2, y2, x3, y3)) {
|
|
984
|
+
out.push(x3, y3);
|
|
985
|
+
arcOut.push(0);
|
|
986
|
+
return 0;
|
|
987
|
+
}
|
|
988
|
+
return flattenCubicArcRec(x0, y0, x1, y1, x2, y2, x3, y3, usableTolerance(tolerance), out, arcOut, 0);
|
|
945
989
|
}
|
|
946
990
|
function flattenCubicArcRec(x0, y0, x1, y1, x2, y2, x3, y3, tolerance, out, arcOut, accum) {
|
|
947
991
|
const d1 = distPointToLine(x1, y1, x0, y0, x3, y3);
|
|
@@ -966,7 +1010,12 @@ function flattenCubicArcRec(x0, y0, x1, y1, x2, y2, x3, y3, tolerance, out, arcO
|
|
|
966
1010
|
return accum;
|
|
967
1011
|
}
|
|
968
1012
|
function flattenQuadraticWithArcLen(x0, y0, x1, y1, x2, y2, tolerance, out, arcOut) {
|
|
969
|
-
|
|
1013
|
+
if (!finite6(x0, y0, x1, y1, x2, y2)) {
|
|
1014
|
+
out.push(x2, y2);
|
|
1015
|
+
arcOut.push(0);
|
|
1016
|
+
return 0;
|
|
1017
|
+
}
|
|
1018
|
+
return flattenQuadraticArcRec(x0, y0, x1, y1, x2, y2, usableTolerance(tolerance), out, arcOut, 0);
|
|
970
1019
|
}
|
|
971
1020
|
function flattenQuadraticArcRec(x0, y0, x1, y1, x2, y2, tolerance, out, arcOut, accum) {
|
|
972
1021
|
const d = distPointToLine(x1, y1, x0, y0, x2, y2);
|
|
@@ -1159,22 +1208,6 @@ function polylineWithinThreshold(path, px, py, t2, tolerance) {
|
|
|
1159
1208
|
if (subOpen && checkSegments(false)) return true;
|
|
1160
1209
|
return false;
|
|
1161
1210
|
}
|
|
1162
|
-
function pointSegmentDist2(px, py, ax, ay, bx, by) {
|
|
1163
|
-
const dx = bx - ax;
|
|
1164
|
-
const dy = by - ay;
|
|
1165
|
-
const len2 = dx * dx + dy * dy;
|
|
1166
|
-
if (len2 === 0) {
|
|
1167
|
-
const ex2 = px - ax, ey2 = py - ay;
|
|
1168
|
-
return ex2 * ex2 + ey2 * ey2;
|
|
1169
|
-
}
|
|
1170
|
-
let t = ((px - ax) * dx + (py - ay) * dy) / len2;
|
|
1171
|
-
if (t < 0) t = 0;
|
|
1172
|
-
else if (t > 1) t = 1;
|
|
1173
|
-
const cx = ax + t * dx;
|
|
1174
|
-
const cy = ay + t * dy;
|
|
1175
|
-
const ex = px - cx, ey = py - cy;
|
|
1176
|
-
return ex * ex + ey * ey;
|
|
1177
|
-
}
|
|
1178
1211
|
var PathBuilder = class _PathBuilder {
|
|
1179
1212
|
cmds = [];
|
|
1180
1213
|
xs = [];
|
|
@@ -1563,7 +1596,7 @@ function createDeleteOp(args) {
|
|
|
1563
1596
|
}
|
|
1564
1597
|
registerOpFactory("delete", (args) => createDeleteOp(args));
|
|
1565
1598
|
|
|
1566
|
-
// ../core/dist/chunk-
|
|
1599
|
+
// ../core/dist/chunk-CSMF654J.js
|
|
1567
1600
|
function createTransformOp(args) {
|
|
1568
1601
|
const { id, from, to, label, coalesceKey = `transform:${id}` } = args;
|
|
1569
1602
|
return {
|
|
@@ -1644,7 +1677,7 @@ function snap(strategy, opts = {}) {
|
|
|
1644
1677
|
};
|
|
1645
1678
|
}
|
|
1646
1679
|
|
|
1647
|
-
// ../core/dist/chunk-
|
|
1680
|
+
// ../core/dist/chunk-J7LUY47N.js
|
|
1648
1681
|
function lockAspectWithModifier(opts = {}) {
|
|
1649
1682
|
const { key = "shift" } = opts;
|
|
1650
1683
|
return {
|
|
@@ -2850,6 +2883,7 @@ function createHistory(adapter, options = {}) {
|
|
|
2850
2883
|
const logger = options.debug ?? SILENT;
|
|
2851
2884
|
let nextEntryId = 1;
|
|
2852
2885
|
let version = 0;
|
|
2886
|
+
let coalesceAnchorVersion = -1;
|
|
2853
2887
|
const listeners = /* @__PURE__ */ new Set();
|
|
2854
2888
|
function bump() {
|
|
2855
2889
|
version++;
|
|
@@ -2890,6 +2924,7 @@ function createHistory(adapter, options = {}) {
|
|
|
2890
2924
|
}
|
|
2891
2925
|
function canCoalesce(top, incoming) {
|
|
2892
2926
|
if (coalesceWindowMs <= 0) return false;
|
|
2927
|
+
if (version !== coalesceAnchorVersion) return false;
|
|
2893
2928
|
if (now() - top.timestamp > coalesceWindowMs) return false;
|
|
2894
2929
|
if (top.forwardOps.length === 0 || incoming.length === 0) return false;
|
|
2895
2930
|
if (top.forwardOps.length !== incoming.length) return false;
|
|
@@ -2927,9 +2962,9 @@ function createHistory(adapter, options = {}) {
|
|
|
2927
2962
|
for (const id of incoming) merged.add(id);
|
|
2928
2963
|
top.touchedIds = merged;
|
|
2929
2964
|
}
|
|
2930
|
-
dropRedo();
|
|
2931
2965
|
logger.log(`coalesce '${label}' into entry id=${top.id} (${ops.length} ops)`);
|
|
2932
2966
|
bump();
|
|
2967
|
+
coalesceAnchorVersion = version;
|
|
2933
2968
|
return;
|
|
2934
2969
|
}
|
|
2935
2970
|
logger.log(`push '${label}' (${ops.length} ops)`);
|
|
@@ -2937,6 +2972,7 @@ function createHistory(adapter, options = {}) {
|
|
|
2937
2972
|
dropRedo();
|
|
2938
2973
|
enforceLimit();
|
|
2939
2974
|
bump();
|
|
2975
|
+
coalesceAnchorVersion = version;
|
|
2940
2976
|
}
|
|
2941
2977
|
return {
|
|
2942
2978
|
apply(op, label) {
|
|
@@ -3042,7 +3078,11 @@ function createHistory(adapter, options = {}) {
|
|
|
3042
3078
|
return j;
|
|
3043
3079
|
},
|
|
3044
3080
|
resumeJournal(journal) {
|
|
3081
|
+
if (activeJournal !== null && activeJournal !== journal && activeJournal.isActive()) {
|
|
3082
|
+
throw new Error("A journal is already active \u2014 commit, cancel, or suspend it first");
|
|
3083
|
+
}
|
|
3045
3084
|
_resumeJournalInternal(journal);
|
|
3085
|
+
activeJournal = journal;
|
|
3046
3086
|
},
|
|
3047
3087
|
restore(snapshot) {
|
|
3048
3088
|
undoStack.length = 0;
|
|
@@ -3123,9 +3163,8 @@ function serialToEntry(se, custom, logger) {
|
|
|
3123
3163
|
label: se.label,
|
|
3124
3164
|
forwardOps,
|
|
3125
3165
|
baseOps,
|
|
3126
|
-
//
|
|
3127
|
-
//
|
|
3128
|
-
// freshly-typed one regardless of when it was originally pushed.
|
|
3166
|
+
// Coalescing is a within-session concept; a restored entry is never a
|
|
3167
|
+
// coalesce anchor, so its timestamp only has to be non-null.
|
|
3129
3168
|
timestamp: 0,
|
|
3130
3169
|
// Re-derive touchedIds from the rebuilt ops rather than trying to
|
|
3131
3170
|
// round-trip the Set through the serialized form (Sets aren't JSON-safe).
|
|
@@ -3133,7 +3172,7 @@ function serialToEntry(se, custom, logger) {
|
|
|
3133
3172
|
};
|
|
3134
3173
|
}
|
|
3135
3174
|
|
|
3136
|
-
// ../core/dist/chunk-
|
|
3175
|
+
// ../core/dist/chunk-3B4QEB2G.js
|
|
3137
3176
|
function worldToScreen(worldX, worldY, view) {
|
|
3138
3177
|
return [view.panX + worldX * view.zoom.x, view.panY + worldY * view.zoom.y];
|
|
3139
3178
|
}
|
|
@@ -3570,13 +3609,20 @@ var GLTextureCache = class {
|
|
|
3570
3609
|
}
|
|
3571
3610
|
gl;
|
|
3572
3611
|
map = /* @__PURE__ */ new Map();
|
|
3612
|
+
wraps = /* @__PURE__ */ new Map();
|
|
3573
3613
|
has(id) {
|
|
3574
3614
|
return this.map.has(id);
|
|
3575
3615
|
}
|
|
3576
|
-
/** Uploads once per id
|
|
3577
|
-
*
|
|
3616
|
+
/** Uploads the pixels once per id. `wrap` is re-applied whenever it differs
|
|
3617
|
+
* from what the id was last uploaded under: the same registered image can
|
|
3618
|
+
* be a clamped shader texture in one draw and a repeating pattern tile in
|
|
3619
|
+
* the next, and first-upload-wins gave the second one the first one's mode. */
|
|
3578
3620
|
upload(id, source, wrap = "clamp") {
|
|
3579
|
-
|
|
3621
|
+
const cached2 = this.map.get(id);
|
|
3622
|
+
if (cached2) {
|
|
3623
|
+
if (this.wraps.get(id) !== wrap) this.applyWrap(id, cached2, wrap);
|
|
3624
|
+
return id;
|
|
3625
|
+
}
|
|
3580
3626
|
const gl = this.gl;
|
|
3581
3627
|
const tex = gl.createTexture();
|
|
3582
3628
|
if (!tex) throw new Error(`GLTextureCache: createTexture failed for id="${id}"`);
|
|
@@ -3589,8 +3635,18 @@ var GLTextureCache = class {
|
|
|
3589
3635
|
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, wrapMode);
|
|
3590
3636
|
gl.bindTexture(gl.TEXTURE_2D, null);
|
|
3591
3637
|
this.map.set(id, tex);
|
|
3638
|
+
this.wraps.set(id, wrap);
|
|
3592
3639
|
return id;
|
|
3593
3640
|
}
|
|
3641
|
+
applyWrap(id, tex, wrap) {
|
|
3642
|
+
const gl = this.gl;
|
|
3643
|
+
const mode = wrap === "repeat" ? gl.REPEAT : gl.CLAMP_TO_EDGE;
|
|
3644
|
+
gl.bindTexture(gl.TEXTURE_2D, tex);
|
|
3645
|
+
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, mode);
|
|
3646
|
+
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, mode);
|
|
3647
|
+
gl.bindTexture(gl.TEXTURE_2D, null);
|
|
3648
|
+
this.wraps.set(id, wrap);
|
|
3649
|
+
}
|
|
3594
3650
|
/** Create a single-channel R8 texture from raw bytes (full upload).
|
|
3595
3651
|
* No-op if `id` already exists. Same LINEAR/CLAMP params as `upload`;
|
|
3596
3652
|
* UNPACK_ALIGNMENT dropped to 1 for non-4-aligned row widths. */
|
|
@@ -3609,6 +3665,7 @@ var GLTextureCache = class {
|
|
|
3609
3665
|
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
|
|
3610
3666
|
gl.bindTexture(gl.TEXTURE_2D, null);
|
|
3611
3667
|
this.map.set(id, tex);
|
|
3668
|
+
this.wraps.set(id, "clamp");
|
|
3612
3669
|
}
|
|
3613
3670
|
/** Patch a rect of an existing R8 texture with tightly-packed w×h bytes. */
|
|
3614
3671
|
subImageR8(id, x, y, w, h, data) {
|
|
@@ -3640,6 +3697,7 @@ var GLTextureCache = class {
|
|
|
3640
3697
|
gl.deleteTexture(tex);
|
|
3641
3698
|
}
|
|
3642
3699
|
this.map.clear();
|
|
3700
|
+
this.wraps.clear();
|
|
3643
3701
|
}
|
|
3644
3702
|
};
|
|
3645
3703
|
var GLImageCache = class {
|
|
@@ -4289,6 +4347,13 @@ var GroupState = class {
|
|
|
4289
4347
|
this.alphaStack.push(nextAlpha);
|
|
4290
4348
|
this.colorMatrixStack.push(nextCM);
|
|
4291
4349
|
}
|
|
4350
|
+
/** Drop every pushed frame, leaving the root. A frame that throws part-way
|
|
4351
|
+
* down the tree never pops, and the next frame would draw under leftovers. */
|
|
4352
|
+
reset() {
|
|
4353
|
+
this.transformStack.length = 1;
|
|
4354
|
+
this.alphaStack.length = 1;
|
|
4355
|
+
this.colorMatrixStack.length = 1;
|
|
4356
|
+
}
|
|
4292
4357
|
pop() {
|
|
4293
4358
|
if (this.transformStack.length <= 1) {
|
|
4294
4359
|
throw new Error("GroupState.pop: cannot pop root frame");
|
|
@@ -4936,16 +5001,28 @@ function verticalAlignOffset(align, boxHeight, textHeight) {
|
|
|
4936
5001
|
return align === "center" ? slack / 2 : slack;
|
|
4937
5002
|
}
|
|
4938
5003
|
var NUM_RE = /[+-]?(?:\d*\.\d+|\d+\.?)(?:[eE][+-]?\d+)?/g;
|
|
5004
|
+
var NUM_RE_AT = /[+-]?(?:\d*\.\d+|\d+\.?)(?:[eE][+-]?\d+)?/y;
|
|
5005
|
+
function isCommandLetter(d, j) {
|
|
5006
|
+
const c = d[j];
|
|
5007
|
+
if (!/[A-Za-z]/.test(c)) return false;
|
|
5008
|
+
if (c !== "e" && c !== "E") return true;
|
|
5009
|
+
if (!/[\d.]/.test(d[j - 1] ?? "")) return true;
|
|
5010
|
+
const k = d[j + 1] === "+" || d[j + 1] === "-" ? j + 2 : j + 1;
|
|
5011
|
+
return !/\d/.test(d[k] ?? "");
|
|
5012
|
+
}
|
|
4939
5013
|
function tokenize(d) {
|
|
4940
5014
|
const out = [];
|
|
4941
5015
|
let i = 0;
|
|
4942
5016
|
while (i < d.length) {
|
|
4943
|
-
|
|
4944
|
-
if (/[A-Za-z]/.test(ch)) {
|
|
5017
|
+
if (isCommandLetter(d, i)) {
|
|
4945
5018
|
let j = i + 1;
|
|
4946
|
-
while (j < d.length &&
|
|
5019
|
+
while (j < d.length && !isCommandLetter(d, j)) j++;
|
|
4947
5020
|
const argSlice = d.slice(i + 1, j);
|
|
4948
|
-
|
|
5021
|
+
const cmd = d[i];
|
|
5022
|
+
out.push({
|
|
5023
|
+
cmd,
|
|
5024
|
+
args: cmd === "A" || cmd === "a" ? readArcArgs(argSlice) : readNumbers(argSlice)
|
|
5025
|
+
});
|
|
4949
5026
|
i = j;
|
|
4950
5027
|
} else {
|
|
4951
5028
|
i++;
|
|
@@ -4963,6 +5040,30 @@ function readNumbers(s) {
|
|
|
4963
5040
|
}
|
|
4964
5041
|
return out;
|
|
4965
5042
|
}
|
|
5043
|
+
function readArcArgs(s) {
|
|
5044
|
+
const out = [];
|
|
5045
|
+
let i = 0;
|
|
5046
|
+
while (i < s.length) {
|
|
5047
|
+
const c = s[i];
|
|
5048
|
+
if (c === "," || c === " " || c === " " || c === "\n" || c === "\r") {
|
|
5049
|
+
i++;
|
|
5050
|
+
continue;
|
|
5051
|
+
}
|
|
5052
|
+
const slot = out.length % 7;
|
|
5053
|
+
if (slot === 3 || slot === 4) {
|
|
5054
|
+
if (c !== "0" && c !== "1") return out;
|
|
5055
|
+
out.push(c === "1" ? 1 : 0);
|
|
5056
|
+
i++;
|
|
5057
|
+
continue;
|
|
5058
|
+
}
|
|
5059
|
+
NUM_RE_AT.lastIndex = i;
|
|
5060
|
+
const m = NUM_RE_AT.exec(s);
|
|
5061
|
+
if (!m) return out;
|
|
5062
|
+
out.push(Number(m[0]));
|
|
5063
|
+
i = NUM_RE_AT.lastIndex;
|
|
5064
|
+
}
|
|
5065
|
+
return out;
|
|
5066
|
+
}
|
|
4966
5067
|
var ARG_COUNTS = {
|
|
4967
5068
|
M: 2,
|
|
4968
5069
|
L: 2,
|
|
@@ -5153,9 +5254,9 @@ function arcToCubics(x1, y1, x2, y2, rx, ry, xAxisRotationDeg, largeArc, sweep,
|
|
|
5153
5254
|
const cx = cosPhi * cxp - sinPhi * cyp + (x1 + x2) / 2;
|
|
5154
5255
|
const cy = sinPhi * cxp + cosPhi * cyp + (y1 + y2) / 2;
|
|
5155
5256
|
const angle = (ux, uy, vx, vy) => {
|
|
5156
|
-
const
|
|
5257
|
+
const dot2 = ux * vx + uy * vy;
|
|
5157
5258
|
const len = Math.sqrt((ux * ux + uy * uy) * (vx * vx + vy * vy));
|
|
5158
|
-
let a = Math.acos(Math.max(-1, Math.min(1,
|
|
5259
|
+
let a = Math.acos(Math.max(-1, Math.min(1, dot2 / len)));
|
|
5159
5260
|
if (ux * vy - uy * vx < 0) a = -a;
|
|
5160
5261
|
return a;
|
|
5161
5262
|
};
|
|
@@ -5867,42 +5968,42 @@ var MAX_VERTICES_PER_BATCH = 32768;
|
|
|
5867
5968
|
var FLOATS_PER_VERTEX = 6;
|
|
5868
5969
|
var INITIAL_VERTICES = 256;
|
|
5869
5970
|
var INITIAL_INDICES = 384;
|
|
5971
|
+
var SOLID_RING_SIZE = 64;
|
|
5972
|
+
var SOLID_RING_SLOT_VERTICES = 1024;
|
|
5973
|
+
var SOLID_RING_SLOT_INDICES = 3072;
|
|
5974
|
+
var SOLID_LARGE_RING_SIZE = 4;
|
|
5975
|
+
function doubledTo(from, need) {
|
|
5976
|
+
let capacity = from;
|
|
5977
|
+
while (capacity < need) capacity *= 2;
|
|
5978
|
+
return capacity;
|
|
5979
|
+
}
|
|
5870
5980
|
var SolidBatch = class {
|
|
5871
5981
|
gl;
|
|
5872
|
-
|
|
5873
|
-
|
|
5874
|
-
|
|
5982
|
+
aPos;
|
|
5983
|
+
aColor;
|
|
5984
|
+
/** Cycled per flush, and created on first use so a renderer that flushes
|
|
5985
|
+
* rarely allocates as few slots as it flushes. */
|
|
5986
|
+
ring = new Array(SOLID_RING_SIZE).fill(void 0);
|
|
5987
|
+
next = 0;
|
|
5988
|
+
/** The same, for flushes past a slot's capacity; these sets grow to fit. */
|
|
5989
|
+
largeRing = new Array(SOLID_LARGE_RING_SIZE).fill(void 0);
|
|
5990
|
+
nextLarge = 0;
|
|
5875
5991
|
verts = new Float32Array(INITIAL_VERTICES * FLOATS_PER_VERTEX);
|
|
5876
5992
|
idx = new Uint32Array(INITIAL_INDICES);
|
|
5877
5993
|
nVerts = 0;
|
|
5878
5994
|
nIdx = 0;
|
|
5879
|
-
/**
|
|
5880
|
-
|
|
5881
|
-
|
|
5995
|
+
/** Whether the staged run is rects alone, so its indices are the canonical
|
|
5996
|
+
* quad pattern and a slot already holding that pattern needs no upload. */
|
|
5997
|
+
pureRects = true;
|
|
5882
5998
|
constructor(gl, prog) {
|
|
5883
5999
|
const aPos = prog.attribute("a_position");
|
|
5884
6000
|
const aColor = prog.attribute("a_vertexColor");
|
|
5885
6001
|
if (aPos === void 0 || aColor === void 0) {
|
|
5886
6002
|
throw new Error("SolidBatch: vertex-color program is missing a_position / a_vertexColor");
|
|
5887
6003
|
}
|
|
5888
|
-
const vao = gl.createVertexArray();
|
|
5889
|
-
const vbo = gl.createBuffer();
|
|
5890
|
-
const ibo = gl.createBuffer();
|
|
5891
|
-
if (!vao || !vbo || !ibo) throw new Error("SolidBatch: failed to create GL objects");
|
|
5892
6004
|
this.gl = gl;
|
|
5893
|
-
this.
|
|
5894
|
-
this.
|
|
5895
|
-
this.ibo = ibo;
|
|
5896
|
-
const stride = FLOATS_PER_VERTEX * 4;
|
|
5897
|
-
gl.bindVertexArray(vao);
|
|
5898
|
-
gl.bindBuffer(gl.ARRAY_BUFFER, vbo);
|
|
5899
|
-
gl.enableVertexAttribArray(aPos);
|
|
5900
|
-
gl.vertexAttribPointer(aPos, 2, gl.FLOAT, false, stride, 0);
|
|
5901
|
-
gl.enableVertexAttribArray(aColor);
|
|
5902
|
-
gl.vertexAttribPointer(aColor, 4, gl.FLOAT, false, stride, 8);
|
|
5903
|
-
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, ibo);
|
|
5904
|
-
gl.bindVertexArray(null);
|
|
5905
|
-
this.growGpu(INITIAL_VERTICES, INITIAL_INDICES);
|
|
6005
|
+
this.aPos = aPos;
|
|
6006
|
+
this.aColor = aColor;
|
|
5906
6007
|
}
|
|
5907
6008
|
get length() {
|
|
5908
6009
|
return this.nIdx;
|
|
@@ -5972,6 +6073,7 @@ var SolidBatch = class {
|
|
|
5972
6073
|
const srcIdx = mesh.indices;
|
|
5973
6074
|
const n = src.length >> 1;
|
|
5974
6075
|
this.reserve(n, srcIdx.length);
|
|
6076
|
+
this.pureRects = false;
|
|
5975
6077
|
const v = this.verts;
|
|
5976
6078
|
let i = this.nVerts * FLOATS_PER_VERTEX;
|
|
5977
6079
|
const ma = m[0], mb = m[1], mc = m[3], md = m[4], mtx = m[6], mty = m[7];
|
|
@@ -5992,67 +6094,109 @@ var SolidBatch = class {
|
|
|
5992
6094
|
this.nVerts += n;
|
|
5993
6095
|
this.nIdx += srcIdx.length;
|
|
5994
6096
|
}
|
|
5995
|
-
/** Upload the staged geometry and bind
|
|
5996
|
-
* count for the caller's `drawElements`. */
|
|
6097
|
+
/** Upload the staged geometry into the next set of buffers and bind its VAO.
|
|
6098
|
+
* Returns the index count for the caller's `drawElements`. */
|
|
5997
6099
|
uploadAndBind() {
|
|
5998
6100
|
const gl = this.gl;
|
|
5999
|
-
|
|
6000
|
-
|
|
6001
|
-
|
|
6002
|
-
gl.bindVertexArray(this.vao);
|
|
6003
|
-
gl.bindBuffer(gl.ARRAY_BUFFER, this.vbo);
|
|
6101
|
+
const set = this.nVerts <= SOLID_RING_SLOT_VERTICES && this.nIdx <= SOLID_RING_SLOT_INDICES ? this.nextRingSlot() : this.nextLargeSlot();
|
|
6102
|
+
gl.bindVertexArray(set.vao);
|
|
6103
|
+
gl.bindBuffer(gl.ARRAY_BUFFER, set.vbo);
|
|
6004
6104
|
gl.bufferSubData(gl.ARRAY_BUFFER, 0, this.verts, 0, this.nVerts * FLOATS_PER_VERTEX);
|
|
6005
|
-
|
|
6105
|
+
const rects = this.pureRects ? this.nVerts >> 2 : -1;
|
|
6106
|
+
if (rects < 0 || rects !== set.indexRects) {
|
|
6107
|
+
gl.bufferSubData(gl.ELEMENT_ARRAY_BUFFER, 0, this.idx, 0, this.nIdx);
|
|
6108
|
+
set.indexRects = rects;
|
|
6109
|
+
}
|
|
6006
6110
|
return this.nIdx;
|
|
6007
6111
|
}
|
|
6008
6112
|
reset() {
|
|
6009
6113
|
this.nVerts = 0;
|
|
6010
6114
|
this.nIdx = 0;
|
|
6115
|
+
this.pureRects = true;
|
|
6011
6116
|
}
|
|
6012
6117
|
dispose() {
|
|
6013
|
-
const
|
|
6014
|
-
|
|
6015
|
-
|
|
6016
|
-
|
|
6118
|
+
for (const set of [...this.ring, ...this.largeRing]) {
|
|
6119
|
+
if (set) this.deleteSet(set);
|
|
6120
|
+
}
|
|
6121
|
+
this.ring.fill(void 0);
|
|
6122
|
+
this.largeRing.fill(void 0);
|
|
6017
6123
|
}
|
|
6018
6124
|
/** Grow the CPU arrays so `vertices` / `indices` more fit. */
|
|
6019
6125
|
reserve(vertices, indices) {
|
|
6020
6126
|
const needVerts = (this.nVerts + vertices) * FLOATS_PER_VERTEX;
|
|
6021
6127
|
if (needVerts > this.verts.length) {
|
|
6022
|
-
|
|
6023
|
-
while (len < needVerts) len *= 2;
|
|
6024
|
-
const grown = new Float32Array(len);
|
|
6128
|
+
const grown = new Float32Array(doubledTo(this.verts.length, needVerts));
|
|
6025
6129
|
grown.set(this.verts);
|
|
6026
6130
|
this.verts = grown;
|
|
6027
6131
|
}
|
|
6028
6132
|
const needIdx = this.nIdx + indices;
|
|
6029
6133
|
if (needIdx > this.idx.length) {
|
|
6030
|
-
|
|
6031
|
-
while (len < needIdx) len *= 2;
|
|
6032
|
-
const grown = new Uint32Array(len);
|
|
6134
|
+
const grown = new Uint32Array(doubledTo(this.idx.length, needIdx));
|
|
6033
6135
|
grown.set(this.idx);
|
|
6034
6136
|
this.idx = grown;
|
|
6035
6137
|
}
|
|
6036
6138
|
}
|
|
6037
|
-
|
|
6038
|
-
|
|
6139
|
+
nextRingSlot() {
|
|
6140
|
+
const slot = this.next;
|
|
6141
|
+
this.next = (slot + 1) % SOLID_RING_SIZE;
|
|
6142
|
+
const existing = this.ring[slot];
|
|
6143
|
+
if (existing) return existing;
|
|
6144
|
+
const set = this.createSet(SOLID_RING_SLOT_VERTICES, SOLID_RING_SLOT_INDICES);
|
|
6145
|
+
this.ring[slot] = set;
|
|
6146
|
+
return set;
|
|
6147
|
+
}
|
|
6148
|
+
nextLargeSlot() {
|
|
6039
6149
|
const gl = this.gl;
|
|
6040
|
-
|
|
6041
|
-
|
|
6042
|
-
|
|
6043
|
-
|
|
6044
|
-
|
|
6045
|
-
|
|
6046
|
-
|
|
6047
|
-
|
|
6048
|
-
|
|
6049
|
-
|
|
6050
|
-
|
|
6051
|
-
|
|
6052
|
-
|
|
6150
|
+
const slot = this.nextLarge;
|
|
6151
|
+
this.nextLarge = (slot + 1) % SOLID_LARGE_RING_SIZE;
|
|
6152
|
+
let set = this.largeRing[slot];
|
|
6153
|
+
if (!set) {
|
|
6154
|
+
set = this.createSet(
|
|
6155
|
+
doubledTo(SOLID_RING_SLOT_VERTICES, this.nVerts),
|
|
6156
|
+
doubledTo(SOLID_RING_SLOT_INDICES, this.nIdx)
|
|
6157
|
+
);
|
|
6158
|
+
this.largeRing[slot] = set;
|
|
6159
|
+
return set;
|
|
6160
|
+
}
|
|
6161
|
+
if (this.nVerts > set.vertexCapacity) {
|
|
6162
|
+
set.vertexCapacity = doubledTo(set.vertexCapacity, this.nVerts);
|
|
6163
|
+
gl.bindBuffer(gl.ARRAY_BUFFER, set.vbo);
|
|
6164
|
+
gl.bufferData(gl.ARRAY_BUFFER, set.vertexCapacity * FLOATS_PER_VERTEX * 4, gl.DYNAMIC_DRAW);
|
|
6165
|
+
}
|
|
6166
|
+
if (this.nIdx > set.indexCapacity) {
|
|
6167
|
+
set.indexCapacity = doubledTo(set.indexCapacity, this.nIdx);
|
|
6168
|
+
gl.bindVertexArray(set.vao);
|
|
6169
|
+
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, set.ibo);
|
|
6170
|
+
gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, set.indexCapacity * 4, gl.DYNAMIC_DRAW);
|
|
6053
6171
|
gl.bindVertexArray(null);
|
|
6054
|
-
|
|
6172
|
+
set.indexRects = -1;
|
|
6055
6173
|
}
|
|
6174
|
+
return set;
|
|
6175
|
+
}
|
|
6176
|
+
createSet(vertices, indices) {
|
|
6177
|
+
const gl = this.gl;
|
|
6178
|
+
const vao = gl.createVertexArray();
|
|
6179
|
+
const vbo = gl.createBuffer();
|
|
6180
|
+
const ibo = gl.createBuffer();
|
|
6181
|
+
if (!vao || !vbo || !ibo) throw new Error("SolidBatch: failed to create GL objects");
|
|
6182
|
+
const stride = FLOATS_PER_VERTEX * 4;
|
|
6183
|
+
gl.bindVertexArray(vao);
|
|
6184
|
+
gl.bindBuffer(gl.ARRAY_BUFFER, vbo);
|
|
6185
|
+
gl.bufferData(gl.ARRAY_BUFFER, vertices * stride, gl.DYNAMIC_DRAW);
|
|
6186
|
+
gl.enableVertexAttribArray(this.aPos);
|
|
6187
|
+
gl.vertexAttribPointer(this.aPos, 2, gl.FLOAT, false, stride, 0);
|
|
6188
|
+
gl.enableVertexAttribArray(this.aColor);
|
|
6189
|
+
gl.vertexAttribPointer(this.aColor, 4, gl.FLOAT, false, stride, 8);
|
|
6190
|
+
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, ibo);
|
|
6191
|
+
gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, indices * 4, gl.DYNAMIC_DRAW);
|
|
6192
|
+
gl.bindVertexArray(null);
|
|
6193
|
+
return { vao, vbo, ibo, vertexCapacity: vertices, indexCapacity: indices, indexRects: -1 };
|
|
6194
|
+
}
|
|
6195
|
+
deleteSet(set) {
|
|
6196
|
+
const gl = this.gl;
|
|
6197
|
+
gl.deleteBuffer(set.vbo);
|
|
6198
|
+
gl.deleteBuffer(set.ibo);
|
|
6199
|
+
gl.deleteVertexArray(set.vao);
|
|
6056
6200
|
}
|
|
6057
6201
|
};
|
|
6058
6202
|
var FRAME_UPLOADS = /* @__PURE__ */ new WeakMap();
|
|
@@ -6075,6 +6219,25 @@ function sameValues(prev, next) {
|
|
|
6075
6219
|
for (let i = 0; i < prev.length; i++) if (prev[i] !== next[i]) return false;
|
|
6076
6220
|
return true;
|
|
6077
6221
|
}
|
|
6222
|
+
function setColorUniform(ctx, prog, r, g, b, a) {
|
|
6223
|
+
const loc = prog.uniform("u_color");
|
|
6224
|
+
if (loc === void 0) return;
|
|
6225
|
+
const uploaded = uploadedFor(ctx, prog);
|
|
6226
|
+
const prev = uploaded.color;
|
|
6227
|
+
if (prev !== void 0 && prev[0] === r && prev[1] === g && prev[2] === b && prev[3] === a) {
|
|
6228
|
+
return;
|
|
6229
|
+
}
|
|
6230
|
+
ctx.gl.uniform4f(loc, r, g, b, a);
|
|
6231
|
+
uploaded.color = [r, g, b, a];
|
|
6232
|
+
}
|
|
6233
|
+
function setAlphaUniform(ctx, prog, alpha) {
|
|
6234
|
+
const loc = prog.uniform("u_alpha");
|
|
6235
|
+
if (loc === void 0) return;
|
|
6236
|
+
const uploaded = uploadedFor(ctx, prog);
|
|
6237
|
+
if (uploaded.alpha === alpha) return;
|
|
6238
|
+
ctx.gl.uniform1f(loc, alpha);
|
|
6239
|
+
uploaded.alpha = alpha;
|
|
6240
|
+
}
|
|
6078
6241
|
var BATCH_MODEL = mat3.identity();
|
|
6079
6242
|
function projFor(ctx) {
|
|
6080
6243
|
let proj = FRAME_PROJ.get(ctx);
|
|
@@ -6367,8 +6530,8 @@ function flushSolids(ctx) {
|
|
|
6367
6530
|
gl.useProgram(prog.handle);
|
|
6368
6531
|
const indexCount = batch.uploadAndBind();
|
|
6369
6532
|
setProjAndModel(ctx, prog, BATCH_MODEL);
|
|
6370
|
-
|
|
6371
|
-
|
|
6533
|
+
setColorUniform(ctx, prog, 1, 1, 1, 1);
|
|
6534
|
+
setAlphaUniform(ctx, prog, staged.alpha);
|
|
6372
6535
|
setColorMatrixUniforms(ctx, prog, staged.colorMatrix);
|
|
6373
6536
|
applyClipTest(ctx, staged.clipDepth);
|
|
6374
6537
|
gl.drawElements(gl.TRIANGLES, indexCount, gl.UNSIGNED_INT, 0);
|
|
@@ -6433,10 +6596,9 @@ function setProjAndModel(ctx, prog, model = ctx.state.transform) {
|
|
|
6433
6596
|
}
|
|
6434
6597
|
}
|
|
6435
6598
|
function setSolidPaintUniforms(ctx, prog, color, opacity) {
|
|
6436
|
-
const gl = ctx.gl;
|
|
6437
6599
|
const [r, g, b, a] = resolveColor(color);
|
|
6438
|
-
|
|
6439
|
-
|
|
6600
|
+
setColorUniform(ctx, prog, r, g, b, a * (opacity ?? 1));
|
|
6601
|
+
setAlphaUniform(ctx, prog, ctx.state.alpha);
|
|
6440
6602
|
}
|
|
6441
6603
|
function drawPathFillByKind(ctx, fill, handle) {
|
|
6442
6604
|
const kind = fill.fill ?? "solid";
|
|
@@ -6482,7 +6644,7 @@ function drawPathFillPattern(ctx, fill, handle) {
|
|
|
6482
6644
|
ctx.textureCache.bind(tex.id, 0);
|
|
6483
6645
|
gl.uniform1i(ctx.patternFill.uniform("u_sampler"), 0);
|
|
6484
6646
|
gl.uniform1f(ctx.patternFill.uniform("u_opacity"), fill.opacity ?? 1);
|
|
6485
|
-
|
|
6647
|
+
setAlphaUniform(ctx, ctx.patternFill, ctx.state.alpha);
|
|
6486
6648
|
applyClipTest(ctx);
|
|
6487
6649
|
gl.drawElements(gl.TRIANGLES, handle.indexCount, gl.UNSIGNED_INT, 0);
|
|
6488
6650
|
gl.bindVertexArray(null);
|
|
@@ -6506,7 +6668,7 @@ function drawPathFillGradient(ctx, fill, handle) {
|
|
|
6506
6668
|
gl.uniformMatrix3fv(ctx.gradFill.uniform("u_worldInv"), false, gradientSpaceInverse(ctx, fill.units));
|
|
6507
6669
|
ctx.gradRampCache.bind(key, 0);
|
|
6508
6670
|
gl.uniform1i(ctx.gradFill.uniform("u_ramp"), 0);
|
|
6509
|
-
|
|
6671
|
+
setAlphaUniform(ctx, ctx.gradFill, ctx.state.alpha);
|
|
6510
6672
|
gl.uniform1f(ctx.gradFill.uniform("u_opacity"), fill.opacity ?? 1);
|
|
6511
6673
|
if (fill.fill === "linear-gradient") {
|
|
6512
6674
|
gl.uniform1i(ctx.gradFill.uniform("u_gradKind"), 0);
|
|
@@ -6656,6 +6818,7 @@ function drawPathStrokeUnclipped(ctx, cmd) {
|
|
|
6656
6818
|
gl.enableVertexAttribArray(aVColorLoc);
|
|
6657
6819
|
gl.vertexAttribPointer(aVColorLoc, 4, gl.FLOAT, false, 0, 0);
|
|
6658
6820
|
}
|
|
6821
|
+
applyClipTest(ctx);
|
|
6659
6822
|
gl.drawElements(gl.TRIANGLES, handle.indexCount, gl.UNSIGNED_INT, 0);
|
|
6660
6823
|
gl.bindVertexArray(null);
|
|
6661
6824
|
gl.deleteBuffer(colorVbo);
|
|
@@ -6771,7 +6934,7 @@ function drawText(ctx, cmd) {
|
|
|
6771
6934
|
preparedPrograms.add(prog);
|
|
6772
6935
|
setProjAndModel(ctx, prog);
|
|
6773
6936
|
setColorMatrixUniforms(ctx, prog);
|
|
6774
|
-
|
|
6937
|
+
setAlphaUniform(ctx, prog, ctx.state.alpha);
|
|
6775
6938
|
}
|
|
6776
6939
|
drawTextGroup(ctx, group, prog, dx, dy);
|
|
6777
6940
|
}
|
|
@@ -6889,8 +7052,8 @@ function drawTextDecorations(ctx, decorations, dx, dy) {
|
|
|
6889
7052
|
if (!ibo) throw new Error("drawTextDecorations: createBuffer (IBO) returned null");
|
|
6890
7053
|
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, ibo);
|
|
6891
7054
|
gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, indices, gl.DYNAMIC_DRAW);
|
|
6892
|
-
|
|
6893
|
-
|
|
7055
|
+
setColorUniform(ctx, prog, rgba[0], rgba[1], rgba[2], rgba[3]);
|
|
7056
|
+
setAlphaUniform(ctx, prog, ctx.state.alpha);
|
|
6894
7057
|
gl.drawElements(gl.TRIANGLES, indices.length, gl.UNSIGNED_INT, 0);
|
|
6895
7058
|
gl.bindVertexArray(null);
|
|
6896
7059
|
gl.deleteVertexArray(vao);
|
|
@@ -6974,7 +7137,7 @@ function drawTextGroup(ctx, group, prog, dx, dy) {
|
|
|
6974
7137
|
if ("color" in group.fill) {
|
|
6975
7138
|
[r, g, b, a] = resolveColor(group.fill.color);
|
|
6976
7139
|
}
|
|
6977
|
-
|
|
7140
|
+
setColorUniform(ctx, prog, r, g, b, a);
|
|
6978
7141
|
const synthBoldAmount = group.synthetic.bold ? 0.08 : 0;
|
|
6979
7142
|
const uSynthBold = prog.uniform("u_synthBold");
|
|
6980
7143
|
if (uSynthBold !== void 0) gl.uniform1f(uSynthBold, synthBoldAmount);
|
|
@@ -7078,7 +7241,7 @@ function drawImage(ctx, cmd) {
|
|
|
7078
7241
|
);
|
|
7079
7242
|
gl.uniform1i(prog.uniform("u_sampler"), 0);
|
|
7080
7243
|
gl.uniform1f(prog.uniform("u_opacity"), cmd.opacity ?? 1);
|
|
7081
|
-
|
|
7244
|
+
setAlphaUniform(ctx, prog, ctx.state.alpha);
|
|
7082
7245
|
applyClipTest(ctx);
|
|
7083
7246
|
gl.drawElements(gl.TRIANGLES, 6, gl.UNSIGNED_INT, 0);
|
|
7084
7247
|
gl.bindVertexArray(null);
|
|
@@ -7293,6 +7456,8 @@ var WeaselRenderer = class {
|
|
|
7293
7456
|
const program = new ShaderProgram(this.gl, vertSrc, fragSrc);
|
|
7294
7457
|
program.lookupUniforms([...CUSTOM_KIT_UNIFORMS, ...extractUniformNames(fragSrc)]);
|
|
7295
7458
|
program.lookupAttributes(CUSTOM_ATTRIBUTES);
|
|
7459
|
+
const previous = this.programRegistry.get(handle.id);
|
|
7460
|
+
if (previous) this.gl.deleteProgram(previous.handle);
|
|
7296
7461
|
this.programRegistry.set(handle.id, program);
|
|
7297
7462
|
}
|
|
7298
7463
|
applyViewport() {
|
|
@@ -7390,7 +7555,7 @@ var WeaselRenderer = class {
|
|
|
7390
7555
|
}
|
|
7391
7556
|
this.meshCache.freeTransient();
|
|
7392
7557
|
this.meshCache.drainPendingDeletes();
|
|
7393
|
-
for (const prog of [this.pathFill, this.pathFillVColor, this.textSdf, this.textSdfR8, this.imageFill, this.gradFill]) {
|
|
7558
|
+
for (const prog of [this.pathFill, this.pathFillVColor, this.textSdf, this.textSdfR8, this.imageFill, this.gradFill, this.patternFill]) {
|
|
7394
7559
|
gl.deleteProgram(prog.handle);
|
|
7395
7560
|
}
|
|
7396
7561
|
for (const prog of this.programRegistry.values()) {
|
|
@@ -7417,6 +7582,7 @@ var WeaselRenderer = class {
|
|
|
7417
7582
|
const gl = this.gl;
|
|
7418
7583
|
this.meshCache.drainPendingDeletes();
|
|
7419
7584
|
resetBakeBudget(this.bakeBudget);
|
|
7585
|
+
this.groupState.reset();
|
|
7420
7586
|
gl.stencilMask(255);
|
|
7421
7587
|
gl.clear(gl.COLOR_BUFFER_BIT | gl.STENCIL_BUFFER_BIT);
|
|
7422
7588
|
const ctx = {
|
|
@@ -7886,7 +8052,7 @@ var IDENTITY_POSE_COMPOSITION = {
|
|
|
7886
8052
|
compose: (_parent, child) => child,
|
|
7887
8053
|
decompose: (_parent, world) => world
|
|
7888
8054
|
};
|
|
7889
|
-
function composeWorldPose(adapter, id,
|
|
8055
|
+
function composeWorldPose(adapter, id, compose2) {
|
|
7890
8056
|
const chain = [id];
|
|
7891
8057
|
const seen = /* @__PURE__ */ new Set([id]);
|
|
7892
8058
|
let cursor = adapter.getParent(id);
|
|
@@ -7898,16 +8064,16 @@ function composeWorldPose(adapter, id, compose) {
|
|
|
7898
8064
|
}
|
|
7899
8065
|
let world = adapter.getPose(chain[chain.length - 1]);
|
|
7900
8066
|
for (let i = chain.length - 2; i >= 0; i--) {
|
|
7901
|
-
world =
|
|
8067
|
+
world = compose2(world, adapter.getPose(chain[i]));
|
|
7902
8068
|
}
|
|
7903
8069
|
return world;
|
|
7904
8070
|
}
|
|
7905
8071
|
function translateRectPose(pose, dx, dy) {
|
|
7906
8072
|
return { ...pose, x: pose.x + dx, y: pose.y + dy };
|
|
7907
8073
|
}
|
|
7908
|
-
function rebaseLocalPose(adapter, worldPose, newParentId,
|
|
8074
|
+
function rebaseLocalPose(adapter, worldPose, newParentId, compose2, decompose) {
|
|
7909
8075
|
if (newParentId === null) return worldPose;
|
|
7910
|
-
const parentWorld = composeWorldPose(adapter, newParentId,
|
|
8076
|
+
const parentWorld = composeWorldPose(adapter, newParentId, compose2);
|
|
7911
8077
|
return decompose(parentWorld, worldPose);
|
|
7912
8078
|
}
|
|
7913
8079
|
function translatePoseGeneric(pose, dx, dy, projection) {
|
|
@@ -10802,9 +10968,17 @@ function arraysEqual(a, b) {
|
|
|
10802
10968
|
return true;
|
|
10803
10969
|
}
|
|
10804
10970
|
function createPartitionedReorderOp(args) {
|
|
10805
|
-
const { ids, fn, label } = args;
|
|
10806
|
-
|
|
10971
|
+
const { ids, direction, fn, label, prevOrders } = args;
|
|
10972
|
+
const argsForSerial = {
|
|
10973
|
+
ids,
|
|
10974
|
+
direction,
|
|
10975
|
+
label,
|
|
10976
|
+
prevOrders: prevOrders ? prevOrders.map((e) => ({ ...e, before: e.before.slice() })) : void 0
|
|
10977
|
+
};
|
|
10978
|
+
let restore = prevOrders ? prevOrders.map((e) => ({ ...e, before: e.before.slice() })) : null;
|
|
10807
10979
|
return {
|
|
10980
|
+
name: "reorder",
|
|
10981
|
+
args: argsForSerial,
|
|
10808
10982
|
label,
|
|
10809
10983
|
apply(adapter) {
|
|
10810
10984
|
const a = adapter;
|
|
@@ -10827,6 +11001,7 @@ function createPartitionedReorderOp(args) {
|
|
|
10827
11001
|
mutated = true;
|
|
10828
11002
|
}
|
|
10829
11003
|
restore = snapshots;
|
|
11004
|
+
argsForSerial.prevOrders = snapshots.map((e) => ({ ...e, before: e.before.slice() }));
|
|
10830
11005
|
return mutated;
|
|
10831
11006
|
},
|
|
10832
11007
|
invert() {
|
|
@@ -10858,10 +11033,17 @@ var REORDER_DIRECTIONS = {
|
|
|
10858
11033
|
back: { fn: sendToBack, defaultLabel: "Send to back" }
|
|
10859
11034
|
};
|
|
10860
11035
|
function createReorderOp(args) {
|
|
10861
|
-
const { ids, direction, label } = args;
|
|
11036
|
+
const { ids, direction, label, prevOrders } = args;
|
|
10862
11037
|
const { fn, defaultLabel } = REORDER_DIRECTIONS[direction];
|
|
10863
|
-
return createPartitionedReorderOp({
|
|
11038
|
+
return createPartitionedReorderOp({
|
|
11039
|
+
ids,
|
|
11040
|
+
direction,
|
|
11041
|
+
fn,
|
|
11042
|
+
label: label ?? defaultLabel,
|
|
11043
|
+
prevOrders
|
|
11044
|
+
});
|
|
10864
11045
|
}
|
|
11046
|
+
registerOpFactory("reorder", (args) => createReorderOp(args));
|
|
10865
11047
|
function createMoveToIndexOp(args) {
|
|
10866
11048
|
const { ids, parentId, index, label } = args;
|
|
10867
11049
|
const argsForSerial = {
|
|
@@ -10986,7 +11168,7 @@ var reorderBackwardAction = {
|
|
|
10986
11168
|
}
|
|
10987
11169
|
],
|
|
10988
11170
|
eligible: { capability: "edits-page" },
|
|
10989
|
-
requires: ["selection", "scene"],
|
|
11171
|
+
requires: ["selection", "scene", "applyOps"],
|
|
10990
11172
|
invoker: {
|
|
10991
11173
|
timing: "immediate",
|
|
10992
11174
|
run: (deps, params) => {
|
|
@@ -11126,6 +11308,7 @@ function makeAlignAction(edge) {
|
|
|
11126
11308
|
icon: ICON_FOR[edge],
|
|
11127
11309
|
group: "align",
|
|
11128
11310
|
eligible: { capability: "transforms-selection" },
|
|
11311
|
+
requires: ["selection", "scene"],
|
|
11129
11312
|
// No default keybindings — six edges/centers don't fit a clean default
|
|
11130
11313
|
// chord set. Wire bindings explicitly via the actions registry override map.
|
|
11131
11314
|
invoker: {
|
|
@@ -11137,7 +11320,14 @@ function makeAlignAction(edge) {
|
|
|
11137
11320
|
alignSelection(selection, scene, edge);
|
|
11138
11321
|
}
|
|
11139
11322
|
},
|
|
11140
|
-
|
|
11323
|
+
// Deps-aware, matching `alignSelection`'s own `ids.length < 2` guard: a
|
|
11324
|
+
// constant disabled reason greys the entry out forever (see
|
|
11325
|
+
// `requiresSelection`).
|
|
11326
|
+
enabled: (deps) => {
|
|
11327
|
+
const selection = deps?.selection;
|
|
11328
|
+
const count = selection?.get().length ?? 0;
|
|
11329
|
+
return count >= 2 ? true : ActionDisabledReason.SelectionRequired;
|
|
11330
|
+
}
|
|
11141
11331
|
};
|
|
11142
11332
|
}
|
|
11143
11333
|
var alignLeftAction = makeAlignAction("left");
|
|
@@ -11218,6 +11408,7 @@ function makeDistributeAction(axis) {
|
|
|
11218
11408
|
icon: ICON_FOR2[axis],
|
|
11219
11409
|
group: "distribute",
|
|
11220
11410
|
eligible: { capability: "transforms-selection" },
|
|
11411
|
+
requires: ["selection", "scene"],
|
|
11221
11412
|
// No default keybindings. Wire bindings explicitly via the actions registry.
|
|
11222
11413
|
invoker: {
|
|
11223
11414
|
timing: "immediate",
|
|
@@ -11228,7 +11419,14 @@ function makeDistributeAction(axis) {
|
|
|
11228
11419
|
distributeSelection(selection, scene, axis);
|
|
11229
11420
|
}
|
|
11230
11421
|
},
|
|
11231
|
-
|
|
11422
|
+
// Deps-aware, matching `distributeSelection`'s own `ids.length < 3` guard:
|
|
11423
|
+
// a constant disabled reason greys the entry out forever (see
|
|
11424
|
+
// `requiresSelection`).
|
|
11425
|
+
enabled: (deps) => {
|
|
11426
|
+
const selection = deps?.selection;
|
|
11427
|
+
const count = selection?.get().length ?? 0;
|
|
11428
|
+
return count >= 3 ? true : ActionDisabledReason.SelectionRequired;
|
|
11429
|
+
}
|
|
11232
11430
|
};
|
|
11233
11431
|
}
|
|
11234
11432
|
var distributeHorizontalAction = makeDistributeAction("x");
|
|
@@ -11310,7 +11508,91 @@ function pathToMultiPolygon(path, opts = {}) {
|
|
|
11310
11508
|
}
|
|
11311
11509
|
finalizeCurrent();
|
|
11312
11510
|
if (rings.length === 0) return [];
|
|
11313
|
-
return rings.
|
|
11511
|
+
return groupRings(rings, path.fillRule);
|
|
11512
|
+
}
|
|
11513
|
+
function ringSignedArea(ring) {
|
|
11514
|
+
let a = 0;
|
|
11515
|
+
for (let i = 0, n = ring.length - 1; i < n; i++) {
|
|
11516
|
+
a += ring[i][0] * ring[i + 1][1] - ring[i + 1][0] * ring[i][1];
|
|
11517
|
+
}
|
|
11518
|
+
return a * 0.5;
|
|
11519
|
+
}
|
|
11520
|
+
function ringBox(ring) {
|
|
11521
|
+
let minX = Infinity, minY = Infinity, maxX = -Infinity, maxY = -Infinity;
|
|
11522
|
+
for (const [x, y] of ring) {
|
|
11523
|
+
if (x < minX) minX = x;
|
|
11524
|
+
if (x > maxX) maxX = x;
|
|
11525
|
+
if (y < minY) minY = y;
|
|
11526
|
+
if (y > maxY) maxY = y;
|
|
11527
|
+
}
|
|
11528
|
+
return [minX, minY, maxX, maxY];
|
|
11529
|
+
}
|
|
11530
|
+
function pointInRing(ring, px, py) {
|
|
11531
|
+
let inside = false;
|
|
11532
|
+
for (let i = 0, n = ring.length - 1; i < n; i++) {
|
|
11533
|
+
const [ax, ay] = ring[i];
|
|
11534
|
+
const [bx, by] = ring[i + 1];
|
|
11535
|
+
if (ay > py !== by > py && px < (bx - ax) * (py - ay) / (by - ay) + ax) {
|
|
11536
|
+
inside = !inside;
|
|
11537
|
+
}
|
|
11538
|
+
}
|
|
11539
|
+
return inside;
|
|
11540
|
+
}
|
|
11541
|
+
function ringContains(outer, outerBox, inner, innerBox) {
|
|
11542
|
+
if (innerBox[0] < outerBox[0] || innerBox[1] < outerBox[1] || innerBox[2] > outerBox[2] || innerBox[3] > outerBox[3]) return false;
|
|
11543
|
+
const n = inner.length - 1;
|
|
11544
|
+
let votes = 0;
|
|
11545
|
+
for (const k of [0, Math.floor(n / 3), Math.floor(2 * n / 3)]) {
|
|
11546
|
+
if (pointInRing(outer, inner[k][0], inner[k][1])) votes++;
|
|
11547
|
+
}
|
|
11548
|
+
return votes >= 2;
|
|
11549
|
+
}
|
|
11550
|
+
function groupRings(rings, fillRule) {
|
|
11551
|
+
const n = rings.length;
|
|
11552
|
+
if (n === 1) return [[rings[0]]];
|
|
11553
|
+
const boxes = rings.map(ringBox);
|
|
11554
|
+
const orient = rings.map((r) => ringSignedArea(r) >= 0 ? 1 : -1);
|
|
11555
|
+
const parent = new Array(n).fill(-1);
|
|
11556
|
+
const children = rings.map(() => []);
|
|
11557
|
+
for (let i = 0; i < n; i++) {
|
|
11558
|
+
let best = -1;
|
|
11559
|
+
let bestArea = Infinity;
|
|
11560
|
+
for (let j = 0; j < n; j++) {
|
|
11561
|
+
if (i === j) continue;
|
|
11562
|
+
if (!ringContains(rings[j], boxes[j], rings[i], boxes[i])) continue;
|
|
11563
|
+
const area = (boxes[j][2] - boxes[j][0]) * (boxes[j][3] - boxes[j][1]);
|
|
11564
|
+
if (area < bestArea) {
|
|
11565
|
+
bestArea = area;
|
|
11566
|
+
best = j;
|
|
11567
|
+
}
|
|
11568
|
+
}
|
|
11569
|
+
parent[i] = best;
|
|
11570
|
+
}
|
|
11571
|
+
for (let i = 0; i < n; i++) if (parent[i] >= 0) children[parent[i]].push(i);
|
|
11572
|
+
const filled = new Array(n);
|
|
11573
|
+
for (let i = 0; i < n; i++) {
|
|
11574
|
+
let depth = 0;
|
|
11575
|
+
let winding = 0;
|
|
11576
|
+
for (let a = i; a >= 0; a = parent[a]) {
|
|
11577
|
+
winding += orient[a];
|
|
11578
|
+
if (a !== i) depth++;
|
|
11579
|
+
}
|
|
11580
|
+
filled[i] = fillRule === "evenodd" ? depth % 2 === 0 : winding !== 0;
|
|
11581
|
+
}
|
|
11582
|
+
const out = [];
|
|
11583
|
+
for (let i = 0; i < n; i++) {
|
|
11584
|
+
if (!filled[i]) continue;
|
|
11585
|
+
if (parent[i] >= 0 && filled[parent[i]]) continue;
|
|
11586
|
+
const polygon = [rings[i]];
|
|
11587
|
+
const queue = [...children[i]];
|
|
11588
|
+
while (queue.length > 0) {
|
|
11589
|
+
const c = queue.pop();
|
|
11590
|
+
if (filled[c]) queue.push(...children[c]);
|
|
11591
|
+
else polygon.push(rings[c]);
|
|
11592
|
+
}
|
|
11593
|
+
out.push(polygon);
|
|
11594
|
+
}
|
|
11595
|
+
return out;
|
|
11314
11596
|
}
|
|
11315
11597
|
function multiPolygonToPath(mp) {
|
|
11316
11598
|
let nCmds = 0;
|
|
@@ -11623,6 +11905,7 @@ function makePathfinderAction(op) {
|
|
|
11623
11905
|
icon: ICON_FOR3[op],
|
|
11624
11906
|
group: "pathfinder",
|
|
11625
11907
|
eligible: { capability: "creates-shapes" },
|
|
11908
|
+
requires: ["selection", "booleansAdapter"],
|
|
11626
11909
|
// No default keybindings — there's no industry-standard chord set for
|
|
11627
11910
|
// boolean ops. Wire bindings explicitly via the actions registry override map.
|
|
11628
11911
|
invoker: {
|
|
@@ -13915,10 +14198,11 @@ function createDispatcher(opts) {
|
|
|
13915
14198
|
uiOngoingByAction.set(actionId, gestureId);
|
|
13916
14199
|
notify2();
|
|
13917
14200
|
let ended = false;
|
|
14201
|
+
const live = () => !ended && inFlightHandles.get(gestureId) === handle;
|
|
13918
14202
|
return {
|
|
13919
14203
|
gestureId,
|
|
13920
14204
|
update(nextParams) {
|
|
13921
|
-
if (
|
|
14205
|
+
if (!live()) return;
|
|
13922
14206
|
if (!handle.onMove) return;
|
|
13923
14207
|
try {
|
|
13924
14208
|
handle.onMove(buildUiInvocationCtx(deps, nextParams));
|
|
@@ -13928,7 +14212,10 @@ function createDispatcher(opts) {
|
|
|
13928
14212
|
notify2();
|
|
13929
14213
|
},
|
|
13930
14214
|
end(reason) {
|
|
13931
|
-
if (
|
|
14215
|
+
if (!live()) {
|
|
14216
|
+
ended = true;
|
|
14217
|
+
return;
|
|
14218
|
+
}
|
|
13932
14219
|
ended = true;
|
|
13933
14220
|
if (handle.onEnd) {
|
|
13934
14221
|
try {
|
|
@@ -15142,6 +15429,7 @@ function useTools(opts) {
|
|
|
15142
15429
|
);
|
|
15143
15430
|
const active = contributions.focused;
|
|
15144
15431
|
const getActiveOverlays = contributions.overlays;
|
|
15432
|
+
const registryKey = Object.keys(slotted.registry).sort().join("|") + "#" + slotted.ambient.map((t) => t.id).join("|");
|
|
15145
15433
|
return useMemo(
|
|
15146
15434
|
() => ({
|
|
15147
15435
|
active,
|
|
@@ -15154,7 +15442,7 @@ function useTools(opts) {
|
|
|
15154
15442
|
has,
|
|
15155
15443
|
getActiveOverlays
|
|
15156
15444
|
}),
|
|
15157
|
-
[active, setActive, hotkeyEngaged, engageHotkey, disengageHotkey, has, getActiveOverlays]
|
|
15445
|
+
[active, setActive, hotkeyEngaged, engageHotkey, disengageHotkey, has, getActiveOverlays, registryKey]
|
|
15158
15446
|
);
|
|
15159
15447
|
}
|
|
15160
15448
|
var TOOL_ACTIVATE_ID = "tool.activate";
|
|
@@ -16545,8 +16833,17 @@ function composeAffordanceLayer(id, label, affordances) {
|
|
|
16545
16833
|
// `buildAffordanceAt` share one implementation rather than two that can
|
|
16546
16834
|
// drift. This wrapper lifts the region's declared cursor and claim onto
|
|
16547
16835
|
// the binding, the way `buildAffordanceAt` lifts them onto `AffordanceHit`.
|
|
16548
|
-
hitTest: (wx, wy,
|
|
16549
|
-
const
|
|
16836
|
+
hitTest: (wx, wy, data, view, _dims, isVisible) => {
|
|
16837
|
+
const state = asChromeState(data);
|
|
16838
|
+
if (!state) return null;
|
|
16839
|
+
const hit = hitAffordanceRegions(
|
|
16840
|
+
affordances,
|
|
16841
|
+
wx,
|
|
16842
|
+
wy,
|
|
16843
|
+
state,
|
|
16844
|
+
view,
|
|
16845
|
+
isVisible ?? asIsVisible(data) ?? void 0
|
|
16846
|
+
);
|
|
16550
16847
|
if (!hit) return null;
|
|
16551
16848
|
const { cursor, strength, claimedKinds } = hit.region;
|
|
16552
16849
|
return {
|
|
@@ -17149,6 +17446,10 @@ function usePenTool(options) {
|
|
|
17149
17446
|
onEnd: (endCtx, reason) => {
|
|
17150
17447
|
const se = s();
|
|
17151
17448
|
if (reason === "cancel") {
|
|
17449
|
+
if (se.current && se.draggingHandleAt === se.current.anchors.length - 1) {
|
|
17450
|
+
se.current.anchors.pop();
|
|
17451
|
+
if (se.current.anchors.length === 0) se.current = null;
|
|
17452
|
+
}
|
|
17152
17453
|
se.draggingHandleAt = null;
|
|
17153
17454
|
forceRenderRef.current();
|
|
17154
17455
|
return;
|
|
@@ -17991,7 +18292,7 @@ function makeContainerAwareBoundsResolver(getPose, getBounds, getChildren, isCon
|
|
|
17991
18292
|
const visit = (nid) => {
|
|
17992
18293
|
const kids = getChildren(nid);
|
|
17993
18294
|
if (kids.length === 0) {
|
|
17994
|
-
out.push(nid);
|
|
18295
|
+
if (!isContainer(nid)) out.push(nid);
|
|
17995
18296
|
return;
|
|
17996
18297
|
}
|
|
17997
18298
|
for (const k of kids) visit(k);
|
|
@@ -18727,7 +19028,6 @@ function CanvasInner(props, ref) {
|
|
|
18727
19028
|
shaders,
|
|
18728
19029
|
previewIdsExtra,
|
|
18729
19030
|
previewPoseExtra,
|
|
18730
|
-
previewBoundsExtra,
|
|
18731
19031
|
gestureSource,
|
|
18732
19032
|
viewport,
|
|
18733
19033
|
backgroundFill,
|
|
@@ -18753,6 +19053,7 @@ function CanvasInner(props, ref) {
|
|
|
18753
19053
|
debugSinkRefForCtx.current = debugSink;
|
|
18754
19054
|
const adapter = adapterProp;
|
|
18755
19055
|
const canvasRef = useRef(null);
|
|
19056
|
+
const helpersForLayersRef = useRef(null);
|
|
18756
19057
|
const dimsRef = useRef({ width, height });
|
|
18757
19058
|
dimsRef.current = { width, height };
|
|
18758
19059
|
const getIsVisibleRef = useRef(getIsVisible);
|
|
@@ -18775,7 +19076,7 @@ function CanvasInner(props, ref) {
|
|
|
18775
19076
|
const isVisible = getIsVisibleRef.current?.() ?? alwaysVisible;
|
|
18776
19077
|
for (const layer of layers2) {
|
|
18777
19078
|
if (!layer.hitTest) continue;
|
|
18778
|
-
const hit = layer.hitTest(worldX, worldY,
|
|
19079
|
+
const hit = layer.hitTest(worldX, worldY, helpersForLayersRef.current, view, dims, isVisible);
|
|
18779
19080
|
if (hit) return { layerId: layer.id, hit };
|
|
18780
19081
|
}
|
|
18781
19082
|
return null;
|
|
@@ -18930,8 +19231,8 @@ function CanvasInner(props, ref) {
|
|
|
18930
19231
|
};
|
|
18931
19232
|
const selectedIdsForWiring = effectiveSelection.current;
|
|
18932
19233
|
const multiActive2 = selectedIdsForWiring.length > 1;
|
|
18933
|
-
const previewExtraRef = useRef({ previewPoseExtra
|
|
18934
|
-
previewExtraRef.current = { previewPoseExtra
|
|
19234
|
+
const previewExtraRef = useRef({ previewPoseExtra });
|
|
19235
|
+
previewExtraRef.current = { previewPoseExtra };
|
|
18935
19236
|
const effectiveBoundsOf = useMemo(() => {
|
|
18936
19237
|
return boundsOf2 ?? baseBoundsOf;
|
|
18937
19238
|
}, [boundsOf2, baseBoundsOf]);
|
|
@@ -18950,10 +19251,6 @@ function CanvasInner(props, ref) {
|
|
|
18950
19251
|
if (p != null) return geometry.getBounds(p);
|
|
18951
19252
|
}
|
|
18952
19253
|
const extras = previewExtraRef.current;
|
|
18953
|
-
if (extras.previewBoundsExtra) {
|
|
18954
|
-
const b = extras.previewBoundsExtra(id);
|
|
18955
|
-
if (b) return b;
|
|
18956
|
-
}
|
|
18957
19254
|
if (extras.previewPoseExtra) {
|
|
18958
19255
|
const p = extras.previewPoseExtra(id);
|
|
18959
19256
|
if (p != null) return geometry.getBounds(p);
|
|
@@ -18994,10 +19291,6 @@ function CanvasInner(props, ref) {
|
|
|
18994
19291
|
const p = firstPreviewPose(tools, id);
|
|
18995
19292
|
if (p != null) return geometry.getBounds(p);
|
|
18996
19293
|
}
|
|
18997
|
-
if (previewBoundsExtra) {
|
|
18998
|
-
const b = previewBoundsExtra(id);
|
|
18999
|
-
if (b) return b;
|
|
19000
|
-
}
|
|
19001
19294
|
if (previewPoseExtra) {
|
|
19002
19295
|
const p = previewPoseExtra(id);
|
|
19003
19296
|
if (p != null) return geometry.getBounds(p);
|
|
@@ -19033,6 +19326,7 @@ function CanvasInner(props, ref) {
|
|
|
19033
19326
|
getDebug: () => debugSink,
|
|
19034
19327
|
getIsVisible: () => getIsVisibleRef.current?.() ?? alwaysVisible
|
|
19035
19328
|
};
|
|
19329
|
+
helpersForLayersRef.current = helpersForLayers;
|
|
19036
19330
|
if (helpersRef) helpersRef.current = helpersForLayers;
|
|
19037
19331
|
const pointerDownRef = useRef(false);
|
|
19038
19332
|
const handlePointerDown = (e) => {
|
|
@@ -19214,6 +19508,11 @@ function CanvasInner(props, ref) {
|
|
|
19214
19508
|
);
|
|
19215
19509
|
renderer.render(commands, viewToMat3(effectiveView));
|
|
19216
19510
|
}, [layersWithDebug, width, height, effectiveView, debugSink, redrawNonce, dprProp]);
|
|
19511
|
+
useEffect(() => () => {
|
|
19512
|
+
glRendererRef.current?.dispose();
|
|
19513
|
+
glRendererRef.current = null;
|
|
19514
|
+
lastResizeRef.current = null;
|
|
19515
|
+
}, []);
|
|
19217
19516
|
const shaderIdKey = shaders?.map((h) => h.id).join("|") ?? "";
|
|
19218
19517
|
useEffect(() => {
|
|
19219
19518
|
const renderer = glRendererRef.current;
|
|
@@ -20642,6 +20941,89 @@ function poseContainsRotated(pose, wx, wy, tolerance) {
|
|
|
20642
20941
|
}
|
|
20643
20942
|
return poseContains(pose, wx, wy, tolerance);
|
|
20644
20943
|
}
|
|
20944
|
+
function hiddenLayerIds(layers) {
|
|
20945
|
+
const out = /* @__PURE__ */ new Set();
|
|
20946
|
+
for (const layer of layers ?? []) {
|
|
20947
|
+
if (layer.visible === false) out.add(layer.id);
|
|
20948
|
+
}
|
|
20949
|
+
return out;
|
|
20950
|
+
}
|
|
20951
|
+
function hitTestArea(scene, bounds) {
|
|
20952
|
+
const { x, y, width: w, height: h } = bounds;
|
|
20953
|
+
const area = [x, y, x + w, y, x + w, y + h, x, y + h];
|
|
20954
|
+
return hitTestAreaPolygon(scene, area, { x, y, width: w, height: h }, true);
|
|
20955
|
+
}
|
|
20956
|
+
function hitTestAreaPolygon(scene, area, areaBounds, areaIsRect = false) {
|
|
20957
|
+
const ab = areaBounds ?? boundsOf(area);
|
|
20958
|
+
if (!ab) return [];
|
|
20959
|
+
const hits = [];
|
|
20960
|
+
const hidden = hiddenLayerIds(scene.layers);
|
|
20961
|
+
const order = scene.renderOrderNodes();
|
|
20962
|
+
for (let i = 0; i < order.length; i++) {
|
|
20963
|
+
const node = order[i];
|
|
20964
|
+
if (node.kind === "container") continue;
|
|
20965
|
+
if (hidden.size > 0 && hidden.has(node.layer)) continue;
|
|
20966
|
+
const pose = node.pose;
|
|
20967
|
+
const silhouette = pose !== null && typeof pose === "object" && pose.kind === "polygon";
|
|
20968
|
+
const b = silhouette ? nodeMemo(node, "aabb", pose, () => aabbOfPose(pose)) : aabbOfPose(pose);
|
|
20969
|
+
if (!Number.isFinite(b.x) || !Number.isFinite(b.y) || !Number.isFinite(b.width) || !Number.isFinite(b.height)) {
|
|
20970
|
+
continue;
|
|
20971
|
+
}
|
|
20972
|
+
if (b.x >= ab.x + ab.width || b.x + b.width <= ab.x || b.y >= ab.y + ab.height || b.y + b.height <= ab.y) {
|
|
20973
|
+
continue;
|
|
20974
|
+
}
|
|
20975
|
+
if (areaIsRect && b.x >= ab.x && b.y >= ab.y && b.x + b.width <= ab.x + ab.width && b.y + b.height <= ab.y + ab.height) {
|
|
20976
|
+
hits.push(node.id);
|
|
20977
|
+
continue;
|
|
20978
|
+
}
|
|
20979
|
+
if (silhouette) {
|
|
20980
|
+
if (silhouetteOverlapsArea(pose.coords, area)) {
|
|
20981
|
+
hits.push(node.id);
|
|
20982
|
+
}
|
|
20983
|
+
continue;
|
|
20984
|
+
}
|
|
20985
|
+
const drawn = findShapeSilhouette(node, pose);
|
|
20986
|
+
if (drawn?.kind === "polygon") {
|
|
20987
|
+
if (silhouetteOverlapsArea(drawn.coords, area)) hits.push(node.id);
|
|
20988
|
+
continue;
|
|
20989
|
+
}
|
|
20990
|
+
hits.push(node.id);
|
|
20991
|
+
}
|
|
20992
|
+
return hits;
|
|
20993
|
+
}
|
|
20994
|
+
function silhouetteOverlapsArea(sil, area) {
|
|
20995
|
+
const ns = sil.length >> 1;
|
|
20996
|
+
const na = area.length >> 1;
|
|
20997
|
+
if (ns < 1 || na < 3) return false;
|
|
20998
|
+
for (let i = 0; i < ns; i++) {
|
|
20999
|
+
if (pointInPolygon(area, sil[i * 2], sil[i * 2 + 1])) return true;
|
|
21000
|
+
}
|
|
21001
|
+
for (let i = 0; i < na; i++) {
|
|
21002
|
+
if (pointInPolygon(sil, area[i * 2], area[i * 2 + 1])) return true;
|
|
21003
|
+
}
|
|
21004
|
+
for (let i = 0, j = ns - 1; i < ns; j = i++) {
|
|
21005
|
+
const ax = sil[j * 2], ay = sil[j * 2 + 1];
|
|
21006
|
+
const bx = sil[i * 2], by = sil[i * 2 + 1];
|
|
21007
|
+
for (let k = 0, l = na - 1; k < na; l = k++) {
|
|
21008
|
+
const cx = area[l * 2], cy = area[l * 2 + 1];
|
|
21009
|
+
const dx = area[k * 2], dy = area[k * 2 + 1];
|
|
21010
|
+
if (segmentsCross(ax, ay, bx, by, cx, cy, dx, dy)) return true;
|
|
21011
|
+
}
|
|
21012
|
+
}
|
|
21013
|
+
return false;
|
|
21014
|
+
}
|
|
21015
|
+
function boundsOf(coords) {
|
|
21016
|
+
if (coords.length < 2) return null;
|
|
21017
|
+
let minX = Infinity, minY = Infinity, maxX = -Infinity, maxY = -Infinity;
|
|
21018
|
+
for (let i = 0; i + 1 < coords.length; i += 2) {
|
|
21019
|
+
const x = coords[i], y = coords[i + 1];
|
|
21020
|
+
if (x < minX) minX = x;
|
|
21021
|
+
if (y < minY) minY = y;
|
|
21022
|
+
if (x > maxX) maxX = x;
|
|
21023
|
+
if (y > maxY) maxY = y;
|
|
21024
|
+
}
|
|
21025
|
+
return { x: minX, y: minY, width: maxX - minX, height: maxY - minY };
|
|
21026
|
+
}
|
|
20645
21027
|
var DEFAULT_PICK_TOLERANCE_PX = 4;
|
|
20646
21028
|
function useSceneSelectTool(args) {
|
|
20647
21029
|
const { scene, selection, geometry, selectTool: opts, insertTool, layouts, getView } = args;
|
|
@@ -20739,7 +21121,9 @@ function useSceneSelectTool(args) {
|
|
|
20739
21121
|
}
|
|
20740
21122
|
const tolerance = pickTolerancePx / meanScale(getView?.()?.scale ?? { x: 1, y: 1 });
|
|
20741
21123
|
const out = [];
|
|
21124
|
+
const hidden = hiddenLayerIds(scene.layers);
|
|
20742
21125
|
for (const n of scene.renderOrderNodes()) {
|
|
21126
|
+
if (hidden.size > 0 && hidden.has(n.layer)) continue;
|
|
20743
21127
|
if (!poseContainsRotated(n.pose, wx, wy, tolerance)) continue;
|
|
20744
21128
|
if (shapePicking && !shapeCoversPoint(n, n.pose, wx, wy, { tolerance })) continue;
|
|
20745
21129
|
out.push(n.id);
|
|
@@ -21623,8 +22007,10 @@ function createPathAnchorAffordances(getAnchorState, opts = {}) {
|
|
|
21623
22007
|
const anchors = {
|
|
21624
22008
|
id: PATH_ANCHOR_CHROME_ID,
|
|
21625
22009
|
regions(state) {
|
|
22010
|
+
const editingId = getAnchorState()?.editingId ?? null;
|
|
21626
22011
|
const out = [];
|
|
21627
22012
|
for (const { id, path } of editablePaths(state)) {
|
|
22013
|
+
if (editingId !== null && id !== editingId) continue;
|
|
21628
22014
|
for (const a of enumerateAnchors(path)) {
|
|
21629
22015
|
out.push(point(
|
|
21630
22016
|
`${id}:anchor:${a.anchorIndex}`,
|
|
@@ -21879,80 +22265,6 @@ function DepRegistryProviderIfRoot({ children }) {
|
|
|
21879
22265
|
if (parent) return /* @__PURE__ */ jsx(Fragment, { children });
|
|
21880
22266
|
return /* @__PURE__ */ jsx(DepRegistryProvider, { children });
|
|
21881
22267
|
}
|
|
21882
|
-
function hitTestArea(scene, bounds) {
|
|
21883
|
-
const { x, y, width: w, height: h } = bounds;
|
|
21884
|
-
const area = [x, y, x + w, y, x + w, y + h, x, y + h];
|
|
21885
|
-
return hitTestAreaPolygon(scene, area, { x, y, width: w, height: h }, true);
|
|
21886
|
-
}
|
|
21887
|
-
function hitTestAreaPolygon(scene, area, areaBounds, areaIsRect = false) {
|
|
21888
|
-
const ab = areaBounds ?? boundsOf(area);
|
|
21889
|
-
if (!ab) return [];
|
|
21890
|
-
const hits = [];
|
|
21891
|
-
const order = scene.renderOrderNodes();
|
|
21892
|
-
for (let i = 0; i < order.length; i++) {
|
|
21893
|
-
const node = order[i];
|
|
21894
|
-
if (node.kind === "container") continue;
|
|
21895
|
-
const pose = node.pose;
|
|
21896
|
-
const silhouette = pose !== null && typeof pose === "object" && pose.kind === "polygon";
|
|
21897
|
-
const b = silhouette ? nodeMemo(node, "aabb", pose, () => aabbOfPose(pose)) : aabbOfPose(pose);
|
|
21898
|
-
if (!Number.isFinite(b.x) || !Number.isFinite(b.y) || !Number.isFinite(b.width) || !Number.isFinite(b.height)) {
|
|
21899
|
-
continue;
|
|
21900
|
-
}
|
|
21901
|
-
if (b.x >= ab.x + ab.width || b.x + b.width <= ab.x || b.y >= ab.y + ab.height || b.y + b.height <= ab.y) {
|
|
21902
|
-
continue;
|
|
21903
|
-
}
|
|
21904
|
-
if (areaIsRect && b.x >= ab.x && b.y >= ab.y && b.x + b.width <= ab.x + ab.width && b.y + b.height <= ab.y + ab.height) {
|
|
21905
|
-
hits.push(node.id);
|
|
21906
|
-
continue;
|
|
21907
|
-
}
|
|
21908
|
-
if (silhouette) {
|
|
21909
|
-
if (silhouetteOverlapsArea(pose.coords, area)) {
|
|
21910
|
-
hits.push(node.id);
|
|
21911
|
-
}
|
|
21912
|
-
continue;
|
|
21913
|
-
}
|
|
21914
|
-
const drawn = findShapeSilhouette(node, pose);
|
|
21915
|
-
if (drawn?.kind === "polygon") {
|
|
21916
|
-
if (silhouetteOverlapsArea(drawn.coords, area)) hits.push(node.id);
|
|
21917
|
-
continue;
|
|
21918
|
-
}
|
|
21919
|
-
hits.push(node.id);
|
|
21920
|
-
}
|
|
21921
|
-
return hits;
|
|
21922
|
-
}
|
|
21923
|
-
function silhouetteOverlapsArea(sil, area) {
|
|
21924
|
-
const ns = sil.length >> 1;
|
|
21925
|
-
const na = area.length >> 1;
|
|
21926
|
-
if (ns < 1 || na < 3) return false;
|
|
21927
|
-
for (let i = 0; i < ns; i++) {
|
|
21928
|
-
if (pointInPolygon(area, sil[i * 2], sil[i * 2 + 1])) return true;
|
|
21929
|
-
}
|
|
21930
|
-
for (let i = 0; i < na; i++) {
|
|
21931
|
-
if (pointInPolygon(sil, area[i * 2], area[i * 2 + 1])) return true;
|
|
21932
|
-
}
|
|
21933
|
-
for (let i = 0, j = ns - 1; i < ns; j = i++) {
|
|
21934
|
-
const ax = sil[j * 2], ay = sil[j * 2 + 1];
|
|
21935
|
-
const bx = sil[i * 2], by = sil[i * 2 + 1];
|
|
21936
|
-
for (let k = 0, l = na - 1; k < na; l = k++) {
|
|
21937
|
-
const cx = area[l * 2], cy = area[l * 2 + 1];
|
|
21938
|
-
const dx = area[k * 2], dy = area[k * 2 + 1];
|
|
21939
|
-
if (segmentsCross(ax, ay, bx, by, cx, cy, dx, dy)) return true;
|
|
21940
|
-
}
|
|
21941
|
-
}
|
|
21942
|
-
return false;
|
|
21943
|
-
}
|
|
21944
|
-
function boundsOf(coords) {
|
|
21945
|
-
if (coords.length < 2) return null;
|
|
21946
|
-
let minX = Infinity, minY = Infinity, maxX = -Infinity, maxY = -Infinity;
|
|
21947
|
-
for (let i = 0; i + 1 < coords.length; i += 2) {
|
|
21948
|
-
const x = coords[i], y = coords[i + 1];
|
|
21949
|
-
if (x < minX) minX = x;
|
|
21950
|
-
if (y < minY) minY = y;
|
|
21951
|
-
if (x > maxX) maxX = x;
|
|
21952
|
-
if (y > maxY) maxY = y;
|
|
21953
|
-
}
|
|
21954
|
-
return { x: minX, y: minY, width: maxX - minX, height: maxY - minY };
|
|
21955
|
-
}
|
|
21956
22268
|
function useViewDepSource(currentViewRef, onViewChange, recenter, hostSize) {
|
|
21957
22269
|
const viewApiRef = useRef({
|
|
21958
22270
|
get: () => currentViewRef.current,
|
|
@@ -22724,6 +23036,7 @@ function useActionsPropResolver(actions) {
|
|
|
22724
23036
|
}
|
|
22725
23037
|
if (!prop) return;
|
|
22726
23038
|
const unregisters = [];
|
|
23039
|
+
const restores = [];
|
|
22727
23040
|
const warnedIds = /* @__PURE__ */ new Set();
|
|
22728
23041
|
for (const [slotId, entry] of Object.entries(prop)) {
|
|
22729
23042
|
if (entry === null) {
|
|
@@ -22751,10 +23064,14 @@ function useActionsPropResolver(actions) {
|
|
|
22751
23064
|
}
|
|
22752
23065
|
const { id: _drop, ...rest } = entry;
|
|
22753
23066
|
const merged = { ...existing, ...rest };
|
|
23067
|
+
restores.push(() => {
|
|
23068
|
+
reg.register(existing);
|
|
23069
|
+
});
|
|
22754
23070
|
unregisters.push(reg.register(merged));
|
|
22755
23071
|
}
|
|
22756
23072
|
return () => {
|
|
22757
23073
|
for (const u of unregisters) u();
|
|
23074
|
+
for (const r of restores) r();
|
|
22758
23075
|
};
|
|
22759
23076
|
}, [reg, actions]);
|
|
22760
23077
|
}
|
|
@@ -24506,5 +24823,5 @@ function oklchToOklab(L, C, h) {
|
|
|
24506
24823
|
}
|
|
24507
24824
|
|
|
24508
24825
|
export { FALLBACK_FIT_VIEW, MinimapCanvas, SceneViewCanvas, UnknownIcon, buildSceneViewCommands, computeFitView2, computeIndicatorCommand, eligibleContribution, evaluateEnabled, oklabToSrgbU8, oklchToOklab, renderSceneToCanvas, rgbaToHex, useActionsRegistry, useOptionalDepRegistry };
|
|
24509
|
-
//# sourceMappingURL=chunk-
|
|
24510
|
-
//# sourceMappingURL=chunk-
|
|
24826
|
+
//# sourceMappingURL=chunk-DJLDIRFN.js.map
|
|
24827
|
+
//# sourceMappingURL=chunk-DJLDIRFN.js.map
|