@weasel-js/routing 1.15.0 → 1.15.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -589,6 +589,69 @@ type OngoingOverlay = {
589
589
  /** A handle's overlays as a list: empty when it has none. */
590
590
  declare function overlaysOf(handle: OngoingHandle): readonly OngoingOverlay[];
591
591
 
592
+ /**
593
+ * The options a gesture binding hands the action it fires, and reading their params.
594
+ */
595
+
596
+ /** Per-invocation options the dispatcher reads from a `GestureBinding`'s
597
+ * `opts` field and passes to `OngoingInvoker.start`. */
598
+ interface BindingOpts {
599
+ /** The id a binding override names this binding by, `<owner>.<role>`:
600
+ * `undo.key`, `rect.drag`, `nudge.left.big`. Without one it is its owner and
601
+ * its position (`<entry>#<n>`, `<action>@<n>`), which moves when the defaults
602
+ * are reordered, so a binding a host may persist an override for declares one. */
603
+ id?: string;
604
+ /** Gesture behaviors the action's own invoker runs. Routing carries the
605
+ * array to the action and never reads an element, so the element type is
606
+ * open here; `@weasel-js/core` narrows it. */
607
+ behaviors?: unknown[];
608
+ /** Per-binding action parameters, which an immediate invoker reads via the
609
+ * second arg to `run`.
610
+ *
611
+ * May also be a thunk evaluated each time the value is needed, so a tool
612
+ * can close over refs that mutate during a gesture (e.g. polygon `sides`
613
+ * adjusted mid-drag via ArrowUp). An ongoing invoker that wants the latest
614
+ * values at commit re-calls it inside `onEnd` via
615
+ * `resolveParams(opts?.params)`. */
616
+ params?: Record<string, unknown> | (() => Record<string, unknown>);
617
+ /**
618
+ * The views this binding is live in, by id, where `null` is the surface's
619
+ * own camera. Omitted means every view.
620
+ *
621
+ * A binding that names the view an input landed in outranks every binding
622
+ * that does not, whatever their scope tiers: naming a view is the most
623
+ * specific thing a binding can say about where it applies. Without that, a
624
+ * drag bound inside a minimap view loses to the active tool's marquee.
625
+ */
626
+ views?: readonly (string | null)[];
627
+ /**
628
+ * Says this binding is declared ahead of another on the same input on
629
+ * purpose: its action declines through `enabled()` when the input is not its
630
+ * to take, and the next binding fires. The dispatcher does that for any
631
+ * binding; this tells the route-conflict check the order is the design.
632
+ */
633
+ yields?: boolean;
634
+ /**
635
+ * For a key binding: live while the pointer is over the surface, whichever
636
+ * canvas holds the keys, and only then. For a key that means "here" — a
637
+ * magnifier's peek — on a page with more than one surface that hears it.
638
+ * A held key follows the pointer: one already down when it arrives presses
639
+ * the binding, and leaving releases it.
640
+ */
641
+ over?: boolean;
642
+ /**
643
+ * Keys for some of the action's `modifierRoles` on this binding, by role
644
+ * id, over the action's defaults and any tuning's.
645
+ */
646
+ roles?: RoleRebinds;
647
+ /** Screen travel, in CSS pixels, a drag makes before this binding's ongoing action starts, over the
648
+ * action's own `dragThresholdPx`. See `OngoingInvoker.dragThresholdPx`. */
649
+ dragThresholdPx?: number;
650
+ }
651
+ /** Resolve `BindingOpts.params` to a concrete record (calling the thunk if
652
+ * needed). Returns `undefined` for absent params. */
653
+ declare function resolveParams(params: BindingOpts['params']): Record<string, unknown> | undefined;
654
+
592
655
  /**
593
656
  * Invoker — pluggable invocation strategy for an Action.
594
657
  *
@@ -779,64 +842,7 @@ interface InvocationCtx {
779
842
  */
780
843
  roles?: Readonly<Record<string, boolean>>;
781
844
  }
782
- /** Per-invocation options the dispatcher reads from a `GestureBinding`'s
783
- * `opts` field and passes to `OngoingInvoker.start`. */
784
- interface BindingOpts {
785
- /** The id a binding override names this binding by, `<owner>.<role>`:
786
- * `undo.key`, `rect.drag`, `nudge.left.big`. Without one it is its owner and
787
- * its position (`<entry>#<n>`, `<action>@<n>`), which moves when the defaults
788
- * are reordered, so a binding a host may persist an override for declares one. */
789
- id?: string;
790
- /** Gesture behaviors the action's own invoker runs. Routing carries the
791
- * array to the action and never reads an element, so the element type is
792
- * open here; `@weasel-js/core` narrows it. */
793
- behaviors?: unknown[];
794
- /** Per-binding action parameters, which an immediate invoker reads via the
795
- * second arg to `run`.
796
- *
797
- * May also be a thunk evaluated each time the value is needed, so a tool
798
- * can close over refs that mutate during a gesture (e.g. polygon `sides`
799
- * adjusted mid-drag via ArrowUp). An ongoing invoker that wants the latest
800
- * values at commit re-calls it inside `onEnd` via
801
- * `resolveParams(opts?.params)`. */
802
- params?: Record<string, unknown> | (() => Record<string, unknown>);
803
- /**
804
- * The views this binding is live in, by id, where `null` is the surface's
805
- * own camera. Omitted means every view.
806
- *
807
- * A binding that names the view an input landed in outranks every binding
808
- * that does not, whatever their scope tiers: naming a view is the most
809
- * specific thing a binding can say about where it applies. Without that, a
810
- * drag bound inside a minimap view loses to the active tool's marquee.
811
- */
812
- views?: readonly (string | null)[];
813
- /**
814
- * Says this binding is declared ahead of another on the same input on
815
- * purpose: its action declines through `enabled()` when the input is not its
816
- * to take, and the next binding fires. The dispatcher does that for any
817
- * binding; this tells the route-conflict check the order is the design.
818
- */
819
- yields?: boolean;
820
- /**
821
- * For a key binding: live while the pointer is over the surface, whichever
822
- * canvas holds the keys, and only then. For a key that means "here" — a
823
- * magnifier's peek — on a page with more than one surface that hears it.
824
- * A held key follows the pointer: one already down when it arrives presses
825
- * the binding, and leaving releases it.
826
- */
827
- over?: boolean;
828
- /**
829
- * Keys for some of the action's `modifierRoles` on this binding, by role
830
- * id, over the action's defaults and any tuning's.
831
- */
832
- roles?: RoleRebinds;
833
- /** Screen travel, in CSS pixels, a drag makes before this binding's ongoing action starts, over the
834
- * action's own `dragThresholdPx`. See {@link OngoingInvoker.dragThresholdPx}. */
835
- dragThresholdPx?: number;
836
- }
837
- /** Resolve `BindingOpts.params` to a concrete record (calling the thunk if
838
- * needed). Returns `undefined` for absent params. */
839
- declare function resolveParams(params: BindingOpts['params']): Record<string, unknown> | undefined;
845
+
840
846
  /** The deps an action receives, composed per call from what it `requires`.
841
847
  * Each name resolves to its {@link DepSchema} entry, and is absent when no
842
848
  * source registered it; a name nothing has declared passes through as
@@ -885,6 +891,13 @@ interface OngoingHandle {
885
891
  * faithfully leaves it out, and its action gets no panel.
886
892
  */
887
893
  replay?(params: Record<string, unknown>): void;
894
+ /**
895
+ * Params this gesture's commit took from what it edited rather than from its binding, read once it has ended:
896
+ * a held warp's own grid and tolerance, say, which the binding's settings do not reach. The last-operation
897
+ * panel shows them over the resolved params, and `replay` is handed them, so a change to one field leaves the
898
+ * rest as the gesture found them.
899
+ */
900
+ params?(): Readonly<Record<string, unknown>>;
888
901
  /**
889
902
  * Optional preview surface: the in-flight state the canvas's preview-ghost
890
903
  * layer renders on top of the committed scene during the gesture.
@@ -1314,6 +1327,10 @@ interface ActionTuning<P = Record<string, unknown>> {
1314
1327
  /** Keys for some of the action's `modifierRoles`, by role id. A binding's
1315
1328
  * own `opts.roles` is laid over these. */
1316
1329
  roles?: RoleRebinds;
1330
+ /** Told the params the last-operation panel just set for the action, which hold for the rest of the session.
1331
+ * A tuning whose `params` thunk reads a host's store writes the ones it supplies back there, so the store, and
1332
+ * whatever draws it, says what the next run will use rather than overriding it. */
1333
+ keep?(params: Readonly<Record<string, unknown>>): void;
1317
1334
  }
1318
1335
  /** `action` with each tuning applied in turn, a later one's params over an
1319
1336
  * earlier one's. Applying a tuning to a copy it already tuned changes nothing. */
@@ -1346,7 +1363,8 @@ interface LastOperationStore {
1346
1363
  * Undo the operation's entry, put back the selection it ran on, and run it again with `patch` laid over its
1347
1364
  * values (a gesture is replayed by its handle), keeping the entry that makes in place of the old one: the
1348
1365
  * history, or the journal open on it, still holds one entry for it. The merged values become the action's
1349
- * params for the rest of the session, under any tuning. Returns whether it ran.
1366
+ * params for the rest of the session, under any tuning, and each tuning that keeps them is handed them
1367
+ * (`ActionTuning.keep`). Returns whether it ran.
1350
1368
  */
1351
1369
  adjust(patch: Readonly<Record<string, unknown>>): boolean;
1352
1370
  /** Forget the operation; the scene and the history stay as they are. */
@@ -1364,6 +1382,8 @@ interface LastOperationHost {
1364
1382
  paramsOf(id: string, given: Record<string, unknown> | undefined): Record<string, unknown>;
1365
1383
  /** Run the action live for `id` here with `params`, as `trigger` would. */
1366
1384
  rerun(id: string, params: Record<string, unknown>): void;
1385
+ /** Hand `params`, which a panel change made `id`'s for the session, to each tuning of `id` that keeps them. */
1386
+ keep(id: string, params: Readonly<Record<string, unknown>>): void;
1367
1387
  }
1368
1388
  /** The store one actions tree keeps at its root. `onSession` is told when an action's session params change. */
1369
1389
  declare class LastOperationKeeper implements LastOperationStore {
package/dist/index.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- export { x as ALWAYS, A as Action, c as ActionDeps, e as ActionDisabledReason, e as ActionDisabledReasonValue, y as ActionDispatch, z as ActionEnabledResult, E as ActionEntry, F as ActionItem, G as ActionParamSchema, H as ActionParams, I as ActionPresentation, J as ActionSettings, P as ActionSettingsState, Q as ActionShortcut, U as ActionSource, V as ActionTuning, X as ActionTunings, Y as ActionUnavailable, f as ActionVariant, Z as ActionsProp, d as ActionsRegistry, s as AffordanceHit, _ as AnyTool, $ as AssemblyInputs, a0 as BROWSER_RESERVED_CHORDS, a1 as BindingOpts, a2 as BindingOverrides, a3 as BindingScope, a4 as BindingSource, a5 as BodyPredicate, B as BoundGesture, a6 as Bounds, a7 as BuildRuleCtxArgs, a8 as COARSE_TARGET_SCALE, a9 as CaptureGestureOptions, aa as CaptureKeyOptions, ab as CaptureKind, ac as CapturedSpec, ad as Carried, ae as Carry, af as CarryCallbacks, ag as CarryPayload, ah as CarryPointer, ai as CarryStage, aj as Condition, ak as Conflict, C as Contribution, al as ContributionChrome, am as ContributionDeps, an as ContributionRouting, ao as DEFAULT_ALLOWED_CAPABILITIES, ap as DEFAULT_DEVICE_PROFILE, aq as DebugSink, ar as DepListing, a as DepName, D as DepRegistry, w as DepSchema, b as DepSource, as as DetectedDeviceFacts, at as DeviceProfile, au as DispatchRecord, av as DispatchRecordInput, t as DispatchTrace, r as Dispatcher, aw as DispatcherContext, ax as DragSample, ay as DroppedCandidate, az as Eligibility, aA as EligibilityState, aB as GestureBinding, aC as GestureKitSettings, aD as HandleKind, aE as HitShape, aF as HotkeyTrigger, aG as INGEST_STRING_MIMES, aH as ImmediateInvoker, aI as ImmediateParams, aJ as InvocationCtx, aK as Invoker, aL as KEYMAP_HOLD, k as KernelOverlay, aM as KeyBinding, aN as KeyReach, aO as KeymapDef, K as KeymapDescription, aP as KeymapRow, aQ as KeymapStack, aR as KeymapUnbound, aS as KeymapVerdict, h as LastOperation, g as LastOperationStore, v as LongPressOptions, aT as LongPressState, aU as LongPressStore, aV as MatchOutcome, aW as MatchResult, aX as MenuAccess, aY as MenuCustomAt, i as MenuDef, aZ as MenuHit, M as MenuHost, a_ as MenuOpenRequest, a$ as MenuSources, b0 as MenuWhen, b1 as ModeShortcutHandlers, b2 as ModeSwitchLogEntry, b3 as ModifierRole, b4 as ModifierRoles, b5 as ModifierState, b6 as NEVER, N as NodeId, b7 as OngoingHandle, b8 as OngoingInvoker, b9 as OngoingOverlay, ba as OpenKeymap, bb as OpenMenu, O as OverlayPosition, bc as OverlayRole, bd as OverlaySchema, be as OwnedMenuDef, bf as PREDICATE_TARGET, bg as PendingIngestItem, bh as PendingLongPress, bi as PlacedBy, bj as Point2, bk as PointerSession, bl as PointerSessionCallbacks, bm as PointerSessionCancelReason, bn as PointerSessionOptions, bo as RankedCandidate, bp as RecordCandidate, bq as RegistryEntry, br as ReservedChord, bs as ResizeAnchor, bt as ResolveAllOptions, bu as ResolveOnlyResult, bv as ResolvedBindingOverrides, bw as ResolvedCandidate, bx as RoleKeys, by as RoleRebinds, bz as Rule, R as RuleCtx, bA as ScopedBinding, bB as ScratchKey, bC as ScratchStore, bD as SelectionApi, bE as SelectionSnapshotDep, bF as Selector, bG as SpecificityPart, bH as TOOL_OFFHAND_ID, l as Tool, bI as ToolDef, bJ as ToolEntry, bK as ToolKeybinding, bL as ToolModifiers, bM as ToolOffhandBindingSpec, bN as ToolOptionStep, bO as ToolOptionValues, bP as ToolOptions, bQ as ToolPresentation, bR as ToolScopes, bS as ToolSet, bT as ToolSlot, bU as TraceLogEntry, bV as TraceRing, bW as TunedBinding, bX as UiOngoingControl, bY as ViewportGestureKind, bZ as WalkStep, W as WorldPoint, b_ as actionBindings, b$ as actionCursor, c0 as actionItemTitle, c1 as actionItems, c2 as actionSettingsParams, c3 as actionShortcuts, c4 as actionsTagged, c5 as admitIngestMime, c6 as assembleEntries, c7 as bindingId, c8 as browserReservedChord, c9 as buildDepsFromRequires, ca as buildRouteRegistry, cb as buildRuleCtx, cc as buildToolOffhandBindings, cd as captureGesture, ce as captureKey, cf as clientToCanvas, cg as clientToCanvasRect, ch as createDepRegistry, ci as createDispatchTrace, cj as createDispatcher, ck as createKeymapStack, cl as createLongPressStore, cm as createMenuHost, cn as createToolOptionValues, co as createTraceRing, cp as defineTool, cq as deleteScratch, cr as describeKeymap, cs as describeRule, ct as dlog, cu as dwarn, cv as evaluate, cw as evaluateActive, cx as evaluateEnabled, cy as findConflicts, cz as getScratch, cA as heldKeySpec, cB as historyKey, cC as holdPreview, cD as holdPreviewId, cE as isAnchor, cF as isAnchorOrControl, cG as isBalanceGrip, cH as isBody, cI as isControlHandle, cJ as isCornerWidget, cK as isDebugEnabled, cL as isEmpty, cM as isPathEditPart, cN as isResizeHandle, cO as isRotateHandle, cP as isSegment, cQ as isSelectedBody, cR as isTool, cS as isToolSet, cT as isUnselectedBody, cU as itemTypesFromDataTransfer, cV as itemsFromClipboardData, cW as itemsFromDataTransfer, cX as itemsFromFiles, cY as keySpecShortcut, cZ as keymapContribution, c_ as keymapLeaderBindingId, c$ as keymapLeaderId, d0 as keymapShortcuts, d1 as keysHeld, d2 as liveScope, d3 as makeToolOffhandAction, d4 as matchActionItem, d5 as matchBest, d6 as matchSorted, d7 as matchSortedWithBarred, d8 as matchesKeyBinding, d9 as mergeContributions, da as mergeMenuDefs, db as modeShortcutSpec, dc as modeShortcuts, dd as modifierStateOf, de as multiTouchGestureId, df as offhandKeyFor, dg as openPointerSession, dh as overlaysOf, di as overriddenBindings, dj as pendingKindOf, dk as pickMenu, dl as pointerGestureId, dm as readActionSettings, dn as reportRouteConflicts, dp as resolveBindingOverrides, dq as resolveDeviceProfile, dr as resolveMenu, ds as resolveParams, dt as resolveSchemaMenu, du as returnToModeDefault, dv as roleReader, dw as routesForSpec, dx as ruleCanHoldIn, dy as rulesExclusive, dz as scopeBindings, dA as scratchKey, dB as setScratch, dC as startCarry, dD as steppedOption, dE as taggedActionItems, dF as targetConsultsAffordance, dG as toolIdsOf, dH as toolOptionParams, dI as toolOptionSteps, dJ as toolSet, dK as toolSetHas, dL as tuneAction, dM as validateActionDefaultBinding, dN as validateActionId, dO as withoutTools } from './index-C2EcHkCp.js';
1
+ export { x as ALWAYS, A as Action, c as ActionDeps, e as ActionDisabledReason, e as ActionDisabledReasonValue, y as ActionDispatch, z as ActionEnabledResult, E as ActionEntry, F as ActionItem, G as ActionParamSchema, H as ActionParams, I as ActionPresentation, J as ActionSettings, P as ActionSettingsState, Q as ActionShortcut, U as ActionSource, V as ActionTuning, X as ActionTunings, Y as ActionUnavailable, f as ActionVariant, Z as ActionsProp, d as ActionsRegistry, s as AffordanceHit, _ as AnyTool, $ as AssemblyInputs, a0 as BROWSER_RESERVED_CHORDS, a1 as BindingOpts, a2 as BindingOverrides, a3 as BindingScope, a4 as BindingSource, a5 as BodyPredicate, B as BoundGesture, a6 as Bounds, a7 as BuildRuleCtxArgs, a8 as COARSE_TARGET_SCALE, a9 as CaptureGestureOptions, aa as CaptureKeyOptions, ab as CaptureKind, ac as CapturedSpec, ad as Carried, ae as Carry, af as CarryCallbacks, ag as CarryPayload, ah as CarryPointer, ai as CarryStage, aj as Condition, ak as Conflict, C as Contribution, al as ContributionChrome, am as ContributionDeps, an as ContributionRouting, ao as DEFAULT_ALLOWED_CAPABILITIES, ap as DEFAULT_DEVICE_PROFILE, aq as DebugSink, ar as DepListing, a as DepName, D as DepRegistry, w as DepSchema, b as DepSource, as as DetectedDeviceFacts, at as DeviceProfile, au as DispatchRecord, av as DispatchRecordInput, t as DispatchTrace, r as Dispatcher, aw as DispatcherContext, ax as DragSample, ay as DroppedCandidate, az as Eligibility, aA as EligibilityState, aB as GestureBinding, aC as GestureKitSettings, aD as HandleKind, aE as HitShape, aF as HotkeyTrigger, aG as INGEST_STRING_MIMES, aH as ImmediateInvoker, aI as ImmediateParams, aJ as InvocationCtx, aK as Invoker, aL as KEYMAP_HOLD, k as KernelOverlay, aM as KeyBinding, aN as KeyReach, aO as KeymapDef, K as KeymapDescription, aP as KeymapRow, aQ as KeymapStack, aR as KeymapUnbound, aS as KeymapVerdict, h as LastOperation, g as LastOperationStore, v as LongPressOptions, aT as LongPressState, aU as LongPressStore, aV as MatchOutcome, aW as MatchResult, aX as MenuAccess, aY as MenuCustomAt, i as MenuDef, aZ as MenuHit, M as MenuHost, a_ as MenuOpenRequest, a$ as MenuSources, b0 as MenuWhen, b1 as ModeShortcutHandlers, b2 as ModeSwitchLogEntry, b3 as ModifierRole, b4 as ModifierRoles, b5 as ModifierState, b6 as NEVER, N as NodeId, b7 as OngoingHandle, b8 as OngoingInvoker, b9 as OngoingOverlay, ba as OpenKeymap, bb as OpenMenu, O as OverlayPosition, bc as OverlayRole, bd as OverlaySchema, be as OwnedMenuDef, bf as PREDICATE_TARGET, bg as PendingIngestItem, bh as PendingLongPress, bi as PlacedBy, bj as Point2, bk as PointerSession, bl as PointerSessionCallbacks, bm as PointerSessionCancelReason, bn as PointerSessionOptions, bo as RankedCandidate, bp as RecordCandidate, bq as RegistryEntry, br as ReservedChord, bs as ResizeAnchor, bt as ResolveAllOptions, bu as ResolveOnlyResult, bv as ResolvedBindingOverrides, bw as ResolvedCandidate, bx as RoleKeys, by as RoleRebinds, bz as Rule, R as RuleCtx, bA as ScopedBinding, bB as ScratchKey, bC as ScratchStore, bD as SelectionApi, bE as SelectionSnapshotDep, bF as Selector, bG as SpecificityPart, bH as TOOL_OFFHAND_ID, l as Tool, bI as ToolDef, bJ as ToolEntry, bK as ToolKeybinding, bL as ToolModifiers, bM as ToolOffhandBindingSpec, bN as ToolOptionStep, bO as ToolOptionValues, bP as ToolOptions, bQ as ToolPresentation, bR as ToolScopes, bS as ToolSet, bT as ToolSlot, bU as TraceLogEntry, bV as TraceRing, bW as TunedBinding, bX as UiOngoingControl, bY as ViewportGestureKind, bZ as WalkStep, W as WorldPoint, b_ as actionBindings, b$ as actionCursor, c0 as actionItemTitle, c1 as actionItems, c2 as actionSettingsParams, c3 as actionShortcuts, c4 as actionsTagged, c5 as admitIngestMime, c6 as assembleEntries, c7 as bindingId, c8 as browserReservedChord, c9 as buildDepsFromRequires, ca as buildRouteRegistry, cb as buildRuleCtx, cc as buildToolOffhandBindings, cd as captureGesture, ce as captureKey, cf as clientToCanvas, cg as clientToCanvasRect, ch as createDepRegistry, ci as createDispatchTrace, cj as createDispatcher, ck as createKeymapStack, cl as createLongPressStore, cm as createMenuHost, cn as createToolOptionValues, co as createTraceRing, cp as defineTool, cq as deleteScratch, cr as describeKeymap, cs as describeRule, ct as dlog, cu as dwarn, cv as evaluate, cw as evaluateActive, cx as evaluateEnabled, cy as findConflicts, cz as getScratch, cA as heldKeySpec, cB as historyKey, cC as holdPreview, cD as holdPreviewId, cE as isAnchor, cF as isAnchorOrControl, cG as isBalanceGrip, cH as isBody, cI as isControlHandle, cJ as isCornerWidget, cK as isDebugEnabled, cL as isEmpty, cM as isPathEditPart, cN as isResizeHandle, cO as isRotateHandle, cP as isSegment, cQ as isSelectedBody, cR as isTool, cS as isToolSet, cT as isUnselectedBody, cU as itemTypesFromDataTransfer, cV as itemsFromClipboardData, cW as itemsFromDataTransfer, cX as itemsFromFiles, cY as keySpecShortcut, cZ as keymapContribution, c_ as keymapLeaderBindingId, c$ as keymapLeaderId, d0 as keymapShortcuts, d1 as keysHeld, d2 as liveScope, d3 as makeToolOffhandAction, d4 as matchActionItem, d5 as matchBest, d6 as matchSorted, d7 as matchSortedWithBarred, d8 as matchesKeyBinding, d9 as mergeContributions, da as mergeMenuDefs, db as modeShortcutSpec, dc as modeShortcuts, dd as modifierStateOf, de as multiTouchGestureId, df as offhandKeyFor, dg as openPointerSession, dh as overlaysOf, di as overriddenBindings, dj as pendingKindOf, dk as pickMenu, dl as pointerGestureId, dm as readActionSettings, dn as reportRouteConflicts, dp as resolveBindingOverrides, dq as resolveDeviceProfile, dr as resolveMenu, ds as resolveParams, dt as resolveSchemaMenu, du as returnToModeDefault, dv as roleReader, dw as routesForSpec, dx as ruleCanHoldIn, dy as rulesExclusive, dz as scopeBindings, dA as scratchKey, dB as setScratch, dC as startCarry, dD as steppedOption, dE as taggedActionItems, dF as targetConsultsAffordance, dG as toolIdsOf, dH as toolOptionParams, dI as toolOptionSteps, dJ as toolSet, dK as toolSetHas, dL as tuneAction, dM as validateActionDefaultBinding, dN as validateActionId, dO as withoutTools } from './index-D-XFwx8D.js';
2
2
  export { CONTROL_SELECTOR, ChannelRef, DRAG_THRESHOLD_PX, DescribeRouteOptions, GESTURE_DESCRIPTORS, GestureArgSpec, GestureDescriptor, GestureName, IngestItem, InputEvent, LONG_PRESS_MS, ModRequirement, ModifierKey, ParsedModifiers, ParsedRoute, PhaseAtom, PhaseContext, RESERVED_ID_NAMES, RESERVED_ID_PREFIXES, ROUTE_FIELD_DEFINITIONS, ROUTE_TERMS, RouteDescriptionPart, RouteFieldName, RouteTermLabel, activatesFocusedControl, canonicalModifiers, collapseShiftPairs, describeRoute, describeRouteParts, focusedControlOwnsKey, formatPhaseAtom, formatRoute, getGestureDescriptor, isEditableTarget, isInControlWithin, isKnownGestureName, matchKey, matchModifiers, matchPhase, matchSpec, matchTarget, parseRoute, pastDragThreshold, routeGestureForSpecKind, specKindForRouteGesture, specificity } from '@weasel-js/gestures';
3
3
  export { SelectionExtendKey, SelectionMode } from '@weasel-js/select';
4
4
  export { View } from '@weasel-js/geom';
package/dist/index.js CHANGED
@@ -1,6 +1,6 @@
1
- export { ALWAYS, COARSE_TARGET_SCALE, DEFAULT_ALLOWED_CAPABILITIES, DEFAULT_DEVICE_PROFILE, GESTURE_DESCRIPTORS, INGEST_STRING_MIMES, KEYMAP_HOLD, LONG_PRESS_MS, NEVER, PREDICATE_TARGET, TOOL_OFFHAND_ID, activatesFocusedControl, admitIngestMime, assembleEntries, buildRouteRegistry, buildRuleCtx, buildToolOffhandBindings, clientToCanvas, clientToCanvasRect, createDispatchTrace, createDispatcher, createKeymapStack, createLongPressStore, createTraceRing, describeKeymap, describeRule, dlog, dwarn, evaluate, findConflicts, focusedControlOwnsKey, getGestureDescriptor, heldKeySpec, historyKey, isDebugEnabled, isEditableTarget, isKnownGestureName, isTool, itemTypesFromDataTransfer, itemsFromClipboardData, itemsFromDataTransfer, itemsFromFiles, keymapContribution, keymapLeaderBindingId, keymapLeaderId, keymapShortcuts, liveScope, makeToolOffhandAction, matchBest, matchKey, matchModifiers, matchPhase, matchSorted, matchSortedWithBarred, matchSpec, matchTarget, matchesKeyBinding, modifierStateOf, multiTouchGestureId, offhandKeyFor, openPointerSession, pendingKindOf, pointerGestureId, reportRouteConflicts, resolveDeviceProfile, routeGestureForSpecKind, routesForSpec, ruleCanHoldIn, rulesExclusive, scopeBindings, specKindForRouteGesture, specificity, startCarry, targetConsultsAffordance } from './chunk-ZK72IBMI.js';
2
- import { actionItems, actionItemTitle, resolveParams, ActionDisabledReason } from './chunk-A6MN3I6R.js';
3
- export { ActionDisabledReason, RESERVED_ID_NAMES, RESERVED_ID_PREFIXES, ROUTE_FIELD_DEFINITIONS, ROUTE_TERMS, actionBindings, actionCursor, actionItemTitle, actionItems, actionSettingsParams, actionShortcuts, bindingId, buildDepsFromRequires, canonicalModifiers, collapseShiftPairs, createDepRegistry, createMenuHost, describeRoute, describeRouteParts, evaluateActive, evaluateEnabled, formatPhaseAtom, formatRoute, keySpecShortcut, keysHeld, mergeMenuDefs, overriddenBindings, parseRoute, pickMenu, readActionSettings, resolveBindingOverrides, resolveMenu, resolveParams, resolveSchemaMenu, roleReader, tuneAction, validateActionDefaultBinding, validateActionId } from './chunk-A6MN3I6R.js';
1
+ export { ALWAYS, COARSE_TARGET_SCALE, DEFAULT_ALLOWED_CAPABILITIES, DEFAULT_DEVICE_PROFILE, GESTURE_DESCRIPTORS, INGEST_STRING_MIMES, KEYMAP_HOLD, LONG_PRESS_MS, NEVER, PREDICATE_TARGET, TOOL_OFFHAND_ID, activatesFocusedControl, admitIngestMime, assembleEntries, buildRouteRegistry, buildRuleCtx, buildToolOffhandBindings, clientToCanvas, clientToCanvasRect, createDispatchTrace, createDispatcher, createKeymapStack, createLongPressStore, createTraceRing, describeKeymap, describeRule, dlog, dwarn, evaluate, findConflicts, focusedControlOwnsKey, getGestureDescriptor, heldKeySpec, historyKey, isDebugEnabled, isEditableTarget, isKnownGestureName, isTool, itemTypesFromDataTransfer, itemsFromClipboardData, itemsFromDataTransfer, itemsFromFiles, keymapContribution, keymapLeaderBindingId, keymapLeaderId, keymapShortcuts, liveScope, makeToolOffhandAction, matchBest, matchKey, matchModifiers, matchPhase, matchSorted, matchSortedWithBarred, matchSpec, matchTarget, matchesKeyBinding, modifierStateOf, multiTouchGestureId, offhandKeyFor, openPointerSession, pendingKindOf, pointerGestureId, reportRouteConflicts, resolveDeviceProfile, routeGestureForSpecKind, routesForSpec, ruleCanHoldIn, rulesExclusive, scopeBindings, specKindForRouteGesture, specificity, startCarry, targetConsultsAffordance } from './chunk-ZUAFANMN.js';
2
+ import { actionItems, actionItemTitle, resolveParams, ActionDisabledReason } from './chunk-Z2BZBJ7W.js';
3
+ export { ActionDisabledReason, RESERVED_ID_NAMES, RESERVED_ID_PREFIXES, ROUTE_FIELD_DEFINITIONS, ROUTE_TERMS, actionBindings, actionCursor, actionItemTitle, actionItems, actionSettingsParams, actionShortcuts, bindingId, buildDepsFromRequires, canonicalModifiers, collapseShiftPairs, createDepRegistry, createMenuHost, describeRoute, describeRouteParts, evaluateActive, evaluateEnabled, formatPhaseAtom, formatRoute, keySpecShortcut, keysHeld, mergeMenuDefs, overriddenBindings, parseRoute, pickMenu, readActionSettings, resolveBindingOverrides, resolveMenu, resolveParams, resolveSchemaMenu, roleReader, tuneAction, validateActionDefaultBinding, validateActionId } from './chunk-Z2BZBJ7W.js';
4
4
  import { hasTag, matchQuery } from '@weasel-js/registry';
5
5
  import { bodyPredicate, hitPredicate, key, isApplePlatform, createPointerRecognizer, RESERVED_ID_PREFIXES, RESERVED_ID_NAMES, DOUBLE_CLICK_MAX_MS } from '@weasel-js/gestures';
6
6
  export { CONTROL_SELECTOR, DRAG_THRESHOLD_PX, isInControlWithin, pastDragThreshold } from '@weasel-js/gestures';
@@ -1,4 +1,4 @@
1
- import { r as Dispatcher, d as ActionsRegistry, C as Contribution, W as WorldPoint, s as AffordanceHit, t as DispatchTrace, v as LongPressOptions, R as RuleCtx, w as DepSchema } from './index-C2EcHkCp.js';
1
+ import { r as Dispatcher, d as ActionsRegistry, C as Contribution, W as WorldPoint, s as AffordanceHit, t as DispatchTrace, v as LongPressOptions, R as RuleCtx, w as DepSchema } from './index-D-XFwx8D.js';
2
2
  import { RefObject } from 'react';
3
3
  import { BodyClassification } from '@weasel-js/gestures';
4
4
  import { PaintedCursorState, CursorSink } from '@weasel-js/cursor';
@@ -102,6 +102,13 @@ interface UseGestureDispatcherOptions {
102
102
  * nest under.
103
103
  */
104
104
  hears?: 'scope' | 'own';
105
+ /**
106
+ * With no canvas: hear no key while a canvas dispatching on `actions`
107
+ * itself holds the keys. That canvas hears everything this one does, and
108
+ * runs it with its own views and deps. For an app-wide dispatcher whose
109
+ * canvases share its registry. Default `false`.
110
+ */
111
+ yieldKeys?: boolean;
105
112
  /** Every entry in play, keyed by id: tools and any other contribution
106
113
  * whose bindings this dispatcher routes. */
107
114
  entriesById: ReadonlyMap<string, Contribution<unknown>>;
@@ -1,5 +1,5 @@
1
- export { a as DispatcherViewTarget, V as ViewIdResolver } from './internal-C8-r3Zmo.js';
2
- import './index-C2EcHkCp.js';
1
+ export { a as DispatcherViewTarget, V as ViewIdResolver } from './internal-nqfC0td8.js';
2
+ import './index-D-XFwx8D.js';
3
3
  import '@weasel-js/history';
4
4
  import '@weasel-js/prefs';
5
5
  import '@weasel-js/geom';
package/dist/react.d.ts CHANGED
@@ -1,9 +1,9 @@
1
- import { U as UseGestureDispatcherOptions } from './internal-C8-r3Zmo.js';
2
- export { D as DispatcherChannels } from './internal-C8-r3Zmo.js';
1
+ import { U as UseGestureDispatcherOptions } from './internal-nqfC0td8.js';
2
+ export { D as DispatcherChannels } from './internal-nqfC0td8.js';
3
3
  import * as react from 'react';
4
4
  import { ReactNode, ReactElement } from 'react';
5
- import { D as DepRegistry, a as DepName, b as DepSource, S as ScopeNode, L as LastOperationKeeper, A as Action, c as ActionDeps, M as MenuHost, d as ActionsRegistry, e as ActionDisabledReason, B as BoundGesture, f as ActionVariant, g as LastOperationStore, h as LastOperation, i as MenuDef, j as DepNode, T as ToolNode, K as KeymapDescription, W as WorldPoint, N as NodeId, k as KernelOverlay, C as Contribution, l as Tool, O as OverlayPosition } from './index-C2EcHkCp.js';
6
- export { m as ActiveToolContextProvider, n as ActiveToolContextProviderIfRoot, o as ActiveToolContextProviderProps, p as ActiveToolContextValue, u as useActiveToolContext, q as useOptionalActiveToolContext } from './index-C2EcHkCp.js';
5
+ import { D as DepRegistry, a as DepName, b as DepSource, S as ScopeNode, L as LastOperationKeeper, A as Action, c as ActionDeps, M as MenuHost, d as ActionsRegistry, e as ActionDisabledReason, B as BoundGesture, f as ActionVariant, g as LastOperationStore, h as LastOperation, i as MenuDef, j as DepNode, T as ToolNode, K as KeymapDescription, W as WorldPoint, N as NodeId, k as KernelOverlay, C as Contribution, l as Tool, O as OverlayPosition } from './index-D-XFwx8D.js';
6
+ export { m as ActiveToolContextProvider, n as ActiveToolContextProviderIfRoot, o as ActiveToolContextProviderProps, p as ActiveToolContextValue, u as useActiveToolContext, q as useOptionalActiveToolContext } from './index-D-XFwx8D.js';
7
7
  import { IconRef } from '@weasel-js/icons';
8
8
  import { ModeRegistry } from '@weasel-js/modes';
9
9
  import '@weasel-js/gestures';
@@ -119,6 +119,8 @@ interface CommandOptions {
119
119
  keys?: BoundGesture | readonly BoundGesture[];
120
120
  /** Shown beside the label. */
121
121
  icon?: IconRef;
122
+ /** The registry group a bar drawing one group gathers it under. */
123
+ group?: string;
122
124
  /** Words a palette finds it by and a tagged bar or menu gathers it under. */
123
125
  tags?: readonly string[];
124
126
  /** One entry each in a bar, menu or palette; `run` receives the chosen one's params. */
@@ -129,7 +131,7 @@ interface CommandOptions {
129
131
  * for the calling component's lifetime, so a menu, toolbar, palette or key
130
132
  * can run it. Callbacks and option functions may be new on every render: the
131
133
  * latest are read when used, and the action is replaced only when `id`,
132
- * `label`, `icon`, `keys`, `tags` or `variants` change by value.
134
+ * `label`, `icon`, `group`, `keys`, `tags` or `variants` change by value.
133
135
  */
134
136
  declare function useCommand(id: string, label: string, run: (params?: Readonly<Record<string, unknown>>) => void, options?: CommandOptions): void;
135
137
 
package/dist/react.js CHANGED
@@ -1,7 +1,7 @@
1
- import { createKeymapStack, createDispatchTrace, createDispatcher, describeKeymap, assembleEntries, liveScope, offhandKeyFor, makeToolOffhandAction, buildToolOffhandBindings, dlog, reportRouteConflicts, isTool, clientToCanvas, LONG_PRESS_HAPTIC_MS, multiTouchGestureId, openPointerSession, addCarrySurface, carryGestureId, anyBinding, isEditableTarget, focusedControlOwnsKey, itemsFromClipboardData, itemsFromDataTransfer, itemTypesFromDataTransfer, immediateParams } from './chunk-ZK72IBMI.js';
2
- import { useDepRegistry, actionsNodeOf, useAction, useActionsRegistry, useOptionalDepRegistry, ActionsNode, MenuHostContext, DepRegistryContext, ActionsContext } from './chunk-3SPPC6UP.js';
3
- export { ActionsProvider, DepRegistryProvider, useAction, useActionsRegistry, useDepRegistry, useDepSource, useMenuHost, useMenus, useOptionalDepRegistry } from './chunk-3SPPC6UP.js';
4
- import { NO_OVERRIDES, ScopeNode, depNodeOf, DepNode, actionCursor, buildDepsFromRequires } from './chunk-A6MN3I6R.js';
1
+ import { createKeymapStack, createDispatchTrace, createDispatcher, describeKeymap, assembleEntries, liveScope, offhandKeyFor, makeToolOffhandAction, buildToolOffhandBindings, dlog, reportRouteConflicts, isTool, clientToCanvas, LONG_PRESS_HAPTIC_MS, multiTouchGestureId, openPointerSession, addCarrySurface, carryGestureId, anyBinding, isEditableTarget, itemsFromClipboardData, itemsFromDataTransfer, itemTypesFromDataTransfer, immediateParams, focusedControlOwnsKey } from './chunk-ZUAFANMN.js';
2
+ import { useDepRegistry, actionsNodeOf, useAction, useActionsRegistry, useOptionalDepRegistry, ActionsNode, MenuHostContext, DepRegistryContext, ActionsContext } from './chunk-VAUJJODS.js';
3
+ export { ActionsProvider, DepRegistryProvider, useAction, useActionsRegistry, useDepRegistry, useDepSource, useMenuHost, useMenus, useOptionalDepRegistry } from './chunk-VAUJJODS.js';
4
+ import { NO_OVERRIDES, ScopeNode, depNodeOf, DepNode, actionCursor, buildDepsFromRequires } from './chunk-Z2BZBJ7W.js';
5
5
  import { createContext, useState, useContext, useEffect, useRef, useMemo, useCallback, useSyncExternalStore } from 'react';
6
6
  import { isApplePlatform, heldPointers, createPointerRecognizer, isInControlWithin, longPressEvents, stylusOf } from '@weasel-js/gestures';
7
7
  import { useLatest, useKitSettings, useStableByContent, sameList, isDev } from '@weasel-js/react';
@@ -187,7 +187,10 @@ function createDispatchCore(src) {
187
187
  }),
188
188
  batch,
189
189
  keymaps: () => src.context().keymaps,
190
- holdsKeys: () => canvas ? src.actions().holdsKeys() : src.actions().isActive(),
190
+ holdsKeys: () => {
191
+ const a = src.actions();
192
+ return canvas ? a.holdsKeys() : a.isActive() && !(src.yieldKeys === true && a.holdsKeys());
193
+ },
191
194
  pointerOver: () => over,
192
195
  setPointerOver: (next) => {
193
196
  over = canvas !== null && next;
@@ -1011,6 +1014,7 @@ function attachInput(canvas, src, channels) {
1011
1014
  clientToLocal: src.clientToLocal,
1012
1015
  context: src.context,
1013
1016
  actions: src.actions,
1017
+ yieldKeys: src.yieldKeys,
1014
1018
  uses: () => {
1015
1019
  redraw.sync(src.dispatchers());
1016
1020
  },
@@ -1112,7 +1116,7 @@ function trackPointerOver(listeners, canvas, core, keys) {
1112
1116
 
1113
1117
  // src/interactions/dispatcher/useGestureDispatcher.tsx
1114
1118
  function useGestureDispatcher(opts) {
1115
- const { canvasRef, actions, entriesById, enabled = true, keyboard = true, affordanceAt, classifyTarget, dispatcher: dispatcherOpt, trace: traceOpt, clientToWorld, clientToLocal, requestRedraw, paintedCursor, cursorSink, getRuleCtx, onClick, onDoubleClick, views, channels, longPress, claimKeys = false, hears = "scope" } = opts;
1119
+ const { canvasRef, actions, entriesById, enabled = true, keyboard = true, affordanceAt, classifyTarget, dispatcher: dispatcherOpt, trace: traceOpt, clientToWorld, clientToLocal, requestRedraw, paintedCursor, cursorSink, getRuleCtx, onClick, onDoubleClick, views, channels, longPress, claimKeys = false, hears = "scope", yieldKeys = false } = opts;
1116
1120
  const pointerChannel = channels?.pointer !== false;
1117
1121
  const hoverChannel = channels?.hover ?? pointerChannel;
1118
1122
  const wheelChannel = channels?.wheel !== false;
@@ -1201,7 +1205,8 @@ function useGestureDispatcher(opts) {
1201
1205
  kitSettings: () => kitSettingsRef.current,
1202
1206
  onClick: () => onClickRef.current,
1203
1207
  onDoubleClick: () => onDoubleClickRef.current,
1204
- clicks: clicksRef.current
1208
+ clicks: clicksRef.current,
1209
+ yieldKeys
1205
1210
  }, {
1206
1211
  keyboard,
1207
1212
  pointer: pointerChannel,
@@ -1215,6 +1220,7 @@ function useGestureDispatcher(opts) {
1215
1220
  }, [
1216
1221
  enabled,
1217
1222
  keyboard,
1223
+ yieldKeys,
1218
1224
  canvasRef,
1219
1225
  pointerChannel,
1220
1226
  hoverChannel,
@@ -1245,6 +1251,7 @@ function useCommand(id, label, run, options) {
1245
1251
  const hasEnabled = options?.enabled !== void 0;
1246
1252
  const hasActive = options?.active !== void 0;
1247
1253
  const icon = options?.icon;
1254
+ const group = options?.group;
1248
1255
  const action = useMemo(() => {
1249
1256
  const read = () => latest.current.options;
1250
1257
  const a = {
@@ -1258,8 +1265,9 @@ function useCommand(id, label, run, options) {
1258
1265
  if (hasEnabled) a.enabled = () => read()?.enabled?.() ?? true;
1259
1266
  if (hasActive) a.active = () => read()?.active?.() ?? false;
1260
1267
  if (icon !== void 0) a.icon = icon;
1268
+ if (group !== void 0) a.group = group;
1261
1269
  return a;
1262
- }, [id, label, icon, keys, tags, variants, hasEnabled, hasActive, latest]);
1270
+ }, [id, label, icon, group, keys, tags, variants, hasEnabled, hasActive, latest]);
1263
1271
  useAction(action);
1264
1272
  }
1265
1273
  function bindingOf(keys) {