@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 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
- * // With referral code from URL
197
- * const referrerCode = new URLSearchParams(window.location.search).get('ref');
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
- * // With referral code from URL
197
- * const referrerCode = new URLSearchParams(window.location.search).get('ref');
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
- return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("form", { onSubmit: handleSubmit, className: `qz-form ${className}`.trim(), children: [
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) => /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "qz-form-row", children: [
237
- showLabel && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("label", { className: "qz-form-label", children: field.label }),
238
- field.type === "select" ? /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
239
- "select",
240
- {
241
- value: formData[field.key] || "",
242
- onChange: (e) => setFormData((prev) => ({ ...prev, [field.key]: e.target.value })),
243
- disabled: loading,
244
- required: field.required,
245
- className: "qz-form-select",
246
- children: [
247
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("option", { value: "", children: field.placeholder || `Select ${field.label}` }),
248
- field.options?.map((opt) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("option", { value: opt, children: opt }, opt))
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
- ) : /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
252
- "input",
253
- {
254
- type: field.type === "number" ? "number" : "text",
255
- value: formData[field.key] || "",
256
- onChange: (e) => setFormData((prev) => ({ ...prev, [field.key]: e.target.value })),
257
- placeholder: field.placeholder || field.label,
258
- disabled: loading,
259
- required: field.required,
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
- children
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
- return /* @__PURE__ */ jsxs("form", { onSubmit: handleSubmit, className: `qz-form ${className}`.trim(), children: [
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) => /* @__PURE__ */ jsxs("div", { className: "qz-form-row", children: [
203
- showLabel && /* @__PURE__ */ jsx2("label", { className: "qz-form-label", children: field.label }),
204
- field.type === "select" ? /* @__PURE__ */ jsxs(
205
- "select",
206
- {
207
- value: formData[field.key] || "",
208
- onChange: (e) => setFormData((prev) => ({ ...prev, [field.key]: e.target.value })),
209
- disabled: loading,
210
- required: field.required,
211
- className: "qz-form-select",
212
- children: [
213
- /* @__PURE__ */ jsx2("option", { value: "", children: field.placeholder || `Select ${field.label}` }),
214
- field.options?.map((opt) => /* @__PURE__ */ jsx2("option", { value: opt, children: opt }, opt))
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
- ) : /* @__PURE__ */ jsx2(
218
- "input",
219
- {
220
- type: field.type === "number" ? "number" : "text",
221
- value: formData[field.key] || "",
222
- onChange: (e) => setFormData((prev) => ({ ...prev, [field.key]: e.target.value })),
223
- placeholder: field.placeholder || field.label,
224
- disabled: loading,
225
- required: field.required,
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
- children
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(Fragment, { children: children(status) });
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 Fragment2, jsx as jsx4, jsxs as jsxs3 } from "react/jsx-runtime";
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(Fragment2, { children: children({ link, code, copy: handleCopy, copied }) });
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.6",
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.4"
38
+ "queuezero": "^0.1.6"
39
39
  },
40
40
  "devDependencies": {
41
41
  "@types/node": "^22.13.11",