lineadraw 0.9.0 → 0.10.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +137 -14
- package/dist/{chunk-BQCSFVAF.js → chunk-YYJAXJOY.js} +4037 -1180
- package/dist/chunk-YYJAXJOY.js.map +1 -0
- package/dist/{exportDxf-T2RTSTH5.js → exportDxf-C4CLQCC3.js} +2 -2
- package/dist/sdk.d.ts +259 -42
- package/dist/sdk.js +127 -66
- package/dist/sdk.js.map +1 -1
- package/lineadraw.d.ts +505 -37
- package/package.json +2 -2
- package/templates/README.md +6 -4
- package/dist/chunk-BQCSFVAF.js.map +0 -1
- /package/dist/{exportDxf-T2RTSTH5.js.map → exportDxf-C4CLQCC3.js.map} +0 -0
package/README.md
CHANGED
|
@@ -113,7 +113,9 @@ appended when missing):
|
|
|
113
113
|
configuration, never written to the file.
|
|
114
114
|
- **Scripts**: `await runScript(source, inputs?, params?)` runs a
|
|
115
115
|
`defineCommand` module (the same one the editor palette runs) headlessly
|
|
116
|
-
as ONE undo step — its declared `inputs`
|
|
116
|
+
as ONE undo step — its declared `inputs` are supplied up front (by name
|
|
117
|
+
for an inputs table: `{ origin: [0, 0], doors: [id] }`; points in order
|
|
118
|
+
for labels),
|
|
117
119
|
its declared `params` by name (`{ count: 3 }`; omitted ones take their
|
|
118
120
|
defaults, unknown names and wrong types throw); `runUserCommand(id, inputs?,
|
|
119
121
|
params?)` runs one of the document's own commands. Returns the script's
|
|
@@ -260,16 +262,32 @@ export default defineBlock({
|
|
|
260
262
|
params: [
|
|
261
263
|
{ name: "kind", type: "enum", default: "rock", options: ["rock", "ground"] },
|
|
262
264
|
],
|
|
263
|
-
|
|
264
|
-
|
|
265
|
+
// What the user picks at insertion, read by name in `draw`.
|
|
266
|
+
inputs: [
|
|
267
|
+
{ name: "start", type: "point", label: "Start point" },
|
|
268
|
+
{ name: "end", type: "point", label: "End point" },
|
|
269
|
+
],
|
|
270
|
+
draw: ({ params, inputs: { start, end } }) => {
|
|
265
271
|
params.kind; // "rock" | "ground" — inferred from the params table
|
|
266
272
|
return [{ type: "line", a: start, b: end }];
|
|
267
273
|
},
|
|
268
274
|
});
|
|
269
275
|
```
|
|
270
276
|
|
|
271
|
-
|
|
272
|
-
`
|
|
277
|
+
Input kinds: `point`; `points` — a chain picked until Enter (`min`,
|
|
278
|
+
`max`, `closed` for a polygon) arriving as `Vec2[]`; `object` / `objects`
|
|
279
|
+
— picked objects filtered by `types` (`["line", "polyline"]`), arriving in
|
|
280
|
+
`draw` as the objects themselves (re-evaluated when they change; a
|
|
281
|
+
deleted one is `null` / dropped). `point` and `object` may be `optional`
|
|
282
|
+
(Enter skips). The first point is the pivot. Instances store their inputs
|
|
283
|
+
by name, so reordering or adding inputs never breaks placed instances —
|
|
284
|
+
removing or renaming one does. (The older `place: ["Start", "End"]` labels
|
|
285
|
+
form, with `draw` reading `inputs` as an array, still works.)
|
|
286
|
+
|
|
287
|
+
Notable optional members: `place` — an interactive
|
|
288
|
+
`({ params, pickPoint, pickPoints, pickObject, pickObjects })` function run
|
|
289
|
+
once at insertion, for conditional or chained picks; with an `inputs`
|
|
290
|
+
table it returns the inputs by name;
|
|
273
291
|
`dependencies` lists ids of blocks your `draw` emits instances of (installs
|
|
274
292
|
pull them along); `paramVisibility({ params })` hides property rows;
|
|
275
293
|
`previewInputs` curates the inputs used for thumbnails. Units are
|
|
@@ -294,6 +312,26 @@ Parameter types (the same rows serve a command's `params`):
|
|
|
294
312
|
- `label` — a section heading (no value); `row` — 2–3 compact params on one
|
|
295
313
|
panel row (`items`, each label a short prefix like "W"); its items are
|
|
296
314
|
ordinary flat params (`params.w`).
|
|
315
|
+
- `data` — structured data the block owns: any JSON value, typed by its
|
|
316
|
+
default (`default: {} as Record<string, Wall>`). It has no Properties row;
|
|
317
|
+
handles, handle menus and actions edit it (agents set it like any param).
|
|
318
|
+
|
|
319
|
+
Geometry helpers come from `"lineadraw/helpers"` — vector math
|
|
320
|
+
(`add`, `sub`, `scale`, `rotate`, `polar`, …) and polygon booleans:
|
|
321
|
+
`union(...polygons)`, `difference(subject, ...clips)`,
|
|
322
|
+
`intersection(...polygons)`. A polygon is a ring of points, or rings with
|
|
323
|
+
holes (first the outer boundary). The result is a flat list of rings,
|
|
324
|
+
ready for closed polylines or ONE hatch, which fills even-odd so holes
|
|
325
|
+
stay holes:
|
|
326
|
+
|
|
327
|
+
```ts
|
|
328
|
+
const solid = union(...walls.map(wallRect)); // overlapping walls → clean outlines
|
|
329
|
+
return [
|
|
330
|
+
{ type: "hatch", loops: solid.map((points) => ({ points })),
|
|
331
|
+
fill: { kind: "pattern", name: "ANSI31", angle: 0, scale: 20 } },
|
|
332
|
+
...solid.map((points) => ({ type: "polyline", points, closed: true })),
|
|
333
|
+
];
|
|
334
|
+
```
|
|
297
335
|
|
|
298
336
|
Every param may carry a `hint` (the label's tooltip). An instance that
|
|
299
337
|
overrides a param shows "Reset" beside it in Properties, back to your
|
|
@@ -302,10 +340,94 @@ default. `draw` also receives
|
|
|
302
340
|
empty or unknown id → the first), for blocks that lay out with real text
|
|
303
341
|
sizes.
|
|
304
342
|
|
|
343
|
+
#### Hosted blocks
|
|
344
|
+
|
|
345
|
+
A block can LIVE ON another instance: a door on a floor plan. Give it a
|
|
346
|
+
`host` input; it then draws in the host's frame (moving, rotating and
|
|
347
|
+
copying with it, and deleted with it), and the two talk through
|
|
348
|
+
`expose`, JSON each publishes from its OWN params:
|
|
349
|
+
|
|
350
|
+
```ts
|
|
351
|
+
// The plan publishes its walls and cuts them where its openings say.
|
|
352
|
+
expose: ({ params }) => ({ walls: wallTable(params) }),
|
|
353
|
+
draw: ({ params, hosted }) => {
|
|
354
|
+
const cuts = hosted.map((h) => h.exposed?.cut).filter(Boolean);
|
|
355
|
+
return wallSolids(params, cuts);
|
|
356
|
+
},
|
|
357
|
+
|
|
358
|
+
// A door: picked by clicking a plan's wall; `attach` turns the click
|
|
359
|
+
// (plan-local) into its params.
|
|
360
|
+
inputs: [{ name: "plan", type: "host", types: ["@my-blocks/floor-plan"] }],
|
|
361
|
+
expose: ({ params }) => ({ cut: { wall: params.wall, at: params.at, width: params.width } }),
|
|
362
|
+
attach: ({ host, point }) => nearestWall(host.walls, point), // → { wall, at }
|
|
363
|
+
draw: ({ params, host }) => doorLeaf(host.walls[params.wall], params),
|
|
364
|
+
```
|
|
365
|
+
|
|
366
|
+
`expose` never sees the host or what's on it, so the two can't loop
|
|
367
|
+
(ADR 0008). What a host publishes and what its openings read is a
|
|
368
|
+
contract between the modules: document it.
|
|
369
|
+
|
|
370
|
+
A hosted block has no host in Library / marketplace previews. Give it a
|
|
371
|
+
stand-in with `previewHost`: the JSON a host's `expose` would return.
|
|
372
|
+
The preview runs `attach` as if the host were clicked at its origin, and
|
|
373
|
+
`draw` gets the stand-in as `host` (the save-time dry run uses it too):
|
|
374
|
+
|
|
375
|
+
```ts
|
|
376
|
+
previewHost: { preview: true, walls: { A: { a: [-1500, 0], b: [1500, 0], t: 200 } } },
|
|
377
|
+
// …and in draw, `host.preview` can add context: a stretch of wall.
|
|
378
|
+
```
|
|
379
|
+
|
|
380
|
+
#### Handles and actions
|
|
381
|
+
|
|
382
|
+
`handles({ params, inputs })` returns the handles a selected instance
|
|
383
|
+
shows, in block-local coordinates. It re-runs as values change, so a
|
|
384
|
+
handle can sit at the current width:
|
|
385
|
+
|
|
386
|
+
```ts
|
|
387
|
+
handles: ({ params }) => [
|
|
388
|
+
// Drag along local X: the distance becomes `width` (clamped to its min/max).
|
|
389
|
+
{ id: "width", at: [params.width, 0], shape: "triangle",
|
|
390
|
+
along: { origin: [0, 0], direction: [1, 0] }, param: "width" },
|
|
391
|
+
// A button: one click, one undo step.
|
|
392
|
+
{ id: "flip", at: [params.width / 2, 150], fixed: true, icon: "flip-horizontal",
|
|
393
|
+
click: ({ params }) => ({ params: { swing: params.swing === "left" ? "right" : "left" } }) },
|
|
394
|
+
// A line handle (shown while hovered) with a hover menu.
|
|
395
|
+
{ id: "wall", kind: "line", from: [0, 0], to: [params.width, 0], fixed: true,
|
|
396
|
+
menu: ["thickness",
|
|
397
|
+
{ field: { type: "boolean", label: "Enabled" }, value: !params.off,
|
|
398
|
+
set: (on) => ({ params: { off: !on } }) }],
|
|
399
|
+
actions: [{ label: "Reset", icon: "x", run: () => ({ params: { off: false } }) }] },
|
|
400
|
+
],
|
|
401
|
+
// The instance's context menu (right-click): pick a point, then run.
|
|
402
|
+
actions: [
|
|
403
|
+
{ label: "Add mark", pick: "point",
|
|
404
|
+
run: ({ params, point }) => ({ params: { marks: [...params.marks, [point.x, point.y]] } }) },
|
|
405
|
+
],
|
|
406
|
+
```
|
|
407
|
+
|
|
408
|
+
A handle has ONE drag behaviour: `param` (the constrained value → a number
|
|
409
|
+
param), `input` (moves a point input, replacing its default handle), or
|
|
410
|
+
`drag` (a function returning a patch). Otherwise it is `fixed`. The
|
|
411
|
+
constraint is free, `along` an axis (value = distance) or `around` a
|
|
412
|
+
centre (value = angle in radians). A line handle moves along its normal by
|
|
413
|
+
default. `click` turns it into a button. Shapes are `square`, `circle`,
|
|
414
|
+
`diamond`, `triangle`, `arrow`, `double-arrow`, `plus` and `minus`, and `icon` names a
|
|
415
|
+
lucide glyph from a small set. Handle functions and actions return a PATCH
|
|
416
|
+
— `{ params?, inputs? }`, with inputs by name and block-local — and never
|
|
417
|
+
mutate anything. Each applies as one undo step. The save-time dry run
|
|
418
|
+
checks every handle record.
|
|
419
|
+
|
|
305
420
|
### Writing a command
|
|
306
421
|
|
|
307
422
|
A command is a macro with a single `defineCommand` default export. Its
|
|
308
|
-
whole run is one undo step; Esc during a pick reverts cleanly.
|
|
423
|
+
whole run is one undo step; Esc during a pick reverts cleanly. Its
|
|
424
|
+
`inputs` table is the same one blocks declare; `object` / `objects` inputs
|
|
425
|
+
take the current selection when it fits (types and count) and arrive as
|
|
426
|
+
ids. To ask more DURING the run (the next question depends on the last
|
|
427
|
+
answer), use `editor.pickPoint` / `pickObject` / `prompt`, or
|
|
428
|
+
`editor.ask(paramsTable, { title })` for several fields in one dialog —
|
|
429
|
+
and declare `requiresEditor: true`, so CLI / agent runs refuse the command
|
|
430
|
+
up front instead of failing halfway. A
|
|
309
431
|
`params` table (the same rows a block's `params` uses) is asked for in a
|
|
310
432
|
dialog before the run and arrives typed as `ctx.params`; headless callers
|
|
311
433
|
pass it by name.
|
|
@@ -317,11 +439,12 @@ import { defineCommand } from "lineadraw";
|
|
|
317
439
|
export default defineCommand({
|
|
318
440
|
id: "@my-blocks/circle-here",
|
|
319
441
|
name: "Circle here",
|
|
320
|
-
inputs: ["Center point"],
|
|
442
|
+
inputs: [{ name: "center", type: "point", label: "Center point" }],
|
|
321
443
|
params: [{ name: "radius", type: "number", default: 10, min: 0.1 }],
|
|
322
|
-
// `inputs` are picked in the editor (or passed by a headless
|
|
323
|
-
// `params` asked for in a dialog; `editor`
|
|
324
|
-
|
|
444
|
+
// `inputs` are picked in the editor (or passed by name by a headless
|
|
445
|
+
// caller: { center: [0, 0] }), `params` asked for in a dialog; `editor`
|
|
446
|
+
// is absent when headless.
|
|
447
|
+
run: async ({ document, editor, inputs: { center }, params }) => {
|
|
325
448
|
document.add([{ type: "circle", center, radius: params.radius }]);
|
|
326
449
|
editor?.toast("Done", "success");
|
|
327
450
|
},
|
|
@@ -371,11 +494,11 @@ Collection name and owner come from your package.json:
|
|
|
371
494
|
|
|
372
495
|
### Using a marketplace in the editor
|
|
373
496
|
|
|
374
|
-
In [
|
|
375
|
-
gear
|
|
376
|
-
`owner/repo` (or `owner/repo@branch`). For a private repository,
|
|
497
|
+
In [Linea](https://lineadraw.com): **App settings → Marketplaces → Add a
|
|
498
|
+
marketplace** (the gear in Library → Marketplace opens the same tab) and
|
|
499
|
+
enter `owner/repo` (or `owner/repo@branch`). For a private repository,
|
|
377
500
|
create a fine-grained personal access token with read-only Contents access
|
|
378
|
-
to just that repository and paste it
|
|
501
|
+
to just that repository and paste it under "Add an access token" — it is stored only
|
|
379
502
|
on that device. Installing embeds the module (and its declared dependency
|
|
380
503
|
closure) in the document, so drawings keep working offline and travel with
|
|
381
504
|
the file.
|