@weasel-js/routing 1.11.0 → 1.11.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{chunk-QBQQIFPI.js → chunk-KLBH7VFF.js} +172 -48
- package/dist/chunk-KLBH7VFF.js.map +1 -0
- package/dist/{index-CmfVvwWD.d.ts → index-Cb7ehEks.d.ts} +912 -766
- package/dist/index.d.ts +2 -2
- package/dist/index.js +34 -3
- package/dist/index.js.map +1 -1
- package/dist/{internal-21M1rTVo.d.ts → internal-Dcyz_cJv.d.ts} +9 -1
- package/dist/internal.d.ts +5 -5
- package/dist/react.d.ts +7 -7
- package/dist/react.js +84 -42
- package/dist/react.js.map +1 -1
- package/package.json +13 -13
- package/dist/chunk-QBQQIFPI.js.map +0 -1
package/dist/index.d.ts
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
export {
|
|
1
|
+
export { s as ALWAYS, A as Action, c as ActionDeps, e as ActionDisabledReason, e as ActionDisabledReasonValue, t as ActionDispatch, v as ActionEnabledResult, w as ActionEntry, x as ActionItem, y as ActionParamSchema, z as ActionParams, E as ActionPresentation, F as ActionSettings, G as ActionSettingsState, H as ActionShortcut, I as ActionSource, J as ActionTuning, P as ActionTunings, f as ActionVariant, Q as ActionsProp, d as ActionsRegistry, p as AffordanceHit, U as AnyTool, V as AssemblyInputs, W as BROWSER_RESERVED_CHORDS, X as BindingOpts, Y as BindingScope, Z as BindingSource, _ as BodyPredicate, B as BoundGesture, $ as Bounds, a0 as BuildRuleCtxArgs, a1 as COARSE_TARGET_SCALE, a2 as Carried, a3 as Carry, a4 as CarryCallbacks, a5 as CarryPayload, a6 as CarryPointer, a7 as CarryStage, a8 as Condition, a9 as Conflict, C as Contribution, aa as ContributionChrome, ab as ContributionDeps, ac as ContributionRouting, ad as DEFAULT_ALLOWED_CAPABILITIES, ae as DEFAULT_DEVICE_PROFILE, af as DebugSink, ag as DepListing, a as DepName, D as DepRegistry, r as DepSchema, b as DepSource, ah as DetectedDeviceFacts, ai as DeviceProfile, aj as DispatchRecord, ak as DispatchRecordInput, q as DispatchTrace, o as Dispatcher, al as DispatcherContext, am as DragSample, an as DroppedCandidate, ao as Eligibility, ap as EligibilityState, aq as GestureBinding, ar as GestureKitSettings, as as HandleKind, at as HitShape, au as HotkeyTrigger, av as INGEST_STRING_MIMES, aw as ImmediateInvoker, ax as InvocationCtx, ay as Invoker, K as KernelOverlay, az as KeyBinding, aA as KeyReach, L as LongPressOptions, aB as LongPressState, aC as LongPressStore, aD as MatchOutcome, aE as MatchResult, g as MenuDef, aF as MenuHit, M as MenuHost, aG as MenuOpenRequest, aH as MenuSources, aI as MenuWhen, aJ as ModeShortcutHandlers, aK as ModeSwitchLogEntry, aL as ModifierRole, aM as ModifierRoles, aN as ModifierState, aO as NEVER, N as NodeId, aP as OngoingHandle, aQ as OngoingInvoker, aR as OngoingOverlay, aS as OpenMenu, O as OverlayPosition, aT as OverlayRole, aU as OverlaySchema, aV as OwnedMenuDef, aW as PREDICATE_TARGET, aX as PendingLongPress, aY as PlacedBy, aZ as Point2, a_ as PointerSession, a$ as PointerSessionCallbacks, b0 as PointerSessionCancelReason, b1 as PointerSessionOptions, b2 as RankedCandidate, b3 as RecordCandidate, b4 as RegistryEntry, b5 as ReservedChord, b6 as ResizeAnchor, b7 as ResolveAllOptions, b8 as ResolveOnlyResult, b9 as ResolvedCandidate, ba as RoleKeys, bb as RoleRebinds, bc as Rule, R as RuleCtx, bd as ScopedBinding, be as ScratchKey, bf as ScratchStore, bg as SelectionApi, bh as Selector, bi as SpecificityPart, bj as TOOL_OFFHAND_ID, i as Tool, bk as ToolDef, bl as ToolEntry, bm as ToolKeybinding, bn as ToolModifiers, bo as ToolOffhandBindingSpec, bp as ToolPresentation, bq as ToolScopes, br as ToolSet, bs as ToolSlot, bt as TraceLogEntry, bu as TraceRing, bv as TunedBinding, bw as UiOngoingControl, bx as ViewportGestureKind, by as WalkStep, bz as actionBindings, bA as actionCursor, bB as actionItemTitle, bC as actionItems, bD as actionSettingsParams, bE as actionShortcuts, bF as actionsTagged, bG as admitIngestMime, bH as assembleEntries, bI as browserReservedChord, bJ as buildDepsFromRequires, bK as buildRouteRegistry, bL as buildRuleCtx, bM as buildToolOffhandBindings, bN as clientToCanvas, bO as clientToCanvasRect, bP as createDepRegistry, bQ as createDispatchTrace, bR as createDispatcher, bS as createLongPressStore, bT as createMenuHost, bU as createTraceRing, bV as defineTool, bW as deleteScratch, bX as describeRule, bY as dlog, bZ as dwarn, b_ as evaluate, b$ as evaluateActive, c0 as evaluateEnabled, c1 as findConflicts, c2 as getScratch, c3 as heldKeySpec, c4 as historyKey, c5 as isAnchor, c6 as isAnchorOrControl, c7 as isBalanceGrip, c8 as isBody, c9 as isControlHandle, ca as isCornerWidget, cb as isDebugEnabled, cc as isEmpty, cd as isPathEditPart, ce as isResizeHandle, cf as isRotateHandle, cg as isSegment, ch as isSelectedBody, ci as isTool, cj as isToolSet, ck as isUnselectedBody, cl as itemTypesFromDataTransfer, cm as itemsFromClipboardData, cn as itemsFromDataTransfer, co as itemsFromFiles, cp as keySpecShortcut, cq as keysHeld, cr as liveScope, cs as makeToolOffhandAction, ct as matchActionItem, cu as matchBest, cv as matchSorted, cw as matchSortedWithBarred, cx as matchesKeyBinding, cy as mergeContributions, cz as mergeMenuDefs, cA as modeShortcutSpec, cB as modeShortcuts, cC as multiTouchGestureId, cD as offhandKeyFor, cE as openPointerSession, cF as overlaysOf, cG as pickMenu, cH as pointerGestureId, cI as readActionSettings, cJ as reportRouteConflicts, cK as resolveDeviceProfile, cL as resolveMenu, cM as resolveParams, cN as resolveSchemaMenu, cO as roleReader, cP as routesForSpec, cQ as ruleCanHoldIn, cR as rulesExclusive, cS as scopeBindings, cT as scratchKey, cU as setScratch, cV as startCarry, cW as taggedActionItems, cX as targetConsultsAffordance, cY as toolIdsOf, cZ as toolSet, c_ as toolSetHas, c$ as tuneAction, d0 as validateActionDefaultBinding, d1 as validateActionId, d2 as withoutTools } from './index-Cb7ehEks.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';
|
|
5
|
+
import '@weasel-js/cursor';
|
|
5
6
|
import '@weasel-js/menu';
|
|
6
7
|
import '@weasel-js/prefs';
|
|
7
8
|
import '@weasel-js/modes';
|
|
8
9
|
import '@weasel-js/icons';
|
|
9
|
-
import '@weasel-js/cursor';
|
|
10
10
|
import 'react';
|
|
11
11
|
import '@weasel-js/registry';
|
package/dist/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { actionItems, actionItemTitle, ActionDisabledReason } from './chunk-
|
|
2
|
-
export { ALWAYS, ActionDisabledReason, COARSE_TARGET_SCALE, DEFAULT_ALLOWED_CAPABILITIES, DEFAULT_DEVICE_PROFILE, GESTURE_DESCRIPTORS, INGEST_STRING_MIMES, LONG_PRESS_MS, NEVER, PREDICATE_TARGET, RESERVED_ID_NAMES, RESERVED_ID_PREFIXES, ROUTE_FIELD_DEFINITIONS, ROUTE_TERMS, TOOL_OFFHAND_ID, actionBindings, actionCursor, actionItemTitle, actionItems, actionShortcuts, activatesFocusedControl, assembleEntries, buildDepsFromRequires, buildRouteRegistry, buildRuleCtx, buildToolOffhandBindings, canonicalModifiers, clientToCanvas, clientToCanvasRect, collapseShiftPairs, createDepRegistry, createDispatcher, createLongPressStore, createMenuHost, describeRoute, describeRouteParts, describeRule, dlog, dwarn, evaluate, evaluateActive, evaluateEnabled, findConflicts, focusedControlOwnsKey, formatPhaseAtom, formatRoute, getGestureDescriptor, heldKeySpec, historyKey, isDebugEnabled, isEditableTarget, isKnownGestureName, isTool, itemTypesFromDataTransfer, itemsFromClipboardData, itemsFromDataTransfer, itemsFromFiles, keySpecShortcut, keysHeld, liveScope, makeToolOffhandAction, matchBest, matchKey, matchModifiers, matchPhase, matchSorted, matchSortedWithBarred, matchSpec, matchTarget, matchesKeyBinding, mergeMenuDefs, multiTouchGestureId, offhandKeyFor, openPointerSession, parseRoute, pickMenu, pointerGestureId,
|
|
1
|
+
import { actionItems, actionItemTitle, ActionDisabledReason } from './chunk-KLBH7VFF.js';
|
|
2
|
+
export { ALWAYS, ActionDisabledReason, COARSE_TARGET_SCALE, DEFAULT_ALLOWED_CAPABILITIES, DEFAULT_DEVICE_PROFILE, GESTURE_DESCRIPTORS, INGEST_STRING_MIMES, LONG_PRESS_MS, NEVER, PREDICATE_TARGET, RESERVED_ID_NAMES, RESERVED_ID_PREFIXES, ROUTE_FIELD_DEFINITIONS, ROUTE_TERMS, TOOL_OFFHAND_ID, actionBindings, actionCursor, actionItemTitle, actionItems, actionSettingsParams, actionShortcuts, activatesFocusedControl, admitIngestMime, assembleEntries, buildDepsFromRequires, buildRouteRegistry, buildRuleCtx, buildToolOffhandBindings, canonicalModifiers, clientToCanvas, clientToCanvasRect, collapseShiftPairs, createDepRegistry, createDispatchTrace, createDispatcher, createLongPressStore, createMenuHost, createTraceRing, describeRoute, describeRouteParts, describeRule, dlog, dwarn, evaluate, evaluateActive, evaluateEnabled, findConflicts, focusedControlOwnsKey, formatPhaseAtom, formatRoute, getGestureDescriptor, heldKeySpec, historyKey, isDebugEnabled, isEditableTarget, isKnownGestureName, isTool, itemTypesFromDataTransfer, itemsFromClipboardData, itemsFromDataTransfer, itemsFromFiles, keySpecShortcut, keysHeld, liveScope, makeToolOffhandAction, matchBest, matchKey, matchModifiers, matchPhase, matchSorted, matchSortedWithBarred, matchSpec, matchTarget, matchesKeyBinding, mergeMenuDefs, multiTouchGestureId, offhandKeyFor, openPointerSession, parseRoute, pickMenu, pointerGestureId, readActionSettings, reportRouteConflicts, resolveDeviceProfile, resolveMenu, resolveParams, resolveSchemaMenu, roleReader, routeGestureForSpecKind, routesForSpec, ruleCanHoldIn, rulesExclusive, scopeBindings, specKindForRouteGesture, specificity, startCarry, targetConsultsAffordance, tuneAction, validateActionDefaultBinding, validateActionId } from './chunk-KLBH7VFF.js';
|
|
3
3
|
import { hasTag, matchQuery } from '@weasel-js/registry';
|
|
4
4
|
import { bodyPredicate, hitPredicate, RESERVED_ID_PREFIXES, RESERVED_ID_NAMES } from '@weasel-js/gestures';
|
|
5
5
|
export { CONTROL_SELECTOR, DRAG_THRESHOLD_PX, isInControlWithin, pastDragThreshold } from '@weasel-js/gestures';
|
|
@@ -208,11 +208,42 @@ function defineTool(def) {
|
|
|
208
208
|
};
|
|
209
209
|
}
|
|
210
210
|
|
|
211
|
+
// src/tools/toolSet.ts
|
|
212
|
+
function toolSet(id, members) {
|
|
213
|
+
return { id, members };
|
|
214
|
+
}
|
|
215
|
+
function isToolSet(entry) {
|
|
216
|
+
return typeof entry !== "string";
|
|
217
|
+
}
|
|
218
|
+
function toolIdsOf(entries) {
|
|
219
|
+
const out = [];
|
|
220
|
+
const seen = /* @__PURE__ */ new Set();
|
|
221
|
+
const walk = (list) => {
|
|
222
|
+
for (const entry of list) {
|
|
223
|
+
if (isToolSet(entry)) walk(entry.members);
|
|
224
|
+
else if (!seen.has(entry)) {
|
|
225
|
+
seen.add(entry);
|
|
226
|
+
out.push(entry);
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
};
|
|
230
|
+
walk(entries);
|
|
231
|
+
return out;
|
|
232
|
+
}
|
|
233
|
+
function withoutTools(set, ...omit) {
|
|
234
|
+
const gone = new Set(toolIdsOf(omit));
|
|
235
|
+
return { id: `${set.id}-without`, members: toolIdsOf([set]).filter((id) => !gone.has(id)) };
|
|
236
|
+
}
|
|
237
|
+
function toolSetHas(set, id) {
|
|
238
|
+
return toolIdsOf([set]).includes(id);
|
|
239
|
+
}
|
|
240
|
+
|
|
211
241
|
// src/interactions/browserReservedKeys.ts
|
|
212
242
|
var chord = (keys, mods, use) => [...keys].map((key) => ({ key, ...mods, use }));
|
|
213
243
|
var BROWSER_RESERVED_CHORDS = [
|
|
214
244
|
...chord("nqtwlrpmh", { mod: true }, "new window, quit, new or close tab, address bar, reload, print, minimize, hide"),
|
|
215
245
|
...chord("ntwrbo", { mod: true, shift: true }, "private window, reopen or close tab, hard reload, bookmarks, bookmark manager"),
|
|
246
|
+
...chord("ijck", { mod: true, shift: true }, "devtools, console and inspector on Windows and Linux; Firefox Browser and Web Console"),
|
|
216
247
|
...chord("ijcukbrlemhdwfn", { mod: true, alt: true }, "devtools, console, inspector, view source, bookmarks, reload from origin, downloads, empty caches, minimize all, hide others, Dock, close all, search field"),
|
|
217
248
|
...chord("fevsbthd", { alt: true }, "menu accelerators and address bar on Windows and Linux"),
|
|
218
249
|
...chord("ita", { alt: true, shift: true }, "feedback, toolbar focus and accessibility commands")
|
|
@@ -248,6 +279,6 @@ function deleteScratch(store, key) {
|
|
|
248
279
|
return false;
|
|
249
280
|
}
|
|
250
281
|
|
|
251
|
-
export { BROWSER_RESERVED_CHORDS, actionsTagged, browserReservedChord, defineTool, deleteScratch, getScratch, isAnchor, isAnchorOrControl, isBalanceGrip, isBody, isControlHandle, isCornerWidget, isEmpty, isPathEditPart, isResizeHandle, isRotateHandle, isSegment, isSelectedBody, isUnselectedBody, matchActionItem, mergeContributions, modeShortcutSpec, modeShortcuts, overlaysOf, scratchKey, setScratch, taggedActionItems };
|
|
282
|
+
export { BROWSER_RESERVED_CHORDS, actionsTagged, browserReservedChord, defineTool, deleteScratch, getScratch, isAnchor, isAnchorOrControl, isBalanceGrip, isBody, isControlHandle, isCornerWidget, isEmpty, isPathEditPart, isResizeHandle, isRotateHandle, isSegment, isSelectedBody, isToolSet, isUnselectedBody, matchActionItem, mergeContributions, modeShortcutSpec, modeShortcuts, overlaysOf, scratchKey, setScratch, taggedActionItems, toolIdsOf, toolSet, toolSetHas, withoutTools };
|
|
252
283
|
//# sourceMappingURL=index.js.map
|
|
253
284
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/interactions/actions/actionTags.ts","../src/interactions/actions/overlay.ts","../src/interactions/dispatcher/predicates.ts","../src/contributions/merge.ts","../src/contributions/modeShortcuts.ts","../src/tools/defineTool.ts","../src/interactions/browserReservedKeys.ts","../src/interactions/scratchKey.ts"],"names":["RESERVED_ID_PREFIXES","RESERVED_ID_NAMES"],"mappings":"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","file":"index.js","sourcesContent":["/**\n * Finding actions by tag: gathering the ones that carry it, and a person's\n * search matching it as it matches a label.\n */\nimport { hasTag, matchQuery, type QueryMatch } from '@weasel-js/registry';\nimport type { Action } from './action';\nimport { actionItems, actionItemTitle, type ActionItem } from './actionItems';\n\n/** The actions carrying `tag`, themselves or on any variant, in\n * the order given. Drags included, which have no entries to show. */\nexport function actionsTagged(actions: readonly Action[], tag: string): Action[] {\n return actions.filter((a) => hasTag(a.tags, tag) || (a.variants?.some((v) => hasTag(v.tags, tag)) ?? false));\n}\n\n/** The entries carrying `tag`: what a bar or a menu built from\n * a tag shows. A variant that does not carry it is left out. */\nexport function taggedActionItems(actions: readonly Action[], tag: string): ActionItem[] {\n return actionsTagged(actions, tag).flatMap(actionItems).filter((i) => hasTag(i.tags, tag));\n}\n\n/** Whether `item` answers a search for `query`, by its palette title or\n * by a tag, and which. */\nexport function matchActionItem(item: ActionItem, query: string): QueryMatch | null {\n return matchQuery(query, { text: [actionItemTitle(item)], tags: item.tags });\n}\n","/** The chrome an in-flight gesture paints beside the scene. */\nimport type { OngoingHandle } from './invoker';\n\n/**\n * What a `polyline` overlay is, in a word — the narrowest thing an action can\n * say about how its run should look without naming a paint.\n *\n * The named roles are the kit's; a painter maps each to a style and falls back\n * to plain chrome for one it does not know, so a package outside core can coin\n * its own and still be drawn.\n */\nexport type OverlayRole =\n /** Generic in-flight chrome — the marquee/lasso paint. */\n | 'chrome'\n /** A cut the gesture would make. */\n | 'cut'\n /** An edge the gesture would author between two points. */\n | 'connector'\n /** The stretch of a path a soft-selection drag reaches. */\n | 'falloff'\n /** What a lock holds a dragged point to — a line, a circle. */\n | 'lock'\n | (string & {});\n\n/**\n * What an in-flight gesture proposes to paint *beside* the scene, returned by\n * `OngoingHandle.overlay()` — a marquee rect, a lasso trail, the outline of a\n * shape being dragged out, the line a slice would cut along.\n *\n * Every variant is world geometry and nothing else — no `DrawCommand`, no\n * color, no coordinate space to choose — so a surface rendering the same\n * gesture some other way can still read it. The painter owns every style\n * decision.\n */\nexport type OngoingOverlay =\n | {\n kind: 'marquee';\n start: { x: number; y: number };\n current: { x: number; y: number };\n shiftHeld: boolean;\n }\n | {\n kind: 'lasso';\n vertices: ReadonlyArray<{ x: number; y: number }>;\n current: { x: number; y: number };\n shiftHeld: boolean;\n }\n | {\n /**\n * An open run of world points the gesture is proposing — a cut line, a\n * routed connector. `role` is the whole of what an action says about\n * appearance.\n */\n kind: 'polyline';\n /** At least two points. Anything shorter is dropped in resolution. */\n points: ReadonlyArray<{ x: number; y: number }>;\n /** What the run means. Omitted reads as {@link OverlayRole} `'chrome'`. */\n role?: OverlayRole;\n }\n | {\n /**\n * A round brush dragged through world points: the area it has swept so\n * far, and its footprint at the last point. The radius is in screen\n * pixels, so the footprint keeps its size at every zoom.\n */\n kind: 'brush';\n /** The brush's path so far, at least one point; the last is where it is now. */\n points: ReadonlyArray<{ x: number; y: number }>;\n radiusPx: number;\n }\n | {\n /**\n * Live insert-drag preview. Pre-commit there is no scene node to ghost\n * via `previewIds()`/`previewPose()`, so insert paints its preview\n * through the overlay instead.\n *\n * `bounds` is the AABB of the current drag (start/current normalized).\n * `extras` is the per-kind extras the action already collected; the\n * overlay renderer narrows on `shape` and casts the field shape it\n * expects.\n */\n kind: 'insertPreview';\n /** Which preview the dispatcher's overlay draws. The kit's own shape\n * kinds are the ones it knows how to render; a consumer-defined kind\n * is legal and simply gets no live preview. */\n shape: string;\n bounds: { x: number; y: number; width: number; height: number };\n extras: unknown;\n /** World-space point to paint a small \"anchor\" dot at, marking the\n * click point — for radial shapes (polygon/star), where no vertex\n * sits on it, and for any shape in center mode. */\n anchorPoint?: { x: number; y: number };\n /** World affines the shape will also be drawn under once it lands, by\n * the container it is drawn into: the preview is painted under each. */\n copies?: readonly (readonly [number, number, number, number, number, number])[];\n };\n\n/** A handle's overlays as a list: empty when it has none. */\nexport function overlaysOf(handle: OngoingHandle): readonly OngoingOverlay[] {\n const ov = handle.overlay?.();\n if (!ov) return [];\n return isOverlayList(ov) ? ov : [ov];\n}\n\nfunction isOverlayList(ov: OngoingOverlay | readonly OngoingOverlay[]): ov is readonly OngoingOverlay[] {\n return Array.isArray(ov);\n}\n","/**\n * Named predicates for `defaultBinding.target.kindOf`. Each matches the\n * `TargetPredicate` shape, declaring whether it reads the hit,\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 */\nimport { bodyPredicate, hitPredicate, type TargetPredicate } from '@weasel-js/gestures';\n\n// ─── Body-class predicates (read the second arg) ───────────────────────\n\n/** A predicate that resolves from `bodyTarget` alone. */\nexport type BodyPredicate = TargetPredicate & { readsAffordance: false };\n\n/** Matches any body hit — selected or unselected node body. */\nexport const isBody: BodyPredicate = bodyPredicate((bodyTarget) =>\n bodyTarget === 'selected-body' || bodyTarget === 'unselected-body');\n\n/** Body hit specifically already in the selection. */\nexport const isSelectedBody: BodyPredicate = bodyPredicate((bodyTarget) =>\n bodyTarget === 'selected-body');\n\n/** Body hit specifically NOT in the selection. */\nexport const isUnselectedBody: BodyPredicate = bodyPredicate((bodyTarget) =>\n bodyTarget === 'unselected-body');\n\n/** Empty-canvas hit — no node beneath cursor. */\nexport const isEmpty: BodyPredicate = bodyPredicate((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 resize handle: a corner (`handle:top-left`, …) or an edge (`handle:top`, …). */\nexport const isResizeHandle = hitPredicate((target) => {\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 = hitPredicate((target) =>\n kindOf(target) === 'rotate-handle');\n\n/** Any path anchor (the on-curve dot). */\nexport const isAnchor = hitPredicate((target) => {\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 = hitPredicate((target) => {\n const k = kindOf(target);\n return k !== undefined && /^(controlIn|controlOut):\\d+$/.test(k);\n});\n\n/** A corner-shape widget, set inside a corner anchor of the edited path. */\nexport const isCornerWidget = hitPredicate((target) => {\n const k = kindOf(target);\n return k !== undefined && /^corner:\\d+$/.test(k);\n});\n\n/** Any of the three anchor-editing affordances (anchor + both controls). */\nexport const isAnchorOrControl = hitPredicate((target) =>\n isAnchor(target) || isControlHandle(target));\n\n/** The outline of the path being edited, between its anchors. */\nexport const isSegment = hitPredicate((target) => kindOf(target) === 'segment');\n\n/** The grip midway along a curved segment's balance line, `balance:N`, where\n * N is the flat index of the anchor the segment starts at. */\nexport const isBalanceGrip = hitPredicate((target) => {\n const k = kindOf(target);\n return k !== undefined && /^balance:\\d+$/.test(k);\n});\n\n/** Anything path edit puts on the path: an anchor, a control, a segment, a\n * segment's balance grip, or a corner widget. */\nexport const isPathEditPart = hitPredicate((target) =>\n isAnchorOrControl(target) || isSegment(target) || isBalanceGrip(target) || isCornerWidget(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 or dep name rather than dropping one: a feature\n * silently losing its bindings, or reading another feature's dep, is the\n * failure this registry exists to make loud.\n */\nexport function mergeContributions<T extends Contribution<unknown>>(\n ...bundles: readonly (readonly T[])[]\n): T[] {\n const out: T[] = [];\n const seen = new Set<string>();\n const depOwner = new Map<string, 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 for (const dep of Object.keys(entry.deps ?? {})) {\n const owner = depOwner.get(dep);\n if (owner !== undefined) {\n throw new Error(\n `mergeContributions: dep \"${dep}\" is provided by both \"${owner}\" and \"${entry.id}\". `\n + `One registry answers each dep name; drop one source.`,\n );\n }\n depOwner.set(dep, entry.id);\n }\n out.push(entry);\n }\n }\n return out;\n}\n","import { modeLabel, type ModeDefinition, type ModeRegistry } from '@weasel-js/modes';\nimport type { KeySpec, ModSpec } from '@weasel-js/gestures';\nimport { ActionDisabledReason, type Action } from '../interactions/actions/action';\nimport type { Rule } from '../eligibility';\nimport type { Contribution } from './types';\n\n/**\n * What each mode shortcut does. A role left out binds nothing, so its key\n * falls through to whatever else the dispatcher has on it.\n */\nexport interface ModeShortcutHandlers {\n /** Enter mode `id` — the `entry` shortcut. */\n enter?: (id: string) => void;\n /** Whether mode `id` can be entered now. A mode that needs a target it\n * doesn't have answers no, and its entry key falls through. Default yes. */\n canEnter?: (id: string) => boolean;\n /** Leave the active soft mode, keeping its session to resume. */\n exit?: () => void;\n /** Leave the active soft mode and throw its session away. */\n discard?: () => void;\n /** Commit the active strict mode's transaction. */\n commit?: () => void;\n /** Abandon the active strict mode's transaction. */\n cancel?: () => void;\n}\n\ntype Role = 'exit' | 'discard' | 'commit' | 'cancel';\nconst LEAVING: readonly Role[] = ['exit', 'discard', 'commit', 'cancel'];\nconst VERB: Record<Role | 'entry', string> = {\n entry: 'Enter', exit: 'Exit', discard: 'Discard', commit: 'Commit', cancel: 'Cancel',\n};\n\nconst MODIFIERS: Record<string, keyof ModSpec> = {\n meta: 'meta', cmd: 'meta', command: 'meta',\n ctrl: 'ctrl', control: 'ctrl',\n alt: 'alt', option: 'alt',\n shift: 'shift',\n mod: 'mod',\n};\n\n/**\n * A `ModeDefinition` shortcut chord — `'Escape'`, `'Meta+T'` — as a key spec.\n * Modifier names are case-insensitive; the last segment is the key.\n */\nexport function modeShortcutSpec(shortcut: string): KeySpec {\n const parts = shortcut.split('+');\n const key = parts.pop();\n if (!key) throw new Error(`mode shortcut \"${shortcut}\" names no key`);\n const mods: ModSpec = {};\n for (const part of parts) {\n const mod = MODIFIERS[part.toLowerCase()];\n if (!mod) throw new Error(`mode shortcut \"${shortcut}\": unknown modifier \"${part}\"`);\n mods[mod] = true;\n }\n return Object.keys(mods).length > 0 ? { kind: 'key', key, mods } : { kind: 'key', key };\n}\n\n/**\n * The registry's declared mode shortcuts as an always-on contribution: one\n * action per shortcut, bound to its chord and gated on the mode it acts on —\n * `exit` / `discard` / `commit` / `cancel` while that mode is active, `entry`\n * while it is not. Install it with `<SceneCanvas ambient>`.\n *\n * An entry key one mode shares with another mode's leaving key is reported as\n * a route conflict unless `canEnter` is given: that is what keeps the entry\n * key from firing inside the other mode.\n *\n * The bindings ride the hotkey tier, so leaving a mode outranks what the same\n * key does otherwise (Escape clearing the selection), and they yield while a\n * gesture is in flight, so Escape mid-drag still cancels the drag first. Keys\n * typed into an editable element never reach them.\n */\nexport function modeShortcuts(\n registry: ModeRegistry,\n handlers: ModeShortcutHandlers,\n): Contribution<never> {\n const actions: Action[] = [];\n for (const mode of registry.list()) {\n const entry = mode.entry?.shortcut;\n const enter = handlers.enter;\n if (entry && enter) {\n // Without `canEnter` an entry key is live in every other mode, so it does not yield there.\n actions.push(shortcutAction(mode, 'entry', entry, { mode: { not: mode.id } },\n () => registry.current().id !== mode.id && (handlers.canEnter?.(mode.id) ?? true),\n () => enter(mode.id), handlers.canEnter !== undefined));\n }\n for (const role of LEAVING) {\n const shortcut = mode[role]?.shortcut;\n const run = handlers[role];\n if (!shortcut || !run) continue;\n actions.push(shortcutAction(mode, role, shortcut, { mode: mode.id },\n () => registry.current().id === mode.id,\n run, true));\n }\n }\n return { id: 'modes.shortcuts', eligibility: { always: true }, actions };\n}\n\nfunction shortcutAction(\n mode: ModeDefinition,\n role: Role | 'entry',\n shortcut: string,\n eligible: Rule,\n live: () => boolean,\n run: () => void,\n yields: boolean,\n): Action {\n return {\n id: `mode.${mode.id}.${role}`,\n label: `${VERB[role]} ${modeLabel(mode)}`,\n scope: 'hotkey',\n defaultBinding: [{\n spec: { ...modeShortcutSpec(shortcut), phase: [{ channel: '*', phase: 'initial' }] },\n opts: { yields },\n }],\n eligible,\n // `eligible` is the gate the dispatcher and palettes read, but a canvas\n // with no `modes` evaluates none; without this the key is\n // swallowed in every mode.\n enabled: () => (live() ? true : ActionDisabledReason.NotApplicable),\n invoker: { timing: 'immediate', run: () => run() },\n };\n}\n","// src/tools/defineTool.ts\nimport type { Tool } 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';\nimport type { KernelOverlay } from '../index';\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` from a declarative `ToolDef`: validates the id, applies the\n * `cursor` default, and keeps the authored form on `Tool.def` for reflection.\n */\nexport function defineTool<TOverlay = KernelOverlay>(\n def: ToolDef<TOverlay>,\n): Tool<TOverlay> {\n validateId(def.id, 'tool');\n\n const resolveCursor = (): CursorSpec => {\n if (def.cursor == null) return '';\n return typeof def.cursor === 'function' ? def.cursor() : 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 menus: def.menus,\n def,\n presentation: def.presentation,\n keybinding: def.keybinding,\n onActivate: def.onActivate,\n onDeactivate: def.onDeactivate,\n cursor: resolveCursor,\n bindings: def.bindings,\n overlay: def.overlay,\n overlayPosition: def.overlayPosition,\n };\n}\n","/**\n * Key chords a major browser or the desktop under it takes before a page can:\n * reload, devtools, tab and window commands, menu accelerators. A binding on\n * one never fires for some users, so kit defaults steer clear of them.\n *\n * `mod` is Cmd on macOS and Ctrl elsewhere, as in a `KeySpec`. The list is\n * the union across Chrome, Safari, Firefox and Edge on macOS, Windows and\n * Linux, and errs toward listing a chord.\n */\nimport type { KeySpec } from '@weasel-js/gestures';\n\n/** One reserved chord, and what takes it. */\nexport interface ReservedChord {\n key: string;\n mod?: boolean;\n alt?: boolean;\n shift?: boolean;\n /** Who takes it, for a message. */\n use: string;\n}\n\nconst chord = (keys: string, mods: Omit<ReservedChord, 'key' | 'use'>, use: string): ReservedChord[] =>\n [...keys].map((key) => ({ key, ...mods, use }));\n\n/** Every chord the module's header describes, one entry per key. */\nexport const BROWSER_RESERVED_CHORDS: readonly ReservedChord[] = [\n ...chord('nqtwlrpmh', { mod: true }, 'new window, quit, new or close tab, address bar, reload, print, minimize, hide'),\n ...chord('ntwrbo', { mod: true, shift: true }, 'private window, reopen or close tab, hard reload, bookmarks, bookmark manager'),\n ...chord('ijcukbrlemhdwfn', { mod: true, alt: true }, 'devtools, console, inspector, view source, bookmarks, reload from origin, downloads, empty caches, minimize all, hide others, Dock, close all, search field'),\n ...chord('fevsbthd', { alt: true }, 'menu accelerators and address bar on Windows and Linux'),\n ...chord('ita', { alt: true, shift: true }, 'feedback, toolbar focus and accessibility commands'),\n];\n\nconst lower = (k: string | readonly string[]): string[] => (typeof k === 'string' ? [k] : [...k]).map((x) => x.toLowerCase());\n\n/** Whether a modifier policy can be satisfied with the modifier held (`true`)\n * or released (`false`). */\nconst allows = (policy: boolean | 'optional' | undefined, held: boolean): boolean =>\n policy === 'optional' || (policy === true) === held;\n\n/** The first reserved chord `spec` can fire on, or `null` when none. */\nexport function browserReservedChord(spec: KeySpec): ReservedChord | null {\n const keys = lower(spec.key);\n const m = spec.mods ?? {};\n const mod = m.mod ?? (m.meta === true || m.ctrl === true ? true : m.meta ?? m.ctrl);\n for (const c of BROWSER_RESERVED_CHORDS) {\n if (!keys.includes(c.key)) continue;\n if (allows(mod, c.mod === true) && allows(m.alt, c.alt === true) && allows(m.shift, c.shift === true)) return c;\n }\n return null;\n}\n","/**\n * Typed keys for the gesture/behavior scratch store, `ctx.scratch`.\n * `ScratchKey<T>` carries its payload type at the typing layer; at runtime\n * the key is just its underlying string and the store remains a plain `Record`.\n *\n * @example\n * ```ts\n * // Module-level constant, shared by writer + reader:\n * const LASSO_VERTICES = scratchKey<readonly { x: number; y: number }[]>('lasso.vertices');\n * setScratch(ctx.scratch, LASSO_VERTICES, vertices);\n * const vertices = getScratch(ctx.scratch, LASSO_VERTICES) ?? [];\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. Two keys with the same `name` refer to the same\n * slot at runtime — the type parameter is a compile-time contract, not a\n * uniqueness guarantee — so namespace the name (`'behavior.field'`).\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/actionTags.ts","../src/interactions/actions/overlay.ts","../src/interactions/dispatcher/predicates.ts","../src/contributions/merge.ts","../src/contributions/modeShortcuts.ts","../src/tools/defineTool.ts","../src/tools/toolSet.ts","../src/interactions/browserReservedKeys.ts","../src/interactions/scratchKey.ts"],"names":["RESERVED_ID_PREFIXES","RESERVED_ID_NAMES"],"mappings":"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","file":"index.js","sourcesContent":["/**\n * Finding actions by tag: gathering the ones that carry it, and a person's\n * search matching it as it matches a label.\n */\nimport { hasTag, matchQuery, type QueryMatch } from '@weasel-js/registry';\nimport type { Action } from './action';\nimport { actionItems, actionItemTitle, type ActionItem } from './actionItems';\n\n/** The actions carrying `tag`, themselves or on any variant, in\n * the order given. Drags included, which have no entries to show. */\nexport function actionsTagged(actions: readonly Action[], tag: string): Action[] {\n return actions.filter((a) => hasTag(a.tags, tag) || (a.variants?.some((v) => hasTag(v.tags, tag)) ?? false));\n}\n\n/** The entries carrying `tag`: what a bar or a menu built from\n * a tag shows. A variant that does not carry it is left out. */\nexport function taggedActionItems(actions: readonly Action[], tag: string): ActionItem[] {\n return actionsTagged(actions, tag).flatMap(actionItems).filter((i) => hasTag(i.tags, tag));\n}\n\n/** Whether `item` answers a search for `query`, by its palette title or\n * by a tag, and which. */\nexport function matchActionItem(item: ActionItem, query: string): QueryMatch | null {\n return matchQuery(query, { text: [actionItemTitle(item)], tags: item.tags });\n}\n","/** The chrome an in-flight gesture paints beside the scene. */\nimport type { OngoingHandle } from './invoker';\n\n/**\n * What a `polyline` overlay is, in a word — the narrowest thing an action can\n * say about how its run should look without naming a paint.\n *\n * The named roles are the kit's; a painter maps each to a style and falls back\n * to plain chrome for one it does not know, so a package outside core can coin\n * its own and still be drawn.\n */\nexport type OverlayRole =\n /** Generic in-flight chrome — the marquee/lasso paint. */\n | 'chrome'\n /** A cut the gesture would make. */\n | 'cut'\n /** An edge the gesture would author between two points. */\n | 'connector'\n /** The stretch of a path a soft-selection drag reaches. */\n | 'falloff'\n /** What a lock holds a dragged point to — a line, a circle. */\n | 'lock'\n /** Where a dragged item would land: a reorder's insertion bar. */\n | 'insert'\n /** Where a dragged item is over and cannot land. */\n | 'refused'\n | (string & {});\n\n/**\n * What an in-flight gesture proposes to paint *beside* the scene, returned by\n * `OngoingHandle.overlay()` — a marquee rect, a lasso trail, the outline of a\n * shape being dragged out, the line a slice would cut along.\n *\n * Every variant is world geometry and nothing else — no `DrawCommand`, no\n * color, no coordinate space to choose — so a surface rendering the same\n * gesture some other way can still read it. The painter owns every style\n * decision.\n */\nexport type OngoingOverlay =\n | {\n kind: 'marquee';\n start: { x: number; y: number };\n current: { x: number; y: number };\n shiftHeld: boolean;\n }\n | {\n kind: 'lasso';\n vertices: ReadonlyArray<{ x: number; y: number }>;\n current: { x: number; y: number };\n shiftHeld: boolean;\n }\n | {\n /**\n * An open run of world points the gesture is proposing — a cut line, a\n * routed connector. `role` is the whole of what an action says about\n * appearance.\n */\n kind: 'polyline';\n /** At least two points. Anything shorter is dropped in resolution. */\n points: ReadonlyArray<{ x: number; y: number }>;\n /** What the run means. Omitted reads as {@link OverlayRole} `'chrome'`. */\n role?: OverlayRole;\n }\n | {\n /**\n * A round brush dragged through world points: the area it has swept so\n * far, and its footprint at the last point. The radius is in screen\n * pixels, so the footprint keeps its size at every zoom.\n */\n kind: 'brush';\n /** The brush's path so far, at least one point; the last is where it is now. */\n points: ReadonlyArray<{ x: number; y: number }>;\n radiusPx: number;\n }\n | {\n /**\n * Live insert-drag preview. Pre-commit there is no scene node to ghost\n * via `previewIds()`/`previewPose()`, so insert paints its preview\n * through the overlay instead.\n *\n * `bounds` is the AABB of the current drag (start/current normalized).\n * `extras` is the per-kind extras the action already collected; the\n * overlay renderer narrows on `shape` and casts the field shape it\n * expects.\n */\n kind: 'insertPreview';\n /** Which preview the dispatcher's overlay draws. The kit's own shape\n * kinds are the ones it knows how to render; a consumer-defined kind\n * is legal and simply gets no live preview. */\n shape: string;\n bounds: { x: number; y: number; width: number; height: number };\n extras: unknown;\n /** World-space point to paint a small \"anchor\" dot at, marking the\n * click point — for radial shapes (polygon/star), where no vertex\n * sits on it, and for any shape in center mode. */\n anchorPoint?: { x: number; y: number };\n /** World affines the shape will also be drawn under once it lands, by\n * the container it is drawn into: the preview is painted under each. */\n copies?: readonly (readonly [number, number, number, number, number, number])[];\n };\n\n/** A handle's overlays as a list: empty when it has none. */\nexport function overlaysOf(handle: OngoingHandle): readonly OngoingOverlay[] {\n const ov = handle.overlay?.();\n if (!ov) return [];\n return isOverlayList(ov) ? ov : [ov];\n}\n\nfunction isOverlayList(ov: OngoingOverlay | readonly OngoingOverlay[]): ov is readonly OngoingOverlay[] {\n return Array.isArray(ov);\n}\n","/**\n * Named predicates for `defaultBinding.target.kindOf`. Each matches the\n * `TargetPredicate` shape, declaring whether it reads the hit,\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 */\nimport { bodyPredicate, hitPredicate, type TargetPredicate } from '@weasel-js/gestures';\n\n// ─── Body-class predicates (read the second arg) ───────────────────────\n\n/** A predicate that resolves from `bodyTarget` alone. */\nexport type BodyPredicate = TargetPredicate & { readsAffordance: false };\n\n/** Matches any body hit — selected or unselected node body. */\nexport const isBody: BodyPredicate = bodyPredicate((bodyTarget) =>\n bodyTarget === 'selected-body' || bodyTarget === 'unselected-body');\n\n/** Body hit specifically already in the selection. */\nexport const isSelectedBody: BodyPredicate = bodyPredicate((bodyTarget) =>\n bodyTarget === 'selected-body');\n\n/** Body hit specifically NOT in the selection. */\nexport const isUnselectedBody: BodyPredicate = bodyPredicate((bodyTarget) =>\n bodyTarget === 'unselected-body');\n\n/** Empty-canvas hit — no node beneath cursor. */\nexport const isEmpty: BodyPredicate = bodyPredicate((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 resize handle: a corner (`handle:top-left`, …) or an edge (`handle:top`, …). */\nexport const isResizeHandle = hitPredicate((target) => {\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 = hitPredicate((target) =>\n kindOf(target) === 'rotate-handle');\n\n/** Any path anchor (the on-curve dot). */\nexport const isAnchor = hitPredicate((target) => {\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 = hitPredicate((target) => {\n const k = kindOf(target);\n return k !== undefined && /^(controlIn|controlOut):\\d+$/.test(k);\n});\n\n/** A corner-shape widget, set inside a corner anchor of the edited path. */\nexport const isCornerWidget = hitPredicate((target) => {\n const k = kindOf(target);\n return k !== undefined && /^corner:\\d+$/.test(k);\n});\n\n/** Any of the three anchor-editing affordances (anchor + both controls). */\nexport const isAnchorOrControl = hitPredicate((target) =>\n isAnchor(target) || isControlHandle(target));\n\n/** The outline of the path being edited, between its anchors. */\nexport const isSegment = hitPredicate((target) => kindOf(target) === 'segment');\n\n/** The grip midway along a curved segment's balance line, `balance:N`, where\n * N is the flat index of the anchor the segment starts at. */\nexport const isBalanceGrip = hitPredicate((target) => {\n const k = kindOf(target);\n return k !== undefined && /^balance:\\d+$/.test(k);\n});\n\n/** Anything path edit puts on the path: an anchor, a control, a segment, a\n * segment's balance grip, or a corner widget. */\nexport const isPathEditPart = hitPredicate((target) =>\n isAnchorOrControl(target) || isSegment(target) || isBalanceGrip(target) || isCornerWidget(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 or dep name rather than dropping one: a feature\n * silently losing its bindings, or reading another feature's dep, is the\n * failure this registry exists to make loud.\n */\nexport function mergeContributions<T extends Contribution<unknown>>(\n ...bundles: readonly (readonly T[])[]\n): T[] {\n const out: T[] = [];\n const seen = new Set<string>();\n const depOwner = new Map<string, 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 for (const dep of Object.keys(entry.deps ?? {})) {\n const owner = depOwner.get(dep);\n if (owner !== undefined) {\n throw new Error(\n `mergeContributions: dep \"${dep}\" is provided by both \"${owner}\" and \"${entry.id}\". `\n + `One registry answers each dep name; drop one source.`,\n );\n }\n depOwner.set(dep, entry.id);\n }\n out.push(entry);\n }\n }\n return out;\n}\n","import { modeLabel, type ModeDefinition, type ModeRegistry } from '@weasel-js/modes';\nimport type { KeySpec, ModSpec } from '@weasel-js/gestures';\nimport { ActionDisabledReason, type Action } from '../interactions/actions/action';\nimport type { Rule } from '../eligibility';\nimport type { Contribution } from './types';\n\n/**\n * What each mode shortcut does. A role left out binds nothing, so its key\n * falls through to whatever else the dispatcher has on it.\n */\nexport interface ModeShortcutHandlers {\n /** Enter mode `id` — the `entry` shortcut. */\n enter?: (id: string) => void;\n /** Whether mode `id` can be entered now. A mode that needs a target it\n * doesn't have answers no, and its entry key falls through. Default yes. */\n canEnter?: (id: string) => boolean;\n /** Leave the active soft mode, keeping its session to resume. */\n exit?: () => void;\n /** Leave the active soft mode and throw its session away. */\n discard?: () => void;\n /** Commit the active strict mode's transaction. */\n commit?: () => void;\n /** Abandon the active strict mode's transaction. */\n cancel?: () => void;\n}\n\ntype Role = 'exit' | 'discard' | 'commit' | 'cancel';\nconst LEAVING: readonly Role[] = ['exit', 'discard', 'commit', 'cancel'];\nconst VERB: Record<Role | 'entry', string> = {\n entry: 'Enter', exit: 'Exit', discard: 'Discard', commit: 'Commit', cancel: 'Cancel',\n};\n\nconst MODIFIERS: Record<string, keyof ModSpec> = {\n meta: 'meta', cmd: 'meta', command: 'meta',\n ctrl: 'ctrl', control: 'ctrl',\n alt: 'alt', option: 'alt',\n shift: 'shift',\n mod: 'mod',\n};\n\n/**\n * A `ModeDefinition` shortcut chord — `'Escape'`, `'Meta+T'` — as a key spec.\n * Modifier names are case-insensitive; the last segment is the key.\n */\nexport function modeShortcutSpec(shortcut: string): KeySpec {\n const parts = shortcut.split('+');\n const key = parts.pop();\n if (!key) throw new Error(`mode shortcut \"${shortcut}\" names no key`);\n const mods: ModSpec = {};\n for (const part of parts) {\n const mod = MODIFIERS[part.toLowerCase()];\n if (!mod) throw new Error(`mode shortcut \"${shortcut}\": unknown modifier \"${part}\"`);\n mods[mod] = true;\n }\n return Object.keys(mods).length > 0 ? { kind: 'key', key, mods } : { kind: 'key', key };\n}\n\n/**\n * The registry's declared mode shortcuts as an always-on contribution: one\n * action per shortcut, bound to its chord and gated on the mode it acts on —\n * `exit` / `discard` / `commit` / `cancel` while that mode is active, `entry`\n * while it is not. Install it with `<SceneCanvas ambient>`.\n *\n * An entry key one mode shares with another mode's leaving key is reported as\n * a route conflict unless `canEnter` is given: that is what keeps the entry\n * key from firing inside the other mode.\n *\n * The bindings ride the hotkey tier, so leaving a mode outranks what the same\n * key does otherwise (Escape clearing the selection), and they yield while a\n * gesture is in flight, so Escape mid-drag still cancels the drag first. Keys\n * typed into an editable element never reach them.\n */\nexport function modeShortcuts(\n registry: ModeRegistry,\n handlers: ModeShortcutHandlers,\n): Contribution<never> {\n const actions: Action[] = [];\n for (const mode of registry.list()) {\n const entry = mode.entry?.shortcut;\n const enter = handlers.enter;\n if (entry && enter) {\n // Without `canEnter` an entry key is live in every other mode, so it does not yield there.\n actions.push(shortcutAction(mode, 'entry', entry, { mode: { not: mode.id } },\n () => registry.current().id !== mode.id && (handlers.canEnter?.(mode.id) ?? true),\n () => enter(mode.id), handlers.canEnter !== undefined));\n }\n for (const role of LEAVING) {\n const shortcut = mode[role]?.shortcut;\n const run = handlers[role];\n if (!shortcut || !run) continue;\n actions.push(shortcutAction(mode, role, shortcut, { mode: mode.id },\n () => registry.current().id === mode.id,\n run, true));\n }\n }\n return { id: 'modes.shortcuts', eligibility: { always: true }, actions };\n}\n\nfunction shortcutAction(\n mode: ModeDefinition,\n role: Role | 'entry',\n shortcut: string,\n eligible: Rule,\n live: () => boolean,\n run: () => void,\n yields: boolean,\n): Action {\n return {\n id: `mode.${mode.id}.${role}`,\n label: `${VERB[role]} ${modeLabel(mode)}`,\n scope: 'hotkey',\n defaultBinding: [{\n spec: { ...modeShortcutSpec(shortcut), phase: [{ channel: '*', phase: 'initial' }] },\n opts: { yields },\n }],\n eligible,\n // `eligible` is the gate the dispatcher and palettes read, but a canvas\n // with no `modes` evaluates none; without this the key is\n // swallowed in every mode.\n enabled: () => (live() ? true : ActionDisabledReason.NotApplicable),\n invoker: { timing: 'immediate', run: () => run() },\n };\n}\n","// src/tools/defineTool.ts\nimport type { Tool } 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';\nimport type { KernelOverlay } from '../index';\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` from a declarative `ToolDef`: validates the id, applies the\n * `cursor` default, and keeps the authored form on `Tool.def` for reflection.\n */\nexport function defineTool<TOverlay = KernelOverlay>(\n def: ToolDef<TOverlay>,\n): Tool<TOverlay> {\n validateId(def.id, 'tool');\n\n const resolveCursor = (): CursorSpec => {\n if (def.cursor == null) return '';\n return typeof def.cursor === 'function' ? def.cursor() : 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 menus: def.menus,\n def,\n presentation: def.presentation,\n keybinding: def.keybinding,\n onActivate: def.onActivate,\n onDeactivate: def.onDeactivate,\n cursor: resolveCursor,\n bindings: def.bindings,\n overlay: def.overlay,\n overlayPosition: def.overlayPosition,\n };\n}\n","/**\n * Tool sets: a named group of tool ids, the unit a consumer opts into whole.\n * A set names ids, never tools, because a tool is built by a hook that holds\n * its state; whatever mounts the set supplies the tool for each id.\n */\n\n/** A named group of tool ids. A member is an id or another set, whose ids it takes in order. */\nexport interface ToolSet<TId extends string = string> {\n readonly id: string;\n readonly members: readonly (TId | ToolSet<TId>)[];\n}\n\n/** One entry of a list of tools to mount: an id, or a set of them. */\nexport type ToolEntry<TId extends string = string> = TId | ToolSet<TId>;\n\n/** A set named `id` of `members`, in palette order. */\nexport function toolSet<TId extends string>(id: string, members: readonly ToolEntry<TId>[]): ToolSet<TId> {\n return { id, members };\n}\n\n/** Whether `entry` is a set rather than a single id. */\nexport function isToolSet<TId extends string>(entry: ToolEntry<TId>): entry is ToolSet<TId> {\n return typeof entry !== 'string';\n}\n\n/** Every id `entries` name, sets opened in place, each id once at its first place. */\nexport function toolIdsOf<TId extends string>(entries: readonly ToolEntry<TId>[]): TId[] {\n const out: TId[] = [];\n const seen = new Set<string>();\n const walk = (list: readonly ToolEntry<TId>[]): void => {\n for (const entry of list) {\n if (isToolSet(entry)) walk(entry.members);\n else if (!seen.has(entry)) {\n seen.add(entry);\n out.push(entry);\n }\n }\n };\n walk(entries);\n return out;\n}\n\n/** `set` less every id `omit` names, sets opened. Keeps `set`'s id with a `-without` suffix. */\nexport function withoutTools<TId extends string>(set: ToolSet<TId>, ...omit: readonly ToolEntry<TId>[]): ToolSet<TId> {\n const gone = new Set<string>(toolIdsOf(omit));\n return { id: `${set.id}-without`, members: toolIdsOf([set]).filter((id) => !gone.has(id)) };\n}\n\n/** Whether `set` names `id`, directly or through a set inside it. */\nexport function toolSetHas<TId extends string>(set: ToolSet<TId>, id: string): boolean {\n return (toolIdsOf([set]) as string[]).includes(id);\n}\n","/**\n * Key chords a major browser or the desktop under it takes before a page can:\n * reload, devtools, tab and window commands, menu accelerators. A binding on\n * one never fires for some users, so kit defaults steer clear of them.\n *\n * `mod` is Cmd on macOS and Ctrl elsewhere, as in a `KeySpec`. The list is\n * the union across Chrome, Safari, Firefox and Edge on macOS, Windows and\n * Linux, and errs toward listing a chord.\n */\nimport type { KeySpec } from '@weasel-js/gestures';\n\n/** One reserved chord, and what takes it. */\nexport interface ReservedChord {\n key: string;\n mod?: boolean;\n alt?: boolean;\n shift?: boolean;\n /** Who takes it, for a message. */\n use: string;\n}\n\nconst chord = (keys: string, mods: Omit<ReservedChord, 'key' | 'use'>, use: string): ReservedChord[] =>\n [...keys].map((key) => ({ key, ...mods, use }));\n\n/** Every chord the module's header describes, one entry per key. */\nexport const BROWSER_RESERVED_CHORDS: readonly ReservedChord[] = [\n ...chord('nqtwlrpmh', { mod: true }, 'new window, quit, new or close tab, address bar, reload, print, minimize, hide'),\n ...chord('ntwrbo', { mod: true, shift: true }, 'private window, reopen or close tab, hard reload, bookmarks, bookmark manager'),\n ...chord('ijck', { mod: true, shift: true }, 'devtools, console and inspector on Windows and Linux; Firefox Browser and Web Console'),\n ...chord('ijcukbrlemhdwfn', { mod: true, alt: true }, 'devtools, console, inspector, view source, bookmarks, reload from origin, downloads, empty caches, minimize all, hide others, Dock, close all, search field'),\n ...chord('fevsbthd', { alt: true }, 'menu accelerators and address bar on Windows and Linux'),\n ...chord('ita', { alt: true, shift: true }, 'feedback, toolbar focus and accessibility commands'),\n];\n\nconst lower = (k: string | readonly string[]): string[] => (typeof k === 'string' ? [k] : [...k]).map((x) => x.toLowerCase());\n\n/** Whether a modifier policy can be satisfied with the modifier held (`true`)\n * or released (`false`). */\nconst allows = (policy: boolean | 'optional' | undefined, held: boolean): boolean =>\n policy === 'optional' || (policy === true) === held;\n\n/** The first reserved chord `spec` can fire on, or `null` when none. */\nexport function browserReservedChord(spec: KeySpec): ReservedChord | null {\n const keys = lower(spec.key);\n const m = spec.mods ?? {};\n const mod = m.mod ?? (m.meta === true || m.ctrl === true ? true : m.meta ?? m.ctrl);\n for (const c of BROWSER_RESERVED_CHORDS) {\n if (!keys.includes(c.key)) continue;\n if (allows(mod, c.mod === true) && allows(m.alt, c.alt === true) && allows(m.shift, c.shift === true)) return c;\n }\n return null;\n}\n","/**\n * Typed keys for the gesture/behavior scratch store, `ctx.scratch`.\n * `ScratchKey<T>` carries its payload type at the typing layer; at runtime\n * the key is just its underlying string and the store remains a plain `Record`.\n *\n * @example\n * ```ts\n * // Module-level constant, shared by writer + reader:\n * const LASSO_VERTICES = scratchKey<readonly { x: number; y: number }[]>('lasso.vertices');\n * setScratch(ctx.scratch, LASSO_VERTICES, vertices);\n * const vertices = getScratch(ctx.scratch, LASSO_VERTICES) ?? [];\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. Two keys with the same `name` refer to the same\n * slot at runtime — the type parameter is a compile-time contract, not a\n * uniqueness guarantee — so namespace the name (`'behavior.field'`).\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,4 +1,4 @@
|
|
|
1
|
-
import { o as Dispatcher, d as ActionsRegistry, C as Contribution, p as AffordanceHit, L as LongPressOptions, R as RuleCtx,
|
|
1
|
+
import { o as Dispatcher, d as ActionsRegistry, C as Contribution, p as AffordanceHit, q as DispatchTrace, L as LongPressOptions, R as RuleCtx, r as DepSchema } from './index-Cb7ehEks.js';
|
|
2
2
|
import { RefObject } from 'react';
|
|
3
3
|
import { BodyClassification } from '@weasel-js/gestures';
|
|
4
4
|
import { PaintedCursorState, CursorSink } from '@weasel-js/cursor';
|
|
@@ -61,6 +61,11 @@ interface DispatcherChannels {
|
|
|
61
61
|
/** `pointerdown`, hover `pointermove`, `pointerleave` — press, drag, click,
|
|
62
62
|
* long-press, multi-touch and the hover-cursor pump. */
|
|
63
63
|
pointer?: boolean;
|
|
64
|
+
/** `hover` gestures and the hover-cursor pump without the rest of
|
|
65
|
+
* `pointer`: no press opens a gesture or captures the pointer, so the
|
|
66
|
+
* element's own clicks and drags are left alone. Omitted, it follows
|
|
67
|
+
* `pointer`, which carries hovers whenever it is on. */
|
|
68
|
+
hover?: boolean;
|
|
64
69
|
/** `wheel`. */
|
|
65
70
|
wheel?: boolean;
|
|
66
71
|
/** WebKit's `gesturestart` / `gesturechange` / `gestureend` — Safari's
|
|
@@ -176,6 +181,9 @@ interface UseGestureDispatcherOptions {
|
|
|
176
181
|
* mounter and other consumers (the preview-ghost layer).
|
|
177
182
|
*/
|
|
178
183
|
dispatcher?: Dispatcher;
|
|
184
|
+
/** Where every dispatcher this hook drives records its decisions. Absent,
|
|
185
|
+
* the hook makes one of its own. Published as the `dispatchTrace` dep. */
|
|
186
|
+
trace?: DispatchTrace;
|
|
179
187
|
/**
|
|
180
188
|
* Converts a client-space pointer position (e.g. `e.clientX`, `e.clientY`)
|
|
181
189
|
* to world-space coordinates. When supplied, every pointer/wheel event's
|
package/dist/internal.d.ts
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
export { a as DispatcherViewTarget, V as ViewIdResolver } from './internal-
|
|
2
|
-
import './index-
|
|
1
|
+
export { a as DispatcherViewTarget, V as ViewIdResolver } from './internal-Dcyz_cJv.js';
|
|
2
|
+
import './index-Cb7ehEks.js';
|
|
3
|
+
import '@weasel-js/gestures';
|
|
4
|
+
import '@weasel-js/geom';
|
|
5
|
+
import '@weasel-js/cursor';
|
|
3
6
|
import '@weasel-js/menu';
|
|
4
7
|
import '@weasel-js/prefs';
|
|
5
|
-
import '@weasel-js/geom';
|
|
6
8
|
import '@weasel-js/modes';
|
|
7
|
-
import '@weasel-js/gestures';
|
|
8
9
|
import '@weasel-js/icons';
|
|
9
|
-
import '@weasel-js/cursor';
|
|
10
10
|
import 'react';
|
|
11
11
|
import '@weasel-js/registry';
|
|
12
12
|
import '@weasel-js/select';
|
package/dist/react.d.ts
CHANGED
|
@@ -1,16 +1,16 @@
|
|
|
1
|
-
import { U as UseGestureDispatcherOptions } from './internal-
|
|
2
|
-
export { D as DispatcherChannels } from './internal-
|
|
1
|
+
import { U as UseGestureDispatcherOptions } from './internal-Dcyz_cJv.js';
|
|
2
|
+
export { D as DispatcherChannels } from './internal-Dcyz_cJv.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
|
|
6
|
-
export { j as ActiveToolContextProvider, k as ActiveToolContextProviderIfRoot, l as ActiveToolContextProviderProps, m as ActiveToolContextValue, u as useActiveToolContext, n as useOptionalActiveToolContext } from './index-
|
|
5
|
+
import { D as DepRegistry, a as DepName, b as DepSource, S as ScopeNode, A as Action, c as ActionDeps, M as MenuHost, d as ActionsRegistry, e as ActionDisabledReason, B as BoundGesture, f as ActionVariant, g as MenuDef, h as DepNode, T as ToolNode, N as NodeId, K as KernelOverlay, C as Contribution, i as Tool, O as OverlayPosition } from './index-Cb7ehEks.js';
|
|
6
|
+
export { j as ActiveToolContextProvider, k as ActiveToolContextProviderIfRoot, l as ActiveToolContextProviderProps, m as ActiveToolContextValue, u as useActiveToolContext, n as useOptionalActiveToolContext } from './index-Cb7ehEks.js';
|
|
7
7
|
import { IconRef } from '@weasel-js/icons';
|
|
8
8
|
import { ModeRegistry } from '@weasel-js/modes';
|
|
9
9
|
import '@weasel-js/gestures';
|
|
10
10
|
import '@weasel-js/cursor';
|
|
11
|
+
import '@weasel-js/geom';
|
|
11
12
|
import '@weasel-js/menu';
|
|
12
13
|
import '@weasel-js/prefs';
|
|
13
|
-
import '@weasel-js/geom';
|
|
14
14
|
import '@weasel-js/registry';
|
|
15
15
|
import '@weasel-js/select';
|
|
16
16
|
|
|
@@ -39,8 +39,8 @@ declare function useDepRegistry(): DepRegistry;
|
|
|
39
39
|
declare function useOptionalDepRegistry(): DepRegistry | null;
|
|
40
40
|
/** Register a live source for `name` for the lifetime of the calling
|
|
41
41
|
* component. The `source` thunk is called at dispatch time and should
|
|
42
|
-
* return the latest value. */
|
|
43
|
-
declare function useDepSource<K extends DepName>(name: K, source:
|
|
42
|
+
* return the latest value; its `below` reads the source it displaced. */
|
|
43
|
+
declare function useDepSource<K extends DepName>(name: K, source: DepSource<K>): void;
|
|
44
44
|
|
|
45
45
|
/**
|
|
46
46
|
* One node of the actions tree: the actions registered at it, over its
|