@weasel-js/routing 1.10.0 → 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-4DR6AJMN.js → chunk-QBQQIFPI.js} +625 -49
- package/dist/chunk-QBQQIFPI.js.map +1 -0
- package/dist/{index-Bm2QEV09.d.ts → index-CmfVvwWD.d.ts} +722 -276
- package/dist/index.d.ts +6 -3
- package/dist/index.js +55 -16
- package/dist/index.js.map +1 -1
- package/dist/{internal-D0rDmi7t.d.ts → internal-21M1rTVo.d.ts} +23 -1
- package/dist/internal.d.ts +8 -5
- package/dist/react.d.ts +63 -27
- package/dist/react.js +535 -268
- package/dist/react.js.map +1 -1
- package/package.json +13 -9
- package/dist/chunk-4DR6AJMN.js.map +0 -1
|
@@ -1,10 +1,14 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import
|
|
3
|
-
import {
|
|
4
|
-
import { Emitter } from '@weasel-js/registry';
|
|
1
|
+
import { MenuEntry, Rect, MenuShortcut } from '@weasel-js/menu';
|
|
2
|
+
import { PrefGroup } from '@weasel-js/prefs';
|
|
3
|
+
import { FramedBox, View, Point } from '@weasel-js/geom';
|
|
5
4
|
import { CapabilityTag, ActiveMode, ModeRegistry } from '@weasel-js/modes';
|
|
5
|
+
import { ModifierKey, ClaimableGesture, GestureSpec, IngestItem, BodyTarget, InputEvent, TargetSpec, KeyHeldSpec, TargetPredicate, KeySpec, ParsedModifiers, GestureName } from '@weasel-js/gestures';
|
|
6
|
+
import * as _weasel_js_icons from '@weasel-js/icons';
|
|
7
|
+
import { IconRef } from '@weasel-js/icons';
|
|
6
8
|
import { CursorSpec } from '@weasel-js/cursor';
|
|
7
|
-
import
|
|
9
|
+
import * as react from 'react';
|
|
10
|
+
import { ReactNode } from 'react';
|
|
11
|
+
import { Emitter, QueryMatch } from '@weasel-js/registry';
|
|
8
12
|
import '@weasel-js/select';
|
|
9
13
|
|
|
10
14
|
/**
|
|
@@ -22,20 +26,9 @@ type NodeId = string & {
|
|
|
22
26
|
readonly __brand: 'NodeId';
|
|
23
27
|
};
|
|
24
28
|
|
|
25
|
-
/**
|
|
26
|
-
*
|
|
27
|
-
|
|
28
|
-
* let chrome carry the frame a box is drawn in without a parallel type;
|
|
29
|
-
* `poseFrameOf` composes the two.
|
|
30
|
-
*/
|
|
31
|
-
interface Bounds {
|
|
32
|
-
x: number;
|
|
33
|
-
y: number;
|
|
34
|
-
width: number;
|
|
35
|
-
height: number;
|
|
36
|
-
rotation?: number;
|
|
37
|
-
transform?: PoseLinear;
|
|
38
|
-
}
|
|
29
|
+
/** Axis-aligned rectangle in world space, with the frame it is drawn in;
|
|
30
|
+
* geom's `FramedBox`. */
|
|
31
|
+
type Bounds = FramedBox;
|
|
39
32
|
/** The selection as routing reads and writes it. */
|
|
40
33
|
interface SelectionApi {
|
|
41
34
|
/** Current selection. Re-renders trigger when this reference changes. */
|
|
@@ -176,106 +169,6 @@ type ResizeAnchor = {
|
|
|
176
169
|
y: 'min' | 'max' | 'free';
|
|
177
170
|
};
|
|
178
171
|
|
|
179
|
-
/**
|
|
180
|
-
* The tree both input registries hang on. A provider is a root; every canvas
|
|
181
|
-
* mounts a scope under the registry in scope; a yoke sits between the two. A
|
|
182
|
-
* registration lives in the node it was made in, and a lookup starts at a leaf
|
|
183
|
-
* and walks up, so one canvas never answers for another.
|
|
184
|
-
*/
|
|
185
|
-
|
|
186
|
-
/** What every node of one tree shares: a version and the listeners to it. */
|
|
187
|
-
interface ScopeTree {
|
|
188
|
-
version: number;
|
|
189
|
-
readonly listeners: Emitter;
|
|
190
|
-
}
|
|
191
|
-
declare class ScopeNode<N extends ScopeNode<N>> {
|
|
192
|
-
readonly parent: N | null;
|
|
193
|
-
readonly descends: boolean;
|
|
194
|
-
readonly tree: ScopeTree;
|
|
195
|
-
private readonly children;
|
|
196
|
-
private activeChild;
|
|
197
|
-
/** `descends`: whether reads made here answer from the active child down —
|
|
198
|
-
* true for a root or a yoke, which chrome reads through; false for a scope,
|
|
199
|
-
* which answers for itself even with a scope nested inside it. */
|
|
200
|
-
constructor(parent: N | null, descends: boolean);
|
|
201
|
-
/** Bump the tree's version and tell every listener in it. */
|
|
202
|
-
changed(): void;
|
|
203
|
-
/** Join the parent's children, newest last; returns the leave. */
|
|
204
|
-
mount(): () => void;
|
|
205
|
-
/** Make this node the one its ancestors resolve through. */
|
|
206
|
-
activate(): void;
|
|
207
|
-
/** The node a lookup made here starts from: down the active children, or the
|
|
208
|
-
* newest where nothing has been activated yet. A yoke with no members yet
|
|
209
|
-
* is passed over — there is no canvas behind it to answer. */
|
|
210
|
-
leaf(): N;
|
|
211
|
-
private newestMember;
|
|
212
|
-
/** Where a read made through this node starts. */
|
|
213
|
-
start(): N;
|
|
214
|
-
/** Whether this node is on the path a read from the root takes. */
|
|
215
|
-
isActive(): boolean;
|
|
216
|
-
/** This node, then each ancestor up to the root. */
|
|
217
|
-
chain(): Generator<N>;
|
|
218
|
-
}
|
|
219
|
-
|
|
220
|
-
/** Which tool is active, plus the stack of tools temporarily held active by a
|
|
221
|
-
* hotkey (space-for-hand and the like). The dispatcher reads this to decide
|
|
222
|
-
* whose bindings are in scope. */
|
|
223
|
-
interface ActiveToolContextValue {
|
|
224
|
-
/** The focused tool's id, or `null` when no tool holds the active slot —
|
|
225
|
-
* a canvas can run on ambient bindings alone. */
|
|
226
|
-
active: string | null;
|
|
227
|
-
hotkeyStack: string[];
|
|
228
|
-
setActive(id: string | null): void;
|
|
229
|
-
pushHotkey(id: string): void;
|
|
230
|
-
/**
|
|
231
|
-
* Disengage a hotkey-held tool. With `id`, removes that tool's own entry
|
|
232
|
-
* wherever it now sits — holds do not have to come up in the order they went
|
|
233
|
-
* down, and popping the top would disengage a tool whose key is still held.
|
|
234
|
-
* With no id, pops the top.
|
|
235
|
-
*/
|
|
236
|
-
popHotkey(id?: string): void;
|
|
237
|
-
}
|
|
238
|
-
/**
|
|
239
|
-
* One node of the tool tree. A node that `owns` a tool holds its state; one
|
|
240
|
-
* that does not — a scope inside a yoke — reads and writes its yoke's.
|
|
241
|
-
*/
|
|
242
|
-
declare class ToolNode extends ScopeNode<ToolNode> {
|
|
243
|
-
private state;
|
|
244
|
-
private value;
|
|
245
|
-
constructor(parent: ToolNode | null, descends: boolean, owns: boolean, initialActive: string | null);
|
|
246
|
-
/** The node whose tool a read here resolves to. */
|
|
247
|
-
owner(): ToolNode;
|
|
248
|
-
private update;
|
|
249
|
-
/** A stable value per owner and state, for `useSyncExternalStore`. */
|
|
250
|
-
snapshot(): ActiveToolContextValue;
|
|
251
|
-
subscribe: (listener: () => void) => (() => void);
|
|
252
|
-
}
|
|
253
|
-
/** Props for `<ActiveToolContextProvider>`. */
|
|
254
|
-
interface ActiveToolContextProviderProps {
|
|
255
|
-
children: ReactNode;
|
|
256
|
-
/** Seeds the active slot, and wins over the first `useTools` call's
|
|
257
|
-
* `active`. Omitted, the slot starts empty and that call seeds it. */
|
|
258
|
-
initialActive?: string | null;
|
|
259
|
-
}
|
|
260
|
-
/** Provides root active-tool state. Every canvas below has a tool of its own;
|
|
261
|
-
* reads and writes here reach the one last used. */
|
|
262
|
-
declare function ActiveToolContextProvider({ children, initialActive, }: ActiveToolContextProviderProps): react.JSX.Element;
|
|
263
|
-
/** The active-tool state in scope. Throws outside a provider; use
|
|
264
|
-
* `useOptionalActiveToolContext` where one is not guaranteed. */
|
|
265
|
-
declare function useActiveToolContext(): ActiveToolContextValue;
|
|
266
|
-
/**
|
|
267
|
-
* Like `useActiveToolContext`, but returns `null` when no
|
|
268
|
-
* `<ActiveToolContextProvider>` is in scope instead of throwing.
|
|
269
|
-
*/
|
|
270
|
-
declare function useOptionalActiveToolContext(): ActiveToolContextValue | null;
|
|
271
|
-
/**
|
|
272
|
-
* Mounts an `<ActiveToolContextProvider>` only when no parent provider is in
|
|
273
|
-
* scope; otherwise renders children unwrapped.
|
|
274
|
-
*/
|
|
275
|
-
declare function ActiveToolContextProviderIfRoot({ children, }: {
|
|
276
|
-
children: ReactNode;
|
|
277
|
-
}): react.JSX.Element;
|
|
278
|
-
|
|
279
172
|
/**
|
|
280
173
|
* Live state read by rule evaluation. Built once per frame on the consuming
|
|
281
174
|
* surface — chrome-caps, the affordance pipeline, the dispatcher's
|
|
@@ -523,6 +416,155 @@ declare function resolveDeviceProfile(detected: DetectedDeviceFacts, overrides?:
|
|
|
523
416
|
*/
|
|
524
417
|
declare const DEFAULT_DEVICE_PROFILE: DeviceProfile;
|
|
525
418
|
|
|
419
|
+
/**
|
|
420
|
+
* Modifier roles: the modifiers an ongoing action reads while it runs, named
|
|
421
|
+
* by what they do rather than which key they are, so a binding or a tuning can
|
|
422
|
+
* move one to another key without forking the action.
|
|
423
|
+
*/
|
|
424
|
+
|
|
425
|
+
/** The keys that hold a role: any one of them held holds it. `'mod'` is Cmd
|
|
426
|
+
* on a Mac and Ctrl elsewhere. An empty list never holds it. */
|
|
427
|
+
type RoleKeys = readonly ModifierKey[];
|
|
428
|
+
/** One modifier an action reads mid-gesture. */
|
|
429
|
+
interface ModifierRole {
|
|
430
|
+
label: string;
|
|
431
|
+
/** The keys that hold it unless a tuning or a binding says otherwise. */
|
|
432
|
+
keys: RoleKeys;
|
|
433
|
+
}
|
|
434
|
+
/** An action's roles by id, e.g. `'handle.holdAngle'`. */
|
|
435
|
+
type ModifierRoles = Readonly<Record<string, ModifierRole>>;
|
|
436
|
+
/** Keys a tuning or a binding gives some of an action's roles. */
|
|
437
|
+
type RoleRebinds = Readonly<Record<string, RoleKeys>>;
|
|
438
|
+
/** Whether any of `keys` is held. */
|
|
439
|
+
declare function keysHeld(keys: RoleKeys, modifiers: ModifierState, isMac: boolean): boolean;
|
|
440
|
+
/**
|
|
441
|
+
* A reader for an action's own roles. It answers from `ctx.roles`, which the
|
|
442
|
+
* dispatcher resolves on every event, and falls back to the role's default
|
|
443
|
+
* keys where nothing resolved them: an invoker called directly, or a context
|
|
444
|
+
* a cancel-all built with no event.
|
|
445
|
+
*/
|
|
446
|
+
declare function roleReader<R extends ModifierRoles>(roles: R): (ctx: {
|
|
447
|
+
roles?: Readonly<Record<string, boolean>>;
|
|
448
|
+
modifiers: ModifierState;
|
|
449
|
+
}, id: keyof R & string) => boolean;
|
|
450
|
+
|
|
451
|
+
/** The chrome an in-flight gesture paints beside the scene. */
|
|
452
|
+
|
|
453
|
+
/**
|
|
454
|
+
* What a `polyline` overlay is, in a word — the narrowest thing an action can
|
|
455
|
+
* say about how its run should look without naming a paint.
|
|
456
|
+
*
|
|
457
|
+
* The named roles are the kit's; a painter maps each to a style and falls back
|
|
458
|
+
* to plain chrome for one it does not know, so a package outside core can coin
|
|
459
|
+
* its own and still be drawn.
|
|
460
|
+
*/
|
|
461
|
+
type OverlayRole =
|
|
462
|
+
/** Generic in-flight chrome — the marquee/lasso paint. */
|
|
463
|
+
'chrome'
|
|
464
|
+
/** A cut the gesture would make. */
|
|
465
|
+
| 'cut'
|
|
466
|
+
/** An edge the gesture would author between two points. */
|
|
467
|
+
| 'connector'
|
|
468
|
+
/** The stretch of a path a soft-selection drag reaches. */
|
|
469
|
+
| 'falloff'
|
|
470
|
+
/** What a lock holds a dragged point to — a line, a circle. */
|
|
471
|
+
| 'lock' | (string & {});
|
|
472
|
+
/**
|
|
473
|
+
* What an in-flight gesture proposes to paint *beside* the scene, returned by
|
|
474
|
+
* `OngoingHandle.overlay()` — a marquee rect, a lasso trail, the outline of a
|
|
475
|
+
* shape being dragged out, the line a slice would cut along.
|
|
476
|
+
*
|
|
477
|
+
* Every variant is world geometry and nothing else — no `DrawCommand`, no
|
|
478
|
+
* color, no coordinate space to choose — so a surface rendering the same
|
|
479
|
+
* gesture some other way can still read it. The painter owns every style
|
|
480
|
+
* decision.
|
|
481
|
+
*/
|
|
482
|
+
type OngoingOverlay = {
|
|
483
|
+
kind: 'marquee';
|
|
484
|
+
start: {
|
|
485
|
+
x: number;
|
|
486
|
+
y: number;
|
|
487
|
+
};
|
|
488
|
+
current: {
|
|
489
|
+
x: number;
|
|
490
|
+
y: number;
|
|
491
|
+
};
|
|
492
|
+
shiftHeld: boolean;
|
|
493
|
+
} | {
|
|
494
|
+
kind: 'lasso';
|
|
495
|
+
vertices: ReadonlyArray<{
|
|
496
|
+
x: number;
|
|
497
|
+
y: number;
|
|
498
|
+
}>;
|
|
499
|
+
current: {
|
|
500
|
+
x: number;
|
|
501
|
+
y: number;
|
|
502
|
+
};
|
|
503
|
+
shiftHeld: boolean;
|
|
504
|
+
} | {
|
|
505
|
+
/**
|
|
506
|
+
* An open run of world points the gesture is proposing — a cut line, a
|
|
507
|
+
* routed connector. `role` is the whole of what an action says about
|
|
508
|
+
* appearance.
|
|
509
|
+
*/
|
|
510
|
+
kind: 'polyline';
|
|
511
|
+
/** At least two points. Anything shorter is dropped in resolution. */
|
|
512
|
+
points: ReadonlyArray<{
|
|
513
|
+
x: number;
|
|
514
|
+
y: number;
|
|
515
|
+
}>;
|
|
516
|
+
/** What the run means. Omitted reads as {@link OverlayRole} `'chrome'`. */
|
|
517
|
+
role?: OverlayRole;
|
|
518
|
+
} | {
|
|
519
|
+
/**
|
|
520
|
+
* A round brush dragged through world points: the area it has swept so
|
|
521
|
+
* far, and its footprint at the last point. The radius is in screen
|
|
522
|
+
* pixels, so the footprint keeps its size at every zoom.
|
|
523
|
+
*/
|
|
524
|
+
kind: 'brush';
|
|
525
|
+
/** The brush's path so far, at least one point; the last is where it is now. */
|
|
526
|
+
points: ReadonlyArray<{
|
|
527
|
+
x: number;
|
|
528
|
+
y: number;
|
|
529
|
+
}>;
|
|
530
|
+
radiusPx: number;
|
|
531
|
+
} | {
|
|
532
|
+
/**
|
|
533
|
+
* Live insert-drag preview. Pre-commit there is no scene node to ghost
|
|
534
|
+
* via `previewIds()`/`previewPose()`, so insert paints its preview
|
|
535
|
+
* through the overlay instead.
|
|
536
|
+
*
|
|
537
|
+
* `bounds` is the AABB of the current drag (start/current normalized).
|
|
538
|
+
* `extras` is the per-kind extras the action already collected; the
|
|
539
|
+
* overlay renderer narrows on `shape` and casts the field shape it
|
|
540
|
+
* expects.
|
|
541
|
+
*/
|
|
542
|
+
kind: 'insertPreview';
|
|
543
|
+
/** Which preview the dispatcher's overlay draws. The kit's own shape
|
|
544
|
+
* kinds are the ones it knows how to render; a consumer-defined kind
|
|
545
|
+
* is legal and simply gets no live preview. */
|
|
546
|
+
shape: string;
|
|
547
|
+
bounds: {
|
|
548
|
+
x: number;
|
|
549
|
+
y: number;
|
|
550
|
+
width: number;
|
|
551
|
+
height: number;
|
|
552
|
+
};
|
|
553
|
+
extras: unknown;
|
|
554
|
+
/** World-space point to paint a small "anchor" dot at, marking the
|
|
555
|
+
* click point — for radial shapes (polygon/star), where no vertex
|
|
556
|
+
* sits on it, and for any shape in center mode. */
|
|
557
|
+
anchorPoint?: {
|
|
558
|
+
x: number;
|
|
559
|
+
y: number;
|
|
560
|
+
};
|
|
561
|
+
/** World affines the shape will also be drawn under once it lands, by
|
|
562
|
+
* the container it is drawn into: the preview is painted under each. */
|
|
563
|
+
copies?: readonly (readonly [number, number, number, number, number, number])[];
|
|
564
|
+
};
|
|
565
|
+
/** A handle's overlays as a list: empty when it has none. */
|
|
566
|
+
declare function overlaysOf(handle: OngoingHandle): readonly OngoingOverlay[];
|
|
567
|
+
|
|
526
568
|
/**
|
|
527
569
|
* Invoker — pluggable invocation strategy for an Action.
|
|
528
570
|
*
|
|
@@ -531,11 +573,8 @@ declare const DEFAULT_DEVICE_PROFILE: DeviceProfile;
|
|
|
531
573
|
* driven by the dispatcher (move, resize, pinch-zoom).
|
|
532
574
|
*/
|
|
533
575
|
|
|
534
|
-
/** A 2D point in either world or screen coordinates
|
|
535
|
-
|
|
536
|
-
x: number;
|
|
537
|
-
y: number;
|
|
538
|
-
}
|
|
576
|
+
/** A 2D point in either world or screen coordinates; geom's `Point`. */
|
|
577
|
+
type Point2 = Point;
|
|
539
578
|
/**
|
|
540
579
|
* Which UI affordance was hit at pointerdown. Populated by the dispatcher when
|
|
541
580
|
* the `affordanceAt` thunk is provided to `useGestureDispatcher`.
|
|
@@ -543,6 +582,8 @@ interface Point2 {
|
|
|
543
582
|
* `kind` is a discriminator string:
|
|
544
583
|
* - `'handle:top-left'` / `'handle:top-right'` / `'handle:bottom-left'` /
|
|
545
584
|
* `'handle:bottom-right'` — corner resize handles.
|
|
585
|
+
* - `'handle:top'` / `'handle:right'` / `'handle:bottom'` / `'handle:left'` —
|
|
586
|
+
* edge resize handles.
|
|
546
587
|
* - `'rotate-handle'` — the rotation affordance.
|
|
547
588
|
* - `'anchor:N'` — a path anchor at index N.
|
|
548
589
|
*/
|
|
@@ -565,8 +606,8 @@ interface AffordanceHit {
|
|
|
565
606
|
};
|
|
566
607
|
/** Which nodes this affordance belongs to. */
|
|
567
608
|
targetIds?: string[];
|
|
568
|
-
/** Set only when `kind` matches `'handle:*'`: which corner stays
|
|
569
|
-
* during a resize. */
|
|
609
|
+
/** Set only when `kind` matches `'handle:*'`: which corner or edge stays
|
|
610
|
+
* fixed during a resize; `'free'` on the axis an edge handle leaves alone. */
|
|
570
611
|
anchor?: ResizeAnchor;
|
|
571
612
|
/** Cursor to show while the pointer hovers this affordance (no gesture in
|
|
572
613
|
* flight). Unset falls through to action-cursor prediction, then to the
|
|
@@ -676,6 +717,12 @@ interface InvocationCtx {
|
|
|
676
717
|
key: string;
|
|
677
718
|
repeat: boolean;
|
|
678
719
|
};
|
|
720
|
+
/** What a carry over the surface brings: its payload, as `startCarry` was
|
|
721
|
+
* handed it. Present for every event of a `carry` binding's gesture. */
|
|
722
|
+
carry?: {
|
|
723
|
+
type: string;
|
|
724
|
+
value: unknown;
|
|
725
|
+
};
|
|
679
726
|
/**
|
|
680
727
|
* The view the input landed in, as the surface's view resolver assigned it:
|
|
681
728
|
* a view id, or `null` for the surface's own camera. Absent where no
|
|
@@ -689,6 +736,13 @@ interface InvocationCtx {
|
|
|
689
736
|
* params via `BindingOpts.params` on `start` (the `opts` arg).
|
|
690
737
|
*/
|
|
691
738
|
params?: Record<string, unknown>;
|
|
739
|
+
/**
|
|
740
|
+
* Which of the action's `modifierRoles` are held for this event, by role
|
|
741
|
+
* id. The dispatcher fills it on every event of a gesture whose action
|
|
742
|
+
* declares roles; absent otherwise. Read it through `roleReader`, which
|
|
743
|
+
* falls back to the roles' default keys where it is absent.
|
|
744
|
+
*/
|
|
745
|
+
roles?: Readonly<Record<string, boolean>>;
|
|
692
746
|
}
|
|
693
747
|
/** Per-invocation options the dispatcher reads from a `GestureBinding`'s
|
|
694
748
|
* `opts` field and passes to `OngoingInvoker.start`. */
|
|
@@ -723,6 +777,11 @@ interface BindingOpts {
|
|
|
723
777
|
* binding; this tells the route-conflict check the order is the design.
|
|
724
778
|
*/
|
|
725
779
|
yields?: boolean;
|
|
780
|
+
/**
|
|
781
|
+
* Keys for some of the action's `modifierRoles` on this binding, by role
|
|
782
|
+
* id, over the action's defaults and any tuning's.
|
|
783
|
+
*/
|
|
784
|
+
roles?: RoleRebinds;
|
|
726
785
|
}
|
|
727
786
|
/** Resolve `BindingOpts.params` to a concrete record (calling the thunk if
|
|
728
787
|
* needed). Returns `undefined` for absent params. */
|
|
@@ -734,98 +793,7 @@ declare function resolveParams(params: BindingOpts['params']): Record<string, un
|
|
|
734
793
|
interface ActionDeps extends Partial<DepSchema> {
|
|
735
794
|
[k: string]: unknown;
|
|
736
795
|
}
|
|
737
|
-
|
|
738
|
-
* What a `polyline` overlay is, in a word — the narrowest thing an action can
|
|
739
|
-
* say about how its run should look without naming a paint.
|
|
740
|
-
*
|
|
741
|
-
* The named roles are the kit's; a painter maps each to a style and falls back
|
|
742
|
-
* to plain chrome for one it does not know, so a package outside core can coin
|
|
743
|
-
* its own and still be drawn.
|
|
744
|
-
*/
|
|
745
|
-
type OverlayRole =
|
|
746
|
-
/** Generic in-flight chrome — the marquee/lasso paint. */
|
|
747
|
-
'chrome'
|
|
748
|
-
/** A cut the gesture would make. */
|
|
749
|
-
| 'cut'
|
|
750
|
-
/** An edge the gesture would author between two points. */
|
|
751
|
-
| 'connector' | (string & {});
|
|
752
|
-
/**
|
|
753
|
-
* What an in-flight gesture proposes to paint *beside* the scene, returned by
|
|
754
|
-
* `OngoingHandle.overlay()` — a marquee rect, a lasso trail, the outline of a
|
|
755
|
-
* shape being dragged out, the line a slice would cut along.
|
|
756
|
-
*
|
|
757
|
-
* Every variant is world geometry and nothing else — no `DrawCommand`, no
|
|
758
|
-
* color, no coordinate space to choose — so a surface rendering the same
|
|
759
|
-
* gesture some other way can still read it. The painter owns every style
|
|
760
|
-
* decision.
|
|
761
|
-
*/
|
|
762
|
-
type OngoingOverlay = {
|
|
763
|
-
kind: 'marquee';
|
|
764
|
-
start: {
|
|
765
|
-
x: number;
|
|
766
|
-
y: number;
|
|
767
|
-
};
|
|
768
|
-
current: {
|
|
769
|
-
x: number;
|
|
770
|
-
y: number;
|
|
771
|
-
};
|
|
772
|
-
shiftHeld: boolean;
|
|
773
|
-
} | {
|
|
774
|
-
kind: 'lasso';
|
|
775
|
-
vertices: ReadonlyArray<{
|
|
776
|
-
x: number;
|
|
777
|
-
y: number;
|
|
778
|
-
}>;
|
|
779
|
-
current: {
|
|
780
|
-
x: number;
|
|
781
|
-
y: number;
|
|
782
|
-
};
|
|
783
|
-
shiftHeld: boolean;
|
|
784
|
-
} | {
|
|
785
|
-
/**
|
|
786
|
-
* An open run of world points the gesture is proposing — a cut line, a
|
|
787
|
-
* routed connector. `role` is the whole of what an action says about
|
|
788
|
-
* appearance.
|
|
789
|
-
*/
|
|
790
|
-
kind: 'polyline';
|
|
791
|
-
/** At least two points. Anything shorter is dropped in resolution. */
|
|
792
|
-
points: ReadonlyArray<{
|
|
793
|
-
x: number;
|
|
794
|
-
y: number;
|
|
795
|
-
}>;
|
|
796
|
-
/** What the run means. Omitted reads as {@link OverlayRole} `'chrome'`. */
|
|
797
|
-
role?: OverlayRole;
|
|
798
|
-
} | {
|
|
799
|
-
/**
|
|
800
|
-
* Live insert-drag preview. Pre-commit there is no scene node to ghost
|
|
801
|
-
* via `previewIds()`/`previewPose()`, so insert paints its preview
|
|
802
|
-
* through the overlay instead.
|
|
803
|
-
*
|
|
804
|
-
* `bounds` is the AABB of the current drag (start/current normalized).
|
|
805
|
-
* `extras` is the per-kind extras the action already collected; the
|
|
806
|
-
* overlay renderer narrows on `shape` and casts the field shape it
|
|
807
|
-
* expects.
|
|
808
|
-
*/
|
|
809
|
-
kind: 'insertPreview';
|
|
810
|
-
/** Which preview the dispatcher's overlay draws. The kit's own shape
|
|
811
|
-
* kinds are the ones it knows how to render; a consumer-defined kind
|
|
812
|
-
* is legal and simply gets no live preview. */
|
|
813
|
-
shape: string;
|
|
814
|
-
bounds: {
|
|
815
|
-
x: number;
|
|
816
|
-
y: number;
|
|
817
|
-
width: number;
|
|
818
|
-
height: number;
|
|
819
|
-
};
|
|
820
|
-
extras: unknown;
|
|
821
|
-
/** World-space point to paint a small "anchor" dot at, marking the
|
|
822
|
-
* click point — for radial shapes (polygon/star), where no vertex
|
|
823
|
-
* sits on it, and for any shape in center mode. */
|
|
824
|
-
anchorPoint?: {
|
|
825
|
-
x: number;
|
|
826
|
-
y: number;
|
|
827
|
-
};
|
|
828
|
-
};
|
|
796
|
+
|
|
829
797
|
/** Handle returned from an `OngoingInvoker.start`. The dispatcher pumps
|
|
830
798
|
* `onMove` on subsequent input events of the same gesture and calls
|
|
831
799
|
* `onEnd` exactly once (with `'commit'` on natural completion or `'cancel'`
|
|
@@ -840,6 +808,12 @@ interface OngoingHandle {
|
|
|
840
808
|
* handle is in flight.
|
|
841
809
|
*/
|
|
842
810
|
kind?: string;
|
|
811
|
+
/**
|
|
812
|
+
* The cursor this gesture shows now, read after every move. Wins over the
|
|
813
|
+
* action's `activeCursor`, for a cursor that follows the gesture — the
|
|
814
|
+
* rotate glyph turning about its pivot. `undefined` defers to the action.
|
|
815
|
+
*/
|
|
816
|
+
cursor?(): CursorSpec | undefined;
|
|
843
817
|
onMove?(ctx: InvocationCtx): void;
|
|
844
818
|
onEnd?(ctx: InvocationCtx, reason: 'commit' | 'cancel'): void;
|
|
845
819
|
/**
|
|
@@ -876,10 +850,19 @@ interface OngoingHandle {
|
|
|
876
850
|
previewData?(id: string): unknown | null;
|
|
877
851
|
/**
|
|
878
852
|
* Optional chrome surface: a non-ghost visual (marquee rectangle, lasso
|
|
879
|
-
* polyline) painted while the gesture is in flight
|
|
880
|
-
*
|
|
853
|
+
* polyline) painted while the gesture is in flight — one, or a list for a
|
|
854
|
+
* gesture showing several runs at once. Returning `null`, or omitting the
|
|
855
|
+
* method, means "no overlay this gesture". Read it through
|
|
856
|
+
* {@link overlaysOf}, which answers a list either way.
|
|
857
|
+
*/
|
|
858
|
+
overlay?(): OngoingOverlay | readonly OngoingOverlay[] | null;
|
|
859
|
+
/**
|
|
860
|
+
* A wheel turned while this gesture is in flight — scrubbing a value the
|
|
861
|
+
* drag is using, say. Return `true` to claim the wheel, so no wheel binding
|
|
862
|
+
* (the viewport's zoom or pan) sees it; anything else lets it through.
|
|
863
|
+
* Omit it and the wheel goes to the bindings as usual.
|
|
881
864
|
*/
|
|
882
|
-
|
|
865
|
+
onWheel?(ctx: InvocationCtx): boolean | void;
|
|
883
866
|
}
|
|
884
867
|
/** Fire-once invocation. Runs to completion synchronously (or fires off an
|
|
885
868
|
* async side-effect; the registry doesn't wait). */
|
|
@@ -903,8 +886,6 @@ type Invoker = ImmediateInvoker | OngoingInvoker;
|
|
|
903
886
|
* GestureBinding — connects a GestureSpec to an Action id (with per-binding
|
|
904
887
|
* options). Tools own arrays of these on their `bindings` field; ambient
|
|
905
888
|
* gesture-bindings are registered globally.
|
|
906
|
-
*
|
|
907
|
-
* See `docs/superpowers/specs/2026-05-16-registry-unification-design.md`.
|
|
908
889
|
*/
|
|
909
890
|
|
|
910
891
|
/** An interaction: a gesture spec composed with the id of the action it
|
|
@@ -916,7 +897,6 @@ interface GestureBinding {
|
|
|
916
897
|
opts?: BindingOpts;
|
|
917
898
|
}
|
|
918
899
|
/**
|
|
919
|
-
* @experimental
|
|
920
900
|
* A single entry in `Action.defaultBinding[]`. Either a bare `GestureSpec`
|
|
921
901
|
* (no per-binding opts) or an object form that pairs a spec with
|
|
922
902
|
* `BindingOpts` for parametric actions (e.g. `{ params: { axis: 'x' } }`).
|
|
@@ -929,7 +909,6 @@ type BoundGesture = GestureSpec | {
|
|
|
929
909
|
opts: BindingOpts;
|
|
930
910
|
};
|
|
931
911
|
/**
|
|
932
|
-
* @experimental
|
|
933
912
|
* The whole of an action `actionBindings` reads. Routing needs this much and
|
|
934
913
|
* none of `Action`'s palette fields, so it is the narrowest type the
|
|
935
914
|
* dispatcher's binding walk can be written against.
|
|
@@ -946,14 +925,12 @@ interface BindingSource {
|
|
|
946
925
|
defaultBinding?: GestureSpec | BoundGesture[];
|
|
947
926
|
}
|
|
948
927
|
/**
|
|
949
|
-
* @experimental
|
|
950
928
|
* Flatten an action's `defaultBinding` into `GestureBinding`s. A bare
|
|
951
929
|
* `GestureSpec` has `kind` at top level; the object form has `spec`.
|
|
952
930
|
*/
|
|
953
931
|
declare function actionBindings(action: BindingSource): GestureBinding[];
|
|
954
932
|
|
|
955
933
|
/**
|
|
956
|
-
* @experimental
|
|
957
934
|
* Closed enum of reasons an action might report itself as disabled. The
|
|
958
935
|
* consumer (palette, menu, etc.) maps these symbolic values to display
|
|
959
936
|
* strings via its own label map.
|
|
@@ -968,20 +945,23 @@ declare const ActionDisabledReason: {
|
|
|
968
945
|
/** Why an action is unavailable right now. */
|
|
969
946
|
type ActionDisabledReason = (typeof ActionDisabledReason)[keyof typeof ActionDisabledReason];
|
|
970
947
|
/**
|
|
971
|
-
* @experimental
|
|
972
948
|
* What a palette, menu or toolbar renders for an action. No part of this is
|
|
973
949
|
* read during dispatch.
|
|
974
950
|
*/
|
|
975
951
|
interface ActionPresentation {
|
|
976
952
|
label: string;
|
|
977
|
-
/**
|
|
978
|
-
|
|
979
|
-
* "lock" toggle). */
|
|
980
|
-
icon?: ReactNode | (() => ReactNode);
|
|
953
|
+
/** The action's icon, by qualified name: `icon('group')` in the package that draws it. */
|
|
954
|
+
icon?: IconRef;
|
|
981
955
|
/** Grouping key for palette/menu surfaces. Free-form string; the kit
|
|
982
956
|
* ships defaults for `'align'` (six edges/centers), `'distribute'`
|
|
983
957
|
* (two axes), and recommends `'pathfinder'` for boolean ops. */
|
|
984
958
|
group?: string;
|
|
959
|
+
/** Words the action is also found by and gathered under. Where `group` is
|
|
960
|
+
* the one place an action sits, an action carries any number of tags: a
|
|
961
|
+
* palette search matches them as it matches the label, and
|
|
962
|
+
* `actionsTagged` / `taggedActionItems` gather every action or entry
|
|
963
|
+
* carrying one, for a bar or a menu built from a tag. */
|
|
964
|
+
tags?: readonly string[];
|
|
985
965
|
/** Display override for the keyboard shortcut. When omitted, palette
|
|
986
966
|
* surfaces derive a label from `defaultBinding` via their own
|
|
987
967
|
* formatter. */
|
|
@@ -994,7 +974,6 @@ interface ActionPresentation {
|
|
|
994
974
|
variants?: readonly ActionVariant[];
|
|
995
975
|
}
|
|
996
976
|
/**
|
|
997
|
-
* @experimental
|
|
998
977
|
* One entry a parametric action contributes to a bar, menu or palette.
|
|
999
978
|
*/
|
|
1000
979
|
interface ActionVariant {
|
|
@@ -1002,13 +981,14 @@ interface ActionVariant {
|
|
|
1002
981
|
key: string;
|
|
1003
982
|
label: string;
|
|
1004
983
|
/** Falls back to the action's own `icon`. */
|
|
1005
|
-
icon?:
|
|
984
|
+
icon?: IconRef;
|
|
985
|
+
/** Tags this variant carries besides its action's, which it carries too. */
|
|
986
|
+
tags?: readonly string[];
|
|
1006
987
|
/** Passed to `trigger`, and matched against each binding's
|
|
1007
988
|
* `opts.params` to find the variant's shortcuts. */
|
|
1008
989
|
params: Readonly<Record<string, unknown>>;
|
|
1009
990
|
}
|
|
1010
991
|
/**
|
|
1011
|
-
* @experimental
|
|
1012
992
|
* What routing consults: the bindings that reach the action, the deps its
|
|
1013
993
|
* invoker reads, the gates it passes, and the cursors it claims.
|
|
1014
994
|
*/
|
|
@@ -1030,14 +1010,14 @@ interface ActionDispatch extends BindingSource {
|
|
|
1030
1010
|
* shortcuts and global held-key triggers. Default: ambient. */
|
|
1031
1011
|
scope?: 'hotkey';
|
|
1032
1012
|
/**
|
|
1033
|
-
* @experimental
|
|
1034
1013
|
* Optional predicate saying whether the action can run right now. Return
|
|
1035
1014
|
* `true` when it can, or an `ActionDisabledReason` when it cannot. The
|
|
1036
1015
|
* command palette greys out a disabled row, skips it in keyboard nav,
|
|
1037
1016
|
* ignores clicks, and shows the reason next to the label. The dispatcher
|
|
1038
1017
|
* skips a disabled action too, on a key as on a pointer, and falls through
|
|
1039
|
-
* to the next binding that matches. `ActionsRegistry.trigger`
|
|
1040
|
-
*
|
|
1018
|
+
* to the next binding that matches. `ActionsRegistry.trigger` asks too, but
|
|
1019
|
+
* with no point, so a `run` whose answer depends on `at` should still
|
|
1020
|
+
* self-guard.
|
|
1041
1021
|
*
|
|
1042
1022
|
* **Contract:** must be pure (no side effects), fast (< 4ms in dev), and
|
|
1043
1023
|
* must not throw. A throw is caught and treated as disabled with reason
|
|
@@ -1052,8 +1032,10 @@ interface ActionDispatch extends BindingSource {
|
|
|
1052
1032
|
* click, a press, a long-press. An action that only applies somewhere
|
|
1053
1033
|
* (on a path segment, say) refuses other points here, so the dispatcher
|
|
1054
1034
|
* falls through to the next binding and hover prediction shows the
|
|
1055
|
-
* action's `cursor` only where it would act.
|
|
1056
|
-
*
|
|
1035
|
+
* action's `cursor` only where it would act. `trigger` passes the
|
|
1036
|
+
* `worldX`/`worldY` its params carry, so a menu row is run under the
|
|
1037
|
+
* question it was shown enabled for. Palettes and keystrokes pass no
|
|
1038
|
+
* point; treat absent as "anywhere".
|
|
1057
1039
|
*
|
|
1058
1040
|
* `carried` is what a drop or a paste being routed brings: its items. For
|
|
1059
1041
|
* a drag still in flight they hold a MIME and nothing else, since a
|
|
@@ -1068,7 +1050,6 @@ interface ActionDispatch extends BindingSource {
|
|
|
1068
1050
|
items: readonly IngestItem[];
|
|
1069
1051
|
}) => true | ActionDisabledReason;
|
|
1070
1052
|
/**
|
|
1071
|
-
* @experimental
|
|
1072
1053
|
* Whether the action reads as held down right now: bold on the selected
|
|
1073
1054
|
* text, snapping switched on. A toolbar button draws it as pressed.
|
|
1074
1055
|
* Omitted = the action has no pressed state, which is not the same as
|
|
@@ -1078,6 +1059,15 @@ interface ActionDispatch extends BindingSource {
|
|
|
1078
1059
|
* throw. `deps` is the bag `enabled` is given.
|
|
1079
1060
|
*/
|
|
1080
1061
|
active?: (deps?: ActionDeps) => boolean;
|
|
1062
|
+
/**
|
|
1063
|
+
* Show what running the action now would do, and change nothing: the
|
|
1064
|
+
* result an operation would make, drawn over the canvas. A toolbar asks
|
|
1065
|
+
* while its button is hovered or focused, through
|
|
1066
|
+
* `ActionsRegistry.preview`, and calls what this returns when that ends.
|
|
1067
|
+
* Asked only while `enabled` says yes, with the deps and params `run`
|
|
1068
|
+
* would get. Omitted = the action has nothing to show.
|
|
1069
|
+
*/
|
|
1070
|
+
preview?: (deps: ActionDeps, params?: Record<string, unknown>) => (() => void) | void;
|
|
1081
1071
|
/**
|
|
1082
1072
|
* Declarative eligibility rule, evaluated against the current
|
|
1083
1073
|
* `RuleCtx` by the dispatcher before invoking `start()`. Omitted =
|
|
@@ -1100,12 +1090,14 @@ interface ActionDispatch extends BindingSource {
|
|
|
1100
1090
|
* resolved earlier in the pump via `AffordanceRegion.cursor` and never
|
|
1101
1091
|
* reach this field.
|
|
1102
1092
|
*
|
|
1103
|
-
*
|
|
1104
|
-
*
|
|
1105
|
-
*
|
|
1106
|
-
*
|
|
1093
|
+
* A function is asked each time with the params the winning binding would
|
|
1094
|
+
* start the action with, tunings included, so a cursor can follow them — a
|
|
1095
|
+
* brush ring as wide as the brush. Read it through {@link actionCursor}.
|
|
1096
|
+
* Prediction runs `enabled()` but cannot run the invoker, so an action that
|
|
1097
|
+
* matches yet bails at `start()` (empty handle) may still show its cursor —
|
|
1098
|
+
* keep `enabled` accurate for actions that declare one.
|
|
1107
1099
|
*/
|
|
1108
|
-
cursor?: CursorSpec;
|
|
1100
|
+
cursor?: CursorSpec | ((params: Record<string, unknown> | undefined) => CursorSpec | undefined);
|
|
1109
1101
|
/**
|
|
1110
1102
|
* CSS cursor shown while THIS action's ongoing handle is in flight —
|
|
1111
1103
|
* grabbing while panning, `move` while dragging a selection, `crosshair`
|
|
@@ -1118,15 +1110,22 @@ interface ActionDispatch extends BindingSource {
|
|
|
1118
1110
|
* gesture.
|
|
1119
1111
|
*/
|
|
1120
1112
|
activeCursor?: CursorSpec;
|
|
1113
|
+
/**
|
|
1114
|
+
* The modifiers an ongoing action reads while it runs, by role: Shift
|
|
1115
|
+
* holding a handle's angle, Alt breaking its mirror. The dispatcher resolves
|
|
1116
|
+
* each into `InvocationCtx.roles` on the press, every move, and the release,
|
|
1117
|
+
* so a binding's `opts.roles` or a tuning's `roles` can move one to another
|
|
1118
|
+
* key. Read them with {@link roleReader}. A binding's own `mods` are matched
|
|
1119
|
+
* once, at the press; these are read throughout.
|
|
1120
|
+
*/
|
|
1121
|
+
modifierRoles?: ModifierRoles;
|
|
1121
1122
|
}
|
|
1122
1123
|
/**
|
|
1123
|
-
* @experimental
|
|
1124
1124
|
* Single registered action.
|
|
1125
1125
|
*/
|
|
1126
1126
|
interface Action extends ActionDispatch, ActionPresentation {
|
|
1127
1127
|
}
|
|
1128
1128
|
/**
|
|
1129
|
-
* @experimental
|
|
1130
1129
|
* The whole of an actions registry the dispatcher reads. It walks the list
|
|
1131
1130
|
* once per event to build its actionId lookup and never mutates it, so the
|
|
1132
1131
|
* routing side depends on this rather than on `ActionsRegistry`, whose
|
|
@@ -1135,37 +1134,314 @@ interface Action extends ActionDispatch, ActionPresentation {
|
|
|
1135
1134
|
interface ActionSource {
|
|
1136
1135
|
list(): readonly Action[];
|
|
1137
1136
|
}
|
|
1137
|
+
/** `action`'s hover cursor for an invocation given `params`: its `cursor`,
|
|
1138
|
+
* asked when it is a function. */
|
|
1139
|
+
declare function actionCursor(action: Pick<Action, 'cursor'> | undefined, params?: Record<string, unknown>): CursorSpec | undefined;
|
|
1140
|
+
|
|
1141
|
+
/** Which canvas hit a menu answers. Every field given must match. */
|
|
1142
|
+
interface MenuWhen {
|
|
1143
|
+
bodyTarget?: BodyTarget | readonly BodyTarget[];
|
|
1144
|
+
bodyKind?: string | readonly string[];
|
|
1145
|
+
}
|
|
1146
|
+
/** A menu as data: a prefs schema drawn as a menu (`resolveSchemaMenu`).
|
|
1147
|
+
* A def without `when` is opened only by id, from chrome. */
|
|
1148
|
+
interface MenuDef {
|
|
1149
|
+
id: string;
|
|
1150
|
+
when?: MenuWhen;
|
|
1151
|
+
menu: PrefGroup;
|
|
1152
|
+
}
|
|
1153
|
+
/** What a right-click landed on. */
|
|
1154
|
+
interface MenuHit {
|
|
1155
|
+
bodyTarget?: BodyTarget;
|
|
1156
|
+
bodyKind?: string;
|
|
1157
|
+
}
|
|
1158
|
+
/** A def with who contributed it: a tool id, or `null` for ambient. */
|
|
1159
|
+
interface OwnedMenuDef {
|
|
1160
|
+
def: MenuDef;
|
|
1161
|
+
owner: string | null;
|
|
1162
|
+
}
|
|
1163
|
+
|
|
1164
|
+
/** What resolving reads: the registered actions, each one's deps, how to run
|
|
1165
|
+
* one, and the values behind the schema's value leaves. */
|
|
1166
|
+
interface MenuSources {
|
|
1167
|
+
actions(): readonly Action[];
|
|
1168
|
+
depsFor(action: Action): ActionDeps | undefined;
|
|
1169
|
+
trigger(id: string, params?: Record<string, unknown>): boolean;
|
|
1170
|
+
/** The value at a leaf's dotted path. Booleans, enums, and numbers are left
|
|
1171
|
+
* out of a menu without both this and `onChange`, colors and strings without
|
|
1172
|
+
* this, and `showIf`/`enableIf` are checked only with it. */
|
|
1173
|
+
values?(path: string): unknown;
|
|
1174
|
+
onChange?(path: string, value: unknown): void;
|
|
1175
|
+
/** The schema an `alias` leaf's `of` is read in. Default: the menu's own. */
|
|
1176
|
+
over?: PrefGroup;
|
|
1177
|
+
}
|
|
1178
|
+
/**
|
|
1179
|
+
* Draw a prefs schema as menu entries. Action leaves become items from the
|
|
1180
|
+
* registry (one per variant for a parametric action), an `actions` leaf one
|
|
1181
|
+
* item per action in its group, a boolean a checked item, an enum radio
|
|
1182
|
+
* rows, and a number a row edited in place (all through `src.values`/`src.onChange`);
|
|
1183
|
+
* a color shows as a swatch and a string as a disabled row, both read-only. A group drawn `as` a
|
|
1184
|
+
* `menu`, `page`, `tab`, or `panel` is a submenu, and any other group's rows
|
|
1185
|
+
* sit inline between separators. Paint, field, compound, and app-defined leaves are left out.
|
|
1186
|
+
* `at` is the world point the menu was opened at and reaches `enabled` and
|
|
1187
|
+
* every action's params; `params` go to every action, under its own.
|
|
1188
|
+
*/
|
|
1189
|
+
declare function resolveSchemaMenu(schema: PrefGroup, src: MenuSources, at?: Point, params?: Record<string, unknown>): MenuEntry[];
|
|
1190
|
+
/** Turn a declared menu into model entries; see {@link resolveSchemaMenu}. */
|
|
1191
|
+
declare function resolveMenu(def: MenuDef, src: MenuSources, at?: Point, params?: Record<string, unknown>): MenuEntry[];
|
|
1192
|
+
|
|
1193
|
+
/** Ask to open a menu: by id (chrome) or by what was hit (canvas). */
|
|
1194
|
+
interface MenuOpenRequest {
|
|
1195
|
+
menu?: string;
|
|
1196
|
+
hit?: MenuHit;
|
|
1197
|
+
/** Viewport point the menu is placed at, unless `under` is set. */
|
|
1198
|
+
client: Point;
|
|
1199
|
+
/** Viewport rect of the button the menu hangs from: placed below it, or above when below does not fit. */
|
|
1200
|
+
under?: Rect;
|
|
1201
|
+
/** World point, passed to `enabled` and to every item. */
|
|
1202
|
+
world?: Point;
|
|
1203
|
+
params?: Record<string, unknown>;
|
|
1204
|
+
source?: 'pointer' | 'keyboard';
|
|
1205
|
+
}
|
|
1206
|
+
/** The menu on screen. `seq` changes on every open, so a renderer remounts. */
|
|
1207
|
+
interface OpenMenu {
|
|
1208
|
+
seq: number;
|
|
1209
|
+
entries: readonly MenuEntry[];
|
|
1210
|
+
client: Point;
|
|
1211
|
+
under?: Rect;
|
|
1212
|
+
world?: Point;
|
|
1213
|
+
source: 'pointer' | 'keyboard';
|
|
1214
|
+
}
|
|
1215
|
+
/** Holds the declared menus and the one open menu. */
|
|
1216
|
+
interface MenuHost {
|
|
1217
|
+
/** Declare a menu; `owner` is a tool id, or `null` for always. Returns a release. */
|
|
1218
|
+
define(def: MenuDef, owner?: string | null): () => void;
|
|
1219
|
+
/** Pick, resolve and show. False when nothing matched or nothing resolved. */
|
|
1220
|
+
open(req: MenuOpenRequest): boolean;
|
|
1221
|
+
/** Whether `open(req)` would show anything. Changes no state and notifies no one. */
|
|
1222
|
+
has(req: MenuOpenRequest): boolean;
|
|
1223
|
+
close(): void;
|
|
1224
|
+
current(): OpenMenu | null;
|
|
1225
|
+
subscribe(fn: () => void): () => void;
|
|
1226
|
+
}
|
|
1227
|
+
/** Creates the host that decides which context menu is open, from the menus registered to it. */
|
|
1228
|
+
declare function createMenuHost(src: MenuSources & {
|
|
1229
|
+
activeTool(): string | null;
|
|
1230
|
+
}): MenuHost;
|
|
1231
|
+
|
|
1232
|
+
/**
|
|
1233
|
+
* The tree both input registries hang on. A provider is a root; every canvas
|
|
1234
|
+
* mounts a scope under the registry in scope; a yoke sits between the two. A
|
|
1235
|
+
* registration lives in the node it was made in, and a lookup starts at a leaf
|
|
1236
|
+
* and walks up, so one canvas never answers for another.
|
|
1237
|
+
*/
|
|
1238
|
+
|
|
1239
|
+
/** What every node of one tree shares: a version and the listeners to it. */
|
|
1240
|
+
interface ScopeTree {
|
|
1241
|
+
version: number;
|
|
1242
|
+
readonly listeners: Emitter;
|
|
1243
|
+
}
|
|
1244
|
+
declare class ScopeNode<N extends ScopeNode<N>> {
|
|
1245
|
+
readonly parent: N | null;
|
|
1246
|
+
readonly descends: boolean;
|
|
1247
|
+
readonly tree: ScopeTree;
|
|
1248
|
+
private readonly children;
|
|
1249
|
+
private activeChild;
|
|
1250
|
+
/** `descends`: whether reads made here answer from the active child down —
|
|
1251
|
+
* true for a root or a yoke, which chrome reads through; false for a scope,
|
|
1252
|
+
* which answers for itself even with a scope nested inside it. */
|
|
1253
|
+
constructor(parent: N | null, descends: boolean);
|
|
1254
|
+
/** Bump the tree's version and tell every listener in it. */
|
|
1255
|
+
changed(): void;
|
|
1256
|
+
/** Join the parent's children, newest last; returns the leave. */
|
|
1257
|
+
mount(): () => void;
|
|
1258
|
+
/** Make this node the one its ancestors resolve through. */
|
|
1259
|
+
activate(): void;
|
|
1260
|
+
/** The node a lookup made here starts from: down the active children, or the
|
|
1261
|
+
* newest where nothing has been activated yet. A yoke with no members yet
|
|
1262
|
+
* is passed over — there is no canvas behind it to answer. */
|
|
1263
|
+
leaf(): N;
|
|
1264
|
+
private newestMember;
|
|
1265
|
+
/** Where a read made through this node starts. */
|
|
1266
|
+
start(): N;
|
|
1267
|
+
/** Whether this node is on the path a read from the root takes. */
|
|
1268
|
+
isActive(): boolean;
|
|
1269
|
+
/** This node, then each ancestor up to the root. */
|
|
1270
|
+
chain(): Generator<N>;
|
|
1271
|
+
}
|
|
1272
|
+
|
|
1273
|
+
/** Which tool is active, plus the stack of tools temporarily held active by a
|
|
1274
|
+
* hotkey (space-for-hand and the like). The dispatcher reads this to decide
|
|
1275
|
+
* whose bindings are in scope. */
|
|
1276
|
+
interface ActiveToolContextValue {
|
|
1277
|
+
/** The focused tool's id, or `null` when no tool holds the active slot —
|
|
1278
|
+
* a canvas can run on ambient bindings alone. */
|
|
1279
|
+
active: string | null;
|
|
1280
|
+
hotkeyStack: string[];
|
|
1281
|
+
setActive(id: string | null): void;
|
|
1282
|
+
pushHotkey(id: string): void;
|
|
1283
|
+
/**
|
|
1284
|
+
* Disengage a hotkey-held tool. With `id`, removes that tool's own entry
|
|
1285
|
+
* wherever it now sits — holds do not have to come up in the order they went
|
|
1286
|
+
* down, and popping the top would disengage a tool whose key is still held.
|
|
1287
|
+
* With no id, pops the top.
|
|
1288
|
+
*/
|
|
1289
|
+
popHotkey(id?: string): void;
|
|
1290
|
+
}
|
|
1291
|
+
/**
|
|
1292
|
+
* One node of the tool tree. A node that `owns` a tool holds its state; one
|
|
1293
|
+
* that does not — a scope inside a yoke — reads and writes its yoke's.
|
|
1294
|
+
*/
|
|
1295
|
+
declare class ToolNode extends ScopeNode<ToolNode> {
|
|
1296
|
+
private state;
|
|
1297
|
+
private value;
|
|
1298
|
+
constructor(parent: ToolNode | null, descends: boolean, owns: boolean, initialActive: string | null);
|
|
1299
|
+
/** The node whose tool a read here resolves to. */
|
|
1300
|
+
owner(): ToolNode;
|
|
1301
|
+
private update;
|
|
1302
|
+
/** A stable value per owner and state, for `useSyncExternalStore`. */
|
|
1303
|
+
snapshot(): ActiveToolContextValue;
|
|
1304
|
+
subscribe: (listener: () => void) => (() => void);
|
|
1305
|
+
}
|
|
1306
|
+
/** Props for `<ActiveToolContextProvider>`. */
|
|
1307
|
+
interface ActiveToolContextProviderProps {
|
|
1308
|
+
children: ReactNode;
|
|
1309
|
+
/** Seeds the active slot, and wins over the first `useTools` call's
|
|
1310
|
+
* `active`. Omitted, the slot starts empty and that call seeds it. */
|
|
1311
|
+
initialActive?: string | null;
|
|
1312
|
+
}
|
|
1313
|
+
/** Provides root active-tool state. Every canvas below has a tool of its own;
|
|
1314
|
+
* reads and writes here reach the one last used. */
|
|
1315
|
+
declare function ActiveToolContextProvider({ children, initialActive, }: ActiveToolContextProviderProps): react.JSX.Element;
|
|
1316
|
+
/** The active-tool state in scope. Throws outside a provider; use
|
|
1317
|
+
* `useOptionalActiveToolContext` where one is not guaranteed. */
|
|
1318
|
+
declare function useActiveToolContext(): ActiveToolContextValue;
|
|
1319
|
+
/**
|
|
1320
|
+
* Like `useActiveToolContext`, but returns `null` when no
|
|
1321
|
+
* `<ActiveToolContextProvider>` is in scope instead of throwing.
|
|
1322
|
+
*/
|
|
1323
|
+
declare function useOptionalActiveToolContext(): ActiveToolContextValue | null;
|
|
1324
|
+
/**
|
|
1325
|
+
* Mounts an `<ActiveToolContextProvider>` only when no parent provider is in
|
|
1326
|
+
* scope; otherwise renders children unwrapped.
|
|
1327
|
+
*/
|
|
1328
|
+
declare function ActiveToolContextProviderIfRoot({ children, }: {
|
|
1329
|
+
children: ReactNode;
|
|
1330
|
+
}): react.JSX.Element;
|
|
1331
|
+
|
|
1332
|
+
/**
|
|
1333
|
+
* Tuning: what a host changes about an action it did not write — the params
|
|
1334
|
+
* every invocation starts from, and bindings added beside the action's own —
|
|
1335
|
+
* without restating the descriptor. `ActionsRegistry.tune` holds tunings and
|
|
1336
|
+
* applies them to whatever descriptor is live for the id.
|
|
1337
|
+
*/
|
|
1338
|
+
|
|
1339
|
+
/** An action's params, or a thunk read each time the action asks for them. */
|
|
1340
|
+
type ActionParams<P = Record<string, unknown>> = Partial<P> | (() => Partial<P>);
|
|
1341
|
+
/** A binding added for an action: a gesture alone, or a gesture with the
|
|
1342
|
+
* options it passes — the {@link BoundGesture} shape, its params typed. */
|
|
1343
|
+
type TunedBinding<P = Record<string, unknown>> = GestureSpec | {
|
|
1344
|
+
spec: GestureSpec;
|
|
1345
|
+
opts: Omit<BindingOpts, 'params'> & {
|
|
1346
|
+
params?: ActionParams<P>;
|
|
1347
|
+
};
|
|
1348
|
+
};
|
|
1349
|
+
/** What a host changes about one action. */
|
|
1350
|
+
interface ActionTuning<P = Record<string, unknown>> {
|
|
1351
|
+
/** Params every invocation starts from. What a binding or a `trigger` call
|
|
1352
|
+
* passes is laid over them, so these fill in what it leaves out. A thunk is
|
|
1353
|
+
* read on every call, and an ongoing action resolving its `opts.params`
|
|
1354
|
+
* mid-gesture sees the value as it is then. */
|
|
1355
|
+
params?: ActionParams<P>;
|
|
1356
|
+
/** Bindings added after the action's own `defaultBinding`. */
|
|
1357
|
+
bindings?: readonly TunedBinding<P>[];
|
|
1358
|
+
/** Keys for some of the action's `modifierRoles`, by role id. A binding's
|
|
1359
|
+
* own `opts.roles` is laid over these. */
|
|
1360
|
+
roles?: RoleRebinds;
|
|
1361
|
+
}
|
|
1362
|
+
/** `action` with each tuning applied in turn, a later one's params over an
|
|
1363
|
+
* earlier one's. Applying a tuning to a copy it already tuned changes nothing. */
|
|
1364
|
+
declare function tuneAction(action: Action, tunings: readonly ActionTuning[]): Action;
|
|
1138
1365
|
|
|
1139
1366
|
/**
|
|
1140
|
-
* @experimental
|
|
1141
1367
|
* The entries an action contributes to a bar, menu or palette — one per
|
|
1142
1368
|
* variant, or the action itself when it declares none.
|
|
1143
1369
|
*/
|
|
1144
1370
|
|
|
1145
|
-
/**
|
|
1371
|
+
/** One renderable entry: an action, optionally with params. */
|
|
1146
1372
|
interface ActionItem {
|
|
1147
1373
|
/** `action.id`, or `action.id:variant.key` — unique across a registry. */
|
|
1148
1374
|
key: string;
|
|
1149
1375
|
action: Action;
|
|
1150
1376
|
label: string;
|
|
1151
|
-
icon?:
|
|
1377
|
+
icon?: IconRef;
|
|
1378
|
+
/** The action's tags, then the variant's own. */
|
|
1379
|
+
tags: readonly string[];
|
|
1152
1380
|
/** What to pass to `trigger(action.id, params)`; absent for a plain action. */
|
|
1153
1381
|
params?: Readonly<Record<string, unknown>>;
|
|
1154
1382
|
}
|
|
1155
|
-
/**
|
|
1383
|
+
/** Expand `action` into the entries a surface renders. An
|
|
1156
1384
|
* action without an immediate invoker has none: `trigger` cannot start a
|
|
1157
1385
|
* drag, so a button for one would do nothing. */
|
|
1158
1386
|
declare function actionItems(action: Action): ActionItem[];
|
|
1387
|
+
/** How a palette titles `item`: a variant reads as its action's
|
|
1388
|
+
* label and its own ("New: A4"), unless its label already holds the action's
|
|
1389
|
+
* as whole words ("Zoom In", "Reset Zoom"). */
|
|
1390
|
+
declare function actionItemTitle(item: ActionItem): string;
|
|
1391
|
+
|
|
1392
|
+
/**
|
|
1393
|
+
* Project an action's keyboard bindings into the shape a shortcut chip
|
|
1394
|
+
* renders from (`formatShortcut` / `formatShortcutParts` in `@weasel-js/ui`).
|
|
1395
|
+
*/
|
|
1396
|
+
|
|
1397
|
+
/** One keyboard shortcut, flattened for display: the chip a menu row draws
|
|
1398
|
+
* (`MenuShortcut` in `@weasel-js/menu`, `ShortcutInput` in `@weasel-js/gestures`). */
|
|
1399
|
+
type ActionShortcut = MenuShortcut;
|
|
1400
|
+
/**
|
|
1401
|
+
* The chip form of a single gesture spec, or `undefined` when the spec has
|
|
1402
|
+
* none.
|
|
1403
|
+
*
|
|
1404
|
+
* - A spec's `key` may list spellings of one keycap (`['[', '{']` — the
|
|
1405
|
+
* shifted bracket reports as `'{'`). The first is the shortcut's name.
|
|
1406
|
+
* - A modifier declared `'optional'` matches held or unheld, so it isn't
|
|
1407
|
+
* part of what the user has to press.
|
|
1408
|
+
*
|
|
1409
|
+
* Non-keyboard specs (drag, wheel, click) have no chip form. Neither does a
|
|
1410
|
+
* *required* `ctrl` or `meta`: the display shape carries only `mod`.
|
|
1411
|
+
*/
|
|
1412
|
+
declare function keySpecShortcut(spec: GestureSpec): ActionShortcut | undefined;
|
|
1413
|
+
/**
|
|
1414
|
+
* Every keyboard shortcut an action answers to, in declaration order.
|
|
1415
|
+
* Specs `keySpecShortcut` has no chip for are skipped, and bindings it leaves
|
|
1416
|
+
* identical are emitted once; an action bound only to those returns empty.
|
|
1417
|
+
*
|
|
1418
|
+
* With `params` — an `ActionItem`'s — only the bindings that pass those same
|
|
1419
|
+
* values count, so each variant of `flip` gets its own key.
|
|
1420
|
+
*/
|
|
1421
|
+
declare function actionShortcuts(action: Action, params?: Readonly<Record<string, unknown>>): readonly ActionShortcut[];
|
|
1422
|
+
|
|
1423
|
+
/**
|
|
1424
|
+
* Finding actions by tag: gathering the ones that carry it, and a person's
|
|
1425
|
+
* search matching it as it matches a label.
|
|
1426
|
+
*/
|
|
1427
|
+
|
|
1428
|
+
/** The actions carrying `tag`, themselves or on any variant, in
|
|
1429
|
+
* the order given. Drags included, which have no entries to show. */
|
|
1430
|
+
declare function actionsTagged(actions: readonly Action[], tag: string): Action[];
|
|
1431
|
+
/** The entries carrying `tag`: what a bar or a menu built from
|
|
1432
|
+
* a tag shows. A variant that does not carry it is left out. */
|
|
1433
|
+
declare function taggedActionItems(actions: readonly Action[], tag: string): ActionItem[];
|
|
1434
|
+
/** Whether `item` answers a search for `query`, by its palette title or
|
|
1435
|
+
* by a tag, and which. */
|
|
1436
|
+
declare function matchActionItem(item: ActionItem, query: string): QueryMatch | null;
|
|
1159
1437
|
|
|
1160
1438
|
/**
|
|
1161
|
-
* @experimental
|
|
1162
1439
|
* Palette-side evaluation of `Action.enabled`. The dispatcher calls the
|
|
1163
1440
|
* predicate raw as a gate; this is the surface that also enforces the
|
|
1164
1441
|
* contract the predicate's JSDoc states — no throwing, under 4ms in dev.
|
|
1165
1442
|
*/
|
|
1166
1443
|
|
|
1167
1444
|
/**
|
|
1168
|
-
* @experimental
|
|
1169
1445
|
* Result of evaluating an Action's `enabled` predicate.
|
|
1170
1446
|
*/
|
|
1171
1447
|
interface ActionEnabledResult {
|
|
@@ -1173,16 +1449,17 @@ interface ActionEnabledResult {
|
|
|
1173
1449
|
reason?: ActionDisabledReason;
|
|
1174
1450
|
}
|
|
1175
1451
|
/**
|
|
1176
|
-
* @experimental
|
|
1177
1452
|
* Safely evaluate an action's `enabled` predicate. Returns `{enabled: true}`
|
|
1178
1453
|
* when no predicate is supplied. Catches throws and treats them as disabled
|
|
1179
1454
|
* with reason `'(predicate threw)'`. In dev mode, warns once per action id
|
|
1180
1455
|
* when a single call exceeds 4ms (single frame at 240fps — generous; real
|
|
1181
1456
|
* predicates should be sub-millisecond).
|
|
1182
1457
|
*/
|
|
1183
|
-
declare function evaluateEnabled(action: Action, deps?: ActionDeps
|
|
1458
|
+
declare function evaluateEnabled(action: Action, deps?: ActionDeps, at?: {
|
|
1459
|
+
x: number;
|
|
1460
|
+
y: number;
|
|
1461
|
+
}): ActionEnabledResult;
|
|
1184
1462
|
/**
|
|
1185
|
-
* @experimental
|
|
1186
1463
|
* Safely evaluate an action's `active` predicate. `undefined` for an action
|
|
1187
1464
|
* with no pressed state; a predicate that throws reads as not active.
|
|
1188
1465
|
*/
|
|
@@ -1253,9 +1530,8 @@ type HotkeyTrigger = 'space' | 'alt' | 'ctrl' | 'meta' | 'shift' | (string & {})
|
|
|
1253
1530
|
interface ToolPresentation {
|
|
1254
1531
|
/** Human-readable label, distinct from the `id`. Falls back to `id`. */
|
|
1255
1532
|
label?: string;
|
|
1256
|
-
/**
|
|
1257
|
-
|
|
1258
|
-
icon?: react.ReactNode | (() => react.ReactNode);
|
|
1533
|
+
/** The tool's icon, by qualified name: `icon('rect')` in the package that draws it. */
|
|
1534
|
+
icon?: _weasel_js_icons.IconRef;
|
|
1259
1535
|
/** Palette grouping key. Tools sharing a group render contiguously
|
|
1260
1536
|
* with separators between groups. Free-form string; the kit
|
|
1261
1537
|
* recommends 'select' | 'shape' | 'draw' | 'type' | 'view'. */
|
|
@@ -1305,6 +1581,8 @@ interface ContributionRouting {
|
|
|
1305
1581
|
eligibility: Eligibility;
|
|
1306
1582
|
bindings?: GestureBinding[];
|
|
1307
1583
|
actions?: Action[];
|
|
1584
|
+
/** Menus this entry declares: always, for an ambient entry; while active, for a tool. */
|
|
1585
|
+
menus?: MenuDef[];
|
|
1308
1586
|
/** Dep sources this entry provides while it is installed. A host installs
|
|
1309
1587
|
* them for as long as the entry is registered, whatever its eligibility. */
|
|
1310
1588
|
deps?: ContributionDeps;
|
|
@@ -1617,6 +1895,8 @@ interface ResolveOnlyResult {
|
|
|
1617
1895
|
scope: BindingScope;
|
|
1618
1896
|
/** Tool id owning the winning binding; `null` for ambient action bindings. */
|
|
1619
1897
|
ownerId: string | null;
|
|
1898
|
+
/** The params the winning binding would start the action with, resolved now. */
|
|
1899
|
+
params?: Record<string, unknown>;
|
|
1620
1900
|
}
|
|
1621
1901
|
/**
|
|
1622
1902
|
* One candidate from `Dispatcher.resolveAll` — a binding that matched the
|
|
@@ -1827,6 +2107,7 @@ declare function recordModeSwitch(mode: string, from: string | null, to: string
|
|
|
1827
2107
|
* with no `pointerId` (a synthesized probe, a programmatic drag, most tests)
|
|
1828
2108
|
* keys to `pointer-mouse`.
|
|
1829
2109
|
* - `multitouch`: `multitouch-<fingers>`.
|
|
2110
|
+
* - `carry`: `carry-<pointerId>`, keyed as a pointer is.
|
|
1830
2111
|
* - any other kind that starts an ongoing invoker: `ongoing-<kind>`.
|
|
1831
2112
|
*/
|
|
1832
2113
|
|
|
@@ -1874,18 +2155,15 @@ declare function createDispatcher(opts?: {
|
|
|
1874
2155
|
}): Dispatcher;
|
|
1875
2156
|
|
|
1876
2157
|
/**
|
|
1877
|
-
* @experimental
|
|
1878
2158
|
* Partial override or full descriptor passed via `<SceneCanvas actions={...}>`.
|
|
1879
2159
|
* `null` disables a default at this id.
|
|
1880
2160
|
*/
|
|
1881
2161
|
type ActionEntry = null | Partial<Action> | Action;
|
|
1882
2162
|
/**
|
|
1883
|
-
* @experimental
|
|
1884
2163
|
* Shape of the `actions` prop on `<SceneCanvas>`. `null` disables all defaults.
|
|
1885
2164
|
*/
|
|
1886
2165
|
type ActionsProp = null | Record<string, ActionEntry>;
|
|
1887
2166
|
/**
|
|
1888
|
-
* @experimental
|
|
1889
2167
|
* Imperative API exposed by `useActionsRegistry()`.
|
|
1890
2168
|
*/
|
|
1891
2169
|
interface ActionsRegistry {
|
|
@@ -1902,14 +2180,29 @@ interface ActionsRegistry {
|
|
|
1902
2180
|
* `trigger` nor `begin` will fire it. Returns a release. This is the
|
|
1903
2181
|
* "not for me" door — `unregister` is the "should not exist" one. */
|
|
1904
2182
|
mute(id: string): () => void;
|
|
2183
|
+
/** Tune `id` here and in scopes below: its params and added bindings
|
|
2184
|
+
* apply to whichever descriptor is live for it, registered before the
|
|
2185
|
+
* tuning or after. Returns a release. See {@link ActionTuning}. */
|
|
2186
|
+
tune(id: string, tuning: ActionTuning): () => void;
|
|
2187
|
+
/** The params an invocation of `id` from this scope starts with when it
|
|
2188
|
+
* passes `given`: every tuning's params, `given` laid over them. What a
|
|
2189
|
+
* tool's chrome reads to show what the action it binds will do. */
|
|
2190
|
+
paramsOf(id: string, given?: Record<string, unknown>): Record<string, unknown>;
|
|
1905
2191
|
list(): readonly Action[];
|
|
1906
2192
|
/** Fire an immediate-invoker action by id. The optional `params` arg is
|
|
1907
2193
|
* forwarded to `ImmediateInvoker.run` as its second argument — use it for
|
|
1908
2194
|
* parametric actions (e.g. `trigger('tool.activate', { toolId: 'rect' })`).
|
|
1909
2195
|
* Returns whether it ran one: `false` for an unknown id, for an action
|
|
1910
2196
|
* whose `enabled` refuses, and for an ongoing-invoker action, which
|
|
1911
|
-
* `trigger` cannot reach (see `begin`). `enabled` is asked
|
|
2197
|
+
* `trigger` cannot reach (see `begin`). `enabled` is asked at
|
|
2198
|
+
* `{ x: params.worldX, y: params.worldY }` when both are numbers, and with
|
|
2199
|
+
* no point otherwise. */
|
|
1912
2200
|
trigger(id: string, params?: Record<string, unknown>): boolean;
|
|
2201
|
+
/** Show what firing `id` with `params` would do, by its `Action.preview`,
|
|
2202
|
+
* and return what takes it down; calling that twice is harmless. Shows
|
|
2203
|
+
* nothing for an unknown id, one with no preview, and one whose `enabled`
|
|
2204
|
+
* refuses, asked as `trigger` asks it. */
|
|
2205
|
+
preview(id: string, params?: Record<string, unknown>): () => void;
|
|
1913
2206
|
/**
|
|
1914
2207
|
* Subscribe to registry mutations. The callback fires after any
|
|
1915
2208
|
* `register`/`unregister` that changes the version. Returns an
|
|
@@ -1977,7 +2270,11 @@ declare function offhandKeyFor(trigger: HotkeyTrigger): string;
|
|
|
1977
2270
|
/** Build the per-tool `BoundGesture` list for the consolidated action's
|
|
1978
2271
|
* `defaultBinding`. Each entry pairs a `key-held` spec with
|
|
1979
2272
|
* `opts.params.toolId` so the invoker's `start` can pick out which tool
|
|
1980
|
-
* to engage.
|
|
2273
|
+
* to engage.
|
|
2274
|
+
*
|
|
2275
|
+
* An offhand tool engages only between gestures. Swapping the tool out
|
|
2276
|
+
* mid-drag would cancel the drag, and the key is free for the gesture's own
|
|
2277
|
+
* tool to use — Space repositions a shape being drawn. */
|
|
1981
2278
|
declare function buildToolOffhandBindings(specs: readonly ToolOffhandBindingSpec[]): BoundGesture[];
|
|
1982
2279
|
/** The `key-held` spec for holding `key` (a `KeyboardEvent.key`, or several).
|
|
1983
2280
|
* A modifier key gets every modifier optional, since its own keydown reports
|
|
@@ -2017,7 +2314,7 @@ declare const isSelectedBody: BodyPredicate;
|
|
|
2017
2314
|
declare const isUnselectedBody: BodyPredicate;
|
|
2018
2315
|
/** Empty-canvas hit — no node beneath cursor. */
|
|
2019
2316
|
declare const isEmpty: BodyPredicate;
|
|
2020
|
-
/** Any
|
|
2317
|
+
/** Any resize handle: a corner (`handle:top-left`, …) or an edge (`handle:top`, …). */
|
|
2021
2318
|
declare const isResizeHandle: TargetPredicate & {
|
|
2022
2319
|
readsAffordance: true;
|
|
2023
2320
|
};
|
|
@@ -2033,10 +2330,28 @@ declare const isAnchor: TargetPredicate & {
|
|
|
2033
2330
|
declare const isControlHandle: TargetPredicate & {
|
|
2034
2331
|
readsAffordance: true;
|
|
2035
2332
|
};
|
|
2333
|
+
/** A corner-shape widget, set inside a corner anchor of the edited path. */
|
|
2334
|
+
declare const isCornerWidget: TargetPredicate & {
|
|
2335
|
+
readsAffordance: true;
|
|
2336
|
+
};
|
|
2036
2337
|
/** Any of the three anchor-editing affordances (anchor + both controls). */
|
|
2037
2338
|
declare const isAnchorOrControl: TargetPredicate & {
|
|
2038
2339
|
readsAffordance: true;
|
|
2039
2340
|
};
|
|
2341
|
+
/** The outline of the path being edited, between its anchors. */
|
|
2342
|
+
declare const isSegment: TargetPredicate & {
|
|
2343
|
+
readsAffordance: true;
|
|
2344
|
+
};
|
|
2345
|
+
/** The grip midway along a curved segment's balance line, `balance:N`, where
|
|
2346
|
+
* N is the flat index of the anchor the segment starts at. */
|
|
2347
|
+
declare const isBalanceGrip: TargetPredicate & {
|
|
2348
|
+
readsAffordance: true;
|
|
2349
|
+
};
|
|
2350
|
+
/** Anything path edit puts on the path: an anchor, a control, a segment, a
|
|
2351
|
+
* segment's balance grip, or a corner widget. */
|
|
2352
|
+
declare const isPathEditPart: TargetPredicate & {
|
|
2353
|
+
readsAffordance: true;
|
|
2354
|
+
};
|
|
2040
2355
|
|
|
2041
2356
|
/** A press being held toward a long-press. */
|
|
2042
2357
|
interface PendingLongPress {
|
|
@@ -2111,6 +2426,29 @@ interface LongPressOptions {
|
|
|
2111
2426
|
/** A store holding the press currently being held, or none. Pass it as `LongPressOptions.state`. */
|
|
2112
2427
|
declare function createLongPressStore(): LongPressStore;
|
|
2113
2428
|
|
|
2429
|
+
/**
|
|
2430
|
+
* The `gestures` kit settings area. Declared here rather than in core because
|
|
2431
|
+
* the dispatcher reads it, and routing sits below core.
|
|
2432
|
+
*/
|
|
2433
|
+
/** Pointer gesture timings and travel; each falls back to its constant in `@weasel-js/gestures`. */
|
|
2434
|
+
interface GestureKitSettings {
|
|
2435
|
+
/** Longest gap between the clicks of a double click, in ms. */
|
|
2436
|
+
doubleClickMs: number;
|
|
2437
|
+
/** Farthest apart the clicks of a double click may land, in CSS px. */
|
|
2438
|
+
doubleClickPx: number;
|
|
2439
|
+
/** How long a touch or pen press is held to fire a long-press, in ms. */
|
|
2440
|
+
longPressMs: number;
|
|
2441
|
+
/** Farthest a multitouch tap's fingers may travel, in CSS px. */
|
|
2442
|
+
tapPx: number;
|
|
2443
|
+
/** Travel that makes a press a drag, in CSS px. */
|
|
2444
|
+
dragPx: number;
|
|
2445
|
+
}
|
|
2446
|
+
declare module '@weasel-js/react' {
|
|
2447
|
+
interface KitSettings {
|
|
2448
|
+
gestures: GestureKitSettings;
|
|
2449
|
+
}
|
|
2450
|
+
}
|
|
2451
|
+
|
|
2114
2452
|
/**
|
|
2115
2453
|
* The DOM half of a drag: one pointer, held down, from press to release.
|
|
2116
2454
|
*
|
|
@@ -2168,6 +2506,60 @@ interface PointerSession {
|
|
|
2168
2506
|
*/
|
|
2169
2507
|
declare function openPointerSession(origin: Element, down: PointerEvent | React.PointerEvent, cb: PointerSessionCallbacks, opts?: PointerSessionOptions): PointerSession;
|
|
2170
2508
|
|
|
2509
|
+
/**
|
|
2510
|
+
* A press that begins on one element and is carried over another: the in-app
|
|
2511
|
+
* sibling of an OS drag. The source opens the carry; every dispatcher with a
|
|
2512
|
+
* `carry` channel registers its element as a surface, and the one under the
|
|
2513
|
+
* pointer dispatches the carry as `carry` events through its bindings.
|
|
2514
|
+
*/
|
|
2515
|
+
|
|
2516
|
+
/** What a carry brings. `type` is what a `carry` spec's `types` globs filter. */
|
|
2517
|
+
interface CarryPayload {
|
|
2518
|
+
type: string;
|
|
2519
|
+
value: unknown;
|
|
2520
|
+
}
|
|
2521
|
+
/** The pointer facts a surface reads off each step of a carry. */
|
|
2522
|
+
interface CarryPointer {
|
|
2523
|
+
clientX: number;
|
|
2524
|
+
clientY: number;
|
|
2525
|
+
altKey: boolean;
|
|
2526
|
+
ctrlKey: boolean;
|
|
2527
|
+
metaKey: boolean;
|
|
2528
|
+
shiftKey: boolean;
|
|
2529
|
+
}
|
|
2530
|
+
/** What a carry did on a surface: came over it, moved on it, was released on
|
|
2531
|
+
* it, or left it — off it, or canceled while over it. */
|
|
2532
|
+
type CarryStage = 'enter' | 'move' | 'drop' | 'leave';
|
|
2533
|
+
/** What {@link startCarry} reports to its source. Exactly one of `onEnd` /
|
|
2534
|
+
* `onCancel` fires. */
|
|
2535
|
+
interface CarryCallbacks {
|
|
2536
|
+
/** Every move of the carrying pointer. */
|
|
2537
|
+
onMove?: (e: PointerEvent) => void;
|
|
2538
|
+
/** The pointer was released. `taken` is whether a binding on the surface
|
|
2539
|
+
* under it took the carry. */
|
|
2540
|
+
onEnd?: (result: {
|
|
2541
|
+
taken: boolean;
|
|
2542
|
+
event: PointerEvent;
|
|
2543
|
+
}) => void;
|
|
2544
|
+
/** The carry ended without a release. Any surface it was over has had its leave. */
|
|
2545
|
+
onCancel?: (reason: PointerSessionCancelReason) => void;
|
|
2546
|
+
}
|
|
2547
|
+
/** A live carry, opened by {@link startCarry}. */
|
|
2548
|
+
interface Carry {
|
|
2549
|
+
readonly pointerId: number;
|
|
2550
|
+
readonly active: boolean;
|
|
2551
|
+
/** End the carry now, as a cancel. Idempotent. */
|
|
2552
|
+
cancel(): void;
|
|
2553
|
+
}
|
|
2554
|
+
/**
|
|
2555
|
+
* Carry `payload` from the press `down` on `origin` until the pointer is
|
|
2556
|
+
* released or the press is canceled. While it moves, the surface under it
|
|
2557
|
+
* hears the carry come over, move, and leave; a release over one is a drop
|
|
2558
|
+
* there. The press is captured to `origin` as any drag is, so nothing the
|
|
2559
|
+
* pointer passes over sees it as a press of its own.
|
|
2560
|
+
*/
|
|
2561
|
+
declare function startCarry(origin: Element, down: PointerEvent | React.PointerEvent, payload: CarryPayload, cb?: CarryCallbacks): Carry;
|
|
2562
|
+
|
|
2171
2563
|
/** What the registry knows at dispatch time. */
|
|
2172
2564
|
interface EligibilityState {
|
|
2173
2565
|
focusedId: string | null;
|
|
@@ -2348,6 +2740,8 @@ interface ToolDef<TOverlay = KernelOverlay> {
|
|
|
2348
2740
|
* binding that points at an action id nothing registered.
|
|
2349
2741
|
*/
|
|
2350
2742
|
actions?: Action[];
|
|
2743
|
+
/** Menus this tool adds while it is active. */
|
|
2744
|
+
menus?: MenuDef[];
|
|
2351
2745
|
/** Hook name as exported from the kit barrel (e.g. `'useHandTool'`).
|
|
2352
2746
|
* Set by built-in hooks for inspector / debugging. Consumer-authored
|
|
2353
2747
|
* tools may set this to surface their hook name; omitted is fine.
|
|
@@ -2554,8 +2948,7 @@ interface ToolScopes {
|
|
|
2554
2948
|
/**
|
|
2555
2949
|
* Detect reachable route conflicts in an assembled tool set and report each one.
|
|
2556
2950
|
*
|
|
2557
|
-
* Call it once wherever a tool set is assembled, behind
|
|
2558
|
-
* `process.env.NODE_ENV !== 'production'` guard.
|
|
2951
|
+
* Call it once wherever a tool set is assembled, behind an `isDev()` guard.
|
|
2559
2952
|
*
|
|
2560
2953
|
* **Warn, never throw.** A conflict between a consumer's tool and a kit tool
|
|
2561
2954
|
* is sometimes deliberate, since the loser can still take the gesture when
|
|
@@ -2573,6 +2966,8 @@ declare function reportRouteConflicts(scopes: ToolScopes, warn?: (message: strin
|
|
|
2573
2966
|
*
|
|
2574
2967
|
* Extracted from the deleted singular `useKeybinding` hook so the remaining
|
|
2575
2968
|
* consumers don't depend on its disappearance.
|
|
2969
|
+
*
|
|
2970
|
+
* @packageDocumentation
|
|
2576
2971
|
*/
|
|
2577
2972
|
|
|
2578
2973
|
/**
|
|
@@ -2618,6 +3013,30 @@ declare function matchesKeyBinding(e: KeyboardEvent, b: KeyBinding): boolean;
|
|
|
2618
3013
|
* React keyboard event as readily as a DOM one. */
|
|
2619
3014
|
declare function historyKey(e: Pick<KeyboardEvent, 'key' | 'metaKey' | 'ctrlKey' | 'shiftKey' | 'altKey'>): 'undo' | 'redo' | null;
|
|
2620
3015
|
|
|
3016
|
+
/**
|
|
3017
|
+
* Key chords a major browser or the desktop under it takes before a page can:
|
|
3018
|
+
* reload, devtools, tab and window commands, menu accelerators. A binding on
|
|
3019
|
+
* one never fires for some users, so kit defaults steer clear of them.
|
|
3020
|
+
*
|
|
3021
|
+
* `mod` is Cmd on macOS and Ctrl elsewhere, as in a `KeySpec`. The list is
|
|
3022
|
+
* the union across Chrome, Safari, Firefox and Edge on macOS, Windows and
|
|
3023
|
+
* Linux, and errs toward listing a chord.
|
|
3024
|
+
*/
|
|
3025
|
+
|
|
3026
|
+
/** One reserved chord, and what takes it. */
|
|
3027
|
+
interface ReservedChord {
|
|
3028
|
+
key: string;
|
|
3029
|
+
mod?: boolean;
|
|
3030
|
+
alt?: boolean;
|
|
3031
|
+
shift?: boolean;
|
|
3032
|
+
/** Who takes it, for a message. */
|
|
3033
|
+
use: string;
|
|
3034
|
+
}
|
|
3035
|
+
/** Every chord the module's header describes, one entry per key. */
|
|
3036
|
+
declare const BROWSER_RESERVED_CHORDS: readonly ReservedChord[];
|
|
3037
|
+
/** The first reserved chord `spec` can fire on, or `null` when none. */
|
|
3038
|
+
declare function browserReservedChord(spec: KeySpec): ReservedChord | null;
|
|
3039
|
+
|
|
2621
3040
|
/**
|
|
2622
3041
|
* Typed keys for the gesture/behavior scratch store, `ctx.scratch`.
|
|
2623
3042
|
* `ScratchKey<T>` carries its payload type at the typing layer; at runtime
|
|
@@ -2750,13 +3169,15 @@ declare function dlog(namespace: string, ...args: unknown[]): void;
|
|
|
2750
3169
|
* (e.g. no-op op batches suppressed). */
|
|
2751
3170
|
declare function dwarn(namespace: string, ...args: unknown[]): void;
|
|
2752
3171
|
|
|
2753
|
-
/**
|
|
2754
|
-
*
|
|
2755
|
-
*
|
|
2756
|
-
*
|
|
2757
|
-
*
|
|
2758
|
-
*
|
|
2759
|
-
|
|
3172
|
+
/** The menus live now: ambient defs, then the active tool's. Defs that share
|
|
3173
|
+
* an id become one menu: each contribution's children in turn, with a
|
|
3174
|
+
* separator between contributions. Children stay at their own keys, so the
|
|
3175
|
+
* paths their values are read at do not move; a key a previous contribution
|
|
3176
|
+
* took gets `~n` appended. The first def of an id supplies the schema's
|
|
3177
|
+
* name and the def's `when`. */
|
|
3178
|
+
declare function mergeMenuDefs(defs: readonly OwnedMenuDef[], activeTool: string | null): MenuDef[];
|
|
3179
|
+
/** The first def whose `when` matches `hit`. */
|
|
3180
|
+
declare function pickMenu(defs: readonly MenuDef[], hit: MenuHit): MenuDef | undefined;
|
|
2760
3181
|
|
|
2761
3182
|
/**
|
|
2762
3183
|
* The dependency schema — the map of dep name → value type that
|
|
@@ -2779,9 +3200,34 @@ declare function dwarn(namespace: string, ...args: unknown[]): void;
|
|
|
2779
3200
|
interface DepSchema {
|
|
2780
3201
|
/** Currently active tool id + hotkey-hold stack. */
|
|
2781
3202
|
activeTool: ActiveToolContextValue;
|
|
3203
|
+
/** The menu host of the `ActionsProvider` in scope. */
|
|
3204
|
+
menuHost?: MenuHost;
|
|
2782
3205
|
}
|
|
2783
3206
|
/** Every dep name declared by anything that has merged into {@link DepSchema}. */
|
|
2784
3207
|
type DepName = keyof DepSchema;
|
|
3208
|
+
/**
|
|
3209
|
+
* The params each action reads, by action id — what types a tuning's
|
|
3210
|
+
* `params` and the params on the bindings it adds. Whoever ships an action
|
|
3211
|
+
* merges its entry in, as with {@link DepSchema}:
|
|
3212
|
+
*
|
|
3213
|
+
* ```ts
|
|
3214
|
+
* declare module '@weasel-js/core' {
|
|
3215
|
+
* interface ActionParamSchema { simplifyBrush: { radiusPx: number } }
|
|
3216
|
+
* }
|
|
3217
|
+
* ```
|
|
3218
|
+
*
|
|
3219
|
+
* Declare an entry as a type literal, not an interface: an interface has no
|
|
3220
|
+
* index signature, so it is not a `Record<string, unknown>`.
|
|
3221
|
+
*/
|
|
3222
|
+
interface ActionParamSchema {
|
|
3223
|
+
}
|
|
3224
|
+
/** Tunings keyed by action id: typed by {@link ActionParamSchema} for an id it
|
|
3225
|
+
* declares, `Record<string, unknown>` params for any other. */
|
|
3226
|
+
type ActionTunings = {
|
|
3227
|
+
readonly [K in keyof ActionParamSchema]?: ActionTuning<ActionParamSchema[K]>;
|
|
3228
|
+
} & {
|
|
3229
|
+
readonly [id: string]: ActionTuning | undefined;
|
|
3230
|
+
};
|
|
2785
3231
|
/**
|
|
2786
3232
|
* What the kernel drawing these tools takes as an overlay. Routing never reads
|
|
2787
3233
|
* an overlay, so it has no type of its own for one; the kernel merges its type
|
|
@@ -2803,4 +3249,4 @@ type KernelOverlay = OverlaySchema extends {
|
|
|
2803
3249
|
overlay: infer O;
|
|
2804
3250
|
} ? O : unknown;
|
|
2805
3251
|
|
|
2806
|
-
export { type
|
|
3252
|
+
export { type CarryCallbacks as $, type Action as A, type BoundGesture as B, type Contribution as C, type DepRegistry as D, type ActionSource as E, type ActionTuning as F, type ActionTunings as G, type ActionsProp as H, type AnyTool as I, type AssemblyInputs as J, type KernelOverlay as K, type LongPressOptions as L, type MenuHost as M, type NodeId as N, type OverlayPosition as O, BROWSER_RESERVED_CHORDS as P, type BindingOpts as Q, type RuleCtx as R, ScopeNode as S, ToolNode as T, type BindingScope as U, type BindingSource as V, type BodyPredicate as W, type Bounds as X, type BuildRuleCtxArgs as Y, COARSE_TARGET_SCALE as Z, type Carry as _, type DepName as a, type ResizeAnchor as a$, type CarryPayload as a0, type CarryPointer as a1, type CarryStage as a2, type Condition as a3, type Conflict as a4, type ContributionChrome as a5, type ContributionDeps as a6, type ContributionRouting as a7, DEFAULT_ALLOWED_CAPABILITIES as a8, DEFAULT_DEVICE_PROFILE as a9, type MenuSources as aA, type MenuWhen as aB, type ModeShortcutHandlers as aC, type ModeSwitchLogEntry as aD, type ModifierRole as aE, type ModifierRoles as aF, type ModifierState as aG, NEVER as aH, type OngoingHandle as aI, type OngoingInvoker as aJ, type OngoingOverlay as aK, type OpenMenu as aL, type OverlayRole as aM, type OverlaySchema as aN, type OwnedMenuDef as aO, PREDICATE_TARGET as aP, type PendingLongPress as aQ, type PlacedBy as aR, type Point2 as aS, type PointerSession as aT, type PointerSessionCallbacks as aU, type PointerSessionCancelReason as aV, type PointerSessionOptions as aW, type RankedCandidate as aX, type RecordCandidate as aY, type RegistryEntry as aZ, type ReservedChord as a_, type DebugSink as aa, type DetectedDeviceFacts as ab, type DeviceProfile as ac, type DispatchRecord as ad, type DispatchRecordInput as ae, type DispatcherContext as af, type DragSample as ag, type DroppedCandidate as ah, type Eligibility as ai, type EligibilityState as aj, type GestureBinding as ak, type GestureKitSettings as al, type HandleKind as am, type HitShape as an, type HotkeyTrigger as ao, INGEST_STRING_MIMES as ap, type ImmediateInvoker as aq, type InvocationCtx as ar, type Invoker as as, type KeyBinding as at, type LongPressState as au, type LongPressStore as av, type MatchOutcome as aw, type MatchResult as ax, type MenuHit as ay, type MenuOpenRequest as az, type DepSchema as b, isPathEditPart as b$, type ResolveAllOptions as b0, type ResolveOnlyResult as b1, type ResolvedCandidate as b2, type RoleKeys as b3, type RoleRebinds as b4, type Rule as b5, type ScopedBinding as b6, type ScratchKey as b7, type ScratchStore as b8, type SelectionApi as b9, buildToolOffhandBindings as bA, clientToCanvas as bB, clientToCanvasRect as bC, createDepRegistry as bD, createDispatcher as bE, createLongPressStore as bF, createMenuHost as bG, defineTool as bH, deleteScratch as bI, describeRule as bJ, dlog as bK, dwarn as bL, evaluate as bM, evaluateActive as bN, evaluateEnabled as bO, findConflicts as bP, getScratch as bQ, heldKeySpec as bR, historyKey as bS, isAnchor as bT, isAnchorOrControl as bU, isBalanceGrip as bV, isBody as bW, isControlHandle as bX, isCornerWidget as bY, isDebugEnabled as bZ, isEmpty as b_, type Selector as ba, type SpecificityPart as bb, TOOL_OFFHAND_ID as bc, type ToolDef as bd, type ToolKeybinding as be, type ToolModifiers as bf, type ToolOffhandBindingSpec as bg, type ToolPresentation as bh, type ToolScopes as bi, type ToolSlot as bj, type TraceLogEntry as bk, type TunedBinding as bl, type UiOngoingControl as bm, type ViewportGestureKind as bn, type WalkStep as bo, actionBindings as bp, actionCursor as bq, actionItemTitle as br, actionItems as bs, actionShortcuts as bt, actionsTagged as bu, assembleEntries as bv, browserReservedChord as bw, buildDepsFromRequires as bx, buildRouteRegistry as by, buildRuleCtx as bz, type ActionDeps as c, isResizeHandle as c0, isRotateHandle as c1, isSegment as c2, isSelectedBody as c3, isTool as c4, isUnselectedBody as c5, itemTypesFromDataTransfer as c6, itemsFromClipboardData as c7, itemsFromDataTransfer as c8, itemsFromFiles as c9, routesForSpec as cA, ruleCanHoldIn as cB, rulesExclusive as cC, scopeBindings as cD, scratchKey as cE, setScratch as cF, startCarry as cG, taggedActionItems as cH, targetConsultsAffordance as cI, tuneAction as cJ, validateActionDefaultBinding as cK, validateActionId as cL, keySpecShortcut as ca, keysHeld as cb, liveScope as cc, makeToolOffhandAction as cd, matchActionItem as ce, matchBest as cf, matchSorted as cg, matchSortedWithBarred as ch, matchesKeyBinding as ci, mergeContributions as cj, mergeMenuDefs as ck, modeShortcutSpec as cl, modeShortcuts as cm, multiTouchGestureId as cn, offhandKeyFor as co, openPointerSession as cp, overlaysOf as cq, pickMenu as cr, pointerGestureId as cs, recordModeSwitch as ct, reportRouteConflicts as cu, resolveDeviceProfile as cv, resolveMenu as cw, resolveParams as cx, resolveSchemaMenu as cy, roleReader as cz, type ActionsRegistry as d, ActionDisabledReason as e, type ActionVariant as f, type MenuDef as g, DepNode as h, type Tool as i, ActiveToolContextProvider as j, ActiveToolContextProviderIfRoot as k, type ActiveToolContextProviderProps as l, type ActiveToolContextValue as m, useOptionalActiveToolContext as n, type Dispatcher as o, type AffordanceHit as p, ALWAYS as q, type ActionDispatch as r, type ActionEnabledResult as s, type ActionEntry as t, useActiveToolContext as u, type ActionItem as v, type ActionParamSchema as w, type ActionParams as x, type ActionPresentation as y, type ActionShortcut as z };
|