@stackshift-ui/signin-signup 6.0.2 → 6.0.4
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/chunk-2B4CU465.mjs +1 -0
- package/dist/chunk-H22IRLD6.mjs +1 -0
- package/dist/index.js +1 -1
- package/dist/index.mjs +1 -1
- package/dist/signin-signup.js +1 -1
- package/dist/signin-signup.mjs +1 -1
- package/dist/signin_signup_a.js +1 -1
- package/dist/signin_signup_a.mjs +1 -1
- package/dist/signin_signup_b.js +1 -1
- package/dist/signin_signup_b.mjs +1 -1
- package/package.json +16 -15
- package/src/helper/index.ts +28 -0
- package/src/index.ts +6 -0
- package/src/signin-signup.test.tsx +13 -0
- package/src/signin-signup.tsx +42 -0
- package/src/signin_signup_a.tsx +287 -0
- package/src/signin_signup_b.tsx +257 -0
- package/src/types.ts +412 -0
- package/dist/chunk-32ATTMKN.mjs +0 -1
- package/dist/chunk-MBEAJPNQ.mjs +0 -1
- /package/dist/{chunk-TUQB6PIH.mjs → chunk-FNVCKDMO.mjs} +0 -0
|
@@ -0,0 +1,287 @@
|
|
|
1
|
+
import { Button } from "@stackshift-ui/button";
|
|
2
|
+
import { Container } from "@stackshift-ui/container";
|
|
3
|
+
import { Flex } from "@stackshift-ui/flex";
|
|
4
|
+
import { Form } from "@stackshift-ui/form";
|
|
5
|
+
import { FormField } from "@stackshift-ui/form-field";
|
|
6
|
+
import { Heading } from "@stackshift-ui/heading";
|
|
7
|
+
import { Image } from "@stackshift-ui/image";
|
|
8
|
+
import { Input } from "@stackshift-ui/input";
|
|
9
|
+
import { Link } from "@stackshift-ui/link";
|
|
10
|
+
import { Section } from "@stackshift-ui/section";
|
|
11
|
+
import { Text } from "@stackshift-ui/text";
|
|
12
|
+
import React from "react";
|
|
13
|
+
|
|
14
|
+
import { SignUpFormProps } from ".";
|
|
15
|
+
import { logoLink, thankYouPageLink } from "./helper";
|
|
16
|
+
import { LabeledRoute, LabeledRouteWithKey, Logo, Form as iForm } from "./types";
|
|
17
|
+
|
|
18
|
+
export default function SigninSignup_A({ logo, form, formLinks, signInLink }: SignUpFormProps) {
|
|
19
|
+
return (
|
|
20
|
+
<Section className="py-10 bg-gray-50 lg:py-20">
|
|
21
|
+
<Container maxWidth={576}>
|
|
22
|
+
<LogoSection logo={logo} />
|
|
23
|
+
<Container className="mb-6 text-center lg:mb-10">
|
|
24
|
+
<SubtitleAndHeadingText form={form} />
|
|
25
|
+
<SignupForm
|
|
26
|
+
form={form}
|
|
27
|
+
signInLink={signInLink}
|
|
28
|
+
thankYouPage={thankYouPageLink(form?.thankYouPage)}
|
|
29
|
+
/>
|
|
30
|
+
</Container>
|
|
31
|
+
<FormLinks formLinks={formLinks} />
|
|
32
|
+
</Container>
|
|
33
|
+
</Section>
|
|
34
|
+
);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
function LogoSection({ logo }: { logo?: Logo }) {
|
|
38
|
+
if (!logo) return null;
|
|
39
|
+
|
|
40
|
+
return (
|
|
41
|
+
<div className="mb-10">
|
|
42
|
+
<Link
|
|
43
|
+
aria-label={`Go to ${logoLink(logo) === "/" ? "home page" : logoLink(logo)}`}
|
|
44
|
+
className="flex justify-center mx-auto text-3xl font-bold leading-none"
|
|
45
|
+
href={logoLink(logo)}
|
|
46
|
+
target={logo?.linkTarget}
|
|
47
|
+
rel={logo?.linkTarget === "_blank" ? "noopener noreferrer" : ""}>
|
|
48
|
+
<Image
|
|
49
|
+
src={logo?.image}
|
|
50
|
+
alt={logo?.alt ?? "signup-logo"}
|
|
51
|
+
width={100}
|
|
52
|
+
height={100}
|
|
53
|
+
className="flex justify-center mx-auto text-3xl font-bold leading-none"
|
|
54
|
+
/>
|
|
55
|
+
</Link>
|
|
56
|
+
</div>
|
|
57
|
+
);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
function SubtitleAndHeadingText({ form }: { form?: iForm }) {
|
|
61
|
+
return (
|
|
62
|
+
<div className="mb-6">
|
|
63
|
+
{form?.subtitle ? <Text muted>{form?.subtitle}</Text> : null}
|
|
64
|
+
{form?.name ? <Heading className="text-2xl lg:text-2xl">{form?.name}</Heading> : null}
|
|
65
|
+
</div>
|
|
66
|
+
);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
function SignupForm({
|
|
70
|
+
form,
|
|
71
|
+
signInLink,
|
|
72
|
+
thankYouPage,
|
|
73
|
+
}: {
|
|
74
|
+
form?: iForm;
|
|
75
|
+
signInLink?: LabeledRoute;
|
|
76
|
+
thankYouPage?: LabeledRoute;
|
|
77
|
+
}) {
|
|
78
|
+
if (!form?.fields) return null;
|
|
79
|
+
const [showPassword, setShowPassword] = React.useState(false);
|
|
80
|
+
|
|
81
|
+
return (
|
|
82
|
+
<Form
|
|
83
|
+
id={form?.id ?? undefined}
|
|
84
|
+
name="SignUp-VariantA-Form"
|
|
85
|
+
className="form-signup"
|
|
86
|
+
thankyouPage={thankYouPage}>
|
|
87
|
+
<FormFields form={form} showPassword={showPassword} setShowPassword={setShowPassword} />
|
|
88
|
+
<div>
|
|
89
|
+
<div className="webriq-recaptcha" />
|
|
90
|
+
</div>
|
|
91
|
+
<div className="text-center">
|
|
92
|
+
{form?.buttonLabel && (
|
|
93
|
+
<Button
|
|
94
|
+
as="button"
|
|
95
|
+
variant="custom"
|
|
96
|
+
ariaLabel={form?.buttonLabel ?? "Sign Up form submit button"}
|
|
97
|
+
className="w-full py-4 text-sm font-bold tex-gray-50"
|
|
98
|
+
type="submit">
|
|
99
|
+
{form?.buttonLabel}
|
|
100
|
+
</Button>
|
|
101
|
+
)}
|
|
102
|
+
</div>
|
|
103
|
+
{signInLink && <SignInLink signInLink={signInLink} />}
|
|
104
|
+
</Form>
|
|
105
|
+
);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
function FormFields({
|
|
109
|
+
form,
|
|
110
|
+
showPassword,
|
|
111
|
+
setShowPassword,
|
|
112
|
+
}: {
|
|
113
|
+
form?: iForm;
|
|
114
|
+
showPassword: boolean;
|
|
115
|
+
setShowPassword: React.Dispatch<React.SetStateAction<boolean>>;
|
|
116
|
+
}) {
|
|
117
|
+
return (
|
|
118
|
+
<>
|
|
119
|
+
<Flex wrap className="-mx-2">
|
|
120
|
+
{form?.fields?.slice(0, 2).map((formFields, index) => (
|
|
121
|
+
<div className="w-full px-2 mb-3 lg:w-1/2" key={index}>
|
|
122
|
+
{formFields.type === "inputText" ? (
|
|
123
|
+
<Input
|
|
124
|
+
textSize="sm"
|
|
125
|
+
variant="primary"
|
|
126
|
+
noLabel
|
|
127
|
+
placeholder={formFields?.placeholder}
|
|
128
|
+
required={formFields?.isRequired}
|
|
129
|
+
className="w-full py-4 text-xs bg-white"
|
|
130
|
+
name={formFields?.name}
|
|
131
|
+
ariaLabel={formFields?.label}
|
|
132
|
+
{...formFields}
|
|
133
|
+
type="text"
|
|
134
|
+
/>
|
|
135
|
+
) : (
|
|
136
|
+
<FormField textSize="sm" noLabel name={formFields?.name ?? ""} {...formFields} />
|
|
137
|
+
)}
|
|
138
|
+
</div>
|
|
139
|
+
))}
|
|
140
|
+
</Flex>
|
|
141
|
+
{form?.fields?.slice(2).map((formFields, index) => (
|
|
142
|
+
<div key={index} className="my-3">
|
|
143
|
+
{formFields.type === "inputPassword" ? (
|
|
144
|
+
<PasswordField
|
|
145
|
+
formFields={formFields}
|
|
146
|
+
showPassword={showPassword}
|
|
147
|
+
setShowPassword={setShowPassword}
|
|
148
|
+
/>
|
|
149
|
+
) : (
|
|
150
|
+
<FormField
|
|
151
|
+
className="py-4"
|
|
152
|
+
textSize="sm"
|
|
153
|
+
noLabel
|
|
154
|
+
variant="primary"
|
|
155
|
+
placeholder={formFields?.placeholder}
|
|
156
|
+
required={formFields?.isRequired}
|
|
157
|
+
name={formFields?.name ?? ""}
|
|
158
|
+
items={formFields?.items}
|
|
159
|
+
type={formFields?.type}
|
|
160
|
+
{...formFields}
|
|
161
|
+
/>
|
|
162
|
+
)}
|
|
163
|
+
</div>
|
|
164
|
+
))}
|
|
165
|
+
</>
|
|
166
|
+
);
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
function SignInLink({ signInLink }: { signInLink?: LabeledRoute }) {
|
|
170
|
+
if (!signInLink?.label) return null;
|
|
171
|
+
|
|
172
|
+
return (
|
|
173
|
+
<div className="w-full text-center mt-3">
|
|
174
|
+
<span className="text-xs text-gray-500">Already have an account? </span>
|
|
175
|
+
<Button
|
|
176
|
+
as="link"
|
|
177
|
+
variant="link"
|
|
178
|
+
link={signInLink}
|
|
179
|
+
className="text-xs text-primary cursor-pointer hover:underline"
|
|
180
|
+
ariaLabel={signInLink?.label}>
|
|
181
|
+
{signInLink?.label}
|
|
182
|
+
</Button>
|
|
183
|
+
</div>
|
|
184
|
+
);
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
function PasswordField({
|
|
188
|
+
formFields,
|
|
189
|
+
showPassword,
|
|
190
|
+
setShowPassword,
|
|
191
|
+
}: {
|
|
192
|
+
formFields?: any;
|
|
193
|
+
showPassword: boolean;
|
|
194
|
+
setShowPassword: React.Dispatch<React.SetStateAction<boolean>>;
|
|
195
|
+
}) {
|
|
196
|
+
return (
|
|
197
|
+
<Flex className="relative">
|
|
198
|
+
<Input
|
|
199
|
+
className="py-4"
|
|
200
|
+
textSize="sm"
|
|
201
|
+
noLabel
|
|
202
|
+
aria-label={formFields?.placeholder ?? formFields?.name}
|
|
203
|
+
variant="primary"
|
|
204
|
+
type={showPassword ? "text" : "password"}
|
|
205
|
+
placeholder={formFields?.placeholder}
|
|
206
|
+
name={formFields?.name}
|
|
207
|
+
required={formFields?.isRequired}
|
|
208
|
+
/>
|
|
209
|
+
<Button
|
|
210
|
+
as="button"
|
|
211
|
+
variant="unstyled"
|
|
212
|
+
ariaLabel={showPassword ? "Show password" : "Hide password"}
|
|
213
|
+
className="absolute top-0 right-0 h-full p-2"
|
|
214
|
+
type="button"
|
|
215
|
+
onClick={() => setShowPassword(!showPassword)}>
|
|
216
|
+
<PasswordIcon showPassword={showPassword} />
|
|
217
|
+
</Button>
|
|
218
|
+
</Flex>
|
|
219
|
+
);
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
function FormLinks({ formLinks }: { formLinks?: LabeledRouteWithKey[] }) {
|
|
223
|
+
if (!formLinks) return null;
|
|
224
|
+
|
|
225
|
+
return (
|
|
226
|
+
<p className="mt-10 text-xs text-center text-gray-700">
|
|
227
|
+
{formLinks?.map((link: any, index: number, { length }: any) => (
|
|
228
|
+
<span key={index}>
|
|
229
|
+
<Button
|
|
230
|
+
as="link"
|
|
231
|
+
variant="link"
|
|
232
|
+
link={link}
|
|
233
|
+
className="text-xs text-primary cursor-pointer hover:underline"
|
|
234
|
+
ariaLabel={link?.label}>
|
|
235
|
+
{link?.label}
|
|
236
|
+
</Button>
|
|
237
|
+
{index === length - 1 ? null : index === length - 2 ? (
|
|
238
|
+
<span> and </span>
|
|
239
|
+
) : (
|
|
240
|
+
<span> , </span>
|
|
241
|
+
)}
|
|
242
|
+
</span>
|
|
243
|
+
))}
|
|
244
|
+
</p>
|
|
245
|
+
);
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
function PasswordIcon({ showPassword }: { showPassword: boolean }) {
|
|
249
|
+
return (
|
|
250
|
+
<>
|
|
251
|
+
{showPassword ? (
|
|
252
|
+
<svg
|
|
253
|
+
className="w-5 h-5 my-auto ml-4 text-gray-500"
|
|
254
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
255
|
+
aria-hidden="true"
|
|
256
|
+
role="img"
|
|
257
|
+
width="1em"
|
|
258
|
+
height="1em"
|
|
259
|
+
preserveAspectRatio="xMidYMid meet"
|
|
260
|
+
viewBox="0 0 16 16">
|
|
261
|
+
<g fill="currentColor">
|
|
262
|
+
<path d="M13.359 11.238C15.06 9.72 16 8 16 8s-3-5.5-8-5.5a7.028 7.028 0 0 0-2.79.588l.77.771A5.944 5.944 0 0 1 8 3.5c2.12 0 3.879 1.168 5.168 2.457A13.134 13.134 0 0 1 14.828 8c-.058.087-.122.183-.195.288c-.335.48-.83 1.12-1.465 1.755c-.165.165-.337.328-.517.486l.708.709z" />
|
|
263
|
+
<path d="M11.297 9.176a3.5 3.5 0 0 0-4.474-4.474l.823.823a2.5 2.5 0 0 1 2.829 2.829l.822.822zm-2.943 1.299l.822.822a3.5 3.5 0 0 1-4.474-4.474l.823.823a2.5 2.5 0 0 0 2.829 2.829z" />
|
|
264
|
+
<path d="M3.35 5.47c-.18.16-.353.322-.518.487A13.134 13.134 0 0 0 1.172 8l.195.288c.335.48.83 1.12 1.465 1.755C4.121 11.332 5.881 12.5 8 12.5c.716 0 1.39-.133 2.02-.36l.77.772A7.029 7.029 0 0 1 8 13.5C3 13.5 0 8 0 8s.939-1.721 2.641-3.238l.708.709zm10.296 8.884l-12-12l.708-.708l12 12l-.708.708z" />
|
|
265
|
+
</g>
|
|
266
|
+
</svg>
|
|
267
|
+
) : (
|
|
268
|
+
<svg
|
|
269
|
+
className="w-5 h-5 my-auto ml-4 text-gray-500"
|
|
270
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
271
|
+
aria-hidden="true"
|
|
272
|
+
role="img"
|
|
273
|
+
width="1em"
|
|
274
|
+
height="1em"
|
|
275
|
+
preserveAspectRatio="xMidYMid meet"
|
|
276
|
+
viewBox="0 0 16 16">
|
|
277
|
+
<g fill="currentColor">
|
|
278
|
+
<path d="M16 8s-3-5.5-8-5.5S0 8 0 8s3 5.5 8 5.5S16 8 16 8zM1.173 8a13.133 13.133 0 0 1 1.66-2.043C4.12 4.668 5.88 3.5 8 3.5c2.12 0 3.879 1.168 5.168 2.457A13.133 13.133 0 0 1 14.828 8c-.058.087-.122.183-.195.288c-.335.48-.83 1.12-1.465 1.755C11.879 11.332 10.119 12.5 8 12.5c-2.12 0-3.879-1.168-5.168-2.457A13.134 13.134 0 0 1 1.172 8z" />
|
|
279
|
+
<path d="M8 5.5a2.5 2.5 0 1 0 0 5a2.5 2.5 0 0 0 0-5zM4.5 8a3.5 3.5 0 1 1 7 0a3.5 3.5 0 0 1-7 0z" />
|
|
280
|
+
</g>
|
|
281
|
+
</svg>
|
|
282
|
+
)}
|
|
283
|
+
</>
|
|
284
|
+
);
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
export { SigninSignup_A };
|
|
@@ -0,0 +1,257 @@
|
|
|
1
|
+
import { Button } from "@stackshift-ui/button";
|
|
2
|
+
import { Card } from "@stackshift-ui/card";
|
|
3
|
+
import { Container } from "@stackshift-ui/container";
|
|
4
|
+
import { Flex } from "@stackshift-ui/flex";
|
|
5
|
+
import { Form } from "@stackshift-ui/form";
|
|
6
|
+
import { FormField } from "@stackshift-ui/form-field";
|
|
7
|
+
import { Heading } from "@stackshift-ui/heading";
|
|
8
|
+
import { Image } from "@stackshift-ui/image";
|
|
9
|
+
import { Input } from "@stackshift-ui/input";
|
|
10
|
+
import { Link } from "@stackshift-ui/link";
|
|
11
|
+
import { Section } from "@stackshift-ui/section";
|
|
12
|
+
import { Text } from "@stackshift-ui/text";
|
|
13
|
+
import React, { useState } from "react";
|
|
14
|
+
import { SignUpFormProps } from ".";
|
|
15
|
+
import { logoLink, thankYouPageLink } from "./helper";
|
|
16
|
+
import { LabeledRoute, Logo, Form as iForm } from "./types";
|
|
17
|
+
|
|
18
|
+
export default function SigninSignup_B({ logo, form, formLinks, signInLink }: SignUpFormProps) {
|
|
19
|
+
return (
|
|
20
|
+
<Section className="py-10 bg-primary lg:py-20">
|
|
21
|
+
<Container maxWidth={1280}>
|
|
22
|
+
<Container maxWidth={576}>
|
|
23
|
+
<LogoSection logo={logo} />
|
|
24
|
+
<Card className="p-6 mb-6 bg-white lg:mb-10 lg:p-12">
|
|
25
|
+
<SubtitleAndHeadingText form={form} />
|
|
26
|
+
<SignupForm form={form} signInLink={signInLink} />
|
|
27
|
+
</Card>
|
|
28
|
+
<FormLinks formLinks={formLinks} />
|
|
29
|
+
</Container>
|
|
30
|
+
</Container>
|
|
31
|
+
</Section>
|
|
32
|
+
);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function LogoSection({ logo }: { logo?: Logo }) {
|
|
36
|
+
if (!logo) return null;
|
|
37
|
+
|
|
38
|
+
return (
|
|
39
|
+
<div className="mb-10">
|
|
40
|
+
<Link
|
|
41
|
+
aria-label={`Go to ${logoLink(logo) === "/" ? "home page" : logoLink(logo)}`}
|
|
42
|
+
className="flex justify-center mx-auto text-3xl font-bold leading-none"
|
|
43
|
+
href={logoLink(logo)}
|
|
44
|
+
target={logo?.linkTarget}
|
|
45
|
+
rel={logo?.linkTarget === "_blank" ? "noopener noreferrer" : ""}>
|
|
46
|
+
<Image
|
|
47
|
+
src={logo?.image}
|
|
48
|
+
alt={logo?.alt ?? "signup-logo"}
|
|
49
|
+
width={100}
|
|
50
|
+
height={100}
|
|
51
|
+
className="flex justify-center text-3xl font-bold leading-none text-white"
|
|
52
|
+
/>
|
|
53
|
+
</Link>
|
|
54
|
+
</div>
|
|
55
|
+
);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
function SubtitleAndHeadingText({ form }: { form?: iForm }) {
|
|
59
|
+
return (
|
|
60
|
+
<div className="mb-6">
|
|
61
|
+
<Text muted>{form?.subtitle}</Text>
|
|
62
|
+
<Heading className="text-2xl lg:text-2xl">{form?.name}</Heading>
|
|
63
|
+
</div>
|
|
64
|
+
);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
function SignupForm({ form, signInLink }: { form?: iForm; signInLink?: LabeledRoute }) {
|
|
68
|
+
if (!form?.fields) return null;
|
|
69
|
+
const [showPassword, setShowPassword] = useState(false);
|
|
70
|
+
|
|
71
|
+
return (
|
|
72
|
+
<Form
|
|
73
|
+
id={form?.id ?? undefined}
|
|
74
|
+
name="SignUp-VariantB-Form"
|
|
75
|
+
className="form-signup"
|
|
76
|
+
thankyouPage={thankYouPageLink(form?.thankYouPage)}>
|
|
77
|
+
<FormFields form={form} showPassword={showPassword} setShowPassword={setShowPassword} />
|
|
78
|
+
<div>
|
|
79
|
+
<div className="webriq-recaptcha" />
|
|
80
|
+
</div>
|
|
81
|
+
<div className="text-center">
|
|
82
|
+
<FormButtonLabel form={form} />
|
|
83
|
+
<SigninLink signInLink={signInLink} />
|
|
84
|
+
</div>
|
|
85
|
+
</Form>
|
|
86
|
+
);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
function FormFields({
|
|
90
|
+
form,
|
|
91
|
+
showPassword,
|
|
92
|
+
setShowPassword,
|
|
93
|
+
}: {
|
|
94
|
+
form?: iForm;
|
|
95
|
+
showPassword: boolean;
|
|
96
|
+
setShowPassword: React.Dispatch<React.SetStateAction<boolean>>;
|
|
97
|
+
}) {
|
|
98
|
+
return (
|
|
99
|
+
<React.Fragment>
|
|
100
|
+
<Flex className="flex-col lg:flex-row gap-3">
|
|
101
|
+
{form?.fields?.slice(0, 2)?.map((formFields, index) => (
|
|
102
|
+
<div className="w-full" key={index}>
|
|
103
|
+
<FormField
|
|
104
|
+
noLabel
|
|
105
|
+
variant="secondary"
|
|
106
|
+
placeholder={formFields?.placeholder}
|
|
107
|
+
required={formFields?.isRequired}
|
|
108
|
+
name={formFields?.name ?? ""}
|
|
109
|
+
items={formFields?.items}
|
|
110
|
+
type={formFields?.type}
|
|
111
|
+
{...formFields}
|
|
112
|
+
/>
|
|
113
|
+
</div>
|
|
114
|
+
))}
|
|
115
|
+
</Flex>
|
|
116
|
+
|
|
117
|
+
{form?.fields?.slice(2)?.map((formFields, index) => (
|
|
118
|
+
<div key={index} className="my-3">
|
|
119
|
+
{formFields?.type === "inputPassword" ? (
|
|
120
|
+
<div className="flex">
|
|
121
|
+
<Input
|
|
122
|
+
noLabel
|
|
123
|
+
ariaLabel={formFields?.placeholder ?? formFields?.name}
|
|
124
|
+
variant="secondary"
|
|
125
|
+
type={showPassword ? "text" : "password"}
|
|
126
|
+
placeholder={formFields?.placeholder}
|
|
127
|
+
name={formFields?.name}
|
|
128
|
+
required={formFields?.isRequired}
|
|
129
|
+
/>
|
|
130
|
+
{/* SVG icon on the right of the password input field */}
|
|
131
|
+
<Button
|
|
132
|
+
variant="unstyled"
|
|
133
|
+
as="button"
|
|
134
|
+
ariaLabel={showPassword ? "Show password" : "Hide password"}
|
|
135
|
+
className="focus:outline-none mr-4"
|
|
136
|
+
type="button"
|
|
137
|
+
onClick={() => setShowPassword(!showPassword)}>
|
|
138
|
+
<PasswordIcon showPassword={showPassword} />
|
|
139
|
+
</Button>
|
|
140
|
+
</div>
|
|
141
|
+
) : (
|
|
142
|
+
<FormField
|
|
143
|
+
noLabel
|
|
144
|
+
variant="secondary"
|
|
145
|
+
name={formFields?.name ?? ""}
|
|
146
|
+
placeholder={formFields?.placeholder}
|
|
147
|
+
required={formFields?.isRequired}
|
|
148
|
+
items={formFields?.items}
|
|
149
|
+
type={formFields?.type}
|
|
150
|
+
{...formFields}
|
|
151
|
+
/>
|
|
152
|
+
)}
|
|
153
|
+
</div>
|
|
154
|
+
))}
|
|
155
|
+
</React.Fragment>
|
|
156
|
+
);
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
function FormButtonLabel({ form }: { form?: iForm }) {
|
|
160
|
+
if (!form?.buttonLabel) return null;
|
|
161
|
+
|
|
162
|
+
return (
|
|
163
|
+
<Button
|
|
164
|
+
as="button"
|
|
165
|
+
className="w-full py-4 mb-3"
|
|
166
|
+
ariaLabel={form?.buttonLabel ?? "Sign Up form submit button"}
|
|
167
|
+
variant="custom"
|
|
168
|
+
type="submit">
|
|
169
|
+
{form?.buttonLabel}
|
|
170
|
+
</Button>
|
|
171
|
+
);
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
function SigninLink({ signInLink }: { signInLink?: LabeledRoute }) {
|
|
175
|
+
if (!signInLink?.label) return null;
|
|
176
|
+
|
|
177
|
+
return (
|
|
178
|
+
<span className="text-xs text-gray-900">
|
|
179
|
+
<span>Already have an account?</span>{" "}
|
|
180
|
+
<Button
|
|
181
|
+
as="link"
|
|
182
|
+
variant="link"
|
|
183
|
+
link={signInLink}
|
|
184
|
+
className="text-xs text-primary hover:underline"
|
|
185
|
+
ariaLabel={signInLink?.label}>
|
|
186
|
+
{signInLink?.label}
|
|
187
|
+
</Button>
|
|
188
|
+
</span>
|
|
189
|
+
);
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
function FormLinks({ formLinks }: { formLinks?: LabeledRoute[] }) {
|
|
193
|
+
if (!formLinks) return null;
|
|
194
|
+
|
|
195
|
+
return (
|
|
196
|
+
<p className="text-xs text-center text-secondary-foreground">
|
|
197
|
+
{formLinks?.map((link, index, { length }) => (
|
|
198
|
+
<span key={index}>
|
|
199
|
+
<Button
|
|
200
|
+
as="link"
|
|
201
|
+
variant="link"
|
|
202
|
+
link={link}
|
|
203
|
+
className="text-xs underline text-secondary-foreground hover:text-gray-50"
|
|
204
|
+
ariaLabel={link?.label}>
|
|
205
|
+
{link?.label}
|
|
206
|
+
</Button>
|
|
207
|
+
{index === length - 1 ? null : index === length - 2 ? (
|
|
208
|
+
<span> and </span>
|
|
209
|
+
) : (
|
|
210
|
+
<span> , </span>
|
|
211
|
+
)}
|
|
212
|
+
</span>
|
|
213
|
+
))}
|
|
214
|
+
</p>
|
|
215
|
+
);
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
function PasswordIcon({ showPassword }: { showPassword: boolean }) {
|
|
219
|
+
return (
|
|
220
|
+
<React.Fragment>
|
|
221
|
+
{showPassword ? (
|
|
222
|
+
<svg
|
|
223
|
+
className="w-5 h-5 my-auto text-gray-500"
|
|
224
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
225
|
+
aria-hidden="true"
|
|
226
|
+
role="img"
|
|
227
|
+
width="1em"
|
|
228
|
+
height="1em"
|
|
229
|
+
preserveAspectRatio="xMidYMid meet"
|
|
230
|
+
viewBox="0 0 16 16">
|
|
231
|
+
<g fill="currentColor">
|
|
232
|
+
<path d="M13.359 11.238C15.06 9.72 16 8 16 8s-3-5.5-8-5.5a7.028 7.028 0 0 0-2.79.588l.77.771A5.944 5.944 0 0 1 8 3.5c2.12 0 3.879 1.168 5.168 2.457A13.134 13.134 0 0 1 14.828 8c-.058.087-.122.183-.195.288c-.335.48-.83 1.12-1.465 1.755c-.165.165-.337.328-.517.486l.708.709z" />
|
|
233
|
+
<path d="M11.297 9.176a3.5 3.5 0 0 0-4.474-4.474l.823.823a2.5 2.5 0 0 1 2.829 2.829l.822.822zm-2.943 1.299l.822.822a3.5 3.5 0 0 1-4.474-4.474l.823.823a2.5 2.5 0 0 0 2.829 2.829z" />
|
|
234
|
+
<path d="M3.35 5.47c-.18.16-.353.322-.518.487A13.134 13.134 0 0 0 1.172 8l.195.288c.335.48.83 1.12 1.465 1.755C4.121 11.332 5.881 12.5 8 12.5c.716 0 1.39-.133 2.02-.36l.77.772A7.029 7.029 0 0 1 8 13.5C3 13.5 0 8 0 8s.939-1.721 2.641-3.238l.708.709zm10.296 8.884l-12-12l.708-.708l12 12l-.708.708z" />
|
|
235
|
+
</g>
|
|
236
|
+
</svg>
|
|
237
|
+
) : (
|
|
238
|
+
<svg
|
|
239
|
+
className="w-5 h-5 my-auto ml-4 text-gray-500"
|
|
240
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
241
|
+
aria-hidden="true"
|
|
242
|
+
role="img"
|
|
243
|
+
width="1em"
|
|
244
|
+
height="1em"
|
|
245
|
+
preserveAspectRatio="xMidYMid meet"
|
|
246
|
+
viewBox="0 0 16 16">
|
|
247
|
+
<g fill="currentColor">
|
|
248
|
+
<path d="M16 8s-3-5.5-8-5.5S0 8 0 8s3 5.5 8 5.5S16 8 16 8zM1.173 8a13.133 13.133 0 0 1 1.66-2.043C4.12 4.668 5.88 3.5 8 3.5c2.12 0 3.879 1.168 5.168 2.457A13.133 13.133 0 0 1 14.828 8c-.058.087-.122.183-.195.288c-.335.48-.83 1.12-1.465 1.755C11.879 11.332 10.119 12.5 8 12.5c-2.12 0-3.879-1.168-5.168-2.457A13.134 13.134 0 0 1 1.172 8z" />
|
|
249
|
+
<path d="M8 5.5a2.5 2.5 0 1 0 0 5a2.5 2.5 0 0 0 0-5zM4.5 8a3.5 3.5 0 1 1 7 0a3.5 3.5 0 0 1-7 0z" />
|
|
250
|
+
</g>
|
|
251
|
+
</svg>
|
|
252
|
+
)}
|
|
253
|
+
</React.Fragment>
|
|
254
|
+
);
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
export { SigninSignup_B };
|