@weasel-js/routing 1.10.1 → 1.11.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-VCEIQ64H.js → chunk-QBQQIFPI.js} +580 -51
- package/dist/chunk-QBQQIFPI.js.map +1 -0
- package/dist/{index-DkOqUxow.d.ts → index-CmfVvwWD.d.ts} +645 -279
- package/dist/index.d.ts +6 -3
- package/dist/index.js +54 -17
- package/dist/index.js.map +1 -1
- package/dist/{internal-Boc2I3zn.d.ts → internal-21M1rTVo.d.ts} +23 -1
- package/dist/internal.d.ts +8 -5
- package/dist/react.d.ts +59 -27
- package/dist/react.js +413 -220
- package/dist/react.js.map +1 -1
- package/package.json +13 -9
- package/dist/chunk-VCEIQ64H.js.map +0 -1
package/dist/react.js
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import { createDepRegistry, createDispatcher, assembleEntries, liveScope,
|
|
2
|
-
import { createContext, useState, useContext, useEffect, useRef, useCallback,
|
|
1
|
+
import { createDepRegistry, createDispatcher, assembleEntries, liveScope, reportRouteConflicts, offhandKeyFor, makeToolOffhandAction, buildToolOffhandBindings, dlog, ScopeNode, tuneAction, createMenuHost, pushOwner, evaluateEnabled, tunedParams, validateActionId, validateActionDefaultBinding, isTool, depNodeOf, DepNode, buildDepsFromRequires, clientToCanvas, DEV, publishLiveDispatch, LONG_PRESS_HAPTIC_MS, multiTouchGestureId, openPointerSession, addCarrySurface, gestureIdFor, isEditableTarget, focusedControlOwnsKey, itemsFromClipboardData, itemsFromDataTransfer, itemTypesFromDataTransfer, actionCursor } from './chunk-QBQQIFPI.js';
|
|
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
|
-
import { useLatest, useStableByContent, sameList } from '@weasel-js/react';
|
|
4
|
+
import { isDev, useLatest, useKitSettings, useStableByContent, sameList } from '@weasel-js/react';
|
|
5
5
|
import { jsx, Fragment } from 'react/jsx-runtime';
|
|
6
6
|
import { createCursorSink, resolveCursorTier } from '@weasel-js/cursor';
|
|
7
|
-
import { createEmitter } from '@weasel-js/registry';
|
|
7
|
+
import { deepEqual, createEmitter } from '@weasel-js/registry';
|
|
8
8
|
import { activeModeOf } from '@weasel-js/modes';
|
|
9
9
|
|
|
10
10
|
var ToolNode = class extends ScopeNode {
|
|
@@ -111,6 +111,277 @@ function useDepSource(name, source) {
|
|
|
111
111
|
return registry.register(name, () => sourceRef.current());
|
|
112
112
|
}, [name, registry, sourceRef]);
|
|
113
113
|
}
|
|
114
|
+
var MenuHostContext = createContext(null);
|
|
115
|
+
function useMenuHost() {
|
|
116
|
+
return useContext(MenuHostContext);
|
|
117
|
+
}
|
|
118
|
+
function useMenus(defs, owner = null) {
|
|
119
|
+
const host = useMenuHost();
|
|
120
|
+
useEffect(() => {
|
|
121
|
+
if (!host) return;
|
|
122
|
+
const releases = defs.map((d) => host.define(d, owner));
|
|
123
|
+
return () => {
|
|
124
|
+
for (const r of releases) r();
|
|
125
|
+
};
|
|
126
|
+
}, [host, defs, owner]);
|
|
127
|
+
}
|
|
128
|
+
var ActionsContext = createContext(null);
|
|
129
|
+
function depsFor(a, r) {
|
|
130
|
+
if (!r) return {};
|
|
131
|
+
if (a.requires) return buildDepsFromRequires(a, r);
|
|
132
|
+
return {
|
|
133
|
+
selection: r.get("selection"),
|
|
134
|
+
scene: r.get("scene"),
|
|
135
|
+
history: r.get("history"),
|
|
136
|
+
view: r.get("view"),
|
|
137
|
+
activeTool: r.get("activeTool"),
|
|
138
|
+
booleansAdapter: r.get("booleansAdapter")
|
|
139
|
+
};
|
|
140
|
+
}
|
|
141
|
+
var ActionsNode = class extends ScopeNode {
|
|
142
|
+
constructor(parent, descends, contextDeps) {
|
|
143
|
+
super(parent, descends);
|
|
144
|
+
this.contextDeps = contextDeps;
|
|
145
|
+
NODES.set(this.registry, this);
|
|
146
|
+
}
|
|
147
|
+
contextDeps;
|
|
148
|
+
actions = /* @__PURE__ */ new Map();
|
|
149
|
+
muted = /* @__PURE__ */ new Map();
|
|
150
|
+
tunings = /* @__PURE__ */ new Map();
|
|
151
|
+
dispatchers = [];
|
|
152
|
+
cache = null;
|
|
153
|
+
host = null;
|
|
154
|
+
/** Called on `activate`, so a scope's dep and tool nodes move with it. */
|
|
155
|
+
onActivate = [];
|
|
156
|
+
resolve(id) {
|
|
157
|
+
for (const n of this.chain()) {
|
|
158
|
+
if (n.muted.has(id)) return void 0;
|
|
159
|
+
const a = n.actions.get(id)?.at(-1);
|
|
160
|
+
if (a) return this.tuned(a);
|
|
161
|
+
}
|
|
162
|
+
return void 0;
|
|
163
|
+
}
|
|
164
|
+
/** Every tuning for `id` from the root down to here, root first. */
|
|
165
|
+
tuningsOf(id) {
|
|
166
|
+
const tunings = [];
|
|
167
|
+
for (const n of this.chain()) {
|
|
168
|
+
const stack = n.tunings.get(id);
|
|
169
|
+
if (stack) tunings.unshift(...stack);
|
|
170
|
+
}
|
|
171
|
+
return tunings;
|
|
172
|
+
}
|
|
173
|
+
/** `a` under every tuning for its id from the root down to here. */
|
|
174
|
+
tuned(a) {
|
|
175
|
+
const tunings = this.tuningsOf(a.id);
|
|
176
|
+
return tunings.length ? tuneAction(a, tunings) : a;
|
|
177
|
+
}
|
|
178
|
+
snapshot() {
|
|
179
|
+
const leaf = this.start();
|
|
180
|
+
const cached = this.cache;
|
|
181
|
+
if (cached && cached.version === this.tree.version && cached.leaf === leaf) return cached.list;
|
|
182
|
+
const ids = /* @__PURE__ */ new Set();
|
|
183
|
+
for (const n of leaf.chain()) for (const id of n.actions.keys()) ids.add(id);
|
|
184
|
+
const out = [];
|
|
185
|
+
for (const id of ids) {
|
|
186
|
+
const a = leaf.resolve(id);
|
|
187
|
+
if (a) out.push(a);
|
|
188
|
+
}
|
|
189
|
+
const list = Object.freeze(out);
|
|
190
|
+
this.cache = { version: this.tree.version, leaf, list };
|
|
191
|
+
return list;
|
|
192
|
+
}
|
|
193
|
+
deps() {
|
|
194
|
+
for (const n of this.chain()) {
|
|
195
|
+
const r = n.contextDeps();
|
|
196
|
+
if (r) return r;
|
|
197
|
+
}
|
|
198
|
+
return null;
|
|
199
|
+
}
|
|
200
|
+
/** The actions registered at this node itself, live, unmuted and tuned —
|
|
201
|
+
* none from the scopes below it. */
|
|
202
|
+
ownActions() {
|
|
203
|
+
const out = [];
|
|
204
|
+
for (const [id, stack] of this.actions) {
|
|
205
|
+
if (stack.length > 0 && !this.muted.has(id)) out.push(this.tuned(stack.at(-1)));
|
|
206
|
+
}
|
|
207
|
+
return out;
|
|
208
|
+
}
|
|
209
|
+
/** The deps `a` is invoked with from here: the active scope's, which is
|
|
210
|
+
* what `trigger` and `begin` run it with. */
|
|
211
|
+
depsOf(a) {
|
|
212
|
+
return depsFor(a, this.start().deps());
|
|
213
|
+
}
|
|
214
|
+
/** The menu host of this node's tree, made by its root on first ask. Rows
|
|
215
|
+
* resolve and run against the active scope, as chrome's `trigger` does. */
|
|
216
|
+
menuHost() {
|
|
217
|
+
const root = [...this.chain()].at(-1);
|
|
218
|
+
return root.host ??= createMenuHost({
|
|
219
|
+
actions: () => root.registry.list(),
|
|
220
|
+
depsFor: (a) => root.depsOf(a),
|
|
221
|
+
trigger: (id, params) => root.registry.trigger(id, params),
|
|
222
|
+
activeTool: () => root.start().deps()?.get("activeTool")?.active ?? null
|
|
223
|
+
});
|
|
224
|
+
}
|
|
225
|
+
dispatcher() {
|
|
226
|
+
for (const n of this.chain()) {
|
|
227
|
+
const d = n.dispatchers.at(-1);
|
|
228
|
+
if (d) return d;
|
|
229
|
+
}
|
|
230
|
+
return null;
|
|
231
|
+
}
|
|
232
|
+
activate() {
|
|
233
|
+
keyHolder = this;
|
|
234
|
+
super.activate();
|
|
235
|
+
for (const f of this.onActivate) f();
|
|
236
|
+
}
|
|
237
|
+
registry = {
|
|
238
|
+
register: (action) => {
|
|
239
|
+
validateActionId(action.id);
|
|
240
|
+
validateActionDefaultBinding(action);
|
|
241
|
+
const stack = this.actions.get(action.id);
|
|
242
|
+
if (stack) stack.push(action);
|
|
243
|
+
else this.actions.set(action.id, [action]);
|
|
244
|
+
this.changed();
|
|
245
|
+
let released = false;
|
|
246
|
+
return () => {
|
|
247
|
+
if (released) return;
|
|
248
|
+
released = true;
|
|
249
|
+
const cur = this.actions.get(action.id);
|
|
250
|
+
if (!cur) return;
|
|
251
|
+
const i = cur.lastIndexOf(action);
|
|
252
|
+
if (i === -1) return;
|
|
253
|
+
cur.splice(i, 1);
|
|
254
|
+
if (cur.length === 0) {
|
|
255
|
+
queueMicrotask(() => {
|
|
256
|
+
if (cur.length === 0 && this.actions.get(action.id) === cur) this.actions.delete(action.id);
|
|
257
|
+
});
|
|
258
|
+
}
|
|
259
|
+
this.changed();
|
|
260
|
+
};
|
|
261
|
+
},
|
|
262
|
+
unregister: (id) => {
|
|
263
|
+
if (this.actions.delete(id)) this.changed();
|
|
264
|
+
},
|
|
265
|
+
mute: (id) => {
|
|
266
|
+
this.muted.set(id, (this.muted.get(id) ?? 0) + 1);
|
|
267
|
+
this.changed();
|
|
268
|
+
let released = false;
|
|
269
|
+
return () => {
|
|
270
|
+
if (released) return;
|
|
271
|
+
released = true;
|
|
272
|
+
const held = this.muted.get(id);
|
|
273
|
+
if (held === void 0) return;
|
|
274
|
+
if (held > 1) this.muted.set(id, held - 1);
|
|
275
|
+
else this.muted.delete(id);
|
|
276
|
+
this.changed();
|
|
277
|
+
};
|
|
278
|
+
},
|
|
279
|
+
tune: (id, tuning) => {
|
|
280
|
+
let stack = this.tunings.get(id);
|
|
281
|
+
if (!stack) this.tunings.set(id, stack = []);
|
|
282
|
+
const release = pushOwner(stack, tuning);
|
|
283
|
+
this.changed();
|
|
284
|
+
let released = false;
|
|
285
|
+
return () => {
|
|
286
|
+
if (released) return;
|
|
287
|
+
released = true;
|
|
288
|
+
release();
|
|
289
|
+
if (stack.length === 0) this.tunings.delete(id);
|
|
290
|
+
this.changed();
|
|
291
|
+
};
|
|
292
|
+
},
|
|
293
|
+
paramsOf: (id, given) => tunedParams(this.tuningsOf(id), given),
|
|
294
|
+
list: () => this.snapshot(),
|
|
295
|
+
trigger: (id, params) => {
|
|
296
|
+
const leaf = this.start();
|
|
297
|
+
const a = leaf.resolve(id);
|
|
298
|
+
if (!a?.invoker || a.invoker.timing !== "immediate") return false;
|
|
299
|
+
const deps = leaf.depsOf(a);
|
|
300
|
+
if (!evaluateEnabled(a, deps, pointOf(params)).enabled) return false;
|
|
301
|
+
try {
|
|
302
|
+
a.invoker.run(deps, params);
|
|
303
|
+
} catch (err) {
|
|
304
|
+
console.error(`weasel ActionsRegistry: action "${id}" threw`, err);
|
|
305
|
+
}
|
|
306
|
+
return true;
|
|
307
|
+
},
|
|
308
|
+
preview: (id, params) => {
|
|
309
|
+
const leaf = this.start();
|
|
310
|
+
const a = leaf.resolve(id);
|
|
311
|
+
if (!a?.preview) return NO_PREVIEW;
|
|
312
|
+
const deps = leaf.depsOf(a);
|
|
313
|
+
if (!evaluateEnabled(a, deps, pointOf(params)).enabled) return NO_PREVIEW;
|
|
314
|
+
let stop;
|
|
315
|
+
try {
|
|
316
|
+
stop = a.preview(deps, params);
|
|
317
|
+
} catch (err) {
|
|
318
|
+
console.error(`weasel ActionsRegistry: preview of "${id}" threw`, err);
|
|
319
|
+
return NO_PREVIEW;
|
|
320
|
+
}
|
|
321
|
+
if (typeof stop !== "function") return NO_PREVIEW;
|
|
322
|
+
let down = false;
|
|
323
|
+
return () => {
|
|
324
|
+
if (down) return;
|
|
325
|
+
down = true;
|
|
326
|
+
try {
|
|
327
|
+
stop();
|
|
328
|
+
} catch (err) {
|
|
329
|
+
console.error(`weasel ActionsRegistry: preview of "${id}" threw as it ended`, err);
|
|
330
|
+
}
|
|
331
|
+
};
|
|
332
|
+
},
|
|
333
|
+
subscribe: (listener) => this.tree.listeners.subscribe(listener),
|
|
334
|
+
setDispatcher: (d) => pushOwner(this.dispatchers, d),
|
|
335
|
+
begin: (id, params) => {
|
|
336
|
+
const leaf = this.start();
|
|
337
|
+
const a = leaf.resolve(id);
|
|
338
|
+
const disp = leaf.dispatcher();
|
|
339
|
+
if (!a || !disp) return null;
|
|
340
|
+
return disp.beginUiOngoing(id, leaf.depsOf(a), params);
|
|
341
|
+
},
|
|
342
|
+
activate: () => this.activate(),
|
|
343
|
+
isActive: () => this.isActive(),
|
|
344
|
+
holdsKeys: () => keyHolder === this,
|
|
345
|
+
dropKeys: () => {
|
|
346
|
+
if (keyHolder === this) keyHolder = null;
|
|
347
|
+
}
|
|
348
|
+
};
|
|
349
|
+
};
|
|
350
|
+
var NO_PREVIEW = () => {
|
|
351
|
+
};
|
|
352
|
+
function pointOf(params) {
|
|
353
|
+
const { worldX: x, worldY: y } = params ?? {};
|
|
354
|
+
return typeof x === "number" && typeof y === "number" ? { x, y } : void 0;
|
|
355
|
+
}
|
|
356
|
+
var keyHolder = null;
|
|
357
|
+
var NODES = /* @__PURE__ */ new WeakMap();
|
|
358
|
+
function actionsNodeOf(registry) {
|
|
359
|
+
return registry ? NODES.get(registry) ?? null : null;
|
|
360
|
+
}
|
|
361
|
+
function ActionsProvider({ children }) {
|
|
362
|
+
const depReg = useOptionalDepRegistry();
|
|
363
|
+
const depRegRef = useLatest(depReg);
|
|
364
|
+
const node = useMemo(() => new ActionsNode(null, true, () => depRegRef.current), [depRegRef]);
|
|
365
|
+
return /* @__PURE__ */ jsx(ActionsContext.Provider, { value: node.registry, children: /* @__PURE__ */ jsx(MenuHostContext.Provider, { value: node.menuHost(), children }) });
|
|
366
|
+
}
|
|
367
|
+
var IS_DEV = isDev();
|
|
368
|
+
function useActionsRegistry() {
|
|
369
|
+
return useContext(ActionsContext);
|
|
370
|
+
}
|
|
371
|
+
function useAction(action) {
|
|
372
|
+
const reg = useActionsRegistry();
|
|
373
|
+
useEffect(() => {
|
|
374
|
+
if (!reg) {
|
|
375
|
+
if (IS_DEV) {
|
|
376
|
+
console.warn(
|
|
377
|
+
`useAction("${action.id}"): no <ActionsProvider> is in scope, so the action was not registered and its bindings will never fire.`
|
|
378
|
+
);
|
|
379
|
+
}
|
|
380
|
+
return;
|
|
381
|
+
}
|
|
382
|
+
return reg.register(action);
|
|
383
|
+
}, [reg, action]);
|
|
384
|
+
}
|
|
114
385
|
function useToolLifecycle(opts) {
|
|
115
386
|
const { active, hotkeyStack } = opts;
|
|
116
387
|
const liveRef = useRef(/* @__PURE__ */ new Set());
|
|
@@ -184,6 +455,8 @@ function createDispatchCore(src) {
|
|
|
184
455
|
return fn ? fn(cx, cy) : { x: cx, y: cy };
|
|
185
456
|
},
|
|
186
457
|
toCanvasLocal: (cx, cy) => {
|
|
458
|
+
const own = src.clientToLocal();
|
|
459
|
+
if (own) return own(cx, cy);
|
|
187
460
|
if (!canvas) return { x: cx, y: cy };
|
|
188
461
|
const [x, y] = clientToCanvas(canvas, cx, cy);
|
|
189
462
|
return { x, y };
|
|
@@ -232,6 +505,56 @@ function dispatcherWatch(onChange) {
|
|
|
232
505
|
};
|
|
233
506
|
}
|
|
234
507
|
|
|
508
|
+
// src/interactions/dispatcher/channels/carry.ts
|
|
509
|
+
function carryInput(core) {
|
|
510
|
+
const { canvas } = core;
|
|
511
|
+
if (!canvas) return () => {
|
|
512
|
+
};
|
|
513
|
+
const pinned = /* @__PURE__ */ new Map();
|
|
514
|
+
return addCarrySurface({
|
|
515
|
+
element: canvas,
|
|
516
|
+
receive(stage, payload, at, pointerId) {
|
|
517
|
+
if (core.disposed()) return "unhandled";
|
|
518
|
+
const event = () => {
|
|
519
|
+
const w = core.toWorld(at.clientX, at.clientY);
|
|
520
|
+
return {
|
|
521
|
+
kind: "carry",
|
|
522
|
+
stage,
|
|
523
|
+
pointerId,
|
|
524
|
+
type: payload.type,
|
|
525
|
+
value: payload.value,
|
|
526
|
+
x: w.x,
|
|
527
|
+
y: w.y,
|
|
528
|
+
clientX: at.clientX,
|
|
529
|
+
clientY: at.clientY,
|
|
530
|
+
altKey: at.altKey,
|
|
531
|
+
ctrlKey: at.ctrlKey,
|
|
532
|
+
metaKey: at.metaKey,
|
|
533
|
+
shiftKey: at.shiftKey
|
|
534
|
+
};
|
|
535
|
+
};
|
|
536
|
+
const routedNow = core.routedView();
|
|
537
|
+
try {
|
|
538
|
+
if (stage === "enter") {
|
|
539
|
+
core.routeAt(null, at.clientX, at.clientY);
|
|
540
|
+
pinned.set(pointerId, core.routedView());
|
|
541
|
+
return core.dispatch(event());
|
|
542
|
+
}
|
|
543
|
+
if (pinned.has(pointerId)) core.setRoutedView(pinned.get(pointerId));
|
|
544
|
+
if (stage !== "move") pinned.delete(pointerId);
|
|
545
|
+
const ev = event();
|
|
546
|
+
if (stage === "drop" && !core.dispatcherNow().inFlight().has(gestureIdFor(ev))) {
|
|
547
|
+
core.routeAt(null, at.clientX, at.clientY);
|
|
548
|
+
return core.dispatch(event());
|
|
549
|
+
}
|
|
550
|
+
return core.dispatch(ev);
|
|
551
|
+
} finally {
|
|
552
|
+
core.setRoutedView(routedNow);
|
|
553
|
+
}
|
|
554
|
+
}
|
|
555
|
+
});
|
|
556
|
+
}
|
|
557
|
+
|
|
235
558
|
// src/interactions/dispatcher/underPointer.ts
|
|
236
559
|
function underPointer(view, mods, w) {
|
|
237
560
|
const affordance = view.affordanceAt?.(w) ?? void 0;
|
|
@@ -243,9 +566,13 @@ function underPointer(view, mods, w) {
|
|
|
243
566
|
shiftKey: mods.shiftKey,
|
|
244
567
|
...affordance !== void 0 ? { affordance } : {},
|
|
245
568
|
...body?.body !== void 0 ? { bodyTarget: body.body } : {},
|
|
246
|
-
...body?.kind !== void 0 ? { bodyKind: body.kind } : {}
|
|
569
|
+
...body?.kind !== void 0 ? { bodyKind: body.kind } : {},
|
|
570
|
+
...body?.doubleClick !== void 0 ? { doubleClickBody: doubleClickBodyOf(body.doubleClick) } : {}
|
|
247
571
|
};
|
|
248
572
|
}
|
|
573
|
+
function doubleClickBodyOf(named) {
|
|
574
|
+
return { bodyTarget: named.body, ...named.kind !== void 0 ? { bodyKind: named.kind } : {} };
|
|
575
|
+
}
|
|
249
576
|
|
|
250
577
|
// src/interactions/dispatcher/channels/contextMenu.ts
|
|
251
578
|
function contextMenuInput(core, takeNativeHold) {
|
|
@@ -253,6 +580,7 @@ function contextMenuInput(core, takeNativeHold) {
|
|
|
253
580
|
const onContextMenu = (e) => {
|
|
254
581
|
e.preventDefault();
|
|
255
582
|
if (takeNativeHold()) return;
|
|
583
|
+
core.activate();
|
|
256
584
|
routeAt(null, e.clientX, e.clientY);
|
|
257
585
|
const w = toWorld(e.clientX, e.clientY);
|
|
258
586
|
const ev = {
|
|
@@ -309,7 +637,8 @@ function hoverCursorInput(core, paintedCursor, pointersHeld, cursorSink = () =>
|
|
|
309
637
|
const press = { kind: "pointerdown", x: w.x, y: w.y, clientX: h.clientX, clientY: h.clientY, ...where };
|
|
310
638
|
if (DEV) publishLiveDispatch(() => d.explain(press, ctx));
|
|
311
639
|
const click = { kind: "click", x: w.x, y: w.y, pressX: w.x, pressY: w.y, ...where };
|
|
312
|
-
const
|
|
640
|
+
const cursorOf = (r) => r ? actionCursor(r.action, r.params) : void 0;
|
|
641
|
+
const cursor = cursorOf(d.resolveOnly(press, ctx)) ?? cursorOf(dispatcherNow().resolveOnly(click, ctx));
|
|
313
642
|
override.apply(cursor ?? null);
|
|
314
643
|
};
|
|
315
644
|
const refresh = () => {
|
|
@@ -324,16 +653,17 @@ function hoverCursorInput(core, paintedCursor, pointersHeld, cursorSink = () =>
|
|
|
324
653
|
if (!core.disposed()) refresh();
|
|
325
654
|
}, 0);
|
|
326
655
|
};
|
|
656
|
+
const hoverAt = (at) => {
|
|
657
|
+
const w = toWorld(at.clientX, at.clientY);
|
|
658
|
+
const where = underPointer(target(), at, w);
|
|
659
|
+
const from = facts ? { from: whereOf(facts.where) } : {};
|
|
660
|
+
facts = { at, where };
|
|
661
|
+
dispatch({ kind: "hover", x: w.x, y: w.y, clientX: at.clientX, clientY: at.clientY, ...where, ...from });
|
|
662
|
+
};
|
|
327
663
|
return {
|
|
328
664
|
moved(e) {
|
|
329
665
|
last = hoverOf(e);
|
|
330
|
-
if (pointersHeld() === 0)
|
|
331
|
-
const w = toWorld(e.clientX, e.clientY);
|
|
332
|
-
const where = underPointer(target(), last, w);
|
|
333
|
-
const from = facts ? { from: whereOf(facts.where) } : {};
|
|
334
|
-
facts = { at: last, where };
|
|
335
|
-
dispatch({ kind: "hover", x: w.x, y: w.y, clientX: e.clientX, clientY: e.clientY, ...where, ...from });
|
|
336
|
-
}
|
|
666
|
+
if (pointersHeld() === 0) hoverAt(last);
|
|
337
667
|
refresh();
|
|
338
668
|
},
|
|
339
669
|
released(e) {
|
|
@@ -354,7 +684,10 @@ function hoverCursorInput(core, paintedCursor, pointersHeld, cursorSink = () =>
|
|
|
354
684
|
},
|
|
355
685
|
onKey(e) {
|
|
356
686
|
if (!last) return;
|
|
687
|
+
const prev = last;
|
|
357
688
|
last = { ...last, altKey: e.altKey, ctrlKey: e.ctrlKey, metaKey: e.metaKey, shiftKey: e.shiftKey };
|
|
689
|
+
const changed = prev.altKey !== last.altKey || prev.ctrlKey !== last.ctrlKey || prev.metaKey !== last.metaKey || prev.shiftKey !== last.shiftKey;
|
|
690
|
+
if (changed && pointersHeld() === 0) hoverAt(last);
|
|
358
691
|
refreshSoon();
|
|
359
692
|
},
|
|
360
693
|
clear: override.clear
|
|
@@ -451,13 +784,14 @@ function typedWithAltGraph(e) {
|
|
|
451
784
|
const base = /^(?:Key|Digit)(.)$/.exec(e.code)?.[1];
|
|
452
785
|
return base === void 0 || base.toLowerCase() !== e.key.toLowerCase();
|
|
453
786
|
}
|
|
787
|
+
var inMenu = (t) => t instanceof Element && t.closest('[role="menu"]') !== null;
|
|
454
788
|
function keyboardInput(core) {
|
|
455
789
|
const { dispatch, dispatcherNow } = core;
|
|
456
790
|
const heldKeys = /* @__PURE__ */ new Map();
|
|
457
791
|
const codeOf = (e) => e.code ? { code: e.code } : {};
|
|
458
792
|
const physicalKey = (e) => e.code || e.key.toLowerCase();
|
|
459
793
|
const onKeyDown = (e) => {
|
|
460
|
-
if (e.defaultPrevented || isEditableTarget(e.target) || focusedControlOwnsKey(e)) return;
|
|
794
|
+
if (e.defaultPrevented || isEditableTarget(e.target) || inMenu(e.target) || focusedControlOwnsKey(e)) return;
|
|
461
795
|
if (!core.holdsKeys()) return;
|
|
462
796
|
if (e.repeat && heldKeys.has(physicalKey(e))) {
|
|
463
797
|
e.preventDefault();
|
|
@@ -620,7 +954,11 @@ function pointerInput(core, opts) {
|
|
|
620
954
|
clock: hold.clock,
|
|
621
955
|
toWorld,
|
|
622
956
|
toSurface: (p) => core.toCanvasLocal(p.x, p.y),
|
|
623
|
-
longPressMs: () => opts.longPress()?.duration,
|
|
957
|
+
longPressMs: () => opts.longPress()?.duration ?? opts.kitSettings().get("gestures.longPressMs"),
|
|
958
|
+
doubleClickMs: () => opts.kitSettings().get("gestures.doubleClickMs"),
|
|
959
|
+
doubleClickPx: () => opts.kitSettings().get("gestures.doubleClickPx"),
|
|
960
|
+
tapPx: () => opts.kitSettings().get("gestures.tapPx"),
|
|
961
|
+
dragPx: () => opts.kitSettings().get("gestures.dragPx"),
|
|
624
962
|
clicks: opts.clicks,
|
|
625
963
|
observer: {
|
|
626
964
|
click: (world) => {
|
|
@@ -765,6 +1103,12 @@ function webkitPinchInput(core) {
|
|
|
765
1103
|
}
|
|
766
1104
|
|
|
767
1105
|
// src/interactions/dispatcher/channels/wheel.ts
|
|
1106
|
+
var LINE_PX = 16;
|
|
1107
|
+
function pixelsPer(e, canvas) {
|
|
1108
|
+
if (e.deltaMode === 1) return LINE_PX;
|
|
1109
|
+
if (e.deltaMode === 2) return canvas?.clientHeight || LINE_PX * 20;
|
|
1110
|
+
return 1;
|
|
1111
|
+
}
|
|
768
1112
|
function wheelInput(core, pinchLive) {
|
|
769
1113
|
const { routeAt, toWorld, target, dispatch } = core;
|
|
770
1114
|
const onWheel = (e) => {
|
|
@@ -777,10 +1121,11 @@ function wheelInput(core, pinchLive) {
|
|
|
777
1121
|
routeAt(null, e.clientX, e.clientY);
|
|
778
1122
|
const local = core.toCanvasLocal(e.clientX, e.clientY);
|
|
779
1123
|
const hitPoint = toWorld(e.clientX, e.clientY);
|
|
1124
|
+
const toPx = pixelsPer(e, core.canvas);
|
|
780
1125
|
const ev = {
|
|
781
1126
|
kind: "wheel",
|
|
782
|
-
deltaX: e.deltaX,
|
|
783
|
-
deltaY: e.deltaY,
|
|
1127
|
+
deltaX: e.deltaX * toPx,
|
|
1128
|
+
deltaY: e.deltaY * toPx,
|
|
784
1129
|
clientX: local.x,
|
|
785
1130
|
clientY: local.y,
|
|
786
1131
|
...underPointer(target(), e, hitPoint)
|
|
@@ -803,6 +1148,7 @@ function attachInput(canvas, src, channels) {
|
|
|
803
1148
|
canvas,
|
|
804
1149
|
root: src.root,
|
|
805
1150
|
views: src.views,
|
|
1151
|
+
clientToLocal: src.clientToLocal,
|
|
806
1152
|
context: src.context,
|
|
807
1153
|
actions: src.actions,
|
|
808
1154
|
uses: () => {
|
|
@@ -817,6 +1163,7 @@ function attachInput(canvas, src, channels) {
|
|
|
817
1163
|
const hover = hoverCursorInput(core, src.paintedCursor, () => held?.count() ?? 0, src.cursorSink);
|
|
818
1164
|
const pointer = pointerInput(core, {
|
|
819
1165
|
longPress: src.longPress,
|
|
1166
|
+
kitSettings: src.kitSettings,
|
|
820
1167
|
onClick: src.onClick,
|
|
821
1168
|
onDoubleClick: src.onDoubleClick,
|
|
822
1169
|
clicks: src.clicks,
|
|
@@ -863,8 +1210,10 @@ function attachInput(canvas, src, channels) {
|
|
|
863
1210
|
listeners.on(canvas, "drop", ingest.onDrop);
|
|
864
1211
|
listeners.on(window, "paste", ingest.onPaste);
|
|
865
1212
|
}
|
|
1213
|
+
const offCarry = channels.carry ? carryInput(core) : null;
|
|
866
1214
|
return () => {
|
|
867
1215
|
listeners.removeAll();
|
|
1216
|
+
offCarry?.();
|
|
868
1217
|
canvas?.classList.remove(DROPOVER_CLASS);
|
|
869
1218
|
src.actions().dropKeys();
|
|
870
1219
|
hover.clear();
|
|
@@ -878,12 +1227,13 @@ function attachInput(canvas, src, channels) {
|
|
|
878
1227
|
|
|
879
1228
|
// src/interactions/dispatcher/useGestureDispatcher.tsx
|
|
880
1229
|
function useGestureDispatcher(opts) {
|
|
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;
|
|
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;
|
|
882
1231
|
const pointerChannel = channels?.pointer !== false;
|
|
883
1232
|
const wheelChannel = channels?.wheel !== false;
|
|
884
1233
|
const pinchChannel = channels?.pinch !== false;
|
|
885
1234
|
const contextMenuChannel = channels?.contextMenu !== false;
|
|
886
1235
|
const ingestChannel = channels?.ingest !== false;
|
|
1236
|
+
const carryChannel = channels?.carry !== false;
|
|
887
1237
|
const onClickRef = useLatest(onClick);
|
|
888
1238
|
const onDoubleClickRef = useLatest(onDoubleClick);
|
|
889
1239
|
const activeTool = useActiveToolContext();
|
|
@@ -894,8 +1244,12 @@ function useGestureDispatcher(opts) {
|
|
|
894
1244
|
dispatcherRef.current = dispatcherOpt ?? createDispatcher();
|
|
895
1245
|
}
|
|
896
1246
|
const registryRef = useLatest(actions);
|
|
1247
|
+
const heard = useMemo(() => {
|
|
1248
|
+
const node = hears === "own" ? actionsNodeOf(actions) : null;
|
|
1249
|
+
return node ? { list: () => node.ownActions() } : actions;
|
|
1250
|
+
}, [actions, hears]);
|
|
897
1251
|
const ctxRef = useLatest({
|
|
898
|
-
actions,
|
|
1252
|
+
actions: heard,
|
|
899
1253
|
depRegistry,
|
|
900
1254
|
activeToolId: activeTool.active,
|
|
901
1255
|
hotkeyStack: activeTool.hotkeyStack,
|
|
@@ -911,6 +1265,7 @@ function useGestureDispatcher(opts) {
|
|
|
911
1265
|
getRuleCtx
|
|
912
1266
|
});
|
|
913
1267
|
const viewsRef = useLatest(views);
|
|
1268
|
+
const clientToLocalRef = useLatest(clientToLocal);
|
|
914
1269
|
const allDispatchers = useCallback(() => [
|
|
915
1270
|
rootTargetRef.current.dispatcher,
|
|
916
1271
|
...(viewsRef.current?.targets() ?? []).map((t) => t.dispatcher)
|
|
@@ -918,6 +1273,7 @@ function useGestureDispatcher(opts) {
|
|
|
918
1273
|
const requestRedrawRef = useLatest(requestRedraw);
|
|
919
1274
|
const cursorRef = useLatest({ painted: paintedCursor, sink: cursorSink });
|
|
920
1275
|
const longPressRef = useLatest(longPress);
|
|
1276
|
+
const kitSettingsRef = useLatest(useKitSettings());
|
|
921
1277
|
const clicksRef = useRef({ last: null });
|
|
922
1278
|
useToolLifecycle({
|
|
923
1279
|
entriesById,
|
|
@@ -936,6 +1292,7 @@ function useGestureDispatcher(opts) {
|
|
|
936
1292
|
return attachInput(canvasRef.current, {
|
|
937
1293
|
root: () => rootTargetRef.current,
|
|
938
1294
|
views: () => viewsRef.current,
|
|
1295
|
+
clientToLocal: () => clientToLocalRef.current,
|
|
939
1296
|
context: () => ctxRef.current,
|
|
940
1297
|
actions: () => registryRef.current,
|
|
941
1298
|
dispatchers: allDispatchers,
|
|
@@ -945,6 +1302,7 @@ function useGestureDispatcher(opts) {
|
|
|
945
1302
|
paintedCursor: () => cursorRef.current.painted?.(),
|
|
946
1303
|
cursorSink: () => cursorRef.current.sink?.(),
|
|
947
1304
|
longPress: () => longPressRef.current,
|
|
1305
|
+
kitSettings: () => kitSettingsRef.current,
|
|
948
1306
|
onClick: () => onClickRef.current,
|
|
949
1307
|
onDoubleClick: () => onDoubleClickRef.current,
|
|
950
1308
|
clicks: clicksRef.current
|
|
@@ -954,7 +1312,8 @@ function useGestureDispatcher(opts) {
|
|
|
954
1312
|
wheel: wheelChannel,
|
|
955
1313
|
pinch: pinchChannel,
|
|
956
1314
|
contextMenu: contextMenuChannel,
|
|
957
|
-
ingest: ingestChannel
|
|
1315
|
+
ingest: ingestChannel,
|
|
1316
|
+
carry: carryChannel
|
|
958
1317
|
});
|
|
959
1318
|
}, [
|
|
960
1319
|
enabled,
|
|
@@ -965,8 +1324,11 @@ function useGestureDispatcher(opts) {
|
|
|
965
1324
|
pinchChannel,
|
|
966
1325
|
contextMenuChannel,
|
|
967
1326
|
ingestChannel,
|
|
1327
|
+
carryChannel,
|
|
968
1328
|
allDispatchers,
|
|
1329
|
+
clientToLocalRef,
|
|
969
1330
|
ctxRef,
|
|
1331
|
+
kitSettingsRef,
|
|
970
1332
|
longPressRef,
|
|
971
1333
|
onClickRef,
|
|
972
1334
|
onDoubleClickRef,
|
|
@@ -977,206 +1339,36 @@ function useGestureDispatcher(opts) {
|
|
|
977
1339
|
viewsRef
|
|
978
1340
|
]);
|
|
979
1341
|
}
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
cache = null;
|
|
1005
|
-
/** Called on `activate`, so a scope's dep and tool nodes move with it. */
|
|
1006
|
-
onActivate = [];
|
|
1007
|
-
resolve(id) {
|
|
1008
|
-
for (const n of this.chain()) {
|
|
1009
|
-
if (n.muted.has(id)) return void 0;
|
|
1010
|
-
const a = n.actions.get(id)?.at(-1);
|
|
1011
|
-
if (a) return this.tuned(a);
|
|
1012
|
-
}
|
|
1013
|
-
return void 0;
|
|
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
|
-
}
|
|
1024
|
-
snapshot() {
|
|
1025
|
-
const leaf = this.start();
|
|
1026
|
-
const cached = this.cache;
|
|
1027
|
-
if (cached && cached.version === this.tree.version && cached.leaf === leaf) return cached.list;
|
|
1028
|
-
const ids = /* @__PURE__ */ new Set();
|
|
1029
|
-
for (const n of leaf.chain()) for (const id of n.actions.keys()) ids.add(id);
|
|
1030
|
-
const out = [];
|
|
1031
|
-
for (const id of ids) {
|
|
1032
|
-
const a = leaf.resolve(id);
|
|
1033
|
-
if (a) out.push(a);
|
|
1034
|
-
}
|
|
1035
|
-
const list = Object.freeze(out);
|
|
1036
|
-
this.cache = { version: this.tree.version, leaf, list };
|
|
1037
|
-
return list;
|
|
1038
|
-
}
|
|
1039
|
-
deps() {
|
|
1040
|
-
for (const n of this.chain()) {
|
|
1041
|
-
const r = n.contextDeps();
|
|
1042
|
-
if (r) return r;
|
|
1043
|
-
}
|
|
1044
|
-
return null;
|
|
1045
|
-
}
|
|
1046
|
-
dispatcher() {
|
|
1047
|
-
for (const n of this.chain()) {
|
|
1048
|
-
const d = n.dispatchers.at(-1);
|
|
1049
|
-
if (d) return d;
|
|
1050
|
-
}
|
|
1051
|
-
return null;
|
|
1052
|
-
}
|
|
1053
|
-
activate() {
|
|
1054
|
-
keyHolder = this;
|
|
1055
|
-
super.activate();
|
|
1056
|
-
for (const f of this.onActivate) f();
|
|
1057
|
-
}
|
|
1058
|
-
registry = {
|
|
1059
|
-
register: (action) => {
|
|
1060
|
-
validateActionId(action.id);
|
|
1061
|
-
validateActionDefaultBinding(action);
|
|
1062
|
-
const stack = this.actions.get(action.id);
|
|
1063
|
-
if (stack) stack.push(action);
|
|
1064
|
-
else this.actions.set(action.id, [action]);
|
|
1065
|
-
this.changed();
|
|
1066
|
-
let released = false;
|
|
1067
|
-
return () => {
|
|
1068
|
-
if (released) return;
|
|
1069
|
-
released = true;
|
|
1070
|
-
const cur = this.actions.get(action.id);
|
|
1071
|
-
if (!cur) return;
|
|
1072
|
-
const i = cur.lastIndexOf(action);
|
|
1073
|
-
if (i === -1) return;
|
|
1074
|
-
cur.splice(i, 1);
|
|
1075
|
-
if (cur.length === 0) {
|
|
1076
|
-
queueMicrotask(() => {
|
|
1077
|
-
if (cur.length === 0 && this.actions.get(action.id) === cur) this.actions.delete(action.id);
|
|
1078
|
-
});
|
|
1079
|
-
}
|
|
1080
|
-
this.changed();
|
|
1081
|
-
};
|
|
1082
|
-
},
|
|
1083
|
-
unregister: (id) => {
|
|
1084
|
-
if (this.actions.delete(id)) this.changed();
|
|
1085
|
-
},
|
|
1086
|
-
mute: (id) => {
|
|
1087
|
-
this.muted.set(id, (this.muted.get(id) ?? 0) + 1);
|
|
1088
|
-
this.changed();
|
|
1089
|
-
let released = false;
|
|
1090
|
-
return () => {
|
|
1091
|
-
if (released) return;
|
|
1092
|
-
released = true;
|
|
1093
|
-
const held = this.muted.get(id);
|
|
1094
|
-
if (held === void 0) return;
|
|
1095
|
-
if (held > 1) this.muted.set(id, held - 1);
|
|
1096
|
-
else this.muted.delete(id);
|
|
1097
|
-
this.changed();
|
|
1098
|
-
};
|
|
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
|
-
},
|
|
1114
|
-
list: () => this.snapshot(),
|
|
1115
|
-
trigger: (id, params) => {
|
|
1116
|
-
const leaf = this.start();
|
|
1117
|
-
const a = leaf.resolve(id);
|
|
1118
|
-
if (!a?.invoker || a.invoker.timing !== "immediate") return false;
|
|
1119
|
-
const deps = depsFor(a, leaf.deps());
|
|
1120
|
-
if (!evaluateEnabled(a, deps).enabled) return false;
|
|
1121
|
-
try {
|
|
1122
|
-
a.invoker.run(deps, params);
|
|
1123
|
-
} catch (err) {
|
|
1124
|
-
console.error(`weasel ActionsRegistry: action "${id}" threw`, err);
|
|
1125
|
-
}
|
|
1126
|
-
return true;
|
|
1127
|
-
},
|
|
1128
|
-
subscribe: (listener) => this.tree.listeners.subscribe(listener),
|
|
1129
|
-
setDispatcher: (d) => pushOwner(this.dispatchers, d),
|
|
1130
|
-
begin: (id, params) => {
|
|
1131
|
-
const leaf = this.start();
|
|
1132
|
-
const a = leaf.resolve(id);
|
|
1133
|
-
const disp = leaf.dispatcher();
|
|
1134
|
-
if (!a || !disp) return null;
|
|
1135
|
-
return disp.beginUiOngoing(id, depsFor(a, leaf.deps()), params);
|
|
1136
|
-
},
|
|
1137
|
-
activate: () => this.activate(),
|
|
1138
|
-
isActive: () => this.isActive(),
|
|
1139
|
-
holdsKeys: () => keyHolder === this,
|
|
1140
|
-
dropKeys: () => {
|
|
1141
|
-
if (keyHolder === this) keyHolder = null;
|
|
1142
|
-
}
|
|
1143
|
-
};
|
|
1144
|
-
};
|
|
1145
|
-
var keyHolder = null;
|
|
1146
|
-
var NODES = /* @__PURE__ */ new WeakMap();
|
|
1147
|
-
function actionsNodeOf(registry) {
|
|
1148
|
-
return registry ? NODES.get(registry) ?? null : null;
|
|
1149
|
-
}
|
|
1150
|
-
function ActionsProvider({ children }) {
|
|
1151
|
-
const depReg = useOptionalDepRegistry();
|
|
1152
|
-
const depRegRef = useLatest(depReg);
|
|
1153
|
-
const node = useMemo(() => new ActionsNode(null, true, () => depRegRef.current), [depRegRef]);
|
|
1154
|
-
return /* @__PURE__ */ jsx(ActionsContext.Provider, { value: node.registry, children });
|
|
1155
|
-
}
|
|
1156
|
-
var IS_DEV = (() => {
|
|
1157
|
-
try {
|
|
1158
|
-
return Boolean(import.meta.env?.DEV);
|
|
1159
|
-
} catch {
|
|
1160
|
-
return false;
|
|
1161
|
-
}
|
|
1162
|
-
})();
|
|
1163
|
-
function useActionsRegistry() {
|
|
1164
|
-
return useContext(ActionsContext);
|
|
1342
|
+
function useCommand(id, label, run, options) {
|
|
1343
|
+
const latest = useLatest({ run, options });
|
|
1344
|
+
const keys = useStableByContent(options?.keys, deepEqual);
|
|
1345
|
+
const tags = useStableByContent(options?.tags, deepEqual);
|
|
1346
|
+
const variants = useStableByContent(options?.variants, deepEqual);
|
|
1347
|
+
const hasEnabled = options?.enabled !== void 0;
|
|
1348
|
+
const hasActive = options?.active !== void 0;
|
|
1349
|
+
const icon = options?.icon;
|
|
1350
|
+
const action = useMemo(() => {
|
|
1351
|
+
const read = () => latest.current.options;
|
|
1352
|
+
const a = {
|
|
1353
|
+
id,
|
|
1354
|
+
label,
|
|
1355
|
+
invoker: { timing: "immediate", run: (_deps, params) => latest.current.run(params) }
|
|
1356
|
+
};
|
|
1357
|
+
if (keys !== void 0) a.defaultBinding = bindingOf(keys);
|
|
1358
|
+
if (tags !== void 0) a.tags = tags;
|
|
1359
|
+
if (variants !== void 0) a.variants = variants;
|
|
1360
|
+
if (hasEnabled) a.enabled = () => read()?.enabled?.() ?? true;
|
|
1361
|
+
if (hasActive) a.active = () => read()?.active?.() ?? false;
|
|
1362
|
+
if (icon !== void 0) a.icon = icon;
|
|
1363
|
+
return a;
|
|
1364
|
+
}, [id, label, icon, keys, tags, variants, hasEnabled, hasActive, latest]);
|
|
1365
|
+
useAction(action);
|
|
1165
1366
|
}
|
|
1166
|
-
function
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
if (!reg) {
|
|
1170
|
-
if (IS_DEV) {
|
|
1171
|
-
console.warn(
|
|
1172
|
-
`useAction("${action.id}"): no <ActionsProvider> is in scope, so the action was not registered and its bindings will never fire.`
|
|
1173
|
-
);
|
|
1174
|
-
}
|
|
1175
|
-
return;
|
|
1176
|
-
}
|
|
1177
|
-
return reg.register(action);
|
|
1178
|
-
}, [reg, action]);
|
|
1367
|
+
function bindingOf(keys) {
|
|
1368
|
+
if (isList(keys)) return [...keys];
|
|
1369
|
+
return "spec" in keys ? [keys] : keys;
|
|
1179
1370
|
}
|
|
1371
|
+
var isList = (keys) => Array.isArray(keys);
|
|
1180
1372
|
function useNodes(descends, ownsTool, parent) {
|
|
1181
1373
|
const parentActions = useActionsRegistry();
|
|
1182
1374
|
const parentDeps = useOptionalDepRegistry();
|
|
@@ -1200,7 +1392,8 @@ function useNodes(descends, ownsTool, parent) {
|
|
|
1200
1392
|
return nodes;
|
|
1201
1393
|
}
|
|
1202
1394
|
function Provide({ nodes, children }) {
|
|
1203
|
-
|
|
1395
|
+
const menuHost = useContext(MenuHostContext) ?? nodes.actions.menuHost();
|
|
1396
|
+
return /* @__PURE__ */ jsx(DepRegistryContext.Provider, { value: nodes.deps.registry, children: /* @__PURE__ */ jsx(ActionsContext.Provider, { value: nodes.actions.registry, children: /* @__PURE__ */ jsx(ActiveToolNodeContext.Provider, { value: nodes.tools, children: /* @__PURE__ */ jsx(MenuHostContext.Provider, { value: menuHost, children }) }) }) });
|
|
1204
1397
|
}
|
|
1205
1398
|
function InputScope({ yoke, children }) {
|
|
1206
1399
|
const nodes = useNodes(false, yoke === void 0, yoke);
|
|
@@ -1533,6 +1726,6 @@ function useTools(opts) {
|
|
|
1533
1726
|
);
|
|
1534
1727
|
}
|
|
1535
1728
|
|
|
1536
|
-
export { ActionsProvider, ActiveToolContextProvider, ActiveToolContextProviderIfRoot, DepRegistryProvider, InputScope, PointerContextProvider, SelectionContextProvider, SelectionContextProviderIfRoot, Yoke, createPointerStore, useAction, useActionsRegistry, useActiveToolContext, useContributions, useDepRegistry, useDepSource, useGestureDispatcher, useOffhandAction, useOngoingAction, useOptionalActiveToolContext, useOptionalDepRegistry, usePointerContext, usePointerPosition, usePublishSelection, useSelectionContext, useTools, useYoke };
|
|
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 };
|
|
1537
1730
|
//# sourceMappingURL=react.js.map
|
|
1538
1731
|
//# sourceMappingURL=react.js.map
|