@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
package/dist/react.d.ts
CHANGED
|
@@ -1,16 +1,16 @@
|
|
|
1
|
-
import { U as UseGestureDispatcherOptions } from './internal-
|
|
2
|
-
export { D as DispatcherChannels } from './internal-
|
|
1
|
+
import { U as UseGestureDispatcherOptions } from './internal-DejHXi0a.js';
|
|
2
|
+
export { D as DispatcherChannels } from './internal-DejHXi0a.js';
|
|
3
3
|
import * as react from 'react';
|
|
4
4
|
import { ReactNode, ReactElement } from 'react';
|
|
5
|
-
import { D as DepRegistry, a as DepName, b as
|
|
6
|
-
export {
|
|
5
|
+
import { D as DepRegistry, a as DepName, b as DepSource, S as ScopeNode, A as Action, c as ActionDeps, M as MenuHost, d as ActionsRegistry, e as ActionDisabledReason, B as BoundGesture, f as ActionVariant, g as MenuDef, h as DepNode, T as ToolNode, K as KeymapDescription, N as NodeId, i as KernelOverlay, C as Contribution, j as Tool, O as OverlayPosition } from './index-CyBCsdie.js';
|
|
6
|
+
export { k as ActiveToolContextProvider, l as ActiveToolContextProviderIfRoot, m as ActiveToolContextProviderProps, n as ActiveToolContextValue, u as useActiveToolContext, o as useOptionalActiveToolContext } from './index-CyBCsdie.js';
|
|
7
7
|
import { IconRef } from '@weasel-js/icons';
|
|
8
8
|
import { ModeRegistry } from '@weasel-js/modes';
|
|
9
9
|
import '@weasel-js/gestures';
|
|
10
10
|
import '@weasel-js/cursor';
|
|
11
|
+
import '@weasel-js/geom';
|
|
11
12
|
import '@weasel-js/menu';
|
|
12
13
|
import '@weasel-js/prefs';
|
|
13
|
-
import '@weasel-js/geom';
|
|
14
14
|
import '@weasel-js/registry';
|
|
15
15
|
import '@weasel-js/select';
|
|
16
16
|
|
|
@@ -39,8 +39,8 @@ declare function useDepRegistry(): DepRegistry;
|
|
|
39
39
|
declare function useOptionalDepRegistry(): DepRegistry | null;
|
|
40
40
|
/** Register a live source for `name` for the lifetime of the calling
|
|
41
41
|
* component. The `source` thunk is called at dispatch time and should
|
|
42
|
-
* return the latest value. */
|
|
43
|
-
declare function useDepSource<K extends DepName>(name: K, source:
|
|
42
|
+
* return the latest value; its `below` reads the source it displaced. */
|
|
43
|
+
declare function useDepSource<K extends DepName>(name: K, source: DepSource<K>): void;
|
|
44
44
|
|
|
45
45
|
/**
|
|
46
46
|
* One node of the actions tree: the actions registered at it, over its
|
|
@@ -53,6 +53,8 @@ declare class ActionsNode extends ScopeNode<ActionsNode> {
|
|
|
53
53
|
private readonly actions;
|
|
54
54
|
private readonly muted;
|
|
55
55
|
private readonly tunings;
|
|
56
|
+
private readonly overrides;
|
|
57
|
+
private overrideCache;
|
|
56
58
|
private readonly dispatchers;
|
|
57
59
|
private cache;
|
|
58
60
|
private host;
|
|
@@ -64,6 +66,8 @@ declare class ActionsNode extends ScopeNode<ActionsNode> {
|
|
|
64
66
|
private tuningsOf;
|
|
65
67
|
/** `a` under every tuning for its id from the root down to here. */
|
|
66
68
|
private tuned;
|
|
69
|
+
/** Every binding override from the root down to here, read into specs. */
|
|
70
|
+
private overridesHere;
|
|
67
71
|
private snapshot;
|
|
68
72
|
private deps;
|
|
69
73
|
/** The actions registered at this node itself, live, unmuted and tuned —
|
|
@@ -220,6 +224,10 @@ interface OngoingAction {
|
|
|
220
224
|
*/
|
|
221
225
|
declare function useOngoingAction(actionId: string): OngoingAction;
|
|
222
226
|
|
|
227
|
+
/** The innermost keymap open on the canvas in scope, described for a hint, or
|
|
228
|
+
* `null` while none is. Re-renders as keymaps open and close. */
|
|
229
|
+
declare function useOpenKeymap(): KeymapDescription | null;
|
|
230
|
+
|
|
223
231
|
/** World-space pointer position and the view it is over — a
|
|
224
232
|
* view id, or `null` for a surface's own camera. `null` as a whole when the
|
|
225
233
|
* pointer is over no publishing surface. */
|
|
@@ -412,4 +420,4 @@ declare function useContributions<TOverlay = KernelOverlay>(opts: UseContributio
|
|
|
412
420
|
*/
|
|
413
421
|
declare function useOffhandAction(entries: readonly Contribution<unknown>[]): void;
|
|
414
422
|
|
|
415
|
-
export { ActionsProvider, type CommandOptions, type ContributionsApi, DepRegistry, DepRegistryProvider, InputScope, type InputScopeProps, type OngoingAction, PointerContextProvider, type PointerContextValue, type PointerWorldPos, SelectionContextProvider, SelectionContextProviderIfRoot, type SelectionContextValue, type ToolsApi, type UseContributionsOptions, UseGestureDispatcherOptions, type UseToolsOptions, Yoke, type YokeProps, createPointerStore, useAction, useActionsRegistry, useCommand, useContributions, useDepRegistry, useDepSource, useGestureDispatcher, useMenuHost, useMenus, useOffhandAction, useOngoingAction, useOptionalDepRegistry, usePointerContext, usePointerPosition, usePublishSelection, useSelectionContext, useTools, useYoke };
|
|
423
|
+
export { ActionsProvider, type CommandOptions, type ContributionsApi, DepRegistry, DepRegistryProvider, InputScope, type InputScopeProps, type OngoingAction, PointerContextProvider, type PointerContextValue, type PointerWorldPos, SelectionContextProvider, SelectionContextProviderIfRoot, type SelectionContextValue, type ToolsApi, type UseContributionsOptions, UseGestureDispatcherOptions, type UseToolsOptions, Yoke, type YokeProps, createPointerStore, useAction, useActionsRegistry, useCommand, useContributions, useDepRegistry, useDepSource, useGestureDispatcher, useMenuHost, useMenus, useOffhandAction, useOngoingAction, useOpenKeymap, useOptionalDepRegistry, usePointerContext, usePointerPosition, usePublishSelection, useSelectionContext, useTools, useYoke };
|
package/dist/react.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { createDepRegistry, createDispatcher, assembleEntries, liveScope,
|
|
1
|
+
import { createDepRegistry, createKeymapStack, createDispatchTrace, createDispatcher, describeKeymap, assembleEntries, liveScope, offhandKeyFor, makeToolOffhandAction, buildToolOffhandBindings, dlog, NO_OVERRIDES, reportRouteConflicts, ScopeNode, overrideActionBindings, tuneAction, resolveBindingOverrides, createMenuHost, pushOwner, evaluateEnabled, tunedParams, validateActionId, validateActionDefaultBinding, isTool, depNodeOf, DepNode, buildDepsFromRequires, clientToCanvas, LONG_PRESS_HAPTIC_MS, multiTouchGestureId, openPointerSession, addCarrySurface, carryGestureId, anyBinding, isEditableTarget, focusedControlOwnsKey, itemsFromClipboardData, itemsFromDataTransfer, itemTypesFromDataTransfer, actionCursor } from './chunk-ARDHI47M.js';
|
|
2
2
|
import { createContext, useState, useContext, useEffect, useMemo, useRef, useCallback, useSyncExternalStore } from 'react';
|
|
3
3
|
import { isApplePlatform, heldPointers, createPointerRecognizer, isInControlWithin, longPressEvents, stylusOf } from '@weasel-js/gestures';
|
|
4
4
|
import { isDev, useLatest, useKitSettings, useStableByContent, sameList } from '@weasel-js/react';
|
|
@@ -108,7 +108,7 @@ function useDepSource(name, source) {
|
|
|
108
108
|
const registry = useDepRegistry();
|
|
109
109
|
const sourceRef = useLatest(source);
|
|
110
110
|
useEffect(() => {
|
|
111
|
-
return registry.register(name, () => sourceRef.current());
|
|
111
|
+
return registry.register(name, (below) => sourceRef.current(below));
|
|
112
112
|
}, [name, registry, sourceRef]);
|
|
113
113
|
}
|
|
114
114
|
var MenuHostContext = createContext(null);
|
|
@@ -148,6 +148,8 @@ var ActionsNode = class extends ScopeNode {
|
|
|
148
148
|
actions = /* @__PURE__ */ new Map();
|
|
149
149
|
muted = /* @__PURE__ */ new Map();
|
|
150
150
|
tunings = /* @__PURE__ */ new Map();
|
|
151
|
+
overrides = [];
|
|
152
|
+
overrideCache = null;
|
|
151
153
|
dispatchers = [];
|
|
152
154
|
cache = null;
|
|
153
155
|
host = null;
|
|
@@ -173,7 +175,17 @@ var ActionsNode = class extends ScopeNode {
|
|
|
173
175
|
/** `a` under every tuning for its id from the root down to here. */
|
|
174
176
|
tuned(a) {
|
|
175
177
|
const tunings = this.tuningsOf(a.id);
|
|
176
|
-
return tunings.length ? tuneAction(a, tunings) : a;
|
|
178
|
+
return overrideActionBindings(tunings.length ? tuneAction(a, tunings) : a, this.overridesHere());
|
|
179
|
+
}
|
|
180
|
+
/** Every binding override from the root down to here, read into specs. */
|
|
181
|
+
overridesHere() {
|
|
182
|
+
const cached = this.overrideCache;
|
|
183
|
+
if (cached && cached.version === this.tree.version) return cached.resolved;
|
|
184
|
+
const maps = [];
|
|
185
|
+
for (const n of this.chain()) maps.unshift(...n.overrides);
|
|
186
|
+
const resolved = resolveBindingOverrides(maps);
|
|
187
|
+
this.overrideCache = { version: this.tree.version, resolved };
|
|
188
|
+
return resolved;
|
|
177
189
|
}
|
|
178
190
|
snapshot() {
|
|
179
191
|
const leaf = this.start();
|
|
@@ -291,6 +303,18 @@ var ActionsNode = class extends ScopeNode {
|
|
|
291
303
|
};
|
|
292
304
|
},
|
|
293
305
|
paramsOf: (id, given) => tunedParams(this.tuningsOf(id), given),
|
|
306
|
+
overrideBindings: (overrides) => {
|
|
307
|
+
const release = pushOwner(this.overrides, overrides);
|
|
308
|
+
this.changed();
|
|
309
|
+
let released = false;
|
|
310
|
+
return () => {
|
|
311
|
+
if (released) return;
|
|
312
|
+
released = true;
|
|
313
|
+
release();
|
|
314
|
+
this.changed();
|
|
315
|
+
};
|
|
316
|
+
},
|
|
317
|
+
bindingOverrides: () => this.start().overridesHere(),
|
|
294
318
|
list: () => this.snapshot(),
|
|
295
319
|
trigger: (id, params) => {
|
|
296
320
|
const leaf = this.start();
|
|
@@ -419,6 +443,7 @@ function useToolLifecycle(opts) {
|
|
|
419
443
|
function createDispatchCore(src) {
|
|
420
444
|
const { canvas } = src;
|
|
421
445
|
let routedId = null;
|
|
446
|
+
let over = false;
|
|
422
447
|
const target = () => {
|
|
423
448
|
if (routedId === null) return src.root();
|
|
424
449
|
return src.views()?.targets().find((t) => t.id === routedId) ?? src.root();
|
|
@@ -426,6 +451,10 @@ function createDispatchCore(src) {
|
|
|
426
451
|
const dispatcherNow = () => target().dispatcher;
|
|
427
452
|
const routedDeps = withViewDeps(() => src.context().depRegistry, () => target().deps?.());
|
|
428
453
|
const routedRuleCtx = () => target().getRuleCtx?.();
|
|
454
|
+
const batch = (fn) => {
|
|
455
|
+
const keymaps = src.context().keymaps;
|
|
456
|
+
return keymaps ? keymaps.batch(fn) : fn();
|
|
457
|
+
};
|
|
429
458
|
const ctxNow = () => ({
|
|
430
459
|
...src.context(),
|
|
431
460
|
depRegistry: routedDeps,
|
|
@@ -461,12 +490,18 @@ function createDispatchCore(src) {
|
|
|
461
490
|
const [x, y] = clientToCanvas(canvas, cx, cy);
|
|
462
491
|
return { x, y };
|
|
463
492
|
},
|
|
464
|
-
dispatch: (ev, on) => {
|
|
493
|
+
dispatch: (ev, on, reach) => batch(() => {
|
|
465
494
|
const d = on ?? dispatcherNow();
|
|
466
495
|
src.uses(d);
|
|
467
|
-
return d.handleInput(ev, ctxNow());
|
|
468
|
-
},
|
|
496
|
+
return d.handleInput(ev, reach ? { ...ctxNow(), keyReach: reach } : ctxNow());
|
|
497
|
+
}),
|
|
498
|
+
batch,
|
|
499
|
+
keymaps: () => src.context().keymaps,
|
|
469
500
|
holdsKeys: () => canvas ? src.actions().holdsKeys() : src.actions().isActive(),
|
|
501
|
+
pointerOver: () => over,
|
|
502
|
+
setPointerOver: (next) => {
|
|
503
|
+
over = canvas !== null && next;
|
|
504
|
+
},
|
|
470
505
|
activate: () => src.actions().activate(),
|
|
471
506
|
disposed: src.disposed
|
|
472
507
|
};
|
|
@@ -505,6 +540,25 @@ function dispatcherWatch(onChange) {
|
|
|
505
540
|
};
|
|
506
541
|
}
|
|
507
542
|
|
|
543
|
+
// src/interactions/dispatcher/underPointer.ts
|
|
544
|
+
function underPointer(view, mods, w) {
|
|
545
|
+
const affordance = view.affordanceAt?.(w) ?? void 0;
|
|
546
|
+
const body = view.classifyTarget?.(w);
|
|
547
|
+
return {
|
|
548
|
+
altKey: mods.altKey,
|
|
549
|
+
ctrlKey: mods.ctrlKey,
|
|
550
|
+
metaKey: mods.metaKey,
|
|
551
|
+
shiftKey: mods.shiftKey,
|
|
552
|
+
...affordance !== void 0 ? { affordance } : {},
|
|
553
|
+
...body?.body !== void 0 ? { bodyTarget: body.body } : {},
|
|
554
|
+
...body?.kind !== void 0 ? { bodyKind: body.kind } : {},
|
|
555
|
+
...body?.doubleClick !== void 0 ? { doubleClickBody: doubleClickBodyOf(body.doubleClick) } : {}
|
|
556
|
+
};
|
|
557
|
+
}
|
|
558
|
+
function doubleClickBodyOf(named) {
|
|
559
|
+
return { bodyTarget: named.body, ...named.kind !== void 0 ? { bodyKind: named.kind } : {} };
|
|
560
|
+
}
|
|
561
|
+
|
|
508
562
|
// src/interactions/dispatcher/channels/carry.ts
|
|
509
563
|
function carryInput(core) {
|
|
510
564
|
const { canvas } = core;
|
|
@@ -517,6 +571,7 @@ function carryInput(core) {
|
|
|
517
571
|
if (core.disposed()) return "unhandled";
|
|
518
572
|
const event = () => {
|
|
519
573
|
const w = core.toWorld(at.clientX, at.clientY);
|
|
574
|
+
const { affordance, bodyTarget, bodyKind } = underPointer(core.target(), at, w);
|
|
520
575
|
return {
|
|
521
576
|
kind: "carry",
|
|
522
577
|
stage,
|
|
@@ -530,7 +585,10 @@ function carryInput(core) {
|
|
|
530
585
|
altKey: at.altKey,
|
|
531
586
|
ctrlKey: at.ctrlKey,
|
|
532
587
|
metaKey: at.metaKey,
|
|
533
|
-
shiftKey: at.shiftKey
|
|
588
|
+
shiftKey: at.shiftKey,
|
|
589
|
+
...affordance !== void 0 ? { affordance } : {},
|
|
590
|
+
...bodyTarget !== void 0 ? { bodyTarget } : {},
|
|
591
|
+
...bodyKind !== void 0 ? { bodyKind } : {}
|
|
534
592
|
};
|
|
535
593
|
};
|
|
536
594
|
const routedNow = core.routedView();
|
|
@@ -541,13 +599,12 @@ function carryInput(core) {
|
|
|
541
599
|
return core.dispatch(event());
|
|
542
600
|
}
|
|
543
601
|
if (pinned.has(pointerId)) core.setRoutedView(pinned.get(pointerId));
|
|
544
|
-
if (stage
|
|
545
|
-
|
|
546
|
-
if (stage === "drop" && !core.dispatcherNow().inFlight().has(gestureIdFor(ev))) {
|
|
602
|
+
if (stage === "drop" || stage === "leave") pinned.delete(pointerId);
|
|
603
|
+
if (stage !== "leave" && !core.dispatcherNow().inFlight().has(carryGestureId(pointerId))) {
|
|
547
604
|
core.routeAt(null, at.clientX, at.clientY);
|
|
548
|
-
|
|
605
|
+
if (stage === "move") pinned.set(pointerId, core.routedView());
|
|
549
606
|
}
|
|
550
|
-
return core.dispatch(
|
|
607
|
+
return core.dispatch(event());
|
|
551
608
|
} finally {
|
|
552
609
|
core.setRoutedView(routedNow);
|
|
553
610
|
}
|
|
@@ -555,25 +612,6 @@ function carryInput(core) {
|
|
|
555
612
|
});
|
|
556
613
|
}
|
|
557
614
|
|
|
558
|
-
// src/interactions/dispatcher/underPointer.ts
|
|
559
|
-
function underPointer(view, mods, w) {
|
|
560
|
-
const affordance = view.affordanceAt?.(w) ?? void 0;
|
|
561
|
-
const body = view.classifyTarget?.(w);
|
|
562
|
-
return {
|
|
563
|
-
altKey: mods.altKey,
|
|
564
|
-
ctrlKey: mods.ctrlKey,
|
|
565
|
-
metaKey: mods.metaKey,
|
|
566
|
-
shiftKey: mods.shiftKey,
|
|
567
|
-
...affordance !== void 0 ? { affordance } : {},
|
|
568
|
-
...body?.body !== void 0 ? { bodyTarget: body.body } : {},
|
|
569
|
-
...body?.kind !== void 0 ? { bodyKind: body.kind } : {},
|
|
570
|
-
...body?.doubleClick !== void 0 ? { doubleClickBody: doubleClickBodyOf(body.doubleClick) } : {}
|
|
571
|
-
};
|
|
572
|
-
}
|
|
573
|
-
function doubleClickBodyOf(named) {
|
|
574
|
-
return { bodyTarget: named.body, ...named.kind !== void 0 ? { bodyKind: named.kind } : {} };
|
|
575
|
-
}
|
|
576
|
-
|
|
577
615
|
// src/interactions/dispatcher/channels/contextMenu.ts
|
|
578
616
|
function contextMenuInput(core, takeNativeHold) {
|
|
579
617
|
const { routeAt, toWorld, target, dispatch } = core;
|
|
@@ -618,6 +656,15 @@ function hoverCursorInput(core, paintedCursor, pointersHeld, cursorSink = () =>
|
|
|
618
656
|
};
|
|
619
657
|
let last = null;
|
|
620
658
|
let facts = null;
|
|
659
|
+
let heldHeard = null;
|
|
660
|
+
const hears = () => {
|
|
661
|
+
if (pointersHeld() === 0) {
|
|
662
|
+
heldHeard = null;
|
|
663
|
+
return true;
|
|
664
|
+
}
|
|
665
|
+
heldHeard ??= anyBinding(ctxNow(), (s) => s.kind === "hover" && s.held !== void 0);
|
|
666
|
+
return heldHeard;
|
|
667
|
+
};
|
|
621
668
|
const resolve = () => {
|
|
622
669
|
if (!canvas || !last) return;
|
|
623
670
|
if (pointersHeld() > 0 || dispatcherNow().inFlight().size > 0) {
|
|
@@ -635,7 +682,7 @@ function hoverCursorInput(core, paintedCursor, pointersHeld, cursorSink = () =>
|
|
|
635
682
|
const ctx = ctxNow();
|
|
636
683
|
const d = dispatcherNow();
|
|
637
684
|
const press = { kind: "pointerdown", x: w.x, y: w.y, clientX: h.clientX, clientY: h.clientY, ...where };
|
|
638
|
-
if (
|
|
685
|
+
if (ctx.trace?.recording()) ctx.trace.setLive(() => d.explain(press, ctx));
|
|
639
686
|
const click = { kind: "click", x: w.x, y: w.y, pressX: w.x, pressY: w.y, ...where };
|
|
640
687
|
const cursorOf = (r) => r ? actionCursor(r.action, r.params) : void 0;
|
|
641
688
|
const cursor = cursorOf(d.resolveOnly(press, ctx)) ?? cursorOf(dispatcherNow().resolveOnly(click, ctx));
|
|
@@ -657,16 +704,18 @@ function hoverCursorInput(core, paintedCursor, pointersHeld, cursorSink = () =>
|
|
|
657
704
|
const w = toWorld(at.clientX, at.clientY);
|
|
658
705
|
const where = underPointer(target(), at, w);
|
|
659
706
|
const from = facts ? { from: whereOf(facts.where) } : {};
|
|
707
|
+
const held = pointersHeld() > 0 ? { held: true } : {};
|
|
660
708
|
facts = { at, where };
|
|
661
|
-
dispatch({ kind: "hover", x: w.x, y: w.y, clientX: at.clientX, clientY: at.clientY, ...where, ...from });
|
|
709
|
+
dispatch({ kind: "hover", x: w.x, y: w.y, clientX: at.clientX, clientY: at.clientY, ...where, ...from, ...held });
|
|
662
710
|
};
|
|
663
711
|
return {
|
|
664
712
|
moved(e) {
|
|
665
713
|
last = hoverOf(e);
|
|
666
|
-
if (
|
|
714
|
+
if (hears()) hoverAt(last);
|
|
667
715
|
refresh();
|
|
668
716
|
},
|
|
669
717
|
released(e) {
|
|
718
|
+
heldHeard = null;
|
|
670
719
|
last = hoverOf(e);
|
|
671
720
|
refreshSoon();
|
|
672
721
|
},
|
|
@@ -678,7 +727,7 @@ function hoverCursorInput(core, paintedCursor, pointersHeld, cursorSink = () =>
|
|
|
678
727
|
}
|
|
679
728
|
facts = null;
|
|
680
729
|
last = null;
|
|
681
|
-
|
|
730
|
+
ctxNow().trace?.setLive(null);
|
|
682
731
|
paintedCursor()?.clearPointer();
|
|
683
732
|
override.clear();
|
|
684
733
|
},
|
|
@@ -687,7 +736,7 @@ function hoverCursorInput(core, paintedCursor, pointersHeld, cursorSink = () =>
|
|
|
687
736
|
const prev = last;
|
|
688
737
|
last = { ...last, altKey: e.altKey, ctrlKey: e.ctrlKey, metaKey: e.metaKey, shiftKey: e.shiftKey };
|
|
689
738
|
const changed = prev.altKey !== last.altKey || prev.ctrlKey !== last.ctrlKey || prev.metaKey !== last.metaKey || prev.shiftKey !== last.shiftKey;
|
|
690
|
-
if (changed &&
|
|
739
|
+
if (changed && hears()) hoverAt(last);
|
|
691
740
|
refreshSoon();
|
|
692
741
|
},
|
|
693
742
|
clear: override.clear
|
|
@@ -778,50 +827,73 @@ function ingestInput(core) {
|
|
|
778
827
|
return { onDragOver, onDragLeave, onDrop, onPaste };
|
|
779
828
|
}
|
|
780
829
|
|
|
830
|
+
// src/interactions/dispatcher/channels/keymapKeys.ts
|
|
831
|
+
function keymapKeys(stack) {
|
|
832
|
+
const leaders = /* @__PURE__ */ new Map();
|
|
833
|
+
const quiet = /* @__PURE__ */ new Set();
|
|
834
|
+
const release = (physical) => {
|
|
835
|
+
if (leaders.delete(physical)) stack()?.release(`key:${physical}`);
|
|
836
|
+
};
|
|
837
|
+
return {
|
|
838
|
+
quiet: (physical) => leaders.has(physical) || quiet.has(physical),
|
|
839
|
+
press: (e, physical, run) => {
|
|
840
|
+
const before = stack()?.innermost() ?? null;
|
|
841
|
+
run();
|
|
842
|
+
const s = stack();
|
|
843
|
+
if (s?.holdOpened(`key:${physical}`)) leaders.set(physical, e.metaKey);
|
|
844
|
+
else if (before !== null && s?.innermost() !== before) quiet.add(physical);
|
|
845
|
+
},
|
|
846
|
+
up: (e, physical) => {
|
|
847
|
+
quiet.delete(physical);
|
|
848
|
+
release(physical);
|
|
849
|
+
if (e.key === "Meta") {
|
|
850
|
+
for (const [k, withCmd] of [...leaders]) if (withCmd) release(k);
|
|
851
|
+
}
|
|
852
|
+
},
|
|
853
|
+
clear: () => {
|
|
854
|
+
leaders.clear();
|
|
855
|
+
quiet.clear();
|
|
856
|
+
}
|
|
857
|
+
};
|
|
858
|
+
}
|
|
859
|
+
|
|
781
860
|
// src/interactions/dispatcher/channels/keyboard.ts
|
|
782
861
|
function typedWithAltGraph(e) {
|
|
783
862
|
if (!e.ctrlKey || !e.altKey || e.key.length !== 1 || !e.getModifierState?.("AltGraph")) return false;
|
|
784
863
|
const base = /^(?:Key|Digit)(.)$/.exec(e.code)?.[1];
|
|
785
864
|
return base === void 0 || base.toLowerCase() !== e.key.toLowerCase();
|
|
786
865
|
}
|
|
866
|
+
function keystrokeEvents(e, mods) {
|
|
867
|
+
const common = { key: e.key, ...e.code ? { code: e.code } : {}, ...mods, metaKey: e.metaKey, shiftKey: e.shiftKey };
|
|
868
|
+
return {
|
|
869
|
+
keyEv: { kind: "key", ...common, repeat: e.repeat },
|
|
870
|
+
heldEv: { kind: "key-held", ...common, phase: "down" }
|
|
871
|
+
};
|
|
872
|
+
}
|
|
787
873
|
var inMenu = (t) => t instanceof Element && t.closest('[role="menu"]') !== null;
|
|
788
874
|
function keyboardInput(core) {
|
|
789
875
|
const { dispatch, dispatcherNow } = core;
|
|
790
876
|
const heldKeys = /* @__PURE__ */ new Map();
|
|
877
|
+
const keymaps = keymapKeys(core.keymaps);
|
|
791
878
|
const codeOf = (e) => e.code ? { code: e.code } : {};
|
|
792
879
|
const physicalKey = (e) => e.code || e.key.toLowerCase();
|
|
793
880
|
const onKeyDown = (e) => {
|
|
794
881
|
if (e.defaultPrevented || isEditableTarget(e.target) || inMenu(e.target) || focusedControlOwnsKey(e)) return;
|
|
795
|
-
|
|
796
|
-
if (
|
|
882
|
+
const reach = { held: core.holdsKeys(), over: core.pointerOver() };
|
|
883
|
+
if (!reach.held && !reach.over) return;
|
|
884
|
+
if (e.repeat && (heldKeys.has(physicalKey(e)) || keymaps.quiet(physicalKey(e)))) {
|
|
797
885
|
e.preventDefault();
|
|
798
886
|
return;
|
|
799
887
|
}
|
|
800
|
-
|
|
801
|
-
|
|
888
|
+
const altGr = typedWithAltGraph(e);
|
|
889
|
+
const typed = { altKey: false, ctrlKey: false };
|
|
890
|
+
keymaps.press(e, physicalKey(e), () => core.batch(() => altGr && core.keymaps()?.innermost() ? press(e, typed, reach) : press(e, { altKey: e.altKey, ctrlKey: e.ctrlKey }, reach) || altGr && press(e, typed, reach)));
|
|
802
891
|
};
|
|
803
|
-
const press = (e, mods) => {
|
|
804
|
-
const keyEv =
|
|
805
|
-
|
|
806
|
-
key: e.key,
|
|
807
|
-
...codeOf(e),
|
|
808
|
-
...mods,
|
|
809
|
-
metaKey: e.metaKey,
|
|
810
|
-
shiftKey: e.shiftKey,
|
|
811
|
-
repeat: e.repeat
|
|
812
|
-
};
|
|
813
|
-
const keyResult = dispatch(keyEv);
|
|
814
|
-
const heldEv = {
|
|
815
|
-
kind: "key-held",
|
|
816
|
-
key: e.key,
|
|
817
|
-
...codeOf(e),
|
|
818
|
-
phase: "down",
|
|
819
|
-
...mods,
|
|
820
|
-
metaKey: e.metaKey,
|
|
821
|
-
shiftKey: e.shiftKey
|
|
822
|
-
};
|
|
892
|
+
const press = (e, mods, reach) => {
|
|
893
|
+
const { keyEv, heldEv } = keystrokeEvents(e, mods);
|
|
894
|
+
const keyResult = dispatch(keyEv, void 0, reach);
|
|
823
895
|
const heldOn = dispatcherNow();
|
|
824
|
-
const heldResult = dispatch(heldEv, heldOn);
|
|
896
|
+
const heldResult = dispatch(heldEv, heldOn, reach);
|
|
825
897
|
if (heldResult === "handled") {
|
|
826
898
|
heldKeys.set(physicalKey(e), { key: e.key, ...codeOf(e), on: heldOn });
|
|
827
899
|
}
|
|
@@ -831,6 +903,7 @@ function keyboardInput(core) {
|
|
|
831
903
|
};
|
|
832
904
|
const onKeyUp = (e) => {
|
|
833
905
|
const physical = physicalKey(e);
|
|
906
|
+
keymaps.up(e, physical);
|
|
834
907
|
const down = heldKeys.get(physical);
|
|
835
908
|
if (down === void 0) return;
|
|
836
909
|
const ev = {
|
|
@@ -847,6 +920,7 @@ function keyboardInput(core) {
|
|
|
847
920
|
dispatch(ev, down.on);
|
|
848
921
|
};
|
|
849
922
|
const releaseAll = () => {
|
|
923
|
+
keymaps.clear();
|
|
850
924
|
const releasing = [...heldKeys.values()];
|
|
851
925
|
heldKeys.clear();
|
|
852
926
|
for (const { key, code, on } of releasing) {
|
|
@@ -887,6 +961,7 @@ var sampleOf = (e) => ({
|
|
|
887
961
|
clientX: e.clientX,
|
|
888
962
|
clientY: e.clientY,
|
|
889
963
|
target: e.target,
|
|
964
|
+
timeStamp: e.timeStamp,
|
|
890
965
|
altKey: e.altKey,
|
|
891
966
|
ctrlKey: e.ctrlKey,
|
|
892
967
|
metaKey: e.metaKey,
|
|
@@ -1173,6 +1248,7 @@ function attachInput(canvas, src, channels) {
|
|
|
1173
1248
|
pinch.end();
|
|
1174
1249
|
pointer.cancelHeld();
|
|
1175
1250
|
keys.releaseAll();
|
|
1251
|
+
src.context().keymaps?.closeAll();
|
|
1176
1252
|
};
|
|
1177
1253
|
const listeners = listenerSet();
|
|
1178
1254
|
const keyCapture = channels.keyboard === "first";
|
|
@@ -1184,6 +1260,12 @@ function attachInput(canvas, src, channels) {
|
|
|
1184
1260
|
listeners.on(canvas, "pointerdown", () => {
|
|
1185
1261
|
src.actions().activate();
|
|
1186
1262
|
});
|
|
1263
|
+
const setOver = (on) => () => {
|
|
1264
|
+
core.setPointerOver(on);
|
|
1265
|
+
};
|
|
1266
|
+
listeners.on(canvas, "pointerenter", setOver(true));
|
|
1267
|
+
listeners.on(canvas, "pointermove", setOver(true));
|
|
1268
|
+
listeners.on(canvas, "pointerleave", setOver(false));
|
|
1187
1269
|
if (channels.pointer) {
|
|
1188
1270
|
listeners.on(window, "keydown", hover.onKey);
|
|
1189
1271
|
listeners.on(window, "keyup", hover.onKey);
|
|
@@ -1191,6 +1273,14 @@ function attachInput(canvas, src, channels) {
|
|
|
1191
1273
|
listeners.on(canvas, "pointerdown", pointer.onPointerDown);
|
|
1192
1274
|
listeners.on(canvas, "pointermove", pointer.onHoverMove);
|
|
1193
1275
|
listeners.on(canvas, "dblclick", pointer.onNativeDoubleClick);
|
|
1276
|
+
} else if (channels.hover) {
|
|
1277
|
+
listeners.on(window, "keydown", hover.onKey);
|
|
1278
|
+
listeners.on(window, "keyup", hover.onKey);
|
|
1279
|
+
listeners.on(canvas, "pointerleave", hover.onLeave);
|
|
1280
|
+
listeners.on(canvas, "pointermove", (e) => {
|
|
1281
|
+
core.routeAt(null, e.clientX, e.clientY);
|
|
1282
|
+
hover.moved(e);
|
|
1283
|
+
});
|
|
1194
1284
|
}
|
|
1195
1285
|
if (channels.wheel) {
|
|
1196
1286
|
listeners.on(canvas, "wheel", wheelInput(core, pinch.live), { passive: false, capture: true });
|
|
@@ -1222,13 +1312,15 @@ function attachInput(canvas, src, channels) {
|
|
|
1222
1312
|
held?.release();
|
|
1223
1313
|
redraw.stop();
|
|
1224
1314
|
for (const d of src.dispatchers()) d.cancelAll("cancel");
|
|
1315
|
+
src.context().keymaps?.closeAll();
|
|
1225
1316
|
};
|
|
1226
1317
|
}
|
|
1227
1318
|
|
|
1228
1319
|
// src/interactions/dispatcher/useGestureDispatcher.tsx
|
|
1229
1320
|
function useGestureDispatcher(opts) {
|
|
1230
|
-
const { canvasRef, actions, entriesById, enabled = true, keyboard = true, affordanceAt, classifyTarget, dispatcher: dispatcherOpt, clientToWorld, clientToLocal, requestRedraw, paintedCursor, cursorSink, getRuleCtx, onClick, onDoubleClick, views, channels, longPress, claimKeys = false, hears = "scope" } = opts;
|
|
1321
|
+
const { canvasRef, actions, entriesById, enabled = true, keyboard = true, affordanceAt, classifyTarget, dispatcher: dispatcherOpt, trace: traceOpt, clientToWorld, clientToLocal, requestRedraw, paintedCursor, cursorSink, getRuleCtx, onClick, onDoubleClick, views, channels, longPress, claimKeys = false, hears = "scope" } = opts;
|
|
1231
1322
|
const pointerChannel = channels?.pointer !== false;
|
|
1323
|
+
const hoverChannel = channels?.hover ?? pointerChannel;
|
|
1232
1324
|
const wheelChannel = channels?.wheel !== false;
|
|
1233
1325
|
const pinchChannel = channels?.pinch !== false;
|
|
1234
1326
|
const contextMenuChannel = channels?.contextMenu !== false;
|
|
@@ -1239,6 +1331,12 @@ function useGestureDispatcher(opts) {
|
|
|
1239
1331
|
const activeTool = useActiveToolContext();
|
|
1240
1332
|
const depRegistry = useDepRegistry();
|
|
1241
1333
|
const [isMac] = useState(isApplePlatform);
|
|
1334
|
+
const [keymaps] = useState(createKeymapStack);
|
|
1335
|
+
useEffect(() => depRegistry.register("keymaps", () => keymaps), [depRegistry, keymaps]);
|
|
1336
|
+
const kitSettings = useKitSettings();
|
|
1337
|
+
const [ownTrace] = useState(createDispatchTrace);
|
|
1338
|
+
const trace = traceOpt ?? ownTrace;
|
|
1339
|
+
useEffect(() => depRegistry.register("dispatchTrace", () => trace), [depRegistry, trace]);
|
|
1242
1340
|
const dispatcherRef = useRef(null);
|
|
1243
1341
|
if (!dispatcherRef.current) {
|
|
1244
1342
|
dispatcherRef.current = dispatcherOpt ?? createDispatcher();
|
|
@@ -1254,7 +1352,11 @@ function useGestureDispatcher(opts) {
|
|
|
1254
1352
|
activeToolId: activeTool.active,
|
|
1255
1353
|
hotkeyStack: activeTool.hotkeyStack,
|
|
1256
1354
|
entriesById,
|
|
1257
|
-
isMac
|
|
1355
|
+
isMac,
|
|
1356
|
+
trace,
|
|
1357
|
+
bindingOverrides: () => registryRef.current.bindingOverrides(),
|
|
1358
|
+
keymaps,
|
|
1359
|
+
leaderUnbound: kitSettings.get("gestures.keymapUnbound")
|
|
1258
1360
|
});
|
|
1259
1361
|
const rootTargetRef = useLatest({
|
|
1260
1362
|
id: null,
|
|
@@ -1273,7 +1375,7 @@ function useGestureDispatcher(opts) {
|
|
|
1273
1375
|
const requestRedrawRef = useLatest(requestRedraw);
|
|
1274
1376
|
const cursorRef = useLatest({ painted: paintedCursor, sink: cursorSink });
|
|
1275
1377
|
const longPressRef = useLatest(longPress);
|
|
1276
|
-
const kitSettingsRef = useLatest(
|
|
1378
|
+
const kitSettingsRef = useLatest(kitSettings);
|
|
1277
1379
|
const clicksRef = useRef({ last: null });
|
|
1278
1380
|
useToolLifecycle({
|
|
1279
1381
|
entriesById,
|
|
@@ -1309,6 +1411,7 @@ function useGestureDispatcher(opts) {
|
|
|
1309
1411
|
}, {
|
|
1310
1412
|
keyboard,
|
|
1311
1413
|
pointer: pointerChannel,
|
|
1414
|
+
hover: hoverChannel,
|
|
1312
1415
|
wheel: wheelChannel,
|
|
1313
1416
|
pinch: pinchChannel,
|
|
1314
1417
|
contextMenu: contextMenuChannel,
|
|
@@ -1320,6 +1423,7 @@ function useGestureDispatcher(opts) {
|
|
|
1320
1423
|
keyboard,
|
|
1321
1424
|
canvasRef,
|
|
1322
1425
|
pointerChannel,
|
|
1426
|
+
hoverChannel,
|
|
1323
1427
|
wheelChannel,
|
|
1324
1428
|
pinchChannel,
|
|
1325
1429
|
contextMenuChannel,
|
|
@@ -1447,6 +1551,34 @@ function useOngoingAction(actionId) {
|
|
|
1447
1551
|
}, [edit, actionId]);
|
|
1448
1552
|
return edit;
|
|
1449
1553
|
}
|
|
1554
|
+
function useInnermostKeymap() {
|
|
1555
|
+
const deps = useOptionalDepRegistry();
|
|
1556
|
+
const subscribe = useCallback((notify) => {
|
|
1557
|
+
if (!deps) return () => {
|
|
1558
|
+
};
|
|
1559
|
+
let leaveStack = deps.get("keymaps")?.subscribe(notify);
|
|
1560
|
+
const leaveDeps = deps.subscribe?.(() => {
|
|
1561
|
+
leaveStack?.();
|
|
1562
|
+
leaveStack = deps.get("keymaps")?.subscribe(notify);
|
|
1563
|
+
notify();
|
|
1564
|
+
});
|
|
1565
|
+
return () => {
|
|
1566
|
+
leaveStack?.();
|
|
1567
|
+
leaveDeps?.();
|
|
1568
|
+
};
|
|
1569
|
+
}, [deps]);
|
|
1570
|
+
return useSyncExternalStore(subscribe, () => deps?.get("keymaps")?.innermost() ?? null);
|
|
1571
|
+
}
|
|
1572
|
+
|
|
1573
|
+
// src/keymaps/useOpenKeymap.ts
|
|
1574
|
+
function useOpenKeymap() {
|
|
1575
|
+
const registry = useActionsRegistry();
|
|
1576
|
+
const open = useInnermostKeymap();
|
|
1577
|
+
return useMemo(
|
|
1578
|
+
() => open ? describeKeymap(open, registry?.list() ?? [], registry?.bindingOverrides()) : null,
|
|
1579
|
+
[open, registry]
|
|
1580
|
+
);
|
|
1581
|
+
}
|
|
1450
1582
|
function samePos(a, b) {
|
|
1451
1583
|
if (a === null || b === null) return a === b;
|
|
1452
1584
|
return a.worldX === b.worldX && a.worldY === b.worldY && a.viewId === b.viewId;
|
|
@@ -1537,7 +1669,7 @@ function usePublishSelection(ids, kinds) {
|
|
|
1537
1669
|
}
|
|
1538
1670
|
}, [ctxRef, serializedRef]);
|
|
1539
1671
|
}
|
|
1540
|
-
var
|
|
1672
|
+
var NO_SUBSCRIBE2 = () => () => {
|
|
1541
1673
|
};
|
|
1542
1674
|
function useContributions(opts) {
|
|
1543
1675
|
const ctx = useActiveToolContext();
|
|
@@ -1559,16 +1691,18 @@ function useContributions(opts) {
|
|
|
1559
1691
|
}, [ctx]);
|
|
1560
1692
|
const modes = opts.modes;
|
|
1561
1693
|
const modeVersion = useSyncExternalStore(
|
|
1562
|
-
modes ? modes.subscribe :
|
|
1694
|
+
modes ? modes.subscribe : NO_SUBSCRIBE2,
|
|
1563
1695
|
() => modes?.getVersion() ?? 0
|
|
1564
1696
|
);
|
|
1697
|
+
const openKeymap = useInnermostKeymap()?.id ?? null;
|
|
1565
1698
|
const snapshot = useCallback(() => assembleEntries(entries, {
|
|
1566
1699
|
focusedId: focused,
|
|
1567
1700
|
hotkeyStack: engaged,
|
|
1701
|
+
openKeymap,
|
|
1568
1702
|
...modes ? { allowedCapabilities: activeModeOf(modes.current()).allowedCapabilities } : {}
|
|
1569
1703
|
// The version is what changes; `modes` is one object for the registry's life.
|
|
1570
1704
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
1571
|
-
}), [entries, focused, engaged, modes, modeVersion]);
|
|
1705
|
+
}), [entries, focused, engaged, openKeymap, modes, modeVersion]);
|
|
1572
1706
|
const overlays = useCallback((position = "top") => {
|
|
1573
1707
|
const { ordered, state } = snapshot();
|
|
1574
1708
|
const active = [];
|
|
@@ -1591,21 +1725,28 @@ function useContributions(opts) {
|
|
|
1591
1725
|
const modesRegistry = opts.modes;
|
|
1592
1726
|
useEffect(() => {
|
|
1593
1727
|
if (!isDev()) return;
|
|
1594
|
-
const
|
|
1595
|
-
|
|
1596
|
-
|
|
1597
|
-
|
|
1598
|
-
|
|
1599
|
-
|
|
1600
|
-
|
|
1601
|
-
|
|
1602
|
-
|
|
1603
|
-
|
|
1604
|
-
|
|
1605
|
-
|
|
1606
|
-
|
|
1607
|
-
|
|
1608
|
-
|
|
1728
|
+
const check = () => {
|
|
1729
|
+
const overrides = actionsRegistry?.bindingOverrides() ?? NO_OVERRIDES;
|
|
1730
|
+
const sig = `${entrySig}|${JSON.stringify([...overrides])}`;
|
|
1731
|
+
const last = lastConflictSigRef.current;
|
|
1732
|
+
if (last?.sig === sig && last.modes === modesRegistry) return;
|
|
1733
|
+
lastConflictSigRef.current = { sig, modes: modesRegistry };
|
|
1734
|
+
const registry = [];
|
|
1735
|
+
const ambient = [];
|
|
1736
|
+
for (const entry of entries) {
|
|
1737
|
+
if (entry.eligibility?.focus) registry.push(entry);
|
|
1738
|
+
if (entry.eligibility?.always || entry.eligibility?.claimed) ambient.push(entry);
|
|
1739
|
+
}
|
|
1740
|
+
reportRouteConflicts({
|
|
1741
|
+
registry,
|
|
1742
|
+
ambient,
|
|
1743
|
+
actions: actionsRegistry?.list() ?? [],
|
|
1744
|
+
overrides,
|
|
1745
|
+
...modesRegistry ? { modes: modesRegistry.list().map(activeModeOf) } : {}
|
|
1746
|
+
});
|
|
1747
|
+
};
|
|
1748
|
+
check();
|
|
1749
|
+
return actionsRegistry?.subscribe(check);
|
|
1609
1750
|
}, [entrySig, entries, actionsRegistry, modesRegistry]);
|
|
1610
1751
|
return useMemo(
|
|
1611
1752
|
() => ({ entries, focused, setFocused, overlays }),
|
|
@@ -1726,6 +1867,6 @@ function useTools(opts) {
|
|
|
1726
1867
|
);
|
|
1727
1868
|
}
|
|
1728
1869
|
|
|
1729
|
-
export { ActionsProvider, ActiveToolContextProvider, ActiveToolContextProviderIfRoot, DepRegistryProvider, InputScope, PointerContextProvider, SelectionContextProvider, SelectionContextProviderIfRoot, Yoke, createPointerStore, useAction, useActionsRegistry, useActiveToolContext, useCommand, useContributions, useDepRegistry, useDepSource, useGestureDispatcher, useMenuHost, useMenus, useOffhandAction, useOngoingAction, useOptionalActiveToolContext, useOptionalDepRegistry, usePointerContext, usePointerPosition, usePublishSelection, useSelectionContext, useTools, useYoke };
|
|
1870
|
+
export { ActionsProvider, ActiveToolContextProvider, ActiveToolContextProviderIfRoot, DepRegistryProvider, InputScope, PointerContextProvider, SelectionContextProvider, SelectionContextProviderIfRoot, Yoke, createPointerStore, useAction, useActionsRegistry, useActiveToolContext, useCommand, useContributions, useDepRegistry, useDepSource, useGestureDispatcher, useMenuHost, useMenus, useOffhandAction, useOngoingAction, useOpenKeymap, useOptionalActiveToolContext, useOptionalDepRegistry, usePointerContext, usePointerPosition, usePublishSelection, useSelectionContext, useTools, useYoke };
|
|
1730
1871
|
//# sourceMappingURL=react.js.map
|
|
1731
1872
|
//# sourceMappingURL=react.js.map
|