anniedrawing 0.3.3 → 0.4.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/CHANGELOG.md +10 -0
- package/README.md +1 -1
- package/dist/agent/index.js +1 -1
- package/dist/agent/index.js.map +1 -1
- package/dist/core/catalog.d.ts +1 -1
- package/dist/core/index.js +1 -1
- package/dist/core/textFit.d.ts +13 -0
- package/dist/docs/agents-repository.md +1 -1
- package/dist/docs/agents.md +2 -2
- package/dist/docs/api.md +3 -3
- package/dist/docs/board-js.md +16 -16
- package/dist/docs/decisions.md +15 -1
- package/dist/docs/format.md +2 -2
- package/dist/docs/index.html +15 -7
- package/dist/docs/llms-full.txt +16 -16
- package/dist/docs/llms.txt +10 -10
- package/dist/docs/mcp.md +1 -1
- package/dist/fellow.js +1 -1
- package/dist/index.js +1 -1
- package/dist/shared/board-OPwsZ2_V.js +2 -0
- package/dist/shared/board-OPwsZ2_V.js.map +1 -0
- package/dist/shared/{cards-DF0uI4-I.js → cards-D_9Lly1d.js} +2 -2
- package/dist/shared/{cards-DF0uI4-I.js.map → cards-D_9Lly1d.js.map} +1 -1
- package/dist/shared/defaults-DZEoAeRz.js +2 -0
- package/dist/shared/defaults-DZEoAeRz.js.map +1 -0
- package/dist/shared/describe-o3vER0cL.js +3 -0
- package/dist/shared/{describe-DaWyf3qV.js.map → describe-o3vER0cL.js.map} +1 -1
- package/dist/shared/{paste-B8nZA2Gh.js → paste-B4b0C9Jh.js} +2 -2
- package/dist/shared/{paste-B8nZA2Gh.js.map → paste-B4b0C9Jh.js.map} +1 -1
- package/dist/shared/picker-ciuPQvRn.js +2 -0
- package/dist/shared/picker-ciuPQvRn.js.map +1 -0
- package/dist/shared/textFit-BrGz6lhQ.js +2 -0
- package/dist/shared/textFit-BrGz6lhQ.js.map +1 -0
- package/dist/shared/ui-c98N8xEV.js +2 -0
- package/dist/shared/ui-c98N8xEV.js.map +1 -0
- package/dist/shared/{urlPaste-Oc4kZ0P7.js → urlPaste-BqcpeQ-c.js} +2 -2
- package/dist/shared/{urlPaste-Oc4kZ0P7.js.map → urlPaste-BqcpeQ-c.js.map} +1 -1
- package/dist/style.css +1 -1
- package/dist/ui/index.js +1 -1
- package/dist/ui/version.d.ts +1 -1
- package/llms-full.txt +16 -16
- package/llms.txt +10 -10
- package/package.json +1 -1
- package/dist/shared/board-p60lv7As.js +0 -2
- package/dist/shared/board-p60lv7As.js.map +0 -1
- package/dist/shared/defaults-C-aC_B4z.js +0 -2
- package/dist/shared/defaults-C-aC_B4z.js.map +0 -1
- package/dist/shared/describe-DaWyf3qV.js +0 -3
- package/dist/shared/picker-DZpEpkED.js +0 -2
- package/dist/shared/picker-DZpEpkED.js.map +0 -1
- package/dist/shared/ui-DWQtW0zJ.js +0 -2
- package/dist/shared/ui-DWQtW0zJ.js.map +0 -1
package/dist/docs/board-js.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
Operate a live or headless board through JavaScript. This is the full AI reference for creating items and reading what is on the board. It does not cover installing, running, or changing the library.
|
|
4
4
|
|
|
5
|
-
Kind catalog:
|
|
5
|
+
Kind catalog: 2
|
|
6
6
|
|
|
7
7
|
`kindsSince(since?)` lists built-in kinds added or last changed after that catalog version. Omit `since`, or pass `0`, to list every built-in kind. Remember the returned `version` and pass it next time you want only what is new.
|
|
8
8
|
|
|
@@ -32,12 +32,12 @@ const board = createDoc();
|
|
|
32
32
|
|
|
33
33
|
```js
|
|
34
34
|
board.kindsSince(); // every built-in kind; same as board.kindsSince(0)
|
|
35
|
-
board.kindsSince(1); // kinds added or changed after catalog 1
|
|
35
|
+
board.kindsSince(1); // kinds added or changed after catalog 1
|
|
36
36
|
```
|
|
37
37
|
|
|
38
38
|
Also exported as `kindsSince` and `CATALOG_VERSION` from `anniedrawing`, `anniedrawing/core`, and `anniedrawing/agent`.
|
|
39
39
|
|
|
40
|
-
Each entry is `{ kind, since, w, h, note }`. `w` and `h` are the default size when those fields are omitted on `add`. Custom host kinds do not appear here.
|
|
40
|
+
Each entry is `{ kind, since, w, h, note }`. `w` and `h` are the default size when those fields are omitted on `add`. An `agent:` create can store a larger box so `text` fits. An `agent:` connector that omits `route` stores `elbow`. Custom host kinds do not appear here.
|
|
41
41
|
|
|
42
42
|
The catalog version is independent of the `.annie` document format version (`2`) and the package version.
|
|
43
43
|
|
|
@@ -93,7 +93,7 @@ Operations: `add`, `set`, `remove`, `order`, `reparent`, `page.add`, `page.set`,
|
|
|
93
93
|
|
|
94
94
|
`set` merges `style`, `text`, and `data` one level deep. Other fields are replaced. Do not change `id` with `set`. `order.to` is `front`, `back`, `forward`, `backward`, or a numeric index.
|
|
95
95
|
|
|
96
|
-
`add` accepts `page`, `parent`, `index`, and `place`. `place` needs exactly one of `rightOf`, `leftOf`, `above`, `below`, `inside`, or `near`. Default `gap` is 32. Default `align` is `middle`. `inside` requires a `group`. Kind aliases: `rectangle` stores `rect`; `arrow` stores `connector` with an end arrow. `from` / `to` accept `{ item, side }`, `{ x, y }`, or a string item id.
|
|
96
|
+
`add` accepts `page`, `parent`, `index`, and `place`. `place` needs exactly one of `rightOf`, `leftOf`, `above`, `below`, `inside`, or `near`. Default `gap` is 32. Default `align` is `middle`. `inside` requires a `group`. `rightOf` / `leftOf` / `above` / `below` slide further along that axis when the first slot is occupied. Kind aliases: `rectangle` stores `rect`; `arrow` stores `connector` with an end arrow. `from` / `to` accept `{ item, side }`, `{ x, y }`, or a string item id. An `agent:` connector that omits `route` stores `elbow`. Elbows go around intervening boxes.
|
|
97
97
|
|
|
98
98
|
`OVERLAPS_EXISTING` and `ID_REMAPPED` are warnings. The batch still committed. An `agent:` create that reuses an id is stored as `id_1`, then `_2`. Same-batch `place`, parent, and connector refs follow the stored id. `get` with the id you sent returns the older item. User and API origins still reject duplicates.
|
|
99
99
|
|
|
@@ -179,7 +179,7 @@ Named colors: `ink`, `slate`, `coral`, `amber`, `moss`, `teal`, `sky`, `violet`,
|
|
|
179
179
|
|
|
180
180
|
## Built-in kinds
|
|
181
181
|
|
|
182
|
-
Omit `w` / `h` to use the default size in the catalog.
|
|
182
|
+
Omit `w` / `h` to use the default size in the catalog. An `agent:` create or text patch on `rect`, `ellipse`, `diamond`, `note`, or `text` grows the stored size so the label fits. Standalone `text` defaults to 600 wide. A larger explicit size is kept.
|
|
183
183
|
|
|
184
184
|
### `rect`
|
|
185
185
|
|
|
@@ -213,7 +213,7 @@ Omit `w` / `h` to use the default size in the catalog.
|
|
|
213
213
|
|
|
214
214
|
### `connector`
|
|
215
215
|
|
|
216
|
-
`from` / `to` are `{ item, side?, anchor? }`, `{ x, y }`, or a string item id stored as `{ item, side: 'auto' }`. `side` is `auto` / `top` / `right` / `bottom` / `left`. `route` is `straight` / `elbow` / `curve`. Heads: `none` / `arrow` / `dot`. Optional `waypoints` are page-space `[x, y]`. Bound ends detach to their last point when the target disappears. `kind: 'arrow'` stores `connector` with an end arrow.
|
|
216
|
+
`from` / `to` are `{ item, side?, anchor? }`, `{ x, y }`, or a string item id stored as `{ item, side: 'auto' }`. `side` is `auto` / `top` / `right` / `bottom` / `left`. `route` is `straight` / `elbow` / `curve`. Heads: `none` / `arrow` / `dot`. Optional `waypoints` are page-space `[x, y]`. An `agent:` create that omits `route` stores `elbow`. Elbows pick a channel that misses intervening boxes. Bound ends detach to their last point when the target disappears. `kind: 'arrow'` stores `connector` with an end arrow.
|
|
217
217
|
|
|
218
218
|
```js
|
|
219
219
|
{ op: 'add', item: { id: 'i_flow', kind: 'connector',
|
|
@@ -233,11 +233,11 @@ Freehand points may include pressure: `[x, y, pressure]`. `closed: true` closes
|
|
|
233
233
|
### `text`
|
|
234
234
|
|
|
235
235
|
```js
|
|
236
|
-
{ op: 'add', item: { id: 'i_title', kind: 'text', x: 80, y: 40,
|
|
236
|
+
{ op: 'add', item: { id: 'i_title', kind: 'text', x: 80, y: 40,
|
|
237
237
|
text: { value: 'Architecture', size: 'l', align: 'start' } } }
|
|
238
238
|
```
|
|
239
239
|
|
|
240
|
-
A browser `text` item with `autoWidth: true` stores measured width and height. Headless documents keep the stored size.
|
|
240
|
+
Omitted `w` is 600. A browser `text` item with `autoWidth: true` (set for `agent:` creates) stores measured width and height. Headless documents keep the stored or grown size.
|
|
241
241
|
|
|
242
242
|
### `note`
|
|
243
243
|
|
|
@@ -327,14 +327,14 @@ PNG `labels: true` draws item IDs for vision models and defaults to a 32-color i
|
|
|
327
327
|
|
|
328
328
|
Optional wrapper around the same APIs. Import `toolDefs` and `runTool` from `anniedrawing/agent`. Map `name`, `description`, and `inputSchema` into the provider envelope. Do not change the operations schema.
|
|
329
329
|
|
|
330
|
-
| Tool | Use
|
|
331
|
-
| ---------------- |
|
|
332
|
-
| `board_describe` | Text with IDs. Start here.
|
|
333
|
-
| `board_read` | Deep JSON copy. Headless accepts only `scope: 'doc'`.
|
|
334
|
-
| `board_query` | Same filters as `query`.
|
|
335
|
-
| `board_apply` | Atomic ops. `runTool` forces an `agent:` origin (`agent:tool` if omitted). Duplicate create ids become `id_1`. |
|
|
336
|
-
| `board_snapshot` | Browser PNG. Defaults: viewport, scale 2, labels on, 32 colors, 240 KiB.
|
|
337
|
-
| `board_view_fit` | Browser camera. Optional `ids`.
|
|
330
|
+
| Tool | Use |
|
|
331
|
+
| ---------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
332
|
+
| `board_describe` | Text with IDs. Start here. |
|
|
333
|
+
| `board_read` | Deep JSON copy. Headless accepts only `scope: 'doc'`. |
|
|
334
|
+
| `board_query` | Same filters as `query`. |
|
|
335
|
+
| `board_apply` | Atomic ops. Grows labels, slides directional place, omitted route → elbow. `runTool` forces an `agent:` origin (`agent:tool` if omitted). Duplicate create ids become `id_1`. |
|
|
336
|
+
| `board_snapshot` | Browser PNG. Defaults: viewport, scale 2, labels on, 32 colors, 240 KiB. |
|
|
337
|
+
| `board_view_fit` | Browser camera. Optional `ids`. |
|
|
338
338
|
|
|
339
339
|
`board_snapshot` and `board_view_fit` need a live board.
|
|
340
340
|
|
package/dist/docs/decisions.md
CHANGED
|
@@ -1,5 +1,19 @@
|
|
|
1
1
|
# Design decisions
|
|
2
2
|
|
|
3
|
+
## 2026-09-20: Elbows miss boxes; place does not stack
|
|
4
|
+
|
|
5
|
+
Agent diagrams go wrong in two cheap ways: several `rightOf` the same node land on one point, and a straight or midpoint elbow walks through the node in between. Orthogonal routing literature (channel + obstacle) and simple packing fix both without a graph layout pass.
|
|
6
|
+
|
|
7
|
+
Elbows stay derived. The default midpoint channel is kept when it is clear. If it hits a box, try the other orientation, then a channel just outside the blocker. Waypoints and non-elbow routes are untouched. Other connectors are not obstacles, so routing cannot cycle.
|
|
8
|
+
|
|
9
|
+
`rightOf` / `leftOf` / `above` / `below` already named an axis. When that slot intersects a solid item, slide further along the same axis by the occupant plus `gap`. `near` and `inside` already searched.
|
|
10
|
+
|
|
11
|
+
An `agent:` connector that omits `route` stores `elbow`. Omitted `route` on disk stays straight.
|
|
12
|
+
|
|
13
|
+
## 2026-09-20: Agent labeled boxes grow to the text
|
|
14
|
+
|
|
15
|
+
Agents often send catalog defaults or example 200×100 boxes with a paragraph of `text`. The label then overflows. An `agent:` `add` or text `set` on `rect`, `ellipse`, `diamond`, `note`, or `text` grows stored `w`/`h` so the label fits, wrapping long lines at a comfortable width. Standalone `text` defaults to 600 wide so graph titles are not capped at the old 200. User and API origins keep the size they wrote. A larger explicit size is kept. The measurement is a headless heuristic so MCP and the browser store the same box. Browser `agent:` text also sets `autoWidth`. Kind catalog 2 records that create contract.
|
|
16
|
+
|
|
3
17
|
## 2026-09-20: Public unfurl hosts
|
|
4
18
|
|
|
5
19
|
Unfurl is a same-browser GET of a user-pasted URL, not a metadata proxy. `isPublicHttpUrl` is a hostname check: it rejects loopback, RFC1918, link-local, ULA, IPv4-mapped IPv6, NAT64, multicast, and names that start with a private IPv4. It does not look up DNS. Preview images from Open Graph go through the same check so a public page cannot point the card at a private URL. The local Vite `/__ad-unfurl` plugin additionally resolves A/AAAA records and refuses private answers. Hosts that need stricter policy pass `unfurl: false` or their own function.
|
|
@@ -70,7 +84,7 @@ Version 2 uses pages in the document, scopes, and editing API. Version 1 documen
|
|
|
70
84
|
|
|
71
85
|
## 2026-09-19: Toolbar and inspector layout
|
|
72
86
|
|
|
73
|
-
Keep primary drawing tools on the sidebar: eraser after hand, image after sticky note, and line and arrow inside Shapes. Do not hide those tools behind a More overflow. On phones, including landscape, and on short tablet-width hosts, the tools move to a bottom bar and hand stays in the board menu so that bar remains tappable, unless a host hides that menu. A short desktop host keeps the tool sidebar and inspector vertically centered and tightens chrome padding and icons instead of pinning those bars to the top. The selection inspector is vertically centered like the tool sidebar. Export downloads the current page. An imported board offers PNG and SVG; AnnieDoc is opt-in through `ui.export`. The local demo offers all three. The AnnieDrawing control opens the same kind of menu for document, appearance, documentation, and GitHub, with the package version at the bottom, and hosts may hide it. Show item-specific style controls only when something is selected, with palettes opened on demand and compact line and text controls visible beside the selection. The inspector does not repeat the selected kind as a title. Page management remains in the bottom bar. Positioning and rotation follow the user's pointer. Shift constrains the move axis or resize proportions.
|
|
87
|
+
Keep primary drawing tools on the sidebar: eraser after hand, image after sticky note, and line and arrow inside Shapes. Do not hide those tools behind a More overflow. On phones, including landscape, and on short tablet-width hosts, the tools move to a bottom bar and hand stays in the board menu so that bar remains tappable, unless a host hides that menu. Pages, zoom, undo, redo, and Export live in a Board controls menu at the top right so they do not compete with that bar. A short desktop host keeps the tool sidebar and inspector vertically centered and tightens chrome padding and icons instead of pinning those bars to the top. That tighter chrome starts at 640px host height when the AnnieDrawing menu or page chips are present. Without those bars, 640px pulls the sidebar inward and uses a middle tool size; tools and buttons fully shrink at 500px. The selection inspector is vertically centered like the tool sidebar. Export downloads the current page. An imported board offers PNG and SVG; AnnieDoc is opt-in through `ui.export`. The local demo offers all three. The AnnieDrawing control opens the same kind of menu for document, appearance, documentation, and GitHub, with the package version at the bottom, and hosts may hide it. Show item-specific style controls only when something is selected, with palettes opened on demand and compact line and text controls visible beside the selection. The inspector does not repeat the selected kind as a title. Page management remains in the bottom bar. Positioning and rotation follow the user's pointer. Shift constrains the move axis or resize proportions.
|
|
74
88
|
|
|
75
89
|
## 2026-09-19: MIT licensing and the named package
|
|
76
90
|
|
package/dist/docs/format.md
CHANGED
|
@@ -42,7 +42,7 @@ The model expands defaults internally and omits default style flags on serializa
|
|
|
42
42
|
|
|
43
43
|
Built-in kinds: `rect`, `ellipse`, `diamond`, `line`, `connector`, `path`, `text`, `note`, `image`, `video`, `link`, `group`, and `html`. Unknown kinds are kept and shown as a placeholder. Load and save do not drop custom content.
|
|
44
44
|
|
|
45
|
-
Default sizes when `w` and `h` are omitted: rect and ellipse 180×110, diamond 160×140, line 180×0, connector 0×0, path 0×0, text
|
|
45
|
+
Default sizes when `w` and `h` are omitted: rect and ellipse 180×110, diamond 160×140, line 180×0, connector 0×0, path 0×0, text 600×48, note 200×180, image 240×180, video 480×270, link 220×200, group 0×0, html 240×160. An `agent:` create or text patch on `rect`, `ellipse`, `diamond`, `note`, or `text` may store a larger size so the label fits.
|
|
46
46
|
|
|
47
47
|
`text` has a plain `value`, horizontal `align` (`start`, `center`, `end`), vertical `valign` (`top`, `middle`, `bottom`), `size` (`s`, `m`, `l`, `xl`, or a number from 1 to 1000), and `font` (`sans`, `serif`, `mono`, `hand`). Omitted `font` is `hand`, the handwritten Comic Sans-like stack. `autoWidth: true` on a browser `text` item stores measured width and height.
|
|
48
48
|
|
|
@@ -54,7 +54,7 @@ Named colors: `ink`, `slate`, `coral`, `amber`, `moss`, `teal`, `sky`, `violet`,
|
|
|
54
54
|
|
|
55
55
|
## Connectors and paths
|
|
56
56
|
|
|
57
|
-
A connector has `from` and `to`. Each stored end is either `{ "item": "i_note", "side": "right" }` or a free `{ "x": 100, "y": 200 }` point. `apply` also accepts a string item id, stored as `{ item, side: "auto" }`. `side` is `auto`, `top`, `right`, `bottom`, or `left`. An attached endpoint can use a normalized `anchor: [0, 0.5]`. Routes are `straight`, `elbow`, or `curve`. Heads accept `none`, `arrow`, or `dot`. Optional `waypoints` are page-space `[x, y]` points between the ends. When a target disappears, that endpoint becomes a free point at its last position in the same atomic edit.
|
|
57
|
+
A connector has `from` and `to`. Each stored end is either `{ "item": "i_note", "side": "right" }` or a free `{ "x": 100, "y": 200 }` point. `apply` also accepts a string item id, stored as `{ item, side: "auto" }`. `side` is `auto`, `top`, `right`, `bottom`, or `left`. An attached endpoint can use a normalized `anchor: [0, 0.5]`. Routes are `straight`, `elbow`, or `curve`. An `agent:` create that omits `route` stores `elbow`. Omitted `route` in a saved file stays `straight`. Elbows pick a channel that misses intervening boxes. Heads accept `none`, `arrow`, or `dot`. Optional `waypoints` are page-space `[x, y]` points between the ends. When a target disappears, that endpoint becomes a free point at its last position in the same atomic edit.
|
|
58
58
|
|
|
59
59
|
Line and freehand `points` are relative to the item's `x` and `y`. Freehand points may include pressure: `[x, y, pressure]`. `closed: true` closes a path. Item IDs and connector bindings survive moves and export or import.
|
|
60
60
|
|
package/dist/docs/index.html
CHANGED
|
@@ -706,10 +706,10 @@ board.apply([{ op: 'add', item: {
|
|
|
706
706
|
to open its inspector. Fill, Line, and Color choose colors. Line also sets thickness and
|
|
707
707
|
pattern. Text-capable shapes show size, alignment, and font. A selected video or link
|
|
708
708
|
card can change its URL from the inspector. More arrangement options opens align,
|
|
709
|
-
distribute, group, and stacking. Pages lists pages.
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
PNG and SVG.
|
|
709
|
+
distribute, group, and stacking. Pages lists pages. On a phone, pages, zoom, undo, redo,
|
|
710
|
+
and Export open from Board controls. The AnnieDrawing menu holds appearance,
|
|
711
|
+
documentation, GitHub, and the package version unless the host hides it. This demo's
|
|
712
|
+
Export control offers PNG, SVG, and AnnieDoc; an imported board defaults to PNG and SVG.
|
|
713
713
|
</p>
|
|
714
714
|
<div class="shortcut-grid">
|
|
715
715
|
<div class="shortcut"><span>Select / move</span><kbd>V</kbd></div>
|
|
@@ -787,8 +787,13 @@ board.apply([{ op: 'add', item: {
|
|
|
787
787
|
<code>order</code>, and <code>reparent</code>, plus page, media, and document metadata
|
|
788
788
|
changes. <code>place</code> takes exactly one of <code>rightOf</code>,
|
|
789
789
|
<code>leftOf</code>, <code>above</code>, <code>below</code>, <code>inside</code>, or
|
|
790
|
-
<code>near</code>.
|
|
791
|
-
|
|
790
|
+
<code>near</code>. Directional <code>place</code> slides further along that axis when
|
|
791
|
+
the first slot is occupied. An <code>agent:</code> create or text patch on
|
|
792
|
+
<code>rect</code>, <code>ellipse</code>, <code>diamond</code>, <code>note</code>, or
|
|
793
|
+
<code>text</code> grows the stored size so the label fits. Standalone
|
|
794
|
+
<code>text</code> defaults to 600 wide. An <code>agent:</code> connector that omits
|
|
795
|
+
<code>route</code> stores <code>elbow</code>. Elbows go around intervening boxes. A dry
|
|
796
|
+
run validates a batch without saving it. Failed batches apply nothing.
|
|
792
797
|
</p>
|
|
793
798
|
<div class="link-row">
|
|
794
799
|
<a class="pill" href="api.md">API reference</a
|
|
@@ -800,7 +805,10 @@ board.apply([{ op: 'add', item: {
|
|
|
800
805
|
<h2>Agents</h2>
|
|
801
806
|
<p>
|
|
802
807
|
The document is JSON with stable item IDs. An agent can describe the scene, query items,
|
|
803
|
-
and apply a batch. Every batch succeeds together or changes nothing.
|
|
808
|
+
and apply a batch. Every batch succeeds together or changes nothing. An
|
|
809
|
+
<code>agent:</code> origin grows labeled boxes and titles to fit text, slides
|
|
810
|
+
directional <code>place</code> when a slot is taken, and stores <code>elbow</code> on
|
|
811
|
+
connectors that omit <code>route</code>. Elbows miss intervening boxes. This demo sets
|
|
804
812
|
<code>exposeGlobal: true</code> so the board is on <code>window.__anniedrawing</code>.
|
|
805
813
|
Other hosts must pass that option.
|
|
806
814
|
</p>
|
package/dist/docs/llms-full.txt
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
Operate a live or headless board through JavaScript. This is the full AI reference for creating items and reading what is on the board. It does not cover installing, running, or changing the library.
|
|
4
4
|
|
|
5
|
-
Kind catalog:
|
|
5
|
+
Kind catalog: 2
|
|
6
6
|
|
|
7
7
|
`kindsSince(since?)` lists built-in kinds added or last changed after that catalog version. Omit `since`, or pass `0`, to list every built-in kind. Remember the returned `version` and pass it next time you want only what is new.
|
|
8
8
|
|
|
@@ -32,12 +32,12 @@ const board = createDoc();
|
|
|
32
32
|
|
|
33
33
|
```js
|
|
34
34
|
board.kindsSince(); // every built-in kind; same as board.kindsSince(0)
|
|
35
|
-
board.kindsSince(1); // kinds added or changed after catalog 1
|
|
35
|
+
board.kindsSince(1); // kinds added or changed after catalog 1
|
|
36
36
|
```
|
|
37
37
|
|
|
38
38
|
Also exported as `kindsSince` and `CATALOG_VERSION` from `anniedrawing`, `anniedrawing/core`, and `anniedrawing/agent`.
|
|
39
39
|
|
|
40
|
-
Each entry is `{ kind, since, w, h, note }`. `w` and `h` are the default size when those fields are omitted on `add`. Custom host kinds do not appear here.
|
|
40
|
+
Each entry is `{ kind, since, w, h, note }`. `w` and `h` are the default size when those fields are omitted on `add`. An `agent:` create can store a larger box so `text` fits. An `agent:` connector that omits `route` stores `elbow`. Custom host kinds do not appear here.
|
|
41
41
|
|
|
42
42
|
The catalog version is independent of the `.annie` document format version (`2`) and the package version.
|
|
43
43
|
|
|
@@ -93,7 +93,7 @@ Operations: `add`, `set`, `remove`, `order`, `reparent`, `page.add`, `page.set`,
|
|
|
93
93
|
|
|
94
94
|
`set` merges `style`, `text`, and `data` one level deep. Other fields are replaced. Do not change `id` with `set`. `order.to` is `front`, `back`, `forward`, `backward`, or a numeric index.
|
|
95
95
|
|
|
96
|
-
`add` accepts `page`, `parent`, `index`, and `place`. `place` needs exactly one of `rightOf`, `leftOf`, `above`, `below`, `inside`, or `near`. Default `gap` is 32. Default `align` is `middle`. `inside` requires a `group`. Kind aliases: `rectangle` stores `rect`; `arrow` stores `connector` with an end arrow. `from` / `to` accept `{ item, side }`, `{ x, y }`, or a string item id.
|
|
96
|
+
`add` accepts `page`, `parent`, `index`, and `place`. `place` needs exactly one of `rightOf`, `leftOf`, `above`, `below`, `inside`, or `near`. Default `gap` is 32. Default `align` is `middle`. `inside` requires a `group`. `rightOf` / `leftOf` / `above` / `below` slide further along that axis when the first slot is occupied. Kind aliases: `rectangle` stores `rect`; `arrow` stores `connector` with an end arrow. `from` / `to` accept `{ item, side }`, `{ x, y }`, or a string item id. An `agent:` connector that omits `route` stores `elbow`. Elbows go around intervening boxes.
|
|
97
97
|
|
|
98
98
|
`OVERLAPS_EXISTING` and `ID_REMAPPED` are warnings. The batch still committed. An `agent:` create that reuses an id is stored as `id_1`, then `_2`. Same-batch `place`, parent, and connector refs follow the stored id. `get` with the id you sent returns the older item. User and API origins still reject duplicates.
|
|
99
99
|
|
|
@@ -179,7 +179,7 @@ Named colors: `ink`, `slate`, `coral`, `amber`, `moss`, `teal`, `sky`, `violet`,
|
|
|
179
179
|
|
|
180
180
|
## Built-in kinds
|
|
181
181
|
|
|
182
|
-
Omit `w` / `h` to use the default size in the catalog.
|
|
182
|
+
Omit `w` / `h` to use the default size in the catalog. An `agent:` create or text patch on `rect`, `ellipse`, `diamond`, `note`, or `text` grows the stored size so the label fits. Standalone `text` defaults to 600 wide. A larger explicit size is kept.
|
|
183
183
|
|
|
184
184
|
### `rect`
|
|
185
185
|
|
|
@@ -213,7 +213,7 @@ Omit `w` / `h` to use the default size in the catalog.
|
|
|
213
213
|
|
|
214
214
|
### `connector`
|
|
215
215
|
|
|
216
|
-
`from` / `to` are `{ item, side?, anchor? }`, `{ x, y }`, or a string item id stored as `{ item, side: 'auto' }`. `side` is `auto` / `top` / `right` / `bottom` / `left`. `route` is `straight` / `elbow` / `curve`. Heads: `none` / `arrow` / `dot`. Optional `waypoints` are page-space `[x, y]`. Bound ends detach to their last point when the target disappears. `kind: 'arrow'` stores `connector` with an end arrow.
|
|
216
|
+
`from` / `to` are `{ item, side?, anchor? }`, `{ x, y }`, or a string item id stored as `{ item, side: 'auto' }`. `side` is `auto` / `top` / `right` / `bottom` / `left`. `route` is `straight` / `elbow` / `curve`. Heads: `none` / `arrow` / `dot`. Optional `waypoints` are page-space `[x, y]`. An `agent:` create that omits `route` stores `elbow`. Elbows pick a channel that misses intervening boxes. Bound ends detach to their last point when the target disappears. `kind: 'arrow'` stores `connector` with an end arrow.
|
|
217
217
|
|
|
218
218
|
```js
|
|
219
219
|
{ op: 'add', item: { id: 'i_flow', kind: 'connector',
|
|
@@ -233,11 +233,11 @@ Freehand points may include pressure: `[x, y, pressure]`. `closed: true` closes
|
|
|
233
233
|
### `text`
|
|
234
234
|
|
|
235
235
|
```js
|
|
236
|
-
{ op: 'add', item: { id: 'i_title', kind: 'text', x: 80, y: 40,
|
|
236
|
+
{ op: 'add', item: { id: 'i_title', kind: 'text', x: 80, y: 40,
|
|
237
237
|
text: { value: 'Architecture', size: 'l', align: 'start' } } }
|
|
238
238
|
```
|
|
239
239
|
|
|
240
|
-
A browser `text` item with `autoWidth: true` stores measured width and height. Headless documents keep the stored size.
|
|
240
|
+
Omitted `w` is 600. A browser `text` item with `autoWidth: true` (set for `agent:` creates) stores measured width and height. Headless documents keep the stored or grown size.
|
|
241
241
|
|
|
242
242
|
### `note`
|
|
243
243
|
|
|
@@ -327,14 +327,14 @@ PNG `labels: true` draws item IDs for vision models and defaults to a 32-color i
|
|
|
327
327
|
|
|
328
328
|
Optional wrapper around the same APIs. Import `toolDefs` and `runTool` from `anniedrawing/agent`. Map `name`, `description`, and `inputSchema` into the provider envelope. Do not change the operations schema.
|
|
329
329
|
|
|
330
|
-
| Tool | Use
|
|
331
|
-
| ---------------- |
|
|
332
|
-
| `board_describe` | Text with IDs. Start here.
|
|
333
|
-
| `board_read` | Deep JSON copy. Headless accepts only `scope: 'doc'`.
|
|
334
|
-
| `board_query` | Same filters as `query`.
|
|
335
|
-
| `board_apply` | Atomic ops. `runTool` forces an `agent:` origin (`agent:tool` if omitted). Duplicate create ids become `id_1`. |
|
|
336
|
-
| `board_snapshot` | Browser PNG. Defaults: viewport, scale 2, labels on, 32 colors, 240 KiB.
|
|
337
|
-
| `board_view_fit` | Browser camera. Optional `ids`.
|
|
330
|
+
| Tool | Use |
|
|
331
|
+
| ---------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
332
|
+
| `board_describe` | Text with IDs. Start here. |
|
|
333
|
+
| `board_read` | Deep JSON copy. Headless accepts only `scope: 'doc'`. |
|
|
334
|
+
| `board_query` | Same filters as `query`. |
|
|
335
|
+
| `board_apply` | Atomic ops. Grows labels, slides directional place, omitted route → elbow. `runTool` forces an `agent:` origin (`agent:tool` if omitted). Duplicate create ids become `id_1`. |
|
|
336
|
+
| `board_snapshot` | Browser PNG. Defaults: viewport, scale 2, labels on, 32 colors, 240 KiB. |
|
|
337
|
+
| `board_view_fit` | Browser camera. Optional `ids`. |
|
|
338
338
|
|
|
339
339
|
`board_snapshot` and `board_view_fit` need a live board.
|
|
340
340
|
|
package/dist/docs/llms.txt
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
Operate a board through JavaScript. The JSON document is the source of truth. People and agents commit through `apply(ops, options)`. This file does not cover installing or changing the library. Full examples: [board JavaScript](board-js.md) / [llms-full.txt](llms-full.txt).
|
|
4
4
|
|
|
5
|
-
Kind catalog:
|
|
5
|
+
Kind catalog: 2
|
|
6
6
|
|
|
7
7
|
```js
|
|
8
8
|
const board = window.__anniedrawing[0]; // demo; hosts pass exposeGlobal: true
|
|
@@ -32,24 +32,24 @@ Pass `expectedRevision` from the read that informed an edit to `apply` or `board
|
|
|
32
32
|
|
|
33
33
|
Operations: `add`, `set`, `remove`, `order`, `reparent`, `page.add`, `page.set`, `page.remove`, `meta.set`, `media.set`, `media.remove`. A failed batch changes nothing. `set` merges `style`, `text`, and `data` one level deep. Do not change `id` with `set`. `add` accepts `page`, `parent`, `index`, and `place`. `order.to` is `front`, `back`, `forward`, `backward`, or a numeric index. Kind aliases: `rectangle` → `rect`, `arrow` → `connector`. Connector `from`/`to` accept `{ item, side }`, `{ x, y }`, or a string id.
|
|
34
34
|
|
|
35
|
-
`place` requires exactly one of `rightOf`, `leftOf`, `above`, `below`, `inside`, or `near`. Default `gap` is 32. Default `align` is `middle`. `inside` requires a `group`. Do not call `load()` to patch a few items.
|
|
35
|
+
`place` requires exactly one of `rightOf`, `leftOf`, `above`, `below`, `inside`, or `near`. Default `gap` is 32. Default `align` is `middle`. `inside` requires a `group`. Directional `place` slides further along that axis when the slot is taken. An `agent:` create or text patch on `rect`, `ellipse`, `diamond`, `note`, or `text` grows the stored size so the label fits. Standalone `text` defaults to 600 wide. An `agent:` connector that omits `route` stores `elbow`. Elbows go around intervening boxes. Do not call `load()` to patch a few items.
|
|
36
36
|
|
|
37
37
|
Check `result.ok`, then read `result.created` for stored ids. `OVERLAPS_EXISTING` and `ID_REMAPPED` are warnings; the batch still committed. An `agent:` create that reuses an id is stored as `id_1` (then `_2`); same-batch `place` and connector refs follow that id. `get` with the id you sent returns the older item. User and API origins still reject duplicates.
|
|
38
38
|
|
|
39
39
|
## Kinds
|
|
40
40
|
|
|
41
|
-
Built-in kinds, default size when `w`/`h` omitted
|
|
41
|
+
Built-in kinds, default size when `w`/`h` omitted. `rect`, `ellipse`, `diamond`, `connector`, `note`, and `text` are catalog 2: labeled boxes grow so the label fits; an omitted connector `route` stores `elbow`.
|
|
42
42
|
|
|
43
43
|
| Kind | Size | Create |
|
|
44
44
|
| ---- | ---- | ------ |
|
|
45
|
-
| `rect` | 180×110 | Box or node. `text`, `style`. |
|
|
46
|
-
| `ellipse` | 180×110 | Ellipse or circle. |
|
|
47
|
-
| `diamond` | 160×140 | Decision or highlight. |
|
|
45
|
+
| `rect` | 180×110 | Box or node. `text`, `style`. Agent creates grow to fit text. |
|
|
46
|
+
| `ellipse` | 180×110 | Ellipse or circle. Agent creates grow to fit text. |
|
|
47
|
+
| `diamond` | 160×140 | Decision or highlight. Agent creates grow to fit text. |
|
|
48
48
|
| `line` | 180×0 | Segment. Optional `points` relative to x/y. |
|
|
49
|
-
| `connector` | 0×0 | `from`/`to` as `{ item, side? }`, `{ x, y }`, or a string item id. `route`: straight/elbow/curve. Compact JSON omits x/y/w/h. |
|
|
49
|
+
| `connector` | 0×0 | `from`/`to` as `{ item, side? }`, `{ x, y }`, or a string item id. `route`: straight/elbow/curve. Agent omit stores elbow. Compact JSON omits x/y/w/h. |
|
|
50
50
|
| `path` | 0×0 | Freehand. `points` (`[x,y,pressure?]`), optional `closed`. |
|
|
51
|
-
| `text` |
|
|
52
|
-
| `note` | 200×180 | Sticky. Default moss fill, 12px corner. |
|
|
51
|
+
| `text` | 600×48 | Plain text. Agent creates grow to fit a title. Browser `autoWidth` measures. |
|
|
52
|
+
| `note` | 200×180 | Sticky. Default moss fill, 12px corner. Agent creates grow to fit text. |
|
|
53
53
|
| `image` | 240×180 | `media` key in the document media table. |
|
|
54
54
|
| `video` | 480×270 | YouTube or Vimeo `href`. |
|
|
55
55
|
| `link` | 220×200 | Website card. `href`, optional `description`. |
|
|
@@ -83,7 +83,7 @@ Optional. Import `toolDefs` and `runTool` from `anniedrawing/agent`. Same operat
|
|
|
83
83
|
| `board_describe` | Text with IDs. Start here. |
|
|
84
84
|
| `board_read` | Deep JSON. Headless: `scope: 'doc'` only. |
|
|
85
85
|
| `board_query` | Filters combine with AND. |
|
|
86
|
-
| `board_apply` | Atomic ops. `dryRun` validates
|
|
86
|
+
| `board_apply` | Atomic ops. Grows labels, slides directional place, omitted route → elbow. `dryRun` validates. Duplicate agent create ids become `id_1`. |
|
|
87
87
|
| `board_snapshot` | Browser PNG. Defaults: viewport, scale 2, labels on, 32 colors, 240 KiB. |
|
|
88
88
|
| `board_view_fit` | Browser camera. Optional `ids`. |
|
|
89
89
|
|
package/dist/docs/mcp.md
CHANGED
|
@@ -50,7 +50,7 @@ Page edits use the current `page.*` operations and `page` destination property:
|
|
|
50
50
|
}
|
|
51
51
|
```
|
|
52
52
|
|
|
53
|
-
`board_snapshot` and `board_view_fit` return an error in headless mode because they require a browser. Other tools use the same model and schemas as the library. An unsuccessful `board_apply` result becomes a tool result with `isError: true`. A successful agent apply that reuses an item id still commits; the stored id is `id_1` (then `_2`), the result includes `ID_REMAPPED`, and `created` lists the stored ids.
|
|
53
|
+
`board_snapshot` and `board_view_fit` return an error in headless mode because they require a browser. Other tools use the same model and schemas as the library. A `board_apply` with an `agent:` origin grows labeled boxes and titles to fit text, slides directional `place` when a slot is taken, and stores `elbow` when a connector omits `route`. An unsuccessful `board_apply` result becomes a tool result with `isError: true`. A successful agent apply that reuses an item id still commits; the stored id is `id_1` (then `_2`), the result includes `ID_REMAPPED`, and `created` lists the stored ids.
|
|
54
54
|
|
|
55
55
|
## Connect a live board
|
|
56
56
|
|
package/dist/fellow.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{n as e}from"./shared/board-
|
|
1
|
+
import{n as e}from"./shared/board-OPwsZ2_V.js";function a(a,n={}){const{fellowName:t,...o}=n;return e(a,{agentHistory:"hidden",agentReveal:"fit",agentPlaceGap:120,agentPresence:{maxStops:3,durationScale:.55},exposeGlobal:!1,unfurl:!1,ui:{menu:!1,export:!1,pages:!1},...o,agentName:o.agentName??t})}export{a as createFellowBoard};
|
|
2
2
|
//# sourceMappingURL=fellow.js.map
|
package/dist/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{b as s,v as a,y as r}from"./shared/defaults-
|
|
1
|
+
import{b as s,v as a,y as r}from"./shared/defaults-DZEoAeRz.js";import{i as o,n as t,r as d,t as e}from"./shared/board-OPwsZ2_V.js";export{e as Board,a as CATALOG_VERSION,r as KIND_CATALOG,t as createBoard,d as defineKind,s as kindsSince,o as registerKind};
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import{a as t,c as e,d as i,i as s,m as n,r as o,t as r,u as a}from"./picker-ciuPQvRn.js";import{a as h,b as d,h as l,m as c,t as p,u,y as m}from"./defaults-DZEoAeRz.js";import{L as g,M as f,O as y,S as x,T as v,_ as w,a as k,d as b,f as $,i as M,o as S,s as I,u as z,y as E}from"./describe-o3vER0cL.js";import{r as C}from"./textFit-BrGz6lhQ.js";import{a as P,c as T,d as L,f as A,i as D,l as R,m as q,n as U,o as O,p as N,r as G,s as j,t as F,u as B}from"./ui-c98N8xEV.js";function K(t){const e=/* @__PURE__ */new Set,i=(t,s=!1)=>{const n=s||!!t.locked;let o=!1;for(const e of t.children??[])o=i(e,n)||o;return(n||o)&&e.add(t.id),n||o};return t.forEach(t=>i(t)),e}var H=/* @__PURE__ */new Map;for(const{kind:It}of m)H.set(It,{kind:It});function W(t){if(!/^[a-z][a-z0-9_-]*$/i.test(t.kind))throw new Error("Kind names must begin with a letter and contain only letters, digits, _ or -.");return t}function J(t){W(t);const e=H.get(t.kind);return H.set(t.kind,t),()=>{e?H.set(t.kind,e):H.delete(t.kind)}}function Y(){return[...H.values()]}function X(t=[]){return new Map([...Y(),...t.map(W)].map(t=>[t.kind,t]))}var _=class{id;element=document.createElement("div");shape=document.createElementNS(D,"svg");text=document.createElement("div");auxiliary=document.createElement("div");previous=/* @__PURE__ */new Map;currentKind;currentDefinition;unmount;doc;item;bounds;constructor(t){this.id=t,this.element.className="ad-item",this.element.style.display="none",this.element.dataset.adId=t,this.element.tabIndex=0,this.element.setAttribute("role","img"),this.shape.classList.add("ad-shape"),this.shape.setAttribute("aria-hidden","true"),this.shape.setAttribute("overflow","visible"),this.text.className="ad-text",this.auxiliary.className="ad-auxiliary",this.element.append(this.shape,this.text,this.auxiliary)}changed(t,e){return this.previous.get(t)!==e&&(this.previous.set(t,e),!0)}paint(t,e,i,s,n,o,r){this.doc=e,this.item=t;const a=/* @__PURE__ */new Set,h=!(!n?.mount&&!n?.paint);let d=!1;if(this.currentKind!==t.kind||this.currentDefinition!==n){this.unmount?.(),this.unmount=void 0,this.currentKind=t.kind,this.currentDefinition=n,this.previous.clear();const e=this.element.style.display;this.element.removeAttribute("style"),this.element.style.display=e,this.element.className="ad-item",delete this.element.dataset.adInteractive,this.shape.removeAttribute("style"),this.text.removeAttribute("style"),this.auxiliary.removeAttribute("style"),this.element.replaceChildren(this.shape,this.text,this.auxiliary),this.shape.replaceChildren(),this.text.replaceChildren(),this.auxiliary.replaceChildren(),this.auxiliary.className="ad-auxiliary",this.shape.style.display="",this.element.dataset.adKind=t.kind,["image","video","link"].includes(t.kind)&&this.auxiliary.classList.add("ad-card"),d=!0}const l="connector"===t.kind?x(t,i,r):void 0,c=l?"":`translate3d(${t.x}px,${t.y}px,0) rotate(${t.rotation??0}deg)`;this.changed("transform",c)&&(this.element.style.transform=c,a.add("transform"));const p=`${t.w}|${t.h}`;this.changed("size",p)&&(this.element.style.width=`${l?1:t.w}px`,this.element.style.height=`${l?1:t.h}px`,this.shape.setAttribute("width",String(l?1:t.w)),this.shape.setAttribute("height",String(l?1:t.h)),a.add("geometry"));const u=JSON.stringify([t.style,s]);this.changed("style",u)&&(this.element.style.opacity=String(t.style?.opacity??1),this.element.style.color=P("ink",s),this.text.style.color=L(t,s),a.add("style"));const m=JSON.stringify([p,t.kind,t.points,t.closed,t.heads,l?.d,u]);if(this.changed("geometry",m)&&(a.add("geometry"),!h)){const e=["rect","ellipse","diamond","note","line","path","connector"];if(this.shape.style.display=e.includes(t.kind)?"":"none",e.includes(t.kind)){const e=l?.points??(t.points??[[0,0],[t.w,t.h]]).map(([t,e])=>({x:t,y:e}));this.shape.innerHTML=q(t,s,this.id,l?.d)+("line"===t.kind||l?B(e,t,s):"")}}const g=JSON.stringify([t.text,t.kind,l?.midpoint,s]);this.changed("text",g)&&(a.add("text"),h||(this.text.isContentEditable||(this.text.textContent=t.text?.value??""),this.text.style.fontSize=`${T(t.text)}px`,this.text.style.fontFamily=j(t.text?.font),this.text.style.textAlign=t.text?.align??("text"===t.kind?"start":"center"),this.text.style.justifyContent="top"===t.text?.valign?"flex-start":"bottom"===t.text?.valign?"flex-end":"center",this.text.style.alignItems="start"===t.text?.align||"text"===t.kind&&!t.text?.align?"flex-start":"end"===t.text?.align?"flex-end":"center",this.text.style.display=t.text||this.text.isContentEditable?"flex":"none",l?(this.text.style.left=`${l.midpoint.x}px`,this.text.style.top=`${l.midpoint.y}px`,this.text.style.backgroundColor=P("paper",s)):(this.text.style.left="",this.text.style.top="",this.text.style.backgroundColor="")));const f=JSON.stringify([t.kind,t.name,t.html,t.href,t.description,t.text?.value,t.media,t.media?e.media[t.media]?.src:void 0,s,!!n,t.crop]);if(this.changed("auxiliary",f)&&(a.add("content"),!h))if(this.auxiliary.replaceChildren(),"image"===t.kind){const i=t.media?e.media[t.media]:void 0;if(i){const e=document.createElement("img");e.draggable=!1,e.alt=t.name??t.text?.value??"Image",e.src=i.src,t.crop&&t.crop.w>0&&t.crop.h>0&&(e.style.width=i.w/t.crop.w*100+"%",e.style.height=i.h/t.crop.h*100+"%",e.style.left=-t.crop.x/t.crop.w*100+"%",e.style.top=-t.crop.y/t.crop.h*100+"%"),this.auxiliary.append(e)}else this.placeholder("Image unavailable")}else if("video"===t.kind||"link"===t.kind){const e=f;import("./cards-D_9Lly1d.js").then(({paintCard:i})=>{this.previous.get("auxiliary")===e&&i(this.auxiliary,t,this.doc)})}else"html"===t.kind?(this.auxiliary.classList.add("ad-html-content"),o?this.auxiliary.innerHTML=o(t.html??""):this.auxiliary.textContent=t.html??"HTML content"):n||this.placeholder(`Unknown kind: ${t.kind}`);this.changed("access",`${t.locked}|${t.hidden}`)&&(this.element.classList.toggle("ad-locked",!!t.locked),this.element.tabIndex=t.hidden?-1:0);const y=n?.summarize?.(t)??`${"rect"===t.kind?"Rectangle":t.kind[0].toUpperCase()+t.kind.slice(1)}${t.text?.value||t.name||t.href?`: ${t.text?.value??t.name??t.href}`:""}`;if(this.changed("aria",y)&&this.element.setAttribute("aria-label",y),h&&this.changed("custom",JSON.stringify(Object.fromEntries(Object.entries(t).filter(([t])=>!["x","y","w","h","rotation","style","text","points","heads","closed"].includes(t)))))&&a.add("content"),d){const t=n?.mount?.(this);"function"==typeof t&&(this.unmount=t)}n?.paint?.(this,t,a)}placeholder(t){const e=document.createElement("div");e.className="ad-placeholder",e.innerHTML=`<span aria-hidden="true">◇</span><span>${O(t)}</span>`,this.auxiliary.append(e)}destroy(){this.unmount?.(),this.unmount=void 0,this.element.remove()}},V=class{host;value={x:0,y:0,zoom:1};listeners=/* @__PURE__ */new Set;observer;animation=0;width;height;constructor(t){this.host=t,this.width=t.clientWidth||800,this.height=t.clientHeight||600,"undefined"!=typeof ResizeObserver&&(this.observer=new ResizeObserver(t=>{const e=t[0]?.contentRect;!e||e.width===this.width&&e.height===this.height||(this.width=e.width,this.height=e.height,this.emit())}),this.observer.observe(t))}get state(){return{...this.value}}get zoom(){return this.value.zoom}get center(){return this.toPage({x:this.width/2,y:this.height/2})}set(t){this.stop();const e={...this.value,...t};[e.x,e.y,e.zoom].every(Number.isFinite)&&(e.zoom=Math.max(.05,Math.min(8,e.zoom)),e.x===this.value.x&&e.y===this.value.y&&e.zoom===this.value.zoom||(this.value=e,this.emit()))}emit(){for(const t of this.listeners)t(this.state)}toPage(t){return{x:(t.x-this.value.x)/this.value.zoom,y:(t.y-this.value.y)/this.value.zoom}}toScreen(t){return{x:t.x*this.value.zoom+this.value.x,y:t.y*this.value.zoom+this.value.y}}viewport(t=0){return{...this.toPage({x:-t,y:-t}),w:(this.width+2*t)/this.zoom,h:(this.height+2*t)/this.zoom}}fitState(t,e=96){const i=Math.max(120,this.width-Math.min(2*e,.3*this.width)),s=Math.max(120,this.height-Math.min(2*e,.35*this.height)),n=Math.max(.05,Math.min(1.5,i/Math.max(1,t.w),s/Math.max(1,t.h)));return{x:this.width/2-(t.x+t.w/2)*n,y:this.height/2-(t.y+t.h/2)*n,zoom:n}}fit(t,e=96){this.stop(),this.set(this.fitState(t,e))}flyTo(t){this.stop();const e=this.fitState(t);if("undefined"==typeof matchMedia||matchMedia("(prefers-reduced-motion: reduce)").matches)return void this.set(e);const i=this.state,s=performance.now(),n=t=>{const o=Math.min(1,(t-s)/280),r=1-(1-o)**3;this.set({x:i.x+(e.x-i.x)*r,y:i.y+(e.y-i.y)*r,zoom:i.zoom+(e.zoom-i.zoom)*r}),this.animation=o<1?requestAnimationFrame(n):0};this.animation=requestAnimationFrame(n)}stop(){this.animation&&cancelAnimationFrame(this.animation),this.animation=0}onChange(t){return this.listeners.add(t),()=>this.listeners.delete(t)}destroy(){this.stop(),this.observer?.disconnect(),this.listeners.clear()}};function Q(t,e,i,s){return`url("data:image/svg+xml,${encodeURIComponent(`<svg xmlns="http://www.w3.org/2000/svg" width="${e}" height="${e}" viewBox="0 0 ${e} ${e}">${t}</svg>`)}") ${i.join(" ")}, ${s}`}var Z="M8.5 6.5c-1.3-.5-2.5.7-2 2l6.1 19.4c.5 1.6 2.7 1.7 3.3.1l3.1-8a1.5 1.5 0 0 1 .9-.9l8-3.1c1.6-.6 1.5-2.8-.1-3.3Z",tt=Q(`<defs><radialGradient id="a"><stop stop-color="#c4b5fd" stop-opacity=".22"/><stop offset="1" stop-color="#c4b5fd" stop-opacity="0"/></radialGradient></defs><circle cx="17" cy="18" r="18" fill="url(#a)"/><path d="${Z}" fill="none" stroke="#b9a6e6" stroke-width="5" stroke-opacity=".14" stroke-linejoin="round"/><path d="${Z}" fill="#18252a" stroke="#fff" stroke-width="2" stroke-linejoin="round"/>`,36,[7,7],"default"),et="M14 4v6m0 8v6M4 14h6m8 0h6",it=Q(`<circle cx="14" cy="14" r="10" fill="#c4b5fd" fill-opacity=".06"/><path d="${et}" stroke="#b9a6e6" stroke-opacity=".15" stroke-width="6" stroke-linecap="round"/><path d="${et}" stroke="#fff" stroke-width="4" stroke-linecap="round"/><path d="${et}" stroke="#18252a" stroke-width="1.7" stroke-linecap="round"/><circle cx="14" cy="14" r="1" fill="#18252a"/>`,28,[14,14],"crosshair");var st=class{root;lens;queue=[];pending=/* @__PURE__ */new Set;restore=/* @__PURE__ */new Map;cursor;name;frame=0;tick=0;generation=0;running=!1;motion=matchMedia("(prefers-reduced-motion: reduce)");quiet=()=>matchMedia("(prefers-reduced-motion: reduce)").matches||document.hidden;preference=()=>{this.quiet()&&this.clear()};maxStops;durationScale;idle=/* @__PURE__ */new Set;constructor(t,e,i={}){this.root=t,this.lens=e,this.maxStops=Math.max(1,i.maxStops??8),this.durationScale=Math.min(2,Math.max(.25,i.durationScale??1)),this.motion.addEventListener("change",this.preference),document.addEventListener("visibilitychange",this.preference)}holds(t){return this.pending.has(t)}busy(){return this.running||0!==this.frame||this.pending.size>0}whenIdle(t){this.busy()?this.idle.add(t):t()}enqueue(t,e){if(this.quiet())return;const i=e?.trim();i&&!this.name&&(this.name=i);for(const s of t)if(s.elements=s.elements.filter(t=>!this.pending.has(t)),s.elements.length){for(const t of s.elements)t.classList.add("ad-agent-pending"),t.tabIndex=-1,this.pending.add(t);this.queue.push(s)}this.running||this.frame||!this.queue.length||(this.frame=requestAnimationFrame(()=>{this.frame=0,this.run(this.generation).catch(()=>this.clear())}))}prune(){let t=!1;for(const e of[...this.pending])e.isConnected||(t=!0,this.restore.get(e)?.(),this.restore.delete(e),this.pending.delete(e));this.queue=this.queue.filter(t=>(t.elements=t.elements.filter(t=>this.pending.has(t)),t.elements.length>0)),this.pending.size||!t&&(this.running||this.frame)||this.clear()}clear(){this.generation++,cancelAnimationFrame(this.frame),cancelAnimationFrame(this.tick),this.frame=0,this.tick=0;for(const e of this.restore.values())e();this.restore.clear();for(const e of this.pending)e.classList.remove("ad-agent-pending"),e.tabIndex<0&&(e.tabIndex=0);this.pending.clear(),this.queue=[],this.cursor?.remove(),this.cursor=void 0,this.name=void 0,this.running=!1;const t=[...this.idle];this.idle.clear();for(const e of t)e()}destroy(){this.clear(),this.motion.removeEventListener("change",this.preference),document.removeEventListener("visibilitychange",this.preference)}async play(t,e,i){if(t!==this.generation)return;if(this.quiet()||e<=0)return void i(1);let s=0;await new Promise(n=>{const o=r=>{if(t!==this.generation)return this.tick=0,void n();s||(s=r);const a=Math.min(1,(r-s)/e);i(1-(1-a)**3),a<1?this.tick=requestAnimationFrame(o):(this.tick=0,n())};this.tick=requestAnimationFrame(o)})}edge(t){const{width:e,height:i}=this.lens;return[{x:-70,y:t.y+40},{x:e+70,y:t.y-40},{x:t.x-40,y:-70},{x:t.x+40,y:i+70}].sort((e,i)=>Math.hypot(e.x-t.x,e.y-t.y)-Math.hypot(i.x-t.x,i.y-t.y))[0]}transform(t){return`translate(${t.x-7}px,${t.y-7}px)`}put(t,e){t.style.transform=this.transform(e),t.dataset.adAt=`${e.x},${e.y}`}center(t){return{x:t.x+t.w/2,y:t.y+t.h/2}}async move(t,e,i,s){const n=this.lens.toScreen(i),o=this.lens.toScreen(s),r=Math.hypot(o.x-n.x,o.y-n.y);await this.play(t,Math.min(650,320+.35*r)*this.durationScale,t=>{const n=this.lens.toScreen(i),o=this.lens.toScreen(s),r=Math.min(36,Math.hypot(o.x-n.x,o.y-n.y)/8),a=1-t;this.put(e,{x:a*a*n.x+2*a*t*((n.x+o.x)/2+r)+t*t*o.x,y:a*a*n.y+2*a*t*((n.y+o.y)/2-r)+t*t*o.y})}),t===this.generation&&this.put(e,this.lens.toScreen(s))}connector(t){return t.elements.length>0&&t.elements.every(t=>"connector"===t.dataset.adKind)}onScreen(t){const e=this.lens.toScreen(t.box),i=e.x+t.box.w*this.lens.zoom,s=e.y+t.box.h*this.lens.zoom,{width:n,height:o}=this.lens;return i>=0&&s>=0&&e.x<=n&&e.y<=o}visitable(t){return t.elements.some(t=>t.isConnected)&&!this.connector(t)&&this.onScreen(t)}take(t){return t.splice(0).flatMap(t=>t.elements)}show(t,e){this.pending.has(e)&&(e.classList.remove("ad-agent-pending"),e.tabIndex=0,this.pending.delete(e),this.reveal(t,e))}reveal(t,e){const i=e.style.opacity||"1",s=e.style.transform,n=Number(i),o=()=>{e.style.opacity=i,e.style.transform=s};this.restore.set(e,o),this.play(t,220*this.durationScale,t=>{e.style.opacity=String(n*t),"connector"!==e.dataset.adKind&&(e.style.transform=`${s} scale(${.97+.03*t})`)}).then(()=>{t===this.generation&&(o(),this.restore.delete(e))})}async run(t){let e;this.running=!0;let i=0;const s=[];for(;this.queue.length&&t===this.generation;){if(this.quiet())return void this.clear();if(this.prune(),t!==this.generation)return;const n=this.queue.shift();if(!n)break;if(!this.visitable(n)){s.push(n);continue}(++i>=this.maxStops||!this.queue.some(t=>this.visitable(t)))&&n.elements.push(...this.take(s),...this.take(this.queue));const o=this.center(n.box);if(!this.cursor){this.cursor=document.createElement("div"),this.cursor.className="ad-agent-cursor",this.cursor.setAttribute("aria-hidden","true"),this.cursor.innerHTML=`<svg width="36" height="36" viewBox="0 0 36 36"><path d="${Z}"/></svg>${this.name?`<span>${O(this.name)}</span>`:""}`;const t=this.edge(this.lens.toScreen(o));e=this.lens.toPage(t),this.put(this.cursor,t),this.cursor.dataset.adFrom=`${t.x},${t.y}`,this.root.append(this.cursor)}const r=this.cursor;if(await this.move(t,r,e,o),t!==this.generation)return;const a=this.lens.toScreen(o);r.dataset.adLanded=`${a.x},${a.y}`,e=o;for(const e of n.elements)this.show(t,e);const h=r.querySelector("svg");h&&await this.play(t,260*this.durationScale,t=>{h.style.transform=`scale(${t<.35?1-t/.35*.1:.9+(t-.35)/.65*.1})`}),h&&t===this.generation&&(h.style.transform="")}if(t===this.generation){if(s.length)for(const e of this.take(s))this.show(t,e);if(t===this.generation){if(this.cursor&&e){const i=this.lens.toPage(this.edge(this.lens.toScreen(e)));await this.move(t,this.cursor,e,i)}if(t===this.generation){if(this.cursor?.remove(),this.cursor=void 0,this.queue.length)return this.run(t);this.clear()}}}}},nt=class{host;options;root=document.createElement("div");world=document.createElement("div");overlay=document.createElementNS(D,"svg");lens;kinds;resolveOutline=t=>this.kinds.get(t.kind)?.outline?.(t);grid=document.createElement("div");records=/* @__PURE__ */new Map;lookup=/* @__PURE__ */new Map;originals=/* @__PURE__ */new Map;ancestors=/* @__PURE__ */new Map;locked=/* @__PURE__ */new Set;presence;dependencies=/* @__PURE__ */new Map;previousDrafts=/* @__PURE__ */new Set;paintedTheme;index=new o;visible=/* @__PURE__ */new Set;selected=[];marquee;overlayMarkup="";theme="light";mediaQuery;mediaListener;settleTimer;cameraFrame=0;disposed=!1;doc;pageId;drafts;constructor(t,e={}){this.host=t,this.options=e,this.kinds=X(e.kinds),this.root.className="ad-root",this.root.tabIndex=0,this.root.setAttribute("role","application"),this.root.setAttribute("aria-label","Drawing board"),this.grid.className="ad-grid",this.world.className="ad-world",this.overlay.classList.add("ad-overlay"),this.overlay.setAttribute("aria-label","Selection controls"),this.root.append(this.grid,this.world,this.overlay),t.append(this.root),this.lens=new V(this.root),this.lens.onChange(()=>{this.cameraFrame||(this.cameraFrame=requestAnimationFrame(()=>{this.cameraFrame=0,this.updateCamera()}))}),"undefined"!=typeof matchMedia&&(this.mediaQuery=matchMedia("(prefers-color-scheme: dark)"),this.mediaListener=()=>{e.theme&&"auto"!==e.theme||this.setTheme("auto")},this.mediaQuery.addEventListener("change",this.mediaListener)),this.setTheme(e.theme??"light"),this.updateCamera()}setTheme(t){this.options.theme=t,this.theme="auto"===t?this.mediaQuery?.matches?"dark":"light":t,this.root.dataset.theme=this.theme,this.doc&&this.pageId&&this.render(this.doc,this.pageId,this.drafts)}get resolvedTheme(){return this.theme}whenPresentationIdle(t){this.presence?this.presence.whenIdle(t):t()}present(t,e){if(!1===this.options.agentPresence)return;const i=new Set(t),s=t.filter(t=>!this.ancestors.get(t)?.some(t=>i.has(t))).flatMap(t=>{const e=this.records.get(t),i=this.lookup.get(t);return e&&i&&!e.hidden?[{box:e.view.bounds,elements:w([i]).flatMap(t=>{const e=this.records.get(t.id);return e&&!e.hidden?[e.view.element]:[]})}]:[]});s.length&&(this.presence??=new st(this.root,this.lens,"object"==typeof this.options.agentPresence?this.options.agentPresence:void 0),this.presence.enqueue(s,e))}finishPresentation(){this.presence?.clear()}prunePresentation(){this.presence?.prune()}isPending(t){const e=this.records.get(t)?.view.element;return!!e&&!!this.presence?.holds(e)}render(t,e,i){if(this.disposed)return;const s=this.doc===t&&this.pageId===e&&this.paintedTheme===this.theme;if(this.doc=t,this.pageId=e,this.drafts=i,s)return void this.renderDrafts(i);this.paintedTheme=this.theme;const n=t.pages.find(t=>t.id===e);this.root.style.backgroundColor=P(n?.background??("dark"===this.theme?"#122f32":"#fbfcfa"),this.theme);const o=[];this.lookup.clear(),this.originals.clear(),this.ancestors.clear(),this.dependencies.clear();const r=(t,e,s)=>{for(const n of t){const t=k(n,i?.get(n.id)),a=s||!!t.hidden;if(this.lookup.set(t.id,t),this.originals.set(t.id,n),this.ancestors.set(t.id,e.map(t=>t.id)),"connector"===t.kind)for(const e of[t.from,t.to]){if(!e||!("item"in e))continue;const i=this.dependencies.get(e.item)??/* @__PURE__ */new Set;i.add(t.id),this.dependencies.set(e.item,i)}o.push({item:t,hidden:a}),t.children&&r(t.children,[...e,t],a)}};r(n?.items??[],[],!1),this.locked=K(n?.items??[]);const a=/* @__PURE__ */new Set;for(let d=0;d<o.length;d++){const{item:e,hidden:i}=o[d];a.add(e.id);let s=this.records.get(e.id);const n=E(e,this.lookup,this.resolveOutline),r={minX:n.x,minY:n.y,maxX:n.x+n.w,maxY:n.y+n.h,id:e.id};s?s.entry.minX===r.minX&&s.entry.minY===r.minY&&s.entry.maxX===r.maxX&&s.entry.maxY===r.maxY||(this.index.remove(s.entry),s.entry=r,this.index.insert(r)):(s={view:new _(e.id),entry:r,hidden:i},this.records.set(e.id,s),this.index.insert(r)),s.hidden=i,s.view.bounds=n,s.view.paint(e,t,this.lookup,this.theme,this.kinds.get(e.kind),this.options.sanitizeHTML,this.resolveOutline),s.view.element.style.zIndex!==String(d)&&(s.view.element.style.zIndex=String(d))}for(const[d,l]of this.records)a.has(d)||(this.index.remove(l.entry),l.view.destroy(),this.records.delete(d),this.visible.delete(d));const h=o.map(({item:t})=>this.records.get(t.id)).sort((t,e)=>t.view.bounds.y-e.view.bounds.y||t.view.bounds.x-e.view.bounds.x);for(let d=0;d<h.length;d++){const t=h[d].view.element;this.world.children[d]!==t&&this.world.insertBefore(t,this.world.children[d]??null)}this.previousDrafts=new Set(i?.keys()),this.updateCulling(),this.paintOverlay(),this.presence?.prune()}renderDrafts(t){const e=/* @__PURE__ */new Set([...this.previousDrafts,...t?.keys()??[]]);for(const i of e){const s=this.originals.get(i);if(!s)continue;const n=t?.get(i);this.lookup.set(i,k(s,n));for(const t of this.ancestors.get(i)??[])e.add(t);if(s.children)for(const t of w(s.children))e.add(t.id)}for(const i of[...e])for(const t of this.dependencies.get(i)??[])e.add(t);for(const i of e){const t=this.lookup.get(i),e=this.records.get(i);if(!t||!e)continue;const s=E(t,this.lookup,this.resolveOutline),n={minX:s.x,minY:s.y,maxX:s.x+s.w,maxY:s.y+s.h,id:i};JSON.stringify(n)!==JSON.stringify(e.entry)&&(this.index.remove(e.entry),this.index.insert(n),e.entry=n),e.view.bounds=s;const o=(this.ancestors.get(i)??[]).map(t=>this.lookup.get(t)).filter(Boolean);e.hidden=!!t.hidden||o.some(t=>t.hidden),e.view.paint(t,this.doc,this.lookup,this.theme,this.kinds.get(t.kind),this.options.sanitizeHTML,this.resolveOutline)}this.previousDrafts=new Set(t?.keys()),e.size&&(this.updateCulling(),this.paintOverlay()),this.presence?.prune()}setSelection(t){if(t.length===this.selected.length&&t.every((t,e)=>t===this.selected[e]))return;const e=new Set(this.selected);this.selected=[...t];for(const i of e)t.includes(i)||this.records.get(i)?.view.element.removeAttribute("data-ad-selected");for(const i of t)this.records.get(i)?.view.element.setAttribute("data-ad-selected","true");this.paintOverlay()}setMarquee(t){this.marquee=t,this.paintOverlay()}updateCamera(){const{x:t,y:e,zoom:i}=this.lens.state;this.world.style.transform=`translate3d(${t}px,${e}px,0) scale(${i})`,this.world.style.willChange="transform",clearTimeout(this.settleTimer),this.settleTimer=setTimeout(()=>{this.world.style.willChange=""},150);const s=24*i*(i<.3?4:i<.6?2:1);this.grid.style.backgroundSize=`${s}px ${s}px`,this.grid.style.backgroundPosition=`${t}px ${e}px`,this.updateCulling(),this.paintOverlay()}updateCulling(){const t=this.lens.viewport(200),e=this.index.search({minX:t.x,minY:t.y,maxX:t.x+t.w,maxY:t.y+t.h}),i=new Set(e.filter(t=>!this.records.get(t.id)?.hidden).map(t=>t.id));for(const s of this.visible)if(!i.has(s)){const t=this.records.get(s);t&&(t.view.element.style.display="none")}for(const s of i)if(!this.visible.has(s)){const t=this.records.get(s);t&&(t.view.element.style.display="")}this.visible=i}paintOverlay(){const t=[],e=this.selected.map(t=>this.lookup.get(t)).filter(t=>!!t&&!t.hidden);if(e.length){const i=1===e.length&&!["connector","line","path","group"].includes(e[0].kind),s=i?e[0]:b(e,this.lookup,this.resolveOutline),n=i?e[0].rotation??0:0,o=$(s,n).map(t=>this.lens.toScreen(t));t.push(`<path class="ad-selection-outline" d="${A(o,!0)}"/>`);const r=[["nw",o[0],"nwse-resize"],["n",{x:(o[0].x+o[1].x)/2,y:(o[0].y+o[1].y)/2},"ns-resize"],["ne",o[1],"nesw-resize"],["e",{x:(o[1].x+o[2].x)/2,y:(o[1].y+o[2].y)/2},"ew-resize"],["se",o[2],"nwse-resize"],["s",{x:(o[2].x+o[3].x)/2,y:(o[2].y+o[3].y)/2},"ns-resize"],["sw",o[3],"nesw-resize"],["w",{x:(o[3].x+o[0].x)/2,y:(o[3].y+o[0].y)/2},"ew-resize"]];if(!e.some(t=>this.locked.has(t.id))){for(const[e,i,s]of r)t.push(`<rect class="ad-selection-handle" data-ad-handle="${e}" x="${i.x-4}" y="${i.y-4}" width="8" height="8" rx="2" style="cursor:${s}" aria-label="Resize ${e}"/>`);{const e=r[1][1],i=n*Math.PI/180,s={x:e.x+26*Math.sin(i),y:e.y-26*Math.cos(i)};t.push(`<path class="ad-selection-outline" d="M${e.x},${e.y}L${s.x},${s.y}"/><circle class="ad-selection-handle" data-ad-handle="rotate" cx="${s.x}" cy="${s.y}" r="4.5" style="cursor:grab" aria-label="Rotate"/>`)}}}if(1===e.length&&!this.locked.has(e[0].id)){const i=e[0],s=this.kinds.get(i.kind)?.handles?.(i)??[],n=(i.rotation??0)*Math.PI/180;for(const e of s){const s=e.x-i.w/2,o=e.y-i.h/2,r=this.lens.toScreen({x:i.x+i.w/2+s*Math.cos(n)-o*Math.sin(n),y:i.y+i.h/2+s*Math.sin(n)+o*Math.cos(n)});t.push(`<circle class="ad-selection-handle ad-custom-handle" data-ad-custom-handle="${O(e.id)}" data-ad-handle="custom:${O(e.id)}" cx="${r.x}" cy="${r.y}" r="5" style="cursor:${O(e.cursor??"crosshair")}" aria-label="${O(e.label??e.id)}"/>`)}}if(this.marquee){const e=this.lens.toScreen(this.marquee);t.push(`<rect class="ad-marquee" x="${e.x}" y="${e.y}" width="${Math.max(0,this.marquee.w*this.lens.zoom)}" height="${Math.max(0,this.marquee.h*this.lens.zoom)}"/>`)}const i=t.join("");i!==this.overlayMarkup&&(this.overlayMarkup=i,this.overlay.innerHTML=i)}destroy(){this.disposed=!0,this.presence?.destroy(),clearTimeout(this.settleTimer),cancelAnimationFrame(this.cameraFrame),this.mediaQuery&&this.mediaListener&&this.mediaQuery.removeEventListener("change",this.mediaListener),this.lens.destroy();for(const t of this.records.values())t.view.destroy();this.records.clear(),this.index.clear(),this.root.remove()}};function ot(t,e,i){if(!t.text?.value)return"";const s=T(t.text),n="text"===t.kind?0:"note"===t.kind?20:12,o=i?220:t.w*("diamond"===t.kind?.6:"ellipse"===t.kind?.75:1)-2*n,r=function(t,e,i){return C(t,e,i,.53)}(t.text.value,o,s),a=1.35*s,h=t.text.align??("text"===t.kind?"start":"center"),d="start"===h?"start":"end"===h?"end":"middle",l=i?.x??("start"===h?n:"end"===h?t.w-n:t.w/2),c=r.length*a,p=i?i.y-c/2+s:"top"===t.text.valign?n+s:"bottom"===t.text.valign?t.h-n-c+s:(t.h-c)/2+s,u=Math.max(...r.map(t=>t.length))*s*.53;return`${i?`<rect x="${l-u/2-7}" y="${i.y-c/2-2}" width="${u+14}" height="${c+4}" rx="4" fill="${P("paper",e)}"/>`:""}<text x="${l}" y="${p}" font-family="${O(j(t.text.font))}" font-size="${s}" text-anchor="${i?"middle":d}" fill="${O(L(t,e))}">${r.map((t,e)=>`<tspan x="${l}" dy="${e?a:0}">${O(t)||" "}</tspan>`).join("")}</text>`}function rt(t,e,i){const s=Math.max(1,Math.floor(e/(.52*i))),n=t.trim();return n.length<=s?n:`${n.slice(0,Math.max(1,s-1))}…`}function at(t,e){const i=a(t);return i?`<a href="${O(i)}" target="_blank" rel="noopener noreferrer" style="text-decoration:none">${e}</a>`:e}function ht(t,s,n,o){const r=Math.min(t.style?.corner??12,t.w/2,t.h/2),h=t.w,d=t.h,l=`adx${o}`,c=R.sans,p=t.href,u=function(t,i){const s=t.text?.value?.trim()||t.name?.trim();if(s&&s.toLowerCase()!==t.kind)return s;if(i){const t=e(i).split(".")[0]??"";if(t)return t[0].toUpperCase()+t.slice(1)}return"video"===t.kind?"Video":"Link"}(t,p),m=function(t){const i=a(t);if(!i)return"";try{const t=new URL(i),s=decodeURIComponent(t.pathname).replace(/\/$/,""),n=`${e(i)}${s}`;return t.search&&n.length<36?`${n}${t.search}`:n}catch{return i.replace(/^https?:\/\//,"").replace(/\/$/,"")}}(p),g=Math.max(10,Math.min(14,.04*h)),f=`<defs><clipPath id="${l}p"><rect width="${h}" height="${d}" rx="${r}"/></clipPath></defs>`;if("video"===t.kind){const t=i(p),e="vimeo"===t?.provider?"Vimeo":t?"YouTube":"",s=.11*Math.min(h,d),n=d>=96?.58*d:d,o=h/2+.06*s,r=d/2,a=rt(u,h-2*g,15),y=rt(m,h-2*g,12);return`${f}<defs>\n <linearGradient id="${l}g" x1="0" y1="0" x2="1" y2="1"><stop offset="0" stop-color="#16494c"/><stop offset="1" stop-color="#103639"/></linearGradient>\n <radialGradient id="${l}s" cx="50%" cy="50%" r="58%"><stop offset="0" stop-color="#05D9AB" stop-opacity=".2"/><stop offset="1" stop-color="#103639" stop-opacity="0"/></radialGradient>\n <linearGradient id="${l}c" x1="0" y1="0" x2="0" y2="1"><stop offset="0" stop-color="#103639" stop-opacity="0"/><stop offset="1" stop-color="#103639" stop-opacity=".92"/></linearGradient>\n </defs>${at(p,`<g clip-path="url(#${l}p)">\n <rect width="${h}" height="${d}" fill="url(#${l}g)"/><rect width="${h}" height="${d}" fill="url(#${l}s)"/>\n <circle cx="${N(h/2)}" cy="${N(r)}" r="${N(1.7*s)}" fill="#fff" fill-opacity=".1"/>\n <path d="M${N(o-.36*s)} ${N(r-.7*s)}L${N(o+.7*s)} ${N(r)}L${N(o-.36*s)} ${N(r+.7*s)}Z" fill="#fff"/>\n ${d>=96?`<rect y="${N(n)}" width="${h}" height="${N(d-n)}" fill="url(#${l}c)"/>`:""}\n ${e&&d>=120?`<text x="${g}" y="${g+10}" fill="#05D9AB" font-family="${O(c)}" font-size="11" font-weight="700">${e}</text>`:""}\n <text x="${g}" y="${d-(y?28:16)}" fill="#fff" font-family="${O(c)}" font-size="15" font-weight="700">${O(a)}</text>\n ${y?`<text x="${g}" y="${d-12}" fill="#B6C5C1" font-family="${O(c)}" font-size="12">${O(y)}</text>`:""}\n </g>`)}`}const y=d>=118?Math.min(.48*d,d-62):0,x=t.media?n.media[t.media]:void 0,v=u.trim().slice(0,1).toUpperCase()||"•",w=y?x?`<image width="${h}" height="${y}" href="${O(x.src)}" preserveAspectRatio="xMidYMid slice"/>`:`<rect width="${h}" height="${y}" fill="#8F93F914"/><text x="${h/2}" y="${y/2+11}" text-anchor="middle" fill="#8F93F9" font-family="${O(c)}" font-size="${Math.min(34,.28*y)}" font-weight="700">${O(v)}</text>`:"",k=y?y+20:24,b=rt(u,h-2*g,15),$=rt(m,h-2*g,12),M=t.description&&d-y>78?rt(t.description,h-2*g,12):"",S="dark"===s?"#ffffff14":"#10363914";return`${f}${at(p,`<g clip-path="url(#${l}p)">\n <rect width="${h}" height="${d}" fill="${P("paper",s)}"/>${w}\n <text x="${g}" y="${k}" fill="${P("ink",s)}" font-family="${O(c)}" font-size="15" font-weight="700">${O(b)}</text>\n ${$?`<text x="${g}" y="${k+18}" fill="${P("slate",s)}" font-family="${O(c)}" font-size="12">${O($)}</text>`:""}\n ${M?`<text x="${g}" y="${k+36}" fill="${P("slate",s)}" font-family="${O(c)}" font-size="12">${O(M)}</text>`:""}\n </g><rect width="${h}" height="${d}" rx="${r}" fill="none" stroke="${S}"/>`)}`}var dt=/* @__PURE__ */new Uint32Array(256);for(let It=0;It<256;It++){let t=It;for(let e=0;e<8;e++)t=1&t?3988292384^t>>>1:t>>>1;dt[It]=t}function lt(t){return Uint8Array.of(t>>>24&255,t>>>16&255,t>>>8&255,255&t)}function ct(t,e){const i=Uint8Array.of(t.charCodeAt(0),t.charCodeAt(1),t.charCodeAt(2),t.charCodeAt(3)),s=new Uint8Array(12+e.length);return s.set(lt(e.length)),s.set(i,4),s.set(e,8),s.set(lt(function(t){let e=-1;for(const i of t)for(const t of i)e=dt[255&(e^t)]^e>>>8;return~e>>>0}([i,e])),8+e.length),s}function pt(t,e,i,s){return(t<<24|e<<16|i<<8|s)>>>0}function ut(t){const e=/* @__PURE__ */new Uint32Array(32768);let i=0;for(let n=0;n<t.length;n+=4)t[n+3]<128?i++:e[t[n]>>3<<10|t[n+1]>>3<<5|t[n+2]>>3]++;const s=[];i&&s.push({r:0,g:0,b:0,a:0,n:i});for(let n=0;n<32768;n++){const t=e[n];if(!t)continue;const i=n>>10<<3,o=(n>>5&31)<<3,r=(31&n)<<3;s.push({r:i|i>>5,g:o|o>>5,b:r|r>>5,a:255,n:t})}return s}function mt(t){let e=255,i=0,s=255,n=0,o=255,r=0,a=255,h=0;for(const u of t)u.r<e&&(e=u.r),u.r>i&&(i=u.r),u.g<s&&(s=u.g),u.g>n&&(n=u.g),u.b<o&&(o=u.b),u.b>r&&(r=u.b),u.a<a&&(a=u.a),u.a>h&&(h=u.a);const d=i-e,l=n-s,c=r-o,p=h-a;return d>=l&&d>=c&&d>=p?"r":l>=c&&l>=p?"g":c>=p?"b":"a"}function gt(t){let e=0,i=0,s=0,n=0,o=0;for(const r of t)e+=r.r*r.n,i+=r.g*r.n,s+=r.b*r.n,n+=r.a*r.n,o+=r.n;return{r:Math.round(e/o),g:Math.round(i/o),b:Math.round(s/o),a:Math.round(n/o)}}function ft(t,e,i,s,n){let o=0,r=1/0;for(let a=0;a<t.length;a++){const h=t[a],d=(e-h.r)**2+(i-h.g)**2+(s-h.b)**2+(n-h.a)**2;d<r&&(r=d,o=a)}return o}function yt(t,e){const i=Math.min(256,Math.max(1,Math.trunc(e))),{colors:s,exact:n}=function(t){const e=/* @__PURE__ */new Map;for(let i=0;i<t.length;i+=4){const s=pt(t[i],t[i+1],t[i+2],t[i+3]),n=e.get(s);if(n)n.n++;else{if(e.size>=4096)return{colors:ut(t),exact:!1};e.set(s,{r:t[i],g:t[i+1],b:t[i+2],a:t[i+3],n:1})}}return{colors:[...e.values()],exact:!0}}(t),o=n&&s.length<=i?s.map(({r:t,g:e,b:i,a:s})=>({r:t,g:e,b:i,a:s})):function(t,e){if(t.length<=e)return t.map(({r:t,g:e,b:i,a:s})=>({r:t,g:e,b:i,a:s}));const i=[t];for(;i.length<e;){let t=-1,e=-1;for(let h=0;h<i.length;h++){if(i[h].length<2)continue;const s=mt(i[h]);let n=255,o=0;for(const t of i[h]){const e=t[s];e<n&&(n=e),e>o&&(o=e)}const r=o-n;r>e&&(e=r,t=h)}if(t<0)break;const s=i[t],n=mt(s);s.sort((t,e)=>t[n]-e[n]);let o=0;for(const i of s)o+=i.n;let r=0,a=Math.max(1,s.length>>1);for(let i=0;i<s.length-1;i++)if(r+=s[i].n,r>=o/2){a=i+1;break}i[t]=s.slice(0,a),i.push(s.slice(a))}return i.map(gt)}(s,i),r=new Uint8Array(t.length/4);if(n&&s.length<=i){const e=/* @__PURE__ */new Map;for(let t=0;t<o.length;t++){const i=o[t];e.set(pt(i.r,i.g,i.b,i.a),t)}for(let i=0,s=0;i<r.length;i++,s+=4)r[i]=e.get(pt(t[s],t[s+1],t[s+2],t[s+3]))}else{const e=/* @__PURE__ */new Map;for(let i=0,s=0;i<r.length;i++,s+=4){const n=pt(t[s],t[s+1],t[s+2],t[s+3]);let a=e.get(n);void 0===a&&(a=ft(o,t[s],t[s+1],t[s+2],t[s+3]),e.set(n,a)),r[i]=a}}return{palette:o,indices:r}}async function xt(t,e,i,s){if(t<1||e<1||i.length<1||i.length>256)throw new Error("Indexed PNG dimensions or palette are invalid.");if(s.length!==t*e)throw new Error("Indexed PNG indices do not match size.");const n=/* @__PURE__ */new Uint8Array(13);n.set(lt(t)),n.set(lt(e),4),n[8]=8,n[9]=3;const o=new Uint8Array(3*i.length);let r=-1;for(let p=0;p<i.length;p++)o[3*p]=i[p].r,o[3*p+1]=i[p].g,o[3*p+2]=i[p].b,i[p].a<255&&(r=p);const a=new Uint8Array((t+1)*e);for(let p=0;p<e;p++){const e=p*(t+1);a[e]=0,a.set(s.subarray(p*t,(p+1)*t),e+1)}const h=[Uint8Array.of(137,80,78,71,13,10,26,10),ct("IHDR",n),ct("PLTE",o)];if(r>=0){const t=new Uint8Array(r+1);for(let e=0;e<=r;e++)t[e]=i[e].a;h.push(ct("tRNS",t))}h.push(ct("IDAT",await async function(t){if("function"!=typeof CompressionStream)throw new Error("CompressionStream is unavailable.");const e=new Response(t).body;if(!e)throw new Error("CompressionStream is unavailable.");return new Uint8Array(await new Response(e.pipeThrough(new CompressionStream("deflate"))).arrayBuffer())}(a)),ct("IEND",/* @__PURE__ */new Uint8Array));let d=0;for(const p of h)d+=p.length;const l=new Uint8Array(d);let c=0;for(const p of h)l.set(p,c),c+=p.length;return new Blob([l],{type:"image/png"})}var vt={png:"image/png",jpeg:"image/jpeg",webp:"image/webp"},wt=[.85,.7,.55,.4];var kt=/* @__PURE__ */new Map;function bt(t,e){const i=JSON.stringify(e),s=kt.get(i);if(s)return kt.delete(i),kt.set(i,s),s;const n=t.createElement("div");n.style.cssText="position:fixed;left:-100000px;top:0;visibility:hidden;pointer-events:none;white-space:pre;line-height:1.35;width:max-content;max-width:none;padding:0;border:0;",n.style.fontFamily=j(e.font),n.style.fontSize=`${T(e)}px`,n.textContent=e.value||" ",t.body.append(n);const o=n.getBoundingClientRect(),r={w:Math.max(24,Math.ceil(o.width+4)),h:Math.max(1.35*T(e),Math.ceil(o.height))};return n.remove(),kt.set(i,r),kt.size>256&&kt.delete(kt.keys().next().value),r}var $t={v:"select",h:"hand",r:"rect",o:"ellipse",d:"diamond",l:"line",a:"connector",p:"path",t:"text",n:"note",e:"eraser"},Mt=class{host;stage;model;ready;readonly;agentName;selectionSignal=n([]);toolSignal=n("select");drafts=/* @__PURE__ */new Map;defaultStyle={stroke:"ink",strokeWidth:2,fill:"paper",corner:12};grid=!0;pageId;document;spatial=new r;geometryLookup=/* @__PURE__ */new Map;hiddenGeometry=/* @__PURE__ */new Set;lockedGeometry=/* @__PURE__ */new Set;listeners=/* @__PURE__ */new Map;cleanup=[];uiCleanup;frame=0;drag;rect;space=!1;clipboard=[];pointers=/* @__PURE__ */new Map;observedPointer;pointerInside=!1;pinch;editor;finishEditor;longPressTimer;lastTouchTap;touchDoubleAt=0;enteredGroup;destroyed=!1;themeValue;drawPreview;previewDocument;previewBase;observer;unfurl;agentReveal;pendingReveal;constructor(e,i={}){this.host=e,this.readonly=i.readonly??!1,this.agentName=i.agentName?.trim()||void 0,this.agentReveal=i.agentReveal??"fit",this.model=t(i.doc,{readonly:this.readonly,allowedImageOrigins:i.allowedImageOrigins,kinds:[...Y(),...i.kinds??[]],sanitizeHTML:i.sanitizeHTML,agentHistory:i.agentHistory,agentPlaceGap:i.agentPlaceGap}),this.document=this.model.toJSON({compact:!1}),this.pageId=this.document.pages[0].id,this.themeValue=i.theme??"light",this.unfurl=i.unfurl,this.stage=new nt(e,{agentPresence:i.agentPresence,theme:this.themeValue,kinds:i.kinds,sanitizeHTML:i.sanitizeHTML}),this.updateCursor(),this.refreshGeometry(),this.rect=this.stage.root.getBoundingClientRect(),this.stage.root.dataset.adBoard="",this.cleanup.push(this.model.on("change",t=>{this.document=this.model.toJSON({compact:!1}),this.document.pages.some(t=>t.id===this.pageId)||(this.pageId=this.document.pages[0].id),this.refreshGeometry(),(this.drag&&["move","resize","rotate","erase"].includes(this.drag.kind)&&this.drag.ids.some(t=>this.isLocked(t))||this.editor&&this.isLocked(this.editor.closest("[data-ad-id]")?.dataset.adId??""))&&this.cancel(),this.select(this.selection.filter(t=>!!this.get(t))),this.schedule(),this.emit("change",t)})),this.cleanup.push(this.stage.lens.onChange(t=>{this.schedule(),this.emit("view",t)}));const s=(t,e,i)=>{this.stage.root.addEventListener(t,e,i),this.cleanup.push(()=>this.stage.root.removeEventListener(t,e,i))};s("pointerenter",this.observePointer),s("pointerdown",this.observePointer),s("pointermove",this.observePointer),s("pointerleave",this.releasePointer),s("pointercancel",this.releasePointer),s("pointerup",t=>{this.observePointer(t),"mouse"!==t.pointerType&&this.releasePointer()}),s("pointerdown",this.pointerDown),s("pointermove",this.pointerMove),s("pointerup",this.pointerUp),s("pointercancel",this.pointerCancel),s("wheel",this.wheel,{passive:!1}),s("keydown",this.keyDown),s("keyup",t=>{"Space"===t.code&&(this.space=!1,this.updateCursor())}),s("dblclick",this.doubleClick),s("contextmenu",t=>{if(this.isUI(t.target))return;t.preventDefault();const e=t.target.closest("[data-ad-id]")?.dataset.adId;this.openContext(this.point(t),e)}),s("copy",this.copyEvent),s("cut",this.cutEvent),s("paste",this.pasteEvent),s("dragover",t=>{this.readonly||(t.preventDefault(),t.dataTransfer&&(t.dataTransfer.dropEffect="copy"))}),s("drop",this.drop),s("focusin",t=>{const e=t.target.closest("[data-ad-id]");e&&t.target===e&&!this.drag&&this.select([e.dataset.adId])});const n=()=>{this.releasePointer(),this.space=!1,this.finishEditor?.(!0),this.cancel(),this.updateCursor()};window.addEventListener("blur",n),this.cleanup.push(()=>window.removeEventListener("blur",n));const o=()=>{this.host.ownerDocument.hidden&&this.releasePointer()};this.host.ownerDocument.addEventListener("visibilitychange",o),this.cleanup.push(()=>this.host.ownerDocument.removeEventListener("visibilitychange",o)),this.observer=new ResizeObserver(()=>{this.rect=this.stage.root.getBoundingClientRect(),this.schedule()}),this.observer.observe(this.stage.root);const r=()=>{this.rect=this.stage.root.getBoundingClientRect()};window.addEventListener("scroll",r,!0),this.cleanup.push(()=>window.removeEventListener("scroll",r,!0)),!1!==i.ui&&(this.uiCleanup=F(this,"object"==typeof i.ui?i.ui:{})),this.render(),this.view.fit(),i.exposeGlobal&&(window.__anniedrawing??=[],window.__anniedrawing.push(this)),this.ready=i.autosaveKey&&!this.readonly?async function(t,e){let i,s,n=!1,o=()=>{};const r=JSON.stringify(t.read()),a=(e,i)=>{n||t.emit("save",{status:e,message:i})},h=()=>{if(!n&&i)try{a("saving");const s=i.transaction("boards","readwrite");s.objectStore("boards").put(t.read(),e),s.oncomplete=()=>a("saved"),s.onerror=()=>a("error","Could not save locally. Export your drawing to keep it.")}catch{a("error","Could not save locally. Export your drawing to keep it.")}},d=()=>{s&&(clearTimeout(s),s=void 0,h())};t.addCleanup(()=>{d(),n=!0,o(),window.removeEventListener("pagehide",d),i?.close()});try{if(i=await new Promise((t,e)=>{const i=indexedDB.open("anniedrawing",1);i.onupgradeneeded=()=>i.result.createObjectStore("boards"),i.onsuccess=()=>t(i.result),i.onerror=()=>e(i.error)}),n)return void i.close();const s=await new Promise((t,s)=>{const n=i.transaction("boards","readonly").objectStore("boards").get(e);n.onsuccess=()=>t(n.result),n.onerror=()=>s(n.error)});if(n)return void i.close();s&&JSON.stringify(t.read())===r&&t.load(s),a("saved")}catch{return void a("error","Browser storage is unavailable. Export your drawing to keep it.")}o=t.on("change",()=>{a("saving"),s&&clearTimeout(s),s=setTimeout(()=>{s=void 0,h()},300)}),window.addEventListener("pagehide",d)}(this,i.autosaveKey):Promise.resolve()}get selection(){return[...this.selectionSignal.value]}getPointer(){const t=this.observedPointer;if(this.destroyed||!t||t.pageId!==this.pageId)return null;const e=this.stage.root.getBoundingClientRect(),i=this.pointerInside&&e.width>0&&e.height>0&&t.client.x>=e.left&&t.client.x<e.right&&t.client.y>=e.top&&t.client.y<e.bottom,s=i?this.stage.lens.toPage({x:t.client.x-e.left,y:t.client.y-e.top}):t.page;return{...s,pageId:t.pageId,inside:i,pointerType:t.type,ageMs:Math.max(0,Date.now()-t.at),itemId:i?this.hit(s,!0)?.id??null:null}}get tool(){return this.toolSignal.value}get theme(){return this.themeValue}get canUndo(){return this.model.canUndo}get canRedo(){return this.model.canRedo}get revision(){return this.model.revision}changesSince(t,e){return this.model.changesSince(t,e)}get items(){return w(this.pageItems())}get view(){const t=this;return{fit(e){t.stage.lens.fit(t.boundsOf(e))},flyTo(e){t.stage.lens.flyTo(e)},get zoom(){return t.stage.lens.state.zoom},set zoom(e){t.zoomAt(e,{x:t.rect.width/2,y:t.rect.height/2})},get center(){return t.stage.lens.toPage({x:t.rect.width/2,y:t.rect.height/2})},set center(e){const i=t.view.zoom;t.stage.lens.set({x:t.rect.width/2-e.x*i,y:t.rect.height/2-e.y*i})}}}read(t="doc"){const e="string"==typeof t?{scope:t}:t,i=this.model.toJSON();if(e.includeDrafts&&this.drawPreview&&i.pages.find(t=>t.id===this.pageId)?.items.push(h(this.drawPreview)),e.scope&&"doc"!==e.scope&&(i.pages=i.pages.filter(t=>t.id===this.pageId)),"selection"===e.scope||"viewport"===e.scope){const t="selection"===e.scope?new Set(this.selection):new Set(this.items.filter(t=>!t.hidden&&this.visible(t)).map(t=>t.id)),s=e=>e.flatMap(e=>t.has(e.id)?[e]:s(e.children??[]));for(const e of i.pages)e.items=s(e.items)}if(e.includeDrafts)for(const s of i.pages.flatMap(t=>w(t.items))){const t=k(s,this.drafts.get(s.id));Object.assign(s,t)}if(e.scope&&"doc"!==e.scope){const t=new Set(i.pages.flatMap(t=>w(t.items)).map(t=>t.media));i.media=Object.fromEntries(Object.entries(i.media).filter(([e])=>t.has(e)))}return i}get(t){return this.model.get(t)}isLocked(t){return this.lockedGeometry.has(t)}lockedResult(t=0){return{ok:!1,created:[],errors:[{index:t,code:"LOCKED",message:"Unlock the selection before editing it."}],warnings:[]}}query(t={}){return this.model.query(t)}describe(t={}){return this.model.describe({...t,page:t.page??("doc"!==t.scope&&t.scope?this.pageId:void 0),selection:t.selection??this.selection,..."viewport"===t.scope?{ids:this.items.filter(t=>!t.hidden&&this.visible(t)).map(t=>t.id)}:{}})}kindsSince(t=0){return d(t)}boundsOf(t){const e=t?new Set(t):void 0,i=this.spatial.search({x:-1e7,y:-1e7,w:2e7,h:2e7}),s=e?i.filter(t=>e.has(t.id)):i;return b(s,this.geometryLookup,this.outline)}apply(t,e={}){const i=t=>!(!t||"object"!=typeof t)&&(("set"!==t.op||!1!==t.patch?.locked||1!==Object.keys(t.patch).length)&&(["set","remove","order","reparent"].includes(t.op)&&"id"in t&&this.isLocked(t.id)||("add"===t.op||"reparent"===t.op)&&!!t.parent&&this.isLocked(t.parent))),s=e.origin??"api";let n=(Array.isArray(t),t);const o=[];if("user"===s&&Array.isArray(t)){const s=t.flatMap((t,e)=>i(t)?[e]:[]);if(s.length&&!e.lenient)return this.lockedResult(s[0]);if(s.length&&e.lenient&&(o.push(...s.map(t=>({index:t,code:"LOCKED",message:"Unlock the selection before editing it."}))),n=t.filter((t,e)=>!s.includes(e)),!n.length))return{ok:!1,created:[],errors:[],warnings:[],skipped:o}}const r=Array.isArray(n)?n.map(t=>{if(!t||"object"!=typeof t)return t;if("add"===t.op&&t.item){let e=t.item;return s.startsWith("agent:")&&"text"===e.kind&&void 0===e.autoWidth&&(e={...e,autoWidth:!0}),"text"===e.kind&&e.autoWidth&&"string"==typeof e.text?.value&&e.text.value.length<=f.maxTextLength&&(e={...e,...bt(this.host.ownerDocument,e.text)}),{...t,item:e,...t.page||t.parent?{}:{page:this.pageId}}}if("set"===t.op&&t.patch){const e=this.get(t.id);if("text"===e?.kind&&(t.patch.autoWidth??e.autoWidth??s.startsWith("agent:"))&&(t.patch.text||t.patch.autoWidth)){const i={...e.text,...t.patch.text};if("string"==typeof i.value&&i.value.length<=f.maxTextLength)return{...t,patch:{...t.patch,...bt(this.host.ownerDocument,i)}}}}return t}):n,a=this.model.apply(r,{origin:"api",...e});if(o.length&&Array.isArray(t)){const e=new Set(o.map(t=>t.index)),i=t.map((t,e)=>e).filter(t=>!e.has(t)),s=t=>t?.map(t=>({...t,index:i[t.index]??t.index}));a.errors=s(a.errors)??a.errors,a.warnings=s(a.warnings)??a.warnings,a.skipped=[...o,...s(a.skipped)??[]].sort((t,e)=>t.index-e.index)}if(a.ok&&!e.dryRun&&a.created.length){if(s.startsWith("agent:")){this.render();const t=(e.agentName??this.agentName)?.trim()||void 0;this.stage.present(a.created,t)}"fit"===(e.reveal??(s.startsWith("agent:")?this.agentReveal:"none"))&&this.queueReveal(a.created)}return a}queueReveal(t){this.pendingReveal=[.../* @__PURE__ */new Set([...this.pendingReveal??[],...t])],this.stage.whenPresentationIdle(()=>this.flushReveal())}flushReveal(){const t=this.pendingReveal;this.pendingReveal=void 0,t?.length&&!this.destroyed&&this.revealCreated(t)}revealCreated(t){const e=t.filter(t=>w(this.pageItems()).some(e=>e.id===t));e.length&&(e.every(t=>{const e=this.get(t);return!!e&&this.visible(e)})||this.view.fit(e))}undo(t){return this.cancel(),this.model.undo(t)}redo(){return this.cancel(),this.model.redo()}load(t){this.cancel(),this.pendingReveal=void 0,this.model.load(t),this.document=this.model.toJSON({compact:!1}),this.pageId=this.document.pages[0].id,this.refreshGeometry(),this.select([]),this.render(),this.view.fit()}clear(){this.cancel(),this.pendingReveal=void 0,this.model.clear(),this.document=this.model.toJSON({compact:!1}),this.pageId=this.document.pages[0].id,this.refreshGeometry(),this.select([]),this.render(),this.view.fit()}select(t){const e=[...new Set(t)].filter(t=>!!this.get(t));e.join(",")!==this.selectionSignal.value.join(",")&&(this.selectionSignal.value=e,this.stage.setSelection(e),this.emit("select",e))}setTool(t){this.cancel(),this.toolSignal.value=t,this.updateCursor(),this.emit("tool",t)}setTheme(t){this.themeValue=t,this.stage.setTheme(t)}setPage(t){this.document.pages.some(e=>e.id===t)&&(this.observedPointer=void 0,this.pointerInside=!1,this.cancel(),this.pendingReveal=void 0,this.pageId=t,this.refreshGeometry(),this.enteredGroup=void 0,this.select([]),this.render(),this.view.fit(),this.emit("page",t))}setGrid(t){this.grid=t,this.stage.root.classList.toggle("ad-no-grid",!t)}on(t,e){const i=this.listeners.get(t)??/* @__PURE__ */new Set;return i.add(e),this.listeners.set(t,i),()=>i.delete(e)}emit(t,e){this.listeners.get(t)?.forEach(t=>t(e))}async export(t,e={}){const i=this.read(e.scope??"page");if("json"===t)return I(i.pages.flatMap(t=>t.items),this.geometryLookup,this.outline),G(i);const s=i.pages.flatMap(t=>t.items).map(t=>this.get(t.id)??t),n=function(t,e,i={}){const s=i.theme??"light",n=M(t),o=new Map(n.map(t=>[t.id,t])),r=X(i.kinds),a=t=>r.get(t.kind)?.outline?.(t),h=/* @__PURE__ */new Set,d=(t,e)=>{for(const i of t)(e||i.hidden)&&h.add(i.id),i.children&&d(i.children,e||!!i.hidden)};for(const x of t.pages)d(x.items,!1);const l=/* @__PURE__ */new Set,c=w(e).filter(t=>!(l.has(t.id)||h.has(t.id)||t.hidden||(l.add(t.id),0))),p=i.bounds??(c.length?b(c,o,a):{x:0,y:0,w:800,h:600}),u=Math.max(0,i.padding??32),m=p.x-u,g=p.y-u-(i.labels?18:0),f=Math.max(1,p.w+2*u),y=Math.max(1,p.h+2*u+(i.labels?18:0)),v=[];for(const[w,b]of c.entries()){let e="";const n=r.get(b.kind),h="connector"===b.kind?x(b,o,a):void 0;if(n?.toSVG){const i=n.toSVG(b,{doc:t,theme:s,color:t=>P(t,s),escape:O});e="string"==typeof i?i:(new XMLSerializer).serializeToString(i)}else if(["rect","ellipse","diamond","note","line","path","connector"].includes(b.kind))e=q(b,s,`export_${w}`,h?.d),(h||"line"===b.kind)&&(e+=B(h?.points??(b.points??[[0,0],[b.w,b.h]]).map(([t,e])=>({x:t,y:e})),b,s));else if("image"===b.kind){const i=b.media?t.media[b.media]:void 0,s=Math.min(b.style?.corner??12,b.w/2,b.h/2),n=`export_clip_${w}`;if(i){const t=b.crop&&b.crop.w>0&&b.crop.h>0?`<svg width="${b.w}" height="${b.h}" viewBox="${b.crop.x} ${b.crop.y} ${b.crop.w} ${b.crop.h}" preserveAspectRatio="none" overflow="hidden"><image width="${i.w}" height="${i.h}" href="${O(i.src)}" preserveAspectRatio="none"/></svg>`:`<image width="${b.w}" height="${b.h}" href="${O(i.src)}" preserveAspectRatio="none"/>`;e=`<defs><clipPath id="${n}"><rect width="${b.w}" height="${b.h}" rx="${s}"/></clipPath></defs><g clip-path="url(#${n})">${t}</g>`}}else"video"===b.kind||"link"===b.kind?e=ht(b,s,t,w):["text","group"].includes(b.kind)||(e=`<rect width="${b.w}" height="${b.h}" rx="8" fill="${P("paper",s)}" stroke="#8F93F9" stroke-dasharray="5 4"/><text x="12" y="24" fill="${P("ink",s)}" font-family="${O(R.sans)}" font-size="14">${O("html"===b.kind?"HTML content":`Unknown kind: ${b.kind}`)}</text>`);if("video"!==b.kind&&"link"!==b.kind&&(e+=ot(b,s,h?.midpoint)),i.labels){const t=h?h.bounds.x:0,i=h?h.bounds.y-22:-22;e+=`<rect x="${t}" y="${i}" width="${6.6*b.id.length+12}" height="17" rx="4" fill="#103639"/><text x="${t+6}" y="${i+12}" fill="#FFFFFF" font-family="monospace" font-size="10">${O(b.id)}</text>`}const d=h?"":`translate(${b.x} ${b.y}) rotate(${b.rotation??0} ${b.w/2} ${b.h/2})`,l=`<g data-ad-id="${O(b.id)}" data-ad-kind="${O(b.kind)}"${d?` transform="${d}"`:""}${void 0!==b.style?.opacity?` opacity="${b.style.opacity}"`:""}><title>${O(b.name??b.text?.value??b.kind)}</title>${e}</g>`;v.push(l)}const k=!1===i.background?"":P("string"==typeof i.background?i.background:"paper",s);return`<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="${f}" height="${y}" viewBox="${m} ${g} ${f} ${y}" role="img" aria-label="${O(t.meta.title)}"><title>${O(t.meta.title)}</title>${k?`<rect x="${m}" y="${g}" width="${f}" height="${y}" fill="${O(k)}"/>`:""}${v.join("")}</svg>`}(this.document,s,{...e,theme:this.stage.resolvedTheme,kinds:[...this.stage.kinds.values()],..."viewport"===e.scope?{bounds:this.stage.lens.viewport(),padding:0}:{}});if("svg"===t)return n;const o="png"===t&&!0===e.labels;return async function(t,e){const i=e.format;if("undefined"==typeof document)throw new Error(`${i.toUpperCase()} export requires a browser. Use SVG export in headless environments.`);let s=e.scale??2;if(!Number.isFinite(s)||s<=0||s>8)throw new Error(`${i.toUpperCase()} scale must be greater than zero and no greater than 8.`);const n="png"===i&&void 0!==e.colors?e.colors:void 0;if(void 0!==n&&(!Number.isInteger(n)||n<2||n>256))throw new Error("PNG colors must be an integer from 2 to 256.");const o=URL.createObjectURL(new Blob([t],{type:"image/svg+xml;charset=utf-8"}));try{const t=new Image;t.decoding="async",await new Promise((e,i)=>{t.onload=()=>e(),t.onerror=()=>i(/* @__PURE__ */new Error("This drawing could not be rasterised. Export SVG instead, or embed external images as data URLs.")),t.src=o});const r=Math.max(1,t.naturalWidth),a=Math.max(1,t.naturalHeight);if(e.maxSide&&Number.isFinite(e.maxSide)&&e.maxSide>0){const t=Math.max(r*s,a*s);t>e.maxSide&&(s*=e.maxSide/t)}const h="png"===i?[1]:[Math.min(1,Math.max(.1,e.quality??.85)),...wt.filter(t=>t<(e.quality??.85))],d=async(e,s,n)=>{const o=Math.max(1,Math.ceil(r*e)),h=Math.max(1,Math.ceil(a*e));if(o>16384||h>16384||o*h>64e6)throw new Error(`${i.toUpperCase()} is too large. Export a smaller selection or reduce the scale.`);const d=document.createElement("canvas");d.width=o,d.height=h;const l=d.getContext("2d",n?{willReadFrequently:!0}:void 0);if(!l)throw new Error(`This browser does not support ${i.toUpperCase()} export.`);if(l.drawImage(t,0,0,o,h),"png"===i&&n){const t=l.getImageData(0,0,o,h),e=yt(t.data,n);try{return await xt(o,h,e.palette,e.indices)}catch{!function(t,e,i){for(let s=0,n=0;s<i.length;s++,n+=4){const o=e[i[s]];t[n]=o.r,t[n+1]=o.g,t[n+2]=o.b,t[n+3]=o.a}}(t.data,e.palette,e.indices),l.putImageData(t,0,0)}}return await new Promise((t,e)=>{try{d.toBlob(s=>s?t(s):e(/* @__PURE__ */new Error(`The browser could not encode this ${i.toUpperCase()}.`)),vt[i],"png"===i?void 0:s)}catch{e(/* @__PURE__ */new Error(`An external image prevents ${i.toUpperCase()} export. Embed images as data URLs or export SVG.`))}})};if(!e.maxBytes)return d(s,h[0],n);let l,c=s;const p=t=>((!l||t.size<l.size)&&(l=t),t.size<=e.maxBytes);for(;c>=.25-1e-9;){if("png"===i){if(void 0===n&&await p(await d(c,1)))return l;if(await p(await d(c,1,n??g.colors)))return l}else for(const e of h)if(await p(await d(c,e)))return l;const t=c/2;if(t<.25-1e-9)break;c=t}return l??d(s,h[0],n)}finally{URL.revokeObjectURL(o)}}(n,{format:t,scale:e.scale??2,maxSide:e.maxSide,maxBytes:e.maxBytes??(o?g.maxBytes:void 0),quality:e.quality,colors:e.colors??(o?g.colors:void 0)})}destroy(){this.destroyed||(this.destroyed=!0,this.pendingReveal=void 0,this.cancel(),cancelAnimationFrame(this.frame),this.observer.disconnect(),this.cleanup.forEach(t=>t()),this.uiCleanup?.(),this.stage.destroy(),this.listeners.clear(),window.__anniedrawing&&(window.__anniedrawing=window.__anniedrawing.filter(t=>t!==this)))}addCleanup(t){this.cleanup.push(t)}focus(){this.stage.root.focus({preventScroll:!0})}add(t,e){const i=e??this.view.center,[s,n]=u(t),o=this.apply([{op:"add",page:this.pageId,item:{kind:t,x:i.x-s/2,y:i.y-n/2,w:s,h:n,style:h(this.defaultStyle),..."note"===t?{style:{...this.defaultStyle,fill:"moss",stroke:"none",corner:12},text:{value:"A little idea",size:"l"}}:{},..."text"===t?{autoWidth:!0,text:{value:"Type something…",size:"l"},style:{fill:"none",stroke:"ink"}}:{}}}],{origin:"user",label:`Add ${t}`});return o.ok&&(this.select(o.created),"text"!==t&&"note"!==t||this.editText(o.created[0])),o}updateSelection(t){if(!1===t.locked&&1===Object.keys(t).length){const e=new Set(this.selection),i=[],s=(t,n=!1)=>{n||=e.has(t.id);let o=!1;for(const e of t.children??[])o=s(e,n)||o;return t.locked&&(n||o)&&i.push(t.id),n||o};return this.document.pages.forEach(t=>t.items.forEach(t=>s(t))),this.apply(i.map(e=>({op:"set",id:e,patch:t})),{origin:"user",label:"Unlock selection"})}return this.apply(this.selection.map(e=>({op:"set",id:e,patch:t})),{origin:"user",label:"Change style"})}deleteSelection(){if(this.selection.some(t=>this.isLocked(t)))return;const t=this.topSelection();this.apply(t.map(t=>({op:"remove",id:t})),{origin:"user",label:"Delete"}),this.select([]),this.focus()}duplicate(t=24){if(this.selection.some(t=>this.isLocked(t)))return this.lockedResult();const e=this.topSelection().map(t=>this.get(t)).filter(Boolean),i=S(e,t),s=this.apply(i.map(t=>({op:"add",item:t,page:this.pageId})),{origin:"user",label:"Duplicate"});return s.ok&&this.select(i.map(t=>t.id)),s}group(){if(this.selection.length<2||this.selection.some(t=>this.isLocked(t)))return;const t=this.topSelection(),e=this.boundsOf(t),i=c();this.apply([{op:"add",page:this.pageId,item:{kind:"group",id:i,...e,children:[]}},...t.map(t=>({op:"reparent",id:t,parent:i}))],{origin:"user",label:"Group"}),this.select([i])}ungroup(){if(this.selection.some(t=>this.isLocked(t)))return;const t=[];for(const e of this.selection){const i=this.get(e);if("group"===i?.kind){for(const e of i.children??[])t.push({op:"reparent",id:e.id,parent:null});t.push({op:"remove",id:e})}}this.apply(t,{origin:"user",label:"Ungroup"}),this.select([])}align(t){if(this.selection.some(t=>this.isLocked(t)))return;const e=this.topSelection().map(t=>this.get(t)).filter(t=>t&&!t.locked&&"connector"!==t.kind),i=t=>E(t,this.geometryLookup,this.outline),s=b(e,this.geometryLookup,this.outline),n=[...e].sort((e,s)=>"horizontal"===t?i(e).x-i(s).x:i(e).y-i(s).y);let o="horizontal"===t?s.x:s.y;const r=e.length>1?(("horizontal"===t?s.w:s.h)-e.reduce((e,s)=>e+("horizontal"===t?i(s).w:i(s).h),0))/(e.length-1):0,a=n.flatMap(e=>{const n=i(e);let a=0,h=0;return"left"===t&&(a=s.x-n.x),"center"===t&&(a=s.x+(s.w-n.w)/2-n.x),"right"===t&&(a=s.x+s.w-n.w-n.x),"top"===t&&(h=s.y-n.y),"middle"===t&&(h=s.y+(s.h-n.h)/2-n.y),"bottom"===t&&(h=s.y+s.h-n.h-n.y),"horizontal"===t&&(a=o-n.x,o+=n.w+r),"vertical"===t&&(h=o-n.y,o+=n.h+r),this.movable([e.id]).map(t=>({op:"set",id:t.id,patch:z(t,a,h)}))});this.apply(a,{origin:"user",label:"Align selection"})}async addImage(t,e){if(this.readonly)return;if(!/^image\/(png|jpeg|gif|webp|avif)$/.test(t.type))throw new Error("Choose a PNG, JPEG, GIF, WebP or AVIF image.");if(t.size>10485760)throw new Error("Images must be under 10 MB.");const i=await new Promise((e,i)=>{const s=new FileReader;s.onload=()=>e(s.result),s.onerror=i,s.readAsDataURL(t)}),s=new Image;s.src=i,await s.decode();const n=Math.min(1,480/s.width,360/s.height),o=s.width*n,r=s.height*n,a=e??this.view.center,h=l(),d=this.apply([{op:"media.set",id:h,media:{src:i,mime:t.type,w:s.width,h:s.height}},{op:"add",page:this.pageId,item:{kind:"image",x:a.x-o/2,y:a.y-r/2,w:o,h:r,media:h,name:t.name}}],{origin:"user",label:"Add image"});d.ok&&this.select(d.created)}setHref(t,e){return import("./urlPaste-BqcpeQ-c.js").then(({updateHref:i})=>i(this.pasteHost(),t,e))}pasteHost(){return{pageId:this.pageId,items:this.items,destroyed:this.destroyed,unfurl:this.unfurl,view:this.view,host:this.host,apply:(t,e)=>this.apply(t,e),select:t=>this.select(t),get:t=>this.get(t)}}editText(t){if(this.readonly||this.editor)return;this.render();const e=this.get(t);if(!e||this.isLocked(t))return;const i=this.stage.world.querySelector(`[data-ad-id="${CSS.escape(t)}"]`);if(!i)return;let s=i.querySelector(".ad-text");s||(s=document.createElement("div"),s.className="ad-text",i.append(s)),s.contentEditable="plaintext-only",s.setAttribute("role","textbox"),s.setAttribute("aria-label","Edit text"),s.style.pointerEvents="auto",s.style.display="flex",s.classList.add("ad-editing"),this.editor=s;const n=e.text?.value??"";s.textContent=n,s.focus();const o=document.createRange();o.selectNodeContents(s);const r=window.getSelection();r?.removeAllRanges(),r?.addRange(o);const a=(i=!0)=>{if(this.editor!==s)return;this.editor=void 0,this.finishEditor=void 0;const o=s.innerText;if(s.contentEditable="false",s.classList.remove("ad-editing"),s.removeAttribute("role"),s.removeAttribute("aria-label"),s.removeEventListener("blur",h),s.removeEventListener("keydown",d),i&&o!==n){const i={...this.get(t)?.text,value:o},s="text"===e.kind&&e.autoWidth?bt(this.host.ownerDocument,i):{};this.apply([{op:"set",id:t,patch:{...s,text:{value:o}}}],{origin:"user",label:"Edit text"})}const r=this.get(t);s.textContent=r?.text?.value??n,s.style.display=r?.text?"flex":"none",this.render(),this.focus()};this.finishEditor=a;const h=()=>a(),d=t=>{t.stopPropagation(),"Escape"===t.key&&(t.preventDefault(),a(!1)),"Enter"===t.key&&(t.metaKey||t.ctrlKey)&&(t.preventDefault(),a())};s.addEventListener("blur",h),s.addEventListener("keydown",d)}cancel(){this.clearInteractive(),clearTimeout(this.longPressTimer),this.lastTouchTap=void 0,this.finishEditor?.(!1),this.drag&&(this.drag=void 0,this.drafts.clear(),this.drawPreview=void 0,this.stage.setMarquee(void 0),this.render()),this.pointers.clear(),this.pinch=void 0,this.updateCursor()}schedule(){this.frame||this.destroyed||(this.frame=requestAnimationFrame(()=>{this.frame=0,this.render()}))}render(){if(this.destroyed)return;let t=this.document;this.drawPreview?(this.previewDocument&&this.previewBase===t||(this.previewBase=t,this.previewDocument={...t,pages:t.pages.map(t=>t.id===this.pageId?{...t,items:[...t.items,this.drawPreview]}:t)}),t=this.previewDocument,this.drafts.set(this.drawPreview.id,{...this.drawPreview})):(this.previewDocument=void 0,this.previewBase=void 0),this.stage.render(t,this.pageId,this.drafts),this.stage.setSelection(this.selection)}visible(t){if(this.hiddenGeometry.has(t.id))return!1;const e=this.stage.lens.viewport(),i=E(t,this.geometryLookup,this.outline);return i.x+i.w>=e.x&&i.y+i.h>=e.y&&i.x<=e.x+e.w&&i.y<=e.y+e.h}isUI(t){return t instanceof Element&&!!t.closest('.ad-ui, .ad-dialog, input, textarea, select, button, [contenteditable="plaintext-only"], [data-ad-interactive="true"], a')}point(t){return{x:t.clientX-this.rect.left,y:t.clientY-this.rect.top}}updateCursor(){this.stage.root.style.cursor=function(t,e={}){return e.panning?"grabbing":e.space||e.readonly||"hand"===t?"grab":"text"===t?"text":"select"===t?tt:it}(this.tool,{space:this.space,readonly:this.readonly,panning:"pan"===this.drag?.kind})}topSelection(){const t=new Set(this.selection),e=[],i=(s,n=!1)=>{for(const o of s){const s=t.has(o.id);s&&!n&&e.push(o.id),o.children&&i(o.children,n||s)}};return i(this.pageItems()),e}pageItems(){return this.document.pages.find(t=>t.id===this.pageId)?.items??[]}movable(t){if(t.some(t=>this.isLocked(t)))return[];const e=/* @__PURE__ */new Map;for(const i of t){const t=this.get(i);if(t&&!t.locked)for(const i of[t,...w(t.children??[])])e.set(i.id,i)}return[...e.values()]}outline=t=>this.stage.kinds.get(t.kind)?.outline?.(t);refreshGeometry(){const t=this.pageItems();this.geometryLookup=new Map(w(t).map(t=>[t.id,t])),this.lockedGeometry=K(this.document.pages.flatMap(t=>t.items)),this.hiddenGeometry.clear();const e=(t,i=!1)=>{for(const s of t){const t=i||!!s.hidden;t&&this.hiddenGeometry.add(s.id),s.children&&e(s.children,t)}};e(t),this.spatial.set(t,this.outline)}hit(t,e=!1){const i=this.spatial.pick(t,{includeLocked:!0,tolerance:6/this.view.zoom,enteredGroup:this.enteredGroup,outline:this.outline,ignore:t=>this.stage.isPending(t.id)});if(i&&i.id!==this.enteredGroup&&(e||!this.isLocked(i.id)))return i}zoomAt(t,e){t=Math.max(.05,Math.min(8,t));const i=this.stage.lens.toPage(e);this.stage.lens.set({zoom:t,x:e.x-i.x*t,y:e.y-i.y*t})}releasePointer=()=>{const t=this.getPointer();t&&this.observedPointer&&(this.observedPointer.page={x:t.x,y:t.y}),this.pointerInside=!1};observePointer=t=>{const e=this.stage.root.getBoundingClientRect();!this.isUI(t.target)&&e.width>0&&e.height>0&&t.clientX>=e.left&&t.clientX<e.right&&t.clientY>=e.top&&t.clientY<e.bottom?(this.pointerInside=!0,this.observedPointer={client:{x:t.clientX,y:t.clientY},page:this.stage.lens.toPage({x:t.clientX-e.left,y:t.clientY-e.top}),pageId:this.pageId,type:t.pointerType||"mouse",at:Date.now()}):this.releasePointer()};pointerDown=t=>{if(this.isUI(t.target)||t.button>1)return;this.clearInteractive(t.target),clearTimeout(this.longPressTimer),"touch"!==t.pointerType&&(this.lastTouchTap=void 0);const e=this.point(t);if(this.pointers.set(t.pointerId,e),2===this.pointers.size){this.lastTouchTap=void 0,this.drag=void 0,this.updateCursor(),this.drafts.clear(),this.drawPreview=void 0;const[t,e]=[...this.pointers.values()],i={x:(t.x+e.x)/2,y:(t.y+e.y)/2};return void(this.pinch={distance:Math.hypot(t.x-e.x,t.y-e.y),zoom:this.view.zoom,center:i,anchor:this.stage.lens.toPage(i)})}t.preventDefault();try{this.stage.root.setPointerCapture(t.pointerId)}catch{}this.focus();const i=this.stage.lens.toPage(e),s={...this.stage.lens.state},n=t.target.closest("[data-ad-handle]")?.dataset.adHandle;if(this.space||"hand"===this.tool||1===t.button||this.readonly)return this.drag={kind:"pan",pointer:t.pointerId,start:i,screen:e,last:e,original:[],ids:[],camera:s,moved:!1},void this.updateCursor();if(n&&this.selection.length){if(this.selection.some(t=>this.isLocked(t)))return;return void(this.drag={kind:"rotate"===n?"rotate":"resize",pointer:t.pointerId,start:i,screen:e,last:i,original:this.movable(this.topSelection()),ids:this.topSelection(),camera:s,handle:n,moved:!1})}if("select"===this.tool){const n=t.target.closest("[data-ad-id]")?.dataset.adId,o=n&&!this.stage.isPending(n)?this.get(n):void 0,r=this.hit(i,!0)??(o&&!this.outline(o)?o:void 0);if(r){t.shiftKey?this.select(this.selection.includes(r.id)?this.selection.filter(t=>t!==r.id):[...this.selection,r.id]):this.selection.includes(r.id)||this.select([r.id]);const n=this.topSelection();this.drag={kind:"move",pointer:t.pointerId,start:i,screen:e,last:i,original:this.movable(n),ids:n,camera:s,moved:!1,alt:t.altKey}}else t.shiftKey||this.select([]),this.drag={kind:"marquee",pointer:t.pointerId,start:i,screen:e,last:i,original:[],ids:this.selection,camera:s,moved:!1};if("touch"===t.pointerType){const i=this.drag;this.longPressTimer=setTimeout(()=>{if(this.drag!==i||i.moved||1!==this.pointers.size)return;this.cancel();const s=t.target.closest("[data-ad-id]")?.dataset.adId;this.openContext(e,s)},500)}return}if("eraser"===this.tool){const n=this.hit(i);return this.drag={kind:"erase",pointer:t.pointerId,start:i,screen:e,last:i,original:[],ids:n?[n.id]:[],camera:s,moved:!1},n&&this.drafts.set(n.id,{hidden:!0}),void this.schedule()}const o=this.tool,r=this.hit(i),a={id:c(),kind:o,x:i.x,y:i.y,w:0,h:0,style:h(this.defaultStyle),..."path"===o?{points:[[0,0,t.pressure||.5]]}:{},..."connector"===o?{from:r?{item:r.id,side:"auto"}:i,to:i,route:"elbow",heads:{end:"arrow"}}:{},..."note"===o?{style:{...this.defaultStyle,fill:"moss",stroke:"none",corner:12},text:{value:"",size:"l"}}:{},..."text"===o?{autoWidth:!0,text:{value:"",size:"l"}}:{}};this.drag={kind:"draw",pointer:t.pointerId,start:i,screen:e,last:i,original:[],ids:[],camera:s,item:a,points:"path"===o?[[0,0,t.pressure||.5]]:void 0,moved:!1},this.drawPreview=a,this.select([]),this.schedule()};pointerMove=t=>{const e=this.point(t);if(this.pointers.has(t.pointerId)&&this.pointers.set(t.pointerId,e),this.pinch&&this.pointers.size>=2){t.preventDefault();const[e,i]=[...this.pointers.values()],s={x:(e.x+i.x)/2,y:(e.y+i.y)/2},n=Math.max(.05,Math.min(8,this.pinch.zoom*Math.hypot(e.x-i.x,e.y-i.y)/Math.max(1,this.pinch.distance)));return void this.stage.lens.set({zoom:n,x:s.x-this.pinch.anchor.x*n,y:s.y-this.pinch.anchor.y*n})}const i=this.drag;if(!i||i.pointer!==t.pointerId)return;const s=this.stage.lens.toPage(e),n=Math.hypot(e.x-i.screen.x,e.y-i.screen.y);if(i.moved||!(n<("touch"===t.pointerType?8:4)))if(clearTimeout(this.longPressTimer),this.lastTouchTap=void 0,i.moved=!0,i.last=s,"pan"!==i.kind){if("move"===i.kind){let e=s.x-i.start.x,n=s.y-i.start.y;t.shiftKey&&(Math.abs(e)>Math.abs(n)?n=0:e=0);for(const t of i.original)this.drafts.set(t.id,z(t,e,n));return void this.schedule()}if("resize"===i.kind){if(i.handle?.startsWith("custom:")){const e=1===i.ids.length?i.original.find(t=>t.id===i.ids[0]):void 0,n=e?this.stage.kinds.get(e.kind)?.dragHandle:void 0;if(e&&n){const r=v(s,{x:e.x+e.w/2,y:e.y+e.h/2},-(e.rotation??0));try{this.drafts.set(e.id,n(h(e),i.handle.slice(7),{x:r.x-e.x,y:r.y-e.y},{shift:t.shiftKey,alt:t.altKey})),this.schedule()}catch(o){this.cancel(),this.host.dispatchEvent(new CustomEvent("ad-error",{detail:o instanceof Error?o.message:String(o)}))}}return}const e=i.original.filter(t=>i.ids.includes(t.id)),n=1===e.length&&!["connector","line","path","group"].includes(e[0].kind),r=n?e[0]:b(e,this.geometryLookup,this.outline),a=i.handle??"se",d=n?e[0].rotation??0:0,l={x:r.x+r.w/2,y:r.y+r.h/2},c=v(i.start,l,-d),p=v(s,l,-d),u=p.x-c.x,m=p.y-c.y,g=a.includes("e")?1:a.includes("w")?-1:0,f=a.includes("s")?1:a.includes("n")?-1:0;let y=r.w+g*u*(t.altKey?2:1),x=r.h+f*m*(t.altKey?2:1);if(t.shiftKey){const t=y/Math.max(1,r.w),e=x/Math.max(1,r.h),i=Math.max(12/Math.max(1,r.w),12/Math.max(1,r.h),g?f?Math.abs(t-1)>=Math.abs(e-1)?t:e:t:e);y=r.w*i,x=r.h*i}else y=Math.max(12,y),x=Math.max(12,x);const w={x:l.x+(t.altKey?0:g*(y-r.w)/2),y:l.y+(t.altKey?0:f*(x-r.h)/2)},k=w.x-y/2,$=w.y-x/2,M=y/Math.max(1,r.w),S=x/Math.max(1,r.h),I=t=>{const e=v(t,l,-d);return v({x:k+(e.x-r.x)*M,y:$+(e.y-r.y)*S},l,d)};for(const t of i.original){const e=I({x:t.x+t.w/2,y:t.y+t.h/2}),i=Math.max(1,t.w*M),s=Math.max(1,t.h*S),n={x:e.x-i/2,y:e.y-s/2,w:i,h:s};if(t.points&&(n.points=t.points.map(t=>t.length>2?[t[0]*M,t[1]*S,t[2]]:[t[0]*M,t[1]*S])),"connector"===t.kind){for(const e of["from","to"]){const i=t[e];i&&!("item"in i)&&(n[e]=I(i))}t.waypoints&&(n.waypoints=t.waypoints.map(([t,e])=>{const i=I({x:t,y:e});return[i.x,i.y]}))}this.drafts.set(t.id,n)}return void this.schedule()}if("rotate"===i.kind){const t=i.original.filter(t=>i.ids.includes(t.id)),e=b(t,this.geometryLookup,this.outline),n={x:e.x+e.w/2,y:e.y+e.h/2},o=180*(Math.atan2(s.y-n.y,s.x-n.x)-Math.atan2(i.start.y-n.y,i.start.x-n.x))/Math.PI;for(const s of i.original){const t=v({x:s.x+s.w/2,y:s.y+s.h/2},n,o),e={x:t.x-s.w/2,y:t.y-s.h/2,rotation:(s.rotation??0)+o};if("connector"===s.kind){e.rotation=0;for(const t of["from","to"]){const i=s[t];i&&!("item"in i)&&(e[t]=v(i,n,o))}s.waypoints&&(e.waypoints=s.waypoints.map(([t,e])=>{const i=v({x:t,y:e},n,o);return[i.x,i.y]}))}this.drafts.set(s.id,e)}return void this.schedule()}if("marquee"!==i.kind){if("erase"===i.kind){const t=this.hit(s);return void(t&&!i.ids.includes(t.id)&&(i.ids.push(t.id),this.drafts.set(t.id,{hidden:!0}),this.schedule()))}if(i.item){const e=i.item;if("path"===e.kind){const s=t.getCoalescedEvents?.(),n=s?.length?s:[t];for(const t of n){const e=this.stage.lens.toPage(this.point(t));i.points.push([e.x-i.start.x,e.y-i.start.y,t.pressure||.5])}e.points=i.points,e.w=Math.max(1,...i.points.map(t=>t[0])),e.h=Math.max(1,...i.points.map(t=>t[1]))}else if("connector"===e.kind){const t=this.hit(s);e.to=t?{item:t.id,side:"auto"}:s}else{let n=Math.abs(s.x-i.start.x),o=Math.abs(s.y-i.start.y);t.shiftKey&&(n=o=Math.max(n,o)),e.x=s.x<i.start.x?i.start.x-n:i.start.x,e.y=s.y<i.start.y?i.start.y-o:i.start.y,e.w=n,e.h=o,"line"===e.kind&&(e.points=[[i.start.x-e.x,i.start.y-e.y],[s.x-e.x,s.y-e.y]])}this.drawPreview=e,this.schedule()}}else this.stage.setMarquee({x:Math.min(s.x,i.start.x),y:Math.min(s.y,i.start.y),w:Math.abs(s.x-i.start.x),h:Math.abs(s.y-i.start.y)})}else this.stage.lens.set({x:i.camera.x+e.x-i.screen.x,y:i.camera.y+e.y-i.screen.y})};pointerUp=t=>{if(clearTimeout(this.longPressTimer),this.pointers.delete(t.pointerId),this.pinch)return void(this.pointers.size<2&&(this.pinch=void 0));const e=this.drag;if(!e||e.pointer!==t.pointerId)return;this.drag=void 0,this.updateCursor();const i="touch"===t.pointerType&&!e.moved&&["move","marquee"].includes(e.kind),s=[];if(("move"===e.kind||"resize"===e.kind||"rotate"===e.kind)&&e.moved&&e.original.length)if("move"===e.kind&&e.alt){const t=e.ids.map(t=>e.original.find(e=>e.id===t)).filter(Boolean).map(t=>this.withDrafts(t)),i=S(t,0);s.push(...i.map(t=>({op:"add",item:t,page:this.pageId}))),this.selectionSignal.value=i.map(t=>t.id)}else for(const[n,o]of this.drafts)s.push({op:"set",id:n,patch:o});if("marquee"===e.kind&&e.moved){const t=e.last,i={x:Math.min(t.x,e.start.x),y:Math.min(t.y,e.start.y),w:Math.abs(t.x-e.start.x),h:Math.abs(t.y-e.start.y)};this.select([...e.ids,...this.spatial.enclosed(i,{enteredGroup:this.enteredGroup,ignore:t=>this.stage.isPending(t.id)}).map(t=>t.id)])}if("erase"===e.kind&&s.push(...e.ids.map(t=>({op:"remove",id:t}))),"draw"===e.kind&&e.item){const t=e.item;if(!e.moved){const[e,i]=u(t.kind);t.w="path"===t.kind?1:e,t.h="path"===t.kind?1:i,"connector"===t.kind&&(t.to={x:t.x+160,y:t.y}),"line"===t.kind&&(t.points=[[0,0],[e,0]]),"path"===t.kind&&(t.points=[[0,0,.5],[.1,.1,.5]])}if("path"===t.kind&&t.points?.length){const e=Math.min(...t.points.map(t=>t[0])),i=Math.min(...t.points.map(t=>t[1])),s=Math.max(...t.points.map(t=>t[0])),n=Math.max(...t.points.map(t=>t[1]));t.x+=e,t.y+=i,t.w=Math.max(1,s-e),t.h=Math.max(1,n-i),t.points=y(t.points.map(t=>[t[0]-e,t[1]-i,t[2]]),.5/this.view.zoom)}"note"!==t.kind||t.text?.value||(t.text={value:"A little idea",size:"l"}),"text"!==t.kind||t.text?.value||(t.text={value:"Type something…",size:"l"}),s.push({op:"add",item:t,page:this.pageId})}if(this.drafts.clear(),this.drawPreview=void 0,this.stage.setMarquee(void 0),s.length){const t=this.apply(s,{origin:"user",label:"draw"===e.kind?`Draw ${e.item.kind}`:"move"===e.kind?"Move":"resize"===e.kind?"Resize":"rotate"===e.kind?"Rotate":"Erase"});t.ok&&t.created.length&&this.select(e.alt?t.created.filter(t=>!this.items.some(e=>w(e.children??[]).some(e=>e.id===t))):[t.created[0]]),t.ok||this.host.dispatchEvent(new CustomEvent("ad-error",{detail:t.errors[0]?.message}))}if(this.render(),"draw"===e.kind&&e.item){const t=e.item.kind;"path"!==t&&this.setTool("select"),"text"!==t&&"note"!==t||this.editText(e.item.id)}if(this.emit("select",this.selection),i){const e=this.point(t),i=Date.now(),s=this.lastTouchTap;this.lastTouchTap={at:i,screen:e},s&&i-s.at<350&&Math.hypot(e.x-s.screen.x,e.y-s.screen.y)<24&&(this.lastTouchTap=void 0,this.touchDoubleAt=i,this.activateAt(e))}};pointerCancel=()=>this.cancel();wheel=t=>{this.isUI(t.target)||(t.preventDefault(),t.ctrlKey||t.metaKey?this.zoomAt(this.view.zoom*Math.exp(.008*-t.deltaY),this.point(t)):this.stage.lens.set({x:this.stage.lens.state.x-t.deltaX,y:this.stage.lens.state.y-t.deltaY}))};doubleClick=t=>{if(this.isUI(t.target)||Date.now()-this.touchDoubleAt<500)return;const e=(t.target instanceof Element?t.target:void 0)?.closest("[data-ad-id]")?.dataset.adId;this.activateAt(this.point(t),e)};openContext(t,e){const i=this.spatial.pick(this.stage.lens.toPage(t),{tolerance:6/this.view.zoom,includeLocked:!0,enteredGroup:this.enteredGroup,outline:this.outline,ignore:t=>this.stage.isPending(t.id)})??(e&&!this.stage.isPending(e)?this.get(e):void 0);i&&(this.setTool("select"),this.select([i.id])),this.host.dispatchEvent(new CustomEvent("ad-context",{detail:{...t,id:i?.id}}))}activateAt(t,e){const i=e?this.get(e):void 0,s=(!i||"html"!==i.kind&&"video"!==i.kind?void 0:i)??this.hit(this.stage.lens.toPage(t),!0)??i;if(!s||!this.isLocked(s.id))return"group"===s?.kind?(this.enteredGroup=s.id,void this.select([])):void("html"!==s?.kind&&"video"!==s?.kind?s&&!["image","path","line","link"].includes(s.kind)?this.editText(s.id):s||this.readonly||this.add("text",this.stage.lens.toPage(t)):this.activateEmbedded(s));this.select([s.id])}activateEmbedded(t){const e=this.stage.world.querySelector(`[data-ad-id="${CSS.escape(t.id)}"]`);if(!e)return;if(this.clearInteractive(),e.dataset.adInteractive="true","html"!==t.kind)return;const i=e.querySelector(".ad-html-content");if(!i)return;i.tabIndex=0,i.focus();const s=t=>{t.relatedTarget instanceof Node&&i.contains(t.relatedTarget)||(delete e.dataset.adInteractive,i.tabIndex=-1,i.removeEventListener("focusout",s))};i.addEventListener("focusout",s)}clearInteractive(t){for(const e of this.stage.world.querySelectorAll("[data-ad-interactive]"))t instanceof Node&&e.contains(t)||delete e.dataset.adInteractive}keyDown=t=>{if(this.isUI(t.target))return;const e=t.metaKey||t.ctrlKey,i=t.key.toLowerCase();if("contextmenu"===i||"f10"===i&&t.shiftKey){t.preventDefault();const e=1===this.selection.length?this.get(this.selection[0]):void 0;if(e){const t=E(e,this.geometryLookup,this.outline),i=this.stage.lens.toScreen({x:t.x+t.w/2,y:t.y+t.h/2});this.host.dispatchEvent(new CustomEvent("ad-context",{detail:{...i,id:e.id}}))}return}if("Space"===t.code)return t.preventDefault(),this.space=!0,void this.updateCursor();if("escape"===i)return this.cancel(),this.enteredGroup=void 0,this.select([]),void this.setTool("select");if(e&&"a"===i)return t.preventDefault(),void this.select(this.items.filter(t=>!t.hidden&&!t.locked&&!this.stage.isPending(t.id)).map(t=>t.id));if("1"!==i||e)if("2"!==i||e)if("+"!==i&&"="!==i)if("-"!==i){if(!this.readonly){if(e&&"z"===i)return t.preventDefault(),void(t.shiftKey?this.redo():this.undo());if(e&&"y"===i)return t.preventDefault(),void this.redo();if(e&&"d"===i)return t.preventDefault(),void this.duplicate();if(e&&"g"===i)return t.preventDefault(),void(t.shiftKey?this.ungroup():this.group());if("delete"===i||"backspace"===i)return t.preventDefault(),void this.deleteSelection();if("enter"===i&&1===this.selection.length){t.preventDefault();const e=this.get(this.selection[0]);return void("html"===e?.kind||"video"===e?.kind?this.activateEmbedded(e):e&&!["image","path","line","link"].includes(e.kind)&&this.editText(e.id))}if("["===i||"]"===i)return t.preventDefault(),void this.apply(this.selection.map(e=>({op:"order",id:e,to:"]"===i?t.shiftKey?"front":"forward":t.shiftKey?"back":"backward"})),{origin:"user",label:"Reorder"});if(i.startsWith("arrow")){t.preventDefault();const e=t.shiftKey?10:1,s="arrowleft"===i?-e:"arrowright"===i?e:0,n="arrowup"===i?-e:"arrowdown"===i?e:0;return void this.apply(this.movable(this.topSelection()).map(t=>({op:"set",id:t.id,patch:z(t,s,n)})),{origin:"user",label:"Nudge"})}!e&&$t[i]&&(t.preventDefault(),this.setTool($t[i]))}}else this.view.zoom/=1.2;else this.view.zoom*=1.2;else this.view.fit();else this.view.zoom=1};withDrafts(t){const e=k(t,this.drafts.get(t.id));return e.children?{...e,children:e.children.map(t=>this.withDrafts(t))}:e}copyEvent=t=>{if(this.isUI(t.target)||!this.selection.length)return;t.preventDefault(),this.clipboard=this.topSelection().map(t=>this.get(t)).filter(Boolean);const e={};for(const s of w(this.clipboard))s.media&&this.document.media[s.media]&&(e[s.media]=h(this.document.media[s.media]));I(this.clipboard,this.geometryLookup,this.outline);const i=JSON.stringify({format:"anniedrawing-clipboard",items:this.clipboard,media:e});t.clipboardData?.setData(U,i),t.clipboardData?.setData("text/plain",i)};cutEvent=t=>{this.readonly||this.isUI(t.target)||(this.copyEvent(t),this.deleteSelection())};pasteEvent=t=>{if(this.readonly||this.isUI(t.target))return;const e=[...t.clipboardData?.files??[]];if(e.length)return t.preventDefault(),void e.forEach(t=>{this.addImage(t).catch(t=>this.host.dispatchEvent(new CustomEvent("ad-error",{detail:String(t)})))});t.clipboardData&&(t.preventDefault(),this.pasteFrom(t.clipboardData))};pasteFrom(t,e){const i=t?.getData("application/vnd.anniedrawing+json")||s(t)||t?.getData("text/html")||"";if(i)try{const t=JSON.parse(i);if(!t||"object"!=typeof t||!Array.isArray(t.items))throw new Error("not clipboard json");const e=S(t.items,24),s=new Map(Object.keys(t.media??{}).map(t=>[t,l()])),n=Object.entries(t.media??{}).map(([t,e])=>({op:"media.set",id:s.get(t),media:e}));for(const i of w(e))i.media&&s.has(i.media)&&(i.media=s.get(i.media));n.push(...e.map(t=>({op:"add",item:t,page:this.pageId})));const o=this.apply(n,{origin:"user",label:"Paste"});o.ok?this.select(e.map(t=>t.id)):this.host.dispatchEvent(new CustomEvent("ad-error",{detail:o.errors[0]?.message}))}catch{import("./urlPaste-BqcpeQ-c.js").then(({pastePlain:t})=>t(this.pasteHost(),i,e))}}drop=t=>{if(this.readonly)return;t.preventDefault();const e=this.stage.lens.toPage(this.point(t)),i=[...t.dataTransfer?.files??[]];if(i.length)for(const s of i)(async()=>{try{s.name.endsWith(".annie")||"application/json"===s.type?this.load(JSON.parse(await s.text())):await this.addImage(s,e)}catch(t){this.host.dispatchEvent(new CustomEvent("ad-error",{detail:String(t)}))}})();else t.dataTransfer&&this.pasteFrom(t.dataTransfer,e)}};function St(t,e){return new Mt(t,e)}export{J as i,St as n,W as r,Mt as t};
|
|
2
|
+
//# sourceMappingURL=board-OPwsZ2_V.js.map
|