@sendmailos/sdk 1.0.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.
@@ -0,0 +1,140 @@
1
+ import * as react_jsx_runtime from 'react/jsx-runtime';
2
+ import React from 'react';
3
+
4
+ interface SendMailOSContextValue {
5
+ publicKey: string;
6
+ baseUrl: string;
7
+ }
8
+ interface SendMailOSProviderProps {
9
+ /** Your public key (pk_live_... or pk_test_...) */
10
+ publicKey: string;
11
+ /** Custom API base URL (optional) */
12
+ baseUrl?: string;
13
+ children: React.ReactNode;
14
+ }
15
+ /**
16
+ * Provider component for SendMailOS React integration
17
+ *
18
+ * @example
19
+ * ```tsx
20
+ * import { SendMailOSProvider } from '@sendmailos/sdk/react';
21
+ *
22
+ * function App() {
23
+ * return (
24
+ * <SendMailOSProvider publicKey="pk_live_...">
25
+ * <YourApp />
26
+ * </SendMailOSProvider>
27
+ * );
28
+ * }
29
+ * ```
30
+ */
31
+ declare function SendMailOSProvider({ publicKey, baseUrl, children, }: SendMailOSProviderProps): react_jsx_runtime.JSX.Element;
32
+ /**
33
+ * Hook to access SendMailOS context
34
+ */
35
+ declare function useSendMailOS(): SendMailOSContextValue;
36
+
37
+ interface SubscribeParams {
38
+ email: string;
39
+ firstName?: string;
40
+ lastName?: string;
41
+ tags?: string[];
42
+ }
43
+ interface SubscribeResult {
44
+ success: boolean;
45
+ subscriberId?: string;
46
+ message?: string;
47
+ }
48
+ interface UseSubscribeReturn {
49
+ /** Subscribe a new email address */
50
+ subscribe: (params: SubscribeParams) => Promise<SubscribeResult>;
51
+ /** Loading state */
52
+ isLoading: boolean;
53
+ /** Error message if subscription failed */
54
+ error: Error | null;
55
+ /** Success state */
56
+ isSuccess: boolean;
57
+ /** Reset the hook state */
58
+ reset: () => void;
59
+ }
60
+ /**
61
+ * Hook for subscribing users to your email list
62
+ *
63
+ * @example
64
+ * ```tsx
65
+ * function NewsletterForm() {
66
+ * const { subscribe, isLoading, error, isSuccess } = useSubscribe();
67
+ * const [email, setEmail] = useState('');
68
+ *
69
+ * const handleSubmit = async (e) => {
70
+ * e.preventDefault();
71
+ * await subscribe({ email, tags: ['newsletter'] });
72
+ * };
73
+ *
74
+ * if (isSuccess) {
75
+ * return <p>Thanks for subscribing!</p>;
76
+ * }
77
+ *
78
+ * return (
79
+ * <form onSubmit={handleSubmit}>
80
+ * <input
81
+ * type="email"
82
+ * value={email}
83
+ * onChange={(e) => setEmail(e.target.value)}
84
+ * placeholder="Enter your email"
85
+ * />
86
+ * <button disabled={isLoading}>
87
+ * {isLoading ? 'Subscribing...' : 'Subscribe'}
88
+ * </button>
89
+ * {error && <p>{error.message}</p>}
90
+ * </form>
91
+ * );
92
+ * }
93
+ * ```
94
+ */
95
+ declare function useSubscribe(): UseSubscribeReturn;
96
+
97
+ interface SubscribeFormProps {
98
+ /** Tags to apply to new subscribers */
99
+ tags?: string[];
100
+ /** Callback when subscription succeeds */
101
+ onSuccess?: () => void;
102
+ /** Callback when subscription fails */
103
+ onError?: (error: Error) => void;
104
+ /** CSS class for the form container */
105
+ className?: string;
106
+ /** Placeholder text for email input */
107
+ placeholder?: string;
108
+ /** Text for submit button */
109
+ buttonText?: string;
110
+ /** Text shown while loading */
111
+ loadingText?: string;
112
+ /** Text shown on success */
113
+ successMessage?: string;
114
+ /** Whether to show first/last name fields */
115
+ showNameFields?: boolean;
116
+ /** Custom styles */
117
+ style?: React.CSSProperties;
118
+ }
119
+ /**
120
+ * Pre-built newsletter subscription form
121
+ *
122
+ * @example
123
+ * ```tsx
124
+ * import { SubscribeForm } from '@sendmailos/sdk/react';
125
+ *
126
+ * function Newsletter() {
127
+ * return (
128
+ * <SubscribeForm
129
+ * tags={['newsletter']}
130
+ * onSuccess={() => console.log('Subscribed!')}
131
+ * buttonText="Join Newsletter"
132
+ * placeholder="you@example.com"
133
+ * />
134
+ * );
135
+ * }
136
+ * ```
137
+ */
138
+ declare function SubscribeForm({ tags, onSuccess, onError, className, placeholder, buttonText, loadingText, successMessage, showNameFields, style, }: SubscribeFormProps): react_jsx_runtime.JSX.Element;
139
+
140
+ export { SendMailOSProvider, SubscribeForm, type SubscribeFormProps, useSendMailOS, useSubscribe };
@@ -0,0 +1,140 @@
1
+ import * as react_jsx_runtime from 'react/jsx-runtime';
2
+ import React from 'react';
3
+
4
+ interface SendMailOSContextValue {
5
+ publicKey: string;
6
+ baseUrl: string;
7
+ }
8
+ interface SendMailOSProviderProps {
9
+ /** Your public key (pk_live_... or pk_test_...) */
10
+ publicKey: string;
11
+ /** Custom API base URL (optional) */
12
+ baseUrl?: string;
13
+ children: React.ReactNode;
14
+ }
15
+ /**
16
+ * Provider component for SendMailOS React integration
17
+ *
18
+ * @example
19
+ * ```tsx
20
+ * import { SendMailOSProvider } from '@sendmailos/sdk/react';
21
+ *
22
+ * function App() {
23
+ * return (
24
+ * <SendMailOSProvider publicKey="pk_live_...">
25
+ * <YourApp />
26
+ * </SendMailOSProvider>
27
+ * );
28
+ * }
29
+ * ```
30
+ */
31
+ declare function SendMailOSProvider({ publicKey, baseUrl, children, }: SendMailOSProviderProps): react_jsx_runtime.JSX.Element;
32
+ /**
33
+ * Hook to access SendMailOS context
34
+ */
35
+ declare function useSendMailOS(): SendMailOSContextValue;
36
+
37
+ interface SubscribeParams {
38
+ email: string;
39
+ firstName?: string;
40
+ lastName?: string;
41
+ tags?: string[];
42
+ }
43
+ interface SubscribeResult {
44
+ success: boolean;
45
+ subscriberId?: string;
46
+ message?: string;
47
+ }
48
+ interface UseSubscribeReturn {
49
+ /** Subscribe a new email address */
50
+ subscribe: (params: SubscribeParams) => Promise<SubscribeResult>;
51
+ /** Loading state */
52
+ isLoading: boolean;
53
+ /** Error message if subscription failed */
54
+ error: Error | null;
55
+ /** Success state */
56
+ isSuccess: boolean;
57
+ /** Reset the hook state */
58
+ reset: () => void;
59
+ }
60
+ /**
61
+ * Hook for subscribing users to your email list
62
+ *
63
+ * @example
64
+ * ```tsx
65
+ * function NewsletterForm() {
66
+ * const { subscribe, isLoading, error, isSuccess } = useSubscribe();
67
+ * const [email, setEmail] = useState('');
68
+ *
69
+ * const handleSubmit = async (e) => {
70
+ * e.preventDefault();
71
+ * await subscribe({ email, tags: ['newsletter'] });
72
+ * };
73
+ *
74
+ * if (isSuccess) {
75
+ * return <p>Thanks for subscribing!</p>;
76
+ * }
77
+ *
78
+ * return (
79
+ * <form onSubmit={handleSubmit}>
80
+ * <input
81
+ * type="email"
82
+ * value={email}
83
+ * onChange={(e) => setEmail(e.target.value)}
84
+ * placeholder="Enter your email"
85
+ * />
86
+ * <button disabled={isLoading}>
87
+ * {isLoading ? 'Subscribing...' : 'Subscribe'}
88
+ * </button>
89
+ * {error && <p>{error.message}</p>}
90
+ * </form>
91
+ * );
92
+ * }
93
+ * ```
94
+ */
95
+ declare function useSubscribe(): UseSubscribeReturn;
96
+
97
+ interface SubscribeFormProps {
98
+ /** Tags to apply to new subscribers */
99
+ tags?: string[];
100
+ /** Callback when subscription succeeds */
101
+ onSuccess?: () => void;
102
+ /** Callback when subscription fails */
103
+ onError?: (error: Error) => void;
104
+ /** CSS class for the form container */
105
+ className?: string;
106
+ /** Placeholder text for email input */
107
+ placeholder?: string;
108
+ /** Text for submit button */
109
+ buttonText?: string;
110
+ /** Text shown while loading */
111
+ loadingText?: string;
112
+ /** Text shown on success */
113
+ successMessage?: string;
114
+ /** Whether to show first/last name fields */
115
+ showNameFields?: boolean;
116
+ /** Custom styles */
117
+ style?: React.CSSProperties;
118
+ }
119
+ /**
120
+ * Pre-built newsletter subscription form
121
+ *
122
+ * @example
123
+ * ```tsx
124
+ * import { SubscribeForm } from '@sendmailos/sdk/react';
125
+ *
126
+ * function Newsletter() {
127
+ * return (
128
+ * <SubscribeForm
129
+ * tags={['newsletter']}
130
+ * onSuccess={() => console.log('Subscribed!')}
131
+ * buttonText="Join Newsletter"
132
+ * placeholder="you@example.com"
133
+ * />
134
+ * );
135
+ * }
136
+ * ```
137
+ */
138
+ declare function SubscribeForm({ tags, onSuccess, onError, className, placeholder, buttonText, loadingText, successMessage, showNameFields, style, }: SubscribeFormProps): react_jsx_runtime.JSX.Element;
139
+
140
+ export { SendMailOSProvider, SubscribeForm, type SubscribeFormProps, useSendMailOS, useSubscribe };
@@ -0,0 +1,228 @@
1
+ 'use strict';
2
+
3
+ var react = require('react');
4
+ var jsxRuntime = require('react/jsx-runtime');
5
+
6
+ // src/react/provider.tsx
7
+ var SendMailOSContext = react.createContext(null);
8
+ function SendMailOSProvider({
9
+ publicKey,
10
+ baseUrl = "https://api.sendmailos.com/api/v1",
11
+ children
12
+ }) {
13
+ if (!publicKey) {
14
+ throw new Error("SendMailOSProvider requires a publicKey");
15
+ }
16
+ if (!publicKey.startsWith("pk_")) {
17
+ console.warn(
18
+ '[SendMailOS] Public keys should start with "pk_". Never expose secret keys (sk_) in client-side code.'
19
+ );
20
+ }
21
+ const value = react.useMemo(
22
+ () => ({
23
+ publicKey,
24
+ baseUrl: baseUrl.replace(/\/$/, "")
25
+ }),
26
+ [publicKey, baseUrl]
27
+ );
28
+ return /* @__PURE__ */ jsxRuntime.jsx(SendMailOSContext.Provider, { value, children });
29
+ }
30
+ function useSendMailOS() {
31
+ const context = react.useContext(SendMailOSContext);
32
+ if (!context) {
33
+ throw new Error("useSendMailOS must be used within a SendMailOSProvider");
34
+ }
35
+ return context;
36
+ }
37
+ function useSubscribe() {
38
+ const { publicKey, baseUrl } = useSendMailOS();
39
+ const [isLoading, setIsLoading] = react.useState(false);
40
+ const [error, setError] = react.useState(null);
41
+ const [isSuccess, setIsSuccess] = react.useState(false);
42
+ const reset = react.useCallback(() => {
43
+ setIsLoading(false);
44
+ setError(null);
45
+ setIsSuccess(false);
46
+ }, []);
47
+ const subscribe = react.useCallback(
48
+ async (params) => {
49
+ setIsLoading(true);
50
+ setError(null);
51
+ setIsSuccess(false);
52
+ try {
53
+ const response = await fetch(`${baseUrl}/public/subscribe`, {
54
+ method: "POST",
55
+ headers: {
56
+ "Content-Type": "application/json",
57
+ "X-Public-Key": publicKey
58
+ },
59
+ body: JSON.stringify({
60
+ email: params.email,
61
+ first_name: params.firstName,
62
+ last_name: params.lastName,
63
+ tags: params.tags
64
+ })
65
+ });
66
+ if (!response.ok) {
67
+ const data2 = await response.json().catch(() => ({}));
68
+ throw new Error(data2.error || "Failed to subscribe");
69
+ }
70
+ const data = await response.json();
71
+ setIsSuccess(true);
72
+ setIsLoading(false);
73
+ return {
74
+ success: true,
75
+ subscriberId: data.subscriber?.id,
76
+ message: data.message
77
+ };
78
+ } catch (err) {
79
+ const error2 = err instanceof Error ? err : new Error("Unknown error");
80
+ setError(error2);
81
+ setIsLoading(false);
82
+ return { success: false, message: error2.message };
83
+ }
84
+ },
85
+ [baseUrl, publicKey]
86
+ );
87
+ return {
88
+ subscribe,
89
+ isLoading,
90
+ error,
91
+ isSuccess,
92
+ reset
93
+ };
94
+ }
95
+ function SubscribeForm({
96
+ tags,
97
+ onSuccess,
98
+ onError,
99
+ className,
100
+ placeholder = "Enter your email",
101
+ buttonText = "Subscribe",
102
+ loadingText = "Subscribing...",
103
+ successMessage = "Thanks for subscribing!",
104
+ showNameFields = false,
105
+ style
106
+ }) {
107
+ const { subscribe, isLoading, error, isSuccess, reset } = useSubscribe();
108
+ const [email, setEmail] = react.useState("");
109
+ const [firstName, setFirstName] = react.useState("");
110
+ const [lastName, setLastName] = react.useState("");
111
+ const handleSubmit = async (e) => {
112
+ e.preventDefault();
113
+ const result = await subscribe({
114
+ email,
115
+ firstName: showNameFields ? firstName : void 0,
116
+ lastName: showNameFields ? lastName : void 0,
117
+ tags
118
+ });
119
+ if (result.success) {
120
+ onSuccess?.();
121
+ setEmail("");
122
+ setFirstName("");
123
+ setLastName("");
124
+ } else if (error) {
125
+ onError?.(error);
126
+ }
127
+ };
128
+ if (isSuccess) {
129
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className, style, children: [
130
+ /* @__PURE__ */ jsxRuntime.jsx("p", { style: { color: "#10b981", margin: 0 }, children: successMessage }),
131
+ /* @__PURE__ */ jsxRuntime.jsx(
132
+ "button",
133
+ {
134
+ type: "button",
135
+ onClick: reset,
136
+ style: {
137
+ marginTop: "8px",
138
+ padding: "4px 8px",
139
+ fontSize: "12px",
140
+ background: "transparent",
141
+ border: "1px solid #ccc",
142
+ borderRadius: "4px",
143
+ cursor: "pointer"
144
+ },
145
+ children: "Subscribe another"
146
+ }
147
+ )
148
+ ] });
149
+ }
150
+ return /* @__PURE__ */ jsxRuntime.jsxs("form", { onSubmit: handleSubmit, className, style, children: [
151
+ showNameFields && /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { display: "flex", gap: "8px", marginBottom: "8px" }, children: [
152
+ /* @__PURE__ */ jsxRuntime.jsx(
153
+ "input",
154
+ {
155
+ type: "text",
156
+ value: firstName,
157
+ onChange: (e) => setFirstName(e.target.value),
158
+ placeholder: "First name",
159
+ style: {
160
+ flex: 1,
161
+ padding: "8px 12px",
162
+ border: "1px solid #ccc",
163
+ borderRadius: "4px"
164
+ }
165
+ }
166
+ ),
167
+ /* @__PURE__ */ jsxRuntime.jsx(
168
+ "input",
169
+ {
170
+ type: "text",
171
+ value: lastName,
172
+ onChange: (e) => setLastName(e.target.value),
173
+ placeholder: "Last name",
174
+ style: {
175
+ flex: 1,
176
+ padding: "8px 12px",
177
+ border: "1px solid #ccc",
178
+ borderRadius: "4px"
179
+ }
180
+ }
181
+ )
182
+ ] }),
183
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { display: "flex", gap: "8px" }, children: [
184
+ /* @__PURE__ */ jsxRuntime.jsx(
185
+ "input",
186
+ {
187
+ type: "email",
188
+ value: email,
189
+ onChange: (e) => setEmail(e.target.value),
190
+ placeholder,
191
+ required: true,
192
+ disabled: isLoading,
193
+ style: {
194
+ flex: 1,
195
+ padding: "8px 12px",
196
+ border: "1px solid #ccc",
197
+ borderRadius: "4px"
198
+ }
199
+ }
200
+ ),
201
+ /* @__PURE__ */ jsxRuntime.jsx(
202
+ "button",
203
+ {
204
+ type: "submit",
205
+ disabled: isLoading || !email,
206
+ style: {
207
+ padding: "8px 16px",
208
+ backgroundColor: isLoading ? "#9ca3af" : "#3b82f6",
209
+ color: "white",
210
+ border: "none",
211
+ borderRadius: "4px",
212
+ cursor: isLoading ? "not-allowed" : "pointer",
213
+ fontWeight: 500
214
+ },
215
+ children: isLoading ? loadingText : buttonText
216
+ }
217
+ )
218
+ ] }),
219
+ error && /* @__PURE__ */ jsxRuntime.jsx("p", { style: { color: "#ef4444", fontSize: "14px", marginTop: "8px" }, children: error.message })
220
+ ] });
221
+ }
222
+
223
+ exports.SendMailOSProvider = SendMailOSProvider;
224
+ exports.SubscribeForm = SubscribeForm;
225
+ exports.useSendMailOS = useSendMailOS;
226
+ exports.useSubscribe = useSubscribe;
227
+ //# sourceMappingURL=index.js.map
228
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/react/provider.tsx","../../src/react/use-subscribe.ts","../../src/react/subscribe-form.tsx"],"names":["createContext","useMemo","jsx","useContext","useState","useCallback","data","error","jsxs"],"mappings":"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","file":"index.js","sourcesContent":["import React, { createContext, useContext, useMemo } from 'react';\n\ninterface SendMailOSContextValue {\n publicKey: string;\n baseUrl: string;\n}\n\nconst SendMailOSContext = createContext<SendMailOSContextValue | null>(null);\n\nexport interface SendMailOSProviderProps {\n /** Your public key (pk_live_... or pk_test_...) */\n publicKey: string;\n /** Custom API base URL (optional) */\n baseUrl?: string;\n children: React.ReactNode;\n}\n\n/**\n * Provider component for SendMailOS React integration\n * \n * @example\n * ```tsx\n * import { SendMailOSProvider } from '@sendmailos/sdk/react';\n * \n * function App() {\n * return (\n * <SendMailOSProvider publicKey=\"pk_live_...\">\n * <YourApp />\n * </SendMailOSProvider>\n * );\n * }\n * ```\n */\nexport function SendMailOSProvider({\n publicKey,\n baseUrl = 'https://api.sendmailos.com/api/v1',\n children,\n}: SendMailOSProviderProps) {\n if (!publicKey) {\n throw new Error('SendMailOSProvider requires a publicKey');\n }\n\n if (!publicKey.startsWith('pk_')) {\n console.warn(\n '[SendMailOS] Public keys should start with \"pk_\". ' +\n 'Never expose secret keys (sk_) in client-side code.'\n );\n }\n\n const value = useMemo(\n () => ({\n publicKey,\n baseUrl: baseUrl.replace(/\\/$/, ''),\n }),\n [publicKey, baseUrl]\n );\n\n return (\n <SendMailOSContext.Provider value={value}>\n {children}\n </SendMailOSContext.Provider>\n );\n}\n\n/**\n * Hook to access SendMailOS context\n */\nexport function useSendMailOS(): SendMailOSContextValue {\n const context = useContext(SendMailOSContext);\n \n if (!context) {\n throw new Error('useSendMailOS must be used within a SendMailOSProvider');\n }\n \n return context;\n}\n","import { useState, useCallback } from 'react';\nimport { useSendMailOS } from './provider';\n\ninterface SubscribeParams {\n email: string;\n firstName?: string;\n lastName?: string;\n tags?: string[];\n}\n\ninterface SubscribeResult {\n success: boolean;\n subscriberId?: string;\n message?: string;\n}\n\ninterface UseSubscribeReturn {\n /** Subscribe a new email address */\n subscribe: (params: SubscribeParams) => Promise<SubscribeResult>;\n /** Loading state */\n isLoading: boolean;\n /** Error message if subscription failed */\n error: Error | null;\n /** Success state */\n isSuccess: boolean;\n /** Reset the hook state */\n reset: () => void;\n}\n\n/**\n * Hook for subscribing users to your email list\n * \n * @example\n * ```tsx\n * function NewsletterForm() {\n * const { subscribe, isLoading, error, isSuccess } = useSubscribe();\n * const [email, setEmail] = useState('');\n * \n * const handleSubmit = async (e) => {\n * e.preventDefault();\n * await subscribe({ email, tags: ['newsletter'] });\n * };\n * \n * if (isSuccess) {\n * return <p>Thanks for subscribing!</p>;\n * }\n * \n * return (\n * <form onSubmit={handleSubmit}>\n * <input\n * type=\"email\"\n * value={email}\n * onChange={(e) => setEmail(e.target.value)}\n * placeholder=\"Enter your email\"\n * />\n * <button disabled={isLoading}>\n * {isLoading ? 'Subscribing...' : 'Subscribe'}\n * </button>\n * {error && <p>{error.message}</p>}\n * </form>\n * );\n * }\n * ```\n */\nexport function useSubscribe(): UseSubscribeReturn {\n const { publicKey, baseUrl } = useSendMailOS();\n const [isLoading, setIsLoading] = useState(false);\n const [error, setError] = useState<Error | null>(null);\n const [isSuccess, setIsSuccess] = useState(false);\n\n const reset = useCallback(() => {\n setIsLoading(false);\n setError(null);\n setIsSuccess(false);\n }, []);\n\n const subscribe = useCallback(\n async (params: SubscribeParams): Promise<SubscribeResult> => {\n setIsLoading(true);\n setError(null);\n setIsSuccess(false);\n\n try {\n const response = await fetch(`${baseUrl}/public/subscribe`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'X-Public-Key': publicKey,\n },\n body: JSON.stringify({\n email: params.email,\n first_name: params.firstName,\n last_name: params.lastName,\n tags: params.tags,\n }),\n });\n\n if (!response.ok) {\n const data = await response.json().catch(() => ({}));\n throw new Error(data.error || 'Failed to subscribe');\n }\n\n const data = await response.json();\n setIsSuccess(true);\n setIsLoading(false);\n\n return {\n success: true,\n subscriberId: data.subscriber?.id,\n message: data.message,\n };\n } catch (err) {\n const error = err instanceof Error ? err : new Error('Unknown error');\n setError(error);\n setIsLoading(false);\n return { success: false, message: error.message };\n }\n },\n [baseUrl, publicKey]\n );\n\n return {\n subscribe,\n isLoading,\n error,\n isSuccess,\n reset,\n };\n}\n","import React, { useState, FormEvent } from 'react';\nimport { useSubscribe } from './use-subscribe';\n\nexport interface SubscribeFormProps {\n /** Tags to apply to new subscribers */\n tags?: string[];\n /** Callback when subscription succeeds */\n onSuccess?: () => void;\n /** Callback when subscription fails */\n onError?: (error: Error) => void;\n /** CSS class for the form container */\n className?: string;\n /** Placeholder text for email input */\n placeholder?: string;\n /** Text for submit button */\n buttonText?: string;\n /** Text shown while loading */\n loadingText?: string;\n /** Text shown on success */\n successMessage?: string;\n /** Whether to show first/last name fields */\n showNameFields?: boolean;\n /** Custom styles */\n style?: React.CSSProperties;\n}\n\n/**\n * Pre-built newsletter subscription form\n * \n * @example\n * ```tsx\n * import { SubscribeForm } from '@sendmailos/sdk/react';\n * \n * function Newsletter() {\n * return (\n * <SubscribeForm\n * tags={['newsletter']}\n * onSuccess={() => console.log('Subscribed!')}\n * buttonText=\"Join Newsletter\"\n * placeholder=\"you@example.com\"\n * />\n * );\n * }\n * ```\n */\nexport function SubscribeForm({\n tags,\n onSuccess,\n onError,\n className,\n placeholder = 'Enter your email',\n buttonText = 'Subscribe',\n loadingText = 'Subscribing...',\n successMessage = 'Thanks for subscribing!',\n showNameFields = false,\n style,\n}: SubscribeFormProps) {\n const { subscribe, isLoading, error, isSuccess, reset } = useSubscribe();\n const [email, setEmail] = useState('');\n const [firstName, setFirstName] = useState('');\n const [lastName, setLastName] = useState('');\n\n const handleSubmit = async (e: FormEvent) => {\n e.preventDefault();\n \n const result = await subscribe({\n email,\n firstName: showNameFields ? firstName : undefined,\n lastName: showNameFields ? lastName : undefined,\n tags,\n });\n\n if (result.success) {\n onSuccess?.();\n setEmail('');\n setFirstName('');\n setLastName('');\n } else if (error) {\n onError?.(error);\n }\n };\n\n if (isSuccess) {\n return (\n <div className={className} style={style}>\n <p style={{ color: '#10b981', margin: 0 }}>{successMessage}</p>\n <button\n type=\"button\"\n onClick={reset}\n style={{\n marginTop: '8px',\n padding: '4px 8px',\n fontSize: '12px',\n background: 'transparent',\n border: '1px solid #ccc',\n borderRadius: '4px',\n cursor: 'pointer',\n }}\n >\n Subscribe another\n </button>\n </div>\n );\n }\n\n return (\n <form onSubmit={handleSubmit} className={className} style={style}>\n {showNameFields && (\n <div style={{ display: 'flex', gap: '8px', marginBottom: '8px' }}>\n <input\n type=\"text\"\n value={firstName}\n onChange={(e) => setFirstName(e.target.value)}\n placeholder=\"First name\"\n style={{\n flex: 1,\n padding: '8px 12px',\n border: '1px solid #ccc',\n borderRadius: '4px',\n }}\n />\n <input\n type=\"text\"\n value={lastName}\n onChange={(e) => setLastName(e.target.value)}\n placeholder=\"Last name\"\n style={{\n flex: 1,\n padding: '8px 12px',\n border: '1px solid #ccc',\n borderRadius: '4px',\n }}\n />\n </div>\n )}\n \n <div style={{ display: 'flex', gap: '8px' }}>\n <input\n type=\"email\"\n value={email}\n onChange={(e) => setEmail(e.target.value)}\n placeholder={placeholder}\n required\n disabled={isLoading}\n style={{\n flex: 1,\n padding: '8px 12px',\n border: '1px solid #ccc',\n borderRadius: '4px',\n }}\n />\n <button\n type=\"submit\"\n disabled={isLoading || !email}\n style={{\n padding: '8px 16px',\n backgroundColor: isLoading ? '#9ca3af' : '#3b82f6',\n color: 'white',\n border: 'none',\n borderRadius: '4px',\n cursor: isLoading ? 'not-allowed' : 'pointer',\n fontWeight: 500,\n }}\n >\n {isLoading ? loadingText : buttonText}\n </button>\n </div>\n \n {error && (\n <p style={{ color: '#ef4444', fontSize: '14px', marginTop: '8px' }}>\n {error.message}\n </p>\n )}\n </form>\n );\n}\n"]}