@weasel-js/routing 1.9.3 → 1.10.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/react.d.ts CHANGED
@@ -1,13 +1,26 @@
1
- export { D as DispatcherChannels, U as UseGestureDispatcherOptions, u as useGestureDispatcher } from './internal-B1B6gfOS.js';
1
+ import { U as UseGestureDispatcherOptions } from './internal-D0rDmi7t.js';
2
+ export { D as DispatcherChannels } from './internal-D0rDmi7t.js';
2
3
  import * as react from 'react';
3
4
  import { ReactNode, ReactElement } from 'react';
4
- import { D as DepRegistry, a as DepName, b as DepSchema, S as ScopeNode, A as ActionsRegistry, c as Action, d as DepNode, K as KernelOverlay, C as Contribution, e as AnyToolOf, O as OverlayPosition, f as ScopedBinding } from './index-CrbDNXT_.js';
5
+ import { D as DepRegistry, a as DepName, b as DepSchema, S as ScopeNode, A as ActionsRegistry, c as Action, d as DepNode, T as ToolNode, N as NodeId, K as KernelOverlay, C as Contribution, e as Tool, O as OverlayPosition } from './index-Bm2QEV09.js';
6
+ export { f as ActiveToolContextProvider, g as ActiveToolContextProviderIfRoot, h as ActiveToolContextProviderProps, i as ActiveToolContextValue, u as useActiveToolContext, j as useOptionalActiveToolContext } from './index-Bm2QEV09.js';
5
7
  import { ModeRegistry } from '@weasel-js/modes';
6
8
  import '@weasel-js/gestures';
7
9
  import '@weasel-js/cursor';
8
- import '@weasel-js/history';
10
+ import '@weasel-js/geom';
11
+ import '@weasel-js/registry';
9
12
  import '@weasel-js/select';
10
13
 
14
+ /**
15
+ * Attach the input pipeline to a canvas: DOM pointer, wheel, keyboard, and
16
+ * multitouch listeners in, normalized input events out, routed through the
17
+ * dispatcher to whichever action a binding names.
18
+ *
19
+ * The active tool and the dep registry come from context, so it must be
20
+ * mounted inside `<SceneCanvas>`'s providers.
21
+ */
22
+ declare function useGestureDispatcher(opts: UseGestureDispatcherOptions): void;
23
+
11
24
  /** Provides the dep registry for a canvas. `<SceneCanvas>` mounts one; a
12
25
  * consumer registering its own dep sources must be inside it. */
13
26
  declare function DepRegistryProvider({ children }: {
@@ -71,72 +84,9 @@ declare function useActionsRegistry(): ActionsRegistry | null;
71
84
  */
72
85
  declare function useAction(action: Action): void;
73
86
 
74
- /** Which tool is active, plus the stack of tools temporarily held active by a
75
- * hotkey (space-for-hand and the like). The dispatcher reads this to decide
76
- * whose bindings are in scope. */
77
- interface ActiveToolContextValue {
78
- /** The focused tool's id, or `null` when no tool holds the active slot —
79
- * a canvas can run on ambient bindings alone. */
80
- active: string | null;
81
- hotkeyStack: string[];
82
- setActive(id: string | null): void;
83
- pushHotkey(id: string): void;
84
- /**
85
- * Disengage a hotkey-held tool. With `id`, removes that tool's own entry
86
- * wherever it now sits — holds do not have to come up in the order they went
87
- * down, and popping the top would disengage a tool whose key is still held.
88
- * With no id, pops the top.
89
- */
90
- popHotkey(id?: string): void;
91
- }
92
- /**
93
- * One node of the tool tree. A node that `owns` a tool holds its state; one
94
- * that does not — a scope inside a yoke — reads and writes its yoke's.
95
- */
96
- declare class ToolNode extends ScopeNode<ToolNode> {
97
- private state;
98
- private value;
99
- constructor(parent: ToolNode | null, descends: boolean, owns: boolean, initialActive: string | null);
100
- /** The node whose tool a read here resolves to. */
101
- owner(): ToolNode;
102
- private update;
103
- /** A stable value per owner and state, for `useSyncExternalStore`. */
104
- snapshot(): ActiveToolContextValue;
105
- subscribe: (listener: () => void) => (() => void);
106
- }
107
- /** Props for `<ActiveToolContextProvider>`. */
108
- interface ActiveToolContextProviderProps {
109
- children: ReactNode;
110
- /** Seeds the active slot, and wins over the first `useTools` call's
111
- * `active`. Omitted, the slot starts empty and that call seeds it. */
112
- initialActive?: string | null;
113
- }
114
- /** Provides root active-tool state. Every canvas below has a tool of its own;
115
- * reads and writes here reach the one last used. */
116
- declare function ActiveToolContextProvider({ children, initialActive, }: ActiveToolContextProviderProps): react.JSX.Element;
117
- /** The active-tool state in scope. Throws outside a provider; use
118
- * `useOptionalActiveToolContext` where one is not guaranteed. */
119
- declare function useActiveToolContext(): ActiveToolContextValue;
120
- /**
121
- * Like `useActiveToolContext`, but returns `null` when no
122
- * `<ActiveToolContextProvider>` is in scope instead of throwing. Used by
123
- * `useStandardActions` to preserve its silent-no-op contract when no provider
124
- * is present.
125
- */
126
- declare function useOptionalActiveToolContext(): ActiveToolContextValue | null;
127
- /**
128
- * Conditional `<ActiveToolContextProvider>` wrapper. Mounts a provider only
129
- * when no parent provider is in scope — otherwise renders children unwrapped
130
- * so `<WeaselProvider>` defers to the host's existing scope.
131
- */
132
- declare function ActiveToolContextProviderIfRoot({ children, }: {
133
- children: ReactNode;
134
- }): react.JSX.Element;
135
-
136
87
  /**
137
88
  * @experimental
138
89
  * Input scopes and yokes: the tiers between a root registry and a canvas.
139
- * Design: docs/proposals/2026-09-27-input-scopes.md.
140
90
  */
141
91
 
142
92
  /** Props for `<InputScope>`. */
@@ -155,7 +105,9 @@ interface InputScopeProps {
155
105
  *
156
106
  * Chrome above calls `trigger` / `begin` / `useActiveToolContext` on its own
157
107
  * registries, and those reach the active scope: the one last activated — by a
158
- * pointerdown or wheel — or the newest where none has been.
108
+ * pointerdown or wheel — or the newest where none has been. Keys are stricter:
109
+ * one that reaches the page goes to the canvas last pressed or scrolled in,
110
+ * across every root on the page, and to none before the first.
159
111
  */
160
112
  declare function InputScope({ yoke, children }: InputScopeProps): ReactElement;
161
113
  /**
@@ -172,11 +124,10 @@ interface YokeProps {
172
124
  /**
173
125
  * @experimental
174
126
  * Canvases that share input on purpose: the active tool, the gesture in
175
- * flight, history and yoke-wide actions. Made once with `useYoke()` where the
176
- * sharing is decided, and passed to each canvas that joins it (`yoke={yoke}`)
177
- * and to `<Yoke value={yoke}>` around anything else that should reach it — a
178
- * toolbar, say. The members can sit anywhere in the tree: the handle, not the
179
- * tree, says who shares.
127
+ * flight, history, and yoke-wide actions. Made once with `useYoke()`, and
128
+ * passed to each canvas that joins it (`yoke={yoke}`) and to
129
+ * `<Yoke value={yoke}>` around anything else that should reach it — a
130
+ * toolbar, say. The members can sit anywhere in the tree.
180
131
  */
181
132
  interface Yoke {
182
133
  /** @internal */
@@ -206,6 +157,10 @@ declare function Yoke({ value, children }: YokeProps): ReactElement;
206
157
  * on its own — a click on a swatch, a switch of paint kind.
207
158
  * - `cancel()` ends an open edit without keeping it.
208
159
  *
160
+ * An edit the dispatcher ended first — a tool switch, Escape, another control
161
+ * committing the same action — counts as not open: the next `input` opens a
162
+ * new one.
163
+ *
209
164
  * All three are no-ops when no action is reachable, so a control renders the
210
165
  * same with or without a canvas in scope.
211
166
  */
@@ -223,6 +178,101 @@ interface OngoingAction {
223
178
  */
224
179
  declare function useOngoingAction(actionId: string): OngoingAction;
225
180
 
181
+ /** @experimental World-space pointer position and the view it is over — a
182
+ * view id, or `null` for a surface's own camera. `null` as a whole when the
183
+ * pointer is over no publishing surface. */
184
+ type PointerWorldPos = {
185
+ worldX: number;
186
+ worldY: number;
187
+ viewId: string | null;
188
+ } | null;
189
+ /** @experimental */
190
+ interface PointerContextValue {
191
+ /** The latest position. */
192
+ get(): PointerWorldPos;
193
+ /** Publish a position. Subscribers hear only a changed value. */
194
+ set(next: PointerWorldPos): void;
195
+ /** Called after every change; returns the unsubscribe. */
196
+ subscribe(fn: () => void): () => void;
197
+ /** Bumps on every change. */
198
+ getVersion(): number;
199
+ /** `get()` as a stable thunk, for hooks taking a drop-point option. */
200
+ readonly getDropPoint: () => PointerWorldPos;
201
+ }
202
+ /** @experimental A pointer store with no provider around it. */
203
+ declare function createPointerStore(): PointerContextValue;
204
+ /**
205
+ * @experimental
206
+ * Wrap the part of the React tree that should share one pointer.
207
+ * `<SceneCanvas>` mounts one when none is in scope, so mount it yourself only
208
+ * when two surfaces should share a pointer. Pass `store` to publish into one
209
+ * you hold elsewhere (`createPointerStore()`).
210
+ */
211
+ declare function PointerContextProvider({ children, store }: {
212
+ children: ReactNode;
213
+ store?: PointerContextValue;
214
+ }): ReactNode;
215
+ /** @experimental The surrounding pointer store, or `null` when no provider is
216
+ * in scope. */
217
+ declare function usePointerContext(): PointerContextValue | null;
218
+ /** @experimental The pointer, re-rendering the caller whenever it changes.
219
+ * `null` outside a provider. */
220
+ declare function usePointerPosition(): PointerWorldPos;
221
+
222
+ /**
223
+ * @experimental
224
+ * SelectionContext — an ambient context that publishes "what's currently
225
+ * selected" so non-canvas UI (command palette, status bar) can read it without
226
+ * threading a selection prop through the tree.
227
+ *
228
+ * **Single slot:** the context holds one selection array. Whichever publisher
229
+ * calls `publishSelection` most recently owns it, so a multi-canvas page gets
230
+ * last-writer-wins. `<SceneCanvas>` publishes automatically.
231
+ */
232
+
233
+ /** @experimental */
234
+ interface SelectionContextValue {
235
+ /** The most-recently-published selection. Empty array when no canvas
236
+ * has published or when the active canvas's selection is empty. */
237
+ readonly selection: readonly NodeId[];
238
+ /** Optional per-id kind label, parallel to `selection` (e.g. `'rectangle'`,
239
+ * `'path'`, `'group'`). Sparse entries (`undefined`) are allowed; treat it
240
+ * as best-effort. */
241
+ readonly kinds?: readonly (string | undefined)[];
242
+ /** Publish the calling canvas's selection. Calling with the same content
243
+ * does not re-render the consumer tree. */
244
+ publishSelection(ids: readonly NodeId[], kinds?: readonly (string | undefined)[]): void;
245
+ }
246
+ /**
247
+ * @experimental
248
+ * Wrap the part of the React tree that should share a selection context.
249
+ * Usually placed at the demo / app root, alongside `<ActionsProvider>`.
250
+ */
251
+ declare function SelectionContextProvider({ children }: {
252
+ children: ReactNode;
253
+ }): ReactNode;
254
+ /**
255
+ * @experimental
256
+ * The current selection-context value, or `null` when no
257
+ * `<SelectionContextProvider>` is in scope.
258
+ */
259
+ declare function useSelectionContext(): SelectionContextValue | null;
260
+ /**
261
+ * @experimental
262
+ * Mounts a `<SelectionContextProvider>` only when no parent provider is in
263
+ * scope; otherwise renders children unwrapped.
264
+ */
265
+ declare function SelectionContextProviderIfRoot({ children, }: {
266
+ children: ReactNode;
267
+ }): ReactNode;
268
+ /**
269
+ * @experimental
270
+ * Publishes `ids` into the surrounding `<SelectionContextProvider>` whenever
271
+ * their content changes, and clears the slot on unmount unless another
272
+ * publisher has written it since. No-op when there's no provider in scope.
273
+ */
274
+ declare function usePublishSelection(ids: readonly NodeId[], kinds?: readonly (string | undefined)[]): void;
275
+
226
276
  /** Options for `useTools`: which tools exist, which one starts active, and
227
277
  * which run continuously regardless of the active one. */
228
278
  interface UseToolsOptions<TOverlay = KernelOverlay> {
@@ -232,7 +282,7 @@ interface UseToolsOptions<TOverlay = KernelOverlay> {
232
282
  /** Tools eligible for the active slot or hotkey slot. The keys are the
233
283
  * tool ids; the values are the tool records. A tool with `hotkey` set
234
284
  * is wired into the hotkey slot whenever the engagement state matches. */
235
- registry: Record<string, AnyToolOf<TOverlay>>;
285
+ registry: Record<string, Tool<TOverlay>>;
236
286
  /** Always-on entries — tools or other contributions, live regardless of
237
287
  * the active slot. */
238
288
  ambient?: readonly Contribution<TOverlay>[];
@@ -248,8 +298,7 @@ interface ToolsApi<TOverlay = KernelOverlay> {
248
298
  /** Set the active-slot tool, or `null` to clear it. The gesture dispatcher
249
299
  * watches the active tool and cancels any in-flight handle itself. */
250
300
  setActive: (id: string | null) => void;
251
- /** Currently hotkey-engaged tool id (or `null`). Derived as the top of
252
- * the hotkey stack for backwards compat with the pre-stack API. */
301
+ /** Currently hotkey-engaged tool id (or `null`): the top of the hotkey stack. */
253
302
  hotkeyEngaged: string | null;
254
303
  /** Engage a hotkey-slot tool by id. */
255
304
  engageHotkey: (id: string) => void;
@@ -258,31 +307,24 @@ interface ToolsApi<TOverlay = KernelOverlay> {
258
307
  /** All always-on entries, in registration order. */
259
308
  ambient: readonly Contribution<TOverlay>[];
260
309
  /** Full registry — for userland UI (palette buttons, etc.). */
261
- registry: Readonly<Record<string, AnyToolOf<TOverlay>>>;
310
+ registry: Readonly<Record<string, Tool<TOverlay>>>;
262
311
  /** Returns true if a tool with the given id is in the registry or ambient list. */
263
312
  has(id: string): boolean;
264
- /** All overlay layers from currently-engaged tools (active slot, hotkey
265
- * slot if engaged, all ambient slot tools) that declare `position`.
266
- * Filters out tools with no `overlay` field. Order: active, then hotkey
267
- * (if engaged), then ambient (registration order). */
313
+ /** Overlay layers from currently-engaged tools that declare `position`.
314
+ * Order: active, then hotkey (if engaged), then ambient (registration order). */
268
315
  getActiveOverlays(position?: OverlayPosition): TOverlay[];
269
316
  }
270
317
  /**
271
- * Manages the active tool and hotkey slot.
272
- *
273
- * A thin shim over {@link useContributions}: the `registry` / `ambient`
274
- * arguments are restated as declared eligibility (`focus` / `always`), and
275
- * assembly happens in one place for tools and non-tool contributions alike.
318
+ * Manages the active tool and hotkey slot; a thin shim over
319
+ * {@link useContributions}.
276
320
  *
277
321
  * Requires `<ActiveToolContextProvider>` (or `<WeaselProvider>` /
278
322
  * `<SceneCanvas>`, which mount one internally) in scope: active/hotkey state
279
- * lives in the context so the gesture dispatcher and any sibling
280
- * `useTools` calls all read the same source of truth.
323
+ * lives in the context.
281
324
  *
282
- * **First-mount-wins semantics**: if the context's slot is unseeded (no
283
- * `initialActive`, nothing set yet) on first mount, `useTools` pushes
284
- * `opts.active` to the context. Subsequent mounts respect whatever the
285
- * context currently holds (the first caller wins).
325
+ * **First mount wins**: if the context's slot is unseeded on first mount,
326
+ * `useTools` pushes `opts.active` to the context. Subsequent mounts respect
327
+ * whatever the context currently holds.
286
328
  */
287
329
  declare function useTools<TOverlay = KernelOverlay>(opts: UseToolsOptions<TOverlay>): ToolsApi<TOverlay>;
288
330
 
@@ -294,9 +336,10 @@ interface UseContributionsOptions<TOverlay = KernelOverlay> {
294
336
  /** Desired focused entry id, or `null` for none. First-mount-wins against
295
337
  * the shared `ActiveToolContext` — see `useTools` for the full semantics. */
296
338
  focused: string | null;
297
- /** The modes the canvas can be in. The dev-time route-conflict check reads
298
- * them to decide whether two gated actions can ever compete; without a
299
- * registry it checks against the kit's `DEFAULT_MODES`. */
339
+ /** The modes the canvas can be in. The active one decides which tagged
340
+ * entries draw their overlays, and the dev-time route-conflict check reads
341
+ * them all to decide whether two gated actions can ever compete; without a
342
+ * registry nothing is barred and the check uses the kit's `DEFAULT_MODES`. */
300
343
  modes?: ModeRegistry;
301
344
  }
302
345
  /** The assembled registry {@link useContributions} returns. */
@@ -308,10 +351,9 @@ interface ContributionsApi<TOverlay = KernelOverlay> {
308
351
  /** Focus an entry, or pass `null` to focus none. Writes through to the
309
352
  * shared `ActiveToolContext`. */
310
353
  setFocused: (id: string | null) => void;
311
- /** Every live binding, tiered by the declaring entry's eligibility. */
312
- scopedBindings(): ScopedBinding[];
313
354
  /** Overlays of every live entry declaring `position`, ordered active, then
314
- * hotkey, then ambient. */
355
+ * hotkey, then ambient. Live is what the dispatcher routes to: an entry the
356
+ * active mode bars draws nothing. */
315
357
  overlays(position?: OverlayPosition): TOverlay[];
316
358
  }
317
359
  /**
@@ -334,4 +376,4 @@ declare function useContributions<TOverlay = KernelOverlay>(opts: UseContributio
334
376
  */
335
377
  declare function useOffhandAction(entries: readonly Contribution<unknown>[]): void;
336
378
 
337
- export { ActionsProvider, ActiveToolContextProvider, ActiveToolContextProviderIfRoot, type ActiveToolContextProviderProps, type ActiveToolContextValue, type ContributionsApi, DepRegistry, DepRegistryProvider, InputScope, type InputScopeProps, type OngoingAction, type ToolsApi, type UseContributionsOptions, type UseToolsOptions, Yoke, type YokeProps, useAction, useActionsRegistry, useActiveToolContext, useContributions, useDepRegistry, useDepSource, useOffhandAction, useOngoingAction, useOptionalActiveToolContext, useOptionalDepRegistry, useTools, useYoke };
379
+ export { ActionsProvider, type ContributionsApi, DepRegistry, DepRegistryProvider, InputScope, type InputScopeProps, type OngoingAction, PointerContextProvider, type PointerContextValue, type PointerWorldPos, SelectionContextProvider, SelectionContextProviderIfRoot, type SelectionContextValue, type ToolsApi, type UseContributionsOptions, UseGestureDispatcherOptions, type UseToolsOptions, Yoke, type YokeProps, createPointerStore, useAction, useActionsRegistry, useContributions, useDepRegistry, useDepSource, useGestureDispatcher, useOffhandAction, useOngoingAction, useOptionalDepRegistry, usePointerContext, usePointerPosition, usePublishSelection, useSelectionContext, useTools, useYoke };