@elaraai/east-ui-components 1.0.13 → 1.0.14
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/collections/schematic/camera.d.ts +175 -0
- package/dist/collections/schematic/camera.d.ts.map +1 -0
- package/dist/collections/schematic/index.d.ts.map +1 -1
- package/dist/collections/schematic/paint.d.ts +91 -0
- package/dist/collections/schematic/paint.d.ts.map +1 -1
- package/dist/index.cjs +536 -197
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +536 -197
- package/dist/index.js.map +1 -1
- package/dist/theme/global-css.d.ts.map +1 -1
- package/dist/theme/slot-recipes/schematic.d.ts +1 -1
- package/dist/theme/slot-recipes/schematic.d.ts.map +1 -1
- package/package.json +4 -4
package/dist/index.js
CHANGED
|
@@ -1170,8 +1170,13 @@ const globalCss = defineGlobalStyles({
|
|
|
1170
1170
|
},
|
|
1171
1171
|
/* ─── Drag & drop stages (drag-drop-visuals) ─────────────────────────
|
|
1172
1172
|
* The DragLayerProvider drives these via data attributes; surfaces get
|
|
1173
|
-
* the treatment for free by registering cells/sinks.
|
|
1174
|
-
|
|
1173
|
+
* the treatment for free by registering cells/sinks.
|
|
1174
|
+
*
|
|
1175
|
+
* Scoped `:not([data-scope])` so it dims only our own drag origins —
|
|
1176
|
+
* Ark/Zag widgets (Slider, etc.) set `data-dragging` on themselves for
|
|
1177
|
+
* their own drag state and carry a `data-scope`; without this exclusion
|
|
1178
|
+
* a slider goes to 40% opacity while its thumb is dragged. */
|
|
1179
|
+
"[data-dragging]:not([data-scope])": {
|
|
1175
1180
|
opacity: "0.4"
|
|
1176
1181
|
},
|
|
1177
1182
|
"[data-drag-ghost]": {
|
|
@@ -2991,6 +2996,7 @@ const schematicSlotRecipe = defineSlotRecipe({
|
|
|
2991
2996
|
"root",
|
|
2992
2997
|
"canvas",
|
|
2993
2998
|
"grid",
|
|
2999
|
+
"cardLayer",
|
|
2994
3000
|
"underlay",
|
|
2995
3001
|
"zone",
|
|
2996
3002
|
"zoneLabel",
|
|
@@ -3068,6 +3074,15 @@ const schematicSlotRecipe = defineSlotRecipe({
|
|
|
3068
3074
|
linear-gradient(to right, color-mix(in oklch, {colors.border.subtle} 22%, transparent) 1px, transparent 1px),
|
|
3069
3075
|
linear-gradient(to bottom, color-mix(in oklch, {colors.border.subtle} 22%, transparent) 1px, transparent 1px)`
|
|
3070
3076
|
},
|
|
3077
|
+
/* Holds the live `--cam-ppu` / `--cam-tx` / `--cam-ty` custom
|
|
3078
|
+
* properties (written by applyCamera each frame). Transparent and
|
|
3079
|
+
* click-through; each card re-enables its own pointer events so the
|
|
3080
|
+
* full-cover layer never swallows canvas clicks (issue #57). */
|
|
3081
|
+
cardLayer: {
|
|
3082
|
+
position: "absolute",
|
|
3083
|
+
inset: "0",
|
|
3084
|
+
pointerEvents: "none"
|
|
3085
|
+
},
|
|
3071
3086
|
/* Links draw in pixel space; tone → token mapping lives here so
|
|
3072
3087
|
* data only ever names a tone. */
|
|
3073
3088
|
underlay: {
|
|
@@ -3264,6 +3279,7 @@ const schematicSlotRecipe = defineSlotRecipe({
|
|
|
3264
3279
|
item: {
|
|
3265
3280
|
position: "absolute",
|
|
3266
3281
|
transform: "translate(-50%, -50%)",
|
|
3282
|
+
pointerEvents: "auto",
|
|
3267
3283
|
display: "flex",
|
|
3268
3284
|
flexDirection: "column",
|
|
3269
3285
|
gap: "2px",
|
|
@@ -3459,14 +3475,24 @@ const schematicSlotRecipe = defineSlotRecipe({
|
|
|
3459
3475
|
minHeight: "0",
|
|
3460
3476
|
overflowY: "auto",
|
|
3461
3477
|
paddingBottom: "{spacing.2}",
|
|
3462
|
-
lineHeight: "1.7"
|
|
3463
|
-
|
|
3478
|
+
lineHeight: "1.7",
|
|
3479
|
+
// Row height shared by the sticky zone headers (their stacked `top`
|
|
3480
|
+
// offset is a multiple of this) so an ancestor chain pins flush.
|
|
3481
|
+
"--nav-row-h": "22px"
|
|
3482
|
+
},
|
|
3483
|
+
/* Zone headers pin to the top of the scroll area like a tree view: each
|
|
3484
|
+
* depth level sticks at `top = depth × --nav-row-h` (set inline), so the
|
|
3485
|
+
* area (and its ancestors) stays visible while you scroll its items.
|
|
3486
|
+
* The opaque surface + z-index occlude the items scrolling underneath. */
|
|
3464
3487
|
navZone: {
|
|
3465
3488
|
display: "flex",
|
|
3466
3489
|
alignItems: "center",
|
|
3467
3490
|
gap: "{spacing.1}",
|
|
3468
|
-
|
|
3469
|
-
paddingRight: "{spacing.3}"
|
|
3491
|
+
height: "var(--nav-row-h)",
|
|
3492
|
+
paddingRight: "{spacing.3}",
|
|
3493
|
+
position: "sticky",
|
|
3494
|
+
background: "bg.surface",
|
|
3495
|
+
zIndex: "1"
|
|
3470
3496
|
},
|
|
3471
3497
|
navCaret: {
|
|
3472
3498
|
background: "transparent",
|
|
@@ -3513,6 +3539,9 @@ const schematicSlotRecipe = defineSlotRecipe({
|
|
|
3513
3539
|
border: "none",
|
|
3514
3540
|
paddingY: "2px",
|
|
3515
3541
|
paddingRight: "{spacing.3}",
|
|
3542
|
+
// Keep the auto-scroll-to-selected item clear of the pinned zone
|
|
3543
|
+
// headers (up to two ancestor levels).
|
|
3544
|
+
scrollMarginTop: "calc(var(--nav-row-h) * 2)",
|
|
3516
3545
|
fontFamily: "mono",
|
|
3517
3546
|
fontSize: "11px",
|
|
3518
3547
|
letterSpacing: "0.06em",
|
|
@@ -61603,6 +61632,83 @@ function multiSelect(arr, left, right, n2, compare) {
|
|
|
61603
61632
|
stack.push(left, mid, mid, right);
|
|
61604
61633
|
}
|
|
61605
61634
|
}
|
|
61635
|
+
const IDENTITY = { zoom: 1, tx: 0, ty: 0 };
|
|
61636
|
+
function project(x2, y2, cam) {
|
|
61637
|
+
return { sx: x2 * cam.ppu + cam.tx, sy: y2 * cam.ppu + cam.ty };
|
|
61638
|
+
}
|
|
61639
|
+
function cardTranslateCss(x2, y2) {
|
|
61640
|
+
return `translate(calc(var(--cam-ppu) * ${x2} * 1px + var(--cam-tx)), calc(var(--cam-ppu) * ${y2} * 1px + var(--cam-ty)))`;
|
|
61641
|
+
}
|
|
61642
|
+
function cardWidthCss(width) {
|
|
61643
|
+
return `calc(var(--cam-ppu) * ${width} * 1px)`;
|
|
61644
|
+
}
|
|
61645
|
+
function viewportWorldBbox(cam, width, height) {
|
|
61646
|
+
return {
|
|
61647
|
+
minX: -cam.tx / cam.ppu,
|
|
61648
|
+
minY: -cam.ty / cam.ppu,
|
|
61649
|
+
maxX: (width - cam.tx) / cam.ppu,
|
|
61650
|
+
maxY: (height - cam.ty) / cam.ppu
|
|
61651
|
+
};
|
|
61652
|
+
}
|
|
61653
|
+
function bboxOverlaps(a2, b2) {
|
|
61654
|
+
return a2.maxX >= b2.minX && a2.minX <= b2.maxX && a2.maxY >= b2.minY && a2.minY <= b2.maxY;
|
|
61655
|
+
}
|
|
61656
|
+
function pointsBbox(pts) {
|
|
61657
|
+
if (pts.length === 0) return null;
|
|
61658
|
+
let minX = Infinity, minY = Infinity, maxX = -Infinity, maxY = -Infinity;
|
|
61659
|
+
for (const p2 of pts) {
|
|
61660
|
+
if (p2.x < minX) minX = p2.x;
|
|
61661
|
+
if (p2.y < minY) minY = p2.y;
|
|
61662
|
+
if (p2.x > maxX) maxX = p2.x;
|
|
61663
|
+
if (p2.y > maxY) maxY = p2.y;
|
|
61664
|
+
}
|
|
61665
|
+
return { minX, minY, maxX, maxY };
|
|
61666
|
+
}
|
|
61667
|
+
function zoomAbout(prev, factor, px, py, min2, max2) {
|
|
61668
|
+
const zoom = Math.max(min2, Math.min(max2, prev.zoom * factor));
|
|
61669
|
+
if (zoom === 1) return IDENTITY;
|
|
61670
|
+
const k2 = zoom / prev.zoom;
|
|
61671
|
+
return { zoom, tx: px - k2 * (px - prev.tx), ty: py - k2 * (py - prev.ty) };
|
|
61672
|
+
}
|
|
61673
|
+
function nextMode(mode, event) {
|
|
61674
|
+
switch (event) {
|
|
61675
|
+
case "pointerDown":
|
|
61676
|
+
return "panning";
|
|
61677
|
+
case "wheel":
|
|
61678
|
+
return "wheeling";
|
|
61679
|
+
case "zoom":
|
|
61680
|
+
return "wheeling";
|
|
61681
|
+
case "flyStart":
|
|
61682
|
+
return "flying";
|
|
61683
|
+
case "pointerUp":
|
|
61684
|
+
return mode === "panning" ? "idle" : mode;
|
|
61685
|
+
case "flyEnd":
|
|
61686
|
+
return mode === "flying" ? "idle" : mode;
|
|
61687
|
+
case "cancel":
|
|
61688
|
+
return "idle";
|
|
61689
|
+
}
|
|
61690
|
+
}
|
|
61691
|
+
function cancelsFly(mode, event) {
|
|
61692
|
+
return mode === "flying" && (event === "pointerDown" || event === "wheel" || event === "zoom" || event === "cancel");
|
|
61693
|
+
}
|
|
61694
|
+
function makeRafCoalescer(schedule, cancel) {
|
|
61695
|
+
let handle2 = null;
|
|
61696
|
+
return {
|
|
61697
|
+
request(run) {
|
|
61698
|
+
if (handle2 !== null) return;
|
|
61699
|
+
handle2 = schedule(() => {
|
|
61700
|
+
handle2 = null;
|
|
61701
|
+
run();
|
|
61702
|
+
});
|
|
61703
|
+
},
|
|
61704
|
+
cancel() {
|
|
61705
|
+
if (handle2 !== null) {
|
|
61706
|
+
cancel(handle2);
|
|
61707
|
+
handle2 = null;
|
|
61708
|
+
}
|
|
61709
|
+
}
|
|
61710
|
+
};
|
|
61711
|
+
}
|
|
61606
61712
|
const css = (c2, a2 = 1) => a2 >= 1 ? `rgb(${c2[0]},${c2[1]},${c2[2]})` : `rgba(${c2[0]},${c2[1]},${c2[2]},${a2})`;
|
|
61607
61713
|
function toneRGB(p2, tone, kind) {
|
|
61608
61714
|
switch (tone) {
|
|
@@ -61683,6 +61789,7 @@ function arcFromBulge(p1, p2, bulge) {
|
|
|
61683
61789
|
const mx = (p1.x + p2.x) / 2, my = (p1.y + p2.y) / 2;
|
|
61684
61790
|
const d2 = chord / 2 / Math.tan(theta / 2);
|
|
61685
61791
|
const cx2 = mx - dy / chord * d2, cy = my + dx / chord * d2;
|
|
61792
|
+
if (!Number.isFinite(radius) || !Number.isFinite(d2) || !Number.isFinite(cx2) || !Number.isFinite(cy)) return null;
|
|
61686
61793
|
return {
|
|
61687
61794
|
cx: cx2,
|
|
61688
61795
|
cy,
|
|
@@ -61710,22 +61817,76 @@ function traceVertices(ctx, pts, closed) {
|
|
|
61710
61817
|
ctx.closePath();
|
|
61711
61818
|
}
|
|
61712
61819
|
}
|
|
61820
|
+
const MARKER_LABEL_FONT = '600 10px ui-monospace, "SF Mono", Menlo, monospace';
|
|
61821
|
+
const MARKER_DOT_RADIUS = 5;
|
|
61822
|
+
const MARKER_DOT_HIT_RADIUS = 10;
|
|
61823
|
+
const MARKER_PIN_PAD_X = 6, MARKER_PIN_DOT_W = 7, MARKER_PIN_GAP = 4, MARKER_PIN_H = 16;
|
|
61824
|
+
function markerHitbox(item, tier, cam, measure) {
|
|
61825
|
+
const { sx, sy } = project(item.x, item.y, cam);
|
|
61826
|
+
if (tier === "dot") return { kind: "circle", cx: sx, cy: sy, r: MARKER_DOT_HIT_RADIUS };
|
|
61827
|
+
const tw = measure(item.label);
|
|
61828
|
+
const w2 = MARKER_PIN_PAD_X + MARKER_PIN_DOT_W + MARKER_PIN_GAP + tw + MARKER_PIN_PAD_X;
|
|
61829
|
+
return { kind: "rect", left: sx - w2 / 2, top: sy - MARKER_PIN_H / 2, w: w2, h: MARKER_PIN_H };
|
|
61830
|
+
}
|
|
61831
|
+
function markerHit(box, sx, sy) {
|
|
61832
|
+
return box.kind === "circle" ? Math.hypot(sx - box.cx, sy - box.cy) <= box.r : sx >= box.left && sx <= box.left + box.w && sy >= box.top && sy <= box.top + box.h;
|
|
61833
|
+
}
|
|
61834
|
+
function hatchSpacing(rawSpacing) {
|
|
61835
|
+
return Number.isFinite(rawSpacing) ? Math.max(1, rawSpacing) : 1;
|
|
61836
|
+
}
|
|
61837
|
+
function hatchSweepBounds(x2, y2, w2, h2, width, height, dx, dy, diag, spacing) {
|
|
61838
|
+
const nx = -dy, ny = dx;
|
|
61839
|
+
if (Math.abs(nx) <= 1e-6) return { oStart: -diag, oEnd: diag };
|
|
61840
|
+
const cx0 = Math.max(x2, 0), cy0 = Math.max(y2, 0);
|
|
61841
|
+
const cx1 = Math.min(x2 + w2, width), cy1 = Math.min(y2 + h2, height);
|
|
61842
|
+
const cs = [cx0 * nx + cy0 * ny, cx1 * nx + cy0 * ny, cx0 * nx + cy1 * ny, cx1 * nx + cy1 * ny];
|
|
61843
|
+
const oOfC = (c2) => (c2 - x2 * nx - (y2 - diag * dy) * ny) / nx;
|
|
61844
|
+
const oA = oOfC(Math.min(...cs)), oB = oOfC(Math.max(...cs));
|
|
61845
|
+
return {
|
|
61846
|
+
oStart: Math.max(-diag, -diag + Math.floor((Math.min(oA, oB) + diag) / spacing) * spacing - spacing),
|
|
61847
|
+
oEnd: Math.min(diag, Math.max(oA, oB) + spacing)
|
|
61848
|
+
};
|
|
61849
|
+
}
|
|
61850
|
+
function zoneWorldBbox(zone, geom) {
|
|
61851
|
+
const bb = { minX: zone.x, minY: zone.y, maxX: zone.x + zone.width, maxY: zone.y + zone.height };
|
|
61852
|
+
if (geom !== void 0 && geom.type === "circle") {
|
|
61853
|
+
const cx2 = zone.x + zone.width / 2, cy = zone.y + zone.height / 2, r2 = geom.value.radius;
|
|
61854
|
+
bb.minX = Math.min(bb.minX, cx2 - r2);
|
|
61855
|
+
bb.minY = Math.min(bb.minY, cy - r2);
|
|
61856
|
+
bb.maxX = Math.max(bb.maxX, cx2 + r2);
|
|
61857
|
+
bb.maxY = Math.max(bb.maxY, cy + r2);
|
|
61858
|
+
} else if (geom !== void 0 && geom.type !== "rect") {
|
|
61859
|
+
const g2 = pointsBbox(geom.value.vertices);
|
|
61860
|
+
if (g2 !== null) {
|
|
61861
|
+
bb.minX = Math.min(bb.minX, g2.minX);
|
|
61862
|
+
bb.minY = Math.min(bb.minY, g2.minY);
|
|
61863
|
+
bb.maxX = Math.max(bb.maxX, g2.maxX);
|
|
61864
|
+
bb.maxY = Math.max(bb.maxY, g2.maxY);
|
|
61865
|
+
}
|
|
61866
|
+
}
|
|
61867
|
+
return bb;
|
|
61868
|
+
}
|
|
61713
61869
|
function paintSchematic(input) {
|
|
61714
61870
|
var _a2, _b, _c, _d;
|
|
61715
61871
|
const { ctx, value, cam, width, height, visibleItems, tiers, selected, centers, palette: p2 } = input;
|
|
61716
61872
|
const wx = (x2) => x2 * cam.ppu + cam.tx;
|
|
61717
61873
|
const wy = (y2) => y2 * cam.ppu + cam.ty;
|
|
61718
61874
|
const ppu = cam.ppu;
|
|
61719
|
-
|
|
61875
|
+
const viewBbox = viewportWorldBbox(cam, width, height);
|
|
61876
|
+
ctx.save();
|
|
61877
|
+
ctx.setTransform(1, 0, 0, 1, 0, 0);
|
|
61878
|
+
ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);
|
|
61879
|
+
ctx.restore();
|
|
61720
61880
|
ctx.lineJoin = "round";
|
|
61721
61881
|
for (const zone of value.zones) {
|
|
61882
|
+
const geom = getSomeorUndefined(zone.geometry);
|
|
61883
|
+
if (!bboxOverlaps(zoneWorldBbox(zone, geom), viewBbox)) continue;
|
|
61722
61884
|
const pattern = zone.pattern;
|
|
61723
61885
|
const patternTone = (pattern.value.tone.type === "some" ? pattern.value.tone.value.type : void 0) ?? "muted";
|
|
61724
61886
|
const tint = resolveTint(p2, getSomeorUndefined(zone.color), (_a2 = getSomeorUndefined(zone.tone)) == null ? void 0 : _a2.type, toneRGB(p2, patternTone, "zone"));
|
|
61725
61887
|
const zbg = getSomeorUndefined(zone.bg);
|
|
61726
61888
|
const zFillAlpha = getSomeorUndefined(zone.fillOpacity) ?? 0.15;
|
|
61727
61889
|
const zWeight = getSomeorUndefined(zone.weight);
|
|
61728
|
-
const geom = getSomeorUndefined(zone.geometry);
|
|
61729
61890
|
const x2 = wx(zone.x), y2 = wy(zone.y), w2 = zone.width * ppu, h2 = zone.height * ppu;
|
|
61730
61891
|
const fillShape = () => {
|
|
61731
61892
|
if (zbg === void 0) return;
|
|
@@ -61773,8 +61934,8 @@ function paintSchematic(input) {
|
|
|
61773
61934
|
}
|
|
61774
61935
|
}
|
|
61775
61936
|
} else if (pattern.type === "hatch") {
|
|
61776
|
-
const spacing = pattern.value.spacing
|
|
61777
|
-
const angle = (pattern.value.angle
|
|
61937
|
+
const spacing = hatchSpacing(getSomeorUndefined(pattern.value.spacing) ?? 8);
|
|
61938
|
+
const angle = (getSomeorUndefined(pattern.value.angle) ?? 45) * Math.PI / 180;
|
|
61778
61939
|
ctx.save();
|
|
61779
61940
|
ctx.beginPath();
|
|
61780
61941
|
ctx.rect(x2, y2, w2, h2);
|
|
@@ -61791,8 +61952,9 @@ function paintSchematic(input) {
|
|
|
61791
61952
|
ctx.lineWidth = zWeight ?? 1;
|
|
61792
61953
|
const dx = Math.cos(angle), dy = Math.sin(angle);
|
|
61793
61954
|
const diag = Math.hypot(w2, h2);
|
|
61955
|
+
const { oStart, oEnd } = hatchSweepBounds(x2, y2, w2, h2, width, height, dx, dy, diag, spacing);
|
|
61794
61956
|
ctx.beginPath();
|
|
61795
|
-
for (let o2 =
|
|
61957
|
+
for (let o2 = oStart; o2 < oEnd; o2 += spacing) {
|
|
61796
61958
|
ctx.moveTo(x2 + o2, y2 - diag * dy);
|
|
61797
61959
|
ctx.lineTo(x2 + o2 + dx * 2 * diag, y2 - diag * dy + dy * 2 * diag);
|
|
61798
61960
|
}
|
|
@@ -61826,6 +61988,8 @@ function paintSchematic(input) {
|
|
|
61826
61988
|
for (const link2 of value.links) {
|
|
61827
61989
|
const from = centers.get(link2.from), to = centers.get(link2.to);
|
|
61828
61990
|
if (!from || !to) continue;
|
|
61991
|
+
const linkBbox = pointsBbox([from, ...link2.via, to]);
|
|
61992
|
+
if (linkBbox !== null && !bboxOverlaps(linkBbox, viewBbox)) continue;
|
|
61829
61993
|
const anchors = [from, ...link2.via, to].map((q) => ({ x: wx(q.x), y: wy(q.y) }));
|
|
61830
61994
|
const corner = link2.route.type === "orthogonal" ? link2.route.value.corner.type === "some" ? link2.route.value.corner.value : 8 : 0;
|
|
61831
61995
|
const pts = link2.route.type === "orthogonal" ? orthogonalize(anchors) : anchors;
|
|
@@ -61899,7 +62063,7 @@ function paintSchematic(input) {
|
|
|
61899
62063
|
const x2 = wx(item.x), y2 = wy(item.y);
|
|
61900
62064
|
if (tier === "dot") {
|
|
61901
62065
|
ctx.beginPath();
|
|
61902
|
-
ctx.arc(x2, y2,
|
|
62066
|
+
ctx.arc(x2, y2, MARKER_DOT_RADIUS, 0, Math.PI * 2);
|
|
61903
62067
|
ctx.fillStyle = tint;
|
|
61904
62068
|
ctx.fill();
|
|
61905
62069
|
ctx.lineWidth = 1.5;
|
|
@@ -61914,11 +62078,10 @@ function paintSchematic(input) {
|
|
|
61914
62078
|
}
|
|
61915
62079
|
continue;
|
|
61916
62080
|
}
|
|
61917
|
-
ctx.font =
|
|
61918
|
-
const
|
|
61919
|
-
|
|
61920
|
-
const
|
|
61921
|
-
const left = x2 - w2 / 2, top = y2 - h2 / 2;
|
|
62081
|
+
ctx.font = MARKER_LABEL_FONT;
|
|
62082
|
+
const box = markerHitbox(item, "label", cam, (t4) => ctx.measureText(t4).width);
|
|
62083
|
+
if (box.kind !== "rect") continue;
|
|
62084
|
+
const { left, top, w: w2, h: h2 } = box;
|
|
61922
62085
|
ctx.beginPath();
|
|
61923
62086
|
(_d = ctx.roundRect) == null ? void 0 : _d.call(ctx, left, top, w2, h2, h2 / 2);
|
|
61924
62087
|
if (!ctx.roundRect) ctx.rect(left, top, w2, h2);
|
|
@@ -61928,12 +62091,12 @@ function paintSchematic(input) {
|
|
|
61928
62091
|
ctx.strokeStyle = isSel ? css(p2.fg) : css(p2.borderStrong);
|
|
61929
62092
|
ctx.stroke();
|
|
61930
62093
|
ctx.beginPath();
|
|
61931
|
-
ctx.arc(left +
|
|
62094
|
+
ctx.arc(left + MARKER_PIN_PAD_X + MARKER_PIN_DOT_W / 2, y2, MARKER_PIN_DOT_W / 2, 0, Math.PI * 2);
|
|
61932
62095
|
ctx.fillStyle = tint;
|
|
61933
62096
|
ctx.fill();
|
|
61934
62097
|
ctx.fillStyle = css(p2.fg);
|
|
61935
62098
|
ctx.textBaseline = "middle";
|
|
61936
|
-
ctx.fillText(item.label, left +
|
|
62099
|
+
ctx.fillText(item.label, left + MARKER_PIN_PAD_X + MARKER_PIN_DOT_W + MARKER_PIN_GAP, y2);
|
|
61937
62100
|
}
|
|
61938
62101
|
}
|
|
61939
62102
|
const TOKENS = {
|
|
@@ -61980,7 +62143,6 @@ const SchematicPaletteProbe = memo$2(function SchematicPaletteProbe2({ onResolve
|
|
|
61980
62143
|
});
|
|
61981
62144
|
library$1.add(icons$2);
|
|
61982
62145
|
const schematicEqual = equalFor(Schematic.Types.Schematic);
|
|
61983
|
-
const IDENTITY = { zoom: 1, tx: 0, ty: 0 };
|
|
61984
62146
|
const MAX_ZOOM = 40;
|
|
61985
62147
|
const LOD_CARD_PPU = 30;
|
|
61986
62148
|
const LOD_LABEL_PPU = 16;
|
|
@@ -62085,7 +62247,7 @@ function declutterTiers(items, tree, baseLod, ppu, selected) {
|
|
|
62085
62247
|
if (selected !== null && tiers.has(selected)) tiers.set(selected, baseLod);
|
|
62086
62248
|
return tiers;
|
|
62087
62249
|
}
|
|
62088
|
-
const EastChakraSchematic = memo$2(function EastChakraSchematic2({ value }) {
|
|
62250
|
+
const EastChakraSchematic = memo$2(function EastChakraSchematic2({ value, storageKey }) {
|
|
62089
62251
|
const styles2 = useSlotRecipe({ key: "schematic" })();
|
|
62090
62252
|
const { width: W2, height: H } = value.extent;
|
|
62091
62253
|
const onSelectFn = useMemo(() => getSomeorUndefined(value.onSelect), [value.onSelect]);
|
|
@@ -62095,14 +62257,17 @@ const EastChakraSchematic = memo$2(function EastChakraSchematic2({ value }) {
|
|
|
62095
62257
|
const showMinimap = getSomeorUndefined(value.minimap) ?? value.items.length >= MINIMAP_AUTO;
|
|
62096
62258
|
const fixedHeight = getSomeorUndefined(value.height);
|
|
62097
62259
|
const [selected, setSelected] = useState(null);
|
|
62098
|
-
const [view, setView] = useState(IDENTITY);
|
|
62099
62260
|
const [query, setQuery] = useState("");
|
|
62100
62261
|
const [openZone, setOpenZone] = useState(null);
|
|
62101
|
-
const
|
|
62262
|
+
const { state: persisted, setState: setPersisted } = usePersistedState(storageKey, { navCollapsed: false });
|
|
62263
|
+
const navCollapsed = persisted.navCollapsed;
|
|
62264
|
+
const setNavCollapsed = useCallback((next) => setPersisted((prev) => ({ ...prev, navCollapsed: next })), [setPersisted]);
|
|
62102
62265
|
const [palette, setPalette] = useState(null);
|
|
62103
62266
|
const navTreeRef = useRef(null);
|
|
62104
62267
|
const canvasRef = useRef(null);
|
|
62105
62268
|
const drawRef = useRef(null);
|
|
62269
|
+
const cardLayerRef = useRef(null);
|
|
62270
|
+
const gridRef = useRef(null);
|
|
62106
62271
|
const [size, setSize] = useState(null);
|
|
62107
62272
|
useLayoutEffect(() => {
|
|
62108
62273
|
const el = canvasRef.current;
|
|
@@ -62113,10 +62278,30 @@ const EastChakraSchematic = memo$2(function EastChakraSchematic2({ value }) {
|
|
|
62113
62278
|
ro.observe(el);
|
|
62114
62279
|
return () => ro.disconnect();
|
|
62115
62280
|
}, []);
|
|
62281
|
+
const [dpr, setDpr] = useState(() => typeof window !== "undefined" ? window.devicePixelRatio || 1 : 1);
|
|
62282
|
+
useEffect(() => {
|
|
62283
|
+
if (typeof window === "undefined" || typeof window.matchMedia !== "function") return;
|
|
62284
|
+
let cleanup = () => {
|
|
62285
|
+
};
|
|
62286
|
+
const subscribe2 = () => {
|
|
62287
|
+
const mql = window.matchMedia(`(resolution: ${window.devicePixelRatio}dppx)`);
|
|
62288
|
+
const onChange2 = () => {
|
|
62289
|
+
cleanup();
|
|
62290
|
+
setDpr(window.devicePixelRatio || 1);
|
|
62291
|
+
subscribe2();
|
|
62292
|
+
};
|
|
62293
|
+
mql.addEventListener("change", onChange2);
|
|
62294
|
+
cleanup = () => mql.removeEventListener("change", onChange2);
|
|
62295
|
+
};
|
|
62296
|
+
subscribe2();
|
|
62297
|
+
return () => cleanup();
|
|
62298
|
+
}, []);
|
|
62299
|
+
const cameraRef = useRef(IDENTITY);
|
|
62300
|
+
const modeRef = useRef("idle");
|
|
62301
|
+
const animRef = useRef(null);
|
|
62302
|
+
const [cameraSnapshot, setCameraSnapshot] = useState(IDENTITY);
|
|
62116
62303
|
const fit = size !== null ? Math.min(size.w / W2, size.h / H) : 0;
|
|
62117
|
-
const ppu = fit *
|
|
62118
|
-
const wx = (x2) => x2 * ppu + view.tx;
|
|
62119
|
-
const wy = (y2) => y2 * ppu + view.ty;
|
|
62304
|
+
const ppu = fit * cameraSnapshot.zoom;
|
|
62120
62305
|
const centers = useMemo(() => {
|
|
62121
62306
|
const out = /* @__PURE__ */ new Map();
|
|
62122
62307
|
for (const item of value.items) out.set(item.key, { x: item.x, y: item.y });
|
|
@@ -62149,12 +62334,12 @@ const EastChakraSchematic = memo$2(function EastChakraSchematic2({ value }) {
|
|
|
62149
62334
|
const visibleItems = useMemo(() => {
|
|
62150
62335
|
if (size === null || ppu === 0) return [];
|
|
62151
62336
|
return index2.search({
|
|
62152
|
-
minX: -
|
|
62153
|
-
minY: -
|
|
62154
|
-
maxX: (size.w -
|
|
62155
|
-
maxY: (size.h -
|
|
62337
|
+
minX: -cameraSnapshot.tx / ppu,
|
|
62338
|
+
minY: -cameraSnapshot.ty / ppu,
|
|
62339
|
+
maxX: (size.w - cameraSnapshot.tx) / ppu,
|
|
62340
|
+
maxY: (size.h - cameraSnapshot.ty) / ppu
|
|
62156
62341
|
}).map((b2) => b2.item);
|
|
62157
|
-
}, [index2, size, ppu,
|
|
62342
|
+
}, [index2, size, ppu, cameraSnapshot]);
|
|
62158
62343
|
const nav = useMemo(() => buildNavTree(value.zones, value.items), [value.zones, value.items]);
|
|
62159
62344
|
const zoneDisplay = useMemo(() => {
|
|
62160
62345
|
const counts = /* @__PURE__ */ new Map();
|
|
@@ -62180,106 +62365,15 @@ const EastChakraSchematic = memo$2(function EastChakraSchematic2({ value }) {
|
|
|
62180
62365
|
const indexOf = new Map(ordered.map((item, i2) => [item.key, i2]));
|
|
62181
62366
|
return { ordered, indexOf };
|
|
62182
62367
|
}, [nav]);
|
|
62183
|
-
const animRef = useRef(null);
|
|
62184
|
-
const viewRef = useRef(view);
|
|
62185
|
-
viewRef.current = view;
|
|
62186
|
-
const flyTo = useCallback((rect) => {
|
|
62187
|
-
if (size === null || fit === 0) return;
|
|
62188
|
-
const pad2 = 1.18;
|
|
62189
|
-
const zoom = Math.min(MAX_ZOOM, Math.min(size.w / (rect.w * pad2 * fit), size.h / (rect.h * pad2 * fit)));
|
|
62190
|
-
const target = {
|
|
62191
|
-
zoom,
|
|
62192
|
-
tx: size.w / 2 - (rect.x + rect.w / 2) * fit * zoom,
|
|
62193
|
-
ty: size.h / 2 - (rect.y + rect.h / 2) * fit * zoom
|
|
62194
|
-
};
|
|
62195
|
-
const from = viewRef.current;
|
|
62196
|
-
const start = performance.now();
|
|
62197
|
-
if (animRef.current !== null) cancelAnimationFrame(animRef.current);
|
|
62198
|
-
const step = (now) => {
|
|
62199
|
-
const t4 = Math.min(1, (now - start) / 350);
|
|
62200
|
-
const e3 = 1 - Math.pow(1 - t4, 3);
|
|
62201
|
-
setView({
|
|
62202
|
-
zoom: from.zoom + (target.zoom - from.zoom) * e3,
|
|
62203
|
-
tx: from.tx + (target.tx - from.tx) * e3,
|
|
62204
|
-
ty: from.ty + (target.ty - from.ty) * e3
|
|
62205
|
-
});
|
|
62206
|
-
if (t4 < 1) animRef.current = requestAnimationFrame(step);
|
|
62207
|
-
};
|
|
62208
|
-
animRef.current = requestAnimationFrame(step);
|
|
62209
|
-
}, [size, fit]);
|
|
62210
|
-
useEffect(() => () => {
|
|
62211
|
-
if (animRef.current !== null) cancelAnimationFrame(animRef.current);
|
|
62212
|
-
}, []);
|
|
62213
|
-
const flyToItem = useCallback((item) => {
|
|
62214
|
-
flyTo({ x: item.x - 4, y: item.y - 3, w: 8, h: 6 });
|
|
62215
|
-
setSelected(item.key);
|
|
62216
|
-
setOpenZone(nav.zoneOf.get(item.key) ?? null);
|
|
62217
|
-
if (onSelectFn) queueMicrotask(() => onSelectFn(item.key));
|
|
62218
|
-
}, [flyTo, nav.zoneOf, onSelectFn]);
|
|
62219
|
-
const stepSelection = useCallback((delta) => {
|
|
62220
|
-
const { ordered, indexOf } = itemOrder;
|
|
62221
|
-
if (ordered.length === 0) return;
|
|
62222
|
-
const idx = selected !== null ? indexOf.get(selected) ?? -1 : -1;
|
|
62223
|
-
flyToItem(ordered[(idx + delta + ordered.length) % ordered.length]);
|
|
62224
|
-
}, [itemOrder, selected, flyToItem]);
|
|
62225
|
-
const flyToZone = useCallback((zone) => {
|
|
62226
|
-
flyTo({ x: zone.x, y: zone.y, w: zone.width, h: zone.height });
|
|
62227
|
-
setOpenZone(zone.key);
|
|
62228
|
-
}, [flyTo]);
|
|
62229
|
-
useEffect(() => {
|
|
62230
|
-
const el = canvasRef.current;
|
|
62231
|
-
if (!el) return;
|
|
62232
|
-
const onWheel = (e3) => {
|
|
62233
|
-
e3.preventDefault();
|
|
62234
|
-
const rect = el.getBoundingClientRect();
|
|
62235
|
-
const px = e3.clientX - rect.left, py = e3.clientY - rect.top;
|
|
62236
|
-
setView((prev) => {
|
|
62237
|
-
const zoom = Math.max(1, Math.min(MAX_ZOOM, prev.zoom * Math.exp(-e3.deltaY * 15e-4)));
|
|
62238
|
-
const k2 = zoom / prev.zoom;
|
|
62239
|
-
const next = { zoom, tx: px - k2 * (px - prev.tx), ty: py - k2 * (py - prev.ty) };
|
|
62240
|
-
return zoom === 1 ? IDENTITY : next;
|
|
62241
|
-
});
|
|
62242
|
-
};
|
|
62243
|
-
el.addEventListener("wheel", onWheel, { passive: false });
|
|
62244
|
-
return () => el.removeEventListener("wheel", onWheel);
|
|
62245
|
-
}, []);
|
|
62246
|
-
const panRef = useRef(null);
|
|
62247
|
-
const movedRef = useRef(false);
|
|
62248
|
-
const onCanvasPointerDown = useCallback((e3) => {
|
|
62249
|
-
if (e3.button !== 0) return;
|
|
62250
|
-
if (e3.target.closest("button") !== null) return;
|
|
62251
|
-
panRef.current = { x: e3.clientX, y: e3.clientY, tx: viewRef.current.tx, ty: viewRef.current.ty };
|
|
62252
|
-
movedRef.current = false;
|
|
62253
|
-
e3.currentTarget.setPointerCapture(e3.pointerId);
|
|
62254
|
-
}, []);
|
|
62255
|
-
const onCanvasPointerMove = useCallback((e3) => {
|
|
62256
|
-
const pan = panRef.current;
|
|
62257
|
-
if (!pan) return;
|
|
62258
|
-
if (Math.abs(e3.clientX - pan.x) > 4 || Math.abs(e3.clientY - pan.y) > 4) movedRef.current = true;
|
|
62259
|
-
setView((prev) => ({ ...prev, tx: pan.tx + e3.clientX - pan.x, ty: pan.ty + e3.clientY - pan.y }));
|
|
62260
|
-
}, []);
|
|
62261
|
-
const onCanvasPointerUp = useCallback(() => {
|
|
62262
|
-
panRef.current = null;
|
|
62263
|
-
}, []);
|
|
62264
|
-
const resetView = useCallback(() => setView(IDENTITY), []);
|
|
62265
|
-
const zoomBy = useCallback((factor) => {
|
|
62266
|
-
if (size === null) return;
|
|
62267
|
-
const px = size.w / 2, py = size.h / 2;
|
|
62268
|
-
setView((prev) => {
|
|
62269
|
-
const zoom = Math.max(1, Math.min(MAX_ZOOM, prev.zoom * factor));
|
|
62270
|
-
const k2 = zoom / prev.zoom;
|
|
62271
|
-
return zoom === 1 ? IDENTITY : { zoom, tx: px - k2 * (px - prev.tx), ty: py - k2 * (py - prev.ty) };
|
|
62272
|
-
});
|
|
62273
|
-
}, [size]);
|
|
62274
62368
|
const [currentZone, setCurrentZone] = useState(void 0);
|
|
62275
62369
|
useEffect(() => {
|
|
62276
62370
|
const SPY_ENTER = 0.3, SPY_STAY = 0.18, SPY_MARGIN = 0.15;
|
|
62277
|
-
if (size === null || ppu === 0 ||
|
|
62371
|
+
if (size === null || ppu === 0 || cameraSnapshot.zoom <= 1.05) {
|
|
62278
62372
|
setCurrentZone(void 0);
|
|
62279
62373
|
return;
|
|
62280
62374
|
}
|
|
62281
|
-
const vx0 = -
|
|
62282
|
-
const vx1 = (size.w -
|
|
62375
|
+
const vx0 = -cameraSnapshot.tx / ppu, vy0 = -cameraSnapshot.ty / ppu;
|
|
62376
|
+
const vx1 = (size.w - cameraSnapshot.tx) / ppu, vy1 = (size.h - cameraSnapshot.ty) / ppu;
|
|
62283
62377
|
const viewArea = (vx1 - vx0) * (vy1 - vy0);
|
|
62284
62378
|
const scoreOf = (z) => {
|
|
62285
62379
|
const ix = Math.max(0, Math.min(vx1, z.x + z.width) - Math.max(vx0, z.x));
|
|
@@ -62303,73 +62397,321 @@ const EastChakraSchematic = memo$2(function EastChakraSchematic2({ value }) {
|
|
|
62303
62397
|
}
|
|
62304
62398
|
return bestScore >= SPY_ENTER ? best : void 0;
|
|
62305
62399
|
});
|
|
62306
|
-
}, [size, ppu,
|
|
62400
|
+
}, [size, ppu, cameraSnapshot, value.zones]);
|
|
62307
62401
|
const lod = ppu >= LOD_CARD_PPU ? "card" : ppu >= LOD_LABEL_PPU ? "label" : "dot";
|
|
62308
62402
|
const centerTree = useMemo(() => buildCenterTree(visibleItems), [visibleItems]);
|
|
62309
62403
|
const tiers = useMemo(() => declutterTiers(visibleItems, centerTree, lod, ppu, selected), [visibleItems, centerTree, lod, ppu, selected]);
|
|
62310
62404
|
const lowerQuery = query.trim().toLowerCase();
|
|
62311
62405
|
const searchHits = useMemo(() => lowerQuery === "" ? [] : value.items.filter((i2) => i2.key.toLowerCase().includes(lowerQuery) || i2.label.toLowerCase().includes(lowerQuery)).slice(0, 12), [lowerQuery, value.items]);
|
|
62312
62406
|
const scaleLen = ppu > 0 ? niceScaleLength(ppu, 100) : 0;
|
|
62313
|
-
|
|
62314
|
-
|
|
62315
|
-
|
|
62316
|
-
|
|
62317
|
-
|
|
62407
|
+
const valueRef = useRef(value);
|
|
62408
|
+
valueRef.current = value;
|
|
62409
|
+
const sizeRef = useRef(size);
|
|
62410
|
+
sizeRef.current = size;
|
|
62411
|
+
const fitRef = useRef(fit);
|
|
62412
|
+
fitRef.current = fit;
|
|
62413
|
+
const dprRef = useRef(dpr);
|
|
62414
|
+
dprRef.current = dpr;
|
|
62415
|
+
const paletteRef = useRef(palette);
|
|
62416
|
+
paletteRef.current = palette;
|
|
62417
|
+
const visibleItemsRef = useRef(visibleItems);
|
|
62418
|
+
visibleItemsRef.current = visibleItems;
|
|
62419
|
+
const tiersRef = useRef(tiers);
|
|
62420
|
+
tiersRef.current = tiers;
|
|
62421
|
+
const selectedRef = useRef(selected);
|
|
62422
|
+
selectedRef.current = selected;
|
|
62423
|
+
const centersRef = useRef(centers);
|
|
62424
|
+
centersRef.current = centers;
|
|
62425
|
+
const openZoneRef = useRef(openZone);
|
|
62426
|
+
openZoneRef.current = openZone;
|
|
62427
|
+
const lastPaintRef = useRef(null);
|
|
62428
|
+
const applyCamera = useCallback(() => {
|
|
62429
|
+
const sz = sizeRef.current;
|
|
62430
|
+
if (sz === null) return;
|
|
62431
|
+
const cam = cameraRef.current;
|
|
62432
|
+
const ppuLive = fitRef.current * cam.zoom;
|
|
62433
|
+
const dprLive = dprRef.current;
|
|
62434
|
+
const layer = cardLayerRef.current;
|
|
62435
|
+
if (layer !== null) {
|
|
62436
|
+
layer.style.setProperty("--cam-ppu", String(ppuLive));
|
|
62437
|
+
layer.style.setProperty("--cam-tx", `${cam.tx}px`);
|
|
62438
|
+
layer.style.setProperty("--cam-ty", `${cam.ty}px`);
|
|
62439
|
+
}
|
|
62440
|
+
const grid = gridRef.current;
|
|
62441
|
+
if (grid !== null) {
|
|
62442
|
+
const len = ppuLive > 0 ? niceScaleLength(ppuLive, 100) : 0;
|
|
62443
|
+
if (len > 0) {
|
|
62444
|
+
const major = len * ppuLive, minor = major / 5;
|
|
62445
|
+
grid.style.backgroundSize = `${major}px ${major}px, ${major}px ${major}px, ${minor}px ${minor}px, ${minor}px ${minor}px`;
|
|
62446
|
+
grid.style.backgroundPosition = `${cam.tx}px 0, 0 ${cam.ty}px, ${cam.tx}px 0, 0 ${cam.ty}px`;
|
|
62447
|
+
}
|
|
62448
|
+
}
|
|
62449
|
+
const canvas = drawRef.current, pal = paletteRef.current;
|
|
62450
|
+
if (canvas === null || pal === null) return;
|
|
62451
|
+
const last = lastPaintRef.current;
|
|
62452
|
+
if (last !== null && last.zoom === cam.zoom && last.tx === cam.tx && last.ty === cam.ty && last.vis === visibleItemsRef.current && last.tiers === tiersRef.current && last.sel === selectedRef.current && last.pal === pal && last.w === sz.w && last.h === sz.h && last.dpr === dprLive && last.val === valueRef.current) return;
|
|
62453
|
+
lastPaintRef.current = {
|
|
62454
|
+
zoom: cam.zoom,
|
|
62455
|
+
tx: cam.tx,
|
|
62456
|
+
ty: cam.ty,
|
|
62457
|
+
vis: visibleItemsRef.current,
|
|
62458
|
+
tiers: tiersRef.current,
|
|
62459
|
+
sel: selectedRef.current,
|
|
62460
|
+
pal,
|
|
62461
|
+
w: sz.w,
|
|
62462
|
+
h: sz.h,
|
|
62463
|
+
dpr: dprLive,
|
|
62464
|
+
val: valueRef.current
|
|
62465
|
+
};
|
|
62466
|
+
const bw = Math.round(sz.w * dprLive), bh = Math.round(sz.h * dprLive);
|
|
62318
62467
|
if (canvas.width !== bw || canvas.height !== bh) {
|
|
62319
62468
|
canvas.width = bw;
|
|
62320
62469
|
canvas.height = bh;
|
|
62321
62470
|
}
|
|
62322
62471
|
const ctx = canvas.getContext("2d");
|
|
62323
62472
|
if (ctx === null) return;
|
|
62324
|
-
ctx.setTransform(
|
|
62473
|
+
ctx.setTransform(dprLive, 0, 0, dprLive, 0, 0);
|
|
62325
62474
|
paintSchematic({
|
|
62326
62475
|
ctx,
|
|
62327
|
-
value,
|
|
62328
|
-
cam: { ppu, tx:
|
|
62329
|
-
width:
|
|
62330
|
-
height:
|
|
62331
|
-
visibleItems,
|
|
62332
|
-
tiers,
|
|
62333
|
-
selected,
|
|
62334
|
-
centers,
|
|
62335
|
-
palette
|
|
62476
|
+
value: valueRef.current,
|
|
62477
|
+
cam: { ppu: ppuLive, tx: cam.tx, ty: cam.ty },
|
|
62478
|
+
width: sz.w,
|
|
62479
|
+
height: sz.h,
|
|
62480
|
+
visibleItems: visibleItemsRef.current,
|
|
62481
|
+
tiers: tiersRef.current,
|
|
62482
|
+
selected: selectedRef.current,
|
|
62483
|
+
centers: centersRef.current,
|
|
62484
|
+
palette: pal
|
|
62336
62485
|
});
|
|
62337
|
-
}, [
|
|
62338
|
-
const
|
|
62339
|
-
|
|
62340
|
-
|
|
62341
|
-
|
|
62342
|
-
|
|
62343
|
-
|
|
62344
|
-
|
|
62486
|
+
}, []);
|
|
62487
|
+
const coalescerRef = useRef(null);
|
|
62488
|
+
if (coalescerRef.current === null && typeof requestAnimationFrame !== "undefined") {
|
|
62489
|
+
coalescerRef.current = makeRafCoalescer(requestAnimationFrame, cancelAnimationFrame);
|
|
62490
|
+
}
|
|
62491
|
+
const requestRender = useCallback(() => {
|
|
62492
|
+
const run = () => {
|
|
62493
|
+
applyCamera();
|
|
62494
|
+
const cam = cameraRef.current;
|
|
62495
|
+
setCameraSnapshot((prev) => prev.zoom === cam.zoom && prev.tx === cam.tx && prev.ty === cam.ty ? prev : { zoom: cam.zoom, tx: cam.tx, ty: cam.ty });
|
|
62496
|
+
};
|
|
62497
|
+
const cz = coalescerRef.current;
|
|
62498
|
+
if (cz !== null) cz.request(run);
|
|
62499
|
+
else run();
|
|
62500
|
+
}, [applyCamera]);
|
|
62501
|
+
const cancelFlyRaf = useCallback(() => {
|
|
62502
|
+
if (animRef.current !== null) {
|
|
62503
|
+
cancelAnimationFrame(animRef.current);
|
|
62504
|
+
animRef.current = null;
|
|
62505
|
+
}
|
|
62506
|
+
}, []);
|
|
62507
|
+
const transition = useCallback((event) => {
|
|
62508
|
+
if (cancelsFly(modeRef.current, event)) cancelFlyRaf();
|
|
62509
|
+
modeRef.current = nextMode(modeRef.current, event);
|
|
62510
|
+
}, [cancelFlyRaf]);
|
|
62511
|
+
const flyTo = useCallback((rect) => {
|
|
62512
|
+
if (sizeRef.current === null || fitRef.current === 0) return;
|
|
62513
|
+
const pad2 = 1.18;
|
|
62514
|
+
const frame = () => {
|
|
62515
|
+
const sz = sizeRef.current, ft = fitRef.current;
|
|
62516
|
+
if (sz === null || ft === 0) return null;
|
|
62517
|
+
const zoom = Math.min(MAX_ZOOM, Math.min(sz.w / (rect.w * pad2 * ft), sz.h / (rect.h * pad2 * ft)));
|
|
62518
|
+
return {
|
|
62519
|
+
zoom,
|
|
62520
|
+
tx: sz.w / 2 - (rect.x + rect.w / 2) * ft * zoom,
|
|
62521
|
+
ty: sz.h / 2 - (rect.y + rect.h / 2) * ft * zoom
|
|
62522
|
+
};
|
|
62523
|
+
};
|
|
62524
|
+
const from = { ...cameraRef.current };
|
|
62525
|
+
const start = performance.now();
|
|
62526
|
+
if (animRef.current !== null) cancelAnimationFrame(animRef.current);
|
|
62527
|
+
transition("flyStart");
|
|
62528
|
+
const step = (now) => {
|
|
62529
|
+
const t4 = Math.min(1, (now - start) / 350);
|
|
62530
|
+
const e3 = 1 - Math.pow(1 - t4, 3);
|
|
62531
|
+
const target = frame();
|
|
62532
|
+
if (target !== null) {
|
|
62533
|
+
cameraRef.current = {
|
|
62534
|
+
zoom: from.zoom + (target.zoom - from.zoom) * e3,
|
|
62535
|
+
tx: from.tx + (target.tx - from.tx) * e3,
|
|
62536
|
+
ty: from.ty + (target.ty - from.ty) * e3
|
|
62537
|
+
};
|
|
62538
|
+
applyCamera();
|
|
62539
|
+
const cam = cameraRef.current;
|
|
62540
|
+
setCameraSnapshot({ zoom: cam.zoom, tx: cam.tx, ty: cam.ty });
|
|
62541
|
+
}
|
|
62542
|
+
if (t4 < 1) {
|
|
62543
|
+
animRef.current = requestAnimationFrame(step);
|
|
62544
|
+
} else {
|
|
62545
|
+
animRef.current = null;
|
|
62546
|
+
transition("flyEnd");
|
|
62547
|
+
}
|
|
62548
|
+
};
|
|
62549
|
+
animRef.current = requestAnimationFrame(step);
|
|
62550
|
+
}, [applyCamera, transition]);
|
|
62551
|
+
const zoneOverrideRef = useRef(null);
|
|
62552
|
+
const flyToItem = useCallback((item) => {
|
|
62553
|
+
flyTo({ x: item.x - 4, y: item.y - 3, w: 8, h: 6 });
|
|
62554
|
+
setSelected(item.key);
|
|
62555
|
+
zoneOverrideRef.current = null;
|
|
62556
|
+
setOpenZone(nav.zoneOf.get(item.key) ?? null);
|
|
62557
|
+
if (onSelectFn) queueMicrotask(() => onSelectFn(item.key));
|
|
62558
|
+
}, [flyTo, nav.zoneOf, onSelectFn]);
|
|
62559
|
+
const stepSelection = useCallback((delta) => {
|
|
62560
|
+
const { ordered, indexOf } = itemOrder;
|
|
62561
|
+
if (ordered.length === 0) return;
|
|
62562
|
+
const idx = selected !== null ? indexOf.get(selected) ?? -1 : -1;
|
|
62563
|
+
flyToItem(ordered[(idx + delta + ordered.length) % ordered.length]);
|
|
62564
|
+
}, [itemOrder, selected, flyToItem]);
|
|
62565
|
+
const flyToZone = useCallback((zone) => {
|
|
62566
|
+
flyTo({ x: zone.x, y: zone.y, w: zone.width, h: zone.height });
|
|
62567
|
+
zoneOverrideRef.current = null;
|
|
62568
|
+
setOpenZone(zone.key);
|
|
62569
|
+
}, [flyTo]);
|
|
62570
|
+
useEffect(() => {
|
|
62571
|
+
const el = canvasRef.current;
|
|
62572
|
+
if (!el) return;
|
|
62573
|
+
const onWheel = (e3) => {
|
|
62574
|
+
e3.preventDefault();
|
|
62575
|
+
const rect = el.getBoundingClientRect();
|
|
62576
|
+
const px = e3.clientX - rect.left, py = e3.clientY - rect.top;
|
|
62577
|
+
transition("wheel");
|
|
62578
|
+
cameraRef.current = zoomAbout(cameraRef.current, Math.exp(-e3.deltaY * 15e-4), px, py, 1, MAX_ZOOM);
|
|
62579
|
+
requestRender();
|
|
62580
|
+
};
|
|
62581
|
+
el.addEventListener("wheel", onWheel, { passive: false });
|
|
62582
|
+
return () => el.removeEventListener("wheel", onWheel);
|
|
62583
|
+
}, [transition, requestRender]);
|
|
62584
|
+
const panRef = useRef(null);
|
|
62585
|
+
const movedRef = useRef(false);
|
|
62586
|
+
const pickAt = useCallback((host, clientX, clientY) => {
|
|
62587
|
+
var _a2, _b, _c;
|
|
62588
|
+
const sz = sizeRef.current;
|
|
62589
|
+
if (sz === null) return false;
|
|
62590
|
+
const cam = cameraRef.current;
|
|
62591
|
+
const ppuLive = fitRef.current * cam.zoom;
|
|
62592
|
+
if (ppuLive === 0) return false;
|
|
62593
|
+
const rect = host.getBoundingClientRect();
|
|
62594
|
+
const sx = clientX - rect.left, sy = clientY - rect.top;
|
|
62595
|
+
const wxp = (sx - cam.tx) / ppuLive, wyp = (sy - cam.ty) / ppuLive;
|
|
62596
|
+
const select = (key) => {
|
|
62597
|
+
setSelected(key);
|
|
62598
|
+
if (onSelectFn) queueMicrotask(() => onSelectFn(key));
|
|
62599
|
+
};
|
|
62600
|
+
for (const it of visibleItems) {
|
|
62345
62601
|
if ((tiers.get(it.key) ?? lod) !== "card") continue;
|
|
62346
62602
|
const fp = getSomeorUndefined(it.footprint);
|
|
62347
62603
|
if (fp === void 0 || fp.type === "rect") continue;
|
|
62348
62604
|
const hit = fp.type === "circle" ? Math.hypot(wxp - it.x, wyp - it.y) <= fp.value.radius : pointInPolygon(wxp, wyp, fp.value.vertices);
|
|
62349
62605
|
if (hit) {
|
|
62350
|
-
|
|
62351
|
-
|
|
62352
|
-
|
|
62606
|
+
select(it.key);
|
|
62607
|
+
return true;
|
|
62608
|
+
}
|
|
62609
|
+
}
|
|
62610
|
+
if (typeof document !== "undefined") {
|
|
62611
|
+
const cardKey = (_b = (_a2 = document.elementFromPoint(clientX, clientY)) == null ? void 0 : _a2.closest("[data-card-key]")) == null ? void 0 : _b.getAttribute("data-card-key");
|
|
62612
|
+
if (cardKey !== null && cardKey !== void 0) {
|
|
62613
|
+
select(cardKey);
|
|
62614
|
+
return true;
|
|
62353
62615
|
}
|
|
62354
62616
|
}
|
|
62617
|
+
const ctx = ((_c = drawRef.current) == null ? void 0 : _c.getContext("2d")) ?? null;
|
|
62618
|
+
if (ctx !== null) {
|
|
62619
|
+
ctx.save();
|
|
62620
|
+
ctx.font = MARKER_LABEL_FONT;
|
|
62621
|
+
}
|
|
62622
|
+
const camScreen = { ppu: ppuLive, tx: cam.tx, ty: cam.ty };
|
|
62355
62623
|
let best = null, bestD = Infinity;
|
|
62356
62624
|
for (const it of visibleItems) {
|
|
62357
62625
|
const tier = tiers.get(it.key) ?? lod;
|
|
62358
62626
|
if (tier === "card") continue;
|
|
62359
|
-
const
|
|
62360
|
-
|
|
62361
|
-
|
|
62627
|
+
const box = markerHitbox(it, tier, camScreen, (t4) => ctx !== null ? ctx.measureText(t4).width : t4.length * 6);
|
|
62628
|
+
if (!markerHit(box, sx, sy)) continue;
|
|
62629
|
+
const d2 = Math.hypot(it.x * ppuLive + cam.tx - sx, it.y * ppuLive + cam.ty - sy);
|
|
62630
|
+
if (d2 < bestD) {
|
|
62362
62631
|
best = it;
|
|
62363
62632
|
bestD = d2;
|
|
62364
62633
|
}
|
|
62365
62634
|
}
|
|
62366
|
-
if (
|
|
62367
|
-
|
|
62635
|
+
if (ctx !== null) ctx.restore();
|
|
62636
|
+
if (best !== null) {
|
|
62637
|
+
flyToItem(best);
|
|
62638
|
+
return true;
|
|
62639
|
+
}
|
|
62640
|
+
return false;
|
|
62641
|
+
}, [tiers, lod, visibleItems, onSelectFn, flyToItem]);
|
|
62642
|
+
const onCanvasPointerDown = useCallback((e3) => {
|
|
62643
|
+
if (e3.button !== 0) return;
|
|
62644
|
+
if (e3.target.closest("button") !== null) return;
|
|
62645
|
+
transition("pointerDown");
|
|
62646
|
+
panRef.current = { x: e3.clientX, y: e3.clientY, tx: cameraRef.current.tx, ty: cameraRef.current.ty };
|
|
62647
|
+
movedRef.current = false;
|
|
62648
|
+
e3.currentTarget.setPointerCapture(e3.pointerId);
|
|
62649
|
+
}, [transition]);
|
|
62650
|
+
const onCanvasPointerMove = useCallback((e3) => {
|
|
62651
|
+
const pan = panRef.current;
|
|
62652
|
+
if (!pan) return;
|
|
62653
|
+
if (Math.abs(e3.clientX - pan.x) > 4 || Math.abs(e3.clientY - pan.y) > 4) movedRef.current = true;
|
|
62654
|
+
cameraRef.current = { ...cameraRef.current, tx: pan.tx + e3.clientX - pan.x, ty: pan.ty + e3.clientY - pan.y };
|
|
62655
|
+
requestRender();
|
|
62656
|
+
}, [requestRender]);
|
|
62657
|
+
const endPan = useCallback(() => {
|
|
62658
|
+
if (panRef.current === null) return false;
|
|
62659
|
+
panRef.current = null;
|
|
62660
|
+
transition("pointerUp");
|
|
62661
|
+
return true;
|
|
62662
|
+
}, [transition]);
|
|
62663
|
+
const onCanvasPointerUp = useCallback((e3) => {
|
|
62664
|
+
const wasPress = endPan();
|
|
62665
|
+
if (!wasPress || movedRef.current) return;
|
|
62666
|
+
if (!pickAt(e3.currentTarget, e3.clientX, e3.clientY)) setSelected(null);
|
|
62667
|
+
}, [endPan, pickAt]);
|
|
62668
|
+
const onCanvasPointerCancel = useCallback(() => {
|
|
62669
|
+
movedRef.current = false;
|
|
62670
|
+
endPan();
|
|
62671
|
+
}, [endPan]);
|
|
62672
|
+
const resetView = useCallback(() => {
|
|
62673
|
+
transition("cancel");
|
|
62674
|
+
cameraRef.current = IDENTITY;
|
|
62675
|
+
requestRender();
|
|
62676
|
+
}, [transition, requestRender]);
|
|
62677
|
+
const zoomBy = useCallback((factor) => {
|
|
62678
|
+
const sz = sizeRef.current;
|
|
62679
|
+
if (sz === null) return;
|
|
62680
|
+
transition("zoom");
|
|
62681
|
+
cameraRef.current = zoomAbout(cameraRef.current, factor, sz.w / 2, sz.h / 2, 1, MAX_ZOOM);
|
|
62682
|
+
requestRender();
|
|
62683
|
+
}, [transition, requestRender]);
|
|
62684
|
+
const minimapDragRef = useRef(false);
|
|
62685
|
+
const minimapJump = useCallback((el, clientX, clientY) => {
|
|
62686
|
+
const sz = sizeRef.current;
|
|
62687
|
+
if (sz === null) return;
|
|
62688
|
+
const rect = el.getBoundingClientRect();
|
|
62689
|
+
const cx2 = (clientX - rect.left) / rect.width * W2;
|
|
62690
|
+
const cy = (clientY - rect.top) / rect.height * H;
|
|
62691
|
+
const cam = cameraRef.current;
|
|
62692
|
+
cameraRef.current = { ...cam, tx: sz.w / 2 - cx2 * fitRef.current * cam.zoom, ty: sz.h / 2 - cy * fitRef.current * cam.zoom };
|
|
62693
|
+
requestRender();
|
|
62694
|
+
}, [W2, H, requestRender]);
|
|
62695
|
+
useEffect(() => () => {
|
|
62696
|
+
var _a2;
|
|
62697
|
+
(_a2 = coalescerRef.current) == null ? void 0 : _a2.cancel();
|
|
62698
|
+
if (animRef.current !== null) cancelAnimationFrame(animRef.current);
|
|
62699
|
+
}, [animRef]);
|
|
62700
|
+
useLayoutEffect(() => {
|
|
62701
|
+
applyCamera();
|
|
62702
|
+
}, [applyCamera, value, visibleItems, tiers, selected, palette, size, dpr, fit, cameraSnapshot]);
|
|
62368
62703
|
const toggleZone = useCallback((key) => {
|
|
62369
|
-
|
|
62704
|
+
const collapsing = openZoneRef.current === key;
|
|
62705
|
+
zoneOverrideRef.current = collapsing ? key : null;
|
|
62706
|
+
setOpenZone(collapsing ? nav.parentOf.get(key) ?? null : key);
|
|
62370
62707
|
}, [nav.parentOf]);
|
|
62371
62708
|
useEffect(() => {
|
|
62372
|
-
if (currentZone
|
|
62709
|
+
if (currentZone === void 0) return;
|
|
62710
|
+
if (zoneOverrideRef.current !== null) {
|
|
62711
|
+
if (zoneOverrideRef.current === currentZone) return;
|
|
62712
|
+
zoneOverrideRef.current = null;
|
|
62713
|
+
}
|
|
62714
|
+
setOpenZone(currentZone);
|
|
62373
62715
|
}, [currentZone]);
|
|
62374
62716
|
const openPath = useMemo(() => {
|
|
62375
62717
|
const path2 = /* @__PURE__ */ new Set();
|
|
@@ -62394,7 +62736,15 @@ const EastChakraSchematic = memo$2(function EastChakraSchematic2({ value }) {
|
|
|
62394
62736
|
Box,
|
|
62395
62737
|
{
|
|
62396
62738
|
css: styles2.navZone,
|
|
62397
|
-
style: {
|
|
62739
|
+
style: {
|
|
62740
|
+
paddingLeft: `${8 + depth * 14}px`,
|
|
62741
|
+
// Pin this header below its ancestors' pinned headers
|
|
62742
|
+
// (each level offset by one row) so the whole path stays
|
|
62743
|
+
// visible while scrolling the zone's items; shallower
|
|
62744
|
+
// levels stack above deeper ones.
|
|
62745
|
+
top: `calc(var(--nav-row-h) * ${depth})`,
|
|
62746
|
+
zIndex: 30 - depth
|
|
62747
|
+
},
|
|
62398
62748
|
...node2.zone.key === currentZone ? { "data-current": "" } : {},
|
|
62399
62749
|
children: [
|
|
62400
62750
|
expandable ? /* @__PURE__ */ jsx(
|
|
@@ -62483,32 +62833,20 @@ const EastChakraSchematic = memo$2(function EastChakraSchematic2({ value }) {
|
|
|
62483
62833
|
onPointerDown: onCanvasPointerDown,
|
|
62484
62834
|
onPointerMove: onCanvasPointerMove,
|
|
62485
62835
|
onPointerUp: onCanvasPointerUp,
|
|
62836
|
+
onPointerCancel: onCanvasPointerCancel,
|
|
62837
|
+
onLostPointerCapture: onCanvasPointerCancel,
|
|
62486
62838
|
onDoubleClick: resetView,
|
|
62487
62839
|
children: [
|
|
62488
|
-
showGrid && size !== null &&
|
|
62489
|
-
const major = scaleLen * ppu;
|
|
62490
|
-
const minor = major / 5;
|
|
62491
|
-
return /* @__PURE__ */ jsx(
|
|
62492
|
-
Box,
|
|
62493
|
-
{
|
|
62494
|
-
css: styles2.grid,
|
|
62495
|
-
style: {
|
|
62496
|
-
backgroundSize: `${major}px ${major}px, ${major}px ${major}px, ${minor}px ${minor}px, ${minor}px ${minor}px`,
|
|
62497
|
-
backgroundPosition: `${view.tx}px 0, 0 ${view.ty}px, ${view.tx}px 0, 0 ${view.ty}px`
|
|
62498
|
-
}
|
|
62499
|
-
}
|
|
62500
|
-
);
|
|
62501
|
-
})(),
|
|
62840
|
+
showGrid && size !== null && /* @__PURE__ */ jsx(Box, { ref: gridRef, css: styles2.grid }),
|
|
62502
62841
|
size !== null && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
62503
62842
|
/* @__PURE__ */ jsx(
|
|
62504
62843
|
"canvas",
|
|
62505
62844
|
{
|
|
62506
62845
|
ref: drawRef,
|
|
62507
|
-
onClick: onCanvasClick,
|
|
62508
62846
|
style: { position: "absolute", inset: 0, width: "100%", height: "100%" }
|
|
62509
62847
|
}
|
|
62510
62848
|
),
|
|
62511
|
-
visibleItems.map((item) => {
|
|
62849
|
+
/* @__PURE__ */ jsx(Box, { ref: cardLayerRef, css: styles2.cardLayer, children: visibleItems.map((item) => {
|
|
62512
62850
|
if ((tiers.get(item.key) ?? lod) !== "card") return null;
|
|
62513
62851
|
const tone = statusTone(item.status);
|
|
62514
62852
|
const isSelected = selected === item.key;
|
|
@@ -62522,17 +62860,14 @@ const EastChakraSchematic = memo$2(function EastChakraSchematic2({ value }) {
|
|
|
62522
62860
|
Box,
|
|
62523
62861
|
{
|
|
62524
62862
|
css: styles2.item,
|
|
62863
|
+
"data-card-key": item.key,
|
|
62525
62864
|
...isSelected ? { "data-selected": "" } : {},
|
|
62526
62865
|
style: {
|
|
62527
|
-
left:
|
|
62528
|
-
top:
|
|
62529
|
-
|
|
62530
|
-
|
|
62531
|
-
onClick: () => {
|
|
62532
|
-
setSelected(item.key);
|
|
62533
|
-
if (onSelectFn) queueMicrotask(() => onSelectFn(item.key));
|
|
62866
|
+
left: 0,
|
|
62867
|
+
top: 0,
|
|
62868
|
+
transform: `${cardTranslateCss(item.x, item.y)} translate(-50%, -50%)`,
|
|
62869
|
+
...typeof width === "number" ? { width: cardWidthCss(width) } : {}
|
|
62534
62870
|
},
|
|
62535
|
-
onPointerDown: (e3) => e3.stopPropagation(),
|
|
62536
62871
|
children: [
|
|
62537
62872
|
/* @__PURE__ */ jsxs(Box, { css: styles2.itemHead, children: [
|
|
62538
62873
|
iconDef !== void 0 && /* @__PURE__ */ jsx(Box, { as: "span", css: styles2.itemIcon, children: /* @__PURE__ */ jsx(FontAwesomeIcon, { icon: iconDef }) }),
|
|
@@ -62546,7 +62881,7 @@ const EastChakraSchematic = memo$2(function EastChakraSchematic2({ value }) {
|
|
|
62546
62881
|
},
|
|
62547
62882
|
item.key
|
|
62548
62883
|
);
|
|
62549
|
-
}),
|
|
62884
|
+
}) }),
|
|
62550
62885
|
/* @__PURE__ */ jsxs(Box, { css: styles2.controls, children: [
|
|
62551
62886
|
/* @__PURE__ */ jsx(Box, { as: "button", css: styles2.controlButton, "aria-label": "Zoom in", title: "Zoom in (scroll)", onClick: () => zoomBy(1.5), children: /* @__PURE__ */ jsx(FontAwesomeIcon, { icon: faPlus }) }),
|
|
62552
62887
|
/* @__PURE__ */ jsx(Box, { as: "button", css: styles2.controlButton, "aria-label": "Zoom out", title: "Zoom out (scroll)", onClick: () => zoomBy(1 / 1.5), children: /* @__PURE__ */ jsx(FontAwesomeIcon, { icon: faMinus }) }),
|
|
@@ -62590,16 +62925,20 @@ const EastChakraSchematic = memo$2(function EastChakraSchematic2({ value }) {
|
|
|
62590
62925
|
style: { width: 150, height: 150 * H / W2 },
|
|
62591
62926
|
onPointerDown: (e3) => {
|
|
62592
62927
|
e3.stopPropagation();
|
|
62593
|
-
const
|
|
62594
|
-
|
|
62595
|
-
|
|
62596
|
-
|
|
62597
|
-
|
|
62598
|
-
|
|
62599
|
-
|
|
62600
|
-
|
|
62601
|
-
|
|
62602
|
-
|
|
62928
|
+
const el = e3.currentTarget;
|
|
62929
|
+
el.setPointerCapture(e3.pointerId);
|
|
62930
|
+
transition("cancel");
|
|
62931
|
+
minimapDragRef.current = true;
|
|
62932
|
+
minimapJump(el, e3.clientX, e3.clientY);
|
|
62933
|
+
},
|
|
62934
|
+
onPointerMove: (e3) => {
|
|
62935
|
+
if (!minimapDragRef.current) return;
|
|
62936
|
+
e3.stopPropagation();
|
|
62937
|
+
minimapJump(e3.currentTarget, e3.clientX, e3.clientY);
|
|
62938
|
+
},
|
|
62939
|
+
onPointerUp: (e3) => {
|
|
62940
|
+
minimapDragRef.current = false;
|
|
62941
|
+
e3.currentTarget.releasePointerCapture(e3.pointerId);
|
|
62603
62942
|
},
|
|
62604
62943
|
children: [
|
|
62605
62944
|
value.zones.map((zone) => /* @__PURE__ */ jsx(
|
|
@@ -62620,8 +62959,8 @@ const EastChakraSchematic = memo$2(function EastChakraSchematic2({ value }) {
|
|
|
62620
62959
|
{
|
|
62621
62960
|
css: styles2.minimapViewport,
|
|
62622
62961
|
style: {
|
|
62623
|
-
left: `${Math.max(0, -
|
|
62624
|
-
top: `${Math.max(0, -
|
|
62962
|
+
left: `${Math.max(0, -cameraSnapshot.tx / ppu / W2 * 100)}%`,
|
|
62963
|
+
top: `${Math.max(0, -cameraSnapshot.ty / ppu / H * 100)}%`,
|
|
62625
62964
|
width: `${Math.min(100, size.w / ppu / W2 * 100)}%`,
|
|
62626
62965
|
height: `${Math.min(100, size.h / ppu / H * 100)}%`
|
|
62627
62966
|
}
|