@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.
- package/dist/AIMarkdownEditor.d.ts +35 -0
- package/dist/AIMarkdownEditor.d.ts.map +1 -0
- package/dist/AIMarkdownEditor.js +412 -0
- package/dist/AIMarkdownEditor.js.map +1 -0
- package/dist/AITextEditor.d.ts +10 -0
- package/dist/AITextEditor.d.ts.map +1 -1
- package/dist/AITextEditor.js +63 -27
- package/dist/AITextEditor.js.map +1 -1
- package/dist/ButtonToolbar.d.ts +35 -0
- package/dist/ButtonToolbar.d.ts.map +1 -0
- package/dist/ButtonToolbar.js +220 -0
- package/dist/ButtonToolbar.js.map +1 -0
- package/dist/CheckList.d.ts +31 -0
- package/dist/CheckList.d.ts.map +1 -0
- package/dist/CheckList.js +336 -0
- package/dist/CheckList.js.map +1 -0
- package/dist/ChunkUploader.d.ts +22 -0
- package/dist/ChunkUploader.d.ts.map +1 -1
- package/dist/ChunkUploader.js +245 -103
- package/dist/ChunkUploader.js.map +1 -1
- package/dist/ComicBalloon.d.ts +82 -0
- package/dist/ComicBalloon.d.ts.map +1 -0
- package/dist/ComicBalloon.js +346 -0
- package/dist/ComicBalloon.js.map +1 -0
- package/dist/Dialog.d.ts +102 -0
- package/dist/Dialog.d.ts.map +1 -0
- package/dist/Dialog.js +299 -0
- package/dist/Dialog.js.map +1 -0
- package/dist/MarkdownPreview.d.ts +25 -0
- package/dist/MarkdownPreview.d.ts.map +1 -0
- package/dist/MarkdownPreview.js +147 -0
- package/dist/MarkdownPreview.js.map +1 -0
- package/dist/ResizableCropper.d.ts +158 -0
- package/dist/ResizableCropper.d.ts.map +1 -0
- package/dist/ResizableCropper.js +562 -0
- package/dist/ResizableCropper.js.map +1 -0
- package/dist/SmartSelect.d.ts +1 -0
- package/dist/SmartSelect.d.ts.map +1 -1
- package/dist/SmartSelect.js +45 -2
- package/dist/SmartSelect.js.map +1 -1
- package/dist/index.d.ts +16 -9
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +52 -29
- package/dist/index.js.map +1 -1
- package/package.json +33 -3
- package/src/AIMarkdownEditor.ts +568 -0
- package/src/AITextEditor.ts +97 -2
- package/src/ButtonToolbar.ts +302 -0
- package/src/CheckList.ts +438 -0
- package/src/ChunkUploader.ts +837 -623
- package/src/ComicBalloon.ts +709 -0
- package/src/Dialog.ts +510 -0
- package/src/MarkdownPreview.ts +213 -0
- package/src/ResizableCropper.ts +1099 -0
- package/src/SmartSelect.ts +48 -2
- 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":"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"}
|
package/dist/Dialog.d.ts
ADDED
|
@@ -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"}
|