@weasel-js/guides 1.10.1 → 1.11.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/README.md +30 -22
- package/dist/index.d.ts +205 -152
- package/dist/index.js +421 -340
- package/dist/index.js.map +1 -1
- package/package.json +4 -16
- package/dist/chunk-B25KFI3I.js +0 -18
- package/dist/chunk-B25KFI3I.js.map +0 -1
- package/dist/chunk-LOFNN7EQ.js +0 -45
- package/dist/chunk-LOFNN7EQ.js.map +0 -1
- package/dist/chunk-TLFMAZ6M.js +0 -31
- package/dist/chunk-TLFMAZ6M.js.map +0 -1
- package/dist/insert.d.ts +0 -30
- package/dist/insert.js +0 -58
- package/dist/insert.js.map +0 -1
- package/dist/move.d.ts +0 -42
- package/dist/move.js +0 -18
- package/dist/move.js.map +0 -1
- package/dist/pointSnapToGrid-BaVEjV23.d.ts +0 -13
- package/dist/resize.d.ts +0 -38
- package/dist/resize.js +0 -89
- package/dist/resize.js.map +0 -1
- package/dist/types-DRSPiXfk.d.ts +0 -38
package/README.md
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
# @weasel-js/guides
|
|
2
2
|
|
|
3
|
-
Placement aids for weasel: a visible grid
|
|
4
|
-
|
|
5
|
-
children with.
|
|
6
|
-
|
|
7
|
-
Everything here plugs into a seam `@weasel-js/core` already has. A snap
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
3
|
+
Placement aids for weasel: a visible grid, ruler guides, the snap sources that
|
|
4
|
+
snap to them and to sibling edges and gaps, and the layout strategies a
|
|
5
|
+
container arranges its children with.
|
|
6
|
+
|
|
7
|
+
Everything here plugs into a seam `@weasel-js/core` already has. A snap source
|
|
8
|
+
goes in `<SceneCanvas snap={{ sources }}>` or a preset's `snapSources`, and
|
|
9
|
+
competes with every other source under core's one ranking rule; see
|
|
10
|
+
[Snapping](https://github.com/orochi235/weasel/blob/main/docs/snapping.md). The grid and guide overlays are
|
|
11
11
|
`RenderLayer`s for a canvas layer slot, and a layout strategy implements core's
|
|
12
12
|
`LayoutStrategy`.
|
|
13
13
|
|
|
@@ -26,34 +26,42 @@ npm install @weasel-js/guides
|
|
|
26
26
|
A grid you can see and snap to:
|
|
27
27
|
|
|
28
28
|
```tsx
|
|
29
|
-
import { SceneCanvas
|
|
30
|
-
import { createGridLayer,
|
|
29
|
+
import { SceneCanvas } from '@weasel-js/core';
|
|
30
|
+
import { createGridLayer, gridSnapSource } from '@weasel-js/guides';
|
|
31
31
|
|
|
32
32
|
const grid = createGridLayer({ spacing: 20, bounds: () => ({ x: 0, y: 0, width: 800, height: 600 }) });
|
|
33
|
+
const snap = { sources: [gridSnapSource({ spacing: 20 })] };
|
|
33
34
|
|
|
34
35
|
<SceneCanvas
|
|
35
36
|
/* … */
|
|
36
|
-
|
|
37
|
+
snap={snap}
|
|
37
38
|
layers={{ grid: { layer: grid } }}
|
|
38
39
|
/>;
|
|
39
40
|
```
|
|
40
41
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
subpath:
|
|
44
|
-
|
|
45
|
-
```ts
|
|
46
|
-
import { snapToGrid } from '@weasel-js/guides/move';
|
|
47
|
-
import { snapToGrid, pointSnapToGrid } from '@weasel-js/guides/resize';
|
|
48
|
-
import { snapToGrid } from '@weasel-js/guides/insert';
|
|
49
|
-
```
|
|
42
|
+
The grid source snaps every snapping gesture — move, resize, insert, the pen —
|
|
43
|
+
and, being a fallback, gives way on any axis a real target in reach claims.
|
|
50
44
|
|
|
51
45
|
| Area | Exports |
|
|
52
46
|
|---|---|
|
|
53
|
-
| Grid | `createGridLayer`, `createCellHighlightLayer`, `useGridCellHover`, `
|
|
54
|
-
| Guides | `useGuides`, `createGuidesLayer`, `
|
|
47
|
+
| Grid | `createGridLayer`, `createCellHighlightLayer`, `useGridCellHover`, `pointToGridCell`, `roundToCell` |
|
|
48
|
+
| Guides | `useGuides`, `createGuidesLayer`, `deriveAlignmentGuides`, `matchSpacing`, `measureGaps`, `siblingBounds`, `worldBoundsOf`, `worldUnionOf` |
|
|
49
|
+
| Snap sources | `gridSnapSource`, `guideSnapSource`, `alignmentSnapSource`, `spacingSnapSource`, for `<SceneCanvas snap={{ sources }}>` or a preset's `snapSources` |
|
|
50
|
+
| Spacing hints | `createSpacingHintsPreset` (below), `distanceReadout`, `measureDistances` |
|
|
55
51
|
| Layout | `freeform`, `tileGrid`, `snapPoint`, `slots` (with the `rowSlots`, `gridSlots`, and `ringSlots` arrangements), `pack`, `quadtree`, `perContainer` for a strategy that keeps state, and the drop-target pickers `none`, `nearest`, `nearestWithin`, `containedThenNearest`, `cellAt` |
|
|
56
52
|
|
|
53
|
+
Spacing hints are one `<SceneCanvas features>` preset: its snap sources move
|
|
54
|
+
the selection to the spacing between its siblings (and, with `align`, to their
|
|
55
|
+
edges and centers), the canvas's snap readout marks the equal gaps, and holding
|
|
56
|
+
Alt over a shape measures its distance from the selection. It lives in
|
|
57
|
+
`src/spacingHints/`.
|
|
58
|
+
|
|
59
|
+
```tsx
|
|
60
|
+
const spacingHints = useMemo(() => createSpacingHintsPreset({ color: '#e0397f' }), []);
|
|
61
|
+
|
|
62
|
+
<SceneCanvas /* … */ features={['draw', spacingHints]} />;
|
|
63
|
+
```
|
|
64
|
+
|
|
57
65
|
## License
|
|
58
66
|
|
|
59
67
|
MIT
|
package/dist/index.d.ts
CHANGED
|
@@ -1,7 +1,5 @@
|
|
|
1
1
|
import { RefObject } from 'react';
|
|
2
|
-
import { ViewTransform, PlaneValue, PlaneUnits,
|
|
3
|
-
export { p as pointSnapToGrid } from './pointSnapToGrid-BaVEjV23.js';
|
|
4
|
-
import { G as Guide, S as SpacingGap } from './types-DRSPiXfk.js';
|
|
2
|
+
import { ViewTransform, PlaneValue, PlaneUnits, View, Dims, CommandStroke, RenderLayer, CommandFill, Bounds, PlaneMap, PoseDescriptor, Scene, NodeId, SnapSource, SurfaceContribution, FeaturePreset, LayoutSnap, LayoutStrategy, LayoutContainer, Vec2, ContainerBounds, LayoutChild } from '@weasel-js/core';
|
|
5
3
|
import { Rect } from '@weasel-js/geom';
|
|
6
4
|
|
|
7
5
|
/** Round `value` to the nearest multiple of `cellSize`. Returns 0 when the result would be -0. */
|
|
@@ -79,8 +77,13 @@ interface GridLayerOpts {
|
|
|
79
77
|
spacing: PlaneValue;
|
|
80
78
|
/** Optional unit system for resolving tagged `spacing` values. */
|
|
81
79
|
unitSystem?: PlaneUnits;
|
|
82
|
-
/**
|
|
83
|
-
|
|
80
|
+
/**
|
|
81
|
+
* The area to cover, in world units, read every paint with that paint's
|
|
82
|
+
* view and canvas size. Lines start at its own `x`/`y`. Omitted, the grid
|
|
83
|
+
* covers whatever the canvas shows, with its lines on world multiples of
|
|
84
|
+
* `spacing` so they stay put as the view pans.
|
|
85
|
+
*/
|
|
86
|
+
bounds?: (view: View, dims: Dims) => {
|
|
84
87
|
x: number;
|
|
85
88
|
y: number;
|
|
86
89
|
width: number;
|
|
@@ -128,28 +131,10 @@ interface CellHighlightLayerOpts {
|
|
|
128
131
|
/** Build a `RenderLayer` that fills a single grid cell — typically a snap-target preview. */
|
|
129
132
|
declare function createCellHighlightLayer(opts: CellHighlightLayerOpts): RenderLayer<unknown>;
|
|
130
133
|
|
|
131
|
-
/** Snap-strategy that rounds the pose's origin to the nearest multiple of
|
|
132
|
-
* `spacing` (resolved through `unitSystem`). Either may be per axis —
|
|
133
|
-
* `{ x, y }` — for a grid whose axes have different pitches or units. For
|
|
134
|
-
* non-rect TPose pass an `OriginProjection` so the strategy knows how to
|
|
135
|
-
* read/write the origin. */
|
|
136
|
-
declare function gridSnapStrategy<TPose>(spacing: PlaneValue, unitSystem?: PlaneUnits): SnapStrategy<TPose>;
|
|
137
|
-
/** As above, additionally reporting each candidate to a debug sink. */
|
|
138
|
-
declare function gridSnapStrategy<TPose>(spacing: PlaneValue, opts: {
|
|
139
|
-
unitSystem?: PlaneUnits;
|
|
140
|
-
debug?: DebugSink;
|
|
141
|
-
}): SnapStrategy<TPose>;
|
|
142
|
-
/** As above, for a `TPose` that is not a rect: `origin` tells the strategy how
|
|
143
|
-
* to read and write the pose's origin. */
|
|
144
|
-
declare function gridSnapStrategy<TPose>(spacing: PlaneValue, opts: {
|
|
145
|
-
unitSystem?: PlaneUnits;
|
|
146
|
-
origin: OriginProjection<TPose>;
|
|
147
|
-
debug?: DebugSink;
|
|
148
|
-
}): SnapStrategy<TPose>;
|
|
149
134
|
/**
|
|
150
135
|
* The integer cell `{col, row}` that contains `point`. Pair with
|
|
151
136
|
* `createCellHighlightLayer` (its `getCell` callback) to draw a snap-target
|
|
152
|
-
* preview that uses the same spacing as `
|
|
137
|
+
* preview that uses the same spacing as `gridSnapSource`.
|
|
153
138
|
*/
|
|
154
139
|
declare function pointToGridCell(point: {
|
|
155
140
|
x: number;
|
|
@@ -162,12 +147,49 @@ declare function pointToGridCell(point: {
|
|
|
162
147
|
row: number;
|
|
163
148
|
};
|
|
164
149
|
|
|
150
|
+
/**
|
|
151
|
+
* Guide — a horizontal or vertical world-space line used as a snap target
|
|
152
|
+
* and an optional rendered overlay.
|
|
153
|
+
*
|
|
154
|
+
* `axis === 'x'` means a vertical line at world `x = offset` (snaps the X
|
|
155
|
+
* coordinate); `axis === 'y'` means a horizontal line at world `y = offset`
|
|
156
|
+
* (snaps the Y coordinate). This matches "the X axis snaps along X."
|
|
157
|
+
*/
|
|
158
|
+
interface Guide {
|
|
159
|
+
/** Stable, caller-supplied id. Used by removeGuide and as a render key. */
|
|
160
|
+
id: string;
|
|
161
|
+
/** Which world axis this guide constrains. */
|
|
162
|
+
axis: 'x' | 'y';
|
|
163
|
+
/** World-space offset along the constrained axis. */
|
|
164
|
+
offset: number;
|
|
165
|
+
/** The stretch of the line worth drawing, in world units on the other
|
|
166
|
+
* axis: an `'x'` guide's y range. Derived alignment guides carry the
|
|
167
|
+
* extent of the boxes that produced them. Absent, the line has no extent
|
|
168
|
+
* of its own and `createGuidesLayer` draws it across the canvas. */
|
|
169
|
+
span?: {
|
|
170
|
+
min: number;
|
|
171
|
+
max: number;
|
|
172
|
+
};
|
|
173
|
+
}
|
|
174
|
+
/**
|
|
175
|
+
* SpacingGap — one measured gap between two boxes, drawn as an equal-spacing
|
|
176
|
+
* marker. `axis === 'x'` is a horizontal gap from world `x = min` to
|
|
177
|
+
* `x = max`, drawn at `y = at`; `axis === 'y'` is the vertical counterpart.
|
|
178
|
+
*/
|
|
179
|
+
interface SpacingGap {
|
|
180
|
+
axis: 'x' | 'y';
|
|
181
|
+
min: number;
|
|
182
|
+
max: number;
|
|
183
|
+
/** World position on the other axis the marker is drawn at. */
|
|
184
|
+
at: number;
|
|
185
|
+
}
|
|
186
|
+
|
|
165
187
|
/** Return shape for `useGuides`. */
|
|
166
188
|
interface UseGuidesReturn {
|
|
167
189
|
/** Live list (state). Re-renders when guides change. */
|
|
168
190
|
guides: Guide[];
|
|
169
191
|
/** Stable getter; reads the latest list without forcing a re-render.
|
|
170
|
-
* Pass to `
|
|
192
|
+
* Pass to `guideSnapSource` and `createGuidesLayer`. */
|
|
171
193
|
getGuides: () => Guide[];
|
|
172
194
|
/** Add a guide. If a guide with the same id already exists it is replaced. */
|
|
173
195
|
addGuide: (guide: Guide) => void;
|
|
@@ -178,7 +200,7 @@ interface UseGuidesReturn {
|
|
|
178
200
|
}
|
|
179
201
|
/**
|
|
180
202
|
* In-memory guide storage. Holds a list of horizontal/vertical world-space
|
|
181
|
-
* lines that callers can pass to `
|
|
203
|
+
* lines that callers can pass to `guideSnapSource` (snap source) and
|
|
182
204
|
* `createGuidesLayer` (render layer).
|
|
183
205
|
*
|
|
184
206
|
* v1 is intentionally minimal: no undo integration, no persistence, no
|
|
@@ -195,7 +217,7 @@ declare function useGuides(initial?: Guide[]): UseGuidesReturn;
|
|
|
195
217
|
* (`SpacingGap`) as ticked segments labeled with their size.
|
|
196
218
|
*
|
|
197
219
|
* Guides are not scene objects; they live outside the scene and are managed
|
|
198
|
-
* via `useGuides`. Pair with `
|
|
220
|
+
* via `useGuides`. Pair with `guideSnapSource` (snap source) to keep
|
|
199
221
|
* the visual guide and the snap target in lockstep.
|
|
200
222
|
*/
|
|
201
223
|
|
|
@@ -203,8 +225,8 @@ declare function useGuides(initial?: Guide[]): UseGuidesReturn;
|
|
|
203
225
|
interface GuidesLayerOpts {
|
|
204
226
|
/** Stable getter for the live guide list — typically `useGuides().getGuides`. */
|
|
205
227
|
getGuides: () => readonly Guide[];
|
|
206
|
-
/** Stable getter for the equal-spacing gaps to draw
|
|
207
|
-
*
|
|
228
|
+
/** Stable getter for the equal-spacing gaps to draw, such as
|
|
229
|
+
* `matchSpacing`'s. */
|
|
208
230
|
getGaps?: () => readonly SpacingGap[];
|
|
209
231
|
/** `'span'` (default) draws a guide that carries a `span` as a segment over
|
|
210
232
|
* it; `'full'` draws every guide across the whole canvas. */
|
|
@@ -234,18 +256,6 @@ interface GuidesLayerOpts {
|
|
|
234
256
|
* space, projected from world coordinates via the active view. */
|
|
235
257
|
declare function createGuidesLayer(opts: GuidesLayerOpts): RenderLayer<unknown>;
|
|
236
258
|
|
|
237
|
-
/** Which feature of a box to test against candidates, per axis.
|
|
238
|
-
* 'min' = left/top edge, 'center' = centerline, 'max' = right/bottom edge. */
|
|
239
|
-
type AlignAnchor = 'min' | 'center' | 'max';
|
|
240
|
-
/** The correction an alignment match asks for: the translation that lands the
|
|
241
|
-
* dragged bounds on the matched guides, and the guides themselves so they can
|
|
242
|
-
* be drawn. */
|
|
243
|
-
interface AlignMatchResult {
|
|
244
|
-
dx: number;
|
|
245
|
-
dy: number;
|
|
246
|
-
activeX: Guide | null;
|
|
247
|
-
activeY: Guide | null;
|
|
248
|
-
}
|
|
249
259
|
/** Which edges of a box move on one axis during a spacing match: `'both'`
|
|
250
260
|
* for a translate, `'min'`/`'max'` for a resize dragging that edge. */
|
|
251
261
|
type SpacingEdge = 'both' | 'min' | 'max';
|
|
@@ -272,74 +282,22 @@ interface DeriveAlignmentGuidesOptions<TPose = Bounds> {
|
|
|
272
282
|
edges?: boolean;
|
|
273
283
|
/** Emit centerX (x) and centerY (y) guides. Default true. */
|
|
274
284
|
centers?: boolean;
|
|
275
|
-
/** How to read each target.
|
|
276
|
-
* gets, or the two sides disagree. Default `AUTO_POSE_DESCRIPTOR`. */
|
|
285
|
+
/** How to read each target. Default `AUTO_POSE_DESCRIPTOR`. */
|
|
277
286
|
poseDescriptor?: PoseDescriptor<TPose>;
|
|
278
287
|
}
|
|
279
|
-
/** Common options shared by the three alignment behavior factories.
|
|
280
|
-
*
|
|
281
|
-
* Everything crossing this interface is in the camera's world, whatever
|
|
282
|
-
* layer the gesture edits: the candidate lines and spacing boxes handed in,
|
|
283
|
-
* and the lines and gaps published, which a layer the camera draws shows.
|
|
284
|
-
* A gesture on a `parallax` layer carries them into its plane to match. */
|
|
285
|
-
interface AlignmentBehaviorBase {
|
|
286
|
-
/** Live candidate lines — consumer derives from current siblings + page.
|
|
287
|
-
* A sibling on a parallax layer goes through `deriveAlignmentGuides`'
|
|
288
|
-
* `planeOf`, or its lines land where its plane's numbers say, not where
|
|
289
|
-
* it is drawn. */
|
|
290
|
-
getCandidates: () => readonly Guide[];
|
|
291
|
-
/** Publish the currently-matched line(s). Called every onMove; cleared
|
|
292
|
-
* (`[]`) on a miss and on onEnd. */
|
|
293
|
-
setActiveGuides: (guides: readonly Guide[]) => void;
|
|
294
|
-
/** Tolerance in screen px, read through the gesture's view. Default 6. */
|
|
295
|
-
tolerance?: number;
|
|
296
|
-
/** Modifier key that bypasses snapping while held. */
|
|
297
|
-
bypassKey?: keyof ModifierState;
|
|
298
|
-
/** Boxes to measure gaps between for equal-spacing snaps (`matchSpacing`):
|
|
299
|
-
* the siblings' visual bounds, without the dragged ones. Omit to snap to
|
|
300
|
-
* alignment lines only. On each axis the nearer of the two snaps wins.
|
|
301
|
-
* Move and unrotated resize use it; insert does not. */
|
|
302
|
-
getSpacingTargets?: () => readonly Bounds[];
|
|
303
|
-
/** Publish the equal-gap markers. Called with the guides; cleared (`[]`) on
|
|
304
|
-
* a miss and on onEnd. */
|
|
305
|
-
setActiveGaps?: (gaps: readonly SpacingGap[]) => void;
|
|
306
|
-
}
|
|
307
288
|
|
|
308
289
|
/** Derive candidate alignment lines from a set of sibling poses plus an
|
|
309
290
|
* optional page box. Each box contributes up to 3 guides per axis: the two
|
|
310
291
|
* edges and the center. Overlapping offsets collapse to one candidate, whose
|
|
311
292
|
* `span` covers every box that produced it.
|
|
312
|
-
* Poses go through
|
|
313
|
-
*
|
|
293
|
+
* Poses go through `opts.poseDescriptor`, so a rotated sibling advertises
|
|
294
|
+
* its ink edges rather than its stored box.
|
|
295
|
+
* The moving selection is measured with its stroke (`drawnBoundsOf`), so
|
|
296
|
+
* pass each sibling's `drawnAABBOf` box as its target for the two to agree.
|
|
314
297
|
* The lines are in the camera's world: a sibling on a parallax layer needs
|
|
315
298
|
* `planeOf` to say which plane its pose is in. */
|
|
316
299
|
declare function deriveAlignmentGuides<TPose = Bounds>(targets: readonly TPose[], opts?: DeriveAlignmentGuidesOptions<TPose>): Guide[];
|
|
317
300
|
|
|
318
|
-
/** Move/insert test all three features per axis. */
|
|
319
|
-
declare const MOVE_ANCHORS: {
|
|
320
|
-
x: readonly AlignAnchor[];
|
|
321
|
-
y: readonly AlignAnchor[];
|
|
322
|
-
};
|
|
323
|
-
/**
|
|
324
|
-
* Match a moving box's selected edge/center features against candidate guide
|
|
325
|
-
* lines. Returns the per-axis snap delta and the matched candidate line(s).
|
|
326
|
-
* The two axes resolve independently; on each axis the closest in-tolerance
|
|
327
|
-
* (feature, candidate) pair wins. A matched guide that carries a `span` comes
|
|
328
|
-
* back with it stretched to cover the snapped box, so the drawn segment runs
|
|
329
|
-
* from the aligned siblings to the box being dragged.
|
|
330
|
-
*
|
|
331
|
-
* `worldTolerance` is per axis because a screen-pixel tolerance is not one
|
|
332
|
-
* world distance under non-uniform zoom. Pass the same number twice for a
|
|
333
|
-
* world-space tolerance.
|
|
334
|
-
*/
|
|
335
|
-
declare function matchAlignment(bounds: Bounds, candidates: readonly Guide[], worldTolerance: {
|
|
336
|
-
x: number;
|
|
337
|
-
y: number;
|
|
338
|
-
}, anchors: {
|
|
339
|
-
x: readonly AlignAnchor[];
|
|
340
|
-
y: readonly AlignAnchor[];
|
|
341
|
-
}): AlignMatchResult;
|
|
342
|
-
|
|
343
301
|
/**
|
|
344
302
|
* The visible gaps between neighboring boxes along `axis`: for `'x'`, each box
|
|
345
303
|
* and the nearest box to its right that shares some of its vertical range, as
|
|
@@ -368,64 +326,159 @@ declare function matchSpacing(bounds: Bounds, targets: readonly Bounds[], worldT
|
|
|
368
326
|
y: SpacingEdge | null;
|
|
369
327
|
}): SpacingMatchResult;
|
|
370
328
|
|
|
371
|
-
/** Options
|
|
372
|
-
interface
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
* candidates, shaping the proposed translate. The gesture applies the
|
|
377
|
-
* transform uniformly to every dragged id, so the selection shifts together
|
|
378
|
-
* and stays rigid. Single-select is the degenerate one-box union. Publishes
|
|
379
|
-
* the matched line(s); clears on miss, end and cancel. */
|
|
380
|
-
declare function alignMoveBehavior<TPose>(given: AlignMoveArgs<TPose>): MoveBehavior<TPose>;
|
|
381
|
-
/** Insert behavior: snap the live `current` point to candidates (treating it
|
|
382
|
-
* as a zero-size box). Publishes the matched line(s). */
|
|
383
|
-
declare function alignInsertBehavior<TPose>(given: AlignmentBehaviorBase): InsertBehavior<TPose>;
|
|
384
|
-
/** Resize constraint: snap the corner(s) the drag moves, as drawn, to
|
|
385
|
-
* candidates; the pinned corner stays fixed. On an unrotated pose that is
|
|
386
|
-
* the moving edge(s). On a rotated one the node's own axes set how the
|
|
387
|
-
* corner can travel: a corner handle snaps each world axis, an edge handle
|
|
388
|
-
* slides its edge until the nearer of its two corners meets a line.
|
|
389
|
-
* `poseDescriptor` reads the origin pose's box and rotation, and must match
|
|
390
|
-
* the resize action's. Publishes the matched line(s). */
|
|
391
|
-
declare function alignResizeBehavior<TPose extends Bounds>(given: AlignMoveArgs<TPose>): BoundsConstraint<TPose>;
|
|
392
|
-
|
|
393
|
-
/** Default snap tolerance (screen pixels). */
|
|
394
|
-
declare const DEFAULT_GUIDE_TOLERANCE_PX = 6;
|
|
395
|
-
/** Options for `guideSnapStrategy`. */
|
|
396
|
-
interface GuideSnapOptions<TPose> {
|
|
397
|
-
/**
|
|
398
|
-
* Tolerance in screen pixels, divided by the gesture view's scale so the
|
|
399
|
-
* trigger zone stays the same on screen at every zoom. Defaults to
|
|
400
|
-
* `DEFAULT_GUIDE_TOLERANCE_PX`.
|
|
401
|
-
*/
|
|
402
|
-
tolerance?: number;
|
|
403
|
-
/**
|
|
404
|
-
* Projection used when `TPose` doesn't expose `{x, y}` directly (Path,
|
|
405
|
-
* polygon, etc.) — same contract as `gridSnapStrategy`. Defaults to the
|
|
406
|
-
* rect-pose identity projection.
|
|
407
|
-
*/
|
|
408
|
-
origin?: OriginProjection<TPose>;
|
|
329
|
+
/** Options shared by the scene readers below. */
|
|
330
|
+
interface SceneBoundsOptions {
|
|
331
|
+
/** How to read a pose's box. Pass the canvas's, so these agree with what it
|
|
332
|
+
* draws. Default `AUTO_POSE_DESCRIPTOR`. */
|
|
333
|
+
poseDescriptor?: PoseDescriptor<unknown>;
|
|
409
334
|
}
|
|
335
|
+
/** The world box each id is drawn in, rotation included, skipping ids the
|
|
336
|
+
* scene no longer holds. Read through the scene's composition. */
|
|
337
|
+
declare function worldBoundsOf(scene: Scene<unknown, string, unknown>, ids: Iterable<NodeId>, opts?: SceneBoundsOptions): Bounds[];
|
|
338
|
+
/** The union of `ids`' world boxes, or null when none is in the scene. */
|
|
339
|
+
declare function worldUnionOf(scene: Scene<unknown, string, unknown>, ids: Iterable<NodeId>, opts?: SceneBoundsOptions): Bounds | null;
|
|
410
340
|
/**
|
|
411
|
-
*
|
|
412
|
-
*
|
|
413
|
-
* a vertical guide (`axis: 'x'`) constrains X, a horizontal guide
|
|
414
|
-
* (`axis: 'y'`) constrains Y. When multiple guides are within range on the
|
|
415
|
-
* same axis, the closest wins.
|
|
416
|
-
*
|
|
417
|
-
* Pair with `useGuides` for storage and `createGuidesLayer` for rendering.
|
|
418
|
-
* Combining with `gridSnapStrategy` is left to the consumer.
|
|
341
|
+
* The world boxes of `ids`' siblings ({@link siblingIds}). What an
|
|
342
|
+
* equal-spacing snap measures gaps between while `ids` move.
|
|
419
343
|
*/
|
|
420
|
-
declare function
|
|
344
|
+
declare function siblingBounds(scene: Scene<unknown, string, unknown>, ids: readonly NodeId[], opts?: SceneBoundsOptions): Bounds[];
|
|
345
|
+
|
|
346
|
+
type Point = {
|
|
421
347
|
x: number;
|
|
422
348
|
y: number;
|
|
423
|
-
}
|
|
424
|
-
/**
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
349
|
+
};
|
|
350
|
+
/** Options for `gridSnapSource`. */
|
|
351
|
+
interface GridSnapSourceOptions {
|
|
352
|
+
/** The grid's pitch, or one per axis, in `unitSystem`'s units. */
|
|
353
|
+
spacing: PlaneValue;
|
|
354
|
+
/** A point the lattice passes through. Default `(0, 0)`. */
|
|
355
|
+
origin?: Point;
|
|
356
|
+
unitSystem?: PlaneUnits;
|
|
357
|
+
}
|
|
358
|
+
/**
|
|
359
|
+
* A grid as snap targets: for each origin or pointer probe, the grid line on
|
|
360
|
+
* either side of it on each axis. Its reach is unlimited and it is a
|
|
361
|
+
* fallback, so it holds every axis no target claims and never displaces one.
|
|
362
|
+
* Its lines are the camera's, carried into the plane a gesture runs in.
|
|
363
|
+
*/
|
|
364
|
+
declare function gridSnapSource(opts: GridSnapSourceOptions): SnapSource;
|
|
365
|
+
|
|
366
|
+
/**
|
|
367
|
+
* Ruler guides as snap targets: each guide within reach of an origin or
|
|
368
|
+
* pointer probe is a line it may land on. Reads `getGuides` every frame, so
|
|
369
|
+
* a guide added mid-drag counts at once.
|
|
370
|
+
*/
|
|
371
|
+
declare function guideSnapSource(getGuides: () => readonly Guide[]): SnapSource;
|
|
372
|
+
|
|
373
|
+
/** Options for `alignmentSnapSource`. */
|
|
374
|
+
interface AlignmentSnapSourceOptions {
|
|
375
|
+
/** A page box whose edges and center are lines too, in the camera's world. */
|
|
376
|
+
page?: Bounds | (() => Bounds | null | undefined);
|
|
377
|
+
/** The lines to align to, in place of the edges and centers of the
|
|
378
|
+
* subject's siblings (of the scene's top-level nodes, for a point gesture). */
|
|
379
|
+
getCandidates?: () => readonly Guide[];
|
|
380
|
+
/** The color of the lines it marks. Default: the readout layer's. */
|
|
381
|
+
color?: string;
|
|
382
|
+
/** Overrides the canvas's reach for these targets, in screen px. */
|
|
383
|
+
reachPx?: number;
|
|
384
|
+
}
|
|
385
|
+
/**
|
|
386
|
+
* The edges and centers of the subject's siblings, and optionally a page, as
|
|
387
|
+
* snap targets: each is a line a box or pointer probe may land on. A move's
|
|
388
|
+
* left, center and right (top, center, bottom) all try every line, as Figma's
|
|
389
|
+
* smart guides do. When the result meets a line, its mark runs from the
|
|
390
|
+
* subject's box to the farthest sibling on that line.
|
|
391
|
+
*/
|
|
392
|
+
declare function alignmentSnapSource(opts?: AlignmentSnapSourceOptions): SnapSource;
|
|
393
|
+
|
|
394
|
+
/** Options for `spacingSnapSource`. */
|
|
395
|
+
interface SpacingSnapSourceOptions {
|
|
396
|
+
/** The boxes to measure gaps between, in place of the subject's siblings. */
|
|
397
|
+
getTargets?: () => readonly Bounds[];
|
|
398
|
+
/** The color of the gaps it marks. Default: the readout layer's. */
|
|
399
|
+
color?: string;
|
|
400
|
+
/** Overrides the canvas's reach for these targets, in screen px. */
|
|
401
|
+
reachPx?: number;
|
|
402
|
+
}
|
|
403
|
+
/**
|
|
404
|
+
* Equal spacing as snap targets, Figma's: on each axis, the positions of the
|
|
405
|
+
* subject's box that make its gap to a neighbor equal one already between
|
|
406
|
+
* two siblings, or center it between its two neighbors. A resize moves only
|
|
407
|
+
* the edges it drags. When the result meets one, it marks every gap of that
|
|
408
|
+
* size, the box's own included.
|
|
409
|
+
*/
|
|
410
|
+
declare function spacingSnapSource(opts?: SpacingSnapSourceOptions): SnapSource;
|
|
411
|
+
|
|
412
|
+
/** The distances `measureDistances` found, ready for `createGuidesLayer`:
|
|
413
|
+
* `gaps` as its `getGaps`, `leaders` as its `getGuides`. */
|
|
414
|
+
interface DistanceReadout {
|
|
415
|
+
/** One measured distance per gap, labeled with its length when drawn. */
|
|
416
|
+
gaps: SpacingGap[];
|
|
417
|
+
/** Where a gap runs past the target, the line from the gap's end along the
|
|
418
|
+
* target's edge to the target, so the number reads as reaching it. */
|
|
419
|
+
leaders: Guide[];
|
|
420
|
+
}
|
|
421
|
+
/**
|
|
422
|
+
* The distances between two boxes, on each axis where they separate: for
|
|
423
|
+
* `from` left of `to`, the gap from `from`'s right edge to `to`'s left. A gap
|
|
424
|
+
* is drawn through the range the boxes share on the other axis, or through
|
|
425
|
+
* `from`'s center when they share none, with a leader to `to`. When one box
|
|
426
|
+
* holds the other on an axis and they overlap on the other, the inner box's
|
|
427
|
+
* distances to the outer's two edges on that axis instead. An axis where the
|
|
428
|
+
* boxes partly overlap, or meet flush, has no distance.
|
|
429
|
+
*/
|
|
430
|
+
declare function measureDistances(from: Bounds, to: Bounds): DistanceReadout;
|
|
431
|
+
|
|
432
|
+
/** Options for `distanceReadout`. */
|
|
433
|
+
interface DistanceReadoutOptions {
|
|
434
|
+
/** The key held to show the readout. Default `'alt'`. */
|
|
435
|
+
modifier?: 'alt' | 'ctrl' | 'meta' | 'shift';
|
|
436
|
+
/** The color of the marks it writes. Default: the readout layer's. */
|
|
437
|
+
color?: string;
|
|
438
|
+
/** Contribution id, and the prefix of its action's. Default `'distanceReadout'`. */
|
|
439
|
+
id?: string;
|
|
440
|
+
}
|
|
441
|
+
/** What `distanceReadout` returns: a surface contribution, plus a read of
|
|
442
|
+
* what it is showing. */
|
|
443
|
+
interface DistanceReadoutContribution extends SurfaceContribution {
|
|
444
|
+
/** The distances on screen now; empty while hidden. */
|
|
445
|
+
read(): DistanceReadout;
|
|
446
|
+
}
|
|
447
|
+
/**
|
|
448
|
+
* Distance readouts on hover: while `modifier` is held over a shape, the
|
|
449
|
+
* distances from the selection's box to that shape's, on each axis where they
|
|
450
|
+
* separate, measured by `measureDistances` and drawn as labeled gaps. Pass it
|
|
451
|
+
* in `<SceneCanvas ambient>`. It runs on `hover` bindings, so it claims no
|
|
452
|
+
* input, and it reads the canvas's `selection`, `scene`, `nodeAtPoint`,
|
|
453
|
+
* `poseDescriptor`, and `snapReadout` deps. A press hides it.
|
|
454
|
+
*/
|
|
455
|
+
declare function distanceReadout(opts?: DistanceReadoutOptions): DistanceReadoutContribution;
|
|
456
|
+
|
|
457
|
+
/** Options for `createSpacingHintsPreset`. */
|
|
458
|
+
interface SpacingHintsOptions {
|
|
459
|
+
/** Preset id. Default `'spacingHints'`. */
|
|
460
|
+
id?: string;
|
|
461
|
+
/** Snap a move so its gap to a neighbor equals one already between its
|
|
462
|
+
* siblings, and mark the equal gaps. Default true. */
|
|
463
|
+
spacing?: boolean;
|
|
464
|
+
/** Snap to the siblings' edges and centers too, and mark the line met.
|
|
465
|
+
* Default false. */
|
|
466
|
+
align?: boolean;
|
|
467
|
+
/** Snap distance in screen px. Default the canvas's reach. */
|
|
468
|
+
tolerance?: number;
|
|
469
|
+
/** The Alt-hover distance readout, configured, or `false` for none. Default
|
|
470
|
+
* on, with the preset's `color`. */
|
|
471
|
+
readout?: false | Omit<DistanceReadoutOptions, 'color'>;
|
|
472
|
+
/** The color of the marks and the readout. */
|
|
473
|
+
color?: string;
|
|
474
|
+
}
|
|
475
|
+
/**
|
|
476
|
+
* Spacing hints as one `<SceneCanvas features>` preset: snap sources for
|
|
477
|
+
* equal spacing between siblings and, if asked, alignment to their edges
|
|
478
|
+
* and centers, whose marks the canvas's snap readout draws; and holding Alt
|
|
479
|
+
* over a shape measures its distance from the selection.
|
|
480
|
+
*/
|
|
481
|
+
declare function createSpacingHintsPreset(opts?: SpacingHintsOptions): FeaturePreset;
|
|
429
482
|
|
|
430
483
|
/** Snap policy that never picks a target — every drop is rejected, which is
|
|
431
484
|
* what a free-form container wants. */
|
|
@@ -756,4 +809,4 @@ interface Sequencer<TPose> {
|
|
|
756
809
|
*/
|
|
757
810
|
declare function sequenceLayout<TPose>(seq: Sequencer<TPose>): LayoutStrategy<TPose>;
|
|
758
811
|
|
|
759
|
-
export { type
|
|
812
|
+
export { type AlignmentSnapSourceOptions, type Arrangement, type CellHighlightLayerOpts, type DeriveAlignmentGuidesOptions, type DistanceReadout, type DistanceReadoutContribution, type DistanceReadoutOptions, type FreeformOptions, type GridLayerOpts, type GridSlotsOptions, type GridSnapSourceOptions, type Guide, type GuidesLayerOpts, type PackOptions, type PackOverflow, type PerContainerOptions, type PerContainerStrategy, type QuadtreeCell, type QuadtreeOptions, type QuadtreeStrategy, type RingSlotsOptions, type RowSlotsOptions, type SceneBoundsOptions, type Sequencer, type Slot, type SlotsOptions, type SnapPattern, type SnapPointOptions, type SpacingEdge, type SpacingGap, type SpacingHintsOptions, type SpacingMatchResult, type SpacingSnapSourceOptions, type TileGridOptions, type TileGridOverflow, type UseGridCellHoverOptions, type UseGridCellHoverReturn, type UseGuidesReturn, alignmentSnapSource, cellAt, containedThenNearest, createCellHighlightLayer, createGridLayer, createGuidesLayer, createSpacingHintsPreset, deriveAlignmentGuides, distanceReadout, freeform, gridSlots, gridSnapSource, guideSnapSource, matchSpacing, measureDistances, measureGaps, nearest, nearestWithin, none, pack, perContainer, pointToGridCell, quadtree, ringSlots, roundToCell, rowSlots, sequenceLayout, siblingBounds, slots, snapPoint, spacingSnapSource, tileGrid, useGridCellHover, useGuides, worldBoundsOf, worldUnionOf };
|