@diegotsi/flint-react 0.1.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 ADDED
@@ -0,0 +1,1116 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/index.ts
21
+ var index_exports = {};
22
+ __export(index_exports, {
23
+ FlintModal: () => FlintModal,
24
+ FlintWidget: () => FlintWidget
25
+ });
26
+ module.exports = __toCommonJS(index_exports);
27
+
28
+ // src/FlintWidget.tsx
29
+ var import_react2 = require("react");
30
+ var import_react_i18next3 = require("react-i18next");
31
+
32
+ // src/FlintModal.tsx
33
+ var import_react = require("react");
34
+ var import_react_i18next = require("react-i18next");
35
+
36
+ // src/api.ts
37
+ var import_fflate = require("fflate");
38
+ async function submitReport(serverUrl, projectKey, payload, screenshot) {
39
+ const url = `${serverUrl.replace(/\/$/, "")}/api/v1/bug-reports`;
40
+ let body;
41
+ let headers = {
42
+ "x-project-key": projectKey
43
+ };
44
+ if (screenshot) {
45
+ const form = new FormData();
46
+ form.append("reporterId", payload.reporterId);
47
+ form.append("reporterName", payload.reporterName);
48
+ form.append("description", payload.description);
49
+ if (payload.expectedBehavior) form.append("expectedBehavior", payload.expectedBehavior);
50
+ if (payload.stepsToReproduce) form.append("stepsToReproduce", JSON.stringify(payload.stepsToReproduce));
51
+ if (payload.externalReplayUrl) form.append("externalReplayUrl", payload.externalReplayUrl);
52
+ if (payload.additionalContext) form.append("additionalContext", payload.additionalContext);
53
+ form.append("severity", payload.severity);
54
+ if (payload.url) form.append("url", payload.url);
55
+ if (payload.meta) form.append("meta", JSON.stringify(payload.meta));
56
+ form.append("screenshot", screenshot);
57
+ body = form;
58
+ } else {
59
+ body = JSON.stringify(payload);
60
+ headers["Content-Type"] = "application/json";
61
+ }
62
+ const res = await fetch(url, { method: "POST", headers, body });
63
+ if (!res.ok) {
64
+ const err = await res.json().catch(() => ({ error: "Unknown error" }));
65
+ throw new Error(err.error ?? `HTTP ${res.status}`);
66
+ }
67
+ return res.json();
68
+ }
69
+ async function submitReplay(serverUrl, projectKey, reportId, events) {
70
+ const json = JSON.stringify(events);
71
+ const encoded = new TextEncoder().encode(json);
72
+ const compressed = (0, import_fflate.gzipSync)(encoded);
73
+ const url = `${serverUrl.replace(/\/$/, "")}/api/v1/bug-reports/${reportId}/replay`;
74
+ await fetch(url, {
75
+ method: "POST",
76
+ headers: {
77
+ "x-project-key": projectKey,
78
+ "Content-Type": "application/octet-stream"
79
+ },
80
+ body: compressed.buffer
81
+ });
82
+ }
83
+
84
+ // src/theme.ts
85
+ var light = {
86
+ background: "rgba(255,255,255,0.90)",
87
+ backgroundSecondary: "rgba(249,250,251,0.75)",
88
+ accent: "#2563eb",
89
+ accentHover: "#1d4ed8",
90
+ text: "#111827",
91
+ textMuted: "#6b7280",
92
+ border: "rgba(255,255,255,0.9)",
93
+ 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)",
94
+ buttonText: "#ffffff",
95
+ backdropFilter: "blur(32px) saturate(1.8)"
96
+ };
97
+ var dark = {
98
+ background: "rgba(15,20,35,0.88)",
99
+ backgroundSecondary: "rgba(5,8,18,0.65)",
100
+ accent: "#f97316",
101
+ accentHover: "#ea6c0a",
102
+ text: "#dde3ef",
103
+ textMuted: "#6b7a93",
104
+ border: "rgba(255,255,255,0.08)",
105
+ shadow: "0 24px 60px rgba(0,0,0,0.6), 0 0 0 1px rgba(255,255,255,0.04)",
106
+ buttonText: "#ffffff",
107
+ backdropFilter: "blur(32px) saturate(1.6)"
108
+ };
109
+ function resolveTheme(theme) {
110
+ if (theme === "dark") return dark;
111
+ if (theme === "light") return light;
112
+ const override = theme;
113
+ return {
114
+ ...light,
115
+ background: override.background ?? light.background,
116
+ accent: override.accent ?? light.accent,
117
+ accentHover: override.accent ?? light.accentHover,
118
+ text: override.text ?? light.text,
119
+ border: override.border ?? light.border
120
+ };
121
+ }
122
+
123
+ // src/FlintModal.tsx
124
+ var import_jsx_runtime = require("react/jsx-runtime");
125
+ var SEVERITIES = ["P1", "P2", "P3", "P4"];
126
+ var SEV_COLOR = {
127
+ P1: "#ef4444",
128
+ P2: "#f97316",
129
+ P3: "#eab308",
130
+ P4: "#22c55e"
131
+ };
132
+ function injectKeyframes() {
133
+ if (typeof document === "undefined") return;
134
+ if (document.getElementById("_flint_kf")) return;
135
+ const s = document.createElement("style");
136
+ s.id = "_flint_kf";
137
+ s.textContent = `
138
+ @keyframes _flint_in {
139
+ from { opacity: 0; transform: scale(0.93) translateY(10px); }
140
+ to { opacity: 1; transform: scale(1) translateY(0); }
141
+ }
142
+ @keyframes _flint_overlay_in {
143
+ from { opacity: 0; }
144
+ to { opacity: 1; }
145
+ }
146
+ @keyframes _flint_spin {
147
+ to { transform: rotate(360deg); }
148
+ }
149
+ @keyframes _flint_pulse {
150
+ 0%, 100% { opacity: 0.5; transform: scale(0.88); }
151
+ 50% { opacity: 1; transform: scale(1.08); }
152
+ }
153
+ @keyframes _flint_ripple {
154
+ 0% { opacity: 0.5; transform: scale(0.75); }
155
+ 100% { opacity: 0; transform: scale(1.55); }
156
+ }
157
+ @keyframes _flint_sending_dot {
158
+ 0%, 80%, 100% { opacity: 0.2; transform: scale(0.8); }
159
+ 40% { opacity: 1; transform: scale(1); }
160
+ }
161
+ @keyframes _flint_success_up {
162
+ from { opacity: 0; transform: translateY(8px); }
163
+ to { opacity: 1; transform: translateY(0); }
164
+ }
165
+ `;
166
+ document.head.appendChild(s);
167
+ }
168
+ function FlintModal({
169
+ projectKey,
170
+ serverUrl,
171
+ user,
172
+ meta,
173
+ theme,
174
+ zIndex,
175
+ onClose,
176
+ getEnvironment,
177
+ getConsoleLogs,
178
+ getNetworkErrors,
179
+ getReplayEvents,
180
+ externalReplayUrl
181
+ }) {
182
+ const { t } = (0, import_react_i18next.useTranslation)();
183
+ const colors = resolveTheme(theme);
184
+ const isDark = theme === "dark";
185
+ const [severity, setSeverity] = (0, import_react.useState)("P2");
186
+ const [description, setDescription] = (0, import_react.useState)("");
187
+ const [expectedBehavior, setExpectedBehavior] = (0, import_react.useState)("");
188
+ const [screenshot, setScreenshot] = (0, import_react.useState)(null);
189
+ const [status, setStatus] = (0, import_react.useState)("idle");
190
+ const [result, setResult] = (0, import_react.useState)(null);
191
+ const [errorMsg, setErrorMsg] = (0, import_react.useState)("");
192
+ const fileRef = (0, import_react.useRef)(null);
193
+ const overlayRef = (0, import_react.useRef)(null);
194
+ (0, import_react.useEffect)(() => {
195
+ injectKeyframes();
196
+ }, []);
197
+ (0, import_react.useEffect)(() => {
198
+ const handler = (e) => {
199
+ if (e.key === "Escape" && status !== "submitting") onClose();
200
+ };
201
+ window.addEventListener("keydown", handler);
202
+ return () => window.removeEventListener("keydown", handler);
203
+ }, [onClose, status]);
204
+ const handleOverlayClick = (0, import_react.useCallback)(
205
+ (e) => {
206
+ if (e.target === overlayRef.current && status !== "submitting") onClose();
207
+ },
208
+ [onClose, status]
209
+ );
210
+ const handleSubmit = async (e) => {
211
+ e.preventDefault();
212
+ if (!description.trim()) return;
213
+ setStatus("submitting");
214
+ setErrorMsg("");
215
+ const collectedMeta = {
216
+ ...meta,
217
+ environment: getEnvironment(),
218
+ consoleLogs: getConsoleLogs(),
219
+ networkErrors: getNetworkErrors()
220
+ };
221
+ try {
222
+ const res = await submitReport(
223
+ serverUrl,
224
+ projectKey,
225
+ {
226
+ reporterId: user?.id ?? "anonymous",
227
+ reporterName: user?.name ?? "Anonymous",
228
+ description: description.trim(),
229
+ expectedBehavior: expectedBehavior.trim() || void 0,
230
+ externalReplayUrl: externalReplayUrl || void 0,
231
+ severity,
232
+ url: window.location.href,
233
+ meta: collectedMeta
234
+ },
235
+ screenshot ?? void 0
236
+ );
237
+ setResult(res);
238
+ setStatus("success");
239
+ const events = getReplayEvents();
240
+ if (events.length > 0) {
241
+ submitReplay(serverUrl, projectKey, res.id, events).catch(() => {
242
+ });
243
+ }
244
+ } catch (err) {
245
+ setErrorMsg(err instanceof Error ? err.message : t("errorLabel"));
246
+ setStatus("error");
247
+ }
248
+ };
249
+ const inputBorder = isDark ? "rgba(255,255,255,0.1)" : "rgba(0,0,0,0.1)";
250
+ const accentGlow = `0 0 20px ${colors.accent}40, 0 4px 16px rgba(0,0,0,0.2)`;
251
+ const overlayStyle = {
252
+ position: "fixed",
253
+ inset: 0,
254
+ background: "rgba(0,0,0,0.5)",
255
+ display: "flex",
256
+ alignItems: "center",
257
+ justifyContent: "center",
258
+ zIndex,
259
+ padding: "16px",
260
+ backdropFilter: "blur(10px)",
261
+ WebkitBackdropFilter: "blur(10px)",
262
+ animation: "_flint_overlay_in 0.2s ease"
263
+ };
264
+ const modalStyle = {
265
+ background: colors.background,
266
+ backdropFilter: colors.backdropFilter,
267
+ WebkitBackdropFilter: colors.backdropFilter,
268
+ borderRadius: "20px",
269
+ boxShadow: colors.shadow,
270
+ border: `1px solid ${colors.border}`,
271
+ width: "100%",
272
+ maxWidth: "480px",
273
+ maxHeight: "92vh",
274
+ overflowY: "auto",
275
+ fontFamily: '-apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif',
276
+ color: colors.text,
277
+ animation: "_flint_in 0.28s cubic-bezier(0.16, 1, 0.3, 1)"
278
+ };
279
+ const inputStyle = {
280
+ width: "100%",
281
+ padding: "11px 13px",
282
+ borderRadius: "10px",
283
+ border: `1px solid ${inputBorder}`,
284
+ background: colors.backgroundSecondary,
285
+ color: colors.text,
286
+ fontSize: "14px",
287
+ outline: "none",
288
+ boxSizing: "border-box",
289
+ fontFamily: "inherit",
290
+ transition: "border-color 0.15s"
291
+ };
292
+ if (status === "submitting" || status === "success") {
293
+ const isSuccess = status === "success";
294
+ const ringBorder = isSuccess ? "3px solid #22c55e" : `3px solid ${isDark ? "rgba(255,255,255,0.08)" : "rgba(0,0,0,0.08)"}`;
295
+ const ringTopColor = isSuccess ? "#22c55e" : colors.accent;
296
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: overlayStyle, children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: modalStyle, role: "dialog", "aria-modal": "true", "aria-label": isSuccess ? t("successTitle") : t("sending"), children: [
297
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ModalHeader, { colors, inputBorder, showClose: false, onClose }),
298
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: { padding: "40px 32px 48px", textAlign: "center", display: "flex", flexDirection: "column", alignItems: "center" }, children: [
299
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: { position: "relative", width: 80, height: 80, marginBottom: 28 }, children: [
300
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: {
301
+ position: "absolute",
302
+ inset: -10,
303
+ borderRadius: "50%",
304
+ border: `1.5px solid ${colors.accent}`,
305
+ animation: "_flint_ripple 1.8s ease-out infinite",
306
+ opacity: isSuccess ? 0 : 1,
307
+ transition: "opacity 0.3s ease"
308
+ } }),
309
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: {
310
+ position: "absolute",
311
+ inset: -10,
312
+ borderRadius: "50%",
313
+ border: `1.5px solid ${colors.accent}`,
314
+ animation: "_flint_ripple 1.8s ease-out infinite 0.6s",
315
+ opacity: isSuccess ? 0 : 1,
316
+ transition: "opacity 0.3s ease"
317
+ } }),
318
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: {
319
+ position: "absolute",
320
+ inset: 0,
321
+ borderRadius: "50%",
322
+ border: ringBorder,
323
+ borderTopColor: ringTopColor,
324
+ animation: isSuccess ? "none" : "_flint_spin 0.85s linear infinite",
325
+ transition: "border-color 0.45s ease, border-top-color 0.45s ease"
326
+ } }),
327
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: { position: "absolute", inset: 14, borderRadius: "50%" }, children: [
328
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: {
329
+ position: "absolute",
330
+ inset: 0,
331
+ borderRadius: "50%",
332
+ background: `linear-gradient(135deg, ${colors.accent}30, ${colors.accentHover}50)`,
333
+ display: "flex",
334
+ alignItems: "center",
335
+ justifyContent: "center",
336
+ animation: isSuccess ? "none" : "_flint_pulse 2s ease-in-out infinite",
337
+ opacity: isSuccess ? 0 : 1,
338
+ transition: "opacity 0.3s ease"
339
+ }, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(SparkIcon, { color: colors.accent, size: 20 }) }),
340
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: {
341
+ position: "absolute",
342
+ inset: 0,
343
+ borderRadius: "50%",
344
+ background: "rgba(34,197,94,0.15)",
345
+ display: "flex",
346
+ alignItems: "center",
347
+ justifyContent: "center",
348
+ opacity: isSuccess ? 1 : 0,
349
+ transform: isSuccess ? "scale(1)" : "scale(0.65)",
350
+ transition: "opacity 0.35s ease 0.2s, transform 0.4s cubic-bezier(0.16,1,0.3,1) 0.2s"
351
+ }, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(CheckIcon, { size: 20 }) })
352
+ ] })
353
+ ] }),
354
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: { position: "relative", height: 26, width: "100%", marginBottom: 10 }, children: [
355
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: {
356
+ position: "absolute",
357
+ inset: 0,
358
+ display: "flex",
359
+ alignItems: "center",
360
+ justifyContent: "center",
361
+ fontSize: 17,
362
+ fontWeight: 700,
363
+ color: colors.text,
364
+ letterSpacing: "-0.02em",
365
+ opacity: isSuccess ? 0 : 1,
366
+ transition: "opacity 0.25s ease",
367
+ pointerEvents: "none"
368
+ }, children: t("sending") }),
369
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: {
370
+ position: "absolute",
371
+ inset: 0,
372
+ display: "flex",
373
+ alignItems: "center",
374
+ justifyContent: "center",
375
+ fontSize: 17,
376
+ fontWeight: 700,
377
+ color: colors.text,
378
+ letterSpacing: "-0.02em",
379
+ opacity: isSuccess ? 1 : 0,
380
+ transform: isSuccess ? "translateY(0)" : "translateY(6px)",
381
+ transition: "opacity 0.35s ease 0.25s, transform 0.35s ease 0.25s",
382
+ pointerEvents: isSuccess ? "auto" : "none"
383
+ }, children: t("successTitle") })
384
+ ] }),
385
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: { position: "relative", minHeight: 76, width: "100%" }, children: [
386
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: {
387
+ position: "absolute",
388
+ inset: 0,
389
+ display: "flex",
390
+ alignItems: "center",
391
+ justifyContent: "center",
392
+ gap: 6,
393
+ color: colors.textMuted,
394
+ fontSize: 13,
395
+ opacity: isSuccess ? 0 : 1,
396
+ transition: "opacity 0.2s ease",
397
+ pointerEvents: "none"
398
+ }, children: [
399
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { children: t("capturingContext") }),
400
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(SendingDots, { color: colors.accent })
401
+ ] }),
402
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: {
403
+ position: "absolute",
404
+ inset: 0,
405
+ display: "flex",
406
+ flexDirection: "column",
407
+ alignItems: "center",
408
+ gap: 10,
409
+ opacity: isSuccess ? 1 : 0,
410
+ transform: isSuccess ? "translateY(0)" : "translateY(8px)",
411
+ transition: "opacity 0.35s ease 0.35s, transform 0.35s ease 0.35s",
412
+ pointerEvents: isSuccess ? "auto" : "none"
413
+ }, children: [
414
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { style: { fontSize: 13, color: colors.textMuted, margin: 0 }, children: result?.isDuplicate ? t("successDuplicate") : result ? `ID: ${result.id}` : "" }),
415
+ result?.githubIssueUrl && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
416
+ "a",
417
+ {
418
+ href: result.githubIssueUrl,
419
+ target: "_blank",
420
+ rel: "noreferrer",
421
+ style: {
422
+ display: "inline-flex",
423
+ alignItems: "center",
424
+ gap: 6,
425
+ padding: "9px 18px",
426
+ borderRadius: "10px",
427
+ background: `linear-gradient(135deg, ${colors.accent}, ${colors.accentHover})`,
428
+ color: colors.buttonText,
429
+ textDecoration: "none",
430
+ fontSize: "13px",
431
+ fontWeight: 600,
432
+ boxShadow: accentGlow
433
+ },
434
+ children: [
435
+ t("successGitHub"),
436
+ " \u2197"
437
+ ]
438
+ }
439
+ ),
440
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
441
+ "button",
442
+ {
443
+ onClick: onClose,
444
+ style: {
445
+ background: "none",
446
+ border: "none",
447
+ cursor: "pointer",
448
+ fontSize: 13,
449
+ color: colors.textMuted,
450
+ padding: "4px 8px",
451
+ fontFamily: "inherit"
452
+ },
453
+ children: t("cancel")
454
+ }
455
+ )
456
+ ] })
457
+ ] })
458
+ ] })
459
+ ] }) });
460
+ }
461
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { ref: overlayRef, style: overlayStyle, onClick: handleOverlayClick, children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: modalStyle, role: "dialog", "aria-modal": "true", "aria-labelledby": "flint-modal-title", children: [
462
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
463
+ ModalHeader,
464
+ {
465
+ colors,
466
+ inputBorder,
467
+ showClose: true,
468
+ onClose,
469
+ titleId: "flint-modal-title",
470
+ title: t("modalTitle")
471
+ }
472
+ ),
473
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("form", { onSubmit: handleSubmit, style: { padding: "20px 24px 24px" }, children: [
474
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: { marginBottom: 18 }, children: [
475
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(FieldLabel, { colors, children: t("severityLabel") }),
476
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: { display: "grid", gridTemplateColumns: "repeat(4,1fr)", gap: 8 }, children: SEVERITIES.map((sev) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
477
+ SeverityButton,
478
+ {
479
+ sev,
480
+ label: t(`severity_${sev}_label`),
481
+ selected: severity === sev,
482
+ hint: t(`severity_${sev}_hint`),
483
+ color: SEV_COLOR[sev],
484
+ accent: colors.accent,
485
+ border: inputBorder,
486
+ bg: colors.backgroundSecondary,
487
+ text: colors.text,
488
+ onClick: () => setSeverity(sev)
489
+ },
490
+ sev
491
+ )) })
492
+ ] }),
493
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: { marginBottom: 14 }, children: [
494
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(FieldLabel, { colors, htmlFor: "flint-description", children: t("whatIsBrokenLabel") }),
495
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
496
+ "textarea",
497
+ {
498
+ id: "flint-description",
499
+ style: { ...inputStyle, resize: "vertical", minHeight: 80 },
500
+ value: description,
501
+ onChange: (e) => setDescription(e.target.value),
502
+ placeholder: t("whatIsBrokenPlaceholder"),
503
+ required: true
504
+ }
505
+ )
506
+ ] }),
507
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: { marginBottom: 14 }, children: [
508
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(FieldLabel, { colors, htmlFor: "flint-expected", children: t("expectedBehaviorLabel") }),
509
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
510
+ "textarea",
511
+ {
512
+ id: "flint-expected",
513
+ style: { ...inputStyle, resize: "vertical", minHeight: 72 },
514
+ value: expectedBehavior,
515
+ onChange: (e) => setExpectedBehavior(e.target.value),
516
+ placeholder: t("expectedBehaviorPlaceholder")
517
+ }
518
+ )
519
+ ] }),
520
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: { marginBottom: 20 }, children: [
521
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(FieldLabel, { colors, children: t("screenshotLabel") }),
522
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
523
+ "label",
524
+ {
525
+ htmlFor: "flint-screenshot",
526
+ style: {
527
+ display: "flex",
528
+ alignItems: "center",
529
+ gap: 8,
530
+ padding: "10px 13px",
531
+ borderRadius: 10,
532
+ border: `1px dashed ${inputBorder}`,
533
+ cursor: "pointer",
534
+ fontSize: 13,
535
+ color: colors.textMuted,
536
+ background: colors.backgroundSecondary
537
+ },
538
+ children: [
539
+ "\u{1F4CE} ",
540
+ screenshot ? screenshot.name : t("screenshotPlaceholder")
541
+ ]
542
+ }
543
+ ),
544
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
545
+ "input",
546
+ {
547
+ id: "flint-screenshot",
548
+ ref: fileRef,
549
+ type: "file",
550
+ accept: "image/*",
551
+ style: { display: "none" },
552
+ onChange: (e) => setScreenshot(e.target.files?.[0] ?? null)
553
+ }
554
+ )
555
+ ] }),
556
+ status === "error" && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: {
557
+ padding: "10px 13px",
558
+ borderRadius: 10,
559
+ background: "rgba(239,68,68,0.08)",
560
+ border: "1px solid rgba(239,68,68,0.2)",
561
+ color: "#f87171",
562
+ fontSize: 12,
563
+ marginBottom: 16
564
+ }, children: [
565
+ "\u26A0\uFE0F ",
566
+ errorMsg || t("errorLabel")
567
+ ] }),
568
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
569
+ "button",
570
+ {
571
+ type: "submit",
572
+ style: {
573
+ width: "100%",
574
+ padding: "13px 20px",
575
+ borderRadius: 12,
576
+ border: "none",
577
+ background: `linear-gradient(135deg, ${colors.accent}, ${colors.accentHover})`,
578
+ color: colors.buttonText,
579
+ fontSize: 15,
580
+ fontWeight: 700,
581
+ cursor: "pointer",
582
+ letterSpacing: "-0.01em",
583
+ boxShadow: accentGlow,
584
+ fontFamily: "inherit",
585
+ display: "flex",
586
+ alignItems: "center",
587
+ justifyContent: "center",
588
+ gap: 8
589
+ },
590
+ children: [
591
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(SparkIcon, { color: colors.buttonText, size: 15 }),
592
+ t("submitLabel")
593
+ ]
594
+ }
595
+ ),
596
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
597
+ "button",
598
+ {
599
+ type: "button",
600
+ onClick: onClose,
601
+ style: {
602
+ width: "100%",
603
+ padding: "10px",
604
+ marginTop: 8,
605
+ background: "none",
606
+ border: "none",
607
+ cursor: "pointer",
608
+ fontSize: 13,
609
+ color: colors.textMuted,
610
+ fontFamily: "inherit",
611
+ borderRadius: 8
612
+ },
613
+ children: t("cancel")
614
+ }
615
+ )
616
+ ] })
617
+ ] }) });
618
+ }
619
+ function ModalHeader({
620
+ colors,
621
+ inputBorder,
622
+ showClose,
623
+ onClose,
624
+ titleId,
625
+ title
626
+ }) {
627
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: {
628
+ display: "flex",
629
+ alignItems: "center",
630
+ gap: 10,
631
+ padding: "16px 20px 14px",
632
+ borderBottom: `1px solid ${inputBorder}`
633
+ }, children: [
634
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: {
635
+ width: 28,
636
+ height: 28,
637
+ borderRadius: 8,
638
+ background: `linear-gradient(135deg, ${colors.accent}20, ${colors.accentHover}35)`,
639
+ border: `1px solid ${colors.accent}30`,
640
+ display: "flex",
641
+ alignItems: "center",
642
+ justifyContent: "center",
643
+ flexShrink: 0
644
+ }, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(SparkIcon, { color: colors.accent, size: 13 }) }),
645
+ titleId && title ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("h2", { id: titleId, style: { margin: 0, fontSize: 14, fontWeight: 600, color: colors.text, letterSpacing: "-0.01em", flex: 1 }, children: title }) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { style: { flex: 1, fontSize: 13, fontWeight: 600, color: colors.textMuted }, children: "Flint" }),
646
+ showClose && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
647
+ "button",
648
+ {
649
+ onClick: onClose,
650
+ "aria-label": "Close",
651
+ style: {
652
+ background: "none",
653
+ border: "none",
654
+ cursor: "pointer",
655
+ padding: 4,
656
+ color: colors.textMuted,
657
+ fontSize: 20,
658
+ lineHeight: 1,
659
+ borderRadius: 6,
660
+ display: "flex",
661
+ alignItems: "center",
662
+ justifyContent: "center",
663
+ opacity: 0.6,
664
+ fontFamily: "inherit"
665
+ },
666
+ children: "\xD7"
667
+ }
668
+ )
669
+ ] });
670
+ }
671
+ function FieldLabel({
672
+ children,
673
+ colors,
674
+ htmlFor
675
+ }) {
676
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
677
+ "label",
678
+ {
679
+ htmlFor,
680
+ style: {
681
+ display: "block",
682
+ fontSize: "10px",
683
+ fontWeight: 700,
684
+ color: colors.textMuted,
685
+ marginBottom: 6,
686
+ textTransform: "uppercase",
687
+ letterSpacing: "0.07em"
688
+ },
689
+ children
690
+ }
691
+ );
692
+ }
693
+ function SendingDots({ color }) {
694
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { style: { display: "inline-flex", gap: 3, alignItems: "center" }, children: [0, 1, 2].map((i) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
695
+ "span",
696
+ {
697
+ style: {
698
+ width: 4,
699
+ height: 4,
700
+ borderRadius: "50%",
701
+ background: color,
702
+ display: "inline-block",
703
+ animation: `_flint_sending_dot 1.4s ease-in-out infinite ${i * 0.2}s`
704
+ }
705
+ },
706
+ i
707
+ )) });
708
+ }
709
+ function SeverityButton({ sev, label, selected, hint, color, accent, border, bg, text, onClick }) {
710
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
711
+ "button",
712
+ {
713
+ type: "button",
714
+ title: hint,
715
+ onClick,
716
+ style: {
717
+ padding: "9px 6px 8px",
718
+ borderRadius: 10,
719
+ border: selected ? `2px solid ${accent}` : `1.5px solid ${border}`,
720
+ background: selected ? `${accent}15` : bg,
721
+ cursor: "pointer",
722
+ display: "flex",
723
+ flexDirection: "column",
724
+ alignItems: "center",
725
+ gap: 5,
726
+ transition: "border-color 0.12s, background 0.12s",
727
+ fontFamily: "inherit"
728
+ },
729
+ children: [
730
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { style: { width: 8, height: 8, borderRadius: "50%", background: color, display: "block" } }),
731
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { style: { fontSize: 11, fontWeight: selected ? 700 : 500, color: selected ? accent : text, letterSpacing: "0.02em" }, children: sev }),
732
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { style: { fontSize: 9, color: selected ? accent : text, opacity: 0.6, letterSpacing: "0.02em" }, children: label })
733
+ ]
734
+ }
735
+ );
736
+ }
737
+ function SparkIcon({ color = "currentColor", size = 14 }) {
738
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("svg", { width: size, height: size, viewBox: "0 0 24 24", fill: "none", stroke: color, strokeWidth: "2.2", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M13 2L3 14h9l-1 8 10-12h-9l1-8z" }) });
739
+ }
740
+ function CheckIcon({ size = 20 }) {
741
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("svg", { width: size, height: size, viewBox: "0 0 24 24", fill: "none", stroke: "#22c55e", strokeWidth: "2.5", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("polyline", { points: "20 6 9 17 4 12" }) });
742
+ }
743
+
744
+ // src/i18n/index.ts
745
+ var import_i18next = require("i18next");
746
+ var import_react_i18next2 = require("react-i18next");
747
+
748
+ // src/i18n/locales/en.json
749
+ var en_default = {
750
+ buttonLabel: "Report bug",
751
+ modalTitle: "Report an issue",
752
+ severityLabel: "Severity",
753
+ severity_P1_hint: "Critical \u2014 system down",
754
+ severity_P2_hint: "High \u2014 core feature broken",
755
+ severity_P3_hint: "Medium \u2014 noticeable but workable",
756
+ severity_P4_hint: "Low \u2014 cosmetic or improvement",
757
+ severity_P1_label: "Critical",
758
+ severity_P2_label: "High",
759
+ severity_P3_label: "Medium",
760
+ severity_P4_label: "Low",
761
+ whatIsBrokenLabel: "What Is Broken",
762
+ whatIsBrokenPlaceholder: "1\u20132 sentences: what is currently happening that should NOT happen.",
763
+ expectedBehaviorLabel: "Expected Behavior (optional)",
764
+ expectedBehaviorPlaceholder: "Describe exactly what the user should see or receive after the fix.",
765
+ screenshotLabel: "Screenshot (optional)",
766
+ screenshotPlaceholder: "Click to attach...",
767
+ submitLabel: "Submit",
768
+ successTitle: "Bug reported!",
769
+ successDuplicate: "Looks like a duplicate of an existing bug.",
770
+ successGitHub: "View GitHub issue",
771
+ errorLabel: "Failed to submit. Please try again.",
772
+ cancel: "Cancel",
773
+ sending: "Sending report",
774
+ capturingContext: "Capturing context"
775
+ };
776
+
777
+ // src/i18n/index.ts
778
+ var widgetI18n = (0, import_i18next.createInstance)();
779
+ widgetI18n.use(import_react_i18next2.initReactI18next).init({
780
+ lng: "en-US",
781
+ fallbackLng: "en-US",
782
+ resources: { "en-US": { translation: en_default } },
783
+ interpolation: { escapeValue: false },
784
+ initImmediate: false
785
+ });
786
+ var i18n_default = widgetI18n;
787
+
788
+ // src/collectors/environment.ts
789
+ function collectEnvironment() {
790
+ const ua = navigator.userAgent;
791
+ let browser = "Unknown";
792
+ const chromeM = ua.match(/Chrome\/(\d+)/);
793
+ const firefoxM = ua.match(/Firefox\/(\d+)/);
794
+ const edgeM = ua.match(/Edg\/(\d+)/);
795
+ const safariM = ua.match(/Version\/(\d+)/);
796
+ const operaM = ua.match(/OPR\/(\d+)/);
797
+ if (operaM) {
798
+ browser = `Opera ${operaM[1]}`;
799
+ } else if (edgeM) {
800
+ browser = `Edge ${edgeM[1]}`;
801
+ } else if (chromeM && !/Edg|OPR/.test(ua)) {
802
+ browser = `Chrome ${chromeM[1]}`;
803
+ } else if (firefoxM) {
804
+ browser = `Firefox ${firefoxM[1]}`;
805
+ } else if (safariM && /Safari\//.test(ua)) {
806
+ browser = `Safari ${safariM[1]}`;
807
+ }
808
+ let os = "Unknown";
809
+ const macM = ua.match(/Mac OS X (\d+[._]\d+)/);
810
+ const winM = ua.match(/Windows NT (\d+\.\d+)/);
811
+ const androidM = ua.match(/Android (\d+)/);
812
+ const iosM = ua.match(/iPhone OS (\d+[._]\d+)/);
813
+ if (macM) {
814
+ os = `macOS ${macM[1].replace("_", ".")}`;
815
+ } else if (winM) {
816
+ const winMap = {
817
+ "10.0": "10/11",
818
+ "6.3": "8.1",
819
+ "6.2": "8",
820
+ "6.1": "7"
821
+ };
822
+ os = `Windows ${winMap[winM[1]] ?? winM[1]}`;
823
+ } else if (androidM) {
824
+ os = `Android ${androidM[1]}`;
825
+ } else if (iosM) {
826
+ os = `iOS ${iosM[1].replace(/_/g, ".")}`;
827
+ } else if (/Linux/.test(ua)) {
828
+ os = "Linux";
829
+ }
830
+ return {
831
+ browser,
832
+ os,
833
+ viewport: `${window.innerWidth}x${window.innerHeight}`,
834
+ screen: `${screen.width}x${screen.height}`,
835
+ language: navigator.language,
836
+ timezone: Intl.DateTimeFormat().resolvedOptions().timeZone,
837
+ online: navigator.onLine
838
+ };
839
+ }
840
+
841
+ // src/collectors/console.ts
842
+ var MAX_ENTRIES = 50;
843
+ function createConsoleCollector() {
844
+ const entries = [];
845
+ let active = false;
846
+ const originals = {
847
+ log: console.log.bind(console),
848
+ warn: console.warn.bind(console),
849
+ error: console.error.bind(console)
850
+ };
851
+ let origOnerror = null;
852
+ let origUnhandled = null;
853
+ function push(level, args) {
854
+ let str;
855
+ try {
856
+ str = args.map((a) => typeof a === "string" ? a : JSON.stringify(a)).join(" ");
857
+ } catch {
858
+ str = String(args[0]);
859
+ }
860
+ if (str.length > 500) str = str.slice(0, 500) + "\u2026";
861
+ entries.push({ level, args: str, timestamp: Date.now() });
862
+ if (entries.length > MAX_ENTRIES) entries.shift();
863
+ }
864
+ return {
865
+ start() {
866
+ if (active) return;
867
+ active = true;
868
+ console.log = (...args) => {
869
+ push("log", args);
870
+ originals.log(...args);
871
+ };
872
+ console.warn = (...args) => {
873
+ push("warn", args);
874
+ originals.warn(...args);
875
+ };
876
+ console.error = (...args) => {
877
+ push("error", args);
878
+ originals.error(...args);
879
+ };
880
+ origOnerror = window.onerror;
881
+ window.onerror = (msg, src, line, col, err) => {
882
+ push("error", [err?.message ?? String(msg), `${src}:${line}:${col}`]);
883
+ if (typeof origOnerror === "function")
884
+ return origOnerror(msg, src, line, col, err);
885
+ return false;
886
+ };
887
+ origUnhandled = window.onunhandledrejection;
888
+ window.onunhandledrejection = (event) => {
889
+ const reason = event.reason instanceof Error ? event.reason.message : JSON.stringify(event.reason);
890
+ push("error", ["UnhandledRejection:", reason]);
891
+ if (typeof origUnhandled === "function")
892
+ origUnhandled.call(window, event);
893
+ };
894
+ },
895
+ stop() {
896
+ if (!active) return;
897
+ active = false;
898
+ console.log = originals.log;
899
+ console.warn = originals.warn;
900
+ console.error = originals.error;
901
+ window.onerror = origOnerror;
902
+ window.onunhandledrejection = origUnhandled;
903
+ },
904
+ getEntries() {
905
+ return [...entries];
906
+ }
907
+ };
908
+ }
909
+
910
+ // src/collectors/network.ts
911
+ var MAX_ENTRIES2 = 20;
912
+ function truncateUrl(url) {
913
+ try {
914
+ const u = new URL(url, location.href);
915
+ const base = `${u.origin}${u.pathname}`;
916
+ return base.length > 200 ? base.slice(0, 200) + "\u2026" : base;
917
+ } catch {
918
+ return url.length > 200 ? url.slice(0, 200) + "\u2026" : url;
919
+ }
920
+ }
921
+ function createNetworkCollector() {
922
+ const entries = [];
923
+ let origFetch = null;
924
+ let origXHROpen = null;
925
+ let active = false;
926
+ function push(entry) {
927
+ entries.push(entry);
928
+ if (entries.length > MAX_ENTRIES2) entries.shift();
929
+ }
930
+ return {
931
+ start() {
932
+ if (active) return;
933
+ active = true;
934
+ origFetch = window.fetch;
935
+ window.fetch = async (input, init) => {
936
+ const method = (init?.method ?? "GET").toUpperCase();
937
+ const url = typeof input === "string" ? input : input instanceof URL ? input.href : input.url;
938
+ const startTime = Date.now();
939
+ const res = await origFetch.call(window, input, init);
940
+ push({
941
+ method,
942
+ url: truncateUrl(url),
943
+ status: res.status,
944
+ duration: Date.now() - startTime,
945
+ timestamp: startTime
946
+ });
947
+ return res;
948
+ };
949
+ origXHROpen = XMLHttpRequest.prototype.open;
950
+ XMLHttpRequest.prototype.open = function(method, url, async, username, password) {
951
+ const startTime = Date.now();
952
+ const urlStr = typeof url === "string" ? url : url.href;
953
+ this.addEventListener("load", () => {
954
+ push({
955
+ method: method.toUpperCase(),
956
+ url: truncateUrl(urlStr),
957
+ status: this.status,
958
+ duration: Date.now() - startTime,
959
+ timestamp: startTime
960
+ });
961
+ });
962
+ return origXHROpen.apply(this, [
963
+ method,
964
+ url,
965
+ async ?? true,
966
+ username,
967
+ password
968
+ ]);
969
+ };
970
+ },
971
+ stop() {
972
+ if (!active) return;
973
+ active = false;
974
+ if (origFetch) window.fetch = origFetch;
975
+ if (origXHROpen) XMLHttpRequest.prototype.open = origXHROpen;
976
+ },
977
+ getEntries() {
978
+ return [...entries];
979
+ }
980
+ };
981
+ }
982
+
983
+ // src/FlintWidget.tsx
984
+ var import_rrweb = require("rrweb");
985
+ var import_jsx_runtime2 = require("react/jsx-runtime");
986
+ var REPLAY_WINDOW_MS = 6e4;
987
+ function FlintWidget(props) {
988
+ const { locale = "en-US" } = props;
989
+ (0, import_react2.useEffect)(() => {
990
+ i18n_default.changeLanguage(locale);
991
+ }, [locale]);
992
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_i18next3.I18nextProvider, { i18n: i18n_default, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(WidgetContent, { ...props }) });
993
+ }
994
+ function WidgetContent({
995
+ projectKey,
996
+ serverUrl,
997
+ user,
998
+ meta,
999
+ extraFields,
1000
+ buttonLabel,
1001
+ theme = "dark",
1002
+ zIndex = 9999
1003
+ }) {
1004
+ const externalReplayUrl = extraFields?.sessionReplay;
1005
+ const { t } = (0, import_react_i18next3.useTranslation)();
1006
+ const [open, setOpen] = (0, import_react2.useState)(false);
1007
+ const [hovered, setHovered] = (0, import_react2.useState)(false);
1008
+ const colors = resolveTheme(theme);
1009
+ const consoleCollector = (0, import_react2.useRef)(null);
1010
+ const networkCollector = (0, import_react2.useRef)(null);
1011
+ const replayEvents = (0, import_react2.useRef)([]);
1012
+ const stopReplay = (0, import_react2.useRef)(null);
1013
+ if (!consoleCollector.current) {
1014
+ consoleCollector.current = createConsoleCollector();
1015
+ consoleCollector.current.start();
1016
+ }
1017
+ if (!networkCollector.current) {
1018
+ networkCollector.current = createNetworkCollector();
1019
+ networkCollector.current.start();
1020
+ }
1021
+ (0, import_react2.useEffect)(() => {
1022
+ const stopFn = (0, import_rrweb.record)({
1023
+ emit(event) {
1024
+ replayEvents.current.push(event);
1025
+ const cutoff = Date.now() - REPLAY_WINDOW_MS;
1026
+ while (replayEvents.current.length > 0 && replayEvents.current[0].timestamp < cutoff) {
1027
+ replayEvents.current.shift();
1028
+ }
1029
+ }
1030
+ });
1031
+ stopReplay.current = stopFn ?? null;
1032
+ return () => {
1033
+ consoleCollector.current?.stop();
1034
+ networkCollector.current?.stop();
1035
+ stopReplay.current?.();
1036
+ };
1037
+ }, []);
1038
+ const label = buttonLabel ?? t("buttonLabel");
1039
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_jsx_runtime2.Fragment, { children: [
1040
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
1041
+ "button",
1042
+ {
1043
+ onClick: () => setOpen(true),
1044
+ onMouseEnter: () => setHovered(true),
1045
+ onMouseLeave: () => setHovered(false),
1046
+ "aria-label": label,
1047
+ style: {
1048
+ position: "fixed",
1049
+ bottom: "20px",
1050
+ right: "20px",
1051
+ zIndex: zIndex - 1,
1052
+ display: "flex",
1053
+ alignItems: "center",
1054
+ gap: "8px",
1055
+ padding: "10px 18px",
1056
+ borderRadius: "24px",
1057
+ border: "none",
1058
+ background: `linear-gradient(135deg, ${colors.accent}, ${colors.accentHover})`,
1059
+ color: colors.buttonText,
1060
+ fontSize: "13px",
1061
+ fontWeight: 600,
1062
+ cursor: "pointer",
1063
+ boxShadow: hovered ? `0 0 28px ${colors.accent}55, 0 8px 24px rgba(0,0,0,0.3)` : `0 0 16px ${colors.accent}33, 0 4px 16px rgba(0,0,0,0.2)`,
1064
+ fontFamily: '-apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif',
1065
+ transform: hovered ? "translateY(-2px)" : "translateY(0)",
1066
+ transition: "transform 0.15s ease, box-shadow 0.15s ease",
1067
+ letterSpacing: "0.01em"
1068
+ },
1069
+ children: [
1070
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(SparkIcon2, {}),
1071
+ label
1072
+ ]
1073
+ }
1074
+ ),
1075
+ open && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
1076
+ FlintModal,
1077
+ {
1078
+ projectKey,
1079
+ serverUrl,
1080
+ user,
1081
+ meta,
1082
+ theme,
1083
+ zIndex,
1084
+ onClose: () => setOpen(false),
1085
+ getEnvironment: collectEnvironment,
1086
+ getConsoleLogs: () => consoleCollector.current?.getEntries() ?? [],
1087
+ getNetworkErrors: () => networkCollector.current?.getEntries() ?? [],
1088
+ getReplayEvents: () => [...replayEvents.current],
1089
+ externalReplayUrl
1090
+ }
1091
+ )
1092
+ ] });
1093
+ }
1094
+ function SparkIcon2() {
1095
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
1096
+ "svg",
1097
+ {
1098
+ width: "14",
1099
+ height: "14",
1100
+ viewBox: "0 0 24 24",
1101
+ fill: "none",
1102
+ stroke: "currentColor",
1103
+ strokeWidth: "2.2",
1104
+ strokeLinecap: "round",
1105
+ strokeLinejoin: "round",
1106
+ "aria-hidden": "true",
1107
+ children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("path", { d: "M13 2L3 14h9l-1 8 10-12h-9l1-8z" })
1108
+ }
1109
+ );
1110
+ }
1111
+ // Annotate the CommonJS export names for ESM import in node:
1112
+ 0 && (module.exports = {
1113
+ FlintModal,
1114
+ FlintWidget
1115
+ });
1116
+ //# sourceMappingURL=index.cjs.map