@weasel-js/core 1.0.1 → 1.0.3
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/CHANGELOG.md +330 -0
- package/dist/{DrawCommand-DCmiNkBj.d.ts → DrawCommand-BbPrSTra.d.ts} +24 -0
- package/dist/{chunk-Z3KNFTTS.js → chunk-3JYFAQIB.js} +3 -3
- package/dist/chunk-3JYFAQIB.js.map +1 -0
- package/dist/{chunk-UB6A6L77.js → chunk-3KGMJMOS.js} +3 -3
- package/dist/{chunk-UB6A6L77.js.map → chunk-3KGMJMOS.js.map} +1 -1
- package/dist/{chunk-IO5Z75X4.js → chunk-HGF5X6MZ.js} +2 -2
- package/dist/chunk-HGF5X6MZ.js.map +1 -0
- package/dist/{chunk-775XXAHR.js → chunk-JOSUVS6C.js} +2 -2
- package/dist/{chunk-775XXAHR.js.map → chunk-JOSUVS6C.js.map} +1 -1
- package/dist/{chunk-FVNWK7U3.js → chunk-SMCZRSYB.js} +1677 -1371
- package/dist/chunk-SMCZRSYB.js.map +1 -0
- package/dist/{chunk-DCIU3SRK.js → chunk-TR3HZN34.js} +79 -151
- package/dist/chunk-TR3HZN34.js.map +1 -0
- package/dist/{chunk-6SHZHXXR.js → chunk-U45SODC2.js} +2 -2
- package/dist/{chunk-6SHZHXXR.js.map → chunk-U45SODC2.js.map} +1 -1
- package/dist/clipboard.d.ts +5 -2
- package/dist/clipboard.js +1 -2
- package/dist/clone.d.ts +2 -2
- package/dist/clone.js +0 -1
- package/dist/{geometry-DVeZ2i-c.d.ts → geometry-5X6TrAkX.d.ts} +1 -1
- package/dist/{grid-XcFQVS0f.d.ts → grid-sfilv5HP.d.ts} +7 -2
- package/dist/index.d.ts +695 -49
- package/dist/index.js +7 -8
- package/dist/insert.d.ts +6 -3
- package/dist/insert.js +1 -2
- package/dist/insert.js.map +1 -1
- package/dist/move.d.ts +26 -5
- package/dist/move.js +2 -3
- package/dist/move.js.map +1 -1
- package/dist/{options-wAvCnOZd.d.ts → options-CbsIgQci.d.ts} +3 -1
- package/dist/patterns-builtin.d.ts +8 -0
- package/dist/patterns-builtin.js +1 -2
- package/dist/{pointSnapToGrid-BuDZWBrL.d.ts → pointSnapToGrid-C3wowsQy.d.ts} +9 -3
- package/dist/{index-DPI8DV0A.d.ts → registry-CxnkXbG8.d.ts} +225 -350
- package/dist/renderer.d.ts +36 -4
- package/dist/renderer.js +7 -8
- package/dist/resize.d.ts +12 -5
- package/dist/resize.js +2 -3
- package/dist/routing.d.ts +106 -7
- package/dist/routing.js +1 -2
- package/dist/{types-BJ8_cyT7.d.ts → types-BHK2dkMu.d.ts} +43 -1
- package/dist/{types-BhJJ2OCM.d.ts → types-ByZxoD6P.d.ts} +1 -1
- package/dist/{types-B_-khFM0.d.ts → types-DpQ0cWYC.d.ts} +32 -0
- package/dist/{types-Kh_osAq9.d.ts → types-vqxpCFVp.d.ts} +31 -0
- package/dist/{viewToMat3-BvaWCN99.d.ts → viewToMat3-CQW_YqDw.d.ts} +1 -1
- package/package.json +6 -6
- package/dist/chunk-DCIU3SRK.js.map +0 -1
- package/dist/chunk-FVNWK7U3.js.map +0 -1
- package/dist/chunk-IO5Z75X4.js.map +0 -1
- package/dist/chunk-PZ5AY32C.js +0 -9
- package/dist/chunk-PZ5AY32C.js.map +0 -1
- package/dist/chunk-Z3KNFTTS.js.map +0 -1
package/dist/renderer.d.ts
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import { I as ImageMinification, G as GLImageCache } from './viewToMat3-
|
|
2
|
-
export { V as ViewLike, v as viewToMat3 } from './viewToMat3-
|
|
1
|
+
import { I as ImageMinification, G as GLImageCache } from './viewToMat3-CQW_YqDw.js';
|
|
2
|
+
export { V as ViewLike, v as viewToMat3 } from './viewToMat3-CQW_YqDw.js';
|
|
3
3
|
import { G as GradStop, S as Stroke } from './paint-types-CnLIzqq1.js';
|
|
4
4
|
export { a as TextureHandle, r as registerTexture } from './paint-types-CnLIzqq1.js';
|
|
5
|
-
import { M as Mat3, S as ShaderProgramHandle, D as DrawCommand } from './DrawCommand-
|
|
6
|
-
export { G as GroupDrawCommand, I as ImageDrawCommand, P as PathDrawCommand, a as ShaderDrawCommand, b as ShaderUniform, c as SolidPaint, T as TextDrawCommand, m as mat3, r as registerProgram } from './DrawCommand-
|
|
5
|
+
import { M as Mat3, S as ShaderProgramHandle, D as DrawCommand } from './DrawCommand-BbPrSTra.js';
|
|
6
|
+
export { G as GroupDrawCommand, I as ImageDrawCommand, P as PathDrawCommand, a as ShaderDrawCommand, b as ShaderUniform, c as SolidPaint, T as TextDrawCommand, m as mat3, r as registerProgram } from './DrawCommand-BbPrSTra.js';
|
|
7
7
|
import { P as Path } from './path-B6MMiodD.js';
|
|
8
8
|
export { canQueryLocalFonts, enableLocalFontOutlines, hasFontOutlines, isCanvasFont, listFontOutlines, outlineStatus, registerCanvasFont, registerFont, registerFontOutlines, subscribeGlyphReady, unregisterCanvasFont, unregisterFontOutlines } from '@weasel-js/font';
|
|
9
9
|
|
|
@@ -16,6 +16,8 @@ export { canQueryLocalFonts, enableLocalFontOutlines, hasFontOutlines, isCanvasF
|
|
|
16
16
|
* via the recorder Proxy without further special-casing.
|
|
17
17
|
*/
|
|
18
18
|
type Stage = 'vertex' | 'fragment' | 'link';
|
|
19
|
+
/** Thrown when a shader fails to compile or link, carrying which stage failed
|
|
20
|
+
* and the driver's log. */
|
|
19
21
|
declare class ShaderCompileError extends Error {
|
|
20
22
|
readonly stage: Stage;
|
|
21
23
|
readonly log: string;
|
|
@@ -109,6 +111,8 @@ declare class GLMeshCache {
|
|
|
109
111
|
private readonly gl;
|
|
110
112
|
private readonly aPositionLoc;
|
|
111
113
|
private readonly map;
|
|
114
|
+
/** Meshes this context has drawn at least once; see `uploadRecurring`. */
|
|
115
|
+
private readonly seen;
|
|
112
116
|
private readonly finalizer;
|
|
113
117
|
private readonly pendingDeletes;
|
|
114
118
|
/** Transient resources allocated this frame; freed at end of render(). */
|
|
@@ -123,6 +127,15 @@ declare class GLMeshCache {
|
|
|
123
127
|
* and the FinalizationRegistry, so transient meshes never wait on GC.
|
|
124
128
|
*/
|
|
125
129
|
uploadTransient(mesh: Mesh): GLMeshHandle;
|
|
130
|
+
/**
|
|
131
|
+
* Upload a Mesh that may or may not recur across frames. Its first sight in
|
|
132
|
+
* *this* context takes `uploadTransient`; every later one takes the
|
|
133
|
+
* persistent handle. One transient upload to find out is cheaper than
|
|
134
|
+
* stranding a persistent VAO on a mesh that never returns, whose release
|
|
135
|
+
* would wait on GC. The transient upload does not populate the persistent
|
|
136
|
+
* map, so steady-state reuse begins on the third frame.
|
|
137
|
+
*/
|
|
138
|
+
uploadRecurring(mesh: Mesh): GLMeshHandle;
|
|
126
139
|
/**
|
|
127
140
|
* Free all transient resources allocated since the last call. Called by
|
|
128
141
|
* the renderer at the end of each `render()`. Safe under context loss.
|
|
@@ -192,6 +205,8 @@ declare class GLTextureCache {
|
|
|
192
205
|
* shader applies premultiplication before writing outColor.
|
|
193
206
|
*/
|
|
194
207
|
|
|
208
|
+
/** Bake gradient stops into a 256-entry RGBA lookup strip, which the shader
|
|
209
|
+
* samples instead of evaluating stops per fragment. */
|
|
195
210
|
declare function buildGradientRamp(stops: GradStop[]): Uint8ClampedArray;
|
|
196
211
|
declare class GradientRampCache {
|
|
197
212
|
private readonly gl;
|
|
@@ -283,6 +298,9 @@ declare class SolidBatch {
|
|
|
283
298
|
private growGpu;
|
|
284
299
|
}
|
|
285
300
|
|
|
301
|
+
/** How to construct a `WeaselRenderer`: the GL context or canvas to draw
|
|
302
|
+
* into, the output size, and the quality knobs that separate screen
|
|
303
|
+
* rendering from print. */
|
|
286
304
|
interface WeaselRendererOptions {
|
|
287
305
|
gl?: WebGL2RenderingContext;
|
|
288
306
|
canvas?: HTMLCanvasElement;
|
|
@@ -315,6 +333,14 @@ interface WeaselRendererOptions {
|
|
|
315
333
|
* print has no reason to sample a field it could evaluate exactly). */
|
|
316
334
|
textOutlineMinScreenSize?: number;
|
|
317
335
|
}
|
|
336
|
+
/**
|
|
337
|
+
* The WebGL2 renderer: takes a list of draw commands and paints them.
|
|
338
|
+
*
|
|
339
|
+
* It knows nothing about the scene — commands are the whole interface, which
|
|
340
|
+
* is what lets layers, HUD widgets and overlays all draw through the same
|
|
341
|
+
* pipeline. GPU resources (meshes, textures, gradient ramps) are cached across
|
|
342
|
+
* frames and keyed by identity, so re-issuing the same command is cheap.
|
|
343
|
+
*/
|
|
318
344
|
declare class WeaselRenderer {
|
|
319
345
|
private readonly gl;
|
|
320
346
|
private pathFill;
|
|
@@ -422,12 +448,18 @@ declare class WeaselRenderer {
|
|
|
422
448
|
/** @internal */ _dpr(): number;
|
|
423
449
|
}
|
|
424
450
|
|
|
451
|
+
/** Options for `tessellate`. A smaller tolerance means more triangles and
|
|
452
|
+
* smoother curves; it is in path-local units, so callers rendering at a
|
|
453
|
+
* larger scale should tighten it. */
|
|
425
454
|
interface TessellateOptions {
|
|
426
455
|
/** Flatness tolerance for bezier subdivision in path-local units. */
|
|
427
456
|
flattenTolerance?: number;
|
|
428
457
|
}
|
|
458
|
+
/** Turn a path into a triangle mesh the renderer can draw: curves flattened to
|
|
459
|
+
* line segments, then the resulting polygon triangulated. */
|
|
429
460
|
declare function tessellate(path: Path, opts?: TessellateOptions): Mesh;
|
|
430
461
|
|
|
462
|
+
/** Options for stroke tessellation. */
|
|
431
463
|
interface StrokeOptions {
|
|
432
464
|
flattenTolerance?: number;
|
|
433
465
|
}
|
package/dist/renderer.js
CHANGED
|
@@ -1,13 +1,12 @@
|
|
|
1
|
-
export { IDENTITY_COLOR_MATRIX, OUTLINE_MIN_SCREEN_PX, ShaderCompileError, WeaselRenderer, buildGradientRamp, canQueryLocalFonts, enableLocalFontOutlines, hasFontOutlines, isCanvasFont, listFontOutlines, mat3, outlineStatus, registerCanvasFont, registerFont, registerFontOutlines, registerProgram, subscribeGlyphReady, tessellate, tessellateStroke, unregisterCanvasFont, unregisterFontOutlines, viewToMat3 } from './chunk-
|
|
2
|
-
import './chunk-
|
|
3
|
-
import './chunk-
|
|
4
|
-
import './chunk-
|
|
5
|
-
import './chunk-
|
|
6
|
-
import './chunk-
|
|
1
|
+
export { IDENTITY_COLOR_MATRIX, OUTLINE_MIN_SCREEN_PX, ShaderCompileError, WeaselRenderer, buildGradientRamp, canQueryLocalFonts, enableLocalFontOutlines, hasFontOutlines, isCanvasFont, listFontOutlines, mat3, outlineStatus, registerCanvasFont, registerFont, registerFontOutlines, registerProgram, subscribeGlyphReady, tessellate, tessellateStroke, unregisterCanvasFont, unregisterFontOutlines, viewToMat3 } from './chunk-SMCZRSYB.js';
|
|
2
|
+
import './chunk-TR3HZN34.js';
|
|
3
|
+
import './chunk-3KGMJMOS.js';
|
|
4
|
+
import './chunk-3JYFAQIB.js';
|
|
5
|
+
import './chunk-U45SODC2.js';
|
|
6
|
+
import './chunk-JOSUVS6C.js';
|
|
7
7
|
import './chunk-UGFFCMQP.js';
|
|
8
8
|
import './chunk-BHVYVFGV.js';
|
|
9
9
|
import './chunk-GVCNT7UH.js';
|
|
10
|
-
export { registerTexture } from './chunk-
|
|
11
|
-
import './chunk-PZ5AY32C.js';
|
|
10
|
+
export { registerTexture } from './chunk-HGF5X6MZ.js';
|
|
12
11
|
//# sourceMappingURL=renderer.js.map
|
|
13
12
|
//# sourceMappingURL=renderer.js.map
|
package/dist/resize.d.ts
CHANGED
|
@@ -1,12 +1,15 @@
|
|
|
1
|
-
export { C as CORNER_ANCHORS, a as CornerAnchor, b as CornerHandle, U as UseResizeOptions, c as cornerPoint, d as cornerResizeHandles, f as fixedCornerOf, h as hitCornerHandle, p as pointSnapToGrid } from './pointSnapToGrid-
|
|
2
|
-
export { P as PoseProjection, R as RECT_POSE_DESCRIPTOR, a as ROTATED_POSE_DESCRIPTOR } from './geometry-
|
|
3
|
-
import { R as ResizePose, B as BoundsConstraint, M as ModifierState } from './types-
|
|
1
|
+
export { C as CORNER_ANCHORS, a as CornerAnchor, b as CornerHandle, U as UseResizeOptions, c as cornerPoint, d as cornerResizeHandles, f as fixedCornerOf, h as hitCornerHandle, p as pointSnapToGrid } from './pointSnapToGrid-C3wowsQy.js';
|
|
2
|
+
export { P as PoseProjection, R as RECT_POSE_DESCRIPTOR, a as ROTATED_POSE_DESCRIPTOR } from './geometry-5X6TrAkX.js';
|
|
3
|
+
import { R as ResizePose, B as BoundsConstraint, M as ModifierState } from './types-ByZxoD6P.js';
|
|
4
4
|
import { G as Guide } from './types-D2tTKEU0.js';
|
|
5
5
|
import { V as View } from './view-DSQgxBJB.js';
|
|
6
|
-
import './types-
|
|
6
|
+
import './types-BHK2dkMu.js';
|
|
7
7
|
import '@weasel-js/history';
|
|
8
|
-
import './types-
|
|
8
|
+
import './types-DpQ0cWYC.js';
|
|
9
9
|
|
|
10
|
+
/** Resize constraint that stops a node shrinking past a minimum. The anchored
|
|
11
|
+
* edge stays put, so clamping pushes the dragged edge back rather than moving
|
|
12
|
+
* the node. */
|
|
10
13
|
declare function clampMinSize<TPose extends ResizePose>(args: {
|
|
11
14
|
minWidth: number;
|
|
12
15
|
minHeight: number;
|
|
@@ -39,6 +42,10 @@ declare function lockAspectWithModifier<TPose extends ResizePose>(opts?: {
|
|
|
39
42
|
}): BoundsConstraint<TPose>;
|
|
40
43
|
|
|
41
44
|
type ModKey$1 = keyof ModifierState;
|
|
45
|
+
/** Resize constraint that snaps the moving edges to a grid, leaving the
|
|
46
|
+
* anchored ones where they are. By default a node already smaller than one
|
|
47
|
+
* grid cell on an axis is left unsnapped on that axis, so it stays resizable
|
|
48
|
+
* at sub-grid sizes. */
|
|
42
49
|
declare function snapToGrid<TPose extends ResizePose>(args: {
|
|
43
50
|
spacing: number;
|
|
44
51
|
bypassKey?: ModKey$1;
|
package/dist/resize.js
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
export { CORNER_ANCHORS, DEFAULT_RESIZE_BEHAVIORS, clampMinSize, cornerPoint, cornerResizeHandles, fixedCornerOf, hitCornerHandle, lockAspectWithModifier, pointSnapToGrid, snapToGrid, snapToGuides } from './chunk-
|
|
2
|
-
export { RECT_POSE_DESCRIPTOR, ROTATED_POSE_DESCRIPTOR } from './chunk-
|
|
3
|
-
import './chunk-PZ5AY32C.js';
|
|
1
|
+
export { CORNER_ANCHORS, DEFAULT_RESIZE_BEHAVIORS, clampMinSize, cornerPoint, cornerResizeHandles, fixedCornerOf, hitCornerHandle, lockAspectWithModifier, pointSnapToGrid, snapToGrid, snapToGuides } from './chunk-3JYFAQIB.js';
|
|
2
|
+
export { RECT_POSE_DESCRIPTOR, ROTATED_POSE_DESCRIPTOR } from './chunk-U45SODC2.js';
|
|
4
3
|
//# sourceMappingURL=resize.js.map
|
|
5
4
|
//# sourceMappingURL=resize.js.map
|
package/dist/routing.d.ts
CHANGED
|
@@ -1,16 +1,115 @@
|
|
|
1
|
-
|
|
1
|
+
import { ParsedModifiers, GestureName, GestureSpec } from '@weasel-js/gestures';
|
|
2
2
|
export { ChannelRef, DescribeRouteOptions, GESTURE_DESCRIPTORS, GestureArgSpec, GestureDescriptor, GestureName, ModRequirement, ModifierKey, ParsedModifiers, ParsedRoute, PhaseAtom, RESERVED_ID_NAMES, RESERVED_ID_PREFIXES, ROUTE_FIELD_DEFINITIONS, ROUTE_TERMS, RouteDescriptionPart, RouteFieldName, RouteTermLabel, canonicalModifiers, collapseShiftPairs, describeRoute, describeRouteParts, formatPhaseAtom, formatRoute, getGestureDescriptor, isKnownGestureName, parseRoute } from '@weasel-js/gestures';
|
|
3
|
-
import './
|
|
3
|
+
import { T as Tool } from './registry-CxnkXbG8.js';
|
|
4
|
+
import './types-vqxpCFVp.js';
|
|
4
5
|
import '@weasel-js/history';
|
|
5
6
|
import './path-B6MMiodD.js';
|
|
6
|
-
import './types-
|
|
7
|
-
import './types-
|
|
7
|
+
import './types-ByZxoD6P.js';
|
|
8
|
+
import './types-DpQ0cWYC.js';
|
|
8
9
|
import './view-DSQgxBJB.js';
|
|
9
10
|
import '@weasel-js/modes';
|
|
10
11
|
import 'react';
|
|
11
|
-
import './geometry-
|
|
12
|
+
import './geometry-5X6TrAkX.js';
|
|
12
13
|
import './paint-types-CnLIzqq1.js';
|
|
13
|
-
import './DrawCommand-
|
|
14
|
+
import './DrawCommand-BbPrSTra.js';
|
|
14
15
|
import 'react/jsx-runtime';
|
|
16
|
+
import './types-BHK2dkMu.js';
|
|
15
17
|
import '@weasel-js/geom';
|
|
16
|
-
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* One row in the route registry — a single `GestureBinding` on one tool,
|
|
21
|
+
* flattened into the route grammar's vocabulary so the inspector, the
|
|
22
|
+
* conflict checker, and `describeRoute` can all read the same shape.
|
|
23
|
+
*
|
|
24
|
+
* Multiple rows can share (gesture, arg, target, modifiers) if different tools
|
|
25
|
+
* declare them; consumers walk the list and group client-side.
|
|
26
|
+
*/
|
|
27
|
+
interface RegistryEntry {
|
|
28
|
+
toolId: string;
|
|
29
|
+
/** Which phase the binding's `phase` spec restricts it to. `'any'` when it
|
|
30
|
+
* declares none, declares `'*'`, or declares an atom list whose atoms
|
|
31
|
+
* don't agree on one phase — such a binding fires in either phase, and
|
|
32
|
+
* reporting it as `'initial'` made it collide with genuinely-initial
|
|
33
|
+
* bindings in `findConflicts`' bucket key. */
|
|
34
|
+
phase: 'initial' | 'engaged' | 'any';
|
|
35
|
+
/** Structured v3 modifier requirements. Empty object = "no modifiers
|
|
36
|
+
* held" (the strict default). */
|
|
37
|
+
modifiers: ParsedModifiers;
|
|
38
|
+
gesture: GestureName;
|
|
39
|
+
/** Resolved arg value for arg-bearing gestures (wheel direction,
|
|
40
|
+
* key name, multiTouchTap fingers). Undefined for gestures whose
|
|
41
|
+
* descriptor has no `arg`. */
|
|
42
|
+
arg: string | undefined;
|
|
43
|
+
/** Target class for hit-testing gestures. `undefined` when the descriptor
|
|
44
|
+
* has `hasTarget: false` or the spec declares no target;
|
|
45
|
+
* {@link PREDICATE_TARGET} when the spec uses a `kindOf` predicate, which
|
|
46
|
+
* the route grammar has no notation for. */
|
|
47
|
+
target: string | undefined;
|
|
48
|
+
/** The action this binding fires. */
|
|
49
|
+
actionId: string;
|
|
50
|
+
/** The `GestureSpec` this row was flattened from, by reference. Reflection
|
|
51
|
+
* consumers that need something the grammar doesn't capture — the
|
|
52
|
+
* specificity tuple, a `kindOf` predicate identity — read it here rather
|
|
53
|
+
* than re-walking `Tool.bindings`. */
|
|
54
|
+
spec: GestureSpec;
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Flatten every tool's `bindings` into route-registry rows.
|
|
58
|
+
*
|
|
59
|
+
* This was `buildActionRegistry`, and it walked `ToolDef.initial` /
|
|
60
|
+
* `.engaged` phase tables — the grammar that no longer exists. It was also
|
|
61
|
+
* blind to `Tool.bindings` the entire time the two lived side by side, which
|
|
62
|
+
* is why the inspector under-reported select by more than half. The rename
|
|
63
|
+
* fixes a second thing: it never had anything to do with the Actions
|
|
64
|
+
* Registry, and reading `buildActionRegistry` next to `ActionsRegistry`
|
|
65
|
+
* suggested otherwise.
|
|
66
|
+
*/
|
|
67
|
+
declare function buildRouteRegistry(tools: readonly Tool<unknown>[]): RegistryEntry[];
|
|
68
|
+
|
|
69
|
+
/** Two or more tools declare the same exact (phase, gesture, arg, target,
|
|
70
|
+
* modifiers) tuple — the dispatcher's slot precedence picks one
|
|
71
|
+
* arbitrarily (well, deterministically by slot order, but the author
|
|
72
|
+
* probably didn't intend the duplication). */
|
|
73
|
+
interface Conflict {
|
|
74
|
+
phase: 'initial' | 'engaged' | 'any';
|
|
75
|
+
gesture: GestureName;
|
|
76
|
+
arg: string | undefined;
|
|
77
|
+
target: string | undefined;
|
|
78
|
+
modifiers: ParsedModifiers;
|
|
79
|
+
/** All tool ids that registered the same tuple. At least 2 by
|
|
80
|
+
* construction. Order matches the input tools[] order. */
|
|
81
|
+
toolIds: string[];
|
|
82
|
+
}
|
|
83
|
+
/** Detect exact-tuple overlaps across a tool registration set.
|
|
84
|
+
*
|
|
85
|
+
* Intentionally NOT flagged:
|
|
86
|
+
* - Broad vs. narrow targets (e.g. an untargeted `click` alongside
|
|
87
|
+
* `click` on `empty`) — the dispatcher's specificity ordering resolves
|
|
88
|
+
* those cleanly, and the broad one is usually the intended fallback.
|
|
89
|
+
* - Different modifier requirements on the same target — they fire on
|
|
90
|
+
* different inputs.
|
|
91
|
+
* - A binding whose action declines via `enabled()` so a lower-priority
|
|
92
|
+
* one can take the gesture. Detecting that intent would mean evaluating
|
|
93
|
+
* the action; consumers can suppress known-intentional compositions in
|
|
94
|
+
* their UI layer.
|
|
95
|
+
*
|
|
96
|
+
* - Two `{ kindOf }` predicate targets. The route grammar renders every
|
|
97
|
+
* predicate as the single token {@link PREDICATE_TARGET}, so bucketing on
|
|
98
|
+
* the rendered target alone reported select's `resize` / `rotate` / `move`
|
|
99
|
+
* drags — three genuinely different predicates — as a three-way conflict.
|
|
100
|
+
* Predicate entries bucket by function identity instead, which means two
|
|
101
|
+
* *separately written but equivalent* predicates go unflagged. That's the
|
|
102
|
+
* right way to be wrong here: this check has to be silent when nothing is
|
|
103
|
+
* wrong or nobody will keep it on.
|
|
104
|
+
*
|
|
105
|
+
* Note that two bindings sharing a tuple on the SAME tool are now possible
|
|
106
|
+
* (bindings are an array, where phase tables were objects with unique
|
|
107
|
+
* keys) — so a conflict may name one tool twice.
|
|
108
|
+
*
|
|
109
|
+
* This is the raw same-tuple detector. Feeding it a whole tool *registry*
|
|
110
|
+
* over-reports, because registry tools take turns in the active slot and
|
|
111
|
+
* can't collide with each other — see {@link findScopedConflicts}.
|
|
112
|
+
*/
|
|
113
|
+
declare function findConflicts(tools: readonly Tool<unknown>[]): Conflict[];
|
|
114
|
+
|
|
115
|
+
export { type Conflict, type RegistryEntry, buildRouteRegistry, findConflicts };
|
package/dist/routing.js
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
export { GESTURE_DESCRIPTORS,
|
|
2
|
-
import './chunk-PZ5AY32C.js';
|
|
1
|
+
export { GESTURE_DESCRIPTORS, RESERVED_ID_NAMES, RESERVED_ID_PREFIXES, ROUTE_FIELD_DEFINITIONS, ROUTE_TERMS, buildRouteRegistry, canonicalModifiers, collapseShiftPairs, describeRoute, describeRouteParts, findConflicts, formatPhaseAtom, formatRoute, getGestureDescriptor, isKnownGestureName, parseRoute } from './chunk-TR3HZN34.js';
|
|
3
2
|
//# sourceMappingURL=routing.js.map
|
|
4
3
|
//# sourceMappingURL=routing.js.map
|
|
@@ -16,8 +16,14 @@ interface DebugConfig {
|
|
|
16
16
|
fps?: boolean;
|
|
17
17
|
/** Optional per-feature color overrides; falls back to the default theme. */
|
|
18
18
|
theme?: Partial<DebugTheme>;
|
|
19
|
+
/** Optional per-feature line-width / dash overrides; falls back to
|
|
20
|
+
* {@link DEFAULT_DEBUG_STROKES}. */
|
|
21
|
+
strokes?: Partial<DebugStrokes>;
|
|
19
22
|
}
|
|
23
|
+
/** The name of one debug-overlay feature — the keys of {@link DebugConfig}
|
|
24
|
+
* that toggle a visualization. */
|
|
20
25
|
type DebugFeature = 'hitboxes' | 'handles' | 'bounds' | 'origins' | 'snap' | 'layers' | 'ids' | 'fps';
|
|
26
|
+
/** Colors the debug overlay draws with, one entry per feature. */
|
|
21
27
|
interface DebugTheme {
|
|
22
28
|
hitboxFill: string;
|
|
23
29
|
hitboxStroke: string;
|
|
@@ -33,7 +39,26 @@ interface DebugTheme {
|
|
|
33
39
|
fpsText: string;
|
|
34
40
|
fpsTextBg: string;
|
|
35
41
|
}
|
|
42
|
+
/** Line width and dash pattern for one stroked debug feature. An empty (or
|
|
43
|
+
* omitted) `dash` is a solid line. */
|
|
44
|
+
interface DebugStroke {
|
|
45
|
+
width: number;
|
|
46
|
+
dash?: readonly number[];
|
|
47
|
+
}
|
|
48
|
+
/** The stroked half of the debug overlay's appearance, split from
|
|
49
|
+
* {@link DebugTheme} because only some features draw a line at all — text
|
|
50
|
+
* panels and filled origin dots take color and nothing else. */
|
|
51
|
+
interface DebugStrokes {
|
|
52
|
+
hitbox: DebugStroke;
|
|
53
|
+
bounds: DebugStroke;
|
|
54
|
+
handle: DebugStroke;
|
|
55
|
+
/** Rejected snap candidates only; accepted ones paint as a filled dot. */
|
|
56
|
+
snap: DebugStroke;
|
|
57
|
+
}
|
|
58
|
+
/** Which kind of handle a recorded handle marker represents. */
|
|
36
59
|
type HandleKind = 'corner' | 'rotation' | 'anchor';
|
|
60
|
+
/** The geometry a hit region actually tests against, as reported to the debug
|
|
61
|
+
* sink so the overlay can draw the real shape rather than its bounding box. */
|
|
37
62
|
type HitShape = {
|
|
38
63
|
kind: 'rect';
|
|
39
64
|
x: number;
|
|
@@ -50,11 +75,13 @@ type HitShape = {
|
|
|
50
75
|
kind: 'path';
|
|
51
76
|
d: Path2D;
|
|
52
77
|
};
|
|
78
|
+
/** A hit region tested during the current frame. */
|
|
53
79
|
interface RecordedHitbox {
|
|
54
80
|
id: string;
|
|
55
81
|
kind: 'body' | 'handle' | 'rotation' | 'anchor';
|
|
56
82
|
shape: HitShape;
|
|
57
83
|
}
|
|
84
|
+
/** A handle drawn during the current frame, and where. */
|
|
58
85
|
interface RecordedHandle {
|
|
59
86
|
id: string;
|
|
60
87
|
position: {
|
|
@@ -63,6 +90,7 @@ interface RecordedHandle {
|
|
|
63
90
|
};
|
|
64
91
|
kind: HandleKind;
|
|
65
92
|
}
|
|
93
|
+
/** A node's bounds as computed during the current frame. */
|
|
66
94
|
interface RecordedBounds {
|
|
67
95
|
id: string;
|
|
68
96
|
bounds: {
|
|
@@ -72,6 +100,7 @@ interface RecordedBounds {
|
|
|
72
100
|
height: number;
|
|
73
101
|
};
|
|
74
102
|
}
|
|
103
|
+
/** A node's transform origin as used during the current frame. */
|
|
75
104
|
interface RecordedOrigin {
|
|
76
105
|
id: string;
|
|
77
106
|
point: {
|
|
@@ -79,6 +108,9 @@ interface RecordedOrigin {
|
|
|
79
108
|
y: number;
|
|
80
109
|
};
|
|
81
110
|
}
|
|
111
|
+
/** A snap candidate considered during the current gesture, and whether it
|
|
112
|
+
* won. Unlike the other records these survive across frames, until the
|
|
113
|
+
* gesture ends. */
|
|
82
114
|
interface RecordedSnap {
|
|
83
115
|
point: {
|
|
84
116
|
x: number;
|
|
@@ -86,12 +118,14 @@ interface RecordedSnap {
|
|
|
86
118
|
};
|
|
87
119
|
accepted: boolean;
|
|
88
120
|
}
|
|
121
|
+
/** A render layer that drew during the current frame. */
|
|
89
122
|
interface RecordedLayer {
|
|
90
123
|
id: string;
|
|
91
124
|
label: string;
|
|
92
125
|
space: 'world' | 'screen';
|
|
93
126
|
index: number;
|
|
94
127
|
}
|
|
128
|
+
/** Everything the sink collected, ready for the overlay to draw. */
|
|
95
129
|
interface DebugSnapshot {
|
|
96
130
|
hitboxes: RecordedHitbox[];
|
|
97
131
|
handles: RecordedHandle[];
|
|
@@ -100,6 +134,14 @@ interface DebugSnapshot {
|
|
|
100
134
|
snap: RecordedSnap[];
|
|
101
135
|
layers: RecordedLayer[];
|
|
102
136
|
}
|
|
137
|
+
/**
|
|
138
|
+
* Where the kit reports what it is doing so the debug overlay can draw it.
|
|
139
|
+
*
|
|
140
|
+
* Recording is push-based and cheap: hit-testers, handle painters and snap
|
|
141
|
+
* strategies call these as they run, whether or not any overlay is watching.
|
|
142
|
+
* Nothing here affects behavior — a sink that discards everything is a valid
|
|
143
|
+
* sink.
|
|
144
|
+
*/
|
|
103
145
|
interface DebugSink {
|
|
104
146
|
recordHitbox(id: string, kind: 'body' | 'handle' | 'rotation' | 'anchor', shape: HitShape): void;
|
|
105
147
|
recordHandle(id: string, position: {
|
|
@@ -127,4 +169,4 @@ interface DebugSink {
|
|
|
127
169
|
clearSnap(): void;
|
|
128
170
|
}
|
|
129
171
|
|
|
130
|
-
export type { DebugSink as D, HandleKind as H, RecordedBounds as R, DebugConfig as a, DebugSnapshot as b,
|
|
172
|
+
export type { DebugSink as D, HandleKind as H, RecordedBounds as R, DebugConfig as a, DebugSnapshot as b, DebugStrokes as c, DebugTheme as d, DebugFeature as e, DebugStroke as f, HitShape as g, RecordedHandle as h, RecordedHitbox as i, RecordedLayer as j, RecordedOrigin as k, RecordedSnap as l };
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Op } from '@weasel-js/history';
|
|
2
|
-
import { S as SnapTarget, M as MoveAdapter, I as InsertAdapter } from './types-
|
|
2
|
+
import { S as SnapTarget, M as MoveAdapter, I as InsertAdapter } from './types-DpQ0cWYC.js';
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* Snapshot of modifier-key state at gesture dispatch.
|
|
@@ -1,15 +1,20 @@
|
|
|
1
1
|
import { Op } from '@weasel-js/history';
|
|
2
2
|
|
|
3
|
+
/** A layout container's extent in world units. */
|
|
3
4
|
type ContainerBounds = {
|
|
4
5
|
x: number;
|
|
5
6
|
y: number;
|
|
6
7
|
width: number;
|
|
7
8
|
height: number;
|
|
8
9
|
};
|
|
10
|
+
/** A child a layout strategy is arranging. */
|
|
9
11
|
interface LayoutChild<TPose> {
|
|
10
12
|
id: string;
|
|
11
13
|
pose: TPose;
|
|
12
14
|
}
|
|
15
|
+
/** One place a dragged child could land. A strategy offers these as the drag
|
|
16
|
+
* moves, a `LayoutSnap` picks between them, and the chosen one decides both
|
|
17
|
+
* the preview and the committed poses. */
|
|
13
18
|
interface DropTarget<TPose> {
|
|
14
19
|
/** Where the dragged child lands if this target is picked. */
|
|
15
20
|
pose: TPose;
|
|
@@ -33,16 +38,22 @@ interface DropTarget<TPose> {
|
|
|
33
38
|
/** Strategy-private metadata (e.g. cell coords for tile-grid). */
|
|
34
39
|
meta?: unknown;
|
|
35
40
|
}
|
|
41
|
+
/** Chooses which of a strategy's drop targets the pointer means, or `null`
|
|
42
|
+
* to reject the drop. Separate from the strategy so the same arrangement can
|
|
43
|
+
* be paired with different snapping rules. */
|
|
36
44
|
interface LayoutSnap<TPose> {
|
|
37
45
|
pickTarget(targets: DropTarget<TPose>[], pointer: {
|
|
38
46
|
x: number;
|
|
39
47
|
y: number;
|
|
40
48
|
}): DropTarget<TPose> | null;
|
|
41
49
|
}
|
|
50
|
+
/** The container a layout strategy is arranging children within. */
|
|
42
51
|
interface LayoutContainer {
|
|
43
52
|
id: string;
|
|
44
53
|
bounds: ContainerBounds;
|
|
45
54
|
}
|
|
55
|
+
/** The child currently being dragged: where it started, where the pointer
|
|
56
|
+
* currently proposes it goes, and which container it came from. */
|
|
46
57
|
interface LayoutDragged<TPose> {
|
|
47
58
|
id: string;
|
|
48
59
|
/** The pose the dragged child currently has (pre-drop). */
|
|
@@ -51,6 +62,15 @@ interface LayoutDragged<TPose> {
|
|
|
51
62
|
pose: TPose;
|
|
52
63
|
sourceContainerId: string | null;
|
|
53
64
|
}
|
|
65
|
+
/**
|
|
66
|
+
* How a container arranges its children, and what happens when one is dragged
|
|
67
|
+
* into or around it.
|
|
68
|
+
*
|
|
69
|
+
* The four required methods cover the whole cycle: `childPoses` is the resting
|
|
70
|
+
* arrangement, `getDropTargets` enumerates where a drag could land,
|
|
71
|
+
* `reflowPoses` is the live preview once a target is picked, and `commitDrop`
|
|
72
|
+
* turns the result into ops so the drop is undoable.
|
|
73
|
+
*/
|
|
54
74
|
interface LayoutStrategy<TPose> {
|
|
55
75
|
childPoses(container: LayoutContainer, children: ReadonlyArray<LayoutChild<TPose>>): Map<string, TPose>;
|
|
56
76
|
getDropTargets(container: LayoutContainer, children: ReadonlyArray<LayoutChild<TPose>>, dragged: LayoutDragged<TPose>): DropTarget<TPose>[];
|
|
@@ -66,6 +86,12 @@ interface LayoutStrategy<TPose> {
|
|
|
66
86
|
x: number;
|
|
67
87
|
y: number;
|
|
68
88
|
}): boolean;
|
|
89
|
+
/** Optional: reject a drag before any drop-target work happens. A type-aware
|
|
90
|
+
* container (a palette that only takes swatches, say) returns `false` and
|
|
91
|
+
* the drag falls through to whatever container is under it next. When
|
|
92
|
+
* absent, every drag is considered — rejection is still possible later, by
|
|
93
|
+
* `snap.pickTarget` returning null. */
|
|
94
|
+
acceptsDrop?(container: LayoutContainer, dragged: LayoutDragged<TPose>): boolean;
|
|
69
95
|
}
|
|
70
96
|
|
|
71
97
|
/**
|
|
@@ -134,6 +160,12 @@ interface MoveAdapter<TNode extends {
|
|
|
134
160
|
* targeting (`getLayout` present), nested-hit collapse
|
|
135
161
|
* (`pickTopMostHit`), and group-pose composition. Flat scenes may omit. */
|
|
136
162
|
getParent?(id: string): string | null;
|
|
163
|
+
/** Optional paint depth, read by `pickTopMostHit` to resolve two *siblings*
|
|
164
|
+
* whose bodies both cover the pointer. Without it the hit list's own order
|
|
165
|
+
* decides, which is right for a back-to-front walk and wrong for anything
|
|
166
|
+
* else. See `PickTopMostHitAdapter` for the `compareZ` alternative. */
|
|
167
|
+
getZIndex?(id: string): number | null | undefined;
|
|
168
|
+
compareZ?(a: string, b: string): number;
|
|
137
169
|
setPose(id: string, pose: TPose): void;
|
|
138
170
|
/** Optional. Used only by reparent ops (e.g. drag-into-container drops via
|
|
139
171
|
* layout strategies). Flat scenes that never reparent may omit. */
|
|
@@ -80,9 +80,13 @@ interface NodeBase<TData, TLayer extends string, TPose> {
|
|
|
80
80
|
data: TData;
|
|
81
81
|
parent: NodeId | null;
|
|
82
82
|
}
|
|
83
|
+
/** A node with no children — a shape, a label, an image. */
|
|
83
84
|
interface LeafNode<TData, TLayer extends string, TPose = RectPose> extends NodeBase<TData, TLayer, TPose> {
|
|
84
85
|
kind: 'leaf';
|
|
85
86
|
}
|
|
87
|
+
/** A node with an ordered list of children. This is the real group: what
|
|
88
|
+
* Cmd+G creates, what SVG `<g>` round-trips to. A container has its own pose,
|
|
89
|
+
* which its children's poses are relative to, and may optionally clip them. */
|
|
86
90
|
interface ContainerNode<TData, TLayer extends string, TPose = RectPose> extends NodeBase<TData, TLayer, TPose> {
|
|
87
91
|
kind: 'container';
|
|
88
92
|
children: NodeId[];
|
|
@@ -93,20 +97,30 @@ interface ContainerNode<TData, TLayer extends string, TPose = RectPose> extends
|
|
|
93
97
|
* paints descendants only where it covers. */
|
|
94
98
|
clipFromPose?: (pose: TPose) => Path | null;
|
|
95
99
|
}
|
|
100
|
+
/** A node in the scene tree: either a leaf or a container. Re-exported
|
|
101
|
+
* publicly as `SceneNode`, to avoid colliding with the DOM's `Node`. */
|
|
96
102
|
type Node<TData, TLayer extends string, TPose = RectPose> = LeafNode<TData, TLayer, TPose> | ContainerNode<TData, TLayer, TPose>;
|
|
97
103
|
interface LayerRecordBase<TLayer extends string> {
|
|
98
104
|
id: TLayer;
|
|
99
105
|
visible: boolean;
|
|
100
106
|
locked: boolean;
|
|
101
107
|
}
|
|
108
|
+
/** A layer declared when the scene was created. Fixed set, no display name —
|
|
109
|
+
* these are the kit's own render bands, not something a user manages. */
|
|
102
110
|
interface SystemLayerRecord<TLayer extends string> extends LayerRecordBase<TLayer> {
|
|
103
111
|
kind: 'system';
|
|
104
112
|
}
|
|
113
|
+
/** A layer the user created and can rename, reorder or delete. */
|
|
105
114
|
interface UserLayerRecord<TLayer extends string> extends LayerRecordBase<TLayer> {
|
|
106
115
|
kind: 'user';
|
|
107
116
|
name: string;
|
|
108
117
|
}
|
|
118
|
+
/** Per-layer metadata held by the scene: whether it is visible and locked,
|
|
119
|
+
* and where it sits in the render stack. Distinct from a node's `layer` tag,
|
|
120
|
+
* which merely names one of these. */
|
|
109
121
|
type LayerRecord<TLayer extends string> = SystemLayerRecord<TLayer> | UserLayerRecord<TLayer>;
|
|
122
|
+
/** What `Scene.add` needs to mint a node. Everything except the id is
|
|
123
|
+
* required; the id is generated unless one is supplied. */
|
|
110
124
|
interface AddNodeSpec<TData, TLayer extends string, TPose = RectPose> {
|
|
111
125
|
kind: 'leaf' | 'container';
|
|
112
126
|
layer: TLayer;
|
|
@@ -120,10 +134,13 @@ interface AddNodeSpec<TData, TLayer extends string, TPose = RectPose> {
|
|
|
120
134
|
* to the node; ignored for leaves. Mirrors `ContainerNode.clipFromPose`. */
|
|
121
135
|
clipFromPose?: (pose: TPose) => Path | null;
|
|
122
136
|
}
|
|
137
|
+
/** A custom scene mutation registered with `Scene.registerOp`: how to apply
|
|
138
|
+
* it and how to undo it. The pair is what makes it participate in history. */
|
|
123
139
|
interface RegisteredOp<P> {
|
|
124
140
|
apply: (payload: P) => void;
|
|
125
141
|
revert: (payload: P) => void;
|
|
126
142
|
}
|
|
143
|
+
/** One of the layers a scene is created with. */
|
|
127
144
|
interface SystemLayerSpec<TLayer extends string> {
|
|
128
145
|
id: TLayer;
|
|
129
146
|
visible?: boolean;
|
|
@@ -171,6 +188,8 @@ interface SceneRegistry<TPose> {
|
|
|
171
188
|
/** Maps registry keys to `clipFromPose` factory functions for container nodes. */
|
|
172
189
|
clipFromPose?: Readonly<Record<string, (pose: TPose) => Path | null>>;
|
|
173
190
|
}
|
|
191
|
+
/** Options for `useScene` — the layers the scene has, what it starts out
|
|
192
|
+
* holding, and how its history behaves. */
|
|
174
193
|
interface UseSceneOptions<TData, TLayer extends string, TPose = RectPose> {
|
|
175
194
|
systemLayers: readonly SystemLayerSpec<TLayer>[];
|
|
176
195
|
initial?: readonly AddNodeSpec<TData, TLayer, TPose>[];
|
|
@@ -204,6 +223,18 @@ interface UseSceneOptions<TData, TLayer extends string, TPose = RectPose> {
|
|
|
204
223
|
* wire it after construction via `scene.setActiveJournalAccessor(fn)`. */
|
|
205
224
|
getActiveJournal?: () => _weasel_js_history.Journal | null;
|
|
206
225
|
}
|
|
226
|
+
/**
|
|
227
|
+
* The kit-owned scene tree: nodes, layers, and the undo history over both.
|
|
228
|
+
*
|
|
229
|
+
* A scene is logical, not visual — it says what exists and where, and nothing
|
|
230
|
+
* about how it is painted. Every mutating method is undoable, and reads are
|
|
231
|
+
* snapshots rather than live views. Nodes are addressed by `NodeId`; hold ids
|
|
232
|
+
* across mutations, not node objects.
|
|
233
|
+
*
|
|
234
|
+
* Three type parameters keep it domain-agnostic: `TData` is the app's payload,
|
|
235
|
+
* which the kit never inspects; `TPose` is the transform shape, `RectPose` by
|
|
236
|
+
* default; `TLayer` is the union of layer names.
|
|
237
|
+
*/
|
|
207
238
|
interface Scene<TData, TLayer extends string, TPose = RectPose> {
|
|
208
239
|
readonly nodes: ReadonlyMap<NodeId, Node<TData, TLayer, TPose>>;
|
|
209
240
|
readonly roots: readonly NodeId[];
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@weasel-js/core",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.3",
|
|
4
4
|
"description": "Domain-agnostic 2D scene graph primitives for React: viewport math, drag/resize/insert/clone interactions, layered canvas rendering.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "orochi235",
|
|
@@ -74,11 +74,11 @@
|
|
|
74
74
|
"react": ">=18"
|
|
75
75
|
},
|
|
76
76
|
"dependencies": {
|
|
77
|
-
"@weasel-js/font": "1.0.
|
|
78
|
-
"@weasel-js/geom": "1.0.
|
|
79
|
-
"@weasel-js/gestures": "1.0.
|
|
80
|
-
"@weasel-js/history": "1.0.
|
|
81
|
-
"@weasel-js/modes": "1.0.
|
|
77
|
+
"@weasel-js/font": "1.0.3",
|
|
78
|
+
"@weasel-js/geom": "1.0.3",
|
|
79
|
+
"@weasel-js/gestures": "1.0.3",
|
|
80
|
+
"@weasel-js/history": "1.0.3",
|
|
81
|
+
"@weasel-js/modes": "1.0.3",
|
|
82
82
|
"earcut": "2.2.4",
|
|
83
83
|
"polygon-clipping": "^0.15.7"
|
|
84
84
|
},
|