@sudobility/email-components-rn 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.
- package/dist/AbTestEmail.d.ts +12 -0
- package/dist/AbTestEmail.d.ts.map +1 -0
- package/dist/ContactCard.d.ts +14 -0
- package/dist/ContactCard.d.ts.map +1 -0
- package/dist/EmailAccountsList.d.ts +30 -0
- package/dist/EmailAccountsList.d.ts.map +1 -0
- package/dist/EmailAnalytics.d.ts +12 -0
- package/dist/EmailAnalytics.d.ts.map +1 -0
- package/dist/EmailCampaign.d.ts +12 -0
- package/dist/EmailCampaign.d.ts.map +1 -0
- package/dist/EmailInputGroup.d.ts +56 -0
- package/dist/EmailInputGroup.d.ts.map +1 -0
- package/dist/EmailTemplate.d.ts +13 -0
- package/dist/EmailTemplate.d.ts.map +1 -0
- package/dist/FreeEmailBanner.d.ts +24 -0
- package/dist/FreeEmailBanner.d.ts.map +1 -0
- package/dist/SubscriberList.d.ts +12 -0
- package/dist/SubscriberList.d.ts.map +1 -0
- package/dist/SubscriptionPlan.d.ts +13 -0
- package/dist/SubscriptionPlan.d.ts.map +1 -0
- package/dist/index.cjs.js +1545 -0
- package/dist/index.cjs.js.map +1 -0
- package/dist/index.d.ts +15 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.esm.js +1545 -0
- package/dist/index.esm.js.map +1 -0
- package/package.json +55 -0
- package/src/AbTestEmail.tsx +39 -0
- package/src/ContactCard.tsx +71 -0
- package/src/EmailAccountsList.tsx +209 -0
- package/src/EmailAnalytics.tsx +39 -0
- package/src/EmailCampaign.tsx +39 -0
- package/src/EmailInputGroup.tsx +204 -0
- package/src/EmailTemplate.tsx +46 -0
- package/src/FreeEmailBanner.tsx +167 -0
- package/src/SubscriberList.tsx +39 -0
- package/src/SubscriptionPlan.tsx +46 -0
- package/src/index.ts +27 -0
- package/src/nativewind.d.ts +23 -0
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { View, Text, type ViewProps } from 'react-native';
|
|
3
|
+
import { cn } from '@sudobility/components-rn';
|
|
4
|
+
|
|
5
|
+
export interface EmailAnalyticsProps extends ViewProps {
|
|
6
|
+
disabled?: boolean;
|
|
7
|
+
children?: React.ReactNode;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* EmailAnalytics component for React Native
|
|
12
|
+
* Email analytics display container
|
|
13
|
+
*/
|
|
14
|
+
export const EmailAnalytics: React.FC<EmailAnalyticsProps> = ({
|
|
15
|
+
className,
|
|
16
|
+
children,
|
|
17
|
+
disabled,
|
|
18
|
+
...props
|
|
19
|
+
}) => {
|
|
20
|
+
return (
|
|
21
|
+
<View
|
|
22
|
+
className={cn(
|
|
23
|
+
'p-4 rounded-lg border',
|
|
24
|
+
'bg-white dark:bg-gray-900',
|
|
25
|
+
'border-gray-200 dark:border-gray-700',
|
|
26
|
+
disabled && 'opacity-50',
|
|
27
|
+
className
|
|
28
|
+
)}
|
|
29
|
+
accessibilityLabel="Email Analytics"
|
|
30
|
+
{...props}
|
|
31
|
+
>
|
|
32
|
+
{children || (
|
|
33
|
+
<Text className="text-gray-900 dark:text-white">
|
|
34
|
+
EmailAnalytics Component
|
|
35
|
+
</Text>
|
|
36
|
+
)}
|
|
37
|
+
</View>
|
|
38
|
+
);
|
|
39
|
+
};
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { View, Text, type ViewProps } from 'react-native';
|
|
3
|
+
import { cn } from '@sudobility/components-rn';
|
|
4
|
+
|
|
5
|
+
export interface EmailCampaignProps extends ViewProps {
|
|
6
|
+
disabled?: boolean;
|
|
7
|
+
children?: React.ReactNode;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* EmailCampaign component for React Native
|
|
12
|
+
* Email campaign display container
|
|
13
|
+
*/
|
|
14
|
+
export const EmailCampaign: React.FC<EmailCampaignProps> = ({
|
|
15
|
+
className,
|
|
16
|
+
children,
|
|
17
|
+
disabled,
|
|
18
|
+
...props
|
|
19
|
+
}) => {
|
|
20
|
+
return (
|
|
21
|
+
<View
|
|
22
|
+
className={cn(
|
|
23
|
+
'p-4 rounded-lg border',
|
|
24
|
+
'bg-white dark:bg-gray-900',
|
|
25
|
+
'border-gray-200 dark:border-gray-700',
|
|
26
|
+
disabled && 'opacity-50',
|
|
27
|
+
className
|
|
28
|
+
)}
|
|
29
|
+
accessibilityLabel="Email Campaign"
|
|
30
|
+
{...props}
|
|
31
|
+
>
|
|
32
|
+
{children || (
|
|
33
|
+
<Text className="text-gray-900 dark:text-white">
|
|
34
|
+
EmailCampaign Component
|
|
35
|
+
</Text>
|
|
36
|
+
)}
|
|
37
|
+
</View>
|
|
38
|
+
);
|
|
39
|
+
};
|
|
@@ -0,0 +1,204 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { View, Text, TextInput, Pressable, type ViewProps } from 'react-native';
|
|
3
|
+
import { cn } from '@sudobility/components-rn';
|
|
4
|
+
|
|
5
|
+
export interface EmailInputFieldProps {
|
|
6
|
+
label: string;
|
|
7
|
+
value: string;
|
|
8
|
+
onChangeText: (value: string) => void;
|
|
9
|
+
placeholder?: string;
|
|
10
|
+
required?: boolean;
|
|
11
|
+
error?: string;
|
|
12
|
+
className?: string;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export const EmailInputField: React.FC<EmailInputFieldProps> = ({
|
|
16
|
+
label,
|
|
17
|
+
value,
|
|
18
|
+
onChangeText,
|
|
19
|
+
placeholder,
|
|
20
|
+
required = false,
|
|
21
|
+
error,
|
|
22
|
+
className,
|
|
23
|
+
}) => {
|
|
24
|
+
return (
|
|
25
|
+
<View className={className}>
|
|
26
|
+
<Text className="text-sm font-medium text-gray-700 dark:text-gray-300 mb-1">
|
|
27
|
+
{label} {required && <Text className="text-red-500">*</Text>}
|
|
28
|
+
</Text>
|
|
29
|
+
<TextInput
|
|
30
|
+
value={value}
|
|
31
|
+
onChangeText={onChangeText}
|
|
32
|
+
placeholder={placeholder}
|
|
33
|
+
placeholderTextColor="#9CA3AF"
|
|
34
|
+
keyboardType="email-address"
|
|
35
|
+
autoCapitalize="none"
|
|
36
|
+
autoCorrect={false}
|
|
37
|
+
accessibilityLabel={label}
|
|
38
|
+
className={cn(
|
|
39
|
+
'px-3 py-2 border rounded-md',
|
|
40
|
+
'bg-white dark:bg-gray-800',
|
|
41
|
+
'text-gray-900 dark:text-white',
|
|
42
|
+
error
|
|
43
|
+
? 'border-red-300 dark:border-red-600'
|
|
44
|
+
: 'border-gray-300 dark:border-gray-600'
|
|
45
|
+
)}
|
|
46
|
+
/>
|
|
47
|
+
{error && (
|
|
48
|
+
<Text className="mt-1 text-sm text-red-600 dark:text-red-400">
|
|
49
|
+
{error}
|
|
50
|
+
</Text>
|
|
51
|
+
)}
|
|
52
|
+
</View>
|
|
53
|
+
);
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
export interface CollapsibleEmailFieldProps extends EmailInputFieldProps {
|
|
57
|
+
isVisible: boolean;
|
|
58
|
+
onToggle: () => void;
|
|
59
|
+
showLabel?: string;
|
|
60
|
+
hideLabel?: string;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
export const CollapsibleEmailField: React.FC<CollapsibleEmailFieldProps> = ({
|
|
64
|
+
isVisible,
|
|
65
|
+
onToggle,
|
|
66
|
+
showLabel,
|
|
67
|
+
hideLabel,
|
|
68
|
+
...fieldProps
|
|
69
|
+
}) => {
|
|
70
|
+
const toggleLabel = isVisible ? hideLabel : showLabel;
|
|
71
|
+
|
|
72
|
+
return (
|
|
73
|
+
<View>
|
|
74
|
+
<Pressable
|
|
75
|
+
onPress={onToggle}
|
|
76
|
+
accessibilityRole="button"
|
|
77
|
+
className="flex-row items-center mb-2"
|
|
78
|
+
>
|
|
79
|
+
<Text className="text-sm text-blue-600 dark:text-blue-400">
|
|
80
|
+
{isVisible ? '▲' : '▼'} {toggleLabel}
|
|
81
|
+
</Text>
|
|
82
|
+
</Pressable>
|
|
83
|
+
|
|
84
|
+
{isVisible && <EmailInputField {...fieldProps} />}
|
|
85
|
+
</View>
|
|
86
|
+
);
|
|
87
|
+
};
|
|
88
|
+
|
|
89
|
+
export interface EmailInputGroupProps extends ViewProps {
|
|
90
|
+
to: string;
|
|
91
|
+
onToChange: (value: string) => void;
|
|
92
|
+
cc?: string;
|
|
93
|
+
onCcChange?: (value: string) => void;
|
|
94
|
+
bcc?: string;
|
|
95
|
+
onBccChange?: (value: string) => void;
|
|
96
|
+
showCc?: boolean;
|
|
97
|
+
showBcc?: boolean;
|
|
98
|
+
onToggleCc?: () => void;
|
|
99
|
+
onToggleBcc?: () => void;
|
|
100
|
+
errors?: {
|
|
101
|
+
to?: string;
|
|
102
|
+
cc?: string;
|
|
103
|
+
bcc?: string;
|
|
104
|
+
};
|
|
105
|
+
labels?: {
|
|
106
|
+
to?: string;
|
|
107
|
+
cc?: string;
|
|
108
|
+
bcc?: string;
|
|
109
|
+
addCc?: string;
|
|
110
|
+
removeCc?: string;
|
|
111
|
+
addBcc?: string;
|
|
112
|
+
removeBcc?: string;
|
|
113
|
+
};
|
|
114
|
+
placeholders?: {
|
|
115
|
+
to?: string;
|
|
116
|
+
cc?: string;
|
|
117
|
+
bcc?: string;
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
/**
|
|
122
|
+
* EmailInputGroup component for React Native
|
|
123
|
+
* Group of email input fields with collapsible CC/BCC
|
|
124
|
+
*/
|
|
125
|
+
export const EmailInputGroup: React.FC<EmailInputGroupProps> = ({
|
|
126
|
+
to,
|
|
127
|
+
onToChange,
|
|
128
|
+
cc = '',
|
|
129
|
+
onCcChange,
|
|
130
|
+
bcc = '',
|
|
131
|
+
onBccChange,
|
|
132
|
+
showCc = false,
|
|
133
|
+
showBcc = false,
|
|
134
|
+
onToggleCc,
|
|
135
|
+
onToggleBcc,
|
|
136
|
+
errors = {},
|
|
137
|
+
className,
|
|
138
|
+
labels = {},
|
|
139
|
+
placeholders = {},
|
|
140
|
+
...props
|
|
141
|
+
}) => {
|
|
142
|
+
const defaultLabels = {
|
|
143
|
+
to: 'To',
|
|
144
|
+
cc: 'CC',
|
|
145
|
+
bcc: 'BCC',
|
|
146
|
+
addCc: 'Add CC',
|
|
147
|
+
removeCc: 'Remove CC',
|
|
148
|
+
addBcc: 'Add BCC',
|
|
149
|
+
removeBcc: 'Remove BCC',
|
|
150
|
+
};
|
|
151
|
+
|
|
152
|
+
const defaultPlaceholders = {
|
|
153
|
+
to: 'recipient@example.com',
|
|
154
|
+
cc: 'cc@example.com',
|
|
155
|
+
bcc: 'bcc@example.com',
|
|
156
|
+
};
|
|
157
|
+
|
|
158
|
+
const finalLabels = { ...defaultLabels, ...labels };
|
|
159
|
+
const finalPlaceholders = { ...defaultPlaceholders, ...placeholders };
|
|
160
|
+
|
|
161
|
+
return (
|
|
162
|
+
<View className={cn('gap-4', className)} {...props}>
|
|
163
|
+
{/* To Field - Always visible */}
|
|
164
|
+
<EmailInputField
|
|
165
|
+
label={finalLabels.to}
|
|
166
|
+
value={to}
|
|
167
|
+
onChangeText={onToChange}
|
|
168
|
+
placeholder={finalPlaceholders.to}
|
|
169
|
+
required
|
|
170
|
+
error={errors.to}
|
|
171
|
+
/>
|
|
172
|
+
|
|
173
|
+
{/* CC Field - Collapsible */}
|
|
174
|
+
{onToggleCc && onCcChange && (
|
|
175
|
+
<CollapsibleEmailField
|
|
176
|
+
label={finalLabels.cc}
|
|
177
|
+
value={cc}
|
|
178
|
+
onChangeText={onCcChange}
|
|
179
|
+
placeholder={finalPlaceholders.cc}
|
|
180
|
+
error={errors.cc}
|
|
181
|
+
isVisible={showCc}
|
|
182
|
+
onToggle={onToggleCc}
|
|
183
|
+
showLabel={finalLabels.addCc}
|
|
184
|
+
hideLabel={finalLabels.removeCc}
|
|
185
|
+
/>
|
|
186
|
+
)}
|
|
187
|
+
|
|
188
|
+
{/* BCC Field - Collapsible */}
|
|
189
|
+
{onToggleBcc && onBccChange && (
|
|
190
|
+
<CollapsibleEmailField
|
|
191
|
+
label={finalLabels.bcc}
|
|
192
|
+
value={bcc}
|
|
193
|
+
onChangeText={onBccChange}
|
|
194
|
+
placeholder={finalPlaceholders.bcc}
|
|
195
|
+
error={errors.bcc}
|
|
196
|
+
isVisible={showBcc}
|
|
197
|
+
onToggle={onToggleBcc}
|
|
198
|
+
showLabel={finalLabels.addBcc}
|
|
199
|
+
hideLabel={finalLabels.removeBcc}
|
|
200
|
+
/>
|
|
201
|
+
)}
|
|
202
|
+
</View>
|
|
203
|
+
);
|
|
204
|
+
};
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { Text, Pressable, type ViewProps } from 'react-native';
|
|
3
|
+
import { cn } from '@sudobility/components-rn';
|
|
4
|
+
|
|
5
|
+
export interface EmailTemplateProps extends ViewProps {
|
|
6
|
+
disabled?: boolean;
|
|
7
|
+
onPress?: () => void;
|
|
8
|
+
children?: React.ReactNode;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* EmailTemplate component for React Native
|
|
13
|
+
* Email template display container
|
|
14
|
+
*/
|
|
15
|
+
export const EmailTemplate: React.FC<EmailTemplateProps> = ({
|
|
16
|
+
className,
|
|
17
|
+
children,
|
|
18
|
+
disabled = false,
|
|
19
|
+
onPress,
|
|
20
|
+
...props
|
|
21
|
+
}) => {
|
|
22
|
+
return (
|
|
23
|
+
<Pressable
|
|
24
|
+
onPress={disabled ? undefined : onPress}
|
|
25
|
+
disabled={disabled}
|
|
26
|
+
accessibilityRole="button"
|
|
27
|
+
accessibilityLabel="Email Template"
|
|
28
|
+
accessibilityState={{ disabled }}
|
|
29
|
+
className={cn(
|
|
30
|
+
'p-4 rounded-lg border',
|
|
31
|
+
'bg-white dark:bg-gray-900',
|
|
32
|
+
'border-gray-200 dark:border-gray-700',
|
|
33
|
+
disabled && 'opacity-50',
|
|
34
|
+
'active:bg-gray-50 dark:active:bg-gray-800',
|
|
35
|
+
className
|
|
36
|
+
)}
|
|
37
|
+
{...props}
|
|
38
|
+
>
|
|
39
|
+
{children || (
|
|
40
|
+
<Text className="text-gray-900 dark:text-white">
|
|
41
|
+
EmailTemplate Component
|
|
42
|
+
</Text>
|
|
43
|
+
)}
|
|
44
|
+
</Pressable>
|
|
45
|
+
);
|
|
46
|
+
};
|
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { View, Text, Pressable, Linking, type ViewProps } from 'react-native';
|
|
3
|
+
import { cn } from '@sudobility/components-rn';
|
|
4
|
+
|
|
5
|
+
type BannerVariant = 'default' | 'compact' | 'minimal' | 'vibrant';
|
|
6
|
+
type BannerSize = 'default' | 'compact' | 'large';
|
|
7
|
+
|
|
8
|
+
export interface FreeEmailBannerProps extends ViewProps {
|
|
9
|
+
variant?: BannerVariant;
|
|
10
|
+
size?: BannerSize;
|
|
11
|
+
message?: string;
|
|
12
|
+
ctaText?: string;
|
|
13
|
+
ctaLink?: string;
|
|
14
|
+
showBadge?: boolean;
|
|
15
|
+
badgeText?: string;
|
|
16
|
+
onDismiss?: () => void;
|
|
17
|
+
isDismissible?: boolean;
|
|
18
|
+
dismissAriaLabel?: string;
|
|
19
|
+
onCtaPress?: () => void;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
const getBannerStyle = (variant: BannerVariant) => {
|
|
23
|
+
switch (variant) {
|
|
24
|
+
case 'compact':
|
|
25
|
+
return 'bg-green-50 dark:bg-green-900/10 border-green-200 dark:border-green-800';
|
|
26
|
+
case 'minimal':
|
|
27
|
+
return 'bg-gray-50 dark:bg-gray-900/50 border-gray-200 dark:border-gray-700';
|
|
28
|
+
case 'vibrant':
|
|
29
|
+
return 'bg-blue-600 border-blue-700';
|
|
30
|
+
default:
|
|
31
|
+
return 'bg-green-100 dark:bg-green-900/20 border-green-200 dark:border-green-700';
|
|
32
|
+
}
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
const getSizeStyle = (size: BannerSize) => {
|
|
36
|
+
switch (size) {
|
|
37
|
+
case 'compact':
|
|
38
|
+
return 'py-3';
|
|
39
|
+
case 'large':
|
|
40
|
+
return 'py-6';
|
|
41
|
+
default:
|
|
42
|
+
return 'py-4';
|
|
43
|
+
}
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
const getTextStyle = (variant: BannerVariant) => {
|
|
47
|
+
switch (variant) {
|
|
48
|
+
case 'compact':
|
|
49
|
+
return 'text-green-700 dark:text-green-300';
|
|
50
|
+
case 'minimal':
|
|
51
|
+
return 'text-gray-700 dark:text-gray-300';
|
|
52
|
+
case 'vibrant':
|
|
53
|
+
return 'text-white';
|
|
54
|
+
default:
|
|
55
|
+
return 'text-green-800 dark:text-green-200';
|
|
56
|
+
}
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
const getButtonStyle = (variant: BannerVariant) => {
|
|
60
|
+
switch (variant) {
|
|
61
|
+
case 'compact':
|
|
62
|
+
return 'bg-green-600 active:bg-green-700';
|
|
63
|
+
case 'minimal':
|
|
64
|
+
return 'bg-blue-600 active:bg-blue-700';
|
|
65
|
+
case 'vibrant':
|
|
66
|
+
return 'bg-white active:bg-gray-100';
|
|
67
|
+
default:
|
|
68
|
+
return 'bg-green-600 active:bg-green-700';
|
|
69
|
+
}
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
const getButtonTextStyle = (variant: BannerVariant) => {
|
|
73
|
+
if (variant === 'vibrant') {
|
|
74
|
+
return 'text-blue-600';
|
|
75
|
+
}
|
|
76
|
+
return 'text-white';
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* FreeEmailBanner component for React Native
|
|
81
|
+
* Promotional banner for free email signup
|
|
82
|
+
*/
|
|
83
|
+
export const FreeEmailBanner: React.FC<FreeEmailBannerProps> = ({
|
|
84
|
+
className,
|
|
85
|
+
variant = 'default',
|
|
86
|
+
size = 'default',
|
|
87
|
+
message = 'Get Your Free Email Address - Start Using Web3 Email Today',
|
|
88
|
+
ctaText = 'Get Free Email',
|
|
89
|
+
ctaLink = '/connect',
|
|
90
|
+
showBadge = true,
|
|
91
|
+
badgeText = 'FREE',
|
|
92
|
+
onDismiss,
|
|
93
|
+
isDismissible = false,
|
|
94
|
+
dismissAriaLabel = 'Dismiss banner',
|
|
95
|
+
onCtaPress,
|
|
96
|
+
...props
|
|
97
|
+
}) => {
|
|
98
|
+
const handleCtaPress = () => {
|
|
99
|
+
if (onCtaPress) {
|
|
100
|
+
onCtaPress();
|
|
101
|
+
} else if (ctaLink.startsWith('http')) {
|
|
102
|
+
Linking.openURL(ctaLink);
|
|
103
|
+
}
|
|
104
|
+
};
|
|
105
|
+
|
|
106
|
+
return (
|
|
107
|
+
<View
|
|
108
|
+
className={cn(
|
|
109
|
+
'border-b px-4',
|
|
110
|
+
getBannerStyle(variant),
|
|
111
|
+
getSizeStyle(size),
|
|
112
|
+
className
|
|
113
|
+
)}
|
|
114
|
+
accessibilityLabel="Free Email Banner"
|
|
115
|
+
{...props}
|
|
116
|
+
>
|
|
117
|
+
<View className="items-center gap-4">
|
|
118
|
+
{isDismissible && onDismiss && (
|
|
119
|
+
<Pressable
|
|
120
|
+
onPress={onDismiss}
|
|
121
|
+
accessibilityRole="button"
|
|
122
|
+
accessibilityLabel={dismissAriaLabel}
|
|
123
|
+
className="absolute right-2 top-2 p-1 rounded-full"
|
|
124
|
+
>
|
|
125
|
+
<Text className="text-current opacity-60">✕</Text>
|
|
126
|
+
</Pressable>
|
|
127
|
+
)}
|
|
128
|
+
|
|
129
|
+
<View className="flex-row items-center justify-center flex-wrap gap-2">
|
|
130
|
+
{showBadge && (
|
|
131
|
+
<View
|
|
132
|
+
className={cn(
|
|
133
|
+
'px-3 py-1 rounded-full',
|
|
134
|
+
variant === 'vibrant' ? 'bg-white' : 'bg-green-500'
|
|
135
|
+
)}
|
|
136
|
+
>
|
|
137
|
+
<Text
|
|
138
|
+
className={cn(
|
|
139
|
+
'text-xs font-bold',
|
|
140
|
+
variant === 'vibrant' ? 'text-blue-600' : 'text-white'
|
|
141
|
+
)}
|
|
142
|
+
>
|
|
143
|
+
{badgeText}
|
|
144
|
+
</Text>
|
|
145
|
+
</View>
|
|
146
|
+
)}
|
|
147
|
+
<Text className={cn('font-semibold text-center', getTextStyle(variant))}>
|
|
148
|
+
{message}
|
|
149
|
+
</Text>
|
|
150
|
+
</View>
|
|
151
|
+
|
|
152
|
+
<Pressable
|
|
153
|
+
onPress={handleCtaPress}
|
|
154
|
+
accessibilityRole="button"
|
|
155
|
+
className={cn(
|
|
156
|
+
'px-6 py-2 rounded-lg',
|
|
157
|
+
getButtonStyle(variant)
|
|
158
|
+
)}
|
|
159
|
+
>
|
|
160
|
+
<Text className={cn('font-medium', getButtonTextStyle(variant))}>
|
|
161
|
+
{ctaText}
|
|
162
|
+
</Text>
|
|
163
|
+
</Pressable>
|
|
164
|
+
</View>
|
|
165
|
+
</View>
|
|
166
|
+
);
|
|
167
|
+
};
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { View, Text, type ViewProps } from 'react-native';
|
|
3
|
+
import { cn } from '@sudobility/components-rn';
|
|
4
|
+
|
|
5
|
+
export interface SubscriberListProps extends ViewProps {
|
|
6
|
+
disabled?: boolean;
|
|
7
|
+
children?: React.ReactNode;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* SubscriberList component for React Native
|
|
12
|
+
* Email subscriber list display container
|
|
13
|
+
*/
|
|
14
|
+
export const SubscriberList: React.FC<SubscriberListProps> = ({
|
|
15
|
+
className,
|
|
16
|
+
children,
|
|
17
|
+
disabled,
|
|
18
|
+
...props
|
|
19
|
+
}) => {
|
|
20
|
+
return (
|
|
21
|
+
<View
|
|
22
|
+
className={cn(
|
|
23
|
+
'p-4 rounded-lg border',
|
|
24
|
+
'bg-white dark:bg-gray-900',
|
|
25
|
+
'border-gray-200 dark:border-gray-700',
|
|
26
|
+
disabled && 'opacity-50',
|
|
27
|
+
className
|
|
28
|
+
)}
|
|
29
|
+
accessibilityLabel="Subscriber List"
|
|
30
|
+
{...props}
|
|
31
|
+
>
|
|
32
|
+
{children || (
|
|
33
|
+
<Text className="text-gray-900 dark:text-white">
|
|
34
|
+
SubscriberList Component
|
|
35
|
+
</Text>
|
|
36
|
+
)}
|
|
37
|
+
</View>
|
|
38
|
+
);
|
|
39
|
+
};
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { Text, Pressable, type ViewProps } from 'react-native';
|
|
3
|
+
import { cn } from '@sudobility/components-rn';
|
|
4
|
+
|
|
5
|
+
export interface SubscriptionPlanProps extends ViewProps {
|
|
6
|
+
disabled?: boolean;
|
|
7
|
+
onPress?: () => void;
|
|
8
|
+
children?: React.ReactNode;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* SubscriptionPlan component for React Native
|
|
13
|
+
* Subscription plan display container
|
|
14
|
+
*/
|
|
15
|
+
export const SubscriptionPlan: React.FC<SubscriptionPlanProps> = ({
|
|
16
|
+
className,
|
|
17
|
+
children,
|
|
18
|
+
disabled = false,
|
|
19
|
+
onPress,
|
|
20
|
+
...props
|
|
21
|
+
}) => {
|
|
22
|
+
return (
|
|
23
|
+
<Pressable
|
|
24
|
+
onPress={disabled ? undefined : onPress}
|
|
25
|
+
disabled={disabled}
|
|
26
|
+
accessibilityRole="button"
|
|
27
|
+
accessibilityLabel="Subscription Plan"
|
|
28
|
+
accessibilityState={{ disabled }}
|
|
29
|
+
className={cn(
|
|
30
|
+
'p-4 rounded-lg border',
|
|
31
|
+
'bg-white dark:bg-gray-900',
|
|
32
|
+
'border-gray-200 dark:border-gray-700',
|
|
33
|
+
disabled && 'opacity-50',
|
|
34
|
+
'active:bg-gray-50 dark:active:bg-gray-800',
|
|
35
|
+
className
|
|
36
|
+
)}
|
|
37
|
+
{...props}
|
|
38
|
+
>
|
|
39
|
+
{children || (
|
|
40
|
+
<Text className="text-gray-900 dark:text-white">
|
|
41
|
+
SubscriptionPlan Component
|
|
42
|
+
</Text>
|
|
43
|
+
)}
|
|
44
|
+
</Pressable>
|
|
45
|
+
);
|
|
46
|
+
};
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @sudobility/email-components-rn
|
|
3
|
+
* React Native Email components for Sudobility
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
export { AbTestEmail, type AbTestEmailProps } from './AbTestEmail';
|
|
7
|
+
export { ContactCard, type ContactCardProps } from './ContactCard';
|
|
8
|
+
export {
|
|
9
|
+
EmailAccountsList,
|
|
10
|
+
type EmailAccountsListProps,
|
|
11
|
+
type EmailAccount,
|
|
12
|
+
type WalletEmailGroup,
|
|
13
|
+
} from './EmailAccountsList';
|
|
14
|
+
export { EmailAnalytics, type EmailAnalyticsProps } from './EmailAnalytics';
|
|
15
|
+
export { EmailCampaign, type EmailCampaignProps } from './EmailCampaign';
|
|
16
|
+
export {
|
|
17
|
+
EmailInputGroup,
|
|
18
|
+
EmailInputField,
|
|
19
|
+
CollapsibleEmailField,
|
|
20
|
+
type EmailInputGroupProps,
|
|
21
|
+
type EmailInputFieldProps,
|
|
22
|
+
type CollapsibleEmailFieldProps,
|
|
23
|
+
} from './EmailInputGroup';
|
|
24
|
+
export { EmailTemplate, type EmailTemplateProps } from './EmailTemplate';
|
|
25
|
+
export { FreeEmailBanner, type FreeEmailBannerProps } from './FreeEmailBanner';
|
|
26
|
+
export { SubscriberList, type SubscriberListProps } from './SubscriberList';
|
|
27
|
+
export { SubscriptionPlan, type SubscriptionPlanProps } from './SubscriptionPlan';
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
// Type declarations for NativeWind className prop
|
|
2
|
+
import 'react-native';
|
|
3
|
+
|
|
4
|
+
declare module 'react-native' {
|
|
5
|
+
interface ViewProps {
|
|
6
|
+
className?: string;
|
|
7
|
+
}
|
|
8
|
+
interface TextProps {
|
|
9
|
+
className?: string;
|
|
10
|
+
}
|
|
11
|
+
interface ImageProps {
|
|
12
|
+
className?: string;
|
|
13
|
+
}
|
|
14
|
+
interface PressableProps {
|
|
15
|
+
className?: string;
|
|
16
|
+
}
|
|
17
|
+
interface TouchableOpacityProps {
|
|
18
|
+
className?: string;
|
|
19
|
+
}
|
|
20
|
+
interface ScrollViewProps {
|
|
21
|
+
className?: string;
|
|
22
|
+
}
|
|
23
|
+
}
|