blocfeed 0.7.2 → 0.8.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/CHANGELOG.md +43 -0
- package/README.md +161 -2
- package/dist/chunk-KJRV7PRA.js +2 -0
- package/dist/chunk-ORVW2RTZ.cjs +2 -0
- package/dist/{controller-BPsU7cuY.d.cts → controller-BnTq9F8J.d.cts} +57 -3
- package/dist/{controller-BPsU7cuY.d.ts → controller-BnTq9F8J.d.ts} +57 -3
- package/dist/engine.cjs +1 -1
- package/dist/engine.d.cts +37 -3
- package/dist/engine.d.ts +37 -3
- package/dist/engine.js +1 -1
- package/dist/main.cjs +107 -4
- package/dist/main.d.cts +5 -2
- package/dist/main.d.ts +5 -2
- package/dist/main.js +107 -4
- package/package.json +4 -2
- package/dist/chunk-JVY6JTXP.cjs +0 -2
- package/dist/chunk-LAK7UUTC.js +0 -2
|
@@ -38,6 +38,8 @@ interface BlocFeedHandle {
|
|
|
38
38
|
open: () => void;
|
|
39
39
|
close: () => void;
|
|
40
40
|
submit: (message: string) => Promise<SubmitResult>;
|
|
41
|
+
startRecording: () => Promise<void>;
|
|
42
|
+
stopRecording: () => void;
|
|
41
43
|
isOpen: boolean;
|
|
42
44
|
}
|
|
43
45
|
interface BlocFeedStrings {
|
|
@@ -59,6 +61,12 @@ interface BlocFeedStrings {
|
|
|
59
61
|
categoryFeature?: string;
|
|
60
62
|
categoryUx?: string;
|
|
61
63
|
categoryGeneral?: string;
|
|
64
|
+
recordButton?: string;
|
|
65
|
+
stopRecordButton?: string;
|
|
66
|
+
recordingText?: string;
|
|
67
|
+
recordingDeniedText?: string;
|
|
68
|
+
videoPreviewLabel?: string;
|
|
69
|
+
removeVideoButton?: string;
|
|
62
70
|
}
|
|
63
71
|
interface ConsoleEntry {
|
|
64
72
|
level: "error" | "warn" | "log";
|
|
@@ -85,6 +93,13 @@ interface DiagnosticsConfig {
|
|
|
85
93
|
network?: boolean;
|
|
86
94
|
/** Max network entries to retain. Default: 15 */
|
|
87
95
|
networkLimit?: number;
|
|
96
|
+
/**
|
|
97
|
+
* URL patterns to exclude from network capture.
|
|
98
|
+
* Each entry is matched as a substring against the request URL.
|
|
99
|
+
* Common analytics/tracking domains are excluded by default.
|
|
100
|
+
* Set to `[]` to disable the built-in blocklist and capture everything.
|
|
101
|
+
*/
|
|
102
|
+
ignoreUrls?: string[];
|
|
88
103
|
}
|
|
89
104
|
type SecurityScanTarget = "hydration" | "scripts" | "meta" | "dom";
|
|
90
105
|
interface SecurityConfig {
|
|
@@ -155,7 +170,7 @@ interface CaptureResult {
|
|
|
155
170
|
diagnostics: CaptureDiagnostics;
|
|
156
171
|
}
|
|
157
172
|
interface BlocFeedError {
|
|
158
|
-
kind: "unknown" | "configuration" | "capture_failed" | "api_failed" | "aborted";
|
|
173
|
+
kind: "unknown" | "configuration" | "capture_failed" | "recording_failed" | "api_failed" | "aborted";
|
|
159
174
|
message: string;
|
|
160
175
|
detail?: Record<string, unknown>;
|
|
161
176
|
}
|
|
@@ -177,6 +192,33 @@ interface ScreenshotAdapter {
|
|
|
177
192
|
captureElement: (element: Element, options: ScreenshotAdapterOptions) => MaybePromise<ImageAsset>;
|
|
178
193
|
captureFullPage: (options: ScreenshotAdapterOptions) => MaybePromise<ImageAsset>;
|
|
179
194
|
}
|
|
195
|
+
type VideoMime = "video/webm";
|
|
196
|
+
interface RecordingConfig {
|
|
197
|
+
/** Enable video recording button in the widget. Default: false */
|
|
198
|
+
enabled?: boolean;
|
|
199
|
+
/** Maximum recording duration in milliseconds. Default: 30 000 (30 s) */
|
|
200
|
+
maxDurationMs?: number;
|
|
201
|
+
/** Video MIME type. Default: "video/webm" */
|
|
202
|
+
mime?: VideoMime;
|
|
203
|
+
/** Video bitrate in bits/s. Default: 2 500 000 (2.5 Mbps) */
|
|
204
|
+
videoBitsPerSecond?: number;
|
|
205
|
+
}
|
|
206
|
+
interface VideoAsset {
|
|
207
|
+
mime: VideoMime;
|
|
208
|
+
/** Object URL (blob:) for local preview. Revoked after submission. */
|
|
209
|
+
blobUrl: string;
|
|
210
|
+
/** The raw Blob — held in memory until uploaded. */
|
|
211
|
+
blob: Blob;
|
|
212
|
+
/** Duration of the recording in milliseconds. */
|
|
213
|
+
durationMs: number;
|
|
214
|
+
/** Byte size of the video blob. */
|
|
215
|
+
sizeBytes: number;
|
|
216
|
+
}
|
|
217
|
+
interface VideoIntent {
|
|
218
|
+
mime: string;
|
|
219
|
+
durationMs: number;
|
|
220
|
+
sizeBytes: number;
|
|
221
|
+
}
|
|
180
222
|
interface CaptureConfig {
|
|
181
223
|
element?: boolean;
|
|
182
224
|
fullPage?: boolean;
|
|
@@ -235,6 +277,8 @@ interface BlocFeedConfig {
|
|
|
235
277
|
diagnostics?: DiagnosticsConfig;
|
|
236
278
|
/** Client-side secret leak detection. */
|
|
237
279
|
security?: SecurityConfig;
|
|
280
|
+
/** Video recording configuration. */
|
|
281
|
+
recording?: RecordingConfig;
|
|
238
282
|
ui?: {
|
|
239
283
|
/** z-index for the widget overlay/panel. */
|
|
240
284
|
zIndex?: number;
|
|
@@ -286,6 +330,10 @@ interface FeedbackPayload {
|
|
|
286
330
|
screenshots?: CaptureResult;
|
|
287
331
|
/** Lightweight screenshot metadata sent instead of base64 dataUrls. */
|
|
288
332
|
screenshot_intent?: ScreenshotIntent;
|
|
333
|
+
/** Video recording asset (blob held separately during transport). */
|
|
334
|
+
video?: VideoAsset;
|
|
335
|
+
/** Lightweight video metadata sent instead of the blob. */
|
|
336
|
+
video_intent?: VideoIntent;
|
|
289
337
|
/** First-class user identity. */
|
|
290
338
|
user?: BlocFeedUser;
|
|
291
339
|
metadata: Record<string, unknown>;
|
|
@@ -296,6 +344,7 @@ interface FeedbackApiResponse {
|
|
|
296
344
|
upload_urls?: {
|
|
297
345
|
element?: string;
|
|
298
346
|
fullPage?: string;
|
|
347
|
+
video?: string;
|
|
299
348
|
};
|
|
300
349
|
}
|
|
301
350
|
interface TransportResult {
|
|
@@ -307,11 +356,13 @@ interface SubmitResult {
|
|
|
307
356
|
ok: boolean;
|
|
308
357
|
api?: TransportResult;
|
|
309
358
|
}
|
|
310
|
-
type SessionPhase = "idle" | "picking" | "review" | "capturing" | "submitting" | "success" | "error";
|
|
359
|
+
type SessionPhase = "idle" | "picking" | "review" | "recording" | "capturing" | "submitting" | "success" | "error";
|
|
311
360
|
interface BlocFeedState {
|
|
312
361
|
phase: SessionPhase;
|
|
313
362
|
selection?: ElementDescriptor;
|
|
314
363
|
capture?: CaptureResult;
|
|
364
|
+
video?: VideoAsset;
|
|
365
|
+
recordingElapsedMs?: number;
|
|
315
366
|
lastSubmit?: SubmitResult;
|
|
316
367
|
lastError?: BlocFeedError;
|
|
317
368
|
}
|
|
@@ -335,10 +386,13 @@ interface BlocFeedController {
|
|
|
335
386
|
capture?: CaptureConfig;
|
|
336
387
|
category?: FeedbackCategory;
|
|
337
388
|
}) => Promise<SubmitResult>;
|
|
389
|
+
startRecording: () => Promise<void>;
|
|
390
|
+
stopRecording: () => void;
|
|
391
|
+
removeVideo: () => void;
|
|
338
392
|
/** Internal: used by UI to access the live element handle. */
|
|
339
393
|
__unsafeGetSelectedElement: () => Element | null;
|
|
340
394
|
destroy: () => void;
|
|
341
395
|
}
|
|
342
396
|
declare function createBlocFeedController(config: BlocFeedConfig): BlocFeedController;
|
|
343
397
|
|
|
344
|
-
export { type BlocFeedConfig as B, type CaptureConfig as C, type DiagnosticsConfig as D, type ElementDescriptor as E, type FeedbackCategory as F, type HoverListener as H, type ImageAsset as I, type MaybePromise as M, type NetworkEntry as N, type PickerConfig as P, type
|
|
398
|
+
export { type VideoMime as A, type BlocFeedConfig as B, type CaptureConfig as C, type DiagnosticsConfig as D, type ElementDescriptor as E, type FeedbackCategory as F, type StateListener as G, type HoverListener as H, type ImageAsset as I, createBlocFeedController as J, type MaybePromise as M, type NetworkEntry as N, type PickerConfig as P, type RecordingConfig as R, type SubmitResult as S, type ThemeConfig as T, type VideoAsset as V, type WidgetPosition as W, type BlocFeedHandle as a, type BlocFeedState as b, type BlocFeedController as c, type BlocFeedError as d, type BlocFeedStrings as e, type BlocFeedUser as f, type CaptureDiagnostics as g, type CaptureResult as h, type ConsoleEntry as i, type FeedbackApiResponse as j, type FeedbackPayload as k, type MetadataConfig as l, type MetadataContext as m, type Rect as n, type ScreenshotAdapter as o, type ScreenshotAdapterOptions as p, type ScreenshotIntent as q, type ScreenshotMime as r, type SecurityConfig as s, type SecurityFinding as t, type SecuritySnapshot as u, type SessionPhase as v, type TransportConfig as w, type TransportResult as x, type TriggerStyle as y, type VideoIntent as z };
|
package/dist/engine.cjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
'use strict';var
|
|
1
|
+
'use strict';var chunkORVW2RTZ_cjs=require('./chunk-ORVW2RTZ.cjs');function c(o){if(o?.aborted)throw new Error("Aborted")}async function P(o){return await new Promise((t,e)=>{let r=new Image;r.onload=()=>t({width:r.naturalWidth,height:r.naturalHeight}),r.onerror=()=>e(new Error("Failed to load generated screenshot")),r.src=o;})}async function l(o,t){let{width:e,height:r}=await P(o);return {dataUrl:o,mime:t,width:e,height:r}}function B(o){return {async captureElement(t,e){if(!chunkORVW2RTZ_cjs.a())throw new Error("captureElement can only run in the browser");c(e.signal);let r={scale:e.pixelRatio},n=e.mime==="image/jpeg"?await o.domToJpeg(t,{...r,quality:e.quality??.92}):await o.domToPng(t,r);return c(e.signal),await l(n,e.mime)},async captureFullPage(t){if(!chunkORVW2RTZ_cjs.a())throw new Error("captureFullPage can only run in the browser");c(t.signal);let e=document.documentElement,r=Math.max(e.scrollWidth,e.clientWidth),n=Math.max(e.scrollHeight,e.clientHeight),a=Math.min(1,t.maxDimension/Math.max(r,n)),s={width:Math.max(1,Math.round(r*a)),height:Math.max(1,Math.round(n*a)),scale:t.pixelRatio},i=t.mime==="image/jpeg"?await o.domToJpeg(e,{...s,quality:t.quality??.92}):await o.domToPng(e,s);return c(t.signal),await l(i,t.mime)}}}function k(o){let[t,e]=o.split(",",2);if(!t||!e)throw new Error("Invalid data URL");let n=/data:(.*?);base64/.exec(t)?.[1]||"application/octet-stream",a=atob(e),s=new Uint8Array(a.length);for(let i=0;i<a.length;i+=1)s[i]=a.charCodeAt(i);return new Blob([s],{type:n})}Object.defineProperty(exports,"clearDiagnostics",{enumerable:true,get:function(){return chunkORVW2RTZ_cjs.p}});Object.defineProperty(exports,"clearQueue",{enumerable:true,get:function(){return chunkORVW2RTZ_cjs.h}});Object.defineProperty(exports,"clearSecurityFindings",{enumerable:true,get:function(){return chunkORVW2RTZ_cjs.s}});Object.defineProperty(exports,"collectMetadata",{enumerable:true,get:function(){return chunkORVW2RTZ_cjs.e}});Object.defineProperty(exports,"createBlocFeedController",{enumerable:true,get:function(){return chunkORVW2RTZ_cjs.l}});Object.defineProperty(exports,"createHtmlToImageAdapter",{enumerable:true,get:function(){return chunkORVW2RTZ_cjs.c}});Object.defineProperty(exports,"dequeueAll",{enumerable:true,get:function(){return chunkORVW2RTZ_cjs.g}});Object.defineProperty(exports,"drainDiagnostics",{enumerable:true,get:function(){return chunkORVW2RTZ_cjs.o}});Object.defineProperty(exports,"enqueue",{enumerable:true,get:function(){return chunkORVW2RTZ_cjs.f}});Object.defineProperty(exports,"getQueueSize",{enumerable:true,get:function(){return chunkORVW2RTZ_cjs.i}});Object.defineProperty(exports,"getSecurityFindings",{enumerable:true,get:function(){return chunkORVW2RTZ_cjs.r}});Object.defineProperty(exports,"installDiagnostics",{enumerable:true,get:function(){return chunkORVW2RTZ_cjs.m}});Object.defineProperty(exports,"isRecordingSupported",{enumerable:true,get:function(){return chunkORVW2RTZ_cjs.j}});Object.defineProperty(exports,"runCapture",{enumerable:true,get:function(){return chunkORVW2RTZ_cjs.d}});Object.defineProperty(exports,"runSecretScan",{enumerable:true,get:function(){return chunkORVW2RTZ_cjs.q}});Object.defineProperty(exports,"startRecording",{enumerable:true,get:function(){return chunkORVW2RTZ_cjs.k}});Object.defineProperty(exports,"uninstallDiagnostics",{enumerable:true,get:function(){return chunkORVW2RTZ_cjs.n}});exports.createModernScreenshotAdapter=B;exports.dataUrlToBlob=k;
|
package/dist/engine.d.cts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
export { B as BlocFeedConfig, c as BlocFeedController, d as BlocFeedError, a as BlocFeedHandle, b as BlocFeedState, e as BlocFeedStrings, i as ConsoleEntry, D as DiagnosticsConfig, E as ElementDescriptor, j as FeedbackApiResponse, F as FeedbackCategory, H as HoverListener, I as ImageAsset, N as NetworkEntry,
|
|
1
|
+
import { o as ScreenshotAdapter, C as CaptureConfig, h as CaptureResult, V as VideoAsset, R as RecordingConfig, l as MetadataConfig, m as MetadataContext, f as BlocFeedUser, k as FeedbackPayload, u as SecuritySnapshot, s as SecurityConfig } from './controller-BnTq9F8J.cjs';
|
|
2
|
+
export { B as BlocFeedConfig, c as BlocFeedController, d as BlocFeedError, a as BlocFeedHandle, b as BlocFeedState, e as BlocFeedStrings, i as ConsoleEntry, D as DiagnosticsConfig, E as ElementDescriptor, j as FeedbackApiResponse, F as FeedbackCategory, H as HoverListener, I as ImageAsset, N as NetworkEntry, n as Rect, p as ScreenshotAdapterOptions, q as ScreenshotIntent, r as ScreenshotMime, t as SecurityFinding, v as SessionPhase, G as StateListener, S as SubmitResult, T as ThemeConfig, w as TransportConfig, y as TriggerStyle, z as VideoIntent, A as VideoMime, W as WidgetPosition, J as createBlocFeedController } from './controller-BnTq9F8J.cjs';
|
|
3
3
|
|
|
4
4
|
declare function createHtmlToImageAdapter(): ScreenshotAdapter;
|
|
5
5
|
|
|
@@ -38,6 +38,33 @@ declare function runCapture(params: {
|
|
|
38
38
|
signal?: AbortSignal;
|
|
39
39
|
}): Promise<CaptureResult | undefined>;
|
|
40
40
|
|
|
41
|
+
interface RecordingSession {
|
|
42
|
+
/** Resolves with the final VideoAsset when recording finishes. */
|
|
43
|
+
result: Promise<VideoAsset>;
|
|
44
|
+
/** Stop recording early (user clicks Stop). */
|
|
45
|
+
stop: () => void;
|
|
46
|
+
/** Subscribe to elapsed-time ticks (~250 ms interval). */
|
|
47
|
+
onTick: (cb: (elapsedMs: number) => void) => void;
|
|
48
|
+
/** Abort the recording and clean up (widget closed). */
|
|
49
|
+
abort: () => void;
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Returns true if the current browser supports screen recording
|
|
53
|
+
* (getDisplayMedia + MediaRecorder with WebM).
|
|
54
|
+
*/
|
|
55
|
+
declare function isRecordingSupported(): boolean;
|
|
56
|
+
/**
|
|
57
|
+
* Start a screen recording session.
|
|
58
|
+
*
|
|
59
|
+
* The returned promise resolves once the user grants screen-share permission
|
|
60
|
+
* and MediaRecorder is initialised. It rejects if the user denies permission
|
|
61
|
+
* or the browser does not support recording.
|
|
62
|
+
*/
|
|
63
|
+
declare function startRecording(params: {
|
|
64
|
+
config?: RecordingConfig;
|
|
65
|
+
signal?: AbortSignal;
|
|
66
|
+
}): Promise<RecordingSession>;
|
|
67
|
+
|
|
41
68
|
declare function collectMetadata(params: {
|
|
42
69
|
config: MetadataConfig | undefined;
|
|
43
70
|
context: MetadataContext;
|
|
@@ -87,6 +114,13 @@ interface DiagnosticsConfig {
|
|
|
87
114
|
network?: boolean;
|
|
88
115
|
/** Max network entries to retain. Default: 15 */
|
|
89
116
|
networkLimit?: number;
|
|
117
|
+
/**
|
|
118
|
+
* URL patterns to exclude from network capture.
|
|
119
|
+
* Each entry is matched as a substring against the request URL.
|
|
120
|
+
* Common analytics/tracking domains are excluded by default.
|
|
121
|
+
* Set to `[]` to disable the built-in blocklist and capture everything.
|
|
122
|
+
*/
|
|
123
|
+
ignoreUrls?: string[];
|
|
90
124
|
}
|
|
91
125
|
interface DiagnosticsSnapshot {
|
|
92
126
|
consoleLogs: ConsoleEntry[];
|
|
@@ -125,4 +159,4 @@ declare function clearSecurityFindings(): void;
|
|
|
125
159
|
|
|
126
160
|
declare function dataUrlToBlob(dataUrl: string): Blob;
|
|
127
161
|
|
|
128
|
-
export { BlocFeedUser, CaptureResult, FeedbackPayload, type ModernScreenshotModule, ScreenshotAdapter, SecurityConfig, SecuritySnapshot, clearDiagnostics, clearQueue, clearSecurityFindings, collectMetadata, createHtmlToImageAdapter, createModernScreenshotAdapter, dataUrlToBlob, dequeueAll, drainDiagnostics, enqueue, getQueueSize, getSecurityFindings, installDiagnostics, runCapture, runSecretScan, uninstallDiagnostics };
|
|
162
|
+
export { BlocFeedUser, CaptureResult, FeedbackPayload, type ModernScreenshotModule, RecordingConfig, type RecordingSession, ScreenshotAdapter, SecurityConfig, SecuritySnapshot, VideoAsset, clearDiagnostics, clearQueue, clearSecurityFindings, collectMetadata, createHtmlToImageAdapter, createModernScreenshotAdapter, dataUrlToBlob, dequeueAll, drainDiagnostics, enqueue, getQueueSize, getSecurityFindings, installDiagnostics, isRecordingSupported, runCapture, runSecretScan, startRecording, uninstallDiagnostics };
|
package/dist/engine.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
export { B as BlocFeedConfig, c as BlocFeedController, d as BlocFeedError, a as BlocFeedHandle, b as BlocFeedState, e as BlocFeedStrings, i as ConsoleEntry, D as DiagnosticsConfig, E as ElementDescriptor, j as FeedbackApiResponse, F as FeedbackCategory, H as HoverListener, I as ImageAsset, N as NetworkEntry,
|
|
1
|
+
import { o as ScreenshotAdapter, C as CaptureConfig, h as CaptureResult, V as VideoAsset, R as RecordingConfig, l as MetadataConfig, m as MetadataContext, f as BlocFeedUser, k as FeedbackPayload, u as SecuritySnapshot, s as SecurityConfig } from './controller-BnTq9F8J.js';
|
|
2
|
+
export { B as BlocFeedConfig, c as BlocFeedController, d as BlocFeedError, a as BlocFeedHandle, b as BlocFeedState, e as BlocFeedStrings, i as ConsoleEntry, D as DiagnosticsConfig, E as ElementDescriptor, j as FeedbackApiResponse, F as FeedbackCategory, H as HoverListener, I as ImageAsset, N as NetworkEntry, n as Rect, p as ScreenshotAdapterOptions, q as ScreenshotIntent, r as ScreenshotMime, t as SecurityFinding, v as SessionPhase, G as StateListener, S as SubmitResult, T as ThemeConfig, w as TransportConfig, y as TriggerStyle, z as VideoIntent, A as VideoMime, W as WidgetPosition, J as createBlocFeedController } from './controller-BnTq9F8J.js';
|
|
3
3
|
|
|
4
4
|
declare function createHtmlToImageAdapter(): ScreenshotAdapter;
|
|
5
5
|
|
|
@@ -38,6 +38,33 @@ declare function runCapture(params: {
|
|
|
38
38
|
signal?: AbortSignal;
|
|
39
39
|
}): Promise<CaptureResult | undefined>;
|
|
40
40
|
|
|
41
|
+
interface RecordingSession {
|
|
42
|
+
/** Resolves with the final VideoAsset when recording finishes. */
|
|
43
|
+
result: Promise<VideoAsset>;
|
|
44
|
+
/** Stop recording early (user clicks Stop). */
|
|
45
|
+
stop: () => void;
|
|
46
|
+
/** Subscribe to elapsed-time ticks (~250 ms interval). */
|
|
47
|
+
onTick: (cb: (elapsedMs: number) => void) => void;
|
|
48
|
+
/** Abort the recording and clean up (widget closed). */
|
|
49
|
+
abort: () => void;
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Returns true if the current browser supports screen recording
|
|
53
|
+
* (getDisplayMedia + MediaRecorder with WebM).
|
|
54
|
+
*/
|
|
55
|
+
declare function isRecordingSupported(): boolean;
|
|
56
|
+
/**
|
|
57
|
+
* Start a screen recording session.
|
|
58
|
+
*
|
|
59
|
+
* The returned promise resolves once the user grants screen-share permission
|
|
60
|
+
* and MediaRecorder is initialised. It rejects if the user denies permission
|
|
61
|
+
* or the browser does not support recording.
|
|
62
|
+
*/
|
|
63
|
+
declare function startRecording(params: {
|
|
64
|
+
config?: RecordingConfig;
|
|
65
|
+
signal?: AbortSignal;
|
|
66
|
+
}): Promise<RecordingSession>;
|
|
67
|
+
|
|
41
68
|
declare function collectMetadata(params: {
|
|
42
69
|
config: MetadataConfig | undefined;
|
|
43
70
|
context: MetadataContext;
|
|
@@ -87,6 +114,13 @@ interface DiagnosticsConfig {
|
|
|
87
114
|
network?: boolean;
|
|
88
115
|
/** Max network entries to retain. Default: 15 */
|
|
89
116
|
networkLimit?: number;
|
|
117
|
+
/**
|
|
118
|
+
* URL patterns to exclude from network capture.
|
|
119
|
+
* Each entry is matched as a substring against the request URL.
|
|
120
|
+
* Common analytics/tracking domains are excluded by default.
|
|
121
|
+
* Set to `[]` to disable the built-in blocklist and capture everything.
|
|
122
|
+
*/
|
|
123
|
+
ignoreUrls?: string[];
|
|
90
124
|
}
|
|
91
125
|
interface DiagnosticsSnapshot {
|
|
92
126
|
consoleLogs: ConsoleEntry[];
|
|
@@ -125,4 +159,4 @@ declare function clearSecurityFindings(): void;
|
|
|
125
159
|
|
|
126
160
|
declare function dataUrlToBlob(dataUrl: string): Blob;
|
|
127
161
|
|
|
128
|
-
export { BlocFeedUser, CaptureResult, FeedbackPayload, type ModernScreenshotModule, ScreenshotAdapter, SecurityConfig, SecuritySnapshot, clearDiagnostics, clearQueue, clearSecurityFindings, collectMetadata, createHtmlToImageAdapter, createModernScreenshotAdapter, dataUrlToBlob, dequeueAll, drainDiagnostics, enqueue, getQueueSize, getSecurityFindings, installDiagnostics, runCapture, runSecretScan, uninstallDiagnostics };
|
|
162
|
+
export { BlocFeedUser, CaptureResult, FeedbackPayload, type ModernScreenshotModule, RecordingConfig, type RecordingSession, ScreenshotAdapter, SecurityConfig, SecuritySnapshot, VideoAsset, clearDiagnostics, clearQueue, clearSecurityFindings, collectMetadata, createHtmlToImageAdapter, createModernScreenshotAdapter, dataUrlToBlob, dequeueAll, drainDiagnostics, enqueue, getQueueSize, getSecurityFindings, installDiagnostics, isRecordingSupported, runCapture, runSecretScan, startRecording, uninstallDiagnostics };
|
package/dist/engine.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import {a}from'./chunk-
|
|
1
|
+
import {a}from'./chunk-KJRV7PRA.js';export{p as clearDiagnostics,h as clearQueue,s as clearSecurityFindings,e as collectMetadata,l as createBlocFeedController,c as createHtmlToImageAdapter,g as dequeueAll,o as drainDiagnostics,f as enqueue,i as getQueueSize,r as getSecurityFindings,m as installDiagnostics,j as isRecordingSupported,d as runCapture,q as runSecretScan,k as startRecording,n as uninstallDiagnostics}from'./chunk-KJRV7PRA.js';function c(o){if(o?.aborted)throw new Error("Aborted")}async function P(o){return await new Promise((t,e)=>{let r=new Image;r.onload=()=>t({width:r.naturalWidth,height:r.naturalHeight}),r.onerror=()=>e(new Error("Failed to load generated screenshot")),r.src=o;})}async function l(o,t){let{width:e,height:r}=await P(o);return {dataUrl:o,mime:t,width:e,height:r}}function B(o){return {async captureElement(t,e){if(!a())throw new Error("captureElement can only run in the browser");c(e.signal);let r={scale:e.pixelRatio},n=e.mime==="image/jpeg"?await o.domToJpeg(t,{...r,quality:e.quality??.92}):await o.domToPng(t,r);return c(e.signal),await l(n,e.mime)},async captureFullPage(t){if(!a())throw new Error("captureFullPage can only run in the browser");c(t.signal);let e=document.documentElement,r=Math.max(e.scrollWidth,e.clientWidth),n=Math.max(e.scrollHeight,e.clientHeight),a$1=Math.min(1,t.maxDimension/Math.max(r,n)),s={width:Math.max(1,Math.round(r*a$1)),height:Math.max(1,Math.round(n*a$1)),scale:t.pixelRatio},i=t.mime==="image/jpeg"?await o.domToJpeg(e,{...s,quality:t.quality??.92}):await o.domToPng(e,s);return c(t.signal),await l(i,t.mime)}}}function k(o){let[t,e]=o.split(",",2);if(!t||!e)throw new Error("Invalid data URL");let n=/data:(.*?);base64/.exec(t)?.[1]||"application/octet-stream",a=atob(e),s=new Uint8Array(a.length);for(let i=0;i<a.length;i+=1)s[i]=a.charCodeAt(i);return new Blob([s],{type:n})}export{B as createModernScreenshotAdapter,k as dataUrlToBlob};
|
package/dist/main.cjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
'use strict';var
|
|
2
|
+
'use strict';var chunkORVW2RTZ_cjs=require('./chunk-ORVW2RTZ.cjs'),react=require('react'),jsxRuntime=require('react/jsx-runtime'),reactDom=require('react-dom'),framerMotion=require('framer-motion');var V=react.createContext(null);function ee(e){let t=react.useMemo(()=>chunkORVW2RTZ_cjs.l({...e.config??{},blocfeed_id:e.blocfeed_id}),[]),[i,o]=react.useState(()=>t.getState());return react.useEffect(()=>t.subscribe(o),[t]),react.useEffect(()=>t.setConfig({...e.config??{},blocfeed_id:e.blocfeed_id}),[t,e.config,e.blocfeed_id]),react.useEffect(()=>()=>t.destroy(),[t]),jsxRuntime.jsx(V.Provider,{value:{controller:t,state:i},children:e.children})}var ke="blocfeed-styles-v1",kt=`
|
|
3
3
|
:where([data-blocfeed-ui-root]),
|
|
4
4
|
:where([data-blocfeed-ui-root]) * {
|
|
5
5
|
box-sizing: border-box;
|
|
@@ -603,6 +603,108 @@
|
|
|
603
603
|
/* Reduced motion */
|
|
604
604
|
/* ------------------------------------------------------------------ */
|
|
605
605
|
|
|
606
|
+
/* ------------------------------------------------------------------ */
|
|
607
|
+
/* Video recording */
|
|
608
|
+
/* ------------------------------------------------------------------ */
|
|
609
|
+
|
|
610
|
+
:where([data-blocfeed-ui-root]) .bf-record-btn {
|
|
611
|
+
display: inline-flex;
|
|
612
|
+
align-items: center;
|
|
613
|
+
gap: 6px;
|
|
614
|
+
padding: 6px 10px;
|
|
615
|
+
border-radius: 10px;
|
|
616
|
+
border: 1px solid var(--bf-border);
|
|
617
|
+
background: transparent;
|
|
618
|
+
color: var(--bf-panel-fg);
|
|
619
|
+
font-size: 13px;
|
|
620
|
+
font-family: var(--bf-font);
|
|
621
|
+
cursor: pointer;
|
|
622
|
+
user-select: none;
|
|
623
|
+
}
|
|
624
|
+
|
|
625
|
+
:where([data-blocfeed-ui-root]) .bf-record-btn:hover {
|
|
626
|
+
border-color: var(--bf-danger);
|
|
627
|
+
color: var(--bf-danger);
|
|
628
|
+
}
|
|
629
|
+
|
|
630
|
+
:where([data-blocfeed-ui-root]) .bf-record-btn:focus-visible {
|
|
631
|
+
outline: 2px solid var(--bf-accent);
|
|
632
|
+
outline-offset: 2px;
|
|
633
|
+
}
|
|
634
|
+
|
|
635
|
+
:where([data-blocfeed-ui-root]) .bf-record-btn[disabled] {
|
|
636
|
+
opacity: 0.6;
|
|
637
|
+
cursor: not-allowed;
|
|
638
|
+
}
|
|
639
|
+
|
|
640
|
+
:where([data-blocfeed-ui-root]) .bf-recording-indicator {
|
|
641
|
+
display: flex;
|
|
642
|
+
align-items: center;
|
|
643
|
+
gap: 8px;
|
|
644
|
+
font-size: 12px;
|
|
645
|
+
color: var(--bf-danger);
|
|
646
|
+
}
|
|
647
|
+
|
|
648
|
+
:where([data-blocfeed-ui-root]) .bf-rec-dot {
|
|
649
|
+
width: 8px;
|
|
650
|
+
height: 8px;
|
|
651
|
+
border-radius: 50%;
|
|
652
|
+
background: var(--bf-danger);
|
|
653
|
+
flex-shrink: 0;
|
|
654
|
+
}
|
|
655
|
+
|
|
656
|
+
:where([data-blocfeed-ui-root]) .bf-rec-dot-pulse {
|
|
657
|
+
animation: bf-rec-pulse 1s ease-in-out infinite;
|
|
658
|
+
}
|
|
659
|
+
|
|
660
|
+
@keyframes bf-rec-pulse {
|
|
661
|
+
0%, 100% { opacity: 1; }
|
|
662
|
+
50% { opacity: 0.3; }
|
|
663
|
+
}
|
|
664
|
+
|
|
665
|
+
:where([data-blocfeed-ui-root]) .bf-video-preview {
|
|
666
|
+
position: relative;
|
|
667
|
+
border-radius: 8px;
|
|
668
|
+
overflow: hidden;
|
|
669
|
+
border: 1px solid var(--bf-border);
|
|
670
|
+
}
|
|
671
|
+
|
|
672
|
+
:where([data-blocfeed-ui-root]) .bf-video-preview video {
|
|
673
|
+
width: 100%;
|
|
674
|
+
max-height: 120px;
|
|
675
|
+
object-fit: contain;
|
|
676
|
+
display: block;
|
|
677
|
+
background: black;
|
|
678
|
+
}
|
|
679
|
+
|
|
680
|
+
:where([data-blocfeed-ui-root]) .bf-video-remove {
|
|
681
|
+
position: absolute;
|
|
682
|
+
top: 4px;
|
|
683
|
+
right: 4px;
|
|
684
|
+
background: rgba(0, 0, 0, 0.7);
|
|
685
|
+
border: none;
|
|
686
|
+
color: white;
|
|
687
|
+
border-radius: 50%;
|
|
688
|
+
width: 20px;
|
|
689
|
+
height: 20px;
|
|
690
|
+
font-size: 12px;
|
|
691
|
+
cursor: pointer;
|
|
692
|
+
display: flex;
|
|
693
|
+
align-items: center;
|
|
694
|
+
justify-content: center;
|
|
695
|
+
line-height: 1;
|
|
696
|
+
}
|
|
697
|
+
|
|
698
|
+
:where([data-blocfeed-ui-root]) .bf-video-remove:hover {
|
|
699
|
+
background: rgba(0, 0, 0, 0.9);
|
|
700
|
+
}
|
|
701
|
+
|
|
702
|
+
:where([data-blocfeed-ui-root]) .bf-video-meta {
|
|
703
|
+
font-size: 11px;
|
|
704
|
+
color: var(--bf-muted);
|
|
705
|
+
padding: 4px 8px;
|
|
706
|
+
}
|
|
707
|
+
|
|
606
708
|
/* ------------------------------------------------------------------ */
|
|
607
709
|
/* Watermark */
|
|
608
710
|
/* ------------------------------------------------------------------ */
|
|
@@ -631,9 +733,10 @@
|
|
|
631
733
|
:where([data-blocfeed-ui-root]) .bf-panel,
|
|
632
734
|
:where([data-blocfeed-ui-root]) .bf-toast,
|
|
633
735
|
:where([data-blocfeed-ui-root]) .bf-hint,
|
|
634
|
-
:where([data-blocfeed-ui-root]) .bf-cursor
|
|
736
|
+
:where([data-blocfeed-ui-root]) .bf-cursor,
|
|
737
|
+
:where([data-blocfeed-ui-root]) .bf-rec-dot-pulse {
|
|
635
738
|
animation: none;
|
|
636
739
|
}
|
|
637
740
|
}
|
|
638
|
-
`;function ve(){if(!chunkJVY6JTXP_cjs.a()||document.getElementById(we))return;let e=document.createElement("style");e.id=we,e.textContent=xt,document.head.appendChild(e);}var ke={triggerLabel:"Feedback",panelTitle:"Feedback",hintText:"Click an element to attach your feedback. Press Esc to cancel.",cancelButton:"Cancel",rePickButton:"Re-pick",closeButton:"Close",textareaPlaceholder:"What's happening? What did you expect?",screenshotElement:"Screenshot element",screenshotFullPage:"Full page",capturingText:"Capturing screenshots\u2026",submittingText:"Submitting\u2026",successText:"Sent. Thank you!",toastText:"Feedback sent",sendButton:"Send",categoryBug:"Bug",categoryFeature:"Feature",categoryUx:"UX",categoryGeneral:"General"};function Te(e){return e?{...ke,...e}:ke}function te(){let e=react.useContext(U);if(!e)throw new Error("useBlocFeed must be used within a <BlocFeedProvider />");return {state:e.state,controller:e.controller,start:e.controller.start,stop:e.controller.stop,clearSelection:e.controller.clearSelection,submit:e.controller.submit}}function y(e){switch(e){case "bottom-left":return "bf-trigger bf-trigger-bl";case "top-right":return "bf-trigger bf-trigger-tr";case "top-left":return "bf-trigger bf-trigger-tl";default:return "bf-trigger"}}function b({size:e=14}){return jsxRuntime.jsx("svg",{width:e,height:e,viewBox:"0 0 24 24",fill:"none",xmlns:"http://www.w3.org/2000/svg","aria-hidden":"true",children:jsxRuntime.jsx("path",{d:"M20 6L9 17l-5-5",stroke:"currentColor",strokeWidth:"2.5",strokeLinecap:"round",strokeLinejoin:"round"})})}function Se({size:e=14}){return jsxRuntime.jsx("svg",{width:e,height:e,viewBox:"0 0 24 24",fill:"none",xmlns:"http://www.w3.org/2000/svg","aria-hidden":"true",children:jsxRuntime.jsx("path",{d:"M21 11.5a8.38 8.38 0 01-.9 3.8 8.5 8.5 0 01-7.6 4.7 8.38 8.38 0 01-3.8-.9L3 21l1.9-5.7a8.38 8.38 0 01-.9-3.8 8.5 8.5 0 014.7-7.6 8.38 8.38 0 013.8-.9h.5a8.48 8.48 0 018 8v.5z",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round"})})}function Pe({size:e=16}){return jsxRuntime.jsxs("svg",{width:e,height:e,viewBox:"0 0 24 24",fill:"none",xmlns:"http://www.w3.org/2000/svg","aria-hidden":"true",children:[jsxRuntime.jsx("path",{d:"M4 4h16c1.1 0 2 .9 2 2v12c0 1.1-.9 2-2 2H4c-1.1 0-2-.9-2-2V6c0-1.1.9-2 2-2z",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round"}),jsxRuntime.jsx("path",{d:"M22 6l-10 7L2 6",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round"})]})}function Ce({position:e,onClick:t,isVisible:n,label:o,queueCount:r,showSuccess:c}){return n?jsxRuntime.jsxs("button",{className:y(e),type:"button",onClick:t,"aria-label":o,children:[c?jsxRuntime.jsx("span",{style:{display:"inline-flex",color:"var(--bf-accent)"},children:jsxRuntime.jsx(b,{size:14})}):jsxRuntime.jsxs(jsxRuntime.Fragment,{children:[jsxRuntime.jsx("span",{className:"bf-dot","aria-hidden":"true"}),o]}),r>0&&jsxRuntime.jsx("span",{className:"bf-badge","aria-label":`${r} queued`,children:r})]}):null}function g(){let[e,t]=react.useState(()=>typeof window>"u"?false:window.matchMedia("(prefers-reduced-motion: reduce)").matches);return react.useEffect(()=>{let n=window.matchMedia("(prefers-reduced-motion: reduce)"),o=r=>t(r.matches);return n.addEventListener("change",o),()=>n.removeEventListener("change",o)},[]),e}var Pt={duration:.18,ease:"easeOut"},Et={duration:0};function Be({position:e,onClick:t,isVisible:n,label:o,queueCount:r,showSuccess:c}){let[i,l]=react.useState(false),a=g(),s=a?Et:Pt;return jsxRuntime.jsx(framerMotion.AnimatePresence,{mode:"wait",children:n&&jsxRuntime.jsx(framerMotion.motion.button,{className:y(e),type:"button",onClick:t,onMouseEnter:()=>l(true),onMouseLeave:()=>l(false),"aria-label":o,initial:{scale:0,opacity:0},animate:{scale:1,opacity:1},exit:{scale:0,opacity:0},transition:s,whileTap:{scale:.92},style:{overflow:"hidden"},children:c?jsxRuntime.jsx(framerMotion.motion.span,{initial:{scale:0},animate:{scale:1},transition:s,style:{display:"inline-flex",color:"var(--bf-accent)"},children:jsxRuntime.jsx(b,{size:14})},"success"):jsxRuntime.jsxs(jsxRuntime.Fragment,{children:[jsxRuntime.jsx(framerMotion.motion.span,{className:"bf-dot","aria-hidden":"true",animate:a?{}:{scale:i?1:[1,1.2,1],boxShadow:i?"0 0 0 4px rgba(99, 102, 241, 0.18)":["0 0 0 4px rgba(99, 102, 241, 0.18)","0 0 0 8px rgba(99, 102, 241, 0.28)","0 0 0 4px rgba(99, 102, 241, 0.18)"]},transition:i||a?s:{duration:2,repeat:1/0,ease:"easeInOut"}}),jsxRuntime.jsx(framerMotion.AnimatePresence,{mode:"wait",children:i&&jsxRuntime.jsx(framerMotion.motion.span,{initial:{opacity:0,x:a?0:-6},animate:{opacity:1,x:0},exit:{opacity:0,x:a?0:-6},transition:s,style:{whiteSpace:"nowrap"},children:o},"label")}),r>0&&jsxRuntime.jsx("span",{className:"bf-badge","aria-label":`${r} queued`,children:r})]})},"dot")})}var Nt={duration:.18,ease:"easeOut"},Re={duration:0};function Le({position:e,onClick:t,isVisible:n,label:o,queueCount:r,showSuccess:c}){let[i,l]=react.useState(false),a=g(),s=a?Re:Nt;return jsxRuntime.jsx(framerMotion.AnimatePresence,{mode:"wait",children:n&&jsxRuntime.jsxs(framerMotion.motion.div,{className:y(e),initial:{scale:0,opacity:0},animate:{scale:1,opacity:1},exit:{y:8,opacity:0},transition:s,onMouseEnter:()=>l(true),onMouseLeave:()=>l(false),style:{background:"transparent",border:"none",boxShadow:"none",padding:0},children:[jsxRuntime.jsx(framerMotion.AnimatePresence,{mode:"wait",children:i&&jsxRuntime.jsx(framerMotion.motion.div,{initial:{opacity:0,y:a?0:4},animate:{opacity:1,y:0},exit:{opacity:0,y:a?0:4},transition:s,style:{position:"absolute",bottom:"calc(100% + 8px)",left:"50%",transform:"translateX(-50%)",padding:"6px 12px",borderRadius:"8px",background:"var(--bf-panel-bg)",border:"1px solid var(--bf-border)",boxShadow:"var(--bf-shadow)",whiteSpace:"nowrap",fontSize:"12px",color:"var(--bf-panel-fg)",pointerEvents:"none"},children:o},"tooltip")}),jsxRuntime.jsxs(framerMotion.motion.button,{type:"button",onClick:t,"aria-label":o,style:{position:"relative",display:"flex",alignItems:"center",justifyContent:"center",width:"40px",height:"40px",borderRadius:"50%",border:"1px solid var(--bf-border)",background:"var(--bf-panel-bg)",color:"var(--bf-panel-fg)",boxShadow:"var(--bf-shadow)",cursor:"pointer",padding:0},animate:a?{}:{y:[0,-3,0]},transition:a?Re:{y:{duration:3,repeat:1/0,ease:"easeInOut"}},whileHover:{scale:1.1,borderColor:"var(--bf-accent)"},whileTap:{scale:.9},children:[c?jsxRuntime.jsx(framerMotion.motion.span,{initial:{scale:0},animate:{scale:1},transition:s,style:{display:"inline-flex",color:"var(--bf-accent)"},children:jsxRuntime.jsx(b,{size:16})},"success"):jsxRuntime.jsx(Se,{size:16}),r>0&&jsxRuntime.jsx("span",{className:"bf-badge bf-badge-float","aria-label":`${r} queued`,children:r})]})]},"bubble")})}var Lt={duration:.2,ease:"easeOut"},zt={duration:0};function Ae(e){return e==="bottom-left"||e==="top-left"}function At(e){return `bf-trigger-edge ${Ae(e)?"bf-trigger-edge-left":"bf-trigger-edge-right"}`}function Ie({position:e,onClick:t,isVisible:n,label:o,queueCount:r,showSuccess:c}){let[i,l]=react.useState(false),a=Ae(e),s=g(),m=s?zt:Lt;return jsxRuntime.jsx(framerMotion.AnimatePresence,{mode:"wait",children:n&&jsxRuntime.jsx(framerMotion.motion.button,{className:At(e),type:"button",onClick:t,onMouseEnter:()=>l(true),onMouseLeave:()=>l(false),"aria-label":o,initial:{opacity:0,width:0},animate:{opacity:1,width:i?140:22,height:i?40:90},exit:{width:0,opacity:0},transition:m,whileTap:{scale:.97},style:{top:"50%",translateY:"-50%"},children:c?jsxRuntime.jsx(framerMotion.motion.span,{initial:{scale:0},animate:{scale:1},transition:m,style:{display:"inline-flex",color:"var(--bf-accent)"},children:jsxRuntime.jsx(b,{size:14})},"success"):jsxRuntime.jsxs(jsxRuntime.Fragment,{children:[jsxRuntime.jsxs(framerMotion.motion.span,{animate:{rotate:s||i?0:a?-90:90,opacity:i?1:.6},transition:m,style:{display:"flex",alignItems:"center",gap:"8px",whiteSpace:"nowrap",fontSize:"12px",letterSpacing:"0.5px",textTransform:"uppercase"},children:[i&&jsxRuntime.jsx(framerMotion.motion.span,{initial:{scale:0},animate:{scale:1},transition:{duration:.12},style:{width:"6px",height:"6px",borderRadius:"50%",background:"var(--bf-accent)",flexShrink:0}}),o]}),jsxRuntime.jsx(framerMotion.motion.span,{"aria-hidden":"true",animate:{opacity:i?1:0},transition:{duration:.12},style:{position:"absolute",top:0,bottom:0,[a?"left":"right"]:0,width:"2px",background:"var(--bf-accent)"}}),r>0&&jsxRuntime.jsx("span",{className:"bf-badge","aria-label":`${r} queued`,children:r})]})},"edge-tab")})}var _t={duration:.18,ease:"easeOut"},Ht={duration:0};function _e({delay:e,hovered:t,reduced:n}){return n?null:jsxRuntime.jsx(framerMotion.motion.span,{"aria-hidden":"true",style:{position:"absolute",width:"10px",height:"10px",borderRadius:"50%",border:"2px solid var(--bf-accent)",pointerEvents:"none"},animate:t?{scale:1,opacity:0}:{scale:[1,1.8],opacity:[.5,0]},transition:t?{duration:.15}:{duration:2,repeat:1/0,delay:e,ease:"easeOut"}})}function Oe({position:e,onClick:t,isVisible:n,label:o,queueCount:r,showSuccess:c}){let[i,l]=react.useState(false),a=g(),s=a?Ht:_t;return jsxRuntime.jsx(framerMotion.AnimatePresence,{mode:"wait",children:n&&jsxRuntime.jsx(framerMotion.motion.button,{className:y(e),type:"button",onClick:t,onMouseEnter:()=>l(true),onMouseLeave:()=>l(false),"aria-label":o,initial:{scale:0,opacity:0},animate:{scale:1,opacity:1},exit:{scale:0,opacity:0},transition:s,whileTap:{scale:.92},style:{overflow:"hidden"},children:c?jsxRuntime.jsx(framerMotion.motion.span,{initial:{scale:0},animate:{scale:1},transition:s,style:{display:"inline-flex",color:"var(--bf-accent)"},children:jsxRuntime.jsx(b,{size:14})},"success"):jsxRuntime.jsxs(jsxRuntime.Fragment,{children:[jsxRuntime.jsxs("span",{style:{position:"relative",display:"flex",alignItems:"center",justifyContent:"center",width:"10px",height:"10px",flexShrink:0},children:[jsxRuntime.jsx(_e,{delay:0,hovered:i,reduced:a}),jsxRuntime.jsx(_e,{delay:.7,hovered:i,reduced:a}),jsxRuntime.jsx(framerMotion.motion.span,{className:"bf-dot","aria-hidden":"true",style:{position:"relative",zIndex:1}})]}),jsxRuntime.jsx(framerMotion.AnimatePresence,{mode:"wait",children:i&&jsxRuntime.jsx(framerMotion.motion.span,{initial:{opacity:0,x:a?0:-6},animate:{opacity:1,x:0},exit:{opacity:0,x:a?0:-6},transition:s,style:{whiteSpace:"nowrap"},children:o},"label")}),r>0&&jsxRuntime.jsx("span",{className:"bf-badge","aria-label":`${r} queued`,children:r})]})},"pulse-ring")})}var $t={duration:.18,ease:"easeOut"},Ut={duration:0};function Xt(e){switch(e){case "bottom-left":return "bf-trigger-minimal bf-trigger-bl";case "top-right":return "bf-trigger-minimal bf-trigger-tr";case "top-left":return "bf-trigger-minimal bf-trigger-tl";default:return "bf-trigger-minimal"}}function $e({position:e,onClick:t,isVisible:n,label:o,queueCount:r,showSuccess:c}){let[i,l]=react.useState(false),a=g(),s=a?Ut:$t;return jsxRuntime.jsx(framerMotion.AnimatePresence,{mode:"wait",children:n&&jsxRuntime.jsxs(framerMotion.motion.button,{className:Xt(e),type:"button",onClick:t,onMouseEnter:()=>l(true),onMouseLeave:()=>l(false),"aria-label":o,initial:{opacity:0,y:a?0:5},animate:{opacity:i?1:.65,y:0},exit:{opacity:0,y:a?0:5},transition:s,whileTap:{scale:.95},children:[c?jsxRuntime.jsx("span",{style:{display:"inline-flex",color:"var(--bf-accent)"},children:jsxRuntime.jsx(b,{size:14})}):jsxRuntime.jsxs(jsxRuntime.Fragment,{children:[jsxRuntime.jsx("span",{children:o}),r>0&&jsxRuntime.jsx("span",{className:"bf-badge",style:{marginLeft:"4px"},"aria-label":`${r} queued`,children:r})]}),!a&&jsxRuntime.jsx(framerMotion.motion.span,{"aria-hidden":"true",style:{position:"absolute",bottom:4,left:4,right:4,height:"2px",background:"var(--bf-accent)",borderRadius:"1px",transformOrigin:"left"},initial:false,animate:{scaleX:i?1:0},transition:s})]},"minimal")})}var Qt={duration:.18,ease:"easeOut"},jt={duration:0};function Xe({position:e,onClick:t,isVisible:n,label:o,queueCount:r,showSuccess:c}){let[i,l]=react.useState(false),a=g(),s=a?jt:Qt;return jsxRuntime.jsx(framerMotion.AnimatePresence,{mode:"wait",children:n&&jsxRuntime.jsx(framerMotion.motion.button,{className:y(e),type:"button",onClick:t,onMouseEnter:()=>l(true),onMouseLeave:()=>l(false),"aria-label":o,initial:{scale:0,opacity:0},animate:{scale:1,opacity:1},exit:{scale:0,opacity:0},transition:s,whileTap:{scale:.9},style:{overflow:"hidden"},children:c?jsxRuntime.jsx(framerMotion.motion.span,{initial:{scale:0},animate:{scale:1},transition:s,style:{display:"inline-flex",color:"var(--bf-accent)"},children:jsxRuntime.jsx(b,{size:14})},"success"):jsxRuntime.jsxs(jsxRuntime.Fragment,{children:[jsxRuntime.jsx(framerMotion.motion.span,{style:{display:"inline-flex",flexShrink:0},animate:a?{}:i?{scale:1.2,rotate:0}:{rotate:[-5,5,-5]},transition:i||a?s:{duration:3,repeat:1/0,ease:"easeInOut"},children:jsxRuntime.jsx(Pe,{size:16})}),jsxRuntime.jsx(framerMotion.AnimatePresence,{mode:"wait",children:i&&jsxRuntime.jsx(framerMotion.motion.span,{initial:{opacity:0,x:a?0:-8},animate:{opacity:1,x:0},exit:{opacity:0,x:a?0:-8},transition:s,style:{whiteSpace:"nowrap"},children:o},"label")}),r>0&&jsxRuntime.jsx("span",{className:"bf-badge","aria-label":`${r} queued`,children:r})]})},"icon-pop")})}var Zt={duration:.18,ease:"easeOut"},eo={duration:0};function Qe({position:e,onClick:t,isVisible:n,label:o,queueCount:r,showSuccess:c}){let[i,l]=react.useState(false),a=g(),s=a?eo:Zt;return jsxRuntime.jsx(framerMotion.AnimatePresence,{mode:"wait",children:n&&jsxRuntime.jsx(framerMotion.motion.button,{className:y(e),type:"button",onClick:t,onMouseEnter:()=>l(true),onMouseLeave:()=>l(false),"aria-label":o,initial:{scale:0,opacity:0},animate:{scale:1,opacity:1},exit:{scale:0,opacity:0},transition:s,whileTap:{scale:.92},style:{overflow:"hidden"},children:c?jsxRuntime.jsx(framerMotion.motion.span,{initial:{scale:0},animate:{scale:1},transition:s,style:{display:"inline-flex",color:"var(--bf-accent)"},children:jsxRuntime.jsx(b,{size:14})},"success"):jsxRuntime.jsxs(jsxRuntime.Fragment,{children:[jsxRuntime.jsxs("span",{style:{position:"relative",display:"inline-flex",alignItems:"center",justifyContent:"center",width:"10px",height:"10px",flexShrink:0},children:[jsxRuntime.jsx(framerMotion.motion.span,{"aria-hidden":"true",style:{width:"10px",height:"10px",borderRadius:"50%",background:"var(--bf-accent)",position:"relative",zIndex:1},animate:a?{}:{opacity:i?1:[.5,1,.5],boxShadow:i?"0 0 8px 2px var(--bf-accent)":["0 0 4px 1px var(--bf-accent)","0 0 12px 4px var(--bf-accent)","0 0 4px 1px var(--bf-accent)"]},transition:i||a?s:{duration:2,repeat:1/0,ease:"easeInOut"}}),!i&&!a&&jsxRuntime.jsx(framerMotion.motion.span,{"aria-hidden":"true",style:{position:"absolute",width:"18px",height:"2px",background:"linear-gradient(90deg, var(--bf-accent), transparent)",transformOrigin:"left center",left:"5px",top:"4px"},animate:{rotate:[0,360]},transition:{duration:4,repeat:1/0,ease:"linear"}})]}),jsxRuntime.jsx(framerMotion.AnimatePresence,{mode:"wait",children:i&&jsxRuntime.jsx(framerMotion.motion.span,{initial:{opacity:0,x:a?0:-6},animate:{opacity:1,x:0},exit:{opacity:0,x:a?0:-6},transition:s,style:{whiteSpace:"nowrap"},children:o},"label")}),r>0&&jsxRuntime.jsx("span",{className:"bf-badge","aria-label":`${r} queued`,children:r})]})},"beacon")})}var io={duration:.18,ease:"easeOut"},no={duration:0};function Je({position:e,onClick:t,isVisible:n,label:o,queueCount:r,showSuccess:c}){let[i,l]=react.useState(false),[a,s]=react.useState(0),m=g(),M=m?no:io,p=react.useRef(null);react.useEffect(()=>{if(p.current&&(clearInterval(p.current),p.current=null),!n||i||m){s(i||m?o.length:0);return}let u=8,E=o.length*2+u*2,x=0;return p.current=setInterval(()=>{x=(x+1)%E,x<=o.length?s(x):x<=o.length+u?s(o.length):x<=o.length*2+u?s(o.length*2+u-x):s(0);},100),()=>{p.current&&(clearInterval(p.current),p.current=null);}},[n,i,m,o]);let T=o.slice(0,a);return jsxRuntime.jsx(framerMotion.AnimatePresence,{mode:"wait",children:n&&jsxRuntime.jsx(framerMotion.motion.button,{className:y(e),type:"button",onClick:t,onMouseEnter:()=>l(true),onMouseLeave:()=>l(false),"aria-label":o,initial:{opacity:0,y:m?0:5},animate:{opacity:1,y:0},exit:{opacity:0,y:m?0:5},transition:M,whileTap:{scale:.95},style:{minWidth:"44px"},children:c?jsxRuntime.jsx(framerMotion.motion.span,{initial:{scale:0},animate:{scale:1},transition:M,style:{display:"inline-flex",color:"var(--bf-accent)"},children:jsxRuntime.jsx(b,{size:14})},"success"):jsxRuntime.jsxs(jsxRuntime.Fragment,{children:[jsxRuntime.jsx("span",{className:"bf-dot","aria-hidden":"true"}),jsxRuntime.jsxs("span",{style:{whiteSpace:"nowrap",minWidth:"1ch"},children:[T,jsxRuntime.jsx("span",{className:"bf-cursor","aria-hidden":"true"})]}),r>0&&jsxRuntime.jsx("span",{className:"bf-badge","aria-label":`${r} queued`,children:r})]})},"typewriter")})}function Ze(e){switch(e){case "dot":return Be;case "bubble":return Le;case "edge-tab":return Ie;case "pulse-ring":return Oe;case "minimal":return $e;case "icon-pop":return Xe;case "beacon":return Qe;case "typewriter":return Je;default:return Ce}}function tt(e,t,n){return Math.max(t,Math.min(n,e))}function fo(e,t,n="bottom-right"){let r=window.innerWidth,c=window.innerHeight,i;i=tt(e.x,12,Math.max(12,r-t-12));let l=e.y+e.height+12,a=Math.max(12,e.y-240);return {top:l+240<=c?l:a,left:i}}function uo(e){let{rect:t}=e,n={left:`${t.x}px`,top:`${t.y}px`,width:`${Math.max(0,t.width)}px`,height:`${Math.max(0,t.height)}px`};return jsxRuntime.jsx("div",{className:"bf-highlight",style:n,"aria-hidden":"true"})}function bo(e){let t=react.useRef(null);return react.useEffect(()=>{if(!e||!t.current)return;t.current.querySelector(".bf-textarea")?.focus();let o=r=>{if(r.key!=="Tab"||!t.current)return;let c=t.current.querySelectorAll('button:not([disabled]), textarea:not([disabled]), input:not([disabled]), [tabindex]:not([tabindex="-1"])');if(c.length===0)return;let i=c[0],l=c[c.length-1];r.shiftKey&&document.activeElement===i?(r.preventDefault(),l.focus()):!r.shiftKey&&document.activeElement===l&&(r.preventDefault(),i.focus());};return document.addEventListener("keydown",o,{capture:true}),()=>document.removeEventListener("keydown",o,{capture:true})},[e]),t}function go(e,t){return e?typeof e=="function"?e(t):e.some(n=>n.endsWith("*")?t.startsWith(n.slice(0,-1)):t===n):true}function mo(e){let[t,n]=react.useState(()=>typeof window<"u"?window.location.pathname:"/");return react.useEffect(()=>{if(typeof window>"u")return;let o=()=>n(window.location.pathname);window.addEventListener("popstate",o);let r=history.pushState,c=history.replaceState;return history.pushState=function(...i){r.apply(this,i),o();},history.replaceState=function(...i){c.apply(this,i),o();},()=>{window.removeEventListener("popstate",o),history.pushState=r,history.replaceState=c;}},[]),go(e,t)}function ho(e){let[t,n]=react.useState(()=>!e||e==="dark"?"dark":e==="light"?"light":typeof window<"u"&&window.matchMedia("(prefers-color-scheme: dark)").matches?"dark":"light");return react.useEffect(()=>{if(e!=="auto"){n(e==="light"?"light":"dark");return}let o=window.matchMedia("(prefers-color-scheme: dark)"),r=c=>n(c.matches?"dark":"light");return n(o.matches?"dark":"light"),o.addEventListener("change",r),()=>o.removeEventListener("change",r)},[e]),t}var xo=["bug","feature","ux","general"],yo={bug:"categoryBug",feature:"categoryFeature",ux:"categoryUx",general:"categoryGeneral"};function wo(e){let{state:t,controller:n,start:o,stop:r,clearSelection:c,submit:i}=te(),l=e.config.ui?.position,a=Te(e.config.ui?.strings),s=e.config.ui?.branding!==false,[m,M]=react.useState(null),[p,T]=react.useState(""),[u,E]=react.useState(e.config.capture?.element??true),[x,re]=react.useState(e.config.capture?.fullPage??false),[rt,ae]=react.useState(null),[O,ie]=react.useState(void 0),ne=e.config.ui?.categories??xo,[at,it]=react.useState(false),[j,nt]=react.useState(0);react.useEffect(()=>{let d=window.setTimeout(()=>{let N=chunkJVY6JTXP_cjs.p();nt(N.findings.length);},500);return ()=>window.clearTimeout(d)},[]),react.useImperativeHandle(e.handleRef,()=>({open:o,close:r,submit:d=>i(d),get isOpen(){return t.phase!=="idle"}}),[o,r,i,t.phase]);let se=t.phase==="review"||t.phase==="capturing"||t.phase==="submitting"||t.phase==="error"||t.phase==="success",st=bo(se),[lt,ct]=react.useState(0);react.useEffect(()=>{t.phase==="idle"&&ct(chunkJVY6JTXP_cjs.i());},[t.phase]);let[dt,le]=react.useState(false),ce=react.useRef(t.phase);react.useEffect(()=>{if(ce.current==="success"&&t.phase==="idle"){le(true);let d=window.setTimeout(()=>le(false),1500);return ()=>window.clearTimeout(d)}ce.current=t.phase;},[t.phase]),react.useEffect(()=>{let d=e.config.ui?.shortcut;if(!d)return;let N=d.toLowerCase().split("+").map(P=>P.trim()),W=N[N.length-1]||"",L=new Set(N.slice(0,-1)),pe=P=>{let ut=/Mac|iPod|iPhone|iPad/.test(navigator.platform);if(L.has("mod")){if(ut?!P.metaKey:!P.ctrlKey)return}else if(L.has("ctrl")&&!P.ctrlKey||(L.has("meta")||L.has("cmd"))&&!P.metaKey)return;L.has("shift")&&!P.shiftKey||(L.has("alt")||L.has("option"))&&!P.altKey||P.key.toLowerCase()===W&&(P.preventDefault(),t.phase==="idle"?o():r());};return document.addEventListener("keydown",pe),()=>document.removeEventListener("keydown",pe)},[e.config.ui?.shortcut,t.phase,o,r]),react.useEffect(()=>n.subscribeHover(M),[n]),react.useEffect(()=>{let d=n.__unsafeGetSelectedElement();if(!d||t.phase==="idle"||t.phase==="picking"){ae(null);return}let N=()=>{ae(chunkJVY6JTXP_cjs.b(d.getBoundingClientRect()));};N();let W=()=>N();return window.addEventListener("scroll",W,{capture:true,passive:true}),window.addEventListener("resize",W,{passive:true}),()=>{window.removeEventListener("scroll",W,{capture:true}),window.removeEventListener("resize",W);}},[n,t.phase,t.selection?.selector]),react.useEffect(()=>{t.phase==="review"&&(T(""),E(e.config.capture?.element??true),re(e.config.capture?.fullPage??false),ie(void 0));},[t.phase,t.selection?.selector,e.config.capture?.element,e.config.capture?.fullPage]),react.useEffect(()=>{if(t.phase!=="success")return;let d=window.setTimeout(()=>r(),1200);return ()=>window.clearTimeout(d)},[t.phase,r]);let S=t.phase==="capturing"||t.phase==="submitting",B=t.phase==="picking"?m?.rect??null:rt??t.selection?.rect??null,V=react.useMemo(()=>B?fo(B,360,l):null,[B?.x,B?.y,B?.width,B?.height,l]),de=t.lastError?.message,q=react.useCallback(()=>{let d={capture:{element:u,fullPage:x}};O&&(d.category=O),i(p,d);},[i,p,u,x,O]),pt=react.useCallback(d=>{(d.metaKey||d.ctrlKey)&&d.key==="Enter"&&p.trim().length>0&&!S&&(d.preventDefault(),q());},[q,p,S]),ft=Ze(e.config.ui?.triggerStyle);return jsxRuntime.jsxs(jsxRuntime.Fragment,{children:[jsxRuntime.jsx(ft,{position:l,onClick:()=>o(),isVisible:t.phase==="idle",label:e.config.ui?.triggerLabel??a.triggerLabel,queueCount:lt,showSuccess:dt}),t.phase!=="idle"&&jsxRuntime.jsxs("div",{className:"bf-overlay",role:"presentation",children:[t.phase!=="picking"&&jsxRuntime.jsx("div",{className:"bf-blocker",role:"presentation",onClick:()=>r()}),B&&jsxRuntime.jsx(uo,{rect:B}),t.phase==="picking"&&jsxRuntime.jsxs("div",{className:"bf-hint",role:"status","aria-live":"polite",children:[jsxRuntime.jsx("p",{id:"bf-hint-text",children:a.hintText}),jsxRuntime.jsx("button",{type:"button",className:"bf-btn",onClick:()=>r(),"aria-label":a.cancelButton,children:a.cancelButton})]}),se&&V&&jsxRuntime.jsxs("div",{ref:st,className:"bf-panel",style:{left:V.left,top:V.top},role:"dialog","aria-modal":"true","aria-label":"Feedback form",children:[jsxRuntime.jsxs("div",{className:"bf-panelHeader",children:[jsxRuntime.jsx("div",{className:"bf-title",id:"bf-panel-title",children:a.panelTitle}),jsxRuntime.jsxs("div",{className:"bf-row",style:{justifyContent:"flex-end"},children:[jsxRuntime.jsx("button",{type:"button",className:"bf-btn",onClick:()=>c(),disabled:S,"aria-label":a.rePickButton,children:a.rePickButton}),jsxRuntime.jsx("button",{type:"button",className:"bf-btn",onClick:()=>r(),disabled:S,"aria-label":a.closeButton,children:a.closeButton})]})]}),jsxRuntime.jsxs("div",{className:"bf-panelBody",children:[jsxRuntime.jsx("textarea",{className:"bf-textarea",placeholder:a.textareaPlaceholder,value:p,onChange:d=>T(d.target.value),onKeyDown:pt,disabled:S,"aria-label":a.panelTitle}),ne.length>0&&jsxRuntime.jsx("div",{className:"bf-pills",role:"group","aria-label":"Feedback category",children:ne.map(d=>jsxRuntime.jsx("button",{type:"button",className:`bf-pill${O===d?" bf-pill-active":""}`,onClick:()=>ie(O===d?void 0:d),disabled:S,children:a[yo[d]]},d))}),jsxRuntime.jsxs("div",{className:"bf-row",role:"group","aria-label":a.screenshotElement,children:[jsxRuntime.jsxs("label",{children:[jsxRuntime.jsx("input",{type:"checkbox",checked:u,onChange:d=>E(d.target.checked),disabled:S}),a.screenshotElement]}),jsxRuntime.jsxs("label",{children:[jsxRuntime.jsx("input",{type:"checkbox",checked:x,onChange:d=>re(d.target.checked),disabled:S}),a.screenshotFullPage]})]}),t.phase==="capturing"&&jsxRuntime.jsxs("div",{className:"bf-status",role:"status","aria-live":"polite",children:[jsxRuntime.jsx("span",{className:"bf-spinner","aria-hidden":"true"}),a.capturingText]}),t.phase==="submitting"&&jsxRuntime.jsxs("div",{className:"bf-status",role:"status","aria-live":"polite",children:[jsxRuntime.jsx("span",{className:"bf-spinner","aria-hidden":"true"}),a.submittingText]}),t.phase==="success"&&jsxRuntime.jsx("div",{className:"bf-status",role:"status","aria-live":"polite",children:a.successText}),t.phase==="error"&&de&&jsxRuntime.jsx("div",{className:"bf-error",role:"alert",children:de}),jsxRuntime.jsxs("div",{className:"bf-actions",children:[jsxRuntime.jsx("button",{type:"button",className:"bf-btn",onClick:()=>r(),disabled:S,"aria-label":a.cancelButton,children:a.cancelButton}),jsxRuntime.jsx("button",{type:"button",className:"bf-btn bf-btnPrimary",onClick:q,disabled:S||p.trim().length===0,"aria-label":a.sendButton,children:a.sendButton})]})]}),s&&jsxRuntime.jsx("div",{className:"bf-watermark",children:jsxRuntime.jsx("a",{href:"https://blocfeed.com",target:"_blank",rel:"noopener noreferrer",children:"Powered by BlocFeed"})})]})]}),t.phase==="success"&&jsxRuntime.jsx("div",{className:"bf-toast",role:"status","aria-live":"polite",children:a.toastText}),j>0&&!at&&jsxRuntime.jsxs("div",{className:"bf-security-banner",role:"alert",children:[jsxRuntime.jsx("button",{type:"button",className:"bf-security-banner-dismiss",onClick:()=>it(true),"aria-label":"Dismiss",children:"\xD7"}),jsxRuntime.jsx("strong",{children:"Security Warning"}),j," potential secret",j>1?"s":""," exposed in client code. Check your environment variables."]})]})}var vo=react.forwardRef(function(t,n){let o={...t.config??{},blocfeed_id:t.blocfeed_id},[r,c]=react.useState(null),i=mo(o.ui?.showOn),l=ho(o.ui?.theme?.mode),a=!!o.diagnostics;react.useEffect(()=>{if(a)return chunkJVY6JTXP_cjs.k(o.diagnostics),()=>chunkJVY6JTXP_cjs.l()},[a]);let s=!!o.security;react.useEffect(()=>{s&&chunkJVY6JTXP_cjs.o(o.security);},[s]);let m=react.useRef(t.config?.metadata?.enrich);m.current=t.config?.metadata?.enrich;let M=react.useMemo(()=>{if(t.config)return {...t.config,metadata:{...t.config.metadata,enrich:async p=>{let T=m.current,u=T?await T(p):{},E=chunkJVY6JTXP_cjs.m(),x=chunkJVY6JTXP_cjs.p();return {...u,...E.consoleLogs.length>0?{_consoleLogs:E.consoleLogs}:{},...E.networkErrors.length>0?{_networkErrors:E.networkErrors}:{},...x.findings.length>0?{_securityFindings:x.findings}:{}}}}}},[]);return react.useEffect(()=>{ve();let p=document.createElement("div");p.setAttribute("data-blocfeed-ui-root","true"),p.setAttribute("data-blocfeed-ui","true"),p.setAttribute("data-bf-theme",l);let T=o.ui?.zIndex;typeof T=="number"&&p.style.setProperty("--bf-z",String(T));let u=o.ui?.theme;return u&&(u.accentColor&&p.style.setProperty("--bf-accent",u.accentColor),u.panelBackground&&p.style.setProperty("--bf-panel-bg",u.panelBackground),u.panelForeground&&p.style.setProperty("--bf-panel-fg",u.panelForeground),u.fontFamily&&p.style.setProperty("--bf-font",u.fontFamily)),document.body.appendChild(p),c(p),()=>{p.remove(),c(null);}},[o.ui?.zIndex,o.ui?.theme?.accentColor,o.ui?.theme?.panelBackground,o.ui?.theme?.panelForeground,o.ui?.theme?.fontFamily,l]),react.useEffect(()=>{r&&r.setAttribute("data-bf-theme",l);},[r,l]),!i||!r?null:reactDom.createPortal(jsxRuntime.jsx(ee,{blocfeed_id:o.blocfeed_id,...M?{config:M}:{},children:jsxRuntime.jsx(wo,{config:o,handleRef:n})}),r)});
|
|
639
|
-
exports.BlocFeedProvider=ee;exports.BlocFeedWidget=
|
|
741
|
+
`;function Te(){if(!chunkORVW2RTZ_cjs.a()||document.getElementById(ke))return;let e=document.createElement("style");e.id=ke,e.textContent=kt,document.head.appendChild(e);}var Se={triggerLabel:"Feedback",panelTitle:"Feedback",hintText:"Click an element to attach your feedback. Press Esc to cancel.",cancelButton:"Cancel",rePickButton:"Re-pick",closeButton:"Close",textareaPlaceholder:"What's happening? What did you expect?",screenshotElement:"Screenshot element",screenshotFullPage:"Full page",capturingText:"Capturing screenshots\u2026",submittingText:"Submitting\u2026",successText:"Sent. Thank you!",toastText:"Feedback sent",sendButton:"Send",categoryBug:"Bug",categoryFeature:"Feature",categoryUx:"UX",categoryGeneral:"General",recordButton:"Record",stopRecordButton:"Stop",recordingText:"Recording\u2026",recordingDeniedText:"Screen share was denied",videoPreviewLabel:"Video attached",removeVideoButton:"Remove"};function Pe(e){return e?{...Se,...e}:Se}function te(){let e=react.useContext(V);if(!e)throw new Error("useBlocFeed must be used within a <BlocFeedProvider />");return {state:e.state,controller:e.controller,start:e.controller.start,stop:e.controller.stop,clearSelection:e.controller.clearSelection,submit:e.controller.submit,startRecording:e.controller.startRecording,stopRecording:e.controller.stopRecording,removeVideo:e.controller.removeVideo}}function v(e){switch(e){case "bottom-left":return "bf-trigger bf-trigger-bl";case "top-right":return "bf-trigger bf-trigger-tr";case "top-left":return "bf-trigger bf-trigger-tl";default:return "bf-trigger"}}function g({size:e=14}){return jsxRuntime.jsx("svg",{width:e,height:e,viewBox:"0 0 24 24",fill:"none",xmlns:"http://www.w3.org/2000/svg","aria-hidden":"true",children:jsxRuntime.jsx("path",{d:"M20 6L9 17l-5-5",stroke:"currentColor",strokeWidth:"2.5",strokeLinecap:"round",strokeLinejoin:"round"})})}function Ce({size:e=14}){return jsxRuntime.jsx("svg",{width:e,height:e,viewBox:"0 0 24 24",fill:"none",xmlns:"http://www.w3.org/2000/svg","aria-hidden":"true",children:jsxRuntime.jsx("path",{d:"M21 11.5a8.38 8.38 0 01-.9 3.8 8.5 8.5 0 01-7.6 4.7 8.38 8.38 0 01-3.8-.9L3 21l1.9-5.7a8.38 8.38 0 01-.9-3.8 8.5 8.5 0 014.7-7.6 8.38 8.38 0 013.8-.9h.5a8.48 8.48 0 018 8v.5z",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round"})})}function Ee({size:e=16}){return jsxRuntime.jsxs("svg",{width:e,height:e,viewBox:"0 0 24 24",fill:"none",xmlns:"http://www.w3.org/2000/svg","aria-hidden":"true",children:[jsxRuntime.jsx("path",{d:"M4 4h16c1.1 0 2 .9 2 2v12c0 1.1-.9 2-2 2H4c-1.1 0-2-.9-2-2V6c0-1.1.9-2 2-2z",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round"}),jsxRuntime.jsx("path",{d:"M22 6l-10 7L2 6",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round"})]})}function Fe({position:e,onClick:t,isVisible:i,label:o,queueCount:a,showSuccess:l}){return i?jsxRuntime.jsxs("button",{className:v(e),type:"button",onClick:t,"aria-label":o,children:[l?jsxRuntime.jsx("span",{style:{display:"inline-flex",color:"var(--bf-accent)"},children:jsxRuntime.jsx(g,{size:14})}):jsxRuntime.jsxs(jsxRuntime.Fragment,{children:[jsxRuntime.jsx("span",{className:"bf-dot","aria-hidden":"true"}),o]}),a>0&&jsxRuntime.jsx("span",{className:"bf-badge","aria-label":`${a} queued`,children:a})]}):null}function m(){let[e,t]=react.useState(()=>typeof window>"u"?false:window.matchMedia("(prefers-reduced-motion: reduce)").matches);return react.useEffect(()=>{let i=window.matchMedia("(prefers-reduced-motion: reduce)"),o=a=>t(a.matches);return i.addEventListener("change",o),()=>i.removeEventListener("change",o)},[]),e}var Ft={duration:.18,ease:"easeOut"},Nt={duration:0};function Re({position:e,onClick:t,isVisible:i,label:o,queueCount:a,showSuccess:l}){let[n,c]=react.useState(false),r=m(),s=r?Nt:Ft;return jsxRuntime.jsx(framerMotion.AnimatePresence,{mode:"wait",children:i&&jsxRuntime.jsx(framerMotion.motion.button,{className:v(e),type:"button",onClick:t,onMouseEnter:()=>c(true),onMouseLeave:()=>c(false),"aria-label":o,initial:{scale:0,opacity:0},animate:{scale:1,opacity:1},exit:{scale:0,opacity:0},transition:s,whileTap:{scale:.92},style:{overflow:"hidden"},children:l?jsxRuntime.jsx(framerMotion.motion.span,{initial:{scale:0},animate:{scale:1},transition:s,style:{display:"inline-flex",color:"var(--bf-accent)"},children:jsxRuntime.jsx(g,{size:14})},"success"):jsxRuntime.jsxs(jsxRuntime.Fragment,{children:[jsxRuntime.jsx(framerMotion.motion.span,{className:"bf-dot","aria-hidden":"true",animate:r?{}:{scale:n?1:[1,1.2,1],boxShadow:n?"0 0 0 4px rgba(99, 102, 241, 0.18)":["0 0 0 4px rgba(99, 102, 241, 0.18)","0 0 0 8px rgba(99, 102, 241, 0.28)","0 0 0 4px rgba(99, 102, 241, 0.18)"]},transition:n||r?s:{duration:2,repeat:1/0,ease:"easeInOut"}}),jsxRuntime.jsx(framerMotion.AnimatePresence,{mode:"wait",children:n&&jsxRuntime.jsx(framerMotion.motion.span,{initial:{opacity:0,x:r?0:-6},animate:{opacity:1,x:0},exit:{opacity:0,x:r?0:-6},transition:s,style:{whiteSpace:"nowrap"},children:o},"label")}),a>0&&jsxRuntime.jsx("span",{className:"bf-badge","aria-label":`${a} queued`,children:a})]})},"dot")})}var zt={duration:.18,ease:"easeOut"},Le={duration:0};function Ae({position:e,onClick:t,isVisible:i,label:o,queueCount:a,showSuccess:l}){let[n,c]=react.useState(false),r=m(),s=r?Le:zt;return jsxRuntime.jsx(framerMotion.AnimatePresence,{mode:"wait",children:i&&jsxRuntime.jsxs(framerMotion.motion.div,{className:v(e),initial:{scale:0,opacity:0},animate:{scale:1,opacity:1},exit:{y:8,opacity:0},transition:s,onMouseEnter:()=>c(true),onMouseLeave:()=>c(false),style:{background:"transparent",border:"none",boxShadow:"none",padding:0},children:[jsxRuntime.jsx(framerMotion.AnimatePresence,{mode:"wait",children:n&&jsxRuntime.jsx(framerMotion.motion.div,{initial:{opacity:0,y:r?0:4},animate:{opacity:1,y:0},exit:{opacity:0,y:r?0:4},transition:s,style:{position:"absolute",bottom:"calc(100% + 8px)",left:"50%",transform:"translateX(-50%)",padding:"6px 12px",borderRadius:"8px",background:"var(--bf-panel-bg)",border:"1px solid var(--bf-border)",boxShadow:"var(--bf-shadow)",whiteSpace:"nowrap",fontSize:"12px",color:"var(--bf-panel-fg)",pointerEvents:"none"},children:o},"tooltip")}),jsxRuntime.jsxs(framerMotion.motion.button,{type:"button",onClick:t,"aria-label":o,style:{position:"relative",display:"flex",alignItems:"center",justifyContent:"center",width:"40px",height:"40px",borderRadius:"50%",border:"1px solid var(--bf-border)",background:"var(--bf-panel-bg)",color:"var(--bf-panel-fg)",boxShadow:"var(--bf-shadow)",cursor:"pointer",padding:0},animate:r?{}:{y:[0,-3,0]},transition:r?Le:{y:{duration:3,repeat:1/0,ease:"easeInOut"}},whileHover:{scale:1.1,borderColor:"var(--bf-accent)"},whileTap:{scale:.9},children:[l?jsxRuntime.jsx(framerMotion.motion.span,{initial:{scale:0},animate:{scale:1},transition:s,style:{display:"inline-flex",color:"var(--bf-accent)"},children:jsxRuntime.jsx(g,{size:16})},"success"):jsxRuntime.jsx(Ce,{size:16}),a>0&&jsxRuntime.jsx("span",{className:"bf-badge bf-badge-float","aria-label":`${a} queued`,children:a})]})]},"bubble")})}var Wt={duration:.2,ease:"easeOut"},_t={duration:0};function We(e){return e==="bottom-left"||e==="top-left"}function Ht(e){return `bf-trigger-edge ${We(e)?"bf-trigger-edge-left":"bf-trigger-edge-right"}`}function _e({position:e,onClick:t,isVisible:i,label:o,queueCount:a,showSuccess:l}){let[n,c]=react.useState(false),r=We(e),s=m(),h=s?_t:Wt;return jsxRuntime.jsx(framerMotion.AnimatePresence,{mode:"wait",children:i&&jsxRuntime.jsx(framerMotion.motion.button,{className:Ht(e),type:"button",onClick:t,onMouseEnter:()=>c(true),onMouseLeave:()=>c(false),"aria-label":o,initial:{opacity:0,width:0},animate:{opacity:1,width:n?140:22,height:n?40:90},exit:{width:0,opacity:0},transition:h,whileTap:{scale:.97},style:{top:"50%",translateY:"-50%"},children:l?jsxRuntime.jsx(framerMotion.motion.span,{initial:{scale:0},animate:{scale:1},transition:h,style:{display:"inline-flex",color:"var(--bf-accent)"},children:jsxRuntime.jsx(g,{size:14})},"success"):jsxRuntime.jsxs(jsxRuntime.Fragment,{children:[jsxRuntime.jsxs(framerMotion.motion.span,{animate:{rotate:s||n?0:r?-90:90,opacity:n?1:.6},transition:h,style:{display:"flex",alignItems:"center",gap:"8px",whiteSpace:"nowrap",fontSize:"12px",letterSpacing:"0.5px",textTransform:"uppercase"},children:[n&&jsxRuntime.jsx(framerMotion.motion.span,{initial:{scale:0},animate:{scale:1},transition:{duration:.12},style:{width:"6px",height:"6px",borderRadius:"50%",background:"var(--bf-accent)",flexShrink:0}}),o]}),jsxRuntime.jsx(framerMotion.motion.span,{"aria-hidden":"true",animate:{opacity:n?1:0},transition:{duration:.12},style:{position:"absolute",top:0,bottom:0,[r?"left":"right"]:0,width:"2px",background:"var(--bf-accent)"}}),a>0&&jsxRuntime.jsx("span",{className:"bf-badge","aria-label":`${a} queued`,children:a})]})},"edge-tab")})}var $t={duration:.18,ease:"easeOut"},Kt={duration:0};function Oe({delay:e,hovered:t,reduced:i}){return i?null:jsxRuntime.jsx(framerMotion.motion.span,{"aria-hidden":"true",style:{position:"absolute",width:"10px",height:"10px",borderRadius:"50%",border:"2px solid var(--bf-accent)",pointerEvents:"none"},animate:t?{scale:1,opacity:0}:{scale:[1,1.8],opacity:[.5,0]},transition:t?{duration:.15}:{duration:2,repeat:1/0,delay:e,ease:"easeOut"}})}function $e({position:e,onClick:t,isVisible:i,label:o,queueCount:a,showSuccess:l}){let[n,c]=react.useState(false),r=m(),s=r?Kt:$t;return jsxRuntime.jsx(framerMotion.AnimatePresence,{mode:"wait",children:i&&jsxRuntime.jsx(framerMotion.motion.button,{className:v(e),type:"button",onClick:t,onMouseEnter:()=>c(true),onMouseLeave:()=>c(false),"aria-label":o,initial:{scale:0,opacity:0},animate:{scale:1,opacity:1},exit:{scale:0,opacity:0},transition:s,whileTap:{scale:.92},style:{overflow:"hidden"},children:l?jsxRuntime.jsx(framerMotion.motion.span,{initial:{scale:0},animate:{scale:1},transition:s,style:{display:"inline-flex",color:"var(--bf-accent)"},children:jsxRuntime.jsx(g,{size:14})},"success"):jsxRuntime.jsxs(jsxRuntime.Fragment,{children:[jsxRuntime.jsxs("span",{style:{position:"relative",display:"flex",alignItems:"center",justifyContent:"center",width:"10px",height:"10px",flexShrink:0},children:[jsxRuntime.jsx(Oe,{delay:0,hovered:n,reduced:r}),jsxRuntime.jsx(Oe,{delay:.7,hovered:n,reduced:r}),jsxRuntime.jsx(framerMotion.motion.span,{className:"bf-dot","aria-hidden":"true",style:{position:"relative",zIndex:1}})]}),jsxRuntime.jsx(framerMotion.AnimatePresence,{mode:"wait",children:n&&jsxRuntime.jsx(framerMotion.motion.span,{initial:{opacity:0,x:r?0:-6},animate:{opacity:1,x:0},exit:{opacity:0,x:r?0:-6},transition:s,style:{whiteSpace:"nowrap"},children:o},"label")}),a>0&&jsxRuntime.jsx("span",{className:"bf-badge","aria-label":`${a} queued`,children:a})]})},"pulse-ring")})}var Yt={duration:.18,ease:"easeOut"},Gt={duration:0};function jt(e){switch(e){case "bottom-left":return "bf-trigger-minimal bf-trigger-bl";case "top-right":return "bf-trigger-minimal bf-trigger-tr";case "top-left":return "bf-trigger-minimal bf-trigger-tl";default:return "bf-trigger-minimal"}}function Ue({position:e,onClick:t,isVisible:i,label:o,queueCount:a,showSuccess:l}){let[n,c]=react.useState(false),r=m(),s=r?Gt:Yt;return jsxRuntime.jsx(framerMotion.AnimatePresence,{mode:"wait",children:i&&jsxRuntime.jsxs(framerMotion.motion.button,{className:jt(e),type:"button",onClick:t,onMouseEnter:()=>c(true),onMouseLeave:()=>c(false),"aria-label":o,initial:{opacity:0,y:r?0:5},animate:{opacity:n?1:.65,y:0},exit:{opacity:0,y:r?0:5},transition:s,whileTap:{scale:.95},children:[l?jsxRuntime.jsx("span",{style:{display:"inline-flex",color:"var(--bf-accent)"},children:jsxRuntime.jsx(g,{size:14})}):jsxRuntime.jsxs(jsxRuntime.Fragment,{children:[jsxRuntime.jsx("span",{children:o}),a>0&&jsxRuntime.jsx("span",{className:"bf-badge",style:{marginLeft:"4px"},"aria-label":`${a} queued`,children:a})]}),!r&&jsxRuntime.jsx(framerMotion.motion.span,{"aria-hidden":"true",style:{position:"absolute",bottom:4,left:4,right:4,height:"2px",background:"var(--bf-accent)",borderRadius:"1px",transformOrigin:"left"},initial:false,animate:{scaleX:n?1:0},transition:s})]},"minimal")})}var Jt={duration:.18,ease:"easeOut"},Zt={duration:0};function Ye({position:e,onClick:t,isVisible:i,label:o,queueCount:a,showSuccess:l}){let[n,c]=react.useState(false),r=m(),s=r?Zt:Jt;return jsxRuntime.jsx(framerMotion.AnimatePresence,{mode:"wait",children:i&&jsxRuntime.jsx(framerMotion.motion.button,{className:v(e),type:"button",onClick:t,onMouseEnter:()=>c(true),onMouseLeave:()=>c(false),"aria-label":o,initial:{scale:0,opacity:0},animate:{scale:1,opacity:1},exit:{scale:0,opacity:0},transition:s,whileTap:{scale:.9},style:{overflow:"hidden"},children:l?jsxRuntime.jsx(framerMotion.motion.span,{initial:{scale:0},animate:{scale:1},transition:s,style:{display:"inline-flex",color:"var(--bf-accent)"},children:jsxRuntime.jsx(g,{size:14})},"success"):jsxRuntime.jsxs(jsxRuntime.Fragment,{children:[jsxRuntime.jsx(framerMotion.motion.span,{style:{display:"inline-flex",flexShrink:0},animate:r?{}:n?{scale:1.2,rotate:0}:{rotate:[-5,5,-5]},transition:n||r?s:{duration:3,repeat:1/0,ease:"easeInOut"},children:jsxRuntime.jsx(Ee,{size:16})}),jsxRuntime.jsx(framerMotion.AnimatePresence,{mode:"wait",children:n&&jsxRuntime.jsx(framerMotion.motion.span,{initial:{opacity:0,x:r?0:-8},animate:{opacity:1,x:0},exit:{opacity:0,x:r?0:-8},transition:s,style:{whiteSpace:"nowrap"},children:o},"label")}),a>0&&jsxRuntime.jsx("span",{className:"bf-badge","aria-label":`${a} queued`,children:a})]})},"icon-pop")})}var ro={duration:.18,ease:"easeOut"},ao={duration:0};function Qe({position:e,onClick:t,isVisible:i,label:o,queueCount:a,showSuccess:l}){let[n,c]=react.useState(false),r=m(),s=r?ao:ro;return jsxRuntime.jsx(framerMotion.AnimatePresence,{mode:"wait",children:i&&jsxRuntime.jsx(framerMotion.motion.button,{className:v(e),type:"button",onClick:t,onMouseEnter:()=>c(true),onMouseLeave:()=>c(false),"aria-label":o,initial:{scale:0,opacity:0},animate:{scale:1,opacity:1},exit:{scale:0,opacity:0},transition:s,whileTap:{scale:.92},style:{overflow:"hidden"},children:l?jsxRuntime.jsx(framerMotion.motion.span,{initial:{scale:0},animate:{scale:1},transition:s,style:{display:"inline-flex",color:"var(--bf-accent)"},children:jsxRuntime.jsx(g,{size:14})},"success"):jsxRuntime.jsxs(jsxRuntime.Fragment,{children:[jsxRuntime.jsxs("span",{style:{position:"relative",display:"inline-flex",alignItems:"center",justifyContent:"center",width:"10px",height:"10px",flexShrink:0},children:[jsxRuntime.jsx(framerMotion.motion.span,{"aria-hidden":"true",style:{width:"10px",height:"10px",borderRadius:"50%",background:"var(--bf-accent)",position:"relative",zIndex:1},animate:r?{}:{opacity:n?1:[.5,1,.5],boxShadow:n?"0 0 8px 2px var(--bf-accent)":["0 0 4px 1px var(--bf-accent)","0 0 12px 4px var(--bf-accent)","0 0 4px 1px var(--bf-accent)"]},transition:n||r?s:{duration:2,repeat:1/0,ease:"easeInOut"}}),!n&&!r&&jsxRuntime.jsx(framerMotion.motion.span,{"aria-hidden":"true",style:{position:"absolute",width:"18px",height:"2px",background:"linear-gradient(90deg, var(--bf-accent), transparent)",transformOrigin:"left center",left:"5px",top:"4px"},animate:{rotate:[0,360]},transition:{duration:4,repeat:1/0,ease:"linear"}})]}),jsxRuntime.jsx(framerMotion.AnimatePresence,{mode:"wait",children:n&&jsxRuntime.jsx(framerMotion.motion.span,{initial:{opacity:0,x:r?0:-6},animate:{opacity:1,x:0},exit:{opacity:0,x:r?0:-6},transition:s,style:{whiteSpace:"nowrap"},children:o},"label")}),a>0&&jsxRuntime.jsx("span",{className:"bf-badge","aria-label":`${a} queued`,children:a})]})},"beacon")})}var lo={duration:.18,ease:"easeOut"},po={duration:0};function et({position:e,onClick:t,isVisible:i,label:o,queueCount:a,showSuccess:l}){let[n,c]=react.useState(false),[r,s]=react.useState(0),h=m(),M=h?po:lo,f=react.useRef(null);react.useEffect(()=>{if(f.current&&(clearInterval(f.current),f.current=null),!i||n||h){s(n||h?o.length:0);return}let u=8,C=o.length*2+u*2,y=0;return f.current=setInterval(()=>{y=(y+1)%C,y<=o.length?s(y):y<=o.length+u?s(o.length):y<=o.length*2+u?s(o.length*2+u-y):s(0);},100),()=>{f.current&&(clearInterval(f.current),f.current=null);}},[i,n,h,o]);let S=o.slice(0,r);return jsxRuntime.jsx(framerMotion.AnimatePresence,{mode:"wait",children:i&&jsxRuntime.jsx(framerMotion.motion.button,{className:v(e),type:"button",onClick:t,onMouseEnter:()=>c(true),onMouseLeave:()=>c(false),"aria-label":o,initial:{opacity:0,y:h?0:5},animate:{opacity:1,y:0},exit:{opacity:0,y:h?0:5},transition:M,whileTap:{scale:.95},style:{minWidth:"44px"},children:l?jsxRuntime.jsx(framerMotion.motion.span,{initial:{scale:0},animate:{scale:1},transition:M,style:{display:"inline-flex",color:"var(--bf-accent)"},children:jsxRuntime.jsx(g,{size:14})},"success"):jsxRuntime.jsxs(jsxRuntime.Fragment,{children:[jsxRuntime.jsx("span",{className:"bf-dot","aria-hidden":"true"}),jsxRuntime.jsxs("span",{style:{whiteSpace:"nowrap",minWidth:"1ch"},children:[S,jsxRuntime.jsx("span",{className:"bf-cursor","aria-hidden":"true"})]}),a>0&&jsxRuntime.jsx("span",{className:"bf-badge","aria-label":`${a} queued`,children:a})]})},"typewriter")})}function tt(e){switch(e){case "dot":return Re;case "bubble":return Ae;case "edge-tab":return _e;case "pulse-ring":return $e;case "minimal":return Ue;case "icon-pop":return Ye;case "beacon":return Qe;case "typewriter":return et;default:return Fe}}function rt(e,t,i){return Math.max(t,Math.min(i,e))}function mo(e,t,i="bottom-right"){let a=window.innerWidth,l=window.innerHeight,n;n=rt(e.x,12,Math.max(12,a-t-12));let c=e.y+e.height+12,r=Math.max(12,e.y-240);return {top:c+240<=l?c:r,left:n}}function ho(e){let{rect:t}=e,i={left:`${t.x}px`,top:`${t.y}px`,width:`${Math.max(0,t.width)}px`,height:`${Math.max(0,t.height)}px`};return jsxRuntime.jsx("div",{className:"bf-highlight",style:i,"aria-hidden":"true"})}function xo(e){let t=react.useRef(null);return react.useEffect(()=>{if(!e||!t.current)return;t.current.querySelector(".bf-textarea")?.focus();let o=a=>{if(a.key!=="Tab"||!t.current)return;let l=t.current.querySelectorAll('button:not([disabled]), textarea:not([disabled]), input:not([disabled]), [tabindex]:not([tabindex="-1"])');if(l.length===0)return;let n=l[0],c=l[l.length-1];a.shiftKey&&document.activeElement===n?(a.preventDefault(),c.focus()):!a.shiftKey&&document.activeElement===c&&(a.preventDefault(),n.focus());};return document.addEventListener("keydown",o,{capture:true}),()=>document.removeEventListener("keydown",o,{capture:true})},[e]),t}function yo(e,t){return e?typeof e=="function"?e(t):e.some(i=>i.endsWith("*")?t.startsWith(i.slice(0,-1)):t===i):true}function vo(e){let[t,i]=react.useState(()=>typeof window<"u"?window.location.pathname:"/");return react.useEffect(()=>{if(typeof window>"u")return;let o=()=>i(window.location.pathname);window.addEventListener("popstate",o);let a=history.pushState,l=history.replaceState;return history.pushState=function(...n){a.apply(this,n),o();},history.replaceState=function(...n){l.apply(this,n),o();},()=>{window.removeEventListener("popstate",o),history.pushState=a,history.replaceState=l;}},[]),yo(e,t)}function wo(e){let[t,i]=react.useState(()=>!e||e==="dark"?"dark":e==="light"?"light":typeof window<"u"&&window.matchMedia("(prefers-color-scheme: dark)").matches?"dark":"light");return react.useEffect(()=>{if(e!=="auto"){i(e==="light"?"light":"dark");return}let o=window.matchMedia("(prefers-color-scheme: dark)"),a=l=>i(l.matches?"dark":"light");return i(o.matches?"dark":"light"),o.addEventListener("change",a),()=>o.removeEventListener("change",a)},[e]),t}var ko=["bug","feature","ux","general"],To={bug:"categoryBug",feature:"categoryFeature",ux:"categoryUx",general:"categoryGeneral"};function oe(e){let t=Math.floor(e/1e3),i=Math.floor(t/60),o=t%60;return `${i}:${String(o).padStart(2,"0")}`}function So(e){return e<1024*1024?`${Math.round(e/1024)} KB`:`${(e/(1024*1024)).toFixed(1)} MB`}function Po(e){let{state:t,controller:i,start:o,stop:a,clearSelection:l,submit:n}=te(),c=e.config.ui?.position,r=Pe(e.config.ui?.strings),s=e.config.ui?.branding!==false,[h,M]=react.useState(null),[f,S]=react.useState(""),[u,C]=react.useState(e.config.capture?.element??true),[y,ae]=react.useState(e.config.capture?.fullPage??false),[it,ie]=react.useState(null),[O,ne]=react.useState(void 0),se=e.config.ui?.categories??ko,nt=e.config.recording?.enabled===true&&chunkORVW2RTZ_cjs.j(),st=e.config.recording?.maxDurationMs??3e4,[ct,lt]=react.useState(false),[j,dt]=react.useState(0);react.useEffect(()=>{let d=window.setTimeout(()=>{let N=chunkORVW2RTZ_cjs.r();dt(N.findings.length);},500);return ()=>window.clearTimeout(d)},[]),react.useImperativeHandle(e.handleRef,()=>({open:o,close:a,submit:d=>n(d),startRecording:()=>i.startRecording(),stopRecording:()=>i.stopRecording(),get isOpen(){return t.phase!=="idle"}}),[o,a,n,i,t.phase]);let ce=t.phase==="review"||t.phase==="recording"||t.phase==="capturing"||t.phase==="submitting"||t.phase==="error"||t.phase==="success",pt=xo(ce),[ft,ut]=react.useState(0);react.useEffect(()=>{t.phase==="idle"&&ut(chunkORVW2RTZ_cjs.i());},[t.phase]);let[bt,le]=react.useState(false),de=react.useRef(t.phase);react.useEffect(()=>{if(de.current==="success"&&t.phase==="idle"){le(true);let d=window.setTimeout(()=>le(false),1500);return ()=>window.clearTimeout(d)}de.current=t.phase;},[t.phase]),react.useEffect(()=>{let d=e.config.ui?.shortcut;if(!d)return;let N=d.toLowerCase().split("+").map(P=>P.trim()),W=N[N.length-1]||"",L=new Set(N.slice(0,-1)),fe=P=>{let ht=/Mac|iPod|iPhone|iPad/.test(navigator.platform);if(L.has("mod")){if(ht?!P.metaKey:!P.ctrlKey)return}else if(L.has("ctrl")&&!P.ctrlKey||(L.has("meta")||L.has("cmd"))&&!P.metaKey)return;L.has("shift")&&!P.shiftKey||(L.has("alt")||L.has("option"))&&!P.altKey||P.key.toLowerCase()===W&&(P.preventDefault(),t.phase==="idle"?o():a());};return document.addEventListener("keydown",fe),()=>document.removeEventListener("keydown",fe)},[e.config.ui?.shortcut,t.phase,o,a]),react.useEffect(()=>i.subscribeHover(M),[i]),react.useEffect(()=>{let d=i.__unsafeGetSelectedElement();if(!d||t.phase==="idle"||t.phase==="picking"){ie(null);return}let N=()=>{ie(chunkORVW2RTZ_cjs.b(d.getBoundingClientRect()));};N();let W=()=>N();return window.addEventListener("scroll",W,{capture:true,passive:true}),window.addEventListener("resize",W,{passive:true}),()=>{window.removeEventListener("scroll",W,{capture:true}),window.removeEventListener("resize",W);}},[i,t.phase,t.selection?.selector]),react.useEffect(()=>{t.phase==="review"&&(S(""),C(e.config.capture?.element??true),ae(e.config.capture?.fullPage??false),ne(void 0));},[t.phase,t.selection?.selector,e.config.capture?.element,e.config.capture?.fullPage]),react.useEffect(()=>{if(t.phase!=="success")return;let d=window.setTimeout(()=>a(),1200);return ()=>window.clearTimeout(d)},[t.phase,a]);let k=t.phase==="capturing"||t.phase==="submitting"||t.phase==="recording",F=t.phase==="picking"?h?.rect??null:it??t.selection?.rect??null,Q=react.useMemo(()=>F?mo(F,360,c):null,[F?.x,F?.y,F?.width,F?.height,c]),pe=t.lastError?.message,q=react.useCallback(()=>{let d={capture:{element:u,fullPage:y}};O&&(d.category=O),n(f,d);},[n,f,u,y,O]),gt=react.useCallback(d=>{(d.metaKey||d.ctrlKey)&&d.key==="Enter"&&f.trim().length>0&&!k&&(d.preventDefault(),q());},[q,f,k]),mt=tt(e.config.ui?.triggerStyle);return jsxRuntime.jsxs(jsxRuntime.Fragment,{children:[jsxRuntime.jsx(mt,{position:c,onClick:()=>o(),isVisible:t.phase==="idle",label:e.config.ui?.triggerLabel??r.triggerLabel,queueCount:ft,showSuccess:bt}),t.phase!=="idle"&&jsxRuntime.jsxs("div",{className:"bf-overlay",role:"presentation",children:[t.phase!=="picking"&&jsxRuntime.jsx("div",{className:"bf-blocker",role:"presentation",onClick:()=>a()}),F&&jsxRuntime.jsx(ho,{rect:F}),t.phase==="picking"&&jsxRuntime.jsxs("div",{className:"bf-hint",role:"status","aria-live":"polite",children:[jsxRuntime.jsx("p",{id:"bf-hint-text",children:r.hintText}),jsxRuntime.jsx("button",{type:"button",className:"bf-btn",onClick:()=>a(),"aria-label":r.cancelButton,children:r.cancelButton})]}),ce&&Q&&jsxRuntime.jsxs("div",{ref:pt,className:"bf-panel",style:{left:Q.left,top:Q.top},role:"dialog","aria-modal":"true","aria-label":"Feedback form",children:[jsxRuntime.jsxs("div",{className:"bf-panelHeader",children:[jsxRuntime.jsx("div",{className:"bf-title",id:"bf-panel-title",children:r.panelTitle}),jsxRuntime.jsxs("div",{className:"bf-row",style:{justifyContent:"flex-end"},children:[jsxRuntime.jsx("button",{type:"button",className:"bf-btn",onClick:()=>l(),disabled:k,"aria-label":r.rePickButton,children:r.rePickButton}),jsxRuntime.jsx("button",{type:"button",className:"bf-btn",onClick:()=>a(),disabled:k,"aria-label":r.closeButton,children:r.closeButton})]})]}),jsxRuntime.jsxs("div",{className:"bf-panelBody",children:[jsxRuntime.jsx("textarea",{className:"bf-textarea",placeholder:r.textareaPlaceholder,value:f,onChange:d=>S(d.target.value),onKeyDown:gt,disabled:k,"aria-label":r.panelTitle}),se.length>0&&jsxRuntime.jsx("div",{className:"bf-pills",role:"group","aria-label":"Feedback category",children:se.map(d=>jsxRuntime.jsx("button",{type:"button",className:`bf-pill${O===d?" bf-pill-active":""}`,onClick:()=>ne(O===d?void 0:d),disabled:k,children:r[To[d]]},d))}),jsxRuntime.jsxs("div",{className:"bf-row",role:"group","aria-label":r.screenshotElement,children:[jsxRuntime.jsxs("label",{children:[jsxRuntime.jsx("input",{type:"checkbox",checked:u,onChange:d=>C(d.target.checked),disabled:k}),r.screenshotElement]}),jsxRuntime.jsxs("label",{children:[jsxRuntime.jsx("input",{type:"checkbox",checked:y,onChange:d=>ae(d.target.checked),disabled:k}),r.screenshotFullPage]})]}),nt&&t.phase==="review"&&!t.video&&jsxRuntime.jsxs("button",{type:"button",className:"bf-record-btn",onClick:()=>i.startRecording(),disabled:k,"aria-label":r.recordButton,children:[jsxRuntime.jsx("span",{className:"bf-rec-dot","aria-hidden":"true"}),r.recordButton]}),t.phase==="recording"&&jsxRuntime.jsxs("div",{className:"bf-recording-indicator",role:"status","aria-live":"polite",children:[jsxRuntime.jsx("span",{className:"bf-rec-dot bf-rec-dot-pulse","aria-hidden":"true"}),jsxRuntime.jsxs("span",{children:[r.recordingText," ",oe(t.recordingElapsedMs??0)," / ",oe(st)]}),jsxRuntime.jsx("button",{type:"button",className:"bf-btn",onClick:()=>i.stopRecording(),"aria-label":r.stopRecordButton,children:r.stopRecordButton})]}),t.video&&t.phase==="review"&&jsxRuntime.jsxs("div",{className:"bf-video-preview",children:[jsxRuntime.jsx("video",{src:t.video.blobUrl,controls:true,muted:true,playsInline:true}),jsxRuntime.jsx("button",{type:"button",className:"bf-video-remove",onClick:()=>i.removeVideo(),"aria-label":r.removeVideoButton,children:"\xD7"}),jsxRuntime.jsxs("div",{className:"bf-video-meta",children:[r.videoPreviewLabel," (",oe(t.video.durationMs),", ",So(t.video.sizeBytes),")"]})]}),t.phase==="capturing"&&jsxRuntime.jsxs("div",{className:"bf-status",role:"status","aria-live":"polite",children:[jsxRuntime.jsx("span",{className:"bf-spinner","aria-hidden":"true"}),r.capturingText]}),t.phase==="submitting"&&jsxRuntime.jsxs("div",{className:"bf-status",role:"status","aria-live":"polite",children:[jsxRuntime.jsx("span",{className:"bf-spinner","aria-hidden":"true"}),r.submittingText]}),t.phase==="success"&&jsxRuntime.jsx("div",{className:"bf-status",role:"status","aria-live":"polite",children:r.successText}),t.phase==="error"&&pe&&jsxRuntime.jsx("div",{className:"bf-error",role:"alert",children:pe}),jsxRuntime.jsxs("div",{className:"bf-actions",children:[jsxRuntime.jsx("button",{type:"button",className:"bf-btn",onClick:()=>a(),disabled:k,"aria-label":r.cancelButton,children:r.cancelButton}),jsxRuntime.jsx("button",{type:"button",className:"bf-btn bf-btnPrimary",onClick:q,disabled:k||f.trim().length===0,"aria-label":r.sendButton,children:r.sendButton})]})]}),s&&jsxRuntime.jsx("div",{className:"bf-watermark",children:jsxRuntime.jsx("a",{href:"https://blocfeed.com",target:"_blank",rel:"noopener noreferrer",children:"Powered by BlocFeed"})})]})]}),t.phase==="success"&&jsxRuntime.jsx("div",{className:"bf-toast",role:"status","aria-live":"polite",children:r.toastText}),j>0&&!ct&&jsxRuntime.jsxs("div",{className:"bf-security-banner",role:"alert",children:[jsxRuntime.jsx("button",{type:"button",className:"bf-security-banner-dismiss",onClick:()=>lt(true),"aria-label":"Dismiss",children:"\xD7"}),jsxRuntime.jsx("strong",{children:"Security Warning"}),j," potential secret",j>1?"s":""," exposed in client code. Check your environment variables."]})]})}var Co=react.forwardRef(function(t,i){let o={...t.config??{},blocfeed_id:t.blocfeed_id},[a,l]=react.useState(null),n=vo(o.ui?.showOn),c=wo(o.ui?.theme?.mode),r=!!o.diagnostics;react.useEffect(()=>{if(r)return chunkORVW2RTZ_cjs.m(o.diagnostics),()=>chunkORVW2RTZ_cjs.n()},[r]);let s=!!o.security;react.useEffect(()=>{s&&chunkORVW2RTZ_cjs.q(o.security);},[s]);let h=react.useRef(t.config?.metadata?.enrich);h.current=t.config?.metadata?.enrich;let M=react.useMemo(()=>{if(t.config)return {...t.config,metadata:{...t.config.metadata,enrich:async f=>{let S=h.current,u=S?await S(f):{},C=chunkORVW2RTZ_cjs.o(),y=chunkORVW2RTZ_cjs.r();return {...u,...C.consoleLogs.length>0?{_consoleLogs:C.consoleLogs}:{},...C.networkErrors.length>0?{_networkErrors:C.networkErrors}:{},...y.findings.length>0?{_securityFindings:y.findings}:{}}}}}},[]);return react.useEffect(()=>{Te();let f=document.createElement("div");f.setAttribute("data-blocfeed-ui-root","true"),f.setAttribute("data-blocfeed-ui","true"),f.setAttribute("data-bf-theme",c);let S=o.ui?.zIndex;typeof S=="number"&&f.style.setProperty("--bf-z",String(S));let u=o.ui?.theme;return u&&(u.accentColor&&f.style.setProperty("--bf-accent",u.accentColor),u.panelBackground&&f.style.setProperty("--bf-panel-bg",u.panelBackground),u.panelForeground&&f.style.setProperty("--bf-panel-fg",u.panelForeground),u.fontFamily&&f.style.setProperty("--bf-font",u.fontFamily)),document.body.appendChild(f),l(f),()=>{f.remove(),l(null);}},[o.ui?.zIndex,o.ui?.theme?.accentColor,o.ui?.theme?.panelBackground,o.ui?.theme?.panelForeground,o.ui?.theme?.fontFamily,c]),react.useEffect(()=>{a&&a.setAttribute("data-bf-theme",c);},[a,c]),!n||!a?null:reactDom.createPortal(jsxRuntime.jsx(ee,{blocfeed_id:o.blocfeed_id,...M?{config:M}:{},children:jsxRuntime.jsx(Po,{config:o,handleRef:i})}),a)});
|
|
742
|
+
exports.BlocFeedProvider=ee;exports.BlocFeedWidget=Co;exports.useBlocFeed=te;
|
package/dist/main.d.cts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { B as BlocFeedConfig, a as BlocFeedHandle, b as BlocFeedState, c as BlocFeedController, C as CaptureConfig, F as FeedbackCategory, S as SubmitResult } from './controller-
|
|
2
|
-
export { d as BlocFeedError, e as BlocFeedStrings, f as BlocFeedUser, g as CaptureDiagnostics, h as CaptureResult, i as ConsoleEntry, D as DiagnosticsConfig, E as ElementDescriptor, j as FeedbackApiResponse, k as FeedbackPayload, I as ImageAsset, M as MaybePromise, l as MetadataConfig, m as MetadataContext, N as NetworkEntry, P as PickerConfig, R as
|
|
1
|
+
import { B as BlocFeedConfig, a as BlocFeedHandle, b as BlocFeedState, c as BlocFeedController, C as CaptureConfig, F as FeedbackCategory, S as SubmitResult } from './controller-BnTq9F8J.cjs';
|
|
2
|
+
export { d as BlocFeedError, e as BlocFeedStrings, f as BlocFeedUser, g as CaptureDiagnostics, h as CaptureResult, i as ConsoleEntry, D as DiagnosticsConfig, E as ElementDescriptor, j as FeedbackApiResponse, k as FeedbackPayload, I as ImageAsset, M as MaybePromise, l as MetadataConfig, m as MetadataContext, N as NetworkEntry, P as PickerConfig, R as RecordingConfig, n as Rect, o as ScreenshotAdapter, p as ScreenshotAdapterOptions, q as ScreenshotIntent, r as ScreenshotMime, s as SecurityConfig, t as SecurityFinding, u as SecuritySnapshot, v as SessionPhase, T as ThemeConfig, w as TransportConfig, x as TransportResult, y as TriggerStyle, V as VideoAsset, z as VideoIntent, A as VideoMime, W as WidgetPosition } from './controller-BnTq9F8J.cjs';
|
|
3
3
|
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
4
4
|
import * as react from 'react';
|
|
5
5
|
import { ReactNode } from 'react';
|
|
@@ -27,6 +27,9 @@ type BlocFeedApi = {
|
|
|
27
27
|
capture?: CaptureConfig;
|
|
28
28
|
category?: FeedbackCategory;
|
|
29
29
|
}) => Promise<SubmitResult>;
|
|
30
|
+
startRecording: () => Promise<void>;
|
|
31
|
+
stopRecording: () => void;
|
|
32
|
+
removeVideo: () => void;
|
|
30
33
|
};
|
|
31
34
|
declare function useBlocFeed(): BlocFeedApi;
|
|
32
35
|
|
package/dist/main.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { B as BlocFeedConfig, a as BlocFeedHandle, b as BlocFeedState, c as BlocFeedController, C as CaptureConfig, F as FeedbackCategory, S as SubmitResult } from './controller-
|
|
2
|
-
export { d as BlocFeedError, e as BlocFeedStrings, f as BlocFeedUser, g as CaptureDiagnostics, h as CaptureResult, i as ConsoleEntry, D as DiagnosticsConfig, E as ElementDescriptor, j as FeedbackApiResponse, k as FeedbackPayload, I as ImageAsset, M as MaybePromise, l as MetadataConfig, m as MetadataContext, N as NetworkEntry, P as PickerConfig, R as
|
|
1
|
+
import { B as BlocFeedConfig, a as BlocFeedHandle, b as BlocFeedState, c as BlocFeedController, C as CaptureConfig, F as FeedbackCategory, S as SubmitResult } from './controller-BnTq9F8J.js';
|
|
2
|
+
export { d as BlocFeedError, e as BlocFeedStrings, f as BlocFeedUser, g as CaptureDiagnostics, h as CaptureResult, i as ConsoleEntry, D as DiagnosticsConfig, E as ElementDescriptor, j as FeedbackApiResponse, k as FeedbackPayload, I as ImageAsset, M as MaybePromise, l as MetadataConfig, m as MetadataContext, N as NetworkEntry, P as PickerConfig, R as RecordingConfig, n as Rect, o as ScreenshotAdapter, p as ScreenshotAdapterOptions, q as ScreenshotIntent, r as ScreenshotMime, s as SecurityConfig, t as SecurityFinding, u as SecuritySnapshot, v as SessionPhase, T as ThemeConfig, w as TransportConfig, x as TransportResult, y as TriggerStyle, V as VideoAsset, z as VideoIntent, A as VideoMime, W as WidgetPosition } from './controller-BnTq9F8J.js';
|
|
3
3
|
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
4
4
|
import * as react from 'react';
|
|
5
5
|
import { ReactNode } from 'react';
|
|
@@ -27,6 +27,9 @@ type BlocFeedApi = {
|
|
|
27
27
|
capture?: CaptureConfig;
|
|
28
28
|
category?: FeedbackCategory;
|
|
29
29
|
}) => Promise<SubmitResult>;
|
|
30
|
+
startRecording: () => Promise<void>;
|
|
31
|
+
stopRecording: () => void;
|
|
32
|
+
removeVideo: () => void;
|
|
30
33
|
};
|
|
31
34
|
declare function useBlocFeed(): BlocFeedApi;
|
|
32
35
|
|