diff --git a/.changeset/sixty-brooms-study.md b/.changeset/sixty-brooms-study.md
new file mode 100644
index 0000000000..2759d9bb89
--- /dev/null
+++ b/.changeset/sixty-brooms-study.md
@@ -0,0 +1,30 @@
+---
+'@commercetools-uikit/async-creatable-select-field': major
+'@commercetools-uikit/localized-rich-text-input': major
+'@commercetools-uikit/async-select-field': major
+'@commercetools-uikit/secondary-button': major
+'@commercetools-uikit/primary-action-dropdown': major
+'@commercetools-uikit/link-button': major
+'@commercetools-uikit/select-input': major
+'@commercetools-uikit/icons': major
+'@commercetools-uikit/card': major
+'@commercetools-uikit/link': major
+'@commercetools-uikit/tag': major
+'visual-testing-app': major
+'@commercetools-uikit/buttons': major
+'@commercetools-uikit/fields': major
+'@commercetools-uikit/inputs': major
+'@commercetools-frontend/ui-kit': major
+---
+
+These changes introduce a migration from react-router v5 to v6. The most obvious change is how the component is now used. Unlike the the pattern in v5 where the `to` props in a nested route requires you to manually interpolate `match.url` for a relative route, v6 accepts a string where all urls are automatically relative routes.
+
+```jsx
+// v5: relative path requires you to manually interpolate
+My Profile
+```
+
+```jsx
+// v6: directly passed string is automatically interpreted as relative path
+My Profile
+```
diff --git a/design-system/src/theme-provider.visualroute.jsx b/design-system/src/theme-provider.visualroute.jsx
index f0f5061b9c..651723b0f8 100644
--- a/design-system/src/theme-provider.visualroute.jsx
+++ b/design-system/src/theme-provider.visualroute.jsx
@@ -1,6 +1,6 @@
import { useState } from 'react';
import { useTheme, designTokens } from '@commercetools-uikit/design-system';
-import { Switch, Route } from 'react-router';
+import { Routes, Route } from 'react-router';
import kebabCase from 'lodash/kebabCase';
import PropTypes from 'prop-types';
import {
@@ -191,8 +191,8 @@ const InteractiveRoute = () => {
};
export const component = () => (
-
-
-
-
+
+ } />
+ } />
+
);
diff --git a/package.json b/package.json
index f7bf56694b..ee7e185151 100644
--- a/package.json
+++ b/package.json
@@ -142,7 +142,7 @@
"react": "17.0.2",
"react-dom": "17.0.2",
"react-intl": "^6.3.2",
- "react-router-dom": "5.3.4",
+ "react-router-dom": "6",
"react-test-renderer": "17.0.2",
"react-value": "0.2.0",
"replace": "1.2.2",
@@ -163,7 +163,6 @@
"@types/eslint": "^9.0.0",
"@types/react": "17.0.83",
"@types/react-dom": "17.0.25",
- "@types/react-router": "5.1.20",
"@types/unist": "3.0.3",
"@typescript-eslint/eslint-plugin": "8.9.0",
"@typescript-eslint/parser": "8.9.0",
diff --git a/packages/components/buttons/link-button/package.json b/packages/components/buttons/link-button/package.json
index d8011055a4..750df23650 100644
--- a/packages/components/buttons/link-button/package.json
+++ b/packages/components/buttons/link-button/package.json
@@ -34,11 +34,11 @@
"devDependencies": {
"react": "17.0.2",
"react-intl": "^6.3.2",
- "react-router-dom": "5.3.4"
+ "react-router-dom": "6"
},
"peerDependencies": {
"react": "17.x",
"react-intl": "6.x",
- "react-router-dom": "5.x"
+ "react-router-dom": "6.x"
}
}
diff --git a/packages/components/buttons/link-button/src/link-button.spec.js b/packages/components/buttons/link-button/src/link-button.spec.js
index fd657ed9f9..6cf809eeff 100644
--- a/packages/components/buttons/link-button/src/link-button.spec.js
+++ b/packages/components/buttons/link-button/src/link-button.spec.js
@@ -5,6 +5,7 @@ import {
fireEvent,
waitFor,
} from '../../../../../test/test-utils';
+import { Routes, Route } from 'react-router-dom';
import LinkButton from './link-button';
const createTestProps = (custom) => ({
@@ -38,10 +39,15 @@ describe('rendering', () => {
expect(screen.getByLabelText('test-button')).toBeEnabled();
});
it('should navigate to link when clicked', async () => {
- const { history } = render();
+ render(
+
+ } />
+ Foo Bar Page} />
+
+ );
fireEvent.click(screen.getByLabelText('test-button'));
await waitFor(() => {
- expect(history.location.pathname).toBe('/foo/bar');
+ expect(screen.getByText('Foo Bar Page')).toBeInTheDocument();
});
});
it('should pass aria attributes"', () => {
@@ -52,10 +58,18 @@ describe('rendering', () => {
);
});
it('should prevent the navigation when "disabled"', async () => {
- const { history } = render();
+ render(
+
+ } />
+ Foo Bar Page} />
+
+ );
fireEvent.click(screen.getByLabelText('test-button'));
await waitFor(() => {
- expect(history.location.pathname).toBe('/');
+ expect(screen.getByLabelText('test-button')).toBeInTheDocument();
+ });
+ await waitFor(() => {
+ expect(screen.queryByText('Foo Bar Page')).not.toBeInTheDocument();
});
});
it('should render icon', () => {
diff --git a/packages/components/buttons/link-button/src/link-button.tsx b/packages/components/buttons/link-button/src/link-button.tsx
index ea75bb1177..6e8a4bfc2c 100644
--- a/packages/components/buttons/link-button/src/link-button.tsx
+++ b/packages/components/buttons/link-button/src/link-button.tsx
@@ -1,5 +1,3 @@
-import type { LocationDescriptor } from 'history';
-
import { cloneElement, ReactElement } from 'react';
import { Link as ReactRouterLink } from 'react-router-dom';
import { css } from '@emotion/react';
@@ -12,6 +10,8 @@ import {
import Inline from '@commercetools-uikit/spacings-inline';
import Text from '@commercetools-uikit/text';
+type LocationDescriptor = { pathname: string; search?: string; hash?: string };
+
export type TLinkButtonProps = {
/**
* Should describe what the button is for.
diff --git a/packages/components/buttons/secondary-button/package.json b/packages/components/buttons/secondary-button/package.json
index 1f1c73cac3..ac86c49e4d 100644
--- a/packages/components/buttons/secondary-button/package.json
+++ b/packages/components/buttons/secondary-button/package.json
@@ -34,11 +34,11 @@
"devDependencies": {
"react": "17.0.2",
"react-intl": "^6.3.2",
- "react-router-dom": "5.3.4"
+ "react-router-dom": "6"
},
"peerDependencies": {
"react": "17.x",
"react-intl": "6.x",
- "react-router-dom": "5.x"
+ "react-router-dom": "6.x"
}
}
diff --git a/packages/components/buttons/secondary-button/src/secondary-button.spec.js b/packages/components/buttons/secondary-button/src/secondary-button.spec.js
index 5022942341..928e9d57a5 100644
--- a/packages/components/buttons/secondary-button/src/secondary-button.spec.js
+++ b/packages/components/buttons/secondary-button/src/secondary-button.spec.js
@@ -1,4 +1,4 @@
-import { Link } from 'react-router-dom';
+import { Routes, Route, Link } from 'react-router-dom';
import { PlusBoldIcon } from '@commercetools-uikit/icons';
import {
screen,
@@ -95,12 +95,25 @@ describe('rendering', () => {
});
describe('when using as', () => {
it('should navigate to link when clicked', async () => {
- const { history } = render(
-
+ render(
+
+
+ }
+ />
+ Foo Bar Page} />
+
);
fireEvent.click(screen.getByLabelText('Add'));
await waitFor(() => {
- expect(history.location.pathname).toBe('/foo/bar');
+ expect(screen.getByText('Foo Bar Page')).toBeInTheDocument();
});
});
});
diff --git a/packages/components/card/package.json b/packages/components/card/package.json
index 070d2dd2e8..c852bfd055 100644
--- a/packages/components/card/package.json
+++ b/packages/components/card/package.json
@@ -26,15 +26,14 @@
"@commercetools-uikit/utils": "19.16.0",
"@emotion/react": "^11.10.5",
"@emotion/styled": "^11.10.5",
- "@types/react-router-dom": "^5.3.3",
"prop-types": "15.8.1"
},
"devDependencies": {
"react": "17.0.2",
- "react-router-dom": "5.3.4"
+ "react-router-dom": "6"
},
"peerDependencies": {
"react": "17.x",
- "react-router-dom": "5.x"
+ "react-router-dom": "6.x"
}
}
diff --git a/packages/components/card/src/card.spec.tsx b/packages/components/card/src/card.spec.tsx
index 8897e9e721..8a9f730207 100644
--- a/packages/components/card/src/card.spec.tsx
+++ b/packages/components/card/src/card.spec.tsx
@@ -1,6 +1,5 @@
import { screen, render, fireEvent } from '../../../../test/test-utils';
import Card from './card';
-import { BrowserRouter } from 'react-router-dom'; // Required for testing
it('should render children', () => {
render(Bread);
@@ -34,11 +33,7 @@ it('should not call `onClick` when the card is disabled', () => {
it('should render as a react-router `Link` when `to` prop is provided', () => {
const content = 'Internal Link';
- render(
-
- {content}
-
- );
+ render({content});
const link = screen.getByText(content).closest('a');
expect(link).toHaveAttribute('href', '/internal-link');
diff --git a/packages/components/card/src/card.tsx b/packages/components/card/src/card.tsx
index 0e7eef0347..47de3c4489 100644
--- a/packages/components/card/src/card.tsx
+++ b/packages/components/card/src/card.tsx
@@ -3,8 +3,7 @@ import { css } from '@emotion/react';
import { designTokens } from '@commercetools-uikit/design-system';
import { filterDataAttributes, warning } from '@commercetools-uikit/utils';
import Inset from '@commercetools-uikit/spacings-inset';
-import { Link } from 'react-router-dom';
-import type { LocationDescriptor } from 'history';
+import { Link, LinkProps } from 'react-router-dom';
export type TCardProps = {
/**
@@ -34,7 +33,7 @@ export type TCardProps = {
/**
* The URL that the Card should point to. If provided, the Card will be rendered as an anchor element.
*/
- to?: string | LocationDescriptor;
+ to?: LinkProps['to'];
/**
* A flag to indicate if the Card points to an external source.
*/
diff --git a/packages/components/fields/async-creatable-select-field/src/async-creatable-select-field.visualroute.jsx b/packages/components/fields/async-creatable-select-field/src/async-creatable-select-field.visualroute.jsx
index 1a0a3e2c95..02e43096f7 100644
--- a/packages/components/fields/async-creatable-select-field/src/async-creatable-select-field.visualroute.jsx
+++ b/packages/components/fields/async-creatable-select-field/src/async-creatable-select-field.visualroute.jsx
@@ -1,4 +1,4 @@
-import { Switch, Route } from 'react-router-dom';
+import { Routes, Route } from 'react-router-dom';
import { AsyncCreatableSelectField } from '@commercetools-frontend/ui-kit';
import { Suite, Spec } from '../../../../../test/percy';
@@ -126,10 +126,10 @@ const DefaultRoute = () => (
);
const InteractionRoute = () => (
-
+
(
+ path="without-default-options/*"
+ element={
(
/>
- )}
+ }
/>
-
(
+ path="/*"
+ element={
(
/>
- )}
+ }
/>
-
+
);
export const component = () => (
-
-
-
-
+
+ } />
+ } />
+
);
diff --git a/packages/components/fields/async-select-field/src/async-select-field.visualroute.jsx b/packages/components/fields/async-select-field/src/async-select-field.visualroute.jsx
index efa459b380..384353da7c 100644
--- a/packages/components/fields/async-select-field/src/async-select-field.visualroute.jsx
+++ b/packages/components/fields/async-select-field/src/async-select-field.visualroute.jsx
@@ -1,4 +1,4 @@
-import { Switch, Route } from 'react-router-dom';
+import { Routes, Route } from 'react-router-dom';
import { AsyncSelectField } from '@commercetools-frontend/ui-kit';
import { Suite, Spec } from '../../../../../test/percy';
@@ -126,10 +126,10 @@ const DefaultRoute = () => (
);
const InteractionRoute = () => (
-
+
(
+ path="without-default-options/*"
+ element={
(
/>
- )}
+ }
/>
(
+ path="/*"
+ element={
(
/>
- )}
+ }
/>
-
+
);
export const component = () => (
-
-
-
-
+
+ } />
+ } />
+
);
diff --git a/packages/components/icons/src/icons.visualroute.jsx b/packages/components/icons/src/icons.visualroute.jsx
index 2011e5c122..b314e7fe0c 100644
--- a/packages/components/icons/src/icons.visualroute.jsx
+++ b/packages/components/icons/src/icons.visualroute.jsx
@@ -1,5 +1,5 @@
import styled from '@emotion/styled';
-import { Switch, Route } from 'react-router-dom';
+import { Routes, Route } from 'react-router-dom';
import { designTokens } from '@commercetools-uikit/design-system';
import * as icons from '@commercetools-uikit/icons';
import CustomIcon from '@commercetools-uikit/icons/custom-icon';
@@ -83,8 +83,9 @@ const renderIcon = (iconName, color, size) => {
};
export const component = () => (
-
-
+
+
{colors.map((color) => (
@@ -106,10 +107,11 @@ export const component = () => (
{`${routePath}/custom-icon`}
-
+ }
+ />
{colors.map((color) => (
-
-
+
{sizes.map((size) => (
(
))}
-
+ }
+ />
))}
-
+
{sizes.map((size) => (
@@ -151,8 +155,10 @@ export const component = () => (
))}
-
-
+ }
+ />
+
{leadingIconSizes.map((size) => (
@@ -202,8 +208,10 @@ export const component = () => (
-
-
+ }
+ />
+
@@ -246,6 +254,7 @@ export const component = () => (
-
-
+ }
+ />
+
);
diff --git a/packages/components/inputs/localized-rich-text-input/src/localized-rich-text-input.visualroute.jsx b/packages/components/inputs/localized-rich-text-input/src/localized-rich-text-input.visualroute.jsx
index 39a2b7a698..03a7ece2d8 100644
--- a/packages/components/inputs/localized-rich-text-input/src/localized-rich-text-input.visualroute.jsx
+++ b/packages/components/inputs/localized-rich-text-input/src/localized-rich-text-input.visualroute.jsx
@@ -1,4 +1,4 @@
-import { Switch, Route } from 'react-router-dom';
+import { Routes, Route } from 'react-router-dom';
import { useState, useCallback, useRef, forwardRef } from 'react';
import {
LocalizedRichTextInput,
@@ -306,8 +306,8 @@ const DefaultRoute = () => (
);
export const component = () => (
-
-
-
-
+
+ } />
+ } />
+
);
diff --git a/packages/components/inputs/rich-text-input/src/rich-text-input.visualroute.jsx b/packages/components/inputs/rich-text-input/src/rich-text-input.visualroute.jsx
index 5e00b151d6..8bd5a11f66 100644
--- a/packages/components/inputs/rich-text-input/src/rich-text-input.visualroute.jsx
+++ b/packages/components/inputs/rich-text-input/src/rich-text-input.visualroute.jsx
@@ -1,5 +1,5 @@
import { useState, useCallback, useRef } from 'react';
-import { Switch, Route } from 'react-router';
+import { Routes, Route } from 'react-router';
import { RichTextInput } from '@commercetools-frontend/ui-kit';
import { Suite, Spec } from '../../../../../test/percy';
@@ -165,8 +165,8 @@ const DefaultRoute = () => (
);
export const component = () => (
-
-
-
-
+
+ } />
+ } />
+
);
diff --git a/packages/components/inputs/select-input/src/select-input.visualroute.jsx b/packages/components/inputs/select-input/src/select-input.visualroute.jsx
index b5fbb41fc3..491490e6eb 100644
--- a/packages/components/inputs/select-input/src/select-input.visualroute.jsx
+++ b/packages/components/inputs/select-input/src/select-input.visualroute.jsx
@@ -1,5 +1,5 @@
/* eslint-disable react/prop-types */
-import { Route, Switch } from 'react-router-dom';
+import { Route, Routes } from 'react-router-dom';
import { SelectInput } from '@commercetools-frontend/ui-kit';
import { Suite, Spec } from '../../../../../test/percy';
import { WorldIcon } from '../../../icons';
@@ -285,16 +285,16 @@ const OpenRouteWithOptionGroupsAndDivider = () => (
);
export const component = () => (
-
-
+
+ } />
}
/>
}
/>
- } />
-
+ } />
+
);
diff --git a/packages/components/link/README.md b/packages/components/link/README.md
index 0afa2ae9df..b1d65a480e 100644
--- a/packages/components/link/README.md
+++ b/packages/components/link/README.md
@@ -49,7 +49,7 @@ export default Example;
| `children` | `ReactNode` | | | Value of the link.
Required if `intlMessage` is not provided. |
| `intlMessage` | `MessageDescriptor` | | | An `intl` message object that will be rendered with `FormattedMessage`.
Required if `children` is not provided. |
| `isExternal` | `boolean` | | `false` | A flag to indicate if the Link points to an external source.
If `true`, a regular `` is rendered instead of the default `react-router`s `` |
-| `to` | `union`
Possible values:
`string , LocationDescriptor` | ✅ | | The URL that the Link should point to. |
+| `to` | `LinkProps['to']` | ✅ | | The relative URL that the Link should point to. |
| `tone` | `union`
Possible values:
`'primary' , 'inverted', 'secondary'` | | `'primary'` | Color of the link |
| `onClick` | `Function`
[See signature.](#signature-onClick) | | | Handler when the link is clicked. |
diff --git a/packages/components/link/package.json b/packages/components/link/package.json
index 408e0a7f50..387c6475cb 100644
--- a/packages/components/link/package.json
+++ b/packages/components/link/package.json
@@ -27,19 +27,17 @@
"@commercetools-uikit/utils": "19.16.0",
"@emotion/react": "^11.10.5",
"@emotion/styled": "^11.10.5",
- "@types/history": "^4.7.11",
- "@types/react-router-dom": "^5.3.3",
"history": "4.10.1",
"prop-types": "15.8.1"
},
"devDependencies": {
"react": "17.0.2",
"react-intl": "^6.3.2",
- "react-router-dom": "5.3.4"
+ "react-router-dom": "6"
},
"peerDependencies": {
"react": "17.x",
"react-intl": "6.x",
- "react-router-dom": "5.x"
+ "react-router-dom": "6.x"
}
}
diff --git a/packages/components/link/src/link.tsx b/packages/components/link/src/link.tsx
index 540739440b..66fcc47aed 100644
--- a/packages/components/link/src/link.tsx
+++ b/packages/components/link/src/link.tsx
@@ -1,4 +1,3 @@
-import type { LocationDescriptor } from 'history';
import type { MessageDescriptor } from 'react-intl';
import {
Children,
@@ -7,7 +6,7 @@ import {
type KeyboardEvent,
} from 'react';
import styled from '@emotion/styled';
-import { Link as ReactRouterLink } from 'react-router-dom';
+import { LinkProps, Link as ReactRouterLink } from 'react-router-dom';
import { css } from '@emotion/react';
import { FormattedMessage } from 'react-intl';
import { designTokens } from '@commercetools-uikit/design-system';
@@ -36,9 +35,9 @@ export type TLinkProps = {
*/
isExternal: boolean;
/**
- * The URL that the Link should point to.
+ * The relative URL that the Link should point to.
*/
- to: string | LocationDescriptor;
+ to: LinkProps['to'];
/**
* Color of the link
*/
diff --git a/packages/components/primary-action-dropdown/src/primary-action-dropdown.visualroute.jsx b/packages/components/primary-action-dropdown/src/primary-action-dropdown.visualroute.jsx
index 2e5696e872..d385348963 100644
--- a/packages/components/primary-action-dropdown/src/primary-action-dropdown.visualroute.jsx
+++ b/packages/components/primary-action-dropdown/src/primary-action-dropdown.visualroute.jsx
@@ -1,4 +1,4 @@
-import { Route, Switch } from 'react-router-dom';
+import { Route, Routes } from 'react-router-dom';
import {
PrimaryActionDropdown,
PrimaryActionDropdownOption,
@@ -62,8 +62,8 @@ const DefaultRoute = () => (
);
export const component = () => (
-
-
-
-
+
+ } />
+ } />
+
);
diff --git a/packages/components/tag/README.md b/packages/components/tag/README.md
index bbd68eceaa..3c7c3079a9 100644
--- a/packages/components/tag/README.md
+++ b/packages/components/tag/README.md
@@ -59,7 +59,7 @@ export default Example;
| ---------------------- | ----------------------------------------------------------------------------------------------------------- | :------: | ----------- | ------------------------------------------------------------------------------------- |
| `type` | `union`
Possible values:
`'normal' , 'warning'` | | | Indicates color scheme of the tag.
@deprecated use `tone` instead |
| `styles` | `Record` | | | Styles object that is spread into the tag body. |
-| `to` | `union`
Possible values:
`string , LocationDescriptor` | | | Link of the tag when not disabled |
+| `to` | `LinkProps['to']` | | | Link of the tag when not disabled |
| `isDisabled` | `boolean` | | `false` | Disable the tag element along with the option to remove it. |
| `isDraggable` | `boolean` | | `false` | Adds the draggable icon on the left side. |
| `onRemove` | `Function`
[See signature.](#signature-onRemove) | | | Called when remove button is clicked. |
diff --git a/packages/components/tag/package.json b/packages/components/tag/package.json
index 850524384f..2376565253 100644
--- a/packages/components/tag/package.json
+++ b/packages/components/tag/package.json
@@ -35,10 +35,10 @@
},
"devDependencies": {
"react": "17.0.2",
- "react-router-dom": "5.3.4"
+ "react-router-dom": "6"
},
"peerDependencies": {
"react": "17.x",
- "react-router-dom": "5.x"
+ "react-router-dom": "6.x"
}
}
diff --git a/packages/components/tag/src/tag.spec.js b/packages/components/tag/src/tag.spec.js
index 82de76b265..13ebc03841 100644
--- a/packages/components/tag/src/tag.spec.js
+++ b/packages/components/tag/src/tag.spec.js
@@ -1,4 +1,5 @@
import { screen, render } from '../../../../test/test-utils';
+import { Route, Routes, useNavigate } from 'react-router-dom';
import Tag from './tag';
it('should render text as children', () => {
@@ -107,31 +108,62 @@ describe('when draggable', () => {
describe('when `to` is set', () => {
it('should redirect when clicked', () => {
- const { history } = render(Bread);
- screen.getByText('Bread').click();
+ render(
+
+ Bread} />
+ Redirected to Foo} />
+ ,
+ { route: '/' }
+ );
- expect(history.location.pathname).toBe('/foo');
+ screen.getByText('Bread').click();
+ expect(screen.getByText('Redirected to Foo')).toBeInTheDocument(); // Assert on UI
});
it('should still call onClick when clicked', () => {
const onClick = jest.fn();
- const { history } = render(
-
- Bread
-
+
+ render(
+
+
+ Bread
+
+ }
+ />
+ Redirected to Foo} />
+ ,
+ { route: '/' }
);
+
screen.getByText('Bread').click();
- expect(onClick).toHaveBeenCalled();
- expect(history.location.pathname).toBe('/foo');
+ expect(onClick).toHaveBeenCalled(); // Assert click handler was called
+ expect(screen.getByText('Redirected to Foo')).toBeInTheDocument(); // Assert redirect
});
it('should redirect on link click if text children proceed it', () => {
- const { history } = render(
-
- Bread
- Peanut Butter
- history.push('/honey')}>Honey
-
+ const TagWithNavigation = () => {
+ const navigate = useNavigate();
+
+ return navigate('/honey')}>Honey;
+ };
+ render(
+
+
+ Bread
+ Peanut Butter
+
+
+ }
+ />
+ Redirected to Honey} />
+ ,
+ { route: '/' }
);
expect(screen.getByText('Bread')).toBeInTheDocument();
@@ -139,38 +171,56 @@ describe('when `to` is set', () => {
expect(screen.getByText('Honey')).toBeInTheDocument();
screen.getByText('Honey').click();
- expect(history.location.pathname).toBe('/honey');
+ expect(screen.getByText('Redirected to Honey')).toBeInTheDocument(); // Assert redirect
});
it('should not redirect when removed', () => {
const onRemove = jest.fn();
- const { history } = render(
-
- Bread
-
+
+ render(
+
+
+ Bread
+
+ }
+ />
+ Redirected to Foo} />
+ ,
+ { route: '/' }
);
screen.getByLabelText('Remove').click();
- // ensure "onRemove" is stil called
+ // Ensure "onRemove" is still called
expect(onRemove).toHaveBeenCalled();
- // ensure the pathname is not "/foo", otherwise a redirect would have
- // happened
- expect(history.location.pathname).toBe('/');
+ // Ensure no redirect occurred by checking the current content
+ expect(screen.queryByText('Redirected to Foo')).not.toBeInTheDocument();
});
it('should not redirect when disabled', () => {
- const { history } = render(
-
- Bread
-
+ render(
+
+
+ Bread
+
+ }
+ />
+ Redirected to Foo} />
+ ,
+ { route: '/' }
);
screen.getByText('Bread').click();
- // ensure the pathname is not "/foo", otherwise a redirect would have
+ // ensure there is not text with `Redirected to Foo`, otherwise a redirect would have
// happened
- expect(history.location.pathname).toBe('/');
+ expect(screen.queryByText('Redirected to Foo')).not.toBeInTheDocument();
});
});
diff --git a/packages/components/tag/src/tag.tsx b/packages/components/tag/src/tag.tsx
index 68ab30f95a..b1eb8530d9 100644
--- a/packages/components/tag/src/tag.tsx
+++ b/packages/components/tag/src/tag.tsx
@@ -1,7 +1,6 @@
-import type { LocationDescriptor } from 'history';
import { ReactNode, MouseEvent, KeyboardEvent, ElementType } from 'react';
import { css, type SerializedStyles } from '@emotion/react';
-import { Link } from 'react-router-dom';
+import { Link, LinkProps } from 'react-router-dom';
import { designTokens } from '@commercetools-uikit/design-system';
import Constraints from '@commercetools-uikit/constraints';
import AccessibleButton from '@commercetools-uikit/accessible-button';
@@ -22,7 +21,7 @@ export type TTagProps = {
/**
* Link of the tag when not disabled
*/
- to?: string | LocationDescriptor;
+ to?: LinkProps['to'];
/**
* Disable the tag element along with the option to remove it.
*/
diff --git a/presets/buttons/package.json b/presets/buttons/package.json
index 594c07dca4..16ef2f0345 100644
--- a/presets/buttons/package.json
+++ b/presets/buttons/package.json
@@ -33,11 +33,11 @@
"devDependencies": {
"react": "17.0.2",
"react-intl": "^6.3.2",
- "react-router-dom": "5.3.4"
+ "react-router-dom": "6"
},
"peerDependencies": {
"react": "17.x",
"react-intl": "6.x",
- "react-router-dom": "5.x"
+ "react-router-dom": "6.x"
}
}
diff --git a/presets/fields/package.json b/presets/fields/package.json
index 49ca433c2a..af8d15ea47 100644
--- a/presets/fields/package.json
+++ b/presets/fields/package.json
@@ -42,11 +42,11 @@
"devDependencies": {
"react": "17.0.2",
"react-intl": "^6.3.2",
- "react-router-dom": "5.3.4"
+ "react-router-dom": "6"
},
"peerDependencies": {
"react": "17.x",
"react-intl": "6.x",
- "react-router-dom": "5.x"
+ "react-router-dom": "6.x"
}
}
diff --git a/presets/inputs/package.json b/presets/inputs/package.json
index 0b7e7df9a2..182ae31434 100644
--- a/presets/inputs/package.json
+++ b/presets/inputs/package.json
@@ -49,11 +49,11 @@
"devDependencies": {
"react": "17.0.2",
"react-intl": "^6.3.2",
- "react-router-dom": "5.3.4"
+ "react-router-dom": "6"
},
"peerDependencies": {
"react": "17.x",
"react-intl": "6.x",
- "react-router-dom": "5.x"
+ "react-router-dom": "6.x"
}
}
diff --git a/presets/ui-kit/package.json b/presets/ui-kit/package.json
index 22436fa52e..237433be05 100644
--- a/presets/ui-kit/package.json
+++ b/presets/ui-kit/package.json
@@ -68,13 +68,13 @@
"moment-timezone": "0.5.46",
"react": "17.0.2",
"react-intl": "^6.3.2",
- "react-router-dom": "5.3.4"
+ "react-router-dom": "6"
},
"peerDependencies": {
"moment": "2.x",
"moment-timezone": "0.5.x",
"react": "17.x",
"react-intl": "6.x",
- "react-router-dom": "5.x"
+ "react-router-dom": "6.x"
}
}
diff --git a/test/setup-tests.js b/test/setup-tests.js
index d323c2abfc..def72c1aa3 100644
--- a/test/setup-tests.js
+++ b/test/setup-tests.js
@@ -35,6 +35,7 @@ Object.defineProperty(window, 'TextDecoder', {
const silenceConsoleWarnings = [];
const notThrowWarnings = [
/"children" property of "Stamp" component has been deprecated/,
+ /React Router Future Flag Warning/,
];
const shouldSilenceWarnings = (...messages) =>
diff --git a/test/test-utils.js b/test/test-utils.js
index 45c8d37342..c774459a70 100644
--- a/test/test-utils.js
+++ b/test/test-utils.js
@@ -2,8 +2,7 @@
import { render } from '@testing-library/react';
import { IntlProvider } from 'react-intl';
-import { Router } from 'react-router-dom';
-import { createMemoryHistory } from 'history';
+import { MemoryRouter } from 'react-router-dom';
const getMessagesForLocale = (locale) => {
switch (locale) {
@@ -24,26 +23,17 @@ const getMessagesForLocale = (locale) => {
const customRender = (
node,
- {
- locale = 'en',
- route = '/',
- history = createMemoryHistory({ initialEntries: [route] }),
- ...rtlOptions
- } = {}
+ { locale = 'en', route = '/', ...rtlOptions } = {}
) => ({
...render(
- {node}
+ {node}
,
rtlOptions
),
- // adding `history` to the returned utilities to allow us
- // to reference it in our tests (just try to avoid using
- // this to test implementation details).
- history,
});
-// re-export everything
+// Re-export everything
export {
act,
fireEvent,
@@ -53,5 +43,5 @@ export {
within,
} from '@testing-library/react';
-// override render method
+// Override render method
export { customRender as render };
diff --git a/visual-testing-app/package.json b/visual-testing-app/package.json
index a78a74e896..778bf618a4 100644
--- a/visual-testing-app/package.json
+++ b/visual-testing-app/package.json
@@ -20,8 +20,8 @@
"react": "17.0.2",
"react-dom": "17.0.2",
"react-intl": "^6.3.2",
- "react-router": "5.3.4",
- "react-router-dom": "5.3.4"
+ "react-router": "6",
+ "react-router-dom": "6"
},
"devDependencies": {
"@vitejs/plugin-react": "4.3.2",
diff --git a/visual-testing-app/src/App.tsx b/visual-testing-app/src/App.tsx
index 8fb8f4f1f1..da2fdfea1e 100644
--- a/visual-testing-app/src/App.tsx
+++ b/visual-testing-app/src/App.tsx
@@ -1,6 +1,6 @@
///
import './globals.css';
-import { BrowserRouter as Router, Route, Switch } from 'react-router-dom';
+import { BrowserRouter as Router, Route, Routes } from 'react-router-dom';
import { ThemeProvider } from '@commercetools-uikit/design-system';
interface TRouteComponent {
@@ -46,11 +46,10 @@ const App = () => {
<>
-
+
(
+ element={
Visual Testing App
@@ -61,25 +60,26 @@ const App = () => {
))}
- )}
+ }
/>
{allSortedComponents.map((Component) => (
}
+ element={}
/>
))}
(
+ path="*"
+ element={
- )}
+ }
/>
-
+
>
);
diff --git a/yarn.lock b/yarn.lock
index 2c5e02e2cf..31fd90e528 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -1952,7 +1952,7 @@ __metadata:
languageName: node
linkType: hard
-"@babel/runtime@npm:^7.1.2, @babel/runtime@npm:^7.10.2, @babel/runtime@npm:^7.12.0, @babel/runtime@npm:^7.12.13, @babel/runtime@npm:^7.12.5, @babel/runtime@npm:^7.14.8, @babel/runtime@npm:^7.15.4, @babel/runtime@npm:^7.16.3, @babel/runtime@npm:^7.17.8, @babel/runtime@npm:^7.18.3, @babel/runtime@npm:^7.20.13, @babel/runtime@npm:^7.21.0, @babel/runtime@npm:^7.22.5, @babel/runtime@npm:^7.5.5, @babel/runtime@npm:^7.7.6, @babel/runtime@npm:^7.7.7, @babel/runtime@npm:^7.8.4, @babel/runtime@npm:^7.8.7, @babel/runtime@npm:^7.9.2":
+"@babel/runtime@npm:^7.1.2, @babel/runtime@npm:^7.10.2, @babel/runtime@npm:^7.12.0, @babel/runtime@npm:^7.12.5, @babel/runtime@npm:^7.14.8, @babel/runtime@npm:^7.15.4, @babel/runtime@npm:^7.16.3, @babel/runtime@npm:^7.17.8, @babel/runtime@npm:^7.18.3, @babel/runtime@npm:^7.20.13, @babel/runtime@npm:^7.21.0, @babel/runtime@npm:^7.22.5, @babel/runtime@npm:^7.5.5, @babel/runtime@npm:^7.7.6, @babel/runtime@npm:^7.7.7, @babel/runtime@npm:^7.8.4, @babel/runtime@npm:^7.8.7, @babel/runtime@npm:^7.9.2":
version: 7.25.0
resolution: "@babel/runtime@npm:7.25.0"
dependencies:
@@ -2435,13 +2435,13 @@ __metadata:
moment-timezone: 0.5.46
react: 17.0.2
react-intl: ^6.3.2
- react-router-dom: 5.3.4
+ react-router-dom: 6
peerDependencies:
moment: 2.x
moment-timezone: 0.5.x
react: 17.x
react-intl: 6.x
- react-router-dom: 5.x
+ react-router-dom: 6.x
languageName: unknown
linkType: soft
@@ -2712,11 +2712,11 @@ __metadata:
"@commercetools-uikit/secondary-icon-button": 19.16.0
react: 17.0.2
react-intl: ^6.3.2
- react-router-dom: 5.3.4
+ react-router-dom: 6
peerDependencies:
react: 17.x
react-intl: 6.x
- react-router-dom: 5.x
+ react-router-dom: 6.x
languageName: unknown
linkType: soft
@@ -2777,13 +2777,12 @@ __metadata:
"@commercetools-uikit/utils": 19.16.0
"@emotion/react": ^11.10.5
"@emotion/styled": ^11.10.5
- "@types/react-router-dom": ^5.3.3
prop-types: 15.8.1
react: 17.0.2
- react-router-dom: 5.3.4
+ react-router-dom: 6
peerDependencies:
react: 17.x
- react-router-dom: 5.x
+ react-router-dom: 6.x
languageName: unknown
linkType: soft
@@ -3315,11 +3314,11 @@ __metadata:
"@commercetools-uikit/time-field": 19.16.0
react: 17.0.2
react-intl: ^6.3.2
- react-router-dom: 5.3.4
+ react-router-dom: 6
peerDependencies:
react: 17.x
react-intl: 6.x
- react-router-dom: 5.x
+ react-router-dom: 6.x
languageName: unknown
linkType: soft
@@ -3513,11 +3512,11 @@ __metadata:
"@commercetools-uikit/toggle-input": 19.16.0
react: 17.0.2
react-intl: ^6.3.2
- react-router-dom: 5.3.4
+ react-router-dom: 6
peerDependencies:
react: 17.x
react-intl: 6.x
- react-router-dom: 5.x
+ react-router-dom: 6.x
languageName: unknown
linkType: soft
@@ -3558,11 +3557,11 @@ __metadata:
prop-types: 15.8.1
react: 17.0.2
react-intl: ^6.3.2
- react-router-dom: 5.3.4
+ react-router-dom: 6
peerDependencies:
react: 17.x
react-intl: 6.x
- react-router-dom: 5.x
+ react-router-dom: 6.x
languageName: unknown
linkType: soft
@@ -3578,17 +3577,15 @@ __metadata:
"@commercetools-uikit/utils": 19.16.0
"@emotion/react": ^11.10.5
"@emotion/styled": ^11.10.5
- "@types/history": ^4.7.11
- "@types/react-router-dom": ^5.3.3
history: 4.10.1
prop-types: 15.8.1
react: 17.0.2
react-intl: ^6.3.2
- react-router-dom: 5.3.4
+ react-router-dom: 6
peerDependencies:
react: 17.x
react-intl: 6.x
- react-router-dom: 5.x
+ react-router-dom: 6.x
languageName: unknown
linkType: soft
@@ -4367,11 +4364,11 @@ __metadata:
prop-types: 15.8.1
react: 17.0.2
react-intl: ^6.3.2
- react-router-dom: 5.3.4
+ react-router-dom: 6
peerDependencies:
react: 17.x
react-intl: 6.x
- react-router-dom: 5.x
+ react-router-dom: 6.x
languageName: unknown
linkType: soft
@@ -4622,10 +4619,10 @@ __metadata:
prop-types: 15.8.1
react: 17.0.2
react-intl: ^6.3.2
- react-router-dom: 5.3.4
+ react-router-dom: 6
peerDependencies:
react: 17.x
- react-router-dom: 5.x
+ react-router-dom: 6.x
languageName: unknown
linkType: soft
@@ -7255,6 +7252,13 @@ __metadata:
languageName: node
linkType: hard
+"@remix-run/router@npm:1.21.0":
+ version: 1.21.0
+ resolution: "@remix-run/router@npm:1.21.0"
+ checksum: d9477a7772053ad0ffcf03385cfb1a54e56f8a56d1f9f5062de3b1dfcbd019dd73282a00a5a72aa55c120771110982448c165c1405d64540aaef13051a8e45cc
+ languageName: node
+ linkType: hard
+
"@rollup/plugin-alias@npm:^3.1.1":
version: 3.1.9
resolution: "@rollup/plugin-alias@npm:3.1.9"
@@ -8743,13 +8747,6 @@ __metadata:
languageName: node
linkType: hard
-"@types/history@npm:^4.7.11":
- version: 4.7.11
- resolution: "@types/history@npm:4.7.11"
- checksum: c92e2ba407dcab0581a9afdf98f533aa41b61a71133420a6d92b1ca9839f741ab1f9395b17454ba5b88cb86020b70b22d74a1950ccfbdfd9beeaa5459fdc3464
- languageName: node
- linkType: hard
-
"@types/hoist-non-react-statics@npm:^3.3.0, @types/hoist-non-react-statics@npm:^3.3.1":
version: 3.3.5
resolution: "@types/hoist-non-react-statics@npm:3.3.5"
@@ -9033,27 +9030,6 @@ __metadata:
languageName: node
linkType: hard
-"@types/react-router-dom@npm:^5.3.3":
- version: 5.3.3
- resolution: "@types/react-router-dom@npm:5.3.3"
- dependencies:
- "@types/history": ^4.7.11
- "@types/react": "*"
- "@types/react-router": "*"
- checksum: 28c4ea48909803c414bf5a08502acbb8ba414669b4b43bb51297c05fe5addc4df0b8fd00e0a9d1e3535ec4073ef38aaafac2c4a2b95b787167d113bc059beff3
- languageName: node
- linkType: hard
-
-"@types/react-router@npm:5.1.20":
- version: 5.1.20
- resolution: "@types/react-router@npm:5.1.20"
- dependencies:
- "@types/history": ^4.7.11
- "@types/react": "*"
- checksum: 128764143473a5e9457ddc715436b5d49814b1c214dde48939b9bef23f0e77f52ffcdfa97eb8d3cc27e2c229869c0cdd90f637d887b62f2c9f065a87d6425419
- languageName: node
- linkType: hard
-
"@types/react-transition-group@npm:^4.4.0":
version: 4.4.11
resolution: "@types/react-transition-group@npm:4.4.11"
@@ -15096,7 +15072,7 @@ __metadata:
languageName: node
linkType: hard
-"history@npm:4.10.1, history@npm:^4.9.0":
+"history@npm:4.10.1":
version: 4.10.1
resolution: "history@npm:4.10.1"
dependencies:
@@ -15110,7 +15086,7 @@ __metadata:
languageName: node
linkType: hard
-"hoist-non-react-statics@npm:^3.1.0, hoist-non-react-statics@npm:^3.3.0, hoist-non-react-statics@npm:^3.3.1, hoist-non-react-statics@npm:^3.3.2":
+"hoist-non-react-statics@npm:^3.3.0, hoist-non-react-statics@npm:^3.3.1, hoist-non-react-statics@npm:^3.3.2":
version: 3.3.2
resolution: "hoist-non-react-statics@npm:3.3.2"
dependencies:
@@ -16128,13 +16104,6 @@ __metadata:
languageName: node
linkType: hard
-"isarray@npm:0.0.1":
- version: 0.0.1
- resolution: "isarray@npm:0.0.1"
- checksum: 49191f1425681df4a18c2f0f93db3adb85573bcdd6a4482539d98eac9e705d8961317b01175627e860516a2fc45f8f9302db26e5a380a97a520e272e2a40a8d4
- languageName: node
- linkType: hard
-
"isarray@npm:^2.0.5":
version: 2.0.5
resolution: "isarray@npm:2.0.5"
@@ -17570,7 +17539,7 @@ __metadata:
languageName: node
linkType: hard
-"loose-envify@npm:^1.0.0, loose-envify@npm:^1.1.0, loose-envify@npm:^1.2.0, loose-envify@npm:^1.3.1, loose-envify@npm:^1.4.0":
+"loose-envify@npm:^1.0.0, loose-envify@npm:^1.1.0, loose-envify@npm:^1.2.0, loose-envify@npm:^1.4.0":
version: 1.4.0
resolution: "loose-envify@npm:1.4.0"
dependencies:
@@ -19758,15 +19727,6 @@ __metadata:
languageName: node
linkType: hard
-"path-to-regexp@npm:^1.7.0":
- version: 1.8.0
- resolution: "path-to-regexp@npm:1.8.0"
- dependencies:
- isarray: 0.0.1
- checksum: 709f6f083c0552514ef4780cb2e7e4cf49b0cc89a97439f2b7cc69a608982b7690fb5d1720a7473a59806508fc2dae0be751ba49f495ecf89fd8fbc62abccbcd
- languageName: node
- linkType: hard
-
"path-to-regexp@npm:^6.3.0":
version: 6.3.0
resolution: "path-to-regexp@npm:6.3.0"
@@ -20632,7 +20592,7 @@ __metadata:
languageName: node
linkType: hard
-"react-is@npm:^16.13.1, react-is@npm:^16.6.0, react-is@npm:^16.7.0":
+"react-is@npm:^16.13.1, react-is@npm:^16.7.0":
version: 16.13.1
resolution: "react-is@npm:16.13.1"
checksum: f7a19ac3496de32ca9ae12aa030f00f14a3d45374f1ceca0af707c831b2a6098ef0d6bdae51bd437b0a306d7f01d4677fcc8de7c0d331eb47ad0f46130e53c5f
@@ -20702,39 +20662,27 @@ __metadata:
languageName: node
linkType: hard
-"react-router-dom@npm:5.3.4":
- version: 5.3.4
- resolution: "react-router-dom@npm:5.3.4"
+"react-router-dom@npm:6":
+ version: 6.28.0
+ resolution: "react-router-dom@npm:6.28.0"
dependencies:
- "@babel/runtime": ^7.12.13
- history: ^4.9.0
- loose-envify: ^1.3.1
- prop-types: ^15.6.2
- react-router: 5.3.4
- tiny-invariant: ^1.0.2
- tiny-warning: ^1.0.0
+ "@remix-run/router": 1.21.0
+ react-router: 6.28.0
peerDependencies:
- react: ">=15"
- checksum: b86a6f2f5222f041e38adf4e4b32c7643d6735a1a915ef25855b2db285fd059d72ba8d62e5bcd5d822b8ef9520a80453209e55077f5a90d0f72e908979b8f535
+ react: ">=16.8"
+ react-dom: ">=16.8"
+ checksum: 0cf4658a92bc66f50ec9d8518c36aa5a402bcadce71fb624ed6f900d73a29ea87ff904a4f2c42279107e75e80cc08c6192563fadcc5d4e642e6d476e38e83b21
languageName: node
linkType: hard
-"react-router@npm:5.3.4":
- version: 5.3.4
- resolution: "react-router@npm:5.3.4"
+"react-router@npm:6, react-router@npm:6.28.0":
+ version: 6.28.0
+ resolution: "react-router@npm:6.28.0"
dependencies:
- "@babel/runtime": ^7.12.13
- history: ^4.9.0
- hoist-non-react-statics: ^3.1.0
- loose-envify: ^1.3.1
- path-to-regexp: ^1.7.0
- prop-types: ^15.6.2
- react-is: ^16.6.0
- tiny-invariant: ^1.0.2
- tiny-warning: ^1.0.0
+ "@remix-run/router": 1.21.0
peerDependencies:
- react: ">=15"
- checksum: 892d4e274a23bf4f39abc2efca54472fb646d3aed4b584020cf49654d2f50d09a2bacebe7c92b4ec7cb8925077376dfcd0664bad6442a73604397cefec9f01f9
+ react: ">=16.8"
+ checksum: 23246ca957b5c2bc8d6f9a81fee2df2ce4fc3feca3ec27c2fd85999568fc1299a4e8273e4ab70b6f3acd43a1fb45e0c93cb01ef77e68c9f9e1f7e4f42a1419ea
languageName: node
linkType: hard
@@ -23644,7 +23592,7 @@ __metadata:
react: 17.0.2
react-dom: 17.0.2
react-intl: ^6.3.2
- react-router-dom: 5.3.4
+ react-router-dom: 6
react-test-renderer: 17.0.2
react-value: 0.2.0
replace: 1.2.2
@@ -24311,8 +24259,8 @@ __metadata:
react: 17.0.2
react-dom: 17.0.2
react-intl: ^6.3.2
- react-router: 5.3.4
- react-router-dom: 5.3.4
+ react-router: 6
+ react-router-dom: 6
vite: 5.4.9
languageName: unknown
linkType: soft