@weasel-js/labkit 0.7.2 → 0.8.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/LICENSE +21 -0
- package/dist/_dts/{DrawCommand-CEvS5AdV.d.ts → DrawCommand-DACv9lhe.d.ts} +34 -46
- package/dist/{chunk-5XDFILHZ.js → chunk-6V7ROR7G.js} +493 -99
- package/dist/chunk-6V7ROR7G.js.map +1 -0
- package/dist/{chunk-BG6NLMOL.js → chunk-FBZCQXI2.js} +3 -3
- package/dist/{chunk-BG6NLMOL.js.map → chunk-FBZCQXI2.js.map} +1 -1
- package/dist/{chunk-ERZQAU4N.js → chunk-OHGEOTCV.js} +3 -3
- package/dist/{chunk-ERZQAU4N.js.map → chunk-OHGEOTCV.js.map} +1 -1
- package/dist/fonts/inter-latin.woff2 +0 -0
- package/dist/fonts/oswald-latin-variable.woff2 +0 -0
- package/dist/index.js +3 -3
- package/dist/passthrough/weasel-canvas.d.ts +1 -1
- package/dist/passthrough/weasel-canvas.js +1 -1
- package/dist/passthrough/weasel-ui.d.ts +237 -122
- package/dist/passthrough/weasel-ui.js +2 -2
- package/dist/styles.css +1 -1
- package/dist/ui/layers/index.js +3 -3
- package/package.json +3 -2
- package/src/theme/base.less +3 -2
- package/dist/chunk-5XDFILHZ.js.map +0 -1
- package/src/fonts/oswald-latin-variable.woff2 +0 -0
|
@@ -21,6 +21,7 @@ var GESTURE_DESCRIPTORS = [
|
|
|
21
21
|
{ name: "keyUp", hasTarget: false, arg: { name: "key", values: "free" } },
|
|
22
22
|
{ name: "keyHeld", hasTarget: false, arg: { name: "key", values: "free" } },
|
|
23
23
|
{ name: "contextMenu", hasTarget: true },
|
|
24
|
+
{ name: "longPress", hasTarget: true },
|
|
24
25
|
{ name: "multiTouchTap", hasTarget: false, arg: { name: "fingers", values: ["2", "3", "4"] } }
|
|
25
26
|
];
|
|
26
27
|
var BY_NAME = new Map(
|
|
@@ -318,6 +319,8 @@ function actionClause(parsed, required) {
|
|
|
318
319
|
return `the user taps with ${parsed.arg ?? "multiple"} fingers`;
|
|
319
320
|
case "contextMenu":
|
|
320
321
|
return `the user ${modPrefix}opens the context menu${target}`;
|
|
322
|
+
case "longPress":
|
|
323
|
+
return `the user ${modPrefix}presses and holds${target}`;
|
|
321
324
|
case "click":
|
|
322
325
|
return `the user ${modPrefix}clicks${target}`;
|
|
323
326
|
case "pointerDown":
|
|
@@ -502,6 +505,11 @@ function matchSpec(e, spec, isMac, phaseCtx) {
|
|
|
502
505
|
if (!matchModifiers(e, spec.mods, isMac)) return false;
|
|
503
506
|
return matchTarget(e.target, spec.target, e.bodyTarget, e.bodyKind);
|
|
504
507
|
}
|
|
508
|
+
case "longPress": {
|
|
509
|
+
if (e.kind !== "longpress") return false;
|
|
510
|
+
if (!matchModifiers(e, spec.mods, isMac)) return false;
|
|
511
|
+
return matchTarget(e.affordance, spec.target, e.bodyTarget, e.bodyKind);
|
|
512
|
+
}
|
|
505
513
|
case "drag": {
|
|
506
514
|
if (e.kind !== "pointerdown") return false;
|
|
507
515
|
if (e.stage === "press") return false;
|
|
@@ -540,7 +548,7 @@ function matchSpec(e, spec, isMac, phaseCtx) {
|
|
|
540
548
|
}
|
|
541
549
|
var EMPTY_ENGAGED = /* @__PURE__ */ new Set();
|
|
542
550
|
|
|
543
|
-
// ../core/dist/chunk-
|
|
551
|
+
// ../core/dist/chunk-6DAUIMTO.js
|
|
544
552
|
var routing_exports = {};
|
|
545
553
|
__export(routing_exports, {
|
|
546
554
|
GESTURE_DESCRIPTORS: () => GESTURE_DESCRIPTORS,
|
|
@@ -613,6 +621,7 @@ var SPEC_KIND_TO_GESTURE = {
|
|
|
613
621
|
click: "click",
|
|
614
622
|
doubleClick: "dblTap",
|
|
615
623
|
contextMenu: "contextMenu",
|
|
624
|
+
longPress: "longPress",
|
|
616
625
|
drag: "drag",
|
|
617
626
|
pointerDown: "pointerDown",
|
|
618
627
|
multiTouch: void 0,
|
|
@@ -873,7 +882,7 @@ function transformCoords(coords, m) {
|
|
|
873
882
|
return out;
|
|
874
883
|
}
|
|
875
884
|
|
|
876
|
-
// ../core/dist/chunk-
|
|
885
|
+
// ../core/dist/chunk-GLZLSPGJ.js
|
|
877
886
|
function resolveUnit(v, unitSystem) {
|
|
878
887
|
if (typeof v === "number") return v;
|
|
879
888
|
if (!unitSystem) {
|
|
@@ -1584,7 +1593,7 @@ function createDeleteOp(args) {
|
|
|
1584
1593
|
}
|
|
1585
1594
|
registerOpFactory("delete", (args) => createDeleteOp(args));
|
|
1586
1595
|
|
|
1587
|
-
// ../core/dist/chunk-
|
|
1596
|
+
// ../core/dist/chunk-BPRHGTLQ.js
|
|
1588
1597
|
function createTransformOp(args) {
|
|
1589
1598
|
const { id, from, to, label, coalesceKey = `transform:${id}` } = args;
|
|
1590
1599
|
return {
|
|
@@ -1665,7 +1674,7 @@ function snap(strategy, opts = {}) {
|
|
|
1665
1674
|
};
|
|
1666
1675
|
}
|
|
1667
1676
|
|
|
1668
|
-
// ../core/dist/chunk-
|
|
1677
|
+
// ../core/dist/chunk-CMBE45MT.js
|
|
1669
1678
|
function lockAspectWithModifier(opts = {}) {
|
|
1670
1679
|
const { key = "shift" } = opts;
|
|
1671
1680
|
return {
|
|
@@ -2210,17 +2219,17 @@ function dynamicPageTextureId(page) {
|
|
|
2210
2219
|
return `weasel-dyn-sdf-page-${page}`;
|
|
2211
2220
|
}
|
|
2212
2221
|
var uploadedVersions = /* @__PURE__ */ new WeakMap();
|
|
2213
|
-
function syncDynamicPageTexture(
|
|
2222
|
+
function syncDynamicPageTexture(cache6, pageIndex) {
|
|
2214
2223
|
const page = pages[pageIndex];
|
|
2215
2224
|
if (!page) return false;
|
|
2216
2225
|
const id = dynamicPageTextureId(pageIndex);
|
|
2217
|
-
let seen = uploadedVersions.get(
|
|
2226
|
+
let seen = uploadedVersions.get(cache6);
|
|
2218
2227
|
if (!seen) {
|
|
2219
2228
|
seen = /* @__PURE__ */ new Map();
|
|
2220
|
-
uploadedVersions.set(
|
|
2229
|
+
uploadedVersions.set(cache6, seen);
|
|
2221
2230
|
}
|
|
2222
|
-
if (!
|
|
2223
|
-
|
|
2231
|
+
if (!cache6.has(id)) {
|
|
2232
|
+
cache6.uploadR8(id, PAGE_SIZE, PAGE_SIZE, page.data);
|
|
2224
2233
|
seen.set(pageIndex, page.version);
|
|
2225
2234
|
return true;
|
|
2226
2235
|
}
|
|
@@ -2233,7 +2242,7 @@ function syncDynamicPageTexture(cache5, pageIndex) {
|
|
|
2233
2242
|
const src = (patch.y + row) * PAGE_SIZE + patch.x;
|
|
2234
2243
|
tight.set(page.data.subarray(src, src + patch.w), row * patch.w);
|
|
2235
2244
|
}
|
|
2236
|
-
|
|
2245
|
+
cache6.subImageR8(id, patch.x, patch.y, patch.w, patch.h, tight);
|
|
2237
2246
|
}
|
|
2238
2247
|
seen.set(pageIndex, page.version);
|
|
2239
2248
|
return true;
|
|
@@ -2441,6 +2450,23 @@ var slots = /* @__PURE__ */ new Map();
|
|
|
2441
2450
|
function slotKey(family, weight, style) {
|
|
2442
2451
|
return `${family}|${weight}|${style}`;
|
|
2443
2452
|
}
|
|
2453
|
+
function closeContours(d) {
|
|
2454
|
+
let out = "";
|
|
2455
|
+
let start = 0;
|
|
2456
|
+
for (let i = 1; i < d.length; i++) {
|
|
2457
|
+
const c = d[i];
|
|
2458
|
+
if (c !== "M" && c !== "m") continue;
|
|
2459
|
+
out += closeOne(d.slice(start, i));
|
|
2460
|
+
start = i;
|
|
2461
|
+
}
|
|
2462
|
+
return out + closeOne(d.slice(start));
|
|
2463
|
+
}
|
|
2464
|
+
function closeOne(contour) {
|
|
2465
|
+
const trimmed = contour.trimEnd();
|
|
2466
|
+
if (trimmed.length === 0) return "";
|
|
2467
|
+
const last = trimmed[trimmed.length - 1];
|
|
2468
|
+
return last === "Z" || last === "z" ? trimmed : `${trimmed}Z`;
|
|
2469
|
+
}
|
|
2444
2470
|
function glyphOutline(family, weight, style, cp) {
|
|
2445
2471
|
const slot = slots.get(slotKey(family, weight, style));
|
|
2446
2472
|
if (!slot) return null;
|
|
@@ -2453,7 +2479,8 @@ function glyphOutline(family, weight, style, cp) {
|
|
|
2453
2479
|
if (cached2 !== void 0) return cached2;
|
|
2454
2480
|
let d = null;
|
|
2455
2481
|
try {
|
|
2456
|
-
|
|
2482
|
+
const raw = slot.face.glyphD(cp);
|
|
2483
|
+
d = raw === null ? null : closeContours(raw);
|
|
2457
2484
|
} catch (err) {
|
|
2458
2485
|
warnOnce(
|
|
2459
2486
|
`glyph|${slotKey(family, weight, style)}`,
|
|
@@ -2982,7 +3009,7 @@ function serialToEntry(se, custom, logger) {
|
|
|
2982
3009
|
};
|
|
2983
3010
|
}
|
|
2984
3011
|
|
|
2985
|
-
// ../core/dist/chunk-
|
|
3012
|
+
// ../core/dist/chunk-DLV5F4NY.js
|
|
2986
3013
|
function worldToScreen(worldX, worldY, view) {
|
|
2987
3014
|
return [view.panX + worldX * view.zoom.x, view.panY + worldY * view.zoom.y];
|
|
2988
3015
|
}
|
|
@@ -4355,6 +4382,16 @@ function extractPolygon(p, opts) {
|
|
|
4355
4382
|
out.push(next);
|
|
4356
4383
|
return next;
|
|
4357
4384
|
};
|
|
4385
|
+
const dropDuplicateClosingPoint = () => {
|
|
4386
|
+
if (!pts || !aA || !aB || !aT) return;
|
|
4387
|
+
const n = pts.length / 2;
|
|
4388
|
+
if (n < 2) return;
|
|
4389
|
+
if (pts[0] !== pts[(n - 1) * 2] || pts[1] !== pts[(n - 1) * 2 + 1]) return;
|
|
4390
|
+
pts.length -= 2;
|
|
4391
|
+
aA.length -= 1;
|
|
4392
|
+
aB.length -= 1;
|
|
4393
|
+
aT.length -= 1;
|
|
4394
|
+
};
|
|
4358
4395
|
const commit = (target) => {
|
|
4359
4396
|
if (!pts || !aA || !aB || !aT) return;
|
|
4360
4397
|
target.anchorA = new Uint32Array(aA);
|
|
@@ -4438,7 +4475,10 @@ function extractPolygon(p, opts) {
|
|
|
4438
4475
|
break;
|
|
4439
4476
|
}
|
|
4440
4477
|
case PATH_Z2: {
|
|
4441
|
-
if (current)
|
|
4478
|
+
if (current) {
|
|
4479
|
+
current.closed = true;
|
|
4480
|
+
dropDuplicateClosingPoint();
|
|
4481
|
+
}
|
|
4442
4482
|
break;
|
|
4443
4483
|
}
|
|
4444
4484
|
default:
|
|
@@ -4919,8 +4959,20 @@ function sameFill(a, b) {
|
|
|
4919
4959
|
}
|
|
4920
4960
|
return false;
|
|
4921
4961
|
}
|
|
4922
|
-
function
|
|
4923
|
-
|
|
4962
|
+
function strokeKey(s) {
|
|
4963
|
+
if (!s) return "-";
|
|
4964
|
+
return [
|
|
4965
|
+
fillKey(s.paint),
|
|
4966
|
+
s.width ?? 1,
|
|
4967
|
+
s.join ?? "miter",
|
|
4968
|
+
s.cap ?? "butt",
|
|
4969
|
+
s.miterLimit ?? "",
|
|
4970
|
+
s.align ?? "center",
|
|
4971
|
+
(s.dash ?? []).join(",")
|
|
4972
|
+
].join(":");
|
|
4973
|
+
}
|
|
4974
|
+
function groupKey(family, weight, style, synthetic, fill, stroke, source, page) {
|
|
4975
|
+
return `${family}|${weight}|${style}|${synthetic.bold ? 1 : 0}${synthetic.italic ? 1 : 0}|${fillKey(fill)}|${strokeKey(stroke)}|${source}|${page}`;
|
|
4924
4976
|
}
|
|
4925
4977
|
function getOrCreateGroup(ctx, run, resolved, page, sourceOverride) {
|
|
4926
4978
|
const atlasFamily = resolved.resolved.family;
|
|
@@ -4933,6 +4985,7 @@ function getOrCreateGroup(ctx, run, resolved, page, sourceOverride) {
|
|
|
4933
4985
|
resolvedStyle,
|
|
4934
4986
|
resolved.synthetic,
|
|
4935
4987
|
run.fill,
|
|
4988
|
+
source === "outline" ? run.stroke : void 0,
|
|
4936
4989
|
source,
|
|
4937
4990
|
page
|
|
4938
4991
|
);
|
|
@@ -4946,6 +4999,9 @@ function getOrCreateGroup(ctx, run, resolved, page, sourceOverride) {
|
|
|
4946
4999
|
source,
|
|
4947
5000
|
page,
|
|
4948
5001
|
fill: run.fill,
|
|
5002
|
+
// Only the outline tier can paint it, and carrying it on an SDF group
|
|
5003
|
+
// would be a promise the renderer cannot keep.
|
|
5004
|
+
...source === "outline" && run.stroke !== void 0 ? { stroke: run.stroke } : {},
|
|
4949
5005
|
quads: [],
|
|
4950
5006
|
glyphs: []
|
|
4951
5007
|
};
|
|
@@ -5542,6 +5598,34 @@ function outlineMesh(key, d) {
|
|
|
5542
5598
|
cache3.set(key, mesh);
|
|
5543
5599
|
return mesh;
|
|
5544
5600
|
}
|
|
5601
|
+
var OUTLINE_STROKE_MESH_CACHE_LIMIT = 2048;
|
|
5602
|
+
var WIDTH_QUANTUM = 1 / 1024;
|
|
5603
|
+
var cache4 = /* @__PURE__ */ new Map();
|
|
5604
|
+
function quantizeEmWidth(emWidth) {
|
|
5605
|
+
return Math.round(emWidth / WIDTH_QUANTUM) * WIDTH_QUANTUM;
|
|
5606
|
+
}
|
|
5607
|
+
function outlineStrokeMesh(glyphKey, d, emWidth, stroke) {
|
|
5608
|
+
if (!(emWidth > 0)) return null;
|
|
5609
|
+
const key = [
|
|
5610
|
+
glyphKey,
|
|
5611
|
+
emWidth,
|
|
5612
|
+
stroke.join ?? "miter",
|
|
5613
|
+
stroke.cap ?? "butt",
|
|
5614
|
+
stroke.miterLimit ?? "",
|
|
5615
|
+
stroke.align ?? "center",
|
|
5616
|
+
(stroke.dash ?? []).join(",")
|
|
5617
|
+
].join("|");
|
|
5618
|
+
const cached2 = cache4.get(key);
|
|
5619
|
+
if (cached2 !== void 0) return cached2.indices.length === 0 ? null : cached2;
|
|
5620
|
+
if (cache4.size >= OUTLINE_STROKE_MESH_CACHE_LIMIT) cache4 = /* @__PURE__ */ new Map();
|
|
5621
|
+
const mesh = tessellateStroke(
|
|
5622
|
+
pathFromD(d),
|
|
5623
|
+
{ ...stroke, width: emWidth },
|
|
5624
|
+
{ flattenTolerance: OUTLINE_FLATTEN_TOLERANCE }
|
|
5625
|
+
);
|
|
5626
|
+
cache4.set(key, mesh);
|
|
5627
|
+
return mesh.indices.length === 0 ? null : mesh;
|
|
5628
|
+
}
|
|
5545
5629
|
function setColorMatrixUniforms(ctx, prog) {
|
|
5546
5630
|
const gl = ctx.gl;
|
|
5547
5631
|
const cm = ctx.state.colorMatrix;
|
|
@@ -6115,16 +6199,30 @@ function drawText(ctx, cmd) {
|
|
|
6115
6199
|
var SYNTHETIC_ITALIC_RADIANS = 0.2094;
|
|
6116
6200
|
function drawTextOutlineGroup(ctx, group, dy) {
|
|
6117
6201
|
const mesh = outlineGroupMesh(group, dy);
|
|
6118
|
-
if (
|
|
6119
|
-
|
|
6202
|
+
if (mesh) drawPathFillByKind(ctx, group.fill, ctx.meshCache.uploadTransient(mesh));
|
|
6203
|
+
if (!group.stroke) return;
|
|
6204
|
+
const strokeMesh = outlineGroupStrokeMesh(group, dy);
|
|
6205
|
+
if (strokeMesh) {
|
|
6206
|
+
drawPathFillByKind(ctx, group.stroke.paint, ctx.meshCache.uploadTransient(strokeMesh));
|
|
6207
|
+
}
|
|
6120
6208
|
}
|
|
6121
6209
|
function outlineGroupMesh(group, dy) {
|
|
6210
|
+
return mergeGlyphMeshes(group, dy, (glyph) => outlineMesh(glyph.key, glyph.d));
|
|
6211
|
+
}
|
|
6212
|
+
function outlineGroupStrokeMesh(group, dy) {
|
|
6213
|
+
const stroke = group.stroke;
|
|
6214
|
+
if (!stroke) return null;
|
|
6215
|
+
const width = stroke.width ?? 1;
|
|
6216
|
+
if (!(width > 0)) return null;
|
|
6217
|
+
return mergeGlyphMeshes(group, dy, (glyph) => glyph.scale > 0 ? outlineStrokeMesh(glyph.key, glyph.d, quantizeEmWidth(width / glyph.scale), stroke) : null);
|
|
6218
|
+
}
|
|
6219
|
+
function mergeGlyphMeshes(group, dy, meshFor) {
|
|
6122
6220
|
const parts = [];
|
|
6123
6221
|
let vertexFloats = 0;
|
|
6124
6222
|
let indexCount = 0;
|
|
6125
6223
|
for (const glyph of group.glyphs) {
|
|
6126
|
-
const mesh =
|
|
6127
|
-
if (mesh.indices.length === 0) continue;
|
|
6224
|
+
const mesh = meshFor(glyph);
|
|
6225
|
+
if (!mesh || mesh.indices.length === 0) continue;
|
|
6128
6226
|
parts.push({ mesh, glyph });
|
|
6129
6227
|
vertexFloats += mesh.vertices.length;
|
|
6130
6228
|
indexCount += mesh.indices.length;
|
|
@@ -6964,6 +7062,103 @@ function clientToCanvas(canvas, clientX, clientY) {
|
|
|
6964
7062
|
function clientToCanvasRect(rect, clientX, clientY) {
|
|
6965
7063
|
return [clientX - rect.left, clientY - rect.top];
|
|
6966
7064
|
}
|
|
7065
|
+
var COARSE_TARGET_SCALE = 1.75;
|
|
7066
|
+
function resolveDeviceProfile(detected, overrides) {
|
|
7067
|
+
const coarsePointer2 = overrides?.coarsePointer ?? detected.coarsePointer;
|
|
7068
|
+
const canHover2 = overrides?.canHover ?? detected.canHover;
|
|
7069
|
+
const dpr = overrides?.dpr ?? detected.dpr;
|
|
7070
|
+
const targetScale = overrides?.targetScale ?? (coarsePointer2 ? COARSE_TARGET_SCALE : 1);
|
|
7071
|
+
return { coarsePointer: coarsePointer2, canHover: canHover2, dpr, targetScale };
|
|
7072
|
+
}
|
|
7073
|
+
var DEFAULT_DEVICE_PROFILE = resolveDeviceProfile({
|
|
7074
|
+
coarsePointer: false,
|
|
7075
|
+
canHover: true,
|
|
7076
|
+
dpr: 1
|
|
7077
|
+
});
|
|
7078
|
+
var COARSE_QUERY = "(pointer: coarse)";
|
|
7079
|
+
var HOVER_QUERY = "(hover: hover)";
|
|
7080
|
+
function hasMatchMedia() {
|
|
7081
|
+
return typeof window !== "undefined" && typeof window.matchMedia === "function";
|
|
7082
|
+
}
|
|
7083
|
+
function detectOnce() {
|
|
7084
|
+
const dpr = typeof window !== "undefined" && window.devicePixelRatio || 1;
|
|
7085
|
+
if (!hasMatchMedia()) {
|
|
7086
|
+
return {
|
|
7087
|
+
coarsePointer: DEFAULT_DEVICE_PROFILE.coarsePointer,
|
|
7088
|
+
canHover: DEFAULT_DEVICE_PROFILE.canHover,
|
|
7089
|
+
dpr
|
|
7090
|
+
};
|
|
7091
|
+
}
|
|
7092
|
+
return {
|
|
7093
|
+
coarsePointer: window.matchMedia(COARSE_QUERY).matches,
|
|
7094
|
+
canHover: window.matchMedia(HOVER_QUERY).matches,
|
|
7095
|
+
dpr
|
|
7096
|
+
};
|
|
7097
|
+
}
|
|
7098
|
+
function useDetectedFacts() {
|
|
7099
|
+
const [facts, setFacts] = useState(detectOnce);
|
|
7100
|
+
useEffect(() => {
|
|
7101
|
+
if (!hasMatchMedia()) return;
|
|
7102
|
+
const coarseMq = window.matchMedia(COARSE_QUERY);
|
|
7103
|
+
const hoverMq = window.matchMedia(HOVER_QUERY);
|
|
7104
|
+
const onCoarse = (e) => setFacts((f) => ({ ...f, coarsePointer: e.matches }));
|
|
7105
|
+
const onHover = (e) => setFacts((f) => ({ ...f, canHover: e.matches }));
|
|
7106
|
+
coarseMq.addEventListener("change", onCoarse);
|
|
7107
|
+
hoverMq.addEventListener("change", onHover);
|
|
7108
|
+
let disposed = false;
|
|
7109
|
+
let densityMq = null;
|
|
7110
|
+
const onDensity = () => {
|
|
7111
|
+
if (disposed) return;
|
|
7112
|
+
const next = window.devicePixelRatio || 1;
|
|
7113
|
+
setFacts((f) => f.dpr === next ? f : { ...f, dpr: next });
|
|
7114
|
+
arm();
|
|
7115
|
+
};
|
|
7116
|
+
function arm() {
|
|
7117
|
+
if (disposed) return;
|
|
7118
|
+
densityMq?.removeEventListener("change", onDensity);
|
|
7119
|
+
densityMq = window.matchMedia(
|
|
7120
|
+
`(resolution: ${window.devicePixelRatio || 1}dppx)`
|
|
7121
|
+
);
|
|
7122
|
+
densityMq.addEventListener("change", onDensity);
|
|
7123
|
+
}
|
|
7124
|
+
arm();
|
|
7125
|
+
setFacts({
|
|
7126
|
+
coarsePointer: coarseMq.matches,
|
|
7127
|
+
canHover: hoverMq.matches,
|
|
7128
|
+
dpr: window.devicePixelRatio || 1
|
|
7129
|
+
});
|
|
7130
|
+
return () => {
|
|
7131
|
+
disposed = true;
|
|
7132
|
+
coarseMq.removeEventListener("change", onCoarse);
|
|
7133
|
+
hoverMq.removeEventListener("change", onHover);
|
|
7134
|
+
densityMq?.removeEventListener("change", onDensity);
|
|
7135
|
+
};
|
|
7136
|
+
}, []);
|
|
7137
|
+
return facts;
|
|
7138
|
+
}
|
|
7139
|
+
var DeviceProfileContext = createContext(null);
|
|
7140
|
+
function useDeviceProfile(overrides) {
|
|
7141
|
+
const provided = useContext(DeviceProfileContext);
|
|
7142
|
+
const detected = useDetectedFacts();
|
|
7143
|
+
const base = provided ?? detected;
|
|
7144
|
+
const { coarsePointer: coarsePointer2, canHover: canHover2, dpr, targetScale } = overrides ?? {};
|
|
7145
|
+
return useMemo(
|
|
7146
|
+
() => resolveDeviceProfile(base, {
|
|
7147
|
+
...coarsePointer2 !== void 0 ? { coarsePointer: coarsePointer2 } : {},
|
|
7148
|
+
...canHover2 !== void 0 ? { canHover: canHover2 } : {},
|
|
7149
|
+
...dpr !== void 0 ? { dpr } : {},
|
|
7150
|
+
...targetScale !== void 0 ? { targetScale } : {}
|
|
7151
|
+
}),
|
|
7152
|
+
[base.coarsePointer, base.canHover, base.dpr, coarsePointer2, canHover2, dpr, targetScale]
|
|
7153
|
+
);
|
|
7154
|
+
}
|
|
7155
|
+
function DeviceProfileProvider({ value, children }) {
|
|
7156
|
+
const profile = useDeviceProfile(value);
|
|
7157
|
+
return createElement(DeviceProfileContext.Provider, { value: profile }, children);
|
|
7158
|
+
}
|
|
7159
|
+
var HANDLE_BASE_PX = 8;
|
|
7160
|
+
var ANCHOR_HIT_BASE_PX = 8;
|
|
7161
|
+
var ROTATION_HANDLE_BASE_PX = 24;
|
|
6967
7162
|
function zoomAt(view, anchor, factor, opts) {
|
|
6968
7163
|
const fx = typeof factor === "number" ? factor : factor.x;
|
|
6969
7164
|
const fy = typeof factor === "number" ? factor : factor.y;
|
|
@@ -8694,6 +8889,10 @@ var clearSelectionAction = {
|
|
|
8694
8889
|
return true;
|
|
8695
8890
|
}
|
|
8696
8891
|
};
|
|
8892
|
+
var counter = 0;
|
|
8893
|
+
function freshNodeId() {
|
|
8894
|
+
return asNodeId(`n${(counter++).toString(36)}-${Math.random().toString(36).slice(2, 8)}`);
|
|
8895
|
+
}
|
|
8697
8896
|
function translatePose(pose, dx, dy) {
|
|
8698
8897
|
const p = pose;
|
|
8699
8898
|
return {
|
|
@@ -8702,10 +8901,6 @@ function translatePose(pose, dx, dy) {
|
|
|
8702
8901
|
y: (p["y"] ?? 0) + dy
|
|
8703
8902
|
};
|
|
8704
8903
|
}
|
|
8705
|
-
var cloneIdCounter = 0;
|
|
8706
|
-
function freshCloneId() {
|
|
8707
|
-
return asNodeId(`n${(cloneIdCounter++).toString(36)}-${Math.random().toString(36).slice(2, 8)}`);
|
|
8708
|
-
}
|
|
8709
8904
|
var cloneAction = {
|
|
8710
8905
|
id: "clone",
|
|
8711
8906
|
label: "Clone",
|
|
@@ -8772,7 +8967,7 @@ var cloneAction = {
|
|
|
8772
8967
|
if (origin === void 0 || !originNode) continue;
|
|
8773
8968
|
const newPose = translatePose(origin, dx, dy);
|
|
8774
8969
|
const node = {
|
|
8775
|
-
id:
|
|
8970
|
+
id: freshNodeId(),
|
|
8776
8971
|
kind: originNode.kind,
|
|
8777
8972
|
layer: originNode.layer,
|
|
8778
8973
|
pose: newPose,
|
|
@@ -9555,6 +9750,119 @@ var pinchZoomAction = {
|
|
|
9555
9750
|
},
|
|
9556
9751
|
enabled: () => true
|
|
9557
9752
|
};
|
|
9753
|
+
function hostIndex(scene, id) {
|
|
9754
|
+
const node = scene.get(id);
|
|
9755
|
+
const siblings = node?.parent == null ? scene.roots : scene.childrenOf(node.parent);
|
|
9756
|
+
return siblings.indexOf(id);
|
|
9757
|
+
}
|
|
9758
|
+
function hasSelectedAncestor(scene, id, set) {
|
|
9759
|
+
let parent = scene.get(id)?.parent ?? null;
|
|
9760
|
+
while (parent != null) {
|
|
9761
|
+
if (set.has(parent)) return true;
|
|
9762
|
+
parent = scene.get(parent)?.parent ?? null;
|
|
9763
|
+
}
|
|
9764
|
+
return false;
|
|
9765
|
+
}
|
|
9766
|
+
function buildDeleteOps(scene, ids, label) {
|
|
9767
|
+
const set = new Set(ids);
|
|
9768
|
+
const ops = [];
|
|
9769
|
+
for (const id of ids) {
|
|
9770
|
+
const node = scene.get(id);
|
|
9771
|
+
if (!node) continue;
|
|
9772
|
+
if (hasSelectedAncestor(scene, id, set)) continue;
|
|
9773
|
+
ops.push(createDeleteOp({
|
|
9774
|
+
node,
|
|
9775
|
+
index: hostIndex(scene, id),
|
|
9776
|
+
label
|
|
9777
|
+
}));
|
|
9778
|
+
}
|
|
9779
|
+
return ops;
|
|
9780
|
+
}
|
|
9781
|
+
var deleteAction = {
|
|
9782
|
+
id: "delete",
|
|
9783
|
+
label: "Delete",
|
|
9784
|
+
// Suppressed while any tool is mid-gesture — accidentally hitting
|
|
9785
|
+
// Delete during a drag shouldn't wipe the selection out from under
|
|
9786
|
+
// the in-flight handle.
|
|
9787
|
+
defaultBinding: {
|
|
9788
|
+
kind: "key",
|
|
9789
|
+
key: ["Delete", "Backspace"],
|
|
9790
|
+
phase: [{ channel: "*", phase: "initial" }]
|
|
9791
|
+
},
|
|
9792
|
+
eligible: { capability: "edits-page" },
|
|
9793
|
+
requires: ["scene", "selection", "applyOps"],
|
|
9794
|
+
invoker: {
|
|
9795
|
+
timing: "immediate",
|
|
9796
|
+
run: (deps) => {
|
|
9797
|
+
const selection = deps.selection;
|
|
9798
|
+
const scene = deps.scene;
|
|
9799
|
+
const applyOps = deps.applyOps;
|
|
9800
|
+
if (!selection || !scene) return;
|
|
9801
|
+
const ids = selection.get();
|
|
9802
|
+
if (ids.length === 0) return;
|
|
9803
|
+
const ops = buildDeleteOps(scene, ids, "Delete");
|
|
9804
|
+
if (ops.length > 0) {
|
|
9805
|
+
if (applyOps) applyOps(ops, "Delete");
|
|
9806
|
+
else scene.applyBatch(ops, "Delete", defaultCommitAdapter(scene));
|
|
9807
|
+
}
|
|
9808
|
+
selection.set([]);
|
|
9809
|
+
}
|
|
9810
|
+
},
|
|
9811
|
+
enabled: () => true
|
|
9812
|
+
};
|
|
9813
|
+
function requiresSelection(deps) {
|
|
9814
|
+
const selection = deps?.selection;
|
|
9815
|
+
if (!selection || selection.get().length === 0) {
|
|
9816
|
+
return ActionDisabledReason.SelectionRequired;
|
|
9817
|
+
}
|
|
9818
|
+
return true;
|
|
9819
|
+
}
|
|
9820
|
+
var clipboardCopyAction = {
|
|
9821
|
+
id: "clipboard.copy",
|
|
9822
|
+
label: "Copy",
|
|
9823
|
+
defaultBinding: { kind: "key", key: "c", mods: { mod: true } },
|
|
9824
|
+
// Same gate as `duplicate`: a mode that can neither edit the page nor own a
|
|
9825
|
+
// selection has nothing to copy. Notably excludes `text-edit`, where Cmd+C
|
|
9826
|
+
// must stay the browser's own copy of the caret range.
|
|
9827
|
+
eligible: { capability: ["edits-page", "creates-selection"] },
|
|
9828
|
+
// `selection` is read by the `enabled` gate, not the invoker — the
|
|
9829
|
+
// dispatcher builds deps for both, and an undeclared read is undefined.
|
|
9830
|
+
requires: ["clipboard", "selection"],
|
|
9831
|
+
invoker: {
|
|
9832
|
+
timing: "immediate",
|
|
9833
|
+
run: (deps) => {
|
|
9834
|
+
deps.clipboard?.copy();
|
|
9835
|
+
}
|
|
9836
|
+
},
|
|
9837
|
+
enabled: requiresSelection
|
|
9838
|
+
};
|
|
9839
|
+
var clipboardCutAction = {
|
|
9840
|
+
id: "clipboard.cut",
|
|
9841
|
+
label: "Cut",
|
|
9842
|
+
defaultBinding: { kind: "key", key: "x", mods: { mod: true } },
|
|
9843
|
+
eligible: { capability: "edits-page" },
|
|
9844
|
+
requires: ["clipboard", "scene", "selection", "applyOps"],
|
|
9845
|
+
invoker: {
|
|
9846
|
+
timing: "immediate",
|
|
9847
|
+
run: (deps) => {
|
|
9848
|
+
const clipboard = deps.clipboard;
|
|
9849
|
+
const selection = deps.selection;
|
|
9850
|
+
const scene = deps.scene;
|
|
9851
|
+
const applyOps = deps.applyOps;
|
|
9852
|
+
if (!clipboard || !selection || !scene) return;
|
|
9853
|
+
const ids = selection.get();
|
|
9854
|
+
if (ids.length === 0) return;
|
|
9855
|
+
clipboard.copy();
|
|
9856
|
+
const ops = buildDeleteOps(scene, ids, "Cut");
|
|
9857
|
+
if (ops.length > 0) {
|
|
9858
|
+
if (applyOps) applyOps(ops, "Cut");
|
|
9859
|
+
else scene.applyBatch(ops, "Cut", defaultCommitAdapter(scene));
|
|
9860
|
+
}
|
|
9861
|
+
selection.set([]);
|
|
9862
|
+
}
|
|
9863
|
+
},
|
|
9864
|
+
enabled: requiresSelection
|
|
9865
|
+
};
|
|
9558
9866
|
var enterTextEditAction = {
|
|
9559
9867
|
id: "enterTextEdit",
|
|
9560
9868
|
label: "Enter text edit",
|
|
@@ -9679,24 +9987,45 @@ var selectAllAction = {
|
|
|
9679
9987
|
}
|
|
9680
9988
|
}
|
|
9681
9989
|
};
|
|
9682
|
-
|
|
9990
|
+
var DUPLICATE_OFFSET = 12;
|
|
9991
|
+
function translatePose2(pose, dx, dy) {
|
|
9992
|
+
const p = pose;
|
|
9993
|
+
return { ...p, x: (p["x"] ?? 0) + dx, y: (p["y"] ?? 0) + dy };
|
|
9994
|
+
}
|
|
9995
|
+
function hasSelectedAncestor2(scene, id, set) {
|
|
9996
|
+
let parent = scene.get(id)?.parent ?? null;
|
|
9997
|
+
while (parent != null) {
|
|
9998
|
+
if (set.has(parent)) return true;
|
|
9999
|
+
parent = scene.get(parent)?.parent ?? null;
|
|
10000
|
+
}
|
|
10001
|
+
return false;
|
|
10002
|
+
}
|
|
10003
|
+
function copySubtree(scene, id, parent, offset, offsetDescendants, ops) {
|
|
9683
10004
|
const node = scene.get(id);
|
|
9684
|
-
|
|
9685
|
-
|
|
10005
|
+
if (!node) return null;
|
|
10006
|
+
const newId = freshNodeId();
|
|
10007
|
+
const copy = {
|
|
10008
|
+
...node,
|
|
10009
|
+
id: newId,
|
|
10010
|
+
pose: translatePose2(node.pose, offset.dx, offset.dy),
|
|
10011
|
+
parent
|
|
10012
|
+
};
|
|
10013
|
+
ops.push(createInsertOp({ node: copy, label: "Duplicate" }));
|
|
10014
|
+
const childOffset = offsetDescendants ? offset : { dx: 0, dy: 0 };
|
|
10015
|
+
for (const child of scene.childrenOf(id)) {
|
|
10016
|
+
copySubtree(scene, child, newId, childOffset, offsetDescendants, ops);
|
|
10017
|
+
}
|
|
10018
|
+
return newId;
|
|
9686
10019
|
}
|
|
9687
|
-
var
|
|
9688
|
-
id: "
|
|
9689
|
-
label: "
|
|
9690
|
-
|
|
9691
|
-
|
|
9692
|
-
// the
|
|
9693
|
-
|
|
9694
|
-
|
|
9695
|
-
|
|
9696
|
-
phase: [{ channel: "*", phase: "initial" }]
|
|
9697
|
-
},
|
|
9698
|
-
eligible: { capability: "edits-page" },
|
|
9699
|
-
requires: ["scene", "selection", "applyOps"],
|
|
10020
|
+
var duplicateAction = {
|
|
10021
|
+
id: "duplicate",
|
|
10022
|
+
label: "Duplicate",
|
|
10023
|
+
defaultBinding: { kind: "key", key: "d", mods: { mod: true } },
|
|
10024
|
+
eligible: { capability: ["edits-page", "creates-selection"] },
|
|
10025
|
+
// `selection` is read by the `enabled` gate as well as the invoker. An
|
|
10026
|
+
// undeclared read throws inside the dev-build deps Proxy before the gate can
|
|
10027
|
+
// answer, which is how this action spent a while doing nothing at all.
|
|
10028
|
+
requires: ["scene", "selection", "applyOps", "poseComposition"],
|
|
9700
10029
|
invoker: {
|
|
9701
10030
|
timing: "immediate",
|
|
9702
10031
|
run: (deps) => {
|
|
@@ -9706,40 +10035,22 @@ var deleteAction = {
|
|
|
9706
10035
|
if (!selection || !scene) return;
|
|
9707
10036
|
const ids = selection.get();
|
|
9708
10037
|
if (ids.length === 0) return;
|
|
10038
|
+
const set = new Set(ids);
|
|
10039
|
+
const offset = { dx: DUPLICATE_OFFSET, dy: DUPLICATE_OFFSET };
|
|
9709
10040
|
const ops = [];
|
|
10041
|
+
const newIds = [];
|
|
9710
10042
|
for (const id of ids) {
|
|
9711
|
-
const
|
|
10043
|
+
const nid = asNodeId(id);
|
|
10044
|
+
const node = scene.get(nid);
|
|
9712
10045
|
if (!node) continue;
|
|
9713
|
-
|
|
9714
|
-
|
|
9715
|
-
|
|
9716
|
-
label: "Delete"
|
|
9717
|
-
}));
|
|
9718
|
-
}
|
|
9719
|
-
if (ops.length > 0) {
|
|
9720
|
-
if (applyOps) applyOps(ops, "Delete");
|
|
9721
|
-
else scene.applyBatch(ops, "Delete", defaultCommitAdapter(scene));
|
|
10046
|
+
if (hasSelectedAncestor2(scene, nid, set)) continue;
|
|
10047
|
+
const newId = copySubtree(scene, nid, node.parent ?? null, offset, deps.poseComposition === void 0, ops);
|
|
10048
|
+
if (newId) newIds.push(newId);
|
|
9722
10049
|
}
|
|
9723
|
-
|
|
9724
|
-
|
|
9725
|
-
|
|
9726
|
-
|
|
9727
|
-
};
|
|
9728
|
-
function requiresSelection(deps) {
|
|
9729
|
-
const selection = deps?.selection;
|
|
9730
|
-
if (!selection || selection.get().length === 0) {
|
|
9731
|
-
return ActionDisabledReason.SelectionRequired;
|
|
9732
|
-
}
|
|
9733
|
-
return true;
|
|
9734
|
-
}
|
|
9735
|
-
var duplicateAction = {
|
|
9736
|
-
id: "duplicate",
|
|
9737
|
-
label: "Duplicate",
|
|
9738
|
-
defaultBinding: { kind: "key", key: "d", mods: { mod: true } },
|
|
9739
|
-
eligible: { capability: ["edits-page", "creates-selection"] },
|
|
9740
|
-
invoker: {
|
|
9741
|
-
timing: "immediate",
|
|
9742
|
-
run: (_deps, params) => {
|
|
10050
|
+
if (ops.length === 0) return;
|
|
10051
|
+
if (applyOps) applyOps(ops, "Duplicate");
|
|
10052
|
+
else scene.applyBatch(ops, "Duplicate", defaultCommitAdapter(scene));
|
|
10053
|
+
selection.set(newIds);
|
|
9743
10054
|
}
|
|
9744
10055
|
},
|
|
9745
10056
|
enabled: requiresSelection
|
|
@@ -11719,7 +12030,8 @@ function resolveTextStyle(style) {
|
|
|
11719
12030
|
selectionColor: style.selectionColor ?? null,
|
|
11720
12031
|
letterSpacing: style.letterSpacing ?? DEFAULT_TEXT_STYLE.letterSpacing,
|
|
11721
12032
|
underline: style.underline ?? DEFAULT_TEXT_STYLE.underline,
|
|
11722
|
-
strikethrough: style.strikethrough ?? DEFAULT_TEXT_STYLE.strikethrough
|
|
12033
|
+
strikethrough: style.strikethrough ?? DEFAULT_TEXT_STYLE.strikethrough,
|
|
12034
|
+
...style.stroke !== void 0 ? { stroke: style.stroke } : {}
|
|
11723
12035
|
};
|
|
11724
12036
|
}
|
|
11725
12037
|
function numericWeight(w) {
|
|
@@ -11740,6 +12052,9 @@ function resolveRuns(runs, style) {
|
|
|
11740
12052
|
fontWeight: run.bold ? 700 : baseWeight,
|
|
11741
12053
|
fontStyle: run.italic ? "italic" : style.fontStyle,
|
|
11742
12054
|
fill: run.fill ?? style.fill,
|
|
12055
|
+
// Unlike the decorations below, a run's stroke *replaces* the node's
|
|
12056
|
+
// rather than adding to it — there is only one outline to paint.
|
|
12057
|
+
...(run.stroke ?? style.stroke) !== void 0 ? { stroke: run.stroke ?? style.stroke } : {},
|
|
11743
12058
|
letterSpacing: run.letterSpacing ?? style.letterSpacing,
|
|
11744
12059
|
// `||`, not `??`: run-level decorations are additive over the node style.
|
|
11745
12060
|
underline: run.underline || style.underline,
|
|
@@ -12116,7 +12431,9 @@ var KIT_STANDARD_DESCRIPTORS = [
|
|
|
12116
12431
|
setStrokeAction,
|
|
12117
12432
|
setFillOpacityAction,
|
|
12118
12433
|
setStrokeOpacityAction,
|
|
12119
|
-
ingestAction
|
|
12434
|
+
ingestAction,
|
|
12435
|
+
clipboardCopyAction,
|
|
12436
|
+
clipboardCutAction
|
|
12120
12437
|
];
|
|
12121
12438
|
function useStandardActions(opts) {
|
|
12122
12439
|
const optsRef = useRef(opts);
|
|
@@ -12281,6 +12598,14 @@ function evaluateSelector(s, ctx) {
|
|
|
12281
12598
|
const resizable2 = ctx.selectionResizable ?? true;
|
|
12282
12599
|
if (resizable2 !== s.resizable) return false;
|
|
12283
12600
|
}
|
|
12601
|
+
if (s.coarsePointer !== void 0) {
|
|
12602
|
+
const device = ctx.device ?? DEFAULT_DEVICE_PROFILE;
|
|
12603
|
+
if (device.coarsePointer !== s.coarsePointer) return false;
|
|
12604
|
+
}
|
|
12605
|
+
if (s.canHover !== void 0) {
|
|
12606
|
+
const device = ctx.device ?? DEFAULT_DEVICE_PROFILE;
|
|
12607
|
+
if (device.canHover !== s.canHover) return false;
|
|
12608
|
+
}
|
|
12284
12609
|
return true;
|
|
12285
12610
|
}
|
|
12286
12611
|
var MAX_RULE_DEPTH = 10;
|
|
@@ -12350,6 +12675,8 @@ cond({ selection: { empty: true } });
|
|
|
12350
12675
|
cond({ when: (c) => c.multiActive });
|
|
12351
12676
|
cond({ hovering: true });
|
|
12352
12677
|
cond({ hoveringSelected: true });
|
|
12678
|
+
cond({ coarsePointer: true });
|
|
12679
|
+
cond({ canHover: true });
|
|
12353
12680
|
var DEFAULT_ALLOWED_CAPABILITIES = /* @__PURE__ */ new Set([
|
|
12354
12681
|
...NORMAL.allows,
|
|
12355
12682
|
...IMPLICIT_TAGS
|
|
@@ -13255,6 +13582,44 @@ function useGestureDispatcher(opts) {
|
|
|
13255
13582
|
const DRAG_THRESHOLD_PX = 4;
|
|
13256
13583
|
const bufferedDown = /* @__PURE__ */ new Map();
|
|
13257
13584
|
const lastPointerDown = /* @__PURE__ */ new Map();
|
|
13585
|
+
const LONG_PRESS_MS = 500;
|
|
13586
|
+
const longPressTimers = /* @__PURE__ */ new Map();
|
|
13587
|
+
const cancelLongPress = (pointerId) => {
|
|
13588
|
+
const t = longPressTimers.get(pointerId);
|
|
13589
|
+
if (t !== void 0) {
|
|
13590
|
+
clearTimeout(t);
|
|
13591
|
+
longPressTimers.delete(pointerId);
|
|
13592
|
+
}
|
|
13593
|
+
};
|
|
13594
|
+
const cancelAllLongPress = () => {
|
|
13595
|
+
for (const t of longPressTimers.values()) clearTimeout(t);
|
|
13596
|
+
longPressTimers.clear();
|
|
13597
|
+
};
|
|
13598
|
+
const fireLongPress = (pointerId) => {
|
|
13599
|
+
const down = lastPointerDown.get(pointerId);
|
|
13600
|
+
if (!down) return;
|
|
13601
|
+
const shared = {
|
|
13602
|
+
target: down.target,
|
|
13603
|
+
altKey: down.altKey,
|
|
13604
|
+
ctrlKey: down.ctrlKey,
|
|
13605
|
+
metaKey: down.metaKey,
|
|
13606
|
+
shiftKey: down.shiftKey,
|
|
13607
|
+
...down.bodyTarget !== void 0 ? { bodyTarget: down.bodyTarget } : {},
|
|
13608
|
+
...down.bodyKind !== void 0 ? { bodyKind: down.bodyKind } : {}
|
|
13609
|
+
};
|
|
13610
|
+
const result = dispatch2({
|
|
13611
|
+
kind: "longpress",
|
|
13612
|
+
x: down.worldX,
|
|
13613
|
+
y: down.worldY,
|
|
13614
|
+
clientX: down.clientX,
|
|
13615
|
+
clientY: down.clientY,
|
|
13616
|
+
...down.affordance !== void 0 ? { affordance: down.affordance } : {},
|
|
13617
|
+
...shared
|
|
13618
|
+
});
|
|
13619
|
+
if (result === "unhandled") {
|
|
13620
|
+
dispatch2({ kind: "contextmenu", ...shared });
|
|
13621
|
+
}
|
|
13622
|
+
};
|
|
13258
13623
|
const DOUBLE_CLICK_MAX_MS = 600;
|
|
13259
13624
|
const DOUBLE_CLICK_MAX_PX = 8;
|
|
13260
13625
|
const onKeyDown = (e) => {
|
|
@@ -13358,6 +13723,7 @@ function useGestureDispatcher(opts) {
|
|
|
13358
13723
|
bufferedDown.set(e.pointerId, { ev, clientX: e.clientX, clientY: e.clientY });
|
|
13359
13724
|
dispatch2({ ...ev, stage: "press" });
|
|
13360
13725
|
lastPointerDown.set(e.pointerId, {
|
|
13726
|
+
target: e.target,
|
|
13361
13727
|
clientX: e.clientX,
|
|
13362
13728
|
clientY: e.clientY,
|
|
13363
13729
|
worldX: w.x,
|
|
@@ -13370,7 +13736,19 @@ function useGestureDispatcher(opts) {
|
|
|
13370
13736
|
metaKey: e.metaKey,
|
|
13371
13737
|
shiftKey: e.shiftKey
|
|
13372
13738
|
});
|
|
13739
|
+
if ((e.pointerType === "touch" || e.pointerType === "pen") && activePointers.size === 1) {
|
|
13740
|
+
cancelLongPress(e.pointerId);
|
|
13741
|
+
longPressTimers.set(
|
|
13742
|
+
e.pointerId,
|
|
13743
|
+
setTimeout(() => {
|
|
13744
|
+
longPressTimers.delete(e.pointerId);
|
|
13745
|
+
if (disposed) return;
|
|
13746
|
+
fireLongPress(e.pointerId);
|
|
13747
|
+
}, LONG_PRESS_MS)
|
|
13748
|
+
);
|
|
13749
|
+
}
|
|
13373
13750
|
if (activePointers.size >= 2) {
|
|
13751
|
+
cancelAllLongPress();
|
|
13374
13752
|
for (const id of activePointers) bufferedDown.delete(id);
|
|
13375
13753
|
const { centroid, spread } = computeMultiTouchGeometry(pointerPositions);
|
|
13376
13754
|
if (!multiTouchStart) {
|
|
@@ -13401,6 +13779,7 @@ function useGestureDispatcher(opts) {
|
|
|
13401
13779
|
const dy = e.clientY - buffered.clientY;
|
|
13402
13780
|
if (Math.hypot(dx, dy) >= DRAG_THRESHOLD_PX) {
|
|
13403
13781
|
bufferedDown.delete(e.pointerId);
|
|
13782
|
+
cancelLongPress(e.pointerId);
|
|
13404
13783
|
dispatch2(buffered.ev);
|
|
13405
13784
|
}
|
|
13406
13785
|
}
|
|
@@ -13514,6 +13893,7 @@ function useGestureDispatcher(opts) {
|
|
|
13514
13893
|
clearHoverCursor();
|
|
13515
13894
|
};
|
|
13516
13895
|
const onPointerUp = (e) => {
|
|
13896
|
+
cancelLongPress(e.pointerId);
|
|
13517
13897
|
const prevSize = activePointers.size;
|
|
13518
13898
|
activePointers.delete(e.pointerId);
|
|
13519
13899
|
pointerPositions.delete(e.pointerId);
|
|
@@ -13618,6 +13998,7 @@ function useGestureDispatcher(opts) {
|
|
|
13618
13998
|
}, 0);
|
|
13619
13999
|
};
|
|
13620
14000
|
const onPointerCancel = (e) => {
|
|
14001
|
+
cancelLongPress(e.pointerId);
|
|
13621
14002
|
activePointers.delete(e.pointerId);
|
|
13622
14003
|
pointerPositions.delete(e.pointerId);
|
|
13623
14004
|
lastPointerDown.delete(e.pointerId);
|
|
@@ -13740,6 +14121,7 @@ function useGestureDispatcher(opts) {
|
|
|
13740
14121
|
window.removeEventListener("paste", onPaste);
|
|
13741
14122
|
canvas?.classList.remove(DROPOVER_CLASS);
|
|
13742
14123
|
clearHoverCursor();
|
|
14124
|
+
cancelAllLongPress();
|
|
13743
14125
|
disposed = true;
|
|
13744
14126
|
dispatcher.cancelAll("cancel");
|
|
13745
14127
|
};
|
|
@@ -14552,7 +14934,7 @@ function textLineBoxes(pose, opts = {}) {
|
|
|
14552
14934
|
}
|
|
14553
14935
|
return out;
|
|
14554
14936
|
}
|
|
14555
|
-
var
|
|
14937
|
+
var cache5 = /* @__PURE__ */ new Map();
|
|
14556
14938
|
var subscribers2 = /* @__PURE__ */ new Set();
|
|
14557
14939
|
var defaultLoader = async (src) => {
|
|
14558
14940
|
if (typeof Image === "undefined" || typeof createImageBitmap === "undefined") {
|
|
@@ -14570,28 +14952,28 @@ function notify() {
|
|
|
14570
14952
|
}
|
|
14571
14953
|
function startLoad(src) {
|
|
14572
14954
|
const entry = { status: "loading" };
|
|
14573
|
-
|
|
14955
|
+
cache5.set(src, entry);
|
|
14574
14956
|
loader(src).then(
|
|
14575
14957
|
(bitmap) => {
|
|
14576
|
-
if (
|
|
14577
|
-
|
|
14958
|
+
if (cache5.get(src) !== entry) return;
|
|
14959
|
+
cache5.set(src, { status: "ready", bitmap });
|
|
14578
14960
|
notify();
|
|
14579
14961
|
},
|
|
14580
14962
|
() => {
|
|
14581
|
-
if (
|
|
14582
|
-
|
|
14963
|
+
if (cache5.get(src) !== entry) return;
|
|
14964
|
+
cache5.set(src, { status: "error" });
|
|
14583
14965
|
notify();
|
|
14584
14966
|
}
|
|
14585
14967
|
);
|
|
14586
14968
|
}
|
|
14587
14969
|
function getImageBitmap(src) {
|
|
14588
|
-
const entry =
|
|
14970
|
+
const entry = cache5.get(src);
|
|
14589
14971
|
if (entry) return entry.bitmap;
|
|
14590
14972
|
startLoad(src);
|
|
14591
14973
|
return void 0;
|
|
14592
14974
|
}
|
|
14593
14975
|
function imageStatus(src) {
|
|
14594
|
-
return
|
|
14976
|
+
return cache5.get(src)?.status ?? "idle";
|
|
14595
14977
|
}
|
|
14596
14978
|
function subscribeImageReady(cb) {
|
|
14597
14979
|
subscribers2.add(cb);
|
|
@@ -14685,6 +15067,13 @@ function shapeCoversPoint(node, pose, x, y, opts = {}) {
|
|
|
14685
15067
|
const reach = ink.strokeWidth / 2 + (opts.tolerance ?? 0);
|
|
14686
15068
|
return reach > 0 && strokeHitTest(sil, x, y, reach);
|
|
14687
15069
|
}
|
|
15070
|
+
function withLeafStroke(style, stroke, strokeWidth) {
|
|
15071
|
+
if (style?.stroke !== void 0) return style;
|
|
15072
|
+
if (!stroke || stroke === "none") return style;
|
|
15073
|
+
const width = strokeWidth ?? 1;
|
|
15074
|
+
if (width <= 0) return style;
|
|
15075
|
+
return { ...style, stroke: { paint: { color: stroke }, width } };
|
|
15076
|
+
}
|
|
14688
15077
|
var TEXT_PAINTER = {
|
|
14689
15078
|
id: "kit:text",
|
|
14690
15079
|
matches: (node) => {
|
|
@@ -14703,7 +15092,8 @@ var TEXT_PAINTER = {
|
|
|
14703
15092
|
const d = node.data;
|
|
14704
15093
|
const p = pose;
|
|
14705
15094
|
const y = p.y;
|
|
14706
|
-
|
|
15095
|
+
const style = withLeafStroke(d.style, d.stroke, d.strokeWidth);
|
|
15096
|
+
return d.runs && d.runs.length > 0 ? [textCommandFromRuns(p.x, y, d.runs, style, void 0, p.height)] : [textCommand(p.x, y, d.text, style, void 0, p.height)];
|
|
14707
15097
|
}),
|
|
14708
15098
|
// The pose is a *wrap box*, not a bounding box — "Away" in a 300-unit box
|
|
14709
15099
|
// leaves most of it empty, and a pose-rect silhouette claims all of it. The
|
|
@@ -16753,7 +17143,7 @@ function buildChromeState(args) {
|
|
|
16753
17143
|
}
|
|
16754
17144
|
};
|
|
16755
17145
|
}
|
|
16756
|
-
var DEFAULT_ROTATION_HANDLE_DISTANCE =
|
|
17146
|
+
var DEFAULT_ROTATION_HANDLE_DISTANCE = ROTATION_HANDLE_BASE_PX;
|
|
16757
17147
|
function rotationHandle(pose, distance = DEFAULT_ROTATION_HANDLE_DISTANCE) {
|
|
16758
17148
|
const rotation = pose.rotation ?? 0;
|
|
16759
17149
|
const c = aabbCenter(pose);
|
|
@@ -16813,7 +17203,7 @@ var DEFAULT_HANDLE_OUTLINE = {
|
|
|
16813
17203
|
paint: { fill: "solid", color: "#1a130d" },
|
|
16814
17204
|
width: 1
|
|
16815
17205
|
};
|
|
16816
|
-
var DEFAULT_HANDLE_SIZE =
|
|
17206
|
+
var DEFAULT_HANDLE_SIZE = HANDLE_BASE_PX;
|
|
16817
17207
|
function defaultHandlesOf(b) {
|
|
16818
17208
|
return [
|
|
16819
17209
|
{ x: b.x, y: b.y },
|
|
@@ -20212,8 +20602,8 @@ var DEFAULT_FILL3 = "#d4c4a8";
|
|
|
20212
20602
|
var DEFAULT_STROKE = "#1a130d";
|
|
20213
20603
|
function createCornerResizeAffordance(opts = {}) {
|
|
20214
20604
|
const {
|
|
20215
|
-
handleHitRadius =
|
|
20216
|
-
handleSize =
|
|
20605
|
+
handleHitRadius = HANDLE_BASE_PX,
|
|
20606
|
+
handleSize = HANDLE_BASE_PX,
|
|
20217
20607
|
fill = DEFAULT_FILL3,
|
|
20218
20608
|
stroke = DEFAULT_STROKE
|
|
20219
20609
|
} = opts;
|
|
@@ -20351,8 +20741,8 @@ function createPathAnchorAffordances(getAnchorState, opts = {}) {
|
|
|
20351
20741
|
};
|
|
20352
20742
|
return [anchors, controls];
|
|
20353
20743
|
}
|
|
20354
|
-
var HANDLE_HIT_RADIUS =
|
|
20355
|
-
var ANCHOR_HIT_RADIUS =
|
|
20744
|
+
var HANDLE_HIT_RADIUS = HANDLE_BASE_PX;
|
|
20745
|
+
var ANCHOR_HIT_RADIUS = ANCHOR_HIT_BASE_PX;
|
|
20356
20746
|
function buildAffordanceAt(opts) {
|
|
20357
20747
|
const {
|
|
20358
20748
|
getChromeState,
|
|
@@ -21567,7 +21957,6 @@ function makeGetNodeAtPoint(pickEvery, nodeResolver) {
|
|
|
21567
21957
|
return { id, kind, pose, data };
|
|
21568
21958
|
};
|
|
21569
21959
|
}
|
|
21570
|
-
var DEFAULT_HANDLE_SIZE2 = 8;
|
|
21571
21960
|
var IS_DEV = (() => {
|
|
21572
21961
|
try {
|
|
21573
21962
|
return Boolean(import.meta.env?.DEV);
|
|
@@ -21586,10 +21975,10 @@ function recordCoordTrace(entry) {
|
|
|
21586
21975
|
coordTrace.push(entry);
|
|
21587
21976
|
if (coordTrace.length > COORD_TRACE_LIMIT) coordTrace.shift();
|
|
21588
21977
|
}
|
|
21589
|
-
function mergeLayersWithDefaults(user) {
|
|
21978
|
+
function mergeLayersWithDefaults(user, targetScale = 1) {
|
|
21590
21979
|
const defaults = {
|
|
21591
21980
|
scene: { drawOne: defaultDrawOne },
|
|
21592
|
-
selectionOverlay: { handles: { size:
|
|
21981
|
+
selectionOverlay: { handles: { size: HANDLE_BASE_PX * targetScale } }
|
|
21593
21982
|
};
|
|
21594
21983
|
if (!user) return defaults;
|
|
21595
21984
|
const result = { ...user };
|
|
@@ -21677,8 +22066,10 @@ function SceneCanvasInner(props, ref) {
|
|
|
21677
22066
|
chromeVisibility,
|
|
21678
22067
|
getActiveMode,
|
|
21679
22068
|
getFocused: getFocusedProp,
|
|
22069
|
+
device,
|
|
21680
22070
|
...rest
|
|
21681
22071
|
} = props;
|
|
22072
|
+
const deviceProfile = useDeviceProfile(device);
|
|
21682
22073
|
const isSerialized = (s) => typeof s === "object" && s != null && s.version === 1 && Array.isArray(s.nodes);
|
|
21683
22074
|
const [bakedScene] = useState(
|
|
21684
22075
|
() => isSerialized(sceneInput) ? sceneFromJSON(sceneInput, {}) : null
|
|
@@ -21796,7 +22187,7 @@ function SceneCanvasInner(props, ref) {
|
|
|
21796
22187
|
}
|
|
21797
22188
|
}), []);
|
|
21798
22189
|
const selectToolWithDefaults = useMemo(() => ({
|
|
21799
|
-
handleHitRadius:
|
|
22190
|
+
handleHitRadius: HANDLE_BASE_PX * deviceProfile.targetScale,
|
|
21800
22191
|
// Shift-click belongs to the anchor selection while a path is being
|
|
21801
22192
|
// anchor-edited; see `UseSelectToolOptions.extendClickLocked`.
|
|
21802
22193
|
extendClickLocked: () => effectivePathEditingId() !== "",
|
|
@@ -21806,7 +22197,7 @@ function SceneCanvasInner(props, ref) {
|
|
|
21806
22197
|
// pipeline (audit 3.4). The classifier is now `select.pick`, which
|
|
21807
22198
|
// declares that capability itself — one rule, evaluated in one place.
|
|
21808
22199
|
...selectToolOpts
|
|
21809
|
-
}), [selectToolOpts]);
|
|
22200
|
+
}), [selectToolOpts, deviceProfile.targetScale]);
|
|
21810
22201
|
const selectionRef = useRef(selection);
|
|
21811
22202
|
selectionRef.current = selection;
|
|
21812
22203
|
const kindClassifier = useMemo(() => {
|
|
@@ -21964,8 +22355,8 @@ function SceneCanvasInner(props, ref) {
|
|
|
21964
22355
|
};
|
|
21965
22356
|
}, [Boolean(onDoubleClick)]);
|
|
21966
22357
|
const mergedLayers = useMemo(
|
|
21967
|
-
() => mergeLayersWithDefaults(layers),
|
|
21968
|
-
[layers]
|
|
22358
|
+
() => mergeLayersWithDefaults(layers, deviceProfile.targetScale),
|
|
22359
|
+
[layers, deviceProfile.targetScale]
|
|
21969
22360
|
);
|
|
21970
22361
|
const resolvedActions = useMemo(() => {
|
|
21971
22362
|
if (selectToolOpts?.rotate !== false) return actions;
|
|
@@ -22024,6 +22415,8 @@ function SceneCanvasInner(props, ref) {
|
|
|
22024
22415
|
chromeVisibilityRef.current = effectiveChromeVisibility;
|
|
22025
22416
|
const getActiveModeRef = useRef(getActiveMode);
|
|
22026
22417
|
getActiveModeRef.current = getActiveMode;
|
|
22418
|
+
const deviceProfileRef = useRef(deviceProfile);
|
|
22419
|
+
deviceProfileRef.current = deviceProfile;
|
|
22027
22420
|
const resizablePredRef = useRef(selectToolOpts?.resize?.resizable);
|
|
22028
22421
|
resizablePredRef.current = selectToolOpts?.resize?.resizable;
|
|
22029
22422
|
const buildCurrentRuleCtx = useCallback(() => {
|
|
@@ -22045,7 +22438,8 @@ function SceneCanvasInner(props, ref) {
|
|
|
22045
22438
|
mode: modeInfo.id,
|
|
22046
22439
|
allowedCapabilities: modeInfo.allowedCapabilities,
|
|
22047
22440
|
selectionResizable,
|
|
22048
|
-
editingAnchors: effectivePathEditingId() !== ""
|
|
22441
|
+
editingAnchors: effectivePathEditingId() !== "",
|
|
22442
|
+
device: deviceProfileRef.current
|
|
22049
22443
|
};
|
|
22050
22444
|
}, [dispatcher, getHover]);
|
|
22051
22445
|
const anchorEditingAllowed = useMemo(
|
|
@@ -22300,7 +22694,7 @@ function SceneCanvasInner(props, ref) {
|
|
|
22300
22694
|
testHookRef.current?._markReady();
|
|
22301
22695
|
}
|
|
22302
22696
|
}, []);
|
|
22303
|
-
return /* @__PURE__ */ jsx(DepRegistryProviderIfRoot, { children: /* @__PURE__ */ jsx(PointerProviderIfRoot, { children: /* @__PURE__ */ jsxs(ActionsProviderIfRoot, { children: [
|
|
22697
|
+
return /* @__PURE__ */ jsx(DeviceProfileProvider, { value: device, children: /* @__PURE__ */ jsx(DepRegistryProviderIfRoot, { children: /* @__PURE__ */ jsx(PointerProviderIfRoot, { children: /* @__PURE__ */ jsxs(ActionsProviderIfRoot, { children: [
|
|
22304
22698
|
canvas,
|
|
22305
22699
|
/* @__PURE__ */ jsx(PointerPublisher, { canvasRef: internalCanvasRef, viewRef: currentViewRef }),
|
|
22306
22700
|
/* @__PURE__ */ jsx(
|
|
@@ -22363,7 +22757,7 @@ function SceneCanvasInner(props, ref) {
|
|
|
22363
22757
|
}
|
|
22364
22758
|
),
|
|
22365
22759
|
children
|
|
22366
|
-
] }) }) });
|
|
22760
|
+
] }) }) }) });
|
|
22367
22761
|
}
|
|
22368
22762
|
function ToolKeybindingsMounter({
|
|
22369
22763
|
internalTools,
|
|
@@ -23152,5 +23546,5 @@ function oklchToOklab(L, C, h) {
|
|
|
23152
23546
|
}
|
|
23153
23547
|
|
|
23154
23548
|
export { FALLBACK_FIT_VIEW, MinimapCanvas, SceneViewCanvas, UnknownIcon, buildSceneViewCommands, computeFitView2, computeIndicatorCommand, eligibleTool, evaluateEnabled, oklabToSrgbU8, oklchToOklab, renderSceneToCanvas, rgbaToHex, useActionsRegistry, useOptionalDepRegistry };
|
|
23155
|
-
//# sourceMappingURL=chunk-
|
|
23156
|
-
//# sourceMappingURL=chunk-
|
|
23549
|
+
//# sourceMappingURL=chunk-6V7ROR7G.js.map
|
|
23550
|
+
//# sourceMappingURL=chunk-6V7ROR7G.js.map
|