lineadraw 0.1.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 (3) hide show
  1. package/lineadraw.d.ts +787 -0
  2. package/main.js +0 -0
  3. package/package.json +19 -0
package/lineadraw.d.ts ADDED
@@ -0,0 +1,787 @@
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;
package/main.js ADDED
File without changes
package/package.json ADDED
@@ -0,0 +1,19 @@
1
+ {
2
+ "name": "lineadraw",
3
+ "version": "0.1.0",
4
+ "description": "Lineadraw types",
5
+ "license": "MIT",
6
+ "author": "Mikhail Koshelev",
7
+ "type": "module",
8
+ "types": "./lineadraw.d.ts",
9
+ "exports": {
10
+ ".": {
11
+ "types": "./lineadraw.d.ts",
12
+ "default": "./main.js"
13
+ },
14
+ "./helpers": {
15
+ "types": "./lineadraw.d.ts",
16
+ "default": "./main.js"
17
+ }
18
+ }
19
+ }