@diegotsi/flint-react 0.6.0 → 1.0.1
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/index.cjs +637 -669
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +35 -8
- package/dist/index.d.ts +35 -8
- package/dist/index.js +622 -664
- package/dist/index.js.map +1 -1
- package/package.json +2 -1
package/dist/index.cjs
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __create = Object.create;
|
|
2
3
|
var __defProp = Object.defineProperty;
|
|
3
4
|
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
5
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
5
7
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
8
|
var __export = (target, all) => {
|
|
7
9
|
for (var name in all)
|
|
@@ -15,6 +17,14 @@ var __copyProps = (to, from, except, desc) => {
|
|
|
15
17
|
}
|
|
16
18
|
return to;
|
|
17
19
|
};
|
|
20
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
22
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
23
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
24
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
25
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
26
|
+
mod
|
|
27
|
+
));
|
|
18
28
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
29
|
|
|
20
30
|
// src/index.ts
|
|
@@ -22,21 +32,20 @@ var index_exports = {};
|
|
|
22
32
|
__export(index_exports, {
|
|
23
33
|
FlintModal: () => FlintModal,
|
|
24
34
|
FlintWidget: () => FlintWidget,
|
|
25
|
-
flint: () => flint
|
|
35
|
+
flint: () => import_core8.flint
|
|
26
36
|
});
|
|
27
37
|
module.exports = __toCommonJS(index_exports);
|
|
28
38
|
|
|
29
|
-
// src/FlintWidget.tsx
|
|
30
|
-
var import_react4 = require("react");
|
|
31
|
-
var import_react_i18next3 = require("react-i18next");
|
|
32
|
-
|
|
33
39
|
// src/FlintModal.tsx
|
|
34
40
|
var import_react2 = require("react");
|
|
35
41
|
var import_react_i18next = require("react-i18next");
|
|
36
42
|
|
|
43
|
+
// src/api.ts
|
|
44
|
+
var import_core = require("@flint/core");
|
|
45
|
+
|
|
37
46
|
// src/ScreenAnnotator.tsx
|
|
38
|
-
var import_react = require("react");
|
|
39
47
|
var import_modern_screenshot = require("modern-screenshot");
|
|
48
|
+
var import_react = require("react");
|
|
40
49
|
var import_jsx_runtime = require("react/jsx-runtime");
|
|
41
50
|
function normalizeRect(startX, startY, endX, endY) {
|
|
42
51
|
return {
|
|
@@ -81,9 +90,7 @@ function ScreenAnnotator({ zIndex, onCapture, onCancel }) {
|
|
|
81
90
|
const dpr = window.devicePixelRatio ?? 1;
|
|
82
91
|
const vw = window.innerWidth;
|
|
83
92
|
const vh = window.innerHeight;
|
|
84
|
-
await new Promise(
|
|
85
|
-
(resolve) => requestAnimationFrame(() => requestAnimationFrame(() => resolve()))
|
|
86
|
-
);
|
|
93
|
+
await new Promise((resolve) => requestAnimationFrame(() => requestAnimationFrame(() => resolve())));
|
|
87
94
|
try {
|
|
88
95
|
const fullCanvas = await (0, import_modern_screenshot.domToCanvas)(document.documentElement, {
|
|
89
96
|
scale: dpr,
|
|
@@ -98,17 +105,7 @@ function ScreenAnnotator({ zIndex, onCapture, onCancel }) {
|
|
|
98
105
|
canvas.width = vw * dpr;
|
|
99
106
|
canvas.height = vh * dpr;
|
|
100
107
|
const ctx = canvas.getContext("2d");
|
|
101
|
-
ctx.drawImage(
|
|
102
|
-
fullCanvas,
|
|
103
|
-
0,
|
|
104
|
-
0,
|
|
105
|
-
vw * dpr,
|
|
106
|
-
vh * dpr,
|
|
107
|
-
0,
|
|
108
|
-
0,
|
|
109
|
-
vw * dpr,
|
|
110
|
-
vh * dpr
|
|
111
|
-
);
|
|
108
|
+
ctx.drawImage(fullCanvas, 0, 0, vw * dpr, vh * dpr, 0, 0, vw * dpr, vh * dpr);
|
|
112
109
|
ctx.fillStyle = "rgba(255,200,0,0.25)";
|
|
113
110
|
ctx.fillRect(finalRect.x * dpr, finalRect.y * dpr, finalRect.w * dpr, finalRect.h * dpr);
|
|
114
111
|
ctx.strokeStyle = "#f97316";
|
|
@@ -146,123 +143,50 @@ function ScreenAnnotator({ zIndex, onCapture, onCancel }) {
|
|
|
146
143
|
pointerEvents: isCapturing ? "none" : "auto"
|
|
147
144
|
},
|
|
148
145
|
children: [
|
|
149
|
-
!isCapturing && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
146
|
+
!isCapturing && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
147
|
+
"div",
|
|
148
|
+
{
|
|
149
|
+
style: {
|
|
150
|
+
position: "absolute",
|
|
151
|
+
top: 16,
|
|
152
|
+
left: "50%",
|
|
153
|
+
transform: "translateX(-50%)",
|
|
154
|
+
background: "rgba(0,0,0,0.75)",
|
|
155
|
+
color: "#fff",
|
|
156
|
+
padding: "8px 18px",
|
|
157
|
+
borderRadius: 8,
|
|
158
|
+
fontSize: 14,
|
|
159
|
+
fontFamily: '-apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif',
|
|
160
|
+
pointerEvents: "none",
|
|
161
|
+
whiteSpace: "nowrap",
|
|
162
|
+
backdropFilter: "blur(4px)"
|
|
163
|
+
},
|
|
164
|
+
children: "Drag to highlight the problem area \xA0\xB7\xA0 Esc to cancel"
|
|
165
|
+
}
|
|
166
|
+
),
|
|
167
|
+
rect && phase === "selecting" && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
168
|
+
"div",
|
|
169
|
+
{
|
|
170
|
+
style: {
|
|
171
|
+
position: "absolute",
|
|
172
|
+
left: rect.x,
|
|
173
|
+
top: rect.y,
|
|
174
|
+
width: rect.w,
|
|
175
|
+
height: rect.h,
|
|
176
|
+
background: "rgba(255,200,0,0.2)",
|
|
177
|
+
border: "2px dashed #f97316",
|
|
178
|
+
boxSizing: "border-box",
|
|
179
|
+
pointerEvents: "none"
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
)
|
|
175
183
|
]
|
|
176
184
|
}
|
|
177
185
|
);
|
|
178
186
|
}
|
|
179
187
|
|
|
180
|
-
// src/api.ts
|
|
181
|
-
var import_fflate = require("fflate");
|
|
182
|
-
async function submitReport(serverUrl, projectKey, payload, screenshot) {
|
|
183
|
-
const url = `${serverUrl.replace(/\/$/, "")}/api/v1/bug-reports`;
|
|
184
|
-
let body;
|
|
185
|
-
let headers = {
|
|
186
|
-
"x-project-key": projectKey
|
|
187
|
-
};
|
|
188
|
-
if (screenshot) {
|
|
189
|
-
const form = new FormData();
|
|
190
|
-
form.append("reporterId", payload.reporterId);
|
|
191
|
-
form.append("reporterName", payload.reporterName);
|
|
192
|
-
form.append("description", payload.description);
|
|
193
|
-
if (payload.expectedBehavior) form.append("expectedBehavior", payload.expectedBehavior);
|
|
194
|
-
if (payload.stepsToReproduce) form.append("stepsToReproduce", JSON.stringify(payload.stepsToReproduce));
|
|
195
|
-
if (payload.externalReplayUrl) form.append("externalReplayUrl", payload.externalReplayUrl);
|
|
196
|
-
if (payload.additionalContext) form.append("additionalContext", payload.additionalContext);
|
|
197
|
-
form.append("severity", payload.severity);
|
|
198
|
-
if (payload.url) form.append("url", payload.url);
|
|
199
|
-
if (payload.meta) form.append("meta", JSON.stringify(payload.meta));
|
|
200
|
-
form.append("screenshot", screenshot);
|
|
201
|
-
body = form;
|
|
202
|
-
} else {
|
|
203
|
-
body = JSON.stringify(payload);
|
|
204
|
-
headers["Content-Type"] = "application/json";
|
|
205
|
-
}
|
|
206
|
-
const res = await fetch(url, { method: "POST", headers, body });
|
|
207
|
-
if (!res.ok) {
|
|
208
|
-
const err = await res.json().catch(() => ({ error: "Unknown error" }));
|
|
209
|
-
throw new Error(err.error ?? `HTTP ${res.status}`);
|
|
210
|
-
}
|
|
211
|
-
return res.json();
|
|
212
|
-
}
|
|
213
|
-
async function submitReplay(serverUrl, projectKey, reportId, events) {
|
|
214
|
-
const json = JSON.stringify(events);
|
|
215
|
-
const encoded = new TextEncoder().encode(json);
|
|
216
|
-
const compressed = (0, import_fflate.gzipSync)(encoded);
|
|
217
|
-
const url = `${serverUrl.replace(/\/$/, "")}/api/v1/bug-reports/${reportId}/replay`;
|
|
218
|
-
await fetch(url, {
|
|
219
|
-
method: "POST",
|
|
220
|
-
headers: {
|
|
221
|
-
"x-project-key": projectKey,
|
|
222
|
-
"Content-Type": "application/octet-stream"
|
|
223
|
-
},
|
|
224
|
-
body: compressed.buffer
|
|
225
|
-
});
|
|
226
|
-
}
|
|
227
|
-
|
|
228
188
|
// src/theme.ts
|
|
229
|
-
var
|
|
230
|
-
background: "rgba(255,255,255,0.90)",
|
|
231
|
-
backgroundSecondary: "rgba(249,250,251,0.75)",
|
|
232
|
-
accent: "#2563eb",
|
|
233
|
-
accentHover: "#1d4ed8",
|
|
234
|
-
text: "#111827",
|
|
235
|
-
textMuted: "#6b7280",
|
|
236
|
-
border: "rgba(255,255,255,0.9)",
|
|
237
|
-
shadow: "0 32px 80px rgba(0,0,0,0.18), 0 8px 32px rgba(0,0,0,0.1), 0 0 0 1px rgba(0,0,0,0.04)",
|
|
238
|
-
buttonText: "#ffffff",
|
|
239
|
-
backdropFilter: "blur(32px) saturate(1.8)"
|
|
240
|
-
};
|
|
241
|
-
var dark = {
|
|
242
|
-
background: "rgba(15,20,35,0.88)",
|
|
243
|
-
backgroundSecondary: "rgba(5,8,18,0.65)",
|
|
244
|
-
accent: "#f97316",
|
|
245
|
-
accentHover: "#ea6c0a",
|
|
246
|
-
text: "#dde3ef",
|
|
247
|
-
textMuted: "#6b7a93",
|
|
248
|
-
border: "rgba(255,255,255,0.08)",
|
|
249
|
-
shadow: "0 24px 60px rgba(0,0,0,0.6), 0 0 0 1px rgba(255,255,255,0.04)",
|
|
250
|
-
buttonText: "#ffffff",
|
|
251
|
-
backdropFilter: "blur(32px) saturate(1.6)"
|
|
252
|
-
};
|
|
253
|
-
function resolveTheme(theme) {
|
|
254
|
-
if (theme === "dark") return dark;
|
|
255
|
-
if (theme === "light") return light;
|
|
256
|
-
const override = theme;
|
|
257
|
-
return {
|
|
258
|
-
...light,
|
|
259
|
-
background: override.background ?? light.background,
|
|
260
|
-
accent: override.accent ?? light.accent,
|
|
261
|
-
accentHover: override.accent ?? light.accentHover,
|
|
262
|
-
text: override.text ?? light.text,
|
|
263
|
-
border: override.border ?? light.border
|
|
264
|
-
};
|
|
265
|
-
}
|
|
189
|
+
var import_core2 = require("@flint/core");
|
|
266
190
|
|
|
267
191
|
// src/FlintModal.tsx
|
|
268
192
|
var import_jsx_runtime2 = require("react/jsx-runtime");
|
|
@@ -322,10 +246,15 @@ function FlintModal({
|
|
|
322
246
|
getNetworkErrors,
|
|
323
247
|
getReplayEvents,
|
|
324
248
|
getExternalReplayUrl,
|
|
325
|
-
initialSelection = ""
|
|
249
|
+
initialSelection = "",
|
|
250
|
+
enableScreenshot = true,
|
|
251
|
+
statusPageUrl,
|
|
252
|
+
onBeforeSubmit,
|
|
253
|
+
onSuccess,
|
|
254
|
+
onError
|
|
326
255
|
}) {
|
|
327
256
|
const { t } = (0, import_react_i18next.useTranslation)();
|
|
328
|
-
const colors = resolveTheme(theme);
|
|
257
|
+
const colors = (0, import_core2.resolveTheme)(theme);
|
|
329
258
|
const isDark = theme === "dark";
|
|
330
259
|
const [severity, setSeverity] = (0, import_react2.useState)("P2");
|
|
331
260
|
const [description, setDescription] = (0, import_react2.useState)("");
|
|
@@ -382,33 +311,40 @@ function FlintModal({
|
|
|
382
311
|
lang: textLang
|
|
383
312
|
};
|
|
384
313
|
}
|
|
314
|
+
const payload = {
|
|
315
|
+
reporterId: user?.id ?? "anonymous",
|
|
316
|
+
reporterName: user?.name ?? "Anonymous",
|
|
317
|
+
reporterEmail: user?.email,
|
|
318
|
+
description: isText ? `[Text issue] "${textOriginal.trim()}" \u2192 "${textSuggested.trim()}"` : description.trim(),
|
|
319
|
+
expectedBehavior: !isText ? expectedBehavior.trim() || void 0 : void 0,
|
|
320
|
+
externalReplayUrl: getExternalReplayUrl() || void 0,
|
|
321
|
+
severity: isText ? "P3" : severity,
|
|
322
|
+
url: window.location.href,
|
|
323
|
+
meta: collectedMeta,
|
|
324
|
+
label: isText ? "TEXT" : void 0
|
|
325
|
+
};
|
|
326
|
+
if (onBeforeSubmit) {
|
|
327
|
+
const proceed = await onBeforeSubmit(payload);
|
|
328
|
+
if (!proceed) {
|
|
329
|
+
setStatus("idle");
|
|
330
|
+
return;
|
|
331
|
+
}
|
|
332
|
+
}
|
|
385
333
|
try {
|
|
386
|
-
const res = await submitReport(
|
|
387
|
-
serverUrl,
|
|
388
|
-
projectKey,
|
|
389
|
-
{
|
|
390
|
-
reporterId: user?.id ?? "anonymous",
|
|
391
|
-
reporterName: user?.name ?? "Anonymous",
|
|
392
|
-
description: isText ? `[Text issue] "${textOriginal.trim()}" \u2192 "${textSuggested.trim()}"` : description.trim(),
|
|
393
|
-
expectedBehavior: !isText ? expectedBehavior.trim() || void 0 : void 0,
|
|
394
|
-
externalReplayUrl: getExternalReplayUrl() || void 0,
|
|
395
|
-
severity: isText ? "P3" : severity,
|
|
396
|
-
url: window.location.href,
|
|
397
|
-
meta: collectedMeta,
|
|
398
|
-
label: isText ? "TEXT" : void 0
|
|
399
|
-
},
|
|
400
|
-
!isText ? screenshot ?? void 0 : void 0
|
|
401
|
-
);
|
|
334
|
+
const res = await (0, import_core.submitReport)(serverUrl, projectKey, payload, !isText ? screenshot ?? void 0 : void 0);
|
|
402
335
|
setResult(res);
|
|
403
336
|
setStatus("success");
|
|
337
|
+
onSuccess?.(res);
|
|
404
338
|
const events = getReplayEvents();
|
|
405
339
|
if (events.length > 0) {
|
|
406
|
-
submitReplay(serverUrl, projectKey, res.id, events).catch(() => {
|
|
340
|
+
(0, import_core.submitReplay)(serverUrl, projectKey, res.id, events).catch(() => {
|
|
407
341
|
});
|
|
408
342
|
}
|
|
409
343
|
} catch (err) {
|
|
410
|
-
|
|
344
|
+
const error = err instanceof Error ? err : new Error(t("errorLabel"));
|
|
345
|
+
setErrorMsg(error.message);
|
|
411
346
|
setStatus("error");
|
|
347
|
+
onError?.(error);
|
|
412
348
|
}
|
|
413
349
|
};
|
|
414
350
|
const inputBorder = isDark ? "rgba(255,255,255,0.1)" : "rgba(0,0,0,0.1)";
|
|
@@ -458,157 +394,249 @@ function FlintModal({
|
|
|
458
394
|
const isSuccess = status === "success";
|
|
459
395
|
const ringBorder = isSuccess ? "3px solid #22c55e" : `3px solid ${isDark ? "rgba(255,255,255,0.08)" : "rgba(0,0,0,0.08)"}`;
|
|
460
396
|
const ringTopColor = isSuccess ? "#22c55e" : colors.accent;
|
|
461
|
-
return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { style: overlayStyle, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
397
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { style: overlayStyle, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
|
|
398
|
+
"div",
|
|
399
|
+
{
|
|
400
|
+
style: modalStyle,
|
|
401
|
+
role: "dialog",
|
|
402
|
+
"aria-modal": "true",
|
|
403
|
+
"aria-label": isSuccess ? t("successTitle") : t("sending"),
|
|
404
|
+
children: [
|
|
405
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(ModalHeader, { colors, inputBorder, showClose: false, onClose }),
|
|
406
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
|
|
407
|
+
"div",
|
|
408
|
+
{
|
|
409
|
+
style: {
|
|
410
|
+
padding: "40px 32px 48px",
|
|
411
|
+
textAlign: "center",
|
|
412
|
+
display: "flex",
|
|
413
|
+
flexDirection: "column",
|
|
414
|
+
alignItems: "center"
|
|
415
|
+
},
|
|
416
|
+
children: [
|
|
417
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { style: { position: "relative", width: 80, height: 80, marginBottom: 28 }, children: [
|
|
418
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
419
|
+
"div",
|
|
420
|
+
{
|
|
421
|
+
style: {
|
|
422
|
+
position: "absolute",
|
|
423
|
+
inset: -10,
|
|
424
|
+
borderRadius: "50%",
|
|
425
|
+
border: `1.5px solid ${colors.accent}`,
|
|
426
|
+
animation: "_flint_ripple 1.8s ease-out infinite",
|
|
427
|
+
opacity: isSuccess ? 0 : 1,
|
|
428
|
+
transition: "opacity 0.3s ease"
|
|
429
|
+
}
|
|
430
|
+
}
|
|
431
|
+
),
|
|
432
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
433
|
+
"div",
|
|
434
|
+
{
|
|
435
|
+
style: {
|
|
436
|
+
position: "absolute",
|
|
437
|
+
inset: -10,
|
|
438
|
+
borderRadius: "50%",
|
|
439
|
+
border: `1.5px solid ${colors.accent}`,
|
|
440
|
+
animation: "_flint_ripple 1.8s ease-out infinite 0.6s",
|
|
441
|
+
opacity: isSuccess ? 0 : 1,
|
|
442
|
+
transition: "opacity 0.3s ease"
|
|
443
|
+
}
|
|
444
|
+
}
|
|
445
|
+
),
|
|
446
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
447
|
+
"div",
|
|
448
|
+
{
|
|
449
|
+
style: {
|
|
450
|
+
position: "absolute",
|
|
451
|
+
inset: 0,
|
|
452
|
+
borderRadius: "50%",
|
|
453
|
+
border: ringBorder,
|
|
454
|
+
borderTopColor: ringTopColor,
|
|
455
|
+
animation: isSuccess ? "none" : "_flint_spin 0.85s linear infinite",
|
|
456
|
+
transition: "border-color 0.45s ease, border-top-color 0.45s ease"
|
|
457
|
+
}
|
|
458
|
+
}
|
|
459
|
+
),
|
|
460
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { style: { position: "absolute", inset: 14, borderRadius: "50%" }, children: [
|
|
461
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
462
|
+
"div",
|
|
463
|
+
{
|
|
464
|
+
style: {
|
|
465
|
+
position: "absolute",
|
|
466
|
+
inset: 0,
|
|
467
|
+
borderRadius: "50%",
|
|
468
|
+
background: `linear-gradient(135deg, ${colors.accent}30, ${colors.accentHover}50)`,
|
|
469
|
+
display: "flex",
|
|
470
|
+
alignItems: "center",
|
|
471
|
+
justifyContent: "center",
|
|
472
|
+
animation: isSuccess ? "none" : "_flint_pulse 2s ease-in-out infinite",
|
|
473
|
+
opacity: isSuccess ? 0 : 1,
|
|
474
|
+
transition: "opacity 0.3s ease"
|
|
475
|
+
},
|
|
476
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(SparkIcon, { color: colors.accent, size: 20 })
|
|
477
|
+
}
|
|
478
|
+
),
|
|
479
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
480
|
+
"div",
|
|
481
|
+
{
|
|
482
|
+
style: {
|
|
483
|
+
position: "absolute",
|
|
484
|
+
inset: 0,
|
|
485
|
+
borderRadius: "50%",
|
|
486
|
+
background: "rgba(34,197,94,0.15)",
|
|
487
|
+
display: "flex",
|
|
488
|
+
alignItems: "center",
|
|
489
|
+
justifyContent: "center",
|
|
490
|
+
opacity: isSuccess ? 1 : 0,
|
|
491
|
+
transform: isSuccess ? "scale(1)" : "scale(0.65)",
|
|
492
|
+
transition: "opacity 0.35s ease 0.2s, transform 0.4s cubic-bezier(0.16,1,0.3,1) 0.2s"
|
|
493
|
+
},
|
|
494
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(CheckIcon, { size: 20 })
|
|
495
|
+
}
|
|
496
|
+
)
|
|
497
|
+
] })
|
|
498
|
+
] }),
|
|
499
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { style: { position: "relative", height: 26, width: "100%", marginBottom: 10 }, children: [
|
|
500
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
501
|
+
"div",
|
|
502
|
+
{
|
|
503
|
+
style: {
|
|
504
|
+
position: "absolute",
|
|
505
|
+
inset: 0,
|
|
506
|
+
display: "flex",
|
|
507
|
+
alignItems: "center",
|
|
508
|
+
justifyContent: "center",
|
|
509
|
+
fontSize: 19,
|
|
510
|
+
fontWeight: 700,
|
|
511
|
+
color: colors.text,
|
|
512
|
+
letterSpacing: "-0.02em",
|
|
513
|
+
opacity: isSuccess ? 0 : 1,
|
|
514
|
+
transition: "opacity 0.25s ease",
|
|
515
|
+
pointerEvents: "none"
|
|
516
|
+
},
|
|
517
|
+
children: t("sending")
|
|
518
|
+
}
|
|
519
|
+
),
|
|
520
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
521
|
+
"div",
|
|
522
|
+
{
|
|
523
|
+
style: {
|
|
524
|
+
position: "absolute",
|
|
525
|
+
inset: 0,
|
|
526
|
+
display: "flex",
|
|
527
|
+
alignItems: "center",
|
|
528
|
+
justifyContent: "center",
|
|
529
|
+
fontSize: 19,
|
|
530
|
+
fontWeight: 700,
|
|
531
|
+
color: colors.text,
|
|
532
|
+
letterSpacing: "-0.02em",
|
|
533
|
+
opacity: isSuccess ? 1 : 0,
|
|
534
|
+
transform: isSuccess ? "translateY(0)" : "translateY(6px)",
|
|
535
|
+
transition: "opacity 0.35s ease 0.25s, transform 0.35s ease 0.25s",
|
|
536
|
+
pointerEvents: isSuccess ? "auto" : "none"
|
|
537
|
+
},
|
|
538
|
+
children: t("successTitle")
|
|
539
|
+
}
|
|
540
|
+
)
|
|
541
|
+
] }),
|
|
542
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { style: { position: "relative", minHeight: 76, width: "100%" }, children: [
|
|
543
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
|
|
544
|
+
"div",
|
|
545
|
+
{
|
|
546
|
+
style: {
|
|
547
|
+
position: "absolute",
|
|
548
|
+
inset: 0,
|
|
549
|
+
display: "flex",
|
|
550
|
+
alignItems: "center",
|
|
551
|
+
justifyContent: "center",
|
|
552
|
+
gap: 6,
|
|
553
|
+
color: colors.textMuted,
|
|
554
|
+
fontSize: 15,
|
|
555
|
+
opacity: isSuccess ? 0 : 1,
|
|
556
|
+
transition: "opacity 0.2s ease",
|
|
557
|
+
pointerEvents: "none"
|
|
558
|
+
},
|
|
559
|
+
children: [
|
|
560
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { children: t("capturingContext") }),
|
|
561
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(SendingDots, { color: colors.accent })
|
|
562
|
+
]
|
|
563
|
+
}
|
|
564
|
+
),
|
|
565
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
|
|
566
|
+
"div",
|
|
567
|
+
{
|
|
568
|
+
style: {
|
|
569
|
+
position: "absolute",
|
|
570
|
+
inset: 0,
|
|
571
|
+
display: "flex",
|
|
572
|
+
flexDirection: "column",
|
|
573
|
+
alignItems: "center",
|
|
574
|
+
gap: 10,
|
|
575
|
+
opacity: isSuccess ? 1 : 0,
|
|
576
|
+
transform: isSuccess ? "translateY(0)" : "translateY(8px)",
|
|
577
|
+
transition: "opacity 0.35s ease 0.35s, transform 0.35s ease 0.35s",
|
|
578
|
+
pointerEvents: isSuccess ? "auto" : "none"
|
|
579
|
+
},
|
|
580
|
+
children: [
|
|
581
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { style: { fontSize: 15, color: colors.textMuted, margin: 0 }, children: result ? `ID: ${result.id}` : "" }),
|
|
582
|
+
statusPageUrl && user?.id && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
|
|
583
|
+
"a",
|
|
584
|
+
{
|
|
585
|
+
href: `${statusPageUrl}/status?project_key=${encodeURIComponent(projectKey)}&reporter_id=${encodeURIComponent(user.id)}&server_url=${encodeURIComponent(serverUrl)}`,
|
|
586
|
+
target: "_blank",
|
|
587
|
+
rel: "noreferrer",
|
|
588
|
+
style: {
|
|
589
|
+
fontSize: 14,
|
|
590
|
+
color: colors.accent,
|
|
591
|
+
textDecoration: "none",
|
|
592
|
+
fontWeight: 600,
|
|
593
|
+
animation: "_flint_success_up 0.35s ease 0.4s both"
|
|
594
|
+
},
|
|
595
|
+
children: [
|
|
596
|
+
"\u{1F4CB}",
|
|
597
|
+
" Track your bugs ",
|
|
598
|
+
"\u2192"
|
|
599
|
+
]
|
|
600
|
+
}
|
|
601
|
+
),
|
|
602
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
603
|
+
"button",
|
|
604
|
+
{
|
|
605
|
+
onClick: onClose,
|
|
606
|
+
style: {
|
|
607
|
+
width: "100%",
|
|
608
|
+
padding: "13px 20px",
|
|
609
|
+
borderRadius: 12,
|
|
610
|
+
border: "none",
|
|
611
|
+
background: `linear-gradient(135deg, ${colors.accent}, ${colors.accentHover})`,
|
|
612
|
+
color: colors.buttonText,
|
|
613
|
+
fontSize: 17,
|
|
614
|
+
fontWeight: 700,
|
|
615
|
+
cursor: "pointer",
|
|
616
|
+
letterSpacing: "-0.01em",
|
|
617
|
+
boxShadow: accentGlow,
|
|
618
|
+
fontFamily: "inherit",
|
|
619
|
+
display: "flex",
|
|
620
|
+
alignItems: "center",
|
|
621
|
+
justifyContent: "center",
|
|
622
|
+
gap: 8
|
|
623
|
+
},
|
|
624
|
+
children: t("close")
|
|
625
|
+
}
|
|
626
|
+
)
|
|
627
|
+
]
|
|
628
|
+
}
|
|
629
|
+
)
|
|
630
|
+
] })
|
|
631
|
+
]
|
|
632
|
+
}
|
|
633
|
+
)
|
|
634
|
+
]
|
|
635
|
+
}
|
|
636
|
+
) });
|
|
609
637
|
}
|
|
610
638
|
return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_jsx_runtime2.Fragment, { children: [
|
|
611
|
-
annotating && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
639
|
+
enableScreenshot && annotating && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
612
640
|
ScreenAnnotator,
|
|
613
641
|
{
|
|
614
642
|
zIndex: zIndex + 1,
|
|
@@ -632,37 +660,43 @@ function FlintModal({
|
|
|
632
660
|
}
|
|
633
661
|
),
|
|
634
662
|
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("form", { onSubmit: handleSubmit, style: { padding: "20px 24px 24px" }, children: [
|
|
635
|
-
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
636
|
-
|
|
637
|
-
gap: 4,
|
|
638
|
-
marginBottom: 20,
|
|
639
|
-
background: colors.backgroundSecondary,
|
|
640
|
-
borderRadius: 12,
|
|
641
|
-
padding: 4,
|
|
642
|
-
border: `1px solid ${inputBorder}`
|
|
643
|
-
}, children: ["bug", "text"].map((m) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
644
|
-
"button",
|
|
663
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
664
|
+
"div",
|
|
645
665
|
{
|
|
646
|
-
type: "button",
|
|
647
|
-
onClick: () => setMode(m),
|
|
648
666
|
style: {
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
fontFamily: "inherit",
|
|
657
|
-
transition: "background 0.15s, color 0.15s",
|
|
658
|
-
background: mode === m ? `linear-gradient(135deg, ${colors.accent}, ${colors.accentHover})` : "transparent",
|
|
659
|
-
color: mode === m ? colors.buttonText : colors.textMuted,
|
|
660
|
-
boxShadow: mode === m ? `0 2px 8px ${colors.accent}30` : "none"
|
|
667
|
+
display: "flex",
|
|
668
|
+
gap: 4,
|
|
669
|
+
marginBottom: 20,
|
|
670
|
+
background: colors.backgroundSecondary,
|
|
671
|
+
borderRadius: 12,
|
|
672
|
+
padding: 4,
|
|
673
|
+
border: `1px solid ${inputBorder}`
|
|
661
674
|
},
|
|
662
|
-
children:
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
675
|
+
children: ["bug", "text"].map((m) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
676
|
+
"button",
|
|
677
|
+
{
|
|
678
|
+
type: "button",
|
|
679
|
+
onClick: () => setMode(m),
|
|
680
|
+
style: {
|
|
681
|
+
flex: 1,
|
|
682
|
+
padding: "8px 10px",
|
|
683
|
+
borderRadius: 9,
|
|
684
|
+
border: "none",
|
|
685
|
+
cursor: "pointer",
|
|
686
|
+
fontSize: 13,
|
|
687
|
+
fontWeight: mode === m ? 700 : 500,
|
|
688
|
+
fontFamily: "inherit",
|
|
689
|
+
transition: "background 0.15s, color 0.15s",
|
|
690
|
+
background: mode === m ? `linear-gradient(135deg, ${colors.accent}, ${colors.accentHover})` : "transparent",
|
|
691
|
+
color: mode === m ? colors.buttonText : colors.textMuted,
|
|
692
|
+
boxShadow: mode === m ? `0 2px 8px ${colors.accent}30` : "none"
|
|
693
|
+
},
|
|
694
|
+
children: m === "bug" ? "\u{1F41B} Bug" : "\u{1F524} Text / Translation"
|
|
695
|
+
},
|
|
696
|
+
m
|
|
697
|
+
))
|
|
698
|
+
}
|
|
699
|
+
),
|
|
666
700
|
mode === "text" && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_jsx_runtime2.Fragment, { children: [
|
|
667
701
|
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { style: { marginBottom: 14 }, children: [
|
|
668
702
|
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(FieldLabel, { colors, htmlFor: "flint-text-original", children: "Original text" }),
|
|
@@ -759,7 +793,7 @@ function FlintModal({
|
|
|
759
793
|
}
|
|
760
794
|
)
|
|
761
795
|
] }),
|
|
762
|
-
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { style: { marginBottom: 20, display: mode === "text" ? "none" : void 0 }, children: [
|
|
796
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { style: { marginBottom: 20, display: mode === "text" || !enableScreenshot ? "none" : void 0 }, children: [
|
|
763
797
|
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(FieldLabel, { colors, children: t("screenshotLabel") }),
|
|
764
798
|
screenshot ? /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { style: { display: "flex", alignItems: "center", gap: 10 }, children: [
|
|
765
799
|
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
@@ -770,7 +804,20 @@ function FlintModal({
|
|
|
770
804
|
style: { height: 60, borderRadius: 8, objectFit: "cover", border: `1px solid ${inputBorder}` }
|
|
771
805
|
}
|
|
772
806
|
),
|
|
773
|
-
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
807
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
808
|
+
"span",
|
|
809
|
+
{
|
|
810
|
+
style: {
|
|
811
|
+
fontSize: 13,
|
|
812
|
+
color: colors.textMuted,
|
|
813
|
+
flex: 1,
|
|
814
|
+
overflow: "hidden",
|
|
815
|
+
textOverflow: "ellipsis",
|
|
816
|
+
whiteSpace: "nowrap"
|
|
817
|
+
},
|
|
818
|
+
children: screenshot.name
|
|
819
|
+
}
|
|
820
|
+
),
|
|
774
821
|
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
775
822
|
"button",
|
|
776
823
|
{
|
|
@@ -857,31 +904,43 @@ function FlintModal({
|
|
|
857
904
|
}
|
|
858
905
|
)
|
|
859
906
|
] }),
|
|
860
|
-
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
907
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
|
|
908
|
+
"div",
|
|
909
|
+
{
|
|
910
|
+
style: {
|
|
911
|
+
display: "flex",
|
|
912
|
+
alignItems: "center",
|
|
913
|
+
gap: 8,
|
|
914
|
+
padding: "9px 12px",
|
|
915
|
+
borderRadius: 10,
|
|
916
|
+
background: isDark ? "rgba(255,255,255,0.04)" : "rgba(0,77,240,0.04)",
|
|
917
|
+
border: `1px solid ${isDark ? "rgba(255,255,255,0.08)" : "rgba(0,77,240,0.1)"}`,
|
|
918
|
+
marginBottom: 16
|
|
919
|
+
},
|
|
920
|
+
children: [
|
|
921
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { style: { fontSize: 16 }, children: "\u{1F3A5}" }),
|
|
922
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { style: { fontSize: 14, color: colors.textMuted, lineHeight: 1.4 }, children: t("replayInfo") })
|
|
923
|
+
]
|
|
924
|
+
}
|
|
925
|
+
),
|
|
926
|
+
status === "error" && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
|
|
927
|
+
"div",
|
|
928
|
+
{
|
|
929
|
+
style: {
|
|
930
|
+
padding: "10px 13px",
|
|
931
|
+
borderRadius: 10,
|
|
932
|
+
background: "rgba(239,68,68,0.08)",
|
|
933
|
+
border: "1px solid rgba(239,68,68,0.2)",
|
|
934
|
+
color: "#f87171",
|
|
935
|
+
fontSize: 14,
|
|
936
|
+
marginBottom: 16
|
|
937
|
+
},
|
|
938
|
+
children: [
|
|
939
|
+
"\u26A0\uFE0F ",
|
|
940
|
+
errorMsg || t("errorLabel")
|
|
941
|
+
]
|
|
942
|
+
}
|
|
943
|
+
),
|
|
885
944
|
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
|
|
886
945
|
"button",
|
|
887
946
|
{
|
|
@@ -942,49 +1001,68 @@ function ModalHeader({
|
|
|
942
1001
|
titleId,
|
|
943
1002
|
title
|
|
944
1003
|
}) {
|
|
945
|
-
return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
1004
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
|
|
1005
|
+
"div",
|
|
1006
|
+
{
|
|
1007
|
+
style: {
|
|
1008
|
+
display: "flex",
|
|
1009
|
+
alignItems: "center",
|
|
1010
|
+
gap: 10,
|
|
1011
|
+
padding: "16px 20px 14px",
|
|
1012
|
+
borderBottom: `1px solid ${inputBorder}`
|
|
1013
|
+
},
|
|
1014
|
+
children: [
|
|
1015
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
1016
|
+
"div",
|
|
1017
|
+
{
|
|
1018
|
+
style: {
|
|
1019
|
+
width: 28,
|
|
1020
|
+
height: 28,
|
|
1021
|
+
borderRadius: 8,
|
|
1022
|
+
background: `linear-gradient(135deg, ${colors.accent}20, ${colors.accentHover}35)`,
|
|
1023
|
+
border: `1px solid ${colors.accent}30`,
|
|
1024
|
+
display: "flex",
|
|
1025
|
+
alignItems: "center",
|
|
1026
|
+
justifyContent: "center",
|
|
1027
|
+
flexShrink: 0
|
|
1028
|
+
},
|
|
1029
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(SparkIcon, { color: colors.accent, size: 13 })
|
|
1030
|
+
}
|
|
1031
|
+
),
|
|
1032
|
+
titleId && title ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
1033
|
+
"h2",
|
|
1034
|
+
{
|
|
1035
|
+
id: titleId,
|
|
1036
|
+
style: { margin: 0, fontSize: 16, fontWeight: 600, color: colors.text, letterSpacing: "-0.01em", flex: 1 },
|
|
1037
|
+
children: title
|
|
1038
|
+
}
|
|
1039
|
+
) : /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { style: { flex: 1, fontSize: 15, fontWeight: 600, color: colors.textMuted }, children: "Flint" }),
|
|
1040
|
+
showClose && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
1041
|
+
"button",
|
|
1042
|
+
{
|
|
1043
|
+
onClick: onClose,
|
|
1044
|
+
"aria-label": "Close",
|
|
1045
|
+
style: {
|
|
1046
|
+
background: "none",
|
|
1047
|
+
border: "none",
|
|
1048
|
+
cursor: "pointer",
|
|
1049
|
+
padding: 4,
|
|
1050
|
+
color: colors.textMuted,
|
|
1051
|
+
fontSize: 22,
|
|
1052
|
+
lineHeight: 1,
|
|
1053
|
+
borderRadius: 6,
|
|
1054
|
+
display: "flex",
|
|
1055
|
+
alignItems: "center",
|
|
1056
|
+
justifyContent: "center",
|
|
1057
|
+
opacity: 0.6,
|
|
1058
|
+
fontFamily: "inherit"
|
|
1059
|
+
},
|
|
1060
|
+
children: "\xD7"
|
|
1061
|
+
}
|
|
1062
|
+
)
|
|
1063
|
+
]
|
|
1064
|
+
}
|
|
1065
|
+
);
|
|
988
1066
|
}
|
|
989
1067
|
function FieldLabel({
|
|
990
1068
|
children,
|
|
@@ -1046,19 +1124,74 @@ function SeverityButton({ sev, label, selected, hint, color, accent, border, bg,
|
|
|
1046
1124
|
},
|
|
1047
1125
|
children: [
|
|
1048
1126
|
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { style: { width: 8, height: 8, borderRadius: "50%", background: color, display: "block" } }),
|
|
1049
|
-
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
1127
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
1128
|
+
"span",
|
|
1129
|
+
{
|
|
1130
|
+
style: {
|
|
1131
|
+
fontSize: 13,
|
|
1132
|
+
fontWeight: selected ? 700 : 500,
|
|
1133
|
+
color: selected ? accent : text,
|
|
1134
|
+
letterSpacing: "0.02em"
|
|
1135
|
+
},
|
|
1136
|
+
children: sev
|
|
1137
|
+
}
|
|
1138
|
+
),
|
|
1050
1139
|
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { style: { fontSize: 11, color: selected ? accent : text, opacity: 0.6, letterSpacing: "0.02em" }, children: label })
|
|
1051
1140
|
]
|
|
1052
1141
|
}
|
|
1053
1142
|
);
|
|
1054
1143
|
}
|
|
1055
1144
|
function SparkIcon({ color = "currentColor", size = 14 }) {
|
|
1056
|
-
return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
1145
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
1146
|
+
"svg",
|
|
1147
|
+
{
|
|
1148
|
+
width: size,
|
|
1149
|
+
height: size,
|
|
1150
|
+
viewBox: "0 0 24 24",
|
|
1151
|
+
fill: "none",
|
|
1152
|
+
stroke: color,
|
|
1153
|
+
strokeWidth: "2.2",
|
|
1154
|
+
strokeLinecap: "round",
|
|
1155
|
+
strokeLinejoin: "round",
|
|
1156
|
+
"aria-hidden": "true",
|
|
1157
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("path", { d: "M13 2L3 14h9l-1 8 10-12h-9l1-8z" })
|
|
1158
|
+
}
|
|
1159
|
+
);
|
|
1057
1160
|
}
|
|
1058
1161
|
function CheckIcon({ size = 20 }) {
|
|
1059
|
-
return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
1162
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
1163
|
+
"svg",
|
|
1164
|
+
{
|
|
1165
|
+
width: size,
|
|
1166
|
+
height: size,
|
|
1167
|
+
viewBox: "0 0 24 24",
|
|
1168
|
+
fill: "none",
|
|
1169
|
+
stroke: "#22c55e",
|
|
1170
|
+
strokeWidth: "2.5",
|
|
1171
|
+
strokeLinecap: "round",
|
|
1172
|
+
strokeLinejoin: "round",
|
|
1173
|
+
"aria-hidden": "true",
|
|
1174
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("polyline", { points: "20 6 9 17 4 12" })
|
|
1175
|
+
}
|
|
1176
|
+
);
|
|
1060
1177
|
}
|
|
1061
1178
|
|
|
1179
|
+
// src/FlintWidget.tsx
|
|
1180
|
+
var import_react4 = require("react");
|
|
1181
|
+
var import_react_i18next3 = require("react-i18next");
|
|
1182
|
+
|
|
1183
|
+
// src/collectors/console.ts
|
|
1184
|
+
var import_core3 = require("@flint/core");
|
|
1185
|
+
|
|
1186
|
+
// src/collectors/environment.ts
|
|
1187
|
+
var import_core4 = require("@flint/core");
|
|
1188
|
+
|
|
1189
|
+
// src/collectors/frustration.ts
|
|
1190
|
+
var import_core5 = require("@flint/core");
|
|
1191
|
+
|
|
1192
|
+
// src/collectors/network.ts
|
|
1193
|
+
var import_core6 = require("@flint/core");
|
|
1194
|
+
|
|
1062
1195
|
// src/i18n/index.ts
|
|
1063
1196
|
var import_i18next = require("i18next");
|
|
1064
1197
|
var import_react_i18next2 = require("react-i18next");
|
|
@@ -1108,251 +1241,15 @@ widgetI18n.use(import_react_i18next2.initReactI18next).init({
|
|
|
1108
1241
|
});
|
|
1109
1242
|
var i18n_default = widgetI18n;
|
|
1110
1243
|
|
|
1111
|
-
// src/collectors/environment.ts
|
|
1112
|
-
function collectEnvironment() {
|
|
1113
|
-
const ua = navigator.userAgent;
|
|
1114
|
-
let browser = "Unknown";
|
|
1115
|
-
const chromeM = ua.match(/Chrome\/(\d+)/);
|
|
1116
|
-
const firefoxM = ua.match(/Firefox\/(\d+)/);
|
|
1117
|
-
const edgeM = ua.match(/Edg\/(\d+)/);
|
|
1118
|
-
const safariM = ua.match(/Version\/(\d+)/);
|
|
1119
|
-
const operaM = ua.match(/OPR\/(\d+)/);
|
|
1120
|
-
if (operaM) {
|
|
1121
|
-
browser = `Opera ${operaM[1]}`;
|
|
1122
|
-
} else if (edgeM) {
|
|
1123
|
-
browser = `Edge ${edgeM[1]}`;
|
|
1124
|
-
} else if (chromeM && !/Edg|OPR/.test(ua)) {
|
|
1125
|
-
browser = `Chrome ${chromeM[1]}`;
|
|
1126
|
-
} else if (firefoxM) {
|
|
1127
|
-
browser = `Firefox ${firefoxM[1]}`;
|
|
1128
|
-
} else if (safariM && /Safari\//.test(ua)) {
|
|
1129
|
-
browser = `Safari ${safariM[1]}`;
|
|
1130
|
-
}
|
|
1131
|
-
let os = "Unknown";
|
|
1132
|
-
const macM = ua.match(/Mac OS X (\d+[._]\d+)/);
|
|
1133
|
-
const winM = ua.match(/Windows NT (\d+\.\d+)/);
|
|
1134
|
-
const androidM = ua.match(/Android (\d+)/);
|
|
1135
|
-
const iosM = ua.match(/iPhone OS (\d+[._]\d+)/);
|
|
1136
|
-
if (macM) {
|
|
1137
|
-
os = `macOS ${macM[1].replace("_", ".")}`;
|
|
1138
|
-
} else if (winM) {
|
|
1139
|
-
const winMap = {
|
|
1140
|
-
"10.0": "10/11",
|
|
1141
|
-
"6.3": "8.1",
|
|
1142
|
-
"6.2": "8",
|
|
1143
|
-
"6.1": "7"
|
|
1144
|
-
};
|
|
1145
|
-
os = `Windows ${winMap[winM[1]] ?? winM[1]}`;
|
|
1146
|
-
} else if (androidM) {
|
|
1147
|
-
os = `Android ${androidM[1]}`;
|
|
1148
|
-
} else if (iosM) {
|
|
1149
|
-
os = `iOS ${iosM[1].replace(/_/g, ".")}`;
|
|
1150
|
-
} else if (/Linux/.test(ua)) {
|
|
1151
|
-
os = "Linux";
|
|
1152
|
-
}
|
|
1153
|
-
return {
|
|
1154
|
-
browser,
|
|
1155
|
-
os,
|
|
1156
|
-
viewport: `${window.innerWidth}x${window.innerHeight}`,
|
|
1157
|
-
screen: `${screen.width}x${screen.height}`,
|
|
1158
|
-
language: navigator.language,
|
|
1159
|
-
timezone: Intl.DateTimeFormat().resolvedOptions().timeZone,
|
|
1160
|
-
online: navigator.onLine
|
|
1161
|
-
};
|
|
1162
|
-
}
|
|
1163
|
-
|
|
1164
|
-
// src/collectors/console.ts
|
|
1165
|
-
var MAX_ENTRIES = 50;
|
|
1166
|
-
function createConsoleCollector() {
|
|
1167
|
-
const entries = [];
|
|
1168
|
-
let active = false;
|
|
1169
|
-
const originals = {
|
|
1170
|
-
log: console.log.bind(console),
|
|
1171
|
-
warn: console.warn.bind(console),
|
|
1172
|
-
error: console.error.bind(console)
|
|
1173
|
-
};
|
|
1174
|
-
let origOnerror = null;
|
|
1175
|
-
let origUnhandled = null;
|
|
1176
|
-
function push(level, args) {
|
|
1177
|
-
let str;
|
|
1178
|
-
try {
|
|
1179
|
-
str = args.map((a) => typeof a === "string" ? a : JSON.stringify(a)).join(" ");
|
|
1180
|
-
} catch {
|
|
1181
|
-
str = String(args[0]);
|
|
1182
|
-
}
|
|
1183
|
-
if (str.length > 500) str = str.slice(0, 500) + "\u2026";
|
|
1184
|
-
entries.push({ level, args: str, timestamp: Date.now() });
|
|
1185
|
-
if (entries.length > MAX_ENTRIES) entries.shift();
|
|
1186
|
-
}
|
|
1187
|
-
return {
|
|
1188
|
-
start() {
|
|
1189
|
-
if (active) return;
|
|
1190
|
-
active = true;
|
|
1191
|
-
console.log = (...args) => {
|
|
1192
|
-
push("log", args);
|
|
1193
|
-
originals.log(...args);
|
|
1194
|
-
};
|
|
1195
|
-
console.warn = (...args) => {
|
|
1196
|
-
push("warn", args);
|
|
1197
|
-
originals.warn(...args);
|
|
1198
|
-
};
|
|
1199
|
-
console.error = (...args) => {
|
|
1200
|
-
push("error", args);
|
|
1201
|
-
originals.error(...args);
|
|
1202
|
-
};
|
|
1203
|
-
origOnerror = window.onerror;
|
|
1204
|
-
window.onerror = (msg, src, line, col, err) => {
|
|
1205
|
-
push("error", [err?.message ?? String(msg), `${src}:${line}:${col}`]);
|
|
1206
|
-
if (typeof origOnerror === "function")
|
|
1207
|
-
return origOnerror(msg, src, line, col, err);
|
|
1208
|
-
return false;
|
|
1209
|
-
};
|
|
1210
|
-
origUnhandled = window.onunhandledrejection;
|
|
1211
|
-
window.onunhandledrejection = (event) => {
|
|
1212
|
-
const reason = event.reason instanceof Error ? event.reason.message : JSON.stringify(event.reason);
|
|
1213
|
-
push("error", ["UnhandledRejection:", reason]);
|
|
1214
|
-
if (typeof origUnhandled === "function")
|
|
1215
|
-
origUnhandled.call(window, event);
|
|
1216
|
-
};
|
|
1217
|
-
},
|
|
1218
|
-
stop() {
|
|
1219
|
-
if (!active) return;
|
|
1220
|
-
active = false;
|
|
1221
|
-
console.log = originals.log;
|
|
1222
|
-
console.warn = originals.warn;
|
|
1223
|
-
console.error = originals.error;
|
|
1224
|
-
window.onerror = origOnerror;
|
|
1225
|
-
window.onunhandledrejection = origUnhandled;
|
|
1226
|
-
},
|
|
1227
|
-
getEntries() {
|
|
1228
|
-
return [...entries];
|
|
1229
|
-
}
|
|
1230
|
-
};
|
|
1231
|
-
}
|
|
1232
|
-
|
|
1233
|
-
// src/collectors/network.ts
|
|
1234
|
-
var MAX_ENTRIES2 = 50;
|
|
1235
|
-
var BLOCKED_HOSTS = /* @__PURE__ */ new Set([
|
|
1236
|
-
"browser-intake-datadoghq.com",
|
|
1237
|
-
"rum.browser-intake-datadoghq.com",
|
|
1238
|
-
"logs.browser-intake-datadoghq.com",
|
|
1239
|
-
"session-replay.browser-intake-datadoghq.com"
|
|
1240
|
-
]);
|
|
1241
|
-
function isBlockedUrl(url, extra) {
|
|
1242
|
-
try {
|
|
1243
|
-
const host = new URL(url, location.href).hostname;
|
|
1244
|
-
const all = [...BLOCKED_HOSTS, ...extra];
|
|
1245
|
-
return all.some((b) => host === b || host.endsWith("." + b));
|
|
1246
|
-
} catch {
|
|
1247
|
-
return false;
|
|
1248
|
-
}
|
|
1249
|
-
}
|
|
1250
|
-
function truncateUrl(url) {
|
|
1251
|
-
try {
|
|
1252
|
-
const u = new URL(url, location.href);
|
|
1253
|
-
const base = `${u.origin}${u.pathname}`;
|
|
1254
|
-
return base.length > 200 ? base.slice(0, 200) + "\u2026" : base;
|
|
1255
|
-
} catch {
|
|
1256
|
-
return url.length > 200 ? url.slice(0, 200) + "\u2026" : url;
|
|
1257
|
-
}
|
|
1258
|
-
}
|
|
1259
|
-
function createNetworkCollector(extraBlockedHosts = []) {
|
|
1260
|
-
const entries = [];
|
|
1261
|
-
const blocked = new Set(extraBlockedHosts);
|
|
1262
|
-
let origFetch = null;
|
|
1263
|
-
let origXHROpen = null;
|
|
1264
|
-
let active = false;
|
|
1265
|
-
function push(entry) {
|
|
1266
|
-
entries.push(entry);
|
|
1267
|
-
if (entries.length > MAX_ENTRIES2) entries.shift();
|
|
1268
|
-
}
|
|
1269
|
-
return {
|
|
1270
|
-
start() {
|
|
1271
|
-
if (active) return;
|
|
1272
|
-
active = true;
|
|
1273
|
-
origFetch = window.fetch;
|
|
1274
|
-
window.fetch = async (input, init) => {
|
|
1275
|
-
const method = (init?.method ?? "GET").toUpperCase();
|
|
1276
|
-
const url = typeof input === "string" ? input : input instanceof URL ? input.href : input.url;
|
|
1277
|
-
const startTime = Date.now();
|
|
1278
|
-
const res = await origFetch.call(window, input, init);
|
|
1279
|
-
if (res.status >= 400 && !isBlockedUrl(url, blocked)) {
|
|
1280
|
-
push({
|
|
1281
|
-
method,
|
|
1282
|
-
url: truncateUrl(url),
|
|
1283
|
-
status: res.status,
|
|
1284
|
-
duration: Date.now() - startTime,
|
|
1285
|
-
timestamp: startTime
|
|
1286
|
-
});
|
|
1287
|
-
}
|
|
1288
|
-
return res;
|
|
1289
|
-
};
|
|
1290
|
-
origXHROpen = XMLHttpRequest.prototype.open;
|
|
1291
|
-
XMLHttpRequest.prototype.open = function(method, url, async, username, password) {
|
|
1292
|
-
const startTime = Date.now();
|
|
1293
|
-
const urlStr = typeof url === "string" ? url : url.href;
|
|
1294
|
-
this.addEventListener("load", () => {
|
|
1295
|
-
if (this.status >= 400 && !isBlockedUrl(urlStr, blocked)) {
|
|
1296
|
-
push({
|
|
1297
|
-
method: method.toUpperCase(),
|
|
1298
|
-
url: truncateUrl(urlStr),
|
|
1299
|
-
status: this.status,
|
|
1300
|
-
duration: Date.now() - startTime,
|
|
1301
|
-
timestamp: startTime
|
|
1302
|
-
});
|
|
1303
|
-
}
|
|
1304
|
-
});
|
|
1305
|
-
return origXHROpen.apply(this, [
|
|
1306
|
-
method,
|
|
1307
|
-
url,
|
|
1308
|
-
async ?? true,
|
|
1309
|
-
username,
|
|
1310
|
-
password
|
|
1311
|
-
]);
|
|
1312
|
-
};
|
|
1313
|
-
},
|
|
1314
|
-
stop() {
|
|
1315
|
-
if (!active) return;
|
|
1316
|
-
active = false;
|
|
1317
|
-
if (origFetch) window.fetch = origFetch;
|
|
1318
|
-
if (origXHROpen) XMLHttpRequest.prototype.open = origXHROpen;
|
|
1319
|
-
},
|
|
1320
|
-
getEntries() {
|
|
1321
|
-
return [...entries];
|
|
1322
|
-
}
|
|
1323
|
-
};
|
|
1324
|
-
}
|
|
1325
|
-
|
|
1326
1244
|
// src/store.ts
|
|
1245
|
+
var import_core7 = require("@flint/core");
|
|
1327
1246
|
var import_react3 = require("react");
|
|
1328
|
-
var
|
|
1329
|
-
var listeners = /* @__PURE__ */ new Set();
|
|
1330
|
-
function emit() {
|
|
1331
|
-
listeners.forEach((fn) => fn());
|
|
1332
|
-
}
|
|
1333
|
-
function subscribeStore(fn) {
|
|
1334
|
-
listeners.add(fn);
|
|
1335
|
-
return () => listeners.delete(fn);
|
|
1336
|
-
}
|
|
1337
|
-
function getSnapshot() {
|
|
1338
|
-
return state;
|
|
1339
|
-
}
|
|
1247
|
+
var import_core8 = require("@flint/core");
|
|
1340
1248
|
function useFlintStore() {
|
|
1341
|
-
return (0, import_react3.useSyncExternalStore)(
|
|
1249
|
+
return (0, import_react3.useSyncExternalStore)(import_core7.subscribe, import_core7.getSnapshot);
|
|
1342
1250
|
}
|
|
1343
|
-
var flint = {
|
|
1344
|
-
setUser(user) {
|
|
1345
|
-
state = { ...state, user: user ?? void 0 };
|
|
1346
|
-
emit();
|
|
1347
|
-
},
|
|
1348
|
-
setSessionReplay(url) {
|
|
1349
|
-
state = { ...state, sessionReplay: url };
|
|
1350
|
-
emit();
|
|
1351
|
-
}
|
|
1352
|
-
};
|
|
1353
1251
|
|
|
1354
1252
|
// src/FlintWidget.tsx
|
|
1355
|
-
var import_rrweb = require("rrweb");
|
|
1356
1253
|
var import_jsx_runtime3 = require("react/jsx-runtime");
|
|
1357
1254
|
var REPLAY_WINDOW_MS = 6e4;
|
|
1358
1255
|
function FlintWidget(props) {
|
|
@@ -1371,7 +1268,19 @@ function WidgetContent({
|
|
|
1371
1268
|
buttonLabel,
|
|
1372
1269
|
theme = "dark",
|
|
1373
1270
|
zIndex = 9999,
|
|
1374
|
-
|
|
1271
|
+
statusPageUrl,
|
|
1272
|
+
datadogSite,
|
|
1273
|
+
enableReplay = true,
|
|
1274
|
+
enableScreenshot = true,
|
|
1275
|
+
enableConsole = true,
|
|
1276
|
+
enableNetwork = true,
|
|
1277
|
+
enableFrustration = false,
|
|
1278
|
+
autoReportFrustration = false,
|
|
1279
|
+
onBeforeSubmit,
|
|
1280
|
+
onSuccess,
|
|
1281
|
+
onError,
|
|
1282
|
+
onOpen,
|
|
1283
|
+
onClose
|
|
1375
1284
|
}) {
|
|
1376
1285
|
const globalState = useFlintStore();
|
|
1377
1286
|
const resolvedUser = user ?? globalState.user;
|
|
@@ -1385,9 +1294,9 @@ function WidgetContent({
|
|
|
1385
1294
|
const ddRum = window.DD_RUM;
|
|
1386
1295
|
const ctx = ddRum?.getInternalContext?.();
|
|
1387
1296
|
if (ctx?.session_id) {
|
|
1388
|
-
const now = Date.now();
|
|
1389
|
-
const fromTs = now -
|
|
1390
|
-
const toTs = now +
|
|
1297
|
+
const now = Math.floor(Date.now() / 1e3);
|
|
1298
|
+
const fromTs = now - 30;
|
|
1299
|
+
const toTs = now + 5;
|
|
1391
1300
|
return `https://${datadogSite}/rum/replay/sessions/${ctx.session_id}?from_ts=${fromTs}&to_ts=${toTs}&tab=replay&live=false`;
|
|
1392
1301
|
}
|
|
1393
1302
|
} catch {
|
|
@@ -1399,7 +1308,7 @@ function WidgetContent({
|
|
|
1399
1308
|
const [open, setOpen] = (0, import_react4.useState)(false);
|
|
1400
1309
|
const [hovered, setHovered] = (0, import_react4.useState)(false);
|
|
1401
1310
|
const pendingSelection = (0, import_react4.useRef)("");
|
|
1402
|
-
const colors = resolveTheme(theme);
|
|
1311
|
+
const colors = (0, import_core2.resolveTheme)(theme);
|
|
1403
1312
|
const [selectionTooltip, setSelectionTooltip] = (0, import_react4.useState)(null);
|
|
1404
1313
|
const tooltipRef = (0, import_react4.useRef)(null);
|
|
1405
1314
|
const triggerRef = (0, import_react4.useRef)(null);
|
|
@@ -1440,16 +1349,17 @@ function WidgetContent({
|
|
|
1440
1349
|
pendingSelection.current = text;
|
|
1441
1350
|
setSelectionTooltip(null);
|
|
1442
1351
|
setOpen(true);
|
|
1352
|
+
onOpen?.();
|
|
1443
1353
|
};
|
|
1444
1354
|
const consoleCollector = (0, import_react4.useRef)(null);
|
|
1445
1355
|
const networkCollector = (0, import_react4.useRef)(null);
|
|
1446
1356
|
const replayEvents = (0, import_react4.useRef)([]);
|
|
1447
1357
|
const stopReplay = (0, import_react4.useRef)(null);
|
|
1448
|
-
if (!consoleCollector.current) {
|
|
1449
|
-
consoleCollector.current = createConsoleCollector();
|
|
1358
|
+
if (enableConsole && !consoleCollector.current) {
|
|
1359
|
+
consoleCollector.current = (0, import_core3.createConsoleCollector)();
|
|
1450
1360
|
consoleCollector.current.start();
|
|
1451
1361
|
}
|
|
1452
|
-
if (!networkCollector.current) {
|
|
1362
|
+
if (enableNetwork && !networkCollector.current) {
|
|
1453
1363
|
const flintHost = (() => {
|
|
1454
1364
|
try {
|
|
1455
1365
|
return new URL(serverUrl).hostname;
|
|
@@ -1457,26 +1367,61 @@ function WidgetContent({
|
|
|
1457
1367
|
return "";
|
|
1458
1368
|
}
|
|
1459
1369
|
})();
|
|
1460
|
-
networkCollector.current = createNetworkCollector(flintHost ? [flintHost] : []);
|
|
1370
|
+
networkCollector.current = (0, import_core6.createNetworkCollector)(flintHost ? [flintHost] : []);
|
|
1461
1371
|
networkCollector.current.start();
|
|
1462
1372
|
}
|
|
1373
|
+
const frustrationCollector = (0, import_react4.useRef)(null);
|
|
1374
|
+
if (enableFrustration && !frustrationCollector.current) {
|
|
1375
|
+
frustrationCollector.current = (0, import_core5.createFrustrationCollector)();
|
|
1376
|
+
frustrationCollector.current.start();
|
|
1377
|
+
}
|
|
1463
1378
|
(0, import_react4.useEffect)(() => {
|
|
1464
|
-
|
|
1465
|
-
|
|
1466
|
-
|
|
1467
|
-
|
|
1468
|
-
|
|
1469
|
-
|
|
1470
|
-
|
|
1471
|
-
|
|
1472
|
-
|
|
1473
|
-
|
|
1379
|
+
let cancelled = false;
|
|
1380
|
+
if (enableReplay) {
|
|
1381
|
+
import("rrweb").then(({ record }) => {
|
|
1382
|
+
if (cancelled) return;
|
|
1383
|
+
const stopFn = record({
|
|
1384
|
+
emit(event) {
|
|
1385
|
+
replayEvents.current.push(event);
|
|
1386
|
+
const cutoff = Date.now() - REPLAY_WINDOW_MS;
|
|
1387
|
+
while (replayEvents.current.length > 0 && replayEvents.current[0].timestamp < cutoff) {
|
|
1388
|
+
replayEvents.current.shift();
|
|
1389
|
+
}
|
|
1390
|
+
}
|
|
1391
|
+
});
|
|
1392
|
+
stopReplay.current = stopFn ?? null;
|
|
1393
|
+
});
|
|
1394
|
+
}
|
|
1474
1395
|
return () => {
|
|
1396
|
+
cancelled = true;
|
|
1475
1397
|
consoleCollector.current?.stop();
|
|
1476
1398
|
networkCollector.current?.stop();
|
|
1399
|
+
frustrationCollector.current?.stop();
|
|
1477
1400
|
stopReplay.current?.();
|
|
1478
1401
|
};
|
|
1479
|
-
}, []);
|
|
1402
|
+
}, [enableReplay]);
|
|
1403
|
+
(0, import_react4.useEffect)(() => {
|
|
1404
|
+
if (!enableFrustration || !autoReportFrustration || !frustrationCollector.current) return;
|
|
1405
|
+
const unsubscribe = frustrationCollector.current.onFrustration(async (event) => {
|
|
1406
|
+
const user2 = resolvedUser;
|
|
1407
|
+
await (0, import_core.submitReport)(serverUrl, projectKey, {
|
|
1408
|
+
reporterId: user2?.id ?? "anonymous",
|
|
1409
|
+
reporterName: user2?.name ?? "Anonymous",
|
|
1410
|
+
reporterEmail: user2?.email,
|
|
1411
|
+
description: `[Auto-detected] ${event.type.replace(/_/g, " ")}: ${event.details}`,
|
|
1412
|
+
severity: event.type === "error_loop" ? "P1" : event.type === "rage_click" ? "P2" : "P3",
|
|
1413
|
+
url: event.url,
|
|
1414
|
+
meta: {
|
|
1415
|
+
environment: (0, import_core4.collectEnvironment)(),
|
|
1416
|
+
consoleLogs: consoleCollector.current?.getEntries() ?? [],
|
|
1417
|
+
networkErrors: networkCollector.current?.getEntries() ?? [],
|
|
1418
|
+
frustrationEvent: event
|
|
1419
|
+
}
|
|
1420
|
+
}).catch(() => {
|
|
1421
|
+
});
|
|
1422
|
+
});
|
|
1423
|
+
return unsubscribe;
|
|
1424
|
+
}, [enableFrustration, autoReportFrustration]);
|
|
1480
1425
|
const label = buttonLabel ?? t("buttonLabel");
|
|
1481
1426
|
return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_jsx_runtime3.Fragment, { children: [
|
|
1482
1427
|
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
|
|
@@ -1486,7 +1431,10 @@ function WidgetContent({
|
|
|
1486
1431
|
onMouseDown: () => {
|
|
1487
1432
|
pendingSelection.current = window.getSelection()?.toString().trim() ?? "";
|
|
1488
1433
|
},
|
|
1489
|
-
onClick: () =>
|
|
1434
|
+
onClick: () => {
|
|
1435
|
+
setOpen(true);
|
|
1436
|
+
onOpen?.();
|
|
1437
|
+
},
|
|
1490
1438
|
onMouseEnter: () => setHovered(true),
|
|
1491
1439
|
onMouseLeave: () => setHovered(false),
|
|
1492
1440
|
"aria-label": label,
|
|
@@ -1567,25 +1515,45 @@ function WidgetContent({
|
|
|
1567
1515
|
zIndex,
|
|
1568
1516
|
onClose: () => {
|
|
1569
1517
|
setOpen(false);
|
|
1518
|
+
onClose?.();
|
|
1570
1519
|
pendingSelection.current = "";
|
|
1571
1520
|
},
|
|
1572
|
-
getEnvironment: collectEnvironment,
|
|
1521
|
+
getEnvironment: import_core4.collectEnvironment,
|
|
1573
1522
|
getConsoleLogs: () => consoleCollector.current?.getEntries() ?? [],
|
|
1574
1523
|
getNetworkErrors: () => networkCollector.current?.getEntries() ?? [],
|
|
1575
1524
|
getReplayEvents: () => [...replayEvents.current],
|
|
1576
1525
|
getExternalReplayUrl,
|
|
1577
|
-
initialSelection: pendingSelection.current
|
|
1526
|
+
initialSelection: pendingSelection.current,
|
|
1527
|
+
enableScreenshot,
|
|
1528
|
+
statusPageUrl,
|
|
1529
|
+
onBeforeSubmit,
|
|
1530
|
+
onSuccess,
|
|
1531
|
+
onError
|
|
1578
1532
|
}
|
|
1579
1533
|
)
|
|
1580
1534
|
] });
|
|
1581
1535
|
}
|
|
1582
1536
|
function TextIcon() {
|
|
1583
|
-
return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
|
|
1584
|
-
|
|
1585
|
-
|
|
1586
|
-
|
|
1587
|
-
|
|
1588
|
-
|
|
1537
|
+
return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
|
|
1538
|
+
"svg",
|
|
1539
|
+
{
|
|
1540
|
+
width: "12",
|
|
1541
|
+
height: "12",
|
|
1542
|
+
viewBox: "0 0 24 24",
|
|
1543
|
+
fill: "none",
|
|
1544
|
+
stroke: "currentColor",
|
|
1545
|
+
strokeWidth: "2.2",
|
|
1546
|
+
strokeLinecap: "round",
|
|
1547
|
+
strokeLinejoin: "round",
|
|
1548
|
+
"aria-hidden": "true",
|
|
1549
|
+
children: [
|
|
1550
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("path", { d: "M17 10H3" }),
|
|
1551
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("path", { d: "M21 6H3" }),
|
|
1552
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("path", { d: "M21 14H3" }),
|
|
1553
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("path", { d: "M17 18H3" })
|
|
1554
|
+
]
|
|
1555
|
+
}
|
|
1556
|
+
);
|
|
1589
1557
|
}
|
|
1590
1558
|
function SparkIcon2() {
|
|
1591
1559
|
return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|