@queuezero/vue 0.1.3
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 +203 -0
- package/dist/index.d.mts +374 -0
- package/dist/index.d.ts +374 -0
- package/dist/index.js +565 -0
- package/dist/index.mjs +528 -0
- package/package.json +46 -0
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,528 @@
|
|
|
1
|
+
// src/composables.ts
|
|
2
|
+
import { ref, onMounted, inject, provide } from "vue";
|
|
3
|
+
import { QueueZeroClient, QueueZeroStateManager } from "queuezero";
|
|
4
|
+
var WAITLIST_INJECTION_KEY = /* @__PURE__ */ Symbol("queuezero-waitlist");
|
|
5
|
+
function useWaitlist(campaign, config) {
|
|
6
|
+
const injected = inject(WAITLIST_INJECTION_KEY, null);
|
|
7
|
+
if (injected && !campaign) {
|
|
8
|
+
return injected;
|
|
9
|
+
}
|
|
10
|
+
if (!campaign) {
|
|
11
|
+
throw new Error("useWaitlist requires a campaign slug or must be used within WaitlistProvider");
|
|
12
|
+
}
|
|
13
|
+
const client = new QueueZeroClient(campaign, config);
|
|
14
|
+
const stateManager = new QueueZeroStateManager(client);
|
|
15
|
+
const loading = ref(stateManager.getState().loading);
|
|
16
|
+
const status = ref(stateManager.getState().status);
|
|
17
|
+
const error = ref(stateManager.getState().error);
|
|
18
|
+
const isJoined = ref(stateManager.getState().isJoined);
|
|
19
|
+
const publicConfig = ref(stateManager.getState().publicConfig);
|
|
20
|
+
stateManager.subscribe((newState) => {
|
|
21
|
+
loading.value = newState.loading;
|
|
22
|
+
status.value = newState.status;
|
|
23
|
+
error.value = newState.error;
|
|
24
|
+
isJoined.value = newState.isJoined;
|
|
25
|
+
publicConfig.value = newState.publicConfig;
|
|
26
|
+
});
|
|
27
|
+
onMounted(async () => {
|
|
28
|
+
await stateManager.fetchPublicConfig();
|
|
29
|
+
if (stateManager.getState().isJoined) {
|
|
30
|
+
stateManager.refresh();
|
|
31
|
+
}
|
|
32
|
+
});
|
|
33
|
+
return {
|
|
34
|
+
loading,
|
|
35
|
+
status,
|
|
36
|
+
error,
|
|
37
|
+
isJoined,
|
|
38
|
+
publicConfig,
|
|
39
|
+
campaign,
|
|
40
|
+
join: stateManager.join.bind(stateManager),
|
|
41
|
+
refresh: stateManager.refresh.bind(stateManager),
|
|
42
|
+
fetchPublicConfig: stateManager.fetchPublicConfig.bind(stateManager),
|
|
43
|
+
getReferralLink: stateManager.getReferralLink.bind(stateManager),
|
|
44
|
+
getReferralCode: stateManager.getReferralCode.bind(stateManager),
|
|
45
|
+
reset: stateManager.reset.bind(stateManager)
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
function provideWaitlist(campaign, config) {
|
|
49
|
+
const waitlist = useWaitlist(campaign, config);
|
|
50
|
+
provide(WAITLIST_INJECTION_KEY, waitlist);
|
|
51
|
+
return waitlist;
|
|
52
|
+
}
|
|
53
|
+
function useWaitlistContext() {
|
|
54
|
+
const context = inject(WAITLIST_INJECTION_KEY);
|
|
55
|
+
if (!context) {
|
|
56
|
+
throw new Error("useWaitlistContext must be used within a component that calls provideWaitlist");
|
|
57
|
+
}
|
|
58
|
+
return context;
|
|
59
|
+
}
|
|
60
|
+
function createWaitlistPlugin(options) {
|
|
61
|
+
return {
|
|
62
|
+
install(app) {
|
|
63
|
+
const waitlist = useWaitlist(options.campaign, options.config);
|
|
64
|
+
app.provide(WAITLIST_INJECTION_KEY, waitlist);
|
|
65
|
+
}
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
// src/WaitlistForm.ts
|
|
70
|
+
import { defineComponent, ref as ref2, computed as computed2, h, reactive } from "vue";
|
|
71
|
+
import { FormController } from "queuezero";
|
|
72
|
+
var WaitlistForm = defineComponent({
|
|
73
|
+
name: "WaitlistForm",
|
|
74
|
+
props: {
|
|
75
|
+
referrerCode: {
|
|
76
|
+
type: String,
|
|
77
|
+
default: void 0
|
|
78
|
+
},
|
|
79
|
+
metadata: {
|
|
80
|
+
type: Object,
|
|
81
|
+
default: () => ({})
|
|
82
|
+
},
|
|
83
|
+
placeholder: {
|
|
84
|
+
type: String,
|
|
85
|
+
default: "Enter your email"
|
|
86
|
+
},
|
|
87
|
+
buttonText: {
|
|
88
|
+
type: String,
|
|
89
|
+
default: "Join Waitlist"
|
|
90
|
+
},
|
|
91
|
+
loadingText: {
|
|
92
|
+
type: String,
|
|
93
|
+
default: "Joining..."
|
|
94
|
+
},
|
|
95
|
+
showLabel: {
|
|
96
|
+
type: Boolean,
|
|
97
|
+
default: true
|
|
98
|
+
},
|
|
99
|
+
labelText: {
|
|
100
|
+
type: String,
|
|
101
|
+
default: "Email"
|
|
102
|
+
}
|
|
103
|
+
},
|
|
104
|
+
emits: {
|
|
105
|
+
success: (response) => true,
|
|
106
|
+
error: (error) => true
|
|
107
|
+
},
|
|
108
|
+
setup(props, { emit, slots }) {
|
|
109
|
+
const { join, loading, error: contextError, isJoined, publicConfig } = useWaitlistContext();
|
|
110
|
+
const email = ref2("");
|
|
111
|
+
const localError = ref2(null);
|
|
112
|
+
const formData = reactive({});
|
|
113
|
+
const displayError = computed2(() => localError.value || contextError.value);
|
|
114
|
+
const formFields = computed2(() => {
|
|
115
|
+
return publicConfig.value?.formFields?.filter((f) => f.enabled) ?? [];
|
|
116
|
+
});
|
|
117
|
+
const controller = computed2(
|
|
118
|
+
() => new FormController(join, formFields.value, props.referrerCode)
|
|
119
|
+
);
|
|
120
|
+
async function handleSubmit(e) {
|
|
121
|
+
e?.preventDefault();
|
|
122
|
+
localError.value = null;
|
|
123
|
+
try {
|
|
124
|
+
const result = await controller.value.submit(email.value, formData, props.metadata);
|
|
125
|
+
if (result) {
|
|
126
|
+
email.value = "";
|
|
127
|
+
Object.keys(formData).forEach((key) => delete formData[key]);
|
|
128
|
+
emit("success", result);
|
|
129
|
+
} else if (contextError.value) {
|
|
130
|
+
emit("error", contextError.value);
|
|
131
|
+
}
|
|
132
|
+
} catch (err) {
|
|
133
|
+
const error = err instanceof Error ? err : new Error("Failed to join");
|
|
134
|
+
localError.value = error;
|
|
135
|
+
emit("error", error);
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
function renderField(field) {
|
|
139
|
+
const fieldId = `qz-field-${field.key}`;
|
|
140
|
+
const fieldValue = formData[field.key] ?? "";
|
|
141
|
+
const labelNode = h("label", {
|
|
142
|
+
class: "qz-form-label",
|
|
143
|
+
for: fieldId
|
|
144
|
+
}, [
|
|
145
|
+
field.label,
|
|
146
|
+
field.required && h("span", { class: "qz-required" }, " *")
|
|
147
|
+
]);
|
|
148
|
+
let inputNode;
|
|
149
|
+
switch (field.type) {
|
|
150
|
+
case "select":
|
|
151
|
+
inputNode = h("select", {
|
|
152
|
+
id: fieldId,
|
|
153
|
+
class: "qz-form-select",
|
|
154
|
+
value: fieldValue,
|
|
155
|
+
disabled: loading.value,
|
|
156
|
+
required: field.required,
|
|
157
|
+
onChange: (e) => {
|
|
158
|
+
formData[field.key] = e.target.value;
|
|
159
|
+
}
|
|
160
|
+
}, [
|
|
161
|
+
h("option", { value: "" }, field.placeholder || `Select ${field.label}`),
|
|
162
|
+
...(field.options || []).map(
|
|
163
|
+
(opt) => h("option", { value: opt }, opt)
|
|
164
|
+
)
|
|
165
|
+
]);
|
|
166
|
+
break;
|
|
167
|
+
case "checkbox":
|
|
168
|
+
inputNode = h("div", { class: "qz-form-checkbox-wrapper" }, [
|
|
169
|
+
h("input", {
|
|
170
|
+
id: fieldId,
|
|
171
|
+
type: "checkbox",
|
|
172
|
+
class: "qz-form-checkbox",
|
|
173
|
+
checked: !!formData[field.key],
|
|
174
|
+
disabled: loading.value,
|
|
175
|
+
required: field.required,
|
|
176
|
+
onChange: (e) => {
|
|
177
|
+
formData[field.key] = e.target.checked;
|
|
178
|
+
}
|
|
179
|
+
}),
|
|
180
|
+
h("label", { for: fieldId, class: "qz-form-checkbox-label" }, field.label)
|
|
181
|
+
]);
|
|
182
|
+
return h("div", { class: "qz-form-field" }, [inputNode]);
|
|
183
|
+
case "number":
|
|
184
|
+
inputNode = h("input", {
|
|
185
|
+
id: fieldId,
|
|
186
|
+
type: "number",
|
|
187
|
+
class: "qz-form-input",
|
|
188
|
+
value: fieldValue,
|
|
189
|
+
placeholder: field.placeholder || "",
|
|
190
|
+
disabled: loading.value,
|
|
191
|
+
required: field.required,
|
|
192
|
+
onInput: (e) => {
|
|
193
|
+
formData[field.key] = e.target.value;
|
|
194
|
+
}
|
|
195
|
+
});
|
|
196
|
+
break;
|
|
197
|
+
default:
|
|
198
|
+
inputNode = h("input", {
|
|
199
|
+
id: fieldId,
|
|
200
|
+
type: field.type,
|
|
201
|
+
class: "qz-form-input",
|
|
202
|
+
value: fieldValue,
|
|
203
|
+
placeholder: field.placeholder || "",
|
|
204
|
+
disabled: loading.value,
|
|
205
|
+
required: field.required,
|
|
206
|
+
onInput: (e) => {
|
|
207
|
+
formData[field.key] = e.target.value;
|
|
208
|
+
}
|
|
209
|
+
});
|
|
210
|
+
}
|
|
211
|
+
return h("div", { class: "qz-form-field" }, [labelNode, inputNode]);
|
|
212
|
+
}
|
|
213
|
+
return () => {
|
|
214
|
+
if (isJoined.value) {
|
|
215
|
+
return null;
|
|
216
|
+
}
|
|
217
|
+
if (slots.default) {
|
|
218
|
+
return slots.default({
|
|
219
|
+
email: email.value,
|
|
220
|
+
setEmail: (val) => email.value = val,
|
|
221
|
+
formData,
|
|
222
|
+
formFields: formFields.value,
|
|
223
|
+
submit: handleSubmit,
|
|
224
|
+
loading: loading.value,
|
|
225
|
+
error: displayError.value
|
|
226
|
+
});
|
|
227
|
+
}
|
|
228
|
+
const fieldNodes = [];
|
|
229
|
+
fieldNodes.push(
|
|
230
|
+
h("div", { class: "qz-form-field" }, [
|
|
231
|
+
props.showLabel && h("label", { class: "qz-form-label", for: "qz-email" }, [
|
|
232
|
+
props.labelText,
|
|
233
|
+
h("span", { class: "qz-required" }, " *")
|
|
234
|
+
]),
|
|
235
|
+
h("input", {
|
|
236
|
+
id: "qz-email",
|
|
237
|
+
type: "email",
|
|
238
|
+
value: email.value,
|
|
239
|
+
onInput: (e) => email.value = e.target.value,
|
|
240
|
+
placeholder: props.placeholder,
|
|
241
|
+
disabled: loading.value,
|
|
242
|
+
required: true,
|
|
243
|
+
class: "qz-form-input",
|
|
244
|
+
"aria-label": !props.showLabel ? props.labelText : void 0
|
|
245
|
+
})
|
|
246
|
+
])
|
|
247
|
+
);
|
|
248
|
+
formFields.value.forEach((field) => {
|
|
249
|
+
fieldNodes.push(renderField(field));
|
|
250
|
+
});
|
|
251
|
+
return h(
|
|
252
|
+
"form",
|
|
253
|
+
{
|
|
254
|
+
class: "qz-form",
|
|
255
|
+
onSubmit: handleSubmit
|
|
256
|
+
},
|
|
257
|
+
[
|
|
258
|
+
...fieldNodes,
|
|
259
|
+
h("div", { class: "qz-form-actions" }, [
|
|
260
|
+
h(
|
|
261
|
+
"button",
|
|
262
|
+
{
|
|
263
|
+
type: "submit",
|
|
264
|
+
disabled: loading.value,
|
|
265
|
+
class: "qz-form-button"
|
|
266
|
+
},
|
|
267
|
+
loading.value ? props.loadingText : props.buttonText
|
|
268
|
+
)
|
|
269
|
+
]),
|
|
270
|
+
displayError.value && h(
|
|
271
|
+
"div",
|
|
272
|
+
{ class: "qz-form-error", role: "alert" },
|
|
273
|
+
displayError.value.message
|
|
274
|
+
)
|
|
275
|
+
]
|
|
276
|
+
);
|
|
277
|
+
};
|
|
278
|
+
}
|
|
279
|
+
});
|
|
280
|
+
|
|
281
|
+
// src/WaitlistStatus.ts
|
|
282
|
+
import { defineComponent as defineComponent2, h as h2 } from "vue";
|
|
283
|
+
var WaitlistStatus = defineComponent2({
|
|
284
|
+
name: "WaitlistStatus",
|
|
285
|
+
props: {
|
|
286
|
+
showReferrals: {
|
|
287
|
+
type: Boolean,
|
|
288
|
+
default: true
|
|
289
|
+
},
|
|
290
|
+
showScore: {
|
|
291
|
+
type: Boolean,
|
|
292
|
+
default: true
|
|
293
|
+
},
|
|
294
|
+
positionLabel: {
|
|
295
|
+
type: String,
|
|
296
|
+
default: "Position"
|
|
297
|
+
},
|
|
298
|
+
scoreLabel: {
|
|
299
|
+
type: String,
|
|
300
|
+
default: "Score"
|
|
301
|
+
},
|
|
302
|
+
referralsLabel: {
|
|
303
|
+
type: String,
|
|
304
|
+
default: "Referrals"
|
|
305
|
+
}
|
|
306
|
+
},
|
|
307
|
+
setup(props, { slots }) {
|
|
308
|
+
const { status, loading, isJoined } = useWaitlistContext();
|
|
309
|
+
return () => {
|
|
310
|
+
if (!isJoined.value || !status.value) {
|
|
311
|
+
return null;
|
|
312
|
+
}
|
|
313
|
+
if (loading.value && !status.value) {
|
|
314
|
+
return h2("div", { class: "qz-status qz-status-loading" }, "Loading...");
|
|
315
|
+
}
|
|
316
|
+
if (slots.default) {
|
|
317
|
+
return slots.default(status.value);
|
|
318
|
+
}
|
|
319
|
+
return h2("div", { class: "qz-status" }, [
|
|
320
|
+
h2("div", { class: "qz-status-item qz-status-position" }, [
|
|
321
|
+
h2("span", { class: "qz-status-label" }, props.positionLabel),
|
|
322
|
+
h2(
|
|
323
|
+
"span",
|
|
324
|
+
{ class: "qz-status-value" },
|
|
325
|
+
`#${status.value.position.toLocaleString()}`
|
|
326
|
+
)
|
|
327
|
+
]),
|
|
328
|
+
props.showScore && h2("div", { class: "qz-status-item qz-status-score" }, [
|
|
329
|
+
h2("span", { class: "qz-status-label" }, props.scoreLabel),
|
|
330
|
+
h2(
|
|
331
|
+
"span",
|
|
332
|
+
{ class: "qz-status-value" },
|
|
333
|
+
status.value.priorityScore.toLocaleString()
|
|
334
|
+
)
|
|
335
|
+
]),
|
|
336
|
+
props.showReferrals && h2("div", { class: "qz-status-item qz-status-referrals" }, [
|
|
337
|
+
h2("span", { class: "qz-status-label" }, props.referralsLabel),
|
|
338
|
+
h2(
|
|
339
|
+
"span",
|
|
340
|
+
{ class: "qz-status-value" },
|
|
341
|
+
status.value.referralCount.toLocaleString()
|
|
342
|
+
)
|
|
343
|
+
])
|
|
344
|
+
]);
|
|
345
|
+
};
|
|
346
|
+
}
|
|
347
|
+
});
|
|
348
|
+
|
|
349
|
+
// src/ReferralShare.ts
|
|
350
|
+
import { defineComponent as defineComponent3, ref as ref3, h as h3 } from "vue";
|
|
351
|
+
var ReferralShare = defineComponent3({
|
|
352
|
+
name: "ReferralShare",
|
|
353
|
+
props: {
|
|
354
|
+
label: {
|
|
355
|
+
type: String,
|
|
356
|
+
default: "Share your referral link:"
|
|
357
|
+
},
|
|
358
|
+
copyButtonText: {
|
|
359
|
+
type: String,
|
|
360
|
+
default: "Copy"
|
|
361
|
+
},
|
|
362
|
+
copiedText: {
|
|
363
|
+
type: String,
|
|
364
|
+
default: "Copied!"
|
|
365
|
+
},
|
|
366
|
+
shareMessage: {
|
|
367
|
+
type: String,
|
|
368
|
+
default: "Join me on the waitlist!"
|
|
369
|
+
},
|
|
370
|
+
showSocialButtons: {
|
|
371
|
+
type: Boolean,
|
|
372
|
+
default: false
|
|
373
|
+
}
|
|
374
|
+
},
|
|
375
|
+
emits: {
|
|
376
|
+
copy: (link) => true
|
|
377
|
+
},
|
|
378
|
+
setup(props, { emit, slots }) {
|
|
379
|
+
const { getReferralLink, getReferralCode, isJoined } = useWaitlistContext();
|
|
380
|
+
const copied = ref3(false);
|
|
381
|
+
async function handleCopy() {
|
|
382
|
+
const link = getReferralLink();
|
|
383
|
+
if (!link) return;
|
|
384
|
+
try {
|
|
385
|
+
await navigator.clipboard.writeText(link);
|
|
386
|
+
copied.value = true;
|
|
387
|
+
emit("copy", link);
|
|
388
|
+
setTimeout(() => copied.value = false, 2e3);
|
|
389
|
+
} catch {
|
|
390
|
+
const textarea = document.createElement("textarea");
|
|
391
|
+
textarea.value = link;
|
|
392
|
+
textarea.style.position = "fixed";
|
|
393
|
+
textarea.style.opacity = "0";
|
|
394
|
+
document.body.appendChild(textarea);
|
|
395
|
+
textarea.select();
|
|
396
|
+
document.execCommand("copy");
|
|
397
|
+
document.body.removeChild(textarea);
|
|
398
|
+
copied.value = true;
|
|
399
|
+
emit("copy", link);
|
|
400
|
+
setTimeout(() => copied.value = false, 2e3);
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
function handleTwitterShare() {
|
|
404
|
+
const link = getReferralLink();
|
|
405
|
+
if (!link) return;
|
|
406
|
+
const text = encodeURIComponent(`${props.shareMessage} ${link}`);
|
|
407
|
+
window.open(`https://twitter.com/intent/tweet?text=${text}`, "_blank", "noopener,noreferrer");
|
|
408
|
+
}
|
|
409
|
+
function handleLinkedInShare() {
|
|
410
|
+
const link = getReferralLink();
|
|
411
|
+
if (!link) return;
|
|
412
|
+
const url = encodeURIComponent(link);
|
|
413
|
+
window.open(
|
|
414
|
+
`https://www.linkedin.com/sharing/share-offsite/?url=${url}`,
|
|
415
|
+
"_blank",
|
|
416
|
+
"noopener,noreferrer"
|
|
417
|
+
);
|
|
418
|
+
}
|
|
419
|
+
function handleEmailShare() {
|
|
420
|
+
const link = getReferralLink();
|
|
421
|
+
if (!link) return;
|
|
422
|
+
const subject = encodeURIComponent("Join me on the waitlist!");
|
|
423
|
+
const body = encodeURIComponent(`${props.shareMessage}
|
|
424
|
+
|
|
425
|
+
${link}`);
|
|
426
|
+
window.location.href = `mailto:?subject=${subject}&body=${body}`;
|
|
427
|
+
}
|
|
428
|
+
return () => {
|
|
429
|
+
const link = getReferralLink();
|
|
430
|
+
const code = getReferralCode();
|
|
431
|
+
if (!isJoined.value || !link || !code) {
|
|
432
|
+
return null;
|
|
433
|
+
}
|
|
434
|
+
if (slots.default) {
|
|
435
|
+
return slots.default({
|
|
436
|
+
link,
|
|
437
|
+
code,
|
|
438
|
+
copy: handleCopy,
|
|
439
|
+
copied: copied.value
|
|
440
|
+
});
|
|
441
|
+
}
|
|
442
|
+
return h3("div", { class: "qz-share" }, [
|
|
443
|
+
props.label && h3("div", { class: "qz-share-label" }, props.label),
|
|
444
|
+
h3("div", { class: "qz-share-link-container" }, [
|
|
445
|
+
h3("input", {
|
|
446
|
+
type: "text",
|
|
447
|
+
value: link,
|
|
448
|
+
readonly: true,
|
|
449
|
+
class: "qz-share-input",
|
|
450
|
+
onClick: (e) => e.target.select()
|
|
451
|
+
}),
|
|
452
|
+
h3(
|
|
453
|
+
"button",
|
|
454
|
+
{
|
|
455
|
+
onClick: handleCopy,
|
|
456
|
+
class: "qz-share-copy-button"
|
|
457
|
+
},
|
|
458
|
+
copied.value ? props.copiedText : props.copyButtonText
|
|
459
|
+
)
|
|
460
|
+
]),
|
|
461
|
+
props.showSocialButtons && h3("div", { class: "qz-share-social" }, [
|
|
462
|
+
h3(
|
|
463
|
+
"button",
|
|
464
|
+
{
|
|
465
|
+
onClick: handleTwitterShare,
|
|
466
|
+
class: "qz-share-social-button qz-share-twitter",
|
|
467
|
+
"aria-label": "Share on Twitter"
|
|
468
|
+
},
|
|
469
|
+
h3(
|
|
470
|
+
"svg",
|
|
471
|
+
{ viewBox: "0 0 24 24", width: "20", height: "20", fill: "currentColor" },
|
|
472
|
+
h3("path", {
|
|
473
|
+
d: "M18.244 2.25h3.308l-7.227 8.26 8.502 11.24H16.17l-5.214-6.817L4.99 21.75H1.68l7.73-8.835L1.254 2.25H8.08l4.713 6.231zm-1.161 17.52h1.833L7.084 4.126H5.117z"
|
|
474
|
+
})
|
|
475
|
+
)
|
|
476
|
+
),
|
|
477
|
+
h3(
|
|
478
|
+
"button",
|
|
479
|
+
{
|
|
480
|
+
onClick: handleLinkedInShare,
|
|
481
|
+
class: "qz-share-social-button qz-share-linkedin",
|
|
482
|
+
"aria-label": "Share on LinkedIn"
|
|
483
|
+
},
|
|
484
|
+
h3(
|
|
485
|
+
"svg",
|
|
486
|
+
{ viewBox: "0 0 24 24", width: "20", height: "20", fill: "currentColor" },
|
|
487
|
+
h3("path", {
|
|
488
|
+
d: "M20.447 20.452h-3.554v-5.569c0-1.328-.027-3.037-1.852-3.037-1.853 0-2.136 1.445-2.136 2.939v5.667H9.351V9h3.414v1.561h.046c.477-.9 1.637-1.85 3.37-1.85 3.601 0 4.267 2.37 4.267 5.455v6.286zM5.337 7.433c-1.144 0-2.063-.926-2.063-2.065 0-1.138.92-2.063 2.063-2.063 1.14 0 2.064.925 2.064 2.063 0 1.139-.925 2.065-2.064 2.065zm1.782 13.019H3.555V9h3.564v11.452zM22.225 0H1.771C.792 0 0 .774 0 1.729v20.542C0 23.227.792 24 1.771 24h20.451C23.2 24 24 23.227 24 22.271V1.729C24 .774 23.2 0 22.222 0h.003z"
|
|
489
|
+
})
|
|
490
|
+
)
|
|
491
|
+
),
|
|
492
|
+
h3(
|
|
493
|
+
"button",
|
|
494
|
+
{
|
|
495
|
+
onClick: handleEmailShare,
|
|
496
|
+
class: "qz-share-social-button qz-share-email",
|
|
497
|
+
"aria-label": "Share via Email"
|
|
498
|
+
},
|
|
499
|
+
h3("svg", { viewBox: "0 0 24 24", width: "20", height: "20", fill: "currentColor" }, [
|
|
500
|
+
h3("path", {
|
|
501
|
+
d: "M1.5 8.67v8.58a3 3 0 003 3h15a3 3 0 003-3V8.67l-8.928 5.493a3 3 0 01-3.144 0L1.5 8.67z"
|
|
502
|
+
}),
|
|
503
|
+
h3("path", {
|
|
504
|
+
d: "M22.5 6.908V6.75a3 3 0 00-3-3h-15a3 3 0 00-3 3v.158l9.714 5.978a1.5 1.5 0 001.572 0L22.5 6.908z"
|
|
505
|
+
})
|
|
506
|
+
])
|
|
507
|
+
)
|
|
508
|
+
])
|
|
509
|
+
]);
|
|
510
|
+
};
|
|
511
|
+
}
|
|
512
|
+
});
|
|
513
|
+
|
|
514
|
+
// src/index.ts
|
|
515
|
+
import { QueueZeroClient as QueueZeroClient2, InMemoryStorageAdapter, LocalStorageAdapter } from "queuezero";
|
|
516
|
+
export {
|
|
517
|
+
InMemoryStorageAdapter,
|
|
518
|
+
LocalStorageAdapter,
|
|
519
|
+
QueueZeroClient2 as QueueZeroClient,
|
|
520
|
+
ReferralShare,
|
|
521
|
+
WAITLIST_INJECTION_KEY,
|
|
522
|
+
WaitlistForm,
|
|
523
|
+
WaitlistStatus,
|
|
524
|
+
createWaitlistPlugin,
|
|
525
|
+
provideWaitlist,
|
|
526
|
+
useWaitlist,
|
|
527
|
+
useWaitlistContext
|
|
528
|
+
};
|
package/package.json
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@queuezero/vue",
|
|
3
|
+
"version": "0.1.3",
|
|
4
|
+
"description": "Vue components and composables for QueueZero viral waitlists",
|
|
5
|
+
"main": "./dist/index.js",
|
|
6
|
+
"module": "./dist/index.mjs",
|
|
7
|
+
"types": "./dist/index.d.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"types": "./dist/index.d.ts",
|
|
11
|
+
"import": "./dist/index.mjs",
|
|
12
|
+
"require": "./dist/index.js"
|
|
13
|
+
}
|
|
14
|
+
},
|
|
15
|
+
"files": [
|
|
16
|
+
"dist",
|
|
17
|
+
"README.md"
|
|
18
|
+
],
|
|
19
|
+
"scripts": {
|
|
20
|
+
"build": "tsup src/index.ts --format cjs,esm --dts --clean --external vue",
|
|
21
|
+
"dev": "tsup src/index.ts --format cjs,esm --dts --watch --external vue",
|
|
22
|
+
"typecheck": "vue-tsc --noEmit"
|
|
23
|
+
},
|
|
24
|
+
"keywords": [
|
|
25
|
+
"waitlist",
|
|
26
|
+
"viral",
|
|
27
|
+
"referral",
|
|
28
|
+
"vue",
|
|
29
|
+
"composables"
|
|
30
|
+
],
|
|
31
|
+
"author": "QueueZero Team",
|
|
32
|
+
"license": "MIT",
|
|
33
|
+
"peerDependencies": {
|
|
34
|
+
"vue": ">=3.3.0"
|
|
35
|
+
},
|
|
36
|
+
"dependencies": {
|
|
37
|
+
"queuezero": "^0.1.2"
|
|
38
|
+
},
|
|
39
|
+
"devDependencies": {
|
|
40
|
+
"@types/node": "^22.13.11",
|
|
41
|
+
"tsup": "^8.4.0",
|
|
42
|
+
"typescript": "^5.8.2",
|
|
43
|
+
"vue": "^3.5.0",
|
|
44
|
+
"vue-tsc": "^2.2.0"
|
|
45
|
+
}
|
|
46
|
+
}
|