@thecb/components 9.3.1-beta.1 → 9.3.1-beta.2

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.3.1-beta.1",
3
+ "version": "9.3.1-beta.2",
4
4
  "description": "Common lib for CityBase react components",
5
5
  "main": "dist/index.cjs.js",
6
6
  "typings": "dist/index.d.ts",
@@ -1,5 +1,6 @@
1
1
  import React, { Fragment, useState } from "react";
2
2
  import styled from "styled-components";
3
+ import SolidDivider from "../../atoms/solid-divider/SolidDivider";
3
4
  import { themeComponent } from "../../../util/themeUtils";
4
5
  import { fallbackValues } from "./RadioSection.theme";
5
6
  import { AnimatePresence } from "framer-motion";
@@ -49,7 +50,8 @@ const RadioSection = ({
49
50
  containerStyles = "",
50
51
  ariaDescribedBy,
51
52
  isSectionRequired = false,
52
- legendText = ""
53
+ legendText = "",
54
+ sectionGroups = null
53
55
  }) => {
54
56
  const handleKeyDown = (id, e) => {
55
57
  if (e?.keyCode === 13 || e?.keyCode === 32) {
@@ -108,149 +110,321 @@ const RadioSection = ({
108
110
  extraStyles={containerStyles}
109
111
  >
110
112
  <Stack childGap="0">
111
- <fieldset role="radiogroup" tabIndex="0" required={isSectionRequired}>
112
- <legend>
113
- <Box
114
- width="0"
115
- srOnly={true}
116
- border="0"
117
- padding="0"
118
- margin="0"
119
- ></Box>
120
- </legend>
121
- {sections
122
- .filter(section => !section.hidden)
123
- .map(section => (
124
- <Motion
125
- tabIndex={
126
- section.hideRadioButton || section.disabled ? "-1" : "0"
127
- }
128
- onKeyDown={e =>
129
- !section.disabled && handleKeyDown(section.id, e)
130
- }
131
- onFocus={() => !section.disabled && setFocused(section.id)}
132
- onBlur={() => !section.disabled && setFocused(null)}
133
- hoverStyles={themeValues.focusStyles}
134
- animate={openSection === section.id ? "open" : "closed"}
135
- initial={initiallyOpen ? "open" : "closed"}
136
- key={`item-${section.id}`}
137
- extraStyles={borderStyles}
138
- role="radio"
139
- aria-checked={openSection === section.id}
140
- aria-disabled={section.disabled}
141
- aria-required={section?.required}
142
- >
143
- <Stack childGap="0">
144
- <Box
145
- padding={
146
- section.hideRadioButton ? "1.5rem" : "1.25rem 1.5rem"
147
- }
148
- background={
149
- section.disabled
150
- ? themeValues.headingDisabledColor
151
- : themeValues.headingBackgroundColor
152
- }
153
- onClick={
154
- (isMobile && supportsTouch) || section.disabled
155
- ? noop
156
- : () => toggleOpenSection(section.id)
157
- }
158
- onTouchEnd={
159
- isMobile && supportsTouch && !section.disabled
160
- ? () => toggleOpenSection(section.id)
161
- : noop
162
- }
163
- key={`header-${section.id}`}
164
- borderSize="0px"
165
- borderColor={themeValues.borderColor}
166
- borderWidthOverride={
167
- openSection === section.id && !!section.content
168
- ? `0px 0px 1px 0px`
169
- : ``
170
- }
171
- extraStyles={!section.disabled ? "cursor: pointer;" : ""}
172
- dataQa={section.dataQa ? section.dataQa : section.id}
173
- >
174
- <Cluster
175
- justify="space-between"
176
- align="center"
177
- childGap="1px"
178
- nowrap
113
+ <fieldset
114
+ role="radiogroup"
115
+ tabIndex="0"
116
+ aria-required={isSectionRequired}
117
+ style={{
118
+ padding: 0,
119
+ margin: 0,
120
+ border: 0
121
+ }}
122
+ >
123
+ <Box as="legend" srOnly={true} padding="0" margin="0">
124
+ {legendText}
125
+ </Box>
126
+ {sectionGroups &&
127
+ sectionGroups.map(sectionGroup => {
128
+ let prependedItem = "";
129
+ if (sectionGroups.indexOf(sectionGroup) !== 0) {
130
+ prependedItem = <SolidDivider />;
131
+ }
132
+ return (
133
+ <>
134
+ {prependedItem}
135
+ {sectionGroup
136
+ .filter(unfilteredSection => !unfilteredSection.hidden)
137
+ .map(section => (
138
+ <Motion
139
+ tabIndex={
140
+ section.hideRadioButton || section.disabled
141
+ ? "-1"
142
+ : "0"
143
+ }
144
+ onKeyDown={e =>
145
+ !section.disabled && handleKeyDown(section.id, e)
146
+ }
147
+ onFocus={() =>
148
+ !section.disabled && setFocused(section.id)
149
+ }
150
+ onBlur={() => !section.disabled && setFocused(null)}
151
+ hoverStyles={themeValues.focusStyles}
152
+ animate={openSection === section.id ? "open" : "closed"}
153
+ initial={initiallyOpen ? "open" : "closed"}
154
+ key={`item-${section.id}`}
155
+ extraStyles={borderStyles}
156
+ role="radio"
157
+ aria-checked={openSection === section.id}
158
+ aria-disabled={section.disabled}
159
+ aria-required={section?.required}
160
+ >
161
+ <Stack childGap="0">
162
+ <Box
163
+ padding={
164
+ section.hideRadioButton
165
+ ? "1.5rem"
166
+ : "1.25rem 1.5rem"
167
+ }
168
+ background={
169
+ section.disabled
170
+ ? themeValues.headingDisabledColor
171
+ : themeValues.headingBackgroundColor
172
+ }
173
+ onClick={
174
+ (isMobile && supportsTouch) || section.disabled
175
+ ? noop
176
+ : () => toggleOpenSection(section.id)
177
+ }
178
+ onTouchEnd={
179
+ isMobile && supportsTouch && !section.disabled
180
+ ? () => toggleOpenSection(section.id)
181
+ : noop
182
+ }
183
+ key={`header-${section.id}`}
184
+ borderSize="0px"
185
+ borderColor={themeValues.borderColor}
186
+ borderWidthOverride={
187
+ openSection === section.id && !!section.content
188
+ ? `0px 0px 1px 0px`
189
+ : ``
190
+ }
191
+ extraStyles={
192
+ !section.disabled ? "cursor: pointer;" : ""
193
+ }
194
+ dataQa={
195
+ section.dataQa ? section.dataQa : section.id
196
+ }
197
+ >
198
+ <Cluster
199
+ justify="space-between"
200
+ align="center"
201
+ childGap="1px"
202
+ nowrap
203
+ >
204
+ <Cluster
205
+ justify="flex-start"
206
+ align="center"
207
+ nowrap
208
+ >
209
+ {!section.hideRadioButton && (
210
+ <Box padding="0">
211
+ <RadioButton
212
+ id={`radio-input-${idString(section)}`}
213
+ name={idString(section)}
214
+ ariaDescribedBy={ariaDescribedBy}
215
+ radioOn={openSection === section.id}
216
+ radioFocused={focused === section.id}
217
+ toggleRadio={
218
+ section.disabled
219
+ ? noop
220
+ : () => toggleOpenSection(section.id)
221
+ }
222
+ isRequired={section?.required}
223
+ />
224
+ </Box>
225
+ )}
226
+ {section.titleIcon && (
227
+ <Cluster align="center">
228
+ {section.titleIcon}
229
+ </Cluster>
230
+ )}
231
+ <Box
232
+ padding={
233
+ section.titleIcon ? "0 0 0 8px" : "0"
234
+ }
235
+ >
236
+ <Text
237
+ as="label"
238
+ htmlFor={`radio-input-${idString(section)}`}
239
+ color={CHARADE_GREY}
240
+ >
241
+ {section.title}
242
+ </Text>
243
+ </Box>
244
+ </Cluster>
245
+ {section.rightIcons && (
246
+ <Cluster
247
+ childGap="0.5rem"
248
+ aria-label={section?.rightIconsLabel || null}
249
+ role={section?.rightIconsRole || null}
250
+ >
251
+ {section.rightIcons.map(icon => (
252
+ <RightIcon
253
+ src={icon.img}
254
+ key={icon.img}
255
+ fade={!icon.enabled}
256
+ isMobile={isMobile}
257
+ alt={icon.altText}
258
+ aria-disabled={!icon.enabled}
259
+ />
260
+ ))}
261
+ </Cluster>
262
+ )}
263
+ {section.rightTitleContent && (
264
+ <Fragment>{section.rightTitleContent}</Fragment>
265
+ )}
266
+ </Cluster>
267
+ </Box>
268
+ <AnimatePresence initial={false}>
269
+ {openSection === section.id && (
270
+ <Motion
271
+ key={`content-${section.id}`}
272
+ padding="0"
273
+ background={themeValues.bodyBackgroundColor}
274
+ layoutTransition
275
+ initial="closed"
276
+ animate="open"
277
+ exit="closed"
278
+ variants={wrapper}
279
+ extraStyles={`transform-origin: 100% 0;`}
280
+ >
281
+ {section.content}
282
+ </Motion>
283
+ )}
284
+ </AnimatePresence>
285
+ </Stack>
286
+ </Motion>
287
+ ))}
288
+ </>
289
+ );
290
+ })}
291
+ {sections &&
292
+ sections
293
+ .filter(section => !section.hidden)
294
+ .map(section => (
295
+ <Motion
296
+ tabIndex={
297
+ section.hideRadioButton || section.disabled ? "-1" : "0"
298
+ }
299
+ onKeyDown={e =>
300
+ !section.disabled && handleKeyDown(section.id, e)
301
+ }
302
+ onFocus={() => !section.disabled && setFocused(section.id)}
303
+ onBlur={() => !section.disabled && setFocused(null)}
304
+ hoverStyles={themeValues.focusStyles}
305
+ animate={openSection === section.id ? "open" : "closed"}
306
+ initial={initiallyOpen ? "open" : "closed"}
307
+ key={`item-${section.id}`}
308
+ extraStyles={borderStyles}
309
+ >
310
+ <Stack childGap="0">
311
+ <Box
312
+ padding={
313
+ section.hideRadioButton ? "1.5rem" : "1.25rem 1.5rem"
314
+ }
315
+ background={
316
+ section.disabled
317
+ ? themeValues.headingDisabledColor
318
+ : themeValues.headingBackgroundColor
319
+ }
320
+ onClick={
321
+ (isMobile && supportsTouch) || section.disabled
322
+ ? noop
323
+ : () => toggleOpenSection(section.id)
324
+ }
325
+ onTouchEnd={
326
+ isMobile && supportsTouch && !section.disabled
327
+ ? () => toggleOpenSection(section.id)
328
+ : noop
329
+ }
330
+ key={`header-${section.id}`}
331
+ borderSize="0px"
332
+ borderColor={themeValues.borderColor}
333
+ borderWidthOverride={
334
+ openSection === section.id && !!section.content
335
+ ? `0px 0px 1px 0px`
336
+ : ``
337
+ }
338
+ extraStyles={!section.disabled ? "cursor: pointer;" : ""}
339
+ dataQa={section.dataQa ? section.dataQa : section.id}
340
+ role="radio"
341
+ aria-checked={openSection === section.id}
342
+ aria-disabled={section.disabled}
343
+ aria-required={section?.required}
344
+ tabIndex="0"
179
345
  >
180
- <Cluster justify="flex-start" align="center" nowrap>
181
- {!section.hideRadioButton && (
182
- <Box padding="0">
183
- <RadioButton
184
- id={`radio-input-${idString(section)}`}
185
- name={idString(section)}
186
- ariaDescribedBy={ariaDescribedBy}
187
- radioOn={openSection === section.id}
188
- radioFocused={focused === section.id}
189
- toggleRadio={
190
- section.disabled
191
- ? noop
192
- : () => toggleOpenSection(section.id)
193
- }
194
- isRequired={section?.required}
195
- />
346
+ <Cluster
347
+ justify="space-between"
348
+ align="center"
349
+ childGap="1px"
350
+ nowrap
351
+ >
352
+ <Cluster justify="flex-start" align="center" nowrap>
353
+ {!section.hideRadioButton && (
354
+ <Box padding="0">
355
+ <RadioButton
356
+ id={`radio-input-${idString(section)}`}
357
+ name={idString(section)}
358
+ ariaDescribedBy={ariaDescribedBy}
359
+ radioOn={openSection === section.id}
360
+ radioFocused={focused === section.id}
361
+ toggleRadio={
362
+ section.disabled
363
+ ? noop
364
+ : () => toggleOpenSection(section.id)
365
+ }
366
+ isRequired={section?.required}
367
+ />
368
+ </Box>
369
+ )}
370
+ {section.titleIcon && (
371
+ <Cluster align="center">
372
+ {section.titleIcon}
373
+ </Cluster>
374
+ )}
375
+ <Box padding={section.titleIcon ? "0 0 0 8px" : "0"}>
376
+ <Text
377
+ as="label"
378
+ htmlFor={`radio-input-${idString(section)}`}
379
+ color={CHARADE_GREY}
380
+ >
381
+ {section.title}
382
+ </Text>
196
383
  </Box>
384
+ </Cluster>
385
+ {section.rightIcons && (
386
+ <Cluster
387
+ childGap="0.5rem"
388
+ aria-label={section?.rightIconsLabel || null}
389
+ role={section?.rightIconsRole || null}
390
+ >
391
+ {section.rightIcons.map(icon => (
392
+ <RightIcon
393
+ src={icon.img}
394
+ key={icon.img}
395
+ fade={!icon.enabled}
396
+ isMobile={isMobile}
397
+ alt={icon.altText}
398
+ aria-disabled={!icon.enabled}
399
+ />
400
+ ))}
401
+ </Cluster>
197
402
  )}
198
- {section.titleIcon && (
199
- <Cluster align="center">{section.titleIcon}</Cluster>
403
+ {section.rightTitleContent && (
404
+ <Fragment>{section.rightTitleContent}</Fragment>
200
405
  )}
201
- <Box padding={section.titleIcon ? "0 0 0 8px" : "0"}>
202
- <Text
203
- as="label"
204
- htmlFor={`radio-input-${idString(section)}`}
205
- color={CHARADE_GREY}
206
- >
207
- {section.title}
208
- </Text>
209
- </Box>
210
406
  </Cluster>
211
- {section.rightIcons && (
212
- <Cluster
213
- childGap="0.5rem"
214
- aria-label={section?.rightIconsLabel || null}
215
- role={section?.rightIconsRole || null}
407
+ </Box>
408
+ <AnimatePresence initial={false}>
409
+ {openSection === section.id && (
410
+ <Motion
411
+ key={`content-${section.id}`}
412
+ padding="0"
413
+ background={themeValues.bodyBackgroundColor}
414
+ layoutTransition
415
+ initial="closed"
416
+ animate="open"
417
+ exit="closed"
418
+ variants={wrapper}
419
+ extraStyles={`transform-origin: 100% 0;`}
216
420
  >
217
- {section.rightIcons.map(icon => (
218
- <RightIcon
219
- src={icon.img}
220
- key={icon.img}
221
- fade={!icon.enabled}
222
- isMobile={isMobile}
223
- alt={icon.altText}
224
- aria-disabled={!icon.enabled}
225
- />
226
- ))}
227
- </Cluster>
228
- )}
229
- {section.rightTitleContent && (
230
- <Fragment>{section.rightTitleContent}</Fragment>
421
+ {section.content}
422
+ </Motion>
231
423
  )}
232
- </Cluster>
233
- </Box>
234
- <AnimatePresence initial={false}>
235
- {openSection === section.id && (
236
- <Motion
237
- key={`content-${section.id}`}
238
- padding="0"
239
- background={themeValues.bodyBackgroundColor}
240
- layoutTransition
241
- initial="closed"
242
- animate="open"
243
- exit="closed"
244
- variants={wrapper}
245
- extraStyles={`transform-origin: 100% 0;`}
246
- >
247
- {section.content}
248
- </Motion>
249
- )}
250
- </AnimatePresence>
251
- </Stack>
252
- </Motion>
253
- ))}
424
+ </AnimatePresence>
425
+ </Stack>
426
+ </Motion>
427
+ ))}
254
428
  </fieldset>
255
429
  </Stack>
256
430
  </Box>
@@ -43,6 +43,22 @@ const cardIconsLabel = `Accepting ${cardIcons
43
43
  ? ` and ${cardIcon.altText}.`
44
44
  : ` ` + cardIcon.altText
45
45
  )}`;
46
+ const sectionGroups = [
47
+ [
48
+ {
49
+ id: "new-card-section",
50
+ title: "New Card",
51
+ content: <p>The form to add a credit card would go here.</p>,
52
+ rightIconsLabel: cardIconsLabel,
53
+ rightIcons: cardIcons,
54
+ required: true
55
+ }
56
+ ],
57
+ [
58
+ { id: "bar", title: "Bar", content: <div>Content 1</div>, required: true },
59
+ { id: "baz", title: "Baz", content: <div>Content 2</div> }
60
+ ]
61
+ ];
46
62
  const sections = [
47
63
  {
48
64
  id: "new-card-section",
@@ -59,15 +75,31 @@ const sections = [
59
75
  export const radioSection = () => {
60
76
  const [openSection, setOpenSection] = useState("");
61
77
  return (
62
- <RadioSection
63
- legendText="Storybook Story for RadioSection"
64
- isMobile={boolean("isMobile", false, "props")}
65
- supportsTouch={boolean("isMobile", false, "props")}
66
- toggleOpenSection={setOpenSection}
67
- openSection={openSection}
68
- staggeredAnimation={boolean("staggeredAnimation", false, "props")}
69
- sections={sections}
70
- isSectionRequired={true}
71
- />
78
+ <>
79
+ <h4>Radio Section with Grouped Sections</h4>
80
+ <RadioSection
81
+ legendText="Storybook Story for RadioSection"
82
+ isMobile={boolean("isMobile", false, "props")}
83
+ supportsTouch={boolean("isMobile", false, "props")}
84
+ toggleOpenSection={setOpenSection}
85
+ openSection={openSection}
86
+ staggeredAnimation={boolean("staggeredAnimation", false, "props")}
87
+ sectionGroups={sectionGroups}
88
+ isSectionRequired={true}
89
+ />
90
+ <br />
91
+ <br />
92
+ <h4>Radio Section with Flat Sections</h4>
93
+ <RadioSection
94
+ legendText="Storybook Story for RadioSection"
95
+ isMobile={boolean("isMobile", false, "props")}
96
+ supportsTouch={boolean("isMobile", false, "props")}
97
+ toggleOpenSection={setOpenSection}
98
+ openSection={openSection}
99
+ staggeredAnimation={boolean("staggeredAnimation", false, "props")}
100
+ sections={sections}
101
+ isSectionRequired={true}
102
+ />
103
+ </>
72
104
  );
73
105
  };