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.
- package/lineadraw.d.ts +787 -0
- package/main.js +0 -0
- 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
|
+
}
|