npm package: @queuezero/vue
Description: Vue components and composables for QueueZero viral waitlists
Author: QueueZero Team
Latest version: 0.1.12

# @queuezero/vue

Vue components and composables for QueueZero viral waitlists.

## Installation

```bash
npm install @queuezero/vue
```

## Quick Start

```vue
<script setup>
import { provideWaitlist, WaitlistForm, WaitlistStatus, ReferralShare } from '@queuezero/vue';

// Get referral code from URL if present
const referrerCode = new URLSearchParams(window.location.search).get('ref');

// Provide waitlist to all child components
provideWaitlist('my-campaign', { 
  apiUrl: 'https://api.queuezero.io' 
});
</script>

<template>
  <WaitlistForm 
    :referrer-code="referrerCode"
    @success="(res) => console.log('Joined!', res)"
  />
  <WaitlistStatus />
  <ReferralShare show-social-buttons />
</template>
```

## Plugin Usage

For app-wide integration:

```ts
import { createApp } from 'vue';
import { createWaitlistPlugin } from '@queuezero/vue';

const app = createApp(App);

app.use(createWaitlistPlugin({
  campaign: 'my-campaign',
  config: { apiUrl: 'https://api.queuezero.io' }
}));

app.mount('#app');
```

## Components

### WaitlistForm

Ready-to-use signup form.

```vue
<template>
  <!-- Basic -->
  <WaitlistForm />

  <!-- With options -->
  <WaitlistForm
    :referrer-code="referrerCode"
    :metadata="{ role: 'Developer' }"
    placeholder="Enter your work email"
    button-text="Get Early Access"
    @success="onSuccess"
    @error="onError"
  />

  <!-- With scoped slot -->
  <WaitlistForm v-slot="{ email, setEmail, submit, loading, error }">
    <input :value="email" @input="setEmail($event.target.value)" />
    <button @click="submit">{{ loading ? '...' : 'Join' }}</button>
  </WaitlistForm>

  <!-- Modal mode -->
  <WaitlistForm
    display-mode="modal"
    trigger-text="Join Our Waitlist"
    modal-size="md"
  <!-- Headless modal mode -->
  <WaitlistForm
    display-mode="modal"
    attach-to-text="Join Waitlist"
    modal-size="md"
  />
</template>
```

#### Modal Mode Props

| Prop | Type | Default | Description |
|------|------|---------|-------------|
| `display-mode` | `'inline' \| 'modal'` | `'inline'` | Display as inline form or modal |
| `trigger-text` | `string` | `'Join Waitlist'` | Button text (modal mode only) |
| `attach-to-text` | `string` | - | Text to match for auto-attaching modal (headless mode) |
| `modal-size` | `'sm' \| 'md' \| 'lg'` | `'md'` | Modal width (modal mode only) |

The modal automatically uses your campaign's branding (logo, cover image, theme color) from the API.

### WaitlistStatus

Displays position, score, and referral count.

```vue
<template>
  <!-- Basic -->
  <WaitlistStatus />

  <!-- With options -->
  <WaitlistStatus
    :show-score="true"
    :show-referrals="true"
    position-label="Your position:"
  />

  <!-- With scoped slot -->
  <WaitlistStatus v-slot="status">
    <h2>#{{ status.position }}</h2>
    <p>{{ status.priority_score }} points</p>
  </WaitlistStatus>
</template>
```

### ReferralShare

Share referral link with copy and social buttons.

```vue
<template>
  <!-- Basic -->
  <ReferralShare />

  <!-- With social buttons -->
  <ReferralShare 
    show-social-buttons 
    share-message="Join me on this awesome waitlist!" 
  />

  <!-- With scoped slot -->
  <ReferralShare v-slot="{ link, code, copy, copied }">
    <code>{{ code }}</code>
    <button @click="copy">{{ copied ? 'Copied!' : 'Copy' }}</button>
  </ReferralShare>
</template>
```

## Composables

### useWaitlist

Standalone composable for full control.

```vue
<script setup>
import { useWaitlist } from '@queuezero/vue';

const { status, loading, join, getReferralLink } = useWaitlist('my-campaign', {
  apiUrl: 'https://api.queuezero.io',
});

async function handleSubmit(email) {
  await join(email, { role: 'Developer' });
}
</script>
```

### provideWaitlist / useWaitlistContext

For component tree sharing.

```vue
<!-- Parent.vue -->
<script setup>
import { provideWaitlist } from '@queuezero/vue';

provideWaitlist('my-campaign');
</script>

<!-- Child.vue -->
<script setup>
import { useWaitlistContext } from '@queuezero/vue';

const { status, join } = useWaitlistContext();
</script>
```

## Styling

Components use `qz-*` class names:

```css
.qz-form { }
.qz-form-row { display: flex; gap: 8px; }
.qz-form-input { flex: 1; padding: 12px; }
.qz-form-button { padding: 12px 24px; }
.qz-form-error { color: red; }

.qz-status { display: flex; gap: 16px; }
.qz-status-label { font-size: 12px; }
.qz-status-value { font-size: 24px; font-weight: bold; }

.qz-share-input { flex: 1; }
.qz-share-social { display: flex; gap: 8px; }
```

## TypeScript

Full TypeScript support:

```ts
import type { 
  UseWaitlistReturn,
  WaitlistFormProps,
  UserStatus 
} from '@queuezero/vue';
```

## License

MIT