@weasel-js/routing 1.5.1 → 1.6.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-ZZICE4J7.js → chunk-D2TZLDP5.js} +26 -12
- package/dist/chunk-D2TZLDP5.js.map +1 -0
- package/dist/{index-DhFGCPmN.d.ts → index-B_KvoXww.d.ts} +60 -10
- package/dist/index.d.ts +1 -1
- package/dist/index.js +18 -3
- package/dist/index.js.map +1 -1
- package/dist/react.d.ts +35 -3
- package/dist/react.js +127 -12
- package/dist/react.js.map +1 -1
- package/package.json +5 -5
- package/dist/chunk-ZZICE4J7.js.map +0 -1
|
@@ -542,6 +542,10 @@ interface InvocationCtx {
|
|
|
542
542
|
* per-sample stylus state when the browser reported it.
|
|
543
543
|
* Accumulated by the dispatcher on every `pointermove` pump event.
|
|
544
544
|
* Available only during `onMove` and `onEnd` calls (not on `start`).
|
|
545
|
+
*
|
|
546
|
+
* During `onMove` this is the dispatcher's live accumulator, and it grows
|
|
547
|
+
* under you — read it, don't retain it. On `onEnd` it is a snapshot, so
|
|
548
|
+
* that is where an action that keeps the trail should take it.
|
|
545
549
|
* Used by `lassoSelectAction` to build its polygon vertex list and by
|
|
546
550
|
* `insertAction`'s pencil kind to carry the freehand stroke.
|
|
547
551
|
*/
|
|
@@ -552,8 +556,18 @@ interface InvocationCtx {
|
|
|
552
556
|
deltaY: number;
|
|
553
557
|
deltaZ: number;
|
|
554
558
|
};
|
|
559
|
+
/** One `pinch` sample: `scale` is a multiplier since the previous sample,
|
|
560
|
+
* `rotation` degrees since it. See `PinchEvent`. */
|
|
561
|
+
pinch?: {
|
|
562
|
+
scale: number;
|
|
563
|
+
rotation: number;
|
|
564
|
+
};
|
|
555
565
|
multiTouch?: {
|
|
566
|
+
/** Canvas-local CSS pixels — see `MultitouchEvent.centroid`. Neither
|
|
567
|
+
* `world` nor `screen`: it is the space `zoomAt` anchors in, so passing
|
|
568
|
+
* it through `clientToWorld` removes the canvas origin twice. */
|
|
556
569
|
centroid: Point2;
|
|
570
|
+
/** Distance between the two primary pointers, in CSS pixels. */
|
|
557
571
|
spread: number;
|
|
558
572
|
rotation: number;
|
|
559
573
|
/**
|
|
@@ -565,6 +579,7 @@ interface InvocationCtx {
|
|
|
565
579
|
pinch?: {
|
|
566
580
|
startSpread: number;
|
|
567
581
|
currentSpread: number;
|
|
582
|
+
/** Canvas-local, same as the enclosing `centroid`. */
|
|
568
583
|
centroid: Point2;
|
|
569
584
|
};
|
|
570
585
|
};
|
|
@@ -923,6 +938,26 @@ interface ActionPresentation {
|
|
|
923
938
|
* surfaces derive a label from `defaultBinding` via their own
|
|
924
939
|
* formatter. */
|
|
925
940
|
shortcut?: string;
|
|
941
|
+
/** The distinct things a parametric action does, one per set of params —
|
|
942
|
+
* `flip` flips horizontally or vertically, `reorder.forward` moves one step
|
|
943
|
+
* or all the way. A bar, menu or palette shows one entry per variant and
|
|
944
|
+
* triggers the action with that variant's `params`. Omitted = the action
|
|
945
|
+
* is one entry. See `actionItems`. */
|
|
946
|
+
variants?: readonly ActionVariant[];
|
|
947
|
+
}
|
|
948
|
+
/**
|
|
949
|
+
* @experimental
|
|
950
|
+
* One entry a parametric action contributes to a bar, menu or palette.
|
|
951
|
+
*/
|
|
952
|
+
interface ActionVariant {
|
|
953
|
+
/** Unique within the action; joined to its id to make the entry's key. */
|
|
954
|
+
key: string;
|
|
955
|
+
label: string;
|
|
956
|
+
/** Falls back to the action's own `icon`. */
|
|
957
|
+
icon?: ReactNode | (() => ReactNode);
|
|
958
|
+
/** Passed to `trigger`, and matched against each binding's
|
|
959
|
+
* `opts.params` to find the variant's shortcuts. */
|
|
960
|
+
params: Readonly<Record<string, unknown>>;
|
|
926
961
|
}
|
|
927
962
|
/**
|
|
928
963
|
* @experimental
|
|
@@ -1050,6 +1085,27 @@ interface ActionSource {
|
|
|
1050
1085
|
list(): readonly Action[];
|
|
1051
1086
|
}
|
|
1052
1087
|
|
|
1088
|
+
/**
|
|
1089
|
+
* @experimental
|
|
1090
|
+
* The entries an action contributes to a bar, menu or palette — one per
|
|
1091
|
+
* variant, or the action itself when it declares none.
|
|
1092
|
+
*/
|
|
1093
|
+
|
|
1094
|
+
/** @experimental One renderable entry: an action, optionally with params. */
|
|
1095
|
+
interface ActionItem {
|
|
1096
|
+
/** `action.id`, or `action.id:variant.key` — unique across a registry. */
|
|
1097
|
+
key: string;
|
|
1098
|
+
action: Action;
|
|
1099
|
+
label: string;
|
|
1100
|
+
icon?: ReactNode | (() => ReactNode);
|
|
1101
|
+
/** What to pass to `trigger(action.id, params)`; absent for a plain action. */
|
|
1102
|
+
params?: Readonly<Record<string, unknown>>;
|
|
1103
|
+
}
|
|
1104
|
+
/** @experimental Expand `action` into the entries a surface renders. An
|
|
1105
|
+
* action without an immediate invoker has none: `trigger` cannot start a
|
|
1106
|
+
* drag, so a button for one would do nothing. */
|
|
1107
|
+
declare function actionItems(action: Action): ActionItem[];
|
|
1108
|
+
|
|
1053
1109
|
/**
|
|
1054
1110
|
* @experimental
|
|
1055
1111
|
* Palette-side evaluation of `Action.enabled`. The dispatcher calls the
|
|
@@ -1241,14 +1297,6 @@ interface ToolCtx<TScratch = unknown> {
|
|
|
1241
1297
|
* zoom/pan tools to convert event clientX/clientY to canvas-relative
|
|
1242
1298
|
* anchors. */
|
|
1243
1299
|
canvasRect: DOMRect;
|
|
1244
|
-
/** Screen-space pointer coords relative to `canvasRect`. Useful for
|
|
1245
|
-
* viewport tools that pan/zoom in screen space (e.g. hand-pan
|
|
1246
|
-
* computes deltas in pixels, not world units). Optional — populated
|
|
1247
|
-
* by the dispatcher on pointer events; absent on keyboard events. */
|
|
1248
|
-
screenPoint?: {
|
|
1249
|
-
x: number;
|
|
1250
|
-
y: number;
|
|
1251
|
-
};
|
|
1252
1300
|
/** Optional debug sink. When `<Canvas debug={...}>` is enabled, Canvas
|
|
1253
1301
|
* threads its sink here so tool-internal hit math (handle hitboxes,
|
|
1254
1302
|
* rotation handle, etc.) lands in the same overlay as Canvas's own
|
|
@@ -1992,7 +2040,9 @@ declare function mergeContributions(...bundles: readonly Contribution[][]): Cont
|
|
|
1992
2040
|
*/
|
|
1993
2041
|
interface ToolDef<TScratch = void, TOverlay = unknown> {
|
|
1994
2042
|
id: string;
|
|
1995
|
-
/** Capability tags for modality eligibility.
|
|
2043
|
+
/** Capability tags for modality eligibility. `defineTool` forwards these
|
|
2044
|
+
* onto `Tool.eligibility.capabilities`, which is where every gate reads
|
|
2045
|
+
* them — the assembled `Tool` carries no `capabilities` of its own. */
|
|
1996
2046
|
capabilities?: CapabilityTag[];
|
|
1997
2047
|
/**
|
|
1998
2048
|
* Actions this tool owns and needs registered while it is in the tools
|
|
@@ -2452,4 +2502,4 @@ interface DepSchema {
|
|
|
2452
2502
|
/** Every dep name declared by anything that has merged into {@link DepSchema}. */
|
|
2453
2503
|
type DepName = keyof DepSchema;
|
|
2454
2504
|
|
|
2455
|
-
export {
|
|
2505
|
+
export { type HitShape as $, type ActionsRegistry as A, type BindingOpts as B, type Contribution as C, type Dispatcher as D, type BuildRuleCtxArgs as E, COARSE_TARGET_SCALE as F, type Condition as G, type Conflict as H, type ContributionChrome as I, type ContributionRouting as J, DEFAULT_ALLOWED_CAPABILITIES as K, DEFAULT_DEVICE_PROFILE as L, type DebugSink as M, type DepName as N, type OverlayPosition as O, type DetectedDeviceFacts as P, type DeviceProfile as Q, type RuleCtx as R, type ScopedBinding as S, type Tool as T, type DispatchLogEntry as U, type DispatcherContext as V, type DragSample as W, type Eligibility as X, type EligibilityState as Y, type GestureBinding as Z, type HandleKind as _, type AffordanceHit as a, findConflicts as a$, type HotkeyTrigger as a0, INGEST_STRING_MIMES as a1, type ImmediateInvoker as a2, type InvocationCtx as a3, type Invoker as a4, type KeyBinding as a5, type MatchResult as a6, type ModeSwitchLogEntry as a7, type ModifierState as a8, NEVER as a9, type ToolDef as aA, type ToolKeybinding as aB, type ToolModifiers as aC, type ToolOffhandBindingSpec as aD, type ToolPresentation as aE, type ToolSlot as aF, type TraceLogEntry as aG, type UiOngoingControl as aH, type View as aI, type ViewportToolDef as aJ, actionBindings as aK, actionItems as aL, buildDepsFromRequires as aM, buildRouteRegistry as aN, buildRuleCtx as aO, buildToolOffhandBindings as aP, clientToCanvas as aQ, clientToCanvasRect as aR, createDispatcher as aS, defineTool as aT, defineViewportTool as aU, deleteScratch as aV, describeRule as aW, dlog as aX, evaluate as aY, evaluateEnabled as aZ, filterEligible as a_, type NodeId as aa, type OngoingHandle as ab, type OngoingInvoker as ac, type OngoingOverlay as ad, type OverlayRole as ae, PREDICATE_TARGET as af, type Point2 as ag, type PointerSession as ah, type PointerSessionCallbacks as ai, type PointerSessionCancelReason as aj, type PointerSessionOptions as ak, type RegistryEntry as al, type ResizeAnchor as am, type ResolveAllOptions as an, type ResolveOnlyResult as ao, type ResolvedCandidate as ap, type Rule as aq, type ScratchKey as ar, type ScratchStore as as, type SelectionApi as at, type SelectionExtendKey as au, type SelectionMode as av, type Selector as aw, TOOL_OFFHAND_ID as ax, type ToolBounds as ay, type ToolCtx as az, type DepSchema as b, getScratch as b0, isAnchor as b1, isAnchorOrControl as b2, isBody as b3, isControlHandle as b4, isEditableTarget as b5, isEmpty as b6, isResizeHandle as b7, isRotateHandle as b8, isSelectedBody as b9, isUnselectedBody as ba, itemsFromClipboardData as bb, itemsFromDataTransfer as bc, itemsFromFiles as bd, liveScope as be, makeToolOffhandAction as bf, matchBest as bg, matchSorted as bh, matchesKeyBinding as bi, mergeContributions as bj, offhandKeyFor as bk, openPointerSession as bl, pointerGestureId as bm, recordModeSwitch as bn, reportRouteConflicts as bo, resolveDeviceProfile as bp, resolveParams as bq, routeGestureForSpecKind as br, routesForSpec as bs, scopeBindings as bt, scratchKey as bu, setScratch as bv, specificity as bw, targetConsultsAffordance as bx, validateActionDefaultBinding as by, validateActionId as bz, type Action as c, type AnyToolOf as d, type DepRegistry as e, DepRegistryProvider as f, useDepSource as g, useOptionalDepRegistry as h, ALWAYS as i, type ActionDeps as j, ActionDisabledReason as k, type ActionDispatch as l, type ActionEnabledResult as m, type ActionEntry as n, type ActionItem as o, type ActionPresentation as p, type ActionSource as q, type ActionVariant as r, type ActionsProp as s, type AnyTool as t, useDepRegistry as u, type BindingScope as v, type BindingSource as w, type BodyPredicate as x, type BoundGesture as y, type Bounds as z };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export { i as ALWAYS, c as Action, j as ActionDeps, k as ActionDisabledReason, k as ActionDisabledReasonValue, l as ActionDispatch, m as ActionEnabledResult, n as ActionEntry, o as
|
|
1
|
+
export { i as ALWAYS, c as Action, j as ActionDeps, k as ActionDisabledReason, k as ActionDisabledReasonValue, l as ActionDispatch, m as ActionEnabledResult, n as ActionEntry, o as ActionItem, p as ActionPresentation, q as ActionSource, r as ActionVariant, s as ActionsProp, A as ActionsRegistry, a as AffordanceHit, t as AnyTool, d as AnyToolOf, B as BindingOpts, v as BindingScope, w as BindingSource, x as BodyPredicate, y as BoundGesture, z as Bounds, E as BuildRuleCtxArgs, F as COARSE_TARGET_SCALE, G as Condition, H as Conflict, C as Contribution, I as ContributionChrome, J as ContributionRouting, K as DEFAULT_ALLOWED_CAPABILITIES, L as DEFAULT_DEVICE_PROFILE, M as DebugSink, N as DepName, b as DepSchema, P as DetectedDeviceFacts, Q as DeviceProfile, U as DispatchLogEntry, D as Dispatcher, V as DispatcherContext, W as DragSample, X as Eligibility, Y as EligibilityState, Z as GestureBinding, _ as HandleKind, $ as HitShape, a0 as HotkeyTrigger, a1 as INGEST_STRING_MIMES, a2 as ImmediateInvoker, a3 as InvocationCtx, a4 as Invoker, a5 as KeyBinding, a6 as MatchResult, a7 as ModeSwitchLogEntry, a8 as ModifierState, a9 as NEVER, aa as NodeId, ab as OngoingHandle, ac as OngoingInvoker, ad as OngoingOverlay, O as OverlayPosition, ae as OverlayRole, af as PREDICATE_TARGET, ag as Point2, ah as PointerSession, ai as PointerSessionCallbacks, aj as PointerSessionCancelReason, ak as PointerSessionOptions, al as RegistryEntry, am as ResizeAnchor, an as ResolveAllOptions, ao as ResolveOnlyResult, ap as ResolvedCandidate, aq as Rule, R as RuleCtx, S as ScopedBinding, ar as ScratchKey, as as ScratchStore, at as SelectionApi, au as SelectionExtendKey, av as SelectionMode, aw as Selector, ax as TOOL_OFFHAND_ID, T as Tool, ay as ToolBounds, az as ToolCtx, aA as ToolDef, aB as ToolKeybinding, aC as ToolModifiers, aD as ToolOffhandBindingSpec, aE as ToolPresentation, aF as ToolSlot, aG as TraceLogEntry, aH as UiOngoingControl, aI as View, aJ as ViewportToolDef, aK as actionBindings, aL as actionItems, aM as buildDepsFromRequires, aN as buildRouteRegistry, aO as buildRuleCtx, aP as buildToolOffhandBindings, aQ as clientToCanvas, aR as clientToCanvasRect, aS as createDispatcher, aT as defineTool, aU as defineViewportTool, aV as deleteScratch, aW as describeRule, aX as dlog, aY as evaluate, aZ as evaluateEnabled, a_ as filterEligible, a$ as findConflicts, b0 as getScratch, b1 as isAnchor, b2 as isAnchorOrControl, b3 as isBody, b4 as isControlHandle, b5 as isEditableTarget, b6 as isEmpty, b7 as isResizeHandle, b8 as isRotateHandle, b9 as isSelectedBody, ba as isUnselectedBody, bb as itemsFromClipboardData, bc as itemsFromDataTransfer, bd as itemsFromFiles, be as liveScope, bf as makeToolOffhandAction, bg as matchBest, bh as matchSorted, bi as matchesKeyBinding, bj as mergeContributions, bk as offhandKeyFor, bl as openPointerSession, bm as pointerGestureId, bn as recordModeSwitch, bo as reportRouteConflicts, bp as resolveDeviceProfile, bq as resolveParams, br as routeGestureForSpecKind, bs as routesForSpec, bt as scopeBindings, bu as scratchKey, bv as setScratch, bw as specificity, bx as targetConsultsAffordance, by as validateActionDefaultBinding, bz as validateActionId } from './index-B_KvoXww.js';
|
|
2
2
|
export { ChannelRef, DescribeRouteOptions, GESTURE_DESCRIPTORS, GestureArgSpec, GestureDescriptor, GestureName, IngestItem, InputEvent, ModRequirement, ModifierKey, ParsedModifiers, ParsedRoute, PhaseAtom, PhaseContext, RESERVED_ID_NAMES, RESERVED_ID_PREFIXES, ROUTE_FIELD_DEFINITIONS, ROUTE_TERMS, RouteDescriptionPart, RouteFieldName, RouteTermLabel, canonicalModifiers, collapseShiftPairs, describeRoute, describeRouteParts, formatPhaseAtom, formatRoute, getGestureDescriptor, isKnownGestureName, matchKey, matchModifiers, matchPhase, matchSpec, matchTarget, parseRoute } from '@weasel-js/gestures';
|
|
3
3
|
import '@weasel-js/modes';
|
|
4
4
|
import 'react';
|
package/dist/index.js
CHANGED
|
@@ -1,7 +1,22 @@
|
|
|
1
|
-
import { isDev } from './chunk-
|
|
2
|
-
export { ALWAYS, COARSE_TARGET_SCALE, DEFAULT_ALLOWED_CAPABILITIES, DEFAULT_DEVICE_PROFILE, GESTURE_DESCRIPTORS, INGEST_STRING_MIMES, NEVER, PREDICATE_TARGET, RESERVED_ID_NAMES, RESERVED_ID_PREFIXES, ROUTE_FIELD_DEFINITIONS, ROUTE_TERMS, TOOL_OFFHAND_ID, actionBindings, buildDepsFromRequires, buildRouteRegistry, buildRuleCtx, buildToolOffhandBindings, canonicalModifiers, clientToCanvas, clientToCanvasRect, collapseShiftPairs, createDispatcher, describeRoute, describeRouteParts, describeRule, dlog, evaluate, filterEligible, findConflicts, formatPhaseAtom, formatRoute, getGestureDescriptor, isEditableTarget, isKnownGestureName, itemsFromClipboardData, itemsFromDataTransfer, itemsFromFiles, liveScope, makeToolOffhandAction, matchBest, matchKey, matchModifiers, matchPhase, matchSorted, matchSpec, matchTarget, matchesKeyBinding, offhandKeyFor, openPointerSession, parseRoute, pointerGestureId, recordModeSwitch, reportRouteConflicts, resolveDeviceProfile, resolveParams, routeGestureForSpecKind, routesForSpec, scopeBindings, specificity, targetConsultsAffordance, validateActionDefaultBinding, validateActionId } from './chunk-
|
|
1
|
+
import { isDev } from './chunk-D2TZLDP5.js';
|
|
2
|
+
export { ALWAYS, COARSE_TARGET_SCALE, DEFAULT_ALLOWED_CAPABILITIES, DEFAULT_DEVICE_PROFILE, GESTURE_DESCRIPTORS, INGEST_STRING_MIMES, NEVER, PREDICATE_TARGET, RESERVED_ID_NAMES, RESERVED_ID_PREFIXES, ROUTE_FIELD_DEFINITIONS, ROUTE_TERMS, TOOL_OFFHAND_ID, actionBindings, buildDepsFromRequires, buildRouteRegistry, buildRuleCtx, buildToolOffhandBindings, canonicalModifiers, clientToCanvas, clientToCanvasRect, collapseShiftPairs, createDispatcher, describeRoute, describeRouteParts, describeRule, dlog, evaluate, filterEligible, findConflicts, formatPhaseAtom, formatRoute, getGestureDescriptor, isEditableTarget, isKnownGestureName, itemsFromClipboardData, itemsFromDataTransfer, itemsFromFiles, liveScope, makeToolOffhandAction, matchBest, matchKey, matchModifiers, matchPhase, matchSorted, matchSpec, matchTarget, matchesKeyBinding, offhandKeyFor, openPointerSession, parseRoute, pointerGestureId, recordModeSwitch, reportRouteConflicts, resolveDeviceProfile, resolveParams, routeGestureForSpecKind, routesForSpec, scopeBindings, specificity, targetConsultsAffordance, validateActionDefaultBinding, validateActionId } from './chunk-D2TZLDP5.js';
|
|
3
3
|
import { RESERVED_ID_PREFIXES, RESERVED_ID_NAMES } from '@weasel-js/gestures';
|
|
4
4
|
|
|
5
|
+
// src/interactions/actions/actionItems.ts
|
|
6
|
+
function actionItems(action) {
|
|
7
|
+
if (action.invoker?.timing !== "immediate") return [];
|
|
8
|
+
if (!action.variants?.length) {
|
|
9
|
+
return [{ key: action.id, action, label: action.label, icon: action.icon }];
|
|
10
|
+
}
|
|
11
|
+
return action.variants.map((v) => ({
|
|
12
|
+
key: `${action.id}:${v.key}`,
|
|
13
|
+
action,
|
|
14
|
+
label: v.label,
|
|
15
|
+
icon: v.icon ?? action.icon,
|
|
16
|
+
params: v.params
|
|
17
|
+
}));
|
|
18
|
+
}
|
|
19
|
+
|
|
5
20
|
// src/interactions/actions/action.ts
|
|
6
21
|
var ActionDisabledReason = {
|
|
7
22
|
SelectionRequired: "selection-required",
|
|
@@ -155,6 +170,6 @@ function deleteScratch(store, key) {
|
|
|
155
170
|
return false;
|
|
156
171
|
}
|
|
157
172
|
|
|
158
|
-
export { ActionDisabledReason, defineTool, defineViewportTool, deleteScratch, evaluateEnabled, getScratch, isAnchor, isAnchorOrControl, isBody, isControlHandle, isEmpty, isResizeHandle, isRotateHandle, isSelectedBody, isUnselectedBody, mergeContributions, scratchKey, setScratch };
|
|
173
|
+
export { ActionDisabledReason, actionItems, defineTool, defineViewportTool, deleteScratch, evaluateEnabled, getScratch, isAnchor, isAnchorOrControl, isBody, isControlHandle, isEmpty, isResizeHandle, isRotateHandle, isSelectedBody, isUnselectedBody, mergeContributions, scratchKey, setScratch };
|
|
159
174
|
//# sourceMappingURL=index.js.map
|
|
160
175
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/interactions/actions/action.ts","../src/interactions/actions/actionEnabled.ts","../src/interactions/dispatcher/predicates.ts","../src/contributions/merge.ts","../src/tools/defineTool.ts","../src/tools/defineViewportTool.ts","../src/interactions/scratchKey.ts"],"names":["RESERVED_ID_PREFIXES","RESERVED_ID_NAMES"],"mappings":"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","file":"index.js","sourcesContent":["/**\n * @experimental\n * The `Action` descriptor, split along the line the dispatcher reads.\n * `ActionDispatch` is everything routing consults to decide whether an action\n * runs and what happens when it does; `ActionPresentation` is what a palette,\n * menu or toolbar renders. `Action` is both.\n */\nimport type { ReactNode } from 'react';\nimport type { CursorSpec } from '@weasel-js/cursor';\nimport type { ActionDeps, Invoker } from './invoker';\nimport type { BindingSource } from './binding';\nimport type { DepName } from '../../index';\n\n/**\n * @experimental\n * Closed enum of reasons an action might report itself as disabled. The\n * consumer (palette, menu, etc.) maps these symbolic values to display\n * strings via its own label map.\n */\nexport const ActionDisabledReason = {\n SelectionRequired: 'selection-required',\n SceneEmpty: 'scene-empty',\n NotApplicable: 'not-applicable',\n /** Sentinel: the predicate threw. Surfaced by `evaluateEnabled`'s catch. */\n PredicateThrew: 'predicate-threw',\n} as const;\n/** Why an action is unavailable right now. */\nexport type ActionDisabledReason =\n (typeof ActionDisabledReason)[keyof typeof ActionDisabledReason];\n\n/**\n * @experimental\n * What a palette, menu or toolbar renders for an action. No part of this is\n * read during dispatch.\n */\nexport interface ActionPresentation {\n label: string;\n /** Inline-SVG icon for palette / toolbar surfaces. Mirrors\n * `ToolPresentation.icon` so a generic `<ActionBar>` can render from\n * action metadata the same way `<ToolPalette>` renders from tool\n * metadata. May be a static `ReactNode` or a function (rare; useful\n * for state-aware icons like a \"lock\" toggle). */\n icon?: ReactNode | (() => ReactNode);\n /** Grouping key for palette/menu surfaces. Free-form string; the kit\n * ships defaults for `'align'` (six edges/centers), `'distribute'`\n * (two axes), and recommends `'pathfinder'` for boolean ops. */\n group?: string;\n /** Display override for the keyboard shortcut. When omitted, palette\n * surfaces derive a label from `defaultBinding` via their own\n * formatter. */\n shortcut?: string;\n}\n\n/**\n * @experimental\n * What routing consults: the bindings that reach the action, the deps its\n * invoker reads, the gates it passes, and the cursors it claims.\n */\nexport interface ActionDispatch extends BindingSource {\n /** Names of the deps this action's invoker reads (keys of `DepSchema`).\n * The dispatcher (and `trigger`, when `requires` is present) resolves\n * each name against the `DepRegistry` at invocation time and passes the\n * resulting bag to the invoker. Dev builds warn when the invoker reads a\n * dep it didn't declare here — see `buildDepsFromRequires`. */\n requires?: readonly DepName[];\n /** Pluggable invocation strategy. The gesture dispatcher routes matched\n * bindings through `invoker.start` / `invoker.run` depending on timing.\n * All kit-standard descriptors ship one; consumer-supplied actions\n * without an invoker can still register but won't be triggered. */\n invoker?: Invoker;\n /** When set to `'hotkey'`, this action's `defaultBinding` rides the hotkey\n * `BindingScope` instead of the ambient scope — meaning it beats any\n * active-tool binding on the same input shape. Use for tool-switch\n * shortcuts and global held-key triggers. Default: ambient. */\n scope?: 'hotkey';\n /**\n * @experimental\n * Optional predicate the command palette consults when rendering. Return\n * `true` when the action is currently triggerable. Return a reason string\n * (e.g. `'Selection required'`) when disabled — the palette greys out\n * the row, skips it in keyboard nav, ignores clicks, and shows the\n * reason next to the label. Keystroke dispatch (the registered binding)\n * is unaffected; the action's own `run` should self-guard.\n *\n * **Contract:** must be pure (no side effects), fast (< 4ms in dev), and\n * must not throw. If a call throws or exceeds the budget in dev mode,\n * `evaluateEnabled` logs a one-time warning per action id; throws are\n * caught and treated as disabled with reason `'(predicate threw)'`.\n *\n * Snapshot-on-open semantics: the palette evaluates `enabled` once when\n * opened and does NOT re-evaluate on selection changes while open. Live\n * reactive updates are deferred — palette is short-lived.\n *\n * The reason set is a closed enum — to add a new reason, edit\n * `ActionDisabledReason` and the consumer's display map.\n *\n * The optional `deps` argument is the same bag passed to\n * `ImmediateInvoker.run`; callers (`evaluateEnabled` / the ActionBar) may\n * synthesize it from the surrounding `DepRegistry` so predicates can\n * inspect selection / scene / etc. Predicates that don't need deps just\n * ignore the arg.\n *\n * `at` is the world point of the event being routed, when it has one — a\n * click, a press, a long-press. An action that only applies somewhere\n * (on a path segment, say) refuses other points here, so the dispatcher\n * falls through to the next binding and hover prediction shows the\n * action's `cursor` only where it would act. Palettes and keystrokes\n * pass no point; treat absent as \"anywhere\".\n */\n enabled?: (deps?: ActionDeps, at?: { x: number; y: number }) => true | ActionDisabledReason;\n /**\n * Declarative eligibility rule, evaluated against the current\n * `RuleCtx` by the dispatcher before invoking `start()`. Omitted =\n * always eligible.\n *\n * Accepts either a fluent `Condition` (callable with `.rule`) or a\n * raw `Rule` tree; the dispatcher normalizes via `.rule` unwrap.\n *\n * Prefer `capability:`-based rules (e.g. `{ capability: 'transforms-selection' }`)\n * over `mode:` rules — capability rules survive new modes being added\n * that allow the same capability.\n */\n eligible?:\n | import('../../eligibility').Rule\n | import('../../eligibility').Condition;\n /**\n * CSS cursor shown while the pointer hovers a spot where this action\n * would win the drag — or, when the drag's winner declares no cursor,\n * the click. The hover-cursor pump (in `useGestureDispatcher`) runs\n * `Dispatcher.resolveOnly` on each idle pointermove — the same match\n * walk a real press takes — and applies the winning action's `cursor`,\n * so the hint and the actual target stay in sync by construction. Omitted = no override (the active tool's\n * `Tool.cursor` shows). Affordance hits are resolved earlier in the\n * pump via `AffordanceRegion.cursor` and never reach this field.\n *\n * Static value only. Prediction runs `enabled()` but cannot run the\n * invoker, so an action that matches yet bails at `start()` (empty\n * handle) may still show its cursor — keep `enabled` accurate for\n * actions that declare one.\n */\n cursor?: CursorSpec;\n /**\n * CSS cursor shown while THIS action's ongoing handle is in flight —\n * grabbing while panning, `move` while dragging a selection, `crosshair`\n * while pulling a marquee.\n *\n * Separate from `cursor` because the two answer different questions:\n * `cursor` is a prediction (\"a drag from here would pan\"), this is a state\n * (\"you are panning\"). An action can declare either, both, or neither;\n * with only `cursor` set, the hover hint holds for the duration of the\n * gesture.\n *\n * This is where mid-gesture cursors live now. They used to come from the\n * tool side — `ViewportToolDef.engaged.cursor` for a phase-gated string,\n * or a function-form `Tool.cursor` reading the gesture scratch out of the\n * tool-routing dispatcher. Both belonged to a pipeline whose whole job was\n * being taken over by bindings, and neither could describe a cursor for an\n * action a tool doesn't own.\n */\n activeCursor?: CursorSpec;\n}\n\n/**\n * @experimental\n * Single registered action. v1: one binding per action.\n */\nexport interface Action extends ActionDispatch, ActionPresentation {}\n\n/**\n * @experimental\n * The whole of an actions registry the dispatcher reads. It walks the list\n * once per event to build its actionId lookup and never mutates it, so the\n * routing side depends on this rather than on `ActionsRegistry`, whose\n * register / mute / trigger surface is the React provider's.\n */\nexport interface ActionSource {\n list(): readonly Action[];\n}\n","/**\n * @experimental\n * Palette-side evaluation of `Action.enabled`. The dispatcher calls the\n * predicate raw as a gate; this is the surface that also enforces the\n * contract the predicate's JSDoc states — no throwing, under 4ms in dev.\n */\nimport type { ActionDeps } from './invoker';\nimport { ActionDisabledReason, type Action } from './action';\nimport { isDev } from '../../devFlag';\n\n/**\n * @experimental\n * Result of evaluating an Action's `enabled` predicate.\n */\nexport interface ActionEnabledResult {\n enabled: boolean;\n reason?: ActionDisabledReason;\n}\n\nconst enabledSlowWarned = new Set<string>();\nconst enabledThrewWarned = new Set<string>();\nconst ENABLED_BUDGET_MS = 4;\n/**\n * @experimental\n * Safely evaluate an action's `enabled` predicate. Returns `{enabled: true}`\n * when no predicate is supplied. Catches throws and treats them as disabled\n * with reason `'(predicate threw)'`. In dev mode, warns once per action id\n * when a single call exceeds 4ms (single frame at 240fps — generous; real\n * predicates should be sub-millisecond).\n */\nexport function evaluateEnabled(\n action: Action,\n deps?: ActionDeps,\n): ActionEnabledResult {\n if (!action.enabled) return { enabled: true };\n const dev = isDev();\n const now = (typeof performance !== 'undefined' && typeof performance.now === 'function')\n ? () => performance.now()\n : () => Date.now();\n const start = dev ? now() : 0;\n try {\n const result = action.enabled(deps);\n if (dev) {\n const elapsed = now() - start;\n if (elapsed > ENABLED_BUDGET_MS && !enabledSlowWarned.has(action.id)) {\n enabledSlowWarned.add(action.id);\n console.warn(\n `weasel actions: enabled() for action \"${action.id}\" took ${elapsed.toFixed(2)}ms ` +\n `(budget ${ENABLED_BUDGET_MS}ms). The predicate must be pure and fast — see Action.enabled JSDoc.`,\n );\n }\n }\n if (result === true) return { enabled: true };\n return { enabled: false, reason: result };\n } catch (e) {\n if (dev && !enabledThrewWarned.has(action.id)) {\n enabledThrewWarned.add(action.id);\n console.warn(\n `weasel actions: enabled() for action \"${action.id}\" threw; treating as disabled. ` +\n `The predicate must not throw — see Action.enabled JSDoc.`,\n e,\n );\n }\n return { enabled: false, reason: ActionDisabledReason.PredicateThrew };\n }\n}\n","/**\n * Named predicates for `defaultBinding.target.kindOf`. Each matches the\n * existing `kindOf` signature `(target: unknown, bodyTarget?: string) => boolean`\n * so they drop into action descriptors without a wrapper:\n *\n * target: { kindOf: isAnchor }\n *\n * Single source of truth for \"what does this affordance kind mean\" — adding\n * a new predicate here is what enables every action that needs the same\n * shape to read it. Drift prevention.\n */\n\n// ─── Body-class predicates (read the second arg) ───────────────────────\n\n/** A predicate that resolves from `bodyTarget` alone. The exclusive-claim\n * filter reads `readsAffordance`: without it a body predicate looks like it\n * consults the hit, and survives a claim that should have barred it. */\nexport type BodyPredicate = ((target: unknown, bodyTarget?: string) => boolean)\n & { readsAffordance: false };\n\nfunction bodyPredicate(\n fn: (target: unknown, bodyTarget?: string) => boolean,\n): BodyPredicate {\n return Object.assign(fn, { readsAffordance: false as const });\n}\n\n/** Matches any body hit — selected or unselected node body. */\nexport const isBody: BodyPredicate = bodyPredicate((_target, bodyTarget) =>\n bodyTarget === 'selected-body' || bodyTarget === 'unselected-body');\n\n/** Body hit specifically already in the selection. */\nexport const isSelectedBody: BodyPredicate = bodyPredicate((_target, bodyTarget) =>\n bodyTarget === 'selected-body');\n\n/** Body hit specifically NOT in the selection. */\nexport const isUnselectedBody: BodyPredicate = bodyPredicate((_target, bodyTarget) =>\n bodyTarget === 'unselected-body');\n\n/** Empty-canvas hit — no node beneath cursor. */\nexport const isEmpty: BodyPredicate = bodyPredicate((_target, bodyTarget) =>\n bodyTarget === 'empty');\n\n// ─── Affordance-kind predicates (read the first arg) ───────────────────\n\nfunction kindOf(target: unknown): string | undefined {\n if (typeof target !== 'object' || target === null) return undefined;\n const k = (target as { kind?: unknown }).kind;\n return typeof k === 'string' ? k : undefined;\n}\n\n/** Any corner resize handle — top-left/top-right/bottom-left/bottom-right. */\nexport const isResizeHandle = (target: unknown): boolean => {\n const k = kindOf(target);\n return k !== undefined && k.startsWith('handle:');\n};\n\n/** The rotate-around-center handle above the bounding box. */\nexport const isRotateHandle = (target: unknown): boolean =>\n kindOf(target) === 'rotate-handle';\n\n/** Any path anchor (the on-curve dot). */\nexport const isAnchor = (target: unknown): boolean => {\n const k = kindOf(target);\n return k !== undefined && /^anchor:\\d+$/.test(k);\n};\n\n/** Either control handle (controlIn or controlOut). */\nexport const isControlHandle = (target: unknown): boolean => {\n const k = kindOf(target);\n return k !== undefined && /^(controlIn|controlOut):\\d+$/.test(k);\n};\n\n/** Any of the three anchor-editing affordances (anchor + both controls). */\nexport const isAnchorOrControl = (target: unknown): boolean =>\n isAnchor(target) || isControlHandle(target);\n","import type { Contribution } from './types';\n\n/**\n * Concatenate contribution bundles into one registry, preserving order —\n * entry order decides which of two same-specificity bindings in one scope\n * tier wins, so it is part of the result, not an accident of it.\n *\n * Throws on a duplicate id rather than dropping one: a feature silently\n * losing its bindings is the failure this registry exists to make loud.\n */\nexport function mergeContributions(...bundles: readonly Contribution[][]): Contribution[] {\n const out: Contribution[] = [];\n const seen = new Set<string>();\n for (const bundle of bundles) {\n for (const entry of bundle) {\n if (seen.has(entry.id)) {\n throw new Error(\n `mergeContributions: duplicate contribution id \"${entry.id}\". `\n + `Two bundles registered the same id; rename one or merge them by hand.`,\n );\n }\n seen.add(entry.id);\n out.push(entry);\n }\n }\n return out;\n}\n","// src/tools/defineTool.ts\nimport type { Tool, ToolCtx } from './types';\nimport type { ToolDef } from './routeTypes';\nimport { RESERVED_ID_NAMES, RESERVED_ID_PREFIXES } from '@weasel-js/gestures';\nimport type { CursorSpec } from '@weasel-js/cursor';\n\n/** Validate that `id` is usable as a tool / channel id in the route\n * grammar. Rejects ids that start with a reserved sigil (would shadow\n * future grammar extensions) and ids that collide with phase keywords\n * (would parse as the bare-phase shorthand). */\nfunction validateId(id: string, kind: 'tool' | 'action'): void {\n if (id.length === 0) {\n throw new Error(`weasel: ${kind} id may not be empty`);\n }\n if (RESERVED_ID_PREFIXES.has(id[0]!)) {\n throw new Error(\n `weasel: ${kind} id \"${id}\" starts with reserved sigil \"${id[0]}\" ` +\n `(reserved set: ${[...RESERVED_ID_PREFIXES].join(' ')})`,\n );\n }\n if (RESERVED_ID_NAMES.has(id)) {\n throw new Error(\n `weasel: ${kind} id \"${id}\" collides with a reserved phase keyword ` +\n `(reserved: ${[...RESERVED_ID_NAMES].join(', ')})`,\n );\n }\n}\n\n/**\n * Build a `Tool<TScratch>` from a declarative `ToolDef<TScratch>`.\n *\n * This used to be a translator: `ToolDef` carried `initial` / `engaged` phase\n * tables of hit-keyed route handlers, and `defineTool` compiled them into the\n * imperative `pointer` / `drag` / `keyboard` / `wheel` handlers the\n * tool-routing dispatcher called. Both ends of that are gone — tools declare\n * `bindings` and the gesture dispatcher routes them — so what remains is\n * identity plumbing plus the id check and the cursor resolver.\n *\n * It stays a function rather than becoming a spread because the id validation\n * and the `initScratch` / `cursor` defaults are worth applying uniformly, and\n * because `Tool.def` gives reflection a handle on the authored form.\n */\nexport function defineTool<TScratch = void, TOverlay = unknown>(\n def: ToolDef<TScratch, TOverlay>,\n): Tool<TScratch, TOverlay> {\n validateId(def.id, 'tool');\n\n // Normalize `CursorSpec | ((ctx) => CursorSpec)` to the function form so\n // callers have one shape to deal with. Returns '' (not undefined) so the\n // signature satisfies `Tool.cursor: (ctx) => CursorSpec`.\n const resolveCursor = (ctx: ToolCtx<TScratch>): CursorSpec => {\n if (def.cursor == null) return '';\n return typeof def.cursor === 'function' ? def.cursor(ctx) : def.cursor;\n };\n\n return {\n id: def.id,\n eligibility: {\n focus: true,\n capabilities: def.capabilities,\n ...(def.hotkey ? { offhand: def.hotkey } : {}),\n },\n actions: def.actions,\n def,\n presentation: def.presentation as Tool<TScratch>['presentation'],\n keybinding: def.keybinding,\n onActivate: def.onActivate,\n onDeactivate: def.onDeactivate,\n initScratch: def.initScratch ?? (() => null as unknown as TScratch),\n cursor: resolveCursor,\n bindings: def.bindings,\n overlay: def.overlay,\n overlayPosition: def.overlayPosition,\n };\n}\n","import type { Tool } from './types';\nimport type { ViewportToolDef } from './routeTypes';\nimport { defineTool } from './defineTool';\n\n/**\n * Define a tool that acts on the viewport rather than the scene.\n *\n * This used to do real work: `ViewportPhaseDef` was a narrowed `PhaseDef`\n * (no click routes, drag restricted to the function form), and the factory\n * lifted it back to the permissive shape before handing it to `defineTool`.\n * With phase tables gone there is no shape left to narrow — a viewport tool\n * declares `bindings` like any other, pointing at `viewport.*` actions.\n *\n * It survives as an authoring signal. `defineViewportTool` at the top of a\n * hook says \"this tool moves the camera, not the drawing\", which is worth\n * more than the type gymnastics it replaced.\n */\nexport function defineViewportTool<TScratch = void, TOverlay = unknown>(\n def: ViewportToolDef<TScratch, TOverlay>,\n): Tool<TScratch, TOverlay> {\n return defineTool<TScratch, TOverlay>(def);\n}\n","/**\n * Typed keys for the gesture/behavior scratch store.\n *\n * Gestures expose `ctx.scratch: Record<string, unknown>` as a per-gesture\n * mutable bag that behaviors use to stash state across `onDown` / `onMove`\n * / `onEnd` calls. The store is `unknown`-valued because behaviors are\n * tool-agnostic — a single behavior may run under different tools with\n * different scratch shapes. Without a typing convention every read site\n * has to `(ctx.scratch as <some shape>)[KEY]`, and a writer changing the\n * shape can silently break readers with no compile-time signal.\n *\n * `ScratchKey<T>` is a phantom-typed string that carries its payload type\n * via a branded interface. `getScratch` and `setScratch` use the brand to\n * narrow / constrain at the typing layer; at runtime the key is just its\n * underlying string and the store remains a plain `Record`.\n *\n * @example\n * ```ts\n * // Module-level (or behavior-level) constant, shared by writer + reader:\n * const LASSO_VERTICES = scratchKey<readonly { x: number; y: number }[]>('lasso.vertices');\n *\n * // Writer (a tool's onMove):\n * setScratch(ctx.scratch, LASSO_VERTICES, vertices);\n *\n * // Reader (a behavior's onEnd):\n * const vertices = getScratch(ctx.scratch, LASSO_VERTICES) ?? [];\n * // ^? readonly { x: number; y: number }[] | undefined\n * ```\n */\n\n/** Phantom-typed key for a scratch slot. The `__scratchKeyPayload` phantom\n * field carries the value type without occupying any runtime memory. */\nexport interface ScratchKey<T> {\n readonly name: string;\n /** Phantom — never read at runtime. Only present so TypeScript can\n * recover `T` at use sites. */\n readonly __scratchKeyPayload?: (_: T) => T;\n}\n\n/** Compatible scratch store shape. The kit's gesture context's `scratch`\n * field already satisfies this; consumers don't need to construct one. */\nexport type ScratchStore = Record<string, unknown>;\n\n/**\n * Make a typed scratch key. Use module-level constants so the same key\n * is shared by writer and reader.\n *\n * Namespace the name by behavior or feature to avoid collisions\n * (`'behavior.field'` is a good convention). Two keys with the same\n * `name` refer to the same slot at runtime — the type parameter is a\n * compile-time contract, not a uniqueness guarantee.\n */\nexport function scratchKey<T>(name: string): ScratchKey<T> {\n return { name };\n}\n\n/** Read a typed slot from the scratch store. Returns `undefined` if\n * nothing has been written under the key. */\nexport function getScratch<T>(\n store: ScratchStore,\n key: ScratchKey<T>,\n): T | undefined {\n return store[key.name] as T | undefined;\n}\n\n/** Write a value to a typed slot. Overwrites whatever was there. */\nexport function setScratch<T>(\n store: ScratchStore,\n key: ScratchKey<T>,\n value: T,\n): void {\n store[key.name] = value;\n}\n\n/** Remove a slot from the scratch store. Returns `true` if it was set,\n * `false` if it wasn't. */\nexport function deleteScratch<T>(\n store: ScratchStore,\n key: ScratchKey<T>,\n): boolean {\n if (Object.prototype.hasOwnProperty.call(store, key.name)) {\n delete store[key.name];\n return true;\n }\n return false;\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/interactions/actions/actionItems.ts","../src/interactions/actions/action.ts","../src/interactions/actions/actionEnabled.ts","../src/interactions/dispatcher/predicates.ts","../src/contributions/merge.ts","../src/tools/defineTool.ts","../src/tools/defineViewportTool.ts","../src/interactions/scratchKey.ts"],"names":["RESERVED_ID_PREFIXES","RESERVED_ID_NAMES"],"mappings":"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","file":"index.js","sourcesContent":["/**\n * @experimental\n * The entries an action contributes to a bar, menu or palette — one per\n * variant, or the action itself when it declares none.\n */\nimport type { ReactNode } from 'react';\nimport type { Action } from './action';\n\n/** @experimental One renderable entry: an action, optionally with params. */\nexport interface ActionItem {\n /** `action.id`, or `action.id:variant.key` — unique across a registry. */\n key: string;\n action: Action;\n label: string;\n icon?: ReactNode | (() => ReactNode);\n /** What to pass to `trigger(action.id, params)`; absent for a plain action. */\n params?: Readonly<Record<string, unknown>>;\n}\n\n/** @experimental Expand `action` into the entries a surface renders. An\n * action without an immediate invoker has none: `trigger` cannot start a\n * drag, so a button for one would do nothing. */\nexport function actionItems(action: Action): ActionItem[] {\n if (action.invoker?.timing !== 'immediate') return [];\n if (!action.variants?.length) {\n return [{ key: action.id, action, label: action.label, icon: action.icon }];\n }\n return action.variants.map((v) => ({\n key: `${action.id}:${v.key}`,\n action,\n label: v.label,\n icon: v.icon ?? action.icon,\n params: v.params,\n }));\n}\n","/**\n * @experimental\n * The `Action` descriptor, split along the line the dispatcher reads.\n * `ActionDispatch` is everything routing consults to decide whether an action\n * runs and what happens when it does; `ActionPresentation` is what a palette,\n * menu or toolbar renders. `Action` is both.\n */\nimport type { ReactNode } from 'react';\nimport type { CursorSpec } from '@weasel-js/cursor';\nimport type { ActionDeps, Invoker } from './invoker';\nimport type { BindingSource } from './binding';\nimport type { DepName } from '../../index';\n\n/**\n * @experimental\n * Closed enum of reasons an action might report itself as disabled. The\n * consumer (palette, menu, etc.) maps these symbolic values to display\n * strings via its own label map.\n */\nexport const ActionDisabledReason = {\n SelectionRequired: 'selection-required',\n SceneEmpty: 'scene-empty',\n NotApplicable: 'not-applicable',\n /** Sentinel: the predicate threw. Surfaced by `evaluateEnabled`'s catch. */\n PredicateThrew: 'predicate-threw',\n} as const;\n/** Why an action is unavailable right now. */\nexport type ActionDisabledReason =\n (typeof ActionDisabledReason)[keyof typeof ActionDisabledReason];\n\n/**\n * @experimental\n * What a palette, menu or toolbar renders for an action. No part of this is\n * read during dispatch.\n */\nexport interface ActionPresentation {\n label: string;\n /** Inline-SVG icon for palette / toolbar surfaces. Mirrors\n * `ToolPresentation.icon` so a generic `<ActionBar>` can render from\n * action metadata the same way `<ToolPalette>` renders from tool\n * metadata. May be a static `ReactNode` or a function (rare; useful\n * for state-aware icons like a \"lock\" toggle). */\n icon?: ReactNode | (() => ReactNode);\n /** Grouping key for palette/menu surfaces. Free-form string; the kit\n * ships defaults for `'align'` (six edges/centers), `'distribute'`\n * (two axes), and recommends `'pathfinder'` for boolean ops. */\n group?: string;\n /** Display override for the keyboard shortcut. When omitted, palette\n * surfaces derive a label from `defaultBinding` via their own\n * formatter. */\n shortcut?: string;\n /** The distinct things a parametric action does, one per set of params —\n * `flip` flips horizontally or vertically, `reorder.forward` moves one step\n * or all the way. A bar, menu or palette shows one entry per variant and\n * triggers the action with that variant's `params`. Omitted = the action\n * is one entry. See `actionItems`. */\n variants?: readonly ActionVariant[];\n}\n\n/**\n * @experimental\n * One entry a parametric action contributes to a bar, menu or palette.\n */\nexport interface ActionVariant {\n /** Unique within the action; joined to its id to make the entry's key. */\n key: string;\n label: string;\n /** Falls back to the action's own `icon`. */\n icon?: ReactNode | (() => ReactNode);\n /** Passed to `trigger`, and matched against each binding's\n * `opts.params` to find the variant's shortcuts. */\n params: Readonly<Record<string, unknown>>;\n}\n\n/**\n * @experimental\n * What routing consults: the bindings that reach the action, the deps its\n * invoker reads, the gates it passes, and the cursors it claims.\n */\nexport interface ActionDispatch extends BindingSource {\n /** Names of the deps this action's invoker reads (keys of `DepSchema`).\n * The dispatcher (and `trigger`, when `requires` is present) resolves\n * each name against the `DepRegistry` at invocation time and passes the\n * resulting bag to the invoker. Dev builds warn when the invoker reads a\n * dep it didn't declare here — see `buildDepsFromRequires`. */\n requires?: readonly DepName[];\n /** Pluggable invocation strategy. The gesture dispatcher routes matched\n * bindings through `invoker.start` / `invoker.run` depending on timing.\n * All kit-standard descriptors ship one; consumer-supplied actions\n * without an invoker can still register but won't be triggered. */\n invoker?: Invoker;\n /** When set to `'hotkey'`, this action's `defaultBinding` rides the hotkey\n * `BindingScope` instead of the ambient scope — meaning it beats any\n * active-tool binding on the same input shape. Use for tool-switch\n * shortcuts and global held-key triggers. Default: ambient. */\n scope?: 'hotkey';\n /**\n * @experimental\n * Optional predicate the command palette consults when rendering. Return\n * `true` when the action is currently triggerable. Return a reason string\n * (e.g. `'Selection required'`) when disabled — the palette greys out\n * the row, skips it in keyboard nav, ignores clicks, and shows the\n * reason next to the label. Keystroke dispatch (the registered binding)\n * is unaffected; the action's own `run` should self-guard.\n *\n * **Contract:** must be pure (no side effects), fast (< 4ms in dev), and\n * must not throw. If a call throws or exceeds the budget in dev mode,\n * `evaluateEnabled` logs a one-time warning per action id; throws are\n * caught and treated as disabled with reason `'(predicate threw)'`.\n *\n * Snapshot-on-open semantics: the palette evaluates `enabled` once when\n * opened and does NOT re-evaluate on selection changes while open. Live\n * reactive updates are deferred — palette is short-lived.\n *\n * The reason set is a closed enum — to add a new reason, edit\n * `ActionDisabledReason` and the consumer's display map.\n *\n * The optional `deps` argument is the same bag passed to\n * `ImmediateInvoker.run`; callers (`evaluateEnabled` / the ActionBar) may\n * synthesize it from the surrounding `DepRegistry` so predicates can\n * inspect selection / scene / etc. Predicates that don't need deps just\n * ignore the arg.\n *\n * `at` is the world point of the event being routed, when it has one — a\n * click, a press, a long-press. An action that only applies somewhere\n * (on a path segment, say) refuses other points here, so the dispatcher\n * falls through to the next binding and hover prediction shows the\n * action's `cursor` only where it would act. Palettes and keystrokes\n * pass no point; treat absent as \"anywhere\".\n */\n enabled?: (deps?: ActionDeps, at?: { x: number; y: number }) => true | ActionDisabledReason;\n /**\n * Declarative eligibility rule, evaluated against the current\n * `RuleCtx` by the dispatcher before invoking `start()`. Omitted =\n * always eligible.\n *\n * Accepts either a fluent `Condition` (callable with `.rule`) or a\n * raw `Rule` tree; the dispatcher normalizes via `.rule` unwrap.\n *\n * Prefer `capability:`-based rules (e.g. `{ capability: 'transforms-selection' }`)\n * over `mode:` rules — capability rules survive new modes being added\n * that allow the same capability.\n */\n eligible?:\n | import('../../eligibility').Rule\n | import('../../eligibility').Condition;\n /**\n * CSS cursor shown while the pointer hovers a spot where this action\n * would win the drag — or, when the drag's winner declares no cursor,\n * the click. The hover-cursor pump (in `useGestureDispatcher`) runs\n * `Dispatcher.resolveOnly` on each idle pointermove — the same match\n * walk a real press takes — and applies the winning action's `cursor`,\n * so the hint and the actual target stay in sync by construction. Omitted = no override (the active tool's\n * `Tool.cursor` shows). Affordance hits are resolved earlier in the\n * pump via `AffordanceRegion.cursor` and never reach this field.\n *\n * Static value only. Prediction runs `enabled()` but cannot run the\n * invoker, so an action that matches yet bails at `start()` (empty\n * handle) may still show its cursor — keep `enabled` accurate for\n * actions that declare one.\n */\n cursor?: CursorSpec;\n /**\n * CSS cursor shown while THIS action's ongoing handle is in flight —\n * grabbing while panning, `move` while dragging a selection, `crosshair`\n * while pulling a marquee.\n *\n * Separate from `cursor` because the two answer different questions:\n * `cursor` is a prediction (\"a drag from here would pan\"), this is a state\n * (\"you are panning\"). An action can declare either, both, or neither;\n * with only `cursor` set, the hover hint holds for the duration of the\n * gesture.\n *\n * This is where mid-gesture cursors live now. They used to come from the\n * tool side — `ViewportToolDef.engaged.cursor` for a phase-gated string,\n * or a function-form `Tool.cursor` reading the gesture scratch out of the\n * tool-routing dispatcher. Both belonged to a pipeline whose whole job was\n * being taken over by bindings, and neither could describe a cursor for an\n * action a tool doesn't own.\n */\n activeCursor?: CursorSpec;\n}\n\n/**\n * @experimental\n * Single registered action. v1: one binding per action.\n */\nexport interface Action extends ActionDispatch, ActionPresentation {}\n\n/**\n * @experimental\n * The whole of an actions registry the dispatcher reads. It walks the list\n * once per event to build its actionId lookup and never mutates it, so the\n * routing side depends on this rather than on `ActionsRegistry`, whose\n * register / mute / trigger surface is the React provider's.\n */\nexport interface ActionSource {\n list(): readonly Action[];\n}\n","/**\n * @experimental\n * Palette-side evaluation of `Action.enabled`. The dispatcher calls the\n * predicate raw as a gate; this is the surface that also enforces the\n * contract the predicate's JSDoc states — no throwing, under 4ms in dev.\n */\nimport type { ActionDeps } from './invoker';\nimport { ActionDisabledReason, type Action } from './action';\nimport { isDev } from '../../devFlag';\n\n/**\n * @experimental\n * Result of evaluating an Action's `enabled` predicate.\n */\nexport interface ActionEnabledResult {\n enabled: boolean;\n reason?: ActionDisabledReason;\n}\n\nconst enabledSlowWarned = new Set<string>();\nconst enabledThrewWarned = new Set<string>();\nconst ENABLED_BUDGET_MS = 4;\n/**\n * @experimental\n * Safely evaluate an action's `enabled` predicate. Returns `{enabled: true}`\n * when no predicate is supplied. Catches throws and treats them as disabled\n * with reason `'(predicate threw)'`. In dev mode, warns once per action id\n * when a single call exceeds 4ms (single frame at 240fps — generous; real\n * predicates should be sub-millisecond).\n */\nexport function evaluateEnabled(\n action: Action,\n deps?: ActionDeps,\n): ActionEnabledResult {\n if (!action.enabled) return { enabled: true };\n const dev = isDev();\n const now = (typeof performance !== 'undefined' && typeof performance.now === 'function')\n ? () => performance.now()\n : () => Date.now();\n const start = dev ? now() : 0;\n try {\n const result = action.enabled(deps);\n if (dev) {\n const elapsed = now() - start;\n if (elapsed > ENABLED_BUDGET_MS && !enabledSlowWarned.has(action.id)) {\n enabledSlowWarned.add(action.id);\n console.warn(\n `weasel actions: enabled() for action \"${action.id}\" took ${elapsed.toFixed(2)}ms ` +\n `(budget ${ENABLED_BUDGET_MS}ms). The predicate must be pure and fast — see Action.enabled JSDoc.`,\n );\n }\n }\n if (result === true) return { enabled: true };\n return { enabled: false, reason: result };\n } catch (e) {\n if (dev && !enabledThrewWarned.has(action.id)) {\n enabledThrewWarned.add(action.id);\n console.warn(\n `weasel actions: enabled() for action \"${action.id}\" threw; treating as disabled. ` +\n `The predicate must not throw — see Action.enabled JSDoc.`,\n e,\n );\n }\n return { enabled: false, reason: ActionDisabledReason.PredicateThrew };\n }\n}\n","/**\n * Named predicates for `defaultBinding.target.kindOf`. Each matches the\n * existing `kindOf` signature `(target: unknown, bodyTarget?: string) => boolean`\n * so they drop into action descriptors without a wrapper:\n *\n * target: { kindOf: isAnchor }\n *\n * Single source of truth for \"what does this affordance kind mean\" — adding\n * a new predicate here is what enables every action that needs the same\n * shape to read it. Drift prevention.\n */\n\n// ─── Body-class predicates (read the second arg) ───────────────────────\n\n/** A predicate that resolves from `bodyTarget` alone. The exclusive-claim\n * filter reads `readsAffordance`: without it a body predicate looks like it\n * consults the hit, and survives a claim that should have barred it. */\nexport type BodyPredicate = ((target: unknown, bodyTarget?: string) => boolean)\n & { readsAffordance: false };\n\nfunction bodyPredicate(\n fn: (target: unknown, bodyTarget?: string) => boolean,\n): BodyPredicate {\n return Object.assign(fn, { readsAffordance: false as const });\n}\n\n/** Matches any body hit — selected or unselected node body. */\nexport const isBody: BodyPredicate = bodyPredicate((_target, bodyTarget) =>\n bodyTarget === 'selected-body' || bodyTarget === 'unselected-body');\n\n/** Body hit specifically already in the selection. */\nexport const isSelectedBody: BodyPredicate = bodyPredicate((_target, bodyTarget) =>\n bodyTarget === 'selected-body');\n\n/** Body hit specifically NOT in the selection. */\nexport const isUnselectedBody: BodyPredicate = bodyPredicate((_target, bodyTarget) =>\n bodyTarget === 'unselected-body');\n\n/** Empty-canvas hit — no node beneath cursor. */\nexport const isEmpty: BodyPredicate = bodyPredicate((_target, bodyTarget) =>\n bodyTarget === 'empty');\n\n// ─── Affordance-kind predicates (read the first arg) ───────────────────\n\nfunction kindOf(target: unknown): string | undefined {\n if (typeof target !== 'object' || target === null) return undefined;\n const k = (target as { kind?: unknown }).kind;\n return typeof k === 'string' ? k : undefined;\n}\n\n/** Any corner resize handle — top-left/top-right/bottom-left/bottom-right. */\nexport const isResizeHandle = (target: unknown): boolean => {\n const k = kindOf(target);\n return k !== undefined && k.startsWith('handle:');\n};\n\n/** The rotate-around-center handle above the bounding box. */\nexport const isRotateHandle = (target: unknown): boolean =>\n kindOf(target) === 'rotate-handle';\n\n/** Any path anchor (the on-curve dot). */\nexport const isAnchor = (target: unknown): boolean => {\n const k = kindOf(target);\n return k !== undefined && /^anchor:\\d+$/.test(k);\n};\n\n/** Either control handle (controlIn or controlOut). */\nexport const isControlHandle = (target: unknown): boolean => {\n const k = kindOf(target);\n return k !== undefined && /^(controlIn|controlOut):\\d+$/.test(k);\n};\n\n/** Any of the three anchor-editing affordances (anchor + both controls). */\nexport const isAnchorOrControl = (target: unknown): boolean =>\n isAnchor(target) || isControlHandle(target);\n","import type { Contribution } from './types';\n\n/**\n * Concatenate contribution bundles into one registry, preserving order —\n * entry order decides which of two same-specificity bindings in one scope\n * tier wins, so it is part of the result, not an accident of it.\n *\n * Throws on a duplicate id rather than dropping one: a feature silently\n * losing its bindings is the failure this registry exists to make loud.\n */\nexport function mergeContributions(...bundles: readonly Contribution[][]): Contribution[] {\n const out: Contribution[] = [];\n const seen = new Set<string>();\n for (const bundle of bundles) {\n for (const entry of bundle) {\n if (seen.has(entry.id)) {\n throw new Error(\n `mergeContributions: duplicate contribution id \"${entry.id}\". `\n + `Two bundles registered the same id; rename one or merge them by hand.`,\n );\n }\n seen.add(entry.id);\n out.push(entry);\n }\n }\n return out;\n}\n","// src/tools/defineTool.ts\nimport type { Tool, ToolCtx } from './types';\nimport type { ToolDef } from './routeTypes';\nimport { RESERVED_ID_NAMES, RESERVED_ID_PREFIXES } from '@weasel-js/gestures';\nimport type { CursorSpec } from '@weasel-js/cursor';\n\n/** Validate that `id` is usable as a tool / channel id in the route\n * grammar. Rejects ids that start with a reserved sigil (would shadow\n * future grammar extensions) and ids that collide with phase keywords\n * (would parse as the bare-phase shorthand). */\nfunction validateId(id: string, kind: 'tool' | 'action'): void {\n if (id.length === 0) {\n throw new Error(`weasel: ${kind} id may not be empty`);\n }\n if (RESERVED_ID_PREFIXES.has(id[0]!)) {\n throw new Error(\n `weasel: ${kind} id \"${id}\" starts with reserved sigil \"${id[0]}\" ` +\n `(reserved set: ${[...RESERVED_ID_PREFIXES].join(' ')})`,\n );\n }\n if (RESERVED_ID_NAMES.has(id)) {\n throw new Error(\n `weasel: ${kind} id \"${id}\" collides with a reserved phase keyword ` +\n `(reserved: ${[...RESERVED_ID_NAMES].join(', ')})`,\n );\n }\n}\n\n/**\n * Build a `Tool<TScratch>` from a declarative `ToolDef<TScratch>`.\n *\n * This used to be a translator: `ToolDef` carried `initial` / `engaged` phase\n * tables of hit-keyed route handlers, and `defineTool` compiled them into the\n * imperative `pointer` / `drag` / `keyboard` / `wheel` handlers the\n * tool-routing dispatcher called. Both ends of that are gone — tools declare\n * `bindings` and the gesture dispatcher routes them — so what remains is\n * identity plumbing plus the id check and the cursor resolver.\n *\n * It stays a function rather than becoming a spread because the id validation\n * and the `initScratch` / `cursor` defaults are worth applying uniformly, and\n * because `Tool.def` gives reflection a handle on the authored form.\n */\nexport function defineTool<TScratch = void, TOverlay = unknown>(\n def: ToolDef<TScratch, TOverlay>,\n): Tool<TScratch, TOverlay> {\n validateId(def.id, 'tool');\n\n // Normalize `CursorSpec | ((ctx) => CursorSpec)` to the function form so\n // callers have one shape to deal with. Returns '' (not undefined) so the\n // signature satisfies `Tool.cursor: (ctx) => CursorSpec`.\n const resolveCursor = (ctx: ToolCtx<TScratch>): CursorSpec => {\n if (def.cursor == null) return '';\n return typeof def.cursor === 'function' ? def.cursor(ctx) : def.cursor;\n };\n\n return {\n id: def.id,\n eligibility: {\n focus: true,\n capabilities: def.capabilities,\n ...(def.hotkey ? { offhand: def.hotkey } : {}),\n },\n actions: def.actions,\n def,\n presentation: def.presentation as Tool<TScratch>['presentation'],\n keybinding: def.keybinding,\n onActivate: def.onActivate,\n onDeactivate: def.onDeactivate,\n initScratch: def.initScratch ?? (() => null as unknown as TScratch),\n cursor: resolveCursor,\n bindings: def.bindings,\n overlay: def.overlay,\n overlayPosition: def.overlayPosition,\n };\n}\n","import type { Tool } from './types';\nimport type { ViewportToolDef } from './routeTypes';\nimport { defineTool } from './defineTool';\n\n/**\n * Define a tool that acts on the viewport rather than the scene.\n *\n * This used to do real work: `ViewportPhaseDef` was a narrowed `PhaseDef`\n * (no click routes, drag restricted to the function form), and the factory\n * lifted it back to the permissive shape before handing it to `defineTool`.\n * With phase tables gone there is no shape left to narrow — a viewport tool\n * declares `bindings` like any other, pointing at `viewport.*` actions.\n *\n * It survives as an authoring signal. `defineViewportTool` at the top of a\n * hook says \"this tool moves the camera, not the drawing\", which is worth\n * more than the type gymnastics it replaced.\n */\nexport function defineViewportTool<TScratch = void, TOverlay = unknown>(\n def: ViewportToolDef<TScratch, TOverlay>,\n): Tool<TScratch, TOverlay> {\n return defineTool<TScratch, TOverlay>(def);\n}\n","/**\n * Typed keys for the gesture/behavior scratch store.\n *\n * Gestures expose `ctx.scratch: Record<string, unknown>` as a per-gesture\n * mutable bag that behaviors use to stash state across `onDown` / `onMove`\n * / `onEnd` calls. The store is `unknown`-valued because behaviors are\n * tool-agnostic — a single behavior may run under different tools with\n * different scratch shapes. Without a typing convention every read site\n * has to `(ctx.scratch as <some shape>)[KEY]`, and a writer changing the\n * shape can silently break readers with no compile-time signal.\n *\n * `ScratchKey<T>` is a phantom-typed string that carries its payload type\n * via a branded interface. `getScratch` and `setScratch` use the brand to\n * narrow / constrain at the typing layer; at runtime the key is just its\n * underlying string and the store remains a plain `Record`.\n *\n * @example\n * ```ts\n * // Module-level (or behavior-level) constant, shared by writer + reader:\n * const LASSO_VERTICES = scratchKey<readonly { x: number; y: number }[]>('lasso.vertices');\n *\n * // Writer (a tool's onMove):\n * setScratch(ctx.scratch, LASSO_VERTICES, vertices);\n *\n * // Reader (a behavior's onEnd):\n * const vertices = getScratch(ctx.scratch, LASSO_VERTICES) ?? [];\n * // ^? readonly { x: number; y: number }[] | undefined\n * ```\n */\n\n/** Phantom-typed key for a scratch slot. The `__scratchKeyPayload` phantom\n * field carries the value type without occupying any runtime memory. */\nexport interface ScratchKey<T> {\n readonly name: string;\n /** Phantom — never read at runtime. Only present so TypeScript can\n * recover `T` at use sites. */\n readonly __scratchKeyPayload?: (_: T) => T;\n}\n\n/** Compatible scratch store shape. The kit's gesture context's `scratch`\n * field already satisfies this; consumers don't need to construct one. */\nexport type ScratchStore = Record<string, unknown>;\n\n/**\n * Make a typed scratch key. Use module-level constants so the same key\n * is shared by writer and reader.\n *\n * Namespace the name by behavior or feature to avoid collisions\n * (`'behavior.field'` is a good convention). Two keys with the same\n * `name` refer to the same slot at runtime — the type parameter is a\n * compile-time contract, not a uniqueness guarantee.\n */\nexport function scratchKey<T>(name: string): ScratchKey<T> {\n return { name };\n}\n\n/** Read a typed slot from the scratch store. Returns `undefined` if\n * nothing has been written under the key. */\nexport function getScratch<T>(\n store: ScratchStore,\n key: ScratchKey<T>,\n): T | undefined {\n return store[key.name] as T | undefined;\n}\n\n/** Write a value to a typed slot. Overwrites whatever was there. */\nexport function setScratch<T>(\n store: ScratchStore,\n key: ScratchKey<T>,\n value: T,\n): void {\n store[key.name] = value;\n}\n\n/** Remove a slot from the scratch store. Returns `true` if it was set,\n * `false` if it wasn't. */\nexport function deleteScratch<T>(\n store: ScratchStore,\n key: ScratchKey<T>,\n): boolean {\n if (Object.prototype.hasOwnProperty.call(store, key.name)) {\n delete store[key.name];\n return true;\n }\n return false;\n}\n"]}
|
package/dist/react.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { D as Dispatcher, A as ActionsRegistry, T as Tool, a as AffordanceHit, R as RuleCtx, b as DepSchema, c as Action, d as AnyToolOf, O as OverlayPosition, C as Contribution, S as ScopedBinding } from './index-
|
|
2
|
-
export { e as DepRegistry, f as DepRegistryProvider, u as useDepRegistry, g as useDepSource, h as useOptionalDepRegistry } from './index-
|
|
1
|
+
import { D as Dispatcher, A as ActionsRegistry, T as Tool, a as AffordanceHit, R as RuleCtx, b as DepSchema, c as Action, d as AnyToolOf, O as OverlayPosition, C as Contribution, S as ScopedBinding } from './index-B_KvoXww.js';
|
|
2
|
+
export { e as DepRegistry, f as DepRegistryProvider, u as useDepRegistry, g as useDepSource, h as useOptionalDepRegistry } from './index-B_KvoXww.js';
|
|
3
3
|
import { RefObject, ReactNode, ReactElement } from 'react';
|
|
4
4
|
import { BodyClassification } from '@weasel-js/gestures';
|
|
5
5
|
import { PaintedCursorState } from '@weasel-js/cursor';
|
|
@@ -72,6 +72,9 @@ interface DispatcherChannels {
|
|
|
72
72
|
pointer?: boolean;
|
|
73
73
|
/** `wheel`. */
|
|
74
74
|
wheel?: boolean;
|
|
75
|
+
/** WebKit's `gesturestart` / `gesturechange` / `gestureend` — Safari's
|
|
76
|
+
* trackpad pinch, dispatched as `pinch` events. */
|
|
77
|
+
pinch?: boolean;
|
|
75
78
|
/** `contextmenu`. Off leaves the browser's native menu in place. */
|
|
76
79
|
contextMenu?: boolean;
|
|
77
80
|
/** OS drop on the element plus `paste` on the window. Off leaves the
|
|
@@ -298,6 +301,35 @@ declare function useActionsRegistry(): ActionsRegistry | null;
|
|
|
298
301
|
*/
|
|
299
302
|
declare function useAction(action: Action): void;
|
|
300
303
|
|
|
304
|
+
/**
|
|
305
|
+
* One UI control's hold on an ongoing action — the handle a color picker, a
|
|
306
|
+
* slider or a swatch drives the action through, the way a drag drives one
|
|
307
|
+
* through a gesture.
|
|
308
|
+
*
|
|
309
|
+
* - `input(params)` opens the action on the first call and moves it on every
|
|
310
|
+
* later one: the live preview.
|
|
311
|
+
* - `commit(params?)` moves it to `params`, if given, and ends it as one
|
|
312
|
+
* undoable edit. With nothing open, a commit carrying params is a whole edit
|
|
313
|
+
* on its own — a click on a swatch, a switch of paint kind.
|
|
314
|
+
* - `cancel()` ends an open edit without keeping it.
|
|
315
|
+
*
|
|
316
|
+
* All three are no-ops when no action is reachable, so a control renders the
|
|
317
|
+
* same with or without a canvas in scope.
|
|
318
|
+
*/
|
|
319
|
+
interface OngoingAction {
|
|
320
|
+
input(params: Record<string, unknown>): void;
|
|
321
|
+
commit(params?: Record<string, unknown>): void;
|
|
322
|
+
cancel(): void;
|
|
323
|
+
}
|
|
324
|
+
/**
|
|
325
|
+
* Drive the ongoing action `actionId` from a UI control: {@link OngoingAction}.
|
|
326
|
+
*
|
|
327
|
+
* An edit left open when the control unmounts, or when `actionId` changes, is
|
|
328
|
+
* committed — it is what the user was looking at when the control went away.
|
|
329
|
+
* The returned object is stable for the life of the component.
|
|
330
|
+
*/
|
|
331
|
+
declare function useOngoingAction(actionId: string): OngoingAction;
|
|
332
|
+
|
|
301
333
|
/** Which tool is active, plus the stack of tools temporarily held active by a
|
|
302
334
|
* hotkey (space-for-hand and the like). The dispatcher reads this to decide
|
|
303
335
|
* whose bindings are in scope. */
|
|
@@ -432,4 +464,4 @@ interface ContributionsApi<TOverlay = unknown> {
|
|
|
432
464
|
*/
|
|
433
465
|
declare function useContributions<TOverlay = unknown>(opts: UseContributionsOptions<TOverlay>): ContributionsApi<TOverlay>;
|
|
434
466
|
|
|
435
|
-
export { ActionsProvider, ActionsScope, ActiveToolContextProvider, ActiveToolContextProviderIfRoot, type ActiveToolContextProviderProps, type ActiveToolContextValue, type ContributionsApi, type DispatcherChannels, type DispatcherViewTarget, type ToolsApi, type UseContributionsOptions, type UseGestureDispatcherOptions, type UseToolsOptions, type ViewIdResolver, useAction, useActionsRegistry, useActiveToolContext, useContributions, useGestureDispatcher, useOptionalActiveToolContext, useTools };
|
|
467
|
+
export { ActionsProvider, ActionsScope, ActiveToolContextProvider, ActiveToolContextProviderIfRoot, type ActiveToolContextProviderProps, type ActiveToolContextValue, type ContributionsApi, type DispatcherChannels, type DispatcherViewTarget, type OngoingAction, type ToolsApi, type UseContributionsOptions, type UseGestureDispatcherOptions, type UseToolsOptions, type ViewIdResolver, useAction, useActionsRegistry, useActiveToolContext, useContributions, useGestureDispatcher, useOngoingAction, useOptionalActiveToolContext, useTools };
|