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 +43 -0
- package/README.md +61 -1
- package/dist/{controller-olqOZLhp.d.cts → controller-did-WBAQ.d.cts} +8 -1
- package/dist/{controller-olqOZLhp.d.ts → controller-did-WBAQ.d.ts} +8 -1
- package/dist/engine.cjs +1 -1
- package/dist/engine.d.cts +2 -2
- package/dist/engine.d.ts +2 -2
- package/dist/engine.js +1 -1
- package/dist/main.cjs +173 -2
- package/dist/main.d.cts +2 -2
- package/dist/main.d.ts +2 -2
- package/dist/main.js +173 -2
- package/package.json +8 -1
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 &
|
|
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
|
|
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
|
|
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
|
|
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-
|
|
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,
|
|
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-
|
|
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,
|
|
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
|
|
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
|
|
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
|
-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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
|
|
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
|
-
|
|
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
|
+
"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",
|