@weasel-js/core 0.6.0 → 0.7.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +233 -0
- package/dist/{DrawCommand-Dl0bXNfS.d.ts → DrawCommand-CJtqqt8H.d.ts} +26 -2
- package/dist/{chunk-7V6JEOXE.js → chunk-2J6V527H.js} +10033 -10912
- package/dist/chunk-2J6V527H.js.map +1 -0
- package/dist/chunk-SYM6RAM4.js +232 -0
- package/dist/chunk-SYM6RAM4.js.map +1 -0
- package/dist/clone.d.ts +1 -1
- package/dist/geometry-D9BDMiQi.d.ts +114 -0
- package/dist/{grid-Cf87knjU.d.ts → grid-CaSK9bHV.d.ts} +1 -1
- package/dist/index-DOYRTfP0.d.ts +2986 -0
- package/dist/index.css +0 -35
- package/dist/index.css.map +1 -1
- package/dist/index.d.ts +1174 -2481
- package/dist/index.js +2 -2
- package/dist/insert.d.ts +2 -2
- package/dist/move.d.ts +3 -3
- package/dist/{options-BPPBWMa7.d.ts → options-DMWeTELe.d.ts} +1 -1
- package/dist/{pointSnapToGrid-D7s7QmOF.d.ts → pointSnapToGrid-C3EruUwt.d.ts} +3 -54
- package/dist/renderer.css +0 -35
- package/dist/renderer.css.map +1 -1
- package/dist/renderer.d.ts +30 -5
- package/dist/renderer.js +2 -2
- package/dist/resize.d.ts +3 -3
- package/dist/routing.d.ts +10 -8
- package/dist/routing.js +1 -1
- package/dist/{types-BjUi2vA-.d.ts → types-Dcaa0tPq.d.ts} +1 -25
- package/dist/{registerFont-CP-wCsrz.d.ts → viewToMat3-D4lrBigW.d.ts} +2 -44
- package/package.json +6 -5
- package/dist/chunk-7V6JEOXE.js.map +0 -1
- package/dist/chunk-AM6ARSPN.js +0 -517
- package/dist/chunk-AM6ARSPN.js.map +0 -1
- package/dist/fitViewToBounds-evGsnR8Q.d.ts +0 -62
- package/dist/index-DZBYMsHI.d.ts +0 -1555
- package/dist/routing.css +0 -35
- package/dist/routing.css.map +0 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,238 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.7.1
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- a3af158: Gestures are now keyed per pointer. `gestureIdFor` returned the literal string
|
|
8
|
+
`pointer-mouse` with nothing interpolated — despite its own docs promising
|
|
9
|
+
`pointer-<pointerId>` — so every pointer shared one in-flight handle slot and
|
|
10
|
+
two pointer gestures could not coexist. Pointer events carry `pointerId` now
|
|
11
|
+
and the id interpolates; events without one (synthetic probes, most tests)
|
|
12
|
+
still key to `pointer-mouse`.
|
|
13
|
+
|
|
14
|
+
That removes an accident the pinch path was relying on, so the multitouch
|
|
15
|
+
policy is stated rather than implied: when a second pointer lands, the
|
|
16
|
+
multitouch channel claims every pointer that hasn't already committed to a
|
|
17
|
+
gesture, suppressing both drags and taps from those pointers. A drag already in
|
|
18
|
+
flight keeps running — yanking a gesture away from someone who rested a palm is
|
|
19
|
+
worse than letting it finish.
|
|
20
|
+
|
|
21
|
+
`useTools` also reports routing conflicts now. `findConflicts` had been
|
|
22
|
+
written, tested, and never called, so the kit could detect its one class of
|
|
23
|
+
genuine routing ambiguity and never looked. It runs at registry assembly under
|
|
24
|
+
a dev guard and warns each conflict in the grammar the route was written in. It
|
|
25
|
+
warns and never throws: a consumer tool colliding with a kit tool can be
|
|
26
|
+
deliberate, since the loser may still take the gesture by declining through
|
|
27
|
+
`enabled()`.
|
|
28
|
+
|
|
29
|
+
- a3af158: Scenes with many shapes or much text draw far less work per frame. Two caches
|
|
30
|
+
the kit already had were missing on essentially every node of every frame,
|
|
31
|
+
because the values they key on were rebuilt each time.
|
|
32
|
+
|
|
33
|
+
The tessellation cache (`WeakMap<Path, Mesh>`) keys on `Path` identity, but
|
|
34
|
+
`kit:shape` allocated a fresh path for every ellipse, polygon and star on every
|
|
35
|
+
draw. Painters now memoize `paint` against the node, so the same path comes
|
|
36
|
+
back and the cache does its job: 1000 shape nodes went from 6.69 to 0.20
|
|
37
|
+
ms/frame through paint and tessellation.
|
|
38
|
+
|
|
39
|
+
Text layout is the larger one. `layoutRuns` — which walks every codepoint,
|
|
40
|
+
resolves a face per run, measures, wraps and places each glyph — ran per text
|
|
41
|
+
command per frame. It is now cached in the renderer, keyed on the resolved
|
|
42
|
+
runs. 200 wrapped paragraphs went from 31.8 to 0.06 ms/frame, 1000 short
|
|
43
|
+
labels from 12.5 to 0.42. The cache drops itself when a font becomes
|
|
44
|
+
available, so text still reflows the moment the real face lands.
|
|
45
|
+
|
|
46
|
+
Two contracts follow from this, for anyone writing a custom painter or calling
|
|
47
|
+
these directly:
|
|
48
|
+
|
|
49
|
+
- The array a painter's `paint` returns belongs to the painter. Treat it as
|
|
50
|
+
immutable and copy before appending — `defaultDrawOne` now does, for its
|
|
51
|
+
label overlay.
|
|
52
|
+
- `registerFont` now notifies `subscribeGlyphReady` when a family finishes
|
|
53
|
+
registering, so a font loaded mid-session repaints without waiting for an
|
|
54
|
+
unrelated redraw. `glyphGeneration()` is a new pull-based companion to that
|
|
55
|
+
signal, for caches that can't hold a subscription.
|
|
56
|
+
|
|
57
|
+
- 6af4806: Reorder: `Cmd/Ctrl+Shift+]` and `Cmd/Ctrl+Shift+[` now bring-to-front and
|
|
58
|
+
send-to-back. The shortcut every drawing app uses could never fire — modifier
|
|
59
|
+
matching is strict, so a binding without `shift` in its spec cannot match a
|
|
60
|
+
keystroke that holds it, which also made the shifted `'}'` / `'{'` characters
|
|
61
|
+
in those key lists unreachable. `Cmd+Alt+]` / `Cmd+Alt+[` remain as the
|
|
62
|
+
fallback for browsers that reserve `Cmd+Shift+[`/`]` for tab switching.
|
|
63
|
+
|
|
64
|
+
`BUNDLE_TOOLS.standard` no longer includes `pencil`. Freehand is a specialist
|
|
65
|
+
instrument rather than part of the everyday shape-drawing set; it is still in
|
|
66
|
+
`exhaustive`. Consumers wanting it back can pass `tools={{ pencil: true }}`
|
|
67
|
+
alongside the bundle.
|
|
68
|
+
|
|
69
|
+
- a3af158: Clicks now land on the shape a node actually paints, not on its bounding box.
|
|
70
|
+
The pose rect is the wrong answer for anything that isn't a rectangle: a click
|
|
71
|
+
in a star's notch, in the corner outside an ellipse, or in the blank half of a
|
|
72
|
+
text box went to the node that merely bounds that point, burying whatever was
|
|
73
|
+
really underneath. `picking: 'shape'` had been available since it shipped and
|
|
74
|
+
was opt-in only because flipping it changes what a click selects.
|
|
75
|
+
|
|
76
|
+
Ink counts too, not just the boundary. A shape whose interior isn't filled —
|
|
77
|
+
an outlined rect, a pencil stroke, a bare line — is now grabbable along its
|
|
78
|
+
outline and not through its empty middle, which is the opposite of what a fill
|
|
79
|
+
test alone answers. Painters declare this through the new `NodeShapeEntry.ink`;
|
|
80
|
+
one that declares none is treated as filled, the previous behavior.
|
|
81
|
+
|
|
82
|
+
Pass `geometry={{ picking: 'pose' }}` to `SceneCanvas` for the old rect
|
|
83
|
+
behavior. Painters with no silhouette are unaffected either way, so nothing
|
|
84
|
+
becomes unreachable.
|
|
85
|
+
|
|
86
|
+
- 2003597: Export `VERSION` — the kit version a build was compiled from, baked in at
|
|
87
|
+
build time. Apps can pair it with their own compile timestamp to report what
|
|
88
|
+
they're running (WeaselDraw now shows `0.7.0 · Jul 30` in its status bar).
|
|
89
|
+
- Updated dependencies [6af4806]
|
|
90
|
+
- Updated dependencies [a3af158]
|
|
91
|
+
- @weasel-js/font@0.7.1
|
|
92
|
+
- @weasel-js/geom@0.7.1
|
|
93
|
+
- @weasel-js/gestures@0.7.1
|
|
94
|
+
- @weasel-js/history@0.7.1
|
|
95
|
+
- @weasel-js/modes@0.7.1
|
|
96
|
+
|
|
97
|
+
## 0.7.0
|
|
98
|
+
|
|
99
|
+
### Minor Changes
|
|
100
|
+
|
|
101
|
+
- d3e5597: Extract the MSDF glyph tier into a new `@weasel-js/font` package: font
|
|
102
|
+
registry, atlas parsing, glyph layout, runtime rasterization, and the SDF
|
|
103
|
+
text shader source. `@weasel-js/core` depends on it; `registerFont` is still
|
|
104
|
+
re-exported from `@weasel-js/core/renderer`, so existing call sites keep
|
|
105
|
+
working.
|
|
106
|
+
|
|
107
|
+
Unregistered font families now render in the default family with a one-time
|
|
108
|
+
warning instead of rendering nothing. Configure with
|
|
109
|
+
`setFontFallbackPolicy('substitute' | 'canvas' | 'none')` — `'none'`
|
|
110
|
+
restores the previous hard-miss behavior, and `'canvas'` rasterizes the real
|
|
111
|
+
typeface at runtime when the browser has it. A family the `'canvas'` policy
|
|
112
|
+
enrolled for itself stops being canvas-served once the policy changes; one
|
|
113
|
+
you name with `registerCanvasFont` is served under every policy, and
|
|
114
|
+
`isCanvasFont` reports that distinction — it answers "will the dynamic tier
|
|
115
|
+
serve this family right now", so an auto-enrolled family reads `false` under
|
|
116
|
+
`'substitute'` and `'none'`. The default
|
|
117
|
+
family may be a canvas-registered family, and when it cannot serve the
|
|
118
|
+
request either, the resulting blank text is reported with its own warning
|
|
119
|
+
naming the default family rather than failing silently. Requesting the
|
|
120
|
+
default family itself also warns — whether it is registered at a variant it
|
|
121
|
+
can't serve, or `setDefaultFontFamily` named a family that was never
|
|
122
|
+
registered at all; either way there is nothing left to fall back to. An app
|
|
123
|
+
that has registered no fonts and set no default stays silent, since that is
|
|
124
|
+
not a misconfiguration.
|
|
125
|
+
|
|
126
|
+
`ResolveResult.substituted` reports the substitution structurally, and
|
|
127
|
+
`ResolveResult.resolved` now
|
|
128
|
+
carries the matched `family` alongside `weight` and `style` — the full atlas
|
|
129
|
+
identity to pass to `getFont` / `textureCacheKey`.
|
|
130
|
+
|
|
131
|
+
Adds `listFonts()` for enumerating registered families.
|
|
132
|
+
|
|
133
|
+
- a925117: Text antialiasing is derived from the screen-space derivative instead of a
|
|
134
|
+
constant.
|
|
135
|
+
|
|
136
|
+
Both SDF text shaders computed their smoothstep band from a fixed `u_aaWidth`
|
|
137
|
+
(0.05, set once per draw). A constant band cannot be correct at more than one
|
|
138
|
+
scale: at 16px it collapsed to well under a screen pixel, so glyph coverage
|
|
139
|
+
quantized to all-or-nothing and edges rendered as hard stair-steps; at display
|
|
140
|
+
sizes the same constant read mushy. `TEXT_FRAG_SRC` and `TEXT_FRAG_R8_SRC` now
|
|
141
|
+
take the band from `fwidth(sdfVal)`, which folds in font size, zoom, and DPR
|
|
142
|
+
together, with a small floor so a degenerate derivative can't reproduce the
|
|
143
|
+
aliased behavior.
|
|
144
|
+
|
|
145
|
+
This changes how all GL-rendered text looks — most visibly at UI sizes, where
|
|
146
|
+
it is the difference between binary and antialiased edges.
|
|
147
|
+
|
|
148
|
+
Breaking, for anyone driving the shaders directly:
|
|
149
|
+
|
|
150
|
+
- `u_aaWidth` is gone from both fragment sources and from `TEXT_SDF_UNIFORMS`.
|
|
151
|
+
There is no CPU-side AA knob to set; the shader derives it. Setting the
|
|
152
|
+
uniform was never useful — the kit only ever wrote 0.05 to it.
|
|
153
|
+
|
|
154
|
+
- eeae450: A codepoint the atlas never baked now falls back to a real glyph instead of a
|
|
155
|
+
literal `?`.
|
|
156
|
+
|
|
157
|
+
Font fallback resolved at family granularity: `resolveFontVariant` picks one
|
|
158
|
+
tier for a whole run. But a baked MSDF atlas covers a fixed charset, so a run
|
|
159
|
+
served by a perfectly good atlas can still contain a character that atlas has
|
|
160
|
+
no glyph for — an em dash, a curly quote, anything outside the subset. Those
|
|
161
|
+
drew codepoint 63. That fabricates a character the author never wrote and is
|
|
162
|
+
indistinguishable from one they did; the committed text baseline read "Themed
|
|
163
|
+
editing ? magenta caret" for a full commit without anyone noticing.
|
|
164
|
+
|
|
165
|
+
`layoutRuns` now escalates the individual codepoint to the dynamic canvas
|
|
166
|
+
tier, which rasterizes from installed fonts and can usually serve it for real.
|
|
167
|
+
The escalated glyph gets its own draw group (different texture and shader) and
|
|
168
|
+
is scaled by its own atlas's bake size. When escalation isn't available the
|
|
169
|
+
character is skipped with a warning naming it, rather than substituted —
|
|
170
|
+
`.notdef` is what a text stack should draw here, and the BmFont format has no
|
|
171
|
+
such glyph.
|
|
172
|
+
|
|
173
|
+
New in `@weasel-js/font`:
|
|
174
|
+
|
|
175
|
+
- `resolveGlyphFallback(family, weight, style)` returns a canvas-tier
|
|
176
|
+
`ResolveResult` for per-codepoint escalation, or `null` when it isn't
|
|
177
|
+
available. Declines under the `'none'` fallback policy, which documents a
|
|
178
|
+
miss as a hard miss, and when there is no canvas to rasterize into (SSR)
|
|
179
|
+
rather than throwing into the layout pass.
|
|
180
|
+
|
|
181
|
+
- e7d71c9: Text properties: node-level typography through the schema-driven panel, and
|
|
182
|
+
caret-range styling through a new tool options bar.
|
|
183
|
+
|
|
184
|
+
`TextStyle` and `StyledRun` gain `letterSpacing`, `underline`, and
|
|
185
|
+
`strikethrough`, with GL rendering, DOM-overlay, and SVG round-trips for all
|
|
186
|
+
three. `styleAtRange` / `applyStyleToRange` expose the run algebra publicly,
|
|
187
|
+
and `useTextEdit` gains `selection`, `rangeStyle`, and
|
|
188
|
+
`applyStyleToSelection`. Text nodes get Character and Paragraph schema
|
|
189
|
+
groups. New `ToolOptionsBar` component; `ToggleBar` renders indeterminate
|
|
190
|
+
segments via `mixedValues`.
|
|
191
|
+
|
|
192
|
+
Behavior changes worth knowing about:
|
|
193
|
+
|
|
194
|
+
- **`SelectionPanel` reads and writes node paths of any depth** (two or more
|
|
195
|
+
segments). It previously split at the first dot and read exactly one level,
|
|
196
|
+
so `data.style.fontSize` resolved to `data['style.fontSize']`.
|
|
197
|
+
- **The default `kit:text` painter paints a node's `runs`** when it has them,
|
|
198
|
+
instead of re-flattening `data.text`. Run styling was previously invisible
|
|
199
|
+
to anything drawn by the default scene layer.
|
|
200
|
+
- **`useTextEdit` no longer commits when focus moves into editing chrome**
|
|
201
|
+
(`isEditorChrome`), and commits on a pointerdown outside both the overlay
|
|
202
|
+
and that chrome. Its published `selection` survives focus leaving the
|
|
203
|
+
overlay — it clears on `startEdit` and when the edit ends. Without this a
|
|
204
|
+
character bar could not exist: clicking its controls ended the edit they
|
|
205
|
+
were there to change.
|
|
206
|
+
- **The edit overlay can scale with the view** (`TextEditScreenPose.zoom`),
|
|
207
|
+
keeping every metric on it — including run-level `fontSize` and
|
|
208
|
+
`letterSpacing` — in world units. Omitting `zoom` keeps the old
|
|
209
|
+
screen-pixel contract.
|
|
210
|
+
- **The canvas-2D measurement path counts tracking**, as the GL path already
|
|
211
|
+
did, so wrap points, `caretIndexAt`, and `fitTextPose` agree on tracked
|
|
212
|
+
text. This moves wrap points on any text with a non-zero `letterSpacing`.
|
|
213
|
+
- **The text tool enters edit on the box it inserts.**
|
|
214
|
+
|
|
215
|
+
Breaking-ish, in packages that have not been published with these paths:
|
|
216
|
+
|
|
217
|
+
- `splitNodePath` is removed from `@weasel-js/ui`'s public API — it was dead
|
|
218
|
+
and encoded the superseded one-level path model. `nodeValueAt` and
|
|
219
|
+
`setAtPath` are exported in its place.
|
|
220
|
+
- A text node's color leaf is now `data.style.fill` of the new `paint` kind
|
|
221
|
+
rather than `data.style.fill.color` of the `color` kind. `TextStyle.fill`
|
|
222
|
+
is a tagged union, so the old leaf read `undefined` off a gradient and
|
|
223
|
+
wrote a hybrid the renderer painted flat solid.
|
|
224
|
+
|
|
225
|
+
### Patch Changes
|
|
226
|
+
|
|
227
|
+
- Updated dependencies [d3e5597]
|
|
228
|
+
- Updated dependencies [a925117]
|
|
229
|
+
- Updated dependencies [eeae450]
|
|
230
|
+
- @weasel-js/font@0.7.0
|
|
231
|
+
- @weasel-js/geom@0.7.0
|
|
232
|
+
- @weasel-js/gestures@0.7.0
|
|
233
|
+
- @weasel-js/history@0.7.0
|
|
234
|
+
- @weasel-js/modes@0.7.0
|
|
235
|
+
|
|
3
236
|
## 0.6.0
|
|
4
237
|
|
|
5
238
|
### Patch Changes
|
|
@@ -242,6 +242,12 @@ interface TextStyle {
|
|
|
242
242
|
selectionBackground?: string;
|
|
243
243
|
/** Selection text color paired with `selectionBackground`. Default: inherits text color. */
|
|
244
244
|
selectionColor?: string;
|
|
245
|
+
/** Extra advance added after each glyph, in world units. Default 0. */
|
|
246
|
+
letterSpacing?: number;
|
|
247
|
+
/** Default `false`. */
|
|
248
|
+
underline?: boolean;
|
|
249
|
+
/** Default `false`. */
|
|
250
|
+
strikethrough?: boolean;
|
|
245
251
|
}
|
|
246
252
|
/** `TextStyle` with all fields filled in from defaults — what the renderer actually consumes. */
|
|
247
253
|
interface ResolvedTextStyle {
|
|
@@ -255,6 +261,9 @@ interface ResolvedTextStyle {
|
|
|
255
261
|
caretColor: string;
|
|
256
262
|
selectionBackground: string | null;
|
|
257
263
|
selectionColor: string | null;
|
|
264
|
+
letterSpacing: number;
|
|
265
|
+
underline: boolean;
|
|
266
|
+
strikethrough: boolean;
|
|
258
267
|
}
|
|
259
268
|
/** Default resolved style used when a `TextPose` omits `style`. */
|
|
260
269
|
declare const DEFAULT_TEXT_STYLE: ResolvedTextStyle;
|
|
@@ -281,6 +290,9 @@ interface StyledRun {
|
|
|
281
290
|
fontFamily?: string;
|
|
282
291
|
fontSize?: number;
|
|
283
292
|
fill?: FillStyle;
|
|
293
|
+
letterSpacing?: number;
|
|
294
|
+
underline?: boolean;
|
|
295
|
+
strikethrough?: boolean;
|
|
284
296
|
}
|
|
285
297
|
declare function toRuns(input: string | StyledRun[]): StyledRun[];
|
|
286
298
|
declare function runsToPlainText(runs: readonly StyledRun[]): string;
|
|
@@ -301,8 +313,14 @@ declare function markdownToRuns(input: string): StyledRun[];
|
|
|
301
313
|
*
|
|
302
314
|
* `bold`/`italic` toggles on a run are folded into `fontWeight`/`fontStyle`:
|
|
303
315
|
* `bold: true` → fontWeight 700, `italic: true` → fontStyle 'italic'.
|
|
304
|
-
* Explicit `fontFamily` / `fontSize` / `fill` on the run
|
|
305
|
-
* node-level value
|
|
316
|
+
* Explicit `fontFamily` / `fontSize` / `fill` / `letterSpacing` on the run
|
|
317
|
+
* override the node-level value (`letterSpacing: 0` on a run is an override,
|
|
318
|
+
* not an absence — it zeroes inherited tracking).
|
|
319
|
+
*
|
|
320
|
+
* `underline` / `strikethrough` are *additive*, like `bold`/`italic`: a run
|
|
321
|
+
* can turn a decoration on but never off, so they resolve as
|
|
322
|
+
* `run.x || style.x` and not `run.x ?? style.x`. See the header of
|
|
323
|
+
* `runs/rangeStyle.ts` for why the model collapses the tri-state.
|
|
306
324
|
*/
|
|
307
325
|
|
|
308
326
|
interface ResolvedRun {
|
|
@@ -312,6 +330,12 @@ interface ResolvedRun {
|
|
|
312
330
|
fontWeight: number;
|
|
313
331
|
fontStyle: 'normal' | 'italic';
|
|
314
332
|
fill: FillStyle;
|
|
333
|
+
/** Extra advance added after each glyph of this run, in world units. */
|
|
334
|
+
letterSpacing: number;
|
|
335
|
+
/** Draw a rule below this run's baseline. Additive over the node style. */
|
|
336
|
+
underline: boolean;
|
|
337
|
+
/** Draw a rule through this run's x-height. Additive over the node style. */
|
|
338
|
+
strikethrough: boolean;
|
|
315
339
|
}
|
|
316
340
|
declare function resolveRuns(runs: readonly StyledRun[], style: ResolvedTextStyle): ResolvedRun[];
|
|
317
341
|
|