@queuezero/react 0.1.6 → 0.1.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.mts +9 -22
- package/dist/index.d.ts +9 -22
- package/dist/index.js +144 -30
- package/dist/index.mjs +150 -36
- package/package.json +2 -2
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
|
@@ -173,12 +173,33 @@ function WaitlistForm({
|
|
|
173
173
|
loadingText = "Joining...",
|
|
174
174
|
showLabel = false,
|
|
175
175
|
labelText = "Email",
|
|
176
|
+
displayMode = "inline",
|
|
177
|
+
triggerText = "Join Waitlist",
|
|
178
|
+
modalSize = "md",
|
|
176
179
|
children
|
|
177
180
|
}) {
|
|
178
181
|
const { join, loading, error, isJoined, config, configLoading } = useWaitlistContext();
|
|
179
182
|
const [email, setEmail] = (0, import_react2.useState)("");
|
|
180
183
|
const [formData, setFormData] = (0, import_react2.useState)({});
|
|
181
184
|
const [localError, setLocalError] = (0, import_react2.useState)(null);
|
|
185
|
+
const [isModalOpen, setIsModalOpen] = (0, import_react2.useState)(false);
|
|
186
|
+
(0, import_react2.useEffect)(() => {
|
|
187
|
+
const handleEsc = (e) => {
|
|
188
|
+
if (e.key === "Escape" && isModalOpen) setIsModalOpen(false);
|
|
189
|
+
};
|
|
190
|
+
document.addEventListener("keydown", handleEsc);
|
|
191
|
+
return () => document.removeEventListener("keydown", handleEsc);
|
|
192
|
+
}, [isModalOpen]);
|
|
193
|
+
(0, import_react2.useEffect)(() => {
|
|
194
|
+
if (isModalOpen) {
|
|
195
|
+
document.body.style.overflow = "hidden";
|
|
196
|
+
} else {
|
|
197
|
+
document.body.style.overflow = "";
|
|
198
|
+
}
|
|
199
|
+
return () => {
|
|
200
|
+
document.body.style.overflow = "";
|
|
201
|
+
};
|
|
202
|
+
}, [isModalOpen]);
|
|
182
203
|
const controller = (0, import_react2.useMemo)(
|
|
183
204
|
() => new import_queuezero2.FormController(join, config?.formFields || [], referrerCode),
|
|
184
205
|
[join, config, referrerCode]
|
|
@@ -205,6 +226,13 @@ function WaitlistForm({
|
|
|
205
226
|
[email, formData, controller, metadata, onSuccess, onError, error]
|
|
206
227
|
);
|
|
207
228
|
const displayError = localError || error;
|
|
229
|
+
const branding = config?.branding || {};
|
|
230
|
+
const themeColor = branding.themeColor || "#10B981";
|
|
231
|
+
const sizeClasses = {
|
|
232
|
+
sm: "max-w-sm",
|
|
233
|
+
md: "max-w-md",
|
|
234
|
+
lg: "max-w-lg"
|
|
235
|
+
};
|
|
208
236
|
if (isJoined) {
|
|
209
237
|
return null;
|
|
210
238
|
}
|
|
@@ -217,7 +245,7 @@ function WaitlistForm({
|
|
|
217
245
|
error: displayError
|
|
218
246
|
});
|
|
219
247
|
}
|
|
220
|
-
|
|
248
|
+
const formContent = /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("form", { onSubmit: handleSubmit, className: `qz-form ${displayMode === "inline" ? className : ""}`.trim(), children: [
|
|
221
249
|
showLabel && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("label", { htmlFor: "qz-email", className: "qz-form-label", children: labelText }),
|
|
222
250
|
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "qz-form-row", children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
223
251
|
"input",
|
|
@@ -233,37 +261,123 @@ function WaitlistForm({
|
|
|
233
261
|
"aria-label": !showLabel ? labelText : void 0
|
|
234
262
|
}
|
|
235
263
|
) }),
|
|
236
|
-
!configLoading && config?.formFields?.map((field) =>
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
264
|
+
!configLoading && config?.formFields?.map((field) => {
|
|
265
|
+
if (field.key === "email") return null;
|
|
266
|
+
const renderFieldInput = () => {
|
|
267
|
+
switch (field.type) {
|
|
268
|
+
case "select":
|
|
269
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
|
|
270
|
+
"select",
|
|
271
|
+
{
|
|
272
|
+
value: formData[field.key] || "",
|
|
273
|
+
onChange: (e) => setFormData((prev) => ({ ...prev, [field.key]: e.target.value })),
|
|
274
|
+
disabled: loading,
|
|
275
|
+
required: field.required,
|
|
276
|
+
className: "qz-form-select",
|
|
277
|
+
children: [
|
|
278
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("option", { value: "", children: field.placeholder || `Select ${field.label}` }),
|
|
279
|
+
field.options?.map((opt) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("option", { value: opt, children: opt }, opt))
|
|
280
|
+
]
|
|
281
|
+
}
|
|
282
|
+
);
|
|
283
|
+
case "checkbox":
|
|
284
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("label", { className: "qz-form-checkbox-label", children: [
|
|
285
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
286
|
+
"input",
|
|
287
|
+
{
|
|
288
|
+
type: "checkbox",
|
|
289
|
+
checked: formData[field.key] === "true",
|
|
290
|
+
onChange: (e) => setFormData((prev) => ({ ...prev, [field.key]: e.target.checked ? "true" : "" })),
|
|
291
|
+
disabled: loading,
|
|
292
|
+
required: field.required,
|
|
293
|
+
className: "qz-form-checkbox"
|
|
294
|
+
}
|
|
295
|
+
),
|
|
296
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("span", { children: [
|
|
297
|
+
field.label,
|
|
298
|
+
field.required && " *"
|
|
299
|
+
] })
|
|
300
|
+
] });
|
|
301
|
+
case "textarea":
|
|
302
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
303
|
+
"textarea",
|
|
304
|
+
{
|
|
305
|
+
value: formData[field.key] || "",
|
|
306
|
+
onChange: (e) => setFormData((prev) => ({ ...prev, [field.key]: e.target.value })),
|
|
307
|
+
placeholder: field.placeholder || field.label,
|
|
308
|
+
disabled: loading,
|
|
309
|
+
required: field.required,
|
|
310
|
+
className: "qz-form-textarea",
|
|
311
|
+
rows: 3
|
|
312
|
+
}
|
|
313
|
+
);
|
|
314
|
+
default:
|
|
315
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
316
|
+
"input",
|
|
317
|
+
{
|
|
318
|
+
type: field.type === "number" ? "number" : "text",
|
|
319
|
+
value: formData[field.key] || "",
|
|
320
|
+
onChange: (e) => setFormData((prev) => ({ ...prev, [field.key]: e.target.value })),
|
|
321
|
+
placeholder: field.placeholder || field.label,
|
|
322
|
+
disabled: loading,
|
|
323
|
+
required: field.required,
|
|
324
|
+
className: "qz-form-input"
|
|
325
|
+
}
|
|
326
|
+
);
|
|
250
327
|
}
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
{
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
className: "qz-form-input"
|
|
261
|
-
}
|
|
262
|
-
)
|
|
263
|
-
] }, field.key)),
|
|
328
|
+
};
|
|
329
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "qz-form-row", children: [
|
|
330
|
+
showLabel && field.type !== "checkbox" && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("label", { className: "qz-form-label", children: [
|
|
331
|
+
field.label,
|
|
332
|
+
field.required && " *"
|
|
333
|
+
] }),
|
|
334
|
+
renderFieldInput()
|
|
335
|
+
] }, field.key);
|
|
336
|
+
}),
|
|
264
337
|
/* @__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 }) }),
|
|
265
|
-
displayError && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "qz-form-error", role: "alert", children: displayError.message })
|
|
266
|
-
|
|
338
|
+
displayError && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "qz-form-error", role: "alert", children: displayError.message })
|
|
339
|
+
] });
|
|
340
|
+
if (displayMode === "inline") {
|
|
341
|
+
return formContent;
|
|
342
|
+
}
|
|
343
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_jsx_runtime2.Fragment, { children: [
|
|
344
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
345
|
+
"button",
|
|
346
|
+
{
|
|
347
|
+
type: "button",
|
|
348
|
+
onClick: () => setIsModalOpen(true),
|
|
349
|
+
className: `qz-modal-trigger ${className}`.trim(),
|
|
350
|
+
style: { "--qz-theme-color": themeColor },
|
|
351
|
+
children: triggerText
|
|
352
|
+
}
|
|
353
|
+
),
|
|
354
|
+
isModalOpen && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
355
|
+
"div",
|
|
356
|
+
{
|
|
357
|
+
className: "qz-modal-overlay",
|
|
358
|
+
onClick: (e) => e.target === e.currentTarget && setIsModalOpen(false),
|
|
359
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: `qz-modal ${sizeClasses[modalSize]}`, style: { "--qz-theme-color": themeColor }, children: [
|
|
360
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "qz-modal-header", children: [
|
|
361
|
+
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", {}),
|
|
362
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
363
|
+
"button",
|
|
364
|
+
{
|
|
365
|
+
type: "button",
|
|
366
|
+
className: "qz-modal-close",
|
|
367
|
+
onClick: () => setIsModalOpen(false),
|
|
368
|
+
"aria-label": "Close",
|
|
369
|
+
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" }) })
|
|
370
|
+
}
|
|
371
|
+
)
|
|
372
|
+
] }),
|
|
373
|
+
branding.coverImageUrl && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("img", { src: branding.coverImageUrl, alt: "", className: "qz-modal-cover" }),
|
|
374
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "qz-modal-body", children: [
|
|
375
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("h2", { className: "qz-modal-title", children: config?.name || "Join Waitlist" }),
|
|
376
|
+
formContent
|
|
377
|
+
] })
|
|
378
|
+
] })
|
|
379
|
+
}
|
|
380
|
+
)
|
|
267
381
|
] });
|
|
268
382
|
}
|
|
269
383
|
|
package/dist/index.mjs
CHANGED
|
@@ -125,9 +125,9 @@ function useWaitlist(campaign, config) {
|
|
|
125
125
|
}
|
|
126
126
|
|
|
127
127
|
// src/WaitlistForm.tsx
|
|
128
|
-
import { useState as useState2, useCallback as useCallback2, useMemo as useMemo2 } from "react";
|
|
128
|
+
import { useState as useState2, useCallback as useCallback2, useMemo as useMemo2, useEffect as useEffect2 } from "react";
|
|
129
129
|
import { FormController } from "queuezero";
|
|
130
|
-
import { jsx as jsx2, jsxs } from "react/jsx-runtime";
|
|
130
|
+
import { Fragment, jsx as jsx2, jsxs } from "react/jsx-runtime";
|
|
131
131
|
function WaitlistForm({
|
|
132
132
|
onSuccess,
|
|
133
133
|
onError,
|
|
@@ -139,12 +139,33 @@ function WaitlistForm({
|
|
|
139
139
|
loadingText = "Joining...",
|
|
140
140
|
showLabel = false,
|
|
141
141
|
labelText = "Email",
|
|
142
|
+
displayMode = "inline",
|
|
143
|
+
triggerText = "Join Waitlist",
|
|
144
|
+
modalSize = "md",
|
|
142
145
|
children
|
|
143
146
|
}) {
|
|
144
147
|
const { join, loading, error, isJoined, config, configLoading } = useWaitlistContext();
|
|
145
148
|
const [email, setEmail] = useState2("");
|
|
146
149
|
const [formData, setFormData] = useState2({});
|
|
147
150
|
const [localError, setLocalError] = useState2(null);
|
|
151
|
+
const [isModalOpen, setIsModalOpen] = useState2(false);
|
|
152
|
+
useEffect2(() => {
|
|
153
|
+
const handleEsc = (e) => {
|
|
154
|
+
if (e.key === "Escape" && isModalOpen) setIsModalOpen(false);
|
|
155
|
+
};
|
|
156
|
+
document.addEventListener("keydown", handleEsc);
|
|
157
|
+
return () => document.removeEventListener("keydown", handleEsc);
|
|
158
|
+
}, [isModalOpen]);
|
|
159
|
+
useEffect2(() => {
|
|
160
|
+
if (isModalOpen) {
|
|
161
|
+
document.body.style.overflow = "hidden";
|
|
162
|
+
} else {
|
|
163
|
+
document.body.style.overflow = "";
|
|
164
|
+
}
|
|
165
|
+
return () => {
|
|
166
|
+
document.body.style.overflow = "";
|
|
167
|
+
};
|
|
168
|
+
}, [isModalOpen]);
|
|
148
169
|
const controller = useMemo2(
|
|
149
170
|
() => new FormController(join, config?.formFields || [], referrerCode),
|
|
150
171
|
[join, config, referrerCode]
|
|
@@ -171,6 +192,13 @@ function WaitlistForm({
|
|
|
171
192
|
[email, formData, controller, metadata, onSuccess, onError, error]
|
|
172
193
|
);
|
|
173
194
|
const displayError = localError || error;
|
|
195
|
+
const branding = config?.branding || {};
|
|
196
|
+
const themeColor = branding.themeColor || "#10B981";
|
|
197
|
+
const sizeClasses = {
|
|
198
|
+
sm: "max-w-sm",
|
|
199
|
+
md: "max-w-md",
|
|
200
|
+
lg: "max-w-lg"
|
|
201
|
+
};
|
|
174
202
|
if (isJoined) {
|
|
175
203
|
return null;
|
|
176
204
|
}
|
|
@@ -183,7 +211,7 @@ function WaitlistForm({
|
|
|
183
211
|
error: displayError
|
|
184
212
|
});
|
|
185
213
|
}
|
|
186
|
-
|
|
214
|
+
const formContent = /* @__PURE__ */ jsxs("form", { onSubmit: handleSubmit, className: `qz-form ${displayMode === "inline" ? className : ""}`.trim(), children: [
|
|
187
215
|
showLabel && /* @__PURE__ */ jsx2("label", { htmlFor: "qz-email", className: "qz-form-label", children: labelText }),
|
|
188
216
|
/* @__PURE__ */ jsx2("div", { className: "qz-form-row", children: /* @__PURE__ */ jsx2(
|
|
189
217
|
"input",
|
|
@@ -199,42 +227,128 @@ function WaitlistForm({
|
|
|
199
227
|
"aria-label": !showLabel ? labelText : void 0
|
|
200
228
|
}
|
|
201
229
|
) }),
|
|
202
|
-
!configLoading && config?.formFields?.map((field) =>
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
230
|
+
!configLoading && config?.formFields?.map((field) => {
|
|
231
|
+
if (field.key === "email") return null;
|
|
232
|
+
const renderFieldInput = () => {
|
|
233
|
+
switch (field.type) {
|
|
234
|
+
case "select":
|
|
235
|
+
return /* @__PURE__ */ jsxs(
|
|
236
|
+
"select",
|
|
237
|
+
{
|
|
238
|
+
value: formData[field.key] || "",
|
|
239
|
+
onChange: (e) => setFormData((prev) => ({ ...prev, [field.key]: e.target.value })),
|
|
240
|
+
disabled: loading,
|
|
241
|
+
required: field.required,
|
|
242
|
+
className: "qz-form-select",
|
|
243
|
+
children: [
|
|
244
|
+
/* @__PURE__ */ jsx2("option", { value: "", children: field.placeholder || `Select ${field.label}` }),
|
|
245
|
+
field.options?.map((opt) => /* @__PURE__ */ jsx2("option", { value: opt, children: opt }, opt))
|
|
246
|
+
]
|
|
247
|
+
}
|
|
248
|
+
);
|
|
249
|
+
case "checkbox":
|
|
250
|
+
return /* @__PURE__ */ jsxs("label", { className: "qz-form-checkbox-label", children: [
|
|
251
|
+
/* @__PURE__ */ jsx2(
|
|
252
|
+
"input",
|
|
253
|
+
{
|
|
254
|
+
type: "checkbox",
|
|
255
|
+
checked: formData[field.key] === "true",
|
|
256
|
+
onChange: (e) => setFormData((prev) => ({ ...prev, [field.key]: e.target.checked ? "true" : "" })),
|
|
257
|
+
disabled: loading,
|
|
258
|
+
required: field.required,
|
|
259
|
+
className: "qz-form-checkbox"
|
|
260
|
+
}
|
|
261
|
+
),
|
|
262
|
+
/* @__PURE__ */ jsxs("span", { children: [
|
|
263
|
+
field.label,
|
|
264
|
+
field.required && " *"
|
|
265
|
+
] })
|
|
266
|
+
] });
|
|
267
|
+
case "textarea":
|
|
268
|
+
return /* @__PURE__ */ jsx2(
|
|
269
|
+
"textarea",
|
|
270
|
+
{
|
|
271
|
+
value: formData[field.key] || "",
|
|
272
|
+
onChange: (e) => setFormData((prev) => ({ ...prev, [field.key]: e.target.value })),
|
|
273
|
+
placeholder: field.placeholder || field.label,
|
|
274
|
+
disabled: loading,
|
|
275
|
+
required: field.required,
|
|
276
|
+
className: "qz-form-textarea",
|
|
277
|
+
rows: 3
|
|
278
|
+
}
|
|
279
|
+
);
|
|
280
|
+
default:
|
|
281
|
+
return /* @__PURE__ */ jsx2(
|
|
282
|
+
"input",
|
|
283
|
+
{
|
|
284
|
+
type: field.type === "number" ? "number" : "text",
|
|
285
|
+
value: formData[field.key] || "",
|
|
286
|
+
onChange: (e) => setFormData((prev) => ({ ...prev, [field.key]: e.target.value })),
|
|
287
|
+
placeholder: field.placeholder || field.label,
|
|
288
|
+
disabled: loading,
|
|
289
|
+
required: field.required,
|
|
290
|
+
className: "qz-form-input"
|
|
291
|
+
}
|
|
292
|
+
);
|
|
216
293
|
}
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
{
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
className: "qz-form-input"
|
|
227
|
-
}
|
|
228
|
-
)
|
|
229
|
-
] }, field.key)),
|
|
294
|
+
};
|
|
295
|
+
return /* @__PURE__ */ jsxs("div", { className: "qz-form-row", children: [
|
|
296
|
+
showLabel && field.type !== "checkbox" && /* @__PURE__ */ jsxs("label", { className: "qz-form-label", children: [
|
|
297
|
+
field.label,
|
|
298
|
+
field.required && " *"
|
|
299
|
+
] }),
|
|
300
|
+
renderFieldInput()
|
|
301
|
+
] }, field.key);
|
|
302
|
+
}),
|
|
230
303
|
/* @__PURE__ */ jsx2("div", { className: "qz-form-row", children: /* @__PURE__ */ jsx2("button", { type: "submit", disabled: loading, className: "qz-form-button", children: loading ? loadingText : buttonText }) }),
|
|
231
|
-
displayError && /* @__PURE__ */ jsx2("div", { className: "qz-form-error", role: "alert", children: displayError.message })
|
|
232
|
-
|
|
304
|
+
displayError && /* @__PURE__ */ jsx2("div", { className: "qz-form-error", role: "alert", children: displayError.message })
|
|
305
|
+
] });
|
|
306
|
+
if (displayMode === "inline") {
|
|
307
|
+
return formContent;
|
|
308
|
+
}
|
|
309
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
310
|
+
/* @__PURE__ */ jsx2(
|
|
311
|
+
"button",
|
|
312
|
+
{
|
|
313
|
+
type: "button",
|
|
314
|
+
onClick: () => setIsModalOpen(true),
|
|
315
|
+
className: `qz-modal-trigger ${className}`.trim(),
|
|
316
|
+
style: { "--qz-theme-color": themeColor },
|
|
317
|
+
children: triggerText
|
|
318
|
+
}
|
|
319
|
+
),
|
|
320
|
+
isModalOpen && /* @__PURE__ */ jsx2(
|
|
321
|
+
"div",
|
|
322
|
+
{
|
|
323
|
+
className: "qz-modal-overlay",
|
|
324
|
+
onClick: (e) => e.target === e.currentTarget && setIsModalOpen(false),
|
|
325
|
+
children: /* @__PURE__ */ jsxs("div", { className: `qz-modal ${sizeClasses[modalSize]}`, style: { "--qz-theme-color": themeColor }, children: [
|
|
326
|
+
/* @__PURE__ */ jsxs("div", { className: "qz-modal-header", children: [
|
|
327
|
+
branding.logoUrl ? /* @__PURE__ */ jsx2("img", { src: branding.logoUrl, alt: "Logo", className: "qz-modal-logo" }) : /* @__PURE__ */ jsx2("span", {}),
|
|
328
|
+
/* @__PURE__ */ jsx2(
|
|
329
|
+
"button",
|
|
330
|
+
{
|
|
331
|
+
type: "button",
|
|
332
|
+
className: "qz-modal-close",
|
|
333
|
+
onClick: () => setIsModalOpen(false),
|
|
334
|
+
"aria-label": "Close",
|
|
335
|
+
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" }) })
|
|
336
|
+
}
|
|
337
|
+
)
|
|
338
|
+
] }),
|
|
339
|
+
branding.coverImageUrl && /* @__PURE__ */ jsx2("img", { src: branding.coverImageUrl, alt: "", className: "qz-modal-cover" }),
|
|
340
|
+
/* @__PURE__ */ jsxs("div", { className: "qz-modal-body", children: [
|
|
341
|
+
/* @__PURE__ */ jsx2("h2", { className: "qz-modal-title", children: config?.name || "Join Waitlist" }),
|
|
342
|
+
formContent
|
|
343
|
+
] })
|
|
344
|
+
] })
|
|
345
|
+
}
|
|
346
|
+
)
|
|
233
347
|
] });
|
|
234
348
|
}
|
|
235
349
|
|
|
236
350
|
// src/WaitlistStatus.tsx
|
|
237
|
-
import { Fragment, jsx as jsx3, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
351
|
+
import { Fragment as Fragment2, jsx as jsx3, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
238
352
|
function WaitlistStatus({
|
|
239
353
|
className = "",
|
|
240
354
|
showReferrals = true,
|
|
@@ -252,7 +366,7 @@ function WaitlistStatus({
|
|
|
252
366
|
return /* @__PURE__ */ jsx3("div", { className: `qz-status qz-status-loading ${className}`.trim(), children: "Loading..." });
|
|
253
367
|
}
|
|
254
368
|
if (typeof children === "function") {
|
|
255
|
-
return /* @__PURE__ */ jsx3(
|
|
369
|
+
return /* @__PURE__ */ jsx3(Fragment2, { children: children(status) });
|
|
256
370
|
}
|
|
257
371
|
return /* @__PURE__ */ jsxs2("div", { className: `qz-status ${className}`.trim(), children: [
|
|
258
372
|
/* @__PURE__ */ jsxs2("div", { className: "qz-status-item qz-status-position", children: [
|
|
@@ -275,7 +389,7 @@ function WaitlistStatus({
|
|
|
275
389
|
|
|
276
390
|
// src/ReferralShare.tsx
|
|
277
391
|
import { useState as useState3, useCallback as useCallback3 } from "react";
|
|
278
|
-
import { Fragment as
|
|
392
|
+
import { Fragment as Fragment3, jsx as jsx4, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
279
393
|
function ReferralShare({
|
|
280
394
|
className = "",
|
|
281
395
|
label = "Share your referral link:",
|
|
@@ -336,7 +450,7 @@ ${link}`);
|
|
|
336
450
|
return null;
|
|
337
451
|
}
|
|
338
452
|
if (typeof children === "function") {
|
|
339
|
-
return /* @__PURE__ */ jsx4(
|
|
453
|
+
return /* @__PURE__ */ jsx4(Fragment3, { children: children({ link, code, copy: handleCopy, copied }) });
|
|
340
454
|
}
|
|
341
455
|
return /* @__PURE__ */ jsxs3("div", { className: `qz-share ${className}`.trim(), children: [
|
|
342
456
|
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.8",
|
|
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",
|