Skip to content

Commit 77d675d

Browse files
connor-baersirineJ
andauthored
Add migration guide for v9 (#2739)
Co-authored-by: sirineJ <[email protected]>
1 parent b10f233 commit 77d675d

File tree

5 files changed

+223
-44
lines changed

5 files changed

+223
-44
lines changed

MIGRATION.md

Lines changed: 200 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,207 @@
22

33
## 🤖 Automated migration
44

5-
Some of the changes in this guide can be automated using [`@sumup/eslint-plugin-circuit-ui`](https://circuit.sumup.com/?path=/docs/packages-eslint-plugin-circuit-ui--docs). Changes that can be automated are marked with a robot emoji (🤖) and the name of the ESLint rule (e.g. _no-deprecated-props_)
5+
Some of the changes in this guide can be automated using the [ESLint](https://circuit.sumup.com/?path=/docs/packages-eslint-plugin-circuit-ui--docs) and [Stylelint](https://circuit.sumup.com/?path=/docs/packages-stylelint-plugin-circuit-ui--docs) plugins. Changes that can be automated are marked with a robot emoji (🤖) and the name of the rule (e.g. _no-deprecated-props_)
66

77
We encourage you to enable and apply the rules incrementally and review the changes before continuing. The rules don't cover all edge cases, so further manual changes might be necessary. For example, the ESLint rules only analyze one file at a time, so if a Circuit UI component is wrapped in a styled component in one file and used in another, ESLint won't be able to update its props.
88

99
Prior to v5, codemods were implemented using [jscodeshift](#-codemods-jscodeshift).
1010

11+
## From v8.x to v9
12+
13+
Circuit UI v9 introduces a [new typeface](#new-typeface), more flexible [typography APIs](#typography-apis), and [stable input components](#stable-components) for colors, dates, and phone numbers. For a complete list of changes, refer to the [changelog](https://github.com/sumup-oss/circuit-ui/blob/main/packages/circuit-ui/CHANGELOG.md).
14+
15+
### Prerequisites
16+
17+
Circuit UI now requires at minimum Node.js v20. Note that [Node 18](https://nodejs.org/en/about/previous-releases) reached its end-of-life in October 2024.
18+
19+
We strongly recommend upgrading to [Foundry v8.3+](https://github.com/sumup-oss/foundry/blob/main/CHANGELOG.md#830) which adds support for the Circuit UI ESLint plugin's [new package scope](#renamed-package-scope) and prevents dependency conflicts in the shared [`@typescript-eslint/*`](https://github.com/typescript-eslint/typescript-eslint) dependencies. If you're unable to upgrade, manually add the Circuit UI ESLint plugin to your ESLint config and enable the relevant rules.
20+
21+
### Renamed package scope
22+
23+
The packages have moved from the `@sumup` to the `@sumup-oss` scope to avoid conflicts with private packages. To get started, remove the old design system packages, then install the new ones:
24+
25+
```sh
26+
npm uninstall @sumup/circuit-ui @sumup/design-tokens @sumup/icons @sumup/intl
27+
npm install @sumup-oss/circuit-ui @sumup-oss/design-tokens @sumup-oss/icons @sumup-oss/intl temporal-polyfill
28+
```
29+
30+
Note that [`temporal-polyfill`](https://www.npmjs.com/package/temporal-polyfill) is a new required peer dependency and that the [`@sumup-oss/intl`](https://www.npmjs.com/package/@sumup-oss/intl) peer dependency has been upgraded to v3. If your app also depends on `@sumup-oss/intl` (previously called `@sumup/intl`), you need to upgrade it as well. Refer to its [changelog](https://github.com/sumup-oss/intl-js/blob/main/CHANGELOG.md) for migration instructions.
31+
32+
Follow the same process to upgrade any linter plugins your app is using:
33+
34+
```sh
35+
# ESLint
36+
npm uninstall @sumup/eslint-plugin-circuit-ui
37+
npm install @sumup-oss/eslint-plugin-circuit-ui
38+
# Stylelint
39+
npm uninstall @sumup/stylelint-plugin-circuit-ui
40+
npm install @sumup-oss/stylelint-plugin-circuit-ui
41+
```
42+
43+
Update any static and dynamic imports to the new package scope (🤖 `renamed-package-scope`). The ESLint rule might not catch all occurrences of the old package names, so manually search for and fix any left-overs after applying the ESLint rule. For example:
44+
45+
```diff
46+
-import { Button, type ButtonProps } from '@sumup/circuit-ui';
47+
+import { Button, type ButtonProps } from '@sumup-oss/circuit-ui';
48+
49+
-jest.mock('@sumup-oss/circuit-ui', () => ({
50+
- ...jest.requireActual<typeof import('@sumup-oss/circuit-ui')>(
51+
- '@sumup-oss/circuit-ui',
52+
- ),
53+
-}));
54+
+jest.mock('@sumup-oss/circuit-ui', () => ({
55+
+ ...jest.requireActual<typeof import('@sumup-oss/circuit-ui')>(
56+
+ '@sumup-oss/circuit-ui',
57+
+ ),
58+
+}));
59+
```
60+
61+
### New typeface
62+
63+
The default typeface has changed from [Aktiv Grotesk](https://www.daltonmaag.com/font-library/aktiv-grotesk.html) to [Inter](https://rsms.me/inter/), a variable font. Variable fonts combine a continuous range of weights and other "axes" into a single file. This speeds up page load times and enables more creative freedom. Inter is a close match to Aktiv Grotesk, so the change should be seamless.
64+
65+
Circuit UI no longer loads the fonts by default. Instead, import the stylesheet that contains the font face declarations globally in your application, such as in a global layout file:
66+
67+
```ts
68+
import '@sumup-oss/design-tokens/fonts.css';
69+
```
70+
71+
To speed up the loading of the fonts, add preload links to the global `<head>` element of your application. Choose which subsets to preload based on the languages your app supports. The available subsets are `latin`, `latin-ext`, `cyrillic`, `cyrillic-ext`, `greek`, `greek-ext`, and `vietnamese`.
72+
73+
```html
74+
<link
75+
rel="preload"
76+
href="https://static.sumup.com/fonts/Inter/Inter-normal-latin.woff2"
77+
as="font"
78+
type="font/woff2"
79+
crossorigin
80+
/>
81+
```
82+
83+
### Typography APIs
84+
85+
The typography components have been redesigned to improve visual hierarchy, ensure consistency across platforms and provide more flexible APIs for developers. The changes are fully backward compatible and can be adopted gradually.
86+
87+
#### Consistent names
88+
89+
The Title component has been renamed to Display for consistency with other platforms. The SubHeadline component has been deprecated in favor of the Headline component in size `s`. The BodyLarge component has been deprecated in favor of the Body component in size `l` (🤖 `no-deprecated-components`).
90+
91+
#### Flexible props
92+
93+
The Body component's `variant` prop has been split into individual `color`, `weight` and `decoration` props. Use the `color` prop instead of the `alert`, `confirm` and `subtle` variants, use the `weight` prop instead of the `highlight` variant, and use custom CSS to replicate the `quote` variant (🤖 `no-renamed-props`). The new `decoration` prop makes it easier to apply `italic` and `strikethrough` styles.
94+
95+
The sizes of the Display (formerly Title), Headline, and Body components have been consolidated and renamed to enforce greater visual hierarchy. Here's how the old size names map to the new ones (🤖 `no-renamed-props`):
96+
97+
**Display**
98+
99+
| Old | New |
100+
| ----- | --- |
101+
| one | l |
102+
| two | m |
103+
| three | m |
104+
| four | s |
105+
106+
**Headline**
107+
108+
| Old | New |
109+
| ----- | --- |
110+
| one | l |
111+
| two | m |
112+
| three | s |
113+
| four | s |
114+
115+
**Body**
116+
117+
| Old | New |
118+
| --- | --- |
119+
| one | m |
120+
| two | s |
121+
122+
The typography design tokens have been updated accordingly (🤖 `no-deprecated-custom-properties` (ESLint & Stylelint)):
123+
124+
| Old | New |
125+
| --------------------------------------- | ------------------------ |
126+
| `typography-title-one-font-size` | `display-l-font-size` |
127+
| `typography-title-one-line-height` | `display-l-line-height` |
128+
| `typography-title-two-font-size` | `display-m-font-size` |
129+
| `typography-title-two-line-height` | `display-m-line-height` |
130+
| `typography-title-three-font-size` | `display-m-font-size` |
131+
| `typography-title-three-line-height` | `display-m-line-height` |
132+
| `typography-title-four-font-size` | `display-s-font-size` |
133+
| `typography-title-four-line-height` | `display-s-line-height` |
134+
| `typography-headline-one-font-size` | `headline-l-font-size` |
135+
| `typography-headline-one-line-height` | `headline-l-line-height` |
136+
| `typography-headline-two-font-size` | `headline-m-font-size` |
137+
| `typography-headline-two-line-height` | `headline-m-line-height` |
138+
| `typography-headline-three-font-size` | `headline-m-font-size` |
139+
| `typography-headline-three-line-height` | `headline-m-line-height` |
140+
| `typography-headline-four-font-size` | `headline-s-font-size` |
141+
| `typography-headline-four-line-height` | `headline-s-line-height` |
142+
| `typography-sub-headline-font-size` | `headline-s-font-size` |
143+
| `typography-sub-headline-line-height` | `headline-s-line-height` |
144+
| `typography-body-large-font-size` | `body-l-font-size` |
145+
| `typography-body-large-line-height` | `body-l-line-height` |
146+
| `typography-body-one-font-size` | `body-m-font-size` |
147+
| `typography-body-one-line-height` | `body-m-line-height` |
148+
| `typography-body-two-font-size` | `body-s-font-size` |
149+
| `typography-body-two-line-height` | `body-s-line-height` |
150+
151+
#### New components
152+
153+
The new Compact component should be used to label information in space-constraint contexts.
154+
155+
The new Numeral component should be used to give emphasis to numerical content such as currency values.
156+
157+
### Stable components
158+
159+
All experimental components are now stable.
160+
161+
- The Calendar and DateInput components have been rebuilt from scratch for better performance and accessibility. They replace the legacy RangePicker, RangePickerController, SingleDayPicker, CalendarTag, and CalendarTagTwoStep components, which have been removed. The DateInput component now requires additional localized label props.
162+
- The ColorInput and PhoneNumberInput components enable users to enter hex colors and phone numbers respectively.
163+
- The Tooltip and Toggletip components have been rebuilt from scratch for improved accessibility. They replace the legacy Tooltip component.
164+
165+
Update the related imports (🤖 `component-lifecycle-imports`). For example:
166+
167+
```diff
168+
- import { Calendar, type CalendarProps, type PlainDateRange } from '@sumup-oss/circuit-ui/experimental';
169+
+ import { Calendar, type CalendarProps, type PlainDateRange } from '@sumup-oss/circuit-ui';
170+
```
171+
172+
### Other changes
173+
174+
- Changed the `PlainDateRange` type from an array to an object with start and end properties. This affects the Calendar component's `selection` prop. Use the new `updatePlainDateRange` helper function to update a date range when a user selects a date:
175+
176+
```tsx
177+
import { useState } from 'react';
178+
import { Calendar, updatePlainDateRange } from '@sumup-oss/circuit-ui';
179+
180+
function Component() {
181+
const [selection, setSelection] = useState({});
182+
return (
183+
<Calendar
184+
onSelect={setSelection((prevSelection) =>
185+
updatePlainDateRange(prevSelection, date)
186+
)}
187+
/>
188+
);
189+
}
190+
```
191+
192+
- Deprecated the `InputElement` interface and narrowed the Input component's element type to `HTMLInputElement` and the TextArea component's element type to `HTMLTextAreaElement`. This affects `ref`s and event handlers.
193+
194+
```diff
195+
-import { InputElement } from '@sumup-oss/circuit-ui';
196+
197+
-ChangeHandler<InputElement>
198+
+ChangeHandler<HTMLInputElement>
199+
200+
-useRef<InputElement>()
201+
+useRef<HTMLInputElement>()
202+
```
203+
204+
- Removed the Table component's deprecated `initialSortedRow` prop. Use the `initialSortedColumn` prop instead (🤖 `no-renamed-props`).
205+
11206
## From v7.x to v8
12207

13208
Circuit UI v8 introduces a redesigned Button component and switches the brand color from blue to black.
@@ -71,7 +266,7 @@ expect.extend({
71266
this.utils.matcherHint(
72267
`${this.isNot ? '.not' : ''}.toBeDisabled`,
73268
'element',
74-
'',
269+
''
75270
),
76271
'',
77272
`Received element ${is} disabled:`,
@@ -92,7 +287,7 @@ expect.extend({
92287
this.utils.matcherHint(
93288
`${this.isNot ? '.not' : ''}.toBeEnabled`,
94289
'element',
95-
'',
290+
''
96291
),
97292
'',
98293
`Received element ${is} enabled:`,
@@ -724,7 +919,7 @@ import styled from 'util/styled';
724919
const RedCard = styled(Card)(
725920
({ theme }) => css`
726921
background-color: red;
727-
`,
922+
`
728923
);
729924
```
730925
@@ -750,7 +945,7 @@ import styled from '@emotion/styled';
750945
const RedCard = styled(Card)(
751946
({ theme }) => css`
752947
background-color: red;
753-
`,
948+
`
754949
);
755950
```
756951

packages/design-tokens/README.md

Lines changed: 1 addition & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -40,8 +40,6 @@ Refer to the [theme documentation](https://circuit.sumup.com/?path=/docs/feature
4040

4141
### Fonts
4242

43-
#### Default
44-
4543
Import the stylesheet that contains the font face declarations globally in your application, such as in a global layout file:
4644

4745
```ts
@@ -60,33 +58,7 @@ To speed up the loading of the fonts, add preload links to the global `<head>` e
6058
/>
6159
```
6260

63-
#### Next.js
64-
65-
If you're using Next.js 13+, use the built-in [font optimization](https://nextjs.org/docs/app/building-your-application/optimizing/fonts) feature with this recommended configuration instead:
66-
67-
```tsx
68-
// app/layout.tsx
69-
import { Inter } from 'next/font/google';
70-
71-
const inter = Inter({
72-
// Choose which subsets to preload based on the languages your app supports
73-
subsets: ['latin'],
74-
// Note that Next.js <14.2.6 contains outdated Google Fonts data which prevents
75-
// usage of the `ital` axis (see https://github.com/vercel/next.js/issues/68395)
76-
axes: ['ital'],
77-
variable: '--cui-font-stack-default',
78-
display: 'swap',
79-
preload: true,
80-
});
81-
82-
export default function RootLayout({ children }) {
83-
return (
84-
<html lang="en">
85-
<body className={inter.variable}>{children}</body>
86-
</html>
87-
);
88-
}
89-
```
61+
Do not use Next.js' built-in font optimization as it doesn't support Inter's italic axis.
9062

9163
### Color schemes
9264

packages/eslint-plugin-circuit-ui/no-renamed-props/index.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -253,6 +253,13 @@ const configs: (Config & { components: string[] })[] = [
253253
});
254254
},
255255
},
256+
{
257+
type: 'name',
258+
components: ['Table'],
259+
props: {
260+
initialSortedRow: 'initialSortedColumn',
261+
},
262+
},
256263
{
257264
type: 'values',
258265
components: ['Title', 'Display'],

templates/nextjs/template/app/layout.tsx

Lines changed: 4 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,10 @@
11
import type { Metadata, Viewport } from 'next';
2-
import { Inter } from 'next/font/google';
32

3+
import '@sumup-oss/design-tokens/fonts.css';
44
import '@sumup-oss/design-tokens/light.css';
55
import '@sumup-oss/circuit-ui/styles.css';
66

7-
const inter = Inter({
8-
subsets: ['latin'],
9-
// FIXME: Re-enable once https://github.com/vercel/next.js/issues/68395 has been resolved
10-
// axes: ['ital'],
11-
variable: '--cui-font-stack-default',
12-
display: 'swap',
13-
preload: true,
14-
});
7+
import { PreloadResources } from './preload-resources';
158

169
export const metadata: Metadata = {
1710
title: {
@@ -42,7 +35,8 @@ export default function RootLayout({
4235
children: React.ReactNode;
4336
}) {
4437
return (
45-
<html lang="en" className={inter.variable}>
38+
<html lang="en">
39+
<PreloadResources />
4640
<body>{children}</body>
4741
</html>
4842
);
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
'use client';
2+
3+
import ReactDOM from 'react-dom';
4+
5+
export function PreloadResources() {
6+
ReactDOM.preload(
7+
'https://static.sumup.com/fonts/Inter/Inter-normal-latin.woff2',
8+
{ as: 'font' },
9+
);
10+
return null;
11+
}

0 commit comments

Comments
 (0)