@linkurious/ogma-annotations 2.1.2 → 2.1.4

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/dist/ui.mjs CHANGED
@@ -1,47 +1,47 @@
1
- var x = Object.defineProperty;
2
- var $ = (r, t, e) => t in r ? x(r, t, { enumerable: !0, configurable: !0, writable: !0, value: e }) : r[t] = e;
3
- var l = (r, t, e) => $(r, typeof t != "symbol" ? t + "" : t, e);
4
- import { RgbaBase as M } from "vanilla-colorful/lib/entrypoints/rgba";
5
- import { j as g, s as L, t as T, i as P, v as k, h as b, G as d, aJ as B, D as C, ak as E, af as S } from "./Polygon-BsnVN6js.js";
6
- const y = "rgba-color-picker";
7
- class D extends M {
1
+ var _ = Object.defineProperty;
2
+ var R = (s, t, e) => t in s ? _(s, t, { enumerable: !0, configurable: !0, writable: !0, value: e }) : s[t] = e;
3
+ var c = (s, t, e) => R(s, typeof t != "symbol" ? t + "" : t, e);
4
+ import { RgbaBase as z } from "vanilla-colorful/lib/entrypoints/rgba";
5
+ import { j as w, s as k, t as T, i as B, v as E, h as S, L as y, aO as F, F as x, ao as P, aj as M, G as q, u as W, M as V, am as $, aN as U } from "./Polygon-BmJ_q7qz.js";
6
+ const A = "rgba-color-picker";
7
+ class Y extends z {
8
8
  }
9
- function F() {
10
- return customElements.get(y) || customElements.define(y, D), document.createElement(y);
9
+ function N() {
10
+ return customElements.get(A) || customElements.define(A, Y), document.createElement(A);
11
11
  }
12
- const O = [
12
+ const j = [
13
13
  { value: "#f5f5f5", style: "--circle-color: #f5f5f5;" },
14
14
  { value: "#EDE6FF", style: "--circle-color: #EDE6FF;" },
15
15
  {
16
16
  value: "transparent",
17
17
  style: "--circle-color: white; border: 2px dashed #ccc;"
18
18
  }
19
- ], m = [
19
+ ], C = [
20
20
  { value: "sans-serif", label: "Sans Serif", icon: "type" },
21
21
  { value: "serif", label: "Serif", icon: "italic" },
22
22
  { value: "monospace", label: "Monospace", icon: "code" }
23
- ], N = [
23
+ ], G = [
24
24
  { value: "none", label: "None", icon: "x" },
25
25
  { value: "arrow", label: "Open Arrow", icon: "arrow-left" },
26
26
  { value: "arrow-plain", label: "Filled Arrow", icon: "play" },
27
27
  { value: "halo-dot", label: "Halo Dot", icon: "circle-dot" },
28
28
  { value: "dot", label: "Dot", icon: "dot" }
29
- ], R = [
29
+ ], X = [
30
30
  { value: "plain", icon: "circle" },
31
31
  { value: "dashed", icon: "circle-dashed" }
32
- ], H = ["#0099FF", "#FF7523", "#44AA99"];
33
- function I(r) {
34
- return `rgba(${r.r}, ${r.g}, ${r.b}, ${r.a})`;
32
+ ], J = ["#0099FF", "#FF7523", "#44AA99"];
33
+ function O(s) {
34
+ return `rgba(${s.r}, ${s.g}, ${s.b}, ${s.a})`;
35
35
  }
36
- const _ = 3;
37
- function z() {
38
- return { colors: [...H], activeIndex: 0 };
36
+ const K = 3;
37
+ function Z() {
38
+ return { colors: [...J], activeIndex: 0 };
39
39
  }
40
- function q(r, t) {
41
- const e = r.colors.indexOf(t);
42
- return e === -1 ? { colors: [t, ...r.colors].slice(0, _), activeIndex: 0 } : { colors: r.colors, activeIndex: e };
40
+ function Q(s, t) {
41
+ const e = s.colors.indexOf(t);
42
+ return e === -1 ? { colors: [t, ...s.colors].slice(0, K), activeIndex: 0 } : { colors: s.colors, activeIndex: e };
43
43
  }
44
- const W = {
44
+ const tt = {
45
45
  "chevron-down": '<path d="m6 9 6 6 6-6"/>',
46
46
  x: '<path d="M18 6 6 18"/><path d="m6 6 12 12"/>',
47
47
  "arrow-left": '<path d="m12 19-7-7 7-7"/><path d="M19 12H5"/>',
@@ -53,6 +53,8 @@ const W = {
53
53
  "circle-dashed": '<path d="M10.1 2.182a10 10 0 0 1 3.8 0"/><path d="M13.9 21.818a10 10 0 0 1-3.8 0"/><path d="M17.609 3.721a10 10 0 0 1 2.69 2.7"/><path d="M2.182 13.9a10 10 0 0 1 0-3.8"/><path d="M20.279 17.609a10 10 0 0 1-2.7 2.69"/><path d="M21.818 10.1a10 10 0 0 1 0 3.8"/><path d="M3.721 6.391a10 10 0 0 1 2.7-2.69"/><path d="M6.391 20.279a10 10 0 0 1-2.69-2.7"/>',
54
54
  type: '<path d="M4 7V4h16v3"/><path d="M9 20h6"/><path d="M12 4v16"/>',
55
55
  italic: '<line x1="19" x2="10" y1="4" y2="4"/><line x1="14" x2="5" y1="20" y2="20"/><line x1="15" x2="9" y1="4" y2="20"/>',
56
+ bold: '<path d="M6 12h9a4 4 0 0 1 0 8H7a1 1 0 0 1-1-1V5a1 1 0 0 1 1-1h7a4 4 0 0 1 0 8"/>',
57
+ user: '<path d="M19 21v-2a4 4 0 0 0-4-4H9a4 4 0 0 0-4 4v2"/><circle cx="12" cy="7" r="4"/>',
56
58
  code: '<polyline points="16 18 22 12 16 6"/><polyline points="8 6 2 12 8 18"/>',
57
59
  trash: '<path d="M3 6h18"/><path d="M19 6v14c0 1-1 2-2 2H7c-1 0-2-1-2-2V6"/><path d="M8 6V4c0-1 1-2 2-2h4c1 0 2 1 2 2v2"/>',
58
60
  undo: '<path d="M3 7v6h6"/><path d="M21 17a9 9 0 0 0-9-9 9 9 0 0 0-6 2.3L3 13"/>',
@@ -68,74 +70,109 @@ const W = {
68
70
  "rotate-ccw": '<path d="M3 12a9 9 0 1 0 9-9 9.75 9.75 0 0 0-6.74 2.74L3 8"/><path d="M3 3v5h5"/>',
69
71
  minimize: '<path d="M8 3v3a2 2 0 0 1-2 2H3"/><path d="M21 8h-3a2 2 0 0 1-2-2V3"/><path d="M3 16h3a2 2 0 0 1 2 2v3"/><path d="M16 21v-3a2 2 0 0 1 2-2h3"/>'
70
72
  };
71
- function v(r, t = 18) {
72
- return `<svg xmlns="http://www.w3.org/2000/svg" width="${t}" height="${t}" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">${W[r]}</svg>`;
73
+ function v(s, t = 18) {
74
+ return `<svg xmlns="http://www.w3.org/2000/svg" width="${t}" height="${t}" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">${tt[s]}</svg>`;
73
75
  }
74
- const V = 150;
75
- function U(r, { onShow: t, onHide: e }) {
76
- let o = null, i = null;
77
- const n = () => {
78
- i !== null && (clearTimeout(i), i = null);
79
- }, s = () => {
80
- n(), o && (t(o), o = null);
81
- }, a = (h) => {
82
- if (n(), h.ids.length === 1) {
83
- const u = r.getAnnotation(h.ids[0]);
84
- if (!u) return;
85
- if (o = u, r.isDrawing()) {
86
- r.once("cancelDrawing", s), r.once("completeDrawing", s);
76
+ const et = 150;
77
+ function D(s, { onShow: t, onHide: e, hideWhenNotEditable: o = !0 }) {
78
+ const i = (p) => !o || s.isAnnotationEditable(p);
79
+ let n = null, r = null, d = null, h = null;
80
+ const a = () => {
81
+ h !== null && (clearTimeout(h), h = null);
82
+ }, l = () => {
83
+ if (a(), n) {
84
+ const p = n;
85
+ n = null, i(p.id) ? (r = p, t(p)) : u();
86
+ return;
87
+ }
88
+ if (!r && d != null) {
89
+ const p = s.getAnnotation(d);
90
+ p && i(p.id) && (r = p, t(p));
91
+ }
92
+ }, u = () => {
93
+ a(), n = null, r = null, e();
94
+ }, m = (p) => {
95
+ if (a(), p.ids.length === 1) {
96
+ const g = s.getAnnotation(p.ids[0]);
97
+ if (!g) return;
98
+ if (d = p.ids[0], n = g, s.isDrawing()) {
99
+ s.once("cancelDrawing", l), s.once("completeDrawing", l);
87
100
  return;
88
101
  }
89
- i = setTimeout(s, V);
102
+ h = setTimeout(l, et);
90
103
  } else
91
- o = null, e();
92
- }, c = () => {
93
- n(), o = null, e();
94
- }, p = () => {
95
- n(), o = null, e();
104
+ d = null, u();
105
+ }, b = () => u(), f = (p) => {
106
+ const g = n ?? r;
107
+ g && !p.ids.includes(g.id) || (d = null, u());
96
108
  };
97
- return r.on("select", a), r.on("click", s), r.on("dragend", s), r.on("dragstart", c), r.on("unselect", p), () => {
98
- n(), r.off("select", a), r.off("click", s), r.off("dragend", s), r.off("dragstart", c), r.off("unselect", p), r.off("cancelDrawing", s), r.off("completeDrawing", s);
109
+ return s.on("select", m), s.on("click", l), s.on("dragend", l), s.on("dragstart", b), s.on("unselect", f), () => {
110
+ a(), s.off("select", m), s.off("click", l), s.off("dragend", l), s.off("dragstart", b), s.off("unselect", f), s.off("cancelDrawing", l), s.off("completeDrawing", l);
99
111
  };
100
112
  }
101
- const G = "right", Y = "vertical";
102
- class Z {
113
+ const ot = "right", it = "vertical", nt = [
114
+ "arrow",
115
+ "text",
116
+ "box",
117
+ "comment",
118
+ "polygon"
119
+ ];
120
+ function rt(s) {
121
+ return w(s) ? "arrow" : k(s) ? "text" : T(s) ? "box" : B(s) ? "comment" : E(s) ? "polygon" : null;
122
+ }
123
+ class kt {
103
124
  constructor(t) {
104
- l(this, "control");
105
- l(this, "panel");
106
- l(this, "panelBody");
107
- l(this, "mode", null);
108
- l(this, "currentAnnotation", null);
109
- l(this, "currentColor", "#0099FF");
110
- l(this, "recent", z());
111
- l(this, "colorCircles", []);
112
- l(this, "colorPickerOverlay", null);
113
- l(this, "colorPicker", null);
114
- l(this, "detachVisibility");
115
- l(this, "documentClickHandler");
116
- l(this, "hide", () => {
125
+ c(this, "control");
126
+ c(this, "panel");
127
+ c(this, "panelBody");
128
+ c(this, "mode", null);
129
+ c(this, "currentAnnotation", null);
130
+ c(this, "currentColor", "#0099FF");
131
+ c(this, "recent", Z());
132
+ c(this, "colorCircles", []);
133
+ c(this, "colorPickerOverlay", null);
134
+ c(this, "colorPicker", null);
135
+ c(this, "detachVisibility");
136
+ c(this, "documentClickHandler");
137
+ c(this, "enabledTypes");
138
+ c(this, "hide", () => {
117
139
  this.panel.style.display = "none", this.closeColorPicker(), this.currentAnnotation = null, this.mode = null;
118
140
  });
119
- this.control = t.control;
120
- const e = t.container ?? document.body;
121
- this.panel = document.createElement("div"), this.panel.className = "annotation-panel", this.panel.style.display = "none", this.panel.dataset.placement = t.placement ?? G, this.panel.dataset.orientation = t.orientation ?? Y, this.panelBody = document.createElement("div"), this.panelBody.className = "panel-body", this.panel.appendChild(this.panelBody), e.appendChild(this.panel), this.detachVisibility = U(this.control, {
122
- onShow: (o) => {
123
- this.setAnnotation(o), this.show();
141
+ var i, n, r, d;
142
+ this.control = t.control, this.enabledTypes = t.enabledTypes ?? nt;
143
+ const e = t.container ?? document.body, o = (d = (r = (n = (i = this.control).getOgma) == null ? void 0 : n.call(i)) == null ? void 0 : r.getContainer) == null ? void 0 : d.call(r);
144
+ !t.container && o && o !== document.body && console.error(
145
+ "[ogma-annotations-control] AnnotationPanel: no `container` option given, defaulting to document.body. If this panel should dock to the Ogma graph area (e.g. it is embedded in a smaller/offset div), pass `container: control.getOgma().getContainer()` and give that container `position: relative`."
146
+ ), this.panel = document.createElement("div"), this.panel.className = "annotation-panel", this.panel.setAttribute("role", "region"), this.panel.setAttribute("aria-label", "Annotation style panel"), this.panel.style.display = "none", this.panel.dataset.placement = t.placement ?? ot, this.panel.dataset.orientation = t.orientation ?? it, this.panelBody = document.createElement("div"), this.panelBody.className = "panel-body", this.panel.appendChild(this.panelBody), e.appendChild(this.panel), this.detachVisibility = D(this.control, {
147
+ onShow: (h) => {
148
+ const a = rt(h);
149
+ if (!a || !this.enabledTypes.includes(a)) {
150
+ this.hide();
151
+ return;
152
+ }
153
+ this.setAnnotation(h), this.show();
124
154
  },
125
- onHide: this.hide
155
+ onHide: this.hide,
156
+ hideWhenNotEditable: t.hideWhenNotEditable
126
157
  }), ["click", "mousedown", "mousemove"].forEach(
127
- (o) => this.panel.addEventListener(o, (i) => i.stopPropagation())
128
- ), this.documentClickHandler = (o) => {
129
- this.colorPickerOverlay && !this.colorPickerOverlay.contains(o.target) && !this.colorCircles.some((i) => i.contains(o.target)) && this.closeColorPicker(), this.panelBody.querySelectorAll(".custom-select").forEach((i) => i.classList.remove("open"));
158
+ (h) => this.panel.addEventListener(h, (a) => a.stopPropagation())
159
+ ), this.documentClickHandler = (h) => {
160
+ this.colorPickerOverlay && !this.colorPickerOverlay.contains(h.target) && !this.colorCircles.some((a) => a.contains(h.target)) && this.closeColorPicker(), this.panelBody.querySelectorAll(".custom-select").forEach((a) => {
161
+ var l;
162
+ a.classList.remove("open"), (l = a.querySelector(".custom-select-trigger")) == null || l.setAttribute(
163
+ "aria-expanded",
164
+ "false"
165
+ );
166
+ });
130
167
  }, document.addEventListener("click", this.documentClickHandler);
131
168
  }
132
169
  setAnnotation(t) {
133
- this.currentAnnotation = t, g(t) ? (this.mode = "arrow", this.renderArrow(t)) : L(t) || T(t) || P(t) ? (this.mode = "text", this.renderText(t)) : k(t) && (this.mode = "polygon", this.renderPolygon(t));
170
+ this.currentAnnotation = t, w(t) ? (this.mode = "arrow", this.renderArrow(t)) : k(t) || T(t) || B(t) ? (this.mode = "text", this.renderText(t)) : E(t) && (this.mode = "polygon", this.renderPolygon(t));
134
171
  }
135
172
  renderArrow(t) {
136
173
  const e = t.properties.style || {};
137
174
  this.updateColorFromAnnotation(
138
- e.strokeColor || b.strokeColor
175
+ e.strokeColor || S.strokeColor
139
176
  ), this.panelBody.innerHTML = `
140
177
  ${this.section("Color", this.colorSelector())}
141
178
  ${this.section(
@@ -145,20 +182,20 @@ class Z {
145
182
  ${this.extremitySelector("tail", t)}
146
183
  </div>`
147
184
  )}
148
- ${this.slider("Stroke width", "line-width", e.strokeWidth || b.strokeWidth, 1, 20)}
185
+ ${this.slider("Stroke width", "line-width", e.strokeWidth || S.strokeWidth, 1, 20)}
149
186
  ${this.lineTypeButtons(e.strokeType || "plain")}
150
187
  `, this.bind();
151
188
  }
152
189
  renderText(t) {
153
190
  const e = t.properties.style || {};
154
- this.updateColorFromAnnotation(e.color || d.color);
155
- const o = typeof e.fontSize == "number" ? e.fontSize : typeof d.fontSize == "number" ? d.fontSize : 18;
191
+ this.updateColorFromAnnotation(e.color || y.color);
192
+ const o = typeof e.fontSize == "number" ? e.fontSize : typeof y.fontSize == "number" ? y.fontSize : 18;
156
193
  this.panelBody.innerHTML = `
157
194
  ${this.section("Color", this.colorSelector())}
158
- ${this.section("Background", this.backgroundSelector(e.background || d.background))}
159
- ${this.section("Font", `<div class="custom-select-section">${this.fontSelector(e.font || d.font)}</div>`)}
195
+ ${this.section("Background", this.backgroundSelector(e.background || y.background))}
196
+ ${this.section("Font", `<div class="custom-select-section">${this.fontSelector(e.font || y.font)}</div>`)}
160
197
  ${this.slider("Font size", "font-size", o, 8, 72)}
161
- ${this.slider("Stroke width", "line-width", e.strokeWidth || d.strokeWidth, 1, 20)}
198
+ ${this.slider("Stroke width", "line-width", e.strokeWidth || y.strokeWidth, 1, 20)}
162
199
  ${this.lineTypeButtons(e.strokeType || "plain")}
163
200
  `, this.bind();
164
201
  }
@@ -166,7 +203,7 @@ class Z {
166
203
  const e = t.properties.style || {};
167
204
  this.updateColorFromAnnotation(e.strokeColor || "#000000"), this.panelBody.innerHTML = `
168
205
  ${this.section("Color", this.colorSelector())}
169
- ${this.section("Fill", this.backgroundSelector(e.background || "transparent"))}
206
+ ${this.section("Fill", this.backgroundSelector(e.background || "transparent", "Fill"))}
170
207
  ${this.slider("Stroke width", "line-width", e.strokeWidth || 2, 1, 20)}
171
208
  ${this.lineTypeButtons(e.strokeType || "plain")}
172
209
  `, this.bind();
@@ -179,54 +216,55 @@ class Z {
179
216
  return e ? `<span style="display:inline-flex;transform:rotate(180deg)">${v(t)}</span>` : v(t);
180
217
  }
181
218
  colorSelector() {
182
- return `<div class="color-selector">${this.recent.colors.map(
219
+ return `<div class="color-selector" role="group" aria-label="Color">${this.recent.colors.map(
183
220
  (t, e) => `
184
- <button class="color-circle ${e === 0 ? "color-circle-primary" : ""}" data-index="${e}" data-color="${t}">
221
+ <button type="button" class="color-circle ${e === 0 ? "color-circle-primary" : ""}" data-index="${e}" data-color="${t}" aria-label="Set color to ${t}" aria-pressed="${e === 0}">
185
222
  <div class="color-inner"></div>
186
223
  </button>
187
224
  `
188
225
  ).join("")}</div>`;
189
226
  }
190
- backgroundSelector(t) {
191
- return `<div class="color-selector">${O.map(
192
- ({ value: e, style: o }) => `
193
- <button class="color-circle ${e === t ? "color-circle-primary" : ""}" data-background-color="${e}">
194
- <div class="color-inner" style="${o}"></div>
227
+ backgroundSelector(t, e = "Background") {
228
+ return `<div class="color-selector" role="group" aria-label="${e}">${j.map(
229
+ ({ value: o, style: i }) => `
230
+ <button type="button" class="color-circle ${o === t ? "color-circle-primary" : ""}" data-background-color="${o}" aria-label="${o === "transparent" ? "No background" : `Background ${o}`}" aria-pressed="${o === t}">
231
+ <div class="color-inner" style="${i}"></div>
195
232
  </button>
196
233
  `
197
234
  ).join("")}</div>`;
198
235
  }
199
236
  fontSelector(t) {
200
- const e = m.find((o) => o.value === t) || m[0];
237
+ const e = C.find((o) => o.value === t) || C[0];
201
238
  return this.dropdown(
202
239
  "font",
203
240
  e,
204
- m.map((o) => ({ ...o, selected: o.value === t }))
241
+ C.map((o) => ({ ...o, selected: o.value === t }))
205
242
  );
206
243
  }
207
244
  extremitySelector(t, e) {
208
- var s;
209
- const o = ((s = e.properties.style) == null ? void 0 : s[t]) || "none", i = N.map((a) => ({
210
- ...a,
211
- icon: a.value === "arrow" && t === "tail" ? "arrow-left" : a.value === "arrow" ? "arrow-right" : a.icon,
212
- selected: a.value === o,
213
- rotate: a.value === "arrow-plain" && t === "tail"
214
- })), n = i.find((a) => a.selected) || i[0];
245
+ var r;
246
+ const o = ((r = e.properties.style) == null ? void 0 : r[t]) || "none", i = G.map((d) => ({
247
+ ...d,
248
+ icon: d.value === "arrow" && t === "tail" ? "arrow-left" : d.value === "arrow" ? "arrow-right" : d.icon,
249
+ selected: d.value === o,
250
+ rotate: d.value === "arrow-plain" && t === "tail"
251
+ })), n = i.find((d) => d.selected) || i[0];
215
252
  return `<div class="extremity-wrapper"><label>${t}</label>${this.dropdown(t, n, i, `data-end="${t}"`)}</div>`;
216
253
  }
217
254
  dropdown(t, e, o, i = "") {
255
+ const n = t === "font" ? "Font" : t;
218
256
  return `<div class="custom-select" data-type="${t}" ${i}>
219
- <div class="custom-select-trigger">
257
+ <button type="button" class="custom-select-trigger" aria-haspopup="listbox" aria-expanded="false" aria-label="${n}: ${e.label}">
220
258
  ${this.icon(e.icon, e.rotate)}
221
259
  <span>${e.label}</span>
222
260
  ${this.icon("chevron-down")}
223
- </div>
224
- <div class="custom-select-options">${o.map(
225
- (n) => `
226
- <div class="custom-select-option ${n.selected ? "selected" : ""}" data-value="${n.value}" data-icon="${n.icon}" data-rotate="${n.rotate ? "1" : ""}" title="${n.label}">
227
- ${this.icon(n.icon, n.rotate)}
228
- <span>${n.label}</span>
229
- </div>
261
+ </button>
262
+ <div class="custom-select-options" role="listbox" aria-label="${n} options">${o.map(
263
+ (r) => `
264
+ <button type="button" role="option" aria-selected="${r.selected ? "true" : "false"}" class="custom-select-option ${r.selected ? "selected" : ""}" data-value="${r.value}" data-icon="${r.icon}" data-rotate="${r.rotate ? "1" : ""}" title="${r.label}">
265
+ ${this.icon(r.icon, r.rotate)}
266
+ <span>${r.label}</span>
267
+ </button>
230
268
  `
231
269
  ).join("")}</div>
232
270
  </div>`;
@@ -235,7 +273,7 @@ class Z {
235
273
  return `${this.section(
236
274
  t,
237
275
  `<div class="slider-section">
238
- <input type="range" id="${e}-slider" class="slider" min="${i}" max="${n}" value="${o}">
276
+ <input type="range" id="${e}-slider" class="slider" aria-label="${t}" min="${i}" max="${n}" value="${o}">
239
277
  <div class="slider-value"><span id="${e}-value">${o}</span></div>
240
278
  </div>`
241
279
  )}`;
@@ -243,9 +281,9 @@ class Z {
243
281
  lineTypeButtons(t) {
244
282
  return `${this.section(
245
283
  "Line type",
246
- `<div class="linetype-section">${R.map(
284
+ `<div class="linetype-section" role="group" aria-label="Line type">${X.map(
247
285
  ({ value: e, icon: o }) => `
248
- <button class="linetype-button ${t === e ? "active" : ""}" data-linetype="${e}" title="${e}">
286
+ <button type="button" class="linetype-button ${t === e ? "active" : ""}" data-linetype="${e}" title="${e}" aria-label="${e} line" aria-pressed="${t === e}">
249
287
  ${this.icon(o)}
250
288
  </button>
251
289
  `
@@ -272,20 +310,28 @@ class Z {
272
310
  ".custom-select-trigger"
273
311
  ), o = t.querySelectorAll(
274
312
  ".custom-select-option"
275
- );
276
- e.addEventListener("click", (i) => {
277
- i.stopPropagation(), this.panelBody.querySelectorAll(".custom-select").forEach((n) => {
278
- n !== t && n.classList.remove("open");
279
- }), t.classList.toggle("open");
280
- }), o.forEach((i) => {
281
- i.addEventListener("click", (n) => {
282
- n.stopPropagation();
283
- const s = i.dataset.value;
284
- o.forEach((w) => w.classList.remove("selected")), i.classList.add("selected");
285
- const a = i.dataset.icon, c = i.dataset.rotate === "1", p = i.querySelector("span").textContent || "", h = e.querySelector("svg, span[style]");
286
- h && (h.outerHTML = this.icon(a, c)), e.querySelector("span").textContent = p, t.classList.remove("open");
287
- const u = t.dataset.type, f = t.dataset.end;
288
- u === "font" ? this.updateStyle({ font: s }) : f === "head" ? this.updateStyle({ head: s }) : f === "tail" && this.updateStyle({ tail: s });
313
+ ), i = t.dataset.type === "font" ? "Font" : t.dataset.type;
314
+ e.addEventListener("click", (n) => {
315
+ n.stopPropagation(), this.panelBody.querySelectorAll(".custom-select").forEach((d) => {
316
+ var h;
317
+ d !== t && (d.classList.remove("open"), (h = d.querySelector(".custom-select-trigger")) == null || h.setAttribute(
318
+ "aria-expanded",
319
+ "false"
320
+ ));
321
+ });
322
+ const r = !t.classList.contains("open");
323
+ t.classList.toggle("open", r), e.setAttribute("aria-expanded", String(r));
324
+ }), o.forEach((n) => {
325
+ n.addEventListener("click", (r) => {
326
+ r.stopPropagation();
327
+ const d = n.dataset.value;
328
+ o.forEach((f) => {
329
+ f.classList.remove("selected"), f.setAttribute("aria-selected", "false");
330
+ }), n.classList.add("selected"), n.setAttribute("aria-selected", "true");
331
+ const h = n.dataset.icon, a = n.dataset.rotate === "1", l = n.querySelector("span").textContent || "", u = e.querySelector("svg, span[style]");
332
+ u && (u.outerHTML = this.icon(h, a)), e.querySelector("span").textContent = l, e.setAttribute("aria-label", `${i}: ${l}`), t.classList.remove("open"), e.setAttribute("aria-expanded", "false");
333
+ const m = t.dataset.type, b = t.dataset.end;
334
+ m === "font" ? this.updateStyle({ font: d }) : b === "head" ? this.updateStyle({ head: d }) : b === "tail" && this.updateStyle({ tail: d });
289
335
  });
290
336
  });
291
337
  }), ["line-width", "font-size"].forEach((t) => {
@@ -301,20 +347,21 @@ class Z {
301
347
  }), this.panelBody.querySelectorAll(".linetype-button").forEach((t) => {
302
348
  t.addEventListener("click", () => {
303
349
  const e = t.dataset.linetype;
304
- this.panelBody.querySelectorAll(".linetype-button").forEach((o) => o.classList.remove("active")), t.classList.add("active"), this.updateStyle({ strokeType: e });
350
+ this.panelBody.querySelectorAll(".linetype-button").forEach((o) => {
351
+ o.classList.remove("active"), o.setAttribute("aria-pressed", "false");
352
+ }), t.classList.add("active"), t.setAttribute("aria-pressed", "true"), this.updateStyle({ strokeType: e });
305
353
  });
306
354
  });
307
355
  }
308
356
  // Color management
309
357
  updateColorFromAnnotation(t) {
310
- this.recent = q(this.recent, t), this.currentColor = t;
358
+ this.recent = Q(this.recent, t), this.currentColor = t;
311
359
  }
312
360
  updateColorCircles() {
313
361
  this.colorCircles.forEach((t, e) => {
314
- t.setAttribute("data-color", this.recent.colors[e]), t.style.setProperty("--circle-color", this.recent.colors[e]), t.classList.toggle(
315
- "color-circle-primary",
316
- e === this.recent.activeIndex
317
- );
362
+ t.setAttribute("data-color", this.recent.colors[e]), t.setAttribute("aria-label", `Set color to ${this.recent.colors[e]}`), t.style.setProperty("--circle-color", this.recent.colors[e]);
363
+ const o = e === this.recent.activeIndex;
364
+ t.classList.toggle("color-circle-primary", o), t.setAttribute("aria-pressed", String(o));
318
365
  });
319
366
  }
320
367
  toggleColorPicker(t) {
@@ -322,10 +369,10 @@ class Z {
322
369
  this.closeColorPicker();
323
370
  return;
324
371
  }
325
- this.colorPickerOverlay = document.createElement("div"), this.colorPickerOverlay.className = "color-picker-overlay", document.body.appendChild(this.colorPickerOverlay), this.colorPicker = F(), this.colorPicker.color = B(this.currentColor), this.colorPickerOverlay.appendChild(this.colorPicker);
372
+ this.colorPickerOverlay = document.createElement("div"), this.colorPickerOverlay.className = "color-picker-overlay", this.colorPickerOverlay.setAttribute("role", "dialog"), this.colorPickerOverlay.setAttribute("aria-label", "Custom color picker"), document.body.appendChild(this.colorPickerOverlay), this.colorPicker = N(), this.colorPicker.color = F(this.currentColor), this.colorPickerOverlay.appendChild(this.colorPicker);
326
373
  const e = t.getBoundingClientRect();
327
374
  this.colorPickerOverlay.style.right = `${window.innerWidth - e.right}px`, this.colorPickerOverlay.style.top = `${e.bottom + 10}px`, this.colorPicker.addEventListener("color-changed", (o) => {
328
- this.currentColor = I(o.detail.value), this.recent.colors[this.recent.activeIndex] = this.currentColor, this.updateColorCircles(), this.mode === "arrow" ? this.updateStyle({ strokeColor: this.currentColor }) : this.mode === "text" ? this.updateStyle({ color: this.currentColor }) : this.mode === "polygon" && this.updateStyle({ strokeColor: this.currentColor });
375
+ this.currentColor = O(o.detail.value), this.recent.colors[this.recent.activeIndex] = this.currentColor, this.updateColorCircles(), this.mode === "arrow" ? this.updateStyle({ strokeColor: this.currentColor }) : this.mode === "text" ? this.updateStyle({ color: this.currentColor }) : this.mode === "polygon" && this.updateStyle({ strokeColor: this.currentColor });
329
376
  });
330
377
  }
331
378
  closeColorPicker() {
@@ -333,7 +380,7 @@ class Z {
333
380
  }
334
381
  // Unified update method
335
382
  updateStyle(t) {
336
- this.currentAnnotation && (g(this.currentAnnotation) ? this.control.updateStyle(this.currentAnnotation.id, t) : k(this.currentAnnotation) ? this.control.updateStyle(this.currentAnnotation.id, t) : this.control.updateStyle(this.currentAnnotation.id, t));
383
+ this.currentAnnotation && (w(this.currentAnnotation) ? this.control.updateStyle(this.currentAnnotation.id, t) : E(this.currentAnnotation) ? this.control.updateStyle(this.currentAnnotation.id, t) : this.control.updateStyle(this.currentAnnotation.id, t));
337
384
  }
338
385
  // Layout
339
386
  setPlacement(t) {
@@ -350,7 +397,7 @@ class Z {
350
397
  this.closeColorPicker(), this.detachVisibility(), document.removeEventListener("click", this.documentClickHandler), this.panel.remove();
351
398
  }
352
399
  }
353
- const j = "bottom", J = "horizontal", A = [
400
+ const st = "bottom", at = "horizontal", L = [
354
401
  "arrow",
355
402
  "comment",
356
403
  "sticky-note",
@@ -358,26 +405,29 @@ const j = "bottom", J = "horizontal", A = [
358
405
  "text",
359
406
  "polygon"
360
407
  ];
361
- class tt {
408
+ class At {
362
409
  constructor(t) {
363
- l(this, "control");
364
- l(this, "root");
365
- l(this, "activeButton", null);
366
- l(this, "undoButton");
367
- l(this, "redoButton");
368
- l(this, "handleDrawingEnd", () => this.setActiveMode(null));
369
- l(this, "handleHistory", () => this.updateUndoRedo());
410
+ c(this, "control");
411
+ c(this, "root");
412
+ c(this, "activeButton", null);
413
+ c(this, "undoButton");
414
+ c(this, "redoButton");
415
+ c(this, "handleDrawingEnd", () => this.setActiveMode(null));
416
+ c(this, "handleHistory", () => this.updateUndoRedo());
417
+ var d, h, a, l;
370
418
  this.control = t.control;
371
- const e = t.container ?? document.body;
372
- this.root = document.createElement("div"), this.root.className = "annotation-toolbar", this.root.dataset.placement = t.placement ?? j, this.root.dataset.orientation = t.orientation ?? J, e.appendChild(this.root), ["click", "mousedown", "mousemove"].forEach(
373
- (s) => this.root.addEventListener(s, (a) => a.stopPropagation())
419
+ const e = t.container ?? document.body, o = (l = (a = (h = (d = this.control).getOgma) == null ? void 0 : h.call(d)) == null ? void 0 : a.getContainer) == null ? void 0 : l.call(a);
420
+ !t.container && o && o !== document.body && console.error(
421
+ "[ogma-annotations-control] AnnotationToolbar: no `container` option given, defaulting to document.body. If this toolbar should dock to the Ogma graph area (e.g. it is embedded in a smaller/offset div), pass `container: control.getOgma().getContainer()` and give that container `position: relative`."
422
+ ), this.root = document.createElement("div"), this.root.className = "annotation-toolbar oa-toolbar oa-toolbar-bar", this.root.setAttribute("role", "group"), this.root.setAttribute("aria-label", "Annotation tools"), this.root.dataset.placement = t.placement ?? st, this.root.dataset.orientation = t.orientation ?? at, e.appendChild(this.root), ["click", "mousedown", "mousemove"].forEach(
423
+ (u) => this.root.addEventListener(u, (m) => m.stopPropagation())
374
424
  );
375
- const o = t.enabledTypes ?? A, i = t.styles ?? {};
376
- A.filter((s) => o.includes(s)).forEach(
377
- (s) => this.root.appendChild(this.drawingButton(s, i))
378
- ), o.length > 0 && this.root.appendChild(this.separator()), this.undoButton = this.button(null, "undo", "Undo", () => this.control.undo()), this.redoButton = this.button(null, "redo", "Redo", () => this.control.redo()), this.root.appendChild(this.undoButton), this.root.appendChild(this.redoButton);
379
- const n = t.deleteMode ?? "erase";
380
- (n === "erase" || n === "both") && (this.root.appendChild(this.separator()), this.root.appendChild(
425
+ const i = t.enabledTypes ?? L, n = t.styles ?? {};
426
+ L.filter((u) => i.includes(u)).forEach(
427
+ (u) => this.root.appendChild(this.drawingButton(u, n))
428
+ ), i.length > 0 && this.root.appendChild(this.separator()), this.undoButton = this.button(null, "undo", "Undo", () => this.control.undo()), this.redoButton = this.button(null, "redo", "Redo", () => this.control.redo()), this.root.appendChild(this.undoButton), this.root.appendChild(this.redoButton);
429
+ const r = t.deleteMode ?? "erase";
430
+ (r === "erase" || r === "both") && (this.root.appendChild(this.separator()), this.root.appendChild(
381
431
  this.button(
382
432
  "erase",
383
433
  "eraser",
@@ -386,16 +436,18 @@ class tt {
386
436
  this.control.isEraseModeActive() ? (this.control.disableEraseMode(), this.setActiveMode(null)) : (this.control.enableEraseMode(), this.setActiveMode("erase"));
387
437
  }
388
438
  )
389
- )), (n === "select" || n === "both") && (n === "select" && this.root.appendChild(this.separator()), this.root.appendChild(
439
+ )), (r === "select" || r === "both") && (r === "select" && this.root.appendChild(this.separator()), this.root.appendChild(
390
440
  this.button(null, "trash", "Delete selected", () => {
391
- const s = this.control.getSelectedAnnotations();
392
- s.features.length > 0 && this.control.remove(s);
441
+ const m = this.control.getSelectedAnnotations().features.filter(
442
+ (b) => this.control.isAnnotationEditable(b.id)
443
+ );
444
+ m.length > 0 && this.control.remove({ type: "FeatureCollection", features: m });
393
445
  })
394
446
  )), (t.onJsonExport || t.onSvgExport) && (this.root.appendChild(this.separator()), t.onJsonExport && this.root.appendChild(
395
447
  this.button(null, "download", "Export annotations", t.onJsonExport)
396
448
  ), t.onSvgExport && this.root.appendChild(
397
449
  this.button(null, "camera", "Export SVG", t.onSvgExport)
398
- )), this.control.on(C, this.handleDrawingEnd), this.control.on(E, this.handleDrawingEnd), this.control.on(S, this.handleHistory), this.updateUndoRedo();
450
+ )), this.control.on(x, this.handleDrawingEnd), this.control.on(P, this.handleDrawingEnd), this.control.on(M, this.handleHistory), this.updateUndoRedo();
399
451
  }
400
452
  drawingButton(t, e) {
401
453
  switch (t) {
@@ -411,11 +463,11 @@ class tt {
411
463
  });
412
464
  case "comment":
413
465
  return this.button("comment", "message-square", "Add comment", () => {
414
- var n, s, a, c;
415
- const o = (n = e.comment) == null ? void 0 : n.commentStyle, i = (s = e.comment) == null ? void 0 : s.arrowStyle;
466
+ var n, r, d, h;
467
+ const o = (n = e.comment) == null ? void 0 : n.commentStyle, i = (r = e.comment) == null ? void 0 : r.arrowStyle;
416
468
  this.control.enableCommentDrawing({
417
- offsetX: ((a = e.comment) == null ? void 0 : a.offsetX) ?? 200,
418
- offsetY: ((c = e.comment) == null ? void 0 : c.offsetY) ?? -150,
469
+ offsetX: ((d = e.comment) == null ? void 0 : d.offsetX) ?? 200,
470
+ offsetY: ((h = e.comment) == null ? void 0 : h.offsetY) ?? -150,
419
471
  commentStyle: {
420
472
  content: "",
421
473
  ...o,
@@ -489,14 +541,14 @@ class tt {
489
541
  }
490
542
  button(t, e, o, i) {
491
543
  const n = document.createElement("button");
492
- return n.dataset.tooltip = o, n.innerHTML = v(e, 16), n.addEventListener("click", i), t && (n.dataset.mode = t), n;
544
+ return n.type = "button", n.className = "oa-toolbar-button", n.dataset.tooltip = o, n.setAttribute("aria-label", o), t && n.setAttribute("aria-pressed", "false"), n.innerHTML = v(e, 16), n.addEventListener("click", i), t && (n.dataset.mode = t), n;
493
545
  }
494
546
  separator() {
495
547
  const t = document.createElement("span");
496
- return t.className = "separator", t;
548
+ return t.className = "oa-toolbar-separator", t;
497
549
  }
498
550
  setActiveMode(t) {
499
- this.activeButton && this.activeButton.classList.remove("active"), this.activeButton = t ? this.root.querySelector(`[data-mode="${t}"]`) : null, this.activeButton && this.activeButton.classList.add("active");
551
+ this.activeButton && (this.activeButton.classList.remove("active"), this.activeButton.setAttribute("aria-pressed", "false")), this.activeButton = t ? this.root.querySelector(`[data-mode="${t}"]`) : null, this.activeButton && (this.activeButton.classList.add("active"), this.activeButton.setAttribute("aria-pressed", "true"));
500
552
  }
501
553
  updateUndoRedo() {
502
554
  this.undoButton.disabled = !this.control.canUndo(), this.redoButton.disabled = !this.control.canRedo();
@@ -509,25 +561,413 @@ class tt {
509
561
  this.root.dataset.orientation = t;
510
562
  }
511
563
  destroy() {
512
- this.control.off(C, this.handleDrawingEnd), this.control.off(E, this.handleDrawingEnd), this.control.off(S, this.handleHistory), this.root.remove();
564
+ this.control.off(x, this.handleDrawingEnd), this.control.off(P, this.handleDrawingEnd), this.control.off(M, this.handleHistory), this.root.remove();
565
+ }
566
+ }
567
+ class lt {
568
+ constructor(t, e) {
569
+ c(this, "element");
570
+ c(this, "onClick", () => {
571
+ this.item.action(this.ctx);
572
+ });
573
+ this.ctx = t, this.item = e, this.element = document.createElement("button"), this.element.type = "button", this.element.className = e.danger ? "oa-toolbar-button oa-toolbar-button-danger" : "oa-toolbar-button", this.element.dataset.tooltip = e.title, this.element.setAttribute("aria-label", e.title), this.element.innerHTML = v(e.icon, 16), this.element.addEventListener("click", this.onClick);
574
+ }
575
+ update(t) {
576
+ if (!this.item.isActive) return;
577
+ const e = this.item.isActive(t);
578
+ this.element.classList.toggle("active", e), this.element.setAttribute("aria-pressed", String(e));
579
+ }
580
+ destroy() {
581
+ this.element.removeEventListener("click", this.onClick);
582
+ }
583
+ }
584
+ function I(s, t) {
585
+ const e = document.createElement("div");
586
+ e.className = "oa-toolbar-dropdown";
587
+ const o = document.createElement("button");
588
+ o.type = "button", o.className = "oa-toolbar-button oa-toolbar-dropdown-trigger", o.dataset.tooltip = s, o.setAttribute("aria-haspopup", "listbox"), o.setAttribute("aria-expanded", "false"), o.setAttribute("aria-label", s);
589
+ const i = document.createElement("span");
590
+ i.className = "oa-toolbar-dropdown-label", i.textContent = t;
591
+ const n = document.createElement("span");
592
+ n.className = "oa-toolbar-dropdown-chevron", n.innerHTML = v("chevron-down", 14), o.appendChild(i), o.appendChild(n);
593
+ const r = document.createElement("div");
594
+ r.className = "oa-toolbar-dropdown-panel", r.setAttribute("role", "listbox"), r.setAttribute("aria-label", `${s} options`);
595
+ const d = (a) => o.setAttribute("aria-expanded", String(a)), h = () => {
596
+ e.classList.remove("open"), d(!1);
597
+ };
598
+ return o.addEventListener("click", (a) => {
599
+ var u;
600
+ a.stopPropagation();
601
+ const l = !e.classList.contains("open");
602
+ (u = e.closest(".annotation-style-toolbar")) == null || u.querySelectorAll(".oa-toolbar-dropdown.open").forEach((m) => {
603
+ var b;
604
+ m !== e && (m.classList.remove("open"), (b = m.querySelector(".oa-toolbar-dropdown-trigger")) == null || b.setAttribute("aria-expanded", "false"));
605
+ }), e.classList.toggle("open", l), d(l);
606
+ }), e.appendChild(o), e.appendChild(r), {
607
+ element: e,
608
+ panel: r,
609
+ close: h,
610
+ setLabel: (a) => {
611
+ i.textContent = a, o.setAttribute("aria-label", `${s}: ${a || t}`);
612
+ }
613
+ };
614
+ }
615
+ class ct {
616
+ constructor(t, e) {
617
+ c(this, "element");
618
+ c(this, "dropdown");
619
+ c(this, "optionElements", []);
620
+ this.ctx = t, this.item = e, this.dropdown = I(e.title, ""), this.element = this.dropdown.element, e.options.forEach((o) => {
621
+ const i = document.createElement("button");
622
+ i.type = "button", i.className = "oa-toolbar-dropdown-option", i.setAttribute("role", "option"), i.setAttribute("aria-selected", "false"), i.textContent = o.label, o.style && Object.assign(i.style, o.style), i.addEventListener("click", (n) => {
623
+ n.stopPropagation(), e.onSelect(o.value, this.ctx), this.dropdown.close();
624
+ }), this.dropdown.panel.appendChild(i), this.optionElements.push(i);
625
+ });
626
+ }
627
+ update(t) {
628
+ const e = this.item.getValue(t), o = this.item.options.find((n) => n.value === e), i = this.item.getLabel ? this.item.getLabel(e, t) : (o == null ? void 0 : o.label) ?? `${e}`;
629
+ this.dropdown.setLabel(i), this.element.title = (o == null ? void 0 : o.label) ?? `${e}`, this.optionElements.forEach((n, r) => {
630
+ n.setAttribute(
631
+ "aria-selected",
632
+ String(this.item.options[r].value === e)
633
+ );
634
+ });
635
+ }
636
+ destroy() {
637
+ }
638
+ }
639
+ const dt = 12;
640
+ class ht {
641
+ constructor(t, e) {
642
+ c(this, "control");
643
+ c(this, "ogma");
644
+ c(this, "options");
645
+ c(this, "annotationId");
646
+ c(this, "overlay");
647
+ /** The element handed to `addOverlay` - Ogma writes its own
648
+ * `style.transform` (translate/rotate/scale, recomputed on every
649
+ * viewChanged/zoom/rotate/move) directly onto this node to place it at
650
+ * `position`, so nothing of ours may also set `transform` here or Ogma's
651
+ * assignment clobbers it (inline style, last writer wins - there's no way
652
+ * to compose two separate `transform` writers on one element). Zero-size
653
+ * and otherwise unstyled; it exists purely as the anchor point. */
654
+ c(this, "anchor");
655
+ /** The actual visible pill - a child of `anchor`, `position: absolute`
656
+ * with its own `transform: translate(-50%, -100%)` (see `styles.css`) to
657
+ * center horizontally and sit fully above the anchor point. This is where
658
+ * our own positioning lives, kept off `anchor` for exactly that reason. */
659
+ c(this, "root");
660
+ c(this, "cells", []);
661
+ c(this, "documentClickHandler", (t) => {
662
+ this.root.contains(t.target) || this.root.querySelectorAll(".oa-toolbar-dropdown.open").forEach((e) => e.classList.remove("open"));
663
+ });
664
+ this.control = t.control, this.options = t, this.ogma = this.control.getOgma(), this.annotationId = e.id, this.anchor = document.createElement("div"), this.anchor.className = "annotation-style-toolbar-anchor", this.root = document.createElement("div"), this.root.className = "annotation-style-toolbar oa-toolbar oa-toolbar-bar", this.root.setAttribute("role", "group"), this.root.setAttribute("aria-label", "Text style toolbar"), this.anchor.appendChild(this.root), ["click", "mousedown", "mousemove"].forEach(
665
+ (i) => this.root.addEventListener(i, (n) => n.stopPropagation())
666
+ );
667
+ const o = {
668
+ getAnnotation: () => this.control.getAnnotation(this.annotationId),
669
+ updateStyle: (i) => this.control.updateStyle(this.annotationId, i),
670
+ deleteAnnotation: () => {
671
+ const i = this.control.getAnnotation(this.annotationId);
672
+ i && this.control.remove(i);
673
+ }
674
+ };
675
+ this.setItems(this.getItems(o), o), this.cells.forEach((i) => i.update(e)), this.overlay = this.ogma.layers.addOverlay({
676
+ element: this.anchor,
677
+ position: this.getAnchor(e),
678
+ scaled: !1
679
+ }), document.addEventListener("click", this.documentClickHandler);
680
+ }
681
+ /** Turns one `ToolbarItem` into its `ToolbarCell` - `"separator"` has
682
+ * none (handled by `setItems` directly), `"custom"` calls its own
683
+ * `build()` (the color picker's escape hatch), `"button"`/`"dropdown"`
684
+ * go through the two generic cell classes. */
685
+ buildCell(t, e) {
686
+ switch (t.kind) {
687
+ case "separator":
688
+ return null;
689
+ case "custom":
690
+ return t.build(e);
691
+ case "button":
692
+ return new lt(e, t);
693
+ case "dropdown":
694
+ return new ct(e, t);
695
+ }
696
+ }
697
+ setItems(t, e) {
698
+ this.cells = [], t.forEach((o) => {
699
+ if (o.kind === "separator") {
700
+ const n = document.createElement("span");
701
+ n.className = "oa-toolbar-separator", this.root.appendChild(n);
702
+ return;
703
+ }
704
+ const i = this.buildCell(o, e);
705
+ this.cells.push(i), this.root.appendChild(i.element);
706
+ });
707
+ }
708
+ /**
709
+ * Top-center of the annotation's box, in graph space, offset outward by
710
+ * `ANCHOR_GAP` (screen-constant, so divided by zoom) and rotated by the
711
+ * global annotation-rotation angle - the same `ctx.rotate(rotation)`
712
+ * transform `Handles.renderOutline` applies to a Text box's outline, so
713
+ * the pill tracks the box exactly as it visually rotates.
714
+ */
715
+ getAnchor(t) {
716
+ var l;
717
+ const e = this.control.getZoom(), o = this.control.getRotation(), i = ((l = t.properties.style) == null ? void 0 : l.fixedSize) === !0;
718
+ let { height: n } = q(t);
719
+ i && (n /= e);
720
+ const r = W(t), d = -(n / 2 + dt / e), h = Math.sin(o), a = Math.cos(o);
721
+ return {
722
+ x: r.x - d * h,
723
+ y: r.y + d * a
724
+ };
725
+ }
726
+ /** Refreshes every cell and repositions the pill for `annotation` -
727
+ * called after a select, an own-cell edit, or an external update to the
728
+ * same annotation. Does not rebuild cells; the host recreates the whole
729
+ * instance when the annotation identity/kind changes. */
730
+ update(t) {
731
+ this.cells.forEach((e) => e.update(t)), this.overlay.setPosition(this.getAnchor(t));
732
+ }
733
+ destroy() {
734
+ document.removeEventListener("click", this.documentClickHandler), this.cells.forEach((t) => t.destroy()), this.overlay.destroy();
735
+ }
736
+ }
737
+ class ut {
738
+ constructor(t, e) {
739
+ c(this, "element");
740
+ c(this, "dropdown");
741
+ c(this, "swatch");
742
+ c(this, "more");
743
+ c(this, "morePicker", null);
744
+ c(this, "morePickerHost", null);
745
+ this.ctx = t, this.options = e;
746
+ const { swatches: o } = e;
747
+ this.dropdown = I("Color", ""), this.element = this.dropdown.element, this.element.classList.add("oa-toolbar-color-cell"), this.swatch = document.createElement("span"), this.swatch.className = "oa-toolbar-swatch", this.dropdown.element.querySelector(".oa-toolbar-dropdown-trigger").insertBefore(this.swatch, this.dropdown.element.querySelector(".oa-toolbar-dropdown-label"));
748
+ const i = document.createElement("div");
749
+ i.className = "oa-toolbar-swatch-grid", o.forEach((n) => {
750
+ const r = document.createElement("button");
751
+ r.type = "button", r.className = "oa-toolbar-swatch-cell", r.classList.toggle("oa-toolbar-swatch-cell-transparent", n.fill === "transparent"), r.title = n.fill, r.setAttribute(
752
+ "aria-label",
753
+ n.fill === "transparent" ? "No background" : `Background ${n.fill}`
754
+ ), r.style.setProperty("--oa-swatch-fill", n.fill), r.style.setProperty("--oa-swatch-stroke", n.stroke), r.addEventListener("click", (d) => {
755
+ d.stopPropagation(), this.pick(n.fill), this.dropdown.close();
756
+ }), i.appendChild(r);
757
+ }), this.dropdown.panel.appendChild(i), this.more = document.createElement("button"), this.more.type = "button", this.more.className = "oa-toolbar-more-colors", this.more.textContent = "More colors…", this.more.addEventListener("click", (n) => {
758
+ n.stopPropagation(), this.openMorePicker();
759
+ }), this.dropdown.panel.appendChild(this.more);
760
+ }
761
+ pick(t) {
762
+ this.ctx.updateStyle({ background: t });
763
+ }
764
+ openMorePicker() {
765
+ var e;
766
+ if (this.options.onMoreColors) {
767
+ this.dropdown.close(), this.options.onMoreColors(this.ctx, this.more);
768
+ return;
769
+ }
770
+ if (this.morePickerHost) {
771
+ this.closeMorePicker();
772
+ return;
773
+ }
774
+ this.morePickerHost = document.createElement("div"), this.morePickerHost.className = "oa-toolbar-more-colors-host", this.morePicker = N();
775
+ const t = ((e = this.ctx.getAnnotation().properties.style) == null ? void 0 : e.background) || y.background;
776
+ this.morePicker.color = F(t), this.morePicker.addEventListener("color-changed", (o) => {
777
+ this.pick(O(o.detail.value));
778
+ }), this.morePickerHost.appendChild(this.morePicker), this.dropdown.panel.appendChild(this.morePickerHost);
779
+ }
780
+ closeMorePicker() {
781
+ var t;
782
+ (t = this.morePickerHost) == null || t.remove(), this.morePickerHost = null, this.morePicker = null;
783
+ }
784
+ update(t) {
785
+ var o;
786
+ const e = ((o = t.properties.style) == null ? void 0 : o.background) || y.background;
787
+ this.swatch.style.setProperty("--oa-swatch-fill", e), this.swatch.classList.toggle("oa-toolbar-swatch-transparent", e === "transparent");
788
+ }
789
+ destroy() {
790
+ this.closeMorePicker();
791
+ }
792
+ }
793
+ const pt = [
794
+ { fill: "#FFE49B", stroke: "#D9A926" },
795
+ { fill: "#FFC8A7", stroke: "#CC8C66" },
796
+ { fill: "#FFA7B5", stroke: "#C2707D" },
797
+ { fill: "#D9F3B0", stroke: "#A2C270" },
798
+ { fill: "#C7F7EF", stroke: "#8CD9CC" },
799
+ { fill: "#99D6FF", stroke: "#5CA5D6" },
800
+ { fill: "#D1C7FA", stroke: "#9B8CD9" },
801
+ { fill: "#C3DAFE", stroke: "#668ECC" },
802
+ { fill: "transparent", stroke: "#CCCCCC" }
803
+ ], mt = [
804
+ { value: "sans-serif", label: "Sans Serif" },
805
+ { value: "serif", label: "Serif", style: { fontFamily: "serif" } },
806
+ { value: "monospace", label: "Monospace", style: { fontFamily: "monospace" } },
807
+ {
808
+ value: "IBM Plex Sans",
809
+ label: "IBM Plex Sans",
810
+ style: { fontFamily: "IBM Plex Sans" }
811
+ },
812
+ {
813
+ value: "IBM Plex Mono",
814
+ label: "IBM Plex Mono",
815
+ style: { fontFamily: "IBM Plex Mono" }
816
+ }
817
+ ], bt = [12, 14, 16, 18, 24, 32, 48, 64];
818
+ class H extends ht {
819
+ getItems(t) {
820
+ var d, h;
821
+ const e = this.options.fonts ?? mt, o = this.options.fontSizes ?? bt, i = this.options.swatches ?? pt, n = this.options.onMoreColors, r = [
822
+ {
823
+ kind: "custom",
824
+ id: "color",
825
+ build: (a) => new ut(a, { swatches: i, onMoreColors: n })
826
+ },
827
+ { kind: "separator" },
828
+ {
829
+ kind: "dropdown",
830
+ id: "font",
831
+ title: "Font",
832
+ options: e,
833
+ getValue: (a) => {
834
+ var l;
835
+ return ((l = a.properties.style) == null ? void 0 : l.font) || y.font;
836
+ },
837
+ getLabel: () => "Aa",
838
+ // `fonts` entries are always string values (font-family names) -
839
+ // ToolbarDropdownValue is string | number only because the size
840
+ // cell also uses this same item shape with numbers.
841
+ onSelect: (a, l) => l.updateStyle({ font: `${a}` })
842
+ },
843
+ {
844
+ kind: "dropdown",
845
+ id: "fontSize",
846
+ title: "Font size",
847
+ options: o.map((a) => ({ value: a, label: `${a}` })),
848
+ getValue: (a) => {
849
+ const l = a.properties.style;
850
+ return Math.round(
851
+ V(
852
+ (l == null ? void 0 : l.fontSize) ?? y.fontSize,
853
+ l == null ? void 0 : l.fontScale
854
+ )
855
+ );
856
+ },
857
+ // Setting fontSize directly (not fontScale) resets any accumulated
858
+ // resize-driven scale, matching what picking an explicit size means.
859
+ onSelect: (a, l) => l.updateStyle({ fontSize: a, fontScale: 1 })
860
+ },
861
+ { kind: "separator" },
862
+ {
863
+ kind: "button",
864
+ id: "bold",
865
+ title: "Bold",
866
+ icon: "bold",
867
+ isActive: (a) => {
868
+ var l;
869
+ return ((l = a.properties.style) == null ? void 0 : l.fontWeight) === "bold";
870
+ },
871
+ action: (a) => {
872
+ var u;
873
+ const l = ((u = a.getAnnotation().properties.style) == null ? void 0 : u.fontWeight) === "bold";
874
+ a.updateStyle({ fontWeight: l ? "normal" : "bold" });
875
+ }
876
+ },
877
+ { kind: "separator" },
878
+ {
879
+ kind: "button",
880
+ id: "showAuthor",
881
+ title: "Show author",
882
+ icon: "user",
883
+ isActive: (a) => {
884
+ var l;
885
+ return ((l = a.properties.style) == null ? void 0 : l.showAuthor) === !0;
886
+ },
887
+ action: (a) => {
888
+ var u;
889
+ const l = ((u = a.getAnnotation().properties.style) == null ? void 0 : u.showAuthor) === !0;
890
+ a.updateStyle({ showAuthor: !l });
891
+ }
892
+ },
893
+ { kind: "separator" },
894
+ {
895
+ kind: "button",
896
+ id: "delete",
897
+ title: "Delete",
898
+ icon: "trash",
899
+ danger: !0,
900
+ action: (a) => a.deleteAnnotation()
901
+ }
902
+ ];
903
+ return ((h = (d = this.options).items) == null ? void 0 : h.call(d, r, t)) ?? r;
904
+ }
905
+ }
906
+ class yt extends H {
907
+ }
908
+ class Ct {
909
+ constructor(t) {
910
+ c(this, "control");
911
+ c(this, "options");
912
+ c(this, "current", null);
913
+ c(this, "detachVisibility");
914
+ c(this, "handleUpdate", (t) => {
915
+ this.current && t.id === this.current.annotationId && k(t) && this.current.update(t);
916
+ });
917
+ this.control = t.control, this.options = t, this.detachVisibility = D(this.control, {
918
+ onShow: (e) => this.show(e),
919
+ onHide: () => this.hide(),
920
+ hideWhenNotEditable: t.hideWhenNotEditable
921
+ }), this.control.on($, this.handleUpdate);
922
+ }
923
+ show(t) {
924
+ if (!k(t)) {
925
+ this.hide();
926
+ return;
927
+ }
928
+ const e = U(t) ? yt : H;
929
+ if (this.current && this.current.annotationId === t.id && this.current instanceof e) {
930
+ this.current.update(t);
931
+ return;
932
+ }
933
+ this.hide(), this.current = new e(this.options, t);
934
+ }
935
+ hide() {
936
+ var t;
937
+ (t = this.current) == null || t.destroy(), this.current = null;
938
+ }
939
+ destroy() {
940
+ this.detachVisibility(), this.control.off($, this.handleUpdate), this.hide();
513
941
  }
514
942
  }
515
943
  export {
516
- Z as AnnotationPanel,
517
- tt as AnnotationToolbar,
518
- O as BACKGROUNDS,
519
- Y as DEFAULT_PANEL_ORIENTATION,
520
- G as DEFAULT_PANEL_PLACEMENT,
521
- H as DEFAULT_RECENT_COLORS,
522
- N as EXTREMITY_OPTIONS,
523
- m as FONTS,
524
- W as ICON_PATHS,
525
- R as LINE_TYPES,
526
- _ as MAX_RECENT_COLORS,
527
- U as attachPanelVisibility,
528
- F as createRgbaColorPicker,
529
- z as initialRecentColors,
530
- I as rgbaToString,
944
+ nt as ALL_PANEL_ANNOTATION_TYPES,
945
+ kt as AnnotationPanel,
946
+ ht as AnnotationStyleToolbar,
947
+ At as AnnotationToolbar,
948
+ j as BACKGROUNDS,
949
+ lt as ButtonItemCell,
950
+ ut as ColorCell,
951
+ it as DEFAULT_PANEL_ORIENTATION,
952
+ ot as DEFAULT_PANEL_PLACEMENT,
953
+ J as DEFAULT_RECENT_COLORS,
954
+ mt as DEFAULT_TOOLBAR_FONTS,
955
+ bt as DEFAULT_TOOLBAR_FONT_SIZES,
956
+ ct as DropdownItemCell,
957
+ G as EXTREMITY_OPTIONS,
958
+ C as FONTS,
959
+ tt as ICON_PATHS,
960
+ X as LINE_TYPES,
961
+ K as MAX_RECENT_COLORS,
962
+ pt as STICKY_SWATCHES,
963
+ yt as StickyNoteStyleToolbar,
964
+ Ct as TextAnnotationToolbar,
965
+ H as TextStyleToolbar,
966
+ D as attachPanelVisibility,
967
+ rt as classifyPanelAnnotationType,
968
+ N as createRgbaColorPicker,
969
+ Z as initialRecentColors,
970
+ O as rgbaToString,
531
971
  v as svgIcon,
532
- q as withColorFromAnnotation
972
+ Q as withColorFromAnnotation
533
973
  };