@okta/odyssey-react-mui 1.0.2 → 1.2.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 (274) hide show
  1. package/CHANGELOG.md +54 -0
  2. package/README.md +1 -1
  3. package/dist/Autocomplete.js +20 -3
  4. package/dist/Autocomplete.js.map +1 -1
  5. package/dist/Banner.js +3 -1
  6. package/dist/Banner.js.map +1 -1
  7. package/dist/Box.js +8 -4
  8. package/dist/Box.js.map +1 -1
  9. package/dist/Button.js +3 -1
  10. package/dist/Button.js.map +1 -1
  11. package/dist/Callout.js +2 -0
  12. package/dist/Callout.js.map +1 -1
  13. package/dist/Checkbox.js +6 -2
  14. package/dist/Checkbox.js.map +1 -1
  15. package/dist/CheckboxGroup.js +5 -7
  16. package/dist/CheckboxGroup.js.map +1 -1
  17. package/dist/CircularProgress.js +2 -0
  18. package/dist/CircularProgress.js.map +1 -1
  19. package/dist/Dialog.js +2 -0
  20. package/dist/Dialog.js.map +1 -1
  21. package/dist/Field.js.map +1 -1
  22. package/dist/FieldError.js +2 -0
  23. package/dist/FieldError.js.map +1 -1
  24. package/dist/FieldHint.js +2 -0
  25. package/dist/FieldHint.js.map +1 -1
  26. package/dist/FieldLabel.js +3 -1
  27. package/dist/FieldLabel.js.map +1 -1
  28. package/dist/Fieldset.js +3 -1
  29. package/dist/Fieldset.js.map +1 -1
  30. package/dist/Form.js +5 -3
  31. package/dist/Form.js.map +1 -1
  32. package/dist/Link.js +3 -1
  33. package/dist/Link.js.map +1 -1
  34. package/dist/MenuButton.js +8 -2
  35. package/dist/MenuButton.js.map +1 -1
  36. package/dist/MenuItem.js +6 -2
  37. package/dist/MenuItem.js.map +1 -1
  38. package/dist/NativeSelect.js +3 -1
  39. package/dist/NativeSelect.js.map +1 -1
  40. package/dist/OdysseyCacheProvider.js +4 -1
  41. package/dist/OdysseyCacheProvider.js.map +1 -1
  42. package/dist/OdysseyProvider.js +12 -5
  43. package/dist/OdysseyProvider.js.map +1 -1
  44. package/dist/OdysseyThemeProvider.js +8 -7
  45. package/dist/OdysseyThemeProvider.js.map +1 -1
  46. package/dist/OdysseyTranslationProvider.js +1 -1
  47. package/dist/OdysseyTranslationProvider.js.map +1 -1
  48. package/dist/OdysseyTranslationProvider.types.js +1 -1
  49. package/dist/OdysseyTranslationProvider.types.js.map +1 -1
  50. package/dist/PasswordField.js +18 -9
  51. package/dist/PasswordField.js.map +1 -1
  52. package/dist/Radio.js +2 -0
  53. package/dist/Radio.js.map +1 -1
  54. package/dist/RadioGroup.js +5 -2
  55. package/dist/RadioGroup.js.map +1 -1
  56. package/dist/SearchField.js +11 -10
  57. package/dist/SearchField.js.map +1 -1
  58. package/dist/Select.js +39 -35
  59. package/dist/Select.js.map +1 -1
  60. package/dist/SeleniumProps.js +2 -0
  61. package/dist/SeleniumProps.js.map +1 -0
  62. package/dist/Status.js +4 -2
  63. package/dist/Status.js.map +1 -1
  64. package/dist/Tabs.js +11 -4
  65. package/dist/Tabs.js.map +1 -1
  66. package/dist/Tag.js +4 -2
  67. package/dist/Tag.js.map +1 -1
  68. package/dist/TagList.js +3 -1
  69. package/dist/TagList.js.map +1 -1
  70. package/dist/TextField.js +6 -2
  71. package/dist/TextField.js.map +1 -1
  72. package/dist/Toast.js +2 -0
  73. package/dist/Toast.js.map +1 -1
  74. package/dist/Tooltip.js +2 -0
  75. package/dist/Tooltip.js.map +1 -1
  76. package/dist/Typography.js +71 -59
  77. package/dist/Typography.js.map +1 -1
  78. package/dist/createShadowDom.js +26 -0
  79. package/dist/createShadowDom.js.map +1 -0
  80. package/dist/{OdysseyI18n.js → i18n.js} +5 -2
  81. package/dist/i18n.js.map +1 -0
  82. package/dist/index.js +1 -0
  83. package/dist/index.js.map +1 -1
  84. package/dist/labs/DatePicker.js +4 -2
  85. package/dist/labs/DatePicker.js.map +1 -1
  86. package/dist/labs/PaginatedTable.js +6 -4
  87. package/dist/labs/PaginatedTable.js.map +1 -1
  88. package/dist/labs/StaticTable.js +9 -4
  89. package/dist/labs/StaticTable.js.map +1 -1
  90. package/dist/labs/datePickerTheme.js +4 -2
  91. package/dist/labs/datePickerTheme.js.map +1 -1
  92. package/dist/properties/ts/odyssey-react-mui.js +2 -0
  93. package/dist/properties/ts/odyssey-react-mui.js.map +1 -1
  94. package/dist/src/Autocomplete.d.ts +29 -4
  95. package/dist/src/Autocomplete.d.ts.map +1 -1
  96. package/dist/src/Banner.d.ts +3 -2
  97. package/dist/src/Banner.d.ts.map +1 -1
  98. package/dist/src/Box.d.ts +9 -2
  99. package/dist/src/Box.d.ts.map +1 -1
  100. package/dist/src/Button.d.ts +3 -2
  101. package/dist/src/Button.d.ts.map +1 -1
  102. package/dist/src/Callout.d.ts +3 -2
  103. package/dist/src/Callout.d.ts.map +1 -1
  104. package/dist/src/Checkbox.d.ts +8 -3
  105. package/dist/src/Checkbox.d.ts.map +1 -1
  106. package/dist/src/CheckboxGroup.d.ts +3 -6
  107. package/dist/src/CheckboxGroup.d.ts.map +1 -1
  108. package/dist/src/CircularProgress.d.ts +3 -2
  109. package/dist/src/CircularProgress.d.ts.map +1 -1
  110. package/dist/src/Dialog.d.ts +3 -2
  111. package/dist/src/Dialog.d.ts.map +1 -1
  112. package/dist/src/Field.d.ts +2 -1
  113. package/dist/src/Field.d.ts.map +1 -1
  114. package/dist/src/FieldError.d.ts +3 -2
  115. package/dist/src/FieldError.d.ts.map +1 -1
  116. package/dist/src/FieldHint.d.ts +3 -2
  117. package/dist/src/FieldHint.d.ts.map +1 -1
  118. package/dist/src/FieldLabel.d.ts +3 -2
  119. package/dist/src/FieldLabel.d.ts.map +1 -1
  120. package/dist/src/Fieldset.d.ts +3 -2
  121. package/dist/src/Fieldset.d.ts.map +1 -1
  122. package/dist/src/Form.d.ts +3 -2
  123. package/dist/src/Form.d.ts.map +1 -1
  124. package/dist/src/Link.d.ts +3 -2
  125. package/dist/src/Link.d.ts.map +1 -1
  126. package/dist/src/MenuButton.d.ts +12 -3
  127. package/dist/src/MenuButton.d.ts.map +1 -1
  128. package/dist/src/MenuItem.d.ts +5 -4
  129. package/dist/src/MenuItem.d.ts.map +1 -1
  130. package/dist/src/NativeSelect.d.ts +56 -2
  131. package/dist/src/NativeSelect.d.ts.map +1 -1
  132. package/dist/src/OdysseyCacheProvider.d.ts +6 -1
  133. package/dist/src/OdysseyCacheProvider.d.ts.map +1 -1
  134. package/dist/src/OdysseyProvider.d.ts +1 -1
  135. package/dist/src/OdysseyProvider.d.ts.map +1 -1
  136. package/dist/src/OdysseyThemeProvider.d.ts +2 -1
  137. package/dist/src/OdysseyThemeProvider.d.ts.map +1 -1
  138. package/dist/src/OdysseyTranslationProvider.d.ts +1 -1
  139. package/dist/src/OdysseyTranslationProvider.d.ts.map +1 -1
  140. package/dist/src/OdysseyTranslationProvider.types.d.ts +1 -1
  141. package/dist/src/OdysseyTranslationProvider.types.d.ts.map +1 -1
  142. package/dist/src/PasswordField.d.ts +78 -2
  143. package/dist/src/PasswordField.d.ts.map +1 -1
  144. package/dist/src/Radio.d.ts +3 -2
  145. package/dist/src/Radio.d.ts.map +1 -1
  146. package/dist/src/RadioGroup.d.ts +8 -3
  147. package/dist/src/RadioGroup.d.ts.map +1 -1
  148. package/dist/src/SearchField.d.ts +58 -2
  149. package/dist/src/SearchField.d.ts.map +1 -1
  150. package/dist/src/Select.d.ts +7 -2
  151. package/dist/src/Select.d.ts.map +1 -1
  152. package/dist/src/SeleniumProps.d.ts +20 -0
  153. package/dist/src/SeleniumProps.d.ts.map +1 -0
  154. package/dist/src/Status.d.ts +3 -2
  155. package/dist/src/Status.d.ts.map +1 -1
  156. package/dist/src/Tabs.d.ts +9 -3
  157. package/dist/src/Tabs.d.ts.map +1 -1
  158. package/dist/src/Tag.d.ts +3 -2
  159. package/dist/src/Tag.d.ts.map +1 -1
  160. package/dist/src/TagList.d.ts +3 -2
  161. package/dist/src/TagList.d.ts.map +1 -1
  162. package/dist/src/TextField.d.ts +86 -2
  163. package/dist/src/TextField.d.ts.map +1 -1
  164. package/dist/src/Toast.d.ts +3 -2
  165. package/dist/src/Toast.d.ts.map +1 -1
  166. package/dist/src/Tooltip.d.ts +3 -2
  167. package/dist/src/Tooltip.d.ts.map +1 -1
  168. package/dist/src/Typography.d.ts +14 -49
  169. package/dist/src/Typography.d.ts.map +1 -1
  170. package/dist/src/createShadowDom.d.ts +16 -0
  171. package/dist/src/createShadowDom.d.ts.map +1 -0
  172. package/dist/src/{OdysseyI18n.d.ts → i18n.d.ts} +20 -2
  173. package/dist/src/i18n.d.ts.map +1 -0
  174. package/dist/src/index.d.ts +1 -0
  175. package/dist/src/index.d.ts.map +1 -1
  176. package/dist/src/labs/DatePicker.d.ts +5 -1
  177. package/dist/src/labs/DatePicker.d.ts.map +1 -1
  178. package/dist/src/labs/PaginatedTable.d.ts.map +1 -1
  179. package/dist/src/labs/StaticTable.d.ts.map +1 -1
  180. package/dist/src/properties/ts/odyssey-react-mui.d.ts +2 -0
  181. package/dist/src/properties/ts/odyssey-react-mui.d.ts.map +1 -1
  182. package/dist/src/theme/components.d.ts +4 -1
  183. package/dist/src/theme/components.d.ts.map +1 -1
  184. package/dist/src/theme/createOdysseyMuiTheme.d.ts +23 -0
  185. package/dist/src/theme/createOdysseyMuiTheme.d.ts.map +1 -0
  186. package/dist/src/theme/mixins.d.ts +3 -1
  187. package/dist/src/theme/mixins.d.ts.map +1 -1
  188. package/dist/src/theme/palette.d.ts +3 -1
  189. package/dist/src/theme/palette.d.ts.map +1 -1
  190. package/dist/src/theme/shape.d.ts +3 -1
  191. package/dist/src/theme/shape.d.ts.map +1 -1
  192. package/dist/src/theme/spacing.d.ts +3 -1
  193. package/dist/src/theme/spacing.d.ts.map +1 -1
  194. package/dist/src/theme/theme.d.ts +1 -8
  195. package/dist/src/theme/theme.d.ts.map +1 -1
  196. package/dist/src/theme/typography.d.ts +3 -1
  197. package/dist/src/theme/typography.d.ts.map +1 -1
  198. package/dist/theme/components.js +118 -73
  199. package/dist/theme/components.js.map +1 -1
  200. package/dist/theme/createOdysseyMuiTheme.js +51 -0
  201. package/dist/theme/createOdysseyMuiTheme.js.map +1 -0
  202. package/dist/theme/mixins.js +4 -1
  203. package/dist/theme/mixins.js.map +1 -1
  204. package/dist/theme/palette.js +4 -1
  205. package/dist/theme/palette.js.map +1 -1
  206. package/dist/theme/shape.js +4 -1
  207. package/dist/theme/shape.js.map +1 -1
  208. package/dist/theme/spacing.js +4 -1
  209. package/dist/theme/spacing.js.map +1 -1
  210. package/dist/theme/theme.js +1 -20
  211. package/dist/theme/theme.js.map +1 -1
  212. package/dist/theme/typography.js +4 -1
  213. package/dist/theme/typography.js.map +1 -1
  214. package/dist/tsconfig.production.tsbuildinfo +1 -1
  215. package/package.json +7 -6
  216. package/src/Autocomplete.tsx +56 -4
  217. package/src/Banner.tsx +11 -2
  218. package/src/Box.tsx +11 -5
  219. package/src/Button.tsx +6 -1
  220. package/src/Callout.tsx +5 -3
  221. package/src/Checkbox.tsx +14 -4
  222. package/src/CheckboxGroup.tsx +6 -10
  223. package/src/CircularProgress.tsx +5 -1
  224. package/src/Dialog.tsx +5 -2
  225. package/src/Field.tsx +2 -0
  226. package/src/FieldError.tsx +5 -3
  227. package/src/FieldHint.tsx +9 -3
  228. package/src/FieldLabel.tsx +5 -3
  229. package/src/Fieldset.tsx +4 -1
  230. package/src/Form.tsx +7 -4
  231. package/src/Link.tsx +18 -3
  232. package/src/MenuButton.tsx +33 -4
  233. package/src/MenuItem.tsx +11 -6
  234. package/src/NativeSelect.tsx +7 -2
  235. package/src/OdysseyCacheProvider.tsx +9 -1
  236. package/src/OdysseyProvider.tsx +18 -8
  237. package/src/OdysseyThemeProvider.tsx +12 -8
  238. package/src/OdysseyTranslationProvider.test.tsx +2 -2
  239. package/src/OdysseyTranslationProvider.tsx +1 -1
  240. package/src/OdysseyTranslationProvider.types.ts +1 -0
  241. package/src/PasswordField.tsx +37 -13
  242. package/src/Radio.tsx +5 -1
  243. package/src/RadioGroup.tsx +12 -4
  244. package/src/SearchField.tsx +23 -15
  245. package/src/Select.tsx +154 -149
  246. package/src/SeleniumProps.ts +20 -0
  247. package/src/Status.tsx +15 -3
  248. package/src/Tabs.tsx +18 -4
  249. package/src/Tag.tsx +12 -3
  250. package/src/TagList.tsx +4 -2
  251. package/src/TextField.tsx +14 -2
  252. package/src/Toast.tsx +4 -1
  253. package/src/Tooltip.tsx +4 -1
  254. package/src/Typography.tsx +76 -54
  255. package/src/createShadowDom.ts +46 -0
  256. package/src/{OdysseyI18n.ts → i18n.ts} +4 -2
  257. package/src/index.ts +1 -0
  258. package/src/labs/DatePicker.tsx +15 -7
  259. package/src/labs/PaginatedTable.tsx +12 -3
  260. package/src/labs/README.md +2 -2
  261. package/src/labs/StaticTable.tsx +13 -3
  262. package/src/labs/datePickerTheme.tsx +2 -2
  263. package/src/properties/odyssey-react-mui.properties +2 -0
  264. package/src/properties/ts/odyssey-react-mui.ts +1 -1
  265. package/src/theme/components.tsx +69 -18
  266. package/src/theme/createOdysseyMuiTheme.ts +47 -0
  267. package/src/theme/mixins.ts +5 -1
  268. package/src/theme/palette.ts +5 -3
  269. package/src/theme/shape.ts +5 -1
  270. package/src/theme/spacing.ts +5 -3
  271. package/src/theme/theme.ts +1 -26
  272. package/src/theme/typography.ts +5 -3
  273. package/dist/OdysseyI18n.js.map +0 -1
  274. package/dist/src/OdysseyI18n.d.ts.map +0 -1
package/src/Form.tsx CHANGED
@@ -17,6 +17,7 @@ import { Button } from "./Button";
17
17
  import { Callout } from "./Callout";
18
18
  import { Heading4, Support } from "./Typography";
19
19
  import { useUniqueId } from "./useUniqueId";
20
+ import type { SeleniumProps } from "./SeleniumProps";
20
21
 
21
22
  export const formEncodingTypeValues = [
22
23
  "application/x-www-form-urlencoded",
@@ -84,7 +85,7 @@ export type FormProps = {
84
85
  * The title of the Form
85
86
  */
86
87
  title?: string;
87
- };
88
+ } & SeleniumProps;
88
89
 
89
90
  const Form = ({
90
91
  alert,
@@ -98,20 +99,22 @@ const Form = ({
98
99
  name,
99
100
  noValidate = false,
100
101
  target,
102
+ testId,
101
103
  title,
102
104
  }: FormProps) => {
103
105
  const id = useUniqueId(idOverride);
104
106
 
105
107
  return (
106
108
  <Box
107
- component="form"
108
109
  autoComplete={autoCompleteType}
109
- name={name}
110
+ component="form"
111
+ data-se={testId}
110
112
  encType={encodingType}
113
+ id={id}
111
114
  method={method}
115
+ name={name}
112
116
  noValidate={noValidate}
113
117
  target={target}
114
- id={id}
115
118
  sx={{
116
119
  maxWidth: (theme) => theme.mixins.maxWidth,
117
120
  margin: (theme) => theme.spacing(0),
package/src/Link.tsx CHANGED
@@ -12,6 +12,7 @@
12
12
 
13
13
  import { memo, ReactElement } from "react";
14
14
  import { ExternalLinkIcon } from "./icons.generated";
15
+ import type { SeleniumProps } from "./SeleniumProps";
15
16
 
16
17
  import { Link as MuiLink } from "@mui/material";
17
18
 
@@ -47,10 +48,24 @@ export type LinkProps = {
47
48
  * The visual presentation of the Link (default or monochrome)
48
49
  */
49
50
  variant?: (typeof linkVariantValues)[number];
50
- };
51
+ } & SeleniumProps;
51
52
 
52
- const Link = ({ children, href, icon, target, rel, variant }: LinkProps) => (
53
- <MuiLink href={href} rel={rel} target={target} variant={variant}>
53
+ const Link = ({
54
+ children,
55
+ href,
56
+ icon,
57
+ rel,
58
+ target,
59
+ testId,
60
+ variant,
61
+ }: LinkProps) => (
62
+ <MuiLink
63
+ data-se={testId}
64
+ href={href}
65
+ rel={rel}
66
+ target={target}
67
+ variant={variant}
68
+ >
54
69
  {icon && <span className="Link-icon">{icon}</span>}
55
70
 
56
71
  {children}
@@ -10,13 +10,20 @@
10
10
  * See the License for the specific language governing permissions and limitations under the License.
11
11
  */
12
12
 
13
- import { Button, buttonVariantValues, MenuItem, useUniqueId } from "./";
13
+ import {
14
+ Button,
15
+ buttonSizeValues,
16
+ buttonVariantValues,
17
+ MenuItem,
18
+ useUniqueId,
19
+ } from "./";
14
20
  import { Divider, ListSubheader, Menu } from "@mui/material";
15
- import { ChevronDownIcon } from "./icons.generated";
21
+ import { ChevronDownIcon, MoreIcon } from "./icons.generated";
16
22
  import { memo, type ReactElement, useCallback, useMemo, useState } from "react";
17
23
 
18
24
  import { MenuContext, MenuContextType } from "./MenuContext";
19
25
  import { NullElement } from "./NullElement";
26
+ import type { SeleniumProps } from "./SeleniumProps";
20
27
 
21
28
  export type MenuButtonProps = {
22
29
  /**
@@ -55,6 +62,14 @@ export type MenuButtonProps = {
55
62
  * The id of the Button
56
63
  */
57
64
  id?: string;
65
+ /**
66
+ * If the MenuButton is an overflow menu or standard menu.
67
+ */
68
+ isOverflow?: boolean;
69
+ /**
70
+ * The size of the button
71
+ */
72
+ size?: (typeof buttonSizeValues)[number];
58
73
  /**
59
74
  * The tooltip text for the Button if it's icon-only
60
75
  */
@@ -75,7 +90,8 @@ export type MenuButtonProps = {
75
90
  ariaLabelledBy: string;
76
91
  buttonLabel?: undefined | "";
77
92
  }
78
- );
93
+ ) &
94
+ SeleniumProps;
79
95
 
80
96
  const MenuButton = ({
81
97
  ariaLabel,
@@ -84,8 +100,11 @@ const MenuButton = ({
84
100
  buttonLabel = "",
85
101
  buttonVariant = "secondary",
86
102
  children,
87
- endIcon = <ChevronDownIcon />,
103
+ endIcon: endIconProp,
88
104
  id: idOverride,
105
+ isOverflow,
106
+ size,
107
+ testId,
89
108
  tooltipText,
90
109
  }: MenuButtonProps) => {
91
110
  const [anchorEl, setAnchorEl] = useState<null | HTMLElement>(null);
@@ -115,6 +134,14 @@ const MenuButton = ({
115
134
  [closeMenu, openMenu]
116
135
  );
117
136
 
137
+ const endIcon = endIconProp ? (
138
+ endIconProp
139
+ ) : isOverflow ? (
140
+ <MoreIcon />
141
+ ) : (
142
+ <ChevronDownIcon />
143
+ );
144
+
118
145
  return (
119
146
  <div>
120
147
  <Button
@@ -124,10 +151,12 @@ const MenuButton = ({
124
151
  ariaDescribedBy={ariaDescribedBy}
125
152
  ariaLabel={ariaLabel}
126
153
  ariaLabelledBy={ariaLabelledBy}
154
+ data-se={testId}
127
155
  endIcon={endIcon}
128
156
  id={`${uniqueId}-button`}
129
157
  label={buttonLabel}
130
158
  onClick={openMenu}
159
+ size={size}
131
160
  tooltipText={tooltipText}
132
161
  variant={buttonVariant}
133
162
  />
package/src/MenuItem.tsx CHANGED
@@ -18,6 +18,7 @@ import { menuItemClasses } from "@mui/material/MenuItem";
18
18
  import { memo, useCallback, useContext, type ReactNode } from "react";
19
19
 
20
20
  import { MenuContext } from "./MenuContext";
21
+ import type { SeleniumProps } from "./SeleniumProps";
21
22
 
22
23
  export type MenuItemProps = {
23
24
  /**
@@ -33,9 +34,9 @@ export type MenuItemProps = {
33
34
  */
34
35
  isSelected?: boolean;
35
36
  /**
36
- * If `true`, the menu item will be visually marked as destructive.
37
+ * If `true`, the menu item will be visually marked as disabled.
37
38
  */
38
- isDestructive?: boolean;
39
+ isDisabled?: boolean;
39
40
  /**
40
41
  * Callback fired when the menu item is clicked.
41
42
  */
@@ -50,13 +51,15 @@ export type MenuItemProps = {
50
51
  * - "destructive": A variant indicating a destructive action.
51
52
  */
52
53
  variant?: "default" | "destructive";
53
- };
54
+ } & SeleniumProps;
54
55
 
55
56
  const MenuItem = ({
56
57
  children,
57
58
  hasInitialFocus,
58
59
  isSelected,
60
+ isDisabled,
59
61
  onClick: onClickProp,
62
+ testId,
60
63
  value,
61
64
  variant = "default",
62
65
  }: MenuItemProps) => {
@@ -74,14 +77,16 @@ const MenuItem = ({
74
77
  <MuiMenuItem
75
78
  /* eslint-disable-next-line jsx-a11y/no-autofocus */
76
79
  autoFocus={hasInitialFocus}
77
- selected={isSelected}
78
- value={value}
79
- onClick={onClick}
80
80
  className={
81
81
  variant === "destructive"
82
82
  ? `${menuItemClasses.root}-destructive`
83
83
  : undefined
84
84
  }
85
+ data-se={testId}
86
+ disabled={isDisabled}
87
+ onClick={onClick}
88
+ selected={isSelected}
89
+ value={value}
85
90
  >
86
91
  {children}
87
92
  </MuiMenuItem>
@@ -15,6 +15,8 @@ import { Select as MuiSelect } from "@mui/material";
15
15
  import { SelectProps as MuiSelectProps } from "@mui/material";
16
16
  import { Field } from "./Field";
17
17
 
18
+ import type { SeleniumProps } from "./SeleniumProps";
19
+
18
20
  export type NativeSelectOption = {
19
21
  text: string;
20
22
  value?: string;
@@ -74,7 +76,7 @@ export type NativeSelectProps = {
74
76
  * The value or values selected in the NativeSelect
75
77
  */
76
78
  value?: string | string[];
77
- };
79
+ } & SeleniumProps;
78
80
 
79
81
  const NativeSelect = forwardRef<HTMLSelectElement, NativeSelectProps>(
80
82
  (
@@ -90,6 +92,7 @@ const NativeSelect = forwardRef<HTMLSelectElement, NativeSelectProps>(
90
92
  onBlur,
91
93
  onChange,
92
94
  onFocus,
95
+ testId,
93
96
  value,
94
97
  children,
95
98
  },
@@ -98,6 +101,7 @@ const NativeSelect = forwardRef<HTMLSelectElement, NativeSelectProps>(
98
101
  const renderFieldComponent = useCallback(
99
102
  () => (
100
103
  <MuiSelect
104
+ data-se={testId}
101
105
  defaultValue={defaultValue}
102
106
  id={idOverride}
103
107
  name={idOverride}
@@ -112,6 +116,7 @@ const NativeSelect = forwardRef<HTMLSelectElement, NativeSelectProps>(
112
116
  />
113
117
  ),
114
118
  [
119
+ children,
115
120
  defaultValue,
116
121
  idOverride,
117
122
  isMultiSelect,
@@ -119,7 +124,7 @@ const NativeSelect = forwardRef<HTMLSelectElement, NativeSelectProps>(
119
124
  onChange,
120
125
  onFocus,
121
126
  ref,
122
- children,
127
+ testId,
123
128
  value,
124
129
  ]
125
130
  );
@@ -24,12 +24,18 @@ import { useUniqueAlphabeticalId } from "./useUniqueAlphabeticalId";
24
24
 
25
25
  export type OdysseyCacheProviderProps = {
26
26
  children: ReactNode;
27
+ /**
28
+ * Emotion renders into this HTML element.
29
+ * When enabling this prop, Emotion renders at the top of this component rather than the bottom like it does in the HTML `<head>`.
30
+ */
31
+ emotionRootElement?: HTMLStyleElement;
27
32
  nonce?: string;
28
33
  stylisPlugins?: StylisPlugin[];
29
34
  };
30
35
 
31
36
  const OdysseyCacheProvider = ({
32
37
  children,
38
+ emotionRootElement,
33
39
  nonce,
34
40
  stylisPlugins,
35
41
  }: OdysseyCacheProviderProps) => {
@@ -38,11 +44,13 @@ const OdysseyCacheProvider = ({
38
44
  const emotionCache = useMemo(
39
45
  () =>
40
46
  createCache({
47
+ container: emotionRootElement,
41
48
  key: uniqueAlphabeticalId,
42
49
  nonce: nonce || window.cspNonce,
50
+ prepend: Boolean(emotionRootElement),
43
51
  stylisPlugins,
44
52
  }),
45
- [nonce, stylisPlugins, uniqueAlphabeticalId]
53
+ [emotionRootElement, nonce, stylisPlugins, uniqueAlphabeticalId]
46
54
  );
47
55
 
48
56
  return <CacheProvider value={emotionCache}>{children}</CacheProvider>;
@@ -11,6 +11,7 @@
11
11
  */
12
12
 
13
13
  import { memo, ReactNode } from "react";
14
+ import { ScopedCssBaseline } from "@mui/material";
14
15
 
15
16
  import {
16
17
  OdysseyCacheProvider,
@@ -34,23 +35,32 @@ export type OdysseyProviderProps = OdysseyCacheProviderProps &
34
35
  const OdysseyProvider = ({
35
36
  children,
36
37
  designTokensOverride,
38
+ emotionRootElement,
39
+ shadowRootElement,
37
40
  languageCode,
38
41
  nonce,
39
42
  stylisPlugins,
40
43
  themeOverride,
41
44
  translationOverrides,
42
45
  }: OdysseyProviderProps) => (
43
- <OdysseyCacheProvider nonce={nonce} stylisPlugins={stylisPlugins}>
46
+ <OdysseyCacheProvider
47
+ emotionRootElement={emotionRootElement}
48
+ nonce={nonce}
49
+ stylisPlugins={stylisPlugins}
50
+ >
44
51
  <OdysseyThemeProvider
45
- themeOverride={themeOverride}
46
52
  designTokensOverride={designTokensOverride}
53
+ shadowRootElement={shadowRootElement}
54
+ themeOverride={themeOverride}
47
55
  >
48
- <OdysseyTranslationProvider
49
- languageCode={languageCode}
50
- translationOverrides={translationOverrides}
51
- >
52
- {children}
53
- </OdysseyTranslationProvider>
56
+ <ScopedCssBaseline>
57
+ <OdysseyTranslationProvider
58
+ languageCode={languageCode}
59
+ translationOverrides={translationOverrides}
60
+ >
61
+ {children}
62
+ </OdysseyTranslationProvider>
63
+ </ScopedCssBaseline>
54
64
  </OdysseyThemeProvider>
55
65
  </OdysseyCacheProvider>
56
66
  );
@@ -16,7 +16,7 @@ import {
16
16
  } from "@mui/material/styles";
17
17
  import { memo, ReactNode, useMemo } from "react";
18
18
 
19
- import { ScopedCssBaseline, ThemeOptions } from "@mui/material";
19
+ import { ThemeOptions } from "@mui/material";
20
20
  import { deepmerge } from "@mui/utils";
21
21
  import { createOdysseyMuiTheme, DesignTokensOverride } from "./theme";
22
22
  import * as Tokens from "@okta/odyssey-design-tokens";
@@ -25,12 +25,14 @@ import { OdysseyDesignTokensContext } from "./OdysseyDesignTokensContext";
25
25
  export type OdysseyThemeProviderProps = {
26
26
  children: ReactNode;
27
27
  designTokensOverride?: DesignTokensOverride;
28
+ shadowRootElement?: HTMLDivElement;
28
29
  themeOverride?: ThemeOptions;
29
30
  };
30
31
 
31
32
  const OdysseyThemeProvider = ({
32
33
  children,
33
34
  designTokensOverride,
35
+ shadowRootElement,
34
36
  themeOverride,
35
37
  }: OdysseyThemeProviderProps) => {
36
38
  const odysseyTokens = useMemo(
@@ -38,8 +40,12 @@ const OdysseyThemeProvider = ({
38
40
  [designTokensOverride]
39
41
  );
40
42
  const odysseyTheme = useMemo(
41
- () => createOdysseyMuiTheme(odysseyTokens),
42
- [odysseyTokens]
43
+ () =>
44
+ createOdysseyMuiTheme({
45
+ odysseyTokens,
46
+ shadowRootElement,
47
+ }),
48
+ [odysseyTokens, shadowRootElement]
43
49
  );
44
50
 
45
51
  const customOdysseyTheme = useMemo(
@@ -49,11 +55,9 @@ const OdysseyThemeProvider = ({
49
55
 
50
56
  return (
51
57
  <MuiThemeProvider theme={customOdysseyTheme ?? odysseyTheme}>
52
- <ScopedCssBaseline>
53
- <OdysseyDesignTokensContext.Provider value={odysseyTokens}>
54
- {children}
55
- </OdysseyDesignTokensContext.Provider>
56
- </ScopedCssBaseline>
58
+ <OdysseyDesignTokensContext.Provider value={odysseyTokens}>
59
+ {children}
60
+ </OdysseyDesignTokensContext.Provider>
57
61
  </MuiThemeProvider>
58
62
  );
59
63
  };
@@ -12,14 +12,14 @@
12
12
 
13
13
  import { render, screen } from "@testing-library/react";
14
14
  import { OdysseyTranslationProvider } from "./OdysseyTranslationProvider";
15
- import i18n from "./OdysseyI18n";
15
+ import { odysseyTranslate } from "./i18n";
16
16
  import { TextField } from "./TextField";
17
17
 
18
18
  describe("OdysseyTranslationProvider", () => {
19
19
  it("defaults to 'en' translation bundle", () => {
20
20
  render(
21
21
  <OdysseyTranslationProvider>
22
- <span>{i18n.t("fieldlabel.optional.text")}</span>
22
+ <span>{odysseyTranslate("fieldlabel.optional.text")}</span>
23
23
  </OdysseyTranslationProvider>
24
24
  );
25
25
 
@@ -14,7 +14,7 @@ import { ReactNode, useEffect } from "react";
14
14
 
15
15
  import { SupportedLanguages } from "./OdysseyTranslationProvider.types";
16
16
 
17
- import i18n, { defaultNS, resources } from "./OdysseyI18n";
17
+ import { i18n, defaultNS, resources } from "./i18n";
18
18
  import { I18nextProvider } from "react-i18next";
19
19
 
20
20
  export type TranslationOverrides = {
@@ -37,6 +37,7 @@ export const supportedLanguages = [
37
37
  "th", // Thai
38
38
  "tr", // Turkish
39
39
  "uk", // Ukrainian
40
+ "vi", // Vietnamese
40
41
  "zh_CN", // Chinese (PRC)
41
42
  "zh_TW", // Chinese
42
43
  ] as const;
@@ -10,7 +10,7 @@
10
10
  * See the License for the specific language governing permissions and limitations under the License.
11
11
  */
12
12
 
13
- import { InputAdornment, InputBase } from "@mui/material";
13
+ import { InputAdornment, InputBase, IconButton } from "@mui/material";
14
14
  import {
15
15
  ChangeEventHandler,
16
16
  FocusEventHandler,
@@ -21,8 +21,9 @@ import {
21
21
  } from "react";
22
22
 
23
23
  import { ShowIcon, HideIcon } from "./icons.generated";
24
- import { Button } from "./Button";
25
24
  import { Field } from "./Field";
25
+ import type { SeleniumProps } from "./SeleniumProps";
26
+ import { useTranslation } from "react-i18next";
26
27
 
27
28
  export type PasswordFieldProps = {
28
29
  /**
@@ -39,6 +40,10 @@ export type PasswordFieldProps = {
39
40
  * If `true`, the component will receive focus automatically.
40
41
  */
41
42
  hasInitialFocus?: boolean;
43
+ /**
44
+ * If `true`, the show/hide icon is not shown to the user
45
+ */
46
+ hasShowPassword?: boolean;
42
47
  /**
43
48
  * The helper text content.
44
49
  */
@@ -63,6 +68,10 @@ export type PasswordFieldProps = {
63
68
  * The label for the `input` element.
64
69
  */
65
70
  label: string;
71
+ /**
72
+ * The name of the `input` element. Defaults to the `id` if not set.
73
+ */
74
+ name?: string;
66
75
  /**
67
76
  * Callback fired when the `input` element loses focus.
68
77
  */
@@ -83,7 +92,7 @@ export type PasswordFieldProps = {
83
92
  * The value of the `input` element, required for a controlled component.
84
93
  */
85
94
  value?: string;
86
- };
95
+ } & SeleniumProps;
87
96
 
88
97
  const PasswordField = forwardRef<HTMLInputElement, PasswordFieldProps>(
89
98
  (
@@ -95,16 +104,20 @@ const PasswordField = forwardRef<HTMLInputElement, PasswordFieldProps>(
95
104
  id: idOverride,
96
105
  isDisabled = false,
97
106
  isOptional = false,
107
+ hasShowPassword = true,
98
108
  isReadOnly,
99
109
  label,
110
+ name: nameOverride,
100
111
  onChange,
101
112
  onFocus,
102
113
  onBlur,
103
114
  placeholder,
115
+ testId,
104
116
  value,
105
117
  },
106
118
  ref
107
119
  ) => {
120
+ const { t } = useTranslation();
108
121
  const [inputType, setInputType] = useState("password");
109
122
 
110
123
  const togglePasswordVisibility = useCallback(() => {
@@ -120,19 +133,26 @@ const PasswordField = forwardRef<HTMLInputElement, PasswordFieldProps>(
120
133
  autoComplete={autoCompleteType}
121
134
  /* eslint-disable-next-line jsx-a11y/no-autofocus */
122
135
  autoFocus={hasInitialFocus}
136
+ data-se={testId}
123
137
  endAdornment={
124
- <InputAdornment position="end">
125
- <Button
126
- ariaLabel="toggle password visibility"
127
- endIcon={inputType === "password" ? <ShowIcon /> : <HideIcon />}
128
- onClick={togglePasswordVisibility}
129
- size="small"
130
- variant="floating"
131
- />
132
- </InputAdornment>
138
+ hasShowPassword && (
139
+ <InputAdornment position="end">
140
+ <IconButton
141
+ aria-label={
142
+ inputType === "password"
143
+ ? t("passwordfield.icon.label.show")
144
+ : t("passwordfield.icon.label.hide")
145
+ }
146
+ onClick={togglePasswordVisibility}
147
+ >
148
+ {inputType === "password" ? <ShowIcon /> : <HideIcon />}
149
+ </IconButton>
150
+ </InputAdornment>
151
+ )
133
152
  }
134
153
  id={id}
135
- name={id}
154
+ inputProps={{ role: "textbox" }}
155
+ name={nameOverride ?? id}
136
156
  onChange={onChange}
137
157
  onFocus={onFocus}
138
158
  onBlur={onBlur}
@@ -147,15 +167,19 @@ const PasswordField = forwardRef<HTMLInputElement, PasswordFieldProps>(
147
167
  [
148
168
  autoCompleteType,
149
169
  hasInitialFocus,
170
+ t,
150
171
  togglePasswordVisibility,
151
172
  inputType,
173
+ nameOverride,
152
174
  onChange,
153
175
  onFocus,
154
176
  onBlur,
155
177
  placeholder,
156
178
  isOptional,
157
179
  isReadOnly,
180
+ hasShowPassword,
158
181
  ref,
182
+ testId,
159
183
  value,
160
184
  ]
161
185
  );
package/src/Radio.tsx CHANGED
@@ -15,6 +15,8 @@ import { memo } from "react";
15
15
 
16
16
  import { FormControlLabel } from "@mui/material";
17
17
 
18
+ import type { SeleniumProps } from "./SeleniumProps";
19
+
18
20
  export type RadioProps = {
19
21
  /**
20
22
  * If `true`, the Radio is selected
@@ -40,7 +42,7 @@ export type RadioProps = {
40
42
  * The value attribute of the Radio
41
43
  */
42
44
  value: string;
43
- };
45
+ } & SeleniumProps;
44
46
 
45
47
  const Radio = ({
46
48
  isChecked,
@@ -48,12 +50,14 @@ const Radio = ({
48
50
  isInvalid,
49
51
  label,
50
52
  name,
53
+ testId,
51
54
  value,
52
55
  }: RadioProps) => (
53
56
  <FormControlLabel
54
57
  checked={isChecked}
55
58
  className={isInvalid ? "Mui-error" : ""}
56
59
  control={<MuiRadio />}
60
+ data-se={testId}
57
61
  disabled={isDisabled}
58
62
  label={label}
59
63
  name={name}
@@ -15,6 +15,7 @@ import { ChangeEventHandler, memo, ReactElement, useCallback } from "react";
15
15
 
16
16
  import { Radio, RadioProps } from "./Radio";
17
17
  import { Field } from "./Field";
18
+ import type { SeleniumProps } from "./SeleniumProps";
18
19
 
19
20
  export type RadioGroupProps = {
20
21
  /**
@@ -34,7 +35,7 @@ export type RadioGroupProps = {
34
35
  */
35
36
  hint?: string;
36
37
  /**
37
- * The id of the `input` element. This will also be the input's `name` field.
38
+ * The id of the `input` element.
38
39
  */
39
40
  id?: string;
40
41
  /**
@@ -45,6 +46,10 @@ export type RadioGroupProps = {
45
46
  * The text label for the RadioGroup
46
47
  */
47
48
  label: string;
49
+ /**
50
+ * The name of the `input` element. Defaults to the `id` if not set.
51
+ */
52
+ name?: string;
48
53
  /**
49
54
  * Listen for changes in the browser that change `value`
50
55
  */
@@ -53,7 +58,7 @@ export type RadioGroupProps = {
53
58
  * The `value` on the selected Radio
54
59
  */
55
60
  value?: RadioProps["value"];
56
- };
61
+ } & SeleniumProps;
57
62
 
58
63
  const RadioGroup = ({
59
64
  children,
@@ -63,23 +68,26 @@ const RadioGroup = ({
63
68
  id: idOverride,
64
69
  isDisabled,
65
70
  label,
71
+ name: nameOverride,
66
72
  onChange,
73
+ testId,
67
74
  value,
68
75
  }: RadioGroupProps) => {
69
76
  const renderFieldComponent = useCallback(
70
77
  ({ ariaDescribedBy, id }) => (
71
78
  <MuiRadioGroup
72
79
  aria-describedby={ariaDescribedBy}
80
+ data-se={testId}
73
81
  defaultValue={defaultValue}
74
82
  id={id}
75
- name={id}
83
+ name={nameOverride ?? id}
76
84
  onChange={onChange}
77
85
  value={value}
78
86
  >
79
87
  {children}
80
88
  </MuiRadioGroup>
81
89
  ),
82
- [children, defaultValue, onChange, value]
90
+ [children, defaultValue, nameOverride, onChange, testId, value]
83
91
  );
84
92
 
85
93
  return (