@thecb/components 9.3.4-beta.0 → 9.3.4-beta.11
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/index.cjs.js +3075 -2962
- package/dist/index.cjs.js.map +1 -1
- package/dist/index.esm.js +3075 -2962
- package/dist/index.esm.js.map +1 -1
- package/dist/src/apps/checkout/pages/payment/sub-pages/payment-amount/PaymentAmount_old.js +49322 -0
- package/package.json +1 -1
- package/src/.DS_Store +0 -0
- package/src/components/.DS_Store +0 -0
- package/src/components/atoms/.DS_Store +0 -0
- package/src/components/atoms/checkbox/Checkbox.js +2 -1
- package/src/components/atoms/dropdown/Dropdown.js +3 -3
- package/src/components/atoms/icons/.DS_Store +0 -0
- package/src/components/atoms/layouts/Motion.js +7 -10
- package/src/components/atoms/toggle-switch/ToggleSwitch.js +2 -1
- package/src/components/molecules/account-and-routing-modal/AccountAndRoutingModal.js +3 -0
- package/src/components/molecules/collapsible-section/CollapsibleSection.js +2 -1
- package/src/components/molecules/modal/Modal.js +16 -1
- package/src/components/molecules/obligation/modules/AutopayModalModule.js +3 -13
- package/src/components/molecules/payment-form-ach/PaymentFormACH.js +1 -0
- package/src/components/molecules/payment-form-card/PaymentFormCard.js +1 -0
- package/src/components/molecules/popover/Popover.js +2 -1
- package/src/components/molecules/radio-section/InnerRadioSection.js +207 -0
- package/src/components/molecules/radio-section/InnerRadioSection.theme.js +15 -0
- package/src/components/molecules/radio-section/RadioSection.js +120 -202
- package/src/components/molecules/radio-section/RadioSection.stories.js +85 -15
- package/src/components/molecules/radio-section/RadioSection.theme.js +2 -2
- package/src/components/molecules/radio-section/radio-button/RadioButton.js +1 -1
- package/src/components/molecules/terms-and-conditions/TermsAndConditions.stories.js +19 -2
- package/src/components/molecules/terms-and-conditions/TermsAndConditionsControlV1.js +3 -1
- package/src/components/molecules/terms-and-conditions/TermsAndConditionsControlV2.js +3 -1
- package/src/components/molecules/terms-and-conditions-modal/TermsAndConditionsModal.js +5 -1
- package/src/components/molecules/terms-and-conditions-modal/TermsAndConditionsModal.stories.js +8 -3
- package/src/constants/keyboard.js +7 -0
- package/src/util/general.js +10 -0
|
@@ -1,34 +1,40 @@
|
|
|
1
|
-
import React, { Fragment, useState } from "react";
|
|
2
|
-
import styled from "styled-components";
|
|
1
|
+
import React, { createRef, Fragment, useRef, useState } from "react";
|
|
3
2
|
import { themeComponent } from "../../../util/themeUtils";
|
|
4
3
|
import { fallbackValues } from "./RadioSection.theme";
|
|
5
|
-
import
|
|
6
|
-
import
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
4
|
+
import SolidDivider from "../../atoms/solid-divider/SolidDivider";
|
|
5
|
+
import { Box, Stack } from "../../atoms/layouts";
|
|
6
|
+
import { createIdFromString, wrapIndex } from "../../../util/general";
|
|
7
|
+
import {
|
|
8
|
+
ARROW_DOWN,
|
|
9
|
+
ARROW_LEFT,
|
|
10
|
+
ARROW_RIGHT,
|
|
11
|
+
ARROW_UP,
|
|
12
|
+
ENTER,
|
|
13
|
+
SPACEBAR
|
|
14
|
+
} from "../../../constants/keyboard";
|
|
15
|
+
import InnerRadioSection from "./InnerRadioSection";
|
|
16
|
+
/**
|
|
17
|
+
- The RadioSection component takes either a flat array (via the 'sections'
|
|
18
|
+
prop) of section objects or a multidimensional array (via the 'groupedSections' prop) of section objects. Note that if using a multidimensional array, the nesting cannot exceed 2 levels deep.
|
|
19
|
+
- Each 'section' object should look like:
|
|
20
|
+
{
|
|
21
|
+
title: <React Component(s)>,
|
|
22
|
+
id: <String> "identifier of section",
|
|
23
|
+
disabled: boolean, (displays section and grayed out radio but disables interaction)
|
|
24
|
+
hideRadioButton: boolean, (keeps section displayed but hides radio and disables open/close function),
|
|
25
|
+
hidden: boolean, (hides section entirely)
|
|
26
|
+
dataQa: string,
|
|
27
|
+
content: <React Component(s)> e.g.: <Box><Stack>cool content stuff</Stack></Box> (any collection of components will work),
|
|
28
|
+
rightTitleContent: <React Component(s)> (rendered on the very right of the title section, use to supplement "rightIcons" with text, as in expired CC status, or render other custom content)
|
|
29
|
+
}
|
|
30
|
+
- It also takes an "openSection" which should equal the id of the section that
|
|
31
|
+
should be open, along with "toggleOpenSection"
|
|
32
|
+
- RadioSection will call "toggleOpenSection" with the id of the section
|
|
33
|
+
that it is in.
|
|
34
|
+
- It is up to the engineer to store the open section value in state up from the
|
|
35
|
+
component using a useState() hook or a reducer.
|
|
36
|
+
- The section itself comes with some motion to open/close. To add more motion
|
|
37
|
+
to the content, wrap your content with a Motion layout primitive and provide appropriate props.
|
|
32
38
|
*/
|
|
33
39
|
|
|
34
40
|
const idString = section =>
|
|
@@ -48,56 +54,44 @@ const RadioSection = ({
|
|
|
48
54
|
openHeight = "auto",
|
|
49
55
|
containerStyles = "",
|
|
50
56
|
ariaDescribedBy,
|
|
51
|
-
isSectionRequired = false
|
|
57
|
+
isSectionRequired = false,
|
|
58
|
+
groupedSections,
|
|
59
|
+
...rest
|
|
52
60
|
}) => {
|
|
53
|
-
const
|
|
54
|
-
if (e?.keyCode === 13 || e?.keyCode === 32) {
|
|
55
|
-
toggleOpenSection(id);
|
|
56
|
-
}
|
|
57
|
-
};
|
|
61
|
+
const [focused, setFocused] = useState(null);
|
|
58
62
|
|
|
59
|
-
const
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
opacity: 1,
|
|
63
|
-
transition: {
|
|
64
|
-
duration: 0.3,
|
|
65
|
-
ease: [0.04, 0.62, 0.23, 0.98],
|
|
66
|
-
staggerChildren: staggeredAnimation ? 0.15 : 0
|
|
67
|
-
}
|
|
68
|
-
},
|
|
69
|
-
closed: {
|
|
70
|
-
height: 0,
|
|
71
|
-
opacity: 0,
|
|
72
|
-
transition: {
|
|
73
|
-
duration: 0.3,
|
|
74
|
-
ease: [0.04, 0.62, 0.23, 0.98],
|
|
75
|
-
staggerChildren: staggeredAnimation ? 0.15 : 0,
|
|
76
|
-
staggerDirection: -1
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
};
|
|
63
|
+
const sectionRefs = useRef(
|
|
64
|
+
[...Array(sections.length)].map(() => createRef())
|
|
65
|
+
);
|
|
80
66
|
|
|
81
|
-
const
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
border-radius: 0px;
|
|
86
|
-
transform-origin: 100% 0;
|
|
67
|
+
const handleKeyDown = (id, e, i) => {
|
|
68
|
+
if (e.currentTarget !== e.target) {
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
87
71
|
|
|
88
|
-
|
|
89
|
-
|
|
72
|
+
// Allow Enter and Space to select a section
|
|
73
|
+
if (e.keyCode === ENTER || e.keyCode === SPACEBAR) {
|
|
74
|
+
e.preventDefault();
|
|
75
|
+
toggleOpenSection(id);
|
|
90
76
|
}
|
|
91
|
-
`;
|
|
92
77
|
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
78
|
+
// Allow Up and Down arrow navigation between sections
|
|
79
|
+
if (
|
|
80
|
+
e.keyCode == ARROW_UP ||
|
|
81
|
+
e.keyCode == ARROW_DOWN ||
|
|
82
|
+
e.keyCode == ARROW_LEFT ||
|
|
83
|
+
e.keyCode == ARROW_RIGHT
|
|
84
|
+
) {
|
|
85
|
+
e.preventDefault();
|
|
86
|
+
const indexIncrement =
|
|
87
|
+
e.keyCode == ARROW_RIGHT || e.keyCode == ARROW_DOWN ? 1 : -1;
|
|
88
|
+
const nextIndex = wrapIndex(i + indexIncrement, sections.length);
|
|
99
89
|
|
|
100
|
-
|
|
90
|
+
sectionRefs?.current[nextIndex]?.current?.focus();
|
|
91
|
+
setFocused(sections[nextIndex]?.id);
|
|
92
|
+
toggleOpenSection(sections[nextIndex]?.id);
|
|
93
|
+
}
|
|
94
|
+
};
|
|
101
95
|
|
|
102
96
|
return (
|
|
103
97
|
<Box
|
|
@@ -108,141 +102,65 @@ const RadioSection = ({
|
|
|
108
102
|
>
|
|
109
103
|
<Stack
|
|
110
104
|
childGap="0"
|
|
111
|
-
|
|
105
|
+
role="radiogroup"
|
|
112
106
|
aria-required={isSectionRequired}
|
|
107
|
+
{...rest}
|
|
113
108
|
>
|
|
114
|
-
{sections
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
aria-checked={openSection === section.id}
|
|
131
|
-
aria-disabled={section.disabled}
|
|
132
|
-
aria-required={section?.required}
|
|
133
|
-
>
|
|
134
|
-
<Stack childGap="0">
|
|
135
|
-
<Box
|
|
136
|
-
padding={
|
|
137
|
-
section.hideRadioButton ? "1.5rem" : "1.25rem 1.5rem"
|
|
109
|
+
{!!sections &&
|
|
110
|
+
sections
|
|
111
|
+
.filter(section => !section.hidden)
|
|
112
|
+
.map((section, i) => (
|
|
113
|
+
<Fragment key={`radio-section-${sections.indexOf(section)}`}>
|
|
114
|
+
<InnerRadioSection
|
|
115
|
+
sectionIndex={i}
|
|
116
|
+
section={section}
|
|
117
|
+
sectionRefs={sectionRefs}
|
|
118
|
+
focused={focused}
|
|
119
|
+
setFocused={setFocused}
|
|
120
|
+
openHeight={openHeight}
|
|
121
|
+
openSection={openSection}
|
|
122
|
+
toggleOpenSection={toggleOpenSection}
|
|
123
|
+
onKeyDown={e =>
|
|
124
|
+
!section.disabled && handleKeyDown(section.id, e, i)
|
|
138
125
|
}
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
}
|
|
154
|
-
key={`header-${section.id}`}
|
|
155
|
-
borderSize="0px"
|
|
156
|
-
borderColor={themeValues.borderColor}
|
|
157
|
-
borderWidthOverride={
|
|
158
|
-
openSection === section.id && !!section.content
|
|
159
|
-
? `0px 0px 1px 0px`
|
|
160
|
-
: ``
|
|
161
|
-
}
|
|
162
|
-
extraStyles={!section.disabled ? "cursor: pointer;" : ""}
|
|
163
|
-
dataQa={section.dataQa ? section.dataQa : section.id}
|
|
126
|
+
ariaLabelledBy={section.id}
|
|
127
|
+
ariaDescribedBy={`right-icons-${idString(section)}`}
|
|
128
|
+
/>
|
|
129
|
+
</Fragment>
|
|
130
|
+
))}
|
|
131
|
+
{!!groupedSections &&
|
|
132
|
+
groupedSections.map(sectionGroup =>
|
|
133
|
+
sectionGroup
|
|
134
|
+
.filter(unfilteredSection => !unfilteredSection.hidden)
|
|
135
|
+
.map((section, i) => (
|
|
136
|
+
<Fragment
|
|
137
|
+
key={`radio-section-${groupedSections.indexOf(
|
|
138
|
+
sectionGroup
|
|
139
|
+
)}-${sectionGroup.indexOf(section)}}`}
|
|
164
140
|
>
|
|
165
|
-
<
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
}
|
|
185
|
-
tabIndex="-1"
|
|
186
|
-
isRequired={section?.required}
|
|
187
|
-
/>
|
|
188
|
-
</Box>
|
|
189
|
-
)}
|
|
190
|
-
{section.titleIcon && (
|
|
191
|
-
<Cluster align="center">{section.titleIcon}</Cluster>
|
|
192
|
-
)}
|
|
193
|
-
<Box padding={section.titleIcon ? "0 0 0 8px" : "0"}>
|
|
194
|
-
<Text
|
|
195
|
-
as="label"
|
|
196
|
-
htmlFor={`radio-input-${idString(section)}`}
|
|
197
|
-
color={CHARADE_GREY}
|
|
198
|
-
>
|
|
199
|
-
{section.title}
|
|
200
|
-
</Text>
|
|
201
|
-
</Box>
|
|
202
|
-
</Cluster>
|
|
203
|
-
{section.rightIcons && (
|
|
204
|
-
<Cluster
|
|
205
|
-
childGap="0.5rem"
|
|
206
|
-
aria-label={section?.rightIconsLabel || null}
|
|
207
|
-
role={section?.rightIconsRole || null}
|
|
208
|
-
>
|
|
209
|
-
{section.rightIcons.map(icon => (
|
|
210
|
-
<RightIcon
|
|
211
|
-
src={icon.img}
|
|
212
|
-
key={icon.img}
|
|
213
|
-
fade={!icon.enabled}
|
|
214
|
-
isMobile={isMobile}
|
|
215
|
-
alt={icon.altText}
|
|
216
|
-
aria-disabled={!icon.enabled}
|
|
217
|
-
/>
|
|
218
|
-
))}
|
|
219
|
-
</Cluster>
|
|
220
|
-
)}
|
|
221
|
-
{section.rightTitleContent && (
|
|
222
|
-
<Fragment>{section.rightTitleContent}</Fragment>
|
|
141
|
+
<InnerRadioSection
|
|
142
|
+
sectionIndex={i}
|
|
143
|
+
section={section}
|
|
144
|
+
sectionRefs={sectionRefs}
|
|
145
|
+
focused={focused}
|
|
146
|
+
setFocused={setFocused}
|
|
147
|
+
openHeight={openHeight}
|
|
148
|
+
ariaLabelledBy={section.id}
|
|
149
|
+
ariaDescribedBy={`right-icons-${idString(section)}`}
|
|
150
|
+
openSection={openSection}
|
|
151
|
+
toggleOpenSection={toggleOpenSection}
|
|
152
|
+
/>
|
|
153
|
+
{sectionGroup.indexOf(section) === sectionGroup.length - 1 &&
|
|
154
|
+
groupedSections.indexOf(sectionGroup) !==
|
|
155
|
+
groupedSections.length - 1 && (
|
|
156
|
+
<SolidDivider
|
|
157
|
+
borderSize="1px" // Resulting line is 2px thick due to border from other element
|
|
158
|
+
color={themeValues.borderColor}
|
|
159
|
+
/>
|
|
223
160
|
)}
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
{openSection === section.id && (
|
|
228
|
-
<Motion
|
|
229
|
-
key={`content-${section.id}`}
|
|
230
|
-
padding="0"
|
|
231
|
-
background={themeValues.bodyBackgroundColor}
|
|
232
|
-
layoutTransition
|
|
233
|
-
initial="closed"
|
|
234
|
-
animate="open"
|
|
235
|
-
exit="closed"
|
|
236
|
-
variants={wrapper}
|
|
237
|
-
extraStyles={`transform-origin: 100% 0;`}
|
|
238
|
-
>
|
|
239
|
-
{section.content}
|
|
240
|
-
</Motion>
|
|
241
|
-
)}
|
|
242
|
-
</AnimatePresence>
|
|
243
|
-
</Stack>
|
|
244
|
-
</Motion>
|
|
245
|
-
))}
|
|
161
|
+
</Fragment>
|
|
162
|
+
))
|
|
163
|
+
)}
|
|
246
164
|
</Stack>
|
|
247
165
|
</Box>
|
|
248
166
|
);
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import React, { useState } from "react";
|
|
2
|
-
import {
|
|
2
|
+
import { boolean } from "@storybook/addon-knobs";
|
|
3
3
|
|
|
4
4
|
import RadioSection from "./RadioSection";
|
|
5
5
|
import page from "../../../../.storybook/page";
|
|
6
|
+
import { Box } from "../../atoms/layouts";
|
|
6
7
|
|
|
7
8
|
const story = page({
|
|
8
9
|
title: "Components|Molecules/RadioSection",
|
|
@@ -43,30 +44,99 @@ const cardIconsLabel = `Accepting ${cardIcons
|
|
|
43
44
|
? ` and ${cardIcon.altText}.`
|
|
44
45
|
: ` ` + cardIcon.altText
|
|
45
46
|
)}`;
|
|
47
|
+
const groupedSections = [
|
|
48
|
+
[
|
|
49
|
+
{
|
|
50
|
+
id: "new-card-section",
|
|
51
|
+
title: "Group 1: New Card",
|
|
52
|
+
content: <p>The form to add a credit card would go here.</p>,
|
|
53
|
+
rightIconsLabel: cardIconsLabel,
|
|
54
|
+
rightIcons: cardIcons,
|
|
55
|
+
required: true
|
|
56
|
+
},
|
|
57
|
+
{
|
|
58
|
+
id: "new-bank-section",
|
|
59
|
+
title: "Group 1: New Bank Account",
|
|
60
|
+
content: <p>The form to add a credit card would go here.</p>,
|
|
61
|
+
required: true
|
|
62
|
+
}
|
|
63
|
+
],
|
|
64
|
+
[
|
|
65
|
+
{
|
|
66
|
+
id: "bar",
|
|
67
|
+
title: "Group 2: Bar",
|
|
68
|
+
content: <div>Content 1</div>,
|
|
69
|
+
required: true
|
|
70
|
+
}
|
|
71
|
+
],
|
|
72
|
+
[
|
|
73
|
+
{
|
|
74
|
+
id: "bar2",
|
|
75
|
+
title: "Group 3: Bar",
|
|
76
|
+
content: <div>Content 1</div>,
|
|
77
|
+
required: true
|
|
78
|
+
},
|
|
79
|
+
{
|
|
80
|
+
id: "baz",
|
|
81
|
+
title: "Group 3: Baz",
|
|
82
|
+
content: <div>Content 1</div>,
|
|
83
|
+
required: true
|
|
84
|
+
}
|
|
85
|
+
]
|
|
86
|
+
];
|
|
46
87
|
const sections = [
|
|
47
88
|
{
|
|
48
|
-
id: "new-card-section",
|
|
49
|
-
title: "New Card",
|
|
50
|
-
content: <
|
|
89
|
+
id: "new-card-section-2",
|
|
90
|
+
title: "Section 1: New Card",
|
|
91
|
+
content: <Box>The form to add a credit card would go here.</Box>,
|
|
51
92
|
rightIconsLabel: cardIconsLabel,
|
|
52
93
|
rightIcons: cardIcons,
|
|
53
94
|
required: true
|
|
54
95
|
},
|
|
55
|
-
{
|
|
56
|
-
|
|
96
|
+
{
|
|
97
|
+
id: "bar3",
|
|
98
|
+
title: "Section 1: Bar",
|
|
99
|
+
content: <div>Content 1</div>,
|
|
100
|
+
required: true
|
|
101
|
+
},
|
|
102
|
+
{ id: "baz2", title: "Section 1: Baz", content: <div>Content 2</div> }
|
|
57
103
|
];
|
|
58
104
|
|
|
59
105
|
export const radioSection = () => {
|
|
60
106
|
const [openSection, setOpenSection] = useState("");
|
|
107
|
+
const [openGroupedSection, setOpenGroupedSection] = useState("");
|
|
61
108
|
return (
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
109
|
+
<>
|
|
110
|
+
<Box padding="0 1rem" extraStyles="text-align: center;">
|
|
111
|
+
<p>
|
|
112
|
+
Using <b>sections</b>, a flat array of section objects.
|
|
113
|
+
</p>
|
|
114
|
+
</Box>
|
|
115
|
+
<RadioSection
|
|
116
|
+
isMobile={boolean("isMobile", false, "props")}
|
|
117
|
+
supportsTouch={boolean("isMobile", false, "props")}
|
|
118
|
+
toggleOpenSection={setOpenSection}
|
|
119
|
+
openSection={openSection}
|
|
120
|
+
staggeredAnimation={boolean("staggeredAnimation", false, "props")}
|
|
121
|
+
sections={sections}
|
|
122
|
+
isSectionRequired={true}
|
|
123
|
+
/>
|
|
124
|
+
<Box />
|
|
125
|
+
<Box padding="0 1rem" extraStyles="text-align: center;">
|
|
126
|
+
<p>
|
|
127
|
+
Using <b>groupedSections</b>, a multidimensional array of sections,
|
|
128
|
+
instead of the <b>sections</b> prop.
|
|
129
|
+
</p>
|
|
130
|
+
</Box>
|
|
131
|
+
<RadioSection
|
|
132
|
+
isMobile={boolean("isMobile", false, "props")}
|
|
133
|
+
supportsTouch={boolean("isMobile", false, "props")}
|
|
134
|
+
toggleOpenSection={setOpenGroupedSection}
|
|
135
|
+
openSection={openGroupedSection}
|
|
136
|
+
staggeredAnimation={boolean("staggeredAnimation", false, "props")}
|
|
137
|
+
groupedSections={groupedSections}
|
|
138
|
+
isSectionRequired={true}
|
|
139
|
+
/>
|
|
140
|
+
</>
|
|
71
141
|
);
|
|
72
142
|
};
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import { WHITE,
|
|
1
|
+
import { WHITE, GHOST_GREY, ATHENS_GREY } from "../../../constants/colors";
|
|
2
2
|
|
|
3
3
|
const headingBackgroundColor = `${WHITE}`;
|
|
4
4
|
const headingDisabledColor = `${ATHENS_GREY}`;
|
|
5
5
|
const bodyBackgroundColor = "#eeeeee";
|
|
6
|
-
const borderColor = `${
|
|
6
|
+
const borderColor = `${GHOST_GREY}`;
|
|
7
7
|
const focusStyles = `outline: none;`;
|
|
8
8
|
|
|
9
9
|
export const fallbackValues = {
|
|
@@ -7,14 +7,31 @@ import { noop } from "../../../util/general";
|
|
|
7
7
|
|
|
8
8
|
const groupId = "props";
|
|
9
9
|
|
|
10
|
+
const Terms = () => (
|
|
11
|
+
<p>
|
|
12
|
+
Modal Content: Elit voluptate cupidatat in pariatur anim in excepteur non.{" "}
|
|
13
|
+
<a href="#modal-bottom" id="focus-me">
|
|
14
|
+
Laboris elit laboris labore pariatur incididunt
|
|
15
|
+
</a>{" "}
|
|
16
|
+
proident occaecat laboris sit elit. Dolor irure enim adipisicing irure
|
|
17
|
+
consectetur dolor enim eiusmod elit eiusmod ut. Pariatur ut quis et pariatur
|
|
18
|
+
nulla nostrud sit esse. Veniam est occaecat cupidatat est nulla dolor minim
|
|
19
|
+
nostrud anim ea voluptate. modal content. Elit voluptate cupidatat in
|
|
20
|
+
pariatur anim in excepteur non. Laboris elit laboris labore pariatur
|
|
21
|
+
incididunt proident occaecat laboris sit elit. Dolor irure enim adipisicing
|
|
22
|
+
irure consectetur dolor enim eiusmod elit eiusmod ut. Pariatur ut quis et
|
|
23
|
+
pariatur nulla nostrud sit esse.
|
|
24
|
+
</p>
|
|
25
|
+
);
|
|
26
|
+
|
|
10
27
|
export const termsAndConditions = () => (
|
|
11
28
|
<TermsAndConditions
|
|
12
29
|
version={select("version", ["v1", "v2"], "v1", groupId)}
|
|
13
30
|
onCheck={noop}
|
|
14
31
|
isChecked={boolean("isChecked", false, groupId)}
|
|
15
|
-
|
|
16
|
-
terms={text("terms", "terms and conditions modal text", groupId)}
|
|
32
|
+
terms={<Terms />}
|
|
17
33
|
error={boolean("error", false, groupId)}
|
|
34
|
+
initialFocusSelector={text("initialFocusSelector", "#focus-me", groupId)}
|
|
18
35
|
description={text("description", "I definitely agree to the", groupId)}
|
|
19
36
|
/>
|
|
20
37
|
);
|
|
@@ -10,7 +10,8 @@ const TermsAndConditionsControlV1 = ({
|
|
|
10
10
|
html,
|
|
11
11
|
terms,
|
|
12
12
|
error = false,
|
|
13
|
-
linkVariant
|
|
13
|
+
linkVariant,
|
|
14
|
+
initialFocusSelector = ""
|
|
14
15
|
}) => {
|
|
15
16
|
const [showTerms, toggleShowTerms] = useState(false);
|
|
16
17
|
return (
|
|
@@ -33,6 +34,7 @@ const TermsAndConditionsControlV1 = ({
|
|
|
33
34
|
isOpen={showTerms}
|
|
34
35
|
toggleOpen={toggleShowTerms}
|
|
35
36
|
linkVariant={linkVariant}
|
|
37
|
+
initialFocusSelector={initialFocusSelector}
|
|
36
38
|
/>
|
|
37
39
|
)}
|
|
38
40
|
</Stack>
|
|
@@ -28,7 +28,8 @@ const TermsAndConditionsControlV2 = ({
|
|
|
28
28
|
modalVariant = "default",
|
|
29
29
|
containerBackground = ATHENS_GREY,
|
|
30
30
|
checkboxMargin = "4px 8px 4px 4px",
|
|
31
|
-
modalTitle = "Terms and Conditions"
|
|
31
|
+
modalTitle = "Terms and Conditions",
|
|
32
|
+
initialFocusSelector = ""
|
|
32
33
|
}) => {
|
|
33
34
|
const [showTerms, toggleShowTerms] = useState(false);
|
|
34
35
|
const standardBoxShadow = generateShadows().standard.base;
|
|
@@ -79,6 +80,7 @@ const TermsAndConditionsControlV2 = ({
|
|
|
79
80
|
toggleOpen={toggleTerms}
|
|
80
81
|
linkVariant={modalVariant}
|
|
81
82
|
title={modalTitle}
|
|
83
|
+
initialFocusSelector={initialFocusSelector}
|
|
82
84
|
/>
|
|
83
85
|
)}
|
|
84
86
|
</Cluster>
|
|
@@ -15,7 +15,8 @@ const TermsAndConditionsModal = ({
|
|
|
15
15
|
terms,
|
|
16
16
|
variant,
|
|
17
17
|
linkVariant = "p",
|
|
18
|
-
themeValues
|
|
18
|
+
themeValues,
|
|
19
|
+
initialFocusSelector = ""
|
|
19
20
|
}) => (
|
|
20
21
|
<Modal
|
|
21
22
|
modalOpen={isOpen}
|
|
@@ -42,6 +43,7 @@ const TermsAndConditionsModal = ({
|
|
|
42
43
|
toggleAccepted(true);
|
|
43
44
|
toggleOpen(false);
|
|
44
45
|
}}
|
|
46
|
+
initialFocusSelector={initialFocusSelector}
|
|
45
47
|
>
|
|
46
48
|
<Text
|
|
47
49
|
variant={linkVariant}
|
|
@@ -52,6 +54,8 @@ const TermsAndConditionsModal = ({
|
|
|
52
54
|
weight={themeValues.fontWeight}
|
|
53
55
|
hoverStyles={themeValues.modalLinkHoverFocus}
|
|
54
56
|
extraStyles={`display: inline-block; width: fit-content; cursor: pointer`}
|
|
57
|
+
role="button" // This should always be a "button" since it opens a modal
|
|
58
|
+
className="modal-trigger"
|
|
55
59
|
>
|
|
56
60
|
{link}
|
|
57
61
|
</Text>
|
package/src/components/molecules/terms-and-conditions-modal/TermsAndConditionsModal.stories.js
CHANGED
|
@@ -20,17 +20,22 @@ const linkVariants = {
|
|
|
20
20
|
pXL: "PXL"
|
|
21
21
|
};
|
|
22
22
|
|
|
23
|
+
const Terms = () => (
|
|
24
|
+
<p>
|
|
25
|
+
Terms content with a <a href="#">link</a> that should NOT get initial focus.
|
|
26
|
+
Instead, the <code>Cancel</code> button below should.
|
|
27
|
+
</p>
|
|
28
|
+
);
|
|
23
29
|
export const termsAndConditionsModal = () => (
|
|
24
30
|
<TermsAndConditionsModal
|
|
25
31
|
link={text("text", "Show modal", groupId)}
|
|
26
32
|
title={text("title", "Title", groupId)}
|
|
27
33
|
isOpen={boolean("isOpen", false, groupId)}
|
|
28
|
-
// toggleOpen={setShowTerms}
|
|
29
|
-
// toggleAccepted={toggleTermsAccepted}
|
|
30
34
|
acceptText={text("acceptText", "Accept", groupId)}
|
|
31
|
-
terms={
|
|
35
|
+
terms={<Terms />}
|
|
32
36
|
variant={select("variants", variants, "default", groupId)}
|
|
33
37
|
linkVariant={select("linkVariants", linkVariants, groupId)}
|
|
38
|
+
initialFocusSelector="[name='Cancel']"
|
|
34
39
|
/>
|
|
35
40
|
);
|
|
36
41
|
|
package/src/util/general.js
CHANGED
|
@@ -163,3 +163,13 @@ export const titleCaseString = string => {
|
|
|
163
163
|
export const kebabCaseString = string => {
|
|
164
164
|
return string?.replaceAll(" ", "-").toLowerCase();
|
|
165
165
|
};
|
|
166
|
+
|
|
167
|
+
export const wrapIndex = (index, length) => {
|
|
168
|
+
if (index <= -1) {
|
|
169
|
+
return length - 1;
|
|
170
|
+
} else if (index >= length) {
|
|
171
|
+
return 0;
|
|
172
|
+
} else {
|
|
173
|
+
return index;
|
|
174
|
+
}
|
|
175
|
+
};
|