@weasel-js/core 1.6.1 → 1.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +242 -0
- package/README.md +24 -4
- package/dist/{builtins-HWyuLzE-.d.ts → builtins-DLn2lCr_.d.ts} +578 -10
- package/dist/{chunk-BJN5ZRIJ.js → chunk-3TY6FHAF.js} +7 -4
- package/dist/chunk-3TY6FHAF.js.map +1 -0
- package/dist/{chunk-H6N2JSZ3.js → chunk-DGWNNKGD.js} +3 -3
- package/dist/{chunk-H6N2JSZ3.js.map → chunk-DGWNNKGD.js.map} +1 -1
- package/dist/{chunk-MZAIDI6D.js → chunk-G4ZGQMY7.js} +2102 -1222
- package/dist/chunk-G4ZGQMY7.js.map +1 -0
- package/dist/{chunk-HPFJUUTF.js → chunk-LU4IJ52W.js} +5 -61
- package/dist/chunk-LU4IJ52W.js.map +1 -0
- package/dist/{chunk-D4AAWR64.js → chunk-M24CLARN.js} +4 -4
- package/dist/{chunk-D4AAWR64.js.map → chunk-M24CLARN.js.map} +1 -1
- package/dist/{chunk-4RJP2N2L.js → chunk-NE27EOLP.js} +8 -5
- package/dist/chunk-NE27EOLP.js.map +1 -0
- package/dist/{chunk-DOBSZOPR.js → chunk-UPZY4ART.js} +3 -3
- package/dist/{chunk-DOBSZOPR.js.map → chunk-UPZY4ART.js.map} +1 -1
- package/dist/{chunk-RMR4QMM6.js → chunk-WPNA6L5O.js} +4 -4
- package/dist/{chunk-RMR4QMM6.js.map → chunk-WPNA6L5O.js.map} +1 -1
- package/dist/{chunk-44EWMJV2.js → chunk-XMAWPGTK.js} +5 -5
- package/dist/{chunk-44EWMJV2.js.map → chunk-XMAWPGTK.js.map} +1 -1
- package/dist/clipboard.d.ts +1 -1
- package/dist/clipboard.js +3 -3
- package/dist/clone.d.ts +2 -2
- package/dist/clone.js +3 -3
- package/dist/grid-CY5UKlZh.d.ts +98 -0
- package/dist/index.css +11 -35
- package/dist/index.css.map +1 -1
- package/dist/index.d.ts +460 -784
- package/dist/index.js +9 -9
- package/dist/insert.d.ts +2 -3
- package/dist/insert.js +1 -1
- package/dist/move.d.ts +5 -4
- package/dist/move.js +4 -4
- package/dist/move.js.map +1 -1
- package/dist/patterns-builtin.js +1 -1
- package/dist/{pointSnapToGrid-7mCcm6qG.d.ts → pointSnapToGrid-Dp2IxLGb.d.ts} +53 -60
- package/dist/renderer.css +11 -35
- package/dist/renderer.css.map +1 -1
- package/dist/renderer.d.ts +16 -8
- package/dist/renderer.js +9 -9
- package/dist/resize.d.ts +3 -3
- package/dist/resize.js +2 -2
- package/dist/routing.d.ts +1 -1
- package/dist/routing.js +1 -1
- package/dist/{types-CxC8P6W0.d.ts → types-D-9QWBy5.d.ts} +9 -6
- package/dist/{types-D_74YlWs.d.ts → types-qYpyTAiZ.d.ts} +4 -7
- package/package.json +15 -12
- package/dist/chunk-4RJP2N2L.js.map +0 -1
- package/dist/chunk-BJN5ZRIJ.js.map +0 -1
- package/dist/chunk-HPFJUUTF.js.map +0 -1
- package/dist/chunk-MZAIDI6D.js.map +0 -1
- package/dist/grid-BXdz8GF2.d.ts +0 -158
- package/dist/options-CzjxFoYZ.d.ts +0 -67
|
@@ -1,25 +1,29 @@
|
|
|
1
1
|
import { rotatePoint, aabbCenter, extractPolylines, createSimulation } from './chunk-PNNZSYRD.js';
|
|
2
|
-
import { createReparentOp, createTransformOp, snap } from './chunk-
|
|
3
|
-
import { fixedCornerOf, DEFAULT_RESIZE_BEHAVIORS, CORNER_ANCHORS, cornerPoint } from './chunk-
|
|
4
|
-
import {
|
|
5
|
-
import { unionBounds, visualBoundsViaDescriptor, translatePoseViaDescriptor, poseDescriptorForNode, unionAABB, AUTO_POSE_DESCRIPTOR, remapRotatedLeaf, PATH_Z, PATH_Q, PATH_C, PATH_L, PATH_M, polylineFromPoints, starPath, regularPolygonPath, linePath, ellipsePath, rectPath, polygonFromPoints, PathBuilder, boundsOfPath, pointInPath, isPathLike, strokeHitTest, isRectPose, transformPath, translatePath, DEFAULT_FLATTEN_TOLERANCE,
|
|
6
|
-
import { dispatchApplyBatch, dlog, dwarn, usePointerContext, PointerContextProvider, extractWeaselClipboardFromSvg, parseWeaselClipboardText, materializePaste, WEASEL_CLIPBOARD_MIME, WEASEL_CLIPBOARD_MIME_WEB, sniffWeaselClipboardText,
|
|
7
|
-
import { createSetSelectionOp } from './chunk-
|
|
8
|
-
import { registerOpFactory, createInsertOp, createDeleteOp, rebuildOp } from './chunk-
|
|
9
|
-
import { getTexture, chunks, dots, crosshatch, hatch } from './chunk-
|
|
2
|
+
import { createReparentOp, createTransformOp, snap } from './chunk-XMAWPGTK.js';
|
|
3
|
+
import { fixedCornerOf, DEFAULT_RESIZE_BEHAVIORS, CORNER_ANCHORS, cornerPoint } from './chunk-DGWNNKGD.js';
|
|
4
|
+
import { withinPxRadius, scaleDelta, pxExtent, withinPxBox, pointToGridCell } from './chunk-LU4IJ52W.js';
|
|
5
|
+
import { unionBounds, visualBoundsViaDescriptor, translatePoseViaDescriptor, poseDescriptorForNode, unionAABB, AUTO_POSE_DESCRIPTOR, remapRotatedLeaf, PATH_Z, PATH_Q, PATH_C, PATH_L, PATH_M, polylineFromPoints, starPath, regularPolygonPath, linePath, ellipsePath, rectPath, polygonFromPoints, PathBuilder, boundsOfPath, pointInPath, isPathLike, strokeHitTest, isRectPose, transformPath, translatePath, DEFAULT_FLATTEN_TOLERANCE, flattenCubicWithArcLen, flattenQuadraticWithArcLen, flattenQuadratic, flattenCubic, RECT_POSE_DESCRIPTOR, aabbIntersectsRect } from './chunk-L5YNZYEG.js';
|
|
6
|
+
import { dispatchApplyBatch, dlog, dwarn, usePointerContext, PointerContextProvider, applyOpsTo, extractWeaselClipboardFromSvg, parseWeaselClipboardText, materializePaste, WEASEL_CLIPBOARD_MIME, WEASEL_CLIPBOARD_MIME_WEB, sniffWeaselClipboardText, usePointerPosition } from './chunk-WPNA6L5O.js';
|
|
7
|
+
import { createSetSelectionOp } from './chunk-UPZY4ART.js';
|
|
8
|
+
import { registerOpFactory, createInsertOp, createDeleteOp, rebuildOp } from './chunk-NE27EOLP.js';
|
|
9
|
+
import { getTexture, chunks, dots, crosshatch, hatch } from './chunk-3TY6FHAF.js';
|
|
10
10
|
import { createContext, createElement, forwardRef, useMemo, useRef, useCallback, useState, useLayoutEffect, useEffect, useImperativeHandle, useSyncExternalStore, useContext, useId, useReducer } from 'react';
|
|
11
11
|
import { GLYPH_COVERAGE_GLSL, subscribeGlyphReady, DEFAULT_BAKE_BUDGET, markAllFontsNotUploaded, resetBakeBudget, syncDynamicPageTexture, ensureFontTexture, dynamicPageTextureId, textureCacheKey, GLYPH_MODE_R8, GLYPH_MODE_MSDF } from '@weasel-js/font';
|
|
12
|
-
export { canQueryLocalFonts, canQueryLocalFonts as canQueryLocalFonts2, enableLocalFontOutlines, enableLocalFontOutlines as enableLocalFontOutlines2, hasFontOutlines, hasFontOutlines as hasFontOutlines2, isCanvasFont, isCanvasFont as isCanvasFont2, listFontOutlines, listFontOutlines as listFontOutlines2, outlineStatus, outlineStatus as outlineStatus2, registerCanvasFont, registerCanvasFont as registerCanvasFont2, registerFont, registerFont as registerFont2, registerFontOutlines, registerFontOutlines as registerFontOutlines2, subscribeGlyphReady, subscribeGlyphReady as subscribeGlyphReady2, unregisterCanvasFont, unregisterCanvasFont as unregisterCanvasFont2, unregisterFontOutlines, unregisterFontOutlines as unregisterFontOutlines2 } from '@weasel-js/font';
|
|
12
|
+
export { canQueryLocalFonts, canQueryLocalFonts as canQueryLocalFonts2, enableLocalFontOutlines, enableLocalFontOutlines as enableLocalFontOutlines2, fontOutlineRegistry, fontOutlineRegistry as fontOutlineRegistry2, fontRegistry, fontRegistry as fontRegistry2, hasFontOutlines, hasFontOutlines as hasFontOutlines2, isCanvasFont, isCanvasFont as isCanvasFont2, listFontOutlines, listFontOutlines as listFontOutlines2, outlineStatus, outlineStatus as outlineStatus2, registerCanvasFont, registerCanvasFont as registerCanvasFont2, registerFont, registerFont as registerFont2, registerFontOutlines, registerFontOutlines as registerFontOutlines2, subscribeGlyphReady, subscribeGlyphReady as subscribeGlyphReady2, unregisterCanvasFont, unregisterCanvasFont as unregisterCanvasFont2, unregisterFontOutlines, unregisterFontOutlines as unregisterFontOutlines2 } from '@weasel-js/font';
|
|
13
13
|
import { hexToColorLiteral, resolvePaletteColor, colorLiteralToHex, dashForStrokeStyle, strokeDashStyleOf, resolveScreenLength, alignedStrokeRect, lerpColorArray, hslToSrgb, srgbFloatToOklab, oklabToOklch, oklchToOklab, oklabToSrgbU8 } from '@weasel-js/paint';
|
|
14
14
|
export { STROKE_DASH_RATIOS, alignedStrokeRect, contrastLineColor, dashForStrokeStyle, hexToOklchDeg, hslToSrgb, interpolateSrgb, lerpColorArray, lerpOklab, lerpOklch, linearSrgbToOklab, linearToSrgb, oklabToLinearSrgb, oklabToOklch, oklabToSrgbU8, oklchDegToHex, oklchToOklab, resolveScreenLength, srgbFloatToOklab, srgbToHsl, srgbToLinear, srgbU8ToOklab, strokeDashStyleOf } from '@weasel-js/paint';
|
|
15
|
-
import { boxToBox, forEachSegment, multiply as multiply$1, rotate, translate as translate$1, rectToContour, invert as invert$1, clampRectWithin, applyToPoint, rotateAboutPoint, cubicEvalAt, pointInPolygon, segmentsCross,
|
|
16
|
-
import {
|
|
15
|
+
import { boxToBox, forEachSegment, multiply as multiply$1, rotate, translate as translate$1, rectToContour, splitCubicAt, invert as invert$1, clampRectWithin, applyToPoint, rotateAboutPoint, nearestOnLine, nearestOnCubic, cubicEvalAt, pathCommandCoordCount, pointInPolygon, segmentsCross, nearestOnPath, splitQuadraticAt } from '@weasel-js/geom';
|
|
16
|
+
import { createReflectable } from '@weasel-js/registry';
|
|
17
|
+
export { createReflectable } from '@weasel-js/registry';
|
|
18
|
+
import { resolveAlign, resolveTextStyle, resolveRuns, cachedLayoutRuns, verticalAlignOffset, textPoseLayoutInput, runsToPlainText, layoutTextPose, fontString, textLineBoxes, SCRIPT_METRICS } from '@weasel-js/text';
|
|
17
19
|
export { DEFAULT_TEXT_STYLE, MARKDOWN_RUN_GRAMMAR, SCRIPT_METRICS, cachedLayoutRuns, createMarkdownRenderer, fontString, layoutMarkdown, layoutRuns, layoutTextPose, markdownToRuns, measureText, measureTextBounds, measuredWidth, resolveAlign, resolveRuns, resolveTextStyle, runsToMarkdown, runsToPlainText, textLineBoxes, textPoseLayoutInput, toRuns, transformRunTexts, verticalAlignOffset } from '@weasel-js/text';
|
|
18
20
|
import earcut from 'earcut';
|
|
19
|
-
import {
|
|
20
|
-
export {
|
|
21
|
-
import {
|
|
22
|
-
export {
|
|
21
|
+
import { unitScale, formatUnit, resolveUnit, ANGLE_RADIANS } from '@weasel-js/quantity';
|
|
22
|
+
export { ANGLE_RADIANS, IMPERIAL_INCHES, METRIC_MM, PIXELS, formatUnit, resolveUnit, unitScale } from '@weasel-js/quantity';
|
|
23
|
+
import { scratchKey, isAnchorOrControl, isBody, ActionDisabledReason, resolveParams, DRAG_THRESHOLD_PX, pastDragThreshold, setScratch, createDispatcher, DEFAULT_ALLOWED_CAPABILITIES, itemsFromFiles, evaluate, resolveDeviceProfile, defineTool, isResizeHandle, isRotateHandle, NEVER, recordModeSwitch, DEFAULT_DEVICE_PROFILE, openPointerSession, actionBindings, getScratch, ALWAYS, clientToCanvas, mergeContributions as mergeContributions$1, clientToCanvasRect, isEditableTarget } from '@weasel-js/routing';
|
|
24
|
+
export { ALWAYS, ActionDisabledReason, COARSE_TARGET_SCALE, DEFAULT_ALLOWED_CAPABILITIES, DEFAULT_DEVICE_PROFILE, DRAG_THRESHOLD_PX, NEVER, actionBindings, actionItems, buildDepsFromRequires, buildRuleCtx, clientToCanvas, createDepRegistry, createDispatcher, defineTool, deleteScratch, describeRule, evaluate, evaluateEnabled, getScratch, isEditableTarget, liveScope, matchesKeyBinding, modeShortcutSpec, modeShortcuts, openPointerSession, pastDragThreshold, resolveDeviceProfile, resolveParams, scopeBindings, scratchKey, setScratch, specificity } from '@weasel-js/routing';
|
|
25
|
+
import { InputScope, useOptionalActiveToolContext, useTools as useTools$1, useActionsRegistry, useDepSource, useDepRegistry, useGestureDispatcher, useOptionalDepRegistry, useOffhandAction, DepRegistryProvider, ActionsProvider, ActiveToolContextProvider, ActiveToolContextProviderIfRoot } from '@weasel-js/routing/react';
|
|
26
|
+
export { ActionsProvider, ActiveToolContextProvider, ActiveToolContextProviderIfRoot, DepRegistryProvider, InputScope, Yoke, useAction, useActionsRegistry, useActiveToolContext, useDepRegistry, useDepSource, useGestureDispatcher, useOngoingAction, useOptionalActiveToolContext, useOptionalDepRegistry, useYoke } from '@weasel-js/routing/react';
|
|
23
27
|
import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
|
|
24
28
|
import { pathCrop as pathCrop$1, pathDivide as pathDivide$1, pathUnion as pathUnion$1, pathSubtract as pathSubtract$1, pathExclude as pathExclude$1, pathIntersect as pathIntersect$1 } from '@weasel-js/geom/booleans';
|
|
25
29
|
import { mimeMatchesGlob } from '@weasel-js/gestures';
|
|
@@ -27,9 +31,10 @@ import { createPaintedCursorState, GLYPHS, cursorWorldSize, cursorPaintOps, chro
|
|
|
27
31
|
export { bakeCursor, createPaintedCursorState, cursorFor, resolveCursor, resolveCursorTier } from '@weasel-js/cursor';
|
|
28
32
|
import { createHistory } from '@weasel-js/history';
|
|
29
33
|
export * from '@weasel-js/history';
|
|
34
|
+
import { getActiveModeFor } from '@weasel-js/modes';
|
|
30
35
|
|
|
31
36
|
// src/version.ts
|
|
32
|
-
var VERSION = "1.
|
|
37
|
+
var VERSION = "1.7.0" ;
|
|
33
38
|
|
|
34
39
|
// src/features/grid/roundToCell.ts
|
|
35
40
|
function roundToCell(value, cellSize) {
|
|
@@ -1719,8 +1724,6 @@ function dropPoseKeyedMemoSlots(node) {
|
|
|
1719
1724
|
if (entry.pose !== void 0) record.slots.delete(slot);
|
|
1720
1725
|
}
|
|
1721
1726
|
}
|
|
1722
|
-
|
|
1723
|
-
// src/core/paintKinds.ts
|
|
1724
1727
|
var BUILTINS = [
|
|
1725
1728
|
{
|
|
1726
1729
|
id: "solid",
|
|
@@ -1751,7 +1754,9 @@ function gradientKind(id, label, icon) {
|
|
|
1751
1754
|
icon,
|
|
1752
1755
|
// `bounds` units make the seed independent of the node's actual size.
|
|
1753
1756
|
seed: (color) => gradientForBounds(id, UNIT_BOX, twoStopRamp(color), "bounds"),
|
|
1754
|
-
colorOf: (paint) => paint.stops?.[0]?.color
|
|
1757
|
+
colorOf: (paint) => paint.stops?.[0]?.color,
|
|
1758
|
+
stopsOf: (paint) => paint.stops,
|
|
1759
|
+
fromStops: (stops) => gradientForBounds(id, UNIT_BOX, stops, "bounds")
|
|
1755
1760
|
};
|
|
1756
1761
|
}
|
|
1757
1762
|
var UNIT_BOX = { x: 0, y: 0, width: 1, height: 1 };
|
|
@@ -1759,44 +1764,61 @@ function twoStopRamp(color) {
|
|
|
1759
1764
|
const isWhite = color.slice(0, 7).toLowerCase() === "#ffffff";
|
|
1760
1765
|
return [{ offset: 0, color }, { offset: 1, color: isWhite ? "#000000ff" : "#ffffffff" }];
|
|
1761
1766
|
}
|
|
1762
|
-
var KINDS =
|
|
1767
|
+
var KINDS = createReflectable();
|
|
1763
1768
|
function seedBuiltins() {
|
|
1764
|
-
for (const entry of BUILTINS) KINDS.
|
|
1769
|
+
for (const entry of BUILTINS) KINDS.push(entry.id, entry, { source: "kit" });
|
|
1765
1770
|
}
|
|
1766
1771
|
seedBuiltins();
|
|
1772
|
+
KINDS.subscribe(bumpNodeMemoGeneration);
|
|
1773
|
+
var paintKindRegistry = KINDS.reflection;
|
|
1767
1774
|
function asPaint(paint) {
|
|
1768
1775
|
return paint;
|
|
1769
1776
|
}
|
|
1770
1777
|
function registerPaintKind(entry) {
|
|
1778
|
+
if (entry.stopsOf === void 0 !== (entry.fromStops === void 0)) {
|
|
1779
|
+
const missing = entry.stopsOf === void 0 ? "stopsOf" : "fromStops";
|
|
1780
|
+
throw new Error(
|
|
1781
|
+
`weasel registerPaintKind: kind "${entry.id}" is missing ${missing}. A gradient kind reads as a stop list and builds from one; supply both or neither.`
|
|
1782
|
+
);
|
|
1783
|
+
}
|
|
1771
1784
|
if (entry.inPoseFrame === void 0 !== (entry.toBoundsFrame === void 0)) {
|
|
1772
1785
|
const missing = entry.inPoseFrame === void 0 ? "inPoseFrame" : "toBoundsFrame";
|
|
1773
1786
|
throw new Error(
|
|
1774
1787
|
`weasel registerPaintKind: kind "${entry.id}" is missing ${missing}. A kind that converts one frame direction and not the other drifts on the next resize; supply both or neither.`
|
|
1775
1788
|
);
|
|
1776
1789
|
}
|
|
1777
|
-
|
|
1778
|
-
KINDS.set(entry.id, entry);
|
|
1779
|
-
bumpNodeMemoGeneration();
|
|
1780
|
-
return () => {
|
|
1781
|
-
if (KINDS.get(entry.id) !== entry) return;
|
|
1782
|
-
if (displaced) KINDS.set(entry.id, displaced);
|
|
1783
|
-
else KINDS.delete(entry.id);
|
|
1784
|
-
bumpNodeMemoGeneration();
|
|
1785
|
-
};
|
|
1790
|
+
return KINDS.push(entry.id, entry);
|
|
1786
1791
|
}
|
|
1787
1792
|
function getPaintKind(kind) {
|
|
1788
1793
|
return KINDS.get(kind ?? "solid");
|
|
1789
1794
|
}
|
|
1790
1795
|
function listPaintKinds() {
|
|
1791
|
-
return
|
|
1796
|
+
return KINDS.entries().map((e) => e.value);
|
|
1797
|
+
}
|
|
1798
|
+
function listGradientKinds() {
|
|
1799
|
+
return listPaintKinds().filter((entry) => entry.stopsOf && entry.fromStops);
|
|
1800
|
+
}
|
|
1801
|
+
function switchGradientKind(paint, kind) {
|
|
1802
|
+
const from = paintKindOf(paint);
|
|
1803
|
+
const to = getPaintKind(kind);
|
|
1804
|
+
if (!from?.stopsOf || !to?.fromStops) return void 0;
|
|
1805
|
+
if (from.id === to.id) return paint;
|
|
1806
|
+
if (isGradientFill(paint) && isGradientFill({ fill: kind })) {
|
|
1807
|
+
return withGradientKind(paint, kind);
|
|
1808
|
+
}
|
|
1809
|
+
const { interpolate, opacity } = paint;
|
|
1810
|
+
return {
|
|
1811
|
+
...to.fromStops(from.stopsOf(paint)),
|
|
1812
|
+
...interpolate !== void 0 ? { interpolate } : {},
|
|
1813
|
+
...opacity !== void 0 ? { opacity } : {}
|
|
1814
|
+
};
|
|
1792
1815
|
}
|
|
1793
1816
|
function paintKindOf(fill) {
|
|
1794
1817
|
return getPaintKind(fill.fill ?? "solid");
|
|
1795
1818
|
}
|
|
1796
1819
|
function _resetPaintKindsForTests() {
|
|
1797
|
-
KINDS
|
|
1820
|
+
KINDS.clear();
|
|
1798
1821
|
seedBuiltins();
|
|
1799
|
-
bumpNodeMemoGeneration();
|
|
1800
1822
|
}
|
|
1801
1823
|
|
|
1802
1824
|
// src/renderer/DrawCommand.ts
|
|
@@ -2970,11 +2992,13 @@ function circle(cx, r, size, segments = 32) {
|
|
|
2970
2992
|
var BUILTIN_MARKERS = [
|
|
2971
2993
|
{
|
|
2972
2994
|
id: "arrow",
|
|
2995
|
+
reads: [],
|
|
2973
2996
|
inset: 3,
|
|
2974
2997
|
path: ({ size }) => poly([0, 0, -3, -1.5, -3, 1.5], size)
|
|
2975
2998
|
},
|
|
2976
2999
|
{
|
|
2977
3000
|
id: "arrow-open",
|
|
3001
|
+
reads: [],
|
|
2978
3002
|
inset: 0,
|
|
2979
3003
|
fill: "none",
|
|
2980
3004
|
outline: { width: 1 },
|
|
@@ -2986,16 +3010,19 @@ var BUILTIN_MARKERS = [
|
|
|
2986
3010
|
},
|
|
2987
3011
|
{
|
|
2988
3012
|
id: "arrow-concave",
|
|
3013
|
+
reads: [],
|
|
2989
3014
|
inset: 3,
|
|
2990
3015
|
path: ({ size }) => poly([0, 0, -3, -1.5, -2, 0, -3, 1.5], size)
|
|
2991
3016
|
},
|
|
2992
3017
|
{
|
|
2993
3018
|
id: "diamond",
|
|
3019
|
+
reads: [],
|
|
2994
3020
|
inset: 4,
|
|
2995
3021
|
path: ({ size }) => poly([0, 0, -2, -1.2, -4, 0, -2, 1.2], size)
|
|
2996
3022
|
},
|
|
2997
3023
|
{
|
|
2998
3024
|
id: "diamond-hollow",
|
|
3025
|
+
reads: [],
|
|
2999
3026
|
inset: 4,
|
|
3000
3027
|
fill: "none",
|
|
3001
3028
|
outline: { width: 0.5 },
|
|
@@ -3003,16 +3030,19 @@ var BUILTIN_MARKERS = [
|
|
|
3003
3030
|
},
|
|
3004
3031
|
{
|
|
3005
3032
|
id: "circle",
|
|
3033
|
+
reads: [],
|
|
3006
3034
|
inset: 2,
|
|
3007
3035
|
path: ({ size }) => circle(-1, 1, size)
|
|
3008
3036
|
},
|
|
3009
3037
|
{
|
|
3010
3038
|
id: "square",
|
|
3039
|
+
reads: [],
|
|
3011
3040
|
inset: 2,
|
|
3012
3041
|
path: ({ size }) => poly([0, -1, 0, 1, -2, 1, -2, -1], size)
|
|
3013
3042
|
},
|
|
3014
3043
|
{
|
|
3015
3044
|
id: "bar",
|
|
3045
|
+
reads: [],
|
|
3016
3046
|
inset: 0,
|
|
3017
3047
|
fill: "none",
|
|
3018
3048
|
outline: { width: 1 },
|
|
@@ -3021,48 +3051,42 @@ var BUILTIN_MARKERS = [
|
|
|
3021
3051
|
];
|
|
3022
3052
|
|
|
3023
3053
|
// src/core/strokeMarkers.ts
|
|
3024
|
-
var MARKERS =
|
|
3054
|
+
var MARKERS = createReflectable();
|
|
3025
3055
|
function seedBuiltins2() {
|
|
3026
|
-
for (const entry of BUILTIN_MARKERS) MARKERS.
|
|
3056
|
+
for (const entry of BUILTIN_MARKERS) MARKERS.push(entry.id, entry, { source: "kit" });
|
|
3027
3057
|
}
|
|
3028
3058
|
seedBuiltins2();
|
|
3059
|
+
var markerRegistry = MARKERS.reflection;
|
|
3060
|
+
function markerGeneration() {
|
|
3061
|
+
return MARKERS.getVersion();
|
|
3062
|
+
}
|
|
3029
3063
|
function registerMarker(entry) {
|
|
3030
|
-
|
|
3031
|
-
MARKERS.set(entry.id, entry);
|
|
3032
|
-
bumpNodeMemoGeneration();
|
|
3033
|
-
return () => {
|
|
3034
|
-
if (MARKERS.get(entry.id) !== entry) return;
|
|
3035
|
-
if (displaced) MARKERS.set(entry.id, displaced);
|
|
3036
|
-
else MARKERS.delete(entry.id);
|
|
3037
|
-
bumpNodeMemoGeneration();
|
|
3038
|
-
};
|
|
3064
|
+
return MARKERS.push(entry.id, entry);
|
|
3039
3065
|
}
|
|
3040
3066
|
function getMarker(key) {
|
|
3041
3067
|
return key === void 0 ? void 0 : MARKERS.get(key);
|
|
3042
3068
|
}
|
|
3043
3069
|
function listMarkers() {
|
|
3044
|
-
return
|
|
3070
|
+
return MARKERS.entries().map((e) => e.value);
|
|
3045
3071
|
}
|
|
3046
3072
|
function _resetMarkersForTests() {
|
|
3047
|
-
MARKERS
|
|
3073
|
+
MARKERS.clear();
|
|
3048
3074
|
seedBuiltins2();
|
|
3049
|
-
bumpNodeMemoGeneration();
|
|
3050
3075
|
}
|
|
3051
3076
|
|
|
3052
3077
|
// src/core/markerInset.ts
|
|
3053
|
-
function resolveMarkerSize(ref, strokeWidth) {
|
|
3078
|
+
function resolveMarkerSize(ref, strokeWidth, scale = 1) {
|
|
3054
3079
|
if (typeof ref === "string" || ref.size === void 0) return strokeWidth;
|
|
3055
|
-
|
|
3056
|
-
return typeof size === "number" ? size : size.px;
|
|
3080
|
+
return resolveScreenLength(ref.size, scale);
|
|
3057
3081
|
}
|
|
3058
3082
|
function markerKeyOf(ref) {
|
|
3059
3083
|
return typeof ref === "string" ? ref : ref.key;
|
|
3060
3084
|
}
|
|
3061
|
-
function markerInset(ref, strokeWidth) {
|
|
3085
|
+
function markerInset(ref, strokeWidth, scale = 1) {
|
|
3062
3086
|
if (ref === void 0) return 0;
|
|
3063
3087
|
const entry = getMarker(markerKeyOf(ref));
|
|
3064
3088
|
if (entry === void 0) return 0;
|
|
3065
|
-
return (entry.inset ?? 0) * resolveMarkerSize(ref, strokeWidth);
|
|
3089
|
+
return (entry.inset ?? 0) * resolveMarkerSize(ref, strokeWidth, scale);
|
|
3066
3090
|
}
|
|
3067
3091
|
function strokeInsets(stroke, strokeWidth) {
|
|
3068
3092
|
return {
|
|
@@ -3119,6 +3143,220 @@ function strokeMesh(path, stroke, flattenTolerance) {
|
|
|
3119
3143
|
return mesh;
|
|
3120
3144
|
}
|
|
3121
3145
|
|
|
3146
|
+
// src/features/paths/markerSites.ts
|
|
3147
|
+
var EPS2 = 1e-9;
|
|
3148
|
+
function dir(pl, i, j) {
|
|
3149
|
+
const dx = pl.points[j * 2] - pl.points[i * 2];
|
|
3150
|
+
const dy = pl.points[j * 2 + 1] - pl.points[i * 2 + 1];
|
|
3151
|
+
const len = Math.hypot(dx, dy);
|
|
3152
|
+
if (len < EPS2) return null;
|
|
3153
|
+
return { x: dx / len, y: dy / len };
|
|
3154
|
+
}
|
|
3155
|
+
function nextDistinct(pl, i, n) {
|
|
3156
|
+
for (let k = i + 1; k < n; k++) if (dir(pl, i, k)) return k;
|
|
3157
|
+
return -1;
|
|
3158
|
+
}
|
|
3159
|
+
function prevDistinct(pl, i) {
|
|
3160
|
+
for (let k = i - 1; k >= 0; k--) if (dir(pl, k, i)) return k;
|
|
3161
|
+
return -1;
|
|
3162
|
+
}
|
|
3163
|
+
function markerSites(pl, want) {
|
|
3164
|
+
const out = [];
|
|
3165
|
+
const n = pl.points.length / 2;
|
|
3166
|
+
if (n < 2) return out;
|
|
3167
|
+
if (want.start && !pl.closed) {
|
|
3168
|
+
const j = nextDistinct(pl, 0, n);
|
|
3169
|
+
const d = j >= 0 ? dir(pl, 0, j) : null;
|
|
3170
|
+
if (d) {
|
|
3171
|
+
out.push({ x: pl.points[0], y: pl.points[1], angle: Math.atan2(-d.y, -d.x), role: "start" });
|
|
3172
|
+
}
|
|
3173
|
+
}
|
|
3174
|
+
if (want.mid) {
|
|
3175
|
+
const A = pl.anchorA, B = pl.anchorB, T = pl.anchorT;
|
|
3176
|
+
if (A && B && T) {
|
|
3177
|
+
for (let i = 1; i < n - 1; i++) {
|
|
3178
|
+
if (A[i] !== B[i] || T[i] !== 0) continue;
|
|
3179
|
+
const p = prevDistinct(pl, i);
|
|
3180
|
+
const q = nextDistinct(pl, i, n);
|
|
3181
|
+
if (p < 0 || q < 0) continue;
|
|
3182
|
+
const inDir = dir(pl, p, i);
|
|
3183
|
+
const outDir = dir(pl, i, q);
|
|
3184
|
+
let bx = inDir.x + outDir.x;
|
|
3185
|
+
let by = inDir.y + outDir.y;
|
|
3186
|
+
if (Math.hypot(bx, by) < EPS2) {
|
|
3187
|
+
bx = inDir.x;
|
|
3188
|
+
by = inDir.y;
|
|
3189
|
+
}
|
|
3190
|
+
out.push({ x: pl.points[i * 2], y: pl.points[i * 2 + 1], angle: Math.atan2(by, bx), role: "mid" });
|
|
3191
|
+
}
|
|
3192
|
+
}
|
|
3193
|
+
}
|
|
3194
|
+
if (want.end && !pl.closed) {
|
|
3195
|
+
const last = n - 1;
|
|
3196
|
+
const p = prevDistinct(pl, last);
|
|
3197
|
+
const d = p >= 0 ? dir(pl, p, last) : null;
|
|
3198
|
+
if (d) {
|
|
3199
|
+
out.push({ x: pl.points[last * 2], y: pl.points[last * 2 + 1], angle: Math.atan2(d.y, d.x), role: "end" });
|
|
3200
|
+
}
|
|
3201
|
+
}
|
|
3202
|
+
return out;
|
|
3203
|
+
}
|
|
3204
|
+
|
|
3205
|
+
// src/features/paths/markerCommands.ts
|
|
3206
|
+
function placed(path, site) {
|
|
3207
|
+
const src = path;
|
|
3208
|
+
const cos = Math.cos(site.angle);
|
|
3209
|
+
const sin = Math.sin(site.angle);
|
|
3210
|
+
const coords = new Float32Array(src.coords.length);
|
|
3211
|
+
for (let i = 0; i < src.coords.length; i += 2) {
|
|
3212
|
+
const x = src.coords[i], y = src.coords[i + 1];
|
|
3213
|
+
coords[i] = site.x + x * cos - y * sin;
|
|
3214
|
+
coords[i + 1] = site.y + x * sin + y * cos;
|
|
3215
|
+
}
|
|
3216
|
+
return { kind: "polygon", commands: src.commands, coords, fillRule: src.fillRule };
|
|
3217
|
+
}
|
|
3218
|
+
function resolvePaint(p, stroke, fallback) {
|
|
3219
|
+
const v = p ?? fallback;
|
|
3220
|
+
if (v === "none") return void 0;
|
|
3221
|
+
return v === "line" ? stroke.paint : v;
|
|
3222
|
+
}
|
|
3223
|
+
function markerHeads(path, stroke, strokeWidth, flattenTolerance) {
|
|
3224
|
+
const want = {
|
|
3225
|
+
start: stroke.markerStart !== void 0,
|
|
3226
|
+
mid: stroke.markerMid !== void 0,
|
|
3227
|
+
end: stroke.markerEnd !== void 0
|
|
3228
|
+
};
|
|
3229
|
+
if (!want.start && !want.mid && !want.end) return [];
|
|
3230
|
+
const refFor = (role) => role === "start" ? stroke.markerStart : role === "mid" ? stroke.markerMid : stroke.markerEnd;
|
|
3231
|
+
const out = [];
|
|
3232
|
+
for (const pl of extractPolylines(path, { flattenTolerance })) {
|
|
3233
|
+
for (const site of markerSites(pl, want)) {
|
|
3234
|
+
const ref = refFor(site.role);
|
|
3235
|
+
if (ref === void 0) continue;
|
|
3236
|
+
const entry = getMarker(markerKeyOf(ref));
|
|
3237
|
+
if (entry === void 0) continue;
|
|
3238
|
+
const size = resolveMarkerSize(ref, strokeWidth);
|
|
3239
|
+
const angle = entry.orient === void 0 || entry.orient === "auto" ? site.angle : entry.orient;
|
|
3240
|
+
out.push({ entry, size, path: placed(entry.path({ size, stroke }), { ...site, angle }) });
|
|
3241
|
+
}
|
|
3242
|
+
}
|
|
3243
|
+
return out;
|
|
3244
|
+
}
|
|
3245
|
+
function headCommands(heads, stroke) {
|
|
3246
|
+
const out = [];
|
|
3247
|
+
for (const { entry, path, size } of heads) {
|
|
3248
|
+
const fill = resolvePaint(entry.fill, stroke, "line");
|
|
3249
|
+
const outline = entry.outline ? { paint: resolvePaint(entry.outline.paint, stroke, "line"), width: entry.outline.width * size } : null;
|
|
3250
|
+
if (fill === void 0 && (outline === null || outline.paint === void 0)) continue;
|
|
3251
|
+
out.push({
|
|
3252
|
+
kind: "path",
|
|
3253
|
+
path,
|
|
3254
|
+
...fill ? { fill } : {},
|
|
3255
|
+
...outline && outline.paint ? { stroke: { paint: outline.paint, width: outline.width, cap: "round", join: "round" } } : {}
|
|
3256
|
+
});
|
|
3257
|
+
}
|
|
3258
|
+
return out;
|
|
3259
|
+
}
|
|
3260
|
+
function markerReadsKey(entry, stroke) {
|
|
3261
|
+
if (entry.reads === void 0) return null;
|
|
3262
|
+
let key = "";
|
|
3263
|
+
for (const field of entry.reads) key += `${JSON.stringify(stroke[field]) ?? ""}|`;
|
|
3264
|
+
return key;
|
|
3265
|
+
}
|
|
3266
|
+
var READINGS_PER_ENTRY = 64;
|
|
3267
|
+
var REACH_BY_READING = /* @__PURE__ */ new WeakMap();
|
|
3268
|
+
var REACH_BY_STROKE = /* @__PURE__ */ new WeakMap();
|
|
3269
|
+
function measureUnitReach(entry, stroke) {
|
|
3270
|
+
const b = boundsOfPath(entry.path({ size: 1, stroke }));
|
|
3271
|
+
return Math.max(Math.abs(b.x), Math.abs(b.x + b.width), Math.abs(b.y), Math.abs(b.y + b.height)) + (entry.outline ? entry.outline.width / 2 : 0);
|
|
3272
|
+
}
|
|
3273
|
+
function unitReach(entry, stroke) {
|
|
3274
|
+
const key = markerReadsKey(entry, stroke);
|
|
3275
|
+
if (key === null) {
|
|
3276
|
+
let byStroke2 = REACH_BY_STROKE.get(entry);
|
|
3277
|
+
if (byStroke2 === void 0) REACH_BY_STROKE.set(entry, byStroke2 = /* @__PURE__ */ new WeakMap());
|
|
3278
|
+
let reach2 = byStroke2.get(stroke);
|
|
3279
|
+
if (reach2 === void 0) byStroke2.set(stroke, reach2 = measureUnitReach(entry, stroke));
|
|
3280
|
+
return reach2;
|
|
3281
|
+
}
|
|
3282
|
+
let byReading = REACH_BY_READING.get(entry);
|
|
3283
|
+
if (byReading === void 0) REACH_BY_READING.set(entry, byReading = /* @__PURE__ */ new Map());
|
|
3284
|
+
let reach = byReading.get(key);
|
|
3285
|
+
if (reach === void 0) {
|
|
3286
|
+
if (byReading.size >= READINGS_PER_ENTRY) byReading.clear();
|
|
3287
|
+
byReading.set(key, reach = measureUnitReach(entry, stroke));
|
|
3288
|
+
}
|
|
3289
|
+
return reach;
|
|
3290
|
+
}
|
|
3291
|
+
function markerReach(stroke, strokeWidth, scale = 1) {
|
|
3292
|
+
let reach = 0;
|
|
3293
|
+
for (const ref of [stroke.markerStart, stroke.markerMid, stroke.markerEnd]) {
|
|
3294
|
+
if (ref === void 0) continue;
|
|
3295
|
+
const entry = getMarker(markerKeyOf(ref));
|
|
3296
|
+
if (entry === void 0) continue;
|
|
3297
|
+
reach = Math.max(reach, unitReach(entry, stroke) * resolveMarkerSize(ref, strokeWidth, scale));
|
|
3298
|
+
}
|
|
3299
|
+
return reach;
|
|
3300
|
+
}
|
|
3301
|
+
|
|
3302
|
+
// src/renderer/cache/markerCommandCache.ts
|
|
3303
|
+
var byValue = /* @__PURE__ */ new WeakMap();
|
|
3304
|
+
var byStroke = /* @__PURE__ */ new WeakMap();
|
|
3305
|
+
var refKey = (ref) => ref === void 0 ? "" : typeof ref === "string" ? ref : `${ref.key}@${String(ref.size ?? "")}`;
|
|
3306
|
+
function readsKey(stroke) {
|
|
3307
|
+
let key = "";
|
|
3308
|
+
for (const ref of [stroke.markerStart, stroke.markerMid, stroke.markerEnd]) {
|
|
3309
|
+
const entry = ref === void 0 ? void 0 : getMarker(markerKeyOf(ref));
|
|
3310
|
+
if (entry === void 0) {
|
|
3311
|
+
key += "/";
|
|
3312
|
+
continue;
|
|
3313
|
+
}
|
|
3314
|
+
const reads = markerReadsKey(entry, stroke);
|
|
3315
|
+
if (reads === null) return null;
|
|
3316
|
+
key += `${reads}/`;
|
|
3317
|
+
}
|
|
3318
|
+
return key;
|
|
3319
|
+
}
|
|
3320
|
+
function mapFor(path, source, reads) {
|
|
3321
|
+
if (reads !== null) {
|
|
3322
|
+
let map2 = byValue.get(path);
|
|
3323
|
+
if (map2 === void 0) byValue.set(path, map2 = /* @__PURE__ */ new Map());
|
|
3324
|
+
return map2;
|
|
3325
|
+
}
|
|
3326
|
+
let strokes = byStroke.get(path);
|
|
3327
|
+
if (strokes === void 0) byStroke.set(path, strokes = /* @__PURE__ */ new WeakMap());
|
|
3328
|
+
let map = strokes.get(source);
|
|
3329
|
+
if (map === void 0) strokes.set(source, map = /* @__PURE__ */ new Map());
|
|
3330
|
+
return map;
|
|
3331
|
+
}
|
|
3332
|
+
function cachedMarkerCommands(path, source, stroke, strokeWidth, flattenTolerance) {
|
|
3333
|
+
if (stroke.markerStart === void 0 && stroke.markerMid === void 0 && stroke.markerEnd === void 0) {
|
|
3334
|
+
return [];
|
|
3335
|
+
}
|
|
3336
|
+
const reads = readsKey(stroke);
|
|
3337
|
+
const map = mapFor(path, source, reads);
|
|
3338
|
+
const key = [
|
|
3339
|
+
strokeWidth,
|
|
3340
|
+
flattenTolerance ?? "",
|
|
3341
|
+
markerGeneration(),
|
|
3342
|
+
refKey(stroke.markerStart),
|
|
3343
|
+
refKey(stroke.markerMid),
|
|
3344
|
+
refKey(stroke.markerEnd),
|
|
3345
|
+
reads ?? ""
|
|
3346
|
+
].join("|");
|
|
3347
|
+
let entry = map.get(key);
|
|
3348
|
+
if (entry === void 0) {
|
|
3349
|
+
const heads = markerHeads(path, stroke, strokeWidth, flattenTolerance);
|
|
3350
|
+
entry = { heads, paint: stroke.paint, cmds: headCommands(heads, stroke) };
|
|
3351
|
+
if (map.size >= STROKE_CONFIGS_PER_PATH) map.clear();
|
|
3352
|
+
map.set(key, entry);
|
|
3353
|
+
} else if (entry.paint !== stroke.paint) {
|
|
3354
|
+
entry.paint = stroke.paint;
|
|
3355
|
+
entry.cmds = headCommands(entry.heads, stroke);
|
|
3356
|
+
}
|
|
3357
|
+
return entry.cmds;
|
|
3358
|
+
}
|
|
3359
|
+
|
|
3122
3360
|
// src/renderer/drawBatch.ts
|
|
3123
3361
|
var MAX_VERTICES_PER_BATCH = 32768;
|
|
3124
3362
|
var FLOATS_PER_VERTEX = 10;
|
|
@@ -3550,9 +3788,8 @@ var DrawBatch = class {
|
|
|
3550
3788
|
gl.deleteVertexArray(set.vao);
|
|
3551
3789
|
}
|
|
3552
3790
|
};
|
|
3553
|
-
|
|
3554
|
-
|
|
3555
|
-
var registry = /* @__PURE__ */ new Map();
|
|
3791
|
+
var registry = createReflectable();
|
|
3792
|
+
var programSourceRegistry = registry.reflection;
|
|
3556
3793
|
function getProgramSource(id) {
|
|
3557
3794
|
return registry.get(id) ?? null;
|
|
3558
3795
|
}
|
|
@@ -4532,23 +4769,42 @@ function drawPathFillStencil(ctx, fill, handle) {
|
|
|
4532
4769
|
gl.disable(gl.STENCIL_TEST);
|
|
4533
4770
|
gl.bindVertexArray(null);
|
|
4534
4771
|
}
|
|
4535
|
-
function
|
|
4772
|
+
function withResolvedStrokeLengths(ctx, cmd) {
|
|
4536
4773
|
const stroke = cmd.stroke;
|
|
4537
|
-
|
|
4538
|
-
|
|
4539
|
-
|
|
4540
|
-
|
|
4774
|
+
const { markerStart, markerMid, markerEnd } = stroke;
|
|
4775
|
+
if (typeof stroke.width !== "object" && !isPxMarker(markerStart) && !isPxMarker(markerMid) && !isPxMarker(markerEnd)) {
|
|
4776
|
+
return cmd;
|
|
4777
|
+
}
|
|
4778
|
+
const scale = mat3.meanScaleOf(ctx.state.transform);
|
|
4779
|
+
const resolved = { ...stroke };
|
|
4780
|
+
if (typeof stroke.width === "object") {
|
|
4781
|
+
resolved.width = resolveStrokeWidth(stroke.width, quantizeStrokeScale(stroke.width.px, scale));
|
|
4782
|
+
}
|
|
4783
|
+
if (isPxMarker(markerStart)) resolved.markerStart = resolvedMarker(markerStart, scale);
|
|
4784
|
+
if (isPxMarker(markerMid)) resolved.markerMid = resolvedMarker(markerMid, scale);
|
|
4785
|
+
if (isPxMarker(markerEnd)) resolved.markerEnd = resolvedMarker(markerEnd, scale);
|
|
4786
|
+
return { ...cmd, stroke: resolved };
|
|
4787
|
+
}
|
|
4788
|
+
function isPxMarker(ref) {
|
|
4789
|
+
return typeof ref === "object" && typeof ref.size === "object";
|
|
4790
|
+
}
|
|
4791
|
+
function resolvedMarker(ref, scale) {
|
|
4792
|
+
return { ...ref, size: resolveMarkerSize(ref, 0, quantizeStrokeScale(ref.size.px, scale)) };
|
|
4541
4793
|
}
|
|
4542
4794
|
function drawPathStroke(ctx, rawCmd) {
|
|
4543
|
-
const cmd =
|
|
4795
|
+
const cmd = withResolvedStrokeLengths(ctx, rawCmd);
|
|
4544
4796
|
const stroke = cmd.stroke;
|
|
4545
4797
|
const align = stroke.align ?? "center";
|
|
4546
4798
|
if (cmd.path.kind === "polygon" && align !== "center") {
|
|
4547
4799
|
flushBatch(ctx);
|
|
4548
4800
|
drawPathStrokeStenciled(ctx, cmd, align);
|
|
4549
|
-
|
|
4801
|
+
} else {
|
|
4802
|
+
drawPathStrokeUnclipped(ctx, cmd);
|
|
4803
|
+
}
|
|
4804
|
+
const width = resolveStrokeWidth(stroke.width ?? 1, 1);
|
|
4805
|
+
for (const marker of cachedMarkerCommands(cmd.path, rawCmd.stroke, stroke, width, ctx.flattenTolerance)) {
|
|
4806
|
+
drawPath(ctx, marker);
|
|
4550
4807
|
}
|
|
4551
|
-
drawPathStrokeUnclipped(ctx, cmd);
|
|
4552
4808
|
}
|
|
4553
4809
|
function drawPathStrokeUnclipped(ctx, cmd) {
|
|
4554
4810
|
const stroke = cmd.stroke;
|
|
@@ -5810,13 +6066,14 @@ function pathMisses(path, stroke, m, box) {
|
|
|
5810
6066
|
return quadMisses(minX - reach, minY - reach, maxX + reach, maxY + reach, m, box);
|
|
5811
6067
|
}
|
|
5812
6068
|
function strokeReach(stroke, m) {
|
|
5813
|
-
const
|
|
5814
|
-
|
|
6069
|
+
const scale = mat3.meanScaleOf(m);
|
|
6070
|
+
const base = resolveStrokeWidth(stroke.width ?? 1, scale);
|
|
6071
|
+
let width = base;
|
|
5815
6072
|
if (stroke.vertexWidths) {
|
|
5816
6073
|
for (const v of stroke.vertexWidths) if (v > width) width = v;
|
|
5817
6074
|
}
|
|
5818
6075
|
const spike = Math.max(stroke.miterLimit ?? DEFAULT_MITER_LIMIT2, Math.SQRT2);
|
|
5819
|
-
return Math.abs(width) * spike;
|
|
6076
|
+
return Math.max(Math.abs(width) * spike, markerReach(stroke, base, scale));
|
|
5820
6077
|
}
|
|
5821
6078
|
function spritesMiss(sprites, m, box) {
|
|
5822
6079
|
let minX = Infinity, minY = Infinity, maxX = -Infinity, maxY = -Infinity;
|
|
@@ -6027,6 +6284,15 @@ function reportLayerFailure({ layerId, error }) {
|
|
|
6027
6284
|
error
|
|
6028
6285
|
);
|
|
6029
6286
|
}
|
|
6287
|
+
function subscribeToSources(sources) {
|
|
6288
|
+
return (listener) => {
|
|
6289
|
+
const list2 = typeof sources === "function" ? sources() : sources;
|
|
6290
|
+
const offs = list2.flatMap((l) => l.subscribe ? [l.subscribe(listener)] : []);
|
|
6291
|
+
return () => {
|
|
6292
|
+
for (const off of offs) off();
|
|
6293
|
+
};
|
|
6294
|
+
};
|
|
6295
|
+
}
|
|
6030
6296
|
function drawLayers(layers, data, visibility, order, view, dims, cache7, onLayerError = reportLayerFailure, groups) {
|
|
6031
6297
|
const layerById = new Map(layers.map((l) => [l.id, l]));
|
|
6032
6298
|
const sequence = order ? order.map((id) => layerById.get(id)).filter((l) => l !== void 0) : layers;
|
|
@@ -6216,6 +6482,7 @@ function createViewportLayer(opts) {
|
|
|
6216
6482
|
id,
|
|
6217
6483
|
label,
|
|
6218
6484
|
space: "screen",
|
|
6485
|
+
subscribe: subscribeToSources(sourceAt),
|
|
6219
6486
|
resolvable(outer, dims) {
|
|
6220
6487
|
return { id, view: viewAt(outer, dims), rect: bounds(outer, dims) };
|
|
6221
6488
|
},
|
|
@@ -6346,6 +6613,7 @@ function createParallaxLayer(opts) {
|
|
|
6346
6613
|
id,
|
|
6347
6614
|
label,
|
|
6348
6615
|
space: "screen",
|
|
6616
|
+
subscribe: subscribeToSources(source),
|
|
6349
6617
|
draw: (data, outer, dims) => {
|
|
6350
6618
|
const inner = deriveParallaxView(getOuterView?.() ?? outer, { pan, zoom, anchor });
|
|
6351
6619
|
return source.flatMap((layer) => drawOneLayer(layer, data, inner, dims));
|
|
@@ -6377,6 +6645,7 @@ function createTiledLayer(opts) {
|
|
|
6377
6645
|
id,
|
|
6378
6646
|
label,
|
|
6379
6647
|
space: "world",
|
|
6648
|
+
subscribe: subscribeToSources(source),
|
|
6380
6649
|
draw: (data, view, dims) => {
|
|
6381
6650
|
const p = axes(typeof period === "function" ? period(view, dims) : period, Infinity);
|
|
6382
6651
|
const b = axes(bleed, 0);
|
|
@@ -6958,13 +7227,16 @@ function worldPoseLookup(adapter, compose2) {
|
|
|
6958
7227
|
};
|
|
6959
7228
|
}
|
|
6960
7229
|
|
|
7230
|
+
// src/core/isPlainObject.ts
|
|
7231
|
+
function isPlainPrototype(proto) {
|
|
7232
|
+
return proto === Object.prototype || proto === null || Object.getPrototypeOf(proto) === null;
|
|
7233
|
+
}
|
|
7234
|
+
function isPlainObject(value) {
|
|
7235
|
+
return typeof value === "object" && value !== null && isPlainPrototype(Object.getPrototypeOf(value));
|
|
7236
|
+
}
|
|
7237
|
+
|
|
6961
7238
|
// src/core/scene/poseSnapshot.ts
|
|
6962
7239
|
var DEPTH = 4;
|
|
6963
|
-
function isPlainObject(v) {
|
|
6964
|
-
if (typeof v !== "object" || v === null) return false;
|
|
6965
|
-
const proto = Object.getPrototypeOf(v);
|
|
6966
|
-
return proto === Object.prototype || proto === null;
|
|
6967
|
-
}
|
|
6968
7240
|
function isTypedArray(v) {
|
|
6969
7241
|
return ArrayBuffer.isView(v) && !(v instanceof DataView);
|
|
6970
7242
|
}
|
|
@@ -6989,9 +7261,8 @@ function samePoseValue(snapshot, value, depth = DEPTH) {
|
|
|
6989
7261
|
if (typeof snapshot !== "object" || snapshot === null || typeof value !== "object" || value === null) return Object.is(snapshot, value);
|
|
6990
7262
|
if (depth <= 0) return false;
|
|
6991
7263
|
const proto = Object.getPrototypeOf(snapshot);
|
|
6992
|
-
if (proto
|
|
6993
|
-
|
|
6994
|
-
if (other !== Object.prototype && other !== null) return false;
|
|
7264
|
+
if (isPlainPrototype(proto)) {
|
|
7265
|
+
if (!isPlainPrototype(Object.getPrototypeOf(value))) return false;
|
|
6995
7266
|
const a = snapshot;
|
|
6996
7267
|
const b = value;
|
|
6997
7268
|
let count = 0;
|
|
@@ -7580,7 +7851,6 @@ function beginPointerDrag(payload, source, startX, startY, ghostFn) {
|
|
|
7580
7851
|
}
|
|
7581
7852
|
};
|
|
7582
7853
|
}
|
|
7583
|
-
var DRAG_THRESHOLD_PX_SQ = 25;
|
|
7584
7854
|
function useDragHandle(getPayload, options) {
|
|
7585
7855
|
const optsRef = useRef(options);
|
|
7586
7856
|
optsRef.current = options;
|
|
@@ -7592,8 +7862,7 @@ function useDragHandle(getPayload, options) {
|
|
|
7592
7862
|
if (e.pointerType === "mouse" && e.button !== 0) return;
|
|
7593
7863
|
const target = e.currentTarget;
|
|
7594
7864
|
if (e.target instanceof HTMLElement && e.target.closest("input, button, select, textarea")) return;
|
|
7595
|
-
const
|
|
7596
|
-
const startY = e.clientY;
|
|
7865
|
+
const start = { clientX: e.clientX, clientY: e.clientY };
|
|
7597
7866
|
let ghost = null;
|
|
7598
7867
|
let past = false;
|
|
7599
7868
|
live2.current = openPointerSession(target, e, {
|
|
@@ -7603,9 +7872,7 @@ function useDragHandle(getPayload, options) {
|
|
|
7603
7872
|
return;
|
|
7604
7873
|
}
|
|
7605
7874
|
if (past) return;
|
|
7606
|
-
|
|
7607
|
-
const dy = ev.clientY - startY;
|
|
7608
|
-
if (dx * dx + dy * dy <= DRAG_THRESHOLD_PX_SQ) return;
|
|
7875
|
+
if (!pastDragThreshold(start, ev)) return;
|
|
7609
7876
|
past = true;
|
|
7610
7877
|
const payload = getPayload();
|
|
7611
7878
|
if (!payload) return;
|
|
@@ -7655,15 +7922,11 @@ function useDropZone(opts) {
|
|
|
7655
7922
|
}, []);
|
|
7656
7923
|
}
|
|
7657
7924
|
function startThresholdDrag(e, opts) {
|
|
7658
|
-
const
|
|
7659
|
-
const startY = e.clientY;
|
|
7660
|
-
const threshold = opts.threshold ?? 4;
|
|
7925
|
+
const start = { clientX: e.clientX, clientY: e.clientY };
|
|
7661
7926
|
let activated = false;
|
|
7662
7927
|
const maybeActivate = (ev) => {
|
|
7663
7928
|
if (activated) return;
|
|
7664
|
-
|
|
7665
|
-
const dy = ev.clientY - startY;
|
|
7666
|
-
if (dx * dx + dy * dy < threshold * threshold) return;
|
|
7929
|
+
if (!pastDragThreshold(start, ev, opts.threshold)) return;
|
|
7667
7930
|
activated = true;
|
|
7668
7931
|
opts.onActivate?.(ev);
|
|
7669
7932
|
};
|
|
@@ -8012,6 +8275,47 @@ function paramsMatch(bound, wanted) {
|
|
|
8012
8275
|
return Object.entries(wanted).every(([k, v]) => bound[k] === v);
|
|
8013
8276
|
}
|
|
8014
8277
|
|
|
8278
|
+
// src/interactions/actions/gestureLifecycle.ts
|
|
8279
|
+
function gestureLifecycleParams(o) {
|
|
8280
|
+
const out = {};
|
|
8281
|
+
if (o.label !== void 0) out.label = o.label;
|
|
8282
|
+
if (o.transient !== void 0) out.transient = o.transient;
|
|
8283
|
+
if (o.onGestureStart) out.onGestureStart = o.onGestureStart;
|
|
8284
|
+
if (o.onGestureEnd) out.onGestureEnd = o.onGestureEnd;
|
|
8285
|
+
return out;
|
|
8286
|
+
}
|
|
8287
|
+
function readGestureLifecycle(source, defaultLabel, behaviors = []) {
|
|
8288
|
+
const o = source ?? {};
|
|
8289
|
+
let started = false;
|
|
8290
|
+
let ended = false;
|
|
8291
|
+
return {
|
|
8292
|
+
label: o.label ?? defaultLabel,
|
|
8293
|
+
labelFor: (ops) => o.label ?? ops[0]?.label ?? defaultLabel,
|
|
8294
|
+
transient: o.transient ?? behaviors.some((b) => b.defaultTransient === true),
|
|
8295
|
+
start(ids) {
|
|
8296
|
+
if (started) return;
|
|
8297
|
+
started = true;
|
|
8298
|
+
o.onGestureStart?.([...ids]);
|
|
8299
|
+
},
|
|
8300
|
+
end(committed) {
|
|
8301
|
+
if (!started || ended) return;
|
|
8302
|
+
ended = true;
|
|
8303
|
+
o.onGestureEnd?.(committed);
|
|
8304
|
+
}
|
|
8305
|
+
};
|
|
8306
|
+
}
|
|
8307
|
+
function commitGestureOps(target, lifecycle, ops) {
|
|
8308
|
+
if (lifecycle.transient) {
|
|
8309
|
+
target.scene.untracked(() => {
|
|
8310
|
+
for (const op of ops) op.apply(target.adapter);
|
|
8311
|
+
});
|
|
8312
|
+
return;
|
|
8313
|
+
}
|
|
8314
|
+
const label = lifecycle.labelFor(ops);
|
|
8315
|
+
if (target.applyOps) target.applyOps(ops, label);
|
|
8316
|
+
else target.scene.applyBatch(ops, label, target.adapter);
|
|
8317
|
+
}
|
|
8318
|
+
|
|
8015
8319
|
// src/core/scene/types.ts
|
|
8016
8320
|
var asNodeId = (s) => s;
|
|
8017
8321
|
|
|
@@ -8373,14 +8677,14 @@ function translateCommitOps(scratch, ids, dx, dy) {
|
|
|
8373
8677
|
id,
|
|
8374
8678
|
from: authored,
|
|
8375
8679
|
to: translatePoseViaDescriptor(authored, l.dx, l.dy, scratch.projection),
|
|
8376
|
-
label:
|
|
8680
|
+
label: scratch.lifecycle.label
|
|
8377
8681
|
}));
|
|
8378
8682
|
if (scratch.geometryProjection) {
|
|
8379
8683
|
const dataOp = geometryDataOp(
|
|
8380
8684
|
scratch.geometryProjection,
|
|
8381
8685
|
{ id, data: node.data, pose: authored },
|
|
8382
8686
|
m,
|
|
8383
|
-
|
|
8687
|
+
scratch.lifecycle.label
|
|
8384
8688
|
);
|
|
8385
8689
|
if (dataOp) ops.push(dataOp);
|
|
8386
8690
|
}
|
|
@@ -8502,7 +8806,10 @@ var moveAction = {
|
|
|
8502
8806
|
const pc = ctx.deps.poseComposition ?? IDENTITY_POSE_COMPOSITION;
|
|
8503
8807
|
if (!selection || !scene) return {};
|
|
8504
8808
|
if (isAnchorOrControl(ctx.drag?.affordance)) return {};
|
|
8505
|
-
const
|
|
8809
|
+
const params = resolveParams(opts?.params);
|
|
8810
|
+
const expandIds = params?.["expandIds"];
|
|
8811
|
+
const selected = [...selection.get()];
|
|
8812
|
+
const ids = expandIds ? expandIds(selected) : selected;
|
|
8506
8813
|
if (ids.length === 0) return {};
|
|
8507
8814
|
const startPoses = /* @__PURE__ */ new Map();
|
|
8508
8815
|
const cascadeIds = [];
|
|
@@ -8545,6 +8852,9 @@ var moveAction = {
|
|
|
8545
8852
|
}
|
|
8546
8853
|
}
|
|
8547
8854
|
const behaviors = opts?.behaviors ?? [];
|
|
8855
|
+
const dragThresholdPx = params?.["dragThresholdPx"] ?? DRAG_THRESHOLD_PX;
|
|
8856
|
+
const lifecycle = readGestureLifecycle(params, "Move", behaviors);
|
|
8857
|
+
let engaged = false;
|
|
8548
8858
|
const adapter = moveGestureAdapter(scene);
|
|
8549
8859
|
const origin = /* @__PURE__ */ new Map();
|
|
8550
8860
|
for (const [id, pose] of startPoses) origin.set(id, pose);
|
|
@@ -8577,12 +8887,170 @@ var moveAction = {
|
|
|
8577
8887
|
layoutPass: null,
|
|
8578
8888
|
pc,
|
|
8579
8889
|
applyOps,
|
|
8580
|
-
geometryProjection
|
|
8890
|
+
geometryProjection,
|
|
8891
|
+
lifecycle
|
|
8892
|
+
};
|
|
8893
|
+
const commitMove = (endCtx) => {
|
|
8894
|
+
const { dx, dy } = scratch.currentDelta;
|
|
8895
|
+
let committed = false;
|
|
8896
|
+
const commitOps = (ops) => {
|
|
8897
|
+
commitGestureOps(scratch, lifecycle, ops);
|
|
8898
|
+
committed = true;
|
|
8899
|
+
};
|
|
8900
|
+
if (scratch.behaviors.length > 0) {
|
|
8901
|
+
const gctx = scratch.gestureCtx;
|
|
8902
|
+
for (const [id, ori] of scratch.startPoses) {
|
|
8903
|
+
gctx.current.set(id, translatePoseViaDescriptor(ori, dx, dy, scratch.projection));
|
|
8904
|
+
}
|
|
8905
|
+
for (const b of scratch.behaviors) {
|
|
8906
|
+
const r = b.onEnd?.(gctx);
|
|
8907
|
+
if (r === void 0) continue;
|
|
8908
|
+
if (r === null) return false;
|
|
8909
|
+
commitOps(r);
|
|
8910
|
+
return true;
|
|
8911
|
+
}
|
|
8912
|
+
}
|
|
8913
|
+
if (dx === 0 && dy === 0) return false;
|
|
8914
|
+
if (scratch.layout && scratch.layoutPass) {
|
|
8915
|
+
const lp = scratch.layoutPass;
|
|
8916
|
+
const pc2 = scratch.pc;
|
|
8917
|
+
const commitAdapter = scenePoseAdapter(scratch.scene);
|
|
8918
|
+
const destId = lp.container.id;
|
|
8919
|
+
const draggedIds = new Set(scratch.ids.map((id) => id));
|
|
8920
|
+
const rebaseOpToLocal = (op) => {
|
|
8921
|
+
if (op.name !== "transform") return op;
|
|
8922
|
+
const a = op.args;
|
|
8923
|
+
const curParent = scratch.scene.get(asNodeId(a.id))?.parent ?? null;
|
|
8924
|
+
const toParent = draggedIds.has(a.id) ? destId : curParent;
|
|
8925
|
+
return createTransformOp({
|
|
8926
|
+
id: a.id,
|
|
8927
|
+
from: rebaseLocalPose(commitAdapter, a.from, curParent, pc2.compose, pc2.decompose),
|
|
8928
|
+
to: rebaseLocalPose(commitAdapter, a.to, toParent, pc2.compose, pc2.decompose),
|
|
8929
|
+
label: a.label,
|
|
8930
|
+
coalesceKey: a.coalesceKey
|
|
8931
|
+
});
|
|
8932
|
+
};
|
|
8933
|
+
const reparentOps = [];
|
|
8934
|
+
const dropOps = [];
|
|
8935
|
+
for (const placement of lp.placements) {
|
|
8936
|
+
if (placement.dragged.sourceContainerId !== destId) {
|
|
8937
|
+
reparentOps.push(createReparentOp({
|
|
8938
|
+
id: placement.dragged.id,
|
|
8939
|
+
fromParentId: placement.dragged.sourceContainerId,
|
|
8940
|
+
toParentId: destId,
|
|
8941
|
+
label: "Reparent"
|
|
8942
|
+
}));
|
|
8943
|
+
}
|
|
8944
|
+
const ops2 = lp.layout.commitDrop(
|
|
8945
|
+
lp.container,
|
|
8946
|
+
placement.children,
|
|
8947
|
+
placement.dragged,
|
|
8948
|
+
placement.target
|
|
8949
|
+
);
|
|
8950
|
+
for (const op of ops2) dropOps.push(rebaseOpToLocal(op));
|
|
8951
|
+
}
|
|
8952
|
+
const reflowOps = [];
|
|
8953
|
+
for (const [cid, worldPose] of lp.sourceReflow) {
|
|
8954
|
+
const parent = scratch.scene.get(asNodeId(cid))?.parent ?? null;
|
|
8955
|
+
reflowOps.push(createTransformOp({
|
|
8956
|
+
id: cid,
|
|
8957
|
+
from: scratch.scene.get(asNodeId(cid)).pose,
|
|
8958
|
+
to: rebaseLocalPose(commitAdapter, worldPose, parent, pc2.compose, pc2.decompose),
|
|
8959
|
+
label: "Source reflow"
|
|
8960
|
+
}));
|
|
8961
|
+
}
|
|
8962
|
+
const ops = [...reparentOps, ...dropOps, ...reflowOps];
|
|
8963
|
+
if (ops.length > 0) commitOps(ops);
|
|
8964
|
+
return committed;
|
|
8965
|
+
}
|
|
8966
|
+
const released = /* @__PURE__ */ new Set();
|
|
8967
|
+
const releasedOps = [];
|
|
8968
|
+
if (scratch.layout && !scratch.layoutPass) {
|
|
8969
|
+
const pc2 = scratch.pc;
|
|
8970
|
+
const commitAdapter = scenePoseAdapter(scratch.scene);
|
|
8971
|
+
const rebaseReleased = (op) => {
|
|
8972
|
+
if (op.name !== "transform") return op;
|
|
8973
|
+
const a = op.args;
|
|
8974
|
+
const parent = scratch.scene.get(asNodeId(a.id))?.parent ?? null;
|
|
8975
|
+
return createTransformOp({
|
|
8976
|
+
id: a.id,
|
|
8977
|
+
from: rebaseLocalPose(commitAdapter, a.from, parent, pc2.compose, pc2.decompose),
|
|
8978
|
+
to: rebaseLocalPose(commitAdapter, a.to, parent, pc2.compose, pc2.decompose),
|
|
8979
|
+
label: a.label,
|
|
8980
|
+
coalesceKey: a.coalesceKey
|
|
8981
|
+
});
|
|
8982
|
+
};
|
|
8983
|
+
const sources = groupBySourceContainer(
|
|
8984
|
+
scratch.ids.map((id) => ({
|
|
8985
|
+
id,
|
|
8986
|
+
sourceContainerId: scratch.scene.get(id)?.parent ?? null
|
|
8987
|
+
})),
|
|
8988
|
+
null
|
|
8989
|
+
);
|
|
8990
|
+
for (const [srcId, leaving] of sources) {
|
|
8991
|
+
const srcLayout = scratch.layout.getLayout(srcId);
|
|
8992
|
+
if (!srcLayout?.releaseDrop) continue;
|
|
8993
|
+
const srcContainer = {
|
|
8994
|
+
id: srcId,
|
|
8995
|
+
bounds: scratch.projection.getBounds(
|
|
8996
|
+
composeWorldPose(commitAdapter, srcId, pc2.compose)
|
|
8997
|
+
)
|
|
8998
|
+
};
|
|
8999
|
+
let srcChildren = scratch.scene.childrenOf(asNodeId(srcId)).filter((cid) => !leaving.has(cid)).map((cid) => ({
|
|
9000
|
+
id: cid,
|
|
9001
|
+
pose: composeWorldPose(commitAdapter, cid, pc2.compose)
|
|
9002
|
+
}));
|
|
9003
|
+
for (const id of leaving) {
|
|
9004
|
+
const startWorld = composeWorldPose(commitAdapter, id, pc2.compose);
|
|
9005
|
+
const ops = srcLayout.releaseDrop(srcContainer, srcChildren, {
|
|
9006
|
+
id,
|
|
9007
|
+
originPose: startWorld,
|
|
9008
|
+
pose: translatePoseViaDescriptor(startWorld, dx, dy, scratch.projection),
|
|
9009
|
+
sourceContainerId: srcId
|
|
9010
|
+
});
|
|
9011
|
+
if (ops === null) continue;
|
|
9012
|
+
released.add(id);
|
|
9013
|
+
let landed = startWorld;
|
|
9014
|
+
for (const op of ops) {
|
|
9015
|
+
const a = op.args;
|
|
9016
|
+
if (op.name === "transform" && a.id === id) landed = a.to;
|
|
9017
|
+
releasedOps.push(rebaseReleased(op));
|
|
9018
|
+
}
|
|
9019
|
+
srcChildren = [...srcChildren, { id, pose: landed }];
|
|
9020
|
+
}
|
|
9021
|
+
}
|
|
9022
|
+
}
|
|
9023
|
+
if (released.size > 0) {
|
|
9024
|
+
const ops = [
|
|
9025
|
+
...releasedOps,
|
|
9026
|
+
...translateCommitOps(scratch, unreleasedIds(scratch, released), dx, dy)
|
|
9027
|
+
];
|
|
9028
|
+
if (ops.length > 0) commitOps(ops);
|
|
9029
|
+
return committed;
|
|
9030
|
+
}
|
|
9031
|
+
const reparentMode = resolveParams(opts?.params)?.["reparentOnDrop"] ?? "off";
|
|
9032
|
+
const dropTarget = reparentMode !== "off" ? resolveDropTarget(endCtx, scratch) : null;
|
|
9033
|
+
if (dropTarget) {
|
|
9034
|
+
const reparent = () => applyReparent(scratch, dropTarget, reparentMode, dx, dy, scratch.pc);
|
|
9035
|
+
if (lifecycle.transient) scratch.scene.untracked(reparent);
|
|
9036
|
+
else scratch.scene.batch(lifecycle.label, reparent);
|
|
9037
|
+
committed = true;
|
|
9038
|
+
} else {
|
|
9039
|
+
const ops = translateCommitOps(scratch, [...scratch.ids, ...scratch.cascadeIds], dx, dy);
|
|
9040
|
+
if (ops.length > 0) commitOps(ops);
|
|
9041
|
+
}
|
|
9042
|
+
return committed;
|
|
8581
9043
|
};
|
|
8582
9044
|
return {
|
|
8583
9045
|
kind: "move",
|
|
8584
9046
|
onMove(moveCtx) {
|
|
8585
9047
|
if (!moveCtx.drag) return;
|
|
9048
|
+
if (!engaged) {
|
|
9049
|
+
const s = moveCtx.drag.screenDelta;
|
|
9050
|
+
if (s && !pastDragThreshold({ clientX: 0, clientY: 0 }, { clientX: s.x, clientY: s.y }, dragThresholdPx)) return;
|
|
9051
|
+
engaged = true;
|
|
9052
|
+
lifecycle.start(scratch.ids);
|
|
9053
|
+
}
|
|
8586
9054
|
let dx = moveCtx.drag.delta.x;
|
|
8587
9055
|
let dy = moveCtx.drag.delta.y;
|
|
8588
9056
|
if (scratch.behaviors.length > 0) {
|
|
@@ -8629,171 +9097,14 @@ var moveAction = {
|
|
|
8629
9097
|
syncPreviewOverrides(scratch);
|
|
8630
9098
|
},
|
|
8631
9099
|
onEnd(endCtx, reason) {
|
|
8632
|
-
|
|
9100
|
+
let committed = false;
|
|
9101
|
+
try {
|
|
9102
|
+
if (reason === "commit") committed = commitMove(endCtx);
|
|
9103
|
+
} finally {
|
|
8633
9104
|
dropPreviewOverrides(scratch);
|
|
8634
9105
|
scratch.previews.clear();
|
|
8635
|
-
|
|
8636
|
-
}
|
|
8637
|
-
const { dx, dy } = scratch.currentDelta;
|
|
8638
|
-
const commitOps = (ops, label) => {
|
|
8639
|
-
if (scratch.applyOps) scratch.applyOps(ops, label);
|
|
8640
|
-
else scratch.scene.applyBatch(ops, label, scratch.adapter);
|
|
8641
|
-
};
|
|
8642
|
-
if (scratch.behaviors.length > 0) {
|
|
8643
|
-
const gctx = scratch.gestureCtx;
|
|
8644
|
-
for (const [id, ori] of scratch.startPoses) {
|
|
8645
|
-
gctx.current.set(id, translatePoseViaDescriptor(ori, dx, dy, scratch.projection));
|
|
8646
|
-
}
|
|
8647
|
-
for (const b of scratch.behaviors) {
|
|
8648
|
-
const r = b.onEnd?.(gctx);
|
|
8649
|
-
if (r === void 0) continue;
|
|
8650
|
-
if (r === null) {
|
|
8651
|
-
scratch.previews.clear();
|
|
8652
|
-
return;
|
|
8653
|
-
}
|
|
8654
|
-
commitOps(r, "Move");
|
|
8655
|
-
scratch.previews.clear();
|
|
8656
|
-
return;
|
|
8657
|
-
}
|
|
8658
|
-
}
|
|
8659
|
-
if (dx === 0 && dy === 0) {
|
|
8660
|
-
scratch.previews.clear();
|
|
8661
|
-
return;
|
|
8662
|
-
}
|
|
8663
|
-
if (scratch.layout && scratch.layoutPass) {
|
|
8664
|
-
const lp = scratch.layoutPass;
|
|
8665
|
-
const pc2 = scratch.pc;
|
|
8666
|
-
const commitAdapter = scenePoseAdapter(scratch.scene);
|
|
8667
|
-
const destId = lp.container.id;
|
|
8668
|
-
const draggedIds = new Set(scratch.ids.map((id) => id));
|
|
8669
|
-
const rebaseOpToLocal = (op) => {
|
|
8670
|
-
if (op.name !== "transform") return op;
|
|
8671
|
-
const a = op.args;
|
|
8672
|
-
const curParent = scratch.scene.get(asNodeId(a.id))?.parent ?? null;
|
|
8673
|
-
const toParent = draggedIds.has(a.id) ? destId : curParent;
|
|
8674
|
-
return createTransformOp({
|
|
8675
|
-
id: a.id,
|
|
8676
|
-
from: rebaseLocalPose(commitAdapter, a.from, curParent, pc2.compose, pc2.decompose),
|
|
8677
|
-
to: rebaseLocalPose(commitAdapter, a.to, toParent, pc2.compose, pc2.decompose),
|
|
8678
|
-
label: a.label,
|
|
8679
|
-
coalesceKey: a.coalesceKey
|
|
8680
|
-
});
|
|
8681
|
-
};
|
|
8682
|
-
const reparentOps = [];
|
|
8683
|
-
const dropOps = [];
|
|
8684
|
-
for (const placement of lp.placements) {
|
|
8685
|
-
if (placement.dragged.sourceContainerId !== destId) {
|
|
8686
|
-
reparentOps.push(createReparentOp({
|
|
8687
|
-
id: placement.dragged.id,
|
|
8688
|
-
fromParentId: placement.dragged.sourceContainerId,
|
|
8689
|
-
toParentId: destId,
|
|
8690
|
-
label: "Reparent"
|
|
8691
|
-
}));
|
|
8692
|
-
}
|
|
8693
|
-
const ops2 = lp.layout.commitDrop(
|
|
8694
|
-
lp.container,
|
|
8695
|
-
placement.children,
|
|
8696
|
-
placement.dragged,
|
|
8697
|
-
placement.target
|
|
8698
|
-
);
|
|
8699
|
-
for (const op of ops2) dropOps.push(rebaseOpToLocal(op));
|
|
8700
|
-
}
|
|
8701
|
-
const reflowOps = [];
|
|
8702
|
-
for (const [cid, worldPose] of lp.sourceReflow) {
|
|
8703
|
-
const parent = scratch.scene.get(asNodeId(cid))?.parent ?? null;
|
|
8704
|
-
reflowOps.push(createTransformOp({
|
|
8705
|
-
id: cid,
|
|
8706
|
-
from: scratch.scene.get(asNodeId(cid)).pose,
|
|
8707
|
-
to: rebaseLocalPose(commitAdapter, worldPose, parent, pc2.compose, pc2.decompose),
|
|
8708
|
-
label: "Source reflow"
|
|
8709
|
-
}));
|
|
8710
|
-
}
|
|
8711
|
-
const ops = [...reparentOps, ...dropOps, ...reflowOps];
|
|
8712
|
-
if (ops.length > 0) {
|
|
8713
|
-
commitOps(ops, ops[0].label ?? "Move");
|
|
8714
|
-
}
|
|
8715
|
-
scratch.previews.clear();
|
|
8716
|
-
return;
|
|
8717
|
-
}
|
|
8718
|
-
const released = /* @__PURE__ */ new Set();
|
|
8719
|
-
const releasedOps = [];
|
|
8720
|
-
if (scratch.layout && !scratch.layoutPass) {
|
|
8721
|
-
const pc2 = scratch.pc;
|
|
8722
|
-
const commitAdapter = scenePoseAdapter(scratch.scene);
|
|
8723
|
-
const rebaseReleased = (op) => {
|
|
8724
|
-
if (op.name !== "transform") return op;
|
|
8725
|
-
const a = op.args;
|
|
8726
|
-
const parent = scratch.scene.get(asNodeId(a.id))?.parent ?? null;
|
|
8727
|
-
return createTransformOp({
|
|
8728
|
-
id: a.id,
|
|
8729
|
-
from: rebaseLocalPose(commitAdapter, a.from, parent, pc2.compose, pc2.decompose),
|
|
8730
|
-
to: rebaseLocalPose(commitAdapter, a.to, parent, pc2.compose, pc2.decompose),
|
|
8731
|
-
label: a.label,
|
|
8732
|
-
coalesceKey: a.coalesceKey
|
|
8733
|
-
});
|
|
8734
|
-
};
|
|
8735
|
-
const sources = groupBySourceContainer(
|
|
8736
|
-
scratch.ids.map((id) => ({
|
|
8737
|
-
id,
|
|
8738
|
-
sourceContainerId: scratch.scene.get(id)?.parent ?? null
|
|
8739
|
-
})),
|
|
8740
|
-
null
|
|
8741
|
-
);
|
|
8742
|
-
for (const [srcId, leaving] of sources) {
|
|
8743
|
-
const srcLayout = scratch.layout.getLayout(srcId);
|
|
8744
|
-
if (!srcLayout?.releaseDrop) continue;
|
|
8745
|
-
const srcContainer = {
|
|
8746
|
-
id: srcId,
|
|
8747
|
-
bounds: scratch.projection.getBounds(
|
|
8748
|
-
composeWorldPose(commitAdapter, srcId, pc2.compose)
|
|
8749
|
-
)
|
|
8750
|
-
};
|
|
8751
|
-
let srcChildren = scratch.scene.childrenOf(asNodeId(srcId)).filter((cid) => !leaving.has(cid)).map((cid) => ({
|
|
8752
|
-
id: cid,
|
|
8753
|
-
pose: composeWorldPose(commitAdapter, cid, pc2.compose)
|
|
8754
|
-
}));
|
|
8755
|
-
for (const id of leaving) {
|
|
8756
|
-
const startWorld = composeWorldPose(commitAdapter, id, pc2.compose);
|
|
8757
|
-
const ops = srcLayout.releaseDrop(srcContainer, srcChildren, {
|
|
8758
|
-
id,
|
|
8759
|
-
originPose: startWorld,
|
|
8760
|
-
pose: translatePoseViaDescriptor(startWorld, dx, dy, scratch.projection),
|
|
8761
|
-
sourceContainerId: srcId
|
|
8762
|
-
});
|
|
8763
|
-
if (ops === null) continue;
|
|
8764
|
-
released.add(id);
|
|
8765
|
-
let landed = startWorld;
|
|
8766
|
-
for (const op of ops) {
|
|
8767
|
-
const a = op.args;
|
|
8768
|
-
if (op.name === "transform" && a.id === id) landed = a.to;
|
|
8769
|
-
releasedOps.push(rebaseReleased(op));
|
|
8770
|
-
}
|
|
8771
|
-
srcChildren = [...srcChildren, { id, pose: landed }];
|
|
8772
|
-
}
|
|
8773
|
-
}
|
|
8774
|
-
}
|
|
8775
|
-
if (released.size > 0) {
|
|
8776
|
-
const ops = [
|
|
8777
|
-
...releasedOps,
|
|
8778
|
-
...translateCommitOps(scratch, unreleasedIds(scratch, released), dx, dy)
|
|
8779
|
-
];
|
|
8780
|
-
if (ops.length > 0) commitOps(ops, ops[0].label ?? "Move");
|
|
8781
|
-
scratch.previews.clear();
|
|
8782
|
-
return;
|
|
9106
|
+
lifecycle.end(committed);
|
|
8783
9107
|
}
|
|
8784
|
-
const resolved = resolveParams(opts?.params);
|
|
8785
|
-
const reparentMode = resolved?.["reparentOnDrop"] ?? "off";
|
|
8786
|
-
const dropTarget = reparentMode !== "off" ? resolveDropTarget(endCtx, scratch) : null;
|
|
8787
|
-
if (dropTarget) {
|
|
8788
|
-
scratch.scene.batch("Move", () => {
|
|
8789
|
-
applyReparent(scratch, dropTarget, reparentMode, dx, dy, scratch.pc);
|
|
8790
|
-
});
|
|
8791
|
-
} else {
|
|
8792
|
-
const ops = translateCommitOps(scratch, [...scratch.ids, ...scratch.cascadeIds], dx, dy);
|
|
8793
|
-
if (ops.length > 0) commitOps(ops, "Move");
|
|
8794
|
-
}
|
|
8795
|
-
dropPreviewOverrides(scratch);
|
|
8796
|
-
scratch.previews.clear();
|
|
8797
9108
|
},
|
|
8798
9109
|
previewIds: () => scratch.previews.keys(),
|
|
8799
9110
|
previewPose: (id) => scratch.previews.get(id) ?? null,
|
|
@@ -8913,14 +9224,16 @@ function resolveDeps(ctx) {
|
|
|
8913
9224
|
behaviors: DEFAULT_RESIZE_BEHAVIORS,
|
|
8914
9225
|
pointSnap: EMPTY_POINT_SNAP,
|
|
8915
9226
|
expandIds: IDENTITY_EXPAND,
|
|
8916
|
-
geometry
|
|
9227
|
+
geometry,
|
|
9228
|
+
policy: void 0
|
|
8917
9229
|
};
|
|
8918
9230
|
}
|
|
8919
9231
|
return {
|
|
8920
9232
|
behaviors: dep.constraints,
|
|
8921
9233
|
pointSnap: dep.pointSnap,
|
|
8922
9234
|
expandIds: dep.expandIds,
|
|
8923
|
-
geometry
|
|
9235
|
+
geometry,
|
|
9236
|
+
policy: dep
|
|
8924
9237
|
};
|
|
8925
9238
|
}
|
|
8926
9239
|
function buildPointSnapContext(pose, rotation, anchor, modifiers) {
|
|
@@ -9004,7 +9317,9 @@ function computeProposedBounds(ob, anchor, dx, dy, rotation) {
|
|
|
9004
9317
|
var resizeAction = {
|
|
9005
9318
|
id: "resize",
|
|
9006
9319
|
label: "Resize",
|
|
9007
|
-
|
|
9320
|
+
// No default binding: a bare `{ kind: 'drag' }` claimed every drag at ambient
|
|
9321
|
+
// scope, tying areaSelect's. The resize handles bind it
|
|
9322
|
+
// (`selectionTransformBindings`, the `transform` preset).
|
|
9008
9323
|
eligible: { capability: "transforms-selection" },
|
|
9009
9324
|
requires: ["selection", "scene", "resizePolicy", "poseDescriptor", "applyOps", "geometryProjection", "poseComposition"],
|
|
9010
9325
|
invoker: {
|
|
@@ -9020,7 +9335,7 @@ var resizeAction = {
|
|
|
9020
9335
|
const affordance = ctx.drag?.affordance;
|
|
9021
9336
|
const anchor = affordance?.anchor;
|
|
9022
9337
|
if (!anchor) return {};
|
|
9023
|
-
const { behaviors, pointSnap, expandIds, geometry } = resolveDeps(ctx);
|
|
9338
|
+
const { behaviors, pointSnap, expandIds, geometry, policy } = resolveDeps(ctx);
|
|
9024
9339
|
const expanded = expandIds(ids);
|
|
9025
9340
|
if (expanded.length === 0) return {};
|
|
9026
9341
|
const isGroupPath = ids.length === 1 && (expanded.length !== 1 || expanded[0] !== ids[0]);
|
|
@@ -9081,7 +9396,78 @@ var resizeAction = {
|
|
|
9081
9396
|
pointSnap,
|
|
9082
9397
|
gestureCtx,
|
|
9083
9398
|
applyOps,
|
|
9084
|
-
geometryProjection
|
|
9399
|
+
geometryProjection,
|
|
9400
|
+
lifecycle: readGestureLifecycle(policy, "Resize", behaviors)
|
|
9401
|
+
};
|
|
9402
|
+
const { lifecycle } = scratch;
|
|
9403
|
+
lifecycle.start(writeIds);
|
|
9404
|
+
const commitResize = () => {
|
|
9405
|
+
const target = {
|
|
9406
|
+
scene,
|
|
9407
|
+
applyOps: scratch.applyOps,
|
|
9408
|
+
adapter: defaultCommitAdapter(scene, selection.adapterMethods)
|
|
9409
|
+
};
|
|
9410
|
+
for (const b of scratch.behaviors) {
|
|
9411
|
+
const r = b.onEnd?.(scratch.gestureCtx);
|
|
9412
|
+
if (r === void 0) continue;
|
|
9413
|
+
if (r === null) return false;
|
|
9414
|
+
commitGestureOps(target, lifecycle, r);
|
|
9415
|
+
return true;
|
|
9416
|
+
}
|
|
9417
|
+
if (scratch.previews.size === 0) return false;
|
|
9418
|
+
const ops = [];
|
|
9419
|
+
for (const id of scratch.writeIds) {
|
|
9420
|
+
const next = scratch.previews.get(id);
|
|
9421
|
+
if (next === void 0) continue;
|
|
9422
|
+
const from = scratch.startPoses.get(id);
|
|
9423
|
+
if (from === void 0) continue;
|
|
9424
|
+
let committed = next;
|
|
9425
|
+
if (scratch.geometryProjection) {
|
|
9426
|
+
const node = scratch.scene.get(id);
|
|
9427
|
+
if (node) {
|
|
9428
|
+
const sb = scratch.geometry.getBounds(from);
|
|
9429
|
+
const db = scratch.geometry.getBounds(next);
|
|
9430
|
+
const m = boxToBox(
|
|
9431
|
+
sb.x,
|
|
9432
|
+
sb.y,
|
|
9433
|
+
sb.width,
|
|
9434
|
+
sb.height,
|
|
9435
|
+
db.x,
|
|
9436
|
+
db.y,
|
|
9437
|
+
db.width,
|
|
9438
|
+
db.height
|
|
9439
|
+
);
|
|
9440
|
+
const dataOp = geometryDataOp(
|
|
9441
|
+
scratch.geometryProjection,
|
|
9442
|
+
{ id, data: node.data, pose: from },
|
|
9443
|
+
m,
|
|
9444
|
+
lifecycle.label
|
|
9445
|
+
);
|
|
9446
|
+
if (dataOp) {
|
|
9447
|
+
ops.push(dataOp);
|
|
9448
|
+
if (db.width < 0 || db.height < 0) {
|
|
9449
|
+
const nb = {
|
|
9450
|
+
...db,
|
|
9451
|
+
x: db.width < 0 ? db.x + db.width : db.x,
|
|
9452
|
+
y: db.height < 0 ? db.y + db.height : db.y,
|
|
9453
|
+
width: Math.abs(db.width),
|
|
9454
|
+
height: Math.abs(db.height)
|
|
9455
|
+
};
|
|
9456
|
+
committed = scratch.geometry.remapBounds(next, db, nb);
|
|
9457
|
+
}
|
|
9458
|
+
}
|
|
9459
|
+
}
|
|
9460
|
+
}
|
|
9461
|
+
ops.push(createTransformOp({
|
|
9462
|
+
id,
|
|
9463
|
+
from,
|
|
9464
|
+
to: committed,
|
|
9465
|
+
label: lifecycle.label
|
|
9466
|
+
}));
|
|
9467
|
+
}
|
|
9468
|
+
if (ops.length === 0) return false;
|
|
9469
|
+
commitGestureOps(target, lifecycle, ops);
|
|
9470
|
+
return true;
|
|
9085
9471
|
};
|
|
9086
9472
|
return {
|
|
9087
9473
|
kind: "resize",
|
|
@@ -9183,79 +9569,14 @@ var resizeAction = {
|
|
|
9183
9569
|
syncPreviewOverrides(scratch);
|
|
9184
9570
|
},
|
|
9185
9571
|
onEnd(_endCtx, reason) {
|
|
9186
|
-
|
|
9572
|
+
let committed = false;
|
|
9573
|
+
try {
|
|
9574
|
+
if (reason === "commit") committed = commitResize();
|
|
9575
|
+
} finally {
|
|
9187
9576
|
dropPreviewOverrides(scratch);
|
|
9188
9577
|
scratch.previews.clear();
|
|
9189
|
-
|
|
9190
|
-
}
|
|
9191
|
-
for (const b of scratch.behaviors) {
|
|
9192
|
-
const r = b.onEnd?.(scratch.gestureCtx);
|
|
9193
|
-
if (r === null) {
|
|
9194
|
-
dropPreviewOverrides(scratch);
|
|
9195
|
-
scratch.previews.clear();
|
|
9196
|
-
return;
|
|
9197
|
-
}
|
|
9198
|
-
}
|
|
9199
|
-
if (scratch.previews.size === 0) {
|
|
9200
|
-
dropPreviewOverrides(scratch);
|
|
9201
|
-
return;
|
|
9202
|
-
}
|
|
9203
|
-
const ops = [];
|
|
9204
|
-
for (const id of scratch.writeIds) {
|
|
9205
|
-
const next = scratch.previews.get(id);
|
|
9206
|
-
if (next === void 0) continue;
|
|
9207
|
-
const from = scratch.startPoses.get(id);
|
|
9208
|
-
if (from === void 0) continue;
|
|
9209
|
-
let committed = next;
|
|
9210
|
-
if (scratch.geometryProjection) {
|
|
9211
|
-
const node = scratch.scene.get(id);
|
|
9212
|
-
if (node) {
|
|
9213
|
-
const sb = scratch.geometry.getBounds(from);
|
|
9214
|
-
const db = scratch.geometry.getBounds(next);
|
|
9215
|
-
const m = boxToBox(
|
|
9216
|
-
sb.x,
|
|
9217
|
-
sb.y,
|
|
9218
|
-
sb.width,
|
|
9219
|
-
sb.height,
|
|
9220
|
-
db.x,
|
|
9221
|
-
db.y,
|
|
9222
|
-
db.width,
|
|
9223
|
-
db.height
|
|
9224
|
-
);
|
|
9225
|
-
const dataOp = geometryDataOp(
|
|
9226
|
-
scratch.geometryProjection,
|
|
9227
|
-
{ id, data: node.data, pose: from },
|
|
9228
|
-
m,
|
|
9229
|
-
"Resize"
|
|
9230
|
-
);
|
|
9231
|
-
if (dataOp) {
|
|
9232
|
-
ops.push(dataOp);
|
|
9233
|
-
if (db.width < 0 || db.height < 0) {
|
|
9234
|
-
const nb = {
|
|
9235
|
-
...db,
|
|
9236
|
-
x: db.width < 0 ? db.x + db.width : db.x,
|
|
9237
|
-
y: db.height < 0 ? db.y + db.height : db.y,
|
|
9238
|
-
width: Math.abs(db.width),
|
|
9239
|
-
height: Math.abs(db.height)
|
|
9240
|
-
};
|
|
9241
|
-
committed = scratch.geometry.remapBounds(next, db, nb);
|
|
9242
|
-
}
|
|
9243
|
-
}
|
|
9244
|
-
}
|
|
9245
|
-
}
|
|
9246
|
-
ops.push(createTransformOp({
|
|
9247
|
-
id,
|
|
9248
|
-
from,
|
|
9249
|
-
to: committed,
|
|
9250
|
-
label: "Resize"
|
|
9251
|
-
}));
|
|
9252
|
-
}
|
|
9253
|
-
if (ops.length > 0) {
|
|
9254
|
-
if (scratch.applyOps) scratch.applyOps(ops, "Resize");
|
|
9255
|
-
else scratch.scene.applyBatch(ops, "Resize", defaultCommitAdapter(scratch.scene, selection.adapterMethods));
|
|
9578
|
+
lifecycle.end(committed);
|
|
9256
9579
|
}
|
|
9257
|
-
dropPreviewOverrides(scratch);
|
|
9258
|
-
scratch.previews.clear();
|
|
9259
9580
|
},
|
|
9260
9581
|
previewIds: () => scratch.previews.keys(),
|
|
9261
9582
|
previewPose: (id) => scratch.previews.get(id) ?? null
|
|
@@ -9276,8 +9597,6 @@ var resizeAction = {
|
|
|
9276
9597
|
*/
|
|
9277
9598
|
enabled: () => true
|
|
9278
9599
|
};
|
|
9279
|
-
|
|
9280
|
-
// src/interactions/actions/defaults/rotate.ts
|
|
9281
9600
|
function applyRotationDelta(d, pose, originRotation, delta3, originCenter, unionCenter, useUnionPivot) {
|
|
9282
9601
|
const rotated = d.withRotation(pose, originRotation + delta3);
|
|
9283
9602
|
if (!useUnionPivot) return rotated;
|
|
@@ -9292,15 +9611,19 @@ function applyRotationDelta(d, pose, originRotation, delta3, originCenter, union
|
|
|
9292
9611
|
var rotateAction = {
|
|
9293
9612
|
id: "rotate",
|
|
9294
9613
|
label: "Rotate",
|
|
9295
|
-
|
|
9614
|
+
// No default binding. It used to be a bare `{ kind: 'drag' }`, which made
|
|
9615
|
+
// any drag no active tool claimed rotate a non-empty selection. The rotation
|
|
9616
|
+
// handle binds it (`selectionTransformBindings`, the `transform` preset).
|
|
9296
9617
|
eligible: { capability: "transforms-selection" },
|
|
9297
9618
|
requires: ["selection", "scene", "applyOps", "poseDescriptor", "poseComposition"],
|
|
9298
9619
|
invoker: {
|
|
9299
9620
|
timing: "ongoing",
|
|
9300
|
-
start(ctx,
|
|
9621
|
+
start(ctx, opts) {
|
|
9301
9622
|
const selection = ctx.deps.selection;
|
|
9302
9623
|
const scene = ctx.deps.scene;
|
|
9303
9624
|
const applyOps = ctx.deps.applyOps;
|
|
9625
|
+
const params = resolveParams(opts?.params);
|
|
9626
|
+
const behaviors = opts?.behaviors ?? [];
|
|
9304
9627
|
if (!selection || !scene) return {};
|
|
9305
9628
|
const ids = selection.get();
|
|
9306
9629
|
if (ids.length === 0) return {};
|
|
@@ -9343,35 +9666,109 @@ var rotateAction = {
|
|
|
9343
9666
|
unionCenter,
|
|
9344
9667
|
startPointerAngle,
|
|
9345
9668
|
currentDelta: 0,
|
|
9346
|
-
useUnionPivot: ids.length > 1,
|
|
9669
|
+
useUnionPivot: ids.length > 1 && params?.["pivot"] !== "each",
|
|
9347
9670
|
previews: /* @__PURE__ */ new Map(),
|
|
9348
9671
|
overrideEntries: /* @__PURE__ */ new Map(),
|
|
9349
|
-
applyOps
|
|
9350
|
-
|
|
9351
|
-
|
|
9352
|
-
|
|
9353
|
-
|
|
9354
|
-
|
|
9355
|
-
|
|
9672
|
+
applyOps,
|
|
9673
|
+
lifecycle: readGestureLifecycle(params, "Rotate", behaviors),
|
|
9674
|
+
behaviors,
|
|
9675
|
+
gestureCtx: {
|
|
9676
|
+
draggedIds: [...originPoses.keys()],
|
|
9677
|
+
origin: new Map([...originWorlds].map(([id, p]) => [id, p])),
|
|
9678
|
+
current: new Map([...originWorlds].map(([id, p]) => [id, p])),
|
|
9679
|
+
snap: null,
|
|
9680
|
+
modifiers: { ...ctx.modifiers },
|
|
9681
|
+
pointer: { worldX: ctx.world.x, worldY: ctx.world.y, clientX: 0, clientY: 0 },
|
|
9682
|
+
adapter: moveGestureAdapter(scene),
|
|
9683
|
+
scratch: {}
|
|
9356
9684
|
}
|
|
9357
|
-
|
|
9358
|
-
|
|
9359
|
-
|
|
9360
|
-
|
|
9361
|
-
|
|
9362
|
-
|
|
9685
|
+
};
|
|
9686
|
+
const { lifecycle } = scratch;
|
|
9687
|
+
const turnedWorlds = (delta3) => {
|
|
9688
|
+
const out = /* @__PURE__ */ new Map();
|
|
9689
|
+
for (const [id, origin] of scratch.originWorlds) {
|
|
9690
|
+
out.set(id, applyRotationDelta(
|
|
9363
9691
|
scratch.descriptor,
|
|
9364
9692
|
origin,
|
|
9365
|
-
|
|
9693
|
+
scratch.originRotations.get(id) ?? 0,
|
|
9366
9694
|
delta3,
|
|
9367
|
-
|
|
9695
|
+
scratch.originCenters.get(id) ?? { x: 0, y: 0 },
|
|
9368
9696
|
scratch.unionCenter,
|
|
9369
9697
|
scratch.useUnionPivot
|
|
9370
|
-
);
|
|
9371
|
-
|
|
9698
|
+
));
|
|
9699
|
+
}
|
|
9700
|
+
return out;
|
|
9701
|
+
};
|
|
9702
|
+
const syncGestureCurrent = (delta3) => {
|
|
9703
|
+
const turned = turnedWorlds(delta3);
|
|
9704
|
+
for (const [id, pose] of turned) scratch.gestureCtx.current.set(id, pose);
|
|
9705
|
+
return turned;
|
|
9706
|
+
};
|
|
9707
|
+
const shapeDelta = (moveCtx, raw) => {
|
|
9708
|
+
const gctx = scratch.gestureCtx;
|
|
9709
|
+
gctx.modifiers = { ...moveCtx.modifiers };
|
|
9710
|
+
gctx.pointer = { worldX: moveCtx.world.x, worldY: moveCtx.world.y, clientX: 0, clientY: 0 };
|
|
9711
|
+
const primary = scratch.originWorlds.keys().next().value;
|
|
9712
|
+
const originRotation = scratch.originRotations.get(primary) ?? 0;
|
|
9713
|
+
let delta3 = raw;
|
|
9714
|
+
let proposed = {
|
|
9715
|
+
pose: syncGestureCurrent(raw).get(primary),
|
|
9716
|
+
rotation: originRotation + raw
|
|
9717
|
+
};
|
|
9718
|
+
for (const b of scratch.behaviors) {
|
|
9719
|
+
const r = b.onMove?.(gctx, proposed);
|
|
9720
|
+
if (!r || r.pose === void 0) continue;
|
|
9721
|
+
const rotation = scratch.descriptor.getRotation?.(r.pose) ?? 0;
|
|
9722
|
+
delta3 = rotation - originRotation;
|
|
9723
|
+
proposed = { pose: r.pose, rotation };
|
|
9724
|
+
}
|
|
9725
|
+
return delta3;
|
|
9726
|
+
};
|
|
9727
|
+
const commitRotate = () => {
|
|
9728
|
+
const target = {
|
|
9729
|
+
scene,
|
|
9730
|
+
applyOps: scratch.applyOps,
|
|
9731
|
+
adapter: defaultCommitAdapter(scene, selection.adapterMethods)
|
|
9732
|
+
};
|
|
9733
|
+
if (scratch.behaviors.length > 0) {
|
|
9734
|
+
syncGestureCurrent(scratch.currentDelta);
|
|
9735
|
+
for (const b of scratch.behaviors) {
|
|
9736
|
+
const r = b.onEnd?.(scratch.gestureCtx);
|
|
9737
|
+
if (r === void 0) continue;
|
|
9738
|
+
if (r === null) return false;
|
|
9739
|
+
commitGestureOps(target, lifecycle, r);
|
|
9740
|
+
return true;
|
|
9741
|
+
}
|
|
9742
|
+
}
|
|
9743
|
+
if (scratch.currentDelta === 0) return false;
|
|
9744
|
+
const ops = [];
|
|
9745
|
+
for (const id of scratch.ids) {
|
|
9746
|
+
const next = scratch.previews.get(id);
|
|
9747
|
+
if (next === void 0) continue;
|
|
9748
|
+
const from = scratch.originPoses.get(id);
|
|
9749
|
+
if (from === void 0) continue;
|
|
9750
|
+
ops.push(createTransformOp({
|
|
9751
|
+
id,
|
|
9752
|
+
from,
|
|
9753
|
+
to: next,
|
|
9754
|
+
label: lifecycle.label
|
|
9755
|
+
}));
|
|
9756
|
+
}
|
|
9757
|
+
if (ops.length === 0) return false;
|
|
9758
|
+
commitGestureOps(target, lifecycle, ops);
|
|
9759
|
+
return true;
|
|
9760
|
+
};
|
|
9761
|
+
const recomputePreviews = (delta3) => {
|
|
9762
|
+
scratch.previews.clear();
|
|
9763
|
+
if (delta3 !== 0) {
|
|
9764
|
+
for (const [id, turned] of turnedWorlds(delta3)) {
|
|
9765
|
+
scratch.previews.set(id, scratch.frame.local(id, turned));
|
|
9766
|
+
}
|
|
9372
9767
|
}
|
|
9373
9768
|
syncPreviewOverrides(scratch);
|
|
9374
9769
|
};
|
|
9770
|
+
for (const b of behaviors) b.onStart?.(scratch.gestureCtx);
|
|
9771
|
+
lifecycle.start(scratch.gestureCtx.draggedIds);
|
|
9375
9772
|
return {
|
|
9376
9773
|
kind: "rotate",
|
|
9377
9774
|
onMove(moveCtx) {
|
|
@@ -9379,39 +9776,19 @@ var rotateAction = {
|
|
|
9379
9776
|
moveCtx.world.y - scratch.unionCenter.y,
|
|
9380
9777
|
moveCtx.world.x - scratch.unionCenter.x
|
|
9381
9778
|
);
|
|
9382
|
-
|
|
9779
|
+
const raw = pointerAngle - scratch.startPointerAngle;
|
|
9780
|
+
scratch.currentDelta = scratch.behaviors.length > 0 ? shapeDelta(moveCtx, raw) : raw;
|
|
9383
9781
|
recomputePreviews(scratch.currentDelta);
|
|
9384
9782
|
},
|
|
9385
9783
|
onEnd(_endCtx, reason) {
|
|
9386
|
-
|
|
9387
|
-
|
|
9388
|
-
|
|
9389
|
-
|
|
9390
|
-
}
|
|
9391
|
-
if (scratch.currentDelta === 0) {
|
|
9784
|
+
let committed = false;
|
|
9785
|
+
try {
|
|
9786
|
+
if (reason === "commit") committed = commitRotate();
|
|
9787
|
+
} finally {
|
|
9392
9788
|
dropPreviewOverrides(scratch);
|
|
9393
9789
|
scratch.previews.clear();
|
|
9394
|
-
|
|
9395
|
-
}
|
|
9396
|
-
const ops = [];
|
|
9397
|
-
for (const id of scratch.ids) {
|
|
9398
|
-
const next = scratch.previews.get(id);
|
|
9399
|
-
if (next === void 0) continue;
|
|
9400
|
-
const from = scratch.originPoses.get(id);
|
|
9401
|
-
if (from === void 0) continue;
|
|
9402
|
-
ops.push(createTransformOp({
|
|
9403
|
-
id,
|
|
9404
|
-
from,
|
|
9405
|
-
to: next,
|
|
9406
|
-
label: "Rotate"
|
|
9407
|
-
}));
|
|
9408
|
-
}
|
|
9409
|
-
if (ops.length > 0) {
|
|
9410
|
-
if (scratch.applyOps) scratch.applyOps(ops, "Rotate");
|
|
9411
|
-
else scratch.scene.applyBatch(ops, "Rotate", defaultCommitAdapter(scratch.scene, selection.adapterMethods));
|
|
9790
|
+
lifecycle.end(committed);
|
|
9412
9791
|
}
|
|
9413
|
-
dropPreviewOverrides(scratch);
|
|
9414
|
-
scratch.previews.clear();
|
|
9415
9792
|
},
|
|
9416
9793
|
previewIds: () => scratch.previews.keys(),
|
|
9417
9794
|
previewPose: (id) => scratch.previews.get(id) ?? null
|
|
@@ -9428,7 +9805,6 @@ var areaSelectAction = {
|
|
|
9428
9805
|
// Crosshair while the marquee is being pulled — the select tool used to
|
|
9429
9806
|
// read this off its own gesture scratch.
|
|
9430
9807
|
activeCursor: "crosshair",
|
|
9431
|
-
defaultBinding: { kind: "drag" },
|
|
9432
9808
|
eligible: { capability: "creates-selection" },
|
|
9433
9809
|
requires: ["areaSelect", "editAnchors", "view"],
|
|
9434
9810
|
invoker: {
|
|
@@ -9618,7 +9994,6 @@ var insertAction = {
|
|
|
9618
9994
|
id: "insert",
|
|
9619
9995
|
label: "Insert",
|
|
9620
9996
|
group: "insert",
|
|
9621
|
-
defaultBinding: { kind: "drag" },
|
|
9622
9997
|
eligible: { capability: "creates-shapes" },
|
|
9623
9998
|
requires: ["insert", "selection", "snap", "textEdit"],
|
|
9624
9999
|
invoker: {
|
|
@@ -9788,7 +10163,9 @@ function freshNodeId() {
|
|
|
9788
10163
|
var cloneAction = {
|
|
9789
10164
|
id: "clone",
|
|
9790
10165
|
label: "Clone",
|
|
9791
|
-
|
|
10166
|
+
// No default binding: a bare `{ kind: 'drag' }` would clone a non-empty
|
|
10167
|
+
// selection on any drag no tool claimed. Alt-drag on a body binds it
|
|
10168
|
+
// (`selectionMoveBindings`, the `move` preset).
|
|
9792
10169
|
// The platform's duplicate cursor, and the whole reason this field is
|
|
9793
10170
|
// modifier-aware: the select tool binds clone behind `mods: { alt: true }`,
|
|
9794
10171
|
// so the pump predicts it — and shows this — only while Alt is down.
|
|
@@ -9924,7 +10301,6 @@ var viewportDragPanAction = {
|
|
|
9924
10301
|
id: "viewport.dragPan",
|
|
9925
10302
|
label: "Drag to pan viewport",
|
|
9926
10303
|
group: "viewport",
|
|
9927
|
-
defaultBinding: { kind: "drag" },
|
|
9928
10304
|
// Hover hint: when this action would win the drag at the hovered point
|
|
9929
10305
|
// (e.g. empty canvas with no marquee-capable tool ahead of it), the
|
|
9930
10306
|
// hover-cursor pump shows the open hand.
|
|
@@ -10178,20 +10554,9 @@ function cubicPointAt(p0, p1, p2, p3, t) {
|
|
|
10178
10554
|
return { x, y };
|
|
10179
10555
|
}
|
|
10180
10556
|
function splitCubicAtT(p0, p1, p2, p3, t) {
|
|
10181
|
-
const
|
|
10182
|
-
|
|
10183
|
-
|
|
10184
|
-
});
|
|
10185
|
-
const q0 = lerp(p0, p1);
|
|
10186
|
-
const q1 = lerp(p1, p2);
|
|
10187
|
-
const q2 = lerp(p2, p3);
|
|
10188
|
-
const r0 = lerp(q0, q1);
|
|
10189
|
-
const r1 = lerp(q1, q2);
|
|
10190
|
-
const s0 = lerp(r0, r1);
|
|
10191
|
-
return {
|
|
10192
|
-
left: [p0, q0, r0, s0],
|
|
10193
|
-
right: [s0, r1, q2, p3]
|
|
10194
|
-
};
|
|
10557
|
+
const [l, r] = splitCubicAt(p0.x, p0.y, p1.x, p1.y, p2.x, p2.y, p3.x, p3.y, t);
|
|
10558
|
+
const quad = (c) => [{ x: c[0], y: c[1] }, { x: c[2], y: c[3] }, { x: c[4], y: c[5] }, { x: c[6], y: c[7] }];
|
|
10559
|
+
return { left: quad(l), right: quad(r) };
|
|
10195
10560
|
}
|
|
10196
10561
|
function fitCubicThroughDeletion(prev, next) {
|
|
10197
10562
|
const dx = next.x - prev.x;
|
|
@@ -10333,59 +10698,11 @@ function segmentEnds(anchors, closed, sub2, segIdx) {
|
|
|
10333
10698
|
function isStraightSegment(a, b) {
|
|
10334
10699
|
return a.outHandle == null && b.inHandle == null;
|
|
10335
10700
|
}
|
|
10336
|
-
var COARSE_SAMPLES = 32;
|
|
10337
|
-
var REFINE_STEPS = 48;
|
|
10338
|
-
var GOLDEN = (Math.sqrt(5) - 1) / 2;
|
|
10339
10701
|
function nearestOnSegment(a, b, x, y) {
|
|
10340
|
-
if (isStraightSegment(a, b)) {
|
|
10341
|
-
const dx = b.x - a.x;
|
|
10342
|
-
const dy = b.y - a.y;
|
|
10343
|
-
const len2 = dx * dx + dy * dy;
|
|
10344
|
-
const t2 = len2 === 0 ? 0 : Math.min(1, Math.max(0, ((x - a.x) * dx + (y - a.y) * dy) / len2));
|
|
10345
|
-
const ex = a.x + dx * t2 - x;
|
|
10346
|
-
const ey = a.y + dy * t2 - y;
|
|
10347
|
-
return { t: t2, d2: ex * ex + ey * ey };
|
|
10348
|
-
}
|
|
10349
10702
|
const p1 = a.outHandle ?? a;
|
|
10350
10703
|
const p2 = b.inHandle ?? b;
|
|
10351
|
-
const
|
|
10352
|
-
|
|
10353
|
-
return (q.x - x) ** 2 + (q.y - y) ** 2;
|
|
10354
|
-
};
|
|
10355
|
-
let bestT = 0;
|
|
10356
|
-
let bestD2 = Infinity;
|
|
10357
|
-
for (let k = 0; k <= COARSE_SAMPLES; k++) {
|
|
10358
|
-
const t2 = k / COARSE_SAMPLES;
|
|
10359
|
-
const d22 = d2At(t2);
|
|
10360
|
-
if (d22 < bestD2) {
|
|
10361
|
-
bestD2 = d22;
|
|
10362
|
-
bestT = t2;
|
|
10363
|
-
}
|
|
10364
|
-
}
|
|
10365
|
-
let lo = Math.max(0, bestT - 1 / COARSE_SAMPLES);
|
|
10366
|
-
let hi = Math.min(1, bestT + 1 / COARSE_SAMPLES);
|
|
10367
|
-
let m1 = hi - GOLDEN * (hi - lo);
|
|
10368
|
-
let m2 = lo + GOLDEN * (hi - lo);
|
|
10369
|
-
let f1 = d2At(m1);
|
|
10370
|
-
let f2 = d2At(m2);
|
|
10371
|
-
for (let i = 0; i < REFINE_STEPS; i++) {
|
|
10372
|
-
if (f1 < f2) {
|
|
10373
|
-
hi = m2;
|
|
10374
|
-
m2 = m1;
|
|
10375
|
-
f2 = f1;
|
|
10376
|
-
m1 = hi - GOLDEN * (hi - lo);
|
|
10377
|
-
f1 = d2At(m1);
|
|
10378
|
-
} else {
|
|
10379
|
-
lo = m1;
|
|
10380
|
-
m1 = m2;
|
|
10381
|
-
f1 = f2;
|
|
10382
|
-
m2 = lo + GOLDEN * (hi - lo);
|
|
10383
|
-
f2 = d2At(m2);
|
|
10384
|
-
}
|
|
10385
|
-
}
|
|
10386
|
-
const t = (lo + hi) / 2;
|
|
10387
|
-
const d2 = d2At(t);
|
|
10388
|
-
return d2 < bestD2 ? { t, d2 } : { t: bestT, d2: bestD2 };
|
|
10704
|
+
const hit = isStraightSegment(a, b) ? nearestOnLine(x, y, a.x, a.y, b.x, b.y) : nearestOnCubic(x, y, a.x, a.y, p1.x, p1.y, p2.x, p2.y, b.x, b.y);
|
|
10705
|
+
return { t: hit.t, d2: hit.dist * hit.dist };
|
|
10389
10706
|
}
|
|
10390
10707
|
function nearestSegmentT(anchors, wx, wy, closed) {
|
|
10391
10708
|
let bestD2 = Infinity;
|
|
@@ -10738,6 +11055,48 @@ var editAnchorsAction = {
|
|
|
10738
11055
|
},
|
|
10739
11056
|
enabled: () => true
|
|
10740
11057
|
};
|
|
11058
|
+
var LASSO_VERTICES = scratchKey("lassoSelect.vertices");
|
|
11059
|
+
var MIN_AREA = 4;
|
|
11060
|
+
function selectFromLasso(opts) {
|
|
11061
|
+
const mode = opts?.mode ?? "intersect";
|
|
11062
|
+
return {
|
|
11063
|
+
defaultTransient: true,
|
|
11064
|
+
onEnd(ctx) {
|
|
11065
|
+
const adapter = ctx.adapter;
|
|
11066
|
+
if (!adapter.getSelection || !adapter.hitTestLasso) return null;
|
|
11067
|
+
const vertices = getScratch(ctx.scratch, LASSO_VERTICES) ?? [];
|
|
11068
|
+
const startPose = ctx.origin.get("gesture");
|
|
11069
|
+
const shiftHeld = startPose ? startPose.shiftHeld === true : false;
|
|
11070
|
+
const from = adapter.getSelection();
|
|
11071
|
+
const tiny = vertices.length < 3 || polygonAabbArea(vertices) < MIN_AREA;
|
|
11072
|
+
if (tiny) {
|
|
11073
|
+
const to2 = shiftHeld ? from : [];
|
|
11074
|
+
const op2 = createSetSelectionOp({ from, to: to2 });
|
|
11075
|
+
return [op2];
|
|
11076
|
+
}
|
|
11077
|
+
const hits = adapter.hitTestLasso(vertices, mode);
|
|
11078
|
+
const to = shiftHeld ? mergeUnique(from, hits) : hits;
|
|
11079
|
+
const op = createSetSelectionOp({ from, to });
|
|
11080
|
+
return [op];
|
|
11081
|
+
}
|
|
11082
|
+
};
|
|
11083
|
+
}
|
|
11084
|
+
function polygonAabbArea(vertices) {
|
|
11085
|
+
if (vertices.length === 0) return 0;
|
|
11086
|
+
let minX = Infinity, minY = Infinity, maxX = -Infinity, maxY = -Infinity;
|
|
11087
|
+
for (const v of vertices) {
|
|
11088
|
+
if (v.x < minX) minX = v.x;
|
|
11089
|
+
if (v.y < minY) minY = v.y;
|
|
11090
|
+
if (v.x > maxX) maxX = v.x;
|
|
11091
|
+
if (v.y > maxY) maxY = v.y;
|
|
11092
|
+
}
|
|
11093
|
+
return (maxX - minX) * (maxY - minY);
|
|
11094
|
+
}
|
|
11095
|
+
function mergeUnique(a, b) {
|
|
11096
|
+
const out = [...a];
|
|
11097
|
+
for (const id of b) if (!out.includes(id)) out.push(id);
|
|
11098
|
+
return out;
|
|
11099
|
+
}
|
|
10741
11100
|
|
|
10742
11101
|
// src/interactions/actions/defaults/lassoSelect.ts
|
|
10743
11102
|
function polygonAABB(pts) {
|
|
@@ -10751,26 +11110,68 @@ function polygonAABB(pts) {
|
|
|
10751
11110
|
}
|
|
10752
11111
|
return { x: minX, y: minY, width: maxX - minX, height: maxY - minY };
|
|
10753
11112
|
}
|
|
10754
|
-
|
|
11113
|
+
function hitTestPolygon(dep, vertices, mode, view) {
|
|
11114
|
+
if (dep.hitTestLasso) return dep.hitTestLasso(vertices, mode, view);
|
|
11115
|
+
const aabb = polygonAABB(vertices);
|
|
11116
|
+
return aabb ? dep.hitTestArea(aabb, view) : [];
|
|
11117
|
+
}
|
|
11118
|
+
function behaviorAdapter(dep, view) {
|
|
11119
|
+
const adapter = {
|
|
11120
|
+
getSelection: () => dep.getSelection(),
|
|
11121
|
+
setSelection: (ids) => dep.setSelection(ids),
|
|
11122
|
+
hitTestArea: (rect) => dep.hitTestArea(rect, view),
|
|
11123
|
+
hitTestLasso: (polygon, mode) => hitTestPolygon(dep, polygon, mode, view),
|
|
11124
|
+
applyOps: (ops) => applyOpsTo(adapter, ops)
|
|
11125
|
+
};
|
|
11126
|
+
return adapter;
|
|
11127
|
+
}
|
|
11128
|
+
var DEFAULT_MIN_VERTEX_SPACING = 2;
|
|
10755
11129
|
var lassoSelectAction = {
|
|
10756
11130
|
id: "lassoSelect",
|
|
10757
11131
|
label: "Lasso Select",
|
|
10758
|
-
defaultBinding: { kind: "drag", mods: { shift: "optional" } },
|
|
10759
11132
|
eligible: { capability: "creates-selection" },
|
|
10760
11133
|
requires: ["lassoSelect", "view"],
|
|
10761
11134
|
invoker: {
|
|
10762
11135
|
timing: "ongoing",
|
|
10763
|
-
start(ctx,
|
|
11136
|
+
start(ctx, opts) {
|
|
10764
11137
|
const dep = ctx.deps.lassoSelect;
|
|
10765
11138
|
if (!dep) return {};
|
|
11139
|
+
const params = resolveParams(opts?.params);
|
|
11140
|
+
const view = ctx.deps.view;
|
|
11141
|
+
const vertices = [{ x: ctx.world.x, y: ctx.world.y }];
|
|
11142
|
+
const behaviors = opts?.behaviors ?? [];
|
|
11143
|
+
let gesture = null;
|
|
11144
|
+
if (behaviors.length > 0) {
|
|
11145
|
+
const pose = {
|
|
11146
|
+
worldX: ctx.world.x,
|
|
11147
|
+
worldY: ctx.world.y,
|
|
11148
|
+
shiftHeld: ctx.modifiers.shift
|
|
11149
|
+
};
|
|
11150
|
+
gesture = {
|
|
11151
|
+
draggedIds: ["gesture"],
|
|
11152
|
+
origin: /* @__PURE__ */ new Map([["gesture", pose]]),
|
|
11153
|
+
current: /* @__PURE__ */ new Map([["gesture", { ...pose }]]),
|
|
11154
|
+
snap: null,
|
|
11155
|
+
modifiers: { ...ctx.modifiers },
|
|
11156
|
+
pointer: { worldX: ctx.world.x, worldY: ctx.world.y, clientX: 0, clientY: 0 },
|
|
11157
|
+
adapter: behaviorAdapter(dep, view),
|
|
11158
|
+
scratch: {}
|
|
11159
|
+
};
|
|
11160
|
+
setScratch(gesture.scratch, LASSO_VERTICES, vertices);
|
|
11161
|
+
for (const b of behaviors) b.onStart?.(gesture);
|
|
11162
|
+
}
|
|
10766
11163
|
const scratch = {
|
|
10767
11164
|
dep,
|
|
10768
|
-
|
|
10769
|
-
|
|
11165
|
+
mode: params?.mode ?? "intersect",
|
|
11166
|
+
minVertexSpacing: params?.minVertexSpacing ?? DEFAULT_MIN_VERTEX_SPACING,
|
|
11167
|
+
view,
|
|
11168
|
+
vertices,
|
|
10770
11169
|
shiftHeld: ctx.modifiers.shift,
|
|
10771
11170
|
currentX: ctx.world.x,
|
|
10772
11171
|
currentY: ctx.world.y,
|
|
10773
|
-
open: true
|
|
11172
|
+
open: true,
|
|
11173
|
+
behaviors,
|
|
11174
|
+
gesture
|
|
10774
11175
|
};
|
|
10775
11176
|
return {
|
|
10776
11177
|
kind: "lasso",
|
|
@@ -10781,9 +11182,18 @@ var lassoSelectAction = {
|
|
|
10781
11182
|
const last = scratch.vertices[scratch.vertices.length - 1];
|
|
10782
11183
|
const dx = x - last.x;
|
|
10783
11184
|
const dy = y - last.y;
|
|
10784
|
-
|
|
11185
|
+
const min = scratch.minVertexSpacing;
|
|
11186
|
+
if (dx * dx + dy * dy >= min * min) {
|
|
10785
11187
|
scratch.vertices.push({ x, y });
|
|
10786
11188
|
}
|
|
11189
|
+
const g = scratch.gesture;
|
|
11190
|
+
if (g) {
|
|
11191
|
+
g.modifiers = { ...moveCtx.modifiers };
|
|
11192
|
+
g.pointer = { worldX: x, worldY: y, clientX: 0, clientY: 0 };
|
|
11193
|
+
g.current.set("gesture", { worldX: x, worldY: y, shiftHeld: scratch.shiftHeld });
|
|
11194
|
+
const proposed = { vertices: scratch.vertices, shiftHeld: scratch.shiftHeld };
|
|
11195
|
+
for (const b of scratch.behaviors) b.onMove?.(g, proposed);
|
|
11196
|
+
}
|
|
10787
11197
|
},
|
|
10788
11198
|
overlay() {
|
|
10789
11199
|
if (!scratch.open) return null;
|
|
@@ -10797,18 +11207,20 @@ var lassoSelectAction = {
|
|
|
10797
11207
|
onEnd(_endCtx, reason) {
|
|
10798
11208
|
scratch.open = false;
|
|
10799
11209
|
if (reason === "cancel") return;
|
|
10800
|
-
const { dep: d, view, vertices, shiftHeld } = scratch;
|
|
10801
|
-
if (
|
|
11210
|
+
const { dep: d, mode, view: view2, vertices: vertices2, shiftHeld, gesture: g } = scratch;
|
|
11211
|
+
if (g) {
|
|
11212
|
+
for (const b of scratch.behaviors) {
|
|
11213
|
+
const r = b.onEnd?.(g);
|
|
11214
|
+
if (r === void 0) continue;
|
|
11215
|
+
if (r !== null) g.adapter.applyOps(r);
|
|
11216
|
+
return;
|
|
11217
|
+
}
|
|
11218
|
+
}
|
|
11219
|
+
if (vertices2.length < 3) {
|
|
10802
11220
|
if (!shiftHeld) d.setSelection([]);
|
|
10803
11221
|
return;
|
|
10804
11222
|
}
|
|
10805
|
-
|
|
10806
|
-
if (d.hitTestLasso) {
|
|
10807
|
-
hits = d.hitTestLasso(vertices, "centers", view);
|
|
10808
|
-
} else {
|
|
10809
|
-
const aabb = polygonAABB(vertices);
|
|
10810
|
-
hits = aabb ? d.hitTestArea(aabb, view) : [];
|
|
10811
|
-
}
|
|
11223
|
+
const hits = hitTestPolygon(d, vertices2, mode, view2);
|
|
10812
11224
|
if (shiftHeld) {
|
|
10813
11225
|
const current = d.getSelection();
|
|
10814
11226
|
const merged = [...current];
|
|
@@ -10829,7 +11241,6 @@ var sliceAction = {
|
|
|
10829
11241
|
id: "slice",
|
|
10830
11242
|
label: "Slice",
|
|
10831
11243
|
group: "edit",
|
|
10832
|
-
defaultBinding: { kind: "drag" },
|
|
10833
11244
|
eligible: { capability: "edits-page" },
|
|
10834
11245
|
requires: ["slice"],
|
|
10835
11246
|
invoker: {
|
|
@@ -11225,9 +11636,13 @@ var escapeAction = {
|
|
|
11225
11636
|
// `exitPathEdit`'s bare key spec, swallowing the Escape that should leave
|
|
11226
11637
|
// edit mode. With this gate, `escape` reports a disabled reason in that
|
|
11227
11638
|
// case and the dispatcher falls through to `exitPathEdit`.
|
|
11639
|
+
// With nothing selected there is nothing to clear, so the press falls
|
|
11640
|
+
// through to `tool.resetToDefault` instead of being spent here.
|
|
11228
11641
|
enabled: (deps) => {
|
|
11229
11642
|
const editAnchors = deps?.editAnchors;
|
|
11230
11643
|
if (editAnchors?.editingId) return ActionDisabledReason.NotApplicable;
|
|
11644
|
+
const sel = deps?.selection?.get() ?? [];
|
|
11645
|
+
if (sel.length === 0) return ActionDisabledReason.NotApplicable;
|
|
11231
11646
|
return true;
|
|
11232
11647
|
}
|
|
11233
11648
|
};
|
|
@@ -13666,12 +14081,27 @@ function useResizePolicy(options) {
|
|
|
13666
14081
|
useDepSource("resizePolicy", () => {
|
|
13667
14082
|
const o = optsRef.current;
|
|
13668
14083
|
return {
|
|
14084
|
+
label: o.label,
|
|
14085
|
+
transient: o.transient,
|
|
14086
|
+
onGestureStart: o.onGestureStart,
|
|
14087
|
+
onGestureEnd: o.onGestureEnd,
|
|
13669
14088
|
constraints: o.constraints ?? DEFAULT_RESIZE_BEHAVIORS,
|
|
13670
14089
|
pointSnap: o.pointSnap ?? EMPTY2,
|
|
13671
14090
|
expandIds: o.expandIds ?? IDENTITY_EXPAND2
|
|
13672
14091
|
};
|
|
13673
14092
|
});
|
|
13674
14093
|
}
|
|
14094
|
+
function resizePolicyOptions(o) {
|
|
14095
|
+
return {
|
|
14096
|
+
constraints: o.behaviors,
|
|
14097
|
+
pointSnap: o.pointSnapBehaviors,
|
|
14098
|
+
expandIds: o.expandIds,
|
|
14099
|
+
label: o.resizeLabel,
|
|
14100
|
+
transient: o.transient,
|
|
14101
|
+
onGestureStart: o.onGestureStart,
|
|
14102
|
+
onGestureEnd: o.onGestureEnd
|
|
14103
|
+
};
|
|
14104
|
+
}
|
|
13675
14105
|
function usePoseDescriptorDepSource(descriptor) {
|
|
13676
14106
|
const ref = useRef(descriptor);
|
|
13677
14107
|
ref.current = descriptor;
|
|
@@ -13816,63 +14246,6 @@ function useDecayLoop() {
|
|
|
13816
14246
|
}, [cancel]);
|
|
13817
14247
|
return { start, cancel };
|
|
13818
14248
|
}
|
|
13819
|
-
function dist(a, b) {
|
|
13820
|
-
return Math.hypot(b.x - a.x, b.y - a.y);
|
|
13821
|
-
}
|
|
13822
|
-
function mid(a, b) {
|
|
13823
|
-
return { x: (a.x + b.x) / 2, y: (a.y + b.y) / 2 };
|
|
13824
|
-
}
|
|
13825
|
-
function usePinchGesture(canvasRef, onPinch, enabled = true) {
|
|
13826
|
-
const onPinchRef = useRef(onPinch);
|
|
13827
|
-
onPinchRef.current = onPinch;
|
|
13828
|
-
useEffect(() => {
|
|
13829
|
-
if (!enabled) return;
|
|
13830
|
-
const el = canvasRef.current;
|
|
13831
|
-
if (!el) return;
|
|
13832
|
-
const pointers = /* @__PURE__ */ new Map();
|
|
13833
|
-
let startDist = null;
|
|
13834
|
-
function getTwo() {
|
|
13835
|
-
const vals = [...pointers.values()];
|
|
13836
|
-
if (vals.length < 2) return null;
|
|
13837
|
-
return [vals[0], vals[1]];
|
|
13838
|
-
}
|
|
13839
|
-
function onDown(e) {
|
|
13840
|
-
pointers.set(e.pointerId, { x: e.clientX, y: e.clientY });
|
|
13841
|
-
const two = getTwo();
|
|
13842
|
-
if (two) startDist = dist(two[0], two[1]);
|
|
13843
|
-
}
|
|
13844
|
-
function onMove(e) {
|
|
13845
|
-
if (!pointers.has(e.pointerId)) return;
|
|
13846
|
-
pointers.set(e.pointerId, { x: e.clientX, y: e.clientY });
|
|
13847
|
-
const two = getTwo();
|
|
13848
|
-
if (!two || startDist === null) return;
|
|
13849
|
-
const currentDist = dist(two[0], two[1]);
|
|
13850
|
-
const anchor = mid(two[0], two[1]);
|
|
13851
|
-
const factor = currentDist / startDist;
|
|
13852
|
-
startDist = currentDist;
|
|
13853
|
-
onPinchRef.current(anchor, factor);
|
|
13854
|
-
}
|
|
13855
|
-
function onUp(e) {
|
|
13856
|
-
pointers.delete(e.pointerId);
|
|
13857
|
-
if (pointers.size < 2) {
|
|
13858
|
-
startDist = null;
|
|
13859
|
-
} else {
|
|
13860
|
-
const two = getTwo();
|
|
13861
|
-
if (two) startDist = dist(two[0], two[1]);
|
|
13862
|
-
}
|
|
13863
|
-
}
|
|
13864
|
-
el.addEventListener("pointerdown", onDown);
|
|
13865
|
-
el.addEventListener("pointermove", onMove);
|
|
13866
|
-
el.addEventListener("pointerup", onUp);
|
|
13867
|
-
el.addEventListener("pointercancel", onUp);
|
|
13868
|
-
return () => {
|
|
13869
|
-
el.removeEventListener("pointerdown", onDown);
|
|
13870
|
-
el.removeEventListener("pointermove", onMove);
|
|
13871
|
-
el.removeEventListener("pointerup", onUp);
|
|
13872
|
-
el.removeEventListener("pointercancel", onUp);
|
|
13873
|
-
};
|
|
13874
|
-
}, [canvasRef, enabled]);
|
|
13875
|
-
}
|
|
13876
14249
|
|
|
13877
14250
|
// src/core/viewport/interpolateView.ts
|
|
13878
14251
|
function axisCurve(x0, s0, x1, s1) {
|
|
@@ -14396,9 +14769,9 @@ function firstAfter(events, t) {
|
|
|
14396
14769
|
let lo = 0;
|
|
14397
14770
|
let hi = events.length;
|
|
14398
14771
|
while (lo < hi) {
|
|
14399
|
-
const
|
|
14400
|
-
if (events[
|
|
14401
|
-
else lo =
|
|
14772
|
+
const mid = lo + hi >> 1;
|
|
14773
|
+
if (events[mid].t > t) hi = mid;
|
|
14774
|
+
else lo = mid + 1;
|
|
14402
14775
|
}
|
|
14403
14776
|
return lo;
|
|
14404
14777
|
}
|
|
@@ -14526,12 +14899,12 @@ function floorKeyIndex(keys, t) {
|
|
|
14526
14899
|
let hi = keys.length - 1;
|
|
14527
14900
|
let found = -1;
|
|
14528
14901
|
while (lo <= hi) {
|
|
14529
|
-
const
|
|
14530
|
-
if (keys[
|
|
14531
|
-
found =
|
|
14532
|
-
lo =
|
|
14902
|
+
const mid = lo + hi >> 1;
|
|
14903
|
+
if (keys[mid].t <= t) {
|
|
14904
|
+
found = mid;
|
|
14905
|
+
lo = mid + 1;
|
|
14533
14906
|
} else {
|
|
14534
|
-
hi =
|
|
14907
|
+
hi = mid - 1;
|
|
14535
14908
|
}
|
|
14536
14909
|
}
|
|
14537
14910
|
return found;
|
|
@@ -15267,12 +15640,6 @@ function useViewAnimationOn(view, animator) {
|
|
|
15267
15640
|
};
|
|
15268
15641
|
}, [key]);
|
|
15269
15642
|
}
|
|
15270
|
-
function defineTool(def) {
|
|
15271
|
-
return defineTool$1(def);
|
|
15272
|
-
}
|
|
15273
|
-
function defineViewportTool(def) {
|
|
15274
|
-
return defineViewportTool$1(def);
|
|
15275
|
-
}
|
|
15276
15643
|
var useTools = useTools$1;
|
|
15277
15644
|
|
|
15278
15645
|
// src/interactions/actions/defaults/toolActivate.ts
|
|
@@ -15359,6 +15726,7 @@ function useKeybindings(tools, options = {}) {
|
|
|
15359
15726
|
useEffect(() => {
|
|
15360
15727
|
if (optionsRef.current.disable) return;
|
|
15361
15728
|
if (!registry2) return;
|
|
15729
|
+
if (Object.keys(toolsRef.current.registry).length === 0) return;
|
|
15362
15730
|
const specs = [];
|
|
15363
15731
|
for (const [toolId, keyOpts] of Object.entries(BUILTIN_SELECT_KEYS)) {
|
|
15364
15732
|
if (toolsRef.current.has(toolId)) {
|
|
@@ -15398,8 +15766,6 @@ function useKeybindings(tools, options = {}) {
|
|
|
15398
15766
|
};
|
|
15399
15767
|
}, [registry2, tools]);
|
|
15400
15768
|
}
|
|
15401
|
-
|
|
15402
|
-
// src/tools/prefs.ts
|
|
15403
15769
|
function prefUnit(system, display, opts) {
|
|
15404
15770
|
let self;
|
|
15405
15771
|
try {
|
|
@@ -15726,13 +16092,19 @@ function UnknownIcon({ className, size = 20 }) {
|
|
|
15726
16092
|
}
|
|
15727
16093
|
);
|
|
15728
16094
|
}
|
|
15729
|
-
function closedSubpaths(path, tolerance) {
|
|
16095
|
+
function closedSubpaths(path, tolerance, keepOpen = false) {
|
|
16096
|
+
const { closed, open } = flatSubpaths(path, tolerance);
|
|
16097
|
+
return keepOpen ? [...closed, ...open] : closed;
|
|
16098
|
+
}
|
|
16099
|
+
function flatSubpaths(path, tolerance) {
|
|
15730
16100
|
const { commands, coords } = path;
|
|
15731
|
-
const
|
|
16101
|
+
const closed = [];
|
|
16102
|
+
const open = [];
|
|
15732
16103
|
let sub2 = [];
|
|
15733
16104
|
forEachSegment(commands, coords, (cmd, ci, curX, curY) => {
|
|
15734
16105
|
switch (cmd) {
|
|
15735
16106
|
case PATH_M:
|
|
16107
|
+
if (sub2.length >= 2) open.push(sub2);
|
|
15736
16108
|
sub2 = [coords[ci], coords[ci + 1]];
|
|
15737
16109
|
break;
|
|
15738
16110
|
case PATH_L:
|
|
@@ -15765,14 +16137,16 @@ function closedSubpaths(path, tolerance) {
|
|
|
15765
16137
|
);
|
|
15766
16138
|
break;
|
|
15767
16139
|
case PATH_Z:
|
|
15768
|
-
if (sub2.length >= 6)
|
|
16140
|
+
if (sub2.length >= 6) closed.push(sub2);
|
|
16141
|
+
else if (sub2.length >= 2) open.push(sub2);
|
|
15769
16142
|
sub2 = [];
|
|
15770
16143
|
break;
|
|
15771
16144
|
default:
|
|
15772
16145
|
throw new Error(`pathHitTest: unknown command ${cmd}`);
|
|
15773
16146
|
}
|
|
15774
16147
|
});
|
|
15775
|
-
|
|
16148
|
+
if (sub2.length >= 2) open.push(sub2);
|
|
16149
|
+
return { closed, open };
|
|
15776
16150
|
}
|
|
15777
16151
|
function rectToVerts(r) {
|
|
15778
16152
|
return [
|
|
@@ -15830,6 +16204,18 @@ function anyEdgeCrossesPolygon(subpaths, poly2) {
|
|
|
15830
16204
|
return false;
|
|
15831
16205
|
});
|
|
15832
16206
|
}
|
|
16207
|
+
function anyOpenEdgeCrossesPolygon(runs, poly2) {
|
|
16208
|
+
for (const run2 of runs) {
|
|
16209
|
+
for (let i = 0; i + 3 < run2.length; i += 2) {
|
|
16210
|
+
const ax = run2[i], ay = run2[i + 1], bx = run2[i + 2], by = run2[i + 3];
|
|
16211
|
+
for (let k = 0; k < poly2.length; k++) {
|
|
16212
|
+
const p0 = poly2[k], p1 = poly2[(k + 1) % poly2.length];
|
|
16213
|
+
if (segmentsCross(ax, ay, bx, by, p0.x, p0.y, p1.x, p1.y)) return true;
|
|
16214
|
+
}
|
|
16215
|
+
}
|
|
16216
|
+
}
|
|
16217
|
+
return false;
|
|
16218
|
+
}
|
|
15833
16219
|
function anyVertexInRect(subpaths, r) {
|
|
15834
16220
|
for (const sub2 of subpaths) {
|
|
15835
16221
|
for (let i = 0; i < sub2.length; i += 2) {
|
|
@@ -15903,128 +16289,34 @@ function pathIntersectsPolygon(path, polygon, opts = {}) {
|
|
|
15903
16289
|
if (anyVertexInPolygon(subpaths, flattenVerts(polygon))) return true;
|
|
15904
16290
|
return anyEdgeCrossesPolygon(subpaths, polygon);
|
|
15905
16291
|
}
|
|
15906
|
-
|
|
15907
|
-
|
|
15908
|
-
|
|
15909
|
-
|
|
15910
|
-
const
|
|
15911
|
-
const
|
|
15912
|
-
|
|
15913
|
-
|
|
15914
|
-
|
|
15915
|
-
}
|
|
15916
|
-
|
|
15917
|
-
for (let k = i + 1; k < n; k++) if (dir(pl, i, k)) return k;
|
|
15918
|
-
return -1;
|
|
16292
|
+
function polygonContainsPath(polygon, path, opts = {}) {
|
|
16293
|
+
if (polygon.length < 3) return false;
|
|
16294
|
+
const subpaths = path.kind === "rect" ? [flattenVerts(rectToVerts(path))] : closedSubpaths(path, opts.tolerance ?? DEFAULT_FLATTEN_TOLERANCE, true);
|
|
16295
|
+
if (subpaths.length === 0) return false;
|
|
16296
|
+
const flatPoly = flattenVerts(polygon);
|
|
16297
|
+
for (const sub2 of subpaths) {
|
|
16298
|
+
for (let i = 0; i < sub2.length; i += 2) {
|
|
16299
|
+
if (!pointInPolygon(flatPoly, sub2[i], sub2[i + 1])) return false;
|
|
16300
|
+
}
|
|
16301
|
+
}
|
|
16302
|
+
return !anyEdgeCrossesPolygon(subpaths, polygon);
|
|
15919
16303
|
}
|
|
15920
|
-
function
|
|
15921
|
-
|
|
15922
|
-
return
|
|
16304
|
+
function polygonIntersectsPath(polygon, path, opts = {}) {
|
|
16305
|
+
if (polygon.length < 3) return false;
|
|
16306
|
+
if (path.kind === "rect") return polygonsIntersect(rectToVerts(path), polygon);
|
|
16307
|
+
const { closed, open } = flatSubpaths(path, opts.tolerance ?? DEFAULT_FLATTEN_TOLERANCE);
|
|
16308
|
+
const flatPoly = flattenVerts(polygon);
|
|
16309
|
+
if (anyVertexInPolygon(closed, flatPoly) || anyVertexInPolygon(open, flatPoly)) return true;
|
|
16310
|
+
if (anyEdgeCrossesPolygon(closed, polygon) || anyOpenEdgeCrossesPolygon(open, polygon)) {
|
|
16311
|
+
return true;
|
|
16312
|
+
}
|
|
16313
|
+
return closed.length > 0 && pointInPath(path, polygon[0].x, polygon[0].y, opts);
|
|
15923
16314
|
}
|
|
15924
|
-
|
|
15925
|
-
|
|
15926
|
-
|
|
15927
|
-
if (
|
|
15928
|
-
|
|
15929
|
-
const j = nextDistinct(pl, 0, n);
|
|
15930
|
-
const d = j >= 0 ? dir(pl, 0, j) : null;
|
|
15931
|
-
if (d) {
|
|
15932
|
-
out.push({ x: pl.points[0], y: pl.points[1], angle: Math.atan2(-d.y, -d.x), role: "start" });
|
|
15933
|
-
}
|
|
15934
|
-
}
|
|
15935
|
-
if (want.mid) {
|
|
15936
|
-
const A = pl.anchorA, B = pl.anchorB, T = pl.anchorT;
|
|
15937
|
-
if (A && B && T) {
|
|
15938
|
-
for (let i = 1; i < n - 1; i++) {
|
|
15939
|
-
if (A[i] !== B[i] || T[i] !== 0) continue;
|
|
15940
|
-
const p = prevDistinct(pl, i);
|
|
15941
|
-
const q = nextDistinct(pl, i, n);
|
|
15942
|
-
if (p < 0 || q < 0) continue;
|
|
15943
|
-
const inDir = dir(pl, p, i);
|
|
15944
|
-
const outDir = dir(pl, i, q);
|
|
15945
|
-
let bx = inDir.x + outDir.x;
|
|
15946
|
-
let by = inDir.y + outDir.y;
|
|
15947
|
-
if (Math.hypot(bx, by) < EPS2) {
|
|
15948
|
-
bx = inDir.x;
|
|
15949
|
-
by = inDir.y;
|
|
15950
|
-
}
|
|
15951
|
-
out.push({ x: pl.points[i * 2], y: pl.points[i * 2 + 1], angle: Math.atan2(by, bx), role: "mid" });
|
|
15952
|
-
}
|
|
15953
|
-
}
|
|
15954
|
-
}
|
|
15955
|
-
if (want.end && !pl.closed) {
|
|
15956
|
-
const last = n - 1;
|
|
15957
|
-
const p = prevDistinct(pl, last);
|
|
15958
|
-
const d = p >= 0 ? dir(pl, p, last) : null;
|
|
15959
|
-
if (d) {
|
|
15960
|
-
out.push({ x: pl.points[last * 2], y: pl.points[last * 2 + 1], angle: Math.atan2(d.y, d.x), role: "end" });
|
|
15961
|
-
}
|
|
15962
|
-
}
|
|
15963
|
-
return out;
|
|
15964
|
-
}
|
|
15965
|
-
|
|
15966
|
-
// src/features/paths/markerCommands.ts
|
|
15967
|
-
function placed(path, site) {
|
|
15968
|
-
const src = path;
|
|
15969
|
-
const cos = Math.cos(site.angle);
|
|
15970
|
-
const sin = Math.sin(site.angle);
|
|
15971
|
-
const coords = new Float32Array(src.coords.length);
|
|
15972
|
-
for (let i = 0; i < src.coords.length; i += 2) {
|
|
15973
|
-
const x = src.coords[i], y = src.coords[i + 1];
|
|
15974
|
-
coords[i] = site.x + x * cos - y * sin;
|
|
15975
|
-
coords[i + 1] = site.y + x * sin + y * cos;
|
|
15976
|
-
}
|
|
15977
|
-
return { kind: "polygon", commands: src.commands, coords, fillRule: src.fillRule };
|
|
15978
|
-
}
|
|
15979
|
-
function resolvePaint(p, stroke, fallback) {
|
|
15980
|
-
const v = p ?? fallback;
|
|
15981
|
-
if (v === "none") return void 0;
|
|
15982
|
-
return v === "line" ? stroke.paint : v;
|
|
15983
|
-
}
|
|
15984
|
-
function commandFor(entry, ref, stroke, strokeWidth, site) {
|
|
15985
|
-
const size = resolveMarkerSize(ref, strokeWidth);
|
|
15986
|
-
const geometry = entry.path({ size, stroke });
|
|
15987
|
-
const angle = entry.orient === void 0 || entry.orient === "auto" ? site.angle : entry.orient;
|
|
15988
|
-
const path = placed(geometry, { ...site, angle });
|
|
15989
|
-
const fill = resolvePaint(entry.fill, stroke, "line");
|
|
15990
|
-
const outline = entry.outline ? {
|
|
15991
|
-
paint: resolvePaint(entry.outline.paint, stroke, "line"),
|
|
15992
|
-
width: entry.outline.width * size
|
|
15993
|
-
} : null;
|
|
15994
|
-
if (fill === void 0 && (outline === null || outline.paint === void 0)) return null;
|
|
15995
|
-
return {
|
|
15996
|
-
kind: "path",
|
|
15997
|
-
path,
|
|
15998
|
-
...fill ? { fill } : {},
|
|
15999
|
-
...outline && outline.paint ? { stroke: { paint: outline.paint, width: outline.width, cap: "round", join: "round" } } : {}
|
|
16000
|
-
};
|
|
16001
|
-
}
|
|
16002
|
-
function markerDrawCommands(path, stroke, strokeWidth, flattenTolerance) {
|
|
16003
|
-
const want = {
|
|
16004
|
-
start: stroke.markerStart !== void 0,
|
|
16005
|
-
mid: stroke.markerMid !== void 0,
|
|
16006
|
-
end: stroke.markerEnd !== void 0
|
|
16007
|
-
};
|
|
16008
|
-
if (!want.start && !want.mid && !want.end) return [];
|
|
16009
|
-
const refFor = (role) => role === "start" ? stroke.markerStart : role === "mid" ? stroke.markerMid : stroke.markerEnd;
|
|
16010
|
-
const out = [];
|
|
16011
|
-
for (const pl of extractPolylines(path, { flattenTolerance })) {
|
|
16012
|
-
for (const site of markerSites(pl, want)) {
|
|
16013
|
-
const ref = refFor(site.role);
|
|
16014
|
-
if (ref === void 0) continue;
|
|
16015
|
-
const entry = getMarker(markerKeyOf(ref));
|
|
16016
|
-
if (entry === void 0) continue;
|
|
16017
|
-
const cmd = commandFor(entry, ref, stroke, strokeWidth, site);
|
|
16018
|
-
if (cmd) out.push(cmd);
|
|
16019
|
-
}
|
|
16020
|
-
}
|
|
16021
|
-
return out;
|
|
16022
|
-
}
|
|
16023
|
-
|
|
16024
|
-
// src/core/fillInPoseFrame.ts
|
|
16025
|
-
function fillInPoseFrame(fill, box) {
|
|
16026
|
-
if (!isBuiltinKind(fill)) {
|
|
16027
|
-
return getPaintKind(fill.fill)?.inPoseFrame?.(fill, box) ?? fill;
|
|
16315
|
+
|
|
16316
|
+
// src/core/fillInPoseFrame.ts
|
|
16317
|
+
function fillInPoseFrame(fill, box) {
|
|
16318
|
+
if (!isBuiltinKind(fill)) {
|
|
16319
|
+
return getPaintKind(fill.fill)?.inPoseFrame?.(fill, box) ?? fill;
|
|
16028
16320
|
}
|
|
16029
16321
|
if (isBoundsPattern(fill)) {
|
|
16030
16322
|
const o = fill.origin ?? { x: 0, y: 0 };
|
|
@@ -16434,11 +16726,7 @@ function strokeInPoseFrame(stroke, box) {
|
|
|
16434
16726
|
function inkReach(stroke, scale) {
|
|
16435
16727
|
if (stroke === null) return { outset: 0, inset: 0 };
|
|
16436
16728
|
const w = resolveStrokeWidth(stroke.width ?? 1, scale ?? 1);
|
|
16437
|
-
const reach =
|
|
16438
|
-
markerInset(stroke.markerStart, w),
|
|
16439
|
-
markerInset(stroke.markerEnd, w),
|
|
16440
|
-
markerInset(stroke.markerMid, w)
|
|
16441
|
-
);
|
|
16729
|
+
const reach = markerReach(stroke, w, scale);
|
|
16442
16730
|
switch (stroke.align ?? "center") {
|
|
16443
16731
|
case "inner":
|
|
16444
16732
|
return { outset: reach, inset: w };
|
|
@@ -16490,9 +16778,7 @@ var PATH_PAINTER = {
|
|
|
16490
16778
|
...fill && d.vertexColors ? { vertexColors: d.vertexColors } : {},
|
|
16491
16779
|
...stroke ? { stroke } : {}
|
|
16492
16780
|
};
|
|
16493
|
-
|
|
16494
|
-
const width = resolveStrokeWidth(stroke.width ?? 1, 1);
|
|
16495
|
-
return [cmd, ...markerDrawCommands(projected, stroke, width, void 0)];
|
|
16781
|
+
return [cmd];
|
|
16496
16782
|
}), ctx),
|
|
16497
16783
|
silhouette: (node, pose) => {
|
|
16498
16784
|
const d = node.data;
|
|
@@ -16657,9 +16943,7 @@ var DERIVED_PAINTER = {
|
|
|
16657
16943
|
...fill && d?.vertexColors ? { vertexColors: d.vertexColors } : {},
|
|
16658
16944
|
...stroke ? { stroke } : {}
|
|
16659
16945
|
};
|
|
16660
|
-
|
|
16661
|
-
const width = resolveStrokeWidth(stroke.width ?? 1, 1);
|
|
16662
|
-
return withAnimatedVertexColors([cmd, ...markerDrawCommands(path, stroke, width, void 0)], ctx);
|
|
16946
|
+
return withAnimatedVertexColors([cmd], ctx);
|
|
16663
16947
|
},
|
|
16664
16948
|
// The derived path *is* the silhouette, and it is already absolute — the
|
|
16665
16949
|
// pose is a placeholder, so nothing here can be recovered from it. Without
|
|
@@ -17010,6 +17294,103 @@ function zOf(getZIndex, id) {
|
|
|
17010
17294
|
const z = getZIndex(id);
|
|
17011
17295
|
return typeof z === "number" && Number.isFinite(z) ? z : -Infinity;
|
|
17012
17296
|
}
|
|
17297
|
+
var SELECTION_MOVE_ID = "selection.move";
|
|
17298
|
+
var SELECTION_TRANSFORM_ID = "selection.transform";
|
|
17299
|
+
function selectionMoveBindings(options = {}) {
|
|
17300
|
+
const moveOpts = (() => {
|
|
17301
|
+
const move = options.move ?? {};
|
|
17302
|
+
const params = gestureLifecycleParams({ ...move, label: move.moveLabel });
|
|
17303
|
+
if (options.reparentOnDrop && options.reparentOnDrop !== "off") params.reparentOnDrop = options.reparentOnDrop;
|
|
17304
|
+
if (move.dragThresholdPx !== void 0) params.dragThresholdPx = move.dragThresholdPx;
|
|
17305
|
+
if (move.expandIds) params.expandIds = move.expandIds;
|
|
17306
|
+
const withParams = Object.keys(params).length > 0 ? { params } : void 0;
|
|
17307
|
+
const behaviors = options.move?.behaviors?.length ? { behaviors: options.move.behaviors } : void 0;
|
|
17308
|
+
return withParams || behaviors ? { opts: { ...withParams, ...behaviors } } : {};
|
|
17309
|
+
})();
|
|
17310
|
+
return [
|
|
17311
|
+
// Alt-drag on a body → clone (Illustrator convention).
|
|
17312
|
+
// Listed BEFORE bare move so the strict-modifier dispatcher
|
|
17313
|
+
// picks this when Alt is held; bare move matches no-mod drags.
|
|
17314
|
+
// Both selected and unselected bodies are valid clone targets — the
|
|
17315
|
+
// select tool's pointerDown classifier calls `selection.applyClick(top, mods)`
|
|
17316
|
+
// on an unselected hit before the drag fires, so cloneAction's
|
|
17317
|
+
// `start` sees the hit node in `selection.get()` either way.
|
|
17318
|
+
{ spec: { kind: "drag", target: "selected-body", mods: { alt: true } }, actionId: "clone" },
|
|
17319
|
+
{ spec: { kind: "drag", target: "unselected-body", mods: { alt: true } }, actionId: "clone" },
|
|
17320
|
+
{
|
|
17321
|
+
// Body-drag → move, BUT defer when the pointerdown hit a path
|
|
17322
|
+
// anchor / control affordance. Anchors lie on the curve so the
|
|
17323
|
+
// body classifier still reports 'selected-body'; without this
|
|
17324
|
+
// opt-out, move's binding beats editAnchors's on every anchor drag.
|
|
17325
|
+
//
|
|
17326
|
+
// `isAnchorOrControl` is the SAME predicate `editAnchorsAction`
|
|
17327
|
+
// matches on. That is load-bearing: the two must agree on what
|
|
17328
|
+
// counts as an anchor hit or move steals the drag — which is
|
|
17329
|
+
// exactly the bug this opt-out exists to prevent.
|
|
17330
|
+
spec: {
|
|
17331
|
+
kind: "drag",
|
|
17332
|
+
target: {
|
|
17333
|
+
kindOf: (afford, body) => body === "selected-body" && !isAnchorOrControl(afford)
|
|
17334
|
+
}
|
|
17335
|
+
},
|
|
17336
|
+
actionId: "move",
|
|
17337
|
+
...moveOpts
|
|
17338
|
+
},
|
|
17339
|
+
// Body-drag on a NOT-yet-selected node → also move. The select tool's
|
|
17340
|
+
// pointerDown classifier selects the hit node before the drag fires (same
|
|
17341
|
+
// contract clone relies on), so by the time moveAction.start() runs the
|
|
17342
|
+
// node is in `selection.get()`. Without this binding an unselected-body
|
|
17343
|
+
// drag falls through to whatever ambient drag binding comes next — once
|
|
17344
|
+
// the `rotate` catch-all, which made the first drag rotate and later ones
|
|
17345
|
+
// move. Unselected nodes never carry anchor affordances (those gate on
|
|
17346
|
+
// selection), so the plain string-form target is sufficient here.
|
|
17347
|
+
{
|
|
17348
|
+
spec: { kind: "drag", target: "unselected-body" },
|
|
17349
|
+
actionId: "move",
|
|
17350
|
+
...moveOpts
|
|
17351
|
+
}
|
|
17352
|
+
];
|
|
17353
|
+
}
|
|
17354
|
+
function selectionTransformBindings(options = {}) {
|
|
17355
|
+
const rotate2 = options.rotate ?? {};
|
|
17356
|
+
const params = gestureLifecycleParams({ ...rotate2, label: rotate2.rotateLabel });
|
|
17357
|
+
if (rotate2.pivot) params.pivot = rotate2.pivot;
|
|
17358
|
+
const opts = {
|
|
17359
|
+
...Object.keys(params).length > 0 ? { params } : {},
|
|
17360
|
+
...rotate2.behaviors?.length ? { behaviors: rotate2.behaviors } : {}
|
|
17361
|
+
};
|
|
17362
|
+
return [
|
|
17363
|
+
{ spec: { kind: "drag", target: { kindOf: isResizeHandle } }, actionId: "resize" },
|
|
17364
|
+
{
|
|
17365
|
+
spec: { kind: "drag", target: { kindOf: isRotateHandle } },
|
|
17366
|
+
actionId: "rotate",
|
|
17367
|
+
...Object.keys(opts).length > 0 ? { opts } : {}
|
|
17368
|
+
}
|
|
17369
|
+
];
|
|
17370
|
+
}
|
|
17371
|
+
function selectionMoveContribution(options = {}) {
|
|
17372
|
+
return {
|
|
17373
|
+
id: SELECTION_MOVE_ID,
|
|
17374
|
+
eligibility: { always: true },
|
|
17375
|
+
bindings: selectionMoveBindings(options)
|
|
17376
|
+
};
|
|
17377
|
+
}
|
|
17378
|
+
function selectionTransformContribution(options = {}) {
|
|
17379
|
+
return {
|
|
17380
|
+
id: SELECTION_TRANSFORM_ID,
|
|
17381
|
+
eligibility: { always: true },
|
|
17382
|
+
bindings: selectionTransformBindings(options)
|
|
17383
|
+
};
|
|
17384
|
+
}
|
|
17385
|
+
var AREA_SELECT_ID = "selection.areaSelect";
|
|
17386
|
+
var onEmptyCanvas = (hit, body) => hit == null && body === "empty";
|
|
17387
|
+
function areaSelectContribution() {
|
|
17388
|
+
return {
|
|
17389
|
+
id: AREA_SELECT_ID,
|
|
17390
|
+
eligibility: { always: true },
|
|
17391
|
+
bindings: [{ spec: { kind: "drag", target: { kindOf: onEmptyCanvas } }, actionId: "areaSelect" }]
|
|
17392
|
+
};
|
|
17393
|
+
}
|
|
17013
17394
|
|
|
17014
17395
|
// src/core/selection/selectionTarget.ts
|
|
17015
17396
|
var MULTI_RESIZE_TARGET_ID = "__weasel:multi-selection";
|
|
@@ -17136,21 +17517,14 @@ function useSelectTool(adapter, options) {
|
|
|
17136
17517
|
},
|
|
17137
17518
|
actions: [pickAction, collapseDeferredAction]
|
|
17138
17519
|
});
|
|
17139
|
-
const moveOpts = (() => {
|
|
17140
|
-
const reparent = options.reparentOnDrop && options.reparentOnDrop !== "off" ? { params: { reparentOnDrop: options.reparentOnDrop } } : void 0;
|
|
17141
|
-
const behaviors = options.move?.behaviors?.length ? { behaviors: options.move.behaviors } : void 0;
|
|
17142
|
-
return reparent || behaviors ? { opts: { ...reparent, ...behaviors } } : {};
|
|
17143
|
-
})();
|
|
17144
17520
|
return {
|
|
17145
17521
|
...base,
|
|
17146
|
-
// Declarative bindings for the gesture dispatcher.
|
|
17147
|
-
//
|
|
17148
|
-
//
|
|
17149
|
-
//
|
|
17150
|
-
//
|
|
17151
|
-
//
|
|
17152
|
-
// 4. Empty drag — marquee area-select.
|
|
17153
|
-
// 5. Click on empty (no modifiers) → clear selection.
|
|
17522
|
+
// Declarative bindings for the gesture dispatcher. The select tool
|
|
17523
|
+
// only chooses: press → classify + select, release → collapse a
|
|
17524
|
+
// deferred multi-click, empty drag → marquee, click on empty → clear.
|
|
17525
|
+
// Moving, cloning, resizing and rotating the selection are ambient
|
|
17526
|
+
// bindings owned by the selection (`selectionContributions.ts`), so
|
|
17527
|
+
// they run under any tool that leaves the gesture unclaimed.
|
|
17154
17528
|
bindings: [
|
|
17155
17529
|
// Every press that landed on the scene rather than on chrome. This
|
|
17156
17530
|
// is the former `initial.pointerDown['*']` route: it classifies the
|
|
@@ -17190,55 +17564,13 @@ function useSelectTool(adapter, options) {
|
|
|
17190
17564
|
},
|
|
17191
17565
|
actionId: "select.collapseDeferred"
|
|
17192
17566
|
},
|
|
17193
|
-
|
|
17194
|
-
|
|
17195
|
-
//
|
|
17196
|
-
// Listed BEFORE bare move so the strict-modifier dispatcher
|
|
17197
|
-
// picks this when Alt is held; bare move matches no-mod drags.
|
|
17198
|
-
// Both selected and unselected bodies are valid clone targets — the
|
|
17199
|
-
// pointerDown classifier calls `selection.applyClick(top, mods)` on
|
|
17200
|
-
// an unselected hit before the drag fires, so cloneAction's
|
|
17201
|
-
// `start` sees the hit node in `selection.get()` either way.
|
|
17202
|
-
{ spec: { kind: "drag", target: "selected-body", mods: { alt: true } }, actionId: "clone" },
|
|
17203
|
-
{ spec: { kind: "drag", target: "unselected-body", mods: { alt: true } }, actionId: "clone" },
|
|
17567
|
+
// Empty drag → marquee. `onEmptyCanvas` rather than a bare `'empty'`
|
|
17568
|
+
// target: the ambient bindings that own the handles rank below this
|
|
17569
|
+
// active one, so `'empty'` took drags that start on them.
|
|
17204
17570
|
{
|
|
17205
|
-
|
|
17206
|
-
|
|
17207
|
-
// body classifier still reports 'selected-body'; without this
|
|
17208
|
-
// opt-out, move's active-scope binding beats editAnchors's
|
|
17209
|
-
// ambient-scope binding on every anchor drag.
|
|
17210
|
-
//
|
|
17211
|
-
// `isAnchorOrControl` is the SAME predicate `editAnchorsAction`
|
|
17212
|
-
// matches on. That is load-bearing: the two must agree on what
|
|
17213
|
-
// counts as an anchor hit or move steals the drag — which is
|
|
17214
|
-
// exactly the bug this opt-out exists to prevent. (It used to be
|
|
17215
|
-
// a hand-rolled regex here that lacked the trailing-index
|
|
17216
|
-
// requirement, so the two sides could disagree.)
|
|
17217
|
-
spec: {
|
|
17218
|
-
kind: "drag",
|
|
17219
|
-
target: {
|
|
17220
|
-
kindOf: (afford, body) => body === "selected-body" && !isAnchorOrControl(afford)
|
|
17221
|
-
}
|
|
17222
|
-
},
|
|
17223
|
-
actionId: "move",
|
|
17224
|
-
...moveOpts
|
|
17225
|
-
},
|
|
17226
|
-
// Body-drag on a NOT-yet-selected node → also move. The pointerDown
|
|
17227
|
-
// classifier selects the hit node before the drag fires (same
|
|
17228
|
-
// contract clone relies on), so by the time moveAction.start() runs
|
|
17229
|
-
// the node is in `selection.get()`. Without this active binding an
|
|
17230
|
-
// unselected-body drag finds no active match and falls through to
|
|
17231
|
-
// ambient scope, where the `rotate` catch-all (`{ kind: 'drag' }`,
|
|
17232
|
-
// start()-guarded only on a non-empty selection) hijacks it — the
|
|
17233
|
-
// "first drag rotates, later drags move" bug. Unselected nodes never
|
|
17234
|
-
// carry anchor affordances (those gate on selection), so the plain
|
|
17235
|
-
// string-form target is sufficient here.
|
|
17236
|
-
{
|
|
17237
|
-
spec: { kind: "drag", target: "unselected-body" },
|
|
17238
|
-
actionId: "move",
|
|
17239
|
-
...moveOpts
|
|
17571
|
+
spec: { kind: "drag", target: { kindOf: onEmptyCanvas } },
|
|
17572
|
+
actionId: "areaSelect"
|
|
17240
17573
|
},
|
|
17241
|
-
{ spec: { kind: "drag", target: "empty" }, actionId: "areaSelect" },
|
|
17242
17574
|
// resize/rotate bind only drag (no click), so a click on either handle
|
|
17243
17575
|
// (body genuinely empty) would hit target:'empty' and wrongly clear selection.
|
|
17244
17576
|
{
|
|
@@ -17252,15 +17584,14 @@ function useSelectTool(adapter, options) {
|
|
|
17252
17584
|
]
|
|
17253
17585
|
};
|
|
17254
17586
|
},
|
|
17255
|
-
|
|
17256
|
-
[options.debug, options.reparentOnDrop, options.move, pickAction, collapseDeferredAction]
|
|
17587
|
+
[pickAction, collapseDeferredAction]
|
|
17257
17588
|
);
|
|
17258
17589
|
}
|
|
17259
17590
|
function useHandTool(opts = {}) {
|
|
17260
17591
|
const optsRef = useRef(opts);
|
|
17261
17592
|
optsRef.current = opts;
|
|
17262
17593
|
return useMemo(
|
|
17263
|
-
() => Object.assign(
|
|
17594
|
+
() => Object.assign(defineTool({
|
|
17264
17595
|
id: "hand",
|
|
17265
17596
|
capabilities: ["navigation"],
|
|
17266
17597
|
hotkey: "space",
|
|
@@ -17290,6 +17621,20 @@ function useHandTool(opts = {}) {
|
|
|
17290
17621
|
[]
|
|
17291
17622
|
);
|
|
17292
17623
|
}
|
|
17624
|
+
|
|
17625
|
+
// src/tools/builtin/hand/dragPanContribution.ts
|
|
17626
|
+
var DRAG_PAN_ID = "viewport.dragPanBinding";
|
|
17627
|
+
function dragPanContribution(params = {}) {
|
|
17628
|
+
return {
|
|
17629
|
+
id: DRAG_PAN_ID,
|
|
17630
|
+
eligibility: { always: true },
|
|
17631
|
+
bindings: [{
|
|
17632
|
+
spec: { kind: "drag" },
|
|
17633
|
+
actionId: "viewport.dragPan",
|
|
17634
|
+
...Object.keys(params).length > 0 ? { opts: { params: { ...params } } } : {}
|
|
17635
|
+
}]
|
|
17636
|
+
};
|
|
17637
|
+
}
|
|
17293
17638
|
var PRESENTATION = {
|
|
17294
17639
|
label: "Text",
|
|
17295
17640
|
icon: createElement(TextIcon),
|
|
@@ -17336,14 +17681,19 @@ useTextTool.options = {
|
|
|
17336
17681
|
underline: flag("Underline", "underline"),
|
|
17337
17682
|
strikethrough: flag("Strikethrough", "strikethrough"),
|
|
17338
17683
|
overline: flag("Overline", "overline"),
|
|
17339
|
-
//
|
|
17340
|
-
//
|
|
17341
|
-
// segment has to clear it. The host draws it and owns that rule.
|
|
17684
|
+
// Clearable: the two values are exclusive *and* absent is a third state,
|
|
17685
|
+
// so clicking the lit segment turns the script off.
|
|
17342
17686
|
script: {
|
|
17343
|
-
kind: "
|
|
17687
|
+
kind: "enum",
|
|
17344
17688
|
name: "Script",
|
|
17345
17689
|
description: "Raise or lower the range off the baseline, at a smaller size.",
|
|
17346
|
-
|
|
17690
|
+
control: "toggle",
|
|
17691
|
+
clearable: true,
|
|
17692
|
+
default: void 0,
|
|
17693
|
+
options: [
|
|
17694
|
+
{ value: "super", label: "Superscript", icon: "superscript" },
|
|
17695
|
+
{ value: "sub", label: "Subscript", icon: "subscript" }
|
|
17696
|
+
]
|
|
17347
17697
|
},
|
|
17348
17698
|
textTransform: {
|
|
17349
17699
|
kind: "enum",
|
|
@@ -18009,52 +18359,13 @@ function useLineTool() {
|
|
|
18009
18359
|
[]
|
|
18010
18360
|
);
|
|
18011
18361
|
}
|
|
18012
|
-
var LASSO_VERTICES = scratchKey("lassoSelect.vertices");
|
|
18013
|
-
var MIN_AREA = 4;
|
|
18014
|
-
function selectFromLasso(opts) {
|
|
18015
|
-
const mode = opts?.mode ?? "intersect";
|
|
18016
|
-
return {
|
|
18017
|
-
defaultTransient: true,
|
|
18018
|
-
onEnd(ctx) {
|
|
18019
|
-
const adapter = ctx.adapter;
|
|
18020
|
-
if (!adapter.getSelection || !adapter.hitTestLasso) return null;
|
|
18021
|
-
const vertices = getScratch(ctx.scratch, LASSO_VERTICES) ?? [];
|
|
18022
|
-
const startPose = ctx.origin.get("gesture");
|
|
18023
|
-
const shiftHeld = startPose ? startPose.shiftHeld === true : false;
|
|
18024
|
-
const from = adapter.getSelection();
|
|
18025
|
-
const tiny = vertices.length < 3 || polygonAabbArea(vertices) < MIN_AREA;
|
|
18026
|
-
if (tiny) {
|
|
18027
|
-
const to2 = shiftHeld ? from : [];
|
|
18028
|
-
const op2 = createSetSelectionOp({ from, to: to2 });
|
|
18029
|
-
return [op2];
|
|
18030
|
-
}
|
|
18031
|
-
const hits = adapter.hitTestLasso(vertices, mode);
|
|
18032
|
-
const to = shiftHeld ? mergeUnique(from, hits) : hits;
|
|
18033
|
-
const op = createSetSelectionOp({ from, to });
|
|
18034
|
-
return [op];
|
|
18035
|
-
}
|
|
18036
|
-
};
|
|
18037
|
-
}
|
|
18038
|
-
function polygonAabbArea(vertices) {
|
|
18039
|
-
if (vertices.length === 0) return 0;
|
|
18040
|
-
let minX = Infinity, minY = Infinity, maxX = -Infinity, maxY = -Infinity;
|
|
18041
|
-
for (const v of vertices) {
|
|
18042
|
-
if (v.x < minX) minX = v.x;
|
|
18043
|
-
if (v.y < minY) minY = v.y;
|
|
18044
|
-
if (v.x > maxX) maxX = v.x;
|
|
18045
|
-
if (v.y > maxY) maxY = v.y;
|
|
18046
|
-
}
|
|
18047
|
-
return (maxX - minX) * (maxY - minY);
|
|
18048
|
-
}
|
|
18049
|
-
function mergeUnique(a, b) {
|
|
18050
|
-
const out = [...a];
|
|
18051
|
-
for (const id of b) if (!out.includes(id)) out.push(id);
|
|
18052
|
-
return out;
|
|
18053
|
-
}
|
|
18054
|
-
|
|
18055
|
-
// src/tools/builtin/lasso/useLassoTool.ts
|
|
18056
18362
|
function useLassoTool(_adapter, options = {}) {
|
|
18057
|
-
|
|
18363
|
+
const paramsRef = useRef({ mode: "intersect" });
|
|
18364
|
+
paramsRef.current = {
|
|
18365
|
+
mode: options.mode ?? "intersect",
|
|
18366
|
+
...options.minVertexSpacing !== void 0 ? { minVertexSpacing: options.minVertexSpacing } : {}
|
|
18367
|
+
};
|
|
18368
|
+
const { behaviors } = options;
|
|
18058
18369
|
return useMemo(() => {
|
|
18059
18370
|
return defineTool({
|
|
18060
18371
|
id: "lasso",
|
|
@@ -18071,10 +18382,19 @@ function useLassoTool(_adapter, options = {}) {
|
|
|
18071
18382
|
// dispatcher invokes `lassoSelectAction`, which owns vertex buffering,
|
|
18072
18383
|
// overlay state, and the commit-on-end selection write.
|
|
18073
18384
|
bindings: [
|
|
18074
|
-
{
|
|
18385
|
+
{
|
|
18386
|
+
spec: { kind: "drag", mods: { shift: "optional" } },
|
|
18387
|
+
actionId: "lassoSelect",
|
|
18388
|
+
// Thunked so a mode or spacing change reaches the next gesture
|
|
18389
|
+
// without rebuilding the tool.
|
|
18390
|
+
opts: {
|
|
18391
|
+
params: () => paramsRef.current,
|
|
18392
|
+
...behaviors ? { behaviors } : {}
|
|
18393
|
+
}
|
|
18394
|
+
}
|
|
18075
18395
|
]
|
|
18076
18396
|
});
|
|
18077
|
-
}, [options.keybinding]);
|
|
18397
|
+
}, [options.keybinding, behaviors]);
|
|
18078
18398
|
}
|
|
18079
18399
|
var MIN_SIDES = 3;
|
|
18080
18400
|
var MAX_SIDES = 32;
|
|
@@ -18324,7 +18644,7 @@ function isCustomEntry(v) {
|
|
|
18324
18644
|
|
|
18325
18645
|
// src/canvas/layerOrder.ts
|
|
18326
18646
|
var STANDARD_SLOT_SET = new Set(STANDARD_SLOTS);
|
|
18327
|
-
function composeOrderedLayers(layersMap, standardLayers, sceneLayers) {
|
|
18647
|
+
function composeOrderedLayers(layersMap, standardLayers, sceneLayers, background) {
|
|
18328
18648
|
const afterByParent = /* @__PURE__ */ new Map();
|
|
18329
18649
|
const beforeByParent = /* @__PURE__ */ new Map();
|
|
18330
18650
|
const tail = [];
|
|
@@ -18346,7 +18666,7 @@ function composeOrderedLayers(layersMap, standardLayers, sceneLayers) {
|
|
|
18346
18666
|
}
|
|
18347
18667
|
}
|
|
18348
18668
|
const emitted = /* @__PURE__ */ new Set();
|
|
18349
|
-
const out = [];
|
|
18669
|
+
const out = background ? [background] : [];
|
|
18350
18670
|
function emitChild(child) {
|
|
18351
18671
|
if (emitted.has(child.key)) {
|
|
18352
18672
|
console.warn(`composeOrderedLayers: cycle detected involving custom layer "${child.key}"`);
|
|
@@ -18471,7 +18791,7 @@ function findMountedCanvas(root, hint) {
|
|
|
18471
18791
|
function* toolsInPriorityOrder(tools) {
|
|
18472
18792
|
const seen = /* @__PURE__ */ new Set();
|
|
18473
18793
|
const hotkey = tools.hotkeyEngaged ? tools.registry[tools.hotkeyEngaged] : void 0;
|
|
18474
|
-
const active = tools.registry[tools.active];
|
|
18794
|
+
const active = tools.active === null ? void 0 : tools.registry[tools.active];
|
|
18475
18795
|
for (const t of [hotkey, active]) {
|
|
18476
18796
|
if (t && !seen.has(t)) {
|
|
18477
18797
|
seen.add(t);
|
|
@@ -18532,22 +18852,17 @@ var EMPTY_CHROME_STATE = {
|
|
|
18532
18852
|
};
|
|
18533
18853
|
function buildChromeState(args) {
|
|
18534
18854
|
const { selection, multiActive: multiActive2, effectiveBoundsOf, modifiers, canRotate } = args;
|
|
18535
|
-
const cached = { value: null, computed: false };
|
|
18536
18855
|
return {
|
|
18537
18856
|
selection,
|
|
18538
18857
|
multiActive: multiActive2,
|
|
18539
18858
|
boundsOf: effectiveBoundsOf,
|
|
18540
18859
|
modifiers,
|
|
18541
18860
|
canRotate: canRotate ?? (() => true),
|
|
18861
|
+
// Not cached: the state is memoized across renders, and poses move under
|
|
18862
|
+
// it (a committed move, a live preview) without any of its inputs changing.
|
|
18542
18863
|
get unionBounds() {
|
|
18543
|
-
if (
|
|
18544
|
-
|
|
18545
|
-
if (!multiActive2) {
|
|
18546
|
-
cached.value = null;
|
|
18547
|
-
return null;
|
|
18548
|
-
}
|
|
18549
|
-
cached.value = unionAABB(selection.map((id) => effectiveBoundsOf(id)));
|
|
18550
|
-
return cached.value;
|
|
18864
|
+
if (!multiActive2) return null;
|
|
18865
|
+
return unionAABB(selection.map((id) => effectiveBoundsOf(id)));
|
|
18551
18866
|
}
|
|
18552
18867
|
};
|
|
18553
18868
|
}
|
|
@@ -19413,7 +19728,7 @@ function pathFor(d) {
|
|
|
19413
19728
|
}
|
|
19414
19729
|
return p;
|
|
19415
19730
|
}
|
|
19416
|
-
function
|
|
19731
|
+
function commandFor(op) {
|
|
19417
19732
|
return {
|
|
19418
19733
|
kind: "path",
|
|
19419
19734
|
path: pathFor(op.d),
|
|
@@ -19453,7 +19768,7 @@ function createPaintedCursorLayer(state) {
|
|
|
19453
19768
|
at
|
|
19454
19769
|
});
|
|
19455
19770
|
const transform = new Float32Array([a, b, 0, c, d, 0, e, f, 1]);
|
|
19456
|
-
const children = ops.map(
|
|
19771
|
+
const children = ops.map(commandFor);
|
|
19457
19772
|
return [{ kind: "group", transform, children }];
|
|
19458
19773
|
}
|
|
19459
19774
|
};
|
|
@@ -19486,6 +19801,9 @@ function wrapNodeOutput(cmds, pose, alpha) {
|
|
|
19486
19801
|
}
|
|
19487
19802
|
return rotated;
|
|
19488
19803
|
}
|
|
19804
|
+
|
|
19805
|
+
// src/canvas/hud.module.css
|
|
19806
|
+
var hud_default = {};
|
|
19489
19807
|
function insetAlong(start, extent, size, align, by) {
|
|
19490
19808
|
if (align === "start") return start + by;
|
|
19491
19809
|
if (align === "end") return start + extent - size - by;
|
|
@@ -19624,20 +19942,8 @@ function CursorCoordsHud({ canvasRef, anchorRef, viewRef, offset }) {
|
|
|
19624
19942
|
"div",
|
|
19625
19943
|
{
|
|
19626
19944
|
ref,
|
|
19627
|
-
|
|
19628
|
-
|
|
19629
|
-
...anchorStyle,
|
|
19630
|
-
zIndex: 1e4,
|
|
19631
|
-
background: "rgba(0,0,0,0.7)",
|
|
19632
|
-
color: "#e8e8e8",
|
|
19633
|
-
font: "11px ui-monospace, SFMono-Regular, Menlo, monospace",
|
|
19634
|
-
padding: "6px 8px",
|
|
19635
|
-
borderRadius: 4,
|
|
19636
|
-
pointerEvents: "none",
|
|
19637
|
-
lineHeight: 1.4,
|
|
19638
|
-
whiteSpace: "pre",
|
|
19639
|
-
textAlign: "right"
|
|
19640
|
-
},
|
|
19945
|
+
className: `${hud_default.hud} ${hud_default.pre}`,
|
|
19946
|
+
style: anchorStyle,
|
|
19641
19947
|
children: [
|
|
19642
19948
|
`fps ${fps.toString().padStart(3)}`,
|
|
19643
19949
|
"\n",
|
|
@@ -19648,9 +19954,6 @@ function CursorCoordsHud({ canvasRef, anchorRef, viewRef, offset }) {
|
|
|
19648
19954
|
}
|
|
19649
19955
|
);
|
|
19650
19956
|
}
|
|
19651
|
-
|
|
19652
|
-
// src/canvas/PickHud.module.css
|
|
19653
|
-
var PickHud_default = {};
|
|
19654
19957
|
function PickHud({ canvasRef, anchorRef, viewRef, pickEvery, pickBest, offset }) {
|
|
19655
19958
|
const [state, setState] = useState({
|
|
19656
19959
|
ids: [],
|
|
@@ -19702,25 +20005,22 @@ function PickHud({ canvasRef, anchorRef, viewRef, pickEvery, pickBest, offset })
|
|
|
19702
20005
|
};
|
|
19703
20006
|
}, [canvasRef, viewRef, pickEvery, pickBest]);
|
|
19704
20007
|
if (!style) return null;
|
|
19705
|
-
return /* @__PURE__ */ jsxs("div", { ref, className:
|
|
19706
|
-
/* @__PURE__ */ jsxs("div", { className:
|
|
20008
|
+
return /* @__PURE__ */ jsxs("div", { ref, className: `${hud_default.hud} ${hud_default.sized}`, style, children: [
|
|
20009
|
+
/* @__PURE__ */ jsxs("div", { className: `${hud_default.header} ${hud_default.muted}`, children: [
|
|
19707
20010
|
"pickEvery (",
|
|
19708
20011
|
state.ids.length,
|
|
19709
20012
|
")"
|
|
19710
20013
|
] }),
|
|
19711
|
-
state.ids.length === 0 ? /* @__PURE__ */ jsx("div", { className:
|
|
20014
|
+
state.ids.length === 0 ? /* @__PURE__ */ jsx("div", { className: hud_default.absent, children: state.inCanvas ? "\u2014" : "off-canvas" }) : /* @__PURE__ */ jsx("ul", { className: hud_default.list, children: state.ids.slice().reverse().map((id) => /* @__PURE__ */ jsx(
|
|
19712
20015
|
"li",
|
|
19713
20016
|
{
|
|
19714
|
-
className: id === state.best ? `${
|
|
20017
|
+
className: id === state.best ? `${hud_default.item} ${hud_default.itemBest}` : hud_default.item,
|
|
19715
20018
|
children: id
|
|
19716
20019
|
},
|
|
19717
20020
|
id
|
|
19718
20021
|
)) })
|
|
19719
20022
|
] });
|
|
19720
20023
|
}
|
|
19721
|
-
|
|
19722
|
-
// src/canvas/ModalityHud.module.css
|
|
19723
|
-
var ModalityHud_default = {};
|
|
19724
20024
|
function ModalityHud({ canvasRef, anchorRef, modeId, offset }) {
|
|
19725
20025
|
const toolCtx = useOptionalActiveToolContext();
|
|
19726
20026
|
const { ref, style } = useHostAnchor(
|
|
@@ -19734,18 +20034,18 @@ function ModalityHud({ canvasRef, anchorRef, modeId, offset }) {
|
|
|
19734
20034
|
const active = toolCtx?.active ?? null;
|
|
19735
20035
|
const hotkeys = toolCtx?.hotkeyStack ?? [];
|
|
19736
20036
|
const hotkeyTop = hotkeys.length > 0 ? hotkeys[hotkeys.length - 1] : null;
|
|
19737
|
-
return /* @__PURE__ */ jsxs("div", { ref, className:
|
|
19738
|
-
/* @__PURE__ */ jsxs("div", { className:
|
|
19739
|
-
/* @__PURE__ */ jsx("span", { className:
|
|
19740
|
-
/* @__PURE__ */ jsx("span", { className: modeId ?
|
|
20037
|
+
return /* @__PURE__ */ jsxs("div", { ref, className: `${hud_default.hud} ${hud_default.sized}`, style, children: [
|
|
20038
|
+
/* @__PURE__ */ jsxs("div", { className: hud_default.row, children: [
|
|
20039
|
+
/* @__PURE__ */ jsx("span", { className: hud_default.muted, children: "mode" }),
|
|
20040
|
+
/* @__PURE__ */ jsx("span", { className: modeId ? void 0 : hud_default.absent, children: modeId ?? "\u2014" })
|
|
19741
20041
|
] }),
|
|
19742
|
-
/* @__PURE__ */ jsxs("div", { className:
|
|
19743
|
-
/* @__PURE__ */ jsx("span", { className:
|
|
19744
|
-
/* @__PURE__ */ jsx("span", { className: active ?
|
|
20042
|
+
/* @__PURE__ */ jsxs("div", { className: hud_default.row, children: [
|
|
20043
|
+
/* @__PURE__ */ jsx("span", { className: hud_default.muted, children: "active" }),
|
|
20044
|
+
/* @__PURE__ */ jsx("span", { className: active ? void 0 : hud_default.absent, children: active ?? "\u2014" })
|
|
19745
20045
|
] }),
|
|
19746
|
-
/* @__PURE__ */ jsxs("div", { className:
|
|
19747
|
-
/* @__PURE__ */ jsx("span", { className:
|
|
19748
|
-
hotkeys.length <= 1 ? /* @__PURE__ */ jsx("span", { className: hotkeyTop ?
|
|
20046
|
+
/* @__PURE__ */ jsxs("div", { className: hud_default.row, children: [
|
|
20047
|
+
/* @__PURE__ */ jsx("span", { className: hud_default.muted, children: "hotkey" }),
|
|
20048
|
+
hotkeys.length <= 1 ? /* @__PURE__ */ jsx("span", { className: hotkeyTop ? void 0 : hud_default.absent, children: hotkeyTop ?? "\u2014" }) : /* @__PURE__ */ jsx("span", { className: hud_default.stack, children: hotkeys.slice().reverse().map((id, i) => /* @__PURE__ */ jsx("span", { className: i === 0 ? void 0 : hud_default.absent, children: id }, `${id}-${i}`)) })
|
|
19749
20049
|
] })
|
|
19750
20050
|
] });
|
|
19751
20051
|
}
|
|
@@ -19837,7 +20137,7 @@ function buildSceneLayers(cfg, adapter, debugSink, boundsOfFn, hideIds) {
|
|
|
19837
20137
|
}
|
|
19838
20138
|
function resolveToolsCursor(tools, ctxBase) {
|
|
19839
20139
|
const id = tools.hotkeyEngaged ?? tools.active;
|
|
19840
|
-
const tool = tools.registry[id];
|
|
20140
|
+
const tool = id === null ? void 0 : tools.registry[id];
|
|
19841
20141
|
if (!tool?.cursor) return void 0;
|
|
19842
20142
|
if (typeof tool.cursor !== "function") return resolveCursorTier(tool.cursor);
|
|
19843
20143
|
if (!ctxBase) return void 0;
|
|
@@ -19861,6 +20161,7 @@ function CanvasInner(props, ref) {
|
|
|
19861
20161
|
flattenTolerance,
|
|
19862
20162
|
contentVersion,
|
|
19863
20163
|
syncPaint = false,
|
|
20164
|
+
redrawOn,
|
|
19864
20165
|
adapter: adapterProp,
|
|
19865
20166
|
layers: layersMap,
|
|
19866
20167
|
selection,
|
|
@@ -20260,8 +20561,12 @@ function CanvasInner(props, ref) {
|
|
|
20260
20561
|
...cfg.poseById ? { getPose: cfg.poseById, poseDescriptor: cfg.poseDescriptor ?? geometry } : {}
|
|
20261
20562
|
});
|
|
20262
20563
|
}
|
|
20263
|
-
const
|
|
20264
|
-
|
|
20564
|
+
const out = composeOrderedLayers(
|
|
20565
|
+
layersMap,
|
|
20566
|
+
standardLayers,
|
|
20567
|
+
sceneLayers,
|
|
20568
|
+
backgroundLayer ?? void 0
|
|
20569
|
+
);
|
|
20265
20570
|
if (decorationLayer) out.push(decorationLayer);
|
|
20266
20571
|
if (tools) {
|
|
20267
20572
|
placeToolOverlays(out, standardLayers.selectionOverlay, tools.getActiveOverlays);
|
|
@@ -20325,6 +20630,26 @@ function CanvasInner(props, ref) {
|
|
|
20325
20630
|
viewRegistryVersion,
|
|
20326
20631
|
paintedCursorLayer
|
|
20327
20632
|
]);
|
|
20633
|
+
useEffect(() => {
|
|
20634
|
+
const redraw = () => {
|
|
20635
|
+
requestRedraw();
|
|
20636
|
+
};
|
|
20637
|
+
const offs = [];
|
|
20638
|
+
for (const layer of layersWithDebug) if (layer.subscribe) offs.push(layer.subscribe(redraw));
|
|
20639
|
+
return () => {
|
|
20640
|
+
for (const off of offs) off();
|
|
20641
|
+
};
|
|
20642
|
+
}, [layersWithDebug, requestRedraw]);
|
|
20643
|
+
const redrawSources = useSameElements(redrawOn);
|
|
20644
|
+
useEffect(() => {
|
|
20645
|
+
const redraw = () => {
|
|
20646
|
+
requestRedraw();
|
|
20647
|
+
};
|
|
20648
|
+
const offs = (redrawSources ?? []).map((src) => src.subscribe(redraw));
|
|
20649
|
+
return () => {
|
|
20650
|
+
for (const off of offs) off();
|
|
20651
|
+
};
|
|
20652
|
+
}, [redrawSources, requestRedraw]);
|
|
20328
20653
|
const shaderIdKey = shaders?.map((h) => h.id).join("|") ?? "";
|
|
20329
20654
|
const paintInputsRef = useRef({
|
|
20330
20655
|
layers: layersWithDebug,
|
|
@@ -20573,6 +20898,14 @@ function CanvasInner(props, ref) {
|
|
|
20573
20898
|
] });
|
|
20574
20899
|
}
|
|
20575
20900
|
var Canvas = forwardRef(CanvasInner);
|
|
20901
|
+
function useSameElements(list2) {
|
|
20902
|
+
const ref = useRef(list2);
|
|
20903
|
+
const prev = ref.current;
|
|
20904
|
+
if (prev !== list2 && !(prev && list2 && prev.length === list2.length && prev.every((x, i) => x === list2[i]))) {
|
|
20905
|
+
ref.current = list2;
|
|
20906
|
+
}
|
|
20907
|
+
return ref.current;
|
|
20908
|
+
}
|
|
20576
20909
|
|
|
20577
20910
|
// src/canvas/colorOverrides.ts
|
|
20578
20911
|
var clock = () => typeof performance !== "undefined" ? performance.now() : Date.now();
|
|
@@ -20602,73 +20935,127 @@ function wireSceneSlotToScene(slot, scene, alphaFor, colorOverrides) {
|
|
|
20602
20935
|
alphaFor: composeAlphaFor(scene, alphaFor)
|
|
20603
20936
|
};
|
|
20604
20937
|
}
|
|
20605
|
-
function
|
|
20606
|
-
|
|
20607
|
-
|
|
20608
|
-
|
|
20609
|
-
|
|
20938
|
+
function aabbOfPose(pose, descriptor = AUTO_POSE_DESCRIPTOR) {
|
|
20939
|
+
return descriptor.getBounds(pose);
|
|
20940
|
+
}
|
|
20941
|
+
var DEFAULT_PATH_STROKE_SLOP = 4;
|
|
20942
|
+
function poseContains(pose, wx, wy, tolerance, descriptor = AUTO_POSE_DESCRIPTOR) {
|
|
20943
|
+
if (isPathLike(pose)) {
|
|
20944
|
+
if (pointInPath(pose, wx, wy)) return true;
|
|
20945
|
+
return strokeHitTest(pose, wx, wy, tolerance ?? DEFAULT_PATH_STROKE_SLOP);
|
|
20610
20946
|
}
|
|
20611
|
-
|
|
20947
|
+
const b = aabbOfPose(pose, descriptor);
|
|
20948
|
+
const t = tolerance ?? 0;
|
|
20949
|
+
return wx >= b.x - t && wx <= b.x + b.width + t && wy >= b.y - t && wy <= b.y + b.height + t;
|
|
20612
20950
|
}
|
|
20613
|
-
function
|
|
20614
|
-
|
|
20951
|
+
function poseContainsRotated(pose, wx, wy, tolerance, descriptor = AUTO_POSE_DESCRIPTOR) {
|
|
20952
|
+
const r = descriptor === AUTO_POSE_DESCRIPTOR ? poseRotationOf(pose) : rotationAboutCenter(pose, descriptor);
|
|
20953
|
+
if (r) {
|
|
20954
|
+
const [lx, ly] = applyToPoint(rotateAboutPoint(r.cx, r.cy, -r.rotation), wx, wy);
|
|
20955
|
+
return poseContains(pose, lx, ly, tolerance, descriptor);
|
|
20956
|
+
}
|
|
20957
|
+
return poseContains(pose, wx, wy, tolerance, descriptor);
|
|
20615
20958
|
}
|
|
20616
|
-
function
|
|
20617
|
-
|
|
20618
|
-
|
|
20619
|
-
|
|
20620
|
-
|
|
20621
|
-
if (!pointInPolygon(flat, rect.x + rect.width, rect.y + rect.height)) return false;
|
|
20622
|
-
if (!pointInPolygon(flat, rect.x, rect.y + rect.height)) return false;
|
|
20623
|
-
return !anyPolyEdgeCrossesRect(poly2, rect);
|
|
20959
|
+
function rotationAboutCenter(pose, descriptor) {
|
|
20960
|
+
const rotation = descriptor.getRotation?.(pose) ?? 0;
|
|
20961
|
+
if (!rotation) return null;
|
|
20962
|
+
const b = descriptor.getBounds(pose);
|
|
20963
|
+
return { cx: b.x + b.width / 2, cy: b.y + b.height / 2, rotation };
|
|
20624
20964
|
}
|
|
20625
|
-
function
|
|
20626
|
-
|
|
20627
|
-
|
|
20628
|
-
|
|
20629
|
-
|
|
20630
|
-
|
|
20631
|
-
|
|
20965
|
+
function regionPickOptions(view, alphaOf, poseComposition) {
|
|
20966
|
+
return {
|
|
20967
|
+
...poseComposition ? { poseComposition } : {},
|
|
20968
|
+
...alphaOf ? { alphaOf } : {},
|
|
20969
|
+
...view?.layerIsPainted ? { layerIsPainted: (layer) => view.layerIsPainted(layer) } : {}
|
|
20970
|
+
};
|
|
20971
|
+
}
|
|
20972
|
+
function hitTestArea(scene, bounds, opts, descriptor = AUTO_POSE_DESCRIPTOR, query = {}) {
|
|
20973
|
+
const { x, y, width: w, height: h } = bounds;
|
|
20974
|
+
const area = Array.from(rectToContour(x, y, w, h));
|
|
20975
|
+
return hitTestAreaPolygon(scene, area, { x, y, width: w, height: h }, true, opts, descriptor, query);
|
|
20976
|
+
}
|
|
20977
|
+
function hitTestAreaPolygon(scene, area, areaBounds, areaIsRect = false, opts, descriptor = AUTO_POSE_DESCRIPTOR, query = {}) {
|
|
20978
|
+
const ab = areaBounds ?? boundsOf(area);
|
|
20979
|
+
if (!ab) return [];
|
|
20980
|
+
const areaVerts = [];
|
|
20981
|
+
for (let i = 0; i + 1 < area.length; i += 2) areaVerts.push({ x: area[i], y: area[i + 1] });
|
|
20982
|
+
return walkArea(scene, ab, opts, descriptor, query, (node, pose, b, silhouette) => {
|
|
20983
|
+
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) {
|
|
20984
|
+
return true;
|
|
20985
|
+
}
|
|
20986
|
+
if (silhouette) {
|
|
20987
|
+
return polygonIntersectsPath(areaVerts, pose);
|
|
20988
|
+
}
|
|
20989
|
+
const outline = outlineOf(node, pose, b);
|
|
20990
|
+
if (outline.kind === "rect" && areaIsRect) return true;
|
|
20991
|
+
return polygonIntersectsPath(areaVerts, outline);
|
|
20992
|
+
});
|
|
20993
|
+
}
|
|
20994
|
+
function hitTestLassoPolygon(scene, polygon, mode, opts, descriptor = AUTO_POSE_DESCRIPTOR, query = {}) {
|
|
20995
|
+
if (polygon.length < 3) return [];
|
|
20996
|
+
const area = [];
|
|
20997
|
+
for (const p of polygon) area.push(p.x, p.y);
|
|
20998
|
+
if (mode === "intersect") {
|
|
20999
|
+
return hitTestAreaPolygon(scene, area, void 0, false, opts, descriptor, query);
|
|
20632
21000
|
}
|
|
20633
|
-
const
|
|
20634
|
-
if (
|
|
20635
|
-
|
|
20636
|
-
|
|
20637
|
-
|
|
20638
|
-
|
|
21001
|
+
const ab = boundsOf(area);
|
|
21002
|
+
if (!ab) return [];
|
|
21003
|
+
return walkArea(scene, ab, opts, descriptor, query, (node, pose, b, silhouette) => {
|
|
21004
|
+
if (mode === "centers") {
|
|
21005
|
+
return pointInPolygon(area, b.x + b.width / 2, b.y + b.height / 2);
|
|
21006
|
+
}
|
|
21007
|
+
if (b.x < ab.x || b.y < ab.y || b.x + b.width > ab.x + ab.width || b.y + b.height > ab.y + ab.height) {
|
|
21008
|
+
return false;
|
|
21009
|
+
}
|
|
21010
|
+
const outline = silhouette ? pose : outlineOf(node, pose, b);
|
|
21011
|
+
return polygonContainsPath(polygon, outline);
|
|
21012
|
+
});
|
|
20639
21013
|
}
|
|
20640
|
-
function
|
|
20641
|
-
|
|
20642
|
-
|
|
20643
|
-
|
|
20644
|
-
|
|
20645
|
-
|
|
20646
|
-
|
|
21014
|
+
function walkArea(scene, ab, opts, descriptor, query, hits) {
|
|
21015
|
+
return pickWalk(scenePickSource(scene, opts), {
|
|
21016
|
+
includeContainers: query.includeContainers === true,
|
|
21017
|
+
clipAdmits: (clip, node, pose) => {
|
|
21018
|
+
const g = poseDescriptorForNode(descriptor, node);
|
|
21019
|
+
return pathIntersectsRect(clip, visualBoundsViaDescriptor(pose, g)) && pathIntersectsRect(clip, ab);
|
|
21020
|
+
},
|
|
21021
|
+
hits: (node, pose) => {
|
|
21022
|
+
const g = poseDescriptorForNode(descriptor, node);
|
|
21023
|
+
const silhouette = pose !== null && typeof pose === "object" && pose.kind === "polygon";
|
|
21024
|
+
const b = silhouette ? nodeMemo(node, "aabb", pose, () => aabbOfPose(pose, g)) : visualBoundsViaDescriptor(pose, g);
|
|
21025
|
+
if (!Number.isFinite(b.x) || !Number.isFinite(b.y) || !Number.isFinite(b.width) || !Number.isFinite(b.height)) {
|
|
21026
|
+
return false;
|
|
21027
|
+
}
|
|
21028
|
+
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) {
|
|
21029
|
+
return false;
|
|
21030
|
+
}
|
|
21031
|
+
return hits(node, pose, b, silhouette);
|
|
21032
|
+
}
|
|
21033
|
+
});
|
|
21034
|
+
}
|
|
21035
|
+
function outlineOf(node, pose, b) {
|
|
21036
|
+
const drawn = findShapeSilhouette(node, pose);
|
|
21037
|
+
if (drawn) return drawn;
|
|
21038
|
+
const r = poseRotationOf(pose);
|
|
21039
|
+
if (r) {
|
|
21040
|
+
const p = pose;
|
|
21041
|
+
return rotatePathAround(rectPath(p.x, p.y, p.width, p.height), r.cx, r.cy, r.rotation);
|
|
20647
21042
|
}
|
|
20648
|
-
return
|
|
21043
|
+
return rectPath(b.x, b.y, b.width, b.height);
|
|
20649
21044
|
}
|
|
20650
|
-
function
|
|
20651
|
-
|
|
20652
|
-
|
|
20653
|
-
|
|
20654
|
-
|
|
20655
|
-
|
|
20656
|
-
|
|
20657
|
-
if (
|
|
20658
|
-
if (
|
|
20659
|
-
if (segmentsCross(a.x, a.y, b.x, b.y, r2x, r2y, r3x, r3y)) return true;
|
|
20660
|
-
if (segmentsCross(a.x, a.y, b.x, b.y, r3x, r3y, r0x, r0y)) return true;
|
|
21045
|
+
function boundsOf(coords) {
|
|
21046
|
+
if (coords.length < 2) return null;
|
|
21047
|
+
let minX = Infinity, minY = Infinity, maxX = -Infinity, maxY = -Infinity;
|
|
21048
|
+
for (let i = 0; i + 1 < coords.length; i += 2) {
|
|
21049
|
+
const x = coords[i], y = coords[i + 1];
|
|
21050
|
+
if (x < minX) minX = x;
|
|
21051
|
+
if (y < minY) minY = y;
|
|
21052
|
+
if (x > maxX) maxX = x;
|
|
21053
|
+
if (y > maxY) maxY = y;
|
|
20661
21054
|
}
|
|
20662
|
-
return
|
|
21055
|
+
return { x: minX, y: minY, width: maxX - minX, height: maxY - minY };
|
|
20663
21056
|
}
|
|
20664
21057
|
|
|
20665
21058
|
// src/canvas/sceneAdapter.ts
|
|
20666
|
-
function walkClipAware(scene, poseBounds, nodeTest, poseComposition) {
|
|
20667
|
-
return pickWalk(scenePickSource(scene, poseComposition ? { poseComposition } : {}), {
|
|
20668
|
-
hits: (node, pose) => nodeTest(node, pose),
|
|
20669
|
-
clipAdmits: (clip, _node, pose) => pathIntersectsRect(clip, poseBounds(pose))
|
|
20670
|
-
});
|
|
20671
|
-
}
|
|
20672
21059
|
var adapterFallbackIdCounter = 0;
|
|
20673
21060
|
function adapterFallbackId() {
|
|
20674
21061
|
return `n${(adapterFallbackIdCounter++).toString(36)}-${Math.random().toString(36).slice(2, 8)}`;
|
|
@@ -20704,6 +21091,7 @@ function sceneToAdapter(scene, options = {}) {
|
|
|
20704
21091
|
);
|
|
20705
21092
|
const composition = options.poseComposition;
|
|
20706
21093
|
const composes = composition !== void 0 && composition.closure !== "identity";
|
|
21094
|
+
const pickOpts = composition ? { poseComposition: composition } : {};
|
|
20707
21095
|
if (composes && options.cascadeContainerPose) {
|
|
20708
21096
|
throw new Error(
|
|
20709
21097
|
"sceneToAdapter: poseComposition and cascadeContainerPose contradict each other. Under a composing strategy a child's pose is already relative to its parent, so the cascade would move every descendant twice. Drop cascadeContainerPose."
|
|
@@ -20840,23 +21228,29 @@ function sceneToAdapter(scene, options = {}) {
|
|
|
20840
21228
|
// AreaSelectAdapter surface — included unconditionally so plain
|
|
20841
21229
|
// `useSelectTool(sceneToAdapter(scene, { selection }))` Just Works for the
|
|
20842
21230
|
// marquee gesture. `applyOps` (above) dispatches transiently when called
|
|
20843
|
-
// without a label, matching the AreaSelectAdapter contract
|
|
20844
|
-
// does an AABB-vs-AABB scan over `scene.renderOrder()`, reading bounds
|
|
20845
|
-
// through the pose descriptor.
|
|
21231
|
+
// without a label, matching the AreaSelectAdapter contract.
|
|
20846
21232
|
getSelection,
|
|
20847
21233
|
setSelection,
|
|
21234
|
+
// The live marquee's and lasso's own hit-tests. Containers come back:
|
|
21235
|
+
// this adapter's consumer has nothing to fold children into them.
|
|
20848
21236
|
hitTestArea(rect) {
|
|
20849
|
-
return
|
|
20850
|
-
|
|
20851
|
-
|
|
20852
|
-
|
|
21237
|
+
return hitTestArea(
|
|
21238
|
+
scene,
|
|
21239
|
+
rect,
|
|
21240
|
+
pickOpts,
|
|
21241
|
+
d,
|
|
21242
|
+
{ includeContainers: true }
|
|
21243
|
+
);
|
|
20853
21244
|
},
|
|
20854
21245
|
hitTestLasso(polygon, mode) {
|
|
20855
|
-
|
|
20856
|
-
|
|
20857
|
-
|
|
20858
|
-
|
|
20859
|
-
|
|
21246
|
+
return hitTestLassoPolygon(
|
|
21247
|
+
scene,
|
|
21248
|
+
polygon,
|
|
21249
|
+
mode,
|
|
21250
|
+
pickOpts,
|
|
21251
|
+
d,
|
|
21252
|
+
{ includeContainers: true }
|
|
21253
|
+
);
|
|
20860
21254
|
},
|
|
20861
21255
|
// commitInsert (gesture-time leaf insert) is opt-in: present only when
|
|
20862
21256
|
// `options.commitInsert` is. The full insertNode/removeNode mutators
|
|
@@ -21757,6 +22151,9 @@ function createScene(options) {
|
|
|
21757
22151
|
canUndo: () => raw.canUndo(),
|
|
21758
22152
|
canRedo: () => raw.canRedo(),
|
|
21759
22153
|
entries: () => raw.entries(),
|
|
22154
|
+
seal: () => raw.seal(),
|
|
22155
|
+
getVersion: () => raw.getVersion(),
|
|
22156
|
+
subscribe: (listener) => raw.subscribe(listener),
|
|
21760
22157
|
commit(label) {
|
|
21761
22158
|
raw.commit(label);
|
|
21762
22159
|
notify2();
|
|
@@ -23310,11 +23707,6 @@ function CanvasView(props) {
|
|
|
23310
23707
|
}, [registry2, effectiveView]);
|
|
23311
23708
|
return null;
|
|
23312
23709
|
}
|
|
23313
|
-
function ActionsProviderIfRoot({ children }) {
|
|
23314
|
-
const parent = useActionsRegistry();
|
|
23315
|
-
if (parent) return /* @__PURE__ */ jsx(ActionsScope, { children });
|
|
23316
|
-
return /* @__PURE__ */ jsx(ActionsProvider, { children });
|
|
23317
|
-
}
|
|
23318
23710
|
function contributionEntries(tools) {
|
|
23319
23711
|
return [...Object.values(tools.registry), ...tools.ambient];
|
|
23320
23712
|
}
|
|
@@ -23339,10 +23731,11 @@ function useKeyedInstall(items) {
|
|
|
23339
23731
|
function useContributionRoles(tools, api) {
|
|
23340
23732
|
const registry2 = useActionsRegistry();
|
|
23341
23733
|
const depRegistry = useOptionalDepRegistry();
|
|
23734
|
+
const { registry: toolRegistry, ambient } = tools;
|
|
23342
23735
|
useEffect(() => {
|
|
23343
23736
|
if (!registry2) return;
|
|
23344
23737
|
const unregisters = [];
|
|
23345
|
-
for (const entry of contributionEntries(
|
|
23738
|
+
for (const entry of contributionEntries({ registry: toolRegistry, ambient })) {
|
|
23346
23739
|
for (const action of entry.actions ?? []) {
|
|
23347
23740
|
unregisters.push(registry2.register(action));
|
|
23348
23741
|
}
|
|
@@ -23350,7 +23743,7 @@ function useContributionRoles(tools, api) {
|
|
|
23350
23743
|
return () => {
|
|
23351
23744
|
for (const u of unregisters) u();
|
|
23352
23745
|
};
|
|
23353
|
-
}, [registry2,
|
|
23746
|
+
}, [registry2, toolRegistry, ambient]);
|
|
23354
23747
|
const installs = /* @__PURE__ */ new Map();
|
|
23355
23748
|
for (const entry of contributionEntries(tools)) {
|
|
23356
23749
|
const deps = entry.deps;
|
|
@@ -23362,6 +23755,7 @@ function useContributionRoles(tools, api) {
|
|
|
23362
23755
|
}
|
|
23363
23756
|
}
|
|
23364
23757
|
useKeyedInstall(installs);
|
|
23758
|
+
useOffhandAction(contributionEntries(tools));
|
|
23365
23759
|
}
|
|
23366
23760
|
function registerDeps(depRegistry, deps) {
|
|
23367
23761
|
const unregisters = Object.keys(deps).map((name) => depRegistry.register(name, deps[name]));
|
|
@@ -23418,35 +23812,6 @@ function PointerPublisher({
|
|
|
23418
23812
|
}, [ctx, canvasRef, registry2]);
|
|
23419
23813
|
return null;
|
|
23420
23814
|
}
|
|
23421
|
-
function aabbOfPose(pose, descriptor = AUTO_POSE_DESCRIPTOR) {
|
|
23422
|
-
return descriptor.getBounds(pose);
|
|
23423
|
-
}
|
|
23424
|
-
var DEFAULT_PATH_STROKE_SLOP = 4;
|
|
23425
|
-
function poseContains(pose, wx, wy, tolerance, descriptor = AUTO_POSE_DESCRIPTOR) {
|
|
23426
|
-
if (isPathLike(pose)) {
|
|
23427
|
-
if (pointInPath(pose, wx, wy)) return true;
|
|
23428
|
-
return strokeHitTest(pose, wx, wy, tolerance ?? DEFAULT_PATH_STROKE_SLOP);
|
|
23429
|
-
}
|
|
23430
|
-
const b = aabbOfPose(pose, descriptor);
|
|
23431
|
-
const t = tolerance ?? 0;
|
|
23432
|
-
return wx >= b.x - t && wx <= b.x + b.width + t && wy >= b.y - t && wy <= b.y + b.height + t;
|
|
23433
|
-
}
|
|
23434
|
-
function poseContainsRotated(pose, wx, wy, tolerance, descriptor = AUTO_POSE_DESCRIPTOR) {
|
|
23435
|
-
const r = descriptor === AUTO_POSE_DESCRIPTOR ? poseRotationOf(pose) : rotationAboutCenter(pose, descriptor);
|
|
23436
|
-
if (r) {
|
|
23437
|
-
const [lx, ly] = applyToPoint(rotateAboutPoint(r.cx, r.cy, -r.rotation), wx, wy);
|
|
23438
|
-
return poseContains(pose, lx, ly, tolerance, descriptor);
|
|
23439
|
-
}
|
|
23440
|
-
return poseContains(pose, wx, wy, tolerance, descriptor);
|
|
23441
|
-
}
|
|
23442
|
-
function rotationAboutCenter(pose, descriptor) {
|
|
23443
|
-
const rotation = descriptor.getRotation?.(pose) ?? 0;
|
|
23444
|
-
if (!rotation) return null;
|
|
23445
|
-
const b = descriptor.getBounds(pose);
|
|
23446
|
-
return { cx: b.x + b.width / 2, cy: b.y + b.height / 2, rotation };
|
|
23447
|
-
}
|
|
23448
|
-
|
|
23449
|
-
// src/canvas/SceneCanvas/useSceneSelectTool.ts
|
|
23450
23815
|
var DEFAULT_PICK_TOLERANCE_PX = 4;
|
|
23451
23816
|
function useSceneSelectTool(args) {
|
|
23452
23817
|
const { scene, adapter, geometry, selectTool: opts, getView, alphaOf, layerIsPainted } = args;
|
|
@@ -23520,7 +23885,6 @@ function useSceneSelectTool(args) {
|
|
|
23520
23885
|
}, [scene, adapter, boundsOfProp, d]);
|
|
23521
23886
|
const selectTool = useSelectTool(adapter, {
|
|
23522
23887
|
pickEvery: wiredHitBody,
|
|
23523
|
-
move: wiredMoveOptions,
|
|
23524
23888
|
...opts?.pickBest ? { pickBest: opts.pickBest } : {},
|
|
23525
23889
|
...opts?.extendClickLocked ? { extendClickLocked: opts.extendClickLocked } : {}
|
|
23526
23890
|
});
|
|
@@ -23534,8 +23898,100 @@ function useSceneSelectTool(args) {
|
|
|
23534
23898
|
selectTool,
|
|
23535
23899
|
pickEvery: wiredHitBody,
|
|
23536
23900
|
pickBest: wiredPickBest,
|
|
23537
|
-
boundsOf: wiredBoundsOf
|
|
23538
|
-
|
|
23901
|
+
boundsOf: wiredBoundsOf,
|
|
23902
|
+
moveOptions: wiredMoveOptions
|
|
23903
|
+
};
|
|
23904
|
+
}
|
|
23905
|
+
|
|
23906
|
+
// src/canvas/SceneCanvas/features.ts
|
|
23907
|
+
var SCENE_CANVAS_FEATURES = [
|
|
23908
|
+
"view",
|
|
23909
|
+
"pick",
|
|
23910
|
+
"move",
|
|
23911
|
+
"transform",
|
|
23912
|
+
"edit",
|
|
23913
|
+
"arrange",
|
|
23914
|
+
"paths",
|
|
23915
|
+
"ingest",
|
|
23916
|
+
"draw"
|
|
23917
|
+
];
|
|
23918
|
+
var BASE_FEATURES = SCENE_CANVAS_FEATURES.filter((f) => f !== "draw");
|
|
23919
|
+
var FEATURE_ACTION_IDS = {
|
|
23920
|
+
view: ["viewport.dragPan", "viewport.pinchZoom"],
|
|
23921
|
+
pick: ["areaSelect", "clearSelection", "lassoSelect"],
|
|
23922
|
+
move: ["move", "clone"],
|
|
23923
|
+
transform: ["resize", "rotate"],
|
|
23924
|
+
edit: [
|
|
23925
|
+
"escape",
|
|
23926
|
+
"cancelGesture",
|
|
23927
|
+
"selectAll",
|
|
23928
|
+
"duplicate",
|
|
23929
|
+
"delete",
|
|
23930
|
+
"group",
|
|
23931
|
+
"ungroup",
|
|
23932
|
+
"undo",
|
|
23933
|
+
"redo",
|
|
23934
|
+
"nudge.up",
|
|
23935
|
+
"nudge.down",
|
|
23936
|
+
"nudge.left",
|
|
23937
|
+
"nudge.right",
|
|
23938
|
+
"clipboard.cut",
|
|
23939
|
+
"clipboard.copy",
|
|
23940
|
+
"clipboard.paste",
|
|
23941
|
+
"setFill",
|
|
23942
|
+
"setStroke",
|
|
23943
|
+
"setFillOpacity",
|
|
23944
|
+
"setStrokeOpacity"
|
|
23945
|
+
],
|
|
23946
|
+
arrange: [
|
|
23947
|
+
"flip",
|
|
23948
|
+
"reorder.forward",
|
|
23949
|
+
"reorder.backward",
|
|
23950
|
+
"align.left",
|
|
23951
|
+
"align.centerX",
|
|
23952
|
+
"align.right",
|
|
23953
|
+
"align.top",
|
|
23954
|
+
"align.centerY",
|
|
23955
|
+
"align.bottom",
|
|
23956
|
+
"distribute.horizontal",
|
|
23957
|
+
"distribute.vertical"
|
|
23958
|
+
],
|
|
23959
|
+
paths: [
|
|
23960
|
+
"pathfinder.union",
|
|
23961
|
+
"pathfinder.subtract",
|
|
23962
|
+
"pathfinder.intersect",
|
|
23963
|
+
"pathfinder.exclude",
|
|
23964
|
+
"pathfinder.divide",
|
|
23965
|
+
"pathfinder.crop",
|
|
23966
|
+
"editAnchors",
|
|
23967
|
+
"enterPathEdit",
|
|
23968
|
+
"exitPathEdit",
|
|
23969
|
+
"insertPathAnchor",
|
|
23970
|
+
"nudgeAnchors.up",
|
|
23971
|
+
"nudgeAnchors.down",
|
|
23972
|
+
"nudgeAnchors.left",
|
|
23973
|
+
"nudgeAnchors.right",
|
|
23974
|
+
"deleteAnchors",
|
|
23975
|
+
"cutPathAtAnchor",
|
|
23976
|
+
"marqueeAnchors",
|
|
23977
|
+
"selectAnchor"
|
|
23978
|
+
],
|
|
23979
|
+
ingest: ["ingest"]
|
|
23980
|
+
};
|
|
23981
|
+
var TOOL_DRIVEN_ACTION_IDS = ["insert", "insert.adjustRotation", "enterTextEdit"];
|
|
23982
|
+
function resolveFeatures(features, opts = {}) {
|
|
23983
|
+
const out = /* @__PURE__ */ new Set();
|
|
23984
|
+
for (const f of features ?? []) {
|
|
23985
|
+
if (f === "draw") for (const b of BASE_FEATURES) out.add(b);
|
|
23986
|
+
else out.add(f);
|
|
23987
|
+
}
|
|
23988
|
+
if (opts.viewport) out.add("view");
|
|
23989
|
+
return out;
|
|
23990
|
+
}
|
|
23991
|
+
function featureActionIds(features) {
|
|
23992
|
+
const ids = /* @__PURE__ */ new Set();
|
|
23993
|
+
for (const f of features) for (const id of FEATURE_ACTION_IDS[f]) ids.add(id);
|
|
23994
|
+
return ids;
|
|
23539
23995
|
}
|
|
23540
23996
|
|
|
23541
23997
|
// src/canvas/drawEnvelope.ts
|
|
@@ -24353,101 +24809,15 @@ function useBuiltinShapeTools(args) {
|
|
|
24353
24809
|
addNode: (carrier) => {
|
|
24354
24810
|
const node = makePenLeaf(carrier);
|
|
24355
24811
|
adapter.insertNode(node);
|
|
24356
|
-
return String(node.id);
|
|
24357
|
-
},
|
|
24358
|
-
makeNode: (carrier) => makePenLeaf(carrier),
|
|
24359
|
-
setSelection: (ids) => adapter.setSelection(ids)
|
|
24360
|
-
}
|
|
24361
|
-
});
|
|
24362
|
-
const lasso = useLassoTool(adapter, options?.lasso ?? {});
|
|
24363
|
-
const text = useTextTool();
|
|
24364
|
-
return { rect, ellipse, line, polygon, star, pen, pencil, lasso, text };
|
|
24365
|
-
}
|
|
24366
|
-
function DepRegistryProviderIfRoot({ children }) {
|
|
24367
|
-
const parent = useOptionalDepRegistry();
|
|
24368
|
-
if (parent) return /* @__PURE__ */ jsx(Fragment, { children });
|
|
24369
|
-
return /* @__PURE__ */ jsx(DepRegistryProvider, { children });
|
|
24370
|
-
}
|
|
24371
|
-
function regionPickOptions(view, alphaOf, poseComposition) {
|
|
24372
|
-
return {
|
|
24373
|
-
...poseComposition ? { poseComposition } : {},
|
|
24374
|
-
...alphaOf ? { alphaOf } : {},
|
|
24375
|
-
...view?.layerIsPainted ? { layerIsPainted: (layer) => view.layerIsPainted(layer) } : {}
|
|
24376
|
-
};
|
|
24377
|
-
}
|
|
24378
|
-
function hitTestArea(scene, bounds, opts, descriptor = AUTO_POSE_DESCRIPTOR) {
|
|
24379
|
-
const { x, y, width: w, height: h } = bounds;
|
|
24380
|
-
const area = Array.from(rectToContour(x, y, w, h));
|
|
24381
|
-
return hitTestAreaPolygon(scene, area, { x, y, width: w, height: h }, true, opts, descriptor);
|
|
24382
|
-
}
|
|
24383
|
-
function hitTestAreaPolygon(scene, area, areaBounds, areaIsRect = false, opts, descriptor = AUTO_POSE_DESCRIPTOR) {
|
|
24384
|
-
const ab = areaBounds ?? boundsOf(area);
|
|
24385
|
-
if (!ab) return [];
|
|
24386
|
-
return pickWalk(scenePickSource(scene, opts), {
|
|
24387
|
-
// A marquee that returns a container *and* its children selects the same
|
|
24388
|
-
// ink twice; the container comes back through the selection's own
|
|
24389
|
-
// parent-folding instead.
|
|
24390
|
-
includeContainers: false,
|
|
24391
|
-
clipAdmits: (clip, node, pose) => {
|
|
24392
|
-
const g = poseDescriptorForNode(descriptor, node);
|
|
24393
|
-
return pathIntersectsRect(clip, visualBoundsViaDescriptor(pose, g)) && pathIntersectsRect(clip, ab);
|
|
24394
|
-
},
|
|
24395
|
-
hits: (node, pose) => {
|
|
24396
|
-
const g = poseDescriptorForNode(descriptor, node);
|
|
24397
|
-
const silhouette = pose !== null && typeof pose === "object" && pose.kind === "polygon";
|
|
24398
|
-
const b = silhouette ? nodeMemo(node, "aabb", pose, () => aabbOfPose(pose, g)) : visualBoundsViaDescriptor(pose, g);
|
|
24399
|
-
if (!Number.isFinite(b.x) || !Number.isFinite(b.y) || !Number.isFinite(b.width) || !Number.isFinite(b.height)) {
|
|
24400
|
-
return false;
|
|
24401
|
-
}
|
|
24402
|
-
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) {
|
|
24403
|
-
return false;
|
|
24404
|
-
}
|
|
24405
|
-
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) {
|
|
24406
|
-
return true;
|
|
24407
|
-
}
|
|
24408
|
-
if (silhouette) {
|
|
24409
|
-
return silhouetteOverlapsArea(pose.coords, area);
|
|
24410
|
-
}
|
|
24411
|
-
const drawn = findShapeSilhouette(node, pose);
|
|
24412
|
-
if (drawn?.kind === "polygon") {
|
|
24413
|
-
return silhouetteOverlapsArea(drawn.coords, area);
|
|
24414
|
-
}
|
|
24415
|
-
return true;
|
|
24812
|
+
return String(node.id);
|
|
24813
|
+
},
|
|
24814
|
+
makeNode: (carrier) => makePenLeaf(carrier),
|
|
24815
|
+
setSelection: (ids) => adapter.setSelection(ids)
|
|
24416
24816
|
}
|
|
24417
24817
|
});
|
|
24418
|
-
}
|
|
24419
|
-
|
|
24420
|
-
|
|
24421
|
-
const na = area.length >> 1;
|
|
24422
|
-
if (ns < 1 || na < 3) return false;
|
|
24423
|
-
for (let i = 0; i < ns; i++) {
|
|
24424
|
-
if (pointInPolygon(area, sil[i * 2], sil[i * 2 + 1])) return true;
|
|
24425
|
-
}
|
|
24426
|
-
for (let i = 0; i < na; i++) {
|
|
24427
|
-
if (pointInPolygon(sil, area[i * 2], area[i * 2 + 1])) return true;
|
|
24428
|
-
}
|
|
24429
|
-
for (let i = 0, j = ns - 1; i < ns; j = i++) {
|
|
24430
|
-
const ax = sil[j * 2], ay = sil[j * 2 + 1];
|
|
24431
|
-
const bx = sil[i * 2], by = sil[i * 2 + 1];
|
|
24432
|
-
for (let k = 0, l = na - 1; k < na; l = k++) {
|
|
24433
|
-
const cx = area[l * 2], cy = area[l * 2 + 1];
|
|
24434
|
-
const dx = area[k * 2], dy = area[k * 2 + 1];
|
|
24435
|
-
if (segmentsCross(ax, ay, bx, by, cx, cy, dx, dy)) return true;
|
|
24436
|
-
}
|
|
24437
|
-
}
|
|
24438
|
-
return false;
|
|
24439
|
-
}
|
|
24440
|
-
function boundsOf(coords) {
|
|
24441
|
-
if (coords.length < 2) return null;
|
|
24442
|
-
let minX = Infinity, minY = Infinity, maxX = -Infinity, maxY = -Infinity;
|
|
24443
|
-
for (let i = 0; i + 1 < coords.length; i += 2) {
|
|
24444
|
-
const x = coords[i], y = coords[i + 1];
|
|
24445
|
-
if (x < minX) minX = x;
|
|
24446
|
-
if (y < minY) minY = y;
|
|
24447
|
-
if (x > maxX) maxX = x;
|
|
24448
|
-
if (y > maxY) maxY = y;
|
|
24449
|
-
}
|
|
24450
|
-
return { x: minX, y: minY, width: maxX - minX, height: maxY - minY };
|
|
24818
|
+
const lasso = useLassoTool(adapter, options?.lasso ?? {});
|
|
24819
|
+
const text = useTextTool();
|
|
24820
|
+
return { rect, ellipse, line, polygon, star, pen, pencil, lasso, text };
|
|
24451
24821
|
}
|
|
24452
24822
|
function useViewDepSource(currentViewRef, onViewChange, recenter, hostSize, animation, decay, layerIsPainted) {
|
|
24453
24823
|
const wiring = useRef({
|
|
@@ -24543,6 +24913,7 @@ function useLassoSelectDepSource(scene, selection, descriptor, poseComposition,
|
|
|
24543
24913
|
const d = descriptorRef.current;
|
|
24544
24914
|
const a = alphaOfRef.current;
|
|
24545
24915
|
return {
|
|
24916
|
+
hitTestLasso: (polygon, mode, view) => hitTestLassoPolygon(sc, polygon, mode, regionPickOptions(view, a, poseComposition), d),
|
|
24546
24917
|
hitTestArea: (bounds, view) => hitTestArea(sc, bounds, regionPickOptions(view, a, poseComposition), d),
|
|
24547
24918
|
getSelection: () => s.current,
|
|
24548
24919
|
setSelection: (ids) => s.set(ids)
|
|
@@ -24765,7 +25136,7 @@ function chordLengthParam(samples) {
|
|
|
24765
25136
|
ts[0] = 0;
|
|
24766
25137
|
let total = 0;
|
|
24767
25138
|
for (let i = 1; i < n; i++) {
|
|
24768
|
-
total +=
|
|
25139
|
+
total += dist(samples[i - 1], samples[i]);
|
|
24769
25140
|
ts[i] = total;
|
|
24770
25141
|
}
|
|
24771
25142
|
if (total === 0) return null;
|
|
@@ -24798,13 +25169,13 @@ function solveLS(samples, ts, a, e, tStart, tEnd) {
|
|
|
24798
25169
|
let alpha1;
|
|
24799
25170
|
let alpha2;
|
|
24800
25171
|
if (Math.abs(det) < 1e-12) {
|
|
24801
|
-
const chord =
|
|
25172
|
+
const chord = dist(a, e);
|
|
24802
25173
|
alpha1 = alpha2 = chord / 3;
|
|
24803
25174
|
} else {
|
|
24804
25175
|
alpha1 = (c22 * x1 - c12 * x2) / det;
|
|
24805
25176
|
alpha2 = (c11 * x2 - c12 * x1) / det;
|
|
24806
25177
|
if (alpha1 < 1e-6 || alpha2 < 1e-6) {
|
|
24807
|
-
const chord =
|
|
25178
|
+
const chord = dist(a, e);
|
|
24808
25179
|
alpha1 = alpha2 = chord / 3;
|
|
24809
25180
|
}
|
|
24810
25181
|
}
|
|
@@ -24839,7 +25210,7 @@ function newtonRefineT(p, t, p0, p1, p2, p3) {
|
|
|
24839
25210
|
function sub(a, b) {
|
|
24840
25211
|
return { x: a.x - b.x, y: a.y - b.y };
|
|
24841
25212
|
}
|
|
24842
|
-
function
|
|
25213
|
+
function dist(a, b) {
|
|
24843
25214
|
return Math.hypot(a.x - b.x, a.y - b.y);
|
|
24844
25215
|
}
|
|
24845
25216
|
function unit(v) {
|
|
@@ -25233,7 +25604,7 @@ function openFilePicker(opts = {}) {
|
|
|
25233
25604
|
input.click();
|
|
25234
25605
|
});
|
|
25235
25606
|
}
|
|
25236
|
-
function useActionsPropResolver(actions) {
|
|
25607
|
+
function useActionsPropResolver(actions, rev) {
|
|
25237
25608
|
const reg = useActionsRegistry();
|
|
25238
25609
|
const actionsRef = useRef(actions);
|
|
25239
25610
|
actionsRef.current = actions;
|
|
@@ -25280,7 +25651,7 @@ function useActionsPropResolver(actions) {
|
|
|
25280
25651
|
return () => {
|
|
25281
25652
|
for (const u of unregisters) u();
|
|
25282
25653
|
};
|
|
25283
|
-
}, [reg, actions]);
|
|
25654
|
+
}, [reg, actions, rev]);
|
|
25284
25655
|
}
|
|
25285
25656
|
function useViewportActions(args) {
|
|
25286
25657
|
const { pan, zoom, pinchZoom } = args;
|
|
@@ -25643,14 +26014,7 @@ function mergeLayersWithDefaults(user, targetScale = 1) {
|
|
|
25643
26014
|
return result;
|
|
25644
26015
|
}
|
|
25645
26016
|
var NON_SHAPE_BUILTIN_TOOLS = ["select", "hand"];
|
|
25646
|
-
var
|
|
25647
|
-
minimal: ["select", "hand"],
|
|
25648
|
-
// No `pencil`: freehand is a specialist instrument, not part of the
|
|
25649
|
-
// everyday shape-drawing set. It stays in `exhaustive`, which means
|
|
25650
|
-
// everything.
|
|
25651
|
-
standard: ["select", "hand", "rect", "ellipse", "line"],
|
|
25652
|
-
exhaustive: [...NON_SHAPE_BUILTIN_TOOLS, ...KIT_SHAPE_KINDS]
|
|
25653
|
-
};
|
|
26017
|
+
var BUILTIN_TOOL_IDS = [...NON_SHAPE_BUILTIN_TOOLS, ...KIT_SHAPE_KINDS];
|
|
25654
26018
|
var EMPTY_ID_SET = /* @__PURE__ */ new Set();
|
|
25655
26019
|
var EMPTY_ANCHOR_SELECTION2 = /* @__PURE__ */ new Set();
|
|
25656
26020
|
function isToolsApi(tools) {
|
|
@@ -25674,10 +26038,10 @@ function SceneCanvasInner(props, ref) {
|
|
|
25674
26038
|
selectionOptions,
|
|
25675
26039
|
selectionMode = "single",
|
|
25676
26040
|
tools: toolsProp,
|
|
26041
|
+
features,
|
|
25677
26042
|
enableKeybindings = true,
|
|
25678
26043
|
enableGestureDispatcher = true,
|
|
25679
26044
|
onToolsCreated,
|
|
25680
|
-
toolBundle,
|
|
25681
26045
|
defaultTools,
|
|
25682
26046
|
toolOptions,
|
|
25683
26047
|
initialActiveTool,
|
|
@@ -25703,7 +26067,7 @@ function SceneCanvasInner(props, ref) {
|
|
|
25703
26067
|
isPointerInteractive,
|
|
25704
26068
|
onDoubleClick,
|
|
25705
26069
|
chromeVisibility,
|
|
25706
|
-
|
|
26070
|
+
modes,
|
|
25707
26071
|
getFocused: getFocusedProp,
|
|
25708
26072
|
device,
|
|
25709
26073
|
...rest
|
|
@@ -25719,7 +26083,12 @@ function SceneCanvasInner(props, ref) {
|
|
|
25719
26083
|
() => isSerialized(sceneInput) ? sceneFromJSON(sceneInput, {}) : null
|
|
25720
26084
|
);
|
|
25721
26085
|
const scene = bakedScene ?? sceneInput;
|
|
25722
|
-
const { view: viewProp, onViewChange: onViewChangeProp, defaultView, ...restProps } = rest;
|
|
26086
|
+
const { view: viewProp, onViewChange: onViewChangeProp, defaultView, redrawOn: redrawOnProp, ...restProps } = rest;
|
|
26087
|
+
const getActiveMode = useMemo(() => modes ? getActiveModeFor(modes) : void 0, [modes]);
|
|
26088
|
+
const redrawOn = useMemo(
|
|
26089
|
+
() => modes ? [...redrawOnProp ?? [], modes] : redrawOnProp,
|
|
26090
|
+
[modes, redrawOnProp]
|
|
26091
|
+
);
|
|
25723
26092
|
const internalCanvasRef = useRef(null);
|
|
25724
26093
|
const canvasApiRef = useRef(null);
|
|
25725
26094
|
const [canvasReady, setCanvasReady] = useState(false);
|
|
@@ -25921,7 +26290,13 @@ function SceneCanvasInner(props, ref) {
|
|
|
25921
26290
|
poseComposition,
|
|
25922
26291
|
cascadeContainerPose: !framed
|
|
25923
26292
|
});
|
|
25924
|
-
const {
|
|
26293
|
+
const {
|
|
26294
|
+
selectTool: internalSelect,
|
|
26295
|
+
pickEvery: internalPickEvery,
|
|
26296
|
+
pickBest: internalPickBest,
|
|
26297
|
+
boundsOf: internalBoundsOf,
|
|
26298
|
+
moveOptions: internalMoveOptions
|
|
26299
|
+
} = useSceneSelectTool({
|
|
25925
26300
|
scene,
|
|
25926
26301
|
adapter,
|
|
25927
26302
|
poseDescriptor: descriptor,
|
|
@@ -25953,7 +26328,13 @@ function SceneCanvasInner(props, ref) {
|
|
|
25953
26328
|
return hit;
|
|
25954
26329
|
};
|
|
25955
26330
|
}, [adapter, internalPickEvery, isPointerInteractive, kindClassifier]);
|
|
25956
|
-
const
|
|
26331
|
+
const featuresKey = (features ?? []).join("|");
|
|
26332
|
+
const hasViewport = viewport !== void 0;
|
|
26333
|
+
const enabled = useMemo(
|
|
26334
|
+
() => resolveFeatures(features, { viewport: hasViewport }),
|
|
26335
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
26336
|
+
[featuresKey, hasViewport]
|
|
26337
|
+
);
|
|
25957
26338
|
const inertiaEnabled = !!viewport?.inertia;
|
|
25958
26339
|
const inertiaObj = typeof viewport?.inertia === "object" ? viewport.inertia : void 0;
|
|
25959
26340
|
const handToolInertia = inertiaEnabled ? {
|
|
@@ -25963,8 +26344,11 @@ function SceneCanvasInner(props, ref) {
|
|
|
25963
26344
|
bounds: inertiaObj?.bounds
|
|
25964
26345
|
} : void 0;
|
|
25965
26346
|
const handTool = useHandTool(handToolInertia ? { inertia: handToolInertia } : {});
|
|
25966
|
-
const
|
|
25967
|
-
|
|
26347
|
+
const baseRequestedTools = [
|
|
26348
|
+
...defaultTools ?? [],
|
|
26349
|
+
...enabled.has("pick") ? ["select"] : [],
|
|
26350
|
+
...enabled.has("view") ? ["hand"] : []
|
|
26351
|
+
];
|
|
25968
26352
|
const KNOWN_BUILTIN_IDS = /* @__PURE__ */ new Set([
|
|
25969
26353
|
...NON_SHAPE_BUILTIN_TOOLS,
|
|
25970
26354
|
...KIT_SHAPE_KINDS
|
|
@@ -25988,10 +26372,10 @@ function SceneCanvasInner(props, ref) {
|
|
|
25988
26372
|
}
|
|
25989
26373
|
const wants = (id) => baseRequestedTools.includes(id) || trueIds.has(id);
|
|
25990
26374
|
const shapeTools = useBuiltinShapeTools({ scene, adapter, options: toolOptions });
|
|
25991
|
-
const mergedAmbient =
|
|
26375
|
+
const mergedAmbient = ambient ?? [];
|
|
25992
26376
|
const internalRegistry = {};
|
|
25993
26377
|
if (wants("select")) internalRegistry.select = internalSelect;
|
|
25994
|
-
if (wants("hand")
|
|
26378
|
+
if (wants("hand")) internalRegistry.hand = handTool;
|
|
25995
26379
|
if (wants("rect")) internalRegistry.rect = shapeTools.rect;
|
|
25996
26380
|
if (wants("ellipse")) internalRegistry.ellipse = shapeTools.ellipse;
|
|
25997
26381
|
if (wants("line")) internalRegistry.line = shapeTools.line;
|
|
@@ -26018,16 +26402,17 @@ function SceneCanvasInner(props, ref) {
|
|
|
26018
26402
|
}
|
|
26019
26403
|
const toolsTakeover = toolsProp && isToolsApi(toolsProp) ? toolsProp : null;
|
|
26020
26404
|
const internalTools = useTools({
|
|
26021
|
-
active: initialActiveTool ?? "select",
|
|
26405
|
+
active: initialActiveTool ?? ("select" in internalRegistry ? "select" : null),
|
|
26022
26406
|
registry: internalRegistry,
|
|
26023
|
-
...mergedAmbient.length ? { ambient: mergedAmbient } : {}
|
|
26407
|
+
...mergedAmbient.length ? { ambient: mergedAmbient } : {},
|
|
26408
|
+
...modes ? { modes } : {}
|
|
26024
26409
|
});
|
|
26025
|
-
const
|
|
26026
|
-
|
|
26410
|
+
const liveToolsRef = useRef(null);
|
|
26411
|
+
liveToolsRef.current = toolsTakeover ?? internalTools;
|
|
26027
26412
|
const isToolEligible = useCallback((toolId) => {
|
|
26028
26413
|
const getMode = getActiveModeRef.current;
|
|
26029
26414
|
if (!getMode) return true;
|
|
26030
|
-
const registry2 =
|
|
26415
|
+
const registry2 = liveToolsRef.current?.registry;
|
|
26031
26416
|
const caps = registry2?.[toolId]?.eligibility.capabilities ?? [];
|
|
26032
26417
|
if (caps.length === 0) return false;
|
|
26033
26418
|
const allowed = getMode().allowedCapabilities;
|
|
@@ -26035,6 +26420,27 @@ function SceneCanvasInner(props, ref) {
|
|
|
26035
26420
|
return false;
|
|
26036
26421
|
}, []);
|
|
26037
26422
|
const tools = toolsTakeover ?? internalTools;
|
|
26423
|
+
const selectionMoveOptions = useMemo(
|
|
26424
|
+
() => ({ move: internalMoveOptions }),
|
|
26425
|
+
[internalMoveOptions]
|
|
26426
|
+
);
|
|
26427
|
+
const rotateOptions = selectToolOpts?.rotate || void 0;
|
|
26428
|
+
const featureContributions = useMemo(() => [
|
|
26429
|
+
...enabled.has("transform") ? [selectionTransformContribution({ rotate: rotateOptions })] : [],
|
|
26430
|
+
...enabled.has("move") ? [selectionMoveContribution(selectionMoveOptions)] : []
|
|
26431
|
+
], [enabled, selectionMoveOptions, rotateOptions]);
|
|
26432
|
+
const standardActionsExclude = useMemo(() => {
|
|
26433
|
+
const include = featureActionIds(enabled);
|
|
26434
|
+
const bound = [
|
|
26435
|
+
...Object.values(tools.registry),
|
|
26436
|
+
...tools.ambient,
|
|
26437
|
+
...featureContributions
|
|
26438
|
+
];
|
|
26439
|
+
for (const entry of bound) {
|
|
26440
|
+
for (const b of entry.bindings ?? []) include.add(b.actionId);
|
|
26441
|
+
}
|
|
26442
|
+
return KIT_STANDARD_ACTION_IDS.filter((id) => !include.has(id));
|
|
26443
|
+
}, [enabled, tools, featureContributions]);
|
|
26038
26444
|
const onToolsCreatedRef = useRef(onToolsCreated);
|
|
26039
26445
|
onToolsCreatedRef.current = onToolsCreated;
|
|
26040
26446
|
useEffect(() => {
|
|
@@ -26123,6 +26529,11 @@ function SceneCanvasInner(props, ref) {
|
|
|
26123
26529
|
getFocusedPropRef.current = getFocusedProp;
|
|
26124
26530
|
const effectiveChromeVisibility = useMemo(() => {
|
|
26125
26531
|
const defaults = {};
|
|
26532
|
+
if (!enabled.has("pick")) defaults["selection.outline"] = never;
|
|
26533
|
+
if (!enabled.has("transform")) {
|
|
26534
|
+
defaults["selection.resize-handles"] = never;
|
|
26535
|
+
defaults["selection.rotation-handle"] = never;
|
|
26536
|
+
}
|
|
26126
26537
|
if (selectionMode === "none") {
|
|
26127
26538
|
defaults["action.marquee"] = never;
|
|
26128
26539
|
defaults["action.lasso"] = never;
|
|
@@ -26130,7 +26541,7 @@ function SceneCanvasInner(props, ref) {
|
|
|
26130
26541
|
if (selectToolOpts?.rotate === false) defaults["selection.rotation-handle"] = never;
|
|
26131
26542
|
if (Object.keys(defaults).length === 0) return chromeVisibility;
|
|
26132
26543
|
return { ...defaults, ...chromeVisibility };
|
|
26133
|
-
}, [chromeVisibility, selectionMode, selectToolOpts?.rotate]);
|
|
26544
|
+
}, [chromeVisibility, selectionMode, selectToolOpts?.rotate, enabled]);
|
|
26134
26545
|
const chromeVisibilityRef = useRef(effectiveChromeVisibility);
|
|
26135
26546
|
chromeVisibilityRef.current = effectiveChromeVisibility;
|
|
26136
26547
|
const getActiveModeRef = useRef(getActiveMode);
|
|
@@ -26188,13 +26599,10 @@ function SceneCanvasInner(props, ref) {
|
|
|
26188
26599
|
() => chromeCaps.isVisible(currentRuleInputs()),
|
|
26189
26600
|
[chromeCaps, currentRuleInputs]
|
|
26190
26601
|
);
|
|
26602
|
+
const wantsPen = wants("pen");
|
|
26191
26603
|
const penPreviewLayer = useMemo(
|
|
26192
|
-
() =>
|
|
26193
|
-
|
|
26194
|
-
// that memoizes via defineTool). `wants('pen')` is recomputed each render
|
|
26195
|
-
// from `baseRequestedTools` + patch-form `true` entries — capture both.
|
|
26196
|
-
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
26197
|
-
[shapeTools.pen, baseRequestedTools, trueIds]
|
|
26604
|
+
() => wantsPen ? createPenPreviewLayer({ penTool: shapeTools.pen }) : null,
|
|
26605
|
+
[shapeTools.pen, wantsPen]
|
|
26198
26606
|
);
|
|
26199
26607
|
useEffect(() => {
|
|
26200
26608
|
canvasApiRef.current?.requestRedraw?.();
|
|
@@ -26396,12 +26804,12 @@ function SceneCanvasInner(props, ref) {
|
|
|
26396
26804
|
onViewChange: notifyViewChange,
|
|
26397
26805
|
shaders,
|
|
26398
26806
|
flattenTolerance,
|
|
26807
|
+
...redrawOn ? { redrawOn } : {},
|
|
26399
26808
|
...restProps
|
|
26400
26809
|
}
|
|
26401
26810
|
);
|
|
26402
26811
|
const testHookSceneRef = useRef(scene);
|
|
26403
26812
|
const testHookSelectionRef = useRef(selection);
|
|
26404
|
-
const testHookActiveToolRef = useRef(null);
|
|
26405
26813
|
testHookSceneRef.current = scene;
|
|
26406
26814
|
testHookSelectionRef.current = selection;
|
|
26407
26815
|
const testHookRef = useRef(null);
|
|
@@ -26411,12 +26819,12 @@ function SceneCanvasInner(props, ref) {
|
|
|
26411
26819
|
getScene: () => testHookSceneRef.current,
|
|
26412
26820
|
getSelectionIds: () => testHookSelectionRef.current?.current ?? [],
|
|
26413
26821
|
getView: () => currentViewRef.current,
|
|
26414
|
-
getActiveToolId: () =>
|
|
26822
|
+
getActiveToolId: () => liveToolsRef.current?.active ?? null
|
|
26415
26823
|
});
|
|
26416
26824
|
testHookRef.current?._markReady();
|
|
26417
26825
|
}
|
|
26418
26826
|
}, []);
|
|
26419
|
-
return /* @__PURE__ */ jsx(DeviceProfileProvider, { value: device, children: /* @__PURE__ */ jsx(ViewInputsProvider, { value: viewInputs, children: /* @__PURE__ */ jsx(
|
|
26827
|
+
return /* @__PURE__ */ jsx(DeviceProfileProvider, { value: device, children: /* @__PURE__ */ jsx(ViewInputsProvider, { value: viewInputs, children: /* @__PURE__ */ jsx(Fragment, { children: /* @__PURE__ */ jsx(PointerProviderIfRoot, { children: /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
26420
26828
|
canvas,
|
|
26421
26829
|
/* @__PURE__ */ jsx(PointerPublisher, { canvasRef: internalCanvasRef }),
|
|
26422
26830
|
/* @__PURE__ */ jsx(
|
|
@@ -26427,6 +26835,7 @@ function SceneCanvasInner(props, ref) {
|
|
|
26427
26835
|
adapter,
|
|
26428
26836
|
actionDefaults,
|
|
26429
26837
|
actions: resolvedActions,
|
|
26838
|
+
excludeActions: standardActionsExclude,
|
|
26430
26839
|
currentViewRef,
|
|
26431
26840
|
onViewChange: handleViewChange,
|
|
26432
26841
|
resizeOptions: selectToolOpts?.resize,
|
|
@@ -26437,9 +26846,9 @@ function SceneCanvasInner(props, ref) {
|
|
|
26437
26846
|
pickEvery: internalPickEvery,
|
|
26438
26847
|
layerIsPainted: viewLayerGate,
|
|
26439
26848
|
alphaOf: alphaFor ? composedAlphaFor : void 0,
|
|
26440
|
-
viewportPanEnabled: viewport?.pan ?? true,
|
|
26441
|
-
viewportZoom: resolvedViewportZoom,
|
|
26442
|
-
viewportPinchZoom: viewport?.pinchZoom ?? true,
|
|
26849
|
+
viewportPanEnabled: enabled.has("view") ? viewport?.pan ?? true : false,
|
|
26850
|
+
viewportZoom: enabled.has("view") ? resolvedViewportZoom : false,
|
|
26851
|
+
viewportPinchZoom: enabled.has("view") ? viewport?.pinchZoom ?? true : false,
|
|
26443
26852
|
viewportRecenter: viewport?.recenter,
|
|
26444
26853
|
viewAnimation,
|
|
26445
26854
|
editAnchorsExternalState,
|
|
@@ -26462,6 +26871,7 @@ function SceneCanvasInner(props, ref) {
|
|
|
26462
26871
|
canvasRef: internalCanvasRef,
|
|
26463
26872
|
canvasApiRef,
|
|
26464
26873
|
tools,
|
|
26874
|
+
contributions: featureContributions,
|
|
26465
26875
|
enabled: enableGestureDispatcher,
|
|
26466
26876
|
keyboard: enableKeybindings,
|
|
26467
26877
|
selectionRef,
|
|
@@ -26516,6 +26926,7 @@ function GestureDispatcherMounter({
|
|
|
26516
26926
|
canvasRef,
|
|
26517
26927
|
canvasApiRef,
|
|
26518
26928
|
tools,
|
|
26929
|
+
contributions,
|
|
26519
26930
|
enabled,
|
|
26520
26931
|
keyboard,
|
|
26521
26932
|
selectionRef,
|
|
@@ -26534,14 +26945,15 @@ function GestureDispatcherMounter({
|
|
|
26534
26945
|
const registry2 = useActionsRegistry();
|
|
26535
26946
|
const depRegistry = useDepRegistry();
|
|
26536
26947
|
const viewRegistry = useOptionalViewRegistry();
|
|
26537
|
-
const
|
|
26948
|
+
const entriesById = useMemo(() => {
|
|
26538
26949
|
const m = /* @__PURE__ */ new Map();
|
|
26539
26950
|
for (const [id, tool] of Object.entries(tools.registry)) {
|
|
26540
26951
|
m.set(id, tool);
|
|
26541
26952
|
}
|
|
26542
|
-
for (const
|
|
26953
|
+
for (const entry of contributions) m.set(entry.id, entry);
|
|
26954
|
+
for (const entry of tools.ambient) m.set(entry.id, entry);
|
|
26543
26955
|
return m;
|
|
26544
|
-
}, [tools.registry, tools.ambient]);
|
|
26956
|
+
}, [tools.registry, tools.ambient, contributions]);
|
|
26545
26957
|
const boundsOfRef = useRef(boundsOf2);
|
|
26546
26958
|
boundsOfRef.current = boundsOf2;
|
|
26547
26959
|
const pickEveryRef = useRef(pickEvery);
|
|
@@ -26660,7 +27072,7 @@ function GestureDispatcherMounter({
|
|
|
26660
27072
|
useGestureDispatcher({
|
|
26661
27073
|
canvasRef,
|
|
26662
27074
|
actions: registry2,
|
|
26663
|
-
|
|
27075
|
+
entriesById,
|
|
26664
27076
|
enabled,
|
|
26665
27077
|
keyboard,
|
|
26666
27078
|
affordanceAt: affordanceWithLayers,
|
|
@@ -26680,6 +27092,7 @@ function StandardActionsRegistrar({
|
|
|
26680
27092
|
scene,
|
|
26681
27093
|
adapter,
|
|
26682
27094
|
actions,
|
|
27095
|
+
excludeActions,
|
|
26683
27096
|
currentViewRef,
|
|
26684
27097
|
onViewChange,
|
|
26685
27098
|
resizeOptions,
|
|
@@ -26719,11 +27132,6 @@ function StandardActionsRegistrar({
|
|
|
26719
27132
|
if (!registry2) return;
|
|
26720
27133
|
return registry2.setDispatcher(dispatcher);
|
|
26721
27134
|
}, [registry2, dispatcher]);
|
|
26722
|
-
const wiredDepRegistry = useDepRegistry();
|
|
26723
|
-
useEffect(() => {
|
|
26724
|
-
if (!registry2) return;
|
|
26725
|
-
return registry2.setDepRegistry(wiredDepRegistry);
|
|
26726
|
-
}, [registry2, wiredDepRegistry]);
|
|
26727
27135
|
useEffect(() => {
|
|
26728
27136
|
if (!registry2) return;
|
|
26729
27137
|
getActionRef.current = (id) => registry2.list().find((a) => a.id === id);
|
|
@@ -26744,7 +27152,7 @@ function StandardActionsRegistrar({
|
|
|
26744
27152
|
decayLoop,
|
|
26745
27153
|
layerIsPainted
|
|
26746
27154
|
);
|
|
26747
|
-
useStandardActions({ selection, scene, view, history: scene.history });
|
|
27155
|
+
useStandardActions({ selection, scene, view, history: scene.history, exclude: excludeActions });
|
|
26748
27156
|
useDepSource("rootView", () => view);
|
|
26749
27157
|
const pointer = usePointerContext();
|
|
26750
27158
|
useDepSource("pointer", () => pointer ?? void 0);
|
|
@@ -26763,7 +27171,7 @@ function StandardActionsRegistrar({
|
|
|
26763
27171
|
useDispatcherDepSource(dispatcher);
|
|
26764
27172
|
usePoseDescriptorDepSource(poseDescriptor);
|
|
26765
27173
|
usePoseCompositionDepSource(poseComposition);
|
|
26766
|
-
useActionsPropResolver(actions);
|
|
27174
|
+
useActionsPropResolver(actions, excludeActions.join("|"));
|
|
26767
27175
|
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
26768
27176
|
resizeOptions ? /* @__PURE__ */ jsx(ResizePolicyRegistrar, { options: resizeOptions }) : null,
|
|
26769
27177
|
geometryProjection ? /* @__PURE__ */ jsx(GeometryProjectionRegistrar, { projection: geometryProjection }) : null
|
|
@@ -26772,11 +27180,7 @@ function StandardActionsRegistrar({
|
|
|
26772
27180
|
function ResizePolicyRegistrar({
|
|
26773
27181
|
options
|
|
26774
27182
|
}) {
|
|
26775
|
-
useResizePolicy(
|
|
26776
|
-
constraints: options.behaviors,
|
|
26777
|
-
pointSnap: options.pointSnapBehaviors,
|
|
26778
|
-
expandIds: options.expandIds
|
|
26779
|
-
});
|
|
27183
|
+
useResizePolicy(resizePolicyOptions(options));
|
|
26780
27184
|
return null;
|
|
26781
27185
|
}
|
|
26782
27186
|
function GeometryProjectionRegistrar({
|
|
@@ -26787,7 +27191,7 @@ function GeometryProjectionRegistrar({
|
|
|
26787
27191
|
}
|
|
26788
27192
|
var SceneCanvasInnerForwardRef = forwardRef(SceneCanvasInner);
|
|
26789
27193
|
function SceneCanvasWrapper(props, ref) {
|
|
26790
|
-
return /* @__PURE__ */ jsx(
|
|
27194
|
+
return /* @__PURE__ */ jsx(InputScope, { yoke: props.yoke, children: /* @__PURE__ */ jsx(ViewRegistryProvider, { children: /* @__PURE__ */ jsx(SceneCanvasInnerForwardRef, { ...props, ref }) }) });
|
|
26791
27195
|
}
|
|
26792
27196
|
var SceneCanvas = forwardRef(SceneCanvasWrapper);
|
|
26793
27197
|
|
|
@@ -26837,6 +27241,18 @@ var markerEncoding = {
|
|
|
26837
27241
|
},
|
|
26838
27242
|
write: (value) => value === "" ? void 0 : value
|
|
26839
27243
|
};
|
|
27244
|
+
var italicEncoding = {
|
|
27245
|
+
read: (stored) => stored === "italic",
|
|
27246
|
+
write: (on) => on ? "italic" : void 0
|
|
27247
|
+
};
|
|
27248
|
+
var alignEncoding = {
|
|
27249
|
+
read: (stored, style) => {
|
|
27250
|
+
if (stored === void 0) return void 0;
|
|
27251
|
+
const direction = style?.direction === "rtl" ? "rtl" : "ltr";
|
|
27252
|
+
return resolveAlign(stored, direction);
|
|
27253
|
+
},
|
|
27254
|
+
write: (edge2) => edge2
|
|
27255
|
+
};
|
|
26840
27256
|
var markerOptions = () => [
|
|
26841
27257
|
{ value: "", label: "None" },
|
|
26842
27258
|
...listMarkers().map((m) => ({ value: m.id, label: m.id }))
|
|
@@ -26940,23 +27356,33 @@ function shapeSchema(opts = {}) {
|
|
|
26940
27356
|
fontFamily: { kind: "font-family", name: "Font", description: "Registered font family.", default: "sans-serif" },
|
|
26941
27357
|
fontSize: { kind: "number", name: "Size", description: "Font size, world units.", default: 16, min: 1, step: 1, pair: "Size / weight" },
|
|
26942
27358
|
fontWeight: { kind: "number", name: "Weight", description: "Font weight, 100\u2013900.", default: 400, min: 100, max: 900, step: 100, pair: "Size / weight" },
|
|
26943
|
-
|
|
27359
|
+
// One row of segments, the strip every text editor
|
|
27360
|
+
// draws: the slant, the three rules, then the two
|
|
27361
|
+
// scripts. Italic is a flag here although the field
|
|
27362
|
+
// is `fontStyle`, whose only other value is upright.
|
|
27363
|
+
fontStyle: { kind: "boolean", name: "Italic", description: "Set the text in its italic face.", default: false, control: "toggle", icon: "italic", short: "I", pair: "Style", encoding: italicEncoding },
|
|
27364
|
+
underline: { kind: "boolean", name: "Underline", description: "Underline the text.", default: false, control: "toggle", icon: "underline", short: "U", pair: "Style" },
|
|
27365
|
+
strikethrough: { kind: "boolean", name: "Strikethrough", description: "Strike through the text.", default: false, control: "toggle", icon: "strikethrough", short: "S", pair: "Style" },
|
|
27366
|
+
overline: { kind: "boolean", name: "Overline", description: "Rule the text above its ascent.", default: false, control: "toggle", icon: "overline", short: "O", pair: "Style" },
|
|
27367
|
+
script: { kind: "enum", name: "Script", description: "Set the text smaller and raised or lowered, on the line it would otherwise hold.", default: void 0, control: "toggle", clearable: true, pair: "Style", options: [{ value: "super", label: "Superscript", icon: "superscript" }, { value: "sub", label: "Subscript", icon: "subscript" }] },
|
|
26944
27368
|
letterSpacing: { kind: "number", name: "Tracking", description: "Extra advance per glyph, world units.", default: 0, step: 0.1 },
|
|
26945
|
-
underline: { kind: "boolean", name: "Underline", description: "Underline the text.", default: false, control: "toggle", short: "U", pair: "Decoration" },
|
|
26946
|
-
strikethrough: { kind: "boolean", name: "Strikethrough", description: "Strike through the text.", default: false, control: "toggle", short: "S", pair: "Decoration" },
|
|
26947
|
-
overline: { kind: "boolean", name: "Overline", description: "Rule the text above its ascent.", default: false, control: "toggle", short: "O", pair: "Decoration" },
|
|
26948
27369
|
textTransform: { kind: "enum", name: "Case", description: "Draw the text in capitals, lowercase or title case. The text itself is unchanged.", default: "none", control: "toggle", options: [{ value: "none", label: "None", short: "\u2013" }, { value: "uppercase", label: "Uppercase", short: "AA" }, { value: "lowercase", label: "Lowercase", short: "aa" }, { value: "capitalize", label: "Capitalize", short: "Aa" }] }
|
|
26949
27370
|
}
|
|
26950
27371
|
},
|
|
26951
27372
|
paragraph: {
|
|
26952
27373
|
name: "Paragraph",
|
|
26953
27374
|
children: {
|
|
26954
|
-
|
|
26955
|
-
|
|
27375
|
+
lineHeight: { kind: "number", name: "Leading", description: "Line height as a multiple of font size.", default: 1.2, min: 0.5, step: 0.1 },
|
|
27376
|
+
wrap: { kind: "boolean", name: "Wrap", description: "Break lines between words at the box width.", default: false, control: "switch" },
|
|
27377
|
+
direction: { kind: "enum", name: "Direction", description: "Reading direction.", default: "ltr", control: "toggle", options: [{ value: "ltr", label: "Left to right", short: "LTR" }, { value: "rtl", label: "Right to left", short: "RTL" }] },
|
|
27378
|
+
// Last, so the box's vertical alignment — a field of
|
|
27379
|
+
// the node rather than of its style — follows it.
|
|
27380
|
+
align: { kind: "enum", name: "Align", description: "Horizontal alignment.", default: "left", control: "toggle", encoding: alignEncoding, options: [{ value: "left", label: "Left", icon: "textAlignLeft" }, { value: "center", label: "Center", icon: "textAlignCenter" }, { value: "right", label: "Right", icon: "textAlignRight" }] }
|
|
26956
27381
|
}
|
|
26957
27382
|
}
|
|
26958
27383
|
}
|
|
26959
|
-
}
|
|
27384
|
+
},
|
|
27385
|
+
"data.verticalAlign": { kind: "enum", name: "Vertical", description: "Where the lines sit in the box's height.", default: "top", control: "toggle", options: [{ value: "top", label: "Top", icon: "textAlignTop" }, { value: "center", label: "Middle", icon: "textAlignMiddle" }, { value: "bottom", label: "Bottom", icon: "textAlignBottom" }] }
|
|
26960
27386
|
}
|
|
26961
27387
|
}
|
|
26962
27388
|
} : {}
|
|
@@ -27545,7 +27971,7 @@ function MinimapCanvasInner(props) {
|
|
|
27545
27971
|
useGestureDispatcher({
|
|
27546
27972
|
canvasRef: localCanvasRef,
|
|
27547
27973
|
actions,
|
|
27548
|
-
|
|
27974
|
+
entriesById: TOOLS_BY_ID,
|
|
27549
27975
|
clientToWorld: clientToWorld2,
|
|
27550
27976
|
keyboard: false,
|
|
27551
27977
|
channels: CHANNELS
|
|
@@ -27824,6 +28250,16 @@ function renderSceneToPixels(args) {
|
|
|
27824
28250
|
renderer.dispose();
|
|
27825
28251
|
}
|
|
27826
28252
|
}
|
|
28253
|
+
function ActionsProviderIfRoot({ children }) {
|
|
28254
|
+
const parent = useActionsRegistry();
|
|
28255
|
+
if (parent) return /* @__PURE__ */ jsx(Fragment, { children });
|
|
28256
|
+
return /* @__PURE__ */ jsx(ActionsProvider, { children });
|
|
28257
|
+
}
|
|
28258
|
+
function DepRegistryProviderIfRoot({ children }) {
|
|
28259
|
+
const parent = useOptionalDepRegistry();
|
|
28260
|
+
if (parent) return /* @__PURE__ */ jsx(Fragment, { children });
|
|
28261
|
+
return /* @__PURE__ */ jsx(DepRegistryProvider, { children });
|
|
28262
|
+
}
|
|
27827
28263
|
function WeaselProvider({ children, isolate = false }) {
|
|
27828
28264
|
const Deps = isolate ? DepRegistryProvider : DepRegistryProviderIfRoot;
|
|
27829
28265
|
const Actions = isolate ? ActionsProvider : ActionsProviderIfRoot;
|
|
@@ -27881,9 +28317,66 @@ function gateLayer(opts) {
|
|
|
27881
28317
|
if (layer.defaultVisible !== void 0) wrapped.defaultVisible = layer.defaultVisible;
|
|
27882
28318
|
if (layer.alwaysOn !== void 0) wrapped.alwaysOn = layer.alwaysOn;
|
|
27883
28319
|
if (layer.space !== void 0) wrapped.space = layer.space;
|
|
28320
|
+
if (layer.subscribe) wrapped.subscribe = subscribeToSources([layer]);
|
|
27884
28321
|
return wrapped;
|
|
27885
28322
|
}
|
|
27886
28323
|
|
|
28324
|
+
// src/features/modes/modeLayers.ts
|
|
28325
|
+
var DEFAULT_INTENSITY = 0.12;
|
|
28326
|
+
function workspaceTintLayer(opts) {
|
|
28327
|
+
const { registry: registry2 } = opts;
|
|
28328
|
+
return {
|
|
28329
|
+
id: opts.id ?? "mode-tint",
|
|
28330
|
+
label: opts.label ?? "Mode tint",
|
|
28331
|
+
space: "screen",
|
|
28332
|
+
subscribe: registry2.subscribe,
|
|
28333
|
+
draw: (_data, view, dims) => {
|
|
28334
|
+
const ws = registry2.current().workspace;
|
|
28335
|
+
const tint = ws?.tint;
|
|
28336
|
+
if (!tint || tint === "transparent") return [];
|
|
28337
|
+
const opacity = opts.intensity ?? ws.intensity ?? DEFAULT_INTENSITY;
|
|
28338
|
+
const { width: W, height: H } = dims;
|
|
28339
|
+
const strip = (x, y, width, height, from, to) => ({
|
|
28340
|
+
kind: "path",
|
|
28341
|
+
path: { kind: "rect", x, y, width, height },
|
|
28342
|
+
fill: ws.gradient ? { fill: "linear-gradient", from, to, stops: [{ offset: 0, color: tint }, { offset: 1, color: "transparent" }], opacity } : { fill: "solid", color: tint, opacity }
|
|
28343
|
+
});
|
|
28344
|
+
const whole = () => [
|
|
28345
|
+
ws.gradient === "top-down" ? strip(0, 0, W, H, { x: 0, y: 0 }, { x: 0, y: H }) : strip(0, 0, W, H, { x: 0, y: H }, { x: 0, y: 0 })
|
|
28346
|
+
];
|
|
28347
|
+
const page = opts.page?.();
|
|
28348
|
+
if (!page) return whole();
|
|
28349
|
+
const t = viewToTransform(view);
|
|
28350
|
+
const [sx0, sy0] = worldToScreen(page.x, page.y, t);
|
|
28351
|
+
const [sx1, sy1] = worldToScreen(page.x + page.width, page.y + page.height, t);
|
|
28352
|
+
const pl = Math.max(0, Math.min(sx0, sx1));
|
|
28353
|
+
const pt = Math.max(0, Math.min(sy0, sy1));
|
|
28354
|
+
const pr = Math.min(W, Math.max(sx0, sx1));
|
|
28355
|
+
const pb = Math.min(H, Math.max(sy0, sy1));
|
|
28356
|
+
if (pr <= pl || pb <= pt) {
|
|
28357
|
+
return [{ kind: "path", path: { kind: "rect", x: 0, y: 0, width: W, height: H }, fill: { fill: "solid", color: tint, opacity } }];
|
|
28358
|
+
}
|
|
28359
|
+
const cmds = [];
|
|
28360
|
+
const push = (x, y, w, h, from, to) => {
|
|
28361
|
+
if (w > 0 && h > 0) cmds.push(strip(x, y, w, h, from, to));
|
|
28362
|
+
};
|
|
28363
|
+
push(0, 0, W, pt, { x: 0, y: 0 }, { x: 0, y: pt });
|
|
28364
|
+
push(0, pb, W, H - pb, { x: 0, y: H }, { x: 0, y: pb });
|
|
28365
|
+
push(0, pt, pl, pb - pt, { x: 0, y: 0 }, { x: pl, y: 0 });
|
|
28366
|
+
push(pr, pt, W - pr, pb - pt, { x: W, y: 0 }, { x: pr, y: 0 });
|
|
28367
|
+
return cmds;
|
|
28368
|
+
}
|
|
28369
|
+
};
|
|
28370
|
+
}
|
|
28371
|
+
function modeDecorationLayer(decorations, opts = {}) {
|
|
28372
|
+
return {
|
|
28373
|
+
id: opts.id ?? "mode-decorations",
|
|
28374
|
+
label: opts.label ?? "Mode decorations",
|
|
28375
|
+
subscribe: decorations.subscribe,
|
|
28376
|
+
draw: () => decorations.paint()
|
|
28377
|
+
};
|
|
28378
|
+
}
|
|
28379
|
+
|
|
27887
28380
|
// src/features/groups/children.ts
|
|
27888
28381
|
function createChildrenLayer(opts) {
|
|
27889
28382
|
return {
|
|
@@ -28989,7 +29482,8 @@ function useTextEdit(opts) {
|
|
|
28989
29482
|
}
|
|
28990
29483
|
if (e.key === "Escape") {
|
|
28991
29484
|
e.preventDefault();
|
|
28992
|
-
|
|
29485
|
+
if (optsRef.current.escape === "commit") commit();
|
|
29486
|
+
else cancelEdit();
|
|
28993
29487
|
return;
|
|
28994
29488
|
}
|
|
28995
29489
|
const toggle = toggleForKey(e);
|
|
@@ -29138,6 +29632,7 @@ function applyOverlayStyle(el, style) {
|
|
|
29138
29632
|
const decorations = [];
|
|
29139
29633
|
if (style.underline) decorations.push("underline");
|
|
29140
29634
|
if (style.strikethrough) decorations.push("line-through");
|
|
29635
|
+
if (style.overline) decorations.push("overline");
|
|
29141
29636
|
el.style.textDecoration = decorations.length > 0 ? decorations.join(" ") : "none";
|
|
29142
29637
|
el.style.textTransform = style.textTransform;
|
|
29143
29638
|
el.style.whiteSpace = style.wrap ? "pre-wrap" : "pre";
|
|
@@ -29178,8 +29673,11 @@ function placeOverlay(el, clipBox, pose, clip, style) {
|
|
|
29178
29673
|
el.style.left = `${pose.x + pose.width * (pose.zoom ?? 1) * anchor + 1 - (clip?.x ?? 0)}px`;
|
|
29179
29674
|
el.style.width = style.wrap ? `${pose.width}px` : "max-content";
|
|
29180
29675
|
el.style.minWidth = style.wrap ? "" : `${pose.width}px`;
|
|
29181
|
-
|
|
29182
|
-
|
|
29676
|
+
const script = style.script ? SCRIPT_METRICS[style.script] : void 0;
|
|
29677
|
+
const lineHeight = pose.lineHeight ?? style.lineHeight;
|
|
29678
|
+
el.style.fontSize = `${pose.fontSize * (script?.size ?? 1)}px`;
|
|
29679
|
+
el.style.lineHeight = script ? `${pose.fontSize * lineHeight}px` : String(lineHeight);
|
|
29680
|
+
el.style.translate = script ? `0 ${-script.shift * pose.fontSize * (pose.zoom ?? 1)}px` : "";
|
|
29183
29681
|
const aligned = pose.verticalAlign !== void 0 && pose.verticalAlign !== "top";
|
|
29184
29682
|
el.style.minHeight = aligned ? "" : `${pose.height}px`;
|
|
29185
29683
|
el.style.top = `${overlayTop(pose, aligned ? el.offsetHeight : pose.height) - (clip?.y ?? 0)}px`;
|
|
@@ -29221,6 +29719,7 @@ function useSceneTextEdit(scene, container, options = {}) {
|
|
|
29221
29719
|
const edit = useTextEdit({
|
|
29222
29720
|
container,
|
|
29223
29721
|
isEditorChrome: (el) => optsRef.current.isEditorChrome?.(el) ?? false,
|
|
29722
|
+
escape: options.escape,
|
|
29224
29723
|
getText: (id) => {
|
|
29225
29724
|
const node = sceneRef.current.get(asNodeId(id));
|
|
29226
29725
|
if (!node) return "";
|
|
@@ -29640,6 +30139,44 @@ function seedMeshPatch(color) {
|
|
|
29640
30139
|
units: "bounds"
|
|
29641
30140
|
};
|
|
29642
30141
|
}
|
|
30142
|
+
function bandPatch(x0, x1, left, right) {
|
|
30143
|
+
const corners = [{ x: x0, y: 0 }, { x: x1, y: 0 }, { x: x1, y: 1 }, { x: x0, y: 1 }];
|
|
30144
|
+
const points = [];
|
|
30145
|
+
for (let i = 0; i < 4; i++) {
|
|
30146
|
+
const a = corners[i];
|
|
30147
|
+
const b = corners[(i + 1) % 4];
|
|
30148
|
+
points.push(a, { x: a.x + (b.x - a.x) / 3, y: a.y + (b.y - a.y) / 3 }, { x: a.x + 2 * (b.x - a.x) / 3, y: a.y + 2 * (b.y - a.y) / 3 });
|
|
30149
|
+
}
|
|
30150
|
+
return { points, colors: [left, right, right, left] };
|
|
30151
|
+
}
|
|
30152
|
+
function meshFromStops(stops) {
|
|
30153
|
+
const sorted = [...stops].sort((a, b) => a.offset - b.offset);
|
|
30154
|
+
if (sorted.length === 1) sorted.push({ offset: 1, color: sorted[0].color });
|
|
30155
|
+
if (sorted.length === 0) return seedMeshPatch("#000000ff");
|
|
30156
|
+
const patches = [];
|
|
30157
|
+
for (let i = 0; i < sorted.length - 1; i++) {
|
|
30158
|
+
const a = sorted[i];
|
|
30159
|
+
const b = sorted[i + 1];
|
|
30160
|
+
if (b.offset > a.offset) patches.push(bandPatch(a.offset, b.offset, a.color, b.color));
|
|
30161
|
+
}
|
|
30162
|
+
return { fill: MESH_GRADIENT_KIND, patches, units: "bounds" };
|
|
30163
|
+
}
|
|
30164
|
+
function meshStops(mesh) {
|
|
30165
|
+
const valid = mesh.patches.filter(isValidPatch);
|
|
30166
|
+
if (valid.length === 0) return [];
|
|
30167
|
+
const xs = valid.flatMap((p) => [p.points[0].x, p.points[3].x]);
|
|
30168
|
+
const lo = Math.min(...xs);
|
|
30169
|
+
const span = Math.max(...xs) - lo;
|
|
30170
|
+
const offsetOf = (x) => span > 0 ? (x - lo) / span : 0;
|
|
30171
|
+
const stops = [];
|
|
30172
|
+
for (const patch of valid) {
|
|
30173
|
+
for (const [point, color] of [[patch.points[0], patch.colors[0]], [patch.points[3], patch.colors[1]]]) {
|
|
30174
|
+
const offset = offsetOf(point.x);
|
|
30175
|
+
if (!stops.some((s) => s.offset === offset && s.color === color)) stops.push({ offset, color });
|
|
30176
|
+
}
|
|
30177
|
+
}
|
|
30178
|
+
return stops.sort((a, b) => a.offset - b.offset);
|
|
30179
|
+
}
|
|
29643
30180
|
function mapPatches(mesh, move) {
|
|
29644
30181
|
return mesh.patches.map((patch) => ({ ...patch, points: patch.points.map(move) }));
|
|
29645
30182
|
}
|
|
@@ -29709,6 +30246,8 @@ registerPaintKind({
|
|
|
29709
30246
|
// The first corner of the first patch: a mesh has no single color, and this
|
|
29710
30247
|
// is the one a fallback swatch and an SVG paint fallback both read.
|
|
29711
30248
|
colorOf: (paint) => asMesh(paint).patches?.[0]?.colors?.[0],
|
|
30249
|
+
stopsOf: (paint) => meshStops(asMesh(paint)),
|
|
30250
|
+
fromStops: (stops) => asPaint(meshFromStops(stops)),
|
|
29712
30251
|
bind: bindMesh,
|
|
29713
30252
|
inPoseFrame: (fill, box) => {
|
|
29714
30253
|
const mesh = asMesh(fill);
|
|
@@ -29899,19 +30438,6 @@ function unionOfChildrenVia(descriptor) {
|
|
|
29899
30438
|
return u === null ? null : poseDescriptorForNode(descriptor, node).fromBounds(u, node.pose);
|
|
29900
30439
|
};
|
|
29901
30440
|
}
|
|
29902
|
-
var BEZIER_SAMPLES = 16;
|
|
29903
|
-
function pointCubicDist2(px, py, x0, y0, x1, y1, x2, y2, x3, y3) {
|
|
29904
|
-
let prevX = x0, prevY = y0;
|
|
29905
|
-
let best = Infinity;
|
|
29906
|
-
for (let i = 1; i <= BEZIER_SAMPLES; i++) {
|
|
29907
|
-
const [sx, sy] = cubicEvalAt(x0, y0, x1, y1, x2, y2, x3, y3, i / BEZIER_SAMPLES);
|
|
29908
|
-
const d2 = pointSegmentDist2(px, py, prevX, prevY, sx, sy);
|
|
29909
|
-
if (d2 < best) best = d2;
|
|
29910
|
-
prevX = sx;
|
|
29911
|
-
prevY = sy;
|
|
29912
|
-
}
|
|
29913
|
-
return best;
|
|
29914
|
-
}
|
|
29915
30441
|
function pointToRectPerimeterDist(px, py, rx, ry, rw, rh) {
|
|
29916
30442
|
const dx = Math.max(rx - px, px - (rx + rw), 0);
|
|
29917
30443
|
const dy = Math.max(ry - py, py - (ry + rh), 0);
|
|
@@ -29924,52 +30450,66 @@ function pathDistanceToPoint(path, px, py) {
|
|
|
29924
30450
|
if (path.kind === "rect") {
|
|
29925
30451
|
return pointToRectPerimeterDist(px, py, path.x, path.y, path.width, path.height);
|
|
29926
30452
|
}
|
|
29927
|
-
return
|
|
30453
|
+
return nearestOnPath(path.commands, path.coords, px, py)?.dist ?? Infinity;
|
|
29928
30454
|
}
|
|
29929
|
-
function
|
|
29930
|
-
const
|
|
29931
|
-
let
|
|
29932
|
-
|
|
29933
|
-
|
|
29934
|
-
|
|
29935
|
-
|
|
29936
|
-
|
|
29937
|
-
|
|
29938
|
-
|
|
29939
|
-
|
|
29940
|
-
|
|
29941
|
-
|
|
29942
|
-
|
|
29943
|
-
|
|
29944
|
-
|
|
29945
|
-
|
|
29946
|
-
|
|
29947
|
-
|
|
29948
|
-
|
|
29949
|
-
|
|
29950
|
-
|
|
29951
|
-
|
|
29952
|
-
|
|
29953
|
-
|
|
29954
|
-
|
|
29955
|
-
|
|
29956
|
-
|
|
29957
|
-
|
|
29958
|
-
|
|
29959
|
-
|
|
29960
|
-
|
|
29961
|
-
|
|
29962
|
-
|
|
29963
|
-
|
|
29964
|
-
|
|
29965
|
-
|
|
29966
|
-
|
|
29967
|
-
|
|
29968
|
-
|
|
29969
|
-
|
|
29970
|
-
|
|
29971
|
-
}
|
|
29972
|
-
return
|
|
30455
|
+
function flattenVerts2(poly2) {
|
|
30456
|
+
const flat = new Array(poly2.length * 2);
|
|
30457
|
+
for (let i = 0; i < poly2.length; i++) {
|
|
30458
|
+
flat[i * 2] = poly2[i].x;
|
|
30459
|
+
flat[i * 2 + 1] = poly2[i].y;
|
|
30460
|
+
}
|
|
30461
|
+
return flat;
|
|
30462
|
+
}
|
|
30463
|
+
function polygonContainsRectCenter(poly2, rect) {
|
|
30464
|
+
return pointInPolygon(flattenVerts2(poly2), rect.x + rect.width / 2, rect.y + rect.height / 2);
|
|
30465
|
+
}
|
|
30466
|
+
function polygonContainsRect(poly2, rect) {
|
|
30467
|
+
if (poly2.length < 3) return false;
|
|
30468
|
+
const flat = flattenVerts2(poly2);
|
|
30469
|
+
if (!pointInPolygon(flat, rect.x, rect.y)) return false;
|
|
30470
|
+
if (!pointInPolygon(flat, rect.x + rect.width, rect.y)) return false;
|
|
30471
|
+
if (!pointInPolygon(flat, rect.x + rect.width, rect.y + rect.height)) return false;
|
|
30472
|
+
if (!pointInPolygon(flat, rect.x, rect.y + rect.height)) return false;
|
|
30473
|
+
return !anyPolyEdgeCrossesRect(poly2, rect);
|
|
30474
|
+
}
|
|
30475
|
+
function polygonIntersectsRect(poly2, rect) {
|
|
30476
|
+
if (poly2.length < 3) return false;
|
|
30477
|
+
const ab = polygonAabb(poly2);
|
|
30478
|
+
if (ab.x + ab.width < rect.x || ab.x > rect.x + rect.width) return false;
|
|
30479
|
+
if (ab.y + ab.height < rect.y || ab.y > rect.y + rect.height) return false;
|
|
30480
|
+
for (const v of poly2) {
|
|
30481
|
+
if (v.x >= rect.x && v.x <= rect.x + rect.width && v.y >= rect.y && v.y <= rect.y + rect.height) return true;
|
|
30482
|
+
}
|
|
30483
|
+
const flat = flattenVerts2(poly2);
|
|
30484
|
+
if (pointInPolygon(flat, rect.x, rect.y)) return true;
|
|
30485
|
+
if (pointInPolygon(flat, rect.x + rect.width, rect.y)) return true;
|
|
30486
|
+
if (pointInPolygon(flat, rect.x + rect.width, rect.y + rect.height)) return true;
|
|
30487
|
+
if (pointInPolygon(flat, rect.x, rect.y + rect.height)) return true;
|
|
30488
|
+
return anyPolyEdgeCrossesRect(poly2, rect);
|
|
30489
|
+
}
|
|
30490
|
+
function polygonAabb(poly2) {
|
|
30491
|
+
let minX = Infinity, minY = Infinity, maxX = -Infinity, maxY = -Infinity;
|
|
30492
|
+
for (const v of poly2) {
|
|
30493
|
+
if (v.x < minX) minX = v.x;
|
|
30494
|
+
if (v.y < minY) minY = v.y;
|
|
30495
|
+
if (v.x > maxX) maxX = v.x;
|
|
30496
|
+
if (v.y > maxY) maxY = v.y;
|
|
30497
|
+
}
|
|
30498
|
+
return { x: minX, y: minY, width: maxX - minX, height: maxY - minY };
|
|
30499
|
+
}
|
|
30500
|
+
function anyPolyEdgeCrossesRect(poly2, rect) {
|
|
30501
|
+
const r0x = rect.x, r0y = rect.y;
|
|
30502
|
+
const r1x = rect.x + rect.width, r1y = rect.y;
|
|
30503
|
+
const r2x = rect.x + rect.width, r2y = rect.y + rect.height;
|
|
30504
|
+
const r3x = rect.x, r3y = rect.y + rect.height;
|
|
30505
|
+
for (let i = 0, j = poly2.length - 1; i < poly2.length; j = i++) {
|
|
30506
|
+
const a = poly2[j], b = poly2[i];
|
|
30507
|
+
if (segmentsCross(a.x, a.y, b.x, b.y, r0x, r0y, r1x, r1y)) return true;
|
|
30508
|
+
if (segmentsCross(a.x, a.y, b.x, b.y, r1x, r1y, r2x, r2y)) return true;
|
|
30509
|
+
if (segmentsCross(a.x, a.y, b.x, b.y, r2x, r2y, r3x, r3y)) return true;
|
|
30510
|
+
if (segmentsCross(a.x, a.y, b.x, b.y, r3x, r3y, r0x, r0y)) return true;
|
|
30511
|
+
}
|
|
30512
|
+
return false;
|
|
29973
30513
|
}
|
|
29974
30514
|
var PLACEHOLDER_FILL = { color: "#ffffff" };
|
|
29975
30515
|
var PLACEHOLDER_STROKE = { paint: { color: "#ffffff" }, width: 1 };
|
|
@@ -30120,60 +30660,400 @@ function splitSubpaths(path) {
|
|
|
30120
30660
|
});
|
|
30121
30661
|
return out;
|
|
30122
30662
|
}
|
|
30123
|
-
|
|
30124
|
-
|
|
30125
|
-
|
|
30126
|
-
|
|
30127
|
-
|
|
30128
|
-
|
|
30663
|
+
function splitPathBySegment(path, a, b, opts = {}) {
|
|
30664
|
+
if (a.x === b.x && a.y === b.y) return null;
|
|
30665
|
+
const outRule = path.kind === "polygon" ? path.fillRule : "nonzero";
|
|
30666
|
+
let contours = parseContours(path);
|
|
30667
|
+
let fillRule = outRule;
|
|
30668
|
+
if (contoursIntersect(contours, opts.flattenTolerance ?? 0.5)) {
|
|
30669
|
+
contours = parseContours(pathUnion(path));
|
|
30670
|
+
fillRule = "nonzero";
|
|
30671
|
+
}
|
|
30672
|
+
const boundaries = orientBoundaries(contours, fillRule);
|
|
30673
|
+
if (boundaries.length === 0) return null;
|
|
30674
|
+
const crossings = findCrossings(boundaries, a, b);
|
|
30675
|
+
const partner = /* @__PURE__ */ new Map();
|
|
30676
|
+
for (let k = 0; k + 1 < crossings.length; k++) {
|
|
30677
|
+
const c0 = crossings[k], c1 = crossings[k + 1];
|
|
30678
|
+
if (c0.enters && !c1.enters && c1.s - c0.s > 1e-9) {
|
|
30679
|
+
partner.set(c0, c1);
|
|
30680
|
+
partner.set(c1, c0);
|
|
30681
|
+
}
|
|
30682
|
+
}
|
|
30683
|
+
if (partner.size === 0) return null;
|
|
30684
|
+
const { loops, untouched } = traceLoops(boundaries, partner);
|
|
30685
|
+
const traced = assembleRegions(loops, untouched.filter((c) => signedArea2(c) < 0));
|
|
30686
|
+
const islands = untouched.filter((c) => signedArea2(c) > 0);
|
|
30687
|
+
const pieces = traced.filter((r) => Math.abs(regionArea(r)) > 1e-6);
|
|
30688
|
+
if (islands.length > 0) {
|
|
30689
|
+
const leftover = untouched.filter((c) => !traced.some((r) => r.includes(c)));
|
|
30690
|
+
pieces.push(leftover);
|
|
30691
|
+
}
|
|
30692
|
+
return pieces.map((r) => toPath(r, outRule));
|
|
30693
|
+
}
|
|
30694
|
+
function evalSeg(s, t) {
|
|
30695
|
+
const u = 1 - t;
|
|
30696
|
+
if (s.length === 2) return { x: u * s[0].x + t * s[1].x, y: u * s[0].y + t * s[1].y };
|
|
30697
|
+
if (s.length === 3) {
|
|
30698
|
+
const a2 = u * u, b2 = 2 * u * t, c2 = t * t;
|
|
30699
|
+
return { x: a2 * s[0].x + b2 * s[1].x + c2 * s[2].x, y: a2 * s[0].y + b2 * s[1].y + c2 * s[2].y };
|
|
30700
|
+
}
|
|
30701
|
+
const a = u * u * u, b = 3 * u * u * t, c = 3 * u * t * t, d = t * t * t;
|
|
30702
|
+
return {
|
|
30703
|
+
x: a * s[0].x + b * s[1].x + c * s[2].x + d * s[3].x,
|
|
30704
|
+
y: a * s[0].y + b * s[1].y + c * s[2].y + d * s[3].y
|
|
30705
|
+
};
|
|
30129
30706
|
}
|
|
30130
|
-
function
|
|
30131
|
-
|
|
30132
|
-
|
|
30133
|
-
|
|
30134
|
-
|
|
30135
|
-
|
|
30136
|
-
|
|
30137
|
-
|
|
30138
|
-
|
|
30139
|
-
|
|
30140
|
-
|
|
30707
|
+
function derivSeg(s, t) {
|
|
30708
|
+
const n = s.length - 1;
|
|
30709
|
+
const d = [];
|
|
30710
|
+
for (let i = 0; i < n; i++) d.push({ x: n * (s[i + 1].x - s[i].x), y: n * (s[i + 1].y - s[i].y) });
|
|
30711
|
+
return d.length === 1 ? d[0] : evalSeg(d, t);
|
|
30712
|
+
}
|
|
30713
|
+
function splitSeg(s, t) {
|
|
30714
|
+
const pts = (c) => {
|
|
30715
|
+
const out = [];
|
|
30716
|
+
for (let i = 0; i < c.length; i += 2) out.push({ x: c[i], y: c[i + 1] });
|
|
30717
|
+
return out;
|
|
30718
|
+
};
|
|
30719
|
+
if (s.length === 2) {
|
|
30720
|
+
const m = evalSeg(s, t);
|
|
30721
|
+
return [[s[0], m], [m, s[1]]];
|
|
30722
|
+
}
|
|
30723
|
+
if (s.length === 3) {
|
|
30724
|
+
const [l2, r2] = splitQuadraticAt(s[0].x, s[0].y, s[1].x, s[1].y, s[2].x, s[2].y, t);
|
|
30725
|
+
return [pts(l2), pts(r2)];
|
|
30726
|
+
}
|
|
30727
|
+
const [l, r] = splitCubicAt(s[0].x, s[0].y, s[1].x, s[1].y, s[2].x, s[2].y, s[3].x, s[3].y, t);
|
|
30728
|
+
return [pts(l), pts(r)];
|
|
30729
|
+
}
|
|
30730
|
+
function subSeg(s, t0, t1, p0, p1) {
|
|
30731
|
+
if (t1 - t0 <= 0) return null;
|
|
30732
|
+
let out = s;
|
|
30733
|
+
if (t0 > 0) out = splitSeg(out, t0)[1];
|
|
30734
|
+
const u = (t1 - t0) / (1 - t0);
|
|
30735
|
+
if (u < 1) out = splitSeg(out, u)[0];
|
|
30736
|
+
out = out.slice();
|
|
30737
|
+
out[0] = p0;
|
|
30738
|
+
out[out.length - 1] = p1;
|
|
30739
|
+
return out;
|
|
30740
|
+
}
|
|
30741
|
+
var reverseContour = (c) => c.map((s) => s.slice().reverse()).reverse();
|
|
30742
|
+
function sampleContour(c) {
|
|
30743
|
+
const out = [];
|
|
30744
|
+
for (const s of c) {
|
|
30745
|
+
const n = s.length === 2 ? 1 : 16;
|
|
30746
|
+
for (let i = 0; i < n; i++) {
|
|
30747
|
+
const p = evalSeg(s, i / n);
|
|
30748
|
+
out.push(p.x, p.y);
|
|
30141
30749
|
}
|
|
30142
30750
|
}
|
|
30143
|
-
return
|
|
30751
|
+
return out;
|
|
30144
30752
|
}
|
|
30145
|
-
function
|
|
30146
|
-
const
|
|
30147
|
-
|
|
30148
|
-
|
|
30149
|
-
|
|
30150
|
-
|
|
30151
|
-
|
|
30152
|
-
|
|
30153
|
-
|
|
30154
|
-
|
|
30155
|
-
|
|
30156
|
-
|
|
30157
|
-
|
|
30158
|
-
const
|
|
30159
|
-
|
|
30160
|
-
|
|
30161
|
-
|
|
30162
|
-
|
|
30163
|
-
|
|
30164
|
-
const
|
|
30165
|
-
const
|
|
30166
|
-
const
|
|
30167
|
-
|
|
30168
|
-
|
|
30169
|
-
const
|
|
30170
|
-
|
|
30753
|
+
function signedArea2(c) {
|
|
30754
|
+
const pts = sampleContour(c);
|
|
30755
|
+
let a = 0;
|
|
30756
|
+
for (let i = 0; i < pts.length; i += 2) {
|
|
30757
|
+
const j = (i + 2) % pts.length;
|
|
30758
|
+
a += pts[i] * pts[j + 1] - pts[j] * pts[i + 1];
|
|
30759
|
+
}
|
|
30760
|
+
return a / 2;
|
|
30761
|
+
}
|
|
30762
|
+
function sideCoeffs(s, o, d) {
|
|
30763
|
+
return s.map((p) => d.x * (p.y - o.y) - d.y * (p.x - o.x));
|
|
30764
|
+
}
|
|
30765
|
+
function bernstein(f, t) {
|
|
30766
|
+
const u = 1 - t;
|
|
30767
|
+
if (f.length === 2) return u * f[0] + t * f[1];
|
|
30768
|
+
if (f.length === 3) return u * u * f[0] + 2 * u * t * f[1] + t * t * f[2];
|
|
30769
|
+
return u * u * u * f[0] + 3 * u * u * t * f[1] + 3 * u * t * t * f[2] + t * t * t * f[3];
|
|
30770
|
+
}
|
|
30771
|
+
function signChanges(f, zeroIsPositive) {
|
|
30772
|
+
const sgn = (v) => v > 0 ? 1 : v < 0 ? -1 : zeroIsPositive ? 1 : 0;
|
|
30773
|
+
const cuts = [0, ...criticalPoints(f), 1];
|
|
30774
|
+
const out = [];
|
|
30775
|
+
for (let i = 0; i + 1 < cuts.length; i++) {
|
|
30776
|
+
let lo = cuts[i], hi = cuts[i + 1];
|
|
30777
|
+
const slo = sgn(bernstein(f, lo)), shi = sgn(bernstein(f, hi));
|
|
30778
|
+
if (slo === 0 && i > 0) {
|
|
30779
|
+
const before = sgn(bernstein(f, lo - 1e-7)), after = sgn(bernstein(f, lo + 1e-7));
|
|
30780
|
+
if (before * after < 0) out.push({ t: lo, before, after });
|
|
30781
|
+
}
|
|
30782
|
+
if (slo * shi >= 0) continue;
|
|
30783
|
+
for (let it = 0; it < 64; it++) {
|
|
30784
|
+
const mid = (lo + hi) / 2;
|
|
30785
|
+
if (sgn(bernstein(f, mid)) === slo) lo = mid;
|
|
30786
|
+
else hi = mid;
|
|
30787
|
+
}
|
|
30788
|
+
out.push({ t: (lo + hi) / 2, before: slo, after: shi });
|
|
30789
|
+
}
|
|
30790
|
+
return out;
|
|
30791
|
+
}
|
|
30792
|
+
function criticalPoints(f) {
|
|
30793
|
+
if (f.length < 3) return [];
|
|
30794
|
+
const n = f.length - 1;
|
|
30795
|
+
const d = f.slice(1).map((v, i) => n * (v - f[i]));
|
|
30796
|
+
let A = 0, B, C;
|
|
30797
|
+
if (d.length === 2) {
|
|
30798
|
+
B = d[1] - d[0];
|
|
30799
|
+
C = d[0];
|
|
30800
|
+
} else {
|
|
30801
|
+
A = d[0] - 2 * d[1] + d[2];
|
|
30802
|
+
B = 2 * (d[1] - d[0]);
|
|
30803
|
+
C = d[0];
|
|
30804
|
+
}
|
|
30805
|
+
const out = [];
|
|
30806
|
+
const scale = Math.max(Math.abs(A), Math.abs(B), Math.abs(C)) || 1;
|
|
30807
|
+
if (Math.abs(A) / scale < 1e-12) {
|
|
30808
|
+
if (Math.abs(B) / scale > 1e-12) out.push(-C / B);
|
|
30809
|
+
} else {
|
|
30810
|
+
const disc = B * B - 4 * A * C;
|
|
30811
|
+
if (disc >= 0) {
|
|
30812
|
+
const q = -0.5 * (B + Math.sign(B || 1) * Math.sqrt(disc));
|
|
30813
|
+
out.push(q / A);
|
|
30814
|
+
if (q !== 0) out.push(C / q);
|
|
30815
|
+
}
|
|
30816
|
+
}
|
|
30817
|
+
return out.filter((t) => t > 0 && t < 1).sort((x, y) => x - y);
|
|
30818
|
+
}
|
|
30819
|
+
function endSide(f, fromStart) {
|
|
30820
|
+
const n = f.length;
|
|
30821
|
+
for (let i = 1; i < n; i++) {
|
|
30822
|
+
const v = fromStart ? f[i] : f[n - 1 - i];
|
|
30823
|
+
if (v !== 0) return Math.sign(v);
|
|
30824
|
+
}
|
|
30825
|
+
return 0;
|
|
30826
|
+
}
|
|
30827
|
+
function parseContours(path) {
|
|
30828
|
+
if (path.kind === "rect") {
|
|
30829
|
+
const { x, y, width: w, height: h } = path;
|
|
30830
|
+
const p = [{ x, y }, { x: x + w, y }, { x: x + w, y: y + h }, { x, y: y + h }];
|
|
30831
|
+
return [p.map((q, i) => [q, p[(i + 1) % 4]])];
|
|
30832
|
+
}
|
|
30833
|
+
const out = [];
|
|
30834
|
+
let cur = [];
|
|
30835
|
+
let start = { x: 0, y: 0 };
|
|
30836
|
+
let pen = start;
|
|
30837
|
+
const finish = () => {
|
|
30838
|
+
if (cur.length > 0 && (pen.x !== start.x || pen.y !== start.y)) cur.push([pen, start]);
|
|
30839
|
+
if (cur.length > 0) out.push(cur);
|
|
30840
|
+
cur = [];
|
|
30841
|
+
pen = start;
|
|
30842
|
+
};
|
|
30843
|
+
const c = path.coords;
|
|
30844
|
+
let k = 0;
|
|
30845
|
+
for (const cmd of path.commands) {
|
|
30846
|
+
if (cmd === PATH_M) {
|
|
30847
|
+
finish();
|
|
30848
|
+
start = pen = { x: c[k], y: c[k + 1] };
|
|
30849
|
+
k += 2;
|
|
30850
|
+
} else if (cmd === PATH_L) {
|
|
30851
|
+
const e = { x: c[k], y: c[k + 1] };
|
|
30852
|
+
if (e.x !== pen.x || e.y !== pen.y) cur.push([pen, e]);
|
|
30853
|
+
pen = e;
|
|
30854
|
+
k += 2;
|
|
30855
|
+
} else if (cmd === PATH_Q) {
|
|
30856
|
+
const e = { x: c[k + 2], y: c[k + 3] };
|
|
30857
|
+
cur.push([pen, { x: c[k], y: c[k + 1] }, e]);
|
|
30858
|
+
pen = e;
|
|
30859
|
+
k += 4;
|
|
30860
|
+
} else if (cmd === PATH_C) {
|
|
30861
|
+
const e = { x: c[k + 4], y: c[k + 5] };
|
|
30862
|
+
cur.push([pen, { x: c[k], y: c[k + 1] }, { x: c[k + 2], y: c[k + 3] }, e]);
|
|
30863
|
+
pen = e;
|
|
30864
|
+
k += 6;
|
|
30865
|
+
} else if (cmd === PATH_Z) {
|
|
30866
|
+
finish();
|
|
30867
|
+
}
|
|
30868
|
+
}
|
|
30869
|
+
finish();
|
|
30870
|
+
return out;
|
|
30871
|
+
}
|
|
30872
|
+
function contoursIntersect(contours, tol) {
|
|
30873
|
+
const edges = [];
|
|
30874
|
+
contours.forEach((contour, ci) => {
|
|
30875
|
+
const pts = [];
|
|
30876
|
+
for (const s of contour) {
|
|
30877
|
+
let n = 1;
|
|
30878
|
+
if (s.length > 2) {
|
|
30879
|
+
let len = 0;
|
|
30880
|
+
for (let i = 0; i + 1 < s.length; i++) len += Math.hypot(s[i + 1].x - s[i].x, s[i + 1].y - s[i].y);
|
|
30881
|
+
n = Math.min(64, Math.max(2, Math.ceil(Math.sqrt(len / Math.max(tol, 1e-3)))));
|
|
30882
|
+
}
|
|
30883
|
+
for (let i = 0; i < n; i++) pts.push(evalSeg(s, i / n));
|
|
30884
|
+
}
|
|
30885
|
+
for (let i = 0; i < pts.length; i++) {
|
|
30886
|
+
const p = pts[i], q = pts[(i + 1) % pts.length];
|
|
30887
|
+
edges.push({ x0: p.x, y0: p.y, x1: q.x, y1: q.y, c: ci, i, n: pts.length });
|
|
30888
|
+
}
|
|
30889
|
+
});
|
|
30890
|
+
for (let i = 0; i < edges.length; i++) {
|
|
30891
|
+
const e = edges[i];
|
|
30892
|
+
for (let j = i + 1; j < edges.length; j++) {
|
|
30893
|
+
const f = edges[j];
|
|
30894
|
+
if (e.c === f.c && (j - i === 1 || i === 0 && f.i === f.n - 1)) continue;
|
|
30895
|
+
if (Math.max(e.x0, e.x1) < Math.min(f.x0, f.x1) || Math.max(f.x0, f.x1) < Math.min(e.x0, e.x1)) continue;
|
|
30896
|
+
if (Math.max(e.y0, e.y1) < Math.min(f.y0, f.y1) || Math.max(f.y0, f.y1) < Math.min(e.y0, e.y1)) continue;
|
|
30897
|
+
if (segmentsCross(e.x0, e.y0, e.x1, e.y1, f.x0, f.y0, f.x1, f.y1)) return true;
|
|
30898
|
+
}
|
|
30899
|
+
}
|
|
30900
|
+
return false;
|
|
30901
|
+
}
|
|
30902
|
+
function windingAt(q, contours) {
|
|
30903
|
+
const dir2 = { x: 1, y: 0 };
|
|
30904
|
+
let w = 0;
|
|
30905
|
+
for (const contour of contours) {
|
|
30906
|
+
for (const s of contour) {
|
|
30907
|
+
for (const c of signChanges(sideCoeffs(s, q, dir2), true)) {
|
|
30908
|
+
if (evalSeg(s, c.t).x > q.x) w += c.after > 0 ? 1 : -1;
|
|
30909
|
+
}
|
|
30910
|
+
}
|
|
30911
|
+
}
|
|
30912
|
+
return w;
|
|
30913
|
+
}
|
|
30914
|
+
function orientBoundaries(contours, fillRule) {
|
|
30915
|
+
const filled = (q) => {
|
|
30916
|
+
const w = windingAt(q, contours);
|
|
30917
|
+
return fillRule === "evenodd" ? (w & 1) !== 0 : w !== 0;
|
|
30918
|
+
};
|
|
30919
|
+
let minX = Infinity, minY = Infinity, maxX = -Infinity, maxY = -Infinity;
|
|
30920
|
+
for (const c of contours) for (const s of c) for (const p of s) {
|
|
30921
|
+
minX = Math.min(minX, p.x);
|
|
30922
|
+
maxX = Math.max(maxX, p.x);
|
|
30923
|
+
minY = Math.min(minY, p.y);
|
|
30924
|
+
maxY = Math.max(maxY, p.y);
|
|
30925
|
+
}
|
|
30926
|
+
const eps = Math.max(Math.hypot(maxX - minX, maxY - minY) * 1e-6, 1e-9);
|
|
30927
|
+
const out = [];
|
|
30928
|
+
for (const contour of contours) {
|
|
30929
|
+
let probe = contour[0];
|
|
30930
|
+
let best = -1;
|
|
30931
|
+
for (const s of contour) {
|
|
30932
|
+
const len = Math.hypot(s[s.length - 1].x - s[0].x, s[s.length - 1].y - s[0].y);
|
|
30933
|
+
if (len > best) {
|
|
30934
|
+
best = len;
|
|
30935
|
+
probe = s;
|
|
30936
|
+
}
|
|
30937
|
+
}
|
|
30938
|
+
const p = evalSeg(probe, 0.5);
|
|
30939
|
+
let tan = derivSeg(probe, 0.5);
|
|
30940
|
+
const tl = Math.hypot(tan.x, tan.y);
|
|
30941
|
+
if (tl === 0) continue;
|
|
30942
|
+
tan = { x: tan.x / tl, y: tan.y / tl };
|
|
30943
|
+
const left = filled({ x: p.x - tan.y * eps, y: p.y + tan.x * eps });
|
|
30944
|
+
const right = filled({ x: p.x + tan.y * eps, y: p.y - tan.x * eps });
|
|
30945
|
+
if (left && !right) out.push(contour);
|
|
30946
|
+
else if (right && !left) out.push(reverseContour(contour));
|
|
30947
|
+
}
|
|
30948
|
+
return out;
|
|
30949
|
+
}
|
|
30950
|
+
function findCrossings(boundaries, a, b) {
|
|
30951
|
+
const d = { x: b.x - a.x, y: b.y - a.y };
|
|
30952
|
+
const dd = d.x * d.x + d.y * d.y;
|
|
30953
|
+
const out = [];
|
|
30954
|
+
const push = (contour, seg, t, before, after) => {
|
|
30955
|
+
const pt = evalSeg(boundaries[contour][seg], t);
|
|
30956
|
+
const s = ((pt.x - a.x) * d.x + (pt.y - a.y) * d.y) / dd;
|
|
30957
|
+
if (s < 0 || s > 1) return;
|
|
30958
|
+
out.push({ contour, seg, t, pt, s, enters: before > 0 && after < 0 });
|
|
30959
|
+
};
|
|
30960
|
+
boundaries.forEach((contour, ci) => {
|
|
30961
|
+
const fs = contour.map((s) => sideCoeffs(s, a, d));
|
|
30962
|
+
const n = contour.length;
|
|
30963
|
+
fs.forEach((f, si) => {
|
|
30964
|
+
for (const c of signChanges(f, false)) push(ci, si, c.t, c.before, c.after);
|
|
30965
|
+
if (f[0] !== 0) return;
|
|
30966
|
+
const after = endSide(f, true);
|
|
30967
|
+
if (after === 0) return;
|
|
30968
|
+
let before = 0;
|
|
30969
|
+
for (let k = 1; k <= n && before === 0; k++) before = endSide(fs[(si - k + n) % n], false);
|
|
30970
|
+
if (before !== 0 && before !== after) push(ci, si, 0, before, after);
|
|
30971
|
+
});
|
|
30972
|
+
});
|
|
30973
|
+
return out.sort((x, y) => x.s - y.s);
|
|
30974
|
+
}
|
|
30975
|
+
function traceLoops(boundaries, partner) {
|
|
30976
|
+
const byContour = /* @__PURE__ */ new Map();
|
|
30977
|
+
for (const c of partner.keys()) {
|
|
30978
|
+
const list2 = byContour.get(c.contour) ?? [];
|
|
30979
|
+
list2.push(c);
|
|
30980
|
+
byContour.set(c.contour, list2);
|
|
30981
|
+
}
|
|
30982
|
+
const arcFrom = /* @__PURE__ */ new Map();
|
|
30983
|
+
const untouched = [];
|
|
30984
|
+
boundaries.forEach((contour, ci) => {
|
|
30985
|
+
const cuts = byContour.get(ci);
|
|
30986
|
+
if (!cuts) {
|
|
30987
|
+
untouched.push(contour);
|
|
30988
|
+
return;
|
|
30989
|
+
}
|
|
30990
|
+
cuts.sort((x, y) => x.seg - y.seg || x.t - y.t);
|
|
30991
|
+
for (let k = 0; k < cuts.length; k++) {
|
|
30992
|
+
const from = cuts[k], to = cuts[(k + 1) % cuts.length];
|
|
30993
|
+
arcFrom.set(from, { segs: arcBetween(contour, from, to, cuts.length === 1), end: to });
|
|
30994
|
+
}
|
|
30995
|
+
});
|
|
30996
|
+
const loops = [];
|
|
30997
|
+
const seen = /* @__PURE__ */ new Set();
|
|
30998
|
+
for (const start of arcFrom.keys()) {
|
|
30999
|
+
if (seen.has(start)) continue;
|
|
31000
|
+
const loop = [];
|
|
31001
|
+
let at = start;
|
|
31002
|
+
while (!seen.has(at)) {
|
|
31003
|
+
seen.add(at);
|
|
31004
|
+
const arc = arcFrom.get(at);
|
|
31005
|
+
loop.push(...arc.segs);
|
|
31006
|
+
const other = partner.get(arc.end);
|
|
31007
|
+
loop.push([arc.end.pt, other.pt]);
|
|
31008
|
+
at = other;
|
|
31009
|
+
}
|
|
31010
|
+
loops.push(loop);
|
|
31011
|
+
}
|
|
31012
|
+
return { loops, untouched };
|
|
31013
|
+
}
|
|
31014
|
+
function arcBetween(contour, from, to, whole) {
|
|
31015
|
+
const out = [];
|
|
31016
|
+
const add = (s) => {
|
|
31017
|
+
if (s) out.push(s);
|
|
30171
31018
|
};
|
|
30172
|
-
|
|
30173
|
-
|
|
31019
|
+
if (!whole && to.seg === from.seg && to.t > from.t) {
|
|
31020
|
+
add(subSeg(contour[from.seg], from.t, to.t, from.pt, to.pt));
|
|
31021
|
+
return out;
|
|
31022
|
+
}
|
|
31023
|
+
const n = contour.length;
|
|
31024
|
+
const first = contour[from.seg];
|
|
31025
|
+
add(subSeg(first, from.t, 1, from.pt, first[first.length - 1]));
|
|
31026
|
+
for (let i = (from.seg + 1) % n; i !== to.seg; i = (i + 1) % n) out.push(contour[i]);
|
|
31027
|
+
const last = contour[to.seg];
|
|
31028
|
+
add(subSeg(last, 0, to.t, last[0], to.pt));
|
|
31029
|
+
return out;
|
|
31030
|
+
}
|
|
31031
|
+
function assembleRegions(outers, holes) {
|
|
31032
|
+
const regions = outers.map((o) => ({ loops: [o], ring: sampleContour(o), area: signedArea2(o) }));
|
|
31033
|
+
for (const h of holes) {
|
|
31034
|
+
const hp = evalSeg(h[0], 0.5);
|
|
31035
|
+
let best = null;
|
|
31036
|
+
for (const r of regions) {
|
|
31037
|
+
if (pointInPolygon(r.ring, hp.x, hp.y) && (!best || r.area < best.area)) best = r;
|
|
31038
|
+
}
|
|
31039
|
+
best?.loops.push(h);
|
|
31040
|
+
}
|
|
31041
|
+
return regions.map((r) => r.loops);
|
|
30174
31042
|
}
|
|
30175
|
-
|
|
30176
|
-
|
|
31043
|
+
var regionArea = (r) => r.reduce((s, c) => s + signedArea2(c), 0);
|
|
31044
|
+
function toPath(loops, fillRule) {
|
|
31045
|
+
const cmds = [];
|
|
31046
|
+
const xs = [];
|
|
31047
|
+
for (const loop of loops) {
|
|
31048
|
+
cmds.push(PATH_M);
|
|
31049
|
+
xs.push(loop[0][0].x, loop[0][0].y);
|
|
31050
|
+
for (const s of loop) {
|
|
31051
|
+
cmds.push(s.length === 2 ? PATH_L : s.length === 3 ? PATH_Q : PATH_C);
|
|
31052
|
+
for (let i = 1; i < s.length; i++) xs.push(s[i].x, s[i].y);
|
|
31053
|
+
}
|
|
31054
|
+
cmds.push(PATH_Z);
|
|
31055
|
+
}
|
|
31056
|
+
return { kind: "polygon", commands: new Uint8Array(cmds), coords: new Float32Array(xs), fillRule };
|
|
30177
31057
|
}
|
|
30178
31058
|
|
|
30179
31059
|
// src/features/paths/unionBoundsPath.ts
|
|
@@ -30471,13 +31351,13 @@ function findSpan(n, p, u, knots) {
|
|
|
30471
31351
|
if (u <= knots[p]) return p;
|
|
30472
31352
|
let lo = p;
|
|
30473
31353
|
let hi = n;
|
|
30474
|
-
let
|
|
30475
|
-
while (u < knots[
|
|
30476
|
-
if (u < knots[
|
|
30477
|
-
else lo =
|
|
30478
|
-
|
|
31354
|
+
let mid = lo + hi >> 1;
|
|
31355
|
+
while (u < knots[mid] || u >= knots[mid + 1]) {
|
|
31356
|
+
if (u < knots[mid]) hi = mid;
|
|
31357
|
+
else lo = mid;
|
|
31358
|
+
mid = lo + hi >> 1;
|
|
30479
31359
|
}
|
|
30480
|
-
return
|
|
31360
|
+
return mid;
|
|
30481
31361
|
}
|
|
30482
31362
|
function basisFunctions(i, u, p, knots) {
|
|
30483
31363
|
const N = new Array(p + 1).fill(0);
|
|
@@ -32168,7 +33048,7 @@ function useRig(options) {
|
|
|
32168
33048
|
}
|
|
32169
33049
|
|
|
32170
33050
|
// src/layout/snaps.ts
|
|
32171
|
-
function
|
|
33051
|
+
function dist2(a, b) {
|
|
32172
33052
|
const dx = a.x - b.x;
|
|
32173
33053
|
const dy = a.y - b.y;
|
|
32174
33054
|
return dx * dx + dy * dy;
|
|
@@ -32176,9 +33056,9 @@ function dist22(a, b) {
|
|
|
32176
33056
|
function nearestOf(targets, pointer) {
|
|
32177
33057
|
if (targets.length === 0) return null;
|
|
32178
33058
|
let best = targets[0];
|
|
32179
|
-
let bestD =
|
|
33059
|
+
let bestD = dist2(best.origin, pointer);
|
|
32180
33060
|
for (let i = 1; i < targets.length; i++) {
|
|
32181
|
-
const d =
|
|
33061
|
+
const d = dist2(targets[i].origin, pointer);
|
|
32182
33062
|
if (d < bestD) {
|
|
32183
33063
|
bestD = d;
|
|
32184
33064
|
best = targets[i];
|
|
@@ -32198,7 +33078,7 @@ function nearestWithin(opts) {
|
|
|
32198
33078
|
pickTarget(targets, pointer) {
|
|
32199
33079
|
const got = nearestOf(targets, pointer);
|
|
32200
33080
|
if (got === null) return null;
|
|
32201
|
-
return
|
|
33081
|
+
return dist2(got.origin, pointer) <= tol2 ? got : null;
|
|
32202
33082
|
}
|
|
32203
33083
|
};
|
|
32204
33084
|
}
|
|
@@ -32487,6 +33367,6 @@ function mergeContributions(...bundles) {
|
|
|
32487
33367
|
return out;
|
|
32488
33368
|
}
|
|
32489
33369
|
|
|
32490
|
-
export { ACTION_GLYPHS, ANCHOR_HIT_BASE_PX, ActionsProviderIfRoot, AlignBottomIcon, AlignCenterXIcon, AlignCenterYIcon, AlignLeftIcon, AlignRightIcon, AlignTopIcon, ArrowIcon, BUILTIN_MARKERS,
|
|
32491
|
-
//# sourceMappingURL=chunk-
|
|
32492
|
-
//# sourceMappingURL=chunk-
|
|
33370
|
+
export { ACTION_GLYPHS, ANCHOR_HIT_BASE_PX, AREA_SELECT_ID, ActionsProviderIfRoot, AlignBottomIcon, AlignCenterXIcon, AlignCenterYIcon, AlignLeftIcon, AlignRightIcon, AlignTopIcon, ArrowIcon, BUILTIN_MARKERS, BUILTIN_TOOL_IDS, BringForwardIcon, BringToFrontIcon, CROSSHAIR_HALO, CURVE_REPS, CanvasView, ColorOverrideRegistry, CopyIcon, CropIcon, CursorCoordsHud, CutIcon, DEFAULT_DEBUG_STROKES, DEFAULT_DEBUG_THEME, DEFAULT_FILL_COLOR, DEFAULT_HANDLE_SIZE2 as DEFAULT_HANDLE_SIZE, DEFAULT_MAX_ZOOM, DEFAULT_MIN_ZOOM, DEFAULT_PALETTE, DEFAULT_ROTATION_HANDLE_DISTANCE, DEFAULT_SHAPE_FILL, DEFAULT_STROKE_COLOR, DRAG_PAN_ID, DeleteIcon, DepRegistryProviderIfRoot, DeviceProfileProvider, DistributeHorizontalIcon, DistributeVerticalIcon, DivideIcon, DuplicateIcon, EASINGS, EFFECT_KIT_UNIFORMS, EFFECT_VERT_SRC, EllipseIcon, ExcludeIcon, EyedropperIcon, FALLBACK_FIT_VIEW, FEATURE_ACTION_IDS, FlipXIcon, FlipYIcon, GHOST_STROKE, GroupIcon, HANDLE_BASE_PX, HandIcon, IDENTITY_COLOR_MATRIX, IDENTITY_JOINT, IDENTITY_POSE_COMPOSITION, ImageIcon, IntersectIcon, KIT_SHAPE_KINDS, KIT_STANDARD_ACTION_IDS, LassoIcon, LineIcon, MESH_BAKE_SIZE, MESH_GRADIENT_KIND, MINIMAP_CENTER, MINIMAP_PAN, MIXED, MOVE_ANCHORS, MinimapCanvas, OUTLINE_MIN_SCREEN_PX, PAINTED_CURSOR_LAYER_ID, PATH_ANCHOR_CHROME_ID, PasteIcon, PenIcon, PencilIcon, PickHud, PointerProviderIfRoot, PolygonIcon, RECT_POSE_COMPOSITION, RIGID_POSE_COMPOSITION, ROTATION_HANDLE_BASE_PX, RectIcon, RedoIcon, SCENE_CANVAS_FEATURES, SELECTION_MOVE_ID, SELECTION_TRANSFORM_ID, SPRING_PRESETS, SPRITE_STRIDE, SceneCanvas, SceneViewCanvas, SelectIcon, SelectionContextProvider, SelectionContextProviderIfRoot, SendBackwardIcon, SendToBackIcon, ShaderCompileError, StarIcon, SubtractIcon, TOOL_DRIVEN_ACTION_IDS, TOOL_PREF_KINDS, TextIcon, UNION_OF_CHILDREN, UndoIcon, UngroupIcon, UnionIcon, UnknownIcon, VERSION, VIEW_ANIMATION_KEY, WHEEL_ZOOM_STEP, WeaselProvider, WeaselRenderer, ZOOM_FLOOR, _resetMarkersForTests, _resetPaintKindsForTests, actionIs, actionShortcuts, alignDeltaFor, alignInsertBehavior, alignMoveBehavior, alignResizeBehavior, always, and, animateLifecycle, animateOnSetPose, annulusSemiAxes, applyBooleanOp, applyStyleToRange, areaSelectAction, areaSelectContribution, arrayAdapter, asNodeId, asPaint, bakeMesh, bezierCubic, bezierQuadratic, bindRig, blendPoses, blur, buildChromeCtx, buildGradientRamp, buildSceneViewCommands, canBringForward, canHover, canSendBackward, capabilityAll, capabilityIn, capabilityIs, capabilityNot, caretIndexAt, cellAt, centerRootOn, charOffsetToDomPosition, circlePath, clampView, clearSelectionAction, clipboardCopyAction, clipboardCutAction, clipboardPasteAction, cloneAction, coarsePointer, composeAffordanceLayer, composePath, composeRectPose, composeRigidPose, composeSelectionPose, composeWorldPose, computeFitView, computeFitViewport, computeIndicatorCommand, computeWheelAction, cond, constrainTo45, containedThenNearest, cornerWeights, countPathAnchors, createCellHighlightLayer, createChildrenLayer, createCornerResizeAffordance, createDebugOverlayLayer, createDebugSink, createGridLayer, createGuidesLayer, createHistory2 as createHistory, createKeyState, createLinkedCursorContribution, createMinimapContribution, createMoveToIndexOp, createNodeProperties, createNodeRouting, createPaintedCursorLayer, createParallaxLayer, createPathAnchorAffordances, createPathEditingOverlayLayer, createPathLayer, createPenPreviewLayer, createPoseFeed, createPoseOverrides, createReorderOp, createRotationAffordance, createScene, createSelectionHandlesLayer, createSelectionOutlineLayer, createSelectionOverlayLayer, createSetDataOp, createSetLayerOp, createSetPathOp, createSetTextOp, createSlew, createTextLayer, createTiledLayer, createVelocityTracker, createViewResolver, createViewportLayer, crosshairRects, cubicBezierEasing, cullDrawCommands, cycleFill, cycleVertexColors, decomposePath, decomposeRectPose, decomposeRigidPose, defaultCommitAdapter, defaultDrawOne, defaultLabelTextRenderer, defaultNodeProperties, defaultNodeRouting, defaultVisibilityRules, definesFrame, deriveAlignmentGuides, deriveParallaxView, derivedDepOf, derivedPose, documentPose, domPositionToCharOffset, domToRuns, dragPanContribution, drawLayers, drawOneLayer, easeIn, easeInBack, easeInBounce, easeInCirc, easeInCubic, easeInElastic, easeInExpo, easeInOut, easeInOutBack, easeInOutBounce, easeInOutCirc, easeInOutCubic, easeInOutElastic, easeInOutExpo, easeInOutQuad, easeInOutQuart, easeInOutQuint, easeInOutSine, easeInQuad, easeInQuart, easeInQuint, easeInSine, easeOut, easeOutBack, easeOutBounce, easeOutCirc, easeOutCubic, easeOutElastic, easeOutExpo, easeOutQuad, easeOutQuart, easeOutQuint, easeOutSine, editAnchorsAction, effectivePose, effectiveRangeStyle, enterTextEditAction, enumerateAnchors, evalPatch, fillInPoseFrame, fillToBoundsFrame, findNodeShape, findShapeInk, findShapeSilhouette, fitTextPose, fitToBounds, fitViewToBounds, fitZoom, flattenPreviews, focused, forEachCoalesced, frameRect, freeform, gateLayer, gesturing, getAlpha01, getImageBitmap, getMarker, getNodeShapes, getPaintKind, getStylusData, gradientForBounds, gradientGeometry, hexToRgba, hitAffordanceRegions, hitAnchor, hitRotationHandle, hostAnchorCss, hostAnchorRect, hovering, hoveringSelected, imageStatus, inferredNodeProperties, inferredNodeRouting, insertAction, insertPreviewExtent, interpolateView, isBuiltinToolPref, isGradientFill, isLayerPainted, isLayerVisible, isMeshGradientFill, isPatternSpec, isPlainObject, isTensorPatch, isValidPatch, isVectorImageSrc, keySpecShortcut, lassoSelectAction, linear, listGradientKinds, listMarkers, listPaintKinds, makePinchZoomAction, makeViewportWheelPanAction, makeViewportZoomAction, markerInset, markerKeyOf, markerRegistry, markerSites, mat3, matchAlignment, meanScale, mergeAlphaFromPrev, mergeContributions, meshBounds, meshFromStops, meshGradientXml, meshStops, minimapCenterAction, minimapPanAction, modeDecorationLayer, modeIn, modeIs, modeNot, modifierHeld, momentum, moveAction, multiActive, nearest, nearestWithin, nestedHitTester, never, nodeHasFlag, none, normalizeHex, normalizeView, normalizeZoom, not, nurbs, onEmptyCanvas, openFilePicker, or, paintAlpha, paintKindOf, paintKindRegistry, paintWithAlpha, paintWithColor, parseColor, parseColorToRgba255, parseDebugFlags, patchBounds, patchCorner, pathContainsPoint, pathContainsPolygon, pathContainsRect, pathDistanceToPoint, pathDivide, pathExclude, pathFromD, pathInPoseFrame, pathInWorld, pathIntersect, pathIntersectsPolygon, pathIntersectsRect, pathOriginProjection, pathSubtract, pathToAnchors, pathUnion, pickTopMostHit, pinchZoomAction, planPixelRender, pointInTextPose, poseRotationOf, prefUnit, pressureToWidth, programSourceRegistry, rainbowVertexColors, rebaseLocalPose, rectMarkerPath, registerContentHandler, registerEffect, registerMarker, registerNodeShape, registerPaintKind, registerProgram, renderLabel, renderSceneToCanvas, renderSceneToPixels, resizeAction, resolveColor, resolveEasing, resolveFillPattern, resolveMarkerSize, resolveOverlays, resolvePatternSpec, resolvePreviews, resolveSkeleton, resolveStrokeWidth, resolveVisibility, rgbaToHex, rigidRigApply, rotateAction, rotateAroundAABBCenter, rotatePathAround, rotationDegreesUnit, rotationHandle, roundRectPath, roundToCell, runsToDom, sampleGradientStops, sampleTrack, sceneFromJSON, sceneNodeClientRect, sceneSelectionStore, sceneToAdapter, screenToWorld, seedMeshPatch, selectFromLasso, selectionAtLeast, selectionEmpty, selectionIs, selectionMoveBindings, selectionMoveContribution, selectionTransformBindings, selectionTransformContribution, setFlagOverRange, shapeCoversPoint, slewToward, sliceAction, snapPoint, solid, solidVertexColors, spiro, splitPathBySegment, splitSubpaths, springPose, springVertexColors, squarePath, staggerVertexColors, startThresholdDrag, strokeInsets, strokeOf, strokeWith, styleAtRange, subscribeImageReady, subscribeToSources, switchGradientKind, tessellate, tessellateStroke, textCommand, textCommandFromPose, textCommandFromRuns, tileGrid, tiledProject, toHex8, translateRectPose, trimPolyline, tweenPose, tweenVertexColors, unionBoundsPath, unionOfChildren, unionOfChildrenVia, useAlign, useAnimator, useArrayAdapter, useAutoCenter, useBooleans, useBooleansAdapter, useCanvasFocus, useCanvasSize, useDecayLoop, useDeviceProfile, useDistribute, useDragGesture, useDragHandle, useDragRadial, useDragRect, useDropZone, useEllipseTool, useEyedropperTool, useGridCellHover, useGuides, useHandTool, useHandleDrag, useHostAnchor, useHoverTracking, useImageTool, useKeyState, useKeybindings, useLassoTool, useLineTool, useNodeOverlayFrame, usePenTool, usePencilTool, usePointerStylus, usePolygonTool, usePoseCompositionDepSource, usePoseDescriptorDepSource, usePoseRun, usePublishSelection, useRectTool, useResizePolicy, useRig, useScene, useSceneAdapter, useSceneTextEdit, useSelectTool, useSelection, useSelectionContext, useSimulation, useSliceDep, useStandardActions, useStarTool, useTextEdit, useTextTool, useTools, useVelocityTracker, useViewAnimation, useViewAnimationOn, useVisibleRaf, viewToMat3, viewToTransform, viewZoom, viewportDragPanAction, viewportWheelPanAction, viewportZoomAction, viewportsAt, vignette, wheelPan, wheelZoom, wheelZoomFactor, when, withAlpha01, withCoord, withGradientKind, workspaceTintLayer, worldEditToStorage, worldPoseLookup, worldToScreen, zoomAt, zoomAtLeast };
|
|
33371
|
+
//# sourceMappingURL=chunk-G4ZGQMY7.js.map
|
|
33372
|
+
//# sourceMappingURL=chunk-G4ZGQMY7.js.map
|