@weasel-js/routing 1.10.0 → 1.10.1
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-4DR6AJMN.js → chunk-VCEIQ64H.js} +53 -6
- package/dist/chunk-VCEIQ64H.js.map +1 -0
- package/dist/{index-Bm2QEV09.d.ts → index-DkOqUxow.d.ts} +86 -6
- package/dist/index.d.ts +1 -1
- package/dist/index.js +5 -3
- package/dist/index.js.map +1 -1
- package/dist/{internal-D0rDmi7t.d.ts → internal-Boc2I3zn.d.ts} +1 -1
- package/dist/internal.d.ts +3 -3
- package/dist/react.d.ts +8 -4
- package/dist/react.js +151 -77
- package/dist/react.js.map +1 -1
- package/package.json +9 -9
- package/dist/chunk-4DR6AJMN.js.map +0 -1
package/dist/react.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { createDepRegistry, createDispatcher, assembleEntries, liveScope, isDev, reportRouteConflicts, offhandKeyFor, makeToolOffhandAction, buildToolOffhandBindings, dlog, ScopeNode, isTool,
|
|
1
|
+
import { createDepRegistry, createDispatcher, assembleEntries, liveScope, isDev, reportRouteConflicts, offhandKeyFor, makeToolOffhandAction, buildToolOffhandBindings, dlog, ScopeNode, isTool, tuneAction, pushOwner, evaluateEnabled, validateActionId, validateActionDefaultBinding, depNodeOf, DepNode, clientToCanvas, DEV, publishLiveDispatch, LONG_PRESS_HAPTIC_MS, multiTouchGestureId, openPointerSession, buildDepsFromRequires, isEditableTarget, focusedControlOwnsKey, itemsFromClipboardData, itemsFromDataTransfer, itemTypesFromDataTransfer } from './chunk-VCEIQ64H.js';
|
|
2
2
|
import { createContext, useState, useContext, useEffect, useRef, useCallback, useMemo, useSyncExternalStore } from 'react';
|
|
3
|
-
import { isApplePlatform, createPointerRecognizer, isInControlWithin, longPressEvents, stylusOf } from '@weasel-js/gestures';
|
|
3
|
+
import { isApplePlatform, heldPointers, createPointerRecognizer, isInControlWithin, longPressEvents, stylusOf } from '@weasel-js/gestures';
|
|
4
4
|
import { useLatest, useStableByContent, sameList } from '@weasel-js/react';
|
|
5
5
|
import { jsx, Fragment } from 'react/jsx-runtime';
|
|
6
6
|
import { createCursorSink, resolveCursorTier } from '@weasel-js/cursor';
|
|
@@ -133,7 +133,7 @@ function useToolLifecycle(opts) {
|
|
|
133
133
|
const next = new Set(active === null ? hotkeyStack : [active, ...hotkeyStack]);
|
|
134
134
|
liveRef.current = next;
|
|
135
135
|
for (const id of prev) if (!next.has(id)) fire(id, "onDeactivate");
|
|
136
|
-
if (prevActiveRef.current !== active) onSwitchRef.current?.();
|
|
136
|
+
if (prevActiveRef.current !== null && prevActiveRef.current !== active) onSwitchRef.current?.();
|
|
137
137
|
prevActiveRef.current = active;
|
|
138
138
|
for (const id of next) if (!prev.has(id)) fire(id, "onActivate");
|
|
139
139
|
});
|
|
@@ -268,6 +268,11 @@ function contextMenuInput(core, takeNativeHold) {
|
|
|
268
268
|
};
|
|
269
269
|
return onContextMenu;
|
|
270
270
|
}
|
|
271
|
+
var whereOf = ({ affordance, bodyTarget, bodyKind }) => ({
|
|
272
|
+
...affordance !== void 0 ? { affordance } : {},
|
|
273
|
+
...bodyTarget !== void 0 ? { bodyTarget } : {},
|
|
274
|
+
...bodyKind !== void 0 ? { bodyKind } : {}
|
|
275
|
+
});
|
|
271
276
|
var hoverOf = (e) => ({
|
|
272
277
|
clientX: e.clientX,
|
|
273
278
|
clientY: e.clientY,
|
|
@@ -325,8 +330,9 @@ function hoverCursorInput(core, paintedCursor, pointersHeld, cursorSink = () =>
|
|
|
325
330
|
if (pointersHeld() === 0) {
|
|
326
331
|
const w = toWorld(e.clientX, e.clientY);
|
|
327
332
|
const where = underPointer(target(), last, w);
|
|
333
|
+
const from = facts ? { from: whereOf(facts.where) } : {};
|
|
328
334
|
facts = { at: last, where };
|
|
329
|
-
dispatch({ kind: "hover", x: w.x, y: w.y, clientX: e.clientX, clientY: e.clientY, ...where });
|
|
335
|
+
dispatch({ kind: "hover", x: w.x, y: w.y, clientX: e.clientX, clientY: e.clientY, ...where, ...from });
|
|
330
336
|
}
|
|
331
337
|
refresh();
|
|
332
338
|
},
|
|
@@ -335,6 +341,12 @@ function hoverCursorInput(core, paintedCursor, pointersHeld, cursorSink = () =>
|
|
|
335
341
|
refreshSoon();
|
|
336
342
|
},
|
|
337
343
|
onLeave() {
|
|
344
|
+
if (facts) {
|
|
345
|
+
const { at, where } = facts;
|
|
346
|
+
const w = toWorld(at.clientX, at.clientY);
|
|
347
|
+
dispatch({ kind: "hover", off: true, x: w.x, y: w.y, clientX: at.clientX, clientY: at.clientY, ...where, from: whereOf(where) });
|
|
348
|
+
}
|
|
349
|
+
facts = null;
|
|
338
350
|
last = null;
|
|
339
351
|
if (DEV) publishLiveDispatch(null);
|
|
340
352
|
paintedCursor()?.clearPointer();
|
|
@@ -678,7 +690,6 @@ function pointerInput(core, opts) {
|
|
|
678
690
|
hold.routeToPress();
|
|
679
691
|
return recognizer.takeHold();
|
|
680
692
|
},
|
|
681
|
-
heldCount: () => recognizer.heldCount(),
|
|
682
693
|
cancelHeld() {
|
|
683
694
|
for (const session of [...sessions.values()]) session.cancel();
|
|
684
695
|
},
|
|
@@ -783,6 +794,88 @@ function wheelInput(core, pinchLive) {
|
|
|
783
794
|
return onWheel;
|
|
784
795
|
}
|
|
785
796
|
|
|
797
|
+
// src/interactions/dispatcher/attachInput.ts
|
|
798
|
+
function attachInput(canvas, src, channels) {
|
|
799
|
+
let disposed = false;
|
|
800
|
+
const redraw = dispatcherWatch(src.requestRedraw);
|
|
801
|
+
redraw.sync(src.dispatchers());
|
|
802
|
+
const core = createDispatchCore({
|
|
803
|
+
canvas,
|
|
804
|
+
root: src.root,
|
|
805
|
+
views: src.views,
|
|
806
|
+
context: src.context,
|
|
807
|
+
actions: src.actions,
|
|
808
|
+
uses: () => {
|
|
809
|
+
redraw.sync(src.dispatchers());
|
|
810
|
+
},
|
|
811
|
+
disposed: () => disposed
|
|
812
|
+
});
|
|
813
|
+
const keys = keyboardInput(core);
|
|
814
|
+
const pinch = webkitPinchInput(core);
|
|
815
|
+
const ingest = ingestInput(core);
|
|
816
|
+
const held = canvas ? heldPointers(canvas) : null;
|
|
817
|
+
const hover = hoverCursorInput(core, src.paintedCursor, () => held?.count() ?? 0, src.cursorSink);
|
|
818
|
+
const pointer = pointerInput(core, {
|
|
819
|
+
longPress: src.longPress,
|
|
820
|
+
onClick: src.onClick,
|
|
821
|
+
onDoubleClick: src.onDoubleClick,
|
|
822
|
+
clicks: src.clicks,
|
|
823
|
+
hover
|
|
824
|
+
});
|
|
825
|
+
const onWindowBlur = () => {
|
|
826
|
+
pinch.end();
|
|
827
|
+
pointer.cancelHeld();
|
|
828
|
+
keys.releaseAll();
|
|
829
|
+
};
|
|
830
|
+
const listeners = listenerSet();
|
|
831
|
+
const keyCapture = channels.keyboard === "first";
|
|
832
|
+
if (channels.keyboard) {
|
|
833
|
+
listeners.on(window, "keydown", keys.onKeyDown, keyCapture);
|
|
834
|
+
listeners.on(window, "keyup", keys.onKeyUp, keyCapture);
|
|
835
|
+
}
|
|
836
|
+
listeners.on(window, "blur", onWindowBlur);
|
|
837
|
+
listeners.on(canvas, "pointerdown", () => {
|
|
838
|
+
src.actions().activate();
|
|
839
|
+
});
|
|
840
|
+
if (channels.pointer) {
|
|
841
|
+
listeners.on(window, "keydown", hover.onKey);
|
|
842
|
+
listeners.on(window, "keyup", hover.onKey);
|
|
843
|
+
listeners.on(canvas, "pointerleave", hover.onLeave);
|
|
844
|
+
listeners.on(canvas, "pointerdown", pointer.onPointerDown);
|
|
845
|
+
listeners.on(canvas, "pointermove", pointer.onHoverMove);
|
|
846
|
+
listeners.on(canvas, "dblclick", pointer.onNativeDoubleClick);
|
|
847
|
+
}
|
|
848
|
+
if (channels.wheel) {
|
|
849
|
+
listeners.on(canvas, "wheel", wheelInput(core, pinch.live), { passive: false, capture: true });
|
|
850
|
+
}
|
|
851
|
+
if (channels.pinch) {
|
|
852
|
+
listeners.on(canvas, "gesturestart", pinch.onGestureStart);
|
|
853
|
+
listeners.on(canvas, "gesturechange", pinch.onGestureChange);
|
|
854
|
+
listeners.on(canvas, "gestureend", pinch.onGestureEnd);
|
|
855
|
+
}
|
|
856
|
+
if (channels.contextMenu) {
|
|
857
|
+
listeners.on(canvas, "contextmenu", contextMenuInput(core, pointer.takeNativeHold));
|
|
858
|
+
}
|
|
859
|
+
if (channels.ingest) {
|
|
860
|
+
listeners.on(canvas, "dragenter", ingest.onDragOver);
|
|
861
|
+
listeners.on(canvas, "dragover", ingest.onDragOver);
|
|
862
|
+
listeners.on(canvas, "dragleave", ingest.onDragLeave);
|
|
863
|
+
listeners.on(canvas, "drop", ingest.onDrop);
|
|
864
|
+
listeners.on(window, "paste", ingest.onPaste);
|
|
865
|
+
}
|
|
866
|
+
return () => {
|
|
867
|
+
listeners.removeAll();
|
|
868
|
+
canvas?.classList.remove(DROPOVER_CLASS);
|
|
869
|
+
src.actions().dropKeys();
|
|
870
|
+
hover.clear();
|
|
871
|
+
disposed = true;
|
|
872
|
+
pointer.dispose();
|
|
873
|
+
held?.release();
|
|
874
|
+
redraw.stop();
|
|
875
|
+
for (const d of src.dispatchers()) d.cancelAll("cancel");
|
|
876
|
+
};
|
|
877
|
+
}
|
|
878
|
+
|
|
786
879
|
// src/interactions/dispatcher/useGestureDispatcher.tsx
|
|
787
880
|
function useGestureDispatcher(opts) {
|
|
788
881
|
const { canvasRef, actions, entriesById, enabled = true, keyboard = true, affordanceAt, classifyTarget, dispatcher: dispatcherOpt, clientToWorld, requestRedraw, paintedCursor, cursorSink, getRuleCtx, onClick, onDoubleClick, views, channels, longPress, claimKeys = false } = opts;
|
|
@@ -840,85 +933,29 @@ function useGestureDispatcher(opts) {
|
|
|
840
933
|
}, [enabled, claimKeys, registryRef]);
|
|
841
934
|
useEffect(() => {
|
|
842
935
|
if (!enabled) return;
|
|
843
|
-
|
|
844
|
-
const canvas = canvasRef.current;
|
|
845
|
-
const redraw = dispatcherWatch(() => {
|
|
846
|
-
requestRedrawRef.current?.();
|
|
847
|
-
});
|
|
848
|
-
redraw.sync(allDispatchers());
|
|
849
|
-
const core = createDispatchCore({
|
|
850
|
-
canvas,
|
|
936
|
+
return attachInput(canvasRef.current, {
|
|
851
937
|
root: () => rootTargetRef.current,
|
|
852
938
|
views: () => viewsRef.current,
|
|
853
939
|
context: () => ctxRef.current,
|
|
854
940
|
actions: () => registryRef.current,
|
|
855
|
-
|
|
856
|
-
|
|
941
|
+
dispatchers: allDispatchers,
|
|
942
|
+
requestRedraw: () => {
|
|
943
|
+
requestRedrawRef.current?.();
|
|
857
944
|
},
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
const keys = keyboardInput(core);
|
|
861
|
-
const pinch = webkitPinchInput(core);
|
|
862
|
-
const ingest = ingestInput(core);
|
|
863
|
-
const hover = hoverCursorInput(core, () => cursorRef.current.painted?.(), () => pointer.heldCount(), () => cursorRef.current.sink?.());
|
|
864
|
-
const pointer = pointerInput(core, {
|
|
945
|
+
paintedCursor: () => cursorRef.current.painted?.(),
|
|
946
|
+
cursorSink: () => cursorRef.current.sink?.(),
|
|
865
947
|
longPress: () => longPressRef.current,
|
|
866
948
|
onClick: () => onClickRef.current,
|
|
867
949
|
onDoubleClick: () => onDoubleClickRef.current,
|
|
868
|
-
clicks: clicksRef.current
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
const listeners = listenerSet();
|
|
877
|
-
const keyCapture = keyboard === "first";
|
|
878
|
-
if (keyboard) {
|
|
879
|
-
listeners.on(window, "keydown", keys.onKeyDown, keyCapture);
|
|
880
|
-
listeners.on(window, "keyup", keys.onKeyUp, keyCapture);
|
|
881
|
-
}
|
|
882
|
-
listeners.on(window, "blur", onWindowBlur);
|
|
883
|
-
listeners.on(canvas, "pointerdown", () => {
|
|
884
|
-
registryRef.current.activate();
|
|
950
|
+
clicks: clicksRef.current
|
|
951
|
+
}, {
|
|
952
|
+
keyboard,
|
|
953
|
+
pointer: pointerChannel,
|
|
954
|
+
wheel: wheelChannel,
|
|
955
|
+
pinch: pinchChannel,
|
|
956
|
+
contextMenu: contextMenuChannel,
|
|
957
|
+
ingest: ingestChannel
|
|
885
958
|
});
|
|
886
|
-
if (pointerChannel) {
|
|
887
|
-
listeners.on(window, "keydown", hover.onKey);
|
|
888
|
-
listeners.on(window, "keyup", hover.onKey);
|
|
889
|
-
listeners.on(canvas, "pointerleave", hover.onLeave);
|
|
890
|
-
listeners.on(canvas, "pointerdown", pointer.onPointerDown);
|
|
891
|
-
listeners.on(canvas, "pointermove", pointer.onHoverMove);
|
|
892
|
-
listeners.on(canvas, "dblclick", pointer.onNativeDoubleClick);
|
|
893
|
-
}
|
|
894
|
-
if (wheelChannel) {
|
|
895
|
-
listeners.on(canvas, "wheel", wheelInput(core, pinch.live), { passive: false, capture: true });
|
|
896
|
-
}
|
|
897
|
-
if (pinchChannel) {
|
|
898
|
-
listeners.on(canvas, "gesturestart", pinch.onGestureStart);
|
|
899
|
-
listeners.on(canvas, "gesturechange", pinch.onGestureChange);
|
|
900
|
-
listeners.on(canvas, "gestureend", pinch.onGestureEnd);
|
|
901
|
-
}
|
|
902
|
-
if (contextMenuChannel) {
|
|
903
|
-
listeners.on(canvas, "contextmenu", contextMenuInput(core, pointer.takeNativeHold));
|
|
904
|
-
}
|
|
905
|
-
if (ingestChannel) {
|
|
906
|
-
listeners.on(canvas, "dragenter", ingest.onDragOver);
|
|
907
|
-
listeners.on(canvas, "dragover", ingest.onDragOver);
|
|
908
|
-
listeners.on(canvas, "dragleave", ingest.onDragLeave);
|
|
909
|
-
listeners.on(canvas, "drop", ingest.onDrop);
|
|
910
|
-
listeners.on(window, "paste", ingest.onPaste);
|
|
911
|
-
}
|
|
912
|
-
return () => {
|
|
913
|
-
listeners.removeAll();
|
|
914
|
-
canvas?.classList.remove(DROPOVER_CLASS);
|
|
915
|
-
registryRef.current.dropKeys();
|
|
916
|
-
hover.clear();
|
|
917
|
-
disposed = true;
|
|
918
|
-
pointer.dispose();
|
|
919
|
-
redraw.stop();
|
|
920
|
-
for (const d of allDispatchers()) d.cancelAll("cancel");
|
|
921
|
-
};
|
|
922
959
|
}, [
|
|
923
960
|
enabled,
|
|
924
961
|
keyboard,
|
|
@@ -962,6 +999,7 @@ var ActionsNode = class extends ScopeNode {
|
|
|
962
999
|
contextDeps;
|
|
963
1000
|
actions = /* @__PURE__ */ new Map();
|
|
964
1001
|
muted = /* @__PURE__ */ new Map();
|
|
1002
|
+
tunings = /* @__PURE__ */ new Map();
|
|
965
1003
|
dispatchers = [];
|
|
966
1004
|
cache = null;
|
|
967
1005
|
/** Called on `activate`, so a scope's dep and tool nodes move with it. */
|
|
@@ -970,10 +1008,19 @@ var ActionsNode = class extends ScopeNode {
|
|
|
970
1008
|
for (const n of this.chain()) {
|
|
971
1009
|
if (n.muted.has(id)) return void 0;
|
|
972
1010
|
const a = n.actions.get(id)?.at(-1);
|
|
973
|
-
if (a) return a;
|
|
1011
|
+
if (a) return this.tuned(a);
|
|
974
1012
|
}
|
|
975
1013
|
return void 0;
|
|
976
1014
|
}
|
|
1015
|
+
/** `a` under every tuning for its id from the root down to here. */
|
|
1016
|
+
tuned(a) {
|
|
1017
|
+
const tunings = [];
|
|
1018
|
+
for (const n of this.chain()) {
|
|
1019
|
+
const stack = n.tunings.get(a.id);
|
|
1020
|
+
if (stack) tunings.unshift(...stack);
|
|
1021
|
+
}
|
|
1022
|
+
return tunings.length ? tuneAction(a, tunings) : a;
|
|
1023
|
+
}
|
|
977
1024
|
snapshot() {
|
|
978
1025
|
const leaf = this.start();
|
|
979
1026
|
const cached = this.cache;
|
|
@@ -1050,6 +1097,20 @@ var ActionsNode = class extends ScopeNode {
|
|
|
1050
1097
|
this.changed();
|
|
1051
1098
|
};
|
|
1052
1099
|
},
|
|
1100
|
+
tune: (id, tuning) => {
|
|
1101
|
+
let stack = this.tunings.get(id);
|
|
1102
|
+
if (!stack) this.tunings.set(id, stack = []);
|
|
1103
|
+
const release = pushOwner(stack, tuning);
|
|
1104
|
+
this.changed();
|
|
1105
|
+
let released = false;
|
|
1106
|
+
return () => {
|
|
1107
|
+
if (released) return;
|
|
1108
|
+
released = true;
|
|
1109
|
+
release();
|
|
1110
|
+
if (stack.length === 0) this.tunings.delete(id);
|
|
1111
|
+
this.changed();
|
|
1112
|
+
};
|
|
1113
|
+
},
|
|
1053
1114
|
list: () => this.snapshot(),
|
|
1054
1115
|
trigger: (id, params) => {
|
|
1055
1116
|
const leaf = this.start();
|
|
@@ -1177,7 +1238,20 @@ function useOngoingAction(actionId) {
|
|
|
1177
1238
|
}
|
|
1178
1239
|
};
|
|
1179
1240
|
}, [regRef, idRef]);
|
|
1180
|
-
|
|
1241
|
+
const leaving = useRef(null);
|
|
1242
|
+
useEffect(() => {
|
|
1243
|
+
const left = leaving.current;
|
|
1244
|
+
leaving.current = null;
|
|
1245
|
+
if (left !== null && left !== actionId) edit.commit();
|
|
1246
|
+
return () => {
|
|
1247
|
+
leaving.current = actionId;
|
|
1248
|
+
queueMicrotask(() => {
|
|
1249
|
+
if (leaving.current !== actionId) return;
|
|
1250
|
+
leaving.current = null;
|
|
1251
|
+
edit.commit();
|
|
1252
|
+
});
|
|
1253
|
+
};
|
|
1254
|
+
}, [edit, actionId]);
|
|
1181
1255
|
return edit;
|
|
1182
1256
|
}
|
|
1183
1257
|
function samePos(a, b) {
|