Skip to content
This repository has been archived by the owner on Dec 6, 2022. It is now read-only.

Clearly distinguish between CSS and Emotion CSS #1568

Closed
wants to merge 5 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions .changeset/unpopular-aduls-behave.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
'@guardian/source-foundations': major
---

- The `input` reset now returns a `SerializedStyles` Emotion object instead of a `string`
- Typography functions: `headline`, `textSans`, `body`, and `titlepiece` now return a `SerializedStyles` Emotion object instead of a `string`.
- String alternatives are provided, but please note that link underline hover styles won't work as expected unless added separately, because they depend on the parent selector which is only available in Emotion.
4 changes: 4 additions & 0 deletions packages/@guardian/source-foundations/src/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ it('Should have exactly these exports', () => {
'body',
'bodyObjectStyles',
'bodySizes',
'bodyString',
Copy link
Member

@sndrs sndrs Oct 6, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i'm not 100% comfortable with naming things after their type – i think it can more instructive to name things after their use, but I don't know what i'd make of body, bodyObjectStyles, bodySizes and bodyCSS etc if i was trying to get some css for styling body text either (or maybe more pertinently, if i was going to use it with emotion, which is probably also a more common use-case).

i don't want to open a larger can of worms here, but an api like fonts.body.sizes, fonts.body.css, fonts.body.emotionStyles seems more explicit to me, but comes with a greater set of changes as well as being untreeshakable :(

given we already have bodyObjectStyles, what do people think about a convention approaching:

  • bodyEmotionStyles
  • bodyObjectStyles
  • bodySizes
  • __partialFunctionalityCSSBody <- this is trying to achieve something similar to __dangerouslySetInnerHTML

cc @ob6160 @joecowton1 @tjsilver @SiAdcock

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like the ___, i think that does a good job of implying that this is a non-standard approach

'border',
'brand',
'brandAlt',
Expand All @@ -57,6 +58,7 @@ it('Should have exactly these exports', () => {
'headline',
'headlineObjectStyles',
'headlineSizes',
'headlineString',
'height',
'iconSize',
'labs',
Expand Down Expand Up @@ -87,9 +89,11 @@ it('Should have exactly these exports', () => {
'textSans',
'textSansObjectStyles',
'textSansSizes',
'textSansString',
'titlepiece',
'titlepieceObjectStyles',
'titlepieceSizes',
'titlepieceString',
'transitions',
'until',
'visuallyHidden',
Expand Down
4 changes: 4 additions & 0 deletions packages/@guardian/source-foundations/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,10 @@ export {
headline,
body,
textSans,
titlepieceString,
headlineString,
bodyString,
textSansString,
titlepieceSizes,
headlineSizes,
bodySizes,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { css } from '@emotion/react';
import {
availableFontWeights,
fonts,
Expand All @@ -12,6 +13,8 @@ import type {
Categories,
FontScaleArgs,
FontScaleFunction,
FontScaleFunctionEmotion,
FontScaleFunctionStr,
FontStyle,
Option,
TypographyConfiguration,
Expand Down Expand Up @@ -103,37 +106,53 @@ export const fontStyleFunction =
};
};

/**
* Helper method that returns a valid CSS string for a given set of typography styles.
*/
const fontStyleToCssString = (styles: TypographyStyles) => {
const { fontFamily, fontSize, fontStyle, fontWeight, lineHeight } = styles;

return `
font-family: ${fontFamily};
font-size: ${typeof fontSize === 'number' ? `${fontSize}px` : fontSize};
line-height: ${lineHeight};
${fontWeight ? `font-weight: ${fontWeight};` : ''}
${fontStyle ? `font-style: ${fontStyle};` : ''}
`;
};

/**
* Generates a method that evaluates a given font scale function with the
* provided options and returns the typography styles as a CSS string.
*
* This method will not work with the `textDecorationThickness` property.
* If you require this, please use `fontStyleToEmotionFunction` instead.
*
* For an example usage see our {@link [typography string function exports](./index.ts)}.
*/
export const fontStyleToStringFunction =
(typographyFunction: FontScaleFunction) =>
(options?: FontScaleArgs): string => {
const {
fontFamily,
fontSize,
fontStyle,
fontWeight,
lineHeight,
textDecorationThickness,
} = typographyFunction(options);
(typographyFunction: FontScaleFunction): FontScaleFunctionStr =>
(options?: FontScaleArgs) =>
fontStyleToCssString(typographyFunction(options));

return `
font-family: ${fontFamily};
font-size: ${typeof fontSize === 'number' ? `${fontSize}px` : fontSize};
line-height: ${lineHeight};
${fontWeight ? `font-weight: ${fontWeight}` : ''};
${fontStyle ? `font-style: ${fontStyle}` : ''};
/**
* Generates a method that evaluates a given font scale function with the
* provided options and returns the typography styles as a serialised emotion object.
*
* For an example usage see our {@link [typography string function exports](./index.ts)}.
*/
export const fontStyleToEmotionFunction =
(typographyFunction: FontScaleFunction): FontScaleFunctionEmotion =>
(options?: FontScaleArgs) => {
const { textDecorationThickness, ...fontStyles } =
typographyFunction(options);

return css`
${fontStyleToCssString(fontStyles)}
&:hover {
${
textDecorationThickness
? `text-decoration-thickness: ${textDecorationThickness}px`
: ``
};
${textDecorationThickness
? `text-decoration-thickness: ${textDecorationThickness}px;`
: ``}
}
`;
};
47 changes: 42 additions & 5 deletions packages/@guardian/source-foundations/src/typography/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,16 @@ import {
textSans as textSansAsObj,
titlepiece as titlepieceAsObj,
} from './api';
import { fontStyleToStringFunction } from './font-styles';
import {
fontStyleToEmotionFunction,
fontStyleToStringFunction,
} from './font-styles';
import type {
BodySizes,
HeadlineSizes,
TextSansSizes,
TitlepieceSizes,
TypographyEmotionFunctions,
TypographyStrFunctions,
} from './types';

Expand All @@ -21,7 +25,13 @@ import type {
* font-family: 'GT Guardian Titlepiece';
* ```
*/
export const titlepiece: TypographyStrFunctions<TitlepieceSizes> = {
export const titlepiece: TypographyEmotionFunctions<TitlepieceSizes> = {
small: fontStyleToEmotionFunction(titlepieceAsObj.small),
medium: fontStyleToEmotionFunction(titlepieceAsObj.medium),
large: fontStyleToEmotionFunction(titlepieceAsObj.large),
};

export const titlepieceString: TypographyStrFunctions<TitlepieceSizes> = {
small: fontStyleToStringFunction(titlepieceAsObj.small),
medium: fontStyleToStringFunction(titlepieceAsObj.medium),
large: fontStyleToStringFunction(titlepieceAsObj.large),
Expand All @@ -35,7 +45,17 @@ export const titlepiece: TypographyStrFunctions<TitlepieceSizes> = {
* font-family: 'GH Guardian Headline';
* ```
*/
export const headline: TypographyStrFunctions<HeadlineSizes> = {
export const headline: TypographyEmotionFunctions<HeadlineSizes> = {
xxxsmall: fontStyleToEmotionFunction(headlineAsObj.xxxsmall),
xxsmall: fontStyleToEmotionFunction(headlineAsObj.xxsmall),
xsmall: fontStyleToEmotionFunction(headlineAsObj.xsmall),
small: fontStyleToEmotionFunction(headlineAsObj.small),
medium: fontStyleToEmotionFunction(headlineAsObj.medium),
large: fontStyleToEmotionFunction(headlineAsObj.large),
xlarge: fontStyleToEmotionFunction(headlineAsObj.xlarge),
};

export const headlineString: TypographyStrFunctions<HeadlineSizes> = {
xxxsmall: fontStyleToStringFunction(headlineAsObj.xxxsmall),
xxsmall: fontStyleToStringFunction(headlineAsObj.xxsmall),
xsmall: fontStyleToStringFunction(headlineAsObj.xsmall),
Expand All @@ -53,7 +73,13 @@ export const headline: TypographyStrFunctions<HeadlineSizes> = {
* font-family: 'GuardianTextEgyptian';
* ```
*/
export const body: TypographyStrFunctions<BodySizes> = {
export const body: TypographyEmotionFunctions<BodySizes> = {
xsmall: fontStyleToEmotionFunction(bodyAsObj.xsmall),
small: fontStyleToEmotionFunction(bodyAsObj.small),
medium: fontStyleToEmotionFunction(bodyAsObj.medium),
};

export const bodyString: TypographyStrFunctions<BodySizes> = {
xsmall: fontStyleToStringFunction(bodyAsObj.xsmall),
small: fontStyleToStringFunction(bodyAsObj.small),
medium: fontStyleToStringFunction(bodyAsObj.medium),
Expand All @@ -67,7 +93,18 @@ export const body: TypographyStrFunctions<BodySizes> = {
* font-family: 'GuardianTextSans';
* ```
*/
export const textSans: TypographyStrFunctions<TextSansSizes> = {
export const textSans: TypographyEmotionFunctions<TextSansSizes> = {
xxsmall: fontStyleToEmotionFunction(textSansAsObj.xxsmall),
xsmall: fontStyleToEmotionFunction(textSansAsObj.xsmall),
small: fontStyleToEmotionFunction(textSansAsObj.small),
medium: fontStyleToEmotionFunction(textSansAsObj.medium),
large: fontStyleToEmotionFunction(textSansAsObj.large),
xlarge: fontStyleToEmotionFunction(textSansAsObj.xlarge),
xxlarge: fontStyleToEmotionFunction(textSansAsObj.xxlarge),
xxxlarge: fontStyleToEmotionFunction(textSansAsObj.xxxlarge),
};

export const textSansString: TypographyStrFunctions<TextSansSizes> = {
xxsmall: fontStyleToStringFunction(textSansAsObj.xxsmall),
xsmall: fontStyleToStringFunction(textSansAsObj.xsmall),
small: fontStyleToStringFunction(textSansAsObj.small),
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import type { SerializedStyles } from '@emotion/react';
import type {
bodySizes,
fontWeights,
Expand Down Expand Up @@ -78,11 +79,19 @@ export type FontScaleFunction = (options?: FontScaleArgs) => TypographyStyles;

// returns styles as a template literal
export type FontScaleFunctionStr = (options?: FontScaleArgs) => string;
// returns styles as an Emotion SerializedStyles object
export type FontScaleFunctionEmotion = (
options?: FontScaleArgs,
) => SerializedStyles;

export type TypographyStrFunctions<Sizes extends AvailableSizes> = {
[key in keyof Sizes]: FontScaleFunctionStr;
};

export type TypographyEmotionFunctions<Sizes extends AvailableSizes> = {
[key in keyof Sizes]: FontScaleFunctionEmotion;
};

export type TypographyFunctions<Sizes extends AvailableSizes> = {
[key in keyof Sizes]: FontScaleFunction;
};
Expand Down
Loading