@weasel-js/core 1.4.3 → 1.5.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.
Files changed (48) hide show
  1. package/CHANGELOG.md +1299 -2197
  2. package/README.md +118 -75
  3. package/dist/{pointSnapToGrid-D1bRdq-j.d.ts → autoPoseDescriptor-CvjflWJK.d.ts} +35 -17
  4. package/dist/{chunk-ORZNKVXM.js → chunk-BDWAA634.js} +4 -22
  5. package/dist/chunk-BDWAA634.js.map +1 -0
  6. package/dist/{chunk-WYPSGIYS.js → chunk-MG7OXCAI.js} +4149 -5316
  7. package/dist/chunk-MG7OXCAI.js.map +1 -0
  8. package/dist/{chunk-BLJNRMKB.js → chunk-MQI4PIX3.js} +3 -3
  9. package/dist/chunk-MQI4PIX3.js.map +1 -0
  10. package/dist/{chunk-SBFC6J3C.js → chunk-UCPV7JXC.js} +201 -256
  11. package/dist/chunk-UCPV7JXC.js.map +1 -0
  12. package/dist/clipboard.d.ts +2 -3
  13. package/dist/clone.d.ts +3 -2
  14. package/dist/depSchema-nMqj_qTM.d.ts +3490 -0
  15. package/dist/{grid-Bw8cSde-.d.ts → grid-BrIa38gG.d.ts} +7 -23
  16. package/dist/index.d.ts +2134 -1210
  17. package/dist/index.js +4 -5
  18. package/dist/insert.d.ts +4 -4
  19. package/dist/insert.js +1 -1
  20. package/dist/move.d.ts +5 -6
  21. package/dist/move.js +3 -6
  22. package/dist/move.js.map +1 -1
  23. package/dist/{options-DYfUlZxk.d.ts → options-BDyCnrp8.d.ts} +3 -2
  24. package/dist/poseDescriptor-CGOgIgf8.d.ts +134 -0
  25. package/dist/renderer.d.ts +10 -4
  26. package/dist/renderer.js +4 -5
  27. package/dist/resize.d.ts +10 -11
  28. package/dist/resize.js +2 -2
  29. package/dist/routing.d.ts +1 -142
  30. package/dist/routing.js +1 -1
  31. package/dist/routing.js.map +1 -1
  32. package/dist/{types-BJqsTlXl.d.ts → types-DMyo7dnM.d.ts} +12 -41
  33. package/dist/{types-CoVTbo_y.d.ts → types-DtjCJA5r.d.ts} +10 -9
  34. package/package.json +13 -10
  35. package/dist/DrawCommand-CD-ug3d9.d.ts +0 -332
  36. package/dist/builtins-CtGORLCG.d.ts +0 -740
  37. package/dist/chunk-BLJNRMKB.js.map +0 -1
  38. package/dist/chunk-LEURURX3.js +0 -561
  39. package/dist/chunk-LEURURX3.js.map +0 -1
  40. package/dist/chunk-ORZNKVXM.js.map +0 -1
  41. package/dist/chunk-SBFC6J3C.js.map +0 -1
  42. package/dist/chunk-WYPSGIYS.js.map +0 -1
  43. package/dist/geometry-CHR36Ub_.d.ts +0 -114
  44. package/dist/path-JEV2c5If.d.ts +0 -48
  45. package/dist/registry-DnoTWGED.d.ts +0 -4003
  46. package/dist/types-BHK2dkMu.d.ts +0 -172
  47. package/dist/types-H7o6MaPo.d.ts +0 -512
  48. package/dist/view-DSQgxBJB.d.ts +0 -63
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/interactions/actions/resize/behaviors/clampMinSize.ts","../src/interactions/actions/resize/behaviors/lockAspect.ts","../src/interactions/actions/resize/behaviors/snapToGrid.ts","../src/interactions/actions/resize/behaviors/snapToGuides.ts","../src/interactions/actions/resize/behaviors/pointSnapToGrid.ts","../src/interactions/actions/resize/behaviors/index.ts","../src/interactions/actions/resize/cornerHandles.ts"],"names":[],"mappings":"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","file":"chunk-BLJNRMKB.js","sourcesContent":["import type { BoundsConstraint, ResizePose } from '../../../gestures/types';\n\n/** Resize constraint that stops a node shrinking past a minimum. The anchored\n * edge stays put, so clamping pushes the dragged edge back rather than moving\n * the node. */\nexport function clampMinSize<TPose extends ResizePose>(args: {\n minWidth: number;\n minHeight: number;\n}): BoundsConstraint<TPose> {\n const { minWidth, minHeight } = args;\n return {\n onMove(_ctx, { pose, anchor }) {\n let { x, y, width, height } = pose;\n let changed = false;\n if (anchor.x !== 'free' && width < minWidth) {\n if (anchor.x === 'min') {\n // West edge is anchor; east edge was dragged. Hold x; widen to min.\n width = minWidth;\n } else {\n // East edge is anchor at originalRight = x + width. Hold the right;\n // shift x left so width = minWidth.\n const right = x + width;\n x = right - minWidth;\n width = minWidth;\n }\n changed = true;\n }\n if (anchor.y !== 'free' && height < minHeight) {\n if (anchor.y === 'min') {\n height = minHeight;\n } else {\n const bottom = y + height;\n y = bottom - minHeight;\n height = minHeight;\n }\n changed = true;\n }\n if (!changed) return;\n return { pose: { ...pose, x, y, width, height } };\n },\n };\n}\n","import type {\n ModifierState,\n BoundsConstraint,\n ResizePose,\n} from '../../../gestures/types';\n\ntype ModKey = keyof ModifierState;\n\n/** Aspect-ratio lock: drag a corner/edge with `key` (default `'shift'`) held\n * to keep the resized bounds at the start-pose's `width / height` ratio.\n *\n * Strategy:\n * - Compute the proposed deltas in width and height (signed, relative to\n * origin). Whichever axis has the larger absolute delta \"wins\"; the other\n * is recomputed from `(originW / originH) * winnerDelta`.\n * - The opposite corner/edge stays anchored — for the corner case we infer\n * the anchor from the proposed bounds; for an edge handle we resize the\n * orthogonal axis symmetrically around the dragged edge's anchor (the\n * handle's own line stays put, the orthogonal axis grows/shrinks centered\n * on the un-dragged edge — see notes below).\n * - No-op when the modifier is not held, when the origin has zero width or\n * height (no defined ratio), or when the proposed pose hasn't moved.\n *\n * Edge-handle handling: with `anchor.x !== 'free' && anchor.y === 'free'`\n * (an `e` or `w` handle), only the width was driven by the pointer. We pick\n * the new height as `width / ratio` and pin it to the un-dragged y axis by\n * anchoring at the origin's top edge (`y` stays at `origin.y`). Symmetric\n * for `n` / `s`.\n */\nexport function lockAspectWithModifier<TPose extends ResizePose>(opts: {\n key?: ModKey;\n} = {}): BoundsConstraint<TPose> {\n const { key = 'shift' } = opts;\n\n return {\n onMove(ctx, { pose, anchor }) {\n if (!ctx.modifiers[key]) return;\n const origin = ctx.origin.get(ctx.draggedIds[0]) as ResizePose | undefined;\n if (!origin) return;\n if (origin.width === 0 || origin.height === 0) return;\n const ratio = origin.width / origin.height; // w / h\n\n // Signed deltas relative to origin. Negative deltas mean the user has\n // dragged through the anchor and flipped the rect; we preserve sign on\n // the recomputed axis so the flipped quadrant stays consistent.\n const dw = pose.width - origin.width;\n const dh = pose.height - origin.height;\n\n let nw: number;\n let nh: number;\n\n if (anchor.x === 'free' && anchor.y === 'free') {\n // No driven axis — nothing to lock against.\n return;\n } else if (anchor.x === 'free') {\n // Edge handle: n or s. height is driven; width follows.\n nh = pose.height;\n nw = nh * ratio;\n // sign-preserve width if the original height delta caused a flip.\n // (height-driven only; width direction follows ratio absolutely.)\n if (nw < 0) nw = -nw;\n } else if (anchor.y === 'free') {\n // Edge handle: e or w. width is driven; height follows.\n nw = pose.width;\n nh = nw / ratio;\n if (nh < 0) nh = -nh;\n } else {\n // Corner handle. Pick the dominant axis by absolute delta.\n if (Math.abs(dw) >= Math.abs(dh)) {\n nw = pose.width;\n // Match height sign to width sign so the rect stays in the same\n // quadrant the pointer chose.\n nh = (Math.abs(nw) / ratio) * Math.sign(pose.height || 1);\n } else {\n nh = pose.height;\n nw = (Math.abs(nh) * ratio) * Math.sign(pose.width || 1);\n }\n }\n\n // Recompute x/y from the anchor (the un-dragged edge stays pinned).\n let nx = pose.x;\n let ny = pose.y;\n if (anchor.x === 'min') {\n // West edge anchored at origin.x.\n nx = origin.x;\n } else if (anchor.x === 'max') {\n // East edge anchored at origin.x + origin.width.\n nx = origin.x + origin.width - nw;\n } else {\n // Edge handle (n/s): width grew/shrunk via ratio. Center horizontally\n // about the origin's center so the rect stays visually centered on\n // the dragged edge's midline.\n nx = origin.x + origin.width / 2 - nw / 2;\n }\n if (anchor.y === 'min') {\n ny = origin.y;\n } else if (anchor.y === 'max') {\n ny = origin.y + origin.height - nh;\n } else {\n ny = origin.y + origin.height / 2 - nh / 2;\n }\n\n return {\n pose: { ...pose, x: nx, y: ny, width: nw, height: nh },\n };\n },\n };\n}\n","import type {\n ModifierState,\n BoundsConstraint,\n ResizePose,\n} from '../../../gestures/types';\n\ntype ModKey = keyof ModifierState;\n\n/** Resize constraint that snaps the moving edges to a grid, leaving the\n * anchored ones where they are. By default a node already smaller than one\n * grid cell on an axis is left unsnapped on that axis, so it stays resizable\n * at sub-grid sizes. */\nexport function snapToGrid<TPose extends ResizePose>(args: {\n spacing: number;\n bypassKey?: ModKey;\n suspendBelowDim?: boolean;\n}): BoundsConstraint<TPose> {\n const { spacing, bypassKey, suspendBelowDim = true } = args;\n const round = (v: number) => Math.round(v / spacing) * spacing;\n\n return {\n onMove(ctx, { pose, anchor }) {\n if (bypassKey && ctx.modifiers[bypassKey]) return;\n const origin = ctx.origin.get(ctx.draggedIds[0])!;\n const subX = suspendBelowDim && origin.width < spacing;\n const subY = suspendBelowDim && origin.height < spacing;\n\n let { x, y, width, height } = pose;\n let changed = false;\n\n if (anchor.x !== 'free' && !subX) {\n if (anchor.x === 'min') {\n // East edge moves; west (x) stays.\n const east = round(x + width);\n width = east - x;\n } else {\n // West edge moves; east (x+width) stays.\n const right = origin.x + origin.width;\n const newX = round(x);\n width = right - newX;\n x = newX;\n }\n changed = true;\n }\n if (anchor.y !== 'free' && !subY) {\n if (anchor.y === 'min') {\n const south = round(y + height);\n height = south - y;\n } else {\n const bottom = origin.y + origin.height;\n const newY = round(y);\n height = bottom - newY;\n y = newY;\n }\n changed = true;\n }\n if (!changed) return;\n return { pose: { ...pose, x, y, width, height } };\n },\n };\n}\n","import type {\n ModifierState,\n BoundsConstraint,\n ResizePose,\n} from '../../../gestures/types';\nimport type { Guide } from 'features/guides/types';\nimport type { View } from 'core/viewport/view';\nimport { pxExtent } from 'core/viewport/pxExtent';\nimport { DEFAULT_GUIDE_TOLERANCE_PX } from '../../../gestures/shared/strategies/guides';\n\ntype ModKey = keyof ModifierState;\n\n/** Options for the resize-flavored `snapToGuides`. */\nexport interface SnapToGuidesResizeArgs {\n /** Stable getter into the live guide list (typically from `useGuides`). */\n getGuides: () => readonly Guide[];\n /** Snap tolerance (screen px when `getView` is set, world units otherwise). */\n tolerance?: number;\n /** Read the active view; required for screen-pixel tolerance. */\n getView?: () => View;\n /** Modifier key that bypasses snapping while held. */\n bypassKey?: ModKey;\n}\n\n/**\n * Resize behavior that snaps the active edge of the dragged rect to the\n * nearest guide on the corresponding axis when within `tolerance`. The\n * \"free\" axis is left untouched. The fixed (anchor) edge stays pinned;\n * only the moving edge snaps.\n *\n * On the X axis, vertical guides (`axis: 'x'`) constrain the moving vertical\n * edge — east when `anchor.x === 'min'` (west pinned), west when `'max'`.\n * Likewise on Y for horizontal guides.\n */\nexport function snapToGuides<TPose extends ResizePose>(\n args: SnapToGuidesResizeArgs,\n): BoundsConstraint<TPose> {\n const tolerance = args.tolerance ?? DEFAULT_GUIDE_TOLERANCE_PX;\n const getView = args.getView;\n const bypassKey = args.bypassKey;\n\n return {\n onMove(ctx, { pose, anchor }) {\n if (bypassKey && ctx.modifiers[bypassKey]) return;\n const guides = args.getGuides();\n if (guides.length === 0) return;\n\n // Per axis: a vertical guide is matched by a horizontal distance, so it\n // answers to `scale.x` alone.\n const tol = getView ? pxExtent(tolerance, getView().scale) : { x: tolerance, y: tolerance };\n\n let { x, y, width, height } = pose;\n let changed = false;\n\n // X-axis: snap the moving vertical edge to the nearest 'x' guide.\n if (anchor.x !== 'free') {\n const movingX = anchor.x === 'min' ? x + width : x;\n let bestD = 0;\n let bestAbs = Infinity;\n for (const g of guides) {\n if (g.axis !== 'x') continue;\n const d = g.offset - movingX;\n const ad = Math.abs(d);\n if (ad <= tol.x && ad < bestAbs) {\n bestAbs = ad;\n bestD = d;\n }\n }\n if (bestAbs !== Infinity && bestD !== 0) {\n if (anchor.x === 'min') {\n // East edge moves; west (x) stays.\n width = width + bestD;\n } else {\n // West edge moves; east (x+width) stays.\n x = x + bestD;\n width = width - bestD;\n }\n changed = true;\n }\n }\n\n // Y-axis: snap the moving horizontal edge to the nearest 'y' guide.\n if (anchor.y !== 'free') {\n const movingY = anchor.y === 'min' ? y + height : y;\n let bestD = 0;\n let bestAbs = Infinity;\n for (const g of guides) {\n if (g.axis !== 'y') continue;\n const d = g.offset - movingY;\n const ad = Math.abs(d);\n if (ad <= tol.y && ad < bestAbs) {\n bestAbs = ad;\n bestD = d;\n }\n }\n if (bestAbs !== Infinity && bestD !== 0) {\n if (anchor.y === 'min') {\n height = height + bestD;\n } else {\n y = y + bestD;\n height = height - bestD;\n }\n changed = true;\n }\n }\n\n if (!changed) return;\n return { pose: { ...pose, x, y, width, height } };\n },\n };\n}\n","import type {\n ModifierState,\n PointSnapBehavior,\n PointSnapContext,\n PointSnapFrame,\n PointSnapResult,\n ResizePose,\n} from '../../../gestures/types';\n\n/** Resize behavior that snaps one reference point of the resize — the dragged\n * corner, the fixed corner, or the center, per `frame` — to a grid, moving\n * the whole pose by the same delta. Unlike the bounds-level `snapToGrid`,\n * this preserves the node's dimensions. */\nexport function pointSnapToGrid<TPose extends ResizePose>(args: {\n spacing: number;\n frame?: PointSnapFrame;\n bypassKey?: keyof ModifierState;\n}): PointSnapBehavior<TPose> {\n const { spacing, frame = 'dragged-corner', bypassKey } = args;\n const round = (v: number) => Math.round(v / spacing) * spacing;\n\n return {\n id: `pointSnapToGrid:${frame}`,\n onMove(ctx: PointSnapContext<TPose>): PointSnapResult | null {\n if (bypassKey && ctx.modifiers[bypassKey]) return null;\n const src =\n frame === 'dragged-corner' ? ctx.draggedCorner :\n frame === 'fixed-corner' ? ctx.fixedCorner :\n frame === 'center' ? ctx.center :\n ctx.origin;\n if (!src) return null;\n return { frame, worldX: round(src.worldX), worldY: round(src.worldY) };\n },\n };\n}\n","export { clampMinSize } from './clampMinSize';\nexport { lockAspectWithModifier } from './lockAspect';\nexport { snapToGrid } from './snapToGrid';\n\nimport type { BoundsConstraint, ResizePose } from '../../../gestures/types';\nimport { lockAspectWithModifier } from './lockAspect';\n\n/** The kit's standard resize behaviors, applied when a consumer doesn't\n * supply its own list: shift-drag locks the start pose's aspect ratio.\n * Pass an explicit `behaviors: []` to opt out. Stateless, so one shared\n * frozen instance is safe across every gesture. */\nexport const DEFAULT_RESIZE_BEHAVIORS: readonly BoundsConstraint<ResizePose>[] =\n Object.freeze([lockAspectWithModifier()]);\nexport { snapToGuides } from './snapToGuides';\nexport { pointSnapToGrid } from './pointSnapToGrid';\n","import type { ResizeAnchor } from '../../gestures/types';\nimport type { Bounds } from 'core/viewport/fitViewToBounds';\n\n/** Corner resize-handle: world-space center plus the anchor that pins the opposite corner during resize. */\nexport interface CornerHandle {\n cx: number;\n cy: number;\n anchor: ResizeAnchor;\n}\n\n/** Which AABB edge a corner sits on, per axis. `'min'` = the x/y origin\n * edge; `'max'` = the origin + extent edge. */\nexport type CornerEdge = 'min' | 'max';\n\n/** One entry of the canonical 4-corner resize layout. The single source of\n * truth for \"which corner maps to which anchor / handle-kind\". */\nexport interface CornerAnchor {\n /** Which x-edge the corner sits on (`'min'` = left, `'max'` = right). */\n xEdge: CornerEdge;\n /** Which y-edge the corner sits on (`'min'` = top, `'max'` = bottom). */\n yEdge: CornerEdge;\n /** Anchor that pins the diagonally-opposite (fixed) corner. Always the\n * axis-wise opposite of `{xEdge, yEdge}`. */\n anchor: ResizeAnchor;\n /** Affordance/handle discriminator string for this corner. */\n kind: string;\n /** Short positional tag (`'<xEdge>-<yEdge>'`), e.g. `'min-max'`. */\n tag: string;\n}\n\n/**\n * The single ordered corner→anchor table. Order is **load-bearing**: every\n * consumer iterates it in this sequence (TL, TR, BL, BR) so positional\n * meaning (the i-th handle / `kind` / `tag`) stays consistent across the\n * resize-handle affordance, the affordance-hit classifier, and\n * `cornerResizeHandles`. Each corner's `anchor` names the diagonally\n * opposite corner, so dragging the corner scales the box from that fixed\n * point.\n */\nexport const CORNER_ANCHORS: readonly CornerAnchor[] = [\n { xEdge: 'min', yEdge: 'min', anchor: { x: 'max', y: 'max' }, kind: 'handle:top-left', tag: 'min-min' },\n { xEdge: 'max', yEdge: 'min', anchor: { x: 'min', y: 'max' }, kind: 'handle:top-right', tag: 'max-min' },\n { xEdge: 'min', yEdge: 'max', anchor: { x: 'max', y: 'min' }, kind: 'handle:bottom-left', tag: 'min-max' },\n { xEdge: 'max', yEdge: 'max', anchor: { x: 'min', y: 'min' }, kind: 'handle:bottom-right', tag: 'max-max' },\n];\n\n/** Resolve a corner's world-space position for the given bounds. `xEdge`\n * `'max'` → `x + width`; `yEdge` `'max'` → `y + height`. */\nexport function cornerPoint(\n bounds: Bounds,\n entry: Pick<CornerAnchor, 'xEdge' | 'yEdge'>,\n): { x: number; y: number } {\n return {\n x: entry.xEdge === 'max' ? bounds.x + bounds.width : bounds.x,\n y: entry.yEdge === 'max' ? bounds.y + bounds.height : bounds.y,\n };\n}\n\n/** Standard 4-corner resize-handle layout: each corner pins the opposite\n * corner via an anchor of `{x: 'min'|'max', y: 'min'|'max'}` so dragging it\n * scales the box from the fixed opposite corner. Decodes {@link CORNER_ANCHORS}\n * against `bounds`. */\nexport function cornerResizeHandles(bounds: Bounds): CornerHandle[] {\n return CORNER_ANCHORS.map((c) => {\n const p = cornerPoint(bounds, c);\n return { cx: p.x, cy: p.y, anchor: c.anchor };\n });\n}\n\n/** Square hit-test for a handle: returns true if `(px, py)` is within\n * `radius` of the handle center on both axes. */\nexport function hitCornerHandle(\n handle: CornerHandle,\n px: number,\n py: number,\n radius: number,\n): boolean {\n return Math.abs(px - handle.cx) <= radius\n && Math.abs(py - handle.cy) <= radius;\n}\n\n/** The corner that does NOT move under a resize gesture with the given\n * anchor. Used by the rotated-resize math to pin a world-space invariant.\n *\n * Convention: `anchor.x === 'min'` means the min-x (left) edge is the\n * fixed anchor, so the fixed corner sits at `x = bounds.x` (min-x).\n * `anchor.x === 'max'` means the max-x (right) edge is fixed, so the\n * fixed corner sits at `x = bounds.x + bounds.width`. `'free'` on an\n * axis means that axis doesn't move; the fixed coord is the bounds\n * origin on that axis. */\nexport function fixedCornerOf(\n bounds: Bounds,\n anchor: ResizeAnchor,\n): { x: number; y: number } {\n return {\n x: anchor.x === 'max' ? bounds.x + bounds.width : bounds.x,\n y: anchor.y === 'max' ? bounds.y + bounds.height : bounds.y,\n };\n}\n"]}
@@ -1,561 +0,0 @@
1
- import { createContext, useRef, useMemo, useContext, useEffect } from 'react';
2
- import { jsx, Fragment } from 'react/jsx-runtime';
3
- import { isKnownGestureName, getGestureDescriptor, formatRoute, canonicalModifiers, RESERVED_ID_PREFIXES, RESERVED_ID_NAMES } from '@weasel-js/gestures';
4
- export { GESTURE_DESCRIPTORS, RESERVED_ID_NAMES, RESERVED_ID_PREFIXES, ROUTE_FIELD_DEFINITIONS, ROUTE_TERMS, canonicalModifiers, collapseShiftPairs, describeRoute, describeRouteParts, formatPhaseAtom, formatRoute, getGestureDescriptor, isKnownGestureName, parseRoute } from '@weasel-js/gestures';
5
-
6
- // src/interactions/actions/depRegistry.tsx
7
- var DepRegistryContext = createContext(null);
8
- function DepRegistryProvider({ children }) {
9
- const sourcesRef = useRef(/* @__PURE__ */ new Map());
10
- const registry = useMemo(() => ({
11
- register: (name, source) => {
12
- sourcesRef.current.set(name, source);
13
- return () => {
14
- sourcesRef.current.delete(name);
15
- };
16
- },
17
- get: (name) => sourcesRef.current.get(name)?.()
18
- }), []);
19
- return /* @__PURE__ */ jsx(DepRegistryContext.Provider, { value: registry, children });
20
- }
21
- function useDepRegistry() {
22
- const r = useContext(DepRegistryContext);
23
- if (r === null) {
24
- throw new Error("useDepRegistry: no DepRegistryProvider in scope. Wrap your tree with <DepRegistryProvider> (typically inside <SceneCanvas>).");
25
- }
26
- return r;
27
- }
28
- function useOptionalDepRegistry() {
29
- return useContext(DepRegistryContext);
30
- }
31
- function useDepSource(name, source) {
32
- const registry = useDepRegistry();
33
- const sourceRef = useRef(source);
34
- sourceRef.current = source;
35
- useEffect(() => {
36
- return registry.register(name, () => sourceRef.current());
37
- }, [name, registry]);
38
- }
39
-
40
- // src/interactions/actions/buildDeps.ts
41
- var DEV = (() => {
42
- try {
43
- return Boolean(import.meta.env?.DEV);
44
- } catch {
45
- return false;
46
- }
47
- })();
48
- function buildDepsFromRequires(action, depRegistry) {
49
- const requires = action.requires ?? [];
50
- const entries = requires.map((name) => [name, depRegistry.get(name)]);
51
- const deps = Object.fromEntries(entries);
52
- if (DEV) {
53
- const declared = new Set(requires);
54
- return new Proxy(deps, {
55
- get(target, prop, receiver) {
56
- if (typeof prop === "string" && !declared.has(prop) && prop !== "then") {
57
- const message = `[weasel:dispatcher] action "${action.id}" read deps.${prop} but did not declare it in \`requires\`. Add \`requires: [...'${prop}']\` to the descriptor or the dep will be undefined at runtime.`;
58
- console.warn(message);
59
- throw new Error(message);
60
- }
61
- return Reflect.get(target, prop, receiver);
62
- }
63
- });
64
- }
65
- return deps;
66
- }
67
- function actionBindings(action) {
68
- const gs = action.defaultBinding;
69
- if (!gs) return [];
70
- const raw = Array.isArray(gs) ? gs : [gs];
71
- return raw.map((entry) => {
72
- const isBoundObj = !("kind" in entry);
73
- const spec = isBoundObj ? entry.spec : entry;
74
- const opts = isBoundObj ? entry.opts : void 0;
75
- return { spec, actionId: action.id, ...opts !== void 0 ? { opts } : {} };
76
- });
77
- }
78
- var ActionDisabledReason = {
79
- SelectionRequired: "selection-required",
80
- SceneEmpty: "scene-empty",
81
- NotApplicable: "not-applicable",
82
- /** Sentinel: the predicate threw. Surfaced by `evaluateEnabled`'s catch. */
83
- PredicateThrew: "predicate-threw"
84
- };
85
- var enabledSlowWarned = /* @__PURE__ */ new Set();
86
- var enabledThrewWarned = /* @__PURE__ */ new Set();
87
- var ENABLED_BUDGET_MS = 4;
88
- function evaluateEnabled(action, deps) {
89
- if (!action.enabled) return { enabled: true };
90
- const isDev = typeof process !== "undefined" ? process.env.NODE_ENV !== "production" : true;
91
- const now = typeof performance !== "undefined" && typeof performance.now === "function" ? () => performance.now() : () => Date.now();
92
- const start = isDev ? now() : 0;
93
- try {
94
- const result = action.enabled(deps);
95
- if (isDev) {
96
- const elapsed = now() - start;
97
- if (elapsed > ENABLED_BUDGET_MS && !enabledSlowWarned.has(action.id)) {
98
- enabledSlowWarned.add(action.id);
99
- console.warn(
100
- `weasel actions: enabled() for action "${action.id}" took ${elapsed.toFixed(2)}ms (budget ${ENABLED_BUDGET_MS}ms). The predicate must be pure and fast \u2014 see Action.enabled JSDoc.`
101
- );
102
- }
103
- }
104
- if (result === true) return { enabled: true };
105
- return { enabled: false, reason: result };
106
- } catch (e) {
107
- if (isDev && !enabledThrewWarned.has(action.id)) {
108
- enabledThrewWarned.add(action.id);
109
- console.warn(
110
- `weasel actions: enabled() for action "${action.id}" threw; treating as disabled. The predicate must not throw \u2014 see Action.enabled JSDoc.`,
111
- e
112
- );
113
- }
114
- return { enabled: false, reason: ActionDisabledReason.PredicateThrew };
115
- }
116
- }
117
- function validateActionId(id) {
118
- if (id.length === 0) {
119
- throw new Error(`weasel: action id may not be empty`);
120
- }
121
- if (RESERVED_ID_PREFIXES.has(id[0])) {
122
- throw new Error(
123
- `weasel: action id "${id}" starts with reserved sigil "${id[0]}" (reserved set: ${[...RESERVED_ID_PREFIXES].join(" ")})`
124
- );
125
- }
126
- if (RESERVED_ID_NAMES.has(id)) {
127
- throw new Error(
128
- `weasel: action id "${id}" collides with a reserved phase keyword (reserved: ${[...RESERVED_ID_NAMES].join(", ")})`
129
- );
130
- }
131
- }
132
- function validateActionDefaultBinding(action) {
133
- const gs = action.defaultBinding;
134
- if (!gs) return;
135
- const entries = Array.isArray(gs) ? gs : [gs];
136
- for (const entry of entries) {
137
- const spec = "kind" in entry ? entry : entry.spec;
138
- const phase = spec.phase;
139
- if (phase === void 0) continue;
140
- const atoms = Array.isArray(phase) ? phase : [{ channel: "&", phase }];
141
- for (const atom of atoms) {
142
- if (atom.channel === "&") {
143
- throw new Error(
144
- `weasel: action "${action.id}" defaultBinding uses '&' channel which has no owning tool to resolve to. Use a named tool channel (e.g. '[rect:engaged]') or '*' instead, or move this binding to the tool's own Tool.bindings.`
145
- );
146
- }
147
- }
148
- }
149
- }
150
- function warnSharedScope() {
151
- if (!IS_DEV) return;
152
- console.warn(
153
- "weasel: a second dispatcher claimed this <ActionsProvider>, so only the newest <SceneCanvas> under it will respond to input. Give each canvas its own scope with <WeaselProvider isolate>."
154
- );
155
- }
156
- var ActionsContext = createContext(null);
157
- function useMuted(base) {
158
- const mutedRef = useRef(/* @__PURE__ */ new Map());
159
- const listenersRef = useRef(/* @__PURE__ */ new Set());
160
- const cacheRef = useRef(null);
161
- return useMemo(() => {
162
- if (!base) return null;
163
- const isMuted = (id) => mutedRef.current.has(id);
164
- const notify = () => {
165
- for (const l of listenersRef.current) {
166
- try {
167
- l();
168
- } catch (err) {
169
- console.error("weasel ActionsRegistry: subscriber threw", err);
170
- }
171
- }
172
- };
173
- return {
174
- ...base,
175
- list: () => {
176
- const src = base.list();
177
- if (mutedRef.current.size === 0) return src;
178
- const cached = cacheRef.current;
179
- if (cached && cached.src === src) return cached.out;
180
- const out = Object.freeze(src.filter((a) => !mutedRef.current.has(a.id)));
181
- cacheRef.current = { src, out };
182
- return out;
183
- },
184
- trigger: (id, params) => isMuted(id) ? false : base.trigger(id, params),
185
- begin: (id, params) => isMuted(id) ? null : base.begin(id, params),
186
- subscribe: (listener) => {
187
- const offBase = base.subscribe(listener);
188
- listenersRef.current.add(listener);
189
- return () => {
190
- offBase();
191
- listenersRef.current.delete(listener);
192
- };
193
- },
194
- mute: (id) => {
195
- mutedRef.current.set(id, (mutedRef.current.get(id) ?? 0) + 1);
196
- cacheRef.current = null;
197
- notify();
198
- let released = false;
199
- return () => {
200
- if (released) return;
201
- released = true;
202
- const held = mutedRef.current.get(id);
203
- if (held === void 0) return;
204
- if (held > 1) mutedRef.current.set(id, held - 1);
205
- else mutedRef.current.delete(id);
206
- cacheRef.current = null;
207
- notify();
208
- };
209
- }
210
- };
211
- }, [base]);
212
- }
213
- function ActionsScope({ children }) {
214
- const parent = useActionsRegistry();
215
- const scoped = useMuted(parent);
216
- if (!scoped) return /* @__PURE__ */ jsx(Fragment, { children });
217
- return /* @__PURE__ */ jsx(ActionsContext.Provider, { value: scoped, children });
218
- }
219
- function ActionsProvider({ children }) {
220
- const actionsRef = useRef(/* @__PURE__ */ new Map());
221
- const liveAction = (id) => actionsRef.current.get(id)?.at(-1);
222
- const versionRef = useRef(0);
223
- const cachedRef = useRef([]);
224
- const cachedVerRef = useRef(-1);
225
- const listenersRef = useRef(/* @__PURE__ */ new Set());
226
- const depReg = useOptionalDepRegistry();
227
- const depRegRef = useRef(depReg);
228
- depRegRef.current = depReg;
229
- const warnedRef = useRef(false);
230
- const wiredDepRegRef = useRef(null);
231
- const dispatcherRef = useRef(null);
232
- const store = useMemo(() => {
233
- const snapshot = () => {
234
- const v = versionRef.current;
235
- if (cachedVerRef.current === v) return cachedRef.current;
236
- const out = Object.freeze(
237
- Array.from(actionsRef.current.values(), (stack) => stack[stack.length - 1])
238
- );
239
- cachedRef.current = out;
240
- cachedVerRef.current = v;
241
- return out;
242
- };
243
- const notify = () => {
244
- for (const l of listenersRef.current) {
245
- try {
246
- l();
247
- } catch (err) {
248
- console.error("weasel ActionsRegistry: subscriber threw", err);
249
- }
250
- }
251
- };
252
- return {
253
- register: (action) => {
254
- validateActionId(action.id);
255
- validateActionDefaultBinding(action);
256
- const stack = actionsRef.current.get(action.id);
257
- if (stack) stack.push(action);
258
- else actionsRef.current.set(action.id, [action]);
259
- versionRef.current++;
260
- notify();
261
- let released = false;
262
- return () => {
263
- if (released) return;
264
- released = true;
265
- const cur = actionsRef.current.get(action.id);
266
- if (!cur) return;
267
- const i = cur.lastIndexOf(action);
268
- if (i === -1) return;
269
- cur.splice(i, 1);
270
- if (cur.length === 0) actionsRef.current.delete(action.id);
271
- versionRef.current++;
272
- notify();
273
- };
274
- },
275
- unregister: (id) => {
276
- if (actionsRef.current.delete(id)) {
277
- versionRef.current++;
278
- notify();
279
- }
280
- },
281
- list: () => snapshot(),
282
- trigger: (id, params) => {
283
- const a = liveAction(id);
284
- if (!a) return false;
285
- try {
286
- if (a.invoker && a.invoker.timing === "immediate") {
287
- const r = wiredDepRegRef.current ?? depRegRef.current;
288
- const deps = !r ? {} : a.requires ? buildDepsFromRequires(a, r) : {
289
- selection: r.get("selection"),
290
- scene: r.get("scene"),
291
- history: r.get("history"),
292
- view: r.get("view"),
293
- pointer: r.get("pointer"),
294
- activeTool: r.get("activeTool"),
295
- booleansAdapter: r.get("booleansAdapter")
296
- };
297
- a.invoker.run(deps, params);
298
- }
299
- } catch (err) {
300
- console.error(`weasel ActionsRegistry: action "${id}" threw`, err);
301
- }
302
- return true;
303
- },
304
- subscribe: (listener) => {
305
- listenersRef.current.add(listener);
306
- return () => {
307
- listenersRef.current.delete(listener);
308
- };
309
- },
310
- setDispatcher: (d) => {
311
- if (d && dispatcherRef.current && dispatcherRef.current !== d && !warnedRef.current) {
312
- warnedRef.current = true;
313
- warnSharedScope();
314
- }
315
- dispatcherRef.current = d;
316
- return () => {
317
- if (dispatcherRef.current === d) dispatcherRef.current = null;
318
- };
319
- },
320
- setDepRegistry: (r) => {
321
- wiredDepRegRef.current = r;
322
- return () => {
323
- if (wiredDepRegRef.current === r) wiredDepRegRef.current = null;
324
- };
325
- },
326
- begin: (id, params) => {
327
- const disp = dispatcherRef.current;
328
- if (!disp) return null;
329
- const r = wiredDepRegRef.current ?? depRegRef.current;
330
- const a = liveAction(id);
331
- const deps = !r ? {} : a?.requires ? buildDepsFromRequires(a, r) : {
332
- selection: r.get("selection"),
333
- scene: r.get("scene"),
334
- history: r.get("history"),
335
- view: r.get("view"),
336
- pointer: r.get("pointer"),
337
- activeTool: r.get("activeTool"),
338
- booleansAdapter: r.get("booleansAdapter")
339
- };
340
- return disp.beginUiOngoing(id, deps, params);
341
- }
342
- };
343
- }, []);
344
- const registry = useMuted(store);
345
- return /* @__PURE__ */ jsx(ActionsContext.Provider, { value: registry, children });
346
- }
347
- var IS_DEV = (() => {
348
- try {
349
- return Boolean(import.meta.env?.DEV);
350
- } catch {
351
- return false;
352
- }
353
- })();
354
- function useActionsRegistry() {
355
- return useContext(ActionsContext);
356
- }
357
- function useAction(action) {
358
- const reg = useActionsRegistry();
359
- useEffect(() => {
360
- if (!reg) {
361
- if (IS_DEV) {
362
- console.warn(
363
- `useAction("${action.id}"): no <ActionsProvider> is in scope, so the action was not registered and its bindings will never fire.`
364
- );
365
- }
366
- return;
367
- }
368
- return reg.register(action);
369
- }, [reg, action]);
370
- }
371
-
372
- // src/tools/routing/reflection/registry.ts
373
- var PREDICATE_TARGET = "predicate";
374
- var SPEC_KIND_TO_GESTURE = {
375
- key: "keyDown",
376
- "key-held": "keyHeld",
377
- wheel: "wheel",
378
- click: "click",
379
- doubleClick: "dblTap",
380
- contextMenu: "contextMenu",
381
- longPress: "longPress",
382
- drag: "drag",
383
- pointerDown: "pointerDown",
384
- multiTouch: void 0,
385
- multiTouchTap: "multiTouchTap",
386
- drop: "drop",
387
- paste: "paste"
388
- };
389
- function buildRouteRegistry(tools) {
390
- const out = [];
391
- for (const tool of tools) {
392
- for (const binding of tool.bindings ?? []) {
393
- const entry = entryFor(tool.id, binding.spec, binding.actionId);
394
- if (entry) out.push(entry);
395
- }
396
- }
397
- return out;
398
- }
399
- function routeGestureForSpecKind(kind) {
400
- const gesture = SPEC_KIND_TO_GESTURE[kind];
401
- return gesture && isKnownGestureName(gesture) ? gesture : void 0;
402
- }
403
- function routesForSpec(spec) {
404
- const gesture = routeGestureForSpecKind(spec.kind);
405
- if (!gesture) return [];
406
- const descriptor = getGestureDescriptor(gesture);
407
- const modifiers = parseModSpec("mods" in spec ? spec.mods : void 0);
408
- const phases = phaseAtomsForSpec("phase" in spec ? spec.phase : void 0);
409
- const target = descriptor.hasTarget ? routeTargetForSpec("target" in spec ? spec.target : void 0) ?? "*" : void 0;
410
- const args = descriptor.arg ? routeArgsForSpec(spec, descriptor.arg.default) : [void 0];
411
- return args.map((arg) => formatRoute({ phases, gesture, arg, target, modifiers }));
412
- }
413
- function entryFor(toolId, spec, actionId) {
414
- const gesture = SPEC_KIND_TO_GESTURE[spec.kind];
415
- if (!gesture || !isKnownGestureName(gesture)) return null;
416
- const descriptor = getGestureDescriptor(gesture);
417
- return {
418
- toolId,
419
- actionId,
420
- gesture,
421
- phase: phaseOf("phase" in spec ? spec.phase : void 0),
422
- modifiers: parseModSpec("mods" in spec ? spec.mods : void 0),
423
- arg: descriptor.arg ? argOf(spec, descriptor.arg.default) : void 0,
424
- target: descriptor.hasTarget ? routeTargetForSpec("target" in spec ? spec.target : void 0) : void 0,
425
- spec
426
- };
427
- }
428
- function phaseOf(phase) {
429
- if (phase === void 0 || phase === "*") return "any";
430
- if (phase === "initial" || phase === "engaged") return phase;
431
- const distinct = new Set(phase.map((atom) => atom.phase));
432
- if (distinct.size !== 1) return "any";
433
- const only = [...distinct][0];
434
- return only === "initial" || only === "engaged" ? only : "any";
435
- }
436
- function parseModSpec(mods) {
437
- if (!mods) return {};
438
- const out = {};
439
- for (const [name, req] of Object.entries(mods)) {
440
- if (req === true) out[name] = "required";
441
- else if (req === "optional") out[name] = "optional";
442
- }
443
- return out;
444
- }
445
- function phaseAtomsForSpec(phase) {
446
- if (phase === void 0) return [{ channel: "&", phase: "*" }];
447
- if (phase === "initial" || phase === "engaged" || phase === "*") {
448
- return [{ channel: "&", phase }];
449
- }
450
- return phase;
451
- }
452
- function routeTargetForSpec(target) {
453
- if (target === void 0) return void 0;
454
- return typeof target === "string" ? target : PREDICATE_TARGET;
455
- }
456
- function routeArgsForSpec(spec, fallback) {
457
- if ("key" in spec) return Array.isArray(spec.key) ? spec.key : [spec.key];
458
- if ("fingers" in spec) return [String(spec.fingers)];
459
- if ("direction" in spec) return [spec.direction ?? fallback];
460
- if ("types" in spec) return [spec.types?.length ? spec.types.join("|") : fallback];
461
- return [fallback];
462
- }
463
- function argOf(spec, fallback) {
464
- const args = routeArgsForSpec(spec, fallback);
465
- return args.length > 1 ? args.join("|") : args[0];
466
- }
467
-
468
- // src/tools/routing/reflection/conflicts.ts
469
- function findConflicts(tools) {
470
- const entries = buildRouteRegistry(tools);
471
- const groups = /* @__PURE__ */ new Map();
472
- for (const entry of entries) {
473
- const key = `${entry.phase}|${entry.gesture}|${entry.arg ?? ""}|${targetKey(entry)}|${canonicalModifiers(entry.modifiers)}`;
474
- const bucket = groups.get(key);
475
- if (bucket) bucket.push(entry);
476
- else groups.set(key, [entry]);
477
- }
478
- const conflicts = [];
479
- for (const bucket of groups.values()) {
480
- if (bucket.length < 2) continue;
481
- const first = bucket[0];
482
- conflicts.push({
483
- phase: first.phase,
484
- gesture: first.gesture,
485
- arg: first.arg,
486
- target: first.target,
487
- modifiers: first.modifiers,
488
- toolIds: bucket.map((e) => e.toolId)
489
- });
490
- }
491
- return conflicts;
492
- }
493
- function targetKey(entry) {
494
- if (entry.target !== PREDICATE_TARGET) return entry.target ?? "";
495
- const spec = entry.spec;
496
- const pred = spec.target;
497
- if (typeof pred !== "object" || pred === null) return PREDICATE_TARGET;
498
- return `${PREDICATE_TARGET}#${predicateId(pred)}`;
499
- }
500
- var PREDICATE_IDS = /* @__PURE__ */ new WeakMap();
501
- var nextPredicateId = 0;
502
- function predicateId(pred) {
503
- let id = PREDICATE_IDS.get(pred);
504
- if (id === void 0) {
505
- id = nextPredicateId++;
506
- PREDICATE_IDS.set(pred, id);
507
- }
508
- return id;
509
- }
510
- function actionAsTool(action) {
511
- return { id: action.id, eligibility: {}, bindings: actionBindings(action) };
512
- }
513
- function findScopedConflicts(scopes) {
514
- const registry = Array.isArray(scopes.registry) ? scopes.registry : Object.values(scopes.registry);
515
- const actions = scopes.actions ?? [];
516
- const ambientActions = actions.filter((a) => a.scope !== "hotkey").map(actionAsTool);
517
- const hotkeyActions = actions.filter((a) => a.scope === "hotkey").map(actionAsTool);
518
- const ambient = [...scopes.ambient ?? [], ...ambientActions];
519
- const out = [];
520
- const seen = /* @__PURE__ */ new Set();
521
- const add = (conflicts) => {
522
- for (const c of conflicts) {
523
- const key = `${c.phase}|${c.gesture}|${c.arg ?? ""}|${c.target ?? ""}|${canonicalModifiers(c.modifiers)}|${c.toolIds.join(",")}`;
524
- if (seen.has(key)) continue;
525
- seen.add(key);
526
- out.push(c);
527
- }
528
- };
529
- for (const tool of [...registry, ...scopes.ambient ?? []]) add(findConflicts([tool]));
530
- if (ambient.length > 1) add(findConflicts(ambient));
531
- const hotkey = [
532
- ...registry.filter((t) => t.def?.hotkey !== void 0),
533
- ...hotkeyActions
534
- ];
535
- if (hotkey.length > 1) add(findConflicts(hotkey));
536
- return out;
537
- }
538
- function formatConflict(conflict) {
539
- const route = formatRoute({
540
- phases: [{ channel: "&", phase: conflict.phase === "any" ? "*" : conflict.phase }],
541
- gesture: conflict.gesture,
542
- arg: conflict.arg,
543
- target: conflict.target,
544
- modifiers: conflict.modifiers
545
- });
546
- return `${route} \u2014 declared by ${conflict.toolIds.join(", ")}`;
547
- }
548
- function reportRouteConflicts(scopes, warn = (m) => console.warn(m)) {
549
- const conflicts = findScopedConflicts(scopes);
550
- for (const c of conflicts) {
551
- warn(
552
- `[weasel] route conflict: two bindings declare the same (phase, gesture, arg, target, modifiers) tuple in the same scope, so declaration order alone decides which one fires.
553
- ${formatConflict(c)}`
554
- );
555
- }
556
- return conflicts;
557
- }
558
-
559
- export { ActionDisabledReason, ActionsProvider, ActionsScope, DepRegistryProvider, PREDICATE_TARGET, actionBindings, buildDepsFromRequires, buildRouteRegistry, evaluateEnabled, findConflicts, reportRouteConflicts, routeGestureForSpecKind, routesForSpec, useAction, useActionsRegistry, useDepRegistry, useDepSource, useOptionalDepRegistry };
560
- //# sourceMappingURL=chunk-LEURURX3.js.map
561
- //# sourceMappingURL=chunk-LEURURX3.js.map