From 1a26c8f38fe19567224814161ac964cadb1087ea Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 30 May 2024 16:59:50 -0400 Subject: [PATCH 1/5] chore(deps): Bump playwright from v1.44.0-focal to v1.44.1-focal (#7342) Bumps playwright from v1.44.0-focal to v1.44.1-focal. [![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=playwright&package-manager=docker&previous-version=v1.44.0-focal&new-version=v1.44.1-focal)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores) Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. [//]: # (dependabot-automerge-start) [//]: # (dependabot-automerge-end) ---
Dependabot commands and options
You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot merge` will merge this PR after your CI passes on it - `@dependabot squash and merge` will squash and merge this PR after your CI passes on it - `@dependabot cancel merge` will cancel a previously requested merge and block automerging - `@dependabot reopen` will reopen this PR if it is closed - `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually - `@dependabot show ignore conditions` will show all of the ignore conditions of the specified dependency - `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
--------- Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Anjali Singh --- .github/workflows/ci.yml | 2 +- Dockerfile | 2 +- package.json | 2 +- yarn.lock | 20 ++++++++++---------- 4 files changed, 13 insertions(+), 13 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 817b2938451..a1f58889ce2 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -161,7 +161,7 @@ jobs: name: e2e-web-tests (${{ matrix.shard-index }}/${{ strategy.job-total }}) runs-on: ubuntu-20.04 # We need to update this each time we update playwright - container: mcr.microsoft.com/playwright:v1.44.0-focal + container: mcr.microsoft.com/playwright:v1.44.1-focal strategy: fail-fast: false matrix: diff --git a/Dockerfile b/Dockerfile index 6376adeb2f1..9c39b9a9392 100644 --- a/Dockerfile +++ b/Dockerfile @@ -5,7 +5,7 @@ # reference: https://stackoverflow.com/a/51683309/3711475 # reference: https://github.com/GoogleChrome/puppeteer/blob/master/docs/troubleshooting.md#running-puppeteer-in-docker -FROM mcr.microsoft.com/playwright:v1.44.0-focal AS setup +FROM mcr.microsoft.com/playwright:v1.44.1-focal AS setup USER root diff --git a/package.json b/package.json index b40e036263c..ca946437c61 100644 --- a/package.json +++ b/package.json @@ -129,7 +129,7 @@ "license-check-and-add": "^4.0.5", "mini-css-extract-plugin": "2.9.0", "npm-run-all": "^4.1.5", - "playwright": "^1.44.0", + "playwright": "^1.44.1", "postcss": "^8.4.35", "postcss-modules": "^6.0.0", "prettier": "^3.2.5", diff --git a/yarn.lock b/yarn.lock index bfb76bd927e..2379603431d 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3354,7 +3354,7 @@ __metadata: luxon: ^3.4.4 mini-css-extract-plugin: 2.9.0 npm-run-all: ^4.1.5 - playwright: ^1.44.0 + playwright: ^1.44.1 postcss: ^8.4.35 postcss-modules: ^6.0.0 prettier: ^3.2.5 @@ -10673,27 +10673,27 @@ __metadata: languageName: node linkType: hard -"playwright-core@npm:1.44.0": - version: 1.44.0 - resolution: "playwright-core@npm:1.44.0" +"playwright-core@npm:1.44.1": + version: 1.44.1 + resolution: "playwright-core@npm:1.44.1" bin: playwright-core: cli.js - checksum: 7bee257c830153578753a6dfb34b8216f8c552d750e24a0be6d3ba10baff013fb1320a1c3d487fbb0df9d1ce5d1f027ccf6e990d4514989da63691f177141ba4 + checksum: ebc6fa0ff77792fe52648fda06cc4474d4e9746db6dc5750d262b7fe2caf9f9e2327a71f1fb365e862213403a9daf95361c5040a9b0fd462928d7eb4fdc760e1 languageName: node linkType: hard -"playwright@npm:^1.44.0": - version: 1.44.0 - resolution: "playwright@npm:1.44.0" +"playwright@npm:^1.44.1": + version: 1.44.1 + resolution: "playwright@npm:1.44.1" dependencies: fsevents: 2.3.2 - playwright-core: 1.44.0 + playwright-core: 1.44.1 dependenciesMeta: fsevents: optional: true bin: playwright: cli.js - checksum: 22653ded652f436c1a837842009a175e8acb91ab340bb3deee87dbdb7205b439bd174f5f20591eb67f0171728c9f8f4bdfa3668a517da6bc7b45a4a79eabdbd5 + checksum: c2e8ff0a855e4a9e665ae5ffa0ff90423289546157be55e83f78916d17075c5910a7244773739c2a973da884a4ff0b3cf9b6e6b543de112e43b12169a9208e86 languageName: node linkType: hard From 9ee52e9f589f811185e88a669dd4fde4b3266713 Mon Sep 17 00:00:00 2001 From: v-rakeshsh <155614445+v-rakeshsh@users.noreply.github.com> Date: Sat, 15 Jun 2024 01:28:19 +0530 Subject: [PATCH 2/5] feat(react 18): upgrade to react 18. (#7336) #### Details This feature updates below packages. 1. react from v16 to v18. 2. react-dom from v16 to v18. 3. @types-react from v16 to v18. 4. @types-react-dom from v16 to v18. 5. @testing-library/react from v12 to v15. 6. @fluentui/react from v8.x.x to v8.118.1. 7. Removed react-helmet and added react-helmet-async. **1. Notable changes for react, react-dom:** **Motivation:** React 18 introduces a new root API which provides better ergonomics for managing roots. The new root API also enables the new concurrent renderer, which allows you to opt-into concurrent features. **In V16, we had below to render the component:** import { render } from 'react-dom'; const container = document.getElementById('app'); render(, container); - **In V18, we have below to render the component:** import { createRoot } from 'react-dom/client'; const container = document.getElementById('app'); const root = createRoot(container); // createRoot(container!) if you use TypeScript root.render(); **2. Notable changes for @types-react and @types-react-dom:** **Motivation:** The new types are safer and catch issues that used to be ignored by the type checker. The most notable change is that the children prop now needs to be listed explicitly when defining props - In old we have below WrappedComponent: React.ComponentType

, - In new we have below WrappedComponent: React.ComponentType<**React.PropsWithChildren

**>, **Approach for type changes:** So this Type changes are added using automation script https://github.com/eps1lon/types-react-codemod. This automation script is suggested in react18 migration document. - Added new package types-react-codemod. - After adding the package, executed yarn types-react-codemod preset-18 ./src in root, and then selected all option from the list of options. - This will transform all types of component type having child components to >. **3. Notable changes for @testing-library/react:** - Current version of @testing-library/react does not support react18, so from v13.x.x, react18 support is added. So updated to latest V15. For reference - https://github.com/testing-library/react-testing-library/releases/tag/v13.0.0 - Wrapped state updates/async operations under act. - Updated test cases with createRoot for createRootMock instead of render and renderMock. - **4. Notable changes for @fluentui/react from v8.x.x to v8.118.1** - Existing fluent ui version does not support react18, test cases were failing, hence after checking v8.118.1 documentation, it supports react and react-dom v18. Hence upadated. **5. Notable changes for react-helmet-async:** - Current react-helmet package throws error 'objects cannot be child, expected elements', for react18, Hence as alternative used react-helmet-async. For reference https://www.npmjs.com/package/react-helmet-async?activeTab=readme because react-helmet-async uses react18 as dependency. - Wrapped Helmet provider for root, as to pass context of react-helmet-async. - Created a variable to store data, and then this data was passed as JSX, instead of passing the data as it is. Because it will throw **"Objects cannot be used as react elements"**. **For example:** `export const GuidanceTitle = NamedFC('GuidanceTitle', ({ name }) => { const titleValue = `Guidance for ${name} - ${productName}`; return ( <> {titleValue}

{name}

); });` **6. Along with above** - Made changes to mock helpers, because after react18 changes, the JSON structure of component was coming differently, so accordingly corrected the helpers, to get proper component name for snapshots. - Updated snapshots, because as we are using latest Fluent UI version, new props are introduced which can be seen in snapshots. - Refactored few test cases, which were wrong logically, like for example: using of mockReactComponents in global and inside test case using of useOriginalComponents to get the props using getMockComponentClassPropsForCall which was wrong logically is fixed to use any one approach. - Updated report package with react, react-dom v18 to keep in sync with AI web. ##### Context This PR includes all changes required for migration of AI web from react16 to react18. It includes test cases fixes. It includes lint issues fixes. #### Pull request checklist - [ ] Addresses an existing issue: #0000 - [x] Ran `yarn fastpass` - [x] Added/updated relevant unit test(s) (and ran `yarn test`) - [x] Verified code coverage for the changes made. Check coverage report at: `/test-results/unit/coverage` - [x] PR title *AND* final merge commit title both start with a semantic tag (`fix:`, `chore:`, `feat(feature-name):`, `refactor:`). See `CONTRIBUTING.md`. - [ ] (UI changes only) Added screenshots/GIFs to description above - [x] (UI changes only) Verified usability with NVDA/JAWS --------- Co-authored-by: Jeevani Chinthala Co-authored-by: JeevaniChinthala <148259226+JeevaniChinthala@users.noreply.github.com> Co-authored-by: v-sharmachir Co-authored-by: Chirag Sharma <150002431+v-sharmachir@users.noreply.github.com> Co-authored-by: Saanica Ghate <148259220+SaanicaG@users.noreply.github.com> Co-authored-by: Saanica Ghate --- package.json | 14 +- packages/report/package.json | 8 +- packages/ui/package.json | 6 +- .../components/assessment-instance-table.tsx | 4 +- src/DetailsView/details-view-initializer.ts | 10 +- src/DetailsView/details-view-renderer.tsx | 11 +- .../no-content-available-view-renderer.tsx | 10 +- .../common/property-bag-column-renderer.tsx | 3 +- .../components/with-store-subscription.tsx | 2 +- .../extensibility/react-extension-point.tsx | 10 +- src/common/react/named-fc.ts | 6 +- src/common/types/link-component-type.ts | 2 +- .../initializer/debug-tools-init.tsx | 6 +- src/injected/dialog-renderer-impl.tsx | 9 +- .../visualization/issues-formatter.ts | 4 +- .../components/diagnostic-view-toggle.tsx | 2 +- src/popup/incompatible-browser-renderer.tsx | 11 +- src/popup/main-renderer.tsx | 11 +- src/popup/popup-initializer.ts | 9 +- .../types/report-export-service.ts | 2 +- src/reports/components/head.tsx | 5 +- .../components/report-instance-list.tsx | 8 +- .../components/summary-report-head.tsx | 3 +- .../settings-drop-down.test.ts.snap | 1 + .../preview-features.test.ts.snap | 1 + .../__snapshots__/settings-panel.test.ts.snap | 4 +- .../first-time-dialog.test.ts.snap | 1 + .../__snapshots__/hamburger-menu.test.ts.snap | 2 + .../unit/mock-helpers/mock-module-helpers.tsx | 22 +- ...uto-detected-failures-dialog.test.tsx.snap | 117 +- .../__snapshots__/export-dialog.test.tsx.snap | 12 +- .../export-dropdown.test.tsx.snap | 20 +- ...valid-load-assessment-dialog.test.tsx.snap | 4 +- .../issue-filing-dialog.test.tsx.snap | 36 +- .../next-requirement-button.test.tsx.snap | 21 +- .../start-over-dropdown.test.tsx.snap | 8 +- .../__snapshots__/switcher.test.tsx.snap | 2 +- ...nstances-collapsible-content.test.tsx.snap | 12 +- .../target-change-dialog.test.tsx.snap | 40 +- .../assessment-instance-table.test.tsx | 28 +- .../auto-detected-failures-dialog.test.tsx | 26 +- .../choice-group-pass-fail.test.tsx | 7 +- .../details-view-command-bar.test.tsx | 29 +- ...ils-view-content-with-local-state.test.tsx | 8 +- .../components/export-dialog.test.tsx | 5 +- .../failure-instance-panel-control.test.tsx | 18 +- .../components/generic-dialog.test.tsx | 8 +- .../invalid-load-assessment-dialog.test.tsx | 6 +- .../components/issue-filing-dialog.test.tsx | 28 +- .../next-requirement-button.test.tsx | 6 +- ...quick-assess-to-assessment-dialog.test.tsx | 5 +- .../report-export-component.test.tsx | 12 +- ...restart-scan-visual-helper-toggle.test.tsx | 2 +- .../save-assessment-button.test.tsx | 32 +- .../components/start-over-dropdown.test.tsx | 62 +- .../DetailsView/components/switcher.test.tsx | 12 +- ...ent-instances-collapsible-content.test.tsx | 16 + .../details-view-renderer.test.tsx | 30 +- ...o-content-available-view-renderer.test.tsx | 32 +- .../telemetry-permission-dialog.test.tsx.snap | 6 +- .../components/selector-input-list.test.tsx | 11 +- .../telemetry-permission-dialog.test.tsx | 10 +- .../tests/common/components/toast.test.tsx | 7 +- .../with-store-subscription.test.tsx | 10 +- src/tests/unit/tests/content/index.test.tsx | 5 + .../__snapshots__/stores-tree.test.tsx.snap | 6 +- .../telemetry-viewer.test.tsx | 17 +- .../components/details-dialog.test.tsx | 3 +- .../injected/dialog-renderer-impl.test.tsx | 46 +- .../azure-boards-settings-form.test.tsx.snap | 8 +- .../launch-panel-header.test.tsx.snap | 380 +- .../diagnostic-view-toggle.test.tsx | 89 +- .../components/launch-panel-header.test.tsx | 17 +- .../incompatible-browser-renderer.test.tsx | 24 +- .../unit/tests/popup/main-renderer.test.tsx | 26 +- .../reports/components/inline-image.test.tsx | 5 +- .../guidance-title.test.tsx.snap | 5 +- .../__snapshots__/markup.test.tsx.snap | 5 +- .../views/content/guidance-title.test.tsx | 5 +- .../unit/tests/views/content/markup.test.tsx | 4 +- .../tests/views/insights/renderer.test.tsx | 13 +- src/views/content/content-page.tsx | 11 +- src/views/content/guidance-title.tsx | 23 +- src/views/content/markup.tsx | 51 +- src/views/insights/initializer.ts | 4 +- src/views/insights/insights-router.tsx | 2 +- src/views/insights/renderer.tsx | 19 +- yarn.lock | 6203 +++++++---------- 88 files changed, 3073 insertions(+), 4773 deletions(-) diff --git a/package.json b/package.json index ca946437c61..3c9080a1cdc 100644 --- a/package.json +++ b/package.json @@ -79,15 +79,15 @@ "@swc/core": "^1.3.107", "@swc/jest": "^0.2.36", "@testing-library/jest-dom": "^6.4.2", - "@testing-library/react": "12.1.2", + "@testing-library/react": "^15.0.5", "@types/chrome": "0.0.260", "@types/jest": "^29.5.11", "@types/jsdom": "^21.1.6", "@types/lodash": "^4.14.202", "@types/luxon": "^3.4.2", "@types/node": "^16.11.7", - "@types/react": "^16.14.25", - "@types/react-dom": "^16.9.15", + "@types/react": "^18.3.1", + "@types/react-dom": "^18.3.0", "@types/react-helmet": "^6.1.11", "@types/react-router-dom": "^5.3.3", "@types/serve-static": "^1.15.5", @@ -151,7 +151,7 @@ "webpack-node-externals": "^3.0.0" }, "dependencies": { - "@fluentui/react": "^8.96.1", + "@fluentui/react": "^8.118.1", "@microsoft/applicationinsights-web": "^2.8.15", "@testing-library/user-event": "^14.5.2", "ajv": "^8.12.0", @@ -160,9 +160,9 @@ "idb-keyval": "^6.2.1", "lodash": "^4.17.21", "luxon": "^3.4.4", - "react": "^16.14.0", - "react-dom": "^16.14.0", - "react-helmet": "^6.1.0", + "react": "^18.3.1", + "react-dom": "^18.3.1", + "react-helmet-async": "^2.0.5", "react-resize-detector": "^9.1.1", "react-router-dom": "^6.21.3", "tabbable": "^6.2.0", diff --git a/packages/report/package.json b/packages/report/package.json index 6bfc40d9fb7..56b8497ad2e 100644 --- a/packages/report/package.json +++ b/packages/report/package.json @@ -18,14 +18,14 @@ "url": "https://github.com/Microsoft/accessibility-insights-web" }, "dependencies": { - "@fluentui/react": "^8.96.1", + "@fluentui/react": "^8.118.1", "axe-core": "4.8.4", "classnames": "^2.5.1", "lodash": "^4.17.21", "luxon": "^3.4.4", - "react": "^16.14.0", - "react-dom": "^16.14.0", - "react-helmet": "^6.1.0", + "react": "^18.3.1", + "react-dom": "^18.3.1", + "react-helmet-async": "^2.0.5", "uuid": "^9.0.1" } } diff --git a/packages/ui/package.json b/packages/ui/package.json index a972de8848a..c44dc002fa1 100644 --- a/packages/ui/package.json +++ b/packages/ui/package.json @@ -22,9 +22,9 @@ "classnames": "^2.5.1", "lodash": "^4.17.21", "luxon": "^3.4.4", - "react": "^16.14.0", - "react-dom": "^16.14.0", - "react-helmet": "^6.1.0", + "react": "^18.3.1", + "react-dom": "^18.3.1", + "react-helmet-async": "^2.0.5", "react-resize-detector": "^9.1.1", "uuid": "^9.0.1" } diff --git a/src/DetailsView/components/assessment-instance-table.tsx b/src/DetailsView/components/assessment-instance-table.tsx index 4221b444ad6..c3fd59b0136 100644 --- a/src/DetailsView/components/assessment-instance-table.tsx +++ b/src/DetailsView/components/assessment-instance-table.tsx @@ -14,7 +14,7 @@ import { AssessmentDefaultMessageGenerator } from 'assessments/assessment-defaul import { InstanceTableHeaderType, InstanceTableRow } from 'assessments/types/instance-table-data'; import { InsightsCommandButton } from 'common/components/controls/insights-command-button'; import { ManualTestStatus } from 'common/types/store-data/manual-test-status'; -import { has } from 'lodash'; +import { hasIn } from 'lodash'; import * as React from 'react'; import { AssessmentNavState, @@ -137,7 +137,7 @@ export class AssessmentInstanceTable extends React.Component - has(item.instance.testStepResults, step) && + hasIn(item.instance.testStepResults, step) && item.instance.testStepResults[step].status === ManualTestStatus.UNKNOWN, ); } diff --git a/src/DetailsView/details-view-initializer.ts b/src/DetailsView/details-view-initializer.ts index 3de773bb90b..1659240f78d 100644 --- a/src/DetailsView/details-view-initializer.ts +++ b/src/DetailsView/details-view-initializer.ts @@ -81,7 +81,7 @@ import { TabStopsFailedCounterIncludingNoInstance, TabStopsFailedCounterInstancesOnly, } from 'DetailsView/tab-stops-failed-counter'; -import * as ReactDOM from 'react-dom'; +import * as ReactDOMClient from 'react-dom/client'; import { ReportExportServiceProviderImpl } from 'report-export/report-export-service-provider-impl'; import { AssessmentJsonExportGenerator } from 'reports/assessment-json-export-generator'; import { AssessmentReportHtmlGenerator } from 'reports/assessment-report-html-generator'; @@ -735,7 +735,7 @@ if (tabId != null) { const renderer = new DetailsViewRenderer( deps, dom, - ReactDOM.render, + ReactDOMClient.createRoot, documentElementSetter, ); @@ -751,7 +751,7 @@ if (tabId != null) { .catch(() => { const renderer = createNullifiedRenderer( document, - ReactDOM.render, + ReactDOMClient.createRoot, createDefaultLogger(), ); renderer.render(); @@ -760,7 +760,7 @@ if (tabId != null) { function createNullifiedRenderer( doc: Document, - render: typeof ReactDOM.render, + createRoot: typeof ReactDOMClient.createRoot, logger: Logger, ): NoContentAvailableViewRenderer { // using an instance of an actual store (instead of a StoreProxy) so we can get the default state. @@ -773,5 +773,5 @@ function createNullifiedRenderer( getNarrowModeThresholds: getNarrowModeThresholdsForWeb, }; - return new NoContentAvailableViewRenderer(deps, doc, render, documentElementSetter); + return new NoContentAvailableViewRenderer(deps, doc, createRoot, documentElementSetter); } diff --git a/src/DetailsView/details-view-renderer.tsx b/src/DetailsView/details-view-renderer.tsx index c241ce2ca7d..9873562059f 100644 --- a/src/DetailsView/details-view-renderer.tsx +++ b/src/DetailsView/details-view-renderer.tsx @@ -1,7 +1,7 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. import * as React from 'react'; -import * as ReactDOM from 'react-dom'; +import * as ReactDOMClient from 'react-dom/client'; import { Theme, ThemeDeps } from '../common/components/theme'; import { config } from '../common/configuration'; import { DocumentManipulator } from '../common/document-manipulator'; @@ -12,21 +12,20 @@ export class DetailsViewRenderer { constructor( private readonly deps: DetailsViewRendererDeps, private readonly dom: Document, - private readonly renderer: typeof ReactDOM.render, + private readonly createRoot: typeof ReactDOMClient.createRoot, private readonly documentManipulator: DocumentManipulator, ) {} public render(): void { - const detailsViewContainer = this.dom.querySelector('#details-container'); + const detailsViewContainer = this.dom.querySelector('#details-container') as Element; const iconPath = '../' + config.getOption('icon128'); this.documentManipulator.setShortcutIcon(iconPath); - - this.renderer( + const root = this.createRoot(detailsViewContainer); + root.render( <> , - detailsViewContainer, ); } } diff --git a/src/DetailsView/no-content-available-view-renderer.tsx b/src/DetailsView/no-content-available-view-renderer.tsx index 310af14edd1..5114ffc414d 100644 --- a/src/DetailsView/no-content-available-view-renderer.tsx +++ b/src/DetailsView/no-content-available-view-renderer.tsx @@ -6,22 +6,22 @@ import { NoContentAvailableViewDeps, } from 'DetailsView/components/no-content-available/no-content-available-view'; import * as React from 'react'; -import * as ReactDOM from 'react-dom'; +import * as ReactDOMClient from 'react-dom/client'; import { config } from '../common/configuration'; export class NoContentAvailableViewRenderer { constructor( private readonly deps: NoContentAvailableViewDeps, private readonly dom: Document, - private readonly renderer: typeof ReactDOM.render, + private readonly createRoot: typeof ReactDOMClient.createRoot, private readonly documentManipulator: DocumentManipulator, ) {} public render(): void { - const detailsViewContainer = this.dom.querySelector('#details-container'); + const detailsViewContainer = this.dom.querySelector('#details-container') as Element; const iconPath = '../' + config.getOption('icon128'); this.documentManipulator.setShortcutIcon(iconPath); - - this.renderer(, detailsViewContainer); + const root = this.createRoot(detailsViewContainer); + root.render(); } } diff --git a/src/assessments/common/property-bag-column-renderer.tsx b/src/assessments/common/property-bag-column-renderer.tsx index ed521bd1751..2695b4c60aa 100644 --- a/src/assessments/common/property-bag-column-renderer.tsx +++ b/src/assessments/common/property-bag-column-renderer.tsx @@ -50,7 +50,8 @@ export function propertyBagColumnRenderer( propertyMap: DictionaryStringTo, ) => { if (isEmpty(propertyMap)) { - return {config.defaultValue}; + const value: any = config.defaultValue; + return {value}; } return Object.keys(propertyMap).map(key => { diff --git a/src/common/components/with-store-subscription.tsx b/src/common/components/with-store-subscription.tsx index 446254fad96..82e9f044577 100644 --- a/src/common/components/with-store-subscription.tsx +++ b/src/common/components/with-store-subscription.tsx @@ -14,7 +14,7 @@ export type WithStoreSubscriptionDeps = { }; export function withStoreSubscription

, S>( - WrappedComponent: React.ComponentType

, + WrappedComponent: React.ComponentType>, ): React.ComponentClass>, Partial> & { displayName: string; } { diff --git a/src/common/extensibility/react-extension-point.tsx b/src/common/extensibility/react-extension-point.tsx index 938865a3207..77f057164db 100644 --- a/src/common/extensibility/react-extension-point.tsx +++ b/src/common/extensibility/react-extension-point.tsx @@ -20,14 +20,14 @@ type ExtensionPoint = { apply: (component: C) => Extension; }; -type ReactExtension

= Extension> & { +type ReactExtension

= Extension>> & { extensionType: 'reactComponent'; }; -type ReactExtensionPoint

= ExtensionPoint> & { +type ReactExtensionPoint

= ExtensionPoint>> & { extensionType: 'reactComponent'; - create: (component: React.FC

) => ReactExtension

; - component: React.FC

; + create: (component: React.FC>) => ReactExtension

; + component: React.FC>; }; function isReactExtension(extension: Extension): extension is ReactExtension { @@ -55,7 +55,7 @@ export function reactExtensionPoint

( return result; }); - function create(extensionComponent: React.FC

): ReactExtension

{ + function create(extensionComponent: React.FC>): ReactExtension

{ const Wrap = extensionComponent; const wrapComponent = NamedFC

(extensionPointKey, props => ); wrapComponent.displayName = extensionPointKey; diff --git a/src/common/react/named-fc.ts b/src/common/react/named-fc.ts index ae9371169c8..508160c9e0b 100644 --- a/src/common/react/named-fc.ts +++ b/src/common/react/named-fc.ts @@ -2,11 +2,13 @@ // Licensed under the MIT License. import * as React from 'react'; -export type ReactFCWithDisplayName

= React.FC

& { displayName: string }; +export type ReactFCWithDisplayName

= React.FC> & { + displayName: string; +}; export function NamedFC

( displayName: string, - component: React.FC

, + component: React.FC>, ): ReactFCWithDisplayName

{ component.displayName = displayName; diff --git a/src/common/types/link-component-type.ts b/src/common/types/link-component-type.ts index 2029ba881f4..0f893e9c970 100644 --- a/src/common/types/link-component-type.ts +++ b/src/common/types/link-component-type.ts @@ -2,4 +2,4 @@ // Licensed under the MIT License. import { ILinkProps } from '@fluentui/react'; -export type LinkComponentType = React.FC; +export type LinkComponentType = React.FC>; diff --git a/src/debug-tools/initializer/debug-tools-init.tsx b/src/debug-tools/initializer/debug-tools-init.tsx index e17f0bebd39..35d26607370 100644 --- a/src/debug-tools/initializer/debug-tools-init.tsx +++ b/src/debug-tools/initializer/debug-tools-init.tsx @@ -30,7 +30,7 @@ import { defaultDateFormatter } from 'debug-tools/components/telemetry-viewer/te import { TelemetryListener } from 'debug-tools/controllers/telemetry-listener'; import { DebugToolsNavStore } from 'debug-tools/stores/debug-tools-nav-store'; import * as React from 'react'; -import * as ReactDOM from 'react-dom'; +import { createRoot } from 'react-dom/client'; import UAParser from 'ua-parser-js'; export const initializeDebugTools = () => { @@ -108,8 +108,8 @@ const createStoreProxies = (storeUpdateMessageHub: StoreUpdateMessageHub) => { const render = (deps: DebugToolsViewDeps) => { const container = document.querySelector('#debug-tools-container'); - - ReactDOM.render(, container); + const root = createRoot(container); + root.render(); }; initializeDebugTools(); diff --git a/src/injected/dialog-renderer-impl.tsx b/src/injected/dialog-renderer-impl.tsx index 0a129a9a2de..8a51edfb036 100644 --- a/src/injected/dialog-renderer-impl.tsx +++ b/src/injected/dialog-renderer-impl.tsx @@ -26,7 +26,7 @@ import { IssueFilingUrlStringUtils } from 'issue-filing/common/issue-filing-url- import { PlainTextFormatter } from 'issue-filing/common/markup/plain-text-formatter'; import { AxeResultToIssueFilingDataConverter } from 'issue-filing/rule-result-to-issue-filing-data'; import * as React from 'react'; -import * as ReactDOM from 'react-dom'; +import * as ReactDOMClient from 'react-dom/client'; import { Target } from 'scanner/iruleresults'; import { DictionaryStringTo } from 'types/common-types'; import { rootContainerId } from './constants'; @@ -43,7 +43,7 @@ export class DialogRendererImpl implements DialogRenderer { constructor( private readonly dom: Document, - private readonly renderer: typeof ReactDOM.render, + private readonly createRoot: typeof ReactDOMClient.createRoot, private readonly frameMessenger: SingleFrameMessenger, private readonly htmlElementUtils: HTMLElementUtils, private readonly windowUtils: WindowUtils, @@ -101,8 +101,8 @@ export class DialogRendererImpl implements DialogRenderer { userConfigMessageCreator: mainWindowContext.getUserConfigMessageCreator(), LinkComponent: NewTabLink, }; - - this.renderer( + const root = this.createRoot(dialogContainer); + root.render( , - dialogContainer, ); return null; } else { diff --git a/src/injected/visualization/issues-formatter.ts b/src/injected/visualization/issues-formatter.ts index c3d1fd07fc5..3f60b35ddd2 100644 --- a/src/injected/visualization/issues-formatter.ts +++ b/src/injected/visualization/issues-formatter.ts @@ -5,7 +5,7 @@ import { NavigatorUtils } from 'common/navigator-utils'; import { HtmlElementAxeResults } from 'common/types/store-data/visualization-scan-result-data'; import { DialogRendererImpl } from 'injected/dialog-renderer-impl'; import { SingleFrameMessenger } from 'injected/frameCommunicators/single-frame-messenger'; -import * as ReactDOM from 'react-dom'; +import * as ReactDOMClient from 'react-dom/client'; import { BrowserAdapter } from '../../common/browser-adapters/browser-adapter'; import { HTMLElementUtils } from '../../common/html-element-utils'; @@ -31,7 +31,7 @@ export class IssuesFormatter implements Formatter { ) { this.dialogRenderer = new DialogRendererImpl( document, - ReactDOM.render, + ReactDOMClient.createRoot, frameMessenger, htmlElementUtils, windowUtils, diff --git a/src/popup/components/diagnostic-view-toggle.tsx b/src/popup/components/diagnostic-view-toggle.tsx index 21d1efc2b0a..4e9687d19d4 100644 --- a/src/popup/components/diagnostic-view-toggle.tsx +++ b/src/popup/components/diagnostic-view-toggle.tsx @@ -46,7 +46,7 @@ export class DiagnosticViewToggle extends React.Component< // Must be consistent with internal react naming for same property to work // tslint:disable-next-line: variable-name - private _isMounted: boolean; + protected _isMounted: boolean; constructor(props: DiagnosticViewToggleProps) { super(props); diff --git a/src/popup/incompatible-browser-renderer.tsx b/src/popup/incompatible-browser-renderer.tsx index d13ac115fe2..c3772132657 100644 --- a/src/popup/incompatible-browser-renderer.tsx +++ b/src/popup/incompatible-browser-renderer.tsx @@ -2,21 +2,21 @@ // Licensed under the MIT License. import { title } from 'content/strings/application'; import * as React from 'react'; -import ReactDOM from 'react-dom'; +import * as ReactDOMClient from 'react-dom/client'; import { NewTabLink } from '../common/components/new-tab-link'; import { Header } from './components/header'; export class IncompatibleBrowserRenderer { constructor( - private readonly renderer: typeof ReactDOM.render, + private readonly createRoot: typeof ReactDOMClient.createRoot, private readonly dom: Document, ) {} public render(): void { - const container = this.dom.querySelector('#popup-container'); - - this.renderer( + const container = this.dom.querySelector('#popup-container') as Element; + const root = this.createRoot(container); + root.render( <>

@@ -38,7 +38,6 @@ export class IncompatibleBrowserRenderer {
, - container, ); } } diff --git a/src/popup/main-renderer.tsx b/src/popup/main-renderer.tsx index 053a147bad5..b34f0fec8f6 100644 --- a/src/popup/main-renderer.tsx +++ b/src/popup/main-renderer.tsx @@ -2,7 +2,7 @@ // Licensed under the MIT License. import { title } from 'content/strings/application'; import * as React from 'react'; -import * as ReactDOM from 'react-dom'; +import * as ReactDOMClient from 'react-dom/client'; import { Theme, ThemeDeps, ThemeInnerState } from '../common/components/theme'; import { WithStoreSubscriptionDeps } from '../common/components/with-store-subscription'; @@ -20,7 +20,7 @@ export class MainRenderer { constructor( private readonly deps: MainRendererDeps, private readonly popupHandlers: PopupHandlers, - private readonly renderer: typeof ReactDOM.render, + private readonly createRoot: typeof ReactDOMClient.createRoot, private readonly dom: Document, private readonly popupWindow: Window, private readonly targetTabUrl: string, @@ -31,9 +31,9 @@ export class MainRenderer { ) {} public render(): void { - const container = this.dom.querySelector('#popup-container'); - - this.renderer( + const container = this.dom.querySelector('#popup-container') as Element; + const root = this.createRoot(container); + root.render( <> , - container, ); } } diff --git a/src/popup/popup-initializer.ts b/src/popup/popup-initializer.ts index 9eefd313c44..3f1462b96fd 100644 --- a/src/popup/popup-initializer.ts +++ b/src/popup/popup-initializer.ts @@ -10,7 +10,7 @@ import { DocumentManipulator } from 'common/document-manipulator'; import { StoreUpdateMessageHub } from 'common/store-update-message-hub'; import { ExceptionTelemetryListener } from 'common/telemetry/exception-telemetry-listener'; import { ExceptionTelemetrySanitizer } from 'common/telemetry/exception-telemetry-sanitizer'; -import * as ReactDOM from 'react-dom'; +import { createRoot } from 'react-dom/client'; import { AxeInfo } from '../common/axe-info'; import { NewTabLink } from '../common/components/new-tab-link'; import { DropdownClickHandler } from '../common/dropdown-click-handler'; @@ -81,10 +81,7 @@ export class PopupInitializer { } private useIncompatibleBrowserRenderer = () => { - const incompatibleBrowserRenderer = new IncompatibleBrowserRenderer( - ReactDOM.render, - document, - ); + const incompatibleBrowserRenderer = new IncompatibleBrowserRenderer(createRoot, document); incompatibleBrowserRenderer.render(); }; @@ -239,7 +236,7 @@ export class PopupInitializer { const renderer = new MainRenderer( deps, popupHandlers, - ReactDOM.render, + createRoot, document, window, tab.url, diff --git a/src/report-export/types/report-export-service.ts b/src/report-export/types/report-export-service.ts index 9825145b39c..445c27b8e50 100644 --- a/src/report-export/types/report-export-service.ts +++ b/src/report-export/types/report-export-service.ts @@ -25,5 +25,5 @@ export type ReportExportService = { href?: string, download?: string, ) => IContextualMenuItem; - exportForm?: React.ComponentType; + exportForm?: React.ComponentType>; }; diff --git a/src/reports/components/head.tsx b/src/reports/components/head.tsx index 331d42339d5..ffe811ef806 100644 --- a/src/reports/components/head.tsx +++ b/src/reports/components/head.tsx @@ -12,13 +12,12 @@ export type bundledStylesProp = { }; export const Head = NamedFC('Head', props => { + const titleValue = `${props.titlePreface} ${props.title}`; // tslint:disable: react-no-dangerous-html return ( - - {props.titlePreface} {props.title} - + {titleValue}