@mushi-mushi/web 1.2.1 → 1.3.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.
- package/CONTRIBUTING.md +11 -0
- package/dist/index.cjs +490 -84
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +40 -1
- package/dist/index.d.ts +40 -1
- package/dist/index.js +490 -84
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
package/dist/index.js
CHANGED
|
@@ -45,10 +45,20 @@ var en = {
|
|
|
45
45
|
heading: "Tell us more",
|
|
46
46
|
descriptionPlaceholder: "Describe what happened\u2026",
|
|
47
47
|
screenshotButton: "Attach Screenshot",
|
|
48
|
-
screenshotAttached: "Screenshot attached",
|
|
48
|
+
screenshotAttached: "Screenshot attached \u2713",
|
|
49
|
+
screenshotCapturing: "Taking screenshot\u2026",
|
|
50
|
+
screenshotFailed: "Couldn't capture \u2014 describe it instead",
|
|
49
51
|
elementButton: "Select Element",
|
|
50
|
-
elementSelected: "Element selected",
|
|
51
|
-
|
|
52
|
+
elementSelected: "Element selected \u2713",
|
|
53
|
+
elementCapturing: "Click anything on the page\u2026",
|
|
54
|
+
elementSelectorHint: "Click any element \xB7 Esc to cancel",
|
|
55
|
+
optional: "(optional)",
|
|
56
|
+
tooShort: "A bit more detail helps us fix it faster",
|
|
57
|
+
examplePrompts: [
|
|
58
|
+
"The save button does nothing",
|
|
59
|
+
"Page froze for 10 seconds",
|
|
60
|
+
"Layout looks broken here"
|
|
61
|
+
]
|
|
52
62
|
}
|
|
53
63
|
};
|
|
54
64
|
|
|
@@ -95,10 +105,20 @@ var ja = {
|
|
|
95
105
|
heading: "\u8A73\u7D30\u3092\u6559\u3048\u3066\u304F\u3060\u3055\u3044",
|
|
96
106
|
descriptionPlaceholder: "\u4F55\u304C\u8D77\u304D\u305F\u304B\u8AAC\u660E\u3057\u3066\u304F\u3060\u3055\u3044\u2026",
|
|
97
107
|
screenshotButton: "\u30B9\u30AF\u30EA\u30FC\u30F3\u30B7\u30E7\u30C3\u30C8\u6DFB\u4ED8",
|
|
98
|
-
screenshotAttached: "\u30B9\u30AF\u30EA\u30FC\u30F3\u30B7\u30E7\u30C3\u30C8\u6DFB\u4ED8\u6E08\u307F",
|
|
108
|
+
screenshotAttached: "\u30B9\u30AF\u30EA\u30FC\u30F3\u30B7\u30E7\u30C3\u30C8\u6DFB\u4ED8\u6E08\u307F \u2713",
|
|
109
|
+
screenshotCapturing: "\u30B9\u30AF\u30EA\u30FC\u30F3\u30B7\u30E7\u30C3\u30C8\u64AE\u5F71\u4E2D\u2026",
|
|
110
|
+
screenshotFailed: "\u53D6\u5F97\u3067\u304D\u307E\u305B\u3093\u3067\u3057\u305F \u2014 \u6587\u5B57\u3067\u6559\u3048\u3066\u304F\u3060\u3055\u3044",
|
|
99
111
|
elementButton: "\u8981\u7D20\u3092\u9078\u629E",
|
|
100
|
-
elementSelected: "\u8981\u7D20\u9078\u629E\u6E08\u307F",
|
|
101
|
-
|
|
112
|
+
elementSelected: "\u8981\u7D20\u9078\u629E\u6E08\u307F \u2713",
|
|
113
|
+
elementCapturing: "\u30DA\u30FC\u30B8\u4E0A\u306E\u8981\u7D20\u3092\u30AF\u30EA\u30C3\u30AF\u2026",
|
|
114
|
+
elementSelectorHint: "\u8981\u7D20\u3092\u30AF\u30EA\u30C3\u30AF \xB7 Esc \u3067\u30AD\u30E3\u30F3\u30BB\u30EB",
|
|
115
|
+
optional: "\uFF08\u4EFB\u610F\uFF09",
|
|
116
|
+
tooShort: "\u3082\u3046\u5C11\u3057\u8A73\u3057\u304F\u6559\u3048\u3066\u304F\u3060\u3055\u3044",
|
|
117
|
+
examplePrompts: [
|
|
118
|
+
"\u4FDD\u5B58\u30DC\u30BF\u30F3\u304C\u53CD\u5FDC\u3057\u306A\u3044",
|
|
119
|
+
"\u30DA\u30FC\u30B8\u304C10\u79D2\u56FA\u307E\u3063\u305F",
|
|
120
|
+
"\u30EC\u30A4\u30A2\u30A6\u30C8\u304C\u5D29\u308C\u3066\u3044\u308B"
|
|
121
|
+
]
|
|
102
122
|
}
|
|
103
123
|
};
|
|
104
124
|
|
|
@@ -145,10 +165,20 @@ var th = {
|
|
|
145
165
|
heading: "\u0E1A\u0E2D\u0E01\u0E40\u0E23\u0E32\u0E40\u0E1E\u0E34\u0E48\u0E21\u0E40\u0E15\u0E34\u0E21",
|
|
146
166
|
descriptionPlaceholder: "\u0E2D\u0E18\u0E34\u0E1A\u0E32\u0E22\u0E2A\u0E34\u0E48\u0E07\u0E17\u0E35\u0E48\u0E40\u0E01\u0E34\u0E14\u0E02\u0E36\u0E49\u0E19\u2026",
|
|
147
167
|
screenshotButton: "\u0E41\u0E19\u0E1A\u0E2A\u0E01\u0E23\u0E35\u0E19\u0E0A\u0E47\u0E2D\u0E15",
|
|
148
|
-
screenshotAttached: "\u0E41\u0E19\u0E1A\u0E2A\u0E01\u0E23\u0E35\u0E19\u0E0A\u0E47\u0E2D\u0E15\u0E41\u0E25\u0E49\u0E27",
|
|
168
|
+
screenshotAttached: "\u0E41\u0E19\u0E1A\u0E2A\u0E01\u0E23\u0E35\u0E19\u0E0A\u0E47\u0E2D\u0E15\u0E41\u0E25\u0E49\u0E27 \u2713",
|
|
169
|
+
screenshotCapturing: "\u0E01\u0E33\u0E25\u0E31\u0E07\u0E16\u0E48\u0E32\u0E22\u0E2A\u0E01\u0E23\u0E35\u0E19\u0E0A\u0E47\u0E2D\u0E15\u2026",
|
|
170
|
+
screenshotFailed: "\u0E44\u0E21\u0E48\u0E2A\u0E32\u0E21\u0E32\u0E23\u0E16\u0E16\u0E48\u0E32\u0E22\u0E20\u0E32\u0E1E\u0E44\u0E14\u0E49 \u2014 \u0E42\u0E1B\u0E23\u0E14\u0E2D\u0E18\u0E34\u0E1A\u0E32\u0E22\u0E41\u0E17\u0E19",
|
|
149
171
|
elementButton: "\u0E40\u0E25\u0E37\u0E2D\u0E01\u0E2D\u0E07\u0E04\u0E4C\u0E1B\u0E23\u0E30\u0E01\u0E2D\u0E1A",
|
|
150
|
-
elementSelected: "\u0E40\u0E25\u0E37\u0E2D\u0E01\u0E2D\u0E07\u0E04\u0E4C\u0E1B\u0E23\u0E30\u0E01\u0E2D\u0E1A\u0E41\u0E25\u0E49\u0E27",
|
|
151
|
-
|
|
172
|
+
elementSelected: "\u0E40\u0E25\u0E37\u0E2D\u0E01\u0E2D\u0E07\u0E04\u0E4C\u0E1B\u0E23\u0E30\u0E01\u0E2D\u0E1A\u0E41\u0E25\u0E49\u0E27 \u2713",
|
|
173
|
+
elementCapturing: "\u0E04\u0E25\u0E34\u0E01\u0E2D\u0E07\u0E04\u0E4C\u0E1B\u0E23\u0E30\u0E01\u0E2D\u0E1A\u0E1A\u0E19\u0E2B\u0E19\u0E49\u0E32\u2026",
|
|
174
|
+
elementSelectorHint: "\u0E04\u0E25\u0E34\u0E01\u0E2D\u0E07\u0E04\u0E4C\u0E1B\u0E23\u0E30\u0E01\u0E2D\u0E1A\u0E43\u0E14\u0E01\u0E47\u0E44\u0E14\u0E49 \xB7 Esc \u0E40\u0E1E\u0E37\u0E48\u0E2D\u0E22\u0E01\u0E40\u0E25\u0E34\u0E01",
|
|
175
|
+
optional: "(\u0E44\u0E21\u0E48\u0E1A\u0E31\u0E07\u0E04\u0E31\u0E1A)",
|
|
176
|
+
tooShort: "\u0E01\u0E23\u0E38\u0E13\u0E32\u0E43\u0E2B\u0E49\u0E23\u0E32\u0E22\u0E25\u0E30\u0E40\u0E2D\u0E35\u0E22\u0E14\u0E40\u0E1E\u0E34\u0E48\u0E21\u0E40\u0E15\u0E34\u0E21",
|
|
177
|
+
examplePrompts: [
|
|
178
|
+
"\u0E1B\u0E38\u0E48\u0E21\u0E1A\u0E31\u0E19\u0E17\u0E36\u0E01\u0E44\u0E21\u0E48\u0E17\u0E33\u0E07\u0E32\u0E19",
|
|
179
|
+
"\u0E2B\u0E19\u0E49\u0E32\u0E04\u0E49\u0E32\u0E07\u0E19\u0E32\u0E19 10 \u0E27\u0E34\u0E19\u0E32\u0E17\u0E35",
|
|
180
|
+
"\u0E40\u0E25\u0E22\u0E4C\u0E40\u0E2D\u0E32\u0E15\u0E4C\u0E1E\u0E31\u0E07"
|
|
181
|
+
]
|
|
152
182
|
}
|
|
153
183
|
};
|
|
154
184
|
|
|
@@ -195,18 +225,29 @@ var es = {
|
|
|
195
225
|
heading: "Cu\xE9ntanos m\xE1s",
|
|
196
226
|
descriptionPlaceholder: "Describe lo que pas\xF3\u2026",
|
|
197
227
|
screenshotButton: "Adjuntar captura",
|
|
198
|
-
screenshotAttached: "Captura adjunta",
|
|
228
|
+
screenshotAttached: "Captura adjunta \u2713",
|
|
229
|
+
screenshotCapturing: "Tomando captura\u2026",
|
|
230
|
+
screenshotFailed: "No se pudo capturar \u2014 descr\xEDbelo en su lugar",
|
|
199
231
|
elementButton: "Seleccionar elemento",
|
|
200
|
-
elementSelected: "Elemento seleccionado",
|
|
201
|
-
|
|
232
|
+
elementSelected: "Elemento seleccionado \u2713",
|
|
233
|
+
elementCapturing: "Haz clic en cualquier elemento\u2026",
|
|
234
|
+
elementSelectorHint: "Clic en cualquier elemento \xB7 Esc para cancelar",
|
|
235
|
+
optional: "(opcional)",
|
|
236
|
+
tooShort: "Un poco m\xE1s de detalle nos ayuda a resolverlo",
|
|
237
|
+
examplePrompts: [
|
|
238
|
+
"El bot\xF3n guardar no responde",
|
|
239
|
+
"La p\xE1gina se congel\xF3 10 segundos",
|
|
240
|
+
"El dise\xF1o se ve roto aqu\xED"
|
|
241
|
+
]
|
|
202
242
|
}
|
|
203
243
|
};
|
|
204
244
|
|
|
205
245
|
// src/i18n/index.ts
|
|
206
246
|
var locales = { en, ja, th, es };
|
|
207
247
|
function getLocale(code) {
|
|
208
|
-
|
|
209
|
-
|
|
248
|
+
const resolved = code && code !== "auto" ? code : typeof navigator !== "undefined" ? navigator.language ?? navigator.languages?.[0] : void 0;
|
|
249
|
+
if (!resolved) return en;
|
|
250
|
+
const base = resolved.split("-")[0].toLowerCase();
|
|
210
251
|
return locales[base] ?? en;
|
|
211
252
|
}
|
|
212
253
|
function getAvailableLocales() {
|
|
@@ -239,6 +280,7 @@ function getWidgetStyles(theme) {
|
|
|
239
280
|
-webkit-font-smoothing: antialiased;
|
|
240
281
|
-moz-osx-font-smoothing: grayscale;
|
|
241
282
|
font-feature-settings: 'ss01', 'cv11'; /* nicer system-ui glyphs where supported */
|
|
283
|
+
--mushi-ok: ${isDark ? "#4ade80" : "#16a34a"};
|
|
242
284
|
}
|
|
243
285
|
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
|
|
244
286
|
button { font-family: inherit; }
|
|
@@ -691,6 +733,51 @@ function getWidgetStyles(theme) {
|
|
|
691
733
|
box-shadow: inset 2px 0 0 ${vermillion};
|
|
692
734
|
}
|
|
693
735
|
|
|
736
|
+
/* Example starter chips \u2014 reduce first-report activation energy */
|
|
737
|
+
.mushi-example-chips {
|
|
738
|
+
display: flex;
|
|
739
|
+
flex-wrap: wrap;
|
|
740
|
+
gap: 6px;
|
|
741
|
+
margin-bottom: 10px;
|
|
742
|
+
}
|
|
743
|
+
.mushi-example-chip {
|
|
744
|
+
padding: 4px 10px;
|
|
745
|
+
border: 1px solid ${rule};
|
|
746
|
+
border-radius: 12px;
|
|
747
|
+
background: transparent;
|
|
748
|
+
color: ${inkMuted};
|
|
749
|
+
font-family: ${fontBody};
|
|
750
|
+
font-size: 11px;
|
|
751
|
+
cursor: pointer;
|
|
752
|
+
transition: color 150ms ${easeStamp}, border-color 150ms ${easeStamp}, background 150ms ${easeStamp};
|
|
753
|
+
white-space: nowrap;
|
|
754
|
+
}
|
|
755
|
+
.mushi-example-chip:hover {
|
|
756
|
+
color: ${ink};
|
|
757
|
+
border-color: ${inkMuted};
|
|
758
|
+
background: ${isDark ? "rgba(242,235,221,0.06)" : "rgba(14,13,11,0.04)"};
|
|
759
|
+
}
|
|
760
|
+
.mushi-example-chip:focus-visible {
|
|
761
|
+
outline: 2px solid ${vermillion};
|
|
762
|
+
outline-offset: 2px;
|
|
763
|
+
}
|
|
764
|
+
|
|
765
|
+
/* Textarea wrapper to position char counter */
|
|
766
|
+
.mushi-textarea-wrap {
|
|
767
|
+
position: relative;
|
|
768
|
+
}
|
|
769
|
+
.mushi-char-counter {
|
|
770
|
+
position: absolute;
|
|
771
|
+
bottom: 4px;
|
|
772
|
+
right: 0;
|
|
773
|
+
font-family: ${fontMono};
|
|
774
|
+
font-size: 10px;
|
|
775
|
+
letter-spacing: 0.04em;
|
|
776
|
+
color: ${inkFaint};
|
|
777
|
+
pointer-events: none;
|
|
778
|
+
transition: color 200ms ${easeStamp};
|
|
779
|
+
}
|
|
780
|
+
|
|
694
781
|
.mushi-textarea {
|
|
695
782
|
width: 100%;
|
|
696
783
|
min-height: 96px;
|
|
@@ -753,10 +840,34 @@ function getWidgetStyles(theme) {
|
|
|
753
840
|
border-color: ${vermillion};
|
|
754
841
|
background: ${vermillionWash};
|
|
755
842
|
}
|
|
843
|
+
.mushi-attach-btn.loading {
|
|
844
|
+
opacity: 0.7;
|
|
845
|
+
cursor: wait;
|
|
846
|
+
}
|
|
847
|
+
.mushi-attach-btn.error {
|
|
848
|
+
color: ${vermillion};
|
|
849
|
+
border-color: ${vermillionWash};
|
|
850
|
+
}
|
|
756
851
|
.mushi-attach-btn:focus-visible {
|
|
757
852
|
outline: 2px solid ${vermillion};
|
|
758
853
|
outline-offset: 2px;
|
|
759
854
|
}
|
|
855
|
+
@keyframes mushi-spin {
|
|
856
|
+
to { transform: rotate(360deg); }
|
|
857
|
+
}
|
|
858
|
+
@keyframes mushi-fade-in {
|
|
859
|
+
from { opacity: 0; transform: translateY(4px); }
|
|
860
|
+
to { opacity: 1; transform: translateY(0); }
|
|
861
|
+
}
|
|
862
|
+
.mushi-spinner {
|
|
863
|
+
display: inline-block;
|
|
864
|
+
width: 10px;
|
|
865
|
+
height: 10px;
|
|
866
|
+
border: 1.5px solid currentColor;
|
|
867
|
+
border-top-color: transparent;
|
|
868
|
+
border-radius: 50%;
|
|
869
|
+
animation: mushi-spin 0.7s linear infinite;
|
|
870
|
+
}
|
|
760
871
|
|
|
761
872
|
.mushi-footer {
|
|
762
873
|
padding: 14px 22px 16px;
|
|
@@ -1230,7 +1341,8 @@ var MushiWidget = class {
|
|
|
1230
1341
|
draggable: config.draggable ?? false,
|
|
1231
1342
|
brandFooter: config.brandFooter ?? true,
|
|
1232
1343
|
outdatedBanner: config.outdatedBanner ?? "auto",
|
|
1233
|
-
betaMode: config.betaMode ?? {}
|
|
1344
|
+
betaMode: config.betaMode ?? {},
|
|
1345
|
+
minDescriptionLength: config.minDescriptionLength ?? 20
|
|
1234
1346
|
};
|
|
1235
1347
|
this.callbacks = callbacks;
|
|
1236
1348
|
this.locale = getLocale(this.config.locale === "auto" ? void 0 : this.config.locale);
|
|
@@ -1249,12 +1361,22 @@ var MushiWidget = class {
|
|
|
1249
1361
|
selectedCategory = null;
|
|
1250
1362
|
selectedIntent = null;
|
|
1251
1363
|
screenshotAttached = false;
|
|
1364
|
+
screenshotCapturing = false;
|
|
1365
|
+
screenshotError = false;
|
|
1252
1366
|
allowScreenshotRemove = true;
|
|
1253
1367
|
elementSelected = false;
|
|
1368
|
+
elementCapturing = false;
|
|
1254
1369
|
submitting = false;
|
|
1370
|
+
/** Hint element injected outside the shadow DOM during element selection. */
|
|
1371
|
+
selectorHint = null;
|
|
1255
1372
|
triggerVisible = true;
|
|
1256
1373
|
triggerShrunk = false;
|
|
1257
1374
|
triggerHiddenByScroll = false;
|
|
1375
|
+
/** Milliseconds since mount — used for the 30s first-time nudge gate. */
|
|
1376
|
+
mountedAt = null;
|
|
1377
|
+
nudgeShown = false;
|
|
1378
|
+
nudgeEl = null;
|
|
1379
|
+
nudgeTimer = null;
|
|
1258
1380
|
sdkFreshness = null;
|
|
1259
1381
|
reporterReports = [];
|
|
1260
1382
|
reporterComments = [];
|
|
@@ -1281,6 +1403,7 @@ var MushiWidget = class {
|
|
|
1281
1403
|
this.syncAttachedLaunchers();
|
|
1282
1404
|
this.syncSmartHide();
|
|
1283
1405
|
this.render();
|
|
1406
|
+
this.mountedAt = Date.now();
|
|
1284
1407
|
}
|
|
1285
1408
|
getIsMounted() {
|
|
1286
1409
|
return this.host.isConnected;
|
|
@@ -1307,7 +1430,8 @@ var MushiWidget = class {
|
|
|
1307
1430
|
...config.draggable !== void 0 ? { draggable: config.draggable } : {},
|
|
1308
1431
|
...config.brandFooter !== void 0 ? { brandFooter: config.brandFooter } : {},
|
|
1309
1432
|
...config.outdatedBanner !== void 0 ? { outdatedBanner: config.outdatedBanner } : {},
|
|
1310
|
-
...config.betaMode !== void 0 ? { betaMode: config.betaMode } : {}
|
|
1433
|
+
...config.betaMode !== void 0 ? { betaMode: config.betaMode } : {},
|
|
1434
|
+
...config.minDescriptionLength !== void 0 ? { minDescriptionLength: config.minDescriptionLength } : {}
|
|
1311
1435
|
};
|
|
1312
1436
|
this.locale = getLocale(this.config.locale === "auto" ? void 0 : this.config.locale);
|
|
1313
1437
|
this.syncAttachedLaunchers();
|
|
@@ -1318,9 +1442,13 @@ var MushiWidget = class {
|
|
|
1318
1442
|
if (this.isOpen) return;
|
|
1319
1443
|
this.isOpen = true;
|
|
1320
1444
|
this.screenshotAttached = false;
|
|
1445
|
+
this.screenshotCapturing = false;
|
|
1446
|
+
this.screenshotError = false;
|
|
1321
1447
|
this.elementSelected = false;
|
|
1448
|
+
this.elementCapturing = false;
|
|
1322
1449
|
this.submitting = false;
|
|
1323
1450
|
this.submittedAt = null;
|
|
1451
|
+
this.removeSelectorHint();
|
|
1324
1452
|
if (options?.category) {
|
|
1325
1453
|
this.selectedCategory = options.category;
|
|
1326
1454
|
this.selectedIntent = null;
|
|
@@ -1376,8 +1504,114 @@ var MushiWidget = class {
|
|
|
1376
1504
|
}
|
|
1377
1505
|
setElementSelected(selected) {
|
|
1378
1506
|
this.elementSelected = selected;
|
|
1507
|
+
this.elementCapturing = false;
|
|
1508
|
+
this.removeSelectorHint();
|
|
1509
|
+
if (this.isOpen) this.render();
|
|
1510
|
+
}
|
|
1511
|
+
setScreenshotCapturing(capturing) {
|
|
1512
|
+
this.screenshotCapturing = capturing;
|
|
1513
|
+
this.screenshotError = false;
|
|
1514
|
+
if (this.isOpen) this.render();
|
|
1515
|
+
}
|
|
1516
|
+
setScreenshotError(failed) {
|
|
1517
|
+
this.screenshotError = failed;
|
|
1518
|
+
this.screenshotCapturing = false;
|
|
1379
1519
|
if (this.isOpen) this.render();
|
|
1380
1520
|
}
|
|
1521
|
+
setElementCapturing(capturing) {
|
|
1522
|
+
this.elementCapturing = capturing;
|
|
1523
|
+
if (capturing) {
|
|
1524
|
+
this.showSelectorHint();
|
|
1525
|
+
} else {
|
|
1526
|
+
this.removeSelectorHint();
|
|
1527
|
+
}
|
|
1528
|
+
if (this.isOpen) this.render();
|
|
1529
|
+
}
|
|
1530
|
+
/** Hide the widget panel (but keep the host element) during element selection
|
|
1531
|
+
* so the user can click any element on the page without the panel
|
|
1532
|
+
* intercepting the event. */
|
|
1533
|
+
hidePanel() {
|
|
1534
|
+
const panel = this.shadow.querySelector(".mushi-panel");
|
|
1535
|
+
if (panel) panel.style.display = "none";
|
|
1536
|
+
}
|
|
1537
|
+
showPanel() {
|
|
1538
|
+
const panel = this.shadow.querySelector(".mushi-panel");
|
|
1539
|
+
if (panel) panel.style.display = "";
|
|
1540
|
+
}
|
|
1541
|
+
showSelectorHint() {
|
|
1542
|
+
this.removeSelectorHint();
|
|
1543
|
+
const hint = document.createElement("div");
|
|
1544
|
+
hint.id = "mushi-selector-hint";
|
|
1545
|
+
hint.setAttribute("role", "status");
|
|
1546
|
+
hint.setAttribute("aria-live", "polite");
|
|
1547
|
+
hint.style.cssText = `
|
|
1548
|
+
position: fixed;
|
|
1549
|
+
bottom: 24px;
|
|
1550
|
+
left: 50%;
|
|
1551
|
+
transform: translateX(-50%);
|
|
1552
|
+
z-index: 2147483646;
|
|
1553
|
+
background: rgba(17,17,17,0.92);
|
|
1554
|
+
color: #fff;
|
|
1555
|
+
font-family: ui-monospace, SFMono-Regular, monospace;
|
|
1556
|
+
font-size: 12px;
|
|
1557
|
+
letter-spacing: 0.04em;
|
|
1558
|
+
padding: 8px 16px;
|
|
1559
|
+
border-radius: 20px;
|
|
1560
|
+
pointer-events: none;
|
|
1561
|
+
white-space: nowrap;
|
|
1562
|
+
backdrop-filter: blur(4px);
|
|
1563
|
+
box-shadow: 0 2px 12px rgba(0,0,0,0.35);
|
|
1564
|
+
`;
|
|
1565
|
+
hint.textContent = this.locale.step3.elementSelectorHint;
|
|
1566
|
+
document.body.appendChild(hint);
|
|
1567
|
+
this.selectorHint = hint;
|
|
1568
|
+
}
|
|
1569
|
+
removeSelectorHint() {
|
|
1570
|
+
this.selectorHint?.remove();
|
|
1571
|
+
this.selectorHint = null;
|
|
1572
|
+
document.getElementById("mushi-selector-hint")?.remove();
|
|
1573
|
+
}
|
|
1574
|
+
showNudge() {
|
|
1575
|
+
if (this.nudgeShown || this.nudgeEl) return;
|
|
1576
|
+
this.nudgeShown = true;
|
|
1577
|
+
const trigger = this.shadow.querySelector(".mushi-trigger");
|
|
1578
|
+
const rect = trigger?.getBoundingClientRect();
|
|
1579
|
+
const nudge = document.createElement("div");
|
|
1580
|
+
nudge.id = "mushi-nudge-bubble";
|
|
1581
|
+
nudge.setAttribute("role", "tooltip");
|
|
1582
|
+
const isRight = this.config.position.includes("right");
|
|
1583
|
+
nudge.style.cssText = `
|
|
1584
|
+
position: fixed;
|
|
1585
|
+
z-index: 2147483645;
|
|
1586
|
+
${rect ? `bottom: ${window.innerHeight - rect.top + 8}px; ${isRight ? `right: ${window.innerWidth - rect.right}px;` : `left: ${rect.left}px;`}` : "bottom: 80px; right: 24px;"}
|
|
1587
|
+
background: rgba(17,17,17,0.92);
|
|
1588
|
+
color: #fff;
|
|
1589
|
+
font-family: ui-sans-serif, system-ui, sans-serif;
|
|
1590
|
+
font-size: 12px;
|
|
1591
|
+
line-height: 1.4;
|
|
1592
|
+
padding: 8px 12px;
|
|
1593
|
+
border-radius: 8px;
|
|
1594
|
+
max-width: 200px;
|
|
1595
|
+
pointer-events: none;
|
|
1596
|
+
backdrop-filter: blur(4px);
|
|
1597
|
+
box-shadow: 0 2px 12px rgba(0,0,0,0.35);
|
|
1598
|
+
animation: mushi-fade-in 0.15s ease forwards;
|
|
1599
|
+
`;
|
|
1600
|
+
nudge.textContent = this.locale.step3.tooShort.startsWith("A bit") ? "Found a bug? One sentence is enough \u{1F41B}" : "\u30D0\u30B0\u3092\u898B\u3064\u3051\u305F\uFF1F\u4E00\u884C\u3067\u5927\u4E08\u592B\u3067\u3059 \u{1F41B}";
|
|
1601
|
+
document.body.appendChild(nudge);
|
|
1602
|
+
this.nudgeEl = nudge;
|
|
1603
|
+
if (this.nudgeTimer !== null) clearTimeout(this.nudgeTimer);
|
|
1604
|
+
this.nudgeTimer = setTimeout(() => this.removeNudge(), 5e3);
|
|
1605
|
+
}
|
|
1606
|
+
removeNudge() {
|
|
1607
|
+
if (this.nudgeTimer !== null) {
|
|
1608
|
+
clearTimeout(this.nudgeTimer);
|
|
1609
|
+
this.nudgeTimer = null;
|
|
1610
|
+
}
|
|
1611
|
+
this.nudgeEl?.remove();
|
|
1612
|
+
this.nudgeEl = null;
|
|
1613
|
+
document.getElementById("mushi-nudge-bubble")?.remove();
|
|
1614
|
+
}
|
|
1381
1615
|
setSdkFreshness(info) {
|
|
1382
1616
|
this.sdkFreshness = info;
|
|
1383
1617
|
if (this.isOpen) this.render();
|
|
@@ -1403,6 +1637,8 @@ var MushiWidget = class {
|
|
|
1403
1637
|
this.smartHideCleanup = null;
|
|
1404
1638
|
this.attachedLaunchers.forEach((cleanup) => cleanup());
|
|
1405
1639
|
this.attachedLaunchers = [];
|
|
1640
|
+
this.removeSelectorHint();
|
|
1641
|
+
this.removeNudge();
|
|
1406
1642
|
this.host.remove();
|
|
1407
1643
|
}
|
|
1408
1644
|
syncAttachedLaunchers() {
|
|
@@ -1498,9 +1734,22 @@ var MushiWidget = class {
|
|
|
1498
1734
|
trigger.style.zIndex = String(this.config.zIndex);
|
|
1499
1735
|
this.applyInsetVars(trigger);
|
|
1500
1736
|
trigger.addEventListener("click", () => {
|
|
1737
|
+
this.removeNudge();
|
|
1501
1738
|
if (this.isOpen) this.close();
|
|
1502
1739
|
else this.open();
|
|
1503
1740
|
});
|
|
1741
|
+
trigger.addEventListener("mouseenter", () => {
|
|
1742
|
+
const onPageMs = this.mountedAt ? Date.now() - this.mountedAt : 0;
|
|
1743
|
+
if (!this.nudgeShown && !this.isOpen && onPageMs >= 3e4) {
|
|
1744
|
+
this.showNudge();
|
|
1745
|
+
}
|
|
1746
|
+
});
|
|
1747
|
+
trigger.addEventListener("mouseleave", () => {
|
|
1748
|
+
if (this.nudgeEl) {
|
|
1749
|
+
if (this.nudgeTimer !== null) clearTimeout(this.nudgeTimer);
|
|
1750
|
+
this.nudgeTimer = setTimeout(() => this.removeNudge(), 2e3);
|
|
1751
|
+
}
|
|
1752
|
+
});
|
|
1504
1753
|
this.shadow.appendChild(trigger);
|
|
1505
1754
|
}
|
|
1506
1755
|
const panel = document.createElement("div");
|
|
@@ -1752,25 +2001,62 @@ var MushiWidget = class {
|
|
|
1752
2001
|
${this.renderStepIndicator(STEP_NUMBER.intent)}
|
|
1753
2002
|
`;
|
|
1754
2003
|
}
|
|
2004
|
+
effectiveMinLength() {
|
|
2005
|
+
const base = this.config.minDescriptionLength ?? 20;
|
|
2006
|
+
const lang = this.config.locale === "auto" ? typeof navigator !== "undefined" ? navigator.language ?? "" : "" : this.config.locale ?? "";
|
|
2007
|
+
const isCjk = /^(ja|zh|ko)/i.test(lang);
|
|
2008
|
+
return isCjk ? Math.max(4, Math.floor(base / 2)) : base;
|
|
2009
|
+
}
|
|
1755
2010
|
renderDetailsStep() {
|
|
1756
2011
|
const t = this.locale;
|
|
2012
|
+
const minLen = this.effectiveMinLength();
|
|
2013
|
+
const screenshotLabel = this.screenshotCapturing ? t.step3.screenshotCapturing : this.screenshotError ? t.step3.screenshotFailed : this.screenshotAttached ? t.step3.screenshotAttached : t.step3.screenshotButton;
|
|
2014
|
+
const screenshotClass = [
|
|
2015
|
+
"mushi-attach-btn",
|
|
2016
|
+
this.screenshotAttached ? "active" : "",
|
|
2017
|
+
this.screenshotError ? "error" : "",
|
|
2018
|
+
this.screenshotCapturing ? "loading" : ""
|
|
2019
|
+
].filter(Boolean).join(" ");
|
|
2020
|
+
const elementLabel = this.elementCapturing ? t.step3.elementCapturing : this.elementSelected ? t.step3.elementSelected : t.step3.elementButton;
|
|
2021
|
+
const elementClass = [
|
|
2022
|
+
"mushi-attach-btn",
|
|
2023
|
+
this.elementSelected ? "active" : "",
|
|
2024
|
+
this.elementCapturing ? "loading" : ""
|
|
2025
|
+
].filter(Boolean).join(" ");
|
|
2026
|
+
const exampleChips = t.step3.examplePrompts.map((p) => `<button type="button" class="mushi-example-chip" data-example="${escapeHtml(p)}">${escapeHtml(p)}</button>`).join("");
|
|
1757
2027
|
return `
|
|
1758
2028
|
${this.renderHeader({ title: t.step3.heading, showBack: true, step: STEP_NUMBER.details })}
|
|
1759
2029
|
<div class="mushi-body">
|
|
1760
|
-
<
|
|
1761
|
-
|
|
1762
|
-
|
|
1763
|
-
|
|
1764
|
-
|
|
1765
|
-
|
|
1766
|
-
|
|
2030
|
+
<div class="mushi-example-chips" aria-label="Example prompts">${exampleChips}</div>
|
|
2031
|
+
<div class="mushi-textarea-wrap">
|
|
2032
|
+
<textarea
|
|
2033
|
+
class="mushi-textarea"
|
|
2034
|
+
placeholder="${t.step3.descriptionPlaceholder}"
|
|
2035
|
+
rows="4"
|
|
2036
|
+
aria-label="${t.step3.heading}"
|
|
2037
|
+
autofocus
|
|
2038
|
+
></textarea>
|
|
2039
|
+
<div class="mushi-char-counter" data-role="char-counter" aria-hidden="true">
|
|
2040
|
+
<span data-role="char-current">0</span>/<span data-role="char-min">${minLen}</span>
|
|
2041
|
+
</div>
|
|
2042
|
+
</div>
|
|
1767
2043
|
<div class="mushi-attachments">
|
|
1768
|
-
<button type="button" class="
|
|
1769
|
-
|
|
2044
|
+
<button type="button" class="${screenshotClass}"
|
|
2045
|
+
data-action="screenshot"
|
|
2046
|
+
${this.screenshotCapturing ? "disabled" : ""}
|
|
2047
|
+
aria-label="${escapeHtml(screenshotLabel)}"
|
|
2048
|
+
>
|
|
2049
|
+
${this.screenshotCapturing ? '<span class="mushi-spinner" aria-hidden="true"></span>' : "\u{1F4F8}"}
|
|
2050
|
+
${escapeHtml(screenshotLabel)}
|
|
1770
2051
|
</button>
|
|
1771
|
-
${this.screenshotAttached && this.allowScreenshotRemove ? '<button type="button" class="mushi-attach-btn danger" data-action="remove-screenshot">\u2715 Remove
|
|
1772
|
-
<button type="button" class="
|
|
1773
|
-
|
|
2052
|
+
${this.screenshotAttached && this.allowScreenshotRemove ? '<button type="button" class="mushi-attach-btn danger" data-action="remove-screenshot" aria-label="Remove screenshot">\u2715 Remove</button>' : ""}
|
|
2053
|
+
<button type="button" class="${elementClass}"
|
|
2054
|
+
data-action="element"
|
|
2055
|
+
${this.elementCapturing ? "disabled" : ""}
|
|
2056
|
+
aria-label="${escapeHtml(elementLabel)}"
|
|
2057
|
+
>
|
|
2058
|
+
${this.elementCapturing ? '<span class="mushi-spinner" aria-hidden="true"></span>' : "\u{1F3AF}"}
|
|
2059
|
+
${escapeHtml(elementLabel)}
|
|
1774
2060
|
</button>
|
|
1775
2061
|
</div>
|
|
1776
2062
|
<div class="mushi-error" style="display:none" role="alert"></div>
|
|
@@ -1940,6 +2226,30 @@ var MushiWidget = class {
|
|
|
1940
2226
|
this.render();
|
|
1941
2227
|
});
|
|
1942
2228
|
});
|
|
2229
|
+
const textarea = panel.querySelector(".mushi-textarea");
|
|
2230
|
+
const charCurrentEl = panel.querySelector('[data-role="char-current"]');
|
|
2231
|
+
if (textarea && charCurrentEl) {
|
|
2232
|
+
const minLen = this.effectiveMinLength();
|
|
2233
|
+
const updateCounter = () => {
|
|
2234
|
+
const len = textarea.value.trim().length;
|
|
2235
|
+
charCurrentEl.textContent = String(len);
|
|
2236
|
+
const counterEl = panel.querySelector('[data-role="char-counter"]');
|
|
2237
|
+
if (counterEl) {
|
|
2238
|
+
counterEl.style.color = len >= minLen ? "var(--mushi-ok, #22c55e)" : "";
|
|
2239
|
+
}
|
|
2240
|
+
};
|
|
2241
|
+
textarea.addEventListener("input", updateCounter);
|
|
2242
|
+
}
|
|
2243
|
+
panel.querySelectorAll("[data-example]").forEach((chip) => {
|
|
2244
|
+
chip.addEventListener("click", () => {
|
|
2245
|
+
const example = chip.dataset.example ?? "";
|
|
2246
|
+
if (textarea) {
|
|
2247
|
+
textarea.value = example;
|
|
2248
|
+
textarea.focus();
|
|
2249
|
+
textarea.dispatchEvent(new Event("input"));
|
|
2250
|
+
}
|
|
2251
|
+
});
|
|
2252
|
+
});
|
|
1943
2253
|
panel.querySelector('[data-action="screenshot"]')?.addEventListener("click", () => {
|
|
1944
2254
|
this.callbacks.onScreenshotRequest();
|
|
1945
2255
|
});
|
|
@@ -1950,14 +2260,16 @@ var MushiWidget = class {
|
|
|
1950
2260
|
this.callbacks.onElementSelectorRequest?.();
|
|
1951
2261
|
});
|
|
1952
2262
|
const submitReport = () => {
|
|
1953
|
-
const
|
|
1954
|
-
const description =
|
|
2263
|
+
const textarea2 = panel.querySelector(".mushi-textarea");
|
|
2264
|
+
const description = textarea2?.value?.trim() ?? "";
|
|
1955
2265
|
const errorEl = panel.querySelector(".mushi-error");
|
|
1956
|
-
const
|
|
1957
|
-
if (description.length <
|
|
2266
|
+
const minLen = this.effectiveMinLength();
|
|
2267
|
+
if (description.length < minLen) {
|
|
1958
2268
|
if (errorEl) {
|
|
1959
|
-
|
|
2269
|
+
const msg = `${t.step3.tooShort} (${description.length}/${minLen})`;
|
|
2270
|
+
errorEl.textContent = msg;
|
|
1960
2271
|
errorEl.style.display = "block";
|
|
2272
|
+
textarea2?.focus();
|
|
1961
2273
|
}
|
|
1962
2274
|
return;
|
|
1963
2275
|
}
|
|
@@ -2620,50 +2932,16 @@ function truncateUrl(url) {
|
|
|
2620
2932
|
function createScreenshotCapture(options = {}) {
|
|
2621
2933
|
let activeOptions = options;
|
|
2622
2934
|
async function take() {
|
|
2623
|
-
|
|
2624
|
-
|
|
2625
|
-
const canvas = document.createElement("canvas");
|
|
2626
|
-
const ctx = canvas.getContext("2d");
|
|
2627
|
-
if (!ctx) return null;
|
|
2628
|
-
const width = window.innerWidth;
|
|
2629
|
-
const height = window.innerHeight;
|
|
2630
|
-
const dpr = Math.min(window.devicePixelRatio || 1, 2);
|
|
2631
|
-
canvas.width = width * dpr;
|
|
2632
|
-
canvas.height = height * dpr;
|
|
2633
|
-
ctx.scale(dpr, dpr);
|
|
2634
|
-
const safeDocument = buildPrivacySafeDocument(activeOptions.privacy);
|
|
2635
|
-
const svgData = `
|
|
2636
|
-
<svg xmlns="http://www.w3.org/2000/svg" width="${width}" height="${height}">
|
|
2637
|
-
<foreignObject width="100%" height="100%">
|
|
2638
|
-
<div xmlns="http://www.w3.org/1999/xhtml">
|
|
2639
|
-
${new XMLSerializer().serializeToString(safeDocument)}
|
|
2640
|
-
</div>
|
|
2641
|
-
</foreignObject>
|
|
2642
|
-
</svg>
|
|
2643
|
-
`;
|
|
2644
|
-
const img = new Image();
|
|
2645
|
-
const blob = new Blob([svgData], { type: "image/svg+xml;charset=utf-8" });
|
|
2646
|
-
const url = URL.createObjectURL(blob);
|
|
2647
|
-
return new Promise((resolve) => {
|
|
2648
|
-
img.onload = () => {
|
|
2649
|
-
ctx.drawImage(img, 0, 0, width, height);
|
|
2650
|
-
URL.revokeObjectURL(url);
|
|
2651
|
-
try {
|
|
2652
|
-
const dataUrl = canvas.toDataURL("image/jpeg", 0.7);
|
|
2653
|
-
resolve(dataUrl);
|
|
2654
|
-
} catch {
|
|
2655
|
-
resolve(null);
|
|
2656
|
-
}
|
|
2657
|
-
};
|
|
2658
|
-
img.onerror = () => {
|
|
2659
|
-
URL.revokeObjectURL(url);
|
|
2660
|
-
resolve(null);
|
|
2661
|
-
};
|
|
2662
|
-
img.src = url;
|
|
2663
|
-
});
|
|
2664
|
-
} catch {
|
|
2665
|
-
return null;
|
|
2935
|
+
if (typeof document === "undefined") {
|
|
2936
|
+
return { ok: false, reason: "unsupported", message: "Not in a browser context" };
|
|
2666
2937
|
}
|
|
2938
|
+
const svgResult = await trySvgCapture(activeOptions.privacy);
|
|
2939
|
+
if (svgResult.ok) return svgResult;
|
|
2940
|
+
if (svgResult.reason !== "unsupported") {
|
|
2941
|
+
const mediaResult = await tryDisplayMediaCapture();
|
|
2942
|
+
if (mediaResult.ok) return mediaResult;
|
|
2943
|
+
}
|
|
2944
|
+
return svgResult;
|
|
2667
2945
|
}
|
|
2668
2946
|
return {
|
|
2669
2947
|
take,
|
|
@@ -2672,8 +2950,110 @@ function createScreenshotCapture(options = {}) {
|
|
|
2672
2950
|
}
|
|
2673
2951
|
};
|
|
2674
2952
|
}
|
|
2953
|
+
async function trySvgCapture(privacy) {
|
|
2954
|
+
try {
|
|
2955
|
+
const canvas = document.createElement("canvas");
|
|
2956
|
+
const ctx = canvas.getContext("2d");
|
|
2957
|
+
if (!ctx) return { ok: false, reason: "unsupported", message: "Canvas 2d context unavailable" };
|
|
2958
|
+
const width = window.innerWidth;
|
|
2959
|
+
const height = window.innerHeight;
|
|
2960
|
+
const dpr = Math.min(window.devicePixelRatio || 1, 2);
|
|
2961
|
+
canvas.width = width * dpr;
|
|
2962
|
+
canvas.height = height * dpr;
|
|
2963
|
+
ctx.scale(dpr, dpr);
|
|
2964
|
+
const safeDocument = buildPrivacySafeDocument(privacy);
|
|
2965
|
+
const svgData = `
|
|
2966
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="${width}" height="${height}">
|
|
2967
|
+
<foreignObject width="100%" height="100%">
|
|
2968
|
+
<div xmlns="http://www.w3.org/1999/xhtml">
|
|
2969
|
+
${new XMLSerializer().serializeToString(safeDocument)}
|
|
2970
|
+
</div>
|
|
2971
|
+
</foreignObject>
|
|
2972
|
+
</svg>
|
|
2973
|
+
`;
|
|
2974
|
+
const img = new Image();
|
|
2975
|
+
const blob = new Blob([svgData], { type: "image/svg+xml;charset=utf-8" });
|
|
2976
|
+
const url = URL.createObjectURL(blob);
|
|
2977
|
+
const loadResult = await new Promise((resolve) => {
|
|
2978
|
+
img.onload = () => resolve("loaded");
|
|
2979
|
+
img.onerror = () => resolve("error");
|
|
2980
|
+
const timeout = setTimeout(() => resolve("error"), 5e3);
|
|
2981
|
+
img.onload = () => {
|
|
2982
|
+
clearTimeout(timeout);
|
|
2983
|
+
resolve("loaded");
|
|
2984
|
+
};
|
|
2985
|
+
});
|
|
2986
|
+
URL.revokeObjectURL(url);
|
|
2987
|
+
if (loadResult === "error") {
|
|
2988
|
+
return { ok: false, reason: "load-error", message: "SVG image load failed" };
|
|
2989
|
+
}
|
|
2990
|
+
ctx.drawImage(img, 0, 0, width, height);
|
|
2991
|
+
try {
|
|
2992
|
+
const dataUrl = canvas.toDataURL("image/jpeg", 0.75);
|
|
2993
|
+
return { ok: true, dataUrl };
|
|
2994
|
+
} catch (err) {
|
|
2995
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
2996
|
+
return { ok: false, reason: "tainted", message };
|
|
2997
|
+
}
|
|
2998
|
+
} catch (err) {
|
|
2999
|
+
return { ok: false, reason: "error", message: err instanceof Error ? err.message : String(err) };
|
|
3000
|
+
}
|
|
3001
|
+
}
|
|
3002
|
+
async function tryDisplayMediaCapture() {
|
|
3003
|
+
if (typeof navigator === "undefined" || !("mediaDevices" in navigator)) {
|
|
3004
|
+
return { ok: false, reason: "unsupported", message: "mediaDevices not available" };
|
|
3005
|
+
}
|
|
3006
|
+
const mediaDevices = navigator.mediaDevices;
|
|
3007
|
+
if (typeof mediaDevices.getDisplayMedia !== "function") {
|
|
3008
|
+
return { ok: false, reason: "unsupported", message: "getDisplayMedia not available" };
|
|
3009
|
+
}
|
|
3010
|
+
let stream = null;
|
|
3011
|
+
try {
|
|
3012
|
+
stream = await mediaDevices.getDisplayMedia({
|
|
3013
|
+
video: { displaySurface: "browser" },
|
|
3014
|
+
audio: false
|
|
3015
|
+
});
|
|
3016
|
+
const track = stream.getVideoTracks()[0];
|
|
3017
|
+
if (!track) return { ok: false, reason: "error", message: "No video track" };
|
|
3018
|
+
const imageCapture = new window.ImageCapture(track);
|
|
3019
|
+
const bitmap = await imageCapture.grabFrame();
|
|
3020
|
+
const canvas = document.createElement("canvas");
|
|
3021
|
+
canvas.width = bitmap.width;
|
|
3022
|
+
canvas.height = bitmap.height;
|
|
3023
|
+
const ctx = canvas.getContext("2d");
|
|
3024
|
+
ctx.drawImage(bitmap, 0, 0);
|
|
3025
|
+
bitmap.close();
|
|
3026
|
+
const dataUrl = canvas.toDataURL("image/jpeg", 0.85);
|
|
3027
|
+
return { ok: true, dataUrl };
|
|
3028
|
+
} catch (err) {
|
|
3029
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
3030
|
+
if (err instanceof Error && err.name === "NotAllowedError") {
|
|
3031
|
+
return { ok: false, reason: "cancelled", message };
|
|
3032
|
+
}
|
|
3033
|
+
return { ok: false, reason: "error", message };
|
|
3034
|
+
} finally {
|
|
3035
|
+
stream?.getTracks().forEach((t) => t.stop());
|
|
3036
|
+
}
|
|
3037
|
+
}
|
|
2675
3038
|
function buildPrivacySafeDocument(privacy) {
|
|
2676
3039
|
const clone = document.documentElement.cloneNode(true);
|
|
3040
|
+
for (const img of Array.from(clone.querySelectorAll("img[src]"))) {
|
|
3041
|
+
const src = img.getAttribute("src") ?? "";
|
|
3042
|
+
try {
|
|
3043
|
+
const url = new URL(src, window.location.href);
|
|
3044
|
+
if (url.origin !== window.location.origin) {
|
|
3045
|
+
img.removeAttribute("src");
|
|
3046
|
+
img.removeAttribute("srcset");
|
|
3047
|
+
}
|
|
3048
|
+
} catch {
|
|
3049
|
+
}
|
|
3050
|
+
}
|
|
3051
|
+
for (const el of Array.from(clone.querySelectorAll("[style]"))) {
|
|
3052
|
+
const style = el.getAttribute("style") ?? "";
|
|
3053
|
+
if (/url\(["']?https?:\/\/(?!localhost)/.test(style)) {
|
|
3054
|
+
el.setAttribute("style", style.replace(/url\([^)]*\)/g, "none"));
|
|
3055
|
+
}
|
|
3056
|
+
}
|
|
2677
3057
|
for (const selector of privacy?.blockSelectors ?? []) {
|
|
2678
3058
|
for (const el of safeQueryAll(clone, selector)) {
|
|
2679
3059
|
el.remove();
|
|
@@ -2870,6 +3250,11 @@ function createElementSelector() {
|
|
|
2870
3250
|
e.stopPropagation();
|
|
2871
3251
|
const target = e.target;
|
|
2872
3252
|
if (target === overlay) return;
|
|
3253
|
+
const path = e.composedPath ? e.composedPath() : [];
|
|
3254
|
+
const hitsMushiHost = path.some(
|
|
3255
|
+
(node) => node instanceof Element && node.id === "mushi-mushi-widget"
|
|
3256
|
+
);
|
|
3257
|
+
if (hitsMushiHost) return;
|
|
2873
3258
|
const captured = captureElement(target);
|
|
2874
3259
|
finish(captured);
|
|
2875
3260
|
}
|
|
@@ -3584,7 +3969,7 @@ function createProactiveManager(config = {}) {
|
|
|
3584
3969
|
|
|
3585
3970
|
// src/version.ts
|
|
3586
3971
|
var MUSHI_SDK_PACKAGE = "@mushi-mushi/web";
|
|
3587
|
-
var MUSHI_SDK_VERSION = "1.
|
|
3972
|
+
var MUSHI_SDK_VERSION = "1.3.0" ;
|
|
3588
3973
|
|
|
3589
3974
|
// src/mushi.ts
|
|
3590
3975
|
var instance = null;
|
|
@@ -3789,8 +4174,21 @@ function createInstance(config) {
|
|
|
3789
4174
|
onScreenshotRequest: async () => {
|
|
3790
4175
|
if (!screenshotCap || activeConfig.capture?.screenshot === "off") return;
|
|
3791
4176
|
log.debug("Taking screenshot");
|
|
3792
|
-
|
|
3793
|
-
|
|
4177
|
+
widget.setScreenshotCapturing(true);
|
|
4178
|
+
const result = await screenshotCap.take();
|
|
4179
|
+
if (result.ok) {
|
|
4180
|
+
pendingScreenshot = result.dataUrl;
|
|
4181
|
+
widget.setScreenshotAttached(true);
|
|
4182
|
+
log.debug("Screenshot captured");
|
|
4183
|
+
} else {
|
|
4184
|
+
pendingScreenshot = null;
|
|
4185
|
+
if (result.reason !== "cancelled") {
|
|
4186
|
+
widget.setScreenshotError(true);
|
|
4187
|
+
log.debug("Screenshot failed", { reason: result.reason, message: result.message });
|
|
4188
|
+
} else {
|
|
4189
|
+
widget.setScreenshotCapturing(false);
|
|
4190
|
+
}
|
|
4191
|
+
}
|
|
3794
4192
|
},
|
|
3795
4193
|
onScreenshotRemove: () => {
|
|
3796
4194
|
log.debug("Screenshot attachment removed");
|
|
@@ -3800,11 +4198,19 @@ function createInstance(config) {
|
|
|
3800
4198
|
onElementSelectorRequest: async () => {
|
|
3801
4199
|
if (!elementSelector || activeConfig.capture?.elementSelector === false) return;
|
|
3802
4200
|
log.debug("Element selector activated");
|
|
3803
|
-
|
|
3804
|
-
|
|
3805
|
-
|
|
3806
|
-
|
|
3807
|
-
|
|
4201
|
+
widget.setElementCapturing(true);
|
|
4202
|
+
widget.hidePanel();
|
|
4203
|
+
try {
|
|
4204
|
+
const el = await elementSelector.activate();
|
|
4205
|
+
if (el) {
|
|
4206
|
+
pendingElement = el;
|
|
4207
|
+
widget.setElementSelected(true);
|
|
4208
|
+
log.debug("Element selected", { tagName: el.tagName, xpath: el.xpath });
|
|
4209
|
+
} else {
|
|
4210
|
+
widget.setElementCapturing(false);
|
|
4211
|
+
}
|
|
4212
|
+
} finally {
|
|
4213
|
+
widget.showPanel();
|
|
3808
4214
|
}
|
|
3809
4215
|
},
|
|
3810
4216
|
async onReporterReportsRequest() {
|