@pingux/astro 1.36.2-alpha.0 → 1.36.2-alpha.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.
Files changed (55) hide show
  1. package/lib/cjs/components/CheckboxField/CheckboxField.js +7 -2
  2. package/lib/cjs/components/CheckboxField/CheckboxField.test.js +16 -0
  3. package/lib/cjs/components/ComboBoxField/ComboBoxField.js +5 -2
  4. package/lib/cjs/components/ComboBoxField/ComboBoxField.test.js +20 -0
  5. package/lib/cjs/components/FieldHelperText/FieldHelperText.js +8 -3
  6. package/lib/cjs/components/FileInputField/FileInputField.js +6 -2
  7. package/lib/cjs/components/FileInputField/FileInputField.test.js +15 -0
  8. package/lib/cjs/components/FileInputField/FileItem.js +5 -2
  9. package/lib/cjs/components/ImageUploadField/ImageUploadField.js +19 -6
  10. package/lib/cjs/components/ImageUploadField/ImageUploadFieldBase.js +4 -3
  11. package/lib/cjs/components/LinkSelectField/LinkSelectField.js +13 -3
  12. package/lib/cjs/components/LinkSelectField/LinkSelectField.test.js +16 -3
  13. package/lib/cjs/components/MultivaluesField/MultivaluesField.js +4 -4
  14. package/lib/cjs/components/MultivaluesField/MultivaluesField.test.js +10 -4
  15. package/lib/cjs/components/NumberField/NumberField.js +8 -2
  16. package/lib/cjs/components/NumberField/NumberField.test.js +14 -0
  17. package/lib/cjs/components/RadioGroupField/RadioGroupField.js +8 -2
  18. package/lib/cjs/components/RadioGroupField/RadioGroupField.test.js +14 -0
  19. package/lib/cjs/components/SelectField/SelectField.js +4 -1
  20. package/lib/cjs/components/SelectField/SelectField.test.js +20 -0
  21. package/lib/cjs/components/SelectFieldBase/SelectFieldBase.js +7 -2
  22. package/lib/cjs/components/SelectFieldBase/SelectFieldBase.test.js +17 -0
  23. package/lib/cjs/components/TextAreaField/TextAreaField.js +8 -2
  24. package/lib/cjs/components/TextAreaField/TextAreaField.test.js +20 -0
  25. package/lib/cjs/components/TextField/TextField.js +9 -2
  26. package/lib/cjs/components/TextField/TextField.test.js +20 -0
  27. package/lib/cjs/recipes/AttributeMappingReadOnlyField.stories.js +7 -1
  28. package/lib/components/CheckboxField/CheckboxField.js +6 -2
  29. package/lib/components/CheckboxField/CheckboxField.test.js +13 -0
  30. package/lib/components/ComboBoxField/ComboBoxField.js +5 -2
  31. package/lib/components/ComboBoxField/ComboBoxField.test.js +15 -0
  32. package/lib/components/FieldHelperText/FieldHelperText.js +8 -3
  33. package/lib/components/FileInputField/FileInputField.js +6 -2
  34. package/lib/components/FileInputField/FileInputField.test.js +13 -0
  35. package/lib/components/FileInputField/FileItem.js +5 -2
  36. package/lib/components/ImageUploadField/ImageUploadField.js +17 -6
  37. package/lib/components/ImageUploadField/ImageUploadFieldBase.js +3 -2
  38. package/lib/components/LinkSelectField/LinkSelectField.js +11 -3
  39. package/lib/components/LinkSelectField/LinkSelectField.test.js +14 -3
  40. package/lib/components/MultivaluesField/MultivaluesField.js +5 -5
  41. package/lib/components/MultivaluesField/MultivaluesField.test.js +8 -4
  42. package/lib/components/NumberField/NumberField.js +7 -2
  43. package/lib/components/NumberField/NumberField.test.js +12 -0
  44. package/lib/components/RadioGroupField/RadioGroupField.js +7 -2
  45. package/lib/components/RadioGroupField/RadioGroupField.test.js +12 -0
  46. package/lib/components/SelectField/SelectField.js +4 -1
  47. package/lib/components/SelectField/SelectField.test.js +15 -0
  48. package/lib/components/SelectFieldBase/SelectFieldBase.js +7 -2
  49. package/lib/components/SelectFieldBase/SelectFieldBase.test.js +13 -0
  50. package/lib/components/TextAreaField/TextAreaField.js +7 -2
  51. package/lib/components/TextAreaField/TextAreaField.test.js +15 -0
  52. package/lib/components/TextField/TextField.js +8 -2
  53. package/lib/components/TextField/TextField.test.js +15 -0
  54. package/lib/recipes/AttributeMappingReadOnlyField.stories.js +6 -1
  55. package/package.json +1 -1
@@ -472,6 +472,23 @@ test('form wrapper will have a max label column width when custom width set', fu
472
472
 
473
473
  expect(textAreaContainer).toHaveStyle('grid-template-columns: 120px auto');
474
474
  });
475
+ test('passing helper text should display it and correct aria attributes on input', function () {
476
+ var testHelperText = 'testHelperText';
477
+ getComponent({
478
+ helperText: testHelperText,
479
+ status: _statuses["default"].ERROR
480
+ });
481
+
482
+ var helper = _testWrapper.screen.getByText(testHelperText);
483
+
484
+ expect(helper).toBeInTheDocument();
485
+ expect(helper).toHaveClass("is-".concat(_statuses["default"].ERROR));
486
+
487
+ var visibleInput = _testWrapper.screen.getAllByLabelText(defaultProps.label)[1];
488
+
489
+ var helperTextID = helper.getAttribute('id');
490
+ expect(visibleInput).toHaveAttribute('aria-describedby', helperTextID);
491
+ });
475
492
  test('should have no accessibility violations', /*#__PURE__*/(0, _asyncToGenerator2["default"])( /*#__PURE__*/_regenerator["default"].mark(function _callee() {
476
493
  var _getComponent3, container, results;
477
494
 
@@ -40,6 +40,8 @@ var _propTypes = _interopRequireDefault(require("prop-types"));
40
40
 
41
41
  var _utils = require("@react-aria/utils");
42
42
 
43
+ var _uuid = require("uuid");
44
+
43
45
  var _ = require("../../");
44
46
 
45
47
  var _ariaAttributes = require("../../utils/devUtils/props/ariaAttributes");
@@ -84,6 +86,7 @@ var TextAreaField = /*#__PURE__*/(0, _react.forwardRef)(function (props, ref) {
84
86
  var labelWrapperRef = (0, _react.useRef)();
85
87
  var slotContainer = (0, _react.useRef)();
86
88
  var textAreaRef = (0, _react.useRef)();
89
+ var helperTextId = (0, _uuid.v4)();
87
90
  (0, _hooks.usePropWarning)(props, 'disabled', 'isDisabled');
88
91
  /* istanbul ignore next */
89
92
 
@@ -168,12 +171,15 @@ var TextAreaField = /*#__PURE__*/(0, _react.forwardRef)(function (props, ref) {
168
171
  paddingRight: '35px'
169
172
  } : {
170
173
  overflow: 'hidden'
171
- }
174
+ },
175
+ "aria-invalid": status === 'error' && true,
176
+ "aria-describedby": helperText && helperTextId
172
177
  })), (slots === null || slots === void 0 ? void 0 : slots.inContainer) && (0, _react2.jsx)(_.Box, {
173
178
  variant: "boxes.textFieldInContainerSlot",
174
179
  ref: slotContainer
175
180
  }, slots === null || slots === void 0 ? void 0 : slots.inContainer)), helperText && (0, _react2.jsx)(_.FieldHelperText, {
176
- status: status
181
+ status: status,
182
+ id: helperTextId
177
183
  }, helperText));
178
184
  });
179
185
  TextAreaField.propTypes = _objectSpread({
@@ -20,6 +20,8 @@ var _testAxe = _interopRequireDefault(require("../../utils/testUtils/testAxe"));
20
20
 
21
21
  var _testWrapper = require("../../utils/testUtils/testWrapper");
22
22
 
23
+ var _statuses = _interopRequireDefault(require("../../utils/devUtils/constants/statuses"));
24
+
23
25
  var _ = _interopRequireDefault(require("."));
24
26
 
25
27
  var _react3 = require("@emotion/react");
@@ -165,4 +167,22 @@ test('providing slot props causes slot to render', function () {
165
167
  slots: slots
166
168
  });
167
169
  expect(_testWrapper.screen.getByTestId('testSlot')).toBeInTheDocument();
170
+ });
171
+ test('passing helper text should display it and correct aria attributes on input', function () {
172
+ var testHelperText = 'testHelperText';
173
+ getComponent({
174
+ helperText: testHelperText,
175
+ status: _statuses["default"].ERROR
176
+ });
177
+
178
+ var helper = _testWrapper.screen.getByText(testHelperText);
179
+
180
+ expect(helper).toBeInTheDocument();
181
+ expect(helper).toHaveClass("is-".concat(_statuses["default"].ERROR));
182
+
183
+ var input = _testWrapper.screen.getByRole('textbox');
184
+
185
+ expect(input).toHaveAttribute('aria-invalid', 'true');
186
+ var helperTextID = helper.getAttribute('id');
187
+ expect(input).toHaveAttribute('aria-describedby', helperTextID);
168
188
  });
@@ -38,6 +38,8 @@ var _react = _interopRequireWildcard(require("react"));
38
38
 
39
39
  var _propTypes = _interopRequireDefault(require("prop-types"));
40
40
 
41
+ var _uuid = require("uuid");
42
+
41
43
  var _ = require("../../");
42
44
 
43
45
  var _ariaAttributes = require("../../utils/devUtils/props/ariaAttributes");
@@ -90,6 +92,7 @@ var TextField = /*#__PURE__*/(0, _react.forwardRef)(function (props, ref) {
90
92
  var columnStyleProps = (0, _useColumnStyles["default"])({
91
93
  labelMode: props.labelMode
92
94
  });
95
+ var helperTextId = (0, _uuid.v4)();
93
96
  return (0, _react2.jsx)(_.Box, (0, _extends2["default"])({
94
97
  variant: "forms.input.wrapper"
95
98
  }, fieldContainerProps, {
@@ -104,8 +107,12 @@ var TextField = /*#__PURE__*/(0, _react.forwardRef)(function (props, ref) {
104
107
  className: fieldControlProps.className
105
108
  }, wrapperProps), slots === null || slots === void 0 ? void 0 : slots.beforeInput, (0, _react2.jsx)(_.Input, (0, _extends2["default"])({
106
109
  ref: inputRef
107
- }, fieldControlProps)), slots === null || slots === void 0 ? void 0 : slots.inContainer), helperText && (0, _react2.jsx)(_.FieldHelperText, {
108
- status: status
110
+ }, fieldControlProps, {
111
+ "aria-invalid": status === 'error' && true,
112
+ "aria-describedby": helperText && helperTextId
113
+ })), slots === null || slots === void 0 ? void 0 : slots.inContainer), helperText && (0, _react2.jsx)(_.FieldHelperText, {
114
+ status: status,
115
+ id: helperTextId
109
116
  }, helperText));
110
117
  });
111
118
  TextField.propTypes = _objectSpread({
@@ -20,6 +20,8 @@ var _ = _interopRequireDefault(require("."));
20
20
 
21
21
  var _testAxe = _interopRequireDefault(require("../../utils/testUtils/testAxe"));
22
22
 
23
+ var _statuses = _interopRequireDefault(require("../../utils/devUtils/constants/statuses"));
24
+
23
25
  var _react3 = require("@emotion/react");
24
26
 
25
27
  var testId = 'test-text-field';
@@ -172,4 +174,22 @@ test('text field container and input have is-read-only class name when isReadOnl
172
174
  var control = _react2.screen.getByLabelText(testLabel);
173
175
 
174
176
  expect(control).toHaveClass('is-read-only');
177
+ });
178
+ test('passing helper text should display it and correct aria attributes on input', function () {
179
+ var testHelperText = 'testHelperText';
180
+ getComponent({
181
+ helperText: testHelperText,
182
+ status: _statuses["default"].ERROR
183
+ });
184
+
185
+ var helper = _react2.screen.getByText(testHelperText);
186
+
187
+ expect(helper).toBeInTheDocument();
188
+ expect(helper).toHaveClass("is-".concat(_statuses["default"].ERROR));
189
+
190
+ var input = _react2.screen.getByRole('textbox');
191
+
192
+ expect(input).toHaveAttribute('aria-invalid', 'true');
193
+ var helperTextID = helper.getAttribute('id');
194
+ expect(input).toHaveAttribute('aria-describedby', helperTextID);
175
195
  });
@@ -16,6 +16,8 @@ var _CreateIcon = _interopRequireDefault(require("mdi-react/CreateIcon"));
16
16
 
17
17
  var _AlertCircleIcon = _interopRequireDefault(require("mdi-react/AlertCircleIcon"));
18
18
 
19
+ var _uuid = require("uuid");
20
+
19
21
  var _index = require("../index");
20
22
 
21
23
  var _react2 = require("@emotion/react");
@@ -87,6 +89,7 @@ var sx = {
87
89
  width: 'md'
88
90
  }
89
91
  };
92
+ var helperTextId = (0, _uuid.v4)();
90
93
 
91
94
  var Row = function Row(props) {
92
95
  var withChip = props.withChip,
@@ -110,6 +113,7 @@ var Row = function Row(props) {
110
113
  width: '165px'
111
114
  }
112
115
  },
116
+ "aria-labelledby": withError && helperTextId,
113
117
  slots: withError && {
114
118
  inContainer: (0, _react2.jsx)(_index.Icon, {
115
119
  icon: _AlertCircleIcon["default"],
@@ -221,7 +225,9 @@ var WithError = function WithError() {
221
225
  icon: _AlertCircleIcon["default"],
222
226
  color: "#A31300"
223
227
  }), (0, _react2.jsx)(_index.Text, {
224
- sx: withErrorSx.text
228
+ sx: withErrorSx.text,
229
+ id: helperTextId,
230
+ role: "alert"
225
231
  }, "This attribute is unavailable. Please map the attribute again or re-map to a different attribute.")), (0, _react2.jsx)(_index.Box, {
226
232
  sx: sx.defaultFieldsWrapperBox
227
233
  }, (0, _react2.jsx)(_index.Box, {
@@ -18,6 +18,7 @@ import React, { forwardRef, useRef, useImperativeHandle, useEffect } from 'react
18
18
  import { useCheckbox } from '@react-aria/checkbox';
19
19
  import { useToggleState } from '@react-stately/toggle';
20
20
  import PropTypes from 'prop-types';
21
+ import { v4 as uuid } from 'uuid';
21
22
  import { Box, Checkbox, FieldHelperText, Label } from '../../';
22
23
  import { ariaAttributesBasePropTypes } from '../../utils/devUtils/props/ariaAttributes';
23
24
  import { useField, usePropWarning } from '../../hooks';
@@ -75,15 +76,18 @@ var CheckboxField = /*#__PURE__*/forwardRef(function (props, ref) {
75
76
  fieldControlProps = _useField.fieldControlProps,
76
77
  fieldLabelProps = _useField.fieldLabelProps;
77
78
 
79
+ var helperTextId = uuid();
78
80
  return ___EmotionJSX(Box, fieldContainerProps, ___EmotionJSX(Label, _extends({
79
81
  variant: "forms.label.checkbox"
80
82
  }, fieldLabelProps), ___EmotionJSX(Checkbox, _extends({
81
- ref: checkboxRef
83
+ ref: checkboxRef,
84
+ "aria-describedby": helperText && helperTextId
82
85
  }, fieldControlProps)), label), helperText && ___EmotionJSX(FieldHelperText, {
83
86
  status: status,
84
87
  sx: {
85
88
  pt: 7
86
- }
89
+ },
90
+ id: helperTextId
87
91
  }, helperText));
88
92
  });
89
93
  CheckboxField.propTypes = _objectSpread({
@@ -3,6 +3,7 @@ import React from 'react';
3
3
  import userEvent from '@testing-library/user-event';
4
4
  import axeTest from '../../utils/testUtils/testAxe';
5
5
  import { render, screen } from '../../utils/testUtils/testWrapper';
6
+ import statuses from '../../utils/devUtils/constants/statuses';
6
7
  import CheckboxField from '../CheckboxField';
7
8
  import { jsx as ___EmotionJSX } from "@emotion/react";
8
9
  var testLabel = 'Test Label';
@@ -87,6 +88,18 @@ test('read only checkbox', function () {
87
88
  var input = screen.getByRole('checkbox');
88
89
  expect(input).toHaveAttribute('readonly');
89
90
  });
91
+ test('passing helper text should display it and correct aria attributes on input', function () {
92
+ var testHelperText = 'testHelperText';
93
+ getComponent({
94
+ helperText: testHelperText,
95
+ status: statuses.ERROR
96
+ });
97
+ var helper = screen.getByText(testHelperText);
98
+ expect(helper).toBeInTheDocument();
99
+ expect(helper).toHaveClass("is-".concat(statuses.ERROR));
100
+ var helperTextID = helper.getAttribute('id');
101
+ expect(screen.getByRole('checkbox')).toHaveAttribute('aria-describedby', helperTextID);
102
+ });
90
103
  test('indeterminate checkbox', function () {
91
104
  var _getComponent = getComponent({
92
105
  isIndeterminate: true
@@ -13,7 +13,7 @@ import _Array$from from "@babel/runtime-corejs3/core-js-stable/array/from";
13
13
  import _concatInstanceProperty from "@babel/runtime-corejs3/core-js-stable/instance/concat";
14
14
  import _defineProperty from "@babel/runtime-corejs3/helpers/esm/defineProperty";
15
15
  import _objectWithoutProperties from "@babel/runtime-corejs3/helpers/esm/objectWithoutProperties";
16
- var _excluded = ["hasAutoFocus", "hasAddOption", "hasCustomValue", "hasNoEmptySelection", "selectedKey", "onSelectionChange", "defaultItems", "items", "loadingState", "onLoadMore", "inputValue", "menuTrigger", "isNotFlippable", "direction", "scrollBoxProps", "controlProps", "defaultFilter"],
16
+ var _excluded = ["hasAutoFocus", "hasAddOption", "hasCustomValue", "hasNoEmptySelection", "selectedKey", "onSelectionChange", "defaultItems", "items", "loadingState", "onLoadMore", "inputValue", "menuTrigger", "isNotFlippable", "direction", "scrollBoxProps", "controlProps", "defaultFilter", "status", "helperText"],
17
17
  _excluded2 = ["shouldFocusOnHover", "shouldSelectOnPressUp"];
18
18
 
19
19
  function ownKeys(object, enumerableOnly) { var keys = _Object$keys(object); if (_Object$getOwnPropertySymbols) { var symbols = _Object$getOwnPropertySymbols(object); enumerableOnly && (symbols = _filterInstanceProperty(symbols).call(symbols, function (sym) { return _Object$getOwnPropertyDescriptor(object, sym).enumerable; })), keys.push.apply(keys, symbols); } return keys; }
@@ -65,6 +65,8 @@ var ComboBoxField = /*#__PURE__*/forwardRef(function (props, ref) {
65
65
  scrollBoxProps = props.scrollBoxProps,
66
66
  controlProps = props.controlProps,
67
67
  defaultFilter = props.defaultFilter,
68
+ status = props.status,
69
+ helperText = props.helperText,
68
70
  others = _objectWithoutProperties(props, _excluded);
69
71
 
70
72
  var _getAriaAttributeProp = getAriaAttributeProps(others),
@@ -230,7 +232,8 @@ var ComboBoxField = /*#__PURE__*/forwardRef(function (props, ref) {
230
232
  inputRef: inputRef,
231
233
  triggerProps: buttonProps,
232
234
  triggerRef: buttonRef,
233
- controlProps: controlProps
235
+ controlProps: controlProps,
236
+ "aria-invalid": status === 'error' && true
234
237
  })), ___EmotionJSX(PopoverContainer, {
235
238
  hasNoArrow: true,
236
239
  isDismissable: true,
@@ -28,6 +28,7 @@ import userEvent from '@testing-library/user-event';
28
28
  import { render, screen, act, within } from '../../utils/testUtils/testWrapper';
29
29
  import { ComboBoxField, Item, OverlayProvider } from '../../index';
30
30
  import loadingStates from '../../utils/devUtils/constants/loadingStates';
31
+ import statuses from '../../utils/devUtils/constants/statuses';
31
32
  import { jsx as ___EmotionJSX } from "@emotion/react";
32
33
  var items = [{
33
34
  name: 'Aardvark',
@@ -912,6 +913,20 @@ test('if "hasAddOption" is provided, then custom value is added to listbox on bl
912
913
  var options = screen.queryAllByRole('option');
913
914
  expect(options[options.length - 1]).toHaveTextContent(inputValue);
914
915
  });
916
+ test('passing helper text should display it and correct aria attributes on input', function () {
917
+ var testHelperText = 'testHelperText';
918
+ getComponent({
919
+ helperText: testHelperText,
920
+ status: statuses.ERROR
921
+ });
922
+ var helper = screen.getByText(testHelperText);
923
+ expect(helper).toBeInTheDocument();
924
+ expect(helper).toHaveClass("is-".concat(statuses.ERROR));
925
+ var input = screen.getByRole('combobox');
926
+ expect(input).toHaveAttribute('aria-invalid', 'true');
927
+ var helperTextID = helper.getAttribute('id');
928
+ expect(input).toHaveAttribute('aria-describedby', helperTextID);
929
+ });
915
930
  test('should have no accessibility violations', /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee5() {
916
931
  var _getComponent6, container, results;
917
932
 
@@ -2,7 +2,7 @@ import _Object$values from "@babel/runtime-corejs3/core-js-stable/object/values"
2
2
  import _extends from "@babel/runtime-corejs3/helpers/esm/extends";
3
3
  import _defineProperty from "@babel/runtime-corejs3/helpers/esm/defineProperty";
4
4
  import _objectWithoutProperties from "@babel/runtime-corejs3/helpers/esm/objectWithoutProperties";
5
- var _excluded = ["className", "status"];
5
+ var _excluded = ["className", "status", "id"];
6
6
  import React, { forwardRef } from 'react';
7
7
  import PropTypes from 'prop-types';
8
8
  import { useStatusClasses } from '../../hooks';
@@ -19,6 +19,7 @@ import { jsx as ___EmotionJSX } from "@emotion/react";
19
19
  var FieldHelperText = /*#__PURE__*/forwardRef(function (props, ref) {
20
20
  var className = props.className,
21
21
  status = props.status,
22
+ id = props.id,
22
23
  others = _objectWithoutProperties(props, _excluded);
23
24
 
24
25
  var _useStatusClasses = useStatusClasses(className, _defineProperty({}, "is-".concat(status), true)),
@@ -28,14 +29,18 @@ var FieldHelperText = /*#__PURE__*/forwardRef(function (props, ref) {
28
29
  ref: ref,
29
30
  pt: "sm",
30
31
  variant: "fieldHelperText",
31
- role: "status"
32
+ role: status === 'error' ? 'alert' : 'status',
33
+ id: id
32
34
  }, others, {
33
35
  className: classNames
34
36
  }));
35
37
  });
36
38
  FieldHelperText.propTypes = {
37
39
  /** Determines the color of the field message. */
38
- status: PropTypes.oneOf(_Object$values(statuses))
40
+ status: PropTypes.oneOf(_Object$values(statuses)),
41
+
42
+ /** The element's unique identifier. See [MDN](https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/id). */
43
+ id: PropTypes.string
39
44
  };
40
45
  FieldHelperText.defaultProps = {
41
46
  status: statuses.DEFAULT
@@ -81,6 +81,8 @@ var FileInputField = /*#__PURE__*/forwardRef(function (_ref, ref) {
81
81
  fieldControlProps = _useField.fieldControlProps,
82
82
  fieldLabelProps = _useField.fieldLabelProps;
83
83
 
84
+ var helperTextId = uuidv4();
85
+
84
86
  var _useVisuallyHidden = useVisuallyHidden(),
85
87
  visuallyHiddenProps = _useVisuallyHidden.visuallyHiddenProps;
86
88
 
@@ -159,7 +161,8 @@ var FileInputField = /*#__PURE__*/forwardRef(function (_ref, ref) {
159
161
  handleFileDelete: handleFileDelete,
160
162
  isDisabled: isDisabled || isLoading,
161
163
  key: fileProps.id,
162
- textProps: textProps
164
+ textProps: textProps,
165
+ helperTextId: helperTextId
163
166
  }, fileProps));
164
167
  });
165
168
  }, [uploadedFilesImperative, uploadedFiles, handleFileDelete, isDisabled, isLoading, textProps]);
@@ -206,7 +209,8 @@ var FileInputField = /*#__PURE__*/forwardRef(function (_ref, ref) {
206
209
  },
207
210
  "data-testid": "file-input-field__loader"
208
211
  })), helperText && ___EmotionJSX(FieldHelperText, {
209
- status: status
212
+ status: status,
213
+ id: helperTextId
210
214
  }, helperText));
211
215
  });
212
216
  FileInputField.displayName = 'FileInputField';
@@ -178,6 +178,19 @@ test('should display loader if appropriate prop is passed', function () {
178
178
  });
179
179
  expect(screen.getByTestId(loaderTestId)).toBeInTheDocument();
180
180
  });
181
+ test('passing helper text should display it and correct aria attributes on input', function () {
182
+ var testHelperText = 'testHelperText';
183
+ getComponent({
184
+ helperText: testHelperText,
185
+ status: statuses.ERROR,
186
+ defaultFileList: [testFileObject]
187
+ });
188
+ var helper = screen.getByText(testHelperText);
189
+ expect(helper).toBeInTheDocument();
190
+ expect(helper).toHaveClass("is-".concat(statuses.ERROR));
191
+ var helperTextID = helper.getAttribute('id');
192
+ expect(screen.getAllByRole('button')[0]).toHaveAttribute('aria-describedby', helperTextID);
193
+ });
181
194
  test('should display helper text if passed', function () {
182
195
  var testHelperText = 'testHelperText';
183
196
  getComponent({
@@ -17,7 +17,8 @@ var FileItem = function FileItem(props) {
17
17
  isDisabled = props.isDisabled,
18
18
  name = props.name,
19
19
  status = props.status,
20
- textProps = props.textProps;
20
+ textProps = props.textProps,
21
+ helperTextId = props.helperTextId;
21
22
  var handleDeleteButtonPress = useCallback(function (e) {
22
23
  return handleFileDelete(e, id);
23
24
  }, [id, handleFileDelete]);
@@ -63,7 +64,8 @@ var FileItem = function FileItem(props) {
63
64
  isDisabled: isDisabled,
64
65
  "aria-label": name,
65
66
  "data-testid": "file-uploaded__download-file-button",
66
- onPress: handleDownloadPress
67
+ onPress: handleDownloadPress,
68
+ "aria-describedby": helperTextId
67
69
  }, ___EmotionJSX(Text, _extends({
68
70
  color: "active"
69
71
  }, textProps), name)), ___EmotionJSX(IconButton, {
@@ -96,6 +98,7 @@ FileItem.propTypes = {
96
98
  id: PropTypes.string,
97
99
  isDisabled: PropTypes.bool,
98
100
  name: PropTypes.string,
101
+ helperTextId: PropTypes.string,
99
102
  status: PropTypes.oneOf(_Object$values(statuses)),
100
103
  textProps: PropTypes.shape({})
101
104
  };
@@ -16,6 +16,8 @@ function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { va
16
16
 
17
17
  import React, { forwardRef, useCallback, useImperativeHandle, useRef } from 'react';
18
18
  import PropTypes from 'prop-types';
19
+ import { VisuallyHidden } from '@react-aria/visually-hidden';
20
+ import { v4 as uuid } from 'uuid';
19
21
  import { Item, Menu } from '../../';
20
22
  import { ariaAttributesBasePropTypes } from '../../utils/devUtils/props/ariaAttributes';
21
23
  import ImagePreviewButton from './ImagePreviewButton';
@@ -40,6 +42,7 @@ var ImageUploadField = /*#__PURE__*/forwardRef(function (props, ref) {
40
42
  useImperativeHandle(ref, function () {
41
43
  return inputRef.current;
42
44
  });
45
+ var statusId = uuid();
43
46
  var onAction = useCallback(function (action) {
44
47
  // eslint-disable-next-line default-case
45
48
  switch (action) {
@@ -61,7 +64,7 @@ var ImageUploadField = /*#__PURE__*/forwardRef(function (props, ref) {
61
64
  }
62
65
  }
63
66
  }, [state.showFileDialog, props === null || props === void 0 ? void 0 : props.onRemove, state.removePreview]);
64
- return ___EmotionJSX(ImageUploadFieldBase, _extends({
67
+ return ___EmotionJSX(React.Fragment, null, ___EmotionJSX(ImageUploadFieldBase, _extends({
65
68
  fileName: state.fileName,
66
69
  handleInputChange: state.handleInputChange,
67
70
  handleLabelClick: state.handleLabelClick,
@@ -80,14 +83,22 @@ var ImageUploadField = /*#__PURE__*/forwardRef(function (props, ref) {
80
83
  previewHeight: props === null || props === void 0 ? void 0 : props.previewHeight,
81
84
  previewImage: state.previewImage,
82
85
  previewWidth: props === null || props === void 0 ? void 0 : props.previewWidth,
83
- widthHeightSx: state.widthHeightSx
86
+ widthHeightSx: state.widthHeightSx,
87
+ "aria-haspopup": state.isMenuOpen
84
88
  }), ___EmotionJSX(Menu, {
85
- onAction: onAction
89
+ onAction: onAction,
90
+ "aria-labelledby": statusId
86
91
  }, ___EmotionJSX(Item, {
87
- key: "upload"
92
+ key: "upload",
93
+ role: "button"
88
94
  }, uploadItemText), ___EmotionJSX(Item, {
89
- key: "remove"
90
- }, removeItemText)));
95
+ key: "remove",
96
+ role: "button"
97
+ }, removeItemText))), ___EmotionJSX(VisuallyHidden, {
98
+ "aria-live": "polite",
99
+ role: state.isMenuOpen ? 'button' : 'status',
100
+ id: statusId
101
+ }, state.isMenuOpen && 'Menu pop up expanded'));
91
102
  });
92
103
  ImageUploadField.propTypes = _objectSpread({
93
104
  /** Image preview (controlled), used to represent the current image state. */
@@ -16,8 +16,8 @@ function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { va
16
16
 
17
17
  import React, { forwardRef, useMemo, useRef } from 'react';
18
18
  import PropTypes from 'prop-types';
19
- import { useVisuallyHidden } from '@react-aria/visually-hidden';
20
19
  import omit from 'lodash/omit';
20
+ import { useVisuallyHidden } from '@react-aria/visually-hidden';
21
21
  import { PopoverMenu } from '../../index';
22
22
  import useField from '../../hooks/useField';
23
23
  import FieldHelperText from '../FieldHelperText';
@@ -55,7 +55,8 @@ var ImageUploadFieldBase = /*#__PURE__*/forwardRef(function (props, inputRef) {
55
55
  variant: "forms.input.wrapper"
56
56
  }, fieldContainerProps), ___EmotionJSX(Label, _extends({}, fieldLabelProps, {
57
57
  onClick: handleLabelClick,
58
- ref: labelRef
58
+ ref: labelRef,
59
+ tabIndex: "-1"
59
60
  })), ___EmotionJSX(PopoverMenu, {
60
61
  isOpen: isMenuOpen,
61
62
  onOpenChange: handleOpenMenuChange
@@ -17,6 +17,8 @@ function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { va
17
17
  import React, { forwardRef } from 'react';
18
18
  import PropTypes from 'prop-types';
19
19
  import MenuDown from 'mdi-react/MenuDownIcon';
20
+ import { v4 as uuid } from 'uuid';
21
+ import { VisuallyHidden } from '@react-aria/visually-hidden';
20
22
  import { Box, Button, Loader, Icon, Text } from '../../';
21
23
  import { ariaAttributesBasePropTypes, getAriaAttributeProps } from '../../utils/devUtils/props/ariaAttributes';
22
24
  import { usePropWarning, useSelectField } from '../../hooks';
@@ -34,11 +36,13 @@ import { jsx as ___EmotionJSX } from "@emotion/react";
34
36
  var LinkSelectField = /*#__PURE__*/forwardRef(function (props, ref) {
35
37
  var placeholder = props.placeholder,
36
38
  isDisabled = props.isDisabled,
37
- status = props.status;
39
+ status = props.status,
40
+ helperText = props.helperText;
38
41
 
39
42
  var _getAriaAttributeProp = getAriaAttributeProps(props),
40
43
  ariaProps = _getAriaAttributeProp.ariaProps;
41
44
 
45
+ var helperTextId = uuid();
42
46
  usePropWarning(props, 'disabled', 'isDisabled');
43
47
 
44
48
  var _useSelectField = useSelectField(_objectSpread(_objectSpread({
@@ -61,7 +65,8 @@ var LinkSelectField = /*#__PURE__*/forwardRef(function (props, ref) {
61
65
  className: fieldControlProps.className,
62
66
  ref: triggerRef,
63
67
  variant: "link",
64
- tabIndex: isDisabled ? -1 : 0
68
+ tabIndex: isDisabled ? -1 : 0,
69
+ "aria-describedby": helperText && helperTextId
65
70
  }, triggerProps, ariaProps), ___EmotionJSX(Text, {
66
71
  variant: "label",
67
72
  color: "active"
@@ -78,7 +83,10 @@ var LinkSelectField = /*#__PURE__*/forwardRef(function (props, ref) {
78
83
  sx: state.isOpen ? {
79
84
  transform: 'rotate(180deg)'
80
85
  } : null
81
- }))));
86
+ }))), ___EmotionJSX(VisuallyHidden, {
87
+ "aria-live": "polite",
88
+ id: helperTextId
89
+ }, helperText));
82
90
 
83
91
  return ___EmotionJSX(SelectFieldBase, _extends({}, props, selectFieldProps, {
84
92
  trigger: trigger
@@ -145,9 +145,9 @@ test('select field with helper text', function () {
145
145
  helperText: helperText,
146
146
  status: statuses.ERROR
147
147
  });
148
- var fieldHelperText = screen.getByText(helperText);
149
- expect(fieldHelperText).toBeInTheDocument();
150
- expect(fieldHelperText).toHaveClass("is-".concat(statuses.ERROR));
148
+ var fieldHelperText = screen.getAllByText(helperText);
149
+ expect(fieldHelperText[1]).toBeInTheDocument();
150
+ expect(fieldHelperText[1]).toHaveClass("is-".concat(statuses.ERROR));
151
151
  });
152
152
  test('displays a loader while loading', function () {
153
153
  var _getComponent = getComponent({
@@ -167,6 +167,17 @@ test('displays a loader while loading', function () {
167
167
  });
168
168
  expect(loader).not.toBeInTheDocument();
169
169
  });
170
+ test('passing helper text should display it and correct aria attributes on input', function () {
171
+ var testHelperText = 'testHelperText';
172
+ getComponent({
173
+ helperText: testHelperText,
174
+ status: statuses.ERROR
175
+ });
176
+ var helper = screen.getAllByText(testHelperText)[0];
177
+ expect(helper).toBeInTheDocument();
178
+ var helperTextID = helper.getAttribute('id');
179
+ expect(screen.getByRole('button')).toHaveAttribute('aria-describedby', helperTextID);
180
+ });
170
181
  test('should have no accessibility violations', /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee() {
171
182
  var _getComponent2, container, results;
172
183
 
@@ -30,7 +30,7 @@ import { useFilter } from '@react-aria/i18n';
30
30
  import { DismissButton, useOverlayPosition } from '@react-aria/overlays';
31
31
  import { useLayoutEffect, useResizeObserver } from '@react-aria/utils';
32
32
  import { useListState } from '@react-stately/list';
33
- import { Box, FieldHelperText, Chip, Icon, IconButton, PopoverContainer, ScrollBox, Text, TextField } from '../../';
33
+ import { Box, Chip, Icon, IconButton, PopoverContainer, ScrollBox, Text, TextField } from '../../';
34
34
  import { ariaAttributesBasePropTypes, getAriaAttributeProps } from '../../utils/devUtils/props/ariaAttributes';
35
35
  import { usePropWarning } from '../../hooks';
36
36
  import ListBox from '../ListBox';
@@ -429,10 +429,10 @@ var MultivaluesField = /*#__PURE__*/forwardRef(function (props, ref) {
429
429
  slots: {
430
430
  beforeInput: ___EmotionJSX(React.Fragment, null, readOnlyItems, " ", selectedItems, readOnlyInputEntry)
431
431
  },
432
- value: filterString
433
- }, ariaProps, inputProps)), helperText && ___EmotionJSX(FieldHelperText, {
434
- status: status
435
- }, helperText), ___EmotionJSX(PopoverContainer, {
432
+ value: filterString,
433
+ helperText: helperText,
434
+ "aria-invalid": status === 'error' && true
435
+ }, ariaProps, inputProps)), ___EmotionJSX(PopoverContainer, {
436
436
  hasNoArrow: true,
437
437
  isDismissable: true,
438
438
  isNonModal: true,
@@ -388,15 +388,19 @@ test('read only keys', function () {
388
388
  var deleteButton2 = firstChip.nextSibling;
389
389
  expect(deleteButton2).toBeNull();
390
390
  });
391
- test(' multivalue field with helper text', function () {
392
- var helperText = 'helper text';
391
+ test('passing helper text should display it and correct aria attributes on input', function () {
392
+ var testHelperText = 'testHelperText';
393
393
  getComponent({
394
- helperText: helperText,
394
+ helperText: testHelperText,
395
395
  status: statuses.ERROR
396
396
  });
397
- var helper = screen.getByText(helperText);
397
+ var helper = screen.getByText(testHelperText);
398
398
  expect(helper).toBeInTheDocument();
399
399
  expect(helper).toHaveClass("is-".concat(statuses.ERROR));
400
+ var input = screen.getByRole('combobox');
401
+ expect(input).toHaveAttribute('aria-invalid', 'true');
402
+ var helperTextID = helper.getAttribute('id');
403
+ expect(input).toHaveAttribute('aria-describedby', helperTextID);
400
404
  });
401
405
  test('read only field', function () {
402
406
  var isReadOnly = true;