@sikka/hawa 0.1.53 → 0.1.55

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.
@@ -1,7 +1,7 @@
1
1
  import React, { FC } from "react"
2
2
  import {
3
3
  HawaTextField,
4
- HawaLogoButton,
4
+ InterfaceSettings,
5
5
  HawaAlert,
6
6
  HawaCheckbox,
7
7
  HawaSelect,
@@ -13,6 +13,10 @@ import { Icons } from "../../elements/Icons"
13
13
  import clsx from "clsx"
14
14
 
15
15
  type SignUpFormTypes = {
16
+ handleLanguage?: () => void
17
+ currentLanguage?: any
18
+ handleColorMode?: () => void
19
+ currentColorMode?: any
16
20
  direction?: "rtl" | "ltr"
17
21
  texts: {
18
22
  fullNameLabel: string
@@ -74,268 +78,276 @@ export const SignUpForm: FC<SignUpFormTypes> = (props) => {
74
78
  } = methods
75
79
 
76
80
  return (
77
- <Card dir={props.direction}>
78
- <CardContent headless>
79
- <div>
80
- {props.showError && (
81
- <HawaAlert
82
- title={props.errorTitle}
83
- text={props.errorText}
84
- severity="error"
85
- />
86
- )}
87
- <FormProvider {...methods}>
88
- <form onSubmit={handleSubmit((e) => props.handleSignUp(e))}>
89
- <div>
90
- {props.signUpFields.map((fld, i) => {
91
- if (fld === "fullname") {
92
- return (
93
- <Controller
94
- key={i}
95
- control={control}
96
- name="fullName"
97
- render={({ field }) => (
98
- <HawaTextField
99
- width="full"
100
- type="text"
101
- label={props.texts.fullNameLabel}
102
- placeholder={props.texts.fullNamePlaceholder}
103
- helpertext={errors.fullName?.message}
104
- onChange={field.onChange}
105
- value={field.value ?? ""}
106
- />
107
- )}
108
- rules={{
109
- required: props.texts.fullNameRequiredText,
110
- }}
111
- />
112
- )
113
- }
114
- if (fld === "email") {
115
- return (
116
- <Controller
117
- control={control}
118
- name="email"
119
- render={({ field }) => (
120
- <HawaTextField
121
- width="full"
122
- type="text"
123
- autoComplete="email"
124
- label={props.texts.emailLabel}
125
- helpertext={errors.email?.message}
126
- placeholder={props.texts.emailPlaceholder}
127
- onChange={field.onChange}
128
- value={field.value ?? ""}
129
- />
130
- )}
131
- rules={{
132
- required: props.texts.emailRequiredText,
133
- pattern: {
134
- value:
135
- /^(([^<>()[\]\\.,;:\s@\"]+(\.[^<>()[\]\\.,;:\s@\"]+)*)|(\".+\"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/,
136
- message: props.texts.emailInvalidText,
137
- },
138
- }}
139
- />
140
- )
141
- }
142
- if (fld === "username") {
143
- return (
144
- <Controller
145
- control={control}
146
- name="username"
147
- render={({ field }) => (
148
- <HawaTextField
149
- width="full"
150
- type="text"
151
- autoComplete="username"
152
- label={props.texts.usernameLabel}
153
- helpertext={errors.username?.message}
154
- placeholder={props.texts.usernamePlaceholder}
155
- onChange={field.onChange}
156
- value={field.value ?? ""}
157
- />
158
- )}
159
- rules={{
160
- required: props.texts.usernameRequired,
161
- }}
162
- />
163
- )
164
- }
165
- })}
166
- </div>
167
- <Controller
168
- control={control}
169
- name="password"
170
- render={({ field }) => (
171
- <HawaTextField
172
- width="full"
173
- type="password"
174
- autoComplete="new-password"
175
- // defaultValue={field.value ?? ""}
176
- label={props.texts.passwordLabel}
177
- placeholder={props.texts.passwordPlaceholder}
178
- helpertext={errors.password?.message}
179
- onChange={field.onChange}
180
- value={field.value ?? ""}
181
- />
182
- )}
183
- rules={{ required: props.texts.passwordRequiredText }}
184
- />
185
- <Controller
186
- control={control}
187
- name="confirm_password"
188
- render={({ field }) => (
189
- <HawaTextField
190
- width="full"
191
- type="password"
192
- autoComplete="new-password"
193
- // defaultValue={field.value ?? ""}
194
- label={props.texts.confirmPasswordLabel}
195
- placeholder={props.texts.confirmPasswordPlaceholder}
196
- helpertext={errors.confirm_password?.message}
197
- onChange={field.onChange}
198
- value={field.value ?? ""}
199
- />
200
- )}
201
- rules={{ required: props.texts.passwordRequiredText }}
81
+ <div className="flex flex-col gap-4">
82
+ <Card dir={props.direction}>
83
+ <CardContent headless>
84
+ <div>
85
+ {props.showError && (
86
+ <HawaAlert
87
+ title={props.errorTitle}
88
+ text={props.errorText}
89
+ severity="error"
202
90
  />
203
- {props.showRefCode && (
91
+ )}
92
+ <FormProvider {...methods}>
93
+ <form onSubmit={handleSubmit((e) => props.handleSignUp(e))}>
94
+ <div>
95
+ {props.signUpFields.map((fld, i) => {
96
+ if (fld === "fullname") {
97
+ return (
98
+ <Controller
99
+ key={i}
100
+ control={control}
101
+ name="fullName"
102
+ render={({ field }) => (
103
+ <HawaTextField
104
+ width="full"
105
+ type="text"
106
+ label={props.texts.fullNameLabel}
107
+ placeholder={props.texts.fullNamePlaceholder}
108
+ helpertext={errors.fullName?.message}
109
+ onChange={field.onChange}
110
+ value={field.value ?? ""}
111
+ />
112
+ )}
113
+ rules={{
114
+ required: props.texts.fullNameRequiredText,
115
+ }}
116
+ />
117
+ )
118
+ }
119
+ if (fld === "email") {
120
+ return (
121
+ <Controller
122
+ control={control}
123
+ name="email"
124
+ render={({ field }) => (
125
+ <HawaTextField
126
+ width="full"
127
+ type="text"
128
+ autoComplete="email"
129
+ label={props.texts.emailLabel}
130
+ helpertext={errors.email?.message}
131
+ placeholder={props.texts.emailPlaceholder}
132
+ onChange={field.onChange}
133
+ value={field.value ?? ""}
134
+ />
135
+ )}
136
+ rules={{
137
+ required: props.texts.emailRequiredText,
138
+ pattern: {
139
+ value:
140
+ /^(([^<>()[\]\\.,;:\s@\"]+(\.[^<>()[\]\\.,;:\s@\"]+)*)|(\".+\"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/,
141
+ message: props.texts.emailInvalidText,
142
+ },
143
+ }}
144
+ />
145
+ )
146
+ }
147
+ if (fld === "username") {
148
+ return (
149
+ <Controller
150
+ control={control}
151
+ name="username"
152
+ render={({ field }) => (
153
+ <HawaTextField
154
+ width="full"
155
+ type="text"
156
+ autoComplete="username"
157
+ label={props.texts.usernameLabel}
158
+ helpertext={errors.username?.message}
159
+ placeholder={props.texts.usernamePlaceholder}
160
+ onChange={field.onChange}
161
+ value={field.value ?? ""}
162
+ />
163
+ )}
164
+ rules={{
165
+ required: props.texts.usernameRequired,
166
+ }}
167
+ />
168
+ )
169
+ }
170
+ })}
171
+ </div>
204
172
  <Controller
205
173
  control={control}
206
- name="refCode"
174
+ name="password"
207
175
  render={({ field }) => (
208
176
  <HawaTextField
209
177
  width="full"
210
- type="text"
211
- defaultValue={field.value ?? ""}
212
- label={props.texts.refCode}
178
+ type="password"
179
+ autoComplete="new-password"
180
+ // defaultValue={field.value ?? ""}
181
+ label={props.texts.passwordLabel}
213
182
  placeholder={props.texts.passwordPlaceholder}
214
183
  helpertext={errors.password?.message}
184
+ onChange={field.onChange}
215
185
  value={field.value ?? ""}
186
+ />
187
+ )}
188
+ rules={{ required: props.texts.passwordRequiredText }}
189
+ />
190
+ <Controller
191
+ control={control}
192
+ name="confirm_password"
193
+ render={({ field }) => (
194
+ <HawaTextField
195
+ width="full"
196
+ type="password"
197
+ autoComplete="new-password"
198
+ // defaultValue={field.value ?? ""}
199
+ label={props.texts.confirmPasswordLabel}
200
+ placeholder={props.texts.confirmPasswordPlaceholder}
201
+ helpertext={errors.confirm_password?.message}
216
202
  onChange={field.onChange}
203
+ value={field.value ?? ""}
217
204
  />
218
205
  )}
206
+ rules={{ required: props.texts.passwordRequiredText }}
219
207
  />
220
- )}
221
- {props.showUserSource && (
222
- <div>
208
+ {props.showRefCode && (
223
209
  <Controller
224
210
  control={control}
225
- name="reference"
211
+ name="refCode"
226
212
  render={({ field }) => (
227
- <HawaSelect
228
- label="How did you learn about us?"
229
- isCreatable={false}
230
- isMulti={false ?? false}
231
- isSearchable={false}
232
- isClearable={false ?? false}
233
- options={[
234
- { value: "friend", label: "From a friend" },
235
- { value: "ad", label: "Advertisement" },
236
- { value: "other", label: "Other" },
237
- ]}
238
- onChange={(e: any) => {
239
- field.onChange(e.value)
240
- }}
213
+ <HawaTextField
214
+ width="full"
215
+ type="text"
216
+ defaultValue={field.value ?? ""}
217
+ label={props.texts.refCode}
218
+ placeholder={props.texts.passwordPlaceholder}
219
+ helpertext={errors.password?.message}
220
+ value={field.value ?? ""}
221
+ onChange={field.onChange}
241
222
  />
242
223
  )}
243
224
  />
244
- </div>
245
- )}
246
- {props.showTermsOption && (
247
- <Controller
248
- control={control}
249
- name="terms_accepted"
250
- render={({ field }) => (
251
- <HawaCheckbox
252
- id="terms_accepted"
253
- helperText={errors.terms_accepted?.message}
254
- onChange={(e) => field.onChange(e)}
255
- label={
256
- <span>
257
- {props.texts.iAcceptText}{" "}
258
- <a
259
- onClick={props.handleRouteToTOS}
260
- className="clickable-link"
261
- >
262
- {props.texts.termsText}
263
- </a>
264
- </span>
265
- }
225
+ )}
226
+ {props.showUserSource && (
227
+ <div>
228
+ <Controller
229
+ control={control}
230
+ name="reference"
231
+ render={({ field }) => (
232
+ <HawaSelect
233
+ label="How did you learn about us?"
234
+ isCreatable={false}
235
+ isMulti={false ?? false}
236
+ isSearchable={false}
237
+ isClearable={false ?? false}
238
+ options={[
239
+ { value: "friend", label: "From a friend" },
240
+ { value: "ad", label: "Advertisement" },
241
+ { value: "other", label: "Other" },
242
+ ]}
243
+ onChange={(e: any) => {
244
+ field.onChange(e.value)
245
+ }}
246
+ />
247
+ )}
266
248
  />
249
+ </div>
250
+ )}
251
+ {props.showTermsOption && (
252
+ <Controller
253
+ control={control}
254
+ name="terms_accepted"
255
+ render={({ field }) => (
256
+ <HawaCheckbox
257
+ id="terms_accepted"
258
+ helperText={errors.terms_accepted?.message}
259
+ onChange={(e) => field.onChange(e)}
260
+ label={
261
+ <span>
262
+ {props.texts.iAcceptText}{" "}
263
+ <a
264
+ onClick={props.handleRouteToTOS}
265
+ className="clickable-link"
266
+ >
267
+ {props.texts.termsText}
268
+ </a>
269
+ </span>
270
+ }
271
+ />
272
+ )}
273
+ rules={{ required: props.texts.termsRequiredText }}
274
+ />
275
+ )}
276
+ {props.showNewsletterOption && (
277
+ <Controller
278
+ control={control}
279
+ name="newsletter_accepted"
280
+ render={({ field }) => (
281
+ <HawaCheckbox
282
+ id="newsletter_accepted"
283
+ label={props.texts.subscribeToNewsletter}
284
+ onChange={field.onChange}
285
+ />
286
+ )}
287
+ />
288
+ )}
289
+
290
+ <Button className="w-full" isLoading={props.isLoading}>
291
+ {props.texts.signUpText}
292
+ </Button>
293
+ </form>
294
+ </FormProvider>
295
+ <div className="flex flex-row items-center justify-center gap-1 p-3 text-center text-sm font-semibold dark:text-white">
296
+ <span>{props.texts.existingUserText}</span>
297
+ <span
298
+ onClick={props.handleRouteToSignIn}
299
+ className="clickable-link"
300
+ >
301
+ {props.texts.signInText}
302
+ </span>
303
+ </div>
304
+ </div>
305
+ </CardContent>
306
+
307
+ {props.viaGithub || props.viaGoogle || props.viaTwitter ? (
308
+ <CardFooter className="grid grid-cols-1 gap-2 ">
309
+ {props.viaGoogle && (
310
+ <Button variant="outline" onClick={props.handleGoogleSignUp}>
311
+ <Icons.google
312
+ className={clsx(
313
+ "h-4 w-4",
314
+ props.direction === "rtl" ? "ml-2" : "mr-2"
267
315
  )}
268
- rules={{ required: props.texts.termsRequiredText }}
269
316
  />
270
- )}
271
- {props.showNewsletterOption && (
272
- <Controller
273
- control={control}
274
- name="newsletter_accepted"
275
- render={({ field }) => (
276
- <HawaCheckbox
277
- id="newsletter_accepted"
278
- label={props.texts.subscribeToNewsletter}
279
- onChange={field.onChange}
280
- />
317
+ {props.texts.signUpViaGoogleLabel}
318
+ </Button>
319
+ )}
320
+ {props.viaGithub && (
321
+ <Button variant="outline" onClick={props.handleGithubSignUp}>
322
+ <Icons.gitHub
323
+ className={clsx(
324
+ "h-4 w-4",
325
+ props.direction === "rtl" ? "ml-2" : "mr-2"
281
326
  )}
282
327
  />
283
- )}
284
-
285
- <Button className="w-full" isLoading={props.isLoading}>
286
- {props.texts.signUpText}
328
+ {props.texts.signUpViaGithubLabel}
287
329
  </Button>
288
- </form>
289
- </FormProvider>
290
- <div className="flex flex-row items-center justify-center gap-1 p-3 text-center text-sm font-semibold dark:text-white">
291
- <span>{props.texts.existingUserText}</span>
292
- <span
293
- onClick={props.handleRouteToSignIn}
294
- className="clickable-link"
295
- >
296
- {props.texts.signInText}
297
- </span>
298
- </div>
299
- </div>
300
- </CardContent>
301
-
302
- {props.viaGithub || props.viaGoogle || props.viaTwitter ? (
303
- <CardFooter className="grid grid-cols-1 gap-2 ">
304
- {props.viaGoogle && (
305
- <Button variant="outline" onClick={props.handleGoogleSignUp}>
306
- <Icons.google
307
- className={clsx(
308
- "h-4 w-4",
309
- props.direction === "rtl" ? "ml-2" : "mr-2"
310
- )}
311
- />
312
- {props.texts.signUpViaGoogleLabel}
313
- </Button>
314
- )}
315
- {props.viaGithub && (
316
- <Button variant="outline" onClick={props.handleGithubSignUp}>
317
- <Icons.gitHub
318
- className={clsx(
319
- "h-4 w-4",
320
- props.direction === "rtl" ? "ml-2" : "mr-2"
321
- )}
322
- />
323
- {props.texts.signUpViaGithubLabel}
324
- </Button>
325
- )}
326
- {props.viaTwitter && (
327
- <Button variant="outline" onClick={props.handleTwitterSignUp}>
328
- <Icons.twitter
329
- className={clsx(
330
- "h-4 w-4",
331
- props.direction === "rtl" ? "ml-2" : "mr-2"
332
- )}
333
- />
334
- {props.texts.signUpViaTwitterLabel}
335
- </Button>
336
- )}
337
- </CardFooter>
338
- ) : null}
339
- </Card>
330
+ )}
331
+ {props.viaTwitter && (
332
+ <Button variant="outline" onClick={props.handleTwitterSignUp}>
333
+ <Icons.twitter
334
+ className={clsx(
335
+ "h-4 w-4",
336
+ props.direction === "rtl" ? "ml-2" : "mr-2"
337
+ )}
338
+ />
339
+ {props.texts.signUpViaTwitterLabel}
340
+ </Button>
341
+ )}
342
+ </CardFooter>
343
+ ) : null}
344
+ </Card>
345
+ <InterfaceSettings
346
+ currentColorMode={props.currentColorMode}
347
+ currentLanguage={props.currentLanguage}
348
+ handleColorMode={props.handleColorMode}
349
+ handleLanguage={props.handleLanguage}
350
+ />
351
+ </div>
340
352
  )
341
353
  }
@@ -0,0 +1,32 @@
1
+ import React, { FC } from "react"
2
+ import { Card, CardContent, CardFooter } from "../../elements/Card"
3
+ import { Button } from "../../elements/Button"
4
+
5
+ type AnnouncementTypes = {
6
+ variant?: "outlined" | "contained" | "neobrutalism"
7
+ onActionClick: () => void
8
+ actionText?: string
9
+ title?: string
10
+ subtitle?: string
11
+ }
12
+
13
+ export const Announcement: FC<AnnouncementTypes> = ({
14
+ variant = "contained",
15
+ onActionClick,
16
+ ...props
17
+ }) => {
18
+ return (
19
+ <Card>
20
+ <CardContent
21
+ headless
22
+ className="flex flex-row items-center justify-between"
23
+ >
24
+ <div className="flex flex-col items-start justify-center ">
25
+ <span className="text-lg font-bold">{props.title}</span>
26
+ <span className="text-sm">{props.subtitle}</span>
27
+ </div>
28
+ <Button onClick={() => onActionClick()}>{props.actionText}</Button>
29
+ </CardContent>
30
+ </Card>
31
+ )
32
+ }
@@ -2,4 +2,5 @@ export * from "./NotFound"
2
2
  export * from "./EmptyState"
3
3
  export * from "./Testimonial"
4
4
  export * from "./LeadGenerator"
5
+ export * from "./Announcement"
5
6
  export * from "./NoPermission"
@@ -1,7 +1,9 @@
1
1
  import React, { FC, RefObject, useState, useEffect, useRef } from "react"
2
2
  import { clsx } from "clsx"
3
+ import { Button } from "./Button"
4
+ import { cn } from "../util"
3
5
 
4
- type ComponentTypes = {
6
+ type BackToTopTypes = {
5
7
  paddingX?: number // Horizontal padding relative to the attached corner
6
8
  paddingY?: number // Vertical padding relative to the attached corner
7
9
  paddingThreshold?: number // Increase to the threshold of the scroll value that has to be passed for the button to appear
@@ -9,7 +11,7 @@ type ComponentTypes = {
9
11
  anchor: RefObject<HTMLInputElement>
10
12
  }
11
13
 
12
- export const BackToTop: FC<ComponentTypes> = ({ ...props }) => {
14
+ export const BackToTop: FC<BackToTopTypes> = ({ ...props }) => {
13
15
  const [visible, setVisible] = useState<boolean>(false)
14
16
  const [rect, _setRect] = useState<DOMRect>(null)
15
17
  const _rect = useRef(rect)
@@ -95,35 +97,31 @@ export const BackToTop: FC<ComponentTypes> = ({ ...props }) => {
95
97
  }
96
98
 
97
99
  return (
98
- <div
99
- className={clsx(
100
- "fixed w-fit rounded bg-blue-300 p-2 text-black transition-all hover:bg-blue-500",
101
- `${
102
- visible
103
- ? "pointer-events-all opacity-100"
104
- : "pointer-events-none opacity-0"
105
- }`
100
+ <Button
101
+ className={cn(
102
+ "fixed cursor-pointer rounded transition-all",
103
+ visible
104
+ ? "pointer-events-all opacity-100"
105
+ : "pointer-events-none opacity-0"
106
106
  )}
107
+ onClick={backToTop}
107
108
  style={{
108
109
  ...getStyles(),
109
110
  transitionProperty: "opacity, background-color",
110
111
  }}
111
- onClick={backToTop}
112
112
  ref={self}
113
+ size="icon"
113
114
  >
114
- {/* Back to top arrow 👇*/}
115
115
  <svg
116
116
  className={clsx(
117
117
  "h-6 w-6 shrink-0 rotate-180 transition-all disabled:bg-gray-200"
118
118
  )}
119
+ aria-label="Arrow Icon"
119
120
  viewBox="0 0 20 20"
121
+ fill="currentColor"
120
122
  >
121
- <path
122
- fillRule="evenodd"
123
- d="M5.293 7.293a1 1 0 011.414 0L10 10.586l3.293-3.293a1 1 0 111.414 1.414l-4 4a1 1 0 01-1.414 0l-4-4a1 1 0 010-1.414z"
124
- clipRule="evenodd"
125
- ></path>
123
+ <path d="M5.293 7.293a1 1 0 011.414 0L10 10.586l3.293-3.293a1 1 0 111.414 1.414l-4 4a1 1 0 01-1.414 0l-4-4a1 1 0 010-1.414z"></path>
126
124
  </svg>
127
- </div>
125
+ </Button>
128
126
  )
129
127
  }