@thecb/components 6.0.0-beta.3 → 6.0.0-beta.4

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": "6.0.0-beta.3",
3
+ "version": "6.0.0-beta.4",
4
4
  "description": "Common lib for CityBase react components",
5
5
  "main": "dist/index.cjs.js",
6
6
  "module": "dist/index.esm.js",
@@ -94,7 +94,8 @@ const Dropdown = ({
94
94
  widthFitOptions = false,
95
95
  disabled,
96
96
  hasTitles = false,
97
- autoEraseTypeAhead = true // legacy behavior as of 05/22
97
+ autoEraseTypeAhead = true, // legacy behavior as of 05/22
98
+ ariaLabelledby
98
99
  }) => {
99
100
  const [inputValue, setInputValue] = useState("");
100
101
  const [optionsState, setOptionsState] = useState([]);
@@ -161,10 +162,18 @@ const Dropdown = ({
161
162
  break;
162
163
  case "Backspace" || "Delete":
163
164
  e.preventDefault();
164
- console.log("input value is", inputValue);
165
- console.log("new input value will be", inputValue.slice(0, -1));
166
165
  setInputValue(inputValue.slice(0, -1));
167
166
  break;
167
+ case "Home":
168
+ e.preventDefault();
169
+ optionRefs.current[0].current.focus();
170
+ break;
171
+ case "End":
172
+ e.preventDefault();
173
+ optionRefs.current[
174
+ optionRefs?.current?.length ?? 0 - 1
175
+ ].current.focus();
176
+ break;
168
177
  }
169
178
  if ((keyCode > 64 && keyCode < 91) || keyCode == 32 || keyCode == 189) {
170
179
  e.preventDefault();
@@ -179,7 +188,11 @@ const Dropdown = ({
179
188
  );
180
189
  console.log("selected refs in isopen useffect", selectedRef);
181
190
  console.log("value in isopen useffect", value);
182
- if (isOpen && optionRefs.current[0].current) {
191
+ if (isOpen && selectedRef !== undefined) {
192
+ // WAI-ARIA requires the selected option to receive focus
193
+ selectedRef.current.focus();
194
+ } else if (isOpen && optionRefs.current[0].current) {
195
+ // If no selected option, first option receives focus
183
196
  optionRefs.current[0].current.focus();
184
197
  }
185
198
  clearTimeout(timer);
@@ -224,6 +237,10 @@ const Dropdown = ({
224
237
  width="100%"
225
238
  hoverStyles={`background-color: ${themeValues.hoverColor};`}
226
239
  aria-expanded={isOpen}
240
+ role="combobox"
241
+ aria-owns={`${ariaLabelledby}_listbox`}
242
+ aria-haspopup="listbox"
243
+ aria-labelledby={ariaLabelledby}
227
244
  extraStyles={
228
245
  disabled &&
229
246
  `color: #6e727e;
@@ -247,7 +264,6 @@ const Dropdown = ({
247
264
  : GREY_CHATEAU
248
265
  }
249
266
  borderRadius="2px"
250
- tabIndex={0}
251
267
  dataQa={placeholder}
252
268
  extraStyles={`height: 48px;
253
269
  ${disabled &&
@@ -257,26 +273,20 @@ const Dropdown = ({
257
273
  `}
258
274
  >
259
275
  <Stack direction="row" bottomItem={2}>
260
- {isOpen ? (
261
- <SearchInput
262
- aria-label={inputValue || "Dropdown awaiting search value"}
263
- value={inputValue}
264
- onChange={noop}
265
- themeValues={themeValues}
266
- />
267
- ) : (
268
- <Text
269
- variant="p"
270
- extraStyles={
271
- disabled &&
272
- `color: #6e727e;
273
- background-color: #f7f7f7;
274
- pointer-events: none;`
275
- }
276
- >
277
- {getSelection()}
278
- </Text>
279
- )}
276
+ <SearchInput
277
+ aria-label={getSelection()}
278
+ placeholder={getSelection()}
279
+ value={inputValue}
280
+ onChange={noop}
281
+ themeValues={themeValues}
282
+ role="searchbox"
283
+ type="text"
284
+ aria-multiline="false"
285
+ aria-autocomplete="list"
286
+ aria-controls={`${ariaLabelledby}_listbox`}
287
+ aria-activedescendant="selected_option"
288
+ tabIndex={0}
289
+ />
280
290
  <IconWrapper open={isOpen}>
281
291
  <DropdownIcon />
282
292
  </IconWrapper>
@@ -289,6 +299,8 @@ const Dropdown = ({
289
299
  ref={dropdownRef}
290
300
  widthFitOptions={widthFitOptions}
291
301
  tabIndex={0}
302
+ role="listbox"
303
+ id={`${ariaLabelledby}_listbox`}
292
304
  >
293
305
  <Stack childGap="0">
294
306
  {filteredOptions.map((choice, i) => {
@@ -297,6 +309,7 @@ const Dropdown = ({
297
309
  }
298
310
  return (
299
311
  <DropdownItemWrapper
312
+ id={choice.value === value ? "selected_option" : choice.value}
300
313
  key={choice.value}
301
314
  ref={optionRefs.current[i]}
302
315
  as="button"
@@ -307,10 +320,12 @@ const Dropdown = ({
307
320
  : () => onSelect(choice.value)
308
321
  }
309
322
  selected={choice.value === value}
323
+ aria-selected={choice.value === value}
310
324
  disabled={disabledValues.includes(choice.value)}
311
325
  data-qa={choice.text}
312
326
  themeValues={themeValues}
313
327
  title={hasTitles ? choice.text : null}
328
+ role="option"
314
329
  >
315
330
  <Text
316
331
  variant="p"
@@ -58,7 +58,7 @@ const FormSelect = ({
58
58
  </Cluster>
59
59
  </Box>
60
60
  <Dropdown
61
- aria-labelledby={labelTextWhenNoError.replace(/\s+/g, "-")}
61
+ ariaLabelledby={labelTextWhenNoError.replace(/\s+/g, "-")}
62
62
  maxHeight={dropdownMaxHeight}
63
63
  hasTitles={hasTitles}
64
64
  placeholder={options[0] ? options[0].text : ""}