mi-float-robot 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,658 @@
1
+ var v = Object.defineProperty, x = Object.defineProperties;
2
+ var D = Object.getOwnPropertyDescriptors;
3
+ var g = Object.getOwnPropertySymbols;
4
+ var L = Object.prototype.hasOwnProperty, z = Object.prototype.propertyIsEnumerable;
5
+ var p = (o, t, e) => t in o ? v(o, t, { enumerable: !0, configurable: !0, writable: !0, value: e }) : o[t] = e, l = (o, t) => {
6
+ for (var e in t || (t = {}))
7
+ L.call(t, e) && p(o, e, t[e]);
8
+ if (g)
9
+ for (var e of g(t))
10
+ z.call(t, e) && p(o, e, t[e]);
11
+ return o;
12
+ }, f = (o, t) => x(o, D(t));
13
+ const I = `
14
+ :host {
15
+ all: initial;
16
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'PingFang SC', 'Microsoft YaHei', sans-serif;
17
+ }
18
+
19
+ .robot-icon-box {
20
+ user-select: none;
21
+ touch-action: none;
22
+ position: fixed;
23
+ z-index: 4000;
24
+ transition: transform 0.3s ease;
25
+ display: flex;
26
+ align-items: center;
27
+ justify-content: center;
28
+ padding: 8px;
29
+ box-sizing: border-box;
30
+ }
31
+
32
+ .robot-icon-image {
33
+ display: block;
34
+ max-width: 100%;
35
+ height: auto;
36
+ object-fit: contain;
37
+ }
38
+
39
+ .robot-drag-mask {
40
+ position: fixed;
41
+ top: 0;
42
+ left: 0;
43
+ width: 100%;
44
+ height: 100%;
45
+ background: rgba(0, 0, 0, 0.3);
46
+ z-index: 3999;
47
+ }
48
+
49
+ .robot-trash-icon {
50
+ position: fixed;
51
+ right: 20px;
52
+ top: 50%;
53
+ transform: translateY(-50%);
54
+ font-size: 40px;
55
+ padding: 10px;
56
+ background: rgba(0, 0, 0, 0.6);
57
+ border-radius: 8px;
58
+ cursor: pointer;
59
+ transition: all 0.2s;
60
+ z-index: 4000;
61
+ }
62
+
63
+ .robot-trash-icon.active {
64
+ transform: translateY(-50%) scale(1.2);
65
+ background: #ff0000;
66
+ }
67
+
68
+ .robot-drawer-container {
69
+ position: fixed;
70
+ left: 0;
71
+ top: 0;
72
+ display: flex;
73
+ flex-direction: column;
74
+ background-color: #ffffff;
75
+ z-index: 4000;
76
+ box-shadow: -2px 0 8px rgba(0, 0, 0, 0.15);
77
+ overflow: hidden;
78
+ border-radius: 8px;
79
+ transition: width 0.3s ease, height 0.3s ease;
80
+ }
81
+
82
+ .robot-drawer-container.drawer-dragging {
83
+ transition: none !important;
84
+ }
85
+
86
+ .drawer-header {
87
+ flex: none;
88
+ display: flex;
89
+ align-items: center;
90
+ justify-content: space-between;
91
+ height: 40px;
92
+ padding: 0 10px 0 14px;
93
+ background: #f5f7fa;
94
+ border-bottom: 1px solid #e4e7ed;
95
+ cursor: move;
96
+ user-select: none;
97
+ touch-action: none;
98
+ z-index: 10001;
99
+ }
100
+
101
+ .drawer-header-title {
102
+ font-size: 14px;
103
+ font-weight: 600;
104
+ color: #303133;
105
+ white-space: nowrap;
106
+ overflow: hidden;
107
+ text-overflow: ellipsis;
108
+ }
109
+
110
+ .drawer-controls {
111
+ display: flex;
112
+ align-items: center;
113
+ gap: 4px;
114
+ }
115
+
116
+ .drawer-control-btn {
117
+ width: 26px;
118
+ height: 26px;
119
+ border: none;
120
+ background: rgba(255, 255, 255, 0.92);
121
+ color: #606266;
122
+ font-size: 16px;
123
+ line-height: 1;
124
+ cursor: pointer;
125
+ border-radius: 4px;
126
+ box-shadow: 0 1px 4px rgba(0, 0, 0, 0.12);
127
+ transition: background 0.2s ease, color 0.2s ease;
128
+ }
129
+
130
+ .drawer-control-btn:hover {
131
+ background: #e4e7ed;
132
+ }
133
+
134
+ .drawer-control-btn--close:hover {
135
+ background: #f56c6c;
136
+ color: #fff;
137
+ }
138
+
139
+ .drawer-body {
140
+ position: relative;
141
+ flex: 1;
142
+ min-height: 0;
143
+ width: 100%;
144
+ }
145
+
146
+ .robot-iframe {
147
+ width: 100%;
148
+ height: 100%;
149
+ border: none;
150
+ display: block;
151
+ }
152
+
153
+ .robot-drawer-container.drawer-dragging .robot-iframe {
154
+ pointer-events: none;
155
+ }
156
+
157
+ .robot-loading-mask {
158
+ position: absolute;
159
+ top: 0;
160
+ left: 0;
161
+ right: 0;
162
+ bottom: 0;
163
+ display: flex;
164
+ align-items: center;
165
+ justify-content: center;
166
+ background: #ffffff;
167
+ z-index: 9000;
168
+ }
169
+
170
+ .robot-loading-spinner {
171
+ width: 28px;
172
+ height: 28px;
173
+ border: 3px solid #dce6f0;
174
+ border-top-color: #409eff;
175
+ border-radius: 50%;
176
+ animation: float-robot-spin 0.8s linear infinite;
177
+ }
178
+
179
+ @keyframes float-robot-spin {
180
+ to { transform: rotate(360deg); }
181
+ }
182
+
183
+ .drawer-resize {
184
+ position: absolute;
185
+ z-index: 10000;
186
+ touch-action: none;
187
+ }
188
+
189
+ .drawer-resize-w { left: 0; top: 0; bottom: 0; width: 6px; cursor: ew-resize; }
190
+ .drawer-resize-e { right: 0; top: 0; bottom: 0; width: 6px; cursor: ew-resize; }
191
+ .drawer-resize-h { left: 0; right: 0; bottom: 0; height: 6px; cursor: ns-resize; }
192
+ .drawer-resize-sw { left: 0; bottom: 0; width: 16px; height: 16px; cursor: nesw-resize; }
193
+ .drawer-resize-se { right: 0; bottom: 0; width: 16px; height: 16px; cursor: nwse-resize; }
194
+
195
+ .minimized-chat {
196
+ position: fixed;
197
+ right: 24px;
198
+ bottom: 24px;
199
+ z-index: 4001;
200
+ display: inline-flex;
201
+ align-items: center;
202
+ height: 40px;
203
+ padding: 0 14px;
204
+ border: 1px solid #d9e6ff;
205
+ border-radius: 20px;
206
+ background: #ffffff;
207
+ color: #315b9d;
208
+ box-shadow: 0 6px 18px rgba(28, 67, 128, 0.2);
209
+ cursor: pointer;
210
+ font-size: 14px;
211
+ font-family: inherit;
212
+ transition: box-shadow 0.2s ease, transform 0.2s ease;
213
+ }
214
+
215
+ .minimized-chat:hover {
216
+ transform: translateY(-2px);
217
+ box-shadow: 0 8px 22px rgba(28, 67, 128, 0.28);
218
+ }
219
+
220
+ .minimized-chat:focus {
221
+ outline: none;
222
+ box-shadow: 0 0 0 2px rgba(64, 158, 255, 0.25), 0 6px 18px rgba(28, 67, 128, 0.2);
223
+ }
224
+ `, _ = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64">
225
+ <rect width="64" height="64" rx="14" fill="#409eff"/>
226
+ <rect x="27" y="10" width="10" height="6" rx="3" fill="#c7ddf5"/>
227
+ <circle cx="23" cy="30" r="5" fill="#ffffff"/>
228
+ <circle cx="41" cy="30" r="5" fill="#ffffff"/>
229
+ <rect x="24" y="42" width="16" height="5" rx="2.5" fill="#ffffff"/>
230
+ </svg>`, u = `data:image/svg+xml,${encodeURIComponent(_)}`;
231
+ class E {
232
+ /**
233
+ * 是否显示机器人图标。
234
+ * @returns {Promise<boolean>|boolean}
235
+ */
236
+ async getSwitch() {
237
+ return !0;
238
+ }
239
+ /**
240
+ * 获取机器人配置;返回 null 表示没有可用配置(不显示)。
241
+ * @returns {Promise<Object|null>|Object|null}
242
+ *
243
+ * 约定返回结构:
244
+ * {
245
+ * showRobot: true, // 是否显示机器人图标
246
+ * avatar: 'https://...', // 头像完整 URL(可选,缺省用默认头像)
247
+ * style: { // 图标样式(全部可选)
248
+ * scale: 1,
249
+ * width: 80,
250
+ * height: 100,
251
+ * opacity: 1,
252
+ * border: 'none',
253
+ * shadowLevel: 'light', // none | light | medium | strong
254
+ * borderRadius: 0,
255
+ * borderRadiusUnit: 'px'
256
+ * }
257
+ * }
258
+ */
259
+ async getConfig() {
260
+ return null;
261
+ }
262
+ }
263
+ class H extends E {
264
+ constructor(t = {}) {
265
+ super(), this.switchUrl = t.switchUrl || t.switch_url || "", this.configUrl = t.configUrl || t.config_url || "", this.fetchImpl = t.fetch || ((e) => window.fetch(e, { credentials: "include" }));
266
+ }
267
+ async getSwitch() {
268
+ if (!this.switchUrl) return !0;
269
+ const t = await this.fetchImpl(this.switchUrl), e = await this._toJson(t);
270
+ return this._normalizeSwitch(e);
271
+ }
272
+ async getConfig() {
273
+ if (!this.configUrl) return null;
274
+ const t = await this.fetchImpl(this.configUrl), e = await this._toJson(t);
275
+ return this._normalizeConfig(e);
276
+ }
277
+ async _toJson(t) {
278
+ return t && typeof t.json == "function" ? t.json() : t;
279
+ }
280
+ _normalizeSwitch(t) {
281
+ if (typeof t == "boolean") return t;
282
+ if (t && typeof t == "object") {
283
+ if (typeof t.showRobot == "boolean") return t.showRobot;
284
+ if (typeof t.enabled == "boolean") return t.enabled;
285
+ if (t.value != null) {
286
+ const e = this._parseValue(t.value);
287
+ if (e && typeof e == "object") {
288
+ const i = Object.values(e);
289
+ return i.length > 0 && i.every((r) => Number(r) === 1);
290
+ }
291
+ return !!e;
292
+ }
293
+ }
294
+ return !0;
295
+ }
296
+ _normalizeConfig(t) {
297
+ if (!t) return null;
298
+ let e = t;
299
+ for (Array.isArray(e) && (e = e[0]); e && typeof e == "object" && !Object.prototype.hasOwnProperty.call(e, "avatar") && !Object.prototype.hasOwnProperty.call(e, "style") && !Object.prototype.hasOwnProperty.call(e, "showRobot"); ) {
300
+ if (Array.isArray(e.data)) {
301
+ e = e.data[0];
302
+ continue;
303
+ }
304
+ if (e.data && typeof e.data == "object") {
305
+ e = e.data;
306
+ continue;
307
+ }
308
+ if (e.result && typeof e.result == "object") {
309
+ e = e.result;
310
+ continue;
311
+ }
312
+ break;
313
+ }
314
+ return !e || typeof e != "object" ? null : e;
315
+ }
316
+ _parseValue(t) {
317
+ if (t == null) return t;
318
+ const e = String(t);
319
+ try {
320
+ return JSON.parse(e.replace(/'/g, '"'));
321
+ } catch (i) {
322
+ return t;
323
+ }
324
+ }
325
+ }
326
+ const m = 560, b = 400, S = "__FLOAT_ROBOT_CONFIG__";
327
+ function c() {
328
+ return typeof window != "undefined" && window[S] || {};
329
+ }
330
+ class $ extends HTMLElement {
331
+ constructor() {
332
+ super(), this.attachShadow({ mode: "open" }), this.imgWidth = 80, this.imgHeight = 100, this.imageAspectRatio = 1.25, this.drawerVisible = !1, this.drawerMinimized = !1, this.drawerLeft = null, this.drawerTop = null, this.drawerWidth = null, this.drawerHeight = null, this.drawerDrag = null, this.posX = 0, this.posY = 0, this.isDragging = !1, this.dragPointerId = null, this.startX = 0, this.startY = 0, this.initialX = 0, this.initialY = 0, this.hasDragged = !1, this.hasMoved = !1, this.dragMaskVisible = !1, this.isHidden = !1, this.isOverTrash = !1, this.windowWidth = 0, this.windowHeight = 0, this.originalPosX = 0, this.originalPosY = 0, this.showRobot = !1, this.robotAvatar = "", this.robotStyleConfig = null, this.robotShowEnabled = !0, this._switchEnabled = !0, this._configAvailable = !0, this._adapter = null, this.chatLoading = !1, this.chatLoadingTimer = null, this.resizeTimer = null, this._onIconDrag = (t) => this.onIconDrag(t), this._stopIconDrag = (t) => this.stopIconDrag(t), this._onDrawerDrag = (t) => this.onDrawerDrag(t), this._stopDrawerDrag = () => this.stopDrawerDrag(), this._handleResize = () => this.handleResize(), this._handleStorageChange = (t) => this.handleStorageChange(t), this._handleWindowBlur = () => this.handleWindowBlur(), this._chatReadyHandler = (t) => this.chatReadyHandler(t);
333
+ }
334
+ // ==================== 生命周期 ====================
335
+ connectedCallback() {
336
+ this.render(), window.addEventListener("message", this._chatReadyHandler), this.initRobot();
337
+ }
338
+ disconnectedCallback() {
339
+ this.removeIconDragListeners(), this.removeDrawerDragListeners(), window.removeEventListener("resize", this._handleResize), window.removeEventListener("storage", this._handleStorageChange), window.removeEventListener("blur", this._handleWindowBlur), window.removeEventListener("message", this._chatReadyHandler), this.chatLoadingTimer && (clearTimeout(this.chatLoadingTimer), this.chatLoadingTimer = null), this.resizeTimer && (clearTimeout(this.resizeTimer), this.resizeTimer = null);
340
+ }
341
+ // ==================== 配置解析 ====================
342
+ getAttr(t) {
343
+ return this.getAttribute(t) || "";
344
+ }
345
+ resolveChatUrl() {
346
+ const t = c();
347
+ return this.getAttr("chat-url") || t.chatUrl || "";
348
+ }
349
+ resolveAvatar() {
350
+ const t = c();
351
+ return this.getAttr("avatar") || t.avatar || u;
352
+ }
353
+ resolveAdapter() {
354
+ const t = c();
355
+ if (t.adapter) return t.adapter;
356
+ const e = this.getAttr("switch-url") || t.switchUrl || "", i = this.getAttr("config-url") || t.configUrl || "";
357
+ return e || i ? new H({ switchUrl: e, configUrl: i, fetch: t.fetch }) : null;
358
+ }
359
+ async initRobot() {
360
+ const t = this.resolveAdapter();
361
+ if (this._adapter = t, t) {
362
+ try {
363
+ this._switchEnabled = !!await t.getSwitch();
364
+ } catch (i) {
365
+ console.warn("[mi-float-robot] 获取机器人开关失败", i), this._switchEnabled = !1;
366
+ }
367
+ if (!this._switchEnabled) return;
368
+ try {
369
+ const i = await t.getConfig();
370
+ i ? this.applyConfig(i) : this._configAvailable = !1;
371
+ } catch (i) {
372
+ console.warn("[mi-float-robot] 获取机器人配置失败", i);
373
+ }
374
+ }
375
+ this.robotAvatar || (this.robotAvatar = this.resolveAvatar(), this.loadImageAspectRatio(this.robotAvatar));
376
+ let e = null;
377
+ try {
378
+ e = JSON.parse(localStorage.getItem("robotPosition"));
379
+ } catch (i) {
380
+ e = null;
381
+ }
382
+ e ? (this.posX = e.x * window.innerWidth, this.posY = e.y * window.innerHeight, this.isHidden = e.isHidden) : this.setInitialPosition(), this.restoreDrawerPosition(e), this.windowWidth = window.innerWidth, this.windowHeight = window.innerHeight, this.originalPosX = this.posX, this.originalPosY = this.posY, window.addEventListener("resize", this._handleResize), window.addEventListener("storage", this._handleStorageChange), window.addEventListener("blur", this._handleWindowBlur), this.updateRobotVisibility(), this.applyIconStyle();
383
+ }
384
+ applyConfig(t) {
385
+ t && (t.avatar && (this.robotAvatar = t.avatar, this.loadImageAspectRatio(t.avatar)), t.style && (this.robotStyleConfig = t.style), t.showRobot !== void 0 && (this.robotShowEnabled = t.showRobot), t.width && (this.imgWidth = t.width), t.height && (this.imgHeight = t.height), t.scale && (this.robotStyleConfig = f(l({}, this.robotStyleConfig || {}), { scale: t.scale })));
386
+ }
387
+ loadImageAspectRatio(t) {
388
+ const e = new Image();
389
+ e.onload = () => {
390
+ e.width > 0 && e.height > 0 && (this.imageAspectRatio = e.height / e.width);
391
+ }, e.onerror = () => {
392
+ }, e.src = t;
393
+ }
394
+ handleStorageChange(t) {
395
+ if (t.key === "robotConfigLive")
396
+ try {
397
+ const e = JSON.parse(t.newValue);
398
+ this.applyConfig(e), e.showRobot !== void 0 && (this._configAvailable = !0, this.robotShowEnabled = e.showRobot, this.updateRobotVisibility(), this.applyIconStyle());
399
+ } catch (e) {
400
+ console.warn("[mi-float-robot] 解析配置失败", e);
401
+ }
402
+ }
403
+ updateRobotVisibility() {
404
+ this.showRobot = this._switchEnabled && this._configAvailable && this.robotShowEnabled;
405
+ }
406
+ // ==================== 样式计算 ====================
407
+ currentScale() {
408
+ return this.robotStyleConfig && this.robotStyleConfig.scale || 1;
409
+ }
410
+ baseWidth() {
411
+ return this.robotStyleConfig && this.robotStyleConfig.width || this.imgWidth;
412
+ }
413
+ currentWidth() {
414
+ return this.baseWidth() * this.currentScale();
415
+ }
416
+ currentHeight() {
417
+ return this.baseWidth() * this.imageAspectRatio * this.currentScale();
418
+ }
419
+ applyIconStyle() {
420
+ const t = this.robotStyleConfig || {}, e = {
421
+ none: "none",
422
+ light: "0 2px 8px rgba(0, 0, 0, 0.08)",
423
+ medium: "0 4px 16px rgba(0, 0, 0, 0.12)",
424
+ strong: "0 6px 24px rgba(0, 0, 0, 0.18)"
425
+ }, i = t.width || this.imgWidth, r = t.scale || 1;
426
+ this.$icon.style.display = this.showRobot ? "flex" : "none", this.$icon.style.left = this.posX + "px", this.$icon.style.top = this.posY + "px", this.$icon.style.width = i + "px", this.$icon.style.height = "auto", this.$icon.style.border = t.border || "none", this.$icon.style.boxShadow = e[t.shadowLevel] || "none", this.$icon.style.opacity = t.opacity != null ? t.opacity : 1, this.$icon.style.transform = (this.isHidden ? "rotate(-90deg) " : "") + "scale(" + r + ")", this.$icon.style.cursor = "move";
427
+ let s = "0";
428
+ t.borderRadius !== void 0 && (s = typeof t.borderRadius == "string" ? t.borderRadius : (t.borderRadius || 0) + (t.borderRadiusUnit || "px")), this.$iconImage.style.width = i + "px", this.$iconImage.style.height = "auto", this.$iconImage.style.objectFit = "contain", this.$iconImage.style.borderRadius = s, this.$iconImage.src = this.robotAvatar || u;
429
+ }
430
+ defaultDrawerWidth() {
431
+ return Math.round(window.innerWidth * 0.8);
432
+ }
433
+ defaultDrawerHeight() {
434
+ return window.innerHeight;
435
+ }
436
+ applyDrawerStyle() {
437
+ const t = this.drawerWidth != null ? this.drawerWidth : this.defaultDrawerWidth(), e = this.drawerHeight != null ? this.drawerHeight : this.defaultDrawerHeight(), i = this.drawerLeft != null ? this.drawerLeft : window.innerWidth - t, r = this.drawerTop != null ? this.drawerTop : 0;
438
+ this.$drawer.style.left = i + "px", this.$drawer.style.top = r + "px", this.$drawer.style.width = t + "px", this.$drawer.style.height = e + "px";
439
+ }
440
+ applyDrawerVisibility() {
441
+ this.$drawer.style.display = this.drawerVisible && !this.drawerMinimized ? "flex" : "none", this.$minimized.style.display = this.drawerVisible && this.drawerMinimized ? "inline-flex" : "none";
442
+ }
443
+ // ==================== 抽屉交互 ====================
444
+ openDrawer() {
445
+ if (!this.hasMoved) {
446
+ if (this.isHidden) {
447
+ this.setInitialPosition(), this.isHidden = !1, this.applyIconStyle();
448
+ return;
449
+ }
450
+ this.drawerVisible || (this.chatLoading = !0, this.$loadingMask.style.display = "flex", this.chatLoadingTimer = setTimeout(() => this.finishChatLoading(), 3e4)), this.drawerVisible = !0, this.drawerMinimized = !1, this.$iframe.src || (this.$iframe.src = this.resolveChatUrl()), this.applyDrawerStyle(), this.applyDrawerVisibility();
451
+ }
452
+ }
453
+ closeDrawer() {
454
+ this.drawerVisible = !1, this.drawerMinimized = !1, this.applyDrawerVisibility(), this.finishChatLoading();
455
+ }
456
+ minimizeDrawer() {
457
+ this.drawerMinimized = !0, this.applyDrawerVisibility();
458
+ }
459
+ restoreDrawer() {
460
+ this.drawerMinimized = !1, this.drawerVisible = !0, this.applyDrawerVisibility();
461
+ }
462
+ finishChatLoading() {
463
+ this.chatLoading = !1, this.$loadingMask.style.display = "none", this.chatLoadingTimer && (clearTimeout(this.chatLoadingTimer), this.chatLoadingTimer = null);
464
+ }
465
+ chatReadyHandler(t) {
466
+ !t || !t.data || t.data.type !== "SMI_CHAT_READY" || this.$iframe && t.source !== this.$iframe.contentWindow || this.finishChatLoading();
467
+ }
468
+ // ==================== 图标拖拽 ====================
469
+ setInitialPosition() {
470
+ this.originalPosX = window.innerWidth - window.innerWidth * 0.02 - this.currentWidth(), this.originalPosY = window.innerHeight - window.innerHeight * 0.08 - this.currentHeight(), this.posX = this.originalPosX, this.posY = this.originalPosY;
471
+ }
472
+ handleResize() {
473
+ clearTimeout(this.resizeTimer), this.resizeTimer = setTimeout(() => {
474
+ if (this.isHidden) {
475
+ const r = this.$icon.getBoundingClientRect();
476
+ this.posX = window.innerWidth - Math.max(40, r.width * 0.3), this.posY = (window.innerHeight - r.height) / 2, this.applyIconStyle();
477
+ return;
478
+ }
479
+ const t = window.innerWidth, e = window.innerHeight;
480
+ if (this.hasDragged) {
481
+ const r = this.posX / this.windowWidth, s = this.posY / this.windowHeight;
482
+ this.posX = t * r, this.posY = e * s;
483
+ } else {
484
+ const r = t / this.windowWidth, s = e / this.windowHeight;
485
+ this.posX = this.originalPosX * r, this.posY = this.originalPosY * s;
486
+ }
487
+ const i = this.$icon.offsetWidth || this.currentWidth();
488
+ this.posX = Math.max(0, Math.min(t - i, this.posX)), this.posY = Math.min(e - this.currentHeight(), Math.max(0, this.posY)), this.windowWidth = t, this.windowHeight = e, this.originalPosX = this.posX, this.originalPosY = this.posY, this.applyIconStyle();
489
+ }, 100);
490
+ }
491
+ getEventPoint(t) {
492
+ return t.touches && t.touches.length ? t.touches[0] : t.changedTouches && t.changedTouches.length ? t.changedTouches[0] : t;
493
+ }
494
+ getEventPointerId(t) {
495
+ return t.pointerId !== void 0 ? t.pointerId : "touch";
496
+ }
497
+ startIconDrag(t) {
498
+ if (this.isHidden || this.isDragging) return;
499
+ const e = this.getEventPoint(t);
500
+ if (t.preventDefault(), t.pointerId !== void 0 && t.currentTarget && t.currentTarget.setPointerCapture)
501
+ try {
502
+ t.currentTarget.setPointerCapture(t.pointerId);
503
+ } catch (i) {
504
+ }
505
+ this.isDragging = !0, this.dragPointerId = this.getEventPointerId(t), this.startX = e.clientX, this.startY = e.clientY, this.initialX = this.posX, this.initialY = this.posY, this.dragMaskVisible = !0, this.$mask.style.display = "block", document.addEventListener("pointermove", this._onIconDrag, { passive: !1 }), document.addEventListener("pointerup", this._stopIconDrag), document.addEventListener("pointercancel", this._stopIconDrag), document.addEventListener("touchmove", this._onIconDrag, { passive: !1 }), document.addEventListener("touchend", this._stopIconDrag), document.addEventListener("touchcancel", this._stopIconDrag);
506
+ }
507
+ onIconDrag(t) {
508
+ if (!this.isDragging || this.getEventPointerId(t) !== this.dragPointerId) return;
509
+ const e = this.getEventPoint(t);
510
+ t.preventDefault();
511
+ const i = e.clientX - this.startX, r = e.clientY - this.startY, s = window.innerWidth - this.currentWidth(), a = window.innerHeight - this.currentHeight();
512
+ this.posX = Math.min(s, Math.max(0, this.initialX + i)), this.posY = Math.min(a, Math.max(0, this.initialY + r)), (i !== 0 || r !== 0) && (this.hasMoved = !0);
513
+ const n = this.$trash.getBoundingClientRect();
514
+ this.isOverTrash = e.clientX >= n.left && e.clientX <= n.right && e.clientY >= n.top && e.clientY <= n.bottom, this.$trash.classList.toggle("active", this.isOverTrash), this.applyIconStyle();
515
+ }
516
+ stopIconDrag(t) {
517
+ if (!this.isDragging || this.getEventPointerId(t) !== this.dragPointerId) return;
518
+ const e = this.getEventPoint(t);
519
+ this.isDragging = !1, this.dragPointerId = null, this.hasDragged = !0, this.removeIconDragListeners();
520
+ const i = this.$trash.getBoundingClientRect();
521
+ if (e.clientX >= i.left && e.clientX <= i.right && e.clientY >= i.top && e.clientY <= i.bottom) {
522
+ this.isHidden = !0;
523
+ const r = this.$icon.getBoundingClientRect();
524
+ this.posY = (window.innerHeight - r.height) / 2, this.posX = window.innerWidth - Math.max(40, r.width * 0.3);
525
+ }
526
+ this.dragMaskVisible = !1, this.isOverTrash = !1, this.$mask.style.display = "none", this.$trash.classList.remove("active"), setTimeout(() => {
527
+ this.hasMoved = !1;
528
+ }, 100), this.saveIconPosition(), this.applyIconStyle();
529
+ }
530
+ removeIconDragListeners() {
531
+ document.removeEventListener("pointermove", this._onIconDrag), document.removeEventListener("pointerup", this._stopIconDrag), document.removeEventListener("pointercancel", this._stopIconDrag), document.removeEventListener("touchmove", this._onIconDrag), document.removeEventListener("touchend", this._stopIconDrag), document.removeEventListener("touchcancel", this._stopIconDrag);
532
+ }
533
+ saveIconPosition() {
534
+ try {
535
+ const t = JSON.parse(localStorage.getItem("robotPosition") || "{}");
536
+ t.x = this.posX / window.innerWidth, t.y = this.posY / window.innerHeight, t.isHidden = this.isHidden, localStorage.setItem("robotPosition", JSON.stringify(t));
537
+ } catch (t) {
538
+ console.warn("[mi-float-robot] 保存图标位置失败", t);
539
+ }
540
+ }
541
+ // ==================== 抽屉拖拽 / 缩放 ====================
542
+ restoreDrawerPosition(t) {
543
+ if (!t || !t.drawer) return;
544
+ const e = t.drawer, i = Math.max(m, Math.min(window.innerWidth, Number(e.width) || this.defaultDrawerWidth())), r = Math.max(b, Math.min(window.innerHeight, Number(e.height) || this.defaultDrawerHeight())), s = Math.max(0, Math.min(window.innerWidth - i, (Number(e.x) || 0) * window.innerWidth)), a = Math.max(0, Math.min(window.innerHeight - r, (Number(e.y) || 0) * window.innerHeight));
545
+ this.drawerWidth = i, this.drawerHeight = r, this.drawerLeft = s, this.drawerTop = a;
546
+ }
547
+ startDrawerDrag(t, e) {
548
+ if (t.preventDefault(), t.stopPropagation(), t.pointerId !== void 0 && t.currentTarget && t.currentTarget.setPointerCapture)
549
+ try {
550
+ t.currentTarget.setPointerCapture(t.pointerId);
551
+ } catch (n) {
552
+ }
553
+ const i = this.drawerWidth != null ? this.drawerWidth : this.defaultDrawerWidth(), r = this.drawerHeight != null ? this.drawerHeight : this.defaultDrawerHeight(), s = this.drawerLeft != null ? this.drawerLeft : window.innerWidth - i, a = this.drawerTop != null ? this.drawerTop : 0;
554
+ this.drawerDrag = { mode: e, startX: t.clientX, startY: t.clientY, left: s, top: a, width: i, height: r }, this.$drawer.classList.add("drawer-dragging"), document.addEventListener("pointermove", this._onDrawerDrag), document.addEventListener("pointerup", this._stopDrawerDrag), document.addEventListener("pointercancel", this._stopDrawerDrag);
555
+ }
556
+ onDrawerDrag(t) {
557
+ if (!this.drawerDrag) return;
558
+ t.preventDefault();
559
+ const e = this.drawerDrag, i = t.clientX - e.startX, r = t.clientY - e.startY, s = m, a = b;
560
+ if (e.mode === "move") {
561
+ const n = Math.max(0, Math.min(window.innerWidth - e.width, e.left + i)), h = Math.max(0, Math.min(window.innerHeight - e.height, e.top + r));
562
+ this.drawerLeft = n, this.drawerTop = h;
563
+ } else if (e.mode === "resize-w") {
564
+ const n = e.left + e.width;
565
+ let h = Math.max(0, e.left + i), d = n - h;
566
+ d < s && (d = s, h = n - s), this.drawerLeft = h, this.drawerWidth = d;
567
+ } else if (e.mode === "resize-h")
568
+ this.drawerHeight = Math.max(a, Math.min(window.innerHeight, e.height + r));
569
+ else if (e.mode === "resize-e")
570
+ this.drawerWidth = Math.max(s, Math.min(window.innerWidth - e.left, e.width + i));
571
+ else if (e.mode === "resize-sw") {
572
+ const n = e.left + e.width;
573
+ let h = Math.max(0, e.left + i), d = n - h;
574
+ d < s && (d = s, h = n - s);
575
+ const y = Math.max(a, Math.min(window.innerHeight, e.height + r));
576
+ this.drawerLeft = h, this.drawerWidth = d, this.drawerHeight = y;
577
+ } else e.mode === "resize-se" && (this.drawerWidth = Math.max(s, Math.min(window.innerWidth - e.left, e.width + i)), this.drawerHeight = Math.max(a, Math.min(window.innerHeight, e.height + r)));
578
+ this.applyDrawerStyle();
579
+ }
580
+ stopDrawerDrag() {
581
+ this.drawerDrag && (this.drawerDrag = null, this.$drawer.classList.remove("drawer-dragging"), this.removeDrawerDragListeners(), this.saveDrawerPosition());
582
+ }
583
+ removeDrawerDragListeners() {
584
+ document.removeEventListener("pointermove", this._onDrawerDrag), document.removeEventListener("pointerup", this._stopDrawerDrag), document.removeEventListener("pointercancel", this._stopDrawerDrag);
585
+ }
586
+ handleWindowBlur() {
587
+ this.drawerDrag && (this.drawerDrag = null, this.$drawer.classList.remove("drawer-dragging"), this.removeDrawerDragListeners()), this.isDragging && (this.isDragging = !1, this.dragPointerId = null, this.removeIconDragListeners(), this.dragMaskVisible = !1, this.isOverTrash = !1, this.$mask.style.display = "none", this.$trash.classList.remove("active"));
588
+ }
589
+ saveDrawerPosition() {
590
+ const t = this.drawerWidth != null ? this.drawerWidth : this.defaultDrawerWidth(), e = this.drawerHeight != null ? this.drawerHeight : this.defaultDrawerHeight(), i = this.drawerLeft != null ? this.drawerLeft : window.innerWidth - t, r = this.drawerTop != null ? this.drawerTop : 0;
591
+ try {
592
+ const s = JSON.parse(localStorage.getItem("robotPosition") || "{}");
593
+ s.drawer = { x: i / window.innerWidth, y: r / window.innerHeight, width: t, height: e }, localStorage.setItem("robotPosition", JSON.stringify(s));
594
+ } catch (s) {
595
+ console.warn("[mi-float-robot] 保存抽屉位置失败", s);
596
+ }
597
+ }
598
+ // ==================== 渲染 ====================
599
+ render() {
600
+ const t = document.createElement("style");
601
+ t.textContent = I, this.shadowRoot.appendChild(t);
602
+ const e = document.createElement("div");
603
+ e.innerHTML = `
604
+ <div class="robot-icon-box" title="智能助手" style="display:none">
605
+ <img class="robot-icon-image" alt="智能助手" />
606
+ </div>
607
+ <div class="robot-drag-mask" style="display:none">
608
+ <div class="robot-trash-icon">🗑️</div>
609
+ </div>
610
+ <div class="robot-drawer-container" style="display:none">
611
+ <div class="drawer-header">
612
+ <span class="drawer-header-title">智能问答</span>
613
+ <div class="drawer-controls">
614
+ <button type="button" class="drawer-control-btn" title="最小化" aria-label="最小化">—</button>
615
+ <button type="button" class="drawer-control-btn drawer-control-btn--close" title="关闭" aria-label="关闭">×</button>
616
+ </div>
617
+ </div>
618
+ <div class="drawer-body">
619
+ <iframe class="robot-iframe" title="智能问答"></iframe>
620
+ <div class="robot-loading-mask" style="display:none"><span class="robot-loading-spinner"></span></div>
621
+ </div>
622
+ <div class="drawer-resize drawer-resize-w"></div>
623
+ <div class="drawer-resize drawer-resize-e"></div>
624
+ <div class="drawer-resize drawer-resize-h"></div>
625
+ <div class="drawer-resize drawer-resize-sw"></div>
626
+ <div class="drawer-resize drawer-resize-se"></div>
627
+ </div>
628
+ <button type="button" class="minimized-chat" title="恢复智能问答" style="display:none">
629
+ <span>智能问答</span>
630
+ </button>
631
+ `, this.shadowRoot.appendChild(e), this.$icon = e.querySelector(".robot-icon-box"), this.$iconImage = e.querySelector(".robot-icon-image"), this.$mask = e.querySelector(".robot-drag-mask"), this.$trash = e.querySelector(".robot-trash-icon"), this.$drawer = e.querySelector(".robot-drawer-container"), this.$drawerHeader = e.querySelector(".drawer-header"), this.$minimizeBtn = e.querySelector('.drawer-control-btn[title="最小化"]'), this.$closeBtn = e.querySelector(".drawer-control-btn--close"), this.$iframe = e.querySelector(".robot-iframe"), this.$loadingMask = e.querySelector(".robot-loading-mask"), this.$minimized = e.querySelector(".minimized-chat"), this.bindEvents();
632
+ }
633
+ bindEvents() {
634
+ this.$icon.addEventListener("pointerdown", (t) => this.startIconDrag(t)), this.$icon.addEventListener("touchstart", (t) => this.startIconDrag(t)), this.$icon.addEventListener("click", () => this.openDrawer()), this.$drawerHeader.addEventListener("pointerdown", (t) => this.startDrawerDrag(t, "move")), this.$minimizeBtn.addEventListener("pointerdown", (t) => t.stopPropagation()), this.$minimizeBtn.addEventListener("click", () => this.minimizeDrawer()), this.$closeBtn.addEventListener("pointerdown", (t) => t.stopPropagation()), this.$closeBtn.addEventListener("click", () => this.closeDrawer()), this.$drawer.querySelector(".drawer-resize-w").addEventListener("pointerdown", (t) => this.startDrawerDrag(t, "resize-w")), this.$drawer.querySelector(".drawer-resize-e").addEventListener("pointerdown", (t) => this.startDrawerDrag(t, "resize-e")), this.$drawer.querySelector(".drawer-resize-h").addEventListener("pointerdown", (t) => this.startDrawerDrag(t, "resize-h")), this.$drawer.querySelector(".drawer-resize-sw").addEventListener("pointerdown", (t) => this.startDrawerDrag(t, "resize-sw")), this.$drawer.querySelector(".drawer-resize-se").addEventListener("pointerdown", (t) => this.startDrawerDrag(t, "resize-se")), this.$minimized.addEventListener("click", () => this.restoreDrawer());
635
+ }
636
+ }
637
+ const w = "__FLOAT_ROBOT_CONFIG__", W = "x-float-robot";
638
+ function T(o = {}) {
639
+ if (typeof window == "undefined") return;
640
+ const t = window[w] || {};
641
+ window[w] = l(l({}, t), o);
642
+ }
643
+ function P() {
644
+ return typeof window != "undefined" && window[w] || {};
645
+ }
646
+ function M(o = W) {
647
+ typeof window != "undefined" && (window.customElements.get(o) || window.customElements.define(o, $));
648
+ }
649
+ M();
650
+ export {
651
+ H as FetchFloatRobotAdapter,
652
+ E as FloatRobotAdapter,
653
+ $ as FloatRobotElement,
654
+ T as configure,
655
+ M as defineFloatRobot,
656
+ P as getConfig
657
+ };
658
+ //# sourceMappingURL=mi-float-robot.js.map