@queuezero/react 0.1.7 → 0.1.9
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 +17 -0
- package/dist/index.d.mts +9 -22
- package/dist/index.d.ts +9 -22
- package/dist/index.js +102 -5
- package/dist/index.mjs +108 -11
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -78,8 +78,25 @@ A ready-to-use signup form.
|
|
|
78
78
|
</div>
|
|
79
79
|
)}
|
|
80
80
|
</WaitlistForm>
|
|
81
|
+
|
|
82
|
+
// Modal mode
|
|
83
|
+
<WaitlistForm
|
|
84
|
+
displayMode="modal"
|
|
85
|
+
triggerText="Join Our Waitlist"
|
|
86
|
+
modalSize="md"
|
|
87
|
+
/>
|
|
81
88
|
```
|
|
82
89
|
|
|
90
|
+
#### Modal Mode Props
|
|
91
|
+
|
|
92
|
+
| Prop | Type | Default | Description |
|
|
93
|
+
|------|------|---------|-------------|
|
|
94
|
+
| `displayMode` | `'inline' \| 'modal'` | `'inline'` | Display as inline form or modal |
|
|
95
|
+
| `triggerText` | `string` | `'Join Waitlist'` | Button text (modal mode only) |
|
|
96
|
+
| `modalSize` | `'sm' \| 'md' \| 'lg'` | `'md'` | Modal width (modal mode only) |
|
|
97
|
+
|
|
98
|
+
The modal automatically uses your campaign's branding (logo, cover image, theme color) from the API.
|
|
99
|
+
|
|
83
100
|
### WaitlistStatus
|
|
84
101
|
|
|
85
102
|
Displays position, score, and referral count.
|
package/dist/index.d.mts
CHANGED
|
@@ -74,6 +74,12 @@ interface WaitlistFormProps {
|
|
|
74
74
|
showLabel?: boolean;
|
|
75
75
|
/** Label text */
|
|
76
76
|
labelText?: string;
|
|
77
|
+
/** Display mode: 'inline' renders form directly, 'modal' renders trigger button */
|
|
78
|
+
displayMode?: 'inline' | 'modal';
|
|
79
|
+
/** Text for modal trigger button (only used when displayMode is 'modal') */
|
|
80
|
+
triggerText?: string;
|
|
81
|
+
/** Modal size (only used when displayMode is 'modal') */
|
|
82
|
+
modalSize?: 'sm' | 'md' | 'lg';
|
|
77
83
|
/** Children for custom rendering */
|
|
78
84
|
children?: React.ReactNode;
|
|
79
85
|
}
|
|
@@ -193,30 +199,11 @@ declare function useWaitlist(campaign: string, config?: WaitlistProviderProps['c
|
|
|
193
199
|
* // Basic usage
|
|
194
200
|
* <WaitlistForm onSuccess={(res) => console.log('Joined!', res)} />
|
|
195
201
|
*
|
|
196
|
-
* //
|
|
197
|
-
*
|
|
198
|
-
* <WaitlistForm referrerCode={referrerCode || undefined} />
|
|
199
|
-
*
|
|
200
|
-
* // With custom styling
|
|
201
|
-
* <WaitlistForm
|
|
202
|
-
* className="my-form"
|
|
203
|
-
* placeholder="Enter your work email"
|
|
204
|
-
* buttonText="Get Early Access"
|
|
205
|
-
* />
|
|
206
|
-
*
|
|
207
|
-
* // With custom rendering
|
|
208
|
-
* <WaitlistForm>
|
|
209
|
-
* {({ email, setEmail, submit, loading, error }) => (
|
|
210
|
-
* <div>
|
|
211
|
-
* <input value={email} onChange={(e) => setEmail(e.target.value)} />
|
|
212
|
-
* <button onClick={submit} disabled={loading}>Join</button>
|
|
213
|
-
* {error && <span>{error.message}</span>}
|
|
214
|
-
* </div>
|
|
215
|
-
* )}
|
|
216
|
-
* </WaitlistForm>
|
|
202
|
+
* // Modal mode
|
|
203
|
+
* <WaitlistForm displayMode="modal" triggerText="Join Our Waitlist" />
|
|
217
204
|
* ```
|
|
218
205
|
*/
|
|
219
|
-
declare function WaitlistForm({ onSuccess, onError, referrerCode, metadata, className, placeholder, buttonText, loadingText, showLabel, labelText, children, }: WaitlistFormProps): any;
|
|
206
|
+
declare function WaitlistForm({ onSuccess, onError, referrerCode, metadata, className, placeholder, buttonText, loadingText, showLabel, labelText, displayMode, triggerText, modalSize, children, }: WaitlistFormProps): any;
|
|
220
207
|
|
|
221
208
|
/**
|
|
222
209
|
* WaitlistStatus - Shows current position, score, and referral count
|
package/dist/index.d.ts
CHANGED
|
@@ -74,6 +74,12 @@ interface WaitlistFormProps {
|
|
|
74
74
|
showLabel?: boolean;
|
|
75
75
|
/** Label text */
|
|
76
76
|
labelText?: string;
|
|
77
|
+
/** Display mode: 'inline' renders form directly, 'modal' renders trigger button */
|
|
78
|
+
displayMode?: 'inline' | 'modal';
|
|
79
|
+
/** Text for modal trigger button (only used when displayMode is 'modal') */
|
|
80
|
+
triggerText?: string;
|
|
81
|
+
/** Modal size (only used when displayMode is 'modal') */
|
|
82
|
+
modalSize?: 'sm' | 'md' | 'lg';
|
|
77
83
|
/** Children for custom rendering */
|
|
78
84
|
children?: React.ReactNode;
|
|
79
85
|
}
|
|
@@ -193,30 +199,11 @@ declare function useWaitlist(campaign: string, config?: WaitlistProviderProps['c
|
|
|
193
199
|
* // Basic usage
|
|
194
200
|
* <WaitlistForm onSuccess={(res) => console.log('Joined!', res)} />
|
|
195
201
|
*
|
|
196
|
-
* //
|
|
197
|
-
*
|
|
198
|
-
* <WaitlistForm referrerCode={referrerCode || undefined} />
|
|
199
|
-
*
|
|
200
|
-
* // With custom styling
|
|
201
|
-
* <WaitlistForm
|
|
202
|
-
* className="my-form"
|
|
203
|
-
* placeholder="Enter your work email"
|
|
204
|
-
* buttonText="Get Early Access"
|
|
205
|
-
* />
|
|
206
|
-
*
|
|
207
|
-
* // With custom rendering
|
|
208
|
-
* <WaitlistForm>
|
|
209
|
-
* {({ email, setEmail, submit, loading, error }) => (
|
|
210
|
-
* <div>
|
|
211
|
-
* <input value={email} onChange={(e) => setEmail(e.target.value)} />
|
|
212
|
-
* <button onClick={submit} disabled={loading}>Join</button>
|
|
213
|
-
* {error && <span>{error.message}</span>}
|
|
214
|
-
* </div>
|
|
215
|
-
* )}
|
|
216
|
-
* </WaitlistForm>
|
|
202
|
+
* // Modal mode
|
|
203
|
+
* <WaitlistForm displayMode="modal" triggerText="Join Our Waitlist" />
|
|
217
204
|
* ```
|
|
218
205
|
*/
|
|
219
|
-
declare function WaitlistForm({ onSuccess, onError, referrerCode, metadata, className, placeholder, buttonText, loadingText, showLabel, labelText, children, }: WaitlistFormProps): any;
|
|
206
|
+
declare function WaitlistForm({ onSuccess, onError, referrerCode, metadata, className, placeholder, buttonText, loadingText, showLabel, labelText, displayMode, triggerText, modalSize, children, }: WaitlistFormProps): any;
|
|
220
207
|
|
|
221
208
|
/**
|
|
222
209
|
* WaitlistStatus - Shows current position, score, and referral count
|
package/dist/index.js
CHANGED
|
@@ -81,7 +81,13 @@ function WaitlistProvider({ campaign, config, children }) {
|
|
|
81
81
|
campaign,
|
|
82
82
|
join: stateManager.join.bind(stateManager),
|
|
83
83
|
refresh: stateManager.refresh.bind(stateManager),
|
|
84
|
-
getReferralLink:
|
|
84
|
+
getReferralLink: () => {
|
|
85
|
+
const code = stateManager.getReferralCode();
|
|
86
|
+
if (code && typeof window !== "undefined") {
|
|
87
|
+
return `${window.location.origin}${window.location.pathname}?ref=${code}`;
|
|
88
|
+
}
|
|
89
|
+
return stateManager.getReferralLink();
|
|
90
|
+
},
|
|
85
91
|
getReferralCode: stateManager.getReferralCode.bind(stateManager),
|
|
86
92
|
reset: stateManager.reset.bind(stateManager),
|
|
87
93
|
config: publicConfig,
|
|
@@ -173,12 +179,34 @@ function WaitlistForm({
|
|
|
173
179
|
loadingText = "Joining...",
|
|
174
180
|
showLabel = false,
|
|
175
181
|
labelText = "Email",
|
|
182
|
+
displayMode = "inline",
|
|
183
|
+
triggerText = "Join Waitlist",
|
|
184
|
+
modalSize = "md",
|
|
176
185
|
children
|
|
177
186
|
}) {
|
|
178
187
|
const { join, loading, error, isJoined, config, configLoading } = useWaitlistContext();
|
|
179
188
|
const [email, setEmail] = (0, import_react2.useState)("");
|
|
180
189
|
const [formData, setFormData] = (0, import_react2.useState)({});
|
|
181
190
|
const [localError, setLocalError] = (0, import_react2.useState)(null);
|
|
191
|
+
const [isModalOpen, setIsModalOpen] = (0, import_react2.useState)(false);
|
|
192
|
+
const [successData, setSuccessData] = (0, import_react2.useState)(null);
|
|
193
|
+
(0, import_react2.useEffect)(() => {
|
|
194
|
+
const handleEsc = (e) => {
|
|
195
|
+
if (e.key === "Escape" && isModalOpen) setIsModalOpen(false);
|
|
196
|
+
};
|
|
197
|
+
document.addEventListener("keydown", handleEsc);
|
|
198
|
+
return () => document.removeEventListener("keydown", handleEsc);
|
|
199
|
+
}, [isModalOpen]);
|
|
200
|
+
(0, import_react2.useEffect)(() => {
|
|
201
|
+
if (isModalOpen) {
|
|
202
|
+
document.body.style.overflow = "hidden";
|
|
203
|
+
} else {
|
|
204
|
+
document.body.style.overflow = "";
|
|
205
|
+
}
|
|
206
|
+
return () => {
|
|
207
|
+
document.body.style.overflow = "";
|
|
208
|
+
};
|
|
209
|
+
}, [isModalOpen]);
|
|
182
210
|
const controller = (0, import_react2.useMemo)(
|
|
183
211
|
() => new import_queuezero2.FormController(join, config?.formFields || [], referrerCode),
|
|
184
212
|
[join, config, referrerCode]
|
|
@@ -192,6 +220,7 @@ function WaitlistForm({
|
|
|
192
220
|
if (result) {
|
|
193
221
|
setEmail("");
|
|
194
222
|
setFormData({});
|
|
223
|
+
setSuccessData(result);
|
|
195
224
|
onSuccess?.(result);
|
|
196
225
|
} else if (error) {
|
|
197
226
|
onError?.(error);
|
|
@@ -205,6 +234,13 @@ function WaitlistForm({
|
|
|
205
234
|
[email, formData, controller, metadata, onSuccess, onError, error]
|
|
206
235
|
);
|
|
207
236
|
const displayError = localError || error;
|
|
237
|
+
const branding = config?.branding || {};
|
|
238
|
+
const themeColor = branding.themeColor || "#10B981";
|
|
239
|
+
const sizeClasses = {
|
|
240
|
+
sm: "max-w-sm",
|
|
241
|
+
md: "max-w-md",
|
|
242
|
+
lg: "max-w-lg"
|
|
243
|
+
};
|
|
208
244
|
if (isJoined) {
|
|
209
245
|
return null;
|
|
210
246
|
}
|
|
@@ -217,7 +253,7 @@ function WaitlistForm({
|
|
|
217
253
|
error: displayError
|
|
218
254
|
});
|
|
219
255
|
}
|
|
220
|
-
|
|
256
|
+
const formContent = /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("form", { onSubmit: handleSubmit, className: `qz-form ${displayMode === "inline" ? className : ""}`.trim(), children: [
|
|
221
257
|
showLabel && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("label", { htmlFor: "qz-email", className: "qz-form-label", children: labelText }),
|
|
222
258
|
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "qz-form-row", children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
223
259
|
"input",
|
|
@@ -247,7 +283,7 @@ function WaitlistForm({
|
|
|
247
283
|
required: field.required,
|
|
248
284
|
className: "qz-form-select",
|
|
249
285
|
children: [
|
|
250
|
-
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("option", { value: "", children:
|
|
286
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("option", { value: "", children: "Select an option" }),
|
|
251
287
|
field.options?.map((opt) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("option", { value: opt, children: opt }, opt))
|
|
252
288
|
]
|
|
253
289
|
}
|
|
@@ -307,8 +343,69 @@ function WaitlistForm({
|
|
|
307
343
|
] }, field.key);
|
|
308
344
|
}),
|
|
309
345
|
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "qz-form-row", children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("button", { type: "submit", disabled: loading, className: "qz-form-button", children: loading ? loadingText : buttonText }) }),
|
|
310
|
-
displayError && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "qz-form-error", role: "alert", children: displayError.message })
|
|
311
|
-
|
|
346
|
+
displayError && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "qz-form-error", role: "alert", children: displayError.message })
|
|
347
|
+
] });
|
|
348
|
+
if (displayMode === "inline") {
|
|
349
|
+
return formContent;
|
|
350
|
+
}
|
|
351
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_jsx_runtime2.Fragment, { children: [
|
|
352
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
353
|
+
"button",
|
|
354
|
+
{
|
|
355
|
+
type: "button",
|
|
356
|
+
onClick: () => setIsModalOpen(true),
|
|
357
|
+
className: `qz-modal-trigger ${className}`.trim(),
|
|
358
|
+
style: { "--qz-theme-color": themeColor },
|
|
359
|
+
children: triggerText
|
|
360
|
+
}
|
|
361
|
+
),
|
|
362
|
+
isModalOpen && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
363
|
+
"div",
|
|
364
|
+
{
|
|
365
|
+
className: "qz-modal-overlay",
|
|
366
|
+
onClick: (e) => e.target === e.currentTarget && setIsModalOpen(false),
|
|
367
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: `qz-modal ${sizeClasses[modalSize]}`, style: { "--qz-theme-color": themeColor }, children: [
|
|
368
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "qz-modal-header", children: [
|
|
369
|
+
branding.logoUrl ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("img", { src: branding.logoUrl, alt: "Logo", className: "qz-modal-logo" }) : /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", {}),
|
|
370
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
371
|
+
"button",
|
|
372
|
+
{
|
|
373
|
+
type: "button",
|
|
374
|
+
className: "qz-modal-close",
|
|
375
|
+
onClick: () => setIsModalOpen(false),
|
|
376
|
+
"aria-label": "Close",
|
|
377
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: 2, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("path", { d: "M18 6L6 18M6 6l12 12" }) })
|
|
378
|
+
}
|
|
379
|
+
)
|
|
380
|
+
] }),
|
|
381
|
+
branding.coverImageUrl && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("img", { src: branding.coverImageUrl, alt: "", className: "qz-modal-cover" }),
|
|
382
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "qz-modal-body", children: [
|
|
383
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("h2", { className: "qz-modal-title", children: config?.name || "Join Waitlist" }),
|
|
384
|
+
successData ? /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "qz-success", children: [
|
|
385
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("h3", { style: { fontSize: "1.25rem", fontWeight: 600, marginBottom: "0.5rem", textAlign: "center" }, children: "You're on the list!" }),
|
|
386
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("p", { style: { textAlign: "center", marginBottom: "1.5rem", opacity: 0.9 }, children: [
|
|
387
|
+
"You're #",
|
|
388
|
+
successData.position || "?",
|
|
389
|
+
" in line."
|
|
390
|
+
] }),
|
|
391
|
+
successData.referralLink && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { style: { marginTop: "1.5rem" }, children: [
|
|
392
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { style: { marginBottom: "0.5rem", fontSize: "0.875rem", opacity: 0.9, textAlign: "center" }, children: "Refer friends to move up:" }),
|
|
393
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
394
|
+
"input",
|
|
395
|
+
{
|
|
396
|
+
readOnly: true,
|
|
397
|
+
value: window.location.origin + window.location.pathname + "?ref=" + successData.referralCode,
|
|
398
|
+
onClick: (e) => e.currentTarget.select(),
|
|
399
|
+
className: "qz-form-input",
|
|
400
|
+
style: { textAlign: "center", cursor: "pointer" }
|
|
401
|
+
}
|
|
402
|
+
)
|
|
403
|
+
] })
|
|
404
|
+
] }) : formContent
|
|
405
|
+
] })
|
|
406
|
+
] })
|
|
407
|
+
}
|
|
408
|
+
)
|
|
312
409
|
] });
|
|
313
410
|
}
|
|
314
411
|
|
package/dist/index.mjs
CHANGED
|
@@ -47,7 +47,13 @@ function WaitlistProvider({ campaign, config, children }) {
|
|
|
47
47
|
campaign,
|
|
48
48
|
join: stateManager.join.bind(stateManager),
|
|
49
49
|
refresh: stateManager.refresh.bind(stateManager),
|
|
50
|
-
getReferralLink:
|
|
50
|
+
getReferralLink: () => {
|
|
51
|
+
const code = stateManager.getReferralCode();
|
|
52
|
+
if (code && typeof window !== "undefined") {
|
|
53
|
+
return `${window.location.origin}${window.location.pathname}?ref=${code}`;
|
|
54
|
+
}
|
|
55
|
+
return stateManager.getReferralLink();
|
|
56
|
+
},
|
|
51
57
|
getReferralCode: stateManager.getReferralCode.bind(stateManager),
|
|
52
58
|
reset: stateManager.reset.bind(stateManager),
|
|
53
59
|
config: publicConfig,
|
|
@@ -125,9 +131,9 @@ function useWaitlist(campaign, config) {
|
|
|
125
131
|
}
|
|
126
132
|
|
|
127
133
|
// src/WaitlistForm.tsx
|
|
128
|
-
import { useState as useState2, useCallback as useCallback2, useMemo as useMemo2 } from "react";
|
|
134
|
+
import { useState as useState2, useCallback as useCallback2, useMemo as useMemo2, useEffect as useEffect2 } from "react";
|
|
129
135
|
import { FormController } from "queuezero";
|
|
130
|
-
import { jsx as jsx2, jsxs } from "react/jsx-runtime";
|
|
136
|
+
import { Fragment, jsx as jsx2, jsxs } from "react/jsx-runtime";
|
|
131
137
|
function WaitlistForm({
|
|
132
138
|
onSuccess,
|
|
133
139
|
onError,
|
|
@@ -139,12 +145,34 @@ function WaitlistForm({
|
|
|
139
145
|
loadingText = "Joining...",
|
|
140
146
|
showLabel = false,
|
|
141
147
|
labelText = "Email",
|
|
148
|
+
displayMode = "inline",
|
|
149
|
+
triggerText = "Join Waitlist",
|
|
150
|
+
modalSize = "md",
|
|
142
151
|
children
|
|
143
152
|
}) {
|
|
144
153
|
const { join, loading, error, isJoined, config, configLoading } = useWaitlistContext();
|
|
145
154
|
const [email, setEmail] = useState2("");
|
|
146
155
|
const [formData, setFormData] = useState2({});
|
|
147
156
|
const [localError, setLocalError] = useState2(null);
|
|
157
|
+
const [isModalOpen, setIsModalOpen] = useState2(false);
|
|
158
|
+
const [successData, setSuccessData] = useState2(null);
|
|
159
|
+
useEffect2(() => {
|
|
160
|
+
const handleEsc = (e) => {
|
|
161
|
+
if (e.key === "Escape" && isModalOpen) setIsModalOpen(false);
|
|
162
|
+
};
|
|
163
|
+
document.addEventListener("keydown", handleEsc);
|
|
164
|
+
return () => document.removeEventListener("keydown", handleEsc);
|
|
165
|
+
}, [isModalOpen]);
|
|
166
|
+
useEffect2(() => {
|
|
167
|
+
if (isModalOpen) {
|
|
168
|
+
document.body.style.overflow = "hidden";
|
|
169
|
+
} else {
|
|
170
|
+
document.body.style.overflow = "";
|
|
171
|
+
}
|
|
172
|
+
return () => {
|
|
173
|
+
document.body.style.overflow = "";
|
|
174
|
+
};
|
|
175
|
+
}, [isModalOpen]);
|
|
148
176
|
const controller = useMemo2(
|
|
149
177
|
() => new FormController(join, config?.formFields || [], referrerCode),
|
|
150
178
|
[join, config, referrerCode]
|
|
@@ -158,6 +186,7 @@ function WaitlistForm({
|
|
|
158
186
|
if (result) {
|
|
159
187
|
setEmail("");
|
|
160
188
|
setFormData({});
|
|
189
|
+
setSuccessData(result);
|
|
161
190
|
onSuccess?.(result);
|
|
162
191
|
} else if (error) {
|
|
163
192
|
onError?.(error);
|
|
@@ -171,6 +200,13 @@ function WaitlistForm({
|
|
|
171
200
|
[email, formData, controller, metadata, onSuccess, onError, error]
|
|
172
201
|
);
|
|
173
202
|
const displayError = localError || error;
|
|
203
|
+
const branding = config?.branding || {};
|
|
204
|
+
const themeColor = branding.themeColor || "#10B981";
|
|
205
|
+
const sizeClasses = {
|
|
206
|
+
sm: "max-w-sm",
|
|
207
|
+
md: "max-w-md",
|
|
208
|
+
lg: "max-w-lg"
|
|
209
|
+
};
|
|
174
210
|
if (isJoined) {
|
|
175
211
|
return null;
|
|
176
212
|
}
|
|
@@ -183,7 +219,7 @@ function WaitlistForm({
|
|
|
183
219
|
error: displayError
|
|
184
220
|
});
|
|
185
221
|
}
|
|
186
|
-
|
|
222
|
+
const formContent = /* @__PURE__ */ jsxs("form", { onSubmit: handleSubmit, className: `qz-form ${displayMode === "inline" ? className : ""}`.trim(), children: [
|
|
187
223
|
showLabel && /* @__PURE__ */ jsx2("label", { htmlFor: "qz-email", className: "qz-form-label", children: labelText }),
|
|
188
224
|
/* @__PURE__ */ jsx2("div", { className: "qz-form-row", children: /* @__PURE__ */ jsx2(
|
|
189
225
|
"input",
|
|
@@ -213,7 +249,7 @@ function WaitlistForm({
|
|
|
213
249
|
required: field.required,
|
|
214
250
|
className: "qz-form-select",
|
|
215
251
|
children: [
|
|
216
|
-
/* @__PURE__ */ jsx2("option", { value: "", children:
|
|
252
|
+
/* @__PURE__ */ jsx2("option", { value: "", children: "Select an option" }),
|
|
217
253
|
field.options?.map((opt) => /* @__PURE__ */ jsx2("option", { value: opt, children: opt }, opt))
|
|
218
254
|
]
|
|
219
255
|
}
|
|
@@ -273,13 +309,74 @@ function WaitlistForm({
|
|
|
273
309
|
] }, field.key);
|
|
274
310
|
}),
|
|
275
311
|
/* @__PURE__ */ jsx2("div", { className: "qz-form-row", children: /* @__PURE__ */ jsx2("button", { type: "submit", disabled: loading, className: "qz-form-button", children: loading ? loadingText : buttonText }) }),
|
|
276
|
-
displayError && /* @__PURE__ */ jsx2("div", { className: "qz-form-error", role: "alert", children: displayError.message })
|
|
277
|
-
|
|
312
|
+
displayError && /* @__PURE__ */ jsx2("div", { className: "qz-form-error", role: "alert", children: displayError.message })
|
|
313
|
+
] });
|
|
314
|
+
if (displayMode === "inline") {
|
|
315
|
+
return formContent;
|
|
316
|
+
}
|
|
317
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
318
|
+
/* @__PURE__ */ jsx2(
|
|
319
|
+
"button",
|
|
320
|
+
{
|
|
321
|
+
type: "button",
|
|
322
|
+
onClick: () => setIsModalOpen(true),
|
|
323
|
+
className: `qz-modal-trigger ${className}`.trim(),
|
|
324
|
+
style: { "--qz-theme-color": themeColor },
|
|
325
|
+
children: triggerText
|
|
326
|
+
}
|
|
327
|
+
),
|
|
328
|
+
isModalOpen && /* @__PURE__ */ jsx2(
|
|
329
|
+
"div",
|
|
330
|
+
{
|
|
331
|
+
className: "qz-modal-overlay",
|
|
332
|
+
onClick: (e) => e.target === e.currentTarget && setIsModalOpen(false),
|
|
333
|
+
children: /* @__PURE__ */ jsxs("div", { className: `qz-modal ${sizeClasses[modalSize]}`, style: { "--qz-theme-color": themeColor }, children: [
|
|
334
|
+
/* @__PURE__ */ jsxs("div", { className: "qz-modal-header", children: [
|
|
335
|
+
branding.logoUrl ? /* @__PURE__ */ jsx2("img", { src: branding.logoUrl, alt: "Logo", className: "qz-modal-logo" }) : /* @__PURE__ */ jsx2("span", {}),
|
|
336
|
+
/* @__PURE__ */ jsx2(
|
|
337
|
+
"button",
|
|
338
|
+
{
|
|
339
|
+
type: "button",
|
|
340
|
+
className: "qz-modal-close",
|
|
341
|
+
onClick: () => setIsModalOpen(false),
|
|
342
|
+
"aria-label": "Close",
|
|
343
|
+
children: /* @__PURE__ */ jsx2("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: 2, children: /* @__PURE__ */ jsx2("path", { d: "M18 6L6 18M6 6l12 12" }) })
|
|
344
|
+
}
|
|
345
|
+
)
|
|
346
|
+
] }),
|
|
347
|
+
branding.coverImageUrl && /* @__PURE__ */ jsx2("img", { src: branding.coverImageUrl, alt: "", className: "qz-modal-cover" }),
|
|
348
|
+
/* @__PURE__ */ jsxs("div", { className: "qz-modal-body", children: [
|
|
349
|
+
/* @__PURE__ */ jsx2("h2", { className: "qz-modal-title", children: config?.name || "Join Waitlist" }),
|
|
350
|
+
successData ? /* @__PURE__ */ jsxs("div", { className: "qz-success", children: [
|
|
351
|
+
/* @__PURE__ */ jsx2("h3", { style: { fontSize: "1.25rem", fontWeight: 600, marginBottom: "0.5rem", textAlign: "center" }, children: "You're on the list!" }),
|
|
352
|
+
/* @__PURE__ */ jsxs("p", { style: { textAlign: "center", marginBottom: "1.5rem", opacity: 0.9 }, children: [
|
|
353
|
+
"You're #",
|
|
354
|
+
successData.position || "?",
|
|
355
|
+
" in line."
|
|
356
|
+
] }),
|
|
357
|
+
successData.referralLink && /* @__PURE__ */ jsxs("div", { style: { marginTop: "1.5rem" }, children: [
|
|
358
|
+
/* @__PURE__ */ jsx2("p", { style: { marginBottom: "0.5rem", fontSize: "0.875rem", opacity: 0.9, textAlign: "center" }, children: "Refer friends to move up:" }),
|
|
359
|
+
/* @__PURE__ */ jsx2(
|
|
360
|
+
"input",
|
|
361
|
+
{
|
|
362
|
+
readOnly: true,
|
|
363
|
+
value: window.location.origin + window.location.pathname + "?ref=" + successData.referralCode,
|
|
364
|
+
onClick: (e) => e.currentTarget.select(),
|
|
365
|
+
className: "qz-form-input",
|
|
366
|
+
style: { textAlign: "center", cursor: "pointer" }
|
|
367
|
+
}
|
|
368
|
+
)
|
|
369
|
+
] })
|
|
370
|
+
] }) : formContent
|
|
371
|
+
] })
|
|
372
|
+
] })
|
|
373
|
+
}
|
|
374
|
+
)
|
|
278
375
|
] });
|
|
279
376
|
}
|
|
280
377
|
|
|
281
378
|
// src/WaitlistStatus.tsx
|
|
282
|
-
import { Fragment, jsx as jsx3, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
379
|
+
import { Fragment as Fragment2, jsx as jsx3, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
283
380
|
function WaitlistStatus({
|
|
284
381
|
className = "",
|
|
285
382
|
showReferrals = true,
|
|
@@ -297,7 +394,7 @@ function WaitlistStatus({
|
|
|
297
394
|
return /* @__PURE__ */ jsx3("div", { className: `qz-status qz-status-loading ${className}`.trim(), children: "Loading..." });
|
|
298
395
|
}
|
|
299
396
|
if (typeof children === "function") {
|
|
300
|
-
return /* @__PURE__ */ jsx3(
|
|
397
|
+
return /* @__PURE__ */ jsx3(Fragment2, { children: children(status) });
|
|
301
398
|
}
|
|
302
399
|
return /* @__PURE__ */ jsxs2("div", { className: `qz-status ${className}`.trim(), children: [
|
|
303
400
|
/* @__PURE__ */ jsxs2("div", { className: "qz-status-item qz-status-position", children: [
|
|
@@ -320,7 +417,7 @@ function WaitlistStatus({
|
|
|
320
417
|
|
|
321
418
|
// src/ReferralShare.tsx
|
|
322
419
|
import { useState as useState3, useCallback as useCallback3 } from "react";
|
|
323
|
-
import { Fragment as
|
|
420
|
+
import { Fragment as Fragment3, jsx as jsx4, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
324
421
|
function ReferralShare({
|
|
325
422
|
className = "",
|
|
326
423
|
label = "Share your referral link:",
|
|
@@ -381,7 +478,7 @@ ${link}`);
|
|
|
381
478
|
return null;
|
|
382
479
|
}
|
|
383
480
|
if (typeof children === "function") {
|
|
384
|
-
return /* @__PURE__ */ jsx4(
|
|
481
|
+
return /* @__PURE__ */ jsx4(Fragment3, { children: children({ link, code, copy: handleCopy, copied }) });
|
|
385
482
|
}
|
|
386
483
|
return /* @__PURE__ */ jsxs3("div", { className: `qz-share ${className}`.trim(), children: [
|
|
387
484
|
label && /* @__PURE__ */ jsx4("div", { className: "qz-share-label", children: label }),
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@queuezero/react",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.9",
|
|
4
4
|
"description": "React components and hooks for QueueZero viral waitlists",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"module": "./dist/index.mjs",
|
|
@@ -35,7 +35,7 @@
|
|
|
35
35
|
"react": ">=17.0.0"
|
|
36
36
|
},
|
|
37
37
|
"dependencies": {
|
|
38
|
-
"queuezero": "^0.1.
|
|
38
|
+
"queuezero": "^0.1.6"
|
|
39
39
|
},
|
|
40
40
|
"devDependencies": {
|
|
41
41
|
"@types/node": "^22.13.11",
|