@liwe3/webcomponents 1.1.0 → 1.1.10

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.
Files changed (56) hide show
  1. package/dist/AIMarkdownEditor.d.ts +35 -0
  2. package/dist/AIMarkdownEditor.d.ts.map +1 -0
  3. package/dist/AIMarkdownEditor.js +412 -0
  4. package/dist/AIMarkdownEditor.js.map +1 -0
  5. package/dist/AITextEditor.d.ts +10 -0
  6. package/dist/AITextEditor.d.ts.map +1 -1
  7. package/dist/AITextEditor.js +63 -27
  8. package/dist/AITextEditor.js.map +1 -1
  9. package/dist/ButtonToolbar.d.ts +35 -0
  10. package/dist/ButtonToolbar.d.ts.map +1 -0
  11. package/dist/ButtonToolbar.js +220 -0
  12. package/dist/ButtonToolbar.js.map +1 -0
  13. package/dist/CheckList.d.ts +31 -0
  14. package/dist/CheckList.d.ts.map +1 -0
  15. package/dist/CheckList.js +336 -0
  16. package/dist/CheckList.js.map +1 -0
  17. package/dist/ChunkUploader.d.ts +22 -0
  18. package/dist/ChunkUploader.d.ts.map +1 -1
  19. package/dist/ChunkUploader.js +245 -103
  20. package/dist/ChunkUploader.js.map +1 -1
  21. package/dist/ComicBalloon.d.ts +82 -0
  22. package/dist/ComicBalloon.d.ts.map +1 -0
  23. package/dist/ComicBalloon.js +346 -0
  24. package/dist/ComicBalloon.js.map +1 -0
  25. package/dist/Dialog.d.ts +102 -0
  26. package/dist/Dialog.d.ts.map +1 -0
  27. package/dist/Dialog.js +299 -0
  28. package/dist/Dialog.js.map +1 -0
  29. package/dist/MarkdownPreview.d.ts +25 -0
  30. package/dist/MarkdownPreview.d.ts.map +1 -0
  31. package/dist/MarkdownPreview.js +147 -0
  32. package/dist/MarkdownPreview.js.map +1 -0
  33. package/dist/ResizableCropper.d.ts +158 -0
  34. package/dist/ResizableCropper.d.ts.map +1 -0
  35. package/dist/ResizableCropper.js +562 -0
  36. package/dist/ResizableCropper.js.map +1 -0
  37. package/dist/SmartSelect.d.ts +1 -0
  38. package/dist/SmartSelect.d.ts.map +1 -1
  39. package/dist/SmartSelect.js +45 -2
  40. package/dist/SmartSelect.js.map +1 -1
  41. package/dist/index.d.ts +16 -9
  42. package/dist/index.d.ts.map +1 -1
  43. package/dist/index.js +52 -29
  44. package/dist/index.js.map +1 -1
  45. package/package.json +33 -3
  46. package/src/AIMarkdownEditor.ts +568 -0
  47. package/src/AITextEditor.ts +97 -2
  48. package/src/ButtonToolbar.ts +302 -0
  49. package/src/CheckList.ts +438 -0
  50. package/src/ChunkUploader.ts +837 -623
  51. package/src/ComicBalloon.ts +709 -0
  52. package/src/Dialog.ts +510 -0
  53. package/src/MarkdownPreview.ts +213 -0
  54. package/src/ResizableCropper.ts +1099 -0
  55. package/src/SmartSelect.ts +48 -2
  56. package/src/index.ts +110 -47
@@ -0,0 +1,346 @@
1
+ var D = /* @__PURE__ */ ((g) => (g.TALK = "talk", g.CLOUD = "cloud", g.WHISPER = "whisper", g.RECTANGLE = "rectangle", g))(D || {});
2
+ class T extends HTMLElement {
3
+ constructor() {
4
+ super(), this._type = "talk", this._handlerPosition = { x: 50, y: 100 }, this.isDragging = !1, this.isResizing = !1, this.dragStartOffset = { x: 0, y: 0 }, this.resizeStartPos = { x: 0, y: 0 }, this.attachShadow({ mode: "open" });
5
+ }
6
+ static get observedAttributes() {
7
+ return ["type", "text"];
8
+ }
9
+ connectedCallback() {
10
+ this.render(), this.setupEventListeners();
11
+ }
12
+ disconnectedCallback() {
13
+ this.removeEventListeners();
14
+ }
15
+ attributeChangedCallback(t, e, n) {
16
+ e !== n && (t === "type" ? (this._type = n || "talk", this.updateBalloonStyle()) : t === "text" && this.contentEditableElement && (this.contentEditableElement.textContent = n));
17
+ }
18
+ get type() {
19
+ return this._type;
20
+ }
21
+ set type(t) {
22
+ this._type = t, this.setAttribute("type", t);
23
+ }
24
+ get handlerPosition() {
25
+ return { ...this._handlerPosition };
26
+ }
27
+ set handlerPosition(t) {
28
+ this._handlerPosition = { ...t }, this.updateHandlerVisual();
29
+ }
30
+ updateHandlerPosition(t) {
31
+ this.handlerPosition = t;
32
+ }
33
+ getHTML() {
34
+ return this.outerHTML;
35
+ }
36
+ render() {
37
+ this.shadowRoot.innerHTML = `
38
+ <style>${this.getStyles()}</style>
39
+ <div class="comic-balloon-container">
40
+ <svg class="balloon-svg" xmlns="http://www.w3.org/2000/svg">
41
+ <g class="cloud-shape"></g>
42
+ </svg>
43
+ <div class="balloon ${this._type}">
44
+ <div class="content" contenteditable="true" role="textbox" aria-label="Balloon text">
45
+ ${this.getAttribute("text") || "Type your text here..."}
46
+ </div>
47
+ <div class="resize-handle" role="button" aria-label="Resize balloon"></div>
48
+ </div>
49
+ <div class="handler ${this._type}" role="button" aria-label="Drag to reposition pointer"></div>
50
+ </div>
51
+ `, this.contentEditableElement = this.shadowRoot.querySelector(".content"), this.handler = this.shadowRoot.querySelector(".handler"), this.resizeHandle = this.shadowRoot.querySelector(".resize-handle"), this.balloon = this.shadowRoot.querySelector(".balloon"), this._type === "cloud" && this.updateCloudShape(), this.updateHandlerVisual();
52
+ }
53
+ getStyles() {
54
+ return `
55
+ :host {
56
+ display: inline-block;
57
+ position: relative;
58
+ width: 300px;
59
+ min-height: 150px;
60
+ overflow: visible;
61
+ }
62
+
63
+ .comic-balloon-container {
64
+ position: relative;
65
+ width: 100%;
66
+ height: 100%;
67
+ padding: 50px;
68
+ margin: -50px;
69
+ }
70
+
71
+ .balloon-svg {
72
+ position: absolute;
73
+ top: 0;
74
+ left: 0;
75
+ width: 100%;
76
+ height: 100%;
77
+ pointer-events: none;
78
+ z-index: 1;
79
+ overflow: visible;
80
+ }
81
+
82
+ .balloon {
83
+ position: relative;
84
+ padding: 20px;
85
+ background: white;
86
+ border: 3px solid #000;
87
+ min-height: 100px;
88
+ z-index: 2;
89
+ margin: 50px;
90
+ width: calc(100% - 100px);
91
+ height: calc(100% - 100px);
92
+ box-sizing: border-box;
93
+ }
94
+
95
+ .balloon.talk {
96
+ border-radius: 25px;
97
+ }
98
+
99
+ .balloon.cloud {
100
+ border: none;
101
+ background: transparent;
102
+ position: relative;
103
+ }
104
+
105
+ .balloon.cloud .content {
106
+ position: relative;
107
+ z-index: 10;
108
+ }
109
+
110
+ .balloon.whisper {
111
+ border-radius: 25px;
112
+ border: 3px dashed #000;
113
+ }
114
+
115
+ .balloon.rectangle {
116
+ border-radius: 5px;
117
+ }
118
+
119
+ .content {
120
+ outline: none;
121
+ min-height: 60px;
122
+ font-family: 'Comic Sans MS', cursive, sans-serif;
123
+ font-size: 16px;
124
+ line-height: 1.4;
125
+ color: #000;
126
+ display: flex;
127
+ align-items: center;
128
+ justify-content: center;
129
+ text-align: center;
130
+ }
131
+
132
+ .content:empty:before {
133
+ content: attr(aria-label);
134
+ color: #999;
135
+ }
136
+
137
+ .handler {
138
+ position: absolute;
139
+ width: 20px;
140
+ height: 20px;
141
+ cursor: move;
142
+ z-index: 3;
143
+ user-select: none;
144
+ background: rgba(0, 0, 0, 0.1);
145
+ border-radius: 50%;
146
+ border: 2px solid rgba(0, 0, 0, 0.3);
147
+ }
148
+
149
+ .handler:hover {
150
+ background: rgba(0, 0, 0, 0.2);
151
+ border-color: rgba(0, 0, 0, 0.5);
152
+ }
153
+
154
+ .handler.dragging {
155
+ cursor: grabbing;
156
+ background: rgba(0, 0, 0, 0.3);
157
+ }
158
+
159
+ .resize-handle {
160
+ position: absolute;
161
+ bottom: 0;
162
+ right: 0;
163
+ width: 20px;
164
+ height: 20px;
165
+ cursor: nwse-resize;
166
+ z-index: 4;
167
+ background: linear-gradient(135deg, transparent 50%, rgba(102, 126, 234, 0.5) 50%);
168
+ border-bottom-right-radius: inherit;
169
+ }
170
+
171
+ .resize-handle:hover {
172
+ background: linear-gradient(135deg, transparent 50%, rgba(102, 126, 234, 0.8) 50%);
173
+ }
174
+
175
+ .resize-handle.resizing {
176
+ background: linear-gradient(135deg, transparent 50%, rgba(102, 126, 234, 1) 50%);
177
+ }
178
+ `;
179
+ }
180
+ updateBalloonStyle() {
181
+ !this.balloon || !this.handler || (this.balloon.className = `balloon ${this._type}`, this.handler.className = `handler ${this._type}`, this._type === "cloud" && this.updateCloudShape(), this.updateHandlerVisual());
182
+ }
183
+ updateCloudShape() {
184
+ if (!this.balloon) return;
185
+ const t = this.shadowRoot.querySelector(".cloud-shape");
186
+ if (!t) return;
187
+ const e = this.balloon.getBoundingClientRect(), n = this.shadowRoot.querySelector(".comic-balloon-container")?.getBoundingClientRect();
188
+ if (!n) return;
189
+ const s = e.left - n.left, o = e.top - n.top, d = e.width, r = e.height;
190
+ t.innerHTML = "";
191
+ const l = s + d / 2, h = o + r / 2, c = 14, p = d / 2.5, b = r / 2.5;
192
+ let u = "";
193
+ for (let i = 0; i <= c; i++) {
194
+ const m = i / c * Math.PI * 2 - Math.PI / 2, M = (i + 1) / c * Math.PI * 2 - Math.PI / 2, v = l + Math.cos(m) * p, w = h + Math.sin(m) * b, f = l + Math.cos(M) * p, y = h + Math.sin(M) * b, z = (v + f) / 2, L = (w + y) / 2, R = f - v, S = y - w, k = Math.sqrt(R * R + S * S), x = z - l, E = L - h, C = Math.sqrt(x * x + E * E), A = x / C, _ = E / C, P = k * 0.8, $ = z + A * P, H = L + _ * P;
195
+ i === 0 && (u += `M ${v} ${w} `), u += `Q ${$} ${H} ${f} ${y} `;
196
+ }
197
+ u += "Z";
198
+ const a = document.createElementNS("http://www.w3.org/2000/svg", "path");
199
+ a.setAttribute("d", u), a.setAttribute("fill", "white"), a.setAttribute("stroke", "#000"), a.setAttribute("stroke-width", "3"), a.setAttribute("stroke-linejoin", "round"), t.appendChild(a);
200
+ }
201
+ updateHandlerVisual() {
202
+ if (!this.handler || !this.balloon) return;
203
+ const t = this._handlerPosition.x, e = this._handlerPosition.y;
204
+ this.handler.style.left = `${t - 10}px`, this.handler.style.top = `${e - 10}px`, this._type === "cloud" && this.updateCloudShape(), this.updateSVGPointer();
205
+ }
206
+ updateSVGPointer() {
207
+ const t = this.shadowRoot.querySelector(".balloon-svg");
208
+ if (!t || !this.balloon) return;
209
+ const e = this.balloon.getBoundingClientRect(), n = t.getBoundingClientRect();
210
+ let s = t.querySelector(".pointer-group");
211
+ s || (s = document.createElementNS("http://www.w3.org/2000/svg", "g"), s.setAttribute("class", "pointer-group"), t.appendChild(s)), s.innerHTML = "";
212
+ const o = e.left - n.left, d = e.top - n.top, r = o + e.width / 2, l = d + e.height / 2, h = this._handlerPosition.x, c = this._handlerPosition.y, p = Math.atan2(c - l, h - r), b = e.width / 2, u = e.height / 2, a = r + Math.cos(p) * b * 0.85, i = l + Math.sin(p) * u * 0.85;
213
+ this._type === "talk" || this._type === "rectangle" ? this.drawTalkPointer(s, a, i, h, c) : this._type === "cloud" ? this.drawCloudPointer(s, a, i, h, c) : this._type === "whisper" && this.drawWhisperPointer(s, a, i, h, c);
214
+ }
215
+ drawTalkPointer(t, e, n, s, o) {
216
+ const r = Math.atan2(o - n, s - e) + Math.PI / 2, l = 20, h = e + Math.cos(r) * l / 2, c = n + Math.sin(r) * l / 2, p = e - Math.cos(r) * l / 2, b = n - Math.sin(r) * l / 2, u = s, a = o, i = document.createElementNS("http://www.w3.org/2000/svg", "path"), m = `M ${h} ${c} L ${u} ${a} L ${p} ${b} Z`;
217
+ i.setAttribute("d", m), i.setAttribute("fill", "white"), i.setAttribute("stroke", "#000"), i.setAttribute("stroke-width", "3"), i.setAttribute("stroke-linejoin", "round"), t.appendChild(i);
218
+ }
219
+ drawCloudPointer(t, e, n, s, o) {
220
+ const d = s - e, r = o - n, l = 3;
221
+ for (let h = 0; h < l; h++) {
222
+ const c = (h + 1) / (l + 1), p = e + d * c, b = n + r * c, u = 8 - h * 2, a = document.createElementNS("http://www.w3.org/2000/svg", "circle");
223
+ a.setAttribute("cx", p.toString()), a.setAttribute("cy", b.toString()), a.setAttribute("r", u.toString()), a.setAttribute("fill", "white"), a.setAttribute("stroke", "#000"), a.setAttribute("stroke-width", "2"), t.appendChild(a);
224
+ }
225
+ }
226
+ drawWhisperPointer(t, e, n, s, o) {
227
+ const r = Math.atan2(o - n, s - e) + Math.PI / 2, l = 20, h = e + Math.cos(r) * l / 2, c = n + Math.sin(r) * l / 2, p = e - Math.cos(r) * l / 2, b = n - Math.sin(r) * l / 2, u = s, a = o, i = document.createElementNS("http://www.w3.org/2000/svg", "path"), m = `M ${h} ${c} L ${u} ${a} L ${p} ${b}`;
228
+ i.setAttribute("d", m), i.setAttribute("fill", "none"), i.setAttribute("stroke", "#000"), i.setAttribute("stroke-width", "3"), i.setAttribute("stroke-dasharray", "10 5"), i.setAttribute("stroke-linejoin", "round"), i.setAttribute("stroke-linecap", "round"), t.appendChild(i);
229
+ }
230
+ setupEventListeners() {
231
+ this.handler && (this.handler.addEventListener("mousedown", this.handleMouseDown.bind(this)), this.handler.addEventListener("touchstart", this.handleTouchStart.bind(this), { passive: !1 }), this.resizeHandle && (this.resizeHandle.addEventListener("mousedown", this.handleResizeMouseDown.bind(this)), this.resizeHandle.addEventListener("touchstart", this.handleResizeTouchStart.bind(this), { passive: !1 })), this.contentEditableElement && this.contentEditableElement.addEventListener("blur", this.handleContentBlur.bind(this)));
232
+ }
233
+ removeEventListeners() {
234
+ this.handler && (this.handler.removeEventListener("mousedown", this.handleMouseDown.bind(this)), this.handler.removeEventListener("touchstart", this.handleTouchStart.bind(this)), this.resizeHandle && (this.resizeHandle.removeEventListener("mousedown", this.handleResizeMouseDown.bind(this)), this.resizeHandle.removeEventListener("touchstart", this.handleResizeTouchStart.bind(this))), this.contentEditableElement && this.contentEditableElement.removeEventListener("blur", this.handleContentBlur.bind(this)));
235
+ }
236
+ handleMouseDown(t) {
237
+ t.preventDefault(), this.startDrag(t.clientX, t.clientY);
238
+ const e = (s) => this.handleDrag(s.clientX, s.clientY), n = () => {
239
+ this.stopDrag(), document.removeEventListener("mousemove", e), document.removeEventListener("mouseup", n);
240
+ };
241
+ document.addEventListener("mousemove", e), document.addEventListener("mouseup", n);
242
+ }
243
+ handleTouchStart(t) {
244
+ t.preventDefault();
245
+ const e = t.touches[0];
246
+ this.startDrag(e.clientX, e.clientY);
247
+ const n = (o) => {
248
+ const d = o.touches[0];
249
+ this.handleDrag(d.clientX, d.clientY);
250
+ }, s = () => {
251
+ this.stopDrag(), document.removeEventListener("touchmove", n), document.removeEventListener("touchend", s);
252
+ };
253
+ document.addEventListener("touchmove", n, { passive: !1 }), document.addEventListener("touchend", s);
254
+ }
255
+ startDrag(t, e) {
256
+ this.isDragging = !0, this.handler && this.handler.classList.add("dragging");
257
+ const n = this.shadowRoot.querySelector(".comic-balloon-container")?.getBoundingClientRect();
258
+ n && (this.dragStartOffset = {
259
+ x: t - n.left - this._handlerPosition.x,
260
+ y: e - n.top - this._handlerPosition.y
261
+ });
262
+ }
263
+ handleDrag(t, e) {
264
+ if (!this.isDragging) return;
265
+ const n = this.shadowRoot.querySelector(".comic-balloon-container")?.getBoundingClientRect();
266
+ if (!n) return;
267
+ let s = t - n.left - this.dragStartOffset.x, o = e - n.top - this.dragStartOffset.y;
268
+ s = Math.max(-50, Math.min(n.width + 50, s)), o = Math.max(-50, Math.min(n.height + 50, o)), this._handlerPosition = { x: s, y: o }, this.updateHandlerVisual();
269
+ }
270
+ stopDrag() {
271
+ this.isDragging = !1, this.handler && this.handler.classList.remove("dragging"), this.dispatchEvent(new CustomEvent("handler-move", {
272
+ detail: {
273
+ finalPosition: { ...this._handlerPosition },
274
+ balloonType: this._type
275
+ },
276
+ bubbles: !0,
277
+ composed: !0
278
+ }));
279
+ }
280
+ handleContentBlur() {
281
+ this.contentEditableElement && this.dispatchEvent(new CustomEvent("balloon-content-change", {
282
+ detail: {
283
+ newContent: this.contentEditableElement.textContent || "",
284
+ balloonType: this._type
285
+ },
286
+ bubbles: !0,
287
+ composed: !0
288
+ }));
289
+ }
290
+ handleResizeMouseDown(t) {
291
+ t.preventDefault(), t.stopPropagation(), this.startResize(t.clientX, t.clientY);
292
+ const e = (s) => this.handleResize(s.clientX, s.clientY), n = () => {
293
+ this.stopResize(), document.removeEventListener("mousemove", e), document.removeEventListener("mouseup", n);
294
+ };
295
+ document.addEventListener("mousemove", e), document.addEventListener("mouseup", n);
296
+ }
297
+ handleResizeTouchStart(t) {
298
+ t.preventDefault(), t.stopPropagation();
299
+ const e = t.touches[0];
300
+ this.startResize(e.clientX, e.clientY);
301
+ const n = (o) => {
302
+ const d = o.touches[0];
303
+ this.handleResize(d.clientX, d.clientY);
304
+ }, s = () => {
305
+ this.stopResize(), document.removeEventListener("touchmove", n), document.removeEventListener("touchend", s);
306
+ };
307
+ document.addEventListener("touchmove", n, { passive: !1 }), document.addEventListener("touchend", s);
308
+ }
309
+ startResize(t, e) {
310
+ !this.balloon || !this.resizeHandle || (this.isResizing = !0, this.resizeHandle.classList.add("resizing"), this.resizeStartPos = {
311
+ x: t,
312
+ y: e
313
+ });
314
+ }
315
+ handleResize(t, e) {
316
+ if (!this.isResizing) return;
317
+ const n = t - this.resizeStartPos.x, s = e - this.resizeStartPos.y, o = this.getBoundingClientRect(), d = Math.max(150, o.width + n), r = Math.max(100, o.height + s);
318
+ this.style.width = `${d}px`, this.style.height = `${r}px`, this.resizeStartPos = {
319
+ x: t,
320
+ y: e
321
+ }, this.updateHandlerVisual();
322
+ }
323
+ stopResize() {
324
+ if (!this.isResizing || !this.balloon || !this.resizeHandle) return;
325
+ this.isResizing = !1, this.resizeHandle.classList.remove("resizing");
326
+ const t = this.balloon.getBoundingClientRect();
327
+ this.dispatchEvent(new CustomEvent("balloon-resize", {
328
+ detail: {
329
+ width: t.width,
330
+ height: t.height,
331
+ balloonType: this._type
332
+ },
333
+ bubbles: !0,
334
+ composed: !0
335
+ }));
336
+ }
337
+ }
338
+ const X = () => {
339
+ typeof window < "u" && !customElements.get("comic-balloon") && customElements.define("comic-balloon", T);
340
+ };
341
+ export {
342
+ D as BalloonType,
343
+ T as ComicBalloonElement,
344
+ X as defineComicBalloon
345
+ };
346
+ //# sourceMappingURL=ComicBalloon.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ComicBalloon.js","sources":["../src/ComicBalloon.ts"],"sourcesContent":["/**\n * ComicBalloon Web Component\n * A customizable comic balloon with different styles and draggable handler\n */\n\nexport enum BalloonType {\n\tTALK = 'talk',\n\tCLOUD = 'cloud',\n\tWHISPER = 'whisper',\n\tRECTANGLE = 'rectangle'\n}\n\nexport type HandlerPosition = {\n\tx: number;\n\ty: number;\n};\n\nexport interface IComicBalloon extends HTMLElement {\n\ttype: BalloonType;\n\ttextContent: string;\n\thandlerPosition: HandlerPosition;\n\tupdateHandlerPosition( position: HandlerPosition ): void;\n\tgetHTML(): string;\n}\n\nexport type ContentChangeEvent = CustomEvent<{\n\tnewContent: string;\n\tballoonType: BalloonType;\n}>;\n\nexport type HandlerMoveEvent = CustomEvent<{\n\tfinalPosition: HandlerPosition;\n\tballoonType: BalloonType;\n}>;\n\nexport type ResizeEvent = CustomEvent<{\n\twidth: number;\n\theight: number;\n\tballoonType: BalloonType;\n}>;\n\nexport class ComicBalloonElement extends HTMLElement implements IComicBalloon {\n\tdeclare shadowRoot: ShadowRoot;\n\tprivate _type: BalloonType = BalloonType.TALK;\n\tprivate _handlerPosition: HandlerPosition = { x: 50, y: 100 };\n\tprivate isDragging: boolean = false;\n\tprivate isResizing: boolean = false;\n\tprivate dragStartOffset: { x: number; y: number } = { x: 0, y: 0 };\n\tprivate resizeStartPos: { x: number; y: number } = { x: 0, y: 0 };\n\tprivate contentEditableElement?: HTMLDivElement;\n\tprivate handler?: HTMLElement;\n\tprivate resizeHandle?: HTMLElement;\n\tprivate balloon?: HTMLElement;\n\n\tstatic get observedAttributes(): string[] {\n\t\treturn [ 'type', 'text' ];\n\t}\n\n\tconstructor() {\n\t\tsuper();\n\t\tthis.attachShadow( { mode: 'open' } );\n\t}\n\n\tconnectedCallback(): void {\n\t\tthis.render();\n\t\tthis.setupEventListeners();\n\t}\n\n\tdisconnectedCallback(): void {\n\t\tthis.removeEventListeners();\n\t}\n\n\tattributeChangedCallback( name: string, oldValue: string, newValue: string ): void {\n\t\tif ( oldValue === newValue ) return;\n\n\t\tif ( name === 'type' ) {\n\t\t\tthis._type = ( newValue as BalloonType ) || BalloonType.TALK;\n\t\t\tthis.updateBalloonStyle();\n\t\t} else if ( name === 'text' ) {\n\t\t\tif ( this.contentEditableElement ) {\n\t\t\t\tthis.contentEditableElement.textContent = newValue;\n\t\t\t}\n\t\t}\n\t}\n\n\tget type(): BalloonType {\n\t\treturn this._type;\n\t}\n\n\tset type( value: BalloonType ) {\n\t\tthis._type = value;\n\t\tthis.setAttribute( 'type', value );\n\t}\n\n\tget handlerPosition(): HandlerPosition {\n\t\treturn { ...this._handlerPosition };\n\t}\n\n\tset handlerPosition( value: HandlerPosition ) {\n\t\tthis._handlerPosition = { ...value };\n\t\tthis.updateHandlerVisual();\n\t}\n\n\tupdateHandlerPosition( position: HandlerPosition ): void {\n\t\tthis.handlerPosition = position;\n\t}\n\n\tgetHTML(): string {\n\t\treturn this.outerHTML;\n\t}\n\n\tprivate render(): void {\n\t\tthis.shadowRoot.innerHTML = `\n\t\t\t<style>${this.getStyles()}</style>\n\t\t\t<div class=\"comic-balloon-container\">\n\t\t\t\t<svg class=\"balloon-svg\" xmlns=\"http://www.w3.org/2000/svg\">\n\t\t\t\t\t<g class=\"cloud-shape\"></g>\n\t\t\t\t</svg>\n\t\t\t\t<div class=\"balloon ${this._type}\">\n\t\t\t\t\t<div class=\"content\" contenteditable=\"true\" role=\"textbox\" aria-label=\"Balloon text\">\n\t\t\t\t\t\t${this.getAttribute( 'text' ) || 'Type your text here...'}\n\t\t\t\t\t</div>\n\t\t\t\t\t<div class=\"resize-handle\" role=\"button\" aria-label=\"Resize balloon\"></div>\n\t\t\t\t</div>\n\t\t\t\t<div class=\"handler ${this._type}\" role=\"button\" aria-label=\"Drag to reposition pointer\"></div>\n\t\t\t</div>\n\t\t`;\n\n\t\tthis.contentEditableElement = this.shadowRoot.querySelector( '.content' ) as HTMLDivElement;\n\t\tthis.handler = this.shadowRoot.querySelector( '.handler' ) as HTMLElement;\n\t\tthis.resizeHandle = this.shadowRoot.querySelector( '.resize-handle' ) as HTMLElement;\n\t\tthis.balloon = this.shadowRoot.querySelector( '.balloon' ) as HTMLElement;\n\n\t\tif ( this._type === BalloonType.CLOUD ) {\n\t\t\tthis.updateCloudShape();\n\t\t}\n\t\tthis.updateHandlerVisual();\n\t}\n\n\tprivate getStyles(): string {\n\t\treturn `\n\t\t\t:host {\n\t\t\t\tdisplay: inline-block;\n\t\t\t\tposition: relative;\n\t\t\t\twidth: 300px;\n\t\t\t\tmin-height: 150px;\n\t\t\t\toverflow: visible;\n\t\t\t}\n\n\t\t\t.comic-balloon-container {\n\t\t\t\tposition: relative;\n\t\t\t\twidth: 100%;\n\t\t\t\theight: 100%;\n\t\t\t\tpadding: 50px;\n\t\t\t\tmargin: -50px;\n\t\t\t}\n\n\t\t\t.balloon-svg {\n\t\t\t\tposition: absolute;\n\t\t\t\ttop: 0;\n\t\t\t\tleft: 0;\n\t\t\t\twidth: 100%;\n\t\t\t\theight: 100%;\n\t\t\t\tpointer-events: none;\n\t\t\t\tz-index: 1;\n\t\t\t\toverflow: visible;\n\t\t\t}\n\n\t\t\t.balloon {\n\t\t\t\tposition: relative;\n\t\t\t\tpadding: 20px;\n\t\t\t\tbackground: white;\n\t\t\t\tborder: 3px solid #000;\n\t\t\t\tmin-height: 100px;\n\t\t\t\tz-index: 2;\n\t\t\t\tmargin: 50px;\n\t\t\t\twidth: calc(100% - 100px);\n\t\t\t\theight: calc(100% - 100px);\n\t\t\t\tbox-sizing: border-box;\n\t\t\t}\n\n\t\t\t.balloon.talk {\n\t\t\t\tborder-radius: 25px;\n\t\t\t}\n\n\t\t\t.balloon.cloud {\n\t\t\t\tborder: none;\n\t\t\t\tbackground: transparent;\n\t\t\t\tposition: relative;\n\t\t\t}\n\t\t\t\n\t\t\t.balloon.cloud .content {\n\t\t\t\tposition: relative;\n\t\t\t\tz-index: 10;\n\t\t\t}\n\n\t\t\t.balloon.whisper {\n\t\t\t\tborder-radius: 25px;\n\t\t\t\tborder: 3px dashed #000;\n\t\t\t}\n\n\t\t\t.balloon.rectangle {\n\t\t\t\tborder-radius: 5px;\n\t\t\t}\n\n\t\t\t.content {\n\t\t\t\toutline: none;\n\t\t\t\tmin-height: 60px;\n\t\t\t\tfont-family: 'Comic Sans MS', cursive, sans-serif;\n\t\t\t\tfont-size: 16px;\n\t\t\t\tline-height: 1.4;\n\t\t\t\tcolor: #000;\n\t\t\t\tdisplay: flex;\n\t\t\t\talign-items: center;\n\t\t\t\tjustify-content: center;\n\t\t\t\ttext-align: center;\n\t\t\t}\n\n\t\t\t.content:empty:before {\n\t\t\t\tcontent: attr(aria-label);\n\t\t\t\tcolor: #999;\n\t\t\t}\n\n\t\t\t.handler {\n\t\t\t\tposition: absolute;\n\t\t\t\twidth: 20px;\n\t\t\t\theight: 20px;\n\t\t\t\tcursor: move;\n\t\t\t\tz-index: 3;\n\t\t\t\tuser-select: none;\n\t\t\t\tbackground: rgba(0, 0, 0, 0.1);\n\t\t\t\tborder-radius: 50%;\n\t\t\t\tborder: 2px solid rgba(0, 0, 0, 0.3);\n\t\t\t}\n\n\t\t\t.handler:hover {\n\t\t\t\tbackground: rgba(0, 0, 0, 0.2);\n\t\t\t\tborder-color: rgba(0, 0, 0, 0.5);\n\t\t\t}\n\n\t\t\t.handler.dragging {\n\t\t\t\tcursor: grabbing;\n\t\t\t\tbackground: rgba(0, 0, 0, 0.3);\n\t\t\t}\n\n\t\t\t.resize-handle {\n\t\t\t\tposition: absolute;\n\t\t\t\tbottom: 0;\n\t\t\t\tright: 0;\n\t\t\t\twidth: 20px;\n\t\t\t\theight: 20px;\n\t\t\t\tcursor: nwse-resize;\n\t\t\t\tz-index: 4;\n\t\t\t\tbackground: linear-gradient(135deg, transparent 50%, rgba(102, 126, 234, 0.5) 50%);\n\t\t\t\tborder-bottom-right-radius: inherit;\n\t\t\t}\n\n\t\t\t.resize-handle:hover {\n\t\t\t\tbackground: linear-gradient(135deg, transparent 50%, rgba(102, 126, 234, 0.8) 50%);\n\t\t\t}\n\n\t\t\t.resize-handle.resizing {\n\t\t\t\tbackground: linear-gradient(135deg, transparent 50%, rgba(102, 126, 234, 1) 50%);\n\t\t\t}\n\t\t`;\n\t}\n\n\tprivate updateBalloonStyle(): void {\n\t\tif ( !this.balloon || !this.handler ) return;\n\n\t\tthis.balloon.className = `balloon ${this._type}`;\n\t\tthis.handler.className = `handler ${this._type}`;\n\t\t\n\t\tif ( this._type === BalloonType.CLOUD ) {\n\t\t\tthis.updateCloudShape();\n\t\t}\n\t\t\n\t\tthis.updateHandlerVisual();\n\t}\n\n\tprivate updateCloudShape(): void {\n\t\tif ( !this.balloon ) return;\n\t\t\n\t\tconst cloudGroup = this.shadowRoot.querySelector( '.cloud-shape' ) as SVGGElement;\n\t\tif ( !cloudGroup ) return;\n\t\t\n\t\tconst rect = this.balloon.getBoundingClientRect();\n\t\tconst containerRect = this.shadowRoot.querySelector( '.comic-balloon-container' )?.getBoundingClientRect();\n\t\tif ( !containerRect ) return;\n\t\t\n\t\tconst x = rect.left - containerRect.left;\n\t\tconst y = rect.top - containerRect.top;\n\t\tconst w = rect.width;\n\t\tconst h = rect.height;\n\t\t\n\t\tcloudGroup.innerHTML = '';\n\t\t\n\t\tconst centerX = x + w / 2;\n\t\tconst centerY = y + h / 2;\n\t\t\n\t\tconst numScallops = 14;\n\t\tconst radiusX = w / 2.5;\n\t\tconst radiusY = h / 2.5;\n\t\t\n\t\tlet pathData = '';\n\t\t\n\t\tfor ( let i = 0; i <= numScallops; i++ ) {\n\t\t\tconst angle = ( i / numScallops ) * Math.PI * 2 - Math.PI / 2;\n\t\t\tconst nextAngle = ( ( i + 1 ) / numScallops ) * Math.PI * 2 - Math.PI / 2;\n\t\t\t\n\t\t\tconst px = centerX + Math.cos( angle ) * radiusX;\n\t\t\tconst py = centerY + Math.sin( angle ) * radiusY;\n\t\t\t\n\t\t\tconst nx = centerX + Math.cos( nextAngle ) * radiusX;\n\t\t\tconst ny = centerY + Math.sin( nextAngle ) * radiusY;\n\t\t\t\n\t\t\t// Chord midpoint\n\t\t\tconst mx = ( px + nx ) / 2;\n\t\t\tconst my = ( py + ny ) / 2;\n\t\t\t\n\t\t\t// Chord length\n\t\t\tconst dx = nx - px;\n\t\t\tconst dy = ny - py;\n\t\t\tconst chordLen = Math.sqrt( dx * dx + dy * dy );\n\t\t\t\n\t\t\t// Vector from center to midpoint\n\t\t\tconst vx = mx - centerX;\n\t\t\tconst vy = my - centerY;\n\t\t\tconst vLen = Math.sqrt( vx * vx + vy * vy );\n\t\t\t\n\t\t\t// Normalized vector\n\t\t\tconst nx_vec = vx / vLen;\n\t\t\tconst ny_vec = vy / vLen;\n\t\t\t\n\t\t\t// Control point distance\n\t\t\tconst scallopHeight = chordLen * 0.8;\n\t\t\t\n\t\t\tconst cx = mx + nx_vec * scallopHeight;\n\t\t\tconst cy = my + ny_vec * scallopHeight;\n\t\t\t\n\t\t\tif ( i === 0 ) {\n\t\t\t\tpathData += `M ${px} ${py} `;\n\t\t\t}\n\t\t\t\n\t\t\tpathData += `Q ${cx} ${cy} ${nx} ${ny} `;\n\t\t}\n\t\t\n\t\tpathData += 'Z';\n\t\t\n\t\tconst path = document.createElementNS( 'http://www.w3.org/2000/svg', 'path' );\n\t\tpath.setAttribute( 'd', pathData );\n\t\tpath.setAttribute( 'fill', 'white' );\n\t\tpath.setAttribute( 'stroke', '#000' );\n\t\tpath.setAttribute( 'stroke-width', '3' );\n\t\tpath.setAttribute( 'stroke-linejoin', 'round' );\n\t\t\n\t\tcloudGroup.appendChild( path );\n\t}\n\n\tprivate updateHandlerVisual(): void {\n\t\tif ( !this.handler || !this.balloon ) return;\n\n\t\tconst relativeX = this._handlerPosition.x;\n\t\tconst relativeY = this._handlerPosition.y;\n\n\t\tthis.handler.style.left = `${relativeX - 10}px`;\n\t\tthis.handler.style.top = `${relativeY - 10}px`;\n\t\t\n\t\tif ( this._type === BalloonType.CLOUD ) {\n\t\t\tthis.updateCloudShape();\n\t\t}\n\n\t\tthis.updateSVGPointer();\n\t}\n\n\tprivate updateSVGPointer(): void {\n\t\tconst svg = this.shadowRoot.querySelector( '.balloon-svg' ) as SVGElement;\n\t\tif ( !svg || !this.balloon ) return;\n\n\t\tconst balloonRect = this.balloon.getBoundingClientRect();\n\t\tconst containerRect = svg.getBoundingClientRect();\n\n\t\tlet pointerGroup = svg.querySelector( '.pointer-group' );\n\t\tif ( !pointerGroup ) {\n\t\t\tpointerGroup = document.createElementNS( 'http://www.w3.org/2000/svg', 'g' );\n\t\t\tpointerGroup.setAttribute( 'class', 'pointer-group' );\n\t\t\tsvg.appendChild( pointerGroup );\n\t\t}\n\n\t\tpointerGroup.innerHTML = '';\n\n\t\tconst balloonLeft = balloonRect.left - containerRect.left;\n\t\tconst balloonTop = balloonRect.top - containerRect.top;\n\t\tconst balloonCenterX = balloonLeft + balloonRect.width / 2;\n\t\tconst balloonCenterY = balloonTop + balloonRect.height / 2;\n\n\t\tconst handlerX = this._handlerPosition.x;\n\t\tconst handlerY = this._handlerPosition.y;\n\n\t\tconst angle = Math.atan2( handlerY - balloonCenterY, handlerX - balloonCenterX );\n\t\t\n\t\tconst balloonRadiusX = balloonRect.width / 2;\n\t\tconst balloonRadiusY = balloonRect.height / 2;\n\t\t\n\t\tconst edgeX = balloonCenterX + Math.cos( angle ) * balloonRadiusX * 0.85;\n\t\tconst edgeY = balloonCenterY + Math.sin( angle ) * balloonRadiusY * 0.85;\n\n\t\tif ( this._type === BalloonType.TALK || this._type === BalloonType.RECTANGLE ) {\n\t\t\tthis.drawTalkPointer( pointerGroup as SVGGElement, edgeX, edgeY, handlerX, handlerY );\n\t\t} else if ( this._type === BalloonType.CLOUD ) {\n\t\t\tthis.drawCloudPointer( pointerGroup as SVGGElement, edgeX, edgeY, handlerX, handlerY );\n\t\t} else if ( this._type === BalloonType.WHISPER ) {\n\t\t\tthis.drawWhisperPointer( pointerGroup as SVGGElement, edgeX, edgeY, handlerX, handlerY );\n\t\t}\n\t}\n\n\tprivate drawTalkPointer( group: SVGGElement, edgeX: number, edgeY: number, handlerX: number, handlerY: number ): void {\n\t\tconst angle = Math.atan2( handlerY - edgeY, handlerX - edgeX );\n\t\tconst perpAngle = angle + Math.PI / 2;\n\t\t\n\t\tconst baseWidth = 20;\n\t\t\n\t\tconst base1X = edgeX + Math.cos( perpAngle ) * baseWidth / 2;\n\t\tconst base1Y = edgeY + Math.sin( perpAngle ) * baseWidth / 2;\n\t\tconst base2X = edgeX - Math.cos( perpAngle ) * baseWidth / 2;\n\t\tconst base2Y = edgeY - Math.sin( perpAngle ) * baseWidth / 2;\n\t\tconst tipX = handlerX;\n\t\tconst tipY = handlerY;\n\n\t\tconst path = document.createElementNS( 'http://www.w3.org/2000/svg', 'path' );\n\t\tconst d = `M ${base1X} ${base1Y} L ${tipX} ${tipY} L ${base2X} ${base2Y} Z`;\n\t\tpath.setAttribute( 'd', d );\n\t\tpath.setAttribute( 'fill', 'white' );\n\t\tpath.setAttribute( 'stroke', '#000' );\n\t\tpath.setAttribute( 'stroke-width', '3' );\n\t\tpath.setAttribute( 'stroke-linejoin', 'round' );\n\t\t\n\t\tgroup.appendChild( path );\n\t}\n\n\tprivate drawCloudPointer( group: SVGGElement, edgeX: number, edgeY: number, handlerX: number, handlerY: number ): void {\n\t\tconst dx = handlerX - edgeX;\n\t\tconst dy = handlerY - edgeY;\n\t\t\n\t\tconst numBubbles = 3;\n\t\tfor ( let i = 0; i < numBubbles; i++ ) {\n\t\t\tconst t = ( i + 1 ) / ( numBubbles + 1 );\n\t\t\tconst x = edgeX + dx * t;\n\t\t\tconst y = edgeY + dy * t;\n\t\t\tconst radius = 8 - i * 2;\n\t\t\t\n\t\t\tconst circle = document.createElementNS( 'http://www.w3.org/2000/svg', 'circle' );\n\t\t\tcircle.setAttribute( 'cx', x.toString() );\n\t\t\tcircle.setAttribute( 'cy', y.toString() );\n\t\t\tcircle.setAttribute( 'r', radius.toString() );\n\t\t\tcircle.setAttribute( 'fill', 'white' );\n\t\t\tcircle.setAttribute( 'stroke', '#000' );\n\t\t\tcircle.setAttribute( 'stroke-width', '2' );\n\t\t\t\n\t\t\tgroup.appendChild( circle );\n\t\t}\n\t}\n\n\tprivate drawWhisperPointer( group: SVGGElement, edgeX: number, edgeY: number, handlerX: number, handlerY: number ): void {\n\t\tconst angle = Math.atan2( handlerY - edgeY, handlerX - edgeX );\n\t\tconst perpAngle = angle + Math.PI / 2;\n\t\t\n\t\tconst baseWidth = 20;\n\t\t\n\t\tconst base1X = edgeX + Math.cos( perpAngle ) * baseWidth / 2;\n\t\tconst base1Y = edgeY + Math.sin( perpAngle ) * baseWidth / 2;\n\t\tconst base2X = edgeX - Math.cos( perpAngle ) * baseWidth / 2;\n\t\tconst base2Y = edgeY - Math.sin( perpAngle ) * baseWidth / 2;\n\t\tconst tipX = handlerX;\n\t\tconst tipY = handlerY;\n\n\t\tconst path = document.createElementNS( 'http://www.w3.org/2000/svg', 'path' );\n\t\tconst d = `M ${base1X} ${base1Y} L ${tipX} ${tipY} L ${base2X} ${base2Y}`;\n\t\tpath.setAttribute( 'd', d );\n\t\tpath.setAttribute( 'fill', 'none' );\n\t\tpath.setAttribute( 'stroke', '#000' );\n\t\tpath.setAttribute( 'stroke-width', '3' );\n\t\tpath.setAttribute( 'stroke-dasharray', '10 5' );\n\t\tpath.setAttribute( 'stroke-linejoin', 'round' );\n\t\tpath.setAttribute( 'stroke-linecap', 'round' );\n\t\t\n\t\tgroup.appendChild( path );\n\t}\n\n\tprivate setupEventListeners(): void {\n\t\tif ( !this.handler ) return;\n\n\t\tthis.handler.addEventListener( 'mousedown', this.handleMouseDown.bind( this ) );\n\t\tthis.handler.addEventListener( 'touchstart', this.handleTouchStart.bind( this ), { passive: false } );\n\n\t\tif ( this.resizeHandle ) {\n\t\t\tthis.resizeHandle.addEventListener( 'mousedown', this.handleResizeMouseDown.bind( this ) );\n\t\t\tthis.resizeHandle.addEventListener( 'touchstart', this.handleResizeTouchStart.bind( this ), { passive: false } );\n\t\t}\n\n\t\tif ( this.contentEditableElement ) {\n\t\t\tthis.contentEditableElement.addEventListener( 'blur', this.handleContentBlur.bind( this ) );\n\t\t}\n\t}\n\n\tprivate removeEventListeners(): void {\n\t\tif ( !this.handler ) return;\n\n\t\tthis.handler.removeEventListener( 'mousedown', this.handleMouseDown.bind( this ) );\n\t\tthis.handler.removeEventListener( 'touchstart', this.handleTouchStart.bind( this ) );\n\n\t\tif ( this.resizeHandle ) {\n\t\t\tthis.resizeHandle.removeEventListener( 'mousedown', this.handleResizeMouseDown.bind( this ) );\n\t\t\tthis.resizeHandle.removeEventListener( 'touchstart', this.handleResizeTouchStart.bind( this ) );\n\t\t}\n\n\t\tif ( this.contentEditableElement ) {\n\t\t\tthis.contentEditableElement.removeEventListener( 'blur', this.handleContentBlur.bind( this ) );\n\t\t}\n\t}\n\n\tprivate handleMouseDown( e: MouseEvent ): void {\n\t\te.preventDefault();\n\t\tthis.startDrag( e.clientX, e.clientY );\n\n\t\tconst handleMouseMove = ( e: MouseEvent ) => this.handleDrag( e.clientX, e.clientY );\n\t\tconst handleMouseUp = () => {\n\t\t\tthis.stopDrag();\n\t\t\tdocument.removeEventListener( 'mousemove', handleMouseMove );\n\t\t\tdocument.removeEventListener( 'mouseup', handleMouseUp );\n\t\t};\n\n\t\tdocument.addEventListener( 'mousemove', handleMouseMove );\n\t\tdocument.addEventListener( 'mouseup', handleMouseUp );\n\t}\n\n\tprivate handleTouchStart( e: TouchEvent ): void {\n\t\te.preventDefault();\n\t\tconst touch = e.touches[0];\n\t\tthis.startDrag( touch.clientX, touch.clientY );\n\n\t\tconst handleTouchMove = ( e: TouchEvent ) => {\n\t\t\tconst touch = e.touches[0];\n\t\t\tthis.handleDrag( touch.clientX, touch.clientY );\n\t\t};\n\t\tconst handleTouchEnd = () => {\n\t\t\tthis.stopDrag();\n\t\t\tdocument.removeEventListener( 'touchmove', handleTouchMove );\n\t\t\tdocument.removeEventListener( 'touchend', handleTouchEnd );\n\t\t};\n\n\t\tdocument.addEventListener( 'touchmove', handleTouchMove, { passive: false } );\n\t\tdocument.addEventListener( 'touchend', handleTouchEnd );\n\t}\n\n\tprivate startDrag( clientX: number, clientY: number ): void {\n\t\tthis.isDragging = true;\n\t\tif ( this.handler ) {\n\t\t\tthis.handler.classList.add( 'dragging' );\n\t\t}\n\n\t\tconst containerRect = this.shadowRoot.querySelector( '.comic-balloon-container' )?.getBoundingClientRect();\n\t\tif ( containerRect ) {\n\t\t\tthis.dragStartOffset = {\n\t\t\t\tx: clientX - containerRect.left - this._handlerPosition.x,\n\t\t\t\ty: clientY - containerRect.top - this._handlerPosition.y\n\t\t\t};\n\t\t}\n\t}\n\n\tprivate handleDrag( clientX: number, clientY: number ): void {\n\t\tif ( !this.isDragging ) return;\n\n\t\tconst containerRect = this.shadowRoot.querySelector( '.comic-balloon-container' )?.getBoundingClientRect();\n\t\tif ( !containerRect ) return;\n\n\t\tlet newX = clientX - containerRect.left - this.dragStartOffset.x;\n\t\tlet newY = clientY - containerRect.top - this.dragStartOffset.y;\n\n\t\tnewX = Math.max( -50, Math.min( containerRect.width + 50, newX ) );\n\t\tnewY = Math.max( -50, Math.min( containerRect.height + 50, newY ) );\n\n\t\tthis._handlerPosition = { x: newX, y: newY };\n\t\tthis.updateHandlerVisual();\n\t}\n\n\tprivate stopDrag(): void {\n\t\tthis.isDragging = false;\n\t\tif ( this.handler ) {\n\t\t\tthis.handler.classList.remove( 'dragging' );\n\t\t}\n\n\t\tthis.dispatchEvent( new CustomEvent<HandlerMoveEvent['detail']>( 'handler-move', {\n\t\t\tdetail: {\n\t\t\t\tfinalPosition: { ...this._handlerPosition },\n\t\t\t\tballoonType: this._type\n\t\t\t},\n\t\t\tbubbles: true,\n\t\t\tcomposed: true\n\t\t} ) );\n\t}\n\n\tprivate handleContentBlur(): void {\n\t\tif ( !this.contentEditableElement ) return;\n\n\t\tthis.dispatchEvent( new CustomEvent<ContentChangeEvent['detail']>( 'balloon-content-change', {\n\t\t\tdetail: {\n\t\t\t\tnewContent: this.contentEditableElement.textContent || '',\n\t\t\t\tballoonType: this._type\n\t\t\t},\n\t\t\tbubbles: true,\n\t\t\tcomposed: true\n\t\t} ) );\n\t}\n\n\tprivate handleResizeMouseDown( e: MouseEvent ): void {\n\t\te.preventDefault();\n\t\te.stopPropagation();\n\t\tthis.startResize( e.clientX, e.clientY );\n\n\t\tconst handleMouseMove = ( e: MouseEvent ) => this.handleResize( e.clientX, e.clientY );\n\t\tconst handleMouseUp = () => {\n\t\t\tthis.stopResize();\n\t\t\tdocument.removeEventListener( 'mousemove', handleMouseMove );\n\t\t\tdocument.removeEventListener( 'mouseup', handleMouseUp );\n\t\t};\n\n\t\tdocument.addEventListener( 'mousemove', handleMouseMove );\n\t\tdocument.addEventListener( 'mouseup', handleMouseUp );\n\t}\n\n\tprivate handleResizeTouchStart( e: TouchEvent ): void {\n\t\te.preventDefault();\n\t\te.stopPropagation();\n\t\tconst touch = e.touches[0];\n\t\tthis.startResize( touch.clientX, touch.clientY );\n\n\t\tconst handleTouchMove = ( e: TouchEvent ) => {\n\t\t\tconst touch = e.touches[0];\n\t\t\tthis.handleResize( touch.clientX, touch.clientY );\n\t\t};\n\t\tconst handleTouchEnd = () => {\n\t\t\tthis.stopResize();\n\t\t\tdocument.removeEventListener( 'touchmove', handleTouchMove );\n\t\t\tdocument.removeEventListener( 'touchend', handleTouchEnd );\n\t\t};\n\n\t\tdocument.addEventListener( 'touchmove', handleTouchMove, { passive: false } );\n\t\tdocument.addEventListener( 'touchend', handleTouchEnd );\n\t}\n\n\tprivate startResize( clientX: number, clientY: number ): void {\n\t\tif ( !this.balloon || !this.resizeHandle ) return;\n\n\t\tthis.isResizing = true;\n\t\tthis.resizeHandle.classList.add( 'resizing' );\n\n\t\tthis.resizeStartPos = {\n\t\t\tx: clientX,\n\t\t\ty: clientY\n\t\t};\n\t}\n\n\tprivate handleResize( clientX: number, clientY: number ): void {\n\t\tif ( !this.isResizing ) return;\n\n\t\tconst deltaX = clientX - this.resizeStartPos.x;\n\t\tconst deltaY = clientY - this.resizeStartPos.y;\n\n\t\tconst hostRect = this.getBoundingClientRect();\n\t\tconst newWidth = Math.max( 150, hostRect.width + deltaX );\n\t\tconst newHeight = Math.max( 100, hostRect.height + deltaY );\n\n\t\tthis.style.width = `${newWidth}px`;\n\t\tthis.style.height = `${newHeight}px`;\n\n\t\tthis.resizeStartPos = {\n\t\t\tx: clientX,\n\t\t\ty: clientY\n\t\t};\n\n\t\tthis.updateHandlerVisual();\n\t}\n\n\tprivate stopResize(): void {\n\t\tif ( !this.isResizing || !this.balloon || !this.resizeHandle ) return;\n\n\t\tthis.isResizing = false;\n\t\tthis.resizeHandle.classList.remove( 'resizing' );\n\n\t\tconst rect = this.balloon.getBoundingClientRect();\n\n\t\tthis.dispatchEvent( new CustomEvent<ResizeEvent['detail']>( 'balloon-resize', {\n\t\t\tdetail: {\n\t\t\t\twidth: rect.width,\n\t\t\t\theight: rect.height,\n\t\t\t\tballoonType: this._type\n\t\t\t},\n\t\t\tbubbles: true,\n\t\t\tcomposed: true\n\t\t} ) );\n\t}\n}\n\nexport const defineComicBalloon = (): void => {\n\tif ( typeof window !== 'undefined' && !customElements.get( 'comic-balloon' ) ) {\n\t\tcustomElements.define( 'comic-balloon', ComicBalloonElement );\n\t}\n};\n"],"names":["BalloonType","ComicBalloonElement","name","oldValue","newValue","value","position","cloudGroup","rect","containerRect","x","y","w","h","centerX","centerY","numScallops","radiusX","radiusY","pathData","angle","nextAngle","px","py","nx","ny","mx","my","dx","dy","chordLen","vx","vy","vLen","nx_vec","ny_vec","scallopHeight","cx","cy","path","relativeX","relativeY","svg","balloonRect","pointerGroup","balloonLeft","balloonTop","balloonCenterX","balloonCenterY","handlerX","handlerY","balloonRadiusX","balloonRadiusY","edgeX","edgeY","group","perpAngle","baseWidth","base1X","base1Y","base2X","base2Y","tipX","tipY","d","numBubbles","i","t","radius","circle","e","handleMouseMove","handleMouseUp","touch","handleTouchMove","handleTouchEnd","clientX","clientY","newX","newY","deltaX","deltaY","hostRect","newWidth","newHeight","defineComicBalloon"],"mappings":"AAKO,IAAKA,sBAAAA,OACXA,EAAA,OAAO,QACPA,EAAA,QAAQ,SACRA,EAAA,UAAU,WACVA,EAAA,YAAY,aAJDA,IAAAA,KAAA,CAAA,CAAA;AAoCL,MAAMC,UAA4B,YAAqC;AAAA,EAiB7E,cAAc;AACb,UAAA,GAhBD,KAAQ,QAAqB,QAC7B,KAAQ,mBAAoC,EAAE,GAAG,IAAI,GAAG,IAAA,GACxD,KAAQ,aAAsB,IAC9B,KAAQ,aAAsB,IAC9B,KAAQ,kBAA4C,EAAE,GAAG,GAAG,GAAG,EAAA,GAC/D,KAAQ,iBAA2C,EAAE,GAAG,GAAG,GAAG,EAAA,GAY7D,KAAK,aAAc,EAAE,MAAM,OAAA,CAAS;AAAA,EACrC;AAAA,EAPA,WAAW,qBAA+B;AACzC,WAAO,CAAE,QAAQ,MAAO;AAAA,EACzB;AAAA,EAOA,oBAA0B;AACzB,SAAK,OAAA,GACL,KAAK,oBAAA;AAAA,EACN;AAAA,EAEA,uBAA6B;AAC5B,SAAK,qBAAA;AAAA,EACN;AAAA,EAEA,yBAA0BC,GAAcC,GAAkBC,GAAyB;AAClF,IAAKD,MAAaC,MAEbF,MAAS,UACb,KAAK,QAAUE,KAA6B,QAC5C,KAAK,mBAAA,KACMF,MAAS,UACf,KAAK,2BACT,KAAK,uBAAuB,cAAcE;AAAA,EAG7C;AAAA,EAEA,IAAI,OAAoB;AACvB,WAAO,KAAK;AAAA,EACb;AAAA,EAEA,IAAI,KAAMC,GAAqB;AAC9B,SAAK,QAAQA,GACb,KAAK,aAAc,QAAQA,CAAM;AAAA,EAClC;AAAA,EAEA,IAAI,kBAAmC;AACtC,WAAO,EAAE,GAAG,KAAK,iBAAA;AAAA,EAClB;AAAA,EAEA,IAAI,gBAAiBA,GAAyB;AAC7C,SAAK,mBAAmB,EAAE,GAAGA,EAAA,GAC7B,KAAK,oBAAA;AAAA,EACN;AAAA,EAEA,sBAAuBC,GAAkC;AACxD,SAAK,kBAAkBA;AAAA,EACxB;AAAA,EAEA,UAAkB;AACjB,WAAO,KAAK;AAAA,EACb;AAAA,EAEQ,SAAe;AACtB,SAAK,WAAW,YAAY;AAAA,YAClB,KAAK,WAAW;AAAA;AAAA;AAAA;AAAA;AAAA,0BAKF,KAAK,KAAK;AAAA;AAAA,QAE5B,KAAK,aAAc,MAAO,KAAK,wBAAwB;AAAA;AAAA;AAAA;AAAA,0BAIrC,KAAK,KAAK;AAAA;AAAA,KAIlC,KAAK,yBAAyB,KAAK,WAAW,cAAe,UAAW,GACxE,KAAK,UAAU,KAAK,WAAW,cAAe,UAAW,GACzD,KAAK,eAAe,KAAK,WAAW,cAAe,gBAAiB,GACpE,KAAK,UAAU,KAAK,WAAW,cAAe,UAAW,GAEpD,KAAK,UAAU,WACnB,KAAK,iBAAA,GAEN,KAAK,oBAAA;AAAA,EACN;AAAA,EAEQ,YAAoB;AAC3B,WAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EA6HR;AAAA,EAEQ,qBAA2B;AAClC,IAAK,CAAC,KAAK,WAAW,CAAC,KAAK,YAE5B,KAAK,QAAQ,YAAY,WAAW,KAAK,KAAK,IAC9C,KAAK,QAAQ,YAAY,WAAW,KAAK,KAAK,IAEzC,KAAK,UAAU,WACnB,KAAK,iBAAA,GAGN,KAAK,oBAAA;AAAA,EACN;AAAA,EAEQ,mBAAyB;AAChC,QAAK,CAAC,KAAK,QAAU;AAErB,UAAMC,IAAa,KAAK,WAAW,cAAe,cAAe;AACjE,QAAK,CAACA,EAAa;AAEnB,UAAMC,IAAO,KAAK,QAAQ,sBAAA,GACpBC,IAAgB,KAAK,WAAW,cAAe,0BAA2B,GAAG,sBAAA;AACnF,QAAK,CAACA,EAAgB;AAEtB,UAAMC,IAAIF,EAAK,OAAOC,EAAc,MAC9BE,IAAIH,EAAK,MAAMC,EAAc,KAC7BG,IAAIJ,EAAK,OACTK,IAAIL,EAAK;AAEf,IAAAD,EAAW,YAAY;AAEvB,UAAMO,IAAUJ,IAAIE,IAAI,GAClBG,IAAUJ,IAAIE,IAAI,GAElBG,IAAc,IACdC,IAAUL,IAAI,KACdM,IAAUL,IAAI;AAEpB,QAAIM,IAAW;AAEf,aAAU,IAAI,GAAG,KAAKH,GAAa,KAAM;AACxC,YAAMI,IAAU,IAAIJ,IAAgB,KAAK,KAAK,IAAI,KAAK,KAAK,GACtDK,KAAgB,IAAI,KAAML,IAAgB,KAAK,KAAK,IAAI,KAAK,KAAK,GAElEM,IAAKR,IAAU,KAAK,IAAKM,CAAM,IAAIH,GACnCM,IAAKR,IAAU,KAAK,IAAKK,CAAM,IAAIF,GAEnCM,IAAKV,IAAU,KAAK,IAAKO,CAAU,IAAIJ,GACvCQ,IAAKV,IAAU,KAAK,IAAKM,CAAU,IAAIH,GAGvCQ,KAAOJ,IAAKE,KAAO,GACnBG,KAAOJ,IAAKE,KAAO,GAGnBG,IAAKJ,IAAKF,GACVO,IAAKJ,IAAKF,GACVO,IAAW,KAAK,KAAMF,IAAKA,IAAKC,IAAKA,CAAG,GAGxCE,IAAKL,IAAKZ,GACVkB,IAAKL,IAAKZ,GACVkB,IAAO,KAAK,KAAMF,IAAKA,IAAKC,IAAKA,CAAG,GAGpCE,IAASH,IAAKE,GACdE,IAASH,IAAKC,GAGdG,IAAgBN,IAAW,KAE3BO,IAAKX,IAAKQ,IAASE,GACnBE,IAAKX,IAAKQ,IAASC;AAEzB,MAAK,MAAM,MACVjB,KAAY,KAAKG,CAAE,IAAIC,CAAE,MAG1BJ,KAAY,KAAKkB,CAAE,IAAIC,CAAE,IAAId,CAAE,IAAIC,CAAE;AAAA,IACtC;AAEA,IAAAN,KAAY;AAEZ,UAAMoB,IAAO,SAAS,gBAAiB,8BAA8B,MAAO;AAC5E,IAAAA,EAAK,aAAc,KAAKpB,CAAS,GACjCoB,EAAK,aAAc,QAAQ,OAAQ,GACnCA,EAAK,aAAc,UAAU,MAAO,GACpCA,EAAK,aAAc,gBAAgB,GAAI,GACvCA,EAAK,aAAc,mBAAmB,OAAQ,GAE9ChC,EAAW,YAAagC,CAAK;AAAA,EAC9B;AAAA,EAEQ,sBAA4B;AACnC,QAAK,CAAC,KAAK,WAAW,CAAC,KAAK,QAAU;AAEtC,UAAMC,IAAY,KAAK,iBAAiB,GAClCC,IAAY,KAAK,iBAAiB;AAExC,SAAK,QAAQ,MAAM,OAAO,GAAGD,IAAY,EAAE,MAC3C,KAAK,QAAQ,MAAM,MAAM,GAAGC,IAAY,EAAE,MAErC,KAAK,UAAU,WACnB,KAAK,iBAAA,GAGN,KAAK,iBAAA;AAAA,EACN;AAAA,EAEQ,mBAAyB;AAChC,UAAMC,IAAM,KAAK,WAAW,cAAe,cAAe;AAC1D,QAAK,CAACA,KAAO,CAAC,KAAK,QAAU;AAE7B,UAAMC,IAAc,KAAK,QAAQ,sBAAA,GAC3BlC,IAAgBiC,EAAI,sBAAA;AAE1B,QAAIE,IAAeF,EAAI,cAAe,gBAAiB;AACvD,IAAME,MACLA,IAAe,SAAS,gBAAiB,8BAA8B,GAAI,GAC3EA,EAAa,aAAc,SAAS,eAAgB,GACpDF,EAAI,YAAaE,CAAa,IAG/BA,EAAa,YAAY;AAEzB,UAAMC,IAAcF,EAAY,OAAOlC,EAAc,MAC/CqC,IAAaH,EAAY,MAAMlC,EAAc,KAC7CsC,IAAiBF,IAAcF,EAAY,QAAQ,GACnDK,IAAiBF,IAAaH,EAAY,SAAS,GAEnDM,IAAW,KAAK,iBAAiB,GACjCC,IAAW,KAAK,iBAAiB,GAEjC9B,IAAQ,KAAK,MAAO8B,IAAWF,GAAgBC,IAAWF,CAAe,GAEzEI,IAAiBR,EAAY,QAAQ,GACrCS,IAAiBT,EAAY,SAAS,GAEtCU,IAAQN,IAAiB,KAAK,IAAK3B,CAAM,IAAI+B,IAAiB,MAC9DG,IAAQN,IAAiB,KAAK,IAAK5B,CAAM,IAAIgC,IAAiB;AAEpE,IAAK,KAAK,UAAU,UAAoB,KAAK,UAAU,cACtD,KAAK,gBAAiBR,GAA6BS,GAAOC,GAAOL,GAAUC,CAAS,IACzE,KAAK,UAAU,UAC1B,KAAK,iBAAkBN,GAA6BS,GAAOC,GAAOL,GAAUC,CAAS,IAC1E,KAAK,UAAU,aAC1B,KAAK,mBAAoBN,GAA6BS,GAAOC,GAAOL,GAAUC,CAAS;AAAA,EAEzF;AAAA,EAEQ,gBAAiBK,GAAoBF,GAAeC,GAAeL,GAAkBC,GAAyB;AAErH,UAAMM,IADQ,KAAK,MAAON,IAAWI,GAAOL,IAAWI,CAAM,IACnC,KAAK,KAAK,GAE9BI,IAAY,IAEZC,IAASL,IAAQ,KAAK,IAAKG,CAAU,IAAIC,IAAY,GACrDE,IAASL,IAAQ,KAAK,IAAKE,CAAU,IAAIC,IAAY,GACrDG,IAASP,IAAQ,KAAK,IAAKG,CAAU,IAAIC,IAAY,GACrDI,IAASP,IAAQ,KAAK,IAAKE,CAAU,IAAIC,IAAY,GACrDK,IAAOb,GACPc,IAAOb,GAEPX,IAAO,SAAS,gBAAiB,8BAA8B,MAAO,GACtEyB,IAAI,KAAKN,CAAM,IAAIC,CAAM,MAAMG,CAAI,IAAIC,CAAI,MAAMH,CAAM,IAAIC,CAAM;AACvE,IAAAtB,EAAK,aAAc,KAAKyB,CAAE,GAC1BzB,EAAK,aAAc,QAAQ,OAAQ,GACnCA,EAAK,aAAc,UAAU,MAAO,GACpCA,EAAK,aAAc,gBAAgB,GAAI,GACvCA,EAAK,aAAc,mBAAmB,OAAQ,GAE9CgB,EAAM,YAAahB,CAAK;AAAA,EACzB;AAAA,EAEQ,iBAAkBgB,GAAoBF,GAAeC,GAAeL,GAAkBC,GAAyB;AACtH,UAAMtB,IAAKqB,IAAWI,GAChBxB,IAAKqB,IAAWI,GAEhBW,IAAa;AACnB,aAAUC,IAAI,GAAGA,IAAID,GAAYC,KAAM;AACtC,YAAMC,KAAMD,IAAI,MAAQD,IAAa,IAC/BvD,IAAI2C,IAAQzB,IAAKuC,GACjBxD,IAAI2C,IAAQzB,IAAKsC,GACjBC,IAAS,IAAIF,IAAI,GAEjBG,IAAS,SAAS,gBAAiB,8BAA8B,QAAS;AAChF,MAAAA,EAAO,aAAc,MAAM3D,EAAE,SAAA,CAAW,GACxC2D,EAAO,aAAc,MAAM1D,EAAE,SAAA,CAAW,GACxC0D,EAAO,aAAc,KAAKD,EAAO,SAAA,CAAW,GAC5CC,EAAO,aAAc,QAAQ,OAAQ,GACrCA,EAAO,aAAc,UAAU,MAAO,GACtCA,EAAO,aAAc,gBAAgB,GAAI,GAEzCd,EAAM,YAAac,CAAO;AAAA,IAC3B;AAAA,EACD;AAAA,EAEQ,mBAAoBd,GAAoBF,GAAeC,GAAeL,GAAkBC,GAAyB;AAExH,UAAMM,IADQ,KAAK,MAAON,IAAWI,GAAOL,IAAWI,CAAM,IACnC,KAAK,KAAK,GAE9BI,IAAY,IAEZC,IAASL,IAAQ,KAAK,IAAKG,CAAU,IAAIC,IAAY,GACrDE,IAASL,IAAQ,KAAK,IAAKE,CAAU,IAAIC,IAAY,GACrDG,IAASP,IAAQ,KAAK,IAAKG,CAAU,IAAIC,IAAY,GACrDI,IAASP,IAAQ,KAAK,IAAKE,CAAU,IAAIC,IAAY,GACrDK,IAAOb,GACPc,IAAOb,GAEPX,IAAO,SAAS,gBAAiB,8BAA8B,MAAO,GACtEyB,IAAI,KAAKN,CAAM,IAAIC,CAAM,MAAMG,CAAI,IAAIC,CAAI,MAAMH,CAAM,IAAIC,CAAM;AACvE,IAAAtB,EAAK,aAAc,KAAKyB,CAAE,GAC1BzB,EAAK,aAAc,QAAQ,MAAO,GAClCA,EAAK,aAAc,UAAU,MAAO,GACpCA,EAAK,aAAc,gBAAgB,GAAI,GACvCA,EAAK,aAAc,oBAAoB,MAAO,GAC9CA,EAAK,aAAc,mBAAmB,OAAQ,GAC9CA,EAAK,aAAc,kBAAkB,OAAQ,GAE7CgB,EAAM,YAAahB,CAAK;AAAA,EACzB;AAAA,EAEQ,sBAA4B;AACnC,IAAM,KAAK,YAEX,KAAK,QAAQ,iBAAkB,aAAa,KAAK,gBAAgB,KAAM,IAAK,CAAE,GAC9E,KAAK,QAAQ,iBAAkB,cAAc,KAAK,iBAAiB,KAAM,IAAK,GAAG,EAAE,SAAS,GAAA,CAAQ,GAE/F,KAAK,iBACT,KAAK,aAAa,iBAAkB,aAAa,KAAK,sBAAsB,KAAM,IAAK,CAAE,GACzF,KAAK,aAAa,iBAAkB,cAAc,KAAK,uBAAuB,KAAM,IAAK,GAAG,EAAE,SAAS,GAAA,CAAQ,IAG3G,KAAK,0BACT,KAAK,uBAAuB,iBAAkB,QAAQ,KAAK,kBAAkB,KAAM,IAAK,CAAE;AAAA,EAE5F;AAAA,EAEQ,uBAA6B;AACpC,IAAM,KAAK,YAEX,KAAK,QAAQ,oBAAqB,aAAa,KAAK,gBAAgB,KAAM,IAAK,CAAE,GACjF,KAAK,QAAQ,oBAAqB,cAAc,KAAK,iBAAiB,KAAM,IAAK,CAAE,GAE9E,KAAK,iBACT,KAAK,aAAa,oBAAqB,aAAa,KAAK,sBAAsB,KAAM,IAAK,CAAE,GAC5F,KAAK,aAAa,oBAAqB,cAAc,KAAK,uBAAuB,KAAM,IAAK,CAAE,IAG1F,KAAK,0BACT,KAAK,uBAAuB,oBAAqB,QAAQ,KAAK,kBAAkB,KAAM,IAAK,CAAE;AAAA,EAE/F;AAAA,EAEQ,gBAAiB+B,GAAsB;AAC9C,IAAAA,EAAE,eAAA,GACF,KAAK,UAAWA,EAAE,SAASA,EAAE,OAAQ;AAErC,UAAMC,IAAkB,CAAED,MAAmB,KAAK,WAAYA,EAAE,SAASA,EAAE,OAAQ,GAC7EE,IAAgB,MAAM;AAC3B,WAAK,SAAA,GACL,SAAS,oBAAqB,aAAaD,CAAgB,GAC3D,SAAS,oBAAqB,WAAWC,CAAc;AAAA,IACxD;AAEA,aAAS,iBAAkB,aAAaD,CAAgB,GACxD,SAAS,iBAAkB,WAAWC,CAAc;AAAA,EACrD;AAAA,EAEQ,iBAAkBF,GAAsB;AAC/C,IAAAA,EAAE,eAAA;AACF,UAAMG,IAAQH,EAAE,QAAQ,CAAC;AACzB,SAAK,UAAWG,EAAM,SAASA,EAAM,OAAQ;AAE7C,UAAMC,IAAkB,CAAEJ,MAAmB;AAC5C,YAAMG,IAAQH,EAAE,QAAQ,CAAC;AACzB,WAAK,WAAYG,EAAM,SAASA,EAAM,OAAQ;AAAA,IAC/C,GACME,IAAiB,MAAM;AAC5B,WAAK,SAAA,GACL,SAAS,oBAAqB,aAAaD,CAAgB,GAC3D,SAAS,oBAAqB,YAAYC,CAAe;AAAA,IAC1D;AAEA,aAAS,iBAAkB,aAAaD,GAAiB,EAAE,SAAS,IAAQ,GAC5E,SAAS,iBAAkB,YAAYC,CAAe;AAAA,EACvD;AAAA,EAEQ,UAAWC,GAAiBC,GAAwB;AAC3D,SAAK,aAAa,IACb,KAAK,WACT,KAAK,QAAQ,UAAU,IAAK,UAAW;AAGxC,UAAMpE,IAAgB,KAAK,WAAW,cAAe,0BAA2B,GAAG,sBAAA;AACnF,IAAKA,MACJ,KAAK,kBAAkB;AAAA,MACtB,GAAGmE,IAAUnE,EAAc,OAAO,KAAK,iBAAiB;AAAA,MACxD,GAAGoE,IAAUpE,EAAc,MAAM,KAAK,iBAAiB;AAAA,IAAA;AAAA,EAG1D;AAAA,EAEQ,WAAYmE,GAAiBC,GAAwB;AAC5D,QAAK,CAAC,KAAK,WAAa;AAExB,UAAMpE,IAAgB,KAAK,WAAW,cAAe,0BAA2B,GAAG,sBAAA;AACnF,QAAK,CAACA,EAAgB;AAEtB,QAAIqE,IAAOF,IAAUnE,EAAc,OAAO,KAAK,gBAAgB,GAC3DsE,IAAOF,IAAUpE,EAAc,MAAM,KAAK,gBAAgB;AAE9D,IAAAqE,IAAO,KAAK,IAAK,KAAK,KAAK,IAAKrE,EAAc,QAAQ,IAAIqE,CAAK,CAAE,GACjEC,IAAO,KAAK,IAAK,KAAK,KAAK,IAAKtE,EAAc,SAAS,IAAIsE,CAAK,CAAE,GAElE,KAAK,mBAAmB,EAAE,GAAGD,GAAM,GAAGC,EAAA,GACtC,KAAK,oBAAA;AAAA,EACN;AAAA,EAEQ,WAAiB;AACxB,SAAK,aAAa,IACb,KAAK,WACT,KAAK,QAAQ,UAAU,OAAQ,UAAW,GAG3C,KAAK,cAAe,IAAI,YAAyC,gBAAgB;AAAA,MAChF,QAAQ;AAAA,QACP,eAAe,EAAE,GAAG,KAAK,iBAAA;AAAA,QACzB,aAAa,KAAK;AAAA,MAAA;AAAA,MAEnB,SAAS;AAAA,MACT,UAAU;AAAA,IAAA,CACT,CAAE;AAAA,EACL;AAAA,EAEQ,oBAA0B;AACjC,IAAM,KAAK,0BAEX,KAAK,cAAe,IAAI,YAA2C,0BAA0B;AAAA,MAC5F,QAAQ;AAAA,QACP,YAAY,KAAK,uBAAuB,eAAe;AAAA,QACvD,aAAa,KAAK;AAAA,MAAA;AAAA,MAEnB,SAAS;AAAA,MACT,UAAU;AAAA,IAAA,CACT,CAAE;AAAA,EACL;AAAA,EAEQ,sBAAuBT,GAAsB;AACpD,IAAAA,EAAE,eAAA,GACFA,EAAE,gBAAA,GACF,KAAK,YAAaA,EAAE,SAASA,EAAE,OAAQ;AAEvC,UAAMC,IAAkB,CAAED,MAAmB,KAAK,aAAcA,EAAE,SAASA,EAAE,OAAQ,GAC/EE,IAAgB,MAAM;AAC3B,WAAK,WAAA,GACL,SAAS,oBAAqB,aAAaD,CAAgB,GAC3D,SAAS,oBAAqB,WAAWC,CAAc;AAAA,IACxD;AAEA,aAAS,iBAAkB,aAAaD,CAAgB,GACxD,SAAS,iBAAkB,WAAWC,CAAc;AAAA,EACrD;AAAA,EAEQ,uBAAwBF,GAAsB;AACrD,IAAAA,EAAE,eAAA,GACFA,EAAE,gBAAA;AACF,UAAMG,IAAQH,EAAE,QAAQ,CAAC;AACzB,SAAK,YAAaG,EAAM,SAASA,EAAM,OAAQ;AAE/C,UAAMC,IAAkB,CAAEJ,MAAmB;AAC5C,YAAMG,IAAQH,EAAE,QAAQ,CAAC;AACzB,WAAK,aAAcG,EAAM,SAASA,EAAM,OAAQ;AAAA,IACjD,GACME,IAAiB,MAAM;AAC5B,WAAK,WAAA,GACL,SAAS,oBAAqB,aAAaD,CAAgB,GAC3D,SAAS,oBAAqB,YAAYC,CAAe;AAAA,IAC1D;AAEA,aAAS,iBAAkB,aAAaD,GAAiB,EAAE,SAAS,IAAQ,GAC5E,SAAS,iBAAkB,YAAYC,CAAe;AAAA,EACvD;AAAA,EAEQ,YAAaC,GAAiBC,GAAwB;AAC7D,IAAK,CAAC,KAAK,WAAW,CAAC,KAAK,iBAE5B,KAAK,aAAa,IAClB,KAAK,aAAa,UAAU,IAAK,UAAW,GAE5C,KAAK,iBAAiB;AAAA,MACrB,GAAGD;AAAA,MACH,GAAGC;AAAA,IAAA;AAAA,EAEL;AAAA,EAEQ,aAAcD,GAAiBC,GAAwB;AAC9D,QAAK,CAAC,KAAK,WAAa;AAExB,UAAMG,IAASJ,IAAU,KAAK,eAAe,GACvCK,IAASJ,IAAU,KAAK,eAAe,GAEvCK,IAAW,KAAK,sBAAA,GAChBC,IAAW,KAAK,IAAK,KAAKD,EAAS,QAAQF,CAAO,GAClDI,IAAY,KAAK,IAAK,KAAKF,EAAS,SAASD,CAAO;AAE1D,SAAK,MAAM,QAAQ,GAAGE,CAAQ,MAC9B,KAAK,MAAM,SAAS,GAAGC,CAAS,MAEhC,KAAK,iBAAiB;AAAA,MACrB,GAAGR;AAAA,MACH,GAAGC;AAAA,IAAA,GAGJ,KAAK,oBAAA;AAAA,EACN;AAAA,EAEQ,aAAmB;AAC1B,QAAK,CAAC,KAAK,cAAc,CAAC,KAAK,WAAW,CAAC,KAAK,aAAe;AAE/D,SAAK,aAAa,IAClB,KAAK,aAAa,UAAU,OAAQ,UAAW;AAE/C,UAAMrE,IAAO,KAAK,QAAQ,sBAAA;AAE1B,SAAK,cAAe,IAAI,YAAoC,kBAAkB;AAAA,MAC7E,QAAQ;AAAA,QACP,OAAOA,EAAK;AAAA,QACZ,QAAQA,EAAK;AAAA,QACb,aAAa,KAAK;AAAA,MAAA;AAAA,MAEnB,SAAS;AAAA,MACT,UAAU;AAAA,IAAA,CACT,CAAE;AAAA,EACL;AACD;AAEO,MAAM6E,IAAqB,MAAY;AAC7C,EAAK,OAAO,SAAW,OAAe,CAAC,eAAe,IAAK,eAAgB,KAC1E,eAAe,OAAQ,iBAAiBpF,CAAoB;AAE9D;"}
@@ -0,0 +1,102 @@
1
+ /**
2
+ * Dialog Web Component
3
+ * A customizable dialog with HTML body, custom buttons, and modal support
4
+ */
5
+ export type DialogButton = {
6
+ label: string;
7
+ backgroundColor?: string;
8
+ onclick: (dialog?: DialogElement) => void;
9
+ };
10
+ export type DialogConfig = {
11
+ title?: string;
12
+ body: string;
13
+ buttons?: DialogButton[];
14
+ modal?: boolean;
15
+ escToClose?: boolean;
16
+ clickToClose?: boolean;
17
+ fxAppear?: 'none' | 'fade' | 'slide';
18
+ fxSpeed?: number;
19
+ onclose?: () => void;
20
+ };
21
+ export declare class DialogElement extends HTMLElement {
22
+ shadowRoot: ShadowRoot;
23
+ private config;
24
+ private backdrop?;
25
+ private escKeyHandler?;
26
+ private eventsBound;
27
+ constructor();
28
+ connectedCallback(): void;
29
+ disconnectedCallback(): void;
30
+ /**
31
+ * Shows the dialog with the given configuration
32
+ */
33
+ show(config: DialogConfig): void;
34
+ /**
35
+ * Closes the dialog
36
+ */
37
+ close(): void;
38
+ /**
39
+ * Creates the modal backdrop
40
+ */
41
+ private createBackdrop;
42
+ /**
43
+ * Sets up keyboard event listeners
44
+ */
45
+ private setupKeyboardListeners;
46
+ /**
47
+ * Removes keyboard event listeners
48
+ */
49
+ private removeKeyboardListeners;
50
+ /**
51
+ * Binds all event listeners
52
+ */
53
+ private bindEvents;
54
+ /**
55
+ * Renders the component
56
+ */
57
+ private render;
58
+ }
59
+ /**
60
+ * Conditionally defines the custom element if in a browser environment.
61
+ */
62
+ declare const defineDialog: (tagName?: string) => void;
63
+ /**
64
+ * Shows a dialog with the given configuration.
65
+ * This is the recommended way to display dialogs.
66
+ *
67
+ * @param config - The dialog configuration
68
+ * @returns The dialog element instance
69
+ *
70
+ * @example
71
+ * ```typescript
72
+ * import { dialogAdd } from '@liwe3/webcomponents';
73
+ *
74
+ * dialogAdd({
75
+ * title: 'Delete File',
76
+ * body: '<p>Are you sure you want to delete this file? This action cannot be undone.</p>',
77
+ * buttons: [
78
+ * {
79
+ * label: 'Delete',
80
+ * backgroundColor: '#dc3545',
81
+ * onclick: (dialog) => {
82
+ * console.log('File deleted');
83
+ * dialog.close();
84
+ * }
85
+ * },
86
+ * {
87
+ * label: 'Cancel',
88
+ * onclick: (dialog) => {
89
+ * console.log('Cancelled');
90
+ * dialog.close();
91
+ * }
92
+ * }
93
+ * ],
94
+ * modal: true,
95
+ * escToClose: true,
96
+ * clickToClose: true
97
+ * });
98
+ * ```
99
+ */
100
+ declare const dialogAdd: (config: DialogConfig) => DialogElement;
101
+ export { defineDialog, dialogAdd };
102
+ //# sourceMappingURL=Dialog.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Dialog.d.ts","sourceRoot":"","sources":["../src/Dialog.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,MAAM,MAAM,YAAY,GAAG;IAC1B,KAAK,EAAG,MAAM,CAAC;IACf,eAAe,CAAC,EAAG,MAAM,CAAC;IAC1B,OAAO,EAAG,CAAE,MAAM,CAAC,EAAG,aAAa,KAAM,IAAI,CAAC;CAC9C,CAAC;AAEF,MAAM,MAAM,YAAY,GAAG;IAC1B,KAAK,CAAC,EAAG,MAAM,CAAC;IAChB,IAAI,EAAG,MAAM,CAAC;IACd,OAAO,CAAC,EAAG,YAAY,EAAE,CAAC;IAC1B,KAAK,CAAC,EAAG,OAAO,CAAC;IACjB,UAAU,CAAC,EAAG,OAAO,CAAC;IACtB,YAAY,CAAC,EAAG,OAAO,CAAC;IACxB,QAAQ,CAAC,EAAG,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC;IACtC,OAAO,CAAC,EAAG,MAAM,CAAC;IAClB,OAAO,CAAC,EAAG,MAAM,IAAI,CAAC;CACtB,CAAC;AAEF,qBAAa,aAAc,SAAQ,WAAW;IACrC,UAAU,EAAG,UAAU,CAAC;IAChC,OAAO,CAAC,MAAM,CAQZ;IACF,OAAO,CAAC,QAAQ,CAAC,CAAe;IAChC,OAAO,CAAC,aAAa,CAAC,CAAiC;IACvD,OAAO,CAAC,WAAW,CAAmB;;IAOtC,iBAAiB,IAAM,IAAI;IAK3B,oBAAoB,IAAM,IAAI;IAO9B;;OAEG;IACH,IAAI,CAAG,MAAM,EAAG,YAAY,GAAK,IAAI;IAyBrC;;OAEG;IACH,KAAK,IAAM,IAAI;IAyBf;;OAEG;IACH,OAAO,CAAC,cAAc;IA2BtB;;OAEG;IACH,OAAO,CAAC,sBAAsB;IAW9B;;OAEG;IACH,OAAO,CAAC,uBAAuB;IAO/B;;OAEG;IACH,OAAO,CAAC,UAAU;IA+BlB;;OAEG;IACH,OAAO,CAAC,MAAM;CAyNd;AAED;;GAEG;AACH,QAAA,MAAM,YAAY,GAAK,UAAU,MAAuB,KAAK,IAI5D,CAAC;AA4BF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoCG;AACH,QAAA,MAAM,SAAS,GAAK,QAAS,YAAY,KAAK,aAc7C,CAAC;AAEF,OAAO,EAAE,YAAY,EAAE,SAAS,EAAE,CAAC"}