blocfeed 0.2.2 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/engine.d.cts CHANGED
@@ -1,8 +1,37 @@
1
- import { h as ScreenshotAdapter, C as CaptureConfig, e as CaptureResult, f as MetadataConfig, g as MetadataContext } from './controller-DmWFVHoj.cjs';
2
- export { B as BlocFeedConfig, b as BlocFeedController, c as BlocFeedError, a as BlocFeedState, E as ElementDescriptor, F as FeedbackPayload, H as HoverListener, I as ImageAsset, R as Rect, i as ScreenshotAdapterOptions, j as ScreenshotMime, k as SessionPhase, l as StateListener, S as SubmitResult, m as createBlocFeedController } from './controller-DmWFVHoj.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-D7kOehzb.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-D7kOehzb.cjs';
3
3
 
4
4
  declare function createHtmlToImageAdapter(): ScreenshotAdapter;
5
5
 
6
+ /**
7
+ * Minimal interface that `modern-screenshot` satisfies.
8
+ * The consumer must install `modern-screenshot` themselves:
9
+ *
10
+ * npm install modern-screenshot
11
+ *
12
+ * Then pass the module into this factory:
13
+ *
14
+ * ```ts
15
+ * import { createModernScreenshotAdapter } from "blocfeed/engine";
16
+ * import * as ms from "modern-screenshot";
17
+ *
18
+ * <BlocFeedWidget
19
+ * blocfeed_id="bf_..."
20
+ * config={{ capture: { adapter: createModernScreenshotAdapter(ms) } }}
21
+ * />
22
+ * ```
23
+ *
24
+ * Benefits over `html-to-image`:
25
+ * - Better cross-origin image handling
26
+ * - Supports CSS `backdrop-filter`, `clip-path`
27
+ * - Better web font rendering
28
+ */
29
+ interface ModernScreenshotModule {
30
+ domToPng: (node: Node, options?: Record<string, unknown>) => Promise<string>;
31
+ domToJpeg: (node: Node, options?: Record<string, unknown>) => Promise<string>;
32
+ }
33
+ declare function createModernScreenshotAdapter(mod: ModernScreenshotModule): ScreenshotAdapter;
34
+
6
35
  declare function runCapture(params: {
7
36
  selectionElement: Element | null;
8
37
  capture: CaptureConfig | undefined;
@@ -12,8 +41,27 @@ declare function runCapture(params: {
12
41
  declare function collectMetadata(params: {
13
42
  config: MetadataConfig | undefined;
14
43
  context: MetadataContext;
44
+ user?: BlocFeedUser;
15
45
  }): Promise<Record<string, unknown>>;
16
46
 
47
+ /**
48
+ * Add a failed payload to the offline queue.
49
+ * Screenshots are stripped to stay within localStorage limits.
50
+ */
51
+ declare function enqueue(payload: FeedbackPayload): void;
52
+ /**
53
+ * Remove and return all queued payloads.
54
+ */
55
+ declare function dequeueAll(): FeedbackPayload[];
56
+ /**
57
+ * Clear the entire queue.
58
+ */
59
+ declare function clearQueue(): void;
60
+ /**
61
+ * Get the number of items in the queue.
62
+ */
63
+ declare function getQueueSize(): number;
64
+
17
65
  declare function dataUrlToBlob(dataUrl: string): Blob;
18
66
 
19
- export { CaptureResult, ScreenshotAdapter, collectMetadata, createHtmlToImageAdapter, dataUrlToBlob, runCapture };
67
+ export { BlocFeedUser, CaptureResult, FeedbackPayload, type ModernScreenshotModule, ScreenshotAdapter, clearQueue, collectMetadata, createHtmlToImageAdapter, createModernScreenshotAdapter, dataUrlToBlob, dequeueAll, enqueue, getQueueSize, runCapture };
package/dist/engine.d.ts CHANGED
@@ -1,8 +1,37 @@
1
- import { h as ScreenshotAdapter, C as CaptureConfig, e as CaptureResult, f as MetadataConfig, g as MetadataContext } from './controller-DmWFVHoj.js';
2
- export { B as BlocFeedConfig, b as BlocFeedController, c as BlocFeedError, a as BlocFeedState, E as ElementDescriptor, F as FeedbackPayload, H as HoverListener, I as ImageAsset, R as Rect, i as ScreenshotAdapterOptions, j as ScreenshotMime, k as SessionPhase, l as StateListener, S as SubmitResult, m as createBlocFeedController } from './controller-DmWFVHoj.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-D7kOehzb.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-D7kOehzb.js';
3
3
 
4
4
  declare function createHtmlToImageAdapter(): ScreenshotAdapter;
5
5
 
6
+ /**
7
+ * Minimal interface that `modern-screenshot` satisfies.
8
+ * The consumer must install `modern-screenshot` themselves:
9
+ *
10
+ * npm install modern-screenshot
11
+ *
12
+ * Then pass the module into this factory:
13
+ *
14
+ * ```ts
15
+ * import { createModernScreenshotAdapter } from "blocfeed/engine";
16
+ * import * as ms from "modern-screenshot";
17
+ *
18
+ * <BlocFeedWidget
19
+ * blocfeed_id="bf_..."
20
+ * config={{ capture: { adapter: createModernScreenshotAdapter(ms) } }}
21
+ * />
22
+ * ```
23
+ *
24
+ * Benefits over `html-to-image`:
25
+ * - Better cross-origin image handling
26
+ * - Supports CSS `backdrop-filter`, `clip-path`
27
+ * - Better web font rendering
28
+ */
29
+ interface ModernScreenshotModule {
30
+ domToPng: (node: Node, options?: Record<string, unknown>) => Promise<string>;
31
+ domToJpeg: (node: Node, options?: Record<string, unknown>) => Promise<string>;
32
+ }
33
+ declare function createModernScreenshotAdapter(mod: ModernScreenshotModule): ScreenshotAdapter;
34
+
6
35
  declare function runCapture(params: {
7
36
  selectionElement: Element | null;
8
37
  capture: CaptureConfig | undefined;
@@ -12,8 +41,27 @@ declare function runCapture(params: {
12
41
  declare function collectMetadata(params: {
13
42
  config: MetadataConfig | undefined;
14
43
  context: MetadataContext;
44
+ user?: BlocFeedUser;
15
45
  }): Promise<Record<string, unknown>>;
16
46
 
47
+ /**
48
+ * Add a failed payload to the offline queue.
49
+ * Screenshots are stripped to stay within localStorage limits.
50
+ */
51
+ declare function enqueue(payload: FeedbackPayload): void;
52
+ /**
53
+ * Remove and return all queued payloads.
54
+ */
55
+ declare function dequeueAll(): FeedbackPayload[];
56
+ /**
57
+ * Clear the entire queue.
58
+ */
59
+ declare function clearQueue(): void;
60
+ /**
61
+ * Get the number of items in the queue.
62
+ */
63
+ declare function getQueueSize(): number;
64
+
17
65
  declare function dataUrlToBlob(dataUrl: string): Blob;
18
66
 
19
- export { CaptureResult, ScreenshotAdapter, collectMetadata, createHtmlToImageAdapter, dataUrlToBlob, runCapture };
67
+ export { BlocFeedUser, CaptureResult, FeedbackPayload, type ModernScreenshotModule, ScreenshotAdapter, clearQueue, collectMetadata, createHtmlToImageAdapter, createModernScreenshotAdapter, dataUrlToBlob, dequeueAll, enqueue, getQueueSize, runCapture };
package/dist/engine.js CHANGED
@@ -1 +1 @@
1
- export{e as collectMetadata,f as createBlocFeedController,c as createHtmlToImageAdapter,d as runCapture}from'./chunk-37P3GL6V.js';function d(n){let[r,o]=n.split(",",2);if(!r||!o)throw new Error("Invalid data URL");let c=/data:(.*?);base64/.exec(r)?.[1]||"application/octet-stream",t=atob(o),a=new Uint8Array(t.length);for(let e=0;e<t.length;e+=1)a[e]=t.charCodeAt(e);return new Blob([a],{type:c})}export{d 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 chunkPEPIK3FN_cjs=require('./chunk-PEPIK3FN.cjs'),react=require('react'),jsxRuntime=require('react/jsx-runtime'),reactDom=require('react-dom');var g=react.createContext(null);function w(t){let e=react.useMemo(()=>chunkPEPIK3FN_cjs.f({...t.config??{},blocfeed_id:t.blocfeed_id}),[]),[a,l]=react.useState(()=>e.getState());return react.useEffect(()=>e.subscribe(l),[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(g.Provider,{value:{controller:e,state:a},children:t.children})}var H="blocfeed-styles-v1",D=`
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 k=react.createContext(null);function M(t){let e=react.useMemo(()=>chunkJLPJP7DD_cjs.j({...t.config??{},blocfeed_id:t.blocfeed_id}),[]),[i,r]=react.useState(()=>e.getState());return react.useEffect(()=>e.subscribe(r),[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(k.Provider,{value:{controller:e,state:i},children:t.children})}var Y="blocfeed-styles-v1",Se=`
3
3
  :where([data-blocfeed-ui-root]),
4
4
  :where([data-blocfeed-ui-root]) * {
5
5
  box-sizing: border-box;
@@ -20,6 +20,10 @@
20
20
  color: var(--bf-panel-fg);
21
21
  }
22
22
 
23
+ /* ------------------------------------------------------------------ */
24
+ /* Trigger button \u2014 default bottom-right */
25
+ /* ------------------------------------------------------------------ */
26
+
23
27
  :where([data-blocfeed-ui-root]) .bf-trigger {
24
28
  position: fixed;
25
29
  right: 18px;
@@ -40,11 +44,26 @@
40
44
  -webkit-tap-highlight-color: transparent;
41
45
  }
42
46
 
47
+ :where([data-blocfeed-ui-root]) .bf-trigger:hover {
48
+ border-color: var(--bf-accent);
49
+ }
50
+
43
51
  :where([data-blocfeed-ui-root]) .bf-trigger:focus-visible {
44
52
  outline: 2px solid var(--bf-accent);
45
53
  outline-offset: 2px;
46
54
  }
47
55
 
56
+ /* Position variants (item 9) */
57
+ :where([data-blocfeed-ui-root]) .bf-trigger-bl {
58
+ left: 18px; bottom: 18px; right: auto; top: auto;
59
+ }
60
+ :where([data-blocfeed-ui-root]) .bf-trigger-tr {
61
+ right: 18px; top: 18px; bottom: auto; left: auto;
62
+ }
63
+ :where([data-blocfeed-ui-root]) .bf-trigger-tl {
64
+ left: 18px; top: 18px; right: auto; bottom: auto;
65
+ }
66
+
48
67
  :where([data-blocfeed-ui-root]) .bf-dot {
49
68
  width: 10px;
50
69
  height: 10px;
@@ -53,6 +72,10 @@
53
72
  box-shadow: 0 0 0 4px rgba(99, 102, 241, 0.18);
54
73
  }
55
74
 
75
+ /* ------------------------------------------------------------------ */
76
+ /* Overlay, blocker, highlight */
77
+ /* ------------------------------------------------------------------ */
78
+
56
79
  :where([data-blocfeed-ui-root]) .bf-overlay {
57
80
  position: fixed;
58
81
  inset: 0;
@@ -75,6 +98,10 @@
75
98
  pointer-events: none;
76
99
  }
77
100
 
101
+ /* ------------------------------------------------------------------ */
102
+ /* Hint bar */
103
+ /* ------------------------------------------------------------------ */
104
+
78
105
  :where([data-blocfeed-ui-root]) .bf-hint {
79
106
  position: fixed;
80
107
  top: 16px;
@@ -99,6 +126,10 @@
99
126
  color: var(--bf-muted);
100
127
  }
101
128
 
129
+ /* ------------------------------------------------------------------ */
130
+ /* Buttons */
131
+ /* ------------------------------------------------------------------ */
132
+
102
133
  :where([data-blocfeed-ui-root]) .bf-btn {
103
134
  border: 1px solid var(--bf-border);
104
135
  background: transparent;
@@ -109,6 +140,11 @@
109
140
  user-select: none;
110
141
  }
111
142
 
143
+ :where([data-blocfeed-ui-root]) .bf-btn:focus-visible {
144
+ outline: 2px solid var(--bf-accent);
145
+ outline-offset: 2px;
146
+ }
147
+
112
148
  :where([data-blocfeed-ui-root]) .bf-btn[disabled] {
113
149
  opacity: 0.6;
114
150
  cursor: not-allowed;
@@ -120,6 +156,10 @@
120
156
  color: white;
121
157
  }
122
158
 
159
+ /* ------------------------------------------------------------------ */
160
+ /* Panel */
161
+ /* ------------------------------------------------------------------ */
162
+
123
163
  :where([data-blocfeed-ui-root]) .bf-panel {
124
164
  position: fixed;
125
165
  width: 360px;
@@ -154,6 +194,10 @@
154
194
  gap: 10px;
155
195
  }
156
196
 
197
+ /* ------------------------------------------------------------------ */
198
+ /* Form elements */
199
+ /* ------------------------------------------------------------------ */
200
+
157
201
  :where([data-blocfeed-ui-root]) .bf-textarea {
158
202
  width: 100%;
159
203
  min-height: 96px;
@@ -195,9 +239,16 @@
195
239
  padding-top: 4px;
196
240
  }
197
241
 
242
+ /* ------------------------------------------------------------------ */
243
+ /* Status, errors, toast */
244
+ /* ------------------------------------------------------------------ */
245
+
198
246
  :where([data-blocfeed-ui-root]) .bf-status {
199
247
  font-size: 12px;
200
248
  color: var(--bf-muted);
249
+ display: flex;
250
+ align-items: center;
251
+ gap: 8px;
201
252
  }
202
253
 
203
254
  :where([data-blocfeed-ui-root]) .bf-error {
@@ -220,4 +271,120 @@
220
271
  font-size: 13px;
221
272
  color: rgba(243, 244, 246, 0.9);
222
273
  }
223
- `;function T(){if(!chunkPEPIK3FN_cjs.a()||document.getElementById(H))return;let t=document.createElement("style");t.id=H,t.textContent=D,document.head.appendChild(t);}function y(){let t=react.useContext(g);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 X(t,e,a){return Math.max(e,Math.min(a,t))}function G(t,e){let l=window.innerWidth,r=window.innerHeight,s=X(t.x,12,Math.max(12,l-e-12)),p=t.y+t.height+12,m=Math.max(12,t.y-240);return {top:p+240<=r?p:m,left:s}}function V(t){let{rect:e}=t,a={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:a})}function Y(t){let{state:e,controller:a,start:l,stop:r,clearSelection:s,submit:p}=y(),[m,C]=react.useState(null),[h,F]=react.useState(""),[B,k]=react.useState(t.config.capture?.element??true),[S,P]=react.useState(t.config.capture?.fullPage??false),[A,N]=react.useState(null);react.useEffect(()=>a.subscribeHover(C),[a]),react.useEffect(()=>{let n=a.__unsafeGetSelectedElement();if(!n||e.phase==="idle"||e.phase==="picking"){N(null);return}let z=()=>{N(chunkPEPIK3FN_cjs.b(n.getBoundingClientRect()));};z();let u=()=>z();return window.addEventListener("scroll",u,{capture:true,passive:true}),window.addEventListener("resize",u,{passive:true}),()=>{window.removeEventListener("scroll",u,{capture:true}),window.removeEventListener("resize",u);}},[a,e.phase,e.selection?.selector]),react.useEffect(()=>{e.phase==="review"&&(F(""),k(t.config.capture?.element??true),P(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(()=>r(),1200);return ()=>window.clearTimeout(n)},[e.phase,r]);let d=e.phase==="capturing"||e.phase==="submitting",c=e.phase==="picking"?m?.rect??null:A??e.selection?.rect??null,x=react.useMemo(()=>c?G(c,360):null,[c?.x,c?.y,c?.width,c?.height]),R=e.lastError?.message;return jsxRuntime.jsxs(jsxRuntime.Fragment,{children:[e.phase==="idle"&&jsxRuntime.jsxs("button",{className:"bf-trigger",type:"button",onClick:()=>l(),"aria-label":"Give feedback",children:[jsxRuntime.jsx("span",{className:"bf-dot","aria-hidden":"true"}),"Feedback"]}),e.phase!=="idle"&&jsxRuntime.jsxs("div",{className:"bf-overlay",children:[e.phase!=="picking"&&jsxRuntime.jsx("div",{className:"bf-blocker",role:"presentation",onClick:()=>r()}),c&&jsxRuntime.jsx(V,{rect:c}),e.phase==="picking"&&jsxRuntime.jsxs("div",{className:"bf-hint",children:[jsxRuntime.jsxs("p",{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:()=>r(),children:"Cancel"})]}),(e.phase==="review"||e.phase==="capturing"||e.phase==="submitting"||e.phase==="error"||e.phase==="success")&&x&&jsxRuntime.jsxs("div",{className:"bf-panel",style:{left:x.left,top:x.top},children:[jsxRuntime.jsxs("div",{className:"bf-panelHeader",children:[jsxRuntime.jsx("div",{className:"bf-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:d,children:"Re-pick"}),jsxRuntime.jsx("button",{type:"button",className:"bf-btn",onClick:()=>r(),disabled:d,children:"Close"})]})]}),jsxRuntime.jsxs("div",{className:"bf-panelBody",children:[jsxRuntime.jsx("textarea",{className:"bf-textarea",placeholder:"What\u2019s happening? What did you expect?",value:h,onChange:n=>F(n.target.value),disabled:d}),jsxRuntime.jsxs("div",{className:"bf-row",children:[jsxRuntime.jsxs("label",{children:[jsxRuntime.jsx("input",{type:"checkbox",checked:B,onChange:n=>k(n.target.checked),disabled:d}),"Screenshot element"]}),jsxRuntime.jsxs("label",{children:[jsxRuntime.jsx("input",{type:"checkbox",checked:S,onChange:n=>P(n.target.checked),disabled:d}),"Full page"]})]}),e.phase==="capturing"&&jsxRuntime.jsx("div",{className:"bf-status",children:"Capturing screenshots\u2026"}),e.phase==="submitting"&&jsxRuntime.jsx("div",{className:"bf-status",children:"Submitting\u2026"}),e.phase==="success"&&jsxRuntime.jsx("div",{className:"bf-status",children:"Sent. Thank you!"}),e.phase==="error"&&R&&jsxRuntime.jsx("div",{className:"bf-error",children:R}),jsxRuntime.jsxs("div",{className:"bf-actions",children:[jsxRuntime.jsx("button",{type:"button",className:"bf-btn",onClick:()=>r(),disabled:d,children:"Cancel"}),jsxRuntime.jsx("button",{type:"button",className:"bf-btn bf-btnPrimary",onClick:()=>p(h,{capture:{element:B,fullPage:S}}),disabled:d||h.trim().length===0,children:"Send"})]})]})]})]}),e.phase==="success"&&jsxRuntime.jsx("div",{className:"bf-toast","aria-live":"polite",children:"Feedback sent"})]})}function q(t){let e={...t.config??{},blocfeed_id:t.blocfeed_id},[a,l]=react.useState(null);return react.useEffect(()=>{T();let r=document.createElement("div");r.setAttribute("data-blocfeed-ui-root","true"),r.setAttribute("data-blocfeed-ui","true");let s=e.ui?.zIndex;return typeof s=="number"&&r.style.setProperty("--bf-z",String(s)),document.body.appendChild(r),l(r),()=>{r.remove(),l(null);}},[e.ui?.zIndex]),a?reactDom.createPortal(jsxRuntime.jsx(w,{blocfeed_id:e.blocfeed_id,...t.config?{config:t.config}:{},children:jsxRuntime.jsx(Y,{config:e})}),a):null}exports.BlocFeedProvider=w;exports.BlocFeedWidget=q;exports.useBlocFeed=y;
274
+
275
+ /* ------------------------------------------------------------------ */
276
+ /* Capture spinner (item 12) */
277
+ /* ------------------------------------------------------------------ */
278
+
279
+ :where([data-blocfeed-ui-root]) .bf-spinner {
280
+ display: inline-block;
281
+ width: 10px;
282
+ height: 10px;
283
+ border-radius: 50%;
284
+ background: var(--bf-accent);
285
+ animation: bf-pulse 1s ease-in-out infinite;
286
+ }
287
+
288
+ @keyframes bf-pulse {
289
+ 0%, 100% { opacity: 0.4; transform: scale(0.8); }
290
+ 50% { opacity: 1; transform: scale(1.2); }
291
+ }
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
+
374
+ /* ------------------------------------------------------------------ */
375
+ /* Screen reader only */
376
+ /* ------------------------------------------------------------------ */
377
+
378
+ :where([data-blocfeed-ui-root]) .bf-sr-only {
379
+ position: absolute;
380
+ width: 1px;
381
+ height: 1px;
382
+ padding: 0;
383
+ margin: -1px;
384
+ overflow: hidden;
385
+ clip: rect(0, 0, 0, 0);
386
+ white-space: nowrap;
387
+ border: 0;
388
+ }
389
+ `;function J(){if(!chunkJLPJP7DD_cjs.a()||document.getElementById(Y))return;let t=document.createElement("style");t.id=Y,t.textContent=Se,document.head.appendChild(t);}function A(){let t=react.useContext(k);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 c(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 Q({position:t,onClick:e,isVisible:i}){return i?jsxRuntime.jsxs("button",{className:c(t),type:"button",onClick:e,"aria-label":"Give feedback",children:[jsxRuntime.jsx("span",{className:"bf-dot","aria-hidden":"true"}),"Feedback"]}):null}function ee({position:t,onClick:e,isVisible:i}){let[r,o]=react.useState(false);return jsxRuntime.jsx(framerMotion.AnimatePresence,{children:i&&jsxRuntime.jsxs(framerMotion.motion.button,{className:c(t),type:"button",onClick:e,onMouseEnter:()=>o(true),onMouseLeave:()=>o(false),"aria-label":"Give feedback",initial:{scale:0,opacity:0},animate:{scale:1,opacity:1,padding:r?"10px 16px":"10px 10px"},exit:{scale:0,opacity:0},transition:{type:"spring",stiffness:500,damping:28},whileTap:{scale:.92},style:{overflow:"hidden"},children:[jsxRuntime.jsx(framerMotion.motion.span,{className:"bf-dot","aria-hidden":"true",animate:{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?{type:"spring",stiffness:400,damping:20}:{duration:2,repeat:1/0,ease:"easeInOut"}}),jsxRuntime.jsx(framerMotion.AnimatePresence,{children:r&&jsxRuntime.jsx(framerMotion.motion.span,{initial:{opacity:0,width:0,x:-8},animate:{opacity:1,width:"auto",x:0},exit:{opacity:0,width:0,x:-8},transition:{type:"spring",stiffness:400,damping:25},style:{whiteSpace:"nowrap",overflow:"hidden"},children:"Feedback"})}),jsxRuntime.jsx(framerMotion.motion.span,{"aria-hidden":"true",style:{position:"absolute",inset:0,borderRadius:"inherit",border:"2px solid var(--bf-accent)",pointerEvents:"none"},initial:false,animate:{scale:1,opacity:0},whileTap:{scale:2.5,opacity:[.6,0]},transition:{duration:.4}})]})})}function te({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 oe({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 ie({position:t,onClick:e,isVisible:i}){let[r,o]=react.useState(false);return jsxRuntime.jsx(framerMotion.AnimatePresence,{children:i&&jsxRuntime.jsxs(framerMotion.motion.div,{style:{position:"fixed",zIndex:"var(--bf-z)"},className:c(t),initial:{scale:0,opacity:0},animate:{scale:1,opacity:1},exit:{y:12,opacity:0,scale:.8},transition:{type:"spring",stiffness:400,damping:25},onMouseEnter:()=>o(true),onMouseLeave:()=>o(false),children:[jsxRuntime.jsx(framerMotion.AnimatePresence,{children:r&&jsxRuntime.jsx(framerMotion.motion.div,{initial:{opacity:0,y:6,scale:.95},animate:{opacity:1,y:0,scale:1},exit:{opacity:0,y:6,scale:.95},transition:{type:"spring",stiffness:500,damping:30},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:"Got feedback?"})}),jsxRuntime.jsx(framerMotion.motion.button,{type:"button",onClick:e,"aria-label":"Give feedback",style:{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:{y:[0,-3,0]},transition:{y:{duration:3,repeat:1/0,ease:"easeInOut"}},whileHover:{scale:1.1,borderColor:"var(--bf-accent)"},whileTap:{scale:.9},children:jsxRuntime.jsx(te,{size:16})})]})})}function ne(t){return t==="bottom-left"||t==="top-left"}function We(t){return `bf-trigger-edge ${ne(t)?"bf-trigger-edge-left":"bf-trigger-edge-right"}`}function se({position:t,onClick:e,isVisible:i}){let[r,o]=react.useState(false),l=ne(t);return jsxRuntime.jsx(framerMotion.AnimatePresence,{children:i&&jsxRuntime.jsxs(framerMotion.motion.button,{className:We(t),type:"button",onClick:e,onMouseEnter:()=>o(true),onMouseLeave:()=>o(false),"aria-label":"Give feedback",initial:{opacity:0,width:0},animate:{opacity:1,width:r?140:22,height:r?40:90},exit:{width:0,opacity:0},transition:{type:"spring",stiffness:350,damping:30},whileTap:{scale:.97},style:{top:"50%",translateY:"-50%"},children:[jsxRuntime.jsxs(framerMotion.motion.span,{animate:{rotate:r?0:l?-90:90,opacity:r?1:.6},transition:{type:"spring",stiffness:300,damping:25},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:{type:"spring",stiffness:500,damping:20},style:{width:"6px",height:"6px",borderRadius:"50%",background:"var(--bf-accent)",flexShrink:0}}),"Feedback"]}),jsxRuntime.jsx(framerMotion.motion.span,{"aria-hidden":"true",animate:{opacity:r?1:0},style:{position:"absolute",top:0,bottom:0,[l?"left":"right"]:0,width:"2px",background:"var(--bf-accent)"}})]})})}function de({delay:t,hovered:e}){return jsxRuntime.jsx(framerMotion.motion.span,{"aria-hidden":"true",style:{position:"absolute",width:"12px",height:"12px",borderRadius:"50%",border:"2px solid var(--bf-accent)",pointerEvents:"none",left:"50%",top:"50%",x:"-50%",y:"-50%"},animate:e?{scale:1.3,opacity:.6}:{scale:[1,2.5],opacity:[.5,0]},transition:e?{type:"spring",stiffness:300,damping:20}:{duration:2,repeat:1/0,delay:t,ease:"easeOut"}})}function pe({position:t,onClick:e,isVisible:i}){let[r,o]=react.useState(false);return jsxRuntime.jsx(framerMotion.AnimatePresence,{children:i&&jsxRuntime.jsxs(framerMotion.motion.button,{className:c(t),type:"button",onClick:e,onMouseEnter:()=>o(true),onMouseLeave:()=>o(false),"aria-label":"Give feedback",initial:{scale:0,opacity:0},animate:{scale:1,opacity:1,padding:r?"10px 16px":"10px 10px"},exit:{scale:0,opacity:0},transition:{type:"spring",stiffness:400,damping:25},whileTap:{scale:.92},style:{position:"relative",overflow:"visible"},children:[jsxRuntime.jsxs("div",{style:{position:"absolute",inset:0,display:"flex",alignItems:"center",justifyContent:"center",pointerEvents:"none"},children:[jsxRuntime.jsx(de,{delay:0,hovered:r}),jsxRuntime.jsx(de,{delay:.7,hovered:r})]}),jsxRuntime.jsx(framerMotion.motion.span,{className:"bf-dot","aria-hidden":"true",style:{position:"relative",zIndex:1},animate:{scale:r?1.1:1},transition:{type:"spring",stiffness:400,damping:20}}),jsxRuntime.jsx(framerMotion.AnimatePresence,{children:r&&jsxRuntime.jsx(framerMotion.motion.span,{initial:{opacity:0,width:0,x:-12},animate:{opacity:1,width:"auto",x:0},exit:{opacity:0,width:0,x:-12},transition:{type:"spring",stiffness:400,damping:25},style:{whiteSpace:"nowrap",overflow:"hidden",position:"relative",zIndex:1},children:"Feedback"})})]})})}function Ge(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:i}){let[r,o]=react.useState(false);return jsxRuntime.jsx(framerMotion.AnimatePresence,{children:i&&jsxRuntime.jsxs(framerMotion.motion.button,{className:Ge(t),type:"button",onClick:e,onMouseEnter:()=>o(true),onMouseLeave:()=>o(false),"aria-label":"Give feedback",initial:{opacity:0,y:5},animate:{opacity:r?1:.65,y:0},exit:{opacity:0,y:5},transition:{type:"spring",stiffness:400,damping:30},whileTap:{scale:.95},children:[jsxRuntime.jsx("span",{children:"Feedback"}),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:{type:"spring",stiffness:400,damping:25}})]})})}function ge({position:t,onClick:e,isVisible:i}){let[r,o]=react.useState(false);return jsxRuntime.jsx(framerMotion.AnimatePresence,{children:i&&jsxRuntime.jsxs(framerMotion.motion.button,{className:c(t),type:"button",onClick:e,onMouseEnter:()=>o(true),onMouseLeave:()=>o(false),"aria-label":"Give feedback",initial:{scale:0,opacity:0,rotate:-45},animate:{scale:1,opacity:1,rotate:0,padding:r?"10px 16px":"10px 10px"},exit:{rotate:180,scale:0,opacity:0},transition:{type:"spring",stiffness:400,damping:22},whileTap:{scale:.9,rotate:360},style:{overflow:"hidden"},children:[jsxRuntime.jsx(framerMotion.motion.span,{style:{display:"inline-flex",flexShrink:0},animate:r?{scale:1.2,rotate:0}:{rotate:[-5,5,-5]},transition:r?{type:"spring",stiffness:500,damping:12}:{duration:3,repeat:1/0,ease:"easeInOut"},children:jsxRuntime.jsx(oe,{size:16})}),jsxRuntime.jsx(framerMotion.AnimatePresence,{children:r&&jsxRuntime.jsx(framerMotion.motion.span,{initial:{opacity:0,width:0,x:-16},animate:{opacity:1,width:"auto",x:0},exit:{opacity:0,width:0,x:-16},transition:{type:"spring",stiffness:350,damping:25,delay:.03},style:{whiteSpace:"nowrap",overflow:"hidden"},children:"Feedback"})})]})})}function me(t){switch(t){case "dot":return ee;case "bubble":return ie;case "edge-tab":return se;case "pulse-ring":return pe;case "minimal":return be;case "icon-pop":return ge;default:return Q}}function xe(t,e,i){return Math.max(e,Math.min(i,t))}function qe(t,e,i="bottom-right"){let o=window.innerWidth,l=window.innerHeight,n;n=xe(t.x,12,Math.max(12,o-e-12));let p=t.y+t.height+12,S=Math.max(12,t.y-240);return {top:p+240<=l?p:S,left:n}}function Ye(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 Je(t){let e=react.useRef(null);return react.useEffect(()=>{if(!t||!e.current)return;e.current.querySelector(".bf-textarea")?.focus();let r=o=>{if(o.key!=="Tab"||!e.current)return;let l=e.current.querySelectorAll('button:not([disabled]), textarea:not([disabled]), input:not([disabled]), [tabindex]:not([tabindex="-1"])');if(l.length===0)return;let n=l[0],p=l[l.length-1];o.shiftKey&&document.activeElement===n?(o.preventDefault(),p.focus()):!o.shiftKey&&document.activeElement===p&&(o.preventDefault(),n.focus());};return document.addEventListener("keydown",r,{capture:true}),()=>document.removeEventListener("keydown",r,{capture:true})},[t]),e}function Qe(t){let{state:e,controller:i,start:r,stop:o,clearSelection:l,submit:n}=A(),p=t.config.ui?.position,[S,_]=react.useState(null),[g,D]=react.useState(""),[B,O]=react.useState(t.config.capture?.element??true),[E,G]=react.useState(t.config.capture?.fullPage??false),[ye,K]=react.useState(null),V=e.phase==="review"||e.phase==="capturing"||e.phase==="submitting"||e.phase==="error"||e.phase==="success",ve=Je(V);react.useEffect(()=>i.subscribeHover(_),[i]),react.useEffect(()=>{let s=i.__unsafeGetSelectedElement();if(!s||e.phase==="idle"||e.phase==="picking"){K(null);return}let $=()=>{K(chunkJLPJP7DD_cjs.b(s.getBoundingClientRect()));};$();let w=()=>$();return window.addEventListener("scroll",w,{capture:true,passive:true}),window.addEventListener("resize",w,{passive:true}),()=>{window.removeEventListener("scroll",w,{capture:true}),window.removeEventListener("resize",w);}},[i,e.phase,e.selection?.selector]),react.useEffect(()=>{e.phase==="review"&&(D(""),O(t.config.capture?.element??true),G(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 s=window.setTimeout(()=>o(),1200);return ()=>window.clearTimeout(s)},[e.phase,o]);let f=e.phase==="capturing"||e.phase==="submitting",b=e.phase==="picking"?S?.rect??null:ye??e.selection?.rect??null,N=react.useMemo(()=>b?qe(b,360,p):null,[b?.x,b?.y,b?.width,b?.height,p]),X=e.lastError?.message,z=react.useCallback(()=>{n(g,{capture:{element:B,fullPage:E}});},[n,g,B,E]),we=react.useCallback(s=>{(s.metaKey||s.ctrlKey)&&s.key==="Enter"&&g.trim().length>0&&!f&&(s.preventDefault(),z());},[z,g,f]),ke=me(t.config.ui?.triggerStyle);return jsxRuntime.jsxs(jsxRuntime.Fragment,{children:[jsxRuntime.jsx(ke,{position:p,onClick:()=>r(),isVisible:e.phase==="idle"}),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(Ye,{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"})]}),V&&N&&jsxRuntime.jsxs("div",{ref:ve,className:"bf-panel",style:{left:N.left,top:N.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:()=>l(),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:g,onChange:s=>D(s.target.value),onKeyDown:we,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:B,onChange:s=>O(s.target.checked),disabled:f}),"Screenshot element"]}),jsxRuntime.jsxs("label",{children:[jsxRuntime.jsx("input",{type:"checkbox",checked:E,onChange:s=>G(s.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"&&X&&jsxRuntime.jsx("div",{className:"bf-error",role:"alert",children:X}),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:z,disabled:f||g.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 Ze(t){let e={...t.config??{},blocfeed_id:t.blocfeed_id},[i,r]=react.useState(null);return react.useEffect(()=>{J();let o=document.createElement("div");o.setAttribute("data-blocfeed-ui-root","true"),o.setAttribute("data-blocfeed-ui","true");let l=e.ui?.zIndex;typeof l=="number"&&o.style.setProperty("--bf-z",String(l));let n=e.ui?.theme;return n&&(n.accentColor&&o.style.setProperty("--bf-accent",n.accentColor),n.panelBackground&&o.style.setProperty("--bf-panel-bg",n.panelBackground),n.panelForeground&&o.style.setProperty("--bf-panel-fg",n.panelForeground),n.fontFamily&&o.style.setProperty("--bf-font",n.fontFamily)),document.body.appendChild(o),r(o),()=>{o.remove(),r(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(M,{blocfeed_id:e.blocfeed_id,...t.config?{config:t.config}:{},children:jsxRuntime.jsx(Qe,{config:e})}),i):null}
390
+ exports.BlocFeedProvider=M;exports.BlocFeedWidget=Ze;exports.useBlocFeed=A;
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-DmWFVHoj.cjs';
2
- export { c as BlocFeedError, d as CaptureDiagnostics, e as CaptureResult, E as ElementDescriptor, F as FeedbackPayload, I as ImageAsset, M as MaybePromise, f as MetadataConfig, g as MetadataContext, P as PickerConfig, R as Rect, h as ScreenshotAdapter, i as ScreenshotAdapterOptions, j as ScreenshotMime, k as SessionPhase, T as TransportResult } from './controller-DmWFVHoj.cjs';
1
+ import { B as BlocFeedConfig, a as BlocFeedState, b as BlocFeedController, C as CaptureConfig, S as SubmitResult } from './controller-D7kOehzb.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-D7kOehzb.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-DmWFVHoj.js';
2
- export { c as BlocFeedError, d as CaptureDiagnostics, e as CaptureResult, E as ElementDescriptor, F as FeedbackPayload, I as ImageAsset, M as MaybePromise, f as MetadataConfig, g as MetadataContext, P as PickerConfig, R as Rect, h as ScreenshotAdapter, i as ScreenshotAdapterOptions, j as ScreenshotMime, k as SessionPhase, T as TransportResult } from './controller-DmWFVHoj.js';
1
+ import { B as BlocFeedConfig, a as BlocFeedState, b as BlocFeedController, C as CaptureConfig, S as SubmitResult } from './controller-D7kOehzb.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-D7kOehzb.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';