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/README.md b/README.md index 1ea19e7e37..38a918ec6a 100644 --- a/README.md +++ b/README.md @@ -130,3 +130,4 @@ const primary = designTokens.colorPrimary; ``` > Please look at the [`design-tokens.ts`](https://github.com/commercetools/ui-kit/blob/main/design-system/src/design-tokens.ts) itself to inspect which variables are available. +> test 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..d118c4b1ba 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,7 +126,7 @@ const DefaultRoute = () => ( ); const InteractionRoute = () => ( - + ( @@ -163,12 +163,12 @@ const InteractionRoute = () => ( )} /> - + ); 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..e17273a677 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,7 +126,7 @@ const DefaultRoute = () => ( ); const InteractionRoute = () => ( - + ( @@ -163,12 +163,12 @@ const InteractionRoute = () => ( )} /> - + ); export const component = () => ( - + - + ); diff --git a/packages/components/icons/src/icons.visualroute.jsx b/packages/components/icons/src/icons.visualroute.jsx index 2011e5c122..e37b71489d 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,7 +83,7 @@ const renderIcon = (iconName, color, size) => { }; export const component = () => ( - +