Skip to content

Commit

Permalink
feat(components): migrate SubHeading to TypeScript (#612)
Browse files Browse the repository at this point in the history
* feat(components): migrate SubHeading to TypeScript

BREAKING CHANGE:
The SubHeading component doesn't export sizes anymore. Instead of writing `size={SubHeading.KILO}`, write `size="kilo"`.
  • Loading branch information
Robin Métral authored Jun 9, 2020
1 parent 23eb9e8 commit 36a4bb5
Show file tree
Hide file tree
Showing 11 changed files with 85 additions and 107 deletions.
4 changes: 2 additions & 2 deletions .storybook/util/theme.js
Original file line number Diff line number Diff line change
Expand Up @@ -57,12 +57,12 @@ export const components = {
}),
h4: withThemeProvider(SubHeading, {
as: 'h4',
size: SubHeading.MEGA,
size: 'mega',
css: subHeadingStyles
}),
h5: withThemeProvider(SubHeading, {
as: 'h5',
size: SubHeading.KILO,
size: 'kilo',
css: subHeadingStyles
}),
p: withThemeProvider(Text, { as: 'p', size: TEXT_SIZE }),
Expand Down
8 changes: 4 additions & 4 deletions scripts/static-styles/config.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,6 @@ import {
RadioButton,
Select,
Selector,
SubHeading,
Tag,
TextArea,
Toggle
Expand Down Expand Up @@ -175,9 +174,10 @@ export default {
renderPrefix: PropTypes.element
}),
{ name: 'selector', component: Selector },
getComponentInfo(SubHeading, {
size: [SubHeading.KILO, SubHeading.MEGA]
}),
// TODO: Make React DocGen work with TypeScript
// getComponentInfo(SubHeading, {
// size: ['kilo', 'mega']
// }),
getComponentInfo(Tag, {
onRemove: PropTypes.func,
prefix: PropTypes.element,
Expand Down
6 changes: 3 additions & 3 deletions src/__snapshots__/storyshots.spec.js.snap
Original file line number Diff line number Diff line change
Expand Up @@ -24098,7 +24098,7 @@ exports[`Storyshots Typography/SubHeading Base 1`] = `
}
<h2
class=" circuit-0 circuit-1"
class="circuit-0"
>
This is a subheading
</h2>
Expand All @@ -24115,7 +24115,7 @@ HTMLCollection [
}
<h3
class=" circuit-0 circuit-1"
class="circuit-0"
>
This is a
mega
Expand All @@ -24130,7 +24130,7 @@ HTMLCollection [
}
<h3
class=" circuit-0 circuit-1"
class="circuit-0"
>
This is a
kilo
Expand Down
2 changes: 1 addition & 1 deletion src/components/Heading/Heading.spec.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ describe('Heading', () => {
const elements = ['h1', 'h2', 'h3', 'h4', 'h5', 'h6'];
it.each(elements)(`should render as %s element`, element => {
const heading = create(
<Heading as={element}>{`${element.toUpperCase()} heading`}</Heading>
<Heading as={element}>{`${element} heading`}</Heading>
);
expect(heading).toMatchSnapshot();
});
Expand Down
12 changes: 6 additions & 6 deletions src/components/Heading/__snapshots__/Heading.spec.tsx.snap
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ exports[`Heading should render as h1 element 1`] = `
<h1
class="circuit-0"
>
H1 heading
h1 heading
</h1>
`;

Expand All @@ -40,7 +40,7 @@ exports[`Heading should render as h2 element 1`] = `
<h2
class="circuit-0"
>
H2 heading
h2 heading
</h2>
`;

Expand All @@ -62,7 +62,7 @@ exports[`Heading should render as h3 element 1`] = `
<h3
class="circuit-0"
>
H3 heading
h3 heading
</h3>
`;

Expand All @@ -84,7 +84,7 @@ exports[`Heading should render as h4 element 1`] = `
<h4
class="circuit-0"
>
H4 heading
h4 heading
</h4>
`;

Expand All @@ -106,7 +106,7 @@ exports[`Heading should render as h5 element 1`] = `
<h5
class="circuit-0"
>
H5 heading
h5 heading
</h5>
`;

Expand All @@ -128,7 +128,7 @@ exports[`Heading should render as h6 element 1`] = `
<h6
class="circuit-0"
>
H6 heading
h6 heading
</h6>
`;

Expand Down
3 changes: 1 addition & 2 deletions src/components/SubHeading/SubHeading.docs.mdx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Status, Props, Story } from '../../../.storybook/components';
import SubHeading from './SubHeading';
import { SubHeading } from './SubHeading';

# Subheadings

Expand All @@ -9,7 +9,6 @@ Subheadings help users break through larger related contents in the same section
They are usually used to separate sections within a card.

<Story id="typography-subheading--base" />

<Props of={SubHeading} />

## Usage guidelines
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,30 +15,28 @@

import React from 'react';

import SubHeading from '.';
import { create, renderToHtml, axe } from '../../util/test-utils';

import { SubHeading } from './SubHeading';

describe('SubHeading', () => {
/**
* Style tests.
*/
const elements = ['h2', 'h3', 'h4', 'h5', 'h6'];
elements.forEach(as => {
it(`should render as ${as.toUpperCase()} element, when passed "${as}" for the element prop`, () => {
const heading = create(
<SubHeading as={as}>{`${as.toUpperCase()} heading`}</SubHeading>
);
expect(heading).toMatchSnapshot();
});
it.each(elements)(`should render as %s element`, element => {
const subheading = create(
<SubHeading as={element}>{`${element} subheading`}</SubHeading>
);
expect(subheading).toMatchSnapshot();
});

const sizes = ['kilo', 'mega'];
sizes.forEach(size => {
it(`should render with size ${size}, when passed "${size}" for the size prop`, () => {
const heading = create(
<SubHeading {...{ size }}>{`${size} heading`}</SubHeading>
);
expect(heading).toMatchSnapshot();
});
const sizes = ['kilo', 'mega'] as const;
it.each(sizes)(`should render with size %s`, size => {
const subheading = create(
<SubHeading {...{ size }}>{`${size} subheading`}</SubHeading>
);
expect(subheading).toMatchSnapshot();
});

it('should render with no margin styles when passed the noMargin prop', () => {
Expand All @@ -50,7 +48,7 @@ describe('SubHeading', () => {
* Accessibility tests.
*/
it('should meet accessibility guidelines', async () => {
const wrapper = renderToHtml(<SubHeading>Sub heading</SubHeading>);
const wrapper = renderToHtml(<SubHeading>Subheading</SubHeading>);
const actual = await axe(wrapper);
expect(actual).toHaveNoViolations();
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,13 @@
*/

import React from 'react';
import { select, boolean, text } from '@storybook/addon-knobs/react';
import { select, boolean, text } from '@storybook/addon-knobs';

import SubHeading from './SubHeading';
import { SubHeading } from './SubHeading';
import docs from './SubHeading.docs.mdx';

const elements = ['h2', 'h3', 'h4', 'h5', 'h6'];
const sizes = ['mega', 'kilo'];
const sizes = ['mega', 'kilo'] as const;

export default {
title: 'Typography/SubHeading',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,75 +13,56 @@
* limitations under the License.
*/

import React from 'react';
import PropTypes from 'prop-types';
import styled from '@emotion/styled';
import { FC, HTMLProps } from 'react';
import { css } from '@emotion/core';
import isPropValid from '@emotion/is-prop-valid';

import { childrenPropType } from '../../util/shared-prop-types';
import styled, { StyleProps } from '../../styles/styled';

const baseStyles = ({ theme }) => css`
type Size = 'kilo' | 'mega';

export interface SubHeadingProps
extends Omit<HTMLProps<HTMLHeadingElement>, 'size'> {
/**
* A Circuit UI subheading size.
*/
size?: Size;
/**
* Removes the default bottom margin from the subheading.
*/
noMargin?: boolean;
/**
* The HTML subheading element to render.
*/
as?: string;
}

const baseStyles = ({ theme }: StyleProps) => css`
label: sub-heading;
text-transform: uppercase;
font-weight: ${theme.fontWeight.bold};
margin-bottom: ${theme.spacings.kilo};
`;

const sizeStyles = ({ theme, size }) =>
const sizeStyles = ({ theme, size = 'kilo' }: StyleProps & SubHeadingProps) =>
size &&
css`
label: ${`sub-heading--${size}`};
font-size: ${theme.typography.subHeadings[size].fontSize};
line-height: ${theme.typography.subHeadings[size].lineHeight};
`;

const noMarginStyles = ({ noMargin }) =>
const noMarginStyles = ({ noMargin }: SubHeadingProps) =>
noMargin &&
css`
label: sub-heading--no-margin;
margin-bottom: 0;
`;

const SubHeadingElement = styled('h3')(baseStyles, sizeStyles, noMarginStyles);

/**
* A flexible subheading component capable of rendering using any HTML heading
* tag, except h1.
*/

const SubHeading = props => <SubHeadingElement {...props} />;

SubHeading.propTypes = {
/**
* Child nodes to be rendered.
*/
children: childrenPropType,
/**
* A Circuit UI sub-heading size.
*/
size: PropTypes.oneOf(['kilo', 'mega']),
/**
* Optional additional className string to overwrite styles.
*/
className: PropTypes.string,
/**
* Removes the default bottom margin from the subheading.
*/
noMargin: PropTypes.bool,
/**
* The HTML heading element to render.
*/
as: PropTypes.oneOf(['h2', 'h3', 'h4', 'h5', 'h6'])
};

SubHeading.defaultProps = {
size: 'kilo',
className: '',
noMargin: false,
children: null
};

/**
* @component
*/
export default SubHeading;
export const SubHeading: FC<SubHeadingProps> = styled('h3', {
shouldForwardProp: prop => isPropValid(prop) && prop !== 'size'
})<SubHeadingProps>(baseStyles, sizeStyles, noMarginStyles);
Loading

0 comments on commit 36a4bb5

Please sign in to comment.