@weasel-js/routing 1.9.3 → 1.9.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +6 -5
- package/dist/{chunk-LOP2JTTA.js → chunk-Y5RURZBH.js} +235 -183
- package/dist/chunk-Y5RURZBH.js.map +1 -0
- package/dist/{index-CrbDNXT_.d.ts → index-gArM2tbt.d.ts} +363 -187
- package/dist/index.d.ts +3 -2
- package/dist/index.js +23 -20
- package/dist/index.js.map +1 -1
- package/dist/{internal-B1B6gfOS.d.ts → internal-B0SsznMG.d.ts} +9 -12
- package/dist/internal.d.ts +4 -3
- package/dist/react.d.ts +30 -73
- package/dist/react.js +410 -299
- package/dist/react.js.map +1 -1
- package/package.json +8 -7
- package/dist/chunk-LOP2JTTA.js.map +0 -1
package/README.md
CHANGED
|
@@ -21,11 +21,12 @@ scene graph, the renderer and the concrete dependency interfaces all live in
|
|
|
21
21
|
|
|
22
22
|
## The dependency schema
|
|
23
23
|
|
|
24
|
-
`DepSchema` is declared here
|
|
25
|
-
|
|
26
|
-
`
|
|
27
|
-
|
|
28
|
-
|
|
24
|
+
`DepSchema` is declared here with one entry, `activeTool`, the dep routing's own
|
|
25
|
+
`tool.offhand` action requires. Everything that names a dependency —
|
|
26
|
+
`Action.requires`, `DepRegistry.get`, `useDepSource` — is keyed on
|
|
27
|
+
`keyof DepSchema`, so the set of legal names is that entry plus whatever has
|
|
28
|
+
been merged in. `@weasel-js/core` merges the kit's own deps; a consumer adds its
|
|
29
|
+
own the same way:
|
|
29
30
|
|
|
30
31
|
```ts
|
|
31
32
|
declare module '@weasel-js/core' {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { RESERVED_ID_PREFIXES, RESERVED_ID_NAMES, parseTargetSpec, matchSpec, routeGestureForSpecKind, getGestureDescriptor, formatRoute, canonicalModifiers, specificity } from '@weasel-js/gestures';
|
|
1
|
+
import { RESERVED_ID_PREFIXES, RESERVED_ID_NAMES, parseTargetSpec, matchSpec, routeGestureForSpecKind, getGestureDescriptor, formatRoute, canonicalModifiers, VALID_MOD_NAMES, specificity } from '@weasel-js/gestures';
|
|
2
2
|
export { GESTURE_DESCRIPTORS, RESERVED_ID_NAMES, RESERVED_ID_PREFIXES, ROUTE_FIELD_DEFINITIONS, ROUTE_TERMS, canonicalModifiers, collapseShiftPairs, describeRoute, describeRouteParts, formatPhaseAtom, formatRoute, getGestureDescriptor, isKnownGestureName, matchKey, matchModifiers, matchPhase, matchSpec, matchTarget, parseRoute, routeGestureForSpecKind, specKindForRouteGesture, specificity } from '@weasel-js/gestures';
|
|
3
3
|
import { activeModeOf, NORMAL, DEFAULT_MODES } from '@weasel-js/modes';
|
|
4
4
|
import { resolveCursor } from '@weasel-js/cursor';
|
|
@@ -155,6 +155,7 @@ var DepNode = class extends ScopeNode {
|
|
|
155
155
|
const stack = this.sources.get(key);
|
|
156
156
|
if (stack) stack.push(entry);
|
|
157
157
|
else this.sources.set(key, [entry]);
|
|
158
|
+
this.changed();
|
|
158
159
|
let released = false;
|
|
159
160
|
return () => {
|
|
160
161
|
if (released) return;
|
|
@@ -165,6 +166,7 @@ var DepNode = class extends ScopeNode {
|
|
|
165
166
|
if (i === -1) return;
|
|
166
167
|
cur.splice(i, 1);
|
|
167
168
|
if (cur.length === 0) this.sources.delete(key);
|
|
169
|
+
this.changed();
|
|
168
170
|
};
|
|
169
171
|
},
|
|
170
172
|
get: (name) => {
|
|
@@ -173,7 +175,14 @@ var DepNode = class extends ScopeNode {
|
|
|
173
175
|
if (source) return source();
|
|
174
176
|
}
|
|
175
177
|
return void 0;
|
|
176
|
-
}
|
|
178
|
+
},
|
|
179
|
+
subscribe: (listener) => {
|
|
180
|
+
this.tree.listeners.add(listener);
|
|
181
|
+
return () => {
|
|
182
|
+
this.tree.listeners.delete(listener);
|
|
183
|
+
};
|
|
184
|
+
},
|
|
185
|
+
changed: () => this.changed()
|
|
177
186
|
};
|
|
178
187
|
constructor(parent, descends) {
|
|
179
188
|
super(parent, descends);
|
|
@@ -248,11 +257,15 @@ function offhandKeyFor(trigger) {
|
|
|
248
257
|
}
|
|
249
258
|
}
|
|
250
259
|
function buildToolOffhandBindings(specs) {
|
|
251
|
-
return specs.map(({ toolId, key }) => ({
|
|
252
|
-
spec: { kind: "key-held", key },
|
|
253
|
-
opts: { params: { toolId } }
|
|
254
|
-
}));
|
|
260
|
+
return specs.map(({ toolId, key }) => ({ spec: heldKeySpec(key), opts: { params: { toolId } } }));
|
|
255
261
|
}
|
|
262
|
+
function heldKeySpec(key) {
|
|
263
|
+
const isModifier = [key].flat().some((k) => MODIFIER_KEYS.has(k));
|
|
264
|
+
return { kind: "key-held", key, mods: { ...isModifier ? ANY_MODS : SHIFT_OR_ALT } };
|
|
265
|
+
}
|
|
266
|
+
var MODIFIER_KEYS = /* @__PURE__ */ new Set(["Alt", "Control", "Meta", "Shift"]);
|
|
267
|
+
var ANY_MODS = { alt: "optional", ctrl: "optional", meta: "optional", shift: "optional" };
|
|
268
|
+
var SHIFT_OR_ALT = { alt: "optional", shift: "optional" };
|
|
256
269
|
function makeToolOffhandAction(bindings) {
|
|
257
270
|
return {
|
|
258
271
|
id: TOOL_OFFHAND_ID,
|
|
@@ -299,6 +312,26 @@ function scopeBindings(entries, state) {
|
|
|
299
312
|
}
|
|
300
313
|
return out;
|
|
301
314
|
}
|
|
315
|
+
function assembleEntries(entries, inputs) {
|
|
316
|
+
const all = [...entries];
|
|
317
|
+
const ordered = [];
|
|
318
|
+
for (let i = inputs.hotkeyStack.length - 1; i >= 0; i--) {
|
|
319
|
+
const entry = all.find((e) => e.id === inputs.hotkeyStack[i]);
|
|
320
|
+
if (entry && !ordered.includes(entry)) ordered.push(entry);
|
|
321
|
+
}
|
|
322
|
+
for (const entry of all) {
|
|
323
|
+
if (!ordered.includes(entry)) ordered.push(entry);
|
|
324
|
+
}
|
|
325
|
+
const allowed = inputs.allowedCapabilities;
|
|
326
|
+
return {
|
|
327
|
+
ordered,
|
|
328
|
+
state: {
|
|
329
|
+
focusedId: inputs.focusedId,
|
|
330
|
+
engagedIds: new Set(inputs.hotkeyStack),
|
|
331
|
+
...allowed ? { allows: (tags) => tags.every((tag) => allowed.has(tag)) } : {}
|
|
332
|
+
}
|
|
333
|
+
};
|
|
334
|
+
}
|
|
302
335
|
|
|
303
336
|
// src/devFlag.ts
|
|
304
337
|
function isDev() {
|
|
@@ -313,7 +346,7 @@ function targetConsultsAffordance(specTarget) {
|
|
|
313
346
|
if (form === null) return false;
|
|
314
347
|
switch (form.form) {
|
|
315
348
|
case "predicate":
|
|
316
|
-
return form.kindOf.readsAffordance
|
|
349
|
+
return form.kindOf.readsAffordance === true;
|
|
317
350
|
case "affordance":
|
|
318
351
|
return true;
|
|
319
352
|
case "body":
|
|
@@ -739,9 +772,8 @@ function buildRuleCtx(args) {
|
|
|
739
772
|
device: args.device
|
|
740
773
|
};
|
|
741
774
|
}
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
}
|
|
775
|
+
|
|
776
|
+
// src/interactions/dispatcher/dispatchTrace.ts
|
|
745
777
|
var DEV2 = (() => {
|
|
746
778
|
try {
|
|
747
779
|
return Boolean(import.meta.env?.DEV);
|
|
@@ -770,6 +802,25 @@ function recordModeSwitch(mode, from, to, detail) {
|
|
|
770
802
|
...detail !== void 0 ? { detail } : {}
|
|
771
803
|
});
|
|
772
804
|
}
|
|
805
|
+
|
|
806
|
+
// src/interactions/dispatcher/inputFacts.ts
|
|
807
|
+
function modifiersOf(e) {
|
|
808
|
+
return { alt: e.altKey, ctrl: e.ctrlKey, meta: e.metaKey, shift: e.shiftKey };
|
|
809
|
+
}
|
|
810
|
+
function worldPointOf(event) {
|
|
811
|
+
switch (event.kind) {
|
|
812
|
+
case "pointerdown":
|
|
813
|
+
case "longpress":
|
|
814
|
+
case "click":
|
|
815
|
+
case "doubleclick":
|
|
816
|
+
case "contextmenu":
|
|
817
|
+
return event.x !== void 0 && event.y !== void 0 ? { x: event.x, y: event.y } : void 0;
|
|
818
|
+
default:
|
|
819
|
+
return void 0;
|
|
820
|
+
}
|
|
821
|
+
}
|
|
822
|
+
|
|
823
|
+
// src/interactions/dispatcher/ranking.ts
|
|
773
824
|
function liveInView(binding, view) {
|
|
774
825
|
const views = binding.opts?.views;
|
|
775
826
|
return views === void 0 || views.includes(view);
|
|
@@ -833,22 +884,76 @@ function sameSpecificity(a, b) {
|
|
|
833
884
|
const sb = specificity(b);
|
|
834
885
|
return sa.every((v, i) => v === sb[i]);
|
|
835
886
|
}
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
887
|
+
|
|
888
|
+
// src/interactions/dispatcher/buildDispatchRecord.ts
|
|
889
|
+
function buildDispatchRecord(r, walked, event, ctx, predicted, outcome) {
|
|
890
|
+
const view = ctx.viewId ?? null;
|
|
891
|
+
const candidates = /* @__PURE__ */ new Map();
|
|
892
|
+
const candidateOf = (m) => {
|
|
893
|
+
let c = candidates.get(m);
|
|
894
|
+
if (!c) {
|
|
895
|
+
const eligible = r.actionMap.get(m.binding.actionId)?.eligible;
|
|
896
|
+
c = {
|
|
897
|
+
actionId: m.binding.actionId,
|
|
898
|
+
routes: routesForSpec(m.binding.spec),
|
|
899
|
+
scope: m.scope,
|
|
900
|
+
ownerId: m.ownerId,
|
|
901
|
+
namesView: namesView(m.binding, view),
|
|
902
|
+
specificity: specificity(m.binding.spec),
|
|
903
|
+
...eligible !== void 0 ? { eligible: describeEligible(eligible) } : {}
|
|
904
|
+
};
|
|
905
|
+
candidates.set(m, c);
|
|
906
|
+
}
|
|
907
|
+
return c;
|
|
908
|
+
};
|
|
909
|
+
const dropped = [
|
|
910
|
+
...r.barred.map((m) => ({
|
|
911
|
+
candidate: candidateOf(m),
|
|
912
|
+
filter: "claim",
|
|
913
|
+
...r.claimOwner !== void 0 ? { owner: r.claimOwner } : {}
|
|
914
|
+
}))
|
|
915
|
+
];
|
|
916
|
+
for (const m of r.ordered) {
|
|
917
|
+
if (r.eligible(m)) continue;
|
|
918
|
+
const c = candidateOf(m);
|
|
919
|
+
dropped.push({ candidate: c, filter: "ineligible", rule: c.eligible ?? "" });
|
|
920
|
+
}
|
|
921
|
+
const gated = (m) => r.actionMap.get(m.binding.actionId)?.eligible !== void 0;
|
|
922
|
+
const ranked = walked.steps.map(({ match, step }, i) => {
|
|
923
|
+
const prev = walked.steps[i - 1]?.match;
|
|
924
|
+
return {
|
|
925
|
+
candidate: candidateOf(match),
|
|
926
|
+
placedBy: prev ? placedBy(prev, match, view, r.ruleCtx !== void 0 && gated(prev) && !gated(match)) : { step: "first" },
|
|
927
|
+
walk: step
|
|
928
|
+
};
|
|
929
|
+
});
|
|
930
|
+
const eventKey = event.kind === "key" || event.kind === "key-held" ? event.key : void 0;
|
|
931
|
+
const world = worldPointOf(event);
|
|
932
|
+
return {
|
|
933
|
+
kind: "dispatch",
|
|
934
|
+
ts: Date.now(),
|
|
935
|
+
input: {
|
|
936
|
+
eventKind: event.kind,
|
|
937
|
+
...eventKey !== void 0 ? { key: eventKey } : {},
|
|
938
|
+
modifiers: modifiersOf(event),
|
|
939
|
+
viewId: view,
|
|
940
|
+
...world !== void 0 ? { world } : {},
|
|
941
|
+
...r.ruleCtx !== void 0 ? { mode: r.ruleCtx.mode } : {}
|
|
942
|
+
},
|
|
943
|
+
matched: [...r.ordered, ...r.barred].map(candidateOf),
|
|
944
|
+
dropped,
|
|
945
|
+
ranked,
|
|
946
|
+
predicted,
|
|
947
|
+
fired: walked.winner?.action.id ?? null,
|
|
948
|
+
outcome
|
|
949
|
+
};
|
|
839
950
|
}
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
case "click":
|
|
845
|
-
case "doubleclick":
|
|
846
|
-
case "contextmenu":
|
|
847
|
-
return event.x !== void 0 && event.y !== void 0 ? { x: event.x, y: event.y } : void 0;
|
|
848
|
-
default:
|
|
849
|
-
return void 0;
|
|
850
|
-
}
|
|
951
|
+
|
|
952
|
+
// src/interactions/dispatcher/dispatcher.ts
|
|
953
|
+
function pointerGestureId(pointerId) {
|
|
954
|
+
return `pointer-${pointerId ?? "mouse"}`;
|
|
851
955
|
}
|
|
956
|
+
var EMPTY_ENGAGED2 = /* @__PURE__ */ new Set();
|
|
852
957
|
function createDispatcher(opts) {
|
|
853
958
|
const inFlightHandles = /* @__PURE__ */ new Map();
|
|
854
959
|
const inFlightOwners = /* @__PURE__ */ new Map();
|
|
@@ -949,7 +1054,7 @@ function createDispatcher(opts) {
|
|
|
949
1054
|
}
|
|
950
1055
|
function gestureIdFor(event) {
|
|
951
1056
|
if (event.kind === "key-held") {
|
|
952
|
-
return `key-held-${event.key}`;
|
|
1057
|
+
return `key-held-${event.code ?? event.key}`;
|
|
953
1058
|
}
|
|
954
1059
|
if (event.kind === "pointerdown" || event.kind === "pointermove" || event.kind === "pointerup" || event.kind === "pointercancel") {
|
|
955
1060
|
return pointerGestureId(event.pointerId);
|
|
@@ -960,23 +1065,14 @@ function createDispatcher(opts) {
|
|
|
960
1065
|
return `ongoing-${event.kind}`;
|
|
961
1066
|
}
|
|
962
1067
|
function assembleScopedBindings(ctx) {
|
|
963
|
-
const
|
|
964
|
-
|
|
965
|
-
const id = ctx.hotkeyStack[i];
|
|
966
|
-
const entry = ctx.entriesById.get(id);
|
|
967
|
-
if (entry && !ordered.includes(entry)) ordered.push(entry);
|
|
968
|
-
}
|
|
969
|
-
for (const entry of ctx.entriesById.values()) {
|
|
970
|
-
if (!ordered.includes(entry)) ordered.push(entry);
|
|
971
|
-
}
|
|
972
|
-
const capsCtx = ctx.getRuleCtx?.();
|
|
973
|
-
const allows = capsCtx ? (tags) => tags.every((tag) => capsCtx.allowedCapabilities.has(tag)) : void 0;
|
|
974
|
-
const view = ctx.viewId ?? null;
|
|
975
|
-
const result = scopeBindings(ordered, {
|
|
1068
|
+
const allowedCapabilities = ctx.getRuleCtx?.()?.allowedCapabilities;
|
|
1069
|
+
const { ordered, state } = assembleEntries(ctx.entriesById.values(), {
|
|
976
1070
|
focusedId: ctx.activeToolId,
|
|
977
|
-
|
|
978
|
-
...
|
|
979
|
-
})
|
|
1071
|
+
hotkeyStack: ctx.hotkeyStack,
|
|
1072
|
+
...allowedCapabilities ? { allowedCapabilities } : {}
|
|
1073
|
+
});
|
|
1074
|
+
const view = ctx.viewId ?? null;
|
|
1075
|
+
const result = scopeBindings(ordered, state).filter((sb) => liveInView(sb.binding, view));
|
|
980
1076
|
for (const action of ctx.actions.list()) {
|
|
981
1077
|
const targetScope = action.scope === "hotkey" ? "hotkey" : "ambient";
|
|
982
1078
|
for (const binding of actionBindings(action)) {
|
|
@@ -1001,20 +1097,31 @@ function createDispatcher(opts) {
|
|
|
1001
1097
|
}
|
|
1002
1098
|
return map;
|
|
1003
1099
|
}
|
|
1100
|
+
function runOnEnd(gestureId, handle, endCtx, reason) {
|
|
1101
|
+
try {
|
|
1102
|
+
handle.onEnd?.(endCtx, reason);
|
|
1103
|
+
} catch (err) {
|
|
1104
|
+
console.error(`weasel dispatcher: gesture "${gestureId}" threw on onEnd`, err);
|
|
1105
|
+
}
|
|
1106
|
+
}
|
|
1107
|
+
function endGesture(gestureId, event, reason) {
|
|
1108
|
+
const handle = inFlightHandles.get(gestureId);
|
|
1109
|
+
if (!handle) return false;
|
|
1110
|
+
const endCtx = buildInvocationCtx(event, {}, gestureId);
|
|
1111
|
+
inFlightHandles.delete(gestureId);
|
|
1112
|
+
inFlightOwners.delete(gestureId);
|
|
1113
|
+
inFlightActions.delete(gestureId);
|
|
1114
|
+
dragOrigins.delete(gestureId);
|
|
1115
|
+
dragPoints.delete(gestureId);
|
|
1116
|
+
pinchStartSpreads.delete(gestureId);
|
|
1117
|
+
runOnEnd(gestureId, handle, endCtx, reason);
|
|
1118
|
+
return true;
|
|
1119
|
+
}
|
|
1004
1120
|
function handleInput(event, ctx) {
|
|
1005
1121
|
routedView = ctx.viewId;
|
|
1006
1122
|
if (event.kind === "key-held" && event.phase === "up") {
|
|
1007
1123
|
const gestureId = gestureIdFor(event);
|
|
1008
|
-
|
|
1009
|
-
if (handle) {
|
|
1010
|
-
const stubCtx = buildInvocationCtx(event, {}, gestureId);
|
|
1011
|
-
handle.onEnd?.(stubCtx, "commit");
|
|
1012
|
-
inFlightHandles.delete(gestureId);
|
|
1013
|
-
inFlightOwners.delete(gestureId);
|
|
1014
|
-
inFlightActions.delete(gestureId);
|
|
1015
|
-
dragOrigins.delete(gestureId);
|
|
1016
|
-
}
|
|
1017
|
-
return handle ? "handled" : "unhandled";
|
|
1124
|
+
return endGesture(gestureId, event, "commit") ? "handled" : "unhandled";
|
|
1018
1125
|
}
|
|
1019
1126
|
if (event.kind === "key-held" && event.phase === "down") {
|
|
1020
1127
|
const gestureId = gestureIdFor(event);
|
|
@@ -1045,31 +1152,18 @@ function createDispatcher(opts) {
|
|
|
1045
1152
|
}
|
|
1046
1153
|
if (event.kind === "pointerup") {
|
|
1047
1154
|
const gestureId = gestureIdFor(event);
|
|
1048
|
-
|
|
1049
|
-
if (handle) {
|
|
1050
|
-
const endCtx = buildInvocationCtx(event, {}, gestureId);
|
|
1051
|
-
handle.onEnd?.(endCtx, "commit");
|
|
1052
|
-
inFlightHandles.delete(gestureId);
|
|
1053
|
-
inFlightOwners.delete(gestureId);
|
|
1054
|
-
inFlightActions.delete(gestureId);
|
|
1055
|
-
dragOrigins.delete(gestureId);
|
|
1056
|
-
dragPoints.delete(gestureId);
|
|
1057
|
-
}
|
|
1058
|
-
return handle ? "handled" : "unhandled";
|
|
1155
|
+
return endGesture(gestureId, event, "commit") ? "handled" : "unhandled";
|
|
1059
1156
|
}
|
|
1060
1157
|
if (event.kind === "pointercancel") {
|
|
1061
1158
|
const gestureId = gestureIdFor(event);
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
inFlightActions.delete(gestureId);
|
|
1069
|
-
dragOrigins.delete(gestureId);
|
|
1070
|
-
dragPoints.delete(gestureId);
|
|
1159
|
+
return endGesture(gestureId, event, "cancel") ? "handled" : "unhandled";
|
|
1160
|
+
}
|
|
1161
|
+
if (event.kind === "multitouch" && event.end !== void 0) {
|
|
1162
|
+
let ended = false;
|
|
1163
|
+
for (const id of [...inFlightHandles.keys()]) {
|
|
1164
|
+
if (id.startsWith("multitouch-")) ended = endGesture(id, event, event.end) || ended;
|
|
1071
1165
|
}
|
|
1072
|
-
return
|
|
1166
|
+
return ended ? "handled" : "unhandled";
|
|
1073
1167
|
}
|
|
1074
1168
|
if (event.kind === "multitouch" && event.centroid !== void 0) {
|
|
1075
1169
|
const gestureId = gestureIdFor(event);
|
|
@@ -1079,19 +1173,14 @@ function createDispatcher(opts) {
|
|
|
1079
1173
|
handle.onMove(moveCtx);
|
|
1080
1174
|
return "handled";
|
|
1081
1175
|
}
|
|
1082
|
-
for (const
|
|
1083
|
-
if (
|
|
1084
|
-
other.onEnd?.(buildInvocationCtx(event, {}, id), "cancel");
|
|
1085
|
-
inFlightHandles.delete(id);
|
|
1086
|
-
inFlightOwners.delete(id);
|
|
1087
|
-
inFlightActions.delete(id);
|
|
1088
|
-
pinchStartSpreads.delete(id);
|
|
1176
|
+
for (const id of [...inFlightHandles.keys()]) {
|
|
1177
|
+
if (id.startsWith("multitouch-") && id !== gestureId) endGesture(id, event, "cancel");
|
|
1089
1178
|
}
|
|
1090
1179
|
}
|
|
1091
1180
|
const r = rank(event, ctx, DEV2);
|
|
1092
1181
|
const walked = walk(r, event, ctx, (match, action, deps) => invoke(event, match, action, deps), false);
|
|
1093
1182
|
const outcome = walked.stop === "fired" ? "handled" : "unhandled";
|
|
1094
|
-
if (DEV2) recordTrace(
|
|
1183
|
+
if (DEV2) recordTrace(buildDispatchRecord(r, walked, event, ctx, false, outcome));
|
|
1095
1184
|
return outcome;
|
|
1096
1185
|
}
|
|
1097
1186
|
function invoke(event, match, action, deps) {
|
|
@@ -1296,68 +1385,6 @@ function createDispatcher(opts) {
|
|
|
1296
1385
|
}
|
|
1297
1386
|
return { steps, stop, winner };
|
|
1298
1387
|
}
|
|
1299
|
-
function buildRecord(r, walked, event, ctx, predicted, outcome) {
|
|
1300
|
-
const view = ctx.viewId ?? null;
|
|
1301
|
-
const candidates = /* @__PURE__ */ new Map();
|
|
1302
|
-
const candidateOf = (m) => {
|
|
1303
|
-
let c = candidates.get(m);
|
|
1304
|
-
if (!c) {
|
|
1305
|
-
const eligible = r.actionMap.get(m.binding.actionId)?.eligible;
|
|
1306
|
-
c = {
|
|
1307
|
-
actionId: m.binding.actionId,
|
|
1308
|
-
routes: routesForSpec(m.binding.spec),
|
|
1309
|
-
scope: m.scope,
|
|
1310
|
-
ownerId: m.ownerId,
|
|
1311
|
-
namesView: namesView(m.binding, view),
|
|
1312
|
-
specificity: specificity(m.binding.spec),
|
|
1313
|
-
...eligible !== void 0 ? { eligible: describeEligible(eligible) } : {}
|
|
1314
|
-
};
|
|
1315
|
-
candidates.set(m, c);
|
|
1316
|
-
}
|
|
1317
|
-
return c;
|
|
1318
|
-
};
|
|
1319
|
-
const dropped = [
|
|
1320
|
-
...r.barred.map((m) => ({
|
|
1321
|
-
candidate: candidateOf(m),
|
|
1322
|
-
filter: "claim",
|
|
1323
|
-
...r.claimOwner !== void 0 ? { owner: r.claimOwner } : {}
|
|
1324
|
-
}))
|
|
1325
|
-
];
|
|
1326
|
-
for (const m of r.ordered) {
|
|
1327
|
-
if (r.eligible(m)) continue;
|
|
1328
|
-
const c = candidateOf(m);
|
|
1329
|
-
dropped.push({ candidate: c, filter: "ineligible", rule: c.eligible ?? "" });
|
|
1330
|
-
}
|
|
1331
|
-
const gated = (m) => r.actionMap.get(m.binding.actionId)?.eligible !== void 0;
|
|
1332
|
-
const ranked = walked.steps.map(({ match, step }, i) => {
|
|
1333
|
-
const prev = walked.steps[i - 1]?.match;
|
|
1334
|
-
return {
|
|
1335
|
-
candidate: candidateOf(match),
|
|
1336
|
-
placedBy: prev ? placedBy(prev, match, view, r.ruleCtx !== void 0 && gated(prev) && !gated(match)) : { step: "first" },
|
|
1337
|
-
walk: step
|
|
1338
|
-
};
|
|
1339
|
-
});
|
|
1340
|
-
const eventKey = event.kind === "key" || event.kind === "key-held" ? event.key : void 0;
|
|
1341
|
-
const world = worldPointOf(event);
|
|
1342
|
-
return {
|
|
1343
|
-
kind: "dispatch",
|
|
1344
|
-
ts: Date.now(),
|
|
1345
|
-
input: {
|
|
1346
|
-
eventKind: event.kind,
|
|
1347
|
-
...eventKey !== void 0 ? { key: eventKey } : {},
|
|
1348
|
-
modifiers: modifiersOf(event),
|
|
1349
|
-
viewId: view,
|
|
1350
|
-
...world !== void 0 ? { world } : {},
|
|
1351
|
-
...r.ruleCtx !== void 0 ? { mode: r.ruleCtx.mode } : {}
|
|
1352
|
-
},
|
|
1353
|
-
matched: [...r.ordered, ...r.barred].map(candidateOf),
|
|
1354
|
-
dropped,
|
|
1355
|
-
ranked,
|
|
1356
|
-
predicted,
|
|
1357
|
-
fired: walked.winner?.action.id ?? null,
|
|
1358
|
-
outcome
|
|
1359
|
-
};
|
|
1360
|
-
}
|
|
1361
1388
|
function resolveAll(event, ctx, resolveOpts) {
|
|
1362
1389
|
const evaluateShadowed = resolveOpts?.evaluateShadowed ?? false;
|
|
1363
1390
|
const r = rank(event, ctx, false);
|
|
@@ -1416,7 +1443,7 @@ function createDispatcher(opts) {
|
|
|
1416
1443
|
function explain(event, ctx, explainOpts) {
|
|
1417
1444
|
const r = rank(event, ctx, true);
|
|
1418
1445
|
const walked = walk(r, event, ctx, null, explainOpts?.evaluateShadowed ?? false);
|
|
1419
|
-
return
|
|
1446
|
+
return buildDispatchRecord(r, walked, event, ctx, true, walked.winner ? "handled" : "unhandled");
|
|
1420
1447
|
}
|
|
1421
1448
|
function cancelAll(reason) {
|
|
1422
1449
|
const stubCtx = {
|
|
@@ -1424,9 +1451,7 @@ function createDispatcher(opts) {
|
|
|
1424
1451
|
modifiers: { alt: false, ctrl: false, meta: false, shift: false },
|
|
1425
1452
|
deps: {}
|
|
1426
1453
|
};
|
|
1427
|
-
|
|
1428
|
-
handle.onEnd?.(stubCtx, reason);
|
|
1429
|
-
}
|
|
1454
|
+
const ending = [...inFlightHandles];
|
|
1430
1455
|
inFlightHandles.clear();
|
|
1431
1456
|
inFlightOwners.clear();
|
|
1432
1457
|
inFlightActions.clear();
|
|
@@ -1434,6 +1459,7 @@ function createDispatcher(opts) {
|
|
|
1434
1459
|
dragOrigins.clear();
|
|
1435
1460
|
dragPoints.clear();
|
|
1436
1461
|
pinchStartSpreads.clear();
|
|
1462
|
+
for (const [gestureId, handle] of ending) runOnEnd(gestureId, handle, stubCtx, reason);
|
|
1437
1463
|
}
|
|
1438
1464
|
function inFlight() {
|
|
1439
1465
|
return inFlightHandles;
|
|
@@ -1441,8 +1467,8 @@ function createDispatcher(opts) {
|
|
|
1441
1467
|
function inFlightCursor() {
|
|
1442
1468
|
let cursor = null;
|
|
1443
1469
|
for (const action of inFlightActions.values()) {
|
|
1444
|
-
const
|
|
1445
|
-
if (
|
|
1470
|
+
const spec = action.activeCursor ?? action.cursor;
|
|
1471
|
+
if (spec !== void 0 && resolveCursor(spec)) cursor = spec;
|
|
1446
1472
|
}
|
|
1447
1473
|
return cursor;
|
|
1448
1474
|
}
|
|
@@ -1469,13 +1495,20 @@ function createDispatcher(opts) {
|
|
|
1469
1495
|
return { kind: lastHandle.kind ?? null, id: lastId };
|
|
1470
1496
|
}
|
|
1471
1497
|
const handleInputWithNotify = (event, ctx) => {
|
|
1472
|
-
const
|
|
1473
|
-
|
|
1474
|
-
|
|
1498
|
+
const before = inFlightHandles.size;
|
|
1499
|
+
try {
|
|
1500
|
+
return handleInput(event, ctx);
|
|
1501
|
+
} finally {
|
|
1502
|
+
if (before > 0 || inFlightHandles.size > 0) notify();
|
|
1503
|
+
}
|
|
1475
1504
|
};
|
|
1476
1505
|
const cancelAllWithNotify = (reason) => {
|
|
1477
|
-
|
|
1478
|
-
|
|
1506
|
+
const before = inFlightHandles.size;
|
|
1507
|
+
try {
|
|
1508
|
+
cancelAll(reason);
|
|
1509
|
+
} finally {
|
|
1510
|
+
if (before > 0) notify();
|
|
1511
|
+
}
|
|
1479
1512
|
};
|
|
1480
1513
|
function beginUiOngoing(actionId, deps, params) {
|
|
1481
1514
|
const getAction = opts?.getAction;
|
|
@@ -1520,6 +1553,9 @@ function createDispatcher(opts) {
|
|
|
1520
1553
|
const live = () => !ended && inFlightHandles.get(gestureId) === handle;
|
|
1521
1554
|
return {
|
|
1522
1555
|
gestureId,
|
|
1556
|
+
get active() {
|
|
1557
|
+
return live();
|
|
1558
|
+
},
|
|
1523
1559
|
update(nextParams) {
|
|
1524
1560
|
if (!live()) return;
|
|
1525
1561
|
if (!handle.onMove) return;
|
|
@@ -1688,33 +1724,45 @@ function findConflictsKeyed(entries, rules, modes = KIT_MODES) {
|
|
|
1688
1724
|
const groups = /* @__PURE__ */ new Map();
|
|
1689
1725
|
for (const entry of rows) {
|
|
1690
1726
|
for (const arg of argKeysOf(entry)) {
|
|
1691
|
-
const
|
|
1692
|
-
const
|
|
1693
|
-
|
|
1694
|
-
|
|
1695
|
-
|
|
1727
|
+
const base = `${entry.phase}|${entry.gesture}|${arg}|${targetKey(entry)}`;
|
|
1728
|
+
for (const state of modifierTieKeys(entry)) {
|
|
1729
|
+
const key = `${base}|${state}`;
|
|
1730
|
+
const bucket = groups.get(key);
|
|
1731
|
+
if (bucket) {
|
|
1732
|
+
if (!bucket.members.includes(entry)) bucket.members.push(entry);
|
|
1733
|
+
} else groups.set(key, { base, members: [entry] });
|
|
1734
|
+
}
|
|
1696
1735
|
}
|
|
1697
1736
|
}
|
|
1698
1737
|
const ruleOf = (entry) => rules?.get(entry.ownerId) ?? ALWAYS;
|
|
1699
1738
|
const tie = (e, f) => viewsTie(e.views, f.views) && rulesCanHoldTogether(ruleOf(e), ruleOf(f), modes);
|
|
1700
|
-
const conflicts =
|
|
1701
|
-
for (const
|
|
1702
|
-
const bucket =
|
|
1739
|
+
const conflicts = /* @__PURE__ */ new Map();
|
|
1740
|
+
for (const { base, members } of groups.values()) {
|
|
1741
|
+
const bucket = members.filter((e) => members.some((f) => f !== e && tie(e, f)));
|
|
1703
1742
|
if (bucket.length < 2) continue;
|
|
1704
1743
|
const first = bucket[0];
|
|
1705
|
-
|
|
1706
|
-
|
|
1707
|
-
|
|
1708
|
-
|
|
1709
|
-
|
|
1710
|
-
|
|
1711
|
-
|
|
1712
|
-
|
|
1713
|
-
|
|
1714
|
-
}
|
|
1744
|
+
const key = `${base}|${bucket.map((e) => `${objectId(e.spec)}:${canonicalModifiers(e.modifiers)}`).join(";")}`;
|
|
1745
|
+
if (conflicts.has(key)) continue;
|
|
1746
|
+
conflicts.set(key, {
|
|
1747
|
+
phase: first.phase,
|
|
1748
|
+
gesture: first.gesture,
|
|
1749
|
+
arg: first.arg,
|
|
1750
|
+
target: first.target,
|
|
1751
|
+
modifiers: first.modifiers,
|
|
1752
|
+
ownerIds: bucket.map((e) => e.ownerId)
|
|
1715
1753
|
});
|
|
1716
1754
|
}
|
|
1717
|
-
return conflicts;
|
|
1755
|
+
return [...conflicts].map(([key, conflict]) => ({ key, conflict }));
|
|
1756
|
+
}
|
|
1757
|
+
function modifierTieKeys(entry) {
|
|
1758
|
+
const optional = VALID_MOD_NAMES.filter((k) => entry.modifiers[k] === "optional");
|
|
1759
|
+
const required = VALID_MOD_NAMES.filter((k) => entry.modifiers[k] === "required");
|
|
1760
|
+
const keys = [];
|
|
1761
|
+
for (let bits = 0; bits < 1 << optional.length; bits++) {
|
|
1762
|
+
const held = [...required, ...optional.filter((_, i) => (bits & 1 << i) !== 0)].sort();
|
|
1763
|
+
keys.push(`${held.join("+")}:${required.length}`);
|
|
1764
|
+
}
|
|
1765
|
+
return keys;
|
|
1718
1766
|
}
|
|
1719
1767
|
function viewsTie(a, b) {
|
|
1720
1768
|
if (a === void 0 || b === void 0) return a === b;
|
|
@@ -1730,15 +1778,15 @@ function targetKey(entry) {
|
|
|
1730
1778
|
const spec = entry.spec;
|
|
1731
1779
|
const pred = spec.target;
|
|
1732
1780
|
if (typeof pred !== "object" || pred === null) return PREDICATE_TARGET;
|
|
1733
|
-
return `${PREDICATE_TARGET}#${
|
|
1781
|
+
return `${PREDICATE_TARGET}#${objectId(pred)}`;
|
|
1734
1782
|
}
|
|
1735
|
-
var
|
|
1736
|
-
var
|
|
1737
|
-
function
|
|
1738
|
-
let id =
|
|
1783
|
+
var OBJECT_IDS = /* @__PURE__ */ new WeakMap();
|
|
1784
|
+
var nextObjectId = 0;
|
|
1785
|
+
function objectId(obj) {
|
|
1786
|
+
let id = OBJECT_IDS.get(obj);
|
|
1739
1787
|
if (id === void 0) {
|
|
1740
|
-
id =
|
|
1741
|
-
|
|
1788
|
+
id = nextObjectId++;
|
|
1789
|
+
OBJECT_IDS.set(obj, id);
|
|
1742
1790
|
}
|
|
1743
1791
|
return id;
|
|
1744
1792
|
}
|
|
@@ -1788,7 +1836,7 @@ function findScopedConflicts(scopes) {
|
|
|
1788
1836
|
if (ambient.length > 1) add(findConflictsKeyed(ambient, rules, modes));
|
|
1789
1837
|
if (gatedActions.length > 1) add(findConflictsKeyed(gatedActions, rules, modes));
|
|
1790
1838
|
const hotkey = [
|
|
1791
|
-
...registry.filter((t) => t.def?.hotkey !== void 0),
|
|
1839
|
+
...registry.filter((t) => t.eligibility?.offhand !== void 0 || t.def?.hotkey !== void 0),
|
|
1792
1840
|
...hotkeyActions
|
|
1793
1841
|
];
|
|
1794
1842
|
if (hotkey.length > 1) add(findConflictsKeyed(hotkey, rules, modes));
|
|
@@ -1972,7 +2020,11 @@ function dlog(namespace, ...args) {
|
|
|
1972
2020
|
if (!isDebugEnabled(namespace)) return;
|
|
1973
2021
|
console.debug(`[${namespace}]`, ...args);
|
|
1974
2022
|
}
|
|
2023
|
+
function dwarn(namespace, ...args) {
|
|
2024
|
+
if (!isDebugEnabled(namespace)) return;
|
|
2025
|
+
console.warn(`[${namespace}]`, ...args);
|
|
2026
|
+
}
|
|
1975
2027
|
|
|
1976
|
-
export { ALWAYS, COARSE_TARGET_SCALE, DEFAULT_ALLOWED_CAPABILITIES, DEFAULT_DEVICE_PROFILE, DepNode, INGEST_STRING_MIMES, LONG_PRESS_MS, NEVER, PREDICATE_TARGET, ScopeNode, TOOL_OFFHAND_ID, actionBindings, activatesFocusedControl, buildDepsFromRequires, buildRouteRegistry, buildRuleCtx, buildToolOffhandBindings, clientToCanvas, clientToCanvasRect, createDepRegistry, createDispatcher, createLongPressStore, depNodeOf, describeRule, dlog, evaluate, findConflicts, historyKey, isDev, isEditableTarget, isTool, itemsFromClipboardData, itemsFromDataTransfer, itemsFromFiles, liveScope, makeToolOffhandAction, matchBest, matchSorted, matchSortedWithBarred, matchesKeyBinding, offhandKeyFor, openPointerSession, pointerGestureId, publishLiveDispatch, pushOwner, recordModeSwitch, reportRouteConflicts, resolveDeviceProfile, resolveParams, routesForSpec, ruleCanHoldIn, rulesExclusive, scopeBindings, targetConsultsAffordance, validateActionDefaultBinding, validateActionId };
|
|
1977
|
-
//# sourceMappingURL=chunk-
|
|
1978
|
-
//# sourceMappingURL=chunk-
|
|
2028
|
+
export { ALWAYS, COARSE_TARGET_SCALE, DEFAULT_ALLOWED_CAPABILITIES, DEFAULT_DEVICE_PROFILE, DepNode, INGEST_STRING_MIMES, LONG_PRESS_MS, NEVER, PREDICATE_TARGET, ScopeNode, TOOL_OFFHAND_ID, actionBindings, activatesFocusedControl, assembleEntries, buildDepsFromRequires, buildRouteRegistry, buildRuleCtx, buildToolOffhandBindings, clientToCanvas, clientToCanvasRect, createDepRegistry, createDispatcher, createLongPressStore, depNodeOf, describeRule, dlog, dwarn, evaluate, findConflicts, heldKeySpec, historyKey, isDebugEnabled, isDev, isEditableTarget, isTool, itemsFromClipboardData, itemsFromDataTransfer, itemsFromFiles, liveScope, makeToolOffhandAction, matchBest, matchSorted, matchSortedWithBarred, matchesKeyBinding, offhandKeyFor, openPointerSession, pointerGestureId, publishLiveDispatch, pushOwner, recordModeSwitch, reportRouteConflicts, resolveDeviceProfile, resolveParams, routesForSpec, ruleCanHoldIn, rulesExclusive, scopeBindings, targetConsultsAffordance, validateActionDefaultBinding, validateActionId };
|
|
2029
|
+
//# sourceMappingURL=chunk-Y5RURZBH.js.map
|
|
2030
|
+
//# sourceMappingURL=chunk-Y5RURZBH.js.map
|