@diegotsi/flint-react 0.1.2 → 0.1.5

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.d.ts CHANGED
@@ -1,10 +1,507 @@
1
1
  import * as react_jsx_runtime from 'react/jsx-runtime';
2
- import { FlintWidgetProps, FlintUser, Theme, EnvironmentInfo, ConsoleEntry, NetworkEntry } from '@flint/types';
3
- export { FlintUser, FlintWidgetProps, Locale, ReportPayload, ReportResult, Severity, Theme, ThemeOverride } from '@flint/types';
4
- import { eventWithTime } from '@rrweb/types';
2
+
3
+ type Severity = "P1" | "P2" | "P3" | "P4";
4
+ interface EnvironmentInfo {
5
+ browser: string;
6
+ os: string;
7
+ viewport: string;
8
+ screen: string;
9
+ language: string;
10
+ timezone: string;
11
+ online: boolean;
12
+ }
13
+ interface ConsoleEntry {
14
+ level: "log" | "warn" | "error";
15
+ args: string;
16
+ timestamp: number;
17
+ }
18
+ interface NetworkEntry {
19
+ method: string;
20
+ url: string;
21
+ status: number;
22
+ duration: number;
23
+ timestamp: number;
24
+ }
25
+ type Locale = "pt-BR" | "en-US";
26
+ type Theme = "light" | "dark" | ThemeOverride;
27
+ interface ThemeOverride {
28
+ background?: string;
29
+ accent?: string;
30
+ text?: string;
31
+ border?: string;
32
+ }
33
+ interface FlintUser {
34
+ id: string;
35
+ name: string;
36
+ }
37
+ interface FlintExtraFields {
38
+ /** Session replay URL from Datadog RUM, FullStory, LogRocket, etc. Pass a function for lazy evaluation. */
39
+ sessionReplay?: string | (() => string);
40
+ [key: string]: unknown;
41
+ }
42
+ interface FlintWidgetProps {
43
+ /** Project API key — get this from the flint-server admin API */
44
+ projectKey: string;
45
+ /** Full URL of the flint-server, e.g. "https://bugs.example.com" */
46
+ serverUrl: string;
47
+ /** Authenticated user info (optional) */
48
+ user?: FlintUser;
49
+ /** Arbitrary metadata to attach to every report */
50
+ meta?: Record<string, unknown>;
51
+ /** Extra fields for developer use (e.g. external session replay URL) */
52
+ extraFields?: FlintExtraFields;
53
+ /** Label shown on the trigger button. Default: "Reportar bug" */
54
+ buttonLabel?: string;
55
+ /** Locale for UI strings. Default: "pt-BR" */
56
+ locale?: Locale;
57
+ /** Visual theme. Default: "light" */
58
+ theme?: Theme;
59
+ /** Custom z-index for the widget. Default: 9999 */
60
+ zIndex?: number;
61
+ }
62
+ interface ReportPayload {
63
+ reporterId: string;
64
+ reporterName: string;
65
+ description: string;
66
+ expectedBehavior?: string;
67
+ stepsToReproduce?: {
68
+ action: string;
69
+ result: string;
70
+ }[];
71
+ externalReplayUrl?: string;
72
+ additionalContext?: string;
73
+ severity: Severity;
74
+ url?: string;
75
+ meta?: Record<string, unknown>;
76
+ }
77
+ interface ReportResult {
78
+ id: string;
79
+ status: string;
80
+ githubIssueUrl?: string | null;
81
+ slackMessageUrl?: string | null;
82
+ isDuplicate: boolean;
83
+ duplicateOfId?: string | null;
84
+ }
5
85
 
6
86
  declare function FlintWidget(props: FlintWidgetProps): react_jsx_runtime.JSX.Element;
7
87
 
88
+ declare type addedNodeMutation = {
89
+ parentId: number;
90
+ previousId?: number | null;
91
+ nextId: number | null;
92
+ node: serializedNodeWithId;
93
+ };
94
+
95
+ declare type adoptedStyleSheetData = {
96
+ source: IncrementalSource.AdoptedStyleSheet;
97
+ } & adoptedStyleSheetParam;
98
+
99
+ declare type adoptedStyleSheetParam = {
100
+ id: number;
101
+ styles?: {
102
+ styleId: number;
103
+ rules: styleSheetAddRule[];
104
+ }[];
105
+ styleIds: number[];
106
+ };
107
+
108
+ declare type attributeMutation = {
109
+ id: number;
110
+ attributes: {
111
+ [key: string]: string | styleOMValue | null;
112
+ };
113
+ };
114
+
115
+ declare type attributes = cssTextKeyAttr & {
116
+ [key: string]: string | number | true | null;
117
+ };
118
+
119
+ declare enum CanvasContext {
120
+ '2D' = 0,
121
+ WebGL = 1,
122
+ WebGL2 = 2
123
+ }
124
+
125
+ declare type canvasMutationCommand = {
126
+ property: string;
127
+ args: Array<unknown>;
128
+ setter?: true;
129
+ };
130
+
131
+ declare type canvasMutationData = {
132
+ source: IncrementalSource.CanvasMutation;
133
+ } & canvasMutationParam;
134
+
135
+ declare type canvasMutationParam = {
136
+ id: number;
137
+ type: CanvasContext;
138
+ commands: canvasMutationCommand[];
139
+ } | ({
140
+ id: number;
141
+ type: CanvasContext;
142
+ } & canvasMutationCommand);
143
+
144
+ declare type cdataNode = {
145
+ type: NodeType.CDATA;
146
+ textContent: '';
147
+ };
148
+
149
+ declare type commentNode = {
150
+ type: NodeType.Comment;
151
+ textContent: string;
152
+ };
153
+
154
+ declare type cssTextKeyAttr = {
155
+ _cssText?: string;
156
+ };
157
+
158
+ declare type customElementData = {
159
+ source: IncrementalSource.CustomElement;
160
+ } & customElementParam;
161
+
162
+ declare type customElementParam = {
163
+ define?: {
164
+ name: string;
165
+ };
166
+ };
167
+
168
+ declare type customEvent<T = unknown> = {
169
+ type: EventType.Custom;
170
+ data: {
171
+ tag: string;
172
+ payload: T;
173
+ };
174
+ };
175
+
176
+ declare type documentNode = {
177
+ type: NodeType.Document;
178
+ childNodes: serializedNodeWithId[];
179
+ compatMode?: string;
180
+ };
181
+
182
+ declare type documentTypeNode = {
183
+ type: NodeType.DocumentType;
184
+ name: string;
185
+ publicId: string;
186
+ systemId: string;
187
+ };
188
+
189
+ declare type domContentLoadedEvent = {
190
+ type: EventType.DomContentLoaded;
191
+ data: unknown;
192
+ };
193
+
194
+ declare type elementNode = {
195
+ type: NodeType.Element;
196
+ tagName: string;
197
+ attributes: attributes;
198
+ childNodes: serializedNodeWithId[];
199
+ isSVG?: true;
200
+ needBlock?: boolean;
201
+ isCustom?: true;
202
+ };
203
+
204
+ declare enum EventType {
205
+ DomContentLoaded = 0,
206
+ Load = 1,
207
+ FullSnapshot = 2,
208
+ IncrementalSnapshot = 3,
209
+ Meta = 4,
210
+ Custom = 5,
211
+ Plugin = 6
212
+ }
213
+
214
+ declare type eventWithoutTime = domContentLoadedEvent | loadedEvent | fullSnapshotEvent | incrementalSnapshotEvent | metaEvent | customEvent | pluginEvent;
215
+
216
+ declare type eventWithTime = eventWithoutTime & {
217
+ timestamp: number;
218
+ delay?: number;
219
+ };
220
+
221
+ declare type fontData = {
222
+ source: IncrementalSource.Font;
223
+ } & fontParam;
224
+
225
+ declare type fontParam = {
226
+ family: string;
227
+ fontSource: string;
228
+ buffer: boolean;
229
+ descriptors?: FontFaceDescriptors;
230
+ };
231
+
232
+ declare type fullSnapshotEvent = {
233
+ type: EventType.FullSnapshot;
234
+ data: {
235
+ node: serializedNodeWithId;
236
+ initialOffset: {
237
+ top: number;
238
+ left: number;
239
+ };
240
+ };
241
+ };
242
+
243
+ declare type incrementalData = mutationData | mousemoveData | mouseInteractionData | scrollData | viewportResizeData | inputData | mediaInteractionData | styleSheetRuleData | canvasMutationData | fontData | selectionData | styleDeclarationData | adoptedStyleSheetData | customElementData;
244
+
245
+ declare type incrementalSnapshotEvent = {
246
+ type: EventType.IncrementalSnapshot;
247
+ data: incrementalData;
248
+ };
249
+
250
+ declare enum IncrementalSource {
251
+ Mutation = 0,
252
+ MouseMove = 1,
253
+ MouseInteraction = 2,
254
+ Scroll = 3,
255
+ ViewportResize = 4,
256
+ Input = 5,
257
+ TouchMove = 6,
258
+ MediaInteraction = 7,
259
+ StyleSheetRule = 8,
260
+ CanvasMutation = 9,
261
+ Font = 10,
262
+ Log = 11,
263
+ Drag = 12,
264
+ StyleDeclaration = 13,
265
+ Selection = 14,
266
+ AdoptedStyleSheet = 15,
267
+ CustomElement = 16
268
+ }
269
+
270
+ declare type inputData = {
271
+ source: IncrementalSource.Input;
272
+ id: number;
273
+ } & inputValue;
274
+
275
+ declare type inputValue = {
276
+ text: string;
277
+ isChecked: boolean;
278
+ userTriggered?: boolean;
279
+ };
280
+
281
+ declare type loadedEvent = {
282
+ type: EventType.Load;
283
+ data: unknown;
284
+ };
285
+
286
+ declare type mediaInteractionData = {
287
+ source: IncrementalSource.MediaInteraction;
288
+ } & mediaInteractionParam;
289
+
290
+ declare type mediaInteractionParam = {
291
+ type: MediaInteractions;
292
+ id: number;
293
+ currentTime?: number;
294
+ volume?: number;
295
+ muted?: boolean;
296
+ loop?: boolean;
297
+ playbackRate?: number;
298
+ };
299
+
300
+ declare enum MediaInteractions {
301
+ Play = 0,
302
+ Pause = 1,
303
+ Seeked = 2,
304
+ VolumeChange = 3,
305
+ RateChange = 4
306
+ }
307
+
308
+ declare type metaEvent = {
309
+ type: EventType.Meta;
310
+ data: {
311
+ href: string;
312
+ width: number;
313
+ height: number;
314
+ };
315
+ };
316
+
317
+ declare type mouseInteractionData = {
318
+ source: IncrementalSource.MouseInteraction;
319
+ } & mouseInteractionParam;
320
+
321
+ declare type mouseInteractionParam = {
322
+ type: MouseInteractions;
323
+ id: number;
324
+ x?: number;
325
+ y?: number;
326
+ pointerType?: PointerTypes;
327
+ };
328
+
329
+ declare enum MouseInteractions {
330
+ MouseUp = 0,
331
+ MouseDown = 1,
332
+ Click = 2,
333
+ ContextMenu = 3,
334
+ DblClick = 4,
335
+ Focus = 5,
336
+ Blur = 6,
337
+ TouchStart = 7,
338
+ TouchMove_Departed = 8,
339
+ TouchEnd = 9,
340
+ TouchCancel = 10
341
+ }
342
+
343
+ declare type mousemoveData = {
344
+ source: IncrementalSource.MouseMove | IncrementalSource.TouchMove | IncrementalSource.Drag;
345
+ positions: mousePosition[];
346
+ };
347
+
348
+ declare type mousePosition = {
349
+ x: number;
350
+ y: number;
351
+ id: number;
352
+ timeOffset: number;
353
+ };
354
+
355
+ declare type mutationCallbackParam = {
356
+ texts: textMutation[];
357
+ attributes: attributeMutation[];
358
+ removes: removedNodeMutation[];
359
+ adds: addedNodeMutation[];
360
+ isAttachIframe?: true;
361
+ };
362
+
363
+ declare type mutationData = {
364
+ source: IncrementalSource.Mutation;
365
+ } & mutationCallbackParam;
366
+
367
+ declare enum NodeType {
368
+ Document = 0,
369
+ DocumentType = 1,
370
+ Element = 2,
371
+ Text = 3,
372
+ CDATA = 4,
373
+ Comment = 5
374
+ }
375
+
376
+ declare type pluginEvent<T = unknown> = {
377
+ type: EventType.Plugin;
378
+ data: {
379
+ plugin: string;
380
+ payload: T;
381
+ };
382
+ };
383
+
384
+ declare enum PointerTypes {
385
+ Mouse = 0,
386
+ Pen = 1,
387
+ Touch = 2
388
+ }
389
+
390
+ declare type removedNodeMutation = {
391
+ parentId: number;
392
+ id: number;
393
+ isShadow?: boolean;
394
+ };
395
+
396
+ declare type scrollData = {
397
+ source: IncrementalSource.Scroll;
398
+ } & scrollPosition;
399
+
400
+ declare type scrollPosition = {
401
+ id: number;
402
+ x: number;
403
+ y: number;
404
+ };
405
+
406
+ declare type selectionData = {
407
+ source: IncrementalSource.Selection;
408
+ } & selectionParam;
409
+
410
+ declare type selectionParam = {
411
+ ranges: Array<SelectionRange>;
412
+ };
413
+
414
+ declare type SelectionRange = {
415
+ start: number;
416
+ startOffset: number;
417
+ end: number;
418
+ endOffset: number;
419
+ };
420
+
421
+ declare type serializedNode = (documentNode | documentTypeNode | elementNode | textNode | cdataNode | commentNode) & {
422
+ rootId?: number;
423
+ isShadowHost?: boolean;
424
+ isShadow?: boolean;
425
+ };
426
+
427
+ declare type serializedNodeWithId = serializedNode & {
428
+ id: number;
429
+ };
430
+
431
+ declare type styleDeclarationData = {
432
+ source: IncrementalSource.StyleDeclaration;
433
+ } & styleDeclarationParam;
434
+
435
+ declare type styleDeclarationParam = {
436
+ id?: number;
437
+ styleId?: number;
438
+ index: number[];
439
+ set?: {
440
+ property: string;
441
+ value: string | null;
442
+ priority: string | undefined;
443
+ };
444
+ remove?: {
445
+ property: string;
446
+ };
447
+ };
448
+
449
+ declare type styleOMValue = {
450
+ [key: string]: styleValueWithPriority | string | false;
451
+ };
452
+
453
+ declare type styleSheetAddRule = {
454
+ rule: string;
455
+ index?: number | number[];
456
+ };
457
+
458
+ declare type styleSheetDeleteRule = {
459
+ index: number | number[];
460
+ };
461
+
462
+ declare type styleSheetRuleData = {
463
+ source: IncrementalSource.StyleSheetRule;
464
+ } & styleSheetRuleParam;
465
+
466
+ declare type styleSheetRuleParam = {
467
+ id?: number;
468
+ styleId?: number;
469
+ removes?: styleSheetDeleteRule[];
470
+ adds?: styleSheetAddRule[];
471
+ replace?: string;
472
+ replaceSync?: string;
473
+ };
474
+
475
+ declare type styleValueWithPriority = [string, string];
476
+
477
+ declare type textMutation = {
478
+ id: number;
479
+ value: string | null;
480
+ };
481
+
482
+ declare type textNode = {
483
+ type: NodeType.Text;
484
+ textContent: string;
485
+ isStyle?: true;
486
+ };
487
+
488
+ declare type viewportResizeData = {
489
+ source: IncrementalSource.ViewportResize;
490
+ } & viewportResizeDimension;
491
+
492
+ declare type viewportResizeDimension = {
493
+ width: number;
494
+ height: number;
495
+ };
496
+
497
+
498
+
499
+ declare global {
500
+ interface Window {
501
+ FontFace: typeof FontFace;
502
+ }
503
+ }
504
+
8
505
  interface Props {
9
506
  projectKey: string;
10
507
  serverUrl: string;
@@ -17,8 +514,13 @@ interface Props {
17
514
  getConsoleLogs: () => ConsoleEntry[];
18
515
  getNetworkErrors: () => NetworkEntry[];
19
516
  getReplayEvents: () => eventWithTime[];
20
- externalReplayUrl?: string;
517
+ getExternalReplayUrl: () => string | undefined;
21
518
  }
22
- declare function FlintModal({ projectKey, serverUrl, user, meta, theme, zIndex, onClose, getEnvironment, getConsoleLogs, getNetworkErrors, getReplayEvents, externalReplayUrl, }: Props): react_jsx_runtime.JSX.Element;
519
+ declare function FlintModal({ projectKey, serverUrl, user, meta, theme, zIndex, onClose, getEnvironment, getConsoleLogs, getNetworkErrors, getReplayEvents, getExternalReplayUrl, }: Props): react_jsx_runtime.JSX.Element;
520
+
521
+ declare const flint: {
522
+ setUser(user: FlintUser | null): void;
523
+ setSessionReplay(url: string | (() => string)): void;
524
+ };
23
525
 
24
- export { FlintModal, FlintWidget };
526
+ export { FlintModal, type FlintUser, FlintWidget, type FlintWidgetProps, type Locale, type ReportPayload, type ReportResult, type Severity, type Theme, type ThemeOverride, flint };
package/dist/index.js CHANGED
@@ -150,7 +150,7 @@ function FlintModal({
150
150
  getConsoleLogs,
151
151
  getNetworkErrors,
152
152
  getReplayEvents,
153
- externalReplayUrl
153
+ getExternalReplayUrl
154
154
  }) {
155
155
  const { t } = useTranslation();
156
156
  const colors = resolveTheme(theme);
@@ -200,7 +200,7 @@ function FlintModal({
200
200
  reporterName: user?.name ?? "Anonymous",
201
201
  description: description.trim(),
202
202
  expectedBehavior: expectedBehavior.trim() || void 0,
203
- externalReplayUrl: externalReplayUrl || void 0,
203
+ externalReplayUrl: getExternalReplayUrl() || void 0,
204
204
  severity,
205
205
  url: window.location.href,
206
206
  meta: collectedMeta
@@ -385,10 +385,10 @@ function FlintModal({
385
385
  pointerEvents: isSuccess ? "auto" : "none"
386
386
  }, children: [
387
387
  /* @__PURE__ */ jsx("p", { style: { fontSize: 13, color: colors.textMuted, margin: 0 }, children: result?.isDuplicate ? t("successDuplicate") : result ? `ID: ${result.id}` : "" }),
388
- result?.githubIssueUrl && /* @__PURE__ */ jsxs(
388
+ result?.slackMessageUrl && /* @__PURE__ */ jsxs(
389
389
  "a",
390
390
  {
391
- href: result.githubIssueUrl,
391
+ href: result.slackMessageUrl,
392
392
  target: "_blank",
393
393
  rel: "noreferrer",
394
394
  style: {
@@ -405,7 +405,7 @@ function FlintModal({
405
405
  boxShadow: accentGlow
406
406
  },
407
407
  children: [
408
- t("successGitHub"),
408
+ t("successSlack"),
409
409
  " \u2197"
410
410
  ]
411
411
  }
@@ -526,6 +526,19 @@ function FlintModal({
526
526
  }
527
527
  )
528
528
  ] }),
529
+ /* @__PURE__ */ jsxs("div", { style: {
530
+ display: "flex",
531
+ alignItems: "center",
532
+ gap: 8,
533
+ padding: "9px 12px",
534
+ borderRadius: 10,
535
+ background: isDark ? "rgba(255,255,255,0.04)" : "rgba(0,77,240,0.04)",
536
+ border: `1px solid ${isDark ? "rgba(255,255,255,0.08)" : "rgba(0,77,240,0.1)"}`,
537
+ marginBottom: 16
538
+ }, children: [
539
+ /* @__PURE__ */ jsx("span", { style: { fontSize: 14 }, children: "\u{1F3A5}" }),
540
+ /* @__PURE__ */ jsx("span", { style: { fontSize: 12, color: colors.textMuted, lineHeight: 1.4 }, children: t("replayInfo") })
541
+ ] }),
529
542
  status === "error" && /* @__PURE__ */ jsxs("div", { style: {
530
543
  padding: "10px 13px",
531
544
  borderRadius: 10,
@@ -741,6 +754,8 @@ var en_default = {
741
754
  successTitle: "Bug reported!",
742
755
  successDuplicate: "Looks like a duplicate of an existing bug.",
743
756
  successGitHub: "View GitHub issue",
757
+ successSlack: "View Slack message",
758
+ replayInfo: "No need to record your screen \u2014 we automatically capture a session replay when you submit.",
744
759
  errorLabel: "Failed to submit. Please try again.",
745
760
  cancel: "Cancel",
746
761
  sending: "Sending report",
@@ -953,6 +968,34 @@ function createNetworkCollector() {
953
968
  };
954
969
  }
955
970
 
971
+ // src/store.ts
972
+ import { useSyncExternalStore } from "react";
973
+ var state = { user: void 0, sessionReplay: void 0 };
974
+ var listeners = /* @__PURE__ */ new Set();
975
+ function emit() {
976
+ listeners.forEach((fn) => fn());
977
+ }
978
+ function subscribeStore(fn) {
979
+ listeners.add(fn);
980
+ return () => listeners.delete(fn);
981
+ }
982
+ function getSnapshot() {
983
+ return state;
984
+ }
985
+ function useFlintStore() {
986
+ return useSyncExternalStore(subscribeStore, getSnapshot);
987
+ }
988
+ var flint = {
989
+ setUser(user) {
990
+ state = { ...state, user: user ?? void 0 };
991
+ emit();
992
+ },
993
+ setSessionReplay(url) {
994
+ state = { ...state, sessionReplay: url };
995
+ emit();
996
+ }
997
+ };
998
+
956
999
  // src/FlintWidget.tsx
957
1000
  import { record } from "rrweb";
958
1001
  import { Fragment, jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
@@ -974,7 +1017,13 @@ function WidgetContent({
974
1017
  theme = "dark",
975
1018
  zIndex = 9999
976
1019
  }) {
977
- const externalReplayUrl = extraFields?.sessionReplay;
1020
+ const globalState = useFlintStore();
1021
+ const resolvedUser = user ?? globalState.user;
1022
+ const resolvedSessionReplay = extraFields?.sessionReplay ?? globalState.sessionReplay;
1023
+ const getExternalReplayUrl = () => {
1024
+ const src = resolvedSessionReplay;
1025
+ return typeof src === "function" ? src() : src;
1026
+ };
978
1027
  const { t } = useTranslation2();
979
1028
  const [open, setOpen] = useState2(false);
980
1029
  const [hovered, setHovered] = useState2(false);
@@ -1019,7 +1068,7 @@ function WidgetContent({
1019
1068
  "aria-label": label,
1020
1069
  style: {
1021
1070
  position: "fixed",
1022
- bottom: "20px",
1071
+ bottom: "40px",
1023
1072
  right: "20px",
1024
1073
  zIndex: zIndex - 1,
1025
1074
  display: "flex",
@@ -1050,7 +1099,7 @@ function WidgetContent({
1050
1099
  {
1051
1100
  projectKey,
1052
1101
  serverUrl,
1053
- user,
1102
+ user: resolvedUser,
1054
1103
  meta,
1055
1104
  theme,
1056
1105
  zIndex,
@@ -1059,7 +1108,7 @@ function WidgetContent({
1059
1108
  getConsoleLogs: () => consoleCollector.current?.getEntries() ?? [],
1060
1109
  getNetworkErrors: () => networkCollector.current?.getEntries() ?? [],
1061
1110
  getReplayEvents: () => [...replayEvents.current],
1062
- externalReplayUrl
1111
+ getExternalReplayUrl
1063
1112
  }
1064
1113
  )
1065
1114
  ] });
@@ -1083,6 +1132,7 @@ function SparkIcon2() {
1083
1132
  }
1084
1133
  export {
1085
1134
  FlintModal,
1086
- FlintWidget
1135
+ FlintWidget,
1136
+ flint
1087
1137
  };
1088
1138
  //# sourceMappingURL=index.js.map