launchq-react 0.1.0
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/LICENSE +21 -0
- package/README.md +106 -0
- package/dist/index.d.mts +103 -0
- package/dist/index.d.ts +103 -0
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +2 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +56 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 LaunchQ
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
# launchq-react
|
|
2
|
+
|
|
3
|
+
Drop-in React component for [LaunchQ](https://launchq.co) waitlists. Native rendering, no iframe — works with Next.js, Vite, Remix, CRA, and any React app.
|
|
4
|
+
|
|
5
|
+
## Install
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install launchq-react
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Quick Start
|
|
12
|
+
|
|
13
|
+
Two lines — that's it:
|
|
14
|
+
|
|
15
|
+
```tsx
|
|
16
|
+
import { LaunchQWaitlist } from 'launchq-react'
|
|
17
|
+
|
|
18
|
+
function App() {
|
|
19
|
+
return <LaunchQWaitlist slug="my-waitlist" />
|
|
20
|
+
}
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
This fetches your waitlist config, renders the signup form with your dashboard settings (accent color, button text, headline), handles submission, and shows the success state with referral link + social share buttons.
|
|
24
|
+
|
|
25
|
+
## Props
|
|
26
|
+
|
|
27
|
+
| Prop | Type | Default | Description |
|
|
28
|
+
|------|------|---------|-------------|
|
|
29
|
+
| `slug` | `string` | **required** | Your waitlist slug from the LaunchQ dashboard |
|
|
30
|
+
| `baseUrl` | `string` | `'https://launchq.co'` | API base URL (for self-hosted or dev) |
|
|
31
|
+
| `referralCode` | `string` | auto from `?ref=` | Pre-filled referral code |
|
|
32
|
+
| `accentColor` | `string` | from dashboard | Override accent color |
|
|
33
|
+
| `theme` | `'dark' \| 'light'` | from dashboard | Color theme |
|
|
34
|
+
| `unstyled` | `boolean` | `false` | Strip all default styles |
|
|
35
|
+
| `buttonText` | `string` | from dashboard | Override button label |
|
|
36
|
+
| `placeholder` | `string` | `'Enter your email...'` | Input placeholder |
|
|
37
|
+
| `onSuccess` | `(result) => void` | — | Called after successful join |
|
|
38
|
+
| `onError` | `(error) => void` | — | Called on error |
|
|
39
|
+
| `className` | `string` | — | CSS class |
|
|
40
|
+
| `style` | `CSSProperties` | — | Inline styles |
|
|
41
|
+
| `children` | render function | — | Full UI control (see below) |
|
|
42
|
+
|
|
43
|
+
## Headless Mode (useWaitlist hook)
|
|
44
|
+
|
|
45
|
+
For complete control over the UI:
|
|
46
|
+
|
|
47
|
+
```tsx
|
|
48
|
+
import { useWaitlist } from 'launchq-react'
|
|
49
|
+
|
|
50
|
+
function CustomWaitlist() {
|
|
51
|
+
const { config, email, setEmail, submit, submitting, error, result } = useWaitlist({
|
|
52
|
+
slug: 'my-waitlist',
|
|
53
|
+
})
|
|
54
|
+
|
|
55
|
+
if (result) {
|
|
56
|
+
return <div>You're #{result.position}! Share: {result.referralLink}</div>
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
return (
|
|
60
|
+
<form onSubmit={(e) => { e.preventDefault(); submit(); }}>
|
|
61
|
+
<input value={email} onChange={(e) => setEmail(e.target.value)} />
|
|
62
|
+
<button disabled={submitting}>{submitting ? 'Joining...' : 'Join'}</button>
|
|
63
|
+
{error && <p>{error}</p>}
|
|
64
|
+
</form>
|
|
65
|
+
)
|
|
66
|
+
}
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
## Render Props
|
|
70
|
+
|
|
71
|
+
```tsx
|
|
72
|
+
<LaunchQWaitlist slug="my-waitlist">
|
|
73
|
+
{({ email, setEmail, submit, submitting, result }) => (
|
|
74
|
+
// Your custom JSX
|
|
75
|
+
)}
|
|
76
|
+
</LaunchQWaitlist>
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
## Provider (optional)
|
|
80
|
+
|
|
81
|
+
For multiple waitlists or custom API URL:
|
|
82
|
+
|
|
83
|
+
```tsx
|
|
84
|
+
import { LaunchQProvider, LaunchQWaitlist } from 'launchq-react'
|
|
85
|
+
|
|
86
|
+
<LaunchQProvider baseUrl="https://my-domain.com">
|
|
87
|
+
<LaunchQWaitlist slug="waitlist-1" />
|
|
88
|
+
<LaunchQWaitlist slug="waitlist-2" />
|
|
89
|
+
</LaunchQProvider>
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
## Optional CSS
|
|
93
|
+
|
|
94
|
+
Default styling uses inline styles (zero-config). For class-based styling:
|
|
95
|
+
|
|
96
|
+
```tsx
|
|
97
|
+
import 'launchq-react/styles.css'
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
Then use the `unstyled` prop and apply `.lq-*` classes to your custom markup via the render prop.
|
|
101
|
+
|
|
102
|
+
## Bundle
|
|
103
|
+
|
|
104
|
+
- **Zero runtime dependencies** — only `react` as peer dep
|
|
105
|
+
- **~9 KB** minified (ESM + CJS)
|
|
106
|
+
- Tree-shakeable (`sideEffects: false`)
|
package/dist/index.d.mts
ADDED
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
|
+
import * as react from 'react';
|
|
3
|
+
|
|
4
|
+
interface WaitlistConfig {
|
|
5
|
+
id: string;
|
|
6
|
+
name: string;
|
|
7
|
+
slug: string;
|
|
8
|
+
status: 'draft' | 'live' | 'paused' | 'closed';
|
|
9
|
+
totalSignups: number;
|
|
10
|
+
settings: {
|
|
11
|
+
headline: string;
|
|
12
|
+
subtext: string;
|
|
13
|
+
buttonText: string;
|
|
14
|
+
accentColor: string;
|
|
15
|
+
backgroundStyle: 'dark' | 'light' | 'gradient';
|
|
16
|
+
showPosition: boolean;
|
|
17
|
+
showReferralLink: boolean;
|
|
18
|
+
showBranding: boolean;
|
|
19
|
+
positionsPerReferral: number;
|
|
20
|
+
appName?: string;
|
|
21
|
+
appLogoUrl?: string;
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
interface JoinResult {
|
|
25
|
+
alreadyExists: boolean;
|
|
26
|
+
position: number;
|
|
27
|
+
referralCode: string;
|
|
28
|
+
}
|
|
29
|
+
interface WaitlistResult extends JoinResult {
|
|
30
|
+
referralLink: string;
|
|
31
|
+
}
|
|
32
|
+
interface LaunchQWaitlistProps {
|
|
33
|
+
/** Your waitlist slug (from the LaunchQ dashboard) */
|
|
34
|
+
slug: string;
|
|
35
|
+
/** API base URL — defaults to 'https://launchq.co' */
|
|
36
|
+
baseUrl?: string;
|
|
37
|
+
/** Pre-filled referral code. If omitted, reads ?ref= from the URL automatically */
|
|
38
|
+
referralCode?: string;
|
|
39
|
+
/** Override the accent color from your dashboard settings */
|
|
40
|
+
accentColor?: string;
|
|
41
|
+
/** Color theme — defaults to 'dark' */
|
|
42
|
+
theme?: 'dark' | 'light';
|
|
43
|
+
/** Strip all default styles for full custom CSS control */
|
|
44
|
+
unstyled?: boolean;
|
|
45
|
+
/** Called after a successful join */
|
|
46
|
+
onSuccess?: (data: WaitlistResult) => void;
|
|
47
|
+
/** Called on join error */
|
|
48
|
+
onError?: (error: Error) => void;
|
|
49
|
+
/** Override button text */
|
|
50
|
+
buttonText?: string;
|
|
51
|
+
/** Override input placeholder */
|
|
52
|
+
placeholder?: string;
|
|
53
|
+
/** Render prop for total UI control */
|
|
54
|
+
children?: (props: WaitlistRenderProps) => React.ReactNode;
|
|
55
|
+
/** Additional CSS class */
|
|
56
|
+
className?: string;
|
|
57
|
+
/** Inline styles */
|
|
58
|
+
style?: React.CSSProperties;
|
|
59
|
+
}
|
|
60
|
+
interface WaitlistRenderProps {
|
|
61
|
+
email: string;
|
|
62
|
+
setEmail: (email: string) => void;
|
|
63
|
+
submit: () => void;
|
|
64
|
+
submitting: boolean;
|
|
65
|
+
error: string | null;
|
|
66
|
+
result: WaitlistResult | null;
|
|
67
|
+
config: WaitlistConfig | null;
|
|
68
|
+
loading: boolean;
|
|
69
|
+
}
|
|
70
|
+
interface UseWaitlistOptions {
|
|
71
|
+
slug: string;
|
|
72
|
+
baseUrl?: string;
|
|
73
|
+
referralCode?: string;
|
|
74
|
+
onSuccess?: (data: WaitlistResult) => void;
|
|
75
|
+
onError?: (error: Error) => void;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
declare function LaunchQWaitlist(props: LaunchQWaitlistProps): react_jsx_runtime.JSX.Element | null;
|
|
79
|
+
|
|
80
|
+
declare function LaunchQProvider({ baseUrl, children, }: {
|
|
81
|
+
baseUrl: string;
|
|
82
|
+
children: React.ReactNode;
|
|
83
|
+
}): react_jsx_runtime.JSX.Element;
|
|
84
|
+
|
|
85
|
+
declare function useWaitlist(options: UseWaitlistOptions): {
|
|
86
|
+
config: WaitlistConfig | null;
|
|
87
|
+
loading: boolean;
|
|
88
|
+
email: string;
|
|
89
|
+
setEmail: react.Dispatch<react.SetStateAction<string>>;
|
|
90
|
+
submit: () => Promise<void>;
|
|
91
|
+
submitting: boolean;
|
|
92
|
+
error: string | null;
|
|
93
|
+
result: WaitlistResult | null;
|
|
94
|
+
};
|
|
95
|
+
|
|
96
|
+
declare function fetchWaitlistConfig(slug: string, baseUrl?: string): Promise<WaitlistConfig>;
|
|
97
|
+
declare function joinWaitlist(baseUrl: string | undefined, params: {
|
|
98
|
+
waitlistId: string;
|
|
99
|
+
email: string;
|
|
100
|
+
referredBy?: string;
|
|
101
|
+
}): Promise<JoinResult>;
|
|
102
|
+
|
|
103
|
+
export { type JoinResult, LaunchQProvider, LaunchQWaitlist, type LaunchQWaitlistProps, type UseWaitlistOptions, type WaitlistConfig, type WaitlistRenderProps, type WaitlistResult, fetchWaitlistConfig, joinWaitlist, useWaitlist };
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
|
+
import * as react from 'react';
|
|
3
|
+
|
|
4
|
+
interface WaitlistConfig {
|
|
5
|
+
id: string;
|
|
6
|
+
name: string;
|
|
7
|
+
slug: string;
|
|
8
|
+
status: 'draft' | 'live' | 'paused' | 'closed';
|
|
9
|
+
totalSignups: number;
|
|
10
|
+
settings: {
|
|
11
|
+
headline: string;
|
|
12
|
+
subtext: string;
|
|
13
|
+
buttonText: string;
|
|
14
|
+
accentColor: string;
|
|
15
|
+
backgroundStyle: 'dark' | 'light' | 'gradient';
|
|
16
|
+
showPosition: boolean;
|
|
17
|
+
showReferralLink: boolean;
|
|
18
|
+
showBranding: boolean;
|
|
19
|
+
positionsPerReferral: number;
|
|
20
|
+
appName?: string;
|
|
21
|
+
appLogoUrl?: string;
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
interface JoinResult {
|
|
25
|
+
alreadyExists: boolean;
|
|
26
|
+
position: number;
|
|
27
|
+
referralCode: string;
|
|
28
|
+
}
|
|
29
|
+
interface WaitlistResult extends JoinResult {
|
|
30
|
+
referralLink: string;
|
|
31
|
+
}
|
|
32
|
+
interface LaunchQWaitlistProps {
|
|
33
|
+
/** Your waitlist slug (from the LaunchQ dashboard) */
|
|
34
|
+
slug: string;
|
|
35
|
+
/** API base URL — defaults to 'https://launchq.co' */
|
|
36
|
+
baseUrl?: string;
|
|
37
|
+
/** Pre-filled referral code. If omitted, reads ?ref= from the URL automatically */
|
|
38
|
+
referralCode?: string;
|
|
39
|
+
/** Override the accent color from your dashboard settings */
|
|
40
|
+
accentColor?: string;
|
|
41
|
+
/** Color theme — defaults to 'dark' */
|
|
42
|
+
theme?: 'dark' | 'light';
|
|
43
|
+
/** Strip all default styles for full custom CSS control */
|
|
44
|
+
unstyled?: boolean;
|
|
45
|
+
/** Called after a successful join */
|
|
46
|
+
onSuccess?: (data: WaitlistResult) => void;
|
|
47
|
+
/** Called on join error */
|
|
48
|
+
onError?: (error: Error) => void;
|
|
49
|
+
/** Override button text */
|
|
50
|
+
buttonText?: string;
|
|
51
|
+
/** Override input placeholder */
|
|
52
|
+
placeholder?: string;
|
|
53
|
+
/** Render prop for total UI control */
|
|
54
|
+
children?: (props: WaitlistRenderProps) => React.ReactNode;
|
|
55
|
+
/** Additional CSS class */
|
|
56
|
+
className?: string;
|
|
57
|
+
/** Inline styles */
|
|
58
|
+
style?: React.CSSProperties;
|
|
59
|
+
}
|
|
60
|
+
interface WaitlistRenderProps {
|
|
61
|
+
email: string;
|
|
62
|
+
setEmail: (email: string) => void;
|
|
63
|
+
submit: () => void;
|
|
64
|
+
submitting: boolean;
|
|
65
|
+
error: string | null;
|
|
66
|
+
result: WaitlistResult | null;
|
|
67
|
+
config: WaitlistConfig | null;
|
|
68
|
+
loading: boolean;
|
|
69
|
+
}
|
|
70
|
+
interface UseWaitlistOptions {
|
|
71
|
+
slug: string;
|
|
72
|
+
baseUrl?: string;
|
|
73
|
+
referralCode?: string;
|
|
74
|
+
onSuccess?: (data: WaitlistResult) => void;
|
|
75
|
+
onError?: (error: Error) => void;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
declare function LaunchQWaitlist(props: LaunchQWaitlistProps): react_jsx_runtime.JSX.Element | null;
|
|
79
|
+
|
|
80
|
+
declare function LaunchQProvider({ baseUrl, children, }: {
|
|
81
|
+
baseUrl: string;
|
|
82
|
+
children: React.ReactNode;
|
|
83
|
+
}): react_jsx_runtime.JSX.Element;
|
|
84
|
+
|
|
85
|
+
declare function useWaitlist(options: UseWaitlistOptions): {
|
|
86
|
+
config: WaitlistConfig | null;
|
|
87
|
+
loading: boolean;
|
|
88
|
+
email: string;
|
|
89
|
+
setEmail: react.Dispatch<react.SetStateAction<string>>;
|
|
90
|
+
submit: () => Promise<void>;
|
|
91
|
+
submitting: boolean;
|
|
92
|
+
error: string | null;
|
|
93
|
+
result: WaitlistResult | null;
|
|
94
|
+
};
|
|
95
|
+
|
|
96
|
+
declare function fetchWaitlistConfig(slug: string, baseUrl?: string): Promise<WaitlistConfig>;
|
|
97
|
+
declare function joinWaitlist(baseUrl: string | undefined, params: {
|
|
98
|
+
waitlistId: string;
|
|
99
|
+
email: string;
|
|
100
|
+
referredBy?: string;
|
|
101
|
+
}): Promise<JoinResult>;
|
|
102
|
+
|
|
103
|
+
export { type JoinResult, LaunchQProvider, LaunchQWaitlist, type LaunchQWaitlistProps, type UseWaitlistOptions, type WaitlistConfig, type WaitlistRenderProps, type WaitlistResult, fetchWaitlistConfig, joinWaitlist, useWaitlist };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
"use strict";var T=Object.defineProperty;var D=Object.getOwnPropertyDescriptor;var J=Object.getOwnPropertyNames;var N=Object.prototype.hasOwnProperty;var O=(e,i)=>{for(var o in i)T(e,o,{get:i[o],enumerable:!0})},M=(e,i,o,n)=>{if(i&&typeof i=="object"||typeof i=="function")for(let a of J(i))!N.call(e,a)&&a!==o&&T(e,a,{get:()=>i[a],enumerable:!(n=D(i,a))||n.enumerable});return e};var Y=e=>M(T({},"__esModule",{value:!0}),e);var H={};O(H,{LaunchQProvider:()=>z,LaunchQWaitlist:()=>_,fetchWaitlistConfig:()=>W,joinWaitlist:()=>L,useWaitlist:()=>P});module.exports=Y(H);var S=require("react");var d=require("react");var Q="https://launchq.co";async function W(e,i=Q){let o=await fetch(`${i}/api/waitlist/${encodeURIComponent(e)}/config`);if(!o.ok)throw o.status===404?new Error(`Waitlist "${e}" not found`):new Error(`Failed to load waitlist config (${o.status})`);return o.json()}async function L(e=Q,i){var a,s;let o=await fetch(`${e}/api/subscriber/join`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(i)});if(!o.ok){let g=await o.json().catch(()=>({}));throw new Error(g.error||`Failed to join waitlist (${o.status})`)}let n=await o.json();return{alreadyExists:n.alreadyExists,position:(a=n.subscriber.position)!=null?a:1,referralCode:(s=n.subscriber.referralCode)!=null?s:""}}var G="https://launchq.co";function P(e){let{slug:i,baseUrl:o=G,onSuccess:n,onError:a}=e,[s,g]=(0,d.useState)(null),[h,f]=(0,d.useState)(!0),[p,u]=(0,d.useState)(""),[B,m]=(0,d.useState)(!1),[U,x]=(0,d.useState)(null),[C,w]=(0,d.useState)(null),[t,k]=(0,d.useState)(e.referralCode);(0,d.useEffect)(()=>{if(!e.referralCode&&typeof window!="undefined"){let l=new URLSearchParams(window.location.search).get("ref");l&&k(l)}},[e.referralCode]),(0,d.useEffect)(()=>{let c=!1;return f(!0),W(i,o).then(l=>{c||(g(l),f(!1))}).catch(l=>{c||(x(l instanceof Error?l.message:"Failed to load waitlist"),f(!1))}),()=>{c=!0}},[i,o]);let v=(0,d.useCallback)(async()=>{if(!(!s||!p.trim())){m(!0),x(null);try{let c=await L(o,{waitlistId:s.id,email:p.trim(),referredBy:t}),l=`${o}/w/${s.slug}?ref=${c.referralCode}`,b={...c,referralLink:l};w(b),n==null||n(b)}catch(c){let l=c instanceof Error?c:new Error("Something went wrong");x(l.message),a==null||a(l)}finally{m(!1)}}},[s,p,o,t,n,a]);return{config:s,loading:h,email:p,setEmail:u,submit:v,submitting:B,error:U,result:C}}var R=require("react"),F=require("react/jsx-runtime"),j=(0,R.createContext)({baseUrl:"https://launchq.co"});function z({baseUrl:e,children:i}){return(0,F.jsx)(j.Provider,{value:{baseUrl:e},children:i})}function A(){return(0,R.useContext)(j)}function E(e,i,o){return e==="light"?o:i}function q(e,i){let o=E(e,"#f0efe9","#111111"),n=E(e,"rgba(255,255,255,0.45)","rgba(0,0,0,0.45)"),a=E(e,"rgba(255,255,255,0.07)","rgba(0,0,0,0.04)"),s=E(e,"rgba(255,255,255,0.1)","rgba(0,0,0,0.1)");return{root:{width:"100%",fontFamily:"system-ui, -apple-system, sans-serif",color:o},form:{display:"flex",background:a,border:`1px solid ${s}`,borderRadius:"100px",padding:"6px",gap:"6px"},input:{flex:1,background:"none",border:"none",outline:"none",padding:"12px 18px",fontSize:"15px",color:o,minWidth:0},button:{background:i,color:"#0a0a0a",border:"none",borderRadius:"100px",padding:"12px 28px",fontSize:"15px",fontWeight:600,cursor:"pointer",whiteSpace:"nowrap",transition:"transform 0.2s, box-shadow 0.2s"},buttonDisabled:{opacity:.7,cursor:"not-allowed"},error:{marginTop:"12px",fontSize:"13px",color:"#f87171",textAlign:"center"},successIcon:{width:"52px",height:"52px",borderRadius:"50%",display:"flex",alignItems:"center",justifyContent:"center",margin:"0 auto 16px",background:`${i}1a`},successTitle:{fontSize:"24px",fontFamily:"Georgia, serif",fontWeight:400,letterSpacing:"-0.5px",marginBottom:"8px",textAlign:"center"},position:{fontSize:"14px",color:n,textAlign:"center",marginBottom:"20px"},positionStrong:{color:i,fontWeight:700},referralBox:{background:a,border:`1px solid ${s}`,borderRadius:"12px",padding:"14px 18px",marginBottom:"16px"},referralLabel:{fontSize:"11px",color:n,textTransform:"uppercase",letterSpacing:"0.08em",fontWeight:600,marginBottom:"8px"},referralRow:{display:"flex",gap:"8px",alignItems:"center"},referralLink:{flex:1,fontSize:"12px",color:o,overflow:"hidden",textOverflow:"ellipsis",whiteSpace:"nowrap",fontFamily:"monospace"},copyBtn:{background:i,color:"#0a0a0a",border:"none",borderRadius:"8px",padding:"7px 14px",fontSize:"12px",fontWeight:600,cursor:"pointer",whiteSpace:"nowrap"},shareRow:{display:"flex",gap:"10px",justifyContent:"center"},shareBtn:{display:"inline-flex",alignItems:"center",gap:"6px",background:a,border:`1px solid ${s}`,borderRadius:"8px",padding:"10px 16px",fontSize:"13px",color:o,textDecoration:"none",cursor:"pointer"},branding:{marginTop:"20px",fontSize:"12px",color:n,textAlign:"center"},brandingLink:{color:i,textDecoration:"none",fontWeight:500}}}var r=require("react/jsx-runtime");function V({color:e}){return(0,r.jsxs)("svg",{width:"24",height:"24",viewBox:"0 0 24 24",fill:"none",children:[(0,r.jsx)("path",{d:"M12 2a10 10 0 1 1 0 20 10 10 0 0 1 0-20z",fill:e,opacity:.2}),(0,r.jsx)("path",{d:"M8 12l2.5 2.5L16 9",stroke:e,strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round"})]})}function X({color:e}){return(0,r.jsxs)("svg",{width:"24",height:"24",viewBox:"0 0 24 24",fill:"none",children:[(0,r.jsx)("circle",{cx:"12",cy:"8",r:"4",stroke:e,strokeWidth:"1.5"}),(0,r.jsx)("path",{d:"M5 20c0-3.5 3.1-6 7-6s7 2.5 7 6",stroke:e,strokeWidth:"1.5",strokeLinecap:"round"})]})}function _(e){var k,v,c,l,b,$,I;let i=A(),o=(k=e.baseUrl)!=null?k:i.baseUrl,{config:n,loading:a,email:s,setEmail:g,submit:h,submitting:f,error:p,result:u}=P({slug:e.slug,baseUrl:o,referralCode:e.referralCode,onSuccess:e.onSuccess,onError:e.onError}),[B,m]=(0,S.useState)(!1),U=(0,S.useCallback)(y=>{typeof navigator!="undefined"&&navigator.clipboard&&navigator.clipboard.writeText(y).catch(()=>{}),m(!0),setTimeout(()=>m(!1),2e3)},[]),x=(0,S.useCallback)(y=>{y.preventDefault(),h()},[h]);if(e.children)return(0,r.jsx)(r.Fragment,{children:e.children({email:s,setEmail:g,submit:h,submitting:f,error:p,result:u,config:n,loading:a})});if(a||!n)return null;let C=(v=e.theme)!=null?v:n.settings.backgroundStyle==="light"?"light":"dark",w=(l=(c=e.accentColor)!=null?c:n.settings.accentColor)!=null?l:"#e8ff5a",t=e.unstyled?void 0:q(C,w);return u?(0,r.jsxs)("div",{className:e.className,style:e.unstyled?e.style:{...t.root,...e.style},"data-launchq-result":!0,children:[(0,r.jsx)("div",{style:t==null?void 0:t.successIcon,children:u.alreadyExists?(0,r.jsx)(X,{color:C==="light"?"rgba(0,0,0,0.4)":"rgba(255,255,255,0.4)"}):(0,r.jsx)(V,{color:w})}),(0,r.jsx)("div",{style:t==null?void 0:t.successTitle,children:u.alreadyExists?"You're already on the list!":"You're on the list!"}),n.settings.showPosition&&!u.alreadyExists&&(0,r.jsxs)("p",{style:t==null?void 0:t.position,children:["You're ",(0,r.jsxs)("strong",{style:t==null?void 0:t.positionStrong,children:["#",u.position]})," on the waitlist"]}),n.settings.showReferralLink&&(0,r.jsxs)("div",{style:t==null?void 0:t.referralBox,children:[(0,r.jsx)("p",{style:t==null?void 0:t.referralLabel,children:"Share to move up"}),(0,r.jsxs)("div",{style:t==null?void 0:t.referralRow,children:[(0,r.jsx)("code",{style:t==null?void 0:t.referralLink,children:u.referralLink}),(0,r.jsx)("button",{onClick:()=>U(u.referralLink),style:t==null?void 0:t.copyBtn,children:B?"Copied!":"Copy"})]})]}),(0,r.jsxs)("div",{style:t==null?void 0:t.shareRow,children:[(0,r.jsx)("a",{href:`https://twitter.com/intent/tweet?text=${encodeURIComponent(`I just joined the waitlist for ${n.name}! Get early access:`)}&url=${encodeURIComponent(u.referralLink)}`,target:"_blank",rel:"noopener noreferrer",style:t==null?void 0:t.shareBtn,children:"Share on X"}),(0,r.jsx)("a",{href:`https://www.linkedin.com/sharing/share-offsite/?url=${encodeURIComponent(u.referralLink)}`,target:"_blank",rel:"noopener noreferrer",style:t==null?void 0:t.shareBtn,children:"Share on LinkedIn"})]}),n.settings.showBranding&&(0,r.jsxs)("p",{style:t==null?void 0:t.branding,children:["Powered by"," ",(0,r.jsx)("a",{href:"https://launchq.co",target:"_blank",rel:"noopener noreferrer",style:t==null?void 0:t.brandingLink,children:"LaunchQ"})]})]}):(0,r.jsxs)("div",{className:e.className,style:e.unstyled?e.style:{...t.root,...e.style},"data-launchq-form":!0,children:[n.status==="live"?(0,r.jsxs)("form",{onSubmit:x,style:t==null?void 0:t.form,children:[(0,r.jsx)("input",{type:"email",value:s,onChange:y=>g(y.target.value),placeholder:(b=e.placeholder)!=null?b:"Enter your email...",required:!0,style:t==null?void 0:t.input}),(0,r.jsx)("button",{type:"submit",disabled:f,style:f?{...t==null?void 0:t.button,...t==null?void 0:t.buttonDisabled}:t==null?void 0:t.button,children:f?"Joining...":(I=($=e.buttonText)!=null?$:n.settings.buttonText)!=null?I:"Join Waitlist"})]}):(0,r.jsxs)("div",{style:{textAlign:"center",fontSize:"14px",color:"rgba(255,255,255,0.45)"},children:["This waitlist is currently ",n.status,"."]}),p&&(0,r.jsx)("div",{style:t==null?void 0:t.error,children:p}),n.settings.showBranding&&(0,r.jsxs)("p",{style:t==null?void 0:t.branding,children:["Powered by"," ",(0,r.jsx)("a",{href:"https://launchq.co",target:"_blank",rel:"noopener noreferrer",style:t==null?void 0:t.brandingLink,children:"LaunchQ"})]})]})}0&&(module.exports={LaunchQProvider,LaunchQWaitlist,fetchWaitlistConfig,joinWaitlist,useWaitlist});
|
|
2
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/LaunchQWaitlist.tsx","../src/useWaitlist.ts","../src/api.ts","../src/LaunchQProvider.tsx","../src/styles.ts"],"sourcesContent":["export { LaunchQWaitlist } from './LaunchQWaitlist';\nexport { LaunchQProvider } from './LaunchQProvider';\nexport { useWaitlist } from './useWaitlist';\nexport { fetchWaitlistConfig, joinWaitlist } from './api';\nexport type {\n LaunchQWaitlistProps,\n WaitlistConfig,\n WaitlistResult,\n JoinResult,\n WaitlistRenderProps,\n UseWaitlistOptions,\n} from './types';\n","import { useState, useCallback } from 'react';\nimport { useWaitlist } from './useWaitlist';\nimport { useLaunchQContext } from './LaunchQProvider';\nimport { getStyles } from './styles';\nimport type { LaunchQWaitlistProps } from './types';\n\n// Inline SVG icons (no external dependency)\nfunction CheckIcon({ color }: { color: string }) {\n return (\n <svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\">\n <path d=\"M12 2a10 10 0 1 1 0 20 10 10 0 0 1 0-20z\" fill={color} opacity={0.2} />\n <path d=\"M8 12l2.5 2.5L16 9\" stroke={color} strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\" />\n </svg>\n );\n}\n\nfunction UserIcon({ color }: { color: string }) {\n return (\n <svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\">\n <circle cx=\"12\" cy=\"8\" r=\"4\" stroke={color} strokeWidth=\"1.5\" />\n <path d=\"M5 20c0-3.5 3.1-6 7-6s7 2.5 7 6\" stroke={color} strokeWidth=\"1.5\" strokeLinecap=\"round\" />\n </svg>\n );\n}\n\nexport function LaunchQWaitlist(props: LaunchQWaitlistProps) {\n const ctx = useLaunchQContext();\n const resolvedBaseUrl = props.baseUrl ?? ctx.baseUrl;\n\n const {\n config,\n loading,\n email,\n setEmail,\n submit,\n submitting,\n error,\n result,\n } = useWaitlist({\n slug: props.slug,\n baseUrl: resolvedBaseUrl,\n referralCode: props.referralCode,\n onSuccess: props.onSuccess,\n onError: props.onError,\n });\n\n const [copied, setCopied] = useState(false);\n\n const handleCopy = useCallback((text: string) => {\n if (typeof navigator !== 'undefined' && navigator.clipboard) {\n navigator.clipboard.writeText(text).catch(() => {});\n }\n setCopied(true);\n setTimeout(() => setCopied(false), 2000);\n }, []);\n\n const handleSubmit = useCallback((e: React.FormEvent) => {\n e.preventDefault();\n submit();\n }, [submit]);\n\n // Render prop mode\n if (props.children) {\n return (\n <>{props.children({ email, setEmail, submit, submitting, error, result, config, loading })}</>\n );\n }\n\n // Don't render anything while loading\n if (loading || !config) return null;\n\n const theme = props.theme ?? (config.settings.backgroundStyle === 'light' ? 'light' : 'dark');\n const accent = props.accentColor ?? config.settings.accentColor ?? '#e8ff5a';\n const s = props.unstyled ? undefined : getStyles(theme, accent);\n\n // Success state\n if (result) {\n return (\n <div\n className={props.className}\n style={props.unstyled ? props.style : { ...s!.root, ...props.style }}\n data-launchq-result\n >\n <div style={s?.successIcon}>\n {result.alreadyExists\n ? <UserIcon color={theme === 'light' ? 'rgba(0,0,0,0.4)' : 'rgba(255,255,255,0.4)'} />\n : <CheckIcon color={accent} />}\n </div>\n <div style={s?.successTitle}>\n {result.alreadyExists ? \"You're already on the list!\" : \"You're on the list!\"}\n </div>\n {config.settings.showPosition && !result.alreadyExists && (\n <p style={s?.position}>\n You're <strong style={s?.positionStrong}>#{result.position}</strong> on the waitlist\n </p>\n )}\n {config.settings.showReferralLink && (\n <div style={s?.referralBox}>\n <p style={s?.referralLabel}>Share to move up</p>\n <div style={s?.referralRow}>\n <code style={s?.referralLink}>{result.referralLink}</code>\n <button onClick={() => handleCopy(result.referralLink)} style={s?.copyBtn}>\n {copied ? 'Copied!' : 'Copy'}\n </button>\n </div>\n </div>\n )}\n <div style={s?.shareRow}>\n <a\n href={`https://twitter.com/intent/tweet?text=${encodeURIComponent(`I just joined the waitlist for ${config.name}! Get early access:`)}&url=${encodeURIComponent(result.referralLink)}`}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n style={s?.shareBtn}\n >\n Share on X\n </a>\n <a\n href={`https://www.linkedin.com/sharing/share-offsite/?url=${encodeURIComponent(result.referralLink)}`}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n style={s?.shareBtn}\n >\n Share on LinkedIn\n </a>\n </div>\n {config.settings.showBranding && (\n <p style={s?.branding}>\n Powered by{' '}\n <a href=\"https://launchq.co\" target=\"_blank\" rel=\"noopener noreferrer\" style={s?.brandingLink}>\n LaunchQ\n </a>\n </p>\n )}\n </div>\n );\n }\n\n // Form state\n return (\n <div\n className={props.className}\n style={props.unstyled ? props.style : { ...s!.root, ...props.style }}\n data-launchq-form\n >\n {config.status === 'live' ? (\n <form onSubmit={handleSubmit} style={s?.form}>\n <input\n type=\"email\"\n value={email}\n onChange={(e) => setEmail(e.target.value)}\n placeholder={props.placeholder ?? 'Enter your email...'}\n required\n style={s?.input}\n />\n <button\n type=\"submit\"\n disabled={submitting}\n style={submitting ? { ...s?.button, ...s?.buttonDisabled } : s?.button}\n >\n {submitting ? 'Joining...' : (props.buttonText ?? config.settings.buttonText ?? 'Join Waitlist')}\n </button>\n </form>\n ) : (\n <div style={{ textAlign: 'center', fontSize: '14px', color: 'rgba(255,255,255,0.45)' }}>\n This waitlist is currently {config.status}.\n </div>\n )}\n {error && <div style={s?.error}>{error}</div>}\n {config.settings.showBranding && (\n <p style={s?.branding}>\n Powered by{' '}\n <a href=\"https://launchq.co\" target=\"_blank\" rel=\"noopener noreferrer\" style={s?.brandingLink}>\n LaunchQ\n </a>\n </p>\n )}\n </div>\n );\n}\n","import { useState, useEffect, useCallback } from 'react';\nimport { fetchWaitlistConfig, joinWaitlist } from './api';\nimport type { WaitlistConfig, WaitlistResult, UseWaitlistOptions } from './types';\n\nconst DEFAULT_BASE_URL = 'https://launchq.co';\n\nexport function useWaitlist(options: UseWaitlistOptions) {\n const { slug, baseUrl = DEFAULT_BASE_URL, onSuccess, onError } = options;\n\n const [config, setConfig] = useState<WaitlistConfig | null>(null);\n const [loading, setLoading] = useState(true);\n const [email, setEmail] = useState('');\n const [submitting, setSubmitting] = useState(false);\n const [error, setError] = useState<string | null>(null);\n const [result, setResult] = useState<WaitlistResult | null>(null);\n\n // Read ?ref= from URL if no referralCode prop\n const [refCode, setRefCode] = useState<string | undefined>(options.referralCode);\n\n useEffect(() => {\n if (!options.referralCode && typeof window !== 'undefined') {\n const params = new URLSearchParams(window.location.search);\n const ref = params.get('ref');\n if (ref) setRefCode(ref);\n }\n }, [options.referralCode]);\n\n // Fetch waitlist config\n useEffect(() => {\n let cancelled = false;\n setLoading(true);\n fetchWaitlistConfig(slug, baseUrl)\n .then((cfg) => {\n if (!cancelled) {\n setConfig(cfg);\n setLoading(false);\n }\n })\n .catch((err) => {\n if (!cancelled) {\n setError(err instanceof Error ? err.message : 'Failed to load waitlist');\n setLoading(false);\n }\n });\n return () => { cancelled = true; };\n }, [slug, baseUrl]);\n\n const submit = useCallback(async () => {\n if (!config || !email.trim()) return;\n setSubmitting(true);\n setError(null);\n try {\n const joinResult = await joinWaitlist(baseUrl, {\n waitlistId: config.id,\n email: email.trim(),\n referredBy: refCode,\n });\n\n const referralLink = `${baseUrl}/w/${config.slug}?ref=${joinResult.referralCode}`;\n const waitlistResult: WaitlistResult = { ...joinResult, referralLink };\n\n setResult(waitlistResult);\n onSuccess?.(waitlistResult);\n } catch (err) {\n const error = err instanceof Error ? err : new Error('Something went wrong');\n setError(error.message);\n onError?.(error);\n } finally {\n setSubmitting(false);\n }\n }, [config, email, baseUrl, refCode, onSuccess, onError]);\n\n return {\n config,\n loading,\n email,\n setEmail,\n submit,\n submitting,\n error,\n result,\n };\n}\n","import type { WaitlistConfig, JoinResult } from './types';\n\nconst DEFAULT_BASE_URL = 'https://launchq.co';\n\nexport async function fetchWaitlistConfig(\n slug: string,\n baseUrl = DEFAULT_BASE_URL\n): Promise<WaitlistConfig> {\n const res = await fetch(`${baseUrl}/api/waitlist/${encodeURIComponent(slug)}/config`);\n if (!res.ok) {\n if (res.status === 404) throw new Error(`Waitlist \"${slug}\" not found`);\n throw new Error(`Failed to load waitlist config (${res.status})`);\n }\n return res.json() as Promise<WaitlistConfig>;\n}\n\nexport async function joinWaitlist(\n baseUrl = DEFAULT_BASE_URL,\n params: { waitlistId: string; email: string; referredBy?: string }\n): Promise<JoinResult> {\n const res = await fetch(`${baseUrl}/api/subscriber/join`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify(params),\n });\n\n if (!res.ok) {\n const body = await res.json().catch(() => ({})) as { error?: string };\n throw new Error(body.error || `Failed to join waitlist (${res.status})`);\n }\n\n const data = await res.json() as {\n alreadyExists: boolean;\n subscriber: { position?: number; referralCode?: string };\n };\n\n return {\n alreadyExists: data.alreadyExists,\n position: data.subscriber.position ?? 1,\n referralCode: data.subscriber.referralCode ?? '',\n };\n}\n","import { createContext, useContext } from 'react';\n\ninterface LaunchQContextValue {\n baseUrl: string;\n}\n\nconst LaunchQContext = createContext<LaunchQContextValue>({\n baseUrl: 'https://launchq.co',\n});\n\nexport function LaunchQProvider({\n baseUrl,\n children,\n}: {\n baseUrl: string;\n children: React.ReactNode;\n}) {\n return (\n <LaunchQContext.Provider value={{ baseUrl }}>\n {children}\n </LaunchQContext.Provider>\n );\n}\n\nexport function useLaunchQContext() {\n return useContext(LaunchQContext);\n}\n","import type { CSSProperties } from 'react';\n\ntype Theme = 'dark' | 'light';\n\nfunction t(theme: Theme, dark: string, light: string) {\n return theme === 'light' ? light : dark;\n}\n\nexport function getStyles(theme: Theme, accent: string) {\n const textColor = t(theme, '#f0efe9', '#111111');\n const subColor = t(theme, 'rgba(255,255,255,0.45)', 'rgba(0,0,0,0.45)');\n const fieldBg = t(theme, 'rgba(255,255,255,0.07)', 'rgba(0,0,0,0.04)');\n const fieldBorder = t(theme, 'rgba(255,255,255,0.1)', 'rgba(0,0,0,0.1)');\n\n return {\n root: {\n width: '100%',\n fontFamily: 'system-ui, -apple-system, sans-serif',\n color: textColor,\n } as CSSProperties,\n\n form: {\n display: 'flex',\n background: fieldBg,\n border: `1px solid ${fieldBorder}`,\n borderRadius: '100px',\n padding: '6px',\n gap: '6px',\n } as CSSProperties,\n\n input: {\n flex: 1,\n background: 'none',\n border: 'none',\n outline: 'none',\n padding: '12px 18px',\n fontSize: '15px',\n color: textColor,\n minWidth: 0,\n } as CSSProperties,\n\n button: {\n background: accent,\n color: '#0a0a0a',\n border: 'none',\n borderRadius: '100px',\n padding: '12px 28px',\n fontSize: '15px',\n fontWeight: 600,\n cursor: 'pointer',\n whiteSpace: 'nowrap' as const,\n transition: 'transform 0.2s, box-shadow 0.2s',\n } as CSSProperties,\n\n buttonDisabled: {\n opacity: 0.7,\n cursor: 'not-allowed',\n } as CSSProperties,\n\n error: {\n marginTop: '12px',\n fontSize: '13px',\n color: '#f87171',\n textAlign: 'center' as const,\n } as CSSProperties,\n\n successIcon: {\n width: '52px',\n height: '52px',\n borderRadius: '50%',\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n margin: '0 auto 16px',\n background: `${accent}1a`,\n } as CSSProperties,\n\n successTitle: {\n fontSize: '24px',\n fontFamily: 'Georgia, serif',\n fontWeight: 400,\n letterSpacing: '-0.5px',\n marginBottom: '8px',\n textAlign: 'center' as const,\n } as CSSProperties,\n\n position: {\n fontSize: '14px',\n color: subColor,\n textAlign: 'center' as const,\n marginBottom: '20px',\n } as CSSProperties,\n\n positionStrong: {\n color: accent,\n fontWeight: 700,\n } as CSSProperties,\n\n referralBox: {\n background: fieldBg,\n border: `1px solid ${fieldBorder}`,\n borderRadius: '12px',\n padding: '14px 18px',\n marginBottom: '16px',\n } as CSSProperties,\n\n referralLabel: {\n fontSize: '11px',\n color: subColor,\n textTransform: 'uppercase' as const,\n letterSpacing: '0.08em',\n fontWeight: 600,\n marginBottom: '8px',\n } as CSSProperties,\n\n referralRow: {\n display: 'flex',\n gap: '8px',\n alignItems: 'center',\n } as CSSProperties,\n\n referralLink: {\n flex: 1,\n fontSize: '12px',\n color: textColor,\n overflow: 'hidden',\n textOverflow: 'ellipsis',\n whiteSpace: 'nowrap' as const,\n fontFamily: 'monospace',\n } as CSSProperties,\n\n copyBtn: {\n background: accent,\n color: '#0a0a0a',\n border: 'none',\n borderRadius: '8px',\n padding: '7px 14px',\n fontSize: '12px',\n fontWeight: 600,\n cursor: 'pointer',\n whiteSpace: 'nowrap' as const,\n } as CSSProperties,\n\n shareRow: {\n display: 'flex',\n gap: '10px',\n justifyContent: 'center',\n } as CSSProperties,\n\n shareBtn: {\n display: 'inline-flex',\n alignItems: 'center',\n gap: '6px',\n background: fieldBg,\n border: `1px solid ${fieldBorder}`,\n borderRadius: '8px',\n padding: '10px 16px',\n fontSize: '13px',\n color: textColor,\n textDecoration: 'none',\n cursor: 'pointer',\n } as CSSProperties,\n\n branding: {\n marginTop: '20px',\n fontSize: '12px',\n color: subColor,\n textAlign: 'center' as const,\n } as CSSProperties,\n\n brandingLink: {\n color: accent,\n textDecoration: 'none',\n fontWeight: 500,\n } as CSSProperties,\n };\n}\n"],"mappings":"yaAAA,IAAAA,EAAA,GAAAC,EAAAD,EAAA,qBAAAE,EAAA,oBAAAC,EAAA,wBAAAC,EAAA,iBAAAC,EAAA,gBAAAC,IAAA,eAAAC,EAAAP,GCAA,IAAAQ,EAAsC,iBCAtC,IAAAC,EAAiD,iBCEjD,IAAMC,EAAmB,qBAEzB,eAAsBC,EACpBC,EACAC,EAAUH,EACe,CACzB,IAAMI,EAAM,MAAM,MAAM,GAAGD,CAAO,iBAAiB,mBAAmBD,CAAI,CAAC,SAAS,EACpF,GAAI,CAACE,EAAI,GACP,MAAIA,EAAI,SAAW,IAAW,IAAI,MAAM,aAAaF,CAAI,aAAa,EAChE,IAAI,MAAM,mCAAmCE,EAAI,MAAM,GAAG,EAElE,OAAOA,EAAI,KAAK,CAClB,CAEA,eAAsBC,EACpBF,EAAUH,EACVM,EACqB,CAnBvB,IAAAC,EAAAC,EAoBE,IAAMJ,EAAM,MAAM,MAAM,GAAGD,CAAO,uBAAwB,CACxD,OAAQ,OACR,QAAS,CAAE,eAAgB,kBAAmB,EAC9C,KAAM,KAAK,UAAUG,CAAM,CAC7B,CAAC,EAED,GAAI,CAACF,EAAI,GAAI,CACX,IAAMK,EAAO,MAAML,EAAI,KAAK,EAAE,MAAM,KAAO,CAAC,EAAE,EAC9C,MAAM,IAAI,MAAMK,EAAK,OAAS,4BAA4BL,EAAI,MAAM,GAAG,CACzE,CAEA,IAAMM,EAAO,MAAMN,EAAI,KAAK,EAK5B,MAAO,CACL,cAAeM,EAAK,cACpB,UAAUH,EAAAG,EAAK,WAAW,WAAhB,KAAAH,EAA4B,EACtC,cAAcC,EAAAE,EAAK,WAAW,eAAhB,KAAAF,EAAgC,EAChD,CACF,CDrCA,IAAMG,EAAmB,qBAElB,SAASC,EAAYC,EAA6B,CACvD,GAAM,CAAE,KAAAC,EAAM,QAAAC,EAAUJ,EAAkB,UAAAK,EAAW,QAAAC,CAAQ,EAAIJ,EAE3D,CAACK,EAAQC,CAAS,KAAI,YAAgC,IAAI,EAC1D,CAACC,EAASC,CAAU,KAAI,YAAS,EAAI,EACrC,CAACC,EAAOC,CAAQ,KAAI,YAAS,EAAE,EAC/B,CAACC,EAAYC,CAAa,KAAI,YAAS,EAAK,EAC5C,CAACC,EAAOC,CAAQ,KAAI,YAAwB,IAAI,EAChD,CAACC,EAAQC,CAAS,KAAI,YAAgC,IAAI,EAG1D,CAACC,EAASC,CAAU,KAAI,YAA6BlB,EAAQ,YAAY,KAE/E,aAAU,IAAM,CACd,GAAI,CAACA,EAAQ,cAAgB,OAAO,QAAW,YAAa,CAE1D,IAAMmB,EADS,IAAI,gBAAgB,OAAO,SAAS,MAAM,EACtC,IAAI,KAAK,EACxBA,GAAKD,EAAWC,CAAG,CACzB,CACF,EAAG,CAACnB,EAAQ,YAAY,CAAC,KAGzB,aAAU,IAAM,CACd,IAAIoB,EAAY,GAChB,OAAAZ,EAAW,EAAI,EACfa,EAAoBpB,EAAMC,CAAO,EAC9B,KAAMoB,GAAQ,CACRF,IACHd,EAAUgB,CAAG,EACbd,EAAW,EAAK,EAEpB,CAAC,EACA,MAAOe,GAAQ,CACTH,IACHN,EAASS,aAAe,MAAQA,EAAI,QAAU,yBAAyB,EACvEf,EAAW,EAAK,EAEpB,CAAC,EACI,IAAM,CAAEY,EAAY,EAAM,CACnC,EAAG,CAACnB,EAAMC,CAAO,CAAC,EAElB,IAAMsB,KAAS,eAAY,SAAY,CACrC,GAAI,GAACnB,GAAU,CAACI,EAAM,KAAK,GAC3B,CAAAG,EAAc,EAAI,EAClBE,EAAS,IAAI,EACb,GAAI,CACF,IAAMW,EAAa,MAAMC,EAAaxB,EAAS,CAC7C,WAAYG,EAAO,GACnB,MAAOI,EAAM,KAAK,EAClB,WAAYQ,CACd,CAAC,EAEKU,EAAe,GAAGzB,CAAO,MAAMG,EAAO,IAAI,QAAQoB,EAAW,YAAY,GACzEG,EAAiC,CAAE,GAAGH,EAAY,aAAAE,CAAa,EAErEX,EAAUY,CAAc,EACxBzB,GAAA,MAAAA,EAAYyB,EACd,OAASL,EAAK,CACZ,IAAMV,EAAQU,aAAe,MAAQA,EAAM,IAAI,MAAM,sBAAsB,EAC3ET,EAASD,EAAM,OAAO,EACtBT,GAAA,MAAAA,EAAUS,EACZ,QAAE,CACAD,EAAc,EAAK,CACrB,EACF,EAAG,CAACP,EAAQI,EAAOP,EAASe,EAASd,EAAWC,CAAO,CAAC,EAExD,MAAO,CACL,OAAAC,EACA,QAAAE,EACA,MAAAE,EACA,SAAAC,EACA,OAAAc,EACA,WAAAb,EACA,MAAAE,EACA,OAAAE,CACF,CACF,CElFA,IAAAc,EAA0C,iBAkBtCC,EAAA,6BAZEC,KAAiB,iBAAmC,CACxD,QAAS,oBACX,CAAC,EAEM,SAASC,EAAgB,CAC9B,QAAAC,EACA,SAAAC,CACF,EAGG,CACD,SACE,OAACH,EAAe,SAAf,CAAwB,MAAO,CAAE,QAAAE,CAAQ,EACvC,SAAAC,EACH,CAEJ,CAEO,SAASC,GAAoB,CAClC,SAAO,cAAWJ,CAAc,CAClC,CCtBA,SAASK,EAAEC,EAAcC,EAAcC,EAAe,CACpD,OAAOF,IAAU,QAAUE,EAAQD,CACrC,CAEO,SAASE,EAAUH,EAAcI,EAAgB,CACtD,IAAMC,EAAYN,EAAEC,EAAO,UAAW,SAAS,EACzCM,EAAWP,EAAEC,EAAO,yBAA0B,kBAAkB,EAChEO,EAAUR,EAAEC,EAAO,yBAA0B,kBAAkB,EAC/DQ,EAAcT,EAAEC,EAAO,wBAAyB,iBAAiB,EAEvE,MAAO,CACL,KAAM,CACJ,MAAO,OACP,WAAY,uCACZ,MAAOK,CACT,EAEA,KAAM,CACJ,QAAS,OACT,WAAYE,EACZ,OAAQ,aAAaC,CAAW,GAChC,aAAc,QACd,QAAS,MACT,IAAK,KACP,EAEA,MAAO,CACL,KAAM,EACN,WAAY,OACZ,OAAQ,OACR,QAAS,OACT,QAAS,YACT,SAAU,OACV,MAAOH,EACP,SAAU,CACZ,EAEA,OAAQ,CACN,WAAYD,EACZ,MAAO,UACP,OAAQ,OACR,aAAc,QACd,QAAS,YACT,SAAU,OACV,WAAY,IACZ,OAAQ,UACR,WAAY,SACZ,WAAY,iCACd,EAEA,eAAgB,CACd,QAAS,GACT,OAAQ,aACV,EAEA,MAAO,CACL,UAAW,OACX,SAAU,OACV,MAAO,UACP,UAAW,QACb,EAEA,YAAa,CACX,MAAO,OACP,OAAQ,OACR,aAAc,MACd,QAAS,OACT,WAAY,SACZ,eAAgB,SAChB,OAAQ,cACR,WAAY,GAAGA,CAAM,IACvB,EAEA,aAAc,CACZ,SAAU,OACV,WAAY,iBACZ,WAAY,IACZ,cAAe,SACf,aAAc,MACd,UAAW,QACb,EAEA,SAAU,CACR,SAAU,OACV,MAAOE,EACP,UAAW,SACX,aAAc,MAChB,EAEA,eAAgB,CACd,MAAOF,EACP,WAAY,GACd,EAEA,YAAa,CACX,WAAYG,EACZ,OAAQ,aAAaC,CAAW,GAChC,aAAc,OACd,QAAS,YACT,aAAc,MAChB,EAEA,cAAe,CACb,SAAU,OACV,MAAOF,EACP,cAAe,YACf,cAAe,SACf,WAAY,IACZ,aAAc,KAChB,EAEA,YAAa,CACX,QAAS,OACT,IAAK,MACL,WAAY,QACd,EAEA,aAAc,CACZ,KAAM,EACN,SAAU,OACV,MAAOD,EACP,SAAU,SACV,aAAc,WACd,WAAY,SACZ,WAAY,WACd,EAEA,QAAS,CACP,WAAYD,EACZ,MAAO,UACP,OAAQ,OACR,aAAc,MACd,QAAS,WACT,SAAU,OACV,WAAY,IACZ,OAAQ,UACR,WAAY,QACd,EAEA,SAAU,CACR,QAAS,OACT,IAAK,OACL,eAAgB,QAClB,EAEA,SAAU,CACR,QAAS,cACT,WAAY,SACZ,IAAK,MACL,WAAYG,EACZ,OAAQ,aAAaC,CAAW,GAChC,aAAc,MACd,QAAS,YACT,SAAU,OACV,MAAOH,EACP,eAAgB,OAChB,OAAQ,SACV,EAEA,SAAU,CACR,UAAW,OACX,SAAU,OACV,MAAOC,EACP,UAAW,QACb,EAEA,aAAc,CACZ,MAAOF,EACP,eAAgB,OAChB,WAAY,GACd,CACF,CACF,CJvKI,IAAAK,EAAA,6BAFJ,SAASC,EAAU,CAAE,MAAAC,CAAM,EAAsB,CAC/C,SACE,QAAC,OAAI,MAAM,KAAK,OAAO,KAAK,QAAQ,YAAY,KAAK,OACnD,oBAAC,QAAK,EAAE,2CAA2C,KAAMA,EAAO,QAAS,GAAK,KAC9E,OAAC,QAAK,EAAE,qBAAqB,OAAQA,EAAO,YAAY,IAAI,cAAc,QAAQ,eAAe,QAAQ,GAC3G,CAEJ,CAEA,SAASC,EAAS,CAAE,MAAAD,CAAM,EAAsB,CAC9C,SACE,QAAC,OAAI,MAAM,KAAK,OAAO,KAAK,QAAQ,YAAY,KAAK,OACnD,oBAAC,UAAO,GAAG,KAAK,GAAG,IAAI,EAAE,IAAI,OAAQA,EAAO,YAAY,MAAM,KAC9D,OAAC,QAAK,EAAE,kCAAkC,OAAQA,EAAO,YAAY,MAAM,cAAc,QAAQ,GACnG,CAEJ,CAEO,SAASE,EAAgBC,EAA6B,CAzB7D,IAAAC,EAAAC,EAAAC,EAAAC,EAAAC,EAAAC,EAAAC,EA0BE,IAAMC,EAAMC,EAAkB,EACxBC,GAAkBT,EAAAD,EAAM,UAAN,KAAAC,EAAiBO,EAAI,QAEvC,CACJ,OAAAG,EACA,QAAAC,EACA,MAAAC,EACA,SAAAC,EACA,OAAAC,EACA,WAAAC,EACA,MAAAC,EACA,OAAAC,CACF,EAAIC,EAAY,CACd,KAAMnB,EAAM,KACZ,QAASU,EACT,aAAcV,EAAM,aACpB,UAAWA,EAAM,UACjB,QAASA,EAAM,OACjB,CAAC,EAEK,CAACoB,EAAQC,CAAS,KAAI,YAAS,EAAK,EAEpCC,KAAa,eAAaC,GAAiB,CAC3C,OAAO,WAAc,aAAe,UAAU,WAChD,UAAU,UAAU,UAAUA,CAAI,EAAE,MAAM,IAAM,CAAC,CAAC,EAEpDF,EAAU,EAAI,EACd,WAAW,IAAMA,EAAU,EAAK,EAAG,GAAI,CACzC,EAAG,CAAC,CAAC,EAECG,KAAe,eAAaC,GAAuB,CACvDA,EAAE,eAAe,EACjBV,EAAO,CACT,EAAG,CAACA,CAAM,CAAC,EAGX,GAAIf,EAAM,SACR,SACE,mBAAG,SAAAA,EAAM,SAAS,CAAE,MAAAa,EAAO,SAAAC,EAAU,OAAAC,EAAQ,WAAAC,EAAY,MAAAC,EAAO,OAAAC,EAAQ,OAAAP,EAAQ,QAAAC,CAAQ,CAAC,EAAE,EAK/F,GAAIA,GAAW,CAACD,EAAQ,OAAO,KAE/B,IAAMe,GAAQxB,EAAAF,EAAM,QAAN,KAAAE,EAAgBS,EAAO,SAAS,kBAAoB,QAAU,QAAU,OAChFgB,GAASvB,GAAAD,EAAAH,EAAM,cAAN,KAAAG,EAAqBQ,EAAO,SAAS,cAArC,KAAAP,EAAoD,UAC7DwB,EAAI5B,EAAM,SAAW,OAAY6B,EAAUH,EAAOC,CAAM,EAG9D,OAAIT,KAEA,QAAC,OACC,UAAWlB,EAAM,UACjB,MAAOA,EAAM,SAAWA,EAAM,MAAQ,CAAE,GAAG4B,EAAG,KAAM,GAAG5B,EAAM,KAAM,EACnE,sBAAmB,GAEnB,oBAAC,OAAI,MAAO4B,GAAA,YAAAA,EAAG,YACZ,SAAAV,EAAO,iBACJ,OAACpB,EAAA,CAAS,MAAO4B,IAAU,QAAU,kBAAoB,wBAAyB,KAClF,OAAC9B,EAAA,CAAU,MAAO+B,EAAQ,EAChC,KACA,OAAC,OAAI,MAAOC,GAAA,YAAAA,EAAG,aACZ,SAAAV,EAAO,cAAgB,8BAAgC,sBAC1D,EACCP,EAAO,SAAS,cAAgB,CAACO,EAAO,kBACvC,QAAC,KAAE,MAAOU,GAAA,YAAAA,EAAG,SAAU,uBACd,QAAC,UAAO,MAAOA,GAAA,YAAAA,EAAG,eAAgB,cAAEV,EAAO,UAAS,EAAS,oBACtE,EAEDP,EAAO,SAAS,qBACf,QAAC,OAAI,MAAOiB,GAAA,YAAAA,EAAG,YACb,oBAAC,KAAE,MAAOA,GAAA,YAAAA,EAAG,cAAe,4BAAgB,KAC5C,QAAC,OAAI,MAAOA,GAAA,YAAAA,EAAG,YACb,oBAAC,QAAK,MAAOA,GAAA,YAAAA,EAAG,aAAe,SAAAV,EAAO,aAAa,KACnD,OAAC,UAAO,QAAS,IAAMI,EAAWJ,EAAO,YAAY,EAAG,MAAOU,GAAA,YAAAA,EAAG,QAC/D,SAAAR,EAAS,UAAY,OACxB,GACF,GACF,KAEF,QAAC,OAAI,MAAOQ,GAAA,YAAAA,EAAG,SACb,oBAAC,KACC,KAAM,yCAAyC,mBAAmB,kCAAkCjB,EAAO,IAAI,qBAAqB,CAAC,QAAQ,mBAAmBO,EAAO,YAAY,CAAC,GACpL,OAAO,SACP,IAAI,sBACJ,MAAOU,GAAA,YAAAA,EAAG,SACX,sBAED,KACA,OAAC,KACC,KAAM,uDAAuD,mBAAmBV,EAAO,YAAY,CAAC,GACpG,OAAO,SACP,IAAI,sBACJ,MAAOU,GAAA,YAAAA,EAAG,SACX,6BAED,GACF,EACCjB,EAAO,SAAS,iBACf,QAAC,KAAE,MAAOiB,GAAA,YAAAA,EAAG,SAAU,uBACV,OACX,OAAC,KAAE,KAAK,qBAAqB,OAAO,SAAS,IAAI,sBAAsB,MAAOA,GAAA,YAAAA,EAAG,aAAc,mBAE/F,GACF,GAEJ,KAMF,QAAC,OACC,UAAW5B,EAAM,UACjB,MAAOA,EAAM,SAAWA,EAAM,MAAQ,CAAE,GAAG4B,EAAG,KAAM,GAAG5B,EAAM,KAAM,EACnE,oBAAiB,GAEhB,UAAAW,EAAO,SAAW,UACjB,QAAC,QAAK,SAAUa,EAAc,MAAOI,GAAA,YAAAA,EAAG,KACtC,oBAAC,SACC,KAAK,QACL,MAAOf,EACP,SAAWY,GAAMX,EAASW,EAAE,OAAO,KAAK,EACxC,aAAapB,EAAAL,EAAM,cAAN,KAAAK,EAAqB,sBAClC,SAAQ,GACR,MAAOuB,GAAA,YAAAA,EAAG,MACZ,KACA,OAAC,UACC,KAAK,SACL,SAAUZ,EACV,MAAOA,EAAa,CAAE,GAAGY,GAAA,YAAAA,EAAG,OAAQ,GAAGA,GAAA,YAAAA,EAAG,cAAe,EAAIA,GAAA,YAAAA,EAAG,OAE/D,SAAAZ,EAAa,cAAgBT,GAAAD,EAAAN,EAAM,aAAN,KAAAM,EAAoBK,EAAO,SAAS,aAApC,KAAAJ,EAAkD,gBAClF,GACF,KAEA,QAAC,OAAI,MAAO,CAAE,UAAW,SAAU,SAAU,OAAQ,MAAO,wBAAyB,EAAG,wCAC1DI,EAAO,OAAO,KAC5C,EAEDM,MAAS,OAAC,OAAI,MAAOW,GAAA,YAAAA,EAAG,MAAQ,SAAAX,EAAM,EACtCN,EAAO,SAAS,iBACf,QAAC,KAAE,MAAOiB,GAAA,YAAAA,EAAG,SAAU,uBACV,OACX,OAAC,KAAE,KAAK,qBAAqB,OAAO,SAAS,IAAI,sBAAsB,MAAOA,GAAA,YAAAA,EAAG,aAAc,mBAE/F,GACF,GAEJ,CAEJ","names":["index_exports","__export","LaunchQProvider","LaunchQWaitlist","fetchWaitlistConfig","joinWaitlist","useWaitlist","__toCommonJS","import_react","import_react","DEFAULT_BASE_URL","fetchWaitlistConfig","slug","baseUrl","res","joinWaitlist","params","_a","_b","body","data","DEFAULT_BASE_URL","useWaitlist","options","slug","baseUrl","onSuccess","onError","config","setConfig","loading","setLoading","email","setEmail","submitting","setSubmitting","error","setError","result","setResult","refCode","setRefCode","ref","cancelled","fetchWaitlistConfig","cfg","err","submit","joinResult","joinWaitlist","referralLink","waitlistResult","import_react","import_jsx_runtime","LaunchQContext","LaunchQProvider","baseUrl","children","useLaunchQContext","t","theme","dark","light","getStyles","accent","textColor","subColor","fieldBg","fieldBorder","import_jsx_runtime","CheckIcon","color","UserIcon","LaunchQWaitlist","props","_a","_b","_c","_d","_e","_f","_g","ctx","useLaunchQContext","resolvedBaseUrl","config","loading","email","setEmail","submit","submitting","error","result","useWaitlist","copied","setCopied","handleCopy","text","handleSubmit","e","theme","accent","s","getStyles"]}
|
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import{useState as O,useCallback as A}from"react";import{useState as g,useEffect as I,useCallback as F}from"react";var $="https://launchq.co";async function R(e,n=$){let o=await fetch(`${n}/api/waitlist/${encodeURIComponent(e)}/config`);if(!o.ok)throw o.status===404?new Error(`Waitlist "${e}" not found`):new Error(`Failed to load waitlist config (${o.status})`);return o.json()}async function E(e=$,n){var l,a;let o=await fetch(`${e}/api/subscriber/join`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(n)});if(!o.ok){let h=await o.json().catch(()=>({}));throw new Error(h.error||`Failed to join waitlist (${o.status})`)}let r=await o.json();return{alreadyExists:r.alreadyExists,position:(l=r.subscriber.position)!=null?l:1,referralCode:(a=r.subscriber.referralCode)!=null?a:""}}var q="https://launchq.co";function B(e){let{slug:n,baseUrl:o=q,onSuccess:r,onError:l}=e,[a,h]=g(null),[m,f]=g(!0),[p,u]=g(""),[L,x]=g(!1),[P,b]=g(null),[C,w]=g(null),[t,k]=g(e.referralCode);I(()=>{if(!e.referralCode&&typeof window!="undefined"){let s=new URLSearchParams(window.location.search).get("ref");s&&k(s)}},[e.referralCode]),I(()=>{let c=!1;return f(!0),R(n,o).then(s=>{c||(h(s),f(!1))}).catch(s=>{c||(b(s instanceof Error?s.message:"Failed to load waitlist"),f(!1))}),()=>{c=!0}},[n,o]);let v=F(async()=>{if(!(!a||!p.trim())){x(!0),b(null);try{let c=await E(o,{waitlistId:a.id,email:p.trim(),referredBy:t}),s=`${o}/w/${a.slug}?ref=${c.referralCode}`,y={...c,referralLink:s};w(y),r==null||r(y)}catch(c){let s=c instanceof Error?c:new Error("Something went wrong");b(s.message),l==null||l(s)}finally{x(!1)}}},[a,p,o,t,r,l]);return{config:a,loading:m,email:p,setEmail:u,submit:v,submitting:L,error:P,result:C}}import{createContext as _,useContext as D}from"react";import{jsx as N}from"react/jsx-runtime";var Q=_({baseUrl:"https://launchq.co"});function J({baseUrl:e,children:n}){return N(Q.Provider,{value:{baseUrl:e},children:n})}function j(){return D(Q)}function W(e,n,o){return e==="light"?o:n}function z(e,n){let o=W(e,"#f0efe9","#111111"),r=W(e,"rgba(255,255,255,0.45)","rgba(0,0,0,0.45)"),l=W(e,"rgba(255,255,255,0.07)","rgba(0,0,0,0.04)"),a=W(e,"rgba(255,255,255,0.1)","rgba(0,0,0,0.1)");return{root:{width:"100%",fontFamily:"system-ui, -apple-system, sans-serif",color:o},form:{display:"flex",background:l,border:`1px solid ${a}`,borderRadius:"100px",padding:"6px",gap:"6px"},input:{flex:1,background:"none",border:"none",outline:"none",padding:"12px 18px",fontSize:"15px",color:o,minWidth:0},button:{background:n,color:"#0a0a0a",border:"none",borderRadius:"100px",padding:"12px 28px",fontSize:"15px",fontWeight:600,cursor:"pointer",whiteSpace:"nowrap",transition:"transform 0.2s, box-shadow 0.2s"},buttonDisabled:{opacity:.7,cursor:"not-allowed"},error:{marginTop:"12px",fontSize:"13px",color:"#f87171",textAlign:"center"},successIcon:{width:"52px",height:"52px",borderRadius:"50%",display:"flex",alignItems:"center",justifyContent:"center",margin:"0 auto 16px",background:`${n}1a`},successTitle:{fontSize:"24px",fontFamily:"Georgia, serif",fontWeight:400,letterSpacing:"-0.5px",marginBottom:"8px",textAlign:"center"},position:{fontSize:"14px",color:r,textAlign:"center",marginBottom:"20px"},positionStrong:{color:n,fontWeight:700},referralBox:{background:l,border:`1px solid ${a}`,borderRadius:"12px",padding:"14px 18px",marginBottom:"16px"},referralLabel:{fontSize:"11px",color:r,textTransform:"uppercase",letterSpacing:"0.08em",fontWeight:600,marginBottom:"8px"},referralRow:{display:"flex",gap:"8px",alignItems:"center"},referralLink:{flex:1,fontSize:"12px",color:o,overflow:"hidden",textOverflow:"ellipsis",whiteSpace:"nowrap",fontFamily:"monospace"},copyBtn:{background:n,color:"#0a0a0a",border:"none",borderRadius:"8px",padding:"7px 14px",fontSize:"12px",fontWeight:600,cursor:"pointer",whiteSpace:"nowrap"},shareRow:{display:"flex",gap:"10px",justifyContent:"center"},shareBtn:{display:"inline-flex",alignItems:"center",gap:"6px",background:l,border:`1px solid ${a}`,borderRadius:"8px",padding:"10px 16px",fontSize:"13px",color:o,textDecoration:"none",cursor:"pointer"},branding:{marginTop:"20px",fontSize:"12px",color:r,textAlign:"center"},brandingLink:{color:n,textDecoration:"none",fontWeight:500}}}import{Fragment as V,jsx as i,jsxs as d}from"react/jsx-runtime";function M({color:e}){return d("svg",{width:"24",height:"24",viewBox:"0 0 24 24",fill:"none",children:[i("path",{d:"M12 2a10 10 0 1 1 0 20 10 10 0 0 1 0-20z",fill:e,opacity:.2}),i("path",{d:"M8 12l2.5 2.5L16 9",stroke:e,strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round"})]})}function Y({color:e}){return d("svg",{width:"24",height:"24",viewBox:"0 0 24 24",fill:"none",children:[i("circle",{cx:"12",cy:"8",r:"4",stroke:e,strokeWidth:"1.5"}),i("path",{d:"M5 20c0-3.5 3.1-6 7-6s7 2.5 7 6",stroke:e,strokeWidth:"1.5",strokeLinecap:"round"})]})}function G(e){var k,v,c,s,y,U,T;let n=j(),o=(k=e.baseUrl)!=null?k:n.baseUrl,{config:r,loading:l,email:a,setEmail:h,submit:m,submitting:f,error:p,result:u}=B({slug:e.slug,baseUrl:o,referralCode:e.referralCode,onSuccess:e.onSuccess,onError:e.onError}),[L,x]=O(!1),P=A(S=>{typeof navigator!="undefined"&&navigator.clipboard&&navigator.clipboard.writeText(S).catch(()=>{}),x(!0),setTimeout(()=>x(!1),2e3)},[]),b=A(S=>{S.preventDefault(),m()},[m]);if(e.children)return i(V,{children:e.children({email:a,setEmail:h,submit:m,submitting:f,error:p,result:u,config:r,loading:l})});if(l||!r)return null;let C=(v=e.theme)!=null?v:r.settings.backgroundStyle==="light"?"light":"dark",w=(s=(c=e.accentColor)!=null?c:r.settings.accentColor)!=null?s:"#e8ff5a",t=e.unstyled?void 0:z(C,w);return u?d("div",{className:e.className,style:e.unstyled?e.style:{...t.root,...e.style},"data-launchq-result":!0,children:[i("div",{style:t==null?void 0:t.successIcon,children:u.alreadyExists?i(Y,{color:C==="light"?"rgba(0,0,0,0.4)":"rgba(255,255,255,0.4)"}):i(M,{color:w})}),i("div",{style:t==null?void 0:t.successTitle,children:u.alreadyExists?"You're already on the list!":"You're on the list!"}),r.settings.showPosition&&!u.alreadyExists&&d("p",{style:t==null?void 0:t.position,children:["You're ",d("strong",{style:t==null?void 0:t.positionStrong,children:["#",u.position]})," on the waitlist"]}),r.settings.showReferralLink&&d("div",{style:t==null?void 0:t.referralBox,children:[i("p",{style:t==null?void 0:t.referralLabel,children:"Share to move up"}),d("div",{style:t==null?void 0:t.referralRow,children:[i("code",{style:t==null?void 0:t.referralLink,children:u.referralLink}),i("button",{onClick:()=>P(u.referralLink),style:t==null?void 0:t.copyBtn,children:L?"Copied!":"Copy"})]})]}),d("div",{style:t==null?void 0:t.shareRow,children:[i("a",{href:`https://twitter.com/intent/tweet?text=${encodeURIComponent(`I just joined the waitlist for ${r.name}! Get early access:`)}&url=${encodeURIComponent(u.referralLink)}`,target:"_blank",rel:"noopener noreferrer",style:t==null?void 0:t.shareBtn,children:"Share on X"}),i("a",{href:`https://www.linkedin.com/sharing/share-offsite/?url=${encodeURIComponent(u.referralLink)}`,target:"_blank",rel:"noopener noreferrer",style:t==null?void 0:t.shareBtn,children:"Share on LinkedIn"})]}),r.settings.showBranding&&d("p",{style:t==null?void 0:t.branding,children:["Powered by"," ",i("a",{href:"https://launchq.co",target:"_blank",rel:"noopener noreferrer",style:t==null?void 0:t.brandingLink,children:"LaunchQ"})]})]}):d("div",{className:e.className,style:e.unstyled?e.style:{...t.root,...e.style},"data-launchq-form":!0,children:[r.status==="live"?d("form",{onSubmit:b,style:t==null?void 0:t.form,children:[i("input",{type:"email",value:a,onChange:S=>h(S.target.value),placeholder:(y=e.placeholder)!=null?y:"Enter your email...",required:!0,style:t==null?void 0:t.input}),i("button",{type:"submit",disabled:f,style:f?{...t==null?void 0:t.button,...t==null?void 0:t.buttonDisabled}:t==null?void 0:t.button,children:f?"Joining...":(T=(U=e.buttonText)!=null?U:r.settings.buttonText)!=null?T:"Join Waitlist"})]}):d("div",{style:{textAlign:"center",fontSize:"14px",color:"rgba(255,255,255,0.45)"},children:["This waitlist is currently ",r.status,"."]}),p&&i("div",{style:t==null?void 0:t.error,children:p}),r.settings.showBranding&&d("p",{style:t==null?void 0:t.branding,children:["Powered by"," ",i("a",{href:"https://launchq.co",target:"_blank",rel:"noopener noreferrer",style:t==null?void 0:t.brandingLink,children:"LaunchQ"})]})]})}export{J as LaunchQProvider,G as LaunchQWaitlist,R as fetchWaitlistConfig,E as joinWaitlist,B as useWaitlist};
|
|
2
|
+
//# sourceMappingURL=index.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/LaunchQWaitlist.tsx","../src/useWaitlist.ts","../src/api.ts","../src/LaunchQProvider.tsx","../src/styles.ts"],"sourcesContent":["import { useState, useCallback } from 'react';\nimport { useWaitlist } from './useWaitlist';\nimport { useLaunchQContext } from './LaunchQProvider';\nimport { getStyles } from './styles';\nimport type { LaunchQWaitlistProps } from './types';\n\n// Inline SVG icons (no external dependency)\nfunction CheckIcon({ color }: { color: string }) {\n return (\n <svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\">\n <path d=\"M12 2a10 10 0 1 1 0 20 10 10 0 0 1 0-20z\" fill={color} opacity={0.2} />\n <path d=\"M8 12l2.5 2.5L16 9\" stroke={color} strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\" />\n </svg>\n );\n}\n\nfunction UserIcon({ color }: { color: string }) {\n return (\n <svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\">\n <circle cx=\"12\" cy=\"8\" r=\"4\" stroke={color} strokeWidth=\"1.5\" />\n <path d=\"M5 20c0-3.5 3.1-6 7-6s7 2.5 7 6\" stroke={color} strokeWidth=\"1.5\" strokeLinecap=\"round\" />\n </svg>\n );\n}\n\nexport function LaunchQWaitlist(props: LaunchQWaitlistProps) {\n const ctx = useLaunchQContext();\n const resolvedBaseUrl = props.baseUrl ?? ctx.baseUrl;\n\n const {\n config,\n loading,\n email,\n setEmail,\n submit,\n submitting,\n error,\n result,\n } = useWaitlist({\n slug: props.slug,\n baseUrl: resolvedBaseUrl,\n referralCode: props.referralCode,\n onSuccess: props.onSuccess,\n onError: props.onError,\n });\n\n const [copied, setCopied] = useState(false);\n\n const handleCopy = useCallback((text: string) => {\n if (typeof navigator !== 'undefined' && navigator.clipboard) {\n navigator.clipboard.writeText(text).catch(() => {});\n }\n setCopied(true);\n setTimeout(() => setCopied(false), 2000);\n }, []);\n\n const handleSubmit = useCallback((e: React.FormEvent) => {\n e.preventDefault();\n submit();\n }, [submit]);\n\n // Render prop mode\n if (props.children) {\n return (\n <>{props.children({ email, setEmail, submit, submitting, error, result, config, loading })}</>\n );\n }\n\n // Don't render anything while loading\n if (loading || !config) return null;\n\n const theme = props.theme ?? (config.settings.backgroundStyle === 'light' ? 'light' : 'dark');\n const accent = props.accentColor ?? config.settings.accentColor ?? '#e8ff5a';\n const s = props.unstyled ? undefined : getStyles(theme, accent);\n\n // Success state\n if (result) {\n return (\n <div\n className={props.className}\n style={props.unstyled ? props.style : { ...s!.root, ...props.style }}\n data-launchq-result\n >\n <div style={s?.successIcon}>\n {result.alreadyExists\n ? <UserIcon color={theme === 'light' ? 'rgba(0,0,0,0.4)' : 'rgba(255,255,255,0.4)'} />\n : <CheckIcon color={accent} />}\n </div>\n <div style={s?.successTitle}>\n {result.alreadyExists ? \"You're already on the list!\" : \"You're on the list!\"}\n </div>\n {config.settings.showPosition && !result.alreadyExists && (\n <p style={s?.position}>\n You're <strong style={s?.positionStrong}>#{result.position}</strong> on the waitlist\n </p>\n )}\n {config.settings.showReferralLink && (\n <div style={s?.referralBox}>\n <p style={s?.referralLabel}>Share to move up</p>\n <div style={s?.referralRow}>\n <code style={s?.referralLink}>{result.referralLink}</code>\n <button onClick={() => handleCopy(result.referralLink)} style={s?.copyBtn}>\n {copied ? 'Copied!' : 'Copy'}\n </button>\n </div>\n </div>\n )}\n <div style={s?.shareRow}>\n <a\n href={`https://twitter.com/intent/tweet?text=${encodeURIComponent(`I just joined the waitlist for ${config.name}! Get early access:`)}&url=${encodeURIComponent(result.referralLink)}`}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n style={s?.shareBtn}\n >\n Share on X\n </a>\n <a\n href={`https://www.linkedin.com/sharing/share-offsite/?url=${encodeURIComponent(result.referralLink)}`}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n style={s?.shareBtn}\n >\n Share on LinkedIn\n </a>\n </div>\n {config.settings.showBranding && (\n <p style={s?.branding}>\n Powered by{' '}\n <a href=\"https://launchq.co\" target=\"_blank\" rel=\"noopener noreferrer\" style={s?.brandingLink}>\n LaunchQ\n </a>\n </p>\n )}\n </div>\n );\n }\n\n // Form state\n return (\n <div\n className={props.className}\n style={props.unstyled ? props.style : { ...s!.root, ...props.style }}\n data-launchq-form\n >\n {config.status === 'live' ? (\n <form onSubmit={handleSubmit} style={s?.form}>\n <input\n type=\"email\"\n value={email}\n onChange={(e) => setEmail(e.target.value)}\n placeholder={props.placeholder ?? 'Enter your email...'}\n required\n style={s?.input}\n />\n <button\n type=\"submit\"\n disabled={submitting}\n style={submitting ? { ...s?.button, ...s?.buttonDisabled } : s?.button}\n >\n {submitting ? 'Joining...' : (props.buttonText ?? config.settings.buttonText ?? 'Join Waitlist')}\n </button>\n </form>\n ) : (\n <div style={{ textAlign: 'center', fontSize: '14px', color: 'rgba(255,255,255,0.45)' }}>\n This waitlist is currently {config.status}.\n </div>\n )}\n {error && <div style={s?.error}>{error}</div>}\n {config.settings.showBranding && (\n <p style={s?.branding}>\n Powered by{' '}\n <a href=\"https://launchq.co\" target=\"_blank\" rel=\"noopener noreferrer\" style={s?.brandingLink}>\n LaunchQ\n </a>\n </p>\n )}\n </div>\n );\n}\n","import { useState, useEffect, useCallback } from 'react';\nimport { fetchWaitlistConfig, joinWaitlist } from './api';\nimport type { WaitlistConfig, WaitlistResult, UseWaitlistOptions } from './types';\n\nconst DEFAULT_BASE_URL = 'https://launchq.co';\n\nexport function useWaitlist(options: UseWaitlistOptions) {\n const { slug, baseUrl = DEFAULT_BASE_URL, onSuccess, onError } = options;\n\n const [config, setConfig] = useState<WaitlistConfig | null>(null);\n const [loading, setLoading] = useState(true);\n const [email, setEmail] = useState('');\n const [submitting, setSubmitting] = useState(false);\n const [error, setError] = useState<string | null>(null);\n const [result, setResult] = useState<WaitlistResult | null>(null);\n\n // Read ?ref= from URL if no referralCode prop\n const [refCode, setRefCode] = useState<string | undefined>(options.referralCode);\n\n useEffect(() => {\n if (!options.referralCode && typeof window !== 'undefined') {\n const params = new URLSearchParams(window.location.search);\n const ref = params.get('ref');\n if (ref) setRefCode(ref);\n }\n }, [options.referralCode]);\n\n // Fetch waitlist config\n useEffect(() => {\n let cancelled = false;\n setLoading(true);\n fetchWaitlistConfig(slug, baseUrl)\n .then((cfg) => {\n if (!cancelled) {\n setConfig(cfg);\n setLoading(false);\n }\n })\n .catch((err) => {\n if (!cancelled) {\n setError(err instanceof Error ? err.message : 'Failed to load waitlist');\n setLoading(false);\n }\n });\n return () => { cancelled = true; };\n }, [slug, baseUrl]);\n\n const submit = useCallback(async () => {\n if (!config || !email.trim()) return;\n setSubmitting(true);\n setError(null);\n try {\n const joinResult = await joinWaitlist(baseUrl, {\n waitlistId: config.id,\n email: email.trim(),\n referredBy: refCode,\n });\n\n const referralLink = `${baseUrl}/w/${config.slug}?ref=${joinResult.referralCode}`;\n const waitlistResult: WaitlistResult = { ...joinResult, referralLink };\n\n setResult(waitlistResult);\n onSuccess?.(waitlistResult);\n } catch (err) {\n const error = err instanceof Error ? err : new Error('Something went wrong');\n setError(error.message);\n onError?.(error);\n } finally {\n setSubmitting(false);\n }\n }, [config, email, baseUrl, refCode, onSuccess, onError]);\n\n return {\n config,\n loading,\n email,\n setEmail,\n submit,\n submitting,\n error,\n result,\n };\n}\n","import type { WaitlistConfig, JoinResult } from './types';\n\nconst DEFAULT_BASE_URL = 'https://launchq.co';\n\nexport async function fetchWaitlistConfig(\n slug: string,\n baseUrl = DEFAULT_BASE_URL\n): Promise<WaitlistConfig> {\n const res = await fetch(`${baseUrl}/api/waitlist/${encodeURIComponent(slug)}/config`);\n if (!res.ok) {\n if (res.status === 404) throw new Error(`Waitlist \"${slug}\" not found`);\n throw new Error(`Failed to load waitlist config (${res.status})`);\n }\n return res.json() as Promise<WaitlistConfig>;\n}\n\nexport async function joinWaitlist(\n baseUrl = DEFAULT_BASE_URL,\n params: { waitlistId: string; email: string; referredBy?: string }\n): Promise<JoinResult> {\n const res = await fetch(`${baseUrl}/api/subscriber/join`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify(params),\n });\n\n if (!res.ok) {\n const body = await res.json().catch(() => ({})) as { error?: string };\n throw new Error(body.error || `Failed to join waitlist (${res.status})`);\n }\n\n const data = await res.json() as {\n alreadyExists: boolean;\n subscriber: { position?: number; referralCode?: string };\n };\n\n return {\n alreadyExists: data.alreadyExists,\n position: data.subscriber.position ?? 1,\n referralCode: data.subscriber.referralCode ?? '',\n };\n}\n","import { createContext, useContext } from 'react';\n\ninterface LaunchQContextValue {\n baseUrl: string;\n}\n\nconst LaunchQContext = createContext<LaunchQContextValue>({\n baseUrl: 'https://launchq.co',\n});\n\nexport function LaunchQProvider({\n baseUrl,\n children,\n}: {\n baseUrl: string;\n children: React.ReactNode;\n}) {\n return (\n <LaunchQContext.Provider value={{ baseUrl }}>\n {children}\n </LaunchQContext.Provider>\n );\n}\n\nexport function useLaunchQContext() {\n return useContext(LaunchQContext);\n}\n","import type { CSSProperties } from 'react';\n\ntype Theme = 'dark' | 'light';\n\nfunction t(theme: Theme, dark: string, light: string) {\n return theme === 'light' ? light : dark;\n}\n\nexport function getStyles(theme: Theme, accent: string) {\n const textColor = t(theme, '#f0efe9', '#111111');\n const subColor = t(theme, 'rgba(255,255,255,0.45)', 'rgba(0,0,0,0.45)');\n const fieldBg = t(theme, 'rgba(255,255,255,0.07)', 'rgba(0,0,0,0.04)');\n const fieldBorder = t(theme, 'rgba(255,255,255,0.1)', 'rgba(0,0,0,0.1)');\n\n return {\n root: {\n width: '100%',\n fontFamily: 'system-ui, -apple-system, sans-serif',\n color: textColor,\n } as CSSProperties,\n\n form: {\n display: 'flex',\n background: fieldBg,\n border: `1px solid ${fieldBorder}`,\n borderRadius: '100px',\n padding: '6px',\n gap: '6px',\n } as CSSProperties,\n\n input: {\n flex: 1,\n background: 'none',\n border: 'none',\n outline: 'none',\n padding: '12px 18px',\n fontSize: '15px',\n color: textColor,\n minWidth: 0,\n } as CSSProperties,\n\n button: {\n background: accent,\n color: '#0a0a0a',\n border: 'none',\n borderRadius: '100px',\n padding: '12px 28px',\n fontSize: '15px',\n fontWeight: 600,\n cursor: 'pointer',\n whiteSpace: 'nowrap' as const,\n transition: 'transform 0.2s, box-shadow 0.2s',\n } as CSSProperties,\n\n buttonDisabled: {\n opacity: 0.7,\n cursor: 'not-allowed',\n } as CSSProperties,\n\n error: {\n marginTop: '12px',\n fontSize: '13px',\n color: '#f87171',\n textAlign: 'center' as const,\n } as CSSProperties,\n\n successIcon: {\n width: '52px',\n height: '52px',\n borderRadius: '50%',\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n margin: '0 auto 16px',\n background: `${accent}1a`,\n } as CSSProperties,\n\n successTitle: {\n fontSize: '24px',\n fontFamily: 'Georgia, serif',\n fontWeight: 400,\n letterSpacing: '-0.5px',\n marginBottom: '8px',\n textAlign: 'center' as const,\n } as CSSProperties,\n\n position: {\n fontSize: '14px',\n color: subColor,\n textAlign: 'center' as const,\n marginBottom: '20px',\n } as CSSProperties,\n\n positionStrong: {\n color: accent,\n fontWeight: 700,\n } as CSSProperties,\n\n referralBox: {\n background: fieldBg,\n border: `1px solid ${fieldBorder}`,\n borderRadius: '12px',\n padding: '14px 18px',\n marginBottom: '16px',\n } as CSSProperties,\n\n referralLabel: {\n fontSize: '11px',\n color: subColor,\n textTransform: 'uppercase' as const,\n letterSpacing: '0.08em',\n fontWeight: 600,\n marginBottom: '8px',\n } as CSSProperties,\n\n referralRow: {\n display: 'flex',\n gap: '8px',\n alignItems: 'center',\n } as CSSProperties,\n\n referralLink: {\n flex: 1,\n fontSize: '12px',\n color: textColor,\n overflow: 'hidden',\n textOverflow: 'ellipsis',\n whiteSpace: 'nowrap' as const,\n fontFamily: 'monospace',\n } as CSSProperties,\n\n copyBtn: {\n background: accent,\n color: '#0a0a0a',\n border: 'none',\n borderRadius: '8px',\n padding: '7px 14px',\n fontSize: '12px',\n fontWeight: 600,\n cursor: 'pointer',\n whiteSpace: 'nowrap' as const,\n } as CSSProperties,\n\n shareRow: {\n display: 'flex',\n gap: '10px',\n justifyContent: 'center',\n } as CSSProperties,\n\n shareBtn: {\n display: 'inline-flex',\n alignItems: 'center',\n gap: '6px',\n background: fieldBg,\n border: `1px solid ${fieldBorder}`,\n borderRadius: '8px',\n padding: '10px 16px',\n fontSize: '13px',\n color: textColor,\n textDecoration: 'none',\n cursor: 'pointer',\n } as CSSProperties,\n\n branding: {\n marginTop: '20px',\n fontSize: '12px',\n color: subColor,\n textAlign: 'center' as const,\n } as CSSProperties,\n\n brandingLink: {\n color: accent,\n textDecoration: 'none',\n fontWeight: 500,\n } as CSSProperties,\n };\n}\n"],"mappings":"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","names":["useState","useCallback","useState","useEffect","useCallback","DEFAULT_BASE_URL","fetchWaitlistConfig","slug","baseUrl","res","joinWaitlist","params","_a","_b","body","data","DEFAULT_BASE_URL","useWaitlist","options","slug","baseUrl","onSuccess","onError","config","setConfig","useState","loading","setLoading","email","setEmail","submitting","setSubmitting","error","setError","result","setResult","refCode","setRefCode","useEffect","ref","cancelled","fetchWaitlistConfig","cfg","err","submit","useCallback","joinResult","joinWaitlist","referralLink","waitlistResult","createContext","useContext","jsx","LaunchQContext","LaunchQProvider","baseUrl","children","useLaunchQContext","t","theme","dark","light","getStyles","accent","textColor","subColor","fieldBg","fieldBorder","Fragment","jsx","jsxs","CheckIcon","color","UserIcon","LaunchQWaitlist","props","_a","_b","_c","_d","_e","_f","_g","ctx","useLaunchQContext","resolvedBaseUrl","config","loading","email","setEmail","submit","submitting","error","result","useWaitlist","copied","setCopied","useState","handleCopy","useCallback","text","handleSubmit","e","theme","accent","s","getStyles"]}
|
package/package.json
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "launchq-react",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "React component for LaunchQ waitlist forms — drop-in, full-width, zero iframe",
|
|
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
|
+
"./styles.css": "./dist/styles.css"
|
|
15
|
+
},
|
|
16
|
+
"files": [
|
|
17
|
+
"dist",
|
|
18
|
+
"README.md",
|
|
19
|
+
"LICENSE"
|
|
20
|
+
],
|
|
21
|
+
"sideEffects": false,
|
|
22
|
+
"scripts": {
|
|
23
|
+
"build": "tsup",
|
|
24
|
+
"dev": "tsup --watch"
|
|
25
|
+
},
|
|
26
|
+
"peerDependencies": {
|
|
27
|
+
"react": ">=17.0.0",
|
|
28
|
+
"react-dom": ">=17.0.0"
|
|
29
|
+
},
|
|
30
|
+
"devDependencies": {
|
|
31
|
+
"@types/react": "^19.0.0",
|
|
32
|
+
"react": "^19.0.0",
|
|
33
|
+
"react-dom": "^19.0.0",
|
|
34
|
+
"tsup": "^8.0.0",
|
|
35
|
+
"typescript": "^5.0.0"
|
|
36
|
+
},
|
|
37
|
+
"keywords": [
|
|
38
|
+
"launchq",
|
|
39
|
+
"waitlist",
|
|
40
|
+
"react",
|
|
41
|
+
"widget",
|
|
42
|
+
"embed",
|
|
43
|
+
"referral",
|
|
44
|
+
"launch"
|
|
45
|
+
],
|
|
46
|
+
"license": "MIT",
|
|
47
|
+
"repository": {
|
|
48
|
+
"type": "git",
|
|
49
|
+
"url": "git+https://github.com/abhinavcdev/launchq-react.git"
|
|
50
|
+
},
|
|
51
|
+
"homepage": "https://launchq.co/docs",
|
|
52
|
+
"author": "Abhinav Chamallamudi",
|
|
53
|
+
"bugs": {
|
|
54
|
+
"url": "https://github.com/abhinavcdev/launchq-react/issues"
|
|
55
|
+
}
|
|
56
|
+
}
|