Skip to content

Commit

Permalink
Drop support for React 17.x (#1054)
Browse files Browse the repository at this point in the history
* Drop React 17.x from dependency range

* Remove useCreateRoot

* this._roots cleanup

* Change to Map for better typings

* Deprecate renderFavorites

* Remove use-sync-external-store

* Remove withWrapperAndProps util

* arg -> param

* Remove some of the isMounted checks

* NextVersion

* Remove outdated test

* Extract API

* rush change

* Remove unused type to fix linter error

* Fix tests
  • Loading branch information
GerardasB authored Sep 27, 2024
1 parent ebf8b59 commit 252752f
Show file tree
Hide file tree
Showing 29 changed files with 1,583 additions and 1,656 deletions.
2 changes: 0 additions & 2 deletions common/api/appui-react.api.md
Original file line number Diff line number Diff line change
Expand Up @@ -2022,8 +2022,6 @@ export interface FrameworkChildWindows {
findId(contentWindow: Window | undefined | null): string | undefined;
open(childWindowId: string, title: string, content: React.ReactNode, location: ChildWindowLocationProps, useDefaultPopoutUrl?: boolean): boolean;
readonly openChildWindows: OpenChildWindowInfo[];
// @beta
useCreateRoot(createRootFn: CreateRoot): void;
}

// @public
Expand Down
4 changes: 3 additions & 1 deletion common/api/components-react.api.md
Original file line number Diff line number Diff line change
Expand Up @@ -714,7 +714,9 @@ export interface ErrorObserver<T> {
// @public
export class FavoritePropertiesRenderer {
hasFavorites(propertyData: PropertyData): boolean;
renderFavorites(propertyData: PropertyData, orientation?: Orientation, createRoot?: CreateRoot): HTMLElement | string;
renderFavorites(propertyData: PropertyData, orientation?: Orientation): HTMLElement | string;
// @deprecated
renderFavorites(propertyData: PropertyData, orientation?: Orientation, _createRoot?: CreateRoot): HTMLElement | string;
}

// @alpha
Expand Down
1,789 changes: 897 additions & 892 deletions common/api/summary/appui-react.exports.csv

Large diffs are not rendered by default.

938 changes: 470 additions & 468 deletions common/api/summary/components-react.exports.csv

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"changes": [
{
"packageName": "@itwin/appui-react",
"comment": "Drop support for React 17.x.",
"type": "none"
}
],
"packageName": "@itwin/appui-react"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"changes": [
{
"packageName": "@itwin/components-react",
"comment": "Drop support for React 17.x.",
"type": "none"
}
],
"packageName": "@itwin/components-react"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"changes": [
{
"packageName": "@itwin/core-react",
"comment": "Drop support for React 17.x.",
"type": "none"
}
],
"packageName": "@itwin/core-react"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"changes": [
{
"packageName": "@itwin/imodel-components-react",
"comment": "Drop support for React 17.x.",
"type": "none"
}
],
"packageName": "@itwin/imodel-components-react"
}
4 changes: 0 additions & 4 deletions common/config/rush/browser-approved-packages.json
Original file line number Diff line number Diff line change
Expand Up @@ -502,10 +502,6 @@
"name": "upath",
"allowedCategories": [ "frontend" ]
},
{
"name": "use-sync-external-store",
"allowedCategories": [ "frontend" ]
},
{
"name": "vite",
"allowedCategories": [ "internal" ]
Expand Down
10 changes: 0 additions & 10 deletions common/config/rush/pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

15 changes: 15 additions & 0 deletions docs/changehistory/NextVersion.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,10 @@
Table of contents:

- [@itwin/appui-react](#itwinappui-react)
- [Removals](#removals)
- [Changes](#changes)
- [@itwin/components-react](#itwincomponents-react)
- [Deprecations](#deprecations)
- [Additions](#additions)
- [Changes](#changes-1)
- [@itwin/core-react](#itwincore-react)
Expand All @@ -14,15 +16,24 @@ Table of contents:

## @itwin/appui-react

### Removals

- Removed `FrameworkChildWindows.useCreateRoot` method which existed solely to prevent runtime warnings when using `React 18.x`. [#1054](https://github.com/iTwin/appui/pull/1054)

### Changes

- Updated `MessageManager.addMessage` and `MessageManager.outputMessage` to ignore already active messages displayed to the user. This API is used by various tools indirectly via `IModelApp.notifications.outputMessage` when `AppNotificationManager` is set up. This change should prevent the same message from being displayed multiple times unnecessarily. [#1042](https://github.com/iTwin/appui/pull/1042)
- Added `exports` field to `package.json` to prevent importing of `@internal` APIs [^1]. [#1048](https://github.com/iTwin/appui/pull/1048)
- Popout widgets are now displayed in flow layout to match the layout of floating, stage panel and popout widgets when `reparentPopoutWidgets` is enabled. [#1049](https://github.com/iTwin/appui/pull/1049)
- Drop support for [iTwin.js 3.x](https://www.itwinjs.org/v3/) [^2]. [#1050](https://github.com/iTwin/appui/pull/1050)
- Drop support for [React 17.x](https://react.dev/versions#react-17) [^3]. [#1054](https://github.com/iTwin/appui/pull/1054)

## @itwin/components-react

### Deprecations

- Deprecated `FavoritePropertiesRenderer.renderFavorites` method in favor of an overload that doesn't take the `createRoot` function as an argument. [#1054](https://github.com/iTwin/appui/pull/1054)

### Additions

- Added `IMergingPropertyDataProvider` interface which combines any number of `IPropertyDataProvider` instances and added `createMergedPropertyDataProvider` factory function that creates `IMergingPropertyDataProvider` instance. [#1040](https://github.com/iTwin/appui/pull/1040)
Expand All @@ -31,6 +42,7 @@ Table of contents:

- Added `exports` field to `package.json` to prevent importing of `@internal` APIs [^1]. [#1048](https://github.com/iTwin/appui/pull/1048)
- Drop support for [iTwin.js 3.x](https://www.itwinjs.org/v3/) [^2]. [#1050](https://github.com/iTwin/appui/pull/1050)
- Drop support for [React 17.x](https://react.dev/versions#react-17) [^3]. [#1054](https://github.com/iTwin/appui/pull/1054)

## @itwin/core-react

Expand All @@ -39,13 +51,16 @@ Table of contents:
- Removed the `resize-observer-polyfill` dependency because `ResizeObserver` is well supported by modern browsers, eliminating the need for a polyfill. [#1045](https://github.com/iTwin/appui/pull/1045)
- Added `exports` field to `package.json` to prevent importing of `@internal` APIs [^1]. [#1048](https://github.com/iTwin/appui/pull/1048)
- Drop support for [iTwin.js 3.x](https://www.itwinjs.org/v3/) [^2]. [#1050](https://github.com/iTwin/appui/pull/1050)
- Drop support for [React 17.x](https://react.dev/versions#react-17) [^3]. [#1054](https://github.com/iTwin/appui/pull/1054)

## @itwin/imodel-components-react

### Changes

- Added `exports` field to `package.json` to prevent importing of `@internal` APIs [^1]. [#1048](https://github.com/iTwin/appui/pull/1048)
- Drop support for [iTwin.js 3.x](https://www.itwinjs.org/v3/) [^2]. [#1050](https://github.com/iTwin/appui/pull/1050)
- Drop support for [React 17.x](https://react.dev/versions#react-17) [^3]. [#1054](https://github.com/iTwin/appui/pull/1054)

[^1]: This change might break consumers that rely on importing `@internal` APIs directly from unsupported submodules i.e. `@itwin/appui-react/lib/esm/appui-react`. Currently supported export paths: main entry point (i.e. `@itwin/appui-react`), `package.json` subpath (i.e. `@itwin/appui-react/package.json`). Additional export paths are available until next major version to facilitate the **AppUI 5.0** adoption: ESM submodule (i.e. `@itwin/appui-react/esm`), CJS submodule (i.e. `@itwin/appui-react/cjs`), all SCSS files are exported by using `sass` custom condition (i.e. `@itwin/core-react/lib/cjs/core-react/typography`).
[^2]: **iTwin.js 3.x** is in end-of-life phase as described in [version support status](https://www.itwinjs.org/learning/api-support-policies/#version-support-status). Consumers of **AppUI 5.0** should upgrade to latest **iTwin.js 4.x** version. Support for newer versions of **iTwin.js** will be added in future AppUI releases.
[^3]: Consumers should upgrade to latest [React 18.x](https://react.dev/blog/2022/03/08/react-18-upgrade-guide) version. Support for newer versions of **React** will be added in future AppUI releases.
6 changes: 2 additions & 4 deletions ui/appui-react/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -65,8 +65,8 @@
"@itwin/core-react": "workspace:^5.0.0-dev.0",
"@itwin/core-telemetry": "^4.0.0",
"@itwin/imodel-components-react": "workspace:^5.0.0-dev.0",
"react": "^17.0.0 || ^18.0.0",
"react-dom": "^17.0.0 || ^18.0.0",
"react": "^18.0.0",
"react-dom": "^18.0.0",
"react-redux": "^7.2.2",
"redux": "^4.1.0"
},
Expand Down Expand Up @@ -101,7 +101,6 @@
"@types/react-redux": "^7.1.18",
"@types/react-transition-group": "^4.4.4",
"@types/rimraf": "^2.0.2",
"@types/use-sync-external-store": "^0.0.6",
"@vitest/coverage-v8": "^1.4.0",
"cpx2": "^3.0.0",
"eslint": "^8.57.1",
Expand Down Expand Up @@ -140,7 +139,6 @@
"react-transition-group": "^4.4.2",
"rxjs": "^7.8.1",
"ts-key-enum": "~2.0.12",
"use-sync-external-store": "^1.2.0",
"zustand": "^4.4.1"
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@

import "./InternalChildWindowManager.scss";
import * as React from "react";
import * as ReactDOM from "react-dom";
import type { Root } from "react-dom/client";
import { createRoot } from "react-dom/client";
import { Provider } from "react-redux";
import { UiFramework } from "../UiFramework";
import { CursorPopupMenu } from "../cursor/cursormenu/CursorMenu";
Expand Down Expand Up @@ -52,64 +53,35 @@ const childHtml = `<!DOCTYPE html>
</body>
</html>`;

/**
* Simplification of non exported CreateRoot parameter, only to be used
* in InternalChildWindowManager and ChildWindowManager
* @internal
*/
export type CreateRoot = Parameters<FrameworkChildWindows["useCreateRoot"]>[0];

/** Supports opening a child browser window from the main application window. The child window is managed by the main application
* and is running in the same security context. The application must deliver the html file iTwinPopup.html along side its index.html.
* See also: [Child Window Manager]($docs/learning/ui/appui-react/ChildWindows.md)
* @internal
* */
export class InternalChildWindowManager implements FrameworkChildWindows {
private _openChildWindows: OpenChildWindowInfo[] = [];
private _createRoot?: CreateRoot;
private _roots: { [childwindowId: string]: any } = {};
private _roots = new Map<string, Root>();

public get openChildWindows() {
return this._openChildWindows;
}

/**
* When using React 18, the `createRoot` function must be provided in order to render Popout content with React 18.
* Do not call if using React 17 or before.
*
* Note: The type of the function is intentionally simplified here.
*
* @param createRootFn Function imported from `import { createRoot } from "react-dom/client";`
* @beta Will be removed once the transition to React 18 is complete.
*/
public useCreateRoot(createRootFn: CreateRoot): void {
this._createRoot = createRootFn;
}

/**
* Abstracts ReactDOM.render to use either the _createRoot method or the default ReactDOM.render.
/** Creates a new element tree to render specified element.
* @param element Element to render.
* @param container Container to render to.
*/
private render(
element: React.FunctionComponentElement<any>,
container: Element | DocumentFragment
) {
// If createRoot is passed in for React 18 we have to render differently
// than without it. React 17 vs React 18. We need to save the root to
// unmount it.
if (this._createRoot) {
const childWindowId = UiFramework.childWindows.findId(
container.ownerDocument.defaultView
);
if (childWindowId) {
this._roots[childWindowId] = this._createRoot(container);
this._roots[childWindowId].render(element);
}
} else {
// eslint-disable-next-line react/no-deprecated, deprecation/deprecation
ReactDOM.render(element, container);
}
const childWindowId = UiFramework.childWindows.findId(
container.ownerDocument.defaultView
);
if (!childWindowId) return;

const root = createRoot(container);
this._roots.set(childWindowId, root);
root.render(element);
}

/**
Expand Down Expand Up @@ -213,13 +185,10 @@ export class InternalChildWindowManager implements FrameworkChildWindows {
// Trigger first so popout can be converted back to main window widget
this.close(childWindowId, false);

// UnmountComponentAtNode is deprecated in React 18, so if they are
// using React 18 and passing in a createRoot function, unmount()
// will be used
if (this._roots[childWindowId]) {
this._roots[childWindowId].unmount();
// eslint-disable-next-line react/no-deprecated, deprecation/deprecation
} else ReactDOM.unmountComponentAtNode(reactConnectionDiv);
const root = this._roots.get(childWindowId);
if (!root) return;
this._roots.delete(childWindowId);
root.unmount();
});
}
}
Expand Down
18 changes: 0 additions & 18 deletions ui/appui-react/src/appui-react/framework/FrameworkChildWindows.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,6 @@ export interface ChildWindowLocationProps {
top: number;
}

/**
* Basic recreation of the `createRoot` function type, intentionally not exported.
*/
type CreateRoot = (container: Element | DocumentFragment) => {
render(children: React.ReactNode): void;
};

/**
* [[UiFramework.childWindows]] interface.
* @public
Expand All @@ -38,17 +31,6 @@ export interface FrameworkChildWindows {
*/
readonly openChildWindows: OpenChildWindowInfo[];

/**
* When using React18, the `createRoot` function must be provided in order to render Popout content with React18.
* Do not call if using React 17 or before.
*
* Note: The type of the function is intentionally simplified here.
*
* @param createRootFn Function imported from `import { createRoot } from "react-dom/client";`
* @beta Will be removed once the transition to react 18 is complete.
*/
useCreateRoot(createRootFn: CreateRoot): void;

/**
* Returns the OpenChildWindowInfo for the related id.
* @param childWindowId Id of the window to retrieve.
Expand Down
2 changes: 1 addition & 1 deletion ui/appui-react/src/appui-react/hooks/useActiveViewport.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@
* @module Hooks
*/

import { useSyncExternalStore } from "react";
import type { ScreenViewport } from "@itwin/core-frontend";
import { IModelApp } from "@itwin/core-frontend";
import { useSyncExternalStore } from "use-sync-external-store/shim";

const subscribe = (onStoreChange: () => void) => {
return IModelApp.viewManager.onSelectedViewportChanged.addListener(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,19 +44,9 @@ export function useAnalysisAnimationDataProvider(
viewport: ScreenViewport | undefined
) {
const supportsAnalysisAnimation = useSupportsAnalysisAnimation(viewport);
const [
analysisAnimationTimelineDataProvider,
setAnalysisAnimationTimelineDataProvider,
] = React.useState<AnalysisAnimationTimelineDataProvider | undefined>();
const isMountedRef = React.useRef(false);

React.useEffect(() => {
isMountedRef.current = true;
return () => {
isMountedRef.current = false;
};
}, []);

const [dataProvider, setDataProvider] = React.useState<
AnalysisAnimationTimelineDataProvider | undefined
>();
React.useEffect(() => {
async function fetchNewDataProvider(vp: ScreenViewport) {
let newProvider: AnalysisAnimationTimelineDataProvider | undefined =
Expand All @@ -65,15 +55,12 @@ export function useAnalysisAnimationDataProvider(
const dataLoaded = await newProvider.loadTimelineData();
if (!dataLoaded) newProvider = undefined;
}
isMountedRef.current &&
setAnalysisAnimationTimelineDataProvider(newProvider);
setDataProvider(newProvider);
}
if (supportsAnalysisAnimation && viewport)
if (supportsAnalysisAnimation && viewport) {
void fetchNewDataProvider(viewport);
else
isMountedRef.current &&
setAnalysisAnimationTimelineDataProvider(undefined);
} else setDataProvider(undefined);
}, [supportsAnalysisAnimation, viewport]);

return analysisAnimationTimelineDataProvider;
return dataProvider;
}
Loading

0 comments on commit 252752f

Please sign in to comment.