lineadraw 0.1.0 → 0.2.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.
Files changed (2) hide show
  1. package/lineadraw.d.ts +1180 -787
  2. package/package.json +18 -18
package/lineadraw.d.ts CHANGED
@@ -1,787 +1,1180 @@
1
- // GENERATED — do not edit. Typings for the virtual "lineadraw" and
2
- // "lineadraw/helpers" modules block scripts import from, emitted from
3
- // packages/core/src/blocks/{blockTypes,blockHelpers}.ts. Regenerate with:
4
- // npm run gen:lineadraw-dts -w @lineadraw/core
5
-
6
- declare module "lineadraw" {
7
- /** A 2D point (mm, y-up). Point-valued fields also accept [x, y]. */
8
- export type Vec2 = {
9
- x: number;
10
- y: number;
11
- };
12
- export type Vec2Like = Vec2 | readonly [number, number];
13
- /** Polyline vertex; bulge = tan(sweep/4), 0 = straight. Accepts [x, y, bulge?]. */
14
- export type PolylineVertexLike = {
15
- x: number;
16
- y: number;
17
- bulge?: number;
18
- } | readonly [number, number, number?];
19
- /** Style overrides children may carry (otherwise inherited from the instance). */
20
- export type BaseStyle = {
21
- /** #rrggbb; absent = by layer. */
22
- color?: string;
23
- /** Line type; absent = by layer. */
24
- lineType?: string;
25
- /** Dash-pattern length multiplier; absent = 1. */
26
- lineTypeScale?: number;
27
- /** Line weight in mm; absent = by layer. */
28
- lineWidth?: number;
29
- };
30
- /**
31
- * T plus the shared style fields, FLATTENED (the homomorphic map forces the
32
- * intersection to resolve): hovers then list every member inline instead of
33
- * the opaque `BaseStyle & { … }` — the block editor has no expand-type
34
- * affordance, so the alias display is all a script author gets.
35
- */
36
- type Styled<T> = {
37
- [K in keyof (T & BaseStyle)]: (T & BaseStyle)[K];
38
- } & {};
39
- export type Line = Styled<{
40
- type: "line";
41
- a: Vec2Like;
42
- b: Vec2Like;
43
- }>;
44
- export type Polyline = Styled<{
45
- type: "polyline";
46
- /** At least 2 vertices. */
47
- points: readonly PolylineVertexLike[];
48
- closed?: boolean;
49
- }>;
50
- export type Circle = Styled<{
51
- type: "circle";
52
- center: Vec2Like;
53
- radius: number;
54
- }>;
55
- /** Runs CCW from startAngle to endAngle (radians; DXF ARC convention). */
56
- export type Arc = Styled<{
57
- type: "arc";
58
- center: Vec2Like;
59
- radius: number;
60
- startAngle: number;
61
- endAngle: number;
62
- }>;
63
- /** majorAxis = endpoint vector from center; ratio = minor/major in (0, 1]. */
64
- export type Ellipse = Styled<{
65
- type: "ellipse";
66
- center: Vec2Like;
67
- majorAxis: Vec2Like;
68
- ratio: number;
69
- startAngle?: number;
70
- endAngle?: number;
71
- }>;
72
- export type Hatch = Styled<{
73
- type: "hatch";
74
- /** loops[0] = outer boundary, the rest are holes (even-odd). */
75
- loops: readonly {
76
- points: readonly PolylineVertexLike[];
77
- }[];
78
- fill?: {
79
- kind: "solid";
80
- } | {
81
- kind: "lines";
82
- angle: number;
83
- spacing: number;
84
- };
85
- /** Pattern spacing multiplier. */
86
- scale?: number;
87
- }>;
88
- export type Text = Styled<{
89
- type: "text";
90
- position: Vec2Like;
91
- content: string;
92
- rotation?: number;
93
- /** Where the text SITS relative to the point. */
94
- hAlign?: "left" | "center" | "right";
95
- vAlign?: "bottom" | "center" | "top";
96
- /** MLEADER-style arrow polylines pointing at the text (arrowhead at [0]). */
97
- leaderLines?: readonly (readonly Vec2Like[])[];
98
- /** Style overrides; absent keys inherit the document text style. */
99
- styleOverride?: {
100
- font?: string;
101
- widthFactor?: number;
102
- /** Cap height in mm (before `scale`). */
103
- textHeight?: number;
104
- arrowSize?: number;
105
- arrowType?: "filled" | "open" | "tick" | "dot" | "none";
106
- };
107
- /** Size multiplier for height + arrow size. */
108
- scale?: number;
109
- }>;
110
- export type Dimension = Styled<{
111
- type: "dimension";
112
- kind?: "linear" | "angular" | "radial" | "diameter";
113
- /** linear: 2+ chained points (measured point to point); angular: [vertex, a, b]; radial: [center, p]; diameter: [p1, p2]. */
114
- points: readonly Vec2Like[];
115
- /** Dimension line offset from the kind's anchor (points[0]; diameter: the
116
- * points' midpoint). anchor + offset lies on the dimension line (angular:
117
- * on the arc; radial/diameter: at the text). */
118
- offset: Vec2Like;
119
- textOverride?: string;
120
- styleOverride?: {
121
- textHeight?: number;
122
- arrowSize?: number;
123
- arrowType?: "filled" | "open" | "tick" | "dot" | "none";
124
- /** "short" = a 2×overshoot tick across the dimension line. */
125
- extensionType?: "long" | "short";
126
- extensionOffset?: number;
127
- extensionOvershoot?: number;
128
- textOffset?: number;
129
- precision?: number;
130
- };
131
- /** Annotation size multiplier (text/arrows/offsets). */
132
- scale?: number;
133
- }>;
134
- /** Nested block instance (inputs may hold points, never object references). */
135
- export type Block = Styled<{
136
- type: "block";
137
- definitionId: string;
138
- /** Applied last, about the pivot (the first input point). */
139
- rotation?: number;
140
- scale?: number;
141
- params?: Record<string, number | string | boolean>;
142
- /** Input points in the PARENT's local coords; the first is the pivot. */
143
- inputs?: readonly Vec2Like[];
144
- }>;
145
- export type ModelObject = Line | Polyline | Circle | Arc | Ellipse | Hatch | Text | Dimension | Block;
146
- /**
147
- * One choice of a "Select" parameter: the value (what scripts receive) with
148
- * an optional properties-panel label. A plain string is shorthand for
149
- * `{ value }`.
150
- */
151
- export type ParameterOption = string | {
152
- value: string;
153
- label?: string;
154
- };
155
- /**
156
- * One entry of the module's optional `params` export — the block's
157
- * parameters table. `name` is the key scripts read from `params`, `label`
158
- * the properties-panel caption (defaults to the name).
159
- */
160
- export type ParamDef = {
161
- name: string;
162
- label?: string;
163
- type: "number";
164
- default: number;
165
- min?: number;
166
- max?: number;
167
- } | {
168
- name: string;
169
- label?: string;
170
- type: "string";
171
- default: string;
172
- } | {
173
- name: string;
174
- label?: string;
175
- type: "boolean";
176
- default: boolean;
177
- } | {
178
- name: string;
179
- label?: string;
180
- type: "enum";
181
- default: string;
182
- options: readonly ParameterOption[];
183
- };
184
- /**
185
- * The block's parameters table — what the `params` member of a BlockSpec
186
- * declares (or its function form returns).
187
- */
188
- export type BlockParamDefs = readonly ParamDef[];
189
- /** What the script's `draw` export must return. */
190
- export type BlockScriptResult = ModelObject[];
191
- /** The value an enum option denotes (its string, or `value` of the record form). */
192
- type OptionValue<O extends ParameterOption> = O extends string ? O : O extends {
193
- value: infer V extends string;
194
- } ? V : never;
195
- /** The runtime value type of one `params` table entry. */
196
- type ParamValue<Q extends ParamDef> = Q extends {
197
- type: "enum";
198
- } ? OptionValue<Q["options"][number]> : Q extends {
199
- type: "number";
200
- } ? number : Q extends {
201
- type: "boolean";
202
- } ? boolean : string;
203
- /**
204
- * The values record a params table produces: each entry's `name` maps to
205
- * its runtime value type (number/string/boolean, or the enum's option
206
- * union). This is what `draw`/`place`/`paramVisibility` receive as
207
- * `params` — inside defineBlock the table type is inferred, so authors
208
- * never spell this out. Unwraps the function form of `params`; a non-table
209
- * type (an already-derived values record, or the open BlockParams default)
210
- * passes through unchanged.
211
- */
212
- export type ParamValues<P> = P extends () => infer R ? ParamValues<R> : P extends readonly (infer Q extends ParamDef)[] ? {
213
- readonly [E in Q as E["name"]]: ParamValue<E>;
214
- } : P;
215
-
216
- // ——— Script contract ———
217
-
218
- // #region BlockParams
219
- /**
220
- * The open fallback for a block's parameter values, by name. Inside
221
- * defineBlock the precise per-parameter types are inferred from the
222
- * `params` member, so this record is only what untyped contexts see.
223
- */
224
- export interface BlockParams {
225
- readonly [name: string]: string | number | boolean;
226
- }
227
- // #endregion BlockParams
228
-
229
- /**
230
- * The inputs `place` acquired at insertion, in pick order: points
231
- * (localized against the first point — the pivot) or object ids.
232
- */
233
- export type BlockInputs = readonly (Vec2 | string)[];
234
-
235
- /**
236
- * The argument of an interactive `place` — runs once at insertion;
237
- * await the pickers for whatever inputs the block needs and return them
238
- * as an array (catch the pick rejection to end an open-ended collection
239
- * when the user presses Escape). `params` holds the DEFAULT values (the
240
- * instance doesn't exist yet).
241
- */
242
- export interface PlaceProps<P = BlockParams> {
243
- params: ParamValues<P>;
244
- pickPoint: (label?: string) => Promise<Vec2>;
245
- pickObject: (label?: string) => Promise<string>;
246
- }
247
-
248
- // ——— defineBlock ———
249
-
250
- /**
251
- * What the `place` member of a BlockSpec accepts: an array of point
252
- * labels — the runtime picks one point per label, in order — or the same
253
- * interactive function a module-level `place` export would be.
254
- */
255
- export type PlaceSpec<P = BlockParams> =
256
- | readonly string[]
257
- | ((props: PlaceProps<P>) => BlockInputs | Promise<BlockInputs>);
258
-
259
- /**
260
- * The inputs `draw` receives for a given `place` member: a label tuple
261
- * maps to a Vec2 tuple of the same length, a function contributes its
262
- * (awaited) return type, and an absent `place` is the single
263
- * "Insertion point" pick. The undefined case is checked FIRST and
264
- * non-distributively: without strictNullChecks (e.g. a lax host config),
265
- * `undefined extends readonly string[]` is true and the homomorphic
266
- * mapped type would collapse to `undefined`.
267
- */
268
- export type PlaceInputs<Pl> = [Pl] extends [undefined]
269
- ? readonly [Vec2]
270
- : Pl extends readonly string[]
271
- ? { readonly [K in keyof Pl]: Vec2 }
272
- : Pl extends (...args: never) => infer R
273
- ? Awaited<R> extends BlockInputs
274
- ? Readonly<Awaited<R>>
275
- : BlockInputs
276
- : readonly [Vec2];
277
-
278
- /**
279
- * One block as a single object: the same members the module-level
280
- * exports declare, gathered so TypeScript infers ACROSS them — `params`
281
- * types `draw`'s params, `place` types `draw`'s inputs — with no
282
- * typeof / satisfies / as-const annotations. See defineBlock.
283
- */
284
- export interface BlockSpec<
285
- P extends BlockParamDefs = readonly [],
286
- Pl extends PlaceSpec<P> | undefined = undefined,
287
- > {
288
- id: string;
289
- name: string;
290
- version?: string;
291
- description?: string;
292
- tags?: readonly string[];
293
- authors?: readonly string[];
294
- /** The parameter table, or a function returning it (data-at-end). */
295
- params?: P | (() => P);
296
- /**
297
- * Per-parameter visibility from the current values — pure, re-run per
298
- * properties-panel render. Names omitted stay visible; `false` hides
299
- * the row (the hidden value is KEPT and still reaches `draw`).
300
- */
301
- paramVisibility?: (props: {
302
- params: ParamValues<P>;
303
- }) => Partial<Record<keyof ParamValues<P> & string, boolean>>;
304
- /** Point labels (fixed picks) or an interactive function (see PlaceSpec). */
305
- place?: Pl;
306
- /**
307
- * Children in block-LOCAL coordinates (pure, runs per evaluation).
308
- * The first point input is the pivot; `inputs` arrive localized
309
- * against it, and the instance's rotation/scale apply last, about it.
310
- */
311
- draw: (props: {
312
- params: ParamValues<P>;
313
- inputs: PlaceInputs<Pl>;
314
- }) => BlockScriptResult;
315
- }
316
-
317
- /**
318
- * The recommended way to author a block: one call, one object, full
319
- * inference — no `typeof params`, no `satisfies`, no `as const`.
320
- *
321
- * import { defineBlock } from "lineadraw";
322
- *
323
- * export default defineBlock({
324
- * id: "…",
325
- * name: "Surface",
326
- * params: [
327
- * { name: "type", type: "enum", default: "rock", options: ["rock", "ground"] },
328
- * ],
329
- * place: ["Start point", "End point"],
330
- * draw: ({ params, inputs: [start, end] }) => {
331
- * params.type; // "rock" | "ground"
332
- * return [{ type: "line", a: start, b: end }];
333
- * },
334
- * });
335
- *
336
- * At runtime defineBlock is the identity function. The module-level
337
- * export form remains fully supported — a default-exported BlockSpec and
338
- * plain named exports describe the same block.
339
- */
340
- export function defineBlock<
341
- const P extends BlockParamDefs = readonly [],
342
- const L extends readonly string[] | undefined = undefined,
343
- >(spec: BlockSpec<P, L>): BlockSpec<P, L>;
344
- // Function-form place: the props type is concrete (from P) and only the
345
- // RETURN is inferred — inferring a whole context-sensitive function into
346
- // a type parameter would fall back to its default.
347
- export function defineBlock<
348
- const P extends BlockParamDefs = readonly [],
349
- const R extends BlockInputs | Promise<BlockInputs> = BlockInputs,
350
- >(
351
- spec: BlockSpec<P, (props: PlaceProps<P>) => R>,
352
- ): BlockSpec<P, (props: PlaceProps<P>) => R>;
353
-
354
- // ——— Commands (macro scripts) ———
355
-
356
- /** An axis-aligned box in world mm. */
357
- export type Box = { minX: number; minY: number; maxX: number; maxY: number };
358
-
359
- /** Filters for CommandDocument.query — all present filters AND together. */
360
- export interface ObjectQuery {
361
- ids?: readonly string[];
362
- type?: ModelObject["type"];
363
- /** Layer name or id. */
364
- layer?: string;
365
- /** #rrggbb override (objects without one inherit from their layer). */
366
- color?: string;
367
- lineType?: string;
368
- /** Substring match on text content. */
369
- content?: string;
370
- /** Bounds intersect this box. */
371
- bbox?: Box;
372
- /** Bounds entirely inside this box. */
373
- inside?: Box;
374
- /** Geometry within `tol` mm of `point`. */
375
- near?: { point: Vec2Like; tol: number };
376
- }
377
-
378
- /** A STORED object as query() returns it: the DTO shape plus identity. */
379
- export type ExistingObject = ModelObject & { id: string; layerId: string };
380
-
381
- /** Per-object measurements; null where the type has no natural value. */
382
- export type Measurement = {
383
- bbox: Box | null;
384
- length: number | null;
385
- area: number | null;
386
- };
387
-
388
- /**
389
- * The document as command scripts see it — the same session surface the
390
- * agent tools are written against. Angles are RADIANS, point-valued
391
- * arguments accept {x, y} or [x, y], `layer` resolves by name or id.
392
- * Object mutations target the ACTIVE space. Methods throw on invalid
393
- * input (an uncaught throw cancels the command and rolls its edits back).
394
- */
395
- export interface CommandDocument {
396
- /** Add objects (each may carry `layer` — a name — instead of an id);
397
- * returns the created ids. */
398
- add(
399
- objects: readonly (ModelObject & { layer?: string })[],
400
- opts?: { layout?: string },
401
- ): string[];
402
- /** Apply per-object patches (`{ id, ...changedFields }`). */
403
- update(entries: readonly ({ id: string } & Record<string, unknown>)[]): void;
404
- /** Delete by id (unknown ids are skipped); returns how many went. */
405
- remove(ids: readonly string[]): number;
406
- move(ids: readonly string[], delta: Vec2Like): void;
407
- rotate(ids: readonly string[], angleRad: number, center?: Vec2Like): void;
408
- scale(ids: readonly string[], factor: number, center?: Vec2Like): void;
409
- mirror(ids: readonly string[], axisA: Vec2Like, axisB: Vec2Like): void;
410
- /** Duplicate displaced by delta; returns the new ids. */
411
- copy(ids: readonly string[], delta: Vec2Like): string[];
412
- /** count TOTAL copies at multiples of delta; returns the new ids. */
413
- array(ids: readonly string[], count: number, delta: Vec2Like): string[];
414
- /** Filtered MODEL-space objects. */
415
- query(filter: ObjectQuery): ExistingObject[];
416
- /** bbox / curve length / enclosed area of one object. */
417
- measure(id: string): Measurement;
418
- listLayers(): {
419
- id: string;
420
- name: string;
421
- current: boolean;
422
- [key: string]: unknown;
423
- }[];
424
- /** Create a layer (unique name); returns its id. */
425
- addLayer(
426
- props: { name: string; color?: string } & Record<string, unknown>,
427
- ): string;
428
- updateLayer(nameOrId: string, patch: Record<string, unknown>): void;
429
- /** Remove an EMPTY, non-current layer. */
430
- removeLayer(nameOrId: string): void;
431
- setCurrentLayer(nameOrId: string): void;
432
- /** Create a paper layout; returns its id. `scale` accepts "1:50". */
433
- createLayout(
434
- name: string,
435
- opts: {
436
- sheet?: "A4" | "A3" | "A2" | "A1" | "A0" | { width: number; height: number };
437
- orientation?: "portrait" | "landscape";
438
- scale?: string;
439
- },
440
- ): string;
441
- /** Counts by type/layer, bbox, layer + layout names. */
442
- summary(): Record<string, unknown>;
443
- }
444
-
445
- /**
446
- * What `run` receives. The pickers and `prompt` REJECT when the user
447
- * cancels (Escape) — let that propagate to abort the command (all edits
448
- * roll back), or catch it to finish an open-ended collection gracefully.
449
- */
450
- export interface CommandContext {
451
- document: CommandDocument;
452
- /** Await one snapped world point. */
453
- pickPoint(label?: string): Promise<Vec2>;
454
- /** Await one object click; resolves the object's id. */
455
- pickObject(label?: string): Promise<string>;
456
- /** Ids currently selected — a snapshot; call again after changes. */
457
- selection(): string[];
458
- setSelection(ids: readonly string[]): void;
459
- /** Await a typed value from a small input dialog. */
460
- prompt(
461
- message: string,
462
- options?: { initial?: string; placeholder?: string },
463
- ): Promise<string>;
464
- showToast(message: string, kind?: "info" | "success" | "error"): void;
465
- }
466
-
467
- /** One user command (macro): identity, metadata, and the `run` body. */
468
- export interface CommandSpec {
469
- id: string;
470
- name: string;
471
- description?: string;
472
- version?: string;
473
- authors?: readonly string[];
474
- tags?: readonly string[];
475
- /**
476
- * The macro body. The whole call is ONE undo step: mutations apply
477
- * live while it runs; cancelling (Escape during a pick/prompt) or an
478
- * uncaught error rolls everything back.
479
- */
480
- run(ctx: CommandContext): void | Promise<void>;
481
- }
482
-
483
- /**
484
- * The way to author a user command: one call, one object. At runtime
485
- * defineCommand is the identity function.
486
- *
487
- * import { defineCommand } from "lineadraw";
488
- *
489
- * export default defineCommand({
490
- * id: "…",
491
- * name: "Number the selected texts",
492
- * run: async ({ document, prompt, selection, showToast }) => {
493
- * const start = Number(await prompt("First number", { initial: "1" }));
494
- * const texts = document
495
- * .query({ ids: selection(), type: "text" });
496
- * texts.forEach((t, i) =>
497
- * document.update([{ id: t.id, content: String(start + i) }]),
498
- * );
499
- * showToast(`Numbered ${texts.length} texts`, "success");
500
- * },
501
- * });
502
- */
503
- export function defineCommand(spec: CommandSpec): CommandSpec;
504
- }
505
-
506
- declare module "lineadraw/helpers" {
507
- /** A 2D point (mm, y-up). A type ALIAS so editor hovers expand its shape. */
508
- export type Vec2 = {
509
- x: number;
510
- y: number;
511
- };
512
- /** [0, 1, ..., n-1] — handy for repeating geometry. */
513
- export const range: (n: number) => number[];
514
- /** Point at `distance` from `p` in direction `angle` (radians, CCW). */
515
- export const polar: (angle: number, distance: number, p?: Vec2) => Vec2;
516
- /** Radians → degrees. */
517
- export const toDeg: (r: number) => number;
518
- /** Degrees → radians. */
519
- export const toRad: (d: number) => number;
520
- /** Length of a vector/point. */
521
- export const len: (p: Vec2) => number;
522
- /** Distance between two points. */
523
- export const dist: (a: Vec2, b: Vec2) => number;
524
- /** Vector/point sum. */
525
- export const add: (a: Vec2, b: Vec2) => Vec2;
526
- /** Vector/point difference (a − b). */
527
- export const sub: (a: Vec2, b: Vec2) => Vec2;
528
- /** Scale a vector by a factor. */
529
- export const scale: (p: Vec2, s: number) => Vec2;
530
- /** Unit vector (a zero vector stays zero). */
531
- export const norm: (p: Vec2) => Vec2;
532
- /** Dot product. */
533
- export const dot: (a: Vec2, b: Vec2) => number;
534
- /** Rotate vector by `angle` (radians, CCW). */
535
- export const rotate: (p: Vec2, angle: number) => Vec2;
536
- /**
537
- * All helpers as one object — what migration-wrapped legacy scripts receive
538
- * via `import { helpers } from "lineadraw"`. New scripts import the named
539
- * functions from "lineadraw/helpers" instead.
540
- */
541
- export const helpers: Readonly<{
542
- range: (n: number) => number[];
543
- polar: (angle: number, distance: number, p?: Vec2) => Vec2;
544
- toDeg: (r: number) => number;
545
- toRad: (d: number) => number;
546
- len: (p: Vec2) => number;
547
- dist: (a: Vec2, b: Vec2) => number;
548
- add: (a: Vec2, b: Vec2) => Vec2;
549
- sub: (a: Vec2, b: Vec2) => Vec2;
550
- scale: (p: Vec2, s: number) => Vec2;
551
- norm: (p: Vec2) => Vec2;
552
- dot: (a: Vec2, b: Vec2) => number;
553
- rotate: (p: Vec2, angle: number) => Vec2;
554
- }>;
555
- }
556
-
557
- // The same declarations again at GLOBAL scope, so scripts can annotate
558
- // without importing. Structurally identical to the "lineadraw" exports, so the
559
- // two mix freely. Requires a DOM-less lib (blocks/tsconfig and the in-app
560
- // editor both use lib es2022) — with lib.dom, `Text` would collide.
561
- /** A 2D point (mm, y-up). Point-valued fields also accept [x, y]. */
562
- type Vec2 = {
563
- x: number;
564
- y: number;
565
- };
566
- type Vec2Like = Vec2 | readonly [number, number];
567
- /** Polyline vertex; bulge = tan(sweep/4), 0 = straight. Accepts [x, y, bulge?]. */
568
- type PolylineVertexLike = {
569
- x: number;
570
- y: number;
571
- bulge?: number;
572
- } | readonly [number, number, number?];
573
- /** Style overrides children may carry (otherwise inherited from the instance). */
574
- type BaseStyle = {
575
- /** #rrggbb; absent = by layer. */
576
- color?: string;
577
- /** Line type; absent = by layer. */
578
- lineType?: string;
579
- /** Dash-pattern length multiplier; absent = 1. */
580
- lineTypeScale?: number;
581
- /** Line weight in mm; absent = by layer. */
582
- lineWidth?: number;
583
- };
584
- /**
585
- * T plus the shared style fields, FLATTENED (the homomorphic map forces the
586
- * intersection to resolve): hovers then list every member inline instead of
587
- * the opaque `BaseStyle & { … }` — the block editor has no expand-type
588
- * affordance, so the alias display is all a script author gets.
589
- */
590
- type Styled<T> = {
591
- [K in keyof (T & BaseStyle)]: (T & BaseStyle)[K];
592
- } & {};
593
- type Line = Styled<{
594
- type: "line";
595
- a: Vec2Like;
596
- b: Vec2Like;
597
- }>;
598
- type Polyline = Styled<{
599
- type: "polyline";
600
- /** At least 2 vertices. */
601
- points: readonly PolylineVertexLike[];
602
- closed?: boolean;
603
- }>;
604
- type Circle = Styled<{
605
- type: "circle";
606
- center: Vec2Like;
607
- radius: number;
608
- }>;
609
- /** Runs CCW from startAngle to endAngle (radians; DXF ARC convention). */
610
- type Arc = Styled<{
611
- type: "arc";
612
- center: Vec2Like;
613
- radius: number;
614
- startAngle: number;
615
- endAngle: number;
616
- }>;
617
- /** majorAxis = endpoint vector from center; ratio = minor/major in (0, 1]. */
618
- type Ellipse = Styled<{
619
- type: "ellipse";
620
- center: Vec2Like;
621
- majorAxis: Vec2Like;
622
- ratio: number;
623
- startAngle?: number;
624
- endAngle?: number;
625
- }>;
626
- type Hatch = Styled<{
627
- type: "hatch";
628
- /** loops[0] = outer boundary, the rest are holes (even-odd). */
629
- loops: readonly {
630
- points: readonly PolylineVertexLike[];
631
- }[];
632
- fill?: {
633
- kind: "solid";
634
- } | {
635
- kind: "lines";
636
- angle: number;
637
- spacing: number;
638
- };
639
- /** Pattern spacing multiplier. */
640
- scale?: number;
641
- }>;
642
- type Text = Styled<{
643
- type: "text";
644
- position: Vec2Like;
645
- content: string;
646
- rotation?: number;
647
- /** Where the text SITS relative to the point. */
648
- hAlign?: "left" | "center" | "right";
649
- vAlign?: "bottom" | "center" | "top";
650
- /** MLEADER-style arrow polylines pointing at the text (arrowhead at [0]). */
651
- leaderLines?: readonly (readonly Vec2Like[])[];
652
- /** Style overrides; absent keys inherit the document text style. */
653
- styleOverride?: {
654
- font?: string;
655
- widthFactor?: number;
656
- /** Cap height in mm (before `scale`). */
657
- textHeight?: number;
658
- arrowSize?: number;
659
- arrowType?: "filled" | "open" | "tick" | "dot" | "none";
660
- };
661
- /** Size multiplier for height + arrow size. */
662
- scale?: number;
663
- }>;
664
- type Dimension = Styled<{
665
- type: "dimension";
666
- kind?: "linear" | "angular" | "radial" | "diameter";
667
- /** linear: 2+ chained points (measured point to point); angular: [vertex, a, b]; radial: [center, p]; diameter: [p1, p2]. */
668
- points: readonly Vec2Like[];
669
- /** Dimension line offset from the kind's anchor (points[0]; diameter: the
670
- * points' midpoint). anchor + offset lies on the dimension line (angular:
671
- * on the arc; radial/diameter: at the text). */
672
- offset: Vec2Like;
673
- textOverride?: string;
674
- styleOverride?: {
675
- textHeight?: number;
676
- arrowSize?: number;
677
- arrowType?: "filled" | "open" | "tick" | "dot" | "none";
678
- /** "short" = a 2×overshoot tick across the dimension line. */
679
- extensionType?: "long" | "short";
680
- extensionOffset?: number;
681
- extensionOvershoot?: number;
682
- textOffset?: number;
683
- precision?: number;
684
- };
685
- /** Annotation size multiplier (text/arrows/offsets). */
686
- scale?: number;
687
- }>;
688
- /** Nested block instance (inputs may hold points, never object references). */
689
- type Block = Styled<{
690
- type: "block";
691
- definitionId: string;
692
- /** Applied last, about the pivot (the first input point). */
693
- rotation?: number;
694
- scale?: number;
695
- params?: Record<string, number | string | boolean>;
696
- /** Input points in the PARENT's local coords; the first is the pivot. */
697
- inputs?: readonly Vec2Like[];
698
- }>;
699
- type ModelObject = Line | Polyline | Circle | Arc | Ellipse | Hatch | Text | Dimension | Block;
700
- /**
701
- * One choice of a "Select" parameter: the value (what scripts receive) with
702
- * an optional properties-panel label. A plain string is shorthand for
703
- * `{ value }`.
704
- */
705
- type ParameterOption = string | {
706
- value: string;
707
- label?: string;
708
- };
709
- /**
710
- * One entry of the module's optional `params` export — the block's
711
- * parameters table. `name` is the key scripts read from `params`, `label`
712
- * the properties-panel caption (defaults to the name).
713
- */
714
- type ParamDef = {
715
- name: string;
716
- label?: string;
717
- type: "number";
718
- default: number;
719
- min?: number;
720
- max?: number;
721
- } | {
722
- name: string;
723
- label?: string;
724
- type: "string";
725
- default: string;
726
- } | {
727
- name: string;
728
- label?: string;
729
- type: "boolean";
730
- default: boolean;
731
- } | {
732
- name: string;
733
- label?: string;
734
- type: "enum";
735
- default: string;
736
- options: readonly ParameterOption[];
737
- };
738
- /**
739
- * The block's parameters table — what the `params` member of a BlockSpec
740
- * declares (or its function form returns).
741
- */
742
- type BlockParamDefs = readonly ParamDef[];
743
- /** What the script's `draw` export must return. */
744
- type BlockScriptResult = ModelObject[];
745
- /** The value an enum option denotes (its string, or `value` of the record form). */
746
- type OptionValue<O extends ParameterOption> = O extends string ? O : O extends {
747
- value: infer V extends string;
748
- } ? V : never;
749
- /** The runtime value type of one `params` table entry. */
750
- type ParamValue<Q extends ParamDef> = Q extends {
751
- type: "enum";
752
- } ? OptionValue<Q["options"][number]> : Q extends {
753
- type: "number";
754
- } ? number : Q extends {
755
- type: "boolean";
756
- } ? boolean : string;
757
- /**
758
- * The values record a params table produces: each entry's `name` maps to
759
- * its runtime value type (number/string/boolean, or the enum's option
760
- * union). This is what `draw`/`place`/`paramVisibility` receive as
761
- * `params` — inside defineBlock the table type is inferred, so authors
762
- * never spell this out. Unwraps the function form of `params`; a non-table
763
- * type (an already-derived values record, or the open BlockParams default)
764
- * passes through unchanged.
765
- */
766
- type ParamValues<P> = P extends () => infer R ? ParamValues<R> : P extends readonly (infer Q extends ParamDef)[] ? {
767
- readonly [E in Q as E["name"]]: ParamValue<E>;
768
- } : P;
769
-
770
- // Script-contract globals: aliases into the module (not re-declarations),
771
- // so the in-app editor's BlockParams substitution flows through them.
772
- declare type BlockParams = import("lineadraw").BlockParams;
773
- declare type BlockInputs = import("lineadraw").BlockInputs;
774
- declare type PlaceProps<P = BlockParams> = import("lineadraw").PlaceProps<P>;
775
- declare type PlaceSpec<P = BlockParams> = import("lineadraw").PlaceSpec<P>;
776
- declare type PlaceInputs<Pl> = import("lineadraw").PlaceInputs<Pl>;
777
- declare type BlockSpec<
778
- P extends import("lineadraw").BlockParamDefs = readonly [],
779
- Pl extends PlaceSpec<P> | undefined = undefined,
780
- > = import("lineadraw").BlockSpec<P, Pl>;
781
- declare type Box = import("lineadraw").Box;
782
- declare type ObjectQuery = import("lineadraw").ObjectQuery;
783
- declare type ExistingObject = import("lineadraw").ExistingObject;
784
- declare type Measurement = import("lineadraw").Measurement;
785
- declare type CommandDocument = import("lineadraw").CommandDocument;
786
- declare type CommandContext = import("lineadraw").CommandContext;
787
- declare type CommandSpec = import("lineadraw").CommandSpec;
1
+ // GENERATED — do not edit. Typings for the virtual "lineadraw" and
2
+ // "lineadraw/helpers" modules block scripts import from, emitted from
3
+ // packages/core/src/blocks/{blockTypes,blockHelpers}.ts. Regenerate with:
4
+ // npm run gen:lineadraw-dts -w @lineadraw/core
5
+
6
+ declare module "lineadraw" {
7
+ /** A 2D point (mm, y-up). Point-valued fields also accept [x, y]. */
8
+ export type Vec2 = {
9
+ x: number;
10
+ y: number;
11
+ };
12
+ export type Vec2Like = Vec2 | readonly [number, number];
13
+ /** Polyline vertex; bulge = tan(sweep/4), 0 = straight. Accepts [x, y, bulge?]. */
14
+ export type PolylineVertexLike = {
15
+ x: number;
16
+ y: number;
17
+ bulge?: number;
18
+ } | readonly [number, number, number?];
19
+ /** Style overrides children may carry (otherwise inherited from the instance). */
20
+ export type BaseStyle = {
21
+ /** #rrggbb; absent = by layer. */
22
+ color?: string;
23
+ /** Line type; absent = by layer. */
24
+ lineType?: string;
25
+ /** Dash-pattern length multiplier; absent = 1. */
26
+ lineTypeScale?: number;
27
+ /** Line weight in mm; absent = by layer. */
28
+ lineWidth?: number;
29
+ };
30
+ /**
31
+ * T plus the shared style fields, FLATTENED (the homomorphic map forces the
32
+ * intersection to resolve): hovers then list every member inline instead of
33
+ * the opaque `BaseStyle & { … }` — the block editor has no expand-type
34
+ * affordance, so the alias display is all a script author gets.
35
+ */
36
+ type Styled<T> = {
37
+ [K in keyof (T & BaseStyle)]: (T & BaseStyle)[K];
38
+ } & {};
39
+ export type Line = Styled<{
40
+ type: "line";
41
+ a: Vec2Like;
42
+ b: Vec2Like;
43
+ }>;
44
+ /** A point: paints as a round dot whose diameter is the lineWidth. */
45
+ export type Point = Styled<{
46
+ type: "point";
47
+ p: Vec2Like;
48
+ }>;
49
+ export type Polyline = Styled<{
50
+ type: "polyline";
51
+ /** At least 2 vertices. */
52
+ points: readonly PolylineVertexLike[];
53
+ closed?: boolean;
54
+ }>;
55
+ export type Circle = Styled<{
56
+ type: "circle";
57
+ center: Vec2Like;
58
+ radius: number;
59
+ }>;
60
+ /** Runs CCW from startAngle to endAngle (radians; DXF ARC convention). */
61
+ export type Arc = Styled<{
62
+ type: "arc";
63
+ center: Vec2Like;
64
+ radius: number;
65
+ startAngle: number;
66
+ endAngle: number;
67
+ }>;
68
+ /** majorAxis = endpoint vector from center; ratio = minor/major in (0, 1]. */
69
+ export type Ellipse = Styled<{
70
+ type: "ellipse";
71
+ center: Vec2Like;
72
+ majorAxis: Vec2Like;
73
+ ratio: number;
74
+ startAngle?: number;
75
+ endAngle?: number;
76
+ }>;
77
+ export type Hatch = Styled<{
78
+ type: "hatch";
79
+ /** loops[0] = outer boundary, the rest are holes (even-odd). */
80
+ loops: readonly {
81
+ points: readonly PolylineVertexLike[];
82
+ }[];
83
+ fill?: {
84
+ kind: "solid";
85
+ } | {
86
+ kind: "lines";
87
+ angle: number;
88
+ spacing: number;
89
+ };
90
+ /** Pattern spacing multiplier. */
91
+ scale?: number;
92
+ }>;
93
+ export type Text = Styled<{
94
+ type: "text";
95
+ position: Vec2Like;
96
+ content: string;
97
+ rotation?: number;
98
+ /** Where the text SITS relative to the point. */
99
+ hAlign?: "left" | "center" | "right";
100
+ vAlign?: "bottom" | "center" | "top";
101
+ /** Word-wrap / frame width in mm (before `scale`); absent = no wrapping. */
102
+ width?: number;
103
+ frame?: "none" | "rectangle" | "bottom";
104
+ /** MLEADER-style arrow polylines pointing at the text (arrowhead at [0]). */
105
+ leaderLines?: readonly (readonly Vec2Like[])[];
106
+ /** Style overrides; absent keys inherit the document text style. */
107
+ styleOverride?: {
108
+ font?: string;
109
+ widthFactor?: number;
110
+ /** Cap height in mm (before `scale`). */
111
+ textHeight?: number;
112
+ arrowSize?: number;
113
+ arrowType?: "filled" | "open" | "tick" | "dot" | "none";
114
+ };
115
+ /** Size multiplier for height + arrow size. */
116
+ scale?: number;
117
+ }>;
118
+ export type Dimension = Styled<{
119
+ type: "dimension";
120
+ kind?: "linear" | "angular" | "radial" | "diameter";
121
+ /** linear: 2+ chained points (measured point to point); angular: [vertex, a, b]; radial: [center, p]; diameter: [p1, p2]. */
122
+ points: readonly Vec2Like[];
123
+ /** Dimension line offset from the kind's anchor (points[0]; diameter: the
124
+ * points' midpoint). anchor + offset lies on the dimension line (angular:
125
+ * on the arc; radial/diameter: at the text). */
126
+ offset: Vec2Like;
127
+ textOverride?: string;
128
+ styleOverride?: {
129
+ textHeight?: number;
130
+ arrowSize?: number;
131
+ arrowType?: "filled" | "open" | "tick" | "dot" | "none";
132
+ /** "short" = a 2×overshoot tick across the dimension line. */
133
+ extensionType?: "long" | "short";
134
+ extensionOffset?: number;
135
+ extensionOvershoot?: number;
136
+ textOffset?: number;
137
+ precision?: number;
138
+ };
139
+ /** Annotation size multiplier (text/arrows/offsets). */
140
+ scale?: number;
141
+ }>;
142
+ /** Nested block instance (inputs may hold points, never object references). */
143
+ export type Block = Styled<{
144
+ type: "block";
145
+ definitionId: string;
146
+ /** Applied last, about the pivot (the first input point). */
147
+ rotation?: number;
148
+ scale?: number;
149
+ params?: Record<string, number | string | boolean>;
150
+ /** Input points in the PARENT's local coords; the first is the pivot. */
151
+ inputs?: readonly Vec2Like[];
152
+ }>;
153
+ export type ModelObject = Line | Point | Polyline | Circle | Arc | Ellipse | Hatch | Text | Dimension | Block;
154
+ /** Identity + shared style fields every stored object carries. */
155
+ export type StoredObjectBase = {
156
+ id: string;
157
+ layerId: string;
158
+ /** #rrggbb override; absent = by layer. */
159
+ color?: string;
160
+ lineType?: string;
161
+ lineTypeScale?: number;
162
+ lineWidth?: number;
163
+ /** Paint opacity 0..1; absent = opaque. */
164
+ opacity?: number;
165
+ };
166
+ /** Flattens base + per-type fields so hovers list every member inline
167
+ * (same trick as Styled<T> for the authoring DTOs). */
168
+ type StoredShape<T> = {
169
+ [K in keyof (T & StoredObjectBase)]: (T & StoredObjectBase)[K];
170
+ } & {};
171
+ /** Stored polyline vertex — bulge always present (default 0 applied). */
172
+ export type StoredPolylineVertex = {
173
+ x: number;
174
+ y: number;
175
+ bulge: number;
176
+ };
177
+ export type StoredLine = StoredShape<{
178
+ type: "line";
179
+ a: Vec2;
180
+ b: Vec2;
181
+ }>;
182
+ export type StoredPoint = StoredShape<{
183
+ type: "point";
184
+ p: Vec2;
185
+ }>;
186
+ export type StoredPolyline = StoredShape<{
187
+ type: "polyline";
188
+ points: readonly StoredPolylineVertex[];
189
+ closed: boolean;
190
+ }>;
191
+ export type StoredCircle = StoredShape<{
192
+ type: "circle";
193
+ center: Vec2;
194
+ radius: number;
195
+ }>;
196
+ export type StoredArc = StoredShape<{
197
+ type: "arc";
198
+ center: Vec2;
199
+ radius: number;
200
+ startAngle: number;
201
+ endAngle: number;
202
+ }>;
203
+ export type StoredEllipse = StoredShape<{
204
+ type: "ellipse";
205
+ center: Vec2;
206
+ majorAxis: Vec2;
207
+ ratio: number;
208
+ startAngle: number;
209
+ endAngle: number;
210
+ }>;
211
+ export type StoredHatchFill = {
212
+ kind: "solid";
213
+ } | {
214
+ kind: "pattern";
215
+ name: string;
216
+ angle: number;
217
+ scale: number;
218
+ } | {
219
+ kind: "lines";
220
+ angle: number;
221
+ spacing: number;
222
+ };
223
+ export type StoredHatch = StoredShape<{
224
+ type: "hatch";
225
+ /** loops[0] = outer boundary, the rest are holes (even-odd). */
226
+ loops: readonly {
227
+ points: readonly StoredPolylineVertex[];
228
+ }[];
229
+ fill: StoredHatchFill;
230
+ scale: number;
231
+ }>;
232
+ export type StoredText = StoredShape<{
233
+ type: "text";
234
+ position: Vec2;
235
+ content: string;
236
+ leaderLines: readonly (readonly Vec2[])[];
237
+ /** Word-wrap / frame width in mm; absent = no wrapping. */
238
+ width?: number;
239
+ hAlign: "left" | "center" | "right";
240
+ vAlign: "bottom" | "center" | "top";
241
+ frame?: "none" | "rectangle" | "bottom";
242
+ styleId?: string;
243
+ /** Only the keys the user actually overrode on this text. */
244
+ styleOverride?: {
245
+ font?: string;
246
+ widthFactor?: number;
247
+ textHeight?: number;
248
+ arrowType?: "filled" | "open" | "tick" | "dot" | "none";
249
+ arrowSize?: number;
250
+ };
251
+ rotation: number;
252
+ scale: number;
253
+ }>;
254
+ export type StoredDimension = StoredShape<{
255
+ type: "dimension";
256
+ kind: "linear" | "angular" | "radial" | "diameter";
257
+ points: readonly Vec2[];
258
+ offset: Vec2;
259
+ textOverride?: string;
260
+ styleId?: string;
261
+ /** Only the keys the user actually overrode on this dimension. */
262
+ styleOverride?: {
263
+ font?: string;
264
+ widthFactor?: number;
265
+ textHeight?: number;
266
+ textOffset?: number;
267
+ arrowType?: "filled" | "open" | "tick" | "dot" | "none";
268
+ arrowSize?: number;
269
+ extensionType?: "long" | "short";
270
+ extensionOffset?: number;
271
+ extensionOvershoot?: number;
272
+ precision?: number;
273
+ };
274
+ scale: number;
275
+ }>;
276
+ export type StoredBlock = StoredShape<{
277
+ type: "block";
278
+ definitionId: string;
279
+ rotation: number;
280
+ scale: number;
281
+ params: Readonly<Record<string, number | string | boolean>>;
282
+ /** World points and/or referenced object ids, in pick order. */
283
+ inputs: readonly (Vec2 | string)[];
284
+ }>;
285
+ /** Paper-space window into model space; exists only in layout spaces. */
286
+ export type StoredViewport = StoredShape<{
287
+ type: "viewport";
288
+ rect: {
289
+ x: number;
290
+ y: number;
291
+ w: number;
292
+ h: number;
293
+ };
294
+ modelCenter: Vec2;
295
+ /** Drawing-scale denominator (model mm per paper mm); 1:50 => 50. */
296
+ scale: number;
297
+ locked: boolean;
298
+ hiddenLayerIds: readonly string[];
299
+ }>;
300
+ /** Raster reference; pixels live in the document's assets map. */
301
+ export type StoredImage = StoredShape<{
302
+ type: "image";
303
+ assetId: string;
304
+ origin: Vec2;
305
+ width: number;
306
+ height: number;
307
+ rotation: number;
308
+ }>;
309
+ /** Any object as stored in the document — what reads hand to scripts. */
310
+ export type StoredObject = StoredLine | StoredPoint | StoredPolyline | StoredCircle | StoredArc | StoredEllipse | StoredHatch | StoredText | StoredDimension | StoredBlock | StoredViewport | StoredImage;
311
+ /**
312
+ * One choice of a "Select" parameter: the value (what scripts receive) with
313
+ * an optional properties-panel label. A plain string is shorthand for
314
+ * `{ value }`.
315
+ */
316
+ export type ParameterOption = string | {
317
+ value: string;
318
+ label?: string;
319
+ };
320
+ /**
321
+ * One entry of the module's optional `params` export — the block's
322
+ * parameters table. `name` is the key scripts read from `params`, `label`
323
+ * the properties-panel caption (defaults to the name).
324
+ */
325
+ export type ParamDef = {
326
+ name: string;
327
+ label?: string;
328
+ type: "number";
329
+ default: number;
330
+ min?: number;
331
+ max?: number;
332
+ } | {
333
+ name: string;
334
+ label?: string;
335
+ type: "string";
336
+ default: string;
337
+ } | {
338
+ name: string;
339
+ label?: string;
340
+ type: "boolean";
341
+ default: boolean;
342
+ } | {
343
+ name: string;
344
+ label?: string;
345
+ type: "enum";
346
+ default: string;
347
+ options: readonly ParameterOption[];
348
+ };
349
+ /**
350
+ * The block's parameters table — what the `params` member of a BlockSpec
351
+ * declares (or its function form returns).
352
+ */
353
+ export type BlockParamDefs = readonly ParamDef[];
354
+ /** What the script's `draw` export must return. */
355
+ export type BlockScriptResult = ModelObject[];
356
+ /** The value an enum option denotes (its string, or `value` of the record form). */
357
+ type OptionValue<O extends ParameterOption> = O extends string ? O : O extends {
358
+ value: infer V extends string;
359
+ } ? V : never;
360
+ /** The runtime value type of one `params` table entry. */
361
+ type ParamValue<Q extends ParamDef> = Q extends {
362
+ type: "enum";
363
+ } ? OptionValue<Q["options"][number]> : Q extends {
364
+ type: "number";
365
+ } ? number : Q extends {
366
+ type: "boolean";
367
+ } ? boolean : string;
368
+ /**
369
+ * The values record a params table produces: each entry's `name` maps to
370
+ * its runtime value type (number/string/boolean, or the enum's option
371
+ * union). This is what `draw`/`place`/`paramVisibility` receive as
372
+ * `params` — inside defineBlock the table type is inferred, so authors
373
+ * never spell this out. Unwraps the function form of `params`; a non-table
374
+ * type (an already-derived values record, or the open BlockParams default)
375
+ * passes through unchanged.
376
+ */
377
+ export type ParamValues<P> = P extends () => infer R ? ParamValues<R> : P extends readonly (infer Q extends ParamDef)[] ? {
378
+ readonly [E in Q as E["name"]]: ParamValue<E>;
379
+ } : P;
380
+
381
+ // ——— Script contract ———
382
+
383
+ // #region BlockParams
384
+ /**
385
+ * The open fallback for a block's parameter values, by name. Inside
386
+ * defineBlock the precise per-parameter types are inferred from the
387
+ * `params` member, so this record is only what untyped contexts see.
388
+ */
389
+ export interface BlockParams {
390
+ readonly [name: string]: string | number | boolean;
391
+ }
392
+ // #endregion BlockParams
393
+
394
+ /**
395
+ * The inputs `place` acquired at insertion, in pick order: points or
396
+ * object ids (what `pickObject` resolved). This is the STORED form —
397
+ * by the time they reach `draw`, ids have been resolved (see
398
+ * ResolvedInput).
399
+ */
400
+ export type BlockInputs = readonly (Vec2 | string)[];
401
+
402
+ /**
403
+ * A referenced document object as `draw` receives it: the STORED record
404
+ * (schema output — defaults applied, points always {x, y}, id/layerId
405
+ * present; see StoredObject), localized against the instance pivot like
406
+ * every point input. Null when the reference no longer resolves (the
407
+ * object was deleted) — handle it or throw (a throw shows as the
408
+ * instance's evaluation error).
409
+ */
410
+ export type ResolvedObject = StoredObject | null;
411
+
412
+ /**
413
+ * How one stored input arrives at `draw`: points pass through
414
+ * (pivot-localized), object ids resolve to the referenced object (or
415
+ * null). Distributes over Vec2 | string for untyped positions.
416
+ */
417
+ export type ResolvedInput<T> = T extends string
418
+ ? ResolvedObject
419
+ : T extends Vec2
420
+ ? T
421
+ : Vec2 | ResolvedObject;
422
+
423
+ /**
424
+ * ResolvedInput applied position-wise. Homomorphic over the bare type
425
+ * parameter ON PURPOSE — inlining `keyof Awaited<R>` into PlaceInputs
426
+ * would map over the array's methods too and destroy tuple-ness.
427
+ */
428
+ export type ResolveInputs<T extends BlockInputs> = {
429
+ readonly [K in keyof T]: ResolvedInput<T[K]>;
430
+ };
431
+
432
+ /**
433
+ * The argument of an interactive `place` — runs once at insertion;
434
+ * await the pickers for whatever inputs the block needs and return them
435
+ * as an array (catch the pick rejection to end an open-ended collection
436
+ * when the user presses Escape). `params` holds the DEFAULT values (the
437
+ * instance doesn't exist yet).
438
+ */
439
+ export interface PlaceProps<P = BlockParams> {
440
+ params: ParamValues<P>;
441
+ pickPoint: (label?: string) => Promise<Vec2>;
442
+ pickObject: (label?: string) => Promise<string>;
443
+ }
444
+
445
+ // ——— defineBlock ———
446
+
447
+ /**
448
+ * What the `place` member of a BlockSpec accepts: an array of point
449
+ * labels — the runtime picks one point per label, in order — or the same
450
+ * interactive function a module-level `place` export would be.
451
+ */
452
+ export type PlaceSpec<P = BlockParams> =
453
+ | readonly string[]
454
+ | ((props: PlaceProps<P>) => BlockInputs | Promise<BlockInputs>);
455
+
456
+ /**
457
+ * The shape `previewInputs` must have for a given `place` member: a
458
+ * label-array place pins the exact tuple length; otherwise any inputs
459
+ * array. Points accept [x, y] tuples for authoring ergonomics.
460
+ */
461
+ export type PreviewInputs<Pl> = Pl extends readonly string[]
462
+ ? { readonly [K in keyof Pl]: Vec2Like }
463
+ : readonly (Vec2Like | string)[];
464
+
465
+ /**
466
+ * The inputs `draw` receives for a given `place` member: a label tuple
467
+ * maps to a Vec2 tuple of the same length, a function contributes its
468
+ * (awaited) return type with every position RESOLVED (string → the
469
+ * referenced object or null, see ResolvedInput), and an absent `place`
470
+ * is the single "Insertion point" pick. The undefined case is checked
471
+ * FIRST and non-distributively: without strictNullChecks (e.g. a lax
472
+ * host config), `undefined extends readonly string[]` is true and the
473
+ * homomorphic mapped type would collapse to `undefined`.
474
+ */
475
+ export type PlaceInputs<Pl> = [Pl] extends [undefined]
476
+ ? readonly [Vec2]
477
+ : Pl extends readonly string[]
478
+ ? { readonly [K in keyof Pl]: Vec2 }
479
+ : Pl extends (...args: never) => infer R
480
+ ? Awaited<R> extends BlockInputs
481
+ ? ResolveInputs<Awaited<R>>
482
+ : readonly (Vec2 | ResolvedObject)[]
483
+ : readonly [Vec2];
484
+
485
+ /**
486
+ * One block as a single object: the same members the module-level
487
+ * exports declare, gathered so TypeScript infers ACROSS them — `params`
488
+ * types `draw`'s params, `place` types `draw`'s inputs — with no
489
+ * typeof / satisfies / as-const annotations. See defineBlock.
490
+ */
491
+ export interface BlockSpec<
492
+ P extends BlockParamDefs = readonly [],
493
+ Pl extends PlaceSpec<P> | undefined = undefined,
494
+ > {
495
+ id: string;
496
+ name: string;
497
+ version?: string;
498
+ description?: string;
499
+ tags?: readonly string[];
500
+ authors?: readonly string[];
501
+ /**
502
+ * Ids of block definitions `draw` emits instances of (e.g.
503
+ * `["@lineadraw/axis"]`). Install, copy/paste, and export bundle the
504
+ * declared closure; the save-time dry run rejects emitted instances
505
+ * that are not declared here.
506
+ */
507
+ dependencies?: readonly string[];
508
+ /** The parameter table, or a function returning it (data-at-end). */
509
+ params?: P | (() => P);
510
+ /**
511
+ * Per-parameter visibility from the current values — pure, re-run per
512
+ * properties-panel render. Names omitted stay visible; `false` hides
513
+ * the row (the hidden value is KEPT and still reaches `draw`).
514
+ */
515
+ paramVisibility?: (props: {
516
+ params: ParamValues<P>;
517
+ }) => Partial<Record<keyof ParamValues<P> & string, boolean>>;
518
+ /** Point labels (fixed picks) or an interactive function (see PlaceSpec). */
519
+ place?: Pl;
520
+ /**
521
+ * Optional inputs used for the block's PREVIEW (panel/Library
522
+ * thumbnails, marketplace cards, save-time dry run) instead of the
523
+ * generic stand-in picks — curate them so the preview shows the block
524
+ * at its best. Same shape `place` produces; points accept [x, y];
525
+ * object-id strings resolve to a stand-in line in previews.
526
+ */
527
+ previewInputs?: PreviewInputs<Pl>;
528
+ /**
529
+ * Children in block-LOCAL coordinates (pure, runs per evaluation).
530
+ * The first point input is the pivot; `inputs` arrive localized
531
+ * against it, and the instance's rotation/scale apply last, about it.
532
+ * Object picks arrive as the referenced object itself (pivot-local,
533
+ * re-evaluated whenever it changes) or null once deleted.
534
+ */
535
+ draw: (props: {
536
+ params: ParamValues<P>;
537
+ inputs: PlaceInputs<Pl>;
538
+ }) => BlockScriptResult;
539
+ }
540
+
541
+ /**
542
+ * The recommended way to author a block: one call, one object, full
543
+ * inference — no `typeof params`, no `satisfies`, no `as const`.
544
+ *
545
+ * import { defineBlock } from "lineadraw";
546
+ *
547
+ * export default defineBlock({
548
+ * id: "…",
549
+ * name: "Surface",
550
+ * params: [
551
+ * { name: "type", type: "enum", default: "rock", options: ["rock", "ground"] },
552
+ * ],
553
+ * place: ["Start point", "End point"],
554
+ * draw: ({ params, inputs: [start, end] }) => {
555
+ * params.type; // "rock" | "ground"
556
+ * return [{ type: "line", a: start, b: end }];
557
+ * },
558
+ * });
559
+ *
560
+ * At runtime defineBlock is the identity function. The module-level
561
+ * export form remains fully supported — a default-exported BlockSpec and
562
+ * plain named exports describe the same block.
563
+ */
564
+ export function defineBlock<
565
+ const P extends BlockParamDefs = readonly [],
566
+ const L extends readonly string[] | undefined = undefined,
567
+ >(spec: BlockSpec<P, L>): BlockSpec<P, L>;
568
+ // Function-form place: the props type is concrete (from P) and only the
569
+ // RETURN is inferred — inferring a whole context-sensitive function into
570
+ // a type parameter would fall back to its default.
571
+ export function defineBlock<
572
+ const P extends BlockParamDefs = readonly [],
573
+ const R extends BlockInputs | Promise<BlockInputs> = BlockInputs,
574
+ >(
575
+ spec: BlockSpec<P, (props: PlaceProps<P>) => R>,
576
+ ): BlockSpec<P, (props: PlaceProps<P>) => R>;
577
+
578
+ // ——— Commands (macro scripts) ———
579
+
580
+ /** An axis-aligned box in world mm. */
581
+ export type Box = { minX: number; minY: number; maxX: number; maxY: number };
582
+
583
+ /** Filters for CommandDocument.query — all present filters AND together. */
584
+ export interface ObjectQuery {
585
+ ids?: readonly string[];
586
+ type?: ModelObject["type"];
587
+ /** Layer name or id. */
588
+ layer?: string;
589
+ /** #rrggbb override (objects without one inherit from their layer). */
590
+ color?: string;
591
+ lineType?: string;
592
+ /** Substring match on text content. */
593
+ content?: string;
594
+ /** Bounds intersect this box. */
595
+ bbox?: Box;
596
+ /** Bounds entirely inside this box. */
597
+ inside?: Box;
598
+ /** Geometry within `tol` mm of `point`. */
599
+ near?: { point: Vec2Like; tol: number };
600
+ }
601
+
602
+ /** A STORED object as query() returns it (see StoredObject — schema
603
+ * output: defaults applied, points always {x, y}, identity present). */
604
+ export type ExistingObject = StoredObject;
605
+
606
+ /** Per-object measurements; null where the type has no natural value. */
607
+ export type Measurement = {
608
+ bbox: Box | null;
609
+ length: number | null;
610
+ area: number | null;
611
+ };
612
+
613
+ /**
614
+ * The document as command scripts see it — the same session surface the
615
+ * agent tools are written against. Angles are RADIANS, point-valued
616
+ * arguments accept {x, y} or [x, y], `layer` resolves by name or id.
617
+ * Object mutations target the ACTIVE space. Methods throw on invalid
618
+ * input (an uncaught throw cancels the command and rolls its edits back).
619
+ */
620
+ export interface CommandDocument {
621
+ /** Add objects (each may carry `layer` — a name — instead of an id);
622
+ * returns the created ids. */
623
+ add(
624
+ objects: readonly (ModelObject & { layer?: string })[],
625
+ opts?: { layout?: string },
626
+ ): string[];
627
+ /** Apply per-object patches (`{ id, ...changedFields }`). */
628
+ update(entries: readonly ({ id: string } & Record<string, unknown>)[]): void;
629
+ /** Delete by id (unknown ids are skipped); returns how many went. */
630
+ remove(ids: readonly string[]): number;
631
+ move(ids: readonly string[], delta: Vec2Like): void;
632
+ rotate(ids: readonly string[], angleRad: number, center?: Vec2Like): void;
633
+ scale(ids: readonly string[], factor: number, center?: Vec2Like): void;
634
+ mirror(ids: readonly string[], axisA: Vec2Like, axisB: Vec2Like): void;
635
+ /** Duplicate displaced by delta; returns the new ids. */
636
+ copy(ids: readonly string[], delta: Vec2Like): string[];
637
+ /** count TOTAL copies at multiples of delta; returns the new ids. */
638
+ array(ids: readonly string[], count: number, delta: Vec2Like): string[];
639
+ /** Filtered MODEL-space objects. */
640
+ query(filter: ObjectQuery): ExistingObject[];
641
+ /** bbox / curve length / enclosed area of one object. */
642
+ measure(id: string): Measurement;
643
+ listLayers(): {
644
+ id: string;
645
+ name: string;
646
+ current: boolean;
647
+ [key: string]: unknown;
648
+ }[];
649
+ /** Create a layer (unique name); returns its id. */
650
+ addLayer(
651
+ props: { name: string; color?: string } & Record<string, unknown>,
652
+ ): string;
653
+ updateLayer(nameOrId: string, patch: Record<string, unknown>): void;
654
+ /** Remove an EMPTY, non-current layer. */
655
+ removeLayer(nameOrId: string): void;
656
+ setCurrentLayer(nameOrId: string): void;
657
+ /** Create a paper layout; returns its id. `scale` accepts "1:50". */
658
+ createLayout(
659
+ name: string,
660
+ opts: {
661
+ sheet?: "A4" | "A3" | "A2" | "A1" | "A0" | { width: number; height: number };
662
+ orientation?: "portrait" | "landscape";
663
+ scale?: string;
664
+ },
665
+ ): string;
666
+ /** Counts by type/layer, bbox, layer + layout names. */
667
+ summary(): Record<string, unknown>;
668
+ }
669
+
670
+ /**
671
+ * What `run` receives. The pickers and `prompt` REJECT when the user
672
+ * cancels (Escape) — let that propagate to abort the command (all edits
673
+ * roll back), or catch it to finish an open-ended collection gracefully.
674
+ */
675
+ export interface CommandContext {
676
+ document: CommandDocument;
677
+ /** Await one snapped world point. */
678
+ pickPoint(label?: string): Promise<Vec2>;
679
+ /** Await one object click; resolves the object's id. */
680
+ pickObject(label?: string): Promise<string>;
681
+ /** Ids currently selected — a snapshot; call again after changes. */
682
+ selection(): string[];
683
+ setSelection(ids: readonly string[]): void;
684
+ /** Await a typed value from a small input dialog. */
685
+ prompt(
686
+ message: string,
687
+ options?: { initial?: string; placeholder?: string },
688
+ ): Promise<string>;
689
+ showToast(message: string, kind?: "info" | "success" | "error"): void;
690
+ }
691
+
692
+ /** One user command (macro): identity, metadata, and the `run` body. */
693
+ export interface CommandSpec {
694
+ id: string;
695
+ name: string;
696
+ description?: string;
697
+ version?: string;
698
+ authors?: readonly string[];
699
+ tags?: readonly string[];
700
+ /**
701
+ * The macro body. The whole call is ONE undo step: mutations apply
702
+ * live while it runs; cancelling (Escape during a pick/prompt) or an
703
+ * uncaught error rolls everything back.
704
+ */
705
+ run(ctx: CommandContext): void | Promise<void>;
706
+ }
707
+
708
+ /**
709
+ * The way to author a user command: one call, one object. At runtime
710
+ * defineCommand is the identity function.
711
+ *
712
+ * import { defineCommand } from "lineadraw";
713
+ *
714
+ * export default defineCommand({
715
+ * id: "…",
716
+ * name: "Number the selected texts",
717
+ * run: async ({ document, prompt, selection, showToast }) => {
718
+ * const start = Number(await prompt("First number", { initial: "1" }));
719
+ * const texts = document
720
+ * .query({ ids: selection(), type: "text" });
721
+ * texts.forEach((t, i) =>
722
+ * document.update([{ id: t.id, content: String(start + i) }]),
723
+ * );
724
+ * showToast(`Numbered ${texts.length} texts`, "success");
725
+ * },
726
+ * });
727
+ */
728
+ export function defineCommand(spec: CommandSpec): CommandSpec;
729
+ }
730
+
731
+ declare module "lineadraw/helpers" {
732
+ /** A 2D point (mm, y-up). A type ALIAS so editor hovers expand its shape. */
733
+ export type Vec2 = {
734
+ x: number;
735
+ y: number;
736
+ };
737
+ /** [0, 1, ..., n-1] — handy for repeating geometry. */
738
+ export const range: (n: number) => number[];
739
+ /** Point at `distance` from `p` in direction `angle` (radians, CCW). */
740
+ export const polar: (angle: number, distance: number, p?: Vec2) => Vec2;
741
+ /** Radians → degrees. */
742
+ export const toDeg: (r: number) => number;
743
+ /** Degrees → radians. */
744
+ export const toRad: (d: number) => number;
745
+ /** Length of a vector/point. */
746
+ export const len: (p: Vec2) => number;
747
+ /** Distance between two points. */
748
+ export const dist: (a: Vec2, b: Vec2) => number;
749
+ /** Vector/point sum. */
750
+ export const add: (a: Vec2, b: Vec2) => Vec2;
751
+ /** Vector/point difference (a − b). */
752
+ export const sub: (a: Vec2, b: Vec2) => Vec2;
753
+ /** Scale a vector by a factor. */
754
+ export const scale: (p: Vec2, s: number) => Vec2;
755
+ /** Unit vector (a zero vector stays zero). */
756
+ export const norm: (p: Vec2) => Vec2;
757
+ /** Dot product. */
758
+ export const dot: (a: Vec2, b: Vec2) => number;
759
+ /** Rotate vector by `angle` (radians, CCW). */
760
+ export const rotate: (p: Vec2, angle: number) => Vec2;
761
+ /**
762
+ * All helpers as one object — what migration-wrapped legacy scripts receive
763
+ * via `import { helpers } from "lineadraw"`. New scripts import the named
764
+ * functions from "lineadraw/helpers" instead.
765
+ */
766
+ export const helpers: Readonly<{
767
+ range: (n: number) => number[];
768
+ polar: (angle: number, distance: number, p?: Vec2) => Vec2;
769
+ toDeg: (r: number) => number;
770
+ toRad: (d: number) => number;
771
+ len: (p: Vec2) => number;
772
+ dist: (a: Vec2, b: Vec2) => number;
773
+ add: (a: Vec2, b: Vec2) => Vec2;
774
+ sub: (a: Vec2, b: Vec2) => Vec2;
775
+ scale: (p: Vec2, s: number) => Vec2;
776
+ norm: (p: Vec2) => Vec2;
777
+ dot: (a: Vec2, b: Vec2) => number;
778
+ rotate: (p: Vec2, angle: number) => Vec2;
779
+ }>;
780
+ }
781
+
782
+ // The same declarations again at GLOBAL scope, so scripts can annotate
783
+ // without importing. Structurally identical to the "lineadraw" exports, so the
784
+ // two mix freely. Requires a DOM-less lib (blocks/tsconfig and the in-app
785
+ // editor both use lib es2022) — with lib.dom, `Text` would collide.
786
+ /** A 2D point (mm, y-up). Point-valued fields also accept [x, y]. */
787
+ type Vec2 = {
788
+ x: number;
789
+ y: number;
790
+ };
791
+ type Vec2Like = Vec2 | readonly [number, number];
792
+ /** Polyline vertex; bulge = tan(sweep/4), 0 = straight. Accepts [x, y, bulge?]. */
793
+ type PolylineVertexLike = {
794
+ x: number;
795
+ y: number;
796
+ bulge?: number;
797
+ } | readonly [number, number, number?];
798
+ /** Style overrides children may carry (otherwise inherited from the instance). */
799
+ type BaseStyle = {
800
+ /** #rrggbb; absent = by layer. */
801
+ color?: string;
802
+ /** Line type; absent = by layer. */
803
+ lineType?: string;
804
+ /** Dash-pattern length multiplier; absent = 1. */
805
+ lineTypeScale?: number;
806
+ /** Line weight in mm; absent = by layer. */
807
+ lineWidth?: number;
808
+ };
809
+ /**
810
+ * T plus the shared style fields, FLATTENED (the homomorphic map forces the
811
+ * intersection to resolve): hovers then list every member inline instead of
812
+ * the opaque `BaseStyle & { … }` — the block editor has no expand-type
813
+ * affordance, so the alias display is all a script author gets.
814
+ */
815
+ type Styled<T> = {
816
+ [K in keyof (T & BaseStyle)]: (T & BaseStyle)[K];
817
+ } & {};
818
+ type Line = Styled<{
819
+ type: "line";
820
+ a: Vec2Like;
821
+ b: Vec2Like;
822
+ }>;
823
+ /** A point: paints as a round dot whose diameter is the lineWidth. */
824
+ type Point = Styled<{
825
+ type: "point";
826
+ p: Vec2Like;
827
+ }>;
828
+ type Polyline = Styled<{
829
+ type: "polyline";
830
+ /** At least 2 vertices. */
831
+ points: readonly PolylineVertexLike[];
832
+ closed?: boolean;
833
+ }>;
834
+ type Circle = Styled<{
835
+ type: "circle";
836
+ center: Vec2Like;
837
+ radius: number;
838
+ }>;
839
+ /** Runs CCW from startAngle to endAngle (radians; DXF ARC convention). */
840
+ type Arc = Styled<{
841
+ type: "arc";
842
+ center: Vec2Like;
843
+ radius: number;
844
+ startAngle: number;
845
+ endAngle: number;
846
+ }>;
847
+ /** majorAxis = endpoint vector from center; ratio = minor/major in (0, 1]. */
848
+ type Ellipse = Styled<{
849
+ type: "ellipse";
850
+ center: Vec2Like;
851
+ majorAxis: Vec2Like;
852
+ ratio: number;
853
+ startAngle?: number;
854
+ endAngle?: number;
855
+ }>;
856
+ type Hatch = Styled<{
857
+ type: "hatch";
858
+ /** loops[0] = outer boundary, the rest are holes (even-odd). */
859
+ loops: readonly {
860
+ points: readonly PolylineVertexLike[];
861
+ }[];
862
+ fill?: {
863
+ kind: "solid";
864
+ } | {
865
+ kind: "lines";
866
+ angle: number;
867
+ spacing: number;
868
+ };
869
+ /** Pattern spacing multiplier. */
870
+ scale?: number;
871
+ }>;
872
+ type Text = Styled<{
873
+ type: "text";
874
+ position: Vec2Like;
875
+ content: string;
876
+ rotation?: number;
877
+ /** Where the text SITS relative to the point. */
878
+ hAlign?: "left" | "center" | "right";
879
+ vAlign?: "bottom" | "center" | "top";
880
+ /** Word-wrap / frame width in mm (before `scale`); absent = no wrapping. */
881
+ width?: number;
882
+ frame?: "none" | "rectangle" | "bottom";
883
+ /** MLEADER-style arrow polylines pointing at the text (arrowhead at [0]). */
884
+ leaderLines?: readonly (readonly Vec2Like[])[];
885
+ /** Style overrides; absent keys inherit the document text style. */
886
+ styleOverride?: {
887
+ font?: string;
888
+ widthFactor?: number;
889
+ /** Cap height in mm (before `scale`). */
890
+ textHeight?: number;
891
+ arrowSize?: number;
892
+ arrowType?: "filled" | "open" | "tick" | "dot" | "none";
893
+ };
894
+ /** Size multiplier for height + arrow size. */
895
+ scale?: number;
896
+ }>;
897
+ type Dimension = Styled<{
898
+ type: "dimension";
899
+ kind?: "linear" | "angular" | "radial" | "diameter";
900
+ /** linear: 2+ chained points (measured point to point); angular: [vertex, a, b]; radial: [center, p]; diameter: [p1, p2]. */
901
+ points: readonly Vec2Like[];
902
+ /** Dimension line offset from the kind's anchor (points[0]; diameter: the
903
+ * points' midpoint). anchor + offset lies on the dimension line (angular:
904
+ * on the arc; radial/diameter: at the text). */
905
+ offset: Vec2Like;
906
+ textOverride?: string;
907
+ styleOverride?: {
908
+ textHeight?: number;
909
+ arrowSize?: number;
910
+ arrowType?: "filled" | "open" | "tick" | "dot" | "none";
911
+ /** "short" = a 2×overshoot tick across the dimension line. */
912
+ extensionType?: "long" | "short";
913
+ extensionOffset?: number;
914
+ extensionOvershoot?: number;
915
+ textOffset?: number;
916
+ precision?: number;
917
+ };
918
+ /** Annotation size multiplier (text/arrows/offsets). */
919
+ scale?: number;
920
+ }>;
921
+ /** Nested block instance (inputs may hold points, never object references). */
922
+ type Block = Styled<{
923
+ type: "block";
924
+ definitionId: string;
925
+ /** Applied last, about the pivot (the first input point). */
926
+ rotation?: number;
927
+ scale?: number;
928
+ params?: Record<string, number | string | boolean>;
929
+ /** Input points in the PARENT's local coords; the first is the pivot. */
930
+ inputs?: readonly Vec2Like[];
931
+ }>;
932
+ type ModelObject = Line | Point | Polyline | Circle | Arc | Ellipse | Hatch | Text | Dimension | Block;
933
+ /** Identity + shared style fields every stored object carries. */
934
+ type StoredObjectBase = {
935
+ id: string;
936
+ layerId: string;
937
+ /** #rrggbb override; absent = by layer. */
938
+ color?: string;
939
+ lineType?: string;
940
+ lineTypeScale?: number;
941
+ lineWidth?: number;
942
+ /** Paint opacity 0..1; absent = opaque. */
943
+ opacity?: number;
944
+ };
945
+ /** Flattens base + per-type fields so hovers list every member inline
946
+ * (same trick as Styled<T> for the authoring DTOs). */
947
+ type StoredShape<T> = {
948
+ [K in keyof (T & StoredObjectBase)]: (T & StoredObjectBase)[K];
949
+ } & {};
950
+ /** Stored polyline vertex — bulge always present (default 0 applied). */
951
+ type StoredPolylineVertex = {
952
+ x: number;
953
+ y: number;
954
+ bulge: number;
955
+ };
956
+ type StoredLine = StoredShape<{
957
+ type: "line";
958
+ a: Vec2;
959
+ b: Vec2;
960
+ }>;
961
+ type StoredPoint = StoredShape<{
962
+ type: "point";
963
+ p: Vec2;
964
+ }>;
965
+ type StoredPolyline = StoredShape<{
966
+ type: "polyline";
967
+ points: readonly StoredPolylineVertex[];
968
+ closed: boolean;
969
+ }>;
970
+ type StoredCircle = StoredShape<{
971
+ type: "circle";
972
+ center: Vec2;
973
+ radius: number;
974
+ }>;
975
+ type StoredArc = StoredShape<{
976
+ type: "arc";
977
+ center: Vec2;
978
+ radius: number;
979
+ startAngle: number;
980
+ endAngle: number;
981
+ }>;
982
+ type StoredEllipse = StoredShape<{
983
+ type: "ellipse";
984
+ center: Vec2;
985
+ majorAxis: Vec2;
986
+ ratio: number;
987
+ startAngle: number;
988
+ endAngle: number;
989
+ }>;
990
+ type StoredHatchFill = {
991
+ kind: "solid";
992
+ } | {
993
+ kind: "pattern";
994
+ name: string;
995
+ angle: number;
996
+ scale: number;
997
+ } | {
998
+ kind: "lines";
999
+ angle: number;
1000
+ spacing: number;
1001
+ };
1002
+ type StoredHatch = StoredShape<{
1003
+ type: "hatch";
1004
+ /** loops[0] = outer boundary, the rest are holes (even-odd). */
1005
+ loops: readonly {
1006
+ points: readonly StoredPolylineVertex[];
1007
+ }[];
1008
+ fill: StoredHatchFill;
1009
+ scale: number;
1010
+ }>;
1011
+ type StoredText = StoredShape<{
1012
+ type: "text";
1013
+ position: Vec2;
1014
+ content: string;
1015
+ leaderLines: readonly (readonly Vec2[])[];
1016
+ /** Word-wrap / frame width in mm; absent = no wrapping. */
1017
+ width?: number;
1018
+ hAlign: "left" | "center" | "right";
1019
+ vAlign: "bottom" | "center" | "top";
1020
+ frame?: "none" | "rectangle" | "bottom";
1021
+ styleId?: string;
1022
+ /** Only the keys the user actually overrode on this text. */
1023
+ styleOverride?: {
1024
+ font?: string;
1025
+ widthFactor?: number;
1026
+ textHeight?: number;
1027
+ arrowType?: "filled" | "open" | "tick" | "dot" | "none";
1028
+ arrowSize?: number;
1029
+ };
1030
+ rotation: number;
1031
+ scale: number;
1032
+ }>;
1033
+ type StoredDimension = StoredShape<{
1034
+ type: "dimension";
1035
+ kind: "linear" | "angular" | "radial" | "diameter";
1036
+ points: readonly Vec2[];
1037
+ offset: Vec2;
1038
+ textOverride?: string;
1039
+ styleId?: string;
1040
+ /** Only the keys the user actually overrode on this dimension. */
1041
+ styleOverride?: {
1042
+ font?: string;
1043
+ widthFactor?: number;
1044
+ textHeight?: number;
1045
+ textOffset?: number;
1046
+ arrowType?: "filled" | "open" | "tick" | "dot" | "none";
1047
+ arrowSize?: number;
1048
+ extensionType?: "long" | "short";
1049
+ extensionOffset?: number;
1050
+ extensionOvershoot?: number;
1051
+ precision?: number;
1052
+ };
1053
+ scale: number;
1054
+ }>;
1055
+ type StoredBlock = StoredShape<{
1056
+ type: "block";
1057
+ definitionId: string;
1058
+ rotation: number;
1059
+ scale: number;
1060
+ params: Readonly<Record<string, number | string | boolean>>;
1061
+ /** World points and/or referenced object ids, in pick order. */
1062
+ inputs: readonly (Vec2 | string)[];
1063
+ }>;
1064
+ /** Paper-space window into model space; exists only in layout spaces. */
1065
+ type StoredViewport = StoredShape<{
1066
+ type: "viewport";
1067
+ rect: {
1068
+ x: number;
1069
+ y: number;
1070
+ w: number;
1071
+ h: number;
1072
+ };
1073
+ modelCenter: Vec2;
1074
+ /** Drawing-scale denominator (model mm per paper mm); 1:50 => 50. */
1075
+ scale: number;
1076
+ locked: boolean;
1077
+ hiddenLayerIds: readonly string[];
1078
+ }>;
1079
+ /** Raster reference; pixels live in the document's assets map. */
1080
+ type StoredImage = StoredShape<{
1081
+ type: "image";
1082
+ assetId: string;
1083
+ origin: Vec2;
1084
+ width: number;
1085
+ height: number;
1086
+ rotation: number;
1087
+ }>;
1088
+ /** Any object as stored in the document — what reads hand to scripts. */
1089
+ type StoredObject = StoredLine | StoredPoint | StoredPolyline | StoredCircle | StoredArc | StoredEllipse | StoredHatch | StoredText | StoredDimension | StoredBlock | StoredViewport | StoredImage;
1090
+ /**
1091
+ * One choice of a "Select" parameter: the value (what scripts receive) with
1092
+ * an optional properties-panel label. A plain string is shorthand for
1093
+ * `{ value }`.
1094
+ */
1095
+ type ParameterOption = string | {
1096
+ value: string;
1097
+ label?: string;
1098
+ };
1099
+ /**
1100
+ * One entry of the module's optional `params` export — the block's
1101
+ * parameters table. `name` is the key scripts read from `params`, `label`
1102
+ * the properties-panel caption (defaults to the name).
1103
+ */
1104
+ type ParamDef = {
1105
+ name: string;
1106
+ label?: string;
1107
+ type: "number";
1108
+ default: number;
1109
+ min?: number;
1110
+ max?: number;
1111
+ } | {
1112
+ name: string;
1113
+ label?: string;
1114
+ type: "string";
1115
+ default: string;
1116
+ } | {
1117
+ name: string;
1118
+ label?: string;
1119
+ type: "boolean";
1120
+ default: boolean;
1121
+ } | {
1122
+ name: string;
1123
+ label?: string;
1124
+ type: "enum";
1125
+ default: string;
1126
+ options: readonly ParameterOption[];
1127
+ };
1128
+ /**
1129
+ * The block's parameters table — what the `params` member of a BlockSpec
1130
+ * declares (or its function form returns).
1131
+ */
1132
+ type BlockParamDefs = readonly ParamDef[];
1133
+ /** What the script's `draw` export must return. */
1134
+ type BlockScriptResult = ModelObject[];
1135
+ /** The value an enum option denotes (its string, or `value` of the record form). */
1136
+ type OptionValue<O extends ParameterOption> = O extends string ? O : O extends {
1137
+ value: infer V extends string;
1138
+ } ? V : never;
1139
+ /** The runtime value type of one `params` table entry. */
1140
+ type ParamValue<Q extends ParamDef> = Q extends {
1141
+ type: "enum";
1142
+ } ? OptionValue<Q["options"][number]> : Q extends {
1143
+ type: "number";
1144
+ } ? number : Q extends {
1145
+ type: "boolean";
1146
+ } ? boolean : string;
1147
+ /**
1148
+ * The values record a params table produces: each entry's `name` maps to
1149
+ * its runtime value type (number/string/boolean, or the enum's option
1150
+ * union). This is what `draw`/`place`/`paramVisibility` receive as
1151
+ * `params` — inside defineBlock the table type is inferred, so authors
1152
+ * never spell this out. Unwraps the function form of `params`; a non-table
1153
+ * type (an already-derived values record, or the open BlockParams default)
1154
+ * passes through unchanged.
1155
+ */
1156
+ type ParamValues<P> = P extends () => infer R ? ParamValues<R> : P extends readonly (infer Q extends ParamDef)[] ? {
1157
+ readonly [E in Q as E["name"]]: ParamValue<E>;
1158
+ } : P;
1159
+
1160
+ // Script-contract globals: aliases into the module (not re-declarations),
1161
+ // so the in-app editor's BlockParams substitution flows through them.
1162
+ declare type BlockParams = import("lineadraw").BlockParams;
1163
+ declare type BlockInputs = import("lineadraw").BlockInputs;
1164
+ declare type ResolvedObject = import("lineadraw").ResolvedObject;
1165
+ declare type ResolvedInput<T> = import("lineadraw").ResolvedInput<T>;
1166
+ declare type PlaceProps<P = BlockParams> = import("lineadraw").PlaceProps<P>;
1167
+ declare type PlaceSpec<P = BlockParams> = import("lineadraw").PlaceSpec<P>;
1168
+ declare type PlaceInputs<Pl> = import("lineadraw").PlaceInputs<Pl>;
1169
+ declare type PreviewInputs<Pl> = import("lineadraw").PreviewInputs<Pl>;
1170
+ declare type BlockSpec<
1171
+ P extends import("lineadraw").BlockParamDefs = readonly [],
1172
+ Pl extends PlaceSpec<P> | undefined = undefined,
1173
+ > = import("lineadraw").BlockSpec<P, Pl>;
1174
+ declare type Box = import("lineadraw").Box;
1175
+ declare type ObjectQuery = import("lineadraw").ObjectQuery;
1176
+ declare type ExistingObject = import("lineadraw").ExistingObject;
1177
+ declare type Measurement = import("lineadraw").Measurement;
1178
+ declare type CommandDocument = import("lineadraw").CommandDocument;
1179
+ declare type CommandContext = import("lineadraw").CommandContext;
1180
+ declare type CommandSpec = import("lineadraw").CommandSpec;