@weasel-js/routing 1.11.0 → 1.12.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{chunk-QBQQIFPI.js → chunk-ARDHI47M.js} +526 -57
- package/dist/chunk-ARDHI47M.js.map +1 -0
- package/dist/{index-CmfVvwWD.d.ts → index-CyBCsdie.d.ts} +1620 -1224
- package/dist/index.d.ts +2 -2
- package/dist/index.js +231 -34
- package/dist/index.js.map +1 -1
- package/dist/{internal-21M1rTVo.d.ts → internal-DejHXi0a.d.ts} +9 -1
- package/dist/internal.d.ts +5 -5
- package/dist/react.d.ts +16 -8
- package/dist/react.js +224 -83
- package/dist/react.js.map +1 -1
- package/package.json +13 -13
- package/dist/chunk-QBQQIFPI.js.map +0 -1
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { isDev } from '@weasel-js/react';
|
|
2
2
|
import { createEmitter } from '@weasel-js/registry';
|
|
3
|
-
import { RESERVED_ID_PREFIXES, RESERVED_ID_NAMES, isApplePlatform, routeGestureForSpecKind, getGestureDescriptor, formatRoute, parseTargetSpec, matchSpec, canonicalModifiers, UNKNOWN_MIME, specificity, VALID_MOD_NAMES, stylusOf } from '@weasel-js/gestures';
|
|
3
|
+
import { RESERVED_ID_PREFIXES, RESERVED_ID_NAMES, isApplePlatform, bindingSpec, routeGestureForSpecKind, getGestureDescriptor, formatRoute, parseTargetSpec, matchSpec, canonicalModifiers, UNKNOWN_MIME, specificity, formatShortcut, VALID_MOD_NAMES, stylusOf } from '@weasel-js/gestures';
|
|
4
4
|
export { GESTURE_DESCRIPTORS, LONG_PRESS_MS, RESERVED_ID_NAMES, RESERVED_ID_PREFIXES, ROUTE_FIELD_DEFINITIONS, ROUTE_TERMS, activatesFocusedControl, canonicalModifiers, collapseShiftPairs, describeRoute, describeRouteParts, focusedControlOwnsKey, formatPhaseAtom, formatRoute, getGestureDescriptor, isEditableTarget, isKnownGestureName, matchKey, matchModifiers, matchPhase, matchSpec, matchTarget, parseRoute, routeGestureForSpecKind, specKindForRouteGesture, specificity } from '@weasel-js/gestures';
|
|
5
5
|
import { activeModeOf, NORMAL, DEFAULT_MODES, capabilitiesAllowed } from '@weasel-js/modes';
|
|
6
6
|
import { resolveCursor } from '@weasel-js/cursor';
|
|
7
|
-
import { prefIsShown, prefIsEnabled, isPrefLeaf, prefAliasTarget, prefLeafAt, prefAliasedLeaf, prefNumberAt, resolvePrefUnit, prefDisplayBounds, prefUnitAccepts } from '@weasel-js/prefs';
|
|
7
|
+
import { prefIsShown, prefIsEnabled, isPrefLeaf, prefAliasTarget, prefLeafAt, prefAliasedLeaf, prefNumberAt, resolvePrefUnit, prefDisplayBounds, prefUnitAccepts, prefValueAtPath } from '@weasel-js/prefs';
|
|
8
8
|
import { endlessAllows } from '@weasel-js/quantity';
|
|
9
9
|
|
|
10
10
|
// src/interactions/actions/actionItems.ts
|
|
@@ -34,6 +34,21 @@ function actionItemTitle(item) {
|
|
|
34
34
|
return `${item.action.label}: ${item.label}`;
|
|
35
35
|
}
|
|
36
36
|
|
|
37
|
+
// src/interactions/actions/actionSettings.ts
|
|
38
|
+
var EMPTY = { values: {} };
|
|
39
|
+
function readActionSettings(action, deps) {
|
|
40
|
+
const settings = action.settings;
|
|
41
|
+
if (!settings) return null;
|
|
42
|
+
try {
|
|
43
|
+
return settings.read(deps ?? {});
|
|
44
|
+
} catch {
|
|
45
|
+
return EMPTY;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
function actionSettingsParams(settings, path, value) {
|
|
49
|
+
return settings.params ? settings.params(path, value) : { [path]: value };
|
|
50
|
+
}
|
|
51
|
+
|
|
37
52
|
// src/interactions/actions/binding.ts
|
|
38
53
|
function actionBindings(action) {
|
|
39
54
|
const gs = action.defaultBinding;
|
|
@@ -270,13 +285,21 @@ var DepNode = class extends ScopeNode {
|
|
|
270
285
|
};
|
|
271
286
|
},
|
|
272
287
|
get: (name) => {
|
|
288
|
+
const stacks = [...this.start().chain()].map((n) => n.sources.get(name) ?? []);
|
|
289
|
+
return readFrom(stacks, 0, (stacks[0]?.length ?? 0) - 1);
|
|
290
|
+
},
|
|
291
|
+
subscribe: (listener) => this.tree.listeners.subscribe(listener),
|
|
292
|
+
list: () => {
|
|
293
|
+
const found = /* @__PURE__ */ new Map();
|
|
294
|
+
let depth = 0;
|
|
273
295
|
for (const n of this.start().chain()) {
|
|
274
|
-
const
|
|
275
|
-
|
|
296
|
+
for (const [name, stack] of n.sources) {
|
|
297
|
+
if (!found.has(name)) found.set(name, { name, depth, stacked: stack.length });
|
|
298
|
+
}
|
|
299
|
+
depth++;
|
|
276
300
|
}
|
|
277
|
-
return
|
|
301
|
+
return [...found.values()].sort((a, b) => a.name < b.name ? -1 : a.name > b.name ? 1 : 0);
|
|
278
302
|
},
|
|
279
|
-
subscribe: (listener) => this.tree.listeners.subscribe(listener),
|
|
280
303
|
changed: () => this.changed()
|
|
281
304
|
};
|
|
282
305
|
constructor(parent, descends) {
|
|
@@ -284,6 +307,11 @@ var DepNode = class extends ScopeNode {
|
|
|
284
307
|
NODES.set(this.registry, this);
|
|
285
308
|
}
|
|
286
309
|
};
|
|
310
|
+
function readFrom(stacks, scope, index) {
|
|
311
|
+
if (scope >= stacks.length) return void 0;
|
|
312
|
+
if (index < 0) return readFrom(stacks, scope + 1, (stacks[scope + 1]?.length ?? 0) - 1);
|
|
313
|
+
return stacks[scope][index](() => readFrom(stacks, scope, index - 1));
|
|
314
|
+
}
|
|
287
315
|
var NODES = /* @__PURE__ */ new WeakMap();
|
|
288
316
|
function depNodeOf(registry) {
|
|
289
317
|
return registry ? NODES.get(registry) ?? null : null;
|
|
@@ -438,6 +466,49 @@ function tuneAction(action, tunings) {
|
|
|
438
466
|
for (const t of tunings) out = tuneOnce(out, t);
|
|
439
467
|
return out;
|
|
440
468
|
}
|
|
469
|
+
var NO_OVERRIDES = /* @__PURE__ */ new Map();
|
|
470
|
+
function bindingId(b, ownerId, index) {
|
|
471
|
+
return b.opts?.id ?? (ownerId === null ? `${b.actionId}@${index}` : `${ownerId}#${index}`);
|
|
472
|
+
}
|
|
473
|
+
function resolveBindingOverrides(maps) {
|
|
474
|
+
if (maps.length === 0) return NO_OVERRIDES;
|
|
475
|
+
const out = /* @__PURE__ */ new Map();
|
|
476
|
+
for (const map of maps) {
|
|
477
|
+
for (const [id, input] of Object.entries(map)) {
|
|
478
|
+
try {
|
|
479
|
+
out.set(id, bindingSpec(input));
|
|
480
|
+
} catch (err) {
|
|
481
|
+
console.warn(`weasel: binding override "${id}" is not a route: ${err.message}`);
|
|
482
|
+
}
|
|
483
|
+
}
|
|
484
|
+
}
|
|
485
|
+
return out;
|
|
486
|
+
}
|
|
487
|
+
function overridden(b, id, overrides) {
|
|
488
|
+
if (!overrides.has(id)) return b;
|
|
489
|
+
const spec = overrides.get(id);
|
|
490
|
+
return spec === null ? null : { ...b, spec };
|
|
491
|
+
}
|
|
492
|
+
function overriddenBindings(bindings, ownerId, overrides = NO_OVERRIDES) {
|
|
493
|
+
const out = [];
|
|
494
|
+
bindings.forEach((b, i) => {
|
|
495
|
+
const next = overridden(b, bindingId(b, ownerId, i), overrides);
|
|
496
|
+
if (next) out.push(next);
|
|
497
|
+
});
|
|
498
|
+
return out;
|
|
499
|
+
}
|
|
500
|
+
function overrideActionBindings(action, overrides) {
|
|
501
|
+
if (overrides.size === 0 || action.defaultBinding === void 0) return action;
|
|
502
|
+
const declared = actionBindings(action);
|
|
503
|
+
if (!declared.some((b, i) => overrides.has(bindingId(b, null, i)))) return action;
|
|
504
|
+
const kept = [];
|
|
505
|
+
declared.forEach((b, i) => {
|
|
506
|
+
const id = bindingId(b, null, i);
|
|
507
|
+
const next = overridden(b, id, overrides);
|
|
508
|
+
if (next) kept.push({ spec: next.spec, opts: { ...next.opts, id } });
|
|
509
|
+
});
|
|
510
|
+
return { ...action, defaultBinding: kept };
|
|
511
|
+
}
|
|
441
512
|
|
|
442
513
|
// src/interactions/actions/toolOffhand.ts
|
|
443
514
|
var TOOL_OFFHAND_ID = "tool.offhand";
|
|
@@ -460,7 +531,7 @@ function offhandKeyFor(trigger) {
|
|
|
460
531
|
function buildToolOffhandBindings(specs) {
|
|
461
532
|
return specs.map(({ toolId, key }) => ({
|
|
462
533
|
spec: { ...heldKeySpec(key), phase: BETWEEN_GESTURES },
|
|
463
|
-
opts: { params: { toolId } }
|
|
534
|
+
opts: { id: `${TOOL_OFFHAND_ID}.${toolId}`, params: { toolId } }
|
|
464
535
|
}));
|
|
465
536
|
}
|
|
466
537
|
var BETWEEN_GESTURES = [{ channel: "*", phase: "initial" }];
|
|
@@ -520,7 +591,8 @@ function routesForSpec(spec) {
|
|
|
520
591
|
const phases = phaseAtomsForSpec("phase" in spec ? spec.phase : void 0);
|
|
521
592
|
const target = descriptor.hasTarget ? routeTargetForSpec("target" in spec ? spec.target : void 0) ?? "*" : void 0;
|
|
522
593
|
const args = descriptor.arg ? routeArgsForSpec(spec, descriptor.arg.default) : [void 0];
|
|
523
|
-
|
|
594
|
+
const held = spec.kind === "hover" && spec.held !== void 0 ? { held: spec.held === true ? "required" : "optional" } : {};
|
|
595
|
+
return args.map((arg) => formatRoute({ phases, gesture, arg, target, modifiers, ...held }));
|
|
524
596
|
}
|
|
525
597
|
function entryFor(ownerId, spec, actionId) {
|
|
526
598
|
const gesture = routeGestureForSpecKind(spec.kind);
|
|
@@ -671,11 +743,11 @@ function matchSortedWithBarred(e, bindings, isMac, engagedChannels, opts = {}) {
|
|
|
671
743
|
const scopeBarred = [];
|
|
672
744
|
for (const sb of bindings) {
|
|
673
745
|
if (sb.scope !== scope) continue;
|
|
674
|
-
const
|
|
675
|
-
if (!
|
|
746
|
+
const admitted2 = admits(sb);
|
|
747
|
+
if (!admitted2 && !opts.collectBarred) continue;
|
|
676
748
|
const phaseCtx = { selfChannel: sb.ownerId, engagedChannels: engaged };
|
|
677
749
|
if (matchSpec(e, sb.binding.spec, isMac, phaseCtx)) {
|
|
678
|
-
(
|
|
750
|
+
(admitted2 ? scopeMatches : scopeBarred).push({ binding: sb.binding, scope, ownerId: sb.ownerId });
|
|
679
751
|
}
|
|
680
752
|
}
|
|
681
753
|
scopeMatches.sort((a, b) => compareSpecificity(a.binding.spec, b.binding.spec));
|
|
@@ -933,33 +1005,14 @@ function buildRuleCtx(args) {
|
|
|
933
1005
|
device: args.device
|
|
934
1006
|
};
|
|
935
1007
|
}
|
|
936
|
-
var DEV2 = isDev();
|
|
937
|
-
var TRACE_LIMIT = 200;
|
|
938
|
-
var traceLog = DEV2 && typeof window !== "undefined" ? window.__weaselDispatchLog__ ??= [] : [];
|
|
939
|
-
function recordTrace(entry) {
|
|
940
|
-
if (!DEV2) return;
|
|
941
|
-
traceLog.push(entry);
|
|
942
|
-
if (traceLog.length > TRACE_LIMIT) traceLog.shift();
|
|
943
|
-
}
|
|
944
|
-
function publishLiveDispatch(explain2) {
|
|
945
|
-
if (!DEV2 || typeof window === "undefined") return;
|
|
946
|
-
window.__weaselDispatchLive__ = explain2;
|
|
947
|
-
}
|
|
948
|
-
function recordModeSwitch(mode, from, to, detail) {
|
|
949
|
-
recordTrace({
|
|
950
|
-
kind: "mode",
|
|
951
|
-
ts: Date.now(),
|
|
952
|
-
mode,
|
|
953
|
-
from,
|
|
954
|
-
to,
|
|
955
|
-
...detail !== void 0 ? { detail } : {}
|
|
956
|
-
});
|
|
957
|
-
}
|
|
958
1008
|
|
|
959
1009
|
// src/interactions/dispatcher/gestureIds.ts
|
|
960
1010
|
function pointerGestureId(pointerId) {
|
|
961
1011
|
return `pointer-${pointerId ?? "mouse"}`;
|
|
962
1012
|
}
|
|
1013
|
+
function carryGestureId(pointerId) {
|
|
1014
|
+
return `carry-${pointerId ?? "mouse"}`;
|
|
1015
|
+
}
|
|
963
1016
|
function multiTouchGestureId(fingers) {
|
|
964
1017
|
return `multitouch-${fingers}`;
|
|
965
1018
|
}
|
|
@@ -977,7 +1030,7 @@ function gestureIdFor(event) {
|
|
|
977
1030
|
return multiTouchGestureId(event.fingers);
|
|
978
1031
|
}
|
|
979
1032
|
if (event.kind === "carry") {
|
|
980
|
-
return
|
|
1033
|
+
return carryGestureId(event.pointerId);
|
|
981
1034
|
}
|
|
982
1035
|
return `ongoing-${event.kind}`;
|
|
983
1036
|
}
|
|
@@ -986,17 +1039,18 @@ function gestureIdFor(event) {
|
|
|
986
1039
|
function liveScope(id, eligibility, state) {
|
|
987
1040
|
const tags = eligibility.capabilities;
|
|
988
1041
|
if (tags && state.allows && !state.allows(tags)) return null;
|
|
1042
|
+
if (eligibility.keymap) return state.openKeymap === id ? "hotkey" : null;
|
|
989
1043
|
if (state.engagedIds?.has(id)) return "hotkey";
|
|
990
1044
|
if (eligibility.focus && state.focusedId === id) return "active";
|
|
991
1045
|
if (eligibility.always || eligibility.claimed) return "ambient";
|
|
992
1046
|
return null;
|
|
993
1047
|
}
|
|
994
|
-
function scopeBindings(entries, state) {
|
|
1048
|
+
function scopeBindings(entries, state, overrides = NO_OVERRIDES) {
|
|
995
1049
|
const out = [];
|
|
996
1050
|
for (const entry of entries) {
|
|
997
1051
|
const scope = liveScope(entry.id, entry.eligibility ?? {}, state);
|
|
998
1052
|
if (scope === null) continue;
|
|
999
|
-
for (const binding of entry.bindings ?? []) {
|
|
1053
|
+
for (const binding of overriddenBindings(entry.bindings ?? [], entry.id, overrides)) {
|
|
1000
1054
|
out.push({ binding, scope, ownerId: entry.id });
|
|
1001
1055
|
}
|
|
1002
1056
|
}
|
|
@@ -1018,10 +1072,56 @@ function assembleEntries(entries, inputs) {
|
|
|
1018
1072
|
state: {
|
|
1019
1073
|
focusedId: inputs.focusedId,
|
|
1020
1074
|
engagedIds: new Set(inputs.hotkeyStack),
|
|
1075
|
+
...inputs.openKeymap ? { openKeymap: inputs.openKeymap } : {},
|
|
1021
1076
|
...allowed ? { allows: (tags) => capabilitiesAllowed(allowed, tags) } : {}
|
|
1022
1077
|
}
|
|
1023
1078
|
};
|
|
1024
1079
|
}
|
|
1080
|
+
function createTraceRing(limit = 200, dev = isDev()) {
|
|
1081
|
+
const entries = [];
|
|
1082
|
+
const pushed = createEmitter();
|
|
1083
|
+
let total = 0;
|
|
1084
|
+
let watchers = 0;
|
|
1085
|
+
const recording = () => dev || watchers > 0;
|
|
1086
|
+
return {
|
|
1087
|
+
recording,
|
|
1088
|
+
push(entry) {
|
|
1089
|
+
if (!recording()) return;
|
|
1090
|
+
entries.push(entry);
|
|
1091
|
+
if (entries.length > limit) entries.shift();
|
|
1092
|
+
total++;
|
|
1093
|
+
pushed.emit();
|
|
1094
|
+
},
|
|
1095
|
+
since(cursor) {
|
|
1096
|
+
const first = total - entries.length;
|
|
1097
|
+
return { entries: entries.slice(Math.max(cursor, first) - first), cursor: total };
|
|
1098
|
+
},
|
|
1099
|
+
watch() {
|
|
1100
|
+
watchers++;
|
|
1101
|
+
let released = false;
|
|
1102
|
+
return () => {
|
|
1103
|
+
if (released) return;
|
|
1104
|
+
released = true;
|
|
1105
|
+
watchers--;
|
|
1106
|
+
};
|
|
1107
|
+
},
|
|
1108
|
+
subscribe: pushed.subscribe
|
|
1109
|
+
};
|
|
1110
|
+
}
|
|
1111
|
+
function createDispatchTrace(limit, dev) {
|
|
1112
|
+
const ring = createTraceRing(limit, dev);
|
|
1113
|
+
let explain2 = null;
|
|
1114
|
+
return {
|
|
1115
|
+
...ring,
|
|
1116
|
+
recordModeSwitch(mode, from, to, detail) {
|
|
1117
|
+
ring.push({ kind: "mode", ts: Date.now(), mode, from, to, ...detail !== void 0 ? { detail } : {} });
|
|
1118
|
+
},
|
|
1119
|
+
setLive(next) {
|
|
1120
|
+
explain2 = next;
|
|
1121
|
+
},
|
|
1122
|
+
live: () => explain2?.() ?? null
|
|
1123
|
+
};
|
|
1124
|
+
}
|
|
1025
1125
|
|
|
1026
1126
|
// src/interactions/dispatcher/inputFacts.ts
|
|
1027
1127
|
function modifiersOf(e) {
|
|
@@ -1043,6 +1143,7 @@ function worldPointOf(event) {
|
|
|
1043
1143
|
}
|
|
1044
1144
|
}
|
|
1045
1145
|
function carriedBy(event) {
|
|
1146
|
+
if (event.kind === "carry") return { items: [], carry: { type: event.type, value: event.value } };
|
|
1046
1147
|
return event.kind === "drop" || event.kind === "paste" ? { items: event.items } : void 0;
|
|
1047
1148
|
}
|
|
1048
1149
|
function immediateParams(event, resolved) {
|
|
@@ -1109,6 +1210,7 @@ function immediateParams(event, resolved) {
|
|
|
1109
1210
|
affordance: event.affordance,
|
|
1110
1211
|
bodyTarget: event.bodyTarget,
|
|
1111
1212
|
mods: modifiersOf(event),
|
|
1213
|
+
held: event.held === true,
|
|
1112
1214
|
...resolved
|
|
1113
1215
|
};
|
|
1114
1216
|
case "carry":
|
|
@@ -1118,6 +1220,9 @@ function immediateParams(event, resolved) {
|
|
|
1118
1220
|
clientX: event.clientX,
|
|
1119
1221
|
clientY: event.clientY,
|
|
1120
1222
|
carry: { type: event.type, value: event.value },
|
|
1223
|
+
affordance: event.affordance,
|
|
1224
|
+
bodyTarget: event.bodyTarget,
|
|
1225
|
+
bodyKind: event.bodyKind,
|
|
1121
1226
|
mods: modifiersOf(event),
|
|
1122
1227
|
...resolved
|
|
1123
1228
|
};
|
|
@@ -1139,6 +1244,10 @@ function liveInView(binding, view) {
|
|
|
1139
1244
|
const views = binding.opts?.views;
|
|
1140
1245
|
return views === void 0 || views.includes(view);
|
|
1141
1246
|
}
|
|
1247
|
+
function liveForKeys(binding, reach) {
|
|
1248
|
+
if (reach === void 0) return true;
|
|
1249
|
+
return binding.opts?.over ? reach.over : reach.held;
|
|
1250
|
+
}
|
|
1142
1251
|
function namesView(binding, view) {
|
|
1143
1252
|
return binding.opts?.views?.includes(view) ?? false;
|
|
1144
1253
|
}
|
|
@@ -1557,7 +1666,7 @@ function pumpCarry(run, event) {
|
|
|
1557
1666
|
if (event.stage === "enter") return void 0;
|
|
1558
1667
|
const gestureId = gestureIdFor(event);
|
|
1559
1668
|
const handle = run.inFlight.handles.get(gestureId);
|
|
1560
|
-
if (!handle) return event.stage === "
|
|
1669
|
+
if (!handle) return event.stage === "leave" ? "unhandled" : void 0;
|
|
1561
1670
|
if (event.stage === "move") {
|
|
1562
1671
|
handle.onMove?.(ctxFor(run, event, {}, gestureId));
|
|
1563
1672
|
return "handled";
|
|
@@ -1566,7 +1675,7 @@ function pumpCarry(run, event) {
|
|
|
1566
1675
|
}
|
|
1567
1676
|
function carryStageFits(event, timing) {
|
|
1568
1677
|
if (event.kind !== "carry") return true;
|
|
1569
|
-
return
|
|
1678
|
+
return timing === "immediate" ? event.stage === "drop" : event.stage === "enter" || event.stage === "move";
|
|
1570
1679
|
}
|
|
1571
1680
|
function invokeAction(run, event, match, action, deps) {
|
|
1572
1681
|
if (action.invoker && !carryStageFits(event, action.invoker.timing)) return "empty-handle";
|
|
@@ -1690,22 +1799,29 @@ function createUiOngoing(inFlight, notify, getAction) {
|
|
|
1690
1799
|
// src/interactions/dispatcher/walk.ts
|
|
1691
1800
|
function assembleScopedBindings(ctx) {
|
|
1692
1801
|
const allowedCapabilities = ctx.getRuleCtx?.()?.allowedCapabilities;
|
|
1802
|
+
const openKeymap = ctx.keymapPass === "none" ? null : ctx.keymaps?.innermost()?.id ?? null;
|
|
1693
1803
|
const { ordered, state } = assembleEntries(ctx.entriesById.values(), {
|
|
1694
1804
|
focusedId: ctx.activeToolId,
|
|
1695
1805
|
hotkeyStack: ctx.hotkeyStack,
|
|
1696
|
-
...allowedCapabilities ? { allowedCapabilities } : {}
|
|
1806
|
+
...allowedCapabilities ? { allowedCapabilities } : {},
|
|
1807
|
+
...openKeymap ? { openKeymap } : {}
|
|
1697
1808
|
});
|
|
1698
1809
|
const view = ctx.viewId ?? null;
|
|
1699
|
-
const
|
|
1810
|
+
const live = (b) => liveInView(b, view) && liveForKeys(b, ctx.keyReach);
|
|
1811
|
+
const overrides = ctx.bindingOverrides?.() ?? NO_OVERRIDES;
|
|
1812
|
+
const result = scopeBindings(ordered, state, overrides).filter((sb) => live(sb.binding));
|
|
1813
|
+
if (ctx.keymapPass === "only") return result.filter((sb) => sb.ownerId === openKeymap);
|
|
1700
1814
|
for (const action of ctx.actions.list()) {
|
|
1701
1815
|
const targetScope = action.scope === "hotkey" ? "hotkey" : "ambient";
|
|
1702
1816
|
for (const binding of actionBindings(action)) {
|
|
1703
|
-
if (
|
|
1704
|
-
result.push({ binding, scope: targetScope, ownerId: null });
|
|
1817
|
+
if (live(binding)) result.push({ binding, scope: targetScope, ownerId: null });
|
|
1705
1818
|
}
|
|
1706
1819
|
}
|
|
1707
1820
|
return result;
|
|
1708
1821
|
}
|
|
1822
|
+
function anyBinding(ctx, test) {
|
|
1823
|
+
return assembleScopedBindings(ctx).some((sb) => test(sb.binding.spec));
|
|
1824
|
+
}
|
|
1709
1825
|
function buildActionMap(registry) {
|
|
1710
1826
|
const map = /* @__PURE__ */ new Map();
|
|
1711
1827
|
for (const action of registry.list()) {
|
|
@@ -1871,6 +1987,68 @@ function explain(event, ctx, engaged, opts) {
|
|
|
1871
1987
|
const walked = walk(r, event, ctx, null, opts?.evaluateShadowed ?? false);
|
|
1872
1988
|
return buildDispatchRecord(r, walked, event, ctx, true, walked.winner ? "handled" : "unhandled");
|
|
1873
1989
|
}
|
|
1990
|
+
var MODIFIER_KEYS2 = /* @__PURE__ */ new Set(["Shift", "Control", "Alt", "Meta", "AltGraph", "CapsLock"]);
|
|
1991
|
+
var STROKES = /* @__PURE__ */ new Set([
|
|
1992
|
+
"click",
|
|
1993
|
+
"doubleclick",
|
|
1994
|
+
"longpress",
|
|
1995
|
+
"contextmenu",
|
|
1996
|
+
"multitouch",
|
|
1997
|
+
"multitouchtap"
|
|
1998
|
+
]);
|
|
1999
|
+
var isPlainEscape = (e) => e.kind === "key" && e.key === "Escape" && !e.altKey && !e.ctrlKey && !e.metaKey && !e.shiftKey;
|
|
2000
|
+
var SETTLES_INTO = ["click", "doubleclick", "longpress", "contextmenu"];
|
|
2001
|
+
function stillLive(id, ctx) {
|
|
2002
|
+
const entry = ctx.entriesById.get(id);
|
|
2003
|
+
if (!entry) return false;
|
|
2004
|
+
const allowed = ctx.getRuleCtx?.()?.allowedCapabilities;
|
|
2005
|
+
const allows = allowed ? (tags) => capabilitiesAllowed(allowed, tags) : void 0;
|
|
2006
|
+
return liveScope(id, entry.eligibility, { focusedId: null, openKeymap: id, ...allows ? { allows } : {} }) !== null;
|
|
2007
|
+
}
|
|
2008
|
+
function routeThroughKeymap(event, ctx, passes) {
|
|
2009
|
+
const stack = ctx.keymaps;
|
|
2010
|
+
const open = stack?.innermost();
|
|
2011
|
+
if (!stack || !open || event.kind === "hover") return void 0;
|
|
2012
|
+
const isKey = event.kind === "key" || event.kind === "key-held";
|
|
2013
|
+
if (isKey && ctx.keyReach && !ctx.keyReach.held) return void 0;
|
|
2014
|
+
if (!stillLive(open.id, ctx)) {
|
|
2015
|
+
stack.closeAll();
|
|
2016
|
+
return void 0;
|
|
2017
|
+
}
|
|
2018
|
+
const verdict = stack.verdict();
|
|
2019
|
+
if (verdict === "taken") return "unhandled";
|
|
2020
|
+
if (verdict === "cascaded") return passes.run("none", event);
|
|
2021
|
+
if (isPlainEscape(event)) {
|
|
2022
|
+
stack.closeInnermost();
|
|
2023
|
+
return "handled";
|
|
2024
|
+
}
|
|
2025
|
+
if (passes.run("only", event) === "handled") {
|
|
2026
|
+
stack.inputSeen();
|
|
2027
|
+
return "handled";
|
|
2028
|
+
}
|
|
2029
|
+
if (isKey) {
|
|
2030
|
+
if (event.kind === "key" && passes.binds({ ...event, kind: "key-held", phase: "down" })) return "unhandled";
|
|
2031
|
+
if (MODIFIER_KEYS2.has(event.key) || event.ctrlKey || event.metaKey || event.key === "Tab") {
|
|
2032
|
+
return passes.run("none", event);
|
|
2033
|
+
}
|
|
2034
|
+
const entry = ctx.entriesById.get(open.id)?.eligibility.keymap;
|
|
2035
|
+
const own = typeof entry === "object" ? entry.unbound : void 0;
|
|
2036
|
+
if ((own ?? ctx.leaderUnbound ?? "modal") === "modal") {
|
|
2037
|
+
stack.swallowed();
|
|
2038
|
+
return "handled";
|
|
2039
|
+
}
|
|
2040
|
+
stack.cascaded();
|
|
2041
|
+
return passes.run("none", event);
|
|
2042
|
+
}
|
|
2043
|
+
if (event.kind === "pointerdown" && SETTLES_INTO.some((kind) => passes.binds({ ...event, kind }))) {
|
|
2044
|
+
return "unhandled";
|
|
2045
|
+
}
|
|
2046
|
+
const outcome = passes.run("none", event);
|
|
2047
|
+
const stroke = STROKES.has(event.kind) || event.kind === "pointerdown" && outcome === "handled";
|
|
2048
|
+
const firstOfDouble = event.kind === "click" && passes.binds({ ...event, kind: "doubleclick" });
|
|
2049
|
+
if (stroke && !firstOfDouble) stack.inputSeen();
|
|
2050
|
+
return outcome;
|
|
2051
|
+
}
|
|
1874
2052
|
|
|
1875
2053
|
// src/interactions/dispatcher/dispatcher.ts
|
|
1876
2054
|
function createDispatcher(opts) {
|
|
@@ -1893,10 +2071,17 @@ function createDispatcher(opts) {
|
|
|
1893
2071
|
const pumped = pumpGesture(run, event);
|
|
1894
2072
|
if (pumped !== void 0) return pumped;
|
|
1895
2073
|
if (event.kind === "hover") return hover(event, ctx);
|
|
1896
|
-
|
|
2074
|
+
return routeThroughKeymap(event, ctx, {
|
|
2075
|
+
run: (pass, ev) => route(ev, { ...ctx, keymapPass: pass }),
|
|
2076
|
+
binds: (ev) => rank(ev, { ...ctx, keymapPass: "only" }, inFlight.engagedOwners(), false).ordered.length > 0
|
|
2077
|
+
}) ?? route(event, ctx);
|
|
2078
|
+
}
|
|
2079
|
+
function route(event, ctx) {
|
|
2080
|
+
const trace = ctx.trace?.recording() ? ctx.trace : null;
|
|
2081
|
+
const r = rank(event, ctx, inFlight.engagedOwners(), trace !== null);
|
|
1897
2082
|
const walked = walk(r, event, ctx, invoking(event), false);
|
|
1898
2083
|
const outcome = walked.stop === "fired" ? "handled" : "unhandled";
|
|
1899
|
-
|
|
2084
|
+
trace?.push(buildDispatchRecord(r, walked, event, ctx, false, outcome));
|
|
1900
2085
|
return outcome;
|
|
1901
2086
|
}
|
|
1902
2087
|
function hover(event, ctx) {
|
|
@@ -2112,6 +2297,229 @@ function startCarry(origin, down, payload, cb = {}) {
|
|
|
2112
2297
|
cancel: () => session.cancel()
|
|
2113
2298
|
};
|
|
2114
2299
|
}
|
|
2300
|
+
var KEYMAP_HOLD = "hold";
|
|
2301
|
+
function createKeymapStack() {
|
|
2302
|
+
let levels = [];
|
|
2303
|
+
let version = 0;
|
|
2304
|
+
const changed = createEmitter();
|
|
2305
|
+
let depth = 0;
|
|
2306
|
+
let serial = 0;
|
|
2307
|
+
let pending = [];
|
|
2308
|
+
let verdict = null;
|
|
2309
|
+
let snapshot = [];
|
|
2310
|
+
const notify = () => {
|
|
2311
|
+
snapshot = levels.map(({ openedIn: _, ...rest }) => Object.freeze({ ...rest }));
|
|
2312
|
+
version++;
|
|
2313
|
+
changed.emit();
|
|
2314
|
+
};
|
|
2315
|
+
const later = (op) => {
|
|
2316
|
+
if (depth > 0) pending.push(op);
|
|
2317
|
+
else op();
|
|
2318
|
+
};
|
|
2319
|
+
const settle = () => {
|
|
2320
|
+
const before = levels;
|
|
2321
|
+
const opened = (l) => l.openedIn === serial && depth > 0;
|
|
2322
|
+
if (levels.some(opened)) return;
|
|
2323
|
+
for (const l of levels) if (l.heldBy !== void 0) l.usedWhileHeld = true;
|
|
2324
|
+
while (levels.length > 0 && levels.at(-1).heldBy === void 0) levels = levels.slice(0, -1);
|
|
2325
|
+
if (levels !== before) notify();
|
|
2326
|
+
};
|
|
2327
|
+
return {
|
|
2328
|
+
open: () => snapshot,
|
|
2329
|
+
innermost: () => snapshot.at(-1) ?? null,
|
|
2330
|
+
push: (id, label, opts) => {
|
|
2331
|
+
const heldBy = opts?.heldBy;
|
|
2332
|
+
const bindings = opts?.bindings ?? [];
|
|
2333
|
+
const open = levels.findIndex((l) => l.id === id);
|
|
2334
|
+
if (open !== -1) levels = levels.slice(0, open);
|
|
2335
|
+
levels = [...levels, { id, label, bindings, ...heldBy !== void 0 ? { heldBy } : {}, usedWhileHeld: false, openedIn: serial }];
|
|
2336
|
+
if (depth > 0) verdict = "taken";
|
|
2337
|
+
notify();
|
|
2338
|
+
},
|
|
2339
|
+
holdOpened: (heldBy) => {
|
|
2340
|
+
let held = false;
|
|
2341
|
+
levels = levels.map((l) => {
|
|
2342
|
+
if (l.openedIn !== serial || l.heldBy !== void 0) return l;
|
|
2343
|
+
held = true;
|
|
2344
|
+
return { ...l, heldBy };
|
|
2345
|
+
});
|
|
2346
|
+
if (held) notify();
|
|
2347
|
+
return held;
|
|
2348
|
+
},
|
|
2349
|
+
release: (heldBy) => {
|
|
2350
|
+
const i = levels.findIndex((l) => l.heldBy === heldBy);
|
|
2351
|
+
if (i === -1) return;
|
|
2352
|
+
const level = levels[i];
|
|
2353
|
+
if (level.usedWhileHeld) {
|
|
2354
|
+
levels = levels.slice(0, i);
|
|
2355
|
+
while (levels.length > 0 && levels.at(-1).heldBy === void 0) levels = levels.slice(0, -1);
|
|
2356
|
+
} else levels = levels.map((l) => l === level ? { ...l, heldBy: void 0 } : l).map(dropUndefinedHeld);
|
|
2357
|
+
notify();
|
|
2358
|
+
},
|
|
2359
|
+
closeInnermost: () => {
|
|
2360
|
+
if (depth > 0) verdict = "taken";
|
|
2361
|
+
later(() => {
|
|
2362
|
+
if (levels.length === 0) return;
|
|
2363
|
+
levels = levels.slice(0, -1);
|
|
2364
|
+
notify();
|
|
2365
|
+
});
|
|
2366
|
+
},
|
|
2367
|
+
inputSeen: () => {
|
|
2368
|
+
if (depth > 0) verdict ??= "taken";
|
|
2369
|
+
later(settle);
|
|
2370
|
+
},
|
|
2371
|
+
cascaded: () => {
|
|
2372
|
+
if (depth > 0) verdict = "cascaded";
|
|
2373
|
+
later(settle);
|
|
2374
|
+
},
|
|
2375
|
+
swallowed: () => {
|
|
2376
|
+
for (const l of levels) if (l.heldBy !== void 0) l.usedWhileHeld = true;
|
|
2377
|
+
},
|
|
2378
|
+
verdict: () => verdict,
|
|
2379
|
+
closeAll: () => {
|
|
2380
|
+
pending = [];
|
|
2381
|
+
if (levels.length === 0) return;
|
|
2382
|
+
levels = [];
|
|
2383
|
+
notify();
|
|
2384
|
+
},
|
|
2385
|
+
batch: (fn) => {
|
|
2386
|
+
if (depth === 0) {
|
|
2387
|
+
serial++;
|
|
2388
|
+
verdict = null;
|
|
2389
|
+
}
|
|
2390
|
+
depth++;
|
|
2391
|
+
try {
|
|
2392
|
+
return fn();
|
|
2393
|
+
} finally {
|
|
2394
|
+
depth--;
|
|
2395
|
+
if (depth === 0) {
|
|
2396
|
+
const ops = pending;
|
|
2397
|
+
pending = [];
|
|
2398
|
+
depth = 1;
|
|
2399
|
+
try {
|
|
2400
|
+
for (const op of ops) op();
|
|
2401
|
+
} finally {
|
|
2402
|
+
depth = 0;
|
|
2403
|
+
}
|
|
2404
|
+
verdict = null;
|
|
2405
|
+
}
|
|
2406
|
+
}
|
|
2407
|
+
},
|
|
2408
|
+
subscribe: changed.subscribe,
|
|
2409
|
+
getVersion: () => version
|
|
2410
|
+
};
|
|
2411
|
+
}
|
|
2412
|
+
function dropUndefinedHeld(l) {
|
|
2413
|
+
if (l.heldBy !== void 0) return l;
|
|
2414
|
+
const { heldBy: _, ...rest } = l;
|
|
2415
|
+
return rest;
|
|
2416
|
+
}
|
|
2417
|
+
|
|
2418
|
+
// src/keymaps/keymapContribution.ts
|
|
2419
|
+
var keymapLeaderId = (id) => `keymap.${id}`;
|
|
2420
|
+
var keymapLeaderBindingId = (id, index = 0) => index === 0 ? `${keymapLeaderId(id)}.leader` : `${keymapLeaderId(id)}.leader#${index}`;
|
|
2421
|
+
function leaderBindings(def) {
|
|
2422
|
+
return [def.leader].flat().map((spec, i) => ({
|
|
2423
|
+
spec: spec.kind === "key-held" ? { ...spec, kind: "key" } : spec,
|
|
2424
|
+
opts: { id: keymapLeaderBindingId(def.id, i) }
|
|
2425
|
+
}));
|
|
2426
|
+
}
|
|
2427
|
+
var isPlainEscape2 = (spec) => spec.kind === "key" && [spec.key].flat().includes("Escape") && Object.values(spec.mods ?? {}).every((m) => m !== true);
|
|
2428
|
+
function keymapContribution(def) {
|
|
2429
|
+
if (def.bindings.some((b) => isPlainEscape2(b.spec))) {
|
|
2430
|
+
throw new Error(`keymap "${def.id}" binds Escape, which always closes a keymap`);
|
|
2431
|
+
}
|
|
2432
|
+
const open = {
|
|
2433
|
+
id: keymapLeaderId(def.id),
|
|
2434
|
+
label: `Open ${def.label} keys`,
|
|
2435
|
+
scope: "hotkey",
|
|
2436
|
+
defaultBinding: leaderBindings(def),
|
|
2437
|
+
requires: ["keymaps"],
|
|
2438
|
+
enabled: (deps) => deps?.keymaps ? true : ActionDisabledReason.NotApplicable,
|
|
2439
|
+
invoker: {
|
|
2440
|
+
timing: "immediate",
|
|
2441
|
+
run: (deps, params) => {
|
|
2442
|
+
deps.keymaps?.push(def.id, def.label, { bindings: def.bindings, ...params?.hold === true ? { heldBy: KEYMAP_HOLD } : {} });
|
|
2443
|
+
}
|
|
2444
|
+
}
|
|
2445
|
+
};
|
|
2446
|
+
return [
|
|
2447
|
+
{
|
|
2448
|
+
id: def.id,
|
|
2449
|
+
eligibility: { keymap: def.unbound ? { unbound: def.unbound } : true },
|
|
2450
|
+
bindings: [...def.bindings],
|
|
2451
|
+
presentation: { label: def.label },
|
|
2452
|
+
...def.overlay !== void 0 ? { overlay: def.overlay } : {},
|
|
2453
|
+
...def.overlayPosition ? { overlayPosition: def.overlayPosition } : {}
|
|
2454
|
+
},
|
|
2455
|
+
{
|
|
2456
|
+
id: `${def.id}.leader`,
|
|
2457
|
+
eligibility: { always: true },
|
|
2458
|
+
actions: [open, ...def.actions ?? []]
|
|
2459
|
+
}
|
|
2460
|
+
];
|
|
2461
|
+
}
|
|
2462
|
+
var ESCAPE = { shortcut: { key: "Escape", mod: false, alt: false, shift: false }, label: "Close" };
|
|
2463
|
+
var GESTURE_WORDS = {
|
|
2464
|
+
click: "click",
|
|
2465
|
+
doubleClick: "double-click",
|
|
2466
|
+
drag: "drag",
|
|
2467
|
+
longPress: "long-press",
|
|
2468
|
+
contextMenu: "right-click",
|
|
2469
|
+
wheel: "scroll",
|
|
2470
|
+
pinch: "pinch",
|
|
2471
|
+
pointerDown: "press"
|
|
2472
|
+
};
|
|
2473
|
+
var MOD_WORDS = [
|
|
2474
|
+
["mod", "Mod"],
|
|
2475
|
+
["ctrl", "Ctrl"],
|
|
2476
|
+
["meta", "Meta"],
|
|
2477
|
+
["alt", "Alt"],
|
|
2478
|
+
["shift", "Shift"]
|
|
2479
|
+
];
|
|
2480
|
+
function gestureWords(spec) {
|
|
2481
|
+
if (spec.kind === "key-held") {
|
|
2482
|
+
const chip = keySpecShortcut(spec);
|
|
2483
|
+
return chip ? `Hold ${formatShortcut(chip)}` : void 0;
|
|
2484
|
+
}
|
|
2485
|
+
const word = GESTURE_WORDS[spec.kind];
|
|
2486
|
+
if (!word) return void 0;
|
|
2487
|
+
const mods = MOD_WORDS.filter(([m]) => spec.mods?.[m] === true).map(([, w]) => w);
|
|
2488
|
+
const text = [...mods, word].join("-");
|
|
2489
|
+
return text[0].toUpperCase() + text.slice(1);
|
|
2490
|
+
}
|
|
2491
|
+
function describeKeymap(level, actions, overrides = NO_OVERRIDES) {
|
|
2492
|
+
const byId = new Map(actions.map((a) => [a.id, a]));
|
|
2493
|
+
const labelOf = (b) => {
|
|
2494
|
+
const action = byId.get(b.actionId);
|
|
2495
|
+
const params = resolveParams(b.opts?.params);
|
|
2496
|
+
const variant = params && action?.variants?.find((v) => paramsMatch(params, v.params));
|
|
2497
|
+
return variant ? variant.label : action?.label ?? b.actionId;
|
|
2498
|
+
};
|
|
2499
|
+
const rows = [ESCAPE];
|
|
2500
|
+
for (const b of overriddenBindings(level.bindings, level.id, overrides)) {
|
|
2501
|
+
const label = labelOf(b);
|
|
2502
|
+
const shortcut = b.spec.kind === "key" ? keySpecShortcut(b.spec) : void 0;
|
|
2503
|
+
if (shortcut) rows.push({ shortcut, label });
|
|
2504
|
+
else {
|
|
2505
|
+
const gesture = gestureWords(b.spec);
|
|
2506
|
+
if (gesture) rows.push({ gesture, label });
|
|
2507
|
+
}
|
|
2508
|
+
}
|
|
2509
|
+
return { id: level.id, label: level.label, held: level.heldBy !== void 0, rows };
|
|
2510
|
+
}
|
|
2511
|
+
function keymapShortcuts(def, overrides = NO_OVERRIDES) {
|
|
2512
|
+
const leaderChip = overriddenBindings(actionBindings({ id: keymapLeaderId(def.id), defaultBinding: leaderBindings(def) }), null, overrides).map((b) => keySpecShortcut(b.spec)).find((c) => c !== void 0);
|
|
2513
|
+
const out = /* @__PURE__ */ new Map();
|
|
2514
|
+
for (const b of overriddenBindings(def.bindings, def.id, overrides)) {
|
|
2515
|
+
if (b.spec.kind !== "key") continue;
|
|
2516
|
+
const chip = keySpecShortcut(b.spec);
|
|
2517
|
+
if (!chip) continue;
|
|
2518
|
+
const withPath = leaderChip ? { ...chip, leader: [{ label: def.label, shortcut: leaderChip }] } : chip;
|
|
2519
|
+
out.set(b.actionId, [...out.get(b.actionId) ?? [], withPath]);
|
|
2520
|
+
}
|
|
2521
|
+
return out;
|
|
2522
|
+
}
|
|
2115
2523
|
|
|
2116
2524
|
// src/tools/types.ts
|
|
2117
2525
|
function isTool(entry) {
|
|
@@ -2238,7 +2646,10 @@ function eligibleRule(action) {
|
|
|
2238
2646
|
return typeof eligible === "function" ? eligible.rule : eligible;
|
|
2239
2647
|
}
|
|
2240
2648
|
function findScopedConflicts(scopes) {
|
|
2241
|
-
const
|
|
2649
|
+
const overrides = scopes.overrides;
|
|
2650
|
+
const asBound = (e) => overrides?.size && e.bindings ? { ...e, bindings: overriddenBindings(e.bindings, e.id, overrides) } : e;
|
|
2651
|
+
const registry = (Array.isArray(scopes.registry) ? scopes.registry : Object.values(scopes.registry)).map(asBound);
|
|
2652
|
+
const declaredAmbient = (scopes.ambient ?? []).map(asBound);
|
|
2242
2653
|
const actions = scopes.actions ?? [];
|
|
2243
2654
|
const rules = /* @__PURE__ */ new Map();
|
|
2244
2655
|
for (const a of actions) {
|
|
@@ -2253,7 +2664,9 @@ function findScopedConflicts(scopes) {
|
|
|
2253
2664
|
(a.eligible !== void 0 ? gatedActions : ungated).push(actionAsEntry(a));
|
|
2254
2665
|
}
|
|
2255
2666
|
const modes = scopes.modes ?? KIT_MODES;
|
|
2256
|
-
const
|
|
2667
|
+
const isKeymap = (e) => e.eligibility?.keymap !== void 0;
|
|
2668
|
+
const keymaps = declaredAmbient.filter(isKeymap);
|
|
2669
|
+
const ambient = [...declaredAmbient.filter((e) => !isKeymap(e)), ...ungated];
|
|
2257
2670
|
const out = [];
|
|
2258
2671
|
const seen = /* @__PURE__ */ new Set();
|
|
2259
2672
|
const add = (keyed) => {
|
|
@@ -2264,7 +2677,7 @@ function findScopedConflicts(scopes) {
|
|
|
2264
2677
|
out.push(conflict);
|
|
2265
2678
|
}
|
|
2266
2679
|
};
|
|
2267
|
-
for (const tool of [...registry, ...ambient, ...gatedActions, ...hotkeyActions]) {
|
|
2680
|
+
for (const tool of [...registry, ...ambient, ...keymaps, ...gatedActions, ...hotkeyActions]) {
|
|
2268
2681
|
add(findConflictsKeyed([tool], rules, modes));
|
|
2269
2682
|
}
|
|
2270
2683
|
if (ambient.length > 1) add(findConflictsKeyed(ambient, rules, modes));
|
|
@@ -2333,6 +2746,20 @@ function normalizeMime(raw) {
|
|
|
2333
2746
|
const bare = raw.split(";")[0].trim().toLowerCase();
|
|
2334
2747
|
return bare || FALLBACK_MIME;
|
|
2335
2748
|
}
|
|
2749
|
+
var admitted = /* @__PURE__ */ new Map();
|
|
2750
|
+
function admitIngestMime(mime) {
|
|
2751
|
+
const key = normalizeMime(mime);
|
|
2752
|
+
admitted.set(key, (admitted.get(key) ?? 0) + 1);
|
|
2753
|
+
let released = false;
|
|
2754
|
+
return () => {
|
|
2755
|
+
if (released) return;
|
|
2756
|
+
released = true;
|
|
2757
|
+
const n = (admitted.get(key) ?? 1) - 1;
|
|
2758
|
+
if (n > 0) admitted.set(key, n);
|
|
2759
|
+
else admitted.delete(key);
|
|
2760
|
+
};
|
|
2761
|
+
}
|
|
2762
|
+
var keepsString = (mime) => INGEST_STRING_MIMES.has(mime) || admitted.has(mime);
|
|
2336
2763
|
function itemsFromFiles(files) {
|
|
2337
2764
|
return files.map((file) => ({ kind: "file", mime: normalizeMime(file.type), file }));
|
|
2338
2765
|
}
|
|
@@ -2346,7 +2773,7 @@ function itemsFromDataTransfer(dt) {
|
|
|
2346
2773
|
if (file) files.push({ kind: "file", mime: normalizeMime(file.type), file });
|
|
2347
2774
|
} else if (item.kind === "string") {
|
|
2348
2775
|
const mime = normalizeMime(item.type);
|
|
2349
|
-
if (
|
|
2776
|
+
if (keepsString(mime)) {
|
|
2350
2777
|
const slot = strings.length;
|
|
2351
2778
|
strings.push(null);
|
|
2352
2779
|
reads.push(
|
|
@@ -2372,7 +2799,7 @@ function itemTypesFromDataTransfer(dt) {
|
|
|
2372
2799
|
for (const item of Array.from(dt.items ?? [])) {
|
|
2373
2800
|
const mime = item.type ? normalizeMime(item.type) : "";
|
|
2374
2801
|
if (item.kind === "file") mimes.push(mime && mime !== "application/x-moz-file" ? mime : UNKNOWN_MIME);
|
|
2375
|
-
else if (
|
|
2802
|
+
else if (keepsString(mime)) mimes.push(mime);
|
|
2376
2803
|
}
|
|
2377
2804
|
if (mimes.length === 0 && Array.from(dt.types ?? []).includes("Files")) mimes.push(UNKNOWN_MIME);
|
|
2378
2805
|
return mimes.map((mime) => ({ mime }));
|
|
@@ -2382,7 +2809,7 @@ function itemsFromClipboardData(cd) {
|
|
|
2382
2809
|
for (const file of Array.from(cd.files ?? [])) {
|
|
2383
2810
|
out.push({ kind: "file", mime: normalizeMime(file.type), file });
|
|
2384
2811
|
}
|
|
2385
|
-
for (const mime of INGEST_STRING_MIMES) {
|
|
2812
|
+
for (const mime of /* @__PURE__ */ new Set([...INGEST_STRING_MIMES, ...admitted.keys()])) {
|
|
2386
2813
|
const text = cd.getData(mime);
|
|
2387
2814
|
if (text) out.push({ kind: "string", mime, text });
|
|
2388
2815
|
}
|
|
@@ -2473,6 +2900,7 @@ var sep = (key) => ({ kind: "separator", key });
|
|
|
2473
2900
|
function itemOf(ctx, it, key, label, off, access) {
|
|
2474
2901
|
const deps = ctx.src.depsFor(it.action);
|
|
2475
2902
|
const point = ctx.at ? { worldX: ctx.at.x, worldY: ctx.at.y } : {};
|
|
2903
|
+
if (it.action.settings) return settingsOf(ctx, it, key, label, off || !evaluateEnabled(it.action, deps, ctx.at).enabled, access);
|
|
2476
2904
|
return {
|
|
2477
2905
|
kind: "item",
|
|
2478
2906
|
key,
|
|
@@ -2487,6 +2915,32 @@ function itemOf(ctx, it, key, label, off, access) {
|
|
|
2487
2915
|
}
|
|
2488
2916
|
};
|
|
2489
2917
|
}
|
|
2918
|
+
function settingsOf(ctx, it, key, label, off, access) {
|
|
2919
|
+
const settings = it.action.settings;
|
|
2920
|
+
const state = off ? null : readActionSettings(it.action, ctx.src.depsFor(it.action));
|
|
2921
|
+
const mixed = new Set(state?.mixed ?? []);
|
|
2922
|
+
const values = (path) => mixed.has(path) ? void 0 : prefValueAtPath(state?.values, path);
|
|
2923
|
+
const onChange = (path, value) => {
|
|
2924
|
+
const params = actionSettingsParams(settings, path, value);
|
|
2925
|
+
if (params) ctx.src.trigger(it.action.id, { ...ctx.params, ...it.params, ...params });
|
|
2926
|
+
};
|
|
2927
|
+
const form = {
|
|
2928
|
+
...ctx,
|
|
2929
|
+
src: { ...ctx.src, values, onChange, over: settings.schema },
|
|
2930
|
+
root: settings.schema,
|
|
2931
|
+
read: (path, from) => from === "item" ? void 0 : values(path)
|
|
2932
|
+
};
|
|
2933
|
+
const entries = state ? tidy(groupRows(form, settings.schema, "", false)) : [];
|
|
2934
|
+
return {
|
|
2935
|
+
kind: "submenu",
|
|
2936
|
+
key,
|
|
2937
|
+
label,
|
|
2938
|
+
...it.icon ? { icon: it.icon } : {},
|
|
2939
|
+
...withAccess(access),
|
|
2940
|
+
...entries.length === 0 ? { disabled: true } : {},
|
|
2941
|
+
entries
|
|
2942
|
+
};
|
|
2943
|
+
}
|
|
2490
2944
|
function itemsNamed(ctx, name) {
|
|
2491
2945
|
const action = ctx.byId.get(name);
|
|
2492
2946
|
if (action) return actionItems(action);
|
|
@@ -2584,9 +3038,23 @@ function colorRows(ctx, leaf, key, path, off) {
|
|
|
2584
3038
|
if (!ctx.src.values) return [];
|
|
2585
3039
|
return [{ kind: "color", key, label: leaf.name, ...withAccess(leaf.access), ...off ? { disabled: true } : {}, value: textAt(ctx, path) }];
|
|
2586
3040
|
}
|
|
2587
|
-
function stringRows(ctx, leaf, key, path) {
|
|
2588
|
-
|
|
2589
|
-
|
|
3041
|
+
function stringRows(ctx, leaf, key, path, off) {
|
|
3042
|
+
const { values, onChange } = ctx.src;
|
|
3043
|
+
if (!values) return [];
|
|
3044
|
+
if (leaf.readout || !onChange) {
|
|
3045
|
+
return [{ kind: "item", key, label: `${leaf.name}: ${textAt(ctx, path) ?? "\u2014"}`, ...withAccess(leaf.access), disabled: true, run: noop }];
|
|
3046
|
+
}
|
|
3047
|
+
const stored = values(path);
|
|
3048
|
+
return [{
|
|
3049
|
+
kind: "text",
|
|
3050
|
+
key,
|
|
3051
|
+
label: leaf.name,
|
|
3052
|
+
...withAccess(leaf.access),
|
|
3053
|
+
...leaf.icon ? { icon: leaf.icon } : {},
|
|
3054
|
+
...off ? { disabled: true } : {},
|
|
3055
|
+
value: typeof stored === "string" ? stored : void 0,
|
|
3056
|
+
set: (text) => onChange(path, text)
|
|
3057
|
+
}];
|
|
2590
3058
|
}
|
|
2591
3059
|
function leafRows(ctx, leaf, key, path, off) {
|
|
2592
3060
|
switch (leaf.kind) {
|
|
@@ -2605,7 +3073,7 @@ function leafRows(ctx, leaf, key, path, off) {
|
|
|
2605
3073
|
case "color":
|
|
2606
3074
|
return colorRows(ctx, leaf, key, path, off);
|
|
2607
3075
|
case "string":
|
|
2608
|
-
return stringRows(ctx, leaf, key, path);
|
|
3076
|
+
return stringRows(ctx, leaf, key, path, off);
|
|
2609
3077
|
case "separator":
|
|
2610
3078
|
return [sep(key)];
|
|
2611
3079
|
case "label":
|
|
@@ -2703,6 +3171,7 @@ function createMenuHost(src) {
|
|
|
2703
3171
|
client: req.client,
|
|
2704
3172
|
world: req.world,
|
|
2705
3173
|
...req.under ? { under: req.under } : {},
|
|
3174
|
+
...req.above ? { above: true } : {},
|
|
2706
3175
|
source: req.source ?? "pointer"
|
|
2707
3176
|
};
|
|
2708
3177
|
emit();
|
|
@@ -2720,6 +3189,6 @@ function createMenuHost(src) {
|
|
|
2720
3189
|
};
|
|
2721
3190
|
}
|
|
2722
3191
|
|
|
2723
|
-
export { ALWAYS, ActionDisabledReason, COARSE_TARGET_SCALE, DEFAULT_ALLOWED_CAPABILITIES, DEFAULT_DEVICE_PROFILE,
|
|
2724
|
-
//# sourceMappingURL=chunk-
|
|
2725
|
-
//# sourceMappingURL=chunk-
|
|
3192
|
+
export { ALWAYS, ActionDisabledReason, COARSE_TARGET_SCALE, DEFAULT_ALLOWED_CAPABILITIES, DEFAULT_DEVICE_PROFILE, DepNode, INGEST_STRING_MIMES, KEYMAP_HOLD, LONG_PRESS_HAPTIC_MS, NEVER, NO_OVERRIDES, PREDICATE_TARGET, ScopeNode, TOOL_OFFHAND_ID, actionBindings, actionCursor, actionItemTitle, actionItems, actionSettingsParams, actionShortcuts, addCarrySurface, admitIngestMime, anyBinding, assembleEntries, bindingId, buildDepsFromRequires, buildRouteRegistry, buildRuleCtx, buildToolOffhandBindings, carryGestureId, clientToCanvas, clientToCanvasRect, createDepRegistry, createDispatchTrace, createDispatcher, createKeymapStack, createLongPressStore, createMenuHost, createTraceRing, depNodeOf, describeKeymap, describeRule, dlog, dwarn, evaluate, evaluateActive, evaluateEnabled, findConflicts, heldKeySpec, historyKey, isDebugEnabled, isTool, itemTypesFromDataTransfer, itemsFromClipboardData, itemsFromDataTransfer, itemsFromFiles, keySpecShortcut, keymapContribution, keymapLeaderBindingId, keymapLeaderId, keymapShortcuts, keysHeld, liveScope, makeToolOffhandAction, matchBest, matchSorted, matchSortedWithBarred, matchesKeyBinding, mergeMenuDefs, multiTouchGestureId, offhandKeyFor, openPointerSession, overriddenBindings, overrideActionBindings, pickMenu, pointerGestureId, pushOwner, readActionSettings, reportRouteConflicts, resolveBindingOverrides, resolveDeviceProfile, resolveMenu, resolveParams, resolveSchemaMenu, roleReader, routesForSpec, ruleCanHoldIn, rulesExclusive, scopeBindings, startCarry, targetConsultsAffordance, tuneAction, tunedParams, validateActionDefaultBinding, validateActionId };
|
|
3193
|
+
//# sourceMappingURL=chunk-ARDHI47M.js.map
|
|
3194
|
+
//# sourceMappingURL=chunk-ARDHI47M.js.map
|