@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.
- package/CHANGELOG.md +13 -0
- package/dist/@types/react-augment.d.js.map +1 -1
- package/dist/Accordion.js +8 -0
- package/dist/Accordion.js.map +1 -1
- package/dist/Autocomplete.js +3 -3
- package/dist/Autocomplete.js.map +1 -1
- package/dist/Button.js +5 -6
- package/dist/Button.js.map +1 -1
- package/dist/Checkbox.js +8 -7
- package/dist/Checkbox.js.map +1 -1
- package/dist/CheckboxGroup.js +4 -0
- package/dist/CheckboxGroup.js.map +1 -1
- package/dist/Link.js +5 -6
- package/dist/Link.js.map +1 -1
- package/dist/NativeSelect.js +16 -4
- package/dist/NativeSelect.js.map +1 -1
- package/dist/PasswordField.js +8 -7
- package/dist/PasswordField.js.map +1 -1
- package/dist/Radio.js +8 -7
- package/dist/Radio.js.map +1 -1
- package/dist/Select.js +8 -7
- package/dist/Select.js.map +1 -1
- package/dist/TextField.js +6 -7
- package/dist/TextField.js.map +1 -1
- package/dist/Typography.js +5 -6
- package/dist/Typography.js.map +1 -1
- package/dist/inputUtils.js.map +1 -1
- package/dist/labs/Switch.js +3 -3
- package/dist/labs/Switch.js.map +1 -1
- package/dist/labs/VirtualizedAutocomplete.js +3 -3
- package/dist/labs/VirtualizedAutocomplete.js.map +1 -1
- package/dist/src/Accordion.d.ts +5 -1
- package/dist/src/Accordion.d.ts.map +1 -1
- package/dist/src/Autocomplete.d.ts.map +1 -1
- package/dist/src/Button.d.ts +4 -4
- package/dist/src/Button.d.ts.map +1 -1
- package/dist/src/Checkbox.d.ts +4 -4
- package/dist/src/Checkbox.d.ts.map +1 -1
- package/dist/src/CheckboxGroup.d.ts +2 -2
- package/dist/src/CheckboxGroup.d.ts.map +1 -1
- package/dist/src/Link.d.ts +4 -4
- package/dist/src/Link.d.ts.map +1 -1
- package/dist/src/NativeSelect.d.ts +12 -1
- package/dist/src/NativeSelect.d.ts.map +1 -1
- package/dist/src/PasswordField.d.ts +5 -5
- package/dist/src/PasswordField.d.ts.map +1 -1
- package/dist/src/Radio.d.ts +4 -4
- package/dist/src/Radio.d.ts.map +1 -1
- package/dist/src/Select.d.ts +4 -4
- package/dist/src/Select.d.ts.map +1 -1
- package/dist/src/TextField.d.ts +5 -5
- package/dist/src/TextField.d.ts.map +1 -1
- package/dist/src/Typography.d.ts +4 -4
- package/dist/src/Typography.d.ts.map +1 -1
- package/dist/src/inputUtils.d.ts +3 -0
- package/dist/src/inputUtils.d.ts.map +1 -1
- package/dist/src/labs/Switch.d.ts.map +1 -1
- package/dist/src/labs/VirtualizedAutocomplete.d.ts.map +1 -1
- package/dist/tsconfig.production.tsbuildinfo +1 -1
- package/package.json +3 -3
- package/src/@types/react-augment.d.ts +8 -4
- package/src/Accordion.tsx +17 -2
- package/src/Autocomplete.tsx +2 -1
- package/src/Button.tsx +8 -9
- package/src/Checkbox.tsx +15 -11
- package/src/CheckboxGroup.tsx +5 -1
- package/src/Link.tsx +8 -9
- package/src/NativeSelect.tsx +33 -2
- package/src/PasswordField.tsx +11 -11
- package/src/Radio.tsx +16 -10
- package/src/Select.tsx +9 -10
- package/src/TextField.tsx +9 -11
- package/src/Typography.tsx +8 -9
- package/src/inputUtils.ts +4 -0
- package/src/labs/Switch.tsx +2 -1
- 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.
|
|
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.
|
|
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": "
|
|
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
|
-
|
|
22
|
-
|
|
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
|
|
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
|
|
102
|
+
<MuiAccordionDetails aria-labelledby={headerId}>
|
|
103
|
+
{children}
|
|
104
|
+
</MuiAccordionDetails>
|
|
90
105
|
</MuiAccordion>
|
|
91
106
|
);
|
|
92
107
|
};
|
package/src/Autocomplete.tsx
CHANGED
|
@@ -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 "
|
|
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
|
|
52
|
+
* The ref forwarded to the Button
|
|
53
53
|
*/
|
|
54
|
-
|
|
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
|
-
|
|
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
|
|
139
|
+
const localButtonRef = useRef<HTMLButtonElement>(null);
|
|
140
140
|
useImperativeHandle(
|
|
141
|
-
|
|
141
|
+
buttonRef,
|
|
142
142
|
() => {
|
|
143
|
-
const element = ref.current;
|
|
144
143
|
return {
|
|
145
144
|
focus: () => {
|
|
146
|
-
|
|
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={
|
|
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 {
|
|
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
|
|
49
|
+
* The ref forwarded to the Checkbox
|
|
47
50
|
*/
|
|
48
|
-
|
|
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
|
-
|
|
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
|
|
122
|
+
const localInputRef = useRef<HTMLInputElement>(null);
|
|
120
123
|
useImperativeHandle(
|
|
121
|
-
|
|
124
|
+
inputRef,
|
|
122
125
|
() => {
|
|
123
|
-
const element = inputRef.current;
|
|
124
126
|
return {
|
|
125
127
|
focus: () => {
|
|
126
|
-
|
|
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
|
-
|
|
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}
|
package/src/CheckboxGroup.tsx
CHANGED
|
@@ -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
|
|
36
|
+
* The ref forwarded to the TextField
|
|
37
37
|
*/
|
|
38
|
-
|
|
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
|
-
|
|
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
|
|
74
|
+
const localLinkRef = useRef<HTMLAnchorElement>(null);
|
|
75
75
|
useImperativeHandle(
|
|
76
|
-
|
|
76
|
+
linkRef,
|
|
77
77
|
() => {
|
|
78
|
-
const element = ref.current;
|
|
79
78
|
return {
|
|
80
79
|
focus: () => {
|
|
81
|
-
|
|
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={
|
|
91
|
+
ref={localLinkRef}
|
|
93
92
|
rel={rel}
|
|
94
93
|
target={target}
|
|
95
94
|
translate={translate}
|
package/src/NativeSelect.tsx
CHANGED
|
@@ -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,
|
package/src/PasswordField.tsx
CHANGED
|
@@ -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
|
|
52
|
+
* The ref forwarded to the TextField
|
|
54
53
|
*/
|
|
55
|
-
|
|
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
|
-
|
|
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
|
|
131
|
+
const localInputRef = useRef<HTMLInputElement>(null);
|
|
133
132
|
useImperativeHandle(
|
|
134
|
-
|
|
133
|
+
inputRef,
|
|
135
134
|
() => {
|
|
136
|
-
const element = inputRef.current;
|
|
137
135
|
return {
|
|
138
136
|
focus: () => {
|
|
139
|
-
|
|
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={
|
|
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 "
|
|
23
|
+
import { FocusHandle } from "./inputUtils";
|
|
24
24
|
|
|
25
25
|
export type RadioProps = {
|
|
26
26
|
/**
|
|
27
|
-
* The ref forwarded to the Radio
|
|
27
|
+
* The ref forwarded to the Radio
|
|
28
28
|
*/
|
|
29
|
-
|
|
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
|
-
|
|
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
|
|
70
|
+
const localInputRef = useRef<HTMLInputElement>(null);
|
|
71
71
|
useImperativeHandle(
|
|
72
|
-
|
|
72
|
+
inputRef,
|
|
73
73
|
() => {
|
|
74
|
-
const element = ref.current;
|
|
75
74
|
return {
|
|
76
75
|
focus: () => {
|
|
77
|
-
|
|
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={
|
|
103
|
-
|
|
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
|
|
66
|
+
* The ref forwarded to the Select
|
|
67
67
|
*/
|
|
68
|
-
|
|
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
|
-
|
|
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
|
|
167
|
+
const localInputRef = useRef<HTMLSelectElement>(null);
|
|
168
168
|
|
|
169
169
|
useImperativeHandle(
|
|
170
|
-
|
|
170
|
+
inputRef,
|
|
171
171
|
() => {
|
|
172
|
-
const element = inputRef.current;
|
|
173
172
|
return {
|
|
174
173
|
focus: () => {
|
|
175
|
-
|
|
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
|
-
|
|
293
|
+
inputProps={{ "data-se": testId }}
|
|
294
|
+
inputRef={localInputRef}
|
|
296
295
|
labelId={labelElementId}
|
|
297
296
|
multiple={hasMultipleChoices}
|
|
298
297
|
name={nameOverride ?? id}
|