@terreno/ui 0.1.0 → 0.2.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.
Files changed (64) hide show
  1. package/dist/Common.d.ts +44 -0
  2. package/dist/SocialLoginButton.d.ts +19 -0
  3. package/dist/SocialLoginButton.js +119 -0
  4. package/dist/SocialLoginButton.js.map +1 -0
  5. package/dist/index.d.ts +3 -0
  6. package/dist/index.js +3 -0
  7. package/dist/index.js.map +1 -1
  8. package/dist/login/LoginScreen.d.ts +25 -0
  9. package/dist/login/LoginScreen.js +55 -0
  10. package/dist/login/LoginScreen.js.map +1 -0
  11. package/dist/login/index.d.ts +2 -0
  12. package/dist/login/index.js +2 -0
  13. package/dist/login/index.js.map +1 -0
  14. package/dist/login/loginTypes.d.ts +48 -0
  15. package/dist/login/loginTypes.js +2 -0
  16. package/dist/login/loginTypes.js.map +1 -0
  17. package/dist/signUp/OAuthButtons.d.ts +18 -0
  18. package/dist/signUp/OAuthButtons.js +15 -0
  19. package/dist/signUp/OAuthButtons.js.map +1 -0
  20. package/dist/signUp/PasswordRequirements.d.ts +15 -0
  21. package/dist/signUp/PasswordRequirements.js +14 -0
  22. package/dist/signUp/PasswordRequirements.js.map +1 -0
  23. package/dist/signUp/SignUpScreen.d.ts +26 -0
  24. package/dist/signUp/SignUpScreen.js +64 -0
  25. package/dist/signUp/SignUpScreen.js.map +1 -0
  26. package/dist/signUp/Swiper.d.ts +13 -0
  27. package/dist/signUp/Swiper.js +16 -0
  28. package/dist/signUp/Swiper.js.map +1 -0
  29. package/dist/signUp/index.d.ts +6 -0
  30. package/dist/signUp/index.js +6 -0
  31. package/dist/signUp/index.js.map +1 -0
  32. package/dist/signUp/passwordPresets.d.ts +9 -0
  33. package/dist/signUp/passwordPresets.js +41 -0
  34. package/dist/signUp/passwordPresets.js.map +1 -0
  35. package/dist/signUp/signUpTypes.d.ts +90 -0
  36. package/dist/signUp/signUpTypes.js +2 -0
  37. package/dist/signUp/signUpTypes.js.map +1 -0
  38. package/package.json +3 -2
  39. package/src/Common.ts +52 -0
  40. package/src/SocialLoginButton.test.tsx +158 -0
  41. package/src/SocialLoginButton.tsx +182 -0
  42. package/src/__snapshots__/SocialLoginButton.test.tsx.snap +277 -0
  43. package/src/index.tsx +4 -0
  44. package/src/login/LoginScreen.test.tsx +148 -0
  45. package/src/login/LoginScreen.tsx +159 -0
  46. package/src/login/__snapshots__/LoginScreen.test.tsx.snap +630 -0
  47. package/src/login/index.ts +2 -0
  48. package/src/login/loginTypes.ts +51 -0
  49. package/src/signUp/OAuthButtons.test.tsx +45 -0
  50. package/src/signUp/OAuthButtons.tsx +52 -0
  51. package/src/signUp/PasswordRequirements.test.tsx +41 -0
  52. package/src/signUp/PasswordRequirements.tsx +49 -0
  53. package/src/signUp/SignUpScreen.test.tsx +134 -0
  54. package/src/signUp/SignUpScreen.tsx +172 -0
  55. package/src/signUp/Swiper.test.tsx +46 -0
  56. package/src/signUp/Swiper.tsx +59 -0
  57. package/src/signUp/__snapshots__/OAuthButtons.test.tsx.snap +272 -0
  58. package/src/signUp/__snapshots__/PasswordRequirements.test.tsx.snap +427 -0
  59. package/src/signUp/__snapshots__/SignUpScreen.test.tsx.snap +851 -0
  60. package/src/signUp/__snapshots__/Swiper.test.tsx.snap +249 -0
  61. package/src/signUp/index.ts +13 -0
  62. package/src/signUp/passwordPresets.test.ts +57 -0
  63. package/src/signUp/passwordPresets.ts +43 -0
  64. package/src/signUp/signUpTypes.ts +94 -0
@@ -0,0 +1,249 @@
1
+ // Bun Snapshot v1, https://bun.sh/docs/test/snapshots
2
+
3
+ exports[`Swiper renders correctly 1`] = `
4
+ {
5
+ "$$typeof": Symbol(react.test.json),
6
+ "children": [
7
+ {
8
+ "$$typeof": Symbol(react.test.json),
9
+ "children": [
10
+ {
11
+ "$$typeof": Symbol(react.test.json),
12
+ "children": [
13
+ {
14
+ "$$typeof": Symbol(react.test.json),
15
+ "children": [
16
+ "Welcome",
17
+ ],
18
+ "props": {
19
+ "numberOfLines": 0,
20
+ "style": {
21
+ "color": "#1C1C1C",
22
+ "fontFamily": "heading-bold",
23
+ "fontSize": 16,
24
+ "textAlign": "center",
25
+ },
26
+ "testID": undefined,
27
+ },
28
+ "type": "Text",
29
+ },
30
+ {
31
+ "$$typeof": Symbol(react.test.json),
32
+ "children": [
33
+ {
34
+ "$$typeof": Symbol(react.test.json),
35
+ "children": [
36
+ {
37
+ "$$typeof": Symbol(react.test.json),
38
+ "children": [
39
+ "Get started with our app",
40
+ ],
41
+ "props": {
42
+ "numberOfLines": 0,
43
+ "selectable": undefined,
44
+ "style": {
45
+ "color": "#686868",
46
+ "fontFamily": "text-regular",
47
+ "fontSize": 14,
48
+ "textAlign": "center",
49
+ },
50
+ "testID": undefined,
51
+ },
52
+ "type": "Text",
53
+ },
54
+ ],
55
+ "props": {},
56
+ "type": "View",
57
+ },
58
+ ],
59
+ "props": {
60
+ "onPointerEnter": [Function: AsyncFunction],
61
+ "onPointerLeave": [Function: AsyncFunction],
62
+ "style": {
63
+ "marginTop": 8,
64
+ },
65
+ "testID": undefined,
66
+ },
67
+ "type": "View",
68
+ },
69
+ ],
70
+ "props": {
71
+ "onPointerEnter": [Function: AsyncFunction],
72
+ "onPointerLeave": [Function: AsyncFunction],
73
+ "style": {
74
+ "alignItems": "center",
75
+ "justifyContent": "center",
76
+ "padding": 16,
77
+ "width": "100%",
78
+ },
79
+ "testID": undefined,
80
+ },
81
+ "type": "View",
82
+ },
83
+ {
84
+ "$$typeof": Symbol(react.test.json),
85
+ "children": [
86
+ {
87
+ "$$typeof": Symbol(react.test.json),
88
+ "children": [
89
+ "Features",
90
+ ],
91
+ "props": {
92
+ "numberOfLines": 0,
93
+ "style": {
94
+ "color": "#1C1C1C",
95
+ "fontFamily": "heading-bold",
96
+ "fontSize": 16,
97
+ "textAlign": "center",
98
+ },
99
+ "testID": undefined,
100
+ },
101
+ "type": "Text",
102
+ },
103
+ {
104
+ "$$typeof": Symbol(react.test.json),
105
+ "children": [
106
+ {
107
+ "$$typeof": Symbol(react.test.json),
108
+ "children": [
109
+ {
110
+ "$$typeof": Symbol(react.test.json),
111
+ "children": [
112
+ "Discover what we offer",
113
+ ],
114
+ "props": {
115
+ "numberOfLines": 0,
116
+ "selectable": undefined,
117
+ "style": {
118
+ "color": "#686868",
119
+ "fontFamily": "text-regular",
120
+ "fontSize": 14,
121
+ "textAlign": "center",
122
+ },
123
+ "testID": undefined,
124
+ },
125
+ "type": "Text",
126
+ },
127
+ ],
128
+ "props": {},
129
+ "type": "View",
130
+ },
131
+ ],
132
+ "props": {
133
+ "onPointerEnter": [Function: AsyncFunction],
134
+ "onPointerLeave": [Function: AsyncFunction],
135
+ "style": {
136
+ "marginTop": 8,
137
+ },
138
+ "testID": undefined,
139
+ },
140
+ "type": "View",
141
+ },
142
+ ],
143
+ "props": {
144
+ "onPointerEnter": [Function: AsyncFunction],
145
+ "onPointerLeave": [Function: AsyncFunction],
146
+ "style": {
147
+ "alignItems": "center",
148
+ "justifyContent": "center",
149
+ "padding": 16,
150
+ "width": "100%",
151
+ },
152
+ "testID": undefined,
153
+ },
154
+ "type": "View",
155
+ },
156
+ {
157
+ "$$typeof": Symbol(react.test.json),
158
+ "children": [
159
+ {
160
+ "$$typeof": Symbol(react.test.json),
161
+ "children": [
162
+ "Ready?",
163
+ ],
164
+ "props": {
165
+ "numberOfLines": 0,
166
+ "style": {
167
+ "color": "#1C1C1C",
168
+ "fontFamily": "heading-bold",
169
+ "fontSize": 16,
170
+ "textAlign": "center",
171
+ },
172
+ "testID": undefined,
173
+ },
174
+ "type": "Text",
175
+ },
176
+ {
177
+ "$$typeof": Symbol(react.test.json),
178
+ "children": [
179
+ {
180
+ "$$typeof": Symbol(react.test.json),
181
+ "children": [
182
+ {
183
+ "$$typeof": Symbol(react.test.json),
184
+ "children": [
185
+ "Create your account",
186
+ ],
187
+ "props": {
188
+ "numberOfLines": 0,
189
+ "selectable": undefined,
190
+ "style": {
191
+ "color": "#686868",
192
+ "fontFamily": "text-regular",
193
+ "fontSize": 14,
194
+ "textAlign": "center",
195
+ },
196
+ "testID": undefined,
197
+ },
198
+ "type": "Text",
199
+ },
200
+ ],
201
+ "props": {},
202
+ "type": "View",
203
+ },
204
+ ],
205
+ "props": {
206
+ "onPointerEnter": [Function: AsyncFunction],
207
+ "onPointerLeave": [Function: AsyncFunction],
208
+ "style": {
209
+ "marginTop": 8,
210
+ },
211
+ "testID": undefined,
212
+ },
213
+ "type": "View",
214
+ },
215
+ ],
216
+ "props": {
217
+ "onPointerEnter": [Function: AsyncFunction],
218
+ "onPointerLeave": [Function: AsyncFunction],
219
+ "style": {
220
+ "alignItems": "center",
221
+ "justifyContent": "center",
222
+ "padding": 16,
223
+ "width": "100%",
224
+ },
225
+ "testID": undefined,
226
+ },
227
+ "type": "View",
228
+ },
229
+ ],
230
+ "props": {
231
+ "style": undefined,
232
+ "testID": "swiper-flatlist",
233
+ },
234
+ "type": "View",
235
+ },
236
+ ],
237
+ "props": {
238
+ "onPointerEnter": [Function: AsyncFunction],
239
+ "onPointerLeave": [Function: AsyncFunction],
240
+ "style": {
241
+ "height": 300,
242
+ "testID": "swiper",
243
+ "width": "100%",
244
+ },
245
+ "testID": "swiper",
246
+ },
247
+ "type": "View",
248
+ }
249
+ `;
@@ -0,0 +1,13 @@
1
+ export {OAuthButtons} from "./OAuthButtons";
2
+ export {PasswordRequirements} from "./PasswordRequirements";
3
+ export {defaultPasswordRequirements, simplePasswordRequirements} from "./passwordPresets";
4
+ export {SignUpScreen} from "./SignUpScreen";
5
+ export {Swiper} from "./Swiper";
6
+ export type {
7
+ OAuthProvider,
8
+ OAuthProviderConfig,
9
+ OnboardingPage,
10
+ PasswordRequirement,
11
+ SignUpFieldConfig,
12
+ SignUpScreenProps,
13
+ } from "./signUpTypes";
@@ -0,0 +1,57 @@
1
+ import {describe, expect, it} from "bun:test";
2
+
3
+ import {defaultPasswordRequirements, simplePasswordRequirements} from "./passwordPresets";
4
+
5
+ describe("defaultPasswordRequirements", () => {
6
+ it("has 5 requirements", () => {
7
+ expect(defaultPasswordRequirements).toHaveLength(5);
8
+ });
9
+
10
+ it("validates minimum length of 8 characters", () => {
11
+ const req = defaultPasswordRequirements.find((r) => r.key === "minLength")!;
12
+ expect(req.validate("short")).toBe(false);
13
+ expect(req.validate("longenough")).toBe(true);
14
+ });
15
+
16
+ it("validates uppercase letter", () => {
17
+ const req = defaultPasswordRequirements.find((r) => r.key === "uppercase")!;
18
+ expect(req.validate("lowercase")).toBe(false);
19
+ expect(req.validate("Uppercase")).toBe(true);
20
+ });
21
+
22
+ it("validates lowercase letter", () => {
23
+ const req = defaultPasswordRequirements.find((r) => r.key === "lowercase")!;
24
+ expect(req.validate("UPPERCASE")).toBe(false);
25
+ expect(req.validate("lowercase")).toBe(true);
26
+ });
27
+
28
+ it("validates number", () => {
29
+ const req = defaultPasswordRequirements.find((r) => r.key === "number")!;
30
+ expect(req.validate("noDigits")).toBe(false);
31
+ expect(req.validate("has1digit")).toBe(true);
32
+ });
33
+
34
+ it("validates special character", () => {
35
+ const req = defaultPasswordRequirements.find((r) => r.key === "special")!;
36
+ expect(req.validate("noSpecial1")).toBe(false);
37
+ expect(req.validate("special!")).toBe(true);
38
+ });
39
+
40
+ it("passes all requirements for a strong password", () => {
41
+ const strongPassword = "MyP@ssw0rd!";
42
+ const allMet = defaultPasswordRequirements.every((r) => r.validate(strongPassword));
43
+ expect(allMet).toBe(true);
44
+ });
45
+ });
46
+
47
+ describe("simplePasswordRequirements", () => {
48
+ it("has 1 requirement", () => {
49
+ expect(simplePasswordRequirements).toHaveLength(1);
50
+ });
51
+
52
+ it("validates minimum length of 6 characters", () => {
53
+ const req = simplePasswordRequirements[0];
54
+ expect(req.validate("short")).toBe(false);
55
+ expect(req.validate("enough")).toBe(true);
56
+ });
57
+ });
@@ -0,0 +1,43 @@
1
+ import type {PasswordRequirement} from "./signUpTypes";
2
+
3
+ /**
4
+ * Default password requirements with strong validation rules.
5
+ */
6
+ export const defaultPasswordRequirements: PasswordRequirement[] = [
7
+ {
8
+ key: "minLength",
9
+ label: "At least 8 characters",
10
+ validate: (password: string) => password.length >= 8,
11
+ },
12
+ {
13
+ key: "uppercase",
14
+ label: "At least one uppercase letter",
15
+ validate: (password: string) => /[A-Z]/.test(password),
16
+ },
17
+ {
18
+ key: "lowercase",
19
+ label: "At least one lowercase letter",
20
+ validate: (password: string) => /[a-z]/.test(password),
21
+ },
22
+ {
23
+ key: "number",
24
+ label: "At least one number",
25
+ validate: (password: string) => /\d/.test(password),
26
+ },
27
+ {
28
+ key: "special",
29
+ label: "At least one special character",
30
+ validate: (password: string) => /[!@#$%^&*(),.?":{}|<>]/.test(password),
31
+ },
32
+ ];
33
+
34
+ /**
35
+ * Simple password requirements with minimal validation.
36
+ */
37
+ export const simplePasswordRequirements: PasswordRequirement[] = [
38
+ {
39
+ key: "minLength",
40
+ label: "At least 6 characters",
41
+ validate: (password: string) => password.length >= 6,
42
+ },
43
+ ];
@@ -0,0 +1,94 @@
1
+ import type {ReactNode} from "react";
2
+
3
+ /**
4
+ * Supported OAuth providers for social login buttons.
5
+ */
6
+ export type OAuthProvider = "google" | "github" | "apple";
7
+
8
+ /**
9
+ * Configuration for an OAuth provider button.
10
+ */
11
+ export interface OAuthProviderConfig {
12
+ /** The OAuth provider identifier. */
13
+ provider: OAuthProvider;
14
+ /** Callback triggered when the provider button is pressed. */
15
+ onPress: () => Promise<void>;
16
+ /** Whether the button is in a loading state. */
17
+ loading?: boolean;
18
+ /** Whether the button is disabled. */
19
+ disabled?: boolean;
20
+ }
21
+
22
+ /**
23
+ * Configuration for a sign-up form field.
24
+ */
25
+ export interface SignUpFieldConfig {
26
+ /** Unique field name used as the key in form state. */
27
+ name: string;
28
+ /** Display label for the field. */
29
+ label: string;
30
+ /** Placeholder text shown when the field is empty. */
31
+ placeholder?: string;
32
+ /** Input type for the field. */
33
+ type?: "text" | "email" | "password";
34
+ /** Whether the field is required. */
35
+ required?: boolean;
36
+ /** Auto-complete hint for the field. */
37
+ autoComplete?: "current-password" | "on" | "off" | "username";
38
+ }
39
+
40
+ /**
41
+ * A single password requirement with a label and validation function.
42
+ */
43
+ export interface PasswordRequirement {
44
+ /** Unique key for the requirement. */
45
+ key: string;
46
+ /** Display label for the requirement. */
47
+ label: string;
48
+ /** Returns true if the password meets this requirement. */
49
+ validate: (password: string) => boolean;
50
+ }
51
+
52
+ /**
53
+ * Configuration for a single onboarding page in the swiper.
54
+ */
55
+ export interface OnboardingPage {
56
+ /** Title text displayed on the page. */
57
+ title: string;
58
+ /** Subtitle or description text. */
59
+ subtitle?: string;
60
+ /** Custom content to render on the page. */
61
+ content?: ReactNode;
62
+ /** Image source for the page. */
63
+ image?: number | {uri: string};
64
+ }
65
+
66
+ /**
67
+ * Props for the SignUpScreen component.
68
+ */
69
+ export interface SignUpScreenProps {
70
+ /** Form field configurations. */
71
+ fields: SignUpFieldConfig[];
72
+ /** Callback triggered on form submission. Receives field values as a record. */
73
+ onSubmit: (values: Record<string, string>) => Promise<void>;
74
+ /** Optional OAuth provider configurations for social login buttons. */
75
+ oauthProviders?: OAuthProviderConfig[];
76
+ /** Password requirements to validate against. */
77
+ passwordRequirements?: PasswordRequirement[];
78
+ /** Onboarding pages to display before the sign-up form. */
79
+ onboardingPages?: OnboardingPage[];
80
+ /** Custom logo or banner to display above the form. */
81
+ logo?: ReactNode;
82
+ /** Title text for the sign-up form. */
83
+ title?: string;
84
+ /** Whether the form is in a loading state. */
85
+ loading?: boolean;
86
+ /** Error message to display. */
87
+ error?: string;
88
+ /** Text for the link to navigate to login. */
89
+ loginLinkText?: string;
90
+ /** Callback triggered when the login link is pressed. */
91
+ onLoginPress?: () => void;
92
+ /** Test ID for the root element. */
93
+ testID?: string;
94
+ }