@thecb/components 9.0.3 → 9.0.4-beta.1

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@thecb/components",
3
- "version": "9.0.3",
3
+ "version": "9.0.4-beta.1",
4
4
  "description": "Common lib for CityBase react components",
5
5
  "main": "dist/index.cjs.js",
6
6
  "typings": "dist/index.d.ts",
@@ -64,6 +64,15 @@ const PaymentFormACH = ({
64
64
  [required.error]: "Account type is required"
65
65
  };
66
66
 
67
+ useEffect(() => {
68
+ const firstFocusableField = document.getElementById(
69
+ `first-focusable-ach-input`
70
+ );
71
+ if (firstFocusableField) {
72
+ firstFocusableField.focus();
73
+ }
74
+ }, []);
75
+
67
76
  return (
68
77
  <FormContainer variant={variant} role="form" aria-label="ACH Payment">
69
78
  <FormInputColumn>
@@ -76,6 +85,7 @@ const PaymentFormACH = ({
76
85
  showErrors={showErrors}
77
86
  onKeyDown={e => e.key === "Enter" && handleSubmit(e)}
78
87
  autocompleteValue="name"
88
+ id="first-focusable-ach-input"
79
89
  />
80
90
  <FormInput
81
91
  labelTextWhenNoError="Routing number"
@@ -71,7 +71,7 @@ const PaymentFormCard = ({
71
71
  [hasLength.error]: "Credit card number is invalid",
72
72
  [matchesRegex.error]: `${displayCardBrand(
73
73
  fields.creditCardNumber.rawValue
74
- )} is not accepted`
74
+ )} is not accepted.`
75
75
  };
76
76
  const expirationDateErrors = {
77
77
  [required.error]: "Expiration date is required",
@@ -91,6 +91,15 @@ const PaymentFormCard = ({
91
91
  [required.error]: "Country is required"
92
92
  };
93
93
 
94
+ useEffect(() => {
95
+ const firstFocusableField = document.getElementById(
96
+ `first-focusable-card-input`
97
+ );
98
+ if (firstFocusableField) {
99
+ firstFocusableField.focus();
100
+ }
101
+ }, []);
102
+
94
103
  const isUS = fields.country.rawValue === "US";
95
104
  return (
96
105
  <FormContainer variant={variant} role="form" aria-label="Card payment">
@@ -121,6 +130,7 @@ const PaymentFormCard = ({
121
130
  showErrors={showErrors}
122
131
  onKeyDown={e => e.key === "Enter" && handleSubmit(e)}
123
132
  autocompleteValue="cc-name"
133
+ id="first-focusable-card-input"
124
134
  />
125
135
  <FormInput
126
136
  labelTextWhenNoError="Credit card number"
@@ -1,4 +1,4 @@
1
- import React, { Fragment, useState } from "react";
1
+ import React, { Fragment, useEffect, useRef, useState } from "react";
2
2
  import styled from "styled-components";
3
3
  import { themeComponent } from "../../../util/themeUtils";
4
4
  import { fallbackValues } from "./RadioSection.theme";
@@ -98,6 +98,19 @@ const RadioSection = ({
98
98
 
99
99
  const [focused, setFocused] = useState(null);
100
100
 
101
+ // useEffect(() => {
102
+ // if (toggledContentRef && toggledContentRef?.current) {
103
+ // const inputEl = toggledContentRef.current?.querySelector(
104
+ // `[tabindex="0"]`
105
+ // );
106
+ // if (inputEl) {
107
+ // inputEl?.focus();
108
+ // } else {
109
+ // toggledContentRef.current.focus();
110
+ // }
111
+ // }
112
+ // }, [toggledContentRef.current]);
113
+
101
114
  return (
102
115
  <Box
103
116
  padding="1px"
@@ -188,6 +201,11 @@ const RadioSection = ({
188
201
  as="label"
189
202
  htmlFor={`radio-input-${idString(section)}`}
190
203
  color={CHARADE_GREY}
204
+ {...{
205
+ ...(section?.titleLabel
206
+ ? { "aria-label": section.titleLabel }
207
+ : {})
208
+ }}
191
209
  >
192
210
  {section.title}
193
211
  </Text>
@@ -1,8 +1,9 @@
1
1
  import React, { useState } from "react";
2
- import { text, boolean } from "@storybook/addon-knobs";
3
-
4
- import RadioSection from "./RadioSection";
2
+ import { boolean } from "@storybook/addon-knobs";
5
3
  import page from "../../../../.storybook/page";
4
+ import RadioSection from "./RadioSection";
5
+ import PaymentFormACH from "../payment-form-ach/PaymentFormACH";
6
+ import PaymentFormCard from "../payment-form-card";
6
7
 
7
8
  const story = page({
8
9
  title: "Components|Molecules/RadioSection",
@@ -36,6 +37,416 @@ const cardIcons = [
36
37
  name: "AMEX"
37
38
  }
38
39
  ];
40
+ const paymentFormCardProps = {
41
+ showErrors: false,
42
+ fields: {
43
+ country: {
44
+ dirty: false,
45
+ rawValue: "US",
46
+ validators: [
47
+ {
48
+ type: "validator/REQUIRED",
49
+ args: [],
50
+ error: "error/REQUIRED"
51
+ }
52
+ ],
53
+ constraints: [],
54
+ errors: [],
55
+ hasErrors: false
56
+ },
57
+ nameOnCard: {
58
+ dirty: false,
59
+ rawValue: "",
60
+ validators: [
61
+ {
62
+ type: "validator/REQUIRED",
63
+ args: [],
64
+ error: "error/REQUIRED"
65
+ }
66
+ ],
67
+ constraints: [],
68
+ errors: ["error/REQUIRED"],
69
+ hasErrors: true
70
+ },
71
+ creditCardNumber: {
72
+ dirty: false,
73
+ rawValue: "",
74
+ validators: [
75
+ {
76
+ type: "validator/REQUIRED",
77
+ args: [],
78
+ error: "error/REQUIRED"
79
+ },
80
+ {
81
+ type: "validator/HAS_LENGTH",
82
+ args: [15, 16],
83
+ error: "error/HAS_LENGTH"
84
+ }
85
+ ],
86
+ constraints: [
87
+ {
88
+ type: "validator/ONLY_INTEGERS",
89
+ args: [],
90
+ error: "error/ONLY_INTEGERS"
91
+ },
92
+ {
93
+ type: "validator/HAS_LENGTH",
94
+ args: [0, 16],
95
+ error: "error/HAS_LENGTH"
96
+ }
97
+ ],
98
+ errors: ["error/REQUIRED"],
99
+ hasErrors: true
100
+ },
101
+ expirationDate: {
102
+ dirty: false,
103
+ rawValue: "",
104
+ validators: [
105
+ {
106
+ type: "validator/REQUIRED",
107
+ args: [],
108
+ error: "error/REQUIRED"
109
+ },
110
+ {
111
+ type: "validator/HAS_LENGTH",
112
+ args: [4, 4],
113
+ error: "error/HAS_LENGTH"
114
+ },
115
+ {
116
+ type: "validator/IS_VALID_MONTH",
117
+ args: [0],
118
+ error: "error/IS_VALID_MONTH"
119
+ },
120
+ {
121
+ type: "validator/DATE_AFTER_TODAY",
122
+ args: ["MMYY", "month", true],
123
+ error: "error/DATE_AFTER_TODAY"
124
+ }
125
+ ],
126
+ constraints: [
127
+ {
128
+ type: "validator/ONLY_EXPIRATION_DATE",
129
+ args: [],
130
+ error: "error/ONLY_EXPIRATION_DATE"
131
+ },
132
+ {
133
+ type: "validator/HAS_LENGTH",
134
+ args: [0, 4],
135
+ error: "error/HAS_LENGTH"
136
+ }
137
+ ],
138
+ errors: ["error/REQUIRED"],
139
+ hasErrors: true
140
+ },
141
+ cvv: {
142
+ dirty: false,
143
+ rawValue: "",
144
+ validators: [
145
+ {
146
+ type: "validator/REQUIRED",
147
+ args: [],
148
+ error: "error/REQUIRED"
149
+ },
150
+ {
151
+ type: "validator/HAS_LENGTH",
152
+ args: [3, 4],
153
+ error: "error/HAS_LENGTH"
154
+ }
155
+ ],
156
+ constraints: [
157
+ {
158
+ type: "validator/ONLY_INTEGERS",
159
+ args: [],
160
+ error: "error/ONLY_INTEGERS"
161
+ },
162
+ {
163
+ type: "validator/HAS_LENGTH",
164
+ args: [0, 4],
165
+ error: "error/HAS_LENGTH"
166
+ }
167
+ ],
168
+ errors: ["error/REQUIRED"],
169
+ hasErrors: true
170
+ },
171
+ zipCode: {
172
+ dirty: false,
173
+ rawValue: "",
174
+ validators: [
175
+ {
176
+ type: "validator/REQUIRED",
177
+ args: [],
178
+ error: "error/REQUIRED"
179
+ },
180
+ {
181
+ type: "validator/VALIDATE_WHEN",
182
+ args: [
183
+ {
184
+ type: "validator/VALIDATE_WHEN",
185
+ args: [
186
+ {
187
+ type: "validator/HAS_LENGTH",
188
+ args: [5, 5],
189
+ error: "error/HAS_LENGTH"
190
+ },
191
+ {
192
+ type: "validator/HAS_LENGTH",
193
+ args: [0, 5],
194
+ error: "error/HAS_LENGTH"
195
+ },
196
+ null
197
+ ],
198
+ error: "error/HAS_LENGTH"
199
+ },
200
+ {
201
+ type: "validator/MATCHES_REGEX",
202
+ args: ["US"],
203
+ error: "error/MATCHES_REGEX"
204
+ },
205
+ "country"
206
+ ],
207
+ error: "error/HAS_LENGTH"
208
+ },
209
+ {
210
+ type: "validator/VALIDATE_WHEN",
211
+ args: [
212
+ {
213
+ type: "validator/VALIDATE_WHEN",
214
+ args: [
215
+ {
216
+ type: "validator/HAS_LENGTH",
217
+ args: [9, 9],
218
+ error: "error/HAS_LENGTH"
219
+ },
220
+ {
221
+ type: "validator/HAS_LENGTH",
222
+ args: [6, 9],
223
+ error: "error/HAS_LENGTH"
224
+ },
225
+ null
226
+ ],
227
+ error: "error/HAS_LENGTH"
228
+ },
229
+ {
230
+ type: "validator/MATCHES_REGEX",
231
+ args: ["US"],
232
+ error: "error/MATCHES_REGEX"
233
+ },
234
+ "country"
235
+ ],
236
+ error: "error/HAS_LENGTH"
237
+ }
238
+ ],
239
+ constraints: [
240
+ {
241
+ type: "validator/VALIDATE_WHEN",
242
+ args: [
243
+ {
244
+ type: "validator/ONLY_INTEGERS",
245
+ args: [],
246
+ error: "error/ONLY_INTEGERS"
247
+ },
248
+ {
249
+ type: "validator/MATCHES_REGEX",
250
+ args: ["US"],
251
+ error: "error/MATCHES_REGEX"
252
+ },
253
+ "country"
254
+ ],
255
+ error: "error/ONLY_INTEGERS"
256
+ },
257
+ {
258
+ type: "validator/VALIDATE_WHEN",
259
+ args: [
260
+ {
261
+ type: "validator/HAS_LENGTH",
262
+ args: [0, 9],
263
+ error: "error/HAS_LENGTH"
264
+ },
265
+ {
266
+ type: "validator/MATCHES_REGEX",
267
+ args: ["US"],
268
+ error: "error/MATCHES_REGEX"
269
+ },
270
+ "country"
271
+ ],
272
+ error: "error/HAS_LENGTH"
273
+ }
274
+ ],
275
+ errors: ["error/REQUIRED"],
276
+ hasErrors: true
277
+ }
278
+ },
279
+ actions: {
280
+ fields: {
281
+ country: {},
282
+ nameOnCard: {},
283
+ creditCardNumber: {},
284
+ expirationDate: {},
285
+ cvv: {},
286
+ zipCode: {}
287
+ },
288
+ form: {}
289
+ }
290
+ };
291
+ const paymentFormACHProps = {
292
+ showErrors: false,
293
+ fields: {
294
+ name: {
295
+ dirty: false,
296
+ rawValue: "",
297
+ validators: [
298
+ {
299
+ type: "validator/REQUIRED",
300
+ args: [],
301
+ error: "error/REQUIRED"
302
+ }
303
+ ],
304
+ constraints: [],
305
+ errors: ["error/REQUIRED"],
306
+ hasErrors: true
307
+ },
308
+ routingNumber: {
309
+ dirty: false,
310
+ rawValue: "",
311
+ validators: [
312
+ {
313
+ type: "validator/REQUIRED",
314
+ args: [],
315
+ error: "error/REQUIRED"
316
+ },
317
+ {
318
+ type: "validator/HAS_LENGTH",
319
+ args: [9, 9],
320
+ error: "error/HAS_LENGTH"
321
+ },
322
+ {
323
+ type: "validator/IS_ROUTING_NUMBER",
324
+ args: [],
325
+ error: "error/IS_ROUTING_NUMBER"
326
+ }
327
+ ],
328
+ constraints: [
329
+ {
330
+ type: "validator/ONLY_INTEGERS",
331
+ args: [],
332
+ error: "error/ONLY_INTEGERS"
333
+ },
334
+ {
335
+ type: "validator/HAS_LENGTH",
336
+ args: [0, 9],
337
+ error: "error/HAS_LENGTH"
338
+ }
339
+ ],
340
+ errors: ["error/REQUIRED"],
341
+ hasErrors: true
342
+ },
343
+ confirmRoutingNumber: {
344
+ dirty: false,
345
+ rawValue: "",
346
+ validators: [
347
+ {
348
+ type: "validator/MATCHES_FIELD",
349
+ args: ["routingNumber"],
350
+ error: "error/MATCHES_FIELD"
351
+ }
352
+ ],
353
+ constraints: [
354
+ {
355
+ type: "validator/ONLY_INTEGERS",
356
+ args: [],
357
+ error: "error/ONLY_INTEGERS"
358
+ },
359
+ {
360
+ type: "validator/HAS_LENGTH",
361
+ args: [0, 9],
362
+ error: "error/HAS_LENGTH"
363
+ }
364
+ ],
365
+ errors: [],
366
+ hasErrors: false
367
+ },
368
+ accountNumber: {
369
+ dirty: false,
370
+ rawValue: "",
371
+ validators: [
372
+ {
373
+ type: "validator/REQUIRED",
374
+ args: [],
375
+ error: "error/REQUIRED"
376
+ },
377
+ {
378
+ type: "validator/HAS_LENGTH",
379
+ args: [5, 17],
380
+ error: "error/HAS_LENGTH"
381
+ }
382
+ ],
383
+ constraints: [
384
+ {
385
+ type: "validator/ONLY_INTEGERS",
386
+ args: [],
387
+ error: "error/ONLY_INTEGERS"
388
+ },
389
+ {
390
+ type: "validator/HAS_LENGTH",
391
+ args: [0, 17],
392
+ error: "error/HAS_LENGTH"
393
+ }
394
+ ],
395
+ errors: ["error/REQUIRED"],
396
+ hasErrors: true
397
+ },
398
+ confirmAccountNumber: {
399
+ dirty: false,
400
+ rawValue: "",
401
+ validators: [
402
+ {
403
+ type: "validator/MATCHES_FIELD",
404
+ args: ["accountNumber"],
405
+ error: "error/MATCHES_FIELD"
406
+ }
407
+ ],
408
+ constraints: [
409
+ {
410
+ type: "validator/ONLY_INTEGERS",
411
+ args: [],
412
+ error: "error/ONLY_INTEGERS"
413
+ },
414
+ {
415
+ type: "validator/HAS_LENGTH",
416
+ args: [0, 17],
417
+ error: "error/HAS_LENGTH"
418
+ }
419
+ ],
420
+ errors: [],
421
+ hasErrors: false
422
+ },
423
+ accountType: {
424
+ dirty: false,
425
+ rawValue: "CHECKING",
426
+ validators: [
427
+ {
428
+ type: "validator/REQUIRED",
429
+ args: [],
430
+ error: "error/REQUIRED"
431
+ }
432
+ ],
433
+ constraints: [],
434
+ errors: [],
435
+ hasErrors: false
436
+ }
437
+ },
438
+ actions: {
439
+ fields: {
440
+ name: {},
441
+ routingNumber: {},
442
+ confirmRoutingNumber: {},
443
+ accountNumber: {},
444
+ confirmAccountNumber: {},
445
+ accountType: {}
446
+ },
447
+ form: {}
448
+ }
449
+ };
39
450
  const cardIconsLabel = `Accepting ${cardIcons
40
451
  .filter(ci => ci.enabled)
41
452
  ?.map((cardIcon, index) =>
@@ -47,14 +458,17 @@ const sections = [
47
458
  {
48
459
  id: "new-card-section",
49
460
  title: "New Card",
50
- content: <p>The form to add a credit card would go here.</p>,
461
+ content: <PaymentFormCard {...paymentFormCardProps} />,
51
462
  rightIconsLabel: cardIconsLabel,
52
463
  rightIcons: cardIcons
53
464
  },
54
- { id: "bar", title: "Bar", content: <div>Content 1</div> },
465
+ {
466
+ id: "new-bank-account-section",
467
+ title: "New bank account",
468
+ content: <PaymentFormACH {...paymentFormACHProps} />
469
+ },
55
470
  { id: "baz", title: "Baz", content: <div>Content 2</div> }
56
471
  ];
57
-
58
472
  export const radioSection = () => {
59
473
  const [openSection, setOpenSection] = useState("");
60
474
  return (