@thecb/components 9.2.11 → 9.2.13-beta.0

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.2.11",
3
+ "version": "9.2.13-beta.0",
4
4
  "description": "Common lib for CityBase react components",
5
5
  "main": "dist/index.cjs.js",
6
6
  "typings": "dist/index.d.ts",
@@ -95,7 +95,6 @@ const Checkbox = ({
95
95
  checkboxMargin = "0 16px 0 0",
96
96
  extraStyles,
97
97
  textExtraStyles,
98
- labelledById,
99
98
  dataQa = null
100
99
  }) => {
101
100
  const [focused, setFocused] = useState(false);
@@ -106,10 +105,6 @@ const Checkbox = ({
106
105
  }
107
106
  };
108
107
 
109
- const titleId = title ? `checkboxlabel-${name}` : undefined;
110
- const ariaLabelledById = labelledById ?? titleId;
111
- const ariaLabel = ariaLabelledById ? undefined : name;
112
-
113
108
  return (
114
109
  <Box
115
110
  padding="0"
@@ -127,8 +122,7 @@ const Checkbox = ({
127
122
  id={`checkbox-${name}`}
128
123
  disabled={disabled}
129
124
  name={name}
130
- aria-label={ariaLabel}
131
- aria-labelledby={ariaLabelledById}
125
+ aria-label={name}
132
126
  checked={checked}
133
127
  onChange={onChange}
134
128
  tabIndex="-1"
@@ -161,7 +155,6 @@ const Checkbox = ({
161
155
  </CheckboxContainer>
162
156
  {title && (
163
157
  <Text
164
- id={titleId}
165
158
  variant="p"
166
159
  weight={themeValues.textFontWeight}
167
160
  color={themeValues.textColor}
@@ -19,7 +19,6 @@ export const checkbox = () => (
19
19
  error={boolean("error", false, "props")}
20
20
  disabled={boolean("disabled", false, "props")}
21
21
  focused={boolean("focused", false, "props")}
22
- labelledById={text("labelledById", undefined, "props")}
23
22
  />
24
23
  );
25
24
 
@@ -318,10 +318,9 @@ const Dropdown = ({
318
318
  >
319
319
  <Box
320
320
  as="input"
321
- aria-multiline="false"
322
321
  autoComplete={autocompleteValue}
323
322
  aria-controls={`${ariaLabelledby}_listbox`}
324
- aria-activedescendant="focused_option"
323
+ aria-activedescendant={isOpen ? "focused_option" : undefined}
325
324
  aria-owns={`${ariaLabelledby}_listbox`}
326
325
  aria-haspopup="listbox"
327
326
  aria-labelledby={ariaLabelledby}
@@ -1,4 +1,4 @@
1
- import React, { Fragment } from "react";
1
+ import React, { Fragment, forwardRef } from "react";
2
2
  import { MotionWrapper } from "./Motion.styled";
3
3
  import { safeChildren } from "../../../util/general";
4
4
 
@@ -37,15 +37,12 @@ import { safeChildren } from "../../../util/general";
37
37
  This should be sufficient for most scenarios, but if you need to, you have the ability to make Motion act like all of the other primitives using the props provided.
38
38
  */
39
39
 
40
- export const Motion = ({
41
- position = "relative",
42
- padding = "0",
43
- children,
44
- ...rest
45
- }) => (
46
- <MotionWrapper position={position} padding={padding} {...rest}>
47
- {safeChildren(children, <Fragment />)}
48
- </MotionWrapper>
40
+ export const Motion = forwardRef(
41
+ ({ position = "relative", padding = "0", children, ...rest }, ref) => (
42
+ <MotionWrapper position={position} padding={padding} ref={ref} {...rest}>
43
+ {safeChildren(children, <Fragment />)}
44
+ </MotionWrapper>
45
+ )
49
46
  );
50
47
 
51
48
  export default Motion;
@@ -1,4 +1,4 @@
1
- import React, { Fragment, useState } from "react";
1
+ import React, { createRef, Fragment, 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";
@@ -48,12 +48,36 @@ const RadioSection = ({
48
48
  openHeight = "auto",
49
49
  containerStyles = "",
50
50
  ariaDescribedBy,
51
- isSectionRequired = false
51
+ isSectionRequired = false,
52
+ ...rest
52
53
  }) => {
53
- const handleKeyDown = (id, e) => {
54
+ const [focused, setFocused] = useState(null);
55
+ const sectionRefs = useRef(
56
+ [...Array(sections.length)].map(() => createRef())
57
+ );
58
+
59
+ const handleKeyDown = (id, e, i) => {
60
+ if (e.currentTarget !== e.target) {
61
+ return;
62
+ }
63
+
64
+ // Allow Enter and Space to select a section
54
65
  if (e?.keyCode === 13 || e?.keyCode === 32) {
66
+ e.preventDefault();
55
67
  toggleOpenSection(id);
56
68
  }
69
+
70
+ // Allow Up and Down arrow navigation between sections
71
+ if (e?.keyCode >= 37 && e?.keyCode <= 40) {
72
+ e.preventDefault();
73
+ const next = i + (e?.keyCode > 38 ? 1 : -1);
74
+ const target =
75
+ next == -1 ? sections.length - 1 : next == sections.length ? 0 : next;
76
+
77
+ sectionRefs.current[target].current.focus();
78
+ setFocused(sections[target]?.id);
79
+ toggleOpenSection(sections[target]?.id);
80
+ }
57
81
  };
58
82
 
59
83
  const wrapper = {
@@ -97,8 +121,6 @@ const RadioSection = ({
97
121
  transition: opacity 0.3s ease;
98
122
  `;
99
123
 
100
- const [focused, setFocused] = useState(null);
101
-
102
124
  return (
103
125
  <Box
104
126
  padding="1px"
@@ -108,19 +130,23 @@ const RadioSection = ({
108
130
  >
109
131
  <Stack
110
132
  childGap="0"
111
- aria-role="radiogroup"
133
+ role="radiogroup"
112
134
  aria-required={isSectionRequired}
135
+ {...rest}
113
136
  >
114
137
  {sections
115
138
  .filter(section => !section.hidden)
116
- .map(section => (
139
+ .map((section, i) => (
117
140
  <Motion
118
141
  tabIndex={
119
142
  section.hideRadioButton || section.disabled ? "-1" : "0"
120
143
  }
121
- onKeyDown={e => !section.disabled && handleKeyDown(section.id, e)}
122
- onFocus={() => !section.disabled && setFocused(section.id)}
144
+ ref={sectionRefs.current[i]}
123
145
  onBlur={() => !section.disabled && setFocused(null)}
146
+ onFocus={() => !section.disabled && setFocused(section.id)}
147
+ onKeyDown={e =>
148
+ !section.disabled && handleKeyDown(section.id, e, i)
149
+ }
124
150
  hoverStyles={themeValues.focusStyles}
125
151
  animate={openSection === section.id ? "open" : "closed"}
126
152
  initial={initiallyOpen ? "open" : "closed"}
@@ -129,7 +155,9 @@ const RadioSection = ({
129
155
  role="radio"
130
156
  aria-checked={openSection === section.id}
131
157
  aria-disabled={section.disabled}
132
- aria-required={section?.required}
158
+ aria-required={section.required}
159
+ aria-labelledby={section.id}
160
+ aria-describedby={`right-icons-${idString(section)}`}
133
161
  >
134
162
  <Stack childGap="0">
135
163
  <Box
@@ -183,7 +211,7 @@ const RadioSection = ({
183
211
  : () => toggleOpenSection(section.id)
184
212
  }
185
213
  tabIndex="-1"
186
- isRequired={section?.required}
214
+ isRequired={section.required}
187
215
  />
188
216
  </Box>
189
217
  )}
@@ -202,9 +230,10 @@ const RadioSection = ({
202
230
  </Cluster>
203
231
  {section.rightIcons && (
204
232
  <Cluster
233
+ id={`right-icons-${idString(section)}`}
205
234
  childGap="0.5rem"
206
- aria-label={section?.rightIconsLabel || null}
207
- role={section?.rightIconsRole || null}
235
+ aria-label={section.rightIconsLabel || null}
236
+ role={section.rightIconsRole || null}
208
237
  >
209
238
  {section.rightIcons.map(icon => (
210
239
  <RightIcon
@@ -16,7 +16,7 @@ const RadioButton = ({
16
16
  toggleRadio,
17
17
  name,
18
18
  disabled = false,
19
- ariaDescribedBy = "",
19
+ ariaDescribedBy,
20
20
  themeValues,
21
21
  ariaLabelledBy = "",
22
22
  ariaLabel = null,
@@ -1,5 +1,5 @@
1
1
  import React from "react";
2
- import { text, boolean, select } from "@storybook/addon-knobs";
2
+ import { text, boolean } from "@storybook/addon-knobs";
3
3
 
4
4
  import TermsAndConditions from "./TermsAndConditions";
5
5
  import page from "../../../../.storybook/page";
@@ -9,13 +9,11 @@ const groupId = "props";
9
9
 
10
10
  export const termsAndConditions = () => (
11
11
  <TermsAndConditions
12
- version={select("version", ["v1", "v2"], "v1", groupId)}
13
12
  onCheck={noop}
14
13
  isChecked={boolean("isChecked", false, groupId)}
15
14
  html={text("html", "terms and conditions summary", groupId)}
16
15
  terms={text("terms", "terms and conditions modal text", groupId)}
17
16
  error={boolean("error", false, groupId)}
18
- description={text("description", "I definitely agree to the", groupId)}
19
17
  />
20
18
  );
21
19
 
@@ -11,8 +11,6 @@ import {
11
11
  import { generateShadows } from "../../../util/generateShadows";
12
12
  import { useScrollTo } from "../../../hooks";
13
13
 
14
- const TermsAndConditionsTitleDivId = "terms-and-conditions-title";
15
-
16
14
  const TermsAndConditionsControlV2 = ({
17
15
  showCheckbox = true,
18
16
  onCheck,
@@ -59,7 +57,6 @@ const TermsAndConditionsControlV2 = ({
59
57
  onChange={onCheck}
60
58
  checkboxMargin={checkboxMargin}
61
59
  extraStyles={`align-self: flex-start;`}
62
- labelledById={TermsAndConditionsTitleDivId}
63
60
  />
64
61
  )}
65
62
  <Stack childGap="0.25rem" fullHeight>
@@ -68,7 +65,6 @@ const TermsAndConditionsControlV2 = ({
68
65
  align="center"
69
66
  nowrap
70
67
  extraStyles={`padding-right: 2px; > div > * { margin: 4px 2px; };`}
71
- id={TermsAndConditionsTitleDivId}
72
68
  >
73
69
  {description && <Text color={CHARADE_GREY}>{description}</Text>}
74
70
  {terms && (