@weasel-js/core 1.5.2 → 1.6.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/CHANGELOG.md CHANGED
@@ -1,5 +1,140 @@
1
1
  # Changelog
2
2
 
3
+ ## 1.6.0
4
+
5
+ ### Patch Changes
6
+
7
+ - 16c0da2: Kit actions can now fill a whole editor toolbar from the registry.
8
+
9
+ - `Action.variants` lists the separate things a parametric action does, each with its own label and params. `flip` declares Flip Horizontal and Flip Vertical; `reorder.forward` and `reorder.backward` declare their one-step and all-the-way forms. `actionItems(action)` expands an action into the entries a bar, menu or palette shows: one per variant, or the action itself. An action without an immediate invoker gets none, because `trigger` cannot start a drag.
10
+ - `actionShortcuts(action, params)` returns only the shortcuts whose binding passes those params, so each variant shows its own key.
11
+ - `ActionBar` renders one button per entry and triggers it with that entry's params. `icons` and `labels` are now keyed by entry key (`flip:y`, `reorder.forward:extreme`), which is still the action id for an action without variants. `enabled` is evaluated with the deps the action declares in `requires`, not a fixed set of six, and a tooltip without a `shortcut` override now shows the binding's key.
12
+ - New groups: `history` (undo, redo), `clipboard` (cut, copy, paste), `edit` (duplicate, delete), `structure` (group, ungroup) and `flip`.
13
+ - New `clipboard.paste` action, which calls the `clipboard` dep's `paste()`. It has no key binding, because Cmd/Ctrl+V already arrives as a paste event.
14
+ - `enabled` now follows the current state: undo and redo follow the history stacks, `delete` and `group` need a selection, `ungroup` needs a selected container, and `clipboard.paste` needs a non-empty clipboard. `delete`, `group` and `ungroup` used to report enabled unconditionally.
15
+ - Align actions now register left, center, right, top, middle, bottom.
16
+ - `buildDepsFromRequires` is re-exported from `@weasel-js/core`.
17
+ - b8ebef6: The eight glyphs the align and distribute actions ship are now exported from `@weasel-js/core` and re-exported from `@weasel-js/ui`, beside the Pathfinder and edit-action icons: `AlignLeftIcon`, `AlignCenterXIcon`, `AlignRightIcon`, `AlignTopIcon`, `AlignCenterYIcon`, `AlignBottomIcon`, `DistributeHorizontalIcon` and `DistributeVerticalIcon`. They are the same components the actions draw, so a consumer can render one outside an `<ActionBar>` without authoring its own.
18
+ - c373af4: Color ramps can interpolate in OKLab, HSL, sRGB and linear sRGB as well as OKLCH. `@weasel-js/ui` adds `colorRamp(from, to, steps, options)` and `rampColor(from, to, t, options)`, whose `space` option picks the space (default `'oklch'`), `hue` picks the shorter or longer arc in the polar spaces, and `chroma` applies a `ChromaCurve` after interpolation in any space. Underneath, `@weasel-js/paint` (re-exported from core) adds `interpolateSrgb` with the `ColorInterpolationSpace` and `HueInterpolation` types, plus float-precision `srgbToLinear`, `linearToSrgb`, `linearSrgbToOklab`, `oklabToLinearSrgb`, `srgbToHsl` and `hslToSrgb`. The forge story `ui/Color/ColorRamp` shows the same endpoints ramped in each space.
19
+ - bfe6a4f: `contrastLineColor(background, strength)` derives a line color that reads against an arbitrary background — a grid or a rule drawn over a page whose color the document picks, where theme tokens follow the chrome instead. It moves the background `strength` in OKLab lightness away from its nearer end, darker over light and lighter over dark, keeping its hue, so dark and tinted pages get lines that show. Re-exported from `@weasel-js/core`.
20
+ - 6857b4d: `DEFAULT_PALETTE` is now a `Palette` of five named sRGB entries rather than a `string[]`, which breaks any code indexing it as an array. `cycleFill(seq, palette?, fallback?)` gives the `seq`th entry as hex, wrapping, and is what the built-in shape tools and the `insert` dep now call. `@weasel-js/paint` gains `hexToColorLiteral` for `#rrggbb` and `#rrggbbaa`.
21
+ - bbaefca: Under a composing `poseComposition`, a container whose pose derives from its children (`dependsOn: 'children'` with a `derivePose`, as `groupAction` mints under the default strategy) is now an envelope rather than a frame: its children are stored in the same frame it is, and the render walk, `getWorldPose`, picking and the actions' world/local conversions pass over it. Before, its derived pose was folded in as the children's frame, which moved every child by its own offset. `unionOfChildren` needs no change and is right under any strategy. `definesFrame(node)` is exported, and `PoseAdapter` takes an optional `definesFrame(id)` so a hand-built adapter can say the same to `composeWorldPose` and `rebaseLocalPose`. Nothing changes without a composing strategy.
22
+
23
+ `moveAction`'s translate-only drag and commit are now right under a composing strategy. Dragging a frame container no longer also translates its descendants, which moved them twice; they ride the frame. A node stored under a turned frame now moves the way the pointer went, instead of by the world drag applied in its frame's rotated axes.
24
+
25
+ Copy and paste now keep a container's `dependsOn: 'children'` and `derivePose`, so a pasted group still tracks its members, under any strategy. Under a composing strategy, `snapshotSelection` also captures in world coordinates any node whose frame is not part of the copy, and `commitPaste` no longer offsets nodes inside a pasted frame a second time.
26
+ - 0cf6a0d: The clipboard, duplicate, group, ungroup, reorder and flip actions now ship their own icons, so `<ActionBar group="clipboard" />` and its siblings draw glyphs with no `icons` map. Each reorder and flip variant carries its own glyph (Bring Forward / Bring to Front, Send Backward / Send to Back, Flip Horizontal / Flip Vertical). The twelve glyphs are exported from `@weasel-js/core` and `@weasel-js/ui` as `CutIcon`, `CopyIcon`, `PasteIcon`, `DuplicateIcon`, `GroupIcon`, `UngroupIcon`, `BringForwardIcon`, `BringToFrontIcon`, `SendBackwardIcon`, `SendToBackIcon`, `FlipXIcon` and `FlipYIcon`, in the same 20×20 `currentColor` register as the Pathfinder icons. An `icons` entry still overrides them.
27
+ - 811abcd: A registered program's struct uniforms now get locations. `uniform Light
28
+ u_lights[2];` is looked up as `u_lights[0].pos`, `u_lights[0].r` and so on,
29
+ nested structs and array members included; before, only the bare name was
30
+ looked up, so every write to a struct member was dropped, with a warning only
31
+ in development.
32
+
33
+ Array sizes written as a `#define`, a top-level `const int`, a small integer
34
+ expression over those, or on the type (`uniform float[2] u_t;`) now resolve;
35
+ before, such a uniform got no locations at all. Uniforms inside comments are no
36
+ longer looked up.
37
+
38
+ A program recompiled after a restored WebGL context now looks up the uniforms
39
+ its own vertex shader declares, as `registerProgram` already did.
40
+ - 7c53d1a: The undo, redo and delete actions now ship their own icons, so `<ActionBar group="history" />` and `<ActionBar group="edit" />` draw glyphs with no `icons` map. `UndoIcon`, `RedoIcon` and `DeleteIcon` move into `@weasel-js/core`, which the actions need them in; `@weasel-js/ui` re-exports them under the same names with the same props, and `<Icon name="undo" />` draws the same glyph. Core also exports `ACTION_GLYPHS`, the three glyphs' SVG markup, which `ICON_PATHS` now points at.
41
+ - 5345efb: A `kit:image` node can crop and mirror its bitmap. `data.image` takes an
42
+ optional `source` — the part of the bitmap to draw into the pose rect, as
43
+ fractions of the bitmap's width and height — and optional `flipX` / `flipY`,
44
+ which mirror the drawn region within the rect without moving it. The painter
45
+ hands both to the renderer's existing `ImageDrawCommand` fields, so hit-testing
46
+ and the silhouette are unchanged. Existing image data draws as before.
47
+
48
+ `svgNodesToKitDrafts` now carries an `SvgImageNode`'s source rect and flips onto
49
+ `data.image` instead of dropping them, and the new `svgImageFromKit(image, pose)`
50
+ writes a `kit:image` leaf back as an `SvgImageNode`, so a cropped or flipped
51
+ image survives SVG → scene → SVG.
52
+ - 87fd8a8: Choose which layout container a drag lands in when several contain the drop point. `<SceneCanvas layoutDropTarget>` takes `'innermost'` (the default, and the behavior until now: the deepest container, ties to the one painted later), `'topmost'` (the container painted last, in the scene's render order across the whole tree) or `'region'` (only containers that declare a drop region). A layout strategy declares one with the new optional `dropRegion(container)`, returning a `Path` or a predicate in the container's local frame; a declared region replaces the container body as its hit area in every mode, and may reach past it. The drag-time reflow preview and the commit follow the same choice. New types: `LayoutDropTargetMode`, `DropRegion`.
53
+ - 6f14f6f: The pen joins paths. Finishing a path by clicking (or dragging on) another open path's endpoint now makes one node: the drawn path's anchors followed by the other path's, turned around when you land on its last anchor, with the other node deleted in the same undo step. The path being drawn keeps its identity — a continued node keeps its id and style, and a new path is minted like any other pen path.
54
+
55
+ Two optional additions make that one op batch: `EditAnchorsDep.editOps(id, worldPath, label)` returns the ops `applyEdit` would commit without applying them, and the pen adapter's `makeNode(pose)` builds the node `addNode` would insert. `<SceneCanvas>` supplies both. Without them the click places an anchor, as before.
56
+ - c1f82e2: The pen's curves now follow the handles you drag. Dragging while placing an anchor gives it an out-handle at the drag point and an in-handle mirrored through it, and each segment runs from its start anchor's out-handle to its end anchor's in-handle — as in Illustrator and Figma. Before, a segment's second control point was the mirror of the *previous* anchor's handle, which sat behind the start of the segment, and a dragged anchor never shaped the segment coming into it. The preview and the committed path both changed.
57
+
58
+ Alt held from the start of the drag leaves the anchor with no in-handle; Alt pressed part-way freezes the in-handle and moves only the out-handle. Dragging the endpoint of a path the pen picked up moves its out-handle only, leaving the existing segment into it alone. `PenAnchor.altBroken` now describes the anchor it is set on, not the one after it.
59
+ - 97561f1: Zoom the canvas on Safari's trackpad pinch
60
+
61
+ Safari reports a trackpad pinch as WebKit `gesturestart` / `gesturechange` /
62
+ `gestureend` events, and nothing listened for them, so the page zoomed instead
63
+ of the canvas. `useGestureDispatcher` now dispatches each `gesturechange` as a
64
+ new `pinch` gesture: `PinchSpec` (`{ kind: 'pinch', direction?: 'in' | 'out' }`),
65
+ `PinchEvent`, route-grammar name `pinch`, and `InvocationCtx.pinch`. Safari's
66
+ cumulative `scale` is turned into a per-sample step, and the focal point is
67
+ canvas-local like a wheel's. A new `pinch` entry in `DispatcherChannels` turns
68
+ the listeners off.
69
+
70
+ `viewport.zoom` binds it. Its wheel and pinch samples now share one path: each
71
+ becomes a scale factor about a focal point, so a pinch sample of 1.1 lands on
72
+ exactly the view a ctrl+wheel `deltaY` of -100 does.
73
+
74
+ Safari can send the same pinch as ctrl+wheel too. While a pinch some binding
75
+ has claimed is live, the dispatcher swallows ctrl+wheel (preventing its
76
+ default, dispatching nothing), so one pinch zooms once. When no binding claims
77
+ the pinch, the gesture events are left to the browser and ctrl+wheel reaches
78
+ its bindings as before.
79
+ - 89926b5: `<SceneCanvas>` now builds its adapter with `useSceneAdapter` and keeps the same adapter across renders unless one of its inputs changes; it used to build a new one on every render. Moving a container still moves its children, now through `sceneToAdapter`'s `cascadeContainerPose` rather than a second copy of that logic.
80
+
81
+ `useSceneAdapter` now passes `poseComposition` through to `sceneToAdapter`. It used to drop it, so the adapter it returned ignored the frame model. The undo entry `cascadeContainerPose` records for a container move is now labeled `move container` rather than `setPose`, the label `<SceneCanvas>` already used.
82
+ - 9f86dec: `<SceneCanvas selectionMode="none">` now blocks every selection write the canvas makes. Before, the adapter it hands its tools could still set the selection, and so could any op batch that selects its result, such as a paste or an ingest. `setSelection` on that adapter, and on the `selection` dep's `adapterMethods`, now does nothing in that mode. The consumer's own `SelectionApi`, passed as the `selection` prop or made with `useSelection({ scene })`, still writes, and the canvas draws what it holds.
83
+
84
+ `defaultCommitAdapter` takes an optional second argument, a `SelectionApi`'s `adapterMethods`. When it is passed, selection reads and writes go through it rather than the scene. Every built-in action now passes its `selection` dep.
85
+
86
+ The `CanvasSelectionMode` docs now say what each mode does. `'single'` is a click rule, not a cap: a marquee, lasso, select-all or paste can still select several nodes.
87
+ - 4074270: `ShapeKindIcon` draws the glyph for a shape kind — the one its insertion tool shows — and falls back to `UnknownIcon` for a kind the kit does not ship. The icon set gains `page` (`PageIcon`), a document page with a folded corner. Core now exports the `ShapeKind` type.
88
+ - debfd5d: An SVG image node (`data:image/svg+xml` source, or a URL ending in `.svg`) now stays sharp under zoom. The image cache re-rasterizes it at the size it is drawn, in power-of-two steps so a zoom gesture does not redraw it every frame, capped at the renderer's maximum texture size and 4096×4096 pixels. The previous raster keeps painting until the new one is ready, and its GL texture is freed when it is replaced. PNG, JPEG and other raster sources are unchanged.
89
+
90
+ New: `getImageBitmap(src, drawnAt?)` takes the size in device pixels an image is about to cover, `NodePaintCtx.pixelScale` carries device pixels per world unit to painters (`defaultDrawOne` fills it from the view and `devicePixelRatio`), and `isVectorImageSrc(src)` reports whether a source is treated as SVG.
91
+ - d975afa: `text-transform` for styled runs and text nodes
92
+
93
+ `StyledRun` and `TextStyle` gain `textTransform: 'none' | 'uppercase' |
94
+ 'lowercase' | 'capitalize'`, with CSS semantics. A run's value overrides the
95
+ node's, and `'none'` on a run turns an inherited transform off. Only what is
96
+ drawn changes: a run's `text` stays as authored, so carets, selections and
97
+ edits still address the source.
98
+
99
+ - Case mapping uses JavaScript's locale-independent full mappings, so `ß`
100
+ uppercases to `SS` and a word-final `Σ` lowercases to `ς`. `capitalize`
101
+ titlecases the first letter of each word (`dž` → `Dž`, `ß` → `Ss`) and leaves
102
+ the rest alone; word starts come from `Intl.Segmenter`, the same boundaries
103
+ browsers use, and are found across run boundaries.
104
+ - `resolveRuns` applies the transform, so `ResolvedRun.text` is the drawn
105
+ text. When a transform changes a length, the run carries `srcMap`: where
106
+ each drawn UTF-16 unit came from in the source. Layout reads each cell's
107
+ `srcIndex` / `srcEnd` off it, so both cells of an uppercased `ß` map to the
108
+ one source character, and `caretIndexAt` treats them as one stop.
109
+ - `transformRunTexts` is exported for callers laying text out themselves;
110
+ `layoutMarkdown` uses it.
111
+ - The range helpers (`applyStyleToRange`, `styleAtRange`,
112
+ `effectiveRangeStyle`) carry the new key, the text tool and the node's
113
+ Character properties offer it as "Case", and the edit overlay shows it with
114
+ CSS `text-transform` on the overlay and on each run span.
115
+ - `@weasel-js/svg` writes it as `style="text-transform:…"` on `<text>` and
116
+ `<tspan>` — it is a CSS property, not an SVG 1.1 presentation attribute — and
117
+ reads it back from either spelling or an ancestor.
118
+ - 62d8d7c: `useOngoingAction(actionId)` lets a UI control — a color picker, a slider, a swatch — drive an ongoing action the way a drag does: `input(params)` opens the action on the first call and moves it on the rest (the live preview), `commit(params?)` ends it as one undo entry, and `cancel()` drops it. A commit with nothing open is a whole edit on its own, which is what a click on a swatch is. An edit still open when the control unmounts or its action id changes is committed. It wraps `ActionsRegistry.begin`, whose begin-or-update-then-end bookkeeping every such control used to hand-roll around a ref; `SceneGradientHandles` now uses it.
119
+ - Updated dependencies [16c0da2]
120
+ - Updated dependencies [c373af4]
121
+ - Updated dependencies [bfe6a4f]
122
+ - Updated dependencies [6857b4d]
123
+ - Updated dependencies [b1c30bc]
124
+ - Updated dependencies [f792755]
125
+ - Updated dependencies [9aa63a1]
126
+ - Updated dependencies [97561f1]
127
+ - Updated dependencies [d975afa]
128
+ - Updated dependencies [62d8d7c]
129
+ - @weasel-js/routing@1.6.0
130
+ - @weasel-js/paint@1.6.0
131
+ - @weasel-js/text@1.6.0
132
+ - @weasel-js/gestures@1.6.0
133
+ - @weasel-js/cursor@1.6.0
134
+ - @weasel-js/font@1.6.0
135
+ - @weasel-js/geom@1.6.0
136
+ - @weasel-js/history@1.6.0
137
+
3
138
  ## 1.5.2
4
139
 
5
140
  ### Patch Changes
@@ -1,4 +1,5 @@
1
- import { P as PoseDescriptor, a as Path } from './poseDescriptor-PgfVKfa0.js';
1
+ import { P as Path } from './path-JEV2c5If.js';
2
+ import { P as PoseDescriptor } from './poseDescriptor-rZa9W5hJ.js';
2
3
 
3
4
  /** True for Path-shaped poses (`{kind: 'polygon' | 'rect'}`). Useful for
4
5
  * callers that need to fork between `pathPoseDescriptor` and