@okta/odyssey-react-mui 1.10.3 → 1.11.1

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 (76) hide show
  1. package/CHANGELOG.md +13 -0
  2. package/dist/@types/react-augment.d.js.map +1 -1
  3. package/dist/Accordion.js +8 -0
  4. package/dist/Accordion.js.map +1 -1
  5. package/dist/Autocomplete.js +3 -3
  6. package/dist/Autocomplete.js.map +1 -1
  7. package/dist/Button.js +5 -6
  8. package/dist/Button.js.map +1 -1
  9. package/dist/Checkbox.js +8 -7
  10. package/dist/Checkbox.js.map +1 -1
  11. package/dist/CheckboxGroup.js +4 -0
  12. package/dist/CheckboxGroup.js.map +1 -1
  13. package/dist/Link.js +5 -6
  14. package/dist/Link.js.map +1 -1
  15. package/dist/NativeSelect.js +16 -4
  16. package/dist/NativeSelect.js.map +1 -1
  17. package/dist/PasswordField.js +8 -7
  18. package/dist/PasswordField.js.map +1 -1
  19. package/dist/Radio.js +8 -7
  20. package/dist/Radio.js.map +1 -1
  21. package/dist/Select.js +8 -7
  22. package/dist/Select.js.map +1 -1
  23. package/dist/TextField.js +6 -7
  24. package/dist/TextField.js.map +1 -1
  25. package/dist/Typography.js +5 -6
  26. package/dist/Typography.js.map +1 -1
  27. package/dist/inputUtils.js.map +1 -1
  28. package/dist/labs/Switch.js +3 -3
  29. package/dist/labs/Switch.js.map +1 -1
  30. package/dist/labs/VirtualizedAutocomplete.js +3 -3
  31. package/dist/labs/VirtualizedAutocomplete.js.map +1 -1
  32. package/dist/src/Accordion.d.ts +5 -1
  33. package/dist/src/Accordion.d.ts.map +1 -1
  34. package/dist/src/Autocomplete.d.ts.map +1 -1
  35. package/dist/src/Button.d.ts +4 -4
  36. package/dist/src/Button.d.ts.map +1 -1
  37. package/dist/src/Checkbox.d.ts +4 -4
  38. package/dist/src/Checkbox.d.ts.map +1 -1
  39. package/dist/src/CheckboxGroup.d.ts +2 -2
  40. package/dist/src/CheckboxGroup.d.ts.map +1 -1
  41. package/dist/src/Link.d.ts +4 -4
  42. package/dist/src/Link.d.ts.map +1 -1
  43. package/dist/src/NativeSelect.d.ts +12 -1
  44. package/dist/src/NativeSelect.d.ts.map +1 -1
  45. package/dist/src/PasswordField.d.ts +5 -5
  46. package/dist/src/PasswordField.d.ts.map +1 -1
  47. package/dist/src/Radio.d.ts +4 -4
  48. package/dist/src/Radio.d.ts.map +1 -1
  49. package/dist/src/Select.d.ts +4 -4
  50. package/dist/src/Select.d.ts.map +1 -1
  51. package/dist/src/TextField.d.ts +5 -5
  52. package/dist/src/TextField.d.ts.map +1 -1
  53. package/dist/src/Typography.d.ts +4 -4
  54. package/dist/src/Typography.d.ts.map +1 -1
  55. package/dist/src/inputUtils.d.ts +3 -0
  56. package/dist/src/inputUtils.d.ts.map +1 -1
  57. package/dist/src/labs/Switch.d.ts.map +1 -1
  58. package/dist/src/labs/VirtualizedAutocomplete.d.ts.map +1 -1
  59. package/dist/tsconfig.production.tsbuildinfo +1 -1
  60. package/package.json +3 -3
  61. package/src/@types/react-augment.d.ts +8 -4
  62. package/src/Accordion.tsx +17 -2
  63. package/src/Autocomplete.tsx +2 -1
  64. package/src/Button.tsx +8 -9
  65. package/src/Checkbox.tsx +15 -11
  66. package/src/CheckboxGroup.tsx +5 -1
  67. package/src/Link.tsx +8 -9
  68. package/src/NativeSelect.tsx +33 -2
  69. package/src/PasswordField.tsx +11 -11
  70. package/src/Radio.tsx +16 -10
  71. package/src/Select.tsx +9 -10
  72. package/src/TextField.tsx +9 -11
  73. package/src/Typography.tsx +8 -9
  74. package/src/inputUtils.ts +4 -0
  75. package/src/labs/Switch.tsx +2 -1
  76. package/src/labs/VirtualizedAutocomplete.tsx +10 -2
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@okta/odyssey-react-mui",
3
- "version": "1.10.3",
3
+ "version": "1.11.1",
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.10.3",
54
+ "@okta/odyssey-design-tokens": "1.11.1",
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": "a6212214c614cc9e2b6199d805e253d4fad586a4"
66
+ "gitHead": "3318d342f74b82e7b957bf881007fe0f78556635"
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
+ }
package/src/Accordion.tsx CHANGED
@@ -20,12 +20,17 @@ import {
20
20
  } from "@mui/material";
21
21
  import { ChevronDownIcon } from "./icons.generated";
22
22
  import { Support } from "./Typography";
23
+ import { useUniqueId } from "./useUniqueId";
23
24
 
24
25
  export type AccordionProps = {
25
26
  /**
26
27
  * The content of the Accordion itself
27
28
  */
28
29
  children: ReactNode;
30
+ /**
31
+ * Defines IDs for the header and the content of the Accordion
32
+ */
33
+ id?: string;
29
34
  /**
30
35
  * The label text for the AccordionSummary
31
36
  */
@@ -66,12 +71,16 @@ const Accordion = ({
66
71
  children,
67
72
  label,
68
73
  hasShadow = true,
74
+ id: idOverride,
69
75
  isDefaultExpanded,
70
76
  isDisabled,
71
77
  isExpanded,
72
78
  onChange,
73
79
  translate,
74
80
  }: AccordionProps) => {
81
+ const id = useUniqueId(idOverride);
82
+ const headerId = `${id}-header`;
83
+ const contentId = `${id}-content`;
75
84
  return (
76
85
  <MuiAccordion
77
86
  defaultExpanded={isDefaultExpanded}
@@ -81,12 +90,18 @@ const Accordion = ({
81
90
  onChange={onChange}
82
91
  className={hasShadow ? `hasShadow` : undefined}
83
92
  >
84
- <MuiAccordionSummary expandIcon={<ChevronDownIcon />}>
93
+ <MuiAccordionSummary
94
+ aria-controls={contentId}
95
+ expandIcon={<ChevronDownIcon />}
96
+ id={headerId}
97
+ >
85
98
  <Support component="div" translate={translate}>
86
99
  {label}
87
100
  </Support>
88
101
  </MuiAccordionSummary>
89
- <MuiAccordionDetails>{children}</MuiAccordionDetails>
102
+ <MuiAccordionDetails aria-labelledby={headerId}>
103
+ {children}
104
+ </MuiAccordionDetails>
90
105
  </MuiAccordion>
91
106
  );
92
107
  };
@@ -267,6 +267,7 @@ const Autocomplete = <
267
267
  ...params.inputProps,
268
268
  "aria-errormessage": errorMessageElementId,
269
269
  "aria-labelledby": labelElementId,
270
+ "data-se": testId,
270
271
  }}
271
272
  aria-describedby={ariaDescribedBy}
272
273
  id={id}
@@ -284,6 +285,7 @@ const Autocomplete = <
284
285
  isOptional,
285
286
  label,
286
287
  nameOverride,
288
+ testId,
287
289
  ]
288
290
  );
289
291
  const onChange = useCallback<
@@ -324,7 +326,6 @@ const Autocomplete = <
324
326
  {...inputValueProp}
325
327
  // 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
328
  aria-disabled={isDisabled}
327
- data-se={testId}
328
329
  disableCloseOnSelect={hasMultipleChoices}
329
330
  disabled={isDisabled}
330
331
  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}
@@ -39,6 +39,7 @@ export type CheckboxGroupProps = {
39
39
  | "errorMessageList"
40
40
  | "hint"
41
41
  | "HintLinkComponent"
42
+ | "id"
42
43
  | "isDisabled"
43
44
  > &
44
45
  AllowedProps;
@@ -49,6 +50,7 @@ const CheckboxGroup = ({
49
50
  errorMessageList,
50
51
  hint,
51
52
  HintLinkComponent,
53
+ id: idOverride,
52
54
  isDisabled,
53
55
  isRequired = false,
54
56
  label,
@@ -56,12 +58,13 @@ const CheckboxGroup = ({
56
58
  translate,
57
59
  }: CheckboxGroupProps) => {
58
60
  const renderFieldComponent = useCallback(
59
- ({ ariaDescribedBy, errorMessageElementId, labelElementId }) => (
61
+ ({ ariaDescribedBy, errorMessageElementId, id, labelElementId }) => (
60
62
  <MuiFormGroup
61
63
  aria-describedby={ariaDescribedBy}
62
64
  aria-errormessage={errorMessageElementId}
63
65
  aria-labelledby={labelElementId}
64
66
  data-se={testId}
67
+ id={id}
65
68
  translate={translate}
66
69
  >
67
70
  {children}
@@ -78,6 +81,7 @@ const CheckboxGroup = ({
78
81
  hasVisibleLabel={true}
79
82
  hint={hint}
80
83
  HintLinkComponent={HintLinkComponent}
84
+ id={idOverride}
81
85
  isDisabled={isDisabled}
82
86
  isOptional={!isRequired}
83
87
  label={label}
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
  */
@@ -98,6 +110,7 @@ const NativeSelect: ForwardRefWithType = forwardRef(
98
110
  HasMultipleChoices extends boolean
99
111
  >(
100
112
  {
113
+ autoCompleteType,
101
114
  defaultValue,
102
115
  errorMessage,
103
116
  errorMessageList,
@@ -105,6 +118,7 @@ const NativeSelect: ForwardRefWithType = forwardRef(
105
118
  hint,
106
119
  HintLinkComponent,
107
120
  id: idOverride,
121
+ inputRef,
108
122
  isDisabled = false,
109
123
  isFullWidth = false,
110
124
  isMultiSelect,
@@ -126,6 +140,20 @@ const NativeSelect: ForwardRefWithType = forwardRef(
126
140
  uncontrolledValue: defaultValue,
127
141
  })
128
142
  );
143
+ const localInputRef = useRef<HTMLSelectElement>(null);
144
+
145
+ useImperativeHandle(
146
+ inputRef,
147
+ () => {
148
+ return {
149
+ focus: () => {
150
+ localInputRef.current?.focus();
151
+ },
152
+ };
153
+ },
154
+ []
155
+ );
156
+
129
157
  const inputValues = useInputValues({
130
158
  defaultValue,
131
159
  value,
@@ -153,13 +181,15 @@ const NativeSelect: ForwardRefWithType = forwardRef(
153
181
  <MuiSelect
154
182
  {...inputValues}
155
183
  aria-describedby={ariaDescribedBy}
184
+ autoComplete={autoCompleteType}
156
185
  children={children}
157
- data-se={testId}
158
186
  id={idOverride}
159
187
  inputProps={{
160
188
  "aria-errormessage": errorMessageElementId,
161
189
  "aria-labelledby": labelElementId,
190
+ "data-se": testId,
162
191
  }}
192
+ inputRef={localInputRef}
163
193
  name={idOverride}
164
194
  multiple={hasMultipleChoices}
165
195
  native={true}
@@ -171,6 +201,7 @@ const NativeSelect: ForwardRefWithType = forwardRef(
171
201
  />
172
202
  ),
173
203
  [
204
+ autoCompleteType,
174
205
  children,
175
206
  idOverride,
176
207
  inputValues,
@@ -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
  */
@@ -90,7 +89,7 @@ const PasswordField = forwardRef<HTMLInputElement, PasswordFieldProps>(
90
89
  hasInitialFocus,
91
90
  hint,
92
91
  id: idOverride,
93
- inputFocusRef,
92
+ inputRef,
94
93
  isDisabled = false,
95
94
  isFullWidth = false,
96
95
  isOptional = false,
@@ -129,14 +128,13 @@ const PasswordField = forwardRef<HTMLInputElement, PasswordFieldProps>(
129
128
  controlState: controlledStateRef.current,
130
129
  });
131
130
 
132
- const inputRef = useRef<HTMLInputElement>(null);
131
+ const localInputRef = useRef<HTMLInputElement>(null);
133
132
  useImperativeHandle(
134
- inputFocusRef,
133
+ inputRef,
135
134
  () => {
136
- const element = inputRef.current;
137
135
  return {
138
136
  focus: () => {
139
- element && element.focus();
137
+ localInputRef.current?.focus();
140
138
  },
141
139
  };
142
140
  },
@@ -160,16 +158,17 @@ const PasswordField = forwardRef<HTMLInputElement, PasswordFieldProps>(
160
158
  autoComplete={inputType === "password" ? autoCompleteType : "off"}
161
159
  /* eslint-disable-next-line jsx-a11y/no-autofocus */
162
160
  autoFocus={hasInitialFocus}
163
- data-se={testId}
164
161
  endAdornment={
165
162
  hasShowPassword && (
166
163
  <InputAdornment position="end">
167
164
  <IconButton
165
+ aria-controls={id}
168
166
  aria-label={
169
167
  inputType === "password"
170
168
  ? t("passwordfield.icon.label.show")
171
169
  : t("passwordfield.icon.label.hide")
172
170
  }
171
+ aria-pressed={inputType === "text"}
173
172
  onClick={togglePasswordVisibility}
174
173
  >
175
174
  {inputType === "password" ? <ShowIcon /> : <HideIcon />}
@@ -181,10 +180,11 @@ const PasswordField = forwardRef<HTMLInputElement, PasswordFieldProps>(
181
180
  inputProps={{
182
181
  "aria-errormessage": errorMessageElementId,
183
182
  "aria-labelledby": labelElementId,
183
+ "data-se": testId,
184
184
  // role: "textbox" Added because password inputs don't have an implicit role assigned. This causes problems with element selection.
185
185
  role: "textbox",
186
186
  }}
187
- inputRef={inputRef}
187
+ inputRef={localInputRef}
188
188
  name={nameOverride ?? id}
189
189
  onChange={onChange}
190
190
  onFocus={onFocus}
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}
package/src/Select.tsx CHANGED
@@ -36,10 +36,10 @@ import { CheckIcon } from "./icons.generated";
36
36
  import type { AllowedProps } from "./AllowedProps";
37
37
  import {
38
38
  ComponentControlledState,
39
+ FocusHandle,
39
40
  useInputValues,
40
41
  getControlState,
41
42
  } from "./inputUtils";
42
- import { FocusHandle } from "./@types/react-augment";
43
43
 
44
44
  export type SelectOption = {
45
45
  text: string;
@@ -63,9 +63,9 @@ export type SelectProps<
63
63
  */
64
64
  hasMultipleChoices?: HasMultipleChoices;
65
65
  /**
66
- * The ref forwarded to the Select to expose focus()
66
+ * The ref forwarded to the Select
67
67
  */
68
- inputFocusRef?: React.RefObject<FocusHandle>;
68
+ inputRef?: React.RefObject<FocusHandle>;
69
69
  /**
70
70
  * @deprecated Use `hasMultipleChoices` instead.
71
71
  */
@@ -136,7 +136,7 @@ const Select = <
136
136
  hint,
137
137
  HintLinkComponent,
138
138
  id: idOverride,
139
- inputFocusRef,
139
+ inputRef,
140
140
  isDisabled = false,
141
141
  isFullWidth = false,
142
142
  isMultiSelect,
@@ -164,15 +164,14 @@ const Select = <
164
164
  const [internalSelectedValues, setInternalSelectedValues] = useState(
165
165
  controlledStateRef.current === CONTROLLED ? value : defaultValue
166
166
  );
167
- const inputRef = useRef<HTMLSelectElement>(null);
167
+ const localInputRef = useRef<HTMLSelectElement>(null);
168
168
 
169
169
  useImperativeHandle(
170
- inputFocusRef,
170
+ inputRef,
171
171
  () => {
172
- const element = inputRef.current;
173
172
  return {
174
173
  focus: () => {
175
- element && element.focus();
174
+ localInputRef.current?.focus();
176
175
  },
177
176
  };
178
177
  },
@@ -290,9 +289,9 @@ const Select = <
290
289
  aria-describedby={ariaDescribedBy}
291
290
  aria-errormessage={errorMessageElementId}
292
291
  children={children}
293
- data-se={testId}
294
292
  id={id}
295
- inputRef={inputRef}
293
+ inputProps={{ "data-se": testId }}
294
+ inputRef={localInputRef}
296
295
  labelId={labelElementId}
297
296
  multiple={hasMultipleChoices}
298
297
  name={nameOverride ?? id}