anniedrawing 0.3.1 → 0.3.3
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 +15 -1
- package/README.md +20 -14
- package/dist/agent/index.js +1 -1
- package/dist/agent/index.js.map +1 -1
- package/dist/agent/toolDefs.d.ts +1 -0
- package/dist/board.d.ts +7 -1
- package/dist/core/index.js +1 -1
- package/dist/core/types.d.ts +12 -0
- package/dist/docs/agents-repository.md +1 -1
- package/dist/docs/agents.md +4 -0
- package/dist/docs/api.md +4 -0
- package/dist/docs/board-js.md +4 -0
- package/dist/docs/decisions.md +8 -2
- package/dist/docs/index.html +2 -1
- package/dist/docs/llms-full.txt +4 -0
- package/dist/docs/llms.txt +4 -0
- package/dist/docs/mcp.md +1 -1
- package/dist/docs/releasing.md +21 -1
- package/dist/docs/security.md +1 -1
- package/dist/fellow.d.ts +2 -2
- package/dist/fellow.js +1 -1
- package/dist/fellow.js.map +1 -1
- package/dist/index.js +1 -1
- package/dist/shared/board-p60lv7As.js +2 -0
- package/dist/shared/board-p60lv7As.js.map +1 -0
- package/dist/shared/{cards-DWgSVE54.js → cards-DF0uI4-I.js} +2 -2
- package/dist/shared/{cards-DWgSVE54.js.map → cards-DF0uI4-I.js.map} +1 -1
- package/dist/shared/{paste-C22i8o-g.js → paste-B8nZA2Gh.js} +2 -2
- package/dist/shared/{paste-C22i8o-g.js.map → paste-B8nZA2Gh.js.map} +1 -1
- package/dist/shared/{picker-Dv_i4iNP.js → picker-DZpEpkED.js} +2 -2
- package/dist/shared/picker-DZpEpkED.js.map +1 -0
- package/dist/shared/{ui-Cay6AVqT.js → ui-DWQtW0zJ.js} +2 -2
- package/dist/shared/ui-DWQtW0zJ.js.map +1 -0
- package/dist/shared/{urlPaste-DN4JtgeB.js → urlPaste-Oc4kZ0P7.js} +2 -2
- package/dist/shared/{urlPaste-DN4JtgeB.js.map → urlPaste-Oc4kZ0P7.js.map} +1 -1
- package/dist/ui/index.js +1 -1
- package/dist/ui/version.d.ts +3 -2
- package/llms-full.txt +4 -0
- package/llms.txt +4 -0
- package/package.json +4 -4
- package/dist/shared/board-Bya0O1I7.js +0 -2
- package/dist/shared/board-Bya0O1I7.js.map +0 -1
- package/dist/shared/picker-Dv_i4iNP.js.map +0 -1
- package/dist/shared/ui-Cay6AVqT.js.map +0 -1
package/dist/docs/board-js.md
CHANGED
|
@@ -68,6 +68,8 @@ board.toJSON(); // portable document
|
|
|
68
68
|
|
|
69
69
|
DOM nodes may show `[data-ad-id]` and `[data-ad-kind]`. Do not treat DOM edits as a write API.
|
|
70
70
|
|
|
71
|
+
`board.getPointer()` returns a copy of the last human pointer: `{ x, y, pageId, inside, pointerType, ageMs, itemId }`, or `null` before a pointer is observed, after a page switch, or after destruction. Coordinates are page-space. While `inside` is true they follow pan and zoom; `itemId` is the topmost hittable item or `null`. Editor controls are excluded. Leaving, blur, hidden tabs, cancel, or touch release sets `inside: false` and preserves the last point. `ageMs` measures time since the last pointer event, not camera changes. Treat an outside point as historical; ask the user to point again when ambiguous. Pointer state is never serialized.
|
|
72
|
+
|
|
71
73
|
## Write
|
|
72
74
|
|
|
73
75
|
```js
|
|
@@ -81,6 +83,8 @@ const result = board.apply(ops, {
|
|
|
81
83
|
// { ok, created, errors, warnings, skipped? }
|
|
82
84
|
```
|
|
83
85
|
|
|
86
|
+
Pass `expectedRevision` from the read that informed an edit to `apply` or `board_apply`. A mismatch returns `STALE_REVISION` without applying any operation, including in lenient or dry-run mode. Read again before retrying. This guards one session only: `load()` and `clear()` reset revisions.
|
|
87
|
+
|
|
84
88
|
A failed batch changes nothing. `dryRun: true` validates and does not write. It does not reserve IDs. Do not call `load()` to patch a few items. Do not set `merge: true` unless you intend to fold this commit into the previous history entry with the same origin and label. `lenient: true` is available on `apply` only.
|
|
85
89
|
|
|
86
90
|
Use stable IDs when later operations in the same batch need to reference new items. Generated prefixes are `i_`, `p_`, and `m_`.
|
package/dist/docs/decisions.md
CHANGED
|
@@ -14,7 +14,7 @@ An `agent:` `apply` that creates an item id already in the document, or repeated
|
|
|
14
14
|
|
|
15
15
|
## 2026-09-20: Public contacts and safer host defaults
|
|
16
16
|
|
|
17
|
-
Security and community reports go to pau@frontierz.com. `package.json` records the GitHub repository, issues URL, and that mailbox. `createBoard` does not register `window.__anniedrawing` unless `exposeGlobal` is true; the local demo opts in. `sanitizeHTML` is probed at create time so identity functions fail closed. npm
|
|
17
|
+
Security and community reports go to pau@frontierz.com. `package.json` records the GitHub repository, issues URL, and that mailbox. `createBoard` does not register `window.__anniedrawing` unless `exposeGlobal` is true; the local demo opts in. `sanitizeHTML` is probed at create time so identity functions fail closed. Further npm releases remain a maintainer action.
|
|
18
18
|
|
|
19
19
|
## 2026-09-20: Session revision, not catalog version
|
|
20
20
|
|
|
@@ -54,7 +54,7 @@ Use the Frontierz palette so the demo matches the rest of the family. Use Nunito
|
|
|
54
54
|
|
|
55
55
|
## 2026-09-19: Demo without a backend
|
|
56
56
|
|
|
57
|
-
The demo works without a backend or account. The development server uses Vite's default port 5173. Portable JSON files are the durable exchange format. Browser autosave does not synchronize users or devices.
|
|
57
|
+
The demo works without a backend or account. The development server uses Vite's default port 5173. The same static build is published at https://anniedrawing.com from Laravel Forge. Portable JSON files are the durable exchange format. Browser autosave does not synchronize users or devices.
|
|
58
58
|
|
|
59
59
|
## 2026-09-19: Live agent integration is explicit
|
|
60
60
|
|
|
@@ -105,3 +105,9 @@ Portable SVG and PNG cannot keep a live player or a working Open control. Export
|
|
|
105
105
|
## 2026-09-19: Publish-facing library surface
|
|
106
106
|
|
|
107
107
|
Package entry points export the documented API, not every helper in a folder. Host page chrome (`html`, `body`, `#app`) belongs in the demo stylesheet; `anniedrawing/style.css` styles the editor host only. Draft merges, copies, translation, and connector detach share one implementation. Comments mark non-obvious contracts. Tests cover invariants, not restated implementation.
|
|
108
|
+
|
|
109
|
+
## 2026-09-20: Human pointing and revision-checked edits
|
|
110
|
+
|
|
111
|
+
Expose pointing through the browser board as transient page-space state, separate from the animated agent cursor and document JSON. Report inside/outside and age instead of guessing that a previous pointer is still current. Hosts decide whether a historical point answers “here.”
|
|
112
|
+
|
|
113
|
+
Put optional optimistic concurrency in the shared `apply` boundary, not in each host adapter. `expectedRevision` is checked before any operation, including lenient batches and previews. This is a session guard, not a persistent document version; document replacement resets it.
|
package/dist/docs/index.html
CHANGED
|
@@ -603,7 +603,8 @@
|
|
|
603
603
|
</p>
|
|
604
604
|
<p>
|
|
605
605
|
Detailed references are linked from each chapter. Install the library with
|
|
606
|
-
<code>npm install anniedrawing</code>.
|
|
606
|
+
<code>npm install anniedrawing</code>. The live demo is
|
|
607
|
+
<a href="https://anniedrawing.com">anniedrawing.com</a>.
|
|
607
608
|
</p>
|
|
608
609
|
<section class="chapter" id="install">
|
|
609
610
|
<span class="number">1</span>
|
package/dist/docs/llms-full.txt
CHANGED
|
@@ -68,6 +68,8 @@ board.toJSON(); // portable document
|
|
|
68
68
|
|
|
69
69
|
DOM nodes may show `[data-ad-id]` and `[data-ad-kind]`. Do not treat DOM edits as a write API.
|
|
70
70
|
|
|
71
|
+
`board.getPointer()` returns a copy of the last human pointer: `{ x, y, pageId, inside, pointerType, ageMs, itemId }`, or `null` before a pointer is observed, after a page switch, or after destruction. Coordinates are page-space. While `inside` is true they follow pan and zoom; `itemId` is the topmost hittable item or `null`. Editor controls are excluded. Leaving, blur, hidden tabs, cancel, or touch release sets `inside: false` and preserves the last point. `ageMs` measures time since the last pointer event, not camera changes. Treat an outside point as historical; ask the user to point again when ambiguous. Pointer state is never serialized.
|
|
72
|
+
|
|
71
73
|
## Write
|
|
72
74
|
|
|
73
75
|
```js
|
|
@@ -81,6 +83,8 @@ const result = board.apply(ops, {
|
|
|
81
83
|
// { ok, created, errors, warnings, skipped? }
|
|
82
84
|
```
|
|
83
85
|
|
|
86
|
+
Pass `expectedRevision` from the read that informed an edit to `apply` or `board_apply`. A mismatch returns `STALE_REVISION` without applying any operation, including in lenient or dry-run mode. Read again before retrying. This guards one session only: `load()` and `clear()` reset revisions.
|
|
87
|
+
|
|
84
88
|
A failed batch changes nothing. `dryRun: true` validates and does not write. It does not reserve IDs. Do not call `load()` to patch a few items. Do not set `merge: true` unless you intend to fold this commit into the previous history entry with the same origin and label. `lenient: true` is available on `apply` only.
|
|
85
89
|
|
|
86
90
|
Use stable IDs when later operations in the same batch need to reference new items. Generated prefixes are `i_`, `p_`, and `m_`.
|
package/dist/docs/llms.txt
CHANGED
|
@@ -20,12 +20,16 @@ board.query({ kind: 'arrow' }); // matches stored connector created as arrow
|
|
|
20
20
|
|
|
21
21
|
Reads return copies. Mutating them does not edit the board.
|
|
22
22
|
|
|
23
|
+
`board.getPointer()` returns a copy of the last human pointer: `{ x, y, pageId, inside, pointerType, ageMs, itemId }`, or `null` before a pointer is observed, after a page switch, or after destruction. Coordinates are page-space. While `inside` is true they follow pan and zoom; `itemId` is the topmost hittable item or `null`. Editor controls are excluded. Leaving, blur, hidden tabs, cancel, or touch release sets `inside: false` and preserves the last point. `ageMs` measures time since the last pointer event, not camera changes. Treat an outside point as historical; ask the user to point again when ambiguous. Pointer state is never serialized.
|
|
24
|
+
|
|
23
25
|
## Write
|
|
24
26
|
|
|
25
27
|
```
|
|
26
28
|
board.apply(ops, { origin: 'agent:name', label: 'What changed', dryRun?: false, agentName?: 'Name', reveal?: 'fit' })
|
|
27
29
|
```
|
|
28
30
|
|
|
31
|
+
Pass `expectedRevision` from the read that informed an edit to `apply` or `board_apply`. A mismatch returns `STALE_REVISION` without applying any operation, including in lenient or dry-run mode. Read again before retrying. This guards one session only: `load()` and `clear()` reset revisions.
|
|
32
|
+
|
|
29
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.
|
|
30
34
|
|
|
31
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.
|
package/dist/docs/mcp.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# AnnieDrawing MCP example
|
|
2
2
|
|
|
3
|
-
This separate local package exposes AnnieDrawing's six agent tools over the MCP stdio transport. It can edit a headless document or a live browser board. It is included in this repository as `anniedrawing-mcp` 0.1.0 (`private: true`). It does not assume a second repository
|
|
3
|
+
This separate local package exposes AnnieDrawing's six agent tools over the MCP stdio transport. It can edit a headless document or a live browser board. It is included in this repository as `anniedrawing-mcp` 0.1.0 (`private: true`). It does not assume a second repository exists.
|
|
4
4
|
|
|
5
5
|
## Install and run headless
|
|
6
6
|
|
package/dist/docs/releasing.md
CHANGED
|
@@ -33,6 +33,26 @@ Review `npm audit` and changes to locked dependencies. CI license approval does
|
|
|
33
33
|
|
|
34
34
|
## Publish only with authorization
|
|
35
35
|
|
|
36
|
-
After the owner authorizes the destination and version, create a signed-off release commit and tag, publish the reviewed tarball
|
|
36
|
+
After the owner authorizes the destination and version, create a signed-off release commit and tag, and publish the reviewed tarball. Do not put registry tokens in repository files. Verify the installed package and the hosted demo after release.
|
|
37
|
+
|
|
38
|
+
The public site is the Vite demo (`npm run build:demo`). It is static files in `site/`. It does not run Node in production. Host it as its own Laravel Forge site next to the others on the Frontierz server (`docs.frontierz.com`, `rebost.ai`, `ssot.frontierz.com`). Do not attach a Forge daemon or PM2 process. Do not change the server-wide Node binary; `scripts/forge-deploy.sh` installs Node 24 under `~/.local` for this site only.
|
|
39
|
+
|
|
40
|
+
In Forge, create a new site `anniedrawing.com`:
|
|
41
|
+
|
|
42
|
+
1. Web directory: `/site` (not `/public`).
|
|
43
|
+
2. PHP version can stay the default; PHP is unused.
|
|
44
|
+
3. No queue worker, scheduler, or daemon.
|
|
45
|
+
4. Deploy script:
|
|
46
|
+
|
|
47
|
+
```sh
|
|
48
|
+
cd /home/forge/anniedrawing.com
|
|
49
|
+
git pull origin $FORGE_SITE_BRANCH
|
|
50
|
+
bash scripts/forge-deploy.sh
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
5. Nginx `location /` should be `try_files $uri $uri/ /index.html;` like the rebost.ai static site, not a PHP front controller.
|
|
54
|
+
6. Point DNS at this Forge server (currently `ssot.frontierz.com` / `165.22.207.153`), then issue the Let's Encrypt certificate in Forge.
|
|
55
|
+
|
|
56
|
+
`docs.frontierz.com` already runs `server.js` under PM2 (`site-3359372`). A separate nginx `server_name` for `anniedrawing.com` does not reload or replace that process.
|
|
37
57
|
|
|
38
58
|
The MCP example is a private package inside this repository. Publishing it separately requires replacing its relative `../../dist` imports with a compatible `anniedrawing` dependency and reviewing its release contents on their own.
|
package/dist/docs/security.md
CHANGED
|
@@ -4,7 +4,7 @@ AnnieDrawing is a local browser library. The embedding application controls who
|
|
|
4
4
|
|
|
5
5
|
## Reporting
|
|
6
6
|
|
|
7
|
-
Email **pau@frontierz.com**.
|
|
7
|
+
Email **pau@frontierz.com**. You can also use [GitHub private vulnerability reporting](https://github.com/Frontierz-AI/AnnieDrawing/security/advisories/new) when GitHub shows that form.
|
|
8
8
|
|
|
9
9
|
Do not file a public GitHub issue for a vulnerability. Do not include real private drawings.
|
|
10
10
|
|
package/dist/fellow.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { type BoardOptions } from './board.js';
|
|
2
|
-
import type { AgentPresenceOptions, ApplyOptions, ApplyResult, ChangeLog } from './core/types.js';
|
|
3
|
-
export type { AgentPresenceOptions, ApplyOptions, ApplyResult, BoardOptions, ChangeLog };
|
|
2
|
+
import type { AgentPresenceOptions, ApplyOptions, ApplyResult, BoardPointer, ChangeLog } from './core/types.js';
|
|
3
|
+
export type { AgentPresenceOptions, ApplyOptions, ApplyResult, BoardOptions, BoardPointer, ChangeLog, };
|
|
4
4
|
export interface FellowBoardOptions extends BoardOptions {
|
|
5
5
|
fellowName?: string;
|
|
6
6
|
}
|
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-p60lv7As.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/fellow.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fellow.js","names":[],"sources":["../src/fellow.ts"],"sourcesContent":["import { createBoard, type BoardOptions } from './board';\nimport type {
|
|
1
|
+
{"version":3,"file":"fellow.js","names":[],"sources":["../src/fellow.ts"],"sourcesContent":["import { createBoard, type BoardOptions } from './board';\nimport type {\n AgentPresenceOptions,\n ApplyOptions,\n ApplyResult,\n BoardPointer,\n ChangeLog,\n} from './core/types';\n\nexport type {\n AgentPresenceOptions,\n ApplyOptions,\n ApplyResult,\n BoardOptions,\n BoardPointer,\n ChangeLog,\n};\n\nexport interface FellowBoardOptions extends BoardOptions {\n fellowName?: string;\n}\n\nexport function createFellowBoard(host: HTMLElement, options: FellowBoardOptions = {}) {\n const { fellowName, ...rest } = options;\n return createBoard(host, {\n agentHistory: 'hidden',\n agentReveal: 'fit',\n agentPlaceGap: 120,\n agentPresence: { maxStops: 3, durationScale: 0.55 },\n exposeGlobal: false,\n unfurl: false,\n ui: { menu: false, export: false, pages: false },\n ...rest,\n agentName: rest.agentName ?? fellowName,\n });\n}\n"],"mappings":"+CAsBA,SAAgB,EAAkB,EAAmB,EAA8B,CAAC,GAClF,MAAM,WAAE,KAAe,GAAS,EAChC,OAAO,EAAY,EAAM,CACvB,aAAc,SACd,YAAa,MACb,cAAe,IACf,cAAe,CAAE,SAAU,EAAG,cAAe,KAC7C,cAAc,EACd,QAAQ,EACR,GAAI,CAAE,MAAM,EAAO,QAAQ,EAAO,OAAO,MACtC,EACH,UAAW,EAAK,WAAa,GAEjC"}
|
package/dist/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{b as s,v as a,y as r}from"./shared/defaults-C-aC_B4z.js";import{i as o,n as t,r as d,t as e}from"./shared/board-
|
|
1
|
+
import{b as s,v as a,y as r}from"./shared/defaults-C-aC_B4z.js";import{i as o,n as t,r as d,t as e}from"./shared/board-p60lv7As.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-DZpEpkED.js";import{a as h,b as d,h as l,m as c,t as p,u,y as m}from"./defaults-C-aC_B4z.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-DaWyf3qV.js";import{a as C,c as P,d as T,f as L,i as A,l as D,m as R,n as q,o as U,p as O,r as N,s as G,t as j,u as F}from"./ui-DWQtW0zJ.js";function B(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 K=/* @__PURE__ */new Map;for(const{kind:St}of m)K.set(St,{kind:St});function H(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){H(t);const e=K.get(t.kind);return K.set(t.kind,t),()=>{e?K.set(t.kind,e):K.delete(t.kind)}}function Y(){return[...K.values()]}function X(t=[]){return new Map([...Y(),...t.map(H)].map(t=>[t.kind,t]))}var _=class{id;element=document.createElement("div");shape=document.createElementNS(A,"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=C("ink",s),this.text.style.color=T(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=R(t,s,this.id,l?.d)+("line"===t.kind||l?F(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=`${P(t.text)}px`,this.text.style.fontFamily=G(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=C("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-DF0uI4-I.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>${U(t)}</span>`,this.auxiliary.append(e)}destroy(){this.unmount?.(),this.unmount=void 0,this.element.remove()}},W=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 V(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 Q="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",Z=V(`<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="${Q}" fill="none" stroke="#b9a6e6" stroke-width="5" stroke-opacity=".14" stroke-linejoin="round"/><path d="${Q}" fill="#18252a" stroke="#fff" stroke-width="2" stroke-linejoin="round"/>`,36,[7,7],"default"),tt="M14 4v6m0 8v6M4 14h6m8 0h6",et=V(`<circle cx="14" cy="14" r="10" fill="#c4b5fd" fill-opacity=".06"/><path d="${tt}" stroke="#b9a6e6" stroke-opacity=".15" stroke-width="6" stroke-linecap="round"/><path d="${tt}" stroke="#fff" stroke-width="4" stroke-linecap="round"/><path d="${tt}" stroke="#18252a" stroke-width="1.7" stroke-linecap="round"/><circle cx="14" cy="14" r="1" fill="#18252a"/>`,28,[14,14],"crosshair");var it=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="${Q}"/></svg>${this.name?`<span>${U(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()}}}}},st=class{host;options;root=document.createElement("div");world=document.createElement("div");overlay=document.createElementNS(A,"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 W(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 it(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=C(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=B(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="${L(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="${U(e.id)}" data-ad-handle="custom:${U(e.id)}" cx="${r.x}" cy="${r.y}" r="5" style="cursor:${U(e.cursor??"crosshair")}" aria-label="${U(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 nt(t,e,i){if(!t.text?.value)return"";const s=P(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){const s=Math.max(1,Math.floor(e/(.53*i))),n=[];for(const o of t.split("\n")){if(!o){n.push("");continue}let t="";for(const e of o.split(/\s+/)){t&&t.length+e.length+1>s&&(n.push(t),t="");let i=e;for(;i.length>s;)t&&(n.push(t),t=""),n.push(i.slice(0,s)),i=i.slice(s);t+=`${t?" ":""}${i}`}n.push(t)}return n}(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="${C("paper",e)}"/>`:""}<text x="${l}" y="${p}" font-family="${U(G(t.text.font))}" font-size="${s}" text-anchor="${i?"middle":d}" fill="${U(T(t,e))}">${r.map((t,e)=>`<tspan x="${l}" dy="${e?a:0}">${U(t)||" "}</tspan>`).join("")}</text>`}function ot(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 rt(t,e){const i=a(t);return i?`<a href="${U(i)}" target="_blank" rel="noopener noreferrer" style="text-decoration:none">${e}</a>`:e}function at(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=D.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=ot(u,h-2*g,15),y=ot(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>${rt(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="${O(h/2)}" cy="${O(r)}" r="${O(1.7*s)}" fill="#fff" fill-opacity=".1"/>\n <path d="M${O(o-.36*s)} ${O(r-.7*s)}L${O(o+.7*s)} ${O(r)}L${O(o-.36*s)} ${O(r+.7*s)}Z" fill="#fff"/>\n ${d>=96?`<rect y="${O(n)}" width="${h}" height="${O(d-n)}" fill="url(#${l}c)"/>`:""}\n ${e&&d>=120?`<text x="${g}" y="${g+10}" fill="#05D9AB" font-family="${U(c)}" font-size="11" font-weight="700">${e}</text>`:""}\n <text x="${g}" y="${d-(y?28:16)}" fill="#fff" font-family="${U(c)}" font-size="15" font-weight="700">${U(a)}</text>\n ${y?`<text x="${g}" y="${d-12}" fill="#B6C5C1" font-family="${U(c)}" font-size="12">${U(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="${U(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="${U(c)}" font-size="${Math.min(34,.28*y)}" font-weight="700">${U(v)}</text>`:"",k=y?y+20:24,b=ot(u,h-2*g,15),$=ot(m,h-2*g,12),M=t.description&&d-y>78?ot(t.description,h-2*g,12):"",S="dark"===s?"#ffffff14":"#10363914";return`${f}${rt(p,`<g clip-path="url(#${l}p)">\n <rect width="${h}" height="${d}" fill="${C("paper",s)}"/>${w}\n <text x="${g}" y="${k}" fill="${C("ink",s)}" font-family="${U(c)}" font-size="15" font-weight="700">${U(b)}</text>\n ${$?`<text x="${g}" y="${k+18}" fill="${C("slate",s)}" font-family="${U(c)}" font-size="12">${U($)}</text>`:""}\n ${M?`<text x="${g}" y="${k+36}" fill="${C("slate",s)}" font-family="${U(c)}" font-size="12">${U(M)}</text>`:""}\n </g><rect width="${h}" height="${d}" rx="${r}" fill="none" stroke="${S}"/>`)}`}var ht=/* @__PURE__ */new Uint32Array(256);for(let St=0;St<256;St++){let t=St;for(let e=0;e<8;e++)t=1&t?3988292384^t>>>1:t>>>1;ht[St]=t}function dt(t){return Uint8Array.of(t>>>24&255,t>>>16&255,t>>>8&255,255&t)}function lt(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(dt(e.length)),s.set(i,4),s.set(e,8),s.set(dt(function(t){let e=-1;for(const i of t)for(const t of i)e=ht[255&(e^t)]^e>>>8;return~e>>>0}([i,e])),8+e.length),s}function ct(t,e,i,s){return(t<<24|e<<16|i<<8|s)>>>0}function pt(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 ut(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 mt(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 gt(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 ft(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=ct(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:pt(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=ut(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=ut(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(mt)}(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(ct(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(ct(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=ct(t[s],t[s+1],t[s+2],t[s+3]);let a=e.get(n);void 0===a&&(a=gt(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 yt(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(dt(t)),n.set(dt(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),lt("IHDR",n),lt("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(lt("tRNS",t))}h.push(lt("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)),lt("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 xt={png:"image/png",jpeg:"image/jpeg",webp:"image/webp"},vt=[.85,.7,.55,.4];var wt=/* @__PURE__ */new Map;function kt(t,e){const i=JSON.stringify(e),s=wt.get(i);if(s)return wt.delete(i),wt.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=G(e.font),n.style.fontSize=`${P(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*P(e),Math.ceil(o.height))};return n.remove(),wt.set(i,r),wt.size>256&&wt.delete(wt.keys().next().value),r}var bt={v:"select",h:"hand",r:"rect",o:"ellipse",d:"diamond",l:"line",a:"connector",p:"path",t:"text",n:"note",e:"eraser"},$t=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 st(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=j(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"text"===e.kind&&e.autoWidth&&"string"==typeof e.text?.value&&e.text.value.length<=f.maxTextLength&&(e={...e,...kt(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)&&(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,...kt(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),N(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=>C(t,s),escape:U});e="string"==typeof i?i:(new XMLSerializer).serializeToString(i)}else if(["rect","ellipse","diamond","note","line","path","connector"].includes(b.kind))e=R(b,s,`export_${w}`,h?.d),(h||"line"===b.kind)&&(e+=F(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="${U(i.src)}" preserveAspectRatio="none"/></svg>`:`<image width="${b.w}" height="${b.h}" href="${U(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=at(b,s,t,w):["text","group"].includes(b.kind)||(e=`<rect width="${b.w}" height="${b.h}" rx="8" fill="${C("paper",s)}" stroke="#8F93F9" stroke-dasharray="5 4"/><text x="12" y="24" fill="${C("ink",s)}" font-family="${U(D.sans)}" font-size="14">${U("html"===b.kind?"HTML content":`Unknown kind: ${b.kind}`)}</text>`);if("video"!==b.kind&&"link"!==b.kind&&(e+=nt(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">${U(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="${U(b.id)}" data-ad-kind="${U(b.kind)}"${d?` transform="${d}"`:""}${void 0!==b.style?.opacity?` opacity="${b.style.opacity}"`:""}><title>${U(b.name??b.text?.value??b.kind)}</title>${e}</g>`;v.push(l)}const k=!1===i.background?"":C("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="${U(t.meta.title)}"><title>${U(t.meta.title)}</title>${k?`<rect x="${m}" y="${g}" width="${f}" height="${y}" fill="${U(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)),...vt.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=ft(t.data,n);try{return await yt(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()}.`)),xt[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-Oc4kZ0P7.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?kt(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?Z:et}(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=B(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&&bt[i]&&(t.preventDefault(),this.setTool(bt[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(q,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-Oc4kZ0P7.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 Mt(t,e){return new $t(t,e)}export{J as i,Mt as n,H as r,$t as t};
|
|
2
|
+
//# sourceMappingURL=board-p60lv7As.js.map
|