Skip to content

Commit

Permalink
Migrate components to CSS Modules (#2163)
Browse files Browse the repository at this point in the history
  • Loading branch information
connor-baer committed Jul 13, 2023
1 parent 415c73d commit 6ff0b7d
Show file tree
Hide file tree
Showing 434 changed files with 10,822 additions and 58,836 deletions.
5 changes: 5 additions & 0 deletions .changeset/brave-bikes-nail.md
@@ -0,0 +1,5 @@
---
'@sumup/icons': patch
---

Fixed the `IconsManifest` type.
11 changes: 11 additions & 0 deletions .changeset/lucky-monkeys-arrive.md
@@ -0,0 +1,11 @@
---
'@sumup/circuit-ui': major
---

Migrated all [stable](https://circuit.sumup.com/?path=/docs/introduction-component-lifecycle--docs) components from [Emotion.js](https://github.com/emotion-js/emotion) to [CSS Modules](https://github.com/css-modules/css-modules).

The styles are bundled and exported as a single CSS file as `@sumup/circuit-ui/styles.css`. Refer to your framework's documentation on how to include the styles globally in your application.

The CSS file includes the base styles, so the BaseStyles component has been removed.

If you are only importing [stable](https://circuit.sumup.com/?path=/docs/introduction-component-lifecycle--docs) components and aren't using Emotion.js in your app, you can remove all Emotion.js-related dependencies.
5 changes: 5 additions & 0 deletions .changeset/moody-doors-float.md
@@ -0,0 +1,5 @@
---
'@sumup/circuit-ui': minor
---

Improved the accessibility of the SearchInput component. The input now has the `search` type and focus is returned to the input after clearing the value.
4 changes: 2 additions & 2 deletions .github/workflows/ci.yml
Expand Up @@ -39,8 +39,8 @@ jobs:
- name: Lint code
run: npm run lint

# - name: Lint styles
# run: npm run lint:css
- name: Lint styles
run: npm run lint:css

- name: Run unit tests
run: npm run test:ci
Expand Down
6 changes: 0 additions & 6 deletions .storybook/components/DocsContainer.tsx
@@ -1,10 +1,7 @@
// import { useEffect, useState } from 'react';
import { ThemeProvider } from '@emotion/react';
import { DocsContainer as BaseContainer } from '@storybook/addon-docs';

import * as themes from '../themes';
import { BaseStyles } from '@sumup/circuit-ui';
import { light } from '@sumup/design-tokens';

/**
* Automatically switch light/dark theme based on system preferences
Expand All @@ -30,9 +27,6 @@ const DocsContainer: typeof BaseContainer = ({ children, context }) => {

return (
<BaseContainer context={context} theme={themes.light}>
<ThemeProvider theme={light}>
<BaseStyles />
</ThemeProvider>
{children}
</BaseContainer>
);
Expand Down
54 changes: 54 additions & 0 deletions .storybook/components/Icons.module.css
@@ -0,0 +1,54 @@
.filters {
display: grid;
grid-template-columns: 2fr 1fr 1fr;
gap: var(--cui-spacings-kilo);
margin-top: var(--cui-spacings-tera);
margin-bottom: var(--cui-spacings-peta);
}

.category {
margin-bottom: var(--cui-spacings-tera);
}

.list {
display: flex;
flex-wrap: wrap;
}

.wrapper {
position: relative;
width: 7.5rem;
margin-top: var(--cui-spacings-giga);
margin-bottom: var(--cui-spacings-giga);
text-align: center;
}

.size {
display: block;
font-style: italic;
color: var(--cui-fg-subtle);
}

.icon-wrapper {
display: flex;
align-items: center;
justify-content: center;
height: 64px; /* 2 * 32px icon */
}

.icon {
max-width: 3rem;
transform: scale(2);
}

.label {
font-size: var(--cui-typography-body-two-font-size);
line-height: var(--cui-typography-body-two-line-height);
}

.badge {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%) rotate(-30deg);
}
116 changes: 36 additions & 80 deletions .storybook/components/Icons.tsx
Expand Up @@ -14,9 +14,7 @@
*/

import { useState } from 'react';
import styled from '@emotion/styled';
import { css, ThemeProvider } from '@emotion/react';
import { light } from '@sumup/design-tokens';
import { Unstyled } from '@storybook/addon-docs';
import * as iconComponents from '@sumup/icons';
import type { IconsManifest } from '@sumup/icons';
import iconsManifest from '@sumup/icons/manifest.json';
Expand All @@ -25,19 +23,24 @@ import {
Body,
SearchInput,
Select,
typography,
BaseStyles,
Badge,
} from '@sumup/circuit-ui';
} from '../../packages/circuit-ui/index.js';
import classes from './Icons.module.css';

function groupBy(icons: IconsManifest['icons'], key: string) {
function groupBy(
icons: IconsManifest['icons'],
key: keyof IconsManifest['icons'][0],
) {
return icons.reduce((groups, icon) => {
(groups[icon[key]] = groups[icon[key]] || []).push(icon);
return groups;
}, {});
}

function sortBy(icons: IconsManifest['icons'], key: string) {
function sortBy(
icons: IconsManifest['icons'],
key: keyof IconsManifest['icons'][0],
) {
return icons.sort((iconA, iconB) => {
return iconA[key].localeCompare(iconB[key]);
});
Expand All @@ -53,61 +56,6 @@ function getComponentName(name: string) {
return pascalCased.join('');
}

const Filters = styled.div`
display: grid;
grid-template-columns: 2fr 1fr 1fr;
gap: ${(p) => p.theme.spacings.kilo};
margin-top: ${(p) => p.theme.spacings.tera};
margin-bottom: ${(p) => p.theme.spacings.peta};
`;

const Category = styled.section`
margin-bottom: ${(p) => p.theme.spacings.tera};
`;

const List = styled.div`
display: flex;
flex-wrap: wrap;
`;

const Wrapper = styled.div`
width: 7.5rem;
text-align: center;
margin-top: ${(p) => p.theme.spacings.giga};
margin-bottom: ${(p) => p.theme.spacings.giga};
position: relative;
`;

const Size = styled.span`
display: block;
color: var(--cui-fg-subtle);
font-style: italic;
`;

const IconWrapper = styled.div`
display: flex;
align-items: center;
justify-content: center;
height: 64px; /* 2 * 32px icon */
`;

const iconStyles = (color: string) =>
css`
transform: scale(2);
max-width: 3rem;
color: ${color};
background-color: ${color === 'var(--cui-fg-on-strong)'
? 'var(--cui-bg-strong)'
: 'var(--cui-bg-normal)'};
`;

const badgeStyles = css`
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%) rotate(-30deg);
`;

const Icons = () => {
const [search, setSearch] = useState('');
const [size, setSize] = useState('all');
Expand Down Expand Up @@ -148,9 +96,8 @@ const Icons = () => {
);

return (
<ThemeProvider theme={light}>
<BaseStyles />
<Filters>
<Unstyled>
<div className={classes.filters}>
<SearchInput
label="Filter icons by name"
placeholder="Search..."
Expand All @@ -171,53 +118,62 @@ const Icons = () => {
value={color}
onChange={handleColorChange}
/>
</Filters>
</div>

{activeIcons.length <= 0 ? (
<Body>No icons found</Body>
) : (
Object.entries<IconsManifest['icons']>(
groupBy(activeIcons, 'category'),
).map(([category, items]) => (
<Category key={category}>
<section key={category} className={classes.category}>
<Headline as="h3" size="three">
{category}
</Headline>
<List>
<div className={classes.list}>
{sortBy(items, 'name').map((icon) => {
const id = `${icon.name}-${icon.size}`;
const componentName = getComponentName(icon.name);
const Icon = iconComponents[componentName];
return (
<Wrapper key={id}>
<IconWrapper>
<div key={id} className={classes.wrapper}>
<div className={classes['icon-wrapper']}>
<Icon
aria-labelledby={id}
size={icon.size}
css={iconStyles(color)}
className={classes.icon}
style={{
color,
backgroundColor:
color === 'var(--cui-fg-on-strong)'
? 'var(--cui-bg-strong)'
: 'var(--cui-bg-normal)',
}}
/>
</IconWrapper>
<span id={id} css={typography('two')}>
</div>
<span id={id} className={classes.label}>
{icon.name}
{size === 'all' && <Size>{icon.size}</Size>}
{size === 'all' && (
<span className={classes.size}>{icon.size}</span>
)}
</span>
{icon.deprecation && (
<Badge
title={icon.deprecation}
variant="warning"
css={badgeStyles}
className={classes.badge}
>
Deprecated
</Badge>
)}
</Wrapper>
</div>
);
})}
</List>
</Category>
</div>
</section>
))
)}
</ThemeProvider>
</Unstyled>
);
};

Expand Down
13 changes: 5 additions & 8 deletions .storybook/components/Image.tsx
Expand Up @@ -13,14 +13,11 @@
* limitations under the License.
*/

import { ThemeProvider } from '@emotion/react';
import { light } from '@sumup/design-tokens';
import { Image as BaseImage, ImageProps } from '@sumup/circuit-ui';
import {
Image as BaseImage,
ImageProps,
} from '../../packages/circuit-ui/index.js';

const Image = ({ children, ...props }: ImageProps) => (
<ThemeProvider theme={light}>
<BaseImage {...props} />
</ThemeProvider>
);
const Image = ({ children, ...props }: ImageProps) => <BaseImage {...props} />;

export default Image;
8 changes: 8 additions & 0 deletions .storybook/components/Intro.module.css
@@ -0,0 +1,8 @@
.base {
margin-bottom: var(--cui-spacings-giga);
}

.base > * {
font-size: var(--cui-typography-body-large-font-size) !important;
line-height: var(--cui-typography-body-large-line-height) !important;
}
31 changes: 6 additions & 25 deletions .storybook/components/Intro.tsx
Expand Up @@ -13,23 +13,11 @@
* limitations under the License.
*/

import { css, ThemeProvider } from '@emotion/react';
import { BodyLarge, spacing, cx } from '@sumup/circuit-ui';
import { light } from '@sumup/design-tokens';
import { BodyLarge } from '../../packages/circuit-ui/index.js';

import type { BodyLargeProps } from '@sumup/circuit-ui';
import type { Theme } from '@sumup/design-tokens';
import type { BodyLargeProps } from '../../packages/circuit-ui/index.js';

/**
* We need this to force children to have bodyLarge typography when the Intro
* is rendered as a div.
*/
const childrenBodyLargeStyles = (theme: Theme) => css`
> * {
font-size: ${theme.typography.bodyLarge.fontSize} !important;
line-height: ${theme.typography.bodyLarge.lineHeight} !important;
}
`;
import classes from './Intro.module.css';

function Intro({
children,
Expand All @@ -38,16 +26,9 @@ function Intro({
children: BodyLargeProps['children'];
}): JSX.Element {
return (
<ThemeProvider theme={light}>
<BodyLarge
as="div"
variant="subtle"
css={cx(childrenBodyLargeStyles, spacing({ bottom: 'giga' }))}
{...props}
>
{children}
</BodyLarge>
</ThemeProvider>
<BodyLarge as="div" variant="subtle" className={classes.base} {...props}>
{children}
</BodyLarge>
);
}

Expand Down
19 changes: 19 additions & 0 deletions .storybook/components/Stack.module.css
@@ -0,0 +1,19 @@
.base {
display: flex;
flex-direction: column;
gap: 2rem;
align-items: center;
justify-content: center;
}

@media screen and (min-width: 600px) {
.base {
flex-direction: row;
}
}

@media screen and (min-width: 600px) {
.vertical {
flex-direction: column;
}
}

0 comments on commit 6ff0b7d

Please sign in to comment.