@drippr/embed-react 0.1.1 → 0.2.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/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
- flowId="your-flow-public-key"
61
- mode="modal"
62
- triggerLabel="Give Feedback"
63
- onSubmitted={() => console.log("Done!")}
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
- **Custom Trigger:**
72
+ **Using External Button with Controlled State:**
70
73
 
71
74
  ```tsx
72
- <DripprFlow flowId="your-flow-public-key" mode="modal">
73
- {({ open }) => (
74
- <button onClick={open} className="custom-button">
75
- Open Feedback Modal
76
- </button>
77
- )}
78
- </DripprFlow>
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
- flowId="your-flow-public-key"
92
- mode="drawer"
93
- triggerLabel="Feedback"
94
- onSubmitted={() => console.log("Done!")}
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 Drawer:**
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 ControlledDrawer() {
107
- const [open, setOpen] = useState(false);
124
+ function FeedbackDrawer() {
125
+ const [isDrawerOpen, setIsDrawerOpen] = useState(false);
108
126
 
109
127
  return (
110
128
  <>
111
- <button onClick={() => setOpen(true)}>Open Drawer</button>
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={open}
116
- onOpenChange={setOpen}
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 custom trigger (modal/drawer only) |
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
- - **Controlled & Uncontrolled**: Support for both controlled and uncontrolled state
181
- - **Custom Triggers**: Use render props to create custom trigger buttons
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 only) */
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, triggerLabel, onSubmitted, className, style, height: fallbackHeight, baseUrl, }: DripprFlowProps): react_jsx_runtime.JSX.Element | null;
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 only) */
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, triggerLabel, onSubmitted, className, style, height: fallbackHeight, baseUrl, }: DripprFlowProps): react_jsx_runtime.JSX.Element | null;
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: 9999,
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: 9999,
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: 1e4,
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: 1e4,
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
- const trigger = mode !== "inline" && children ? children(api) : mode !== "inline" ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
563
- "button",
564
- {
565
- type: "button",
566
- onClick: () => handleOpenChange(true),
567
- style: {
568
- padding: "8px 16px",
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
- ) : null;
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: 9999,
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: 9999,
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: 1e4,
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: 1e4,
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
- const trigger = mode !== "inline" && children ? children(api) : mode !== "inline" ? /* @__PURE__ */ jsx4(
527
- "button",
528
- {
529
- type: "button",
530
- onClick: () => handleOpenChange(true),
531
- style: {
532
- padding: "8px 16px",
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
- ) : null;
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,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@drippr/embed-react",
3
- "version": "0.1.1",
3
+ "version": "0.2.0",
4
4
  "description": "React component for embedding Drippr feedback flows",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.mjs",