@drippr/embed-react 0.1.1 → 0.2.1
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/README.md +59 -32
- package/dist/index.d.mts +2 -4
- package/dist/index.d.ts +2 -4
- package/dist/index.js +21 -22
- package/dist/index.mjs +21 -22
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -49,71 +49,92 @@ function FeedbackSection() {
|
|
|
49
49
|
|
|
50
50
|
### Modal Mode
|
|
51
51
|
|
|
52
|
-
Open the flow in a modal dialog:
|
|
52
|
+
Open the flow in a modal dialog. **You must provide your own trigger button** using either a render prop or controlled state:
|
|
53
|
+
|
|
54
|
+
**Using Render Prop (Recommended):**
|
|
53
55
|
|
|
54
56
|
```tsx
|
|
55
57
|
import { DripprFlow } from "@drippr/embed-react";
|
|
56
58
|
|
|
57
59
|
function FeedbackButton() {
|
|
58
60
|
return (
|
|
59
|
-
<DripprFlow
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
61
|
+
<DripprFlow flowId="your-flow-public-key" mode="modal">
|
|
62
|
+
{({ open }) => (
|
|
63
|
+
<button onClick={open} className="custom-button">
|
|
64
|
+
Give Feedback
|
|
65
|
+
</button>
|
|
66
|
+
)}
|
|
67
|
+
</DripprFlow>
|
|
65
68
|
);
|
|
66
69
|
}
|
|
67
70
|
```
|
|
68
71
|
|
|
69
|
-
**
|
|
72
|
+
**Using External Button with Controlled State:**
|
|
70
73
|
|
|
71
74
|
```tsx
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
75
|
+
import { useState } from "react";
|
|
76
|
+
import { DripprFlow } from "@drippr/embed-react";
|
|
77
|
+
|
|
78
|
+
function FeedbackButton() {
|
|
79
|
+
const [isModalOpen, setIsModalOpen] = useState(false);
|
|
80
|
+
|
|
81
|
+
return (
|
|
82
|
+
<>
|
|
83
|
+
<button onClick={() => setIsModalOpen(true)}>
|
|
84
|
+
Give Feedback
|
|
85
|
+
</button>
|
|
86
|
+
<DripprFlow
|
|
87
|
+
flowId="your-flow-public-key"
|
|
88
|
+
mode="modal"
|
|
89
|
+
open={isModalOpen}
|
|
90
|
+
onOpenChange={setIsModalOpen}
|
|
91
|
+
onSubmitted={() => console.log("Done!")}
|
|
92
|
+
/>
|
|
93
|
+
</>
|
|
94
|
+
);
|
|
95
|
+
}
|
|
79
96
|
```
|
|
80
97
|
|
|
81
98
|
### Drawer Mode
|
|
82
99
|
|
|
83
|
-
Open the flow in a side drawer:
|
|
100
|
+
Open the flow in a side drawer. **You must provide your own trigger button** using either a render prop or controlled state:
|
|
101
|
+
|
|
102
|
+
**Using Render Prop:**
|
|
84
103
|
|
|
85
104
|
```tsx
|
|
86
105
|
import { DripprFlow } from "@drippr/embed-react";
|
|
87
106
|
|
|
88
107
|
function FeedbackDrawer() {
|
|
89
108
|
return (
|
|
90
|
-
<DripprFlow
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
/>
|
|
109
|
+
<DripprFlow flowId="your-flow-public-key" mode="drawer">
|
|
110
|
+
{({ open }) => (
|
|
111
|
+
<button onClick={open}>Open Feedback</button>
|
|
112
|
+
)}
|
|
113
|
+
</DripprFlow>
|
|
96
114
|
);
|
|
97
115
|
}
|
|
98
116
|
```
|
|
99
117
|
|
|
100
|
-
**Controlled
|
|
118
|
+
**Using External Button with Controlled State (Recommended):**
|
|
101
119
|
|
|
102
120
|
```tsx
|
|
103
121
|
import { useState } from "react";
|
|
104
122
|
import { DripprFlow } from "@drippr/embed-react";
|
|
105
123
|
|
|
106
|
-
function
|
|
107
|
-
const [
|
|
124
|
+
function FeedbackDrawer() {
|
|
125
|
+
const [isDrawerOpen, setIsDrawerOpen] = useState(false);
|
|
108
126
|
|
|
109
127
|
return (
|
|
110
128
|
<>
|
|
111
|
-
<button onClick={() =>
|
|
129
|
+
<button onClick={() => setIsDrawerOpen(true)}>
|
|
130
|
+
Send Feedback
|
|
131
|
+
</button>
|
|
112
132
|
<DripprFlow
|
|
113
133
|
flowId="your-flow-public-key"
|
|
114
134
|
mode="drawer"
|
|
115
|
-
open={
|
|
116
|
-
onOpenChange={
|
|
135
|
+
open={isDrawerOpen}
|
|
136
|
+
onOpenChange={setIsDrawerOpen}
|
|
137
|
+
onSubmitted={() => console.log("Done!")}
|
|
117
138
|
/>
|
|
118
139
|
</>
|
|
119
140
|
);
|
|
@@ -131,8 +152,7 @@ function ControlledDrawer() {
|
|
|
131
152
|
| `open` | `boolean` | No | - | Controlled open state (for modal/drawer) |
|
|
132
153
|
| `onOpenChange` | `(open: boolean) => void` | No | - | Callback when open state changes |
|
|
133
154
|
| `prefill` | `PrefillData` | No | - | Pre-fill contact form fields |
|
|
134
|
-
| `children` | `(api: DripprFlowApi) => ReactNode` | No | - | Render prop for
|
|
135
|
-
| `triggerLabel` | `string` | No | `"Give Feedback"` | Default trigger label when no children provided |
|
|
155
|
+
| `children` | `(api: DripprFlowApi) => ReactNode` | No | - | Render prop for trigger button (required for modal/drawer modes) |
|
|
136
156
|
| `onSubmitted` | `() => void` | No | - | Called when the user completes the flow |
|
|
137
157
|
| `className` | `string` | No | - | Additional CSS class for the container |
|
|
138
158
|
| `style` | `React.CSSProperties` | No | - | Inline styles for the container |
|
|
@@ -177,13 +197,20 @@ interface DripprFlowApi {
|
|
|
177
197
|
## Features
|
|
178
198
|
|
|
179
199
|
- **Three Display Modes**: Inline, modal, and drawer
|
|
180
|
-
- **
|
|
181
|
-
- **
|
|
200
|
+
- **Flexible Triggers**: Use render props or controlled state with external buttons
|
|
201
|
+
- **Automatic Z-Index**: High z-index values prevent CSS framework conflicts (Tailwind, etc.)
|
|
182
202
|
- **Prefill Support**: Pre-populate form fields with user data
|
|
183
203
|
- **Auto-resize**: Iframe automatically resizes based on content
|
|
184
204
|
- **TypeScript**: Full TypeScript support with exported types
|
|
185
205
|
- **React 18+**: Built for React 18 and above
|
|
186
206
|
|
|
207
|
+
## Important Notes
|
|
208
|
+
|
|
209
|
+
- **Modal/Drawer Modes**: You must provide your own trigger button. Use either:
|
|
210
|
+
- Render prop `children` pattern, OR
|
|
211
|
+
- External button with controlled `open`/`onOpenChange` props
|
|
212
|
+
- **Z-Index**: Automatically set to high values (99999+) to prevent conflicts with CSS frameworks like Tailwind CSS
|
|
213
|
+
|
|
187
214
|
## Requirements
|
|
188
215
|
|
|
189
216
|
- React >= 18.0.0
|
package/dist/index.d.mts
CHANGED
|
@@ -42,10 +42,8 @@ interface DripprFlowProps {
|
|
|
42
42
|
onOpenChange?: (open: boolean) => void;
|
|
43
43
|
/** Pre-fill contact form fields */
|
|
44
44
|
prefill?: PrefillData;
|
|
45
|
-
/** Render prop for custom trigger (modal/drawer
|
|
45
|
+
/** Render prop for custom trigger (required for modal/drawer modes) */
|
|
46
46
|
children?: (api: DripprFlowApi) => React.ReactNode;
|
|
47
|
-
/** Default trigger label when no children provided (modal/drawer only) */
|
|
48
|
-
triggerLabel?: string;
|
|
49
47
|
/** Called when the user completes the flow */
|
|
50
48
|
onSubmitted?: () => void;
|
|
51
49
|
/** Additional CSS class for the container */
|
|
@@ -58,6 +56,6 @@ interface DripprFlowProps {
|
|
|
58
56
|
baseUrl?: string;
|
|
59
57
|
}
|
|
60
58
|
|
|
61
|
-
declare function DripprFlow({ flowId, mode, open: controlledOpen, onOpenChange, prefill, children,
|
|
59
|
+
declare function DripprFlow({ flowId, mode, open: controlledOpen, onOpenChange, prefill, children, onSubmitted, className, style, height: fallbackHeight, baseUrl, }: DripprFlowProps): react_jsx_runtime.JSX.Element | null;
|
|
62
60
|
|
|
63
61
|
export { DripprFlow, type DripprFlowApi, type DripprFlowProps, type DripprMessage, type DripprMessageFromChild, type DripprMessageToChild, type EmbedMode, type PrefillData };
|
package/dist/index.d.ts
CHANGED
|
@@ -42,10 +42,8 @@ interface DripprFlowProps {
|
|
|
42
42
|
onOpenChange?: (open: boolean) => void;
|
|
43
43
|
/** Pre-fill contact form fields */
|
|
44
44
|
prefill?: PrefillData;
|
|
45
|
-
/** Render prop for custom trigger (modal/drawer
|
|
45
|
+
/** Render prop for custom trigger (required for modal/drawer modes) */
|
|
46
46
|
children?: (api: DripprFlowApi) => React.ReactNode;
|
|
47
|
-
/** Default trigger label when no children provided (modal/drawer only) */
|
|
48
|
-
triggerLabel?: string;
|
|
49
47
|
/** Called when the user completes the flow */
|
|
50
48
|
onSubmitted?: () => void;
|
|
51
49
|
/** Additional CSS class for the container */
|
|
@@ -58,6 +56,6 @@ interface DripprFlowProps {
|
|
|
58
56
|
baseUrl?: string;
|
|
59
57
|
}
|
|
60
58
|
|
|
61
|
-
declare function DripprFlow({ flowId, mode, open: controlledOpen, onOpenChange, prefill, children,
|
|
59
|
+
declare function DripprFlow({ flowId, mode, open: controlledOpen, onOpenChange, prefill, children, onSubmitted, className, style, height: fallbackHeight, baseUrl, }: DripprFlowProps): react_jsx_runtime.JSX.Element | null;
|
|
62
60
|
|
|
63
61
|
export { DripprFlow, type DripprFlowApi, type DripprFlowProps, type DripprMessage, type DripprMessageFromChild, type DripprMessageToChild, type EmbedMode, type PrefillData };
|
package/dist/index.js
CHANGED
|
@@ -143,7 +143,7 @@ function ModalContainer({
|
|
|
143
143
|
display: "flex",
|
|
144
144
|
alignItems: isMobile ? "flex-end" : "center",
|
|
145
145
|
justifyContent: "center",
|
|
146
|
-
zIndex:
|
|
146
|
+
zIndex: 99999,
|
|
147
147
|
padding: isMobile ? 0 : "16px",
|
|
148
148
|
// Animation
|
|
149
149
|
opacity: visible ? 1 : 0,
|
|
@@ -158,6 +158,7 @@ function ModalContainer({
|
|
|
158
158
|
maxHeight: "calc(100dvh - 32px)",
|
|
159
159
|
overflow: "hidden",
|
|
160
160
|
position: "relative",
|
|
161
|
+
zIndex: 1e5,
|
|
161
162
|
boxShadow: "0 -4px 25px -5px rgba(0, 0, 0, 0.1)",
|
|
162
163
|
// Animation - slide from bottom
|
|
163
164
|
transform: visible ? "translateY(0)" : "translateY(100%)",
|
|
@@ -171,6 +172,7 @@ function ModalContainer({
|
|
|
171
172
|
maxHeight: "90vh",
|
|
172
173
|
overflow: "hidden",
|
|
173
174
|
position: "relative",
|
|
175
|
+
zIndex: 1e5,
|
|
174
176
|
boxShadow: "0 25px 50px -12px rgba(0, 0, 0, 0.25)",
|
|
175
177
|
// Animation - scale + fade
|
|
176
178
|
opacity: visible ? 1 : 0,
|
|
@@ -224,7 +226,9 @@ function ModalContainer({
|
|
|
224
226
|
className,
|
|
225
227
|
style: {
|
|
226
228
|
...dialogStyles,
|
|
227
|
-
...style
|
|
229
|
+
...style,
|
|
230
|
+
// Ensure z-index is always set (user's style prop shouldn't override it)
|
|
231
|
+
zIndex: style?.zIndex ?? dialogStyles.zIndex
|
|
228
232
|
},
|
|
229
233
|
children: [
|
|
230
234
|
isMobile && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { style: handleStyles }),
|
|
@@ -328,7 +332,7 @@ function DrawerContainer({
|
|
|
328
332
|
position: "fixed",
|
|
329
333
|
inset: 0,
|
|
330
334
|
backgroundColor: "rgba(0, 0, 0, 0.5)",
|
|
331
|
-
zIndex:
|
|
335
|
+
zIndex: 99999,
|
|
332
336
|
// Animation
|
|
333
337
|
opacity: visible ? 1 : 0,
|
|
334
338
|
transition: `opacity ${ANIMATION_DURATION2}ms ease-out`
|
|
@@ -344,7 +348,7 @@ function DrawerContainer({
|
|
|
344
348
|
backgroundColor: "#fff",
|
|
345
349
|
borderRadius: "16px 16px 0 0",
|
|
346
350
|
boxShadow: "0 -4px 25px -5px rgba(0, 0, 0, 0.1)",
|
|
347
|
-
zIndex:
|
|
351
|
+
zIndex: 1e5,
|
|
348
352
|
display: "flex",
|
|
349
353
|
flexDirection: "column",
|
|
350
354
|
overflow: "hidden",
|
|
@@ -361,7 +365,7 @@ function DrawerContainer({
|
|
|
361
365
|
maxWidth: "480px",
|
|
362
366
|
backgroundColor: "#fff",
|
|
363
367
|
boxShadow: "-4px 0 25px -5px rgba(0, 0, 0, 0.1)",
|
|
364
|
-
zIndex:
|
|
368
|
+
zIndex: 1e5,
|
|
365
369
|
display: "flex",
|
|
366
370
|
flexDirection: "column",
|
|
367
371
|
overflow: "hidden",
|
|
@@ -421,7 +425,9 @@ function DrawerContainer({
|
|
|
421
425
|
className,
|
|
422
426
|
style: {
|
|
423
427
|
...drawerStyles,
|
|
424
|
-
...style
|
|
428
|
+
...style,
|
|
429
|
+
// Ensure z-index is always set (user's style prop shouldn't override it)
|
|
430
|
+
zIndex: style?.zIndex ?? drawerStyles.zIndex
|
|
425
431
|
},
|
|
426
432
|
role: "dialog",
|
|
427
433
|
"aria-modal": "true",
|
|
@@ -473,7 +479,6 @@ function DripprFlow({
|
|
|
473
479
|
onOpenChange,
|
|
474
480
|
prefill,
|
|
475
481
|
children,
|
|
476
|
-
triggerLabel = "Give Feedback",
|
|
477
482
|
onSubmitted,
|
|
478
483
|
className,
|
|
479
484
|
style,
|
|
@@ -559,22 +564,16 @@ function DripprFlow({
|
|
|
559
564
|
sendPrefill();
|
|
560
565
|
}
|
|
561
566
|
}, [prefill, sendPrefill]);
|
|
562
|
-
|
|
563
|
-
"
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
borderRadius: "6px",
|
|
570
|
-
border: "1px solid #e5e5e5",
|
|
571
|
-
background: "#fff",
|
|
572
|
-
cursor: "pointer",
|
|
573
|
-
fontSize: "14px"
|
|
574
|
-
},
|
|
575
|
-
children: triggerLabel
|
|
567
|
+
React3.useEffect(() => {
|
|
568
|
+
if (mode !== "inline" && !children && !isControlled) {
|
|
569
|
+
console.warn(
|
|
570
|
+
`[@drippr/embed-react] ${mode} mode requires either:
|
|
571
|
+
1. A render prop children: <DripprFlow mode="${mode}">{({ open }) => <button onClick={open}>...</button>}</DripprFlow>
|
|
572
|
+
2. Controlled state with external button: <DripprFlow mode="${mode}" open={isOpen} onOpenChange={setIsOpen} />`
|
|
573
|
+
);
|
|
576
574
|
}
|
|
577
|
-
|
|
575
|
+
}, [mode, children, isControlled]);
|
|
576
|
+
const trigger = mode !== "inline" && children ? children(api) : null;
|
|
578
577
|
if (mode === "inline") {
|
|
579
578
|
return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
580
579
|
InlineContainer,
|
package/dist/index.mjs
CHANGED
|
@@ -107,7 +107,7 @@ function ModalContainer({
|
|
|
107
107
|
display: "flex",
|
|
108
108
|
alignItems: isMobile ? "flex-end" : "center",
|
|
109
109
|
justifyContent: "center",
|
|
110
|
-
zIndex:
|
|
110
|
+
zIndex: 99999,
|
|
111
111
|
padding: isMobile ? 0 : "16px",
|
|
112
112
|
// Animation
|
|
113
113
|
opacity: visible ? 1 : 0,
|
|
@@ -122,6 +122,7 @@ function ModalContainer({
|
|
|
122
122
|
maxHeight: "calc(100dvh - 32px)",
|
|
123
123
|
overflow: "hidden",
|
|
124
124
|
position: "relative",
|
|
125
|
+
zIndex: 1e5,
|
|
125
126
|
boxShadow: "0 -4px 25px -5px rgba(0, 0, 0, 0.1)",
|
|
126
127
|
// Animation - slide from bottom
|
|
127
128
|
transform: visible ? "translateY(0)" : "translateY(100%)",
|
|
@@ -135,6 +136,7 @@ function ModalContainer({
|
|
|
135
136
|
maxHeight: "90vh",
|
|
136
137
|
overflow: "hidden",
|
|
137
138
|
position: "relative",
|
|
139
|
+
zIndex: 1e5,
|
|
138
140
|
boxShadow: "0 25px 50px -12px rgba(0, 0, 0, 0.25)",
|
|
139
141
|
// Animation - scale + fade
|
|
140
142
|
opacity: visible ? 1 : 0,
|
|
@@ -188,7 +190,9 @@ function ModalContainer({
|
|
|
188
190
|
className,
|
|
189
191
|
style: {
|
|
190
192
|
...dialogStyles,
|
|
191
|
-
...style
|
|
193
|
+
...style,
|
|
194
|
+
// Ensure z-index is always set (user's style prop shouldn't override it)
|
|
195
|
+
zIndex: style?.zIndex ?? dialogStyles.zIndex
|
|
192
196
|
},
|
|
193
197
|
children: [
|
|
194
198
|
isMobile && /* @__PURE__ */ jsx2("div", { style: handleStyles }),
|
|
@@ -292,7 +296,7 @@ function DrawerContainer({
|
|
|
292
296
|
position: "fixed",
|
|
293
297
|
inset: 0,
|
|
294
298
|
backgroundColor: "rgba(0, 0, 0, 0.5)",
|
|
295
|
-
zIndex:
|
|
299
|
+
zIndex: 99999,
|
|
296
300
|
// Animation
|
|
297
301
|
opacity: visible ? 1 : 0,
|
|
298
302
|
transition: `opacity ${ANIMATION_DURATION2}ms ease-out`
|
|
@@ -308,7 +312,7 @@ function DrawerContainer({
|
|
|
308
312
|
backgroundColor: "#fff",
|
|
309
313
|
borderRadius: "16px 16px 0 0",
|
|
310
314
|
boxShadow: "0 -4px 25px -5px rgba(0, 0, 0, 0.1)",
|
|
311
|
-
zIndex:
|
|
315
|
+
zIndex: 1e5,
|
|
312
316
|
display: "flex",
|
|
313
317
|
flexDirection: "column",
|
|
314
318
|
overflow: "hidden",
|
|
@@ -325,7 +329,7 @@ function DrawerContainer({
|
|
|
325
329
|
maxWidth: "480px",
|
|
326
330
|
backgroundColor: "#fff",
|
|
327
331
|
boxShadow: "-4px 0 25px -5px rgba(0, 0, 0, 0.1)",
|
|
328
|
-
zIndex:
|
|
332
|
+
zIndex: 1e5,
|
|
329
333
|
display: "flex",
|
|
330
334
|
flexDirection: "column",
|
|
331
335
|
overflow: "hidden",
|
|
@@ -385,7 +389,9 @@ function DrawerContainer({
|
|
|
385
389
|
className,
|
|
386
390
|
style: {
|
|
387
391
|
...drawerStyles,
|
|
388
|
-
...style
|
|
392
|
+
...style,
|
|
393
|
+
// Ensure z-index is always set (user's style prop shouldn't override it)
|
|
394
|
+
zIndex: style?.zIndex ?? drawerStyles.zIndex
|
|
389
395
|
},
|
|
390
396
|
role: "dialog",
|
|
391
397
|
"aria-modal": "true",
|
|
@@ -437,7 +443,6 @@ function DripprFlow({
|
|
|
437
443
|
onOpenChange,
|
|
438
444
|
prefill,
|
|
439
445
|
children,
|
|
440
|
-
triggerLabel = "Give Feedback",
|
|
441
446
|
onSubmitted,
|
|
442
447
|
className,
|
|
443
448
|
style,
|
|
@@ -523,22 +528,16 @@ function DripprFlow({
|
|
|
523
528
|
sendPrefill();
|
|
524
529
|
}
|
|
525
530
|
}, [prefill, sendPrefill]);
|
|
526
|
-
|
|
527
|
-
"
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
borderRadius: "6px",
|
|
534
|
-
border: "1px solid #e5e5e5",
|
|
535
|
-
background: "#fff",
|
|
536
|
-
cursor: "pointer",
|
|
537
|
-
fontSize: "14px"
|
|
538
|
-
},
|
|
539
|
-
children: triggerLabel
|
|
531
|
+
React3.useEffect(() => {
|
|
532
|
+
if (mode !== "inline" && !children && !isControlled) {
|
|
533
|
+
console.warn(
|
|
534
|
+
`[@drippr/embed-react] ${mode} mode requires either:
|
|
535
|
+
1. A render prop children: <DripprFlow mode="${mode}">{({ open }) => <button onClick={open}>...</button>}</DripprFlow>
|
|
536
|
+
2. Controlled state with external button: <DripprFlow mode="${mode}" open={isOpen} onOpenChange={setIsOpen} />`
|
|
537
|
+
);
|
|
540
538
|
}
|
|
541
|
-
|
|
539
|
+
}, [mode, children, isControlled]);
|
|
540
|
+
const trigger = mode !== "inline" && children ? children(api) : null;
|
|
542
541
|
if (mode === "inline") {
|
|
543
542
|
return /* @__PURE__ */ jsx4(
|
|
544
543
|
InlineContainer,
|