@vibecook/ice 0.15.0-desk.5 → 0.15.0-desk.6
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/{chunk-OHEHS2EM.js → chunk-7XSZRL74.js} +2 -2
- package/dist/{chunk-HSIFKQNP.js → chunk-CAJ64OD6.js} +210 -35
- package/dist/chunk-CAJ64OD6.js.map +1 -0
- package/dist/{chunk-5QVYKU64.js → chunk-G3LDSWL4.js} +64 -7
- package/dist/chunk-G3LDSWL4.js.map +1 -0
- package/dist/{chunk-ZHASMOQV.js → chunk-WWFLFPSG.js} +43 -3
- package/dist/chunk-WWFLFPSG.js.map +1 -0
- package/dist/desk-kit.js +2 -2
- package/dist/desk-objects.js +3 -3
- package/dist/desk.js +3 -3
- package/dist/devtools.js +1 -1
- package/dist/dom.js +2 -2
- package/dist/index.js +11 -1
- package/dist/react.js +2 -2
- package/dist/types/packages/core/src/catalog/desk.d.ts +19 -1
- package/dist/types/packages/core/src/catalog/pointer.d.ts +7 -0
- package/dist/types/packages/core/src/catalog/selection-presence.d.ts +11 -1
- package/dist/types/packages/core/src/engine/frame-control.d.ts +14 -0
- package/dist/types/packages/core/src/facade/create-canvas-engine.d.ts +13 -0
- package/dist/types/packages/core/src/index.d.ts +2 -2
- package/dist/types/packages/core/src/input/queue.d.ts +5 -1
- package/dist/types/packages/core/src/ops/tray.d.ts +20 -1
- package/dist/types/packages/core/src/presence/index.d.ts +2 -2
- package/dist/types/packages/core/src/presence/presence-kit.d.ts +14 -0
- package/dist/types/packages/core/src/presence/publish.d.ts +7 -0
- package/dist/types/packages/core/src/presence/remote-cursors.d.ts +17 -2
- package/dist/types/packages/core/src/systems/tray.d.ts +3 -0
- package/dist/types/packages/desk/src/ground.d.ts +11 -3
- package/dist/types/packages/desk/src/host/layer.d.ts +49 -3
- package/dist/types/packages/desk/src/marks/layout.d.ts +8 -0
- package/dist/types/packages/desk/src/still.d.ts +13 -1
- package/dist/types/packages/dom/src/desk-host.d.ts +5 -0
- package/dist/types/packages/dom/src/pointer-adapter.d.ts +12 -2
- package/package.json +1 -1
- package/dist/chunk-5QVYKU64.js.map +0 -1
- package/dist/chunk-HSIFKQNP.js.map +0 -1
- package/dist/chunk-ZHASMOQV.js.map +0 -1
- /package/dist/{chunk-OHEHS2EM.js.map → chunk-7XSZRL74.js.map} +0 -0
|
@@ -12,7 +12,7 @@ import {
|
|
|
12
12
|
defineQuery,
|
|
13
13
|
field,
|
|
14
14
|
init
|
|
15
|
-
} from "./chunk-
|
|
15
|
+
} from "./chunk-CAJ64OD6.js";
|
|
16
16
|
|
|
17
17
|
// ../desk/src/lattice/lod.ts
|
|
18
18
|
var BASE_SPACING = 20;
|
|
@@ -2399,4 +2399,4 @@ export {
|
|
|
2399
2399
|
writeChanged,
|
|
2400
2400
|
lineWeight
|
|
2401
2401
|
};
|
|
2402
|
-
//# sourceMappingURL=chunk-
|
|
2402
|
+
//# sourceMappingURL=chunk-7XSZRL74.js.map
|
|
@@ -571,6 +571,9 @@ function createFrameControl(world) {
|
|
|
571
571
|
const listeners = /* @__PURE__ */ new Set();
|
|
572
572
|
let settleLeft = 0;
|
|
573
573
|
let parked = false;
|
|
574
|
+
const parkListeners = /* @__PURE__ */ new Set();
|
|
575
|
+
let heardParked = false;
|
|
576
|
+
let parkOwed = false;
|
|
574
577
|
const sources = /* @__PURE__ */ new Map();
|
|
575
578
|
const wakeListeners = /* @__PURE__ */ new Set();
|
|
576
579
|
const wakeCounts = {};
|
|
@@ -593,6 +596,41 @@ function createFrameControl(world) {
|
|
|
593
596
|
for (const r of reporters.values()) if (r.busy()) names.push(r.name);
|
|
594
597
|
return names;
|
|
595
598
|
};
|
|
599
|
+
const announcePark = (on) => {
|
|
600
|
+
if (heardParked === on) return;
|
|
601
|
+
heardParked = on;
|
|
602
|
+
for (const fn of [...parkListeners]) {
|
|
603
|
+
if (heardParked !== on) return;
|
|
604
|
+
try {
|
|
605
|
+
fn(on);
|
|
606
|
+
} catch (err) {
|
|
607
|
+
console.error("[ice] frame.onParked \u2014 a listener threw; the gate stands", err);
|
|
608
|
+
}
|
|
609
|
+
}
|
|
610
|
+
};
|
|
611
|
+
const claim = () => {
|
|
612
|
+
if (freezes.size === 0) return true;
|
|
613
|
+
if (!parked && settleLeft <= 0) {
|
|
614
|
+
parked = true;
|
|
615
|
+
if (devGuardsEnabled()) {
|
|
616
|
+
console.warn(
|
|
617
|
+
`ice: frame.freeze \u2014 settle cap (${SETTLE_CAP} frames) reached with reporters still busy: ${busyNames().join(", ")}. Parking on a possibly unsettled frame.`
|
|
618
|
+
);
|
|
619
|
+
}
|
|
620
|
+
}
|
|
621
|
+
if (parked) {
|
|
622
|
+
if (heardParked) return false;
|
|
623
|
+
parkOwed = false;
|
|
624
|
+
announcePark(true);
|
|
625
|
+
return parked ? false : claim();
|
|
626
|
+
}
|
|
627
|
+
settleLeft -= 1;
|
|
628
|
+
if (busyNames().length === 0) {
|
|
629
|
+
parked = true;
|
|
630
|
+
parkOwed = true;
|
|
631
|
+
}
|
|
632
|
+
return true;
|
|
633
|
+
};
|
|
596
634
|
return {
|
|
597
635
|
freeze(name) {
|
|
598
636
|
const token = Symbol(name);
|
|
@@ -609,12 +647,15 @@ function createFrameControl(world) {
|
|
|
609
647
|
if (released) return;
|
|
610
648
|
released = true;
|
|
611
649
|
freezes.delete(token);
|
|
612
|
-
|
|
650
|
+
const open = freezes.size === 0;
|
|
651
|
+
if (open) {
|
|
613
652
|
settleLeft = 0;
|
|
614
653
|
parked = false;
|
|
654
|
+
parkOwed = false;
|
|
615
655
|
}
|
|
616
656
|
sync();
|
|
617
657
|
announce();
|
|
658
|
+
if (open) announcePark(false);
|
|
618
659
|
};
|
|
619
660
|
},
|
|
620
661
|
isFrozen: () => freezes.size > 0,
|
|
@@ -631,28 +672,19 @@ function createFrameControl(world) {
|
|
|
631
672
|
};
|
|
632
673
|
},
|
|
633
674
|
settling: () => busyNames(),
|
|
634
|
-
claimStep
|
|
635
|
-
if (freezes.size === 0) return true;
|
|
636
|
-
if (parked) return false;
|
|
637
|
-
if (settleLeft <= 0) {
|
|
638
|
-
parked = true;
|
|
639
|
-
if (devGuardsEnabled()) {
|
|
640
|
-
console.warn(
|
|
641
|
-
`ice: frame.freeze \u2014 settle cap (${SETTLE_CAP} frames) reached with reporters still busy: ${busyNames().join(", ")}. Parking on a possibly unsettled frame.`
|
|
642
|
-
);
|
|
643
|
-
}
|
|
644
|
-
return false;
|
|
645
|
-
}
|
|
646
|
-
settleLeft -= 1;
|
|
647
|
-
if (busyNames().length === 0) parked = true;
|
|
648
|
-
return true;
|
|
649
|
-
},
|
|
675
|
+
claimStep: claim,
|
|
650
676
|
onChange(fn) {
|
|
651
677
|
listeners.add(fn);
|
|
652
678
|
return () => {
|
|
653
679
|
listeners.delete(fn);
|
|
654
680
|
};
|
|
655
681
|
},
|
|
682
|
+
onParked(fn) {
|
|
683
|
+
parkListeners.add(fn);
|
|
684
|
+
return () => {
|
|
685
|
+
parkListeners.delete(fn);
|
|
686
|
+
};
|
|
687
|
+
},
|
|
656
688
|
wake(reason) {
|
|
657
689
|
if (inStep) return;
|
|
658
690
|
wakeCounts[reason] = (wakeCounts[reason] ?? 0) + 1;
|
|
@@ -722,6 +754,10 @@ function createFrameControl(world) {
|
|
|
722
754
|
},
|
|
723
755
|
leaveStep() {
|
|
724
756
|
inStep = false;
|
|
757
|
+
if (parkOwed) {
|
|
758
|
+
parkOwed = false;
|
|
759
|
+
announcePark(true);
|
|
760
|
+
}
|
|
725
761
|
},
|
|
726
762
|
stepping: () => inStep,
|
|
727
763
|
sleepStats: () => ({ asleep, sleeps, wakes: { ...wakeCounts }, timed, steps })
|
|
@@ -1371,7 +1407,14 @@ var Tray = defineComponent("Tray", {
|
|
|
1371
1407
|
* `setTrayCategory` (the bar's chips, the desk handle's door) and `trayLay` — which lays only that category's entries, zeroes the
|
|
1372
1408
|
* scroll and the band when it moves, and falls back to all ("") when the frame hangs none of it.
|
|
1373
1409
|
*/
|
|
1374
|
-
category: field3("string", { default: "" })
|
|
1410
|
+
category: field3("string", { default: "" }),
|
|
1411
|
+
/**
|
|
1412
|
+
* Petition I37 — THE KEYBOARD FOCUS on the board: the type of the specimen it is on ("" — none), a fact of the view like `hover`.
|
|
1413
|
+
* Its writer is the op `focusTray` (next/prev/first/last along the lay's order, or a type by its id); `trayLay` scrolls the
|
|
1414
|
+
* specimen it moves to into the board's face, and lets it go when what it was on is laid no more (a category, a frame). The
|
|
1415
|
+
* renderer draws no ring for it: a host does, from the desk handle's `TrayAnchor.focused`.
|
|
1416
|
+
*/
|
|
1417
|
+
focus: field3("string", { default: "" })
|
|
1375
1418
|
});
|
|
1376
1419
|
var TrayIntent = defineResource(
|
|
1377
1420
|
"TrayIntent",
|
|
@@ -1394,7 +1437,8 @@ var TrayContent = defineComponent("TrayContent", {
|
|
|
1394
1437
|
width: field3("f64", { default: 0 }),
|
|
1395
1438
|
bottom: field3("f64", { default: 0 }),
|
|
1396
1439
|
laid: field3("u32", { default: 0 }),
|
|
1397
|
-
present: field3("string", { default: "[]" })
|
|
1440
|
+
present: field3("string", { default: "[]" }),
|
|
1441
|
+
order: field3("string", { default: "[]" })
|
|
1398
1442
|
});
|
|
1399
1443
|
var Specimen = defineTag("Specimen");
|
|
1400
1444
|
var TrayPress = defineComponent("TrayPress", {
|
|
@@ -1646,6 +1690,7 @@ var PointerPart = defineComponent("PointerPart", { part: field7("string", { defa
|
|
|
1646
1690
|
var PartTap = defineResource("PartTap", { seq: "u32", target: "eid", part: "string" });
|
|
1647
1691
|
var WheelHandled = defineTag("WheelHandled");
|
|
1648
1692
|
var OverInteractive = defineTag("OverInteractive");
|
|
1693
|
+
var PointerOutside = defineTag("PointerOutside");
|
|
1649
1694
|
var LocalPointer = defineTag("LocalPointer");
|
|
1650
1695
|
var PointerWorld = defineComponent("PointerWorld", {
|
|
1651
1696
|
x: field7("f64", { default: 0 }),
|
|
@@ -1691,7 +1736,9 @@ var PresenceInfo = defineComponent("PresenceInfo", { name: "string", color: "str
|
|
|
1691
1736
|
var PresenceCursor = defineComponent("PresenceCursor", {
|
|
1692
1737
|
x: field9("f64", { default: 0 }),
|
|
1693
1738
|
y: field9("f64", { default: 0 }),
|
|
1694
|
-
device: enumOf6(["mouse", "touch", "pen"])
|
|
1739
|
+
device: enumOf6(["mouse", "touch", "pen"]),
|
|
1740
|
+
away: field9("bool", { default: false }),
|
|
1741
|
+
canvas: field9("string", { default: "" })
|
|
1695
1742
|
});
|
|
1696
1743
|
var SelectionSummary = defineComponent("SelectionSummary", {
|
|
1697
1744
|
count: field9("u16", { default: 0 }),
|
|
@@ -8953,6 +9000,8 @@ function createTrayLay(world, opts) {
|
|
|
8953
9000
|
let rangeKey = "";
|
|
8954
9001
|
let laidTray;
|
|
8955
9002
|
let laidCategory = "";
|
|
9003
|
+
let focusedFor = "";
|
|
9004
|
+
let laidTypes = [];
|
|
8956
9005
|
const clampToRange = (ctx, tray, frame2, bottom) => {
|
|
8957
9006
|
if (frame2.face === void 0) return;
|
|
8958
9007
|
const range = trayScrollMax(bottom, frame2.face - (frame2.foot ?? 0), frame2.pitch);
|
|
@@ -8963,6 +9012,34 @@ function createTrayLay(world, opts) {
|
|
|
8963
9012
|
rangeKey = key;
|
|
8964
9013
|
if (t.scroll > range) ctx.edit(tray).set(Tray, { ...t, scroll: range });
|
|
8965
9014
|
};
|
|
9015
|
+
const focusInView = (ctx, tray, frame2, bottom) => {
|
|
9016
|
+
const t = ctx.read(tray, Tray);
|
|
9017
|
+
const focus = t.focus ?? "";
|
|
9018
|
+
if (focus !== "" && !laidTypes.includes(focus)) {
|
|
9019
|
+
focusedFor = "";
|
|
9020
|
+
ctx.edit(tray).set(Tray, { ...t, focus: "" });
|
|
9021
|
+
return;
|
|
9022
|
+
}
|
|
9023
|
+
if (focus === focusedFor) return;
|
|
9024
|
+
if (focus === "") {
|
|
9025
|
+
focusedFor = "";
|
|
9026
|
+
return;
|
|
9027
|
+
}
|
|
9028
|
+
const hung = specimensOf(world, tray).find((e) => world.get(e, PrefabId)?.id === focus);
|
|
9029
|
+
if (hung === void 0) return;
|
|
9030
|
+
const at = ctx.get(hung, Position);
|
|
9031
|
+
const size = ctx.get(hung, Size);
|
|
9032
|
+
if (at === void 0 || size === void 0) return;
|
|
9033
|
+
focusedFor = focus;
|
|
9034
|
+
if (frame2.face === void 0) return;
|
|
9035
|
+
const top = frame2.head ?? 0;
|
|
9036
|
+
const showing = frame2.face - (frame2.foot ?? 0) - top;
|
|
9037
|
+
let scroll = t.scroll;
|
|
9038
|
+
if (at.y < scroll + top || size.h > showing) scroll = at.y - top;
|
|
9039
|
+
else if (at.y + size.h > scroll + top + showing) scroll = at.y + size.h - top - showing;
|
|
9040
|
+
scroll = Math.min(Math.max(scroll, 0), trayScrollMax(bottom, frame2.face - (frame2.foot ?? 0), frame2.pitch));
|
|
9041
|
+
if (scroll !== t.scroll || t.stretch !== 0) ctx.edit(tray).set(Tray, { ...t, scroll, stretch: 0 });
|
|
9042
|
+
};
|
|
8966
9043
|
return defineTickSystem9(
|
|
8967
9044
|
(ctx) => {
|
|
8968
9045
|
const tray = world.firstOf(trayQ2);
|
|
@@ -8985,6 +9062,7 @@ function createTrayLay(world, opts) {
|
|
|
8985
9062
|
const key = `${tray}|${content?.laid ?? 0}|${frame2.w}|${frame2.pitch}|${types.map((q) => q.type).join(",")}|${category}`;
|
|
8986
9063
|
if (key === laidKey) {
|
|
8987
9064
|
clampToRange(ctx, tray, frame2, content?.bottom ?? 0);
|
|
9065
|
+
focusInView(ctx, tray, frame2, content?.bottom ?? 0);
|
|
8988
9066
|
return;
|
|
8989
9067
|
}
|
|
8990
9068
|
const shown = category === "" ? types : types.filter((q) => categoryOf(q) === category);
|
|
@@ -9014,13 +9092,15 @@ function createTrayLay(world, opts) {
|
|
|
9014
9092
|
ctx.setRelation(spawned, ChildOf, tray, "last");
|
|
9015
9093
|
}
|
|
9016
9094
|
for (const e of have.values()) ctx.destroy(e);
|
|
9017
|
-
const next2 = { width: frame2.w, bottom: layout.bottom, laid: (content?.laid ?? 0) + 1, present: JSON.stringify(presentOf(types)) };
|
|
9095
|
+
const next2 = { width: frame2.w, bottom: layout.bottom, laid: (content?.laid ?? 0) + 1, present: JSON.stringify(presentOf(types)), order: JSON.stringify(layout.placed.map((q) => q.type)) };
|
|
9018
9096
|
if (content === void 0) ctx.addComponent(tray, TrayContent, next2);
|
|
9019
9097
|
else ctx.edit(tray).set(TrayContent, next2);
|
|
9020
9098
|
laidKey = `${tray}|${next2.laid}|${frame2.w}|${frame2.pitch}|${types.map((q) => q.type).join(",")}|${category}`;
|
|
9021
9099
|
laidTray = tray;
|
|
9022
9100
|
laidCategory = category;
|
|
9101
|
+
laidTypes = layout.placed.map((q) => q.type);
|
|
9023
9102
|
clampToRange(ctx, tray, frame2, layout.bottom);
|
|
9103
|
+
focusInView(ctx, tray, frame2, layout.bottom);
|
|
9024
9104
|
},
|
|
9025
9105
|
// Petition I34: in derive, after `trayInput` (react) by the phase — the lay reads back what the input wrote this tick, so the two
|
|
9026
9106
|
// `Tray` writers are ORDERED, never attested. `Position`/`Size` it writes on the tray's specimens alone, rows disjoint from the
|
|
@@ -9051,7 +9131,7 @@ var write = (world, patch) => {
|
|
|
9051
9131
|
const e = ensureTray(world);
|
|
9052
9132
|
const cur = world.read(e, Tray);
|
|
9053
9133
|
const next2 = { ...cur, ...patch };
|
|
9054
|
-
if (next2.open !== cur.open || next2.scroll !== cur.scroll || next2.stretch !== cur.stretch || next2.hover !== cur.hover || next2.category !== cur.category) world.edit(e).set(Tray, next2);
|
|
9134
|
+
if (next2.open !== cur.open || next2.scroll !== cur.scroll || next2.stretch !== cur.stretch || next2.hover !== cur.hover || next2.category !== cur.category || next2.focus !== cur.focus) world.edit(e).set(Tray, next2);
|
|
9055
9135
|
};
|
|
9056
9136
|
function openTray(world) {
|
|
9057
9137
|
if (heldEntity(world) !== void 0) return false;
|
|
@@ -9072,6 +9152,31 @@ function toggleTray(world) {
|
|
|
9072
9152
|
function scrollTray(world, scroll) {
|
|
9073
9153
|
write(world, { scroll, stretch: 0 });
|
|
9074
9154
|
}
|
|
9155
|
+
function trayHung(world) {
|
|
9156
|
+
const e = world.firstOf(trayQ3);
|
|
9157
|
+
const raw = e === void 0 ? void 0 : world.get(e, TrayContent)?.order;
|
|
9158
|
+
if (raw === void 0 || raw === null || raw === "") return [];
|
|
9159
|
+
const list = JSON.parse(raw);
|
|
9160
|
+
return Array.isArray(list) ? list.filter((q) => typeof q === "string") : [];
|
|
9161
|
+
}
|
|
9162
|
+
function trayFocus(world) {
|
|
9163
|
+
const e = world.firstOf(trayQ3);
|
|
9164
|
+
return e === void 0 ? "" : world.get(e, Tray)?.focus ?? "";
|
|
9165
|
+
}
|
|
9166
|
+
function focusTray(world, to) {
|
|
9167
|
+
const order = trayHung(world);
|
|
9168
|
+
const cur = trayFocus(world);
|
|
9169
|
+
const i = order.indexOf(cur);
|
|
9170
|
+
const last = order.length - 1;
|
|
9171
|
+
let next2;
|
|
9172
|
+
if (to === "first") next2 = order[0] ?? "";
|
|
9173
|
+
else if (to === "last") next2 = order[last] ?? "";
|
|
9174
|
+
else if (to === "next") next2 = order[i < 0 ? 0 : Math.min(i + 1, last)] ?? "";
|
|
9175
|
+
else if (to === "prev") next2 = order[i < 0 ? last : Math.max(i - 1, 0)] ?? "";
|
|
9176
|
+
else next2 = order.includes(to) ? to : cur;
|
|
9177
|
+
write(world, { focus: next2 });
|
|
9178
|
+
return next2;
|
|
9179
|
+
}
|
|
9075
9180
|
function trayCategory(world) {
|
|
9076
9181
|
const e = world.firstOf(trayQ3);
|
|
9077
9182
|
return e === void 0 ? "" : world.get(e, Tray)?.category ?? "";
|
|
@@ -9339,6 +9444,7 @@ function createL0Systems(world, queue) {
|
|
|
9339
9444
|
wentCancelled: false,
|
|
9340
9445
|
handled: false,
|
|
9341
9446
|
overInteractive: void 0,
|
|
9447
|
+
outside: false,
|
|
9342
9448
|
mods: { shift: ev.mods.shift, ctrl: ev.mods.ctrl, alt: ev.mods.alt, meta: ev.mods.meta },
|
|
9343
9449
|
wheelDx: 0,
|
|
9344
9450
|
wheelDy: 0,
|
|
@@ -9368,6 +9474,7 @@ function createL0Systems(world, queue) {
|
|
|
9368
9474
|
s.hasWheel = true;
|
|
9369
9475
|
if (ev.wheelHandled === true) s.wheelHandled = true;
|
|
9370
9476
|
}
|
|
9477
|
+
s.outside = ev.kind === "leave";
|
|
9371
9478
|
if (ev.surfaceHandled === true) s.handled = true;
|
|
9372
9479
|
if (ev.overInteractive !== void 0) s.overInteractive = ev.overInteractive;
|
|
9373
9480
|
}
|
|
@@ -9393,6 +9500,7 @@ function createL0Systems(world, queue) {
|
|
|
9393
9500
|
if (s.handled) ctx.addTag(spawned, HandledByWidget);
|
|
9394
9501
|
if (s.wheelHandled) ctx.addTag(spawned, WheelHandled);
|
|
9395
9502
|
if (s.overInteractive === true) ctx.addTag(spawned, OverInteractive);
|
|
9503
|
+
if (s.outside) ctx.addTag(spawned, PointerOutside);
|
|
9396
9504
|
byId.set(id, spawned);
|
|
9397
9505
|
continue;
|
|
9398
9506
|
}
|
|
@@ -9422,6 +9530,10 @@ function createL0Systems(world, queue) {
|
|
|
9422
9530
|
if (s.overInteractive) ctx.addTag(existing, OverInteractive);
|
|
9423
9531
|
else ctx.removeTag(existing, OverInteractive);
|
|
9424
9532
|
}
|
|
9533
|
+
if (s.outside !== ctx.hasTag(existing, PointerOutside)) {
|
|
9534
|
+
if (s.outside) ctx.addTag(existing, PointerOutside);
|
|
9535
|
+
else ctx.removeTag(existing, PointerOutside);
|
|
9536
|
+
}
|
|
9425
9537
|
}
|
|
9426
9538
|
bumpVersion(world, PointerVersion);
|
|
9427
9539
|
},
|
|
@@ -14127,7 +14239,7 @@ function attachPresence(world, opts) {
|
|
|
14127
14239
|
const source = new LoroEphemeralSnapshot(loro);
|
|
14128
14240
|
const onRemote = opts.onRemote;
|
|
14129
14241
|
const stopRemote = onRemote === void 0 ? void 0 : loro.subscribe((ev) => {
|
|
14130
|
-
if (ev.by !== "local") onRemote();
|
|
14242
|
+
if (ev.by !== "local" && (ev.added.length > 0 || ev.updated.length > 0 || ev.removed.length > 0)) onRemote();
|
|
14131
14243
|
});
|
|
14132
14244
|
const outbound = /* @__PURE__ */ new Set();
|
|
14133
14245
|
const eph = createEphemeralStore(source, {
|
|
@@ -14150,6 +14262,8 @@ function attachPresence(world, opts) {
|
|
|
14150
14262
|
});
|
|
14151
14263
|
let localPeer = spawnLocalPeer();
|
|
14152
14264
|
let detached = false;
|
|
14265
|
+
let awayReason = null;
|
|
14266
|
+
const awayHeard = /* @__PURE__ */ new Set();
|
|
14153
14267
|
let healQueued = false;
|
|
14154
14268
|
const stopResetHeal = world.observe({
|
|
14155
14269
|
onReset: () => {
|
|
@@ -14184,6 +14298,19 @@ function attachPresence(world, opts) {
|
|
|
14184
14298
|
outbound.delete(fn);
|
|
14185
14299
|
};
|
|
14186
14300
|
},
|
|
14301
|
+
setAway(reason) {
|
|
14302
|
+
if (reason !== null && typeof reason !== "string") throw new Error(`ice: presence setAway \u2014 the reason is a string or null (got ${String(reason)})`);
|
|
14303
|
+
if (detached || reason === awayReason) return;
|
|
14304
|
+
awayReason = reason;
|
|
14305
|
+
for (const fn of [...awayHeard]) fn(reason);
|
|
14306
|
+
},
|
|
14307
|
+
away: () => awayReason,
|
|
14308
|
+
onAway(fn) {
|
|
14309
|
+
awayHeard.add(fn);
|
|
14310
|
+
return () => {
|
|
14311
|
+
awayHeard.delete(fn);
|
|
14312
|
+
};
|
|
14313
|
+
},
|
|
14187
14314
|
detach() {
|
|
14188
14315
|
if (detached) return;
|
|
14189
14316
|
detached = true;
|
|
@@ -14195,6 +14322,7 @@ function attachPresence(world, opts) {
|
|
|
14195
14322
|
}
|
|
14196
14323
|
attachment.detach();
|
|
14197
14324
|
outbound.clear();
|
|
14325
|
+
awayHeard.clear();
|
|
14198
14326
|
stopRemote?.();
|
|
14199
14327
|
loro.destroy();
|
|
14200
14328
|
}
|
|
@@ -14206,6 +14334,11 @@ import { defineQuery as defineQuery47 } from "@vibecook/strata-ecs";
|
|
|
14206
14334
|
var SELECTION_KEY_CAP = 32;
|
|
14207
14335
|
var COUNT_MAX = 65535;
|
|
14208
14336
|
var localMouseQ = defineQuery47([Pointer, LocalPointer, PointerWorld]);
|
|
14337
|
+
function presenceCanvasOf(world, peerId, keyOf) {
|
|
14338
|
+
const frame2 = currentNavFrame(world);
|
|
14339
|
+
if (frame2 === void 0 || frame2 === world.getResource(BoardRoot)?.root) return "";
|
|
14340
|
+
return keyOf?.(frame2) ?? `~${peerId}/${frame2}`;
|
|
14341
|
+
}
|
|
14209
14342
|
function createPresencePublish(world, session, opts = {}) {
|
|
14210
14343
|
const { eph } = session;
|
|
14211
14344
|
const keyOf = opts.keyOf;
|
|
@@ -14227,18 +14360,26 @@ function createPresencePublish(world, session, opts = {}) {
|
|
|
14227
14360
|
publishSelection(world);
|
|
14228
14361
|
};
|
|
14229
14362
|
function publishCursor(w) {
|
|
14230
|
-
let
|
|
14363
|
+
let mouse;
|
|
14231
14364
|
w.query(localMouseQ).each((b) => {
|
|
14232
14365
|
for (const r of b) {
|
|
14233
|
-
if (
|
|
14366
|
+
if (mouse !== void 0) break;
|
|
14234
14367
|
const e = b.entity(r);
|
|
14235
14368
|
if (w.read(e, Pointer).device !== "mouse") continue;
|
|
14236
14369
|
const pw = w.read(e, PointerWorld);
|
|
14237
|
-
|
|
14370
|
+
mouse = { x: pw.x, y: pw.y, outside: w.hasTag(e, PointerOutside) };
|
|
14238
14371
|
}
|
|
14239
14372
|
});
|
|
14240
|
-
|
|
14241
|
-
if (
|
|
14373
|
+
const at = mouse ?? (cursorPresent ? lastCursor : void 0);
|
|
14374
|
+
if (at === void 0) return;
|
|
14375
|
+
const cursor = {
|
|
14376
|
+
x: at.x,
|
|
14377
|
+
y: at.y,
|
|
14378
|
+
device: "mouse",
|
|
14379
|
+
away: mouse?.outside === true || session.away() !== null,
|
|
14380
|
+
canvas: presenceCanvasOf(w, session.peerId, keyOf)
|
|
14381
|
+
};
|
|
14382
|
+
if (cursorPresent && lastCursor !== void 0 && cursorEquals(lastCursor, cursor)) {
|
|
14242
14383
|
return;
|
|
14243
14384
|
}
|
|
14244
14385
|
if (cursorPresent) eph.edit(localPeer).set(PresenceCursor, cursor);
|
|
@@ -14293,6 +14434,9 @@ function createPresencePublish(world, session, opts = {}) {
|
|
|
14293
14434
|
lastSummary = summary;
|
|
14294
14435
|
}
|
|
14295
14436
|
}
|
|
14437
|
+
function cursorEquals(a, b) {
|
|
14438
|
+
return a.x === b.x && a.y === b.y && a.device === b.device && a.away === b.away && a.canvas === b.canvas;
|
|
14439
|
+
}
|
|
14296
14440
|
function summaryEquals(a, b) {
|
|
14297
14441
|
return a.count === b.count && a.x === b.x && a.y === b.y && a.w === b.w && a.h === b.h && a.keys === b.keys;
|
|
14298
14442
|
}
|
|
@@ -14301,16 +14445,18 @@ function summaryEquals(a, b) {
|
|
|
14301
14445
|
import { Not as Not8, defineQuery as defineQuery48, defineTickSystem as defineTickSystem17 } from "@vibecook/strata-ecs";
|
|
14302
14446
|
import { Local as Local2 } from "@vibecook/strata-ecs";
|
|
14303
14447
|
var remotePeerCursorsQ = defineQuery48([PresenceCursor, PresencePeer, Not8(Local2)]);
|
|
14304
|
-
function createRemoteCursorsRig(world) {
|
|
14448
|
+
function createRemoteCursorsRig(world, opts = {}) {
|
|
14305
14449
|
const pool = /* @__PURE__ */ new Map();
|
|
14306
14450
|
const system = defineTickSystem17(
|
|
14307
14451
|
(ctx) => {
|
|
14308
14452
|
const live = /* @__PURE__ */ new Set();
|
|
14453
|
+
const here = presenceCanvasOf(world, opts.peerId ?? "", opts.keyOf);
|
|
14309
14454
|
ctx.query(remotePeerCursorsQ).each((b) => {
|
|
14310
14455
|
for (const r of b) {
|
|
14311
14456
|
const peer = b.entity(r);
|
|
14312
|
-
live.add(peer);
|
|
14313
14457
|
const pc = ctx.read(peer, PresenceCursor);
|
|
14458
|
+
if (pc.away || (pc.canvas ?? "") !== here) continue;
|
|
14459
|
+
live.add(peer);
|
|
14314
14460
|
const entry = pool.get(peer);
|
|
14315
14461
|
if (entry === void 0) {
|
|
14316
14462
|
const cursor = ctx.spawn({
|
|
@@ -14358,14 +14504,23 @@ function createRemoteCursorsRig(world) {
|
|
|
14358
14504
|
}
|
|
14359
14505
|
};
|
|
14360
14506
|
}
|
|
14361
|
-
function createRemoteCursorsSystem(world) {
|
|
14362
|
-
return createRemoteCursorsRig(world).system;
|
|
14507
|
+
function createRemoteCursorsSystem(world, opts = {}) {
|
|
14508
|
+
return createRemoteCursorsRig(world, opts).system;
|
|
14363
14509
|
}
|
|
14364
14510
|
function installPresence(engine, session, opts = {}) {
|
|
14365
|
-
const
|
|
14366
|
-
const
|
|
14511
|
+
const publish = createPresencePublish(engine.world, session, opts);
|
|
14512
|
+
const removePublish = engine.onPublish(publish);
|
|
14513
|
+
let installed = true;
|
|
14514
|
+
const stopAway = session.onAway(() => {
|
|
14515
|
+
queueMicrotask(() => {
|
|
14516
|
+
if (installed && !engine.frame.stepping()) publish(engine.world);
|
|
14517
|
+
});
|
|
14518
|
+
});
|
|
14519
|
+
const rig = createRemoteCursorsRig(engine.world, { peerId: session.peerId, ...opts.keyOf !== void 0 ? { keyOf: opts.keyOf } : {} });
|
|
14367
14520
|
const removeSystem = engine.addSystems("present", rig.system);
|
|
14368
14521
|
return () => {
|
|
14522
|
+
installed = false;
|
|
14523
|
+
stopAway();
|
|
14369
14524
|
removePublish();
|
|
14370
14525
|
removeSystem();
|
|
14371
14526
|
rig.reap();
|
|
@@ -16260,6 +16415,21 @@ function createCanvasEngine(opts = {}) {
|
|
|
16260
16415
|
}
|
|
16261
16416
|
return spawned;
|
|
16262
16417
|
},
|
|
16418
|
+
layFromTray(type, at) {
|
|
16419
|
+
if (typeof at?.x !== "number" || typeof at.y !== "number" || !Number.isFinite(at.x) || !Number.isFinite(at.y)) {
|
|
16420
|
+
throw new Error(`ice: ops.layFromTray \u2014 the point is ${JSON.stringify(at) ?? String(at)}: { x, y }, a world point of the current frame, two finite numbers.`);
|
|
16421
|
+
}
|
|
16422
|
+
if (heldNow() !== void 0 || !trayHung(world).includes(type)) return void 0;
|
|
16423
|
+
const widget = catalog.widget(type);
|
|
16424
|
+
const entry = widget?.tray;
|
|
16425
|
+
if (widget === void 0 || entry === void 0) return void 0;
|
|
16426
|
+
const { w, h } = widget.defaultSize;
|
|
16427
|
+
const props = trayTakeProps(entry);
|
|
16428
|
+
const laid = ops.spawnWidget(type, { x: at.x - w / 2, y: at.y - h / 2, w, h, ...props !== void 0 ? { props } : {} });
|
|
16429
|
+
ops.setSelection([laid]);
|
|
16430
|
+
closeTray(world);
|
|
16431
|
+
return laid;
|
|
16432
|
+
},
|
|
16263
16433
|
insertByDrag(type, o) {
|
|
16264
16434
|
requireWritable("insertByDrag");
|
|
16265
16435
|
const targetFrame = requireCurrentFrame("insertByDrag");
|
|
@@ -16825,6 +16995,7 @@ export {
|
|
|
16825
16995
|
PartTap,
|
|
16826
16996
|
WheelHandled,
|
|
16827
16997
|
OverInteractive,
|
|
16998
|
+
PointerOutside,
|
|
16828
16999
|
LocalPointer,
|
|
16829
17000
|
PointerWorld,
|
|
16830
17001
|
Keyboard,
|
|
@@ -16987,6 +17158,9 @@ export {
|
|
|
16987
17158
|
closeTray,
|
|
16988
17159
|
toggleTray,
|
|
16989
17160
|
scrollTray,
|
|
17161
|
+
trayHung,
|
|
17162
|
+
trayFocus,
|
|
17163
|
+
focusTray,
|
|
16990
17164
|
trayCategory,
|
|
16991
17165
|
setTrayCategory,
|
|
16992
17166
|
trayCategories,
|
|
@@ -17036,6 +17210,7 @@ export {
|
|
|
17036
17210
|
attachBroadcastRelay,
|
|
17037
17211
|
DEFAULT_PRESENCE_TTL_MS,
|
|
17038
17212
|
attachPresence,
|
|
17213
|
+
presenceCanvasOf,
|
|
17039
17214
|
createPresencePublish,
|
|
17040
17215
|
createRemoteCursorsSystem,
|
|
17041
17216
|
installPresence,
|
|
@@ -17060,4 +17235,4 @@ export {
|
|
|
17060
17235
|
Local3 as Local,
|
|
17061
17236
|
DurableUndoStatus
|
|
17062
17237
|
};
|
|
17063
|
-
//# sourceMappingURL=chunk-
|
|
17238
|
+
//# sourceMappingURL=chunk-CAJ64OD6.js.map
|