Skip to content

Commit c10e53c

Browse files
committed
feat: MUI upgrade [wip]
1 parent 5898105 commit c10e53c

58 files changed

Lines changed: 1733 additions & 1202 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

package.json

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -61,12 +61,12 @@
6161
"@businessnjgovnavigator/shared": "*",
6262
"@emotion/react": "11.14.0",
6363
"@emotion/styled": "11.14.1",
64-
"@mui/icons-material": "5.18.0",
65-
"@mui/lab": "5.0.0-alpha.177",
66-
"@mui/material": "5.18.0",
67-
"@mui/styles": "5.18.0",
68-
"@mui/x-date-pickers": "5.0.20",
64+
"@mui/icons-material": "9.0.1",
65+
"@mui/material": "9.0.1",
66+
"@mui/material-pigment-css": "9.0.1",
67+
"@mui/x-date-pickers": "9.4.0",
6968
"@newjersey/njwds": "0.3.0",
69+
"@pigment-css/react": "0.0.31",
7070
"@react-email/components": "1.0.12",
7171
"@react-email/render": "2.0.8",
7272
"@smithy/node-http-handler": "4.8.0",
@@ -135,7 +135,7 @@
135135
"@cypress-audit/pa11y": "1.4.2",
136136
"@jest/globals": "30.1.2",
137137
"@jest/types": "29.6.3",
138-
"@mui/system": "5.18.0",
138+
"@mui/system": "9.0.1",
139139
"@next/bundle-analyzer": "16.2.4",
140140
"@next/eslint-plugin-next": "15.5.15",
141141
"@open_resources/semantic-release-uv": "1.5.1",

web/cypress.config.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
/* global process */
12
import { lighthouse, prepareAudit } from "@cypress-audit/lighthouse";
23
import { pa11y } from "@cypress-audit/pa11y";
34
import { defineConfig } from "cypress";
@@ -43,6 +44,8 @@ export default defineConfig({
4344
});
4445

4546
config = dotenvPlugin(config);
47+
config.env.ADMIN_PASSWORD =
48+
process.env.ADMIN_PASSWORD || config.env.ADMIN_PASSWORD || "Test1!";
4649
return config;
4750
},
4851
baseUrl: "http://localhost:3000",

web/cypress/e2e/deadlinks.spec.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ describe("unusedContent page [feature] [all] [group3]", () => {
1616
it("allows the user to login", () => {
1717
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
1818
cy.get('input[data-testid="mgmt-password-field"]').clear();
19-
cy.get('input[data-testid="mgmt-password-field"]').type("Test1!");
19+
cy.get('input[data-testid="mgmt-password-field"]').type(Cypress.env("ADMIN_PASSWORD"));
2020
cy.get('button[data-testid="mgmt-submit-bttn"]').click();
2121
cy.get('[data-testid="dl-task-header"]').should("exist");
2222
});
@@ -38,7 +38,7 @@ describe("unusedContent page [feature] [all] [group3]", () => {
3838
it("allows the user to login", () => {
3939
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
4040
cy.get('input[data-testid="mgmt-password-field"]').clear();
41-
cy.get('input[data-testid="mgmt-password-field"]').type("Test1!");
41+
cy.get('input[data-testid="mgmt-password-field"]').type(Cypress.env("ADMIN_PASSWORD"));
4242
cy.get('button[data-testid="mgmt-submit-bttn"]').click();
4343
cy.get('[data-testid="dl-task-header"]').should("exist");
4444
});

web/cypress/support/commands.js

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -125,16 +125,23 @@ Cypress.Commands.add("chooseDatePicker", (selector, value) => {
125125
const mobilePickerSelector = `input${selector}[readonly]`;
126126
const isMobile = $body.find(mobilePickerSelector).length > 0;
127127
if (isMobile) {
128-
// The MobileDatePicker component has readonly inputs and needs to
129-
// be opened and clicked on edit so its inputs can be edited
130128
cy.get(mobilePickerSelector).click({ force: true });
131129
cy.get('[role="dialog"] [aria-label="calendar view is open, go to text input view"]').click({
132130
force: true,
133131
});
134132
cy.get(`[role="dialog"] input${selector}`).last().clear({ force: true }).type(value);
135133
cy.contains('[role="dialog"] button', "OK").click({ force: true });
136134
} else {
137-
cy.get(`input${selector} `).clear({ force: true }).type(value).blur();
135+
cy.get(`input${selector}`).then(($input) => {
136+
const nativeInputValueSetter = Object.getOwnPropertyDescriptor(
137+
window.HTMLInputElement.prototype,
138+
"value",
139+
).set;
140+
nativeInputValueSetter.call($input[0], value);
141+
$input[0].dispatchEvent(new Event("input", { bubbles: true }));
142+
$input[0].dispatchEvent(new Event("change", { bubbles: true }));
143+
$input[0].blur();
144+
});
138145
}
139146
});
140147
});

web/cypress/support/helpers/helpers.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -196,6 +196,15 @@ export const completeTaxClearanceFlow = (): void => {
196196
cy.contains("button", "Save & Continue").click();
197197
cy.wait(1000);
198198

199+
cy.get("body").then(($body) => {
200+
if ($body.find("button:contains('Unlink Tax ID')").length > 0) {
201+
cy.contains("button", "Unlink Tax ID").click();
202+
cy.wait(1000);
203+
cy.contains("button", "Save & Continue").click();
204+
cy.wait(1000);
205+
}
206+
});
207+
199208
cy.contains(Config.taxClearanceCertificateDownload.headerTwoLabel, { timeout: 500 })
200209
.should("be.visible")
201210
.and("contain.text", "Your Certificate is Ready!");

web/package.json

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -51,12 +51,12 @@
5151
"@businessnjgovnavigator/shared": "*",
5252
"@emotion/react": "11.14.0",
5353
"@emotion/styled": "11.14.1",
54-
"@mui/icons-material": "5.18.0",
55-
"@mui/lab": "5.0.0-alpha.177",
56-
"@mui/material": "5.18.0",
57-
"@mui/styles": "5.18.0",
58-
"@mui/x-date-pickers": "5.0.20",
54+
"@mui/icons-material": "9.0.1",
55+
"@mui/material": "9.0.1",
56+
"@mui/material-pigment-css": "9.0.1",
57+
"@mui/x-date-pickers": "9.4.0",
5958
"@newjersey/njwds": "0.3.0",
59+
"@pigment-css/react": "0.0.31",
6060
"@types/mdast": "4.0.4",
6161
"aws-amplify": "6.15.8",
6262
"axios": "1.16.0",
@@ -99,7 +99,7 @@
9999
"@cypress-audit/lighthouse": "1.4.2",
100100
"@cypress-audit/pa11y": "1.4.2",
101101
"@jest/types": "29.6.3",
102-
"@mui/system": "5.18.0",
102+
"@mui/system": "9.0.1",
103103
"@next/bundle-analyzer": "16.2.4",
104104
"@next/eslint-plugin-next": "15.5.15",
105105
"@storybook/addon-designs": "11.1.3",

web/setupTests.js

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,8 +54,14 @@ window.matchMedia =
5454
function () {
5555
return {
5656
matches: false,
57+
media: "",
5758
addListener: function () {},
5859
removeListener: function () {},
60+
addEventListener: function () {},
61+
removeEventListener: function () {},
62+
dispatchEvent: function () {
63+
return false;
64+
},
5965
};
6066
};
6167

web/src/components/ArrowTooltip.tsx

Lines changed: 27 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,30 @@
11
import { UnStyledButton } from "@/components/njwds-extended/UnStyledButton";
22
import { MediaQueries } from "@/lib/PageSizes";
33
import analytics from "@/lib/utils/analytics";
4-
import { ClickAwayListener, Theme, Tooltip, TooltipProps, useMediaQuery } from "@mui/material";
5-
import makeStyles from "@mui/styles/makeStyles";
4+
import {
5+
ClickAwayListener,
6+
Tooltip,
7+
tooltipClasses,
8+
TooltipProps,
9+
useMediaQuery,
10+
} from "@mui/material";
11+
import { styled } from "@mui/material/styles";
612
import { ReactElement, useState } from "react";
713

8-
const useStylesBootstrap = makeStyles((theme: Theme) => {
9-
return {
10-
arrow: {
11-
color: theme.palette.common.black,
12-
},
13-
tooltip: {
14-
backgroundColor: theme.palette.common.black,
15-
fontSize: "1em",
16-
padding: ".5em .75em",
17-
},
18-
};
19-
});
14+
const NavigatorTooltip = styled(({ className, ...props }: TooltipProps) => (
15+
<Tooltip {...props} classes={{ popper: className }} />
16+
))(({ theme }) => ({
17+
[`& .${tooltipClasses.arrow}`]: {
18+
color: theme.palette.common.black,
19+
},
20+
[`& .${tooltipClasses.tooltip}`]: {
21+
backgroundColor: theme.palette.common.black,
22+
fontSize: "1em",
23+
padding: ".5em .75em",
24+
},
25+
}));
2026

2127
export const ArrowTooltip = (props: TooltipProps): ReactElement => {
22-
const classes = useStylesBootstrap();
23-
2428
const isMobile = useMediaQuery(MediaQueries.isMobile);
2529

2630
const [open, setOpen] = useState(false);
@@ -30,13 +34,14 @@ export const ArrowTooltip = (props: TooltipProps): ReactElement => {
3034
{isMobile ? (
3135
<ClickAwayListener onClickAway={(): void => setOpen(false)}>
3236
<div className="display-flex">
33-
<Tooltip
37+
<NavigatorTooltip
3438
arrow
3539
enterTouchDelay={0}
36-
classes={classes}
3740
onOpen={analytics.event.tooltip.mouseover.view_tooltip}
38-
PopperProps={{
39-
disablePortal: true,
41+
slotProps={{
42+
popper: {
43+
disablePortal: true,
44+
},
4045
}}
4146
onClose={(): void => setOpen(false)}
4247
open={open}
@@ -50,14 +55,13 @@ export const ArrowTooltip = (props: TooltipProps): ReactElement => {
5055
{props.children}
5156
</UnStyledButton>
5257
</div>
53-
</Tooltip>
58+
</NavigatorTooltip>
5459
</div>
5560
</ClickAwayListener>
5661
) : (
57-
<Tooltip
62+
<NavigatorTooltip
5863
arrow
5964
enterTouchDelay={0}
60-
classes={classes}
6165
{...props}
6266
onOpen={analytics.event.tooltip.mouseover.view_tooltip}
6367
/>

web/src/components/CountryDropdown.tsx

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -112,11 +112,6 @@ export const CountryDropdown = (props: Props): ReactElement => {
112112
id={props.fieldName}
113113
name={props.fieldName}
114114
disabled={props.disabled}
115-
inputProps={{
116-
"aria-label": camelCaseToSentence(props.fieldName),
117-
"data-testid": props.fieldName,
118-
...params.inputProps,
119-
}}
120115
onSubmit={onValidation}
121116
autoComplete={props.autoComplete ? "country" : "no"}
122117
variant="outlined"
@@ -128,6 +123,15 @@ export const CountryDropdown = (props: Props): ReactElement => {
128123
}}
129124
error={props.error}
130125
helperText={props.error && props.validationText}
126+
slotProps={{
127+
...params.slotProps,
128+
129+
htmlInput: {
130+
"aria-label": camelCaseToSentence(props.fieldName),
131+
"data-testid": props.fieldName,
132+
...params.slotProps.htmlInput,
133+
},
134+
}}
131135
/>
132136
);
133137
}}

web/src/components/GenericTextField.tsx

Lines changed: 34 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import {
1414
FocusEvent,
1515
forwardRef,
1616
HTMLInputTypeAttribute,
17+
InputHTMLAttributes,
1718
ReactElement,
1819
RefObject,
1920
useMemo,
@@ -135,7 +136,13 @@ export const GenericTextField = forwardRef(
135136
};
136137
fieldOptions = {
137138
...fieldOptions,
138-
inputProps: { ...fieldOptions?.inputProps, inputMode: "numeric" },
139+
slotProps: {
140+
...fieldOptions?.slotProps,
141+
htmlInput: {
142+
...fieldOptions?.slotProps?.htmlInput,
143+
inputMode: "numeric",
144+
},
145+
},
139146
};
140147
}
141148

@@ -163,6 +170,13 @@ export const GenericTextField = forwardRef(
163170
};
164171

165172
const error = props.error ?? isFormFieldInvalid;
173+
const fieldSlotProps = fieldOptions?.slotProps as
174+
| {
175+
htmlInput?: InputHTMLAttributes<HTMLInputElement>;
176+
input?: Partial<OutlinedInputProps>;
177+
}
178+
| undefined;
179+
166180
return (
167181
<div className={`${widthStyling} ${props.className ?? ""} ${error ? "error" : ""}`}>
168182
<TextField
@@ -179,26 +193,30 @@ export const GenericTextField = forwardRef(
179193
disabled={props.disabled}
180194
{...fieldOptions}
181195
sx={{ width: 1, ...fieldOptions?.sx }}
182-
inputProps={{
183-
readOnly: props.readOnly,
184-
"aria-readonly": props.readOnly,
185-
className: `${props.readOnly ? "bg-base-lightest" : ""}`,
186-
...fieldOptions?.inputProps,
187-
"aria-label": props.ariaLabel ?? camelCaseToSentence(props.fieldName),
188-
tabIndex: 0,
189-
}}
190-
InputProps={{
191-
readOnly: props.readOnly,
192-
"aria-readonly": props.readOnly,
193-
className: `${props.readOnly ? "bg-base-lightest" : ""}`,
194-
...props.inputProps,
195-
}}
196196
required={props.required}
197197
type={props.type}
198198
onFocus={props.onFocus}
199199
onKeyDown={props.onKeyDown}
200+
slotProps={{
201+
...fieldSlotProps,
202+
input: {
203+
...fieldSlotProps?.input,
204+
readOnly: props.readOnly,
205+
"aria-readonly": props.readOnly,
206+
className: `${props.readOnly ? "bg-base-lightest" : ""}`,
207+
...props.inputProps,
208+
},
209+
210+
htmlInput: {
211+
...fieldSlotProps?.htmlInput,
212+
readOnly: props.readOnly,
213+
"aria-readonly": props.readOnly,
214+
className: `${props.readOnly ? "bg-base-lightest" : ""}`,
215+
"aria-label": props.ariaLabel ?? camelCaseToSentence(props.fieldName),
216+
tabIndex: 0,
217+
},
218+
}}
200219
/>
201-
202220
<div aria-live="polite" className="screen-reader-only">
203221
{error && (
204222
<div>{`${

0 commit comments

Comments
 (0)