blocfeed 0.3.0 → 0.5.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 CHANGED
@@ -1,5 +1,48 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.5.0 — 2026-02-20
4
+
5
+ ### New features
6
+
7
+ - **Custom trigger label** — `config.ui.triggerLabel` sets the text shown on the trigger button (default: `"Feedback"`). Applies to all trigger styles.
8
+ - **Keyboard shortcut** — `config.ui.shortcut` (e.g., `"mod+shift+f"`) toggles the widget open/closed. Supports `ctrl`, `meta`/`cmd`, `shift`, `alt`/`option` modifiers; `mod` maps to Ctrl on Windows/Linux and Cmd on Mac.
9
+ - **Beacon trigger style** — new `"beacon"` trigger with a lighthouse-style sweeping beam and glowing dot that expands to a pill on hover.
10
+ - **Typewriter trigger style** — new `"typewriter"` trigger with text that types out character by character with a blinking cursor, fully visible on hover.
11
+ - **Offline queue badge** — when submissions are queued for retry, a red badge with the count appears on the trigger button across all styles.
12
+ - **Success checkmark** — after a successful submission, the trigger briefly shows a checkmark icon for 1.5 seconds before returning to normal.
13
+ - **Panel / toast / hint animations** — the feedback panel slides in from below, the success toast slides up, and the hint bar slides down using CSS keyframe animations.
14
+
15
+ ### Improvements
16
+
17
+ - **`prefers-reduced-motion` support** — all framer-motion animations and CSS keyframe animations are disabled when the user prefers reduced motion. Animated triggers use instant transitions; panel/toast/hint entrance animations are suppressed.
18
+ - **`TriggerStyle` type** updated to include `"beacon"` and `"typewriter"`.
19
+
20
+ ---
21
+
22
+ ## 0.4.0 — 2026-02-20
23
+
24
+ ### New features
25
+
26
+ - **Animated trigger styles** — new `config.ui.triggerStyle` option with 7 selectable styles:
27
+ - `"classic"` (default) — standard pill button, no framer-motion required
28
+ - `"dot"` — breathing dot with glow that springs into a pill on hover
29
+ - `"bubble"` — floating chat-bubble icon with tooltip on hover
30
+ - `"edge-tab"` — thin vertical tab flush to screen edge that slides out on hover
31
+ - `"pulse-ring"` — sonar-style pulsing rings around a dot that contracts to a pill on hover
32
+ - `"minimal"` — text-only "Feedback" with animated underline on hover
33
+ - `"icon-pop"` — wobbling message icon that pops and reveals text on hover
34
+ - All animated styles include smooth spring-based enter/exit transitions via framer-motion
35
+ - `framer-motion` added as an optional peer dependency (only required for non-classic styles)
36
+ - New `TriggerStyle` type exported from both `blocfeed` and `blocfeed/engine`
37
+
38
+ ### Architecture
39
+
40
+ - Trigger button extracted from `BlocFeedWidget` into modular components under `src/react/triggers/`
41
+ - Each trigger variant is a self-contained component with its own animations
42
+ - `ClassicTrigger` has zero framer-motion imports for consumers who don't need animations
43
+
44
+ ---
45
+
3
46
  ## 0.3.0 — 2026-02-20
4
47
 
5
48
  ### New features
package/README.md CHANGED
@@ -102,9 +102,12 @@ All configuration is passed via the `config` prop on `<BlocFeedWidget>` or `<Blo
102
102
  name: "Jane Doe",
103
103
  },
104
104
 
105
- // Widget position & theme
105
+ // Widget position, theme & trigger style
106
106
  ui: {
107
107
  position: "bottom-right", // "bottom-left" | "top-right" | "top-left"
108
+ triggerStyle: "dot", // "classic" | "bubble" | "edge-tab" | "pulse-ring" | "minimal" | "icon-pop" | "beacon" | "typewriter"
109
+ triggerLabel: "Feedback", // custom label text
110
+ shortcut: "mod+shift+f", // keyboard shortcut to toggle widget
108
111
  zIndex: 99999,
109
112
  theme: {
110
113
  accentColor: "#12D393",
@@ -181,6 +184,60 @@ config={{
181
184
 
182
185
  Options: `"bottom-right"` | `"bottom-left"` | `"top-right"` | `"top-left"`
183
186
 
187
+ ## Trigger Styles
188
+
189
+ Customize the trigger button's appearance and animation:
190
+
191
+ ```tsx
192
+ config={{
193
+ ui: { triggerStyle: "dot" }
194
+ }}
195
+ ```
196
+
197
+ | Style | Description | Requires framer-motion |
198
+ |-------|-------------|----------------------|
199
+ | `"classic"` | Default pill button with colored dot (no animation) | No |
200
+ | `"dot"` | Breathing dot that expands to pill on hover | Yes |
201
+ | `"bubble"` | Floating chat-bubble icon with tooltip on hover | Yes |
202
+ | `"edge-tab"` | Thin tab anchored to screen edge, slides out on hover | Yes |
203
+ | `"pulse-ring"` | Sonar-style pulsing rings around a dot, expands on hover | Yes |
204
+ | `"minimal"` | Text-only "Feedback" with animated underline on hover | Yes |
205
+ | `"icon-pop"` | Wobbling icon that pops and reveals text on hover | Yes |
206
+ | `"beacon"` | Lighthouse-style sweeping beam with glowing dot, expands on hover | Yes |
207
+ | `"typewriter"` | Text types out character by character with blinking cursor | Yes |
208
+
209
+ All animated styles include smooth enter/exit transitions. Animations automatically simplify when `prefers-reduced-motion: reduce` is active.
210
+
211
+ ### Custom trigger label
212
+
213
+ ```tsx
214
+ config={{
215
+ ui: { triggerLabel: "Report Bug" }
216
+ }}
217
+ ```
218
+
219
+ The label defaults to `"Feedback"` and is used across all trigger styles.
220
+
221
+ ### Keyboard shortcut
222
+
223
+ Open/close the widget with a keyboard shortcut:
224
+
225
+ ```tsx
226
+ config={{
227
+ ui: { shortcut: "mod+shift+f" }
228
+ }}
229
+ ```
230
+
231
+ Use `mod` for platform-aware behavior (Ctrl on Windows/Linux, Cmd on Mac). Supports `ctrl`, `meta`/`cmd`, `shift`, `alt`/`option` modifiers.
232
+
233
+ ### Installing framer-motion
234
+
235
+ All styles except `"classic"` require `framer-motion` as a peer dependency:
236
+
237
+ ```bash
238
+ npm install framer-motion
239
+ ```
240
+
184
241
  ## Theme Customization
185
242
 
186
243
  Override the widget's visual appearance via CSS variables:
@@ -315,9 +372,11 @@ The widget supports full keyboard navigation:
315
372
  - **Shift+Tab** cycles backward
316
373
  - **Escape** cancels picking or closes the panel
317
374
  - **Ctrl/Cmd+Enter** submits feedback from the textarea
375
+ - **Custom shortcut** — configurable via `config.ui.shortcut` (e.g., `"mod+shift+f"`)
318
376
  - Focus is trapped within the panel when open
319
377
  - All interactive elements have `aria-label` attributes
320
378
  - Status messages use `aria-live="polite"` for screen reader announcements
379
+ - Animations respect `prefers-reduced-motion: reduce` — all motion is disabled when the user prefers reduced motion
321
380
 
322
381
  ## Client-Side Rate Limiting
323
382
 
@@ -368,6 +427,7 @@ import type {
368
427
  BlocFeedConfig,
369
428
  BlocFeedUser,
370
429
  TransportConfig,
430
+ TriggerStyle,
371
431
  WidgetPosition,
372
432
  ThemeConfig,
373
433
  FeedbackPayload,
@@ -24,6 +24,7 @@ interface TransportConfig {
24
24
  backoffMs?: number;
25
25
  }
26
26
  type WidgetPosition = "bottom-right" | "bottom-left" | "top-right" | "top-left";
27
+ type TriggerStyle = "classic" | "dot" | "bubble" | "edge-tab" | "pulse-ring" | "minimal" | "icon-pop" | "beacon" | "typewriter";
27
28
  interface ThemeConfig {
28
29
  accentColor?: string;
29
30
  panelBackground?: string;
@@ -152,6 +153,12 @@ interface BlocFeedConfig {
152
153
  position?: WidgetPosition;
153
154
  /** Theme overrides. */
154
155
  theme?: ThemeConfig;
156
+ /** Trigger button animation style. Default: "classic" */
157
+ triggerStyle?: TriggerStyle;
158
+ /** Custom label text for the trigger button. Default: "Feedback" */
159
+ triggerLabel?: string;
160
+ /** Keyboard shortcut to toggle the widget. e.g. "ctrl+shift+f" */
161
+ shortcut?: string;
155
162
  };
156
163
  }
157
164
  interface ScreenshotIntent {
@@ -229,4 +236,4 @@ interface BlocFeedController {
229
236
  }
230
237
  declare function createBlocFeedController(config: BlocFeedConfig): BlocFeedController;
231
238
 
232
- export { type BlocFeedConfig as B, type CaptureConfig as C, type ElementDescriptor as E, type FeedbackApiResponse as F, type HoverListener as H, type ImageAsset as I, type MaybePromise as M, type PickerConfig as P, type Rect as R, type SubmitResult as S, type ThemeConfig as T, type WidgetPosition as W, type BlocFeedState as a, type BlocFeedController as b, type BlocFeedError as c, type BlocFeedUser as d, type CaptureDiagnostics as e, type CaptureResult as f, type FeedbackPayload as g, type MetadataConfig as h, type MetadataContext as i, type ScreenshotAdapter as j, type ScreenshotAdapterOptions as k, type ScreenshotIntent as l, type ScreenshotMime as m, type SessionPhase as n, type TransportConfig as o, type TransportResult as p, type StateListener as q, createBlocFeedController as r };
239
+ export { type BlocFeedConfig as B, type CaptureConfig as C, type ElementDescriptor as E, type FeedbackApiResponse as F, type HoverListener as H, type ImageAsset as I, type MaybePromise as M, type PickerConfig as P, type Rect as R, type SubmitResult as S, type ThemeConfig as T, type WidgetPosition as W, type BlocFeedState as a, type BlocFeedController as b, type BlocFeedError as c, type BlocFeedUser as d, type CaptureDiagnostics as e, type CaptureResult as f, type FeedbackPayload as g, type MetadataConfig as h, type MetadataContext as i, type ScreenshotAdapter as j, type ScreenshotAdapterOptions as k, type ScreenshotIntent as l, type ScreenshotMime as m, type SessionPhase as n, type TransportConfig as o, type TransportResult as p, type TriggerStyle as q, type StateListener as r, createBlocFeedController as s };
@@ -24,6 +24,7 @@ interface TransportConfig {
24
24
  backoffMs?: number;
25
25
  }
26
26
  type WidgetPosition = "bottom-right" | "bottom-left" | "top-right" | "top-left";
27
+ type TriggerStyle = "classic" | "dot" | "bubble" | "edge-tab" | "pulse-ring" | "minimal" | "icon-pop" | "beacon" | "typewriter";
27
28
  interface ThemeConfig {
28
29
  accentColor?: string;
29
30
  panelBackground?: string;
@@ -152,6 +153,12 @@ interface BlocFeedConfig {
152
153
  position?: WidgetPosition;
153
154
  /** Theme overrides. */
154
155
  theme?: ThemeConfig;
156
+ /** Trigger button animation style. Default: "classic" */
157
+ triggerStyle?: TriggerStyle;
158
+ /** Custom label text for the trigger button. Default: "Feedback" */
159
+ triggerLabel?: string;
160
+ /** Keyboard shortcut to toggle the widget. e.g. "ctrl+shift+f" */
161
+ shortcut?: string;
155
162
  };
156
163
  }
157
164
  interface ScreenshotIntent {
@@ -229,4 +236,4 @@ interface BlocFeedController {
229
236
  }
230
237
  declare function createBlocFeedController(config: BlocFeedConfig): BlocFeedController;
231
238
 
232
- export { type BlocFeedConfig as B, type CaptureConfig as C, type ElementDescriptor as E, type FeedbackApiResponse as F, type HoverListener as H, type ImageAsset as I, type MaybePromise as M, type PickerConfig as P, type Rect as R, type SubmitResult as S, type ThemeConfig as T, type WidgetPosition as W, type BlocFeedState as a, type BlocFeedController as b, type BlocFeedError as c, type BlocFeedUser as d, type CaptureDiagnostics as e, type CaptureResult as f, type FeedbackPayload as g, type MetadataConfig as h, type MetadataContext as i, type ScreenshotAdapter as j, type ScreenshotAdapterOptions as k, type ScreenshotIntent as l, type ScreenshotMime as m, type SessionPhase as n, type TransportConfig as o, type TransportResult as p, type StateListener as q, createBlocFeedController as r };
239
+ export { type BlocFeedConfig as B, type CaptureConfig as C, type ElementDescriptor as E, type FeedbackApiResponse as F, type HoverListener as H, type ImageAsset as I, type MaybePromise as M, type PickerConfig as P, type Rect as R, type SubmitResult as S, type ThemeConfig as T, type WidgetPosition as W, type BlocFeedState as a, type BlocFeedController as b, type BlocFeedError as c, type BlocFeedUser as d, type CaptureDiagnostics as e, type CaptureResult as f, type FeedbackPayload as g, type MetadataConfig as h, type MetadataContext as i, type ScreenshotAdapter as j, type ScreenshotAdapterOptions as k, type ScreenshotIntent as l, type ScreenshotMime as m, type SessionPhase as n, type TransportConfig as o, type TransportResult as p, type TriggerStyle as q, type StateListener as r, createBlocFeedController as s };
package/dist/engine.cjs CHANGED
@@ -1 +1 @@
1
- 'use strict';var chunkJLPJP7DD_cjs=require('./chunk-JLPJP7DD.cjs');function c(o){if(o?.aborted)throw new Error("Aborted")}async function S(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 S(o);return {dataUrl:o,mime:t,width:e,height:r}}function x(o){return {async captureElement(t,e){if(!chunkJLPJP7DD_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(!chunkJLPJP7DD_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 y(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,"clearQueue",{enumerable:true,get:function(){return chunkJLPJP7DD_cjs.h}});Object.defineProperty(exports,"collectMetadata",{enumerable:true,get:function(){return chunkJLPJP7DD_cjs.e}});Object.defineProperty(exports,"createBlocFeedController",{enumerable:true,get:function(){return chunkJLPJP7DD_cjs.j}});Object.defineProperty(exports,"createHtmlToImageAdapter",{enumerable:true,get:function(){return chunkJLPJP7DD_cjs.c}});Object.defineProperty(exports,"dequeueAll",{enumerable:true,get:function(){return chunkJLPJP7DD_cjs.g}});Object.defineProperty(exports,"enqueue",{enumerable:true,get:function(){return chunkJLPJP7DD_cjs.f}});Object.defineProperty(exports,"getQueueSize",{enumerable:true,get:function(){return chunkJLPJP7DD_cjs.i}});Object.defineProperty(exports,"runCapture",{enumerable:true,get:function(){return chunkJLPJP7DD_cjs.d}});exports.createModernScreenshotAdapter=x;exports.dataUrlToBlob=y;
1
+ 'use strict';var chunkJLPJP7DD_cjs=require('./chunk-JLPJP7DD.cjs');function c(o){if(o?.aborted)throw new Error("Aborted")}async function A(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 A(o);return {dataUrl:o,mime:t,width:e,height:r}}function x(o){return {async captureElement(t,e){if(!chunkJLPJP7DD_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(!chunkJLPJP7DD_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 b(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,"clearQueue",{enumerable:true,get:function(){return chunkJLPJP7DD_cjs.h}});Object.defineProperty(exports,"collectMetadata",{enumerable:true,get:function(){return chunkJLPJP7DD_cjs.e}});Object.defineProperty(exports,"createBlocFeedController",{enumerable:true,get:function(){return chunkJLPJP7DD_cjs.j}});Object.defineProperty(exports,"createHtmlToImageAdapter",{enumerable:true,get:function(){return chunkJLPJP7DD_cjs.c}});Object.defineProperty(exports,"dequeueAll",{enumerable:true,get:function(){return chunkJLPJP7DD_cjs.g}});Object.defineProperty(exports,"enqueue",{enumerable:true,get:function(){return chunkJLPJP7DD_cjs.f}});Object.defineProperty(exports,"getQueueSize",{enumerable:true,get:function(){return chunkJLPJP7DD_cjs.i}});Object.defineProperty(exports,"runCapture",{enumerable:true,get:function(){return chunkJLPJP7DD_cjs.d}});exports.createModernScreenshotAdapter=x;exports.dataUrlToBlob=b;
package/dist/engine.d.cts CHANGED
@@ -1,5 +1,5 @@
1
- import { j as ScreenshotAdapter, C as CaptureConfig, f as CaptureResult, h as MetadataConfig, i as MetadataContext, d as BlocFeedUser, g as FeedbackPayload } from './controller-olqOZLhp.cjs';
2
- export { B as BlocFeedConfig, b as BlocFeedController, c as BlocFeedError, a as BlocFeedState, E as ElementDescriptor, F as FeedbackApiResponse, H as HoverListener, I as ImageAsset, R as Rect, k as ScreenshotAdapterOptions, l as ScreenshotIntent, m as ScreenshotMime, n as SessionPhase, q as StateListener, S as SubmitResult, T as ThemeConfig, o as TransportConfig, W as WidgetPosition, r as createBlocFeedController } from './controller-olqOZLhp.cjs';
1
+ import { j as ScreenshotAdapter, C as CaptureConfig, f as CaptureResult, h as MetadataConfig, i as MetadataContext, d as BlocFeedUser, g as FeedbackPayload } from './controller-did-WBAQ.cjs';
2
+ export { B as BlocFeedConfig, b as BlocFeedController, c as BlocFeedError, a as BlocFeedState, E as ElementDescriptor, F as FeedbackApiResponse, H as HoverListener, I as ImageAsset, R as Rect, k as ScreenshotAdapterOptions, l as ScreenshotIntent, m as ScreenshotMime, n as SessionPhase, r as StateListener, S as SubmitResult, T as ThemeConfig, o as TransportConfig, q as TriggerStyle, W as WidgetPosition, s as createBlocFeedController } from './controller-did-WBAQ.cjs';
3
3
 
4
4
  declare function createHtmlToImageAdapter(): ScreenshotAdapter;
5
5
 
package/dist/engine.d.ts CHANGED
@@ -1,5 +1,5 @@
1
- import { j as ScreenshotAdapter, C as CaptureConfig, f as CaptureResult, h as MetadataConfig, i as MetadataContext, d as BlocFeedUser, g as FeedbackPayload } from './controller-olqOZLhp.js';
2
- export { B as BlocFeedConfig, b as BlocFeedController, c as BlocFeedError, a as BlocFeedState, E as ElementDescriptor, F as FeedbackApiResponse, H as HoverListener, I as ImageAsset, R as Rect, k as ScreenshotAdapterOptions, l as ScreenshotIntent, m as ScreenshotMime, n as SessionPhase, q as StateListener, S as SubmitResult, T as ThemeConfig, o as TransportConfig, W as WidgetPosition, r as createBlocFeedController } from './controller-olqOZLhp.js';
1
+ import { j as ScreenshotAdapter, C as CaptureConfig, f as CaptureResult, h as MetadataConfig, i as MetadataContext, d as BlocFeedUser, g as FeedbackPayload } from './controller-did-WBAQ.js';
2
+ export { B as BlocFeedConfig, b as BlocFeedController, c as BlocFeedError, a as BlocFeedState, E as ElementDescriptor, F as FeedbackApiResponse, H as HoverListener, I as ImageAsset, R as Rect, k as ScreenshotAdapterOptions, l as ScreenshotIntent, m as ScreenshotMime, n as SessionPhase, r as StateListener, S as SubmitResult, T as ThemeConfig, o as TransportConfig, q as TriggerStyle, W as WidgetPosition, s as createBlocFeedController } from './controller-did-WBAQ.js';
3
3
 
4
4
  declare function createHtmlToImageAdapter(): ScreenshotAdapter;
5
5
 
package/dist/engine.js CHANGED
@@ -1 +1 @@
1
- import {a}from'./chunk-FMFONS5S.js';export{h as clearQueue,e as collectMetadata,j as createBlocFeedController,c as createHtmlToImageAdapter,g as dequeueAll,f as enqueue,i as getQueueSize,d as runCapture}from'./chunk-FMFONS5S.js';function c(o){if(o?.aborted)throw new Error("Aborted")}async function S(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 S(o);return {dataUrl:o,mime:t,width:e,height:r}}function x(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 y(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{x as createModernScreenshotAdapter,y as dataUrlToBlob};
1
+ import {a}from'./chunk-FMFONS5S.js';export{h as clearQueue,e as collectMetadata,j as createBlocFeedController,c as createHtmlToImageAdapter,g as dequeueAll,f as enqueue,i as getQueueSize,d as runCapture}from'./chunk-FMFONS5S.js';function c(o){if(o?.aborted)throw new Error("Aborted")}async function A(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 A(o);return {dataUrl:o,mime:t,width:e,height:r}}function x(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 b(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{x as createModernScreenshotAdapter,b as dataUrlToBlob};
package/dist/main.cjs CHANGED
@@ -1,5 +1,5 @@
1
1
  "use client";
2
- 'use strict';var chunkJLPJP7DD_cjs=require('./chunk-JLPJP7DD.cjs'),react=require('react'),jsxRuntime=require('react/jsx-runtime'),reactDom=require('react-dom');var h=react.createContext(null);function k(t){let e=react.useMemo(()=>chunkJLPJP7DD_cjs.j({...t.config??{},blocfeed_id:t.blocfeed_id}),[]),[i,c]=react.useState(()=>e.getState());return react.useEffect(()=>e.subscribe(c),[e]),react.useEffect(()=>e.setConfig({...t.config??{},blocfeed_id:t.blocfeed_id}),[e,t.config,t.blocfeed_id]),react.useEffect(()=>()=>e.destroy(),[e]),jsxRuntime.jsx(h.Provider,{value:{controller:e,state:i},children:t.children})}var L="blocfeed-styles-v1",G=`
2
+ 'use strict';var chunkJLPJP7DD_cjs=require('./chunk-JLPJP7DD.cjs'),react=require('react'),jsxRuntime=require('react/jsx-runtime'),reactDom=require('react-dom'),framerMotion=require('framer-motion');var $=react.createContext(null);function J(t){let e=react.useMemo(()=>chunkJLPJP7DD_cjs.j({...t.config??{},blocfeed_id:t.blocfeed_id}),[]),[n,i]=react.useState(()=>e.getState());return react.useEffect(()=>e.subscribe(i),[e]),react.useEffect(()=>e.setConfig({...t.config??{},blocfeed_id:t.blocfeed_id}),[e,t.config,t.blocfeed_id]),react.useEffect(()=>()=>e.destroy(),[e]),jsxRuntime.jsx($.Provider,{value:{controller:e,state:n},children:t.children})}var ce="blocfeed-styles-v1",tt=`
3
3
  :where([data-blocfeed-ui-root]),
4
4
  :where([data-blocfeed-ui-root]) * {
5
5
  box-sizing: border-box;
@@ -290,6 +290,87 @@
290
290
  50% { opacity: 1; transform: scale(1.2); }
291
291
  }
292
292
 
293
+ /* ------------------------------------------------------------------ */
294
+ /* Trigger variant: edge-tab */
295
+ /* ------------------------------------------------------------------ */
296
+
297
+ :where([data-blocfeed-ui-root]) .bf-trigger-edge {
298
+ position: fixed;
299
+ z-index: var(--bf-z);
300
+ display: flex;
301
+ align-items: center;
302
+ justify-content: center;
303
+ border: 1px solid var(--bf-border);
304
+ background: var(--bf-panel-bg);
305
+ color: var(--bf-panel-fg);
306
+ box-shadow: var(--bf-shadow);
307
+ cursor: pointer;
308
+ user-select: none;
309
+ -webkit-tap-highlight-color: transparent;
310
+ overflow: hidden;
311
+ padding: 0;
312
+ font-family: var(--bf-font);
313
+ font-size: 12px;
314
+ letter-spacing: 0.5px;
315
+ }
316
+
317
+ :where([data-blocfeed-ui-root]) .bf-trigger-edge:focus-visible {
318
+ outline: 2px solid var(--bf-accent);
319
+ outline-offset: 2px;
320
+ }
321
+
322
+ :where([data-blocfeed-ui-root]) .bf-trigger-edge-left {
323
+ left: 0;
324
+ right: auto;
325
+ border-radius: 0 6px 6px 0;
326
+ border-left: none;
327
+ }
328
+
329
+ :where([data-blocfeed-ui-root]) .bf-trigger-edge-right {
330
+ right: 0;
331
+ left: auto;
332
+ border-radius: 6px 0 0 6px;
333
+ border-right: none;
334
+ }
335
+
336
+ /* ------------------------------------------------------------------ */
337
+ /* Trigger variant: minimal */
338
+ /* ------------------------------------------------------------------ */
339
+
340
+ :where([data-blocfeed-ui-root]) .bf-trigger-minimal {
341
+ position: fixed;
342
+ right: 18px;
343
+ bottom: 18px;
344
+ z-index: var(--bf-z);
345
+ display: inline-flex;
346
+ align-items: center;
347
+ background: transparent;
348
+ border: none;
349
+ box-shadow: none;
350
+ padding: 8px 4px;
351
+ font-family: var(--bf-font);
352
+ font-size: 13px;
353
+ color: var(--bf-panel-fg);
354
+ cursor: pointer;
355
+ user-select: none;
356
+ -webkit-tap-highlight-color: transparent;
357
+ }
358
+
359
+ :where([data-blocfeed-ui-root]) .bf-trigger-minimal.bf-trigger-bl {
360
+ left: 18px; bottom: 18px; right: auto; top: auto;
361
+ }
362
+ :where([data-blocfeed-ui-root]) .bf-trigger-minimal.bf-trigger-tr {
363
+ right: 18px; top: 18px; bottom: auto; left: auto;
364
+ }
365
+ :where([data-blocfeed-ui-root]) .bf-trigger-minimal.bf-trigger-tl {
366
+ left: 18px; top: 18px; right: auto; bottom: auto;
367
+ }
368
+
369
+ :where([data-blocfeed-ui-root]) .bf-trigger-minimal:focus-visible {
370
+ outline: 2px solid var(--bf-accent);
371
+ outline-offset: 2px;
372
+ }
373
+
293
374
  /* ------------------------------------------------------------------ */
294
375
  /* Screen reader only */
295
376
  /* ------------------------------------------------------------------ */
@@ -305,4 +386,94 @@
305
386
  white-space: nowrap;
306
387
  border: 0;
307
388
  }
308
- `;function W(){if(!chunkJLPJP7DD_cjs.a()||document.getElementById(L))return;let t=document.createElement("style");t.id=L,t.textContent=G,document.head.appendChild(t);}function B(){let t=react.useContext(h);if(!t)throw new Error("useBlocFeed must be used within a <BlocFeedProvider />");return {state:t.state,controller:t.controller,start:t.controller.start,stop:t.controller.stop,clearSelection:t.controller.clearSelection,submit:t.controller.submit}}function I(t,e,i){return Math.max(e,Math.min(i,t))}function Z(t,e,i="bottom-right"){let o=window.innerWidth,s=window.innerHeight,a;a=I(t.x,12,Math.max(12,o-e-12));let d=t.y+t.height+12,x=Math.max(12,t.y-240);return {top:d+240<=s?d:x,left:a}}function ee(t){switch(t){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 te(t){let{rect:e}=t,i={left:`${e.x}px`,top:`${e.y}px`,width:`${Math.max(0,e.width)}px`,height:`${Math.max(0,e.height)}px`};return jsxRuntime.jsx("div",{className:"bf-highlight",style:i,"aria-hidden":"true"})}function oe(t){let e=react.useRef(null);return react.useEffect(()=>{if(!t||!e.current)return;e.current.querySelector(".bf-textarea")?.focus();let c=o=>{if(o.key!=="Tab"||!e.current)return;let s=e.current.querySelectorAll('button:not([disabled]), textarea:not([disabled]), input:not([disabled]), [tabindex]:not([tabindex="-1"])');if(s.length===0)return;let a=s[0],d=s[s.length-1];o.shiftKey&&document.activeElement===a?(o.preventDefault(),d.focus()):!o.shiftKey&&document.activeElement===d&&(o.preventDefault(),a.focus());};return document.addEventListener("keydown",c,{capture:true}),()=>document.removeEventListener("keydown",c,{capture:true})},[t]),e}function re(t){let{state:e,controller:i,start:c,stop:o,clearSelection:s,submit:a}=B(),d=t.config.ui?.position,[x,S]=react.useState(null),[p,P]=react.useState(""),[v,E]=react.useState(t.config.capture?.element??true),[y,R]=react.useState(t.config.capture?.fullPage??false),[K,N]=react.useState(null),z=e.phase==="review"||e.phase==="capturing"||e.phase==="submitting"||e.phase==="error"||e.phase==="success",j=oe(z);react.useEffect(()=>i.subscribeHover(S),[i]),react.useEffect(()=>{let n=i.__unsafeGetSelectedElement();if(!n||e.phase==="idle"||e.phase==="picking"){N(null);return}let M=()=>{N(chunkJLPJP7DD_cjs.b(n.getBoundingClientRect()));};M();let m=()=>M();return window.addEventListener("scroll",m,{capture:true,passive:true}),window.addEventListener("resize",m,{passive:true}),()=>{window.removeEventListener("scroll",m,{capture:true}),window.removeEventListener("resize",m);}},[i,e.phase,e.selection?.selector]),react.useEffect(()=>{e.phase==="review"&&(P(""),E(t.config.capture?.element??true),R(t.config.capture?.fullPage??false));},[e.phase,e.selection?.selector,t.config.capture?.element,t.config.capture?.fullPage]),react.useEffect(()=>{if(e.phase!=="success")return;let n=window.setTimeout(()=>o(),1200);return ()=>window.clearTimeout(n)},[e.phase,o]);let f=e.phase==="capturing"||e.phase==="submitting",b=e.phase==="picking"?x?.rect??null:K??e.selection?.rect??null,w=react.useMemo(()=>b?Z(b,360,d):null,[b?.x,b?.y,b?.width,b?.height,d]),T=e.lastError?.message,C=react.useCallback(()=>{a(p,{capture:{element:v,fullPage:y}});},[a,p,v,y]),O=react.useCallback(n=>{(n.metaKey||n.ctrlKey)&&n.key==="Enter"&&p.trim().length>0&&!f&&(n.preventDefault(),C());},[C,p,f]);return jsxRuntime.jsxs(jsxRuntime.Fragment,{children:[e.phase==="idle"&&jsxRuntime.jsxs("button",{className:ee(d),type:"button",onClick:()=>c(),"aria-label":"Give feedback",children:[jsxRuntime.jsx("span",{className:"bf-dot","aria-hidden":"true"}),"Feedback"]}),e.phase!=="idle"&&jsxRuntime.jsxs("div",{className:"bf-overlay",role:"presentation",children:[e.phase!=="picking"&&jsxRuntime.jsx("div",{className:"bf-blocker",role:"presentation",onClick:()=>o()}),b&&jsxRuntime.jsx(te,{rect:b}),e.phase==="picking"&&jsxRuntime.jsxs("div",{className:"bf-hint",role:"status","aria-live":"polite",children:[jsxRuntime.jsxs("p",{id:"bf-hint-text",children:["Click an element to attach your feedback. Press ",jsxRuntime.jsx("strong",{children:"Esc"})," to cancel."]}),jsxRuntime.jsx("button",{type:"button",className:"bf-btn",onClick:()=>o(),"aria-label":"Cancel element selection",children:"Cancel"})]}),z&&w&&jsxRuntime.jsxs("div",{ref:j,className:"bf-panel",style:{left:w.left,top:w.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:"Feedback"}),jsxRuntime.jsxs("div",{className:"bf-row",style:{justifyContent:"flex-end"},children:[jsxRuntime.jsx("button",{type:"button",className:"bf-btn",onClick:()=>s(),disabled:f,"aria-label":"Re-pick element",children:"Re-pick"}),jsxRuntime.jsx("button",{type:"button",className:"bf-btn",onClick:()=>o(),disabled:f,"aria-label":"Close feedback form",children:"Close"})]})]}),jsxRuntime.jsxs("div",{className:"bf-panelBody",children:[jsxRuntime.jsx("textarea",{className:"bf-textarea",placeholder:"What's happening? What did you expect?",value:p,onChange:n=>P(n.target.value),onKeyDown:O,disabled:f,"aria-label":"Feedback message"}),jsxRuntime.jsxs("div",{className:"bf-row",role:"group","aria-label":"Screenshot options",children:[jsxRuntime.jsxs("label",{children:[jsxRuntime.jsx("input",{type:"checkbox",checked:v,onChange:n=>E(n.target.checked),disabled:f}),"Screenshot element"]}),jsxRuntime.jsxs("label",{children:[jsxRuntime.jsx("input",{type:"checkbox",checked:y,onChange:n=>R(n.target.checked),disabled:f}),"Full page"]})]}),e.phase==="capturing"&&jsxRuntime.jsxs("div",{className:"bf-status",role:"status","aria-live":"polite",children:[jsxRuntime.jsx("span",{className:"bf-spinner","aria-hidden":"true"}),"Capturing screenshots\u2026"]}),e.phase==="submitting"&&jsxRuntime.jsxs("div",{className:"bf-status",role:"status","aria-live":"polite",children:[jsxRuntime.jsx("span",{className:"bf-spinner","aria-hidden":"true"}),"Submitting\u2026"]}),e.phase==="success"&&jsxRuntime.jsx("div",{className:"bf-status",role:"status","aria-live":"polite",children:"Sent. Thank you!"}),e.phase==="error"&&T&&jsxRuntime.jsx("div",{className:"bf-error",role:"alert",children:T}),jsxRuntime.jsxs("div",{className:"bf-actions",children:[jsxRuntime.jsx("button",{type:"button",className:"bf-btn",onClick:()=>o(),disabled:f,"aria-label":"Cancel feedback",children:"Cancel"}),jsxRuntime.jsx("button",{type:"button",className:"bf-btn bf-btnPrimary",onClick:C,disabled:f||p.trim().length===0,"aria-label":"Send feedback",children:"Send"})]})]})]})]}),e.phase==="success"&&jsxRuntime.jsx("div",{className:"bf-toast",role:"status","aria-live":"polite",children:"Feedback sent"})]})}function ae(t){let e={...t.config??{},blocfeed_id:t.blocfeed_id},[i,c]=react.useState(null);return react.useEffect(()=>{W();let o=document.createElement("div");o.setAttribute("data-blocfeed-ui-root","true"),o.setAttribute("data-blocfeed-ui","true");let s=e.ui?.zIndex;typeof s=="number"&&o.style.setProperty("--bf-z",String(s));let a=e.ui?.theme;return a&&(a.accentColor&&o.style.setProperty("--bf-accent",a.accentColor),a.panelBackground&&o.style.setProperty("--bf-panel-bg",a.panelBackground),a.panelForeground&&o.style.setProperty("--bf-panel-fg",a.panelForeground),a.fontFamily&&o.style.setProperty("--bf-font",a.fontFamily)),document.body.appendChild(o),c(o),()=>{o.remove(),c(null);}},[e.ui?.zIndex,e.ui?.theme?.accentColor,e.ui?.theme?.panelBackground,e.ui?.theme?.panelForeground,e.ui?.theme?.fontFamily]),i?reactDom.createPortal(jsxRuntime.jsx(k,{blocfeed_id:e.blocfeed_id,...t.config?{config:t.config}:{},children:jsxRuntime.jsx(re,{config:e})}),i):null}exports.BlocFeedProvider=k;exports.BlocFeedWidget=ae;exports.useBlocFeed=B;
389
+
390
+ /* ------------------------------------------------------------------ */
391
+ /* Queue badge */
392
+ /* ------------------------------------------------------------------ */
393
+
394
+ :where([data-blocfeed-ui-root]) .bf-badge {
395
+ display: inline-flex;
396
+ align-items: center;
397
+ justify-content: center;
398
+ min-width: 16px;
399
+ height: 16px;
400
+ padding: 0 4px;
401
+ border-radius: 999px;
402
+ background: var(--bf-danger);
403
+ color: white;
404
+ font-size: 10px;
405
+ font-weight: 600;
406
+ line-height: 1;
407
+ flex-shrink: 0;
408
+ }
409
+
410
+ :where([data-blocfeed-ui-root]) .bf-badge-float {
411
+ position: absolute;
412
+ top: -4px;
413
+ right: -4px;
414
+ }
415
+
416
+ /* ------------------------------------------------------------------ */
417
+ /* Typewriter cursor */
418
+ /* ------------------------------------------------------------------ */
419
+
420
+ :where([data-blocfeed-ui-root]) .bf-cursor {
421
+ display: inline-block;
422
+ width: 1px;
423
+ height: 1em;
424
+ background: var(--bf-panel-fg);
425
+ margin-left: 1px;
426
+ vertical-align: text-bottom;
427
+ animation: bf-blink 1s steps(2) infinite;
428
+ }
429
+
430
+ @keyframes bf-blink {
431
+ 0% { opacity: 1; }
432
+ 50% { opacity: 0; }
433
+ }
434
+
435
+ /* ------------------------------------------------------------------ */
436
+ /* Panel / toast / hint entrance animations */
437
+ /* ------------------------------------------------------------------ */
438
+
439
+ :where([data-blocfeed-ui-root]) .bf-panel {
440
+ animation: bf-panel-in 0.2s ease-out;
441
+ }
442
+
443
+ @keyframes bf-panel-in {
444
+ from { opacity: 0; transform: translateY(8px); }
445
+ to { opacity: 1; transform: translateY(0); }
446
+ }
447
+
448
+ :where([data-blocfeed-ui-root]) .bf-toast {
449
+ animation: bf-toast-in 0.25s ease-out;
450
+ }
451
+
452
+ @keyframes bf-toast-in {
453
+ from { opacity: 0; transform: translateX(-50%) translateY(12px); }
454
+ to { opacity: 1; transform: translateX(-50%) translateY(0); }
455
+ }
456
+
457
+ :where([data-blocfeed-ui-root]) .bf-hint {
458
+ animation: bf-hint-in 0.2s ease-out;
459
+ }
460
+
461
+ @keyframes bf-hint-in {
462
+ from { opacity: 0; transform: translateX(-50%) translateY(-10px); }
463
+ to { opacity: 1; transform: translateX(-50%) translateY(0); }
464
+ }
465
+
466
+ /* ------------------------------------------------------------------ */
467
+ /* Reduced motion */
468
+ /* ------------------------------------------------------------------ */
469
+
470
+ @media (prefers-reduced-motion: reduce) {
471
+ :where([data-blocfeed-ui-root]) .bf-panel,
472
+ :where([data-blocfeed-ui-root]) .bf-toast,
473
+ :where([data-blocfeed-ui-root]) .bf-hint,
474
+ :where([data-blocfeed-ui-root]) .bf-cursor {
475
+ animation: none;
476
+ }
477
+ }
478
+ `;function de(){if(!chunkJLPJP7DD_cjs.a()||document.getElementById(ce))return;let t=document.createElement("style");t.id=ce,t.textContent=tt,document.head.appendChild(t);}function Z(){let t=react.useContext($);if(!t)throw new Error("useBlocFeed must be used within a <BlocFeedProvider />");return {state:t.state,controller:t.controller,start:t.controller.start,stop:t.controller.stop,clearSelection:t.controller.clearSelection,submit:t.controller.submit}}function m(t){switch(t){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 f({size:t=14}){return jsxRuntime.jsx("svg",{width:t,height:t,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 pe({size:t=14}){return jsxRuntime.jsx("svg",{width:t,height:t,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 fe({size:t=16}){return jsxRuntime.jsxs("svg",{width:t,height:t,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 be({position:t,onClick:e,isVisible:n,label:i,queueCount:o,showSuccess:c}){return n?jsxRuntime.jsxs("button",{className:m(t),type:"button",onClick:e,"aria-label":i,children:[c?jsxRuntime.jsx("span",{style:{display:"inline-flex",color:"var(--bf-accent)"},children:jsxRuntime.jsx(f,{size:14})}):jsxRuntime.jsxs(jsxRuntime.Fragment,{children:[jsxRuntime.jsx("span",{className:"bf-dot","aria-hidden":"true"}),i]}),o>0&&jsxRuntime.jsx("span",{className:"bf-badge","aria-label":`${o} queued`,children:o})]}):null}function b(){let[t,e]=react.useState(()=>typeof window>"u"?false:window.matchMedia("(prefers-reduced-motion: reduce)").matches);return react.useEffect(()=>{let n=window.matchMedia("(prefers-reduced-motion: reduce)"),i=o=>e(o.matches);return n.addEventListener("change",i),()=>n.removeEventListener("change",i)},[]),t}var lt={duration:.18,ease:"easeOut"},ct={duration:0};function ge({position:t,onClick:e,isVisible:n,label:i,queueCount:o,showSuccess:c}){let[r,l]=react.useState(false),a=b(),s=a?ct:lt;return jsxRuntime.jsx(framerMotion.AnimatePresence,{mode:"wait",children:n&&jsxRuntime.jsx(framerMotion.motion.button,{className:m(t),type:"button",onClick:e,onMouseEnter:()=>l(true),onMouseLeave:()=>l(false),"aria-label":i,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(f,{size:14})},"success"):jsxRuntime.jsxs(jsxRuntime.Fragment,{children:[jsxRuntime.jsx(framerMotion.motion.span,{className:"bf-dot","aria-hidden":"true",animate:a?{}:{scale:r?1:[1,1.2,1],boxShadow:r?"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:r||a?s:{duration:2,repeat:1/0,ease:"easeInOut"}}),jsxRuntime.jsx(framerMotion.AnimatePresence,{mode:"wait",children:r&&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:i},"label")}),o>0&&jsxRuntime.jsx("span",{className:"bf-badge","aria-label":`${o} queued`,children:o})]})},"dot")})}var ut={duration:.18,ease:"easeOut"},xe={duration:0};function ve({position:t,onClick:e,isVisible:n,label:i,queueCount:o,showSuccess:c}){let[r,l]=react.useState(false),a=b(),s=a?xe:ut;return jsxRuntime.jsx(framerMotion.AnimatePresence,{mode:"wait",children:n&&jsxRuntime.jsxs(framerMotion.motion.div,{className:m(t),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:r&&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:i},"tooltip")}),jsxRuntime.jsxs(framerMotion.motion.button,{type:"button",onClick:e,"aria-label":i,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?xe:{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(f,{size:16})},"success"):jsxRuntime.jsx(pe,{size:16}),o>0&&jsxRuntime.jsx("span",{className:"bf-badge bf-badge-float","aria-label":`${o} queued`,children:o})]})]},"bubble")})}var gt={duration:.2,ease:"easeOut"},ht={duration:0};function ke(t){return t==="bottom-left"||t==="top-left"}function xt(t){return `bf-trigger-edge ${ke(t)?"bf-trigger-edge-left":"bf-trigger-edge-right"}`}function Te({position:t,onClick:e,isVisible:n,label:i,queueCount:o,showSuccess:c}){let[r,l]=react.useState(false),a=ke(t),s=b(),u=s?ht:gt;return jsxRuntime.jsx(framerMotion.AnimatePresence,{mode:"wait",children:n&&jsxRuntime.jsx(framerMotion.motion.button,{className:xt(t),type:"button",onClick:e,onMouseEnter:()=>l(true),onMouseLeave:()=>l(false),"aria-label":i,initial:{opacity:0,width:0},animate:{opacity:1,width:r?140:22,height:r?40:90},exit:{width:0,opacity:0},transition:u,whileTap:{scale:.97},style:{top:"50%",translateY:"-50%"},children:c?jsxRuntime.jsx(framerMotion.motion.span,{initial:{scale:0},animate:{scale:1},transition:u,style:{display:"inline-flex",color:"var(--bf-accent)"},children:jsxRuntime.jsx(f,{size:14})},"success"):jsxRuntime.jsxs(jsxRuntime.Fragment,{children:[jsxRuntime.jsxs(framerMotion.motion.span,{animate:{rotate:s||r?0:a?-90:90,opacity:r?1:.6},transition:u,style:{display:"flex",alignItems:"center",gap:"8px",whiteSpace:"nowrap",fontSize:"12px",letterSpacing:"0.5px",textTransform:"uppercase"},children:[r&&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}}),i]}),jsxRuntime.jsx(framerMotion.motion.span,{"aria-hidden":"true",animate:{opacity:r?1:0},transition:{duration:.12},style:{position:"absolute",top:0,bottom:0,[a?"left":"right"]:0,width:"2px",background:"var(--bf-accent)"}}),o>0&&jsxRuntime.jsx("span",{className:"bf-badge","aria-label":`${o} queued`,children:o})]})},"edge-tab")})}var wt={duration:.18,ease:"easeOut"},kt={duration:0};function Pe({delay:t,hovered:e,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:e?{scale:1,opacity:0}:{scale:[1,1.8],opacity:[.5,0]},transition:e?{duration:.15}:{duration:2,repeat:1/0,delay:t,ease:"easeOut"}})}function Se({position:t,onClick:e,isVisible:n,label:i,queueCount:o,showSuccess:c}){let[r,l]=react.useState(false),a=b(),s=a?kt:wt;return jsxRuntime.jsx(framerMotion.AnimatePresence,{mode:"wait",children:n&&jsxRuntime.jsx(framerMotion.motion.button,{className:m(t),type:"button",onClick:e,onMouseEnter:()=>l(true),onMouseLeave:()=>l(false),"aria-label":i,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(f,{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(Pe,{delay:0,hovered:r,reduced:a}),jsxRuntime.jsx(Pe,{delay:.7,hovered:r,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:r&&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:i},"label")}),o>0&&jsxRuntime.jsx("span",{className:"bf-badge","aria-label":`${o} queued`,children:o})]})},"pulse-ring")})}var Et={duration:.18,ease:"easeOut"},St={duration:0};function Nt(t){switch(t){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 Be({position:t,onClick:e,isVisible:n,label:i,queueCount:o,showSuccess:c}){let[r,l]=react.useState(false),a=b(),s=a?St:Et;return jsxRuntime.jsx(framerMotion.AnimatePresence,{mode:"wait",children:n&&jsxRuntime.jsxs(framerMotion.motion.button,{className:Nt(t),type:"button",onClick:e,onMouseEnter:()=>l(true),onMouseLeave:()=>l(false),"aria-label":i,initial:{opacity:0,y:a?0:5},animate:{opacity:r?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(f,{size:14})}):jsxRuntime.jsxs(jsxRuntime.Fragment,{children:[jsxRuntime.jsx("span",{children:i}),o>0&&jsxRuntime.jsx("span",{className:"bf-badge",style:{marginLeft:"4px"},"aria-label":`${o} queued`,children:o})]}),!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:r?1:0},transition:s})]},"minimal")})}var Mt={duration:.18,ease:"easeOut"},Rt={duration:0};function Re({position:t,onClick:e,isVisible:n,label:i,queueCount:o,showSuccess:c}){let[r,l]=react.useState(false),a=b(),s=a?Rt:Mt;return jsxRuntime.jsx(framerMotion.AnimatePresence,{mode:"wait",children:n&&jsxRuntime.jsx(framerMotion.motion.button,{className:m(t),type:"button",onClick:e,onMouseEnter:()=>l(true),onMouseLeave:()=>l(false),"aria-label":i,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(f,{size:14})},"success"):jsxRuntime.jsxs(jsxRuntime.Fragment,{children:[jsxRuntime.jsx(framerMotion.motion.span,{style:{display:"inline-flex",flexShrink:0},animate:a?{}:r?{scale:1.2,rotate:0}:{rotate:[-5,5,-5]},transition:r||a?s:{duration:3,repeat:1/0,ease:"easeInOut"},children:jsxRuntime.jsx(fe,{size:16})}),jsxRuntime.jsx(framerMotion.AnimatePresence,{mode:"wait",children:r&&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:i},"label")}),o>0&&jsxRuntime.jsx("span",{className:"bf-badge","aria-label":`${o} queued`,children:o})]})},"icon-pop")})}var Lt={duration:.18,ease:"easeOut"},Wt={duration:0};function Ae({position:t,onClick:e,isVisible:n,label:i,queueCount:o,showSuccess:c}){let[r,l]=react.useState(false),a=b(),s=a?Wt:Lt;return jsxRuntime.jsx(framerMotion.AnimatePresence,{mode:"wait",children:n&&jsxRuntime.jsx(framerMotion.motion.button,{className:m(t),type:"button",onClick:e,onMouseEnter:()=>l(true),onMouseLeave:()=>l(false),"aria-label":i,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(f,{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:r?1:[.5,1,.5],boxShadow:r?"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:r||a?s:{duration:2,repeat:1/0,ease:"easeInOut"}}),!r&&!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:r&&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:i},"label")}),o>0&&jsxRuntime.jsx("span",{className:"bf-badge","aria-label":`${o} queued`,children:o})]})},"beacon")})}var Dt={duration:.18,ease:"easeOut"},$t={duration:0};function Oe({position:t,onClick:e,isVisible:n,label:i,queueCount:o,showSuccess:c}){let[r,l]=react.useState(false),[a,s]=react.useState(0),u=b(),W=u?$t:Dt,h=react.useRef(null);react.useEffect(()=>{if(h.current&&(clearInterval(h.current),h.current=null),!n||r||u){s(r||u?i.length:0);return}let P=8,D=i.length*2+P*2,v=0;return h.current=setInterval(()=>{v=(v+1)%D,v<=i.length?s(v):v<=i.length+P?s(i.length):v<=i.length*2+P?s(i.length*2+P-v):s(0);},100),()=>{h.current&&(clearInterval(h.current),h.current=null);}},[n,r,u,i]);let K=i.slice(0,a);return jsxRuntime.jsx(framerMotion.AnimatePresence,{mode:"wait",children:n&&jsxRuntime.jsx(framerMotion.motion.button,{className:m(t),type:"button",onClick:e,onMouseEnter:()=>l(true),onMouseLeave:()=>l(false),"aria-label":i,initial:{opacity:0,y:u?0:5},animate:{opacity:1,y:0},exit:{opacity:0,y:u?0:5},transition:W,whileTap:{scale:.95},style:{minWidth:"44px"},children:c?jsxRuntime.jsx(framerMotion.motion.span,{initial:{scale:0},animate:{scale:1},transition:W,style:{display:"inline-flex",color:"var(--bf-accent)"},children:jsxRuntime.jsx(f,{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:[K,jsxRuntime.jsx("span",{className:"bf-cursor","aria-hidden":"true"})]}),o>0&&jsxRuntime.jsx("span",{className:"bf-badge","aria-label":`${o} queued`,children:o})]})},"typewriter")})}function He(t){switch(t){case "dot":return ge;case "bubble":return ve;case "edge-tab":return Te;case "pulse-ring":return Se;case "minimal":return Be;case "icon-pop":return Re;case "beacon":return Ae;case "typewriter":return Oe;default:return be}}function De(t,e,n){return Math.max(e,Math.min(n,t))}function Qt(t,e,n="bottom-right"){let o=window.innerWidth,c=window.innerHeight,r;r=De(t.x,12,Math.max(12,o-e-12));let l=t.y+t.height+12,a=Math.max(12,t.y-240);return {top:l+240<=c?l:a,left:r}}function Ut(t){let{rect:e}=t,n={left:`${e.x}px`,top:`${e.y}px`,width:`${Math.max(0,e.width)}px`,height:`${Math.max(0,e.height)}px`};return jsxRuntime.jsx("div",{className:"bf-highlight",style:n,"aria-hidden":"true"})}function Vt(t){let e=react.useRef(null);return react.useEffect(()=>{if(!t||!e.current)return;e.current.querySelector(".bf-textarea")?.focus();let i=o=>{if(o.key!=="Tab"||!e.current)return;let c=e.current.querySelectorAll('button:not([disabled]), textarea:not([disabled]), input:not([disabled]), [tabindex]:not([tabindex="-1"])');if(c.length===0)return;let r=c[0],l=c[c.length-1];o.shiftKey&&document.activeElement===r?(o.preventDefault(),l.focus()):!o.shiftKey&&document.activeElement===l&&(o.preventDefault(),r.focus());};return document.addEventListener("keydown",i,{capture:true}),()=>document.removeEventListener("keydown",i,{capture:true})},[t]),e}function Gt(t){let{state:e,controller:n,start:i,stop:o,clearSelection:c,submit:r}=Z(),l=t.config.ui?.position,[a,s]=react.useState(null),[u,W]=react.useState(""),[h,K]=react.useState(t.config.capture?.element??true),[P,D]=react.useState(t.config.capture?.fullPage??false),[v,q]=react.useState(null),ee=e.phase==="review"||e.phase==="capturing"||e.phase==="submitting"||e.phase==="error"||e.phase==="success",Xe=Vt(ee),[Ye,je]=react.useState(0);react.useEffect(()=>{e.phase==="idle"&&je(chunkJLPJP7DD_cjs.i());},[e.phase]);let[Qe,te]=react.useState(false),oe=react.useRef(e.phase);react.useEffect(()=>{if(oe.current==="success"&&e.phase==="idle"){te(true);let p=window.setTimeout(()=>te(false),1500);return ()=>window.clearTimeout(p)}oe.current=e.phase;},[e.phase]),react.useEffect(()=>{let p=t.config.ui?.shortcut;if(!p)return;let z=p.toLowerCase().split("+").map(y=>y.trim()),I=z[z.length-1]||"",F=new Set(z.slice(0,-1)),ie=y=>{let Ge=/Mac|iPod|iPhone|iPad/.test(navigator.platform);if(F.has("mod")){if(Ge?!y.metaKey:!y.ctrlKey)return}else if(F.has("ctrl")&&!y.ctrlKey||(F.has("meta")||F.has("cmd"))&&!y.metaKey)return;F.has("shift")&&!y.shiftKey||(F.has("alt")||F.has("option"))&&!y.altKey||y.key.toLowerCase()===I&&(y.preventDefault(),e.phase==="idle"?i():o());};return document.addEventListener("keydown",ie),()=>document.removeEventListener("keydown",ie)},[t.config.ui?.shortcut,e.phase,i,o]),react.useEffect(()=>n.subscribeHover(s),[n]),react.useEffect(()=>{let p=n.__unsafeGetSelectedElement();if(!p||e.phase==="idle"||e.phase==="picking"){q(null);return}let z=()=>{q(chunkJLPJP7DD_cjs.b(p.getBoundingClientRect()));};z();let I=()=>z();return window.addEventListener("scroll",I,{capture:true,passive:true}),window.addEventListener("resize",I,{passive:true}),()=>{window.removeEventListener("scroll",I,{capture:true}),window.removeEventListener("resize",I);}},[n,e.phase,e.selection?.selector]),react.useEffect(()=>{e.phase==="review"&&(W(""),K(t.config.capture?.element??true),D(t.config.capture?.fullPage??false));},[e.phase,e.selection?.selector,t.config.capture?.element,t.config.capture?.fullPage]),react.useEffect(()=>{if(e.phase!=="success")return;let p=window.setTimeout(()=>o(),1200);return ()=>window.clearTimeout(p)},[e.phase,o]);let w=e.phase==="capturing"||e.phase==="submitting",E=e.phase==="picking"?a?.rect??null:v??e.selection?.rect??null,U=react.useMemo(()=>E?Qt(E,360,l):null,[E?.x,E?.y,E?.width,E?.height,l]),re=e.lastError?.message,V=react.useCallback(()=>{r(u,{capture:{element:h,fullPage:P}});},[r,u,h,P]),Ue=react.useCallback(p=>{(p.metaKey||p.ctrlKey)&&p.key==="Enter"&&u.trim().length>0&&!w&&(p.preventDefault(),V());},[V,u,w]),Ve=He(t.config.ui?.triggerStyle);return jsxRuntime.jsxs(jsxRuntime.Fragment,{children:[jsxRuntime.jsx(Ve,{position:l,onClick:()=>i(),isVisible:e.phase==="idle",label:t.config.ui?.triggerLabel??"Feedback",queueCount:Ye,showSuccess:Qe}),e.phase!=="idle"&&jsxRuntime.jsxs("div",{className:"bf-overlay",role:"presentation",children:[e.phase!=="picking"&&jsxRuntime.jsx("div",{className:"bf-blocker",role:"presentation",onClick:()=>o()}),E&&jsxRuntime.jsx(Ut,{rect:E}),e.phase==="picking"&&jsxRuntime.jsxs("div",{className:"bf-hint",role:"status","aria-live":"polite",children:[jsxRuntime.jsxs("p",{id:"bf-hint-text",children:["Click an element to attach your feedback. Press ",jsxRuntime.jsx("strong",{children:"Esc"})," to cancel."]}),jsxRuntime.jsx("button",{type:"button",className:"bf-btn",onClick:()=>o(),"aria-label":"Cancel element selection",children:"Cancel"})]}),ee&&U&&jsxRuntime.jsxs("div",{ref:Xe,className:"bf-panel",style:{left:U.left,top:U.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:"Feedback"}),jsxRuntime.jsxs("div",{className:"bf-row",style:{justifyContent:"flex-end"},children:[jsxRuntime.jsx("button",{type:"button",className:"bf-btn",onClick:()=>c(),disabled:w,"aria-label":"Re-pick element",children:"Re-pick"}),jsxRuntime.jsx("button",{type:"button",className:"bf-btn",onClick:()=>o(),disabled:w,"aria-label":"Close feedback form",children:"Close"})]})]}),jsxRuntime.jsxs("div",{className:"bf-panelBody",children:[jsxRuntime.jsx("textarea",{className:"bf-textarea",placeholder:"What's happening? What did you expect?",value:u,onChange:p=>W(p.target.value),onKeyDown:Ue,disabled:w,"aria-label":"Feedback message"}),jsxRuntime.jsxs("div",{className:"bf-row",role:"group","aria-label":"Screenshot options",children:[jsxRuntime.jsxs("label",{children:[jsxRuntime.jsx("input",{type:"checkbox",checked:h,onChange:p=>K(p.target.checked),disabled:w}),"Screenshot element"]}),jsxRuntime.jsxs("label",{children:[jsxRuntime.jsx("input",{type:"checkbox",checked:P,onChange:p=>D(p.target.checked),disabled:w}),"Full page"]})]}),e.phase==="capturing"&&jsxRuntime.jsxs("div",{className:"bf-status",role:"status","aria-live":"polite",children:[jsxRuntime.jsx("span",{className:"bf-spinner","aria-hidden":"true"}),"Capturing screenshots\u2026"]}),e.phase==="submitting"&&jsxRuntime.jsxs("div",{className:"bf-status",role:"status","aria-live":"polite",children:[jsxRuntime.jsx("span",{className:"bf-spinner","aria-hidden":"true"}),"Submitting\u2026"]}),e.phase==="success"&&jsxRuntime.jsx("div",{className:"bf-status",role:"status","aria-live":"polite",children:"Sent. Thank you!"}),e.phase==="error"&&re&&jsxRuntime.jsx("div",{className:"bf-error",role:"alert",children:re}),jsxRuntime.jsxs("div",{className:"bf-actions",children:[jsxRuntime.jsx("button",{type:"button",className:"bf-btn",onClick:()=>o(),disabled:w,"aria-label":"Cancel feedback",children:"Cancel"}),jsxRuntime.jsx("button",{type:"button",className:"bf-btn bf-btnPrimary",onClick:V,disabled:w||u.trim().length===0,"aria-label":"Send feedback",children:"Send"})]})]})]})]}),e.phase==="success"&&jsxRuntime.jsx("div",{className:"bf-toast",role:"status","aria-live":"polite",children:"Feedback sent"})]})}function Jt(t){let e={...t.config??{},blocfeed_id:t.blocfeed_id},[n,i]=react.useState(null);return react.useEffect(()=>{de();let o=document.createElement("div");o.setAttribute("data-blocfeed-ui-root","true"),o.setAttribute("data-blocfeed-ui","true");let c=e.ui?.zIndex;typeof c=="number"&&o.style.setProperty("--bf-z",String(c));let r=e.ui?.theme;return r&&(r.accentColor&&o.style.setProperty("--bf-accent",r.accentColor),r.panelBackground&&o.style.setProperty("--bf-panel-bg",r.panelBackground),r.panelForeground&&o.style.setProperty("--bf-panel-fg",r.panelForeground),r.fontFamily&&o.style.setProperty("--bf-font",r.fontFamily)),document.body.appendChild(o),i(o),()=>{o.remove(),i(null);}},[e.ui?.zIndex,e.ui?.theme?.accentColor,e.ui?.theme?.panelBackground,e.ui?.theme?.panelForeground,e.ui?.theme?.fontFamily]),n?reactDom.createPortal(jsxRuntime.jsx(J,{blocfeed_id:e.blocfeed_id,...t.config?{config:t.config}:{},children:jsxRuntime.jsx(Gt,{config:e})}),n):null}
479
+ exports.BlocFeedProvider=J;exports.BlocFeedWidget=Jt;exports.useBlocFeed=Z;
package/dist/main.d.cts CHANGED
@@ -1,5 +1,5 @@
1
- import { B as BlocFeedConfig, a as BlocFeedState, b as BlocFeedController, C as CaptureConfig, S as SubmitResult } from './controller-olqOZLhp.cjs';
2
- export { c as BlocFeedError, d as BlocFeedUser, e as CaptureDiagnostics, f as CaptureResult, E as ElementDescriptor, F as FeedbackApiResponse, g as FeedbackPayload, I as ImageAsset, M as MaybePromise, h as MetadataConfig, i as MetadataContext, P as PickerConfig, R as Rect, j as ScreenshotAdapter, k as ScreenshotAdapterOptions, l as ScreenshotIntent, m as ScreenshotMime, n as SessionPhase, T as ThemeConfig, o as TransportConfig, p as TransportResult, W as WidgetPosition } from './controller-olqOZLhp.cjs';
1
+ import { B as BlocFeedConfig, a as BlocFeedState, b as BlocFeedController, C as CaptureConfig, S as SubmitResult } from './controller-did-WBAQ.cjs';
2
+ export { c as BlocFeedError, d as BlocFeedUser, e as CaptureDiagnostics, f as CaptureResult, E as ElementDescriptor, F as FeedbackApiResponse, g as FeedbackPayload, I as ImageAsset, M as MaybePromise, h as MetadataConfig, i as MetadataContext, P as PickerConfig, R as Rect, j as ScreenshotAdapter, k as ScreenshotAdapterOptions, l as ScreenshotIntent, m as ScreenshotMime, n as SessionPhase, T as ThemeConfig, o as TransportConfig, p as TransportResult, q as TriggerStyle, W as WidgetPosition } from './controller-did-WBAQ.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';
package/dist/main.d.ts CHANGED
@@ -1,5 +1,5 @@
1
- import { B as BlocFeedConfig, a as BlocFeedState, b as BlocFeedController, C as CaptureConfig, S as SubmitResult } from './controller-olqOZLhp.js';
2
- export { c as BlocFeedError, d as BlocFeedUser, e as CaptureDiagnostics, f as CaptureResult, E as ElementDescriptor, F as FeedbackApiResponse, g as FeedbackPayload, I as ImageAsset, M as MaybePromise, h as MetadataConfig, i as MetadataContext, P as PickerConfig, R as Rect, j as ScreenshotAdapter, k as ScreenshotAdapterOptions, l as ScreenshotIntent, m as ScreenshotMime, n as SessionPhase, T as ThemeConfig, o as TransportConfig, p as TransportResult, W as WidgetPosition } from './controller-olqOZLhp.js';
1
+ import { B as BlocFeedConfig, a as BlocFeedState, b as BlocFeedController, C as CaptureConfig, S as SubmitResult } from './controller-did-WBAQ.js';
2
+ export { c as BlocFeedError, d as BlocFeedUser, e as CaptureDiagnostics, f as CaptureResult, E as ElementDescriptor, F as FeedbackApiResponse, g as FeedbackPayload, I as ImageAsset, M as MaybePromise, h as MetadataConfig, i as MetadataContext, P as PickerConfig, R as Rect, j as ScreenshotAdapter, k as ScreenshotAdapterOptions, l as ScreenshotIntent, m as ScreenshotMime, n as SessionPhase, T as ThemeConfig, o as TransportConfig, p as TransportResult, q as TriggerStyle, W as WidgetPosition } from './controller-did-WBAQ.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';
package/dist/main.js CHANGED
@@ -1,5 +1,5 @@
1
1
  "use client";
2
- import {j,a,b}from'./chunk-FMFONS5S.js';import {createContext,useMemo,useState,useEffect,useContext,useCallback,useRef}from'react';import {jsx,jsxs,Fragment}from'react/jsx-runtime';import {createPortal}from'react-dom';var h=createContext(null);function k(t){let e=useMemo(()=>j({...t.config??{},blocfeed_id:t.blocfeed_id}),[]),[i,c]=useState(()=>e.getState());return useEffect(()=>e.subscribe(c),[e]),useEffect(()=>e.setConfig({...t.config??{},blocfeed_id:t.blocfeed_id}),[e,t.config,t.blocfeed_id]),useEffect(()=>()=>e.destroy(),[e]),jsx(h.Provider,{value:{controller:e,state:i},children:t.children})}var L="blocfeed-styles-v1",G=`
2
+ import {j,a,i,b as b$1}from'./chunk-FMFONS5S.js';import {createContext,useMemo,useState,useEffect,useContext,useRef,useCallback}from'react';import {jsx,jsxs,Fragment}from'react/jsx-runtime';import {createPortal}from'react-dom';import {AnimatePresence,motion}from'framer-motion';var $=createContext(null);function J(t){let e=useMemo(()=>j({...t.config??{},blocfeed_id:t.blocfeed_id}),[]),[n,i]=useState(()=>e.getState());return useEffect(()=>e.subscribe(i),[e]),useEffect(()=>e.setConfig({...t.config??{},blocfeed_id:t.blocfeed_id}),[e,t.config,t.blocfeed_id]),useEffect(()=>()=>e.destroy(),[e]),jsx($.Provider,{value:{controller:e,state:n},children:t.children})}var ce="blocfeed-styles-v1",tt=`
3
3
  :where([data-blocfeed-ui-root]),
4
4
  :where([data-blocfeed-ui-root]) * {
5
5
  box-sizing: border-box;
@@ -290,6 +290,87 @@ import {j,a,b}from'./chunk-FMFONS5S.js';import {createContext,useMemo,useState,u
290
290
  50% { opacity: 1; transform: scale(1.2); }
291
291
  }
292
292
 
293
+ /* ------------------------------------------------------------------ */
294
+ /* Trigger variant: edge-tab */
295
+ /* ------------------------------------------------------------------ */
296
+
297
+ :where([data-blocfeed-ui-root]) .bf-trigger-edge {
298
+ position: fixed;
299
+ z-index: var(--bf-z);
300
+ display: flex;
301
+ align-items: center;
302
+ justify-content: center;
303
+ border: 1px solid var(--bf-border);
304
+ background: var(--bf-panel-bg);
305
+ color: var(--bf-panel-fg);
306
+ box-shadow: var(--bf-shadow);
307
+ cursor: pointer;
308
+ user-select: none;
309
+ -webkit-tap-highlight-color: transparent;
310
+ overflow: hidden;
311
+ padding: 0;
312
+ font-family: var(--bf-font);
313
+ font-size: 12px;
314
+ letter-spacing: 0.5px;
315
+ }
316
+
317
+ :where([data-blocfeed-ui-root]) .bf-trigger-edge:focus-visible {
318
+ outline: 2px solid var(--bf-accent);
319
+ outline-offset: 2px;
320
+ }
321
+
322
+ :where([data-blocfeed-ui-root]) .bf-trigger-edge-left {
323
+ left: 0;
324
+ right: auto;
325
+ border-radius: 0 6px 6px 0;
326
+ border-left: none;
327
+ }
328
+
329
+ :where([data-blocfeed-ui-root]) .bf-trigger-edge-right {
330
+ right: 0;
331
+ left: auto;
332
+ border-radius: 6px 0 0 6px;
333
+ border-right: none;
334
+ }
335
+
336
+ /* ------------------------------------------------------------------ */
337
+ /* Trigger variant: minimal */
338
+ /* ------------------------------------------------------------------ */
339
+
340
+ :where([data-blocfeed-ui-root]) .bf-trigger-minimal {
341
+ position: fixed;
342
+ right: 18px;
343
+ bottom: 18px;
344
+ z-index: var(--bf-z);
345
+ display: inline-flex;
346
+ align-items: center;
347
+ background: transparent;
348
+ border: none;
349
+ box-shadow: none;
350
+ padding: 8px 4px;
351
+ font-family: var(--bf-font);
352
+ font-size: 13px;
353
+ color: var(--bf-panel-fg);
354
+ cursor: pointer;
355
+ user-select: none;
356
+ -webkit-tap-highlight-color: transparent;
357
+ }
358
+
359
+ :where([data-blocfeed-ui-root]) .bf-trigger-minimal.bf-trigger-bl {
360
+ left: 18px; bottom: 18px; right: auto; top: auto;
361
+ }
362
+ :where([data-blocfeed-ui-root]) .bf-trigger-minimal.bf-trigger-tr {
363
+ right: 18px; top: 18px; bottom: auto; left: auto;
364
+ }
365
+ :where([data-blocfeed-ui-root]) .bf-trigger-minimal.bf-trigger-tl {
366
+ left: 18px; top: 18px; right: auto; bottom: auto;
367
+ }
368
+
369
+ :where([data-blocfeed-ui-root]) .bf-trigger-minimal:focus-visible {
370
+ outline: 2px solid var(--bf-accent);
371
+ outline-offset: 2px;
372
+ }
373
+
293
374
  /* ------------------------------------------------------------------ */
294
375
  /* Screen reader only */
295
376
  /* ------------------------------------------------------------------ */
@@ -305,4 +386,94 @@ import {j,a,b}from'./chunk-FMFONS5S.js';import {createContext,useMemo,useState,u
305
386
  white-space: nowrap;
306
387
  border: 0;
307
388
  }
308
- `;function W(){if(!a()||document.getElementById(L))return;let t=document.createElement("style");t.id=L,t.textContent=G,document.head.appendChild(t);}function B(){let t=useContext(h);if(!t)throw new Error("useBlocFeed must be used within a <BlocFeedProvider />");return {state:t.state,controller:t.controller,start:t.controller.start,stop:t.controller.stop,clearSelection:t.controller.clearSelection,submit:t.controller.submit}}function I(t,e,i){return Math.max(e,Math.min(i,t))}function Z(t,e,i="bottom-right"){let o=window.innerWidth,s=window.innerHeight,a;a=I(t.x,12,Math.max(12,o-e-12));let d=t.y+t.height+12,x=Math.max(12,t.y-240);return {top:d+240<=s?d:x,left:a}}function ee(t){switch(t){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 te(t){let{rect:e}=t,i={left:`${e.x}px`,top:`${e.y}px`,width:`${Math.max(0,e.width)}px`,height:`${Math.max(0,e.height)}px`};return jsx("div",{className:"bf-highlight",style:i,"aria-hidden":"true"})}function oe(t){let e=useRef(null);return useEffect(()=>{if(!t||!e.current)return;e.current.querySelector(".bf-textarea")?.focus();let c=o=>{if(o.key!=="Tab"||!e.current)return;let s=e.current.querySelectorAll('button:not([disabled]), textarea:not([disabled]), input:not([disabled]), [tabindex]:not([tabindex="-1"])');if(s.length===0)return;let a=s[0],d=s[s.length-1];o.shiftKey&&document.activeElement===a?(o.preventDefault(),d.focus()):!o.shiftKey&&document.activeElement===d&&(o.preventDefault(),a.focus());};return document.addEventListener("keydown",c,{capture:true}),()=>document.removeEventListener("keydown",c,{capture:true})},[t]),e}function re(t){let{state:e,controller:i,start:c,stop:o,clearSelection:s,submit:a}=B(),d=t.config.ui?.position,[x,S]=useState(null),[p,P]=useState(""),[v,E]=useState(t.config.capture?.element??true),[y,R]=useState(t.config.capture?.fullPage??false),[K,N]=useState(null),z=e.phase==="review"||e.phase==="capturing"||e.phase==="submitting"||e.phase==="error"||e.phase==="success",j=oe(z);useEffect(()=>i.subscribeHover(S),[i]),useEffect(()=>{let n=i.__unsafeGetSelectedElement();if(!n||e.phase==="idle"||e.phase==="picking"){N(null);return}let M=()=>{N(b(n.getBoundingClientRect()));};M();let m=()=>M();return window.addEventListener("scroll",m,{capture:true,passive:true}),window.addEventListener("resize",m,{passive:true}),()=>{window.removeEventListener("scroll",m,{capture:true}),window.removeEventListener("resize",m);}},[i,e.phase,e.selection?.selector]),useEffect(()=>{e.phase==="review"&&(P(""),E(t.config.capture?.element??true),R(t.config.capture?.fullPage??false));},[e.phase,e.selection?.selector,t.config.capture?.element,t.config.capture?.fullPage]),useEffect(()=>{if(e.phase!=="success")return;let n=window.setTimeout(()=>o(),1200);return ()=>window.clearTimeout(n)},[e.phase,o]);let f=e.phase==="capturing"||e.phase==="submitting",b$1=e.phase==="picking"?x?.rect??null:K??e.selection?.rect??null,w=useMemo(()=>b$1?Z(b$1,360,d):null,[b$1?.x,b$1?.y,b$1?.width,b$1?.height,d]),T=e.lastError?.message,C=useCallback(()=>{a(p,{capture:{element:v,fullPage:y}});},[a,p,v,y]),O=useCallback(n=>{(n.metaKey||n.ctrlKey)&&n.key==="Enter"&&p.trim().length>0&&!f&&(n.preventDefault(),C());},[C,p,f]);return jsxs(Fragment,{children:[e.phase==="idle"&&jsxs("button",{className:ee(d),type:"button",onClick:()=>c(),"aria-label":"Give feedback",children:[jsx("span",{className:"bf-dot","aria-hidden":"true"}),"Feedback"]}),e.phase!=="idle"&&jsxs("div",{className:"bf-overlay",role:"presentation",children:[e.phase!=="picking"&&jsx("div",{className:"bf-blocker",role:"presentation",onClick:()=>o()}),b$1&&jsx(te,{rect:b$1}),e.phase==="picking"&&jsxs("div",{className:"bf-hint",role:"status","aria-live":"polite",children:[jsxs("p",{id:"bf-hint-text",children:["Click an element to attach your feedback. Press ",jsx("strong",{children:"Esc"})," to cancel."]}),jsx("button",{type:"button",className:"bf-btn",onClick:()=>o(),"aria-label":"Cancel element selection",children:"Cancel"})]}),z&&w&&jsxs("div",{ref:j,className:"bf-panel",style:{left:w.left,top:w.top},role:"dialog","aria-modal":"true","aria-label":"Feedback form",children:[jsxs("div",{className:"bf-panelHeader",children:[jsx("div",{className:"bf-title",id:"bf-panel-title",children:"Feedback"}),jsxs("div",{className:"bf-row",style:{justifyContent:"flex-end"},children:[jsx("button",{type:"button",className:"bf-btn",onClick:()=>s(),disabled:f,"aria-label":"Re-pick element",children:"Re-pick"}),jsx("button",{type:"button",className:"bf-btn",onClick:()=>o(),disabled:f,"aria-label":"Close feedback form",children:"Close"})]})]}),jsxs("div",{className:"bf-panelBody",children:[jsx("textarea",{className:"bf-textarea",placeholder:"What's happening? What did you expect?",value:p,onChange:n=>P(n.target.value),onKeyDown:O,disabled:f,"aria-label":"Feedback message"}),jsxs("div",{className:"bf-row",role:"group","aria-label":"Screenshot options",children:[jsxs("label",{children:[jsx("input",{type:"checkbox",checked:v,onChange:n=>E(n.target.checked),disabled:f}),"Screenshot element"]}),jsxs("label",{children:[jsx("input",{type:"checkbox",checked:y,onChange:n=>R(n.target.checked),disabled:f}),"Full page"]})]}),e.phase==="capturing"&&jsxs("div",{className:"bf-status",role:"status","aria-live":"polite",children:[jsx("span",{className:"bf-spinner","aria-hidden":"true"}),"Capturing screenshots\u2026"]}),e.phase==="submitting"&&jsxs("div",{className:"bf-status",role:"status","aria-live":"polite",children:[jsx("span",{className:"bf-spinner","aria-hidden":"true"}),"Submitting\u2026"]}),e.phase==="success"&&jsx("div",{className:"bf-status",role:"status","aria-live":"polite",children:"Sent. Thank you!"}),e.phase==="error"&&T&&jsx("div",{className:"bf-error",role:"alert",children:T}),jsxs("div",{className:"bf-actions",children:[jsx("button",{type:"button",className:"bf-btn",onClick:()=>o(),disabled:f,"aria-label":"Cancel feedback",children:"Cancel"}),jsx("button",{type:"button",className:"bf-btn bf-btnPrimary",onClick:C,disabled:f||p.trim().length===0,"aria-label":"Send feedback",children:"Send"})]})]})]})]}),e.phase==="success"&&jsx("div",{className:"bf-toast",role:"status","aria-live":"polite",children:"Feedback sent"})]})}function ae(t){let e={...t.config??{},blocfeed_id:t.blocfeed_id},[i,c]=useState(null);return useEffect(()=>{W();let o=document.createElement("div");o.setAttribute("data-blocfeed-ui-root","true"),o.setAttribute("data-blocfeed-ui","true");let s=e.ui?.zIndex;typeof s=="number"&&o.style.setProperty("--bf-z",String(s));let a=e.ui?.theme;return a&&(a.accentColor&&o.style.setProperty("--bf-accent",a.accentColor),a.panelBackground&&o.style.setProperty("--bf-panel-bg",a.panelBackground),a.panelForeground&&o.style.setProperty("--bf-panel-fg",a.panelForeground),a.fontFamily&&o.style.setProperty("--bf-font",a.fontFamily)),document.body.appendChild(o),c(o),()=>{o.remove(),c(null);}},[e.ui?.zIndex,e.ui?.theme?.accentColor,e.ui?.theme?.panelBackground,e.ui?.theme?.panelForeground,e.ui?.theme?.fontFamily]),i?createPortal(jsx(k,{blocfeed_id:e.blocfeed_id,...t.config?{config:t.config}:{},children:jsx(re,{config:e})}),i):null}export{k as BlocFeedProvider,ae as BlocFeedWidget,B as useBlocFeed};
389
+
390
+ /* ------------------------------------------------------------------ */
391
+ /* Queue badge */
392
+ /* ------------------------------------------------------------------ */
393
+
394
+ :where([data-blocfeed-ui-root]) .bf-badge {
395
+ display: inline-flex;
396
+ align-items: center;
397
+ justify-content: center;
398
+ min-width: 16px;
399
+ height: 16px;
400
+ padding: 0 4px;
401
+ border-radius: 999px;
402
+ background: var(--bf-danger);
403
+ color: white;
404
+ font-size: 10px;
405
+ font-weight: 600;
406
+ line-height: 1;
407
+ flex-shrink: 0;
408
+ }
409
+
410
+ :where([data-blocfeed-ui-root]) .bf-badge-float {
411
+ position: absolute;
412
+ top: -4px;
413
+ right: -4px;
414
+ }
415
+
416
+ /* ------------------------------------------------------------------ */
417
+ /* Typewriter cursor */
418
+ /* ------------------------------------------------------------------ */
419
+
420
+ :where([data-blocfeed-ui-root]) .bf-cursor {
421
+ display: inline-block;
422
+ width: 1px;
423
+ height: 1em;
424
+ background: var(--bf-panel-fg);
425
+ margin-left: 1px;
426
+ vertical-align: text-bottom;
427
+ animation: bf-blink 1s steps(2) infinite;
428
+ }
429
+
430
+ @keyframes bf-blink {
431
+ 0% { opacity: 1; }
432
+ 50% { opacity: 0; }
433
+ }
434
+
435
+ /* ------------------------------------------------------------------ */
436
+ /* Panel / toast / hint entrance animations */
437
+ /* ------------------------------------------------------------------ */
438
+
439
+ :where([data-blocfeed-ui-root]) .bf-panel {
440
+ animation: bf-panel-in 0.2s ease-out;
441
+ }
442
+
443
+ @keyframes bf-panel-in {
444
+ from { opacity: 0; transform: translateY(8px); }
445
+ to { opacity: 1; transform: translateY(0); }
446
+ }
447
+
448
+ :where([data-blocfeed-ui-root]) .bf-toast {
449
+ animation: bf-toast-in 0.25s ease-out;
450
+ }
451
+
452
+ @keyframes bf-toast-in {
453
+ from { opacity: 0; transform: translateX(-50%) translateY(12px); }
454
+ to { opacity: 1; transform: translateX(-50%) translateY(0); }
455
+ }
456
+
457
+ :where([data-blocfeed-ui-root]) .bf-hint {
458
+ animation: bf-hint-in 0.2s ease-out;
459
+ }
460
+
461
+ @keyframes bf-hint-in {
462
+ from { opacity: 0; transform: translateX(-50%) translateY(-10px); }
463
+ to { opacity: 1; transform: translateX(-50%) translateY(0); }
464
+ }
465
+
466
+ /* ------------------------------------------------------------------ */
467
+ /* Reduced motion */
468
+ /* ------------------------------------------------------------------ */
469
+
470
+ @media (prefers-reduced-motion: reduce) {
471
+ :where([data-blocfeed-ui-root]) .bf-panel,
472
+ :where([data-blocfeed-ui-root]) .bf-toast,
473
+ :where([data-blocfeed-ui-root]) .bf-hint,
474
+ :where([data-blocfeed-ui-root]) .bf-cursor {
475
+ animation: none;
476
+ }
477
+ }
478
+ `;function de(){if(!a()||document.getElementById(ce))return;let t=document.createElement("style");t.id=ce,t.textContent=tt,document.head.appendChild(t);}function Z(){let t=useContext($);if(!t)throw new Error("useBlocFeed must be used within a <BlocFeedProvider />");return {state:t.state,controller:t.controller,start:t.controller.start,stop:t.controller.stop,clearSelection:t.controller.clearSelection,submit:t.controller.submit}}function m(t){switch(t){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 f({size:t=14}){return jsx("svg",{width:t,height:t,viewBox:"0 0 24 24",fill:"none",xmlns:"http://www.w3.org/2000/svg","aria-hidden":"true",children:jsx("path",{d:"M20 6L9 17l-5-5",stroke:"currentColor",strokeWidth:"2.5",strokeLinecap:"round",strokeLinejoin:"round"})})}function pe({size:t=14}){return jsx("svg",{width:t,height:t,viewBox:"0 0 24 24",fill:"none",xmlns:"http://www.w3.org/2000/svg","aria-hidden":"true",children: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 fe({size:t=16}){return jsxs("svg",{width:t,height:t,viewBox:"0 0 24 24",fill:"none",xmlns:"http://www.w3.org/2000/svg","aria-hidden":"true",children:[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"}),jsx("path",{d:"M22 6l-10 7L2 6",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round"})]})}function be({position:t,onClick:e,isVisible:n,label:i,queueCount:o,showSuccess:c}){return n?jsxs("button",{className:m(t),type:"button",onClick:e,"aria-label":i,children:[c?jsx("span",{style:{display:"inline-flex",color:"var(--bf-accent)"},children:jsx(f,{size:14})}):jsxs(Fragment,{children:[jsx("span",{className:"bf-dot","aria-hidden":"true"}),i]}),o>0&&jsx("span",{className:"bf-badge","aria-label":`${o} queued`,children:o})]}):null}function b(){let[t,e]=useState(()=>typeof window>"u"?false:window.matchMedia("(prefers-reduced-motion: reduce)").matches);return useEffect(()=>{let n=window.matchMedia("(prefers-reduced-motion: reduce)"),i=o=>e(o.matches);return n.addEventListener("change",i),()=>n.removeEventListener("change",i)},[]),t}var lt={duration:.18,ease:"easeOut"},ct={duration:0};function ge({position:t,onClick:e,isVisible:n,label:i,queueCount:o,showSuccess:c}){let[r,l]=useState(false),a=b(),s=a?ct:lt;return jsx(AnimatePresence,{mode:"wait",children:n&&jsx(motion.button,{className:m(t),type:"button",onClick:e,onMouseEnter:()=>l(true),onMouseLeave:()=>l(false),"aria-label":i,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?jsx(motion.span,{initial:{scale:0},animate:{scale:1},transition:s,style:{display:"inline-flex",color:"var(--bf-accent)"},children:jsx(f,{size:14})},"success"):jsxs(Fragment,{children:[jsx(motion.span,{className:"bf-dot","aria-hidden":"true",animate:a?{}:{scale:r?1:[1,1.2,1],boxShadow:r?"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:r||a?s:{duration:2,repeat:1/0,ease:"easeInOut"}}),jsx(AnimatePresence,{mode:"wait",children:r&&jsx(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:i},"label")}),o>0&&jsx("span",{className:"bf-badge","aria-label":`${o} queued`,children:o})]})},"dot")})}var ut={duration:.18,ease:"easeOut"},xe={duration:0};function ve({position:t,onClick:e,isVisible:n,label:i,queueCount:o,showSuccess:c}){let[r,l]=useState(false),a=b(),s=a?xe:ut;return jsx(AnimatePresence,{mode:"wait",children:n&&jsxs(motion.div,{className:m(t),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:[jsx(AnimatePresence,{mode:"wait",children:r&&jsx(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:i},"tooltip")}),jsxs(motion.button,{type:"button",onClick:e,"aria-label":i,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?xe:{y:{duration:3,repeat:1/0,ease:"easeInOut"}},whileHover:{scale:1.1,borderColor:"var(--bf-accent)"},whileTap:{scale:.9},children:[c?jsx(motion.span,{initial:{scale:0},animate:{scale:1},transition:s,style:{display:"inline-flex",color:"var(--bf-accent)"},children:jsx(f,{size:16})},"success"):jsx(pe,{size:16}),o>0&&jsx("span",{className:"bf-badge bf-badge-float","aria-label":`${o} queued`,children:o})]})]},"bubble")})}var gt={duration:.2,ease:"easeOut"},ht={duration:0};function ke(t){return t==="bottom-left"||t==="top-left"}function xt(t){return `bf-trigger-edge ${ke(t)?"bf-trigger-edge-left":"bf-trigger-edge-right"}`}function Te({position:t,onClick:e,isVisible:n,label:i,queueCount:o,showSuccess:c}){let[r,l]=useState(false),a=ke(t),s=b(),u=s?ht:gt;return jsx(AnimatePresence,{mode:"wait",children:n&&jsx(motion.button,{className:xt(t),type:"button",onClick:e,onMouseEnter:()=>l(true),onMouseLeave:()=>l(false),"aria-label":i,initial:{opacity:0,width:0},animate:{opacity:1,width:r?140:22,height:r?40:90},exit:{width:0,opacity:0},transition:u,whileTap:{scale:.97},style:{top:"50%",translateY:"-50%"},children:c?jsx(motion.span,{initial:{scale:0},animate:{scale:1},transition:u,style:{display:"inline-flex",color:"var(--bf-accent)"},children:jsx(f,{size:14})},"success"):jsxs(Fragment,{children:[jsxs(motion.span,{animate:{rotate:s||r?0:a?-90:90,opacity:r?1:.6},transition:u,style:{display:"flex",alignItems:"center",gap:"8px",whiteSpace:"nowrap",fontSize:"12px",letterSpacing:"0.5px",textTransform:"uppercase"},children:[r&&jsx(motion.span,{initial:{scale:0},animate:{scale:1},transition:{duration:.12},style:{width:"6px",height:"6px",borderRadius:"50%",background:"var(--bf-accent)",flexShrink:0}}),i]}),jsx(motion.span,{"aria-hidden":"true",animate:{opacity:r?1:0},transition:{duration:.12},style:{position:"absolute",top:0,bottom:0,[a?"left":"right"]:0,width:"2px",background:"var(--bf-accent)"}}),o>0&&jsx("span",{className:"bf-badge","aria-label":`${o} queued`,children:o})]})},"edge-tab")})}var wt={duration:.18,ease:"easeOut"},kt={duration:0};function Pe({delay:t,hovered:e,reduced:n}){return n?null:jsx(motion.span,{"aria-hidden":"true",style:{position:"absolute",width:"10px",height:"10px",borderRadius:"50%",border:"2px solid var(--bf-accent)",pointerEvents:"none"},animate:e?{scale:1,opacity:0}:{scale:[1,1.8],opacity:[.5,0]},transition:e?{duration:.15}:{duration:2,repeat:1/0,delay:t,ease:"easeOut"}})}function Se({position:t,onClick:e,isVisible:n,label:i,queueCount:o,showSuccess:c}){let[r,l]=useState(false),a=b(),s=a?kt:wt;return jsx(AnimatePresence,{mode:"wait",children:n&&jsx(motion.button,{className:m(t),type:"button",onClick:e,onMouseEnter:()=>l(true),onMouseLeave:()=>l(false),"aria-label":i,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?jsx(motion.span,{initial:{scale:0},animate:{scale:1},transition:s,style:{display:"inline-flex",color:"var(--bf-accent)"},children:jsx(f,{size:14})},"success"):jsxs(Fragment,{children:[jsxs("span",{style:{position:"relative",display:"flex",alignItems:"center",justifyContent:"center",width:"10px",height:"10px",flexShrink:0},children:[jsx(Pe,{delay:0,hovered:r,reduced:a}),jsx(Pe,{delay:.7,hovered:r,reduced:a}),jsx(motion.span,{className:"bf-dot","aria-hidden":"true",style:{position:"relative",zIndex:1}})]}),jsx(AnimatePresence,{mode:"wait",children:r&&jsx(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:i},"label")}),o>0&&jsx("span",{className:"bf-badge","aria-label":`${o} queued`,children:o})]})},"pulse-ring")})}var Et={duration:.18,ease:"easeOut"},St={duration:0};function Nt(t){switch(t){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 Be({position:t,onClick:e,isVisible:n,label:i,queueCount:o,showSuccess:c}){let[r,l]=useState(false),a=b(),s=a?St:Et;return jsx(AnimatePresence,{mode:"wait",children:n&&jsxs(motion.button,{className:Nt(t),type:"button",onClick:e,onMouseEnter:()=>l(true),onMouseLeave:()=>l(false),"aria-label":i,initial:{opacity:0,y:a?0:5},animate:{opacity:r?1:.65,y:0},exit:{opacity:0,y:a?0:5},transition:s,whileTap:{scale:.95},children:[c?jsx("span",{style:{display:"inline-flex",color:"var(--bf-accent)"},children:jsx(f,{size:14})}):jsxs(Fragment,{children:[jsx("span",{children:i}),o>0&&jsx("span",{className:"bf-badge",style:{marginLeft:"4px"},"aria-label":`${o} queued`,children:o})]}),!a&&jsx(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:r?1:0},transition:s})]},"minimal")})}var Mt={duration:.18,ease:"easeOut"},Rt={duration:0};function Re({position:t,onClick:e,isVisible:n,label:i,queueCount:o,showSuccess:c}){let[r,l]=useState(false),a=b(),s=a?Rt:Mt;return jsx(AnimatePresence,{mode:"wait",children:n&&jsx(motion.button,{className:m(t),type:"button",onClick:e,onMouseEnter:()=>l(true),onMouseLeave:()=>l(false),"aria-label":i,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?jsx(motion.span,{initial:{scale:0},animate:{scale:1},transition:s,style:{display:"inline-flex",color:"var(--bf-accent)"},children:jsx(f,{size:14})},"success"):jsxs(Fragment,{children:[jsx(motion.span,{style:{display:"inline-flex",flexShrink:0},animate:a?{}:r?{scale:1.2,rotate:0}:{rotate:[-5,5,-5]},transition:r||a?s:{duration:3,repeat:1/0,ease:"easeInOut"},children:jsx(fe,{size:16})}),jsx(AnimatePresence,{mode:"wait",children:r&&jsx(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:i},"label")}),o>0&&jsx("span",{className:"bf-badge","aria-label":`${o} queued`,children:o})]})},"icon-pop")})}var Lt={duration:.18,ease:"easeOut"},Wt={duration:0};function Ae({position:t,onClick:e,isVisible:n,label:i,queueCount:o,showSuccess:c}){let[r,l]=useState(false),a=b(),s=a?Wt:Lt;return jsx(AnimatePresence,{mode:"wait",children:n&&jsx(motion.button,{className:m(t),type:"button",onClick:e,onMouseEnter:()=>l(true),onMouseLeave:()=>l(false),"aria-label":i,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?jsx(motion.span,{initial:{scale:0},animate:{scale:1},transition:s,style:{display:"inline-flex",color:"var(--bf-accent)"},children:jsx(f,{size:14})},"success"):jsxs(Fragment,{children:[jsxs("span",{style:{position:"relative",display:"inline-flex",alignItems:"center",justifyContent:"center",width:"10px",height:"10px",flexShrink:0},children:[jsx(motion.span,{"aria-hidden":"true",style:{width:"10px",height:"10px",borderRadius:"50%",background:"var(--bf-accent)",position:"relative",zIndex:1},animate:a?{}:{opacity:r?1:[.5,1,.5],boxShadow:r?"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:r||a?s:{duration:2,repeat:1/0,ease:"easeInOut"}}),!r&&!a&&jsx(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"}})]}),jsx(AnimatePresence,{mode:"wait",children:r&&jsx(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:i},"label")}),o>0&&jsx("span",{className:"bf-badge","aria-label":`${o} queued`,children:o})]})},"beacon")})}var Dt={duration:.18,ease:"easeOut"},$t={duration:0};function Oe({position:t,onClick:e,isVisible:n,label:i,queueCount:o,showSuccess:c}){let[r,l]=useState(false),[a,s]=useState(0),u=b(),W=u?$t:Dt,h=useRef(null);useEffect(()=>{if(h.current&&(clearInterval(h.current),h.current=null),!n||r||u){s(r||u?i.length:0);return}let P=8,D=i.length*2+P*2,v=0;return h.current=setInterval(()=>{v=(v+1)%D,v<=i.length?s(v):v<=i.length+P?s(i.length):v<=i.length*2+P?s(i.length*2+P-v):s(0);},100),()=>{h.current&&(clearInterval(h.current),h.current=null);}},[n,r,u,i]);let K=i.slice(0,a);return jsx(AnimatePresence,{mode:"wait",children:n&&jsx(motion.button,{className:m(t),type:"button",onClick:e,onMouseEnter:()=>l(true),onMouseLeave:()=>l(false),"aria-label":i,initial:{opacity:0,y:u?0:5},animate:{opacity:1,y:0},exit:{opacity:0,y:u?0:5},transition:W,whileTap:{scale:.95},style:{minWidth:"44px"},children:c?jsx(motion.span,{initial:{scale:0},animate:{scale:1},transition:W,style:{display:"inline-flex",color:"var(--bf-accent)"},children:jsx(f,{size:14})},"success"):jsxs(Fragment,{children:[jsx("span",{className:"bf-dot","aria-hidden":"true"}),jsxs("span",{style:{whiteSpace:"nowrap",minWidth:"1ch"},children:[K,jsx("span",{className:"bf-cursor","aria-hidden":"true"})]}),o>0&&jsx("span",{className:"bf-badge","aria-label":`${o} queued`,children:o})]})},"typewriter")})}function He(t){switch(t){case "dot":return ge;case "bubble":return ve;case "edge-tab":return Te;case "pulse-ring":return Se;case "minimal":return Be;case "icon-pop":return Re;case "beacon":return Ae;case "typewriter":return Oe;default:return be}}function De(t,e,n){return Math.max(e,Math.min(n,t))}function Qt(t,e,n="bottom-right"){let o=window.innerWidth,c=window.innerHeight,r;r=De(t.x,12,Math.max(12,o-e-12));let l=t.y+t.height+12,a=Math.max(12,t.y-240);return {top:l+240<=c?l:a,left:r}}function Ut(t){let{rect:e}=t,n={left:`${e.x}px`,top:`${e.y}px`,width:`${Math.max(0,e.width)}px`,height:`${Math.max(0,e.height)}px`};return jsx("div",{className:"bf-highlight",style:n,"aria-hidden":"true"})}function Vt(t){let e=useRef(null);return useEffect(()=>{if(!t||!e.current)return;e.current.querySelector(".bf-textarea")?.focus();let i=o=>{if(o.key!=="Tab"||!e.current)return;let c=e.current.querySelectorAll('button:not([disabled]), textarea:not([disabled]), input:not([disabled]), [tabindex]:not([tabindex="-1"])');if(c.length===0)return;let r=c[0],l=c[c.length-1];o.shiftKey&&document.activeElement===r?(o.preventDefault(),l.focus()):!o.shiftKey&&document.activeElement===l&&(o.preventDefault(),r.focus());};return document.addEventListener("keydown",i,{capture:true}),()=>document.removeEventListener("keydown",i,{capture:true})},[t]),e}function Gt(t){let{state:e,controller:n,start:i$1,stop:o,clearSelection:c,submit:r}=Z(),l=t.config.ui?.position,[a,s]=useState(null),[u,W]=useState(""),[h,K]=useState(t.config.capture?.element??true),[P,D]=useState(t.config.capture?.fullPage??false),[v,q]=useState(null),ee=e.phase==="review"||e.phase==="capturing"||e.phase==="submitting"||e.phase==="error"||e.phase==="success",Xe=Vt(ee),[Ye,je]=useState(0);useEffect(()=>{e.phase==="idle"&&je(i());},[e.phase]);let[Qe,te]=useState(false),oe=useRef(e.phase);useEffect(()=>{if(oe.current==="success"&&e.phase==="idle"){te(true);let p=window.setTimeout(()=>te(false),1500);return ()=>window.clearTimeout(p)}oe.current=e.phase;},[e.phase]),useEffect(()=>{let p=t.config.ui?.shortcut;if(!p)return;let z=p.toLowerCase().split("+").map(y=>y.trim()),I=z[z.length-1]||"",F=new Set(z.slice(0,-1)),ie=y=>{let Ge=/Mac|iPod|iPhone|iPad/.test(navigator.platform);if(F.has("mod")){if(Ge?!y.metaKey:!y.ctrlKey)return}else if(F.has("ctrl")&&!y.ctrlKey||(F.has("meta")||F.has("cmd"))&&!y.metaKey)return;F.has("shift")&&!y.shiftKey||(F.has("alt")||F.has("option"))&&!y.altKey||y.key.toLowerCase()===I&&(y.preventDefault(),e.phase==="idle"?i$1():o());};return document.addEventListener("keydown",ie),()=>document.removeEventListener("keydown",ie)},[t.config.ui?.shortcut,e.phase,i$1,o]),useEffect(()=>n.subscribeHover(s),[n]),useEffect(()=>{let p=n.__unsafeGetSelectedElement();if(!p||e.phase==="idle"||e.phase==="picking"){q(null);return}let z=()=>{q(b$1(p.getBoundingClientRect()));};z();let I=()=>z();return window.addEventListener("scroll",I,{capture:true,passive:true}),window.addEventListener("resize",I,{passive:true}),()=>{window.removeEventListener("scroll",I,{capture:true}),window.removeEventListener("resize",I);}},[n,e.phase,e.selection?.selector]),useEffect(()=>{e.phase==="review"&&(W(""),K(t.config.capture?.element??true),D(t.config.capture?.fullPage??false));},[e.phase,e.selection?.selector,t.config.capture?.element,t.config.capture?.fullPage]),useEffect(()=>{if(e.phase!=="success")return;let p=window.setTimeout(()=>o(),1200);return ()=>window.clearTimeout(p)},[e.phase,o]);let w=e.phase==="capturing"||e.phase==="submitting",E=e.phase==="picking"?a?.rect??null:v??e.selection?.rect??null,U=useMemo(()=>E?Qt(E,360,l):null,[E?.x,E?.y,E?.width,E?.height,l]),re=e.lastError?.message,V=useCallback(()=>{r(u,{capture:{element:h,fullPage:P}});},[r,u,h,P]),Ue=useCallback(p=>{(p.metaKey||p.ctrlKey)&&p.key==="Enter"&&u.trim().length>0&&!w&&(p.preventDefault(),V());},[V,u,w]),Ve=He(t.config.ui?.triggerStyle);return jsxs(Fragment,{children:[jsx(Ve,{position:l,onClick:()=>i$1(),isVisible:e.phase==="idle",label:t.config.ui?.triggerLabel??"Feedback",queueCount:Ye,showSuccess:Qe}),e.phase!=="idle"&&jsxs("div",{className:"bf-overlay",role:"presentation",children:[e.phase!=="picking"&&jsx("div",{className:"bf-blocker",role:"presentation",onClick:()=>o()}),E&&jsx(Ut,{rect:E}),e.phase==="picking"&&jsxs("div",{className:"bf-hint",role:"status","aria-live":"polite",children:[jsxs("p",{id:"bf-hint-text",children:["Click an element to attach your feedback. Press ",jsx("strong",{children:"Esc"})," to cancel."]}),jsx("button",{type:"button",className:"bf-btn",onClick:()=>o(),"aria-label":"Cancel element selection",children:"Cancel"})]}),ee&&U&&jsxs("div",{ref:Xe,className:"bf-panel",style:{left:U.left,top:U.top},role:"dialog","aria-modal":"true","aria-label":"Feedback form",children:[jsxs("div",{className:"bf-panelHeader",children:[jsx("div",{className:"bf-title",id:"bf-panel-title",children:"Feedback"}),jsxs("div",{className:"bf-row",style:{justifyContent:"flex-end"},children:[jsx("button",{type:"button",className:"bf-btn",onClick:()=>c(),disabled:w,"aria-label":"Re-pick element",children:"Re-pick"}),jsx("button",{type:"button",className:"bf-btn",onClick:()=>o(),disabled:w,"aria-label":"Close feedback form",children:"Close"})]})]}),jsxs("div",{className:"bf-panelBody",children:[jsx("textarea",{className:"bf-textarea",placeholder:"What's happening? What did you expect?",value:u,onChange:p=>W(p.target.value),onKeyDown:Ue,disabled:w,"aria-label":"Feedback message"}),jsxs("div",{className:"bf-row",role:"group","aria-label":"Screenshot options",children:[jsxs("label",{children:[jsx("input",{type:"checkbox",checked:h,onChange:p=>K(p.target.checked),disabled:w}),"Screenshot element"]}),jsxs("label",{children:[jsx("input",{type:"checkbox",checked:P,onChange:p=>D(p.target.checked),disabled:w}),"Full page"]})]}),e.phase==="capturing"&&jsxs("div",{className:"bf-status",role:"status","aria-live":"polite",children:[jsx("span",{className:"bf-spinner","aria-hidden":"true"}),"Capturing screenshots\u2026"]}),e.phase==="submitting"&&jsxs("div",{className:"bf-status",role:"status","aria-live":"polite",children:[jsx("span",{className:"bf-spinner","aria-hidden":"true"}),"Submitting\u2026"]}),e.phase==="success"&&jsx("div",{className:"bf-status",role:"status","aria-live":"polite",children:"Sent. Thank you!"}),e.phase==="error"&&re&&jsx("div",{className:"bf-error",role:"alert",children:re}),jsxs("div",{className:"bf-actions",children:[jsx("button",{type:"button",className:"bf-btn",onClick:()=>o(),disabled:w,"aria-label":"Cancel feedback",children:"Cancel"}),jsx("button",{type:"button",className:"bf-btn bf-btnPrimary",onClick:V,disabled:w||u.trim().length===0,"aria-label":"Send feedback",children:"Send"})]})]})]})]}),e.phase==="success"&&jsx("div",{className:"bf-toast",role:"status","aria-live":"polite",children:"Feedback sent"})]})}function Jt(t){let e={...t.config??{},blocfeed_id:t.blocfeed_id},[n,i]=useState(null);return useEffect(()=>{de();let o=document.createElement("div");o.setAttribute("data-blocfeed-ui-root","true"),o.setAttribute("data-blocfeed-ui","true");let c=e.ui?.zIndex;typeof c=="number"&&o.style.setProperty("--bf-z",String(c));let r=e.ui?.theme;return r&&(r.accentColor&&o.style.setProperty("--bf-accent",r.accentColor),r.panelBackground&&o.style.setProperty("--bf-panel-bg",r.panelBackground),r.panelForeground&&o.style.setProperty("--bf-panel-fg",r.panelForeground),r.fontFamily&&o.style.setProperty("--bf-font",r.fontFamily)),document.body.appendChild(o),i(o),()=>{o.remove(),i(null);}},[e.ui?.zIndex,e.ui?.theme?.accentColor,e.ui?.theme?.panelBackground,e.ui?.theme?.panelForeground,e.ui?.theme?.fontFamily]),n?createPortal(jsx(J,{blocfeed_id:e.blocfeed_id,...t.config?{config:t.config}:{},children:jsx(Gt,{config:e})}),n):null}
479
+ export{J as BlocFeedProvider,Jt as BlocFeedWidget,Z as useBlocFeed};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "blocfeed",
3
- "version": "0.3.0",
3
+ "version": "0.5.0",
4
4
  "description": "Drop-in feedback + screenshot widget for React.",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -65,15 +65,22 @@
65
65
  "prepublishOnly": "npm run typecheck && npm test"
66
66
  },
67
67
  "peerDependencies": {
68
+ "framer-motion": ">=10.0.0",
68
69
  "react": ">=17.0.0",
69
70
  "react-dom": ">=17.0.0"
70
71
  },
72
+ "peerDependenciesMeta": {
73
+ "framer-motion": {
74
+ "optional": true
75
+ }
76
+ },
71
77
  "dependencies": {
72
78
  "html-to-image": "^1.11.11"
73
79
  },
74
80
  "devDependencies": {
75
81
  "@types/react": "^18.2.55",
76
82
  "@types/react-dom": "^18.2.19",
83
+ "framer-motion": "^12.34.2",
77
84
  "jsdom": "^24.0.0",
78
85
  "tsup": "^8.0.2",
79
86
  "typescript": "^5.5.4",