@queuezero/vue 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
@@ -56,6 +56,12 @@ interface WaitlistFormProps {
56
56
  showLabel?: boolean;
57
57
  /** Label text */
58
58
  labelText?: string;
59
+ /** Display mode: 'inline' renders form directly, 'modal' renders trigger button */
60
+ displayMode?: 'inline' | 'modal';
61
+ /** Text for modal trigger button (only used when displayMode is 'modal') */
62
+ triggerText?: string;
63
+ /** Modal size (only used when displayMode is 'modal') */
64
+ modalSize?: 'sm' | 'md' | 'lg';
59
65
  }
60
66
  /**
61
67
  * Props for WaitlistStatus component
@@ -200,6 +206,18 @@ declare const WaitlistForm: vue.DefineComponent<vue.ExtractPropTypes<{
200
206
  type: StringConstructor;
201
207
  default: string;
202
208
  };
209
+ displayMode: {
210
+ type: PropType<"inline" | "modal">;
211
+ default: string;
212
+ };
213
+ triggerText: {
214
+ type: StringConstructor;
215
+ default: string;
216
+ };
217
+ modalSize: {
218
+ type: PropType<"sm" | "md" | "lg">;
219
+ default: string;
220
+ };
203
221
  }>, () => VNode<vue.RendererNode, vue.RendererElement, {
204
222
  [key: string]: any;
205
223
  }> | VNode<vue.RendererNode, vue.RendererElement, {
@@ -236,6 +254,18 @@ declare const WaitlistForm: vue.DefineComponent<vue.ExtractPropTypes<{
236
254
  type: StringConstructor;
237
255
  default: string;
238
256
  };
257
+ displayMode: {
258
+ type: PropType<"inline" | "modal">;
259
+ default: string;
260
+ };
261
+ triggerText: {
262
+ type: StringConstructor;
263
+ default: string;
264
+ };
265
+ modalSize: {
266
+ type: PropType<"sm" | "md" | "lg">;
267
+ default: string;
268
+ };
239
269
  }>> & Readonly<{
240
270
  onSuccess?: ((response: SubmitResponse) => any) | undefined;
241
271
  onError?: ((error: Error) => any) | undefined;
@@ -247,6 +277,9 @@ declare const WaitlistForm: vue.DefineComponent<vue.ExtractPropTypes<{
247
277
  loadingText: string;
248
278
  showLabel: boolean;
249
279
  labelText: string;
280
+ displayMode: "inline" | "modal";
281
+ triggerText: string;
282
+ modalSize: "sm" | "md" | "lg";
250
283
  }, {}, {}, {}, string, vue.ComponentProvideOptions, true, {}, any>;
251
284
 
252
285
  /**
package/dist/index.d.ts CHANGED
@@ -56,6 +56,12 @@ interface WaitlistFormProps {
56
56
  showLabel?: boolean;
57
57
  /** Label text */
58
58
  labelText?: string;
59
+ /** Display mode: 'inline' renders form directly, 'modal' renders trigger button */
60
+ displayMode?: 'inline' | 'modal';
61
+ /** Text for modal trigger button (only used when displayMode is 'modal') */
62
+ triggerText?: string;
63
+ /** Modal size (only used when displayMode is 'modal') */
64
+ modalSize?: 'sm' | 'md' | 'lg';
59
65
  }
60
66
  /**
61
67
  * Props for WaitlistStatus component
@@ -200,6 +206,18 @@ declare const WaitlistForm: vue.DefineComponent<vue.ExtractPropTypes<{
200
206
  type: StringConstructor;
201
207
  default: string;
202
208
  };
209
+ displayMode: {
210
+ type: PropType<"inline" | "modal">;
211
+ default: string;
212
+ };
213
+ triggerText: {
214
+ type: StringConstructor;
215
+ default: string;
216
+ };
217
+ modalSize: {
218
+ type: PropType<"sm" | "md" | "lg">;
219
+ default: string;
220
+ };
203
221
  }>, () => VNode<vue.RendererNode, vue.RendererElement, {
204
222
  [key: string]: any;
205
223
  }> | VNode<vue.RendererNode, vue.RendererElement, {
@@ -236,6 +254,18 @@ declare const WaitlistForm: vue.DefineComponent<vue.ExtractPropTypes<{
236
254
  type: StringConstructor;
237
255
  default: string;
238
256
  };
257
+ displayMode: {
258
+ type: PropType<"inline" | "modal">;
259
+ default: string;
260
+ };
261
+ triggerText: {
262
+ type: StringConstructor;
263
+ default: string;
264
+ };
265
+ modalSize: {
266
+ type: PropType<"sm" | "md" | "lg">;
267
+ default: string;
268
+ };
239
269
  }>> & Readonly<{
240
270
  onSuccess?: ((response: SubmitResponse) => any) | undefined;
241
271
  onError?: ((error: Error) => any) | undefined;
@@ -247,6 +277,9 @@ declare const WaitlistForm: vue.DefineComponent<vue.ExtractPropTypes<{
247
277
  loadingText: string;
248
278
  showLabel: boolean;
249
279
  labelText: string;
280
+ displayMode: "inline" | "modal";
281
+ triggerText: string;
282
+ modalSize: "sm" | "md" | "lg";
250
283
  }, {}, {}, {}, string, vue.ComponentProvideOptions, true, {}, any>;
251
284
 
252
285
  /**
package/dist/index.js CHANGED
@@ -135,6 +135,18 @@ var WaitlistForm = (0, import_vue2.defineComponent)({
135
135
  labelText: {
136
136
  type: String,
137
137
  default: "Email"
138
+ },
139
+ displayMode: {
140
+ type: String,
141
+ default: "inline"
142
+ },
143
+ triggerText: {
144
+ type: String,
145
+ default: "Join Waitlist"
146
+ },
147
+ modalSize: {
148
+ type: String,
149
+ default: "md"
138
150
  }
139
151
  },
140
152
  emits: {
@@ -145,8 +157,12 @@ var WaitlistForm = (0, import_vue2.defineComponent)({
145
157
  const { join, loading, error: contextError, isJoined, publicConfig } = useWaitlistContext();
146
158
  const email = (0, import_vue2.ref)("");
147
159
  const localError = (0, import_vue2.ref)(null);
160
+ const isModalOpen = (0, import_vue2.ref)(false);
148
161
  const formData = (0, import_vue2.reactive)({});
149
162
  const displayError = (0, import_vue2.computed)(() => localError.value || contextError.value);
163
+ const branding = (0, import_vue2.computed)(() => publicConfig.value?.branding || {});
164
+ const themeColor = (0, import_vue2.computed)(() => branding.value.themeColor || "#10B981");
165
+ const sizeClasses = { sm: "qz-modal-sm", md: "qz-modal-md", lg: "qz-modal-lg" };
150
166
  const formFields = (0, import_vue2.computed)(() => {
151
167
  return publicConfig.value?.formFields?.filter((f) => f.enabled) ?? [];
152
168
  });
@@ -230,6 +246,20 @@ var WaitlistForm = (0, import_vue2.defineComponent)({
230
246
  }
231
247
  });
232
248
  break;
249
+ case "textarea":
250
+ inputNode = (0, import_vue2.h)("textarea", {
251
+ id: fieldId,
252
+ class: "qz-form-textarea",
253
+ value: fieldValue,
254
+ placeholder: field.placeholder || "",
255
+ disabled: loading.value,
256
+ required: field.required,
257
+ rows: 3,
258
+ onInput: (e) => {
259
+ formData[field.key] = e.target.value;
260
+ }
261
+ });
262
+ break;
233
263
  default:
234
264
  inputNode = (0, import_vue2.h)("input", {
235
265
  id: fieldId,
@@ -284,7 +314,7 @@ var WaitlistForm = (0, import_vue2.defineComponent)({
284
314
  formFields.value.forEach((field) => {
285
315
  fieldNodes.push(renderField(field));
286
316
  });
287
- return (0, import_vue2.h)(
317
+ const formContent = (0, import_vue2.h)(
288
318
  "form",
289
319
  {
290
320
  class: "qz-form",
@@ -310,6 +340,61 @@ var WaitlistForm = (0, import_vue2.defineComponent)({
310
340
  )
311
341
  ]
312
342
  );
343
+ if (props.displayMode === "inline") {
344
+ return formContent;
345
+ }
346
+ return (0, import_vue2.h)("div", { class: "qz-waitlist-modal-wrapper" }, [
347
+ // Trigger button
348
+ (0, import_vue2.h)(
349
+ "button",
350
+ {
351
+ type: "button",
352
+ class: "qz-modal-trigger",
353
+ style: { "--qz-theme-color": themeColor.value },
354
+ onClick: () => {
355
+ isModalOpen.value = true;
356
+ }
357
+ },
358
+ props.triggerText
359
+ ),
360
+ // Modal overlay (only when open)
361
+ isModalOpen.value && (0, import_vue2.h)(
362
+ "div",
363
+ {
364
+ class: "qz-modal-overlay",
365
+ onClick: (e) => {
366
+ if (e.target === e.currentTarget) isModalOpen.value = false;
367
+ }
368
+ },
369
+ [
370
+ (0, import_vue2.h)("div", { class: `qz-modal ${sizeClasses[props.modalSize]}`, style: { "--qz-theme-color": themeColor.value } }, [
371
+ // Header
372
+ (0, import_vue2.h)("div", { class: "qz-modal-header" }, [
373
+ branding.value.logoUrl ? (0, import_vue2.h)("img", { src: branding.value.logoUrl, alt: "Logo", class: "qz-modal-logo" }) : (0, import_vue2.h)("span"),
374
+ (0, import_vue2.h)("button", {
375
+ type: "button",
376
+ class: "qz-modal-close",
377
+ "aria-label": "Close",
378
+ onClick: () => {
379
+ isModalOpen.value = false;
380
+ }
381
+ }, [
382
+ (0, import_vue2.h)("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", "stroke-width": "2" }, [
383
+ (0, import_vue2.h)("path", { d: "M18 6L6 18M6 6l12 12" })
384
+ ])
385
+ ])
386
+ ]),
387
+ // Cover image
388
+ branding.value.coverImageUrl && (0, import_vue2.h)("img", { src: branding.value.coverImageUrl, alt: "", class: "qz-modal-cover" }),
389
+ // Body
390
+ (0, import_vue2.h)("div", { class: "qz-modal-body" }, [
391
+ (0, import_vue2.h)("h2", { class: "qz-modal-title" }, publicConfig.value?.name || "Join Waitlist"),
392
+ formContent
393
+ ])
394
+ ])
395
+ ]
396
+ )
397
+ ]);
313
398
  };
314
399
  }
315
400
  });
package/dist/index.mjs CHANGED
@@ -99,6 +99,18 @@ var WaitlistForm = defineComponent({
99
99
  labelText: {
100
100
  type: String,
101
101
  default: "Email"
102
+ },
103
+ displayMode: {
104
+ type: String,
105
+ default: "inline"
106
+ },
107
+ triggerText: {
108
+ type: String,
109
+ default: "Join Waitlist"
110
+ },
111
+ modalSize: {
112
+ type: String,
113
+ default: "md"
102
114
  }
103
115
  },
104
116
  emits: {
@@ -109,8 +121,12 @@ var WaitlistForm = defineComponent({
109
121
  const { join, loading, error: contextError, isJoined, publicConfig } = useWaitlistContext();
110
122
  const email = ref2("");
111
123
  const localError = ref2(null);
124
+ const isModalOpen = ref2(false);
112
125
  const formData = reactive({});
113
126
  const displayError = computed2(() => localError.value || contextError.value);
127
+ const branding = computed2(() => publicConfig.value?.branding || {});
128
+ const themeColor = computed2(() => branding.value.themeColor || "#10B981");
129
+ const sizeClasses = { sm: "qz-modal-sm", md: "qz-modal-md", lg: "qz-modal-lg" };
114
130
  const formFields = computed2(() => {
115
131
  return publicConfig.value?.formFields?.filter((f) => f.enabled) ?? [];
116
132
  });
@@ -194,6 +210,20 @@ var WaitlistForm = defineComponent({
194
210
  }
195
211
  });
196
212
  break;
213
+ case "textarea":
214
+ inputNode = h("textarea", {
215
+ id: fieldId,
216
+ class: "qz-form-textarea",
217
+ value: fieldValue,
218
+ placeholder: field.placeholder || "",
219
+ disabled: loading.value,
220
+ required: field.required,
221
+ rows: 3,
222
+ onInput: (e) => {
223
+ formData[field.key] = e.target.value;
224
+ }
225
+ });
226
+ break;
197
227
  default:
198
228
  inputNode = h("input", {
199
229
  id: fieldId,
@@ -248,7 +278,7 @@ var WaitlistForm = defineComponent({
248
278
  formFields.value.forEach((field) => {
249
279
  fieldNodes.push(renderField(field));
250
280
  });
251
- return h(
281
+ const formContent = h(
252
282
  "form",
253
283
  {
254
284
  class: "qz-form",
@@ -274,6 +304,61 @@ var WaitlistForm = defineComponent({
274
304
  )
275
305
  ]
276
306
  );
307
+ if (props.displayMode === "inline") {
308
+ return formContent;
309
+ }
310
+ return h("div", { class: "qz-waitlist-modal-wrapper" }, [
311
+ // Trigger button
312
+ h(
313
+ "button",
314
+ {
315
+ type: "button",
316
+ class: "qz-modal-trigger",
317
+ style: { "--qz-theme-color": themeColor.value },
318
+ onClick: () => {
319
+ isModalOpen.value = true;
320
+ }
321
+ },
322
+ props.triggerText
323
+ ),
324
+ // Modal overlay (only when open)
325
+ isModalOpen.value && h(
326
+ "div",
327
+ {
328
+ class: "qz-modal-overlay",
329
+ onClick: (e) => {
330
+ if (e.target === e.currentTarget) isModalOpen.value = false;
331
+ }
332
+ },
333
+ [
334
+ h("div", { class: `qz-modal ${sizeClasses[props.modalSize]}`, style: { "--qz-theme-color": themeColor.value } }, [
335
+ // Header
336
+ h("div", { class: "qz-modal-header" }, [
337
+ branding.value.logoUrl ? h("img", { src: branding.value.logoUrl, alt: "Logo", class: "qz-modal-logo" }) : h("span"),
338
+ h("button", {
339
+ type: "button",
340
+ class: "qz-modal-close",
341
+ "aria-label": "Close",
342
+ onClick: () => {
343
+ isModalOpen.value = false;
344
+ }
345
+ }, [
346
+ h("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", "stroke-width": "2" }, [
347
+ h("path", { d: "M18 6L6 18M6 6l12 12" })
348
+ ])
349
+ ])
350
+ ]),
351
+ // Cover image
352
+ branding.value.coverImageUrl && h("img", { src: branding.value.coverImageUrl, alt: "", class: "qz-modal-cover" }),
353
+ // Body
354
+ h("div", { class: "qz-modal-body" }, [
355
+ h("h2", { class: "qz-modal-title" }, publicConfig.value?.name || "Join Waitlist"),
356
+ formContent
357
+ ])
358
+ ])
359
+ ]
360
+ )
361
+ ]);
277
362
  };
278
363
  }
279
364
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@queuezero/vue",
3
- "version": "0.1.6",
3
+ "version": "0.1.8",
4
4
  "description": "Vue components and composables for QueueZero viral waitlists",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/index.mjs",
@@ -34,7 +34,7 @@
34
34
  "vue": ">=3.3.0"
35
35
  },
36
36
  "dependencies": {
37
- "queuezero": "^0.1.4"
37
+ "queuezero": "^0.1.6"
38
38
  },
39
39
  "devDependencies": {
40
40
  "@types/node": "^22.13.11",