@diegotsi/flint-react 0.6.0 → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +604 -669
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +31 -8
- package/dist/index.d.ts +31 -8
- package/dist/index.js +589 -664
- package/dist/index.js.map +1 -1
- package/package.json +2 -1
package/dist/index.js
CHANGED
|
@@ -1,14 +1,13 @@
|
|
|
1
|
-
// src/FlintWidget.tsx
|
|
2
|
-
import { useState as useState3, useEffect as useEffect3, useRef as useRef3, useCallback as useCallback2 } from "react";
|
|
3
|
-
import { I18nextProvider, useTranslation as useTranslation2 } from "react-i18next";
|
|
4
|
-
|
|
5
1
|
// src/FlintModal.tsx
|
|
6
|
-
import {
|
|
2
|
+
import { useCallback, useEffect as useEffect2, useRef as useRef2, useState as useState2 } from "react";
|
|
7
3
|
import { useTranslation } from "react-i18next";
|
|
8
4
|
|
|
5
|
+
// src/api.ts
|
|
6
|
+
import { submitReplay, submitReport } from "@flint/core";
|
|
7
|
+
|
|
9
8
|
// src/ScreenAnnotator.tsx
|
|
10
|
-
import { useEffect, useRef, useState } from "react";
|
|
11
9
|
import { domToCanvas } from "modern-screenshot";
|
|
10
|
+
import { useEffect, useRef, useState } from "react";
|
|
12
11
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
13
12
|
function normalizeRect(startX, startY, endX, endY) {
|
|
14
13
|
return {
|
|
@@ -53,9 +52,7 @@ function ScreenAnnotator({ zIndex, onCapture, onCancel }) {
|
|
|
53
52
|
const dpr = window.devicePixelRatio ?? 1;
|
|
54
53
|
const vw = window.innerWidth;
|
|
55
54
|
const vh = window.innerHeight;
|
|
56
|
-
await new Promise(
|
|
57
|
-
(resolve) => requestAnimationFrame(() => requestAnimationFrame(() => resolve()))
|
|
58
|
-
);
|
|
55
|
+
await new Promise((resolve) => requestAnimationFrame(() => requestAnimationFrame(() => resolve())));
|
|
59
56
|
try {
|
|
60
57
|
const fullCanvas = await domToCanvas(document.documentElement, {
|
|
61
58
|
scale: dpr,
|
|
@@ -70,17 +67,7 @@ function ScreenAnnotator({ zIndex, onCapture, onCancel }) {
|
|
|
70
67
|
canvas.width = vw * dpr;
|
|
71
68
|
canvas.height = vh * dpr;
|
|
72
69
|
const ctx = canvas.getContext("2d");
|
|
73
|
-
ctx.drawImage(
|
|
74
|
-
fullCanvas,
|
|
75
|
-
0,
|
|
76
|
-
0,
|
|
77
|
-
vw * dpr,
|
|
78
|
-
vh * dpr,
|
|
79
|
-
0,
|
|
80
|
-
0,
|
|
81
|
-
vw * dpr,
|
|
82
|
-
vh * dpr
|
|
83
|
-
);
|
|
70
|
+
ctx.drawImage(fullCanvas, 0, 0, vw * dpr, vh * dpr, 0, 0, vw * dpr, vh * dpr);
|
|
84
71
|
ctx.fillStyle = "rgba(255,200,0,0.25)";
|
|
85
72
|
ctx.fillRect(finalRect.x * dpr, finalRect.y * dpr, finalRect.w * dpr, finalRect.h * dpr);
|
|
86
73
|
ctx.strokeStyle = "#f97316";
|
|
@@ -118,123 +105,50 @@ function ScreenAnnotator({ zIndex, onCapture, onCancel }) {
|
|
|
118
105
|
pointerEvents: isCapturing ? "none" : "auto"
|
|
119
106
|
},
|
|
120
107
|
children: [
|
|
121
|
-
!isCapturing && /* @__PURE__ */ jsx(
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
108
|
+
!isCapturing && /* @__PURE__ */ jsx(
|
|
109
|
+
"div",
|
|
110
|
+
{
|
|
111
|
+
style: {
|
|
112
|
+
position: "absolute",
|
|
113
|
+
top: 16,
|
|
114
|
+
left: "50%",
|
|
115
|
+
transform: "translateX(-50%)",
|
|
116
|
+
background: "rgba(0,0,0,0.75)",
|
|
117
|
+
color: "#fff",
|
|
118
|
+
padding: "8px 18px",
|
|
119
|
+
borderRadius: 8,
|
|
120
|
+
fontSize: 14,
|
|
121
|
+
fontFamily: '-apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif',
|
|
122
|
+
pointerEvents: "none",
|
|
123
|
+
whiteSpace: "nowrap",
|
|
124
|
+
backdropFilter: "blur(4px)"
|
|
125
|
+
},
|
|
126
|
+
children: "Drag to highlight the problem area \xA0\xB7\xA0 Esc to cancel"
|
|
127
|
+
}
|
|
128
|
+
),
|
|
129
|
+
rect && phase === "selecting" && /* @__PURE__ */ jsx(
|
|
130
|
+
"div",
|
|
131
|
+
{
|
|
132
|
+
style: {
|
|
133
|
+
position: "absolute",
|
|
134
|
+
left: rect.x,
|
|
135
|
+
top: rect.y,
|
|
136
|
+
width: rect.w,
|
|
137
|
+
height: rect.h,
|
|
138
|
+
background: "rgba(255,200,0,0.2)",
|
|
139
|
+
border: "2px dashed #f97316",
|
|
140
|
+
boxSizing: "border-box",
|
|
141
|
+
pointerEvents: "none"
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
)
|
|
147
145
|
]
|
|
148
146
|
}
|
|
149
147
|
);
|
|
150
148
|
}
|
|
151
149
|
|
|
152
|
-
// src/api.ts
|
|
153
|
-
import { gzipSync } from "fflate";
|
|
154
|
-
async function submitReport(serverUrl, projectKey, payload, screenshot) {
|
|
155
|
-
const url = `${serverUrl.replace(/\/$/, "")}/api/v1/bug-reports`;
|
|
156
|
-
let body;
|
|
157
|
-
let headers = {
|
|
158
|
-
"x-project-key": projectKey
|
|
159
|
-
};
|
|
160
|
-
if (screenshot) {
|
|
161
|
-
const form = new FormData();
|
|
162
|
-
form.append("reporterId", payload.reporterId);
|
|
163
|
-
form.append("reporterName", payload.reporterName);
|
|
164
|
-
form.append("description", payload.description);
|
|
165
|
-
if (payload.expectedBehavior) form.append("expectedBehavior", payload.expectedBehavior);
|
|
166
|
-
if (payload.stepsToReproduce) form.append("stepsToReproduce", JSON.stringify(payload.stepsToReproduce));
|
|
167
|
-
if (payload.externalReplayUrl) form.append("externalReplayUrl", payload.externalReplayUrl);
|
|
168
|
-
if (payload.additionalContext) form.append("additionalContext", payload.additionalContext);
|
|
169
|
-
form.append("severity", payload.severity);
|
|
170
|
-
if (payload.url) form.append("url", payload.url);
|
|
171
|
-
if (payload.meta) form.append("meta", JSON.stringify(payload.meta));
|
|
172
|
-
form.append("screenshot", screenshot);
|
|
173
|
-
body = form;
|
|
174
|
-
} else {
|
|
175
|
-
body = JSON.stringify(payload);
|
|
176
|
-
headers["Content-Type"] = "application/json";
|
|
177
|
-
}
|
|
178
|
-
const res = await fetch(url, { method: "POST", headers, body });
|
|
179
|
-
if (!res.ok) {
|
|
180
|
-
const err = await res.json().catch(() => ({ error: "Unknown error" }));
|
|
181
|
-
throw new Error(err.error ?? `HTTP ${res.status}`);
|
|
182
|
-
}
|
|
183
|
-
return res.json();
|
|
184
|
-
}
|
|
185
|
-
async function submitReplay(serverUrl, projectKey, reportId, events) {
|
|
186
|
-
const json = JSON.stringify(events);
|
|
187
|
-
const encoded = new TextEncoder().encode(json);
|
|
188
|
-
const compressed = gzipSync(encoded);
|
|
189
|
-
const url = `${serverUrl.replace(/\/$/, "")}/api/v1/bug-reports/${reportId}/replay`;
|
|
190
|
-
await fetch(url, {
|
|
191
|
-
method: "POST",
|
|
192
|
-
headers: {
|
|
193
|
-
"x-project-key": projectKey,
|
|
194
|
-
"Content-Type": "application/octet-stream"
|
|
195
|
-
},
|
|
196
|
-
body: compressed.buffer
|
|
197
|
-
});
|
|
198
|
-
}
|
|
199
|
-
|
|
200
150
|
// src/theme.ts
|
|
201
|
-
|
|
202
|
-
background: "rgba(255,255,255,0.90)",
|
|
203
|
-
backgroundSecondary: "rgba(249,250,251,0.75)",
|
|
204
|
-
accent: "#2563eb",
|
|
205
|
-
accentHover: "#1d4ed8",
|
|
206
|
-
text: "#111827",
|
|
207
|
-
textMuted: "#6b7280",
|
|
208
|
-
border: "rgba(255,255,255,0.9)",
|
|
209
|
-
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)",
|
|
210
|
-
buttonText: "#ffffff",
|
|
211
|
-
backdropFilter: "blur(32px) saturate(1.8)"
|
|
212
|
-
};
|
|
213
|
-
var dark = {
|
|
214
|
-
background: "rgba(15,20,35,0.88)",
|
|
215
|
-
backgroundSecondary: "rgba(5,8,18,0.65)",
|
|
216
|
-
accent: "#f97316",
|
|
217
|
-
accentHover: "#ea6c0a",
|
|
218
|
-
text: "#dde3ef",
|
|
219
|
-
textMuted: "#6b7a93",
|
|
220
|
-
border: "rgba(255,255,255,0.08)",
|
|
221
|
-
shadow: "0 24px 60px rgba(0,0,0,0.6), 0 0 0 1px rgba(255,255,255,0.04)",
|
|
222
|
-
buttonText: "#ffffff",
|
|
223
|
-
backdropFilter: "blur(32px) saturate(1.6)"
|
|
224
|
-
};
|
|
225
|
-
function resolveTheme(theme) {
|
|
226
|
-
if (theme === "dark") return dark;
|
|
227
|
-
if (theme === "light") return light;
|
|
228
|
-
const override = theme;
|
|
229
|
-
return {
|
|
230
|
-
...light,
|
|
231
|
-
background: override.background ?? light.background,
|
|
232
|
-
accent: override.accent ?? light.accent,
|
|
233
|
-
accentHover: override.accent ?? light.accentHover,
|
|
234
|
-
text: override.text ?? light.text,
|
|
235
|
-
border: override.border ?? light.border
|
|
236
|
-
};
|
|
237
|
-
}
|
|
151
|
+
import { resolveTheme } from "@flint/core";
|
|
238
152
|
|
|
239
153
|
// src/FlintModal.tsx
|
|
240
154
|
import { Fragment, jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
@@ -294,7 +208,12 @@ function FlintModal({
|
|
|
294
208
|
getNetworkErrors,
|
|
295
209
|
getReplayEvents,
|
|
296
210
|
getExternalReplayUrl,
|
|
297
|
-
initialSelection = ""
|
|
211
|
+
initialSelection = "",
|
|
212
|
+
enableScreenshot = true,
|
|
213
|
+
statusPageUrl,
|
|
214
|
+
onBeforeSubmit,
|
|
215
|
+
onSuccess,
|
|
216
|
+
onError
|
|
298
217
|
}) {
|
|
299
218
|
const { t } = useTranslation();
|
|
300
219
|
const colors = resolveTheme(theme);
|
|
@@ -354,33 +273,40 @@ function FlintModal({
|
|
|
354
273
|
lang: textLang
|
|
355
274
|
};
|
|
356
275
|
}
|
|
276
|
+
const payload = {
|
|
277
|
+
reporterId: user?.id ?? "anonymous",
|
|
278
|
+
reporterName: user?.name ?? "Anonymous",
|
|
279
|
+
reporterEmail: user?.email,
|
|
280
|
+
description: isText ? `[Text issue] "${textOriginal.trim()}" \u2192 "${textSuggested.trim()}"` : description.trim(),
|
|
281
|
+
expectedBehavior: !isText ? expectedBehavior.trim() || void 0 : void 0,
|
|
282
|
+
externalReplayUrl: getExternalReplayUrl() || void 0,
|
|
283
|
+
severity: isText ? "P3" : severity,
|
|
284
|
+
url: window.location.href,
|
|
285
|
+
meta: collectedMeta,
|
|
286
|
+
label: isText ? "TEXT" : void 0
|
|
287
|
+
};
|
|
288
|
+
if (onBeforeSubmit) {
|
|
289
|
+
const proceed = await onBeforeSubmit(payload);
|
|
290
|
+
if (!proceed) {
|
|
291
|
+
setStatus("idle");
|
|
292
|
+
return;
|
|
293
|
+
}
|
|
294
|
+
}
|
|
357
295
|
try {
|
|
358
|
-
const res = await submitReport(
|
|
359
|
-
serverUrl,
|
|
360
|
-
projectKey,
|
|
361
|
-
{
|
|
362
|
-
reporterId: user?.id ?? "anonymous",
|
|
363
|
-
reporterName: user?.name ?? "Anonymous",
|
|
364
|
-
description: isText ? `[Text issue] "${textOriginal.trim()}" \u2192 "${textSuggested.trim()}"` : description.trim(),
|
|
365
|
-
expectedBehavior: !isText ? expectedBehavior.trim() || void 0 : void 0,
|
|
366
|
-
externalReplayUrl: getExternalReplayUrl() || void 0,
|
|
367
|
-
severity: isText ? "P3" : severity,
|
|
368
|
-
url: window.location.href,
|
|
369
|
-
meta: collectedMeta,
|
|
370
|
-
label: isText ? "TEXT" : void 0
|
|
371
|
-
},
|
|
372
|
-
!isText ? screenshot ?? void 0 : void 0
|
|
373
|
-
);
|
|
296
|
+
const res = await submitReport(serverUrl, projectKey, payload, !isText ? screenshot ?? void 0 : void 0);
|
|
374
297
|
setResult(res);
|
|
375
298
|
setStatus("success");
|
|
299
|
+
onSuccess?.(res);
|
|
376
300
|
const events = getReplayEvents();
|
|
377
301
|
if (events.length > 0) {
|
|
378
302
|
submitReplay(serverUrl, projectKey, res.id, events).catch(() => {
|
|
379
303
|
});
|
|
380
304
|
}
|
|
381
305
|
} catch (err) {
|
|
382
|
-
|
|
306
|
+
const error = err instanceof Error ? err : new Error(t("errorLabel"));
|
|
307
|
+
setErrorMsg(error.message);
|
|
383
308
|
setStatus("error");
|
|
309
|
+
onError?.(error);
|
|
384
310
|
}
|
|
385
311
|
};
|
|
386
312
|
const inputBorder = isDark ? "rgba(255,255,255,0.1)" : "rgba(0,0,0,0.1)";
|
|
@@ -430,157 +356,249 @@ function FlintModal({
|
|
|
430
356
|
const isSuccess = status === "success";
|
|
431
357
|
const ringBorder = isSuccess ? "3px solid #22c55e" : `3px solid ${isDark ? "rgba(255,255,255,0.08)" : "rgba(0,0,0,0.08)"}`;
|
|
432
358
|
const ringTopColor = isSuccess ? "#22c55e" : colors.accent;
|
|
433
|
-
return /* @__PURE__ */ jsx2("div", { style: overlayStyle, children: /* @__PURE__ */ jsxs2(
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
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
|
-
|
|
359
|
+
return /* @__PURE__ */ jsx2("div", { style: overlayStyle, children: /* @__PURE__ */ jsxs2(
|
|
360
|
+
"div",
|
|
361
|
+
{
|
|
362
|
+
style: modalStyle,
|
|
363
|
+
role: "dialog",
|
|
364
|
+
"aria-modal": "true",
|
|
365
|
+
"aria-label": isSuccess ? t("successTitle") : t("sending"),
|
|
366
|
+
children: [
|
|
367
|
+
/* @__PURE__ */ jsx2(ModalHeader, { colors, inputBorder, showClose: false, onClose }),
|
|
368
|
+
/* @__PURE__ */ jsxs2(
|
|
369
|
+
"div",
|
|
370
|
+
{
|
|
371
|
+
style: {
|
|
372
|
+
padding: "40px 32px 48px",
|
|
373
|
+
textAlign: "center",
|
|
374
|
+
display: "flex",
|
|
375
|
+
flexDirection: "column",
|
|
376
|
+
alignItems: "center"
|
|
377
|
+
},
|
|
378
|
+
children: [
|
|
379
|
+
/* @__PURE__ */ jsxs2("div", { style: { position: "relative", width: 80, height: 80, marginBottom: 28 }, children: [
|
|
380
|
+
/* @__PURE__ */ jsx2(
|
|
381
|
+
"div",
|
|
382
|
+
{
|
|
383
|
+
style: {
|
|
384
|
+
position: "absolute",
|
|
385
|
+
inset: -10,
|
|
386
|
+
borderRadius: "50%",
|
|
387
|
+
border: `1.5px solid ${colors.accent}`,
|
|
388
|
+
animation: "_flint_ripple 1.8s ease-out infinite",
|
|
389
|
+
opacity: isSuccess ? 0 : 1,
|
|
390
|
+
transition: "opacity 0.3s ease"
|
|
391
|
+
}
|
|
392
|
+
}
|
|
393
|
+
),
|
|
394
|
+
/* @__PURE__ */ jsx2(
|
|
395
|
+
"div",
|
|
396
|
+
{
|
|
397
|
+
style: {
|
|
398
|
+
position: "absolute",
|
|
399
|
+
inset: -10,
|
|
400
|
+
borderRadius: "50%",
|
|
401
|
+
border: `1.5px solid ${colors.accent}`,
|
|
402
|
+
animation: "_flint_ripple 1.8s ease-out infinite 0.6s",
|
|
403
|
+
opacity: isSuccess ? 0 : 1,
|
|
404
|
+
transition: "opacity 0.3s ease"
|
|
405
|
+
}
|
|
406
|
+
}
|
|
407
|
+
),
|
|
408
|
+
/* @__PURE__ */ jsx2(
|
|
409
|
+
"div",
|
|
410
|
+
{
|
|
411
|
+
style: {
|
|
412
|
+
position: "absolute",
|
|
413
|
+
inset: 0,
|
|
414
|
+
borderRadius: "50%",
|
|
415
|
+
border: ringBorder,
|
|
416
|
+
borderTopColor: ringTopColor,
|
|
417
|
+
animation: isSuccess ? "none" : "_flint_spin 0.85s linear infinite",
|
|
418
|
+
transition: "border-color 0.45s ease, border-top-color 0.45s ease"
|
|
419
|
+
}
|
|
420
|
+
}
|
|
421
|
+
),
|
|
422
|
+
/* @__PURE__ */ jsxs2("div", { style: { position: "absolute", inset: 14, borderRadius: "50%" }, children: [
|
|
423
|
+
/* @__PURE__ */ jsx2(
|
|
424
|
+
"div",
|
|
425
|
+
{
|
|
426
|
+
style: {
|
|
427
|
+
position: "absolute",
|
|
428
|
+
inset: 0,
|
|
429
|
+
borderRadius: "50%",
|
|
430
|
+
background: `linear-gradient(135deg, ${colors.accent}30, ${colors.accentHover}50)`,
|
|
431
|
+
display: "flex",
|
|
432
|
+
alignItems: "center",
|
|
433
|
+
justifyContent: "center",
|
|
434
|
+
animation: isSuccess ? "none" : "_flint_pulse 2s ease-in-out infinite",
|
|
435
|
+
opacity: isSuccess ? 0 : 1,
|
|
436
|
+
transition: "opacity 0.3s ease"
|
|
437
|
+
},
|
|
438
|
+
children: /* @__PURE__ */ jsx2(SparkIcon, { color: colors.accent, size: 20 })
|
|
439
|
+
}
|
|
440
|
+
),
|
|
441
|
+
/* @__PURE__ */ jsx2(
|
|
442
|
+
"div",
|
|
443
|
+
{
|
|
444
|
+
style: {
|
|
445
|
+
position: "absolute",
|
|
446
|
+
inset: 0,
|
|
447
|
+
borderRadius: "50%",
|
|
448
|
+
background: "rgba(34,197,94,0.15)",
|
|
449
|
+
display: "flex",
|
|
450
|
+
alignItems: "center",
|
|
451
|
+
justifyContent: "center",
|
|
452
|
+
opacity: isSuccess ? 1 : 0,
|
|
453
|
+
transform: isSuccess ? "scale(1)" : "scale(0.65)",
|
|
454
|
+
transition: "opacity 0.35s ease 0.2s, transform 0.4s cubic-bezier(0.16,1,0.3,1) 0.2s"
|
|
455
|
+
},
|
|
456
|
+
children: /* @__PURE__ */ jsx2(CheckIcon, { size: 20 })
|
|
457
|
+
}
|
|
458
|
+
)
|
|
459
|
+
] })
|
|
460
|
+
] }),
|
|
461
|
+
/* @__PURE__ */ jsxs2("div", { style: { position: "relative", height: 26, width: "100%", marginBottom: 10 }, children: [
|
|
462
|
+
/* @__PURE__ */ jsx2(
|
|
463
|
+
"div",
|
|
464
|
+
{
|
|
465
|
+
style: {
|
|
466
|
+
position: "absolute",
|
|
467
|
+
inset: 0,
|
|
468
|
+
display: "flex",
|
|
469
|
+
alignItems: "center",
|
|
470
|
+
justifyContent: "center",
|
|
471
|
+
fontSize: 19,
|
|
472
|
+
fontWeight: 700,
|
|
473
|
+
color: colors.text,
|
|
474
|
+
letterSpacing: "-0.02em",
|
|
475
|
+
opacity: isSuccess ? 0 : 1,
|
|
476
|
+
transition: "opacity 0.25s ease",
|
|
477
|
+
pointerEvents: "none"
|
|
478
|
+
},
|
|
479
|
+
children: t("sending")
|
|
480
|
+
}
|
|
481
|
+
),
|
|
482
|
+
/* @__PURE__ */ jsx2(
|
|
483
|
+
"div",
|
|
484
|
+
{
|
|
485
|
+
style: {
|
|
486
|
+
position: "absolute",
|
|
487
|
+
inset: 0,
|
|
488
|
+
display: "flex",
|
|
489
|
+
alignItems: "center",
|
|
490
|
+
justifyContent: "center",
|
|
491
|
+
fontSize: 19,
|
|
492
|
+
fontWeight: 700,
|
|
493
|
+
color: colors.text,
|
|
494
|
+
letterSpacing: "-0.02em",
|
|
495
|
+
opacity: isSuccess ? 1 : 0,
|
|
496
|
+
transform: isSuccess ? "translateY(0)" : "translateY(6px)",
|
|
497
|
+
transition: "opacity 0.35s ease 0.25s, transform 0.35s ease 0.25s",
|
|
498
|
+
pointerEvents: isSuccess ? "auto" : "none"
|
|
499
|
+
},
|
|
500
|
+
children: t("successTitle")
|
|
501
|
+
}
|
|
502
|
+
)
|
|
503
|
+
] }),
|
|
504
|
+
/* @__PURE__ */ jsxs2("div", { style: { position: "relative", minHeight: 76, width: "100%" }, children: [
|
|
505
|
+
/* @__PURE__ */ jsxs2(
|
|
506
|
+
"div",
|
|
507
|
+
{
|
|
508
|
+
style: {
|
|
509
|
+
position: "absolute",
|
|
510
|
+
inset: 0,
|
|
511
|
+
display: "flex",
|
|
512
|
+
alignItems: "center",
|
|
513
|
+
justifyContent: "center",
|
|
514
|
+
gap: 6,
|
|
515
|
+
color: colors.textMuted,
|
|
516
|
+
fontSize: 15,
|
|
517
|
+
opacity: isSuccess ? 0 : 1,
|
|
518
|
+
transition: "opacity 0.2s ease",
|
|
519
|
+
pointerEvents: "none"
|
|
520
|
+
},
|
|
521
|
+
children: [
|
|
522
|
+
/* @__PURE__ */ jsx2("span", { children: t("capturingContext") }),
|
|
523
|
+
/* @__PURE__ */ jsx2(SendingDots, { color: colors.accent })
|
|
524
|
+
]
|
|
525
|
+
}
|
|
526
|
+
),
|
|
527
|
+
/* @__PURE__ */ jsxs2(
|
|
528
|
+
"div",
|
|
529
|
+
{
|
|
530
|
+
style: {
|
|
531
|
+
position: "absolute",
|
|
532
|
+
inset: 0,
|
|
533
|
+
display: "flex",
|
|
534
|
+
flexDirection: "column",
|
|
535
|
+
alignItems: "center",
|
|
536
|
+
gap: 10,
|
|
537
|
+
opacity: isSuccess ? 1 : 0,
|
|
538
|
+
transform: isSuccess ? "translateY(0)" : "translateY(8px)",
|
|
539
|
+
transition: "opacity 0.35s ease 0.35s, transform 0.35s ease 0.35s",
|
|
540
|
+
pointerEvents: isSuccess ? "auto" : "none"
|
|
541
|
+
},
|
|
542
|
+
children: [
|
|
543
|
+
/* @__PURE__ */ jsx2("p", { style: { fontSize: 15, color: colors.textMuted, margin: 0 }, children: result ? `ID: ${result.id}` : "" }),
|
|
544
|
+
statusPageUrl && user?.id && /* @__PURE__ */ jsxs2(
|
|
545
|
+
"a",
|
|
546
|
+
{
|
|
547
|
+
href: `${statusPageUrl}/status?project_key=${encodeURIComponent(projectKey)}&reporter_id=${encodeURIComponent(user.id)}&server_url=${encodeURIComponent(serverUrl)}`,
|
|
548
|
+
target: "_blank",
|
|
549
|
+
rel: "noreferrer",
|
|
550
|
+
style: {
|
|
551
|
+
fontSize: 14,
|
|
552
|
+
color: colors.accent,
|
|
553
|
+
textDecoration: "none",
|
|
554
|
+
fontWeight: 600,
|
|
555
|
+
animation: "_flint_success_up 0.35s ease 0.4s both"
|
|
556
|
+
},
|
|
557
|
+
children: [
|
|
558
|
+
"\u{1F4CB}",
|
|
559
|
+
" Track your bugs ",
|
|
560
|
+
"\u2192"
|
|
561
|
+
]
|
|
562
|
+
}
|
|
563
|
+
),
|
|
564
|
+
/* @__PURE__ */ jsx2(
|
|
565
|
+
"button",
|
|
566
|
+
{
|
|
567
|
+
onClick: onClose,
|
|
568
|
+
style: {
|
|
569
|
+
width: "100%",
|
|
570
|
+
padding: "13px 20px",
|
|
571
|
+
borderRadius: 12,
|
|
572
|
+
border: "none",
|
|
573
|
+
background: `linear-gradient(135deg, ${colors.accent}, ${colors.accentHover})`,
|
|
574
|
+
color: colors.buttonText,
|
|
575
|
+
fontSize: 17,
|
|
576
|
+
fontWeight: 700,
|
|
577
|
+
cursor: "pointer",
|
|
578
|
+
letterSpacing: "-0.01em",
|
|
579
|
+
boxShadow: accentGlow,
|
|
580
|
+
fontFamily: "inherit",
|
|
581
|
+
display: "flex",
|
|
582
|
+
alignItems: "center",
|
|
583
|
+
justifyContent: "center",
|
|
584
|
+
gap: 8
|
|
585
|
+
},
|
|
586
|
+
children: t("close")
|
|
587
|
+
}
|
|
588
|
+
)
|
|
589
|
+
]
|
|
590
|
+
}
|
|
591
|
+
)
|
|
592
|
+
] })
|
|
593
|
+
]
|
|
594
|
+
}
|
|
595
|
+
)
|
|
596
|
+
]
|
|
597
|
+
}
|
|
598
|
+
) });
|
|
581
599
|
}
|
|
582
600
|
return /* @__PURE__ */ jsxs2(Fragment, { children: [
|
|
583
|
-
annotating && /* @__PURE__ */ jsx2(
|
|
601
|
+
enableScreenshot && annotating && /* @__PURE__ */ jsx2(
|
|
584
602
|
ScreenAnnotator,
|
|
585
603
|
{
|
|
586
604
|
zIndex: zIndex + 1,
|
|
@@ -604,37 +622,43 @@ function FlintModal({
|
|
|
604
622
|
}
|
|
605
623
|
),
|
|
606
624
|
/* @__PURE__ */ jsxs2("form", { onSubmit: handleSubmit, style: { padding: "20px 24px 24px" }, children: [
|
|
607
|
-
/* @__PURE__ */ jsx2(
|
|
608
|
-
|
|
609
|
-
gap: 4,
|
|
610
|
-
marginBottom: 20,
|
|
611
|
-
background: colors.backgroundSecondary,
|
|
612
|
-
borderRadius: 12,
|
|
613
|
-
padding: 4,
|
|
614
|
-
border: `1px solid ${inputBorder}`
|
|
615
|
-
}, children: ["bug", "text"].map((m) => /* @__PURE__ */ jsx2(
|
|
616
|
-
"button",
|
|
625
|
+
/* @__PURE__ */ jsx2(
|
|
626
|
+
"div",
|
|
617
627
|
{
|
|
618
|
-
type: "button",
|
|
619
|
-
onClick: () => setMode(m),
|
|
620
628
|
style: {
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
fontFamily: "inherit",
|
|
629
|
-
transition: "background 0.15s, color 0.15s",
|
|
630
|
-
background: mode === m ? `linear-gradient(135deg, ${colors.accent}, ${colors.accentHover})` : "transparent",
|
|
631
|
-
color: mode === m ? colors.buttonText : colors.textMuted,
|
|
632
|
-
boxShadow: mode === m ? `0 2px 8px ${colors.accent}30` : "none"
|
|
629
|
+
display: "flex",
|
|
630
|
+
gap: 4,
|
|
631
|
+
marginBottom: 20,
|
|
632
|
+
background: colors.backgroundSecondary,
|
|
633
|
+
borderRadius: 12,
|
|
634
|
+
padding: 4,
|
|
635
|
+
border: `1px solid ${inputBorder}`
|
|
633
636
|
},
|
|
634
|
-
children:
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
637
|
+
children: ["bug", "text"].map((m) => /* @__PURE__ */ jsx2(
|
|
638
|
+
"button",
|
|
639
|
+
{
|
|
640
|
+
type: "button",
|
|
641
|
+
onClick: () => setMode(m),
|
|
642
|
+
style: {
|
|
643
|
+
flex: 1,
|
|
644
|
+
padding: "8px 10px",
|
|
645
|
+
borderRadius: 9,
|
|
646
|
+
border: "none",
|
|
647
|
+
cursor: "pointer",
|
|
648
|
+
fontSize: 13,
|
|
649
|
+
fontWeight: mode === m ? 700 : 500,
|
|
650
|
+
fontFamily: "inherit",
|
|
651
|
+
transition: "background 0.15s, color 0.15s",
|
|
652
|
+
background: mode === m ? `linear-gradient(135deg, ${colors.accent}, ${colors.accentHover})` : "transparent",
|
|
653
|
+
color: mode === m ? colors.buttonText : colors.textMuted,
|
|
654
|
+
boxShadow: mode === m ? `0 2px 8px ${colors.accent}30` : "none"
|
|
655
|
+
},
|
|
656
|
+
children: m === "bug" ? "\u{1F41B} Bug" : "\u{1F524} Text / Translation"
|
|
657
|
+
},
|
|
658
|
+
m
|
|
659
|
+
))
|
|
660
|
+
}
|
|
661
|
+
),
|
|
638
662
|
mode === "text" && /* @__PURE__ */ jsxs2(Fragment, { children: [
|
|
639
663
|
/* @__PURE__ */ jsxs2("div", { style: { marginBottom: 14 }, children: [
|
|
640
664
|
/* @__PURE__ */ jsx2(FieldLabel, { colors, htmlFor: "flint-text-original", children: "Original text" }),
|
|
@@ -731,7 +755,7 @@ function FlintModal({
|
|
|
731
755
|
}
|
|
732
756
|
)
|
|
733
757
|
] }),
|
|
734
|
-
/* @__PURE__ */ jsxs2("div", { style: { marginBottom: 20, display: mode === "text" ? "none" : void 0 }, children: [
|
|
758
|
+
/* @__PURE__ */ jsxs2("div", { style: { marginBottom: 20, display: mode === "text" || !enableScreenshot ? "none" : void 0 }, children: [
|
|
735
759
|
/* @__PURE__ */ jsx2(FieldLabel, { colors, children: t("screenshotLabel") }),
|
|
736
760
|
screenshot ? /* @__PURE__ */ jsxs2("div", { style: { display: "flex", alignItems: "center", gap: 10 }, children: [
|
|
737
761
|
/* @__PURE__ */ jsx2(
|
|
@@ -742,7 +766,20 @@ function FlintModal({
|
|
|
742
766
|
style: { height: 60, borderRadius: 8, objectFit: "cover", border: `1px solid ${inputBorder}` }
|
|
743
767
|
}
|
|
744
768
|
),
|
|
745
|
-
/* @__PURE__ */ jsx2(
|
|
769
|
+
/* @__PURE__ */ jsx2(
|
|
770
|
+
"span",
|
|
771
|
+
{
|
|
772
|
+
style: {
|
|
773
|
+
fontSize: 13,
|
|
774
|
+
color: colors.textMuted,
|
|
775
|
+
flex: 1,
|
|
776
|
+
overflow: "hidden",
|
|
777
|
+
textOverflow: "ellipsis",
|
|
778
|
+
whiteSpace: "nowrap"
|
|
779
|
+
},
|
|
780
|
+
children: screenshot.name
|
|
781
|
+
}
|
|
782
|
+
),
|
|
746
783
|
/* @__PURE__ */ jsx2(
|
|
747
784
|
"button",
|
|
748
785
|
{
|
|
@@ -829,31 +866,43 @@ function FlintModal({
|
|
|
829
866
|
}
|
|
830
867
|
)
|
|
831
868
|
] }),
|
|
832
|
-
/* @__PURE__ */ jsxs2(
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
869
|
+
/* @__PURE__ */ jsxs2(
|
|
870
|
+
"div",
|
|
871
|
+
{
|
|
872
|
+
style: {
|
|
873
|
+
display: "flex",
|
|
874
|
+
alignItems: "center",
|
|
875
|
+
gap: 8,
|
|
876
|
+
padding: "9px 12px",
|
|
877
|
+
borderRadius: 10,
|
|
878
|
+
background: isDark ? "rgba(255,255,255,0.04)" : "rgba(0,77,240,0.04)",
|
|
879
|
+
border: `1px solid ${isDark ? "rgba(255,255,255,0.08)" : "rgba(0,77,240,0.1)"}`,
|
|
880
|
+
marginBottom: 16
|
|
881
|
+
},
|
|
882
|
+
children: [
|
|
883
|
+
/* @__PURE__ */ jsx2("span", { style: { fontSize: 16 }, children: "\u{1F3A5}" }),
|
|
884
|
+
/* @__PURE__ */ jsx2("span", { style: { fontSize: 14, color: colors.textMuted, lineHeight: 1.4 }, children: t("replayInfo") })
|
|
885
|
+
]
|
|
886
|
+
}
|
|
887
|
+
),
|
|
888
|
+
status === "error" && /* @__PURE__ */ jsxs2(
|
|
889
|
+
"div",
|
|
890
|
+
{
|
|
891
|
+
style: {
|
|
892
|
+
padding: "10px 13px",
|
|
893
|
+
borderRadius: 10,
|
|
894
|
+
background: "rgba(239,68,68,0.08)",
|
|
895
|
+
border: "1px solid rgba(239,68,68,0.2)",
|
|
896
|
+
color: "#f87171",
|
|
897
|
+
fontSize: 14,
|
|
898
|
+
marginBottom: 16
|
|
899
|
+
},
|
|
900
|
+
children: [
|
|
901
|
+
"\u26A0\uFE0F ",
|
|
902
|
+
errorMsg || t("errorLabel")
|
|
903
|
+
]
|
|
904
|
+
}
|
|
905
|
+
),
|
|
857
906
|
/* @__PURE__ */ jsxs2(
|
|
858
907
|
"button",
|
|
859
908
|
{
|
|
@@ -914,49 +963,68 @@ function ModalHeader({
|
|
|
914
963
|
titleId,
|
|
915
964
|
title
|
|
916
965
|
}) {
|
|
917
|
-
return /* @__PURE__ */ jsxs2(
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
966
|
+
return /* @__PURE__ */ jsxs2(
|
|
967
|
+
"div",
|
|
968
|
+
{
|
|
969
|
+
style: {
|
|
970
|
+
display: "flex",
|
|
971
|
+
alignItems: "center",
|
|
972
|
+
gap: 10,
|
|
973
|
+
padding: "16px 20px 14px",
|
|
974
|
+
borderBottom: `1px solid ${inputBorder}`
|
|
975
|
+
},
|
|
976
|
+
children: [
|
|
977
|
+
/* @__PURE__ */ jsx2(
|
|
978
|
+
"div",
|
|
979
|
+
{
|
|
980
|
+
style: {
|
|
981
|
+
width: 28,
|
|
982
|
+
height: 28,
|
|
983
|
+
borderRadius: 8,
|
|
984
|
+
background: `linear-gradient(135deg, ${colors.accent}20, ${colors.accentHover}35)`,
|
|
985
|
+
border: `1px solid ${colors.accent}30`,
|
|
986
|
+
display: "flex",
|
|
987
|
+
alignItems: "center",
|
|
988
|
+
justifyContent: "center",
|
|
989
|
+
flexShrink: 0
|
|
990
|
+
},
|
|
991
|
+
children: /* @__PURE__ */ jsx2(SparkIcon, { color: colors.accent, size: 13 })
|
|
992
|
+
}
|
|
993
|
+
),
|
|
994
|
+
titleId && title ? /* @__PURE__ */ jsx2(
|
|
995
|
+
"h2",
|
|
996
|
+
{
|
|
997
|
+
id: titleId,
|
|
998
|
+
style: { margin: 0, fontSize: 16, fontWeight: 600, color: colors.text, letterSpacing: "-0.01em", flex: 1 },
|
|
999
|
+
children: title
|
|
1000
|
+
}
|
|
1001
|
+
) : /* @__PURE__ */ jsx2("span", { style: { flex: 1, fontSize: 15, fontWeight: 600, color: colors.textMuted }, children: "Flint" }),
|
|
1002
|
+
showClose && /* @__PURE__ */ jsx2(
|
|
1003
|
+
"button",
|
|
1004
|
+
{
|
|
1005
|
+
onClick: onClose,
|
|
1006
|
+
"aria-label": "Close",
|
|
1007
|
+
style: {
|
|
1008
|
+
background: "none",
|
|
1009
|
+
border: "none",
|
|
1010
|
+
cursor: "pointer",
|
|
1011
|
+
padding: 4,
|
|
1012
|
+
color: colors.textMuted,
|
|
1013
|
+
fontSize: 22,
|
|
1014
|
+
lineHeight: 1,
|
|
1015
|
+
borderRadius: 6,
|
|
1016
|
+
display: "flex",
|
|
1017
|
+
alignItems: "center",
|
|
1018
|
+
justifyContent: "center",
|
|
1019
|
+
opacity: 0.6,
|
|
1020
|
+
fontFamily: "inherit"
|
|
1021
|
+
},
|
|
1022
|
+
children: "\xD7"
|
|
1023
|
+
}
|
|
1024
|
+
)
|
|
1025
|
+
]
|
|
1026
|
+
}
|
|
1027
|
+
);
|
|
960
1028
|
}
|
|
961
1029
|
function FieldLabel({
|
|
962
1030
|
children,
|
|
@@ -1018,19 +1086,71 @@ function SeverityButton({ sev, label, selected, hint, color, accent, border, bg,
|
|
|
1018
1086
|
},
|
|
1019
1087
|
children: [
|
|
1020
1088
|
/* @__PURE__ */ jsx2("span", { style: { width: 8, height: 8, borderRadius: "50%", background: color, display: "block" } }),
|
|
1021
|
-
/* @__PURE__ */ jsx2(
|
|
1089
|
+
/* @__PURE__ */ jsx2(
|
|
1090
|
+
"span",
|
|
1091
|
+
{
|
|
1092
|
+
style: {
|
|
1093
|
+
fontSize: 13,
|
|
1094
|
+
fontWeight: selected ? 700 : 500,
|
|
1095
|
+
color: selected ? accent : text,
|
|
1096
|
+
letterSpacing: "0.02em"
|
|
1097
|
+
},
|
|
1098
|
+
children: sev
|
|
1099
|
+
}
|
|
1100
|
+
),
|
|
1022
1101
|
/* @__PURE__ */ jsx2("span", { style: { fontSize: 11, color: selected ? accent : text, opacity: 0.6, letterSpacing: "0.02em" }, children: label })
|
|
1023
1102
|
]
|
|
1024
1103
|
}
|
|
1025
1104
|
);
|
|
1026
1105
|
}
|
|
1027
1106
|
function SparkIcon({ color = "currentColor", size = 14 }) {
|
|
1028
|
-
return /* @__PURE__ */ jsx2(
|
|
1107
|
+
return /* @__PURE__ */ jsx2(
|
|
1108
|
+
"svg",
|
|
1109
|
+
{
|
|
1110
|
+
width: size,
|
|
1111
|
+
height: size,
|
|
1112
|
+
viewBox: "0 0 24 24",
|
|
1113
|
+
fill: "none",
|
|
1114
|
+
stroke: color,
|
|
1115
|
+
strokeWidth: "2.2",
|
|
1116
|
+
strokeLinecap: "round",
|
|
1117
|
+
strokeLinejoin: "round",
|
|
1118
|
+
"aria-hidden": "true",
|
|
1119
|
+
children: /* @__PURE__ */ jsx2("path", { d: "M13 2L3 14h9l-1 8 10-12h-9l1-8z" })
|
|
1120
|
+
}
|
|
1121
|
+
);
|
|
1029
1122
|
}
|
|
1030
1123
|
function CheckIcon({ size = 20 }) {
|
|
1031
|
-
return /* @__PURE__ */ jsx2(
|
|
1124
|
+
return /* @__PURE__ */ jsx2(
|
|
1125
|
+
"svg",
|
|
1126
|
+
{
|
|
1127
|
+
width: size,
|
|
1128
|
+
height: size,
|
|
1129
|
+
viewBox: "0 0 24 24",
|
|
1130
|
+
fill: "none",
|
|
1131
|
+
stroke: "#22c55e",
|
|
1132
|
+
strokeWidth: "2.5",
|
|
1133
|
+
strokeLinecap: "round",
|
|
1134
|
+
strokeLinejoin: "round",
|
|
1135
|
+
"aria-hidden": "true",
|
|
1136
|
+
children: /* @__PURE__ */ jsx2("polyline", { points: "20 6 9 17 4 12" })
|
|
1137
|
+
}
|
|
1138
|
+
);
|
|
1032
1139
|
}
|
|
1033
1140
|
|
|
1141
|
+
// src/FlintWidget.tsx
|
|
1142
|
+
import { useCallback as useCallback2, useEffect as useEffect3, useRef as useRef3, useState as useState3 } from "react";
|
|
1143
|
+
import { I18nextProvider, useTranslation as useTranslation2 } from "react-i18next";
|
|
1144
|
+
|
|
1145
|
+
// src/collectors/console.ts
|
|
1146
|
+
import { createConsoleCollector } from "@flint/core";
|
|
1147
|
+
|
|
1148
|
+
// src/collectors/environment.ts
|
|
1149
|
+
import { collectEnvironment } from "@flint/core";
|
|
1150
|
+
|
|
1151
|
+
// src/collectors/network.ts
|
|
1152
|
+
import { createNetworkCollector } from "@flint/core";
|
|
1153
|
+
|
|
1034
1154
|
// src/i18n/index.ts
|
|
1035
1155
|
import { createInstance } from "i18next";
|
|
1036
1156
|
import { initReactI18next } from "react-i18next";
|
|
@@ -1080,251 +1200,15 @@ widgetI18n.use(initReactI18next).init({
|
|
|
1080
1200
|
});
|
|
1081
1201
|
var i18n_default = widgetI18n;
|
|
1082
1202
|
|
|
1083
|
-
// src/collectors/environment.ts
|
|
1084
|
-
function collectEnvironment() {
|
|
1085
|
-
const ua = navigator.userAgent;
|
|
1086
|
-
let browser = "Unknown";
|
|
1087
|
-
const chromeM = ua.match(/Chrome\/(\d+)/);
|
|
1088
|
-
const firefoxM = ua.match(/Firefox\/(\d+)/);
|
|
1089
|
-
const edgeM = ua.match(/Edg\/(\d+)/);
|
|
1090
|
-
const safariM = ua.match(/Version\/(\d+)/);
|
|
1091
|
-
const operaM = ua.match(/OPR\/(\d+)/);
|
|
1092
|
-
if (operaM) {
|
|
1093
|
-
browser = `Opera ${operaM[1]}`;
|
|
1094
|
-
} else if (edgeM) {
|
|
1095
|
-
browser = `Edge ${edgeM[1]}`;
|
|
1096
|
-
} else if (chromeM && !/Edg|OPR/.test(ua)) {
|
|
1097
|
-
browser = `Chrome ${chromeM[1]}`;
|
|
1098
|
-
} else if (firefoxM) {
|
|
1099
|
-
browser = `Firefox ${firefoxM[1]}`;
|
|
1100
|
-
} else if (safariM && /Safari\//.test(ua)) {
|
|
1101
|
-
browser = `Safari ${safariM[1]}`;
|
|
1102
|
-
}
|
|
1103
|
-
let os = "Unknown";
|
|
1104
|
-
const macM = ua.match(/Mac OS X (\d+[._]\d+)/);
|
|
1105
|
-
const winM = ua.match(/Windows NT (\d+\.\d+)/);
|
|
1106
|
-
const androidM = ua.match(/Android (\d+)/);
|
|
1107
|
-
const iosM = ua.match(/iPhone OS (\d+[._]\d+)/);
|
|
1108
|
-
if (macM) {
|
|
1109
|
-
os = `macOS ${macM[1].replace("_", ".")}`;
|
|
1110
|
-
} else if (winM) {
|
|
1111
|
-
const winMap = {
|
|
1112
|
-
"10.0": "10/11",
|
|
1113
|
-
"6.3": "8.1",
|
|
1114
|
-
"6.2": "8",
|
|
1115
|
-
"6.1": "7"
|
|
1116
|
-
};
|
|
1117
|
-
os = `Windows ${winMap[winM[1]] ?? winM[1]}`;
|
|
1118
|
-
} else if (androidM) {
|
|
1119
|
-
os = `Android ${androidM[1]}`;
|
|
1120
|
-
} else if (iosM) {
|
|
1121
|
-
os = `iOS ${iosM[1].replace(/_/g, ".")}`;
|
|
1122
|
-
} else if (/Linux/.test(ua)) {
|
|
1123
|
-
os = "Linux";
|
|
1124
|
-
}
|
|
1125
|
-
return {
|
|
1126
|
-
browser,
|
|
1127
|
-
os,
|
|
1128
|
-
viewport: `${window.innerWidth}x${window.innerHeight}`,
|
|
1129
|
-
screen: `${screen.width}x${screen.height}`,
|
|
1130
|
-
language: navigator.language,
|
|
1131
|
-
timezone: Intl.DateTimeFormat().resolvedOptions().timeZone,
|
|
1132
|
-
online: navigator.onLine
|
|
1133
|
-
};
|
|
1134
|
-
}
|
|
1135
|
-
|
|
1136
|
-
// src/collectors/console.ts
|
|
1137
|
-
var MAX_ENTRIES = 50;
|
|
1138
|
-
function createConsoleCollector() {
|
|
1139
|
-
const entries = [];
|
|
1140
|
-
let active = false;
|
|
1141
|
-
const originals = {
|
|
1142
|
-
log: console.log.bind(console),
|
|
1143
|
-
warn: console.warn.bind(console),
|
|
1144
|
-
error: console.error.bind(console)
|
|
1145
|
-
};
|
|
1146
|
-
let origOnerror = null;
|
|
1147
|
-
let origUnhandled = null;
|
|
1148
|
-
function push(level, args) {
|
|
1149
|
-
let str;
|
|
1150
|
-
try {
|
|
1151
|
-
str = args.map((a) => typeof a === "string" ? a : JSON.stringify(a)).join(" ");
|
|
1152
|
-
} catch {
|
|
1153
|
-
str = String(args[0]);
|
|
1154
|
-
}
|
|
1155
|
-
if (str.length > 500) str = str.slice(0, 500) + "\u2026";
|
|
1156
|
-
entries.push({ level, args: str, timestamp: Date.now() });
|
|
1157
|
-
if (entries.length > MAX_ENTRIES) entries.shift();
|
|
1158
|
-
}
|
|
1159
|
-
return {
|
|
1160
|
-
start() {
|
|
1161
|
-
if (active) return;
|
|
1162
|
-
active = true;
|
|
1163
|
-
console.log = (...args) => {
|
|
1164
|
-
push("log", args);
|
|
1165
|
-
originals.log(...args);
|
|
1166
|
-
};
|
|
1167
|
-
console.warn = (...args) => {
|
|
1168
|
-
push("warn", args);
|
|
1169
|
-
originals.warn(...args);
|
|
1170
|
-
};
|
|
1171
|
-
console.error = (...args) => {
|
|
1172
|
-
push("error", args);
|
|
1173
|
-
originals.error(...args);
|
|
1174
|
-
};
|
|
1175
|
-
origOnerror = window.onerror;
|
|
1176
|
-
window.onerror = (msg, src, line, col, err) => {
|
|
1177
|
-
push("error", [err?.message ?? String(msg), `${src}:${line}:${col}`]);
|
|
1178
|
-
if (typeof origOnerror === "function")
|
|
1179
|
-
return origOnerror(msg, src, line, col, err);
|
|
1180
|
-
return false;
|
|
1181
|
-
};
|
|
1182
|
-
origUnhandled = window.onunhandledrejection;
|
|
1183
|
-
window.onunhandledrejection = (event) => {
|
|
1184
|
-
const reason = event.reason instanceof Error ? event.reason.message : JSON.stringify(event.reason);
|
|
1185
|
-
push("error", ["UnhandledRejection:", reason]);
|
|
1186
|
-
if (typeof origUnhandled === "function")
|
|
1187
|
-
origUnhandled.call(window, event);
|
|
1188
|
-
};
|
|
1189
|
-
},
|
|
1190
|
-
stop() {
|
|
1191
|
-
if (!active) return;
|
|
1192
|
-
active = false;
|
|
1193
|
-
console.log = originals.log;
|
|
1194
|
-
console.warn = originals.warn;
|
|
1195
|
-
console.error = originals.error;
|
|
1196
|
-
window.onerror = origOnerror;
|
|
1197
|
-
window.onunhandledrejection = origUnhandled;
|
|
1198
|
-
},
|
|
1199
|
-
getEntries() {
|
|
1200
|
-
return [...entries];
|
|
1201
|
-
}
|
|
1202
|
-
};
|
|
1203
|
-
}
|
|
1204
|
-
|
|
1205
|
-
// src/collectors/network.ts
|
|
1206
|
-
var MAX_ENTRIES2 = 50;
|
|
1207
|
-
var BLOCKED_HOSTS = /* @__PURE__ */ new Set([
|
|
1208
|
-
"browser-intake-datadoghq.com",
|
|
1209
|
-
"rum.browser-intake-datadoghq.com",
|
|
1210
|
-
"logs.browser-intake-datadoghq.com",
|
|
1211
|
-
"session-replay.browser-intake-datadoghq.com"
|
|
1212
|
-
]);
|
|
1213
|
-
function isBlockedUrl(url, extra) {
|
|
1214
|
-
try {
|
|
1215
|
-
const host = new URL(url, location.href).hostname;
|
|
1216
|
-
const all = [...BLOCKED_HOSTS, ...extra];
|
|
1217
|
-
return all.some((b) => host === b || host.endsWith("." + b));
|
|
1218
|
-
} catch {
|
|
1219
|
-
return false;
|
|
1220
|
-
}
|
|
1221
|
-
}
|
|
1222
|
-
function truncateUrl(url) {
|
|
1223
|
-
try {
|
|
1224
|
-
const u = new URL(url, location.href);
|
|
1225
|
-
const base = `${u.origin}${u.pathname}`;
|
|
1226
|
-
return base.length > 200 ? base.slice(0, 200) + "\u2026" : base;
|
|
1227
|
-
} catch {
|
|
1228
|
-
return url.length > 200 ? url.slice(0, 200) + "\u2026" : url;
|
|
1229
|
-
}
|
|
1230
|
-
}
|
|
1231
|
-
function createNetworkCollector(extraBlockedHosts = []) {
|
|
1232
|
-
const entries = [];
|
|
1233
|
-
const blocked = new Set(extraBlockedHosts);
|
|
1234
|
-
let origFetch = null;
|
|
1235
|
-
let origXHROpen = null;
|
|
1236
|
-
let active = false;
|
|
1237
|
-
function push(entry) {
|
|
1238
|
-
entries.push(entry);
|
|
1239
|
-
if (entries.length > MAX_ENTRIES2) entries.shift();
|
|
1240
|
-
}
|
|
1241
|
-
return {
|
|
1242
|
-
start() {
|
|
1243
|
-
if (active) return;
|
|
1244
|
-
active = true;
|
|
1245
|
-
origFetch = window.fetch;
|
|
1246
|
-
window.fetch = async (input, init) => {
|
|
1247
|
-
const method = (init?.method ?? "GET").toUpperCase();
|
|
1248
|
-
const url = typeof input === "string" ? input : input instanceof URL ? input.href : input.url;
|
|
1249
|
-
const startTime = Date.now();
|
|
1250
|
-
const res = await origFetch.call(window, input, init);
|
|
1251
|
-
if (res.status >= 400 && !isBlockedUrl(url, blocked)) {
|
|
1252
|
-
push({
|
|
1253
|
-
method,
|
|
1254
|
-
url: truncateUrl(url),
|
|
1255
|
-
status: res.status,
|
|
1256
|
-
duration: Date.now() - startTime,
|
|
1257
|
-
timestamp: startTime
|
|
1258
|
-
});
|
|
1259
|
-
}
|
|
1260
|
-
return res;
|
|
1261
|
-
};
|
|
1262
|
-
origXHROpen = XMLHttpRequest.prototype.open;
|
|
1263
|
-
XMLHttpRequest.prototype.open = function(method, url, async, username, password) {
|
|
1264
|
-
const startTime = Date.now();
|
|
1265
|
-
const urlStr = typeof url === "string" ? url : url.href;
|
|
1266
|
-
this.addEventListener("load", () => {
|
|
1267
|
-
if (this.status >= 400 && !isBlockedUrl(urlStr, blocked)) {
|
|
1268
|
-
push({
|
|
1269
|
-
method: method.toUpperCase(),
|
|
1270
|
-
url: truncateUrl(urlStr),
|
|
1271
|
-
status: this.status,
|
|
1272
|
-
duration: Date.now() - startTime,
|
|
1273
|
-
timestamp: startTime
|
|
1274
|
-
});
|
|
1275
|
-
}
|
|
1276
|
-
});
|
|
1277
|
-
return origXHROpen.apply(this, [
|
|
1278
|
-
method,
|
|
1279
|
-
url,
|
|
1280
|
-
async ?? true,
|
|
1281
|
-
username,
|
|
1282
|
-
password
|
|
1283
|
-
]);
|
|
1284
|
-
};
|
|
1285
|
-
},
|
|
1286
|
-
stop() {
|
|
1287
|
-
if (!active) return;
|
|
1288
|
-
active = false;
|
|
1289
|
-
if (origFetch) window.fetch = origFetch;
|
|
1290
|
-
if (origXHROpen) XMLHttpRequest.prototype.open = origXHROpen;
|
|
1291
|
-
},
|
|
1292
|
-
getEntries() {
|
|
1293
|
-
return [...entries];
|
|
1294
|
-
}
|
|
1295
|
-
};
|
|
1296
|
-
}
|
|
1297
|
-
|
|
1298
1203
|
// src/store.ts
|
|
1204
|
+
import { getSnapshot, subscribe } from "@flint/core";
|
|
1299
1205
|
import { useSyncExternalStore } from "react";
|
|
1300
|
-
|
|
1301
|
-
var listeners = /* @__PURE__ */ new Set();
|
|
1302
|
-
function emit() {
|
|
1303
|
-
listeners.forEach((fn) => fn());
|
|
1304
|
-
}
|
|
1305
|
-
function subscribeStore(fn) {
|
|
1306
|
-
listeners.add(fn);
|
|
1307
|
-
return () => listeners.delete(fn);
|
|
1308
|
-
}
|
|
1309
|
-
function getSnapshot() {
|
|
1310
|
-
return state;
|
|
1311
|
-
}
|
|
1206
|
+
import { flint as flint2 } from "@flint/core";
|
|
1312
1207
|
function useFlintStore() {
|
|
1313
|
-
return useSyncExternalStore(
|
|
1208
|
+
return useSyncExternalStore(subscribe, getSnapshot);
|
|
1314
1209
|
}
|
|
1315
|
-
var flint = {
|
|
1316
|
-
setUser(user) {
|
|
1317
|
-
state = { ...state, user: user ?? void 0 };
|
|
1318
|
-
emit();
|
|
1319
|
-
},
|
|
1320
|
-
setSessionReplay(url) {
|
|
1321
|
-
state = { ...state, sessionReplay: url };
|
|
1322
|
-
emit();
|
|
1323
|
-
}
|
|
1324
|
-
};
|
|
1325
1210
|
|
|
1326
1211
|
// src/FlintWidget.tsx
|
|
1327
|
-
import { record } from "rrweb";
|
|
1328
1212
|
import { Fragment as Fragment2, jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
1329
1213
|
var REPLAY_WINDOW_MS = 6e4;
|
|
1330
1214
|
function FlintWidget(props) {
|
|
@@ -1343,7 +1227,17 @@ function WidgetContent({
|
|
|
1343
1227
|
buttonLabel,
|
|
1344
1228
|
theme = "dark",
|
|
1345
1229
|
zIndex = 9999,
|
|
1346
|
-
|
|
1230
|
+
statusPageUrl,
|
|
1231
|
+
datadogSite,
|
|
1232
|
+
enableReplay = true,
|
|
1233
|
+
enableScreenshot = true,
|
|
1234
|
+
enableConsole = true,
|
|
1235
|
+
enableNetwork = true,
|
|
1236
|
+
onBeforeSubmit,
|
|
1237
|
+
onSuccess,
|
|
1238
|
+
onError,
|
|
1239
|
+
onOpen,
|
|
1240
|
+
onClose
|
|
1347
1241
|
}) {
|
|
1348
1242
|
const globalState = useFlintStore();
|
|
1349
1243
|
const resolvedUser = user ?? globalState.user;
|
|
@@ -1357,9 +1251,9 @@ function WidgetContent({
|
|
|
1357
1251
|
const ddRum = window.DD_RUM;
|
|
1358
1252
|
const ctx = ddRum?.getInternalContext?.();
|
|
1359
1253
|
if (ctx?.session_id) {
|
|
1360
|
-
const now = Date.now();
|
|
1361
|
-
const fromTs = now -
|
|
1362
|
-
const toTs = now +
|
|
1254
|
+
const now = Math.floor(Date.now() / 1e3);
|
|
1255
|
+
const fromTs = now - 30;
|
|
1256
|
+
const toTs = now + 5;
|
|
1363
1257
|
return `https://${datadogSite}/rum/replay/sessions/${ctx.session_id}?from_ts=${fromTs}&to_ts=${toTs}&tab=replay&live=false`;
|
|
1364
1258
|
}
|
|
1365
1259
|
} catch {
|
|
@@ -1412,16 +1306,17 @@ function WidgetContent({
|
|
|
1412
1306
|
pendingSelection.current = text;
|
|
1413
1307
|
setSelectionTooltip(null);
|
|
1414
1308
|
setOpen(true);
|
|
1309
|
+
onOpen?.();
|
|
1415
1310
|
};
|
|
1416
1311
|
const consoleCollector = useRef3(null);
|
|
1417
1312
|
const networkCollector = useRef3(null);
|
|
1418
1313
|
const replayEvents = useRef3([]);
|
|
1419
1314
|
const stopReplay = useRef3(null);
|
|
1420
|
-
if (!consoleCollector.current) {
|
|
1315
|
+
if (enableConsole && !consoleCollector.current) {
|
|
1421
1316
|
consoleCollector.current = createConsoleCollector();
|
|
1422
1317
|
consoleCollector.current.start();
|
|
1423
1318
|
}
|
|
1424
|
-
if (!networkCollector.current) {
|
|
1319
|
+
if (enableNetwork && !networkCollector.current) {
|
|
1425
1320
|
const flintHost = (() => {
|
|
1426
1321
|
try {
|
|
1427
1322
|
return new URL(serverUrl).hostname;
|
|
@@ -1433,22 +1328,29 @@ function WidgetContent({
|
|
|
1433
1328
|
networkCollector.current.start();
|
|
1434
1329
|
}
|
|
1435
1330
|
useEffect3(() => {
|
|
1436
|
-
|
|
1437
|
-
|
|
1438
|
-
|
|
1439
|
-
|
|
1440
|
-
|
|
1441
|
-
|
|
1442
|
-
|
|
1443
|
-
|
|
1444
|
-
|
|
1445
|
-
|
|
1331
|
+
let cancelled = false;
|
|
1332
|
+
if (enableReplay) {
|
|
1333
|
+
import("rrweb").then(({ record }) => {
|
|
1334
|
+
if (cancelled) return;
|
|
1335
|
+
const stopFn = record({
|
|
1336
|
+
emit(event) {
|
|
1337
|
+
replayEvents.current.push(event);
|
|
1338
|
+
const cutoff = Date.now() - REPLAY_WINDOW_MS;
|
|
1339
|
+
while (replayEvents.current.length > 0 && replayEvents.current[0].timestamp < cutoff) {
|
|
1340
|
+
replayEvents.current.shift();
|
|
1341
|
+
}
|
|
1342
|
+
}
|
|
1343
|
+
});
|
|
1344
|
+
stopReplay.current = stopFn ?? null;
|
|
1345
|
+
});
|
|
1346
|
+
}
|
|
1446
1347
|
return () => {
|
|
1348
|
+
cancelled = true;
|
|
1447
1349
|
consoleCollector.current?.stop();
|
|
1448
1350
|
networkCollector.current?.stop();
|
|
1449
1351
|
stopReplay.current?.();
|
|
1450
1352
|
};
|
|
1451
|
-
}, []);
|
|
1353
|
+
}, [enableReplay]);
|
|
1452
1354
|
const label = buttonLabel ?? t("buttonLabel");
|
|
1453
1355
|
return /* @__PURE__ */ jsxs3(Fragment2, { children: [
|
|
1454
1356
|
/* @__PURE__ */ jsxs3(
|
|
@@ -1458,7 +1360,10 @@ function WidgetContent({
|
|
|
1458
1360
|
onMouseDown: () => {
|
|
1459
1361
|
pendingSelection.current = window.getSelection()?.toString().trim() ?? "";
|
|
1460
1362
|
},
|
|
1461
|
-
onClick: () =>
|
|
1363
|
+
onClick: () => {
|
|
1364
|
+
setOpen(true);
|
|
1365
|
+
onOpen?.();
|
|
1366
|
+
},
|
|
1462
1367
|
onMouseEnter: () => setHovered(true),
|
|
1463
1368
|
onMouseLeave: () => setHovered(false),
|
|
1464
1369
|
"aria-label": label,
|
|
@@ -1539,6 +1444,7 @@ function WidgetContent({
|
|
|
1539
1444
|
zIndex,
|
|
1540
1445
|
onClose: () => {
|
|
1541
1446
|
setOpen(false);
|
|
1447
|
+
onClose?.();
|
|
1542
1448
|
pendingSelection.current = "";
|
|
1543
1449
|
},
|
|
1544
1450
|
getEnvironment: collectEnvironment,
|
|
@@ -1546,18 +1452,37 @@ function WidgetContent({
|
|
|
1546
1452
|
getNetworkErrors: () => networkCollector.current?.getEntries() ?? [],
|
|
1547
1453
|
getReplayEvents: () => [...replayEvents.current],
|
|
1548
1454
|
getExternalReplayUrl,
|
|
1549
|
-
initialSelection: pendingSelection.current
|
|
1455
|
+
initialSelection: pendingSelection.current,
|
|
1456
|
+
enableScreenshot,
|
|
1457
|
+
statusPageUrl,
|
|
1458
|
+
onBeforeSubmit,
|
|
1459
|
+
onSuccess,
|
|
1460
|
+
onError
|
|
1550
1461
|
}
|
|
1551
1462
|
)
|
|
1552
1463
|
] });
|
|
1553
1464
|
}
|
|
1554
1465
|
function TextIcon() {
|
|
1555
|
-
return /* @__PURE__ */ jsxs3(
|
|
1556
|
-
|
|
1557
|
-
|
|
1558
|
-
|
|
1559
|
-
|
|
1560
|
-
|
|
1466
|
+
return /* @__PURE__ */ jsxs3(
|
|
1467
|
+
"svg",
|
|
1468
|
+
{
|
|
1469
|
+
width: "12",
|
|
1470
|
+
height: "12",
|
|
1471
|
+
viewBox: "0 0 24 24",
|
|
1472
|
+
fill: "none",
|
|
1473
|
+
stroke: "currentColor",
|
|
1474
|
+
strokeWidth: "2.2",
|
|
1475
|
+
strokeLinecap: "round",
|
|
1476
|
+
strokeLinejoin: "round",
|
|
1477
|
+
"aria-hidden": "true",
|
|
1478
|
+
children: [
|
|
1479
|
+
/* @__PURE__ */ jsx3("path", { d: "M17 10H3" }),
|
|
1480
|
+
/* @__PURE__ */ jsx3("path", { d: "M21 6H3" }),
|
|
1481
|
+
/* @__PURE__ */ jsx3("path", { d: "M21 14H3" }),
|
|
1482
|
+
/* @__PURE__ */ jsx3("path", { d: "M17 18H3" })
|
|
1483
|
+
]
|
|
1484
|
+
}
|
|
1485
|
+
);
|
|
1561
1486
|
}
|
|
1562
1487
|
function SparkIcon2() {
|
|
1563
1488
|
return /* @__PURE__ */ jsx3(
|
|
@@ -1579,6 +1504,6 @@ function SparkIcon2() {
|
|
|
1579
1504
|
export {
|
|
1580
1505
|
FlintModal,
|
|
1581
1506
|
FlintWidget,
|
|
1582
|
-
flint
|
|
1507
|
+
flint2 as flint
|
|
1583
1508
|
};
|
|
1584
1509
|
//# sourceMappingURL=index.js.map
|