@okta/odyssey-react-mui 1.11.0 → 1.12.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.
Files changed (92) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/dist/@types/react-augment.d.js.map +1 -1
  3. package/dist/Autocomplete.js +5 -3
  4. package/dist/Autocomplete.js.map +1 -1
  5. package/dist/Button.js +5 -6
  6. package/dist/Button.js.map +1 -1
  7. package/dist/Checkbox.js +8 -7
  8. package/dist/Checkbox.js.map +1 -1
  9. package/dist/CheckboxGroup.js +2 -0
  10. package/dist/CheckboxGroup.js.map +1 -1
  11. package/dist/Field.js +3 -2
  12. package/dist/Field.js.map +1 -1
  13. package/dist/FieldComponentProps.js.map +1 -1
  14. package/dist/Link.js +5 -6
  15. package/dist/Link.js.map +1 -1
  16. package/dist/NativeSelect.js +18 -4
  17. package/dist/NativeSelect.js.map +1 -1
  18. package/dist/PasswordField.js +8 -7
  19. package/dist/PasswordField.js.map +1 -1
  20. package/dist/Radio.js +8 -7
  21. package/dist/Radio.js.map +1 -1
  22. package/dist/RadioGroup.js +2 -0
  23. package/dist/RadioGroup.js.map +1 -1
  24. package/dist/SearchField.js +2 -0
  25. package/dist/SearchField.js.map +1 -1
  26. package/dist/Select.js +10 -7
  27. package/dist/Select.js.map +1 -1
  28. package/dist/TextField.js +8 -7
  29. package/dist/TextField.js.map +1 -1
  30. package/dist/Typography.js +5 -6
  31. package/dist/Typography.js.map +1 -1
  32. package/dist/inputUtils.js.map +1 -1
  33. package/dist/labs/Switch.js +3 -3
  34. package/dist/labs/Switch.js.map +1 -1
  35. package/dist/labs/VirtualizedAutocomplete.js +5 -3
  36. package/dist/labs/VirtualizedAutocomplete.js.map +1 -1
  37. package/dist/src/Autocomplete.d.ts +2 -2
  38. package/dist/src/Autocomplete.d.ts.map +1 -1
  39. package/dist/src/Button.d.ts +4 -4
  40. package/dist/src/Button.d.ts.map +1 -1
  41. package/dist/src/Checkbox.d.ts +4 -4
  42. package/dist/src/Checkbox.d.ts.map +1 -1
  43. package/dist/src/CheckboxGroup.d.ts +2 -2
  44. package/dist/src/CheckboxGroup.d.ts.map +1 -1
  45. package/dist/src/Field.d.ts +1 -1
  46. package/dist/src/Field.d.ts.map +1 -1
  47. package/dist/src/FieldComponentProps.d.ts +4 -0
  48. package/dist/src/FieldComponentProps.d.ts.map +1 -1
  49. package/dist/src/Link.d.ts +4 -4
  50. package/dist/src/Link.d.ts.map +1 -1
  51. package/dist/src/NativeSelect.d.ts +13 -2
  52. package/dist/src/NativeSelect.d.ts.map +1 -1
  53. package/dist/src/PasswordField.d.ts +5 -5
  54. package/dist/src/PasswordField.d.ts.map +1 -1
  55. package/dist/src/Radio.d.ts +4 -4
  56. package/dist/src/Radio.d.ts.map +1 -1
  57. package/dist/src/RadioGroup.d.ts +2 -2
  58. package/dist/src/RadioGroup.d.ts.map +1 -1
  59. package/dist/src/SearchField.d.ts +2 -2
  60. package/dist/src/SearchField.d.ts.map +1 -1
  61. package/dist/src/Select.d.ts +5 -5
  62. package/dist/src/Select.d.ts.map +1 -1
  63. package/dist/src/TextField.d.ts +5 -5
  64. package/dist/src/TextField.d.ts.map +1 -1
  65. package/dist/src/Typography.d.ts +4 -4
  66. package/dist/src/Typography.d.ts.map +1 -1
  67. package/dist/src/inputUtils.d.ts +3 -0
  68. package/dist/src/inputUtils.d.ts.map +1 -1
  69. package/dist/src/labs/Switch.d.ts.map +1 -1
  70. package/dist/src/labs/VirtualizedAutocomplete.d.ts +2 -2
  71. package/dist/src/labs/VirtualizedAutocomplete.d.ts.map +1 -1
  72. package/dist/tsconfig.production.tsbuildinfo +1 -1
  73. package/package.json +3 -3
  74. package/src/@types/react-augment.d.ts +8 -4
  75. package/src/Autocomplete.tsx +6 -1
  76. package/src/Button.tsx +8 -9
  77. package/src/Checkbox.tsx +15 -11
  78. package/src/CheckboxGroup.tsx +3 -0
  79. package/src/Field.tsx +8 -4
  80. package/src/FieldComponentProps.ts +4 -0
  81. package/src/Link.tsx +8 -9
  82. package/src/NativeSelect.tsx +36 -2
  83. package/src/PasswordField.tsx +11 -11
  84. package/src/Radio.tsx +16 -10
  85. package/src/RadioGroup.tsx +3 -0
  86. package/src/SearchField.tsx +6 -1
  87. package/src/Select.tsx +12 -10
  88. package/src/TextField.tsx +11 -11
  89. package/src/Typography.tsx +8 -9
  90. package/src/inputUtils.ts +4 -0
  91. package/src/labs/Switch.tsx +2 -1
  92. package/src/labs/VirtualizedAutocomplete.tsx +20 -3
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@okta/odyssey-react-mui",
3
- "version": "1.11.0",
3
+ "version": "1.12.0",
4
4
  "description": "React MUI components for Odyssey, Okta's design system",
5
5
  "author": "Okta, Inc.",
6
6
  "license": "Apache-2.0",
@@ -51,7 +51,7 @@
51
51
  "@mui/system": "^5.14.9",
52
52
  "@mui/utils": "^5.11.2",
53
53
  "@mui/x-date-pickers": "^5.0.15",
54
- "@okta/odyssey-design-tokens": "1.11.0",
54
+ "@okta/odyssey-design-tokens": "1.12.0",
55
55
  "date-fns": "^2.30.0",
56
56
  "i18next": "^23.5.1",
57
57
  "material-react-table": "^2.0.2",
@@ -63,5 +63,5 @@
63
63
  "react": ">=17 <19",
64
64
  "react-dom": ">=17 <19"
65
65
  },
66
- "gitHead": "36ec4393909bdea95455892c4a9eb65c38ea0857"
66
+ "gitHead": "1bffe33f2c5946144232f60f983bfe76b6339453"
67
67
  }
@@ -11,13 +11,17 @@
11
11
  */
12
12
 
13
13
  import { FC } from "react";
14
-
15
14
  export interface ForwardRefWithType extends FC<WithForwardRefProps<Option>> {
16
15
  <T extends Option>(props: WithForwardRefProps<T>): ReturnType<
17
16
  FC<WithForwardRefProps<T>>
18
17
  >;
19
18
  }
20
19
 
21
- export type FocusHandle = {
22
- focus: () => void;
23
- };
20
+ declare module "react" {
21
+ type DataAttributeKey = `data-${string}`;
22
+ interface InputHTMLAttributes<T> extends HTMLAttributes<T> {
23
+ // Allows data-* props to be passed to inputProps in nested MUI components
24
+ // see: https://github.com/mui/material-ui/issues/20160
25
+ [dataAttribute: DataAttributeKey]: string | undefined;
26
+ }
27
+ }
@@ -161,6 +161,7 @@ export type AutocompleteProps<
161
161
  getIsOptionEqualToValue?: (option: OptionType, value: OptionType) => boolean;
162
162
  } & Pick<
163
163
  FieldComponentProps,
164
+ | "ariaDescribedBy"
164
165
  | "errorMessage"
165
166
  | "errorMessageList"
166
167
  | "hint"
@@ -177,6 +178,7 @@ const Autocomplete = <
177
178
  HasMultipleChoices extends boolean | undefined,
178
179
  IsCustomValueAllowed extends boolean | undefined
179
180
  >({
181
+ ariaDescribedBy,
180
182
  defaultValue,
181
183
  errorMessage,
182
184
  errorMessageList,
@@ -245,6 +247,7 @@ const Autocomplete = <
245
247
  const renderInput = useCallback(
246
248
  ({ InputLabelProps, InputProps, ...params }) => (
247
249
  <Field
250
+ ariaDescribedBy={ariaDescribedBy}
248
251
  errorMessage={errorMessage}
249
252
  errorMessageList={errorMessageList}
250
253
  fieldType="single"
@@ -267,6 +270,7 @@ const Autocomplete = <
267
270
  ...params.inputProps,
268
271
  "aria-errormessage": errorMessageElementId,
269
272
  "aria-labelledby": labelElementId,
273
+ "data-se": testId,
270
274
  }}
271
275
  aria-describedby={ariaDescribedBy}
272
276
  id={id}
@@ -277,6 +281,7 @@ const Autocomplete = <
277
281
  />
278
282
  ),
279
283
  [
284
+ ariaDescribedBy,
280
285
  errorMessage,
281
286
  errorMessageList,
282
287
  hint,
@@ -284,6 +289,7 @@ const Autocomplete = <
284
289
  isOptional,
285
290
  label,
286
291
  nameOverride,
292
+ testId,
287
293
  ]
288
294
  );
289
295
  const onChange = useCallback<
@@ -324,7 +330,6 @@ const Autocomplete = <
324
330
  {...inputValueProp}
325
331
  // AutoComplete is wrapped in a div within MUI which does not get the disabled attr. So this aria-disabled gets set in the div
326
332
  aria-disabled={isDisabled}
327
- data-se={testId}
328
333
  disableCloseOnSelect={hasMultipleChoices}
329
334
  disabled={isDisabled}
330
335
  freeSolo={isCustomValueAllowed}
package/src/Button.tsx CHANGED
@@ -23,7 +23,7 @@ import {
23
23
  import { MuiPropsContext, useMuiProps } from "./MuiPropsContext";
24
24
  import { Tooltip } from "./Tooltip";
25
25
  import type { AllowedProps } from "./AllowedProps";
26
- import { FocusHandle } from "./@types/react-augment";
26
+ import { FocusHandle } from "./inputUtils";
27
27
 
28
28
  export const buttonSizeValues = ["small", "medium", "large"] as const;
29
29
  export const buttonTypeValues = ["button", "submit", "reset"] as const;
@@ -49,9 +49,9 @@ export type ButtonProps = {
49
49
  */
50
50
  ariaDescribedBy?: string;
51
51
  /**
52
- * The ref forwarded to the Button to expose focus()
52
+ * The ref forwarded to the Button
53
53
  */
54
- buttonFocusRef?: React.RefObject<FocusHandle>;
54
+ buttonRef?: React.RefObject<FocusHandle>;
55
55
  /**
56
56
  * The icon element to display at the end of the Button
57
57
  */
@@ -119,7 +119,7 @@ const Button = ({
119
119
  ariaDescribedBy,
120
120
  ariaLabel,
121
121
  ariaLabelledBy,
122
- buttonFocusRef,
122
+ buttonRef,
123
123
  endIcon,
124
124
  id,
125
125
  isDisabled,
@@ -136,14 +136,13 @@ const Button = ({
136
136
  }: ButtonProps) => {
137
137
  const muiProps = useMuiProps();
138
138
 
139
- const ref = useRef<HTMLButtonElement>(null);
139
+ const localButtonRef = useRef<HTMLButtonElement>(null);
140
140
  useImperativeHandle(
141
- buttonFocusRef,
141
+ buttonRef,
142
142
  () => {
143
- const element = ref.current;
144
143
  return {
145
144
  focus: () => {
146
- element && element.focus();
145
+ localButtonRef.current?.focus();
147
146
  },
148
147
  };
149
148
  },
@@ -163,7 +162,7 @@ const Button = ({
163
162
  fullWidth={isFullWidth}
164
163
  id={id}
165
164
  onClick={onClick}
166
- ref={ref}
165
+ ref={localButtonRef}
167
166
  size={size}
168
167
  startIcon={startIcon}
169
168
  translate={translate}
package/src/Checkbox.tsx CHANGED
@@ -23,9 +23,12 @@ import {
23
23
  import { FieldComponentProps } from "./FieldComponentProps";
24
24
  import { Typography } from "./Typography";
25
25
  import type { AllowedProps } from "./AllowedProps";
26
- import { ComponentControlledState, getControlState } from "./inputUtils";
26
+ import {
27
+ ComponentControlledState,
28
+ FocusHandle,
29
+ getControlState,
30
+ } from "./inputUtils";
27
31
  import { CheckedFieldProps } from "./FormCheckedProps";
28
- import { FocusHandle } from "./@types/react-augment";
29
32
 
30
33
  export const checkboxValidityValues = ["valid", "invalid", "inherit"] as const;
31
34
 
@@ -43,9 +46,9 @@ export type CheckboxProps = {
43
46
  */
44
47
  id?: string;
45
48
  /**
46
- * The ref forwarded to the Checkbox to expose focus()
49
+ * The ref forwarded to the Checkbox
47
50
  */
48
- inputFocusRef?: React.RefObject<FocusHandle>;
51
+ inputRef?: React.RefObject<FocusHandle>;
49
52
  /**
50
53
  * Determines whether the Checkbox is disabled
51
54
  */
@@ -86,7 +89,7 @@ const Checkbox = ({
86
89
  ariaLabel,
87
90
  ariaLabelledBy,
88
91
  id: idOverride,
89
- inputFocusRef,
92
+ inputRef,
90
93
  isChecked,
91
94
  isDefaultChecked,
92
95
  isDisabled,
@@ -116,14 +119,13 @@ const Checkbox = ({
116
119
  return { defaultChecked: isDefaultChecked };
117
120
  }, [isDefaultChecked, isChecked]);
118
121
 
119
- const inputRef = useRef<HTMLInputElement>(null);
122
+ const localInputRef = useRef<HTMLInputElement>(null);
120
123
  useImperativeHandle(
121
- inputFocusRef,
124
+ inputRef,
122
125
  () => {
123
- const element = inputRef.current;
124
126
  return {
125
127
  focus: () => {
126
- element && element.focus();
128
+ localInputRef.current?.focus();
127
129
  },
128
130
  };
129
131
  },
@@ -179,13 +181,15 @@ const Checkbox = ({
179
181
  indeterminate={isIndeterminate}
180
182
  onChange={onChange}
181
183
  required={isRequired}
182
- inputRef={inputRef}
184
+ inputProps={{
185
+ "data-se": testId,
186
+ }}
187
+ inputRef={localInputRef}
183
188
  sx={() => ({
184
189
  marginBlockStart: "2px",
185
190
  })}
186
191
  />
187
192
  }
188
- data-se={testId}
189
193
  disabled={isDisabled}
190
194
  id={idOverride}
191
195
  label={label}
@@ -35,6 +35,7 @@ export type CheckboxGroupProps = {
35
35
  label: string;
36
36
  } & Pick<
37
37
  FieldComponentProps,
38
+ | "ariaDescribedBy"
38
39
  | "errorMessage"
39
40
  | "errorMessageList"
40
41
  | "hint"
@@ -45,6 +46,7 @@ export type CheckboxGroupProps = {
45
46
  AllowedProps;
46
47
 
47
48
  const CheckboxGroup = ({
49
+ ariaDescribedBy,
48
50
  children,
49
51
  errorMessage,
50
52
  errorMessageList,
@@ -75,6 +77,7 @@ const CheckboxGroup = ({
75
77
 
76
78
  return (
77
79
  <Field
80
+ ariaDescribedBy={ariaDescribedBy}
78
81
  errorMessage={errorMessage}
79
82
  errorMessageList={errorMessageList}
80
83
  fieldType="group"
package/src/Field.tsx CHANGED
@@ -80,6 +80,7 @@ export type FieldProps = {
80
80
  };
81
81
 
82
82
  const Field = ({
83
+ ariaDescribedBy,
83
84
  errorMessage,
84
85
  errorMessageList,
85
86
  fieldType,
@@ -96,6 +97,7 @@ const Field = ({
96
97
  }: FieldProps &
97
98
  Pick<
98
99
  FieldComponentProps,
100
+ | "ariaDescribedBy"
99
101
  | "errorMessage"
100
102
  | "errorMessageList"
101
103
  | "hint"
@@ -113,9 +115,11 @@ const Field = ({
113
115
  errorMessage || errorMessageList ? `${id}-error` : undefined;
114
116
  const labelElementId = `${id}-label`;
115
117
 
116
- const ariaDescribedBy = useMemo(
117
- () => [hintId, errorMessageElementId].join(" ").trim() || undefined,
118
- [errorMessageElementId, hintId]
118
+ const localAriaDescribedBy = useMemo(
119
+ () =>
120
+ [hintId, errorMessageElementId, ariaDescribedBy].join(" ").trim() ||
121
+ undefined,
122
+ [ariaDescribedBy, errorMessageElementId, hintId]
119
123
  );
120
124
 
121
125
  const { isDisabled: isFieldsetDisabled } = useFieldset();
@@ -160,7 +164,7 @@ const Field = ({
160
164
  )}
161
165
 
162
166
  {renderFieldComponent({
163
- ariaDescribedBy,
167
+ ariaDescribedBy: localAriaDescribedBy,
164
168
  errorMessageElementId,
165
169
  id,
166
170
  labelElementId,
@@ -15,6 +15,10 @@ import { ReactElement } from "react";
15
15
  import { HintLink } from "./HintLink";
16
16
 
17
17
  export type FieldComponentProps = {
18
+ /**
19
+ * The ID of the element that describes the Field
20
+ */
21
+ ariaDescribedBy?: string;
18
22
  /**
19
23
  * If `error` is not undefined, the `input` will indicate an error.
20
24
  */
package/src/Link.tsx CHANGED
@@ -13,9 +13,9 @@
13
13
  import { memo, ReactElement, useImperativeHandle, useRef } from "react";
14
14
  import { ExternalLinkIcon } from "./icons.generated";
15
15
  import type { AllowedProps } from "./AllowedProps";
16
+ import { FocusHandle } from "./inputUtils";
16
17
 
17
18
  import { Link as MuiLink, LinkProps as MuiLinkProps } from "@mui/material";
18
- import { FocusHandle } from "./@types/react-augment";
19
19
 
20
20
  export const linkVariantValues = ["default", "monochrome"] as const;
21
21
 
@@ -33,9 +33,9 @@ export type LinkProps = {
33
33
  */
34
34
  icon?: ReactElement;
35
35
  /**
36
- * The ref forwarded to the TextField to expose focus()
36
+ * The ref forwarded to the TextField
37
37
  */
38
- linkFocusRef?: React.RefObject<FocusHandle>;
38
+ linkRef?: React.RefObject<FocusHandle>;
39
39
  /**
40
40
  * The click event handler for the Link
41
41
  */
@@ -63,7 +63,7 @@ const Link = ({
63
63
  children,
64
64
  href,
65
65
  icon,
66
- linkFocusRef,
66
+ linkRef,
67
67
  rel,
68
68
  target,
69
69
  testId,
@@ -71,14 +71,13 @@ const Link = ({
71
71
  variant,
72
72
  onClick,
73
73
  }: LinkProps) => {
74
- const ref = useRef<HTMLAnchorElement>(null);
74
+ const localLinkRef = useRef<HTMLAnchorElement>(null);
75
75
  useImperativeHandle(
76
- linkFocusRef,
76
+ linkRef,
77
77
  () => {
78
- const element = ref.current;
79
78
  return {
80
79
  focus: () => {
81
- element && element.focus();
80
+ localLinkRef.current?.focus();
82
81
  },
83
82
  };
84
83
  },
@@ -89,7 +88,7 @@ const Link = ({
89
88
  <MuiLink
90
89
  data-se={testId}
91
90
  href={href}
92
- ref={ref}
91
+ ref={localLinkRef}
93
92
  rel={rel}
94
93
  target={target}
95
94
  translate={translate}
@@ -11,10 +11,12 @@
11
11
  */
12
12
 
13
13
  import React, {
14
+ InputHTMLAttributes,
14
15
  ReactElement,
15
16
  forwardRef,
16
17
  memo,
17
18
  useCallback,
19
+ useImperativeHandle,
18
20
  useMemo,
19
21
  useRef,
20
22
  } from "react";
@@ -25,7 +27,7 @@ import {
25
27
  import { Field } from "./Field";
26
28
  import { FieldComponentProps } from "./FieldComponentProps";
27
29
  import type { AllowedProps } from "./AllowedProps";
28
- import { getControlState, useInputValues } from "./inputUtils";
30
+ import { FocusHandle, getControlState, useInputValues } from "./inputUtils";
29
31
  import { ForwardRefWithType } from "./@types/react-augment";
30
32
 
31
33
  export type NativeSelectOption = {
@@ -41,6 +43,12 @@ export type NativeSelectProps<
41
43
  Value extends NativeSelectValueType<HasMultipleChoices>,
42
44
  HasMultipleChoices extends boolean
43
45
  > = {
46
+ /**
47
+ * This prop helps users to fill forms faster, especially on mobile devices.
48
+ * The name can be confusing, as it's more like an autofill.
49
+ * @see https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#autofill
50
+ */
51
+ autoCompleteType?: InputHTMLAttributes<HTMLInputElement>["autoComplete"];
44
52
  /**
45
53
  * The options or optgroup elements within the NativeSelect
46
54
  */
@@ -53,6 +61,10 @@ export type NativeSelectProps<
53
61
  * If `true`, the Select allows multiple selections
54
62
  */
55
63
  hasMultipleChoices?: HasMultipleChoices;
64
+ /**
65
+ * The ref forwarded to the NativeSelect
66
+ */
67
+ inputRef?: React.RefObject<FocusHandle>;
56
68
  /**
57
69
  * @deprecated Use `hasMultipleChoices` instead
58
70
  */
@@ -81,6 +93,7 @@ export type NativeSelectProps<
81
93
  value?: Value;
82
94
  } & Pick<
83
95
  FieldComponentProps,
96
+ | "ariaDescribedBy"
84
97
  | "errorMessage"
85
98
  | "errorMessageList"
86
99
  | "hint"
@@ -98,6 +111,8 @@ const NativeSelect: ForwardRefWithType = forwardRef(
98
111
  HasMultipleChoices extends boolean
99
112
  >(
100
113
  {
114
+ ariaDescribedBy,
115
+ autoCompleteType,
101
116
  defaultValue,
102
117
  errorMessage,
103
118
  errorMessageList,
@@ -105,6 +120,7 @@ const NativeSelect: ForwardRefWithType = forwardRef(
105
120
  hint,
106
121
  HintLinkComponent,
107
122
  id: idOverride,
123
+ inputRef,
108
124
  isDisabled = false,
109
125
  isFullWidth = false,
110
126
  isMultiSelect,
@@ -126,6 +142,20 @@ const NativeSelect: ForwardRefWithType = forwardRef(
126
142
  uncontrolledValue: defaultValue,
127
143
  })
128
144
  );
145
+ const localInputRef = useRef<HTMLSelectElement>(null);
146
+
147
+ useImperativeHandle(
148
+ inputRef,
149
+ () => {
150
+ return {
151
+ focus: () => {
152
+ localInputRef.current?.focus();
153
+ },
154
+ };
155
+ },
156
+ []
157
+ );
158
+
129
159
  const inputValues = useInputValues({
130
160
  defaultValue,
131
161
  value,
@@ -153,13 +183,15 @@ const NativeSelect: ForwardRefWithType = forwardRef(
153
183
  <MuiSelect
154
184
  {...inputValues}
155
185
  aria-describedby={ariaDescribedBy}
186
+ autoComplete={autoCompleteType}
156
187
  children={children}
157
- data-se={testId}
158
188
  id={idOverride}
159
189
  inputProps={{
160
190
  "aria-errormessage": errorMessageElementId,
161
191
  "aria-labelledby": labelElementId,
192
+ "data-se": testId,
162
193
  }}
194
+ inputRef={localInputRef}
163
195
  name={idOverride}
164
196
  multiple={hasMultipleChoices}
165
197
  native={true}
@@ -171,6 +203,7 @@ const NativeSelect: ForwardRefWithType = forwardRef(
171
203
  />
172
204
  ),
173
205
  [
206
+ autoCompleteType,
174
207
  children,
175
208
  idOverride,
176
209
  inputValues,
@@ -186,6 +219,7 @@ const NativeSelect: ForwardRefWithType = forwardRef(
186
219
 
187
220
  return (
188
221
  <Field
222
+ ariaDescribedBy={ariaDescribedBy}
189
223
  errorMessage={errorMessage}
190
224
  errorMessageList={errorMessageList}
191
225
  fieldType="single"
@@ -27,8 +27,7 @@ import { Field } from "./Field";
27
27
  import { FieldComponentProps } from "./FieldComponentProps";
28
28
  import type { AllowedProps } from "./AllowedProps";
29
29
  import { useTranslation } from "react-i18next";
30
- import { getControlState, useInputValues } from "./inputUtils";
31
- import { FocusHandle } from "./@types/react-augment";
30
+ import { FocusHandle, getControlState, useInputValues } from "./inputUtils";
32
31
 
33
32
  export type PasswordFieldProps = {
34
33
  /**
@@ -50,9 +49,9 @@ export type PasswordFieldProps = {
50
49
  */
51
50
  hasShowPassword?: boolean;
52
51
  /**
53
- * The ref forwarded to the TextField to expose focus()
52
+ * The ref forwarded to the TextField
54
53
  */
55
- inputFocusRef?: React.RefObject<FocusHandle>;
54
+ inputRef?: React.RefObject<FocusHandle>;
56
55
  /**
57
56
  * The label for the `input` element.
58
57
  */
@@ -83,6 +82,7 @@ export type PasswordFieldProps = {
83
82
  const PasswordField = forwardRef<HTMLInputElement, PasswordFieldProps>(
84
83
  (
85
84
  {
85
+ ariaDescribedBy,
86
86
  autoCompleteType,
87
87
  defaultValue,
88
88
  errorMessage,
@@ -90,7 +90,7 @@ const PasswordField = forwardRef<HTMLInputElement, PasswordFieldProps>(
90
90
  hasInitialFocus,
91
91
  hint,
92
92
  id: idOverride,
93
- inputFocusRef,
93
+ inputRef,
94
94
  isDisabled = false,
95
95
  isFullWidth = false,
96
96
  isOptional = false,
@@ -129,14 +129,13 @@ const PasswordField = forwardRef<HTMLInputElement, PasswordFieldProps>(
129
129
  controlState: controlledStateRef.current,
130
130
  });
131
131
 
132
- const inputRef = useRef<HTMLInputElement>(null);
132
+ const localInputRef = useRef<HTMLInputElement>(null);
133
133
  useImperativeHandle(
134
- inputFocusRef,
134
+ inputRef,
135
135
  () => {
136
- const element = inputRef.current;
137
136
  return {
138
137
  focus: () => {
139
- element && element.focus();
138
+ localInputRef.current?.focus();
140
139
  },
141
140
  };
142
141
  },
@@ -160,7 +159,6 @@ const PasswordField = forwardRef<HTMLInputElement, PasswordFieldProps>(
160
159
  autoComplete={inputType === "password" ? autoCompleteType : "off"}
161
160
  /* eslint-disable-next-line jsx-a11y/no-autofocus */
162
161
  autoFocus={hasInitialFocus}
163
- data-se={testId}
164
162
  endAdornment={
165
163
  hasShowPassword && (
166
164
  <InputAdornment position="end">
@@ -183,10 +181,11 @@ const PasswordField = forwardRef<HTMLInputElement, PasswordFieldProps>(
183
181
  inputProps={{
184
182
  "aria-errormessage": errorMessageElementId,
185
183
  "aria-labelledby": labelElementId,
184
+ "data-se": testId,
186
185
  // role: "textbox" Added because password inputs don't have an implicit role assigned. This causes problems with element selection.
187
186
  role: "textbox",
188
187
  }}
189
- inputRef={inputRef}
188
+ inputRef={localInputRef}
190
189
  name={nameOverride ?? id}
191
190
  onChange={onChange}
192
191
  onFocus={onFocus}
@@ -222,6 +221,7 @@ const PasswordField = forwardRef<HTMLInputElement, PasswordFieldProps>(
222
221
 
223
222
  return (
224
223
  <Field
224
+ ariaDescribedBy={ariaDescribedBy}
225
225
  errorMessage={errorMessage}
226
226
  errorMessageList={errorMessageList}
227
227
  fieldType="single"
package/src/Radio.tsx CHANGED
@@ -20,13 +20,13 @@ import { memo, useCallback, useRef, useImperativeHandle } from "react";
20
20
 
21
21
  import { FieldComponentProps } from "./FieldComponentProps";
22
22
  import type { AllowedProps } from "./AllowedProps";
23
- import { FocusHandle } from "./@types/react-augment";
23
+ import { FocusHandle } from "./inputUtils";
24
24
 
25
25
  export type RadioProps = {
26
26
  /**
27
- * The ref forwarded to the Radio to expose focus()
27
+ * The ref forwarded to the Radio
28
28
  */
29
- inputFocusRef?: React.RefObject<FocusHandle>;
29
+ inputRef?: React.RefObject<FocusHandle>;
30
30
  /**
31
31
  * If `true`, the Radio is selected
32
32
  */
@@ -55,7 +55,7 @@ export type RadioProps = {
55
55
  AllowedProps;
56
56
 
57
57
  const Radio = ({
58
- inputFocusRef,
58
+ inputRef,
59
59
  isChecked,
60
60
  isDisabled,
61
61
  isInvalid,
@@ -67,14 +67,13 @@ const Radio = ({
67
67
  onChange: onChangeProp,
68
68
  onBlur: onBlurProp,
69
69
  }: RadioProps) => {
70
- const ref = useRef<HTMLInputElement>(null);
70
+ const localInputRef = useRef<HTMLInputElement>(null);
71
71
  useImperativeHandle(
72
- inputFocusRef,
72
+ inputRef,
73
73
  () => {
74
- const element = ref.current;
75
74
  return {
76
75
  focus: () => {
77
- element && element.focus();
76
+ localInputRef.current?.focus();
78
77
  },
79
78
  };
80
79
  },
@@ -99,8 +98,15 @@ const Radio = ({
99
98
  <FormControlLabel
100
99
  checked={isChecked}
101
100
  className={isInvalid ? "Mui-error" : ""}
102
- control={<MuiRadio inputRef={ref} onChange={onChange} />}
103
- data-se={testId}
101
+ control={
102
+ <MuiRadio
103
+ inputProps={{
104
+ "data-se": testId,
105
+ }}
106
+ inputRef={localInputRef}
107
+ onChange={onChange}
108
+ />
109
+ }
104
110
  disabled={isDisabled}
105
111
  label={label}
106
112
  name={name}
@@ -45,6 +45,7 @@ export type RadioGroupProps = {
45
45
  value?: RadioProps["value"];
46
46
  } & Pick<
47
47
  FieldComponentProps,
48
+ | "ariaDescribedBy"
48
49
  | "errorMessage"
49
50
  | "errorMessageList"
50
51
  | "hint"
@@ -56,6 +57,7 @@ export type RadioGroupProps = {
56
57
  AllowedProps;
57
58
 
58
59
  const RadioGroup = ({
60
+ ariaDescribedBy,
59
61
  children,
60
62
  defaultValue,
61
63
  errorMessage,
@@ -107,6 +109,7 @@ const RadioGroup = ({
107
109
 
108
110
  return (
109
111
  <Field
112
+ ariaDescribedBy={ariaDescribedBy}
110
113
  errorMessage={errorMessage}
111
114
  errorMessageList={errorMessageList}
112
115
  fieldType="group"
@@ -78,12 +78,16 @@ export type SearchFieldProps = {
78
78
  * The value of the `input` element, to use when controlled.
79
79
  */
80
80
  value?: string;
81
- } & Pick<FieldComponentProps, "id" | "isDisabled" | "name" | "isFullWidth"> &
81
+ } & Pick<
82
+ FieldComponentProps,
83
+ "ariaDescribedBy" | "id" | "isDisabled" | "name" | "isFullWidth"
84
+ > &
82
85
  AllowedProps;
83
86
 
84
87
  const SearchField = forwardRef<HTMLInputElement, SearchFieldProps>(
85
88
  (
86
89
  {
90
+ ariaDescribedBy,
87
91
  autoCompleteType,
88
92
  defaultValue,
89
93
  hasInitialFocus,
@@ -186,6 +190,7 @@ const SearchField = forwardRef<HTMLInputElement, SearchFieldProps>(
186
190
 
187
191
  return (
188
192
  <Field
193
+ ariaDescribedBy={ariaDescribedBy}
189
194
  fieldType="single"
190
195
  hasVisibleLabel={false}
191
196
  id={idOverride}