@weasel-js/core 1.0.1 → 1.0.2
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 +269 -0
- package/dist/{chunk-FVNWK7U3.js → chunk-PI56ORHE.js} +1593 -1316
- package/dist/chunk-PI56ORHE.js.map +1 -0
- package/dist/{chunk-DCIU3SRK.js → chunk-W2WB4352.js} +79 -151
- package/dist/chunk-W2WB4352.js.map +1 -0
- package/dist/clipboard.d.ts +1 -1
- package/dist/clipboard.js +0 -1
- package/dist/clone.d.ts +2 -2
- package/dist/clone.js +0 -1
- package/dist/{geometry-DVeZ2i-c.d.ts → geometry-CnISZ11w.d.ts} +1 -1
- package/dist/{grid-XcFQVS0f.d.ts → grid-CBiLBnyc.d.ts} +2 -2
- package/dist/index.d.ts +163 -43
- package/dist/index.js +2 -3
- package/dist/insert.d.ts +3 -3
- package/dist/insert.js +0 -1
- package/dist/insert.js.map +1 -1
- package/dist/move.d.ts +5 -5
- package/dist/move.js +0 -1
- package/dist/move.js.map +1 -1
- package/dist/{options-wAvCnOZd.d.ts → options-DoOvx50U.d.ts} +1 -1
- package/dist/patterns-builtin.js +0 -1
- package/dist/{pointSnapToGrid-BuDZWBrL.d.ts → pointSnapToGrid-Bj4r_lEQ.d.ts} +3 -3
- package/dist/{index-DPI8DV0A.d.ts → registry-BQL4oyTg.d.ts} +139 -348
- package/dist/renderer.d.ts +11 -0
- package/dist/renderer.js +2 -3
- package/dist/resize.d.ts +5 -5
- package/dist/resize.js +0 -1
- package/dist/routing.d.ts +104 -5
- package/dist/routing.js +1 -2
- package/dist/{types-B_-khFM0.d.ts → types-Ch0Goo-j.d.ts} +12 -0
- package/dist/{types-BhJJ2OCM.d.ts → types-Ct4n0Z38.d.ts} +1 -1
- package/dist/{types-BJ8_cyT7.d.ts → types-Dtxe7jTS.d.ts} +20 -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-PZ5AY32C.js +0 -9
- package/dist/chunk-PZ5AY32C.js.map +0 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,274 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 1.0.2
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- 28710f2: The renderer's solid batch is drained at the sites that decide routing or
|
|
8
|
+
change stencil state, instead of at each emitter that happened to remember.
|
|
9
|
+
Geometry that cannot join a run now goes through `tryStageSolid`, which returns
|
|
10
|
+
`false` only after flushing — so the only way an emitter earns permission to
|
|
11
|
+
draw for itself is to have called the function that drained the batch. `pushClip`
|
|
12
|
+
and `popClip` flush as their first statement, since rasterizing into the stencil
|
|
13
|
+
is what creates the obligation.
|
|
14
|
+
|
|
15
|
+
Nothing about the drawn result changes; this removes a way for a future draw
|
|
16
|
+
path to paint under geometry staged before it.
|
|
17
|
+
|
|
18
|
+
- 2e3fea2: The `routing` namespace is gone from the main barrel, and the reflection
|
|
19
|
+
surface exports only what a consumer can use.
|
|
20
|
+
|
|
21
|
+
`export * as routing` made tool authoring reachable two ways — `core.routing.defineTool`
|
|
22
|
+
and the `@weasel-js/core/routing` subpath — and no consumer ever used the first.
|
|
23
|
+
It survived as the unfinished half of the 2026-05-12 declarative-routing work,
|
|
24
|
+
whose Phase 6 was to move `defineTool` out of `routing/` entirely. **Removing
|
|
25
|
+
it is a breaking change for anyone importing the namespace form**; the subpath
|
|
26
|
+
is unchanged and is what every known consumer already uses.
|
|
27
|
+
|
|
28
|
+
`tools/routing/reflection` now exports `buildRouteRegistry`, `findConflicts`,
|
|
29
|
+
`RegistryEntry` and `Conflict` — the four an external inspector needs.
|
|
30
|
+
`PREDICATE_TARGET`, `findScopedConflicts`, `formatConflict`,
|
|
31
|
+
`reportRouteConflicts` and `ToolScopes` are still there and still used; they
|
|
32
|
+
are just no longer public, since their only caller is inside the kit.
|
|
33
|
+
|
|
34
|
+
- 75ba7b1: Three fixes found by re-checking backlog entries against the code.
|
|
35
|
+
|
|
36
|
+
SVG gradients survive a round trip. The parser now reads `gradientUnits`
|
|
37
|
+
(`objectBoundingBox` → `units: 'bounds'`, `userSpaceOnUse` → `'world'`) and the
|
|
38
|
+
serializer writes back whichever the paint declares, instead of hardcoding
|
|
39
|
+
`userSpaceOnUse` on the way out — which had been reading a box-relative
|
|
40
|
+
gradient's `0..1` geometry as page coordinates, i.e. a gradient the size of a
|
|
41
|
+
pixel.
|
|
42
|
+
|
|
43
|
+
`unpackSvgFiles` keeps gradient fills instead of flattening them to a solid.
|
|
44
|
+
The reason recorded for the flattening — that the `kit:path` painter has no
|
|
45
|
+
gradient slot — had not been true for some time; `NodeFill` is
|
|
46
|
+
`string | FillStyle`, now exported. A `userSpaceOnUse` gradient is normalized
|
|
47
|
+
against the leaf's own box on the way in, so it survives the fit-clamp and
|
|
48
|
+
drop-point placement that move the geometry out from under it. Gradient
|
|
49
|
+
_strokes_ still flatten: `data.stroke` genuinely is a color string.
|
|
50
|
+
|
|
51
|
+
`extractUniformNames` skips precision and interpolation qualifiers. `uniform
|
|
52
|
+
highp float u_t;` — the common spelling in hand-written GLSL — matched nothing
|
|
53
|
+
at all, so the uniform got no location and every write to it was dropped in
|
|
54
|
+
silence. Comma-separated declarator lists (`uniform float a, b;`) read too.
|
|
55
|
+
|
|
56
|
+
Also adds `tests/visual/text-decoration.spec.ts`, a baseline-free assertion
|
|
57
|
+
that underline and strikethrough sit `0.40 em` apart and span only their own
|
|
58
|
+
runs. It measures the gap between two gap-free horizontal ink runs, which is
|
|
59
|
+
something `text.spec.ts`'s 5% diff tolerance cannot see move.
|
|
60
|
+
|
|
61
|
+
- e4a6ec4: Tool authoring moved out of `routing/` and onto the main barrel. `defineTool`,
|
|
62
|
+
`defineViewportTool`, `ToolDef`, `ViewportToolDef` and `ToolKeybinding` now come
|
|
63
|
+
from `@weasel-js/core`:
|
|
64
|
+
|
|
65
|
+
```ts
|
|
66
|
+
import { defineTool, type ToolDef } from "@weasel-js/core";
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
**This is a breaking change for anyone importing them from
|
|
70
|
+
`@weasel-js/core/routing`.** That subpath keeps the route grammar (`parseRoute`,
|
|
71
|
+
`formatRoute`, `describeRoute`, the gesture descriptors) and the reflection
|
|
72
|
+
consumers (`buildRouteRegistry`, `findConflicts`) — it is now only the surface
|
|
73
|
+
that _reads_ routes back, matching its name.
|
|
74
|
+
|
|
75
|
+
Finishes Phase 6 of the 2026-05-12 declarative-routing work. Source layout
|
|
76
|
+
follows: the factory and its `ToolDef` types sit at the top of `src/tools/`
|
|
77
|
+
alongside `useTools` and `useKeybindings`, with `routing/types.ts` renamed
|
|
78
|
+
`routeTypes.ts` to clear the existing `tools/types.ts`. Behavior and runtime
|
|
79
|
+
contract are unchanged.
|
|
80
|
+
|
|
81
|
+
- d2a9049: Six backlog entries, all in the input and hit-test layers.
|
|
82
|
+
|
|
83
|
+
Tool overlays can say where they sit. `Contribution.overlay` takes a
|
|
84
|
+
`RenderLayer` or an array of them, and a new `overlayPosition` (`'top'` — the
|
|
85
|
+
default — / `'before-selection'` / `'after-selection'`) anchors them against
|
|
86
|
+
the selection chrome instead of always landing on top; with no selection layer
|
|
87
|
+
in the stack the anchored positions fall back to the tail.
|
|
88
|
+
`getActiveOverlays(position?)` partitions, and `placeToolOverlays` in
|
|
89
|
+
`canvas/layerOrder.ts` does the splice, so the ordering is testable without a
|
|
90
|
+
GL context.
|
|
91
|
+
|
|
92
|
+
`drop` and `paste` are route-grammar gesture names. They shipped without them,
|
|
93
|
+
so the inspector reported `undefined` for every ingestion binding. Both are
|
|
94
|
+
targetless and carry the spec's MIME-glob filter as their arg — `drop(image/*)`.
|
|
95
|
+
|
|
96
|
+
An unhandled paste stays the page's. `onPaste` now dispatches first and calls
|
|
97
|
+
`preventDefault` only on `'handled'`, the shape `onWheel` already used.
|
|
98
|
+
Clipboard items materialize synchronously, so unlike `onDrop` the result is
|
|
99
|
+
known while the default can still be suppressed.
|
|
100
|
+
|
|
101
|
+
Marquee and lasso see the shape a node actually draws. `hitTestArea` asked the
|
|
102
|
+
_pose_ for a silhouette, which meant the kit's own inserted shapes — geometry
|
|
103
|
+
on `node.data.path` behind a plain `{x,y,w,h}` pose — took the AABB path and
|
|
104
|
+
kept every false positive the silhouette test exists to drop. It now asks
|
|
105
|
+
`findShapeSilhouette` for the drawn world-frame boundary. Paying for that is a
|
|
106
|
+
containment short-circuit: a node the rect marquee swallows whole is a hit no
|
|
107
|
+
silhouette can overturn, so neither the kernel nor the painter runs. Net
|
|
108
|
+
against the committed bench baseline, polygon-pose scenes gain (1.25x at 1000
|
|
109
|
+
nodes / 100% area) and plain-rect scenes lose ~8% on the two rows that scan
|
|
110
|
+
everything. The short-circuit is marquee-only, behind `hitTestAreaPolygon`'s
|
|
111
|
+
`areaIsRect` flag, because a node inside a lasso hull's bounding box can still
|
|
112
|
+
miss the hull.
|
|
113
|
+
|
|
114
|
+
Layout siblings reflowing mid-drag render opaque. `OngoingHandle.previewOpaqueIds()`
|
|
115
|
+
names the subset of `previewIds()` that skips the ghost alpha; `moveAction`
|
|
116
|
+
fills it from the destination and source reflow ids. A ghost means "in flight
|
|
117
|
+
under the pointer", which a sibling settling into its destination slot is not.
|
|
118
|
+
|
|
119
|
+
`LayoutStrategy.acceptsDrop(container, dragged)` rejects a drag before any
|
|
120
|
+
drop-target work, so a type-aware container falls through to whatever sits
|
|
121
|
+
under it rather than swallowing everything in its bounds.
|
|
122
|
+
|
|
123
|
+
`flipAction` reads `params.pivot`. `'each'` (the default, unchanged) mirrors
|
|
124
|
+
every pose about its own AABB; `'union'` mirrors about the selection envelope
|
|
125
|
+
so items swap sides, and the `geometryProjection` data op follows the same
|
|
126
|
+
pivot.
|
|
127
|
+
|
|
128
|
+
- 5f05431: `viewport.pinchZoom` now pans as well as zooms. It anchored `zoomAt` on the
|
|
129
|
+
current gesture centroid and never translated by the centroid delta, so two
|
|
130
|
+
fingers travelling together — spread unchanged, zoom factor 1 — moved the view
|
|
131
|
+
not at all.
|
|
132
|
+
|
|
133
|
+
Each frame now anchors the zoom on the previous centroid and then translates by
|
|
134
|
+
how far the centroid travelled. Together those pin the world point under the
|
|
135
|
+
gesture midpoint as the midpoint moves, which is what makes a pinch feel
|
|
136
|
+
attached to the fingers.
|
|
137
|
+
|
|
138
|
+
The action's id and label are unchanged (`viewport.pinchZoom` / `Pinch Zoom`).
|
|
139
|
+
Consumers who bound it get panning with no wiring change.
|
|
140
|
+
|
|
141
|
+
- 5fea43d: Five unrelated small fixes.
|
|
142
|
+
|
|
143
|
+
A tapered stroke with `align: 'inner'` or `'outer'` on a polygon path painted
|
|
144
|
+
at half its requested widths. That alignment renders by tessellating at twice
|
|
145
|
+
the width and stencilling half away, and the doubling reached `stroke.width`
|
|
146
|
+
but not `vertexWidths`. The doubled array is memoized per source array, since
|
|
147
|
+
the ribbon cache compares it by reference.
|
|
148
|
+
|
|
149
|
+
An image insert previews the decoded bitmap inside the drag bounds instead of
|
|
150
|
+
committing on release with no preview at all. It falls back to the bare
|
|
151
|
+
outline until the image decodes, and `useImageTool({ preview: 'outline' })`
|
|
152
|
+
opts out of the bitmap entirely.
|
|
153
|
+
|
|
154
|
+
A HUD widget that claims the pointer reports a `'pointer'` cursor without
|
|
155
|
+
implementing anything — hovering one while a drawing tool was active used to
|
|
156
|
+
keep showing that tool's cursor. The rule is keyed on the `claims` every
|
|
157
|
+
widget already declares, so it covers consumer-authored widgets too;
|
|
158
|
+
decoration claims nothing and the hit walk descends past it. A widget's own
|
|
159
|
+
`cursorAt` still wins, and `button` takes a `cursor` option that feeds it.
|
|
160
|
+
|
|
161
|
+
`composeAffordanceLayer`'s `hitTest` returns a `LayerHit`, carrying the hit
|
|
162
|
+
region's declared cursor and claim instead of dropping them. `AffordanceRegion`
|
|
163
|
+
gains optional `strength` / `claimedKinds` to declare that claim.
|
|
164
|
+
|
|
165
|
+
`ToolPalette` uses the shared `useRovingTabIndex` rather than its own container
|
|
166
|
+
handler, so arrow keys skip tools that are ineligible in the current mode and
|
|
167
|
+
the tab stop no longer sits on one. `ToolButton` takes an `onKeyDown`.
|
|
168
|
+
|
|
169
|
+
- 443d74e: Stroke ribbons are tessellated once per stroke configuration instead of once
|
|
170
|
+
per frame. The renderer rebuilt every stroked path's ribbon geometry on every
|
|
171
|
+
frame and discarded it; it now caches the result on `Path` identity, keyed by
|
|
172
|
+
the parameters that change the ribbon — width, cap, join, miter limit,
|
|
173
|
+
alignment, dash, and flatten tolerance. Paint and vertex colors are not in the
|
|
174
|
+
key, since both are applied over the same triangles at draw time.
|
|
175
|
+
|
|
176
|
+
A ribbon that survives a frame also stops paying for a fresh VAO and two
|
|
177
|
+
buffers on every subsequent frame. One whose path or stroke parameters change
|
|
178
|
+
each frame keeps the transient upload it had before, freed at end of frame —
|
|
179
|
+
so an animated or freshly drawn path never accumulates GL resources waiting on
|
|
180
|
+
garbage collection.
|
|
181
|
+
|
|
182
|
+
Nothing about the drawn result changes. The cache is keyed on object identity,
|
|
183
|
+
matching the fill cache: a `Path` rebuilt with equal coordinates is a distinct
|
|
184
|
+
entry and re-tessellates.
|
|
185
|
+
|
|
186
|
+
- 7decec1: Four more backlog fixes.
|
|
187
|
+
|
|
188
|
+
`@weasel-js/svg` reads and writes `<image>`. A new `SvgImageNode` holds the
|
|
189
|
+
`href` verbatim — an external URL or a `data:` URI, with `xlink:href` accepted
|
|
190
|
+
on the way in — plus a box that inherited transforms collapse onto and an
|
|
191
|
+
element-local rotation. `unpackSvgFiles` maps it onto the `kit:image` painter's
|
|
192
|
+
`data.image.src`, so a dropped SVG carrying raster content now keeps it instead
|
|
193
|
+
of dropping the element on parse. `preserveAspectRatio` is not modeled: the box
|
|
194
|
+
is taken literally and written back as `none`, and a non-`none` source warns.
|
|
195
|
+
|
|
196
|
+
`pickTopMostHit` resolves sibling z-order. An adapter can supply `getZIndex(id)`
|
|
197
|
+
or `compareZ(a, b)`; both compose with the existing parent/child collapse rather
|
|
198
|
+
than replacing it, so a child still beats its own ancestor whatever z the two
|
|
199
|
+
report. Without either, the hit list's own order decides, as before.
|
|
200
|
+
|
|
201
|
+
`useSceneTextEdit` supplies `setStyle`. Clearing a style flag that the _node_
|
|
202
|
+
sets is the one edit the additive run algebra can't express, and `useTextEdit`
|
|
203
|
+
declines it without a writer — so every scene-wired consumer silently refused
|
|
204
|
+
that toggle. Override the projection with `setStyle(data, style)` for a
|
|
205
|
+
non-default data shape.
|
|
206
|
+
|
|
207
|
+
The slops debug overlay draws handle halos at the real hit radius. Affordance
|
|
208
|
+
regions moved to screen-pixel radii, but this layer still scaled its circles by
|
|
209
|
+
the view, so at 4x zoom it drew a 32px halo over an 8px target — the one thing
|
|
210
|
+
a hit-test overlay must not do. Anchor slops now read the anchor radius rather
|
|
211
|
+
than the handle radius.
|
|
212
|
+
|
|
213
|
+
- 24daa08: Five unrelated backlog fixes.
|
|
214
|
+
|
|
215
|
+
The specificity tuple's `phase` dimension is graded rather than binary: an
|
|
216
|
+
atom scores 2 when both its channel and its lifecycle state are concrete, 1
|
|
217
|
+
when one axis is wildcarded, and 0 for `*:*`, which matches everything an
|
|
218
|
+
undeclared phase would have matched. An atom list takes the minimum, since
|
|
219
|
+
`matchPhase` is a union. No existing binding reorders — the four ambient
|
|
220
|
+
actions hold at 1, and the polygon and star tools' `phase: 'engaged'` wheel
|
|
221
|
+
bindings rise to 2, widening a gap they already won.
|
|
222
|
+
|
|
223
|
+
The loupe's pixel mode no longer drops the end of a fast drag: a readback
|
|
224
|
+
requested while `createImageBitmap` is in flight is remembered and re-run when
|
|
225
|
+
that one settles, instead of being discarded.
|
|
226
|
+
|
|
227
|
+
SVG unpack applies the fit-clamp to text on both axes. `fontSize` now scales
|
|
228
|
+
with the file, and a text node's box width is estimated from its longest line
|
|
229
|
+
instead of inheriting the parser's unbounded-width wrap sentinel — which,
|
|
230
|
+
folded into the union AABB, had been clamping any external SVG containing
|
|
231
|
+
text down to a speck. That sentinel is now the exported `UNBOUNDED_TEXT_WIDTH`
|
|
232
|
+
rather than a bare `99999`, so a consumer reading `SvgTextNode.width` can tell
|
|
233
|
+
a measurement from a placeholder.
|
|
234
|
+
|
|
235
|
+
The debug overlay takes per-feature line widths and dashes through
|
|
236
|
+
`DebugConfig.strokes`, alongside the colors `DebugConfig.theme` already
|
|
237
|
+
carried. Defaults are unchanged.
|
|
238
|
+
|
|
239
|
+
A `.dfont` face declines the outline tier by name. Datafork TrueType holds its
|
|
240
|
+
sfnt tables inside a Macintosh resource map, which is still not unpacked, but
|
|
241
|
+
it is now recognized before parsing and reported as itself rather than dying
|
|
242
|
+
on an unrecognized-signature message that never says which format it saw.
|
|
243
|
+
|
|
244
|
+
- f79e4b2: Viewport layers can now answer where a screen point lands inside them.
|
|
245
|
+
`createViewportLayer` returns a `ViewportLayer`, adding:
|
|
246
|
+
|
|
247
|
+
```ts
|
|
248
|
+
layer.reproject(outer, dims, screen); // → inner-world point, or null if outside
|
|
249
|
+
viewportsAt(layers, outer, dims, screen); // → topmost viewport containing it
|
|
250
|
+
```
|
|
251
|
+
|
|
252
|
+
`bounds` is already a pure function of `(outer, dims)`, so re-projection
|
|
253
|
+
recomputes the exact rect the frame painted rather than a remembered one — no
|
|
254
|
+
stored state and nothing to go stale. Right and bottom edges are exclusive, so
|
|
255
|
+
adjacent viewports never both claim a pixel.
|
|
256
|
+
|
|
257
|
+
This deliberately does **not** touch the dispatcher, which the previous
|
|
258
|
+
docstring promised it would. Tools still target the outer view; a consumer that
|
|
259
|
+
wants a click inside a viewport to mean something calls `reproject` from its own
|
|
260
|
+
handler. Making tools work _inside_ a viewport raises questions this primitive
|
|
261
|
+
does not answer — which view a pinch zooms, what a drag leaving the rect does —
|
|
262
|
+
and is tracked as its own item.
|
|
263
|
+
|
|
264
|
+
- Updated dependencies [d2a9049]
|
|
265
|
+
- Updated dependencies [24daa08]
|
|
266
|
+
- @weasel-js/gestures@1.0.2
|
|
267
|
+
- @weasel-js/font@1.0.2
|
|
268
|
+
- @weasel-js/geom@1.0.2
|
|
269
|
+
- @weasel-js/history@1.0.2
|
|
270
|
+
- @weasel-js/modes@1.0.2
|
|
271
|
+
|
|
3
272
|
## 1.0.1
|
|
4
273
|
|
|
5
274
|
### Patch Changes
|